pax_global_header00006660000000000000000000000064151630366150014520gustar00rootroot0000000000000052 comment=17ad2f62dda7e39985955da189183e594683d45e libvips-8.18.2/000077500000000000000000000000001516303661500132705ustar00rootroot00000000000000libvips-8.18.2/CITATION.cff000066400000000000000000000013441516303661500151640ustar00rootroot00000000000000cff-version: 1.2.0 message: If you use this software, please cite it as below. title: libvips authors: - family-names: libvips team url: https://libvips.org preferred-citation: type: conference-paper title: The libvips image processing library authors: - family-names: Cupitt given-names: John - family-names: Martinez given-names: Kirk - family-names: Fuller given-names: Lovell - family-names: Wolthuizen given-names: Kleis Auke collection-title: Electronic Imaging 2025 collection-type: proceedings month: 2 year: 2025 publisher: name: Society for Imaging Science and Technology doi: "10.2352/EI.2025.37.12.HPCI-178" url: "https://doi.org/10.2352/EI.2025.37.12.HPCI-178" libvips-8.18.2/CODE_OF_CONDUCT.md000066400000000000000000000071711516303661500160750ustar00rootroot00000000000000libvips Code of Conduct ======================= libvips, is developed and maintained by a mixed group of professionals and volunteers from all over the world. We ask people to adhere to a few ground rules. They apply equally to founders, maintainers, contributors and those seeking help and guidance. This is not meant to be an exhaustive list of things you are not allowed to do. We rather would like you to think of it as a guide to enrich our community and the technical community in general with new knowledge and perspectives by allowing everyone to participate. This code of conduct applies to all spaces managed by the libvips community. This includes the mailing list, our GitHub projects, face to face events, and any other forums created by the community for communication within the community. In addition, violations of this code outside these spaces may also affect a person's ability to participate within them. If you believe someone is violating the code of conduct, we ask that you report it. - **Be friendly and patient.** - **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds. - **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. - **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of our community should be respectful when dealing with other members as well as with people outside the our community. - **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to: - Violent threats or language directed against another person. - Discriminatory jokes and language. - Posting sexually explicit or violent material. - Posting (or threatening to post) other people's personally identifying information ("doxing"). - Personal insults, especially those using racist or sexist terms. - Unwelcome sexual attention. - Advocating for, or encouraging, any of the above behavior. - Repeated harassment of others. In general, if someone asks you to stop, then stop. - **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of group software development comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget we all make mistakes and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. Text based on the Code of Conduct of the [Django community](https://www.djangoproject.com/conduct/). libvips-8.18.2/CONTRIBUTING.md000066400000000000000000000027551516303661500155320ustar00rootroot00000000000000# Contributing to libvips Thank you for your interest in contributing to libvips! There are many ways to contribute, and we appreciate all contributions. ## Code style This project uses `clang-format` to maintain a consistent code style throughout the codebase. We recommend using version 14 (as available in Ubuntu 22.04), to avoid any formatting mismatch with our [GitHub Actions lint check]( .github/workflows/lint.yml). `clang-format` can be used via the `git-clang-format` script. On some systems, it may already be installed (or be installable via your package manager). If so, you can simply run it – the following commands will format only the code on the staged changes: ```shell # Stage original changes $ git add . # Run clang-format on staged changes $ git clang-format # Stage formatting changes and commit $ git add . $ git commit -m "My commit message" ``` Alternatively, you can format only the code changed in the most recent commit: ```shell $ git clang-format HEAD~1 ``` Note that this modifies the files, but doesn't commit them – you'll likely want to run: ```shell $ git commit --amend -a ``` in order to update the last commit with all pending changes. In an emergency, reformat the entire project with something like: ```shell find . \ \( -name "*.[hc]" -o -name "*.cc" -o -name "*.cpp" \) \ -not \( -path "./libvips/foreign/libnsgif/*" -o \ -name vips-operators.cpp -o \ -name StandaloneFuzzTargetMain.c -o \ -name profiles.c \) | \ xargs clang-format -i ``` libvips-8.18.2/ChangeLog000066400000000000000000005054431516303661500150550ustar00rootroot0000000000000031/3/26 8.18.2 - convolution: avoid using unsigned accumulators [nakrovati] - exif: check ifdN range [trailofbits] - tiffload: check jpeg and jp2k components [wooseokdotkim] - uhdrsave: set Q for gainmap recompress, don't chroma subsample RGB gainmaps - uhdrsave: prevent early unref of image with alpha channel [lovell] - rad2float: limit band count when converting from radiance [lovell] - jxlload: check EXIF buffer size before reading header [lovell] 18/3/26 8.18.1 - vector: mask supported Highway targets by builtin targets [kleisauke] - fix Highway paths on big-endian targets [kleisauke] - fix build with MSVC [star-hengxing] - fix compatibility with glibc 2.43 [mtasaka] - pngload: avoid an expensive check during header read [kleisauke] - improve vips7 JPEG load compatibility [kleisauke] - fix saving 3-band MATRIX images [kleisauke] - uhdrload: expose original gainmap scale factor [lovell] - uhdrsave: control generated gainmap scale factor [lovell] - source: guard against length truncation [Niebelungen-D] - shrinkh: fix possible OOB read in Highway path [dloebl] [kleisauke] - string_to_array_double: ensure delimiter list is consistent [dloebl] [lovell] - fix loading/saving of non-8-bit JXL images [DarthSim] - invertlut: check height before interpolating values [dloebl] [lovell] - extract: check bounds using unsigned arithmetic [Niebelungen-D] [lovell] - matrixload: guard against empty and very large inputs [Niebelungen-D] [lovell] - unpremultiply: check `alpha_band` is in range [Niebelungen-D] [lovell] - maplut: ensure lookup table index is unsigned [dloebl] [lovell] - fwfft: fix heap-buffer-overflow for single-row images [dloebl] - draw_flood: reject out-of-bounds start point [dloebl] - openexrload: fix a leak with invalid images [kleisauke] - canny: fix UB in atan2 lookup table init [dloebl] [kleisauke] - conva: guard against divide by zero [kleisauke] - csvload: check whitespace and separator are ASCII [Niebelungen-D] [lovell] - bandrank: check `index` is in range [Niebelungen-D] [lovell] - remainder_const: guard against divide by zero [kleisauke] - vips_window_take: prevent int underflow for small mapped images [jcupitt] - composite: fix UB (invalid-enum-value) in `->build()` [kleisauke] - add: prevent possible int overflow [kleisauke] - bandmean: prevent possible int overflow [kleisauke] - fastcor: prevent possible int overflow [kleisauke] - multiply: prevent possible int overflow [kleisauke] - subtract: prevent possible int overflow [kleisauke] - hist_cum: prevent possible int overflow [kleisauke] - convasep: prevent possible int overflow [kleisauke] - conva: prevent possible int overflow [kleisauke] - convi: prevent possible int overflow [kleisauke] - draw_circle: prevent possible int overflow [kleisauke] - csvload: guard against negative index access [kleisauke] - convi: guard against invalid shift [kleisauke] - nary: guard against empty input [kleisauke] - maplut: add missing overflow checks [kleisauke] - jpegsave: fix assert fail when saving 2-band image [kleisauke] - LabS2LabQ: fix UB (undefined-shift) [kleisauke] - convasep: use unsigned accumulator where appropriate [kleisauke] - min: fix possible OOB read with complex images [kleisauke] - max: fix possible OOB read with complex images [kleisauke] - guard against dimension overflow [ElhananHaenel] [kleisauke] - gifload: prevent int overflow on 32-bit platforms [ElhananHaenel] [kleisauke] - sign: use ready image instead of `unary->in` [kleisauke] - statistic: use ready image instead of `statistic->in` [kleisauke] - hist_plot: handle near-zero ranges for float images [kleisauke] - affine: check bounds using unsigned arithmetic [kleisauke] 17/12/25 8.18.0 - add dcrawload, dcrawload_source, dcrawload_buffer: load raw camera files using libraw [lxsameer] - add magickload_source: load from a source with imagemagick - add vips__worker_exit(): enables fast threadpool shutdown - larger mmap windows on 64-bit machines improve random access mode for many file formats - pdfload: control region to be rendered via `page_box` [lovell] - system: add "cache" argument - add vips_image_get_tile_width(), vips_image_get_tile_height(): get tile cache geometry hints [jbaiter] - add vips_uhdrload(), vips_uhdrload_buffer(), vips_uhdrload_source(): load an UltraHDR image - add vips_uhdrsave(), vips_uhdrsave_buffer(), vips_uhdrsave_target(): save an UltraHDR image - fix cpp binding leak [VivitionDeveloper] - add "gainmap" to VipsKeep - add vips_image_get_gainmap() - thumbnail updates gainmaps - add "bitdepth" to jxlsave - add "path" option to vipsthumbnail, deprecate "output" option [zjturner] - add "exact" to webpsave - add "uhdr2scRGB" - dzsave has gainmap support - cpp: add .gainmap(), .set(VImage) - add support for Oklab and Oklch colourspaces - add vips_Oklab2XYZ(), vips_XYZ2Oklab() - add vips_Oklab2Oklch(), vips_OKlch2Oklab() - add vips_interpretation_bands() - heifsave: add "tune" parameter - require C++14 as a minimum standard [kleisauke] - prefer libpng over spng 8.17.4 - vipsthumbnail: fix pyramidal image layer selection [esiqveland] - tools: fix possible deadlock during process exit on win32 - fix temp dir handling on win32 with Unicode usernames [kleisauke] - pngsave, ppmsave: support for more image interpretations [gcsideal] 30/10/25 8.17.3 - tiffsave: fix saved resolution with a non-default resolution-unit metadata item [machur] - svgload: ensure short/malformed compressed input is ignored [kleisauke,lovell] - dzsave: Zoomify: ensure correct tile count in ImageProperties.xml [kleisauke] - VipsSaveable: reimplement with macros to help C++ compat [jcupitt] 13/9/25 8.17.2 - rank: fix an off-by-one error [larsmaxfield] - popplerload, svgload: validate page size [Yang Luo] - pdfiumload: allow both dpi and scale to be set [kleisauke] - svgload: honor DPI when scaling elements with non-pixel units [kleisauke] - disable redundant Highway AVX512 targets [kleisauke] - openslideload_source: flag operation as "nocache" [kleisauke] - remove `vipsprofile.1` man page from install [kleisauke] - tiffload: ensure processing halts for memory-related errors [lovell] - tiffload: increase memory limit from 20MB to 50MB [lovell] - fix vapi build [stydxm] - tiffsave: include sample format when copying tiff data [manthey] 7/7/25 8.17.1 - fix API docs build with meson < 0.60 [lovell] - improve function checks in meson [kleisauke] - tiff: use correct log domain in threadsafe warning handlers [kleisauke] - shift 16-bit output down to 8-bit when unsupported by saver [kleisauke] - text: prevent use of rgba subpixel anti-aliasing [lovell] - tiffsave: always apply resolution unit conversion [kleisauke] - cache: suppress invalidation errors in release builds [kleisauke] - dzsave: IIIF: use named region of 'full' when no crop takes place [lovell] - pdfload: fix potential crash with pdfium < 6633 [zhifengzhuang] 5/6/25 8.17.0 - gifsave: add `keep_duplicate_frames` flag [dloebl] - add Magic Kernel support [akimon658] - tiff: add threadsafe warning/error handlers (requires libtiff 4.5.0+) [lovell] - tiffload: add support for `fail_on` flag [lovell] - tiffload: add support for `unlimited` flag (requires libtiff 4.7.0+) [lovell] - much more reliable operation caching - colour: add support for auto-selecting the rendering intent [kleisauke] - add matrixmultiply - better handling of malformed size values [Simcha Kosman] - improve performance of vips_shrink() [kleisauke] - svgload: add support for custom CSS via `stylesheet` option [lovell] - heifload: `unlimited` flag removes all limits (requires libheif 1.19.0+) [lovell] - heifsave: improve alpha channel detection [lovell] - convi: ensure double sum precision for floats [lovell] - improve guard against corrupt ICC profiles with older lcms2 versions [kleisauke] - improve vips_sink_screen() thumbnail rendering - heifload: improve detection of seek beyond EOF [lovell] - jp2kload: add `oneshot` flag [mbklein] - share and reuse openslide connections - drop support for openslide 3.3 - fix vips_quadratic() - rename `thumbnail`'s export/import profile options as input/output for consistency - restore vips_remosaic(), it was not being linked - deprecate VipsSaveable, add VipsForeignSaveable - move vips_image_preeval(), vips_image_eval(), vips_image_posteval() into the public API - jxlsave: add support for chunked save (requires libjxl 0.9.0+) - increase minimum version of libjxl dependency to 0.7.0 - increase minimum version of libheif dependency to 1.7.0 - improve scaling of hough_line feature space [ecbypi] - heifload: limit per-image memory usage to 2GB (requires libheif 1.20.0+) - svgload: add support for scRGB output via `high_bitdepth` flag [kstanikviacbs] - remove vipsprofile from default install - add ppmload_buffer [kleisauke] 12/3/25 8.16.1 - support multipage JXL - fix PFM byte order on big-endian machines [agoode] - morph: fix erode Highway path [kleisauke] - morph: fix C-paths with masks containing zero [kleisauke] - fix `--vips-info` CLI flag with GLib >= 2.80 [kleisauke] - make `subsample-mode=on` and `lossless=true` mutually exclusive [kleisauke] - fix SZI write with openslide4 [goran-hc] - heifsave: prevent use of AV1 intra block copy feature [lovell] - threadpool: improve cooperative downsizing [kleisauke] - fix alpha shift during colourspace conversions [frederikrosenberg] - heifsave: set image orientation using irot and imir transformations [lovell] - XYZ2Yxy: guard against divide by zero - fix MSVC compile error [na-trium-144] - exif: ensure enumerated entries can be converted to string values [lovell] - gifsave: add support for eval callback, ensure correct return code [lovell] - tiffsave: honor disc threshold during pyramid save [kleisauke] - fill_nearest: fix a leak - colour: use suggested rendering intent as fallback [kleisauke] - morph: fix Orc path with large masks [kleisauke] - invertlut: fix final value in some cases - matrixload: fix file format detect for some matrix types - radload: improve sanity check of colour-related headers [lovell] - heifsave: reject multiband images [lovell] - heifload: prevent possible int overflow for large images [kleisauke] - tiffload: add missing read loop [kleisauke] - prevent possible use-after-free when debugging via `--vips-leak` flag [lovell] - avoid possible overflow when multiplication result is cast up [lovell] 10/10/24 8.16.0 - allow small offsets for the PDF magic string [project0] - add support for OJPEG tiffs [DarthSim] - add "palette" metadata item to flag palette images [DarthSim] - jxl load and save now support exif, xmp, animation [DarthSim] - improved configure output - add a filetype blocker for imagemagick - add basic g_auto support - support for long EXIF values [MarcosAndre] - better system error messages on windows [kleisauke] - add configurable max coordinate and vips_max_coord_get() - improve kill handling - PFM save and load now uses scRGB (ie. linear 0-1) [NiHoel] - turn vips_addalpha() into a VipsOperation [RiskoZoSlovenska] - add vips_rawsave_target(), vips_rawsave_buffer() [akash-akya] - vipsheader supports multiple "-f field" arguments [sergeevabc] - add "target_size" to webpsave [john-parton] - add "passes" to webpsave [john-parton] - revise sRGB -> B_W coefficients [daniellovera] - add vips_sdf(), vips_clamp(), vips_maxpair(), vips_minpair() - more const for the C++ API [Julianiolo] - deprecate "cache" (use tilecache instead) - add tests for tokenisation - add "unpack_complex" option to vips_getpoint() - add deflate compression level setting to tiffsave [ruven] - add "smart_deblock" to webpsave [goodusername123] 4/10/24 8.15.5 - version bump, revise C++ soname 3/10/24 8.15.4 - fix an off-by-one error in vips__token_get() - heifsave: fix crash when passing an invalid bitdepth [kleisauke] - webpsave: fix memory leak on error [dloebl] - heifsave: ensure NCLX profile is freed in lossless mode [kleisauke] - threadpool: fix a race condition in error handling [kleisauke] - disable GLib cast checks and asserts for plain builds [kleisauke] - fix jpeg in tiff for high Q [nahilsobh] - threadset: fix a race condition during thread exit [kleisauke] - fix compatibility with MSVC [Julianiolo] 11/8/24 8.15.3 - fix dzsave of >8-bit images to JPEG - jpegsave: fix chrominance subsampling mode with jpegli [kleisauke] - pngload: disable ADLER32/CRC checking in non-fail mode [kleisauke] - improve target_clones support check [kleisauke] - fix pipe read limit - fix a rare crash on Windows in highly threaded applications [Julianiolo] - vipssave: fix infinite loop on Windows with large images [pdbourke] - conva: fix a crash with {u,}{short,int} images [erdmann] - fix vips_image_get_string - heifsave: fix lossless mode [kleisauke] - composite: fix dest-atop blend mode [kleisauke] - fix vips_source_map for zero-length sources [kleisauke] 12/3/24 8.15.2 - fix deflate compression of tiff pyramids [manthey] - thumbnail always writes 8-bit thumbnails [turtletowerz] - lower min scale factor to 0.0 in svgload and pdfload [lovell] - heifload: don't warn on images with nclx profiles [kleisauke] - ppmload: ensure multi-line comments are skipped [lovell] - fix arrayjoin with some pipelines [TheEssem] - fix high Q mono JPEG TIFF write with mozjpeg [cavenel] - tiffsave: ensure large file support (>2GB) on MSVC [kleisauke] - check linker for target_clones support [lovell] 18/12/23 8.15.1 - reduceh: fix Highway path on SSE2 [DarthSim] - fix JPEG in TIFF colourspace for Q >= 90 [heman1-test] - fix build with upcoming libjxl 0.9 [kleisauke] - jxlsave: lower min effort value to 1 [DarthSim] - fix build without libjpeg [ionenwks] - fix vips7 plugin load [jcupitt] - allow ".jfif" as a suffix for jpegsave [casperbrike] - don't let the magick sniffer hijack TIFF [kleisauke] - ignore BLOCKED classes in foreign map [jcupitt] - add locks to fftw3 calls [akash-akya] 11/11/23 8.15.0 - add support for target_clones attribute [lovell] * use with (un)premultiply for ~10% perf gain on AVX CPUs * use with XYZ to LAB colourspace conversion for ~10% perf gain on AVX CPUs - add fast path to extract_band and bandjoin for uchar images [lovell] - reduce `vips_sharpen` max `sigma` to 10 [lovell] - inline scRGB to XYZ colourspace conversion, ~2x faster [lovell] - set "interlaced=1" for interlaced GIF images [kleisauke] - add @line_art to find_trim [miltoncandelero] - improve C++ binding [MathemanFlo] * add `inplace()` / `VImage::new_from_memory_copy()` * add overloads for `draw_*()` / `VImage::thumbnail_buffer()` - allow negative line spacing in text [donghuikugou] - add VIPS_META_BITS_PER_SAMPLE metadata, deprecate the "palette-bit-depth" and "heif-bitdepth" meta fields [MathemanFlo] - add "revalidate" to foreign loaders [jcupitt] - add `premultiplied` option to smartcrop [lovell] - add "prewitt" and "scharr" edge detectors, "sobel" is more accurate for non-uchar formats [jcupitt] - add support for forms in pdfium loader [kleisauke] - swap built-in profiles with ICC v4 variants [kleisauke] - remove libgsf dependency in favor of libarchive [kleisauke] - better chunking for small shrinks [jcupitt] - use alpha range of 0.0 - 1.0 for scRGB images [DarthSim] - add support for 16-bit float TIFFs [DarthSim] - add direct mode to dzsave [jcupitt] - require C++11 as a minimum standard [kleisauke] - add support for SIMD via Highway [kleisauke] - threaded write in tiffsave for tiled JPEG and JPEG2000 [jcupitt] - add vips_thread_execute() to the public API [jcupitt] - add "keep" flag to foreign savers, deprecate "strip" [a3mar] - improve scRGB handling [jcupitt] 18/9/23 8.14.5 - fix a crash with alpha plus icc_import and icc_export [jcupitt] - fix a crash in jxlsave [jcupitt] 15/8/23 8.14.4 - fix null-pointer dereference during svgload [kleisauke] - heif{load,save}: guard against NULL strings [kleisauke] - pdfiumload: fix rendering of pages with different sizes [DarthSim] 20/7/23 8.14.3 - fix ICC handling of greyscale images with a incompatible profile [kleisauke] - fix use-after-free during tiff pyramid save [kleisauke] - fix vips7 PNG load and save when using libspng [jcupitt] - tiffload: slightly relax tile size sanity check [lovell] - heifsave: limit dimensions to a maximum edge of 16384 [lovell] - colourspace: ensure CMYK conversion uses the embedded ICC profile [kleisauke] - ensure chromatic adaptation during icc_{im,ex}port() [kleisauke] - improve ICC compatibility check for CMYK images [kleisauke] 21/3/23 8.14.2 - use a private fontmap in vips_text() [jcupitt] - increase sanity checks on TIFF tile dimensions [lovell] - ensure compatibility with libheif > 1.14.2 [kleisauke] - minor doc fixes [jcupitt] - sanitise dimensions in JPEG-compressed TIFF images [lovell] - fix target pnm write [ewelot] - dedupe FITS header write [ewelot] - fix `strip` parameter in webpsave [jcupitt] - earlier abort of webpsave on kill [dloebl] - fix thumbnail of CMYK images with an embedded ICC profile [kleisauke] - fix ICC handling of RGB images with a monochrome profile [kleisauke] - ensure ICC transforms keep all precision [kleisauke] - fix openslideload associated=XXX load [jcupitt] - fix compatibility with MSVC [SpaceIm] 9/1/23 8.14.1 - add vips_thread_isworker() compatibility function [remicollet] - add vips_semaphore_down_timeout() [kleisauke] - idle threads are removed after 15s [kleisauke] - fix version number in gtk-doc index [kleisauke] - save mono fits images as NAXIS=2 [ewelot] - fix jpeg `autorotate` for orientation 3 [zhifengzhuang] 22/12/22 8.14.0 - remove autotools - remove various obsolete scripts - remove benchmark - `jp2ksave` defaults to chroma subsample off, and jp2 write - don't minimise `vips_sink_screen()` input after expose ... improves caching during interactive use - require libjxl 0.6+ - add `interlace` option to GIF save [dloebl] - magick load sets `magick-format` metadata [aksdb] - add `.pnm` save [ewelot] - threaded tiff jp2k and jpeg decompress - improve speed and efficiency of animated WebP write [dloebl] - add `rgb` mode to openslideload - new thread recycler - threadpools size dynamically with load - operations can hint threadpool size - faster `dzsave` - support for N-colour ICC profiles - add bash completions for `vips` - fits load and allows many more bands - fits write doesn't duplicate header fields - add `wrap` to `vips_text()` - GIF load supports truncated frames [tlsa] - EXIF support for PNG load and save - expose location of interest when using attention based cropping [ejoebstl] - deprecate gifsave `reoptimise`, add `reuse` - add `encoder` to heifsave [dloebl] - add `cplusplus` meson build option [jcupitt] - make arrayjoin much faster with large arrays 9/11/22 started 8.13.4 - missing include in mosaic_fuzzer [ServOKio] - emit "finish" at the end of targetcustom write [lucaskanashiro] 11/10/22 started 8.13.3 - improve rules for 16-bit heifsave [johntrunc] - improve libspng palette write [kleisauke] - improve libspng palette sort [DarthSim] - ensure EXIF has prefix before parsing [lovell] - fix low bit depth palette spng save [DarthSim] - fix thumbnail of non-sRGB images with an export profile [kleisauke] 5/9/22 started 8.13.2 - in dzsave, add add missing include directive for errno/EEXIST [kleisauke] - fix 8 bit palette PNG save [lovell] - fix null string in buffer print [pclewis] - revise caching of seq mode loaders [jcupitt] - reduce latency on dzsave kill [kleisauke] - improve text too large check [kleisauke] - fix subifd writing for small images [ruven] - name ICC profiles in spngsave [lovell] 24/7/22 started 8.13.1 - fix im7 feature detection in meson - add a summary table at the end of configure in meson - fix libpng fallback when spng is disabled in meson - add "unlimited" to jpegload - better 0 detection in unpremultiply - fix low bitdepth spng save [jeffska] - fix PNG low bitdepth save of high bitdepth images - add support for libjxl 0.7 [kleisauke] - improve compatibility with older libgsf versions [kleisauke] 21/11/21 started 8.13 - configure fails for requested but unmet dependencies [remicollet] - add support for another quantiser [DarthSim] - add "extend", "background" and "premultiplied" to vips_mapim() to fix edge antialiasing [GavinJoyce] - add support for HDR HEIC and AVIF images - add vips_spngsave() - jpeg2000 load left-justifies bitdepth - add "password" option to pdfload, fix byte ordering of "background" - add vips_operation_block_set(), vips_block_untrusted_set() - improve the pixel rng - new meson build system [tintou] - improve introspection annotations [tintou] - add "unlimited" to heifload [lovell] - add support for regions in C++ API [shado23] - add "maxerror" to gifsave [dloebl] - update libnsgif API [tlsa] - deprecate "properties" option to dzsave (now always on) - add vips_dzsave_buffer() - always set the min stack size for pthreads, if we can - add "fail-on" to thumbnail - add "gap" option to vips_reduce[hv]() and vips_resize() [kleisauke] - add "ceil" option to vips_shrink() [kleisauke] - quality improvements for image resizing [kleisauke] - add vips_source_new_from_target() - add vips_target_seek(), vips_target_read(), vips_target_new_temp() - add vips_tiffsave_target() - add vips_target_end(), deprecate vips_target_finish() - add "mixed" to webpsave [dloebl] - add support for ICC profiles and linear encoding to JXL load and save [f1ac] - add "reoptimise" to gifsave [dloebl] - add "bitdepth" to magicksave [dloebl] - change default PNG filter to "none" [lovell] 26/11/21 started 8.12.3 - better arg checking for vips_hist_find_ndim() [travisbell] - fix thumbnail with CMYK output [AdamGaskins] - fix size_t / ssize_t confusion [flga] - fix jxl compatibility break [lovell] 26/11/21 started 8.12.2 - make exif resuint optional and default to inch - win: don't set create time on inappropriate file descriptors [lovell] - fall back to magicksave for gif if cgif is not present [erik-frontify] - fix a crash with 0 length vectors - change default frame delay for GIFs from 1s to 0.1s - remove stray trailing comma from iiif3 dirnames [whalehub] - fix TTF load [chregu] - revise GIF save alpha threshold [jfcalvo] - raise libpng pixel size limit from 1m to 10m pixels [jskrzypek] - fix gif save change detector [TheEssem] - fix load from pipe with variable size reads 21/11/21 started 8.12.1 - fix insert [chregu] 14/6/21 started 8.12 - all tools support `--version` - add vips_svgload_string() convenience function - fix thumbnail with small image plus crop plus no upsize [Andrewsville] - rename speed / reduction-effort / etc. params as "effort" - add gifsave [lovell] - arrayjoin minimises inputs during sequential processing, saving a lot of memory and file descriptors - add vips_image_get_format_max() - flatten handles out of range alpha and max_alpha correctly - don't use atexit for cleanup, it's too unreliable - tiff writer loops for the whole image rather than per page [LionelArn2] - fix VipsSource with named pipes [vibbix] - added restart_interval option to jpegsave [manthey] - add IIIF3 support to dzsave [martimpassos] - add atan2 to math2 [indus] - improve buffer and target save file format selection - added VipsForeignPpmFormat, format arg to ppm savers - add fail-on to give better control over loader error sensitivity - add hyperbolic functions sinh, cosh, tanh, asinh, acosh, atanh [hroskes] - add untiled jp2k load - "insert" will minimise in seq mode - better EXIF string handling [lovell] 16/8/21 started 8.11.4 - fix off-by-one error in new rank fast path - add "unlimited" flag to png load [joshuamsager] - improve filtering of .v enums [lovell] - better logic to prevent shrink to nothing in thumbnail [kleisauke] 14/7/21 started 8.11.3 - build threadpool later [kleisauke] - add jxlsave prototypes [adil-benameur] - limit text chunks in PNGs [randy408] 15/6/20 started 8.11.2 - better libdir guessing [remi] - fix tiff pyramid creation with jp2k compression (was broken by 8.11.1) - don't load modules if we're built without modules 18/6/21 started 8.11.1 - add more example code to C docs - update libtool support in configure.ac - more startup info if VIPS_INFO is set - command-line programs set glib prgname (no longer set for you by VIPS_INIT) - enable strip chopping for TIFF read [DavidStorm] - disable modules by default for static builds [kleisauke] - fix jpeg tiff pyramid save 14/8/20 started 8.11 - add vips_jpegload_source() and vips_svgload_source() to public C API - integrate doxygen in build system to generate C++ API docs - improve C++ API doc comments - add VipsInterpolate and guint64 support to C++ API - add VImage::new_from_memory_steal [Zeranoe] - vipsthumbnail supports stdin / stdout thumbnailing - have a lock just for pdfium [DarthSim] - get pdfium load building again [Projkt-James] - add _source load support for pdfium - add "seed" param to perlin, worley and gaussnoise - add vips_source_g_input_stream_new() to load images from a GInputStream - add openslideload_source(), vipsload_source(), vipssave_target() - add hist path to rank for large windows on uchar images - better 8/16-bit choice for pngsave - avoid NaN in mapim [afontenot] - hist_find outputs a double histogram for large images [erdmann] - fix ref leaks in mosaicing package - run libvips leak test in CI - add vips_fitsload_source(), vips_niftiload_source() - png and gif load note background colour as metadata [781545872] - add vips_image_[set|get]_array_double() - add GIF load with libnsgif - add jp2kload, jp2ksave - add jp2k compression to tiff load and save - add JPEG-XL load and save - add black_point_compensation flag for icc transforms - add "rgba" flag to vips_text() to enable full colour text rendering - move openslide, libheif, poppler and magick to loadable modules [kleisauke] - better detection of invalid ICC profiles, better fallback paths - add "premultiply" flag to tiffsave - new threading model has a single threadpool shared by all pipelines [kleisauke] 30/4/21 start 8.10.7 - better vips7 PNG load compatibility [SkyDiverCool] - fix load of large PPM images from a pipe [ewelot] 22/12/20 start 8.10.6 - don't seek on bad file descriptors [kleisauke] - check for null memory sources [kleisauke] - improve ppmload, fixing a couple of small bugs - improve EOF detection in jpegload [bozaro] - improve error detection in spngload [randy408] - fix includes of glib headers in C++ [lovell] - fix build with more modern librsvg [lovell] - fix a possible segv with very wide images [f1ac] - fix issue thumbnailing RGBA images in linear mode [jjonesrs] - improve vipsthumbnail profile handling - fix tiff deflate predictor setting [Adios] - fix vector path for composite on i386 [kleisauke] 18/12/20 started 8.10.5 - fix potential /0 in animated webp load [lovell] 14/12/20 started 8.10.4 - fix spng detection 18/10/20 started 8.10.3 - relax heic is_a rules [hisham] - fix vips7 webp load [barryspearce] - fix out of bounds exif read in heifload - fix out of bounds read in tiffload - fix tiffsave region shrink mode [imgifty] - add missing flushes on write to target [harukizaemon] - hide info messages you could get with some older glibs [kleisauke] - fix --no-strip on dzsave with icc-profiles [altert] - better GraphicsMagick image write [bfriesen] - add missing read loops to spng, heif, giflib and ppm load [kleisauke] - block zero width or height images from imagemagick load [Koen1999] - check for overflow in gifload height [lovell] - fix msb_first default in ppm load and save [ewelot] - force binary mode on win for connection read / write [Alreiber] - better testing for output to target [barryspearce] - ppmload_source was missing is_a [ewelot] - improve webpload rounding and blending behaviour [lovell] - fix range clip in int32 -> unsigned casts [ewelot] - fix precision error in clip of float -> int casts [ewelot] - fix load of HEIC images with 0 length metadata [ddennedy-gpsw] - revise rounding in reduce [kleisauke] 6/9/20 started 8.10.2 - update magicksave/load profile handling [kelilevi] - better demand hint rules [kaas3000] - fix tiff thumbnail from buffer and source [vansante] - in jpegsave, don't set JFIF resolution if we set EXIF resolution - bump minimum libheif version to 1.3 [lovell] - dzsave in iiif mode could set info.json dimensions off by one [Linden6] - pdfload allows dpi and scale to both be set [le0daniel] - allow gaussblur sigma zero, meaning no blur - better heif signature detection [lovell] - fix vips_fractsurf() typo [kleisauke] - better heif EOF detection [lovell] - fix gir build with g-o-i 1.66+ [László] - improve seek behaviour on pipes - add "speed" param to heifsave [lovell] - fix regression in C path for dilate / erode [kleisauke] - fix build with libheif save but no load [estepnv] 9/8/20 started 8.10.1 - fix markdown -> xml conversion in doc generation - remove typedef redefinitions to please old gccs - fix regression in tiff pyramid thumbnailing [tand826] - stop 0-length buffer being passed to imagemagick [lovell] - convert no-profile CMYK to RGB on save [augustocdias] - ensure SVG loader skips input with chars outside x09-x7F range [lovell] - better mask sizing in gaussmat [johntrunc] - fix tiffsave "squash" handling [barryspearce] - fix jpegload autorotate [chregu] - only start the background render thread on first use 24/1/20 started 8.10.0 - more conformat IIIF output from dzsave [regisrob] - add @id to dzsave to set IIIF id property [regisrob] - add max and min to region shrink [rgluskin] - allow \ as an escape character in vips_break_token() [akemrir] - tiffsave has a "depth" param to set max pyr depth - libtiff LOGLUV images load and save as libvips XYZ - add gifload_source, csvload_source, csvsave_target, matrixload_source, matrixsave_source, pdfload_source, heifload_source, heifsave_target, ppmload_source, ppmsave_target - revise vipsthumbnail flags - add VIPS_LEAK env var - add vips_pipe_read_limit_set(), --vips-pipe-read-limit, VIPS_PIPE_READ_LIMIT - revise gifload to fix BACKGROUND and PREVIOUS dispose [alon-ne] - add subsample_mode, deprecate no_subsample in jpegsave [Elad-Laufer] - add vips_isdirf() - add PAGENUMBER support to tiff write [jclavoie-jive] - add "all" mode to smartcrop - flood fill could stop half-way for some very complex shapes - better handling of unaligned reads in multipage tiffs [petoor] - mark old --delete option to vipsthumbnail as deprecated [UweOhse] - png save with a bad ICC profile just gives a warning - add "premultipled" option to vips_affine(), clarified vips_resize() behaviour with alpha channels - improve bioformats support with read and write of tiff subifd pyramids - thumbnail exploits subifd pyramids - handle all EXIF orientation cases, deprecate vips_autorot_get_angle() [Elad-Laufer] - load PNGs with libspng, if possible - deprecate heifload autorotate -- it's now always on - revised resize improves accuracy [kleisauke] - add --vips-config flag to show configuration info - add "bitdepth" param to tiff save, deprecate "squash" [MathemanFlo] - tiff load and save now supports 2 and 4 bit data [MathemanFlo] - pngsave @bitdepth parameter lets you write 1, 2 and 4 bit PNGs - ppmsave also uses "bitdepth" now, for consistency - reduce operation cache max to 100 - rework the final bits of vips7 for vips8 [kleisauke] - --disable-deprecated now works [kleisauke] - vipsheader allows "stdin" as a filename - gifload allows gifs with images outside the canvas - wasm compatibility patches [kleisauke] - webpsave has a @profile param 24/4/20 started 8.9.3 - better iiif tile naming [IllyaMoskvin] 31/1/19 started 8.9.2 - fix a deadlock with --vips-leak [DarthSim] - better gifload behaviour for DISPOSAL_UNSPECIFIED [DarthSim] - ban ppm max_value < 0 - add fuzz corpus to dist - detect read errors correctly in source_sniff - fix regression in autorot [malomalo] - thumbnail on HEIC images could select the thumbnail incorrectly under some size modes [ZorinArsenij] 20/6/19 started 8.9.1 - don't use the new source loaders for new_from_file or new_from_buffer, it will break the loader priority system - fix thumbnail autorot [janko] - fix a warning with magicksave with no delay array [chregu] - fix a race in tiled tiff load [kleisauke] - better imagemagick init [LebronCurry] - lock for metadata changes [jcupitt] 20/6/19 started 8.9.0 - add vips_image_get/set_array_int() - disable webp alpha output if all frame fill the canvas and are solid - support arrays of delays for animated images [deftomat] - add "unlimited" flag to svgload - disable webp alpha output if all frames fill the canvas and are solid - add "compression" option to heifsave [lovell] - support webp and zstd compression in tiff - loaders use "minimise" to close input files earlier - integrate support for oss-fuzz [omira-sch] - add vips_switch() / vips_case() ... fast many-way ifthenelse - better const handling for arithmetic operators fixes comparisons against out of range values - sharpen restores input colourspace - handle alpha in heifload / heifsave [meyermarcel] - add @interpretation and @format to rawload - nifti load/save uses double for all floating point metadata - add vips_error_buffer_copy() - add VipsSource and VipsTarget: a universal IO class for loaders and savers - jpeg, png, tiff (though not tiffsave), rad, svg, ppm and webp use the new IO class - rewritten ppm load/save is faster and uses less memory - add @no_strip option to dzsave [kalozka1] - add iiif layout to dzsave - fix use of resolution-unit metadata on tiff save [kayarre] - support TIFF CIELAB images with alpha [angelmixu] - support TIFF with premultiplied alpha in any band - block metadata changes on shared images [pvdz] - RGB and sRGB are synonmous 17/9/19 started 8.8.4 - improve compatibility with older imagemagick versions - remove realpath, since it can fail on systems with grsec 31/8/19 started 8.8.3 - revert sharpen restoring the input colourspace - xres/yres tiffsave params were in pixels/cm [f--f] 9/7/19 started 8.8.2 - better early shutdown in readers - don't attempt to save large XMP to jpeg [tnextday] - always fetch HEIC metadata from the main image [zhoux2016] - fix loop in malformed ppm [Kyle-Kyle] - better support for PNGs with long comment names - fix build with GM - add locks for pdfium load - fix build with MSVC - fix a problem with shinkv tail processing [angelmixu] - fix a read one byte beyond buffer bug in jpegload - make GIF parsing less strict - better feof() handling in GIF load - clip coding and interpretation on vips image read - check image bounds for GIF load - prevent over-pre-shrink in thumbnail [kleisauke] - fix sharpen with sigma 0.5 [2h4dl] - sharpen restores input colourspace - verify bands/format for coded images - improve data_length handling for jpeg metadata 24/5/19 started 8.8.1 - improve realpath() use on older libc - better magickload error messages - more consistent behaviour for page-height metadata - fix for composite with many small images and some combinations of blend modes - fix memleak in tiff pyr save to memory [scossu] - istiff attempts to read the first directory rather than just testing the magic number [przemyslawpluta] - much faster ismagick() [jcupitt] - better behaviour for vips_region_fetch() if request lies partly outside image - remove 256 band limit in arithmetic.c [erdmann] - disable Orc if building with CET [lovell] - fix vipsthumbnail with pyr tiff [kleisauke] - text autofit could occasionally terminate early [levmorozov] - fewer warnings on tiffload [chregu] - vips_resize() breaks aspect ratio and limits shrink to prevent <1px dimensions [lovell] 21/9/18 started 8.8.0 - much faster smartcrop [lovell] - add low/high to smartcrop [jcupitt] - add XMP support to png read/write [jcupitt] - deprecate thumbnail auto_rotate, add no_rotate [jcupitt] - implement thumbnail shrink-on-load for openslide images [jcupitt] - add animated webp support [jcupitt] - revise vips_cast() to improve behaviour with uint images [erdmann] - add bandand()/or()/eor() to cplusplus binding [clcaalu] - implement shrink-on-load for tiff pyramids [jcupitt] - added vips_image_set_blob_copy() [jcupitt] - don't stop composite on first non-transparent image [felixbuenemann, GDmac] - add vips_rect_overlapsrect() - composite is much faster at positioning subimages - stop tiff pyr layers if width or height drop to 1 [gvincke] - dzsave has a new skip_blanks option - add vips_CMYK2XYZ() and vips_XYZ2CMYK(), plus associated routes - include cmyk and srgb fallback profiles - add vips_profile_load() and use it everywhere - fix race in temp filename creation [lhecker] - add @reduction_effort param to webpsave [lovell] - add @option_string param to thumbnail_buffer [kleisauke] - add XMP, IPCT, ICC, EXIF etc. support to magickload/magicksave - much lower memuse for gifload - tilecache speedups - add vips_heifload(), vips_heifsave() - add heif thumbnail support to vips_thumbnail() - free threadpool earlier, reducing mem growth for some long-running processes [jtorresfabra] - add vips_region_fetch() / _width() / _height() for language bindings - vips_text() supports justification - move vips_image_set_kill() and iskilled() to the public API - dzsave to szi sets suffix correctly [martinweihrauch] - dzsave szi writes "scan-properties.xml" - add vips_image_(get|set)_image() - add openslideload option to attach all associated images as metadata - dzsave to szi will write all associated images - remove old c++ and python interfaces - vipsthumbnail can thumbnail animated and multipage images - deprecate webpload @shrink, use @scale instead 31/3/19 started 8.7.5 - better buffer sizing in tiff reader [omira-sch] 4/1/19 started 8.7.4 - magickload with magick6 API did not chain exceptions correctly causing a memory leak under some conditions [kleisauke] - zero memory on allocate to prevent write of uninitialized memory under some error conditions [Balint Varga-Perke] 21/11/18 started 8.7.3 - fix infinite loop for autofit with non-scaleable font - mapim was not offsetting by window offset [erdmann] - better rounding for scale [kleisauke] - fix a memleak in magick6load [kleisauke] 21/11/18 started 8.7.2 - more info output for temp files to help diagnose problems - vips_text() could set the wrong DPI - vips_text() leaked in autofit mode 23/9/18 started 8.7.1 - update function list in docs [janko-m] - test for g_str_to_ascii() [jcupitt] - fix temp file open on Windows and fallback on linux [lovell] 23/12/17 started 8.7.0 - add magicksave, save image with libMagick [dlemstra] - remove jpeg thumbnail from EXIF if "jpeg-thumbnail-data" has been removed by user - hough_line scales width to 0 - 180, not 0 - 360 - hough_line is 4x faster - hough_circle is 2x faster - add vips_sobel() and vips_canny() edge detectors - add vips_rotate() ... a convenience method for vips_similarity() - svgload was missing is_a [lovell] - better header sniffing for small files - drop incompatible ICC profiles before save - better hasalpha rules - create funcs always make MULTIBAND (ie. no alpha) - use O_TMPFILE, if available [Alexander--] - set "interlaced=1" for interlaced JPG and PNG images - add PDFium PDF loader - jpegload adds a jpeg-chroma-subsample field with eg. 4:4:4 for no chrominance subsampling. - tiffload, pdfload, magickload set VIPS_META_N_PAGES "n-pages" metadata item - add fontfile option to vips_text() [fangqiao] - add vips_transpose3d() -- swap major dimensions in a volumetric image - remove vips7 stuff from default API ... you must now #include it explicitly - added vips_argument_get_id() to fix derived classes on win32 [angelmixu] - fix compile with MSVC 2017 [angelmixu] - pdfload has a option for background - vips7 C++ interface defaults off - make members, getters and operators "const" in cpp API - composite has params for x/y position of sub-images [medakk] - add Mitchell kernel - pyramid builders have a choice of 2x2 shrinkers [harukizaemon] - add `palette` option to pngsave [felixbuenemann] - add basic nifti load/save support - support writing string-valued fields via libexif - paste in the test suite from pyvips - get EXIF tag names from tag plus ifd [@Nan619] - escape ASCII control characters in XML - magickload now sniffs some file types itself - update radiance load from upstream - add region_shrink to tiffsave - mapim could fail for float index images with coordinates out of int range - scale openexr alpha to 0 - 255 - close input earlier, when we can [kleisauke] - add vips_object_get_args() for language bindings [kleisauke] 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges [Adrià] - revise C++ example [fangqiao] - strict round down on jpeg shrink on load [davidwood] - configure test for g++ 7.2 and composite.cpp - don't Ping in magickload, too unreliable - ensure WebP can add metadata when compiled with libwebpmux [lovell] - improve accuracy of vector path convolution [felixbuenemann] 12/2/18 started 8.6.3 - use pkg-config to find libjpeg, if we can - better clean of output image in vips_image_write() fixes a crash writing twice to memory - better rounding behaviour in convolution means we hit the vector path more often - fix a crash if a delayed load failed [gsharpsh00ter] - icc_import attaches the fallback profile if it used it 5/1/18 started 8.6.2 - vips_sink_screen() keeps a ref to the input image ... stops a rare race - fix a minor accidental ABI break in 8.6.0 -> 8.6.1 [remicollet] - fix read of plane-separate TIFFs with large strips [remicollet] - fix a C++ warning in composite.cpp [lovell] - remove number of images limit in composite - composite allows 1 mode ... reused for all joins - fix race in vips_sink() for seq read 10/12/17 started 8.6.1 - fix mmap window new/free cycling - fix some compiler warnings - remove the 64-image limit on bandary operations - better version date [bmwiedemann] - bump wrapper script version [bgilbert] - fix a memleak on error during jpeg buffer write [lovell] - fix misspelling of IPTC as IPCT [lovell] - seq could be set on small images opened in random-access mode [aferrero2707] - fix small memleak in dzsave [lovell] - small speedup for rgb->g [lovell] 15/4/17 started 8.6.0 - supports fits images with leading non-image HDUs, thanks benepo - add vips_image_new_from_image() and vips_image_new_from_image1() ... make a constant image - add new_from_image() to Python as well - slight change to cpp new_from_image() to match py/C behaviour - vips_conv(), vips_compass(), vips_convsep() default to FLOAT precision - add FORCE resize mode to break aspect ratio - add vips_thumbnail_image() - better prefix guessing on Windows, thanks tumagonx - savers support a "page_height" option for multipage save - rename 'disc' as 'memory' and default off - add vips_find_trim(), search for non-background areas - remove lcms1 support, it had bitrotted - `join` tagged as seq - support tiffsave_buffer for pyramids, thanks bubba - thumbnail and vipsthumbnail have an option for rendering intent, thanks kleisauke - set file create time on Windows, thanks dlong500 - remove python tests ... moved to pyvips test suite - vips7 and vips8 python bindings default to off ... use the new pyvips binding instead - better svgload: larger output, handle missing width/height, thanks lovell - add vips_gravity() ... embed, but with direction rather than position - vips_text() can autofit text to a box, thanks gargsms - add vips_composite() / vips_composite2(): merge a set of images with a set of blend modes - better gobject-introspection annotations, thanks astavale - vips_image_write() severs all links between images, when it can ... thanks Warren and Nakilon - vector path for convolution is more accurate and can handle larger masks - linear and cubic kernels for reduce are higher quality - added vips_value_set_blob_free() - "--size Nx" to vipsthumbnail was broken, thanks jrochkind - fix build with gcc 7 - add vips_fill_nearest() ... fill pixels with nearest colour - add VIPS_COMBINE_MIN, a new combining mode for vips_compass() - vips_hist_find_indexed() now has a @combine parameter - vips_affine() and vips_similarity() have a "background" parameter - fix nasty jaggies on the edges of affine output, thanks chregu - add gif-delay, gif-comment and gif-loop metadata - add dispose handling to gifload - dzsave outputs extra right and bottom overlap-only tiles, for closer spec adherence - deprecate the "centre" option for vips_resize(): it's now always on - setting the EXIF data block automatically sets other image tags - add "extend" option to affine; resize uses it to stop black edges 29/8/17 started 8.5.9 - make --fail stop jpeg read on any libjpeg warning, thanks @mceachen - don't build enumtypes so often, removing perl as a compile dependency - fix a crash with heavy use of draw operations from language bindings, thanks @Nakilon 2/8/17 started 8.5.8 - fix transparency detection in merge, thanks Haida - define env var VIPS_WARNING to hide warning messages - shut down dzsave output earlier to help mark-sweep bindings - fix webp thumbnail upscale, thanks Kleis 9/6/17 started 8.5.7 - better smartcrop - transform cmyk->rgb automatically on write if there's an embedded profile and the saver does not support cmyk - fix DPI mixup in svgload ... we were writing images about 20% too large, thanks Fosk 19/5/17 started 8.5.6 - tiff read with start page > 0 could break edge tiles or strips - raise b64 limit to allow for huge profiles (thanks jaume) - fix error return in blob save (thanks jaume) - tag vipsprofile as py2 (thanks ioquatix) - don't cache thumbnail (thanks tomasc) 23/4/17 started 8.5.5 - doc polishing - more improvements for truncated PNG files, thanks juyunsang - improve corrupted jpg handling, thanks juyunsang - fix small test suite issues on os x 23/4/17 started 8.5.4 - don't depend on image width when setting n_lines, thanks kleisauke 7/4/17 started 8.5.3 - more link fixing in docs - revise cache sizing again to help out of order errors under heavy load, thanks kleisauke 25/3/17 started 8.5.2 - better behaviour for truncated PNG files, thanks Yury - missing proto for vips_tiffsave_buffer(), thanks greut - move some docs from the wiki and blog into core libvips docs - add support for markdown in docs 25/3/17 started 8.5.1 - init more classes earlier, thanks David 13/10/16 started 8.5.0 - rewritten buffer system is safer and frees memory earlier - added tiff save to buffer - added dzsave save to buffer (zip only) - revise header get/set functions - better vipsheader behaviour with complex field types - added vips_image_hasalpha() - added vips_thumbnail() / vips_thumbnail_buffer() - webpload/webpsave read and write icc, xmp, exif metadata - better >4gb detect for zip dzsave output [Felix Bünemann] - all loaders have a @fail option, meaning fail on first warning, though it only does anything for jpg and csv - add vips_image_get_fields() to help bindings - add tiff multi-page read/write - add VIPS_META_PAGE_HEIGHT metadata - IM6/IM7 magickload supports page/n/page-height, all_frames deprecated - gifload supports n/page-height - added #defines for VIPS_SONAME, VIPS_LIBRARY_CURRENT, VIPS_LIBRARY_REVISION, VIPS_LIBRARY_AGE - better support for bscale / bzero in fits images - deprecate vips_warn() / vips_info(); use g_warning() / g_info() instead - vipsthumbnail supports much fancier geometry strings, thanks tomasc - vips_thumbnail() has new @size option - fix --vips-cache-max etc. - add compute reordering, plus some new API to support it: vips_reorder_margin_hint() and vips_reorder_prepare_many(), thanks aferrero2707 - kick load operations from cache on read error, thanks gaillard - fix return from C++ assignment operator overloads (+=, -= etc) - add @max_slope to vips_hist_local() to implement CLAHE, thanks hunter-87 - vips_gaussnoise() pixels are reproducible on recalc, thanks MvGulik - max/min sort values by y and x coordinate - tiff read uses libtiff scanline API if rows-per-strip is large - vips_region_shrink() knows about alpha, helps dzsave and tiffsave - use expat, not libxml, for XML load ... removes a required dependency, since we get expat as part of glib - new sequential mode infrastructure is faster and more flexible - add vips_smartcrop(), based on sharp's smartcropper - vipsthumbnail has a --smartcrop option - added vips_rot90() etc. convenience functions - fix vips_resize() bug when hscale and vscale were very different 8/12/16 started 8.4.5 - allow libgsf-1.14.26 to help centos, thanks tdiprima 11/11/16 started 8.4.4 - fix crash in vips.exe arg parsing on Windows, thanks Yury 18/10/16 started 8.4.3 - fix error detection in gif_close, thanks aaron42net - fix tiny threading memleak - improve compatibility with very old glib, see #548 27/9/16 started 8.4.2 - small doc improvements - fix error message for metadata fetch type mismatch - resolve a race condition in thread shutdown, thanks Lovell 1/5/16 started 8.4 - many more wepsave options [Felix Bünemann] - added quant_table option to wepsave [Felix Bünemann] - added @n option to pdfload, thanks andris - dzsave won't write empty tiles in google mode, thanks bverem, perog, felixbuenemann - allow nested [] in CLI args - restore BandFmt on unpremultiply in vipsthumbnail - better python detection and build [Felix Bünemann] - max-alpha defaults to 65535 for RGB16/GREY16 - added radsave_buffer [Henri Chain] - support tiff orientation tag - autorotate option for tiff load - tiffsave converts for jpg if jpg compression is turned on - tiffsave supports --strip - conversions to GREY16 could lock - free pixel buffers on image close as well as thread exit ... stops main thread buffers clogging up the system - dzsave can write compressed zips [Felix Bünemann] - vips_image_write() only refs the input when it has to ... makes it easier to combine many images in bounded memory - VImage::write() implementation was missing - VImage::write() return value changed from void to VImage to help chaining - added C++ arithmetic assignment overloads, += etc. - VImage::ifthenelse() with double args was missing =0 on options - better accuracy for reducev with smarter multiplication - better quality for vips_resize() with linear/cubic kernels - pyvips8 can create new metadata - better upsizing with vips_resize() - add imagemagick v7 support, thanks sachinwalia2k8 - added vips_worley(), vips_perlin() noise generators - added vips_convf(), vips_convi(), vips_convasep(), vips_conva() ... im_conv*() functions rewritten as classes - vips_convsep() calls vips_convasep() for the approximate case - new fixed-point vector path for convi is up to about 2x faster - gif loader can make 1, 2, 3, or 4 bands depending on file contents - support --strip for pngsave - add svgz support [Felix Bünemann] - rename bootstrap.sh -> autogen.sh to help snapcraft - support unicode filenames on Windows - added VIPS_ROUND as well as VIPS_RINT - resize/reduce*/shrink*/affine now round output size to nearest rather than rounding down, thanks ioquatix - better support for tile overlaps in google maps mode in dzsave - dzsave puts vips-properties.xml in the main dir for gm and zoomify layouts - resize and reduce have @centre option for centre convention downsampling - vipsthumbnail uses centre convention to better match imagemagick _ add vips_foreign_get_suffixes() 19/8/16 started 8.3.4 - better transparency handling in gifload, thanks diegocsandrim 30/7/16 started 8.3.3 - fix performance regression in 8.3.2, thanks Lovell - yet more robust vips file reading 18/5/16 started 8.3.2 - more robust vips image reading - more robust tiff read [Matt Richards] 15/4/16 started 8.3.1 - rename vips wrapper script, it was still vips-8.2, thanks Benjamin - export C++ operator overloads for MSVC linking [Lovell] - fix magickload @page with GraphicsMagick - add giflib5 support - allow resize >1 on one axis, <1 on the other - vips_resize has an optional @kernel argument - fix giflib4 detection [felixbuenemann] 29/1/16 started 8.3 - add vips_reduce*() ... a fast path for affine downsize - vips_resize() uses vips_reduce() with lanczos3 - bicubic is better on 32-bit int images - add pdfload, svgload, gifload for PDF, SVG and GIF rendering - vipsthumbnail knows about pdfload and svgload - added @page param to magickload - matload is more specific (thanks bithive) - lower mem use for progressive jpg decode - sharpen has a new @sigma param, @radius is deprecated - sharpen allows a much greater range of parameters - sharpen defaults now suitable for screen output - better handling of deprecated args in python - much better handling of arrayimage command-line args - faster hist_find (Lovell Fuller) - webpload has a @shrink parameter for shrink-on-load - vipsthumbnail knows about webp shrink-on-load - better behaviour for vips_cast() shift of non-int types (thanks apacheark) - python .bandrank() now works like .bandjoin() - vipsthumbnail --interpolator and --sharpen switches are deprecated - switches to disable PPM, Rad and Analyze support - added VIPS_COUNT_PIXELS(), overcomputation tracking - @out_format in vips_system() can contain [options] - webpsave_buffer no longer ignores @lossless, thanks aaron42net - float tiff tagged as scRGB to match photoshop convention, thanks Murat - better jpeg autorot, thanks otto 24/3/16 started 8.2.4 - fix nohalo and vsqbs interpolators, thanks Rafael 27/1/16 started 8.2.3 - fix a crash with SPARC byte-order labq vips images - fix parsing of filenames containing brackets, thanks shilpi230 - fix hist_entropy (lovell) - small fixes to radiance load 12/1/16 started 8.2.2 - changes to ease compiling C++ binding with MSVC [Lovell Fuller] - reorder file tests to put slow loaders last - ifthenelse needs less C stack during eval - better rounding in bilinear interpolator - fix to "make check" in non-C locales [felixbuenemann] - use compiler builtins isnan, isinf, fabs, fmin, fmax, ceil, floor when possible [Lovell Fuller] - tune vips_shrinkh(), 30% faster [Lovell Fuller] - remove SEQ hint from vips_subsample(), fixes cli performance [erdmann] - fix double free on attach ICC profile from file in tiff write [erdmann] - use g_assert_not_reached() - better vips-from-C docs - remove Duff from im_conv() / im_conv_f() for a 25% speedup [Lovell Fuller] 1/1/16 started 8.2.1 - add a compat stub [Benjamin Gilbert] - python bandjoin is now just an instance function - small doc improvements - small vips7 C++ improvement - remove exception specifications from vips8 C++ interface [Lovell Fuller] - VImage::get_typeof() now returns GType 7/10/15 started 8.2.0 - added im_bufmagick2vips(), a vips7 wrapper for magick load from buffer - fetch unset property now returns default value rather than warning - many more const declarations to help gobject-introspection - rewritten vips_shrink() is 2x faster, much lower memuse, now handles complex - only allow [] for filename options - add memory.h to Python API .. makes tracked highwater visible - added bandjoin_const to add constant bands to an image - better alpha handling for tiff write, thanks sadaqatullahn - better cache sizing for vips_resize() - sizealike / formatalike / bandsalike elide completely if they can for a x2 saving in C stack use in many cases - added vips_mapim() ... resample with an index image, plus test - try to improve vips_resize() quality a little more - vips_resize() can do non-square resizes - dzsave removes tile metadata by default, thanks Benjamin - jpeg strip option removes a little more, thanks Benjamin - added vips_image_new_from_memory_copy() - improve vips_sink_screen() stability under heavy load - added vips_arrayjoin() - Python x.bandjoin(y) is now x.ibandjoin(y), sorry - faster and lower-mem TIFF read - faster bilinear interpolator - TIFF loads and saves IMAGEDESCRIPTION - add --properties flag to tiffsave - dzsave defaults changed: now writes 256x256 jpegs for non-edge tiles, thanks Daniel 7/5/15 started 8.1.1 - oop, vips-8.0 wrapper script should be vips-8.1, thanks Danilo - fix vips7 pathname parsing on windows, thanks Lovell 7/5/15 starteld 8.1.0 - add vips_premultiply(), vips_unpremultiply() - change the alpha range rules for vips_flatten() to match vips_premultiply() - vipsthumbnail uses vips_resize() rather than its own code - vipsthumbnail uses vips_premultiply() for better alpha quality - added bandand() bandor() bandeor() convenience funcs to Python - oops, base64 encode could pad by up to two zero bytes - added VipsRefString as a thing that gi bindings can unpack - support "with Vips.Image as i:" in Python - try to support DOS CSV and PPM files on linux - add vips_byteswap(), remove byteswap option from vips_copy() - add vips_bandfold()/vips_bandunfold() - dzsave supports zip output > 4gb, thanks benjamin - add support for HSV colourspace [Jonas Øgaard] - skip oversized markers in jpeg write - jpeg exif tags saved as name rather than title - can now set any jpeg exif tag, not just modify existing tags - add vips_hist_entropy() - vips_log(), vips_log10() are zero-avoiding - better overlap handling for dzsave, thanks robclouth - add @spacing option to vips_text() - tiff loads and saves IPCT and Photoshop data 7/5/15 started 8.0.3 - dzsave and tif pyr write could fail for some image dimensions, thanks Jonas 4/5/15 started 8.0.2 - fix a refcount error in C++ wrapper, thanks huskier - better C++ api test - test suite improvements - remove a couple of stray header decls, thanks benjamin 25/4/15 started 8.0.1 - fix some compiler warnings - work around a glib bug that can cause segv under load - add some notes on threading to the docs - better leak reporting 11/2/15 started 8.0 - remove old doc stuff, lots of doc improvements - add fliphor(), flipver(), rot90(), rot180(), rot270(), median(), dilate(), erode() convenience methods to Python and C++ - python: use [] to index and slice image bands, use () to get a point - c++: use [] to band index, () returns a vector - add shift option to cast - sRGB2scRGB and scRGB2sRGB scale 16-bit alpha to and from 8-bit - add magickload_buffer() [mcuelenaere] - add vips_foreign_is_a_buffer() [mcuelenaere] - added test_foreign.py, plus more test images - added vips_region_shrink(), fast x2 shrinker - rewritten tiff writer is about 3 - 4x faster at making pyramids - jpg, magick, png, tiff readers now use only 1 fd per input image - added vips_info_set(), vips_progress_set(), vips_profile_set() ... bindings can now support all the vips command-line options if they wish - better conversion to greyscale, thanks bkw - add vips_image_copy_memory(), improves stability with heavy threading - jpegsave supports new mozjpeg features [lovell] - add vips_vipsload(), vips_vipssave() ... why not 26/3/15 started 7.42.4 - im_maxpos_avg() avoids NaN - small tiffsave doc improvements - better thresholding for tiffsave "squash" mode - add @miniswhite mode to tiffsave 6/2/15 started 7.42.3 - bump version for back-compat ABI change - added vips_image_memory(), an alias for vips_image_new_memory() - improvements to configure for python - remove --disable-cxx configure flag - python imageize preserves interpretation - fix dzsave as a target format 30/12/14 started 7.42.2 - C++ required output params were broken, thanks Lovell - remove VImage::scale() to get scale from header, it clashed with the VipsScale operator, thanks Lovell - allow c++ set enum from string - display param default and range in usage - better docs - more tests - renamed VIPS_FOREIGN_DZ_DEPTH_1 as VIPS_FOREIGN_DZ_DEPTH_ONE etc. to help bindings - vipsthumbnail will return an error code if one or more conversions failed - disable chroma subsample in jpeg-tiff if Q >= 90 - try to handle tiffs with old-style 8-bit colormaps - rename vipsthumbnail -o as -f, -o stays as a hidden flag - fix some small leaks - faster openslide load, thanks Benjamin - add VInterpolate class to cplusplus binding, thanks Lovell - add lower-level operation cache access - turn on leak testing in test suite - don't use isnormal() to test for crazy FP numbers, thanks Murat - much faster RGB16 -> sRGB path 24/12/14 started 7.42.1 - add gobject-2.0 to Requires: in vips and vips-cpp .pc files - bump soname - fix VipsBlob read - remove "future" dependency, thanks bgilbert 4/11/14 started 7.42.0 - better default resolution for png load - better pbm (one bit) load, better pfm (float) load/save - added pbm (one bit) save - changed vips_gaussblur() parameters, sorry - add .szi as a dzsave zip synonym - support tiff XMP metadata - support @density arg to magickload [Lovell] - support python3.4 and python2.7 in new python binding - vips_gaussmat() and vips_logmat() are now int by default, to match vips_conv(), and use @precision, not @integer - added --disable-pyvips8 switch to turn off new py binding - "vips thing" exit status can now be used to test for optional components 25/7/14 started 7.41.0 - start working on --disable-deprecated - fix pngload with libpng >1.6.1 - add vips_resize() - return of vips_init(), but just for bindings - revised type.c to make it more binding-friendly - add @background arg to save: the colour to flatten against - add VIPS_ARGUMENT_MODIFY flag ... used for draw_circle etc, meaning an op which modifies its argument - rename VIPS_OPERATION_RELATIONAL_NOTEQUAL as VIPS_OPERATION_RELATIONAL_NOTEQ for consistency - python vips8 binding - python vips8 test suite: test_arithmetic.py, test_colour.py, test_conversion.py - move zoomify ImageProperties file, now a better match to the official tool - rename VIPS_ANGLE_180 as VIPS_ANGLE_D180 etc. to help python - remove cimg support, we have a gmic plugin now instead - add support for vips8 plugins - added "autorotate" option to jpeg load - added autorot operator - added @filter option to pngsave (Lovell) - C++ vips8 binding 27/10/14 started 7.40.12 - better tiff detection (Lovell) - fix memleak in sharpen (Lovell) - fix profile handling in XYZ2scRGB, thanks Lovell 8/10/14 started 7.40.11 - rework extra band handling for colour functions - set interpretation of matlut output more carefully 8/9/14 started 7.40.10 - icc_import and icc_transform checks the input profile for compatibility with the image, thanks James - try to make vips_thread_shutdown() optional 8/9/14 started 7.40.9 - support jfif resunit "none" - support GRAY as an input and output ICC space - fix a read loop with setjmp() in png read, if the png file is broken - fix vipsthumbnail with both input cmyk and output rgb profiles specified - vipsthumbnail retries with specified input profile if embedded profile is broken - add @profile option to pngsave, matching tiff and jpeg - fix a race in the operation cache [Lovell] 8/9/14 started 7.40.8 - fix configure on rhel6 [Lovell] - mono <-> rgb converters were not handling extra bands, thanks James - support jpeg resunit "none" 21/8/14 started 7.40.7 - width and height were swapped in matlab load - set interpretation more carefully on matlab load - fix memleak in tilecache [Lovell] - fix memleak in VipsArray [Lovell] - fix memleak in webp load from buffer [Lovell] - fix memleak in png save to buffer [Lovell] - make out of order read in png and jpg a fatal error - add thread_shutdown() to C++ (and thereby to python) 12/8/14 started 7.40.6 - more doc fixes - fix similarity rotate+scale, thanks Topochicho - fix 16-bit PNG save, thanks John - fix dzsave date on Windows, thanks John - fix vipsthumbnail on many-core systems, thanks James 25/7/14 started 7.40.5 - fix a race in im_maxpos_avg() - limit n_thr on tiny images - don't exit() on memleak detected, just warn - add "autocrop" option to openslide load - argh fix affine, again, there were sometimes black bars with nohalo and the vips8 interface - pngsave in interlaced mode makes a copy of the image, so it's always seq - vipsthumbnail shrinks to 1/2 window_size - vipsthumbnail has an anti-alias filter between shrink and affine - vipsthumbnail defaults to bicubic - better rounding behaviour for fixed-point bicubic reduces noise - fix pngload with libpng >=1.6.11 - fix colour for openslide read associated 4/7/14 started 7.40.4 - fix vips_rawsave_fd(), thanks aferrero2707 - fix im_point() - vips_scale() now does round to nearest to avoid rounding errors - improve im_openout() compat macro - more vips7 compatibility fixes, thanks steve - more robust vips_system() - add webp support to vips7 30/6/14 started 7.40.3 - fix interlaced thumbnails in vipsthumbnail, thanks lovell - fix use of "header" in benchmark/, thanks David - fits save now caches the image before write, so it's top-to-bottom - add --properties argument to dzsave, thanks bgilbert, jhenriksen 25/6/14 started 7.40.2 - dzsave write to zip stops at 4gb, thanks bgilbert - improve short option name handling, thanks bgilbert - added --enable-docs configure option to help freebsd - removed a bash-ism from configure to help freebsd - don't assume GType fits in an int to help freebsd 24/6/14 started 7.40.1 - revise man.1 pages - fix vips_guess_prefix() 23/6/14 started 7.40.0 - version bump - renamed "header" as "vipsheader" and "edvips" as "vipsedit" 21/1/14 started 7.39.0 - auto-decode for (almost) all operations, see vips_image_decode() - background render thread cleans up and quits neatly - colourspace has a source_space option - operations can be tagged as "deprecated" - redo im_draw_circle(), im_draw_flood(), im_draw_line(), im_draw_mask(), im_draw_image(), im_draw_rect(), im_draw_point(), im_read_point(), im_draw_smudge(), im_label_regions() as classes - better rounding in vips_flatten() - VipsStatistic operations are sequential - vipsthumbnail has --rotate auto-rotate option - removed embedded thumbnail reader from vipsthumbnail: embedded thumbnails are too unlike the main image - fix to vipsthumbnail --crop, thanks Alessandro - add vips_sum() - add vips_hough base class and vips_hough_line() - add "mode" param to vips_draw_image() - add vips_hough_circle() - reduce default cache size to 1,000 operations - added "postbuild" signal - vips_system() now supports many input images and you can change image argument order - support 16-bit palette TIFFs, plus palette TIFFs can have an alpha - libgsf-1 is now an optional dependency - dzsave can directly write a ZIP file - add ".vips" as an alternative suffix for vips files - added vips_tiffload_buffer() - added vips_image_new_from_buffer(), vips_image_write_to_buffer() - added vips_object_set_from_string() - added @container option to dzsave - support 1/2/4 bit palette tiff images with alpha - vips_system() now uses g_spawn_command_line_sync() - added im_tile_cache_random() to help nip2 - added hough_circle() to vips7 C++ API - added Travis CI config, thanks Lovell - im_*merge(), im_*mosaic(), im_match*(), im_global_balance*(), im_remosaic(), im_*mosaic1(), im_*merge1() redone as classes - better filename tracking for globalbalance - revised vips8 image load/save API, now simpler and more logical - operations emit "invalidate" if any of their input images invalidate - operation cache drops ops on invalidate - skipahead is back, thanks to a new threadpool tweak 6/3/14 started 7.38.6 - grey ramp minimum was wrong - vipsthumbnail --crop could fail for very non-square images, thanks Alessandro - fix a crash in vips_rawsave(), thanks Andrea - updated German translation, thanks Chris - fix coordinate error in affine, thanks ferryfax 24/2/14 started 7.38.5 - jpeg load from buffer could write to input, thanks Lovell - fix webpload from buffer, thanks Lovell - vips_sequential() could fail under heavy load - remove support for seq mode read for operations like extract 13/2/14 started 7.38.4 - --sharpen=none option to vipsthumbnail was broken, thanks ferryfax - more locking on property create and lookup to help very-threaded systems, thanks Nick 22/1/14 started 7.38.3 - undeprecate VIPS_MASK_IDEAL_HIGHPASS and friends, ruby-vips was using them, thanks ahacking 22/1/14 started 7.38.2 - auto RAD decode for affine - falsecolour was not working for some image types - foreign memory buffer images did not have the right dhint, broke command-line falsecolour on sequential images - support many Radiance readers active at once - add secret "rgbjpeg" flag to vips_tiffsave() to help IIP 19/1/14 started 7.38.1 - bump soname, thanks benjamin - better conversion to and from scrgb/xyz for rad (hdr) - fix --interpolate flag to vipsthumbnail, thanks Lovell 18/1/14 started 7.38.0 - version bump 19/10/13 started 7.37.0 - redone im_rotate_*mask45(), im_gauss_*mask*(), im_log_*mask(), im_dilate(), im_erode(), im_rank_image(), im_compass(), im_linedet(), im_gradient(), im_convsep(), im_convsep_f(), im_fastcor(), im_spcor(), im_sharpen() as classes - im_gradcor() deprecated - vips_init() now does some ABI compat checking, though this change requires an ABI break - add "interlace" option to vips_jpegsave() - remove vips_image_copy_fields() and vips_demand_hint() and add vips_image_pipeline() to do both jobs - vipsthumbnail allows non-square bounding boxes, thanks seth - add vips_matrixprint() - add @point subsample mode to vips_subsample() - im_contrast_surface() deprecated: it was slower than calling conv a few times - radiance load supports sequential read - rewritten radiance decode is much faster - add vips_crop(), a synonym for vips_extract_area() - rename vips_gammacorrect() as vips_gamma(), now takes 1 / exp - vips_gamma() works for any format - add --linear mode to vipsthumbnail - support XYZ as a PCS for vips_icc_import() and vips_icc_export() - add --strip option to jpegsave - added vips_gaussblur() convenience function - added --vips-profile, records and dumps thread timing and memory use info - added vipsprofile, visualises --vips-profile output - auto-vectorization-friendly inner loops - added vips::init() and vips::shutdown() to C++ API - reuse pixel buffers on sharing to reduce mem cycling - conv is SMALLTILE, huge mem use saving on wide images - vipsthumbnail has a --crop option - remove video4linux1 code, it was useless on all modern linuxes - redone freq filter builders as classes - redone im_fwfft(), im_invfft(), im_freqflt(), im_disp_ps(), im_fractsurf(), im_phasecor() as classes - vips_colourspace() allows B_W, GREY16, RGB16 as source / target - added vips_thread_shutdown(), thanks Lovell - vips_linear() has a uchar output mode - redone im_cntlines(), im_rank() as classes - move im_zerox() to deprecated, it wasm't very useful 9/1/14 started 7.36.6 - fix some clang compiler warnings 20/11/13 started 7.36.5 - better cache sizing in unbuffered sequential mode - allow larger tile_size in dzsave - remove use of PATH_MAX to help gnu hurd - fix vips_hist_match() 15/11/13 started 7.36.4 - improve compat with im_init_world() 18/10/13 started 7.36.3 - fix compiler warnings in ubuntu 13.10 - reverse similarity rotation direction to match the convention used elsewhere in vips - fix blocked caching of sequential load operations - fix cache flags - fix --delete option to vipsthumbnail 10/10/13 started 7.36.2 - better jpeg startup - rename jpeg bool type to reduce confusion between libraries 3/10/13 started 7.36.1 - fix to help OS X build 3/10/13 started 7.36.0 - version bump 1/7/13 started 7.35.0 - added vips_matrixload() and vips_matrixsave(), load and save vips mat format - rename image arrays as image matrices ... INTERPRETATION_ARRAY -> INTERPRETATION_MATRIX etc. - rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(), im_gammacorrect(), im_histgr(), im_histcum(), im_histnorm(), im_heq(), im_histnD(), im_histindexed(), im_histspec(), im_invertlut(), im_lhisteq(), im_stdif(), im_project(), im_profile(), im_tone_build*(), im_mpercent*(), im_ismonotonic() as classes - vips_hist_local(), vips_stdif() do any number of bands - thin vips8 wrapper for im_histplot() - added vips_error_freeze() / vips_error_thaw() - used freeze() / thaw() to stop file format sniffers logging spurious errors - vipsthumbnail uses embedded jpg thumbnails if it can - rename vips_diag() as vips_info(), add --vips-info flag - deprecate im_hsp() - added vips_webpload(), vips_webpload_buffer(), vips_webpsave(), vips_webpsave_buffer(), vips_webpsave_mime() - tiff reader allows separate planes for strip read - tiff reader and writer allow many more formats, eg. 32-bit int, complex, etc. - tiff reader and writer allow any number of bands - added vips_image_new_matrixv() - dzsave basename param now called filename, so you can use .dz as a destination (basename is still there but deprecated) - new _UNBUFFERED sequential mode saves memory in some important cases - vips_conv() is a simple wrapper over the old convolution functions - new optimize_coding param for jpeg write produces optimal Huffman tables, thanks Lovell - im_tone_map() and im_tone_analyse() deprecated - new --band arg to vips_maplut() replaces im_tone_map() functionality - added vips_similarity(), simple wrapper for vips_affine() that lets you give a scale and rotate 3/7/13 started 7.34.2 - lower priority for Matlab load to reduce segvs from Mat_Open(), thanks Michael - null-terminate libexif strings, thanks Mike - openslide always outputs solid pixels 28/6/13 started 7.34.1 - fix morphological operators on non-uchar images - remove any ICC profile when we use vips to go to srgb 7/6/13 started 7.34.0 - version bump - oops, VImage.PIL_mode_from_vips() failed for CMYK, thanks Alessandro - fix no-pango build - add im_vips2dz(): run the deepzoom writer from vips7 - vips_magickload() has an option to read all images in a sequence - redo im_make_xy(), im_*eye(), im_zone*(), im_sines() as classes - added vips_pngload_buffer() - faster --centre option to dzsave, thanks Kacey 12/3/13 started 7.33.0 - vipsthumbnail lets you specify the sharpening mask - turn off caching for im_copy()/vips_copy(), we use copy to stop sharing, and it's cheap so caching doesn't help anyway - auto rshift down to 8 bits on save, if necessary - im_gaussnoise(), im_copy_file(), im_grid(), im_scale(), im_scaleps(), im_wrap(), im_rotquad(), im_zoom(), im_subsample(), im_msb(), im_text(), im_system(), im_system_image() redone as classes - add --angle option to dzsave - another vips_shrink() fix argh 14/5/13 started 7.32.4 - icc import and export could segv on very wide images - fix centos 5 build, thanks re-boot 16/4/13 started 7.32.3 - rename GETTEXT_PACKAGE as vips7.32 to help Debian (thanks Jay) - added "persistent" option to tilecache 12/3/13 started 7.32.2 - removed some left-over debugging code from configure.ac - better handling of args without values, thanks Ruven - better error messages from vips.c - fix demand hints so "vips shrink" works again, thanks Jan - im_jpeg2vips.c builds without jpeglib.h, thanks Alessandro 6/2/13 started 7.32.1 - fix --without-lcms, thanks speckins - updates to licence, thanks Benjamin - remove "fred" from dist - better bootstrap on OS X 22/1/13 started 7.32.0 - tilecache in threaded mode could deadlock if the downstream pixel source raised an error (thanks Todd) - fix another dzsave corner-case (thanks Martin) - neater output for "header" - added VIPS_META_LOADER: record the loader name = header displays this loader hint - vipsthumbnail is better at cache sizing 31/8/12 started 7.31.0 - redone im_Lab2XYZ(), im_XYZ2Lab(), im_Lab2LCh(), im_LCh2Lab(), im_UCS2LCh, im_LCh2UCS(), im_XYZ2Yxy(), im_Yxy2XYZ(), im_float2rad(), im_rad2float(), im_Lab2LabQ(), im_LabQ2Lab(), im_Lab2LabS(), im_LabS2Lab(), im_LabQ2LabS(), im_LabS2LabQ(), im_LabQ2disp(), im_XYZ2disp(), im_disp2XYZ(), im_icc_import*(), im_icc_export*(), im_icc_transform*(), im_dE_fromLab(), im_dECMC_fromLab(), im_dE00_from_Lab(), im_icc_ac2rc() as classes - added vips_colourspace(), vips_colourspace_issupported(), replaces all derived conversions - faster and more accurate sRGB <-> XYZ conversion - support 16-bit sRGB import and export - rename UCS colourspace as CMC - dzsave can write zoomify and google maps layout as well - tilecache supports threaded access, so openslide read now threads - openslide2vips gets underlying tile size from openslide - embed has 'background' option - dzsave --layout google has a @background option - dzsave has a --depth option - update for new glib threading API - remove no threads option, glib no longer support it - better --help output for vips driver prog - vipsthumbnail -o allows absolute file names - much better exif handling for jpg images (thanks Gary) - preserve jpeg app13 (photoshop ipct) - vips_max() / _min() track the top n maxima / minima - deprecate im_maxpos_avg(): too specialised to be worth maintaining - deprecate im_linreg(): easily done by combining other operators - deprecate im_point(): easily done by combining other operators - add binary complex operations, with cross_phase as the only one so far - added vips_bandbool(), with vips_bandand(), _bandor(), _bandeor() as convenience functions - added scRGB colourspace, linear light float space with sRGB primaries - all interpolators use corner convention ... we had round-to-nearest in several of them before, causing a range of annoying problems - redone im_affine*() as a class - added input space displacement to affine - VipsArea is threadsafe - dzsave has a --centre option 31/12/12 started 7.30.8 - png icc profile write was broken 31/12/12 started 7.30.7 - better option parsing for "vips", thanks Haida - small fixes to help OS X - backported threaded tile cache from next version, im_tile_cache() now uses it to prevent a deadlock, see comment there 14/11/12 started 7.30.6 - capture tiff warnings earlier 14/11/12 started 7.30.5 - fix libtool version mess up (thanks Benjamin) 2/10/12 started 7.30.4 - remove options from format string in .dzi (thanks Martin) - vipsCC.pc required the wrong version of vips (thanks Alessandro) - larger max tile size for dzsave - linecache is 50% larger to leave some slop room 13/9/12 started 7.30.3 - linecache sized itself too large - fix a compile failure if libtiff was not found (thanks Martin) - dzsave did not work for images with an odd number of scanlines (thanks Martin) 4/9/12 started 7.30.2 - sequential stops all threads on error - sequential delays ahead threads rather than blocking them completely 6/8/12 started 7.30.1 - fixes to dzsave: shrink down to a 1x1 pixel tile, round image size up on shrink, write a .dzi file with the pyramid params, default tile size and overlap now matches the openslide writer - wrap VipsInterpolate for C++ - so affinei and affinei_all appear in Python - be more cautious enabling YCbCr mode in tiff write - add "DEPRECATED" flag to arguments - jpeg load/save note and use the preferred resolution unit - better error msgs for enum args - fix compiler warnings in production build (thanks Dmitry) - fix spurious warnings about exif updates - VipsSequential has an integrated cache and stalls out of order threads - add a line cache ... sizes up dynamically with request size - tilecache / linecache use a hash table not a linear list 20/7/12 started 7.30.0 - support "rs" mode in vips7 - add --vips-version cmdline arg - fix --without-tiff / exr / jpeg / png / magick - add --vips-fatal flag 19/3/12 started 7.29.0 - sanity-check PNG read geometry - nearest-neighbor interpolation rounds coordinates to nearest instead of rounding down (thanks Nicolas) - add dzsave, save in deep zoom format - rework im_shrink() as a class - remove im_rightshift_size(), just a convenience function now - vipsthumbnail no longer removes profiles by default - much more gentle sharpening in thumbnails - added "minimise" signal, used by tilecache to drop - add :seq support to im_tiff2vips(), im_jpeg2vips() ... helps ruby-vips - better thread safety for vips8 operation dispatch - better thread safety for upstream / downstream image linking - added "rs" open mode, removed "rd" - added vips_operation_get_flags() ... system for attaching sets of flags to operations - added VIPS_OPERATION_SEQUENTIAL flag - vips8 command-line interface uses this to turn sequential mode on automatically when possible - better handling of input files in vips7 command-line interface - sequential can skip ahead, so extract / insert are now seq 16/7/12 started 7.28.10 - wopconst was broken - vips_sign() was broken - png save compression range was wrong - more/moreeq was wrong - vips7 ppm save with options was broken - don't cache write operations 18/6/12 started 7.28.9 - slightly more memory debugging output - remove references to the static bicubic interpolator from the docs - fix temp file handling on Windows --- was breaking for non-vips files over 100mb - better support for using images from multiple threads 18/6/12 started 7.28.8 - fixes for centos5 portability 18/6/12 started 7.28.7 - add vips_flatten() -- flatten RGBA to RGB - better alpha handling in PNG load - don't save RGBA PNG as CMYK JPG (thanks Tobsn) - fix a crash with malformed jpg files (thanks Grigoriy) - vipsthumbnail enables sequential mode more and caches lines better 19/4/12 started 7.28.6 - better resolution unit handling in deprecated im_vips2tiff() - use TIFF_CFLAGS output from pkg-config (thanks Jay) - much faster vips_argument_map() - make jpeg pyramids work with tiff4 - tiff loader always offers THINSTRIP (thanks Diuming) - add "nocache" operation flag, set for sequential load (thanks Diuming) - fix a crash in the tiff reader for huge values of RowsPerStrip (thanks Nicolas) - remove use of G_DEFINE_BOXED_TYPE() to help compat (thanks Jake) 19/4/12 started 7.28.5 - ifthenelse blend mode was broken - small blend speedup - default to libtiff-4 17/4/12 started 7.28.4 - up max buffer size for vipsbuf 6/4/12 started 7.28.3 - vips_divide() failed for int arguments - fix warning for unused vips7 gvalue argument - fix openslide read: always return png-style rgba, im_argb2rgba() becomes a NOP - cast to unsigned int now removes <0 values - vips7 interface to openslide now supports :,level,associated options (thanks Benjamin) - make vips8 cache smaller - more accurate progress reporting 13/3/12 started 7.28.2 - xres/yres tiffsave args were broken 13/3/12 started 7.28.1 - add ICC profile read/write for png files 30/1/12 started 7.28.0 - version bump - added vips_foreign_find_save_options()/vips_foreign_find_load_options() - delayed write to foreign via a "w" image was not working - support operations with many returns in Python - sequential read mode - better im_shrink() - added vips_sequential() - new vips_sink_memory() keeps read ordering - tiff, jpeg, png readers support sequential read - max/min avoid NaN - oop, histnorm was broken by the new vipsstats - never use IM ping to get a header, fixes BMP load - set @filename for non-vips formats in vips7 compat layer - make Xres/Yres double - completely disable debug by default in production builds 20/8/11 started 7.27.0 - version bump for new dev cycle - im_subtract(), im_avg(), im_min(), im_minpos(), im_copy(), im_embed(), im_flophor(), im_flipver(), im_insert(), im_insert_noexpand(), im_lrjoin(), im_tbjoin(), im_extract_area(), im_extract_bands(), im_extract_areabands(), im_replicate(), im_clip2fmt(), im_gbandjoin(), im_bandjoin(), im_invert(), im_lintra(), im_lintra_vec(), im_black(), im_rot90, im_rot180(), im_rot270() im_sintra(), im_costra(), im_tantra(), im_asintra(), im_acostra(), im_atantra(), im_exptra(), im_exp10tra(), im_logtra(), im_log10tra(), im_abs(), im_sign(), im_max(), im_maxpos(), im_deviate(), im_divide(), im_multiply(), im_stats(), im_measure(), im_recomb(), im_floor(), im_ceil(), im_rint(), im_equal*(), im_notequal*(), im_less*(), im_lesseq*(), im_more*(), im_moreeq*(), im_remainder*(), im_and*(), im_or*(), im_eor*(), im_shift*(), im_pow*(), im_exp*(), im_ifthenelse(), im_blend(), im_c2amph(), im_c2rect(), im_bandmean(), im_c2real(), im_c2imag(), im_ri2c(), im_jpeg*2vips(), im_vips2jpeg*(), im_tiff2vips(), im_vips2tiff(), im_exr2vips(), im_fits2vips(), im_vips2fits(), im_analyze2vips(), im_raw2vips(), im_vips2raw(), im_magick2vips(), im_png2vips(), im_png2*(), im_ppm2vips(), im_vips2ppm(), im_mat2vips(), im_rad2vips(), im_vips2rad() redone as classes - added argument priorities to help control arg ordering - generate has a 'stop' param to signal successful early termination - added optional output args, eg. x/y for min - CLI supports optional output args - in im_vips2tiff, enable YCbCr compression for jpeg write - VipsMin stops search early if it can - C API supports optional output args - switch back to int-valued operations - add the operation cache, various --vips-cache-* flags - fallback vips_init() - vips_tracked_malloc() tracks allocation size and can report total mem usage - cache limits, drop, init, flush plus command-line controls - remove dmalloc support, was never used and valgrind is better - im_csv2vips() allows quoted strings, including escaped quotes - added vips_shutdown() - added --vips-leak flag - more VipsImage props - added vips_image_write(), old one becomes vips_image_write_to_file() - added vips_region_paint_pel() - added VipsArea as a public struct - added array members and arguments - added nary - remove VipsPool, vips_object_local_array() is much better - cache.c now drops if you have too many open files - CLI args to change max files - new format for handling exif tags - switch SMALLTILE to 128, 512 was just too big - oop mode "rd" was not always being used for images - added ARRAY interpretation for images - VipsStats tracks minpos/maxpos as well - moved mask/ to deprecated - use atexit() to call vips_shutdown() - set _O_TEMPORARY on delete-on-close temp images if possible - unlink temps on rewind on *nix, less likely to leave temps on a crash - added complex conj as a basic operation - rect/polar/conj work on any format, not just complex - new VipsFile system for load/save in image formats - options now introspectable, try "vips jpegsave" - copy swap uses glib byteswap macros, about 2x faster - edvips can change vips header byte ordering - "header" is terse by default - "header" outputs filenames if working on many files - added openslide support (Benjamin Gilbert) - allow new-style load/save options in filenames to vips_image_new_from_file() etc. - VipsFormat is deprecated - remove outchecks from documented API - support gobject-introspection - new Python binding based on gobject-introspection - only spot options at the end of arg strings - add vips_cache() as a vips8 operator - remove the old fft fallback - remove fftw2 support - much faster im_draw_smudge() 14/1/12 started 7.26.8 - interpolate CLI args were broken (thanks speckins) 5/12/11 started 7.26.7 - lazy read from tiled tiff from layers other than 0 was broken - optional args to vips_call*() do not work, disabled (fixed correctly in master) - address calculations in files over 4gb were broken on 32-bit platforms (broken since March 2011, oops) 12/10/11 started 7.26.6 - NOCACHE was not being set correctly on OS X causing performance problems with large files - update Orientation exif tag on jpeg write 12/10/11 started 7.26.5 - jpeg read/write copies over XMP data - handle offset correctly in separable convolutions (thanks Nicolas) - macros for class arg boilerplate - class arg order set by new 'priority' param - VipsExtend, VipsDirection enums added 12/9/11 started 7.26.4 - fallback vips_init() - im_openout() compat stub was wrong, breaking ruby-vips - vips_class_map_concrete_all() needed a compat macro too - vips_class_map_all() was broken 10/8/11 started 7.26.3 - don't use G_VALUE_COLLECT_INIT(), many platforms do not have a glib this recent - don't leave image->kill set when we detect termination - test for a working C++ compiler, disable C++ parts of none found 10/8/11 started 7.26.2 - oops, im_benchmark.c had some stuff turned off - configure option --without-cfitsio was broken (thanks Mike) 26/7/11 started 7.26.1 - doc fixups - oops, ==0 missing from a strcmp() in vips7compat - fixed a race in im_XYZ2Lab() table build - added im_concurrency_get() to operation db - better benchmarkn.sh runs for the correct number of CPUs automatically, runs three times for each one, and just reports the fastest 26/7/11 started 7.26.0 - version bunp for 7.26 - various fixes to get win32 and OS X building 6/12/10 started 7.25.0 - attach the jpeg thumbnail and multiscan fields (thanks Mike) - faster tiff read for some common cases - faster im_tile_cache() - if we use C++ in libvips, add -lstdc++ to vips-7.xx.pc - im_vips2png() / im_png2vips() set / get png resolution (thanks Zhiyu Wu) - updated README - don't use tables for bilinear on float data for a small speedup (thanks Nicolas Robidoux) - no tables for uchar either, about a 15% speedup (thanks Nicolas) - dmask write was broken - lr/tbmerge() cast images to match, like im_insert() - lr/tbmosaic() work for any mix of image formats / bands - removed ancient balance stuff from im_lr/tbmosaic() - gtk-doc for mosaicing - add im_fits2vips() to the operation database - im_fits2vips() is lazy and much faster - im__file_open_write() / _read() has a flag for text_mode, get rid of all the remaining fopen()s - move cooc_* and glds_* to deprecated - move im_dif_std() to almostdeprecated - move im_simcontr() to almostdeprecated - add im_sines() to operation db - move im_spatres() to almostdeprecated - done gtk-doc for other - --vips-progress tells you about nthreads, tile size, nlines - gtk-doc for interpolate - move im_stretch3() to deprecated - move im_clamp() to deprecated - gtk-doc for video ... all operators done! amazing argh - set MAP_NOCACHE on OS X, otherwise performance dives off a cliff with files larger than memory - removed man pages, we are all gtk-doc now - im_jpeg2vips() ignores weird APP1 chunks - im_add() for int/uint was broken - im_ri2c() was broken - added VIPS_FORMAT_BIGENDIAN format flag - moved IMAGE and REGION to VipsImage and VipsRegion, classes over VipsObject - Rect -> VipsRect - libpng-1.5 supported - better png read for 1-bit and palette images - fits write - better fits metadata support - renamed all header fields, old names still supported, hopefully - all of iofuncs moved to vips_ namespace - lots of old iofuncs API moved to deprecated - added VipsOperation, an abstract base class for all vips operations - added VipsAdd, the first operation object - im_tiff2vips() int/uint mixup for rows_per_strip, thanks Bubba - removed the links feature, won't work with vips8 - got rid of the tools/ subdirs - added im_bufjpeg2vips() - tiff reader can do 1, 2, 4, 8 bit palette images - tiff palette read can do mono images - im_bufjpeg2vips() has a "header_only" parameter - added vips_image_get_data() - updated German translation (thanks Chris) - fixed typo in im_conv() overflow estimation which could cause errors - vips.c has new action syntax, knows about vips8 operations - add now has sizealike - vips7 binops all do sizealike too, also gbandjoin and ifthenelse - new API is now functional - vips.c generates GOption flags for vips8 operations - added im_gauss_dmask_sep() - laplacian generator lost -ve lobes for large sigma - added im_aconv(), approximate convolution - bumped smalltile to 512x512 for testing - added VipsPool, got rid of floating refs again, argh - VIPS_EXEEXT is now part of the exported API - im_blend() also does sizealike, oops - jpeg write was not inverting CMYK, thanks Ole - im_falsecolour() converts to mono 8-bit for you - im_icc_import*/export*() cast inputs for you - im_vips2tiff() uses im__temp_name() for intermediates - added vips_wrap7 ... wrap up vips7 operations as vips8 classes - man pages are back for commands 30/11/10 started 7.24.0 - bump for new stable - added im_dmask2imask(), im_imask2dmask() - im_rotate_*mask90() can do masks of any size (thanks Adam Turcotte) 18/7/10 started 7.23.0 - im_vips2bufjpeg() writes to a linked list, so it will work for any size image and header - added im_vips2bufpng() - use GetTempPath() to pick a temp dir on Windows - added "rd" mode to im_open() - vipsthumbnail and vips use "rd" - im_divide spots /0 - remove liboil dependency, we will use Orc instead - various small cleanups (thanks Tim) - add lcms2 support - VImage(filename) defaults to "rd" mode - revise window_offset / window_size, again - fix a mixup with ANY hints that caused performance problems on the main benchmark - rewritten im_circle as im_draw_circle, im_circle moved to almostdeprecated - added IM_TYPE_RW args for inplace ops --- nip2 uses this to wrap inplace ops automatically - special-case 3x3 masks in im_conv() for a 20% speedup - add IM_TYPE_RW flag for im__rw_image, helps nip2 auto-wrap inplace ops - im_insertplace() casts and bandalikes - copy iconv.m4 and friends in bootstrap, thanks Mike - moved the stupid _copy() versions of the inplace ops to deprecated, since nip2 can call inplace ops directly now - added im_draw_rect(), moved im_paintrect() to deprecated - added im_draw_image(), moved im_insertplace() to deprecated - added im_draw_line(), now clips, moved im_fastline() to deprecated - added im_draw_line_user(), now clips, moved im_fastlineuser() to deprecated - added im_draw_mask(), now wrappable, moved im_plotmask() to deprecated - added im_draw_point(), moved im_plotpoint() to deprecated - added im_read_point(), now partial, moved im_readpoint() to deprecated - added im_draw_smudge(), moved im_smudge() / im_smear() to deprecated - convolution functions support complex images - im_blend() can have any format condition image and it's converted to uchar - security fix for vips-7.23 wrapper script (thanks Jay) - im_affine() has a larger safety margin - fix gtk-doc warnings - small mask load/save improvements - mask gtk-doc done - add cfitsio dependency - add FITS reader - land the vector branch and the orc dependency ... we have SSE erode/dilate/add/conv - add IM_SWAP - dilate/erode do (!=0) on non-uchar images - add multipass Orc to im_conv(), 3.5x faster for 5x5 mask - im_profile() works for any image format, any number of bands - im_rank_image() works for mix of formats, bands - morph gtk-doc done - oops, missing braces in debug.h and util.h, thanks Laurence - update C++/Python binding - oop, bool constants are always (int) now, so (^-1) works for unsigned types, thanks Nicolas Robidoux - much lower memuse for im_cache() in complex pipelines - im_scale_dmask() normalises to 20, not 100 ... we hit the fast conv path more often 12/5/10 started 7.22.2 - the conditional image of ifthenelse can be any format, a (!=0) is added if necessary - oops vipsthumbnail sharpening was turning off for integer shrinks, thanks Nicolas Robidoux - im_vips2jpeg() could fail for very small images (thanks Tim) - threadpool wasn't stopping on allocate errors (thanks Tim) - vips_sink_disc() could block if allocate failed (thanks Tim) 12/5/10 started 7.22.1 - fix a problem with tiff pyramid write and >1cpu, thanks Ruven - constant ops clip to target range - oops, moreconst and moreeqconst were the same - better buffer handling in sinkdisc for single-line images - less chatty errors from "vips" - oops, don't rename "copy_set" as "copy_", thanks Ole 12/5/10 started 7.22.0 - bump and rename - vipsthumbnail has a manualpage and sharpens correctly - more interpolator work - fixes to --disable-cxx mode (thanks Mike) - added German translation, thanks Chris Leick - fixed typos in some messages, thanks Chris Leick - fix gettext startup - all "colour" in messages changed to "color", have a proper en_GB translation file - vipsthumbnail delete profile failed if there was a profile - interpolate cli unref was broken - more accurate, slightly faster bilinear and bicubic (thanks Nicolas Robidoux) 21/3/10 started 7.21.3 - added progress feedback to threadpool - --vips-wbuffer2 switch does all wbuffer use now - im_wbuffer2() renamed as vips_discsink(), some cleanups - im_gammacorrect() can do 16-bit images too - im_histplot() could fail for signed int histograms - im_fwfft() and im_invfft() could free their output image too early - added im_local_imask(), im_local_dmask() - added im_mpercent_hist() - im_maplut() casts the index image to one of the uint types - fixed a couple of /0 problems with scale == 0 masks - set G_LOG_DOMAIN to VIPS so we can use g_warning etc. - added VIPS_DEBUG_MSG() macro - --vips-wbuffer2 turns on threadpool for im_iterate as well - im_vips2tiff() uses vips_sink() instead of threadgroup - strip out threadgroup - add --enable-debug=xxx flag - im_iterate() -> vips_sink() - better number-of-bands detection for im_magick2vips() - added im_get_argv0() - added PFM read / write 16/1/10 started 7.21.2 - "invalidate" is careful to keep images alive, so invalidate callbacks can do im_close() - flood_blob could loop if start point == ink - added im_meta_remove() - added remove profile option to vipsthumbnail - added vips_bandfmt_iscomplex() and friends, im_iscomplex() and friends deprecated - im_bandjoin()/im_gbandjoin() work with images of varying formats - added im_copy_native(), deprecated im_copy_from() and friends - im_check*() name rationalisation - finally removed old flood stuff - im_insert*() bandalike and formatalike - im_*join() bandalike and formatalike - im_ri2c() bandalike - im_vips2png() saves 16-bit PNGs, if necessary - vipsthumbnail has selectable interpolators, optional sharpen - moved a lot of stuff (eg. im_iscomplex()) from deprecated to almostdeprecated to avoid breakage - im_csv2vips(): allow lines that end with EOF rather than \n - im_vips2tiff has a bigtiff option - oops, im_lineset() needs to ask for WIO of mask and ink - move cache invalidation to REGION, fixes a race - don't im_invalidate() after paint, it can cause horrible performance problems ... for example, im_plotmask() used as the action operator for im_fastlineuser() is terrible - instead, users of the inplace operations need to call im_invalidate() at the end of a set of paint actions to trigger an update - parent/child renamed as upstream/downstream in DAG - set VIPS_ICC_DIR in configure - ICC profiles are looked for in VIPS_ICC_DIR as a fallback - im_render() mask image generation no longer triggers image calc - threadgroups scale output buffers with number of threads for smalltile ... improves SMP scaling for narrow images on many-way machines - default to max number of processors (--vips-concurrency and IM_CONCURRENCY set >0 can override) on linux and win32 - better nprocs guesser - im_render() fixes to help the paintbox, some speedups too - added im_wbuffer2(), a new distributed threading system, and --vips-wbuffer2 to enable it, thank you Christian 15/1/10 started 7.21.1 - added "written" callbacks, used to implement write to non-vips formats 26/11/09 started 7.21.0 - branch for new dev cycle - argh, missing init from colour.c (thanks Peter) - argh, im_measure() was not looping over bands correctly (thanks Peter) - removed mmap_limit, we now always use windows ... reduces VM use hugely, because mmap windows are freed when their regions are freed, while images are only unmapped when they are closed - have a min bytes for mmap windows as well, so we don't make too many tiny windows - im_disp2Lab() was broken - deprecated.h is now defined in terms of current functionality, rather than repeating stuff - im_flood() and friends rewritten, typically 4x faster - removed --with-cimg option, added --disable-cxx - added im_system_image() (thanks Roland) - added postclose callbacks - added vipsthumbnail - oops, generate C++/Python wrappers for deprecated operations by default - read TIFF images strip-wise, not scanline-wise - better TIFF YCbCr reading (thanks Ole) - isanalyze generates fewer silly error messages 26/11/09 started 7.20.3 - updated en_GB.po translation - file_length is gint64 to avoid win32 breakage 23/11/09 started 7.20.2 - GETTEXT_PACKAGE now includes lib version number (thanks Jay) 11/11/09 started 7.20.1 - oop, im_clip2fmt() was missing PTOP flag, should get a small speedup - im_conv() / im_convf() didn't like all-zero masks - small updates to im_convf() from im_conv() - im_read_imask() produced an incorrect error message if passed a doublemask - rename im_convf(), im_convsepf() as _f() - vips.c drops _f suffix when overloading - regenerate C++ binding, don't make deprecated package 9/11/09 started 7.20.0 - removed vips-7.x.spec.in, shouldn't really have this in SVN - bumped version to 7.20 - fixes to get "make dist" working again 3/4/09 started 7.19.0 - version bump - tiny conv speedup - catch lcms error messages - fix includes for gtk+-3.0 - report virtual memory too in im__print_all() - cosmetic changes to nohalo - im_magick2vips() needs to invert alpha - now (more or less) passes -Wextra - added "fail" option to im_jpeg2vips: fail with an error on any warning (thank you Ole) - started gtk-doc changes - renamed im_meta_get_type() and im_header_get_type() as im_meta_get_typeof() and im_header_get_typeof() to prevent confusion with GObject type definers (was breaking gtkdoc object scan) - revised more names, limited documented API - im_buildlut() could segv for non-zero based tables (thanks Jack) - VIPS_BUF_STATIC() does not take length arg - check for SetImageOption() so we work with GraphicsMagick too - "header" sets a non-zero exit code if anything failed - add and use im_check_uncoded() and friends - matlab load handles column-major and plane-separated images (thanks Mikhail) - JPEG save allows "none" for profile, meaning don't attach a profile - saner, simpler, faster typecasting for im_add(), im_subtract(), im_multiply(), im_divide(), im_remainder() - im_remainder() has a float result for float types - im_measure() allows sel == NULL, meaning all patches - added "deprecated" package - faster, simpler, better im_max(), im_min, im_avg(), im_deviate() - im_max() returns true modulus, not square of modulus, for complex images - im_avg() works for complex, returning average modulus - im_system() fix (thanks Roland) - im_system() rewrite - im_maxpos()/im_minpos() are partial and work for complex - im_max()/im_min() are now convenience functions - im_maxpos_avg() handles complex and multi-band images - added im_point(), rewrite im_point_bilinear() in terms of this - close callbacks now happen *after* images have closed resources (such as open files) ... this lets them delete temps and stuff. Expect breakage :( - added vips_interpolate_get_window_offset() - boolean revised: smaller, more general, faster - im_remainderconst_vec() renamed to im_remainder_vec() for consistency - added im_shift*_vec() - renamed im_eor_vec() as im_eorimage_vec() for consistency, also and, or - renamed im_eorconst() as im_eorimage_const() for consistency, also and, or - relational revised: smaller, more general, faster - im_blend()/im_ifthenelse() allows many-band conditional, 1-band then/else - im_blend()/im_ifthenelse() allows band and format to differ between then and else parts - better im_check() functions - added im_flood_other() as start of simple segmentation operator - added im_label_regions() - im_printlines(), im_debugim() deprecated (use im_vips2csv() instead) - meta, header, callback, error, region, check, generate, memory gtkdocs - removed printlines tool, vips2csv is much better - removed other useless tools as well: debugim, binfile - fix up addr calcs on 64-bit machines with >2gb images and inplace ops (thanks Christoph) - im_generate() checks that im_demand_hint() has been called for this image - im_jpeg2vips.c, set scale_num on shrink (thanks Guido) - heh argh reading history always stopped after the first line (thanks Haida) - added im_histindexed - new im_iterate() calls start and stop functions from workers so resources they make are owned by the worker thread ... this makes it possible to have start functions which create multiple regions and therefore allows im_iterate() to scan more than one image at once - threadgroup no longer has any default action, you must attach a work function - added im_copy_file() - added im_insertset() - im_insertplace() allows small to be outside big - added im__colour_difference(), colour ops now work on any image format - added im_col_display_get_table(), so display tables are now shared by name - added im__colour_unary() - drop "set" postfix from names, so "insert" can now take a vector of positions - deprecate all the "_raw" variants, not really necessary now - removed "contrib", not very useful anymore - added im_header_as_string() - im_malloc()/im_free() now call g_try_malloc()/g_free() ... removes confusion over whether to use im_free() or g_free() for things like im_header_string() - added im_history_get(), im_getexp(), im_printdesc() as wrapped functions ... so you no longer need the "header" program - image vectors from Python work, woo 25/3/09 started 7.18.0 - revised version numbers - updated vipsmanual - revised manpages - removed name and "changed" from vipsobject since we don't use them yet - explicitly link with stdc++ for nohalo etc. stuff - wrap im_gauss_imask_sep in C++/Python 6/3/09 started 7.17.3 - revised nohalo - remove fading stuff from im_render() -- cleaner and simpler - configure spots support for "restrict" - reset dcm:display-range on magick read to help DICOM - saner im_buildlut() behaviour - added im_gauss_imask_sep() - allow open and view of truncated images (thanks Joe & Rachel) - revising rounding on im_affine*() coordinate transforms to make them more stable - added Radiance write - added im_float2rad() - added IM_CODING_RAD, support where it makes sense (extract, flip, rotate, etc.) - IM_PROGRESS env var - docs for rad2float and IM_CODING_RAD 3/3/09 started 7.17.2 - im_magick2vips.c: allow funky bit depths, like 14 (thanks Mikkel) - isradiance was returning TRUE too often - radiance loader now loads packed RGBE/XYZE instead of unpacking to float - added im_rad2float() 11/10/08 started 7.17.0 - merge vips-7.16 branch back into trunk - bumped version number to 7.17.0 - re-added type.[hc] - added vipsinterpolate and im_affinei - added yafrsmooth interpolation - added yafrtest - added yafrnohalo - ubuntu 8.10 changes - interpolators get an output pointer, not region - tuning for bicubic - revised transform / clip code, we now do corner not centre - yafr-smooth reworked along the lines of bicubic - cleanups after yafr hacking - added affinei_all - don't set im_error() on failed callback - moved im_format_t to VipsFormat, now sits over VipsObject - IM_FORMAT_FLAG_PARTIAL -> VIPS_FORMAT_PARTIAL - updated docs - interpolators use type introspection - added vips --list classes, does formats too - include sys/param.h to get PATH_MAX in more places - added vips_format_get_flags() - oop, forgot to check for cancel during tiled tiff write - don't use mmap for tiff read: no performance advantage, chews up VM - VIPS_INTERPOLATE_SHIFT bumped to 12, we need the extra precision for u16 gel data - added string->double transform for cmdline args - merged class-params branch back into trunk - IM_FREE() can do "const char*" variables - im_buf_t renamed as VipsBuf - added vips_object_to_string() - added "nickname" and "description" properties to VipsObject - shift/and/or/eor ops were broken for non-int types - added nohalo interpolator - updated format docs - IM_INPUT_INTERPOLATE() now used by affinei and affinei_all - added vips_object_new - resamplers/interpolators now in a resample package - removed yafrnohalo.c - added matio as a dependency - added Matlab save file read - added Radiance file read - better file-not-found messages 11/9/08 started 7.16.3 - oop typo in manpage for im_project() - doc fixes - returning non-zero from eval callbacks was not always stopping computation 11/9/08 started 7.16.2 - added --without-v4l option - added -no-undefined to libsrcCC build, so we get a libvipsCC.dll - removed the swig dependency: we include the generated bindings in the distribution tarball 6/9/08 started 7.16.1 - trigger eval callbacks on tiled tiff write - added vips as an im_format_t - added im_format_write()/_read() convenience functions - more cleanups for the format API, argh - removed win32/ directory now mingw finally makes DLLs correctly - removed the windowed spcor for now, it has some edge effects 24/8/08 branch for 7.16 - renames and version numbers - load plgs from libdir as well as libdir/vips-x.x for compat - complex -> complex conversion was broken - refstring <-> gstring transforms - better behaviour with Magick non-presence - added --enable-links switch to configure ... we no longer make the bin/im_* links by default - started a 'format' section in the docs - configure fails if no gettext found - revised po/ - released as 7.16.0! 25/5/08 fork for loadable image format branch - image load/save in non-vips format code moved to own dir - simple format searching added - some cleanups for vips load - im_open() simplified - add im_format_flags - only consider formats with a save method in im_format_for_name() - oops, format sort order was reversed - im_filename_suffix() includes "." in suffix - merge back into trunk for 7.15.1 - remove im_ispng(), im_png2vips_header() etc. & friends - add "vips --list formats" - rename VBuf as im_buf_t for consistency - add type.[hc], start of new type system - removed man pages for IM_MIN, MAX and RINT to avoid case confusion on OS X / win 7/3/08 started 7.15.0 - MAGIC constants should be tagged as unsigned - write MAGIC correctly on sparc/powerpc machines (thanks Joe) - oop, we were still making fade threads even when not fading - tiny cond jump fixes for valgrind in colour.c - remove -lstdc++ from libs, except on windows - push Magick cflags earlier in the include order to make it easier to pick GraphicsMagick over ImageMagick (thanks Mikhail) - fix the en_GB translation - use meta to preserve resunit between tiff load and save - small doc improvements - read and write CMYKA tiff (thanks Doron) - performance improvements for morphology ops, esp. when zooming out - oop, im_render() was broken for mask == NULL - better support for multiple Python installs (thanks Jay) - better IM_SETSTR() stops some warnings - im_histcum() works for signed histograms - better rounding for im_conv(), im_convsep() - tiny speedup for im_conv() - better /0 test for remainderconst - revise i18n configure, get rid of intltool - command-line IMAGVEC input could segv with non-vips image output - added .tobuffer()/.frombuffer(), .tostring()/.fromstring() to Python binding - add PIL_mode_from_vips () and vips_from_PIL_mode () utility functions - update docs for new Python stuff - FIND_ macros no longer search for stuff, you have to specify prefixes if the packages are not on the default path (or in $prefix). This avoids some accidents on some platforms - configure prints a summary of optional packages found at the end - im_lhisteq() checks for window too small - added invalidate callbacks - now tests for MagickWand before ImageMagick (thanks Adam Turcotte) - added "-rotate" option to vips2dj - added man page for im_resize_linear - better jpeg-in-tiff YCbCr read (thanks Ole) - oops, invalidatefns were not being freed on im__close() - VMask() can init from std::vector, so Python can init from [] - added IM_LIBDIR, im_guess_libdir() - load plugins from libdir/vips-x.x on startup - added meta get/set int/double/string/area/blob/GValue to C++ API - include time_t in vips.h, thanks Nicolas Robidoux - lock global image list (thanks lee) 25/1/08 started 7.14.0 - bump all version numbers for new stable - better CMYK JPEG read (thanks Ole) - add __str__ to VError in Python (thanks Ole) - revert the dynamic wrapping for Python :-( next version! - added VImage::convert2disc (thanks Ole) - you can now set the jpeg quality factor for tiff pyramids (thanks Joe) - you can now shrink jpegs during read, see "man im_jpeg2vips" - added CMYK JPEG write - optionally use GraphicsMagick (thanks Bob Friesenhahn) - look for MAGICKCORE_HDRI_SUPPORT (thanks Marcel) - set icc profiles in tiff pyramids explicitly (thanks Joe) - add --without-cimg configure option - add im_maxpos_subpel - make im_abs compile without liboil - add im_align_bands - fix type overflow in complex division - fix im_cross_phase and im_addgnoise (Tom) - updated docs, C++ and python - header no longer stops on error - C++ dummy2.cpp helps OS X linking 12/12/07 started 7.13.3 - added "include " to VImage.cc to help gcc 4.3 - started moving the python binding to dynamic wrapping - added im_wrap(), im_wraptwo(), im_phasecor_fft(), im_cross_phase() (Tom) - memleak plugged in im_save_string_setf() - bugfix in and docs for im_gradcor() (Tom) - use Glib macros to make im_msb work on big-endian platforms (Tom) - use Glib macros to get rid of needless compile warnings (Tom) - fix type overflow in im_c2ps/im_abs (Tom) 31/10/07 started 7.13.2 - build cimg on windows fixes - various include cleanups, updated man pages - break im_wbuffer() out to a separate API - use im_wbuffer() to make im_vips2jpeg() compress in the background - also im_vips2png(), im_vips2tiff(), im_vips2ppm() - revised evaluation progress system - new evalstart/evalend/preclose callbacks fix over/underflow reporting - but the meaning of evalend has changed in a non-backwards-compatible way :( use preclose instead ito get the old behaviour - added "--vips-progress" flag to turn on a simple eval progress tracker - make im_spcor[12] static, im_spcor is wrapper (Tom) 28/9/07 started 7.13.1 - vips2dj can print RGB images - oop, include missing - add protos for generate/iterate function args, fix warnings - add cimg package, we now have C++ source inside VIPS, sigh - added OUTPUT_DOUBLEVEC and OUTPUT_INTVEC, use for im_maxpos_vec() and friends 29/8/07 started 7.13.0 - we now have a trunk and the version is 7.13.x, woo! - move manpages into a separate man/ dir ... speeds up builds a lot on windows - don't install malkovich - don't fail on unknown args for python (thanks Simon) 1/8/07 started 7.12.5 - im_embed() is more general ... x and y can be negative - predicate.c is smaller and cleaner - libsrcCC link improvement from Pablo - support 32/64-bit ImageMagick as well (thanks Marcel) - better im_magick2vips() for Q8 ImageMagick - split repository to trunk/branches ready for a stable 7.12.x branch 27/7/07 started 7.12.4 - proto.h had vars called small, breaking on win32 - more python fixing, we now have working matrices too 17/7/07 started 7.12.3 - fix to VImage.i for gcc 4.2 (thanks Damir) - eek, off by 1 for more than 1 band hists - needed a slightly larger worst-case buffer in im__b64_encode() - tiny cleanup for make_hI() prevents cond jump on ui in valgrind - --disable-threads was broken again - remove .svn dirs from dist - now passes distcheck again 17/7/07 started 7.12.2 - added im_bandmean() - added support for TIFFTAG_PREDICTOR (Andrey Kiselev) - fix TIFFOpen() mode snafu (Andrey Kiselev) 11/5/07 started 7.12.1 - memory.c abort()s with DEBUG - oops, im_bits_of_fmt() manpage was not being installed - im_histcum() can do all image types - updated NEWS - added im_csv2vips_header() - command-line csv read was broken (thanks Tom) - removed length limit on argument vectors (Tom) - added IM_PREFIX, configure-time install prefix - oop, turned off memory.c DEBUG - fix some bogus gcc 4.1 warnings with im_open_local_array() - better vips usage message - oops, IM_ANY missing from im_demand_hint() manpage (thanks Shahid) - just warn if plugins fail to load in im_init_world() - expose Vargv and make refblock public rather than private so that subclasses of VImage can add vips-style member operations (thanks Pablo) - oops, im_initdesc() needed to have bbits set correctly (thanks Shahid) - make VError derive from std::exception more officially - woo, got exceptions working in SWIG - soname version bumped to 12.x.x - oops, added vector ops to Python - check for overflow of int in return of strtol in dispatch system (Tom) - add im_[di]mask_[xy]size to dispatch system (Tom) - add im_gradcor(), im_grad_[xy] (Tom) 26/3/07 started 7.11.21 - ooo, added %include "std_except.i" & friends to VError.i, VImage.i - im_init_world() is more lenient about recursive invocation - im_gbandjoin() falls back to im_copy() for 1 input image - race condition fixed in im_render.c (thanks Simon) - bump for 7.12!!! 26/1/07 started 7.11.20 - another fix to im_region_image() (thanks Mikkel) - tiny speed up to im_rect_includesrect() - avoid recursive invocation in im_init_world() (thanks Christian) - fix to extract_prefix (thanks Christian) - buffer cache is now per thread - combine buffer unref and ref in a single operation to reduce malloc/free cycles - new internal API for passing regions between threads means we can remove buffer locks - more buffer/region sanity checks, plus a memory barrier - lock around error buffer changes - im_vips2mask() was wrong for nx1 m-band images - liboil back to "test" - add buffer_cache_list to avoid GHashTable _insert()s - oop, --vips-concurrency was broken - renamed (in dispatch layer) im_and/or/eor_const -> im_and/or/eorimageconst for consistency - C++ API wraps IMAGEVEC, DOUBLEVEC, INTVEC arguments - oop, IMAGE % vector was broken 21/12/06 started 7.11.19 - added im_linreg() (Tom) - various C++ API polishes, plus a bugfix (Dennis Lubert) - vips.spec split to devel and python too (Dennis Lubert) - be more explicit about sizeof(magic) - init magic to native order by default (thanks Dennis) - Hist becomes im_history_get() - new history mechanism is faster, uses much less memory, and removes duplicate lines - added im_get_option_group() - added official im_concurrency_set()/_get()() - don't read bbits from vips files ... set ourselves from bandfmt - oops add RGB16 and GREY16 to C++ header - --list packages option to vips.c - updated docs to 7.12 - oops, im_region_image() snafu was causing a lot of recomputation - make im_mpercent() suck a little less - EXIF save was a bit bOrked ... cause of mac crashes? - im_histgr(), im_heq(), im_hist() all number bands from zero now - fix stride in liboil calls - set RGB16 on 16-bit RGB ICC export 29/11/06 started 7.11.18 - added im_buffer_t so regions can share calculated pixels: 2-3x speedup on the benchmark - im_region_local() -> im_region_buffer() - im_sharpen() order change to help sharing - im_invalidate() clears buffer caches - add sentinel attributes - add some missing im_demand_hint()s - paint ops invalidate the output image - fix nothread eval - raise threads limit to 1024 (thanks Christian) - manual redone - vipsCC python init() hooks - add liboil dependency - use liboil for im_abs(), im_add(), im_divide(), im_floor(), im_multiply(), im_subtract(), im_lintra(), im_avg(),im_deviate() - quiet libtoolize test (thanks Tom) - im_benchmarkn now regrows image each time - strip meta from sample2.v ... saves a lot of mem (esp. Hist) - added im_isscalar() (Tom) - added IM_REGION_ADDR_TOPLEFT() (Tom) - reduce size of im_rightshift_size.c to help compile (Tom) - make im_stop_many(NULL) safe (Tom) 24/11/06 started 7.11.17 1;5Q - better benchmark script makes graphing easier - double-buffer image file writes - reuse write threads - clean up threadgroup / iterate / generate - added im_benchmarkn to make it easier to make a CPU-bound op on large machines - im_cache() failed for cpus > 1 1/11/06 started 7.11.16 - moved im__convert_saveable() into im_copy() (thanks Christian) - missing gobject dependency (thanks Christian) - --enable-threads was broken (thanks Christian) - eval without theads was broken (thanks Christian) - LIBADD libvips.la to libvipsCC.la (thanks Simon) - benchmark.sh is now plain sh, not bash - set ORIENTATION_TOPLEFT in im_vips2tiff (thanks Josef) - oops, im_vips2csv() output separator was broken - added im_benchmark2 - move XYZ2Lab LUT build outside the eval thread 30/10/06 started 7.11.15 - print leaked windows - oops, race condition in im_window_unref() - integrated im_region_window() into im_region_image(), tiny speed up 6/10/06 started 7.11.14 - ifthenelse and affine dhints revised - buildlut no longer outputs x cods - configure asks for glib >= 2.6 (we need GOption) - configure uses AC_TOOL_CHECK to find tool names to help cross-compiling. - better configure test for libexif - add C++ include ... include in a namespace - added im_benchmark / SMP benchmark script - add im_maxpos_avg() and im_point_bilinear() (Tom) - make im_region_free(NULL) safe (Tom) - link in manpages for im_contrast_surface (Tom) 8/9/06 started 7.11.11 - add im_norm_dmask() - removed old code for gradient and lindetect - internal decls split from proto.h to help SWIG - test for python and SWIG during configure - added python dir for the binding - python binding done! - oops, --without-python was broken (thanks Tom) - added python/test - add im_lu_decomp() im_lu_solve(), rewrite NR type functions in terms of these (Tom) 23/6/06 started 7.11.10 - still more im_affine() rounding/clipping tweaks - ignore "--" arguments to vips.c - im_init_world() also sets g_*_prgname() and loads plugins - add manpage for im_init_world() (oops) - error_exit() prints prgname - various cygwin fixes - fix cache thread assert failure (thanks Joe) - "header" now uses GOption, slightly different args, will loop over args - fixed assert() overenthusiasm in im_prepare() - im_csv2vips() now has separate whitespace / separator tables - add im_rightshift_size() (Tom) - add im_maxpos_vec(), im_minpos_vec() (Tom) - add im_norm_dmask() (Tom) - make im_free_[di]mask(NULL) safe (Tom) 23/6/06 started 7.11.9 - back on sourceforge CVS again - require openexr 1.2.2 or greater - range check xy on im_insert*() for sanity - VMask::invertlut decl removed (thanks Jean) - added \"all\" option to vips.c 17/5/06 started 7.11.8 - debrokened openexr read - added im_tile_cache() - added tiled read to im_exr2vips() - im_tiff2vips() now uses im_tile_cache() rather than its own cache ... faster in some cases, less RAM use in some cases, saves 200+ lines - removed 'broken' read option from im_tiff2vips() - read/write doubles with g_ascii_strtod() and friends where appropriate - add a "thread" member to region to help sanity check region ownership - saner threadgroup fixes a race problem on gcc 4.0.3 / amd64 - added im_vips2csv() - im_open() now does CSV read/write too - oops, broke vips main prog for function name in argv1 case 22/4/06 started 7.11.7 - split vips_png.c to im_vips2png.c and im_png2vips.c - added OpenEXR dependency - added im_exr2vips(), im_exr2vips_header() - added im_isexr(), im_open() knows about OpenEXR - added im_contrast_surface(), im_contrast_surface_raw() (Tom) - added im_msb(), im_msb_band() (Tom) - im_scale() sets Type on output - added RGB16, GREY16 types - im_*2vips() set these types if appropriate - configure fixes for mac - vips main prog uses GOption - im_icc_* locks around calls to cmsDoTransform() to avoid corruption on SMP machines - add im_prepare_many() (Tom) 10/3/06 started 7.11.6 - typo in manpage and header for im_rect_dup() (Tom) - don't abort image load if XML read fails - added im_video_test() ... test video source - oops, lcms .pc finder was not working - clipping problem in im_affine() fixed (thanks Clare) - test for attr support in libmagick - im_text() returns an error for empty string - im_falsecolour() scale reversed - im_remosaic() could crash on bad mosaics - configure changes to fix --without-magick, lcms and fftw (but sadly we now require .pc files for these libs) - im_vips2jpeg() automatically converts to 1 or 3 band sRGB uchar for write - also im_vips2png() - added im_project() 20/2/06 started 7.11.5 - added im_csv2vips() - commas in filename options can be escaped with a '\' - raise tile buffer limit (thanks Ruven) - im_spcor() and im_fastcor() have prettier borders - im_fastcor() returns sum of squares of differences, not sum of abs of differences 18/11/05 started 7.11.4 - small win32 fixes, thanks Juan - added im_flood_blob_copy() ... a temporary hack - much faster im_histplot() - read RGBA palette-ized PNG images more robustly (thanks Tom) - turn on -ms-bitfields automatically for mingw 26/9/05 started 7.11.3 - better error recovery for im_binfile() file too large - all raw files now use mmap windows, so (eg.) ppm and analyze reads can go >2GB - remove DISABLE_COMPAT ... you now have to define IM_ENABLE_DEPRECATED to get broken #defines - fix to build without exif, thanks Chas - use native win32 API for seek()/truncate() to work with large files - use attribute to check printf-style args with gcc - fix gcc4 warnings - removed ebuild, since it's in gentoo now - im_magick2vips() sets meta from attributes (good for dicom) - im_magick2vips() writes many-frame images as tall thin VIPS images - im_histcum() was broken for vertical histograms - im_histnorm() is neater - simpler and faster inner loop for im_conv() and im_convf() avoids gcc4 bug - appendc() was reading past the end of the buffer on MSB machines 13/6/05 started 7.11.2 - im_copy_set() was messed up in 7.11.1 - put into CVS, phew - fixed a rounding bug in im_affine() ... should no longer get black edges on image resize - if TIFF open fails in im_open(), try going through libmagick - merge requires all bands == 0 for transparency (used to just check 1st band) - 16 bit LAB TIFF read/write was wrong - new GType for refstring makes it visible from im_header_map() - jpeg loader attaches exif data (and human-readable meta fields) - jpeg saver writes any exif data - meta not wiped by im_*incheck() in a "w" image - meta keeps traverse order - now require glib >= 2.4 - require libxml-2.0 for meta save and new history mechanism - no more .desc files, history saved in XML after pixel data - i/s/d meta fields saved there too - added base64 encode/decode - added blob header write - added a save string type: types which define transforms to and from the save format get serialized - GValue meta API now exposed, since we can serialise anything - jpeg loader loads ICC profiles - jpeg saver saves ICC profiles from the VIPS header - src/header.c knows about meta system - added im_analyze2vips(), im_grid(), im_raw2vips() - extract/grid/replicate/zoom were not setting TRANSFORM flag - better falsecolour LUT - less stupid + more portable read/write of VIPS header - better im_updatehist() - jpeg load sets vips xres/yres from exif, if possible - jpeg save sets exif xres/yres from vips, if possible - icc_export and icc_transform attach profiles and intents to output images - added im_icc_import_embedded() to import with an embedded profile - split vips_jpeg.c into two, it was getting too big - added im_cp_descv(), im_cp_desc_array(), funcs use them - removed im_append_Hist() from API - fixed meta copy bug - better history copy, removed nonsense about 1st line of Hist being special - tiff read/write now reads/writes ICC profile from meta - edvips rewritten to remove stupidness, and can now set xml - header can now print xml extension block - IM_ prefix for colour temp names 1/6/05 started 7.11 - added im_copy_morph() - im_region_region() allows Bands and BandFmt to differ, provided sizeof( pel ) is the same ... makes im_copy_morph() work - added im_meta*() functions (MW) - im_header_*() rewritten for meta - added im_header_exists(), im_header_map() - use pkg-config to find libpng and ImageMagick - added im_lineset() - added im_extract_areabands() (JF) - added im_copy_from() (JF) 15/4/05 started 7.10.12 - im_ifthenelse just evals left/right for region all zero/all one - also im_blend - swap g_setenv() back to plain setenv() so we work with glib 2.2 9/4/05 JC started 7.10.11 - docs no longer have broken links - fixed memleak in im_text() 8/4/05 - one bit tiff read was sometimes reading a byte too far in each scanline 14/1/05 started 7.10.9 - im_filename_split() will now usually work for filenames containing ':' characters - added im_render_fade() for fancier nip2 image repaint - added "ccittfax4" as a TIFF compression option - fix all 64-bit compiler warnings - "," allowed as column separator in mask read - better at spotting singular matrices - small im_render() tidies - glib dependency reduced to just 2.0, but untested ... helps people building on older systems who aren't interested in nip2 - removing leading spaces from IMAGEVEC arguments - load non-interlaced PNGs more efficiently - 1 point mosaic functions work on more image types - better memory allocation debugging info - local memory on regions can shrink as well as grow - shut down threadgroups on render if no dirty tiles - limit number of simultaneous renders - higher mmap window threshold - allow max == -1 for unlimited render cache - 'priority' marks non-suspendable renders - im_embed() mode == 4 paints white pels - im_tiff2vips() was broken with --disable-threads - oops, im_errormsg() compat macros were GCC only - larger default tile size and strip height - tiff write sets PHOTOMETRIC_CIELAB for vips TYPE_LAB images ... so we can write float LAB as well as float RGB (thanks Ruven) - also 16 bit LAB TIFF write - im_render() rewritten 20/11/04 started 7.10.8 - im_sharpen() is ~15% faster - more quoting for MAGICK finder - im_XYZ2Lab() uses a LUT rather than cbrt(), 5x faster - --disable-threads removes gthread dependency completely (thanks Simon) - intercept TIFF warnings as well as errors ... stops occasional libMagick exceptions - add im_init_world() to im_init() as well to help backwards compat (thanks Simon) - im_icc_present() function description was broken, thanks Jay - oops, libtool library versioning was wrong, thanks Jay - can now make TIFF pyramids of any non-complex image type (was uchar and LAB only), thanks Ruven - 1st order mosaic code now works for LABQ too - build system changes to make "make distcheck" work - RPM .spec files fixed up and updated by configure (thanks Simon) - tiny cleanups for vdump - use g_setenv()/g_getenv() - tiny improvements to IM_FREE*() - tiny VImage debug print fixes (thanks Jay) - swap off_t for gint64 to fix LARGEFILE support on win32 - computation feedback now uses gint64 for number of pels, so we give feedback correctly on images with >2**31 pels - other small fixes for >2**31 pels in an image 10/11/04 started 7.10.7 - im_histnD() was not checking BandFmt (thanks Kirk) - improvements to threading system speed up non-vips output in some cases - use cbrt(x) where we can ... 10x faster than pow(x,1.0/3) on win32 - typeo in im_text() when built without PANGOFT2 (thanks Stefan) 1/11/04 styarted 7.10.6 - tiny doc fixes - scripts now only depend on 'vips' program - im_open( "r" ) is now lazier ... for non-VIPS formats, we delay read until the first ->generate() - so im_open_header() now deprecated since im_open("r") is identical - now looks for fftw3 as well as fftw2 ... slightly faster ffts 19/10/04 started 7.10.5 - fix to light_correct (thanks Jay) - edvips knows about xoffset/yoffset - better vips enum<->char conversions 4/10/04 started 7.10.4 - man page fixes (thanks Jay) - removed last csh scripts (thanks Jay) - scripts default VIPSHOME to $prefix (thanks Jay) - doc build system tidies - im_rank() edge padding was wrong - im_vips2tiff() can now embed ICC profiles 22/9/04 started 7.10.3 - mildly better im_vips2tiff() - *, -, +, /, % between two images now work for mixed number of bands - im_free() was missing a man page - revised documentation 1/9/04 started 7.10.2 - C++ .pc files were still set for 7.9, grr - im_insertplace() didn't check compatibility of images (thanks Matt) 27/7/04 started 7.10.1 - set default stack size explicitly to help platforms with a very low default - 16 bit RGB tiff read was broken (bug introduced in 7.9.5, thanks Haida) - !pangoft2 was broken, thanks Kenneth - win32 build fixes 12/7/04 renamed as 7.10.0 - added NOCACHE function flag ... stops nip memoising video & paint ops - added im_extract_bands() ... takes out many bands from an image - im_vips2tiff() scanline write speed up for area pipelines 10/6/04 started 7.9.6 - tiny polishing of im_ppm2vips() - im_blend() can now work on labq - boolean ops all work on float/complex images (by casting to int) - im_maplut() was broken for 1 band image + many band lut + >8 bit output - im_lintra_vec() now handles 1 band image and many band vector to make many band image - oops, im_lintra_vec() was missing a man page - im_measure() can work on labq - im_lhisteq() uses new embed mode, _raw() version is one pixel smaller, sets Xoffset/Yoffset for new origin scheme - generalised im_tone_build() to any image type to make im_tone_build_range() 20/5/04 started 7.9.5 - tiff output res can be a single number too - added im_text() to make a bitmap from a string with pango - im_tiff2vips() does 16 bit RGBA - im_binfile() was broken since 7.9.2 due to im_mapfile() change - im_ppm2vips() now works for 16 bit images - added im_copy_swap() ... copies, reversing byte order - im_resize_linear() was broken for some images, thanks Javi 8/3/04 started 7.9.4 - oops, config.h include missing in a few places - im_vips2tiff() can now write 1 bit images - im__find_lr/tboverlap() now exported to nip - better edge tile handling for tiff read/write (thanks Ruven) - added extend-pixels-from-edge mode to im_embed() - im_conv*(), im_rank(), im_stdif(), im_dilate(), im_erode() all use it to expand their input, so their output now has guess borders, not black borders - im_fastcor() now does an im_embed( 1 ) on the output ... the zero borders were very annoying before, since you would usually be searching for the minimum point - no change to im_spcor(), since you will usually be searching for the maximum - better im_render() cache behaviour under heavy loads - im_affine() revised * clip, resample and transform is now pixel-perfect for all inputs (I hope) * uses the new embed to make sure there are no black borders from edge interpolation * about 20 - 30% faster - policy change: Xoffset and Yoffset are now set by all operations to record the position of the input origin in the output - im_replicate() is much faster for some cases - added tile and mirror flags to im_embed() - added im_cache() convenience function - better ETA for image calculation - im_tiff2vips() now has a "broken" option so it can read tiled tiffs made with earlier versions of vips - on convert float to int format, now does floor() not rint() ... more 'mathematical' - added im_rint() - im_sharpen() now uses a gaussian mask - im_convsep() more resistant to int overflow problems - added im_make_xy(), avoids rounding problems with the old float-based thing - im_profile() now makes vertical images for a vertical profile - added im_vips2tiff() option to set the resolution in inches not cm (thanks Andrey) - im_binfile() is now exported 6/2/04 started 7.9.3 - added an im_init_world() to im_open(), to help old progs - renamed VSemaphore as im_semaphore_t - started using libtool library versioning - now uses g_module_*() in place of dlopen() - now uses pkg-config instead of vips-config (thanks Simon) - fixes to vips.h for _ADDR() with DEBUG on (thanks Konrad) 10/12/03 started 7.9.2 - patches for freebsd, thanks Lev Serebryakov - vips2dj knows about my colour laser printer - added i18n support, glib/gmodule/gthread dependency - im_error*() API revised to be more i18n friendly - List type removed, now uses g_slist - VBuf added, some more utility funcs pushed down from nip - im_thread stuff removed, now uses g_thread - im_lock stuff removed, now uses g_mutex - im_semaphore_t renamed to VSemaphore, not sure this is a good idea - build with --disable-threads to turn off threaded render - #include now pulls in most of the public API, you shouldn't need other vips includes very often - im_close() is better at cleaning up if there's an error - inverse FFTs could fail for wider-than-high images with fftw - better im_icc_transform error messages - bug fix in im_render with large caches - im_binfile() now has an offset parameter - im_mapfile()/im_unmapfile() now work on IMAGE and record the length of the file they mapped ... this lets VIPS successfully unmap a file if it changes size while it's open 20/10/03 started 7.9.1 - threadgroups now have their own kill flag - im_plotmask() now does anti-aliasing - im_iterate() fix for operations on mmap window images (thanks Clare) - im_writeline() stops on kill - fix for im_fwfft() segv for wider-than-high real images (thanks Andrey) - fix for im_fwfft() to work for non-square real images (thanks Andrey) - can now read and write 32-bit IEEE float TIFF (Andrey Kiselev) - clean-ups for colour.c (Andrey Kiselev) - no longer lets you make an image with width|height|bands == 0 (thanks Joe) - im_vips2tiff(), im_vips2*jpeg*(), im_vips2png(), im_vips2ppm() could sometimes fail for mmap window input images (thanks David) - added IM_RECT_HCENTRE(), IM_RECT_VCENTRE() macros 20/8/03 JC - started 7.9.0 - added im_rank_image() ... im_maxvalue() a special case of this - im_subtract() goes up to int earlier for better value preserving, thanks Haida - im_rank() much faster for large windows, correct result on all platforms (dratted memcpy() was causing problems before) - fixed problem with libMagick config if installed somewhere strange - fixed problem with include order in library compile - added --without-magick configure option - added im_render(), threaded background image paint - added im_replicate(), replicate an image horizontally and vertically 31/5/03 JC - started 7.8.11 - fixed a problem with relational operators and some combinations of input types (bug introduced in 7.8.9), thanks Haida - vips-7.8 script overrides VIPSHOME environment variable - better im_guess_prefix - stupid light_correct script no longer uses /pics/tmp - added batch_crop script 22/5/03 - started 7.8.10 - the JPEG writer can embed ICC profiles in output images ... although I've yet to see it make any difference :-( test this carefully at some point - fixed a possible coredumper in jpeg write - jpeg read now spots truncated files - im_invertlut() now makes an image, not a mask ... sorry :-( - im_histnD() makes an n-dimensional histogram from an n-band image - im_col_pythagoras() patch - IM_NUMBER() now returns int not size_t - new win32 build system from Juan and friends, based on tmake - sample project files for MSVC added, thanks Juan - win32/ subdir now has the win32 build systems - spec/ subdir now has the spec files for building RPMs - dist now includes formatted documentation - license change: VIPS is now LGPL, nip stays GPL ... this means proprietary programs can link against the vips library - had a report of a working VIPS build on a 64 bit system (!) - im_log_dmask() now includes all of the negative lobe, thanks matt - vips-7.8 start script now auto-relocates - im_spcor_raw(), im_fastcor_raw() now exported 29/4/03 - started 7.8.9 - changes to build to help MSVC - oops, makedef.pl missed out function names with an initial cap, and error_exit() - im_min() and im_max() gave random wrong results for >1 thread on >1 CPU machines (bug introduced in 7.7.20), thanks Joe - vips.c no longer generates C++ wrappers for functions with no image argument (thanks Haida) - im_invertlut() now wrapped by hand in VMask.cc - C++ docs updated - added im_open_header(), returns an IMAGE with just width/height/etc and no data - ... so now "header" will print useful stuff even on truncated files - tiff writer knows about alpha (thanks Jenny) 7/2/03 - started 7.8.8 - build failed with lcms turned off - im_spcor() could segv for 16bit images (thanks Joe) - im_tiff2vips() read resolution expressed as pixels/cm incorrectly - im_vips2tiff() tries not to write mad resolutions - header and im_open file type tests reordered for slight speedup - im_copy_set() had a broken dispatch function for xres/yres - im_fwfft() exploits libfftw real -> complex transform if possible for a 2x speed-up (thanks Matt) - im_invfftr() added for complex -> real inverse transform for 2x speed-up (thanks Matt) - im_freqflt() now uses im_invfftr() for real result and speedup - im_flipver() could segv on some inputs, thanks Clare - relational operators now work on complex - relational rewritten ... now fractionally slower, but 1/3 the size - vips2dj -1:1 produced incorrect height - better overlap-too-small detection in mosaicing code - im_system() can have NULL output - global balance ignores overlaps with only transparent pixels 3/1/03 - started 7.8.7 - worked in patch from Hans Breuer (thanks!) - png read/write with im_png2vips(), im_png2vips_header(), im_vips2png(), im_ispng() - im_errorstring() and im_col_displays() are now functions not externs (helps DLLs) - many include fixes to help native win32 build - added libMagick support, 78 file formats now loadable with im_magick2vips(), im_magick2vips_header() and im_ismagick(), w00t - now installs vips.m4 to $prefix/share/aclocal - added im_icc_export_depth() ... export to device space with a specified bit depth (8 or 16) - vips.def now rebuilt with custom rule in libsrc/Makefile.am - removed externs im_Type, im_BandFmt, im_Coding, im_Compression to simplify DLL build - im_mmap() -> im__mmap(), since it's supposed to be an internal function - new vips-7.8.x/proj directory holds unsupported sample makefiles and config.h for building with the MSC toolchain - new scripts batch_image_convert and batch_rubber_sheet (thanks Joe) - added the RPM .spec files to the main distribution - InitializeMagic() now passed "" rather than NULL to avoid assert() problems on some libMagic versions 2/12/02 - started 7.8.6 - now reads 8-bit RGBA tiff - C++ build guide fixes (thanks fsicre) - im_Type2char array text slightly messed up - global_balance is safer for complex mixed mosaics - removed im_lintra() fallback to im_copy() for scale == 1, offset == 0 ... too confusing - im_tiff2vips() now reads 16-bit LAB - added im_Lab2LabS() and im_LabS2Lab() 5/11/02 - started 7.8.5 - fix for mmap window of local region ... caused im_iterate() to break sometimes for large images, in turn occasionally breaking im_max()/im_min()/etc. (thanks Joe) - tiny speed up for im_rot90()/270() - on install on win32, add .exe suffix for links - vips.c knows to remove .exe suffix for linked commands - added im_errormsg_system() ... decode win32 error codes too - pagesize calcs for roving mmap windows were messed up on win32 (thanks Kirk) - some TODO cleanups - global balance broke horribly if you had filenames with spaces in (thanks Clare) 31/10/02 - started 7.8.4 - im_unmapfile() includes mixed up on mac os x - libtool patched for mac os x - vips.c sets numeric locale to "C" 27/10/02 - started 7.8.3 - configure fixes help mac os x - im_guess_prefix() adds ".exe" suffix on w32 if not there - changed im_measure() error messages to number bands from 1 - added func descriptor for im_read_dmask() to help nip, updated C++ API, docs 21/10/02 JC - started 7.8.2 - tries rand() if random() is not available - tries mktemp() if mkstemp() is not available - turns off realpath() if not available - added IM_DIR_SEP/IM_DIR_SEP_STR directory separator character/string - added IM_PATH_SEP/IM_PATH_SEP_STR path separator character/string - added im_path_is_absolute() - vips.c knows to link to vips.exe on win32 - spot mingw* and set BINARY_OPEN - open images in binary too (since we now read() the header) 10/10/02 JC - im_lintra() and im_lintra_vec() were broken for complex images :-( thanks matt - renamed im_and() as im_andimage(), im_eor() as im_eorimage() and im_or() as im_orimage() ... avoids breakage in the C++ layer - added im_dE00_fromLab() - limited release as vips-7.8.0 2/10/02 - renamed as vips-7.8, woohoo - revised documentation 19/9/02 JC - started sorting out VIPS #defines ... there are now a sensible set of new names (eg. NOCODING becomes IM_CODING_NONE, LAB becomes IM_TYPE_LAB) - define IM_NO_VIPS7_COMPAT to turn off the old names - added im_mmap()/im_munmap() layer for windows portability - removed the contents of history.h .. obsolete - added IM_IMAGE_ADDR() macro 10/9/02 JC - handle errors from TIFF lib correctly - configure fixes for cygwin - CMYK TIFF write fixed - configure fixes for mingw 5/9/02 JC - im_cp_desc() now copies Xoffset/Yoffset 21/8/02 JC - started 7.7.24 - reads CMYK TIFF - reads dpi from TIFFs - better float Xres/Yres 14/8/02 JC - new header fields Xoffset and Yoffset ... used by functions to hint the position of the origin in output images - support added to c++ api and to header - im__lrmerge(), im__tbmerge(), im__affine(), im_insert(), set Xoffset/Yoffset - now uses , not for better suse w0rkage - better configure for fftw (uses libdfftw name if libfftw not found) 8/8/02 JC - large file support with mmap() windows ... had to change im_prepare_inplace() to im_prepare_to() benchmark: - system hardware: 2 x 2.5GHz P4, 1GB RAM, 15k SCSI, ReiserFS os: suse 8 (kernel 2.4.18) compiler: gcc 2.95.3, -O2, threads turned on images: fred.v, fred2.v; both 4k by 4k LABPACK (64MB) images: jim.v, jim2.v; both 15k by 15k LABPACK (900MB) time: smallest real of 5 runs, system idle vips: 7.7.23, debug on in im_openin.c, window limit set with an environment variable - benchmarks cpu-bound: im_sharpen fred.v fred3.v 11 1.5 20 50 1 2 io-bound: im_insert fred.v fred2.v fred3.v 4000 0 worst-case: im_rot90 fred.v fred3.v - results desktop: no mmap windows mmap windows cpu-bound real 0m3.712s real 0m3.970s user 0m6.010s user 0m6.390s sys 0m0.900s sys 0m1.110s io-bound real 0m1.813s real 0m1.865s user 0m0.900s user 0m0.990s sys 0m1.720s sys 0m1.520s worst-case real 0m1.344s real 0m3.039s user 0m1.270s user 0m2.230s sys 0m0.850s sys 0m3.050s not quite sure why sharpen is a little slower (4%?) ... IO speed is about the same though ... worst-case is having to constantly move windows about (500,000 page faults, vs 10,000 for no windows) again, with an image larger than RAM no mmap windows mmap windows io-bound real 2m52.759s real 2m11.172s user 0m14.940s user 0m14.890s sys 0m29.940s sys 0m26.560s worst-case real 3m35.391s real 3m50.760s user 0m19.850s user 0m26.600s sys 0m12.650s sys 0m43.130s mmap windows actually slightly faster in this case ... plus they stress the OS less 31/7/02 JC - added -lm for better lcms detect - README notes for fftw on suse8 - im_profile() sets HISTOGRAM for output image - im_copy()/im_copy_set() function descriptor no longer sets PTOP ... helps avoid LUT problems - im_subsample()/im_zoom() fall back to im_copy() for shrink/grow == 1 - im_lintra() falls back to im_copy() for scale == 1, offset == 0 - no longer use Type == LUT ... all just Type == HISTOGRAM now - im_blend() was messed up for > 1 band images :( 16/7/02 JC - started 7.7.23 - im_XYZ2sRGB() wasn't setting Type = sRGB - im_icc_import() was broken for rgb - im_header_string() had wrong return type in function database 13/7/02 JC - added im_flood_blob() - added im_open_local_array() ... C API convenience function - oop, im_flood() was missing a man page - Type == FOURIER added to help visualisation - released as 7.7.22 30/6/02 JC - JPEG, TIFF and PPM import all now set sRGB Type for RGB import - im_header_int(), im_header_double() and im_header_string() added to aid UIs - now uses gettimeofday(), not time() - for consistency with other trig functions, im_c2amph() now returns degrees not radians (ouch) - added im_c2rect() ... turn (amp, phase) to rectangular - added im_sign() ... unit vector in direction of value - better im_scaleps() ... old code was terrible - rewritten im_rotquad() ... now partial - im_icc_export()/_import() now do ABSOLUTE correctly - added im_icc_ac2rc() ... converts absolute to relative colorimetry 25/6/02 JC - added im_copy_set(3) ... like im_copy(), but set informational header fields 20/6/02 JC - added im_ceil(), im_floor() - im_Lab2LabQ was not clipping a/b range correctly - im_icc_export(), own ABSOLUTE mode - released as 7.7.21 28/5/02 JC - im_remainderconst_vec broken for float/double - added Yxy colourspace 16/05/02 JC - auug, libtool was all messed up ... redone all the autotools stuff - uses libtool convenience libraries to build vips in sections - uses config subdir for temp files and .m4 things - patched stupid suse config.guess - vips2dj patched for better raw cmyk - released as 7.7.20 12/5/02 JC - im_vips2jpeg*() and im_vips2ppm() now both partial - started updating the C++ guide - had to change the location of the C++ headers :-( all C++ progs should now have: #include this is so things can work on systems which do not have case sensitive file systems - changes for Mac OS X * im_system() TRUE/FALSE removed * searches /*/[lib|include] to get fink libs for tiff and jpeg 30/4/02 JC - several functions were missing IM_FN_PIO in their descriptor ... this was harmless for nip/ip/C, but broke the ref counting in the C++ layer - im_system() now defaults "/tmp" for temp files - STRING input and output args were broken for C++ :-( - threads exit more quickly on error - im_min()/im_max() now partial (at last) - im_remainderconst()/im_remainderconst_vec() added - --with-dmalloc configure switch - vips2dj does CMYK and mono too - im_vips2tiff() allows any number of bands (but not the right way to write CMYK, see TODO) 26/4/02 JC - old ICC profile reader removed - little cms wrapped ... configure spots it, im_icc_transform() uses it to map between two images - also im_icc_import() and im_icc_export() so you can see PCS images - im_icc_present() to test for existence of lib - README fixes 4/4/02 JC - TODO changes - oops, DEBUG left on in im_invertlut() 2/4/02 JC - im_fwfft.c/im_invfft.c now use libfftw if available ... about 5x speed up and double precision - added FIND_FFTW autoconf macro - include/vips/proto.h changes 26/3/02 JC - started 7.7.19 25/3/02 JC - im_log_dmask() was broken (thanks matt) - casts between VDMask and VIMask were broken (thanks matt) - various error msgs improvements and tiny man page fixes 13/3/02 JC - tb/lr merge first/last cache moved to per-call state for better sharing - im_remosaic() bails out faster on error and makes better error messages 13/3/02 ruven - im_vips2tiff() pyramids stop at tilesize, not 64x64 25/02/02 JC - im_remosaic() is smarter, and works better with im_global_balance() - im_affine() 2x faster 14/2/02 JC - started 7.7.18 - vips.m4 and libsrc/Makefile.am fixes for IRIX 11/02/02 JC - vips/thread.h and vips/threadgroup.h were missing extern "C" for C++ - VImage::write() now tracks dependencies, so you can write() to a partial safely ... although it's not a very useful thing to do (thanks Mike) - new VImage::print() function for debugging - added im_print() 22/01/02 JC - started 7.7.17 15/01/02 JC - im_rect_unionrect() and im_rect_intersectrect() safer for repeated args - im_video_v4l() no longer perror()s on ioctl fail for less spam 03/01/02 JC - started 7.7.16 - im_version_string() really does return the date as well now 12/12/01 JC - im_guess_prefix() extra smartness for relative path names - VImage() no longer uses tmpnam() (thanks Paul) 11/12/01 JC - renamed im_fexists() as im_existsf() 7/12/01 JC - ppm man pages added (doh) 28/11/01 JC - warnings on g++ 2.96 fixed 22/11/01 JC - started 7.7.15 - im_video_v4l() failed to compile on non-linux platforms 7/11/01 JC - im_remosaic() added - im_*merge() are more intelligent about transparency in bizarre overlaps - grr! putenv() semantics change on more recent clibs ... should be safer now 19/10/01 JC - VDisplay( "display name" ) segved on unknown display :-( thanks mike 26/9/01 JC - contrib tools get data files from share/vips/xxx area now - im_vipshome() renamed as im_guess_prefix(), reworked for new package layout - doc/ build sorted out - ... but of course, docs still need updating for 7.8 20/9/01 JC - fix to im_vipshome() - ip2 renamed as nip - split to library only ... separate ip and nip packages - new VIPS_VERSION_* macros set from configure.in in vips/version.h.in - vips.m4 VIPS finder - reworked README, doc/README and TODO - now installs to /usr/local/ by default - fmask4th.c was including varargs.h ... d'oh - include area reorganised: everything inside now ... hopefully the only user-visible change is that all plain C progs need to change: #include to: #include the C++ API should be unaltered 21/8/01 ruven - im_setupout() was missing some #includes 20/8/01 JC - started 7.7.14 15/8/01 JC - added libxml dependency for ip2 27/7/01 JC - im_conv(), im_convf(), im_convsep(), im_convsepf() now reject masks with scale == 0 26/7/01 JC - started 7.7.12 25/7/01 JC - started 7.7.11 - oop, im_histeq() and im_tonemap() also missed - better error messages from im_run_command() 23/7/01 JC - started 7.7.10 - im_sharpen() failed due to change in im_band_extract() offset 20/7/01 JC - started 7.7.9 4/7/01 JC - im_open(,"w") open() delayed until im_setupout(), very slightly safer - updated im_open() man page - im_tiff2vips() now embeds index in filename ... and it's page number (from 0), not subsample factor - finally bit the bullet ... im_extract()/im_extract_band() now number from zero (sorry!) - and im_lrmosaic()/im_tbmosaic() bandno param too 29/6/01 JC - im_region_free() now frees immediately 27/6/01 JC - im_vips2tiff() man page updated for deflate, 2 years late 22/6/01 JC - oops, limit wrong on im_rank() 21/6/01 JC - better post_install for --prefix outside VIPS's tree - -ltiff needs -lm in acinclude.m4 ... fixes configure on redhat 7.x 13/6/01 JC - started 7.7.8 6/6/01 JC - im_invertlut() added 31/5/01 JC - im_colour_temperature, im_XYZ2Lab_temp, im_Lab2XYZ_temp added - ... colour temp stuff needs sorting out properly 25/5/01 JC - added vips-config script, cf. gtk-config - --without-threads option added - did a bit of work on the C++ API docs 24/5/01 JC - added im_tiff2vips_header(), im_jpeg2vips_header() and im_ppm2vips_header() - header uses these to print fields quickly - switched to config.h - configure.in rewritten ... much nicer, fewer options, more automatic 17/5/01 JC - im_matinv() didn't free stuff correctly on singular matrix 16/5/01 JC - vips2dj now knows about 5000ps printers - allow RW mode for non-native VIPS image files, for 8 bit images 2/5/01 JC - started 7.7.7 1/5/01 JC - im_addgnoise() did not work for >1 band images 23/4/01 JC - configure options to remove support for JPEG and TIFF ... helpful for a no- dependencies build 20/4/01 JC - im_(v)snprintf() added - all sprintf()s removed 15/4/01 JC - im_affine() had a rounding problem 11/4/01 JC - tiny mosaicing bug fixed in im__lrcalcon - started 7.7.6 21/3/01 JC - new iblend code in im_tbmerge() was typo-d - mosaic1 was broken by affine too 20/3/01 JC - im_image() failed for FMTUCHAR 12/3/01 JC - started 7.7.5 - im_sharpen() uses separable convolution for big speed up - new "Print" menu 11/3/01 JC - REALVEC renamed as DOUBLEVEC - added IMAGEVEC - added IM_INPUT_IMAGEVEC - gbandjoin now has function description - new function im_maxvalue() - im_compass()/im_lindetect() reimplemented with im_conv()/im_maxvalue(), about 15% faster, works for any type, partial - im_gradient() reimplemented with im_conv()/im_abs()/im_add(), about 30% slower, works for any type, partial 10/3/01 JC - new function, im_clip2fmt() converts between any image formats ... slightly faster than the old im_clip() - legacy im_clip2us() etc. functions now just call this 9/3/01 JC - im_conv() rewritten, simpler, about 10% faster - im_convsep() rewritten, now does any non-complex type, partial, 20% faster - new functions: im_convf(), im_convsepf() for DOUBLEMASK - raw versions of each - legacy convolvers (eg. im_convbi()) removed 8/3/01 JC - new function im_blend() - new function im_lab_morph() - speed up to im_ifthenelse() - speed up to im_*merge() (uses integer arithmetic for integer blends) 4/3/01 JC - tiny speed ups to im_histgr() - speed ups to im_maplut() 3/3/01 JC - new functions: im_histnorm(), im_histcum() - im_histeq() more general - im_vipshome() --- better behaviour for relative paths 2/3/01 JC - new video package - im_video_v4l1() (video for linux) added - configure.in switches to turn v4l1 on and off 1/3/01 JC - new im_histspec() implementation ... more general, bugs removed 14/2/01 JC - better vips2dj usage message 13/2/01 JC - im_image_sanity() added, called in various places in iofuncs 9/2/01 JC - added 'check' and 'name' class member stuff to ip from ip_gtk2 - new "Plot" menu - new "Overlay" menu - more stuff in _stdenv/_list ... curried forms of head/tail etc. 7/2/01 JC - started 7.7.4 - vips2dj and vdump now use im_vipshome() 5/2/01 JC - new im_vipshome() function - min()/max() macros renamed as MIN()/MAX() - new im_load_plugins() function - vips.exe and ip now load $VIPSHOME/lib plugins at startup 2/2/01 JC - mosaicing functions now have an extra max blend width parameter 30/1/01 JC - fixed tbmerge no overlap detect 13/12/00 JC - started 7.7.3 30/12/00 JC - vips.h fixes for cygwin/wingdi conflict 27/11/00 JC - added im_vips2ppm(), im_open() imports and exports it - fixed nasty implicit output conversion problem for PIO dispatch() calls 21/11/00 JC - added im_ppm2vips() 16/11/00 JC - configure.in fixes ... jpeg found correctly now - searches for libz as well 16/11/00 JC - started 7.7.2 5/11/00 JC - speed up to lab2labq 19/10/00 JC - started 7.7.1 13/1/00 JC - oops, im_open() was missing an 'else' in jpeg/tiff load 5/8/00 JC - im_vips2tiff() now has mode string embedded in output filename - im_vips2jpeg() now has qfac in output filename - im_open() understands this 11/7/00 JC - new im_image() function ... wraps a VIPS image around a memory buffer - C++ layer changes: * now use #include * error renamed as VError * new VMask() constructors * new VImage() constructor * new VImage::data() access member * more operator equivalences: <, >, <=, >=, ==, !=, &, |, ^, % 17/6/00 JC - more consts added to vips protos 10/5/00 JC - minor configure.in changes to help solaris - removed _TIFFmalloc() and _TIFFfree() calls 9/3/00 JC - fixed rounding problem in generate grid 8/3/00 JC - fixup to im_system() temp dir 7/3/00 JC - added im_system() - small tidies 1/3/00 JC - better plugin test in configure.in 26/2/00 JC - fixes to Makefile.am in ip/src* and configure.in, to help ip find the right gtk includes on systems with more than one gtk-xxx installed 21/2/00 JC - now builds ip and ip_gtk2 16/2/00 JC - configure.in fixes for xil and some TIFF/JPEG strangeness 15/2/00 JC - im_global_balancef() was broken! d'oh - note in README about enabling video cards 10/2/00 JC - configure now searches for xil ... FIND_XIL macro - im_zoom() spots integer overflow - better shape set on region drag end in ip - better zoom-too-far handling in ip 13/1/00 JC - fixes to configure etc. to help cygwin - jpeg is now searched for too ... FIND_JPEG macro 10/1/00 JC - global_balance() now uses new affine() atuff 27/12/99 JC - mosaic1 stuff now uses new affine() funcs 21/12/99 JC - added Joe's docs - im_LabS2LabQ() rounding on a/b slightly broken for a/b == 0 20/12/99 JC - new function: im_affine() - similarity*() now in terms of affine() - tests for error return in reduce.c from maplut - small clean-ups 15/12/99 - im_version() added, new iofuncs package for it - ip did not call zero-input-arg vips functions - vips.c did not like zero-input-arg functions 6/12/99 JC - Sobel filter was a bit broken 3/12/99 JC - menu reorganisation - generate gauss mask dialog 2/12/99 JC - reworked text file IO, better error messages 1/12/99 JC - reworked .iprc filename stuff, cleaner 30/11/99 JC - better menu set switcher in calc preferences - ip now thinks it's 7.7 - did a spellcheck on the ip guide 29/11/99 JC - 7.7 started! - srgb D65->D50 converter - Negate added to arith - find similar pixel value dialog - find similar colour dialog - paste into background dialog 19/11/99 JC - adjust labq was missing - shrink image defaulted to /2 not /1 - sharpdropshadow broken - Rotate.* broken - vips-7.6.3 release 18/11/99 JC - ip didn't report space free on >2GB filesystems correctly - ip did not link statically against libXpm on solaris7 17/11/99 JC - im_histplot() failed for all 0's histogram - new profile_image dialog - man pages for im_sRGB2XYZ/im_XYZ2sRGB were broken - new colourize image dialog - new shrink image image dialog - new expand image image dialog - better doc Makefiles 16/11/99 JC - more menu reorganising - new image_to_mask/mask_to_image buttons - new match_two_images dialog - new measure_colour_chart dialog 15/11/99 JC - new custom LABQ sharpen in Image menu - configure support for SGI video (thanks Ruven) - menu fiddling in ip - new "resize canvas" menu item - im_insert_noexpand() added, no docs tho' 11/11/99 JC - new ip menu item: Image=>Adjust white/black/saturation of LabQ - fixed bug in decompose complex number - browse-icons now ignores errors - better error msg for "12 12" etc cases 10/11/99 JC - open hi-res gives proper error msg if no file found - made file-select boxes a bit more compact and clearer - updated configure.in for vips-examples-7.6 9/11/99 JC - new column start point moved - vdump now defaults to subsample 1, portrait - navigation boxes were broken - no longer shrink-to-fit if loading as high res - better positioning of zoom windows - removed some old cruft 8/11/99 JC - ooops, im_remainder() got lost somehow - refguide converted to latex and updated - cppguide updated 5/11/99 JC - libguide converted to latex and updated 4/11/99 JC - ip guide now latex2htmls cleanly ... still needs updating tho' - cpp/app guide latex2html redone 2/11/99 JC - configure no longer adds -32 to IRIX builds for you - some more stuff in README - simple DEBUGM malloc tracking, made libsrc/iofuncs/memory.c - changed im_malloc() to return void * - removed duplicate im_malloc() proto from util.h - changed all malloc/free to go through im_malloc()/im_free() 23/10/99 JC - double-click on error image now pops a load browser and an error dialog - add-new-column no longer scrolls to right edge of workspace - better scroll-to-bottom on item add - load ws twice does not cause 'already open' errors - memorise directory button in fsb 18/10/99 JC - new FIND_TIFF/FIND_MOTIF macros for acinclude.m4 - new ./configure switches, see ./configure --help - enabled static libs 8/10/99 - broke action_proc_bop() into smaller functions, stops bad code gen on gcc2.95.1 (and others, prolly) - restored old Makefiles in doc/src/ipguide - vips7.6 script renamed as vips-7.6 5/10/99 - replace image was broken - some menu reorganisation - 'reload all menus' button 4/10/99 - computed regions in ip were broken - updated system.iprc defaults - new menu item: adjust white/black points 2/10/99 - browse icons was broken - greyscale 16-bit tiled tiff was broken - extra mutex locks for TIFF*() in im_tiff2vips() 1/10/99 - some automake probs fixed - squished two ip bugs 30/9/99 - fixed problem with pthreads, now works on suse6.2 as well - new API stuff for threaded evaluation with im_threadgroup_t - new public interface provide platform independent threads/locks/semaphores - no error box if you zoom out too far now 26/9/99 - lr/tb merge blend was not quite right ... should be smoother now - histplot broken for float images 24/9/99 - better mono->labq converter - more portable ispoweroftwo detect for freq filter stuff 23/9/99 - better graphics expose handling 17/9/99 - >/< stuff in ip was a bit mixed up - ink preview fixed for mono images - help popup fixed 15/9/99 - linedetect and sobel filters for ip, thnx Kirk 14/9/99 - Find_histogram was broken - im_profile() man pages was broken - ooops, ip had old set of macros 10/9/99 - im_and/im_or/im_eor now work for any integer type Summer hols: (2nd half August '99) - initial heap block larger to avoid start gcs - def slicer fixed - larger max heap - toolkits with initial '_' hidden by default - custom recomb - dialog.def removed - ... other menu fixes - generate grid menu - im_remainder() added - new cursor change code, hglass rotates during comp! - dialog.c handles cursor changes better - rubber band in paintbox displays - mag widget stays on right! - undo/redo single pixel paint ops - heap size control from prefs - cancel for reductions as well as for image calc - browse stuff reworked, no more .icon.v files - save stops you overwriting open .v files - better animate_countdown() handling - better resize behaviour for bars added to images - better code generation, bug fixed in state tracking - auto recover from crash libvips-8.18.2/LICENSE000066400000000000000000000636421516303661500143100ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libvips-8.18.2/README.md000066400000000000000000000237001516303661500145510ustar00rootroot00000000000000# libvips: an image processing library [![CI](https://github.com/libvips/libvips/workflows/CI/badge.svg)](https://github.com/libvips/libvips/actions) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libvips.svg)](https://issues.oss-fuzz.com/issues?q=is:open%20project:libvips) [![Coverity Status](https://scan.coverity.com/projects/6503/badge.svg)](https://scan.coverity.com/projects/jcupitt-libvips) [![Gitter](https://badges.gitter.im/libvips/devchat.svg)](https://gitter.im/libvips/devchat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) # Introduction libvips is a [demand-driven, horizontally threaded](https://github.com/libvips/libvips/wiki/Why-is-libvips-quick) image processing library. Compared to similar libraries, [libvips runs quickly and uses little memory](https://github.com/libvips/libvips/wiki/Speed-and-memory-use). libvips is licensed under the [LGPL-2.1-or-later]( https://spdx.org/licenses/LGPL-2.1-or-later). It has around [300 operations](https://www.libvips.org/API/current/function-list.html) covering arithmetic, histograms, convolution, morphological operations, frequency filtering, colour, resampling, statistics and others. It supports a large range of [numeric types](https://www.libvips.org/API/current/enum.BandFormat.html), from 8-bit int to 128-bit complex. Images can have any number of bands. It supports a good range of image formats, including JPEG, JPEG 2000, JPEG XL, TIFF, PNG, WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM, CSV, GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images via ImageMagick or GraphicsMagick, letting it work with formats like DICOM. It comes with bindings for [C](https://www.libvips.org/API/current/using-from-c.html), [C++](https://www.libvips.org/API/current/using-from-cplusplus.html), and the [command-line](https://www.libvips.org/API/current/using-the-cli.html). Full bindings are available for: | Language | Binding | |---|---| | Ruby | [ruby-vips](https://rubygems.org/gems/ruby-vips) | | Python | [pyvips](https://pypi.python.org/pypi/pyvips) | | PHP | [php-vips](https://github.com/libvips/php-vips) | | C# / .NET | [NetVips](https://www.nuget.org/packages/NetVips) | | Go | [vips-gen](https://github.com/cshum/vipsgen) | | Lua | [lua-vips](https://github.com/libvips/lua-vips) | | Crystal | [crystal-vips](https://github.com/naqvis/crystal-vips) | | Elixir | [vix](https://github.com/akash-akya/vix) | | Java | [vips-ffm](https://github.com/lopcode/vips-ffm) | | Nim | [libvips-nim](https://github.com/openpeeps/libvips-nim) | libvips is used as an image processing engine by: | | |---| | [Mastodon](https://github.com/mastodon/mastodon) | | [sharp (on Node.js)](https://www.npmjs.org/package/sharp) | | [imgproxy](https://github.com/imgproxy/imgproxy) | | [wsrv.nl](https://github.com/weserv/images) | | [bimg](https://github.com/h2non/bimg) | | [Ruby on Rails](https://edgeguides.rubyonrails.org/active_storage_overview.html) | | [CarrierWave](https://github.com/carrierwaveuploader/carrierwave#using-vips) | | [MediaWiki](https://www.mediawiki.org/wiki/Extension:Thumbro) | and others. The official libvips GUI is [nip2](https://github.com/libvips/nip2), a strange combination of a spreadsheet and a photo editor. # Install There are packages for most Unix-like operating systems, including macOS. Check your package manager. There are binaries for Windows in [releases](https://github.com/libvips/libvips/releases). The [libvips website](https://www.libvips.org) has [detailed install notes](https://www.libvips.org/install.html). # Building from source libvips uses the [Meson build system](https://mesonbuild.com), version 0.56 or later. Meson can use [`ninja`](https://ninja-build.org), Visual Studio or XCode as a backend, so you'll also need one of them. libvips must have `build-essential`, `pkg-config`, `libglib2.0-dev`, `libexpat1-dev`. See the **Dependencies** section below for a full list of the libvips optional dependencies. There are basic bash completions in `completions/`, see the README in there. ## Cheatsheet ``` cd libvips-x.y.x meson setup build --prefix /my/install/prefix cd build meson compile meson test meson install ``` Check the output of `meson setup` carefully and make sure it found everything you wanted it to find. Add arguments to `meson setup` to change the build configuration. - Add flags like `-Dnsgif=false` to turn libvips options on and off, see `meson_options.txt` for a list of all the build options libvips supports. - Add flags like `-Dmagick=disabled` to turn libvips dependencies on and off, see `meson_options.txt` and the list below for a summary of all the libvips dependencies. - You might need to add `--libdir lib` on Debian if you don't want the arch name in the library path. - Add `--default-library static` for a static build. - Use e.g. `CC=clang CXX=clang++ meson setup ...` to change compiler. - You can have an alternative build directory, pick whatever names you like, for example one for release and one for debug. There's a more comprehensive test suite you can run once libvips has been installed. Use `pytest` in the libvips base directory. ## Optional dependencies If suitable versions are found, libvips will add support for the following libraries automatically. Packages are generally found with `pkg-config`, so make sure that is working. ### libjpeg Anything that is compatible with the IJG JPEG library. Use `mozjpeg` if you can. Another option is `libjpeg-turbo`. ### libultrahdr (libuhdr) If present, libvips will load UltraHDR images with Google's libultrahdr library. The `pkg-config` name is libuhdr. ### libexif If available, libvips adds support for EXIF metadata in JPEG files. ### librsvg The usual SVG loader. If this is not present, vips will try to load SVGs via imagemagick instead. ### libraw The usual camera RAW loader. If this is not present, vips will try to load raw camera images via imagemagick instead. ### PDFium If present, libvips will attempt to load PDFs with PDFium. Download the prebuilt pdfium binary from: https://github.com/bblanchon/pdfium-binaries/releases/latest Untar to the libvips install prefix, for example: ``` cd ~/vips tar xf ~/pdfium-linux.tgz ``` Create a `pdfium.pc` like this (update the version number): ``` VIPSHOME=$HOME/vips mkdir -p $VIPSHOME/lib/pkgconfig cat > $VIPSHOME/lib/pkgconfig/pdfium.pc << EOF prefix=$VIPSHOME exec_prefix=\${prefix} libdir=\${exec_prefix}/lib includedir=\${prefix}/include Name: pdfium Description: PDFium Version: 4290 Libs: -L\${libdir} -lpdfium Cflags: -I\${includedir} EOF ``` If PDFium is not detected, libvips will look for `poppler-glib` instead. ### poppler-glib The Poppler PDF renderer, with a glib API. If this is not present, vips will try to load PDFs via imagemagick. ### cgif If available, libvips will save GIFs with [cgif](https://github.com/dloebl/cgif). If this is not present, vips will try to save gifs via imagemagick instead. ### libarchive If available, libvips adds support for creating image pyramids with `dzsave`. ### libtiff The TIFF library. It needs to be built with support for JPEG and ZIP compression. 3.4b037 and later are known to be OK. ### fftw3 If libvips finds this library, it uses it for fourier transforms. ### lcms2 If present, `vips_icc_import()`, `vips_icc_export()` and `vips_icc_transform()` can be used to manipulate images with ICC profiles. ### libpng If present, libvips will load and save PNG files using libpng. If not, it will look for the spng package. ### libimagequant, quantizr If one of these quantisation packages is present, libvips can write 8-bit palette-ised PNGs and GIFs. ### ImageMagick, or optionally GraphicsMagick If available, libvips adds support for loading and saving all libMagick-supported image file types. You can enable and disable load and save separately. Imagemagick 6.9+ needs to have been built with `--with-modules`. Most packaged IMs are, I think. If you are going to be using libvips with untrusted images, perhaps in a web server, for example, you should consider the security implications of enabling a package with such a large attack surface. ### pangocairo If available, libvips adds support for text rendering. You need the package pangocairo in `pkg-config --list-all`. ### highway If present, libvips will accelerate some operations with SIMD. If not, it will look for the orc-0.4 package. ### matio If available, vips can load images from Matlab save files. ### cfitsio If available, vips can load FITS images. ### libwebp If available, vips can load and save WebP images. ### libniftiio If available, vips can load and save NIfTI images. ### OpenEXR If available, libvips will directly read (but not write, sadly) OpenEXR images. ### OpenJPEG If available, libvips will read and write JPEG2000 images. ### libjxl If available, libvips will read and write JPEG-XL images. ### OpenSlide If available, libvips can load OpenSlide-supported virtual slide files: Aperio, Hamamatsu, Leica, MIRAX, Sakura, Trestle, and Ventana. ### libheif If available, libvips can load and save HEIC and AVIF images. Your libheif (in turn) needs to be built with the correct decoders and encoders. You can check with eg.: ```console $ heif-convert --list-decoders HEIC decoders: - libde265 = libde265 HEVC decoder, version 1.0.9 AVIF decoders: - dav1d = dav1d v6.6.0 - aom = AOMedia Project AV1 Decoder v3.5.0 $ heif-enc --list-encoders HEIC encoders: - x265 = x265 HEVC encoder (3.5+1-f0c1022b6) [default] AVIF encoders: - aom = AOMedia Project AV1 Encoder v3.5.0 [default] - svt = SVT-AV1 encoder v1.1.0 - rav1e = Rav1e encoder ``` # Contributors ### Code Contributors This project exists thanks to all the people who contribute. ### Organizations We've had generous financial support from our sponsors. Thank you very much! libvips-8.18.2/completions/000077500000000000000000000000001516303661500156245ustar00rootroot00000000000000libvips-8.18.2/completions/README.md000066400000000000000000000015441516303661500171070ustar00rootroot00000000000000# Shell completions for vips Basic shell completions for the `vips` program. Internally, these use the `-c` argument to `vips` to list argument options. ## Example ``` $ vips relational relational relational_const $ vips relational_const ~/pics/k2. ~/pics/k2.avif ~/pics/k2.hdr ~/pics/k2.pdf ~/pics/k2.tif ~/pics/k2.bmp ~/pics/k2.heic ~/pics/k2.pfm ~/pics/k2.v ~/pics/k2.csv ~/pics/k2.jp2 ~/pics/k2.pgm ~/pics/k2.vips ~/pics/k2.fits ~/pics/k2.jpg ~/pics/k2.png ~/pics/k2.webp ~/pics/k2.flif ~/pics/k2.jxl ~/pics/k2.ppm ~/pics/k2.gif ~/pics/k2.pbm ~/pics/k2.ppt $ vips relational_const ~/pics/k2.jpg x.v less less lesseq $ vips relational_const ~/pics/k2.jpg x.v lesseq 12 ``` ## Install ### `vips-completion.bash` Usually copy to `/etc/bash_completion.d` to install, but it depends on your system. libvips-8.18.2/completions/vips-completion.bash000066400000000000000000000020641516303661500216150ustar00rootroot00000000000000#/usr/bin/env bash # bash completions for the "vips" command # copy to /etc/bash_completion.d to install _vips_compgen_f() { COMPREPLY=($(compgen -f -- "${COMP_WORDS[-1]}")) if [ ${#COMPREPLY[@]} = 1 ]; then local LASTCHAR= if [ -d "$COMPREPLY" ]; then LASTCHAR=/ fi COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR") else for ((i=0; i < ${#COMPREPLY[@]}; i++)); do if [ -d "${COMPREPLY[$i]}" ]; then COMPREPLY[$i]=${COMPREPLY[$i]}/ fi done fi } _vips_completions() { if [ ${#COMP_WORDS[@]} == "2" ]; then COMPREPLY=($(compgen -W "$(vips -c)" "${COMP_WORDS[1]}")) else local args=($(vips -c ${COMP_WORDS[1]})) local arg_type=${args[${#COMP_WORDS[@]}-3]} if [ x$arg_type == x"" ]; then COMPREPLY= elif [ $arg_type == "file" ]; then _vips_compgen_f elif [[ $arg_type = word:* ]]; then local options=$(echo $arg_type | sed 's/word://' | sed 's/|/ /g') COMPREPLY=($(compgen -W "${options[@]}" "${COMP_WORDS[-1]}")) fi fi } complete -F _vips_completions vips libvips-8.18.2/cplusplus/000077500000000000000000000000001516303661500153225ustar00rootroot00000000000000libvips-8.18.2/cplusplus/Doxyfile.in000066400000000000000000000023541516303661500174410ustar00rootroot00000000000000PROJECT_NAME = vips-cpp PROJECT_NUMBER = @VIPS_MAJOR_VERSION@.@VIPS_MINOR_VERSION@ PROJECT_BRIEF = "libvips C++ binding" OUTPUT_DIRECTORY = @DOXY_OUTPUT_DIRECTORY@ QUIET = YES INPUT = @DOXY_INPUT_DIRECTORY@/README.md \ @DOXY_INPUT_DIRECTORY@/VConnection.cpp \ @DOXY_INPUT_DIRECTORY@/VError.cpp \ @DOXY_INPUT_DIRECTORY@/VImage.cpp \ @DOXY_INPUT_DIRECTORY@/VInterpolate.cpp \ @DOXY_INPUT_DIRECTORY@/VRegion.cpp \ @DOXY_INPUT_DIRECTORY@/vips-operators.cpp \ @DOXY_INPUT_DIRECTORY@/include/vips/VConnection8.h \ @DOXY_INPUT_DIRECTORY@/include/vips/VError8.h \ @DOXY_INPUT_DIRECTORY@/include/vips/VImage8.h \ @DOXY_INPUT_DIRECTORY@/include/vips/VInterpolate8.h \ @DOXY_INPUT_DIRECTORY@/include/vips/VRegion8.h \ @DOXY_INPUT_DIRECTORY@/include/vips/vips8 USE_MDFILE_AS_MAINPAGE = @DOXY_INPUT_DIRECTORY@/README.md GENERATE_LATEX = NO HAVE_DOT = YES DOT_IMAGE_FORMAT = svg libvips-8.18.2/cplusplus/README.md000066400000000000000000000227551516303661500166140ustar00rootroot00000000000000### Introduction The libvips C++ API is a thin layer over the libvips GObject API. It adds automatic reference counting, exceptions, operator overloads, and automatic constant expansion. You can drop down to the C API at any point, so all the C API docs also work for C++. ### Example /* compile with: * g++ -g -Wall example.cc `pkg-config vips-cpp --cflags --libs` */ #include using namespace vips; int main (int argc, char **argv) { if (VIPS_INIT (argv[0])) vips_error_exit (NULL); if (argc != 3) vips_error_exit ("usage: %s input-file output-file", argv[0]); VImage in = VImage::new_from_file (argv[1], VImage::option ()->set ("access", VIPS_ACCESS_SEQUENTIAL)); double avg = in.avg (); printf ("avg = %g\n", avg); printf ("width = %d\n", in.width ()); in = VImage::new_from_file (argv[1], VImage::option ()->set ("access", VIPS_ACCESS_SEQUENTIAL)); VImage out = in.embed (10, 10, 1000, 1000, VImage::option ()-> set ("extend", "background")-> set ("background", 128)); out.write_to_file (argv[2]); vips_shutdown (); return 0; } Everything before `VImage in = VImage::new_from_file()` is exactly as the C API. `vips_error_exit()` just prints the arguments plus the libvips error log and exits with an error code. `VImage::new_from_file()` is the C++ equivalent of `vips_image_new_from_file()`. It works in the same way, the differences being: - VImage lifetime is managed automatically, like a smart pointer. You don't need to call `g_object_unref()`. - Instead of using varargs and a `NULL`-terminated option list, this function takes an optional `VOption` pointer. This gives a list of name / value pairs for optional arguments to the function. In this case we request unbuffered IO for the image, meaning, we expect to do a single top-to-bottom scan of the image and do not need it to be decompressed entirely. You can use the C enum name, as is done in this case, or use a string and have the string looked up. See below. The function will delete the `VOption` pointer for us when it's finished with it. - Instead of returning `NULL` on error, this constructor will raise a `VError` exception. There are a series of similar constructors which parallel the other constructors in the C API, see `VImage::new_from_memory()`, `VImage::new_from_buffer()`, and `VImage::new_matrix()`. The convenience function `VImage::new_from_image()` makes a constant image from an existing image. The image it returns will have the same size, interpretation, resolution and format as the image you call it on, but with every pixel having the constant value you specify. For example: new_image = image.new_from_image (12); Now `new_image` has the same size as `image`, but has one band, and every pixel has the value 12. You can pass a `std::vector` as the argument to make a constant image with a different number of bands. There's also `VImage::new_memory()` and `VImage::new_temp_file()`, which when written to with `VImage::write()` will create whole images on memory or on disc. The next line finds the average pixel value, it's the equivalent of the `vips_avg()` function. The differences from the C API are: - `VImage::avg()` is a member function: the `this` parameter is the first (the only, in this case) input image. - The function returns the first output parameter, in this case the average pixel value. Other return values are via pointer arguments, as in the C API. - Like `VImage::new_from_file()`, function raises the `VError` exception on error. - Like `VImage::new_from_file()`, extra arguments are passed via an optional `VOption` parameter. There are none in this case, so the function brackets can be left empty. All other operations follow the same pattern, for example the C API call `vips_add(`): int vips_add (VipsImage *left, VipsImage *right, VipsImage **out, ...); appears in C++ as: VImage VImage::add (VImage right, VOption *options) const The next line uses `VImage::width()` to get the image width in pixels. There are similar functions paralleling `vips_image_get_format()` and friends. Use `VImage::set()` to set metadata fields, `VImage::get_int()` and c. to fetch metadata. Next we reload the image. The `VImage::avg()` will have scanned the image and reached the end of the file, we need to scan again for the next operation. If we'd selected random access mode (the default) in the original `VImage::new_from_file()`, we would not need to reload. The next line runs `vips_embed()` with two optional parameters. The first sets the value to an enum (here we use a string to set the value, it'll be looked up in the list of possible enum values, or you can use the symbols from the C API), the second sets the value to an `int`. The `"background"` parameter is actually a `VipsArrayDouble`: if you pass an `int` instead, it will be automatically converted to a one-element array for you. You can pass a `std::vector` too: the utility function `VImage::to_vectorv()` is a convenient way to make one. Finally, `VImage::write_to_file()` will write the new image to the filesystem. You can add a `VOption` as a final parameter and set options for the writer if you wish. Again, the operation will throw a `VError` exception on error. The other writers from the C API are also present: you can write to a memory array, to a formatted image in memory, or to another image. The API docs have a [handy table of all vips operations](https://www.libvips.org/API/current/function-list.html), if you want to find out how to do something, try searching that. ### Automatic constant expansion The C++ API will automatically turn constants into images in some cases. For example, you can join two images together bandwise (the bandwise join of two RGB images would be a six-band image) with: VImage rgb = ...; VImage six_band = rgb.bandjoin (rgb); You can also bandjoin a constant, for example: VImage rgb_with_alpha = rgb.bandjoin (255); Will add an extra band to an image, with every element in the new band having the value 255. This is quite a general feature. You can use a constant in most places where you can use an image and it will be converted. For example: VImage a = (a < 128).ifthenelse (128, a); Will set every band element of `a` less than 128 to 128. The C++ API includes the usual range of arithmetic operator overloads. You can mix constants, vectors and images freely. The API overloads `[]` to be `vips_extract_band()`. You can write: VImage xyz = VImage::xyz (256, 256) - VImage::to_vectorv (2, 128.0, 128.0); VImage mask = (xyz[0].pow (2) + xyz[1].pow (2)).pow (0.5) < 100; to make a circular mask, for example. The API overloads `()` to be `vips_getpoint()`. You can write: VImage xyz = VImage::xyz (256, 256) - VImage::to_vectorv (2, 128.0, 128.0); // this will have the value [0, 0] std::vector point = xyz (128, 128); ### Enum expansion libvips operations which implement several functions with a controlling enum, such as `vips_math()`, are expanded to a set of member functions named after the enum. For example, the C function: int vips_math (VipsImage *in, VipsImage **out, VipsOperationMath math, ...); where `VipsOperationMath` has the member `VIPS_OPERATION_MATH_SIN`, has a C convenience function `vips_sin()`: int vips_sin (VipsImage *in, VipsImage **out, ...); and a C++ member function `VImage::sin()`: VImage VImage::sin (VOption *options = nullptr) const ### Image metadata libvips images can have a lot of metadata attached to them, giving things like ICC profiles, EXIF data, and so on. You can use the command-line program `vipsheader` with the `-a` flag to list all the fields. You can read metadata items with the member functions `get_int()`, `get_double()`, `get_string()` and `get_blob()`. Use `get_typeof()` to call `vips_image_get_typeof()` and read the type of an item. This will return 0 for undefined fields. const char *VImage::get_string (const char *field); You can use the `set()` family of overloaded members to set metadata, for example: void VImage::set (const char *field, const char *value); You can use these functions to manipulate exif metadata, for example: VImage im = VImage::new_from_file ("x.jpg") int orientation = im.get_int (VIPS_META_ORIENTATION); im.set (VIPS_META_ORIENTATION, 2); im.write_to_file ("y.jpg"); ### Extending the C++ interface The C++ interface comes in two parts. First, `VImage8.h` defines a simple layer over `GObject` for automatic reference counting, then a generic way to call any vips8 operation with `VImage::call()`, then a few convenience functions, then a set of overloads. The member definition and declaration for each operation, for example `VImage::add()`, is generated by a small Python program called `gen-operators.py`. If you write a new libvips operator, you'll need to rerun this program to make it visible in the C++ interface. You can write the wrapper yourself, of course, they are very simple. The one for `VImage::add()` looks like this: VImage VImage::add (VImage right, VOption *options) const { VImage out; call("add", (options ? options : VImage::option())-> set("out", &out)-> set("left", *this)-> set("right", right)); return out; } Where `VImage::call()` is the generic call-a-vips8-operation function. libvips-8.18.2/cplusplus/VConnection.cpp000066400000000000000000000050531516303661500202560ustar00rootroot00000000000000/* Object part of the VSource and VTarget class */ /* Copyright (C) 1991-2001 The National Gallery This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include /* #define VIPS_DEBUG #define VIPS_DEBUG_VERBOSE */ VIPS_NAMESPACE_START VSource VSource::new_from_descriptor(int descriptor) { VipsSource *input; if (!(input = vips_source_new_from_descriptor(descriptor))) throw VError(); VSource out(input); return out; } VSource VSource::new_from_file(const char *filename) { VipsSource *input; if (!(input = vips_source_new_from_file(filename))) throw VError(); VSource out(input); return out; } VSource VSource::new_from_blob(VipsBlob *blob) { VipsSource *input; if (!(input = vips_source_new_from_blob(blob))) throw VError(); VSource out(input); return out; } VSource VSource::new_from_memory(const void *data, size_t size) { VipsSource *input; if (!(input = vips_source_new_from_memory(data, size))) throw VError(); VSource out(input); return out; } VSource VSource::new_from_options(const char *options) { VipsSource *input; if (!(input = vips_source_new_from_options(options))) throw VError(); VSource out(input); return out; } VTarget VTarget::new_to_descriptor(int descriptor) { VipsTarget *output; if (!(output = vips_target_new_to_descriptor(descriptor))) throw VError(); VTarget out(output); return out; } VTarget VTarget::new_to_file(const char *filename) { VipsTarget *output; if (!(output = vips_target_new_to_file(filename))) throw VError(); VTarget out(output); return out; } VTarget VTarget::new_to_memory() { VipsTarget *output; if (!(output = vips_target_new_to_memory())) throw VError(); VTarget out(output); return out; } VIPS_NAMESPACE_END libvips-8.18.2/cplusplus/VError.cpp000066400000000000000000000022511516303661500172450ustar00rootroot00000000000000// Code for error type /* Copyright (C) 1991-2001 The National Gallery This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include VIPS_NAMESPACE_START std::ostream & operator<<(std::ostream &file, const VError &err) { err.ostream_print(file); return file; } void VError::ostream_print(std::ostream &file) const { file << what(); } VIPS_NAMESPACE_END libvips-8.18.2/cplusplus/VImage.cpp000066400000000000000000000725231516303661500172070ustar00rootroot00000000000000/* Object part of VImage class * * 30/12/14 * - allow set enum value from string * 10/6/16 * - missing implementation of VImage::write() * 11/6/16 * - added arithmetic assignment overloads, += etc. */ /* Copyright (C) 1991-2001 The National Gallery This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include /* #define VIPS_DEBUG #define VIPS_DEBUG_VERBOSE */ VIPS_NAMESPACE_START /** * \namespace vips * * General docs for the vips namespace. */ std::vector to_vectorv(int n, ...) { std::vector vector(n); va_list ap; va_start(ap, n); for (int i = 0; i < n; i++) vector[i] = va_arg(ap, double); va_end(ap); return vector; } std::vector to_vector(double value) { return to_vectorv(1, value); } std::vector to_vector(int n, double array[]) { std::vector vector(n); for (int i = 0; i < n; i++) vector[i] = array[i]; return vector; } std::vector negate(std::vector vector) { std::vector new_vector(vector.size()); for (std::vector::size_type i = 0; i < vector.size(); i++) new_vector[i] = vector[i] * -1; return new_vector; } std::vector invert(std::vector vector) { std::vector new_vector(vector.size()); for (std::vector::size_type i = 0; i < vector.size(); i++) new_vector[i] = 1.0 / vector[i]; return new_vector; } VOption::~VOption() { std::list::iterator i; for (i = options.begin(); i != options.end(); ++i) delete *i; } // input bool VOption * VOption::set(const char *name, bool value) { Pair *pair = new Pair(name); pair->input = true; g_value_init(&pair->value, G_TYPE_BOOLEAN); g_value_set_boolean(&pair->value, value); options.push_back(pair); return this; } // input int ... this path is used for enums as well VOption * VOption::set(const char *name, int value) { Pair *pair = new Pair(name); pair->input = true; g_value_init(&pair->value, G_TYPE_INT); g_value_set_int(&pair->value, value); options.push_back(pair); return this; } // input guint64 VOption * VOption::set(const char *name, guint64 value) { Pair *pair = new Pair(name); pair->input = true; g_value_init(&pair->value, G_TYPE_UINT64); g_value_set_uint64(&pair->value, value); options.push_back(pair); return this; } // input double VOption * VOption::set(const char *name, double value) { Pair *pair = new Pair(name); pair->input = true; g_value_init(&pair->value, G_TYPE_DOUBLE); g_value_set_double(&pair->value, value); options.push_back(pair); return this; } VOption * VOption::set(const char *name, const char *value) { Pair *pair = new Pair(name); pair->input = true; g_value_init(&pair->value, G_TYPE_STRING); g_value_set_string(&pair->value, value); options.push_back(pair); return this; } // input vips object (image, source, target, etc. etc.) VOption * VOption::set(const char *name, const VObject value) { Pair *pair = new Pair(name); VipsObject *object = value.get_object(); GType type = G_OBJECT_TYPE(object); pair->input = true; g_value_init(&pair->value, type); g_value_set_object(&pair->value, object); options.push_back(pair); return this; } // input int array VOption * VOption::set(const char *name, std::vector value) { Pair *pair = new Pair(name); int *array; pair->input = true; g_value_init(&pair->value, VIPS_TYPE_ARRAY_INT); vips_value_set_array_int(&pair->value, nullptr, static_cast(value.size())); array = vips_value_get_array_int(&pair->value, nullptr); for (std::vector::size_type i = 0; i < value.size(); i++) array[i] = value[i]; options.push_back(pair); return this; } // input double array VOption * VOption::set(const char *name, std::vector value) { Pair *pair = new Pair(name); double *array; pair->input = true; g_value_init(&pair->value, VIPS_TYPE_ARRAY_DOUBLE); vips_value_set_array_double(&pair->value, nullptr, static_cast(value.size())); array = vips_value_get_array_double(&pair->value, nullptr); for (std::vector::size_type i = 0; i < value.size(); i++) array[i] = value[i]; options.push_back(pair); return this; } // input image array VOption * VOption::set(const char *name, std::vector value) { Pair *pair = new Pair(name); VipsImage **array; pair->input = true; g_value_init(&pair->value, VIPS_TYPE_ARRAY_IMAGE); vips_value_set_array_image(&pair->value, static_cast(value.size())); array = vips_value_get_array_image(&pair->value, nullptr); for (std::vector::size_type i = 0; i < value.size(); i++) { VipsImage *vips_image = value[i].get_image(); array[i] = vips_image; g_object_ref(vips_image); } options.push_back(pair); return this; } // input blob VOption * VOption::set(const char *name, VipsBlob *value) { Pair *pair = new Pair(name); pair->input = true; g_value_init(&pair->value, VIPS_TYPE_BLOB); g_value_set_boxed(&pair->value, value); options.push_back(pair); return this; } // output bool VOption * VOption::set(const char *name, bool *value) { Pair *pair = new Pair(name); pair->input = false; pair->vbool = value; g_value_init(&pair->value, G_TYPE_BOOLEAN); options.push_back(pair); return this; } // output int VOption * VOption::set(const char *name, int *value) { Pair *pair = new Pair(name); pair->input = false; pair->vint = value; g_value_init(&pair->value, G_TYPE_INT); options.push_back(pair); return this; } // output double VOption * VOption::set(const char *name, double *value) { Pair *pair = new Pair(name); pair->input = false; pair->vdouble = value; g_value_init(&pair->value, G_TYPE_DOUBLE); options.push_back(pair); return this; } // output image VOption * VOption::set(const char *name, VImage *value) { Pair *pair = new Pair(name); pair->input = false; pair->vimage = value; g_value_init(&pair->value, VIPS_TYPE_IMAGE); options.push_back(pair); return this; } // output doublearray VOption * VOption::set(const char *name, std::vector *value) { Pair *pair = new Pair(name); pair->input = false; pair->vvector = value; g_value_init(&pair->value, VIPS_TYPE_ARRAY_DOUBLE); options.push_back(pair); return this; } // output blob VOption * VOption::set(const char *name, VipsBlob **value) { Pair *pair = new Pair(name); pair->input = false; pair->vblob = value; g_value_init(&pair->value, VIPS_TYPE_BLOB); options.push_back(pair); return this; } // just g_object_set_property(), except we allow set enum from string static void set_property(VipsObject *object, const char *name, const GValue *value) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); GType type = G_VALUE_TYPE(value); GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) { g_warning("%s", vips_error_buffer()); vips_error_clear(); return; } if (G_IS_PARAM_SPEC_ENUM(pspec) && type == G_TYPE_STRING) { GType pspec_type = G_PARAM_SPEC_VALUE_TYPE(pspec); int enum_value; GValue value2 = G_VALUE_INIT; if ((enum_value = vips_enum_from_nick(object_class->nickname, pspec_type, g_value_get_string(value))) < 0) { g_warning("%s", vips_error_buffer()); vips_error_clear(); return; } g_value_init(&value2, pspec_type); g_value_set_enum(&value2, enum_value); g_object_set_property(G_OBJECT(object), name, &value2); g_value_unset(&value2); } else g_object_set_property(G_OBJECT(object), name, value); } // walk the options and set props on the operation void VOption::set_operation(VipsOperation *operation) { std::list::iterator i; for (i = options.begin(); i != options.end(); ++i) if ((*i)->input) { #ifdef VIPS_DEBUG_VERBOSE printf("set_operation: "); vips_object_print_name(VIPS_OBJECT(operation)); char *str_value = g_strdup_value_contents(&(*i)->value); printf(".%s = %s\n", (*i)->name, str_value); g_free(str_value); #endif /*VIPS_DEBUG_VERBOSE*/ set_property(VIPS_OBJECT(operation), (*i)->name, &(*i)->value); } } // walk the options and fetch any requested outputs void VOption::get_operation(VipsOperation *operation) { std::list::iterator i; for (i = options.begin(); i != options.end(); ++i) if (!(*i)->input) { const char *name = (*i)->name; g_object_get_property(G_OBJECT(operation), name, &(*i)->value); #ifdef VIPS_DEBUG_VERBOSE printf("get_operation: "); vips_object_print_name(VIPS_OBJECT(operation)); char *str_value = g_strdup_value_contents(&(*i)->value); printf(".%s = %s\n", name, str_value); g_free(str_value); #endif /*VIPS_DEBUG_VERBOSE*/ GValue *value = &(*i)->value; GType type = G_VALUE_TYPE(value); if (type == VIPS_TYPE_IMAGE) { // rebox object VipsImage *image = VIPS_IMAGE(g_value_get_object(value)); *((*i)->vimage) = VImage(image, NOSTEAL); } else if (type == G_TYPE_INT) *((*i)->vint) = g_value_get_int(value); else if (type == G_TYPE_BOOLEAN) *((*i)->vbool) = g_value_get_boolean(value); else if (type == G_TYPE_DOUBLE) *((*i)->vdouble) = g_value_get_double(value); else if (type == VIPS_TYPE_ARRAY_DOUBLE) { int length; double *array = vips_value_get_array_double(value, &length); ((*i)->vvector)->resize(length); for (int j = 0; j < length; j++) (*((*i)->vvector))[j] = array[j]; } else if (type == VIPS_TYPE_BLOB) // our caller gets a reference *((*i)->vblob) = (VipsBlob *) g_value_dup_boxed(value); } } void VImage::call_option_string(const char *operation_name, const char *option_string, VOption *options) { VipsOperation *operation; VIPS_DEBUG_MSG("call_option_string: starting for %s ...\n", operation_name); if (!(operation = vips_operation_new(operation_name))) { delete options; throw(VError()); } /* Set str options before vargs options, so the user can't * override things we set deliberately. */ if (option_string && vips_object_set_from_string(VIPS_OBJECT(operation), option_string)) { vips_object_unref_outputs(VIPS_OBJECT(operation)); g_object_unref(operation); delete options; throw(VError()); } if (options) options->set_operation(operation); /* Build from cache. */ if (vips_cache_operation_buildp(&operation)) { vips_object_unref_outputs(VIPS_OBJECT(operation)); g_object_unref(operation); delete options; throw(VError()); } /* Walk args again, writing output. */ if (options) options->get_operation(operation); /* Unref all unassigned outputs. */ vips_object_unref_outputs(VIPS_OBJECT(operation)); /* The operation we have built should now have been reffed by * one of its arguments or have finished its work. Either * way, we can unref. */ g_object_unref(operation); /* We're done with options! */ delete options; } void VImage::call(const char *operation_name, VOption *options) { call_option_string(operation_name, nullptr, options); } VImage VImage::new_from_file(const char *name, VOption *options) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; VImage out; vips__filename_split8(name, filename, option_string); if (!(operation_name = vips_foreign_find_load(filename))) { delete options; throw VError(); } call_option_string(operation_name, option_string, (options ? options : VImage::option()) ->set("filename", filename) ->set("out", &out)); return out; } VImage VImage::new_from_buffer(const void *buf, size_t len, const char *option_string, VOption *options) { const char *operation_name; VipsBlob *blob; VImage out; if (!(operation_name = vips_foreign_find_load_buffer(buf, len))) { delete options; throw(VError()); } /* We don't take a copy of the data or free it. */ blob = vips_blob_new(nullptr, buf, len); options = (options ? options : VImage::option()) ->set("buffer", blob) ->set("out", &out); vips_area_unref(VIPS_AREA(blob)); call_option_string(operation_name, option_string, options); return out; } VImage VImage::new_from_buffer(const std::string &buf, const char *option_string, VOption *options) { return new_from_buffer(buf.c_str(), buf.size(), option_string, options); } VImage VImage::new_from_source(VSource source, const char *option_string, VOption *options) { const char *operation_name; VImage out; if (!(operation_name = vips_foreign_find_load_source( source.get_source()))) { delete options; throw(VError()); } options = (options ? options : VImage::option()) ->set("source", source) ->set("out", &out); call_option_string(operation_name, option_string, options); return out; } VImage VImage::new_from_memory_steal(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format) { VipsImage *image; if (!(image = vips_image_new_from_memory(data, size, width, height, bands, format))) throw(VError()); g_signal_connect(image, "postclose", G_CALLBACK(vips_image_free_buffer), const_cast(data)); return VImage(image); } VImage VImage::new_matrix(int width, int height) { return VImage(vips_image_new_matrix(width, height)); } VImage VImage::new_matrixv(int width, int height, ...) { VImage matrix = new_matrix(width, height); VipsImage *vips_matrix = matrix.get_image(); va_list ap; va_start(ap, height); for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) *VIPS_MATRIX(vips_matrix, x, y) = va_arg(ap, double); va_end(ap); return matrix; } VImage VImage::write(VImage out) const { if (vips_image_write(this->get_image(), out.get_image())) throw VError(); return out; } void VImage::write_to_file(const char *name, VOption *options) const { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; vips__filename_split8(name, filename, option_string); if (!(operation_name = vips_foreign_find_save(filename))) { delete options; throw VError(); } call_option_string(operation_name, option_string, (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } void VImage::write_to_buffer(const char *suffix, void **buf, size_t *size, VOption *options) const { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; VipsBlob *blob; /* Save with the new target API if we can. Fall back to the older * mechanism in case the saver we need has not been converted yet. * * We need to hide any errors from this first phase. */ vips__filename_split8(suffix, filename, option_string); vips_error_freeze(); operation_name = vips_foreign_find_save_target(filename); vips_error_thaw(); if (operation_name) { VTarget target = VTarget::new_to_memory(); call_option_string(operation_name, option_string, (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); g_object_get(target.get_target(), "blob", &blob, nullptr); } else if ((operation_name = vips_foreign_find_save_buffer(filename))) { call_option_string(operation_name, option_string, (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &blob)); } else { delete options; throw VError(); } if (blob) { if (buf) { *buf = VIPS_AREA(blob)->data; VIPS_AREA(blob)->free_fn = nullptr; } if (size) *size = VIPS_AREA(blob)->length; vips_area_unref(VIPS_AREA(blob)); } } void VImage::write_to_target(const char *suffix, VTarget target, VOption *options) const { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; vips__filename_split8(suffix, filename, option_string); if (!(operation_name = vips_foreign_find_save_target(filename))) { delete options; throw VError(); } call_option_string(operation_name, option_string, (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::thumbnail_buffer(void *buf, size_t len, int width, VOption *options) { VipsBlob *blob; VImage out; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(nullptr, buf, len); options = (options ? options : VImage::option()) ->set("buffer", blob) ->set("width", width) ->set("out", &out); vips_area_unref(VIPS_AREA(blob)); call("thumbnail_buffer", options); return out; } VRegion VImage::region() const { return VRegion::new_from_image(*this); } VRegion VImage::region(VipsRect *rect) const { VRegion region = VRegion::new_from_image(*this); region.prepare(rect); return region; } VRegion VImage::region(int left, int top, int width, int height) const { VRegion region = VRegion::new_from_image(*this); region.prepare(left, top, width, height); return region; } #include "vips-operators.cpp" std::vector VImage::bandsplit(VOption *options) const { std::vector b; b.reserve(bands()); for (int i = 0; i < bands(); i++) b.push_back(extract_band(i)); return b; } VImage VImage::bandjoin(VImage other, VOption *options) const { VImage v[2] = { *this, other }; std::vector vec(v, v + VIPS_NUMBER(v)); return bandjoin(vec, options); } VImage VImage::composite(VImage other, VipsBlendMode mode, VOption *options) const { VImage v[2] = { *this, other }; std::vector ivec(v, v + VIPS_NUMBER(v)); int m[1] = { static_cast(mode) }; std::vector mvec(m, m + VIPS_NUMBER(m)); return composite(ivec, mvec, options); } std::complex VImage::minpos(VOption *options) const { double x, y; (void) min((options ? options : VImage::option()) ->set("x", &x) ->set("y", &y)); return {x, y}; } std::complex VImage::maxpos(VOption *options) const { double x, y; (void) max((options ? options : VImage::option()) ->set("x", &x) ->set("y", &y)); return {x, y}; } // Operator overloads VImage VImage::operator[](int index) const { return this->extract_band(index); } std::vector VImage::operator()(int x, int y) const { return this->getpoint(x, y); } VImage operator+(const VImage a, const VImage b) { return a.add(b); } VImage operator+(double a, const VImage b) { return b.linear(1.0, a); } VImage operator+(const VImage a, double b) { return a.linear(1.0, b); } VImage operator+(const std::vector a, const VImage b) { return b.linear(1.0, a); } VImage operator+(const VImage a, const std::vector b) { return a.linear(1.0, b); } VImage & operator+=(VImage &a, const VImage b) { a = a + b; return a; } VImage & operator+=(VImage &a, const double b) { a = a + b; return a; } VImage & operator+=(VImage &a, const std::vector b) { a = a + b; return a; } VImage operator-(const VImage a, const VImage b) { return a.subtract(b); } VImage operator-(double a, const VImage b) { return b.linear(-1.0, a); } VImage operator-(const VImage a, double b) { return a.linear(1.0, -b); } VImage operator-(const std::vector a, const VImage b) { return b.linear(-1.0, a); } VImage operator-(const VImage a, const std::vector b) { return a.linear(1.0, vips::negate(b)); } VImage & operator-=(VImage &a, const VImage b) { a = a - b; return a; } VImage & operator-=(VImage &a, const double b) { a = a - b; return a; } VImage & operator-=(VImage &a, const std::vector b) { a = a - b; return a; } VImage operator-(const VImage a) { return a * -1; } VImage operator*(const VImage a, const VImage b) { return a.multiply(b); } VImage operator*(double a, const VImage b) { return b.linear(a, 0.0); } VImage operator*(const VImage a, double b) { return a.linear(b, 0.0); } VImage operator*(const std::vector a, const VImage b) { return b.linear(a, 0.0); } VImage operator*(const VImage a, const std::vector b) { return a.linear(b, 0.0); } VImage & operator*=(VImage &a, const VImage b) { a = a * b; return a; } VImage & operator*=(VImage &a, const double b) { a = a * b; return a; } VImage & operator*=(VImage &a, const std::vector b) { a = a * b; return a; } VImage operator/(const VImage a, const VImage b) { return a.divide(b); } VImage operator/(double a, const VImage b) { return b.pow(-1.0).linear(a, 0.0); } VImage operator/(const VImage a, double b) { return a.linear(1.0 / b, 0.0); } VImage operator/(const std::vector a, const VImage b) { return b.pow(-1.0).linear(a, 0.0); } VImage operator/(const VImage a, const std::vector b) { return a.linear(vips::invert(b), 0.0); } VImage & operator/=(VImage &a, const VImage b) { a = a / b; return a; } VImage & operator/=(VImage &a, const double b) { a = a / b; return a; } VImage & operator/=(VImage &a, const std::vector b) { a = a / b; return a; } VImage operator%(const VImage a, const VImage b) { return a.remainder(b); } VImage operator%(const VImage a, const double b) { return a.remainder_const(to_vector(b)); } VImage operator%(const VImage a, const std::vector b) { return a.remainder_const(b); } VImage & operator%=(VImage &a, const VImage b) { a = a % b; return a; } VImage & operator%=(VImage &a, const double b) { a = a % b; return a; } VImage & operator%=(VImage &a, const std::vector b) { a = a % b; return a; } VImage operator<(const VImage a, const VImage b) { return a.relational(b, VIPS_OPERATION_RELATIONAL_LESS); } VImage operator<(const double a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_MORE, to_vector(a)); } VImage operator<(const VImage a, const double b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_LESS, to_vector(b)); } VImage operator<(const std::vector a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_MORE, a); } VImage operator<(const VImage a, const std::vector b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_LESS, b); } VImage operator<=(const VImage a, const VImage b) { return a.relational(b, VIPS_OPERATION_RELATIONAL_LESSEQ); } VImage operator<=(const double a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_MOREEQ, to_vector(a)); } VImage operator<=(const VImage a, const double b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_LESSEQ, to_vector(b)); } VImage operator<=(const std::vector a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_MOREEQ, a); } VImage operator<=(const VImage a, const std::vector b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_LESSEQ, b); } VImage operator>(const VImage a, const VImage b) { return a.relational(b, VIPS_OPERATION_RELATIONAL_MORE); } VImage operator>(const double a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_LESS, to_vector(a)); } VImage operator>(const VImage a, const double b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_MORE, to_vector(b)); } VImage operator>(const std::vector a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_LESS, a); } VImage operator>(const VImage a, const std::vector b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_MORE, b); } VImage operator>=(const VImage a, const VImage b) { return a.relational(b, VIPS_OPERATION_RELATIONAL_MOREEQ); } VImage operator>=(const double a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_LESSEQ, to_vector(a)); } VImage operator>=(const VImage a, const double b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_MOREEQ, to_vector(b)); } VImage operator>=(const std::vector a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_LESSEQ, a); } VImage operator>=(const VImage a, const std::vector b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_MOREEQ, b); } VImage operator==(const VImage a, const VImage b) { return a.relational(b, VIPS_OPERATION_RELATIONAL_EQUAL); } VImage operator==(const double a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_EQUAL, to_vector(a)); } VImage operator==(const VImage a, const double b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_EQUAL, to_vector(b)); } VImage operator==(const std::vector a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_EQUAL, a); } VImage operator==(const VImage a, const std::vector b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_EQUAL, b); } VImage operator!=(const VImage a, const VImage b) { return a.relational(b, VIPS_OPERATION_RELATIONAL_NOTEQ); } VImage operator!=(const double a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_NOTEQ, to_vector(a)); } VImage operator!=(const VImage a, const double b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_NOTEQ, to_vector(b)); } VImage operator!=(const std::vector a, const VImage b) { return b.relational_const(VIPS_OPERATION_RELATIONAL_NOTEQ, a); } VImage operator!=(const VImage a, const std::vector b) { return a.relational_const(VIPS_OPERATION_RELATIONAL_NOTEQ, b); } VImage operator&(const VImage a, const VImage b) { return a.boolean(b, VIPS_OPERATION_BOOLEAN_AND); } VImage operator&(const double a, const VImage b) { return b.boolean_const(VIPS_OPERATION_BOOLEAN_AND, to_vector(a)); } VImage operator&(const VImage a, const double b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_AND, to_vector(b)); } VImage operator&(const std::vector a, const VImage b) { return b.boolean_const(VIPS_OPERATION_BOOLEAN_AND, a); } VImage operator&(const VImage a, const std::vector b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_AND, b); } VImage & operator&=(VImage &a, const VImage b) { a = a & b; return a; } VImage & operator&=(VImage &a, const double b) { a = a & b; return a; } VImage & operator&=(VImage &a, const std::vector b) { a = a & b; return a; } VImage operator|(const VImage a, const VImage b) { return a.boolean(b, VIPS_OPERATION_BOOLEAN_OR); } VImage operator|(const double a, const VImage b) { return b.boolean_const(VIPS_OPERATION_BOOLEAN_OR, to_vector(a)); } VImage operator|(const VImage a, const double b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_OR, to_vector(b)); } VImage operator|(const std::vector a, const VImage b) { return b.boolean_const(VIPS_OPERATION_BOOLEAN_OR, a); } VImage operator|(const VImage a, const std::vector b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_OR, b); } VImage & operator|=(VImage &a, const VImage b) { a = a | b; return a; } VImage & operator|=(VImage &a, const double b) { a = a | b; return a; } VImage & operator|=(VImage &a, const std::vector b) { a = a | b; return a; } VImage operator^(const VImage a, const VImage b) { return a.boolean(b, VIPS_OPERATION_BOOLEAN_EOR); } VImage operator^(const double a, const VImage b) { return b.boolean_const(VIPS_OPERATION_BOOLEAN_EOR, to_vector(a)); } VImage operator^(const VImage a, const double b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_EOR, to_vector(b)); } VImage operator^(const std::vector a, const VImage b) { return b.boolean_const(VIPS_OPERATION_BOOLEAN_EOR, a); } VImage operator^(const VImage a, const std::vector b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_EOR, b); } VImage & operator^=(VImage &a, const VImage b) { a = a ^ b; return a; } VImage & operator^=(VImage &a, const double b) { a = a ^ b; return a; } VImage & operator^=(VImage &a, const std::vector b) { a = a ^ b; return a; } VImage operator<<(const VImage a, const VImage b) { return a.boolean(b, VIPS_OPERATION_BOOLEAN_LSHIFT); } VImage operator<<(const VImage a, const double b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_LSHIFT, to_vector(b)); } VImage operator<<(const VImage a, const std::vector b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_LSHIFT, b); } VImage & operator<<=(VImage &a, const VImage b) { a = a << b; return a; } VImage & operator<<=(VImage &a, const double b) { a = a << b; return a; } VImage & operator<<=(VImage &a, const std::vector b) { a = a << b; return a; } VImage operator>>(const VImage a, const VImage b) { return a.boolean(b, VIPS_OPERATION_BOOLEAN_RSHIFT); } VImage operator>>(const VImage a, const double b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_RSHIFT, to_vector(b)); } VImage operator>>(const VImage a, const std::vector b) { return a.boolean_const(VIPS_OPERATION_BOOLEAN_RSHIFT, b); } VImage & operator>>=(VImage &a, const VImage b) { a = a << b; return a; } VImage & operator>>=(VImage &a, const double b) { a = a << b; return a; } VImage & operator>>=(VImage &a, const std::vector b) { a = a << b; return a; } // Compat operations VImage VImage::new_from_memory_steal(void *data, size_t size, int width, int height, int bands, VipsBandFormat format) { return new_from_memory_steal(static_cast(data), size, width, height, bands, format); } void VImage::rawsave_fd(int fd, VOption *options) const { rawsave_target(VTarget::new_to_descriptor(fd), options); } VIPS_NAMESPACE_END libvips-8.18.2/cplusplus/VInterpolate.cpp000066400000000000000000000025171516303661500204470ustar00rootroot00000000000000/* Object part of VInterpolate class */ /* Copyright (C) 1991-2001 The National Gallery This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include /* #define VIPS_DEBUG #define VIPS_DEBUG_VERBOSE */ VIPS_NAMESPACE_START VInterpolate VInterpolate::new_from_name(const char *name, VOption *options) { VipsInterpolate *interp; if (!(interp = vips_interpolate_new(name))) { delete options; throw VError(); } delete options; VInterpolate out(interp); return out; } VIPS_NAMESPACE_END libvips-8.18.2/cplusplus/VRegion.cpp000066400000000000000000000005671516303661500174070ustar00rootroot00000000000000// Object part of VRegion class #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include VIPS_NAMESPACE_START VRegion VRegion::new_from_image(VImage image) { VipsRegion *region; if (!(region = vips_region_new(image.get_image()))) { throw VError(); } VRegion out(region); return out; } VIPS_NAMESPACE_END libvips-8.18.2/cplusplus/examples/000077500000000000000000000000001516303661500171405ustar00rootroot00000000000000libvips-8.18.2/cplusplus/examples/avg.cpp000066400000000000000000000006711516303661500204250ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall avg.cpp `pkg-config vips-cpp --cflags --libs` * */ #define DEBUG #include using namespace vips; int main(int argc, char **argv) { if (vips_init(argv[0])) vips_error_exit(NULL); VImage in = VImage::new_from_file(argv[1], VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); double avg; avg = in.avg(); printf("avg = %g\n", avg); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/buffer.cpp000066400000000000000000000016221516303661500211160ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall buffer.cpp `pkg-config vips-cpp --cflags --libs` * */ #define DEBUG #include using namespace vips; int main(int argc, char **argv) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); // load an image from a file VImage im = VImage::new_from_file(argv[1], VImage::option()->set("access", "sequential")); printf("loaded %d x %d pixel image from %s\n", im.width(), im.height(), argv[1]); // write to a formatted memory buffer size_t size; void *buf; im.write_to_buffer(".png", &buf, &size); printf("written to memory %p in png format, %zu bytes\n", buf, size); // load from the formatted memory area im = VImage::new_from_buffer(buf, size, ""); printf("loaded from memory, %d x %d pixel image\n", im.width(), im.height()); // write back to a file im.write_to_file(argv[2]); printf("written back to %s\n", argv[2]); return 0; } libvips-8.18.2/cplusplus/examples/embed.cpp000066400000000000000000000007531516303661500207250ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall embed.cpp `pkg-config vips-cpp --cflags --libs` * */ #define DEBUG #include using namespace vips; int main(int argc, char **argv) { if (vips_init(argv[0])) vips_error_exit(NULL); VImage in = VImage::new_from_file(argv[1], VImage::option()->set("access", "sequential")); VImage out = in.embed(10, 10, 1000, 1000, VImage::option()->set("extend", "copy")); out.write_to_file(argv[2]); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/invert.cpp000066400000000000000000000011621516303661500211530ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall invert.cpp `pkg-config vips-cpp --cflags --libs` * */ #define DEBUG #include using namespace vips; int main(int argc, char **argv) { if (vips_init(argv[0])) vips_error_exit(NULL); printf("these should match if VImage is compile-time-only\n"); printf("sizeof(VipsImage *) = %zd\n", sizeof(VipsImage *)); printf("sizeof(VImage) = %zd\n", sizeof(VImage)); VImage in = VImage::new_from_file(argv[1], VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); VImage out; out = in.invert(); out.write_to_file(argv[2]); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/keep.cpp000066400000000000000000000011651516303661500205730ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall keep.cpp `pkg-config vips-cpp --cflags --libs` * * run with: * * ./a.out test/test-suite/images/ultra-hdr.jpg x.jpg * */ #include using namespace vips; int main(int argc, char **argv) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s infile outfile", argv[0]); { VImage img = VImage::new_from_file(argv[1], VImage::option()->set("access", "sequential")); img.write_to_file(argv[2], VImage::option()->set("keep", VIPS_FOREIGN_KEEP_ALL ^ VIPS_FOREIGN_KEEP_EXIF)); } vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/profile.cpp000066400000000000000000000006641516303661500213120ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall profile.cpp `pkg-config vips-cpp --cflags --libs` * */ #define DEBUG #include using namespace vips; int main(int argc, char **argv) { if (vips_init(argv[0])) vips_error_exit(NULL); VImage in = VImage::new_from_file(argv[1]); VImage rows; VImage cols = in.profile(&rows); rows.write_to_file(argv[2]); cols.write_to_file(argv[3]); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/resize.cpp000066400000000000000000000010631516303661500211450ustar00rootroot00000000000000/* compile with: * * g++ -g -Wall resize.cpp `pkg-config vips-cpp --cflags --libs` */ #include using namespace vips; int main(int argc, char **argv) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s infile outfile", argv[0]); VImage in = VImage::new_from_file(argv[1], VImage::option() ->set("access", "sequential")); VImage out = in.resize(0.2, VImage::option() ->set("kernel", "cubic") ->set("vscale", 0.2)); out.write_to_file(argv[2]); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/test.cpp000066400000000000000000000210571516303661500206300ustar00rootroot00000000000000/* Test the C++ API. * * This isn't a full test suite, look in the Python area for that. This is * just supposed to check that the C++ binding is working. * * compile with: * * g++ -g -Wall test.cpp `pkg-config vips-cpp --cflags --libs` * * run with: * * VIPS_LEAK=1 ./a.out ~/pics/k2.jpg ~/pics/shark.jpg * valgrind --leak-check=yes ./a.out ~/pics/k2.jpg ~/pics/shark.jpg * rm x.tif * */ /* #define VIPS_DEBUG #define VIPS_DEBUG_VERBOSE */ #include #include using namespace vips; bool equal_vector(std::vector a, std::vector b) { for (unsigned int i = 0; i < a.size(); i++) if (fabs(a[i] - b[i]) > 0.001) { printf("vectors differ at %u: should be [", i); for (unsigned int i = 0; i < a.size(); i++) { if (i > 0) printf(", "); printf("%g", a[i]); } printf("], is ["); for (unsigned int i = 0; i < a.size(); i++) { if (i > 0) printf(", "); printf("%g", a[i]); } printf("]\n"); return false; } return true; } bool equal_double(double a, double b) { if (fabs(a - b) > 0.001) { printf("doubles differ: should be %g, is %g\n", a, b); return false; } return true; } /* We can't do this with a template, I think we'd need partially-parameterised * template, which is C++11 only. */ /* Only test a few points and only test uchar: we are just testing the C++ * overloads, we rely on the python test suite for testing the underlying * vips operators. */ #define TEST_BINARY(OPERATOR) \ void \ test_binary_##OPERATOR(VImage left, VImage right) \ { \ for (int x = 10; x < 30; x += 10) { \ std::vector p_left = left.getpoint(x, x); \ std::vector p_right = right.getpoint(x, x); \ std::vector p_result = \ OPERATOR, \ std::vector, \ std::vector >(p_left, p_right); \ \ VImage im_result; \ std::vector p_im_result; \ \ /* test: image = image OP image \ */ \ im_result = OPERATOR(left, right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(VImage, VImage) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image = image OP vec \ */ \ im_result = \ OPERATOR >(left, p_right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(VImage, vector) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image = vec OP image \ */ \ im_result = \ OPERATOR, \ VImage>(p_left, right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(vector, VImage) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image = image OP double \ */ \ for (unsigned int i = 0; i < p_right.size(); i++) { \ im_result = \ OPERATOR(left, p_right[i]); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_double(p_result[i], p_im_result[i])) { \ printf(#OPERATOR \ "(VImage, double) failed at " \ "(%d, %d)\n", \ x, x); \ abort(); \ } \ } \ \ /* test: image = double OP image \ */ \ for (unsigned int i = 0; i < p_left.size(); i++) { \ im_result = \ OPERATOR(p_left[i], right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_double(p_result[i], p_im_result[i])) { \ printf(#OPERATOR \ "(double, VImage) failed at " \ "(%d, %d)\n", \ x, x); \ abort(); \ } \ } \ } \ } // eg. double = double + double // or image = double + image template A test_add(B left, C right) { return left + right; } template std::vector operator+(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] + v2[i]; return result; } TEST_BINARY(test_add); template A test_subtract(B left, C right) { return left - right; } template std::vector operator-(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] - v2[i]; return result; } TEST_BINARY(test_subtract); template A test_multiply(B left, C right) { return left * right; } template std::vector operator*(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] * v2[i]; return result; } TEST_BINARY(test_multiply); template A test_divide(B left, C right) { return left / right; } template std::vector operator/(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] / v2[i]; return result; } TEST_BINARY(test_divide); int main(int argc, char **argv) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); VImage left = VImage::new_from_file(argv[1]); VImage right = VImage::new_from_file(argv[2]); { printf("testing constant args ...\n"); double a[] = { 1.0, 2.0, 3.0 }; double b[] = { 4.0, 5.0, 6.0 }; std::vector avec(a, a + VIPS_NUMBER(a)); std::vector bvec(b, b + VIPS_NUMBER(b)); VImage out = left.linear(avec, bvec); out.write_to_file("x.tif"); } { printf("testing operator overloads ...\n"); test_binary_test_add(left, right); test_binary_test_subtract(left, right); test_binary_test_multiply(left, right); test_binary_test_divide(left, right); VImage band_one = left[1]; std::vector point = left(0, 0); } { // write to a formatted memory buffer printf("testing formatted memory write ...\n"); size_t size; void *buf; left.write_to_buffer(".png", &buf, &size); printf("written to memory %p in png format, %zu bytes\n", buf, size); // load from the formatted memory area VImage im = VImage::new_from_buffer(buf, size, ""); printf("loaded from memory, %d x %d pixel image\n", im.width(), im.height()); // write back to a file im.write_to_file("x.tif"); printf("written back to x.tif\n"); g_free(buf); } { // write to a formatted AVIF memory buffer printf("testing formatted AVIF memory write ...\n"); if (vips_type_find("VipsOperation", "avifsave_target") != 0) { size_t size; void *buf; // speed-up test by setting @effort to 0 left.write_to_buffer(".avif", &buf, &size, VImage::option()->set("effort", 0)); printf("written to memory %p in AVIF format, %zu bytes\n", buf, size); // load from the formatted memory area VImage im = VImage::new_from_buffer(buf, size, ""); printf("loaded from memory, %d x %d pixel %s image\n", im.width(), im.height(), im.get_string("heif-compression")); g_free(buf); } else { printf("skipped, not compiled against libheif\n"); } } { // write to a vanilla memory buffer printf("testing memory array write ...\n"); size_t size; void *buf; buf = left.write_to_memory(&size); printf("written to memory %p as an array, %zu bytes\n", buf, size); // load from the memory array VImage im = VImage::new_from_memory(buf, size, left.width(), left.height(), left.bands(), left.format()); printf("loaded from memory array, %d x %d pixel image\n", im.width(), im.height()); // write back to a file im.write_to_file("x.tif"); printf("written back to x.tif\n"); g_free(buf); } { printf("testing double return from operation ...\n"); double avg = left.avg(); printf("left.avg() = %g\n", avg); } { printf("testing optional enum args ...\n"); VImage out = left.embed(10, 10, 1000, 1000, VImage::option()->set("extend", "copy")); out.write_to_file("x.tif"); } { printf("testing multiple image return ...\n"); VImage rows; VImage cols = left.profile(&rows); rows.write_to_file("x.tif"); cols.write_to_file("x.tif"); } { printf("testing interpolators ...\n"); VInterpolate interp = VInterpolate::new_from_name("nohalo"); VImage out; out = left.resize(0.2, VImage::option()->set("interpolate", interp)); out.write_to_file("x.tif"); } { printf("testing new_from_image() ...\n"); VImage out = left.new_from_image(128); out.write_to_file("x.tif"); } printf("all tests passed\n"); return 0; } libvips-8.18.2/cplusplus/examples/test_overloads.cpp000066400000000000000000000211541516303661500227040ustar00rootroot00000000000000/* Test +/-* overloads with every combination of vector, image and double. * This isn't a full test suite, look in the Python area for that. * * compile with: * * g++ -g -Wall test_overloads.cpp `pkg-config vips-cpp --cflags --libs` * * run with: * * valgrind --leak-check=yes ./a.out ~/pics/k2.jpg ~/pics/shark.jpg * */ /* #define VIPS_DEBUG #define VIPS_DEBUG_VERBOSE */ #include #include using namespace vips; bool equal_vector(std::vector a, std::vector b) { for (unsigned int i = 0; i < a.size(); i++) if (fabs(a[i] - b[i]) > 0.001) { printf("vectors differ at %u: should be [", i); for (unsigned int i = 0; i < a.size(); i++) { if (i > 0) printf(", "); printf("%g", a[i]); } printf("], is ["); for (unsigned int i = 0; i < a.size(); i++) { if (i > 0) printf(", "); printf("%g", a[i]); } printf("]\n"); return false; } return true; } bool equal_double(double a, double b) { if (fabs(a - b) > 0.001) { printf("doubles differ: should be %g, is %g\n", a, b); return false; } return true; } /* We can't do this with a template, I think we'd need partially-parameterised * template, which is C++11 only. */ /* Only test a few points and only test uchar: we are just testing the C++ * overloads, we rely on the python test suite for testing the underlying * vips operators. */ #define TEST_BINARY(OPERATOR) \ void \ test_binary_##OPERATOR(VImage left, VImage right) \ { \ for (int x = 10; x < 30; x += 10) { \ std::vector p_left = left.getpoint(x, x); \ std::vector p_right = right.getpoint(x, x); \ std::vector p_result = \ OPERATOR, \ std::vector, \ std::vector >(p_left, p_right); \ \ VImage im_result; \ std::vector p_im_result; \ \ /* test: image = image OP image \ */ \ im_result = OPERATOR(left, right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(VImage, VImage) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image = image OP vec \ */ \ im_result = \ OPERATOR >(left, p_right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(VImage, vector) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image = vec OP image \ */ \ im_result = \ OPERATOR, \ VImage>(p_left, right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(vector, VImage) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image = image OP double \ */ \ for (unsigned int i = 0; i < p_right.size(); i++) { \ im_result = \ OPERATOR(left, p_right[i]); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_double(p_result[i], p_im_result[i])) { \ printf(#OPERATOR \ "(VImage, double) failed at " \ "(%d, %d)\n", \ x, x); \ abort(); \ } \ } \ \ /* test: image = double OP image \ */ \ for (unsigned int i = 0; i < p_left.size(); i++) { \ im_result = \ OPERATOR(p_left[i], right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_double(p_result[i], p_im_result[i])) { \ printf(#OPERATOR \ "(double, VImage) failed at " \ "(%d, %d)\n", \ x, x); \ abort(); \ } \ } \ } \ } // eg. double = double + double // or image = double + image template A test_add(B left, C right) { return left + right; } template std::vector operator+(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] + v2[i]; return result; } TEST_BINARY(test_add); template A test_subtract(B left, C right) { return left - right; } template std::vector operator-(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] - v2[i]; return result; } TEST_BINARY(test_subtract); template A test_multiply(B left, C right) { return left * right; } template std::vector operator*(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] * v2[i]; return result; } TEST_BINARY(test_multiply); template A test_divide(B left, C right) { return left / right; } template std::vector operator/(std::vector &v1, const std::vector &v2) { std::vector result(v1.size()); for (unsigned int i = 0; i < v1.size(); i++) result[i] = v1[i] / v2[i]; return result; } TEST_BINARY(test_divide); /* We can't test remainder easily, vips does not support constant % image. */ /* We'd need an int version to test the bool operators, C++ does not like * double & double. */ /* Only test a few points and only test uchar: we are just testing the C++ * overloads, we rely on the python test suite for testing the underlying * vips operators. */ #define TEST_ASSIGNMENT(OPERATOR) \ void \ test_assignment_##OPERATOR(VImage left, VImage right) \ { \ for (int x = 10; x < 30; x += 10) { \ std::vector p_left = left.getpoint(x, x); \ std::vector p_right = right.getpoint(x, x); \ std::vector p_result = p_left; \ OPERATOR, \ std::vector >(p_result, p_right); \ \ /* test: image OP= image \ */ \ VImage im_result = left; \ OPERATOR(im_result, right); \ std::vector p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(VImage, VImage) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image OP= vec \ */ \ im_result = left; \ OPERATOR >(im_result, p_right); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_vector(p_result, p_im_result)) { \ printf(#OPERATOR \ "(VImage, vector) failed at (%d, %d)\n", \ x, x); \ abort(); \ } \ \ /* test: image OP= double \ */ \ for (unsigned int i = 0; i < p_left.size(); i++) { \ im_result = left; \ OPERATOR(im_result, p_right[i]); \ p_im_result = im_result.getpoint(x, x); \ \ if (!equal_double(p_result[i], p_im_result[i])) { \ printf(#OPERATOR \ "(VImage, double) failed at " \ "(%d, %d)\n", \ x, x); \ abort(); \ } \ } \ } \ } template std::vector & operator+=(std::vector &a, std::vector b) { a = a + b; return a; } template void test_plusequals(A &left, B right) { left += right; } TEST_ASSIGNMENT(test_plusequals); template std::vector & operator-=(std::vector &a, std::vector b) { a = a - b; return a; } template void test_minusequals(A &left, B right) { left -= right; } TEST_ASSIGNMENT(test_minusequals); template std::vector & operator*=(std::vector &a, std::vector b) { a = a * b; return a; } template void test_timesequals(A &left, B right) { left *= right; } TEST_ASSIGNMENT(test_timesequals); template std::vector & operator/=(std::vector &a, std::vector b) { a = a / b; return a; } template void test_divideequals(A &left, B right) { left /= right; } TEST_ASSIGNMENT(test_divideequals); /* We can't test remainder easily, vips does not support constant % image. */ /* We'd need an int version to test the bool operators. */ int main(int argc, char **argv) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); VImage left = VImage::new_from_file(argv[1]); VImage right = VImage::new_from_file(argv[2]); VImage band_one = left[1]; std::vector point = left(0, 0); test_binary_test_add(left, right); test_binary_test_subtract(left, right); test_binary_test_multiply(left, right); test_binary_test_divide(left, right); test_assignment_test_plusequals(left, right); test_assignment_test_minusequals(left, right); test_assignment_test_timesequals(left, right); test_assignment_test_divideequals(left, right); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/examples/tomemory.cpp000066400000000000000000000024701516303661500215220ustar00rootroot00000000000000/* compile with: * * g++ -g -Wall tomemory.cpp `pkg-config vips-cpp --cflags --libs` */ #include #include int main(int argc, char* argv[]) { if (VIPS_INIT(argv[0])) vips_error_exit(nullptr); for (int i = 0; i < 1000; i++) { std::cout << "loop " << i << " ..." << std::endl; // create a uint8 RGBA VImage // `black` makes a mono image, so you need to explicitly tag it as srgb const int width = 50; const int height = 50; const int channels = 3; vips::VImage image = vips::VImage::black(width, height, vips::VImage::option() ->set("bands", channels)) .copy(vips::VImage::option() ->set("interpretation", "srgb")) .bandjoin(255); // C libvips API to print a vips subclass ... handy for debugging std::cout << "built: "; vips_object_print_summary(VIPS_OBJECT(image.get_image())); // render to an area of memory ... you can use `.data()`, but this is // just as quick, and is threadsafe size_t len; void *data = image.write_to_memory(&len); std::cout << len << " bytes of data at address " << data << std::endl; // you own this pointer and must free it g_free(data); } return 0; } libvips-8.18.2/cplusplus/examples/uhdr.cpp000066400000000000000000000024001516303661500206020ustar00rootroot00000000000000/* * compile with: * * g++ -g -Wall uhdr.cpp `pkg-config vips-cpp --cflags --libs` * * run with: * * ./a.out test/test-suite/images/ultra-hdr.jpg x.jpg * */ #include using namespace vips; int main(int argc, char **argv) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s infile outfile", argv[0]); int left = 60; int top = 1560; int width = 128; int height = 128; VImage in = VImage::new_from_file(argv[1], VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); VImage out = in.crop(left, top, width, height); // also crop the gainmap, if there is one VImage gainmap = out.gainmap(); if (!gainmap.is_null()) { // the gainmap can be smaller than the image, we must scale the // crop area double hscale = (double) gainmap.width() / in.width(); double vscale = (double) gainmap.height() / in.height(); VImage x = gainmap.crop(left * hscale, top * vscale, width * hscale, height * vscale); // .set() modifies the image, so we need to make a unique // copy ... you can skip this step if you know your image is // already unique out = out.copy(); // update the gainmap out.set("gainmap", x); } out.write_to_file(argv[2]); vips_shutdown(); return 0; } libvips-8.18.2/cplusplus/gen-operators.py000077500000000000000000000213741516303661500204730ustar00rootroot00000000000000#!/usr/bin/env python3 # This file generates the member definitions and declarations for all vips # operators. # this needs pyvips # pip install --user pyvips # rebuild with: # meson compile -Cbuild vips-operators-header # meson compile -Cbuild vips-operators-source # Sample member declaration: # VImage invert(VOption *options = nullptr) const; # Sample member definition: # VImage # VImage::invert(VOption *options) const # { # VImage out; # # call("invert", (options ? options : VImage::option()) # ->set("in", *this) # ->set("out", &out)); # # return out; # } import argparse from pyvips import Introspect, Operation, GValue, Error, \ ffi, gobject_lib, type_map, type_from_name, nickname_find, type_name # turn a GType into a C++ type gtype_to_cpp = { GValue.gbool_type: 'bool', GValue.gint_type: 'int', GValue.gdouble_type: 'double', GValue.gstr_type: 'const char *', GValue.refstr_type: 'char *', GValue.image_type: 'VImage', GValue.source_type: 'VSource', GValue.target_type: 'VTarget', GValue.guint64_type: 'guint64', type_from_name('VipsInterpolate'): 'VInterpolate', GValue.array_int_type: 'std::vector', GValue.array_double_type: 'std::vector', GValue.array_image_type: 'std::vector', GValue.blob_type: 'VipsBlob *' } cplusplus_suffixes = ('*', '&') cplusplus_keywords = ('case', 'switch') # values for VipsArgumentFlags _REQUIRED = 1 _INPUT = 16 _OUTPUT = 32 _DEPRECATED = 64 _MODIFY = 128 # for VipsOperationFlags _OPERATION_NOCACHE = 4 _OPERATION_DEPRECATED = 8 def get_cpp_type(gtype): """Map a gtype to the C++ type name we use to represent it. """ if gtype in gtype_to_cpp: return gtype_to_cpp[gtype] fundamental = gobject_lib.g_type_fundamental(gtype) # enum/flag params use the C name as their name if fundamental == GValue.genum_type or fundamental == GValue.gflags_type: return type_name(gtype) if fundamental in gtype_to_cpp: return gtype_to_cpp[fundamental] return '' # swap any '-' for '_' def cppize(name): return name.replace('-', '_') def generate_operation(operation_name, declaration_only=False, indent=''): intro = Introspect.get(operation_name) required_output = [name for name in intro.required_output if name != intro.member_x] # We are only interested in non-deprecated arguments optional_input = [name for name in intro.optional_input if intro.details[name]['flags'] & _DEPRECATED == 0] # Drop "revalidate" flag from operations marked "nocache" optional_input = [name for name in optional_input if name != 'revalidate' or (intro.flags & _OPERATION_NOCACHE) == 0] has_output = len(required_output) >= 1 # Add a C++ style comment block with some additional markings (@param, # @return) if declaration_only: description = intro.description.capitalize() # hide library-specific implementation details description = (description .replace('imagemagick7', 'imagemagick') .replace(' (pdfium)', '') .replace(' (poppler)', '')) result = f'\n{indent}/**' result += f'\n{indent} * {description}.' if len(optional_input) > 0: result += f'\n{indent} *' result += f'\n{indent} * **Optional parameters**' for name in optional_input: details = intro.details[name] result += f'\n{indent} * - **{cppize(name)}** -- ' result += f'{details["blurb"]}, ' result += f'{get_cpp_type(details["type"])}.' result += f'\n{indent} *' for name in intro.method_args: details = intro.details[name] result += f'\n{indent} * @param {cppize(name)} {details["blurb"]}.' if has_output: # skip the first element for name in required_output[1:]: details = intro.details[name] result += f'\n{indent} * @param {cppize(name)} {details["blurb"]}.' result += f'\n{indent} * @param options Set of options.' if has_output: details = intro.details[required_output[0]] result += f'\n{indent} * @return {details["blurb"]}.' result += f'\n{indent} */\n' if intro.flags & _OPERATION_DEPRECATED: result += f'{indent}G_DEPRECATED\n' else: result = '\n' if intro.member_x is None and declaration_only: result += f'{indent}static ' else: result += indent if has_output: # the first output arg will be used as the result cpp_type = get_cpp_type(intro.details[required_output[0]]['type']) result += f'{cpp_type}' else: cpp_type = 'void' result += cpp_type if declaration_only: result += '' if cpp_type.endswith(cplusplus_suffixes) else ' ' else: result += '\nVImage::' cplusplus_operation = operation_name if operation_name in cplusplus_keywords: cplusplus_operation += '_image' result += f'{cplusplus_operation}(' for name in intro.method_args: details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}{cppize(name)}, ' # output params are passed by reference if has_output: # skip the first element for name in required_output[1:]: details = intro.details[name] gtype = details['type'] cpp_type = get_cpp_type(gtype) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'{cpp_type}{spacing}*{cppize(name)}, ' result += f'VOption *options{" = nullptr" if declaration_only else ""})' # if no 'this' available, it's a class method and they are all const if intro.member_x is not None: result += ' const' if declaration_only: result += ';' return result result += '\n{\n' if has_output: # the first output arg will be used as the result name = required_output[0] cpp_type = get_cpp_type(intro.details[name]['type']) spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' ' result += f'\t{cpp_type}{spacing}{cppize(name)};\n\n' result += f'\tcall("{operation_name}", (options ? options : VImage::option())' if intro.member_x is not None: result += f'\n\t\t\t->set("{intro.member_x}", *this)' all_required = intro.method_args if has_output: # first element needs to be passed by reference arg = cppize(required_output[0]) result += f'\n\t\t\t->set("{required_output[0]}", &{arg})' # append the remaining list all_required += required_output[1:] for name in all_required: arg = cppize(name) result += f'\n\t\t\t->set("{name}", {arg})' result += ');\n' if has_output: result += f'\n' result += f'\treturn {required_output[0]};\n' result += '}' return result def generate_operators(declarations_only=False): all_nicknames = [] # hidden CLI savers needs to be excluded from the API hidden_savers = [ 'avifsave_target', 'magicksave_bmp', 'magicksave_bmp_buffer', 'pbmsave_target', 'pfmsave_target', 'pgmsave_target', 'pnmsave_target', ] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types _ = Introspect.get(nickname) all_nicknames.append(nickname) except Error: pass type_map(gtype, add_nickname) return ffi.NULL type_map(type_from_name('VipsOperation'), add_nickname) # add 'missing' synonyms by hand all_nicknames.append('crop') # make list unique and sort all_nicknames = list(set(all_nicknames) - set(hidden_savers)) all_nicknames.sort() indent = '\t' if declarations_only else '' print(f'''{indent}// {'headers' if declarations_only else 'bodies'} for vips operations {indent}// this file is generated automatically, do not edit! {indent}// clang-format off''') for nickname in all_nicknames: print(generate_operation(nickname, declarations_only, indent)) parser = argparse.ArgumentParser(description='C++ binding generator') parser.add_argument('--gen', '-g', default='cpp', choices=['h', 'cpp'], help='File to generate: h (headers) or cpp ' + \ '(implementations) (default: %(default)s)') if __name__ == '__main__': args = parser.parse_args() generate_operators(args.gen == 'h') libvips-8.18.2/cplusplus/include/000077500000000000000000000000001516303661500167455ustar00rootroot00000000000000libvips-8.18.2/cplusplus/include/vips/000077500000000000000000000000001516303661500177265ustar00rootroot00000000000000libvips-8.18.2/cplusplus/include/vips/VConnection8.h000066400000000000000000000064561516303661500224270ustar00rootroot00000000000000// VIPS connection wrapper /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VCONNECTION_H #define VIPS_VCONNECTION_H #include VIPS_NAMESPACE_START /** * A generic source object. These supply a stream of bytes that loaders can * use to fetch image files, see VImage::new_from_source(). * * Methods let you can connect a source up to memory, a file or * a file descriptor. Use vips::VSourceCustom to implement custom sources * using GObject signals. */ class VSource : public VObject { public: /** * Wrap a VSource around an underlying VipsSource object. */ explicit VSource(VipsSource *input, VSteal steal = STEAL) : VObject((VipsObject *) input, steal) { } /** * Make a new VSource from a file descriptor. */ static VSource new_from_descriptor(int descriptor); /** * Make a new VSource from a file on disc. */ static VSource new_from_file(const char *filename); /** * Make a new VSource from a binary object. */ static VSource new_from_blob(VipsBlob *blob); /** * Make a new VSource from an area of memory. */ static VSource new_from_memory(const void *data, size_t size); /** * Make a new VSource from a set of options encoded as a string. See * vips_source_new(). */ static VSource new_from_options(const char *options); /** * Get a pointer to the underlying VipsSoure object. */ VipsSource * get_source() const { return (VipsSource *) VObject::get_object(); } }; /** * A generic target object. Savers can use these to write a stream of bytes * somewhere, see VImage::write_to_target(). * * Methods let you can connect a target up to memory, a file or * a file descriptor. Use vips::VTargetCustom to implement custom targets * using GObject signals. */ class VTarget : public VObject { public: /** * Wrap a VTarget around an underlying VipsTarget object. */ explicit VTarget(VipsTarget *output, VSteal steal = STEAL) : VObject((VipsObject *) output, steal) { } /** * Make a new VTarget which, when written to, will write to a file * descriptor. */ static VTarget new_to_descriptor(int descriptor); /** * Make a new VTarget which, when written to, will write to a file. */ static VTarget new_to_file(const char *filename); /** * Make a new VTarget which, when written to, will write to a file * descriptor. */ static VTarget new_to_memory(); /** * Get a pointer to the underlying VipsTarget object. */ VipsTarget * get_target() const { return (VipsTarget *) VObject::get_object(); } }; VIPS_NAMESPACE_END #endif /*VIPS_VCONNECTION_H*/ libvips-8.18.2/cplusplus/include/vips/VError8.h000066400000000000000000000040161516303661500214070ustar00rootroot00000000000000// Header for error type /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VERROR_H #define VIPS_VERROR_H #include #include #include #include VIPS_NAMESPACE_START /** * The libvips error class. It holds a single string containing an * internationalized error message in utf-8 encoding. */ class VIPS_CPLUSPLUS_API VError : public std::runtime_error { public: using std::runtime_error::runtime_error; /** * Construct a VError, fetching the error message from the libvips * error buffer. */ VError() : std::runtime_error(vips_error_buffer()) {} /** * Get a reference to the underlying C string. * Note: this override must be preserved for ABI, removing it * would also eliminate the `_ZNK4vips6VError4whatEv` symbol. */ const char * what() const noexcept override { return std::runtime_error::what(); } /** * Print the error message to a stream. */ void ostream_print(std::ostream &) const; private: /** * ABI padding to preserve original VError size. */ // TODO: Migrate to [[maybe_unused]] once we require C++17. char _abi_padding[sizeof(std::exception) + sizeof(std::string) - sizeof(std::runtime_error)] G_GNUC_UNUSED = {}; }; VIPS_NAMESPACE_END #endif /*VIPS_VERROR_H*/ libvips-8.18.2/cplusplus/include/vips/VImage8.h000066400000000000000000006253361516303661500213560ustar00rootroot00000000000000// VIPS image wrapper /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VIMAGE_H #define VIPS_VIMAGE_H #include #include #include #include #include VIPS_NAMESPACE_START /* Small utility things. */ VIPS_CPLUSPLUS_API std::vector to_vectorv(int n, ...); VIPS_CPLUSPLUS_API std::vector to_vector(double value); VIPS_CPLUSPLUS_API std::vector to_vector(int n, double array[]); VIPS_CPLUSPLUS_API std::vector negate(std::vector value); VIPS_CPLUSPLUS_API std::vector invert(std::vector value); /** * Whether or not VObject should take over the reference that you pass in. See * VObject(). */ enum VSteal { NOSTEAL = 0, STEAL = 1 }; /** * A smart VipsObject pointer. It calls g_object_ref()/_unref() for you * automatically. * * VObjects can be null (have no value set). See is_null(). */ class VObject { private: // can be NULL, see eg. VObject() VipsObject *vobject; public: /** * Wrap a VObject around the underlying VipsObject pointer. * * If steal is STEAL, then the new VObject takes over the reference * that you pass in. */ explicit VObject(VipsObject *new_vobject, VSteal steal = STEAL) : vobject(new_vobject) { // we allow NULL init, eg. "VImage a;" g_assert(!new_vobject || VIPS_IS_OBJECT(new_vobject)); #ifdef VIPS_DEBUG_VERBOSE printf("VObject constructor, obj = %p, steal = %d\n", new_vobject, steal); if (new_vobject) { printf(" obj "); vips_object_print_name(VIPS_OBJECT(new_vobject)); printf("\n"); } #endif /*VIPS_DEBUG_VERBOSE*/ if (!steal && vobject) { #ifdef VIPS_DEBUG_VERBOSE printf(" reffing object\n"); #endif /*VIPS_DEBUG_VERBOSE*/ g_object_ref(vobject); } } VObject() : vobject(nullptr) { } VObject(const VObject &a) : vobject(a.vobject) { g_assert(!vobject || VIPS_IS_OBJECT(vobject)); #ifdef VIPS_DEBUG_VERBOSE printf("VObject copy constructor, obj = %p\n", vobject); printf(" reffing object\n"); #endif /*VIPS_DEBUG_VERBOSE*/ if (vobject) g_object_ref(vobject); } // assignment ... we must delete the old ref VObject & operator=(const VObject &a) { #ifdef VIPS_DEBUG_VERBOSE printf("VObject assignment\n"); printf(" reffing %p\n", a.vobject); printf(" unreffing %p\n", vobject); #endif /*VIPS_DEBUG_VERBOSE*/ g_assert(!vobject || VIPS_IS_OBJECT(vobject)); g_assert(!a.vobject || VIPS_IS_OBJECT(a.vobject)); // delete the old ref at the end ... otherwise "a = a;" could // unref before reffing again if (a.vobject) g_object_ref(a.vobject); if (vobject) g_object_unref(vobject); vobject = a.vobject; return *this; } // this mustn't be virtual: we want this class to only be a pointer, // no vtable allowed ~VObject() { #ifdef VIPS_DEBUG_VERBOSE printf("VObject destructor\n"); printf(" unreffing %p\n", vobject); #endif /*VIPS_DEBUG_VERBOSE*/ g_assert(!vobject || VIPS_IS_OBJECT(vobject)); if (vobject) g_object_unref(vobject); } /** * Return the underlying VipsObject pointer. This does not make a new * reference -- you'll need to g_object_ref() the result if you want * to keep it. */ VipsObject * get_object() const { g_assert(!vobject || VIPS_IS_OBJECT(vobject)); return vobject; } /** * TRUE if this is a null VObject. */ bool is_null() const { return vobject == nullptr; } }; class VIPS_CPLUSPLUS_API VImage; class VIPS_CPLUSPLUS_API VInterpolate; class VIPS_CPLUSPLUS_API VRegion; class VIPS_CPLUSPLUS_API VSource; class VIPS_CPLUSPLUS_API VTarget; class VIPS_CPLUSPLUS_API VOption; /** * A list of name-value pairs. Pass these to libvips operations to set * options. For example: * * VImage out = in.embed(10, 10, 1000, 1000, VImage::option() * ->set("extend", "background") * ->set("background", 128)); * * The `set` member functions will take copies (or hold references to) * compound objects, so you can free them immediately afterwards if necessary. * * You can get values back from operations by using the * form of the set * member functions. For example: * * VImage in = VImage::new_from_file(argv[1]); * int x, y; * double value = in.max(VImage::option() * ->set("x", &x) * ->set("y", &y)); * */ class VOption { private: struct Pair { const char *name; // the thing we pass to and from our caller GValue value; // an input or output parameter ... we guess the direction // from the arg to set() bool input; // the pointer we write output values to union { bool *vbool; int *vint; double *vdouble; VImage *vimage; std::vector *vvector; VipsBlob **vblob; }; explicit Pair(const char *name) : name(name), value(G_VALUE_INIT), input(false), vimage(nullptr) { } ~Pair() { g_value_unset(&value); } }; std::list options; public: VOption() = default; virtual ~VOption(); /** * Set an input boolean option. */ VOption * set(const char *name, bool value); /** * Set an input int option. This is used for enums as well, or you can * use the string version. */ VOption * set(const char *name, int value); /** * Set an input unsigned 64-bit integer option. */ VOption * set(const char *name, guint64 value); /** * Set an input double option. */ VOption * set(const char *name, double value); /** * Set an input string option. * * A copy is taken of the object. */ VOption * set(const char *name, const char *value); /** * Set a libvips object as an option. These can be images, sources, * targets, etc. * * A copy is taken of the object. */ VOption * set(const char *name, const VObject value); /** * Set an array of integers as an input option. * * A copy is taken of the object. */ VOption * set(const char *name, std::vector value); /** * Set an array of doubles as an input option. * * A copy is taken of the object. */ VOption * set(const char *name, std::vector value); /** * Set an array of images as an input option. * * A copy is taken of the object. */ VOption * set(const char *name, std::vector value); /** * Set a binary object an input option. Use vips_blob_new() to make * blobs. * * A copy is taken of the object. */ VOption * set(const char *name, VipsBlob *value); /** * Set an option which will return a bool value. */ VOption * set(const char *name, bool *value); /** * Set an option which will return an integer value. */ VOption * set(const char *name, int *value); /** * Set an option which will return a double value. */ VOption * set(const char *name, double *value); /** * Set an option which will return a reference to an image. */ VOption * set(const char *name, VImage *value); /** * Set an option which will return an array of doubles. */ VOption * set(const char *name, std::vector *value); /** * Set an option which will return a binary object, such as an ICC * profile. */ VOption * set(const char *name, VipsBlob **blob); /** * Walk the set of options, setting options on the operation. This is * used internally by VImage::call(). */ void set_operation(VipsOperation *operation); /** * Walk the set of options, fetching any output values. This is used * internally by VImage::call(). */ void get_operation(VipsOperation *operation); }; /** * An image object. * * Image processing operations on images are member functions of VImage. For * example: * * VImage in = VImage::new_from_file(argv[1], VImage::option() * ->set("access", "sequential")); * VImage out = in.embed(10, 10, 1000, 1000, VImage::option() * ->set("extend", "copy")); * out.write_to_file(argv[2]); * * VImage objects are smart pointers over the underlying VipsImage objects. * They manage the complications of GLib's ref and unref system for you. */ class VImage : public VObject { public: using VObject::is_null; /** * Wrap a VImage around an underlying VipsImage object. * * If steal is STEAL, then the VImage will take ownership of the * reference to the VipsImage. */ explicit VImage(VipsImage *image, VSteal steal = STEAL) : VObject((VipsObject *) image, steal) { } /** * An empty (NULL) VImage, eg. "VImage a;" */ VImage() : VObject(nullptr) { } /** * Return the underlying VipsImage reference that this VImage holds. * This does not make a new reference -- you'll need to g_object_ref() * the pointer if you need it to last. */ VipsImage * get_image() const { return (VipsImage *) VObject::get_object(); } /** * Return the width of the image in pixels. */ int width() const { return vips_image_get_width(get_image()); } /** * Return the height of the image in pixels. */ int height() const { return vips_image_get_height(get_image()); } /** * Return the number of image bands. */ int bands() const { return vips_image_get_bands(get_image()); } /** * Return the image format, for example VIPS_FORMAT_UCHAR. */ VipsBandFormat format() const { return vips_image_get_format(get_image()); } /** * Return the image coding, for example VIPS_CODING_NONE. */ VipsCoding coding() const { return vips_image_get_coding(get_image()); } /** * Return the image interpretation, for example * VIPS_INTERPRETATION_sRGB. */ VipsInterpretation interpretation() const { return vips_image_get_interpretation(get_image()); } /** * Try to guess the image interpretation from other fields. This is * handy if the interpretation has not been set correctly. */ VipsInterpretation guess_interpretation() const { return vips_image_guess_interpretation(get_image()); } /** * The horizontal resolution in pixels per millimeter. */ double xres() const { return vips_image_get_xres(get_image()); } /** * The vertical resolution in pixels per millimeter. */ double yres() const { return vips_image_get_yres(get_image()); } /** * The horizontal offset of the origin in pixels. */ int xoffset() const { return vips_image_get_xoffset(get_image()); } /** * The vertical offset of the origin in pixels. */ int yoffset() const { return vips_image_get_yoffset(get_image()); } /** * TRUE if the image has an alpha channel. */ bool has_alpha() const { return vips_image_hasalpha(get_image()); } /** * The name of the file this image originally came from, or NULL if * it's not a file image. */ const char * filename() const { return vips_image_get_filename(get_image()); } /** * The associated gainmap image, if any. */ VImage gainmap() const { return VImage(vips_image_get_gainmap(get_image())); } /** * Gets an VImage ready for an in-place operation, such as draw_circle(). * After calling this function you can both read and write the image with * VIPS_IMAGE_ADDR(). * * This method is called for you by the draw operations, * there's no need to call it yourself. * * Since this function modifies the image, it is not thread-safe. Only * call it on images which you are sure have not been shared with another * thread. All in-place operations are inherently not thread-safe, so * you need to take great care in any case. */ void inplace() { if (vips_image_inplace(this->get_image())) throw(VError()); } /** * Arrange for the underlying object to be entirely in memory, then * return a pointer to the first pixel. * * This can take a long time and need a very large amount of RAM. */ const void * data() const { return vips_image_get_data(get_image()); } /** * Set the value of an int metadata item on an image. */ void set(const char *field, int value) { vips_image_set_int(this->get_image(), field, value); } /** * Set the value of an int array metadata item on an image. * * A copy of the array is taken. */ void set(const char *field, int *value, int n) { vips_image_set_array_int(this->get_image(), field, value, n); } /** * Set the value of an int array metadata item on an image. * * A copy of the array is taken. */ void set(const char *field, std::vector value) { vips_image_set_array_int(this->get_image(), field, &value[0], static_cast(value.size())); } /** * Set the value of an double array metadata item on an image. * * A copy of the array is taken. */ void set(const char *field, double *value, int n) { vips_image_set_array_double(this->get_image(), field, value, n); } /** * Set the value of an double array metadata item on an image. * * A copy of the array is taken. */ void set(const char *field, std::vector value) { vips_image_set_array_double(this->get_image(), field, &value[0], static_cast(value.size())); } /** * Set the value of a double metadata item on an image. */ void set(const char *field, double value) { vips_image_set_double(this->get_image(), field, value); } /** * Set the value of a string metadata item on an image. * * A copy of the string is taken. */ void set(const char *field, const char *value) { vips_image_set_string(this->get_image(), field, value); } /** * Set the value of a binary object metadata item on an image, such as * an ICC profile. * * When libvips no longer needs the value, it will be disposed with * the free function. This can be NULL. */ void set(const char *field, VipsCallbackFn free_fn, void *data, size_t length) { vips_image_set_blob(this->get_image(), field, free_fn, data, length); } /** * Set the value of an image metadata item on an image. */ void set(const char *field, const VImage value) { vips_image_set_image(this->get_image(), field, value.get_image()); } /** * Return the GType of a metadata item, or 0 if the named item does not * exist. */ GType get_typeof(const char *field) const { return vips_image_get_typeof(this->get_image(), field); } /** * Get the value of a metadata item as an int. * * If the item is not of this type, an exception is thrown. */ int get_int(const char *field) const { int value; if (vips_image_get_int(this->get_image(), field, &value)) throw(VError()); return value; } /** * Get the value of a metadata item as an array of ints. Do not free * the result. * * If the item is not of this type, an exception is thrown. */ void get_array_int(const char *field, int **out, int *n) const { if (vips_image_get_array_int(this->get_image(), field, out, n)) throw(VError()); } /** * Get the value of a metadata item as an array of ints. * * If the item is not of this type, an exception is thrown. */ std::vector get_array_int(const char *field) const { int length; int *array; if (vips_image_get_array_int(this->get_image(), field, &array, &length)) throw(VError()); std::vector vector(array, array + length); return vector; } /** * Get the value of a metadata item as an array of doubles. Do not free * the result. * * If the item is not of this type, an exception is thrown. */ void get_array_double(const char *field, double **out, int *n) const { if (vips_image_get_array_double(this->get_image(), field, out, n)) throw(VError()); } /** * Get the value of a metadata item as an array of doubles. * * If the item is not of this type, an exception is thrown. */ std::vector get_array_double(const char *field) const { int length; double *array; if (vips_image_get_array_double(this->get_image(), field, &array, &length)) throw(VError()); std::vector vector(array, array + length); return vector; } /** * Get the value of a metadata item as a double. * * If the item is not of this type, an exception is thrown. */ double get_double(const char *field) const { double value; if (vips_image_get_double(this->get_image(), field, &value)) throw(VError()); return value; } /** * Get the value of a metadata item as a string. You must not free the * result. * * If the item is not of this type, an exception is thrown. */ const char * get_string(const char *field) const { const char *value; if (vips_image_get_string(this->get_image(), field, &value)) throw(VError()); return value; } /** * Get the value of a metadata item as a binary object. You must not * free the result. * * If the item is not of this type, an exception is thrown. */ const void * get_blob(const char *field, size_t *length) const { const void *value; if (vips_image_get_blob(this->get_image(), field, &value, length)) throw(VError()); return value; } /** * Remove a metadata item. This does nothing if the item does not * exist. */ bool remove(const char *name) const { return vips_image_remove(get_image(), name); } /** * Make a new VOption. Can save some typing. */ static VOption * option() { return new VOption(); } /** * Call any libvips operation, with a set of string-encoded options as * well as VOption. */ static void call_option_string(const char *operation_name, const char *option_string, VOption *options = nullptr); /** * Call any libvips operation. */ static void call(const char *operation_name, VOption *options = nullptr); /** * Make a new image which, when written to, will create a large memory * object. See VImage::write(). */ static VImage new_memory() { return VImage(vips_image_new_memory()); } /** * Make a new VImage which, when written to, will create a temporary * file on disc. See VImage::write(). */ static VImage new_temp_file(const char *file_format = ".v") { VipsImage *image; if (!(image = vips_image_new_temp_file(file_format))) throw(VError()); return VImage(image); } /** * Create a new VImage object from a file on disc. * * The available options depends on the image format. See for example * VImage::jpegload(). */ static VImage new_from_file(const char *name, VOption *options = nullptr); /** * Create a new VImage object from an area of memory containing an * image encoded in some format such as JPEG. * * The available options depends on the image format. See for example * VImage::jpegload(). */ static VImage new_from_buffer(const void *buf, size_t len, const char *option_string, VOption *options = nullptr); /** * Create a new VImage object from an area of memory containing an * image encoded in some format such as JPEG. * * The available options depends on the image format. See for example * VImage::jpegload(). */ static VImage new_from_buffer(const std::string &buf, const char *option_string, VOption *options = nullptr); /** * Create a new VImage object from a generic source object. * * The available options depends on the image format. See for example * VImage::jpegload(). */ static VImage new_from_source(VSource source, const char *option_string, VOption *options = nullptr); /** * Create a new VImage object from an area of memory containing a * C-style array. */ static VImage new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format) { VipsImage *image; if (!(image = vips_image_new_from_memory(data, size, width, height, bands, format))) throw(VError()); return VImage(image); } /** * Create a new VImage object from an area of memory containing a * C-style array. * The VImage makes a copy of @data. */ static VImage new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format) { VipsImage *image; if (!(image = vips_image_new_from_memory_copy(data, size, width, height, bands, format))) throw(VError()); return VImage(image); } /** * Create a new VImage object from an area of memory containing a * C-style array. * * The VImage steals ownership of @data and will free() it when it * goes out of scope. */ static VImage new_from_memory_steal(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format); /** * Create a matrix image of a specified size. All elements will be * zero. */ static VImage new_matrix(int width, int height); /** * Create a matrix image of a specified size, initialized from the * array. */ static VImage new_matrix(int width, int height, double *array, int size) { VipsImage *image; if (!(image = vips_image_new_matrix_from_array(width, height, array, size))) throw(VError()); return VImage(image); } /** * Create a matrix image of a specified size, initialized from the * function parameters. */ static VImage new_matrixv(int width, int height, ...); /** * Make a new image of the same size and type as self, but with each * pixel initialized with the constant. */ VImage new_from_image(std::vector pixel) const { VipsImage *image; if (!(image = vips_image_new_from_image(this->get_image(), &pixel[0], static_cast(pixel.size())))) throw(VError()); return VImage(image); } /** * Make a new image of the same size and type as self, but with each * pixel initialized with the constant. */ VImage new_from_image(double pixel) const { return new_from_image(to_vectorv(1, pixel)); } /** * This operation allocates memory, renders self into it, builds a new * image around the memory area, and returns that. * * If the image is already a simple area of memory, it does nothing. * * Call this before using the draw operations to make sure you have a * memory image that can be modified. * * VImage::copy() adds a null "copy" node to a pipeline. Use that * instead if you want to change metadata and not pixels. */ VImage copy_memory() const { VipsImage *image; if (!(image = vips_image_copy_memory(this->get_image()))) throw(VError()); return VImage(image); } /** * Write self to out. See VImage::new_memory() etc. */ VImage write(VImage out) const; /** * Write an image to a file. * * The available options depends on the file format. See * VImage::jpegsave(), for example. */ void write_to_file(const char *name, VOption *options = nullptr) const; /** * Write an image to an area of memory in the specified format. You * must free() the memory area once you are done with it. * * For example: * * void *buf; * size_t size; * image.write_to_buffer(".jpg", &buf, &size); * * The available options depends on the file format. See * VImage::jpegsave(), for example. */ void write_to_buffer(const char *suffix, void **buf, size_t *size, VOption *options = nullptr) const; /** * Write an image to a generic target object in the specified format. * * The available options depends on the file format. See * VImage::jpegsave(), for example. */ void write_to_target(const char *suffix, VTarget target, VOption *options = nullptr) const; /** * Write an image to an area of memory as a C-style array. */ void * write_to_memory(size_t *size) const { void *result; if (!(result = vips_image_write_to_memory(this->get_image(), size))) throw(VError()); return result; } /** * Acquire an unprepared VRegion. */ VRegion region() const; /** * Acquire VRegion covering the given VipsRect. */ VRegion region(VipsRect *rect) const; /** * Acquire VRegion covering the given coordinates. */ VRegion region(int left, int top, int width, int height) const; /** * Apply a linear transform to an image. For every pixel, * * out = in * a + b */ VImage linear(double a, double b, VOption *options = nullptr) const { return this->linear(to_vector(a), to_vector(b), options); } /** * Apply a linear transform to an image. For every pixel, * * out = in * a + b */ VImage linear(std::vector a, double b, VOption *options = nullptr) const { return this->linear(a, to_vector(b), options); } /** * Apply a linear transform to an image. For every pixel, * * out = in * a + b */ VImage linear(double a, std::vector b, VOption *options = nullptr) const { return this->linear(to_vector(a), b, options); } /** * Split a many-band image into an array of one-band images. */ std::vector bandsplit(VOption *options = nullptr) const; /** * Join two images bandwise. */ VImage bandjoin(VImage other, VOption *options = nullptr) const; /** * Append a band to an image, with each element initialized to the * constant value. */ VImage bandjoin(double other, VOption *options = nullptr) const { return bandjoin(to_vector(other), options); } /** * Append a series of bands to an image, with each element initialized * to the constant values. */ VImage bandjoin(std::vector other, VOption *options = nullptr) const { return bandjoin_const(other, options); } /** * Composite other on top of self using the specified blending mode. */ VImage composite(VImage other, VipsBlendMode mode, VOption *options = nullptr) const; /** * Find the position of the image minimum as (x, y). */ std::complex minpos(VOption *options = nullptr) const; /** * Find the position of the image maximum as (x, y). */ std::complex maxpos(VOption *options = nullptr) const; /** * Flip the image left-right. */ VImage fliphor(VOption *options = nullptr) const { return flip(VIPS_DIRECTION_HORIZONTAL, options); } /** * Flip the image top-bottom. */ VImage flipver(VOption *options = nullptr) const { return flip(VIPS_DIRECTION_VERTICAL, options); } /** * Rotate the image by 90 degrees clockwise. */ VImage rot90(VOption *options = nullptr) const { return rot(VIPS_ANGLE_D90, options); } /** * Rotate the image by 180 degrees. */ VImage rot180(VOption *options = nullptr) const { return rot(VIPS_ANGLE_D180, options); } /** * Rotate the image by 270 degrees clockwise. */ VImage rot270(VOption *options = nullptr) const { return rot(VIPS_ANGLE_D270, options); } /** * Dilate the image with the specified structuring element, see * VImage::new_matrix(). Structuring element values can be 0 for * black, 255 for white and 128 for don't care. See VImage::morph(). */ VImage dilate(VImage mask, VOption *options = nullptr) const { return morph(mask, VIPS_OPERATION_MORPHOLOGY_DILATE, options); } /** * Erode the image with the specified structuring element, see * VImage::new_matrix(). Structuring element values can be 0 for * black, 255 for white and 128 for don't care. See VImage::morph(). */ VImage erode(VImage mask, VOption *options = nullptr) const { return morph(mask, VIPS_OPERATION_MORPHOLOGY_ERODE, options); } /** * A median filter of the specified size. See VImage::rank(). */ VImage median(int size = 3, VOption *options = nullptr) const { return rank(size, size, (size * size) / 2, options); } /** * Convert to integer, rounding down. */ VImage floor(VOption *options = nullptr) const { return round(VIPS_OPERATION_ROUND_FLOOR, options); } /** * Convert to integer, rounding up. */ VImage ceil(VOption *options = nullptr) const { return round(VIPS_OPERATION_ROUND_CEIL, options); } /** * Convert to integer, rounding to nearest. */ VImage rint(VOption *options = nullptr) const { return round(VIPS_OPERATION_ROUND_RINT, options); } /** * AND all bands of an image together to make a one-band image. Useful * with the relational operators, for example: * * VImage mask = (in > 128).bandand() */ VImage bandand(VOption *options = nullptr) const { return bandbool(VIPS_OPERATION_BOOLEAN_AND, options); } /** * OR all bands of an image together to make a one-band image. Useful * with the relational operators, for example: * * VImage mask = (in > 128).bandand() */ VImage bandor(VOption *options = nullptr) const { return bandbool(VIPS_OPERATION_BOOLEAN_OR, options); } /** * EOR all bands of an image together to make a one-band image. Useful * with the relational operators, for example: * * VImage mask = (in > 128).bandand() */ VImage bandeor(VOption *options = nullptr) const { return bandbool(VIPS_OPERATION_BOOLEAN_EOR, options); } /** * Return the real part of a complex image. */ VImage real(VOption *options = nullptr) const { return complexget(VIPS_OPERATION_COMPLEXGET_REAL, options); } /** * Return the imaginary part of a complex image. */ VImage imag(VOption *options = nullptr) const { return complexget(VIPS_OPERATION_COMPLEXGET_IMAG, options); } /** * Convert a complex image to polar coordinates. */ VImage polar(VOption *options = nullptr) const { return complex(VIPS_OPERATION_COMPLEX_POLAR, options); } /** * Convert a complex image to rectangular coordinates. */ VImage rect(VOption *options = nullptr) const { return complex(VIPS_OPERATION_COMPLEX_RECT, options); } /** * Find the complex conjugate. */ VImage conj(VOption *options = nullptr) const { return complex(VIPS_OPERATION_COMPLEX_CONJ, options); } /** * Find the sine of each pixel. Angles are in degrees. */ VImage sin(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_SIN, options); } /** * Find the cosine of each pixel. Angles are in degrees. */ VImage cos(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_COS, options); } /** * Find the tangent of each pixel. Angles are in degrees. */ VImage tan(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_TAN, options); } /** * Find the arc sine of each pixel. Angles are in degrees. */ VImage asin(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_ASIN, options); } /** * Find the arc cosine of each pixel. Angles are in degrees. */ VImage acos(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_ACOS, options); } /** * Find the arc tangent of each pixel. Angles are in degrees. */ VImage atan(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_ATAN, options); } /** * Find the hyperbolic sine of each pixel. Angles are in degrees. */ VImage sinh(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_SINH, options); } /** * Find the hyperbolic cosine of each pixel. Angles are in degrees. */ VImage cosh(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_COSH, options); } /** * Find the hyperbolic tangent of each pixel. Angles are in degrees. */ VImage tanh(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_TANH, options); } /** * Find the hyperbolic arc sine of each pixel. Angles are in radians. */ VImage asinh(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_ASINH, options); } /** * Find the hyperbolic arc cosine of each pixel. Angles are in radians. */ VImage acosh(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_ACOSH, options); } /** * Find the hyperbolic arc tangent of each pixel. Angles are in radians. */ VImage atanh(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_ATANH, options); } /** * Find the natural log of each pixel. */ VImage log(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_LOG, options); } /** * Find the base 10 log of each pixel. */ VImage log10(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_LOG10, options); } /** * Find e to the power of each pixel. */ VImage exp(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_EXP, options); } /** * Find 10 to the power of each pixel. */ VImage exp10(VOption *options = nullptr) const { return math(VIPS_OPERATION_MATH_EXP10, options); } /** * Raise each pixel to the specified power. */ VImage pow(VImage other, VOption *options = nullptr) const { return math2(other, VIPS_OPERATION_MATH2_POW, options); } /** * Raise each pixel to the specified power. */ VImage pow(double other, VOption *options = nullptr) const { return math2_const(VIPS_OPERATION_MATH2_POW, to_vector(other), options); } /** * Raise each pixel to the specified power. */ VImage pow(std::vector other, VOption *options = nullptr) const { return math2_const(VIPS_OPERATION_MATH2_POW, other, options); } /** * Raise other to the power of each pixel (the opposite of pow). */ VImage wop(VImage other, VOption *options = nullptr) const { return math2(other, VIPS_OPERATION_MATH2_WOP, options); } /** * Raise the constant to the power of each pixel (the opposite of pow). */ VImage wop(double other, VOption *options = nullptr) const { return math2_const(VIPS_OPERATION_MATH2_WOP, to_vector(other), options); } /** * Raise the constant to the power of each pixel (the opposite of pow). */ VImage wop(std::vector other, VOption *options = nullptr) const { return math2_const(VIPS_OPERATION_MATH2_WOP, other, options); } /** * Calculate atan2 of each pixel. */ VImage atan2(VImage other, VOption *options = nullptr) const { return math2(other, VIPS_OPERATION_MATH2_ATAN2, options); } /** * Calculate atan2 of each pixel. */ VImage atan2(double other, VOption *options = nullptr) const { return math2_const(VIPS_OPERATION_MATH2_ATAN2, to_vector(other), options); } /** * Calculate atan2 of each pixel. */ VImage atan2(std::vector other, VOption *options = nullptr) const { return math2_const(VIPS_OPERATION_MATH2_ATAN2, other, options); } /** * Use self as a conditional image (not zero meaning TRUE) to pick * pixels from th (then) or el (else). */ VImage ifthenelse(std::vector th, VImage el, VOption *options = nullptr) const { return ifthenelse(el.new_from_image(th), el, options); } /** * Use self as a conditional image (not zero meaning TRUE) to pick * pixels from th (then) or el (else). */ VImage ifthenelse(VImage th, std::vector el, VOption *options = nullptr) const { return ifthenelse(th, th.new_from_image(el), options); } /** * Use self as a conditional image (not zero meaning TRUE) to pick * pixels from th (then) or el (else). */ VImage ifthenelse(std::vector th, std::vector el, VOption *options = nullptr) const { return ifthenelse(new_from_image(th), new_from_image(el), options); } /** * Use self as a conditional image (not zero meaning TRUE) to pick * pixels from th (then) or el (else). */ VImage ifthenelse(double th, VImage el, VOption *options = nullptr) const { return ifthenelse(to_vector(th), el, options); } /** * Use self as a conditional image (not zero meaning TRUE) to pick * pixels from th (then) or el (else). */ VImage ifthenelse(VImage th, double el, VOption *options = nullptr) const { return ifthenelse(th, to_vector(el), options); } /** * Use self as a conditional image (not zero meaning TRUE) to pick * pixels from th (then) or el (else). */ VImage ifthenelse(double th, double el, VOption *options = nullptr) const { return ifthenelse(to_vector(th), to_vector(el), options); } /** * Draw a circle on an image. * * **Optional parameters** * - **fill** -- Draw a solid object, bool. * * @param ink Color for pixels. * @param cx Centre of draw_circle. * @param cy Centre of draw_circle. * @param radius Radius in pixels. * @param options Set of options. */ void draw_circle(double ink, int cx, int cy, int radius, VOption *options = nullptr) const { return draw_circle(to_vector(ink), cx, cy, radius, options); } /** * Draw a line on an image. * @param ink Color for pixels. * @param x1 Start of draw_line. * @param y1 Start of draw_line. * @param x2 End of draw_line. * @param y2 End of draw_line. * @param options Set of options. */ void draw_line(double ink, int x1, int y1, int x2, int y2, VOption *options = nullptr) const { return draw_line(to_vector(ink), x1, y1, x2, y2, options); } /** * Paint a rectangle on an image. * * **Optional parameters** * - **fill** -- Draw a solid object, bool. * * @param ink Color for pixels. * @param left Rect to fill. * @param top Rect to fill. * @param width Rect to fill. * @param height Rect to fill. * @param options Set of options. */ void draw_rect(double ink, int left, int top, int width, int height, VOption *options = nullptr) const { return draw_rect(to_vector(ink), left, top, width, height, options); } /** * Paint a single pixel on an image. * * @param ink Color for pixels. * @param x Point to paint. * @param y Point to paint. */ void draw_point(double ink, int x, int y, VOption *options = nullptr) const { return draw_rect(ink, x, y, 1, 1, options); } /** * Paint a single pixel on an image. * * @param ink Color for pixels. * @param x Point to paint. * @param y Point to paint. */ void draw_point(std::vector ink, int x, int y, VOption *options = nullptr) const { return draw_rect(ink, x, y, 1, 1, options); } /** * Flood-fill an area. * * **Optional parameters** * - **test** -- Test pixels in this image, VImage. * - **equal** -- DrawFlood while equal to edge, bool. * * @param ink Color for pixels. * @param x DrawFlood start point. * @param y DrawFlood start point. * @param options Set of options. */ void draw_flood(double ink, int x, int y, VOption *options = nullptr) const { return draw_flood(to_vector(ink), x, y, options); } /** * Draw a mask on an image. * @param ink Color for pixels. * @param mask Mask of pixels to draw. * @param x Draw mask here. * @param y Draw mask here. * @param options Set of options. */ void draw_mask(double ink, VImage mask, int x, int y, VOption *options = nullptr) const { return draw_mask(to_vector(ink), mask, x, y, options); } /** * Generate thumbnail from buffer. * * **Optional parameters** * - **option_string** -- Options that are passed on to the underlying loader, const char *. * - **height** -- Size to this height, int. * - **size** -- Only upsize, only downsize, or both, VipsSize. * - **no_rotate** -- Don't use orientation tags to rotate image upright, bool. * - **crop** -- Reduce to fill target rectangle, then crop, VipsInteresting. * - **linear** -- Reduce in linear light, bool. * - **import_profile** -- Fallback import profile, const char *. * - **export_profile** -- Fallback export profile, const char *. * - **intent** -- Rendering intent, VipsIntent. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param buf Buffer to load from. * @param len Size of buffer. * @param width Size to this width. * @param options Set of options. * @return Output image. */ static VImage thumbnail_buffer(void *buf, size_t len, int width, VOption *options = nullptr); // Operator overloads VImage operator[](int index) const; std::vector operator()(int x, int y) const; friend VIPS_CPLUSPLUS_API VImage operator+(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator+(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator+(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator+(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator+(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator+=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator+=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator+=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator-(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator-(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator-(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator-(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator-(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator-=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator-=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator-=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator-(const VImage a); friend VIPS_CPLUSPLUS_API VImage operator*(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator*(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator*(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator*(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator*(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator*=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator*=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator*=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator/(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator/(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator/(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator/(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator/(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator/=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator/=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator/=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator%(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator%(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator%(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator%=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator%=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator%=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator<(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator<(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator<=(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<=(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<=(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator<=(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<=(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator>(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator>(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator>=(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>=(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>=(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator>=(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>=(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator==(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator==(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator==(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator==(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator==(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator!=(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator!=(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator!=(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator!=(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator!=(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator&(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator&(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator&(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator&(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator&(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator&=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator&=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator&=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator|(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator|(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator|(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator|(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator|(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator|=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator|=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator|=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator^(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator^(const double a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator^(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator^(const std::vector a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator^(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator^=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator^=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator^=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator<<(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator<<(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator<<(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator<<=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator<<=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator<<=(VImage &a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage operator>>(const VImage a, const VImage b); friend VIPS_CPLUSPLUS_API VImage operator>>(const VImage a, const double b); friend VIPS_CPLUSPLUS_API VImage operator>>(const VImage a, const std::vector b); friend VIPS_CPLUSPLUS_API VImage & operator>>=(VImage &a, const VImage b); friend VIPS_CPLUSPLUS_API VImage & operator>>=(VImage &a, const double b); friend VIPS_CPLUSPLUS_API VImage & operator>>=(VImage &a, const std::vector b); // Compat operations static VImage new_from_memory_steal(void *data, size_t size, int width, int height, int bands, VipsBandFormat format); /** * Write raw image to file descriptor. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param fd File descriptor to write to. * @param options Set of options. */ [[deprecated("Use 'rawsave_target' instead")]] void rawsave_fd(int fd, VOption *options = nullptr) const; /* Automatically generated members. * * Rebuild with: * * meson compile -Cbuild vips-operators-header * * Then delete from here to the end of the class and paste in * vips-operators.h. We could just #include "vips-operators.h", but * that confuses doxygen. */ // headers for vips operations // this file is generated automatically, do not edit! // clang-format off /** * Transform lch to cmc. * @param options Set of options. * @return Output image. */ VImage CMC2LCh(VOption *options = nullptr) const; /** * Transform cmyk to xyz. * @param options Set of options. * @return Output image. */ VImage CMYK2XYZ(VOption *options = nullptr) const; /** * Transform hsv to srgb. * @param options Set of options. * @return Output image. */ VImage HSV2sRGB(VOption *options = nullptr) const; /** * Transform lch to cmc. * @param options Set of options. * @return Output image. */ VImage LCh2CMC(VOption *options = nullptr) const; /** * Transform lch to lab. * @param options Set of options. * @return Output image. */ VImage LCh2Lab(VOption *options = nullptr) const; /** * Transform lab to lch. * @param options Set of options. * @return Output image. */ VImage Lab2LCh(VOption *options = nullptr) const; /** * Transform float lab to labq coding. * @param options Set of options. * @return Output image. */ VImage Lab2LabQ(VOption *options = nullptr) const; /** * Transform float lab to signed short. * @param options Set of options. * @return Output image. */ VImage Lab2LabS(VOption *options = nullptr) const; /** * Transform cielab to xyz. * * **Optional parameters** * - **temp** -- Color temperature, std::vector. * * @param options Set of options. * @return Output image. */ VImage Lab2XYZ(VOption *options = nullptr) const; /** * Unpack a labq image to float lab. * @param options Set of options. * @return Output image. */ VImage LabQ2Lab(VOption *options = nullptr) const; /** * Unpack a labq image to short lab. * @param options Set of options. * @return Output image. */ VImage LabQ2LabS(VOption *options = nullptr) const; /** * Convert a labq image to srgb. * @param options Set of options. * @return Output image. */ VImage LabQ2sRGB(VOption *options = nullptr) const; /** * Transform signed short lab to float. * @param options Set of options. * @return Output image. */ VImage LabS2Lab(VOption *options = nullptr) const; /** * Transform short lab to labq coding. * @param options Set of options. * @return Output image. */ VImage LabS2LabQ(VOption *options = nullptr) const; /** * Transform oklab to oklch. * @param options Set of options. * @return Output image. */ VImage Oklab2Oklch(VOption *options = nullptr) const; /** * Transform oklab to xyz. * @param options Set of options. * @return Output image. */ VImage Oklab2XYZ(VOption *options = nullptr) const; /** * Transform oklch to oklab. * @param options Set of options. * @return Output image. */ VImage Oklch2Oklab(VOption *options = nullptr) const; /** * Transform xyz to cmyk. * @param options Set of options. * @return Output image. */ VImage XYZ2CMYK(VOption *options = nullptr) const; /** * Transform xyz to lab. * * **Optional parameters** * - **temp** -- Colour temperature, std::vector. * * @param options Set of options. * @return Output image. */ VImage XYZ2Lab(VOption *options = nullptr) const; /** * Transform xyz to oklab. * @param options Set of options. * @return Output image. */ VImage XYZ2Oklab(VOption *options = nullptr) const; /** * Transform xyz to yxy. * @param options Set of options. * @return Output image. */ VImage XYZ2Yxy(VOption *options = nullptr) const; /** * Transform xyz to scrgb. * @param options Set of options. * @return Output image. */ VImage XYZ2scRGB(VOption *options = nullptr) const; /** * Transform yxy to xyz. * @param options Set of options. * @return Output image. */ VImage Yxy2XYZ(VOption *options = nullptr) const; /** * Absolute value of an image. * @param options Set of options. * @return Output image. */ VImage abs(VOption *options = nullptr) const; /** * Add two images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage add(VImage right, VOption *options = nullptr) const; /** * Append an alpha channel. * @param options Set of options. * @return Output image. */ VImage addalpha(VOption *options = nullptr) const; /** * Affine transform of an image. * * **Optional parameters** * - **interpolate** -- Interpolate pixels with this, VInterpolate. * - **oarea** -- Area of output to generate, std::vector. * - **odx** -- Horizontal output displacement, double. * - **ody** -- Vertical output displacement, double. * - **idx** -- Horizontal input displacement, double. * - **idy** -- Vertical input displacement, double. * - **background** -- Background value, std::vector. * - **premultiplied** -- Images have premultiplied alpha, bool. * - **extend** -- How to generate the extra pixels, VipsExtend. * * @param matrix Transformation matrix. * @param options Set of options. * @return Output image. */ VImage affine(std::vector matrix, VOption *options = nullptr) const; /** * Load an analyze6 image. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage analyzeload(const char *filename, VOption *options = nullptr); /** * Join an array of images. * * **Optional parameters** * - **across** -- Number of images across grid, int. * - **shim** -- Pixels between images, int. * - **background** -- Colour for new pixels, std::vector. * - **halign** -- Align on the left, centre or right, VipsAlign. * - **valign** -- Align on the top, centre or bottom, VipsAlign. * - **hspacing** -- Horizontal spacing between images, int. * - **vspacing** -- Vertical spacing between images, int. * * @param in Array of input images. * @param options Set of options. * @return Output image. */ static VImage arrayjoin(std::vector in, VOption *options = nullptr); /** * Autorotate image by exif tag. * @param options Set of options. * @return Output image. */ VImage autorot(VOption *options = nullptr) const; /** * Find image average. * @param options Set of options. * @return Output value. */ double avg(VOption *options = nullptr) const; /** * Boolean operation across image bands. * @param boolean Boolean to perform. * @param options Set of options. * @return Output image. */ VImage bandbool(VipsOperationBoolean boolean, VOption *options = nullptr) const; /** * Fold up x axis into bands. * * **Optional parameters** * - **factor** -- Fold by this factor, int. * * @param options Set of options. * @return Output image. */ VImage bandfold(VOption *options = nullptr) const; /** * Bandwise join a set of images. * @param in Array of input images. * @param options Set of options. * @return Output image. */ static VImage bandjoin(std::vector in, VOption *options = nullptr); /** * Append a constant band to an image. * @param c Array of constants to add. * @param options Set of options. * @return Output image. */ VImage bandjoin_const(std::vector c, VOption *options = nullptr) const; /** * Band-wise average. * @param options Set of options. * @return Output image. */ VImage bandmean(VOption *options = nullptr) const; /** * Band-wise rank of a set of images. * * **Optional parameters** * - **index** -- Select this band element from sorted list, int. * * @param in Array of input images. * @param options Set of options. * @return Output image. */ static VImage bandrank(std::vector in, VOption *options = nullptr); /** * Unfold image bands into x axis. * * **Optional parameters** * - **factor** -- Unfold by this factor, int. * * @param options Set of options. * @return Output image. */ VImage bandunfold(VOption *options = nullptr) const; /** * Make a black image. * * **Optional parameters** * - **bands** -- Number of bands in image, int. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage black(int width, int height, VOption *options = nullptr); /** * Boolean operation on two images. * @param right Right-hand image argument. * @param boolean Boolean to perform. * @param options Set of options. * @return Output image. */ VImage boolean(VImage right, VipsOperationBoolean boolean, VOption *options = nullptr) const; /** * Boolean operations against a constant. * @param boolean Boolean to perform. * @param c Array of constants. * @param options Set of options. * @return Output image. */ VImage boolean_const(VipsOperationBoolean boolean, std::vector c, VOption *options = nullptr) const; /** * Build a look-up table. * @param options Set of options. * @return Output image. */ VImage buildlut(VOption *options = nullptr) const; /** * Byteswap an image. * @param options Set of options. * @return Output image. */ VImage byteswap(VOption *options = nullptr) const; /** * Cache an image. * * **Optional parameters** * - **max_tiles** -- Maximum number of tiles to cache, int. * - **tile_height** -- Tile height in pixels, int. * - **tile_width** -- Tile width in pixels, int. * * @param options Set of options. * @return Output image. */ G_DEPRECATED VImage cache(VOption *options = nullptr) const; /** * Canny edge detector. * * **Optional parameters** * - **sigma** -- Sigma of Gaussian, double. * - **precision** -- Convolve with this precision, VipsPrecision. * * @param options Set of options. * @return Output image. */ VImage canny(VOption *options = nullptr) const; /** * Use pixel values to pick cases from an array of images. * @param cases Array of case images. * @param options Set of options. * @return Output image. */ VImage case_image(std::vector cases, VOption *options = nullptr) const; /** * Cast an image. * * **Optional parameters** * - **shift** -- Shift integer values up and down, bool. * * @param format Format to cast to. * @param options Set of options. * @return Output image. */ VImage cast(VipsBandFormat format, VOption *options = nullptr) const; /** * Clamp values of an image. * * **Optional parameters** * - **min** -- Minimum value, double. * - **max** -- Maximum value, double. * * @param options Set of options. * @return Output image. */ VImage clamp(VOption *options = nullptr) const; /** * Convert to a new colorspace. * * **Optional parameters** * - **source_space** -- Source color space, VipsInterpretation. * * @param space Destination color space. * @param options Set of options. * @return Output image. */ VImage colourspace(VipsInterpretation space, VOption *options = nullptr) const; /** * Convolve with rotating mask. * * **Optional parameters** * - **times** -- Rotate and convolve this many times, int. * - **angle** -- Rotate mask by this much between convolutions, VipsAngle45. * - **combine** -- Combine convolution results like this, VipsCombine. * - **precision** -- Convolve with this precision, VipsPrecision. * - **layers** -- Use this many layers in approximation, int. * - **cluster** -- Cluster lines closer than this in approximation, int. * * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage compass(VImage mask, VOption *options = nullptr) const; /** * Perform a complex operation on an image. * @param cmplx Complex to perform. * @param options Set of options. * @return Output image. */ VImage complex(VipsOperationComplex cmplx, VOption *options = nullptr) const; /** * Complex binary operations on two images. * @param right Right-hand image argument. * @param cmplx Binary complex operation to perform. * @param options Set of options. * @return Output image. */ VImage complex2(VImage right, VipsOperationComplex2 cmplx, VOption *options = nullptr) const; /** * Form a complex image from two real images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage complexform(VImage right, VOption *options = nullptr) const; /** * Get a component from a complex image. * @param get Complex to perform. * @param options Set of options. * @return Output image. */ VImage complexget(VipsOperationComplexget get, VOption *options = nullptr) const; /** * Blend an array of images with an array of blend modes. * * **Optional parameters** * - **x** -- Array of x coordinates to join at, std::vector. * - **y** -- Array of y coordinates to join at, std::vector. * - **compositing_space** -- Composite images in this colour space, VipsInterpretation. * - **premultiplied** -- Images have premultiplied alpha, bool. * * @param in Array of input images. * @param mode Array of VipsBlendMode to join with. * @param options Set of options. * @return Output image. */ static VImage composite(std::vector in, std::vector mode, VOption *options = nullptr); /** * Blend a pair of images with a blend mode. * * **Optional parameters** * - **x** -- x position of overlay, int. * - **y** -- y position of overlay, int. * - **compositing_space** -- Composite images in this colour space, VipsInterpretation. * - **premultiplied** -- Images have premultiplied alpha, bool. * * @param overlay Overlay image. * @param mode VipsBlendMode to join with. * @param options Set of options. * @return Output image. */ VImage composite2(VImage overlay, VipsBlendMode mode, VOption *options = nullptr) const; /** * Convolution operation. * * **Optional parameters** * - **precision** -- Convolve with this precision, VipsPrecision. * - **layers** -- Use this many layers in approximation, int. * - **cluster** -- Cluster lines closer than this in approximation, int. * * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage conv(VImage mask, VOption *options = nullptr) const; /** * Approximate integer convolution. * * **Optional parameters** * - **layers** -- Use this many layers in approximation, int. * - **cluster** -- Cluster lines closer than this in approximation, int. * * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage conva(VImage mask, VOption *options = nullptr) const; /** * Approximate separable integer convolution. * * **Optional parameters** * - **layers** -- Use this many layers in approximation, int. * * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage convasep(VImage mask, VOption *options = nullptr) const; /** * Float convolution operation. * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage convf(VImage mask, VOption *options = nullptr) const; /** * Int convolution operation. * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage convi(VImage mask, VOption *options = nullptr) const; /** * Separable convolution operation. * * **Optional parameters** * - **precision** -- Convolve with this precision, VipsPrecision. * - **layers** -- Use this many layers in approximation, int. * - **cluster** -- Cluster lines closer than this in approximation, int. * * @param mask Input matrix image. * @param options Set of options. * @return Output image. */ VImage convsep(VImage mask, VOption *options = nullptr) const; /** * Copy an image. * * **Optional parameters** * - **width** -- Image width in pixels, int. * - **height** -- Image height in pixels, int. * - **bands** -- Number of bands in image, int. * - **format** -- Pixel format in image, VipsBandFormat. * - **coding** -- Pixel coding, VipsCoding. * - **interpretation** -- Pixel interpretation, VipsInterpretation. * - **xres** -- Horizontal resolution in pixels/mm, double. * - **yres** -- Vertical resolution in pixels/mm, double. * - **xoffset** -- Horizontal offset of origin, int. * - **yoffset** -- Vertical offset of origin, int. * * @param options Set of options. * @return Output image. */ VImage copy(VOption *options = nullptr) const; /** * Count lines in an image. * @param direction Countlines left-right or up-down. * @param options Set of options. * @return Number of lines. */ double countlines(VipsDirection direction, VOption *options = nullptr) const; /** * Extract an area from an image. * @param left Left edge of extract area. * @param top Top edge of extract area. * @param width Width of extract area. * @param height Height of extract area. * @param options Set of options. * @return Output image. */ VImage crop(int left, int top, int width, int height, VOption *options = nullptr) const; /** * Load csv. * * **Optional parameters** * - **skip** -- Skip this many lines at the start of the file, int. * - **lines** -- Read this many lines from the file, int. * - **whitespace** -- Set of whitespace characters, const char *. * - **separator** -- Set of separator characters, const char *. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage csvload(const char *filename, VOption *options = nullptr); /** * Load csv. * * **Optional parameters** * - **skip** -- Skip this many lines at the start of the file, int. * - **lines** -- Read this many lines from the file, int. * - **whitespace** -- Set of whitespace characters, const char *. * - **separator** -- Set of separator characters, const char *. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage csvload_source(VSource source, VOption *options = nullptr); /** * Save image to csv. * * **Optional parameters** * - **separator** -- Separator characters, const char *. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void csvsave(const char *filename, VOption *options = nullptr) const; /** * Save image to csv. * * **Optional parameters** * - **separator** -- Separator characters, const char *. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void csvsave_target(VTarget target, VOption *options = nullptr) const; /** * Calculate de00. * @param right Right-hand input image. * @param options Set of options. * @return Output image. */ VImage dE00(VImage right, VOption *options = nullptr) const; /** * Calculate de76. * @param right Right-hand input image. * @param options Set of options. * @return Output image. */ VImage dE76(VImage right, VOption *options = nullptr) const; /** * Calculate decmc. * @param right Right-hand input image. * @param options Set of options. * @return Output image. */ VImage dECMC(VImage right, VOption *options = nullptr) const; /** * Load raw camera files. * * **Optional parameters** * - **bitdepth** -- Number of bits per pixel, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage dcrawload(const char *filename, VOption *options = nullptr); /** * Load raw camera files. * * **Optional parameters** * - **bitdepth** -- Number of bits per pixel, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage dcrawload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load raw camera files. * * **Optional parameters** * - **bitdepth** -- Number of bits per pixel, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage dcrawload_source(VSource source, VOption *options = nullptr); /** * Find image standard deviation. * @param options Set of options. * @return Output value. */ double deviate(VOption *options = nullptr) const; /** * Divide two images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage divide(VImage right, VOption *options = nullptr) const; /** * Draw a circle on an image. * * **Optional parameters** * - **fill** -- Draw a solid object, bool. * * @param ink Color for pixels. * @param cx Centre of draw_circle. * @param cy Centre of draw_circle. * @param radius Radius in pixels. * @param options Set of options. */ void draw_circle(std::vector ink, int cx, int cy, int radius, VOption *options = nullptr) const; /** * Flood-fill an area. * * **Optional parameters** * - **test** -- Test pixels in this image, VImage. * - **equal** -- DrawFlood while equal to edge, bool. * * @param ink Color for pixels. * @param x DrawFlood start point. * @param y DrawFlood start point. * @param options Set of options. */ void draw_flood(std::vector ink, int x, int y, VOption *options = nullptr) const; /** * Paint an image into another image. * * **Optional parameters** * - **mode** -- Combining mode, VipsCombineMode. * * @param sub Sub-image to insert into main image. * @param x Draw image here. * @param y Draw image here. * @param options Set of options. */ void draw_image(VImage sub, int x, int y, VOption *options = nullptr) const; /** * Draw a line on an image. * @param ink Color for pixels. * @param x1 Start of draw_line. * @param y1 Start of draw_line. * @param x2 End of draw_line. * @param y2 End of draw_line. * @param options Set of options. */ void draw_line(std::vector ink, int x1, int y1, int x2, int y2, VOption *options = nullptr) const; /** * Draw a mask on an image. * @param ink Color for pixels. * @param mask Mask of pixels to draw. * @param x Draw mask here. * @param y Draw mask here. * @param options Set of options. */ void draw_mask(std::vector ink, VImage mask, int x, int y, VOption *options = nullptr) const; /** * Paint a rectangle on an image. * * **Optional parameters** * - **fill** -- Draw a solid object, bool. * * @param ink Color for pixels. * @param left Rect to fill. * @param top Rect to fill. * @param width Rect to fill. * @param height Rect to fill. * @param options Set of options. */ void draw_rect(std::vector ink, int left, int top, int width, int height, VOption *options = nullptr) const; /** * Blur a rectangle on an image. * @param left Rect to fill. * @param top Rect to fill. * @param width Rect to fill. * @param height Rect to fill. * @param options Set of options. */ void draw_smudge(int left, int top, int width, int height, VOption *options = nullptr) const; /** * Save image to deepzoom file. * * **Optional parameters** * - **imagename** -- Image name, const char *. * - **layout** -- Directory layout, VipsForeignDzLayout. * - **suffix** -- Filename suffix for tiles, const char *. * - **overlap** -- Tile overlap in pixels, int. * - **tile_size** -- Tile size in pixels, int. * - **centre** -- Center image in tile, bool. * - **depth** -- Pyramid depth, VipsForeignDzDepth. * - **angle** -- Rotate image during save, VipsAngle. * - **container** -- Pyramid container type, VipsForeignDzContainer. * - **compression** -- ZIP deflate compression level, int. * - **region_shrink** -- Method to shrink regions, VipsRegionShrink. * - **skip_blanks** -- Skip tiles which are nearly equal to the background, int. * - **id** -- Resource ID, const char *. * - **Q** -- Q factor, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void dzsave(const char *filename, VOption *options = nullptr) const; /** * Save image to dz buffer. * * **Optional parameters** * - **imagename** -- Image name, const char *. * - **layout** -- Directory layout, VipsForeignDzLayout. * - **suffix** -- Filename suffix for tiles, const char *. * - **overlap** -- Tile overlap in pixels, int. * - **tile_size** -- Tile size in pixels, int. * - **centre** -- Center image in tile, bool. * - **depth** -- Pyramid depth, VipsForeignDzDepth. * - **angle** -- Rotate image during save, VipsAngle. * - **container** -- Pyramid container type, VipsForeignDzContainer. * - **compression** -- ZIP deflate compression level, int. * - **region_shrink** -- Method to shrink regions, VipsRegionShrink. * - **skip_blanks** -- Skip tiles which are nearly equal to the background, int. * - **id** -- Resource ID, const char *. * - **Q** -- Q factor, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *dzsave_buffer(VOption *options = nullptr) const; /** * Save image to deepzoom target. * * **Optional parameters** * - **imagename** -- Image name, const char *. * - **layout** -- Directory layout, VipsForeignDzLayout. * - **suffix** -- Filename suffix for tiles, const char *. * - **overlap** -- Tile overlap in pixels, int. * - **tile_size** -- Tile size in pixels, int. * - **centre** -- Center image in tile, bool. * - **depth** -- Pyramid depth, VipsForeignDzDepth. * - **angle** -- Rotate image during save, VipsAngle. * - **container** -- Pyramid container type, VipsForeignDzContainer. * - **compression** -- ZIP deflate compression level, int. * - **region_shrink** -- Method to shrink regions, VipsRegionShrink. * - **skip_blanks** -- Skip tiles which are nearly equal to the background, int. * - **id** -- Resource ID, const char *. * - **Q** -- Q factor, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void dzsave_target(VTarget target, VOption *options = nullptr) const; /** * Embed an image in a larger image. * * **Optional parameters** * - **extend** -- How to generate the extra pixels, VipsExtend. * - **background** -- Color for background pixels, std::vector. * * @param x Left edge of input in output. * @param y Top edge of input in output. * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ VImage embed(int x, int y, int width, int height, VOption *options = nullptr) const; /** * Extract an area from an image. * @param left Left edge of extract area. * @param top Top edge of extract area. * @param width Width of extract area. * @param height Height of extract area. * @param options Set of options. * @return Output image. */ VImage extract_area(int left, int top, int width, int height, VOption *options = nullptr) const; /** * Extract band from an image. * * **Optional parameters** * - **n** -- Number of bands to extract, int. * * @param band Band to extract. * @param options Set of options. * @return Output image. */ VImage extract_band(int band, VOption *options = nullptr) const; /** * Make an image showing the eye's spatial response. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **factor** -- Maximum spatial frequency, double. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage eye(int width, int height, VOption *options = nullptr); /** * False-color an image. * @param options Set of options. * @return Output image. */ VImage falsecolour(VOption *options = nullptr) const; /** * Fast correlation. * @param ref Input reference image. * @param options Set of options. * @return Output image. */ VImage fastcor(VImage ref, VOption *options = nullptr) const; /** * Fill image zeros with nearest non-zero pixel. * @param options Set of options. * @return Value of nearest non-zero pixel. */ VImage fill_nearest(VOption *options = nullptr) const; /** * Search an image for non-edge areas. * * **Optional parameters** * - **threshold** -- Object threshold, double. * - **background** -- Color for background pixels, std::vector. * - **line_art** -- Enable line art mode, bool. * * @param top Top edge of extract area. * @param width Width of extract area. * @param height Height of extract area. * @param options Set of options. * @return Left edge of image. */ int find_trim(int *top, int *width, int *height, VOption *options = nullptr) const; /** * Load a fits image. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage fitsload(const char *filename, VOption *options = nullptr); /** * Load fits from a source. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage fitsload_source(VSource source, VOption *options = nullptr); /** * Save image to fits file. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void fitssave(const char *filename, VOption *options = nullptr) const; /** * Flatten alpha out of an image. * * **Optional parameters** * - **background** -- Background value, std::vector. * - **max_alpha** -- Maximum value of alpha channel, double. * * @param options Set of options. * @return Output image. */ VImage flatten(VOption *options = nullptr) const; /** * Flip an image. * @param direction Direction to flip image. * @param options Set of options. * @return Output image. */ VImage flip(VipsDirection direction, VOption *options = nullptr) const; /** * Transform float rgb to radiance coding. * @param options Set of options. * @return Output image. */ VImage float2rad(VOption *options = nullptr) const; /** * Make a fractal surface. * @param width Image width in pixels. * @param height Image height in pixels. * @param fractal_dimension Fractal dimension. * @param options Set of options. * @return Output image. */ static VImage fractsurf(int width, int height, double fractal_dimension, VOption *options = nullptr); /** * Frequency-domain filtering. * @param mask Input mask image. * @param options Set of options. * @return Output image. */ VImage freqmult(VImage mask, VOption *options = nullptr) const; /** * Forward fft. * @param options Set of options. * @return Output image. */ VImage fwfft(VOption *options = nullptr) const; /** * Gamma an image. * * **Optional parameters** * - **exponent** -- Gamma factor, double. * * @param options Set of options. * @return Output image. */ VImage gamma(VOption *options = nullptr) const; /** * Gaussian blur. * * **Optional parameters** * - **min_ampl** -- Minimum amplitude of Gaussian, double. * - **precision** -- Convolve with this precision, VipsPrecision. * * @param sigma Sigma of Gaussian. * @param options Set of options. * @return Output image. */ VImage gaussblur(double sigma, VOption *options = nullptr) const; /** * Make a gaussian image. * * **Optional parameters** * - **separable** -- Generate separable Gaussian, bool. * - **precision** -- Generate with this precision, VipsPrecision. * * @param sigma Sigma of Gaussian. * @param min_ampl Minimum amplitude of Gaussian. * @param options Set of options. * @return Output image. */ static VImage gaussmat(double sigma, double min_ampl, VOption *options = nullptr); /** * Make a gaussnoise image. * * **Optional parameters** * - **sigma** -- Standard deviation of pixels in generated image, double. * - **mean** -- Mean of pixels in generated image, double. * - **seed** -- Random number seed, int. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage gaussnoise(int width, int height, VOption *options = nullptr); /** * Read a point from an image. * * **Optional parameters** * - **unpack_complex** -- Complex pixels should be unpacked, bool. * * @param x Point to read. * @param y Point to read. * @param options Set of options. * @return Array of output values. */ std::vector getpoint(int x, int y, VOption *options = nullptr) const; /** * Load gif with libnsgif. * * **Optional parameters** * - **n** -- Number of pages to load, -1 for all, int. * - **page** -- First page to load, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage gifload(const char *filename, VOption *options = nullptr); /** * Load gif with libnsgif. * * **Optional parameters** * - **n** -- Number of pages to load, -1 for all, int. * - **page** -- First page to load, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage gifload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load gif from source. * * **Optional parameters** * - **n** -- Number of pages to load, -1 for all, int. * - **page** -- First page to load, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage gifload_source(VSource source, VOption *options = nullptr); /** * Save as gif. * * **Optional parameters** * - **dither** -- Amount of dithering, double. * - **effort** -- Quantisation effort, int. * - **bitdepth** -- Number of bits per pixel, int. * - **interframe_maxerror** -- Maximum inter-frame error for transparency, double. * - **reuse** -- Reuse palette from input, bool. * - **interpalette_maxerror** -- Maximum inter-palette error for palette reusage, double. * - **interlace** -- Generate an interlaced (progressive) GIF, bool. * - **keep_duplicate_frames** -- Keep duplicate frames in the output instead of combining them, bool. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void gifsave(const char *filename, VOption *options = nullptr) const; /** * Save as gif. * * **Optional parameters** * - **dither** -- Amount of dithering, double. * - **effort** -- Quantisation effort, int. * - **bitdepth** -- Number of bits per pixel, int. * - **interframe_maxerror** -- Maximum inter-frame error for transparency, double. * - **reuse** -- Reuse palette from input, bool. * - **interpalette_maxerror** -- Maximum inter-palette error for palette reusage, double. * - **interlace** -- Generate an interlaced (progressive) GIF, bool. * - **keep_duplicate_frames** -- Keep duplicate frames in the output instead of combining them, bool. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *gifsave_buffer(VOption *options = nullptr) const; /** * Save as gif. * * **Optional parameters** * - **dither** -- Amount of dithering, double. * - **effort** -- Quantisation effort, int. * - **bitdepth** -- Number of bits per pixel, int. * - **interframe_maxerror** -- Maximum inter-frame error for transparency, double. * - **reuse** -- Reuse palette from input, bool. * - **interpalette_maxerror** -- Maximum inter-palette error for palette reusage, double. * - **interlace** -- Generate an interlaced (progressive) GIF, bool. * - **keep_duplicate_frames** -- Keep duplicate frames in the output instead of combining them, bool. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void gifsave_target(VTarget target, VOption *options = nullptr) const; /** * Global balance an image mosaic. * * **Optional parameters** * - **gamma** -- Image gamma, double. * - **int_output** -- Integer output, bool. * * @param options Set of options. * @return Output image. */ VImage globalbalance(VOption *options = nullptr) const; /** * Place an image within a larger image with a certain gravity. * * **Optional parameters** * - **extend** -- How to generate the extra pixels, VipsExtend. * - **background** -- Color for background pixels, std::vector. * * @param direction Direction to place image within width/height. * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ VImage gravity(VipsCompassDirection direction, int width, int height, VOption *options = nullptr) const; /** * Make a grey ramp image. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage grey(int width, int height, VOption *options = nullptr); /** * Grid an image. * @param tile_height Chop into tiles this high. * @param across Number of tiles across. * @param down Number of tiles down. * @param options Set of options. * @return Output image. */ VImage grid(int tile_height, int across, int down, VOption *options = nullptr) const; /** * Load a heif image. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **thumbnail** -- Fetch thumbnail image, bool. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage heifload(const char *filename, VOption *options = nullptr); /** * Load a heif image. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **thumbnail** -- Fetch thumbnail image, bool. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage heifload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load a heif image. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **thumbnail** -- Fetch thumbnail image, bool. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage heifload_source(VSource source, VOption *options = nullptr); /** * Save image in heif format. * * **Optional parameters** * - **Q** -- Q factor, int. * - **bitdepth** -- Number of bits per pixel, int. * - **lossless** -- Enable lossless compression, bool. * - **compression** -- Compression format, VipsForeignHeifCompression. * - **effort** -- CPU effort, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **encoder** -- Select encoder to use, VipsForeignHeifEncoder. * - **tune** -- Tuning parameters, const char *. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void heifsave(const char *filename, VOption *options = nullptr) const; /** * Save image in heif format. * * **Optional parameters** * - **Q** -- Q factor, int. * - **bitdepth** -- Number of bits per pixel, int. * - **lossless** -- Enable lossless compression, bool. * - **compression** -- Compression format, VipsForeignHeifCompression. * - **effort** -- CPU effort, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **encoder** -- Select encoder to use, VipsForeignHeifEncoder. * - **tune** -- Tuning parameters, const char *. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *heifsave_buffer(VOption *options = nullptr) const; /** * Save image in heif format. * * **Optional parameters** * - **Q** -- Q factor, int. * - **bitdepth** -- Number of bits per pixel, int. * - **lossless** -- Enable lossless compression, bool. * - **compression** -- Compression format, VipsForeignHeifCompression. * - **effort** -- CPU effort, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **encoder** -- Select encoder to use, VipsForeignHeifEncoder. * - **tune** -- Tuning parameters, const char *. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void heifsave_target(VTarget target, VOption *options = nullptr) const; /** * Form cumulative histogram. * @param options Set of options. * @return Output image. */ VImage hist_cum(VOption *options = nullptr) const; /** * Estimate image entropy. * @param options Set of options. * @return Output value. */ double hist_entropy(VOption *options = nullptr) const; /** * Histogram equalisation. * * **Optional parameters** * - **band** -- Equalise with this band, int. * * @param options Set of options. * @return Output image. */ VImage hist_equal(VOption *options = nullptr) const; /** * Find image histogram. * * **Optional parameters** * - **band** -- Find histogram of band, int. * * @param options Set of options. * @return Output histogram. */ VImage hist_find(VOption *options = nullptr) const; /** * Find indexed image histogram. * * **Optional parameters** * - **combine** -- Combine bins like this, VipsCombine. * * @param index Index image. * @param options Set of options. * @return Output histogram. */ VImage hist_find_indexed(VImage index, VOption *options = nullptr) const; /** * Find n-dimensional image histogram. * * **Optional parameters** * - **bins** -- Number of bins in each dimension, int. * * @param options Set of options. * @return Output histogram. */ VImage hist_find_ndim(VOption *options = nullptr) const; /** * Test for monotonicity. * @param options Set of options. * @return true if in is monotonic. */ bool hist_ismonotonic(VOption *options = nullptr) const; /** * Local histogram equalisation. * * **Optional parameters** * - **max_slope** -- Maximum slope (CLAHE), int. * * @param width Window width in pixels. * @param height Window height in pixels. * @param options Set of options. * @return Output image. */ VImage hist_local(int width, int height, VOption *options = nullptr) const; /** * Match two histograms. * @param ref Reference histogram. * @param options Set of options. * @return Output image. */ VImage hist_match(VImage ref, VOption *options = nullptr) const; /** * Normalise histogram. * @param options Set of options. * @return Output image. */ VImage hist_norm(VOption *options = nullptr) const; /** * Plot histogram. * @param options Set of options. * @return Output image. */ VImage hist_plot(VOption *options = nullptr) const; /** * Find hough circle transform. * * **Optional parameters** * - **scale** -- Scale down dimensions by this factor, int. * - **min_radius** -- Smallest radius to search for, int. * - **max_radius** -- Largest radius to search for, int. * * @param options Set of options. * @return Output image. */ VImage hough_circle(VOption *options = nullptr) const; /** * Find hough line transform. * * **Optional parameters** * - **width** -- Horizontal size of parameter space, int. * - **height** -- Vertical size of parameter space, int. * * @param options Set of options. * @return Output image. */ VImage hough_line(VOption *options = nullptr) const; /** * Output to device with icc profile. * * **Optional parameters** * - **pcs** -- Set Profile Connection Space, VipsPCS. * - **intent** -- Rendering intent, VipsIntent. * - **black_point_compensation** -- Enable black point compensation, bool. * - **output_profile** -- Filename to load output profile from, const char *. * - **depth** -- Output device space depth in bits, int. * * @param options Set of options. * @return Output image. */ VImage icc_export(VOption *options = nullptr) const; /** * Import from device with icc profile. * * **Optional parameters** * - **pcs** -- Set Profile Connection Space, VipsPCS. * - **intent** -- Rendering intent, VipsIntent. * - **black_point_compensation** -- Enable black point compensation, bool. * - **embedded** -- Use embedded input profile, if available, bool. * - **input_profile** -- Filename to load input profile from, const char *. * * @param options Set of options. * @return Output image. */ VImage icc_import(VOption *options = nullptr) const; /** * Transform between devices with icc profiles. * * **Optional parameters** * - **pcs** -- Set Profile Connection Space, VipsPCS. * - **intent** -- Rendering intent, VipsIntent. * - **black_point_compensation** -- Enable black point compensation, bool. * - **embedded** -- Use embedded input profile, if available, bool. * - **input_profile** -- Filename to load input profile from, const char *. * - **depth** -- Output device space depth in bits, int. * * @param output_profile Filename to load output profile from. * @param options Set of options. * @return Output image. */ VImage icc_transform(const char *output_profile, VOption *options = nullptr) const; /** * Make a 1d image where pixel values are indexes. * * **Optional parameters** * - **bands** -- Number of bands in LUT, int. * - **ushort** -- Create a 16-bit LUT, bool. * - **size** -- Size of 16-bit LUT, int. * * @param options Set of options. * @return Output image. */ static VImage identity(VOption *options = nullptr); /** * Ifthenelse an image. * * **Optional parameters** * - **blend** -- Blend smoothly between then and else parts, bool. * * @param in1 Source for TRUE pixels. * @param in2 Source for FALSE pixels. * @param options Set of options. * @return Output image. */ VImage ifthenelse(VImage in1, VImage in2, VOption *options = nullptr) const; /** * Insert image @sub into @main at @x, @y. * * **Optional parameters** * - **expand** -- Expand output to hold all of both inputs, bool. * - **background** -- Color for new pixels, std::vector. * * @param sub Sub-image to insert into main image. * @param x Left edge of sub in main. * @param y Top edge of sub in main. * @param options Set of options. * @return Output image. */ VImage insert(VImage sub, int x, int y, VOption *options = nullptr) const; /** * Invert an image. * @param options Set of options. * @return Output image. */ VImage invert(VOption *options = nullptr) const; /** * Build an inverted look-up table. * * **Optional parameters** * - **size** -- LUT size to generate, int. * * @param options Set of options. * @return Output image. */ VImage invertlut(VOption *options = nullptr) const; /** * Inverse fft. * * **Optional parameters** * - **real** -- Output only the real part of the transform, bool. * * @param options Set of options. * @return Output image. */ VImage invfft(VOption *options = nullptr) const; /** * Join a pair of images. * * **Optional parameters** * - **expand** -- Expand output to hold all of both inputs, bool. * - **shim** -- Pixels between images, int. * - **background** -- Colour for new pixels, std::vector. * - **align** -- Align on the low, centre or high coordinate edge, VipsAlign. * * @param in2 Second input image. * @param direction Join left-right or up-down. * @param options Set of options. * @return Output image. */ VImage join(VImage in2, VipsDirection direction, VOption *options = nullptr) const; /** * Load jpeg2000 image. * * **Optional parameters** * - **page** -- Load this page from the image, int. * - **oneshot** -- Load images a frame at a time, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage jp2kload(const char *filename, VOption *options = nullptr); /** * Load jpeg2000 image. * * **Optional parameters** * - **page** -- Load this page from the image, int. * - **oneshot** -- Load images a frame at a time, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage jp2kload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load jpeg2000 image. * * **Optional parameters** * - **page** -- Load this page from the image, int. * - **oneshot** -- Load images a frame at a time, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage jp2kload_source(VSource source, VOption *options = nullptr); /** * Save image in jpeg2000 format. * * **Optional parameters** * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **lossless** -- Enable lossless compression, bool. * - **Q** -- Q factor, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void jp2ksave(const char *filename, VOption *options = nullptr) const; /** * Save image in jpeg2000 format. * * **Optional parameters** * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **lossless** -- Enable lossless compression, bool. * - **Q** -- Q factor, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *jp2ksave_buffer(VOption *options = nullptr) const; /** * Save image in jpeg2000 format. * * **Optional parameters** * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **lossless** -- Enable lossless compression, bool. * - **Q** -- Q factor, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void jp2ksave_target(VTarget target, VOption *options = nullptr) const; /** * Load jpeg from file. * * **Optional parameters** * - **shrink** -- Shrink factor on load, int. * - **autorotate** -- Rotate image using exif orientation, bool. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage jpegload(const char *filename, VOption *options = nullptr); /** * Load jpeg from buffer. * * **Optional parameters** * - **shrink** -- Shrink factor on load, int. * - **autorotate** -- Rotate image using exif orientation, bool. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage jpegload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load image from jpeg source. * * **Optional parameters** * - **shrink** -- Shrink factor on load, int. * - **autorotate** -- Rotate image using exif orientation, bool. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage jpegload_source(VSource source, VOption *options = nullptr); /** * Save as jpeg. * * **Optional parameters** * - **Q** -- Q factor, int. * - **optimize_coding** -- Compute optimal Huffman coding tables, bool. * - **interlace** -- Generate an interlaced (progressive) jpeg, bool. * - **trellis_quant** -- Apply trellis quantisation to each 8x8 block, bool. * - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool. * - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool. * - **quant_table** -- Use predefined quantization table with given index, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **restart_interval** -- Add restart markers every specified number of mcu, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void jpegsave(const char *filename, VOption *options = nullptr) const; /** * Save as jpeg. * * **Optional parameters** * - **Q** -- Q factor, int. * - **optimize_coding** -- Compute optimal Huffman coding tables, bool. * - **interlace** -- Generate an interlaced (progressive) jpeg, bool. * - **trellis_quant** -- Apply trellis quantisation to each 8x8 block, bool. * - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool. * - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool. * - **quant_table** -- Use predefined quantization table with given index, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **restart_interval** -- Add restart markers every specified number of mcu, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *jpegsave_buffer(VOption *options = nullptr) const; /** * Save image to jpeg mime. * * **Optional parameters** * - **Q** -- Q factor, int. * - **optimize_coding** -- Compute optimal Huffman coding tables, bool. * - **interlace** -- Generate an interlaced (progressive) jpeg, bool. * - **trellis_quant** -- Apply trellis quantisation to each 8x8 block, bool. * - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool. * - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool. * - **quant_table** -- Use predefined quantization table with given index, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **restart_interval** -- Add restart markers every specified number of mcu, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. */ void jpegsave_mime(VOption *options = nullptr) const; /** * Save as jpeg. * * **Optional parameters** * - **Q** -- Q factor, int. * - **optimize_coding** -- Compute optimal Huffman coding tables, bool. * - **interlace** -- Generate an interlaced (progressive) jpeg, bool. * - **trellis_quant** -- Apply trellis quantisation to each 8x8 block, bool. * - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool. * - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool. * - **quant_table** -- Use predefined quantization table with given index, int. * - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample. * - **restart_interval** -- Add restart markers every specified number of mcu, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void jpegsave_target(VTarget target, VOption *options = nullptr) const; /** * Load jpeg-xl image. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage jxlload(const char *filename, VOption *options = nullptr); /** * Load jpeg-xl image. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage jxlload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load jpeg-xl image. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage jxlload_source(VSource source, VOption *options = nullptr); /** * Save image in jpeg-xl format. * * **Optional parameters** * - **tier** -- Decode speed tier, int. * - **distance** -- Target butteraugli distance, double. * - **effort** -- Encoding effort, int. * - **lossless** -- Enable lossless compression, bool. * - **Q** -- Quality factor, int. * - **bitdepth** -- Bit depth, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void jxlsave(const char *filename, VOption *options = nullptr) const; /** * Save image in jpeg-xl format. * * **Optional parameters** * - **tier** -- Decode speed tier, int. * - **distance** -- Target butteraugli distance, double. * - **effort** -- Encoding effort, int. * - **lossless** -- Enable lossless compression, bool. * - **Q** -- Quality factor, int. * - **bitdepth** -- Bit depth, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *jxlsave_buffer(VOption *options = nullptr) const; /** * Save image in jpeg-xl format. * * **Optional parameters** * - **tier** -- Decode speed tier, int. * - **distance** -- Target butteraugli distance, double. * - **effort** -- Encoding effort, int. * - **lossless** -- Enable lossless compression, bool. * - **Q** -- Quality factor, int. * - **bitdepth** -- Bit depth, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void jxlsave_target(VTarget target, VOption *options = nullptr) const; /** * Label regions in an image. * @param options Set of options. * @return Mask of region labels. */ VImage labelregions(VOption *options = nullptr) const; /** * Calculate (a * in + b). * * **Optional parameters** * - **uchar** -- Output should be uchar, bool. * * @param a Multiply by this. * @param b Add this. * @param options Set of options. * @return Output image. */ VImage linear(std::vector a, std::vector b, VOption *options = nullptr) const; /** * Cache an image as a set of lines. * * **Optional parameters** * - **tile_height** -- Tile height in pixels, int. * - **access** -- Expected access pattern, VipsAccess. * - **threaded** -- Allow threaded access, bool. * - **persistent** -- Keep cache between evaluations, bool. * * @param options Set of options. * @return Output image. */ VImage linecache(VOption *options = nullptr) const; /** * Make a laplacian of gaussian image. * * **Optional parameters** * - **separable** -- Generate separable Gaussian, bool. * - **precision** -- Generate with this precision, VipsPrecision. * * @param sigma Radius of Gaussian. * @param min_ampl Minimum amplitude of Gaussian. * @param options Set of options. * @return Output image. */ static VImage logmat(double sigma, double min_ampl, VOption *options = nullptr); /** * Load file with imagemagick. * * **Optional parameters** * - **density** -- Canvas resolution for rendering vector formats like SVG, const char *. * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage magickload(const char *filename, VOption *options = nullptr); /** * Load buffer with imagemagick. * * **Optional parameters** * - **density** -- Canvas resolution for rendering vector formats like SVG, const char *. * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage magickload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load source with imagemagick. * * **Optional parameters** * - **density** -- Canvas resolution for rendering vector formats like SVG, const char *. * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage magickload_source(VSource source, VOption *options = nullptr); /** * Save file with imagemagick. * * **Optional parameters** * - **format** -- Format to save in, const char *. * - **quality** -- Quality to use, int. * - **optimize_gif_frames** -- Apply GIF frames optimization, bool. * - **optimize_gif_transparency** -- Apply GIF transparency optimization, bool. * - **bitdepth** -- Number of bits per pixel, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void magicksave(const char *filename, VOption *options = nullptr) const; /** * Save image to magick buffer. * * **Optional parameters** * - **format** -- Format to save in, const char *. * - **quality** -- Quality to use, int. * - **optimize_gif_frames** -- Apply GIF frames optimization, bool. * - **optimize_gif_transparency** -- Apply GIF transparency optimization, bool. * - **bitdepth** -- Number of bits per pixel, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *magicksave_buffer(VOption *options = nullptr) const; /** * Resample with a map image. * * **Optional parameters** * - **interpolate** -- Interpolate pixels with this, VInterpolate. * - **background** -- Background value, std::vector. * - **premultiplied** -- Images have premultiplied alpha, bool. * - **extend** -- How to generate the extra pixels, VipsExtend. * * @param index Index pixels with this. * @param options Set of options. * @return Output image. */ VImage mapim(VImage index, VOption *options = nullptr) const; /** * Map an image though a lut. * * **Optional parameters** * - **band** -- Apply one-band lut to this band of in, int. * * @param lut Look-up table image. * @param options Set of options. * @return Output image. */ VImage maplut(VImage lut, VOption *options = nullptr) const; /** * Make a butterworth filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param order Filter order. * @param frequency_cutoff Frequency cutoff. * @param amplitude_cutoff Amplitude cutoff. * @param options Set of options. * @return Output image. */ static VImage mask_butterworth(int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, VOption *options = nullptr); /** * Make a butterworth_band filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param order Filter order. * @param frequency_cutoff_x Frequency cutoff x. * @param frequency_cutoff_y Frequency cutoff y. * @param radius Radius of circle. * @param amplitude_cutoff Amplitude cutoff. * @param options Set of options. * @return Output image. */ static VImage mask_butterworth_band(int width, int height, double order, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, VOption *options = nullptr); /** * Make a butterworth ring filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param order Filter order. * @param frequency_cutoff Frequency cutoff. * @param amplitude_cutoff Amplitude cutoff. * @param ringwidth Ringwidth. * @param options Set of options. * @return Output image. */ static VImage mask_butterworth_ring(int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, double ringwidth, VOption *options = nullptr); /** * Make fractal filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param fractal_dimension Fractal dimension. * @param options Set of options. * @return Output image. */ static VImage mask_fractal(int width, int height, double fractal_dimension, VOption *options = nullptr); /** * Make a gaussian filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param frequency_cutoff Frequency cutoff. * @param amplitude_cutoff Amplitude cutoff. * @param options Set of options. * @return Output image. */ static VImage mask_gaussian(int width, int height, double frequency_cutoff, double amplitude_cutoff, VOption *options = nullptr); /** * Make a gaussian filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param frequency_cutoff_x Frequency cutoff x. * @param frequency_cutoff_y Frequency cutoff y. * @param radius Radius of circle. * @param amplitude_cutoff Amplitude cutoff. * @param options Set of options. * @return Output image. */ static VImage mask_gaussian_band(int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, VOption *options = nullptr); /** * Make a gaussian ring filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param frequency_cutoff Frequency cutoff. * @param amplitude_cutoff Amplitude cutoff. * @param ringwidth Ringwidth. * @param options Set of options. * @return Output image. */ static VImage mask_gaussian_ring(int width, int height, double frequency_cutoff, double amplitude_cutoff, double ringwidth, VOption *options = nullptr); /** * Make an ideal filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param frequency_cutoff Frequency cutoff. * @param options Set of options. * @return Output image. */ static VImage mask_ideal(int width, int height, double frequency_cutoff, VOption *options = nullptr); /** * Make an ideal band filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param frequency_cutoff_x Frequency cutoff x. * @param frequency_cutoff_y Frequency cutoff y. * @param radius Radius of circle. * @param options Set of options. * @return Output image. */ static VImage mask_ideal_band(int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, VOption *options = nullptr); /** * Make an ideal ring filter. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **nodc** -- Remove DC component, bool. * - **reject** -- Invert the sense of the filter, bool. * - **optical** -- Rotate quadrants to optical space, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param frequency_cutoff Frequency cutoff. * @param ringwidth Ringwidth. * @param options Set of options. * @return Output image. */ static VImage mask_ideal_ring(int width, int height, double frequency_cutoff, double ringwidth, VOption *options = nullptr); /** * First-order match of two images. * * **Optional parameters** * - **hwindow** -- Half window size, int. * - **harea** -- Half area size, int. * - **search** -- Search to improve tie-points, bool. * - **interpolate** -- Interpolate pixels with this, VInterpolate. * * @param sec Secondary image. * @param xr1 Position of first reference tie-point. * @param yr1 Position of first reference tie-point. * @param xs1 Position of first secondary tie-point. * @param ys1 Position of first secondary tie-point. * @param xr2 Position of second reference tie-point. * @param yr2 Position of second reference tie-point. * @param xs2 Position of second secondary tie-point. * @param ys2 Position of second secondary tie-point. * @param options Set of options. * @return Output image. */ VImage match(VImage sec, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, VOption *options = nullptr) const; /** * Apply a math operation to an image. * @param math Math to perform. * @param options Set of options. * @return Output image. */ VImage math(VipsOperationMath math, VOption *options = nullptr) const; /** * Binary math operations. * @param right Right-hand image argument. * @param math2 Math to perform. * @param options Set of options. * @return Output image. */ VImage math2(VImage right, VipsOperationMath2 math2, VOption *options = nullptr) const; /** * Binary math operations with a constant. * @param math2 Math to perform. * @param c Array of constants. * @param options Set of options. * @return Output image. */ VImage math2_const(VipsOperationMath2 math2, std::vector c, VOption *options = nullptr) const; /** * Load mat from file. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage matload(const char *filename, VOption *options = nullptr); /** * Invert a matrix. * @param options Set of options. * @return Output matrix. */ VImage matrixinvert(VOption *options = nullptr) const; /** * Load matrix. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage matrixload(const char *filename, VOption *options = nullptr); /** * Load matrix. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage matrixload_source(VSource source, VOption *options = nullptr); /** * Multiply two matrices. * @param right Second matrix to multiply. * @param options Set of options. * @return Output matrix. */ VImage matrixmultiply(VImage right, VOption *options = nullptr) const; /** * Print matrix. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. */ void matrixprint(VOption *options = nullptr) const; /** * Save image to matrix. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void matrixsave(const char *filename, VOption *options = nullptr) const; /** * Save image to matrix. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void matrixsave_target(VTarget target, VOption *options = nullptr) const; /** * Find image maximum. * * **Optional parameters** * - **size** -- Number of maximum values to find, int. * * @param options Set of options. * @return Output value. */ double max(VOption *options = nullptr) const; /** * Maximum of a pair of images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage maxpair(VImage right, VOption *options = nullptr) const; /** * Measure a set of patches on a color chart. * * **Optional parameters** * - **left** -- Left edge of extract area, int. * - **top** -- Top edge of extract area, int. * - **width** -- Width of extract area, int. * - **height** -- Height of extract area, int. * * @param h Number of patches across chart. * @param v Number of patches down chart. * @param options Set of options. * @return Output array of statistics. */ VImage measure(int h, int v, VOption *options = nullptr) const; /** * Merge two images. * * **Optional parameters** * - **mblend** -- Maximum blend size, int. * * @param sec Secondary image. * @param direction Horizontal or vertical merge. * @param dx Horizontal displacement from sec to ref. * @param dy Vertical displacement from sec to ref. * @param options Set of options. * @return Output image. */ VImage merge(VImage sec, VipsDirection direction, int dx, int dy, VOption *options = nullptr) const; /** * Find image minimum. * * **Optional parameters** * - **size** -- Number of minimum values to find, int. * * @param options Set of options. * @return Output value. */ double min(VOption *options = nullptr) const; /** * Minimum of a pair of images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage minpair(VImage right, VOption *options = nullptr) const; /** * Morphology operation. * @param mask Input matrix image. * @param morph Morphological operation to perform. * @param options Set of options. * @return Output image. */ VImage morph(VImage mask, VipsOperationMorphology morph, VOption *options = nullptr) const; /** * Mosaic two images. * * **Optional parameters** * - **hwindow** -- Half window size, int. * - **harea** -- Half area size, int. * - **mblend** -- Maximum blend size, int. * - **bandno** -- Band to search for features on, int. * * @param sec Secondary image. * @param direction Horizontal or vertical mosaic. * @param xref Position of reference tie-point. * @param yref Position of reference tie-point. * @param xsec Position of secondary tie-point. * @param ysec Position of secondary tie-point. * @param options Set of options. * @return Output image. */ VImage mosaic(VImage sec, VipsDirection direction, int xref, int yref, int xsec, int ysec, VOption *options = nullptr) const; /** * First-order mosaic of two images. * * **Optional parameters** * - **hwindow** -- Half window size, int. * - **harea** -- Half area size, int. * - **search** -- Search to improve tie-points, bool. * - **interpolate** -- Interpolate pixels with this, VInterpolate. * - **mblend** -- Maximum blend size, int. * * @param sec Secondary image. * @param direction Horizontal or vertical mosaic. * @param xr1 Position of first reference tie-point. * @param yr1 Position of first reference tie-point. * @param xs1 Position of first secondary tie-point. * @param ys1 Position of first secondary tie-point. * @param xr2 Position of second reference tie-point. * @param yr2 Position of second reference tie-point. * @param xs2 Position of second secondary tie-point. * @param ys2 Position of second secondary tie-point. * @param options Set of options. * @return Output image. */ VImage mosaic1(VImage sec, VipsDirection direction, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, VOption *options = nullptr) const; /** * Pick most-significant byte from an image. * * **Optional parameters** * - **band** -- Band to msb, int. * * @param options Set of options. * @return Output image. */ VImage msb(VOption *options = nullptr) const; /** * Multiply two images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage multiply(VImage right, VOption *options = nullptr) const; /** * Load nifti volume. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage niftiload(const char *filename, VOption *options = nullptr); /** * Load nifti volumes. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage niftiload_source(VSource source, VOption *options = nullptr); /** * Save image to nifti file. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void niftisave(const char *filename, VOption *options = nullptr) const; /** * Load an openexr image. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage openexrload(const char *filename, VOption *options = nullptr); /** * Load file with openslide. * * **Optional parameters** * - **level** -- Load this level from the file, int. * - **autocrop** -- Crop to image bounds, bool. * - **associated** -- Load this associated image, const char *. * - **attach_associated** -- Attach all associated images, bool. * - **rgb** -- Output RGB (not RGBA), bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage openslideload(const char *filename, VOption *options = nullptr); /** * Load source with openslide. * * **Optional parameters** * - **level** -- Load this level from the file, int. * - **autocrop** -- Crop to image bounds, bool. * - **associated** -- Load this associated image, const char *. * - **attach_associated** -- Attach all associated images, bool. * - **rgb** -- Output RGB (not RGBA), bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage openslideload_source(VSource source, VOption *options = nullptr); /** * Load pdf from file. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **dpi** -- DPI to render at, double. * - **scale** -- Factor to scale by, double. * - **background** -- Background colour, std::vector. * - **password** -- Password to decrypt with, const char *. * - **page_box** -- The region of the page to render, VipsForeignPdfPageBox. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage pdfload(const char *filename, VOption *options = nullptr); /** * Load pdf from buffer. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **dpi** -- DPI to render at, double. * - **scale** -- Factor to scale by, double. * - **background** -- Background colour, std::vector. * - **password** -- Password to decrypt with, const char *. * - **page_box** -- The region of the page to render, VipsForeignPdfPageBox. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage pdfload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load pdf from source. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **dpi** -- DPI to render at, double. * - **scale** -- Factor to scale by, double. * - **background** -- Background colour, std::vector. * - **password** -- Password to decrypt with, const char *. * - **page_box** -- The region of the page to render, VipsForeignPdfPageBox. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage pdfload_source(VSource source, VOption *options = nullptr); /** * Find threshold for percent of pixels. * @param percent Percent of pixels. * @param options Set of options. * @return Threshold above which lie percent of pixels. */ int percent(double percent, VOption *options = nullptr) const; /** * Make a perlin noise image. * * **Optional parameters** * - **cell_size** -- Size of Perlin cells, int. * - **uchar** -- Output an unsigned char image, bool. * - **seed** -- Random number seed, int. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage perlin(int width, int height, VOption *options = nullptr); /** * Calculate phase correlation. * @param in2 Second input image. * @param options Set of options. * @return Output image. */ VImage phasecor(VImage in2, VOption *options = nullptr) const; /** * Load png from file. * * **Optional parameters** * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage pngload(const char *filename, VOption *options = nullptr); /** * Load png from buffer. * * **Optional parameters** * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage pngload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load png from source. * * **Optional parameters** * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage pngload_source(VSource source, VOption *options = nullptr); /** * Save image to file as png. * * **Optional parameters** * - **compression** -- Compression factor, int. * - **interlace** -- Interlace image, bool. * - **filter** -- libpng row filter flag(s), VipsForeignPngFilter. * - **palette** -- Quantise to 8bpp palette, bool. * - **Q** -- Quantisation quality, int. * - **dither** -- Amount of dithering, double. * - **bitdepth** -- Write as a 1, 2, 4, 8 or 16 bit image, int. * - **effort** -- Quantisation CPU effort, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void pngsave(const char *filename, VOption *options = nullptr) const; /** * Save image to buffer as png. * * **Optional parameters** * - **compression** -- Compression factor, int. * - **interlace** -- Interlace image, bool. * - **filter** -- libpng row filter flag(s), VipsForeignPngFilter. * - **palette** -- Quantise to 8bpp palette, bool. * - **Q** -- Quantisation quality, int. * - **dither** -- Amount of dithering, double. * - **bitdepth** -- Write as a 1, 2, 4, 8 or 16 bit image, int. * - **effort** -- Quantisation CPU effort, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *pngsave_buffer(VOption *options = nullptr) const; /** * Save image to target as png. * * **Optional parameters** * - **compression** -- Compression factor, int. * - **interlace** -- Interlace image, bool. * - **filter** -- libpng row filter flag(s), VipsForeignPngFilter. * - **palette** -- Quantise to 8bpp palette, bool. * - **Q** -- Quantisation quality, int. * - **dither** -- Amount of dithering, double. * - **bitdepth** -- Write as a 1, 2, 4, 8 or 16 bit image, int. * - **effort** -- Quantisation CPU effort, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void pngsave_target(VTarget target, VOption *options = nullptr) const; /** * Load ppm from file. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage ppmload(const char *filename, VOption *options = nullptr); /** * Load ppm from buffer. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage ppmload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load ppm from source. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage ppmload_source(VSource source, VOption *options = nullptr); /** * Save image to ppm file. * * **Optional parameters** * - **format** -- Format to save in, VipsForeignPpmFormat. * - **ascii** -- Save as ascii, bool. * - **bitdepth** -- Set to 1 to write as a 1 bit image, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void ppmsave(const char *filename, VOption *options = nullptr) const; /** * Save to ppm. * * **Optional parameters** * - **format** -- Format to save in, VipsForeignPpmFormat. * - **ascii** -- Save as ascii, bool. * - **bitdepth** -- Set to 1 to write as a 1 bit image, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void ppmsave_target(VTarget target, VOption *options = nullptr) const; /** * Premultiply image alpha. * * **Optional parameters** * - **max_alpha** -- Maximum value of alpha channel, double. * * @param options Set of options. * @return Output image. */ VImage premultiply(VOption *options = nullptr) const; /** * Prewitt edge detector. * @param options Set of options. * @return Output image. */ VImage prewitt(VOption *options = nullptr) const; /** * Find image profiles. * @param rows First non-zero pixel in row. * @param options Set of options. * @return First non-zero pixel in column. */ VImage profile(VImage *rows, VOption *options = nullptr) const; /** * Load named icc profile. * @param name Profile name. * @param options Set of options. * @return Loaded profile. */ static VipsBlob *profile_load(const char *name, VOption *options = nullptr); /** * Find image projections. * @param rows Sums of rows. * @param options Set of options. * @return Sums of columns. */ VImage project(VImage *rows, VOption *options = nullptr) const; /** * Resample an image with a quadratic transform. * * **Optional parameters** * - **interpolate** -- Interpolate values with this, VInterpolate. * * @param coeff Coefficient matrix. * @param options Set of options. * @return Output image. */ VImage quadratic(VImage coeff, VOption *options = nullptr) const; /** * Unpack radiance coding to float rgb. * @param options Set of options. * @return Output image. */ VImage rad2float(VOption *options = nullptr) const; /** * Load a radiance image from a file. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage radload(const char *filename, VOption *options = nullptr); /** * Load rad from buffer. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage radload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load rad from source. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage radload_source(VSource source, VOption *options = nullptr); /** * Save image to radiance file. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void radsave(const char *filename, VOption *options = nullptr) const; /** * Save image to radiance buffer. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *radsave_buffer(VOption *options = nullptr) const; /** * Save image to radiance target. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void radsave_target(VTarget target, VOption *options = nullptr) const; /** * Rank filter. * @param width Window width in pixels. * @param height Window height in pixels. * @param index Select pixel at index. * @param options Set of options. * @return Output image. */ VImage rank(int width, int height, int index, VOption *options = nullptr) const; /** * Load raw data from a file. * * **Optional parameters** * - **offset** -- Offset in bytes from start of file, guint64. * - **format** -- Pixel format in image, VipsBandFormat. * - **interpretation** -- Pixel interpretation, VipsInterpretation. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param width Image width in pixels. * @param height Image height in pixels. * @param bands Number of bands in image. * @param options Set of options. * @return Output image. */ static VImage rawload(const char *filename, int width, int height, int bands, VOption *options = nullptr); /** * Save image to raw file. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void rawsave(const char *filename, VOption *options = nullptr) const; /** * Write raw image to buffer. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *rawsave_buffer(VOption *options = nullptr) const; /** * Write raw image to target. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void rawsave_target(VTarget target, VOption *options = nullptr) const; /** * Linear recombination with matrix. * @param m Matrix of coefficients. * @param options Set of options. * @return Output image. */ VImage recomb(VImage m, VOption *options = nullptr) const; /** * Reduce an image. * * **Optional parameters** * - **kernel** -- Resampling kernel, VipsKernel. * - **gap** -- Reducing gap, double. * * @param hshrink Horizontal shrink factor. * @param vshrink Vertical shrink factor. * @param options Set of options. * @return Output image. */ VImage reduce(double hshrink, double vshrink, VOption *options = nullptr) const; /** * Shrink an image horizontally. * * **Optional parameters** * - **kernel** -- Resampling kernel, VipsKernel. * - **gap** -- Reducing gap, double. * * @param hshrink Horizontal shrink factor. * @param options Set of options. * @return Output image. */ VImage reduceh(double hshrink, VOption *options = nullptr) const; /** * Shrink an image vertically. * * **Optional parameters** * - **kernel** -- Resampling kernel, VipsKernel. * - **gap** -- Reducing gap, double. * * @param vshrink Vertical shrink factor. * @param options Set of options. * @return Output image. */ VImage reducev(double vshrink, VOption *options = nullptr) const; /** * Relational operation on two images. * @param right Right-hand image argument. * @param relational Relational to perform. * @param options Set of options. * @return Output image. */ VImage relational(VImage right, VipsOperationRelational relational, VOption *options = nullptr) const; /** * Relational operations against a constant. * @param relational Relational to perform. * @param c Array of constants. * @param options Set of options. * @return Output image. */ VImage relational_const(VipsOperationRelational relational, std::vector c, VOption *options = nullptr) const; /** * Remainder after integer division of two images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage remainder(VImage right, VOption *options = nullptr) const; /** * Remainder after integer division of an image and a constant. * @param c Array of constants. * @param options Set of options. * @return Output image. */ VImage remainder_const(std::vector c, VOption *options = nullptr) const; /** * Rebuild an mosaiced image. * @param old_str Search for this string. * @param new_str And swap for this string. * @param options Set of options. * @return Output image. */ VImage remosaic(const char *old_str, const char *new_str, VOption *options = nullptr) const; /** * Replicate an image. * @param across Repeat this many times horizontally. * @param down Repeat this many times vertically. * @param options Set of options. * @return Output image. */ VImage replicate(int across, int down, VOption *options = nullptr) const; /** * Resize an image. * * **Optional parameters** * - **kernel** -- Resampling kernel, VipsKernel. * - **gap** -- Reducing gap, double. * - **vscale** -- Vertical scale image by this factor, double. * * @param scale Scale image by this factor. * @param options Set of options. * @return Output image. */ VImage resize(double scale, VOption *options = nullptr) const; /** * Rotate an image. * @param angle Angle to rotate image. * @param options Set of options. * @return Output image. */ VImage rot(VipsAngle angle, VOption *options = nullptr) const; /** * Rotate an image. * * **Optional parameters** * - **angle** -- Angle to rotate image, VipsAngle45. * * @param options Set of options. * @return Output image. */ VImage rot45(VOption *options = nullptr) const; /** * Rotate an image by a number of degrees. * * **Optional parameters** * - **interpolate** -- Interpolate pixels with this, VInterpolate. * - **background** -- Background value, std::vector. * - **odx** -- Horizontal output displacement, double. * - **ody** -- Vertical output displacement, double. * - **idx** -- Horizontal input displacement, double. * - **idy** -- Vertical input displacement, double. * * @param angle Rotate clockwise by this many degrees. * @param options Set of options. * @return Output image. */ VImage rotate(double angle, VOption *options = nullptr) const; /** * Perform a round function on an image. * @param round Rounding operation to perform. * @param options Set of options. * @return Output image. */ VImage round(VipsOperationRound round, VOption *options = nullptr) const; /** * Transform srgb to hsv. * @param options Set of options. * @return Output image. */ VImage sRGB2HSV(VOption *options = nullptr) const; /** * Convert an srgb image to scrgb. * @param options Set of options. * @return Output image. */ VImage sRGB2scRGB(VOption *options = nullptr) const; /** * Convert scrgb to bw. * * **Optional parameters** * - **depth** -- Output device space depth in bits, int. * * @param options Set of options. * @return Output image. */ VImage scRGB2BW(VOption *options = nullptr) const; /** * Transform scrgb to xyz. * @param options Set of options. * @return Output image. */ VImage scRGB2XYZ(VOption *options = nullptr) const; /** * Convert scrgb to srgb. * * **Optional parameters** * - **depth** -- Output device space depth in bits, int. * * @param options Set of options. * @return Output image. */ VImage scRGB2sRGB(VOption *options = nullptr) const; /** * Scale an image to uchar. * * **Optional parameters** * - **exp** -- Exponent for log scale, double. * - **log** -- Log scale, bool. * * @param options Set of options. * @return Output image. */ VImage scale(VOption *options = nullptr) const; /** * Scharr edge detector. * @param options Set of options. * @return Output image. */ VImage scharr(VOption *options = nullptr) const; /** * Create an sdf image. * * **Optional parameters** * - **r** -- Radius, double. * - **a** -- Point a, std::vector. * - **b** -- Point b, std::vector. * - **corners** -- Corner radii, std::vector. * * @param width Image width in pixels. * @param height Image height in pixels. * @param shape SDF shape to create. * @param options Set of options. * @return Output image. */ static VImage sdf(int width, int height, VipsSdfShape shape, VOption *options = nullptr); /** * Check sequential access. * * **Optional parameters** * - **tile_height** -- Tile height in pixels, int. * * @param options Set of options. * @return Output image. */ VImage sequential(VOption *options = nullptr) const; /** * Unsharp masking for print. * * **Optional parameters** * - **sigma** -- Sigma of Gaussian, double. * - **x1** -- Flat/jaggy threshold, double. * - **y2** -- Maximum brightening, double. * - **y3** -- Maximum darkening, double. * - **m1** -- Slope for flat areas, double. * - **m2** -- Slope for jaggy areas, double. * * @param options Set of options. * @return Output image. */ VImage sharpen(VOption *options = nullptr) const; /** * Shrink an image. * * **Optional parameters** * - **ceil** -- Round-up output dimensions, bool. * * @param hshrink Horizontal shrink factor. * @param vshrink Vertical shrink factor. * @param options Set of options. * @return Output image. */ VImage shrink(double hshrink, double vshrink, VOption *options = nullptr) const; /** * Shrink an image horizontally. * * **Optional parameters** * - **ceil** -- Round-up output dimensions, bool. * * @param hshrink Horizontal shrink factor. * @param options Set of options. * @return Output image. */ VImage shrinkh(int hshrink, VOption *options = nullptr) const; /** * Shrink an image vertically. * * **Optional parameters** * - **ceil** -- Round-up output dimensions, bool. * * @param vshrink Vertical shrink factor. * @param options Set of options. * @return Output image. */ VImage shrinkv(int vshrink, VOption *options = nullptr) const; /** * Unit vector of pixel. * @param options Set of options. * @return Output image. */ VImage sign(VOption *options = nullptr) const; /** * Similarity transform of an image. * * **Optional parameters** * - **scale** -- Scale by this factor, double. * - **angle** -- Rotate clockwise by this many degrees, double. * - **interpolate** -- Interpolate pixels with this, VInterpolate. * - **background** -- Background value, std::vector. * - **odx** -- Horizontal output displacement, double. * - **ody** -- Vertical output displacement, double. * - **idx** -- Horizontal input displacement, double. * - **idy** -- Vertical input displacement, double. * * @param options Set of options. * @return Output image. */ VImage similarity(VOption *options = nullptr) const; /** * Make a 2d sine wave. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * - **hfreq** -- Horizontal spatial frequency, double. * - **vfreq** -- Vertical spatial frequency, double. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage sines(int width, int height, VOption *options = nullptr); /** * Extract an area from an image. * * **Optional parameters** * - **interesting** -- How to measure interestingness, VipsInteresting. * - **premultiplied** -- Input image already has premultiplied alpha, bool. * * @param width Width of extract area. * @param height Height of extract area. * @param options Set of options. * @return Output image. */ VImage smartcrop(int width, int height, VOption *options = nullptr) const; /** * Sobel edge detector. * @param options Set of options. * @return Output image. */ VImage sobel(VOption *options = nullptr) const; /** * Spatial correlation. * @param ref Input reference image. * @param options Set of options. * @return Output image. */ VImage spcor(VImage ref, VOption *options = nullptr) const; /** * Make displayable power spectrum. * @param options Set of options. * @return Output image. */ VImage spectrum(VOption *options = nullptr) const; /** * Find many image stats. * @param options Set of options. * @return Output array of statistics. */ VImage stats(VOption *options = nullptr) const; /** * Statistical difference. * * **Optional parameters** * - **s0** -- New deviation, double. * - **b** -- Weight of new deviation, double. * - **m0** -- New mean, double. * - **a** -- Weight of new mean, double. * * @param width Window width in pixels. * @param height Window height in pixels. * @param options Set of options. * @return Output image. */ VImage stdif(int width, int height, VOption *options = nullptr) const; /** * Subsample an image. * * **Optional parameters** * - **point** -- Point sample, bool. * * @param xfac Horizontal subsample factor. * @param yfac Vertical subsample factor. * @param options Set of options. * @return Output image. */ VImage subsample(int xfac, int yfac, VOption *options = nullptr) const; /** * Subtract two images. * @param right Right-hand image argument. * @param options Set of options. * @return Output image. */ VImage subtract(VImage right, VOption *options = nullptr) const; /** * Sum an array of images. * @param in Array of input images. * @param options Set of options. * @return Output image. */ static VImage sum(std::vector in, VOption *options = nullptr); /** * Load svg with rsvg. * * **Optional parameters** * - **dpi** -- Render at this DPI, double. * - **scale** -- Scale output by this factor, double. * - **unlimited** -- Allow SVG of any size, bool. * - **stylesheet** -- Custom CSS, const char *. * - **high_bitdepth** -- Enable scRGB 128-bit output (32-bit per channel), bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage svgload(const char *filename, VOption *options = nullptr); /** * Load svg with rsvg. * * **Optional parameters** * - **dpi** -- Render at this DPI, double. * - **scale** -- Scale output by this factor, double. * - **unlimited** -- Allow SVG of any size, bool. * - **stylesheet** -- Custom CSS, const char *. * - **high_bitdepth** -- Enable scRGB 128-bit output (32-bit per channel), bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage svgload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load svg from source. * * **Optional parameters** * - **dpi** -- Render at this DPI, double. * - **scale** -- Scale output by this factor, double. * - **unlimited** -- Allow SVG of any size, bool. * - **stylesheet** -- Custom CSS, const char *. * - **high_bitdepth** -- Enable scRGB 128-bit output (32-bit per channel), bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage svgload_source(VSource source, VOption *options = nullptr); /** * Find the index of the first non-zero pixel in tests. * @param tests Table of images to test. * @param options Set of options. * @return Output image. */ static VImage switch_image(std::vector tests, VOption *options = nullptr); /** * Run an external command. * * **Optional parameters** * - **in** -- Array of input images, std::vector. * - **in_format** -- Format for input filename, const char *. * - **out_format** -- Format for output filename, const char *. * - **cache** -- Cache this call, bool. * * @param cmd_format Command to run. * @param options Set of options. */ static void system(const char *cmd_format, VOption *options = nullptr); /** * Make a text image. * * **Optional parameters** * - **font** -- Font to render with, const char *. * - **width** -- Maximum image width in pixels, int. * - **height** -- Maximum image height in pixels, int. * - **align** -- Align on the low, centre or high edge, VipsAlign. * - **justify** -- Justify lines, bool. * - **dpi** -- DPI to render at, int. * - **spacing** -- Line spacing, int. * - **fontfile** -- Load this font file, const char *. * - **rgba** -- Enable RGBA output, bool. * - **wrap** -- Wrap lines on word or character boundaries, VipsTextWrap. * * @param text Text to render. * @param options Set of options. * @return Output image. */ static VImage text(const char *text, VOption *options = nullptr); /** * Generate thumbnail from file. * * **Optional parameters** * - **height** -- Size to this height, int. * - **size** -- Only upsize, only downsize, or both, VipsSize. * - **no_rotate** -- Don't use orientation tags to rotate image upright, bool. * - **crop** -- Reduce to fill target rectangle, then crop, VipsInteresting. * - **linear** -- Reduce in linear light, bool. * - **input_profile** -- Fallback input profile, const char *. * - **output_profile** -- Fallback output profile, const char *. * - **intent** -- Rendering intent, VipsIntent. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param filename Filename to read from. * @param width Size to this width. * @param options Set of options. * @return Output image. */ static VImage thumbnail(const char *filename, int width, VOption *options = nullptr); /** * Generate thumbnail from buffer. * * **Optional parameters** * - **option_string** -- Options that are passed on to the underlying loader, const char *. * - **height** -- Size to this height, int. * - **size** -- Only upsize, only downsize, or both, VipsSize. * - **no_rotate** -- Don't use orientation tags to rotate image upright, bool. * - **crop** -- Reduce to fill target rectangle, then crop, VipsInteresting. * - **linear** -- Reduce in linear light, bool. * - **input_profile** -- Fallback input profile, const char *. * - **output_profile** -- Fallback output profile, const char *. * - **intent** -- Rendering intent, VipsIntent. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param buffer Buffer to load from. * @param width Size to this width. * @param options Set of options. * @return Output image. */ static VImage thumbnail_buffer(VipsBlob *buffer, int width, VOption *options = nullptr); /** * Generate thumbnail from image. * * **Optional parameters** * - **height** -- Size to this height, int. * - **size** -- Only upsize, only downsize, or both, VipsSize. * - **no_rotate** -- Don't use orientation tags to rotate image upright, bool. * - **crop** -- Reduce to fill target rectangle, then crop, VipsInteresting. * - **linear** -- Reduce in linear light, bool. * - **input_profile** -- Fallback input profile, const char *. * - **output_profile** -- Fallback output profile, const char *. * - **intent** -- Rendering intent, VipsIntent. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param width Size to this width. * @param options Set of options. * @return Output image. */ VImage thumbnail_image(int width, VOption *options = nullptr) const; /** * Generate thumbnail from source. * * **Optional parameters** * - **option_string** -- Options that are passed on to the underlying loader, const char *. * - **height** -- Size to this height, int. * - **size** -- Only upsize, only downsize, or both, VipsSize. * - **no_rotate** -- Don't use orientation tags to rotate image upright, bool. * - **crop** -- Reduce to fill target rectangle, then crop, VipsInteresting. * - **linear** -- Reduce in linear light, bool. * - **input_profile** -- Fallback input profile, const char *. * - **output_profile** -- Fallback output profile, const char *. * - **intent** -- Rendering intent, VipsIntent. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param width Size to this width. * @param options Set of options. * @return Output image. */ static VImage thumbnail_source(VSource source, int width, VOption *options = nullptr); /** * Load tiff from file. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **autorotate** -- Rotate image using orientation tag, bool. * - **subifd** -- Subifd index, int. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage tiffload(const char *filename, VOption *options = nullptr); /** * Load tiff from buffer. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **autorotate** -- Rotate image using orientation tag, bool. * - **subifd** -- Subifd index, int. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage tiffload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load tiff from source. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **autorotate** -- Rotate image using orientation tag, bool. * - **subifd** -- Subifd index, int. * - **unlimited** -- Remove all denial of service limits, bool. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage tiffload_source(VSource source, VOption *options = nullptr); /** * Save image to tiff file. * * **Optional parameters** * - **compression** -- Compression for this file, VipsForeignTiffCompression. * - **Q** -- Q factor, int. * - **predictor** -- Compression prediction, VipsForeignTiffPredictor. * - **tile** -- Write a tiled tiff, bool. * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **pyramid** -- Write a pyramidal tiff, bool. * - **miniswhite** -- Use 0 for white in 1-bit images, bool. * - **bitdepth** -- Write as a 1, 2, 4 or 8 bit image, int. * - **resunit** -- Resolution unit, VipsForeignTiffResunit. * - **xres** -- Horizontal resolution in pixels/mm, double. * - **yres** -- Vertical resolution in pixels/mm, double. * - **bigtiff** -- Write a bigtiff image, bool. * - **properties** -- Write a properties document to IMAGEDESCRIPTION, bool. * - **region_shrink** -- Method to shrink regions, VipsRegionShrink. * - **level** -- Deflate (1-9, default 6) or ZSTD (1-22, default 9) compression level, int. * - **lossless** -- Enable WEBP lossless mode, bool. * - **depth** -- Pyramid depth, VipsForeignDzDepth. * - **subifd** -- Save pyr layers as sub-IFDs, bool. * - **premultiply** -- Save with premultiplied alpha, bool. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void tiffsave(const char *filename, VOption *options = nullptr) const; /** * Save image to tiff buffer. * * **Optional parameters** * - **compression** -- Compression for this file, VipsForeignTiffCompression. * - **Q** -- Q factor, int. * - **predictor** -- Compression prediction, VipsForeignTiffPredictor. * - **tile** -- Write a tiled tiff, bool. * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **pyramid** -- Write a pyramidal tiff, bool. * - **miniswhite** -- Use 0 for white in 1-bit images, bool. * - **bitdepth** -- Write as a 1, 2, 4 or 8 bit image, int. * - **resunit** -- Resolution unit, VipsForeignTiffResunit. * - **xres** -- Horizontal resolution in pixels/mm, double. * - **yres** -- Vertical resolution in pixels/mm, double. * - **bigtiff** -- Write a bigtiff image, bool. * - **properties** -- Write a properties document to IMAGEDESCRIPTION, bool. * - **region_shrink** -- Method to shrink regions, VipsRegionShrink. * - **level** -- Deflate (1-9, default 6) or ZSTD (1-22, default 9) compression level, int. * - **lossless** -- Enable WEBP lossless mode, bool. * - **depth** -- Pyramid depth, VipsForeignDzDepth. * - **subifd** -- Save pyr layers as sub-IFDs, bool. * - **premultiply** -- Save with premultiplied alpha, bool. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *tiffsave_buffer(VOption *options = nullptr) const; /** * Save image to tiff target. * * **Optional parameters** * - **compression** -- Compression for this file, VipsForeignTiffCompression. * - **Q** -- Q factor, int. * - **predictor** -- Compression prediction, VipsForeignTiffPredictor. * - **tile** -- Write a tiled tiff, bool. * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **pyramid** -- Write a pyramidal tiff, bool. * - **miniswhite** -- Use 0 for white in 1-bit images, bool. * - **bitdepth** -- Write as a 1, 2, 4 or 8 bit image, int. * - **resunit** -- Resolution unit, VipsForeignTiffResunit. * - **xres** -- Horizontal resolution in pixels/mm, double. * - **yres** -- Vertical resolution in pixels/mm, double. * - **bigtiff** -- Write a bigtiff image, bool. * - **properties** -- Write a properties document to IMAGEDESCRIPTION, bool. * - **region_shrink** -- Method to shrink regions, VipsRegionShrink. * - **level** -- Deflate (1-9, default 6) or ZSTD (1-22, default 9) compression level, int. * - **lossless** -- Enable WEBP lossless mode, bool. * - **depth** -- Pyramid depth, VipsForeignDzDepth. * - **subifd** -- Save pyr layers as sub-IFDs, bool. * - **premultiply** -- Save with premultiplied alpha, bool. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void tiffsave_target(VTarget target, VOption *options = nullptr) const; /** * Cache an image as a set of tiles. * * **Optional parameters** * - **tile_width** -- Tile width in pixels, int. * - **tile_height** -- Tile height in pixels, int. * - **max_tiles** -- Maximum number of tiles to cache, int. * - **access** -- Expected access pattern, VipsAccess. * - **threaded** -- Allow threaded access, bool. * - **persistent** -- Keep cache between evaluations, bool. * * @param options Set of options. * @return Output image. */ VImage tilecache(VOption *options = nullptr) const; /** * Build a look-up table. * * **Optional parameters** * - **in_max** -- Size of LUT to build, int. * - **out_max** -- Maximum value in output LUT, int. * - **Lb** -- Lowest value in output, double. * - **Lw** -- Highest value in output, double. * - **Ps** -- Position of shadow, double. * - **Pm** -- Position of mid-tones, double. * - **Ph** -- Position of highlights, double. * - **S** -- Adjust shadows by this much, double. * - **M** -- Adjust mid-tones by this much, double. * - **H** -- Adjust highlights by this much, double. * * @param options Set of options. * @return Output image. */ static VImage tonelut(VOption *options = nullptr); /** * Transpose3d an image. * * **Optional parameters** * - **page_height** -- Height of each input page, int. * * @param options Set of options. * @return Output image. */ VImage transpose3d(VOption *options = nullptr) const; /** * Transform uhdr to scrgb. * @param options Set of options. * @return Output image. */ VImage uhdr2scRGB(VOption *options = nullptr) const; /** * Load a uhdr image. * * **Optional parameters** * - **shrink** -- Shrink factor on load, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage uhdrload(const char *filename, VOption *options = nullptr); /** * Load a uhdr image. * * **Optional parameters** * - **shrink** -- Shrink factor on load, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage uhdrload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load a uhdr image. * * **Optional parameters** * - **shrink** -- Shrink factor on load, int. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage uhdrload_source(VSource source, VOption *options = nullptr); /** * Save image in ultrahdr format. * * **Optional parameters** * - **Q** -- Q factor, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void uhdrsave(const char *filename, VOption *options = nullptr) const; /** * Save image in ultrahdr format. * * **Optional parameters** * - **Q** -- Q factor, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *uhdrsave_buffer(VOption *options = nullptr) const; /** * Save image in ultrahdr format. * * **Optional parameters** * - **Q** -- Q factor, int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void uhdrsave_target(VTarget target, VOption *options = nullptr) const; /** * Unpremultiply image alpha. * * **Optional parameters** * - **max_alpha** -- Maximum value of alpha channel, double. * - **alpha_band** -- Unpremultiply with this alpha, int. * * @param options Set of options. * @return Output image. */ VImage unpremultiply(VOption *options = nullptr) const; /** * Load vips from file. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage vipsload(const char *filename, VOption *options = nullptr); /** * Load vips from source. * * **Optional parameters** * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage vipsload_source(VSource source, VOption *options = nullptr); /** * Save image to file in vips format. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void vipssave(const char *filename, VOption *options = nullptr) const; /** * Save image to target in vips format. * * **Optional parameters** * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void vipssave_target(VTarget target, VOption *options = nullptr) const; /** * Load webp from file. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **scale** -- Factor to scale by, double. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param filename Filename to load from. * @param options Set of options. * @return Output image. */ static VImage webpload(const char *filename, VOption *options = nullptr); /** * Load webp from buffer. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **scale** -- Factor to scale by, double. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * - **revalidate** -- Don't use a cached result for this operation, bool. * * @param buffer Buffer to load from. * @param options Set of options. * @return Output image. */ static VImage webpload_buffer(VipsBlob *buffer, VOption *options = nullptr); /** * Load webp from source. * * **Optional parameters** * - **page** -- First page to load, int. * - **n** -- Number of pages to load, -1 for all, int. * - **scale** -- Factor to scale by, double. * - **memory** -- Force open via memory, bool. * - **access** -- Required access pattern for this file, VipsAccess. * - **fail_on** -- Error level to fail on, VipsFailOn. * * @param source Source to load from. * @param options Set of options. * @return Output image. */ static VImage webpload_source(VSource source, VOption *options = nullptr); /** * Save as webp. * * **Optional parameters** * - **Q** -- Q factor, int. * - **lossless** -- Enable lossless compression, bool. * - **exact** -- Preserve color values from transparent pixels, bool. * - **preset** -- Preset for lossy compression, VipsForeignWebpPreset. * - **smart_subsample** -- Enable high quality chroma subsampling, bool. * - **near_lossless** -- Enable preprocessing in lossless mode (uses Q), bool. * - **alpha_q** -- Change alpha plane fidelity for lossy compression, int. * - **min_size** -- Optimise for minimum size, bool. * - **kmin** -- Minimum number of frames between key frames, int. * - **kmax** -- Maximum number of frames between key frames, int. * - **effort** -- Level of CPU effort to reduce file size, int. * - **target_size** -- Desired target size in bytes, int. * - **mixed** -- Allow mixed encoding (might reduce file size), bool. * - **smart_deblock** -- Enable auto-adjusting of the deblocking filter, bool. * - **passes** -- Number of entropy-analysis passes (in [1..10]), int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param filename Filename to save to. * @param options Set of options. */ void webpsave(const char *filename, VOption *options = nullptr) const; /** * Save as webp. * * **Optional parameters** * - **Q** -- Q factor, int. * - **lossless** -- Enable lossless compression, bool. * - **exact** -- Preserve color values from transparent pixels, bool. * - **preset** -- Preset for lossy compression, VipsForeignWebpPreset. * - **smart_subsample** -- Enable high quality chroma subsampling, bool. * - **near_lossless** -- Enable preprocessing in lossless mode (uses Q), bool. * - **alpha_q** -- Change alpha plane fidelity for lossy compression, int. * - **min_size** -- Optimise for minimum size, bool. * - **kmin** -- Minimum number of frames between key frames, int. * - **kmax** -- Maximum number of frames between key frames, int. * - **effort** -- Level of CPU effort to reduce file size, int. * - **target_size** -- Desired target size in bytes, int. * - **mixed** -- Allow mixed encoding (might reduce file size), bool. * - **smart_deblock** -- Enable auto-adjusting of the deblocking filter, bool. * - **passes** -- Number of entropy-analysis passes (in [1..10]), int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. * @return Buffer to save to. */ VipsBlob *webpsave_buffer(VOption *options = nullptr) const; /** * Save image to webp mime. * * **Optional parameters** * - **Q** -- Q factor, int. * - **lossless** -- Enable lossless compression, bool. * - **exact** -- Preserve color values from transparent pixels, bool. * - **preset** -- Preset for lossy compression, VipsForeignWebpPreset. * - **smart_subsample** -- Enable high quality chroma subsampling, bool. * - **near_lossless** -- Enable preprocessing in lossless mode (uses Q), bool. * - **alpha_q** -- Change alpha plane fidelity for lossy compression, int. * - **min_size** -- Optimise for minimum size, bool. * - **kmin** -- Minimum number of frames between key frames, int. * - **kmax** -- Maximum number of frames between key frames, int. * - **effort** -- Level of CPU effort to reduce file size, int. * - **target_size** -- Desired target size in bytes, int. * - **mixed** -- Allow mixed encoding (might reduce file size), bool. * - **smart_deblock** -- Enable auto-adjusting of the deblocking filter, bool. * - **passes** -- Number of entropy-analysis passes (in [1..10]), int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param options Set of options. */ void webpsave_mime(VOption *options = nullptr) const; /** * Save as webp. * * **Optional parameters** * - **Q** -- Q factor, int. * - **lossless** -- Enable lossless compression, bool. * - **exact** -- Preserve color values from transparent pixels, bool. * - **preset** -- Preset for lossy compression, VipsForeignWebpPreset. * - **smart_subsample** -- Enable high quality chroma subsampling, bool. * - **near_lossless** -- Enable preprocessing in lossless mode (uses Q), bool. * - **alpha_q** -- Change alpha plane fidelity for lossy compression, int. * - **min_size** -- Optimise for minimum size, bool. * - **kmin** -- Minimum number of frames between key frames, int. * - **kmax** -- Maximum number of frames between key frames, int. * - **effort** -- Level of CPU effort to reduce file size, int. * - **target_size** -- Desired target size in bytes, int. * - **mixed** -- Allow mixed encoding (might reduce file size), bool. * - **smart_deblock** -- Enable auto-adjusting of the deblocking filter, bool. * - **passes** -- Number of entropy-analysis passes (in [1..10]), int. * - **keep** -- Which metadata to retain, VipsForeignKeep. * - **background** -- Background value, std::vector. * - **page_height** -- Set page height for multipage save, int. * - **profile** -- Filename of ICC profile to embed, const char *. * * @param target Target to save to. * @param options Set of options. */ void webpsave_target(VTarget target, VOption *options = nullptr) const; /** * Make a worley noise image. * * **Optional parameters** * - **cell_size** -- Size of Worley cells, int. * - **seed** -- Random number seed, int. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage worley(int width, int height, VOption *options = nullptr); /** * Wrap image origin. * * **Optional parameters** * - **x** -- Left edge of input in output, int. * - **y** -- Top edge of input in output, int. * * @param options Set of options. * @return Output image. */ VImage wrap(VOption *options = nullptr) const; /** * Make an image where pixel values are coordinates. * * **Optional parameters** * - **csize** -- Size of third dimension, int. * - **dsize** -- Size of fourth dimension, int. * - **esize** -- Size of fifth dimension, int. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage xyz(int width, int height, VOption *options = nullptr); /** * Make a zone plate. * * **Optional parameters** * - **uchar** -- Output an unsigned char image, bool. * * @param width Image width in pixels. * @param height Image height in pixels. * @param options Set of options. * @return Output image. */ static VImage zone(int width, int height, VOption *options = nullptr); /** * Zoom an image. * @param xfac Horizontal zoom factor. * @param yfac Vertical zoom factor. * @param options Set of options. * @return Output image. */ VImage zoom(int xfac, int yfac, VOption *options = nullptr) const; }; VIPS_NAMESPACE_END #endif /*VIPS_VIMAGE_H*/ libvips-8.18.2/cplusplus/include/vips/VInterpolate8.h000066400000000000000000000037701516303661500226120ustar00rootroot00000000000000// VIPS interpolate wrapper /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VINTERPOLATE_H #define VIPS_VINTERPOLATE_H #include VIPS_NAMESPACE_START /** * An interpolation. You can pass one of these to something like * VImage::affine for it to use to interpolate pixels. * * The available interpolators vary a bit with your libvips version and how it * was built, but will include `nearest`, `bilinear` and `bicubic`. Run * vips -l interpolate` to see them all. */ class VInterpolate : public VObject { public: /** * Create a VInterpolate that wraps a VipsInterpolate object. If steal * is STEAL, then this VInterpolate takes over ownership of the libvips * object and will automatically unref it. */ explicit VInterpolate(VipsInterpolate *interpolate, VSteal steal = STEAL) : VObject((VipsObject *) interpolate, steal) { } /** * Create a VInterpolate from a name, for example `"bicubic"`. */ static VInterpolate new_from_name(const char *name, VOption *options = nullptr); /** * Get a pointer to the underlying VipsInterpolate object. */ VipsInterpolate * get_interpolate() const { return (VipsInterpolate *) VObject::get_object(); } }; VIPS_NAMESPACE_END #endif /*VIPS_VINTERPOLATE_H*/ libvips-8.18.2/cplusplus/include/vips/VRegion8.h000066400000000000000000000055761516303661500215550ustar00rootroot00000000000000// VIPS region wrapper /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VREGION_H #define VIPS_VREGION_H #include VIPS_NAMESPACE_START /** * A region of an image. Can be used to access raw pixel data. * */ class VRegion : public VObject { public: /** * Create a VRegion that wraps a VipsRegion object. If steal * is STEAL, then this VRegion takes over ownership of the libvips * object and will automatically unref it. */ explicit VRegion(VipsRegion *region, VSteal steal = STEAL) : VObject((VipsObject *) region, steal) { } /** * Create a VRegion from an image. */ static VRegion new_from_image(VImage image); /** * Get a pointer to the underlying VipsRegion object. */ VipsRegion * get_region() const { return (VipsRegion *) VObject::get_object(); } /** * Prepare the region from VipsRect. */ void prepare(const VipsRect *rect) const { if (vips_region_prepare(get_region(), rect)) throw VError(); } /** * Prepare the region from rectangle coordinates. */ void prepare(int left, int top, int width, int height) const { VipsRect rect = { left, top, width, height }; prepare(&rect); } /** * Get valid bounds of the region. */ VipsRect valid() const { return get_region()->valid; } /** * Get pointer to the start of the region. */ VipsPel * addr() const { return addr(0); } /** * Get pointer at the given index of the region. */ VipsPel * addr(size_t i) const { return &VIPS_REGION_ADDR_TOPLEFT(get_region())[i]; } /** * Get pointer at the given coordinates of the region. */ VipsPel * addr(int x, int y) const { return VIPS_REGION_ADDR(get_region(), x, y); } /** * Get the stride (bytes per row, including padding) of the region. */ size_t stride() const { return VIPS_REGION_LSKIP(get_region()); } /** * Get VipsPel at the given index of the region. */ VipsPel operator[](size_t i) const { return *addr(i); } /** * Get VipsPel at the given coordinates of the region. */ VipsPel operator()(int x, int y) const { return *addr(x, y); } }; VIPS_NAMESPACE_END #endif /*VIPS_VREGION_H*/ libvips-8.18.2/cplusplus/include/vips/meson.build000066400000000000000000000003771516303661500220770ustar00rootroot00000000000000public_cpp_headers = files( 'VError8.h', 'VImage8.h', 'VInterpolate8.h', 'VRegion8.h', 'VConnection8.h', 'vips8', ) install_headers( public_cpp_headers, subdir: 'vips' ) libvips_cpp_includedir = include_directories('..') libvips-8.18.2/cplusplus/include/vips/vips8000066400000000000000000000033571516303661500207320ustar00rootroot00000000000000// Include file to get vips C++ binding /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_CPLUSPLUS #define VIPS_CPLUSPLUS /* avoid conflict with Qt definitions, if they exist */ #if defined(signals) && defined(Q_SIGNALS) #define _VIPS_QT_SIGNALS_DEFINED #undef signals #endif #include #include /* Note: when building without Meson, it may be necessary to define * _VIPS_PUBLIC as __declspec(dllexport) when building a DLL. */ #ifndef _VIPS_PUBLIC #define _VIPS_PUBLIC #endif #define VIPS_CPLUSPLUS_API _VIPS_PUBLIC #define VIPS_NAMESPACE_START namespace vips { #define VIPS_NAMESPACE_END } #include "VError8.h" #include "VImage8.h" #include "VInterpolate8.h" #include "VRegion8.h" #include "VConnection8.h" /* restore Qt keywords if they were disabled for GLib inclusion */ #ifdef _VIPS_QT_SIGNALS_DEFINED #define signals Q_SIGNALS #undef _VIPS_QT_SIGNALS_DEFINED #endif #endif /*VIPS_CPLUSPLUS*/ libvips-8.18.2/cplusplus/meson.build000066400000000000000000000033261516303661500174700ustar00rootroot00000000000000subdir('include/vips') libvips_cpp_lib = library('vips-cpp', 'VImage.cpp', 'VInterpolate.cpp', 'VRegion.cpp', 'VConnection.cpp', 'VError.cpp', dependencies: libvips_dep, include_directories: libvips_cpp_includedir, version: library_version, darwin_versions: darwin_versions, gnu_symbol_visibility: 'hidden', install: true, ) libvips_cpp_dep = declare_dependency( link_with: libvips_cpp_lib, dependencies: libvips_dep, include_directories: libvips_cpp_includedir, ) pkg.generate( libvips_cpp_lib, requires: [ libvips_lib, glib_dep, gobject_dep ], name: 'vips-cpp', description: 'C++ API for vips8 image processing library', ) custom_target('vips-operators-header', command: [ 'gen-operators.py', '-g', 'h'], capture: true, output: 'vips-operators.h' ) custom_target('vips-operators-source', command: [ 'gen-operators.py', '-g', 'cpp'], capture: true, output: 'vips-operators.cpp' ) if get_option('cpp-docs') doxygen = find_program('doxygen') doxygen_data = configuration_data() doxygen_data.set('VIPS_MAJOR_VERSION', version_major) doxygen_data.set('VIPS_MINOR_VERSION', version_minor) doxygen_data.set('DOXY_INPUT_DIRECTORY', meson.current_source_dir()) doxygen_data.set('DOXY_OUTPUT_DIRECTORY', 'cplusplus') doxyfile = configure_file( input: 'Doxyfile.in', output: 'Doxyfile', configuration: doxygen_data, install: false ) html_target = custom_target('vips-cpp-docs', input: doxyfile, output: 'html', command: [doxygen, doxyfile], install: true, install_dir: get_option('prefix') / get_option('datadir') / 'doc' / 'vips-cpp' ) endif libvips-8.18.2/cplusplus/vips-operators.cpp000066400000000000000000002210401516303661500210220ustar00rootroot00000000000000// bodies for vips operations // this file is generated automatically, do not edit! // clang-format off VImage VImage::CMC2LCh(VOption *options) const { VImage out; call("CMC2LCh", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::CMYK2XYZ(VOption *options) const { VImage out; call("CMYK2XYZ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::HSV2sRGB(VOption *options) const { VImage out; call("HSV2sRGB", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LCh2CMC(VOption *options) const { VImage out; call("LCh2CMC", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LCh2Lab(VOption *options) const { VImage out; call("LCh2Lab", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Lab2LCh(VOption *options) const { VImage out; call("Lab2LCh", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Lab2LabQ(VOption *options) const { VImage out; call("Lab2LabQ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Lab2LabS(VOption *options) const { VImage out; call("Lab2LabS", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Lab2XYZ(VOption *options) const { VImage out; call("Lab2XYZ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LabQ2Lab(VOption *options) const { VImage out; call("LabQ2Lab", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LabQ2LabS(VOption *options) const { VImage out; call("LabQ2LabS", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LabQ2sRGB(VOption *options) const { VImage out; call("LabQ2sRGB", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LabS2Lab(VOption *options) const { VImage out; call("LabS2Lab", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::LabS2LabQ(VOption *options) const { VImage out; call("LabS2LabQ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Oklab2Oklch(VOption *options) const { VImage out; call("Oklab2Oklch", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Oklab2XYZ(VOption *options) const { VImage out; call("Oklab2XYZ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Oklch2Oklab(VOption *options) const { VImage out; call("Oklch2Oklab", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::XYZ2CMYK(VOption *options) const { VImage out; call("XYZ2CMYK", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::XYZ2Lab(VOption *options) const { VImage out; call("XYZ2Lab", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::XYZ2Oklab(VOption *options) const { VImage out; call("XYZ2Oklab", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::XYZ2Yxy(VOption *options) const { VImage out; call("XYZ2Yxy", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::XYZ2scRGB(VOption *options) const { VImage out; call("XYZ2scRGB", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::Yxy2XYZ(VOption *options) const { VImage out; call("Yxy2XYZ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::abs(VOption *options) const { VImage out; call("abs", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::add(VImage right, VOption *options) const { VImage out; call("add", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::addalpha(VOption *options) const { VImage out; call("addalpha", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::affine(std::vector matrix, VOption *options) const { VImage out; call("affine", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("matrix", matrix)); return out; } VImage VImage::analyzeload(const char *filename, VOption *options) { VImage out; call("analyzeload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::arrayjoin(std::vector in, VOption *options) { VImage out; call("arrayjoin", (options ? options : VImage::option()) ->set("out", &out) ->set("in", in)); return out; } VImage VImage::autorot(VOption *options) const { VImage out; call("autorot", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } double VImage::avg(VOption *options) const { double out; call("avg", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::bandbool(VipsOperationBoolean boolean, VOption *options) const { VImage out; call("bandbool", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("boolean", boolean)); return out; } VImage VImage::bandfold(VOption *options) const { VImage out; call("bandfold", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::bandjoin(std::vector in, VOption *options) { VImage out; call("bandjoin", (options ? options : VImage::option()) ->set("out", &out) ->set("in", in)); return out; } VImage VImage::bandjoin_const(std::vector c, VOption *options) const { VImage out; call("bandjoin_const", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("c", c)); return out; } VImage VImage::bandmean(VOption *options) const { VImage out; call("bandmean", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::bandrank(std::vector in, VOption *options) { VImage out; call("bandrank", (options ? options : VImage::option()) ->set("out", &out) ->set("in", in)); return out; } VImage VImage::bandunfold(VOption *options) const { VImage out; call("bandunfold", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::black(int width, int height, VOption *options) { VImage out; call("black", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::boolean(VImage right, VipsOperationBoolean boolean, VOption *options) const { VImage out; call("boolean", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right) ->set("boolean", boolean)); return out; } VImage VImage::boolean_const(VipsOperationBoolean boolean, std::vector c, VOption *options) const { VImage out; call("boolean_const", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("boolean", boolean) ->set("c", c)); return out; } VImage VImage::buildlut(VOption *options) const { VImage out; call("buildlut", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::byteswap(VOption *options) const { VImage out; call("byteswap", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::cache(VOption *options) const { VImage out; call("cache", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::canny(VOption *options) const { VImage out; call("canny", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::case_image(std::vector cases, VOption *options) const { VImage out; call("case", (options ? options : VImage::option()) ->set("index", *this) ->set("out", &out) ->set("cases", cases)); return out; } VImage VImage::cast(VipsBandFormat format, VOption *options) const { VImage out; call("cast", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("format", format)); return out; } VImage VImage::clamp(VOption *options) const { VImage out; call("clamp", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::colourspace(VipsInterpretation space, VOption *options) const { VImage out; call("colourspace", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("space", space)); return out; } VImage VImage::compass(VImage mask, VOption *options) const { VImage out; call("compass", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::complex(VipsOperationComplex cmplx, VOption *options) const { VImage out; call("complex", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("cmplx", cmplx)); return out; } VImage VImage::complex2(VImage right, VipsOperationComplex2 cmplx, VOption *options) const { VImage out; call("complex2", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right) ->set("cmplx", cmplx)); return out; } VImage VImage::complexform(VImage right, VOption *options) const { VImage out; call("complexform", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::complexget(VipsOperationComplexget get, VOption *options) const { VImage out; call("complexget", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("get", get)); return out; } VImage VImage::composite(std::vector in, std::vector mode, VOption *options) { VImage out; call("composite", (options ? options : VImage::option()) ->set("out", &out) ->set("in", in) ->set("mode", mode)); return out; } VImage VImage::composite2(VImage overlay, VipsBlendMode mode, VOption *options) const { VImage out; call("composite2", (options ? options : VImage::option()) ->set("base", *this) ->set("out", &out) ->set("overlay", overlay) ->set("mode", mode)); return out; } VImage VImage::conv(VImage mask, VOption *options) const { VImage out; call("conv", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::conva(VImage mask, VOption *options) const { VImage out; call("conva", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::convasep(VImage mask, VOption *options) const { VImage out; call("convasep", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::convf(VImage mask, VOption *options) const { VImage out; call("convf", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::convi(VImage mask, VOption *options) const { VImage out; call("convi", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::convsep(VImage mask, VOption *options) const { VImage out; call("convsep", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::copy(VOption *options) const { VImage out; call("copy", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } double VImage::countlines(VipsDirection direction, VOption *options) const { double nolines; call("countlines", (options ? options : VImage::option()) ->set("in", *this) ->set("nolines", &nolines) ->set("direction", direction)); return nolines; } VImage VImage::crop(int left, int top, int width, int height, VOption *options) const { VImage out; call("crop", (options ? options : VImage::option()) ->set("input", *this) ->set("out", &out) ->set("left", left) ->set("top", top) ->set("width", width) ->set("height", height)); return out; } VImage VImage::csvload(const char *filename, VOption *options) { VImage out; call("csvload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::csvload_source(VSource source, VOption *options) { VImage out; call("csvload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::csvsave(const char *filename, VOption *options) const { call("csvsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } void VImage::csvsave_target(VTarget target, VOption *options) const { call("csvsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::dE00(VImage right, VOption *options) const { VImage out; call("dE00", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::dE76(VImage right, VOption *options) const { VImage out; call("dE76", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::dECMC(VImage right, VOption *options) const { VImage out; call("dECMC", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::dcrawload(const char *filename, VOption *options) { VImage out; call("dcrawload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::dcrawload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("dcrawload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::dcrawload_source(VSource source, VOption *options) { VImage out; call("dcrawload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } double VImage::deviate(VOption *options) const { double out; call("deviate", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::divide(VImage right, VOption *options) const { VImage out; call("divide", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } void VImage::draw_circle(std::vector ink, int cx, int cy, int radius, VOption *options) const { call("draw_circle", (options ? options : VImage::option()) ->set("image", *this) ->set("ink", ink) ->set("cx", cx) ->set("cy", cy) ->set("radius", radius)); } void VImage::draw_flood(std::vector ink, int x, int y, VOption *options) const { call("draw_flood", (options ? options : VImage::option()) ->set("image", *this) ->set("ink", ink) ->set("x", x) ->set("y", y)); } void VImage::draw_image(VImage sub, int x, int y, VOption *options) const { call("draw_image", (options ? options : VImage::option()) ->set("image", *this) ->set("sub", sub) ->set("x", x) ->set("y", y)); } void VImage::draw_line(std::vector ink, int x1, int y1, int x2, int y2, VOption *options) const { call("draw_line", (options ? options : VImage::option()) ->set("image", *this) ->set("ink", ink) ->set("x1", x1) ->set("y1", y1) ->set("x2", x2) ->set("y2", y2)); } void VImage::draw_mask(std::vector ink, VImage mask, int x, int y, VOption *options) const { call("draw_mask", (options ? options : VImage::option()) ->set("image", *this) ->set("ink", ink) ->set("mask", mask) ->set("x", x) ->set("y", y)); } void VImage::draw_rect(std::vector ink, int left, int top, int width, int height, VOption *options) const { call("draw_rect", (options ? options : VImage::option()) ->set("image", *this) ->set("ink", ink) ->set("left", left) ->set("top", top) ->set("width", width) ->set("height", height)); } void VImage::draw_smudge(int left, int top, int width, int height, VOption *options) const { call("draw_smudge", (options ? options : VImage::option()) ->set("image", *this) ->set("left", left) ->set("top", top) ->set("width", width) ->set("height", height)); } void VImage::dzsave(const char *filename, VOption *options) const { call("dzsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::dzsave_buffer(VOption *options) const { VipsBlob *buffer; call("dzsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::dzsave_target(VTarget target, VOption *options) const { call("dzsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::embed(int x, int y, int width, int height, VOption *options) const { VImage out; call("embed", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("x", x) ->set("y", y) ->set("width", width) ->set("height", height)); return out; } VImage VImage::extract_area(int left, int top, int width, int height, VOption *options) const { VImage out; call("extract_area", (options ? options : VImage::option()) ->set("input", *this) ->set("out", &out) ->set("left", left) ->set("top", top) ->set("width", width) ->set("height", height)); return out; } VImage VImage::extract_band(int band, VOption *options) const { VImage out; call("extract_band", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("band", band)); return out; } VImage VImage::eye(int width, int height, VOption *options) { VImage out; call("eye", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::falsecolour(VOption *options) const { VImage out; call("falsecolour", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::fastcor(VImage ref, VOption *options) const { VImage out; call("fastcor", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("ref", ref)); return out; } VImage VImage::fill_nearest(VOption *options) const { VImage out; call("fill_nearest", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } int VImage::find_trim(int *top, int *width, int *height, VOption *options) const { int left; call("find_trim", (options ? options : VImage::option()) ->set("in", *this) ->set("left", &left) ->set("top", top) ->set("width", width) ->set("height", height)); return left; } VImage VImage::fitsload(const char *filename, VOption *options) { VImage out; call("fitsload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::fitsload_source(VSource source, VOption *options) { VImage out; call("fitsload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::fitssave(const char *filename, VOption *options) const { call("fitssave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VImage VImage::flatten(VOption *options) const { VImage out; call("flatten", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::flip(VipsDirection direction, VOption *options) const { VImage out; call("flip", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("direction", direction)); return out; } VImage VImage::float2rad(VOption *options) const { VImage out; call("float2rad", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::fractsurf(int width, int height, double fractal_dimension, VOption *options) { VImage out; call("fractsurf", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("fractal_dimension", fractal_dimension)); return out; } VImage VImage::freqmult(VImage mask, VOption *options) const { VImage out; call("freqmult", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask)); return out; } VImage VImage::fwfft(VOption *options) const { VImage out; call("fwfft", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::gamma(VOption *options) const { VImage out; call("gamma", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::gaussblur(double sigma, VOption *options) const { VImage out; call("gaussblur", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("sigma", sigma)); return out; } VImage VImage::gaussmat(double sigma, double min_ampl, VOption *options) { VImage out; call("gaussmat", (options ? options : VImage::option()) ->set("out", &out) ->set("sigma", sigma) ->set("min_ampl", min_ampl)); return out; } VImage VImage::gaussnoise(int width, int height, VOption *options) { VImage out; call("gaussnoise", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } std::vector VImage::getpoint(int x, int y, VOption *options) const { std::vector out_array; call("getpoint", (options ? options : VImage::option()) ->set("in", *this) ->set("out_array", &out_array) ->set("x", x) ->set("y", y)); return out_array; } VImage VImage::gifload(const char *filename, VOption *options) { VImage out; call("gifload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::gifload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("gifload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::gifload_source(VSource source, VOption *options) { VImage out; call("gifload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::gifsave(const char *filename, VOption *options) const { call("gifsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::gifsave_buffer(VOption *options) const { VipsBlob *buffer; call("gifsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::gifsave_target(VTarget target, VOption *options) const { call("gifsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::globalbalance(VOption *options) const { VImage out; call("globalbalance", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::gravity(VipsCompassDirection direction, int width, int height, VOption *options) const { VImage out; call("gravity", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("direction", direction) ->set("width", width) ->set("height", height)); return out; } VImage VImage::grey(int width, int height, VOption *options) { VImage out; call("grey", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::grid(int tile_height, int across, int down, VOption *options) const { VImage out; call("grid", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("tile_height", tile_height) ->set("across", across) ->set("down", down)); return out; } VImage VImage::heifload(const char *filename, VOption *options) { VImage out; call("heifload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::heifload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("heifload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::heifload_source(VSource source, VOption *options) { VImage out; call("heifload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::heifsave(const char *filename, VOption *options) const { call("heifsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::heifsave_buffer(VOption *options) const { VipsBlob *buffer; call("heifsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::heifsave_target(VTarget target, VOption *options) const { call("heifsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::hist_cum(VOption *options) const { VImage out; call("hist_cum", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } double VImage::hist_entropy(VOption *options) const { double out; call("hist_entropy", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::hist_equal(VOption *options) const { VImage out; call("hist_equal", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::hist_find(VOption *options) const { VImage out; call("hist_find", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::hist_find_indexed(VImage index, VOption *options) const { VImage out; call("hist_find_indexed", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("index", index)); return out; } VImage VImage::hist_find_ndim(VOption *options) const { VImage out; call("hist_find_ndim", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } bool VImage::hist_ismonotonic(VOption *options) const { bool monotonic; call("hist_ismonotonic", (options ? options : VImage::option()) ->set("in", *this) ->set("monotonic", &monotonic)); return monotonic; } VImage VImage::hist_local(int width, int height, VOption *options) const { VImage out; call("hist_local", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::hist_match(VImage ref, VOption *options) const { VImage out; call("hist_match", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("ref", ref)); return out; } VImage VImage::hist_norm(VOption *options) const { VImage out; call("hist_norm", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::hist_plot(VOption *options) const { VImage out; call("hist_plot", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::hough_circle(VOption *options) const { VImage out; call("hough_circle", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::hough_line(VOption *options) const { VImage out; call("hough_line", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::icc_export(VOption *options) const { VImage out; call("icc_export", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::icc_import(VOption *options) const { VImage out; call("icc_import", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::icc_transform(const char *output_profile, VOption *options) const { VImage out; call("icc_transform", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("output_profile", output_profile)); return out; } VImage VImage::identity(VOption *options) { VImage out; call("identity", (options ? options : VImage::option()) ->set("out", &out)); return out; } VImage VImage::ifthenelse(VImage in1, VImage in2, VOption *options) const { VImage out; call("ifthenelse", (options ? options : VImage::option()) ->set("cond", *this) ->set("out", &out) ->set("in1", in1) ->set("in2", in2)); return out; } VImage VImage::insert(VImage sub, int x, int y, VOption *options) const { VImage out; call("insert", (options ? options : VImage::option()) ->set("main", *this) ->set("out", &out) ->set("sub", sub) ->set("x", x) ->set("y", y)); return out; } VImage VImage::invert(VOption *options) const { VImage out; call("invert", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::invertlut(VOption *options) const { VImage out; call("invertlut", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::invfft(VOption *options) const { VImage out; call("invfft", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::join(VImage in2, VipsDirection direction, VOption *options) const { VImage out; call("join", (options ? options : VImage::option()) ->set("in1", *this) ->set("out", &out) ->set("in2", in2) ->set("direction", direction)); return out; } VImage VImage::jp2kload(const char *filename, VOption *options) { VImage out; call("jp2kload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::jp2kload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("jp2kload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::jp2kload_source(VSource source, VOption *options) { VImage out; call("jp2kload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::jp2ksave(const char *filename, VOption *options) const { call("jp2ksave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::jp2ksave_buffer(VOption *options) const { VipsBlob *buffer; call("jp2ksave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::jp2ksave_target(VTarget target, VOption *options) const { call("jp2ksave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::jpegload(const char *filename, VOption *options) { VImage out; call("jpegload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::jpegload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("jpegload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::jpegload_source(VSource source, VOption *options) { VImage out; call("jpegload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::jpegsave(const char *filename, VOption *options) const { call("jpegsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::jpegsave_buffer(VOption *options) const { VipsBlob *buffer; call("jpegsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::jpegsave_mime(VOption *options) const { call("jpegsave_mime", (options ? options : VImage::option()) ->set("in", *this)); } void VImage::jpegsave_target(VTarget target, VOption *options) const { call("jpegsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::jxlload(const char *filename, VOption *options) { VImage out; call("jxlload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::jxlload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("jxlload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::jxlload_source(VSource source, VOption *options) { VImage out; call("jxlload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::jxlsave(const char *filename, VOption *options) const { call("jxlsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::jxlsave_buffer(VOption *options) const { VipsBlob *buffer; call("jxlsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::jxlsave_target(VTarget target, VOption *options) const { call("jxlsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::labelregions(VOption *options) const { VImage mask; call("labelregions", (options ? options : VImage::option()) ->set("in", *this) ->set("mask", &mask)); return mask; } VImage VImage::linear(std::vector a, std::vector b, VOption *options) const { VImage out; call("linear", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("a", a) ->set("b", b)); return out; } VImage VImage::linecache(VOption *options) const { VImage out; call("linecache", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::logmat(double sigma, double min_ampl, VOption *options) { VImage out; call("logmat", (options ? options : VImage::option()) ->set("out", &out) ->set("sigma", sigma) ->set("min_ampl", min_ampl)); return out; } VImage VImage::magickload(const char *filename, VOption *options) { VImage out; call("magickload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::magickload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("magickload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::magickload_source(VSource source, VOption *options) { VImage out; call("magickload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::magicksave(const char *filename, VOption *options) const { call("magicksave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::magicksave_buffer(VOption *options) const { VipsBlob *buffer; call("magicksave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } VImage VImage::mapim(VImage index, VOption *options) const { VImage out; call("mapim", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("index", index)); return out; } VImage VImage::maplut(VImage lut, VOption *options) const { VImage out; call("maplut", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("lut", lut)); return out; } VImage VImage::mask_butterworth(int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, VOption *options) { VImage out; call("mask_butterworth", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("order", order) ->set("frequency_cutoff", frequency_cutoff) ->set("amplitude_cutoff", amplitude_cutoff)); return out; } VImage VImage::mask_butterworth_band(int width, int height, double order, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, VOption *options) { VImage out; call("mask_butterworth_band", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("order", order) ->set("frequency_cutoff_x", frequency_cutoff_x) ->set("frequency_cutoff_y", frequency_cutoff_y) ->set("radius", radius) ->set("amplitude_cutoff", amplitude_cutoff)); return out; } VImage VImage::mask_butterworth_ring(int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, double ringwidth, VOption *options) { VImage out; call("mask_butterworth_ring", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("order", order) ->set("frequency_cutoff", frequency_cutoff) ->set("amplitude_cutoff", amplitude_cutoff) ->set("ringwidth", ringwidth)); return out; } VImage VImage::mask_fractal(int width, int height, double fractal_dimension, VOption *options) { VImage out; call("mask_fractal", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("fractal_dimension", fractal_dimension)); return out; } VImage VImage::mask_gaussian(int width, int height, double frequency_cutoff, double amplitude_cutoff, VOption *options) { VImage out; call("mask_gaussian", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("frequency_cutoff", frequency_cutoff) ->set("amplitude_cutoff", amplitude_cutoff)); return out; } VImage VImage::mask_gaussian_band(int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, VOption *options) { VImage out; call("mask_gaussian_band", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("frequency_cutoff_x", frequency_cutoff_x) ->set("frequency_cutoff_y", frequency_cutoff_y) ->set("radius", radius) ->set("amplitude_cutoff", amplitude_cutoff)); return out; } VImage VImage::mask_gaussian_ring(int width, int height, double frequency_cutoff, double amplitude_cutoff, double ringwidth, VOption *options) { VImage out; call("mask_gaussian_ring", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("frequency_cutoff", frequency_cutoff) ->set("amplitude_cutoff", amplitude_cutoff) ->set("ringwidth", ringwidth)); return out; } VImage VImage::mask_ideal(int width, int height, double frequency_cutoff, VOption *options) { VImage out; call("mask_ideal", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("frequency_cutoff", frequency_cutoff)); return out; } VImage VImage::mask_ideal_band(int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, VOption *options) { VImage out; call("mask_ideal_band", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("frequency_cutoff_x", frequency_cutoff_x) ->set("frequency_cutoff_y", frequency_cutoff_y) ->set("radius", radius)); return out; } VImage VImage::mask_ideal_ring(int width, int height, double frequency_cutoff, double ringwidth, VOption *options) { VImage out; call("mask_ideal_ring", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("frequency_cutoff", frequency_cutoff) ->set("ringwidth", ringwidth)); return out; } VImage VImage::match(VImage sec, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, VOption *options) const { VImage out; call("match", (options ? options : VImage::option()) ->set("ref", *this) ->set("out", &out) ->set("sec", sec) ->set("xr1", xr1) ->set("yr1", yr1) ->set("xs1", xs1) ->set("ys1", ys1) ->set("xr2", xr2) ->set("yr2", yr2) ->set("xs2", xs2) ->set("ys2", ys2)); return out; } VImage VImage::math(VipsOperationMath math, VOption *options) const { VImage out; call("math", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("math", math)); return out; } VImage VImage::math2(VImage right, VipsOperationMath2 math2, VOption *options) const { VImage out; call("math2", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right) ->set("math2", math2)); return out; } VImage VImage::math2_const(VipsOperationMath2 math2, std::vector c, VOption *options) const { VImage out; call("math2_const", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("math2", math2) ->set("c", c)); return out; } VImage VImage::matload(const char *filename, VOption *options) { VImage out; call("matload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::matrixinvert(VOption *options) const { VImage out; call("matrixinvert", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::matrixload(const char *filename, VOption *options) { VImage out; call("matrixload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::matrixload_source(VSource source, VOption *options) { VImage out; call("matrixload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } VImage VImage::matrixmultiply(VImage right, VOption *options) const { VImage out; call("matrixmultiply", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } void VImage::matrixprint(VOption *options) const { call("matrixprint", (options ? options : VImage::option()) ->set("in", *this)); } void VImage::matrixsave(const char *filename, VOption *options) const { call("matrixsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } void VImage::matrixsave_target(VTarget target, VOption *options) const { call("matrixsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } double VImage::max(VOption *options) const { double out; call("max", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::maxpair(VImage right, VOption *options) const { VImage out; call("maxpair", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::measure(int h, int v, VOption *options) const { VImage out; call("measure", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("h", h) ->set("v", v)); return out; } VImage VImage::merge(VImage sec, VipsDirection direction, int dx, int dy, VOption *options) const { VImage out; call("merge", (options ? options : VImage::option()) ->set("ref", *this) ->set("out", &out) ->set("sec", sec) ->set("direction", direction) ->set("dx", dx) ->set("dy", dy)); return out; } double VImage::min(VOption *options) const { double out; call("min", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::minpair(VImage right, VOption *options) const { VImage out; call("minpair", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::morph(VImage mask, VipsOperationMorphology morph, VOption *options) const { VImage out; call("morph", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("mask", mask) ->set("morph", morph)); return out; } VImage VImage::mosaic(VImage sec, VipsDirection direction, int xref, int yref, int xsec, int ysec, VOption *options) const { VImage out; call("mosaic", (options ? options : VImage::option()) ->set("ref", *this) ->set("out", &out) ->set("sec", sec) ->set("direction", direction) ->set("xref", xref) ->set("yref", yref) ->set("xsec", xsec) ->set("ysec", ysec)); return out; } VImage VImage::mosaic1(VImage sec, VipsDirection direction, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, VOption *options) const { VImage out; call("mosaic1", (options ? options : VImage::option()) ->set("ref", *this) ->set("out", &out) ->set("sec", sec) ->set("direction", direction) ->set("xr1", xr1) ->set("yr1", yr1) ->set("xs1", xs1) ->set("ys1", ys1) ->set("xr2", xr2) ->set("yr2", yr2) ->set("xs2", xs2) ->set("ys2", ys2)); return out; } VImage VImage::msb(VOption *options) const { VImage out; call("msb", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::multiply(VImage right, VOption *options) const { VImage out; call("multiply", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::niftiload(const char *filename, VOption *options) { VImage out; call("niftiload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::niftiload_source(VSource source, VOption *options) { VImage out; call("niftiload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::niftisave(const char *filename, VOption *options) const { call("niftisave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VImage VImage::openexrload(const char *filename, VOption *options) { VImage out; call("openexrload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::openslideload(const char *filename, VOption *options) { VImage out; call("openslideload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::openslideload_source(VSource source, VOption *options) { VImage out; call("openslideload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } VImage VImage::pdfload(const char *filename, VOption *options) { VImage out; call("pdfload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::pdfload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("pdfload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::pdfload_source(VSource source, VOption *options) { VImage out; call("pdfload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } int VImage::percent(double percent, VOption *options) const { int threshold; call("percent", (options ? options : VImage::option()) ->set("in", *this) ->set("threshold", &threshold) ->set("percent", percent)); return threshold; } VImage VImage::perlin(int width, int height, VOption *options) { VImage out; call("perlin", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::phasecor(VImage in2, VOption *options) const { VImage out; call("phasecor", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("in2", in2)); return out; } VImage VImage::pngload(const char *filename, VOption *options) { VImage out; call("pngload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::pngload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("pngload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::pngload_source(VSource source, VOption *options) { VImage out; call("pngload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::pngsave(const char *filename, VOption *options) const { call("pngsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::pngsave_buffer(VOption *options) const { VipsBlob *buffer; call("pngsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::pngsave_target(VTarget target, VOption *options) const { call("pngsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::ppmload(const char *filename, VOption *options) { VImage out; call("ppmload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::ppmload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("ppmload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::ppmload_source(VSource source, VOption *options) { VImage out; call("ppmload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::ppmsave(const char *filename, VOption *options) const { call("ppmsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } void VImage::ppmsave_target(VTarget target, VOption *options) const { call("ppmsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::premultiply(VOption *options) const { VImage out; call("premultiply", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::prewitt(VOption *options) const { VImage out; call("prewitt", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::profile(VImage *rows, VOption *options) const { VImage columns; call("profile", (options ? options : VImage::option()) ->set("in", *this) ->set("columns", &columns) ->set("rows", rows)); return columns; } VipsBlob * VImage::profile_load(const char *name, VOption *options) { VipsBlob *profile; call("profile_load", (options ? options : VImage::option()) ->set("profile", &profile) ->set("name", name)); return profile; } VImage VImage::project(VImage *rows, VOption *options) const { VImage columns; call("project", (options ? options : VImage::option()) ->set("in", *this) ->set("columns", &columns) ->set("rows", rows)); return columns; } VImage VImage::quadratic(VImage coeff, VOption *options) const { VImage out; call("quadratic", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("coeff", coeff)); return out; } VImage VImage::rad2float(VOption *options) const { VImage out; call("rad2float", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::radload(const char *filename, VOption *options) { VImage out; call("radload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::radload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("radload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::radload_source(VSource source, VOption *options) { VImage out; call("radload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::radsave(const char *filename, VOption *options) const { call("radsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::radsave_buffer(VOption *options) const { VipsBlob *buffer; call("radsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::radsave_target(VTarget target, VOption *options) const { call("radsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::rank(int width, int height, int index, VOption *options) const { VImage out; call("rank", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("index", index)); return out; } VImage VImage::rawload(const char *filename, int width, int height, int bands, VOption *options) { VImage out; call("rawload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename) ->set("width", width) ->set("height", height) ->set("bands", bands)); return out; } void VImage::rawsave(const char *filename, VOption *options) const { call("rawsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::rawsave_buffer(VOption *options) const { VipsBlob *buffer; call("rawsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::rawsave_target(VTarget target, VOption *options) const { call("rawsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::recomb(VImage m, VOption *options) const { VImage out; call("recomb", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("m", m)); return out; } VImage VImage::reduce(double hshrink, double vshrink, VOption *options) const { VImage out; call("reduce", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("hshrink", hshrink) ->set("vshrink", vshrink)); return out; } VImage VImage::reduceh(double hshrink, VOption *options) const { VImage out; call("reduceh", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("hshrink", hshrink)); return out; } VImage VImage::reducev(double vshrink, VOption *options) const { VImage out; call("reducev", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("vshrink", vshrink)); return out; } VImage VImage::relational(VImage right, VipsOperationRelational relational, VOption *options) const { VImage out; call("relational", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right) ->set("relational", relational)); return out; } VImage VImage::relational_const(VipsOperationRelational relational, std::vector c, VOption *options) const { VImage out; call("relational_const", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("relational", relational) ->set("c", c)); return out; } VImage VImage::remainder(VImage right, VOption *options) const { VImage out; call("remainder", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::remainder_const(std::vector c, VOption *options) const { VImage out; call("remainder_const", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("c", c)); return out; } VImage VImage::remosaic(const char *old_str, const char *new_str, VOption *options) const { VImage out; call("remosaic", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("old_str", old_str) ->set("new_str", new_str)); return out; } VImage VImage::replicate(int across, int down, VOption *options) const { VImage out; call("replicate", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("across", across) ->set("down", down)); return out; } VImage VImage::resize(double scale, VOption *options) const { VImage out; call("resize", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("scale", scale)); return out; } VImage VImage::rot(VipsAngle angle, VOption *options) const { VImage out; call("rot", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("angle", angle)); return out; } VImage VImage::rot45(VOption *options) const { VImage out; call("rot45", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::rotate(double angle, VOption *options) const { VImage out; call("rotate", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("angle", angle)); return out; } VImage VImage::round(VipsOperationRound round, VOption *options) const { VImage out; call("round", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("round", round)); return out; } VImage VImage::sRGB2HSV(VOption *options) const { VImage out; call("sRGB2HSV", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::sRGB2scRGB(VOption *options) const { VImage out; call("sRGB2scRGB", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::scRGB2BW(VOption *options) const { VImage out; call("scRGB2BW", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::scRGB2XYZ(VOption *options) const { VImage out; call("scRGB2XYZ", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::scRGB2sRGB(VOption *options) const { VImage out; call("scRGB2sRGB", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::scale(VOption *options) const { VImage out; call("scale", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::scharr(VOption *options) const { VImage out; call("scharr", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::sdf(int width, int height, VipsSdfShape shape, VOption *options) { VImage out; call("sdf", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height) ->set("shape", shape)); return out; } VImage VImage::sequential(VOption *options) const { VImage out; call("sequential", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::sharpen(VOption *options) const { VImage out; call("sharpen", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::shrink(double hshrink, double vshrink, VOption *options) const { VImage out; call("shrink", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("hshrink", hshrink) ->set("vshrink", vshrink)); return out; } VImage VImage::shrinkh(int hshrink, VOption *options) const { VImage out; call("shrinkh", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("hshrink", hshrink)); return out; } VImage VImage::shrinkv(int vshrink, VOption *options) const { VImage out; call("shrinkv", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("vshrink", vshrink)); return out; } VImage VImage::sign(VOption *options) const { VImage out; call("sign", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::similarity(VOption *options) const { VImage out; call("similarity", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::sines(int width, int height, VOption *options) { VImage out; call("sines", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::smartcrop(int width, int height, VOption *options) const { VImage out; call("smartcrop", (options ? options : VImage::option()) ->set("input", *this) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::sobel(VOption *options) const { VImage out; call("sobel", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::spcor(VImage ref, VOption *options) const { VImage out; call("spcor", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("ref", ref)); return out; } VImage VImage::spectrum(VOption *options) const { VImage out; call("spectrum", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::stats(VOption *options) const { VImage out; call("stats", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::stdif(int width, int height, VOption *options) const { VImage out; call("stdif", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::subsample(int xfac, int yfac, VOption *options) const { VImage out; call("subsample", (options ? options : VImage::option()) ->set("input", *this) ->set("out", &out) ->set("xfac", xfac) ->set("yfac", yfac)); return out; } VImage VImage::subtract(VImage right, VOption *options) const { VImage out; call("subtract", (options ? options : VImage::option()) ->set("left", *this) ->set("out", &out) ->set("right", right)); return out; } VImage VImage::sum(std::vector in, VOption *options) { VImage out; call("sum", (options ? options : VImage::option()) ->set("out", &out) ->set("in", in)); return out; } VImage VImage::svgload(const char *filename, VOption *options) { VImage out; call("svgload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::svgload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("svgload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::svgload_source(VSource source, VOption *options) { VImage out; call("svgload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } VImage VImage::switch_image(std::vector tests, VOption *options) { VImage out; call("switch", (options ? options : VImage::option()) ->set("out", &out) ->set("tests", tests)); return out; } void VImage::system(const char *cmd_format, VOption *options) { call("system", (options ? options : VImage::option()) ->set("cmd_format", cmd_format)); } VImage VImage::text(const char *text, VOption *options) { VImage out; call("text", (options ? options : VImage::option()) ->set("out", &out) ->set("text", text)); return out; } VImage VImage::thumbnail(const char *filename, int width, VOption *options) { VImage out; call("thumbnail", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename) ->set("width", width)); return out; } VImage VImage::thumbnail_buffer(VipsBlob *buffer, int width, VOption *options) { VImage out; call("thumbnail_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer) ->set("width", width)); return out; } VImage VImage::thumbnail_image(int width, VOption *options) const { VImage out; call("thumbnail_image", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out) ->set("width", width)); return out; } VImage VImage::thumbnail_source(VSource source, int width, VOption *options) { VImage out; call("thumbnail_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source) ->set("width", width)); return out; } VImage VImage::tiffload(const char *filename, VOption *options) { VImage out; call("tiffload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::tiffload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("tiffload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::tiffload_source(VSource source, VOption *options) { VImage out; call("tiffload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::tiffsave(const char *filename, VOption *options) const { call("tiffsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::tiffsave_buffer(VOption *options) const { VipsBlob *buffer; call("tiffsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::tiffsave_target(VTarget target, VOption *options) const { call("tiffsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::tilecache(VOption *options) const { VImage out; call("tilecache", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::tonelut(VOption *options) { VImage out; call("tonelut", (options ? options : VImage::option()) ->set("out", &out)); return out; } VImage VImage::transpose3d(VOption *options) const { VImage out; call("transpose3d", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::uhdr2scRGB(VOption *options) const { VImage out; call("uhdr2scRGB", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::uhdrload(const char *filename, VOption *options) { VImage out; call("uhdrload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::uhdrload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("uhdrload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::uhdrload_source(VSource source, VOption *options) { VImage out; call("uhdrload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::uhdrsave(const char *filename, VOption *options) const { call("uhdrsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::uhdrsave_buffer(VOption *options) const { VipsBlob *buffer; call("uhdrsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::uhdrsave_target(VTarget target, VOption *options) const { call("uhdrsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::unpremultiply(VOption *options) const { VImage out; call("unpremultiply", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::vipsload(const char *filename, VOption *options) { VImage out; call("vipsload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::vipsload_source(VSource source, VOption *options) { VImage out; call("vipsload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::vipssave(const char *filename, VOption *options) const { call("vipssave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } void VImage::vipssave_target(VTarget target, VOption *options) const { call("vipssave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::webpload(const char *filename, VOption *options) { VImage out; call("webpload", (options ? options : VImage::option()) ->set("out", &out) ->set("filename", filename)); return out; } VImage VImage::webpload_buffer(VipsBlob *buffer, VOption *options) { VImage out; call("webpload_buffer", (options ? options : VImage::option()) ->set("out", &out) ->set("buffer", buffer)); return out; } VImage VImage::webpload_source(VSource source, VOption *options) { VImage out; call("webpload_source", (options ? options : VImage::option()) ->set("out", &out) ->set("source", source)); return out; } void VImage::webpsave(const char *filename, VOption *options) const { call("webpsave", (options ? options : VImage::option()) ->set("in", *this) ->set("filename", filename)); } VipsBlob * VImage::webpsave_buffer(VOption *options) const { VipsBlob *buffer; call("webpsave_buffer", (options ? options : VImage::option()) ->set("in", *this) ->set("buffer", &buffer)); return buffer; } void VImage::webpsave_mime(VOption *options) const { call("webpsave_mime", (options ? options : VImage::option()) ->set("in", *this)); } void VImage::webpsave_target(VTarget target, VOption *options) const { call("webpsave_target", (options ? options : VImage::option()) ->set("in", *this) ->set("target", target)); } VImage VImage::worley(int width, int height, VOption *options) { VImage out; call("worley", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::wrap(VOption *options) const { VImage out; call("wrap", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } VImage VImage::xyz(int width, int height, VOption *options) { VImage out; call("xyz", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::zone(int width, int height, VOption *options) { VImage out; call("zone", (options ? options : VImage::option()) ->set("out", &out) ->set("width", width) ->set("height", height)); return out; } VImage VImage::zoom(int xfac, int yfac, VOption *options) const { VImage out; call("zoom", (options ? options : VImage::option()) ->set("input", *this) ->set("out", &out) ->set("xfac", xfac) ->set("yfac", yfac)); return out; } libvips-8.18.2/doc/000077500000000000000000000000001516303661500140355ustar00rootroot00000000000000libvips-8.18.2/doc/binding.md000066400000000000000000000144721516303661500160010ustar00rootroot00000000000000Title: Advanced > Writing bindings There are full libvips bindings for quite a few environments now, including C, C++, command-line, Ruby, PHP, Lua, Python, Crystal, Elixir, and JavaScript (Node.js). This chapter runs through the four main styles that have been found to work well. If you want to write a new binding, one of these should be close to what you need. ## Don't bind the top-level C API The libvips C API ([method@Image.add] and so on) was designed to be easy for humans to write. It is inconvenient and dangerous to use from other languages due to its heavy use of varargs. It's much better to use the layer below. This lower layer is structured as: - Create operator. You can use [ctor@Operation.new] to make a new [class@Operation] object from an operator nickname, like `"add"`. - Set parameters. You can use [method@Object.get_args] to get the name and type of all arguments. For each argument, you need to get the value from your language, convert to a [struct@GObject.Value], then use [method@GObject.Object.set_property] to set that value on the operator. - Execute with [func@cache_operation_build]. - Extract results. Again, you loop over the arguments, but instead of inputs, this time you look for output arguments. You extract their value with [method@GObject.Object.get_property], and pass the value back to your language. For example, you can execute [method@Image.invert] like this: ```c /* compile with * * gcc -g -Wall callvips.c `pkg-config vips --cflags --libs` * */ #include int main(int argc, char **argv) { VipsImage *in; VipsImage *out; VipsOperation *op; VipsOperation *new_op; GValue gvalue = G_VALUE_INIT; if (VIPS_INIT(argv[0])) /* This shows the libvips error buffer and quits with a fail exit * code. */ vips_error_exit(NULL); /* This will print a table of any ref leaks on exit, very handy for * development. */ vips_leak_set(TRUE); if (argc != 3) vips_error_exit("usage: %s input-filename output-filename", argv[0]); if (!(in = vips_image_new_from_file(argv[1], NULL))) vips_error_exit(NULL); /* Create a new operator from a nickname. NULL for unknown operator. */ op = vips_operation_new("invert"); /* Init a gvalue as an image, set it to in, use the gvalue to set the * operator property. */ g_value_init(&gvalue, VIPS_TYPE_IMAGE); g_value_set_object(&gvalue, in); g_object_set_property(G_OBJECT(op), "in", &gvalue); g_value_unset(&gvalue); /* We no longer need in: op will hold a ref to it as long as it needs * it. */ g_object_unref(in); /* Call the operation. This will look up the operation+args in the libvips * operation cache and either return a previous operation, or build * this one. In either case, we have a new ref we must release. */ if (!(new_op = vips_cache_operation_build(op))) { g_object_unref(op); vips_error_exit(NULL); } g_object_unref(op); op = new_op; /* Now get the result from op. g_value_get_object() does not ref the * object, so we need to make a ref for out to hold. */ g_value_init(&gvalue, VIPS_TYPE_IMAGE); g_object_get_property(G_OBJECT(op), "out", &gvalue); out = VIPS_IMAGE(g_value_get_object(&gvalue)); g_object_ref(out); g_value_unset(&gvalue); /* All done: we can unref op. The output objects from op actually hold * refs back to it, so before we can unref op, we must unref them. */ vips_object_unref_outputs(VIPS_OBJECT(op)); g_object_unref(op); if (vips_image_write_to_file(out, argv[2], NULL)) vips_error_exit(NULL); g_object_unref(out); return 0; } ``` ## Compiled language which can call C The C++ binding uses this lower layer to define a function called `VImage::call()` which can call any libvips operator with a set of variable arguments. A small Python program walks the set of all libvips operators and generates a set of static bindings. For example: ```c++ VImage VImage::invert(VOption *options) const { VImage out; call("invert", (options ? options : VImage::option()) ->set("in", *this) ->set("out", &out)); return out; } ``` So from C++ you can call any libvips operator (though without static typechecking) with `VImage::call()`, or use the member functions on `VImage` to get type-checked calls for at least the required operator arguments. The `VImage` class also adds automatic reference counting, constant expansion, operator overloads, and various other useful features. ## Dynamic language with FFI Languages like Ruby, Python, JavaScript and LuaJIT can't call C directly, but they do support FFI. The bindings for these languages work rather like C++, but use FFI to call into libvips and run operations. Since these languages are dynamic, they can add another trick: they intercept the method-missing hook and attempt to run any method calls not implemented by the [class@Image] class as libvips operators. In effect, the binding is generated at runtime. # gobject-introspection The C source code to libvips has been marked up with special comments describing the interface in a standard way. These comments are read by the `gobject-introspection` package when libvips is compiled and used to generate a typelib, a description of how to call the library. Many languages have gobject-introspection packages: all you need to do to call libvips from your favorite language is to start g-o-i, load the libvips typelib, and you should have the whole library available. For example, from Python it's as simple as: ```python from gi.repository import Vips ``` You can now use all of the libvips introspection machinery, as noted above. Unfortunately g-o-i has some strong disadvantages. It is not very portable, since you will need a g-o-i layer for whatever platform you are targeting; it does not cross-compile well, since typelibs include a lot of very-low level data (such as exact structure layouts); and installation for your users is likely to be tricky. If you have a choice, I would recommend simply using FFI. ## Documentation You can generate searchable docs from a `.gir` (the thing that is built from scanning libvips and which in turn the typelib is made from) with `g-ir-doc-tool`, for example: ```bash $ g-ir-doc-tool --language=Python -o ~/mydocs Vips-8.0.gir ``` Then to view them, either: ```bash $ yelp ~/mydocs ``` Or perhaps: ```bash $ cd ~/mydocs $ yelp-build html . ``` To make HTML docs. This is an easy way to see what you can call in the library. libvips-8.18.2/doc/check-sections.py000077500000000000000000000073721516303661500173250ustar00rootroot00000000000000#!/usr/bin/env python3 import sys import argparse import xml.etree.ElementTree as ET from pathlib import Path def register_all_namespaces(filename): namespaces = dict([node for _, node in ET.iterparse(filename, events=['start-ns'])]) for ns in namespaces: ET.register_namespace(ns, namespaces[ns]) def check_sections(args): tree = ET.parse(args.gir) root = tree.getroot() register_all_namespaces(args.gir) namespace = { 'goi': 'http://www.gtk.org/introspection/core/1.0', 'glib': 'http://www.gtk.org/introspection/glib/1.0', } namespace_node = root.find('goi:namespace', namespace) file_dict = {} for file in args.files: content = Path(file).read_text() comment_start_idx = content.find('', comment_start_idx) section_covers = content[comment_start_idx + 5:comment_end_idx] file_dict[section_covers] = {'file': file, 'content': content} tag_parser_dict = { f'{{{namespace["goi"]}}}alias': lambda n, _ : f'[alias@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}bitfield': lambda n, _ : f'[flags@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}callback': lambda n, _ : f'[callback@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}class': lambda n, _ : f'[class@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}constructor': lambda n, p : f'[ctor@{p}{n.attrib["name"]}]', f'{{{namespace["goi"]}}}method': lambda n, p : f'[method@{p}{n.attrib["name"]}]', f'{{{namespace["goi"]}}}constant': lambda n, _ : f'[const@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}enumeration': lambda n, _ : f'[enum@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}function-macro': lambda n, _ : f'[func@{n.attrib["name"]}]', f'{{{namespace["goi"]}}}function': lambda n, p : f'[func@{p}{n.attrib["name"]}]', # each struct has its own documentation # f'{{{namespace["goi"]}}}record': lambda n, _ : f'[struct@{n.attrib["name"]}]', # struct and enum members do not need to be listed # f'{{{namespace["goi"]}}}field': lambda n, p : f'[struct@Vips.{p}{n.attrib["name"]}]', # f'{{{namespace["goi"]}}}member': lambda n, p : f'[enum@Vips.{p}{n.attrib["name"]}]', } exitcode = 0 parent_map = {c: p for p in namespace_node.iter() for c in p} for node in parent_map: if 'moved-to' in node.attrib: continue child = node.find('goi:doc', namespace) if child is None: continue filename = child.attrib['filename'] section = next((k for k in file_dict.keys() if filename.startswith(k)), None) if section is None: continue parser_method = tag_parser_dict.get(node.tag, None) if parser_method is None: continue parent_name = parent_map.get(node, {}).attrib.get('name') or '' if parent_name == 'Vips': parent_name = '' if parent_name: parent_name += '.' symbol = parser_method(node, parent_name) if f'* {symbol}' not in file_dict[section]['content']: print(f"ERROR: Symbol '{symbol}' is not listed in '{file_dict[section]['file']}'", file=sys.stderr) exitcode = 1 sys.exit(exitcode) def main(): parser = argparse.ArgumentParser() parser.add_argument('--gir', help='input GIR file', type=Path) parser.add_argument('files', help='markdown files', type=Path, nargs=argparse.REMAINDER) args = parser.parse_args() check_sections(args) if __name__ == '__main__': main() libvips-8.18.2/doc/cite.md000066400000000000000000000012071516303661500153030ustar00rootroot00000000000000Title: Citing libvips Cupitt, J., Martinez, K., Fuller, L. and Wolthuizen, K. A. (2025) [The libvips image processing library]( https://www.southampton.ac.uk/~km2/papers/2025/vips-ist-preprint.pdf). In Proceedings of Electronic Imaging 2025, Burlingame. Martinez, K. and Cupitt, J. (2005) [VIPS -- a highly tuned image processing software architecture]( http://eprints.ecs.soton.ac.uk/12371). In Proceedings of IEEE International Conference on Image Processing 2, pp. 574-577, Genova. Cupitt, J. and Martinez, K. (1996) [VIPS: An image processing system for large images]( http://eprints.soton.ac.uk/252227), Proc. SPIE, vol. 2663, pp. 19--28. libvips-8.18.2/doc/developer-checklist.md000066400000000000000000000131531516303661500203160ustar00rootroot00000000000000Title: Using > Checklist for programmers using libvips libvips is a slightly unusual library and you may need to take some of its stranger features into account when you design software that uses it. ## If you can, use [ctor@Image.thumbnail], not [method@Image.resize] The [ctor@Image.thumbnail] operation combines load and resize into one step. This lets it take advantage of format library features, such as shrink on load, and can lead to a large improvement in speed and a large drop in memory use. For example, with this JPEG image: ```bash $ vipsheader nina.jpg nina.jpg: 6048x4032 uchar, 3 bands, srgb, jpegload ``` I see: ```bash $ /usr/bin/time -f %M:%e vips resize nina.jpg x.jpg 0.1 123648:0.23 ``` 124 MB of RAM and 0.23s to shink by a factor of 10. With `thumbnail` it's: ```bash $ /usr/bin/time -f %M:%e vips thumbnail nina.jpg x.jpg 605 68864:0.08 ``` Now it's 68 MB of memory and 0.08s -- half the memory use, and 3x faster. In fact the improvement is better than that, since the `vips` command takes a while to start and needs a fair amount of memory: ```bash $ /usr/bin/time -f %M:%e vips > /dev/null 31232:0.02 ``` 31 MB and 0.02s, so [ctor@Image.thumbnail] is really 2.5x less memory and 4x faster. You can see much larger improvements with other formats, and quality will often be better as well, since [ctor@Image.thumbnail] will automatically premultiply and can render vector images directly at the correct size. ## Don't use [method@Image.thumbnail_image] It's just there for emergencies. It can't do any of the rendering tricks, so it's not faster than [method@Image.resize]. Use [ctor@Image.thumbnail] if you can. ## Use sequential mode if you can This is a hint you pass to [ctor@Image.new_from_file] and friends that signals that you will only scan this image in the direction that the underlying load library supports. This can give a useful improvement in speed and reduction in memory use in many cases. See [the "How it opens files" chapter](how-it-opens-files.html) for background on this feature. ## Use longer pipelines if you can libvips is demand-driven, and uses partial images as intermediates. This means you can construct long pipelines of image processing operations, they won't use much memory, and they'll (usually) join efficiently. libvips is horizontally threaded, meaning that threads run along the pipeline of operations you are evaluating, not up and down images. This means that libvips can (usually) parallelise longer pipelines more efficiently than short ones. If you can, aim for long pipelines of processing operations. ## Cache commonly reused images If an image is reused repeatedly in one pipeline, it'll be recomputed each time. You can sometimes get a big speedup by keeping images like this in memory rather than recalculating their pixels, see (for example), `copy_memory()` in pyvips. This can raise memory use, of course. ## Adjust the order of operations in pipelines If you can, put large resizes right at the start (see [ctor@Image.thumbnail] above), then area filters (sharpen, for example), and finally any point operations. ## Only enable the load libraries you need libvips after version 8.13 has a system for enabling and disabling image load libraries at runtime, see: You can usually improve security and avoid memory spikes by only enabling the image formats you really need. If you are handling untrusted data, I would set the `VIPS_BLOCK_UNTRUSTED` env var and only use the loaders we have tested for security. Older versions of libvips need compile-time configuration. ## Sanity-check images before processing libvips image open is always fast and safe, as long as you have disabled load via imagemagick. This means you can open an image and sanity-check it before further processing. First, it is well worth checking image dimensions to protect yourself from decompression bombs, like those described at . Secondly, I would check for interlaced (also called progressive) images. These are images that appear in low detail first, then progressively sharpen as they are downloaded. Although they can be convenient for presentation, the downside is that you don't get the final pixels until the whole image is in memory, which prevents any streaming processing and hugely increases memory use. For example: ```bash $ /usr/bin/time -f %M:%e vipsthumbnail big-progressive.jpg 3732224:4.23 $ vips copy big-progressive.jpg x.jpg $ /usr/bin/time -f %M:%e vipsthumbnail x.jpg 72448:0.26 ``` So this progressive jpeg takes 4gb of memory and 4.3s to thumbnail, but exactly the same image as a regular jpeg takes 72mb and 0.26s. I would detect these horrors before processing by looking for the `interlaced` metadata item and either ban them, or if your users insist on uploading in this terrible format, push them to a separate low-priority queue on a special container. Keep them away from your main image path. ## Linux memory allocator The default memory allocator on most glibc-based Linux systems (e.g. Debian, Red Hat) is unsuitable for long-running, multi-threaded processes that involve lots of small memory allocations. To help avoid fragmentation and improve performance on these systems, the use of an alternative memory allocator such as [jemalloc]( https://github.com/jemalloc/jemalloc) is recommended. Those using musl-based Linux (e.g. Alpine) and non-Linux systems are unaffected. ## Disable the libvips operation cache if you don't need it The libvips operation cache is not useful for image proxies (i.e. processing many different images). Consider disabling this with `vips_cache_set_max(0);`. libvips-8.18.2/doc/examples.md000066400000000000000000000065541516303661500162070ustar00rootroot00000000000000Title: Using > Python examples This page shows a few libvips examples using Python. They will work with small syntax changes in any language with a libvips binding. The libvips test suite is written in Python and exercises every operation in the API. It's also a useful source of examples. ## Average a region of interest box on an image ```python #!/usr/bin/python3 import sys import pyvips left = 10 top = 10 width = 64 height = 64 image = pyvips.Image.new_from_file(sys.argv[1]) roi = image.crop(left, top, width, height) print('average:', roi.avg()) ``` ## libvips and numpy You can use `pyvips.Image.new_from_memory()` to make a libvips image from an area of memory. The memory array needs to be laid out band-interleaved, as a set of scanlines, with no padding between lines. ```python #!/usr/bin/python3 import sys import time import pyvips from PIL import Image import numpy as np if len(sys.argv) != 3: print(f'usage: {sys.argv[0]} input-filename output-filename') sys.exit(-1) # load with PIL start_pillow = time.time() pillow_img = np.asarray(Image.open(sys.argv[1])) print('Pillow Time:', time.time()-start_pillow) print('original shape', pillow_img.shape) # load with vips to a numpy array start_vips = time.time() img = pyvips.Image.new_from_file(sys.argv[1], access='sequential') np_3d = img.numpy() print('Vips Time:', time.time()-start_vips) print('final shape', np_3d.shape) # verify we have the same result print('Sum of the Differences:', np.sum(np_3d-pillow_img)) # make a vips image from the numpy array vi = pyvips.Image.new_from_array(np_3d) # and write back to disc for checking vi.write_to_file(sys.argv[2]) ``` ## Build huge image mosaic This makes a 100,000 x 100,000 black image, then inserts all the images you pass on the command-line into it at random positions. libvips is able to run this program in sequential mode: it'll open all the input images at the same time, and stream pixels from them as it needs them to generate the output. To test it, first make a large 1-bit image. This command will take the green channel and write as a 1-bit fax image. `wtc.jpg` is a test 10,000 x 10,000 jpeg: ```bash $ vips extract_band wtc.jpg x.tif[squash,compression=ccittfax4,keep=none] 1 ``` Now make 1,000 copies of that image in a subdirectory: ```bash $ mkdir test $ for i in {1..1000}; do cp x.tif test/$i.tif; done ``` And run this Python program on them: ```bash $ time python try255.py x.tif[squash,compression=ccittfax4,strip,bigtiff] test/* real 1m59.924s user 4m5.388s sys 0m8.936s ``` It completes in just under two minutes on this laptop, and needs about 7gb of RAM to run. It would need about the same amount of memory for a full-colour RGB image, I was just keen to keep disc usage down. If you wanted to handle transparency, or if you wanted mixed CMYK and RGB images, you'd need to do some more work to convert them all into the same colourspace before inserting them. ```python #!/usr/bin/python3 #file try255.py import sys import random import pyvips # this makes a 8-bit, mono image of 100,000 x 100,000 pixels, each pixel zero im = pyvips.Image.black(100000, 100000) for filename in sys.argv[2:]: tile = pyvips.Image.new_from_file(filename, access='sequential') im = im.insert(tile, random.randint(0, im.width - tile.width), random.randint(0, im.height - tile.height)) im.write_to_file(sys.argv[1]) ``` libvips-8.18.2/doc/extending.md000066400000000000000000000271511516303661500163520ustar00rootroot00000000000000Title: Advanced > Writing operators This section runs quickly through adding a simple operator to libvips. For more information, see [class@Operation] and [class@Region]. A good starting point for a new operation is a similar one in libvips. All libvips operations are subclasses of [class@Operation], which in turn subclasses [class@Object] and then [class@GObject.Object]. You add an operation to libvips by defining a new subclass of [class@Operation] and arranging for its `class_init()` to be called, perhaps by calling its `get_type()` function. ## The class and object structures First you need to define a new object struct and a new class struct. ```c typedef struct _Negative { VipsOperation parent_instance; VipsImage *in; VipsImage *out; int image_max; } Negative; typedef struct _NegativeClass { VipsOperationClass parent_class; /* No new class members needed for this op. */ } NegativeClass; ``` This operation will find the photographic negative of an unsigned 8-bit image, optionally letting you specify the value which the pixels "pivot" about. It doesn't need any class members (ie. values common to all operations of this type), so the second struct is empty. See the source to [method@Image.invert] for a more complete version of this operation that's actually in the library. [class@GObject.Object] has a handy macro to write some of the boilerplate for you. ```c G_DEFINE_TYPE(Negative, negative, VIPS_TYPE_OPERATION); ``` [func@GObject.DEFINE_TYPE] defines a function called `negative_get_type()`, which registers this new class and returns its [alias@GObject.Type] (a pointer-sized integer). `negative_get_type()` in turn needs two functions, `negative_init()`, to initialise a new instance, and `negative_class_init()`, to initialise a new class. ## Class and object initialisation `negative_init()` is very simple, it just sets the default value for our optional parameter. ```c static void negative_init(Negative *negative) { negative->image_max = 255; } ``` `negative_class_init()` is more complicated: it has to set various fields in various superclasses and define the operation's parameters. ```c static void negative_class_init(NegativeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "negative"; object_class->description = "photographic negative"; object_class->build = negative_build; VIPS_ARG_IMAGE(class, "in", 1, "Input", "Input image", VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(Negative, in)); VIPS_ARG_IMAGE(class, "out", 2, "Output", "Output image", VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(Negative, out)); VIPS_ARG_INT(class, "image_max", 4, "Image maximum", "Maximum value in image: pivot about this", VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(Negative, image_max), 0, 255, 255); } ``` In [class@GObject.Object], it needs to set the getters and setters for this class. libvips has a generic get/set system, so any subclass of [class@VipsObject] needs to use the libvips ones. In [class@VipsObject], it needs to set the operation [property@VipsObject:nickname] and [property@VipsObject:description], and set a build function (see below). [property@VipsObject:nickname] is used to refer to this operation in the API, [property@VipsObject:description] is used to explain this operation to users and will be translated into their language. Finally, it needs to define the arguments the constructor for this class takes. There are a set of handy macros for doing this, see [func@ARG_INT] and friends. The first few parameters are always the same and mean: class pointer for argument, argument name, argument priority (bindings expect required arguments in order of priority), long argument name (this one is internationalised and displayed to users), description (again, users can see this), some flags describing the argument, and finally the position of the member in the struct. Integer arguments take three more values: the minimum, maximum and default value for the argument. ## The `build()` function The build function is the thing [class@VipsObject] calls during object construction, after all arguments have been supplied and before the object is used. It has two roles: to verify that arguments are correct, and then to construct the object. After `build()`, the object is expected to be ready for use. ```c static int negative_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); Negative *negative = (Negative *) object; if (VIPS_OBJECT_CLASS(negative_parent_class)->build(object)) return -1; if (vips_check_uncoded(class->nickname, negative->in) || vips_check_format(class->nickname, negative->in, VIPS_FORMAT_UCHAR)) return -1; g_object_set(object, "out", vips_image_new(), NULL); if (vips_image_pipelinev(negative->out, VIPS_DEMAND_STYLE_THINSTRIP, negative->in, NULL)) return -1; if (vips_image_generate(negative->out, vips_start_one, negative_generate, vips_stop_one, negative->in, negative)) return -1; return 0; } ``` `negative_build()` first chains up to the superclass: this will check that all input arguments have been supplied and are sane. Next, it adds its own checks. This is a demo operation, so we just work for uncoded, unsigned 8-bit images. There are a lot of convenience functions like [func@check_format], see the docs. Next, it creates the output image. This needs to be set with [method@Object.set] so that libvips can see that it has been assigned. libvips will also handle the reference counting for you. [method@Image.pipelinev] links our new image onto the input image and notes that this operation prefers to work in lines. You can request other input geometries, see [enum@DemandStyle]. The geometry hint is just a hint, an operation needs to be able to supply any size [class@Region] on request. If you must have a certain size request, you can put a cache in the pipeline after your operation, see [method@Image.linecache] and [method@Image.tilecache]. You can also make requests to your operation ordered, see [method@Image.sequential]. Finally, [method@Image.generate] attaches a set of callbacks to the output image to generate chunks of it on request. [func@start_one] and [func@stop_one] are convenience functions that make the input region for you, see below. ## The `generate()` function The `generate()` function does the actual image processing. `negative_generate()` (of type [callback@GenerateFn], supplied to [method@Image.generate] above) is called whenever some pixels of our output image are required. ```c static int negative_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { /* The area of the output region we have been asked to make. */ VipsRect *r = &out_region->valid; /* The sequence value ... the thing returned by vips_start_one(). */ VipsRegion *ir = (VipsRegion *) vseq; VipsImage *in = (VipsImage *) a; Negative *negative = (Negative *) b; int line_size = r->width * negative->in->Bands; int x, y; /* Request matching part of input region. */ if (vips_region_prepare(ir, r)) return -1; for (y = 0; y < r->height; y++) { unsigned char *p = (unsigned char *) VIPS_REGION_ADDR(ir, r->left, r->top + y); unsigned char *q = (unsigned char *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); for (x = 0; x < line_size; x++) q[x] = negative->image_max - p[x]; } return 0; } ``` This has to calculate a section of the output image. The output [class@Region], `out_region`, contains a [struct@Rect] called `valid` which is the area needing calculation. This call to `negative_generate()` must somehow make this part of `out_region` contain pixel data. `vseq` is the sequence value. This is the per-thread state for this generate, created (in this example) by [func@start_one]. In this simple case it's just a [class@Region] defined on the input image. If you need more per-thread state you can write your own start and stop functions and have a struct you create and pass as a sequence value. There are plenty of examples in the libvips source code, see [method@Image.rank]. `a` and `b` are the last two arguments to [method@Image.generate] above. `stop` is a bool pointer you can set to stop computation early. [method@Image.min] on an unsigned int image, for example, will set `stop` as soon as it sees a zero, and will not scan the entire image. The first thing `negative_generate()` does is use [method@Region.prepare] to ask for the corresponding pixels from the input image. Operations which do coordinate transforms or which need an area of input for each output point will need to calculate a new rect before calling [method@Region.prepare]. Finally, it can calculate some pixels. `negative_generate()` loops over the valid area of the output and calls [func@REGION_ADDR] for each line. This macro is reasonably quick, but it's best not to call it for each pixel. Once per line is fine though. ## Adding to libvips To add the operation to libvips, just call `negative_get_type()`. You can include the source in your program, or use [GModule]( https://docs.gtk.org/gmodule/) to make a binary plugin that will be loaded by libvips at startup. There are some [example plugins available]( https://github.com/jcupitt/vips-gmic). You can then use `negative` from any of the libvips interfaces. For example, in Python you'd use it like this: ```python out = in.negative(image_max=128) ``` From the command-line it'd look like this: ```bash $ vips negative in.png out.tif --image-max 128 ``` And from C like this: ```c VipsImage *in; VipsImage *out; if (vips_call("negative", in, &out, "image_max", 128, NULL)) ... error ``` Unfortunately that will do almost no compile-time type checking, so all libvips operations have a tiny extra wrapper to add a bit of safety. For example: ```c static int negative(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("negative", ap, in, out); va_end(ap); return result; } ``` And now you can write: ```c if (negative(in, &out, "image_max", 128, NULL)) ... error ``` and it's at least a bit safer. ## Other types of operation Change the `_build()` function to make other types of operation. Use [method@Image.generate] with [func@start_many] to make operations which demand pixels from more than one image at once, such as image plus image. Use [method@Image.sink] instead of [method@Image.generate] to loop over an image and calculate a value. libvips uses this for the statistics operations, like [method@Image.avg]. Use [method@Image.wio_input] to get an entire image into memory so you can read it with a pointer. This will obviously not scale well to very large images, but some operations, like FFTs or flood-fill, need the whole image to be available at once. Make area operations, like filters, by enlarging the [struct@Rect] that `_generate()` is given before calling [method@Region.prepare]. You can enlarge the input image, so that the output image is the same size as the original input, by using [method@Image.embed] within the `_build()` function. Make things like flips and rotates by making larger changes to the [struct@Rect] in `_generate()`. Make zero-copy operations, like [method@Image.insert], with [method@Region.region]. libvips-8.18.2/doc/file-format.md000066400000000000000000000116211516303661500165650ustar00rootroot00000000000000Title: Technical background > The libvips file format libvips has a simple, native file format. It's very fast, there is no image size limit, and it supports arbitrary metadata. Although few other programs can read these images (though recent versions of ImageMagick do have basic support for the `.v` format), it can be useful as an intermediate format for command-line processing. For example: ```bash $ vips invert input.tif t.v $ vips gamma t.v output.tif ``` is faster than using `.tif` for the temporary intermediate image. This section documents the libvips file format. libvips comes with a command-line program called `vipsedit` which is useful for destructively changing fields in a `.v` image. The `vipsheader` program can be used to extract any metadata. libvips files come in three parts. First, there is a 64-byte header, containing an identifying magic number and a set of very basic fields, such as image width in pixels. Next, the image data is stored as a set of band-interleaved scanlines, from the top of the image to the bottom. Finally, after the pixel data comes an optional block of XML containing any extra metadata, such as an ICC profile or the EXIF data. ## The header The fields in the libvips header are always stored least-significant byte first (Intel ordering). Only the most basic information about the image is in the header: most metadata is stored in the XML extension block after the pixel data. If the first four bytes of the file are in order 08 f2 a6 b6, the image data (see the next section) is stored in Intel byte order (LSB first) and will need to be swapped if read on a SPARC-style machine (MSB first). If the magic number is b6 a6 f2 08, the image data is in SPARC order and will need to swapped if read on an Intel-style machine. libvips does this swapping automatically. | Bytes | Type | libvips name | Meaning | |---------|-----------------------|------------------|-------------------------------------------| | 0 - 3 | | | Magic number: 08 f2 a6 b6, or b6 a6 f2 08 | | 4 - 7 | int32 | `width` | Width of image, in pixels | | 8 - 11 | int32 | `height` | Height of image, in pixels | | 12 - 15 | int32 | `bands` | Number of image bands (channels) | | 16 - 19 | | | Unused | | 20 - 23 | [enum@BandFormat] | `format` | Band format | | 24 - 27 | [enum@Coding] | `coding` | Image coding | | 28 - 31 | [enum@Interpretation] | `interpretation` | Pixel interpretation | | 32 - 35 | float32 | `xres` | Horizontal resolution, in pixels per mm | | 36 - 39 | float32 | `yres` | Vertical resolution, in pixels per mm | | 40 - 47 | | | Unused | | 48 - 51 | int32 | `xoffset` | Horizontal offset of origin, in pixels | | 52 - 55 | int32 | `yoffset` | Vertical offset of origin, in pixels | | 56 - 63 | | | Unused | ## The image data If `coding` is set to [enum@Vips.Coding.NONE], pixels are stored in native C format, that is, the native format of the machine that wrote the data. If you open a big-endian image on a little-endian machine, libvips will automatically byte-swap for you. libvips has 10 band formats, see [enum@BandFormat]. Image data is stored as a simple list of scanlines, from the top of the image to the bottom. Pixels are band-interleaved, so RGBRGBRGBRGB, for example. There is no padding at the end of scanlines. If `coding` is set to [enum@Vips.Coding.LABQ], each pixel is four bytes, with 10 bits for L\* and 11 bits for each of a\* and b\*. These 32 bits are packed into 4 bytes, with the most significant 8 bits of each value in the first 3 bytes, and the left-over bits packed into the final byte as 2:3:3. If `coding` is set to [enum@Vips.Coding.RAD], each pixel is RGB or XYZ float, with 8 bits of mantissa and then 8 bits of exponent, shared between the three channels. This coding style is used by the Radiance family of programs (and the HDR format) commonly used for HDR imaging. Other values of `coding` can set other coding styles. Use [func@IMAGE_SIZEOF_IMAGE] to calculate the size of the image data section. ## The metadata Following the image data is a chunk of XML holding a simple list of name-value pairs. Binary data is encoded with base64. Use [method@Image.set] and friends to set and get image metadata. You can use `vipsheader -f getext some_file.v` to get the XML from a libvips image, and `vipsedit --setext some_file.v < file.xml` to replace the XML. libvips-8.18.2/doc/fixup-gir-for-doc.py000077500000000000000000000052631516303661500176610ustar00rootroot00000000000000#!/usr/bin/env python3 import argparse import xml.etree.ElementTree as ET from pathlib import Path def register_all_namespaces(filename): namespaces = dict([node for _, node in ET.iterparse(filename, events=['start-ns'])]) for ns in namespaces: ET.register_namespace(ns, namespaces[ns]) def fixup_gir_for_doc(args): tree = ET.parse(args.in_path) root = tree.getroot() register_all_namespaces(args.in_path) namespace = { 'goi': 'http://www.gtk.org/introspection/core/1.0' } namespace_node = root.find('goi:namespace', namespace) image_node = namespace_node.find('goi:class[@name="Image"]', namespace) blob_node = namespace_node.find('goi:record[@name="Blob"]', namespace) # A list of functions that needs to be converted to an Image constructor. # Note that all functions containing "load" are already converted. image_ctors = [ 'black', 'eye', 'fractsurf', 'gaussmat', 'gaussnoise', 'grey', 'identity', 'logmat', 'mask_butterworth', 'mask_butterworth_band', 'mask_butterworth_ring', 'mask_fractal', 'mask_gaussian', 'mask_gaussian_band', 'mask_gaussian_ring', 'mask_ideal', 'mask_ideal_band', 'mask_ideal_ring', 'perlin', 'sdf', 'sines', 'system', 'text', 'thumbnail', 'thumbnail_buffer', 'thumbnail_source', 'tonelut', 'worley', 'xyz', 'zone', ] # Functions that take multiple images as input argument ... make them # part of the Image class. # Keep-in-sync with gen-function-list.py image_funcs = [ 'arrayjoin', 'bandjoin', 'bandrank', 'composite', 'sum', 'switch', ] for node in namespace_node.findall('goi:function', namespace): name = node.get('name') if name == 'profile_load': namespace_node.remove(node) node.tag = 'constructor' blob_node.append(node) elif 'load' in name or name in image_ctors: namespace_node.remove(node) node.tag = 'constructor' image_node.append(node) elif name in image_funcs: namespace_node.remove(node) image_node.append(node) tree.write(args.out_path, encoding='utf-8', xml_declaration=True) def main(): parser = argparse.ArgumentParser() parser.add_argument('in_path', help='input file', type=Path) parser.add_argument('out_path', help='output file', type=Path) args = parser.parse_args() fixup_gir_for_doc(args) if __name__ == '__main__': main() libvips-8.18.2/doc/function-list.md000066400000000000000000000652341516303661500171670ustar00rootroot00000000000000Title: Operator index / Alphabetical libvips has a set of operators, each of which computes some useful image processing operation. Each operator is implemented as a [class@GObject.Object] class, for example `VipsGamma`. Classes are identified by their unique [property@VipsObject:nickname], in this case `gamma`. From the command-line, C++ and most language bindings, you use the nickname to call the operator. For example in C++: ```c++ vips::VImage fred = ...; vips::VImage jim = fred.gamma(); ``` or Python: ```python fred = jim.gamma() ``` libvips has a set of C wrapper functions for calling operators, in this case [method@Image.gamma]: ```c VipsImage *fred = ...; VipsImage *jim; if (vips_gamma(fred, &jim, NULL)) ...error; ``` Some operators have many C convenience functions. # All libvips operators This table lists all the libvips operators with their C convenience functions and a short description. It's supposed to be useful for searching. See the API docs each function links to for more details. | Operator | Description | C functions | | -------- | ----------- | ----------- | | `CMC2LCh` | Transform lch to cmc | [method@Image.CMC2LCh] | | `CMYK2XYZ` | Transform cmyk to xyz | [method@Image.CMYK2XYZ] | | `HSV2sRGB` | Transform hsv to srgb | [method@Image.HSV2sRGB] | | `LCh2CMC` | Transform lch to cmc | [method@Image.LCh2CMC] | | `LCh2Lab` | Transform lch to lab | [method@Image.LCh2Lab] | | `Lab2LCh` | Transform lab to lch | [method@Image.Lab2LCh] | | `Lab2LabQ` | Transform float lab to labq coding | [method@Image.Lab2LabQ] | | `Lab2LabS` | Transform float lab to signed short | [method@Image.Lab2LabS] | | `Lab2XYZ` | Transform cielab to xyz | [method@Image.Lab2XYZ] | | `LabQ2Lab` | Unpack a labq image to float lab | [method@Image.LabQ2Lab] | | `LabQ2LabS` | Unpack a labq image to short lab | [method@Image.LabQ2LabS] | | `LabQ2sRGB` | Convert a labq image to srgb | [method@Image.LabQ2sRGB] | | `LabS2Lab` | Transform signed short lab to float | [method@Image.LabS2Lab] | | `LabS2LabQ` | Transform short lab to labq coding | [method@Image.LabS2LabQ] | | `Oklab2Oklch` | Transform oklab to oklch | [method@Image.Oklab2Oklch] | | `Oklab2XYZ` | Transform oklab to xyz | [method@Image.Oklab2XYZ] | | `Oklch2Oklab` | Transform oklch to oklab | [method@Image.Oklch2Oklab] | | `XYZ2CMYK` | Transform xyz to cmyk | [method@Image.XYZ2CMYK] | | `XYZ2Lab` | Transform xyz to lab | [method@Image.XYZ2Lab] | | `XYZ2Oklab` | Transform xyz to oklab | [method@Image.XYZ2Oklab] | | `XYZ2Yxy` | Transform xyz to yxy | [method@Image.XYZ2Yxy] | | `XYZ2scRGB` | Transform xyz to scrgb | [method@Image.XYZ2scRGB] | | `Yxy2XYZ` | Transform yxy to xyz | [method@Image.Yxy2XYZ] | | `abs` | Absolute value of an image | [method@Image.abs] | | `add` | Add two images | [method@Image.add] | | `addalpha` | Append an alpha channel | [method@Image.addalpha] | | `affine` | Affine transform of an image | [method@Image.affine] | | `analyzeload` | Load an analyze6 image | [ctor@Image.analyzeload] | | `arrayjoin` | Join an array of images | [func@Image.arrayjoin] | | `autorot` | Autorotate image by exif tag | [method@Image.autorot] | | `avg` | Find image average | [method@Image.avg] | | `bandbool` | Boolean operation across image bands | [method@Image.bandbool], [method@Image.bandand], [method@Image.bandor], [method@Image.bandeor], [method@Image.bandmean] | | `bandfold` | Fold up x axis into bands | [method@Image.bandfold] | | `bandjoin` | Bandwise join a set of images | [func@Image.bandjoin], [method@Image.bandjoin2] | | `bandjoin_const` | Append a constant band to an image | [method@Image.bandjoin_const], [method@Image.bandjoin_const1] | | `bandmean` | Band-wise average | [method@Image.bandmean] | | `bandrank` | Band-wise rank of a set of images | [func@Image.bandrank] | | `bandunfold` | Unfold image bands into x axis | [method@Image.bandunfold] | | `black` | Make a black image | [ctor@Image.black] | | `boolean` | Boolean operation on two images | [method@Image.boolean], [method@Image.andimage], [method@Image.orimage], [method@Image.eorimage], [method@Image.lshift], [method@Image.rshift] | | `boolean_const` | Boolean operations against a constant | [method@Image.boolean_const], [method@Image.andimage_const], [method@Image.orimage_const], [method@Image.eorimage_const], [method@Image.lshift_const], [method@Image.rshift_const], [method@Image.boolean_const1], [method@Image.andimage_const1], [method@Image.orimage_const1], [method@Image.eorimage_const1], [method@Image.lshift_const1], [method@Image.rshift_const1] | | `buildlut` | Build a look-up table | [method@Image.buildlut] | | `byteswap` | Byteswap an image | [method@Image.byteswap] | | `canny` | Canny edge detector | [method@Image.canny] | | `case` | Use pixel values to pick cases from an array of images | [method@Image.case] | | `cast` | Cast an image | [method@Image.cast], [method@Image.cast_uchar], [method@Image.cast_char], [method@Image.cast_ushort], [method@Image.cast_short], [method@Image.cast_uint], [method@Image.cast_int], [method@Image.cast_float], [method@Image.cast_double], [method@Image.cast_complex], [method@Image.cast_dpcomplex] | | `clamp` | Clamp values of an image | [method@Image.clamp] | | `colourspace` | Convert to a new colorspace | [method@Image.colourspace] | | `compass` | Convolve with rotating mask | [method@Image.compass] | | `complex` | Perform a complex operation on an image | [method@Image.complex], [method@Image.polar], [method@Image.rect], [method@Image.conj] | | `complex2` | Complex binary operations on two images | [method@Image.complex2], [method@Image.cross_phase] | | `complexform` | Form a complex image from two real images | [method@Image.complexform] | | `complexget` | Get a component from a complex image | [method@Image.complexget], [method@Image.real], [method@Image.imag] | | `composite` | Blend an array of images with an array of blend modes | [func@Image.composite] | | `composite2` | Blend a pair of images with a blend mode | [method@Image.composite2] | | `conv` | Convolution operation | [method@Image.conv] | | `conva` | Approximate integer convolution | [method@Image.conva] | | `convasep` | Approximate separable integer convolution | [method@Image.convasep] | | `convf` | Float convolution operation | [method@Image.convf] | | `convi` | Int convolution operation | [method@Image.convi] | | `convsep` | Separable convolution operation | [method@Image.convsep] | | `copy` | Copy an image | [method@Image.copy] | | `countlines` | Count lines in an image | [method@Image.countlines] | | `csvload` | Load csv | [ctor@Image.csvload] | | `csvload_source` | Load csv | [ctor@Image.csvload_source] | | `csvsave` | Save image to csv | [method@Image.csvsave] | | `csvsave_target` | Save image to csv | [method@Image.csvsave_target] | | `dE00` | Calculate de00 | [method@Image.dE00] | | `dE76` | Calculate de76 | [method@Image.dE76] | | `dECMC` | Calculate decmc | [method@Image.dECMC] | | `dcrawload` | Load raw camera files | [ctor@Image.dcrawload] | | `dcrawload_buffer` | Load raw camera files | [ctor@Image.dcrawload_buffer] | | `dcrawload_source` | Load raw camera files | [ctor@Image.dcrawload_source] | | `deviate` | Find image standard deviation | [method@Image.deviate] | | `divide` | Divide two images | [method@Image.divide] | | `draw_circle` | Draw a circle on an image | [method@Image.draw_circle], [method@Image.draw_circle1] | | `draw_flood` | Flood-fill an area | [method@Image.draw_flood], [method@Image.draw_flood1] | | `draw_image` | Paint an image into another image | [method@Image.draw_image] | | `draw_line` | Draw a line on an image | [method@Image.draw_line], [method@Image.draw_line1] | | `draw_mask` | Draw a mask on an image | [method@Image.draw_mask], [method@Image.draw_mask1] | | `draw_rect` | Paint a rectangle on an image | [method@Image.draw_rect], [method@Image.draw_rect1], [method@Image.draw_point], [method@Image.draw_point1] | | `draw_smudge` | Blur a rectangle on an image | [method@Image.draw_smudge] | | `dzsave` | Save image to deepzoom file | [method@Image.dzsave] | | `dzsave_buffer` | Save image to dz buffer | [method@Image.dzsave_buffer] | | `dzsave_target` | Save image to deepzoom target | [method@Image.dzsave_target] | | `embed` | Embed an image in a larger image | [method@Image.embed] | | `extract_area` | Extract an area from an image | [method@Image.extract_area], [method@Image.crop] | | `extract_band` | Extract band from an image | [method@Image.extract_band] | | `eye` | Make an image showing the eye's spatial response | [ctor@Image.eye] | | `falsecolour` | False-color an image | [method@Image.falsecolour] | | `fastcor` | Fast correlation | [method@Image.fastcor] | | `fill_nearest` | Fill image zeros with nearest non-zero pixel | [method@Image.fill_nearest] | | `find_trim` | Search an image for non-edge areas | [method@Image.find_trim] | | `fitsload` | Load a fits image | [ctor@Image.fitsload] | | `fitsload_source` | Load fits from a source | [ctor@Image.fitsload_source] | | `fitssave` | Save image to fits file | [method@Image.fitssave] | | `flatten` | Flatten alpha out of an image | [method@Image.flatten] | | `flip` | Flip an image | [method@Image.flip] | | `float2rad` | Transform float rgb to radiance coding | [method@Image.float2rad] | | `fractsurf` | Make a fractal surface | [ctor@Image.fractsurf] | | `freqmult` | Frequency-domain filtering | [method@Image.freqmult] | | `fwfft` | Forward fft | [method@Image.fwfft] | | `gamma` | Gamma an image | [method@Image.gamma] | | `gaussblur` | Gaussian blur | [method@Image.gaussblur] | | `gaussmat` | Make a gaussian image | [ctor@Image.gaussmat] | | `gaussnoise` | Make a gaussnoise image | [ctor@Image.gaussnoise] | | `getpoint` | Read a point from an image | [method@Image.getpoint] | | `gifload` | Load gif with libnsgif | [ctor@Image.gifload] | | `gifload_buffer` | Load gif with libnsgif | [ctor@Image.gifload_buffer] | | `gifload_source` | Load gif from source | [ctor@Image.gifload_source] | | `gifsave` | Save as gif | [method@Image.gifsave] | | `gifsave_buffer` | Save as gif | [method@Image.gifsave_buffer] | | `gifsave_target` | Save as gif | [method@Image.gifsave_target] | | `globalbalance` | Global balance an image mosaic | [method@Image.globalbalance] | | `gravity` | Place an image within a larger image with a certain gravity | [method@Image.gravity] | | `grey` | Make a grey ramp image | [ctor@Image.grey] | | `grid` | Grid an image | [method@Image.grid] | | `heifload` | Load a heif image | [ctor@Image.heifload] | | `heifload_buffer` | Load a heif image | [ctor@Image.heifload_buffer] | | `heifload_source` | Load a heif image | [ctor@Image.heifload_source] | | `heifsave` | Save image in heif format | [method@Image.heifsave] | | `heifsave_buffer` | Save image in heif format | [method@Image.heifsave_buffer] | | `heifsave_target` | Save image in heif format | [method@Image.heifsave_target] | | `hist_cum` | Form cumulative histogram | [method@Image.hist_cum] | | `hist_entropy` | Estimate image entropy | [method@Image.hist_entropy] | | `hist_equal` | Histogram equalisation | [method@Image.hist_equal] | | `hist_find` | Find image histogram | [method@Image.hist_find] | | `hist_find_indexed` | Find indexed image histogram | [method@Image.hist_find_indexed] | | `hist_find_ndim` | Find n-dimensional image histogram | [method@Image.hist_find_ndim] | | `hist_ismonotonic` | Test for monotonicity | [method@Image.hist_ismonotonic] | | `hist_local` | Local histogram equalisation | [method@Image.hist_local] | | `hist_match` | Match two histograms | [method@Image.hist_match] | | `hist_norm` | Normalise histogram | [method@Image.hist_norm] | | `hist_plot` | Plot histogram | [method@Image.hist_plot] | | `hough_circle` | Find hough circle transform | [method@Image.hough_circle] | | `hough_line` | Find hough line transform | [method@Image.hough_line] | | `icc_export` | Output to device with icc profile | [method@Image.icc_export] | | `icc_import` | Import from device with icc profile | [method@Image.icc_import] | | `icc_transform` | Transform between devices with icc profiles | [method@Image.icc_transform] | | `identity` | Make a 1d image where pixel values are indexes | [ctor@Image.identity] | | `ifthenelse` | Ifthenelse an image | [method@Image.ifthenelse] | | `insert` | Insert image @sub into @main at @x, @y | [method@Image.insert] | | `invert` | Invert an image | [method@Image.invert] | | `invertlut` | Build an inverted look-up table | [method@Image.invertlut] | | `invfft` | Inverse fft | [method@Image.invfft] | | `join` | Join a pair of images | [method@Image.join] | | `jp2kload` | Load jpeg2000 image | [ctor@Image.jp2kload] | | `jp2kload_buffer` | Load jpeg2000 image | [ctor@Image.jp2kload_buffer] | | `jp2kload_source` | Load jpeg2000 image | [ctor@Image.jp2kload_source] | | `jp2ksave` | Save image in jpeg2000 format | [method@Image.jp2ksave] | | `jp2ksave_buffer` | Save image in jpeg2000 format | [method@Image.jp2ksave_buffer] | | `jp2ksave_target` | Save image in jpeg2000 format | [method@Image.jp2ksave_target] | | `jpegload` | Load jpeg from file | [ctor@Image.jpegload] | | `jpegload_buffer` | Load jpeg from buffer | [ctor@Image.jpegload_buffer] | | `jpegload_source` | Load image from jpeg source | [ctor@Image.jpegload_source] | | `jpegsave` | Save as jpeg | [method@Image.jpegsave] | | `jpegsave_buffer` | Save as jpeg | [method@Image.jpegsave_buffer] | | `jpegsave_mime` | Save image to jpeg mime | [method@Image.jpegsave_mime] | | `jpegsave_target` | Save as jpeg | [method@Image.jpegsave_target] | | `jxlload` | Load jpeg-xl image | [ctor@Image.jxlload] | | `jxlload_buffer` | Load jpeg-xl image | [ctor@Image.jxlload_buffer] | | `jxlload_source` | Load jpeg-xl image | [ctor@Image.jxlload_source] | | `jxlsave` | Save image in jpeg-xl format | [method@Image.jxlsave] | | `jxlsave_buffer` | Save image in jpeg-xl format | [method@Image.jxlsave_buffer] | | `jxlsave_target` | Save image in jpeg-xl format | [method@Image.jxlsave_target] | | `labelregions` | Label regions in an image | [method@Image.labelregions] | | `linear` | Calculate (a * in + b) | [method@Image.linear], [method@Image.linear1] | | `linecache` | Cache an image as a set of lines | [method@Image.linecache] | | `logmat` | Make a laplacian of gaussian image | [ctor@Image.logmat] | | `magickload` | Load file with imagemagick | [ctor@Image.magickload] | | `magickload_buffer` | Load buffer with imagemagick | [ctor@Image.magickload_buffer] | | `magickload_source` | Load source with imagemagick | [ctor@Image.magickload_source] | | `magicksave` | Save file with imagemagick | [method@Image.magicksave] | | `magicksave_buffer` | Save image to magick buffer | [method@Image.magicksave_buffer] | | `mapim` | Resample with a map image | [method@Image.mapim] | | `maplut` | Map an image though a lut | [method@Image.maplut] | | `mask_butterworth` | Make a butterworth filter | [ctor@Image.mask_butterworth] | | `mask_butterworth_band` | Make a butterworth_band filter | [ctor@Image.mask_butterworth_band] | | `mask_butterworth_ring` | Make a butterworth ring filter | [ctor@Image.mask_butterworth_ring] | | `mask_fractal` | Make fractal filter | [ctor@Image.mask_fractal] | | `mask_gaussian` | Make a gaussian filter | [ctor@Image.mask_gaussian] | | `mask_gaussian_band` | Make a gaussian filter | [ctor@Image.mask_gaussian_band] | | `mask_gaussian_ring` | Make a gaussian ring filter | [ctor@Image.mask_gaussian_ring] | | `mask_ideal` | Make an ideal filter | [ctor@Image.mask_ideal] | | `mask_ideal_band` | Make an ideal band filter | [ctor@Image.mask_ideal_band] | | `mask_ideal_ring` | Make an ideal ring filter | [ctor@Image.mask_ideal_ring] | | `match` | First-order match of two images | [method@Image.match] | | `math` | Apply a math operation to an image | [method@Image.math], [method@Image.sin], [method@Image.cos], [method@Image.tan], [method@Image.asin], [method@Image.acos], [method@Image.atan], [method@Image.sinh], [method@Image.cosh], [method@Image.tanh], [method@Image.asinh], [method@Image.acosh], [method@Image.atanh], [method@Image.exp], [method@Image.exp10], [method@Image.log], [method@Image.log10] | | `math2` | Binary math operations | [method@Image.math2], [method@Image.pow], [method@Image.wop], [method@Image.atan2] | | `math2_const` | Binary math operations with a constant | [method@Image.math2_const], [method@Image.andimage_const], [method@Image.orimage_const], [method@Image.eorimage_const], [method@Image.lshift_const], [method@Image.rshift_const], [method@Image.math2_const1], [method@Image.andimage_const1], [method@Image.orimage_const1], [method@Image.eorimage_const1], [method@Image.lshift_const1], [method@Image.rshift_const1] | | `matload` | Load mat from file | [ctor@Image.matload] | | `matrixinvert` | Invert a matrix | [method@Image.matrixinvert] | | `matrixload` | Load matrix | [ctor@Image.matrixload] | | `matrixload_source` | Load matrix | [ctor@Image.matrixload_source] | | `matrixmultiply` | Multiply two matrices | [method@Image.matrixmultiply] | | `matrixprint` | Print matrix | [method@Image.matrixprint] | | `matrixsave` | Save image to matrix | [method@Image.matrixsave] | | `matrixsave_target` | Save image to matrix | [method@Image.matrixsave_target] | | `max` | Find image maximum | [method@Image.max] | | `maxpair` | Maximum of a pair of images | [method@Image.maxpair] | | `measure` | Measure a set of patches on a color chart | [method@Image.measure] | | `merge` | Merge two images | [method@Image.merge] | | `min` | Find image minimum | [method@Image.min] | | `minpair` | Minimum of a pair of images | [method@Image.minpair] | | `morph` | Morphology operation | [method@Image.morph] | | `mosaic` | Mosaic two images | [method@Image.mosaic] | | `mosaic1` | First-order mosaic of two images | [method@Image.mosaic1] | | `msb` | Pick most-significant byte from an image | [method@Image.msb] | | `multiply` | Multiply two images | [method@Image.multiply] | | `niftiload` | Load nifti volume | [ctor@Image.niftiload] | | `niftiload_source` | Load nifti volumes | [ctor@Image.niftiload_source] | | `niftisave` | Save image to nifti file | [method@Image.niftisave] | | `openexrload` | Load an openexr image | [ctor@Image.openexrload] | | `openslideload` | Load file with openslide | [ctor@Image.openslideload] | | `openslideload_source` | Load source with openslide | [ctor@Image.openslideload_source] | | `pdfload` | Load pdf from file | [ctor@Image.pdfload] | | `pdfload_buffer` | Load pdf from buffer | [ctor@Image.pdfload_buffer] | | `pdfload_source` | Load pdf from source | [ctor@Image.pdfload_source] | | `percent` | Find threshold for percent of pixels | [method@Image.percent] | | `perlin` | Make a perlin noise image | [ctor@Image.perlin] | | `phasecor` | Calculate phase correlation | [method@Image.phasecor] | | `pngload` | Load png from file | [ctor@Image.pngload] | | `pngload_buffer` | Load png from buffer | [ctor@Image.pngload_buffer] | | `pngload_source` | Load png from source | [ctor@Image.pngload_source] | | `pngsave` | Save image to file as png | [method@Image.pngsave] | | `pngsave_buffer` | Save image to buffer as png | [method@Image.pngsave_buffer] | | `pngsave_target` | Save image to target as png | [method@Image.pngsave_target] | | `ppmload` | Load ppm from file | [ctor@Image.ppmload] | | `ppmload_buffer` | Load ppm from buffer | [ctor@Image.ppmload_buffer] | | `ppmload_source` | Load ppm from source | [ctor@Image.ppmload_source] | | `ppmsave` | Save image to ppm file | [method@Image.ppmsave] | | `ppmsave_target` | Save to ppm | [method@Image.ppmsave_target] | | `premultiply` | Premultiply image alpha | [method@Image.premultiply] | | `prewitt` | Prewitt edge detector | [method@Image.prewitt] | | `profile` | Find image profiles | [method@Image.profile] | | `profile_load` | Load named icc profile | [ctor@Blob.profile_load] | | `project` | Find image projections | [method@Image.project] | | `quadratic` | Resample an image with a quadratic transform | [method@Image.quadratic] | | `rad2float` | Unpack radiance coding to float rgb | [method@Image.rad2float] | | `radload` | Load a radiance image from a file | [ctor@Image.radload] | | `radload_buffer` | Load rad from buffer | [ctor@Image.radload_buffer] | | `radload_source` | Load rad from source | [ctor@Image.radload_source] | | `radsave` | Save image to radiance file | [method@Image.radsave] | | `radsave_buffer` | Save image to radiance buffer | [method@Image.radsave_buffer] | | `radsave_target` | Save image to radiance target | [method@Image.radsave_target] | | `rank` | Rank filter | [method@Image.rank], [method@Image.median] | | `rawload` | Load raw data from a file | [ctor@Image.rawload] | | `rawsave` | Save image to raw file | [method@Image.rawsave] | | `rawsave_buffer` | Write raw image to buffer | [method@Image.rawsave_buffer] | | `rawsave_target` | Write raw image to target | [method@Image.rawsave_target] | | `recomb` | Linear recombination with matrix | [method@Image.recomb] | | `reduce` | Reduce an image | [method@Image.reduce] | | `reduceh` | Shrink an image horizontally | [method@Image.reduceh] | | `reducev` | Shrink an image vertically | [method@Image.reducev] | | `relational` | Relational operation on two images | [method@Image.relational], [method@Image.equal], [method@Image.notequal], [method@Image.less], [method@Image.lesseq], [method@Image.more], [method@Image.moreeq] | | `relational_const` | Relational operations against a constant | [method@Image.relational_const], [method@Image.equal_const], [method@Image.notequal_const], [method@Image.less_const], [method@Image.lesseq_const], [method@Image.more_const], [method@Image.moreeq_const], [method@Image.relational_const1], [method@Image.equal_const1], [method@Image.notequal_const1], [method@Image.less_const1], [method@Image.lesseq_const1], [method@Image.more_const1], [method@Image.moreeq_const1] | | `remainder` | Remainder after integer division of two images | [method@Image.remainder] | | `remainder_const` | Remainder after integer division of an image and a constant | [method@Image.remainder_const], [method@Image.remainder_const1] | | `remosaic` | Rebuild an mosaiced image | [method@Image.remosaic] | | `replicate` | Replicate an image | [method@Image.replicate] | | `resize` | Resize an image | [method@Image.resize] | | `rot` | Rotate an image | [method@Image.rot] | | `rot45` | Rotate an image | [method@Image.rot45] | | `rotate` | Rotate an image by a number of degrees | [method@Image.rotate] | | `round` | Perform a round function on an image | [method@Image.round], [method@Image.floor], [method@Image.ceil], [method@Image.rint] | | `sRGB2HSV` | Transform srgb to hsv | [method@Image.sRGB2HSV] | | `sRGB2scRGB` | Convert an srgb image to scrgb | [method@Image.sRGB2scRGB] | | `scRGB2BW` | Convert scrgb to bw | [method@Image.scRGB2BW] | | `scRGB2XYZ` | Transform scrgb to xyz | [method@Image.scRGB2XYZ] | | `scRGB2sRGB` | Convert scrgb to srgb | [method@Image.scRGB2sRGB] | | `scale` | Scale an image to uchar | [method@Image.scale] | | `scharr` | Scharr edge detector | [method@Image.scharr] | | `sdf` | Create an sdf image | [ctor@Image.sdf] | | `sequential` | Check sequential access | [method@Image.sequential] | | `sharpen` | Unsharp masking for print | [method@Image.sharpen] | | `shrink` | Shrink an image | [method@Image.shrink] | | `shrinkh` | Shrink an image horizontally | [method@Image.shrinkh] | | `shrinkv` | Shrink an image vertically | [method@Image.shrinkv] | | `sign` | Unit vector of pixel | [method@Image.sign] | | `similarity` | Similarity transform of an image | [method@Image.similarity] | | `sines` | Make a 2d sine wave | [ctor@Image.sines] | | `smartcrop` | Extract an area from an image | [method@Image.smartcrop] | | `sobel` | Sobel edge detector | [method@Image.sobel] | | `spcor` | Spatial correlation | [method@Image.spcor] | | `spectrum` | Make displayable power spectrum | [method@Image.spectrum] | | `stats` | Find many image stats | [method@Image.stats] | | `stdif` | Statistical difference | [method@Image.stdif] | | `subsample` | Subsample an image | [method@Image.subsample] | | `subtract` | Subtract two images | [method@Image.subtract] | | `sum` | Sum an array of images | [func@Image.sum] | | `svgload` | Load svg with rsvg | [ctor@Image.svgload] | | `svgload_buffer` | Load svg with rsvg | [ctor@Image.svgload_buffer] | | `svgload_source` | Load svg from source | [ctor@Image.svgload_source] | | `switch` | Find the index of the first non-zero pixel in tests | [func@Image.switch] | | `system` | Run an external command | [ctor@Image.system] | | `text` | Make a text image | [ctor@Image.text] | | `thumbnail` | Generate thumbnail from file | [ctor@Image.thumbnail] | | `thumbnail_buffer` | Generate thumbnail from buffer | [ctor@Image.thumbnail_buffer] | | `thumbnail_image` | Generate thumbnail from image | [method@Image.thumbnail_image] | | `thumbnail_source` | Generate thumbnail from source | [ctor@Image.thumbnail_source] | | `tiffload` | Load tiff from file | [ctor@Image.tiffload] | | `tiffload_buffer` | Load tiff from buffer | [ctor@Image.tiffload_buffer] | | `tiffload_source` | Load tiff from source | [ctor@Image.tiffload_source] | | `tiffsave` | Save image to tiff file | [method@Image.tiffsave] | | `tiffsave_buffer` | Save image to tiff buffer | [method@Image.tiffsave_buffer] | | `tiffsave_target` | Save image to tiff target | [method@Image.tiffsave_target] | | `tilecache` | Cache an image as a set of tiles | [method@Image.tilecache] | | `tonelut` | Build a look-up table | [ctor@Image.tonelut] | | `transpose3d` | Transpose3d an image | [method@Image.transpose3d] | | `uhdr2scRGB` | Transform uhdr to scrgb | [method@Image.uhdr2scRGB] | | `uhdrload` | Load a uhdr image | [ctor@Image.uhdrload] | | `uhdrload_buffer` | Load a uhdr image | [ctor@Image.uhdrload_buffer] | | `uhdrload_source` | Load a uhdr image | [ctor@Image.uhdrload_source] | | `uhdrsave` | Save image in ultrahdr format | [method@Image.uhdrsave] | | `uhdrsave_buffer` | Save image in ultrahdr format | [method@Image.uhdrsave_buffer] | | `uhdrsave_target` | Save image in ultrahdr format | [method@Image.uhdrsave_target] | | `unpremultiply` | Unpremultiply image alpha | [method@Image.unpremultiply] | | `vipsload` | Load vips from file | [ctor@Image.vipsload] | | `vipsload_source` | Load vips from source | [ctor@Image.vipsload_source] | | `vipssave` | Save image to file in vips format | [method@Image.vipssave] | | `vipssave_target` | Save image to target in vips format | [method@Image.vipssave_target] | | `webpload` | Load webp from file | [ctor@Image.webpload] | | `webpload_buffer` | Load webp from buffer | [ctor@Image.webpload_buffer] | | `webpload_source` | Load webp from source | [ctor@Image.webpload_source] | | `webpsave` | Save as webp | [method@Image.webpsave] | | `webpsave_buffer` | Save as webp | [method@Image.webpsave_buffer] | | `webpsave_mime` | Save image to webp mime | [method@Image.webpsave_mime] | | `webpsave_target` | Save as webp | [method@Image.webpsave_target] | | `worley` | Make a worley noise image | [ctor@Image.worley] | | `wrap` | Wrap image origin | [method@Image.wrap] | | `xyz` | Make an image where pixel values are coordinates | [ctor@Image.xyz] | | `zone` | Make a zone plate | [ctor@Image.zone] | | `zoom` | Zoom an image | [method@Image.zoom] | libvips-8.18.2/doc/gen-function-list.py000077500000000000000000000124641516303661500177660ustar00rootroot00000000000000#!/usr/bin/env python3 # walk vips and generate a list of all operators and their descriptions # for docs # this needs pyvips # pip install --user pyvips # rebuild with: # ./gen-function-list.py > function-list.md # sample output: # | `gamma` | Gamma an image | [method@Image.gamma] | from pyvips import Introspect, Operation, Error, \ ffi, type_map, type_from_name, nickname_find # for VipsOperationFlags _OPERATION_DEPRECATED = 8 def gen_function(operation_name, overloads): intro = Introspect.get(operation_name) # Keep-in-sync with fixup-gir-for-doc.py image_funcs = [ 'arrayjoin', 'bandjoin', 'bandrank', 'composite', 'sum', 'switch', ] if operation_name in image_funcs: c_operations = f'[func@Image.{operation_name}]' else: operation_type = 'ctor' if intro.member_x is None else 'method' operation_class = 'Blob' if operation_name == 'profile_load' else 'Image' c_operations = f'[{operation_type}@{operation_class}.{operation_name}]' if overloads: c_operations += ', ' + (', '.join(f'[method@Image.{n}]' for n in overloads)) description = intro.description.capitalize() # hide library-specific implementation details description = (description .replace('imagemagick7', 'imagemagick') .replace(' (pdfium)', '') .replace(' (poppler)', '')) result = f"| `{operation_name}` | {description} | {c_operations} |" return result def gen_function_list(): all_nicknames = [] def add_nickname(gtype, a, b): nickname = nickname_find(gtype) try: # can fail for abstract types intro = Introspect.get(nickname) # we are only interested in non-deprecated operations if (intro.flags & _OPERATION_DEPRECATED) == 0: all_nicknames.append(nickname) except Error: pass type_map(gtype, add_nickname) return ffi.NULL type_map(type_from_name('VipsOperation'), add_nickname) # make list unique and sort all_nicknames = list(set(all_nicknames)) all_nicknames.sort() # make dict with overloads overloads = { 'bandbool': ['bandand', 'bandor', 'bandeor', 'bandmean'], 'bandjoin': ['bandjoin2'], 'bandjoin_const': ['bandjoin_const1'], 'boolean': ['andimage', 'orimage', 'eorimage', 'lshift', 'rshift'], 'cast': ['cast_uchar', 'cast_char', 'cast_ushort', 'cast_short', 'cast_uint', 'cast_int', 'cast_float', 'cast_double', 'cast_complex', 'cast_dpcomplex'], 'complex': ['polar', 'rect', 'conj'], 'complex2': ['cross_phase'], 'complexget': ['real', 'imag'], 'draw_circle': ['draw_circle1'], 'draw_flood': ['draw_flood1'], 'draw_line': ['draw_line1'], 'draw_mask': ['draw_mask1'], 'draw_rect': ['draw_rect1', 'draw_point', 'draw_point1'], 'extract_area': ['crop'], 'linear': ['linear1'], 'math': ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', 'exp', 'exp10', 'log', 'log10'], 'math2': ['pow', 'wop', 'atan2'], 'rank': ['median'], 'relational': ['equal', 'notequal', 'less', 'lesseq', 'more', 'moreeq'], 'remainder_const': ['remainder_const1'], 'round': ['floor', 'ceil', 'rint'], } overloads['boolean_const'] = \ [o + '_const' for o in overloads['boolean']] \ + ['boolean_const1'] \ + [o + '_const1' for o in overloads['boolean']] overloads['math2_const'] = \ [o + '_const' for o in overloads['boolean']] \ + ['math2_const1'] \ + [o + '_const1' for o in overloads['boolean']] overloads['relational_const'] = \ [o + '_const' for o in overloads['relational']] \ + ['relational_const1'] \ + [o + '_const1' for o in overloads['relational']] for nickname in all_nicknames: result = gen_function(nickname, overloads[nickname] if nickname in overloads else None) print(result) if __name__ == '__main__': print("""Title: Operator index / Alphabetical libvips has a set of operators, each of which computes some useful image processing operation. Each operator is implemented as a [class@GObject.Object] class, for example `VipsGamma`. Classes are identified by their unique [property@VipsObject:nickname], in this case `gamma`. From the command-line, C++ and most language bindings, you use the nickname to call the operator. For example in C++: ```c++ vips::VImage fred = ...; vips::VImage jim = fred.gamma(); ``` or Python: ```python fred = jim.gamma() ``` libvips has a set of C wrapper functions for calling operators, in this case [method@Image.gamma]: ```c VipsImage *fred = ...; VipsImage *jim; if (vips_gamma(fred, &jim, NULL)) ...error; ``` Some operators have many C convenience functions. # All libvips operators This table lists all the libvips operators with their C convenience functions and a short description. It's supposed to be useful for searching. See the API docs each function links to for more details. | Operator | Description | C functions | | -------- | ----------- | ----------- |""") gen_function_list() libvips-8.18.2/doc/how-it-opens-files.md000066400000000000000000000116761516303661500200230ustar00rootroot00000000000000Title: Technical background > Opening files libvips has at least four different ways of opening image files, each best for different file types, file sizes and image use cases. libvips tries hard to pick the best strategy in each case and mostly you don't need to know what it is doing behind the scenes, except unfortunately when you do. This page tries to explain what the different strategies are and when each is used. If you are running into unexpected memory, disc or CPU use, this might be helpful. [ctor@Image.new_from_file] has the official documentation. ## Caching libvips caches recent operations. This means that if a file changes between one load and the next, the second load will return the old image, even though the file has been replaced. You can force libvips to load a file and ignore any cached value by setting the `revalidate` flag, see [class@ForeignLoad]. ## Direct access This is the fastest and simplest one. The file is mapped directly into the process's address space and can be read with ordinary pointer access. Small files are completely mapped; large files are mapped in a series of small windows that are shared and which scroll about as pixels are read. Files which are accessed like this can be read by many threads at once, making them especially quick. They also interact well with the computer's operating system: your OS will use spare memory to cache recently used chunks of the file. For this to be possible, the file format needs to be a simple dump of a memory array. libvips supports direct access for `.v`, 8-bit binary ppm/pbm/pnm, analyse and raw. libvips has a special direct write mode where pixels can be written directly to the file image. This is used for the [draw operations](libvips-draw.html). ## Random access via load library Some image file formats have libraries which allow true random access to image pixels. For example, libtiff lets you read any tile out of a tiled tiff image very quickly. Because the libraries allow true random access, libvips can simply hook the image load library up to the input of the operation pipeline. These libraries are generally single-threaded, so only one thread may read at once, making them slower than simple direct access. Additionally, tiles are often compressed, meaning that each time a tile is fetched it must be decompressed. libvips keeps a cache of recently-decompressed tiles to try to avoid repeatedly decompressing the same tile. libvips can load tiled tiff, tiled OpenEXR, FITS and OpenSlide images in this manner. ## Full decompression Many image load libraries do not support random access. In order to use images of this type as inputs to pipelines, libvips has to convert them to a random access format first. For small images (less than 100mb when decompressed), libvips allocates a large area of memory and decompresses the entire image to that. It then uses that memory buffer of decompressed pixels to feed the pipeline. For large images, libvips decompresses to a temporary file on disc, then loads that temporary file in direct access mode (see above). Note that on open libvips just reads the image header and is quick: the image decompress happens on the first pixel access. You can control this process with environment variables, command-line flags and API calls as you choose, see [ctor@Image.new_from_file]. They let you set the threshold at which libvips switches between memory and disc and where on disc the temporary files are held. This is the slowest and most memory-hungry way to read files, but it's unavoidable for many file formats. Unless you can use the next one! ## Sequential access This a fairly recent addition to libvips and is a hybrid of the previous two. Imagine how this command might be executed: ```bash $ vips flip fred.jpg jim.jpg vertical ``` meaning, read `fred.jpg`, flip it up-down, and write as `jim.jpg`. In order to write `jim.jpg` top-to-bottom, it'll have to read `fred.jpg` bottom-to-top. Unfortunately libjpeg only supports top-to-bottom reading and writing, so libvips must convert `fred.jpg` to a random access format before it can run the flip operation. However many useful operations do not require true random access. For example: ```bash $ vips shrink fred.png jim.png 10 10 ``` meaning shrink `fred.png` by a factor of 10 in both axes and write as `jim.png`. You can imagine this operation running without needing `fred.png` to be completely decompressed first. You just read 10 lines from `fred.png` for every one line you write to `jim.png`. To help in this case, libvips has a hint you can give to loaders to say "I will only need pixels from this image in top-to-bottom order". With this hint set, libvips will hook up the pipeline of operations directly to the read-a-line interface provided by the image library, and add a small cache of the most recent 100 or so lines. This is done automatically in command-line operation. In programs, you need to set `access` to #VIPS_ACCESS_SEQUENTIAL in calls to functions like [ctor@Image.new_from_file]. libvips-8.18.2/doc/how-it-works.md000066400000000000000000000322331516303661500167340ustar00rootroot00000000000000Title: Technical background > Evaluation Compared to most image processing libraries, libvips needs little RAM and runs quickly, especially on machines with more than one CPU. libvips achieves this improvement by only keeping the pixels currently being processed in RAM and by having an efficient, threaded image IO system. This page explains how these features are implemented. ## Images libvips images have three dimensions: width, height and bands. Bands usually (though not always) represent colour. These three dimensions can be any size up to 2 ** 31 elements. Every band element in an image has to have the same format. A format is an 8-, 16- or 32-bit int, signed or unsigned, 32- or 64-bit float, and 64- or 128-bit complex. ## Regions An image can be very large, much larger than the available memory, so you can't just access pixels with a pointer \*. Instead, you read pixels from an image with a region. This is a rectangular sub-area of an image. In C, the API looks like: ```c VipsImage *image = vips_image_new_from_file(filename, NULL); VipsRegion *region = vips_region_new(image); // ask for a 100x100 pixel region at 0x0 (top left) VipsRect r = { .left = 0, .top = 0, .width = 100, .height = 100 }; if (vips_region_prepare(region, &r)) vips_error(...); // get a pointer to the pixel at x, y, where x, y must // be within the region // as long as you stay within the valid area for the region, // you can address pixels with regular pointer arithmetic // compile with -DDEBUG and the macro will check bounds for you // add VIPS_REGION_LSKIP() to move down a line VipsPel *pixel = VIPS_REGION_ADDR(region, x, y); // you can call vips_region_prepare() many times // everything in libvips is a GObject ... when you're done, // just free with g_object_unref(region); ``` The action that [method@Region.prepare] takes varies with the type of image. If the image is a file on disc, for example, then libvips will arrange for a section of the file to be read in. (\* there is an image access mode where you can just use a pointer, but it's rarely used) ## Partial images A partial image is one where, instead of storing a value for each pixel, libvips stores a function which can make any rectangular area of pixels on demand. If you use [method@Region.prepare] on a region created on a partial image, libvips will allocate enough memory to hold the pixels you asked for and use the stored function to calculate values for just those pixels \*. The stored function comes in three parts: a start function, a generate function and a stop function. The start function creates a state, the generate function uses the state plus a requested area to calculate pixel values and the stop function frees the state again. Breaking the stored function into three parts is good for SMP scaling: resource allocation and synchronisation mostly happens in start functions, so generate functions can run without having to talk to each other. libvips makes a set of guarantees about parallelism that make this simple to program. Start and stop functions are mutually exclusive and a state is never used by more than one generate. In other words, a start / generate / generate / stop sequence works like a thread. ![Sequence](Sequence.png) (\* in fact libvips keeps a cache of calculated pixel buffers and will return a pointer to a previously-calculated buffer if it can) # Operations libvips operations read input images and write output images, performing some transformation on the pixels. When an operation writes to an image the action it takes depends upon the image type. For example, if the image is a file on disc then libvips will start a data sink to stream pixels to the file, or if the image is a partial one then it will just attach start / generate / stop functions. Like most threaded image processing systems, all libvips operations have to be free of side-effects. In other words, operations cannot modify images, they can only create new images. This could result in a lot of copying if an operation is only making a small change to a large image so libvips has a set of mechanisms to copy image areas by just adjusting pointers. Most of the time no actual copying is necessary and you can perform operations on large images at low cost. ## SIMD optimisations libvips uses [Highway](https://github.com/google/highway), a C++ library, to optimise various operations with SIMD/vector instructions. These optimised code paths are flexible and can adapt to different instruction sets, including those with 'scalable' vectors (size unknown at compile time). At runtime, dynamic dispatch selects the best available implementation based on the processor's capabilities, ensuring optimal performance. SIMD typically speeds operations up by a factor of three or four. ## Joining operations together The region create / prepare / prepare / free calls you use to get pixels from an image are an exact parallel to the start / generate / generate / stop calls that images use to create pixels. In fact, they are the same: a region on a partial image holds the state created by that image for the generate function that will fill the region with pixels. ![Combine](Combine.png) libvips joins image processing operations together by linking the output of one operation (the start / generate / stop sequence) to the input of the next (the region it uses to get pixels for processing). This link is a single function call, and very fast. Additionally, because of the the split between allocation and processing, once a pipeline of operations has been set up, libvips is able to run without allocating and freeing memory. This graph (generated by `vipsprofile`, the libvips profiler) shows memory use over time for a libvips pipeline running on a large image. The bottom trace shows total memory, the upper traces show threads calculating useful results (green), threads blocked on synchronisation (red) and memory allocations (white ticks). ![Memtrace](Memtrace.png) Because the intermediate image is just a small region in memory, a pipeline of operations running together needs very little RAM. In fact, intermediates are small enough that they can fit in L2 cache on most machines, so an entire pipeline can run without touching main memory. And finally, because each thread runs a very cheap copy of just the writeable state of the entire pipeline, threads can run with few locks. libvips needs just four lock operations per output tile, regardless of the pipeline length or complexity. ## Data sources libvips has data sources which can supply pixels for processing from a variety of sources. libvips can stream images from files in libvips native format, from tiled TIFF files, from binary PPM/PGM/PBM/PFM, from Radiance (HDR) files, from FITS images and from tiled OpenEXR images. libvips will automatically unpack other formats to temporary disc files for you but this can obviously generate a lot of disc traffic. It also has a special sequential mode for streaming operations on non-random-access formats. Another section in these docs explains [how libvips opens files]( how-it-opens-files.html). One of the sources uses the [ImageMagick]( https://imagemagick.org/) (or optionally [GraphicsMagick]( http://graphicsmagick.org)) library, so libvips can read any image format that these libraries can read. libvips images are held on disc as a 64-byte header containing basic image information like width, height, bands and format, then the image data as a single large block of pixels, left-to-right and top-to-bottom, then an XML extension block holding all the image metadata, such as ICC profiles and EXIF blocks. When reading from a large libvips image (or any other format with the same structure on disc, such as binary PPM), libvips keeps a set of small rolling windows into the file, some small number of scanlines in size. As pixels are demanded by different threads libvips will move these windows up and down the file. As a result, libvips can process images much larger than RAM, even on 32-bit machines. ## Data sinks In a demand-driven system, something has to do the demanding. libvips has a variety of data sinks that you can use to pull image data though a pipeline in various situations. There are sinks that will build a complete image in memory, sinks to draw to a display, sinks to loop over an image (useful for statistical operations, for example) and sinks to stream an image to disc. The disc sink looks something like this: ![Sink](Sink.png) The sink keeps two buffers\*, each as wide as the image. It starts threads as rapidly as it can up to the concurrency limit, filling each buffer with tiles\*\* of calculated pixels, each thread calculating one tile at once. A separate background thread watches each buffer and, as soon as the last tile in a buffer finishes, writes that complete set of scanlines to disc using whatever image write library is appropriate. libvips can write with libjpeg, libtiff, libpng and others. It then wipes the buffer and repositions it further down the image, ready for the next set of tiles to stream in. These features in combination mean that, once a pipeline of image processing operations has been built, libvips can run almost lock-free. This is very important for SMP scaling: you don't want the synchronization overhead to scale with either the number of threads or the complexity of the pipeline of operations being performed. As a result, libvips scales almost linearly with increasing numbers of threads: ![SMP scaling](Vips-smp.png) Number of CPUs is on the horizontal axis, speedup is on the vertical axis. Taken from the [[Benchmarks]] page. (\* there can actually be more than one, it allocate enough buffers to ensure that there are at least two tiles for every thread) (\*\* tiles can be any shape and size, libvips has a tile hint system that operations use to tell sinks what tile geometry they prefer) ## Operation cache Because libvips operations are free of side-effects\*, you can cache them. Every time you call an operation, libvips searches the cache for a previous call to the same operation with the same arguments. If it finds a match, you get the previous result again. This can give a huge speedup. By default, libvips caches the last 100 operation calls. You can also control the cache size by memory use or by files opened. (\* Some libvips operations DO have side effects, for example, [method@Image.draw_circle] will draw a circle on an image. These operations emit an "invalidate" signal on the image they are called on and this signal makes all downstream operations and caches drop their contents.) ## Operation database and APIs libvips has around 300 image processing operations written in this style. Each operation is a GObject class. You can use the standard GObject calls to walk the class hierarchy and discover operations, and libvips adds a small amount of extra introspection metadata to handle things like optional arguments. The [C API](using-from-c.md) is a set of simple wrappers which create class instances for you. The [C++ API](using-from-cplusplus.md) is a little fancier and adds things like automatic object lifetime management. The [command-line interface](using-the-cli.md) uses introspection to run any libvips operation in the class hierarchy. There are bindings for [many other languages](https://www.libvips.org/) on many platforms. Most of these bindings use the introspection system to generate the binding at run-time. ## Snip The libvips GUI, nip2, has its own scripting language called Snip. Snip is a lazy, higher-order, purely functional, object oriented language. Almost all of nip2's menus are implemented in it, and nip2 workspaces are Snip programs. libvips operations listed in the operation database appear as Snip functions. For example, `abs` can be used from Snip as: ``` // absolute value of image b a = vips_call "abs" [b] []; ``` However, `abs` won't work on anything except the primitive `.v` image type. It can't be used on any class, or list or number. Definitions in `_stdenv.dev` wrap each libvips operation as a higher level Snip operation. For example: ``` abs x = oo_unary_function abs_op x, is_class x = vips_call "abs" [x] [], is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } ``` This defines the behaviour of `abs` for the base Snip types (number, list, matrix, image and so on), then classes will use that to define operator behaviour on higher-level objects. Now you can use: ``` // absolute value of anything a = abs b; ``` and you ought to get sane behaviour for any object, including things like the `Matrix` class. You can write Snip classes which present functions to the user as menu items. For example, `Math.def` has this: ``` Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } } ``` Now the user can select an object and click `Math / Abs` to find the absolute value of that object. libvips-8.18.2/doc/images/000077500000000000000000000000001516303661500153025ustar00rootroot00000000000000libvips-8.18.2/doc/images/Combine.png000066400000000000000000000312031516303661500173630ustar00rootroot00000000000000PNG  IHDR?kPsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwgo7; R4b[ bEMlXK,1[?5FMK 4 p;Wa;ߙ{YY\yyCbT硚&5ڻ"""] hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">`{7@ږ@/go]tmnJi N`sEipά^q@vV+ιo[ҡDZzVZ0_wr=PulB[5VC| (6$AeH&GuXi)m޼1/^ ۯ4>r-L˃;_ʚDx;fv p,0̞~[ʫ">i{ =̼9wyUUnR]׬Vee_Uؖԯ ] Ue(ӀSz.)ރ_C"%.]ϭUe0/997VM$63;N3DO7ˊ{ϯZ2lHNwI]mu.ނyuHH9vicZ/9YS}Ӂfvsnͮ/yTS3Ԓ%=׭ߔYkJM~`εqb}_eC1f$s FZbȪ>sp 3luVMXS.TS+PI?Wz,LwlLM:8Ք?(;~Lo?1 #^}n-73gFCnH뇋/gFY{i )P@wPe/>{>HJQ?pU6Dඅph.rYm)HKRMzT4ϖqB  .E"ag`TS"] eoqYEbb Zio$M}絇z!Ͽ5ujJ:-t⳷->{G+*vmwkzN̓q+}UqmoMՔt> fcYaofe}uy0 p - w|FU/>}%(H;M ĩQ@w0>{5ǹ%iI< -ƆKRF|{~!}qicj@5%7̃ks1!)˗ΪR֚:5u|sQP63S7o\Y9S*clH9N:nw6p: mRSC͙'I)]fvuief6gt; ).IٴkW/LރT7+ݑÆXMJNJP)i]TgC@vjiY0fGt7vEo}r@C6{lN)LK 5dC^YKL~פjB¯glk]̜KH^XVk"{o=vrN-Vr:;Tr ϼz$79`I'ac%$WWWMIcsdι^ 1OkǁޯQ{>0f E}8s+' dzv82Dp `49~Zb3Oe|mzf7^?|v]˹7֬ܲ2.y ˩hNWf =ˊY=yf={Gtm sjT1h͚:ԝxM={B Gիp8}ffߘf0I3̖f4ߙR3[kfefY3rmf֏v[{X=jrsIK3ڻD,..jC ft[`F瞸)4pȒh=lθ ~去*7|=?\s͕鑗^b<л7:?1/Kw0;( 4l^1A{6m,N\`FMC5U[j3,{V~sCh7ύ)+jJb望>uhS u]oaej0~-pb&n~ qH@Q1ޯwwD#PR@vN}lEvKǨ驠E3rM| ͻ4Ϲ *hэi E PBmՔt: fC6vX/]bؽZbSjK{ܖY.]SSՔt. &ÎԾ-htvo 'è o mw}֦(Ք(;U} HUe^?oՊwm^?šѦ9LՔ?ɥ>s˃@'=-Ï?Kzp#9_\kC̔G011{ޜ;RXyxiZι\ 5ZWg\u֚kIݔ-ޫgqt跫vY_]֯{#}]aȰ_ݑ lp8xT(}q=pJ{tAZ_gn)ݲS}Ev$ةލ>S *Km%Pu\q+?ե dMEk ;r.6-v/SsoskՕ6z5ujJvv#>hFHP6q ?狷z6Y=$9Q{RH , gaH(ݢ~[L{tjj6r ލ.ow^{7 ?XV)t}ژTSQgeW^޷^d` o7Kfkn4 09'dIǠi N䄓X^n03@P:BJHTS"G݉9ޞ͆nTS"-G*!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!ۻ1>q;#:dfdĥuMKZU~FT5gm{YM5%-NhMٴ83ҳӣ^CN)wHU4Y|N5%c hi 혴:Z ݫg5uݺW[ BAj-?|:"S:ǀX'i_))e]n}f8<Nʃ)Őඟ/+r@pmVBEk +IK_~>y'qP+jJ$v hi < {.ekwk\0ed\yrM$Rm%%ߝK}K<GUʈ/DCtm]8nSEmrkOeuIGfz{%~5\⿳g2tqqI./+/PtgʆKXVtT5Yt.X:Q^>@qW)?}+~t=oڜqLgg {} W%V5H5պTSTgAKCeC:i9|[D39됚6v>oHN]wޛh֣E ḫ.ޘu@CpzvIJZ?yK~TS"G-ٱ޳?g=. 7`?#=u-mx:TS"OəYp?>fw6l8g~$..=R]Uܓ7jDvjJe(J?<԰R b:$ .3-DZ3lˤE0ap|p!Эٕ)^~Hd?PMtk :F6{;>nP*y[~*;TS"-DI{Ϧ΃Ai)nw.פT0g曹m.SMuiQ8O͑3ĕfUWU%%XUDZ;?6BZhO􆬜 @(T7]iA =ye6)ޟC҂Rv٫W nn@]=ij~vs>Et"nkMX#㓎8<>)9PM0;1>ԾS쬝ffgفEޓ̙N_?tQGpZA#~kG vEX`gѣ{ pU/6|Vu)i¯?W pZjkXScO攜 5\]r?jb7VM*8 iGgk۶iafw?afG+ ǟ53g{Ƈܫ|cpZafܺMx{)M%aH2ecAy3`7uΨs[asڵOϵc]^aXtg}>>xO+FTpi]{6ԪUSmZiL|/^|"nTS{&ܛf6snbi;Y9 䜫0@9.:7,uE ^k}Khuιpt+ ]rrzWN([93zC||⑗Bֹicz}"gCd?_|1>8z4kj fd\{}E:5k¡xc_Ĥ!Dܖ`MIM1bݷdN{տ{ 1PpAScoIǚ*)D7br. fgt1+)qMj;6ιj`2pc0H4)ιEf Xwrdzt3XwY`9l+>V]\ks^A$gwݗw7ƀe49aY?G>O<8ߞux^yNnz֬ګR~M N7'oﵵqۿm˗~ɛ#=z}oγC-R5pIs憪J"XnKԔ~/y#[s٣x|s.lfû@10<mf< \{hqf \Y)?W TU #O١O_q1%?j;x:3gd2*^{3RSͪ*6nnwcI)!bTSE0ILJ '$}gTS[RSf5]S'>vL0_ZW{RM.y9W `fG5KL;hOK-şIDATpsf6̎r} k~9>naf<7t#n׬iv승k I}GR/>}H`68`~/2v%m-KKٔN<3l/*SS̪n\oSS6 ..rU s->>1srqŧ{+Wv555,^޾#Sp kin_qŮ'^Ԝ*< 9w5!t̓gr}kfOϛ]@Nfn c[׷ХMM看R`_  x8hX9\uTWc~f&I#FJ^~ 0xrXpƊrjjچxz޸)egZFn~Mmpm/`\s}h7K}v^/zʲƽzpZ޽CaK)'G9M?)=  _>fjg  {tI$7ՔH t'ss޳9iCEo%N5fRcFS)n6B]l%pnH D7 okP "C5%BНs~N;Ȩ(_05緪ҾTS"-G-\XH ߻9ƲϿa㋆?qcTS"-@EI{1pPhښ/>=W8\HNɨ;GY6ՔHP@ ιw˽ghz"*|ٽₑ/}~nH} h9w[.0 #*W?|wrүN>W 0uCvp)ݣ$z{4X0Ȧ@)F,Ca)sLM&.\>KkQMu.ɛGףﮀYÏsaL3 }aptx]辣%l#UUUλ-{Պg:nсO]ZjuZOgΤCt0wL;s4P^9ǿ };cP`'`) ,wWeOf^?} kkچjJ:T@KۉM+v" G} W-2r2l[iyM(-T9ݏ;ǟ|#{ՔH(ess6D؜ w@eBR<^nvuUA0b]ƲEIE#LʛrUfS ))IιT388 DX?̻EV 28׷в}G'vﯛwb))%fιߙY8`%;wJZFVMzzvmFfNMC+F9$-=K] ՔȎ)e8kl}.EvF5%-ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@ZDDć""">!)EDD|H-""C hR@PC{7B̪6zT籪G5yj9ڻ """uqZDDć""">!)EDD|H-""C hR@ZDDć""">!)E|zYb{C f4fm6}3۱3f66b3sfm3fnΘl=5̞3.i5sۻ;cf53͒6; n1 s݀A@2py6I:ι@O}$mfSfv4OlkfkfY-~O~ff+31!qA3-3fe4.\s `A~3{~af 3;̎\3`#3ˋƯ[޹f4:\ef6Qq3>Zq3j]ιws 7''!-̎7-f>2}t3f ff_Y-2lkl-4qIfvGt;Qs9W}\ | mOBZJh 8 H>^~a3뀓-̎0q#Tn>?8 uWOAp8xx8 Ӝs=j"3;F@jt+4`wΩGҦu':0 o0rԏ?7Rw,pE$D 7:!52;&wӀw{munvw;V; lp}l+%{-?q gߣK۸ʞ' 9W 99.~p6DƱmMpνwkQ`#ǁ)ffvކW-6sw9犁S[kf}sZX.gs=\p`?j|;⣀D bk,& hι߆]E@x'}C|k̷ /1p>ޞw, к?rmpE;`vTSS;¹5Krنɶ]a7ְhw篁 ι]\?i{ -E@sn9s.nx'^\WSiiXSo`x; I_Qѝ+R/kIH:ZTo?ssfx9X[5V:ks/ ƭ;$Bt x9w_,o=+fHlPp5ι.h0۩ zqν o50̒sU0y!f.֩w`jf5,{YO143bfg6&֮΃eϓlx ;LzWfnf{ُ{3;X-xݡVY#i79,̮6od3n7٤vjxv2fN;~s ƅN 7xm6Px7~ׅsn%nixJ܃wo>^wAx]WFs?2`v?;Ro.P}#/l~ ᝸xƴ$:>*چ'6? p*^m݈qG_5WWS }'~w D3zIxg[On;]j~=HëOzf>iZJ0Xbfιs.9E]MM;)RdWmWS?.sq'nʧfVy gMY .T8nZ`fK񺾳UAo¬IENDB`libvips-8.18.2/doc/images/Memtrace.png000066400000000000000000001604461516303661500175600ustar00rootroot00000000000000PNG  IHDRPU pHYs{Rk IDATxy\Uy]j^K 4De:~UGgՁ;QfA.0Mš,@BB'tzǹuzI{F sΩh^s=){]L]޵ 7 s6?py>o3ۦ!,JΑ1+Qs(Ľ62+DLb>@Qr 6} !2b>K2j] ȀٙDaњG@̗=g qEF[6e@LiO0$"cVd3yȀC&b^_+֩9owyP"2+H H_b}Qfg^${ jlJ 8|b6&Y#>Zp a@+l'L900YJP%A~!JyP=L 0'bCrB_z;`zlRy @q\4h A'2:Ķ_f]_ oRř9lCEurmpրGp10I?[?fI/fGNv*1< |0{%O&؃ ڨ) '*QR9P+83f,{#d@yh.,I&KaHu@.UR\^ȅ#DpR9%"/xXP+lyO$oi!K&5LȄ UQ"ɢI"ٞwEOj3$Q 4 Rwi8cFMccz$xo,g{>?~_mXj4֜zz2MSQ5}?OԗZo mxؗ%GE4j圊Wkj}}(KCEh6ny([:<ٳ?իru޻~]Ѽ8f-(aQ>ݝ&qLϛ"mA؏ JX={n={{7k]wѳ~]^s˖f5knhT?˞}{Ox^Ѹfͭ7+{ v/dv2s9gƝ߸qgaö Ffq?wh}MOp2wpaQěk1oO[mk_smKΫXH]·w{$|< oJ֟?ߞygr9&q晳WZve v>-?o>Xlރ}Q[.k3f\{w؂rgjXԸ_o<εe޿avgcIYAKQr({%zF)_-=$B%Ie0\,%Dd9!LD%Ir_bȤILF #|,]"d0 &7).q8/XB`p7'xPOdָ7!]R"샢(1s $+E%4:au1 zp$Ȃ oDu ɂI%a F%ATxHpN@DPl`rrLfI$%LQA6&A 2R*!l.)>؈ȐI)3fȐeɧOpX+UrGf@LRPT{⋻zܳk.\sƝ+W.֟xE'>o}}'?o;w~{ʳ6?ѯ*\??7|w<|gNPm[u(^`Ay:%2.{-hc\Uyׅs9͛wß]{mٽvᩝUU{]/s͟}`R|GL42x}p}g+W.ۛk-o[[CS[6mص@wwDlaqy]qŹGO.Z4'-nѨ7v4ݸKo^{"ƍvv6 e_xfp[/6^iD7zi3_5k~/4VFybX楛nmmmm;묎wk>uFX,R&)e-s.ӽkׁk?XňFu;׻zlWީ? K|wqN;K|~kŇ~,>_? ફN'i[6W5Fs`Xn[6?ްvr9} /q ܜnh?MWW>tO_~֭ۺhќikWFh4) rΚ5/]zص}+V,zߩF?٬{_}pݺmK.b.W}gomѨpa痿Iz|V-?5VZjҚZ~?mF_j΋Fh4B-|Ņ ;iu x9uחOm6l~v}Xr9}OoӺuۮrMlP?_/7sgo}}ƽ{-Y2wɒa26Fh4ǎ#=q)Kh4͛#Ӳ Ы FhLh4F}F-4FL'zmh4f:k Fh4Ӊ^[h4FN{"7,k֤2@>orgK۔u ZV`x,+uab=֏Шwc2{D֑Gr,"{Ÿ 'L!W9)dL+V4TFUB':Ya|M^Q}I,TBZ|_szm/NsLq^Sgmw~?èvݶΜ2gm=oiQ8PSd"yݖ8;l4;h5D>h ݃D7'eV(4V wv;"/{Mq,Q.>(s{LE)6*DXUi*X~)sXIFb$J:VM`ơrFeq"R3v{{ZF}qRư^e} E cdPe!؊,2IrQdڌ_=2Q*%[1_xDNL"5èR7/;~&9L4*` 2x sݹܦi5L^[h4FND4ȇs_{ƭ޺q8k=񙯞ܐ?j?uk_}^sCcW}h݌x{uK5%Oﱦ?XSյ6e6_|s/U&> W/~>cWݸ2e_?x{ׯZ}ϾG~S?1њZzplX0o̸j8s^zE}x3N.'9/$/g4 g5쨚3kuڼҮPCCO5:;JxOoI=5{]o_tgxmծG羽6ggpV~)CMR+.~` ݽ/&r{%5gV^`j8E{jSn{o7׮/l<>`sz~ţM NZr՗^|kkSnGkfUc}wzuOeK}y rQ뤒ޖ_ޓ2 zG/T%9m*kkm̆}cMXtɋ_ZqA7`648`YCW/X|3.[+U9cؕmY_bz~`+va[p/ZgtU}ACV_?zvmVmS˺ E~ŚyCO^M9w@OG~~Ѝg.Yrhc믾t/h\8_.ٹ7 <\݊wt`8gX^Oxi,z[K/Wj8ϼ6l̷7?BݕZֽ~sz~kW3 茬T%FUW;yx5,S-_ޓ8A+pwW~0rbypqމEXU^[h& /<'r3g:F$-/-;m>_ PtOiO;s2k3r;gVfFP( sڇg 1nkcټq2-ÞOY:e!I>:7e)L:ո;e)Uq?]ҚNs3["H:J!5e\kS.UY&M(mmMو%39Spc]@Kc>yQ_5 N%Hv }3+֔E&gV'\q$KeE|I*wvk>ڞ;bږr՜||m1\Nmo*AUT;uV&7b8^N_W& VSF4Z?nǎ7i$'w''c(-~h9ɛ&!rܞ+? ЗI8|,'N&p`]9nk S:9ʆa3! 9IQlaREQAC(XF% Y,[aHEKh(*`, dFi&Q*TΔ  3P$0WliA'6Z'K.qq8PEk%U'q숕BLYUbDDq&Ljjo{ULA:ALUxSbb0JN|QzTZeyek$rIktLv-4+j -9ch׾Xa]ryqʬapCĢR*G}ے)kSyɄO@4ۖq@c}@:20N9SmlG$X-Kz>S ,,YT%<o VeH${"{X7 1[l@2-ɘRZ1@ ,lS+# @M D*P`a $['b:$!ؓu史zpM*PhlRu6 [Ƣ>ڔkR\_J$aPM*Uɑ,6@M5%mI0 ze@20MVt<miɘ  bDSvJ!t߶Al{Lʨx*:4 ( A 瓺W[OLcv@M *ٖ$ RH[F`(Jxшe4H%=H2%Tueģ~*IL\T3MM IDAT_&!3bQgE53qCW6R/ bĺm2GVT@DRu* %d%hp+U32(*@%ʭ &d Rj  B U >(Lh!R+)b :B31;ݯlRNֹ>=+DWo& ~O 1{$|f UlYFaOySj3TAW](̌/2#2c> rlޏy_ W'x "<τ%1X?)v¥i8SnYx(?'; S"pFBsFdC+<ܐLyQr{*Ќؒd6gD#2qڨyGj [ob8ol9VÃVK}.lS]兂 z>ǢDHrI7`>yM+bK!He+z(\^4~yQܵтe;Beq+ 㫚|z,Sb ŁVdr1['SQ7"x8q7Nԏ2:?0|[I%hg|^Dm?ό|ި.E,9̖qe赅Fh4DODh4tFhTxD"N F<:>B3uu7h4F3 d2D4FL'zmh4f:k F'(>v=?ڇqќىvA}|7}O#Sԫǭz- o#p=͖^[hchhvA桡u>CǭzMf}|,j4'9FysݿpM|g:I5+ȣr{Ͼ|#KR?y/P>ږ{K|~P e +~|y{}͛Fysћ|)sKs;i՟=7uE[!w%}aQ6oƍy˟nӯ3u;MC?}!'_~}m{@)y?C-~nӉFs2ͮ}q]Ba[~Z7箢ۿmkϢ:;S~Î+jmVmyOnnuuGl-g)|sYM^[h4 /H7`%^MUg^ޝшlkʮ8{:ܐNzшw/?P}QW]%g>]cO}5)7 ѝv-U{ڍ[C6oIe4 BѼu OoRx5fu%wxoҁ5dڐNL~?N_Jv__;{=kQ{xI }'F9uUD#2r½es_Nh4 h4F3˗y}h4FցFh4L&]]ӫVsBW Yhq^PDp_s%X" l C7)!A1"Gɼ'0% v 1DI8`!-I">8+[q\ٯ `#@,s^']RVP &` [v @-`" \w<Nn\K _dY3?mLoD:ouZsO?m``#zx97sEs}}zK_a.LsfnlHwmqs0/&>yhr]#1 Âj]h=gQTCFb.Sv[JrYy8BİK$=p<R@F[^H x$%&-/ c!h#kp^ >!p6DI1)h{"a d3/[<,B=2+H Α!d><0lMN( E]Q+8cP+"0fݗ#<`RUq8+B".;PELiﲎ:Cy^&*$@#&13=v`:+$QKFu 0) πkpFA32`{3#{L! y\J3yȀC32dO 6T8v8 w"ɄI>3 ~A5!ҞwTbԜ'*J ¢j;Paк꫿VeO?}ŊS}3n;xm]ϯzѨo_n Qfά;pob )9s 7|qL9Y3Ѣ~H4Lɒ)͸THӱ\_nݶlY{]r_~cŊEUW-Q~3WwzϢQۮ﾿Rmmņ?(S#7?+W.gX oSJϝvڟW\q?Or5̝zmKλ>xhJr𧶛mrUp/W~zn?]嬷?˟x兗:藏Z#y~51+ ǟ&,T*%$#,W ɹ`/g̠ɶlp3`/ga[V1M `Γj@D'0Y̹=qj p%lc+B4T=\u1!P؟8i&; ءWp/'`p`:/PD/l-  Q G@m@ rF}v#! `$neD0_$.PU]18 #aaYY5c=R5jO%"yBd:(ć`ʰqqýJ0A0 *dQ [^*O\l(qsp/;yђJ:}FY@~⌇*M%950t?/mmN̉恒RR?}Ad 631$@K~cbrΚ5/-Y2{ןsΩ޻~ժ v_yCVZz@߭ @.|K?߻rp)/|L7ছ>dٸq:{֮_M)֟~]S5xٗѸhќ ;s9'sDS$._“ri_0}VgND6m냃e':>~х γkȽh48aذa۵^/|_{MM꫗bvuu\hkkPOC}}{7ý{=s@GGe-kUpCPh+@EsyCfͰ|?;z78o_pggϿO;Y=sfwٶmh4cxnϴmǷ$nޡknҹEjjܿyd?/\馻[J٣$9eLO}'''þ̝w> `nufӦ]O[Lk]Fќ[:=o;w^_xsΜ?M._~fUUl]c)|?oxB \8s2ۙ غuh4F3yL/zܷUx~׮ſKɷGݬ1/0sx.wzOܵko·z{g\uՒ.y2^|_|F*Oen t>̩̎ɟ\裛Fh4eɒK̍Fnc.Fh4c]h4t"&nh4F3iBh4tFhh4F3赅Fh4D-4FL'v@sRL^6$GdJ aP8# _,?D@2K"SSrdEGDmY)H*m "i) 0K: H)]!"D<Dfz [h6,DL GHY^0J3Jmʲ6V+evU(GCR/ !GV_w%(E@do+Y9"SiRt0hv|9-(cԣBWA9L$ 0ufC١a-öO}9@+}N`ՎmuRmy0urNe蠔}ʢa4JV-koD{Aè! {B}1͆(QXr`zmw2=۲ZDBUK#(S5urcjSQ)cFiHnSѮ(uO!q/Ѭ45g u[٨JpQ>[;"ӎ00$E1)-4.V5ag<, H*]b'W{PW ݈j#=BME 3㶶D4' :qb9٢1sȱ|5e(G#{b{2'h8k Fh4Ӊ^[h4FNh#]8$3Sѡd>|P8~A3#9YQgp`b5Q;“%2oCB .` eѪ`"ڌ' "YfGmy$39Ԝ_Xw LODzU47E #+2D d[8.J{95m<.h4M^[h&c·|;w틫3<ʞ?-?cYȺ >ȺLָv{mZuG5\kbf>ݫ7_ЦmmD{z^vVSN]K}=;&n~d]\vټ13ugr~㊞>!+S2yW''C[_vo6^xv͵gbYewEmk.8S׽c^`o ys|=u.>U- t]=X#^ݛX8ݦ@׮qtf KIʥg_;{(bg']j*ZjXT>RzBO>Ww~WsZPĖ/l^zVc/9̣.[ڽ~syшug;[lޞ:kmmMT[ŇB;~@lh؜9Z9`ˎҳzzE=ͼ5]g }zK9gDC;1.0D4w艤\ےv%u 곻E0q3jGayCWRO{9ZotG+~qϦm՝|-975v5_Bt 'גsg9:FuݺY>khXcp4?E=7\{ބmo6]guȘ{b ?L26 w..KP-/y[[?d~06:bI2+Hcm~DS]>:%;:VmMą YgVDN\vYnɮ۔^w`;{m_ y9ezc 斌hKt|=a[!iju.93/:g;UTiZ\mY{Ǟtɡk74l3<#ĩϧ%G{ [jw'20lږY\EyXmkH=v 97b!}eo߾o9bxh[2z |" ̓h3a1\*W5M$Rv# G)qM"q/ɸ}$'(quNVvzE\äcyE5(ܓq<&kf9>3 6赅f8o0&->=o<ƁJБQ5Sr FB7YиW')?ъ A=&d?~jGhek>}iMzm<_!``lL`D0$00M` a  `̪fBqB0dmJ QF%"Br8sH ӐlK`,ϖɢ+D UU8[}hݗ_)T  1Py.TDCmj2#gR\_p#~2v@H|IΉE|CpU IDATPr-a7&! Dj\H> F|\UH%% I@uSTqThE,i2\xD#߈%-S&S "`4X2U=& `F]`P_뀐{jv5eM-kT B*9I69ː`'r8Rt FʋXnH;KBN`Ț*G;2(Duţ>ǣ*ڮAt@*q2Tayb`&,SVaH˔j7mTU7!D} Ĭk[} ݸw+_tu#¦[@aIz²$3wRz2KOL)%>%FvD,% ?$S/I(I`e(9QaIWP*6GJ)dY,%@ D!DG 1313I\ =,VU8 TMlݗd(}F!V g2X:yd,`!0*yd dTd#CVO'lSsXĂx0$308@ aA9#A=gB̤_Z_\LQ1OIE(SJPEYRzR1yPI3 KW]Q&8urJ^S UdE]G$OfqZRNOd`(cz[VW>Q, 22<-DT[:rs[k!ǖ?+wlyf[&}PIxhю}Q _,zmhNn?oneqEjU ;zn֜߷<ŏ;`\g{߾?\ٱ@6wvۗ|b/}~nݿEw?M)Vg)P Fy Fssgx?lYĒwfL>fEgwμgW?KP:ttʋ'ɺ'lχ߽wϛyE+/ٶ=4}b0>}Y|ͬI_Ҹ34{_ zmhNz⍝ywăi'o\{M@eٜ%3S&`k{-LTXֻV}~ʿ*nտ& Ah4o9@@qٱ Ƕ_~Q1̈-yZn! bѱ/>Lw_#.s(m{"M^[h4?. _7{fP_~sWK%>o@K5A8~ Iќlܖ2 y~xLLJyw?Xcy->ڔ75A!8ܷnʒ.W+;Rq@O׿gU.[Z ZCtּO3_<ӠFA#Fh TFh4q ?>h4Fy` OFh:˖F"ֺuWp-0X|b Lsd?c ɀ8'* $sXZ)|c %c`J#eJ c c 8AH bPj' k&,p (@ ůCQA9҃A\#K\(#`1 rT`! uJC@Q`P0A !j.@E0"P8zC5c"s# %B\D"|,Bi F3Pb8: Tc:Bs 0DeA0&d!=$ J ~b!%g"ZX#(@ 5FRޢC |:`JqD*0#1Be $#yO.)ř| k ^"8p(f- ~ah$3$ Т!PULmjQ"#`! `ȤcF>ДA ~vqUZY(|VTmBT,Ie8`:DBtQuSS(jRJMXajJ3b1РXH$MyM]}T*>knȲemmgbDZ֯vk+uq4)} Վ(= @TdM:5ZsmL8h"" ƀ||ci~ H9u>r0Z\-{ @2{8,B .9b2EDG`M<`yd Ȑ6cMi.u[#Ow!k oL2LyƢRvZj: |MYI$hqe@B13V  K>cL!PJp!hɘʌA<̳!&Vhz!Z$Mrgd yFnIKAn8  j.*tżڒҦl3]=ry D@y^v`6Y ><Chǁ<+U*zӠ>#y9#]P3`K=x9jEg6m"tUI9+@m@fr~kT((@E?+2RDPLMǚ C)%LMX̃)ψ, (U`\BLF$y I9'bI&c]L൵ͨ:k_&HD&7eF4c6_|_t_51?>VƭOa*꘣=1w+xhnn|v#j+W8VW*Zf{칍wmm3/n瞍W]uYoVZԔկW_lɒ]n{xAF$^r ؘXX}zoGL4'q?׷oHz88QoJ:v8vq%S`;-|\? ;Ԕ;w >YsM7}dӦ]T$bkҗ{r{C7skS֯3yիo?K[L;9~5_/遣Mr,#L"Gʼnsg̜4Nc FX9G;o†=NLǨaCjͽgv#\0.lN&cLv[?_xῨ㳷ofh_~#z̊/[OjmquYSLV)OycjsŊL ;7xeoo'?ypf{ƌgDɈIzh N ){^7wu׼Ooh]s\W~d{?\8ڲchOf7GHDphxcݖ(F a!x ,E@@*׏HyX  .[/3WşjV:!FtZ̫O UW>v]!<\F H'aCq ǔ\* <,1F-Aj,UH3Tz}d5?Jr X#+oE}jO5*UC.\B&B{-+Vqm\voSZjՂ{ٸto V93o*o speѪ~#{w/_yJgӦ5Jx⨙?jjާ[`ŊBh4Hӆ W_'w@mڴkŊӯgu?w_O2%{޿=p{o_Hz7~ժ;wdmm3V>Ӷ/Ν>sHڶ˾o|h4F&mm3-{=ueZ͛q睏{"8֚5g-YrZoo'_ lk6{6WZeZxL&*qkϞCjFXS$cQY6%(e?c#PY,S1aQ6t> p\|B9ٲf9"Eʽ1't> p̜S>rse cFX2 ˚*0Ԇw1{*Z`YC¶猞 s]!aY [Q߶OF=B=ڌ4#uU"U+"DQ2z;T ]e]\HU&xD KQ ceF2Vk۳ cM'h4~F3JQ-4Fь'zmh4f<ѿ' ƢG(AXΊ#yc3ƹK.2\SԱsa5p,cƱnRlHYx*L. }]$ |D4!e/W\g4OM`ݓ ܮw'>g}ӴI#\6tΙQ;]seR띑y-єw=֕-0D\LW%䎺[UCo-S{[miHyKTv; 3ҐLo{ Ioz7TSg|}}l;kV;Ν߳#1J` NLs`ogd{K֧W9pLy_ڴ#ugRl{xS}ǩ,S0с.@-%J -9ٺޡvũjusFf#bn;PC "~,Rj6?\0ʛ:cti,FC*q^<ȨXVl%>#9iGV,d$۱#KC1ԌRh:NJ[% h4F3赅f<9?x0t)Шb q$8EUԥ#p`é=Ѝ<}jAG3n "qFJ2jD Z)`R@jF#|HK `R22^|8RyW&$@X1z;B)V,c~5bCZ2${YLuTdp ܐ`[3`HA*kX|e !*'`Ha14IC3U4 근P I %@H%eK@% <*U&sJ1bLNpN"٦PuH `!VT;0,q %#b;0]L ,F(oj(zXʚ:t龺2=3{"E(p,kbAđ-#d"E"j-a ud 0@ #2!ˠ#A28LDmaȈ%  Ȩ-K""7 EIӠxTئLuj|ˤ-L`Ʉ5d2 `ɄoҶȱ$&>g'/`[viP Y*3D KF!$K&|S4*LN0LaXҶ$"۔,&pN`ԦPLNE[Y؎Mi[RHT-=`"RX$@L%|۔X`YdTorJDA0d7 J!&iDTXQQ(gY2A*tA5 kbkH#yCńcĢi$MXD*! NAQ`rrl;Ljeɨ#MCSĂPec5bHL&M.O%|I99Ty4Lr,,ce Ihdұjǒh`d2@L)#,) 1J&-c0Mo2z,"P%('B/TOA% 6p,SږW%; "JIJI$H&˔QGj)'àxT0I%`s2 kʸZ&"@"< %eAQGL150DđMLRE``a2;HĄaaX%+!jK@T/e\UZTq-Alxj ZS4d)gxd·M2]ZqFI !:"nk~ a_7}w#t&k) g˕ڷla"e#jb mW/8;zh>1־_J?DlRZo gw(MNj~J%\|X]E DrQ QJ4$jbA6o fah$ |EYpY,"3}48MS}9|4M09|fl|I< \ 2$ǖ}Y2rF4 |qDDXcK_ pFAQW}\D#"WdwY9 /UZA ےyGYmJ|Τ y#S<m0JQ/0ӔMS\EQS˻2Թ^ *n QQX8۔UDΫ;+0۔AnA`߀ߏLj4' wP5/ݻ잆-jw]Sƿo_;cve: F|hYzThkXwE}W~Cjc_7?xomr[ړ//\_|](z߫I㳦D'2͛}Bќ|gsVwhk{74K?֬8nn /H޵J^=Y_n\uٞ۾lo|?-_Գٺ) 7]~w;[&r͛h4oM~SԋuO6Xl>(.zE9|drF~ Fss(m=-տ)^$ܮI)Ol2د6׬8h4[h4mS ?/zDٜ '~pZl[}\I?2P>v{DHǾw~>n6KWk_g}ќϠj4O޿QO=]iku@5` gl|+m<^q(x^|-6kj>U㿲'zrO5M9kj۾gz5:?O5tgYS>/BmhAKOFh:-4Fь'ϝh4FѼuUDh4?oqU%oo|:8֭/^Ry@z4hƉNO330%x q95 *Xl.' Is@,.dڠ>Q#&!G0$:_2XGO(ǁ<L H&$B2 @HĘB>œ] &@$ ACߚ*^4gPW<#q`Ϟ3-o?;^5 ,Anqc)1* x1ja\s#O<32i{' |$ O DH*|D$MLIY.֚H,rcNAf $&{c!J2Z\& (!@V V'`&{h ]&x bӠ|V-A8x4h@Ȣ p8 `\궤 P!y>, ,%Jr@H,Wc!ȧh%m3rF+{LDT獥X%}f{ jE8 Yz_T+Jzp'mDIU OТԤDQgP0°P0,C,=V2m HByA`eUM@b.K.`D6c\&c*%T0ܿdQR@yƧ#W=d`VlD| vP)CJe'*k@"C3 ӆ3%X |NDHQyrM{Icu_߽d͚Yn;9 xq/}nXkяc}rv37B5k^̻Znnn|{Q]I?eJk޽lY;|L ꪋܿ?}Uy7r%L-\|[#j >< 'qgK~nݽjՂjmqիո=yr׿뚚5\|yۥ~ڦëV>Y|~oǺN&c\rC%u׮}wܱqo~{g?r\pFgg;G-Y^}իwmxCsmߖ{⾚rAT@ԋ\e9œt;;uR}M}Q>٭G0rJs1|=LsKP!GrLvkHIgJ$x8xHH( r >0 hZg$"Lsz( IyF}\}۔CdIz PiMg|N>0j@g1 "L1p"Lf89 e9.I||l_n=8e  ~PjI"X乌0xânCs`Te0#Lz>CɄ$ T,#K"C%dAy@e)а(mfL  +kH^C|4R𤘵p$"ICٰD7A@cpuXD>D \F9 CY ؿ?ck˗mݺsOMWL2mjq9gNK;::`۶G-ꍼ6w~uƝzLI=W2,|k_r j@{Wr:L-F>"^zӅr__s?9,"}U?n{Ow~z'n͟3js}}5kn|o}<2,Xp}pO,4F3aC/W>75.|ك>3m:`i۷nޜZ@ooba1wOzCAstzLm:eYƙgx]GNd?~?MU _ʝjgGG^7Fh4ŷau}mW]uڵϨAkn46}PFuo}ow?{ ._Fګ`iƯ| <:FFh[l>I({^vu}>nWY&?>偭[w7> dinnz-j`Ҥ; ~U|[˥sL}7U4FьN&cOHLr@ss-aC{H&cUĔ))({~BiV@GGgTĔ)|e)VUFh4Fh4d؉v@h4[ h4F3赅Fh4D-4Fь'zmh4f:tׄ:zm]mU1f , ڈ&͘V# 6plB".f"b'B me_W*)J1UCH\ʎzj0r]0#̓1 +saGE'5Z-4BBw"R\nzpF-!u;lA;F8lFH~_*Tp%˘-, =Fh4^[h4FO8͋'rOn*ۓ&HKK E$8!r"Bt)xHH/&BH SCz!!D me]DHU#D?4QAHG]AH e_dn}(CMR ʃ9,EOT&1*V6"r]D1gj4$2V =*SeX+#;DDUWN,5ua7=N6c0BAF{2MUg) 9)Rfա\Dwh4F3g9552}'& >L"*~͙>ް-3ZfN®Wco?w6^^;VBM<"Lr7nOɗࣛ7ju:ϓV-^MM%/YuϣM.j&ҿKWw9>m{XtY Kw=熥 29`uܫ")?^-]y m-~;ZqMxy֝{:3&B"D0*UxU*U۟o[|wbk"VETpSPJ涻31e |?^vfgy3'3gf,=~ݖT})i_`}vIlt<ag^2r? xS`ʵ_2VFִ/,_۹y(Mᢂ`Ai-rCuJUڧWQtkꥣ*)ҿ.y]74rP Tmܞ+9y>Kgn|q5I/Yc(s@G*Uݯ(,_9g ޘ~ո#2}wOg[SS WYy ^*QGW̋/ܱ KUċݪbN\sk/hc ;~DUb{kAgYnȚ//,`C>۾w D`Aܾ:``]VXHj|1䜣r]ƅUM#ŋ7yw>?꫽^r-μ|庌zDYmO kWUʅU .VUVՄ,8hTGwfegHbL;U} KT[\vtIݻ/+<ҨLw{11_:rէ6aCFpi8]s'T#+%7Joڑ+6՟9pVQl.~×隳i{jzM2rp{,z}{RSb_|忢Vu/Y+}B+w;~GxkU.9~vW|8㢂{EhgO۸#qٶԀ/-|c1VV P{z#qaƤ,s_b8^kC^Q>׿~5oANIJz}q#*M<8oor]:`~6H=w=l~^u(Ǐ W-;PXҭ#*?"zn+冽2ӣC/+,?^YMGT Eê*`߷q)g8^XP%-뽲"%?9ʘ.S޿wf4kyYݢ9#^+u~_++#Amٵ2q#*~_l̐`h ӟbgeZ zF-peZ$#?/6zf%#nу*[{mX2tpHonȣ;9M7vwϰ㸹+96$;zp.$QkN~zMq*l˜fiz=c`mH_j X#1?_nHUEVz4[tyuJe/7b9ua9o9WUWyJCsF_}|y {z^P5}5Ul?,:59 ),vOvO2V{A?%vuQؔr]- {y  j!o9GT&JO]+TS'>_њEЪDvɍdȊ~!CǷ 5uri~nߺF{:GT&v~gS-~^uYfFaXkNB^;'2fH0f ;;BӿwHSwEaωI x#*5naUjonXSU{u4n}Hv(2zt*UYF c6 2 baK0vyڷk@ɾ<ʹO/(؜No4UAkK+ (9v켖|k떕vkShLS 5rqNSǢ$ޒ{*AwɩoA:AVBH ӹoAZ㲤*h[uִ؉z'O*ip[5 7a4CK h$'ID&?4fʠUd*1ištIj^VlHCv&;B+Vl7uD[kJ-E-ȩQ%&@&o= g=#I(I0 ,@Mf;cYF` %"&稩ąQ⨩N"EGEF7a3@Dr̀0t Y pd, ДxI @W7wT#qCw3GEq+5@ 0@.cٱ2@DpsTwdtw'UCY^]!+6ȂK薶g"@Q⛏'p ƀ" UrpFkSUs!qgnJsM-*IF@PUt[~EV)A$n4Te Q䚊UX6+[&WITp8GP7!r(XMuA$PU-q`^1UNJqwgI.m7HUA(KjE`3@CLvJ_ 709i/XL)Ώf"TúH4fYB⻪W;@Mx>O,yLQ$Bź||= 4qCJ$G{H5P{(zUE(R$׈ŻDۮL^vjY*2` % ŰXn | rj#U_6@?B9x7|6aLEѨ̀uJ{mEF?Ŗ%L<ӽ"g9| n{tں&ST_LWp<#qymwEC^chButMc&YB64O:RlM^É%U8 P3M)^ǣ9! MHz «;&$u]04ǣ;^T5CwtM)ЅGw CxuGЄ4!˨iԔ UA£;Ö%T%T!M(j041z GSe 14 ݑ8(UUjG&|[џbmbkzՅ$# fN(2 Mnu{uG1YBUхLjU|u$Lښ"|^ЄbVdnxGw$* =[ں& ]x5O ͑et"$U D$T*£ YFغ hNjJLӄ;.4M,9]RmUH1lhGw4 =-KC>ۣ IB_uM-YDʒH8vЫۆ.|^qcS045$#xm5[f{ u ͑e4TL)ЄGw4-ޘ= GS,֗aps*&5ѵxƳWUa£;*^14Gֻ=x]>J.TEh:ѽ籏 X&TM r{l1t!x{NM^GUDq;n}%.R+-6ܣQapM0.|&1xHuN躐9&j3y]w7TDoRJ3g*(X^Ñ8XNz9/׆uw_Z;owa80EF3qXg⟏Bc`̆Y1>] &m*5w bpC#YC ~@,y1@` 6[']7]D`А]܏Uh8 N6 ,^'l"}hTM%{L3U"c 8[_Seu4w‰ۂUUdmM0@qz?Ŏ.pʖIyt{|bF5sGha{h8q%2M> ~cQKD%<.wbMlxul-%yifGN:rYr“5gɻi^4"o}uq{m88b j9YjES0^*1ʠ;;T]2FmѝLK xc:c8`(@0jIQc8+/mwfѣ%q2b,EwjòpCRƆTTi)^qPZuɍGU"2U& Eb6s35$ǧ G%IB`FpbW!d2C,cASU$5Y"22iJ1:&Nb]# `,Q]EڰB 7dŠq!@qą[W8c1bd;DQ*lT5*$ &OD\tء"DKDDEXEn8,l7-IeIG!lMN.+EVWqQ\HF6dVP"\ˡɂ5-Hs8"MIf;ܧ.#IXS'{ 2cNC3HjD!`ԇeM5urI8ٝA`M&p@!f3]uTHs(:1ޘp(#b\_fL xcQ"5*:wDy5fC}^[ ZG&u/">;ۊ1EF.aF1t+>(9䕹(<~2oA!DB!-Q߂B!mBiK| r2YY$)QBieevȈ[B!-Q߂B!moJ탳^a9o '^ò#d,k$vv=US[{oo9pjlw8{gwLv1Q߂L0lg@ȩ!h(O @uŠ[7HiE:&;B8[BlS.=< ܳK;М{ojʝ{R/[ri؜w=iQ?z/y/[웾?VYAWqS O|p4식qqͺ~ϔKW*ϼڻ[Bl2/?CԮZXk?VgV&)E}ݱ/s7)L{d@ϺcyO74_l[p7t[9 &3u;KRϝo~͜`¡U+e ,\gߴGFtUT*k_i{$ry^|+>OvyǏJzr`=v~m0!]-!N6ts?T*}r‰83yʽO(M^7/'i{*ʃΈ?".\rг+;o !g[BRL{z ssB8_>[y1+WɻJl!g&[Bx?-q{j^NxƯՔÿ~l Kr'jGUDvYZޑ8AI(W׺u}c^y01'o;Sל̨;s{r{DwvIy;əS'" | ,|״I|װd뾵/ׇ7_kٙ}]nFϛrCs`gfyl =[4!U!.]y9a]s@~ߺ}k%5%=յF_ryy9ᒃӓW,,Ж6-|hTENykuVv!qԷ BH[BiK6|HbDC r tML*w:>Ө, (Ӭ3'qE}gF:Ѻ Vު|gBRҰ gB F/mYdg֭+x`-J=;;`->F @^»աF ̜9aȐ<زe+2zL*w]~тx{ 8_gt#JO-mCgJ~{̈vN̈́:;";lŎ?Glu.L`탢{:ꋫ IDAT ,O=_Į<㨯jVB ]oΝޣG۞C`-ɓ;{^yyMff%k]?;޸MvNvBi}Űa-ZU\Ý,(%&[{n۶ذ~F_=Ѝ=z4s!9zBph}v'v=˳oaoǣ%y}X/4yp]W9g_oߟ˩׸w#.F_?DNaMxϞ6 xA\?ć~:BHgoߟ1f5kv=-~7vy[K,:o[o}b͚fM~FMv뺒YgeWOƍw\tSOGOVx꧞z;uu͚?lհaw>5k58pVuu(H9眞o|4 VALMX;疔=koiw 33Q)+ʯԾjV++uJjPΔZ:c=$TIB j?U)d\Q Wc9CBދ iEo WY>ppQJm90i߷ɥ-[~{׬qu{Ӧ-(iɓϝjb%K2nfMO8Qif:,Bb/u[䞁_1pO ~m=0oM24iʕ[V*j4_'d\0턼[n-ZxYΠ=|tvkD[g'tKO8!U/[o}:f@oQWy寿~_-˾si~O>y[0Ȳn{_jkæKLԄաI7oڵlYΝ`d֬I6ɍꩧf1nm̟,//=?EB!eu5499irUN{I!wB!-B!*Է BH[!Bڒx4!Bcwv BDɜ%E;;6# PNEY30-_w]` }jBfegr*gVS&#_-۬sggv|zܸ{7mݢs,ajjgF  -;lX!C~c-K<"-{W7Zxժ/?pK.Kڬ/;;6hm&_NtuO]iͻu:wNdDd8ʯnַgݼK=ZҢM+E^٥Kյ~[E= ^MGtC446p;a4oךϛ74c#G4'[7~3z􀲲܌_^[:lwyǎ=۟!aշHCe-\~yfywI|:cƂA{9/~sB%BH'ǫ}E g{PS/sg=//+؁/N:Fպ n]wժ`pѮ]O Nw ee/:0??Q'z{#fM^ti#!BH+Wna\KBqߍ{oK,7>Z\cK|rVIIʕu]itrsg^=̟<6o~ߛ? ӌy~ sz0=%KaӦ]<~}%%eo;kɓf,\CP֩:C]=3B ~muv8Ppm}[Utv4'|`J{|V Y|;z^&=f7X]P lh7ZL8iZ8qʕǎ=of̸M'O>wE~+7SO=m؛n*r'd{ 6|#1ukvϟxMPUyƌ{G_}kj@ 3x8:V [,ݭKH qD]8p0 0 ,\cm_M.C9nцV6BGZ5Έnusi(|` Er]03BB7Ĥ@Co"}97L( 2n(c 8 hhuXr@+; 0@!$H︫0"0(bt6pD@Bc`瀘hQIĀaC%J3.PHN Ս8b"<`oMXLDDY)0QA0&r@n9K队f=v~o[?rJiiޢ#G?Qq1,樀(OjV^20׶eN9%E:Z*sjQI~[r p^խ&2yvQA45: !C9SPD<*lS%,B8ϒ:LɮbEҼ@ҥk˩yyYM߼WΟXz7~gϾf Zmg^70nz Ý92R|z_2?8?:8B!d9~UW<Æ;NCɣ2M331mM͟XD}DWa)- k; 7vp = N-l44cw\C!8چN5;>d{+2j=فE~?phᖾڴs`L}= ^KIIl93BIIա%Ktʭdi}n%Y^߰᫋.U+2j=Z mE~dV &ݻ{ !3B [l߾߲Gfفo~Aiiޒ2 Ws+߸ѣy <!d⋒_|QD,))>}}]7kh[S `njXzk#>bꭹtwRiiկ~gY~k'BHۢB!-3 !B\Է BH[!B-!ҖoA!D} B!<; ]/p?QkYtn0BHEGKO!o&B!D} B!%[]iXW?u !mphUxy3t1O /',^n !Bc9[CS̚\ݤo[ٷkfBHǣ̔K?r׶Cq]P]ZIfgdΐ)~;SkCm ^.Ma{=97]s`ZwăumNBOooڤC2k[?fZn,b|Y?{~i9eA!4[m_kΰZgk~6V1;>oTCsf]wcZr{D~װ{ћ=?'3~=]76K?ֽ[ܽuX޳%wós6_ӑ^ B Qߢ3Mnsr3"J+4(9q{jP~\hTŒwݙ7sܑ%<%=͉!X2gpzuy9fK!t[@iK޾; IDAT%Ϲ}gѨΈ&]izeIO ظ=UUD~z[B:h0`=n|Vx&{b_UTui~. 8bfTj~BHǠE>7n=x  443^c*ВOr J^ &pѨ MN!NA} =} o{K 8\Y1~ krfTo|0[эVUk囿 Mym~j4J|%eo<[2| Px篭ZVͻauZ>4xo<?!ٛCspO(mNxBFD!gQn薸Cde!3=)E#+ krb`^=Ύ6&B6?f2*?ydG?|sXV9O34.SVr;ziik#6zv!B]!BH[k"k5kmMjԪCmT ַSʦifuiV$bGP_iM3D)el93^;H~EGDHݵ)S~WZ7Ҽӧ|˖/Kwk-[yK/9nܽ班^_;묌'ս{ܹt2OYYϾc}.So':% uc!EG&BrsĎ>\@Gf扱c旯QLP8N>OfyEb67Ӵ z[t:y[:KtV:-[RXx.11]@\v V^PP!vpI#|aT/׉܅z  |'N|:44ر]!A >8'tvv؁@K,{KOl/9yfLLh~Y+T*G޼yύN~~؁@K&׌Dn6ѸB?)v `B('l٤S.;NuvFn]M;%$l7bֱЕĄTeo@nP8%`'@gf46}`Ӧ=V?TN6ŎZeZFPgvv) N5L>e؁[ }{fe sgR*.\(v p7<=r xp%q {J;h˗>r xk٥ǎ;"hE-4}|⊋+Ŏ:e% 6e./  IEP -=ޱcVLJ1̐[ed,1 W0xZCp>|0MOœ`25bTYLLhZZ6 h'p2Y/@!o،\gPAT CWT$v`Fc7_$܇L-[xH@:^OERBXV b>X[FaSEЖaw; J[@[T*%; %A2hcuu )ot--r @ HMQ(+An-GP[@ G-$djt,*ʕ:.['bG] r hUH޽bG'cЮ/ؘԈ 0߽{ Ď`]tn׮Ď`:?Qe@ - +'4f&aw`ĉOc<`EXoVVQP *ؕVbS3`o!!>Ǐc'< RHStU-. CK²f>Qd`?#F +; []9.v ,􉀝t^%%zQ@@@&S#DN"#0'@w Α[[Cnw0 -t[=DFqL(@pFc[=DEffty-JeDa;nG;+FR\\ɲfͷ<=y`K@8<0bGaEM_@=z8ԘDXYYk67HD)\\<=N; WTXU޽!7o"47 Ǝf67&O#7l;h׮キ맟~;Ngfm;(12,=hձcpXբ*~Ă ~R(:#IcՍ7Ϝ'EN ,.]kkqrBUT fU0l `K-zBT*J_RogjE%3\]_}պ~z ̝;ޞEpܹs͛{_ߕ2rZߟ XEFYQQq)0pѪU?lVw 32CC""kSRZ-3v^_P89HQT**.֎֮ 󽷘GX YWϘ278X;mZRDo6j1v?XwoM^yeC37sǎ}kނf8mڳCܺCJvmLR7G߳ZPu׮22 cN 90pQbbOi˭J#c0u6QahM mZ= C75sj0tU游 Tʍ/rϞ-J.^Rllrg555. cȐ"m/:ב#GZ]A[TNnス};s-[1Lq_?'2ohnD>}ܦMhzo:9mw?I~?~pNX}8Li#N(ىWT\_WY-P8VWoY%V…-={-!d55~s_b\->C)/>>b|~0A^d;+zƅ2Ewv&b'պ߾9mڳUU*+7VUm"#6== GQQkjUUm6ӿnUҦѸd=M1bȽ%  F{KZ1B 'ccue~`0 !u(jk#o;פ(ټy:T,u wzY\Wwť%[fsΞ][Xxn/+ŋW[C v[+{&߫k+57HJ>0@Q^~,/Dh'y:~~W_-lOHY( ٺRHLLkY֜z 5+$--kkbY̙19д!IJ7-i46Fc#!<`E}]]c߾rT-W#NT۷qJ\77%+a2Y'(ER(ilnVVo=> ,k5cR(oג%w_o~Yhl{sԨQ <=]SR~A.mɏvhQ;] 45`m||}߮Ds>&3wlQqWU*efMpgd ?`jp2O .Ð*EjX_$VnX֜>@Ѱz?.t•{Kz{܌tݻ坑pe25Bܔ/J5:/'XxA~yK\qUrw{/>M-O㛥K7M{ uq闑Qmj4.|>s:(ȓߌI<+oG*N}?FOuPֶee=x2 ŋ_֍- BgW_ 6'LzZlZ4yHw22ҏ{% e}3jB:*JO 'M6U*l><|di4Vx{Oyygi\Ed25 2ГrTell &S#uԆ YMM=b462 =kVj ˚6_?b0\ ׿޹sAQyvݺfdd,ٰ!+8X M1r;(/9kƨ.|q=P8y-պՋ֍=D'bF/իFG=t蝴j)S<>aͯsX]R!dժ4 WذhK7䛻rsWnr8.n#!LKSKZjwAo:TeVi93$!aC8ֹf0\kM/v򔔹嗦Lѕ_ܺ5kf~S :;;jI>5pmzd֬Gï==]'N|zw_x9DyⴣGW-,<7qjSC+Ǐ 47:v׎Ǯ^iѣ} l͚}y L >|oO yr:S*++kFz';FW ɓ?] 479 Cvǎ/j;9pƠ /~Kn߸ :Eqo C{x<β YVuSeoed: vƌtd lVVQsmh`.-Ä́'OG}ݝhرΞDt骫kǜKJS)(/j{z>#[5lJ,O _5NTG) L :i6f|RI@2y>0ixQR݁kf..,ruEF:)ל`=Z͍QJ6Zk Lz@,Zkj(Esc1;@P퀀 J)`1p%(й5x^m\(fB,v ;8VGƷ9J!@x-Ӻm80 2ޓR*:h{_|lk|0ΐ*7J)/pG`:cy]0*6kWTp{}ZuĞ\4@T2pzǸ1󥞭/JKH= >#0#'߻ Mk]1؀8ݺj?\Z[1IZ_REiwz,?0[\rz?xTk6_"MDfbtcq?f{T+7J=)Ǝ=R J+P461  RzLY)eQJc(c׀;+'([p'8SLn%p0 8nB|>`ۂX :gR+W?-pO>) UZ7l/{ (gn2p װγ0vVn61=kv$T"pyL^q^9/ a}@6p{uY[a\w}:l0ו`{3cz,T`_-=(FusCT X ]R~r }j{>(WJqTyXn=YR=Re-&lj߄:iEJN!F:PF`,Ɓ7v`Dz#b4O&FR}3?pz@~袔Z/c$6ϝT`(PJRG\@oGeh.ɾ JZ{ӂьy{.wa\=Q N<#}wI؇HJ)|t?YJՖ]RuKFzhRNݩ~o`Ǹׁ ` {GOJ*8~Gk1ZR`\ ZgsD+\XZ?X9B)eZRD*qci R; MJ{Cx&_Y~GHkJ\;N9d}qwuRkc+;RJ=g=>κ{^JR0k[FZo8#ϟ1;[13@4 |_+jWJ=l5Y-gaܯ.;$Z 㑷՞GGhS@'F#vtGM0nZtO8*8x^{z砷ckyRj8Wm:uׄ8JQ.~,=+w<=q 9&uQe ĸ k8X\A}Q(GVjø-۸܏Z6~$]kjw)BZu>h}R*' pدRj0 k?1NFǣBԦ${!B4 yW!h$ !-${!d/BpBNBIB!Z8IB!D '^!h$ !-${!d/BpBNBIB!Z8IB!D '^!h$ !-${!d/BpBv:= CB@n`(35VFiOALB .!-Ws8&;z3ǁ J!D<p8fR+^ tmBF8%:aow4ZDB!Zm@ZZ}lll[`LF$[\p8HKQcV="!R1cف%X?`0ؔBN`ܭyNll>ABHsW:2#Sˆ سg䐝M^^V]2tP[!D\<!!g}t6og"#g`x{YwSCxE_TT-[ƺux衇߿lBSecv Q.뚔zR,:v۰X|:\?С7(/jr7s嗟u!8#&6فTG1k,***a9DD\bG)XXlm[99+))`ƍ3bRfWBC0gϞfXK_2Cx6J+~~ 쏾JK]gf\Ӿ6Lvmg_FMվ),,dƍڵL";;___',,( Fǎ[!N>44ZkS Y|̹qAtS[frgp:v&..-[ u`"= 5G34PFԪ嬾bŊdz}vktMBBBո?v1|pFEӦy05[VL,_ ϴimY" ||,|n ^z)Ν9pr,s~u2jt?k!$$4Z!//XJKK+e# `+=(-Mp+餥1o<͛G޽1c$}!DgP\rٵbƌvl\Hi b˖,޽EDEyqade|y.vsea]Ϙ1AgKٻ>f= EDF.rk>$$DoFJKK/(..f &$daar6[}l!+k K(,Ν;yG0`r ݺuk؍BSdz$!!klJ{׏ yq]y'ӷ?V|I*#Fѧ/CE _9f=5-&Gl &FRn.ygV?DL]XsNS+2B­I$qѾ}{֬]{uaaaL.1CNNO=xya j.]&:z| /6f${-@JF_bzӽR 833f̐kMا~JFFV/}_{Ӿ7}ZRe@ e@%0xEkY)H`:Y&{O{{nj+5k^^^&E&ѷVzfX!x{+֭+ /sNgݺp~DF s%=ֺeFkWESǫJqq1aë߼[f#<|"qJHIÇߤ4xq:v["̦.WJ^ʴ֛Ru%(:b|6~sZMD(.NN䫯203ӦQ+сzkyy,_KB//U5E&#-ƇrJJ2Y4MZk>c{9w CB۶{l6/:tÇcQNrr2<V2{Eii@R@)ezL/c=M||E3V8δZbf^=?ȤI( v1X0sؽ۸&U;jYf;#Ug웮 y+2dbb+Х_8["q: G 00Pnm/^ @ңS) $opבoA6m߿[4R`i-fU^kWKiwnbϿ 9{!j2rH>3LDٴ)MWyv^PPN||1۽I] IDATcڣrb@Iy29iէ8`$#F zMի裏hbz|3Y,^ _JqA}Y^{5y_1r^4[;w1cƘ\3&oʋhzRFf #F8S ѳd[,5o[`k?%%ݮ(+S.AAV>jٳ3((0Z FgV#% 4cؿ0.%#U˨=u:wjA6E?O.\ܹsbؾ}>;[s\BB׹2'HHXAB PJ1vXO.7G[]4+ WWwDjU>[]#+G9"ri O?,ZR'6~Z[*RQ$^h ?>_}qKu$4#m ?b 3)(Ƞ ȑ#>}::u2g) L# C=A. [#xTo/1Ϝَ[UNn>x{+<ڝ_2jt~~~VNh+8q"qqqdzqFN'YYde%k9]ves9tҥ dJPP-;%%,ZŢEYLƄ G!DDذXDhes/%%.lDEOj^9 |}njIqq(,,t7[rE?~[)%"+돪x8r{=z4)dfn5ӛJbׯ%ZIBVGm}ʾ} >|864Š#^*wy9FC%1g22CU:u*;YUӛ+ >ljnEAU k`o1^)Ν_vɵ$Z IBVK/]vhPVgj}Fv^`ر-0;!0n{fELi/*Je?S^$,,oiExf!f0`w}7ObtxMee̟g ÓO>)oͫ](0;$Bi„ \}<3Ӥ/#GvbXNnL&Mr)d/30adΜՠMĜ97=M&Or)B!̦/ ]ta֬Y/f0j |6ۙb0ի-[ $$~}u`N @)2e ]v^ ''+`ٌu;_ros:P^nG `u[H0:$بzLkG!D PJ?:,rJa' R+{ !'EiRJMf~Ƙn9psʩ-qpQg0kqJ?i?93 !h nS*^m8ؽnNxiS`Rx{+|Ro*썺B!-9?J)+=0?~\ Jfw%”Trlxt/CBQ9?5oRuKSPp%ow0߆P!ٟ͟$]е;`[|]q?f^sBFOR"ech!|gɖ67[!D3'ɾ7Ľ Xc6,4^hҷT@%PJ)!͔$ 4r뻿B' zR-E1޼'BG}=(€'%|_ WR*@!D3&ɾ~BV$Y^2 !+A!D$ɾ~?94n}GLqlB!Q렔 23ʴp+7@5!h$}9鉽ru㽢!*A!D*R2Tz~cxaz}MR#$C!D ⒽRʢLTJմV`RMJ,L??QqlB!E%{}Rʯڬ )>UJ >z&_p!6:$K` szD.",$6:* gW};ިZpBR-S< v+[+\)Sv:) t) F8y']-łr""fr;H8N~hL;@QL)a])D@>Zqw.N6b-*_{ (rWS^S'*-E=$$lyarH)up p 30(SJ>Z;,X!DѢzRjF7Q@:KR!h` Bk=W@8_'m>A=cA̍7 S4Fk}_ ̮QJ G'#`h_1NP J }!}`K(]UJ={MGJZϕRsuMMq u u&%KH[MVql<99jm$qqܽ~=,\vرtj>L @eVݡdTPJ!uʃId8?/ hX 1CJ?EKAu9ƍv5SGpvk'qܘ1|fdPp=|U^NEz:k6r ݻI7C~2v\~/SXKٵt){^xESn@U·v8?z2 =A"htL{ J)+BVGyZ(BNR:`6( &@.+,/G?0goLB^^ӉҼSPnnZju|J5}Z5 {6𮀇6~! ;0euZ}JwI @`1"`|eo,B`Ik|y{;Z% (cxx w W欄bx7_H?9̈́!^w e@ pgo8c u=D KOa^@U h$ٟu p)PApݰ×FI'xewCA(P LZjr}3q`isDW>xl)d[dtQ'4Jv0qHZʳ34]e7!D 4h!= C`^Nua( zvtr0Dk}.rERJ]WNi0(ӛk+*;OjC4F)M.״NӤNQJn:)c!WNN C DŽߓ~Rj4ZdJmcG&ƙt5*^PJk3͎H:T0L/ <).y*w^:}@cڜYyaƝaP[mYW&;a`@+%o/樂Z+7j 6l!+WedeQusݾ$J*GDK^'[!诵VϊJfz?&j`,`?d ?DS ɾa\dI|FO{_̈5RJZkGyaUsΝ$M2J)*ۺxpzQݟՙqc;Fe@]J R!VTjx}RҌ֥bw}?Ѥ 21ђe>.exԗx4bj.EwsfC ?gm_[% pMBf|9Ygw[RBIT^7=xq=﹇z<B(~f@)u FJc1I0%M%'x5kH# 8YYZYkwxl: I!& (^ްWX!"zE^OET"*  Uz ! %'{~l 1 lyٙ3CwΙ3vE`_fQioՀ31TX7a[{0T#!N-~@kl[~=4!p_u] Pd>m!`6S 9 :u8vQ!c&ǔR &?s C /m5|Crvx- #1:mQJ]^`/3qiZ_qRjhOŘ =o3_O8~6vJOГ77HWL !JANGয়شjR|`kۯ!-J<-k/jqy{&L xSMk~ SJM^ҍo#'^@kJ Ũ P19~! =U: jٯ^M˅iߟGoYgX_uW l+.lSJe~H) ,zk. B߆îE m*H¤^SJ}lWiZ:#tss) ~zUNH`mٰas?4I_~F J'Kx IDAT'ilRBl#+,HCf9@OpäھwzABlY)WkB_~Eւ{zVx56ҵk9O7߰曉7qz*: ˅{f.]!w$YcXN'NԌ]zcNUd=vkEa;+v;!*QJZ> n,_pϞEd|l?r.zdj/_=zzxXn\]^ vJZ$k"V67ܳÆ򡇸4$" _}-83ЃL,R5t~OWB ?c 0cH^JU7wIh /B G:RiFvfzJa~mo.Zϵ8Nd"!|3 pp,bZK0z l,/YqgY̩JW3 BwcsaSX{ qN8QO6h S7P|iه;pρ B3@ XqGm7(kOp5 JP"cФϥ+,8U1!'u6KwVN93jϷê;Ͳ^<3셨o`~|t-K~0ȋx|&uo\ftMyXثJw4f#GAx{!ֺ  R?΅[Pn)LRjR+;x;rVAW\ MDk}c\L( `ip>v73YkA)WJ[MV@RJkUm+hm,:5RCf;T Hiw,g{Assi_ PJRsI*z(Ÿ? HWJnN[Kp]rs~:eKƥD;4z4lݻұ#AuݟZe;3(ꃌ'D=ZRJ .~pMӊ(x`,$wPܪ{JaLG :_)cn5ԧ3(c3=1ZgjW;8ZTDqh(!ò^b{L Ч]22Ȏ {3s&)tJZuN~-_̏u;69 ~NjBX@k >4 ➀͉aWˆa(3HQլl/Oȏx #]йZjW^IK/e۶-?%按7C6%ukhۖ>:npdfRв%уw=~ݻR~.,oR"f[R_b=bt FG6Cli[{=ncukL+N\n5TZ|'Se'$~R/'`){8>LoBcfCZ gOB­5n))8@5<8xxC) BXLk>XFÆFz 2 <dC( ((h 1Pڤf7d{~}Ee[ZW*ޫk0?Zg(N0*ah~aa(lw:"h '$,|g,~,.,2ۍsN<)),";u}=wu/"^?F)-0~\H5: , 9^~O)[1&RLJ<#`hfM߰."fC!ChCf2\_ϒmϸJmZ5f`/Zfz}&ƣX1[y@zX#XCk=M)_kj= |Q+u9kg쎠+lv{sdh 9[?W]E7ߐKдi Bu+Gá?k. ZxQ"% !cGS#pà ڶ' \Yֽ4 !ZoPJ:'51tyPBᇤf/ce`9O|S1y'  %^!@m|$ }UkZ˲k¢m䷬`;/2ȬwDxsֻo"4²I&DfAh!6((6 xn/HjBрiRSb !j@Lk%7>0[1C)~)@,|m R͔S,)71kI+;!`/B4rBFNBIB!9 B!D#'^!h$ !{!`/B4rBFNBD8Ȝ T́ YkVM!D%އRm1敾sTJ6VP!{/SJE+1擮 ;g RZ_U!_{/QJwOb4՛BFEС:A\)`i Hl Ev>JBN(Ӂ d(Vs?VX JlMswW 0 #?ӃBH? J)u^y'`7\nmxO=8KcZkWB!D'ޝ T @J,^?}.,Z KBϣ~PJUU BTO PJEK5 apv~ ~;"B!D$'/4<VAK!N+< @wkT`=BJAy_m4WNɫͲcBH?J0.ߊOkKbݬwG-`_G`9KS_}8}YRQ>;x! {hv7k94 t̀ɾ>B!& upGjh Wn09A)G@!D&nB XCޣb`oд&$!h$8mСK+%0fYο !$0B)5l,]˃{UF`;3B4d26~.7^`\E9U.Y]"!/YWJݪ:O)Pg/2z[]. mw!Y J}rjƏ,R*zװ6K,,5YǖW!04f|T4 \5G)u:ՓOk\)5?fiWجl,׬'ۀր/BQ[?g)UZ׬v Lj]r%؏A90p@f$%AѣLT OgNXv-9IIzVɍ7LSQat˭ 1lE+ Hi,5`^#= \WM<`>xXH-#F2õs'ɀ\.R e(6kfٳݤqm55+Nu]{~ϔR1.8@KJl`: !gWa9iZcjJJubtNk]b]/;"v^VFYp0Th %SW ̡>`cͲedxEָPlZm6̿[[1WAf )jGѸ:I)u< LZ/O)f.nև*mϩ: t6~[k]X{~/&k.|pN:ȇ%оڗ@@J0$/aEkb Jw+u:B4`^VJy 6zCWth "&r>~ȭSp02{r\wͲD:ffȺul ֻ7]dُRhU==`yPJb\bT4p,qN>pa | _v`AET`Rj: !X/͚}TVJ] X2US^lJ q^}5} OL=p=z?\wjR֫}@MncM|x+.?NeZ߽6TGuGkK"ğUk wN3)sa!]ǠpBRS9zy>>Ko%Ny+^4b0‰hWUQxy NV*Zo>FjuL:hB<%Ve^)5xXj+|Ӝ0~$!;'5{>r5WL5= ?@.b ?ݍ1wJPr@k30Xycy ޻,ZkiSJi0wSH疛 廣B upXC]9]?rʼnRJ) ZC. 7&ŻE)Uq!D#$1Z3`Vz^k!ۗW@\ q^ !$(~3|K~g[A+bX 7%cy..G=VJIN!1 Ak]\3\?],8 \,v` ,WLɣ*O%hD$'A_p0<}ZrD]fI=QyYaJ>9BI?Z߀ P S?e.p Fބw("s way`*ݶ]L!&iaL)PXh2.7^iw%y~^\+NE@фN,O_Uj^ }7Aa5 'Ak}c܏59_`9m(ZvJ˔R+} t.Z|ufyG FD)ꢔJPJ+R2\_c$s8ޛRu=2;Ea3' Luy+ ~n`iPV! `z+E)RZUJ}qK5(/m0p|d7 8hZMVRcyf$UTCH.fCh5((4'7Y<ߖZ(yV։~TaU2)zG|@<\f/K9!Ch|9iPGW_i;d-!tnvdDtϞD&;(oi' >)8Y96R=c5.f$n0/FR>gyJWKs}QJ]VjϬw"Z5Z || l0=f`w2j6r qN'G2oV`L׮Y17>}톽{RP D+`  D..O^) c;97yH!Ю:C"h` C`o,i-bKo*w}fdI}|$mmT6@W}T`:Ϛ f}Rj;^Ut30c?FuVET+M>^&150h0Fj JT` A~^OK>"\ ͆rpGs`l|wR9SkB79u/b>1F=vKۍs iFZ  K)Z`/a&dB*Zy"TJy4OzF4TJ= 4jP& #øNfoAv6~Hk6o&p+ˣij ͆iZ @:h1)\d7Pu1p`Hn LUJ n1+/`/TJ^x2 xSk=b>T0p#Zb>Vk_,r|&];B}ٗU8k( ͸mM*Y!T7Ac7ܷo/<I oCaY; R\/.D}0ihR*zUwZS/VmN/7΅pז-ܗBۍp[.eͦMM4%$2qBR`L <+D`,T8cY)JHE!u F yAޓ&1d؇1ڣ//3۰G< IDATbz}Y>;k$ {S4pٳ=ag/|ib>j7Xl~+ӳ`>`/#=m,8 .K^,j>;xqv|n7 SgU13셨_o]wƒ@!nJC0&b-N9}d+Ļ-;^[c$ Q1Jc{7Sצp (C&ԓJuf K[jJ9$^zb7`pa~o9y<5۴֟17vJ0~ Œ*L cfŧJJ{ymx%:ڄt:^}6~l!yH~;g'I)fd+f\1%KȬ<aJpZ! BXHk=M)5\ !v; X oGj VD]aJ*h;0k3RU_ Viݗ3N;(hZcKπܶŔ,]ʑ,r}7ux8%TPGp pu ,#Gx )u@6mxyO}(6[jܯ`My$ Ǵ.`D8s3XEoS۷ׯ'S'fvv%*=3 l!w>B-'gZ/n¯qlǣwQJuĨw¶p9 ޼#]=7kFTvpO.Z=ۗ8YRB ( ;jʬ{aݎ}RǍ /Pm{oKh)0k<{MwU4ɾX\+N +>X>~th(~c_=?l6޾p)xOZ Ge$^!$Dc)#9ztXpG`/~Jko,}p5Kkcσ͞ZWIBv+ .;0RLsw|{›$ !ZP OMצi] cd΅EB9&J madޙz_5 `pI ?'^!BQ0qf$<x9B`u,lFk똅HBBk 0n;|1Z=NkM6{.t} 6iz0DkUx{!h@[xNr@FNgzAg.LCu{=DN)ru^=2GJd"q"9qg6:n-04 "H'99`}?H?l3`{8H DX+RYk·l*H(gHy-HD8BiUJu1~DJZ(_ZPJEX8 ) إtjZ$Nꞽ\hqJNرc˒ "~8;pCFuv!5iҤ>B ! %$$4Nc~kc0P{nl?=I\BR Tq̿= t8&$$HgXp8 &GO?eܹ o[T2!UV9oG/ ԘZw8a44i|[tr}⡇B!6p| < SzY5{Xq巁W^j 5iiih9x .<7"*6f`fuajd_ ~G)g]gC%$#B@84&U{1X ✜QFz!~) p8. ş1Q{fM6u͚5_~H! >{qLw8?68'r-~ȑaB4,$Qf&ӊxñK8zh K#$u޳ ]yw8}-,WDDD0x1cΝiޯBq:3.DCVf*d0OSȑ#-Boju24HNNfƍa fÆ $''guBa#B4T7XZPVVƦMXf k֬!==Oy}c7oN||<ۗ`Z!Յh44>sV\q=±ۛtfrQ?z( ,`1d/ E#(!!Af$()6^Ov{(:nRv:O+MuM?(Hzz:/by@!~!,"믿&11n&Ѳ>Wӳ12֭[O<-B!I`ٳKNw|]S\tx'#--#|r]OB`?sL #8t_]!BBZt:?OE}z5L2Ś !k{cѢEtzќfЭD6mz+VӳgO%lС?9sMqq1ӦM#332Ǝ7BqlnѩM6WNڍ#"1deeQTTġC(++`VO!N^kիhv (ڵ5k_4;ұc-Bx~۶mdffЦv?x. ڴ9B֯_o>2d^jB`rJ;uU&M%((Çf1bJ$cy߹s'[uB-Z0dHϛcct 5j1'&&Ƣ!X322 ksB:5yDD=j>ԳgObcc˗>l K#cw᭩馨8 =zPRY2ۋ9Zs-q5|b\< N||8n7ZORR!qq ޽%AQњ;ޅ QFgСC.Bx5JJJ k]c377'66/_',Ltٷ76qc!Ji9'nkΝŤr}-9pҴligܸh.22}ii6[j~^ۜerY8\WyVٺ|֭~61MnF̲ Xm*-֭[ILL_%%%Oy.\… ˗CCC0`fРA4mڴ>,'`Npp0%%%T5|֯ϧ[P. {iԩ)3=PTE ;))-VwMдiAAPVf|E ;Gո͚5ыl&//<6[(q CkW_}RAHvܓ븷kӢ%hq1G~Ǿ}S).ҥKٷo<1 !?{g@^8M~~:SX褸r~#l"'eeZSPpߏ)_L2ڵk->Bq,˃}˛[xז.aɒ?F>}XyD-JJJxgXnmڌ_ S@O lFAA?|Erj\f`*lι\E>R-˪s~pcQCD5L6͜oAѣǫr |3_@XXWn7SNeVc .̚5/¢ q,˃=E]D@@ش||`tqqxɾn)44?!(9=zXyD ;w.ө}\_ق9|0ӦM_1bvqÔѮ];ufq 0E+^_NQQtMV"Q |@T@zzҿz lذD+O𡈈\g*M,&GFFr5kB֮}ͦM3f ZB ,g-ojJ65:s~ᇵv WUA])%S$ 7K/3 1]vrXC%K^o+OAAAfem\JӦ,a$8gHIIaV&C |}y|C46JNJJJ[[U6 J)&NX>?>K 6== Akqqq%+Wer?BrrJPŦ|XR8`'R*P{wey/pL&dNB.Qr :JrĭrSRB{sRT U*Jl@H =Lf} !aK2|yyy߼3@fw#B!BN@bawfܰLɼ⋁3暚^{mEEpmRf^{̮]s^~e.,X(--"if/*fPTT#& ޼ P?<*TzEQ!wE2E˅:EQL`"`4 O=&L7ߤ}rr3a­$&fv먩ftEFF2o<͛8۬8ҰPUU@RT4wb^Ŵi ~L39t}ߏB hnnV4 ZFvIBBFP* uFN& 1"nV)[a/Lɾǜ9s馛Xv-6mmVm*0ntƎ8C:N ؿ+#""9s&{{6477Ju3,H/Znnn˜jeΝl߾ovZ+W:%%\rrr8q<E !6) L\@Rs)@ WQSm%,=?#'?c֭vڎc;NZAˊw{=7{7L${>U RZছb#w)XG{ 3fĠժ(//=(wݕ_v neJ>%f-TVVfQO,PV'ӄsr'Na6l؀Fa̟?Ӷ#_ ZMv@t@({nL1x $xPQ *l}$q{1***(--@(6j(NԩS8q"N'GE ę{fs'.W=.WhmE~~>_}v#!!]KaJQb%U !BOsG& !l.EQo=(! !JEwa{j&MĤIxq:YVIHH,ّjueL-tQUՉϧPQyƁ׫P^n3'~ONGI棏Q|I eevLH~8x!hZm?@nW^y>,Г7=q:6U*-ju:QQO#=i:s*\6l͛Y`d+3{:9" {FeEyXS`pWyKv !~Lajz҈Gkk+.WK2'`A2fQ\lc6݁ɤ!/DWa4Fs`M#ɓ Atb&?tO :]O3jzt&ƌyA{GΪUaѢEz~R Ⱥ{ۻޟϦWz;S;I:q"ula^xPXdLw%SnNNVwG}6F^Ig7=菫MZhzݍǣ0j:omDBzkUUc]?-fiٻw/K.(js5 = @PSS3<#/HbĔKOϣV끠eH&%EC{^ڵ\z^^3 a[вbE&NO]^/05۷wPXtG=g?L8q˅VkbҤb0LBCAf;8~8? v~ֆZÔ)oa0g}oɳ^?_駟|IF񥰕ZFQ|=ZpxhowuUˋַ*u;/(_>Lw'd;|[qi$^ [QQQLq|{tzY>S__DP&᧪[0~bnGq$%Y,|I:g2Ka'bԞbi~Ç; 큒NuV=rϢRE|wS;vyyy44I΅LRXtqߐU{uh=zbR^LDIʐkٴI|>cƌᩧ STT@Jt"#B^ oIJF;B%4b̟?[n;^!qZ-[FttYB' uIvQ 5u)J҅#I#/~ ٽ{7۶LS^f\Z=nO岣VYd iiiOtuu韘`0RHySIKd_hnnH#L҈VYl/ٳ}~HLy uⴘ%Bd/]222{AQhiiVz=FHbb?hZllGx7~\\>{mm<_GNX"˗W&n9 _m2]vETTII^}iIII~KL%OABB dee:i\}SW6.|rjN#?ouB@]]ٶ%rssyB|T  b1ԁH$J||'AJU<{h$!{}vf3!se#fssNz詥%]uhjں:_[w9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D u𲊺Qm])3=a40f󹈳@#Ahn9I]m~ \fN`Gﯥ@E#t?ȁh {"sA9 xa<0D"f`fٍw2fiffm$Yfqf#3bf6OdIo5IRǵf0%͐tCl]Kwsgf#f6o6'.t%-OVxI#)97\bw.9l>9Wfjs/:ދ}$iJǟH::3pSIc$%Mr=;%=*ǒ2$97o75)i]&iiq+m\$nb۶J9fefK%e vFH:9Pota()4UYf54BjIw; cmFN4Vsƅ9~=hE xg.7 ,}۟ I%=.aH$z3qpOͬnj%=蝪%%df&CIꪐ4rp~Th {&tN^!)KZIKk6Iձ,YXOHJ4bm],YI)Z#{Npg%wKQ44=kf/J97̆*8,Iι%VwIys1I2}V&49qz&v|_Iņ:if*M[9pҧԹsn-᜛;6ARu?TIwlEWcs]߄ܙxs9wsc߈ ,i] ĂE@] iY?nyed7 $i-0Eq쾇>۩MaoKafla,eϾ}Cw䜛gfWH*t"I],9W?Th+,[coY+97jsIv +54}5)J%MwΝ}=@;9gمflΓdI, QTþ)dfyNޕ̾^:34N{8|30EcN&iu}5I5#Vޗ/^r5f\R%][뜫tw6|E]H8GJZsnaNIlyْ*:d7Iڪ3K Oi^BY>_o%i21gI 3sfh~k++y5K%EKwŤg뱿hv, OgIrmi}B?bwLҶ;ܝkmK0ҦaJ 6]<36eo)j/saߐն)@0K xa<0D"sA9@[M-ݏ@ ̵#fO!HrIcI%}kĔHvb:a _xIK:CҐ}8ޖws-Pb`\/Ԗ5h~ u t46`f>IIYR߯oKѥS['UIe{T')G%tsUO&fN3oaeV[@GCkefv[$ jmJ-ҹ[3^3*=Ez0G$INO쯒qUIy[,+ݚ}̌åϵut$VbftWk"ytB龵vpyt2iSt@R]$qmЮ&j|+U?ųșlW$ ^(ݲ@:kޭVzbtrCWJ>OsMWWW+/Mq^Vﯦ_^-$J}DV0$()C2'btO,5#$IϘu߮H؂aKh. 3 )5(=tBI[N/f# )q5@!̵3,MIRf7IүJ=rbfYh-`fɒ^#g&KU\Òޞ".$ƵhGID3mSSEVnIJo/TIJR41)暙H^V#2Jzh I?oJsIRZlikXN&.t8f`fٍw2fiffm$Yfqf#D!r[Pw^}8}"bf6OdIo5Iḿf0%͐tCl]Kfffv2fg3볿anN5fK3˾ã ڬdwݥakPHWOS6gf}G~:qМ.tG$hpigT}1RsÝs]&is~WE IJ%fhs{4IKlfٹf}E/W 5kTvݚG{[;'i_B뒜{$m4fm:smrMq=ܰ|fS3{6\[if3c/iܨif63{F3%%Ŏ̎0_ٿC0,̮535nVnf13̮ک[,̎GIfv] aEskp`fwY^~cff[蜻9797O5&Y߽9nk3$(io{,u)W_*)'U |0I6=ˌCp\$.>1l .ntkl(%af$ QR$+Ox}uwǍ>te%KIg;sKk؛zX>IϸOvu`cf(ι{6jaSZZ53شY!)v-4RIE4JD~mQ,-Z'c݆ Nu›7k[^ZۍmR]ðs7H3CwhnC EU}ݮ)f圛gfWH*tCYsr,97\qꪝهKt\ ι==>04BёvTӕJ;cT敏Pͷ$Vtt sCgN9[ض,ӴIHU''+aݨQV\rI3^ԥa[j[7u^Ne;0q&@7ћo5\+Nm̸sHHH&1 ,'$l$Rt_Ɔ(a_E.St"fIQbt1YFNŊ>&I$ 1PbS&fvd /I06՛6J{s{`fc%3%ur]Emd`-]{ TWj-M8$qFA;ƙ"IsE9)6):r-iwI>VUYNxMzEϷHڝGJ:Ngfb)MZmG%K؄}D0q3:gtQMjx@wIϧȜ9Z׏JKUJ%3⋵c&ӄ?>ж9wsnCjv)isn>9wLgxC r97MҀ(s[c4%f轩q;F_W9h9^q&i[][I2Km?ٝak|H&sqVt;ιF89Z}~ s;Hc*ڵ>Hmfr)r)zK榛4vcnM޾圛 ):oOl)j/sMeێ}CvW~C,ϻ$0Kwޱz_ipg8jlsG(lٷx}v):yI?/׋ΕKzl47s]* žix, G?r},?;B*Uun uQlbzK׎V-+N/ܗ-s\3sν̖9_(C'FtER]%@ ̵_KjҤ 6Ʃ͆Wxdts[\ p-t42^5COo-|Z a8ސtMۊQҰIkC.\tKc|"'-zZ&hAιͬc+=~t֖8 p4؊Œq[ϯ|.)9#q-;v{[V]q]cf%#twt ??ҚwD*[Ks'$EzJplR" )?xG`gEttιlNJo,]T)~?_KN>:vJ05` i'C|o&TU_]isl񴼻o;|Ա8ktϝ:&"أ~/7a(e\\pN3W%tkB5sEMv5H=PFu^3Ͽvq'pk@AKu}/gL*I@HNuUYٗ՚9ߟ䲲/̺EBsk]|٭+~|CYiAC\>b钔zl{ϧf Xf.'5߯۸gN{ۖM+Si9#=s>X{?rr@\f|ε͒윟TKK2gChsvpчg K3$k{˻vgjWrIZvazP^0`>sKKR^+s.6k%/ܼ+$iv~;zUhs$I+Lt$)#ڮTR*tq[EZ{vռ:a$OrJHR3f\O;s[> aMy)oúřԵ>bWo(5eϚfN^%0"}%)5u|]vΙ>S{XrW26(Iotw! lKTwv^\oJ^dzZ^-0̜'I Cimnc㻆%iwj9d繒}Jsq>F4m@A`+L+/۞(I9ygW|r͵ krΪ-,5"kHϗi! $wN|ԩo>)۶yXI5 sm]SZ-A;͜kζ{LT~x\YuiW\\~$o@G`e9}79ꫧMܻ)??1<E COO'ud\cOԖǛY֖rsrNZWZgIwUg%}f|ZfϿlYjJnwUk|BP0_VZߒ+f  cw:wZYvIDAT>@a? $\vwY i.'lw*ʊW\YuH蔓/~B)xbHO7& ÒTVZȝ9Z'I@R|N;/3*h>c_]cFS_c>'Saa$HMI&|N8' ;'s:? Vnz'X5dp !'|O4@0K`gͯ95Х7p?o, y>ߠY+ |&g>Bm$_ΚL |C% HPMJ%)-#Z303$)X5`oN['ħ~>5XECn⤆TPG/{VUpgʂ>s3xqRVe q jj$m%96bq@\$l}-gTϊ+,Em+?l]&u3fkf 4l7>RW񔺪5nAג%)>>1s>sfNaYL"GwJQ[_/0sBv&IZ~EKuΔG!)9st׭KLJk}KݜWd፹HRR2gm}eJҖMooߔml\tZR%;^r_G I:+6wS)9͛.%3\Qg $u6|I?!$w5_U̩ԬL5UY- ZZzn}Ƌt9;/Km|=KKL0sgK I9]m}]#? 'iw5՛>|fukN\֬|"ӏU[-D.Žj^ںϸ,JM͚nXUUi3Z}F17&$4D$_ޔ~˙]7gw/4]:⬮KҺzqKn8\;qPo?Nz~ AG9͍n5K=zYݺTޭw+;wP%4ipֶl ew6mx/>X旤Gn`&0wCO-(Ҷ-hs/˙áwH^꒒R:KRuզꭁ-qe+| 8Dιz}Vvg&:jں:am&=mi9E7%6rzT vX '_)/g]s׈v0@3c%}ҩKڋ~t*Il^8g9+|UVVXUQ_]]\$SSRYj _<;m<oK]Ig^a]$҂8I̯-0Y|>o-WsA9 xa<0D"sA9 xa@֬³³w3ݬ`]~|颩v樱5UnqHںF:kΜF׸H$'=&@oMj:[K$ɒkR] мϺ7pqBq'p$Z>;u9iH _ֻߨo\$y颩p W֧誝Ï(̯//7k9qq [h#L(MLJ /[<-==3/XSUX#`[ZzNhə/MZwa|~'IK~߫.7G$mm󪤡#.D6c9c9x";JRI/gY-ua6mXTYY߹W$mݼ*nߧ貪Ҹɓ}9ZyԄ $iOu~{xHq.}z޿E,)=4C<{{EyQQߩK>oWu]y.T0wY0grcG2n>ϽC=̭G@V,>gy`KE)ʸ7_ߟ`w[6HKwUQOh:s@S\%|U'UFS&I/mwJ?GM8޼dgoUۛ6,K~>\~IJ{o=--='?7.K?𠒆#FW"}}9iYٝjvX#Iq^}GnX8URq'5|ܵ_ŪӇ8li}ަmF];7Ia|.5-;WӊF9`ovR~޿{r/x۳..6I29s1115Խ򩟼صn@7|#Ȭ/U[~]ucȃwxX -]tFvMu_rޞj?҂-W&JT֭]ٻ I{XU_8]ֳ+z ._xzvcz,0`ʶ' GHĶm]ݥ/$I<[/>豇gPMI ;p%ϼ/>w9Sm뒯7ϮA͓ '4q¹pqg@ ~}`͑^?GX:3OQ%:PFtbQ}Y|iɶ䔌gr^<Q_WWQd| =tKۺ]I 'KLLM5ާ,0oY9]r̴#.k^m]%3" rhYk++7.O8d|$9h'Qu#Eg{t?֮^׸UgnX$%7[ݰQǖ}5"?gƤ.Wgt nL;`le$>>꘲lX(9!)5ߩW$m[0grfZzNa/[<=} -vT^5qsm] a͂0w`{u?L~{n^+~Ҷ af0K20鍿|n =M{? 0`׶u f"Ww`o˦I߶ښJ-3#oc9wm7@K"PCz^!I.L~G}۶͟Wm(MѭJ&}Ooa3ݬHK UW0kJeV2u'lX8>XKN-q֐Gft C&IK|U__+tС%Djk*sf]^V7p>FW\C}ַzŗ5Օ韽k= 7[l1Ts_|j1Ǘ,YYFYiAq'^5emۼ:[UW}SygUuگz츓nULZt9gn~)m[9-CТ#9pڧ/-[<-{'|+KO :{!UsgSW[wԊ-WC5+K胾SRT1/ӹ&S}It5BVmmr}ֿfts+^n=֣}<Gs~$=R .ңЊ:_`߀JNy/*Y9]kof^t_"IK~胿ٷؒ`]ߺKA|Hɲ%ӳN8-˖L4t|S8Kgd 4aߒ-I?uj\\BD~?GLNqN_u]+]ۿǯ:ᤉ[KJN ?ez$֣UsfNosoA%g%V[[I$l=lsH_ +/+xu'VX~u^~Ϻ^yϡ{?i$=5ˊR 96)>9e^<;v3λfMþ,irMaՏ?t " CV[SWT1!7G[ _U#*>z_o1fBq絫e|>Пs.NsHf̜z5 2¡zsm/X߳nUi'u m zXez^A:3l{xu ..2Ws{xuþ)ҶsN}*2ϭsE32NBbr痋|=Kffvіs>4;j7w6& ӏaY\aMrJFwrꊸ}vPdYN$-]4rC"JϟW/W}64vYc2:N/};~܀WWl[|ío^}FT%$i9FWg{E#2r%6{y׬}WڶumJo s;Nti[q* Z>;uȰ#<"9%=,I۶Nu9dǰ-W&FacPMúmn^4tđe@ x 7$gqTYJJn߼qyRM #FWq丸H.}k%¿v!Ï,s?<[dz+#Z:H$b| l舣֯]ܭԬ$nLXӌ=ްvaaG7>{k"Hsh9{Aں#sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<0D"sA9 xa<^NIENDB`libvips-8.18.2/doc/images/Vips-smp.png000066400000000000000000000261431516303661500175340ustar00rootroot00000000000000PNG  IHDR IDATx{XUu{"j&)y PA9xijjy*W3IdjYd6fYvlP<+Pp~ **Y{~]ו{)}e[a*q8Pλ = ԯEܧ:A= ԏG7$P øhXrO"(9u== dH= ~tH:y/J.A,s^(''e`eZZL!Czll”pƺtHR0׬}JP+Ngw'VW{]p !)W9rZGUqq/UBR"(5k4|x0pJYT˩S%0a֯ɽխ[ G|pYןаaԠCɑ I%Ξ-{mGejԨEE]kHTi߾SISf -%ɛ4th||퀠T-+BJG2$I?pTCRPPS͝ۏ;J"L٢:1cz曯6{$BPؑ_LShh3-XFfqJRCҬY_:GX%ѣe=g8_AAMɣ0W_ԫU5vBQ [wB&ݢk۰![ÆOYO+!Y3(Ξ-̙Zpbbnw1{$DPJ11kմi-XnlH^䓽4i{ wO+`Ezڷ@Gaax,.imݺ.ĎXQSoE_~yPS,/cGFLSpJI]J2wkz普J"ǎTPpz<% [@>=%x&WB-у Ď<ƍ>| Ђ Qr:K5kVRRhtU45nHjEOJ KSB&=hx=[ckϞSzcYOkVԟ0($EENME_|qP/SJO'"(;wk4kהVGP@=*-5[ᄏ]O?UOO#(;vZtdv0{$T@=(i޽fKHzvFgfq߬nPC(M{ZϞ-i%$;Jp1T￿C ֋/Ѐm u@P eehԨ45j#u5z;\O)!ay$LÇחnYA uWck>6SAg%|uf1 R-[6RRRB҂Q@-;[n&%Ю]e=m4тjтV+#(JK }͘MO=E?!fz@P@5?~F딗W>뮣.x.cժC6lv М9} IaG Q7)" :;bG Uؼ9GÇRIIRRIcG 8={wJف5j6QRRnJ_'nil-?u|έ)a m1 J4~$!*`;=˖e{ӊK"(e=^D))QJPZjh=>}.oC ^`yǏ/Snn`*P}<Ҿs=vB5Ǝ%>}V'n?oܤ=C`9[9TJJ!:aG 2R͙S /tw=,` :iKq 륦C}[kI;J^+?XƭWFFMU;SAcG +?5t*5opvJqSSM5ztn#J^cϞ92MZk( #(xRC}wJO+A 8QӚ]ٳ*$#fx6lÛkB`G >}VzQի#Q([jU*(8 " I%tjܝJL,izZJ;tPFph|zZY8z`e˲ߨo֚1VxvLqdƏߠ[۷멠gbG ޥ6kP Ix4vMIIYO맟KO+<A ^sR11ij_ Dꪫ [Z(SӦmoC0{,Jnsť3zjߞ :x}Wڱc3}! ŎK9sV wGk7ލ%)iF'O(%%%PgNgwiܝz^zZa%:9|PFaJJk+Z,=7ӧ}! KbG {Zlɥǎ@]{\ÆRӦ IH)))ܹԳgOXZNN( 0@999nyJJz-bb"Ը1RjҥK+//O#G԰a**,,L Wll[`̓z "կe氏jebbBBB#ámV\KMMճ>&M(::Zn@[(Sw5yroa;5:7q8ʊrʊ߯`IRHH\8"3dg).nVy P~~O_%qkذ w5k^cƌx]vڻw:vLUQyZa xo=qnԍ7RAT{GOرcӄ t 7T\4hUXX <-pmr(/X))$j({衈eggO>JJJ!CE۷.\aYyvvivfx$0 sp8n >\^Z+ЫR6M pK*楘Z~A3`W˗gQޭ{}I"lԩmڔ.]Z=Q6n RJN$$j`G @IS3flK7k %`q{RLL`AZ E25u=DgCPS%`A99Ezt:TYnWhfx-,f#:tGHuĎ"&MڬUk_覛6{$Q}{x`IH.ĎbNgvkΜnBP^BN%%JL짶m܁W }=7斚9! ;J:U_ߠ r4eJouJn(/^ڰ# I<ٳz5EF '`ȑijޜV,%LMEKg BO+`0=jաtx WѰatuM؏<;J95yf}!K7L)Jdy92M͔ @%%`Tɻ;Uw#A ԓŒuiVEEN͝OAATAyHUW5Ұaz0LJ*d'cL@M,FUdu%@Pn~%F99Ej"sB%FcƤ{ FB.< 'UVVƏQ x+pMYG=:p1TFGqA ;C p Ж-9JNޭT ș3gV/][71{.BP.Y_\wd(\W##JI4{.FPu[u;J?bu4fzsOnjG%P|WQ G@-Ѿ;JRZw (Z3g6}^ں5WII4>;p5pYF`#%P&mQu=v+PMW7}tӋf8za̘6fw!(Xd;٣0G%de(!a;.}Gh쌠.vAx8zukͣ};JgΜULL%pI(Hq ۢ}@uT޾_7w\A [<}gРvfq ᇣZRRhpy%l%7H/NcR<^a+cǮ>t>sJ>^a (>5ǎt꥗H#(aysC=Qx!^ai۶*1qhP;|e9k}@ɓ7c+5x0;jWX?_ӾJXNy+}@q 7n h[nie(,,]OwSOѾ58zekGbA}!;܇%Rnnbc).EP+M"(uRSӾ=Jx 4q&wv0A KhP8zWؾ}g޼~W|Ɓ+kY6m=!(L٢f0ErѢE޽5j޽{kݺurrr4p@kq˰,k9٣jeJJÇkСbccl+66-^5ztYN@@#`SIa5M'O5\BIR|ruQ;v=ܣ]vUC5 ?eFzvjg钥y)ֿp{ _+88XZHe;v駻= qP{Zd&O\YTT?*ĉ4v/h`e||N˗+ (ڵ޽{%I \Ra\(W}sgwGRvucƌќ9sW_骫:ڠAB%$$h7o.0]y66(ѕpѣ%IW_}ukO4dhB}… 9;,j\};u~VTqɝ奎Hb W*oyٮ0]9 SlQW藿Qؘ`cH):LW޾i(pS+6v^~霠j Ӹqu[[= T-Ȋ{o}_;w멧= r&6Bw8tPoIo}V9q&}*TGA_OT<̃z[N#:= \g^Wy3giLzSTȑimiJԛ*k߹>wx^Q/֬9/}aG +kACPƏ_kumט= Gpe˲= A 9|Po^WY^Z}w#(IIu?ލ0܎y=;C}\;h` %\j- B;W̚5vpbƮ}p7ִ^Qg˖ei۶<%'ӾzJ ;WZy΃ҾJe;?L cG?C6>áwyh`m%jЯl(vF֬9о6Qh`G%6_kh`+Z>w2BLyHJ-|miK!(mrH[ (m5;K (m"=Z]#(m$-WFH6pane I~š= X;J/f1g룏x;J/RTԸqP&|"sPԯ_kG`[%=Z QVQzGպuG[!(eY)fѫ/V|&߬ y=ԩ[տkuh(`K(=ƍZ-=`v|+lPɻռ jg(`kzÇ 5kVfk(`{(=olҐ!QJsgy$Q"(=g=ԨDPzwݮ=ջw+Gy<Ν}(GTŽ;v|Z7{@%JQ|9998p5`tH[dJJJ= <J0dFbccl+66eZ]NNzkFAlӸ3sjj}Y5iDJMMuŇͺ u`(*a+80$$DYYYv\kД)[4`@uQ.ŽEOPzÎΞ-رsԬ\eDD,$EGwWLje-$%$l֧0qpZ C}0a5TUHV;\AYC;l]FH5YO>ٹ$Xo6m+_QրY 6*:쀠Ey8٣ ۢj-Ҍ4}mfG(wi6 kn(zĎvӊ+QVÄ Q+(7X]٣L@P^™3gY/]Qݩ.]tMW= $WJI_}P'N 탲ȩ7AqcdHLܩΝt.dy.ԼyD+jQNE}{mK+j ʵkkݺz\gˠt:K5aF=LW\dˠ\x4ijk(gT~~M۪߾U>>x8(gخkչ3}˳Վr׮|-[EsTvoIsZP= ʕ+2٣2"b""W><}ljDD,[nTaaWwV&NF !YnC&Lv ʪB:W\P_kTrA)U$6,NU+ڲdg[֘10{\Pfe`;zߤ?Zjl( TPYsL۷顇:= ",NgxcQ#_Xe* O5{XabMMӦj(Ďrƌ튌V:= b~GgI}~-Zt٣,w'nң+0٣,ȫ++@C7{EymP8曛s԰!oeJmT}6{y<%I-Z< jGYS훙8 &(+^"(/%"(0Wez@]yEPJvw&M(::Z%A~KBBB  0ATPP DW\q.uQQQZjU]TΞ=[p8\vi޽ر233TrʋRװzVi-vYTֺrAB%$$h%G2d;W .T-?MacNk:p&(.XeZN5AI3AauZ]:.\V8zq eV-Sw8?g5/ZHݻwWFԻwo[⚕֚Ν;O={Ԋ+*Yi咓kV[g{jk},sju3 Z]ijPZL0>ee5(99Y>|ZqJk]t>siȑ6lX5+S4e 2׭N:|M:Ur:Jrر>|x5W0Khhc0 ### 5mwk77n\s+̙3… =zTfu>|իi 4kVZaT}ZoFO?YСO?UVuJ2L ʆ ņaFqqg,P՟g1V[7h_uȈ4{0 [n\:I2JiӦ̊kVZsM41:ud׬r_9_F)a{ァ%Khf6a(??_z'x 1B}$۷0 iϞ=ҥ9GuVt:G?=[͚5K>? f?[+yĉF=Ǐjeǯ":嬲Ϊ 6ja]aFNN`8qzjҎeV[1c4g}Wꪫιf>:v4ap ׬N|:ϗǟt+ٳUXXٳg[n׬NIJJJw߭s^w:]5v ;4;6mW%*ښZӧ ðZgΜii7N###⚕Y_4''Ǹ{ ???{Fzzz5+0 gϞ_|quY$f.f.)M@z1I\cnNUuqO8ޫ8zfu== s p8.ܓ@~lp_spOpIENDB`libvips-8.18.2/doc/images/interconvert.png000066400000000000000000000664241516303661500205460ustar00rootroot00000000000000PNG  IHDRYssBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwxTE[ ! PC-ޛ4)Rl("b{E?D_ATU@޶|dҀf3g޽ܓΙ3gQ!-n@k>Ppi@p;@ H$DbAZq.ZH$B6+0[pw64OzP+s@k 1n |!5H$Dbi*AP<D"Xb AS`ix6Vx#S |N+;ӁoE`D"H(=M/@[2B4x: |Ra?d# `=bA"H$Ƒ=* ~ SwhWPv <\ H$;Ǒ WfXXTY*x5hX< oD"HG20.`psOem#D"H$w#y\ @t[m-P>#,pI$DRG< GDI0g#iTD"H$w#K1 Nn5` EUD" b4ڊGNbs62Cm$D"-Z[ `!-&D!!$.Wkm-B!u6;8Q"p؃)dOhg0B]fшbe]=K$KXp*i-X@Tb"e`Z3:w.aèCYZ(A!t~FƁ"m3#~=rH,@BX JlRCjp  ]3 a(T6:)0Ud>2$gQ^pų1Q4mrՐAp+6&p{=JhNKN&g:ncj1<Az=U-ON#h3h6m" 03fbȦEmuCpjǤ0蜿+8 q=l%z"N1 <LGب #,J6\7 uFb\`e5-BbS\FRq/(6cc?^8^ܙw.{5ŸnQQ=Yr-Zu N> lr۷giRc})}NYçKw7Y%WɫU(-awUx{᰾MZL±#x_649ScҙGa4 M+"s$DbCagf,7y |P :wfeF,9twޡs-mۖ{ >!8SV;vSvx.GL3IX 8AtX oq.o_ahaRFtbeGh_1a_7ڙ8Z c5BJ$ ܧF#/37&"//ܫVb@' 99e ڶ&W>0Ӊ)t=P$ %]nrr :MmX[V53a>2Ry2͚7'+1C Z@:W]Kѣ$ %7b@k1ʜp=f[9 R@OumuT7}Ͻ6=P,UiʗZeq)?p;2h҄%K8Ebڦ<jhLǷnMHTʕޝV[it޳ii. n ̨F[яe +7G6P1eq퍷'sa׽O5L]voh'H,#x D,\&ܹNO'۴b>Ms׈ ~ÛoһeKԭoW?H.޶I7oZ=zh8f k !8ld1VЅ0Plxf W", #@N0b}}_XS=Iy 7Ap ėݡ3 !D0V%n gsn]hܘG2{6;^%anz nnܚ5GtS޽$Fs-bW0wǏb.C~{D \FU;(cNi6PHx!0@͛} 뱉N}s XA,{H,#,;xr!~TIŸOv4ܙbbLT{|@:*| AU"gcπ@+,vP6R,8A9u7 MUtvR)6Yd( Z<ΰB \`!X䪠p7ҡ3$[Aom!oEM)h%7Kk0)r ",&C)DUΊtEG9hjNzx͔x=©(BraO"(2PR hFjp[g׸cP- мM:'Ē8A+b :>B3S/(o< -(:]((]3^ "`2F޿`_|/DX&ΜI#Kh6"]'i{7}Z%[FWYCd*,L4bOϡz9*V+nB@0p ŋW:fvJc(1`͆eƍ$h>A¨ohrbctNH\ Td"S*\ ֔]HLJ99SzZF$kW6l7QQdxxFSҽ@2>DbC"6cát8AD'!I8B]#1PQUM #N~6ލnڧӡ>C^F!YHڕ徢yjR]H B)T M~tZ9å39n~̂\ܵ  yőYҽE 1%J~8 !011Ձ3`70n,}B[tdʊxq˦՚FCCqgNbJ187d5L> EuYj&,o L"b_MO$hz<MTt\>{rc~KNٳL:| {pi"Mނ1XĒR=D-pdDT(:5c#,Z \Vnjax3`D$ad lF-woI42/b u)ɰ0^NŢƍ&'"/CA. Q'rM *kptW~4бER¨ ''4>Dr29/ޣu&N /wD~'uN>jk:Z āptD`l fZZwš!j< lRޛ0 tZ3(APܨ62lrZg   :z77TE߻q*,QRig8D0ULp@6>jqR1̞'e ϭ:uJ 4 wVjF:]Ka@ $Qc shgCfX04p֕2Ea_q7@%,DH2a#%ٓ{!Aw '{ś7tn9sePsvN-0ZVi~4k: 'krS'6kkƄ~ŋ\wqA[ҽEz2  WGA A nhp HuLWXK+`B-`A5$( ᚶU/*F,YwgتUJL$m[Bv/sn0KqJsۄlZ`/D[02;wBF;23=m_wq0&G]<l@LWH݈@=`nO)^zDR-{'X.6Ww[*lCC0\SdU4 Xi5l,:&0`M[ǀR|`JGlG}g?RHXXgcY$'D7Dd5Iwq?_MlyiUAo[Y€ ^ZES1^Į ǀ@mEXi"D\ Dׅ88UA#xY7_{0:gb8;|kLvH$eGs?jcY$t~;:l򇡯+ -P2Xț6EZjɈl#DrgB~D ip!G6Bi]^m7 Uz}~x+q" * NdHUh \W= K$A^Ī:ۊ#c @d^~qK2F)F/TQـԅӍaƝ\ hSQ׀SNp1-tBAe~+a_j9WZ D埔Zx"rEPׂ cL 7M)fX~uAa6P-=Nto?@bh! :c-{#^p;? HH?[xxn̲q`p;!^l*; 8G,oT^A+@mZ 3{?zÖc*Ż; }&P$R4BG~H1AJ$iT,bĈI+s+_\}CĔύR%/cB!hQ&:܆g'8rݔ?rL?S`EG yL>}v|[~G:CUDM" :=)_ vC䡘 T߭2%Aq^YଇdWHWP^fBLSV&T%M ~uCp%gxg-WHj W@ىF/Ć8qpQnqU_{QPuw]r]":CPqqFT{1x-tM_D|7Ċ>DJۍ 74B)B!X' a4D!JA dD"C?RXX XD"T2 DVC0%D")w M K H$Db%S@$ւH$Db"#$DbgAāD"C,=ikAxD"T s]m-!$DR!ipE H$a xeH$(s+xGl-D"H$ pkkA*xֶD"H$KQgdD"H*s㒂xD"T*F' %/ H$Jɣaւ2^@"H$ xmPD"TZ^FwdB~D"8 XH$TTƲXSƲH$DR!P!F+.)l-D"3o)@>P p@XY6Kx{V(XG"4p)q+\_"H$B00 ؀ehY`xpTUwx+0aP\l:5"oܻ[/zגH$X4Ȁz < 'A`:h8#b k݄3,4j*YP+%_!S\u2^@"H6e 1ঃ.q-$Btp3~N'a/׀gN [1ϫ!ouuӎ)P-Ǹ*U*f9e : K$D{݂ä+ॿKf@>1_ƶxљ9 *`°: EU{`Z4ʼ[ZcJ8Q H$=P P`%!VOYGaUb?.\Qpas .jm> Y,,s(W !|txc$_"H*n4Gţ> ]xJCi a~3ЩQNQG$ + ~iֹj0{(;>SވDJہ71!D"  h(EIֿ_~0;$"V$ 1 B@_á-ZD̅% :áʎt`2^@"H,!~ҭ0܋' 7<4;%WTj'Q#,5Rv$=D"Gu2-0`(k7ALDYIy*23v7\tl3yX1"H$ @G1}' 1\έ-a h @*"Ѱط [B Ql%<>.EDHD"#6ewa`eɯ IDAT[ S7!U$4^ ‰s d!X1s3ͮ]CG-H$G3V/ NV|2DFC| p hpW!߭'!00G񦥇l-D"Td)Y@95UhvLΊB|_lAOVn܏a H$Q `ؼtfy{Դ<+P :|0"p{ $2(AOSՙz *(=sܳ4C EACNcsժfCCD"48A[$@T,4 @;n5,s=\h:j(mQXiqDBZwwfWJH$(A[2Etx/>/oy ,ZpddLv6ݼɄ~Clg#hkUmXEFtHuMղkj>>,`';9/ȫE6H$]B |k( ThFeB;s,+N,%C|z${W6? ؀F%82ߟ*y{Y1*N K HwGȼί!H$Gx":W <"U*k6lw3(:qNo<YGF2qFMH0׭tl,~^?bZ_- x&bɈ*];o }|&)KWI$X pȥh?HL8w;g< RahPˆ(2MJ;>b=DSx}Ə?FISK`QWp\'[YN G5nÇ໵Vq')Woȍ}٭5jr0ݺQ8h:wض}; ۷У{sl:2RCJ$DAF-SշM1s&_|\NK#+(_>!#̨(L_DBzTIInja;fM\Υ2⯿)҅z?? ڟelj\,b=8 6o#SډEx8BQ/sMqq){7w,]^:œi2JyIߖhpH DMs}zϋ1TR2!@c-\\O k!(v`dϜyhtzxT*nnx{NIAǭ[NL cDz-#Q)R 04|y + v=%s'!x%:-]ʮɓ0> ȫ`=:ZwxܮI3yRJ`?hkW ,>K>h Apʗc mR%9QӤ0G.]h~gAF`z;u§S'=6F`bo3j$%qkfih}f&9\Rd^jvZd'^F#x_}%.T6.cƀ9K\9)jn(X/[1))$s5lH%%q3* v.Z~|ASMq$g% x#;$_ /ʨg`l[ 衴}5x]+]^ 7 tŜr HwB$kDtGvxxN~N޷j <> -0Pi[FۉQ ̀p󓻹;笝Qt Gsr '٘9M {4ըQeeI>)mˑOr^ROMDne .Ha j_ >V;c>GɾW혺x5@_E 4. 5|ᜩC#F3KG%h-:`%xtMKia~}*ĸ,G1flxÖeW;tN{[KT *TLu SW^GXS`#H솁[GU(DX3Cux%\5-w= .oabҙw/A3 Z_j <@a7<?.gC h;- ޴}'0/ G1@ Plukl-<yLB ;KYr>(-Asx I' /Ĕvݑ-`i% ( / xeGX*U}^Bws?"^B U`>xJF--kkLv#KދXGrǀ W]"}40!HgE]XS:6ץyN5@L(DwB9=5-ؾ&`5} [Pn3[ـ nM+ Uck ?wi GFvVò6nj[O(o;l)5.CPm- ̈́,w`>%؜J@a.5wN@,b Qm'@x'CoiLZ.Zx:V#-G4@<abXO0L :`"I9gZ!0 C:X|Do0F {dW_b#B狰kiK\sƣ!ɝwĄ7+  GC+"hΰA/KVY@g!b4d8#FM؄XGõ0?hO+bL oT@!7[Bh.΅:= 4_e_2"04}s@qS:] |9# %`0h:f#v Wp \BM}.:X`s]b@ښ!鈵k 0`/cXxs*!"TtH\:'8uK \B'#{qﱤdT3byhտwf$k)/@38мs<3u%&ZK LA'`[6? 7^@za1wh4,z ZD1\6#gŮAmxͼr[gBrb1Det@ĚoSNI y9` 7\xJu ǞPUsx%;g`4ON@Z@J5'@(x-<O*j btE!*ǭځ Kj%hE\Z7S`w0jh :D\"Kv*FHex I.l-UKZ x_+yd/ӁuWTdM_`[X `8H3l>N}BOe;"G# J&o ЅV077WܡN/:P-x 7w1-@:W!vJ*KKÈ* ;;["rd,϶XAZ-P{};C賃E8ݛȫQkkg  mU{ZWK<47+r k][,^ñ "Fd3?Mo1.9a^*: MOC5ڦRm+ pi Alv+,Y'w ~GdK/qLF"2w5 27͛,ZġYW~A"ѧf 'x}XAijNB_}O?54 73[w3[|9] 9@V9QQĿ ;l!tLXn}Go0`hPGGs}\} Lt6e ;/^W 4}ط>}Y>'cߘ_^x#j5,_Ni nlɲs ukV_nǎСm[qiWH]Me2nV C !tT&KZg\V(! wm\0Pta|0ށo|D\X\x#oNMLiymJF +ÔAQ\C k=6 %ET1.bc` e{\D@b/n+Hw*EzL{ΌYٕ? Fn#4*UPoDkx &>{?4s*1T* F#ĐEYun :bmz ˗s%'N~nDD[f&::\t'c&xK]fCMeIr-%\D:wu:ǎ2ok `9 ړ'I n'~݃cb8rի9HrVǤϚ妝;GѧSrXJ=(ߨRa MIܑ#$Ltsp.=}H:wӦCi+ޢgeƀDۮW#dO a$!2cE#:>Gg>b .οtd; TAtyȷj-Dԕ%^43{6UóCed5`Vcغqq$/ r-TRI Æd4‚\TB3hբݛz.z5q>Έ鷏+k'^4z(782c0t(K"W/!_FF$Rn=qKII'eӇqijL-i T#/sa515-T/j53h`wAms0꯿iQku})2 lNPO>+APӏ6A`srBLTZyW(&`pqASm@=l!!iOg TFSb"ϨTZMKp t2t:*P??^yMWs]ϰa=8ljCYcf& D5tgMP+<:ʨѨUg7WίRaЁFtr`,Eq{{E}~5ٮ]AhzjhZT$S k•jDP-O3ŸG`D* С443RC 9 >ǐ9spٶÃ>'ٜ6ϟo++O.A˜I֮]$Ebv6+,oɅg@͚8ĐH\ EؽDUx> oVX oucoBa0C O³0\> S DMJLx8D{,\7Nn|")SV"J 2&p4cŕ8 IB?'S}{t:7s-7\ML$ƍ#c YY,`رtACƒ%lye!pF=v,AZ-Z]2`~|BM ۺU ]af~͓3`~=D ]$ܺE^tlNt oͱkHؾ1:4N6?fM3̽gd=Z&Yw i-lw1ahNFߦAh(%ahjPmFN_sׯscX[dR8W? ("úb?Qc+cָ<Ӣ$ll &M__H\]5woϙCsx9-ݻ9p!gn\Oۗ&=G)S82b.^;GI|3a<˗V. ,a`Z\waԩ'*?d#K7l >CxLLs)H=@ʕ+\/QCݬ IDATpdLF #"H cW_q ;nsgg\26C&)2`/^49iH4{d7`} "dJ;pHn).qgh7f yyM9:}:G?t)| 7agmXH_+=F *qJ!hv.0Y ހo$E3[K!l'l^fka;G1blZAͰ\ F*c2()E܉ +p j5W]՚5 eL^Ő@] 6g!2`&bȷ'Mv6>c(ZU'N\c4(h\H^=vOjBׇaIEգc֛Ba1~~l>wYoF^nOe57: R$`wS1wuHo/qy^!;Lm8n5cfy;=6cmi8^c1쑷yT!'.o &}zzm+ H)#0bzXmʿx$#)TTkh B@b0*6CzW+CH U.HH~w/$ VqNb!'H[|!bT5d2w[V ]F yuʐ}*.Yt^{hca-̐q `ju~\&E~IɂE$?Pλ+ELμq?ɞ6kĔD䟀!I ݩ0(6ϋYG@nlɭ5D&t>O{ qi<()89.L$n `DI,6޸u_T P$m1߈ 1a #Elv8oh,?FpNd.Svt]D xk '&p{|DBl}0 TyqB ƱP[3H{|PA`:*#Y Ғ|-B[ 6c6">l0ghXd!UMQhmv0dz Xdݯm5V!-l Au|>;> ;LWͅT9qC=2PR_`6m1Pp>!4k']$E ːG`IFs u(Rt 6_pT1H) 7GUd>`CCy2 TJı|my\E4x  Zr_ R5_ާ$ljȱ1&hl5` 08 =a< 힂 9~Zo 5D_c< 힆= 9ĵfPK;HTk4tr\)0U؂/R #~ ;XLm&RKmn|V^{U6V| 2y#p,Z Amxk$ܬ`X<8S0t05xj',Z!sbJ(7n3VETVU!p<%s*/ė]xPt"YH/8o#ʢgt[ʅ\{9u4D1|xT+"d3z|CBϟaB_8x/r_JFwqkYf<{݄a֟P\W? GŒ$6[T!pǑ@hxm?Jȅ?)Xe-hFn!slĻ; rM5\!-*,WSx߄6M00c`rCXF䀸vrU>ס*xo}9oo7:{ E$fUH68٘ԂW,*5~/Tm͹<Fj.@$4ͣJS(:RJ5 /\l F(؉<(ZHFMAklE,V^E+bK|7l-ȏo!+<Y-/n/| R&9_`/?/#vʝ]HjOъq *"B O(:"X_2*RT澋REBgfO.iBs0EnE4`\ " |_ˑ80TPF!tQ@kyx|CF*`JFj]4C`n@ʢ6CgI(2#Vq^myhqv.S\"V[nP\2.Ek+JB[ڞfHS܌z{**%imAhn ypv v :Ӡ(i8ҐFqn<COۊsZAץ_́ݶNQcZ"lXhxi L؍񭁅h/ش*VPB( *W@UE/haa@aG-RP \#f:H@o}sH_c03Q[jpzց,jX2Rl( Y˾@1"<$wے H^|Ȭ8.Iw16WW=V?̙Ql$ /oߒ F?ɓ\Vǎ4mswařF:pWclIu 9'Zj l#(Ύ+TYO73`1"\5V$OB>X| pxڻԨU#"H0֮׬adTanl읮ҥq߻'laםä:Eqv91@˰WxZ!ky+tѣٚLڐ!7 0B.xj D!C{x~nJoͥ(g!q@Yy#%cpfcBm! .-~ F^N)a/9 @,KN&H<*Wԩ44PSRH#YѫBpEQ{,Hxxs]%w`s6hVUf袑G3ɀ;,eٳ<0_r :r0z4?FF``GD/\1),j8*>?CBH+,(M?Ht@+œM@[h6}gkaf|SxR+ϭ(L.?D!(7Anufz԰ʷW_egCvYn@E)V8B0(n0uV&xoF_$(vQ:_.5Fæp4ԐuAQ;ę\{Ͱ{`~+*P,2~zBH8.xq`=\(PJ]8Yjڡ#Bh,o^@b)x)8ۯ'3 H`$ࢍSq A2>=$ش͈0n$F J.]J:@jHǎ1hXںIݻk9I*œKHl|0tw6VhxАkh6)TQg,@My\,T>Q#Lj„٤ @t%ukݺqd9Ge*7HU͗`G;p/-&7YÑ H RK`1<1(N3XHWlbiݼ)ф^\BU\^ϖ-3u*nݺҥl]2@pn; 8 (l")Fǹ2E9%M%\-0!! 255}(ڵXzTm&``(D:aE VSNyA' 8^ Ҩ?PPnp\lŅ4WtlKԟonn4?xH+5`[F ³@w@[ OyjxP"=WQGѦ/ 0̣'OrZ5 ᮱iQiivjIE@B-H&݁ː Bpw8X|]wgZC! LnS-Hv'R`>RpKQC}̟<(&GO>>ի٫#"۾efȑTMp E_@2ĕ_ƟAqw?x%4} *̂/GCt  O@#$aqܒp\EQg 4ajK>s'ϝ#woV u&Ofɓ9r 7jD?I8X%V |whR R-5beb>X5J16 0 sm(yg<&KQ nguCx)8d-|Hf$(, 09 Xaèv ?Hzڵ=z*Qen-]ʉ fфQ%1۹8kRS-Z *Ŗ@_$rӵ$#$U˚k -*b8B0paO@YSf<\+cakihC,+ p 8n>N.^4䈳(sﲵ@wu5lKi C H}GQp$ 8 l-ݴ[ U)~t>@ ! 85, u 8rP PlφZ 6 sPe@)Z#eH>oy'R(9A:\rlD!_mU[cRAR#O_CFб8:Τ'oZ s6TׅW_@zR{^X >9c&uC( bvTD{@\m6qi(=DrLRQ2W@B@,R\O O8Bp?R* BmK );3 71V Cj+b1H4Bփd)`OƊߑ"R'8n␜[5{ 8қYi+m_,3Ź8|dj"|)Rx&a!M*j0Ce#-bPYv_qVSfՄI [&Y*S D2f# N6ˇ /Y.`Tn%–ʈe5T H-]#`EYhqShp/HHd(# ,BjDRw#6H@Hg$VWǃWAҋ8C:Ť,z܆֫ߠw30wԒW1e$r~xZ^EQ,( ^B|%[`Ax0*l `]+8R< Hqӊ(֥T@;l( @J4PqB`RlwU+L$ŀO $M;MF~\" [8EQr% E`ïPJA6]c&%qն(Jgo$*gRkq HF-(@{w~Wՠl,֎O~qh8ݑ[YE)('`%C]`M}sQp(?v7x*PbEJ:;GpwmSiSj NHc8};,;oI;VE)($K;y_F>pkH46mG̃rϠA|O2z0ĉ4R{٢Ḙ8'R T!P1ByP \\Hsq!-m)ٸ1D?|za WlуfÆQ? HhC њ(AEQo7$f A:??}}n*a( _~ɩ4RN4Y,J-(∜"m<,[FgÆ DO~Z2l $ptv|p!Έe([Yr"ɴF \!).uQQ$Ⱥysj6lY_p$v>(EGf ASY0Tc,n+?ڐmDEEӧ#14g,ZG3YgydXPVYw:`+jpQ1(Uc#-mr7hb\xH%ROr |Q<-_JӦ/8ܐ"J(B8ze/J R]lÏ\\mGKL\%!p˴y,`_%{!>SlҮzTr6XI!X ;|$n!BpG(=b~7F:S`0QL7yh}ݐ=ٜo>C,$CEOw`il[ 3۷hͶ5Gx;Ͷ >Og!'{20X.hވ5`?E3< Xb|-LeOS,VkRRVE)$L77@{j}!7M{HBr7dqPh˚ma|1l7y0}{!ɡL0LD1hg|gHO5f U8h1f? ˌU'6e (R0 c`%+A!XŐqpj3(I!x+߾90ym&;|4kÝu1]Dq菤W4!JBfB}>3[wx}8lq78EUDYq3d*>QdyEQ&xMޞcZ`seTk$}{E)D\_pħ'3-i8Tf9iIM  ULu}7@yfl{(F{DLIDHb[Yįl6#$!֊NXN:-[JL$Ē(JOX~󶂫`x[gx-H8@[$mo fmtǙ<^Cײ(w5!#/FnlQ=ϴmmjN 2o b9 B "h(EIa(>z`U & 6Km @3_ 1DfqgY+~0/+P :Y>~@Hρ >:cy-$e=+ GQ%$@6vQnas.!kK%n{`74C 1@ߦE!Y&w Q@C6 .C3;rc?o|>G_csA˫ :!{ YC:!6$?9 y#㜱rQգy>viȨ(JX*B\) n!+g[A'p](o(Da.@nx_5ؖH'E0O*  ;+N!Vţ9XPBRFLSQ[s[AˆB Kq[ ֔:f*C͍EqVaӇ~WI;HV#TUEqv"Mjf ۡ!uFgћnC%.nCyIU.((3KAnP*ʟI.Y쟌;k/(B2* GpD gn䂔;+bU 20A(ЧeQphLA2g5n!i/r5LQv@~>HfAO0ҡRb"R#! ZF 5Y,"DOG('XJrC % dzSQѪ3D~@.HJ>RxP}Zu됪%̶#=111膔5 DrAn9N46R(7F>EQEqX&!*8lm#Okh_9\!ʎƈFd݊YڇXN!A 0]A9@F12o`mbhblϬLD 5^EQ)c1o,?V&ۈD!H3k'2"M\G/8O AgBT` BQEQK$!47F~2w:t9ma{v'7{`r$ MLtBr@_hjl((MD! y]t|iKl"}ɈȊSba)n)2D, OFLMDdɴ>76[~(bx푎1H`B:Ura`!oBL/ofl @4G2Lq{hAF7{Mʊ(bW#7ͷ߁Ǹ3 ?FR{jO!mC#k#HH{ 8#ĩH ]i^̐sĢLF](.Jąp5`H 㬞ʽ%c7$z4jfl?T5_QLu &dD lr'D1g]E Z8X7 BZ*oCk+(JF&(Xk((?`(IENDB`libvips-8.18.2/doc/images/interconvert.svg000066400000000000000000000566021516303661500205560ustar00rootroot00000000000000 image/svg+xml Lab XYZ LCh scRGB Yxy UCS LabQ LabS ICC Any device withan ICC profile sRGB HSV libvips-8.18.2/doc/images/owl.jpg000066400000000000000000000510041516303661500166050ustar00rootroot00000000000000 ExifII*2&i:@2011:03:03 02:17:20j JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((i" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?䄔%RH_8|٠BOJr5=BբSP+z W./-m?.Mpŏ#zoj,FS3>R5QZ\zGi$\㞜z|1{e yly@jZ\[rfl :]'cZQ>أ*sۓj-h E,q[zX×}z ǯY{+RN.|QSQD#R)TOFbx$JPv3)j˧4>+E2lSqQ*Ur< H֬"VRHbkkšbUd~p3 t[@XӠVԮ]70bӒOaZu4)Y:by5y49%e!Xtskj}+|YRڗƷ#oJK|N'5v:rYF9$1YfUlRۉǢ{W<_gG,6ڷ1 !R|mkգx/ͷ{ETArٽگQȂC    ' .)10.)-,3:J>36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOX";!1Aa"Qq2B#3Rb$rc"!1A"Qqa ?YBNǠRWlJӴ{\-4^!Y ?tQ! )YIPV";$ "SIP]z}_B7uBB?k4T>QHMJ%T`\E#nV%]St0[Z)?tr0$Ri`UI4dRdn7?|Z/duO#`)"MP&N]* *zJ*T*ߒZ;JҽWjm NȵpuE{!0Z9?;I BBAB>&#0KWB>RLB(=Wtd([T@n#N t>YQ4K4$Piv)P@S0BB$ T#r[M * (B llF_$ZJBVCMJbR4Siv4!\]yKئɡT$Kd @/$T ґӒi% >h@YQFE!KI:YSBPB~`HE cɄPdM9uI2)1 $P!!W!P'hER?!]L ך4# {(uJL7;@ӴZ˺VAV'tJoh) /nHBVB "h{nH$!@SH]vBhPJ=ӭ@#PsY &LrRtOBQI4#i~ɠt%]0 엺 `?dB`\SIT$#d+hO$@B(EGʡ! ע`p?t! #iB=P-!hj:sG`}M 'NiVJ"Zi{"$EJЁi^J~BRTBP$ЊQBe tL a=L hB Z-w ZCӪE0D@򺣉o8 $c+8yjHGRvT| OfS ţdFhsC;-t7I+@s N_$nh z/q, Vh\й~C׋ |s9.>Gunk?ZְoB[DE&$@$_t#4B?t*#AH4rI?(#y!+GʠB^L飢TIEq8 j@^A'x#Ӳ&0荓g/4د.ønDka~<`\*40NS^)dHdpM r:fFos̒w;sr8u]7DlĆMZ ڬy~:@$v]5IELas0ib呌V˿X`ڡji^MMf,QpeF~V,;0Hd>R#] $*_B! TEZa tuBU' W)U#`HR:B:n}PP 6(h |'%r|=Ǣ-$J eBJ Ѝ{!?).Rj򏵧E*U`,Y"#o[Lw ٳk3e5,9r7  O-n4{uks3"\KWU3.3)# ai\^%}''5Ka"B74^ظ m %/ 1,H%׽9Ұ35jeYQi|1a5yDm?tp":wAlz!p(Oʅ/㥛 Yl$w/a\Y)"YKESZ*|ZCw痫‡#Coe?DpG'+$7^dP=;/ܜ)oBz.Y+gn;uVBcu88lV/,.󵻹~'rUɗ)czuzXkEG,sq _Lgk+b@`A$jjgNя71@O`R@sAGih !9jUGRL ?t#M@&NR4R$oO3$mۜZ!6-P\p0M_]~1kc#ce7$@X,, Fq{԰ub`Yp3z~V"cZ7^Gxyh6}V3%1GE˕?v #<sur ^#!xGf49 7 d!oOOPs<&::͋c~vFF26lHYR°vd<4Yȟږ-[ ϋ.ɇ` Ȃ+&F`riuM\6zE?.u7[cu|'#''%;n*.W xk׮\5t.X#.y"uϛ:I4"W|9ohPO×W[^d|v6s3",#CIM&He'OcWے\oq)#`;;Ƨ˅c1V7o].Tֶ= \;G3nYc>:ǩ/M#29`/m %tatϖ<1w \yZd$nh"}RW5j$Is!sfSYOZb-$5L5s(X$4mpkp㚄dWuXM'[HD*WBUvHJ%[[J>*BU%V4Кշ$:PJ]RDs*Nu5j$R]thN4JGثI&+#*#deP%TA)'HS['JZ Mf4 RNE#oDm@ep1Ӳi@|~KCt9n17z~Zjpl^f>r dc\g a89ў32H~D'@R61y![BߏbcZwt^Ֆ bx4^ָw`{~;L/KEjy;5ɝA\j5ÓW'4찖K5c9N/^|B=|m#@[Z#%};s cHAeywJTE!tr9c`Fާ93cCkZ냑.V0U04E\AcwlL4M6[O^3'-ycdqd51jUEf9r1aU &O? ث"r6J CKh\?ڵ<`J$-O07BޓN?tru5U+x1kf}֋2&l{2A(Yj|r.&}-4MFGs"dS'J؍cDNJR1 ]<֖lmakfp_$nMíJ)>Ys*RU[Ut*I:MV*RhК%*VBJJ~R ]}):IgB*--*BR#t )*iUJ):>HIE"A(%[sMD%[*%I&[%J4M4B:L4*N('J(U):RVa55SK~"&dL 1^=Wo) d:äp \W|KLimy[t{uƕ]#ɠ ?EX,!>yi;bF܁+_]73H{MҲHR)iE3\dޖlSl _^!L!Ŭ ]PasýlZڕĂώ%ۛS+Vh>c0ZmZnbXYg&V1/hSH浸3Hh1E"X/H-N8̺G+lEl 5U'̐[HViجi--q|O=mV6d'bhɇKZc?N,oW8y(h1ߐVG7^hVrHsRY: _zWJ4E,m{?rkLF7FkV\i<ls}WI{x,B%`FN,5$߲궠 <+{t(.p8 p˟hi%d$&TutJ%IRTWIRE*$JM!Unё*U$T"IRj%*UWӚT!M+%I]Ti?tWuU\H*UӢUSDT쮢JzMlUHQ5 t{&I6NE*NWe@"RRiT%:'H]H8\Li#?]0Ѯmq}pց4OtZ vmǑޖ fKih5'LPoO𺺳dd9"Ic0x~w+Z O{LjRs|akx.s}I6s+6CG-_Z,$ 3&+OSWӆ]gXrgw|-; Nr|gs\[}7'm h  ݹ>m_4cr.OO=#WP:;(IK zid)cFǛO$;DJIs rVaO9cBzZdtҞ'3 R\!8ֿ,~h Htt$)W.iC[eP$!8m|hㅎFl[rKo1+(?'䆒{%MvChs_cN\`%sLp56s_eO4ɷ+(] X?ӓ֟No=hp5eb: i+6,.deёuΓPkKGRWy/i?c5k4MVln<+916< ר+G"<ߞ0/`v> /p'(1ުY\9Z(k{h w#r݊ZÅnՍ4n6X(j6!p?2!uIJ!A)őkևN UyRu՛d&`n-L\-$ Ü~3M-F(e!o;̯ %@4"k pIP)ׯ5ewi7jʎ]lvK7ω1m;WEu1;XX<==#۲H \ n$%1OC Sbc~krm2b593+emkrj6kkaz)0]mdI ś2!uAЬgp'tc:(b|=cΏ^$oc;/1P q;xMG(z%;4Hᩴ7?w{#uh^ms­ҥ[&R)]*RiRhM+&U"*&)UI"B%tO=Ӯi*WIRj!*5uq;I^L/dGhJs5q4UT&'i)4*L:M:Up!RhNT E"6 NeReyik\ܧ)䙋m!4 ~CZbu:"X-,IC?lX7_ٮNV^<<2|IZ/Kt ~n#m׺S~b25iuyI^7dp"٨a~G]ԿӻƠ{)gQk\onn[m?R]l= ^z_#s:m3!jfKVmZ qf^Y_<-viqc҆F,itEqi)w 7CUckㇽ<]|}0lFwVNk tC;,~ R"-[6s˂cHQFX5\Ul81O J$2Qϩꔗa/ޖZoK,dms> .6 VL\MwC5eo<2qåBIϧ]\Ӫ(p0Ȳa:NbԲ0qőa-qgz,/1x._އ)[Ej`B^,}o8G%U\?q®ȮDJ+t*T$'H@N$BV#)QI]H@{*r $RT$t$uKIRJB"&'4^AA)n*MIժWJ'IRuIB+R+='HE&B=@?Кcai=F: ktJ5[L̜q#q$Ր֍'@?yxt s^Ϗ'9R:&O bǗ&6jEsxld𤽜;(9 u__O\XAiUj7sp5̄l!K" xg#KĄ-O 9Boe>mXqsN4~ qn:znI a!o,H wmäpd:W߰E.hatpuU&7av#L:قX'8Ck=[0iv8)PWKю4!keՑ猙'-eQaٰGJA0A6]?8#+JkŌHL̬GJ^szM $ШN@ B}!:EZk T"%I4h|)t %TR^ʑH&N!:E UN'VkR}#:N-hUHuU^U4TA4Ёi֊E =BfCqǠ=6i`K^ Җt/?sT#w\otomXk5_:tnۑ?eqΪR~el8Q+˅&<'`m{~,qrL.yz-hcZizGǐgA$jVzc?%d@+3%z}=~Ђfku1\\`-ǯu$k[͐Yp$hVz;9 U˃33qZ:W HAo2Ѹ=po nN cZ$h;=Çl]O74{ocOz沌GF\eRO0$rfrfSLmwY-fהU||n[e`3?'H~dνlc;'ڜNK&a޹d!v?[$Y:Vf˜g4+ FhFjKxZb&ŏ:~֊Wb97\%ď{ldO 8kcqs[lm$rBd1͊NYך6n O^-h$!p XypnmkC׺%&c㓞Dzpӌd;7t=B AI8 |ܯge;\Fv'Wó[u<>hU" :?6WѻK^Fxt18a;&%l?0FWUq0F,1/XsG[yWBX:2ǐ܆ n_ѝnz(PqI䑹~`|Z]~ǔeᙑHszzv||N=l IC\w;c3&m`sda9TI@) S עhcDYhmú|O[ ^0: 屽ly n=V,nn#"?ҏ%w`]9 fߺsE*켶0E+ҊLIR^MJFjILd]S:B] iOOecF4 tvW:S1E,Q\VM)ҘZQK.iLO˥-!0FҲiFJtOd벘1*J{& zStLHt)4KOeOd=)V-mM& tvY40E%K!iW>IRجtztW.IY/ nF08 m4?N`Вǹ*d!nOU;Ip,k^{fOІ,qsSM=ddkK龧w}?{b|qS ƾip|#(ۛqg6v[+װi |^/<1?#_+ݩ7oe&~+ ӏ]˕- L^F-?g7%GɡdlO:YCXn$]uam5گeNC~^D1VI),[9/h-sm]^XٳkwY 7cnVQ)Q ZZYC~c`EVuc{vݻ4GZx@dep$`$tV\t/4O۟ &C?P4[z/l'76/SL]/|^^n^V^ut0Y85~,a-ncst|m4@\=bl15Lmߖܖ!d& ҝ+R툊N)0FQY)1NdWdQ]'0F]")Q]JEvW:'^#J4ے"J"UIR6OACo]Nfъmdrk?<5][ ZY wVIl,n\R%5﮾niS,8Ѻא7A5kNe>H4K G8<>̌U1x:Ρy6Gq-ȝNepyE.}N]\_s'7e<[&pum[q=q%n:CVŠ 9dq"B\v+.r?P mPAحujhn3dގY2ka8s eYej8e/#zgֻ2^$lp68k$He m)&sy Of88sW#6z+4 :cwײf4&P%gP|5߁ΓS~kH c#kv cs67ZE6@uՋX2 y1&8;-ۭ'Yqݒ=Jz_ƮQur;憒ll#chkCַX;gj'Zߪu賆1-tMд]UBԩ] sdƑ~z|%@Zmxels˒,{zoʊ KXoYaZzrYc`M@ ebA>X2hu} D9 hi_dI9/kwX1_F$\zoi*tZUC0;)+R"nJI4K%"diW=(ҮJ`E+\HUHLIҴuDנNR 4HI*Rttii)A4VA*IR5CXIp,E'b+O),U=jFKHp'˾NS _>YE+QkZN lx9dL%iut= _? h`tK,D`vWF'a򥲜@ЭG+ϊ^C)cdž87=S<+t5[V+,B5-_Er_gFZ)8[\M: d[[v5ԞխyXl<֣٨?Uxu{Ysv{s[)u^,t5U^kX=1ݹH vä ۍ&Ҭj~`J;rJ\UB2VǥxZrQ{SvM#VOm]E9ıK7[]6!8͑٥IR&R:&R& RE"Z)0E!Zlibvips-8.18.2/doc/images/tn_owl.jpg000066400000000000000000000154201516303661500173100ustar00rootroot00000000000000JFIF ExifII*jr(2Viz2011:03:03 02:17:208c8c02100100 ( HHJFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((i" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?䄔%RH_8|٠BOJr5=BբSP+z W./-m?.Mpŏ#zoj,FS3>R5QZ\zGi$\㞜z|1{e yly@jZ\[rfl :]'cZQ>أ*sۓj-h E,q[zX×}z ǯY{+RN.|QSQD#R)TOFbx$JPv3)j˧4>+E2lSqQ*Ur< H֬"VRHbkkšbUd~p3 t[@XӠVԮ]70bӒOaZu4)Y:by5y49%e!Xtskj}+|YRڗƷ#oJK|N'5v:rYF9$1YfUlRۉǢ{W<_gG,6ڷ1 !R|mkգx/ͷ{ETArٽگQȂC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Q74i^Mmr3E)Q$ H4 H@➢ rN 8 v-.PE3!RPbu S:D S1*%Hx dd%Arڑݵlm U(AN&)*@@iåhLRi굛cCUyHO|h䉮Ϟ˴1;Y-I嬮kh5wU(n R 2IInmMu8Iʼf2 f;Q'U},n KK9ZQkG|̓;S?[$aBZF8QX^*e@&1O:F4IUp\:He||U]8羽ky"*:g-N䉒e;D<ʤ2)SA"gdQu*5d4%#2U˜EEJHLS)  NDV.E$l:~VWv{x}j6̶rZhɑ x<%n!X#o\vʶބ=\^Nz6 "m|p}p~7L .7HӤvhķf!ןcW .ZL7;iZm -dm~UvMlF[.we3쎎n7ӻTO"Q+ukB{k91=jг6jD11sU泒0tfq `[E]6+LlRs >f][}١V0ȫՁ f[IQz5f*k+mɦXL" i*^ijbU=EXsC*uZrJr({l6a .hdGnueWkr߮O nxBxKN9Me'ߊfg2Hv{H\tvHkke+r.NG`%m6Ev}) ƂE'qcv}6(Ȳ"d*Ӛ3V}b3oGe~RzJ6'RC^j- 5hX`>ȼ8iL ?1=ǧ^B;(v& y qK/1%][Gl'=<{WE- WE(Tv91XVhoމ1Zi^jM+^g9bLJw%))JX=Oj~j~jP9b[{0[ʆ&w,W?&2qֹj w"\AE}޺"Ƞ8= ^"8խ/FNq߅tQ*1}BRQO UoOݮg ' KF澟#%[u*I52 kqc n TAOX[sz#:8#bmJ$3 R P¥#al ۭn'؆VGI`@ǵO+9Xkvcqʋ 6R0r7\nX,][^Zdea:bRNAP6,Gr$Lck֦,c7f#"'2 ԛjbݵ1"4#Z?g8]J &ʺSD FICV@UV,vici8TTIܻ@[X, /X9n0O2=5>D˄b:h!"vɝc9^O-F['Rg.A u#s]58b8D!q qz-2;NW!`ykR}&aN&-C"hs=i``eF fc;?a\+H8UJ ҭu{)1ΖUHܱ#tk[\sU5C&QǛ2ȸ=y]G7[O$۬gEʜ3ǎ3Rs{΢gL)zspK= R(9z+ڣM(l4=I{W/$0{S \vдpkĖ<+2Exgl=q]5%^khf)8ǥTĺUr$<݀^P'xbE'Rԁ^qycrQrˑ\T,U7ns;ik Ko.Yd9W=vשP6 '=G^KkheUKg=th0[I9CBR-Zyl^qk֛vߌcۨK'3ܸʅ9'kV1\? lq4*YGZGe62º3xoXm#YMFT =g^#Ư%C/<`ΐ@8!}yBm"q` "_緷^}zjNOrI>sKzNlQ,MߡЎƮy^Ղs;ȭW.libvips-8.18.2/doc/libvips-arithmetic.md000066400000000000000000000175031516303661500201640ustar00rootroot00000000000000Title: Operator index > By section > Arithmetic These operations perform pixel arithmetic, that is, they perform an arithmetic operation, such as addition, on every pixel in an image or a pair of images. All (except in a few cases noted below) will work with images of any type or any mixture of types, of any size and of any number of bands. For binary operations, if the number of bands differs, one of the images must have one band. In this case, an n-band image is formed from the one-band image by joining n copies of the one-band image together, and then the two n-band images are operated upon. In the same way, for operations that take an array constant, such as [method@Image.remainder_const], you can mix single-element arrays or single-band images freely. Arithmetic operations try to preserve precision by increasing the number of bits in the output image when necessary. Generally, this follows the ANSI C conventions for type promotion, so multiplying two [enum@Vips.BandFormat.UCHAR] images together, for example, produces a [enum@Vips.BandFormat.USHORT] image, and taking the [method@Image.cos] of a [enum@Vips.BandFormat.USHORT] image produces [enum@Vips.BandFormat.FLOAT] image. After processing, use [method@Image.cast] and friends to take then format back down again.[method@Image.cast_uchar], for example, will cast any image down to 8-bit unsigned. Images have an interpretation: a meaning for the pixel values. With [enum@Vips.Interpretation.SRGB], for example, the first three bands will be interpreted (for example, by a saver like [method@Image.jpegsave]) as R, G and B, with values in 0 - 255, and any fourth band will be interpreted as an alpha channel. After arithmetic, you may wish to change the interpretation (for example to save as 16-bit PNG). Use [method@Image.copy] to change the interpretation without changing pixels. For binary arithmetic operations, type promotion occurs in two stages. First, the two input images are cast up to the smallest common format, that is, the type with the smallest range that can represent the full range of both inputs. This conversion can be represented as a table: ## Smallest common format | **@in2/@in1** | **uchar** | **char** | **ushort** | **short** | **uint** | **int** | **float** | **double** | **complex** | **double complex** | |----------------|----------------|----------------|----------------|----------------|----------------|----------------|----------------|----------------|----------------|--------------------| | uchar | ushort | short | ushort | short | uint | int | float | double | complex | double complex | | char | short | short | short | short | int | int | float | double | complex | double complex | | ushort | ushort | short | ushort | short | uint | int | float | double | complex | double complex | | short | short | short | short | short | int | int | float | double | complex | double complex | | uint | uint | int | uint | int | uint | int | float | double | complex | double complex | | int | int | int | int | int | int | int | float | double | complex | double complex | | float | float | float | float | float | float | float | float | double | complex | double complex | | double | double | double | double | double | double | double | double | double | double complex | double complex | | complex | complex | complex | complex | complex | complex | complex | complex | double complex | complex | double complex | | double complex | double complex | double complex | double complex | double complex | double complex | double complex | double complex | double complex | double complex | double complex | In the second stage, the operation is performed between the two identical types to form the output. The details vary between operations, but generally the principle is that the output type should be large enough to represent the whole range of possible values, except that int never becomes float. ## Functions * [method@Image.add] * [func@Image.sum] * [method@Image.subtract] * [method@Image.multiply] * [method@Image.divide] * [method@Image.linear] * [method@Image.linear1] * [method@Image.remainder] * [method@Image.remainder_const] * [method@Image.remainder_const1] * [method@Image.invert] * [method@Image.abs] * [method@Image.sign] * [method@Image.clamp] * [method@Image.maxpair] * [method@Image.minpair] * [method@Image.round] * [method@Image.floor] * [method@Image.ceil] * [method@Image.rint] * [method@Image.math] * [method@Image.sin] * [method@Image.cos] * [method@Image.tan] * [method@Image.asin] * [method@Image.acos] * [method@Image.atan] * [method@Image.exp] * [method@Image.exp10] * [method@Image.log] * [method@Image.log10] * [method@Image.sinh] * [method@Image.cosh] * [method@Image.tanh] * [method@Image.asinh] * [method@Image.acosh] * [method@Image.atanh] * [method@Image.complex] * [method@Image.polar] * [method@Image.rect] * [method@Image.conj] * [method@Image.complex2] * [method@Image.cross_phase] * [method@Image.complexget] * [method@Image.real] * [method@Image.imag] * [method@Image.complexform] * [method@Image.relational] * [method@Image.equal] * [method@Image.notequal] * [method@Image.less] * [method@Image.lesseq] * [method@Image.more] * [method@Image.moreeq] * [method@Image.relational_const] * [method@Image.equal_const] * [method@Image.notequal_const] * [method@Image.less_const] * [method@Image.lesseq_const] * [method@Image.more_const] * [method@Image.moreeq_const] * [method@Image.relational_const1] * [method@Image.equal_const1] * [method@Image.notequal_const1] * [method@Image.less_const1] * [method@Image.lesseq_const1] * [method@Image.more_const1] * [method@Image.moreeq_const1] * [method@Image.boolean] * [method@Image.andimage] * [method@Image.orimage] * [method@Image.eorimage] * [method@Image.lshift] * [method@Image.rshift] * [method@Image.boolean_const] * [method@Image.andimage_const] * [method@Image.orimage_const] * [method@Image.eorimage_const] * [method@Image.lshift_const] * [method@Image.rshift_const] * [method@Image.boolean_const1] * [method@Image.andimage_const1] * [method@Image.orimage_const1] * [method@Image.eorimage_const1] * [method@Image.lshift_const1] * [method@Image.rshift_const1] * [method@Image.math2] * [method@Image.pow] * [method@Image.wop] * [method@Image.atan2] * [method@Image.math2_const] * [method@Image.pow_const] * [method@Image.wop_const] * [method@Image.atan2_const] * [method@Image.math2_const1] * [method@Image.pow_const1] * [method@Image.wop_const1] * [method@Image.atan2_const1] * [method@Image.avg] * [method@Image.deviate] * [method@Image.min] * [method@Image.max] * [method@Image.stats] * [method@Image.measure] * [method@Image.find_trim] * [method@Image.getpoint] * [method@Image.hist_find] * [method@Image.hist_find_ndim] * [method@Image.hist_find_indexed] * [method@Image.hough_line] * [method@Image.hough_circle] * [method@Image.project] * [method@Image.profile] ## Enumerations * [enum@OperationMath] * [enum@OperationMath2] * [enum@OperationRound] * [enum@OperationRelational] * [enum@OperationBoolean] * [enum@OperationComplex] * [enum@OperationComplex2] * [enum@OperationComplexget] libvips-8.18.2/doc/libvips-basic.md000066400000000000000000000032721516303661500171120ustar00rootroot00000000000000Title: Operator index > By section > Basic A selection of basic aliases, [alias@GObject.Type] helpers and macro definitions used by libvips. ## Structs * [struct@Area] * [struct@ArrayDouble] * [struct@ArrayImage] * [struct@ArrayInt] * [struct@Blob] * [struct@RefString] * [struct@SaveString] ## Aliases * [alias@Pel] ## Callbacks * [callback@CallbackFn] * [callback@SListMap2Fn] * [callback@SListMap4Fn] * [callback@SListFold2Fn] ## Functions * [method@Area.copy] * [func@Area.free_cb] * [method@Area.unref] * [ctor@Area.new] * [ctor@Area.new_array] * [ctor@Area.new_array_object] * [method@Area.get_data] * [ctor@RefString.new] * [method@RefString.get] * [ctor@Blob.new] * [func@Blob.copy] * [method@Blob.get] * [method@Blob.set] * [ctor@ArrayDouble.new] * [ctor@ArrayDouble.newv] * [method@ArrayDouble.get] * [ctor@ArrayInt.new] * [ctor@ArrayInt.newv] * [method@ArrayInt.get] * [ctor@ArrayImage.new] * [ctor@ArrayImage.newv] * [ctor@ArrayImage.empty] * [method@ArrayImage.append] * [method@ArrayImage.get] * [func@value_set_area] * [func@value_get_area] * [func@value_get_save_string] * [func@value_set_save_string] * [func@value_set_save_stringf] * [func@value_get_ref_string] * [func@value_set_ref_string] * [func@value_get_blob] * [func@value_set_blob] * [func@value_set_blob_free] * [func@value_set_array] * [func@value_get_array] * [func@value_get_array_double] * [func@value_set_array_double] * [func@value_get_array_image] * [func@value_set_array_image] * [func@value_get_array_int] * [func@value_set_array_int] * [func@value_get_array_object] * [func@value_set_array_object] ## Function macros * [func@DEPRECATED_FOR] * [func@DEPRECATED_MACRO_FOR] * [func@ARRAY_ADDR] libvips-8.18.2/doc/libvips-colour.md000066400000000000000000000156051516303661500173370ustar00rootroot00000000000000Title: Operator index > By section > Colour These operators let you transform coordinates and images between colour spaces, calculate colour differences, and move to and from device spaces. All operations process colour from the first few bands and pass other bands through unaltered. This means you can operate on images with alpha channels safely. If you move to or from 16-bit RGB, any alpha channels are rescaled for you. Radiance images have four 8-bits bands and store 8 bits of R, G and B and another 8 bits of exponent, common to all channels. They are widely used in the HDR imaging community. The colour functions can be divided into three main groups. First, functions to transform images between the different colour spaces supported by libvips: [enum@Vips.Interpretation.SRGB], [enum@Vips.Interpretation.SCRGB], [enum@Vips.Interpretation.HSV], [enum@Vips.Interpretation.B_W], [enum@Vips.Interpretation.CMYK], [enum@Vips.Interpretation.XYZ], [enum@Vips.Interpretation.YXY], [enum@Vips.Interpretation.LAB], [enum@Vips.Interpretation.LCH], [enum@Vips.Interpretation.Oklab], [enum@Vips.Interpretation.Oklch], and [enum@Vips.Interpretation.CMC]. There are also a set of minor colourspaces which are one of the above in a slightly different format: [enum@Vips.Interpretation.LABQ], [enum@Vips.Interpretation.LABS], [enum@Vips.Interpretation.RGB16], and [enum@Vips.Interpretation.GREY16]. Use [method@Image.colourspace] to move an image to a target colourspace using the best sequence of colour transform operations. Use [method@Image.uhdr2scRGB] to convert an SDR image with an attached gainmap to a full HDR scRGB image. Secondly, there are a set of operations for calculating colour difference metrics. Finally, libvips wraps LittleCMS and uses it to provide a set of operations for reading and writing images with ICC profiles. This figure shows how the libvips colour spaces interconvert: ![Interconvert](interconvert.png) The colour spaces supported by libvips are: - [enum@Vips.Interpretation.LAB]: CIELAB '76 colourspace with a D65 white. This uses three floats for each band, and bands have the obvious range.

There are two variants, [enum@Vips.Interpretation.LABQ] and [enum@Vips.Interpretation.LABS], which use ints to store values. These are less precise, but can be quicker to store and process.

[enum@Vips.Interpretation.LCH] is the same, but with a\*b\* as polar coordinates. Hue is expressed in degrees. - [enum@Vips.Interpretation.OKLAB]: The Oklab colourspace with a D65 white. This uses three floats for each band, with 0 - 1 for L and roughly plus or minus 0.5 for a and b. Values can be outside this range for HDR images.

[enum@Vips.Interpretation.Oklch] is the same, but with a and b as polar coordinates. Hue is expressed in degrees. - [enum@Vips.Interpretation.XYZ]: CIE XYZ. This uses three floats. See [const@D75_X0] and friends for values for the ranges under various illuminants.

[enum@Vips.Interpretation.YXY] is the same, but with little x and y. - [enum@Vips.Interpretation.SCRGB]: a linear colourspace with the sRGB primaries. This is useful if you need linear light and don't care much what the primaries are.

Linearization is performed with the usual sRGB equations, see below. - [enum@Vips.Interpretation.SRGB]: the standard sRGB colourspace, see: [wikipedia sRGB](http://en.wikipedia.org/wiki/SRGB).

This uses three 8-bit values for each of RGB.

[enum@Vips.Interpretation.RGB16] is the same, but using three 16-bit values for RGB.

[enum@Vips.Interpretation.HSV] is sRGB, but in polar coordinates. [enum@Vips.Interpretation.LCH] is much better, only use HSV if you have to. - [enum@Vips.Interpretation.B_W]: a monochrome image, roughly G from sRGB. The grey value is calculated in linear [enum@Vips.Interpretation.SCRGB] space with RGB ratios 0.2126, 0.7152, 0.0722 as defined by CIE 1931 linear luminance.

[enum@Vips.Interpretation.GREY16] is the same, but using 16 bits. - [enum@Vips.Interpretation.CMC]: a colour space based on the CMC(1:1) colour difference measurement. This is a highly uniform colour space, and much better than CIELAB for expressing small differences.

The CMC colourspace is described in “Uniform Colour Space Based on the CMC(l:c) Colour-difference Formula”, M R Luo and B Rigg, Journal of the Society of Dyers and Colourists, vol 102, 1986. Distances in this colourspace approximate, within 10% or so, differences in the CMC(l:c) colour difference formula.

You can calculate metrics like CMC(2:1) by scaling the spaces before finding differences. ## Functions * [method@Image.colourspace_issupported] * [method@Image.colourspace] * [method@Image.LabQ2sRGB] * [method@Image.rad2float] * [method@Image.float2rad] * [method@Image.LabS2LabQ] * [method@Image.LabQ2LabS] * [method@Image.LabQ2Lab] * [method@Image.Lab2LabQ] * [method@Image.LCh2Lab] * [method@Image.Lab2LCh] * [method@Image.Lab2XYZ] * [method@Image.XYZ2Lab] * [method@Image.XYZ2scRGB] * [method@Image.scRGB2sRGB] * [method@Image.scRGB2BW] * [method@Image.sRGB2scRGB] * [method@Image.scRGB2XYZ] * [method@Image.HSV2sRGB] * [method@Image.sRGB2HSV] * [method@Image.LCh2CMC] * [method@Image.CMC2LCh] * [method@Image.XYZ2Yxy] * [method@Image.XYZ2Oklab] * [method@Image.Oklab2Oklch] * [method@Image.Oklab2XYZ] * [method@Image.Oklch2Oklab] * [method@Image.Yxy2XYZ] * [method@Image.LabS2Lab] * [method@Image.Lab2LabS] * [method@Image.CMYK2XYZ] * [method@Image.XYZ2CMYK] * [method@Image.uhdr2scRGB] * [ctor@Blob.profile_load] * [func@icc_present] * [method@Image.icc_transform] * [method@Image.icc_import] * [method@Image.icc_export] * [method@Image.icc_ac2rc] * [func@icc_is_compatible_profile] * [method@Image.dE76] * [method@Image.dE00] * [method@Image.dECMC] * [func@col_Lab2XYZ] * [func@col_XYZ2Lab] * [func@col_ab2h] * [func@col_ab2Ch] * [func@col_Ch2ab] * [func@col_L2Lcmc] * [func@col_C2Ccmc] * [func@col_Ch2hcmc] * [func@col_make_tables_CMC] * [func@col_Lcmc2L] * [func@col_Ccmc2C] * [func@col_Chcmc2h] * [func@col_sRGB2scRGB_8] * [func@col_sRGB2scRGB_16] * [func@col_sRGB2scRGB_8_noclip] * [func@col_sRGB2scRGB_16_noclip] * [func@col_scRGB2XYZ] * [func@col_XYZ2scRGB] * [func@col_scRGB2sRGB_8] * [func@col_scRGB2sRGB_16] * [func@col_scRGB2BW_16] * [func@col_scRGB2BW_8] * [func@pythagoras] * [func@col_dE00] ## Constants * [const@D93_X0] * [const@D93_Y0] * [const@D93_Z0] * [const@D75_X0] * [const@D75_Y0] * [const@D75_Z0] * [const@D65_X0] * [const@D65_Y0] * [const@D65_Z0] * [const@D55_X0] * [const@D55_Y0] * [const@D55_Z0] * [const@D50_X0] * [const@D50_Y0] * [const@D50_Z0] * [const@A_X0] * [const@A_Y0] * [const@A_Z0] * [const@B_X0] * [const@B_Y0] * [const@B_Z0] * [const@C_X0] * [const@C_Y0] * [const@C_Z0] * [const@E_X0] * [const@E_Y0] * [const@E_Z0] * [const@D3250_X0] * [const@D3250_Y0] * [const@D3250_Z0] ## Enumerations * [enum@Intent] * [enum@PCS] libvips-8.18.2/doc/libvips-conversion.md000066400000000000000000000045721516303661500202220ustar00rootroot00000000000000Title: Operator index > By section > Conversion These operations convert an image in some way. They can be split into two main groups. The first set of operations change an image's format in some way. You can change the band format (for example, cast to 32-bit unsigned int), form complex images from real images, convert images to matrices and back, change header fields, and a few others. The second group move pixels about in some way. You can flip, rotate, extract, insert and join pairs of images in various ways. ## Functions * [method@Image.copy] * [method@Image.tilecache] * [method@Image.linecache] * [method@Image.sequential] * [method@Image.copy_file] * [method@Image.embed] * [method@Image.gravity] * [method@Image.flip] * [method@Image.insert] * [method@Image.join] * [func@Image.arrayjoin] * [method@Image.extract_area] * [method@Image.crop] * [method@Image.smartcrop] * [method@Image.extract_band] * [method@Image.replicate] * [method@Image.grid] * [method@Image.transpose3d] * [method@Image.wrap] * [method@Image.rot] * [method@Image.rot90] * [method@Image.rot180] * [method@Image.rot270] * [method@Image.rot45] * [method@Image.autorot_remove_angle] * [method@Image.autorot] * [method@Image.zoom] * [method@Image.subsample] * [method@Image.cast] * [method@Image.cast_uchar] * [method@Image.cast_char] * [method@Image.cast_ushort] * [method@Image.cast_short] * [method@Image.cast_uint] * [method@Image.cast_int] * [method@Image.cast_float] * [method@Image.cast_double] * [method@Image.cast_complex] * [method@Image.cast_dpcomplex] * [method@Image.scale] * [method@Image.msb] * [method@Image.byteswap] * [func@Image.bandjoin] * [method@Image.bandjoin2] * [method@Image.bandjoin_const] * [method@Image.bandjoin_const1] * [func@Image.bandrank] * [method@Image.bandfold] * [method@Image.bandunfold] * [method@Image.bandbool] * [method@Image.bandand] * [method@Image.bandor] * [method@Image.bandeor] * [method@Image.bandmean] * [method@Image.recomb] * [method@Image.ifthenelse] * [func@Image.switch] * [method@Image.flatten] * [method@Image.addalpha] * [method@Image.premultiply] * [method@Image.unpremultiply] * [func@Image.composite] * [method@Image.composite2] * [method@Image.falsecolour] * [method@Image.gamma] ## Enumerations * [enum@Extend] * [enum@CompassDirection] * [enum@Direction] * [enum@Align] * [enum@Angle] * [enum@Angle45] * [enum@Interesting] * [enum@BlendMode] libvips-8.18.2/doc/libvips-convolution.md000066400000000000000000000011761516303661500204110ustar00rootroot00000000000000Title: Operator index > By section > Convolution These operations convolve an image in some way, or are operations based on simple convolution, or are useful with convolution. ## Functions * [method@Image.conv] * [method@Image.convf] * [method@Image.convi] * [method@Image.conva] * [method@Image.convsep] * [method@Image.convasep] * [method@Image.compass] * [method@Image.gaussblur] * [method@Image.sharpen] * [method@Image.spcor] * [method@Image.fastcor] * [method@Image.sobel] * [method@Image.scharr] * [method@Image.prewitt] * [method@Image.canny] ## Enumerations * [enum@Combine] * [enum@Precision] libvips-8.18.2/doc/libvips-create.md000066400000000000000000000017431516303661500172750ustar00rootroot00000000000000Title: Operator index > By section > Create These functions generate various images. You can combine them with the arithmetic and rotate functions to build more complicated images. ## Functions * [ctor@Image.black] * [ctor@Image.xyz] * [ctor@Image.grey] * [ctor@Image.gaussmat] * [ctor@Image.logmat] * [ctor@Image.text] * [ctor@Image.gaussnoise] * [ctor@Image.eye] * [ctor@Image.sines] * [ctor@Image.zone] * [ctor@Image.sdf] * [ctor@Image.identity] * [method@Image.buildlut] * [method@Image.invertlut] * [ctor@Image.tonelut] * [ctor@Image.mask_ideal] * [ctor@Image.mask_ideal_ring] * [ctor@Image.mask_ideal_band] * [ctor@Image.mask_butterworth] * [ctor@Image.mask_butterworth_ring] * [ctor@Image.mask_butterworth_band] * [ctor@Image.mask_gaussian] * [ctor@Image.mask_gaussian_ring] * [ctor@Image.mask_gaussian_band] * [ctor@Image.mask_fractal] * [ctor@Image.fractsurf] * [ctor@Image.worley] * [ctor@Image.perlin] ## Enumerations * [enum@TextWrap] * [enum@SdfShape] libvips-8.18.2/doc/libvips-draw.md000066400000000000000000000033541516303661500167670ustar00rootroot00000000000000Title: Operator index > By section > Draw These operations directly modify the image. They do not thread, on 32-bit machines they will be limited to 2GB images, and a little care needs to be taken if you use them as part of an image pipeline. They are mostly supposed to be useful for paintbox-style programs. libvips operations are all functional: they take zero or more existing input images and generate zero or more new output images. Images are never altered, you always create new images. This means libvips can cache and thread very aggressively. The downside is that creating entirely fresh images each time can be very slow. libvips has a range of tricks to avoid these problems, but there are still times when you really have to be able to modify an image. An example might be drawing a curved line from a set of straight line segments: if you need to draw 1,000 straight lines, a 1,000 operation-deep pipeline is going to be a slow way to do it. This is where the draw operations come in. To use these operations, use [method@Image.copy_memory] to make a private memory copy of the image you want to modify, then call a series of draw operations. Once you are done drawing, return to normal use of vips operations. Any time you want to start drawing again, you'll need to copy again. ## Functions * [method@Image.draw_rect] * [method@Image.draw_rect1] * [method@Image.draw_point] * [method@Image.draw_point1] * [method@Image.draw_image] * [method@Image.draw_mask] * [method@Image.draw_mask1] * [method@Image.draw_line] * [method@Image.draw_line1] * [method@Image.draw_circle] * [method@Image.draw_circle1] * [method@Image.draw_flood] * [method@Image.draw_flood1] * [method@Image.draw_smudge] ## Enumerations * [enum@CombineMode] libvips-8.18.2/doc/libvips-error.md000066400000000000000000000055021516303661500171600ustar00rootroot00000000000000Title: Operator index > By section > Error libvips maintains an error buffer (a log of localised text messages), a set of functions for adding messages, and a way to access and clear the buffer. The error buffer is global, that is, it is shared between all threads. You can add to the buffer from any thread (there is a lock to prevent corruption), but it's sensible to only read and clear the buffer from the main thread of execution. The general principle is: if you detect an error, log a message for the user. If a function you call detects an error, just propagate it and don't add another message. ```c VipsImage *im; if (!(im = vips_image_new_from_file(filename, NULL))) // vips_image_new_from_file() will set a message, we don't need to return -1; if (vips_image_get_width(im) < 100) { // we have detected an error, we must set a message vips_error("myprogram", "%s", _("width too small")); return -1; } ``` The domain argument most of these functions take is not localised and is supposed to indicate the component which failed. libvips uses [func@GLib.warning] and [func@GLib.info] to send warning and information messages to the user. You can use the usual GLib mechanisms to display or divert these messages. For example, info messages are hidden by default, but you can see them with: ```bash $ G_MESSAGES_DEBUG=VIPS vipsthumbnail k2.jpg VIPS-INFO: thumbnailing k2.jpg VIPS-INFO: selected loader is VipsForeignLoadJpegFile VIPS-INFO: input size is 1450 x 2048 VIPS-INFO: loading jpeg with factor 8 pre-shrink VIPS-INFO: converting to processing space srgb VIPS-INFO: residual reducev by 0.5 VIPS-INFO: 13 point mask VIPS-INFO: using vector path VIPS-INFO: residual reduceh by 0.5 VIPS-INFO: 13 point mask VIPS-INFO: thumbnailing k2.jpg as ./tn_k2.jpg ``` ## Functions * [func@error_buffer] * [func@error_buffer_copy] * [func@error_clear] * [func@error_freeze] * [func@error_thaw] * [func@error] * [func@verror] * [func@error_system] * [func@verror_system] * [func@error_g] * [func@g_error] * [func@error_exit] * [func@check_uncoded] * [func@check_coding] * [func@check_coding_known] * [func@check_coding_noneorlabq] * [func@check_coding_same] * [func@check_mono] * [func@check_bands] * [func@check_bands_1or3] * [func@check_bands_atleast] * [func@check_bands_1orn] * [func@check_bands_1orn_unary] * [func@check_bands_same] * [func@check_bandno] * [func@check_int] * [func@check_uint] * [func@check_uintorf] * [func@check_noncomplex] * [func@check_complex] * [func@check_twocomponents] * [func@check_format] * [func@check_u8or16] * [func@check_8or16] * [func@check_u8or16orf] * [func@check_format_same] * [func@check_size_same] * [func@check_oddsquare] * [func@check_vector_length] * [func@check_vector] * [func@check_hist] * [func@check_matrix] * [func@check_separable] * [func@check_precision_intfloat] libvips-8.18.2/doc/libvips-freqfilt.md000066400000000000000000000004751516303661500176470ustar00rootroot00000000000000Title: Operator index > By section > Fourier To and from Fourier space, filter in Fourier space, convert Fourier-space images to a displayable form. ## Functions * [method@Image.fwfft] * [method@Image.invfft] * [method@Image.freqmult] * [method@Image.spectrum] * [method@Image.phasecor] libvips-8.18.2/doc/libvips-generate.md000066400000000000000000000012131516303661500176140ustar00rootroot00000000000000Title: Operator index > By section > Generate These functions let you attach generate functions to images and ask for regions of images to be calculated. ## Callbacks * [callback@GenerateFn] * [callback@RegionWrite] * [callback@SinkNotify] * [callback@StartFn] * [callback@StopFn] ## Functions * [method@Image.sink_disc] * [method@Image.sink] * [method@Image.sink_tile] * [method@Image.sink_screen] * [func@sink_memory] * [func@start_one] * [func@stop_one] * [func@start_many] * [func@stop_many] * [func@allocate_input_array] * [method@Image.generate] * [func@Image.pipeline_array] * [method@Image.pipelinev] libvips-8.18.2/doc/libvips-header.md000066400000000000000000000103361516303661500172600ustar00rootroot00000000000000Title: Operator index > By section > Header libvips supports getting and setting image header data (including metadata) in a uniform way. Use [method@Image.get_typeof] to test for the existence and [alias@GObject.Type] of a header field. You can attach arbitrary metadata to images. Metadata is copied as images are processed, so all images which used this image as input, directly or indirectly, will have this same bit of metadata attached to them. Copying is implemented with reference-counted pointers, so it is efficient, even for large items of data. This does however mean that metadata items need to be immutable. Metadata is handy for things like ICC profiles or EXIF data. Various convenience functions (e.g. [method@Image.set_int]) let you easily attach simple types like numbers, strings and memory blocks to images. Use [method@Image.map] to loop over an image's fields, including all metadata. Items of metadata are identified by strings. Some strings are reserved, for example the ICC profile for an image is known by convention as "icc-profile-data" (i.e. the [const@META_ICC_NAME] constant). If you save an image in `.v` format, all metadata (with a restriction, see below) is automatically saved for you in a block of XML at the end of the file. When you load a `.v` image, the metadata is restored. You can use the `vipsedit` command-line tool to extract or replace this block of XML. `.v` metadata is based on [struct@GObject.Value]. See the docs for that system if you want to do fancy stuff such as defining a new metadata type. libvips defines a new [struct@GObject.Value] called [struct@SaveString], a variety of string, see [func@value_set_save_string]. If your [struct@GObject.Value] can be transformed to [struct@SaveString], it will be saved and loaded to and from `.v` files for you. libvips provides a couple of base classes which implement reference-counted areas of memory. If you base your metadata on one of these types, it can be copied between images efficiently. ## Callbacks * [callback@ImageMapFn] ## Functions * [func@format_sizeof] * [func@format_sizeof_unsafe] * [func@Interpretation.max_alpha] * [func@Interpretation.bands] * [method@Image.get_width] * [method@Image.get_height] * [method@Image.get_bands] * [method@Image.get_format] * [func@Image.get_format_max] * [method@Image.guess_format] * [method@Image.get_coding] * [method@Image.get_interpretation] * [method@Image.guess_interpretation] * [method@Image.get_xres] * [method@Image.get_yres] * [method@Image.get_xoffset] * [method@Image.get_yoffset] * [method@Image.get_filename] * [method@Image.get_mode] * [method@Image.get_scale] * [method@Image.get_offset] * [method@Image.get_page_height] * [method@Image.get_n_pages] * [method@Image.get_n_subifds] * [method@Image.get_orientation] * [method@Image.get_orientation_swap] * [method@Image.get_tile_width] * [method@Image.get_tile_height] * [method@Image.get_gainmap] * [method@Image.get_concurrency] * [method@Image.get_data] * [method@Image.init_fields] * [method@Image.set] * [method@Image.get] * [method@Image.get_as_string] * [method@Image.get_typeof] * [method@Image.remove] * [method@Image.map] * [method@Image.get_fields] * [method@Image.set_area] * [method@Image.get_area] * [method@Image.set_blob] * [method@Image.set_blob_copy] * [method@Image.get_blob] * [method@Image.get_int] * [method@Image.set_int] * [method@Image.get_double] * [method@Image.set_double] * [method@Image.get_string] * [method@Image.set_string] * [method@Image.print_field] * [method@Image.get_image] * [method@Image.set_image] * [method@Image.set_array_int] * [method@Image.get_array_int] * [method@Image.get_array_double] * [method@Image.set_array_double] * [method@Image.history_printf] * [method@Image.history_args] * [method@Image.get_history] ## Constants * [const@META_EXIF_NAME] * [const@META_XMP_NAME] * [const@META_IPTC_NAME] * [const@META_PHOTOSHOP_NAME] * [const@META_ICC_NAME] * [const@META_IMAGEDESCRIPTION] * [const@META_RESOLUTION_UNIT] * [const@META_BITS_PER_SAMPLE] * [const@META_PALETTE] * [const@META_LOADER] * [const@META_SEQUENTIAL] * [const@META_ORIENTATION] * [const@META_PAGE_HEIGHT] * [const@META_N_PAGES] * [const@META_N_SUBIFDS] * [const@META_TILE_WIDTH] * [const@META_TILE_HEIGHT] * [const@META_CONCURRENCY] libvips-8.18.2/doc/libvips-histogram.md000066400000000000000000000024711516303661500200260ustar00rootroot00000000000000Title: Operator index > By section > Histogram Histograms and look-up tables are 1xn or nx1 images, where n is less than 256 or less than 65536, corresponding to 8- and 16-bit unsigned int images. They are tagged with a [enum@Interpretation] of [enum@Vips.Interpretation.HISTOGRAM] and usually displayed by user-interfaces such as nip2 as plots rather than images. These functions can be broadly grouped as things to find or build histograms ([method@Image.hist_find], [method@Image.hist_find_indexed], [method@Image.hist_find_ndim], [method@Image.buildlut], [ctor@Image.identity]), operations that manipulate histograms in some way ([method@Image.hist_cum], [method@Image.hist_norm]), operations to apply histograms ([method@Image.maplut]), and a variety of utility operations. A final group of operations build tone curves. These are useful in pre-press work for adjusting the appearance of images. They are designed for CIELAB images, but might be useful elsewhere. ## Functions * [method@Image.maplut] * [method@Image.percent] * [method@Image.stdif] * [method@Image.hist_cum] * [method@Image.hist_norm] * [method@Image.hist_equal] * [method@Image.hist_plot] * [method@Image.hist_match] * [method@Image.hist_local] * [method@Image.hist_ismonotonic] * [method@Image.hist_entropy] * [method@Image.case] libvips-8.18.2/doc/libvips-memory.md000066400000000000000000000022451516303661500173400ustar00rootroot00000000000000Title: Operator index > By section > Memory These functions cover two main areas. First, some simple utility functions over the underlying [func@GLib.malloc] / [func@GLib.free] functions. Memory that is allocated and freed using these functions is interchangeable with any other GLib library. Second, a pair of functions, [func@tracked_malloc] and [func@tracked_free], which are NOT compatible. If you [func@GLib.free] memory that has been allocated with [func@tracked_malloc] you will see crashes. The tracked functions are only suitable for large allocations internal to the library, for example pixel buffers. libvips watches the total amount of live tracked memory and uses this information to decide when to trim caches. ## Functions * [func@malloc] * [func@strdup] * [func@tracked_free] * [func@tracked_aligned_free] * [func@tracked_malloc] * [func@tracked_aligned_alloc] * [func@tracked_get_mem] * [func@tracked_get_mem_highwater] * [func@tracked_get_allocs] * [func@tracked_open] * [func@tracked_close] * [func@tracked_get_files] ## Function macros * [func@FREEF] * [func@FREE] * [func@SETSTR] * [func@MALLOC] * [func@NEW] * [func@ARRAY] libvips-8.18.2/doc/libvips-morphology.md000066400000000000000000000042001516303661500202200ustar00rootroot00000000000000Title: Operator index > By section > Morphology The morphological functions search images for particular patterns of pixels, specified with the mask argument, either adding or removing pixels when they find a match. They are useful for cleaning up images --- for example, you might threshold an image, and then use one of the morphological functions to remove all single isolated pixels from the result. If you combine the morphological operators with the mask rotators ([method@Image.rot45], for example) and apply them repeatedly, you can achieve very complicated effects: you can thin, prune, fill, open edges, close gaps, and many others. For example, see “Fundamentals of Digital Image Processing” by A. Jain, pp 384-388, Prentice-Hall, 1989 for more ideas. Beware that libvips reverses the usual image processing convention, by assuming white objects (non-zero pixels) on a black background (zero pixels). The mask you give to the morphological functions should contain only the values 0 (for background), 128 (for don't care) and 255 (for object). The mask must have odd length sides --- the origin of the mask is taken to be the centre value. For example, the mask: ```c VipsImage *mask = vips_image_new_matrixv(3, 3, 128.0, 255.0, 128.0, 255.0, 255.0, 255.0, 128.0, 255.0, 128.0); ``` applied to an image with [method@Image.morph] [enum@Vips.OperationMorphology.DILATE] will do a 4-connected dilation. Dilate sets pixels in the output if any part of the mask matches, whereas erode sets pixels only if all the mask matches. See [method@Image.andimage], [method@Image.orimage] and [method@Image.eorimage] for analogues of the usual set difference and set union operations. Use [ctor@Image.new_matrixv] to create a mask in source, [ctor@Image.matrixload] to load a mask from a simple text file, and [ctor@Image.mask_ideal] and friends to create square, circular and ring masks of specific sizes. ## Functions * [method@Image.morph] * [method@Image.rank] * [method@Image.median] * [method@Image.countlines] * [method@Image.labelregions] * [method@Image.fill_nearest] ## Enumerations * [enum@OperationMorphology] libvips-8.18.2/doc/libvips-mosaicing.md000066400000000000000000000030311516303661500177730ustar00rootroot00000000000000Title: Operator index > By section > Mosaicing These functions are useful for joining many small images together to make one large image. They can cope with unstable contrast and arbitrary sub-image layout, but will not do any geometric correction. Geometric errors should be removed before using these functions. The mosaicing functions can be grouped into layers: The lowest level operation is [method@Image.merge] which joins two images together left-right or up-down with a smooth seam. Next, [method@Image.mosaic] uses search functions plus the two low-level merge operations to join two images given just an approximate overlap as a start point. [method@Image.mosaic1] is a first-order analogue of the basic mosaic functions: it takes two approximate tie-points and uses them to rotate and scale the right-hand or bottom image before starting to join. Finally, [method@Image.globalbalance] can be used to remove contrast differences in a mosaic which has been assembled with these functions. It takes the mosaic apart, measures image contrast differences along the seams, finds a set of correction factors which will minimise these differences, and reassembles the mosaic. [method@Image.remosaic] uses the same techniques, but will reassemble the image from a different set of source images. ## Functions * [method@Image.merge] * [method@Image.mosaic] * [method@Image.mosaic1] * [method@Image.match] * [method@Image.globalbalance] * [method@Image.remosaic] * [method@Image.matrixinvert] * [method@Image.matrixmultiply] libvips-8.18.2/doc/libvips-resample.md000066400000000000000000000047251516303661500176450ustar00rootroot00000000000000Title: Operator index > By section > Resample These operations build on each other in a set of layers. First, [method@Image.affine] applies an affine transform to an image. This is any sort of 2D transform which preserves straight lines; so any combination of stretch, sheer, rotate and translate. You supply an interpolator for it to use to generate pixels, see [ctor@Interpolate.new]. It will not produce good results for very large shrinks: you'll see aliasing. [method@Image.reduce] is like [method@Image.affine], but it can only shrink images, it can't enlarge, rotate, or skew. It's very fast and uses an adaptive kernel for interpolation. [method@Image.shrink] is a fast block shrinker. It can quickly reduce images by large integer factors. It will give poor results for small size reductions: again, you'll see aliasing. Next, [method@Image.resize] specialises in the common task of image reduce and enlarge. It strings together combinations of [method@Image.shrink], [method@Image.reduce], [method@Image.affine] and others to implement a general, high-quality image resizer. Finally, [ctor@Image.thumbnail] combines load and resize in one operation, and adds colour management and correct handling of alpha transparency. Because load and resize happen together, it can exploit tricks like JPEG and TIFF shrink-on-load, giving a (potentially) huge speedup. [method@Image.thumbnail_image] is only there for emergencies, don't use it unless you really have to. As a separate thing, [method@Image.mapim] can apply arbitrary 2D image transforms to an image. ## Classes * [class@Interpolate] ## Callbacks * [callback@InterpolateMethod] ## Functions * [method@Image.shrink] * [method@Image.shrinkh] * [method@Image.shrinkv] * [method@Image.reduce] * [method@Image.reduceh] * [method@Image.reducev] * [ctor@Image.thumbnail] * [ctor@Image.thumbnail_buffer] * [method@Image.thumbnail_image] * [ctor@Image.thumbnail_source] * [method@Image.similarity] * [method@Image.rotate] * [method@Image.affine] * [method@Image.resize] * [method@Image.mapim] * [method@Image.quadratic] * [func@interpolate] * [ctor@Interpolate.new] * [func@Interpolate.bilinear_static] * [func@Interpolate.nearest_static] * [method@Interpolate.get_method] * [method@Interpolate.get_window_offset] * [method@Interpolate.get_window_size] ## Constants * [const@INTERPOLATE_SCALE] * [const@INTERPOLATE_SHIFT] * [const@TRANSFORM_SCALE] * [const@TRANSFORM_SHIFT] ## Enumerations * [enum@Kernel] * [enum@Size] libvips-8.18.2/doc/libvips-vips.md000066400000000000000000000020411516303661500170030ustar00rootroot00000000000000Title: Operator index > By section > Initialisation These functions handle the initialization, finalization, version retrieval, and relocation for libvips. libvips is a relocatable package, meaning you can move the directory tree you compiled it to at runtime and it will still be able to find all data files. This is required for macOS and Windows, but slightly unusual in the Unix world. See [func@init] and [func@guess_prefix]. ## Functions * [func@max_coord_get] * [func@init] * [func@get_argv0] * [func@get_prgname] * [func@shutdown] * [func@thread_shutdown] * [func@add_option_entries] * [func@leak_set] * [func@block_untrusted_set] * [func@version_string] * [func@version] * [func@guess_prefix] * [func@guess_libdir] ## Function macros * [func@INIT] ## Constants * [const@DEFAULT_MAX_COORD] * [const@ENABLE_DEPRECATED] * [const@LIBRARY_AGE] * [const@LIBRARY_CURRENT] * [const@LIBRARY_REVISION] * [const@MAJOR_VERSION] * [const@MICRO_VERSION] * [const@MINOR_VERSION] * [const@VERSION] * [const@VERSION_STRING] libvips-8.18.2/doc/making-image-pyramids.md000066400000000000000000000151041516303661500205340ustar00rootroot00000000000000Title: Using > Building image pyramids libvips includes [method@Image.dzsave], an operation that can build image pyramids compatible with [DeepZoom](http://en.wikipedia.org/wiki/Deep_Zoom), Zoomify and [Google Maps](https://developers.google.com/maps) image viewers. It's fast and can generate pyramids for large images using only a small amount of memory. The TIFF writer, [method@Image.tiffsave] can also build tiled pyramidal TIFF images, but that's very simple to use. This page concentrates on the DeepZoom builder. Run dzsave with no arguments to see a summary: ```bash $ vips dzsave save image to deepzoom file usage: dzsave in filename [--option-name option-value ...] where: in - Image to save, input VipsImage filename - Filename to save to, input gchararray optional arguments: imagename - Image name, input gchararray layout - Directory layout, input VipsForeignDzLayout default enum: dz allowed enums: dz, zoomify, google, iiif, iiif3 suffix - Filename suffix for tiles, input gchararray overlap - Tile overlap in pixels, input gint default: 1 min: 0, max: 8192 tile-size - Tile size in pixels, input gint default: 254 min: 1, max: 8192 centre - Center image in tile, input gboolean default: false depth - Pyramid depth, input VipsForeignDzDepth default enum: onepixel allowed enums: onepixel, onetile, one angle - Rotate image during save, input VipsAngle default enum: d0 allowed enums: d0, d90, d180, d270 container - Pyramid container type, input VipsForeignDzContainer default enum: fs allowed enums: fs, zip, szi compression - ZIP deflate compression level, input gint default: 0 min: -1, max: 9 region-shrink - Method to shrink regions, input VipsRegionShrink default enum: mean allowed enums: mean, median, mode, max, min, nearest skip-blanks - Skip tiles which are nearly equal to the background, input gint default: -1 min: -1, max: 65535 id - Resource ID, input gchararray Q - Q factor, input gint default: 75 min: 1, max: 100 keep - Which metadata to retain, input VipsForeignKeep default flags: exif:xmp:iptc:icc:other:all allowed flags: none, exif, xmp, iptc, icc, other, all background - Background value, input VipsArrayDouble operation flags: sequential nocache ``` You can also call [method@Image.dzsave] from any language with a libvips binding, or by using `.dz` or `.szi` as an output file suffix. ## Writing DeepZoom pyramids The `--layout` option sets the basic mode of operation. With no `--layout`, dzsave writes DeepZoom pyramids. For example: ```bash $ vips dzsave huge.tif mydz ``` This will create a directory called `mydz_files` containing the image tiles, and write a file called `mydz.dzi` containing the image metadata. You can use the `--suffix` option to control how tiles are written. For example: ```bash $ vips dzsave huge.tif mydz --suffix .jpg[Q=90] ``` will write JPEG tiles with the quality factor set to 90. You can set any format write options you like, see the API docs for [method@Image.jpegsave] for details. ## Writing Zoomify pyramids Use `--layout zoomify` to put dzsave into zoomify mode. For example: ```bash $ vips dzsave huge.tif myzoom --layout zoomify ``` This will create a directory called `myzoom` containing a file called `ImageProperties.xml` with the image metadata in, and a series of directories called `TileGroupn`, each containing 256 image tiles. As with DeepZoom, you can use `--suffix` to set jpeg quality. ## Writing Google Maps pyramids Use `--layout google` to write Google maps-style pyramids. These are compatible with [Leaflet](http://leafletjs.com). For example: ```bash $ vips dzsave wtc.tif gmapdir --layout google ``` Will create a directory called `gmapdir` containing `blank.png`, the file to display for blank tiles, and a set of numbered directories, one for each zoom level. The pyramid can be sparse (blank tiles are not written). As with DeepZoom, you can use `--suffix` to set jpeg quality. Use `--background` to set the background colour. This is the colour displayed for bits of the pyramid not in the image (image edges, for example). By default, the image background is white. Use `--centre` to add a border to the image large enough to centre the image within the lowest resolution tile. By default, images are not centred. For example: ```bash $ vips dzsave wtc.tif gmapdir --layout google --background 0 --centre ``` ## Other options You can use `--tile-size` and `--overlap` to control how large the tiles are and how they overlap (obviously). They default to the correct values for the selected layout. You can use `--depth` to control how deep the pyramid should be. Possible values are `onepixel`, `onetile` and `one`. `onepixel` means the image is shrunk until it fits within a single pixel. `onetile` means shrink until it fits with a tile. `one` means only write one pyramid layer (the highest resolution one). It defaults to the correct value for the selected layout. `--depth one` is handy for slicing up a large image into tiles (rather than a pyramid). You can use `--angle` to do a 90, 180 or 270 degree rotate of an image during pyramid write. You can use `--container` to set the container type. Normally dzsave will write a tree of directories, but with `--container zip` you'll get a zip file instead. Use .zip as the directory suffix to turn on zip format automatically: ```bash $ vips dzsave wtc.tif mypyr.zip ``` to write a zipfile containing the tiles. You can use `.szi` as a suffix to enable zip output as well. ## Preprocessing images You can use `.dz` as a filename suffix, meaning send the image to [method@Image.dzsave]. This means you can write the output of any libvips operation to a pyramid. For example: ```bash $ vips extract_area huge.svs mypy.dz[layout=google] 100 100 10000 10000 ``` The arguments to `extract_area` are image-in, image-out, left, top, width, height. So this command will cut out a 10,000 by 10,000 pixel area from near the top-left-hand corner of an Aperio slide image, then build a pyramid in Google layout using just those pixels. If you are working from OpenSlide images, you can use the shrink-on-load feature of many of those formats. For example: ```bash $ vips dzsave CMU-1.mrxs[level=1] x ``` Will pull out level 1 (the half-resolution level of an MRXS slide) and make a pyramid from that. ## Troubleshooting If you are building libvips from source you do need to check the summary at the end of configure carefully. You must have the `libarchive-dev` package for [method@Image.dzsave] to work. libvips-8.18.2/doc/meson.build000066400000000000000000000051751516303661500162070ustar00rootroot00000000000000gidocgen = find_program('gi-docgen') if not enable_introspection error('API reference requires introspection.') endif docs_dir = get_option('prefix') / get_option('datadir') / 'doc' vips_content_files = files( 'binding.md', 'cite.md', 'developer-checklist.md', 'examples.md', 'extending.md', 'file-format.md', 'function-list.md', 'how-it-opens-files.md', 'how-it-works.md', 'making-image-pyramids.md', 'multipage-and-animated-images.md', 'uhdr.md', 'using-from-c.md', 'using-from-cplusplus.md', 'using-the-cli.md', 'using-threads.md', 'using-vipsthumbnail.md', ) vips_section_files = files( 'libvips-arithmetic.md', 'libvips-basic.md', 'libvips-colour.md', 'libvips-conversion.md', 'libvips-convolution.md', 'libvips-create.md', 'libvips-draw.md', 'libvips-error.md', 'libvips-freqfilt.md', 'libvips-generate.md', 'libvips-header.md', 'libvips-histogram.md', 'libvips-memory.md', 'libvips-morphology.md', 'libvips-mosaicing.md', 'libvips-resample.md', 'libvips-vips.md', ) vips_include_dir = meson.current_build_dir() / 'libvips' / 'include' doc_conf = configuration_data() doc_conf.set('VIPS_VERSION', '@0@.@1@'.format(version_major, version_minor)) vips_toml = configure_file( input: 'vips.toml.in', output: 'vips.toml', configuration: doc_conf, install: true, install_dir: docs_dir / 'vips', ) fixup_gir_for_doc = find_program('fixup-gir-for-doc.py') vips_gir_doc = custom_target('vips-gir-docs', input: vips_gir[0], output: 'Vips-@0@.0-doc.gir'.format(version_major), command: [fixup_gir_for_doc, '@INPUT@', '@OUTPUT@'], depends: vips_gir[0], ) custom_target('vips-docs', input: [vips_toml, vips_gir_doc], output: 'vips', command: [ gidocgen, 'generate', '--quiet', '--no-namespace-dir', '--add-include-path=@0@'.format(vips_include_dir), '--config=@INPUT0@', '--output-dir=@OUTPUT@', '--content-dir=@0@'.format(meson.current_source_dir()), '@INPUT1@', ], depends: vips_gir_doc, depend_files: [vips_content_files, vips_section_files], build_by_default: true, install: true, install_dir: docs_dir, ) test('doc-check-gir', gidocgen, args: [ 'check', '--config', vips_toml, '--add-include-path=@0@'.format(vips_include_dir), vips_gir_doc, ], depends: vips_gir_doc, # FIXME: Remove once we have documented all public-facing symbols, # parameters and return values. should_fail: true, suite: ['docs'], ) check_sections = find_program('check-sections.py') test('doc-check-sections', check_sections, args: ['--gir', vips_gir_doc] + vips_section_files, depends: vips_gir_doc, suite: ['docs'], ) libvips-8.18.2/doc/multipage-and-animated-images.md000066400000000000000000000135041516303661500221340ustar00rootroot00000000000000Title: Using > Multipage and animated images libvips represents animated and multipage images as tall, thin strips of frames, like a strip of movie film (or a roll of toilet paper). Special image metadata items are used to hold the page height, the number of frames, and any frame delay or loop settings. At least the JXL, GIF and WebP loaders and savers support animation, and the TIFF, PDF, HEIC, AVIF and VIPS loaders and savers support multipage. ## Reading multipage images For example, at the command-line, try: ```bash $ vipsheader -a silver-gear-cogs-animation-5.gif[n=-1] silver-gear-cogs-animation-5.gif: 281x2560 uchar, 4 bands, srgb, gifload width: 281 height: 2560 bands: 4 format: uchar coding: none interpretation: srgb xoffset: 0 yoffset: 0 xres: 1 yres: 1 filename: silver-gear-cogs-animation-5.gif vips-loader: gifload page-height: 320 n-pages: 8 loop: 0 delay: 100 100 100 100 100 100 100 100 background: 0 0 0 gif-palette: -12500671 -11447983 -723724 -3289651 -11974327 -11711155 -5395027 -13027015 -9276814 -9408400 -16777216 -14079703 -197380 -12237499 -5723992 -526345 -15592942 -12763843 -5921371 -13750738 -13553359 -10592674 -6908266 -7829368 -7960954 -8158333 -809254 bits-per-sample: 7 palette: 1 ``` Points to note: - By default, libvips will just read the first page from an animated or multipage image. You pass `[n=-1]` to the loader to get all pages (or frames) in the animation. You can pick out a single page or range of pages with perhaps `[page=4]` and `[page=2,n=2]`. - `page-height` is the vertical size of each frame within the overall image (2560 pixels high in this case). - `n-pages` is the number of pages (or frames) in this animation. Obviously `n-pages * frame-height == height`, or in this case 320 * 8 == 2560. - `loop` is the number of times the animation should loop before stopping. Zero means "never stop looping". - `delay` is an optional array with a time in milliseconds which each frame should display for. You'll see a similar set of metadata for a multipage image, such as a PDF: ```bash $ vipsheader -a nipguide.pdf[n=-1] nipguide.pdf: 595x48836 uchar, 4 bands, srgb, pdfload width: 595 height: 48836 bands: 4 format: uchar coding: none interpretation: srgb xoffset: 0 yoffset: 0 xres: 2.83465 yres: 2.83465 filename: nipguide.pdf vips-loader: pdfload page-height: 842 pdf-n_pages: 58 n-pages: 58 pdf-creator: TeX pdf-producer: pdfTeX-1.40.16 ``` Now there's no `loop` or `delay` since this is not animated, but `n-pages` and `page-height` are set. In just the same way, you can load all pages, a single page or a range of pages. This all assumes that every page (or frame) has the same dimensions. If they don't (this can commonly happen with PDF and TIFF), you have to read pages one by one. ## Writing multipage images As long as these various pieces of metadata are set, you can write animated and multipage images in the obvious way. For example: ```bash $ vips copy nipguide.pdf[n=-1] x.gif ``` This will take the 58-page PDF and render a 58-frame animation. This only works because this specific PDF has pages which are all the same size -- PDFs with (for example) a mix of portrait and landscape pages can't be handled like this. More usefully, you could convert a GIF to WebP with: ```bash $ vips copy silver-gear-cogs-animation-5.gif[n=-1] silver.webp ``` To write an animated or multipage image programmatically, you need to construct the tall, thin image and set the metadata. For example: ```bash $ vips arrayjoin "k2.jpg k4a.png" x.tif[page-height=2048] --across=1 ``` Provided that the images are both 2048 pixels high, this will write a two-page TIFF. In Python you could write something like: ```python #!/usr/bin/env python3 import sys import pyvips # the input images -- assume these are all the same size images = [pyvips.Image.new_from_file(filename, access="sequential") for filename in sys.argv[2:]] # frame delays are in milliseconds delay_array = [300] * len(images) animation = pyvips.Image.arrayjoin(images, across=1).copy() animation.set_type(pyvips.GValue.gint_type, "loop", 10) animation.set_type(pyvips.GValue.gint_type, "n-pages", len(images)) animation.set_type(pyvips.GValue.gint_type, "page-height", images[0].height) animation.set_type(pyvips.GValue.array_int_type, "delay", delay_array) print(f"writing {sys.argv[1]} ...") animation.write_to_file(sys.argv[1]) ``` It's a little more fiddly in C: ```c /* compile with * * gcc -g -Wall assemble-animated.c `pkg-config vips --cflags --libs` */ #include #include /* for libvips before 8.16, add this line: * G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsImage, g_object_unref) */ int main(int argc, char *argv[]) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc < 3) vips_error_exit("usage: %s outfile infile1 infile2 ...", argv[0]); /* Load a set of input files. */ g_autoptr(GPtrArray) frames = g_ptr_array_new_full(argc, g_object_unref); for (int i = 2; i < argc; i++) { VipsImage *frame; if (!(frame = vips_image_new_from_file(argv[i], "access", VIPS_ACCESS_SEQUENTIAL, NULL))) vips_error_exit(NULL); g_ptr_array_add(frames, frame); } /* Combine to form a vertical strip. */ g_autoptr(VipsImage) strip; if (vips_arrayjoin((VipsImage **) frames->pdata, &strip, frames->len, "across", 1, NULL)) vips_error_exit(NULL); /* Set the animation metadata. Delay times are in milliseconds. */ VipsImage *frame0 = VIPS_IMAGE(frames->pdata[0]); vips_image_set_int(strip, "page-height", frame0->Ysize); vips_image_set_int(strip, "loop", 10); int delays[] = { 300, 300, 300 }; vips_image_set_array_int(strip, "delay", delays, VIPS_NUMBER(delays)); if (vips_image_write_to_file(strip, argv[1], NULL)) vips_error_exit(NULL); return 0; } ``` libvips-8.18.2/doc/uhdr.md000066400000000000000000000144471516303661500153330ustar00rootroot00000000000000Title: Using > Processing UltraHDR images libvips can process HDR images encoded with [UltraHDR](https://en.wikipedia.org/wiki/Ultra_HDR). These are ordinary SDR images, but with a gainmap embedded within them -- SDR displays will just show the regular SDR image, but for an HDR display, the extra gainmap can be used as an exponent to recover the full HDR range. This ability to show the same file in good quality on both SDR and HDR displays makes the format very useful. libvips uses Google's [libultrahdr](https://github.com/google/libultrahdr) for UltraHDR load and save. The current version of this library only supports UltraHDR JPEG images; the next version is expected to add support for a wider range of image formats. There are two main paths for UltraHDR images in libvips: as an SDR image with a separate gainmap, and as a full HDR image. The separate gainmap path is relatively fast but you will sometimes need to update the gainmap during processing. The full HDR path does not require gainmap updates, but can be slower, and will usually lose the original image's tone mapping. ## UltraHDR as SDR with a separate gainmap libvips will detect JPEG images with an embedded gainmap and automatically invoke the [ctor@Image.uhdrload] operation to load them. This operation attaches the gainmap (a small JPEG-compressed image) as the `"gainmap-data"` metadata item, plus some other gainmap tags. ### Load and save For example: ``` $ vipsheader -a ultra-hdr.jpg ultra-hdr.jpg: 3840x2160 uchar, 3 bands, srgb, uhdrload width: 3840 height: 2160 bands: 3 format: uchar coding: none interpretation: srgb xoffset: 0 yoffset: 0 xres: 1 yres: 1 filename: ultra-hdr.jpg vips-loader: uhdrload icc-profile-data: 588 bytes of binary data gainmap-data: 31738 bytes of binary data gainmap-max-content-boost: 100 100 100 gainmap-min-content-boost: 1 1 1 gainmap-gamma: 1 1 1 gainmap-offset-sdr: 0 0 0 gainmap-offset-hdr: 0 0 0 gainmap-hdr-capacity-min: 1 gainmap-hdr-capacity-max: 100 gainmap-use-base-cg: 1 ``` This gainmap metadata is copied unmodified through any processing operations. If you save an image with gainmap metadata to a JPEG file, libvips will do the write with the [method@Image.uhdrsave] operation, embedding the gainmap and the associated metadata in the output image. Intermediate operations which change the image geometry will also need to update the `"gainmap-data"` metadata item, the mechanisms for doing this are described below. The other gainmap fields should probably not be changed unless the intention is to alter the image appearance. ### High-level libvips operations Two high-level libvips operations will automatically update the gainmap for you during processing: [method@Image.dzsave] and [ctor@Image.thumbnail]. [method@Image.dzsave] always strips all metadata by default, so you'll need to set `keep="gainmap"` to write the gainmap to the tiles. For example: ``` $ vips dzsave ultra-hdr.jpg x --keep gainmap ``` ### À la carte processing Other operations will NOT automatically update the gainmap for you. If you call something like [method@Image.crop], an operation which changes the image geometry, the gainmap and the image will no longer match. When you save the cropped image, the gainmap is likely to be incorrect. A helper function, [method@Image.get_gainmap], makes updating the gainmap relatively easy: it returns a [class@Image] for the gainmap, and attaches the image pointer as the metadata item `"gainmap"`. Once you have updated the gainmap, you can overwrite this value. For example, in C you could write ```C VipsImage *image = ...; VipsImage *out; int left, top, width, height; if (vips_crop(image, &out, left, top, width, height, NULL)) return -1; // also crop the gainmap, if there is one VipsImage *gainmap; if ((gainmap = vips_image_get_gainmap(out))) { // the gainmap can be smaller than the image, we must scale the // crop area double hscale = (double) gainmap->Xsize / image->Xsize; double vscale = (double) gainmap->Ysize / image->Ysize; VipsImage *new_gainmap; if (vips_crop(gainmap, &new_gainmap, left * hscale, top * vscale, width * hscale, height * vscale, NULL)) return -1; g_object_unref(gainmap); // vips_image_set_image() modifies the image, so we need to make a // unique copy ... you can skip this step if you know your image is // already unique VipsImage *new_out; if (vips_copy(out, &new_out, NULL)) { g_object_unref(new_gainmap); return -1; } g_object_unref(out); out = new_out; // update the gainmap vips_image_set_image(out, "gainmap", new_gainmap); g_object_unref(new_gainmap); } ``` Or with ruby-vips: ```ruby def crop_image_and_gainmap(image, left, top, width, height) image = image.crop left, top, width, height gainmap = image.get_gainmap unless gainmap.nil? hscale = gainmap.width / image.width vscale = gainmap.height / image.height new_gainmap = gainmap.crop left * hscale, top * vscale, width * hscale, height * vscale image = image.mutate do |mutable| mutable.set_type! Vips::IMAGE_TYPE, "gainmap", new_gainmap end end image end ``` ### Performance and quality considerations Doing gainmap processing explicitly like this has two big advantages: first, you have exact control over this processing, so you can make sure only the gainmap transformations that are strictly necessary take place. Secondly, since you supply the gainmap to the UltraHDR save, you can also be certain any user tone mapping is preserved. The disadvantage is the extra development work necessary. The second UltraHDR path in libvips avoids this problem. ## Full HDR processing You can transform an UltraHDR SDR plus gainmap image to full HDR with [method@Image.uhdr2scRGB]. This will compute an scRGB image: a three-band float with sRGB primaries, black to white as linear 0-1, and out of range values used to represent HDR. For example: ``` $ vips uhdr2scRGB ultra-hdr.jpg x.v $ vipsheader x.v x.v: 3840x2160 float, 3 bands, scrgb, uhdrload $ vips max x.v 15.210938 ``` If you save an scRGB image as JPEG, it will be automatically written as UltraJPEG. Any associated gainmap is thrown away and basic tonemapping performed to make a new gainmap for SDR display. Full HDR processing with scRGB is simple, but potentially slower than the separate gainmap path, and will not preserve any user tone map. libvips-8.18.2/doc/urlmap.js000066400000000000000000000004121516303661500156700ustar00rootroot00000000000000// A map between namespaces and base URLs for their online documentation baseURLs = [ ['GLib', 'https://docs.gtk.org/glib/'], ['Gio', 'https://docs.gtk.org/gio/'], ['GObject', 'https://docs.gtk.org/gobject/'], ['GModule', 'https://docs.gtk.org/gmodule/'], ] libvips-8.18.2/doc/using-from-c.md000066400000000000000000000220411516303661500166640ustar00rootroot00000000000000Title: Using > C libvips comes with a convenient, high-level C API. You should read the API docs for full details, but this section will try to give a brief overview. ## Library startup When your program starts, use [func@INIT] to start up libvips. You should pass it the name of your program, usually `argv[0]`. If you call [func@shutdown] just before you exit, libvips will attempt to free all resources. This can help leak checking, but is not required. [func@INIT] is a macro to let it check that the libvips shared library you have linked to matches the libvips headers you included. You can add the libvips flags to your [class@GObject.Object] command-line processing with [func@add_option_entries]. ## The [class@Image] class The basic data object is the [class@Image]. You can create an image from a file on disc or from an area of memory, either as a C-style array, or as a formatted object, like JPEG. See [ctor@Image.new_from_file] and friends. Loading an image is fast: libvips read just enough of the image to be able to get the various properties, such as width, but no decoding occurs until pixel values are really needed. Once you have an image, you can get properties from it in the usual way. You can use projection functions, like [method@Image.get_width] or [method@GObject.Object.get], to get [class@GObject.Object] properties. All libvips objects are immutable, meaning you can only get properties, you can't set them. See [libvips Header](file-format.html) to read about image properties. ## Reference counting libvips is based on the [class@GObject.Object] library and is therefore reference counted. [ctor@Image.new_from_file] returns an object with a count of 1. When you are done with an image, use [method@GObject.Object.unref] to dispose of it. If you pass an image to an operation and that operation needs to keep a copy of the image, it will ref it. So you can unref an image as soon as you no longer need it, you don't need to hang on to it in case anyone else is still using it. See [class@Operation] for more details on libvips' reference counting conventions. See the [Reference pools](#reference-pools) section below for a way to automate reference counting in C. ## libvips operations Use things like [method@Image.embed] to manipulate your images. You use it from C like this: ```c const char *filename; VipsImage *in = vips_image_new_from_file(filename, NULL); const int x = 10; const int y = 10; const int width = 1000; const int height = 1000; VipsImage *out; if (vips_embed(in, &out, x, y, width, height, NULL)) error_handling(); ``` Now `out` will hold a reference to a 1000 by 1000 pixel image, with `in` pasted 10 right and 10 down from the top left-hand corner. The remainder of the image will be black. If `in` is too large, it will be clipped at the image edges. Operations can take optional arguments. You give these as a set of NULL-terminated name-value pairs at the end of the call. For example, you can write: ```c if (vips_embed(in, &out, x, y, width, height, "extend", VIPS_EXTEND_COPY, NULL)) error_handling(); ``` And now the new edge pixels, which were black, will be filled with a copy of the edge pixels of `in`. Operation options are listed at the top of each operation's entry in the docs. Alternatively, the `vips` program is handy for getting a summary of an operation's parameters. For example: ```bash $ vips embed embed an image in a larger image usage: embed in out x y width height [--option-name option-value ...] where: in - Input image, input VipsImage out - Output image, output VipsImage x - Left edge of input in output, input gint default: 0 min: -1000000000, max: 1000000000 y - Top edge of input in output, input gint default: 0 min: -1000000000, max: 1000000000 width - Image width in pixels, input gint default: 1 min: 1, max: 1000000000 height - Image height in pixels, input gint default: 1 min: 1, max: 1000000000 optional arguments: extend - How to generate the extra pixels, input VipsExtend default enum: black allowed enums: black, copy, repeat, mirror, white, background background - Colour for background pixels, input VipsArrayDouble ``` See [class@Operation] for more information on running operations on images. The API docs have a [handy table of all libvips operations]( function-list.html), if you want to find out how to do something, try searching that. When you are done, you can write the final image to a disc file, to a formatted memory buffer, or to C-style memory array. See [method@Image.write_to_file] and friends. ## Getting pixels Use [class@Region] to read pixels out of images. You can use [func@IMAGE_ADDR] as well, but this can need a large amount of memory to work. See [extending]( extending.html) for an introduction to writing your own operations. ## Error handling libvips keeps a log of error message, see [func@error_buffer] and [func@error_clear] to find out how to get and clear the error log. ## Example On Unix systems, you can compile the [example code](#libvips-from-c-example) with something like: ```bash $ gcc -g -Wall myprog.c `pkg-config vips --cflags --libs` ``` On Windows, you'll need to set the compiler flags by hand, perhaps: ```bash x86_64-w64-mingw32-gcc-win32 -mms-bitfields \ -Ic:/vips-8.6/include \ -Ic:/vips-8.6/include/glib-2.0 \ -Ic:/vips-8.6/lib/glib-2.0/include \ myprog.c \ -Lc:/vips-8.6/lib \ -lvips -lz -ljpeg -lstdc++ -lxml2 -lfftw3 -lm -lMagickWand -llcms2 \ -lopenslide -lcfitsio -lpangoft2-1.0 -ltiff -lpng14 -lexif \ -lMagickCore -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 \ -lgmodule-2.0 -lgthread-2.0 -lglib-2.0 -lintl \ -o myprog.exe ``` ## libvips from C example ```c #include #include int main(int argc, char **argv) { VipsImage *in; double mean; VipsImage *out; if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s infile outfile", argv[0]); if (!(in = vips_image_new_from_file(argv[1], NULL))) vips_error_exit(NULL); printf("image width = %d\n", vips_image_get_width(in)); if (vips_avg(in, &mean, NULL)) vips_error_exit(NULL); printf("mean pixel value = %g\n", mean); if (vips_invert(in, &out, NULL)) vips_error_exit(NULL); g_object_unref(in); if (vips_image_write_to_file(out, argv[2], NULL)) vips_error_exit(NULL); g_object_unref(out); return 0; } ``` ## Reference pools libvips has a simple system to automate at least some reference counting issues. Reference pools are arrays of object pointers which will be released automatically when some other object is finalized. The code below crops a many-page image (perhaps a GIF or PDF). It splits the image into separate pages, crops each page, reassembles the cropped areas, and saves again. It creates a `context` object representing the state of processing, and `crop_animation` allocates two reference pools off that using [method@Object.local_array], one to hold the cropped frames, and one to assemble and copy the result. All unreffing is handled by `main`, and it doesn't need to know anything about `crop_animation`. ```c #include static int crop_animation(VipsObject *context, VipsImage *image, VipsImage **out, int left, int top, int width, int height) { int page_height = vips_image_get_page_height(image); int n_pages = image->Ysize / page_height; VipsImage **page = (VipsImage **) vips_object_local_array(context, n_pages); VipsImage **copy = (VipsImage **) vips_object_local_array(context, 1); int i; /* Split the image into cropped frames. */ for (i = 0; i < n_pages; i++) if (vips_crop(image, &page[i], left, page_height * i + top, width, height, NULL)) return -1; /* Reassemble the frames and set the page height. You must copy before * modifying metadata. */ if (vips_arrayjoin(page, ©[0], n_pages, "across", 1, NULL) || vips_copy(copy[0], out, NULL)) return -1; vips_image_set_int(*out, "page-height", height); return 0; } int main(int argc, char **argv) { VipsImage *image; VipsObject *context; VipsImage *x; if (VIPS_INIT(NULL)) vips_error_exit(NULL); if (!(image = vips_image_new_from_file(argv[1], "access", VIPS_ACCESS_SEQUENTIAL, NULL))) vips_error_exit(NULL); context = VIPS_OBJECT(vips_image_new()); if (crop_animation(context, image, &x, 10, 10, 500, 500)) { g_object_unref(image); g_object_unref(context); vips_error_exit(NULL); } g_object_unref(image); g_object_unref(context); image = x; if (vips_image_write_to_file(image, argv[2], NULL)) { g_object_unref(image); vips_error_exit(NULL); } g_object_unref(image); return 0; } ``` libvips-8.18.2/doc/using-from-cplusplus.md000066400000000000000000000004541516303661500205000ustar00rootroot00000000000000Title: Using > C++ libvips comes with a convenient C++ API. It is a very thin wrapper over the C API and adds automatic reference counting, exceptions, operator overloads, and automatic constant expansion. See the [C++ API documentation](https://www.libvips.org/API/current/cpp/) for more details. libvips-8.18.2/doc/using-the-cli.md000066400000000000000000000107111516303661500170270ustar00rootroot00000000000000Title: Using > At the command-line Use the `vips` command to execute libvips operations from the command-line. For example: ```bash $ vips rot k2.jpg x.jpg d90 ``` Will rotate the image `k2.jpg` by 90 degrees anticlockwise and write the result to the file `x.jpg`. If you don't give any arguments to an operation, `vips` will give a short description, for example: ```bash $ vips rot rotate an image usage: rot in out angle where: in - Input image, input VipsImage out - Output image, output VipsImage angle - Angle to rotate image, input VipsAngle default: d90 allowed: d0, d90, d180, d270 ``` There's a straightforward relationship with the C API: compare this to the API docs for [method@Image.rot]. ## Listing all operations You can list all classes with: ```bash $ vips -l ... VipsOperation (operation), operations VipsSystem (system), run an external command VipsArithmetic (arithmetic), arithmetic operations VipsBinary (binary), binary operations VipsAdd (add), add two images ... etc. ``` Each line shows the canonical name of the class (for example `VipsAdd`), the class nickname (`add` in this case), and a short description. Some subclasses of operation will show more: for example, subclasses of `VipsForeign` will show some of the extra flags supported by the file load/save operations. The API docs have a [handy table of all libvips operations]( function-list.html), if you want to find out how to do something, try searching that. ## Optional arguments Many operations take optional arguments. You can supply these as command-line options. For example: ```bash $ vips gamma gamma an image usage: gamma in out [--option-name option-value ...] where: in - Input image, input VipsImage out - Output image, output VipsImage optional arguments: exponent - Gamma factor, input gdouble default: 0.416667 min: 1e-06, max: 1000 operation flags: sequential ``` [method@Image.gamma] applies a gamma factor to an image. By default, it uses 2.4, the sRGB gamma factor, but you can specify any gamma with the `exponent` option. Use it from the command-line like this: ```bash $ vips gamma k2.jpg x.jpg --exponent 0.42 ``` This will read file `k2.jpg`, un-gamma it, and write the result to file `x.jpg`. ## Array arguments Some operations take arrays of values as arguments. For example, [method@Image.affine] needs an array of four numbers for the 2x2 transform matrix. You pass arrays as space-separated lists: ```bash $ vips affine k2.jpg x.jpg "2 0 0 1" ``` You may need the quotes to stop your shell breaking the argument at the spaces. [func@Image.bandjoin] needs an array of input images to join, run it like this: ```bash $ vips bandjoin "k2.jpg k4.jpg" x.tif ``` ## Implicit file format conversion `vips` will automatically convert between image file formats for you. Input images are detected by sniffing their first few bytes; output formats are set from the filename suffix. You can see a list of all the supported file formats with something like: ```bash $ vips -l foreign ``` Then get a list of the options a format supports with: ```bash $ vips jpegsave ``` You can pass options to the implicit load and save operations enclosed in square brackets after the filename: ```bash $ vips affine k2.jpg x.jpg[Q=90,strip] "2 0 0 1" ``` Will write `x.jpg` at quality level 90 and will strip all metadata from the image. ## Chaining operations Because each operation runs in a separate process, you can't use libvips's chaining system to join operations together, you have to use intermediate files. The command-line interface is therefore quite a bit slower than Python or C. The best alternative is to use libvips files for intermediates. Something like: ```bash $ vips invert input.jpg t1.v $ vips affine t1.v output.jpg "2 0 0 1" $ rm t1.v ``` ## Other features Finally, `vips` has a couple of useful extra options. - Use `--vips-progress` to get `vips` to display a simple progress indicator. - Use `--vips-leak` and `vips` will leak-test on exit, and also display an estimate of peak memory use. - Set `G_MESSAGES_DEBUG=VIPS` and GLib will display informational and debug messages from libvips. libvips comes with a couple of other useful programs. `vipsheader` is a command which can print image header fields. `vipsedit` can change fields in `.v` format images. `vipsthumbnail` can make image thumbnails quickly. libvips-8.18.2/doc/using-threads.md000066400000000000000000000110411516303661500171310ustar00rootroot00000000000000Title: Using > Threads This section tries to summarise the rules for threaded programs using libvips. Generally, libvips is threaded and thread-safe, with a few exceptions. ## Images On startup, you need to call [func@INIT] single-threaded. After that, you can freely create images in any thread and read them in any other thread. See the example at the end of this chapter. Note that results can also be shared between threads for you by the libvips operation cache. The exception is the drawing operators, such as [method@Image.draw_circle]. These operations modify their image argument so you can't call them on the same image from more than one thread. Reading from an image while another thread is writing to it with one of the draw operations will obviously also fail. When libvips calculates an image, by default it will use as many threads as you have CPU cores. Use [func@concurrency_set] to change this. ## Error handling libvips has a single error code (-1 or %NULL) returned by all functions on error. Error messages are not returned, instead they are logged in a single global error buffer shared by all threads, see [func@error_buffer]. This makes error handling very simple but the obvious downside is that because error returns and error messages are separate, when you detect an error return you can't be sure that what's in the error buffer is the message that matches your error. The simplest way to handle this is to present the whole error log to the user on the next interaction and leave it to them to decide what action caused the failure. ## Using [class@Region] between threads [class@Image] objects are immutable and can be shared between threads very simply. However the lower-level [class@Region] object used to implement [class@Image] (see [extending libvips](extending.html)) is mutable and you can only use a [class@Region] from one thread at once. In fact it's worse than that: to reduce locking, [class@Region] keeps a lot of state in per-thread storage. If you want to create a region in one thread and use it in another, you have to first tag the region as unowned from the creating thread with `vips__region_no_ownership()`, then in the receiving thread take ownership with `vips__region_take_ownership()`. See the source for operations like [method@Image.tilecache] if you're curious how this works. libvips includes a set of sanity checks for region ownership and will fail if you don't pass ownership correctly. ## Example This example runs many [method@Image.resize] in parallel from many threads. ```c /* Read from many threads. * * Compile with: * * gcc -g -Wall soak.c `pkg-config vips --cflags --libs` * * Run with: * * rm -rf x * mkdir x * for i in {0..10}; do ./a.out ~/pics/k2.jpg; done * */ #include #include #include /* How many pings we run at once. */ #define NUM_IN_PARALLEL (50) /* Number of tests we do in total. */ #define TOTAL_TESTS (NUM_IN_PARALLEL * 20) /* Workers queue up on this. */ GMutex allocation_lock; /* Our set of threads. */ GThread *workers[NUM_IN_PARALLEL]; /* Number of calls so far. */ int n_calls = 0; /* Our test function. This is called by NUM_IN_PARALLEL threads a total of * TOTAL_TESTS times. */ static int test(const char *filename) { VipsImage *im, *x; char output_file[256]; snprintf(output_file, 256, "x/tmp-%p.jpg", g_thread_self()); if (!(im = vips_image_new_from_file(filename, "access", VIPS_ACCESS_SEQUENTIAL, NULL))) return -1; if (vips_resize(im, &x, 0.1, NULL)) { g_object_unref(im); return -1; } g_object_unref(im); im = x; if (vips_image_write_to_file(im, output_file, NULL)) { g_object_unref(im); return -1; } g_object_unref(im); return 0; } /* What we run as a thread. */ static void * worker(void *data) { const char *filename = (const char *) data; for (;;) { gboolean done; done = FALSE; g_mutex_lock(&allocation_lock); n_calls += 1; if (n_calls > TOTAL_TESTS) done = TRUE; g_mutex_unlock(&allocation_lock); if (done) break; if (test(filename)) vips_error_exit(NULL); } return NULL; } int main(int argc, char **argv) { int i; if (VIPS_INIT(argv[0])) vips_error_exit(NULL); for (i = 0; i < NUM_IN_PARALLEL; i++) workers[i] = g_thread_new(NULL, (GThreadFunc) worker, argv[1]); for (i = 0; i < NUM_IN_PARALLEL; i++) g_thread_join(workers[i]); return 0; } ``` libvips-8.18.2/doc/using-vipsthumbnail.md000066400000000000000000000154151516303661500203750ustar00rootroot00000000000000Title: Using > vipsthumbnail libvips ships with a handy command-line image thumbnailer, `vipsthumbnail`. This page introduces it, with some examples. The thumbnailing functionality is implemented by [ctor@Image.thumbnail], see the docs for details. You can it from any language with a libvips binding. For example, from PHP you could write: ```php $filename = "image.jpg"; $image = Vips\Image::thumbnail($filename, 200, ["height" => 200]); $image->writeToFile("my-thumbnail.jpg"); ``` You can also call `thumbnail_source` from the CLI, for example: ```console $ cat k2.jpg | \ vips thumbnail_source [descriptor=0] .jpg[Q=90] 128 | \ cat > x.jpg ``` To thumbnail directly between a pair of pipes. ## libvips options `vipsthumbnail` supports the usual range of `vips` command-line options. A few of them are useful: `--vips-cache-trace` shows each operation as libvips starts it. It can be handy to see exactly what operations `vipsthumbnail` is running for you. `--vips-leak` turns on the libvips memory leak checker. As well as reporting leaks (hopefully there are none) it also tracks and reports peak memory use. `--vips-progress` runs a progress indicator during computation. It can be useful to see where libvips is looping and how often. `--vips-info` shows a higher level view of the operations that `vipsthumbnail` is running. ## Looping `vipsthumbnail` can process many images in one command. For example: ```console $ vipsthumbnail *.jpg ``` will make a thumbnail for every JPEG in the current directory. See the [Path option](#path-option) section below to see how to control where thumbnails are written. `vipsthumbnail` will process images one after the other. You can get a good speedup by running several `vipsthumbnail`s in parallel, depending on how much load you want to put on your system. For example: ```console $ parallel vipsthumbnail ::: *.jpg ``` ## Thumbnail size You can set the bounding box of the generated thumbnail with the `--size` option. For example: ```console $ vipsthumbnail shark.jpg --size 200x100 ``` Use a single number to set a square bounding box. You can omit either number but keep the x to mean resize just based on that axis, for example: ```console $ vipsthumbnail shark.jpg --size 200x ``` Will resize to 200 pixels across, no matter what the height of the input image is. You can append `<` or `>` to mean only resize if the image is smaller or larger than the target. You can append `!` to force a resize to the exact target size, breaking the aspect ratio. ## Cropping `vipsthumbnail` normally shrinks images to fit within the box set by `--size`. You can use the `--smartcrop` option to crop to fill the box instead. Excess pixels are trimmed away using the strategy you set. For example: ```console $ vipsthumbnail owl.jpg --smartcrop attention -s 128 ``` Where `owl.jpg` is an off-centre composition: ![Owl](owl.jpg) Gives this result: ![Smartcrop](tn_owl.jpg) First it shrinks the image to get the vertical axis to 128 pixels, then crops down to 128 pixels across using the `attention` strategy. This one searches the image for features which might catch a human eye, see [method@Image.smartcrop] for details. ## Linear light Shrinking images involves combining many pixels into one. Arithmetic averaging really ought to be in terms of the number of photons, but for historical reasons the values stored in image files are usually related to the voltage that should be applied to the electron gun in a CRT display. `vipsthumbnail` has an option to perform image shrinking in linear space, that is, a colourspace where values are proportional to photon numbers. For example: ```console $ vipsthumbnail fred.jpg --linear ``` The downside is that in linear mode none of the very fast shrink-on-load tricks that `vipsthumbnail` normally uses are possible, since the shrinking is done at encode time, not decode time, and is done in terms of CRT voltage, not photons. This can make linear light thumbnailing of large images slow. For example, for a 10,000 x 10,000 pixel JPEG I see: ```console $ time vipsthumbnail wtc.jpg real 0m0.317s user 0m0.292s sys 0m0.016s $ time vipsthumbnail wtc.jpg --linear real 0m4.660s user 0m4.640s sys 0m0.016s ``` ## Path option Use `--path` to control where and how the thumbnail is written. Three substitutions are performed on the argument: `%s` is replaced by the input basename with any suffix removed, `%d` is replaced by the input dirname, and `%c` is replaced by the current working directory. The default value is `%d/tn_%s.jpg` meaning JPEG output, to the same directory as the input file, with `tn_` prepended. You can add format options too, for example `%c/%s/tn_%s.jpg[Q=20]` will write JPEG images to a tree within the current directory with `Q` set to 20, or `tn_%s.png` will write thumbnails as PNG images. The `keep` option to savers is especially useful. Many image have very large IPTC, ICC or XMP metadata items embedded in them, and removing these can give a large saving. For example: ```console $ vipsthumbnail 42-32157534.jpg $ ls -l tn_42-32157534.jpg -rw-r–r– 1 john john 6682 Nov 12 21:27 tn_42-32157534.jpg ``` `keep=none` almost halves the size of the thumbnail: ```console $ vipsthumbnail 42-32157534.jpg --path x.jpg[optimize_coding,keep=none] $ ls -l x.jpg -rw-r–r– 1 john john 3600 Nov 12 21:27 x.jpg ``` ## Colour management `vipsthumbnail` will optionally put images through LittleCMS for you. You can use this to move all thumbnails to the same colour space. All web browsers assume that images without an ICC profile are in sRGB colourspace, so if you move your thumbnails to sRGB, you can strip all the embedded profiles. This can save several kb per thumbnail. For example: ```console $ vipsthumbnail shark.jpg $ ls -l tn_shark.jpg -rw-r–r– 1 john john 7295 Nov  9 14:33 tn_shark.jpg ``` Now transform to sRGB and don't attach a profile (you can also use `keep=none`, though that will remove *all* metadata from the image): ```console $ vipsthumbnail shark.jpg --output-profile srgb --path tn_shark.jpg[profile=none] $ ls -l tn_shark.jpg -rw-r–r– 1 john john 4229 Nov  9 14:33 tn_shark.jpg ``` (You can use the filename of any RGB profile. The magic string `srgb` selects a high-quality sRGB profile that's built into libvips.) `tn_shark.jpg` will look identical to a user, but it's almost half the size. You can also specify a fallback input profile to use if the image has no embedded one. For example, perhaps you somehow know that a JPEG is in Adobe98 space, even though it has no embedded profile. ```console $ vipsthumbnail kgdev.jpg --input-profile /my/profiles/a98.icm ``` ## Final suggestion Putting all this together, I suggest this as a sensible set of options: ```console $ vipsthumbnail fred.jpg \ --size 128 \ --output-profile srgb \ --path tn_%s.jpg[optimize_coding,keep=none] ``` libvips-8.18.2/doc/vips.toml.in000066400000000000000000000044201516303661500163200ustar00rootroot00000000000000[library] name = "Vips" version = "@VIPS_VERSION@" browse_url = "https://github.com/libvips/libvips" repository_url = "https://github.com/libvips/libvips.git" website_url = "https://www.libvips.org" docs_url = "https://www.libvips.org/API/@VIPS_VERSION@/" authors = "libvips team and contributors" license = "LGPL-2.1-or-later" description = "The libvips image processing library" search_index = true # List the dependencies using their GIR namespace dependencies = ["GObject-2.0"] [dependencies."GObject-2.0"] name = "GObject" description = "The base type system library" docs_url = "https://docs.gtk.org/gobject/" related = ["GObject-2.0"] [related."GObject-2.0"] name = "GObject" description = "The base type system library" docs_url = "https://docs.gtk.org/gobject/" [theme] name = "basic" show_class_hierarchy = true show_index_summary = true [source-location] # The base URL for accessing a file in the repository base_url = "https://github.com/libvips/libvips/blob/master/" [extra] # The same order will be used when generating the index content_files = [ "using-the-cli.md", "using-from-c.md", "using-from-cplusplus.md", "making-image-pyramids.md", "multipage-and-animated-images.md", "uhdr.md", "using-vipsthumbnail.md", "using-threads.md", "developer-checklist.md", "examples.md", "function-list.md", "libvips-basic.md", "libvips-memory.md", "libvips-error.md", "libvips-vips.md", "libvips-arithmetic.md", "libvips-colour.md", "libvips-conversion.md", "libvips-convolution.md", "libvips-create.md", "libvips-draw.md", "libvips-freqfilt.md", "libvips-generate.md", "libvips-header.md", "libvips-histogram.md", "libvips-morphology.md", "libvips-mosaicing.md", "libvips-resample.md", "how-it-works.md", "how-it-opens-files.md", "file-format.md", "extending.md", "binding.md", "cite.md", ] content_images = [ "images/Combine.png", "images/interconvert.png", "images/Memtrace.png", "images/owl.jpg", "images/Sequence.png", "images/Sink.png", "images/tn_owl.jpg", "images/Vips-smp.png", ] content_base_url = "https://github.com/libvips/libvips/blob/master/doc/" urlmap_file = "urlmap.js" [check] ignore_deprecated = true # Hide the following types from the docs [[object]] name = "Token" hidden = true libvips-8.18.2/examples/000077500000000000000000000000001516303661500151065ustar00rootroot00000000000000libvips-8.18.2/examples/annotate-animated.c000066400000000000000000000044351516303661500206510ustar00rootroot00000000000000/* Draw something on every frame of an animated image. * * compile with: * * gcc -g -Wall annotate-animated.c `pkg-config vips --cflags --libs` * * run with: * * annotate-animated ~/pics/3198.gif[n=-1] x.webp */ #include static int annotate_image(VipsObject *context, VipsImage *image, VipsImage **out) { int page_height = vips_image_get_page_height(image); int n_pages = image->Ysize / page_height; VipsImage **overlay = (VipsImage **) vips_object_local_array(context, n_pages); VipsImage **page = (VipsImage **) vips_object_local_array(context, n_pages); VipsImage **annotated = (VipsImage **) vips_object_local_array(context, n_pages); /* Red as RGBA. */ double red[] = { 255, 0, 0, 255 }; double transparent[] = { 0, 0, 0, 0 }; int i; /* Split the image into frames. */ for (i = 0; i < n_pages; i++) if (vips_crop(image, &page[i], 0, page_height * i, image->Xsize, page_height, NULL)) return -1; /* Make an overlay ... a solid red square, with a transparent hole. */ if ( !(overlay[0] = vips_image_new_from_image(page[0], red, VIPS_NUMBER(red))) || vips_draw_rect(overlay[0], transparent, VIPS_NUMBER(transparent), 10, 10, overlay[0]->Xsize - 20, overlay[0]->Ysize - 20, "fill", TRUE, NULL)) return -1; /* Draw the overlay on every page. */ for (i = 0; i < n_pages; i++) if (vips_composite2(page[i], overlay[0], &annotated[i], VIPS_BLEND_MODE_OVER, NULL)) return -1; /* Reassemble the frames. */ if (vips_arrayjoin(annotated, out, n_pages, "across", 1, NULL)) return -1; return 0; } int main(int argc, char **argv) { VipsImage *image; VipsObject *context; VipsImage *x; if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s xxx.gif[n=-1] yyy.gif", argv[0]); if (!(image = vips_image_new_from_file(argv[1], "access", VIPS_ACCESS_SEQUENTIAL, NULL))) vips_error_exit(NULL); context = VIPS_OBJECT(vips_image_new()); if (annotate_image(context, image, &x)) { g_object_unref(image); g_object_unref(context); vips_error_exit(NULL); } g_object_unref(image); g_object_unref(context); image = x; if (vips_image_write_to_file(image, argv[2], NULL)) { g_object_unref(image); vips_error_exit(NULL); } g_object_unref(image); return 0; } libvips-8.18.2/examples/assemble-animated.c000066400000000000000000000025141516303661500206270ustar00rootroot00000000000000/* compile with * * gcc -g -Wall assemble-animated.c `pkg-config vips --cflags --libs` */ #include #include /* for libvips before 8.16, add this line: * G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsImage, g_object_unref) */ int main(int argc, char *argv[]) { if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc < 3) vips_error_exit("usage: %s outfile infile1 infile2 ...", argv[0]); /* Load a set of input files. */ g_autoptr(GPtrArray) frames = g_ptr_array_new_full(argc, g_object_unref); for (int i = 2; i < argc; i++) { VipsImage *frame; if (!(frame = vips_image_new_from_file(argv[i], "access", VIPS_ACCESS_SEQUENTIAL, NULL))) vips_error_exit(NULL); g_ptr_array_add(frames, frame); } /* Combine to form a vertical strip. */ g_autoptr(VipsImage) strip; if (vips_arrayjoin((VipsImage **) frames->pdata, &strip, frames->len, "across", 1, NULL)) vips_error_exit(NULL); /* Set the animation metadata. Delay times are in milliseconds. */ VipsImage *frame0 = VIPS_IMAGE(frames->pdata[0]); vips_image_set_int(strip, "page-height", frame0->Ysize); vips_image_set_int(strip, "loop", 10); int delays[] = { 300, 300, 300 }; vips_image_set_array_int(strip, "delay", delays, VIPS_NUMBER(delays)); if (vips_image_write_to_file(strip, argv[1], NULL)) vips_error_exit(NULL); return 0; } libvips-8.18.2/examples/meson.build000066400000000000000000000003721516303661500172520ustar00rootroot00000000000000examples = [ 'annotate-animated', 'new-from-buffer', 'progress-cancel', 'use-vips-func', 'my-add', ] foreach example : examples executable(example, example + '.c', dependencies: libvips_dep, ) endforeach libvips-8.18.2/examples/my-add.c000066400000000000000000000065611516303661500164350ustar00rootroot00000000000000/* A tiny example operation. This adds two uchar images to make a ushort * image. * * It only outputs the common pixels, so both inputs are cropped to the common * size in all three dimensions (width, height, bands). * * compile with * * gcc my-add.c -g -Wall `pkg-config vips --cflags --libs` * * (derived from code by @prasadbandodkar with thanks) */ #include #include static int my_add_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { // output area and output image VipsRect *r = &out_region->valid; VipsImage *out = out_region->im; // input regions and input images VipsRegion **ir = (VipsRegion **) vseq; VipsImage **inputs = (VipsImage **) a; // request matching part of input regions if (vips_reorder_prepare_many(out_region->im, ir, r)) return -1; for (int y = 0; y < r->height; y++) { unsigned char *p1 = VIPS_REGION_ADDR(ir[0], r->left, r->top + y); unsigned char *p2 = VIPS_REGION_ADDR(ir[1], r->left, r->top + y); unsigned short *q = (unsigned short *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); for (int x = 0; x < r->width; x++) { for (int b = 0; b < out->Bands; b++) q[b] = p1[b] + p2[b]; p1 += inputs[0]->Bands; p2 += inputs[1]->Bands; q += out->Bands; } } return 0; } static int my_add_operation(VipsImage *in1, VipsImage *in2, VipsImage **out_reference) { // we only work for uchar images if (vips_check_format("try", in1, VIPS_FORMAT_UCHAR) || vips_check_format("try", in2, VIPS_FORMAT_UCHAR)) return -1; // make the output image VipsImage *out = vips_image_new(); // make a self-freeing, null-terminated array of input images VipsImage **inputs = vips_allocate_input_array(out, in1, in2, NULL); if (vips_image_pipeline_array(out, VIPS_DEMAND_STYLE_THINSTRIP, inputs)) { g_object_unref(out); return -1; } // out will inherit all the properties of the inputs ... we must override // the ones we want to change (dimensions and format) out->Xsize = VIPS_MIN(in1->Xsize, in2->Xsize); out->Ysize = VIPS_MIN(in1->Ysize, in2->Ysize); out->Bands = VIPS_MIN(in1->Bands, in2->Bands); out->BandFmt = VIPS_FORMAT_USHORT; // generate pixels if (vips_image_generate(out, vips_start_many, my_add_generate, vips_stop_many, inputs, NULL)) { g_object_unref(out); return -1; } // success! set the output pointer *out_reference = out; return 0; } int main(int argc, char **argv) { // initialize vips if (VIPS_INIT(argv[0])) vips_error_exit("try"); if (argc != 4) vips_error_exit("usage: %s in1 in2 out", argv[0]); // open inputs ... sequential access is fine for our operation VipsImage *in1 = vips_image_new_from_file(argv[1], "access", VIPS_ACCESS_SEQUENTIAL, NULL); VipsImage *in2 = vips_image_new_from_file(argv[2], "access", VIPS_ACCESS_SEQUENTIAL, NULL); // call our operation VipsImage *out; if (my_add_operation(in1, in2, &out)) { g_object_unref(in1); g_object_unref(in2); vips_error_exit("try"); } // save the result if (vips_image_write_to_file(out, argv[3], NULL)) { g_object_unref(in1); g_object_unref(in2); g_object_unref(out); vips_error_exit("try"); } // release any resources g_object_unref(in1); g_object_unref(in2); g_object_unref(out); return 0; } libvips-8.18.2/examples/new-from-buffer.c000066400000000000000000000016131516303661500202540ustar00rootroot00000000000000/* Read and write formatted images to memory. * * Compile with: * * gcc -g -Wall new-from-buffer.c `pkg-config vips --cflags --libs` * */ #include int main(int argc, char **argv) { gchar *buf; gsize len; int i; if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 2) vips_error_exit("usage: %s FILENAME", argv[0]); if (!g_file_get_contents(argv[1], &buf, &len, NULL)) vips_error_exit(NULL); for (i = 0; i < 10; i++) { VipsImage *image; void *new_buf; size_t new_len; printf("loop %d ...\n", i); if (!(image = vips_image_new_from_buffer(buf, len, "", "access", VIPS_ACCESS_SEQUENTIAL, NULL))) vips_error_exit(NULL); if (vips_image_write_to_buffer(image, ".jpg", &new_buf, &new_len, "Q", 95, NULL)) vips_error_exit(NULL); g_object_unref(image); g_free(new_buf); } g_free(buf); vips_shutdown(); return 0; } libvips-8.18.2/examples/progress-cancel.c000066400000000000000000000032641516303661500203460ustar00rootroot00000000000000/* Show progress feedback and computation cancel. * * compile with * * gcc -g -Wall progress-cancel.c `pkg-config vips --cflags --libs` */ #include #include #include void preeval_callback(VipsImage *image, VipsProgress *progress, void *pdata) { printf("preeval_callback:\n"); } void eval_callback(VipsImage *image, VipsProgress *progress, void *pdata) { printf("eval_callback: percent = %d\n", progress->percent); if (progress->percent >= 25) { printf("calling vips_image_set_kill() ...\n"); vips_image_set_kill(image, TRUE); } } void posteval_callback(VipsImage *image, VipsProgress *progress, void *pdata) { printf("posteval_callback: finished in %.3gs\n", g_timer_elapsed(progress->start, NULL)); } int main(int argc, char **argv) { VipsImage *image; VipsImage *out; void *output; size_t output_length; if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s INPUT-FILE OUTPUT-FILE", argv[0]); if (!(image = vips_image_new_from_file(argv[1], "access", VIPS_ACCESS_SEQUENTIAL, NULL))) vips_error_exit(NULL); if (vips_resize(image, &out, 0.5, NULL)) vips_error_exit(NULL); vips_image_set_progress(out, TRUE); g_signal_connect(out, "preeval", G_CALLBACK(preeval_callback), NULL); g_signal_connect(out, "eval", G_CALLBACK(eval_callback), NULL); g_signal_connect(out, "posteval", G_CALLBACK(posteval_callback), NULL); output = NULL; if (vips_image_write_to_buffer(out, argv[2], &output, &output_length, NULL)) printf("error return from vips_image_write_to_buffer()\n"); g_object_unref(out); g_object_unref(image); if (output) g_free(output); vips_shutdown(); return 0; } libvips-8.18.2/examples/use-vips-func.c000066400000000000000000000016171516303661500177630ustar00rootroot00000000000000/* Example showing how to call a couple of vips functions using an input * image file and creating an output file * also gathers some info on the input image */ #include #include int main(int argc, char **argv) { VipsImage *in; double mean; VipsImage *out; if (VIPS_INIT(argv[0])) vips_error_exit(NULL); if (argc != 3) vips_error_exit("usage: %s infile outfile", argv[0]); if (!(in = vips_image_new_from_file(argv[1], NULL))) vips_error_exit(NULL); printf("image width = %d\n", vips_image_get_width(in)); if (vips_avg(in, &mean, NULL)) vips_error_exit(NULL); printf("mean pixel value = %g\n", mean); /* generate photo nexative - replace with other vips_ funcs */ if (vips_invert(in, &out, NULL)) vips_error_exit(NULL); g_object_unref(in); if (vips_image_write_to_file(out, argv[2], NULL)) vips_error_exit(NULL); g_object_unref(out); return 0; } libvips-8.18.2/examples/vipsprofile000077500000000000000000000341761516303661500174110ustar00rootroot00000000000000#!/usr/bin/env python3 # Analyses the file written by the --vips-profile option, calculates some # statistics, and draws a graph of evaluation. # # Run any vips program with the --vips-profile option to generate a file called # "vips-profile.txt". This contains timing information about CPU use, memory use # and thread synchronisation. # # Run vipsprofile to load this file, calculate some statistics, and draw a graph # of evaluation saved to vips-profile.svg. This analysis can help track down # performance problems. # # For example: # # $ vips sharpen ~/pics/k2.jpg x.jpg --vips-profile # recording profile in vips-profile.txt # $ vipsprofile # reading from vips-profile.txt # loaded 30001 events # total time = 0.082064 # name alive wait% work% unkn% mem peakm # worker 40 0.01 31.8 56.9 11.3 3.4 3.4 # worker 42 0.02 37.8 42.1 20.1 3.4 3.4 # ... # writing to vips-profile.svg import re import cairo from io import open class ReadFile: def __init__(self, filename): self.filename = filename def __enter__(self): self.f = open(self.filename, 'r', encoding='utf-8') self.lineno = 0 self.getnext(); return self def __exit__(self, type, value, traceback): self.f.close() def __bool__(self): return self.line != "" __nonzero__ = __bool__ def getnext(self): self.lineno += 1 self.line = self.f.readline() def read_times(rf): times = [] while True: match = re.match('[+-]?[0-9]+ ', rf.line) if not match: break times += [int(x) for x in re.split(' ', rf.line.rstrip())] rf.getnext() return times[::-1] class Thread: thread_number = 0 def __init__(self, thread_name): # no one cares about the thread address match = re.match(r'(.*) \(0x.*?\) (.*)', thread_name) if match: thread_name = match.group(1) + " " + match.group(2) self.thread_name = thread_name self.thread_number = Thread.thread_number self.all_events = [] self.workwait_events = [] self.memory_events = [] self.other_events = [] Thread.thread_number += 1 all_events = [] class Event: def __init__(self, thread, gate_location, gate_name, start, stop): self.thread = thread self.gate_location = gate_location self.gate_name = gate_name self.work = False self.wait = False self.memory = False if gate_location == "memory": self.memory = True elif re.match('.*work.*', gate_name): self.work = True elif re.match('.*wait.*', gate_name): self.wait = True if self.memory: self.start = start self.stop = start self.size = stop else: self.start = start self.stop = stop thread.all_events.append(self) all_events.append(self) if self.wait or self.work: thread.workwait_events.append(self) elif self.memory: thread.memory_events.append(self) else: thread.other_events.append(self) input_filename = 'vips-profile.txt' thread_id = 0 threads = [] n_events = 0 print('reading from', input_filename) with ReadFile(input_filename) as rf: while rf: if rf.line.rstrip() == "": rf.getnext() continue if rf.line[0] == "#": rf.getnext() continue match = re.match('thread: (.*)', rf.line) if not match: print('parse error line %d, expected "thread"' % rf.lineno) thread_name = match.group(1) + " " + str(thread_id) thread_id += 1 thread = Thread(thread_name) threads.append(thread) rf.getnext() while True: match = re.match('^gate: (.*?)(: (.*))?$', rf.line) if not match: break gate_location = match.group(1) gate_name = match.group(3) rf.getnext() match = re.match('start:', rf.line) if not match: continue rf.getnext() start = read_times(rf) match = re.match('stop:', rf.line) if not match: continue rf.getnext() stop = read_times(rf) if len(start) != len(stop): print('start and stop length mismatch') for a, b in zip(start, stop): Event(thread, gate_location, gate_name, a, b) n_events += 1 for thread in threads: thread.all_events.sort(key=lambda x: x.start) thread.workwait_events.sort(key=lambda x: x.start) thread.memory_events.sort(key=lambda x: x.start) thread.other_events.sort(key=lambda x: x.start) all_events.sort(key=lambda x: x.start) print(f'loaded {n_events} events') # move time axis to secs of computation ticks_per_sec = 1000000.0 first_time = all_events[0].start last_time = 0 for event in all_events: if event.start < first_time: first_time = event.start if event.stop > last_time: last_time = event.stop for event in all_events: event.start = (event.start - first_time) / ticks_per_sec event.stop = (event.stop - first_time) / ticks_per_sec last_time = (last_time - first_time) / ticks_per_sec first_time = 0 print(f'total time = {last_time}') # calculate some simple stats for thread in threads: thread.start = last_time thread.stop = 0 thread.wait = 0 thread.work = 0 thread.mem = 0 thread.peak_mem = 0 for event in thread.all_events: if event.start < thread.start: thread.start = event.start if event.stop > thread.stop: thread.stop = event.stop if event.wait: thread.wait += event.stop - event.start if event.work: thread.work += event.stop - event.start if event.memory: thread.mem += event.size if thread.mem > thread.peak_mem: thread.peak_mem = thread.mem thread.alive = thread.stop - thread.start # hide very short-lived threads thread.hide = thread.alive < 0.01 print('name alive wait% work% unkn% mem peakm') for thread in threads: if thread.hide: continue wait_percent = 100 * thread.wait / thread.alive work_percent = 100 * thread.work / thread.alive unkn_percent = 100 - 100 * (thread.work + thread.wait) / thread.alive print((f'{thread.thread_name:>13}\t{thread.alive:6.2f}\t' f'{wait_percent:>4.1f}\t{work_percent:>4.1f}\t{unkn_percent:>4.1f}\t' f'{thread.mem / (1024 * 1024):>4.1f}\t' f'{thread.peak_mem / (1024 * 1024):>4.1f}')) mem = 0 peak_mem = 0 for event in all_events: if event.memory: mem += event.size if mem > peak_mem: peak_mem = mem print(f'peak memory = {peak_mem / (1024 * 1024):.1f} MB') if mem != 0: print(f'leak! final memory = {mem / (1024 * 1024):.1f} MB') # does a list of events contain an overlap? # assume the list of events has been sorted by start time def events_overlap(events): for i in range(0, len(events) - 1): # we can't just test for stop1 > start2 since one (or both) events # might have duration zero event1 = events[i] event2 = events[i + 1] overlap_start = max(event1.start, event2.start) overlap_stop = min(event1.stop, event2.stop) if overlap_stop - overlap_start > 0: return True return False # do the events on two gates overlap? def gates_overlap(events, gate_name1, gate_name2): merged = [] for event in events: if event.gate_name == gate_name1 or event.gate_name == gate_name2: merged.append(event) merged.sort(key=lambda x: x.start) return events_overlap(merged) # show top 10 waits wait = {} for thread in threads: for event in thread.all_events: if event.wait: name = f'{event.gate_location}::{event.gate_name}' if name not in wait: wait[name] = 0 wait[name] += event.stop - event.start print('name wait') for [name, time] in sorted(wait.items(), reverse=True, key=lambda x: x[1])[:10]: print(f'{name:>35}\t{time:.2f}') # allocate a y position for each gate total_y = 0 for thread in threads: if thread.hide: continue thread.total_y = total_y gate_positions = {} # first pass .. move work and wait events to y == 0 if events_overlap(thread.workwait_events): print('gate overlap on thread', thread.thread_name) for i in range(0, len(thread.workwait_events) - 1): event1 = thread.workwait_events[i] event2 = thread.workwait_events[i + 1] overlap_start = max(event1.start, event2.start) overlap_stop = min(event1.stop, event2.stop) if overlap_stop - overlap_start > 0: print('overlap:') print('event', event1.gate_location, event1.gate_name, end=' ') print('starts at', event1.start, 'stops at', event1.stop) print('event', event2.gate_location, event2.gate_name, end=' ') print('starts at', event2.start, 'stops at', event2.stop) for event in thread.workwait_events: gate_positions[event.gate_name] = 0 event.y = 0 event.total_y = total_y for event in thread.memory_events: gate_positions[event.gate_name] = 0 event.y = 0 event.total_y = total_y # second pass: move all other events to non-overlapping ys y = 1 for event in thread.other_events: if not event.gate_name in gate_positions: # look at all the ys we've allocated previously and see if we can # add this gate to one of them for gate_y in range(1, y): found_overlap = False for gate_name in gate_positions: if gate_positions[gate_name] != gate_y: continue if gates_overlap(thread.other_events, event.gate_name, gate_name): found_overlap = True break if not found_overlap: gate_positions[event.gate_name] = gate_y break # failure? add a new y if not event.gate_name in gate_positions: gate_positions[event.gate_name] = y y += 1 event.y = gate_positions[event.gate_name] # third pass: flip the order of the ys to get the lowest-level ones at the # top, next to the wait/work line for event in thread.other_events: event.y = y - event.y event.total_y = total_y + event.y total_y += y PIXELS_PER_SECOND = 1000 PIXELS_PER_GATE = 20 LEFT_BORDER = 130 BAR_HEIGHT = 5 MEM_HEIGHT = 100 WIDTH = int(LEFT_BORDER + last_time * PIXELS_PER_SECOND) + 20 HEIGHT = int(total_y * PIXELS_PER_GATE) + MEM_HEIGHT + 30 output_filename = "vips-profile.svg" print('writing to', output_filename) surface = cairo.SVGSurface(output_filename, WIDTH, HEIGHT) ctx = cairo.Context(surface) ctx.select_font_face('Sans') ctx.set_font_size(15) ctx.rectangle(0, 0, WIDTH, HEIGHT) ctx.set_source_rgba(0.0, 0.0, 0.3, 1.0) ctx.fill() def draw_event(ctx, event): left = event.start * PIXELS_PER_SECOND + LEFT_BORDER top = event.total_y * PIXELS_PER_GATE + BAR_HEIGHT // 2 width = (event.stop - event.start) * PIXELS_PER_SECOND height = BAR_HEIGHT if event.memory: width = 1 height /= 2 top += BAR_HEIGHT ctx.rectangle(left, top, width, height) if event.wait: ctx.set_source_rgb(0.9, 0.1, 0.1) elif event.work: ctx.set_source_rgb(0.1, 0.9, 0.1) elif event.memory: ctx.set_source_rgb(1.0, 1.0, 1.0) else: ctx.set_source_rgb(0.1, 0.1, 0.9) ctx.fill() if not event.wait and not event.work and not event.memory: xbearing, ybearing, twidth, theight, xadvance, yadvance = \ ctx.text_extents(event.gate_name) ctx.move_to(left + width // 2 - twidth // 2, top + 3 * BAR_HEIGHT) ctx.set_source_rgb(1.00, 0.83, 0.00) ctx.show_text(event.gate_name) for thread in threads: if thread.hide: continue ctx.rectangle(0, thread.total_y * PIXELS_PER_GATE, WIDTH, 1) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.fill() xbearing, ybearing, twidth, theight, xadvance, yadvance = \ ctx.text_extents(thread.thread_name) ctx.move_to(0, theight + thread.total_y * PIXELS_PER_GATE + BAR_HEIGHT // 2) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.show_text(thread.thread_name) for event in thread.all_events: draw_event(ctx, event) memory_y = total_y * PIXELS_PER_GATE label = "memory" xbearing, ybearing, twidth, theight, xadvance, yadvance = \ ctx.text_extents(label) ctx.move_to(0, memory_y + theight + 8) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.show_text(label) mem = 0 ctx.move_to(LEFT_BORDER, memory_y + MEM_HEIGHT) for event in all_events: if event.memory: mem += event.size left = LEFT_BORDER + event.start * PIXELS_PER_SECOND top = memory_y + MEM_HEIGHT - (MEM_HEIGHT * mem / peak_mem) ctx.line_to(left, top) ctx.set_line_width(1) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.stroke() axis_y = total_y * PIXELS_PER_GATE + MEM_HEIGHT ctx.rectangle(LEFT_BORDER, axis_y, last_time * PIXELS_PER_SECOND, 1) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.fill() label = "time" xbearing, ybearing, twidth, theight, xadvance, yadvance = \ ctx.text_extents(label) ctx.move_to(0, axis_y + theight + 8) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.show_text(label) for t in range(0, int(last_time * PIXELS_PER_SECOND), PIXELS_PER_SECOND // 10): left = t + LEFT_BORDER top = axis_y ctx.rectangle(left, top, 1, 5) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.fill() label = str(t / PIXELS_PER_SECOND) xbearing, ybearing, twidth, theight, xadvance, yadvance = \ ctx.text_extents(label) ctx.move_to(left - twidth // 2, top + theight + 8) ctx.set_source_rgb(1.00, 1.00, 1.00) ctx.show_text(label) surface.finish() libvips-8.18.2/fuzz/000077500000000000000000000000001516303661500142665ustar00rootroot00000000000000libvips-8.18.2/fuzz/StandaloneFuzzTargetMain.c000066400000000000000000000033211516303661500213540ustar00rootroot00000000000000/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // This main() function can be linked to a fuzz target (i.e. a library // that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize()) // instead of libFuzzer. This main() function will not perform any fuzzing // but will simply feed all input files one by one to the fuzz target. // // Use this file to provide reproducers for bugs when linking against libFuzzer // or other fuzzing engine is undesirable. //===----------------------------------------------------------------------===*/ #include #include #include extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); __attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv); int main(int argc, char **argv) { fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1); if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv); for (int i = 1; i < argc; i++) { fprintf(stderr, "Running: %s\n", argv[i]); FILE *f = fopen(argv[i], "r"); assert(f); fseek(f, 0, SEEK_END); size_t len = ftell(f); fseek(f, 0, SEEK_SET); unsigned char *buf = (unsigned char*)malloc(len); size_t n_read = fread(buf, 1, len, f); fclose(f); assert(n_read == len); LLVMFuzzerTestOneInput(buf, len); free(buf); fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read); } } libvips-8.18.2/fuzz/common_fuzzer_corpus/000077500000000000000000000000001516303661500205565ustar00rootroot00000000000000libvips-8.18.2/fuzz/common_fuzzer_corpus/.keep000066400000000000000000000000001516303661500214710ustar00rootroot00000000000000libvips-8.18.2/fuzz/common_fuzzer_corpus/generic_buffer_with_args_avif_to_avif000066400000000000000000000016031516303661500302310ustar00rootroot00000000000000[thumbnail=true] .avif[encoder=aom,subsample-mode=on,compression=av1,effort=3,lossless=false,bitdepth=16,Q=32] ftypavifavifmif1miafmeta!hdlrpictpitmFilocD@NUMiinfinfeav01infeav01infeExifiprpipcocolrnclx av1Cispepixi8auxCurn:mpeg:mpegB:cicp:systems:auxiliary:alpha av1C ispepixiipma(irefauxlcdsc*mdat  T2  e  @@Ѐ2?EpBA3-4Ae5#إQ H|f=coNB$Yt"CNExifII*V^(if8c8c02100100 libvips-8.18.2/fuzz/common_fuzzer_corpus/generic_buffer_with_args_gif_to_gif_all_pages000066400000000000000000000014611516303661500317020ustar00rootroot00000000000000[n=-1] .gif[dither=1,effort=8,bitdepth=4,interframe-maxerror=8,reuse=true,interpalette-maxerror=32,interlace=false] GIF89a    ! NETSCAPE2.0!, $ @ FtHX)]^x/libvips-8.18.2/fuzz/common_fuzzer_corpus/generic_buffer_with_args_leak_webpsave000066400000000000000000000014701516303661500304070ustar00rootroot00000000000000[n=-1] .webp[Q=75,lossless=true,smart_subsample=false,near_lossless=true,alpha_q=50,effort=3,min_size=true,kmin=2,kmax=4] GIF89a    ! NETSCAPE2.0!, $ @ FtH> endobj 2 0 obj << /MediaBox [0 0 595 842] /Kids [3 0 R] /Count 1 /Type /Pages >> endobj 3 0 obj << /Parent 2 0 R /MediaBox [0 0 595 842] /Type /Page >> endobj xref 0 4 0000000000 65535 f 0000000015 00000 n 0000000066 00000 n 0000000149 00000 n trailer << /Root 1 0 R /Size 4 >> startxref 221 %%EOF libvips-8.18.2/fuzz/common_fuzzer_corpus/generic_buffer_with_args_webp_to_tiff000066400000000000000000000012261516303661500302450ustar00rootroot00000000000000[scale=2] .tiff[compression=lzw,Q=50,predictor=float,tile=false,tile-width=16,tile-height=16,pyramid=true,miniswhite=false,bitdepth=4,resunit=inch,xres=10,yres=10,bigtiff=true,properties=false,region-shrink=min,level=22,depth=one,subifd=true,premultiply=true] RIFFWEBPVP8X VP8 p*>:G0 f2p"5Df#?k RACLp {7>Y[LfWf-(\PP܃c*;8I@LςTpi)T X8փ+9wzzT;O̒EXIFExifII*V^(if8c8c02100100libvips-8.18.2/fuzz/common_fuzzer_corpus/jpegsave_buffer_fuzzer-5658586599915520000066400000000000000000000002521516303661500270470ustar00rootroot00000000000000II*0? P           libvips-8.18.2/fuzz/common_fuzzer_corpus/jpegsave_buffer_fuzzer-5673786296238080000066400000000000000000000000541516303661500270370ustar00rootroot00000000000000  !  A http libvips-8.18.2/fuzz/common_fuzzer_corpus/jpegsave_buffer_fuzzer-5759265708441600000066400000000000000000000004411516303661500270240ustar00rootroot00000000000000ExifMM*b1 i cs  ;"5  ;"cs  ;"5 libvips-8.18.2/fuzz/common_fuzzer_corpus/jpegsave_file_fuzzer-5662041322291200000066400000000000000000000077561516303661500264620ustar00rootroot00000000000000   MatrRAP"A%Q 65535xFIF׀JFID׀ MatrRAP"A%Q 65535x MatrRAP"A%Q 65535xRAP"A%Q 65535x@?3aJ{FIF׀JFID׀ MatrRAP"A%Q 65535x MatrRAP"A%Q 65535xFIF׀JFID׀ MatrRAP"A%Q 65535x MatrRAP"A%Q 65535xlibvips-8.18.2/fuzz/common_fuzzer_corpus/pngsave_buffer_fuzzer-5078454764044288000066400000000000000000000001071516303661500266710ustar00rootroot00000000000000PNG  IHDR  iTXt IDAT(@fIDATlibvips-8.18.2/fuzz/common_fuzzer_corpus/sharpen_fuzzer-5203581631725568000066400000000000000000000000151516303661500253220ustar00rootroot00000000000000GIF8 =libvips-8.18.2/fuzz/common_fuzzer_corpus/sharpen_fuzzer-5678720198639616000066400000000000000000000004621516303661500253510ustar00rootroot00000000000000II*      R  libvips-8.18.2/fuzz/common_fuzzer_corpus/sharpen_fuzzer-5691855517253632000066400000000000000000000031151516303661500253340ustar00rootroot00000000000000II* I R         libvips-8.18.2/fuzz/common_fuzzer_corpus/sharpen_fuzzer-5806172036399104000066400000000000000000035110531516303661500253330ustar00rootroot00000000000000GIF82,-)Z,-)Z,-)Z,,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Rg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-Str)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)ZB)Zg )Z,-)Z@)^,-)Z,-)Z?--)Z,-)Z,-)Z,-)Z,-@)^,-SriZ,-)Z,-Z,-@)^,-SriZ,-)Z,-Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-Str)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-Str)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)ZB)Zg )Z,-)Z@)^,-)Z,-)Z?--)Z,-)Z,-)Z,-)Z,-@)^,-SriZ,-)Z,-Z,-@)^,-SriZ,-)Z,-Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-Str)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)ZB)Zg )Z,-)Z@)^,-)Z,-)Z?--)Z,-)Z,-)Z,-)Z,-@)^,-SriZ,-)Z,-Z,-@)^,-SriZ,-)Z,-Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)*Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z@,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)ZB)Zg )Z,-)Z@)^,-)Z,-)Z?--)Z,-)Z,-)Z,-)Z,-@)^,-SriZ,-)Z,-Z,-@)^,-SriZ,-)Z,-Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg )Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)*Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z@,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)Z,-)Z,-)Z,-@)^,-StriZ,-)Z)Zg ))Z,-)Z,-)ZB)Zg )Z,-)Z@)^,-)Z,-)Z?--)Z,-)Z,-)Z,-)Z,-@)^,-SriZ,-)Z,-Z,-@)^,-SriZ,-)Z,-Z,- )Z,-)Z,-@)^,-StriZ,-)Z,-Z,-)Zg )Z,-)Z,-)Z?-libvips-8.18.2/fuzz/common_fuzzer_corpus/smartcrop_fuzzer-5687924892368896000066400000000000000000000001551516303661500257420ustar00rootroot00000000000000GIF8 ! ,  libvips-8.18.2/fuzz/common_fuzzer_corpus/thumbnail_fuzzer-5111890150424576000066400000000000000000000000411516303661500256340ustar00rootroot00000000000000#?RADIANCE X1Y5 libvips-8.18.2/fuzz/common_fuzzer_corpus/thumbnail_fuzzer-5676300823429120000066400000000000000000000005721516303661500256440ustar00rootroot00000000000000II*       libvips-8.18.2/fuzz/common_fuzzer_corpus/thumbnail_fuzzer-5718717719117824000066400000000000000000000020321516303661500256570ustar00rootroot00000000000000II* J Q       S libvips-8.18.2/fuzz/common_fuzzer_corpus/thumbnail_fuzzer-5741423734816768000066400000000000000000000040051516303661500256610ustar00rootroot00000000000000II*       S k libvips-8.18.2/fuzz/common_fuzzer_corpus/webpsave_buffer_fuzzer-5207224829345792000066400000000000000000000002461516303661500270410ustar00rootroot00000000000000RIFFWEBPVP8L/0? pڶ\ /* #define DEBUG */ #ifndef SAVE_SUFFIX #define SAVE_SUFFIX ".jpg" #endif extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); #ifdef DEBUG printf("available suffixes:\n"); GSList *suffixes = nullptr; char **array = vips_foreign_get_suffixes(); for (int i = 0; array[i] != nullptr; i++) { if (!g_slist_find_custom(suffixes, array[i], (GCompareFunc) g_strcmp0)) { printf("%s\n", array[i]); suffixes = g_slist_append(suffixes, g_strdup(array[i])); } g_free(array[i]); } g_free(array); g_slist_free_full(suffixes, g_free); #endif return 0; } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { VipsImage *image; void *buf; size_t len; if (!(image = vips_image_new_from_buffer(data, size, "", nullptr))) return 0; if (image->Xsize > 100 || image->Ysize > 100 || image->Bands > 4) { g_object_unref(image); return 0; } if (vips_image_write_to_buffer(image, SAVE_SUFFIX, &buf, &len, nullptr)) { g_object_unref(image); return 0; } g_free(buf); g_object_unref(image); return 0; } libvips-8.18.2/fuzz/generic_buffer_with_args_fuzzer.cc000066400000000000000000000027001516303661500232150ustar00rootroot00000000000000#include #define MAX_ARG_LEN 4096 // =VIPS_PATH_MAX extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); return 0; } static char * ExtractLine(const guint8 *data, size_t size, size_t *n) { const guint8 *end; end = static_cast( memchr(data, '\n', VIPS_MIN(size, MAX_ARG_LEN))); if (end == nullptr) return nullptr; *n = end - data; return g_strndup(reinterpret_cast(data), *n); } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { VipsImage *image; void *buf; char *option_string, *suffix; size_t len, n; option_string = ExtractLine(data, size, &n); if (option_string == nullptr) return 0; data += n + 1; size -= n + 1; suffix = ExtractLine(data, size, &n); if (suffix == nullptr) { g_free(option_string); return 0; } data += n + 1; size -= n + 1; if (!(image = vips_image_new_from_buffer(data, size, option_string, nullptr))) { g_free(option_string); g_free(suffix); return 0; } // We're done with option_string, free early. g_free(option_string); if (image->Xsize > 100 || image->Ysize > 100 || image->Bands > 4) { g_object_unref(image); g_free(suffix); return 0; } if (vips_image_write_to_buffer(image, suffix, &buf, &len, nullptr)) { g_object_unref(image); g_free(suffix); return 0; } g_free(buf); g_free(suffix); g_object_unref(image); return 0; } libvips-8.18.2/fuzz/jpegsave_file_fuzzer.cc000066400000000000000000000017071516303661500210120ustar00rootroot00000000000000#include extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); return 0; } static int test_one_file(const char *name) { VipsImage *image; void *buf; size_t len; if (!(image = vips_image_new_from_file(name, "access", VIPS_ACCESS_SEQUENTIAL, nullptr))) return 0; if (image->Xsize > 100 || image->Ysize > 100 || image->Bands > 4) { g_object_unref(image); return 0; } if (vips_jpegsave_buffer(image, &buf, &len, nullptr)) { g_object_unref(image); return 0; } g_free(buf); g_object_unref(image); return 0; } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { char *name; if (!(name = vips__temp_name("%s"))) return 0; if (!g_file_set_contents(name, (const char *) data, size, nullptr) || test_one_file(name)) { g_unlink(name); g_free(name); return 0; } g_unlink(name); g_free(name); return 0; } libvips-8.18.2/fuzz/meson.build000066400000000000000000000064401516303661500164340ustar00rootroot00000000000000fuzz_deps = libvips_deps fuzz_ldflags = [] if get_option('fuzzer_ldflags') != '' fuzz_ldflags += [get_option('fuzzer_ldflags')] endif if fuzzing_engine == 'none' standalone_engine = static_library('standalone_engine', 'StandaloneFuzzTargetMain.c' ) fuzz_deps += declare_dependency(link_with: standalone_engine) elif fuzzing_engine == 'libfuzzer' fuzz_ldflags += ['-fsanitize=fuzzer'] endif fuzz_progs = [ 'sharpen_fuzzer', 'thumbnail_fuzzer', 'smartcrop_fuzzer', 'mosaic_fuzzer' ] if libjpeg_dep.found() fuzz_progs += ['jpegsave_file_fuzzer'] endif fuzz_execs = [] foreach fuzz_prog : fuzz_progs fuzz_execs += executable(fuzz_prog, fuzz_prog + '.cc', dependencies: [libvips_dep, fuzz_deps], link_args: fuzz_ldflags ) endforeach fuzz_save_buffer_progs = { 'csvsave': '.csv', 'matrixsave': '.mat', 'rawsave': '.raw', # vipssave requires a associated filename # https://github.com/libvips/libvips/discussions/2051 # 'vipssave': '.vips', } if get_option('radiance') fuzz_save_buffer_progs += {'radsave': '.hdr'} endif if get_option('ppm') fuzz_save_buffer_progs += {'ppmsave': '.ppm'} endif if libjpeg_dep.found() fuzz_save_buffer_progs += {'jpegsave': '.jpg'} endif if libjxl_found fuzz_save_buffer_progs += {'jxlsave': '.jxl'} endif if libopenjp2_dep.found() fuzz_save_buffer_progs += {'jp2ksave': '.jp2'} endif if png_package.found() fuzz_save_buffer_progs += {'pngsave': '.png'} endif if libtiff_dep.found() fuzz_save_buffer_progs += {'tiffsave': '.tiff'} endif if libarchive_dep.found() fuzz_save_buffer_progs += {'dzsave': '.dz'} endif if libheif_dep.found() fuzz_save_buffer_progs += {'heifsave': '.avif'} endif if libwebp_dep.found() fuzz_save_buffer_progs += {'webpsave': '.webp'} endif # niftisave and fitssave is missing a buffer saver # https://github.com/libvips/libvips/discussions/2051 # if libnifti_found # fuzz_save_buffer_progs += {'niftisave': '.nii'} # endif # if cfitsio_dep.found() # fuzz_save_buffer_progs += {'fitssave': '.fits'} # endif if cgif_dep.found() fuzz_save_buffer_progs += {'gifsave': '.gif'} endif if magick_found and 'save' in get_option('magick-features') fuzz_save_buffer_progs += {'magicksave': '.bmp'} endif foreach fuzz_basename, fuzz_save_suffix : fuzz_save_buffer_progs fuzz_execs += executable(fuzz_basename + '_buffer_fuzzer', 'generic_buffer_fuzzer.cc', dependencies: [libvips_dep, fuzz_deps], link_args: fuzz_ldflags, cpp_args: '-DSAVE_SUFFIX="@0@"'.format(fuzz_save_suffix) ) endforeach fuzz_execs += executable('generic_buffer_with_args_fuzzer', 'generic_buffer_with_args_fuzzer.cc', dependencies: [libvips_dep, fuzz_deps], link_args: fuzz_ldflags, ) # If the fuzzing engine is not OSS-Fuzz, build the unit tests to be run on CI if fuzzing_engine != 'oss-fuzz' test_fuzz = configure_file( input: 'test_fuzz.sh', output: 'test_fuzz.sh', copy: true, ) test( 'fuzz', test_fuzz, workdir: meson.current_build_dir(), depends: [ fuzz_execs, ], # Increase the timeout as running the tests with sanitizers # enabled could be slower than the default 30 seconds. timeout: 120, ) endif libvips-8.18.2/fuzz/mosaic_fuzzer.cc000066400000000000000000000026161516303661500174620ustar00rootroot00000000000000#include #include #ifdef __GNUC__ #define PACK(...) __VA_ARGS__ __attribute__((__packed__)) #elif defined(_MSC_VER) #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop)) #else #define PACK(...) __VA_ARGS__ #endif PACK(struct mosaic_opt { guint8 dir : 1; guint16 xref; guint16 yref; guint16 xsec; guint16 ysec; }); extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); return 0; } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { VipsImage *ref, *sec, *out; mosaic_opt opt = {}; double d; if (size < sizeof(mosaic_opt)) return 0; /* The tail of `data` is treated as mosaic configuration */ size -= sizeof(mosaic_opt); memcpy(&opt, data + size, sizeof(mosaic_opt)); /* Remainder of input is the image */ if (!(ref = vips_image_new_from_buffer(data, size, "", nullptr))) return 0; if (ref->Xsize > 100 || ref->Ysize > 100 || ref->Bands > 4) { g_object_unref(ref); return 0; } if (vips_rot180(ref, &sec, nullptr)) { g_object_unref(ref); return 0; } if (vips_mosaic(ref, sec, &out, (VipsDirection) opt.dir, opt.xref, opt.yref, opt.xsec, opt.ysec, nullptr)) { g_object_unref(sec); g_object_unref(ref); return 0; } vips_max(out, &d, nullptr); g_object_unref(out); g_object_unref(sec); g_object_unref(ref); return 0; } libvips-8.18.2/fuzz/oss_fuzz_build.sh000077500000000000000000000154761516303661500177030ustar00rootroot00000000000000#!/bin/bash -eu export PKG_CONFIG="pkg-config --static" export PKG_CONFIG_PATH="$WORK/lib/pkgconfig" export CPPFLAGS="-I$WORK/include" export LDFLAGS="-L$WORK/lib" # `-fuse-ld=gold` can't be passed via `CFLAGS` and `CXXFLAGS` as Meson # injects `-Werror=ignored-optimization-argument` during compile tests. # https://github.com/google/oss-fuzz/issues/12167 # https://github.com/mesonbuild/meson/issues/6377#issuecomment-575977919 if [[ "$CFLAGS" == *"-fuse-ld=gold"* ]]; then export CFLAGS="${CFLAGS//-fuse-ld=gold/}" export CC_LD=gold fi if [[ "$CXXFLAGS" == *"-fuse-ld=gold"* ]]; then export CXXFLAGS="${CXXFLAGS//-fuse-ld=gold/}" export CXX_LD=gold fi # Run as many parallel jobs as there are available CPU cores export MAKEFLAGS="-j$(nproc)" # libz pushd $SRC/zlib ./configure --static --prefix=$WORK make install popd # libexif pushd $SRC/libexif autoreconf -fi ./configure \ --enable-static \ --disable-shared \ --disable-nls \ --disable-docs \ --disable-dependency-tracking \ --prefix=$WORK make install doc_DATA= popd # lcms pushd $SRC/lcms meson setup build --prefix=$WORK --libdir=lib --default-library=static --buildtype=debugoptimized \ -Dtests=disabled -Djpeg=disabled -Dtiff=disabled meson install -C build --tag devel popd # aom pushd $SRC/aom mkdir -p build/linux cd build/linux extra_libaom_flags='-DAOM_MAX_ALLOCABLE_MEMORY=536870912 -DDO_RANGE_CHECK_CLAMP=1' cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=$WORK \ -DCONFIG_PIC=1 \ -DENABLE_EXAMPLES=0 \ -DENABLE_DOCS=0 \ -DENABLE_TESTS=0 \ -DENABLE_TOOLS=0 \ -DCONFIG_SIZE_LIMIT=1 \ -DDECODE_HEIGHT_LIMIT=12288 \ -DDECODE_WIDTH_LIMIT=12288 \ -DAOM_EXTRA_C_FLAGS="$extra_libaom_flags" \ -DAOM_EXTRA_CXX_FLAGS="$extra_libaom_flags" \ -DAOM_TARGET_CPU=generic \ ../../ cmake --build . --target install popd # libheif pushd $SRC/libheif cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=$WORK \ -DBUILD_SHARED_LIBS=FALSE \ -DBUILD_TESTING=FALSE \ -DWITH_EXAMPLES=FALSE \ -DENABLE_PLUGIN_LOADING=FALSE \ . cmake --build . --target install popd # libjpeg-turbo pushd $SRC/libjpeg-turbo cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=$WORK \ -DENABLE_STATIC=TRUE \ -DENABLE_SHARED=FALSE \ -DWITH_TURBOJPEG=FALSE \ -DWITH_TOOLS=FALSE \ -DWITH_TESTS=FALSE \ . cmake --build . --target install popd # libpng pushd $SRC/libpng autoreconf -fi ./configure \ --prefix=$WORK \ --disable-shared \ --disable-tools \ --without-binconfigs \ --disable-unversioned-libpng-config \ --disable-dependency-tracking make install dist_man_MANS= popd # libwebp pushd $SRC/libwebp autoreconf -fi ./configure \ --enable-libwebpdemux \ --enable-libwebpmux \ --disable-shared \ --disable-jpeg \ --disable-tiff \ --disable-gif \ --disable-wic \ --disable-threading \ --disable-dependency-tracking \ --prefix=$WORK make install bin_PROGRAMS= noinst_PROGRAMS= man_MANS= popd # libtiff ... a bug in libtiff master as of 20 Nov 2019 means we have to # explicitly disable lzma pushd $SRC/libtiff autoreconf -fi ./configure \ --disable-tools \ --disable-tests \ --disable-contrib \ --disable-docs \ --disable-lzma \ --disable-shared \ --disable-dependency-tracking \ --prefix=$WORK make install noinst_PROGRAMS= dist_doc_DATA= popd # libimagequant pushd $SRC/libimagequant meson setup build --prefix=$WORK --libdir=lib --default-library=static --buildtype=debugoptimized meson install -C build --tag devel popd # cgif pushd $SRC/cgif meson setup build --prefix=$WORK --libdir=lib --default-library=static --buildtype=debugoptimized \ -Dexamples=false -Dtests=false meson install -C build --tag devel popd # pdfium doesn't need fuzzing, but we want to fuzz the libvips/pdfium link pushd $SRC/pdfium-latest cp lib/* $WORK/lib cp -r include/* $WORK/include popd # make a pdfium.pc that libvips can use ... the version number just needs to # be higher than 4200 to satisfy libvips cat > $WORK/lib/pkgconfig/pdfium.pc << EOF prefix=$WORK libdir=\${prefix}/lib includedir=\${prefix}/include Name: pdfium Description: pdfium Version: 4901 Libs: -L\${libdir} -lpdfium Cflags: -I\${includedir} EOF # highway pushd $SRC/highway cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=$WORK \ -DBUILD_SHARED_LIBS=0 \ -DBUILD_TESTING=0 \ -DHWY_ENABLE_CONTRIB=0 \ -DHWY_ENABLE_EXAMPLES=0 \ -DHWY_ENABLE_TESTS=0 \ . cmake --build . --target install popd # libjxl pushd $SRC/libjxl # libvips always decodes to pixels, so build with # -DJPEGXL_ENABLE_TRANSCODE_JPEG=FALSE cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=$WORK \ -DCMAKE_FIND_ROOT_PATH=$WORK \ -DBUILD_SHARED_LIBS=FALSE \ -DBUILD_TESTING=FALSE \ -DJPEGXL_ENABLE_BENCHMARK=FALSE \ -DJPEGXL_ENABLE_EXAMPLES=FALSE \ -DJPEGXL_ENABLE_FUZZERS=FALSE \ -DJPEGXL_ENABLE_JPEGLI=FALSE \ -DJPEGXL_ENABLE_MANPAGES=FALSE \ -DJPEGXL_ENABLE_SJPEG=FALSE \ -DJPEGXL_ENABLE_SKCMS=FALSE \ -DJPEGXL_ENABLE_TOOLS=FALSE \ -DJPEGXL_ENABLE_TRANSCODE_JPEG=FALSE \ -DJPEGXL_FORCE_SYSTEM_BROTLI=TRUE \ -DJPEGXL_FORCE_SYSTEM_HWY=TRUE \ -DJPEGXL_FORCE_SYSTEM_LCMS2=TRUE \ . cmake --build . --target install popd # libultrahdr pushd $SRC/libultrahdr cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=$WORK \ -DBUILD_SHARED_LIBS=FALSE \ -DUHDR_BUILD_EXAMPLES=FALSE \ -DUHDR_MAX_DIMENSION=65500 \ . cmake --build . --target install popd # libvips # Disable building man pages, gettext po files, tools, and tests sed -i "/subdir('man')/{N;N;N;d;}" meson.build meson setup build --prefix=$WORK --libdir=lib --prefer-static --default-library=static --buildtype=debugoptimized \ -Dbackend_max_links=4 -Ddeprecated=false -Dexamples=false -Dcplusplus=false -Dmodules=disabled \ -Dfuzzing_engine=oss-fuzz -Dfuzzer_ldflags="$LIB_FUZZING_ENGINE" \ -Dcpp_link_args="$LDFLAGS -Wl,-rpath=\$ORIGIN/lib" meson install -C build --tag devel # Copy fuzz executables to $OUT find build/fuzz -maxdepth 1 -executable -type f -exec cp -v '{}' $OUT \; # All shared libraries needed during fuzz target execution should be inside the $OUT/lib directory mkdir -p $OUT/lib cp $WORK/lib/*.so $OUT/lib # Merge the seed corpus in a single directory, exclude files larger than 4k mkdir -p fuzz/corpus find \ $SRC/afl-testcases/{gif*,jpeg*,png,tiff,webp}/full/images \ fuzz/*_fuzzer_corpus \ test/test-suite/images \ -type f -size -4k \ -exec bash -c 'hash=($(sha1sum {})); mv {} fuzz/corpus/$hash' \; zip -jrq $OUT/seed_corpus.zip fuzz/corpus # Link corpus for fuzzer in $OUT/*_fuzzer; do target=$(basename "$fuzzer") ln -sf "seed_corpus.zip" "$OUT/${target}_seed_corpus.zip" done # Copy options and dictionary files to $OUT find fuzz -name '*_fuzzer.dict' -exec cp -v '{}' $OUT \; find fuzz -name '*_fuzzer.options' -exec cp -v '{}' $OUT \; libvips-8.18.2/fuzz/sharpen_fuzzer.cc000066400000000000000000000012071516303661500176420ustar00rootroot00000000000000#include extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); return 0; } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { VipsImage *image, *out; double d; if (!(image = vips_image_new_from_buffer(data, size, "", nullptr))) return 0; if (image->Xsize > 100 || image->Ysize > 100 || image->Bands > 4) { g_object_unref(image); return 0; } if (vips_sharpen(image, &out, nullptr)) { g_object_unref(image); return 0; } vips_avg(out, &d, nullptr); g_object_unref(out); g_object_unref(image); return 0; } libvips-8.18.2/fuzz/smartcrop_fuzzer.cc000066400000000000000000000012211516303661500202100ustar00rootroot00000000000000#include extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); return 0; } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { VipsImage *image, *out; double d; if (!(image = vips_image_new_from_buffer(data, size, "", nullptr))) return 0; if (image->Xsize > 100 || image->Ysize > 100 || image->Bands > 4) { g_object_unref(image); return 0; } if (vips_smartcrop(image, &out, 32, 32, nullptr)) { g_object_unref(image); return 0; } vips_min(out, &d, nullptr); g_object_unref(out); g_object_unref(image); return 0; } libvips-8.18.2/fuzz/test_fuzz.sh000077500000000000000000000005531516303661500166650ustar00rootroot00000000000000#!/bin/sh #set -x set -e . ../test/variables.sh # Hide all warning messages from vips. export VIPS_WARNING=0 ret=0 for fuzzer in *_fuzzer; do for file in $top_srcdir/fuzz/common_fuzzer_corpus/*; do exit_code=0 ./$fuzzer $file || exit_code=$? if [ $exit_code -ne 0 ]; then echo FAIL $fuzzer $file ret=1 fi done done exit $ret libvips-8.18.2/fuzz/thumbnail_fuzzer.cc000066400000000000000000000012231516303661500201630ustar00rootroot00000000000000#include extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { if (VIPS_INIT(*argv[0])) return -1; vips_concurrency_set(1); return 0; } extern "C" int LLVMFuzzerTestOneInput(const guint8 *data, size_t size) { VipsImage *image, *out; double d; if (!(image = vips_image_new_from_buffer(data, size, "", nullptr))) return 0; if (image->Xsize > 100 || image->Ysize > 100 || image->Bands > 4) { g_object_unref(image); return 0; } if (vips_thumbnail_image(image, &out, 42, nullptr)) { g_object_unref(image); return 0; } vips_avg(out, &d, nullptr); g_object_unref(out); g_object_unref(image); return 0; } libvips-8.18.2/libvips/000077500000000000000000000000001516303661500147405ustar00rootroot00000000000000libvips-8.18.2/libvips/Vips-8.0.metadata000066400000000000000000000031641516303661500176720ustar00rootroot00000000000000Object.new_from_string.object_class type="GLib.ObjectClass" Object.print_summary_class.klass type="GLib.ObjectClass" ArgumentClass.object_class type="GLib.ObjectClass" class_find type="GLib.ObjectClass" ClassMapFn.cls type="GLib.ObjectClass" ArgumentClassMapFn.object_class type="GLib.ObjectClass" ArgumentTable type="GLib.HashTable" ArrayDouble.newv skip=false ArrayImage.newv skip=false ArrayInt.newv skip=false Image.*#method skip=false Image.eval#virtual_method name="eval_impl" Image.invalidate#virtual_method name="invalidate_impl" Image.minimise#virtual_method name="minimise_impl" Image.posteval#virtual_method name="posteval_impl" Image.preeval#virtual_method name="preeval_impl" Image.written#virtual_method name="written_impl" Image.written#virtual_method.result out Image.set_area.free_fn closure=-1 destroy=-1 Object.close#virtual_method name="close_impl" Object.postbuild#virtual_method name="postbuild_impl" Object.postclose#virtual_method name="postclose_impl" Object.preclose#virtual_method name="preclose_impl" Object.preclose#method name="do_preclose" Object.sanity#virtual_method name="sanity_impl" _object_set_member name="set_member" parent="Vips.Object" symbol_type="method" instance_idx=0 value_set_blob.free_fn closure=-1 destroy=-1 value_set_area.free_fn closure=-1 destroy=-1 Area.new.free_fn closure=-1 destroy=-1 cache_* skip=false name="cache_(.+)" parent="Vips.Cache" col_* skip=false name="col_(.+)" parent="Vips.ColorUtils" tracked_* skip=false name="tracked_(.+)" parent="Vips.Tracked" check_* skip=false parent="Vips.Utils" value_* skip=false name="value_(.+)" parent="Vips.Value" libvips-8.18.2/libvips/arithmetic/000077500000000000000000000000001516303661500170715ustar00rootroot00000000000000libvips-8.18.2/libvips/arithmetic/abs.c000066400000000000000000000123011516303661500177770ustar00rootroot00000000000000/* absolute value * * Copyright: 1990, N. Dessipris, based on im_powtra() * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 5/5/93 J.Cupitt * - adapted from im_lintra to work with partial images * - complex and signed support added * 30/6/93 JC * - adapted for partial v2 * - ANSI conversion * - spe29873r6k3h()**!@lling errors removed * 9/2/95 JC * - adapted for im_wrap... * 20/6/02 JC * - tiny speed up * 8/12/06 * - add liboil support * 28/8/09 * - gtkdoc * - tiny polish * 31/7/10 * - remove liboil * 6/11/11 * - redone as a class * 3/12/13 * - add orc, though the speed improvement vs. gcc's auto-vectorizer * seems very marginal * 21/2/19 * - move orc init to first use of abs */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef VipsUnary VipsAbs; typedef VipsUnaryClass VipsAbsClass; G_DEFINE_TYPE(VipsAbs, vips_abs, VIPS_TYPE_UNARY); static int vips_abs_build(VipsObject *object) { VipsUnary *unary = (VipsUnary *) object; if (unary->in && vips_band_format_isuint(unary->in->BandFmt)) return vips_unary_copy(unary); if (VIPS_OBJECT_CLASS(vips_abs_parent_class)->build(object)) return -1; return 0; } /* Integer abs operation: just test and negate. */ #define ABS_INT(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int x; \ \ for (x = 0; x < sz; x++) \ q[x] = p[x] < 0 ? 0 - p[x] : p[x]; \ } /* Float abs operation: call fabs(). */ #define ABS_FLOAT(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int x; \ \ for (x = 0; x < sz; x++) \ q[x] = fabs(p[x]); \ } /* Complex abs operation: calculate modulus. */ #define ABS_COMPLEX(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int x; \ \ for (x = 0; x < sz; x++) { \ q[x] = hypot(p[0], p[1]); \ p += 2; \ } \ } static void vips_abs_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int bands = vips_image_get_bands(im); int sz = width * bands; switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: ABS_INT(signed char); break; case VIPS_FORMAT_SHORT: ABS_INT(signed short); break; case VIPS_FORMAT_INT: ABS_INT(signed int); break; case VIPS_FORMAT_FLOAT: ABS_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: ABS_FLOAT(double); break; case VIPS_FORMAT_COMPLEX: ABS_COMPLEX(float); break; case VIPS_FORMAT_DPCOMPLEX: ABS_COMPLEX(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Format doesn't change with abs, other than complex -> real. */ static const VipsBandFormat vips_abs_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, F, D, D }; static void vips_abs_class_init(VipsAbsClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "abs"; object_class->description = _("absolute value of an image"); object_class->build = vips_abs_build; aclass->process_line = vips_abs_buffer; vips_arithmetic_set_format_table(aclass, vips_abs_format_table); } static void vips_abs_init(VipsAbs *abs) { } /** * vips_abs: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * This operation finds the absolute value of an image. It does a copy for * unsigned integer types, negate for negative values in * signed integer types, [`fabs()`](man:fabs(3)) for * float types, and calculates modulus for complex * types. * * ::: seealso * [method@Image.sign]. * * Returns: 0 on success, -1 on error */ int vips_abs(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("abs", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/add.c000066400000000000000000000151171516303661500177720ustar00rootroot00000000000000/* add operation * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 29/4/93 J.Cupitt * - now works for partial images * 1/7/93 JC * - adapted for partial v2 * 9/5/95 JC * - simplified: now just handles 10 cases (instead of 50), using * im_clip2*() to help * - now uses im_wrapmany() rather than im_generate() * 31/5/96 JC * - SWAP() removed, *p++ removed * 27/9/04 * - im__cast_and_call() now matches bands as well * - ... so 1 band + 4 band image -> 4 band image * 8/12/06 * - add liboil support * 18/8/08 * - revise upcasting system * - im__cast_and_call() no longer sets bbits for you * - add gtkdoc comments * - remove separate complex case, just double size * 11/9/09 * - im__cast_and_call() becomes im__arith_binary() * - more of operation scaffold moved inside * 25/7/10 * - remove oil support again ... we'll try Orc instead * 29/10/10 * - move to VipsVector for Orc support * 28/2/11 * - argh vector int/uint was broken * 4/4/11 * - rewrite as a class * 2/12/13 * - remove vector code, gcc autovec with -O3 is now as fast */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "binary.h" typedef VipsBinary VipsAdd; typedef VipsBinaryClass VipsAddClass; G_DEFINE_TYPE(VipsAdd, vips_add, VIPS_TYPE_BINARY); #define LOOP(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = left[x] + right[x]; \ } /* Special case for VIPS_FORMAT_INT, to prevent UB. */ #define LOOP_INT64(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = (int64_t) left[x] + right[x]; \ } static void add_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; int bands = vips_image_get_bands(im); VipsBandFormat format = vips_image_get_format(im); int sz = width * bands * (vips_band_format_iscomplex(format) ? 2 : 1); int x; /* Add all input types. Keep types here in sync with * vips_add_format_table[] below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, unsigned short); break; case VIPS_FORMAT_CHAR: LOOP(signed char, signed short); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, unsigned int); break; case VIPS_FORMAT_SHORT: LOOP(signed short, signed int); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, unsigned int); break; case VIPS_FORMAT_INT: LOOP_INT64(signed int, signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: LOOP(float, float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: LOOP(double, double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for addition. Sign and value preserving. Make sure these * match the case statement in add_buffer() above. */ static const VipsBandFormat vips_add_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ US, S, UI, I, UI, I, F, X, D, DX }; static void vips_add_class_init(VipsAddClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "add"; object_class->description = _("add two images"); aclass->process_line = add_buffer; vips_arithmetic_set_format_table(aclass, vips_add_format_table); } static void vips_add_init(VipsAdd *add) { } /** * vips_add: (method) * @left: input image * @right: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @in1 + @in2 and writes the result to @out. * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), then the * following table is used to determine the output type: * * ## [method@Image.add] type promotion * * | input type | output type | * |----------------|----------------| * | uchar | ushort | * | char | short | * | ushort | uint | * | short | int | * | uint | uint | * | int | int | * | float | float | * | double | double | * | complex | complex | * | double complex | double complex | * * In other words, the output type is just large enough to hold the whole * range of possible values. * * ::: seealso * [method@Image.subtract], [method@Image.linear]. * * Returns: 0 on success, -1 on error */ int vips_add(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("add", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/arithmetic.c000066400000000000000000000360031516303661500213700ustar00rootroot00000000000000/* base class for all arithmetic operations * * properties: * - one output image, one or more inputs * - cast input images to match * - output is large enough to hold output values (value preserving) * - point-to-point operations (ie. each pixel depends only on the * corresponding pixel in the input) * - LUT-able: ie. arithmetic (image) can be exactly replaced by * maplut (image, arithmetic (lut)) for 8/16 bit int images */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "parithmetic.h" G_DEFINE_ABSTRACT_TYPE(VipsArithmetic, vips_arithmetic, VIPS_TYPE_OPERATION); /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* For two integer types, the "largest", ie. one which can represent the * full range of both. */ static VipsBandFormat format_largest[6][6] = { /* UC C US S UI I */ /* UC */ { UC, S, US, S, UI, I }, /* C */ { S, C, I, S, I, I }, /* US */ { US, I, US, I, UI, I }, /* S */ { S, S, I, S, I, I }, /* UI */ { UI, I, UI, I, UI, I }, /* I */ { I, I, I, I, I, I } }; /* For two formats, find one which can represent the full range of both. */ static VipsBandFormat vips_format_common(VipsBandFormat a, VipsBandFormat b) { if (vips_band_format_iscomplex(a) || vips_band_format_iscomplex(b)) { if (a == VIPS_FORMAT_DPCOMPLEX || b == VIPS_FORMAT_DPCOMPLEX) return VIPS_FORMAT_DPCOMPLEX; else return VIPS_FORMAT_COMPLEX; } else if (vips_band_format_isfloat(a) || vips_band_format_isfloat(b)) { if (a == VIPS_FORMAT_DOUBLE || b == VIPS_FORMAT_DOUBLE) return VIPS_FORMAT_DOUBLE; else return VIPS_FORMAT_FLOAT; } else return format_largest[a][b]; } int vips__formatalike_vec(VipsImage **in, VipsImage **out, int n) { int i; VipsBandFormat format; g_assert(n >= 1); format = in[0]->BandFmt; for (i = 1; i < n; i++) format = vips_format_common(format, in[i]->BandFmt); for (i = 0; i < n; i++) if (in[i]->BandFmt == format) { /* Already in the right format ... just copy the image * pointer and add a ref. */ out[i] = in[i]; g_object_ref(in[i]); } else { if (vips_cast(in[i], &out[i], format, NULL)) return -1; } return 0; } int vips__sizealike_vec(VipsImage **in, VipsImage **out, int n) { int i; int width_max; int height_max; g_assert(n >= 1); width_max = in[0]->Xsize; height_max = in[0]->Ysize; for (i = 1; i < n; i++) { width_max = VIPS_MAX(width_max, in[i]->Xsize); height_max = VIPS_MAX(height_max, in[i]->Ysize); } for (i = 0; i < n; i++) if (in[i]->Xsize == width_max && in[i]->Ysize == height_max) { /* Already the right size ... just copy the image * pointer and add a ref. */ out[i] = in[i]; g_object_ref(in[i]); } else { if (vips_embed(in[i], &out[i], 0, 0, width_max, height_max, NULL)) return -1; } return 0; } /* Make an n-band image. Input 1 or n bands. */ int vips__bandup(const char *domain, VipsImage *in, VipsImage **out, int n) { VipsImage **bands; int i; int result; if (in->Bands == n) return vips_copy(in, out, NULL); if (in->Bands != 1) { vips_error(domain, _("not one band or %d bands"), n); return -1; } if (n > VIPS_MAX_COORD || n < 1) { vips_error(domain, "%s", _("bad bands")); return -1; } if (!(bands = VIPS_ARRAY(NULL, n, VipsImage *))) return -1; for (i = 0; i < n; i++) bands[i] = in; result = vips_bandjoin(bands, out, n, NULL); VIPS_FREE(bands); return result; } /* base_bands is the default minimum. * * Handy for example, if you have VipsLinear with * a 3-element vector of constants and a 1-band input image, you need to cast * the image up to three bands. */ int vips__bandalike_vec(const char *domain, VipsImage **in, VipsImage **out, int n, int base_bands) { int i; int max_bands; VipsInterpretation interpretation; g_assert(n >= 1); /* We try to set the interpretation of the output images from the * interpretation of the n-band input. For example, if we are matching * a set of BW images to an RGB image, we want the BW images to be * tagged as RGB. */ max_bands = base_bands; interpretation = VIPS_INTERPRETATION_ERROR; for (i = 0; i < n; i++) { /* >= so we can pick up interpretation if base_bands is equal * to the number of bands of the largest image. */ if (in[i]->Bands >= max_bands) { max_bands = in[i]->Bands; interpretation = in[i]->Type; } } for (i = 0; i < n; i++) if (in[i]->Bands == max_bands) { /* Already the right number of bands ... just copy the * image pointer and add a ref. */ out[i] = in[i]; g_object_ref(in[i]); } else { if (vips__bandup(domain, in[i], &out[i], max_bands)) return -1; if (interpretation != VIPS_INTERPRETATION_ERROR) out[i]->Type = interpretation; } return 0; } int vips__formatalike(VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2) { VipsImage *in[2]; VipsImage *out[2]; in[0] = in1; in[1] = in2; if (vips__formatalike_vec(in, out, 2)) return -1; *out1 = out[0]; *out2 = out[1]; return 0; } int vips__sizealike(VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2) { VipsImage *in[2]; VipsImage *out[2]; in[0] = in1; in[1] = in2; if (vips__sizealike_vec(in, out, 2)) return -1; *out1 = out[0]; *out2 = out[1]; return 0; } int vips__bandalike(const char *domain, VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2) { VipsImage *in[2]; VipsImage *out[2]; in[0] = in1; in[1] = in2; if (vips__bandalike_vec(domain, in, out, 2, 1)) return -1; *out1 = out[0]; *out2 = out[1]; return 0; } /* Our sequence value. */ typedef struct { VipsArithmetic *arithmetic; /* Set of input regions. */ VipsRegion **ir; /* For each input, an input pointer. */ VipsPel **p; } VipsArithmeticSequence; static int vips_arithmetic_stop(void *vseq, void *a, void *b) { VipsArithmeticSequence *seq = (VipsArithmeticSequence *) vseq; if (seq->ir) { int i; for (i = 0; seq->ir[i]; i++) VIPS_UNREF(seq->ir[i]); VIPS_FREE(seq->ir); } VIPS_FREE(seq->p); VIPS_FREE(seq); return 0; } static void * vips_arithmetic_start(VipsImage *out, void *a, void *b) { VipsImage **in = (VipsImage **) a; VipsArithmetic *arithmetic = (VipsArithmetic *) b; VipsArithmeticSequence *seq; int i, n; if (!(seq = VIPS_NEW(NULL, VipsArithmeticSequence))) return NULL; seq->arithmetic = arithmetic; seq->ir = NULL; seq->p = NULL; /* How many images? */ for (n = 0; in[n]; n++) ; /* Allocate space for region array. */ if (!(seq->ir = VIPS_ARRAY(NULL, n + 1, VipsRegion *))) { vips_arithmetic_stop(seq, NULL, NULL); return NULL; } /* Create a set of regions. */ for (i = 0; i < n; i++) if (!(seq->ir[i] = vips_region_new(in[i]))) { vips_arithmetic_stop(seq, NULL, NULL); return NULL; } seq->ir[n] = NULL; /* Input pointers. */ if (!(seq->p = VIPS_ARRAY(NULL, n + 1, VipsPel *))) { vips_arithmetic_stop(seq, NULL, NULL); return NULL; } return seq; } static int vips_arithmetic_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsArithmeticSequence *seq = (VipsArithmeticSequence *) vseq; VipsRegion **ir = seq->ir; VipsArithmetic *arithmetic = VIPS_ARITHMETIC(b); VipsArithmeticClass *class = VIPS_ARITHMETIC_GET_CLASS(arithmetic); VipsRect *r = &out_region->valid; VipsPel *q; int i, y; /* Prepare all input regions and make buffer pointers. */ if (vips_reorder_prepare_many(out_region->im, ir, r)) return -1; for (i = 0; ir[i]; i++) seq->p[i] = (VipsPel *) VIPS_REGION_ADDR(ir[i], r->left, r->top); seq->p[i] = NULL; q = (VipsPel *) VIPS_REGION_ADDR(out_region, r->left, r->top); VIPS_GATE_START("vips_arithmetic_gen: work"); for (y = 0; y < r->height; y++) { class->process_line(arithmetic, q, seq->p, r->width); for (i = 0; ir[i]; i++) seq->p[i] += VIPS_REGION_LSKIP(ir[i]); q += VIPS_REGION_LSKIP(out_region); } VIPS_GATE_STOP("vips_arithmetic_gen: work"); VIPS_COUNT_PIXELS(out_region, VIPS_OBJECT_CLASS(class)->nickname); return 0; } static int vips_arithmetic_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsArithmetic *arithmetic = VIPS_ARITHMETIC(object); VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS(arithmetic); VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; int i; #ifdef DEBUG printf("vips_arithmetic_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_arithmetic_parent_class)->build(object)) return -1; g_object_set(arithmetic, "out", vips_image_new(), NULL); decode = (VipsImage **) vips_object_local_array(object, arithmetic->n); format = (VipsImage **) vips_object_local_array(object, arithmetic->n); band = (VipsImage **) vips_object_local_array(object, arithmetic->n); size = (VipsImage **) vips_object_local_array(object, arithmetic->n); /* Decode RAD/LABQ etc. */ for (i = 0; i < arithmetic->n; i++) if (vips_image_decode(arithmetic->in[i], &decode[i])) return -1; /* Cast our input images up to a common format, bands and size. */ if (vips__formatalike_vec(decode, format, arithmetic->n) || vips__bandalike_vec(class->nickname, format, band, arithmetic->n, arithmetic->base_bands) || vips__sizealike_vec(band, size, arithmetic->n)) return -1; /* Keep a copy of the processed images here for subclasses. */ arithmetic->ready = size; if (vips_image_pipeline_array(arithmetic->out, VIPS_DEMAND_STYLE_THINSTRIP, arithmetic->ready)) return -1; arithmetic->out->Bands = arithmetic->ready[0]->Bands; if (arithmetic->format != VIPS_FORMAT_NOTSET) arithmetic->out->BandFmt = arithmetic->format; else arithmetic->out->BandFmt = aclass->format_table[arithmetic->ready[0]->BandFmt]; if (vips_image_generate(arithmetic->out, vips_arithmetic_start, vips_arithmetic_gen, vips_arithmetic_stop, arithmetic->ready, arithmetic)) return -1; return 0; } static void vips_arithmetic_class_init(VipsArithmeticClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "arithmetic"; vobject_class->description = _("arithmetic operations"); vobject_class->build = vips_arithmetic_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsArithmetic, out)); } static void vips_arithmetic_init(VipsArithmetic *arithmetic) { arithmetic->base_bands = 1; arithmetic->format = VIPS_FORMAT_NOTSET; } void vips_arithmetic_set_format_table(VipsArithmeticClass *class, const VipsBandFormat *format_table) { g_assert(!class->format_table); class->format_table = format_table; } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_arithmetic_operation_init(void) { extern GType vips_add_get_type(void); extern GType vips_clamp_get_type(void); extern GType vips_minpair_get_type(void); extern GType vips_maxpair_get_type(void); extern GType vips_sum_get_type(void); extern GType vips_subtract_get_type(void); extern GType vips_multiply_get_type(void); extern GType vips_divide_get_type(void); extern GType vips_invert_get_type(void); extern GType vips_avg_get_type(void); extern GType vips_min_get_type(void); extern GType vips_max_get_type(void); extern GType vips_deviate_get_type(void); extern GType vips_linear_get_type(void); extern GType vips_math_get_type(void); extern GType vips_abs_get_type(void); extern GType vips_sign_get_type(void); extern GType vips_stats_get_type(void); extern GType vips_hist_find_get_type(void); extern GType vips_hist_find_ndim_get_type(void); extern GType vips_hist_find_indexed_get_type(void); extern GType vips_hough_line_get_type(void); extern GType vips_hough_circle_get_type(void); extern GType vips_project_get_type(void); extern GType vips_profile_get_type(void); extern GType vips_measure_get_type(void); extern GType vips_getpoint_get_type(void); extern GType vips_round_get_type(void); extern GType vips_relational_get_type(void); extern GType vips_relational_const_get_type(void); extern GType vips_remainder_get_type(void); extern GType vips_remainder_const_get_type(void); extern GType vips_boolean_get_type(void); extern GType vips_boolean_const_get_type(void); extern GType vips_math2_get_type(void); extern GType vips_math2_const_get_type(void); extern GType vips_complex_get_type(void); extern GType vips_complex2_get_type(void); extern GType vips_complexget_get_type(void); extern GType vips_complexform_get_type(void); extern GType vips_find_trim_get_type(void); vips_add_get_type(); vips_clamp_get_type(); vips_minpair_get_type(); vips_maxpair_get_type(); vips_sum_get_type(); vips_subtract_get_type(); vips_multiply_get_type(); vips_divide_get_type(); vips_invert_get_type(); vips_avg_get_type(); vips_min_get_type(); vips_max_get_type(); vips_deviate_get_type(); vips_linear_get_type(); vips_math_get_type(); vips_abs_get_type(); vips_sign_get_type(); vips_stats_get_type(); vips_hist_find_get_type(); vips_hist_find_ndim_get_type(); vips_hist_find_indexed_get_type(); vips_hough_line_get_type(); vips_hough_circle_get_type(); vips_project_get_type(); vips_profile_get_type(); vips_measure_get_type(); vips_getpoint_get_type(); vips_round_get_type(); vips_relational_get_type(); vips_relational_const_get_type(); vips_remainder_get_type(); vips_remainder_const_get_type(); vips_boolean_get_type(); vips_boolean_const_get_type(); vips_math2_get_type(); vips_math2_const_get_type(); vips_complex_get_type(); vips_complex2_get_type(); vips_complexget_get_type(); vips_complexform_get_type(); vips_find_trim_get_type(); } libvips-8.18.2/libvips/arithmetic/avg.c000066400000000000000000000130531516303661500200140ustar00rootroot00000000000000/* avg ... average value of image * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 02/08/1990 * Modified on: * 5/5/93 JC * - now does partial images * - less likely to overflow * 1/7/93 JC * - adapted for partial v2 * - ANSI C * 21/2/95 JC * - modernised again * 11/5/95 JC * - oops! return( NULL ) in im_avg(), instead of return( -1 ) * 20/6/95 JC * - now returns double * 13/1/05 * - use 64 bit arithmetic * 8/12/06 * - add liboil support * 18/8/09 * - gtkdoc, minor reformatting * 7/9/09 * - rewrite for im__wrapiter() * - add complex case (needed for im_max()) * 8/9/09 * - wrapscan stuff moved here * 31/7/10 * - remove liboil * 24/8/11 * - rewrite as a class * 12/9/14 * - oops, fix complex avg */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "statistic.h" typedef struct _VipsAvg { VipsStatistic parent_instance; double sum; double out; } VipsAvg; typedef VipsStatisticClass VipsAvgClass; G_DEFINE_TYPE(VipsAvg, vips_avg, VIPS_TYPE_STATISTIC); static int vips_avg_build(VipsObject *object) { VipsStatistic *statistic = VIPS_STATISTIC(object); VipsAvg *avg = (VipsAvg *) object; guint64 vals; double average; if (VIPS_OBJECT_CLASS(vips_avg_parent_class)->build(object)) return -1; vals = VIPS_IMAGE_N_PELS(statistic->ready) * vips_image_get_bands(statistic->ready); average = avg->sum / vals; g_object_set(object, "out", average, NULL); return 0; } /* Start function: allocate space for a double in which we can accumulate the * sum for this thread. */ static void * vips_avg_start(VipsStatistic *statistic) { return (void *) g_new0(double, 1); } /* Stop function. Add this little sum to the main sum. */ static int vips_avg_stop(VipsStatistic *statistic, void *seq) { VipsAvg *avg = (VipsAvg *) statistic; double *sum = (double *) seq; avg->sum += *sum; g_free(seq); return 0; } /* Sum pels in this section. */ #define LOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ \ for (i = 0; i < sz; i++) \ m += p[i]; \ } #define CLOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ \ for (i = 0; i < sz; i++) { \ double mod = sqrt(p[0] * p[0] + p[1] * p[1]); \ \ m += mod; \ p += 2; \ } \ } /* Loop over region, accumulating a sum in *tmp. */ static int vips_avg_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { const int sz = n * vips_image_get_bands(statistic->ready); double *sum = (double *) seq; int i; double m; m = *sum; /* Now generate code for all types. */ switch (vips_image_get_format(statistic->ready)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOP(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOP(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int); break; case VIPS_FORMAT_FLOAT: LOOP(float); break; case VIPS_FORMAT_DOUBLE: LOOP(double); break; case VIPS_FORMAT_COMPLEX: CLOOP(float); break; case VIPS_FORMAT_DPCOMPLEX: CLOOP(double); break; default: g_assert_not_reached(); } *sum = m; return 0; } static void vips_avg_class_init(VipsAvgClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "avg"; object_class->description = _("find image average"); object_class->build = vips_avg_build; sclass->start = vips_avg_start; sclass->scan = vips_avg_scan; sclass->stop = vips_avg_stop; VIPS_ARG_DOUBLE(class, "out", 2, _("Output"), _("Output value"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsAvg, out), -INFINITY, INFINITY, 0.0); } static void vips_avg_init(VipsAvg *avg) { } /** * vips_avg: (method) * @in: input [class@Image] * @out: (out): output pixel average * @...: `NULL`-terminated list of optional named arguments * * This operation finds the average value in an image. It operates on all * bands of the input image: use [method@Image.stats] if you need to calculate an * average for each band. For complex images, return the average modulus. * * ::: seealso * [method@Image.stats], [method@Image.bandmean], [method@Image.deviate], [method@Image.rank] * * Returns: 0 on success, -1 on error */ int vips_avg(VipsImage *in, double *out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("avg", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/binary.c000066400000000000000000000052521516303661500205250ustar00rootroot00000000000000/* base class for all binary operations * * 13/3/11 * - argh, forgot to make a private array for the inputs * 16/5/11 * - added sizealike * 30/10/11 * - moe most functionality into arithmetic.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" G_DEFINE_ABSTRACT_TYPE(VipsBinary, vips_binary, VIPS_TYPE_ARITHMETIC); static int vips_binary_build(VipsObject *object) { VipsArithmetic *arithmetic = VIPS_ARITHMETIC(object); VipsBinary *binary = VIPS_BINARY(object); arithmetic->n = 2; arithmetic->in = (VipsImage **) vips_object_local_array(object, 2); arithmetic->in[0] = binary->left; arithmetic->in[1] = binary->right; if (arithmetic->in[0]) g_object_ref(arithmetic->in[0]); if (arithmetic->in[1]) g_object_ref(arithmetic->in[1]); if (VIPS_OBJECT_CLASS(vips_binary_parent_class)->build(object)) return -1; return 0; } static void vips_binary_class_init(VipsBinaryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "binary"; vobject_class->description = _("binary operations"); vobject_class->build = vips_binary_build; /* Create properties. */ VIPS_ARG_IMAGE(class, "left", 1, _("Left"), _("Left-hand image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBinary, left)); VIPS_ARG_IMAGE(class, "right", 2, _("Right"), _("Right-hand image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBinary, right)); } static void vips_binary_init(VipsBinary *binary) { /* Init our instance fields. */ } libvips-8.18.2/libvips/arithmetic/binary.h000066400000000000000000000035661516303661500205400ustar00rootroot00000000000000/* base class for all binary arithmetic operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_BINARY_H #define VIPS_BINARY_H #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include "parithmetic.h" #define VIPS_TYPE_BINARY (vips_binary_get_type()) #define VIPS_BINARY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), VIPS_TYPE_BINARY, VipsBinary)) #define VIPS_BINARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), VIPS_TYPE_BINARY, VipsBinaryClass)) #define VIPS_IS_BINARY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_BINARY)) #define VIPS_IS_BINARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_BINARY)) #define VIPS_BINARY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), VIPS_TYPE_BINARY, VipsBinaryClass)) typedef struct _VipsBinary { VipsArithmetic parent_instance; /* Original left and right image args. */ VipsImage *left; VipsImage *right; } VipsBinary; typedef VipsArithmeticClass VipsBinaryClass; GType vips_binary_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_BINARY_H*/ libvips-8.18.2/libvips/arithmetic/boolean.c000066400000000000000000000551461516303661500206670ustar00rootroot00000000000000/* boolean.c -- various bit operations * * Modified: * 15/12/94 JC * - ANSIfied * - adapted to partials with im_wrap... * 25/1/95 JC * - added check1ary(), check2ary() * 8/2/95 JC * - new im_wrapmany * 19/7/95 JC * - added im_shiftleft() and im_shiftright() * 6/7/98 JC * - added _vec forms * - removed *p++ stuff * 10/9/99 JC * - and/or/eor now do all int types * 10/10/02 JC * - renamed im_and() etc. as im_andimage() to remove breakage in the C++ * layer if operator names are turned on * 30/6/04 * - now cast float/complex args to int * 11/9/09 * - use new im__cast_and__call() * - therefore now supports 1-band $op n-band * 17/9/09 * - moved to im__arith_binary*() * - renamed im_eor_vec() as im_eorimage_vec() for C++ sanity * 21/11/10 * - oop, constants are always (int) now, so (^-1) works for unsigned * types * 12/11/11 * - redo as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" #include "unaryconst.h" typedef struct _VipsBoolean { VipsBinary parent_instance; VipsOperationBoolean operation; } VipsBoolean; typedef VipsBinaryClass VipsBooleanClass; G_DEFINE_TYPE(VipsBoolean, vips_boolean, VIPS_TYPE_BINARY); static int vips_boolean_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBinary *binary = (VipsBinary *) object; if (binary->left && vips_check_noncomplex(class->nickname, binary->left)) return -1; if (binary->right && vips_check_noncomplex(class->nickname, binary->right)) return -1; if (VIPS_OBJECT_CLASS(vips_boolean_parent_class)->build(object)) return -1; return 0; } #define LOOP(TYPE, OP) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = left[x] OP right[x]; \ } #define FLOOP(TYPE, OP) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ int *restrict q = (int *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = ((int) left[x]) OP((int) right[x]); \ } #define SWITCH(I, F, OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ I(unsigned char, OP); \ break; \ case VIPS_FORMAT_CHAR: \ I(signed char, OP); \ break; \ case VIPS_FORMAT_USHORT: \ I(unsigned short, OP); \ break; \ case VIPS_FORMAT_SHORT: \ I(signed short, OP); \ break; \ case VIPS_FORMAT_UINT: \ I(unsigned int, OP); \ break; \ case VIPS_FORMAT_INT: \ I(signed int, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ F(float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ F(double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } #define FNLOOP(TYPE, FN) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ int *restrict q = (int *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = FN(left[x], right[x]); \ } static void vips_boolean_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsBoolean *boolean = (VipsBoolean *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (boolean->operation) { case VIPS_OPERATION_BOOLEAN_AND: SWITCH(LOOP, FLOOP, &); break; case VIPS_OPERATION_BOOLEAN_OR: SWITCH(LOOP, FLOOP, |); break; case VIPS_OPERATION_BOOLEAN_EOR: SWITCH(LOOP, FLOOP, ^); break; /* Special case: we need to be able to use VIPS_LSHIFT_INT(). */ case VIPS_OPERATION_BOOLEAN_LSHIFT: switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, <<); break; case VIPS_FORMAT_CHAR: FNLOOP(signed char, VIPS_LSHIFT_INT); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, <<); break; case VIPS_FORMAT_SHORT: FNLOOP(signed short, VIPS_LSHIFT_INT); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, <<); break; case VIPS_FORMAT_INT: FNLOOP(signed int, VIPS_LSHIFT_INT); break; case VIPS_FORMAT_FLOAT: FLOOP(float, <<); break; case VIPS_FORMAT_DOUBLE: FLOOP(double, <<); break; default: g_assert_not_reached(); } break; case VIPS_OPERATION_BOOLEAN_RSHIFT: SWITCH(LOOP, FLOOP, >>); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type conversions for boolean. */ static const VipsBandFormat vips_boolean_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, I, I, I, I }; static void vips_boolean_class_init(VipsBooleanClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "boolean"; object_class->description = _("boolean operation on two images"); object_class->build = vips_boolean_build; aclass->process_line = vips_boolean_buffer; vips_arithmetic_set_format_table(aclass, vips_boolean_format_table); VIPS_ARG_ENUM(class, "boolean", 200, _("Operation"), _("Boolean to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBoolean, operation), VIPS_TYPE_OPERATION_BOOLEAN, VIPS_OPERATION_BOOLEAN_AND); } static void vips_boolean_init(VipsBoolean *boolean) { } static int vips_booleanv(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationBoolean operation, va_list ap) { return vips_call_split("boolean", ap, left, right, out, operation); } /** * vips_boolean: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @boolean: boolean operation to perform * @...: `NULL`-terminated list of optional named arguments * * Perform various boolean operations on pairs of images. * * The output image is the same format as the upcast input images for integer * types. Float types are cast to int before processing. Complex types are not * supported. * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * ::: seealso * [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_boolean(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationBoolean boolean, ...) { va_list ap; int result; va_start(ap, boolean); result = vips_booleanv(left, right, out, boolean, ap); va_end(ap); return result; } /** * vips_andimage: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.AND] on a pair of images. See * [method@Image.boolean]. * * Returns: 0 on success, -1 on error */ int vips_andimage(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_booleanv(left, right, out, VIPS_OPERATION_BOOLEAN_AND, ap); va_end(ap); return result; } /** * vips_orimage: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.OR] on a pair of images. See * [method@Image.boolean]. * * Returns: 0 on success, -1 on error */ int vips_orimage(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_booleanv(left, right, out, VIPS_OPERATION_BOOLEAN_OR, ap); va_end(ap); return result; } /** * vips_eorimage: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.EOR] on a pair of images. See * [method@Image.boolean]. * * Returns: 0 on success, -1 on error */ int vips_eorimage(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_booleanv(left, right, out, VIPS_OPERATION_BOOLEAN_EOR, ap); va_end(ap); return result; } /** * vips_lshift: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.LSHIFT] on a pair of images. See * [method@Image.boolean]. * * Returns: 0 on success, -1 on error */ int vips_lshift(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_booleanv(left, right, out, VIPS_OPERATION_BOOLEAN_LSHIFT, ap); va_end(ap); return result; } /** * vips_rshift: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.RSHIFT] on a pair of images. See * [method@Image.boolean]. * * Returns: 0 on success, -1 on error */ int vips_rshift(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_booleanv(left, right, out, VIPS_OPERATION_BOOLEAN_RSHIFT, ap); va_end(ap); return result; } typedef struct _VipsBooleanConst { VipsUnaryConst parent_instance; VipsOperationBoolean operation; } VipsBooleanConst; typedef VipsUnaryConstClass VipsBooleanConstClass; G_DEFINE_TYPE(VipsBooleanConst, vips_boolean_const, VIPS_TYPE_UNARY_CONST); static int vips_boolean_const_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsUnary *unary = (VipsUnary *) object; if (unary->in && vips_check_noncomplex(class->nickname, unary->in)) return -1; if (VIPS_OBJECT_CLASS(vips_boolean_const_parent_class)->build(object)) return -1; return 0; } #define LOOPC(TYPE, OP) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int *restrict c = uconst->c_int; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) \ q[i] = p[i] OP c[b]; \ } #define FLOOPC(TYPE, OP) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ int *restrict q = (int *) out; \ int *restrict c = uconst->c_int; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) \ q[i] = ((int) p[i]) OP((int) c[b]); \ } static void vips_boolean_const_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsUnaryConst *uconst = (VipsUnaryConst *) arithmetic; VipsBooleanConst *bconst = (VipsBooleanConst *) arithmetic; VipsImage *im = arithmetic->ready[0]; int bands = im->Bands; int i, x, b; switch (bconst->operation) { case VIPS_OPERATION_BOOLEAN_AND: SWITCH(LOOPC, FLOOPC, &); break; case VIPS_OPERATION_BOOLEAN_OR: SWITCH(LOOPC, FLOOPC, |); break; case VIPS_OPERATION_BOOLEAN_EOR: SWITCH(LOOPC, FLOOPC, ^); break; case VIPS_OPERATION_BOOLEAN_LSHIFT: SWITCH(LOOPC, FLOOPC, <<); break; case VIPS_OPERATION_BOOLEAN_RSHIFT: SWITCH(LOOPC, FLOOPC, >>); break; default: g_assert_not_reached(); } } static void vips_boolean_const_class_init(VipsBooleanConstClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "boolean_const"; object_class->description = _("boolean operations against a constant"); object_class->build = vips_boolean_const_build; aclass->process_line = vips_boolean_const_buffer; vips_arithmetic_set_format_table(aclass, vips_boolean_format_table); VIPS_ARG_ENUM(class, "boolean", 200, _("Operation"), _("Boolean to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBooleanConst, operation), VIPS_TYPE_OPERATION_BOOLEAN, VIPS_OPERATION_BOOLEAN_AND); } static void vips_boolean_const_init(VipsBooleanConst *boolean_const) { } static int vips_boolean_constv(VipsImage *in, VipsImage **out, VipsOperationBoolean operation, const double *c, int n, va_list ap) { VipsArea *area_c; double *array; int result; int i; area_c = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); array = (double *) area_c->data; for (i = 0; i < n; i++) array[i] = c[i]; result = vips_call_split("boolean_const", ap, in, out, operation, area_c); vips_area_unref(area_c); return result; } /** * vips_boolean_const: (method) * @in: input image * @out: (out): output image * @boolean: boolean operation to perform * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform various boolean operations on an image against an array of * constants. * * The output type is always uchar, with 0 for `FALSE` and 255 for `TRUE`. * * If the array of constants has just one element, that constant is used for * all image bands. If the array has more than one element and they have * the same number of elements as there are bands in the image, then * one array element is used for each band. If the arrays have more than one * element and the image only has a single band, the result is a many-band * image where each band corresponds to one array element. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const1]. * * Returns: 0 on success, -1 on error */ int vips_boolean_const(VipsImage *in, VipsImage **out, VipsOperationBoolean boolean, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_boolean_constv(in, out, boolean, c, n, ap); va_end(ap); return result; } /** * vips_andimage_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.AND] on an image and an array of constants. * See [method@Image.boolean_const]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const1]. * * Returns: 0 on success, -1 on error */ int vips_andimage_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_AND, c, n, ap); va_end(ap); return result; } /** * vips_orimage_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.OR] on an image and an array of constants. * See [method@Image.boolean_const]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const1]. * * Returns: 0 on success, -1 on error */ int vips_orimage_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_OR, c, n, ap); va_end(ap); return result; } /** * vips_eorimage_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.EOR] on an image and an array of constants. * See [method@Image.boolean_const]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const1]. * * Returns: 0 on success, -1 on error */ int vips_eorimage_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_EOR, c, n, ap); va_end(ap); return result; } /** * vips_lshift_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.LSHIFT] on an image and an array of constants. * See [method@Image.boolean_const]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const1]. * * Returns: 0 on success, -1 on error */ int vips_lshift_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_LSHIFT, c, n, ap); va_end(ap); return result; } /** * vips_rshift_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.LSHIFT] on an image and an array of constants. * See [method@Image.boolean_const]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const1]. * * Returns: 0 on success, -1 on error */ int vips_rshift_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_RSHIFT, c, n, ap); va_end(ap); return result; } /** * vips_boolean_const1: (method) * @in: input image * @out: (out): output image * @boolean: boolean operation to perform * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform various boolean operations on an image with a single constant. See * [method@Image.boolean_const]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_boolean_const1(VipsImage *in, VipsImage **out, VipsOperationBoolean boolean, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_boolean_constv(in, out, boolean, &c, 1, ap); va_end(ap); return result; } /** * vips_andimage_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.AND] on an image and a constant. * See [method@Image.boolean_const1]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_andimage_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_AND, &c, 1, ap); va_end(ap); return result; } /** * vips_orimage_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.OR] on an image and a constant. * See [method@Image.boolean_const1]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_orimage_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_OR, &c, 1, ap); va_end(ap); return result; } /** * vips_eorimage_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.EOR] on an image and a constant. * See [method@Image.boolean_const1]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_eorimage_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_EOR, &c, 1, ap); va_end(ap); return result; } /** * vips_lshift_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.LSHIFT] on an image and a constant. * See [method@Image.boolean_const1]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_lshift_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_LSHIFT, &c, 1, ap); va_end(ap); return result; } /** * vips_rshift_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.RSHIFT] on an image and a constant. * See [method@Image.boolean_const1]. * * ::: seealso * [method@Image.boolean], [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_rshift_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_boolean_constv(in, out, VIPS_OPERATION_BOOLEAN_RSHIFT, &c, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/clamp.c000066400000000000000000000111351516303661500203320ustar00rootroot00000000000000/* clamp pixels to range * * 17/6/24 * - from abs.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef struct _VipsClamp { VipsUnary parent_instance; double min; double max; } VipsClamp; typedef VipsUnaryClass VipsClampClass; G_DEFINE_TYPE(VipsClamp, vips_clamp, VIPS_TYPE_UNARY); #define CLAMP_LINE(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ \ for (int x = 0; x < sz; x++) \ q[x] = VIPS_CLIP(clamp->min, p[x], clamp->max); \ } static void vips_clamp_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsClamp *clamp = (VipsClamp *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int bands = vips_image_get_bands(im); int sz = width * bands * (vips_band_format_iscomplex(im->BandFmt) ? 2 : 1); switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: CLAMP_LINE(signed char); break; case VIPS_FORMAT_UCHAR: CLAMP_LINE(unsigned char); break; case VIPS_FORMAT_SHORT: CLAMP_LINE(signed short); break; case VIPS_FORMAT_USHORT: CLAMP_LINE(unsigned short); break; case VIPS_FORMAT_INT: CLAMP_LINE(signed int); break; case VIPS_FORMAT_UINT: CLAMP_LINE(unsigned int); break; case VIPS_FORMAT_FLOAT: CLAMP_LINE(float); break; case VIPS_FORMAT_DOUBLE: CLAMP_LINE(double); break; case VIPS_FORMAT_COMPLEX: CLAMP_LINE(float); break; case VIPS_FORMAT_DPCOMPLEX: CLAMP_LINE(double); break; default: g_assert_not_reached(); } } #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Format doesn't change with clamp. */ static const VipsBandFormat vips_clamp_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_clamp_class_init(VipsClampClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "clamp"; object_class->description = _("clamp values of an image"); aclass->process_line = vips_clamp_buffer; vips_arithmetic_set_format_table(aclass, vips_clamp_format_table); VIPS_ARG_DOUBLE(class, "min", 10, _("Min"), _("Minimum value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsClamp, min), -INFINITY, INFINITY, 0.0); VIPS_ARG_DOUBLE(class, "max", 11, _("Max"), _("Maximum value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsClamp, max), -INFINITY, INFINITY, 1.0); } static void vips_clamp_init(VipsClamp *clamp) { clamp->min = 0.0; clamp->max = 1.0; } /** * vips_clamp: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * This operation clamps pixel values to a range, by default 0 - 1. * * Use @min and @max to change the range. * * ::: tip "Optional arguments" * * @min: `gdouble`, minimum value * * @max: `gdouble`, maximum value * * ::: seealso * [method@Image.sign], [method@Image.abs], [ctor@Image.sdf]. * * Returns: 0 on success, -1 on error */ int vips_clamp(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("clamp", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/complex.c000066400000000000000000000546141516303661500207160ustar00rootroot00000000000000/* complex.c ... various complex operations * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 12/02/1990 * Modified on : 09/05/1990 * 15/6/93 JC * - stupid stupid includes and externs fixed * - I have been editing for 1 1/2 hours and I'm still drowning in * rubbish extetrnshh * 13/12/94 JC * - modernised * 9/7/02 JC * - degree output, for consistency * - slightly better behaviour in edge cases * 27/1/10 * - modernised * - gtk-doc * 19/11/11 * - redo as a class * 21/11/11 * - add vips_complexget() * 29/9/15 * - return 0 for cross-product where one arg is zero */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" #include "binary.h" typedef struct _VipsComplex { VipsUnary parent_instance; VipsOperationComplex cmplx; } VipsComplex; typedef VipsUnaryClass VipsComplexClass; G_DEFINE_TYPE(VipsComplex, vips_complex, VIPS_TYPE_UNARY); #define LOOP(IN, OUT, OP) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) { \ OP(q, p[x], 0.0); \ \ q += 2; \ } \ } #define CLOOP(IN, OUT, OP) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) { \ OP(q, p[0], p[1]); \ \ p += 2; \ q += 2; \ } \ } #define SWITCH(OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ LOOP(unsigned char, float, OP); \ break; \ case VIPS_FORMAT_CHAR: \ LOOP(signed char, float, OP); \ break; \ case VIPS_FORMAT_USHORT: \ LOOP(unsigned short, float, OP); \ break; \ case VIPS_FORMAT_SHORT: \ LOOP(signed short, float, OP); \ break; \ case VIPS_FORMAT_UINT: \ LOOP(unsigned int, float, OP); \ break; \ case VIPS_FORMAT_INT: \ LOOP(signed int, float, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ LOOP(float, float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ LOOP(double, double, OP); \ break; \ case VIPS_FORMAT_COMPLEX: \ CLOOP(float, float, OP); \ break; \ case VIPS_FORMAT_DPCOMPLEX: \ CLOOP(double, double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } static double vips_complex_atan2(double a, double b) { double h; h = VIPS_DEG(atan2(b, a)); if (h < 0.0) h += 360; return h; } #define POLAR(Q, X, Y) \ { \ double re = (X); \ double im = (Y); \ double am, ph; \ \ am = hypot(re, im); \ ph = vips_complex_atan2(re, im); \ \ Q[0] = am; \ Q[1] = ph; \ } #define RECT(Q, X, Y) \ { \ double am = (X); \ double ph = (Y); \ double re, im; \ \ re = am * cos(VIPS_RAD(ph)); \ im = am * sin(VIPS_RAD(ph)); \ \ Q[0] = re; \ Q[1] = im; \ } #define CONJ(Q, X, Y) \ { \ double re = (X); \ double im = (Y); \ \ im *= -1; \ \ Q[0] = re; \ Q[1] = im; \ } static void vips_complex_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsComplex *cmplx = (VipsComplex *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (cmplx->cmplx) { case VIPS_OPERATION_COMPLEX_POLAR: SWITCH(POLAR); break; case VIPS_OPERATION_COMPLEX_RECT: SWITCH(RECT); break; case VIPS_OPERATION_COMPLEX_CONJ: SWITCH(CONJ); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_complex_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ X, X, X, X, X, X, X, X, DX, DX }; static void vips_complex_class_init(VipsComplexClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "complex"; object_class->description = _("perform a complex operation on an image"); aclass->process_line = vips_complex_buffer; vips_arithmetic_set_format_table(aclass, vips_complex_format_table); VIPS_ARG_ENUM(class, "cmplx", 200, _("Operation"), _("Complex to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsComplex, cmplx), VIPS_TYPE_OPERATION_COMPLEX, VIPS_OPERATION_COMPLEX_POLAR); } static void vips_complex_init(VipsComplex *cmplx) { } static int vips_complexv(VipsImage *in, VipsImage **out, VipsOperationComplex cmplx, va_list ap) { return vips_call_split("complex", ap, in, out, cmplx); } /** * vips_complex: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @cmplx: complex operation to perform * @...: `NULL`-terminated list of optional named arguments * * Perform various operations on complex images. * * Angles are expressed in degrees. The output type is complex unless the * input is double or dpcomplex, in which case the output is dpcomplex. * * Returns: 0 on success, -1 on error */ int vips_complex(VipsImage *in, VipsImage **out, VipsOperationComplex cmplx, ...) { va_list ap; int result; va_start(ap, cmplx); result = vips_complexv(in, out, cmplx, ap); va_end(ap); return result; } /** * vips_polar: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationComplex.POLAR] on an image. See [method@Image.complex]. * * Returns: 0 on success, -1 on error */ int vips_polar(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_complexv(in, out, VIPS_OPERATION_COMPLEX_POLAR, ap); va_end(ap); return result; } /** * vips_rect: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationComplex.RECT] on an image. See [method@Image.complex]. * * Returns: 0 on success, -1 on error */ int vips_rect(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_complexv(in, out, VIPS_OPERATION_COMPLEX_RECT, ap); va_end(ap); return result; } /** * vips_conj: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationComplex.CONJ] on an image. See [method@Image.complex]. * * Returns: 0 on success, -1 on error */ int vips_conj(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_complexv(in, out, VIPS_OPERATION_COMPLEX_CONJ, ap); va_end(ap); return result; } typedef struct _VipsComplex2 { VipsBinary parent_instance; VipsOperationComplex2 cmplx; } VipsComplex2; typedef VipsBinaryClass VipsComplex2Class; G_DEFINE_TYPE(VipsComplex2, vips_complex2, VIPS_TYPE_BINARY); #define LOOP2(IN, OUT, OP) \ { \ IN *p1 = (IN *) in[0]; \ IN *p2 = (IN *) in[1]; \ OUT *q = (OUT *) out; \ \ for (x = 0; x < sz; x++) { \ OP(q, p1[x], 0.0, p2[x], 0.0); \ \ q += 2; \ } \ } #define CLOOP2(IN, OUT, OP) \ { \ IN *p1 = (IN *) in[0]; \ IN *p2 = (IN *) in[1]; \ OUT *q = (OUT *) out; \ \ for (x = 0; x < sz; x++) { \ OP(q, p1[0], p1[1], p2[0], p2[1]); \ \ p1 += 2; \ p2 += 2; \ q += 2; \ } \ } #define SWITCH2(OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ LOOP2(unsigned char, float, OP); \ break; \ case VIPS_FORMAT_CHAR: \ LOOP2(signed char, float, OP); \ break; \ case VIPS_FORMAT_USHORT: \ LOOP2(unsigned short, float, OP); \ break; \ case VIPS_FORMAT_SHORT: \ LOOP2(signed short, float, OP); \ break; \ case VIPS_FORMAT_UINT: \ LOOP2(unsigned int, float, OP); \ break; \ case VIPS_FORMAT_INT: \ LOOP2(signed int, float, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ LOOP2(float, float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ LOOP2(double, double, OP); \ break; \ case VIPS_FORMAT_COMPLEX: \ CLOOP2(float, float, OP); \ break; \ case VIPS_FORMAT_DPCOMPLEX: \ CLOOP2(double, double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } #define CROSS(Q, X1, Y1, X2, Y2) \ { \ if (((X1) == 0.0 && (Y1) == 0.0) || \ ((X2) == 0.0 && (Y2) == 0.0) || \ ((Y1) == 0.0 && (Y2) == 0.0)) { \ Q[0] = 0.0; \ Q[1] = 0.0; \ } \ else if (ABS(Y1) > ABS(Y2)) { \ double y1 = Y1; /* this suppress C2142 (division by zero) error on MSVC */ \ double a = Y2 / y1; \ double b = Y1 + Y2 * a; \ double re = (X1 + X2 * a) / b; \ double im = (X2 - X1 * a) / b; \ double mod = hypot(re, im); \ \ Q[0] = re / mod; \ Q[1] = im / mod; \ } \ else { \ double y2 = Y2; \ double a = Y1 / y2; \ double b = Y2 + Y1 * a; \ double re = (X1 * a + X2) / b; \ double im = (X2 * a - X1) / b; \ double mod = hypot(re, im); \ \ Q[0] = re / mod; \ Q[1] = im / mod; \ } \ } static void vips_complex2_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsComplex2 *cmplx = (VipsComplex2 *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (cmplx->cmplx) { case VIPS_OPERATION_COMPLEX2_CROSS_PHASE: SWITCH2(CROSS); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_complex2_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ X, X, X, X, X, X, X, X, DX, DX }; static void vips_complex2_class_init(VipsComplex2Class *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "complex2"; object_class->description = _("complex binary operations on two images"); aclass->process_line = vips_complex2_buffer; vips_arithmetic_set_format_table(aclass, vips_complex2_format_table); VIPS_ARG_ENUM(class, "cmplx", 200, _("Operation"), _("Binary complex operation to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsComplex2, cmplx), VIPS_TYPE_OPERATION_COMPLEX2, VIPS_OPERATION_COMPLEX2_CROSS_PHASE); } static void vips_complex2_init(VipsComplex2 *cmplx) { } static int vips_complex2v(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationComplex2 cmplx, va_list ap) { return vips_call_split("complex2", ap, left, right, out, cmplx); } /** * vips_complex2: (method) * @left: input [class@Image] * @right: input [class@Image] * @out: (out): output [class@Image] * @cmplx: complex2 operation to perform * @...: `NULL`-terminated list of optional named arguments * * Perform various binary operations on complex images. * * Angles are expressed in degrees. The output type is complex unless the * input is double or dpcomplex, in which case the output is dpcomplex. * * Returns: 0 on success, -1 on error */ int vips_complex2(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationComplex2 cmplx, ...) { va_list ap; int result; va_start(ap, cmplx); result = vips_complex2v(left, right, out, cmplx, ap); va_end(ap); return result; } /** * vips_cross_phase: (method) * @left: input [class@Image] * @right: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationComplex2.CROSS_PHASE] on an image. * See [method@Image.complex2]. * * Returns: 0 on success, -1 on error */ int vips_cross_phase(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_complex2v(left, right, out, VIPS_OPERATION_COMPLEX2_CROSS_PHASE, ap); va_end(ap); return result; } typedef struct _VipsComplexget { VipsUnary parent_instance; VipsOperationComplexget get; } VipsComplexget; typedef VipsUnaryClass VipsComplexgetClass; G_DEFINE_TYPE(VipsComplexget, vips_complexget, VIPS_TYPE_UNARY); static int vips_complexget_build(VipsObject *object) { VipsUnary *unary = (VipsUnary *) object; VipsComplexget *complexget = (VipsComplexget *) object; if (unary->in && !vips_band_format_iscomplex(unary->in->BandFmt) && complexget->get == VIPS_OPERATION_COMPLEXGET_REAL) return vips_unary_copy(unary); if (VIPS_OBJECT_CLASS(vips_complexget_parent_class)->build(object)) return -1; return 0; } #define GETLOOP(TYPE, OP) \ { \ TYPE *p G_GNUC_UNUSED = (TYPE *) in[0]; \ TYPE *q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) { \ OP(q[x], p[x], 0.0); \ } \ } #define CGETLOOP(TYPE, OP) \ { \ TYPE *p G_GNUC_UNUSED = (TYPE *) in[0]; \ TYPE *q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) { \ OP(q[x], p[0], p[1]); \ \ p += 2; \ } \ } #define GETSWITCH(OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ GETLOOP(unsigned char, OP); \ break; \ case VIPS_FORMAT_CHAR: \ GETLOOP(signed char, OP); \ break; \ case VIPS_FORMAT_USHORT: \ GETLOOP(unsigned short, OP); \ break; \ case VIPS_FORMAT_SHORT: \ GETLOOP(signed short, OP); \ break; \ case VIPS_FORMAT_UINT: \ GETLOOP(unsigned int, OP); \ break; \ case VIPS_FORMAT_INT: \ GETLOOP(signed int, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ GETLOOP(float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ GETLOOP(double, OP); \ break; \ case VIPS_FORMAT_COMPLEX: \ CGETLOOP(float, OP); \ break; \ case VIPS_FORMAT_DPCOMPLEX: \ CGETLOOP(double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } #define REAL(Q, X, Y) \ { \ Q = X; \ } #define IMAG(Q, X, Y) \ { \ Q = Y; \ } static void vips_complexget_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsComplexget *complexget = (VipsComplexget *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (complexget->get) { case VIPS_OPERATION_COMPLEXGET_REAL: GETSWITCH(REAL); break; case VIPS_OPERATION_COMPLEXGET_IMAG: GETSWITCH(IMAG); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_complexget_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, F, D, D }; static void vips_complexget_class_init(VipsComplexgetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "complexget"; object_class->description = _("get a component from a complex image"); object_class->build = vips_complexget_build; aclass->process_line = vips_complexget_buffer; vips_arithmetic_set_format_table(aclass, vips_complexget_format_table); VIPS_ARG_ENUM(class, "get", 200, _("Operation"), _("Complex to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsComplexget, get), VIPS_TYPE_OPERATION_COMPLEXGET, VIPS_OPERATION_COMPLEXGET_REAL); } static void vips_complexget_init(VipsComplexget *complexget) { } static int vips_complexgetv(VipsImage *in, VipsImage **out, VipsOperationComplexget get, va_list ap) { return vips_call_split("complexget", ap, in, out, get); } /** * vips_complexget: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @get: complex operation to perform * @...: `NULL`-terminated list of optional named arguments * * Get components of complex images. * * The output type is the same as the input type, except [enum@Vips.BandFormat.COMPLEX] * becomes [enum@Vips.BandFormat.FLOAT] and [enum@Vips.BandFormat.DPCOMPLEX] becomes * [enum@Vips.BandFormat.DOUBLE]. * * Returns: 0 on success, -1 on error */ int vips_complexget(VipsImage *in, VipsImage **out, VipsOperationComplexget get, ...) { va_list ap; int result; va_start(ap, get); result = vips_complexgetv(in, out, get, ap); va_end(ap); return result; } /** * vips_real: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationComplexget.REAL] on an image. See [method@Image.complexget]. * * Returns: 0 on success, -1 on error */ int vips_real(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_complexgetv(in, out, VIPS_OPERATION_COMPLEXGET_REAL, ap); va_end(ap); return result; } /** * vips_imag: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationComplexget.IMAG] on an image. See [method@Image.complexget]. * * Returns: 0 on success, -1 on error */ int vips_imag(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_complexgetv(in, out, VIPS_OPERATION_COMPLEXGET_IMAG, ap); va_end(ap); return result; } typedef VipsBinary VipsComplexform; typedef VipsBinaryClass VipsComplexformClass; G_DEFINE_TYPE(VipsComplexform, vips_complexform, VIPS_TYPE_BINARY); static int vips_complexform_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBinary *binary = (VipsBinary *) object; if (binary->left && vips_check_noncomplex(class->nickname, binary->left)) return -1; if (binary->right && vips_check_noncomplex(class->nickname, binary->right)) return -1; if (VIPS_OBJECT_CLASS(vips_complexform_parent_class)->build(object)) return -1; return 0; } #define CFORM(IN, OUT) \ { \ IN *left = (IN *) in[0]; \ IN *right = (IN *) in[1]; \ OUT *q = (OUT *) out; \ \ for (x = 0; x < sz; x++) { \ q[0] = left[x]; \ q[1] = right[x]; \ \ q += 2; \ } \ } static void vips_complexform_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; /* Keep types here in sync with bandfmt_complexform[] * below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: CFORM(unsigned char, float); break; case VIPS_FORMAT_CHAR: CFORM(signed char, float); break; case VIPS_FORMAT_USHORT: CFORM(unsigned short, float); break; case VIPS_FORMAT_SHORT: CFORM(signed short, float); break; case VIPS_FORMAT_UINT: CFORM(unsigned int, float); break; case VIPS_FORMAT_INT: CFORM(signed int, float); break; case VIPS_FORMAT_FLOAT: CFORM(float, float); break; case VIPS_FORMAT_DOUBLE: CFORM(double, double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for form complex. Sign and value preserving. Make sure * these match the case statement in complexform_buffer() above. */ static VipsBandFormat vips_complexform_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ X, X, X, X, X, X, X, X, DX, DX }; static void vips_complexform_class_init(VipsComplexformClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "complexform"; object_class->description = _("form a complex image from two real images"); object_class->build = vips_complexform_build; aclass->process_line = vips_complexform_buffer; vips_arithmetic_set_format_table(aclass, vips_complexform_format_table); } static void vips_complexform_init(VipsComplexform *complexform) { } /** * vips_complexform: (method) * @left: input image * @right: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Compose two real images to make a complex image. If either @left or @right * are [enum@Vips.BandFormat.DOUBLE], @out is [enum@Vips.BandFormat.DPCOMPLEX]. Otherwise @out * is [enum@Vips.BandFormat.COMPLEX]. @left becomes the real component of @out and * @right the imaginary. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * ::: seealso * [method@Image.complexget]. * * Returns: 0 on success, -1 on error */ int vips_complexform(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("complexform", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/deviate.c000066400000000000000000000134141516303661500206610ustar00rootroot00000000000000/* VipsDeviate * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 02/08/1990 * Modified on: * 5/5/93 JC * - now does partial images * - less likely to overflow * - adapted from im_deviate * 1/7/93 JC * - adapted for partial v2 * - ANSIfied * 21/2/95 JC * - modernised again * 11/5/95 JC * - oops! return( NULL ) in im_deviate(), instead of return( -1 ) * 20/6/95 JC * - now returns double, not float * 13/1/05 * - use 64 bit arithmetic * 8/12/06 * - add liboil support * 2/9/09 * - gtk-doc comment * - minor reformatting * 4/9/09 * - use im__wrapscan() * 31/7/10 * - remove liboil * 6/11/11 * - rewrite as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "statistic.h" typedef struct _VipsDeviate { VipsStatistic parent_instance; double sum; double sum2; double out; } VipsDeviate; typedef VipsStatisticClass VipsDeviateClass; G_DEFINE_TYPE(VipsDeviate, vips_deviate, VIPS_TYPE_STATISTIC); static int vips_deviate_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsDeviate *deviate = (VipsDeviate *) object; guint64 vals; double s, s2; if (statistic->in && vips_check_noncomplex(class->nickname, statistic->in)) return -1; if (VIPS_OBJECT_CLASS(vips_deviate_parent_class)->build(object)) return -1; /* NOTE: NR suggests a two-pass algorithm to minimise roundoff. But that's too expensive for us :-( so do it the old one-pass way. */ /* Calculate and return deviation. Add a fabs to stop sqrt(<=0). */ vals = VIPS_IMAGE_N_PELS(statistic->ready) * vips_image_get_bands(statistic->ready); s = deviate->sum; s2 = deviate->sum2; g_object_set(object, "out", sqrt(fabs(s2 - (s * s / vals)) / (vals - 1)), NULL); return 0; } /* Start function: allocate space for an array in which we can accumulate the * sum and sum of squares for this thread. */ static void * vips_deviate_start(VipsStatistic *statistic) { return (void *) g_new0(double, 2); } /* Stop function. Add this little sum to the main sum. */ static int vips_deviate_stop(VipsStatistic *statistic, void *seq) { VipsDeviate *deviate = (VipsDeviate *) statistic; double *ss2 = (double *) seq; deviate->sum += ss2[0]; deviate->sum2 += ss2[1]; g_free(ss2); return 0; } #define LOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ \ for (x = 0; x < sz; x++) { \ TYPE v = p[x]; \ \ sum += v; \ sum2 += (double) v * (double) v; \ } \ } static int vips_deviate_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { const int sz = n * vips_image_get_bands(statistic->ready); double *ss2 = (double *) seq; double sum; double sum2; sum = ss2[0]; sum2 = ss2[1]; /* Now generate code for all types. */ switch (vips_image_get_format(statistic->ready)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOP(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOP(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int); break; case VIPS_FORMAT_FLOAT: LOOP(float); break; case VIPS_FORMAT_DOUBLE: LOOP(double); break; default: g_assert_not_reached(); } ss2[0] = sum; ss2[1] = sum2; return 0; } static void vips_deviate_class_init(VipsDeviateClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "deviate"; object_class->description = _("find image standard deviation"); object_class->build = vips_deviate_build; sclass->start = vips_deviate_start; sclass->scan = vips_deviate_scan; sclass->stop = vips_deviate_stop; VIPS_ARG_DOUBLE(class, "out", 2, _("Output"), _("Output value"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsDeviate, out), -INFINITY, INFINITY, 0.0); } static void vips_deviate_init(VipsDeviate *deviate) { } /** * vips_deviate: (method) * @in: input [class@Image] * @out: (out): output pixel standard deviation * @...: `NULL`-terminated list of optional named arguments * * This operation finds the standard deviation of all pixels in @in. It * operates on all bands of the input image: use [method@Image.stats] if you need * to calculate an average for each band. * * Non-complex images only. * * ::: seealso * [method@Image.avg], [method@Image.stats].. * * Returns: 0 on success, -1 on error */ int vips_deviate(VipsImage *in, double *out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("deviate", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/divide.c000066400000000000000000000155201516303661500205040ustar00rootroot00000000000000/* Divide two images * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 29/4/93 JC * - now works for partial images * 1/7/93 JC * - adapted for partial v2 * - ANSIfied * 19/10/93 JC * - coredump-inducing bug in complex*complex fixed * 13/12/93 * - char * short bug fixed * 12/6/95 JC * - new im_multiply adapted to make new im_divide * 27/9/04 * - updated for 1 band $op n band image -> n band image case * 8/12/06 * - add liboil support * 18/8/08 * - revise upcasting system * - add gtkdoc comments * 31/7/10 * - remove liboil support * - avoid /0 * 6/11/11 * - rewrite as a class * 22/2/12 * - avoid /0 for complex as well * 6/4/12 * - fixed switch cases * - fixed int operands with <1 result */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" typedef VipsBinary VipsDivide; typedef VipsBinaryClass VipsDivideClass; G_DEFINE_TYPE(VipsDivide, vips_divide, VIPS_TYPE_BINARY); #define CLOOP(TYPE) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ int i; \ \ for (i = 0; i < sz; i++) { \ if (right[0] == 0.0 && \ right[1] == 0.0) { \ q[0] = 0.0; \ q[1] = 0.0; \ } \ else if (fabs(right[0]) > fabs(right[1])) { \ double a = right[1] / right[0]; \ double b = right[0] + right[1] * a; \ \ q[0] = (left[0] + left[1] * a) / b; \ q[1] = (left[1] - left[0] * a) / b; \ } \ else { \ double a = right[0] / right[1]; \ double b = right[1] + right[0] * a; \ \ q[0] = (left[0] * a + left[1]) / b; \ q[1] = (left[1] * a - left[0]) / b; \ } \ \ left += 2; \ right += 2; \ q += 2; \ } \ } /* Real divide. Cast in to OUT before divide so we work for float output. */ #define RLOOP(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = right[x] == 0 ? 0 : (OUT) left[x] / (OUT) right[x]; \ } static void vips_divide_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; /* Keep types here in sync with vips_divide_format_table[] * below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: RLOOP(signed char, float); break; case VIPS_FORMAT_UCHAR: RLOOP(unsigned char, float); break; case VIPS_FORMAT_SHORT: RLOOP(signed short, float); break; case VIPS_FORMAT_USHORT: RLOOP(unsigned short, float); break; case VIPS_FORMAT_INT: RLOOP(signed int, float); break; case VIPS_FORMAT_UINT: RLOOP(unsigned int, float); break; case VIPS_FORMAT_FLOAT: RLOOP(float, float); break; case VIPS_FORMAT_DOUBLE: RLOOP(double, double); break; case VIPS_FORMAT_COMPLEX: CLOOP(float); break; case VIPS_FORMAT_DPCOMPLEX: CLOOP(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for division. Sign and value preserving. Make sure * these match the case statement in divide_buffer() above. */ static VipsBandFormat vips_divide_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ F, F, F, F, F, F, F, X, D, DX }; static void vips_divide_class_init(VipsDivideClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "divide"; object_class->description = _("divide two images"); aclass->process_line = vips_divide_buffer; vips_arithmetic_set_format_table(aclass, vips_divide_format_table); } static void vips_divide_init(VipsDivide *divide) { } /** * vips_divide: (method) * @left: input image * @right: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @in1 / @in2 and writes the result to @out. If any * pixels in @in2 are zero, the corresponding pixel in @out is also zero. * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), then the * following table is used to determine the output type: * * ## [method@Image.divide] type promotion * * | input type | output type | * |----------------|----------------| * | uchar | float | * | char | float | * | ushort | float | * | short | float | * | uint | float | * | int | float | * | float | float | * | double | double | * | complex | complex | * | double complex | double complex | * * In other words, the output type is just large enough to hold the whole * range of possible values. * * ::: seealso * [method@Image.multiply], [method@Image.linear], [method@Image.pow]. * * Returns: 0 on success, -1 on error */ int vips_divide(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("divide", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/find_trim.c000066400000000000000000000176351516303661500212240ustar00rootroot00000000000000/* return the bounding box of the non-border part of the image * * 26/7/17 * - from a ruby example * 18/9/17 kleisauke * - missing bandor * - only flatten if there is an alpha * 8/2/23 * - add @line_art */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsFindTrim { VipsOperation parent_instance; VipsImage *in; double threshold; VipsArrayDouble *background; gboolean line_art; int left; int top; int width; int height; } VipsFindTrim; typedef VipsOperationClass VipsFindTrimClass; G_DEFINE_TYPE(VipsFindTrim, vips_find_trim, VIPS_TYPE_OPERATION); static int vips_find_trim_build(VipsObject *object) { VipsFindTrim *find_trim = (VipsFindTrim *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 20); VipsImage *in; double *background; int n; double *neg_bg; double *ones; int i; double left; double top; double right; double bottom; if (VIPS_OBJECT_CLASS(vips_find_trim_parent_class)->build(object)) return -1; /* Is "background" unset? Default to the correct value * for this interpretation. */ if (!vips_object_argument_isset(object, "background")) find_trim->background = vips_array_double_newv(1, // FIXME: Invalidates operation cache vips_interpretation_max_alpha(find_trim->in->Type)); /* Flatten out alpha, if any. */ in = find_trim->in; if (vips_image_hasalpha(in)) { if (vips_flatten(in, &t[0], "background", find_trim->background, NULL)) return -1; in = t[0]; } /* We want to subtract the bg. */ background = vips_array_double_get(find_trim->background, &n); if (!(neg_bg = VIPS_ARRAY(find_trim, n, double)) || !(ones = VIPS_ARRAY(find_trim, n, double))) return -1; for (i = 0; i < n; i++) { neg_bg[i] = -1 * background[i]; ones[i] = 1.0; } /* Filter out noise, unless we're in line_art mode. */ if (!find_trim->line_art) { if (vips_median(in, &t[1], 3, NULL)) return -1; in = t[1]; } /* Find difference from bg, abs, threshold. */ if (vips_linear(in, &t[2], ones, neg_bg, n, NULL) || vips_abs(t[2], &t[3], NULL) || vips_more_const1(t[3], &t[4], find_trim->threshold, NULL) || vips_bandor(t[4], &t[5], NULL)) return -1; in = t[5]; /* t[6] == column sums, t[7] == row sums. */ if (vips_project(in, &t[6], &t[7], NULL)) return -1; /* t[8] == search column sums in from left. */ if (vips_profile(t[6], &t[8], &t[9], NULL) || vips_avg(t[9], &left, NULL)) return -1; if (vips_flip(t[6], &t[10], VIPS_DIRECTION_HORIZONTAL, NULL) || vips_profile(t[10], &t[11], &t[12], NULL) || vips_avg(t[12], &right, NULL)) return -1; /* t[8] == search column sums in from left. */ if (vips_profile(t[7], &t[13], &t[14], NULL) || vips_avg(t[13], &top, NULL)) return -1; if (vips_flip(t[7], &t[15], VIPS_DIRECTION_VERTICAL, NULL) || vips_profile(t[15], &t[16], &t[17], NULL) || vips_avg(t[16], &bottom, NULL)) return -1; g_object_set(find_trim, "left", (int) left, "top", (int) top, "width", (int) VIPS_MAX(0, (t[6]->Xsize - right) - left), "height", (int) VIPS_MAX(0, (t[7]->Ysize - bottom) - top), NULL); return 0; } static void vips_find_trim_class_init(VipsFindTrimClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "find_trim"; object_class->description = _("search an image for non-edge areas"); object_class->build = vips_find_trim_build; // operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Image to find_trim"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFindTrim, in)); VIPS_ARG_DOUBLE(class, "threshold", 2, _("Threshold"), _("Object threshold"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsFindTrim, threshold), 0, INFINITY, 10.0); VIPS_ARG_BOXED(class, "background", 3, _("Background"), _("Color for background pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsFindTrim, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOOL(class, "line_art", 4, _("Line art mode"), _("Enable line art mode"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsFindTrim, line_art), FALSE); VIPS_ARG_INT(class, "left", 5, _("Left"), _("Left edge of image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsFindTrim, left), 0, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "top", 11, _("Top"), _("Top edge of extract area"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsFindTrim, top), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "width", 12, _("Width"), _("Width of extract area"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsFindTrim, width), 0, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 13, _("Height"), _("Height of extract area"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsFindTrim, height), 0, VIPS_MAX_COORD, 1); } static void vips_find_trim_init(VipsFindTrim *find_trim) { find_trim->threshold = 10; } /** * vips_find_trim: (method) * @in: image to find_trim * @left: (out): output left edge * @top: (out): output top edge * @width: (out): output width * @height: (out): output height * @...: `NULL`-terminated list of optional named arguments * * Search @in for the bounding box of the non-background area. * * Any alpha is flattened out, then the image is median-filtered (unless * @line_art is set, see below). The absolute difference from @background is * computed and binarized according to @threshold. Row and column sums of * the absolute difference are calculated from this binary image and searched * for the first row or column in each direction to obtain the bounding box. * * If the image is entirely background, [method@Image.find_trim] returns * @width == 0 and @height == 0. * * @background defaults to 255, or 65535 for 16-bit images. Set another value, * or use [method@Image.getpoint] to pick a value from an edge. You'll need * to flatten before [method@Image.getpoint] to get a correct background value. * * @threshold defaults to 10. * * The detector is designed for photographic or compressed images where there * is a degree of noise that needs filtering. If your images are synthetic * (eg. rendered from vector art, perhaps), set @line_art to disable this * filtering. * * The image needs to be at least 3x3 pixels in size. * * ::: tip "Optional arguments" * * @threshold: `gdouble`, background / object threshold * * @background: [struct@ArrayDouble], background colour * * @line_art: `gboolean`, enable line art mode * * ::: seealso * [method@Image.getpoint], [method@Image.extract_area], [method@Image.smartcrop]. * * Returns: 0 on success, -1 on error */ int vips_find_trim(VipsImage *in, int *left, int *top, int *width, int *height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("find_trim", ap, in, left, top, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/getpoint.c000066400000000000000000000135631516303661500210760ustar00rootroot00000000000000/* read a single getpoint * * Copyright: J. Cupitt * Written: 15/06/1992 * 22/7/93 JC * - im_incheck() added * 16/8/94 JC * - im_incheck() changed to im_makerw() * 5/12/06 * - im_invalidate() after paint * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 29/9/10 * - gtk-doc * - use Draw base class * - read_getpoint partial-ised * 10/2/14 * - redo as a class * 16/12/14 * - free the input region much earlier * 14/10/16 * - crop to a memory image rather than using a region ... this means we * use workers to calculate pixels and therefore use per-thread caching * in the revised buffer system * 26/8/24 * - add "unpack_complex" */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "statistic.h" typedef struct _VipsGetpoint { VipsOperation parent_instance; VipsImage *in; int x; int y; gboolean unpack_complex; VipsArrayDouble *out_array; } VipsGetpoint; typedef VipsOperationClass VipsGetpointClass; G_DEFINE_TYPE(VipsGetpoint, vips_getpoint, VIPS_TYPE_OPERATION); static int vips_getpoint_build(VipsObject *object) { VipsGetpoint *getpoint = (VipsGetpoint *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsArrayDouble *out_array; if (VIPS_OBJECT_CLASS(vips_getpoint_parent_class)->build(object)) return -1; /* Unpack to double. Complex unpacks to 2 * bands. */ gboolean iscomplex = getpoint->unpack_complex && vips_band_format_iscomplex(getpoint->in->BandFmt); int target_bands = iscomplex ? getpoint->in->Bands * 2 : getpoint->in->Bands; VipsBandFormat target_format = iscomplex ? VIPS_FORMAT_DPCOMPLEX : VIPS_FORMAT_DOUBLE; /* Crop, decode and unpack to double. */ if (vips_crop(getpoint->in, &t[0], getpoint->x, getpoint->y, 1, 1, NULL) || vips_image_decode(t[0], &t[1]) || vips_cast(t[1], &t[2], target_format, NULL)) return -1; /* To a mem buffer, then copy to out. */ vips_image_set_int(t[2], "hide-progress", 1); if (!(t[3] = vips_image_new_memory()) || vips_image_write(t[2], t[3])) return -1; out_array = vips_array_double_new((double *) t[3]->data, target_bands); g_object_set(object, "out_array", out_array, NULL); vips_area_unref(VIPS_AREA(out_array)); return 0; } static void vips_getpoint_class_init(VipsGetpointClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "getpoint"; object_class->description = _("read a point from an image"); object_class->build = vips_getpoint_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGetpoint, in)); VIPS_ARG_BOXED(class, "out_array", 2, _("Output array"), _("Array of output values"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsGetpoint, out_array), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_INT(class, "x", 5, _("x"), _("Point to read"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGetpoint, x), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "y", 6, _("y"), _("Point to read"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGetpoint, y), 0, VIPS_MAX_COORD, 0); VIPS_ARG_BOOL(class, "unpack_complex", 7, _("unpack_complex"), _("Complex pixels should be unpacked"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGetpoint, unpack_complex), FALSE); } static void vips_getpoint_init(VipsGetpoint *getpoint) { } /** * vips_getpoint: (method) * @in: image to read from * @vector: (out)(array length=n): output pixel value here * @n: length of output vector * @x: position to read * @y: position to read * @...: `NULL`-terminated list of optional named arguments * * Reads a single pixel on an image. * * The pixel values are returned in @vector, the length of the * array in @n. You must free the array with [func@GLib.free] when you are * done with it. * * The result array has an element for each band. If @unpack_complex is set, * pixels in complex images are returned as double-length arrays. * * This operation is slow. If you want to read many points, use * [method@Image.write_to_memory]. * * ::: seealso * [method@Image.draw_point], [method@Image.write_to_memory]. * * Returns: 0 on success, or -1 on error. */ int vips_getpoint(VipsImage *in, double **vector, int *n, int x, int y, ...) { va_list ap; VipsArrayDouble *out_array; VipsArea *area; int result; va_start(ap, y); result = vips_call_split("getpoint", ap, in, &out_array, x, y); va_end(ap); if (result) return -1; area = VIPS_AREA(out_array); *vector = VIPS_ARRAY(NULL, area->n, double); if (!*vector) { vips_area_unref(area); return -1; } memcpy(*vector, area->data, area->n * area->sizeof_type); *n = area->n; vips_area_unref(area); return 0; } libvips-8.18.2/libvips/arithmetic/hist_find.c000066400000000000000000000245101516303661500212060ustar00rootroot00000000000000/* find histograms * * Copyright: 1990, 1991, N. Dessipris. * * Author: Nicos Dessipris. * Written on: 09/07/1990 * Modified on : 11/03/1991 * 19/7/93 JC * - test for Coding type added * 26/10/94 JC * - rewritten for ANSI * - now does USHORT too * - 5 x faster! * 2/6/95 JC * - rewritten for partials * 3/3/01 JC * - tiny speed ups * 21/1/07 * - number bands from zero * 24/3/10 * - gtkdoc * - small cleanups * 25/1/12 * - cast @in to u8/u16. * 12/8/13 * - redo as a class * 28/2/16 lovell * - unroll common cases * 1/2/21 erdmann * - use double for very large histograms */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "statistic.h" /* Accumulate a histogram in one of these. */ typedef struct { int n_bands; /* Number of bands in output */ int band; /* If one band in out, which band of input */ int size; /* Number of bins for each band */ int mx; /* Maximum value we have seen */ VipsPel **bins; /* double or uint bins */ } Histogram; typedef struct _VipsHistFind { VipsStatistic parent_instance; /* -1 for all bands, or the band we scan. */ int band; /* Main image histogram. Subhists accumulate to this. */ Histogram *hist; /* Write hist to this output image. */ VipsImage *out; /* TRUE for "large" histograms ... causes double output rather than * uint. */ gboolean large; } VipsHistFind; typedef VipsStatisticClass VipsHistFindClass; G_DEFINE_TYPE(VipsHistFind, vips_hist_find, VIPS_TYPE_STATISTIC); /* Build a Histogram. */ static Histogram * histogram_new(VipsHistFind *hist_find, int n_bands, int band, int size) { /* We won't use all of this for uint accumulators. */ int n_bytes = size * sizeof(double); Histogram *hist; int i; if (!(hist = VIPS_NEW(hist_find, Histogram)) || !(hist->bins = VIPS_ARRAY(hist_find, n_bands, VipsPel *))) return NULL; for (i = 0; i < n_bands; i++) { if (!(hist->bins[i] = VIPS_ARRAY(hist_find, n_bytes, VipsPel))) return NULL; memset(hist->bins[i], 0, n_bytes); } hist->n_bands = n_bands; hist->band = band; hist->size = size; hist->mx = 0; return hist; } static int vips_hist_find_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsHistFind *hist_find = (VipsHistFind *) object; VipsImage *in = statistic->in; VipsPel *obuffer; g_object_set(object, "out", vips_image_new(), NULL); if (in && vips_check_bandno(class->nickname, in, hist_find->band)) return -1; /* Is this a large histogram? We want to avoid overflow of the uint * accumulators. */ if (in && (guint64) in->Xsize * (guint64) in->Ysize >= ((guint64) 1 << 32)) hist_find->large = TRUE; /* main hist made on in vips_hist_find_start(). */ if (VIPS_OBJECT_CLASS(vips_hist_find_parent_class)->build(object)) return -1; /* Make the output image. */ if (vips_image_pipelinev(hist_find->out, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL)) return -1; vips_image_init_fields(hist_find->out, hist_find->hist->mx + 1, 1, hist_find->hist->n_bands, hist_find->large ? VIPS_FORMAT_DOUBLE : VIPS_FORMAT_UINT, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); /* Interleave for output. */ if (!(obuffer = VIPS_ARRAY(object, VIPS_IMAGE_SIZEOF_LINE(hist_find->out), VipsPel))) return -1; #define INTERLEAVE(TYPE) \ G_STMT_START \ { \ TYPE **bins = (TYPE **) hist_find->hist->bins; \ \ TYPE *q; \ int i, j; \ \ for (q = (TYPE *) obuffer, j = 0; j < hist_find->out->Xsize; j++) \ for (i = 0; i < hist_find->out->Bands; i++) \ *q++ = bins[i][j]; \ } \ G_STMT_END if (hist_find->large) INTERLEAVE(double); else INTERLEAVE(unsigned int); if (vips_image_write_line(hist_find->out, 0, obuffer)) return -1; return 0; } /* Build a sub-hist, based on the main hist. */ static void * vips_hist_find_start(VipsStatistic *statistic) { VipsHistFind *hist_find = (VipsHistFind *) statistic; /* Make the main hist, if necessary. */ if (!hist_find->hist) hist_find->hist = histogram_new(hist_find, hist_find->band == -1 ? statistic->ready->Bands : 1, hist_find->band, statistic->ready->BandFmt == VIPS_FORMAT_UCHAR ? 256 : 65536); return (void *) histogram_new(hist_find, hist_find->hist->n_bands, hist_find->hist->band, hist_find->hist->size); } /* Join a sub-hist onto the main hist. */ static int vips_hist_find_stop(VipsStatistic *statistic, void *seq) { Histogram *sub_hist = (Histogram *) seq; VipsHistFind *hist_find = (VipsHistFind *) statistic; Histogram *hist = hist_find->hist; int i, j; g_assert(sub_hist->n_bands == hist->n_bands && sub_hist->size == hist->size); /* Add on sub-data. */ hist->mx = VIPS_MAX(hist->mx, sub_hist->mx); #define SUM(TYPE) \ G_STMT_START \ { \ TYPE **main_bins = (TYPE **) hist->bins; \ TYPE **sub_bins = (TYPE **) sub_hist->bins; \ \ for (i = 0; i < hist->n_bands; i++) \ for (j = 0; j < hist->size; j++) \ main_bins[i][j] += sub_bins[i][j]; \ } \ G_STMT_END if (hist_find->large) SUM(double); else SUM(unsigned int); /* Blank out sub-hist to make sure we can't add it again. */ sub_hist->mx = 0; for (i = 0; i < sub_hist->n_bands; i++) sub_hist->bins[i] = NULL; return 0; } #define SCANOP \ G_STMT_START \ { \ for (z = 0; z < nb; z++) { \ int v = p[z]; \ \ if (v > mx) \ mx = v; \ \ bins[z][v] += 1; \ } \ \ p += nb; \ } \ G_STMT_END /* No need to track max for uchar images (it's always 255). */ #define UCSCANOP \ G_STMT_START \ { \ for (z = 0; z < nb; z++) { \ int v = p[z]; \ \ bins[z][v] += 1; \ } \ \ p += nb; \ } \ G_STMT_END /* Hist of all bands. This one is just about worth unrolling. */ #define SCAN(IMAGE_TYPE, HIST_TYPE, OP) \ G_STMT_START \ { \ HIST_TYPE **bins = (HIST_TYPE **) hist->bins; \ IMAGE_TYPE *p = (IMAGE_TYPE *) in; \ \ int z; \ \ VIPS_UNROLL(n, OP); \ } \ G_STMT_END /* Hist of selected band. */ #define SCAN1(IMAGE_TYPE, HIST_TYPE) \ G_STMT_START \ { \ HIST_TYPE *bins = (HIST_TYPE *) hist->bins[0]; \ IMAGE_TYPE *p = (IMAGE_TYPE *) in; \ int max = nb * n; \ \ for (i = hist->band; i < max; i += nb) { \ int v = p[i]; \ \ if (v > mx) \ mx = v; \ \ bins[v] += 1; \ } \ } \ G_STMT_END static int vips_hist_find_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { VipsHistFind *hist_find = (VipsHistFind *) statistic; Histogram *hist = (Histogram *) seq; int nb = statistic->ready->Bands; int mx = hist->mx; int i; if (hist_find->band < 0) switch (statistic->ready->BandFmt) { case VIPS_FORMAT_UCHAR: if (hist_find->large) SCAN(unsigned char, double, UCSCANOP); else SCAN(unsigned char, unsigned int, UCSCANOP); mx = 255; break; case VIPS_FORMAT_USHORT: if (hist_find->large) SCAN(unsigned short, double, SCANOP); else SCAN(unsigned short, unsigned int, SCANOP); break; default: g_assert_not_reached(); } else switch (statistic->ready->BandFmt) { case VIPS_FORMAT_UCHAR: if (hist_find->large) SCAN1(unsigned char, double); else SCAN1(unsigned char, unsigned int); break; case VIPS_FORMAT_USHORT: if (hist_find->large) SCAN1(unsigned short, double); else SCAN1(unsigned short, unsigned int); break; default: g_assert_not_reached(); } hist->mx = mx; return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT /* Type mapping: go to uchar or ushort. */ static const VipsBandFormat vips_hist_find_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, US, US, US, US, US, US }; static void vips_hist_find_class_init(VipsHistFindClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_find"; object_class->description = _("find image histogram"); object_class->build = vips_hist_find_build; sclass->start = vips_hist_find_start; sclass->scan = vips_hist_find_scan; sclass->stop = vips_hist_find_stop; sclass->format_table = vips_hist_find_format_table; VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output histogram"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistFind, out)); VIPS_ARG_INT(class, "band", 110, _("Band"), _("Find histogram of band"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHistFind, band), -1, 100000, -1); } static void vips_hist_find_init(VipsHistFind *hist_find) { hist_find->band = -1; } /** * vips_hist_find: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Find the histogram of @in. Find the histogram for band @band (producing a * one-band histogram), or for all bands (producing an n-band histogram) if * @band is -1. * * char and uchar images are cast to uchar before histogramming, all other * image types are cast to ushort. * * ::: tip "Optional arguments" * * @band: `gint`, band to equalise * * ::: seealso * [method@Image.hist_find_ndim], [method@Image.hist_find_indexed]. * * Returns: 0 on success, -1 on error */ int vips_hist_find(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_find", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/hist_find_indexed.c000066400000000000000000000304271516303661500227120ustar00rootroot00000000000000/* indexed histogram: use an index image to pick the bins * * 13/10/09 * - from im_histgr.c * 24/3/10 * - gtkdoc * 17/8/13 * - redo as a class * 2/11/17 * - add @combine ... pick a bin combine mode */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "statistic.h" struct _VipsHistFindIndexed; /* Accumulate a histogram in one of these. */ typedef struct { struct _VipsHistFindIndexed *indexed; VipsRegion *reg; /* Get index pixels with this */ int size; /* Length of bins */ int mx; /* Maximum value we have seen */ double *bins; /* All the bins! */ int *init; /* TRUE for bin has been initialised */ } Histogram; typedef struct _VipsHistFindIndexed { VipsStatistic parent_instance; VipsImage *index; /* Index image, cast to uchar/ushort. */ VipsImage *index_ready; /* Main image histogram. Subhists accumulate to this. */ Histogram *hist; /* Write hist to this output image. */ VipsImage *out; /* Combine bins with this. */ VipsCombine combine; } VipsHistFindIndexed; typedef VipsStatisticClass VipsHistFindIndexedClass; G_DEFINE_TYPE(VipsHistFindIndexed, vips_hist_find_indexed, VIPS_TYPE_STATISTIC); static Histogram * histogram_new(VipsHistFindIndexed *indexed) { VipsStatistic *statistic = VIPS_STATISTIC(indexed); int bands = statistic->ready->Bands; Histogram *hist; if (!(hist = VIPS_NEW(indexed, Histogram))) return NULL; hist->indexed = indexed; hist->reg = NULL; hist->size = indexed->index_ready->BandFmt == VIPS_FORMAT_UCHAR ? 256 : 65536; hist->mx = 0; hist->bins = NULL; hist->init = NULL; if (!(hist->bins = VIPS_ARRAY(indexed, bands * hist->size, double)) || !(hist->init = VIPS_ARRAY(indexed, hist->size, int)) || !(hist->reg = vips_region_new(indexed->index_ready))) return NULL; memset(hist->bins, 0, (size_t) bands * hist->size * sizeof(double)); memset(hist->init, 0, (size_t) hist->size * sizeof(int)); return hist; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT /* Type mapping: go to uchar or ushort. */ static const VipsBandFormat vips_hist_find_indexed_format[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, US, US, US, US, US, US }; static int vips_hist_find_indexed_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); g_object_set(object, "out", vips_image_new(), NULL); /* main hist made on first thread start. */ /* index image must be cast to uchar/ushort. */ if (indexed->index && statistic->in) { if (vips_check_uncoded(class->nickname, indexed->index) || vips_check_size_same(class->nickname, indexed->index, statistic->in) || vips_check_mono(class->nickname, indexed->index)) return -1; if (vips_cast(indexed->index, &t[0], vips_hist_find_indexed_format[indexed->index->BandFmt], NULL)) return -1; indexed->index_ready = t[0]; } if (statistic->in) if (vips_check_noncomplex(class->nickname, statistic->in)) return -1; if (VIPS_OBJECT_CLASS(vips_hist_find_indexed_parent_class)->build(object)) return -1; VIPS_UNREF(indexed->hist->reg); if (vips_image_pipelinev(indexed->out, VIPS_DEMAND_STYLE_ANY, statistic->ready, indexed->index_ready, NULL)) return -1; vips_image_init_fields(indexed->out, indexed->hist->mx + 1, 1, statistic->ready->Bands, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (vips_image_write_line(indexed->out, 0, (VipsPel *) indexed->hist->bins)) return -1; return 0; } static void * vips_hist_find_indexed_start(VipsStatistic *statistic) { VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) statistic; /* Make the main hist, if necessary. */ if (!indexed->hist) indexed->hist = histogram_new(indexed); return (void *) histogram_new(indexed); } /* Combine B with A according to mode. */ #define COMBINE(MODE, A, B) \ G_STMT_START \ { \ switch (MODE) { \ case VIPS_COMBINE_MAX: \ (A) = VIPS_MAX(A, B); \ break; \ \ case VIPS_COMBINE_SUM: \ (A) += (B); \ break; \ \ case VIPS_COMBINE_MIN: \ (A) = VIPS_MIN(A, B); \ break; \ \ default: \ g_assert_not_reached(); \ } \ } \ G_STMT_END /* Join a sub-hist onto the main hist. */ static int vips_hist_find_indexed_stop(VipsStatistic *statistic, void *seq) { Histogram *sub_hist = (Histogram *) seq; VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) statistic; Histogram *hist = indexed->hist; int bands = statistic->ready->Bands; int i, j; double *bins; double *sub_bins; int *init; int *sub_init; hist->mx = VIPS_MAX(hist->mx, sub_hist->mx); bins = hist->bins; sub_bins = sub_hist->bins; init = hist->init; sub_init = sub_hist->init; for (i = 0; i <= sub_hist->mx; i++) { if (sub_init[i]) { if (init[i]) for (j = 0; j < bands; j++) COMBINE(indexed->combine, bins[j], sub_bins[j]); else { for (j = 0; j < bands; j++) bins[j] = sub_bins[j]; init[i] = TRUE; } } bins += bands; sub_bins += bands; } VIPS_UNREF(sub_hist->reg); return 0; } /* Accumulate a buffer of pels, uchar index. */ #define ACCUMULATE_UCHAR(TYPE) \ { \ int x, z; \ TYPE *tv = (TYPE *) in; \ \ for (x = 0; x < n; x++) { \ int ix = i[x]; \ double *bin = hist->bins + ix * bands; \ \ if (hist->init[ix]) \ for (z = 0; z < bands; z++) \ COMBINE(indexed->combine, bin[z], tv[z]); \ else { \ for (z = 0; z < bands; z++) \ bin[z] = tv[z]; \ hist->init[ix] = TRUE; \ } \ \ tv += bands; \ } \ } /* A uchar index image. */ static void vips_hist_find_indexed_uchar_scan(VipsHistFindIndexed *indexed, Histogram *hist, void *in, void *index, int n) { VipsStatistic *statistic = VIPS_STATISTIC(indexed); int bands = statistic->ready->Bands; unsigned char *i = (unsigned char *) index; switch (statistic->ready->BandFmt) { case VIPS_FORMAT_UCHAR: ACCUMULATE_UCHAR(unsigned char); break; case VIPS_FORMAT_CHAR: ACCUMULATE_UCHAR(signed char); break; case VIPS_FORMAT_USHORT: ACCUMULATE_UCHAR(unsigned short); break; case VIPS_FORMAT_SHORT: ACCUMULATE_UCHAR(signed short); break; case VIPS_FORMAT_UINT: ACCUMULATE_UCHAR(unsigned int); break; case VIPS_FORMAT_INT: ACCUMULATE_UCHAR(signed int); break; case VIPS_FORMAT_FLOAT: ACCUMULATE_UCHAR(float); break; case VIPS_FORMAT_DOUBLE: ACCUMULATE_UCHAR(double); break; default: g_assert_not_reached(); } /* Max is always 255. */ hist->mx = 255; } /* Accumulate a buffer of pels, ushort index. */ #define ACCUMULATE_USHORT(TYPE) \ { \ int x, z; \ TYPE *tv = (TYPE *) in; \ \ for (x = 0; x < n; x++) { \ int ix = i[x]; \ double *bin = hist->bins + ix * bands; \ \ if (ix > mx) \ mx = ix; \ \ if (hist->init[ix]) \ for (z = 0; z < bands; z++) \ COMBINE(indexed->combine, bin[z], tv[z]); \ else { \ for (z = 0; z < bands; z++) \ bin[z] = tv[z]; \ hist->init[ix] = TRUE; \ } \ \ tv += bands; \ } \ } /* A ushort index image. */ static void vips_hist_find_indexed_ushort_scan(VipsHistFindIndexed *indexed, Histogram *hist, void *in, void *index, int n) { VipsStatistic *statistic = VIPS_STATISTIC(indexed); int bands = statistic->ready->Bands; unsigned short *i = (unsigned short *) index; int mx; mx = hist->mx; switch (statistic->ready->BandFmt) { case VIPS_FORMAT_UCHAR: ACCUMULATE_USHORT(unsigned char); break; case VIPS_FORMAT_CHAR: ACCUMULATE_USHORT(signed char); break; case VIPS_FORMAT_USHORT: ACCUMULATE_USHORT(unsigned short); break; case VIPS_FORMAT_SHORT: ACCUMULATE_USHORT(signed short); break; case VIPS_FORMAT_UINT: ACCUMULATE_USHORT(unsigned int); break; case VIPS_FORMAT_INT: ACCUMULATE_USHORT(signed int); break; case VIPS_FORMAT_FLOAT: ACCUMULATE_USHORT(float); break; case VIPS_FORMAT_DOUBLE: ACCUMULATE_USHORT(double); break; default: g_assert_not_reached(); } /* Note the maximum. */ hist->mx = mx; } typedef void (*VipsHistFindIndexedScanFn)(VipsHistFindIndexed *indexed, Histogram *hist, void *in, void *index, int n); static int vips_hist_find_indexed_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { Histogram *hist = (Histogram *) seq; VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) statistic; VipsRect r = { x, y, n, 1 }; VipsHistFindIndexedScanFn scan; /* Need the corresponding area of the index image. */ if (vips_region_prepare(hist->reg, &r)) return -1; if (indexed->index_ready->BandFmt == VIPS_FORMAT_UCHAR) scan = vips_hist_find_indexed_uchar_scan; else scan = vips_hist_find_indexed_ushort_scan; scan(indexed, hist, in, VIPS_REGION_ADDR(hist->reg, x, y), n); return 0; } static void vips_hist_find_indexed_class_init(VipsHistFindIndexedClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_find_indexed"; object_class->description = _("find indexed image histogram"); object_class->build = vips_hist_find_indexed_build; sclass->start = vips_hist_find_indexed_start; sclass->scan = vips_hist_find_indexed_scan; sclass->stop = vips_hist_find_indexed_stop; VIPS_ARG_IMAGE(class, "index", 90, _("Index"), _("Index image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistFindIndexed, index)); VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output histogram"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistFindIndexed, out)); VIPS_ARG_ENUM(class, "combine", 104, _("Combine"), _("Combine bins like this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHistFindIndexed, combine), VIPS_TYPE_COMBINE, VIPS_COMBINE_SUM); } static void vips_hist_find_indexed_init(VipsHistFindIndexed *indexed) { indexed->combine = VIPS_COMBINE_SUM; } /** * vips_hist_find_indexed: (method) * @in: input [class@Image] * @index: input index [class@Image] * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * * Make a histogram of @in, but use image @index to pick the bins. In other * words, element zero in @out contains the combination of all the pixels in @in * whose corresponding pixel in @index is zero. * * char and uchar @index images are cast to uchar before histogramming, all * other image types are cast to ushort. @index must have just one band. * * @in must be non-complex. * * @out always has the same size and format as @in. * * Normally, bins are summed, but you can use @combine to set other combine * modes. * * This operation is useful in conjunction with [method@Image.labelregions]. * You can use it to find the centre of gravity of blobs in an image, for * example. * * ::: tip "Optional arguments" * * @combine: [enum@Combine], combine bins like this * * ::: seealso * [method@Image.hist_find], [method@Image.labelregions]. * * Returns: 0 on success, -1 on error */ int vips_hist_find_indexed(VipsImage *in, VipsImage *index, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_find_indexed", ap, in, index, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/hist_find_ndim.c000066400000000000000000000204471516303661500222220ustar00rootroot00000000000000/* n-dimensional histogram * * Written on: 8/7/03 * 10/11/04 * - oops, was not checking the bandfmt coming in * 24/3/10 * - gtkdoc * - small celanups * 17/8/13 * - redo as a class * 28/1/22 travisbell * - better arg checking */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "statistic.h" struct _VipsHistFindNDim; /* Accumulate a histogram in one of these. */ typedef struct { struct _VipsHistFindNDim *ndim; unsigned int ***data; } Histogram; typedef struct _VipsHistFindNDim { VipsStatistic parent_instance; /* Number of bins on each axis. */ int bins; /* Max pixel value for this format. */ int max_val; /* Main image histogram. Subhists accumulate to this. */ Histogram *hist; /* Write hist to this output image. */ VipsImage *out; } VipsHistFindNDim; typedef VipsStatisticClass VipsHistFindNDimClass; G_DEFINE_TYPE(VipsHistFindNDim, vips_hist_find_ndim, VIPS_TYPE_STATISTIC); /* Build a Histogram. */ static Histogram * histogram_new(VipsHistFindNDim *ndim) { VipsImage *in = VIPS_STATISTIC(ndim)->ready; int bins = ndim->bins; /* How many dimensions do we need to allocate? */ int ilimit = in->Bands > 2 ? bins : 1; int jlimit = in->Bands > 1 ? bins : 1; int i, j; Histogram *hist; if (!(hist = VIPS_NEW(ndim, Histogram))) return NULL; hist->ndim = ndim; if (!(hist->data = VIPS_ARRAY(ndim, bins, unsigned int **))) return NULL; memset(hist->data, 0, bins * sizeof(unsigned int **)); for (i = 0; i < ilimit; i++) { if (!(hist->data[i] = VIPS_ARRAY(ndim, bins, unsigned int *))) return NULL; memset(hist->data[i], 0, bins * sizeof(unsigned int *)); for (j = 0; j < jlimit; j++) { if (!(hist->data[i][j] = VIPS_ARRAY(ndim, bins, unsigned int))) return NULL; memset(hist->data[i][j], 0, bins * sizeof(unsigned int)); } } return hist; } static int vips_hist_find_ndim_build(VipsObject *object) { VipsStatistic *statistic = VIPS_STATISTIC(object); VipsHistFindNDim *ndim = (VipsHistFindNDim *) object; unsigned int *obuffer; int y, i, x, z; g_object_set(object, "out", vips_image_new(), NULL); if (statistic->in) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(ndim); if (statistic->in->Bands > 3) { vips_error(class->nickname, "%s", _("image is not 1 - 3 bands")); return -1; } ndim->max_val = statistic->in->BandFmt == VIPS_FORMAT_UCHAR ? 256 : 65536; if (ndim->bins < 1 || ndim->bins > ndim->max_val) { vips_error(class->nickname, _("bins out of range [1,%d]"), ndim->max_val); return -1; } } /* main hist made on first thread start. */ if (VIPS_OBJECT_CLASS(vips_hist_find_ndim_parent_class)->build(object)) return -1; if (vips_image_pipelinev(ndim->out, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL)) return -1; vips_image_init_fields(ndim->out, ndim->bins, statistic->ready->Bands > 1 ? ndim->bins : 1, statistic->ready->Bands > 2 ? ndim->bins : 1, VIPS_FORMAT_UINT, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (!(obuffer = VIPS_ARRAY(ndim, VIPS_IMAGE_N_ELEMENTS(ndim->out), unsigned int))) return -1; for (y = 0; y < ndim->out->Ysize; y++) { for (i = 0, x = 0; x < ndim->out->Xsize; x++) for (z = 0; z < ndim->out->Bands; z++, i++) obuffer[i] = ndim->hist->data[z][y][x]; if (vips_image_write_line(ndim->out, y, (VipsPel *) obuffer)) return -1; } return 0; } static void * vips_hist_find_ndim_start(VipsStatistic *statistic) { VipsHistFindNDim *ndim = (VipsHistFindNDim *) statistic; /* Make the main hist, if necessary. */ if (!ndim->hist) ndim->hist = histogram_new(ndim); return (void *) histogram_new(ndim); } /* Join a sub-hist onto the main hist. */ static int vips_hist_find_ndim_stop(VipsStatistic *statistic, void *seq) { Histogram *sub_hist = (Histogram *) seq; VipsHistFindNDim *ndim = (VipsHistFindNDim *) statistic; Histogram *hist = ndim->hist; int i, j, k; for (i = 0; i < ndim->bins; i++) for (j = 0; j < ndim->bins; j++) for (k = 0; k < ndim->bins; k++) if (hist->data[i] && hist->data[i][j]) { hist->data[i][j][k] += sub_hist->data[i][j][k]; /* Zap sub-hist to make sure we * can't add it again. */ sub_hist->data[i][j][k] = 0; } return 0; } #define LOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ \ for (i = 0, j = 0; j < n; j++) { \ for (k = 0; k < nb; k++, i++) \ index[k] = p[i] / scale; \ \ hist->data[index[2]][index[1]][index[0]] += 1; \ } \ } static int vips_hist_find_ndim_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { Histogram *hist = (Histogram *) seq; VipsHistFindNDim *ndim = (VipsHistFindNDim *) statistic; VipsImage *im = statistic->ready; int nb = im->Bands; double scale = (double) (ndim->max_val + 1) / ndim->bins; int i, j, k; int index[3]; /* Fill these with dimensions, backwards. */ index[0] = index[1] = index[2] = 0; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; default: g_assert_not_reached(); } return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT #define UI VIPS_FORMAT_UINT /* Type mapping: go to uchar or ushort. */ static const VipsBandFormat vips_hist_find_ndim_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, US, US, US, US, US, US }; static void vips_hist_find_ndim_class_init(VipsHistFindNDimClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_find_ndim"; object_class->description = _("find n-dimensional image histogram"); object_class->build = vips_hist_find_ndim_build; sclass->start = vips_hist_find_ndim_start; sclass->scan = vips_hist_find_ndim_scan; sclass->stop = vips_hist_find_ndim_stop; sclass->format_table = vips_hist_find_ndim_format_table; VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output histogram"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistFindNDim, out)); VIPS_ARG_INT(class, "bins", 110, _("Bins"), _("Number of bins in each dimension"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHistFindNDim, bins), 1, 65536, 10); } static void vips_hist_find_ndim_init(VipsHistFindNDim *ndim) { ndim->bins = 10; } /** * vips_hist_find_ndim: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Make a one, two or three dimensional histogram of a 1, 2 or * 3 band image. Divide each axis into @bins bins .. ie. * output is 1 x bins, bins x bins, or bins x bins x bins bands. * @bins defaults to 10. * * char and uchar images are cast to uchar before histogramming, all other * image types are cast to ushort. * * ::: tip "Optional arguments" * * @bins: `gint`, number of bins to make on each axis * * ::: seealso * [method@Image.hist_find], [method@Image.hist_find_indexed]. * * Returns: 0 on success, -1 on error */ int vips_hist_find_ndim(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_find_ndim", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/hough.c000066400000000000000000000104151516303661500203500ustar00rootroot00000000000000/* hough transform * * 7/3/14 * - from hist_find.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "statistic.h" #include "hough.h" G_DEFINE_ABSTRACT_TYPE(VipsHough, vips_hough, VIPS_TYPE_STATISTIC); static VipsImage * vips_hough_new_accumulator(VipsHough *hough) { VipsHoughClass *class = VIPS_HOUGH_GET_CLASS(hough); VipsStatistic *statistic = VIPS_STATISTIC(hough); VipsImage *accumulator; accumulator = vips_image_new_memory(); if (vips_image_pipelinev(accumulator, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL) || class->init_accumulator(hough, accumulator) || vips_image_write_prepare(accumulator)) { g_object_unref(accumulator); return NULL; } return accumulator; } static int vips_hough_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsHough *hough = (VipsHough *) object; VipsImage *out; /* Mono only, we use the bands dimension of the output image for * a parameter. */ if (statistic->in) if (vips_check_mono(class->nickname, statistic->in)) return -1; if (!(out = vips_hough_new_accumulator(hough))) return -1; g_object_set(object, "out", out, NULL); if (VIPS_OBJECT_CLASS(vips_hough_parent_class)->build(object)) return -1; return 0; } /* Build a new accumulator. */ static void * vips_hough_start(VipsStatistic *statistic) { VipsHough *hough = (VipsHough *) statistic; VipsImage *accumulator; if (!(accumulator = vips_hough_new_accumulator(hough))) return NULL; return (void *) accumulator; } /* Add our finished accumulator to the main area. */ static int vips_hough_stop(VipsStatistic *statistic, void *seq) { VipsImage *accumulator = (VipsImage *) seq; VipsHough *hough = (VipsHough *) statistic; if (vips_draw_image(hough->out, accumulator, 0, 0, "mode", VIPS_COMBINE_MODE_ADD, NULL)) { g_object_unref(accumulator); return -1; } g_object_unref(accumulator); return 0; } static int vips_hough_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { VipsHough *hough = (VipsHough *) statistic; VipsHoughClass *class = VIPS_HOUGH_GET_CLASS(hough); VipsImage *accumulator = (VipsImage *) seq; VipsPel *p = (VipsPel *) in; int i; for (i = 0; i < n; i++) if (p[i]) class->vote(hough, accumulator, x + i, y); return 0; } #define UC VIPS_FORMAT_UCHAR /* Input image is cast to this format. */ static const VipsBandFormat vips_hough_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static void vips_hough_class_init(VipsHoughClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hough"; object_class->description = _("find hough transform"); object_class->build = vips_hough_build; sclass->start = vips_hough_start; sclass->scan = vips_hough_scan; sclass->stop = vips_hough_stop; sclass->format_table = vips_hough_format_table; VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHough, out)); } static void vips_hough_init(VipsHough *hough) { } libvips-8.18.2/libvips/arithmetic/hough.h000066400000000000000000000042471516303661500203630ustar00rootroot00000000000000/* hough transform * * 7/3/14 * - from hist_find.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_HOUGH_H #define VIPS_HOUGH_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_HOUGH (vips_hough_get_type()) #define VIPS_HOUGH(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_HOUGH, VipsHough)) #define VIPS_HOUGH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_HOUGH, VipsHoughClass)) #define VIPS_IS_HOUGH(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_HOUGH)) #define VIPS_IS_HOUGH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_HOUGH)) #define VIPS_HOUGH_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_HOUGH, VipsHoughClass)) typedef struct _VipsHough VipsHough; typedef struct _VipsHoughClass VipsHoughClass; typedef int (*VipsHoughInitAccumulator)(VipsHough *hough, VipsImage *accumulator); typedef void (*VipsHoughVote)(VipsHough *hough, VipsImage *accumulator, int x, int y); struct _VipsHough { VipsStatistic parent_instance; /* Sum the thread accumulators to here. */ VipsImage *out; }; struct _VipsHoughClass { VipsStatisticClass parent_class; /* Init an accumulator image. */ VipsHoughInitAccumulator init_accumulator; /* Vote function for this parameter space. */ VipsHoughVote vote; }; GType vips_hough_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_HOUGH_H*/ libvips-8.18.2/libvips/arithmetic/hough_circle.c000066400000000000000000000175311516303661500216770ustar00rootroot00000000000000/* hough transform for circles * * 7/3/14 * - from hough_line.c * 2/1/18 * - 20% speedup */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Derived in part from David Young's Matlab circle detector: * * http://www.mathworks.com/matlabcentral/fileexchange/26978-hough-transform-for-circles */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "statistic.h" #include "hough.h" typedef struct _VipsHoughCircle { VipsHough parent_instance; int scale; int min_radius; int max_radius; int width; int height; int bands; } VipsHoughCircle; typedef VipsHoughClass VipsHoughCircleClass; G_DEFINE_TYPE(VipsHoughCircle, vips_hough_circle, VIPS_TYPE_HOUGH); /* Smaller circles have fewer pixels and therefore fewer votes. Scale bands by * the ratio of circumference, so all radii get equal weight. */ static void vips_hough_circle_normalise(VipsHoughCircle *hough_circle) { VipsHough *hough = (VipsHough *) hough_circle; int max_radius = hough_circle->max_radius; int min_radius = hough_circle->min_radius; int scale = hough_circle->scale; int bands = hough_circle->bands; int width = hough_circle->width; int height = hough_circle->height; double max_circumference = 2 * VIPS_PI * max_radius; int b; for (b = 0; b < bands; b++) { int radius = b * scale + min_radius; double circumference = 2 * VIPS_PI * radius; double ratio = max_circumference / circumference; size_t n_pels = (size_t) width * height * bands; size_t i; guint *q; q = b + (guint *) VIPS_IMAGE_ADDR(hough->out, 0, 0); for (i = 0; i < n_pels; i += bands) q[i] *= ratio; } } static int vips_hough_circle_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = (VipsStatistic *) object; VipsHoughCircle *hough_circle = (VipsHoughCircle *) object; int range = hough_circle->max_radius - hough_circle->min_radius; if (range <= 0) { vips_error(class->nickname, "%s", _("parameters out of range")); return -1; } hough_circle->width = statistic->in->Xsize / hough_circle->scale; hough_circle->height = statistic->in->Ysize / hough_circle->scale; hough_circle->bands = 1 + range / hough_circle->scale; if (VIPS_OBJECT_CLASS(vips_hough_circle_parent_class)->build(object)) return -1; vips_hough_circle_normalise(hough_circle); return 0; } static int vips_hough_circle_init_accumulator(VipsHough *hough, VipsImage *accumulator) { VipsHoughCircle *hough_circle = (VipsHoughCircle *) hough; vips_image_init_fields(accumulator, hough_circle->width, hough_circle->height, hough_circle->bands, VIPS_FORMAT_UINT, VIPS_CODING_NONE, VIPS_INTERPRETATION_MATRIX, 1.0, 1.0); return 0; } /* Vote endpoints, with clip. */ static void vips_hough_circle_vote_endpoints_clip(VipsImage *image, int y, int x1, int x2, int quadrant, void *client) { int r = *((int *) client); int b = image->Bands; if (y >= 0 && y < image->Ysize) { guint *line = (guint *) VIPS_IMAGE_ADDR(image, 0, y) + r; if (x1 >= 0 && x1 < image->Xsize) line[x1 * b] += 1; if (x2 >= 0 && x2 < image->Xsize) line[x2 * b] += 1; } } /* Vote endpoints, no clip. */ static void vips_hough_circle_vote_endpoints_noclip(VipsImage *image, int y, int x1, int x2, int quadrant, void *client) { int r = *((int *) client); guint *line = (guint *) VIPS_IMAGE_ADDR(image, 0, y) + r; int b = image->Bands; line[x1 * b] += 1; line[x2 * b] += 1; } /* Cast votes for all possible circles passing through x, y. */ static void vips_hough_circle_vote(VipsHough *hough, VipsImage *accumulator, int x, int y) { VipsHoughCircle *hough_circle = (VipsHoughCircle *) hough; int min_radius = hough_circle->min_radius; int cx = x / hough_circle->scale; int cy = y / hough_circle->scale; int rb; g_assert(hough_circle->max_radius - min_radius >= 0); for (rb = 0; rb < hough_circle->bands; rb++) { /* r needs to be in scaled down image space. */ int r = rb + min_radius / hough_circle->scale; VipsDrawScanline draw_scanline; if (cx - r >= 0 && cx + r < accumulator->Xsize && cy - r >= 0 && cy + r < accumulator->Ysize) draw_scanline = vips_hough_circle_vote_endpoints_noclip; else draw_scanline = vips_hough_circle_vote_endpoints_clip; vips__draw_circle_direct(accumulator, cx, cy, r, draw_scanline, &rb); } } static void vips_hough_circle_class_init(VipsHoughClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsHoughClass *hclass = (VipsHoughClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hough_circle"; object_class->description = _("find hough circle transform"); object_class->build = vips_hough_circle_build; hclass->init_accumulator = vips_hough_circle_init_accumulator; hclass->vote = vips_hough_circle_vote; VIPS_ARG_INT(class, "scale", 119, _("Scale"), _("Scale down dimensions by this factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHoughCircle, scale), 1, 100000, 1); VIPS_ARG_INT(class, "min_radius", 120, _("Min radius"), _("Smallest radius to search for"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHoughCircle, min_radius), 1, 100000, 10); VIPS_ARG_INT(class, "max_radius", 121, _("Max radius"), _("Largest radius to search for"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHoughCircle, max_radius), 1, 100000, 20); } static void vips_hough_circle_init(VipsHoughCircle *hough_circle) { hough_circle->scale = 1; hough_circle->min_radius = 10; hough_circle->max_radius = 20; } /** * vips_hough_circle: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Find the circular Hough transform of an image. @in must be one band, with * non-zero pixels for image edges. @out is three-band, with the third channel * representing the detected circle radius. The operation scales the number of * votes by circle circumference so circles of differing size are given equal * weight. * * The output pixel at (x, y, band) is the strength of the circle centred on * (x, y) and with radius (band). * * Use @max_radius and @min_radius to set the range of radii to search for. * * Use @scale to set how @in coordinates are scaled to @out coordinates. A * @scale of 3, for example, will make @out 1/3rd of the width and height of * @in, and reduce the number of radii tested (and hence the number of bands * int @out) by a factor of three as well. * * ::: tip "Optional arguments" * * @scale: `gint`, scale down dimensions by this much * * @min_radius: `gint`, smallest radius to search for * * @max_radius: `gint`, largest radius to search for * * ::: seealso * [method@Image.hough_line]. * * Returns: 0 on success, -1 on error */ int vips_hough_circle(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hough_circle", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/hough_line.c000066400000000000000000000121021516303661500213520ustar00rootroot00000000000000/* hough transform for lines * * 7/3/14 * - from hist_find.c * 1/2/18 * - change width to 0 - 180 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "statistic.h" #include "hough.h" typedef struct _VipsHoughLine { VipsHough parent_instance; /* Size of parameter space. */ int width; int height; /* LUT for this transform. */ double *sin; } VipsHoughLine; typedef VipsHoughClass VipsHoughLineClass; G_DEFINE_TYPE(VipsHoughLine, vips_hough_line, VIPS_TYPE_HOUGH); static int vips_hough_line_build(VipsObject *object) { VipsHoughLine *hough_line = (VipsHoughLine *) object; int width = hough_line->width; if (!(hough_line->sin = VIPS_ARRAY(object, 2 * width, double))) return -1; /* Map width to 180 degrees, width * 2 to 360. */ for (int i = 0; i < 2 * width; i++) hough_line->sin[i] = sin(2 * VIPS_PI * i / (2 * width)); if (VIPS_OBJECT_CLASS(vips_hough_line_parent_class)->build(object)) return -1; return 0; } static int vips_hough_line_init_accumulator(VipsHough *hough, VipsImage *accumulator) { VipsHoughLine *hough_line = (VipsHoughLine *) hough; vips_image_init_fields(accumulator, hough_line->width, hough_line->height, 1, VIPS_FORMAT_UINT, VIPS_CODING_NONE, VIPS_INTERPRETATION_MATRIX, 1.0, 1.0); return 0; } /* Cast votes for all lines passing through x, y. */ static void vips_hough_line_vote(VipsHough *hough, VipsImage *accumulator, int x, int y) { VipsHoughLine *hough_line = (VipsHoughLine *) hough; VipsStatistic *statistic = (VipsStatistic *) hough; // normalise (x, y) to diagonal size of input image int xs = statistic->ready->Xsize; int ys = statistic->ready->Ysize; double d = sqrt(xs * xs + ys * ys); double xd = (double) x / d; double yd = (double) y / d; // size of hough space int width = hough_line->width; int height = hough_line->height; guint *data = (guint *) accumulator->data; for (int i = 0; i < width; i++) { int i90 = i + width / 2; double r = xd * hough_line->sin[i90] + yd * hough_line->sin[i]; int ri = (r + 1) * (height / 2.0); g_assert(ri >= 0 && ri < height); data[i + ri * width] += 1; } } static void vips_hough_line_class_init(VipsHoughClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsHoughClass *hclass = (VipsHoughClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hough_line"; object_class->description = _("find hough line transform"); object_class->build = vips_hough_line_build; hclass->init_accumulator = vips_hough_line_init_accumulator; hclass->vote = vips_hough_line_vote; VIPS_ARG_INT(class, "width", 110, _("Width"), _("Horizontal size of parameter space"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHoughLine, width), 1, 100000, 256); VIPS_ARG_INT(class, "height", 111, _("Height"), _("Vertical size of parameter space"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHoughLine, height), 1, 100000, 256); } static void vips_hough_line_init(VipsHoughLine *hough_line) { hough_line->width = 256; hough_line->height = 256; } /** * vips_hough_line: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Find the line Hough transform for @in. @in must have one band. @out has one * band, with pixels being the number of votes for that line. The X dimension * of @out is the line angle in 0 - 180 degrees, the Y dimension is the * distance of the closest part of that line to the origin in the top-left. * * Use @width @height to set the size of the parameter space image (@out), * that is, how accurate the line determination should be. * * ::: tip "Optional arguments" * * @width: `gint`, horizontal size of parameter space * * @height: `gint`, vertical size of parameter space * * ::: seealso * [method@Image.hough_circle]. * * Returns: 0 on success, -1 on error */ int vips_hough_line(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hough_line", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/invert.c000066400000000000000000000110631516303661500205450ustar00rootroot00000000000000/* photographic negative ... just an example, really * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 12/02/1990 * Modified on : * 7/7/93 JC * - memory leaks fixed * - adapted for partial v2 * - ANSIfied * 22/2/95 JC * - tidied up again * 2/9/09 * - gtk-doc comment * 23/8/11 * - rewrite as a class * 7/12/12 * - only invert real part of complex */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef VipsUnary VipsInvert; typedef VipsUnaryClass VipsInvertClass; G_DEFINE_TYPE(VipsInvert, vips_invert, VIPS_TYPE_UNARY); #define LOOP(TYPE, L) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = (L) - p[x]; \ } #define LOOPN(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = -1 * p[x]; \ } #define LOOPC(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) { \ q[0] = -1 * p[0]; \ q[1] = p[1]; \ \ p += 2; \ q += 2; \ } \ } static void vips_invert_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, UCHAR_MAX); break; case VIPS_FORMAT_CHAR: LOOPN(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, USHRT_MAX); break; case VIPS_FORMAT_SHORT: LOOPN(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, UINT_MAX); break; case VIPS_FORMAT_INT: LOOPN(signed int); break; case VIPS_FORMAT_FLOAT: LOOPN(float); break; case VIPS_FORMAT_DOUBLE: LOOPN(double); break; case VIPS_FORMAT_COMPLEX: LOOPC(float); break; case VIPS_FORMAT_DPCOMPLEX: LOOPC(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Format doesn't change with invert. */ static const VipsBandFormat vips_invert_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_invert_class_init(VipsInvertClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "invert"; object_class->description = _("invert an image"); aclass->process_line = vips_invert_buffer; vips_arithmetic_set_format_table(aclass, vips_invert_format_table); } static void vips_invert_init(VipsInvert *invert) { } /** * vips_invert: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * For unsigned formats, this operation calculates (max - @in), eg. (255 - * @in) for uchar. For signed and float formats, this operation calculates (-1 * @in). * * For complex images, only the real part is inverted. See also [method@Image.conj]. * * ::: seealso * [method@Image.linear]. * * Returns: 0 on success, -1 on error */ int vips_invert(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("invert", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/linear.c000066400000000000000000000307341516303661500205160ustar00rootroot00000000000000/* im_lintra.c -- linear transform * * Copyright: 1990, N. Dessipris, based on im_powtra() * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 23/4/93 JC * - adapted to work with partial images * 1/7/93 JC * - adapted for partial v2 * 7/10/94 JC * - new IM_NEW() * - more typedefs * 9/2/95 JC * - adapted for im_wrap... * - operations on complex images now just transform the real channel * 29/9/95 JC * - complex was broken * 15/4/97 JC * - return(0) missing from generate, arrgh! * 1/7/98 JC * - im_lintra_vec added * 3/8/02 JC * - fall back to im_copy() for a == 1, b == 0 * 10/10/02 JC * - auug, failing to multiply imag for complex! (thanks matt) * 10/12/02 JC * - removed im_copy() fallback ... meant that output format could change * with value :-( very confusing * 30/6/04 * - added 1 band image * n band vector case * 8/12/06 * - add liboil support * 9/9/09 * - gtkdoc comment, minor reformat * 31/7/10 * - remove liboil * 31/10/11 * - rework as a class * - removed the 1-ary constant path, no faster * 30/11/13 * - 1ary is back, faster with gcc 4.8 * 14/1/14 * - add uchar output option * 30/9/17 * - squash constants with all elements equal so we use 1ary path more * often */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef struct _VipsLinear { VipsUnary parent_instance; /* Our constants: multiply by a, add b. */ VipsArea *a; VipsArea *b; /* uchar output. */ gboolean uchar; /* TRUE if a and b each contain only one unique value. */ gboolean single_element; /* Our constants expanded to match arith->ready in size. */ double *a_ready; double *b_ready; } VipsLinear; typedef VipsUnaryClass VipsLinearClass; G_DEFINE_TYPE(VipsLinear, vips_linear, VIPS_TYPE_UNARY); static int vips_linear_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsArithmetic *arithmetic = VIPS_ARITHMETIC(object); VipsUnary *unary = (VipsUnary *) object; VipsLinear *linear = (VipsLinear *) object; int i; /* If we have a $n element vector, we need to bandup the image to * match. */ int n = 1; if (linear->a) n = VIPS_MAX(n, linear->a->n); if (linear->b) n = VIPS_MAX(n, linear->b->n); if (unary->in) { int bands; vips_image_decode_predict(unary->in, &bands, NULL); n = VIPS_MAX(n, bands); } arithmetic->base_bands = n; if (unary->in && linear->a && linear->b) { if (vips_check_vector(class->nickname, linear->a->n, unary->in) || vips_check_vector(class->nickname, linear->b->n, unary->in)) return -1; } /* If all elements of the constants are equal, we can treat them as * a single element. */ int a_n = 1; if (linear->a) { double *ary = (double *) linear->a->data; for (i = 1; i < linear->a->n; i++) if (ary[i] != ary[0]) { a_n = linear->a->n; break; } } int b_n = 1; if (linear->b) { double *ary = (double *) linear->b->data; for (i = 1; i < linear->b->n; i++) if (ary[i] != ary[0]) { b_n = linear->b->n; break; } } linear->single_element = a_n == 1 && b_n == 1; /* Make up-banded versions of our constants. */ linear->a_ready = VIPS_ARRAY(linear, n, double); linear->b_ready = VIPS_ARRAY(linear, n, double); for (i = 0; i < n; i++) { if (linear->a) { double *ary = (double *) linear->a->data; int j = VIPS_MIN(i, a_n - 1); linear->a_ready[i] = ary[j]; } if (linear->b) { double *ary = (double *) linear->b->data; int j = VIPS_MIN(i, b_n - 1); linear->b_ready[i] = ary[j]; } } if (linear->uchar) arithmetic->format = VIPS_FORMAT_UCHAR; if (VIPS_OBJECT_CLASS(vips_linear_parent_class)->build(object)) return -1; return 0; } /* Non-complex input, any output, all bands of the constant equal. */ #define LOOP1(IN, OUT) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ OUT a1 = a[0]; \ OUT b1 = b[0]; \ int sz = width * nb; \ \ for (x = 0; x < sz; x++) \ q[x] = a1 * (OUT) p[x] + b1; \ } /* Non-complex input, any output. */ #define LOOPN(IN, OUT) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ \ for (i = 0, x = 0; x < width; x++) \ for (k = 0; k < nb; k++, i++) \ q[i] = a[k] * (OUT) p[i] + b[k]; \ } #define LOOP(IN, OUT) \ { \ if (linear->single_element) { \ LOOP1(IN, OUT); \ } \ else { \ LOOPN(IN, OUT); \ } \ } /* Complex input, complex output. */ #define LOOPCMPLXN(IN, OUT) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) \ for (k = 0; k < nb; k++) { \ q[0] = a[k] * p[0] + b[k]; \ q[1] = p[1]; \ q += 2; \ p += 2; \ } \ } /* Non-complex input, any output, all bands of the constant equal, uchar * output. */ #define LOOP1uc(IN) \ { \ IN *restrict p = (IN *) in[0]; \ VipsPel *restrict q = (VipsPel *) out; \ float a1 = a[0]; \ float b1 = b[0]; \ int sz = width * nb; \ \ for (x = 0; x < sz; x++) { \ float t = a1 * p[x] + b1; \ \ q[x] = VIPS_FCLIP(0, t, 255); \ } \ } /* Non-complex input, uchar output. */ #define LOOPNuc(IN) \ { \ IN *restrict p = (IN *) in[0]; \ VipsPel *restrict q = (VipsPel *) out; \ \ for (i = 0, x = 0; x < width; x++) \ for (k = 0; k < nb; k++, i++) { \ double t = a[k] * p[i] + b[k]; \ \ q[i] = VIPS_FCLIP(0, t, 255); \ } \ } #define LOOPuc(IN) \ { \ if (linear->single_element) { \ LOOP1uc(IN); \ } \ else { \ LOOPNuc(IN); \ } \ } /* Complex input, uchar output. */ #define LOOPCMPLXNuc(IN) \ { \ IN *restrict p = (IN *) in[0]; \ VipsPel *restrict q = (VipsPel *) out; \ \ for (i = 0, x = 0; x < width; x++) \ for (k = 0; k < nb; k++, i++) { \ double t = a[k] * p[0] + b[k]; \ \ q[i] = VIPS_FCLIP(0, t, 255); \ p += 2; \ } \ } /* Lintra a buffer, n set of scale/offset. */ static void vips_linear_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; VipsLinear *linear = (VipsLinear *) arithmetic; double *restrict a = linear->a_ready; double *restrict b = linear->b_ready; int nb = im->Bands; int i, x, k; if (linear->uchar) switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOPuc(unsigned char); break; case VIPS_FORMAT_CHAR: LOOPuc(signed char); break; case VIPS_FORMAT_USHORT: LOOPuc(unsigned short); break; case VIPS_FORMAT_SHORT: LOOPuc(signed short); break; case VIPS_FORMAT_UINT: LOOPuc(unsigned int); break; case VIPS_FORMAT_INT: LOOPuc(signed int); break; case VIPS_FORMAT_FLOAT: LOOPuc(float); break; case VIPS_FORMAT_DOUBLE: LOOPuc(double); break; case VIPS_FORMAT_COMPLEX: LOOPCMPLXNuc(float); break; case VIPS_FORMAT_DPCOMPLEX: LOOPCMPLXNuc(double); break; default: g_assert_not_reached(); } else switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, float); break; case VIPS_FORMAT_CHAR: LOOP(signed char, float); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, float); break; case VIPS_FORMAT_SHORT: LOOP(signed short, float); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, float); break; case VIPS_FORMAT_INT: LOOP(signed int, float); break; case VIPS_FORMAT_FLOAT: LOOP(float, float); break; case VIPS_FORMAT_DOUBLE: LOOP(double, double); break; case VIPS_FORMAT_COMPLEX: LOOPCMPLXN(float, float); break; case VIPS_FORMAT_DPCOMPLEX: LOOPCMPLXN(double, double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Format doesn't change with linear. */ static const VipsBandFormat vips_linear_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ F, F, F, F, F, F, F, X, D, DX }; static void vips_linear_class_init(VipsLinearClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "linear"; object_class->description = _("calculate (a * in + b)"); object_class->build = vips_linear_build; aclass->process_line = vips_linear_buffer; vips_arithmetic_set_format_table(aclass, vips_linear_format_table); VIPS_ARG_BOXED(class, "a", 110, _("a"), _("Multiply by this"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsLinear, a), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOXED(class, "b", 111, _("b"), _("Add this"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsLinear, b), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOOL(class, "uchar", 112, _("uchar"), _("Output should be uchar"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsLinear, uchar), FALSE); } static void vips_linear_init(VipsLinear *linear) { } static int vips_linearv(VipsImage *in, VipsImage **out, const double *a, const double *b, int n, va_list ap) { VipsArea *area_a; VipsArea *area_b; int result; area_a = VIPS_AREA(vips_array_double_new(a, n)); area_b = VIPS_AREA(vips_array_double_new(b, n)); result = vips_call_split("linear", ap, in, out, area_a, area_b); vips_area_unref(area_a); vips_area_unref(area_b); return result; } /** * vips_linear: (method) * @in: image to transform * @out: (out): output image * @a: (array length=n): array of constants for multiplication * @b: (array length=n): array of constants for addition * @n: length of constant arrays * @...: `NULL`-terminated list of optional named arguments * * Pass an image through a linear transform, ie. (@out = @in * @a + @b). Output * is float for integer input, double for double input, complex for * complex input and double complex for double complex input. Set @uchar to * output uchar pixels. * * If the arrays of constants have just one element, that constant is used for * all image bands. If the arrays have more than one element and they have * the same number of elements as there are bands in the image, then * one array element is used for each band. If the arrays have more than one * element and the image only has a single band, the result is a many-band * image where each band corresponds to one array element. * * ::: tip "Optional arguments" * * @uchar: `gboolean`, output uchar pixels * * ::: seealso * [method@Image.linear1], [method@Image.add]. * * Returns: 0 on success, -1 on error */ int vips_linear(VipsImage *in, VipsImage **out, const double *a, const double *b, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_linearv(in, out, a, b, n, ap); va_end(ap); return result; } /** * vips_linear1: (method) * @in: image to transform * @out: (out): output image * @a: constant for multiplication * @b: constant for addition * @...: `NULL`-terminated list of optional named arguments * * Run [method@Image.linear] with a single constant. * * ::: tip "Optional arguments" * * @uchar: `gboolean`, output uchar pixels * * ::: seealso * [method@Image.linear]. * * Returns: 0 on success, -1 on error */ int vips_linear1(VipsImage *in, VipsImage **out, double a, double b, ...) { va_list ap; int result; va_start(ap, b); result = vips_linearv(in, out, &a, &b, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/math.c000066400000000000000000000344131516303661500201730ustar00rootroot00000000000000/* VipsMath -- call various -lm functions (trig, log etc.) on images * * Copyright: 1990, N. Dessipris, based on im_powtra() * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 5/5/93 JC * - adapted from im_lintra to work with partial images * - incorrect implementation of complex logs removed * 1/7/93 JC * - adapted for partial v2 * - ANSIfied * 24/2/95 JC * - im_logtra() adapted to make im_sintra() * - adapted for im_wrapone() * 26/1/96 JC * - im_asintra() added * 30/8/09 * - gtkdoc * - tiny cleanups * - use im__math() * 19/9/09 * - im_sintra() adapted to make math.c * 4/11/11 * - redone as a class * 11/8/15 * - log/log10 zero-avoid */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef struct _VipsMath { VipsUnary parent_instance; VipsOperationMath math; } VipsMath; typedef VipsUnaryClass VipsMathClass; G_DEFINE_TYPE(VipsMath, vips_math, VIPS_TYPE_UNARY); static int vips_math_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsUnary *unary = (VipsUnary *) object; if (unary->in && vips_check_noncomplex(class->nickname, unary->in)) return -1; if (VIPS_OBJECT_CLASS(vips_math_parent_class)->build(object)) return -1; return 0; } #define LOOP(IN, OUT, OP) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = OP(p[x]); \ } #define SWITCH(OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ LOOP(unsigned char, float, OP); \ break; \ case VIPS_FORMAT_CHAR: \ LOOP(signed char, float, OP); \ break; \ case VIPS_FORMAT_USHORT: \ LOOP(unsigned short, float, OP); \ break; \ case VIPS_FORMAT_SHORT: \ LOOP(signed short, float, OP); \ break; \ case VIPS_FORMAT_UINT: \ LOOP(unsigned int, float, OP); \ break; \ case VIPS_FORMAT_INT: \ LOOP(signed int, float, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ LOOP(float, float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ LOOP(double, double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } /* sin/cos/tan in degrees. */ #define DSIN(X) (sin(VIPS_RAD(X))) #define DCOS(X) (cos(VIPS_RAD(X))) #define DTAN(X) (tan(VIPS_RAD(X))) #define ADSIN(X) (VIPS_DEG(asin(X))) #define ADCOS(X) (VIPS_DEG(acos(X))) #define ADTAN(X) (VIPS_DEG(atan(X))) /* exp10() is a gnu extension, use pow(). */ #define EXP10(X) (pow(10.0, (X))) /* Zero-avoiding log, cf. zero-avoiding behaviour of /. */ #define LOGZ(X) ((X) == 0.0 ? 0.0 : log(X)) #define LOGZ10(X) ((X) == 0.0 ? 0.0 : log10(X)) static void vips_math_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsMath *math = (VipsMath *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (math->math) { case VIPS_OPERATION_MATH_SIN: SWITCH(DSIN); break; case VIPS_OPERATION_MATH_COS: SWITCH(DCOS); break; case VIPS_OPERATION_MATH_TAN: SWITCH(DTAN); break; case VIPS_OPERATION_MATH_ASIN: SWITCH(ADSIN); break; case VIPS_OPERATION_MATH_ACOS: SWITCH(ADCOS); break; case VIPS_OPERATION_MATH_ATAN: SWITCH(ADTAN); break; case VIPS_OPERATION_MATH_SINH: SWITCH(sinh); break; case VIPS_OPERATION_MATH_COSH: SWITCH(cosh); break; case VIPS_OPERATION_MATH_TANH: SWITCH(tanh); break; case VIPS_OPERATION_MATH_ASINH: SWITCH(asinh); break; case VIPS_OPERATION_MATH_ACOSH: SWITCH(acosh); break; case VIPS_OPERATION_MATH_ATANH: SWITCH(atanh); break; case VIPS_OPERATION_MATH_LOG: SWITCH(LOGZ); break; case VIPS_OPERATION_MATH_LOG10: SWITCH(LOGZ10); break; case VIPS_OPERATION_MATH_EXP: SWITCH(exp); break; case VIPS_OPERATION_MATH_EXP10: SWITCH(EXP10); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_math_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ F, F, F, F, F, F, F, X, D, DX }; static void vips_math_class_init(VipsMathClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "math"; object_class->description = _("apply a math operation to an image"); object_class->build = vips_math_build; aclass->process_line = vips_math_buffer; vips_arithmetic_set_format_table(aclass, vips_math_format_table); VIPS_ARG_ENUM(class, "math", 200, _("Operation"), _("Math to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMath, math), VIPS_TYPE_OPERATION_MATH, VIPS_OPERATION_MATH_SIN); } static void vips_math_init(VipsMath *math) { } static int vips_mathv(VipsImage *in, VipsImage **out, VipsOperationMath math, va_list ap) { return vips_call_split("math", ap, in, out, math); } /** * vips_math: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @math: math operation to perform * @...: `NULL`-terminated list of optional named arguments * * Perform various functions in -lm, the maths library, on images. * * Angles are expressed in degrees. The output type is float unless the * input is double, in which case the output is double. * * Non-complex images only. * * ::: seealso * [method@Image.math2]. * * Returns: 0 on success, -1 on error */ int vips_math(VipsImage *in, VipsImage **out, VipsOperationMath math, ...) { va_list ap; int result; va_start(ap, math); result = vips_mathv(in, out, math, ap); va_end(ap); return result; } /** * vips_sin: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.SIN] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_sin(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_SIN, ap); va_end(ap); return result; } /** * vips_cos: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.COS] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_cos(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_COS, ap); va_end(ap); return result; } /** * vips_tan: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.TAN] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_tan(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_TAN, ap); va_end(ap); return result; } /** * vips_asin: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.ASIN] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_asin(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_ASIN, ap); va_end(ap); return result; } /** * vips_acos: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.ACOS] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_acos(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_ACOS, ap); va_end(ap); return result; } /** * vips_atan: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.ATAN] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_atan(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_ATAN, ap); va_end(ap); return result; } /** * vips_sinh: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.SINH] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_sinh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_SINH, ap); va_end(ap); return result; } /** * vips_cosh: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.COSH] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_cosh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_COSH, ap); va_end(ap); return result; } /** * vips_tanh: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.TANH] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_tanh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_TANH, ap); va_end(ap); return result; } /** * vips_asinh: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.ASINH] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_asinh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_ASINH, ap); va_end(ap); return result; } /** * vips_acosh: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.ACOSH] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_acosh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_ACOSH, ap); va_end(ap); return result; } /** * vips_atanh: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.ATANH] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_atanh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_ATANH, ap); va_end(ap); return result; } /** * vips_log: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.LOG] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_log(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_LOG, ap); va_end(ap); return result; } /** * vips_log10: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.LOG10] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_log10(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_LOG10, ap); va_end(ap); return result; } /** * vips_exp: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.EXP] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_exp(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_EXP, ap); va_end(ap); return result; } /** * vips_exp10: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath.EXP10] on an image. See [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_exp10(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_mathv(in, out, VIPS_OPERATION_MATH_EXP10, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/math2.c000066400000000000000000000421721516303661500202560ustar00rootroot00000000000000/* math2.c -- 2ary math funcs * * Copyright: 1990, N. Dessipris * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 10/12/93 JC * - now reports total number of x/0, rather than each one. * 1/2/95 JC * - rewritten for PIO with im_wrapone() * - incorrect complex code removed * - /0 reporting removed for ease of programming * 15/4/97 JC * - return( 0 ) missing, oops! * 6/7/98 JC * - _vec form added * 30/8/09 * - gtkdoc * - tiny cleanups * 20/9/09 * - im_powtra() adapted to make math2.c * 12/11/11 * - redone as a class * 17/7/12 * - wopconst was broken * 20/10/21 indus * - add atan2 */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" #include "unaryconst.h" typedef struct _VipsMath2 { VipsBinary parent_instance; VipsOperationMath2 math2; } VipsMath2; typedef VipsBinaryClass VipsMath2Class; G_DEFINE_TYPE(VipsMath2, vips_math2, VIPS_TYPE_BINARY); static int vips_math2_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBinary *binary = (VipsBinary *) object; if (binary->left && vips_check_noncomplex(class->nickname, binary->left)) return -1; if (binary->right && vips_check_noncomplex(class->nickname, binary->right)) return -1; if (VIPS_OBJECT_CLASS(vips_math2_parent_class)->build(object)) return -1; return 0; } #define LOOP(IN, OUT, OP) \ { \ IN *restrict p1 = (IN *) in[0]; \ IN *restrict p2 = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ OP(q[x], p1[x], p2[x]); \ } #define SWITCH(L, OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ L(unsigned char, float, OP); \ break; \ case VIPS_FORMAT_CHAR: \ L(signed char, float, OP); \ break; \ case VIPS_FORMAT_USHORT: \ L(unsigned short, float, OP); \ break; \ case VIPS_FORMAT_SHORT: \ L(signed short, float, OP); \ break; \ case VIPS_FORMAT_UINT: \ L(unsigned int, float, OP); \ break; \ case VIPS_FORMAT_INT: \ L(signed int, float, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ L(float, float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ L(double, double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } #define POW(Y, X, E) \ { \ double left = (double) (X); \ double right = (double) (E); \ \ /* Special case for **-1 and **0.5, since they are so common. Also \ * watch for /0. \ */ \ (Y) = (left == 0.0) \ ? 0.0 \ : (right == -1) \ ? 1.0 / left \ : (right == 0.5) \ ? sqrt(left) \ : pow(left, right); \ } #define WOP(Y, X, E) POW(Y, E, X) #define ATAN2(Y, L, R) \ { \ double left = (double) (L); \ double right = (double) (R); \ \ (Y) = VIPS_DEG(atan2(left, right)); \ if ((Y) < 0.0) \ (Y) += 360; \ } static void vips_math2_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsMath2 *math2 = (VipsMath2 *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (math2->math2) { case VIPS_OPERATION_MATH2_POW: SWITCH(LOOP, POW); break; case VIPS_OPERATION_MATH2_WOP: SWITCH(LOOP, WOP); break; case VIPS_OPERATION_MATH2_ATAN2: SWITCH(LOOP, ATAN2); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for math2. Keep in sync with math2_buffer() above. */ static const VipsBandFormat vips_math2_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ F, F, F, F, F, F, F, X, D, DX }; static void vips_math2_class_init(VipsMath2Class *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "math2"; object_class->description = _("binary math operations"); object_class->build = vips_math2_build; aclass->process_line = vips_math2_buffer; vips_arithmetic_set_format_table(aclass, vips_math2_format_table); VIPS_ARG_ENUM(class, "math2", 200, _("Operation"), _("Math to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMath2, math2), VIPS_TYPE_OPERATION_MATH2, VIPS_OPERATION_MATH2_POW); } static void vips_math2_init(VipsMath2 *math2) { } static int vips_math2v(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationMath2 math2, va_list ap) { return vips_call_split("math2", ap, left, right, out, math2); } /** * vips_math2: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @math2: math operation to perform * @...: `NULL`-terminated list of optional named arguments * * This operation calculates a 2-ary maths operation on a pair of images * and writes the result to @out. The images may have any * non-complex format. @out is float except in the case that either of @left * or @right are double, in which case @out is also double. * * It detects division by zero, setting those pixels to zero in the output. * Beware: it does this silently! * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), and that format is the * result type. * * ::: seealso * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_math2(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationMath2 math2, ...) { va_list ap; int result; va_start(ap, math2); result = vips_math2v(left, right, out, math2, ap); va_end(ap); return result; } /** * vips_pow: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.POW] on a pair of images. See * [method@Image.math2]. * * Returns: 0 on success, -1 on error */ int vips_pow(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_math2v(left, right, out, VIPS_OPERATION_MATH2_POW, ap); va_end(ap); return result; } /** * vips_wop: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.WOP] on a pair of images. See * [method@Image.math2]. * * Returns: 0 on success, -1 on error */ int vips_wop(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_math2v(left, right, out, VIPS_OPERATION_MATH2_WOP, ap); va_end(ap); return result; } /** * vips_atan2: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.ATAN2] on a pair of images. See * [method@Image.math2]. * * Returns: 0 on success, -1 on error */ int vips_atan2(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_math2v(left, right, out, VIPS_OPERATION_MATH2_ATAN2, ap); va_end(ap); return result; } typedef struct _VipsMath2Const { VipsUnaryConst parent_instance; VipsOperationMath2 math2; } VipsMath2Const; typedef VipsUnaryConstClass VipsMath2ConstClass; G_DEFINE_TYPE(VipsMath2Const, vips_math2_const, VIPS_TYPE_UNARY_CONST); static int vips_math2_const_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsUnary *unary = (VipsUnary *) object; if (unary->in && vips_check_noncomplex(class->nickname, unary->in)) return -1; if (VIPS_OBJECT_CLASS(vips_math2_const_parent_class)->build(object)) return -1; return 0; } #define LOOPC(IN, OUT, OP) \ { \ IN *restrict p = (IN *) in[0]; \ OUT *restrict q = (OUT *) out; \ double *restrict c = uconst->c_double; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) \ OP(q[i], p[i], c[b]); \ } static void vips_math2_const_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsUnaryConst *uconst = (VipsUnaryConst *) arithmetic; VipsMath2Const *math2 = (VipsMath2Const *) arithmetic; VipsImage *im = arithmetic->ready[0]; int bands = im->Bands; int i, x, b; switch (math2->math2) { case VIPS_OPERATION_MATH2_POW: SWITCH(LOOPC, POW); break; case VIPS_OPERATION_MATH2_WOP: SWITCH(LOOPC, WOP); break; case VIPS_OPERATION_MATH2_ATAN2: SWITCH(LOOPC, ATAN2); break; default: g_assert_not_reached(); break; } } static void vips_math2_const_class_init(VipsMath2ConstClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "math2_const"; object_class->description = _("binary math operations with a constant"); object_class->build = vips_math2_const_build; aclass->process_line = vips_math2_const_buffer; vips_arithmetic_set_format_table(aclass, vips_math2_format_table); VIPS_ARG_ENUM(class, "math2", 200, _("Operation"), _("Math to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMath2Const, math2), VIPS_TYPE_OPERATION_MATH2, VIPS_OPERATION_MATH2_POW); } static void vips_math2_const_init(VipsMath2Const *math2_const) { } static int vips_math2_constv(VipsImage *in, VipsImage **out, VipsOperationMath2 math2, const double *c, int n, va_list ap) { VipsArea *area_c; double *array; int result; int i; area_c = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); array = (double *) area_c->data; for (i = 0; i < n; i++) array[i] = c[i]; result = vips_call_split("math2_const", ap, in, out, math2, area_c); vips_area_unref(area_c); return result; } /** * vips_math2_const: (method) * @in: input image * @out: (out): output image * @math2: math operation to perform * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * This operation calculates various 2-ary maths operations on an image and * an array of constants and writes the result to @out. * The image may have any * non-complex format. @out is float except in the case that @in * is double, in which case @out is also double. * * It detects division by zero, setting those pixels to zero in the output. * Beware: it does this silently! * * If the array of constants has just one element, that constant is used for * all image bands. If the array has more than one element and they have * the same number of elements as there are bands in the image, then * one array element is used for each band. If the arrays have more than one * element and the image only has a single band, the result is a many-band * image where each band corresponds to one array element. * * ::: seealso * [method@Image.math2], [method@Image.math]. * * Returns: 0 on success, -1 on error */ int vips_math2_const(VipsImage *in, VipsImage **out, VipsOperationMath2 math2, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_math2_constv(in, out, math2, c, n, ap); va_end(ap); return result; } /** * vips_pow_const: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.POW] on an image and a constant. See * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_pow_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_math2_constv(in, out, VIPS_OPERATION_MATH2_POW, c, n, ap); va_end(ap); return result; } /** * vips_wop_const: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.WOP] on an image and a constant. See * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_wop_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_math2_constv(in, out, VIPS_OPERATION_MATH2_WOP, c, n, ap); va_end(ap); return result; } /** * vips_atan2_const: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.ATAN2] on an image and a constant. See * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_atan2_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_math2_constv(in, out, VIPS_OPERATION_MATH2_ATAN2, c, n, ap); va_end(ap); return result; } /** * vips_math2_const1: (method) * @in: input image * @out: (out): output image * @math2: math operation to perform * @c: constant * @...: `NULL`-terminated list of optional named arguments * * This operation calculates various 2-ary maths operations on an image and * a constant. See [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_math2_const1(VipsImage *in, VipsImage **out, VipsOperationMath2 math2, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_math2_constv(in, out, math2, &c, 1, ap); va_end(ap); return result; } /** * vips_pow_const1: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.POW] on an image and a constant. See * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_pow_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_math2_constv(in, out, VIPS_OPERATION_MATH2_POW, &c, 1, ap); va_end(ap); return result; } /** * vips_wop_const1: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.WOP] on an image and a constant. See * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_wop_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_math2_constv(in, out, VIPS_OPERATION_MATH2_WOP, &c, 1, ap); va_end(ap); return result; } /** * vips_atan2_const1: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationMath2.ATAN2] on an image and a constant. See * [method@Image.math2_const]. * * Returns: 0 on success, -1 on error */ int vips_atan2_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_math2_constv(in, out, VIPS_OPERATION_MATH2_ATAN2, &c, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/max.c000066400000000000000000000315261516303661500200310ustar00rootroot00000000000000/* find image maximum * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 02/05/1990 * Modified on : 18/03/1991, N. Dessipris * 23/11/92: J.Cupitt - correct result for more than 1 band now. * 23/7/93 JC * - im_incheck() call added * 20/6/95 JC * - now returns double for value, like im_max() * 4/9/09 * - gtkdoc comment * 8/9/09 * - rewrite based on im_max() to get partial * - move im_max() in here as a convenience function * 6/11/11 * - rewrite as a class * - abandon scan if we find maximum possible value * 24/2/12 * - avoid NaN in float/double/complex images * - allow +/- INFINITY as a result * 4/12/12 * - track and return top n values * 24/1/17 * - sort equal values by y then x to make order more consistent */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "statistic.h" /* Track max values and position here. We need one of these for each thread, * and one for the main value. * * We will generally only be tracking a small (<10?) number of values, so * simple arrays will be fastest. */ typedef struct _VipsValues { struct _VipsMax *max; /* Number of values we track. */ int size; /* How many values we have in the arrays. */ int n; /* Position and values. We track mod**2 for complex and do a sqrt() at * the end. The three arrays are sorted by @value, smallest first. */ double *value; int *x_pos; int *y_pos; } VipsValues; typedef struct _VipsMax { VipsStatistic parent_instance; /* Max number of values we track. */ int size; /* The single max. Can be unset if, for example, the whole image is * NaN. */ double out; int x; int y; /* And the positions and values we found as VipsArrays for returning * to our caller. */ VipsArrayDouble *out_array; VipsArrayInt *x_array; VipsArrayInt *y_array; /* Global state here. */ VipsValues values; } VipsMax; static void vips_values_init(VipsValues *values, VipsMax *max) { values->max = max; values->size = max->size; values->n = 0; values->value = VIPS_ARRAY(max, values->size, double); values->x_pos = VIPS_ARRAY(max, values->size, int); values->y_pos = VIPS_ARRAY(max, values->size, int); } /* Add a value. Do nothing if the value is too small. */ static void vips_values_add(VipsValues *values, double v, int x, int y) { int i, j; /* Find insertion point. */ for (i = 0; i < values->n; i++) { if (v < values->value[i]) break; if (v == values->value[i]) { if (y < values->y_pos[i]) break; if (y == values->y_pos[i]) if (x <= values->x_pos[i]) break; } } /* Array full? */ if (values->n == values->size) { if (i > 0) { /* We need to move stuff to the left to make space, * shunting the smallest out. */ for (j = 0; j < i - 1; j++) { values->value[j] = values->value[j + 1]; values->x_pos[j] = values->x_pos[j + 1]; values->y_pos[j] = values->y_pos[j + 1]; } values->value[i - 1] = v; values->x_pos[i - 1] = x; values->y_pos[i - 1] = y; } } else { /* Not full, move stuff to the right into empty space. */ for (j = values->n; j > i; j--) { values->value[j] = values->value[j - 1]; values->x_pos[j] = values->x_pos[j - 1]; values->y_pos[j] = values->y_pos[j - 1]; } values->value[i] = v; values->x_pos[i] = x; values->y_pos[i] = y; values->n += 1; } } typedef VipsStatisticClass VipsMaxClass; G_DEFINE_TYPE(VipsMax, vips_max, VIPS_TYPE_STATISTIC); static int vips_max_build(VipsObject *object) { VipsStatistic *statistic = VIPS_STATISTIC(object); VipsMax *max = (VipsMax *) object; VipsValues *values = &max->values; vips_values_init(values, max); if (VIPS_OBJECT_CLASS(vips_max_parent_class)->build(object)) return -1; /* For speed we accumulate max ** 2 for complex. */ if (vips_band_format_iscomplex( vips_image_get_format(statistic->ready))) { int i; for (i = 0; i < values->n; i++) values->value[i] = sqrt(values->value[i]); } /* Don't set if there's no value (eg. if every pixel is NaN). This * will trigger an error later. */ if (values->n > 0) { VipsArrayDouble *out_array; VipsArrayInt *x_array; VipsArrayInt *y_array; out_array = vips_array_double_new(values->value, values->n); x_array = vips_array_int_new(values->x_pos, values->n); y_array = vips_array_int_new(values->y_pos, values->n); /* We have to set the props via g_object_set() to stop vips * complaining they are unset. */ g_object_set(max, "out", values->value[values->n - 1], "x", values->x_pos[values->n - 1], "y", values->y_pos[values->n - 1], "out_array", out_array, "x_array", x_array, "y_array", y_array, NULL); vips_area_unref(VIPS_AREA(out_array)); vips_area_unref(VIPS_AREA(x_array)); vips_area_unref(VIPS_AREA(y_array)); } #ifdef DEBUG { int i; printf("vips_max_build: %d values found\n", values->n); for (i = 0; i < values->n; i++) printf("%d) %g\t%d\t%d\n", i, values->value[i], values->x_pos[i], values->y_pos[i]); } #endif /*DEBUG*/ return 0; } /* New sequence value. Make a private VipsValues for this thread. */ static void * vips_max_start(VipsStatistic *statistic) { VipsValues *values; values = g_new(VipsValues, 1); vips_values_init(values, (VipsMax *) statistic); return (void *) values; } /* Merge the sequence value back into the per-call state. */ static int vips_max_stop(VipsStatistic *statistic, void *seq) { VipsMax *max = (VipsMax *) statistic; VipsValues *values = (VipsValues *) seq; int i; for (i = 0; i < values->n; i++) vips_values_add(&max->values, values->value[i], values->x_pos[i], values->y_pos[i]); g_free(values); return 0; } /* Real max with an upper bound. * * Add values to the buffer if they are greater than the buffer minimum. If * the buffer isn't full, there is no minimum. * * Avoid a double test by splitting the loop into two phases: before and after * the buffer fills. * * Stop if our array fills with maxval. */ #define LOOPU(TYPE, UPPER) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ for (i = 0; i < sz && values->n < values->size; i++) \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ \ for (; i < sz; i++) { \ if (p[i] > m) { \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ \ if (m >= UPPER) { \ statistic->stop = TRUE; \ break; \ } \ } \ } \ } /* float/double max ... no limits, and we have to avoid NaN. * * NaN compares false to every float value, so we don't need to test for NaN * in the second loop. */ #define LOOPF(TYPE) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ for (i = 0; i < sz && values->n < values->size; i++) \ if (!isnan(p[i])) \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ \ for (; i < sz; i++) \ if (p[i] > m) { \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ } \ } /* As LOOPF, but complex. Track max(mod ** 2) to avoid sqrt(). */ #define LOOPC(TYPE) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ for (i = 0; i < sz && values->n < values->size; i++) { \ TYPE mod2 = p[0] * p[0] + p[1] * p[1]; \ \ if (!isnan(mod2)) \ vips_values_add(values, mod2, x + i / bands, y); \ \ p += 2; \ } \ m = values->value[0]; \ \ for (; i < sz; i++) { \ TYPE mod2 = p[0] * p[0] + p[1] * p[1]; \ \ if (mod2 > m) { \ vips_values_add(values, mod2, x + i / bands, y); \ m = values->value[0]; \ } \ \ p += 2; \ } \ } /* Loop over region, adding to seq. */ static int vips_max_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { VipsValues *values = (VipsValues *) seq; const int bands = vips_image_get_bands(statistic->ready); const int sz = n * bands; int i; switch (vips_image_get_format(statistic->ready)) { case VIPS_FORMAT_UCHAR: LOOPU(unsigned char, UCHAR_MAX); break; case VIPS_FORMAT_CHAR: LOOPU(signed char, SCHAR_MAX); break; case VIPS_FORMAT_USHORT: LOOPU(unsigned short, USHRT_MAX); break; case VIPS_FORMAT_SHORT: LOOPU(signed short, SHRT_MAX); break; case VIPS_FORMAT_UINT: LOOPU(unsigned int, UINT_MAX); break; case VIPS_FORMAT_INT: LOOPU(signed int, INT_MAX); break; case VIPS_FORMAT_FLOAT: LOOPF(float); break; case VIPS_FORMAT_DOUBLE: LOOPF(double); break; case VIPS_FORMAT_COMPLEX: LOOPC(float); break; case VIPS_FORMAT_DPCOMPLEX: LOOPC(double); break; default: g_assert_not_reached(); } return 0; } static void vips_max_class_init(VipsMaxClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "max"; object_class->description = _("find image maximum"); object_class->build = vips_max_build; sclass->start = vips_max_start; sclass->scan = vips_max_scan; sclass->stop = vips_max_stop; VIPS_ARG_DOUBLE(class, "out", 1, _("Output"), _("Output value"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMax, out), -INFINITY, INFINITY, 0.0); VIPS_ARG_INT(class, "x", 2, _("x"), _("Horizontal position of maximum"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMax, x), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "y", 3, _("y"), _("Vertical position of maximum"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMax, y), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "size", 4, _("Size"), _("Number of maximum values to find"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMax, size), 1, 1000000, 1); VIPS_ARG_BOXED(class, "out_array", 6, _("Output array"), _("Array of output values"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMax, out_array), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOXED(class, "x_array", 7, _("x array"), _("Array of horizontal positions"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMax, x_array), VIPS_TYPE_ARRAY_INT); VIPS_ARG_BOXED(class, "y_array", 8, _("y array"), _("Array of vertical positions"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMax, y_array), VIPS_TYPE_ARRAY_INT); } static void vips_max_init(VipsMax *max) { max->size = 1; } /** * vips_max: (method) * @in: input [class@Image] * @out: (out): output pixel maximum * @...: `NULL`-terminated list of optional named arguments * * This operation finds the maximum value in an image. * * By default it finds the single largest value. If @size is set >1, it will * find the @size largest values. It will stop searching early if has found * enough values. * Equal values will be sorted by y then x. * * It operates on all * bands of the input image: use [method@Image.stats] if you need to find an * maximum for each band. * * For complex images, this operation finds the maximum modulus. * * You can read out the position of the maximum with @x and @y. You can read * out arrays of the values and positions of the top @size maxima with * @out_array, @x_array and @y_array. These values are returned sorted from * largest to smallest. * * If there are more than @size maxima, the maxima returned will be a random * selection of the maxima in the image. * * ::: tip "Optional arguments" * * @x: `gint`, output, horizontal position of maximum * * @y: `gint`, output, vertical position of maximum * * @size: `gint`, number of maxima to find * * @out_array: [struct@ArrayDouble], output, array of maximum values * * @x_array: [struct@ArrayInt], output, corresponding horizontal positions * * @y_array: [struct@ArrayInt]. output, corresponding vertical positions * * ::: seealso * [method@Image.min], [method@Image.stats]. * * Returns: 0 on success, -1 on error */ int vips_max(VipsImage *in, double *out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("max", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/maxpair.c000066400000000000000000000100761516303661500207020ustar00rootroot00000000000000/* max of a pair of images * * 18/6/24 * - from add.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" typedef VipsBinary VipsMaxpair; typedef VipsBinaryClass VipsMaxpairClass; G_DEFINE_TYPE(VipsMaxpair, vips_maxpair, VIPS_TYPE_BINARY); #define LOOP(TYPE) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (int x = 0; x < sz; x++) \ q[x] = VIPS_MAX(left[x], right[x]); \ } #define FLOOP(TYPE) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (int x = 0; x < sz; x++) \ q[x] = fmax(left[x], right[x]); \ } static void maxpair_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; int bands = vips_image_get_bands(im); VipsBandFormat format = vips_image_get_format(im); int sz = width * bands * (vips_band_format_iscomplex(format) ? 2 : 1); /* Maxpair all input types. Keep types here in sync with * vips_maxpair_format_table[] below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOP(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOP(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: FLOOP(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: FLOOP(double); break; default: g_assert_not_reached(); } } #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_maxpair_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_maxpair_class_init(VipsMaxpairClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "maxpair"; object_class->description = _("maximum of a pair of images"); aclass->process_line = maxpair_buffer; vips_arithmetic_set_format_table(aclass, vips_maxpair_format_table); } static void vips_maxpair_init(VipsMaxpair *maxpair) { } /** * vips_maxpair: (method) * @left: input image * @right: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * For each pixel, pick the maximum of a pair of images. * * ::: seealso * [method@Image.minpair]. * * Returns: 0 on success, -1 on error */ int vips_maxpair(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("maxpair", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/measure.c000066400000000000000000000163021516303661500207000ustar00rootroot00000000000000/* im_measure.c * * Modified: * 19/8/94 JC * - now uses doubles for addressing * - could miss by up to h pixels previously! * - ANSIfied * - now issues warning if any deviations are greater than 20% of the * mean * 31/10/95 JC * - more careful about warning for averages <0, or averages near zero * - can get these cases with im_measure() of IM_TYPE_LAB images * 28/10/02 JC * - number bands from zero in error messages * 7/7/04 * - works on labq * 18/8/08 * - add gtkdoc comments * - remove deprecated im_extract() * 30/11/09 * - changes for im_extract() broke averaging * 9/11/11 * - redo as a class * 19/5/14 * - add auto-unpack */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "statistic.h" typedef struct _VipsMeasure { VipsOperation parent_instance; VipsImage *in; VipsImage *out; int left; int top; int width; int height; int h; int v; } VipsMeasure; typedef VipsOperationClass VipsMeasureClass; G_DEFINE_TYPE(VipsMeasure, vips_measure, VIPS_TYPE_OPERATION); static int vips_measure_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsMeasure *measure = (VipsMeasure *) object; VipsImage *ready; int bands; double pw; double ph; int j, i; int w, h; int b; if (VIPS_OBJECT_CLASS(vips_measure_parent_class)->build(object)) return -1; if (vips_image_decode(measure->in, &ready)) return -1; vips_object_local(measure, ready); bands = vips_image_get_bands(ready); g_object_set(object, "out", vips_image_new_matrix(bands, measure->h * measure->v), NULL); /* left/top/width/height default to the size of the image. */ if (!vips_object_argument_isset(object, "width")) measure->width = vips_image_get_width(ready); // FIXME: Invalidates operation cache if (!vips_object_argument_isset(object, "height")) measure->height = vips_image_get_height(ready); // FIXME: Invalidates operation cache /* How large are the patches we are to measure? */ pw = (double) measure->width / measure->h; ph = (double) measure->height / measure->v; /* The size of a patch. */ w = (pw + 1) / 2; h = (ph + 1) / 2; for (j = 0; j < measure->v; j++) { for (i = 0; i < measure->h; i++) { int x = measure->left + i * pw + (pw + 2) / 4; int y = measure->top + j * ph + (ph + 2) / 4; double avg, dev; for (b = 0; b < bands; b++) { VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); /* Extract and measure. */ if (vips_extract_area(ready, &t[0], x, y, w, h, NULL) || vips_extract_band(t[0], &t[1], b, NULL) || vips_avg(t[1], &avg, NULL) || vips_deviate(t[1], &dev, NULL)) return -1; /* Is the deviation large compared with the * average? This could be a clue that our * parameters have caused us to miss the * patch. Look out for averages <0, or * averages near zero (can get these if use * measure on IM_TYPE_LAB images). */ if (dev * 5 > fabs(avg) && fabs(avg) > 3) g_warning("%s: " "patch %d x %d, " "band %d: " "avg = %g, sdev = %g", class->nickname, i, j, b, avg, dev); *VIPS_MATRIX(measure->out, b, i + j * measure->h) = avg; } } } return 0; } static void vips_measure_class_init(VipsMeasureClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "measure"; object_class->description = _("measure a set of patches on a color chart"); object_class->build = vips_measure_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Image to measure"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMeasure, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output array of statistics"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMeasure, out)); VIPS_ARG_INT(class, "h", 5, _("Across"), _("Number of patches across chart"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMeasure, h), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "v", 6, _("Down"), _("Number of patches down chart"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMeasure, v), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "left", 10, _("Left"), _("Left edge of extract area"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMeasure, left), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "top", 11, _("Top"), _("Top edge of extract area"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMeasure, top), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "width", 12, _("Width"), _("Width of extract area"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMeasure, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 13, _("Height"), _("Height of extract area"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMeasure, height), 1, VIPS_MAX_COORD, 1); } static void vips_measure_init(VipsMeasure *measure) { } /** * vips_measure: (method) * @in: image to measure * @out: (out): array of measurements * @h: patches across chart * @v: patches down chart * @...: `NULL`-terminated list of optional named arguments * * Analyse a grid of colour patches, producing an array of patch averages. * The mask has a row for each measured patch and a column for each image * band. The operations issues a warning if any patch has a deviation more * than 20% of * the mean. Only the central 50% of each patch is averaged. * * If the chart does not fill the whole image, use the optional @left, @top, * @width, @height arguments to indicate the * position of the chart. * * ::: tip "Optional arguments" * * @left: `gint`, area of image containing chart * * @top: `gint`, area of image containing chart * * @width: `gint`, area of image containing chart * * @height: `gint`, area of image containing chart * * ::: seealso * [method@Image.avg], [method@Image.deviate]. * * Returns: 0 on success, -1 on error */ int vips_measure(VipsImage *in, VipsImage **out, int h, int v, ...) { va_list ap; int result; va_start(ap, v); result = vips_call_split("measure", ap, in, out, h, v); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/meson.build000066400000000000000000000021351516303661500212340ustar00rootroot00000000000000arithmetic_sources = files( 'abs.c', 'add.c', 'arithmetic.c', 'avg.c', 'binary.c', 'boolean.c', 'clamp.c', 'complex.c', 'deviate.c', 'divide.c', 'find_trim.c', 'getpoint.c', 'hist_find.c', 'hist_find_indexed.c', 'hist_find_ndim.c', 'hough.c', 'hough_circle.c', 'hough_line.c', 'invert.c', 'linear.c', 'math2.c', 'math.c', 'max.c', 'maxpair.c', 'measure.c', 'min.c', 'minpair.c', 'multiply.c', 'nary.c', 'profile.c', 'project.c', 'relational.c', 'remainder.c', 'round.c', 'sign.c', 'statistic.c', 'stats.c', 'subtract.c', 'sum.c', 'unary.c', 'unaryconst.c', ) arithmetic_headers = files( 'binary.h', 'hough.h', 'nary.h', 'parithmetic.h', 'statistic.h', 'unaryconst.h', 'unary.h', ) libvips_sources += arithmetic_sources arithmetic_lib = static_library('arithmetic', arithmetic_sources, arithmetic_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += arithmetic_lib libvips-8.18.2/libvips/arithmetic/min.c000066400000000000000000000313031516303661500200200ustar00rootroot00000000000000/* find image minimum * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 02/05/1990 * Modified on : 18/03/1991, N. Dessipris * 23/11/92 JC * - correct result for more than 1 band now. * 23/7/93 JC * - im_incheck() added * 20/6/95 JC * - now returns double for value, like im_min() * 4/9/09 * - gtkdoc comment * 8/9/09 * - rewrite, from im_minpos() * 30/8/11 * - rewrite as a class * 5/9/11 * - abandon scan if we find minimum possible value * 24/2/12 * - avoid NaN in float/double/complex images * - allow +/- INFINITY as a result * 4/12/12 * - from min.c * - track and return bottom n values */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "statistic.h" /* Track min values and position here. We need one of these for each thread, * and one for the main value. * * We will generally only be tracking a small (<10?) number of values, so * simple arrays will be fastest. */ typedef struct _VipsValues { struct _VipsMin *min; /* The min number of values we track. */ int size; /* How many values we have in the arrays. */ int n; /* Position and values. We track mod**2 for complex and do a sqrt() at * the end. The three arrays are sorted by @value, largest first. */ double *value; int *x_pos; int *y_pos; } VipsValues; typedef struct _VipsMin { VipsStatistic parent_instance; /* Number of values we track. */ int size; /* The single min. Can be unset if, for example, the whole image is * NaN. */ double min; int x; int y; /* And the positions and values we found as VipsArrays for returning * to our caller. */ VipsArrayDouble *min_array; VipsArrayInt *x_array; VipsArrayInt *y_array; /* Global state here. */ VipsValues values; } VipsMin; static void vips_values_init(VipsValues *values, VipsMin *min) { values->min = min; values->size = min->size; values->n = 0; values->value = VIPS_ARRAY(min, values->size, double); values->x_pos = VIPS_ARRAY(min, values->size, int); values->y_pos = VIPS_ARRAY(min, values->size, int); } /* Add a value. Do nothing if the value is too large. */ static void vips_values_add(VipsValues *values, double v, int x, int y) { int i, j; /* Find insertion point. */ for (i = 0; i < values->n; i++) { if (v > values->value[i]) break; if (v == values->value[i]) { if (y < values->y_pos[i]) break; if (y == values->y_pos[i]) if (x <= values->x_pos[i]) break; } } /* Array full? */ if (values->n == values->size) { if (i > 0) { /* We need to move stuff to the left to make space, * shunting the largest out. */ for (j = 0; j < i - 1; j++) { values->value[j] = values->value[j + 1]; values->x_pos[j] = values->x_pos[j + 1]; values->y_pos[j] = values->y_pos[j + 1]; } values->value[i - 1] = v; values->x_pos[i - 1] = x; values->y_pos[i - 1] = y; } } else { /* Not full, move stuff to the right into empty space. */ for (j = values->n; j > i; j--) { values->value[j] = values->value[j - 1]; values->x_pos[j] = values->x_pos[j - 1]; values->y_pos[j] = values->y_pos[j - 1]; } values->value[i] = v; values->x_pos[i] = x; values->y_pos[i] = y; values->n += 1; } } typedef VipsStatisticClass VipsMinClass; G_DEFINE_TYPE(VipsMin, vips_min, VIPS_TYPE_STATISTIC); static int vips_min_build(VipsObject *object) { VipsStatistic *statistic = VIPS_STATISTIC(object); VipsMin *min = (VipsMin *) object; VipsValues *values = &min->values; vips_values_init(values, min); if (VIPS_OBJECT_CLASS(vips_min_parent_class)->build(object)) return -1; /* For speed we accumulate min ** 2 for complex. */ if (vips_band_format_iscomplex( vips_image_get_format(statistic->ready))) { int i; for (i = 0; i < values->n; i++) values->value[i] = sqrt(values->value[i]); } /* Don't set if there's no value (eg. if every pixel is NaN). This * will trigger an error later. */ if (values->n > 0) { VipsArrayDouble *out_array; VipsArrayInt *x_array; VipsArrayInt *y_array; out_array = vips_array_double_new(values->value, values->n); x_array = vips_array_int_new(values->x_pos, values->n); y_array = vips_array_int_new(values->y_pos, values->n); /* We have to set the props via g_object_set() to stop vips * complaining they are unset. */ g_object_set(min, "out", values->value[values->n - 1], "x", values->x_pos[values->n - 1], "y", values->y_pos[values->n - 1], "out_array", out_array, "x_array", x_array, "y_array", y_array, NULL); vips_area_unref(VIPS_AREA(out_array)); vips_area_unref(VIPS_AREA(x_array)); vips_area_unref(VIPS_AREA(y_array)); } #ifdef DEBUG { int i; printf("vips_min_build: %d values found\n", values->n); for (i = 0; i < values->n; i++) printf("%d) %g\t%d\t%d\n", i, values->value[i], values->x_pos[i], values->y_pos[i]); } #endif /*DEBUG*/ return 0; } /* New sequence value. Make a private VipsValues for this thread. */ static void * vips_min_start(VipsStatistic *statistic) { VipsValues *values; values = g_new(VipsValues, 1); vips_values_init(values, (VipsMin *) statistic); return (void *) values; } /* Merge the sequence value back into the per-call state. */ static int vips_min_stop(VipsStatistic *statistic, void *seq) { VipsMin *min = (VipsMin *) statistic; VipsValues *values = (VipsValues *) seq; int i; for (i = 0; i < values->n; i++) vips_values_add(&min->values, values->value[i], values->x_pos[i], values->y_pos[i]); g_free(values); return 0; } /* Real min with a lower bound. * * Add values to the buffer if they are less than the buffer maximum. If * the buffer isn't full, there is no maximum. * * Avoid a double test by splitting the loop into two phases: before and after * the buffer fills. * * Stop if our array fills with minval. */ #define LOOPU(TYPE, LOWER) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ for (i = 0; i < sz && values->n < values->size; i++) \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ \ for (; i < sz; i++) { \ if (p[i] < m) { \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ \ if (m <= LOWER) { \ statistic->stop = TRUE; \ break; \ } \ } \ } \ } /* float/double min ... no limits, and we have to avoid NaN. * * NaN compares false to every float value, so we don't need to test for NaN * in the second loop. */ #define LOOPF(TYPE) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ for (i = 0; i < sz && values->n < values->size; i++) \ if (!isnan(p[i])) \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ \ for (; i < sz; i++) \ if (p[i] < m) { \ vips_values_add(values, p[i], x + i / bands, y); \ m = values->value[0]; \ } \ } /* As LOOPF, but complex. Track min(mod ** 2) to avoid sqrt(). */ #define LOOPC(TYPE) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ for (i = 0; i < sz && values->n < values->size; i++) { \ TYPE mod2 = p[0] * p[0] + p[1] * p[1]; \ \ if (!isnan(mod2)) \ vips_values_add(values, mod2, x + i / bands, y); \ \ p += 2; \ } \ m = values->value[0]; \ \ for (; i < sz; i++) { \ TYPE mod2 = p[0] * p[0] + p[1] * p[1]; \ \ if (mod2 < m) { \ vips_values_add(values, mod2, x + i / bands, y); \ m = values->value[0]; \ } \ \ p += 2; \ } \ } /* Loop over region, adding to seq. */ static int vips_min_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { VipsValues *values = (VipsValues *) seq; const int bands = vips_image_get_bands(statistic->ready); const int sz = n * bands; int i; switch (vips_image_get_format(statistic->ready)) { case VIPS_FORMAT_UCHAR: LOOPU(unsigned char, 0); break; case VIPS_FORMAT_CHAR: LOOPU(signed char, SCHAR_MIN); break; case VIPS_FORMAT_USHORT: LOOPU(unsigned short, 0); break; case VIPS_FORMAT_SHORT: LOOPU(signed short, SHRT_MIN); break; case VIPS_FORMAT_UINT: LOOPU(unsigned int, 0); break; case VIPS_FORMAT_INT: LOOPU(signed int, INT_MIN); break; case VIPS_FORMAT_FLOAT: LOOPF(float); break; case VIPS_FORMAT_DOUBLE: LOOPF(double); break; case VIPS_FORMAT_COMPLEX: LOOPC(float); break; case VIPS_FORMAT_DPCOMPLEX: LOOPC(double); break; default: g_assert_not_reached(); } return 0; } static void vips_min_class_init(VipsMinClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "min"; object_class->description = _("find image minimum"); object_class->build = vips_min_build; sclass->start = vips_min_start; sclass->scan = vips_min_scan; sclass->stop = vips_min_stop; VIPS_ARG_DOUBLE(class, "out", 1, _("Output"), _("Output value"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMin, min), -INFINITY, INFINITY, 0.0); VIPS_ARG_INT(class, "x", 2, _("x"), _("Horizontal position of minimum"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMin, x), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "y", 3, _("y"), _("Vertical position of minimum"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMin, y), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "size", 4, _("Size"), _("Number of minimum values to find"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMin, size), 1, 1000000, 1); VIPS_ARG_BOXED(class, "out_array", 6, _("Output array"), _("Array of output values"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMin, min_array), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOXED(class, "x_array", 7, _("x array"), _("Array of horizontal positions"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMin, x_array), VIPS_TYPE_ARRAY_INT); VIPS_ARG_BOXED(class, "y_array", 8, _("y array"), _("Array of vertical positions"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMin, y_array), VIPS_TYPE_ARRAY_INT); } static void vips_min_init(VipsMin *min) { min->size = 1; } /** * vips_min: (method) * @in: input [class@Image] * @out: (out): output pixel minimum * @...: `NULL`-terminated list of optional named arguments * * This operation finds the minimum value in an image. * * By default it finds the single smallest value. If @size is set >1, it will * find the @size smallest values. It will stop searching early if has found * enough values. * Equal values will be sorted by y then x. * * It operates on all * bands of the input image: use [method@Image.stats] if you need to find an * minimum for each band. * * For complex images, this operation finds the minimum modulus. * * You can read out the position of the minimum with @x and @y. You can read * out arrays of the values and positions of the top @size minima with * @out_array, @x_array and @y_array. * These values are returned sorted from * smallest to largest. * * If there are more than @size minima, the minima returned will be a random * selection of the minima in the image. * * ::: tip "Optional arguments" * * @x: `gint`, output, horizontal position of minimum * * @y: `gint`, output, vertical position of minimum * * @size: `gint`, number of minima to find * * @out_array: [struct@ArrayDouble], output, array of minimum values * * @x_array: [struct@ArrayInt], output, corresponding horizontal positions * * @y_array: [struct@ArrayInt], output, corresponding vertical positions * * ::: seealso * [method@Image.min], [method@Image.stats]. * * Returns: 0 on success, -1 on error */ int vips_min(VipsImage *in, double *out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("min", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/minpair.c000066400000000000000000000101021516303661500206660ustar00rootroot00000000000000/* min of a pair of images * * 18/6/24 * - from maxpair.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" typedef VipsBinary VipsMinpair; typedef VipsBinaryClass VipsMinpairClass; G_DEFINE_TYPE(VipsMinpair, vips_minpair, VIPS_TYPE_BINARY); #define LOOP(TYPE) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (int x = 0; x < sz; x++) \ q[x] = VIPS_MIN(left[x], right[x]); \ } #define FLOOP(TYPE) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (int x = 0; x < sz; x++) \ q[x] = fmin(left[x], right[x]); \ } static void minpair_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; int bands = vips_image_get_bands(im); VipsBandFormat format = vips_image_get_format(im); int sz = width * bands * (vips_band_format_iscomplex(format) ? 2 : 1); /* Minpair all input types. Keep types here in sync with * vips_minpair_format_table[] below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOP(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOP(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: FLOOP(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: FLOOP(double); break; default: g_assert_not_reached(); } } #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_minpair_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_minpair_class_init(VipsMinpairClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "minpair"; object_class->description = _("minimum of a pair of images"); aclass->process_line = minpair_buffer; vips_arithmetic_set_format_table(aclass, vips_minpair_format_table); } static void vips_minpair_init(VipsMinpair *minpair) { } /** * vips_minpair: (method) * @left: input image * @right: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * For each pixel, pick the minimum of a pair of images. * * ::: seealso * [method@Image.minpair]. * * Returns: 0 on success, -1 on error */ int vips_minpair(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("minpair", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/multiply.c000066400000000000000000000151351516303661500211210ustar00rootroot00000000000000/* im_multiply.c * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 29/4/93 JC * - now works for partial images * 1/7/93 JC * - adapted for partial v2 * - ANSIfied * 19/10/93 JC * - coredump-inducing bug in complex*complex fixed * 13/12/93 * - char * short bug fixed * 12/6/95 JC * - new im_add adapted to make new im_multiply * 27/9/04 * - updated for 1 band $op n band image -> n band image case * 8/12/06 * - add liboil support * 18/8/08 * - revise upcasting system * - add gtkdoc comments * 31/7/10 * - remove liboil * 7/11/11 * - redo as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "binary.h" typedef VipsBinary VipsMultiply; typedef VipsBinaryClass VipsMultiplyClass; G_DEFINE_TYPE(VipsMultiply, vips_multiply, VIPS_TYPE_BINARY); /* Complex multiply. */ #define CLOOP(TYPE) \ { \ TYPE *restrict left = (TYPE *) in[0]; \ TYPE *restrict right = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) { \ double x1 = left[0]; \ double y1 = left[1]; \ double x2 = right[0]; \ double y2 = right[1]; \ \ left += 2; \ right += 2; \ \ q[0] = x1 * x2 - y1 * y2; \ q[1] = x1 * y2 + x2 * y1; \ \ q += 2; \ } \ } /* Real multiply. */ #define RLOOP(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = (OUT) left[x] * right[x]; \ } /* Special case for VIPS_FORMAT_INT, to prevent UB. */ #define RLOOP_INT64(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = (int64_t) left[x] * right[x]; \ } static void vips_multiply_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; /* Keep types here in sync with vips_bandfmt_multiply[] * below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: RLOOP(signed char, signed short); break; case VIPS_FORMAT_UCHAR: RLOOP(unsigned char, unsigned short); break; case VIPS_FORMAT_SHORT: RLOOP(signed short, signed int); break; case VIPS_FORMAT_USHORT: RLOOP(unsigned short, unsigned int); break; case VIPS_FORMAT_INT: RLOOP_INT64(signed int, signed int); break; case VIPS_FORMAT_UINT: RLOOP(unsigned int, unsigned int); break; case VIPS_FORMAT_FLOAT: RLOOP(float, float); break; case VIPS_FORMAT_DOUBLE: RLOOP(double, double); break; case VIPS_FORMAT_COMPLEX: CLOOP(float); break; case VIPS_FORMAT_DPCOMPLEX: CLOOP(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for multiplication. Sign and value preserving. Make sure * these match the case statement in multiply_buffer() above. */ static const VipsBandFormat vips_multiply_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ US, S, UI, I, UI, I, F, X, D, DX }; static void vips_multiply_class_init(VipsMultiplyClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "multiply"; object_class->description = _("multiply two images"); aclass->process_line = vips_multiply_buffer; vips_arithmetic_set_format_table(aclass, vips_multiply_format_table); } static void vips_multiply_init(VipsMultiply *multiply) { } /** * vips_multiply: (method) * @left: left-hand image * @right: right-hand image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @left * @right and writes the result to @out. * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), then the * following table is used to determine the output type: * * ## [method@Image.multiply] type promotion * * | input type | output type | * |----------------|----------------| * | uchar | ushort | * | char | short | * | ushort | uint | * | short | int | * | uint | uint | * | int | int | * | float | float | * | double | double | * | complex | complex | * | double complex | double complex | * * In other words, the output type is just large enough to hold the whole * range of possible values. * * ::: seealso * [method@Image.add], [method@Image.linear]. * * Returns: 0 on success, -1 on error */ int vips_multiply(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("multiply", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/nary.c000066400000000000000000000045331516303661500202130ustar00rootroot00000000000000/* base class for all nary operations * * 18/3/14 * - from binary.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "nary.h" G_DEFINE_ABSTRACT_TYPE(VipsNary, vips_nary, VIPS_TYPE_ARITHMETIC); static int vips_nary_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsArithmetic *arithmetic = VIPS_ARITHMETIC(object); VipsNary *nary = VIPS_NARY(object); if (nary->in) { arithmetic->in = nary->in->data; arithmetic->n = nary->in->n; } if (arithmetic->n <= 0) { vips_error(class->nickname, "%s", _("no input images")); return -1; } if (VIPS_OBJECT_CLASS(vips_nary_parent_class)->build(object)) return -1; return 0; } static void vips_nary_class_init(VipsNaryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "nary"; vobject_class->description = _("nary operations"); vobject_class->build = vips_nary_build; /* Create properties. */ VIPS_ARG_BOXED(class, "in", 0, _("Input"), _("Array of input images"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsNary, in), VIPS_TYPE_ARRAY_IMAGE); } static void vips_nary_init(VipsNary *nary) { /* Init our instance fields. */ } libvips-8.18.2/libvips/arithmetic/nary.h000066400000000000000000000034401516303661500202140ustar00rootroot00000000000000/* base class for all nary arithmetic operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_NARY_H #define VIPS_NARY_H #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include "parithmetic.h" #define VIPS_TYPE_NARY (vips_nary_get_type()) #define VIPS_NARY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), VIPS_TYPE_NARY, VipsNary)) #define VIPS_NARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), VIPS_TYPE_NARY, VipsNaryClass)) #define VIPS_IS_NARY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_NARY)) #define VIPS_IS_NARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_NARY)) #define VIPS_NARY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), VIPS_TYPE_NARY, VipsNaryClass)) typedef struct _VipsNary { VipsArithmetic parent_instance; /* The input images. */ VipsArea *in; } VipsNary; typedef VipsArithmeticClass VipsNaryClass; GType vips_nary_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_NARY_H*/ libvips-8.18.2/libvips/arithmetic/parithmetic.h000066400000000000000000000054541516303661500215630ustar00rootroot00000000000000/* base class for all arithmetic operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PARITHMETIC_H #define VIPS_PARITHMETIC_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include #define VIPS_TYPE_ARITHMETIC (vips_arithmetic_get_type()) #define VIPS_ARITHMETIC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_ARITHMETIC, VipsArithmetic)) #define VIPS_ARITHMETIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_ARITHMETIC, VipsArithmeticClass)) #define VIPS_IS_ARITHMETIC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_ARITHMETIC)) #define VIPS_IS_ARITHMETIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_ARITHMETIC)) #define VIPS_ARITHMETIC_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_ARITHMETIC, VipsArithmeticClass)) struct _VipsArithmetic; typedef void (*VipsArithmeticProcessFn)(struct _VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width); typedef struct _VipsArithmetic { VipsOperation parent_instance; /* All have an output image. */ VipsImage *out; /* Array of input arguments, set these from a subclass. */ VipsImage **in; int n; /* The minimum number of output bands. For example, VipsLinear with a * three element constant must make at least a three-band output. */ int base_bands; /* The input images, ready for the operation. */ VipsImage **ready; /* Set this to override class->format_table. */ VipsBandFormat format; } VipsArithmetic; typedef struct _VipsArithmeticClass { VipsOperationClass parent_class; /* For each input format, what output format. Used for arithmetic * too, since we cast inputs to match. */ const VipsBandFormat *format_table; /* The buffer processor. */ VipsArithmeticProcessFn process_line; } VipsArithmeticClass; GType vips_arithmetic_get_type(void); void vips_arithmetic_set_format_table(VipsArithmeticClass *klass, const VipsBandFormat *format_table); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PARITHMETIC_H*/ libvips-8.18.2/libvips/arithmetic/profile.c000066400000000000000000000172331516303661500207030ustar00rootroot00000000000000/* find image profiles * * 11/8/99 JC * - from im_cntlines() * 22/4/04 * - now outputs horizontal/vertical image * 9/11/10 * - any image format, any number of bands * - gtk-doc * 21/9/13 * - rewrite as a class * - output h and v profile in one pass * - partial * - output is int rather than ushort */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "statistic.h" struct _Edges; typedef struct { /* Horizontal array: Ys of top-most non-zero pixel. */ int *column_edges; /* Vertical array: Xs of left-most non-zero pixel. */ int *row_edges; } Edges; typedef struct _VipsProfile { VipsStatistic parent_instance; /* Main edge set. Threads accumulate to this. */ Edges *edges; /* Write profiles here. */ VipsImage *columns; VipsImage *rows; } VipsProfile; typedef VipsStatisticClass VipsProfileClass; G_DEFINE_TYPE(VipsProfile, vips_profile, VIPS_TYPE_STATISTIC); static Edges * edges_new(VipsProfile *profile) { VipsStatistic *statistic = VIPS_STATISTIC(profile); VipsImage *in = statistic->ready; Edges *edges; int i; if (!(edges = VIPS_NEW(profile, Edges))) return NULL; edges->column_edges = VIPS_ARRAY(profile, in->Xsize * in->Bands, int); edges->row_edges = VIPS_ARRAY(profile, in->Ysize * in->Bands, int); if (!edges->column_edges || !edges->row_edges) return NULL; for (i = 0; i < in->Xsize * in->Bands; i++) edges->column_edges[i] = in->Ysize; for (i = 0; i < in->Ysize * in->Bands; i++) edges->row_edges[i] = in->Xsize; return edges; } static int vips_profile_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsProfile *profile = (VipsProfile *) object; int y; if (statistic->in && vips_check_noncomplex(class->nickname, statistic->in)) return -1; g_object_set(object, "columns", vips_image_new(), "rows", vips_image_new(), NULL); /* main edge set made on first thread start. */ if (VIPS_OBJECT_CLASS(vips_profile_parent_class)->build(object)) return -1; /* Make the output image. */ if (vips_image_pipelinev(profile->columns, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL) || vips_image_pipelinev(profile->rows, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL)) return -1; profile->columns->Ysize = 1; profile->columns->BandFmt = VIPS_FORMAT_INT; profile->columns->Type = VIPS_INTERPRETATION_HISTOGRAM; profile->rows->Xsize = 1; profile->rows->BandFmt = VIPS_FORMAT_INT; profile->rows->Type = VIPS_INTERPRETATION_HISTOGRAM; if (vips_image_write_line(profile->columns, 0, (VipsPel *) profile->edges->column_edges)) return -1; for (y = 0; y < profile->rows->Ysize; y++) if (vips_image_write_line(profile->rows, y, (VipsPel *) profile->edges->row_edges + y * VIPS_IMAGE_SIZEOF_PEL(profile->rows))) return -1; return 0; } /* New edge accumulator. */ static void * vips_profile_start(VipsStatistic *statistic) { VipsProfile *profile = (VipsProfile *) statistic; /* Make the main hist, if necessary. */ if (!profile->edges) profile->edges = edges_new(profile); return (void *) edges_new(profile); } /* We do this a lot. */ #define MINBANG(V, C) ((V) = VIPS_MIN(V, C)) /* Add a line of pixels. */ #define ADD_PIXELS(TYPE) \ { \ TYPE *p; \ int *column_edges; \ int *row_edges; \ \ p = (TYPE *) in; \ column_edges = edges->column_edges + x * nb; \ row_edges = edges->row_edges + y * nb; \ for (i = 0; i < n; i++) { \ for (j = 0; j < nb; j++) { \ if (p[j]) { \ MINBANG(column_edges[j], y); \ MINBANG(row_edges[j], x + i); \ } \ } \ \ p += nb; \ column_edges += nb; \ } \ } /* Add a region to a profile. */ static int vips_profile_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { int nb = statistic->ready->Bands; Edges *edges = (Edges *) seq; int i, j; switch (statistic->ready->BandFmt) { case VIPS_FORMAT_UCHAR: ADD_PIXELS(guchar); break; case VIPS_FORMAT_CHAR: ADD_PIXELS(char); break; case VIPS_FORMAT_USHORT: ADD_PIXELS(gushort); break; case VIPS_FORMAT_SHORT: ADD_PIXELS(short); break; case VIPS_FORMAT_UINT: ADD_PIXELS(guint); break; case VIPS_FORMAT_INT: ADD_PIXELS(int); break; case VIPS_FORMAT_FLOAT: ADD_PIXELS(float); break; case VIPS_FORMAT_DOUBLE: ADD_PIXELS(double); break; default: g_assert_not_reached(); } return 0; } /* Join a sub-profile onto the main profile. */ static int vips_profile_stop(VipsStatistic *statistic, void *seq) { VipsProfile *profile = (VipsProfile *) statistic; Edges *edges = profile->edges; Edges *sub_edges = (Edges *) seq; VipsImage *in = statistic->ready; int i; for (i = 0; i < in->Xsize * in->Bands; i++) MINBANG(edges->column_edges[i], sub_edges->column_edges[i]); for (i = 0; i < in->Ysize * in->Bands; i++) MINBANG(edges->row_edges[i], sub_edges->row_edges[i]); /* Blank out sub-profile to make sure we can't add it again. */ sub_edges->row_edges = NULL; sub_edges->column_edges = NULL; return 0; } static void vips_profile_class_init(VipsProfileClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "profile"; object_class->description = _("find image profiles"); object_class->build = vips_profile_build; sclass->start = vips_profile_start; sclass->scan = vips_profile_scan; sclass->stop = vips_profile_stop; VIPS_ARG_IMAGE(class, "columns", 100, _("Columns"), _("First non-zero pixel in column"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsProfile, columns)); VIPS_ARG_IMAGE(class, "rows", 101, _("Rows"), _("First non-zero pixel in row"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsProfile, rows)); } static void vips_profile_init(VipsProfile *profile) { } /** * vips_profile: (method) * @in: input image * @columns: (out): distances from top edge * @rows: (out): distances from left edge * @...: `NULL`-terminated list of optional named arguments * * [method@Image.profile] searches inward from the edge of @in and finds the * first non-zero pixel. Pixels in @columns have the distance from the top edge * to the first non-zero pixel in that column, @rows has the distance from the * left edge to the first non-zero pixel in that row. * * ::: seealso * [method@Image.project], [method@Image.hist_find]. * * Returns: 0 on success, -1 on error */ int vips_profile(VipsImage *in, VipsImage **columns, VipsImage **rows, ...) { va_list ap; int result; va_start(ap, rows); result = vips_call_split("profile", ap, in, columns, rows); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/project.c000066400000000000000000000207551516303661500207140ustar00rootroot00000000000000/* horizontal and vertical projection * * 20/4/06 * - from im_histgr() * 25/3/10 * - gtkdoc * - small celanups * 11/9/13 * - redo as a class, from vips_hist_find() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "statistic.h" struct _Project; typedef struct { /* Horizontal array: sums of all columns. */ void *column_sums; /* Vertical array: sums of all rows. */ void *row_sums; } Histogram; typedef struct _VipsProject { VipsStatistic parent_instance; /* Main image histogram. Subhists accumulate to this. */ Histogram *hist; /* Write sums here. */ VipsImage *columns; VipsImage *rows; } VipsProject; typedef VipsStatisticClass VipsProjectClass; G_DEFINE_TYPE(VipsProject, vips_project, VIPS_TYPE_STATISTIC); /* Save a bit of typing. */ #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define D VIPS_FORMAT_DOUBLE #define N VIPS_FORMAT_NOTSET static const VipsBandFormat vips_project_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UI, I, UI, I, UI, I, D, N, D, N }; static Histogram * histogram_new(VipsProject *project) { VipsStatistic *statistic = VIPS_STATISTIC(project); VipsImage *in = statistic->ready; VipsBandFormat outfmt = vips_project_format_table[in->BandFmt]; int psize = vips_format_sizeof(outfmt) * in->Bands; Histogram *hist; if (!(hist = VIPS_NEW(project, Histogram))) return NULL; hist->column_sums = VIPS_ARRAY(project, psize * in->Xsize, guchar); hist->row_sums = VIPS_ARRAY(project, psize * in->Ysize, guchar); if (!hist->column_sums || !hist->row_sums) return NULL; memset(hist->column_sums, 0, (size_t) psize * in->Xsize); memset(hist->row_sums, 0, (size_t) psize * in->Ysize); return hist; } static int vips_project_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsProject *project = (VipsProject *) object; int y; if (statistic->in && vips_check_noncomplex(class->nickname, statistic->in)) return -1; g_object_set(object, "columns", vips_image_new(), "rows", vips_image_new(), NULL); /* main hist made on first thread start. */ if (VIPS_OBJECT_CLASS(vips_project_parent_class)->build(object)) return -1; /* Make the output image. */ if (vips_image_pipelinev(project->columns, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL) || vips_image_pipelinev(project->rows, VIPS_DEMAND_STYLE_ANY, statistic->ready, NULL)) return -1; project->columns->Ysize = 1; project->columns->BandFmt = vips_project_format_table[statistic->ready->BandFmt]; project->columns->Type = VIPS_INTERPRETATION_HISTOGRAM; project->rows->Xsize = 1; project->rows->BandFmt = vips_project_format_table[statistic->ready->BandFmt]; project->rows->Type = VIPS_INTERPRETATION_HISTOGRAM; if (vips_image_write_line(project->columns, 0, (VipsPel *) project->hist->column_sums)) return -1; for (y = 0; y < project->rows->Ysize; y++) if (vips_image_write_line(project->rows, y, (VipsPel *) project->hist->row_sums + y * VIPS_IMAGE_SIZEOF_PEL(project->rows))) return -1; return 0; } /* Build a sub-hist, based on the main hist. */ static void * vips_project_start(VipsStatistic *statistic) { VipsProject *project = (VipsProject *) statistic; /* Make the main hist, if necessary. */ if (!project->hist) project->hist = histogram_new(project); return (void *) histogram_new(project); } /* Add a line of pixels. */ #define ADD_PIXELS(OUT, IN) \ { \ OUT *row_sums = ((OUT *) hist->row_sums) + y * nb; \ OUT *column_sums; \ IN *p; \ \ column_sums = ((OUT *) hist->column_sums) + x * nb; \ p = (IN *) in; \ for (i = 0; i < n; i++) { \ for (j = 0; j < nb; j++) { \ column_sums[j] += p[j]; \ row_sums[j] += p[j]; \ } \ \ p += nb; \ column_sums += nb; \ } \ } /* Add a region to a project. */ static int vips_project_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { int nb = statistic->ready->Bands; Histogram *hist = (Histogram *) seq; int i, j; switch (statistic->ready->BandFmt) { case VIPS_FORMAT_UCHAR: ADD_PIXELS(guint, guchar); break; case VIPS_FORMAT_CHAR: ADD_PIXELS(int, char); break; case VIPS_FORMAT_USHORT: ADD_PIXELS(guint, gushort); break; case VIPS_FORMAT_SHORT: ADD_PIXELS(int, short); break; case VIPS_FORMAT_UINT: ADD_PIXELS(guint, guint); break; case VIPS_FORMAT_INT: ADD_PIXELS(int, int); break; case VIPS_FORMAT_FLOAT: ADD_PIXELS(double, float); break; case VIPS_FORMAT_DOUBLE: ADD_PIXELS(double, double); break; default: g_assert_not_reached(); } return 0; } #define ADD_BUFFER(TYPE, Q, P, N) \ { \ TYPE *p = (TYPE *) (P); \ TYPE *q = (TYPE *) (Q); \ int n = (N); \ int i; \ \ for (i = 0; i < n; i++) \ q[i] += p[i]; \ } /* Join a sub-project onto the main project. */ static int vips_project_stop(VipsStatistic *statistic, void *seq) { VipsProject *project = (VipsProject *) statistic; Histogram *hist = project->hist; Histogram *sub_hist = (Histogram *) seq; VipsImage *in = statistic->ready; VipsBandFormat outfmt = vips_project_format_table[in->BandFmt]; int hsz = in->Xsize * in->Bands; int vsz = in->Ysize * in->Bands; /* Add on sub-data. */ switch (outfmt) { case VIPS_FORMAT_UINT: ADD_BUFFER(guint, hist->column_sums, sub_hist->column_sums, hsz); ADD_BUFFER(guint, hist->row_sums, sub_hist->row_sums, vsz); break; case VIPS_FORMAT_INT: ADD_BUFFER(int, hist->column_sums, sub_hist->column_sums, hsz); ADD_BUFFER(int, hist->row_sums, sub_hist->row_sums, vsz); break; case VIPS_FORMAT_DOUBLE: ADD_BUFFER(double, hist->column_sums, sub_hist->column_sums, hsz); ADD_BUFFER(double, hist->row_sums, sub_hist->row_sums, vsz); break; default: g_assert_not_reached(); } /* Blank out sub-project to make sure we can't add it again. */ sub_hist->column_sums = NULL; sub_hist->row_sums = NULL; return 0; } static void vips_project_class_init(VipsProjectClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "project"; object_class->description = _("find image projections"); object_class->build = vips_project_build; sclass->start = vips_project_start; sclass->scan = vips_project_scan; sclass->stop = vips_project_stop; VIPS_ARG_IMAGE(class, "columns", 100, _("Columns"), _("Sums of columns"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsProject, columns)); VIPS_ARG_IMAGE(class, "rows", 101, _("Rows"), _("Sums of rows"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsProject, rows)); } static void vips_project_init(VipsProject *project) { } /** * vips_project: (method) * @in: input image * @columns: (out): sums of columns * @rows: (out): sums of rows * @...: `NULL`-terminated list of optional named arguments * * Find the horizontal and vertical projections of an image, ie. the sum * of every row of pixels, and the sum of every column of pixels. The output * format is uint, int or double, depending on the input format. * * Non-complex images only. * * ::: seealso * [method@Image.hist_find], [method@Image.profile]. * * Returns: 0 on success, -1 on error */ int vips_project(VipsImage *in, VipsImage **columns, VipsImage **rows, ...) { va_list ap; int result; va_start(ap, rows); result = vips_call_split("project", ap, in, columns, rows); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/relational.c000066400000000000000000000607111516303661500213740ustar00rootroot00000000000000/* relational.c -- various relational operations * * Modified: * 26/7/93 JC * - >,<,>=,<= tests now as (double) to prevent compiler warnings. Should * split into int/float cases really for speed. * 25/1/95 JC * - partialized * - updated * 7/2/95 JC * - oops! bug with doubles fixed * 3/7/98 JC * - vector versions added ... im_equal_vec(), im_lesseq_vec() etc * - small tidies * - should be a bit faster, lots of *q++ changed to q[x] * 10/3/03 JC * - reworked to remove nested #defines: a bit slower, but much smaller * - all except _vec forms now work on complex * 31/7/03 JC * - oops, relational_format was broken for some combinations * 23/9/09 * - gtkdoc * - use new im__arith_binary*() functions * - more meta-programming * 23/6/10 * - oops, moreconst and moreeqconst were the same * 4/11/11 * - redone as a class * 1/2/12 * - complex ==, != were broken * 16/7/12 * - im1 > im2, im1 >= im2 were broken * 17/9/14 * - im1 > im2, im1 >= im2 were still broken, but in a more subtle way */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "binary.h" #include "unaryconst.h" typedef struct _VipsRelational { VipsBinary parent_instance; VipsOperationRelational relational; } VipsRelational; typedef VipsBinaryClass VipsRelationalClass; G_DEFINE_TYPE(VipsRelational, vips_relational, VIPS_TYPE_BINARY); #define RLOOP(TYPE, ROP) \ { \ TYPE *restrict left = (TYPE *) in0; \ TYPE *restrict right = (TYPE *) in1; \ VipsPel *restrict q = (VipsPel *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = (left[x] ROP right[x]) ? 255 : 0; \ } #define CLOOP(TYPE, COP) \ { \ TYPE *restrict left = (TYPE *) in0; \ TYPE *restrict right = (TYPE *) in1; \ VipsPel *restrict q = (VipsPel *) out; \ \ for (x = 0; x < sz; x++) { \ q[x] = COP(left[0], left[1], right[0], right[1]) ? 255 : 0; \ \ left += 2; \ right += 2; \ } \ } #define SWITCH(R, C, ROP, COP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ R(unsigned char, ROP); \ break; \ case VIPS_FORMAT_CHAR: \ R(signed char, ROP); \ break; \ case VIPS_FORMAT_USHORT: \ R(unsigned short, ROP); \ break; \ case VIPS_FORMAT_SHORT: \ R(signed short, ROP); \ break; \ case VIPS_FORMAT_UINT: \ R(unsigned int, ROP); \ break; \ case VIPS_FORMAT_INT: \ R(signed int, ROP); \ break; \ case VIPS_FORMAT_FLOAT: \ R(float, ROP); \ break; \ case VIPS_FORMAT_DOUBLE: \ R(double, ROP); \ break; \ case VIPS_FORMAT_COMPLEX: \ C(float, COP); \ break; \ case VIPS_FORMAT_DPCOMPLEX: \ C(double, COP); \ break; \ \ default: \ g_assert_not_reached(); \ } #define CEQUAL(x1, y1, x2, y2) (x1 == x2 && y1 == y2) #define CNOTEQ(x1, y1, x2, y2) (x1 != x2 || y1 != y2) #define CLESS(x1, y1, x2, y2) (x1 * x1 + y1 * y1 < x2 * x2 + y2 * y2) #define CLESSEQ(x1, y1, x2, y2) (x1 * x1 + y1 * y1 <= x2 * x2 + y2 * y2) #define CMORE(x1, y1, x2, y2) (x1 * x1 + y1 * y1 > x2 * x2 + y2 * y2) #define CMOREEQ(x1, y1, x2, y2) (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) static void vips_relational_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsRelational *relational = (VipsRelational *) arithmetic; VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); VipsOperationRelational op; VipsPel *in0; VipsPel *in1; int x; in0 = in[0]; in1 = in[1]; op = relational->relational; if (op == VIPS_OPERATION_RELATIONAL_MORE) { op = VIPS_OPERATION_RELATIONAL_LESS; VIPS_SWAP(VipsPel *, in0, in1); } if (op == VIPS_OPERATION_RELATIONAL_MOREEQ) { op = VIPS_OPERATION_RELATIONAL_LESSEQ; VIPS_SWAP(VipsPel *, in0, in1); } switch (op) { case VIPS_OPERATION_RELATIONAL_EQUAL: SWITCH(RLOOP, CLOOP, ==, CEQUAL); break; case VIPS_OPERATION_RELATIONAL_NOTEQ: SWITCH(RLOOP, CLOOP, !=, CNOTEQ); break; case VIPS_OPERATION_RELATIONAL_LESS: SWITCH(RLOOP, CLOOP, <, CLESS); break; case VIPS_OPERATION_RELATIONAL_LESSEQ: SWITCH(RLOOP, CLOOP, <=, CLESSEQ); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_relational_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static void vips_relational_class_init(VipsRelationalClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "relational"; object_class->description = _("relational operation on two images"); aclass->process_line = vips_relational_buffer; vips_arithmetic_set_format_table(aclass, vips_relational_format_table); VIPS_ARG_ENUM(class, "relational", 200, _("Operation"), _("Relational to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRelational, relational), VIPS_TYPE_OPERATION_RELATIONAL, VIPS_OPERATION_RELATIONAL_EQUAL); } static void vips_relational_init(VipsRelational *relational) { } static int vips_relationalv(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationRelational relational, va_list ap) { return vips_call_split("relational", ap, left, right, out, relational); } /** * vips_relational: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @relational: relational operation to perform * @...: `NULL`-terminated list of optional named arguments * * Perform various relational operations on pairs of images. * * The output type is always uchar, with 0 for `FALSE` and 255 for `TRUE`. * * Less-than and greater-than for complex images compare the modulus. * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * To decide if pixels match exactly, that is have the same value in every * band, use [method@Image.bandbool] after this operation to AND or OR image * bands together. * * ::: seealso * [method@Image.boolean], [method@Image.bandbool], * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_relational(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationRelational relational, ...) { va_list ap; int result; va_start(ap, relational); result = vips_relationalv(left, right, out, relational, ap); va_end(ap); return result; } /** * vips_equal: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.EQUAL] on a pair of images. See * [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_equal(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_relationalv(left, right, out, VIPS_OPERATION_RELATIONAL_EQUAL, ap); va_end(ap); return result; } /** * vips_notequal: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.NOTEQ] on a pair of images. See * [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_notequal(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_relationalv(left, right, out, VIPS_OPERATION_RELATIONAL_NOTEQ, ap); va_end(ap); return result; } /** * vips_more: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.MORE] on a pair of images. See * [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_more(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_relationalv(left, right, out, VIPS_OPERATION_RELATIONAL_MORE, ap); va_end(ap); return result; } /** * vips_moreeq: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.MOREEQ] on a pair of images. See * [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_moreeq(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_relationalv(left, right, out, VIPS_OPERATION_RELATIONAL_MOREEQ, ap); va_end(ap); return result; } /** * vips_less: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.LESS] on a pair of images. See * [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_less(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_relationalv(left, right, out, VIPS_OPERATION_RELATIONAL_LESS, ap); va_end(ap); return result; } /** * vips_lesseq: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.LESSEQ] on a pair of images. See * [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_lesseq(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_relationalv(left, right, out, VIPS_OPERATION_RELATIONAL_LESSEQ, ap); va_end(ap); return result; } typedef struct _VipsRelationalConst { VipsUnaryConst parent_instance; VipsOperationRelational relational; } VipsRelationalConst; typedef VipsUnaryConstClass VipsRelationalConstClass; G_DEFINE_TYPE(VipsRelationalConst, vips_relational_const, VIPS_TYPE_UNARY_CONST); #define RLOOPCI(TYPE, OP) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ int *restrict c = uconst->c_int; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) \ out[i] = (p[i] OP c[b]) ? 255 : 0; \ } #define RLOOPCF(TYPE, OP) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ double *restrict c = uconst->c_double; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) \ out[i] = (p[i] OP c[b]) ? 255 : 0; \ } #define CLOOPC(TYPE, OP) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ \ for (i = 0, x = 0; x < width; x++) { \ double *restrict c = uconst->c_double; \ \ for (b = 0; b < bands; b++, i++) { \ out[i] = OP(p[0], p[1], c[0], c[1]) ? 255 : 0; \ \ p += 2; \ c += 2; \ } \ } \ } static void vips_relational_const_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsUnaryConst *uconst = (VipsUnaryConst *) arithmetic; VipsRelationalConst *rconst = (VipsRelationalConst *) arithmetic; VipsImage *im = arithmetic->ready[0]; int bands = im->Bands; gboolean is_int = uconst->is_int && vips_band_format_isint(im->BandFmt); int i, x, b; switch (rconst->relational) { case VIPS_OPERATION_RELATIONAL_EQUAL: if (is_int) { SWITCH(RLOOPCI, CLOOPC, ==, CEQUAL); } else { SWITCH(RLOOPCF, CLOOPC, ==, CEQUAL); } break; case VIPS_OPERATION_RELATIONAL_NOTEQ: if (is_int) { SWITCH(RLOOPCI, CLOOPC, !=, CNOTEQ); } else { SWITCH(RLOOPCF, CLOOPC, !=, CNOTEQ); } break; case VIPS_OPERATION_RELATIONAL_LESS: if (is_int) { SWITCH(RLOOPCI, CLOOPC, <, CLESS); } else { SWITCH(RLOOPCF, CLOOPC, <, CLESS); } break; case VIPS_OPERATION_RELATIONAL_LESSEQ: if (is_int) { SWITCH(RLOOPCI, CLOOPC, <=, CLESSEQ); } else { SWITCH(RLOOPCF, CLOOPC, <=, CLESSEQ); } break; case VIPS_OPERATION_RELATIONAL_MORE: if (is_int) { SWITCH(RLOOPCI, CLOOPC, >, CMORE); } else { SWITCH(RLOOPCF, CLOOPC, >, CMORE); } break; case VIPS_OPERATION_RELATIONAL_MOREEQ: if (is_int) { SWITCH(RLOOPCI, CLOOPC, >=, CMOREEQ); } else { SWITCH(RLOOPCF, CLOOPC, >=, CMOREEQ); } break; default: g_assert_not_reached(); } } static void vips_relational_const_class_init(VipsRelationalConstClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "relational_const"; object_class->description = _("relational operations against a constant"); aclass->process_line = vips_relational_const_buffer; vips_arithmetic_set_format_table(aclass, vips_relational_format_table); VIPS_ARG_ENUM(class, "relational", 200, _("Operation"), _("Relational to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRelationalConst, relational), VIPS_TYPE_OPERATION_RELATIONAL, VIPS_OPERATION_RELATIONAL_EQUAL); } static void vips_relational_const_init(VipsRelationalConst *relational_const) { } static int vips_relational_constv(VipsImage *in, VipsImage **out, VipsOperationRelational relational, const double *c, int n, va_list ap) { VipsArea *area_c; double *array; int result; int i; area_c = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); array = (double *) area_c->data; for (i = 0; i < n; i++) array[i] = c[i]; result = vips_call_split("relational_const", ap, in, out, relational, area_c); vips_area_unref(area_c); return result; } /** * vips_relational_const: (method) * @in: input image * @out: (out): output image * @relational: relational operation to perform * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform various relational operations on an image and an array of * constants. * * The output type is always uchar, with 0 for `FALSE` and 255 for `TRUE`. * * If the array of constants has just one element, that constant is used for * all image bands. If the array has more than one element and they have * the same number of elements as there are bands in the image, then * one array element is used for each band. If the arrays have more than one * element and the image only has a single band, the result is a many-band * image where each band corresponds to one array element. * * ::: seealso * [method@Image.boolean], [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_relational_const(VipsImage *in, VipsImage **out, VipsOperationRelational relational, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, relational, c, n, ap); va_end(ap); return result; } /** * vips_equal_const: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.EQUAL] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_equal_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_EQUAL, c, n, ap); va_end(ap); return result; } /** * vips_notequal_const: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.NOTEQ] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_notequal_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_NOTEQ, c, n, ap); va_end(ap); return result; } /** * vips_less_const: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.LESS] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_less_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_LESS, c, n, ap); va_end(ap); return result; } /** * vips_lesseq_const: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.LESSEQ] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_lesseq_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_LESSEQ, c, n, ap); va_end(ap); return result; } /** * vips_more_const: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.MORE] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_more_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_MORE, c, n, ap); va_end(ap); return result; } /** * vips_moreeq_const: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.MOREEQ] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_moreeq_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_MOREEQ, c, n, ap); va_end(ap); return result; } /** * vips_relational_const1: (method) * @in: input image * @out: (out): output image * @relational: relational operation to perform * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform various relational operations on an image and a constant. See * [method@Image.relational_const]. * * ::: seealso * [method@Image.boolean], [method@Image.relational]. * * Returns: 0 on success, -1 on error */ int vips_relational_const1(VipsImage *in, VipsImage **out, VipsOperationRelational relational, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, relational, &c, 1, ap); va_end(ap); return result; } /** * vips_equal_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.EQUAL] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_equal_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_EQUAL, &c, 1, ap); va_end(ap); return result; } /** * vips_notequal_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.NOTEQ] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_notequal_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_NOTEQ, &c, 1, ap); va_end(ap); return result; } /** * vips_less_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.LESS] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_less_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_LESS, &c, 1, ap); va_end(ap); return result; } /** * vips_lesseq_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.LESSEQ] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_lesseq_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_LESSEQ, &c, 1, ap); va_end(ap); return result; } /** * vips_more_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.MORE] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_more_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_MORE, &c, 1, ap); va_end(ap); return result; } /** * vips_moreeq_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationRelational.MOREEQ] on an image and a constant. See * [method@Image.relational_const]. * * Returns: 0 on success, -1 on error */ int vips_moreeq_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_relational_constv(in, out, VIPS_OPERATION_RELATIONAL_MOREEQ, &c, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/remainder.c000066400000000000000000000273341516303661500212140ustar00rootroot00000000000000/* remainder.c * * 2/8/99 JC * - im_divide adapted to make im_remainder * 8/5/02 JC * - im_remainderconst added * - im_remainderconst_vec added * 27/9/04 * - updated for 1 band $op n band image -> n band image case * 26/2/07 * - oop, broken for _vec case :-( * 14/5/08 * - better /0 test * 27/8/08 * - revise upcasting system * - add gtkdoc comments * 23/6/10 * - constant ops clip to target range * 12/11/11 * - redone as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "binary.h" #include "unaryconst.h" typedef VipsBinary VipsRemainder; typedef VipsBinaryClass VipsRemainderClass; G_DEFINE_TYPE(VipsRemainder, vips_remainder, VIPS_TYPE_BINARY); static int vips_remainder_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBinary *binary = (VipsBinary *) object; if (binary->left && vips_check_noncomplex(class->nickname, binary->left)) return -1; if (binary->right && vips_check_noncomplex(class->nickname, binary->right)) return -1; if (VIPS_OBJECT_CLASS(vips_remainder_parent_class)->build(object)) return -1; return 0; } /* Integer remainder-after-division. */ #define IREMAINDER(TYPE) \ { \ TYPE *restrict p1 = (TYPE *) in[0]; \ TYPE *restrict p2 = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = p2[x] ? p1[x] % p2[x] : -1; \ } /* Float remainder-after-division. */ #define FREMAINDER(TYPE) \ { \ TYPE *restrict p1 = (TYPE *) in[0]; \ TYPE *restrict p2 = (TYPE *) in[1]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) { \ double a = p1[x]; \ double b = p2[x]; \ \ q[x] = b ? a - b * floor(a / b) : -1; \ } \ } static void vips_remainder_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int sz = width * vips_image_get_bands(im); int x; switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: IREMAINDER(signed char); break; case VIPS_FORMAT_UCHAR: IREMAINDER(unsigned char); break; case VIPS_FORMAT_SHORT: IREMAINDER(signed short); break; case VIPS_FORMAT_USHORT: IREMAINDER(unsigned short); break; case VIPS_FORMAT_INT: IREMAINDER(signed int); break; case VIPS_FORMAT_UINT: IREMAINDER(unsigned int); break; case VIPS_FORMAT_FLOAT: FREMAINDER(float); break; case VIPS_FORMAT_DOUBLE: FREMAINDER(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for remainder. Keep in sync with remainder_buffer() above. */ static const VipsBandFormat vips_remainder_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_remainder_class_init(VipsRemainderClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "remainder"; object_class->description = _("remainder after integer division of two images"); object_class->build = vips_remainder_build; aclass->process_line = vips_remainder_buffer; vips_arithmetic_set_format_table(aclass, vips_remainder_format_table); } static void vips_remainder_init(VipsRemainder *remainder) { } /** * vips_remainder: (method) * @left: left-hand input [class@Image] * @right: right-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @left % @right (remainder after integer division) * and writes the result to @out. The images may have any * non-complex format. For float formats, [method@Image.remainder] calculates @in1 - * @in2 * floor (@in1 / @in2). * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), and that format is the * result type. * * ::: seealso * [method@Image.remainder_const], [method@Image.divide], [method@Image.round]. * * Returns: 0 on success, -1 on error */ int vips_remainder(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("remainder", ap, left, right, out); va_end(ap); return result; } typedef VipsUnaryConst VipsRemainderConst; typedef VipsUnaryConstClass VipsRemainderConstClass; G_DEFINE_TYPE(VipsRemainderConst, vips_remainder_const, VIPS_TYPE_UNARY_CONST); static int vips_remainder_const_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsUnary *unary = (VipsUnary *) object; if (unary->in && vips_check_noncomplex(class->nickname, unary->in)) return -1; if (VIPS_OBJECT_CLASS(vips_remainder_const_parent_class)->build(object)) return -1; return 0; } /* Integer remainder-after-divide, per-band constant. */ #define IREMAINDERCONST(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int *restrict c = uconst->c_int; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) \ q[i] = c[b] ? p[i] % c[b] : -1; \ } /* Float remainder-after-divide, per-band constant. */ #define FREMAINDERCONST(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int *restrict c = uconst->c_int; \ \ for (i = 0, x = 0; x < width; x++) \ for (b = 0; b < bands; b++, i++) { \ double left = p[i]; \ double right = c[b]; \ \ q[i] = right ? left - right * floor(left / right) : -1; \ } \ } static void vips_remainder_const_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsUnaryConst *uconst = (VipsUnaryConst *) arithmetic; VipsImage *im = arithmetic->ready[0]; int bands = im->Bands; int i, x, b; switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: IREMAINDERCONST(signed char); break; case VIPS_FORMAT_UCHAR: IREMAINDERCONST(unsigned char); break; case VIPS_FORMAT_SHORT: IREMAINDERCONST(signed short); break; case VIPS_FORMAT_USHORT: IREMAINDERCONST(unsigned short); break; case VIPS_FORMAT_INT: IREMAINDERCONST(signed int); break; case VIPS_FORMAT_UINT: IREMAINDERCONST(unsigned int); break; case VIPS_FORMAT_FLOAT: FREMAINDERCONST(float); break; case VIPS_FORMAT_DOUBLE: FREMAINDERCONST(double); break; default: g_assert_not_reached(); } } static void vips_remainder_const_class_init(VipsRemainderConstClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "remainder_const"; object_class->description = _("remainder after integer division of an image and a constant"); object_class->build = vips_remainder_const_build; aclass->process_line = vips_remainder_const_buffer; vips_arithmetic_set_format_table(aclass, vips_remainder_format_table); } static void vips_remainder_const_init(VipsRemainderConst *remainder_const) { } static int vips_remainder_constv(VipsImage *in, VipsImage **out, const double *c, int n, va_list ap) { VipsArea *area_c; double *array; int result; int i; area_c = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); array = (double *) area_c->data; for (i = 0; i < n; i++) array[i] = c[i]; result = vips_call_split("remainder_const", ap, in, out, area_c); vips_area_unref(area_c); return result; } /** * vips_remainder_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants * @n: number of constants in @c * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @in % @c (remainder after division by an * array of constants) * and writes the result to @out. * The image may have any * non-complex format. For float formats, [method@Image.remainder_const] calculates * @in - @c * floor (@in / @c). * * If the array of constants has just one element, that constant is used for * all image bands. If the array has more than one element and they have * the same number of elements as there are bands in the image, then * one array element is used for each band. If the arrays have more than one * element and the image only has a single band, the result is a many-band * image where each band corresponds to one array element. * * ::: seealso * [method@Image.remainder], [method@Image.divide], [method@Image.round]. * * Returns: 0 on success, -1 on error */ int vips_remainder_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_remainder_constv(in, out, c, n, ap); va_end(ap); return result; } /** * vips_remainder_const1: (method) * @in: input image * @out: (out): output image * @c: constant * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @in % @c (remainder after division by a * constant) * and writes the result to @out. * The image may have any * non-complex format. For float formats, [method@Image.remainder_const] calculates * @in - @c * floor (@in / @c). * * If the array of constants has just one element, that constant is used for * all image bands. If the array has more than one element and they have * the same number of elements as there are bands in the image, then * one array element is used for each band. If the arrays have more than one * element and the image only has a single band, the result is a many-band * image where each band corresponds to one array element. * * ::: seealso * [method@Image.remainder], [method@Image.divide], [method@Image.round]. * * Returns: 0 on success, -1 on error */ int vips_remainder_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_remainder_constv(in, out, &c, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/round.c000066400000000000000000000147461516303661500204000ustar00rootroot00000000000000/* round.c -- various rounding operations * * 20/6/02 JC * - adapted from im_abs() * 29/8/09 * - gtkdoc * - tiny cleanups * 19/9/09 * - im_ceil.c adapted to make round.c * 10/11/11 * - redone as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef struct _VipsRound { VipsUnary parent_instance; VipsOperationRound round; } VipsRound; typedef VipsUnaryClass VipsRoundClass; G_DEFINE_TYPE(VipsRound, vips_round, VIPS_TYPE_UNARY); static int vips_round_build(VipsObject *object) { VipsUnary *unary = (VipsUnary *) object; /* Is this one of the int types? Degenerate to vips_copy() if it * is. */ if (unary->in && vips_band_format_isint(unary->in->BandFmt)) return vips_unary_copy(unary); if (VIPS_OBJECT_CLASS(vips_round_parent_class)->build(object)) return -1; return 0; } #define LOOP(TYPE, OP) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = OP(p[x]); \ } #define SWITCH(OP) \ { \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_COMPLEX: \ case VIPS_FORMAT_FLOAT: \ LOOP(float, OP); \ break; \ \ case VIPS_FORMAT_DPCOMPLEX: \ case VIPS_FORMAT_DOUBLE: \ LOOP(double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } \ } static void vips_round_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsRound *round = (VipsRound *) arithmetic; VipsImage *im = arithmetic->ready[0]; /* Complex just doubles the size. */ const int sz = width * im->Bands * (vips_band_format_iscomplex(im->BandFmt) ? 2 : 1); int x; switch (round->round) { case VIPS_OPERATION_ROUND_RINT: SWITCH(rint); break; case VIPS_OPERATION_ROUND_CEIL: SWITCH(ceil); break; case VIPS_OPERATION_ROUND_FLOOR: SWITCH(floor); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_round_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_round_class_init(VipsRoundClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "round"; object_class->description = _("perform a round function on an image"); object_class->build = vips_round_build; aclass->process_line = vips_round_buffer; vips_arithmetic_set_format_table(aclass, vips_round_format_table); VIPS_ARG_ENUM(class, "round", 200, _("Round operation"), _("Rounding operation to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRound, round), VIPS_TYPE_OPERATION_ROUND, VIPS_OPERATION_ROUND_RINT); } static void vips_round_init(VipsRound *round) { } static int vips_roundv(VipsImage *in, VipsImage **out, VipsOperationRound round, va_list ap) { return vips_call_split("round", ap, in, out, round); } /** * vips_round: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @round: [class@Operation]Round rounding operation to perform * @...: `NULL`-terminated list of optional named arguments * * Round to an integral value. * * Copy for integer types, round float and * complex types. * * The format of @out is always the same as @in, so you may wish to cast to an * integer format afterwards. * * ::: seealso * [method@Image.cast] * * Returns: 0 on success, -1 on error */ int vips_round(VipsImage *in, VipsImage **out, VipsOperationRound round, ...) { va_list ap; int result; va_start(ap, round); result = vips_roundv(in, out, round, ap); va_end(ap); return result; } /** * vips_floor: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Round to an integral value with [enum@Vips.OperationRound.FLOOR]. See * [method@Image.round]. * * Returns: 0 on success, -1 on error */ int vips_floor(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_roundv(in, out, VIPS_OPERATION_ROUND_FLOOR, ap); va_end(ap); return result; } /** * vips_ceil: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Round to an integral value with [enum@Vips.OperationRound.CEIL]. See * [method@Image.round]. * * Returns: 0 on success, -1 on error */ int vips_ceil(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_roundv(in, out, VIPS_OPERATION_ROUND_CEIL, ap); va_end(ap); return result; } /** * vips_rint: (method) * @in: input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Round to an integral value with [enum@Vips.OperationRound.RINT]. See * [method@Image.round]. * * Returns: 0 on success, -1 on error */ int vips_rint(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_roundv(in, out, VIPS_OPERATION_ROUND_RINT, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/sign.c000066400000000000000000000105011516303661500201720ustar00rootroot00000000000000/* im_sign.c * * 9/7/02 JC * - from im_cmulnorm * 9/9/09 * - gtkdoc, tidies * 6/11/11 * - redone as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" typedef VipsUnary VipsSign; typedef VipsUnaryClass VipsSignClass; G_DEFINE_TYPE(VipsSign, vips_sign, VIPS_TYPE_UNARY); #define CSIGN(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ TYPE *restrict q = (TYPE *) out; \ int x; \ \ for (x = 0; x < sz; x++) { \ TYPE re = p[0]; \ TYPE im = p[1]; \ double fac = sqrt(re * re + im * im); \ \ p += 2; \ \ if (fac == 0.0) { \ q[0] = 0.0; \ q[1] = 0.0; \ } \ else { \ q[0] = re / fac; \ q[1] = im / fac; \ } \ \ q += 2; \ } \ } #define SIGN(TYPE) \ { \ TYPE *restrict p = (TYPE *) in[0]; \ signed char *restrict q = (signed char *) out; \ int x; \ \ for (x = 0; x < sz; x++) { \ TYPE v = p[x]; \ \ if (v > 0) \ q[x] = 1; \ else if (v == 0) \ q[x] = 0; \ else \ q[x] = -1; \ } \ } static void vips_sign_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; const int bands = vips_image_get_bands(im); int sz = width * bands; switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: SIGN(unsigned char); break; case VIPS_FORMAT_CHAR: SIGN(signed char); break; case VIPS_FORMAT_USHORT: SIGN(unsigned short); break; case VIPS_FORMAT_SHORT: SIGN(signed short); break; case VIPS_FORMAT_UINT: SIGN(unsigned int); break; case VIPS_FORMAT_INT: SIGN(signed int); break; case VIPS_FORMAT_FLOAT: SIGN(float); break; case VIPS_FORMAT_DOUBLE: SIGN(double); break; case VIPS_FORMAT_COMPLEX: CSIGN(float); break; case VIPS_FORMAT_DPCOMPLEX: CSIGN(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_sign_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ C, C, C, C, C, C, C, X, C, DX }; static void vips_sign_class_init(VipsSignClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "sign"; object_class->description = _("unit vector of pixel"); aclass->process_line = vips_sign_buffer; vips_arithmetic_set_format_table(aclass, vips_sign_format_table); } static void vips_sign_init(VipsSign *sign) { } /** * vips_sign: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Finds the unit vector in the direction of the pixel value. For non-complex * images, it returns a signed char image with values -1, 0, and 1 for negative, * zero and positive pixels. For complex images, it returns a * complex normalised to length 1. * * ::: seealso * [method@Image.abs]. * * Returns: 0 on success, -1 on error */ int vips_sign(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("sign", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/statistic.c000066400000000000000000000102721516303661500212460ustar00rootroot00000000000000/* base class for all stats operations * * properties: * - one image in, single value or matrix out * - output depends on whole of input, ie. we have a sink * * 24/8/11 * - from im_avg.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "statistic.h" G_DEFINE_ABSTRACT_TYPE(VipsStatistic, vips_statistic, VIPS_TYPE_OPERATION); static void * vips_statistic_scan_start(VipsImage *in, void *a, void *b) { VipsStatistic *statistic = VIPS_STATISTIC(a); VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS(statistic); return class->start(statistic); } static int vips_statistic_scan(VipsRegion *region, void *seq, void *a, void *b, gboolean *stop) { VipsStatistic *statistic = VIPS_STATISTIC(a); VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS(statistic); VipsRect *r = ®ion->valid; int lsk = VIPS_REGION_LSKIP(region); int y; VipsPel *p; VIPS_DEBUG_MSG("vips_statistic_scan: %d x %d @ %d x %d\n", r->width, r->height, r->left, r->top); p = VIPS_REGION_ADDR(region, r->left, r->top); for (y = 0; y < r->height; y++) { if (class->scan(statistic, seq, r->left, r->top + y, p, r->width)) return -1; p += lsk; } /* If we've requested stop, pass the message on. */ if (statistic->stop) *stop = TRUE; return 0; } static int vips_statistic_scan_stop(void *seq, void *a, void *b) { VipsStatistic *statistic = VIPS_STATISTIC(a); VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS(statistic); return class->stop(statistic, seq); } static int vips_statistic_build(VipsObject *object) { VipsStatistic *statistic = VIPS_STATISTIC(object); VipsStatisticClass *sclass = VIPS_STATISTIC_GET_CLASS(statistic); VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); #ifdef DEBUG printf("vips_statistic_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_statistic_parent_class)->build(object)) return -1; statistic->ready = statistic->in; if (vips_image_decode(statistic->ready, &t[0])) return -1; statistic->ready = t[0]; /* If there's a format table, cast the input. */ if (sclass->format_table) { if (vips_cast(statistic->ready, &t[1], sclass->format_table[statistic->in->BandFmt], NULL)) return -1; statistic->ready = t[1]; } if (vips_sink(statistic->ready, vips_statistic_scan_start, vips_statistic_scan, vips_statistic_scan_stop, statistic, NULL)) return -1; return 0; } static void vips_statistic_class_init(VipsStatisticClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "statistic"; vobject_class->description = _("VIPS statistic operations"); vobject_class->build = vips_statistic_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsStatistic, in)); } static void vips_statistic_init(VipsStatistic *statistic) { } libvips-8.18.2/libvips/arithmetic/statistic.h000066400000000000000000000051521516303661500212540ustar00rootroot00000000000000/* base class for all stats operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_STATISTIC_H #define VIPS_STATISTIC_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_STATISTIC (vips_statistic_get_type()) #define VIPS_STATISTIC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_STATISTIC, VipsStatistic)) #define VIPS_STATISTIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_STATISTIC, VipsStatisticClass)) #define VIPS_IS_STATISTIC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_STATISTIC)) #define VIPS_IS_STATISTIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_STATISTIC)) #define VIPS_STATISTIC_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_STATISTIC, VipsStatisticClass)) typedef struct _VipsStatistic VipsStatistic; typedef struct _VipsStatisticClass VipsStatisticClass; typedef void *(*VipsStatisticStartFn)(VipsStatistic *statistic); typedef int (*VipsStatisticScanFn)(VipsStatistic *statistic, void *seq, int x, int y, void *p, int n); typedef int (*VipsStatisticStopFn)(VipsStatistic *statistic, void *seq); struct _VipsStatistic { VipsOperation parent_instance; /* All have an input image. */ VipsImage *in; /* The input image cast and ready for processing. */ VipsImage *ready; /* Set this to stop computation early. */ gboolean stop; /* Client data for the subclass. */ void *a; void *b; }; struct _VipsStatisticClass { VipsOperationClass parent_class; /* Start/scan/stop, for vips_sink. */ VipsStatisticStartFn start; VipsStatisticScanFn scan; VipsStatisticStopFn stop; /* For each input format, what output format. If NULL, no casting. */ const VipsBandFormat *format_table; }; GType vips_statistic_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_STATISTIC_H*/ libvips-8.18.2/libvips/arithmetic/stats.c000066400000000000000000000253141516303661500204000ustar00rootroot00000000000000/* stats.c ... many image stats in a single pass * (C) Kirk Martinez 1993 23/4/93 J.Cupitt - adapted to partial images - special struct abandoned; now returns DOUBLEMASK. 1/7/93 JC - adapted for partial v2 - ANSIfied 27/7/93 JC - init of mask changed to use actual values, not IM_MAXDOUBLE and (-IM_MAXDOUBLE). These caused problems when assigned to floats. funny business with offset==42, yuk! 31/8/93 JC - forgot to init global max/min properly! sorry. 21/6/95 JC - still did not init max and min correctly -- now fixed for good * 13/1/05 * - use 64 bit arithmetic * 1/9/09 * - argh nope min/max was broken again for >1CPU in short pipelines on * some architectures * 7/9/09 * - rework based on new im__wrapscan() / im_max() ideas for a proper fix * - gtkdoc comment * 7/11/11 * - redone as a class * - track maxpos / minpos too */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "statistic.h" typedef struct _VipsStats { VipsStatistic parent_instance; VipsImage *out; gboolean set; /* FALSE means no value yet */ } VipsStats; typedef VipsStatisticClass VipsStatsClass; G_DEFINE_TYPE(VipsStats, vips_stats, VIPS_TYPE_STATISTIC); /* Names for our columns. */ enum { COL_MIN = 0, COL_MAX = 1, COL_SUM = 2, COL_SUM2 = 3, COL_AVG = 4, COL_SD = 5, COL_XMIN = 6, COL_YMIN = 7, COL_XMAX = 8, COL_YMAX = 9, COL_LAST = 10 }; static int vips_stats_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStatistic *statistic = VIPS_STATISTIC(object); VipsStats *stats = (VipsStats *) object; guint64 vals, pels; double *row0, *row; int b, y, i; if (vips_object_argument_isset(object, "in")) { int bands = vips_image_get_bands(statistic->in); if (vips_check_noncomplex(class->nickname, statistic->in)) return -1; g_object_set(object, "out", vips_image_new_matrix(COL_LAST, bands + 1), NULL); } if (VIPS_OBJECT_CLASS(vips_stats_parent_class)->build(object)) return -1; pels = VIPS_IMAGE_N_PELS(statistic->ready); vals = pels * vips_image_get_bands(statistic->ready); row0 = VIPS_MATRIX(stats->out, 0, 0); row = VIPS_MATRIX(stats->out, 0, 1); for (i = 0; i < COL_LAST; i++) row0[i] = row[i]; for (b = 1; b < vips_image_get_bands(statistic->ready); b++) { row = VIPS_MATRIX(stats->out, 0, b + 1); if (row[COL_MIN] < row0[COL_MIN]) { row0[COL_MIN] = row[COL_MIN]; row0[COL_XMIN] = row[COL_XMIN]; row0[COL_YMIN] = row[COL_YMIN]; } if (row[COL_MAX] > row0[COL_MAX]) { row0[COL_MAX] = row[COL_MAX]; row0[COL_XMAX] = row[COL_XMAX]; row0[COL_YMAX] = row[COL_YMAX]; } row0[COL_SUM] += row[COL_SUM]; row0[COL_SUM2] += row[COL_SUM2]; } for (y = 1; y < vips_image_get_height(stats->out); y++) { double *row = VIPS_MATRIX(stats->out, 0, y); row[COL_AVG] = row[COL_SUM] / pels; row[COL_SD] = sqrt( fabs(row[COL_SUM2] - (row[COL_SUM] * row[COL_SUM] / pels)) / (pels - 1)); } row0[COL_AVG] = row0[COL_SUM] / vals; row0[COL_SD] = sqrt( fabs(row0[COL_SUM2] - (row0[COL_SUM] * row0[COL_SUM] / vals)) / (vals - 1)); return 0; } /* Stop function. Add these little stats to the main set of stats. */ static int vips_stats_stop(VipsStatistic *statistic, void *seq) { int bands = vips_image_get_bands(statistic->ready); VipsStats *global = (VipsStats *) statistic; VipsStats *local = (VipsStats *) seq; int b; if (local->set && !global->set) { for (b = 0; b < bands; b++) { double *p = VIPS_MATRIX(local->out, 0, b + 1); double *q = VIPS_MATRIX(global->out, 0, b + 1); int i; for (i = 0; i < COL_LAST; i++) q[i] = p[i]; } global->set = TRUE; } else if (local->set && global->set) { for (b = 0; b < bands; b++) { double *p = VIPS_MATRIX(local->out, 0, b + 1); double *q = VIPS_MATRIX(global->out, 0, b + 1); if (p[COL_MIN] < q[COL_MIN]) { q[COL_MIN] = p[COL_MIN]; q[COL_XMIN] = p[COL_XMIN]; q[COL_YMIN] = p[COL_YMIN]; } if (p[COL_MAX] > q[COL_MAX]) { q[COL_MAX] = p[COL_MAX]; q[COL_XMAX] = p[COL_XMAX]; q[COL_YMAX] = p[COL_YMAX]; } q[COL_SUM] += p[COL_SUM]; q[COL_SUM2] += p[COL_SUM2]; } } VIPS_FREEF(g_object_unref, local->out); VIPS_FREEF(g_free, seq); return 0; } /* Start function: make a dummy local stats for the private use of this thread. */ static void * vips_stats_start(VipsStatistic *statistic) { int bands = vips_image_get_bands(statistic->ready); VipsStats *stats; stats = g_new(VipsStats, 1); if (!(stats->out = vips_image_new_matrix(COL_LAST, bands + 1))) { g_free(stats); return NULL; } stats->set = FALSE; return (void *) stats; } /* We scan lines bands times to avoid repeating band loops. * Use temp variables of same type for min/max for faster comparisons. */ #define LOOP(TYPE) \ { \ for (b = 0; b < bands; b++) { \ TYPE *p = ((TYPE *) in) + b; \ double *q = VIPS_MATRIX(local->out, 0, b + 1); \ TYPE small, big; \ double sum, sum2; \ int xmin, ymin; \ int xmax, ymax; \ \ if (local->set) { \ small = q[COL_MIN]; \ big = q[COL_MAX]; \ sum = q[COL_SUM]; \ sum2 = q[COL_SUM2]; \ xmin = q[COL_XMIN]; \ ymin = q[COL_YMIN]; \ xmax = q[COL_XMAX]; \ ymax = q[COL_YMAX]; \ } \ else { \ small = p[0]; \ big = p[0]; \ sum = 0; \ sum2 = 0; \ xmin = x; \ ymin = y; \ xmax = x; \ ymax = y; \ } \ \ for (i = 0; i < n; i++) { \ TYPE value = *p; \ \ sum += value; \ sum2 += (double) value * (double) value; \ if (value > big) { \ big = value; \ xmax = x + i; \ ymax = y; \ } \ else if (value < small) { \ small = value; \ xmin = x + i; \ ymin = y; \ } \ \ p += bands; \ } \ \ q[COL_MIN] = small; \ q[COL_MAX] = big; \ q[COL_SUM] = sum; \ q[COL_SUM2] = sum2; \ q[COL_XMIN] = xmin; \ q[COL_YMIN] = ymin; \ q[COL_XMAX] = xmax; \ q[COL_YMAX] = ymax; \ } \ \ local->set = TRUE; \ } /* As above, but for float/double types where we have to avoid NaN. */ #define LOOPF(TYPE) \ { \ for (b = 0; b < bands; b++) { \ TYPE *p = ((TYPE *) in) + b; \ double *q = VIPS_MATRIX(local->out, 0, b + 1); \ TYPE small, big; \ double sum, sum2; \ int xmin, ymin; \ int xmax, ymax; \ \ if (local->set) { \ small = q[COL_MIN]; \ big = q[COL_MAX]; \ sum = q[COL_SUM]; \ sum2 = q[COL_SUM2]; \ xmin = q[COL_XMIN]; \ ymin = q[COL_YMIN]; \ xmax = q[COL_XMAX]; \ ymax = q[COL_YMAX]; \ } \ else { \ small = p[0]; \ big = p[0]; \ sum = 0; \ sum2 = 0; \ xmin = x; \ ymin = y; \ xmax = x; \ ymax = y; \ } \ \ for (i = 0; i < n; i++) { \ TYPE value = *p; \ \ sum += value; \ sum2 += (double) value * (double) value; \ if (value > big) { \ big = value; \ xmax = x + i; \ ymax = y; \ } \ else if (value < small) { \ small = value; \ xmin = x + i; \ ymin = y; \ } \ \ p += bands; \ } \ \ q[COL_MIN] = small; \ q[COL_MAX] = big; \ q[COL_SUM] = sum; \ q[COL_SUM2] = sum2; \ q[COL_XMIN] = xmin; \ q[COL_YMIN] = ymin; \ q[COL_XMAX] = xmax; \ q[COL_YMAX] = ymax; \ } \ \ local->set = TRUE; \ } /* Loop over region, accumulating a sum in *tmp. */ static int vips_stats_scan(VipsStatistic *statistic, void *seq, int x, int y, void *in, int n) { const int bands = vips_image_get_bands(statistic->ready); VipsStats *local = (VipsStats *) seq; int b, i; switch (vips_image_get_format(statistic->ready)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOP(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOP(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int); break; case VIPS_FORMAT_FLOAT: LOOP(float); break; case VIPS_FORMAT_DOUBLE: LOOP(double); break; default: g_assert_not_reached(); } return 0; } static void vips_stats_class_init(VipsStatsClass *class) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class; VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "stats"; object_class->description = _("find many image stats"); object_class->build = vips_stats_build; sclass->start = vips_stats_start; sclass->scan = vips_stats_scan; sclass->stop = vips_stats_stop; VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output array of statistics"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsStats, out)); } static void vips_stats_init(VipsStats *stats) { } /** * vips_stats: (method) * @in: image to scan * @out: (out): image of statistics * @...: `NULL`-terminated list of optional named arguments * * Find many image statistics in a single pass through the data. @out is a * one-band [enum@Vips.BandFormat.DOUBLE] image of at least 10 columns by n + 1 * (where n is number of bands in image @in) * rows. Columns are statistics, and are, in order: minimum, maximum, sum, * sum of squares, mean, standard deviation, x coordinate of minimum, y * coordinate of minimum, x coordinate of maximum, y coordinate of maximum. * Later versions of [method@Image.stats] may add more columns. * * Row 0 has statistics for all * bands together, row 1 has stats for band 1, and so on. * * If there is more than one maxima or minima, one of them will be chosen at * random. * * ::: seealso * [method@Image.avg], [method@Image.min]. * * Returns: 0 on success, -1 on error */ int vips_stats(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("stats", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/subtract.c000066400000000000000000000146141516303661500210720ustar00rootroot00000000000000/* Subtract two images * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 29/4/93 J.Cupitt * - now works for partial images * 1/7/93 JC * - adapted for partial v2 * 9/5/95 JC * - simplified: now just handles 10 cases (instead of 50), using * im_clip2*() to help * - now uses im_wrapmany() rather than im_generate() * 12/6/95 JC * - new im_add() adapted to make this * 31/5/96 JC * - what was this SWAP() stuff? failed for small - big! * 22/8/03 JC * - cast up more quickly to help accuracy * 27/9/04 * - updated for 1 band $op n band image -> n band image case * 8/12/06 * - add liboil support * 18/8/08 * - revise upcasting system * - add gtkdoc comments * - remove separate complex case, just double size * 31/7/10 * - remove liboil * 23/8/11 * - rewrite as a class from add.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "binary.h" typedef VipsBinary VipsSubtract; typedef VipsBinaryClass VipsSubtractClass; G_DEFINE_TYPE(VipsSubtract, vips_subtract, VIPS_TYPE_BINARY); #define LOOP(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = left[x] - right[x]; \ } /* Special case for VIPS_FORMAT_INT, to prevent UB. */ #define LOOP_INT64(IN, OUT) \ { \ IN *restrict left = (IN *) in[0]; \ IN *restrict right = (IN *) in[1]; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = (int64_t) left[x] - right[x]; \ } static void vips_subtract_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; /* Complex just doubles the size. */ const int sz = width * vips_image_get_bands(im) * (vips_band_format_iscomplex(vips_image_get_format(im)) ? 2 : 1); int x; /* Keep types here in sync with bandfmt_subtract[] * below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: LOOP(signed char, signed short); break; case VIPS_FORMAT_UCHAR: LOOP(unsigned char, signed short); break; case VIPS_FORMAT_SHORT: LOOP(signed short, signed int); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, signed int); break; case VIPS_FORMAT_INT: LOOP_INT64(signed int, signed int); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: LOOP(float, float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: LOOP(double, double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for subtraction. Sign and value preserving. Make sure these * match the case statement in vips_subtract_buffer() above. */ static const VipsBandFormat vips_subtract_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ S, S, I, I, I, I, F, X, D, DX }; static void vips_subtract_class_init(VipsSubtractClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "subtract"; object_class->description = _("subtract two images"); aclass->process_line = vips_subtract_buffer; vips_arithmetic_set_format_table(aclass, vips_subtract_format_table); } static void vips_subtract_init(VipsSubtract *subtract) { } /** * vips_subtract: (method) * @in1: input image * @in2: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation calculates @in1 - @in2 and writes the result to @out. * * If the images differ in size, the smaller image is enlarged to match the * larger by adding zero pixels along the bottom and right. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), then the * following table is used to determine the output type: * * ## [method@Image.subtract] type promotion * * | input type | output type | * |----------------|----------------| * | uchar | short | * | char | short | * | ushort | int | * | short | int | * | uint | int | * | int | int | * | float | float | * | double | double | * | complex | complex | * | double complex | double complex | * * In other words, the output type is just large enough to hold the whole * range of possible values. * * ::: seealso * [method@Image.add], [method@Image.linear]. * * Returns: 0 on success, -1 on error */ int vips_subtract(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("subtract", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/sum.c000066400000000000000000000127411516303661500200460ustar00rootroot00000000000000/* sum an array of images * * 18/3/14 * - from add.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "nary.h" typedef VipsNary VipsSum; typedef VipsNaryClass VipsSumClass; G_DEFINE_TYPE(VipsSum, vips_sum, VIPS_TYPE_NARY); #define LOOP(IN, OUT) \ { \ IN **restrict p = (IN **) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < sz; x++) { \ OUT sum; \ \ sum = p[0][x]; \ for (i = 1; i < n; i++) \ sum += p[i][x]; \ q[x] = sum; \ } \ } static void sum_buffer(VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width) { VipsImage *im = arithmetic->ready[0]; int n = arithmetic->n; /* Complex just doubles the size. */ const int sz = width * vips_image_get_bands(im) * (vips_band_format_iscomplex(vips_image_get_format(im)) ? 2 : 1); int x; int i; /* Sum all input types. Keep types here in sync with * vips_sum_format_table[] below. */ switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, unsigned int); break; case VIPS_FORMAT_CHAR: LOOP(signed char, signed int); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, unsigned int); break; case VIPS_FORMAT_SHORT: LOOP(signed short, signed int); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int, signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: LOOP(float, float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: LOOP(double, double); break; default: g_assert_not_reached(); } } #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for addition. Sign and value preserving. Make sure these * match the case statement in sum_buffer() above. */ static const VipsBandFormat vips_sum_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UI, I, UI, I, UI, I, F, X, D, DX }; static void vips_sum_class_init(VipsSumClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); object_class->nickname = "sum"; object_class->description = _("sum an array of images"); aclass->process_line = sum_buffer; vips_arithmetic_set_format_table(aclass, vips_sum_format_table); } static void vips_sum_init(VipsSum *sum) { } static int vips_sumv(VipsImage **in, VipsImage **out, int n, va_list ap) { VipsArrayImage *array; int result; array = vips_array_image_new(in, n); result = vips_call_split("sum", ap, array, out); vips_area_unref(VIPS_AREA(array)); return result; } /** * vips_sum: * @in: (array length=n): array of input images * @out: (out): output image * @n: number of input images * @...: `NULL`-terminated list of optional named arguments * * This operation sums all images in @in and writes the result to @out. * * If the images differ in size, the smaller images are enlarged to match the * largest by adding zero pixels along the bottom and right. * * If the number of bands differs, all but one of the images * must have one band. In this case, n-band images are formed from the * one-band images by joining n copies of the one-band images together, and then * the n-band images are operated upon. * * The input images are cast up to the smallest common format (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)), then the * following table is used to determine the output type: * * ## [func@Image.sum] type promotion * * | input type | output type | * |----------------|----------------| * | uchar | uint | * | char | int | * | ushort | uint | * | short | int | * | uint | uint | * | int | int | * | float | float | * | double | double | * | complex | complex | * | double complex | double complex | * * In other words, the output type is just large enough to hold the whole * range of possible values. * * ::: seealso * [method@Image.add]. * * Returns: 0 on success, -1 on error */ int vips_sum(VipsImage **in, VipsImage **out, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_sumv(in, out, n, ap); va_end(ap); return result; } libvips-8.18.2/libvips/arithmetic/unary.c000066400000000000000000000052561516303661500204030ustar00rootroot00000000000000/* base class for all unary operations * * 30/10/11 * - from binary.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unary.h" G_DEFINE_ABSTRACT_TYPE(VipsUnary, vips_unary, VIPS_TYPE_ARITHMETIC); static int vips_unary_build(VipsObject *object) { VipsArithmetic *arithmetic = VIPS_ARITHMETIC(object); VipsUnary *unary = VIPS_UNARY(object); arithmetic->n = 1; arithmetic->in = (VipsImage **) vips_object_local_array(object, 1); arithmetic->in[0] = unary->in; if (arithmetic->in[0]) g_object_ref(arithmetic->in[0]); if (VIPS_OBJECT_CLASS(vips_unary_parent_class)->build(object)) return -1; return 0; } static void vips_unary_class_init(VipsUnaryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "unary"; vobject_class->description = _("unary operations"); vobject_class->build = vips_unary_build; /* Create properties. */ VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsUnary, in)); } static void vips_unary_init(VipsUnary *unary) { /* Init our instance fields. */ } /* Call this before chaining up in _build() to make the operation fall back to * copy. */ int vips_unary_copy(VipsUnary *unary) { VipsArithmetic *arithmetic = VIPS_ARITHMETIC(unary); /* This isn't set by arith until build(), so we have to set * again here. * * Should arith set out in _init()? */ g_object_set(unary, "out", vips_image_new(), NULL); return vips_image_write(unary->in, arithmetic->out); } libvips-8.18.2/libvips/arithmetic/unary.h000066400000000000000000000034551516303661500204070ustar00rootroot00000000000000/* base class for all unary arithmetic operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_UNARY_H #define VIPS_UNARY_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include "parithmetic.h" #define VIPS_TYPE_UNARY (vips_unary_get_type()) #define VIPS_UNARY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), VIPS_TYPE_UNARY, VipsUnary)) #define VIPS_UNARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), VIPS_TYPE_UNARY, VipsUnaryClass)) #define VIPS_IS_UNARY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_UNARY)) #define VIPS_IS_UNARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_UNARY)) #define VIPS_UNARY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), VIPS_TYPE_UNARY, VipsUnaryClass)) typedef struct _VipsUnary { VipsArithmetic parent_instance; VipsImage *in; } VipsUnary; typedef VipsArithmeticClass VipsUnaryClass; GType vips_unary_get_type(void); int vips_unary_copy(VipsUnary *unary); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_UNARY_H*/ libvips-8.18.2/libvips/arithmetic/unaryconst.c000066400000000000000000000074461516303661500214550ustar00rootroot00000000000000/* an image plus a constant * * 11/11/11 * - from arith_binary_const * 21/8/19 * - revise to fix out of range comparisons */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "unaryconst.h" G_DEFINE_ABSTRACT_TYPE(VipsUnaryConst, vips_unary_const, VIPS_TYPE_UNARY); static int vips_unary_const_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsArithmetic *arithmetic = VIPS_ARITHMETIC(object); VipsUnary *unary = (VipsUnary *) object; VipsUnaryConst *uconst = (VipsUnaryConst *) object; /* If we have a three-element vector we need to bandup the image to * match. */ uconst->n = 1; if (uconst->c) uconst->n = VIPS_MAX(uconst->n, uconst->c->n); if (unary->in) uconst->n = VIPS_MAX(uconst->n, unary->in->Bands); arithmetic->base_bands = uconst->n; if (unary->in && uconst->c) { if (vips_check_vector(class->nickname, uconst->c->n, unary->in)) return -1; } /* Some operations need int constants, for example boolean AND, SHIFT * etc. * * Some can use int constants as an optimisation, for example (x < * 12). It depends on the value though: obviously (x < 12.5) should * not use the int form. * * For complex images, we double the vector length and set the * imaginary part to 0. */ if (uconst->c) { gboolean is_complex = vips_band_format_iscomplex(unary->in->BandFmt); int step = is_complex ? 2 : 1; int n = step * uconst->n; double *c = (double *) uconst->c->data; int i; uconst->c_int = VIPS_ARRAY(object, n, int); uconst->c_double = VIPS_ARRAY(object, n, double); if (!uconst->c_int || !uconst->c_double) return -1; memset(uconst->c_int, 0, n * sizeof(int)); memset(uconst->c_double, 0, n * sizeof(double)); for (i = 0; i < n; i += step) uconst->c_double[i] = c[VIPS_MIN(i / step, uconst->c->n - 1)]; for (i = 0; i < n; i += step) uconst->c_int[i] = uconst->c_double[i]; uconst->is_int = TRUE; for (i = 0; i < n; i += step) if (uconst->c_int[i] != uconst->c_double[i]) { uconst->is_int = FALSE; break; } } if (VIPS_OBJECT_CLASS(vips_unary_const_parent_class)->build(object)) return -1; return 0; } static void vips_unary_const_class_init(VipsUnaryConstClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "unary_const"; object_class->description = _("unary operations with a constant"); object_class->build = vips_unary_const_build; VIPS_ARG_BOXED(class, "c", 201, _("c"), _("Array of constants"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsUnaryConst, c), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_unary_const_init(VipsUnaryConst *uconst) { } libvips-8.18.2/libvips/arithmetic/unaryconst.h000066400000000000000000000042561516303661500214560ustar00rootroot00000000000000/* base class for all unaryconst arithmetic operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_UNARY_CONST_H #define VIPS_UNARY_CONST_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include "unary.h" #define VIPS_TYPE_UNARY_CONST (vips_unary_const_get_type()) #define VIPS_UNARY_CONST(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_UNARY_CONST, VipsUnaryConst)) #define VIPS_UNARY_CONST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_UNARY_CONST, VipsUnaryConstClass)) #define VIPS_IS_UNARY_CONST(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_UNARY_CONST)) #define VIPS_IS_UNARY_CONST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_UNARY_CONST)) #define VIPS_UNARY_CONST_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_UNARY_CONST, VipsUnaryConstClass)) typedef struct _VipsUnaryConst { VipsUnary parent_instance; /* Our constants. */ VipsArea *c; /* Our constant expanded to match arith->ready in size. We need int * and double versions. * * is_int is TRUE if the two arrays are equal for every element. */ int n; int *c_int; double *c_double; gboolean is_int; } VipsUnaryConst; typedef struct _VipsUnaryConstClass { VipsUnaryClass parent_class; } VipsUnaryConstClass; GType vips_unary_const_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_UNARY_CONST_H*/ libvips-8.18.2/libvips/colour/000077500000000000000000000000001516303661500162435ustar00rootroot00000000000000libvips-8.18.2/libvips/colour/CMYK2XYZ.c000066400000000000000000000126061516303661500176540ustar00rootroot00000000000000/* Use lcms to move from CMYK to XYZ, if we can. This needs a working * vips_icc_import. * * 21/12/18 * - from scRGB2XYZ.c * 7/5/23 kleisauke * - use embedded ICC profile, if available */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "profiles.h" #include "pcolour.h" #ifdef HAVE_LCMS2 typedef struct _VipsCMYK2XYZ { VipsOperation parent_instance; VipsImage *in; VipsImage *out; } VipsCMYK2XYZ; typedef VipsColourCodeClass VipsCMYK2XYZClass; G_DEFINE_TYPE(VipsCMYK2XYZ, vips_CMYK2XYZ, VIPS_TYPE_OPERATION); /* Our actual processing, as a VipsColourTransformFn. */ static int vips_CMYK2XYZ_process(VipsImage *in, VipsImage **out, ...) { return vips_icc_import(in, out, "input_profile", "cmyk", "embedded", TRUE, "pcs", VIPS_PCS_XYZ, NULL); } static int vips_CMYK2XYZ_build(VipsObject *object) { VipsCMYK2XYZ *CMYK2XYZ = (VipsCMYK2XYZ *) object; VipsImage *out; VipsImage *t; if (VIPS_OBJECT_CLASS(vips_CMYK2XYZ_parent_class)->build(object)) return -1; out = vips_image_new(); g_object_set(object, "out", out, NULL); if (vips__colourspace_process_n("CMYK2XYZ", CMYK2XYZ->in, &t, 4, vips_CMYK2XYZ_process)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static void vips_CMYK2XYZ_class_init(VipsCMYK2XYZClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "CMYK2XYZ"; object_class->description = _("transform CMYK to XYZ"); object_class->build = vips_CMYK2XYZ_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCMYK2XYZ, in)); VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsCMYK2XYZ, out)); } static void vips_CMYK2XYZ_init(VipsCMYK2XYZ *CMYK2XYZ) { } #else /*!HAVE_LCMS2*/ typedef VipsColourCode VipsCMYK2XYZ; typedef VipsColourCodeClass VipsCMYK2XYZClass; G_DEFINE_TYPE(VipsCMYK2XYZ, vips_CMYK2XYZ, VIPS_TYPE_COLOUR_CODE); static void vips_CMYK2XYZ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { unsigned char *p = (unsigned char *) in[0]; float *q = (float *) out; int i; for (i = 0; i < width; i++) { float c = p[0] / 255.0; float m = p[1] / 255.0; float y = p[2] / 255.0; float k = p[3] / 255.0; float r = 1.0 - (c * (1.0 - k) + k); float g = 1.0 - (m * (1.0 - k) + k); float b = 1.0 - (y * (1.0 - k) + k); q[0] = VIPS_D65_X0 * r; q[1] = VIPS_D65_Y0 * g; q[2] = VIPS_D65_Z0 * b; p += 4; q += 3; } } static void vips_CMYK2XYZ_class_init(VipsCMYK2XYZClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "CMYK2XYZ"; object_class->description = _("transform CMYK to XYZ"); colour_class->process_line = vips_CMYK2XYZ_line; } static void vips_CMYK2XYZ_init(VipsCMYK2XYZ *CMYK2XYZ) { VipsColour *colour = VIPS_COLOUR(CMYK2XYZ); VipsColourCode *code = VIPS_COLOUR_CODE(CMYK2XYZ); colour->interpretation = VIPS_INTERPRETATION_XYZ; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 3; colour->input_bands = 4; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_UCHAR; code->input_interpretation = VIPS_INTERPRETATION_CMYK; } #endif /*HAVE_LCMS2*/ /** * vips_CMYK2XYZ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn CMYK to XYZ. If the image has an embedded ICC profile this will be * used for the conversion. If there is no embedded profile, a generic * fallback profile will be used. * * Conversion is to D65 XYZ with relative intent. If you need more control * over the process, use [method@Image.icc_import] instead. * * Returns: 0 on success, -1 on error */ int vips_CMYK2XYZ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("CMYK2XYZ", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/HSV2sRGB.c000066400000000000000000000070111516303661500176460ustar00rootroot00000000000000/* to sRGB from HSV * * 9/6/15 * - from sRGB2HSV.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" #define SIXTH_OF_CHAR (42.5) typedef VipsColourCode VipsHSV2sRGB; typedef VipsColourCodeClass VipsHSV2sRGBClass; G_DEFINE_TYPE(VipsHSV2sRGB, vips_HSV2sRGB, VIPS_TYPE_COLOUR_CODE); static void vips_HSV2sRGB_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { unsigned char *p = (unsigned char *) in[0]; unsigned char *q = (unsigned char *) out; int i; for (i = 0; i < width; i++) { float c, x, m; c = p[2] * p[1] / 255.0; x = c * (1 - fabsf(fmodf(p[0] / SIXTH_OF_CHAR, 2) - 1)); m = p[2] - c; if (p[0] < (int) SIXTH_OF_CHAR) { q[0] = c + m; q[1] = x + m; q[2] = 0 + m; } else if (p[0] < (int) (2 * SIXTH_OF_CHAR)) { q[0] = x + m; q[1] = c + m; q[2] = 0 + m; } else if (p[0] < (int) (3 * SIXTH_OF_CHAR)) { q[0] = 0 + m; q[1] = c + m; q[2] = x + m; } else if (p[0] < (int) (4 * SIXTH_OF_CHAR)) { q[0] = 0 + m; q[1] = x + m; q[2] = c + m; } else if (p[0] < (int) (5 * SIXTH_OF_CHAR)) { q[0] = x + m; q[1] = 0 + m; q[2] = c + m; } else { q[0] = c + m; q[1] = 0 + m; q[2] = x + m; } p += 3; q += 3; } } static void vips_HSV2sRGB_class_init(VipsHSV2sRGBClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "HSV2sRGB"; object_class->description = _("transform HSV to sRGB"); colour_class->process_line = vips_HSV2sRGB_line; } static void vips_HSV2sRGB_init(VipsHSV2sRGB *HSV2sRGB) { VipsColour *colour = VIPS_COLOUR(HSV2sRGB); VipsColourCode *code = VIPS_COLOUR_CODE(HSV2sRGB); colour->interpretation = VIPS_INTERPRETATION_sRGB; colour->format = VIPS_FORMAT_UCHAR; colour->bands = 3; colour->input_bands = 3; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_UCHAR; code->input_interpretation = VIPS_INTERPRETATION_HSV; } /** * vips_HSV2sRGB: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert HSV to sRGB. * * HSV is a crude polar coordinate system for RGB images. It is provided for * compatibility with other image processing systems. See [method@Image.Lab2LCh] for a * much better colour space. * * ::: seealso * [method@Image.sRGB2HSV]. * * Returns: 0 on success, -1 on error. */ int vips_HSV2sRGB(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("HSV2sRGB", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/LCh2Lab.c000066400000000000000000000056161516303661500175660ustar00rootroot00000000000000/* im_LCh2Lab * * 15/11/94 JC * - error messages added * - memory leak fixed * 16/11/94 JC * - uses im_wrap_oneonebuf() now * 8/2/95 JC * - im_wrap v2 * 2/11/09 * - gtkdoc * 19/9/12 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsLCh2Lab; typedef VipsColourTransformClass VipsLCh2LabClass; G_DEFINE_TYPE(VipsLCh2Lab, vips_LCh2Lab, VIPS_TYPE_COLOUR_TRANSFORM); /** * vips_col_Ch2ab: * @C: Chroma * @h: Hue angle (degrees) * @a: return CIE a* value * @b: return CIE b* value * * Calculate ab from Ch, h in degrees. */ void vips_col_Ch2ab(float C, float h, float *a, float *b) { *a = C * cosf(VIPS_RAD(h)); *b = C * sinf(VIPS_RAD(h)); } /* Process a buffer of data. */ static void vips_LCh2Lab_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; int x; for (x = 0; x < width; x++) { float L = p[0]; float C = p[1]; float h = p[2]; float a, b; p += 3; vips_col_Ch2ab(C, h, &a, &b); q[0] = L; q[1] = a; q[2] = b; q += 3; } } static void vips_LCh2Lab_class_init(VipsLCh2LabClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LCh2Lab"; object_class->description = _("transform LCh to Lab"); colour_class->process_line = vips_LCh2Lab_line; } static void vips_LCh2Lab_init(VipsLCh2Lab *LCh2Lab) { VipsColour *colour = VIPS_COLOUR(LCh2Lab); colour->interpretation = VIPS_INTERPRETATION_LAB; } /** * vips_LCh2Lab: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn LCh to Lab. * * Returns: 0 on success, -1 on error */ int vips_LCh2Lab(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LCh2Lab", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/LCh2UCS.c000066400000000000000000000116411516303661500175150ustar00rootroot00000000000000/* LCh2CMC * * Modified: * 2/11/09 * - gtkdoc * 19/9/12 * - redone as a class * 24/9/14 * - rechecked against original paper, seems OK */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsLCh2CMC; typedef VipsColourTransformClass VipsLCh2CMCClass; G_DEFINE_TYPE(VipsLCh2CMC, vips_LCh2CMC, VIPS_TYPE_COLOUR_TRANSFORM); /* I ordered this paper from the library and it took ages. For reference, the * recommended short formula are: * * Lucs * = 1.744 * L, L < 16 * = (1/l) * (21.75 * ln(L) + 0.3838 * L - 38.54), otherwise * * Cucs = (l/c) * (0.162 * C + 10.92 * (ln(0.638 + 0.07216 * C)) + 4.907) * * hucs = h + D * f * where * D = k4 + k5 * P * | P | ** k6 * P = cos(k7 * h + k8) * f = (C ** 4 / (C ** 4 + 1900)) ** 0.5 * * h k4 k5 k6 k7 k8 * 0 - 49 133.87 -134.5 -0.924 1.727 340 * 49 - 110 11.78 -12.7 -0.218 2.120 333 * 110 - 269.5 13.87 10.93 0.140 1.000 -83 * 269.5 - 360 0.14 5.23 0.170 1.610 233 * * They have a much more complicated but slightly more accurate formula for * hucs. This one is pretty good, simple approximation. */ /** * vips_col_L2Lcmc: * @L: CIE L* * * Calculate Lcmc from L. * * Returns: Lcmc */ float vips_col_L2Lcmc(float L) { float Lcmc; if (L < 16.0) Lcmc = 1.744F * L; else Lcmc = 21.75F * logf(L) + 0.3838F * L - 38.54F; return Lcmc; } /** * vips_col_C2Ccmc: * @C: Chroma * * Calculate Ccmc from C. * * Returns: Ccmc. */ float vips_col_C2Ccmc(float C) { float Ccmc; Ccmc = 0.162F * C + 10.92F * logf(0.638F + 0.07216F * C) + 4.907F; if (Ccmc < 0) Ccmc = 0; return Ccmc; } /** * vips_col_Ch2hcmc: * @C: Chroma * @h: Hue (degrees) * * Calculate hcmc from C and h. * * Returns: hcmc. */ float vips_col_Ch2hcmc(float C, float h) { float P, D, f, g; float k4, k5, k6, k7, k8; float hcmc; if (h < 49.1) { k4 = 133.87F; k5 = -134.5F; k6 = -.924F; k7 = 1.727F; k8 = 340.0F; } else if (h < 110.1) { k4 = 11.78F; k5 = -12.7F; k6 = -.218F; k7 = 2.12F; k8 = 333.0F; } else if (h < 269.6) { k4 = 13.87F; k5 = 10.93F; k6 = 0.14F; k7 = 1.0F; k8 = -83.0F; } else { k4 = .14F; k5 = 5.23F; k6 = .17F; k7 = 1.61F; k8 = 233.0F; } P = cosf(VIPS_RAD(k7 * h + k8)); D = k4 + k5 * P * powf(fabsf(P), k6); g = C * C * C * C; f = sqrtf(g / (g + 1900.0F)); hcmc = h + D * f; return hcmc; } static void vips_LCh2CMC_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *p = (float *) in[0]; float *q = (float *) out; int x; for (x = 0; x < width; x++) { float L = p[0]; float C = p[1]; float h = p[2]; p += 3; q[0] = vips_col_L2Lcmc(L); q[1] = vips_col_C2Ccmc(C); q[2] = vips_col_Ch2hcmc(C, h); q += 3; } } static void vips_LCh2CMC_class_init(VipsLCh2CMCClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LCh2CMC"; object_class->description = _("transform LCh to CMC"); colour_class->process_line = vips_LCh2CMC_line; } static void vips_LCh2CMC_init(VipsLCh2CMC *LCh2CMC) { VipsColour *colour = VIPS_COLOUR(LCh2CMC); colour->interpretation = VIPS_INTERPRETATION_CMC; } /** * vips_LCh2CMC: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn LCh to CMC. * * The CMC colourspace is described in "Uniform Colour Space Based on the * CMC(l:c) Colour-difference Formula", M R Luo and B Rigg, Journal of the * Society of Dyers and Colourists, vol 102, 1986. Distances in this * colourspace approximate, within 10% or so, differences in the CMC(l:c) * colour difference formula. * * This operation generates CMC(1:1). For CMC(2:1), halve Lucs and double * Cucs. * * ::: seealso * [method@Image.CMC2LCh]. * * Returns: 0 on success, -1 on error */ int vips_LCh2CMC(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LCh2CMC", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Lab2LCh.c000066400000000000000000000060501516303661500175570ustar00rootroot00000000000000/* Turn Lab to LCh * * 2/11/09 * - gtkdoc * - cleanups * 18/9/12 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsLab2LCh; typedef VipsColourTransformClass VipsLab2LChClass; G_DEFINE_TYPE(VipsLab2LCh, vips_Lab2LCh, VIPS_TYPE_COLOUR_TRANSFORM); /** * vips_col_ab2h: * @a: CIE a * @b: CIE b * * Returns: Hue (degrees) */ double vips_col_ab2h(double a, double b) { double h; /* We have to get the right quadrant! */ if (a == 0) { if (b < 0.0) h = 270; else if (b == 0.0) h = 0; else h = 90; } else { double t = atan(b / a); if (a > 0.0) if (b < 0.0) h = VIPS_DEG(t + VIPS_PI * 2.0); else h = VIPS_DEG(t); else h = VIPS_DEG(t + VIPS_PI); } return h; } void vips_col_ab2Ch(float a, float b, float *C, float *h) { *h = vips_col_ab2h(a, b); *C = hypotf(a, b); } static void vips_Lab2LCh_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; int x; for (x = 0; x < width; x++) { float L = p[0]; float a = p[1]; float b = p[2]; float C, h; p += 3; C = sqrtf(a * a + b * b); h = vips_col_ab2h(a, b); q[0] = L; q[1] = C; q[2] = h; q += 3; } } static void vips_Lab2LCh_class_init(VipsLab2LChClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Lab2LCh"; object_class->description = _("transform Lab to LCh"); colour_class->process_line = vips_Lab2LCh_line; } static void vips_Lab2LCh_init(VipsLab2LCh *Lab2LCh) { VipsColour *colour = VIPS_COLOUR(Lab2LCh); colour->interpretation = VIPS_INTERPRETATION_LCH; } /** * vips_Lab2LCh: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn Lab to LCh. * * Returns: 0 on success, -1 on error */ int vips_Lab2LCh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Lab2LCh", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Lab2LabQ.c000066400000000000000000000105241516303661500177310ustar00rootroot00000000000000/* Lab2LabQ: quantise FLOAT Lab image into 10 11 11 format * * 4 bytes per pel: l a b lsbs * this is an image wrapper which calls line-wise packing * Copyright K.Martinez 3/5/93 * Modified: * 7/6/93 JC * - adapted for partial v2 * 5/5/94 JC * - some nint->+0.5, for speed and to ease portability * - other nint->rint * - now includes ! * 15/11/94 JC * - all nint(), rint() removed for speed * - now -128 rather than -127 for a, b * - checks input type properly * 16/11/94 JC * - uses new im_wrap_oneonebuf() * 22/5/95 JC * - changed L to scale by 10.24, not 10.23 * 11/7/95 JC * - now uses IM_RINT() for rounding * 4/9/97 JC * - L* = 100.0 now allowed * 5/11/00 JC * - go int earlier for speed up * 20/6/02 JC * - oops, were not clipping a/b range correctly * 1/11/09 * - gtkdoc * - cleanups * 20/9/12 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLab2LabQ; typedef VipsColourCodeClass VipsLab2LabQClass; G_DEFINE_TYPE(VipsLab2LabQ, vips_Lab2LabQ, VIPS_TYPE_COLOUR_CODE); /* @(#) convert float Lab to packed Lab32 format 10 11 11 bits * works only on buffers, not IMAGEs * Copyright 1993 K.Martinez * Modified: 3/5/93, 16/6/93 */ static void vips_Lab2LabQ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; VipsPel *restrict q = out; int i; for (i = 0; i < width; i++) { float fval; int lsbs; int intv; /* Scale L up to 10 bits. */ intv = VIPS_ROUND_UINT(10.23 * p[0]); intv = VIPS_CLIP(0, intv, 1023); lsbs = (intv & 0x3) << 6; /* 00000011 -> 11000000 */ q[0] = intv >> 2; /* drop bot 2 bits and store */ fval = 8.0F * p[1]; /* do a */ intv = rintf(fval); intv = VIPS_CLIP(-1024, intv, 1023); lsbs |= (intv & 0x7) << 3; /* 00000111 -> 00111000 */ q[1] = intv >> 3; /* drop bot 3 bits & store */ fval = 8.0F * p[2]; /* do b */ intv = rintf(fval); intv = VIPS_CLIP(-1024, intv, 1023); lsbs |= (intv & 0x7); q[2] = intv >> 3; q[3] = lsbs; /* store lsb band */ p += 3; q += 4; } } void vips__Lab2LabQ_vec(VipsPel *out, float *in, int width) { vips_Lab2LabQ_line(NULL, out, (VipsPel **) &in, width); } static void vips_Lab2LabQ_class_init(VipsLab2LabQClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Lab2LabQ"; object_class->description = _("transform float Lab to LabQ coding"); colour_class->process_line = vips_Lab2LabQ_line; } static void vips_Lab2LabQ_init(VipsLab2LabQ *Lab2LabQ) { VipsColour *colour = VIPS_COLOUR(Lab2LabQ); VipsColourCode *code = VIPS_COLOUR_CODE(Lab2LabQ); colour->coding = VIPS_CODING_LABQ; colour->interpretation = VIPS_INTERPRETATION_LABQ; colour->format = VIPS_FORMAT_UCHAR; colour->input_bands = 3; colour->bands = 4; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_FLOAT; } /** * vips_Lab2LabQ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert a Lab three-band float image to LabQ ([enum@Vips.Coding.LABQ]). * * ::: seealso * [method@Image.LabQ2Lab]. * * Returns: 0 on success, -1 on error. */ int vips_Lab2LabQ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Lab2LabQ", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Lab2LabS.c000066400000000000000000000057121516303661500177360ustar00rootroot00000000000000/* Lab2LabS: quantise FLOAT Lab image into signed short format * * 12/12/02 JC * - from im_Lab2LabS * 1/11/09 * - gtkdoc * - cleanups * 20/9/12 * - redo as a class * 13/7/24 * - clip out of range values */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLab2LabS; typedef VipsColourCodeClass VipsLab2LabSClass; G_DEFINE_TYPE(VipsLab2LabS, vips_Lab2LabS, VIPS_TYPE_COLOUR_CODE); static void vips_Lab2LabS_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; signed short *restrict q = (signed short *) out; int i; for (i = 0; i < width; i++) { q[0] = VIPS_CLIP(0, p[0] * (32767.0 / 100.0), SHRT_MAX); q[1] = VIPS_CLIP(SHRT_MIN, p[1] * (32768.0 / 128.0), SHRT_MAX); q[2] = VIPS_CLIP(SHRT_MIN, p[2] * (32768.0 / 128.0), SHRT_MAX); q += 3; p += 3; } } static void vips_Lab2LabS_class_init(VipsLab2LabSClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Lab2LabS"; object_class->description = _("transform float Lab to signed short"); colour_class->process_line = vips_Lab2LabS_line; } static void vips_Lab2LabS_init(VipsLab2LabS *Lab2LabS) { VipsColour *colour = VIPS_COLOUR(Lab2LabS); VipsColourCode *code = VIPS_COLOUR_CODE(Lab2LabS); colour->interpretation = VIPS_INTERPRETATION_LABS; colour->format = VIPS_FORMAT_SHORT; colour->input_bands = 3; colour->bands = 3; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_FLOAT; } /** * vips_Lab2LabS: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn Lab to LabS, signed 16-bit int fixed point. * * ::: seealso * [method@Image.LabQ2Lab]. * * Returns: 0 on success, -1 on error. */ int vips_Lab2LabS(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Lab2LabS", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Lab2XYZ.c000066400000000000000000000125411516303661500176050ustar00rootroot00000000000000/* Lab to XYZ. * * Modified: * 15/11/94 JC * - ANSIfied * - sets Type of output * - better error messages * 16/11/94 JC * - partialed * - in-line conversion * 8/2/95 JC * - new im_wrapone function * 2/11/09 * - gtkdoc * - cleanups * 18/9/12 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcolour.h" typedef struct _VipsLab2XYZ { VipsColourTransform parent_instance; /* The colour temperature -- default to D65. */ VipsArea *temp; /* Broken out as xyz. */ double X0; double Y0; double Z0; } VipsLab2XYZ; typedef VipsColourTransformClass VipsLab2XYZClass; G_DEFINE_TYPE(VipsLab2XYZ, vips_Lab2XYZ, VIPS_TYPE_COLOUR_TRANSFORM); static void vips_col_Lab2XYZ_helper(VipsLab2XYZ *Lab2XYZ, float L, float a, float b, float *X, float *Y, float *Z) { double cby, tmp; if (L < 8.0) { *Y = (L * Lab2XYZ->Y0) / 903.3; cby = 7.787 * (*Y / Lab2XYZ->Y0) + 16.0 / 116.0; } else { cby = (L + 16.0) / 116.0; *Y = Lab2XYZ->Y0 * cby * cby * cby; } tmp = a / 500.0 + cby; if (tmp < 0.2069) *X = Lab2XYZ->X0 * (tmp - 0.13793) / 7.787; else *X = Lab2XYZ->X0 * tmp * tmp * tmp; tmp = cby - b / 200.0; if (tmp < 0.2069) *Z = Lab2XYZ->Z0 * (tmp - 0.13793) / 7.787; else *Z = Lab2XYZ->Z0 * tmp * tmp * tmp; } /* Process a buffer of data. */ static void vips_Lab2XYZ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsLab2XYZ *Lab2XYZ = (VipsLab2XYZ *) colour; float *restrict p = (float *) in[0]; float *restrict q = (float *) out; int x; VIPS_DEBUG_MSG("vips_Lab2XYZ_line: X0 = %g, Y0 = %g, Z0 = %g\n", Lab2XYZ->X0, Lab2XYZ->Y0, Lab2XYZ->Z0); for (x = 0; x < width; x++) { float L, a, b; float X, Y, Z; L = p[0]; a = p[1]; b = p[2]; p += 3; vips_col_Lab2XYZ_helper(Lab2XYZ, L, a, b, &X, &Y, &Z); /* Write. */ q[0] = X; q[1] = Y; q[2] = Z; q += 3; } } static int vips_Lab2XYZ_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsLab2XYZ *Lab2XYZ = (VipsLab2XYZ *) object; if (Lab2XYZ->temp) { if (vips_check_vector_length(class->nickname, Lab2XYZ->temp->n, 3)) return -1; Lab2XYZ->X0 = ((double *) Lab2XYZ->temp->data)[0]; Lab2XYZ->Y0 = ((double *) Lab2XYZ->temp->data)[1]; Lab2XYZ->Z0 = ((double *) Lab2XYZ->temp->data)[2]; } if (VIPS_OBJECT_CLASS(vips_Lab2XYZ_parent_class)->build(object)) return -1; return 0; } static void vips_Lab2XYZ_class_init(VipsLab2XYZClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "Lab2XYZ"; object_class->description = _("transform CIELAB to XYZ"); object_class->build = vips_Lab2XYZ_build; colour_class->process_line = vips_Lab2XYZ_line; VIPS_ARG_BOXED(class, "temp", 110, _("Temperature"), _("Color temperature"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsLab2XYZ, temp), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_Lab2XYZ_init(VipsLab2XYZ *Lab2XYZ) { VipsColour *colour = VIPS_COLOUR(Lab2XYZ); Lab2XYZ->X0 = VIPS_D65_X0; Lab2XYZ->Y0 = VIPS_D65_Y0; Lab2XYZ->Z0 = VIPS_D65_Z0; colour->interpretation = VIPS_INTERPRETATION_XYZ; } /** * vips_Lab2XYZ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn Lab to XYZ. The colour temperature defaults to D65, but can be * specified with @temp. * * ::: tip "Optional arguments" * * @temp: [struct@ArrayDouble], colour temperature * * Returns: 0 on success, -1 on error */ int vips_Lab2XYZ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Lab2XYZ", ap, in, out); va_end(ap); return result; } /** * vips_col_Lab2XYZ: * @L: Input CIE Lab value * @a: Input CIE Lab value * @b: Input CIE Lab value * @X: (out): Return CIE XYZ colour * @Y: (out): Return CIE XYZ colour * @Z: (out): Return CIE XYZ colour * * Calculate XYZ from Lab, D65. * * ::: seealso * [method@Image.Lab2XYZ]. */ void vips_col_Lab2XYZ(float L, float a, float b, float *X, float *Y, float *Z) { VipsLab2XYZ Lab2XYZ; Lab2XYZ.X0 = VIPS_D65_X0; Lab2XYZ.Y0 = VIPS_D65_Y0; Lab2XYZ.Z0 = VIPS_D65_Z0; vips_col_Lab2XYZ_helper(&Lab2XYZ, L, a, b, X, Y, Z); } libvips-8.18.2/libvips/colour/LabQ2Lab.c000066400000000000000000000076231516303661500177370ustar00rootroot00000000000000/* LabQ2Lab * * Copyright Kirk Martinez 2/5/1993 * * Modified: 16/6/93 * 7/6/93 JC * - adapted for partial v2 * 16/11/94 JC * - adapted to new im_wrap_oneonebuf() function. * 9/2/95 JC * - new im_wrapone function * 22/5/95 JC * - changed char to unsigned char for RS/6000 * - small tidies and speed-ups * 4/9/97 JC * - L* = 100.0 now handled correctly * 2/11/09 * - gtkdoc * 20/9/12 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLabQ2Lab; typedef VipsColourCodeClass VipsLabQ2LabClass; G_DEFINE_TYPE(VipsLabQ2Lab, vips_LabQ2Lab, VIPS_TYPE_COLOUR_CODE); /* imb_LabQ2Lab: CONVERT n pels from packed 32bit Lab to float values * in a buffer * ARGS: VipsPel *inp pointer to first byte of Lab32 buffer * float *outbuf destination buffer * int n number of pels to process * (C) K.Martinez 2/5/93 */ static void vips_LabQ2Lab_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { signed char *restrict p = (signed char *) in[0]; float *restrict q = (float *) out; int l; int lsbs; /* for lsbs byte */ int i; /* counter */ /* Read input with a signed pointer to get signed ab easily. */ for (i = 0; i < width; i++) { /* Get extra bits. */ lsbs = ((unsigned char *) p)[3]; /* Build L. */ l = ((unsigned char *) p)[0]; l = (l << 2) | (lsbs >> 6); q[0] = (float) l * (100.0F / 1023.0F); /* Build a. */ l = VIPS_LSHIFT_INT(p[1], 3) | ((lsbs >> 3) & 0x7); q[1] = (float) l * 0.125F; /* And b. */ l = VIPS_LSHIFT_INT(p[2], 3) | (lsbs & 0x7); q[2] = (float) l * 0.125F; p += 4; q += 3; } } void vips__LabQ2Lab_vec(float *out, VipsPel *in, int width) { vips_LabQ2Lab_line(NULL, (VipsPel *) out, &in, width); } static void vips_LabQ2Lab_class_init(VipsLabQ2LabClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LabQ2Lab"; object_class->description = _("unpack a LabQ image to float Lab"); colour_class->process_line = vips_LabQ2Lab_line; } static void vips_LabQ2Lab_init(VipsLabQ2Lab *LabQ2Lab) { VipsColour *colour = VIPS_COLOUR(LabQ2Lab); VipsColourCode *code = VIPS_COLOUR_CODE(LabQ2Lab); colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_LAB; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 3; code->input_coding = VIPS_CODING_LABQ; } /** * vips_LabQ2Lab: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Unpack a LabQ ([enum@Vips.Coding.LABQ]) image to a three-band float image. * * ::: seealso * [method@Image.LabQ2Lab], [method@Image.LabQ2LabS], [method@Image.rad2float]. * * Returns: 0 on success, -1 on error. */ int vips_LabQ2Lab(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LabQ2Lab", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/LabQ2LabS.c000066400000000000000000000063671516303661500200660ustar00rootroot00000000000000/* LabQ2LabS * * 17/11/93 JC * - adapted from im_LabQ2LabS() * 16/11/94 JC * - uses new im_wrap_oneonebuf() fn * 9/2/95 JC * - new im_wrapone function * 2/11/09 * - gtkdoc * 21/9/12 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLabQ2LabS; typedef VipsColourCodeClass VipsLabQ2LabSClass; G_DEFINE_TYPE(VipsLabQ2LabS, vips_LabQ2LabS, VIPS_TYPE_COLOUR_CODE); /* CONVERT n pels from packed 32bit Lab to signed short. */ static void vips_LabQ2LabS_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { unsigned char *restrict p = (unsigned char *) in[0]; signed short *restrict q = (signed short *) out; int i; unsigned char ext; signed short l, a, b; for (i = 0; i < width; i++) { /* Get most significant 8 bits of lab. */ l = p[0] << 7; a = p[1] << 8; b = p[2] << 8; /* Get x-tra bits. */ ext = p[3]; p += 4; /* Shift and mask in to lab. */ l |= (unsigned char) (ext & 0xc0) >> 1; a |= (ext & 0x38) << 2; b |= (ext & 0x7) << 5; /* Write! */ q[0] = l; q[1] = a; q[2] = b; q += 3; } } static void vips_LabQ2LabS_class_init(VipsLabQ2LabSClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LabQ2LabS"; object_class->description = _("unpack a LabQ image to short Lab"); colour_class->process_line = vips_LabQ2LabS_line; } static void vips_LabQ2LabS_init(VipsLabQ2LabS *LabQ2LabS) { VipsColour *colour = VIPS_COLOUR(LabQ2LabS); VipsColourCode *code = VIPS_COLOUR_CODE(LabQ2LabS); colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_LABS; colour->format = VIPS_FORMAT_SHORT; colour->bands = 3; code->input_coding = VIPS_CODING_LABQ; } /** * vips_LabQ2LabS: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Unpack a LabQ ([enum@Vips.Coding.LABQ]) image to a three-band short image. * * ::: seealso * [method@Image.LabS2LabQ], [method@Image.LabQ2LabS], [method@Image.rad2float]. * * Returns: 0 on success, -1 on error. */ int vips_LabQ2LabS(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LabQ2LabS", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/LabQ2sRGB.c000066400000000000000000000273621516303661500200400ustar00rootroot00000000000000/* Turn Lab 32bit packed format into displayable rgb. Fast, but very * inaccurate: for display only! Note especially that this dithers and will * give different results on different runs. * * The XYZ <-> sRGB transform implemented is this one: * * http://en.wikipedia.org/wiki/SRGB * * 5/11/97 Steve Perry * - adapted from old ip code * 7/11/97 JC * - small tidies, added to VIPS * - LUT build split into separate function * 21/9/12 * - redone as a class * - sRGB only, support for other RGBs is now via lcms * 1/11/12 * - faster and more accurate sRGB <-> XYZ conversion * 6/11/12 * - added a 16-bit path * 11/12/12 * - spot NaN, Inf in XYZ2RGB, they break LUT indexing * - split sRGB <-> XYZ into sRGB <-> scRGB <-> XYZ so we can support * scRGB as a colourspace * 10/3/16 Lovell Fuller * - move vips_col_make_tables_LabQ2sRGB() to first pixel processing */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLabQ2sRGB; typedef VipsColourCodeClass VipsLabQ2sRGBClass; G_DEFINE_TYPE(VipsLabQ2sRGB, vips_LabQ2sRGB, VIPS_TYPE_COLOUR_CODE); /* 8-bit linear -> sRGB lut. * * There's an extra element at the end to let us do a +1 for interpolation. */ static int vips_Y2v_8[256 + 1]; /* 8-bit sRGB -> linear lut. */ float vips_v2Y_8[256]; /* 16-bit linear -> sRGB lut. * * There's an extra element at the end to let us do a +1 for interpolation. */ static int vips_Y2v_16[65536 + 1]; /* 16-bit sRGB -> linear lut. */ float vips_v2Y_16[65536]; /* Do our own indexing of the arrays below to make sure we get efficient mults. */ #define INDEX(L, A, B) (L + (A << 6) + (B << 12)) /* A set of LUTs for quick LabQ->sRGB transforms. */ static VipsPel vips_red[64 * 64 * 64]; static VipsPel vips_green[64 * 64 * 64]; static VipsPel vips_blue[64 * 64 * 64]; /* sRGB to scRGB. * * @range is eg. 256 for 8-bit data. */ static int vips_col_sRGB2scRGB(int range, float *lut, int r, int g, int b, float *R, float *G, float *B) { int maxval = range - 1; int i; i = VIPS_CLIP(0, r, maxval); *R = lut[i]; i = VIPS_CLIP(0, g, maxval); *G = lut[i]; i = VIPS_CLIP(0, b, maxval); *B = lut[i]; return 0; } /* Create the sRGB linear and unlinear luts. @range is eg. 256 for 8-bit luts. */ static void calcul_tables(int range, int *Y2v, float *v2Y) { int i; for (i = 0; i < range; i++) { float f = (float) i / (range - 1); float v; if (f <= 0.0031308) v = 12.92F * f; else v = (1.0F + 0.055F) * powf(f, 1.0F / 2.4F) - 0.055F; Y2v[i] = rintf((range - 1) * v); } /* Copy the final element. This is used in the piecewise linear * interpolator below. */ Y2v[range] = Y2v[range - 1]; for (i = 0; i < range; i++) { float f = (float) i / (range - 1); if (f <= 0.04045) v2Y[i] = f / 12.92F; else v2Y[i] = powf((f + 0.055F) / (1 + 0.055F), 2.4F); } } static void * calcul_tables_8(void *client) { calcul_tables(256, vips_Y2v_8, vips_v2Y_8); return NULL; } void vips_col_make_tables_RGB_8(void) { static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, calcul_tables_8, NULL); } int vips_col_sRGB2scRGB_8(int r, int g, int b, float *R, float *G, float *B) { vips_col_make_tables_RGB_8(); return vips_col_sRGB2scRGB(256, vips_v2Y_8, r, g, b, R, G, B); } static void * calcul_tables_16(void *client) { calcul_tables(65536, vips_Y2v_16, vips_v2Y_16); return NULL; } void vips_col_make_tables_RGB_16(void) { static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, calcul_tables_16, NULL); } int vips_col_sRGB2scRGB_16(int r, int g, int b, float *R, float *G, float *B) { vips_col_make_tables_RGB_16(); return vips_col_sRGB2scRGB(65536, vips_v2Y_16, r, g, b, R, G, B); } /* The matrix already includes the D65 channel weighting, so we just scale by * Y. */ #define SCALE (VIPS_D65_Y0) /** * vips_col_scRGB2XYZ: * @R: Input scRGB value * @G: Input scRGB value * @B: Input scRGB value * @X: (out): Return XYZ colour * @Y: (out): Return XYZ colour * @Z: (out): Return XYZ colour * * Turn scRGB into XYZ. * * ::: seealso * [method@Image.scRGB2XYZ]. */ int vips_col_scRGB2XYZ(float R, float G, float B, float *X, float *Y, float *Z) { R *= SCALE; G *= SCALE; B *= SCALE; *X = 0.4124F * R + 0.3576F * G + 0.1805F * B; *Y = 0.2126F * R + 0.7152F * G + 0.0722F * B; *Z = 0.0193F * R + 0.1192F * G + 0.9505F * B; return 0; } /** * vips_col_XYZ2scRGB: * @X: Input XYZ value * @Y: Input XYZ value * @Z: Input XYZ value * @R: (out): Return scRGB colour * @G: (out): Return scRGB colour * @B: (out): Return scRGB colour * * Turn XYZ into scRGB. * * ::: seealso * [method@Image.XYZ2scRGB]. */ int vips_col_XYZ2scRGB(float X, float Y, float Z, float *R, float *G, float *B) { X /= SCALE; Y /= SCALE; Z /= SCALE; /* Use 6 decimal places of precision for the inverse matrix. */ *R = 3.240625F * X + -1.537208F * Y + -0.498629F * Z; *G = -0.968931F * X + 1.875756F * Y + 0.041518F * Z; *B = 0.055710F * X + -0.204021F * Y + 1.056996F * Z; return 0; } /* Turn scRGB into sRGB. Return og=1 for out of gamut - rgb will contain an * approximation of the right colour. * * Return -1 for NaN. */ static int vips_col_scRGB2sRGB(int range, int *lut, float R, float G, float B, int *r, int *g, int *b, int *og_ret) { int maxval = range - 1; int og; float Yf; int Yi; float v; /* RGB can be NaN. Throw those values out, they will break * our clipping. * * Don't use isnormal(), it is false for 0.0 and for subnormal * numbers. */ if (isnan(R) || isnan(G) || isnan(B)) { *r = 0; *g = 0; *b = 0; return -1; } /* Clip range, set the out-of-gamut flag. */ #define CLIP(L, V, H) \ { \ if ((V) < (L)) { \ (V) = (L); \ og = 1; \ } \ else if ((V) > (H)) { \ (V) = (H); \ og = 1; \ } \ } /* Look up with a float index: interpolate between the nearest two * points. * * The +1 on the index is safe, see above. */ og = 0; Yf = R * maxval; CLIP(0, Yf, maxval); Yi = (int) Yf; v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); *r = rintf(v); Yf = G * maxval; CLIP(0, Yf, maxval); Yi = (int) Yf; v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); *g = rintf(v); Yf = B * maxval; CLIP(0, Yf, maxval); Yi = (int) Yf; v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); *b = rintf(v); if (og_ret) *og_ret = og; return 0; } int vips_col_scRGB2sRGB_8(float R, float G, float B, int *r, int *g, int *b, int *og) { vips_col_make_tables_RGB_8(); return vips_col_scRGB2sRGB(256, vips_Y2v_8, R, G, B, r, g, b, og); } int vips_col_scRGB2sRGB_16(float R, float G, float B, int *r, int *g, int *b, int *og) { vips_col_make_tables_RGB_16(); return vips_col_scRGB2sRGB(65536, vips_Y2v_16, R, G, B, r, g, b, og); } /* Turn scRGB into BW. Return or=1 for out of gamut - g will contain an * approximation of the right colour. * * Return -1 for NaN. */ static int vips_col_scRGB2BW(int range, int *lut, float R, float G, float B, int *g, int *og_ret) { int maxval = range - 1; float Y; int og; float Yf; int Yi; float v; /* CIE linear luminance function, see * https://en.wikipedia.org/wiki/Grayscale#Colorimetric_(perceptual_luminance-preserving)_conversion_to_grayscale */ Y = 0.2126F * R + 0.7152F * G + 0.0722F * B; /* Y can be Nan. Throw those values out, they will break * our clipping. */ if (isnan(Y)) { *g = 0; return -1; } /* Look up with a float index: interpolate between the nearest two * points. * * The +1 on the index is safe, see above. */ og = 0; Yf = Y * maxval; CLIP(0, Yf, maxval); Yi = (int) Yf; v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); *g = rintf(v); if (og_ret) *og_ret = og; return 0; } int vips_col_scRGB2BW_16(float R, float G, float B, int *g, int *og) { vips_col_make_tables_RGB_16(); return vips_col_scRGB2BW(65536, vips_Y2v_16, R, G, B, g, og); } int vips_col_scRGB2BW_8(float R, float G, float B, int *g, int *og) { vips_col_make_tables_RGB_8(); return vips_col_scRGB2BW(256, vips_Y2v_8, R, G, B, g, og); } /* Build Lab->disp dither tables. */ static void * build_tables(void *client) { int l, a, b; int t; for (l = 0; l < 64; l++) { for (a = 0; a < 64; a++) { for (b = 0; b < 64; b++) { /* Scale to lab space. */ float L = (l << 2) * (100.0F / 256.0F); float A = (signed char) (a << 2); float B = (signed char) (b << 2); float X, Y, Z; float Rf, Gf, Bf; int rb, gb, bb; vips_col_Lab2XYZ(L, A, B, &X, &Y, &Z); vips_col_XYZ2scRGB(X, Y, Z, &Rf, &Gf, &Bf); vips_col_scRGB2sRGB_8(Rf, Gf, Bf, &rb, &gb, &bb, NULL); t = INDEX(l, a, b); vips_red[t] = rb; vips_green[t] = gb; vips_blue[t] = bb; } } } return NULL; } static void vips_col_make_tables_LabQ2sRGB(void) { static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, build_tables, NULL); } /* Process a buffer of data. */ static void vips_LabQ2sRGB_line(VipsColour *colour, VipsPel *q, VipsPel **in, int width) { unsigned char *p = (unsigned char *) in[0]; int i, t; /* Current error. */ int le = 0; int ae = 0; int be = 0; vips_col_make_tables_LabQ2sRGB(); for (i = 0; i < width; i++) { /* Get colour, add in error from previous pixel. */ int L = p[0] + le; int A = (signed char) p[1] + ae; int B = (signed char) p[2] + be; p += 4; /* Look out for overflow. */ L = VIPS_MIN(255, L); A = VIPS_MIN(127, A); B = VIPS_MIN(127, B); /* Find new quant error. This will always be +ve. */ le = L & 3; ae = A & 3; be = B & 3; /* Scale to 0-63. */ L = (L >> 2) & 63; A = (A >> 2) & 63; B = (B >> 2) & 63; /* Convert to RGB. */ t = INDEX(L, A, B); q[0] = vips_red[t]; q[1] = vips_green[t]; q[2] = vips_blue[t]; q += 3; } } static void vips_LabQ2sRGB_class_init(VipsLabQ2sRGBClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LabQ2sRGB"; object_class->description = _("convert a LabQ image to sRGB"); colour_class->process_line = vips_LabQ2sRGB_line; } static void vips_LabQ2sRGB_init(VipsLabQ2sRGB *LabQ2sRGB) { VipsColour *colour = VIPS_COLOUR(LabQ2sRGB); VipsColourCode *code = VIPS_COLOUR_CODE(LabQ2sRGB); colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_sRGB; colour->format = VIPS_FORMAT_UCHAR; colour->bands = 3; code->input_coding = VIPS_CODING_LABQ; } /** * vips_LabQ2sRGB: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Unpack a LabQ ([enum@Vips.Coding.LABQ]) image to a three-band short image. * * ::: seealso * [method@Image.LabS2LabQ], [method@Image.LabQ2sRGB], [method@Image.rad2float]. * * Returns: 0 on success, -1 on error. */ int vips_LabQ2sRGB(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LabQ2sRGB", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/LabS2Lab.c000066400000000000000000000054451516303661500177410ustar00rootroot00000000000000/* LabS2Lab() * * 12/12/02 JC * - adapted from im_LabS2LabQ() * 2/11/09 * - gtkdoc, cleanup */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLabS2Lab; typedef VipsColourCodeClass VipsLabS2LabClass; G_DEFINE_TYPE(VipsLabS2Lab, vips_LabS2Lab, VIPS_TYPE_COLOUR_CODE); /* Convert n pels from signed short to Lab. */ static void vips_LabS2Lab_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { signed short *p = (signed short *) in[0]; float *q = (float *) out; int i; for (i = 0; i < width; i++) { q[0] = p[0] / (32767.0 / 100.0); q[1] = p[1] / (32768.0 / 128.0); q[2] = p[2] / (32768.0 / 128.0); p += 3; q += 3; } } static void vips_LabS2Lab_class_init(VipsLabS2LabClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LabS2Lab"; object_class->description = _("transform signed short Lab to float"); colour_class->process_line = vips_LabS2Lab_line; } static void vips_LabS2Lab_init(VipsLabS2Lab *LabS2Lab) { VipsColour *colour = VIPS_COLOUR(LabS2Lab); VipsColourCode *code = VIPS_COLOUR_CODE(LabS2Lab); colour->interpretation = VIPS_INTERPRETATION_LAB; colour->format = VIPS_FORMAT_FLOAT; colour->input_bands = 3; colour->bands = 3; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_SHORT; } /** * vips_LabS2Lab: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert a LabS three-band signed short image to a three-band float image. * * ::: seealso * [method@Image.LabS2Lab]. * * Returns: 0 on success, -1 on error. */ int vips_LabS2Lab(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LabS2Lab", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/LabS2LabQ.c000066400000000000000000000072161516303661500200600ustar00rootroot00000000000000/* LabS2LabQ() * * 17/11/93 JC * - adapted from im_LabS2LabQ() * 16/11/94 JC * - adapted to new im_wrap_oneonebuf() function * 15/6/95 JC * - oops! rounding was broken * 6/6/95 JC * - added round-to-nearest * - somewhat slower ... * 21/12/99 JC * - a/b ==0 rounding was broken * 2/11/09 * - gtkdoc, cleanup * 21/9/12 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourCode VipsLabS2LabQ; typedef VipsColourCodeClass VipsLabS2LabQClass; G_DEFINE_TYPE(VipsLabS2LabQ, vips_LabS2LabQ, VIPS_TYPE_COLOUR_CODE); /* Convert n pels from signed short to IM_CODING_LABQ. */ static void vips_LabS2LabQ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { signed short *p = (signed short *) in[0]; unsigned char *q = (unsigned char *) out; int i; for (i = 0; i < width; i++) { int l, a, b; unsigned char ext; /* Get LAB, rounding to 10, 11, 11. */ l = p[0] + 16; l = VIPS_CLIP(0, l, 32767); l >>= 5; /* Make sure we round -ves in the right direction! */ a = p[1]; if (a >= 0) a += 16; else a -= 16; a = VIPS_CLIP(-32768, a, 32767); a >>= 5; b = p[2]; if (b >= 0) b += 16; else b -= 16; b = VIPS_CLIP(-32768, b, 32767); b >>= 5; p += 3; /* Extract top 8 bits. */ q[0] = l >> 2; q[1] = a >> 3; q[2] = b >> 3; /* Form extension byte. */ ext = VIPS_LSHIFT_INT(l, 6) & 0xc0; ext |= VIPS_LSHIFT_INT(a, 3) & 0x38; ext |= b & 0x7; q[3] = ext; q += 4; } } static void vips_LabS2LabQ_class_init(VipsLabS2LabQClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "LabS2LabQ"; object_class->description = _("transform short Lab to LabQ coding"); colour_class->process_line = vips_LabS2LabQ_line; } static void vips_LabS2LabQ_init(VipsLabS2LabQ *LabS2LabQ) { VipsColour *colour = VIPS_COLOUR(LabS2LabQ); VipsColourCode *code = VIPS_COLOUR_CODE(LabS2LabQ); colour->coding = VIPS_CODING_LABQ; colour->interpretation = VIPS_INTERPRETATION_LABQ; colour->format = VIPS_FORMAT_UCHAR; colour->input_bands = 3; colour->bands = 4; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_SHORT; } /** * vips_LabS2LabQ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert a LabS three-band signed short image to LabQ * * ::: seealso * [method@Image.LabQ2LabS]. * * Returns: 0 on success, -1 on error. */ int vips_LabS2LabQ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("LabS2LabQ", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Oklab2Oklch.c000066400000000000000000000047511516303661500205110ustar00rootroot00000000000000/* Turn Oklab to Oklch * * 3/12/25 * - from Lab2LCh.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsOklab2Oklch; typedef VipsColourTransformClass VipsOklab2OklchClass; G_DEFINE_TYPE(VipsOklab2Oklch, vips_Oklab2Oklch, VIPS_TYPE_COLOUR_TRANSFORM); static void vips_Oklab2Oklch_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; for (int x = 0; x < width; x++) { float L = p[0]; float a = p[1]; float b = p[2]; p += 3; q[0] = L; q[1] = sqrtf(a * a + b * b); q[2] = vips_col_ab2h(a, b); q += 3; } } static void vips_Oklab2Oklch_class_init(VipsOklab2OklchClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Oklab2Oklch"; object_class->description = _("transform Oklab to Oklch"); colour_class->process_line = vips_Oklab2Oklch_line; } static void vips_Oklab2Oklch_init(VipsOklab2Oklch *Oklab2Oklch) { VipsColour *colour = VIPS_COLOUR(Oklab2Oklch); colour->interpretation = VIPS_INTERPRETATION_OKLCH; } /** * vips_Oklab2Oklch: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn Oklab to Oklch. * * Returns: 0 on success, -1 on error */ int vips_Oklab2Oklch(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Oklab2Oklch", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Oklab2XYZ.c000066400000000000000000000061371516303661500201430ustar00rootroot00000000000000/* Oklab to XYZ. * */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsOklab2XYZ; typedef VipsColourTransformClass VipsOklab2XYZClass; G_DEFINE_TYPE(VipsOklab2XYZ, vips_Oklab2XYZ, VIPS_TYPE_COLOUR_TRANSFORM); /* Process a buffer of data. */ static void vips_Oklab2XYZ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; for (int x = 0; x < width; x++) { const float L = p[0]; const float a = p[1]; const float b = p[2]; p += 3; // M2 inv to get LMS prime const float lp = L * 1. + a * 0.39633779 + b * 0.21580376; const float mp = L * 1.00000001 + a * -0.10556134 + b * -0.06385417; const float sp = L * 1.00000005 + a * -0.08948418 + b * -1.29148554; // back to lms const float l = lp * lp * lp; const float m = mp * mp * mp; const float s = sp * sp * sp; // M1 inv to get D65 normalised XYZ float X = l * 1.22701385 + m * -0.55779998 + s * 0.28125615; float Y = l * -0.04058018 + m * 1.11225687 + s * -0.07167668; float Z = l * -0.07638128 + m * -0.42148198 + s * 1.58616322; q[0] = X * 100.0; q[1] = Y * 100.0; q[2] = Z * 100.0; q += 3; } } static void vips_Oklab2XYZ_class_init(VipsOklab2XYZClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Oklab2XYZ"; object_class->description = _("transform Oklab to XYZ"); colour_class->process_line = vips_Oklab2XYZ_line; } static void vips_Oklab2XYZ_init(VipsOklab2XYZ *Oklab2XYZ) { VipsColour *colour = VIPS_COLOUR(Oklab2XYZ); colour->interpretation = VIPS_INTERPRETATION_XYZ; } /** * vips_Oklab2XYZ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Transform Oklab to XYZ using D65 illuminant. * * Returns: 0 on success, -1 on error */ int vips_Oklab2XYZ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Oklab2XYZ", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Oklch2Oklab.c000066400000000000000000000050151516303661500205030ustar00rootroot00000000000000/* _Oklch2Oklab * * 3/12/25 * - from LCh2Lab.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsOklch2Oklab; typedef VipsColourTransformClass VipsOklch2OklabClass; G_DEFINE_TYPE(VipsOklch2Oklab, vips_Oklch2Oklab, VIPS_TYPE_COLOUR_TRANSFORM); /* Process a buffer of data. */ static void vips_Oklch2Oklab_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; for (int x = 0; x < width; x++) { float L = p[0]; float C = p[1]; float h = p[2]; p += 3; float a, b; vips_col_Ch2ab(C, h, &a, &b); q[0] = L; q[1] = a; q[2] = b; q += 3; } } static void vips_Oklch2Oklab_class_init(VipsOklch2OklabClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Oklch2Oklab"; object_class->description = _("transform Oklch to Oklab"); colour_class->process_line = vips_Oklch2Oklab_line; } static void vips_Oklch2Oklab_init(VipsOklch2Oklab *Oklch2Oklab) { VipsColour *colour = VIPS_COLOUR(Oklch2Oklab); colour->interpretation = VIPS_INTERPRETATION_OKLAB; } /** * vips_Oklch2Oklab: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn Oklch to Oklab. * * Returns: 0 on success, -1 on error */ int vips_Oklch2Oklab(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Oklch2Oklab", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/UCS2LCh.c000066400000000000000000000132011516303661500175070ustar00rootroot00000000000000/* Turn CMC to LCh * * 15/11/94 JC * - error messages added * - memory leak fixed * 16/11/94 JC * - uses im_wrap_oneonebuf() now * 2/11/09 * - gtkdoc * 30/11/09 * - argh, im_col_make_tables_CMC(); missing, thanks Peter * 19/9/12 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" /* Arrays for lookup tables for the inverse function. */ static float LI[1001]; static float CI[3001]; static float hI[101][361]; typedef VipsColourTransform VipsCMC2LCh; typedef VipsColourTransformClass VipsCMC2LChClass; G_DEFINE_TYPE(VipsCMC2LCh, vips_CMC2LCh, VIPS_TYPE_COLOUR_TRANSFORM); /* Generate LI (inverse) tables. */ static void make_LI(void) { int i; float Ll[1001]; for (i = 0; i < 1001; i++) Ll[i] = vips_col_L2Lcmc(i / 10.0); for (i = 0; i < 1001; i++) { int j; /* Must be 1000, since j will be +1 on exit. */ for (j = 0; j < 1000 && Ll[j] <= i / 10.0; j++) ; LI[i] = (j - 1) / 10.0 + (i / 10.0 - Ll[j - 1]) / ((Ll[j] - Ll[j - 1]) * 10.0); } } /* Generate Ccmc table. */ static void make_CI(void) { int i; float Cl[3001]; for (i = 0; i < 3001; i++) Cl[i] = vips_col_C2Ccmc(i / 10.0); for (i = 0; i < 3001; i++) { int j; /* Must be 3000, since j will be +1 on exit. */ for (j = 0; j < 3000 && Cl[j] <= i / 10.0; j++) ; CI[i] = (j - 1) / 10.0 + (i / 10.0 - Cl[j - 1]) / ((Cl[j] - Cl[j - 1]) * 10.0); } } /* The difficult one: hcmc. */ static void make_hI(void) { int i, j; float hl[101][361]; for (i = 0; i < 361; i++) for (j = 0; j < 101; j++) hl[j][i] = vips_col_Ch2hcmc(j * 2.0, i); for (j = 0; j < 101; j++) { for (i = 0; i < 361; i++) { int k; for (k = 1; k < 360 && hl[j][k] <= i; k++) ; hI[j][i] = k - 1 + (i - hl[j][k - 1]) / (hl[j][k] - hl[j][k - 1]); } } } /** * vips_col_Lcmc2L: * @Lcmc: L cmc * * Calculate L from Lcmc using a table. Call [func@col_make_tables_CMC] at * least once before using this function. * * Returns: L* */ float vips_col_Lcmc2L(float Lcmc) { int known; known = floor(Lcmc * 10.0); known = VIPS_CLIP(0, known, 999); return LI[known] + (LI[known + 1] - LI[known]) * (Lcmc * 10.0F - known); } /** * vips_col_Ccmc2C: * @Ccmc: Ccmc * * Calculate C from Ccmc using a table. * Call [func@col_make_tables_CMC] at * least once before using this function. * * Returns: C. */ float vips_col_Ccmc2C(float Ccmc) { int known; known = floor(Ccmc * 10.0); known = VIPS_CLIP(0, known, 2999); return CI[known] + (CI[known + 1] - CI[known]) * (Ccmc * 10.0F - known); } /** * vips_col_Chcmc2h: * @C: Chroma * @hcmc: Hue cmc (degrees) * * Calculate h from C and hcmc, using a table. * Call [func@col_make_tables_CMC] at * least once before using this function. * * Returns: h. */ float vips_col_Chcmc2h(float C, float hcmc) { int r; int known; /* Which row of the table? */ r = (int) ((C + 1.0) / 2.0); r = VIPS_CLIP(0, r, 99); known = floor(hcmc); known = VIPS_CLIP(0, known, 359); return hI[r][known] + (hI[r][(known + 1) % 360] - hI[r][known]) * (hcmc - known); } static void * tables_init(void *client) { make_LI(); make_CI(); make_hI(); return NULL; } /** * vips_col_make_tables_CMC: * * Make the lookup tables for cmc. */ void vips_col_make_tables_CMC(void) { static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, tables_init, NULL); } /* Process a buffer of data. */ static void vips_CMC2LCh_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *p = (float *) in[0]; float *q = (float *) out; int x; for (x = 0; x < width; x++) { float Lcmc = p[0]; float Ccmc = p[1]; float hcmc = p[2]; /* Turn from CMC. */ float C = vips_col_Ccmc2C(Ccmc); float h = vips_col_Chcmc2h(C, hcmc); float L = vips_col_Lcmc2L(Lcmc); p += 3; q[0] = L; q[1] = C; q[2] = h; q += 3; } } static void vips_CMC2LCh_class_init(VipsCMC2LChClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "CMC2LCh"; object_class->description = _("transform LCh to CMC"); colour_class->process_line = vips_CMC2LCh_line; } static void vips_CMC2LCh_init(VipsCMC2LCh *CMC2LCh) { VipsColour *colour = VIPS_COLOUR(CMC2LCh); vips_col_make_tables_CMC(); colour->interpretation = VIPS_INTERPRETATION_LCH; } /** * vips_CMC2LCh: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn LCh to CMC. * * ::: seealso * [method@Image.LCh2CMC]. * * Returns: 0 on success, -1 on error */ int vips_CMC2LCh(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("CMC2LCh", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/XYZ2CMYK.c000066400000000000000000000127151516303661500176550ustar00rootroot00000000000000/* Use lcms to move from XYZ to CMYK, if we can. This needs a working * vips_icc_export. * * 21/12/18 * - from CMYK2XYZ.c * 09/01/2019 * - add CMYK <-> XYZ conversions if no lcms2 has been found */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcolour.h" #include "profiles.h" #ifdef HAVE_LCMS2 typedef struct _VipsXYZ2CMYK { VipsOperation parent_instance; VipsImage *in; VipsImage *out; } VipsXYZ2CMYK; typedef VipsColourCodeClass VipsXYZ2CMYKClass; G_DEFINE_TYPE(VipsXYZ2CMYK, vips_XYZ2CMYK, VIPS_TYPE_OPERATION); /* Our actual processing, as a VipsColourTransformFn. */ static int vips_XYZ2CMYK_process(VipsImage *in, VipsImage **out, ...) { return vips_icc_export(in, out, "output_profile", "cmyk", "pcs", VIPS_PCS_XYZ, NULL); } static int vips_XYZ2CMYK_build(VipsObject *object) { VipsXYZ2CMYK *XYZ2CMYK = (VipsXYZ2CMYK *) object; VipsImage *out; VipsImage *t; if (VIPS_OBJECT_CLASS(vips_XYZ2CMYK_parent_class)->build(object)) return -1; out = vips_image_new(); g_object_set(object, "out", out, NULL); if (vips__colourspace_process_n("XYZ2CMYK", XYZ2CMYK->in, &t, 3, vips_XYZ2CMYK_process)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static void vips_XYZ2CMYK_class_init(VipsXYZ2CMYKClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "XYZ2CMYK"; object_class->description = _("transform XYZ to CMYK"); object_class->build = vips_XYZ2CMYK_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsXYZ2CMYK, in)); VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsXYZ2CMYK, out)); } static void vips_XYZ2CMYK_init(VipsXYZ2CMYK *XYZ2CMYK) { } #else /*!HAVE_LCMS2*/ typedef VipsColourCode VipsXYZ2CMYK; typedef VipsColourCodeClass VipsXYZ2CMYKClass; G_DEFINE_TYPE(VipsXYZ2CMYK, vips_XYZ2CMYK, VIPS_TYPE_COLOUR_CODE); static void vips_XYZ2CMYK_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *p = (float *) in[0]; unsigned char *q = (unsigned char *) out; const float epsilon = 0.00001; int i; for (i = 0; i < width; i++) { float r = p[0] / VIPS_D65_X0; float g = p[1] / VIPS_D65_Y0; float b = p[2] / VIPS_D65_Z0; float c = 1.0 - r; float m = 1.0 - g; float y = 1.0 - b; float k = VIPS_MIN(c, VIPS_MIN(m, y)); float ik = 1.0 - k; if (ik < epsilon) { q[0] = 255; q[1] = 255; q[2] = 255; q[3] = 255; } else { q[0] = VIPS_CLIP(0, 255 * (c - k) / ik, 255); q[1] = VIPS_CLIP(0, 255 * (m - k) / ik, 255); q[2] = VIPS_CLIP(0, 255 * (y - k) / ik, 255); q[3] = VIPS_CLIP(0, 255 * k, 255); } p += 3; q += 4; } } static void vips_XYZ2CMYK_class_init(VipsXYZ2CMYKClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "XYZ2CMYK"; object_class->description = _("transform XYZ to CMYK"); colour_class->process_line = vips_XYZ2CMYK_line; } static void vips_XYZ2CMYK_init(VipsXYZ2CMYK *XYZ2CMYK) { VipsColour *colour = VIPS_COLOUR(XYZ2CMYK); VipsColourCode *code = VIPS_COLOUR_CODE(XYZ2CMYK); colour->interpretation = VIPS_INTERPRETATION_CMYK; colour->format = VIPS_FORMAT_UCHAR; colour->bands = 4; colour->input_bands = 3; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_FLOAT; code->input_interpretation = VIPS_INTERPRETATION_XYZ; } #endif /*HAVE_LCMS2*/ /** * vips_XYZ2CMYK: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn XYZ to CMYK. * * Conversion is from D65 XYZ with relative intent. If you need more control * over the process, use [method@Image.icc_export] instead. * * Returns: 0 on success, -1 on error */ int vips_XYZ2CMYK(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("XYZ2CMYK", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/XYZ2Lab.c000066400000000000000000000142541516303661500176100ustar00rootroot00000000000000/* Turn XYZ to Lab colourspace. * * Modified: * 16/11/94 JC * - uses im_wrapone() * - in-line conversion * 27/1/03 JC * - swapped cbrt() for pow(), more portable * 12/11/04 * - swapped pow() for cbrt() again, pow() is insanely slow on win32 * - added a configure test for cbrt(). * 23/11/04 * - use a large LUT instead, about 5x faster * 23/11/06 * - ahem, build the LUT outside the eval thread * 2/11/09 * - gtkdoc * 3/8/11 * - fix a race in the table build * 19/9/12 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcolour.h" /* Lookup table size. */ #define QUANT_ELEMENTS (100000) static float cbrt_table[QUANT_ELEMENTS]; typedef struct _VipsXYZ2Lab { VipsColourTransform parent_instance; /* The colour temperature -- default to D65. */ VipsArea *temp; /* Broken out as xyz. */ double X0; double Y0; double Z0; } VipsXYZ2Lab; typedef VipsColourTransformClass VipsXYZ2LabClass; G_DEFINE_TYPE(VipsXYZ2Lab, vips_XYZ2Lab, VIPS_TYPE_COLOUR_TRANSFORM); static GOnce table_init_once = G_ONCE_INIT; static void * table_init(void *client) { int i; for (i = 0; i < QUANT_ELEMENTS; i++) { float Y = (double) i / QUANT_ELEMENTS; if (Y < 0.008856) cbrt_table[i] = 7.787F * Y + (16.0F / 116.0F); else cbrt_table[i] = cbrtf(Y); } return NULL; } static void vips_col_XYZ2Lab_helper(VipsXYZ2Lab *XYZ2Lab, float X, float Y, float Z, float *L, float *a, float *b) { float nX, nY, nZ; int i; float f; float cbx, cby, cbz; nX = QUANT_ELEMENTS * X / XYZ2Lab->X0; nY = QUANT_ELEMENTS * Y / XYZ2Lab->Y0; nZ = QUANT_ELEMENTS * Z / XYZ2Lab->Z0; /* CLIP is much faster than FCLIP, and we want an int result. */ i = VIPS_CLIP(0, (int) nX, QUANT_ELEMENTS - 2); f = nX - i; cbx = cbrt_table[i] + f * (cbrt_table[i + 1] - cbrt_table[i]); i = VIPS_CLIP(0, (int) nY, QUANT_ELEMENTS - 2); f = nY - i; cby = cbrt_table[i] + f * (cbrt_table[i + 1] - cbrt_table[i]); i = VIPS_CLIP(0, (int) nZ, QUANT_ELEMENTS - 2); f = nZ - i; cbz = cbrt_table[i] + f * (cbrt_table[i + 1] - cbrt_table[i]); *L = 116.0F * cby - 16.0F; *a = 500.0F * (cbx - cby); *b = 200.0F * (cby - cbz); } /* Process a buffer of data. */ VIPS_TARGET_CLONES("default,avx") static void vips_XYZ2Lab_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsXYZ2Lab *XYZ2Lab = (VipsXYZ2Lab *) colour; float *p = (float *) in[0]; float *q = (float *) out; int x; VIPS_ONCE(&table_init_once, table_init, NULL); for (x = 0; x < width; x++) { float X, Y, Z; float L, a, b; X = p[0]; Y = p[1]; Z = p[2]; p += 3; vips_col_XYZ2Lab_helper(XYZ2Lab, X, Y, Z, &L, &a, &b); q[0] = L; q[1] = a; q[2] = b; q += 3; } } /** * vips_col_XYZ2Lab: * @X: Input CIE XYZ colour * @Y: Input CIE XYZ colour * @Z: Input CIE XYZ colour * @L: (out): Return CIE Lab value * @a: (out): Return CIE Lab value * @b: (out): Return CIE Lab value * * Calculate XYZ from Lab, D65. * * ::: seealso * [method@Image.XYZ2Lab]. */ void vips_col_XYZ2Lab(float X, float Y, float Z, float *L, float *a, float *b) { VipsXYZ2Lab XYZ2Lab; VIPS_ONCE(&table_init_once, table_init, NULL); XYZ2Lab.X0 = VIPS_D65_X0; XYZ2Lab.Y0 = VIPS_D65_Y0; XYZ2Lab.Z0 = VIPS_D65_Z0; vips_col_XYZ2Lab_helper(&XYZ2Lab, X, Y, Z, L, a, b); } static int vips_XYZ2Lab_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsXYZ2Lab *XYZ2Lab = (VipsXYZ2Lab *) object; if (XYZ2Lab->temp) { if (vips_check_vector_length(class->nickname, XYZ2Lab->temp->n, 3)) return -1; XYZ2Lab->X0 = ((double *) XYZ2Lab->temp->data)[0]; XYZ2Lab->Y0 = ((double *) XYZ2Lab->temp->data)[1]; XYZ2Lab->Z0 = ((double *) XYZ2Lab->temp->data)[2]; } if (VIPS_OBJECT_CLASS(vips_XYZ2Lab_parent_class)->build(object)) return -1; return 0; } static void vips_XYZ2Lab_class_init(VipsXYZ2LabClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "XYZ2Lab"; object_class->description = _("transform XYZ to Lab"); object_class->build = vips_XYZ2Lab_build; colour_class->process_line = vips_XYZ2Lab_line; VIPS_ARG_BOXED(class, "temp", 110, _("Temperature"), _("Colour temperature"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsXYZ2Lab, temp), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_XYZ2Lab_init(VipsXYZ2Lab *XYZ2Lab) { VipsColour *colour = VIPS_COLOUR(XYZ2Lab); XYZ2Lab->X0 = VIPS_D65_X0; XYZ2Lab->Y0 = VIPS_D65_Y0; XYZ2Lab->Z0 = VIPS_D65_Z0; colour->interpretation = VIPS_INTERPRETATION_LAB; } /** * vips_XYZ2Lab: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn XYZ to Lab, optionally specifying the colour temperature. @temp * defaults to D65. * * ::: tip "Optional arguments" * * @temp: [struct@ArrayDouble], colour temperature * * Returns: 0 on success, -1 on error. */ int vips_XYZ2Lab(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("XYZ2Lab", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/XYZ2Oklab.c000066400000000000000000000062711516303661500201420ustar00rootroot00000000000000/* Transform XYZ to Oklab coordinates * * 2/12/25 * - from XYZ2scRGB.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsXYZ2Oklab; typedef VipsColourTransformClass VipsXYZ2OklabClass; G_DEFINE_TYPE(VipsXYZ2Oklab, vips_XYZ2Oklab, VIPS_TYPE_COLOUR_TRANSFORM); // see https://en.wikipedia.org/wiki/Oklab_color_space#Conversion_from_CIE_XYZ static void vips_XYZ2Oklab_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; for (int i = 0; i < width; i++) { // to D65 normalised XYZ ... M1 already has D65_X0 included etc. const float X = p[0] / 100.0; const float Y = p[1] / 100.0; const float Z = p[2] / 100.0; p += 3; // convert to LMS const float l = X * 0.8189330101 + Y * 0.3618667424 + Z * -0.1288597137; const float m = X * 0.0329845436 + Y * 0.9293118715 + Z * 0.0361456387; const float s = X * 0.0482003018 + Y * 0.2643662691 + Z * 0.6338517070; // cube root ... possibly LUT this? const float lp = cbrtf(l); const float mp = cbrtf(m); const float sp = cbrtf(s); // to Oklab q[0] = lp * 0.2104542553 + mp * 0.7936177850 + sp * -0.0040720468; q[1] = lp * 1.9779984951 + mp * -2.4285922050 + sp * 0.4505937099; q[2] = lp * 0.0259040371 + mp * 0.7827717662 + sp * -0.8086757660; q += 3; } } static void vips_XYZ2Oklab_class_init(VipsXYZ2OklabClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "XYZ2Oklab"; object_class->description = _("transform XYZ to Oklab"); colour_class->process_line = vips_XYZ2Oklab_line; } static void vips_XYZ2Oklab_init(VipsXYZ2Oklab *XYZ2Oklab) { VipsColour *colour = VIPS_COLOUR(XYZ2Oklab); colour->interpretation = VIPS_INTERPRETATION_OKLAB; } /** * vips_XYZ2Oklab: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Transform XYZ to Oklab assuming D65 illuminant. * * Returns: 0 on success, -1 on error */ int vips_XYZ2Oklab(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("XYZ2Oklab", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/XYZ2Yxy.c000066400000000000000000000051471516303661500177040ustar00rootroot00000000000000/* Turn XYZ to Yxy colourspace. * * Modified: * 29/5/02 JC * - from lab2xyz * 2/11/09 * - gtkdoc * - cleanups * 20/9/12 * redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsXYZ2Yxy; typedef VipsColourTransformClass VipsXYZ2YxyClass; G_DEFINE_TYPE(VipsXYZ2Yxy, vips_XYZ2Yxy, VIPS_TYPE_COLOUR_TRANSFORM); static void vips_XYZ2Yxy_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; int i; for (i = 0; i < width; i++) { float X = p[0]; float Y = p[1]; float Z = p[2]; double total = X + Y + Z; float x, y; p += 3; if (total == 0.0) { x = 0; y = 0; } else { x = X / total; y = Y / total; } q[0] = Y; q[1] = x; q[2] = y; q += 3; } } static void vips_XYZ2Yxy_class_init(VipsXYZ2YxyClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "XYZ2Yxy"; object_class->description = _("transform XYZ to Yxy"); colour_class->process_line = vips_XYZ2Yxy_line; } static void vips_XYZ2Yxy_init(VipsXYZ2Yxy *XYZ2Yxy) { VipsColour *colour = VIPS_COLOUR(XYZ2Yxy); colour->interpretation = VIPS_INTERPRETATION_YXY; } /** * vips_XYZ2Yxy: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn XYZ to Yxy. * * Returns: 0 on success, -1 on error */ int vips_XYZ2Yxy(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("XYZ2Yxy", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/XYZ2scRGB.c000066400000000000000000000060711516303661500200500ustar00rootroot00000000000000/* Turn XYZ to scRGB colourspace. * * 11/12/12 * - from Yxy2XYZ.c * 1/7/13 * - remove any ICC profile * 25/11/14 * - oh argh, revert the above */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsXYZ2scRGB; typedef VipsColourTransformClass VipsXYZ2scRGBClass; G_DEFINE_TYPE(VipsXYZ2scRGB, vips_XYZ2scRGB, VIPS_TYPE_COLOUR_TRANSFORM); /* We used to have the comment: * We've converted to sRGB without a profile. We must remove any ICC * profile left over from import or there will be a mismatch between * pixel values and the attached profile. But this isn't right, we often call things sRGB that we know are not true sRGB, for example: vips sharpen k2.jpg x.jpg sharpen will treat k2 as being in sRGB space even if that image has a profile. If we drop the profile, x.jpg is suddenly untagged. */ static void vips_XYZ2scRGB_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; for (int i = 0; i < width; i++) { const float X = p[0]; const float Y = p[1]; const float Z = p[2]; float R, G, B; p += 3; vips_col_XYZ2scRGB(X, Y, Z, &R, &G, &B); q[0] = R; q[1] = G; q[2] = B; q += 3; } } static void vips_XYZ2scRGB_class_init(VipsXYZ2scRGBClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "XYZ2scRGB"; object_class->description = _("transform XYZ to scRGB"); colour_class->process_line = vips_XYZ2scRGB_line; } static void vips_XYZ2scRGB_init(VipsXYZ2scRGB *XYZ2scRGB) { VipsColour *colour = VIPS_COLOUR(XYZ2scRGB); colour->interpretation = VIPS_INTERPRETATION_scRGB; } /** * vips_XYZ2scRGB: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn XYZ to scRGB. * * Returns: 0 on success, -1 on error */ int vips_XYZ2scRGB(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("XYZ2scRGB", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/Yxy2XYZ.c000066400000000000000000000052511516303661500177000ustar00rootroot00000000000000/* Turn Yxy to XYZ colourspace. * * Modified: * 29/5/02 JC * - from lab2xyz * 2/11/09 * - gtkdoc * - cleanups * 20/9/12 * - redo as a class * 29/8/19 * - avoid /0 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsYxy2XYZ; typedef VipsColourTransformClass VipsYxy2XYZClass; G_DEFINE_TYPE(VipsYxy2XYZ, vips_Yxy2XYZ, VIPS_TYPE_COLOUR_TRANSFORM); static void vips_Yxy2XYZ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; int i; for (i = 0; i < width; i++) { float Y = p[0]; float x = p[1]; float y = p[2]; float X, Z; if (x == 0.0 || y == 0.0) { X = 0.0F; Z = 0.0F; } else { float total; total = Y / y; X = x * total; Z = (X - x * X - x * Y) / x; } q[0] = X; q[1] = Y; q[2] = Z; p += 3; q += 3; } } static void vips_Yxy2XYZ_class_init(VipsYxy2XYZClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "Yxy2XYZ"; object_class->description = _("transform Yxy to XYZ"); colour_class->process_line = vips_Yxy2XYZ_line; } static void vips_Yxy2XYZ_init(VipsYxy2XYZ *Yxy2XYZ) { VipsColour *colour = VIPS_COLOUR(Yxy2XYZ); colour->interpretation = VIPS_INTERPRETATION_XYZ; } /** * vips_Yxy2XYZ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn XYZ to Yxy. * * Returns: 0 on success, -1 on error */ int vips_Yxy2XYZ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("Yxy2XYZ", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/colour.c000066400000000000000000000410471516303661500177200ustar00rootroot00000000000000/* base class for all colour operations */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcolour.h" /* Areas under curves for Dxx. 2 degree observer. */ /** * VIPS_D93_X0: * * Areas under curves for D93, 2 degree observer. */ /** * VIPS_D75_X0: * * Areas under curves for D75, 2 degree observer. */ /** * VIPS_D65_X0: * * Areas under curves for D65, 2 degree observer. */ /** * VIPS_D55_X0: * * Areas under curves for D55, 2 degree observer. */ /** * VIPS_D50_X0: * * Areas under curves for D50, 2 degree observer. */ /** * VIPS_A_X0: * * Areas under curves for illuminant A (2856K), 2 degree observer. */ /** * VIPS_B_X0: * * Areas under curves for illuminant B (4874K), 2 degree observer. */ /** * VIPS_C_X0: * * Areas under curves for illuminant C (6774K), 2 degree observer. */ /** * VIPS_E_X0: * * Areas under curves for equal energy illuminant E. */ /** * VIPS_D3250_X0: * * Areas under curves for black body at 3250K, 2 degree observer. */ G_DEFINE_ABSTRACT_TYPE(VipsColour, vips_colour, VIPS_TYPE_OPERATION); /* Maximum number of input images -- why not? */ #define MAX_INPUT_IMAGES (64) static int vips_colour_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion **ir = (VipsRegion **) seq; VipsColour *colour = VIPS_COLOUR(b); VipsColourClass *class = VIPS_COLOUR_GET_CLASS(colour); VipsRect *r = &out_region->valid; int i, y; VipsPel *p[MAX_INPUT_IMAGES], *q; /* printf("vips_colour_gen: %s, " "left = %d, top = %d, width = %d, height = %d\n", VIPS_OBJECT_CLASS(class)->nickname, r->left, r->top, r->width, r->height); */ if (vips_reorder_prepare_many(out_region->im, ir, r)) return -1; VIPS_GATE_START("vips_colour_gen: work"); for (y = 0; y < r->height; y++) { for (i = 0; ir[i]; i++) p[i] = VIPS_REGION_ADDR(ir[i], r->left, r->top + y); p[i] = NULL; q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); class->process_line(colour, q, p, r->width); } VIPS_GATE_STOP("vips_colour_gen: work"); VIPS_COUNT_PIXELS(out_region, VIPS_OBJECT_GET_CLASS(colour)->nickname); return 0; } static int vips_colour_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsColour *colour = VIPS_COLOUR(object); VipsImage **in; VipsImage **extra_bands; VipsImage *out; #ifdef DEBUG printf("vips_colour_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_colour_parent_class)->build(object)) return -1; if (colour->n > MAX_INPUT_IMAGES) { vips_error(class->nickname, "%s", _("too many input images")); return -1; } for (int i = 0; i < colour->n; i++) if (vips_image_pio_input(colour->in[i])) return -1; /* colour->in[] must be NULL-terminated, we can use it as an arg to * vips_start_many(). */ g_assert(!colour->in[colour->n]); in = colour->in; extra_bands = (VipsImage **) vips_object_local_array(object, colour->n); /* If there are more than @input_bands bands, we detach and reattach * after processing. */ if (colour->input_bands > 0) { VipsImage **new_in = (VipsImage **) vips_object_local_array(object, colour->n); for (int i = 0; i < colour->n; i++) { if (vips_check_bands_atleast(class->nickname, in[i], colour->input_bands)) return -1; if (in[i]->Bands > colour->input_bands) { if (vips_extract_band(in[i], &new_in[i], 0, "n", colour->input_bands, NULL)) return -1; } else { new_in[i] = in[i]; g_object_ref(new_in[i]); } if (in[i]->Bands > colour->input_bands) if (vips_extract_band(in[i], &extra_bands[i], colour->input_bands, "n", in[i]->Bands - colour->input_bands, NULL)) return -1; } in = new_in; } out = vips_image_new(); if (vips_image_pipeline_array(out, VIPS_DEMAND_STYLE_THINSTRIP, in)) { g_object_unref(out); return -1; } out->Coding = colour->coding; out->Type = colour->interpretation; out->BandFmt = colour->format; out->Bands = colour->bands; if (colour->profile_filename && vips__profile_set(out, colour->profile_filename)) return -1; if (vips_image_generate(out, vips_start_many, vips_colour_gen, vips_stop_many, in, colour)) { VIPS_UNREF(out); return -1; } /* Reattach higher bands, if necessary. If we have more than one input * image, just use the first extra bands. */ for (int i = 0; i < colour->n; i++) if (extra_bands[i]) { VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); double max_alpha_before = vips_interpretation_max_alpha(extra_bands[i]->Type); double max_alpha_after = vips_interpretation_max_alpha(out->Type); VipsImage *alpha; alpha = extra_bands[i]; /* Rescale, if the alpha scale has changed. */ if (max_alpha_before != max_alpha_after) { if (vips_linear1(alpha, &t[0], max_alpha_after / max_alpha_before, 0.0, NULL)) { VIPS_UNREF(out); return -1; } alpha = t[0]; } if (vips_cast(alpha, &t[1], out->BandFmt, NULL)) { VIPS_UNREF(out); return -1; } alpha = t[1]; if (vips_bandjoin2(out, alpha, &t[2], NULL)) { VIPS_UNREF(out); return -1; } g_object_unref(out); out = t[2]; t[2] = NULL; break; } g_object_set(colour, "out", out, NULL); return 0; } static void vips_colour_class_init(VipsColourClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "colour"; vobject_class->description = _("color operations"); vobject_class->build = vips_colour_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "out", 100, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsColour, out)); } static void vips_colour_init(VipsColour *colour) { colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_sRGB; colour->format = VIPS_FORMAT_UCHAR; colour->bands = 3; colour->input_bands = -1; } G_DEFINE_ABSTRACT_TYPE(VipsColourTransform, vips_colour_transform, VIPS_TYPE_COLOUR); static int vips_colour_transform_build(VipsObject *object) { VipsColour *colour = VIPS_COLOUR(object); VipsColourTransform *transform = VIPS_COLOUR_TRANSFORM(object); VipsImage **t = (VipsImage **) vips_object_local_array(object, 1); /* We only process float. */ if (transform->in && transform->in->BandFmt != VIPS_FORMAT_FLOAT) { if (vips_cast_float(transform->in, &t[0], NULL)) return -1; } else { t[0] = transform->in; g_object_ref(t[0]); } /* We always do 3 bands -> 3 bands. */ colour->input_bands = 3; colour->n = 1; colour->in = t; if (VIPS_OBJECT_CLASS(vips_colour_transform_parent_class)->build(object)) return -1; return 0; } static void vips_colour_transform_class_init(VipsColourTransformClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "space"; vobject_class->description = _("color space transformations"); vobject_class->build = vips_colour_transform_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourTransform, in)); } static void vips_colour_transform_init(VipsColourTransform *space) { VipsColour *colour = (VipsColour *) space; /* What we write. interpretation should be overwritten in subclass * builds. */ colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_LAB; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 3; } G_DEFINE_ABSTRACT_TYPE(VipsColourCode, vips_colour_code, VIPS_TYPE_COLOUR); static int vips_colour_code_build(VipsObject *object) { VipsColour *colour = VIPS_COLOUR(object); VipsColourCode *code = VIPS_COLOUR_CODE(object); VipsColourCodeClass *class = VIPS_COLOUR_CODE_GET_CLASS(object); VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); VipsImage *in; in = code->in; /* We want labq, rad etc. all decoded (unlike colour_build). */ if (in && code->input_coding == VIPS_CODING_NONE && in->Coding != code->input_coding) { if (vips_image_decode(in, &t[0])) return -1; in = t[0]; } if (in && vips_check_coding(VIPS_OBJECT_CLASS(class)->nickname, in, code->input_coding)) return -1; if (in && code->input_coding == VIPS_CODING_NONE && code->input_format != VIPS_FORMAT_NOTSET && in->BandFmt != code->input_format) { if (vips_cast(in, &t[3], code->input_format, NULL)) return -1; in = t[3]; } if (in && code->input_coding == VIPS_CODING_NONE && code->input_interpretation != VIPS_INTERPRETATION_ERROR && in->Type != code->input_interpretation) { if (vips_colourspace(in, &t[4], code->input_interpretation, NULL)) return -1; in = t[4]; } colour->n = 1; colour->in = VIPS_ARRAY(object, 2, VipsImage *); colour->in[0] = in; colour->in[1] = NULL; if (VIPS_OBJECT_CLASS(vips_colour_code_parent_class)->build(object)) return -1; return 0; } static void vips_colour_code_class_init(VipsColourCodeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "code"; vobject_class->description = _("change color coding"); vobject_class->build = vips_colour_code_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourCode, in)); } static void vips_colour_code_init(VipsColourCode *code) { code->input_coding = VIPS_CODING_NONE; code->input_interpretation = VIPS_INTERPRETATION_ERROR; code->input_format = VIPS_FORMAT_NOTSET; } G_DEFINE_ABSTRACT_TYPE(VipsColourDifference, vips_colour_difference, VIPS_TYPE_COLOUR); static int vips_colour_difference_build(VipsObject *object) { VipsColour *colour = VIPS_COLOUR(object); VipsColourDifference *difference = VIPS_COLOUR_DIFFERENCE(object); VipsImage **t; VipsImage *left; VipsImage *right; t = (VipsImage **) vips_object_local_array(object, 12); left = difference->left; right = difference->right; if (left) { if (vips_image_decode(left, &t[0])) return -1; left = t[0]; } if (right) { if (vips_image_decode(right, &t[1])) return -1; right = t[1]; } /* Detach and reattach any extra bands. */ colour->input_bands = 3; if (left && left->Type != difference->interpretation) { if (vips_colourspace(left, &t[6], difference->interpretation, NULL)) return -1; left = t[6]; } if (right && right->Type != difference->interpretation) { if (vips_colourspace(right, &t[7], difference->interpretation, NULL)) return -1; right = t[7]; } /* We only process float. */ if (left && left->BandFmt != VIPS_FORMAT_FLOAT) { if (vips_cast_float(left, &t[8], NULL)) return -1; left = t[8]; } if (right && right->BandFmt != VIPS_FORMAT_FLOAT) { if (vips_cast_float(right, &t[9], NULL)) return -1; right = t[9]; } if (vips__sizealike(left, right, &t[10], &t[11])) return -1; left = t[10]; right = t[11]; colour->n = 2; colour->in = VIPS_ARRAY(object, 3, VipsImage *); colour->in[0] = left; colour->in[1] = right; colour->in[2] = NULL; if (VIPS_OBJECT_CLASS(vips_colour_difference_parent_class)->build(object)) return -1; return 0; } static void vips_colour_difference_class_init(VipsColourDifferenceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "difference"; vobject_class->description = _("calculate color difference"); vobject_class->build = vips_colour_difference_build; VIPS_ARG_IMAGE(class, "left", 1, _("Left"), _("Left-hand input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourDifference, left)); VIPS_ARG_IMAGE(class, "right", 2, _("Right"), _("Right-hand input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourDifference, right)); } static void vips_colour_difference_init(VipsColourDifference *difference) { VipsColour *colour = VIPS_COLOUR(difference); colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_B_W; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 1; } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_colour_operation_init(void) { extern GType vips_colourspace_get_type(void); extern GType vips_Lab2XYZ_get_type(void); extern GType vips_XYZ2Lab_get_type(void); extern GType vips_Lab2LCh_get_type(void); extern GType vips_LCh2Lab_get_type(void); extern GType vips_LCh2CMC_get_type(void); extern GType vips_CMC2LCh_get_type(void); extern GType vips_Yxy2XYZ_get_type(void); extern GType vips_XYZ2Yxy_get_type(void); extern GType vips_LabQ2Lab_get_type(void); extern GType vips_Lab2LabQ_get_type(void); extern GType vips_LabQ2LabS_get_type(void); extern GType vips_LabS2LabQ_get_type(void); extern GType vips_LabS2Lab_get_type(void); extern GType vips_Lab2LabS_get_type(void); extern GType vips_rad2float_get_type(void); extern GType vips_float2rad_get_type(void); extern GType vips_LabQ2sRGB_get_type(void); extern GType vips_XYZ2sRGB_get_type(void); extern GType vips_sRGB2scRGB_get_type(void); extern GType vips_sRGB2HSV_get_type(void); extern GType vips_HSV2sRGB_get_type(void); extern GType vips_scRGB2XYZ_get_type(void); extern GType vips_scRGB2BW_get_type(void); extern GType vips_XYZ2scRGB_get_type(void); extern GType vips_scRGB2sRGB_get_type(void); extern GType vips_CMYK2XYZ_get_type(void); extern GType vips_XYZ2CMYK_get_type(void); extern GType vips_XYZ2Oklab_get_type(void); extern GType vips_Oklab2XYZ_get_type(void); extern GType vips_Oklab2Oklch_get_type(void); extern GType vips_Oklch2Oklab_get_type(void); extern GType vips_uhdr2scRGB_get_type(void); extern GType vips_profile_load_get_type(void); #ifdef HAVE_LCMS2 extern GType vips_icc_import_get_type(void); extern GType vips_icc_export_get_type(void); extern GType vips_icc_transform_get_type(void); #endif extern GType vips_dE76_get_type(void); extern GType vips_dE00_get_type(void); extern GType vips_dECMC_get_type(void); vips_colourspace_get_type(); vips_Oklab2Oklch_get_type(); vips_Oklch2Oklab_get_type(); vips_Oklab2XYZ_get_type(); vips_XYZ2Oklab_get_type(); vips_Lab2XYZ_get_type(); vips_XYZ2Lab_get_type(); vips_Lab2LCh_get_type(); vips_LCh2Lab_get_type(); vips_LCh2CMC_get_type(); vips_CMC2LCh_get_type(); vips_XYZ2Yxy_get_type(); vips_Yxy2XYZ_get_type(); vips_LabQ2Lab_get_type(); vips_Lab2LabQ_get_type(); vips_LabQ2LabS_get_type(); vips_LabS2LabQ_get_type(); vips_LabS2Lab_get_type(); vips_Lab2LabS_get_type(); vips_rad2float_get_type(); vips_float2rad_get_type(); vips_LabQ2sRGB_get_type(); vips_sRGB2scRGB_get_type(); vips_scRGB2XYZ_get_type(); vips_scRGB2BW_get_type(); vips_sRGB2HSV_get_type(); vips_HSV2sRGB_get_type(); vips_XYZ2scRGB_get_type(); vips_scRGB2sRGB_get_type(); vips_CMYK2XYZ_get_type(); vips_XYZ2CMYK_get_type(); vips_uhdr2scRGB_get_type(); vips_profile_load_get_type(); #ifdef HAVE_LCMS2 vips_icc_import_get_type(); vips_icc_export_get_type(); vips_icc_transform_get_type(); #endif vips_dE76_get_type(); vips_dE00_get_type(); vips_dECMC_get_type(); } libvips-8.18.2/libvips/colour/colourspace.c000066400000000000000000000701571516303661500207400ustar00rootroot00000000000000/* convert between colourspaces * * 6/11/12 * - add RGB16 as a destination * 12/1/14 * - add B_W as a source / dest * - add GREY16 as a source / dest * - add RGB16 as a source * 19/1/14 * - auto-decode RAD images * 3/2/14 * - add "source_space", overrides source space guess * 8/5/14 * - oops, don't treat RGB16 as sRGB * 9/9/14 * - mono <-> rgb converters were not handling extra bands, thanks James * 4/2/15 * - much faster RGB16->sRGB path * 17/4/15 * - better conversion to greyscale, see * https://github.com/lovell/sharp/issues/193 * 27/12/18 * - add CMYK conversions */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcolour.h" static int vips_scRGB2RGB16(VipsImage *in, VipsImage **out, ...) { return vips_scRGB2sRGB(in, out, "depth", 16, NULL); } static int vips_scRGB2BW16(VipsImage *in, VipsImage **out, ...) { return vips_scRGB2BW(in, out, "depth", 16, NULL); } /* Do these two with a simple cast ... since we're just cast shifting, we can * short-circuit the extra band processing. */ static int vips_RGB162sRGB(VipsImage *in, VipsImage **out, ...) { if (vips_cast(in, out, VIPS_FORMAT_UCHAR, "shift", TRUE, NULL)) return -1; (*out)->Type = VIPS_INTERPRETATION_sRGB; return 0; } static int vips_sRGB2RGB16(VipsImage *in, VipsImage **out, ...) { if (vips_cast(in, out, VIPS_FORMAT_USHORT, "shift", TRUE, NULL)) return -1; (*out)->Type = VIPS_INTERPRETATION_RGB16; return 0; } /* Process the first @n bands with @fn, detach and reattach remaining bands. * * Also used by CMYK2XYZ and XYZ2CMYK. */ int vips__colourspace_process_n(const char *domain, VipsImage *in, VipsImage **out, int n, VipsColourTransformFn fn) { if (in->Bands > n) { VipsImage *scope = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(scope), 4); if (vips_extract_band(in, &t[0], 0, "n", n, NULL) || vips_extract_band(in, &t[1], n, "n", in->Bands - n, NULL) || fn(t[0], &t[2], NULL) || vips_cast(t[1], &t[3], t[2]->BandFmt, NULL) || vips_bandjoin2(t[2], t[3], out, NULL)) { g_object_unref(scope); return -1; } g_object_unref(scope); } else if (in->Bands == n) { if (fn(in, out, NULL)) return -1; } else { vips_error(domain, "%s", _("too few bands for operation")); return -1; } return 0; } static int vips_BW2sRGB_op(VipsImage *in, VipsImage **out, ...) { VipsImage *t[3]; t[0] = in; t[1] = in; t[2] = in; if (vips_bandjoin(t, out, 3, NULL)) return -1; return 0; } static int vips_BW2sRGB(VipsImage *in, VipsImage **out, ...) { if (vips__colourspace_process_n("BW2sRGB", in, out, 1, vips_BW2sRGB_op)) return -1; (*out)->Type = VIPS_INTERPRETATION_sRGB; return 0; } static int vips_GREY162RGB16(VipsImage *in, VipsImage **out, ...) { if (vips__colourspace_process_n("GREY162RGB16", in, out, 1, vips_BW2sRGB_op)) return -1; (*out)->Type = VIPS_INTERPRETATION_RGB16; return 0; } /* Maximum number of steps we allow in a route. 10 steps should be enough * for anyone. */ #define MAX_STEPS (10) /* A route between two colour spaces. */ typedef struct _VipsColourRoute { VipsInterpretation from; VipsInterpretation to; VipsColourTransformFn route[MAX_STEPS + 1]; } VipsColourRoute; /* Some defines to save typing. These are the colour spaces we support * conversions between. */ #define XYZ VIPS_INTERPRETATION_XYZ #define LAB VIPS_INTERPRETATION_LAB #define LABQ VIPS_INTERPRETATION_LABQ #define LCH VIPS_INTERPRETATION_LCH #define CMC VIPS_INTERPRETATION_CMC #define LABS VIPS_INTERPRETATION_LABS #define CMYK VIPS_INTERPRETATION_CMYK #define scRGB VIPS_INTERPRETATION_scRGB #define sRGB VIPS_INTERPRETATION_sRGB #define HSV VIPS_INTERPRETATION_HSV #define BW VIPS_INTERPRETATION_B_W #define RGB16 VIPS_INTERPRETATION_RGB16 #define GREY16 VIPS_INTERPRETATION_GREY16 #define YXY VIPS_INTERPRETATION_YXY #define OKLAB VIPS_INTERPRETATION_OKLAB #define OKLCH VIPS_INTERPRETATION_OKLCH /* All the routes we know about. */ static VipsColourRoute vips_colour_routes[] = { { XYZ, XYZ, { vips_cast_float, NULL } }, { XYZ, LAB, { vips_XYZ2Lab, NULL } }, { XYZ, LABQ, { vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { XYZ, LCH, { vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { XYZ, CMC, { vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { XYZ, LABS, { vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { XYZ, CMYK, { vips_XYZ2CMYK, NULL } }, { XYZ, scRGB, { vips_XYZ2scRGB, NULL } }, { XYZ, sRGB, { vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { XYZ, HSV, { vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { XYZ, BW, { vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { XYZ, RGB16, { vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { XYZ, GREY16, { vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { XYZ, YXY, { vips_XYZ2Yxy, NULL } }, { XYZ, OKLAB, { vips_XYZ2Oklab, NULL } }, { XYZ, OKLCH, { vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { LAB, XYZ, { vips_Lab2XYZ, NULL } }, { LAB, LAB, { vips_cast_float, NULL } }, { LAB, LABQ, { vips_Lab2LabQ, NULL } }, { LAB, LCH, { vips_Lab2LCh, NULL } }, { LAB, CMC, { vips_Lab2LCh, vips_LCh2CMC, NULL } }, { LAB, LABS, { vips_Lab2LabS, NULL } }, { LAB, CMYK, { vips_Lab2XYZ, vips_XYZ2CMYK, NULL } }, { LAB, scRGB, { vips_Lab2XYZ, vips_XYZ2scRGB, NULL } }, { LAB, sRGB, { vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { LAB, HSV, { vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { LAB, BW, { vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { LAB, RGB16, { vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { LAB, GREY16, { vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { LAB, YXY, { vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LAB, OKLAB, { vips_Lab2XYZ, vips_XYZ2Oklab, NULL } }, { LAB, OKLCH, { vips_Lab2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { LABQ, XYZ, { vips_LabQ2Lab, vips_Lab2XYZ, NULL } }, { LABQ, LAB, { vips_LabQ2Lab, NULL } }, { LABQ, LABQ, { NULL } }, { LABQ, LCH, { vips_LabQ2Lab, vips_Lab2LCh, NULL } }, { LABQ, CMC, { vips_LabQ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { LABQ, LABS, { vips_LabQ2LabS, NULL } }, { LABQ, CMYK, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2CMYK, NULL } }, { LABQ, scRGB, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } }, { LABQ, sRGB, { vips_LabQ2sRGB, NULL } }, { LABQ, HSV, { vips_LabQ2sRGB, vips_sRGB2HSV, NULL } }, { LABQ, BW, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { LABQ, RGB16, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { LABQ, GREY16, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { LABQ, YXY, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LABQ, OKLAB, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, NULL } }, { LABQ, OKLCH, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { LCH, XYZ, { vips_LCh2Lab, vips_Lab2XYZ, NULL } }, { LCH, LAB, { vips_LCh2Lab, NULL } }, { LCH, LABQ, { vips_LCh2Lab, vips_Lab2LabQ, NULL } }, { LCH, LCH, { vips_cast_float, NULL } }, { LCH, CMC, { vips_LCh2CMC, NULL } }, { LCH, LABS, { vips_LCh2Lab, vips_Lab2LabS, NULL } }, { LCH, CMYK, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2CMYK, NULL } }, { LCH, scRGB, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } }, { LCH, sRGB, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { LCH, HSV, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { LCH, BW, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { LCH, RGB16, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { LCH, GREY16, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { LCH, YXY, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LCH, OKLAB, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, NULL } }, { LCH, OKLCH, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { CMC, XYZ, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, NULL } }, { CMC, LAB, { vips_CMC2LCh, vips_LCh2Lab, NULL } }, { CMC, LABQ, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2LabQ, NULL } }, { CMC, LCH, { vips_CMC2LCh, NULL } }, { CMC, CMC, { vips_cast_float, NULL } }, { CMC, LABS, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2LabS, NULL } }, { CMC, CMYK, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2CMYK, NULL } }, { CMC, scRGB, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } }, { CMC, sRGB, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { CMC, HSV, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { CMC, BW, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { CMC, RGB16, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { CMC, GREY16, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { CMC, YXY, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { CMC, OKLAB, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, NULL } }, { CMC, OKLCH, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { LABS, XYZ, { vips_LabS2Lab, vips_Lab2XYZ, NULL } }, { LABS, LAB, { vips_LabS2Lab, NULL } }, { LABS, LABQ, { vips_LabS2LabQ, NULL } }, { LABS, LCH, { vips_LabS2Lab, vips_Lab2LCh, NULL } }, { LABS, CMC, { vips_LabS2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { LABS, LABS, { vips_cast_short, NULL } }, { LABS, CMYK, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2CMYK, NULL } }, { LABS, scRGB, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } }, { LABS, sRGB, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { LABS, HSV, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { LABS, BW, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { LABS, RGB16, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { LABS, GREY16, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { LABS, YXY, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LABS, OKLAB, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, NULL } }, { LABS, OKLCH, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { CMYK, XYZ, { vips_CMYK2XYZ, NULL } }, { CMYK, LAB, { vips_CMYK2XYZ, vips_XYZ2Lab, NULL } }, { CMYK, LABQ, { vips_CMYK2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { CMYK, LCH, { vips_CMYK2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { CMYK, CMC, { vips_CMYK2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { CMYK, LABS, { vips_CMYK2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, // can be 8 or 16 bit, so do nothing { CMYK, CMYK, { NULL } }, { CMYK, scRGB, { vips_CMYK2XYZ, vips_XYZ2scRGB, NULL } }, { CMYK, sRGB, { vips_CMYK2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { CMYK, HSV, { vips_CMYK2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { CMYK, BW, { vips_CMYK2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { CMYK, RGB16, { vips_CMYK2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { CMYK, GREY16, { vips_CMYK2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { CMYK, YXY, { vips_CMYK2XYZ, vips_XYZ2Yxy, NULL } }, { CMYK, OKLAB, { vips_CMYK2XYZ, vips_XYZ2Oklab, NULL } }, { CMYK, OKLCH, { vips_CMYK2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { scRGB, XYZ, { vips_scRGB2XYZ, NULL } }, { scRGB, LAB, { vips_scRGB2XYZ, vips_XYZ2Lab, NULL } }, { scRGB, LABQ, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { scRGB, LCH, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { scRGB, CMC, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { scRGB, LABS, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { scRGB, CMYK, { vips_scRGB2XYZ, vips_XYZ2CMYK, NULL } }, { scRGB, scRGB, { vips_cast_float, NULL } }, { scRGB, sRGB, { vips_scRGB2sRGB, NULL } }, { scRGB, HSV, { vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { scRGB, BW, { vips_scRGB2BW, NULL } }, { scRGB, RGB16, { vips_scRGB2RGB16, NULL } }, { scRGB, GREY16, { vips_scRGB2BW16, NULL } }, { scRGB, YXY, { vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } }, { scRGB, OKLAB, { vips_scRGB2XYZ, vips_XYZ2Oklab, NULL } }, { scRGB, OKLCH, { vips_scRGB2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { sRGB, XYZ, { vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } }, { sRGB, LAB, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, NULL } }, { sRGB, LABQ, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { sRGB, LCH, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { sRGB, CMC, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { sRGB, LABS, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { sRGB, CMYK, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2CMYK, NULL } }, { sRGB, scRGB, { vips_sRGB2scRGB, NULL } }, { sRGB, sRGB, { vips_cast_uchar, NULL } }, { sRGB, HSV, { vips_sRGB2HSV, NULL } }, { sRGB, BW, { vips_sRGB2scRGB, vips_scRGB2BW, NULL } }, { sRGB, RGB16, { vips_sRGB2RGB16, NULL } }, { sRGB, GREY16, { vips_sRGB2scRGB, vips_scRGB2BW16, NULL } }, { sRGB, YXY, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } }, { sRGB, OKLAB, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, NULL } }, { sRGB, OKLCH, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { HSV, XYZ, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } }, { HSV, LAB, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, NULL } }, { HSV, LABQ, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { HSV, LCH, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { HSV, CMC, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { HSV, LABS, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { HSV, CMYK, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2CMYK, NULL } }, { HSV, scRGB, { vips_HSV2sRGB, vips_sRGB2scRGB, NULL } }, { HSV, sRGB, { vips_HSV2sRGB, NULL } }, { HSV, HSV, { vips_cast_uchar, NULL } }, { HSV, BW, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2BW, NULL } }, { HSV, RGB16, { vips_HSV2sRGB, vips_sRGB2RGB16, NULL } }, { HSV, GREY16, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2BW16, NULL } }, { HSV, YXY, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } }, { HSV, OKLAB, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, NULL } }, { HSV, OKLCH, { vips_HSV2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { BW, XYZ, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } }, { BW, LAB, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, NULL } }, { BW, LABQ, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { BW, LCH, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { BW, CMC, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { BW, LABS, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { BW, CMYK, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2CMYK, NULL } }, { BW, scRGB, { vips_BW2sRGB, vips_sRGB2scRGB, NULL } }, { BW, sRGB, { vips_BW2sRGB, NULL } }, { BW, HSV, { vips_BW2sRGB, vips_sRGB2HSV, NULL } }, { BW, BW, { vips_cast_uchar, NULL } }, { BW, RGB16, { vips_BW2sRGB, vips_sRGB2RGB16, NULL } }, { BW, GREY16, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2BW16, NULL } }, { BW, YXY, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } }, { BW, OKLAB, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, NULL } }, { BW, OKLCH, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { RGB16, XYZ, { vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } }, { RGB16, LAB, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, NULL } }, { RGB16, LABQ, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { RGB16, LCH, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { RGB16, CMC, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { RGB16, LABS, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { RGB16, CMYK, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2CMYK, NULL } }, { RGB16, scRGB, { vips_sRGB2scRGB, NULL } }, { RGB16, sRGB, { vips_RGB162sRGB, NULL } }, { RGB16, HSV, { vips_RGB162sRGB, vips_sRGB2HSV, NULL } }, { RGB16, BW, { vips_sRGB2scRGB, vips_scRGB2BW, NULL } }, { RGB16, RGB16, { vips_cast_ushort, NULL } }, { RGB16, GREY16, { vips_sRGB2scRGB, vips_scRGB2BW16, NULL } }, { RGB16, YXY, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } }, { RGB16, OKLAB, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, NULL } }, { RGB16, OKLCH, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { GREY16, XYZ, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } }, { GREY16, LAB, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, NULL } }, { GREY16, LABQ, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { GREY16, LCH, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { GREY16, CMC, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { GREY16, LABS, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { GREY16, CMYK, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2CMYK, NULL } }, { GREY16, scRGB, { vips_GREY162RGB16, vips_sRGB2scRGB, NULL } }, { GREY16, sRGB, { vips_GREY162RGB16, vips_RGB162sRGB, NULL } }, { GREY16, HSV, { vips_GREY162RGB16, vips_RGB162sRGB, vips_sRGB2HSV, NULL } }, { GREY16, BW, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2BW, NULL } }, { GREY16, RGB16, { vips_GREY162RGB16, NULL } }, { GREY16, GREY16, { vips_cast_ushort, NULL } }, { GREY16, YXY, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } }, { GREY16, OKLAB, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, NULL } }, { GREY16, OKLCH, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { YXY, XYZ, { vips_Yxy2XYZ, NULL } }, { YXY, LAB, { vips_Yxy2XYZ, vips_XYZ2Lab, NULL } }, { YXY, LABQ, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { YXY, LCH, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { YXY, CMC, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { YXY, LABS, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { YXY, CMYK, { vips_Yxy2XYZ, vips_XYZ2CMYK, NULL } }, { YXY, scRGB, { vips_Yxy2XYZ, vips_XYZ2scRGB, NULL } }, { YXY, sRGB, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { YXY, HSV, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { YXY, BW, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { YXY, RGB16, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { YXY, GREY16, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { YXY, YXY, { vips_cast_float, NULL } }, { YXY, OKLAB, { vips_Yxy2XYZ, vips_XYZ2Oklab, NULL } }, { YXY, OKLCH, { vips_Yxy2XYZ, vips_XYZ2Oklab, vips_Oklab2Oklch, NULL } }, { OKLAB, XYZ, { vips_Oklab2XYZ, NULL } }, { OKLAB, LAB, { vips_Oklab2XYZ, vips_XYZ2Lab, NULL } }, { OKLAB, LABQ, { vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { OKLAB, LCH, { vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { OKLAB, CMC, { vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { OKLAB, LABS, { vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { OKLAB, CMYK, { vips_Oklab2XYZ, vips_XYZ2CMYK, NULL } }, { OKLAB, scRGB, { vips_Oklab2XYZ, vips_XYZ2scRGB, NULL } }, { OKLAB, sRGB, { vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { OKLAB, HSV, { vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { OKLAB, BW, { vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { OKLAB, RGB16, { vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { OKLAB, GREY16, { vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { OKLAB, YXY, { vips_Oklab2XYZ, vips_XYZ2Yxy, NULL } }, { OKLAB, OKLAB, { vips_cast_float, NULL } }, { OKLAB, OKLCH, { vips_Oklab2Oklch, NULL } }, { OKLCH, XYZ, { vips_Oklch2Oklab, vips_Oklab2XYZ, NULL } }, { OKLCH, LAB, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2Lab, NULL } }, { OKLCH, LABQ, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { OKLCH, LCH, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { OKLCH, CMC, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { OKLCH, LABS, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { OKLCH, CMYK, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2CMYK, NULL } }, { OKLCH, scRGB, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2scRGB, NULL } }, { OKLCH, sRGB, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } }, { OKLCH, HSV, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, vips_sRGB2HSV, NULL } }, { OKLCH, BW, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW, NULL } }, { OKLCH, RGB16, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } }, { OKLCH, GREY16, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2scRGB, vips_scRGB2BW16, NULL } }, { OKLCH, YXY, { vips_Oklch2Oklab, vips_Oklab2XYZ, vips_XYZ2Yxy, NULL } }, { OKLCH, OKLAB, { vips_Oklch2Oklab, NULL } }, { OKLCH, OKLCH, { vips_cast_float, NULL } }, }; /* Is an image in a supported colourspace. */ /** * vips_colourspace_issupported: (method) * @image: input image * * Test if @image is in a colourspace that [method@Image.colourspace] can * process. * * Returns: `TRUE` if @image is in a supported colourspace. */ gboolean vips_colourspace_issupported(const VipsImage *image) { VipsInterpretation interpretation; int i; interpretation = vips_image_guess_interpretation(image); /* Treat RGB as sRGB. If you want some other treatment, * you'll need to use the icc funcs. */ if (interpretation == VIPS_INTERPRETATION_RGB) interpretation = VIPS_INTERPRETATION_sRGB; /* Treat MATRIX as B_W. */ if (interpretation == VIPS_INTERPRETATION_MATRIX) interpretation = VIPS_INTERPRETATION_B_W; for (i = 0; i < VIPS_NUMBER(vips_colour_routes); i++) if (vips_colour_routes[i].from == interpretation) return TRUE; return FALSE; } typedef struct _VipsColourspace { VipsOperation parent_instance; VipsImage *in; VipsImage *out; VipsInterpretation space; VipsInterpretation source_space; } VipsColourspace; typedef VipsOperationClass VipsColourspaceClass; G_DEFINE_TYPE(VipsColourspace, vips_colourspace, VIPS_TYPE_OPERATION); static int vips_colourspace_build(VipsObject *object) { VipsColourspace *colourspace = (VipsColourspace *) object; int i, j; VipsImage *x; VipsImage **t = (VipsImage **) vips_object_local_array(object, 1); VipsImage **pipe = (VipsImage **) vips_object_local_array(object, MAX_STEPS); VipsInterpretation interpretation; /* Verify that all input args have been set. */ if (VIPS_OBJECT_CLASS(vips_colourspace_parent_class)->build(object)) return -1; x = colourspace->in; /* Unpack radiance-coded images. We can't use interpretation for this, * since rad images can be scRGB or XYZ. */ if (x->Coding == VIPS_CODING_RAD) { if (vips_rad2float(x, &t[0], NULL)) return -1; x = t[0]; } if (vips_object_argument_isset(object, "source_space")) interpretation = colourspace->source_space; else interpretation = vips_image_guess_interpretation(x); /* Treat RGB as sRGB. If you want some other treatment, * you'll need to use the icc funcs. */ if (interpretation == VIPS_INTERPRETATION_RGB) interpretation = VIPS_INTERPRETATION_sRGB; /* Treat MATRIX as B_W. */ if (interpretation == VIPS_INTERPRETATION_MATRIX) interpretation = VIPS_INTERPRETATION_B_W; for (i = 0; i < VIPS_NUMBER(vips_colour_routes); i++) if (vips_colour_routes[i].from == interpretation && vips_colour_routes[i].to == colourspace->space) break; if (i == VIPS_NUMBER(vips_colour_routes)) { vips_error("vips_colourspace", _("no known route from '%s' to '%s'"), vips_enum_nick(VIPS_TYPE_INTERPRETATION, interpretation), vips_enum_nick(VIPS_TYPE_INTERPRETATION, colourspace->space)); return -1; } for (j = 0; vips_colour_routes[i].route[j]; j++) { if (vips_colour_routes[i].route[j](x, &pipe[j], NULL)) return -1; x = pipe[j]; } g_object_set(colourspace, "out", vips_image_new(), NULL); if (vips_image_write(x, colourspace->out)) return -1; return 0; } static void vips_colourspace_class_init(VipsColourspaceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "colourspace"; vobject_class->description = _("convert to a new colorspace"); vobject_class->build = vips_colourspace_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourspace, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsColourspace, out)); VIPS_ARG_ENUM(class, "space", 6, _("Space"), _("Destination color space"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourspace, space), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB); VIPS_ARG_ENUM(class, "source_space", 6, _("Source space"), _("Source color space"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsColourspace, source_space), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB); } static void vips_colourspace_init(VipsColourspace *colourspace) { colourspace->source_space = VIPS_INTERPRETATION_sRGB; } /** * vips_colourspace: (method) * @in: input image * @out: (out): output image * @space: convert to this colour space * @...: `NULL`-terminated list of optional named arguments * * This operation looks at the interpretation field of @in (or uses * @source_space, if set) and runs * a set of colourspace conversion functions to move it to @space. * * For example, given an image tagged as [enum@Vips.Interpretation.YXY], running * [method@Image.colourspace] with @space set to * [enum@Vips.Interpretation.LAB] will convert with [method@Image.Yxy2XYZ] * and [method@Image.XYZ2Lab]. * * ::: tip "Optional arguments" * * @source_space: [enum@Interpretation], input colour space * * ::: seealso * [method@Image.colourspace_issupported], * [method@Image.guess_interpretation]. * * Returns: 0 on success, -1 on error. */ int vips_colourspace(VipsImage *in, VipsImage **out, VipsInterpretation space, ...) { va_list ap; int result; va_start(ap, space); result = vips_call_split("colourspace", ap, in, out, space); va_end(ap); return result; } libvips-8.18.2/libvips/colour/dE00.c000066400000000000000000000141501516303661500171000ustar00rootroot00000000000000/* dE00.c * * Modified: * 31/10/12 * - from dE76.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef struct _VipsdE00 { VipsColourDifference parent_instance; } VipsdE00; typedef VipsColourDifferenceClass VipsdE00Class; G_DEFINE_TYPE(VipsdE00, vips_dE00, VIPS_TYPE_COLOUR_DIFFERENCE); /** * vips_col_dE00: * @L1: Input coordinate 1 * @a1: Input coordinate 1 * @b1: Input coordinate 1 * @L2: Input coordinate 2 * @a2: Input coordinate 2 * @b2: Input coordinate 2 * * CIEDE2000, from: * * Luo, Cui, Rigg, "The Development of the CIE 2000 Colour-Difference * Formula: CIEDE2000", COLOR research and application, pp 340 * * Returns: CIE dE2000 colour difference. */ float vips_col_dE00(float L1, float a1, float b1, float L2, float a2, float b2) { /* Code if you want XYZ params and the colour temp used in the reference float vips_col_dE00(float X1, float Y1, float Z1, float X2, float Y2, float Z2) { const double X0 = 94.811; const double Y0 = 100.0; const double Z0 = 107.304; #define f(I) ((I) > 0.008856 \ ? cbrt((I), 1.0 / 3.0) \ : 7.7871 * (I) + (16.0 / 116.0)) double nX1 = f(X1 / X0); double nY1 = f(Y1 / Y0); double nZ1 = f(Z1 / Z0); double L1 = 116 * nY1 - 16; double a1 = 500 * (nX1 - nY1); double b1 = 200 * (nY1 - nZ1); double nX2 = f(X2 / X0); double nY2 = f(Y2 / Y0); double nZ2 = f(Z2 / Z0); double L2 = 116 * nY2 - 16; double a2 = 500 * (nX2 - nY2); double b2 = 200 * (nY2 - nZ2); */ /* Chroma and mean chroma (C bar) */ double C1 = sqrt(a1 * a1 + b1 * b1); double C2 = sqrt(a2 * a2 + b2 * b2); double Cb = (C1 + C2) / 2; /* G */ double Cb7 = Cb * Cb * Cb * Cb * Cb * Cb * Cb; double G = 0.5 * (1 - sqrt(Cb7 / (Cb7 + pow(25, 7)))); /* L', a', b', C', h' */ double L1d = L1; double a1d = (1 + G) * a1; double b1d = b1; double C1d = sqrt(a1d * a1d + b1d * b1d); double h1d = vips_col_ab2h(a1d, b1d); double L2d = L2; double a2d = (1 + G) * a2; double b2d = b2; double C2d = sqrt(a2d * a2d + b2d * b2d); double h2d = vips_col_ab2h(a2d, b2d); /* L' bar, C' bar, h' bar */ double Ldb = (L1d + L2d) / 2; double Cdb = (C1d + C2d) / 2; double hdb = fabs(h1d - h2d) < 180 ? (h1d + h2d) / 2 : fabs(h1d + h2d - 360) / 2; /* dtheta, RC */ double hdbd = (hdb - 275) / 25; double dtheta = 30 * exp(-(hdbd * hdbd)); double Cdb7 = Cdb * Cdb * Cdb * Cdb * Cdb * Cdb * Cdb; double RC = 2 * sqrt(Cdb7 / (Cdb7 + pow(25, 7))); /* RT, T. */ double RT = -sin(VIPS_RAD(2 * dtheta)) * RC; double T = 1 - 0.17 * cos(VIPS_RAD(hdb - 30)) + 0.24 * cos(VIPS_RAD(2 * hdb)) + 0.32 * cos(VIPS_RAD(3 * hdb + 6)) - 0.20 * cos(VIPS_RAD(4 * hdb - 63)); /* SL, SC, SH */ double Ldb50 = Ldb - 50; double SL = 1 + (0.015 * Ldb50 * Ldb50) / sqrt(20 + Ldb50 * Ldb50); double SC = 1 + 0.045 * Cdb; double SH = 1 + 0.015 * Cdb * T; /* hue difference ... careful! */ double dhd = fabs(h1d - h2d) < 180 ? h1d - h2d : 360 - (h1d - h2d); /* dLd, dCd dHd */ double dLd = L1d - L2d; double dCd = C1d - C2d; double dHd = 2 * sqrt(C1d * C2d) * sin(VIPS_RAD(dhd / 2)); /* Parametric factors for viewing parameters. */ const double kL = 1.0; const double kC = 1.0; const double kH = 1.0; /* Normalised terms. */ double nL = dLd / (kL * SL); double nC = dCd / (kC * SC); double nH = dHd / (kH * SH); /* dE00!! */ double dE00 = sqrt(nL * nL + nC * nC + nH * nH + RT * nC * nH); /* printf("X1 = %g, Y1 = %g, Z1 = %g\n", X1, Y1, Z1); printf("X2 = %g, Y2 = %g, Z2 = %g\n", X2, Y2, Z2); printf("L1 = %g, a1 = %g, b1 = %g\n", L1, a1, b1); printf("L2 = %g, a2 = %g, b2 = %g\n", L2, a2, b2); printf("L1d = %g, a1d = %g, b1d = %g, C1d = %g, h1d = %g\n", L1d, a1d, b1d, C1d, h1d); printf("L2d = %g, a2d = %g, b2d = %g, C2d = %g, h2d = %g\n", L2d, a2d, b2d, C2d, h2d); printf("G = %g, T = %g, SL = %g, SC = %g, SH = %g, RT = %g\n", G, T, SL, SC, SH, RT); printf("dE00 = %g\n", dE00); */ return dE00; } /* Find the difference between two buffers of LAB data. */ static void vips_dE00_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *p1 = (float *) in[0]; float *p2 = (float *) in[1]; float *q = (float *) out; int x; for (x = 0; x < width; x++) { q[x] = vips_col_dE00(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]); p1 += 3; p2 += 3; } } static void vips_dE00_class_init(VipsdE00Class *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "dE00"; object_class->description = _("calculate dE00"); colour_class->process_line = vips_dE00_line; } static void vips_dE00_init(VipsdE00 *dE00) { VipsColourDifference *difference = VIPS_COLOUR_DIFFERENCE(dE00); difference->interpretation = VIPS_INTERPRETATION_LAB; } /** * vips_dE00: (method) * @left: first input image * @right: second input image * @out: output image * @...: `NULL`-terminated list of optional named arguments * * Calculate dE 00. * * Returns: 0 on success, -1 on error */ int vips_dE00(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("dE00", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/dE76.c000066400000000000000000000062431516303661500171210ustar00rootroot00000000000000/* dE76.c * * Modified: * 16/11/94 JC * - partialed! * 31/10/09 * - use im__colour_binary() * - gtkdoc comment * 25/10/12 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef struct _VipsdE76 { VipsColourDifference parent_instance; } VipsdE76; typedef VipsColourDifferenceClass VipsdE76Class; G_DEFINE_TYPE(VipsdE76, vips_dE76, VIPS_TYPE_COLOUR_DIFFERENCE); /** * vips_pythagoras: * @L1: Input coordinate 1 * @a1: Input coordinate 1 * @b1: Input coordinate 1 * @L2: Input coordinate 2 * @a2: Input coordinate 2 * @b2: Input coordinate 2 * * Pythagorean distance between two points in colour space. Lab/XYZ/CMC etc. */ float vips_pythagoras(float L1, float a1, float b1, float L2, float a2, float b2) { float dL = L1 - L2; float da = a1 - a2; float db = b1 - b2; return sqrtf(dL * dL + da * da + db * db); } /* Find the difference between two buffers of LAB data. */ void vips__pythagoras_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p1 = (float *) in[0]; float *restrict p2 = (float *) in[1]; float *restrict q = (float *) out; int x; for (x = 0; x < width; x++) { float dL = p1[0] - p2[0]; float da = p1[1] - p2[1]; float db = p1[2] - p2[2]; q[x] = sqrtf(dL * dL + da * da + db * db); p1 += 3; p2 += 3; } } static void vips_dE76_class_init(VipsdE76Class *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "dE76"; object_class->description = _("calculate dE76"); colour_class->process_line = vips__pythagoras_line; } static void vips_dE76_init(VipsdE76 *dE76) { VipsColourDifference *difference = VIPS_COLOUR_DIFFERENCE(dE76); difference->interpretation = VIPS_INTERPRETATION_LAB; } /** * vips_dE76: (method) * @left: first input image * @right: second input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Calculate dE 76. * * Returns: 0 on success, -1 on error */ int vips_dE76(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("dE76", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/dECMC.c000066400000000000000000000050161516303661500172640ustar00rootroot00000000000000/* dECMC.c * * Modified: * 31/10/12 * - from dE76.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pcolour.h" typedef struct _VipsdECMC { VipsColourDifference parent_instance; } VipsdECMC; typedef VipsColourDifferenceClass VipsdECMCClass; G_DEFINE_TYPE(VipsdECMC, vips_dECMC, VIPS_TYPE_COLOUR_DIFFERENCE); static void vips_dECMC_class_init(VipsdECMCClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "dECMC"; object_class->description = _("calculate dECMC"); colour_class->process_line = vips__pythagoras_line; } static void vips_dECMC_init(VipsdECMC *dECMC) { VipsColourDifference *difference = VIPS_COLOUR_DIFFERENCE(dECMC); difference->interpretation = VIPS_INTERPRETATION_CMC; } /** * vips_dECMC: (method) * @left: first input image * @right: second input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Calculate dE CMC. The input images are transformed to CMC colour space and * the euclidean distance between corresponding pixels calculated. * * To calculate a colour difference with values for (l:c) other than (1:1), * transform the two source images to CMC yourself, scale the channels * appropriately, and call this function. * * ::: seealso * [method@Image.colourspace] * * Returns: 0 on success, -1 on error */ int vips_dECMC(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("dECMC", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/float2rad.c000066400000000000000000000160271516303661500202730ustar00rootroot00000000000000/* Convert float to Radiance 32bit packed format * * 23/3/09 * - from im_rad2float and Radiance sources * 2/11/09 * - gtkdoc * 20/9/12 * - redo as a class * 13/12/12 * - tag as scRGB rather than XYZ */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Sections of this file from Greg Ward and Radiance with kind permission. The Radience copyright notice appears below. */ /* ==================================================================== * The Radiance Software License, Version 1.0 * * Copyright (c) 1990 - 2009 The Regents of the University of California, * through Lawrence Berkeley National Laboratory. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes Radiance software * (http://radsite.lbl.gov/) * developed by the Lawrence Berkeley National Laboratory * (http://www.lbl.gov/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Radiance," "Lawrence Berkeley National Laboratory" * and "The Regents of the University of California" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact radiance@radsite.lbl.gov. * * 5. Products derived from this software may not be called "Radiance", * nor may "Radiance" appear in their name, without prior written * permission of Lawrence Berkeley National Laboratory. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of Lawrence Berkeley National Laboratory. For more * information on Lawrence Berkeley National Laboratory, please see * . */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" /* Begin copy-paste from Radiance sources. */ #define RED 0 #define GRN 1 #define BLU 2 #define CIEX 0 /* or, if input is XYZ... */ #define CIEY 1 #define CIEZ 2 #define EXP 3 /* exponent same for either format */ #define COLXS 128 /* excess used for exponent */ #define WHT 3 /* used for RGBPRIMS type */ #undef BYTE #define BYTE unsigned char /* 8-bit unsigned integer */ typedef BYTE COLR[4]; /* red, green, blue (or X,Y,Z), exponent */ typedef float COLORV; typedef COLORV COLOR[3]; /* red, green, blue (or X,Y,Z) */ #define copycolor(c1, c2) ( \ (c1)[0] = (c2)[0], \ (c1)[1] = (c2)[1], \ (c1)[2] = (c2)[2]) /* assign a short color value */ static void setcolr(COLR clr, double r, double g, double b) { double d; int e; d = r > g ? r : g; if (b > d) d = b; if (d <= 1e-32) { clr[RED] = clr[GRN] = clr[BLU] = 0; clr[EXP] = 0; return; } d = frexp(d, &e) * 255.9999 / d; if (r > 0.0) clr[RED] = r * d; else clr[RED] = 0; if (g > 0.0) clr[GRN] = g * d; else clr[GRN] = 0; if (b > 0.0) clr[BLU] = b * d; else clr[BLU] = 0; clr[EXP] = e + COLXS; } /* End copy-paste from Radiance sources. */ typedef VipsColourCode VipsFloat2rad; typedef VipsColourCodeClass VipsFloat2radClass; G_DEFINE_TYPE(VipsFloat2rad, vips_float2rad, VIPS_TYPE_COLOUR_CODE); static void vips_float2rad_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { COLOR *inp = (COLOR *) in[0]; COLR *outbuf = (COLR *) out; while (width-- > 0) { setcolr(outbuf[0], inp[0][RED], inp[0][GRN], inp[0][BLU]); inp++; outbuf++; } } static void vips_float2rad_class_init(VipsFloat2radClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "float2rad"; object_class->description = _("transform float RGB to Radiance coding"); colour_class->process_line = vips_float2rad_line; } static void vips_float2rad_init(VipsFloat2rad *float2rad) { VipsColour *colour = VIPS_COLOUR(float2rad); VipsColourCode *code = VIPS_COLOUR_CODE(float2rad); colour->coding = VIPS_CODING_RAD; colour->interpretation = VIPS_INTERPRETATION_scRGB; colour->format = VIPS_FORMAT_UCHAR; colour->input_bands = 3; colour->bands = 4; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_FLOAT; } /** * vips_float2rad: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert a three-band float image to Radiance 32-bit packed format. * * ::: seealso * [method@Image.rad2float], [enum@Vips.Coding.RAD], [method@Image.LabQ2Lab]. * * Returns: 0 on success, -1 on error. */ int vips_float2rad(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("float2rad", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/icc_transform.c000066400000000000000000001154211516303661500212440ustar00rootroot00000000000000/* Transform images with little cms * * 26/4/02 JC * 26/8/05 * - attach profiles and intents to output images * - added im_icc_import_embedded() to import with an embedded profile * 12/5/06 * - lock around cmsDoTransform * 23/1/07 * - set RGB16 on 16-bit RGB export * 6/4/09 * - catch lcms error messages * 2/11/09 * - gtkdoc * - small cleanups * - call attach_profile() before im_wrapone() so the profile will get * written if we are wrinting to a file * 2/8/10 * - add lcms2 * 12/7/11 * - import and export cast @in to an appropriate format for you * 25/9/12 * - redo as a class * 14/5/13 * - import and export would segv on very wide images * 12/11/13 * - support XYZ as an alternative PCS * 10/9/14 * - support GRAY as an input and output space * 29/9/14 * - check input profiles for compatibility with the input image, thanks * James * 26/6/15 * - better profile sanity checking for icc import * 2/8/17 * - remove lcms1 support, it was untested * 10/10/17 * - more input profile sanity tests * 8/3/18 * - attach fallback profile on import if we used it * 28/12/18 * - remove warning messages from vips_icc_is_compatible_profile() since * they can be triggered under normal circumstances * 17/4/19 kleisauke * - better rejection of broken embedded profiles * 29/3/21 [hanssonrickard] * - add black_point_compensation */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_LCMS2 #include #include /* Has to be before VIPS to avoid nameclashes. */ #include #include #include "pcolour.h" /* Call lcms with up to this many pixels at once. */ #define PIXEL_BUFFER_SIZE (10000) /** * VipsIntent: * @VIPS_INTENT_PERCEPTUAL: perceptual rendering intent * @VIPS_INTENT_RELATIVE: relative colorimetric rendering intent * @VIPS_INTENT_SATURATION: saturation rendering intent * @VIPS_INTENT_ABSOLUTE: absolute colorimetric rendering intent * @VIPS_INTENT_AUTO: the rendering intent that the profile suggests * * The rendering intent. [enum@Vips.Intent.ABSOLUTE] is best for * scientific work, [enum@Vips.Intent.RELATIVE] is usually best for * accurate communication with other imaging libraries. */ /** * VipsPCS: * @VIPS_PCS_LAB: use CIELAB D65 as the Profile Connection Space * @VIPS_PCS_XYZ: use XYZ as the Profile Connection Space * * Pick a Profile Connection Space for [method@Image.icc_import] and * [method@Image.icc_export]. LAB is usually best, XYZ can be more convenient in some * cases. */ /** * vips_icc_present: * * VIPS can optionally be built without the ICC library. Use this function to * test for its availability. * * Returns: non-zero if the ICC library is present. */ int vips_icc_present(void) { return 1; } #define VIPS_TYPE_ICC (vips_icc_get_type()) #define VIPS_ICC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_ICC, VipsIcc)) #define VIPS_ICC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_ICC, VipsIccClass)) #define VIPS_IS_ICC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_ICC)) #define VIPS_IS_ICC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_ICC)) #define VIPS_ICC_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_ICC, VipsIccClass)) typedef struct _VipsIcc { VipsColourCode parent_instance; VipsIntent intent; VipsPCS pcs; int depth; gboolean black_point_compensation; VipsIntent selected_intent; VipsBlob *in_blob; cmsHPROFILE in_profile; VipsBlob *out_blob; cmsHPROFILE out_profile; cmsUInt32Number in_icc_format; cmsUInt32Number out_icc_format; cmsHTRANSFORM trans; gboolean non_standard_input_profile; } VipsIcc; typedef VipsColourCodeClass VipsIccClass; G_DEFINE_ABSTRACT_TYPE(VipsIcc, vips_icc, VIPS_TYPE_COLOUR_CODE); /* Error from lcms. */ static void icc_error(cmsContext context, cmsUInt32Number code, const char *text) { vips_error("VipsIcc", "%s", text); } static void vips_icc_dispose(GObject *gobject) { VipsIcc *icc = (VipsIcc *) gobject; VIPS_FREEF(cmsDeleteTransform, icc->trans); VIPS_FREEF(cmsCloseProfile, icc->in_profile); VIPS_FREEF(cmsCloseProfile, icc->out_profile); if (icc->in_blob) { vips_area_unref((VipsArea *) icc->in_blob); icc->in_blob = NULL; } if (icc->out_blob) { vips_area_unref((VipsArea *) icc->out_blob); icc->out_blob = NULL; } G_OBJECT_CLASS(vips_icc_parent_class)->dispose(gobject); } /* Is a profile just a pcs stub. */ static gboolean is_pcs(cmsHPROFILE profile) { return cmsGetColorSpace(profile) == cmsSigLabData || cmsGetColorSpace(profile) == cmsSigXYZData; } /* Info for all supported lcms profile signatures. */ typedef struct _VipsIccInfo { int signature; int bands; guint lcms_type8; guint lcms_type16; } VipsIccInfo; static VipsIccInfo vips_icc_info_table[] = { { cmsSigGrayData, 1, TYPE_GRAY_8, TYPE_GRAY_16 }, { cmsSigRgbData, 3, TYPE_RGB_8, TYPE_RGB_16 }, { cmsSigLabData, 3, TYPE_Lab_FLT, TYPE_Lab_16 }, { cmsSigXYZData, 3, TYPE_XYZ_FLT, TYPE_XYZ_16 }, { cmsSigCmykData, 4, TYPE_CMYK_8, TYPE_CMYK_16 }, { cmsSig4colorData, 4, TYPE_CMYK_8, TYPE_CMYK_16 }, { cmsSig5colorData, 5, TYPE_CMYK5_8, TYPE_CMYK5_16 }, { cmsSig6colorData, 6, TYPE_CMYK6_8, TYPE_CMYK6_16 }, { cmsSig7colorData, 7, TYPE_CMYK7_8, TYPE_CMYK7_16 }, { cmsSig8colorData, 8, TYPE_CMYK8_8, TYPE_CMYK8_16 }, { cmsSig9colorData, 9, TYPE_CMYK9_8, TYPE_CMYK9_16 }, { cmsSig10colorData, 10, TYPE_CMYK10_8, TYPE_CMYK10_16 }, { cmsSig11colorData, 11, TYPE_CMYK11_8, TYPE_CMYK11_16 }, { cmsSig12colorData, 12, TYPE_CMYK12_8, TYPE_CMYK12_16 }, }; static VipsIccInfo * vips_icc_info(int signature) { int i; for (i = 0; i < VIPS_NUMBER(vips_icc_info_table); i++) if (vips_icc_info_table[i].signature == signature) return &vips_icc_info_table[i]; return NULL; } static int vips_icc_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsColour *colour = (VipsColour *) object; VipsColourCode *code = (VipsColourCode *) object; VipsIcc *icc = (VipsIcc *) object; cmsUInt32Number flags; if (icc->depth != 8 && icc->depth != 16) { vips_error(class->nickname, "%s", _("depth must be 8 or 16")); return -1; } if (icc->in_profile && code->in) { int signature; VipsIccInfo *info; signature = cmsGetColorSpace(icc->in_profile); if (!(info = vips_icc_info(signature))) { vips_error(class->nickname, _("unimplemented input color space 0x%x"), signature); return -1; } colour->input_bands = info->bands; switch (signature) { case cmsSigGrayData: code->input_format = code->in->BandFmt == VIPS_FORMAT_USHORT ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR; icc->in_icc_format = code->in->BandFmt == VIPS_FORMAT_USHORT ? info->lcms_type16 : info->lcms_type8; break; case cmsSigRgbData: code->input_format = code->in->BandFmt == VIPS_FORMAT_USHORT ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR; icc->in_icc_format = code->in->BandFmt == VIPS_FORMAT_USHORT ? info->lcms_type16 : info->lcms_type8; break; case cmsSigLabData: code->input_format = VIPS_FORMAT_FLOAT; code->input_interpretation = VIPS_INTERPRETATION_LAB; icc->in_icc_format = info->lcms_type8; break; case cmsSigXYZData: code->input_format = VIPS_FORMAT_FLOAT; code->input_interpretation = VIPS_INTERPRETATION_XYZ; icc->in_icc_format = info->lcms_type8; break; case cmsSigCmykData: case cmsSig5colorData: case cmsSig6colorData: case cmsSig7colorData: case cmsSig8colorData: case cmsSig9colorData: case cmsSig10colorData: case cmsSig11colorData: case cmsSig12colorData: /* Treat as forms of CMYK. */ info = vips_icc_info( cmsGetColorSpace(icc->in_profile)); code->input_format = code->in->BandFmt == VIPS_FORMAT_USHORT ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR; icc->in_icc_format = code->in->BandFmt == VIPS_FORMAT_USHORT ? info->lcms_type16 : info->lcms_type8; break; default: g_assert_not_reached(); return -1; } } if (icc->out_profile) { int signature; VipsIccInfo *info; signature = cmsGetColorSpace(icc->out_profile); if (!(info = vips_icc_info(signature))) { vips_error(class->nickname, _("unimplemented output color space 0x%x"), signature); return -1; } colour->bands = info->bands; switch (signature) { case cmsSigGrayData: colour->interpretation = icc->depth == 8 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_GREY16; colour->format = icc->depth == 8 ? VIPS_FORMAT_UCHAR : VIPS_FORMAT_USHORT; icc->out_icc_format = icc->depth == 16 ? info->lcms_type16 : info->lcms_type8; break; case cmsSigRgbData: colour->interpretation = icc->depth == 8 ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16; colour->format = icc->depth == 8 ? VIPS_FORMAT_UCHAR : VIPS_FORMAT_USHORT; icc->out_icc_format = icc->depth == 16 ? info->lcms_type16 : info->lcms_type8; break; case cmsSigLabData: colour->interpretation = VIPS_INTERPRETATION_LAB; colour->format = VIPS_FORMAT_FLOAT; icc->out_icc_format = info->lcms_type16; break; case cmsSigXYZData: colour->interpretation = VIPS_INTERPRETATION_XYZ; colour->format = VIPS_FORMAT_FLOAT; icc->out_icc_format = info->lcms_type16; break; case cmsSigCmykData: case cmsSig5colorData: case cmsSig6colorData: case cmsSig7colorData: case cmsSig8colorData: case cmsSig9colorData: case cmsSig10colorData: case cmsSig11colorData: case cmsSig12colorData: /* Treat as forms of CMYK. */ colour->interpretation = VIPS_INTERPRETATION_CMYK; colour->format = icc->depth == 8 ? VIPS_FORMAT_UCHAR : VIPS_FORMAT_USHORT; icc->out_icc_format = icc->depth == 16 ? info->lcms_type16 : info->lcms_type8; break; default: g_assert_not_reached(); return -1; } } /* At least one must be a device profile. */ if (icc->in_profile && icc->out_profile && is_pcs(icc->in_profile) && is_pcs(icc->out_profile)) { vips_error(class->nickname, "%s", _("no device profile")); return -1; } /* Use cmsFLAGS_NOCACHE to disable the 1-pixel cache and make * calling cmsDoTransform() from multiple threads safe. */ flags = cmsFLAGS_NOCACHE; if (icc->black_point_compensation) flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; if (!(icc->trans = cmsCreateTransform( icc->in_profile, icc->in_icc_format, icc->out_profile, icc->out_icc_format, icc->selected_intent, flags))) return -1; if (VIPS_OBJECT_CLASS(vips_icc_parent_class)->build(object)) return -1; return 0; } /* Get from an image. */ static VipsBlob * vips_icc_get_profile_image(VipsImage *image) { const void *data; size_t size; if (!vips_image_get_typeof(image, VIPS_META_ICC_NAME)) return NULL; if (vips_image_get_blob(image, VIPS_META_ICC_NAME, &data, &size)) return NULL; return vips_blob_new(NULL, data, size); } #ifdef DEBUG static void vips_icc_print_profile(const char *name, cmsHPROFILE profile) { static const cmsInfoType info_types[] = { cmsInfoDescription, cmsInfoManufacturer, cmsInfoModel, cmsInfoCopyright }; static const char *info_names[] = { "description", "manufacturer", "model", "copyright" }; int i; cmsUInt32Number n_bytes; cmsUInt32Number n_intents; cmsUInt32Number *intent_codes; char **intent_descriptions; printf("icc profile %s: %p\n", name, profile); for (i = 0; i < VIPS_NUMBER(info_types); i++) { if ((n_bytes = cmsGetProfileInfoASCII(profile, info_types[i], "en", "US", NULL, 0))) { char *buffer; buffer = VIPS_ARRAY(NULL, n_bytes, char); (void) cmsGetProfileInfoASCII(profile, info_types[i], "en", "US", buffer, n_bytes); printf("%s: %s\n", info_names[i], buffer); g_free(buffer); } } printf("intent: %d\n", cmsGetHeaderRenderingIntent(profile)); printf("profile class: %#x\n", cmsGetDeviceClass(profile)); { cmsColorSpaceSignature pcs = cmsGetPCS(profile); guint pcs_as_be = GUINT_TO_BE(pcs); char name[5]; g_strlcpy(name, (const char *) &pcs_as_be, 5); printf("PCS: %#x (%s)\n", pcs, name); } printf("matrix shaper: %d\n", cmsIsMatrixShaper(profile)); printf("version: %g\n", cmsGetProfileVersion(profile)); n_intents = cmsGetSupportedIntents(0, NULL, NULL); printf("n_intents = %u\n", n_intents); intent_codes = VIPS_ARRAY(NULL, n_intents, cmsUInt32Number); intent_descriptions = VIPS_ARRAY(NULL, n_intents, char *); (void) cmsGetSupportedIntents(n_intents, intent_codes, intent_descriptions); for (i = 0; i < n_intents; i++) { printf(" %#x: %s, in CLUT = %d, out CLUT = %d\n", intent_codes[i], intent_descriptions[i], cmsIsCLUT(profile, intent_codes[i], LCMS_USED_AS_INPUT), cmsIsCLUT(profile, intent_codes[i], LCMS_USED_AS_OUTPUT)); } g_free(intent_codes); g_free(intent_descriptions); } #endif /*DEBUG*/ /* TRUE if the number of bands in the ICC profile is compatible with the * image. */ static gboolean vips_image_is_profile_compatible(VipsImage *image, int profile_bands) { int bands = vips_interpretation_bands(image->Type); // CMYK can mean more than 4 bands for eg. hexachrome if (image->Type == VIPS_INTERPRETATION_CMYK) return profile_bands >= 4; if (bands > 0) return bands == profile_bands; else return image->Bands >= profile_bands; } /* Load a profile from a blob and check compatibility with image, intent and * direction. * * Don't set any errors since this is used to test compatibility. */ static cmsHPROFILE vips_icc_load_profile_blob(VipsIcc *icc, VipsBlob *blob, VipsImage *image, int direction) { const void *data; size_t size; cmsHPROFILE profile; VipsIccInfo *info; #ifdef DEBUG printf("loading %s profile, intent %s, from blob %p\n", direction == LCMS_USED_AS_INPUT ? "input" : "output", vips_enum_nick(VIPS_TYPE_INTENT, icc->intent), blob); #endif /*DEBUG*/ data = vips_blob_get(blob, &size); if (!(profile = cmsOpenProfileFromMem(data, size))) { g_warning("corrupt profile"); return NULL; } icc->selected_intent = icc->intent; if (icc->intent == VIPS_INTENT_AUTO || !cmsIsIntentSupported(profile, icc->intent, direction)) { cmsUInt32Number intent = cmsGetHeaderRenderingIntent(profile); if (intent > VIPS_INTENT_ABSOLUTE) { VIPS_FREEF(cmsCloseProfile, profile); g_warning("corrupt profile"); return NULL; } icc->selected_intent = (VipsIntent) intent; } if (icc->intent != VIPS_INTENT_AUTO && icc->selected_intent != icc->intent) g_warning("fallback to suggested %s intent, as profile " "does not support %s %s intent", vips_enum_nick(VIPS_TYPE_INTENT, icc->selected_intent), vips_enum_nick(VIPS_TYPE_INTENT, icc->intent), direction == LCMS_USED_AS_INPUT ? "input" : "output"); #ifdef DEBUG vips_icc_print_profile("loaded from blob to make", profile); #endif /*DEBUG*/ if (!(info = vips_icc_info(cmsGetColorSpace(profile)))) { VIPS_FREEF(cmsCloseProfile, profile); g_warning("unsupported profile"); return NULL; } if (image && !vips_image_is_profile_compatible(image, info->bands)) { VIPS_FREEF(cmsCloseProfile, profile); g_warning("profile incompatible with image"); return NULL; } if (!cmsIsIntentSupported(profile, icc->selected_intent, direction)) { VIPS_FREEF(cmsCloseProfile, profile); g_warning("profile does not support %s %s intent", vips_enum_nick(VIPS_TYPE_INTENT, icc->selected_intent), direction == LCMS_USED_AS_INPUT ? "input" : "output"); return NULL; } return profile; } /* Verify that a blob is not corrupt and is compatible with this image. * * unref the blob if it's useless. */ static cmsHPROFILE vips_icc_verify_blob(VipsIcc *icc, VipsBlob **blob) { if (*blob) { VipsColourCode *code = (VipsColourCode *) icc; cmsHPROFILE profile = vips_icc_load_profile_blob(icc, *blob, code->in, LCMS_USED_AS_INPUT); if (!profile) { vips_area_unref((VipsArea *) *blob); *blob = NULL; } return profile; } return NULL; } /* Try to set the import profile. We read the input profile like this: * * | embedded | filename | action | * |----------|----------|-------------------------------| * | 0 | 0 | image | * | 1 | 0 | image | * | 0 | 1 | file | * | 1 | 1 | image, then fall back to file | * * If averything fails, we fall back to one of our built-in profiles, * depending on the input image. * * We set attach_input_profile if we used a non-embedded profile. The profile * in in_blob will need to be attached to the output image in some way. */ static int vips_icc_set_import(VipsIcc *icc, gboolean embedded, const char *input_profile_filename) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(icc); VipsColourCode *code = (VipsColourCode *) icc; icc->non_standard_input_profile = FALSE; /* Try embedded profile. */ if (code->in && (embedded || !input_profile_filename)) { icc->in_blob = vips_icc_get_profile_image(code->in); icc->in_profile = vips_icc_verify_blob(icc, &icc->in_blob); } /* Try profile from filename. */ if (code->in && !icc->in_blob && input_profile_filename) { if (!vips_profile_load(input_profile_filename, &icc->in_blob, NULL) && (icc->in_profile = vips_icc_verify_blob(icc, &icc->in_blob))) icc->non_standard_input_profile = TRUE; } /* Try a built-in profile. */ if (code->in && !icc->in_profile) { const char *name; switch (code->in->Type) { case VIPS_INTERPRETATION_B_W: case VIPS_INTERPRETATION_GREY16: name = "sgrey"; break; case VIPS_INTERPRETATION_CMYK: name = "cmyk"; break; default: name = "srgb"; break; } if (!vips_profile_load(name, &icc->in_blob, NULL) && (icc->in_profile = vips_icc_verify_blob(icc, &icc->in_blob))) icc->non_standard_input_profile = TRUE; } if (!icc->in_profile) { vips_error(class->nickname, "%s", _("unable to load or find any compatible input profile")); return -1; } return 0; } static void vips_icc_class_init(VipsIccClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->dispose = vips_icc_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "icc"; object_class->description = _("transform using ICC profiles"); object_class->build = vips_icc_build; VIPS_ARG_ENUM(class, "intent", 6, _("Intent"), _("Rendering intent"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIcc, intent), VIPS_TYPE_INTENT, VIPS_INTENT_RELATIVE); VIPS_ARG_ENUM(class, "pcs", 6, _("PCS"), _("Set Profile Connection Space"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIcc, pcs), VIPS_TYPE_PCS, VIPS_PCS_LAB); VIPS_ARG_BOOL(class, "black_point_compensation", 7, _("Black point compensation"), _("Enable black point compensation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIcc, black_point_compensation), FALSE); cmsSetLogErrorHandler(icc_error); } static void vips_icc_init(VipsIcc *icc) { icc->intent = VIPS_INTENT_RELATIVE; icc->pcs = VIPS_PCS_LAB; icc->depth = 8; } typedef struct _VipsIccImport { VipsIcc parent_instance; gboolean embedded; char *input_profile_filename; } VipsIccImport; typedef VipsIccClass VipsIccImportClass; G_DEFINE_TYPE(VipsIccImport, vips_icc_import, VIPS_TYPE_ICC); static int vips_icc_import_build(VipsObject *object) { VipsColour *colour = (VipsColour *) object; VipsIcc *icc = (VipsIcc *) object; VipsIccImport *import = (VipsIccImport *) object; if (vips_icc_set_import(icc, import->embedded, import->input_profile_filename)) return -1; if (icc->pcs == VIPS_PCS_LAB) { cmsCIExyY white; cmsWhitePointFromTemp(&white, 6504); icc->out_profile = cmsCreateLab4Profile(&white); } else icc->out_profile = cmsCreateXYZProfile(); if (VIPS_OBJECT_CLASS(vips_icc_import_parent_class)->build(object)) return -1; /* If we used the fallback profile, we need to attach it to the PCS * image, since the PCS image needs a route back to device space. * * In the same way, we don't remove the embedded input profile on * import. */ if (icc->non_standard_input_profile && icc->in_blob) { const void *data; size_t size; data = vips_blob_get(icc->in_blob, &size); vips_image_set_blob(colour->out, VIPS_META_ICC_NAME, NULL, data, size); } return 0; } static void decode_lab(guint16 *fixed, float *lab, int n) { int i; for (i = 0; i < n; i++) { /* cmsLabEncoded2Float inlined. */ lab[0] = (double) fixed[0] / 655.35; lab[1] = ((double) fixed[1] / 257.0) - 128.0; lab[2] = ((double) fixed[2] / 257.0) - 128.0; lab += 3; fixed += 3; } } /* The matrix already includes the D65 channel weighting, so we just scale by * Y. */ #define SCALE (VIPS_D65_Y0) static void decode_xyz(guint16 *fixed, float *xyz, int n) { int i; for (i = 0; i < n; i++) { /* cmsXYZEncoded2Float inlined. */ float X = fixed[0] / 32768.0; float Y = fixed[1] / 32768.0; float Z = fixed[2] / 32768.0; X *= SCALE; Y *= SCALE; Z *= SCALE; /* Transform XYZ D50 to D65, chromatic adaption is done with the * Bradford transformation. See: * https://fujiwaratko.sakura.ne.jp/infosci/colorspace/bradford_e.html */ xyz[0] = 0.955513F * X + -0.023073F * Y + 0.063309F * Z; xyz[1] = -0.028325F * X + 1.009942F * Y + 0.021055F * Z; xyz[2] = 0.012329F * X + -0.020536F * Y + 1.330714F * Z; xyz += 3; fixed += 3; } } /* Process a buffer of data. */ static void vips_icc_import_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsIcc *icc = (VipsIcc *) colour; VipsPel *p; float *q; int i; /* Transform to PCS pixels here. */ guint16 encoded[3 * PIXEL_BUFFER_SIZE]; p = (VipsPel *) in[0]; q = (float *) out; for (i = 0; i < width; i += PIXEL_BUFFER_SIZE) { const int chunk = VIPS_MIN(width - i, PIXEL_BUFFER_SIZE); cmsDoTransform(icc->trans, p, encoded, chunk); if (icc->pcs == VIPS_PCS_LAB) decode_lab(encoded, q, chunk); else decode_xyz(encoded, q, chunk); // use input_bands, since in[0] may have had alpha removed, // and can have 1, 3 or 4 bands p += PIXEL_BUFFER_SIZE * colour->input_bands * VIPS_IMAGE_SIZEOF_ELEMENT(colour->in[0]); q += PIXEL_BUFFER_SIZE * 3; } } static void vips_icc_import_class_init(VipsIccImportClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "icc_import"; object_class->description = _("import from device with ICC profile"); object_class->build = vips_icc_import_build; colour_class->process_line = vips_icc_import_line; VIPS_ARG_BOOL(class, "embedded", 110, _("Embedded"), _("Use embedded input profile, if available"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIccImport, embedded), FALSE); VIPS_ARG_STRING(class, "input_profile", 120, _("Input profile"), _("Filename to load input profile from"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIccImport, input_profile_filename), NULL); } static void vips_icc_import_init(VipsIccImport *import) { } typedef struct _VipsIccExport { VipsIcc parent_instance; char *output_profile_filename; } VipsIccExport; typedef VipsIccClass VipsIccExportClass; G_DEFINE_TYPE(VipsIccExport, vips_icc_export, VIPS_TYPE_ICC); static int vips_icc_export_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsColour *colour = (VipsColour *) object; VipsColourCode *code = (VipsColourCode *) object; VipsIcc *icc = (VipsIcc *) object; VipsIccExport *export = (VipsIccExport *) object; /* If icc->pcs hasn't been set and this image is tagged as XYZ, swap * to XYZ pcs. This will save a XYZ->LAB conversion when we chain up. */ if (!vips_object_argument_isset(object, "pcs") && code->in && code->in->Type == VIPS_INTERPRETATION_XYZ) icc->pcs = VIPS_PCS_XYZ; // FIXME: Invalidates operation cache if (icc->pcs == VIPS_PCS_LAB) { cmsCIExyY white; cmsWhitePointFromTemp(&white, 6504); icc->in_profile = cmsCreateLab4Profile(&white); } else icc->in_profile = cmsCreateXYZProfile(); if (code->in && !export->output_profile_filename) icc->out_blob = vips_icc_get_profile_image(code->in); if (!icc->out_blob && export->output_profile_filename) { if (vips_profile_load(export->output_profile_filename, &icc->out_blob, NULL)) return -1; colour->profile_filename = export->output_profile_filename; } if (icc->out_blob && !(icc->out_profile = vips_icc_load_profile_blob(icc, icc->out_blob, NULL, LCMS_USED_AS_OUTPUT))) { vips_error(class->nickname, "%s", _("no output profile")); return -1; } if (VIPS_OBJECT_CLASS(vips_icc_export_parent_class)->build(object)) return -1; return 0; } static void encode_xyz(float *in, float *out, int n) { int i; for (i = 0; i < n; i++) { float X = in[0] / SCALE; float Y = in[1] / SCALE; float Z = in[2] / SCALE; /* Transform XYZ D65 to D50, chromatic adaption is done with the * Bradford transformation. See: * https://fujiwaratko.sakura.ne.jp/infosci/colorspace/bradford_e.html */ out[0] = 1.047886F * X + 0.022919F * Y + -0.050216F * Z; out[1] = 0.029582F * X + 0.990484F * Y + -0.017079F * Z; out[2] = -0.009252F * X + 0.015073F * Y + 0.751678F * Z; in += 3; out += 3; } } static void vips_icc_export_line_xyz(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsIcc *icc = (VipsIcc *) colour; float *p; VipsPel *q; int x; /* Buffer of PCS pixels we transform to device space. */ float encoded[3 * PIXEL_BUFFER_SIZE]; p = (float *) in[0]; q = (VipsPel *) out; for (x = 0; x < width; x += PIXEL_BUFFER_SIZE) { const int chunk = VIPS_MIN(width - x, PIXEL_BUFFER_SIZE); encode_xyz(p, encoded, chunk); cmsDoTransform(icc->trans, encoded, q, chunk); p += PIXEL_BUFFER_SIZE * 3; // use colour->bands, since out may have had alpha reattached // and can have extra bands q += PIXEL_BUFFER_SIZE * colour->bands * VIPS_IMAGE_SIZEOF_ELEMENT(colour->out); } } /* Process a buffer of data. */ static void vips_icc_export_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsIcc *icc = (VipsIcc *) colour; if (icc->pcs == VIPS_PCS_LAB) cmsDoTransform(icc->trans, in[0], out, width); else vips_icc_export_line_xyz(colour, out, in, width); } static void vips_icc_export_class_init(VipsIccExportClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "icc_export"; object_class->description = _("output to device with ICC profile"); object_class->build = vips_icc_export_build; colour_class->process_line = vips_icc_export_line; VIPS_ARG_STRING(class, "output_profile", 110, _("Output profile"), _("Filename to load output profile from"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIccExport, output_profile_filename), NULL); VIPS_ARG_INT(class, "depth", 130, _("Depth"), _("Output device space depth in bits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIcc, depth), 8, 16, 8); } static void vips_icc_export_init(VipsIccExport *export) { } typedef struct _VipsIccTransform { VipsIcc parent_instance; gboolean embedded; char *input_profile_filename; char *output_profile_filename; } VipsIccTransform; typedef VipsIccClass VipsIccTransformClass; G_DEFINE_TYPE(VipsIccTransform, vips_icc_transform, VIPS_TYPE_ICC); static int vips_icc_transform_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsColour *colour = (VipsColour *) object; VipsColourCode *code = (VipsColourCode *) object; VipsIcc *icc = (VipsIcc *) object; VipsIccTransform *transform = (VipsIccTransform *) object; /* Depth defaults to 16 for 16 bit images. */ if (!vips_object_argument_isset(object, "depth") && code->in && (code->in->Type == VIPS_INTERPRETATION_RGB16 || code->in->Type == VIPS_INTERPRETATION_GREY16)) icc->depth = 16; // FIXME: Invalidates operation cache if (vips_icc_set_import(icc, transform->embedded, transform->input_profile_filename)) return -1; if (transform->output_profile_filename) { if (vips_profile_load(transform->output_profile_filename, &icc->out_blob, NULL)) return -1; colour->profile_filename = transform->output_profile_filename; } if (icc->out_blob) icc->out_profile = vips_icc_load_profile_blob(icc, icc->out_blob, NULL, LCMS_USED_AS_OUTPUT); if (!icc->out_profile) { vips_error(class->nickname, "%s", _("no output profile")); return -1; } if (VIPS_OBJECT_CLASS(vips_icc_transform_parent_class)->build(object)) return -1; return 0; } /* Process a buffer of data. */ static void vips_icc_transform_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsIcc *icc = (VipsIcc *) colour; cmsDoTransform(icc->trans, in[0], out, width); } static void vips_icc_transform_class_init(VipsIccImportClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "icc_transform"; object_class->description = _("transform between devices with ICC profiles"); object_class->build = vips_icc_transform_build; colour_class->process_line = vips_icc_transform_line; VIPS_ARG_STRING(class, "output_profile", 110, _("Output profile"), _("Filename to load output profile from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsIccTransform, output_profile_filename), NULL); VIPS_ARG_BOOL(class, "embedded", 120, _("Embedded"), _("Use embedded input profile, if available"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIccTransform, embedded), FALSE); VIPS_ARG_STRING(class, "input_profile", 130, _("Input profile"), _("Filename to load input profile from"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIccTransform, input_profile_filename), NULL); VIPS_ARG_INT(class, "depth", 140, _("Depth"), _("Output device space depth in bits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIcc, depth), 8, 16, 8); } static void vips_icc_transform_init(VipsIccTransform *transform) { } /** * vips_icc_ac2rc: (method) * @in: input image * @out: (out): output image * @profile_filename: use this profile * * Transform an image from absolute to relative colorimetry using the * MediaWhitePoint stored in the ICC profile. * * ::: seealso * [method@Image.icc_transform], [method@Image.icc_import]. * * Returns: 0 on success, -1 on error. */ int vips_icc_ac2rc(VipsImage *in, VipsImage **out, const char *profile_filename) { VipsImage *t; cmsHPROFILE profile; cmsCIEXYZ *media; double X, Y, Z; double *add; double *mul; int i; #ifdef G_OS_WIN32 if (!(profile = cmsOpenProfileFromFile(profile_filename, "r"))) #else /*!G_OS_WIN32*/ if (!(profile = cmsOpenProfileFromFile(profile_filename, "re"))) #endif /*G_OS_WIN32*/ return -1; #ifdef DEBUG vips_icc_print_profile(profile_filename, profile); #endif /*DEBUG*/ if (!(media = cmsReadTag(profile, cmsSigMediaWhitePointTag))) { vips_error("vips_icc_ac2rc", "%s", _("unable to get media white point")); return -1; } X = media->X; Y = media->Y; Z = media->Z; cmsCloseProfile(profile); /* We need XYZ so we can adjust the white balance. */ if (vips_colourspace(in, &t, VIPS_INTERPRETATION_XYZ, NULL)) return -1; in = t; if (!(add = VIPS_ARRAY(in, in->Bands, double)) || !(mul = VIPS_ARRAY(in, in->Bands, double))) return -1; /* There might be extra bands off to the right somewhere. */ for (i = 0; i < in->Bands; i++) add[i] = 0.0; mul[0] = VIPS_D50_X0 / (X * 100.0); mul[1] = VIPS_D50_Y0 / (Y * 100.0); mul[2] = VIPS_D50_Z0 / (Z * 100.0); for (i = 3; i < in->Bands; i++) mul[i] = 1.0; if (vips_linear(in, &t, add, mul, in->Bands, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = t; *out = in; return 0; } /* TRUE if a profile is sane and is compatible with an image. */ gboolean vips_icc_is_compatible_profile(VipsImage *image, const void *data, size_t data_length) { cmsHPROFILE profile; VipsIccInfo *info; if (!(profile = cmsOpenProfileFromMem(data, data_length))) /* Corrupt profile. */ return FALSE; #ifdef DEBUG vips_icc_print_profile("from memory", profile); #endif /*DEBUG*/ if (!(info = vips_icc_info(cmsGetColorSpace(profile)))) { /* Unsupported profile. */ VIPS_FREEF(cmsCloseProfile, profile); return FALSE; } if (!vips_image_is_profile_compatible(image, info->bands)) { /* Bands mismatch. */ VIPS_FREEF(cmsCloseProfile, profile); return FALSE; } VIPS_FREEF(cmsCloseProfile, profile); return TRUE; } #else /*!HAVE_LCMS2*/ #include int vips_icc_present(void) { return 0; } int vips_icc_ac2rc(VipsImage *in, VipsImage **out, const char *profile_filename) { vips_error("VipsIcc", "%s", _("libvips configured without lcms support")); return -1; } gboolean vips_icc_is_compatible_profile(VipsImage *image, const void *data, size_t data_length) { return TRUE; } #endif /*HAVE_LCMS2*/ /** * vips_icc_import: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Import an image from device space to D65 LAB with an ICC profile. * * If @pcs is set to [enum@Vips.PCS.XYZ], use CIE XYZ PCS instead. * * The input profile is searched for in three places: * * 1. If @embedded is set, libvips will try to use any profile in the input * image metadata. You can test for the presence of an embedded profile * with [method@Image.get_typeof] with [const@META_ICC_NAME] as an * argument. This will return [alias@GObject.Type] 0 if there is no profile. * * 2. Otherwise, if @input_profile is set, libvips will try to load a * profile from the named file. This can also be the name of one of the * built-in profiles. * * 3. Otherwise, libvips will try to pick a compatible profile from the set * of built-in profiles. * * If @black_point_compensation is set, LCMS black point compensation is * enabled. * * ::: tip "Optional arguments" * * @pcs: [enum@PCS], use XYZ or LAB PCS * * @intent: [enum@Intent], transform with this intent * * @black_point_compensation: `gboolean`, enable black point compensation * * @embedded: `gboolean`, use profile embedded in input image * * @input_profile: `gchararray`, get the input profile from here * * Returns: 0 on success, -1 on error. */ int vips_icc_import(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("icc_import", ap, in, out); va_end(ap); return result; } /** * vips_icc_export: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Export an image from D65 LAB to device space with an ICC profile. * * If @pcs is set to [enum@Vips.PCS.XYZ], use CIE XYZ PCS instead. * If @output_profile is not set, use the embedded profile, if any. * If @output_profile is set, export with that and attach it to the output * image. * * If @black_point_compensation is set, LCMS black point compensation is * enabled. * * ::: tip "Optional arguments" * * @pcs: [enum@PCS], use XYZ or LAB PCS * * @intent: [enum@Intent], transform with this intent * * @black_point_compensation: `gboolean`, enable black point compensation * * @output_profile: `gchararray`, get the output profile from here * * @depth: `gint`, depth of output image in bits * * Returns: 0 on success, -1 on error. */ int vips_icc_export(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("icc_export", ap, in, out); va_end(ap); return result; } /** * vips_icc_transform: (method) * @in: input image * @out: (out): output image * @output_profile: get the output profile from here * @...: `NULL`-terminated list of optional named arguments * * Transform an image with a pair of ICC profiles. * * The input image is moved to profile-connection space with the input * profile and then to the output space with the output profile. * * The input profile is searched for in three places: * * 1. If @embedded is set, libvips will try to use any profile in the input * image metadata. You can test for the presence of an embedded profile * with [method@Image.get_typeof] with [const@META_ICC_NAME] as an * argument. This will return [alias@GObject.Type] 0 if there is no profile. * * 2. Otherwise, if @input_profile is set, libvips will try to load a * profile from the named file. This can also be the name of one of the * built-in profiles. * * 3. Otherwise, libvips will try to pick a compatible profile from the set * of built-in profiles. * * If @black_point_compensation is set, LCMS black point compensation is * enabled. * * @depth defaults to 8, or 16 if @in is a 16-bit image. * * The output image has the output profile attached to the [const@META_ICC_NAME] * field. * * Use [method@Image.icc_import] and [method@Image.icc_export] to do either * the first or second half of this operation in isolation. * * ::: tip "Optional arguments" * * @pcs: [enum@PCS], use XYZ or LAB PCS * * @intent: [enum@Intent], transform with this intent * * @black_point_compensation: `gboolean`, enable black point compensation * * @embedded: `gboolean`, use profile embedded in input image * * @input_profile: `gchararray`, get the input profile from here * * @depth: `gint`, depth of output image in bits * * Returns: 0 on success, -1 on error. */ int vips_icc_transform(VipsImage *in, VipsImage **out, const char *output_profile, ...) { va_list ap; int result; va_start(ap, output_profile); result = vips_call_split("icc_transform", ap, in, out, output_profile); va_end(ap); return result; } libvips-8.18.2/libvips/colour/meson.build000066400000000000000000000017771516303661500204210ustar00rootroot00000000000000colour_sources = files( 'CMYK2XYZ.c', 'colour.c', 'colourspace.c', 'dE00.c', 'dE76.c', 'dECMC.c', 'float2rad.c', 'HSV2sRGB.c', 'icc_transform.c', 'Lab2LabQ.c', 'Lab2LabS.c', 'Lab2LCh.c', 'Lab2XYZ.c', 'LabQ2Lab.c', 'LabQ2LabS.c', 'LabQ2sRGB.c', 'LabS2Lab.c', 'LabS2LabQ.c', 'LCh2Lab.c', 'LCh2UCS.c', 'Oklab2XYZ.c', 'Oklab2Oklch.c', 'Oklch2Oklab.c', 'profile_load.c', 'profiles.c', 'rad2float.c', 'scRGB2BW.c', 'scRGB2sRGB.c', 'scRGB2XYZ.c', 'sRGB2HSV.c', 'sRGB2scRGB.c', 'uhdr2scRGB.c', 'UCS2LCh.c', 'XYZ2CMYK.c', 'XYZ2Lab.c', 'XYZ2scRGB.c', 'XYZ2Oklab.c', 'XYZ2Yxy.c', 'Yxy2XYZ.c', ) colour_headers = files( 'pcolour.h', 'profiles.h', ) libvips_sources += colour_sources colour_lib = static_library('colour', colour_sources, colour_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += colour_lib libvips-8.18.2/libvips/colour/pcolour.h000066400000000000000000000141031516303661500200760ustar00rootroot00000000000000/* base class for all colour operations */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PCOLOUR_H #define VIPS_PCOLOUR_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include #define VIPS_TYPE_COLOUR (vips_colour_get_type()) #define VIPS_COLOUR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_COLOUR, VipsColour)) #define VIPS_COLOUR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_COLOUR, VipsColourClass)) #define VIPS_IS_COLOUR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_COLOUR)) #define VIPS_IS_COLOUR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_COLOUR)) #define VIPS_COLOUR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_COLOUR, VipsColourClass)) struct _VipsColour; typedef void (*VipsColourProcessFn)(struct _VipsColour *colour, VipsPel *out, VipsPel **in, int width); typedef struct _VipsColour { VipsOperation parent_instance; /* Null-terminated array of input arguments, set these from a * subclass. */ VipsImage **in; int n; /* If this is >0, only process this many bands from the input. Extra * bands are removed and reattached after processing. */ int input_bands; VipsImage *out; /* Set fields on ->out from these. */ VipsCoding coding; VipsInterpretation interpretation; VipsBandFormat format; int bands; /* Attach this profile, if set. */ char *profile_filename; } VipsColour; typedef struct _VipsColourClass { VipsOperationClass parent_class; /* The buffer processor. */ VipsColourProcessFn process_line; } VipsColourClass; GType vips_colour_get_type(void); /* A float in, float out colourspace transformation. */ #define VIPS_TYPE_COLOUR_TRANSFORM (vips_colour_transform_get_type()) #define VIPS_COLOUR_TRANSFORM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_COLOUR_TRANSFORM, VipsColourTransform)) #define VIPS_COLOUR_TRANSFORM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_COLOUR_TRANSFORM, VipsColourTransformClass)) #define VIPS_IS_COLOUR_TRANSFORM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_COLOUR_TRANSFORM)) #define VIPS_IS_COLOUR_TRANSFORM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_COLOUR_TRANSFORM)) #define VIPS_COLOUR_TRANSFORM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_COLOUR_TRANSFORM, VipsColourTransformClass)) typedef struct _VipsColourTransform { VipsColour parent_instance; VipsImage *in; } VipsColourTransform; typedef struct _VipsColourTransformClass { VipsColourClass parent_class; } VipsColourTransformClass; GType vips_colour_transform_get_type(void); /* Change colour encoding ... either in or out is not three-band float. */ #define VIPS_TYPE_COLOUR_CODE (vips_colour_code_get_type()) #define VIPS_COLOUR_CODE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_COLOUR_CODE, VipsColourCode)) #define VIPS_COLOUR_CODE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_COLOUR_CODE, VipsColourCodeClass)) #define VIPS_IS_COLOUR_CODE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_COLOUR_CODE)) #define VIPS_IS_COLOUR_CODE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_COLOUR_CODE)) #define VIPS_COLOUR_CODE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_COLOUR_CODE, VipsColourCodeClass)) typedef struct _VipsColourCode { VipsColour parent_instance; VipsImage *in; /* Test in against these. */ VipsCoding input_coding; VipsBandFormat input_format; VipsInterpretation input_interpretation; } VipsColourCode; typedef struct _VipsColourCodeClass { VipsColourClass parent_class; } VipsColourCodeClass; GType vips_colour_code_get_type(void); /* Difference between two colour images. */ #define VIPS_TYPE_COLOUR_DIFFERENCE (vips_colour_difference_get_type()) #define VIPS_COLOUR_DIFFERENCE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_COLOUR_DIFFERENCE, VipsColourDifference)) #define VIPS_COLOUR_DIFFERENCE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_COLOUR_DIFFERENCE, VipsColourDifferenceClass)) #define VIPS_IS_COLOUR_DIFFERENCE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_COLOUR_DIFFERENCE)) #define VIPS_IS_COLOUR_DIFFERENCE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_COLOUR_DIFFERENCE)) #define VIPS_COLOUR_DIFFERENCE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_COLOUR_DIFFERENCE, VipsColourDifferenceClass)) typedef struct _VipsColourDifference { VipsColour parent_instance; VipsImage *left; VipsImage *right; /* Both get converted to this space. */ VipsInterpretation interpretation; } VipsColourDifference; typedef struct _VipsColourDifferenceClass { VipsColourClass parent_class; } VipsColourDifferenceClass; GType vips_colour_difference_get_type(void); void vips__pythagoras_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width); /* Colour tables for Y<->v conversion. Call vips_col_make_tables_RGB_8() and * vips_col_make_tables_RGB_16() before use to initialize. */ extern float vips_v2Y_8[256]; void vips_col_make_tables_RGB_8(void); /* A colour-transforming function. */ typedef int (*VipsColourTransformFn)(VipsImage *in, VipsImage **out, ...); int vips__colourspace_process_n(const char *domain, VipsImage *in, VipsImage **out, int n, VipsColourTransformFn fn); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PCOLOUR_H*/ libvips-8.18.2/libvips/colour/profile_load.c000066400000000000000000000125431516303661500210530ustar00rootroot00000000000000/* Load profiles as blobs. * * 10/1/19 * - from CMYK2XYZ.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "profiles.h" #include "pcolour.h" typedef struct _VipsProfileLoad { VipsOperation parent_instance; const char *name; VipsBlob *profile; } VipsProfileLoad; typedef VipsOperationClass VipsProfileLoadClass; G_DEFINE_TYPE(VipsProfileLoad, vips_profile_load, VIPS_TYPE_OPERATION); static const void * vips_profile_fallback_get(const char *name, size_t *length) { int i; VipsProfileFallback *fallback; for (i = 0; (fallback = vips__profile_fallback_table[i]); i++) if (g_ascii_strcasecmp(fallback->name, name) == 0) { void *data; GConverter *converter; GConverterResult res; gsize bytes_read; gsize bytes_written; data = g_malloc0(fallback->length); converter = G_CONVERTER(g_zlib_decompressor_new( G_ZLIB_COMPRESSOR_FORMAT_ZLIB)); res = g_converter_convert(converter, fallback->data, fallback->length, data, fallback->length, G_CONVERTER_INPUT_AT_END, &bytes_read, &bytes_written, NULL); g_object_unref(converter); if (res == G_CONVERTER_FINISHED) { *length = fallback->length; return data; } else { g_free(data); g_warning("fallback profile decompression failed"); } } return NULL; } static int vips_profile_load_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsProfileLoad *load = (VipsProfileLoad *) object; size_t length; const void *data; VipsBlob *profile; if (VIPS_OBJECT_CLASS(vips_profile_load_parent_class)->build(object)) return -1; if (g_ascii_strcasecmp(load->name, "none") == 0) profile = NULL; else if ((data = vips_profile_fallback_get(load->name, &length))) profile = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, data, length); else if ((data = vips__file_read_name(load->name, vips__icc_dir(), &length))) profile = vips_blob_new( (VipsCallbackFn) vips_area_free_cb, data, length); else { vips_error(class->nickname, _("unable to load profile \"%s\""), load->name); return -1; } g_object_set(object, "profile", profile, NULL); if (profile) { vips_area_unref((VipsArea *) profile); profile = NULL; } return 0; } static void vips_profile_load_class_init(VipsProfileLoadClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "profile_load"; object_class->description = _("load named ICC profile"); object_class->build = vips_profile_load_build; VIPS_ARG_STRING(class, "name", 1, _("Name"), _("Profile name"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsProfileLoad, name), NULL); VIPS_ARG_BOXED(class, "profile", 2, _("Profile"), _("Loaded profile"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsProfileLoad, profile), VIPS_TYPE_BLOB); } static void vips_profile_load_init(VipsProfileLoad *load) { } /** * vips_profile_load: * @name: name of profile to load * @profile: (out): loaded profile * @...: `NULL`-terminated list of optional named arguments * * Load a named profile. * * Profiles are loaded from four sources: * * - The special name `"none"` means no profile. @profile will be `NULL` in this * case. * * - @name can be the name of one of the ICC profiles embedded in libvips. * These names can be at least `"cmyk"`, `"p3"` and `"srgb"`. * * - @name can be the full path to a file. * * - @name can be the name of an ICC profile in the system profile directory * for your platform. * * Returns: 0 on success, -1 on error */ int vips_profile_load(const char *name, VipsBlob **profile, ...) { va_list ap; int result; va_start(ap, profile); result = vips_call_split("profile_load", ap, name, profile); va_end(ap); return result; } /* Set (or remove) a named profile on an image. */ int vips__profile_set(VipsImage *image, const char *name) { VipsBlob *profile; if (vips_profile_load(name, &profile, NULL)) return -1; if (profile) { GValue value = G_VALUE_INIT; g_value_init(&value, VIPS_TYPE_BLOB); g_value_set_boxed(&value, profile); vips_image_set(image, VIPS_META_ICC_NAME, &value); g_value_unset(&value); } else vips_image_remove(image, VIPS_META_ICC_NAME); if (profile) { vips_area_unref((VipsArea *) profile); profile = NULL; } return 0; } libvips-8.18.2/libvips/colour/profiles.c000066400000000000000000107606651516303661500202570ustar00rootroot00000000000000/* this file is generated automatically, do not edit! */ /* clang-format off */ #include "profiles.h" static VipsProfileFallback vips__profile_fallback_cmyk = { "cmyk", 961644, { 0x78, 0xDA, 0xAC, 0x99, 0x03, 0x40, 0xDD, 0xFF, 0xFF, 0xFD, 0x6F, 0x5A, 0x5C, 0xDA, 0x6A, 0xD9, 0xB6, 0x6D, 0xDB, 0xD6, 0xBA, 0xD9, 0xB8, 0xD9, 0x36, 0x96, 0x6D, 0x2F, 0xDB, 0x36, 0x97, 0xD7, 0x32, 0xB6, 0x5A, 0xAE, 0x55, 0xCB, 0xF8, 0xBF, 0xBF, 0x9F, 0xBF, 0xAD, 0xDF, 0xF3, 0xEA, 0x5C, 0xFB, 0x7D, 0x1E, 0xAF, 0x73, 0x40, 0xA8, 0xD5, 0x76, 0x60, 0x88, 0xA5, 0x1D, 0x34, 0x09, 0x08, 0xE4, 0x04, 0x71, 0x85, 0x88, 0x2B, 0xEA, 0xCA, 0x2B, 0x80, 0x4D, 0x48, 0xE0, 0xB7, 0x40, 0x08, 0x20, 0x5C, 0x10, 0x0A, 0x88, 0x06, 0xC4, 0x09, 0x36, 0x75, 0x71, 0x52, 0x54, 0x97, 0xD2, 0x00, 0xFD, 0x8F, 0x07, 0x0A, 0x04, 0xBA, 0xFD, 0x0E, 0x1C, 0x03, 0xB3, 0xC8, 0xF8, 0xAF, 0xC7, 0x02, 0xFD, 0xDF, 0x0D, 0x9A, 0x99, 0xB9, 0x8B, 0x29, 0xF0, 0x30, 0x3C, 0x80, 0xB6, 0x36, 0x05, 0x5E, 0x04, 0xA0, 0x4B, 0x00, 0x6D, 0xE9, 0xE1, 0xEA, 0x04, 0x68, 0x68, 0x14, 0x40, 0x7F, 0x34, 0xB1, 0xFD, 0x47, 0x93, 0xFC, 0x4B, 0x9B, 0xDA, 0x41, 0xFE, 0xA5, 0x39, 0x00, 0x5D, 0x22, 0xCA, 0x26, 0xC6, 0x0A, 0xE8, 0x1F, 0x20, 0xD0, 0xFC, 0x23, 0xA0, 0x59, 0xFE, 0x0B, 0xCD, 0xF6, 0x1F, 0xB5, 0x18, 0x9B, 0x28, 0x70, 0x9B, 0xA5, 0x25, 0x40, 0x77, 0x03, 0x9A, 0x05, 0x04, 0x55, 0x96, 0xF0, 0x1F, 0x34, 0x1B, 0x08, 0xDA, 0x53, 0xE1, 0x5F, 0xDA, 0x12, 0x6C, 0xEF, 0x0A, 0x82, 0x91, 0x43, 0x00, 0x81, 0x98, 0xD2, 0x5C, 0x81, 0x37, 0x01, 0x82, 0xF1, 0x2C, 0x00, 0x21, 0xB3, 0x4F, 0x49, 0x98, 0xBB, 0x4B, 0xFC, 0x47, 0x2D, 0x2E, 0x2B, 0xF9, 0x9F, 0xF4, 0x3F, 0xAF, 0xF9, 0x3F, 0xBC, 0x7E, 0x71, 0x2B, 0x73, 0x7B, 0x6B, 0x53, 0xB0, 0x1D, 0x89, 0x13, 0xC4, 0xD1, 0xD1, 0x02, 0xF4, 0x6F, 0x3E, 0xAE, 0xE6, 0x9E, 0xAE, 0x20, 0x60, 0xC4, 0x21, 0xE6, 0x60, 0x57, 0x73, 0x33, 0x12, 0x13, 0x2F, 0x12, 0x69, 0x08, 0xD8, 0xDC, 0xDE, 0x9C, 0x44, 0x9B, 0x89, 0x44, 0xDA, 0xDA, 0xCE, 0x8E, 0x89, 0x44, 0xCD, 0xDC, 0xCE, 0x1C, 0xEC, 0x02, 0x5C, 0x67, 0xED, 0xE0, 0xEA, 0x48, 0xE2, 0x6A, 0x65, 0x4E, 0xE2, 0xE4, 0x66, 0x62, 0x67, 0x6D, 0x4A, 0x62, 0xE6, 0x68, 0x0F, 0xB6, 0x76, 0x60, 0x22, 0x51, 0x72, 0x24, 0xD1, 0x06, 0x43, 0x20, 0x60, 0x07, 0x57, 0x2F, 0x06, 0x12, 0x4D, 0x17, 0x73, 0x12, 0xB0, 0x2B, 0x89, 0x97, 0xA3, 0x1B, 0x84, 0xC4, 0xD1, 0xC3, 0x81, 0x04, 0x62, 0xED, 0x62, 0xCB, 0x04, 0x02, 0xE9, 0xE8, 0xEA, 0x91, 0x80, 0xFE, 0x99, 0xDD, 0x49, 0x10, 0xE8, 0x28, 0x1A, 0x04, 0x1A, 0x52, 0xFD, 0xCF, 0x97, 0xC1, 0x52, 0x00, 0x07, 0x3E, 0x10, 0x08, 0xA6, 0xE0, 0x9F, 0xCF, 0xFF, 0x3F, 0x5C, 0x28, 0xEE, 0x05, 0x76, 0xF8, 0x5F, 0xBD, 0xF6, 0x04, 0x4F, 0x7D, 0x6E, 0x79, 0x78, 0x45, 0xB0, 0xA5, 0xB9, 0x83, 0x2B, 0xF8, 0x7F, 0x7A, 0xAB, 0x30, 0xF2, 0x99, 0x24, 0xDF, 0x3B, 0x5D, 0x73, 0x3B, 0x3B, 0x47, 0x8F, 0xFF, 0xF9, 0x63, 0x5D, 0xA1, 0xF9, 0x52, 0xED, 0x13, 0x8B, 0xD9, 0x81, 0x4D, 0x6D, 0x41, 0xFF, 0xF3, 0xA1, 0x74, 0x0C, 0x79, 0xF2, 0x19, 0xB0, 0xB7, 0x70, 0x65, 0xFB, 0xE7, 0x05, 0xC2, 0x20, 0xFE, 0xF3, 0x0B, 0xFD, 0x2F, 0xE7, 0x7F, 0x74, 0x1E, 0x16, 0xD8, 0x01, 0xA3, 0x07, 0x6A, 0x86, 0x7A, 0x0F, 0x65, 0x09, 0x35, 0x00, 0x8D, 0x0F, 0xED, 0x0A, 0xFD, 0x0D, 0x86, 0x06, 0x26, 0x08, 0x66, 0x1D, 0x96, 0x13, 0x36, 0x1E, 0xF6, 0x10, 0x4E, 0x0C, 0x2E, 0x1B, 0xEE, 0xEF, 0x3B, 0xA5, 0x77, 0x15, 0xF0, 0xD0, 0xF0, 0xFA, 0xF0, 0x2D, 0x08, 0xA8, 0x08, 0x56, 0x08, 0x03, 0x88, 0xF8, 0x88, 0xAE, 0x88, 0x33, 0x48, 0xD4, 0x48, 0x81, 0x48, 0x6B, 0xC8, 0xEC, 0xC8, 0xB1, 0xC8, 0x07, 0x28, 0xC2, 0x28, 0x19, 0x28, 0x57, 0xEF, 0xE5, 0xDF, 0x97, 0xBC, 0x7F, 0x45, 0xD5, 0x46, 0xAD, 0x47, 0x43, 0x44, 0x33, 0x45, 0xEB, 0x46, 0xC7, 0x42, 0x77, 0x40, 0x1F, 0xC3, 0x20, 0xC1, 0xF0, 0xC6, 0x58, 0xC4, 0x64, 0xC0, 0x0C, 0xC3, 0xDC, 0xFA, 0xC0, 0xFD, 0x21, 0xE1, 0xC3, 0xD1, 0x47, 0xB1, 0x8F, 0xD9, 0x1F, 0x6F, 0xB0, 0x14, 0xB1, 0xCA, 0xB0, 0xDE, 0xB0, 0x75, 0xB0, 0x1B, 0x3E, 0x21, 0x7D, 0x32, 0xFD, 0xD4, 0x8D, 0x83, 0x85, 0x63, 0x8F, 0x33, 0x8A, 0x4B, 0x8C, 0xEB, 0x89, 0x3B, 0x8F, 0x47, 0x87, 0x17, 0x82, 0xB7, 0x8E, 0xCF, 0x81, 0x1F, 0x87, 0x7F, 0x40, 0x20, 0x4C, 0x90, 0x4E, 0x70, 0x49, 0x28, 0x4B, 0x58, 0x48, 0xF8, 0x48, 0xA4, 0x4E, 0x54, 0x4D, 0x0C, 0x4B, 0x6C, 0x48, 0xDC, 0x4A, 0x82, 0x4C, 0xA2, 0x40, 0x12, 0x4F, 0x32, 0x47, 0x8A, 0x49, 0xAA, 0x41, 0x9A, 0x4A, 0xBA, 0x42, 0x86, 0x4B, 0xA6, 0x4F, 0x96, 0x43, 0xB6, 0x45, 0x4E, 0x42, 0x6E, 0x42, 0x5E, 0x4C, 0xBE, 0x4F, 0x41, 0x4D, 0x61, 0x45, 0x51, 0x49, 0x71, 0x4A, 0xC9, 0x48, 0xE9, 0x48, 0xD9, 0x40, 0x79, 0x45, 0xC5, 0x41, 0xE5, 0x4E, 0xD5, 0x46, 0xF5, 0x40, 0xCD, 0x47, 0xED, 0x4B, 0xDD, 0x4B, 0xFD, 0x46, 0x23, 0x4A, 0x13, 0x4C, 0x33, 0x4C, 0x0B, 0x47, 0x2B, 0x4D, 0x1B, 0x49, 0x3B, 0x49, 0x87, 0x4C, 0xA7, 0x48, 0x17, 0x4F, 0x37, 0x4B, 0x8F, 0x41, 0xAF, 0x46, 0x9F, 0x4C, 0xBF, 0xCC, 0x80, 0xCD, 0xA0, 0xCD, 0x90, 0xC9, 0xB0, 0xC6, 0x88, 0xCF, 0x68, 0xC8, 0x98, 0xC7, 0xB8, 0xCD, 0x44, 0xC2, 0x04, 0x66, 0x2A, 0x62, 0xFA, 0xC5, 0x4C, 0xC9, 0x6C, 0xC1, 0x5C, 0xCE, 0x7C, 0xC8, 0x42, 0xCB, 0x62, 0xC3, 0x52, 0xC5, 0x72, 0xCA, 0xCA, 0xC8, 0xEA, 0xC0, 0x5A, 0xC7, 0x7A, 0xC9, 0xC6, 0xCA, 0x06, 0x61, 0x6B, 0x62, 0xBB, 0x61, 0xE7, 0x60, 0x77, 0x63, 0x6F, 0x65, 0xBF, 0xE3, 0xE0, 0xE1, 0xF0, 0xE4, 0xE8, 0xE0, 0x78, 0xE4, 0xE4, 0xE3, 0xF4, 0xE1, 0xEC, 0xE6, 0x7C, 0xE6, 0x12, 0xE4, 0xF2, 0xE3, 0xEA, 0xE5, 0x7A, 0xE3, 0x16, 0xE6, 0x0E, 0xE4, 0xEE, 0xE7, 0x01, 0xF1, 0x88, 0xF2, 0x04, 0xF1, 0x0C, 0xF2, 0x42, 0xF3, 0x8A, 0xF1, 0x86, 0xF0, 0x0E, 0xF1, 0xC1, 0xF0, 0x49, 0xF0, 0x85, 0xF2, 0x0D, 0xF3, 0xC3, 0xF2, 0x4B, 0xF2, 0x87, 0xF1, 0x8F, 0x08, 0xC0, 0x09, 0x48, 0x0A, 0x84, 0x09, 0x8C, 0x08, 0xC2, 0x09, 0x4A, 0x0A, 0x86, 0x09, 0x8E, 0x08, 0xC1, 0x09, 0x49, 0x0A, 0x85, 0x09, 0x8D, 0x08, 0xC3, 0x09, 0x4B, 0x08, 0x87, 0x0A, 0x0F, 0x8B, 0xC0, 0x88, 0x08, 0x8A, 0x78, 0x88, 0x34, 0x88, 0x9C, 0x88, 0x52, 0x8A, 0x7E, 0x16, 0xCD, 0x10, 0x5D, 0x10, 0x43, 0x11, 0x93, 0x12, 0x0B, 0x10, 0xEB, 0x10, 0xBB, 0x16, 0x67, 0x10, 0xB7, 0x10, 0xCF, 0x17, 0x5F, 0x95, 0xC0, 0x94, 0x50, 0x90, 0x08, 0x93, 0xE8, 0x93, 0xB8, 0x97, 0x64, 0x93, 0xB4, 0x95, 0x2C, 0x91, 0xDC, 0x92, 0xFA, 0x24, 0xA5, 0x22, 0x15, 0x25, 0x35, 0x24, 0xF5, 0x2C, 0xCD, 0x29, 0xED, 0x20, 0x5D, 0x2E, 0xBD, 0x23, 0x83, 0x2B, 0xA3, 0x26, 0x13, 0x23, 0x33, 0x2C, 0xF3, 0x22, 0xCB, 0x25, 0xEB, 0x28, 0x5B, 0x21, 0xBB, 0x2B, 0x87, 0x27, 0xA7, 0x26, 0x17, 0x23, 0x37, 0x2C, 0xF7, 0x2C, 0xCF, 0x29, 0xEF, 0x20, 0x5F, 0x26, 0xBF, 0xAD, 0x80, 0xA3, 0xA0, 0xA2, 0x10, 0xA5, 0x30, 0xA0, 0xF0, 0xA0, 0xC8, 0xA6, 0x68, 0xA3, 0x58, 0xAC, 0xB8, 0xAE, 0xF4, 0x41, 0x49, 0x41, 0x29, 0x54, 0xA9, 0x5B, 0xE9, 0x46, 0x99, 0x51, 0xD9, 0x5C, 0x39, 0x57, 0x79, 0x59, 0xE5, 0xBD, 0x8A, 0xA4, 0x8A, 0x9F, 0x4A, 0x8B, 0xCA, 0x99, 0x2A, 0xA5, 0xAA, 0xA1, 0x6A, 0xAA, 0xEA, 0x8C, 0x1A, 0x9C, 0x9A, 0xA0, 0x9A, 0x9B, 0x5A, 0xB5, 0xDA, 0x2F, 0x75, 0x02, 0x75, 0x0D, 0xF5, 0x18, 0xF5, 0x21, 0xF5, 0x27, 0x0D, 0x36, 0x0D, 0x1B, 0x8D, 0x42, 0x8D, 0x55, 0x4D, 0x0C, 0x4D, 0x19, 0xCD, 0x40, 0xCD, 0x36, 0xCD, 0x73, 0x2D, 0x2A, 0x2D, 0x43, 0xAD, 0x54, 0xAD, 0x69, 0x6D, 0x18, 0x6D, 0x3E, 0x6D, 0x88, 0xF6, 0x57, 0xED, 0x1D, 0x9D, 0x4F, 0x3A, 0x4A, 0x3A, 0xE1, 0x3A, 0x3D, 0x3A, 0x37, 0xBA, 0xF4, 0xBA, 0x26, 0xBA, 0x99, 0xBA, 0x73, 0x7A, 0xF0, 0x7A, 0x42, 0x7A, 0x6E, 0x7A, 0xD5, 0x7A, 0x3F, 0xF5, 0xF1, 0xF4, 0x55, 0xF5, 0x23, 0xF5, 0xFB, 0xF4, 0x6F, 0x0D, 0x18, 0x0D, 0xCC, 0x0C, 0xB2, 0x0D, 0x16, 0x0C, 0x11, 0x0D, 0x45, 0x0C, 0x3D, 0x0C, 0x6B, 0x0D, 0xF7, 0x8D, 0x08, 0x8C, 0xD4, 0x8D, 0xA2, 0x8D, 0x06, 0x8C, 0xEE, 0x3F, 0x33, 0x7D, 0x36, 0xFF, 0x9C, 0xF3, 0x79, 0xD1, 0x18, 0xD9, 0x58, 0xC6, 0x38, 0xD4, 0x78, 0xC0, 0xF8, 0x05, 0xCC, 0x0B, 0x76, 0x07, 0x37, 0x82, 0xCF, 0x4D, 0xE8, 0x4D, 0x2C, 0x4D, 0x4A, 0x4C, 0x76, 0x4C, 0x09, 0x4C, 0x75, 0x4D, 0x53, 0x4D, 0xE7, 0xCD, 0x50, 0xCD, 0xE4, 0xCC, 0xC2, 0xCD, 0x86, 0xCC, 0xDE, 0xCC, 0xF9, 0xCD, 0x3D, 0xCD, 0x9B, 0xCD, 0x2F, 0x2D, 0x18, 0x2C, 0xAC, 0x2D, 0x4A, 0x2D, 0x76, 0x2D, 0x09, 0x2D, 0xF5, 0x2C, 0xD3, 0x2C, 0x17, 0xAC, 0x50, 0xAD, 0xE4, 0xAC, 0xC2, 0xAD, 0x86, 0xAC, 0xDE, 0xAC, 0xF9, 0xAD, 0x3D, 0xAC, 0x9B, 0xAC, 0x2F, 0x6C, 0xE8, 0x6D, 0x2C, 0x6D, 0x4A, 0x6C, 0x76, 0x6C, 0x09, 0x6C, 0x75, 0x6C, 0x53, 0x6C, 0xE7, 0xEC, 0x50, 0xEC, 0x64, 0xEC, 0xC2, 0xEC, 0x06, 0xEC, 0x5E, 0xEC, 0x79, 0xED, 0xDD, 0xEC, 0x1B, 0xEC, 0xCF, 0x1C, 0x68, 0x1D, 0x2C, 0x1C, 0x8A, 0x1C, 0xB6, 0x1C, 0xF1, 0x1C, 0xB5, 0x1C, 0x93, 0x1C, 0xBF, 0x39, 0x21, 0x3B, 0x49, 0x3B, 0x85, 0x38, 0xF5, 0x39, 0x3D, 0x39, 0x73, 0x3B, 0xBB, 0x3A, 0xD7, 0x3B, 0x9F, 0x42, 0x68, 0x20, 0x66, 0x90, 0x02, 0xC8, 0x86, 0x0B, 0xAE, 0x8B, 0xA6, 0x4B, 0xA2, 0xCB, 0x8C, 0x2B, 0xA2, 0xAB, 0xA4, 0x6B, 0x90, 0x6B, 0xAF, 0xEB, 0xA3, 0x1B, 0x97, 0x1B, 0xC4, 0xAD, 0xD6, 0xED, 0xD8, 0x9D, 0xCA, 0xDD, 0xD4, 0x3D, 0xDF, 0x7D, 0xDD, 0xE3, 0x93, 0x87, 0xBA, 0xC7, 0x17, 0x8F, 0x29, 0x4F, 0x78, 0x4F, 0x09, 0xCF, 0x40, 0xCF, 0x6E, 0xCF, 0x7B, 0x2F, 0x0E, 0x2F, 0x27, 0xAF, 0x6A, 0xAF, 0x43, 0x6F, 0x0A, 0x6F, 0x63, 0xEF, 0x5C, 0xEF, 0x55, 0x1F, 0x2C, 0x1F, 0x55, 0x9F, 0x38, 0x9F, 0x09, 0x5F, 0x38, 0x5F, 0x51, 0x5F, 0x3F, 0xDF, 0x0E, 0xDF, 0xBF, 0x7E, 0x6C, 0x7E, 0x0E, 0x7E, 0x95, 0x7E, 0x07, 0xFE, 0x64, 0xFE, 0x46, 0xFE, 0x59, 0xFE, 0xDF, 0x03, 0x30, 0x03, 0x94, 0x02, 0xA2, 0x03, 0x46, 0x03, 0xA1, 0x03, 0x85, 0x03, 0x7D, 0x03, 0x3B, 0x02, 0x6F, 0x83, 0xD8, 0x83, 0x9C, 0x82, 0x6A, 0x82, 0x8E, 0x83, 0xA9, 0x83, 0xCD, 0x82, 0x0B, 0x83, 0xB7, 0x42, 0xF0, 0x43, 0x74, 0x42, 0x52, 0x43, 0x16, 0x43, 0xD1, 0x43, 0x15, 0x43, 0xA3, 0x43, 0xC7, 0xC2, 0x60, 0xC3, 0xC4, 0xC2, 0x02, 0xC2, 0xBA, 0xC3, 0x1E, 0xC2, 0xB9, 0xC3, 0x5D, 0xC3, 0x1B, 0xC2, 0x2F, 0x22, 0x18, 0x22, 0x6C, 0x22, 0xCA, 0x23, 0xF6, 0x23, 0xC9, 0x22, 0x8D, 0x23, 0x73, 0x23, 0xD7, 0xA3, 0x70, 0xA2, 0xB4, 0xA2, 0x52, 0xA2, 0xE6, 0xA3, 0xD1, 0xA2, 0x15, 0xA3, 0xA3, 0xA3, 0xC7, 0x63, 0xDE, 0xC5, 0x48, 0xC4, 0x04, 0xC5, 0xF4, 0xC5, 0xBC, 0xC4, 0xF2, 0xC7, 0x7A, 0xC5, 0xB6, 0xC5, 0xFE, 0x8D, 0x63, 0x8F, 0x73, 0x8E, 0xAB, 0x8B, 0x3B, 0x8B, 0xA7, 0x8F, 0xB7, 0x8E, 0x2F, 0x8F, 0xDF, 0xFF, 0x42, 0xFE, 0x05, 0xFC, 0xA5, 0xE0, 0xCB, 0x56, 0x02, 0x41, 0x82, 0x5E, 0x42, 0x66, 0xC2, 0x4A, 0x22, 0x56, 0xA2, 0x46, 0x62, 0x52, 0xE2, 0x5C, 0x12, 0x5A, 0x92, 0x62, 0x52, 0x6C, 0xD2, 0x64, 0x32, 0x62, 0xB2, 0x74, 0x72, 0x78, 0xF2, 0x70, 0x0A, 0x4C, 0x8A, 0x58, 0x4A, 0x60, 0x4A, 0x5F, 0xCA, 0x6B, 0xAA, 0x40, 0xAA, 0x4F, 0x6A, 0x67, 0xEA, 0x43, 0x1A, 0x4F, 0x9A, 0x7B, 0x5A, 0x4B, 0xDA, 0x4D, 0x3A, 0x7B, 0x3A, 0x24, 0xBD, 0x21, 0xFD, 0x32, 0x83, 0x39, 0xC3, 0x21, 0xA3, 0x36, 0xE3, 0x2C, 0x93, 0x21, 0xD3, 0x36, 0xB3, 0x32, 0xF3, 0x38, 0x8B, 0x36, 0xCB, 0x2A, 0xAB, 0x22, 0xEB, 0x77, 0x36, 0x55, 0xB6, 0x45, 0x76, 0x69, 0xF6, 0x7E, 0x0E, 0x45, 0x8E, 0x59, 0x4E, 0x71, 0xCE, 0xCF, 0x5C, 0xB2, 0x5C, 0x93, 0xDC, 0xA2, 0xDC, 0xDD, 0x3C, 0xD2, 0x3C, 0x70, 0x5E, 0x61, 0xDE, 0x4E, 0x3E, 0x49, 0xBE, 0x71, 0x7E, 0x41, 0xFE, 0x4E, 0x01, 0x61, 0x81, 0x4E, 0x41, 0x72, 0xC1, 0xB7, 0x42, 0xC4, 0x42, 0x89, 0xC2, 0x80, 0xC2, 0xCE, 0xC2, 0xBF, 0x45, 0x2C, 0x45, 0xB6, 0x45, 0xE5, 0x45, 0x7B, 0xC5, 0x84, 0xC5, 0x3A, 0xC5, 0xC9, 0xC5, 0xB3, 0x25, 0x48, 0x25, 0x92, 0x25, 0x41, 0x25, 0xDD, 0x25, 0x77, 0xA5, 0xEC, 0xA5, 0x0E, 0xA5, 0x5F, 0x4B, 0xF7, 0xCB, 0x48, 0xCA, 0x0C, 0xCA, 0xD2, 0xCB, 0x16, 0xCB, 0x51, 0xCB, 0xE5, 0xCA, 0xC3, 0xCA, 0x07, 0xCA, 0x9F, 0x2B, 0x78, 0x2A, 0x5C, 0x2A, 0xEA, 0x2A, 0x4E, 0xBE, 0x52, 0x7D, 0x35, 0xF9, 0x9A, 0xF7, 0x75, 0xB5, 0x12, 0xAB, 0x52, 0xB5, 0x32, 0xAE, 0x72, 0xA2, 0x0A, 0xB6, 0x4A, 0xA4, 0xCA, 0xB7, 0xAA, 0xBD, 0xEA, 0xA6, 0x9A, 0xA5, 0xDA, 0xAE, 0xBA, 0xA2, 0xFA, 0x67, 0x0D, 0x71, 0x8D, 0x7E, 0x4D, 0x7A, 0xCD, 0x62, 0x2D, 0x5A, 0xAD, 0x7C, 0x6D, 0x44, 0xED, 0x50, 0xED, 0x5B, 0x1D, 0x7F, 0x9D, 0x47, 0x5D, 0x63, 0xDD, 0x79, 0x3D, 0x5D, 0xBD, 0x45, 0x7D, 0x51, 0xFD, 0x56, 0x03, 0x5E, 0x83, 0x56, 0x43, 0x52, 0xC3, 0xB7, 0x46, 0xC4, 0x46, 0xC9, 0xC6, 0xA0, 0xC6, 0x9E, 0xC6, 0x87, 0x26, 0xCE, 0x26, 0xE7, 0xA6, 0x9A, 0xA6, 0xA3, 0x66, 0xCA, 0x66, 0xE3, 0xE6, 0x9C, 0xE6, 0x1F, 0x2D, 0x1F, 0x5B, 0x54, 0x5A, 0x62, 0x5B, 0xC6, 0x5B, 0x61, 0x5A, 0x85, 0x5B, 0x7D, 0x5A, 0xDB, 0x5A, 0xAF, 0xDB, 0x98, 0xDB, 0x6C, 0xDA, 0xCA, 0xDA, 0xF6, 0xDA, 0x89, 0xDA, 0xF5, 0xDA, 0x53, 0xDB, 0xE7, 0x3B, 0xDE, 0x77, 0xC8, 0x76, 0x84, 0x76, 0xF4, 0x77, 0x3C, 0x77, 0xF2, 0x74, 0xBA, 0x74, 0xD6, 0x75, 0x9E, 0x74, 0x51, 0x75, 0x99, 0x74, 0xE5, 0x75, 0xAD, 0x75, 0x63, 0x75, 0xAB, 0x76, 0xC7, 0x76, 0x8F, 0xF7, 0xC0, 0xF6, 0x08, 0xF7, 0xF8, 0xF4, 0xB4, 0xF5, 0x5C, 0xF5, 0x32, 0xF5, 0x5A, 0xF7, 0x96, 0xF6, 0xEE, 0xF4, 0x11, 0xF4, 0xE9, 0xF4, 0x25, 0xF7, 0xCD, 0xF6, 0x23, 0xF5, 0x8B, 0xF5, 0x7B, 0xF7, 0x37, 0xF5, 0x9F, 0x0C, 0x90, 0x0F, 0x18, 0x0C, 0xA4, 0x0C, 0x4C, 0x0F, 0xC2, 0x0D, 0x0A, 0x0E, 0xBA, 0x0D, 0xD6, 0x0E, 0x1E, 0x0C, 0x11, 0x0D, 0x69, 0x0D, 0x7D, 0x19, 0x1A, 0x1B, 0x7A, 0x1B, 0xE6, 0x1E, 0x76, 0x1C, 0xAE, 0x18, 0xDE, 0x19, 0xC1, 0x19, 0x51, 0x19, 0x89, 0x1C, 0xE9, 0x1F, 0x79, 0x18, 0x65, 0x1D, 0xB5, 0x1E, 0x2D, 0x1C, 0x5D, 0x1D, 0xC3, 0x18, 0x93, 0x1D, 0x0B, 0x1A, 0xEB, 0x18, 0xBB, 0x1A, 0xA7, 0x1B, 0x37, 0x19, 0xCF, 0x1A, 0x5F, 0x98, 0x40, 0x9A, 0x10, 0x9B, 0xF0, 0x9E, 0x68, 0x9C, 0x38, 0x9E, 0x24, 0x9B, 0xD4, 0x9B, 0x4C, 0x9A, 0x9C, 0x9C, 0x82, 0x9E, 0xE2, 0x9B, 0x82, 0x4C, 0x55, 0x4E, 0xED, 0x4D, 0xE3, 0x4D, 0xAB, 0x4D, 0x47, 0x4F, 0x0F, 0x4E, 0x3F, 0xCE, 0xB0, 0xCD, 0xD8, 0xCC, 0x14, 0xCF, 0xAC, 0x7F, 0xFB, 0xF0, 0x4D, 0xFE, 0x5B, 0xC8, 0xB7, 0xAE, 0x6F, 0xD7, 0xB3, 0xF4, 0xB3, 0xA6, 0xB3, 0xD9, 0xB3, 0x8B, 0x73, 0xC8, 0x73, 0xE2, 0x73, 0xBE, 0x73, 0xCD, 0x73, 0xA7, 0xF3, 0x14, 0xF3, 0x06, 0xF3, 0x29, 0xF3, 0xD3, 0x0B, 0xB0, 0x0B, 0x02, 0x0B, 0x6E, 0x0B, 0x35, 0x0B, 0xFB, 0x8B, 0x84, 0x8B, 0x9A, 0x8B, 0x71, 0x8B, 0x23, 0x8B, 0xAF, 0x4B, 0x5C, 0x4B, 0x0E, 0x4B, 0x65, 0x4B, 0x5B, 0xCB, 0xD8, 0xCB, 0x4A, 0xCB, 0xE1, 0xCB, 0x7D, 0xCB, 0x77, 0xDF, 0x99, 0xBF, 0x5B, 0x7E, 0xCF, 0xFF, 0xBE, 0xB2, 0x82, 0xB6, 0x22, 0xB3, 0x12, 0xB8, 0xD2, 0xBE, 0x72, 0xF9, 0x83, 0xE6, 0x87, 0xF1, 0x8F, 0x8C, 0x1F, 0x73, 0xAB, 0x88, 0xAB, 0xA2, 0xAB, 0x5E, 0xAB, 0x0D, 0xAB, 0x47, 0x6B, 0xA4, 0x6B, 0xBA, 0x6B, 0x49, 0x6B, 0x93, 0xEB, 0xD0, 0xEB, 0x7C, 0xEB, 0x90, 0xF5, 0xCA, 0xF5, 0xBD, 0x0D, 0xFC, 0x0D, 0xF5, 0x8D, 0x98, 0x8D, 0xA1, 0x8D, 0xA7, 0x4D, 0xF6, 0x4D, 0xDB, 0xCD, 0x92, 0xCD, 0x8D, 0xAD, 0x8F, 0x5B, 0x0A, 0x5B, 0xA1, 0x5B, 0xDD, 0x5B, 0x37, 0xDB, 0x0C, 0xDB, 0x66, 0xDB, 0xB9, 0xDB, 0xCB, 0x3B, 0x98, 0x3B, 0x46, 0x3B, 0x95, 0x3B, 0xB7, 0xBB, 0x62, 0xBB, 0xF1, 0xBB, 0xEB, 0x7B, 0xD4, 0x7B, 0x2E, 0x7B, 0x7D, 0x3F, 0x91, 0x7F, 0x6A, 0xFF, 0x2C, 0xFE, 0x79, 0xF1, 0x8B, 0xFF, 0x57, 0xC4, 0xAF, 0xC5, 0x7D, 0xE2, 0x7D, 0xDB, 0xFD, 0xB6, 0x03, 0x98, 0x03, 0xE5, 0x83, 0xEC, 0x83, 0xDF, 0xBF, 0xD9, 0x7F, 0x07, 0xFC, 0x9E, 0x3A, 0xFC, 0x74, 0x68, 0x7A, 0x58, 0x77, 0xF8, 0x74, 0x24, 0x7D, 0x94, 0x7C, 0xB4, 0x75, 0x4C, 0x77, 0xEC, 0x7E, 0x3C, 0x78, 0x82, 0x7A, 0xA2, 0x77, 0x52, 0x7A, 0xF2, 0xE7, 0x54, 0xF0, 0x34, 0xEA, 0x74, 0xF9, 0x8C, 0xE4, 0xCC, 0xEE, 0xAC, 0xFD, 0x1C, 0xF6, 0x5C, 0xF9, 0x3C, 0xFB, 0xFC, 0xF7, 0x05, 0xFB, 0x85, 0xFF, 0xC5, 0xE4, 0x25, 0xF6, 0x25, 0xF8, 0xB2, 0xE6, 0xF2, 0xE1, 0x8F, 0xC4, 0x9F, 0x84, 0x3F, 0x1B, 0x57, 0xD4, 0x57, 0x2E, 0x57, 0xBD, 0xD7, 0x48, 0xD7, 0x5A, 0xD7, 0x85, 0xD7, 0x67, 0x37, 0x3C, 0x37, 0xA1, 0x37, 0xB3, 0x7F, 0xF1, 0xFF, 0x5A, 0xFE, 0x6D, 0xFC, 0xFB, 0x7A, 0x2B, 0x7B, 0x9B, 0x72, 0xBB, 0x73, 0x47, 0x7F, 0xE7, 0x71, 0x37, 0x78, 0x8F, 0x7A, 0xAF, 0x7B, 0x5F, 0x7A, 0x7F, 0xF9, 0xC0, 0xFF, 0x10, 0xF1, 0xB0, 0xF0, 0x48, 0xF4, 0x68, 0xFD, 0xD8, 0xFC, 0x04, 0x7A, 0x92, 0x7F, 0x4A, 0x7B, 0xDA, 0x7B, 0x66, 0x7C, 0xF6, 0x7C, 0x1E, 0x7A, 0x41, 0x7B, 0xD1, 0x7B, 0x29, 0x7D, 0xF9, 0xF3, 0x2A, 0xF0, 0x1A, 0xF1, 0xBA, 0xF0, 0x46, 0xF8, 0x66, 0xFD, 0xD6, 0xFC, 0xF6, 0x06, 0xF8, 0xBF, 0x32, 0x28, 0x17, 0x74, 0x0A, 0xC5, 0x0F, 0x15, 0x05, 0xF5, 0x03, 0x9A, 0x0A, 0xDA, 0x0D, 0x7A, 0x18, 0x06, 0x13, 0x06, 0x0C, 0x53, 0x07, 0xF3, 0x0A, 0xAB, 0x00, 0x9B, 0x0D, 0x7B, 0x04, 0xC7, 0x03, 0x17, 0x0E, 0xB7, 0xFC, 0x8E, 0xFC, 0x1D, 0xE4, 0x5D, 0x3F, 0x3C, 0x2A, 0xBC, 0x21, 0x7C, 0x15, 0xFC, 0x23, 0x82, 0x0C, 0x42, 0x1A, 0xC2, 0x3E, 0x22, 0x3B, 0x62, 0x10, 0xE2, 0x1C, 0x12, 0x11, 0x92, 0x1D, 0x52, 0x17, 0x32, 0x22, 0xB2, 0x36, 0x72, 0x29, 0xF2, 0x0D, 0x8A, 0x18, 0x4A, 0x02, 0xCA, 0xD6, 0x7B, 0x86, 0xF7, 0xDE, 0xEF, 0x27, 0x50, 0x3F, 0xA1, 0x9A, 0xA3, 0x36, 0xA1, 0x41, 0xA1, 0x29, 0xA3, 0xE5, 0xA2, 0x9D, 0xA0, 0xF3, 0xA1, 0x47, 0xA2, 0x7F, 0xC7, 0xA0, 0xC0, 0x80, 0x60, 0xF4, 0x63, 0xA2, 0x62, 0x1A, 0x60, 0x56, 0x62, 0xDE, 0x7F, 0x90, 0xFA, 0x90, 0xF2, 0x61, 0xEF, 0x23, 0xF3, 0x47, 0xBF, 0x8F, 0x53, 0x58, 0xB8, 0x58, 0x96, 0x58, 0x2D, 0xD8, 0x30, 0xD8, 0xAA, 0xD8, 0x79, 0xD8, 0xA7, 0x9F, 0xF8, 0x3E, 0x45, 0x7E, 0xFA, 0x8E, 0x43, 0x81, 0xE3, 0x8C, 0xD3, 0x87, 0xFB, 0x1E, 0x57, 0x1F, 0xB7, 0x02, 0xF7, 0x16, 0x4F, 0x02, 0x2F, 0x09, 0x6F, 0x1B, 0x9F, 0x11, 0xDF, 0x07, 0x7F, 0x9C, 0x00, 0x9B, 0xC0, 0x8C, 0xA0, 0x81, 0xE0, 0x8D, 0x50, 0x81, 0x30, 0x8B, 0xF0, 0x90, 0x88, 0x93, 0x28, 0x84, 0x68, 0x8E, 0x98, 0x88, 0xD8, 0x96, 0xB8, 0x83, 0x04, 0x8E, 0x44, 0x86, 0x24, 0x9A, 0x64, 0x86, 0x14, 0x8D, 0x54, 0x8D, 0x34, 0xE5, 0x3F, 0x90, 0x41, 0x1E, 0xD9, 0x0E, 0x39, 0x39, 0xB9, 0x39, 0x79, 0x39, 0xF9, 0x31, 0x05, 0x03, 0x85, 0x03, 0x45, 0x03, 0xC5, 0x35, 0x25, 0x27, 0xA5, 0x27, 0x65, 0x27, 0xE5, 0x33, 0x95, 0x30, 0x55, 0x10, 0xD5, 0x10, 0x35, 0x1C, 0xB5, 0x34, 0x75, 0x34, 0xF5, 0x34, 0x0D, 0x2A, 0x8D, 0x0A, 0x4D, 0x12, 0xCD, 0x12, 0x2D, 0x36, 0xAD, 0x0E, 0x6D, 0x16, 0xED, 0x06, 0x1D, 0x11, 0x9D, 0x31, 0x5D, 0x11, 0xDD, 0x2F, 0x7A, 0x2A, 0x7A, 0x2B, 0xFA, 0x4A, 0xFA, 0x53, 0x06, 0x26, 0x06, 0x47, 0x86, 0x06, 0x86, 0x6B, 0x46, 0x4E, 0x46, 0x0F, 0xC6, 0x76, 0xC6, 0x47, 0x26, 0x01, 0x26, 0x7F, 0xA6, 0x3E, 0x66, 0x28, 0x66, 0x71, 0xE6, 0x50, 0xE6, 0x51, 0x16, 0x04, 0x16, 0x59, 0x96, 0x18, 0x96, 0x19, 0x56, 0x54, 0x56, 0x15, 0xD6, 0x44, 0xD6, 0x45, 0xB6, 0x8F, 0x6C, 0x5A, 0x6C, 0x19, 0x6C, 0xAB, 0xEC, 0x78, 0xEC, 0x06, 0xEC, 0xB9, 0xEC, 0xDB, 0x1C, 0x24, 0x1C, 0x26, 0x1C, 0xC5, 0x1C, 0xFB, 0x9C, 0x54, 0x9C, 0x96, 0x9C, 0x5F, 0x39, 0x8F, 0xB9, 0xE8, 0xB9, 0xEC, 0xB9, 0x6A, 0xB9, 0x2E, 0xB8, 0x59, 0xB9, 0x21, 0xDC, 0x4D, 0xDC, 0x37, 0x3C, 0x5C, 0x3C, 0x1E, 0x3C, 0xED, 0x3C, 0x0F, 0xBC, 0x7C, 0xBC, 0xBE, 0xBC, 0x3D, 0xBC, 0xAF, 0x7C, 0xC2, 0x7C, 0x81, 0x7C, 0x03, 0xFC, 0xD0, 0xFC, 0xE2, 0xFC, 0xA1, 0x00, 0x17, 0xBC, 0x13, 0x90, 0x16, 0x88, 0x14, 0x98, 0x10, 0x44, 0x12, 0x94, 0x17, 0x8C, 0x15, 0x9C, 0x11, 0x42, 0x15, 0x52, 0x16, 0x4A, 0x10, 0x9A, 0x13, 0xC6, 0x10, 0x56, 0x13, 0x4E, 0x16, 0x5E, 0x12, 0xC1, 0x12, 0xD1, 0x16, 0xC9, 0x12, 0xD9, 0x10, 0x25, 0x12, 0x05, 0x8B, 0x16, 0x8B, 0xEE, 0x8B, 0x51, 0x8B, 0xD9, 0x88, 0x55, 0x8B, 0x9D, 0x8B, 0xB3, 0x88, 0x43, 0xC4, 0x5B, 0xC4, 0xEF, 0x24, 0x78, 0x25, 0x7C, 0x24, 0x7A, 0x24, 0xDE, 0x24, 0x45, 0x25, 0x43, 0x24, 0x47, 0xA4, 0x10, 0xA4, 0xE4, 0xA4, 0x62, 0xA5, 0xBE, 0x49, 0xA3, 0x4B, 0xAB, 0x49, 0x27, 0x4B, 0x2F, 0xCB, 0x7C, 0x92, 0xD1, 0x95, 0xC9, 0x96, 0xD9, 0x94, 0x25, 0x96, 0x05, 0xCB, 0x16, 0xCB, 0xEE, 0xCB, 0x51, 0xC9, 0x59, 0xC9, 0x55, 0xCA, 0x9D, 0xCA, 0x33, 0xC9, 0x3B, 0xCA, 0x37, 0xC8, 0x5F, 0x2B, 0x70, 0x28, 0xB8, 0x2B, 0xB4, 0x2B, 0x3C, 0x2A, 0xF2, 0x2B, 0xFA, 0x29, 0xF6, 0x2A, 0x81, 0x94, 0xC4, 0x94, 0x42, 0x94, 0x46, 0x94, 0xDF, 0x29, 0xCB, 0x28, 0x47, 0x29, 0x4F, 0x01, 0x0C, 0xA0, 0xA4, 0x92, 0xA0, 0x32, 0xAF, 0x8A, 0xA9, 0xAA, 0x01, 0x10, 0xC0, 0x8A, 0x1A, 0x8E, 0x9A, 0x9E, 0x5A, 0xB6, 0xDA, 0x86, 0x3A, 0x91, 0xFA, 0x67, 0xF5, 0x02, 0xF5, 0x3D, 0x0D, 0x72, 0x0D, 0x33, 0x8D, 0x32, 0x8D, 0xDF, 0x9A, 0x34, 0x9A, 0xD6, 0x9A, 0x95, 0x9A, 0xA7, 0x5A, 0x8C, 0x5A, 0x0E, 0x5A, 0x75, 0x5A, 0x97, 0xDA, 0xAC, 0x80, 0xF3, 0x37, 0x69, 0xDF, 0xE8, 0x70, 0xEA, 0xB8, 0xEB, 0xB4, 0xE9, 0xDC, 0xEB, 0xF2, 0xEA, 0x7A, 0xEB, 0x76, 0xE9, 0x3E, 0xEB, 0x09, 0xEA, 0xF9, 0xEB, 0xF5, 0xE9, 0x83, 0xF4, 0x45, 0xF4, 0x83, 0xF4, 0x07, 0x0D, 0x60, 0x0C, 0x24, 0x0C, 0x42, 0x0D, 0x46, 0x0C, 0xDF, 0x19, 0x4A, 0x1B, 0x46, 0x18, 0x8E, 0x1B, 0x21, 0x1A, 0xC9, 0x02, 0x7E, 0x3F, 0xF5, 0x19, 0xF9, 0xB3, 0xC2, 0xE7, 0xD8, 0xCF, 0x33, 0xC6, 0x68, 0xC6, 0xEA, 0xC6, 0xE9, 0xC6, 0xEB, 0x60, 0x62, 0xB0, 0x29, 0xB8, 0x1C, 0x7C, 0x6A, 0xC2, 0x62, 0xE2, 0x6A, 0xD2, 0x61, 0xF2, 0x62, 0x2A, 0x6A, 0x1A, 0x6E, 0x3A, 0x69, 0x86, 0x66, 0xA6, 0x6E, 0x96, 0x61, 0xB6, 0x61, 0x4E, 0x6A, 0x6E, 0x6E, 0x5E, 0x69, 0x7E, 0x61, 0xC1, 0x6E, 0xE1, 0x69, 0xD1, 0x63, 0x09, 0x6D, 0x29, 0x65, 0x19, 0x63, 0x39, 0x67, 0x85, 0x65, 0xA5, 0x67, 0x95, 0x6F, 0xF5, 0xCB, 0x9A, 0xD6, 0xDA, 0x01, 0xF0, 0xF8, 0x7B, 0x1B, 0x41, 0x9B, 0x60, 0x9B, 0x71, 0xDB, 0xF7, 0xB6, 0x6A, 0xB6, 0xE9, 0xB6, 0x1B, 0x76, 0x64, 0x76, 0x96, 0x76, 0xD5, 0x76, 0x57, 0xF6, 0xDC, 0xF6, 0xBE, 0xF6, 0x83, 0x0E, 0xF0, 0x0E, 0x8A, 0x0E, 0x49, 0x0E, 0x3F, 0x1C, 0x09, 0x1D, 0x4D, 0x1D, 0x2B, 0x1C, 0xCF, 0x9D, 0xD8, 0x9D, 0xBC, 0x9C, 0xFA, 0x9C, 0x61, 0x9D, 0xE5, 0x9C, 0x13, 0x9C, 0x97, 0x21, 0xF8, 0x10, 0x30, 0xA4, 0x1C, 0x72, 0xE6, 0xC2, 0xE6, 0xE2, 0xE9, 0xD2, 0xEB, 0x0A, 0xEB, 0x2A, 0xE7, 0x9A, 0xE0, 0xFA, 0xDD, 0x8D, 0xC0, 0xCD, 0xC4, 0xAD, 0xC2, 0xED, 0xDC, 0x9D, 0xC3, 0xDD, 0xDB, 0xBD, 0xDF, 0x03, 0xDE, 0x43, 0xD1, 0x23, 0xD9, 0x63, 0xD5, 0x93, 0xD8, 0xD3, 0xC2, 0xB3, 0xDA, 0xF3, 0xCA, 0x8B, 0xD7, 0x2B, 0xC0, 0x6B, 0xC4, 0x1B, 0xC5, 0x5B, 0xCD, 0x3B, 0xC3, 0x7B, 0xDB, 0x87, 0xD2, 0xC7, 0xCE, 0xA7, 0xD1, 0xE7, 0xC1, 0x57, 0xC4, 0x37, 0xDC, 0x77, 0xC6, 0xEF, 0x83, 0x9F, 0x9E, 0x5F, 0xA1, 0xDF, 0xA1, 0x3F, 0x93, 0xBF, 0x9B, 0x7F, 0x77, 0x00, 0x4C, 0x80, 0x5C, 0x40, 0x62, 0xC0, 0x4A, 0x20, 0x7E, 0xA0, 0x41, 0x60, 0x4E, 0xE0, 0x46, 0x10, 0x61, 0x90, 0x61, 0x50, 0x6E, 0xD0, 0x56, 0x30, 0x51, 0xF0, 0xE7, 0xE0, 0xFC, 0xE0, 0x9D, 0x10, 0x92, 0x10, 0x70, 0x48, 0x61, 0xC8, 0x5E, 0x28, 0x79, 0xA8, 0x69, 0x68, 0x49, 0xE8, 0x7E, 0x18, 0x65, 0x98, 0x45, 0x58, 0x79, 0xD8, 0x61, 0x38, 0x6D, 0xB8, 0x4D, 0x78, 0x65, 0xF8, 0x09, 0xE0, 0xE2, 0xF6, 0x11, 0xB5, 0x11, 0x17, 0x91, 0xAC, 0x91, 0x90, 0xC8, 0xA6, 0xC8, 0x9B, 0x28, 0xCE, 0x28, 0xF7, 0xA8, 0xF6, 0xA8, 0x87, 0x68, 0xBE, 0x68, 0x9F, 0xE8, 0x9E, 0xE8, 0xD7, 0x18, 0x61, 0xC0, 0xC3, 0x07, 0x63, 0x61, 0x63, 0x25, 0x63, 0x23, 0x62, 0xC7, 0xE3, 0x90, 0xE2, 0xE4, 0xE3, 0xE2, 0xE2, 0x66, 0xE3, 0xD1, 0xE3, 0xD5, 0xE2, 0x53, 0xE2, 0xBF, 0x7F, 0xF9, 0xF4, 0x45, 0xF7, 0x4B, 0xF6, 0x97, 0xCD, 0x04, 0xE2, 0x04, 0x70, 0x42, 0x71, 0xC2, 0x7E, 0x22, 0x75, 0xA2, 0x4D, 0x62, 0x75, 0xE2, 0x79, 0x12, 0x4B, 0x12, 0x24, 0xA9, 0x25, 0xE9, 0x2E, 0x99, 0x2F, 0xD9, 0x37, 0xB9, 0x37, 0x05, 0x2A, 0x45, 0x22, 0x25, 0x3C, 0x65, 0x22, 0x15, 0x39, 0x55, 0x29, 0x35, 0x31, 0x75, 0x29, 0x0D, 0x3B, 0x4D, 0x37, 0x2D, 0x27, 0x6D, 0x3B, 0x9D, 0x2C, 0xDD, 0x3C, 0xBD, 0x22, 0xFD, 0x24, 0x83, 0x29, 0xC3, 0x39, 0xA3, 0x39, 0xE3, 0x3E, 0x93, 0x3F, 0xD3, 0x3F, 0x73, 0x30, 0x0B, 0x2E, 0x4B, 0x26, 0x2B, 0x36, 0x6B, 0x36, 0xFB, 0x43, 0xB6, 0x56, 0x76, 0x56, 0xF6, 0x66, 0x0E, 0x69, 0x8E, 0x79, 0xCE, 0xD7, 0x9C, 0xD3, 0x5C, 0x96, 0x5C, 0xD7, 0xDC, 0xF6, 0xDC, 0xE7, 0x3C, 0x91, 0xBC, 0xD0, 0xBC, 0xF1, 0x7C, 0x94, 0x7C, 0x95, 0xFC, 0x94, 0xFC, 0x1F, 0x05, 0x9F, 0x0A, 0x54, 0x0A, 0xA2, 0x0A, 0x06, 0x0A, 0x1E, 0x0B, 0xD9, 0x0B, 0xED, 0x0A, 0x4B, 0x0B, 0xB7, 0x8A, 0xB0, 0x8B, 0x94, 0x8B, 0x22, 0x8B, 0x06, 0x8A, 0x1E, 0x8B, 0xD9, 0x8B, 0xED, 0x8A, 0x4B, 0x8B, 0xB7, 0x4B, 0x70, 0x4A, 0x54, 0x4B, 0xA2, 0x4B, 0x86, 0x4A, 0x9E, 0x4B, 0xB9, 0x4A, 0x1D, 0x4B, 0x2B, 0x4A, 0x77, 0xCB, 0xF0, 0xCB, 0x34, 0xCA, 0xE2, 0xCA, 0xC6, 0xCA, 0x41, 0xE5, 0xBC, 0xE5, 0x2E, 0xE5, 0xD5, 0xE5, 0x07, 0x15, 0xC4, 0x15, 0xBA, 0x15, 0x49, 0x15, 0xD3, 0x5F, 0xE1, 0xBE, 0x0A, 0x7F, 0xF5, 0xFA, 0xDA, 0xF8, 0xF5, 0xB4, 0x92, 0xB2, 0xF2, 0x73, 0x65, 0x66, 0xE5, 0x62, 0x15, 0x4A, 0x95, 0x54, 0x55, 0x60, 0x55, 0x67, 0xD5, 0x75, 0x35, 0x63, 0xB5, 0x65, 0x75, 0x61, 0xF5, 0x7A, 0x0D, 0x56, 0x8D, 0x52, 0x4D, 0x64, 0xCD, 0x60, 0xCD, 0x73, 0x2D, 0x57, 0xAD, 0x53, 0x6D, 0x65, 0xED, 0xAF, 0x3A, 0xA2, 0x3A, 0x9D, 0xBA, 0xA4, 0xBA, 0xE9, 0xFA, 0x77, 0xF5, 0x22, 0xF5, 0xDE, 0xF5, 0xCD, 0xF5, 0xE7, 0x0D, 0x34, 0x0D, 0x26, 0x0D, 0x39, 0x0D, 0x2B, 0x8D, 0x18, 0x8D, 0xF2, 0x8D, 0x61, 0x8D, 0x7D, 0x80, 0x7F, 0x73, 0x34, 0x39, 0x34, 0x55, 0x34, 0xED, 0x35, 0x13, 0x36, 0x6B, 0x37, 0x27, 0x36, 0x4F, 0xB7, 0xBC, 0x6B, 0x11, 0x69, 0xF1, 0x69, 0x69, 0x69, 0xB9, 0x68, 0xA5, 0x6D, 0x35, 0x6B, 0xCD, 0x6B, 0xFD, 0xD1, 0x86, 0xD9, 0xA6, 0xD0, 0x16, 0xD1, 0x36, 0xD0, 0xF6, 0xD4, 0xCE, 0xD9, 0xEE, 0xD8, 0xFE, 0xB5, 0xFD, 0x67, 0x07, 0x61, 0x87, 0x76, 0x47, 0x62, 0xC7, 0x54, 0x27, 0x5C, 0xA7, 0x70, 0xA7, 0x57, 0x67, 0x53, 0xE7, 0x29, 0xE0, 0xE0, 0xC6, 0x5D, 0x59, 0x5D, 0x4B, 0xDD, 0xA8, 0xDD, 0xD2, 0xDD, 0x41, 0xDD, 0x5D, 0xDD, 0x37, 0x3D, 0x4C, 0x3D, 0x56, 0x3D, 0x45, 0x3D, 0xEB, 0xBD, 0x58, 0xBD, 0x4A, 0xBD, 0x91, 0xBD, 0x83, 0xBD, 0x4F, 0x7D, 0x9C, 0x7D, 0x0E, 0x7D, 0x15, 0x7D, 0xBB, 0xFD, 0x9F, 0xFA, 0xE5, 0xFA, 0x7D, 0xFB, 0xEB, 0xFA, 0x77, 0x07, 0x3E, 0x0E, 0x48, 0x0D, 0x78, 0x0E, 0x54, 0x0D, 0x6C, 0x0E, 0xA2, 0x0F, 0x8A, 0x0D, 0xBA, 0x0E, 0x96, 0x0F, 0xAE, 0x0E, 0x21, 0x0F, 0x09, 0x0D, 0x39, 0x0D, 0x15, 0x0D, 0x2D, 0x0D, 0xC3, 0x0F, 0xF3, 0x0E, 0xDB, 0x0E, 0xE7, 0x0E, 0xCF, 0x8E, 0x40, 0x8F, 0x70, 0x8C, 0x58, 0x8C, 0x64, 0x8C, 0x4C, 0x8E, 0x3C, 0x8F, 0x32, 0x8D, 0x1A, 0x8F, 0x26, 0x8D, 0x8E, 0x8C, 0xDE, 0x8D, 0xD1, 0x8E, 0xE9, 0x8F, 0xC5, 0x8D, 0xF5, 0x8D, 0xFD, 0x19, 0x27, 0x1F, 0xD7, 0x1C, 0x0F, 0x1F, 0x6F, 0x1F, 0x3F, 0x9E, 0x20, 0x98, 0x50, 0x9A, 0x08, 0x04, 0xDC, 0xFC, 0xD7, 0x24, 0xF6, 0xA4, 0xF4, 0xA4, 0xD7, 0x64, 0xD5, 0xE4, 0xE6, 0x14, 0xDA, 0x94, 0x08, 0xE0, 0xE7, 0x25, 0x53, 0xDF, 0xA7, 0xE1, 0xA7, 0x79, 0xA7, 0x6D, 0xA7, 0x73, 0xA6, 0xBF, 0xCD, 0x80, 0x66, 0x58, 0x67, 0x4C, 0x67, 0x52, 0x66, 0x46, 0x67, 0xEE, 0xBE, 0xD1, 0x7E, 0xD3, 0xFF, 0x16, 0xFB, 0xAD, 0xF7, 0xDB, 0xC5, 0x2C, 0xE9, 0xAC, 0xDA, 0x6C, 0xC8, 0x6C, 0xCB, 0xEC, 0xC1, 0x1C, 0xCE, 0x9C, 0xEC, 0x9C, 0xCF, 0x5C, 0xF5, 0xDC, 0xE6, 0x3C, 0xDA, 0xBC, 0xC8, 0xBC, 0xF3, 0x7C, 0xF1, 0xFC, 0xD2, 0x02, 0xDC, 0x02, 0xD7, 0x82, 0xD5, 0x42, 0xE6, 0xC2, 0xE4, 0xC2, 0xD3, 0x22, 0xE3, 0xA2, 0xD1, 0xE2, 0x97, 0xC5, 0xFE, 0xC5, 0x3F, 0x4B, 0x64, 0x4B, 0x1A, 0x4B, 0x61, 0x4B, 0xAD, 0x4B, 0xBF, 0x97, 0x71, 0x96, 0x65, 0x97, 0xBD, 0x97, 0xAB, 0x96, 0x37, 0xBE, 0xBF, 0xFF, 0x2E, 0xF4, 0xDD, 0xF1, 0x7B, 0xC1, 0xF7, 0xF9, 0x15, 0xE8, 0x15, 0xF6, 0x15, 0xB3, 0x95, 0xD4, 0x95, 0xD1, 0x95, 0x3B, 0xC0, 0xDF, 0x75, 0x7F, 0x44, 0xFF, 0xE8, 0xFA, 0x71, 0xBA, 0x4A, 0xB8, 0xAA, 0xB8, 0xEA, 0xBF, 0x5A, 0xB7, 0xBA, 0xB3, 0x86, 0xB1, 0x26, 0xB6, 0x06, 0x59, 0x2B, 0x5E, 0x5B, 0x5A, 0x87, 0x5B, 0xE7, 0x5A, 0xB7, 0x58, 0x4F, 0x5F, 0x1F, 0x5F, 0xBF, 0xDF, 0xA0, 0xDD, 0xD0, 0x03, 0x5C, 0xBE, 0x6B, 0xE3, 0x74, 0x93, 0x60, 0x53, 0x71, 0xD3, 0x7F, 0xB3, 0x76, 0x73, 0x7B, 0x0B, 0x6D, 0x4B, 0x64, 0xCB, 0x69, 0xAB, 0x70, 0x6B, 0x7E, 0x1B, 0x7A, 0x9B, 0x6D, 0xDB, 0x74, 0x3B, 0x79, 0x7B, 0x78, 0xFB, 0x66, 0x87, 0x6B, 0xC7, 0x77, 0x67, 0x68, 0x17, 0x71, 0x57, 0x79, 0x37, 0x6D, 0x77, 0x63, 0x8F, 0x7C, 0xCF, 0x7A, 0xAF, 0x6E, 0xEF, 0xEF, 0x4F, 0x81, 0x9F, 0xC1, 0x3F, 0xC7, 0x7F, 0xA1, 0xFE, 0xD2, 0xFC, 0x95, 0xFD, 0x6B, 0x77, 0x9F, 0x7A, 0xDF, 0x7E, 0xBF, 0x69, 0xFF, 0xE1, 0x40, 0xF8, 0x20, 0xEC, 0x60, 0xEA, 0x37, 0xC6, 0x6F, 0xED, 0xDF, 0xB9, 0xBF, 0xF7, 0x0E, 0x69, 0x0E, 0x1D, 0x0E, 0x9B, 0x0F, 0x1F, 0x8F, 0x84, 0x8F, 0xC2, 0x8E, 0xA6, 0x8E, 0xD1, 0x8F, 0xB5, 0x8E, 0xB3, 0x8F, 0x77, 0x4F, 0xA8, 0x4F, 0xEC, 0x4E, 0x1A, 0x4E, 0xEE, 0x4E, 0x05, 0x4E, 0x83, 0x4F, 0xC7, 0xCE, 0x50, 0xCE, 0xD4, 0xCE, 0xD2, 0xCF, 0x36, 0xCE, 0x49, 0xCF, 0x2D, 0xCE, 0xAB, 0xCF, 0xFF, 0x5C, 0x70, 0x5D, 0xF8, 0x5C, 0xF4, 0x5F, 0xC2, 0x5D, 0xCA, 0x5D, 0x7E, 0xB9, 0x5C, 0xFA, 0x83, 0xFB, 0xC7, 0xF0, 0x4F, 0xD1, 0x9F, 0xDF, 0x57, 0x0C, 0x57, 0xCE, 0x57, 0x2D, 0x57, 0x8F, 0xD7, 0xC2, 0xD7, 0x21, 0xD7, 0xE3, 0x37, 0xEF, 0x6F, 0x54, 0x6F, 0xD2, 0x6E, 0xD6, 0xFE, 0x12, 0xFF, 0x35, 0xFD, 0x5B, 0xF1, 0xF7, 0xF4, 0x96, 0xE5, 0xD6, 0xED, 0xB6, 0xE3, 0xF6, 0xE5, 0x4E, 0xEC, 0x2E, 0xFC, 0x6E, 0x12, 0x70, 0x7E, 0xB5, 0xFB, 0xB4, 0xFB, 0xF5, 0x07, 0xE2, 0x07, 0xD3, 0x87, 0xF2, 0x87, 0x93, 0x47, 0xE6, 0x47, 0x97, 0xC7, 0xB6, 0xC7, 0xC7, 0x27, 0xA1, 0xA7, 0xE0, 0xA7, 0xD1, 0x67, 0xA4, 0x67, 0xC5, 0xE7, 0xC4, 0xE7, 0xE5, 0x17, 0x9C, 0x17, 0x83, 0x97, 0x82, 0x97, 0x9F, 0xAF, 0xD4, 0xAF, 0x36, 0xAF, 0xB5, 0xAF, 0x7F, 0xDE, 0x38, 0xDF, 0x3C, 0xDF, 0xBA, 0xFF, 0xF1, 0x7F, 0x09, 0x50, 0x04, 0x68, 0x0A, 0x0A, 0x15, 0x4A, 0x0D, 0x2A, 0x15, 0x6A, 0x15, 0x9A, 0x00, 0xDA, 0x18, 0xBA, 0x18, 0xFA, 0x37, 0x0C, 0x1D, 0x8C, 0x03, 0x4C, 0x03, 0xCC, 0x0D, 0x2C, 0x0F, 0xAC, 0x0F, 0x6C, 0x1F, 0x1C, 0x34, 0x9C, 0x14, 0x5C, 0x14, 0xDC, 0xF4, 0x3B, 0xF4, 0x77, 0xEA, 0xEF, 0xD2, 0xDE, 0xAD, 0xC1, 0x13, 0xC2, 0x1B, 0xC3, 0x97, 0xC0, 0xFF, 0x46, 0xA0, 0x43, 0x70, 0x40, 0x68, 0x40, 0xB8, 0x41, 0xE4, 0x41, 0xF4, 0x41, 0xEC, 0x45, 0x82, 0x42, 0x92, 0x44, 0x8A, 0x44, 0x9A, 0x42, 0x46, 0x45, 0x56, 0x45, 0x4E, 0x45, 0xFE, 0x81, 0x82, 0x8F, 0x62, 0x84, 0x52, 0x88, 0xB2, 0xFF, 0x9E, 0xE6, 0xBD, 0xED, 0xFB, 0xDA, 0xF7, 0x7F, 0x50, 0x39, 0x50, 0x3D, 0x50, 0x3B, 0x51, 0x5F, 0xD1, 0x44, 0xD1, 0x42, 0xD1, 0xC6, 0xD0, 0x91, 0xD0, 0x15, 0xD1, 0x13, 0xD0, 0x17, 0x31, 0xB0, 0x31, 0x74, 0x31, 0x72, 0x30, 0xB6, 0x31, 0xC9, 0x30, 0xCD, 0x31, 0x2B, 0x30, 0x4F, 0x3E, 0x30, 0x7D, 0x70, 0xFE, 0xD0, 0xFC, 0xE1, 0xEE, 0x23, 0x1F, 0x40, 0x05, 0xFD, 0x58, 0x30, 0x58, 0x52, 0x58, 0x51, 0x58, 0xD3, 0xD8, 0x68, 0x00, 0x17, 0xA4, 0x60, 0xAF, 0x7C, 0xC2, 0xFB, 0x64, 0xF8, 0xA9, 0xE0, 0xD3, 0x4F, 0x1C, 0x2A, 0x1C, 0x6B, 0x9C, 0x2A, 0x9C, 0x73, 0x5C, 0x56, 0x5C, 0x57, 0xDC, 0x36, 0xDC, 0x47, 0x3C, 0x01, 0xBC, 0x00, 0xBC, 0x41, 0x7C, 0x38, 0x7C, 0x19, 0xFC, 0x68, 0xFC, 0x19, 0x02, 0x74, 0x02, 0x75, 0x82, 0x54, 0x82, 0x1F, 0x84, 0xF8, 0x84, 0x46, 0x84, 0x05, 0x84, 0x3F, 0x89, 0xA8, 0x88, 0xAC, 0x88, 0xAA, 0x88, 0xCE, 0x89, 0x59, 0x89, 0x5D, 0x88, 0x5B, 0x89, 0x1F, 0x48, 0x38, 0x49, 0x9C, 0x48, 0xAA, 0x48, 0x0E, 0x48, 0xC9, 0x48, 0x0D, 0x49, 0x33, 0x48, 0x17, 0xC9, 0xD0, 0xC8, 0xE4, 0xC8, 0xC2, 0xC8, 0xFA, 0xC9, 0x9E, 0xC8, 0xB9, 0xC9, 0x21, 0xE4, 0x35, 0xE4, 0x87, 0x14, 0xE4, 0x14, 0x46, 0x14, 0x99, 0x14, 0xCB, 0x94, 0xE8, 0x94, 0xF2, 0x94, 0xE1, 0x94, 0x03, 0x00, 0x27, 0x70, 0x53, 0x41, 0xA8, 0x6A, 0xA8, 0x0E, 0xA9, 0xC9, 0xA9, 0x8D, 0xA8, 0x33, 0xA9, 0x97, 0x68, 0xD0, 0x68, 0xE4, 0x68, 0xC2, 0x68, 0xFA, 0x69, 0x9E, 0x68, 0xB9, 0x68, 0x9D, 0x69, 0xAB, 0x69, 0x7F, 0xD3, 0x91, 0xD1, 0x19, 0xD2, 0x65, 0xD0, 0x2D, 0xD2, 0xA3, 0xD2, 0xCB, 0xD0, 0x87, 0xD0, 0xF7, 0xD2, 0x3F, 0x30, 0x70, 0x00, 0xB4, 0x50, 0xC9, 0xF0, 0x8B, 0x91, 0x98, 0x51, 0x8F, 0x31, 0x95, 0x71, 0x8E, 0x09, 0x99, 0x49, 0x92, 0x29, 0x90, 0xA9, 0x8B, 0xE9, 0x96, 0x99, 0x95, 0xD9, 0x8E, 0xB9, 0x8C, 0x79, 0x97, 0x85, 0x80, 0x45, 0x9B, 0x25, 0x09, 0x20, 0x06, 0x04, 0x56, 0x31, 0x56, 0x3F, 0xD6, 0x76, 0xD6, 0x6B, 0x36, 0x26, 0x36, 0x6B, 0xB6, 0x12, 0xB6, 0x6D, 0x76, 0x5C, 0x76, 0x0D, 0xF6, 0x2F, 0xEC, 0x93, 0x1C, 0x70, 0x1C, 0x22, 0x1C, 0x3E, 0x1C, 0xAD, 0x1C, 0x7F, 0x38, 0xE9, 0x39, 0x2D, 0x38, 0x0B, 0x39, 0x37, 0xB8, 0x3E, 0x71, 0xA9, 0x71, 0xC5, 0x71, 0x8D, 0x71, 0x43, 0x73, 0x0B, 0x72, 0x7B, 0x02, 0xDC, 0x70, 0xCE, 0x43, 0xC3, 0x63, 0xCA, 0x93, 0xC7, 0xB3, 0xCA, 0xFB, 0x91, 0x57, 0x89, 0x37, 0x8A, 0x77, 0x98, 0xF7, 0x8D, 0x8F, 0x8F, 0xCF, 0x95, 0xAF, 0x8E, 0xEF, 0x98, 0x9F, 0x92, 0xFF, 0x33, 0x7F, 0x16, 0xFF, 0xB2, 0x00, 0x9A, 0x80, 0x1C, 0x90, 0x29, 0xF4, 0x09, 0x3C, 0x0A, 0x72, 0x0A, 0x3A, 0x0A, 0x56, 0x0A, 0xEE, 0x0B, 0x11, 0x0B, 0xE9, 0x09, 0xA5, 0x08, 0xCD, 0x0A, 0x23, 0x01, 0xA9, 0x42, 0x80, 0x70, 0x87, 0xF0, 0x8D, 0x08, 0x8B, 0x88, 0xBD, 0x48, 0xA5, 0xC8, 0x81, 0x28, 0xB9, 0xA8, 0xB1, 0x68, 0xAE, 0xE8, 0xAA, 0x18, 0xB6, 0x98, 0xBA, 0xD8, 0x17, 0xB1, 0x69, 0x71, 0x04, 0x71, 0x49, 0xF1, 0x60, 0xF1, 0x5E, 0xF1, 0x27, 0x09, 0x6E, 0x09, 0x57, 0x89, 0x7A, 0x89, 0x33, 0x49, 0x5A, 0x49, 0x0B, 0xC9, 0x22, 0x20, 0x53, 0xC0, 0x97, 0xD2, 0x96, 0x4A, 0x91, 0x9A, 0x93, 0x46, 0x91, 0x96, 0x95, 0x0E, 0x93, 0x1E, 0x90, 0x7E, 0x91, 0xE1, 0x93, 0x71, 0x97, 0x69, 0x94, 0x39, 0x97, 0xA5, 0x93, 0xB5, 0x04, 0x28, 0x62, 0x5B, 0x0E, 0x5F, 0x4E, 0x5B, 0x2E, 0x59, 0x6E, 0x56, 0x1E, 0x59, 0x5E, 0x5A, 0x3E, 0x44, 0xBE, 0x4F, 0xFE, 0x49, 0x81, 0x5B, 0xC1, 0x45, 0xA1, 0x4E, 0xE1, 0x44, 0x91, 0x5A, 0xD1, 0x54, 0x31, 0x5F, 0x71, 0x4D, 0x09, 0x5B, 0x49, 0x4D, 0x29, 0x5E, 0x69, 0x52, 0x19, 0x4E, 0x59, 0x54, 0xD9, 0x4F, 0xB9, 0x43, 0xF9, 0x46, 0x85, 0x45, 0xC5, 0x4E, 0xA5, 0x5C, 0xE5, 0xA7, 0x2A, 0xB1, 0xAA, 0x9E, 0x6A, 0x9A, 0xEA, 0xBC, 0xDA, 0x7B, 0x35, 0x19, 0xB5, 0x50, 0xB5, 0x3E, 0xB5, 0x27, 0x75, 0x2E, 0x75, 0x88, 0x7A, 0x8D, 0xFA, 0x91, 0x06, 0x85, 0x86, 0xB1, 0x46, 0xB6, 0xC6, 0x77, 0x4D, 0x4C, 0x4D, 0x45, 0xCD, 0x48, 0xCD, 0x61, 0xCD, 0x37, 0x2D, 0x3E, 0x2D, 0x37, 0xAD, 0x06, 0xAD, 0x53, 0x6D, 0x1A, 0x6D, 0x53, 0xED, 0x3C, 0xED, 0x35, 0x1D, 0x2C, 0x1D, 0x55, 0x9D, 0x58, 0x9D, 0x71, 0x5D, 0x18, 0x5D, 0x61, 0x80, 0x28, 0x5A, 0x75, 0xAF, 0xF4, 0x18, 0xF5, 0xAC, 0xF5, 0x4A, 0xF5, 0x76, 0xF4, 0x09, 0xF4, 0x75, 0xF4, 0x53, 0xF4, 0x67, 0x0D, 0x90, 0x0D, 0xA4, 0x0D, 0x42, 0x0C, 0xFA, 0x0C, 0x1E, 0x0D, 0xB9, 0x0C, 0x21, 0x40, 0x8A, 0x70, 0x6C, 0x44, 0x65, 0x64, 0x62, 0x94, 0x67, 0xB4, 0xF6, 0x19, 0xFB, 0xB3, 0xDA, 0xE7, 0xF8, 0xCF, 0x93, 0xC6, 0xF0, 0xC6, 0x52, 0xC6, 0x61, 0xC6, 0xC3, 0x60, 0x18, 0xB0, 0x18, 0x38, 0x08, 0xDC, 0x0F, 0x7E, 0x33, 0x11, 0x36, 0xF1, 0x37, 0xE9, 0x31, 0x79, 0x36, 0xE5, 0x37, 0xF5, 0x31, 0xED, 0x34, 0x7D, 0x30, 0xE3, 0x35, 0xF3, 0x34, 0x6B, 0x33, 0xBB, 0x33, 0xE7, 0x32, 0x77, 0x33, 0x6F, 0x31, 0xBF, 0xB1, 0xE0, 0xB0, 0x70, 0xB1, 0x68, 0xB2, 0xB8, 0xB2, 0x64, 0xB3, 0x74, 0xB6, 0x6C, 0xB0, 0xBC, 0xB4, 0x62, 0xB1, 0x72, 0xB2, 0xAA, 0xB3, 0xBA, 0xB0, 0x66, 0xB6, 0x76, 0xB4, 0xAE, 0xB5, 0x3E, 0xB7, 0x61, 0xB2, 0x71, 0xB0, 0xA9, 0xB5, 0x39, 0xB7, 0x65, 0xB2, 0x75, 0xB0, 0xAD, 0xB5, 0x3D, 0xB7, 0x63, 0xB2, 0x73, 0xB0, 0xAB, 0xB5, 0xBB, 0xB0, 0x67, 0xB6, 0x77, 0xB4, 0xAF, 0xB3, 0xBF, 0x74, 0x60, 0x71, 0x70, 0x76, 0x68, 0x70, 0xF8, 0xE3, 0xC8, 0xE6, 0x08, 0x71, 0x6C, 0x72, 0xBC, 0x71, 0xE2, 0x70, 0x72, 0x73, 0x6A, 0x75, 0xBA, 0x05, 0xB2, 0x03, 0x4F, 0xE7, 0x0E, 0xE7, 0x07, 0x08, 0x1F, 0xC4, 0x07, 0xD2, 0x0D, 0x79, 0x71, 0x11, 0x72, 0x09, 0x70, 0xE9, 0x77, 0x85, 0x72, 0x15, 0x73, 0x0D, 0x75, 0x1D, 0x71, 0x7B, 0xE7, 0x26, 0xED, 0x16, 0xE9, 0x36, 0xE9, 0x8E, 0xEC, 0xAE, 0xE0, 0x1E, 0xEF, 0x3E, 0xEB, 0x81, 0xEE, 0xA1, 0x06, 0x30, 0xC6, 0xB2, 0x27, 0xB6, 0xA7, 0x8E, 0x67, 0xA6, 0xE7, 0xBA, 0x17, 0xA1, 0x97, 0x91, 0x57, 0x81, 0xD7, 0x9E, 0x37, 0xB9, 0xB7, 0xB9, 0x77, 0xB9, 0xF7, 0x91, 0x0F, 0x1D, 0x40, 0x19, 0xB5, 0x3E, 0x97, 0xBE, 0x6C, 0xBE, 0xAE, 0xBE, 0xAD, 0xBE, 0xF7, 0x7E, 0x7C, 0x7E, 0xBE, 0x7E, 0xBD, 0xFE, 0x20, 0x7F, 0x31, 0xFF, 0x50, 0xFF, 0xD1, 0x00, 0xC4, 0x00, 0xF9, 0x80, 0xB8, 0x80, 0xD9, 0x40, 0xF4, 0x40, 0xA5, 0xC0, 0xB8, 0xC0, 0xA9, 0x20, 0xC4, 0x20, 0xE9, 0xA0, 0xB0, 0xA0, 0xA1, 0x60, 0xA8, 0x60, 0x91, 0x60, 0xFF, 0xE0, 0xEE, 0xE0, 0xA7, 0x10, 0xDE, 0x10, 0xCF, 0x90, 0xD6, 0x90, 0xBF, 0xA1, 0xEC, 0xA1, 0x90, 0xD0, 0xFA, 0xD0, 0x8B, 0x30, 0xA6, 0x30, 0xBB, 0xB0, 0xAA, 0xB0, 0x63, 0x80, 0x34, 0xAC, 0xC2, 0xCB, 0xC3, 0x0F, 0x22, 0x28, 0x23, 0xCC, 0x22, 0x8A, 0x23, 0xF6, 0x22, 0x49, 0x81, 0xBC, 0xA0, 0x20, 0x72, 0x3B, 0x8A, 0x28, 0xCA, 0x30, 0x2A, 0x37, 0x6A, 0x23, 0x9A, 0x20, 0x5A, 0x3F, 0x3A, 0x3B, 0x7A, 0x2D, 0x06, 0x2F, 0x46, 0x2F, 0x26, 0x33, 0x66, 0x35, 0x16, 0x37, 0x56, 0x37, 0x36, 0x33, 0x76, 0x35, 0x0E, 0x37, 0x4E, 0x37, 0x2E, 0x33, 0x6E, 0x35, 0x1E, 0x37, 0x5E, 0x37, 0x3E, 0x33, 0x7E, 0xED, 0x0B, 0xDE, 0x17, 0x3D, 0x80, 0x35, 0xD6, 0x81, 0xB4, 0xC0, 0x20, 0x21, 0x37, 0x61, 0x2B, 0x91, 0x28, 0xF1, 0x73, 0x62, 0x41, 0xE2, 0x6E, 0x12, 0x59, 0x92, 0x69, 0x52, 0x49, 0xD2, 0x7E, 0x32, 0x55, 0xB2, 0x65, 0x72, 0x45, 0xF2, 0x51, 0x0A, 0x7D, 0x8A, 0x5D, 0x4A, 0x4D, 0xCA, 0x45, 0x2A, 0x4B, 0x2A, 0x24, 0xB5, 0x29, 0xF5, 0x6F, 0x1A, 0x77, 0x9A, 0x57, 0x5A, 0x67, 0xDA, 0x73, 0xBA, 0x50, 0x7A, 0x60, 0xFA, 0x60, 0x06, 0x6C, 0x86, 0x54, 0x46, 0x64, 0xC6, 0x64, 0xE6, 0xFB, 0x4C, 0xE5, 0xCC, 0xC4, 0xCC, 0xA5, 0x2C, 0xEC, 0x2C, 0x9D, 0xAC, 0xEC, 0xAC, 0xCD, 0x6C, 0x92, 0x6C, 0x53, 0x20, 0x29, 0x38, 0xCC, 0xA1, 0xCF, 0xB1, 0xCF, 0xA9, 0xCF, 0xB9, 0xCE, 0xE5, 0xCA, 0xF5, 0xCA, 0xED, 0xCE, 0x7D, 0xCB, 0x13, 0xCB, 0x0B, 0x03, 0x68, 0x03, 0x39, 0x5F, 0x29, 0x3F, 0x31, 0x7F, 0xB9, 0x00, 0xBB, 0x40, 0xA3, 0x20, 0xA9, 0x60, 0xBE, 0x10, 0xAD, 0x50, 0xB1, 0x30, 0xB6, 0x70, 0xB2, 0x08, 0xA1, 0x48, 0xBA, 0x28, 0xAC, 0x68, 0xB8, 0x18, 0xBA, 0x58, 0xB4, 0x38, 0xA0, 0xB8, 0xB7, 0xF8, 0xB9, 0x84, 0xBF, 0xC4, 0xBB, 0xA4, 0xA3, 0xE4, 0x0E, 0x20, 0x0D, 0xB7, 0xD2, 0xE6, 0xD2, 0xEB, 0x32, 0xD6, 0x32, 0xA7, 0xB2, 0xBA, 0xB2, 0xF3, 0x72, 0xC6, 0x72, 0x3B, 0x80, 0x33, 0x4E, 0x2A, 0xE8, 0x2A, 0xAC, 0x2B, 0x2A, 0x2A, 0x0E, 0xBF, 0x52, 0x7F, 0xB5, 0xF8, 0x5A, 0xFA, 0x75, 0xBF, 0x92, 0xA2, 0xD2, 0xB4, 0xB2, 0xB8, 0x72, 0xAF, 0x8A, 0xB4, 0xCA, 0xB8, 0xAA, 0xA0, 0x6A, 0xBB, 0x9A, 0xA8, 0xDA, 0xB0, 0x3A, 0x07, 0x60, 0x0C, 0xBC, 0x1A, 0xDD, 0x9A, 0x8C, 0x9A, 0x95, 0x5A, 0xAC, 0x5A, 0x8D, 0xDA, 0xE4, 0xDA, 0x85, 0x3A, 0xF4, 0x3A, 0xE5, 0xBA, 0x78, 0x80, 0x30, 0x90, 0xEB, 0xE5, 0xEA, 0x23, 0xEB, 0xC7, 0x1A, 0xE0, 0x1A, 0x24, 0x1A, 0x82, 0x1B, 0xFA, 0x1B, 0xDE, 0x1A, 0x05, 0x1B, 0x7D, 0x1A, 0x3B, 0x1B, 0xEF, 0x9B, 0xB8, 0x9A, 0x5C, 0x9B, 0x9A, 0x9A, 0xFE, 0x34, 0x33, 0x37, 0xDB, 0x37, 0x57, 0x35, 0x1F, 0xB5, 0x50, 0xB7, 0x98, 0xB7, 0x14, 0xB7, 0xEC, 0xB4, 0x12, 0xB5, 0x1A, 0xB4, 0x66, 0x01, 0x74, 0x81, 0xD5, 0xA6, 0xDE, 0x96, 0xD8, 0xF6, 0xAD, 0x1D, 0xA5, 0x5D, 0xB6, 0x3D, 0xA2, 0x7D, 0xB8, 0x03, 0xBA, 0x43, 0xB8, 0xC3, 0xAF, 0xA3, 0xB3, 0xE3, 0xAE, 0x93, 0xB3, 0x13, 0xD2, 0x59, 0x07, 0xB0, 0x05, 0x6D, 0x97, 0x65, 0x57, 0x49, 0xD7, 0x6E, 0x37, 0x51, 0xB7, 0x7E, 0x77, 0x46, 0xF7, 0x72, 0x0F, 0x66, 0x8F, 0x72, 0x4F, 0x6C, 0xCF, 0x78, 0x2F, 0x5C, 0xAF, 0x58, 0x6F, 0x40, 0x6F, 0x57, 0xEF, 0x3D, 0x40, 0x16, 0xCE, 0x7D, 0xB5, 0x7D, 0xC7, 0xFD, 0xF4, 0xFD, 0x8E, 0xFD, 0x8D, 0xFD, 0xB7, 0x03, 0xBC, 0x03, 0x7E, 0x03, 0xFD, 0x83, 0x30, 0x83, 0xD2, 0x83, 0xD1, 0x83, 0x33, 0x43, 0xE8, 0x43, 0xEA, 0x43, 0x69, 0x43, 0xAB, 0xC3, 0x04, 0xC3, 0x9F, 0x87, 0x8B, 0x86, 0xF7, 0x47, 0x68, 0x46, 0x6C, 0x47, 0x6A, 0x47, 0x2E, 0x47, 0xD9, 0x47, 0xDD, 0x47, 0xDB, 0x47, 0x9F, 0xC6, 0x84, 0xC6, 0x02, 0xC7, 0x86, 0xC6, 0xE1, 0xC6, 0x65, 0xC6, 0xA3, 0xC7, 0x67, 0x26, 0xD0, 0x26, 0x54, 0x27, 0x92, 0x27, 0xBE, 0x4F, 0xE2, 0x00, 0x69, 0x40, 0xCE, 0xE4, 0xF6, 0x14, 0xE9, 0x94, 0xE9, 0x54, 0xE9, 0xD4, 0xEF, 0x69, 0x5A, 0x80, 0x1C, 0x6A, 0xA6, 0x2F, 0x00, 0x6E, 0x70, 0x99, 0x69, 0x01, 0xA8, 0x81, 0xF7, 0x9B, 0xCF, 0xB7, 0x9E, 0x6F, 0xAF, 0xB3, 0x22, 0xB3, 0xC1, 0xB3, 0xC3, 0x73, 0xEF, 0xE6, 0xA4, 0xE7, 0xA2, 0xE6, 0xA6, 0xE6, 0x51, 0xE6, 0x95, 0xE6, 0xBF, 0xCC, 0xCF, 0x2F, 0x7C, 0x58, 0xD0, 0x58, 0x48, 0x5B, 0x58, 0x59, 0xC4, 0x5D, 0xD4, 0x5B, 0xCC, 0x5E, 0xDC, 0x5C, 0x22, 0x5A, 0x32, 0x5E, 0x2A, 0x5C, 0xFA, 0xB9, 0x4C, 0xB1, 0x6C, 0xBE, 0x5C, 0xBE, 0x7C, 0xF8, 0x9D, 0xF6, 0xBB, 0xCD, 0xF7, 0xEA, 0xEF, 0x67, 0x2B, 0x4C, 0x2B, 0x8E, 0x2B, 0x0D, 0x2B, 0x57, 0x3F, 0xD8, 0x7F, 0xB8, 0xFE, 0x68, 0xF9, 0x71, 0xB7, 0xCA, 0x03, 0xAC, 0xFC, 0x3B, 0x57, 0x9F, 0xD6, 0x04, 0xD6, 0xFC, 0xD6, 0x7A, 0xD7, 0xDE, 0xD6, 0x45, 0xD6, 0x83, 0xD6, 0x07, 0x37, 0x60, 0x36, 0x24, 0x36, 0xC2, 0x36, 0x46, 0x37, 0xE1, 0x37, 0xA5, 0x37, 0x23, 0x37, 0x27, 0xB6, 0x90, 0xB6, 0xE4, 0xB7, 0x62, 0xB6, 0xA6, 0xB7, 0xDF, 0x6F, 0x2B, 0x6D, 0xC7, 0x6F, 0xCF, 0xEE, 0x60, 0xEC, 0xE8, 0xED, 0x14, 0xED, 0x9C, 0xEC, 0xB2, 0xEF, 0xFA, 0xEE, 0x0E, 0xEF, 0xA1, 0xEC, 0x69, 0xEC, 0xE5, 0xEE, 0xED, 0xFF, 0x64, 0xFC, 0xE9, 0xF6, 0xB3, 0xE7, 0xD7, 0xBB, 0x5F, 0x4A, 0xBF, 0xD2, 0x7E, 0x6D, 0xED, 0x53, 0xED, 0x3B, 0xEC, 0xB7, 0xEE, 0xBF, 0x1E, 0x48, 0x1D, 0xC4, 0x1F, 0x2C, 0xFF, 0x26, 0xFC, 0x6D, 0xFE, 0xBB, 0xE6, 0xF7, 0xDF, 0x43, 0x81, 0xC3, 0xD0, 0xC3, 0xE9, 0xA3, 0x0F, 0x47, 0xFA, 0x47, 0xC5, 0x47, 0xC7, 0xC7, 0x6C, 0xC7, 0xDE, 0xC7, 0x03, 0x27, 0x88, 0x27, 0x2A, 0x27, 0x19, 0x27, 0xDB, 0xA7, 0x54, 0xA7, 0x0E, 0xA7, 0x2D, 0xA7, 0xCF, 0x67, 0x12, 0x67, 0x31, 0x67, 0x0B, 0xE7, 0x78, 0xE7, 0xE0, 0xF3, 0x8A, 0xF3, 0x0B, 0x80, 0x01, 0xFC, 0x2F, 0x46, 0x2E, 0x51, 0x2E, 0xD5, 0x2F, 0xB3, 0x2E, 0x77, 0xFF, 0xD0, 0xFC, 0x71, 0xFC, 0xD3, 0xFA, 0xE7, 0xE5, 0x4A, 0xE2, 0x2A, 0xE6, 0x6A, 0xFE, 0x1A, 0xE7, 0xFA, 0xF3, 0x75, 0x19, 0xB0, 0xF2, 0x67, 0xBF, 0xF1, 0xBE, 0x19, 0xF8, 0x0B, 0xFF, 0x57, 0xE9, 0x6F, 0xEA, 0xDF, 0xF5, 0x5B, 0xB2, 0x5B, 0xAB, 0xDB, 0xBA, 0xDB, 0xDB, 0x3B, 0x81, 0xBB, 0xE0, 0xBB, 0x89, 0x7B, 0xB4, 0x7B, 0xAD, 0xFB, 0x9C, 0xFB, 0xBD, 0x07, 0xDA, 0x07, 0xC7, 0x87, 0x96, 0x87, 0xE7, 0x47, 0xB1, 0xC7, 0xC8, 0xC7, 0x6F, 0x4F, 0x1F, 0x9F, 0xF4, 0x9E, 0x0A, 0x9E, 0x7E, 0x03, 0xAB, 0x7F, 0x97, 0xE7, 0x8E, 0xE7, 0xB7, 0x17, 0xC9, 0x97, 0x98, 0x97, 0xB9, 0x57, 0xEC, 0x57, 0x83, 0xD7, 0xA2, 0xD7, 0xC3, 0x37, 0xA6, 0x37, 0xD7, 0xB7, 0x8E, 0x7F, 0xFC, 0x5F, 0x1A, 0x14, 0x07, 0x5A, 0x82, 0xC2, 0x83, 0x02, 0x43, 0x95, 0x43, 0x9D, 0x43, 0x73, 0x40, 0x7B, 0x43, 0x0F, 0xC0, 0xC0, 0xC3, 0x28, 0xC1, 0xA4, 0xC0, 0xAC, 0xC1, 0x92, 0xC2, 0x5A, 0xC2, 0xD6, 0xC0, 0x5E, 0xC3, 0xF1, 0xC1, 0x05, 0xC2, 0x8D, 0xBE, 0x43, 0x79, 0xA7, 0xF6, 0x2E, 0xF3, 0xDD, 0x36, 0x3C, 0x25, 0xBC, 0x2D, 0x7C, 0x03, 0xFC, 0x1D, 0x82, 0x20, 0x42, 0x08, 0xC2, 0x04, 0x22, 0x1A, 0xA2, 0x26, 0x62, 0x36, 0xE2, 0x2E, 0xD0, 0x07, 0xD8, 0x23, 0x35, 0x21, 0x3D, 0x20, 0x0B, 0x23, 0x87, 0x21, 0x4F, 0xA1, 0xA0, 0xA3, 0x68, 0xA1, 0xE4, 0xA0, 0xEC, 0x01, 0xDE, 0x6F, 0xFF, 0xBE, 0xE9, 0xFD, 0x03, 0xAA, 0x10, 0x6A, 0x28, 0xEA, 0x24, 0x1A, 0x1A, 0x9A, 0x26, 0x5A, 0x36, 0xDA, 0x0E, 0x3A, 0x15, 0xBA, 0x2D, 0x7A, 0x03, 0xFA, 0x1D, 0x86, 0x00, 0x46, 0x30, 0xC6, 0x18, 0x26, 0x0A, 0xA6, 0x1A, 0x66, 0x3A, 0xE6, 0xE6, 0x07, 0xB2, 0x0F, 0x56, 0x1F, 0x6A, 0x3E, 0x5C, 0x7D, 0xE4, 0x01, 0x9C, 0x7F, 0x10, 0x0B, 0x01, 0x68, 0x08, 0x92, 0xB0, 0x56, 0xB0, 0x09, 0xB1, 0x4D, 0xB0, 0xCB, 0x81, 0x44, 0x80, 0xF5, 0x93, 0x07, 0xD0, 0x12, 0x40, 0xE1, 0x48, 0xE1, 0xC4, 0xE0, 0xCC, 0xE1, 0x62, 0xE1, 0xEA, 0xE1, 0xE6, 0xE3, 0xFE, 0xC2, 0xA3, 0xC5, 0x73, 0xC0, 0x6B, 0xC2, 0xBB, 0xC7, 0x17, 0xC4, 0x0F, 0xC6, 0x1F, 0x23, 0x40, 0x21, 0x50, 0x25, 0x48, 0x23, 0x58, 0x27, 0x24, 0x21, 0x34, 0x27, 0xAC, 0x24, 0x3C, 0x27, 0x62, 0x27, 0xF2, 0x24, 0xEA, 0x21, 0x86, 0x26, 0x96, 0x22, 0x8E, 0x21, 0x9E, 0x23, 0xC1, 0x00, 0x92, 0x81, 0x40, 0x92, 0x36, 0x92, 0x0B, 0x52, 0x2A, 0x52, 0x23, 0xA0, 0x35, 0x98, 0x21, 0x83, 0x23, 0x13, 0x20, 0x73, 0x25, 0xAB, 0x22, 0xDB, 0x23, 0xC7, 0x23, 0x57, 0x25, 0x8F, 0x22, 0xEF, 0x27, 0xBF, 0xA7, 0x60, 0xA6, 0xB0, 0xA0, 0xC8, 0x03, 0x9C, 0xFF, 0x3D, 0xA5, 0x04, 0xA5, 0x0F, 0x65, 0x13, 0xE5, 0x31, 0x15, 0x29, 0x95, 0x0E, 0x55, 0x02, 0xD5, 0x18, 0xD5, 0x2B, 0x35, 0x27, 0xB5, 0x3D, 0x75, 0x09, 0xF5, 0x3A, 0x0D, 0x26, 0x8D, 0x2C, 0x4D, 0x10, 0x4D, 0x3B, 0xCD, 0x05, 0x2D, 0x15, 0xAD, 0x21, 0x6D, 0x0A, 0xED, 0x14, 0x1D, 0x0C, 0x1D, 0x1F, 0x9D, 0x33, 0x5D, 0x05, 0xDD, 0x36, 0x3D, 0x36, 0xBD, 0x22, 0x7D, 0x28, 0x7D, 0x17, 0xFD, 0x15, 0x03, 0x2D, 0x83, 0x31, 0x43, 0x3A, 0xC3, 0x37, 0x46, 0x38, 0x46, 0x01, 0x46, 0x17, 0xC6, 0x4A, 0xC6, 0x5D, 0x26, 0x1C, 0x26, 0x65, 0xA6, 0x70, 0xA6, 0x6E, 0xA6, 0x6B, 0x66, 0x3A, 0x66, 0x30, 0x73, 0x06, 0xF3, 0x2C, 0x0B, 0x1C, 0x8B, 0x00, 0x8B, 0x0B, 0x4B, 0x25, 0xCB, 0x2E, 0xEB, 0x27, 0x56, 0x25, 0xD6, 0x30, 0xD6, 0x6E, 0xD6, 0x2B, 0x36, 0x5A, 0x36, 0x63, 0xB6, 0x34, 0xB6, 0x19, 0x76, 0x58, 0x76, 0x3E, 0x76, 0x67, 0xF6, 0x72, 0xF6, 0x2D, 0x0E, 0x2C, 0x0E, 0x79, 0x8E, 0x60, 0x8E, 0x76, 0x8E, 0x0B, 0x4E, 0x4A, 0x4E, 0x03, 0xCE, 0x64, 0xCE, 0x09, 0x2E, 0x10, 0x17, 0x37, 0x90, 0x1D, 0x94, 0x70, 0xAD, 0x73, 0x63, 0x72, 0xCB, 0x70, 0x07, 0x70, 0xB7, 0x72, 0x9F, 0xF1, 0x50, 0xF0, 0xE8, 0xF3, 0x24, 0xF1, 0x8C, 0xF3, 0xBC, 0xF1, 0x72, 0xF1, 0xDA, 0xF3, 0x96, 0xF0, 0xAE, 0xF3, 0x61, 0xF2, 0xC9, 0xF2, 0x05, 0xF1, 0xB5, 0xF3, 0x5D, 0xF0, 0x53, 0xF1, 0x1B, 0xF2, 0xA7, 0xF0, 0x4F, 0x09, 0xC0, 0x08, 0xF0, 0x09, 0x38, 0x0B, 0x54, 0x08, 0xEC, 0x08, 0x7E, 0x12, 0x54, 0x02, 0xDA, 0x85, 0x1E, 0xC1, 0x1B, 0x21, 0x06, 0x21, 0x53, 0xA1, 0x2C, 0xA1, 0x05, 0x61, 0x44, 0x61, 0x51, 0x61, 0x4F, 0xE1, 0x7A, 0xE1, 0xDF, 0x22, 0xC4, 0x22, 0x5A, 0x22, 0xF1, 0x22, 0x23, 0x22, 0xCF, 0xA2, 0x1C, 0xA2, 0xB6, 0xA2, 0x45, 0xA2, 0x6B, 0x62, 0x18, 0x62, 0xB2, 0x62, 0x81, 0x62, 0x6D, 0x62, 0x17, 0xE2, 0x54, 0xE2, 0x86, 0xE2, 0x29, 0xE2, 0xD3, 0x12, 0x30, 0x12, 0x7C, 0x12, 0xCE, 0x12, 0x5F, 0x25, 0x76, 0x24, 0x3F, 0x49, 0x2A, 0x49, 0x86, 0x49, 0xF6, 0x48, 0xDE, 0x48, 0xD1, 0x4B, 0x99, 0x48, 0x65, 0x02, 0x3C, 0x80, 0x20, 0x2D, 0x2C, 0xED, 0x2E, 0x5D, 0x23, 0xFD, 0x4B, 0x06, 0x1F, 0xE8, 0x18, 0xA2, 0x64, 0xFA, 0x65, 0xEE, 0x64, 0x99, 0x64, 0xCD, 0x65, 0x73, 0x64, 0x17, 0xE5, 0x90, 0xE4, 0x44, 0xE5, 0x3C, 0xE5, 0xEA, 0xE4, 0x0E, 0xE4, 0x09, 0xE5, 0x35, 0xE4, 0x63, 0xE4, 0x07, 0xE5, 0xEF, 0x15, 0x98, 0x15, 0x2C, 0x14, 0x72, 0x15, 0x96, 0x14, 0x91, 0x14, 0x45, 0x15, 0x3D, 0x15, 0xEB, 0x14, 0xF7, 0x95, 0x08, 0x94, 0xD4, 0x95, 0xA2, 0x95, 0xFA, 0x95, 0xEE, 0x94, 0x99, 0x94, 0xCD, 0x94, 0xB3, 0x95, 0xE7, 0x55, 0x10, 0x54, 0x84, 0x55, 0xDC, 0x54, 0xAA, 0x55, 0xF6, 0x54, 0x71, 0x55, 0x95, 0x55, 0xC3, 0x55, 0xBB, 0x55, 0xAF, 0xD5, 0x68, 0xD5, 0x8C, 0xD5, 0xD2, 0xD4, 0xA6, 0xD5, 0x61, 0xD4, 0x79, 0xD5, 0x9D, 0xD4, 0xCB, 0xD4, 0x37, 0x34, 0x3E, 0x68, 0xC8, 0x6A, 0x04, 0x68, 0xB4, 0x6A, 0x9C, 0x69, 0x92, 0x6B, 0xEA, 0x69, 0x26, 0x6A, 0x8E, 0x69, 0xBE, 0x6A, 0x71, 0x6A, 0xD9, 0x69, 0x15, 0x6B, 0xAD, 0x69, 0x63, 0x68, 0xCB, 0x68, 0x07, 0x68, 0xB7, 0x69, 0x9F, 0xEB, 0x50, 0xEA, 0x18, 0xEA, 0xA4, 0xE8, 0x4C, 0x03, 0x74, 0xC0, 0xAF, 0x0B, 0xD1, 0xAD, 0xD4, 0xDD, 0xD3, 0xC3, 0xD3, 0x53, 0xD3, 0x8B, 0xD6, 0x1B, 0xD0, 0x7B, 0xD4, 0x67, 0xD3, 0xB7, 0xD1, 0x2F, 0xD2, 0x5F, 0x33, 0xC0, 0x34, 0x90, 0x07, 0xF8, 0xA0, 0xCB, 0xE0, 0xC6, 0x90, 0xC1, 0xD0, 0xDC, 0x30, 0xCF, 0xF0, 0xBB, 0x11, 0x9A, 0x91, 0x8C, 0x51, 0x90, 0x51, 0xA7, 0xD1, 0xD5, 0x67, 0xFA, 0xCF, 0x66, 0x9F, 0xF3, 0x3E, 0xAF, 0x18, 0xA3, 0x1A, 0x8B, 0x1B, 0x7B, 0x18, 0x57, 0x19, 0x6F, 0x83, 0x3F, 0x82, 0x65, 0xC0, 0x7E, 0xE0, 0x06, 0xF0, 0x81, 0x09, 0xBE, 0x89, 0xB2, 0x49, 0x28, 0x90, 0x3E, 0x9C, 0x99, 0x92, 0x99, 0x6A, 0x9B, 0xC6, 0x9A, 0x0E, 0x98, 0xDE, 0x9A, 0xD1, 0x9B, 0x19, 0x9B, 0xA5, 0x98, 0x4D, 0x98, 0xBD, 0x9A, 0xB3, 0x9B, 0x5B, 0x99, 0xE7, 0x9A, 0x2F, 0x58, 0x20, 0x58, 0x08, 0x5A, 0x40, 0x2C, 0xCA, 0x2D, 0x36, 0x2C, 0x31, 0x80, 0x1C, 0xC2, 0x07, 0xA0, 0x85, 0x03, 0x2B, 0x7C, 0x2B, 0x15, 0xA0, 0x6F, 0xE8, 0xB2, 0xBA, 0xB4, 0xA6, 0xB4, 0xD6, 0xB7, 0x4E, 0xB0, 0x1E, 0xB5, 0x7E, 0xB2, 0x61, 0xB1, 0xB1, 0xB0, 0xC9, 0xB6, 0x99, 0xB7, 0x7D, 0x67, 0x2B, 0x60, 0xEB, 0x6C, 0x5B, 0x6E, 0xBB, 0x69, 0x87, 0x09, 0x74, 0x0E, 0x7E, 0x76, 0x4D, 0x76, 0x47, 0xF6, 0xC4, 0xF6, 0x1A, 0xF6, 0xD1, 0xF6, 0xFD, 0xF6, 0xB7, 0x0E, 0xF4, 0x0E, 0x60, 0x87, 0x74, 0x87, 0x19, 0x47, 0x18, 0x47, 0x5E, 0x47, 0x47, 0xC7, 0x52, 0xC7, 0x75, 0x27, 0x0C, 0xA0, 0x77, 0xF0, 0x73, 0x6A, 0x72, 0x3A, 0x72, 0x26, 0x76, 0xD6, 0x74, 0x8E, 0x71, 0x1E, 0x70, 0xBE, 0x87, 0x30, 0x01, 0xCD, 0x43, 0x16, 0x64, 0xDE, 0x05, 0xDE, 0x45, 0xD0, 0xC5, 0xD5, 0xA5, 0xD2, 0x65, 0xC7, 0xF5, 0x93, 0xAB, 0xA2, 0x6B, 0x88, 0x6B, 0xA7, 0xEB, 0xA5, 0x1B, 0xB5, 0x9B, 0xA1, 0x5B, 0x0A, 0xC0, 0x10, 0x50, 0xEE, 0x3C, 0xEE, 0x0E, 0xEE, 0xA5, 0xEE, 0x1B, 0x1E, 0x98, 0x1E, 0xB2, 0x1E, 0x01, 0x1E, 0xAD, 0x1E, 0x67, 0x9E, 0xE4, 0x9E, 0x7A, 0x9E, 0x09, 0x9E, 0x63, 0x9E, 0xAF, 0x40, 0xFF, 0x60, 0xEB, 0x55, 0xE4, 0xB5, 0xEA, 0x8D, 0xE6, 0x2D, 0xE5, 0xED, 0xE7, 0xDD, 0xEC, 0x7D, 0xE2, 0x43, 0xE6, 0xA3, 0xEB, 0xF3, 0xC5, 0x67, 0xD4, 0xE7, 0xC5, 0x97, 0xC3, 0xD7, 0xCE, 0xB7, 0xD8, 0x77, 0xCD, 0x0F, 0xC3, 0x4F, 0xC6, 0x2F, 0xC0, 0xAF, 0xD5, 0xEF, 0xCC, 0x9F, 0xD2, 0xDF, 0xC0, 0x3F, 0xD9, 0x7F, 0x2A, 0x00, 0x3A, 0x80, 0x37, 0xC0, 0x39, 0xA0, 0x22, 0x60, 0x27, 0x10, 0x33, 0x50, 0x28, 0xD0, 0x26, 0x30, 0x2D, 0x70, 0x30, 0xF0, 0x3C, 0x08, 0x2F, 0x48, 0x2A, 0x08, 0x12, 0x94, 0x17, 0x34, 0x19, 0x74, 0x1B, 0x4C, 0x16, 0xAC, 0x14, 0xEC, 0x1D, 0x5C, 0x16, 0xBC, 0x10, 0xFC, 0x16, 0x42, 0x1F, 0xA2, 0x1D, 0x12, 0x12, 0x52, 0x1F, 0xB2, 0x11, 0x8A, 0x10, 0xCA, 0x19, 0x0A, 0x0E, 0x8D, 0x0B, 0xED, 0x0C, 0x3D, 0x08, 0xFB, 0x10, 0x26, 0x0C, 0x50, 0x46, 0x46, 0xD8, 0x48, 0xD8, 0x9F, 0x70, 0xA2, 0x70, 0xB9, 0x70, 0x8F, 0xF0, 0x92, 0xF0, 0xB9, 0xF0, 0x97, 0x08, 0xBA, 0x08, 0xAD, 0x88, 0x90, 0x88, 0xFA, 0x88, 0xCD, 0x48, 0xC4, 0x48, 0xAE, 0x48, 0xD3, 0xC8, 0x84, 0xC8, 0x9E, 0xC8, 0xA3, 0x28, 0xEC, 0x28, 0xF1, 0x28, 0x27, 0x80, 0x39, 0x26, 0xA3, 0xEE, 0xA2, 0x29, 0xA2, 0x55, 0xA3, 0xFD, 0xA3, 0xAB, 0xA2, 0x7F, 0xC4, 0xC0, 0xC5, 0xB0, 0xC7, 0x18, 0xC7, 0xC4, 0xC5, 0x74, 0xC5, 0x1C, 0xC6, 0x62, 0xC5, 0x8A, 0xC7, 0x3A, 0xC5, 0xE6, 0xC5, 0x4E, 0xC7, 0x3E, 0xC4, 0x51, 0xC7, 0x69, 0xC6, 0x85, 0xC4, 0x35, 0xC4, 0x6D, 0xC7, 0xBF, 0x8F, 0xE7, 0x07, 0x1A, 0x8B, 0xF4, 0xF8, 0x91, 0xF8, 0xEB, 0x2F, 0x64, 0x5F, 0x54, 0xBE, 0xF8, 0x7F, 0xA9, 0x01, 0x38, 0x04, 0x29, 0x81, 0x27, 0xC1, 0x32, 0x21, 0x2D, 0x61, 0x24, 0xE1, 0x3A, 0x91, 0x2C, 0x51, 0x35, 0x31, 0x30, 0xB1, 0x2E, 0x71, 0x2B, 0xE9, 0x7D, 0x92, 0x40, 0x92, 0x6D, 0x52, 0x56, 0xD2, 0x64, 0xD2, 0x43, 0x32, 0x4D, 0xB2, 0x4E, 0x72, 0x44, 0x72, 0x5B, 0xF2, 0x41, 0x0A, 0x76, 0x8A, 0x54, 0x8A, 0x5B, 0x4A, 0x69, 0xCA, 0x72, 0x2A, 0x5C, 0x2A, 0x67, 0xAA, 0x79, 0x6A, 0x4A, 0xEA, 0x70, 0xEA, 0x4D, 0x1A, 0x45, 0x9A, 0x46, 0x5A, 0x68, 0x5A, 0x73, 0xDA, 0xAF, 0xF4, 0x0F, 0xE9, 0xE2, 0xE9, 0x2E, 0xE9, 0xC5, 0xE9, 0x8B, 0x19, 0xD0, 0x19, 0x6C, 0x19, 0x26, 0x19, 0x49, 0x19, 0x83, 0x19, 0x7F, 0x32, 0x49, 0x33, 0x55, 0x33, 0x83, 0x32, 0xEB, 0x33, 0x77, 0xB2, 0xD0, 0xB3, 0x84, 0xB3, 0x1C, 0xB3, 0xF2, 0xB3, 0xBE, 0x65, 0xBD, 0x66, 0x33, 0x65, 0x1B, 0x66, 0xC7, 0x65, 0xF7, 0x64, 0x9F, 0xE6, 0x10, 0xE4, 0x28, 0xE4, 0xF8, 0xE4, 0x54, 0xE5, 0xAC, 0xE5, 0x22, 0xE5, 0xF2, 0xE5, 0x5A, 0xE7, 0x66, 0xE6, 0x8E, 0xE7, 0xDE, 0xE7, 0x51, 0xE7, 0x69, 0xE7, 0x85, 0xE7, 0xB5, 0xE6, 0xED, 0xE7, 0x63, 0xE5, 0x4B, 0xE4, 0xBB, 0xE6, 0x17, 0xE7, 0x2F, 0x16, 0xC0, 0x14, 0x70, 0x17, 0xD8, 0x15, 0x14, 0x14, 0x2C, 0x03, 0x0D, 0x87, 0x50, 0x21, 0xA4, 0xB0, 0xBC, 0x70, 0xBD, 0x08, 0xBD, 0x48, 0xA2, 0xC8, 0xAB, 0xA8, 0x06, 0xE8, 0x38, 0xB0, 0x8B, 0xE5, 0x01, 0x7A, 0x69, 0x2E, 0x3E, 0x2C, 0x21, 0x00, 0x92, 0x92, 0x30, 0x80, 0x5F, 0xCE, 0x4B, 0xC9, 0x4A, 0xB5, 0x4A, 0xA3, 0x4B, 0x7B, 0x4B, 0xAF, 0xCA, 0xA8, 0xCA, 0xF4, 0xCA, 0xE2, 0xCB, 0x06, 0xCB, 0x6E, 0xCB, 0xE9, 0xCA, 0x8D, 0xCA, 0x93, 0xCA, 0x47, 0xCA, 0x1F, 0x2A, 0x18, 0x2B, 0x8C, 0x2B, 0x52, 0x2A, 0xC6, 0x2B, 0x9E, 0xBE, 0x32, 0x03, 0x5D, 0x47, 0xDA, 0xD7, 0x89, 0xAF, 0xCF, 0x95, 0x2C, 0x00, 0xC9, 0xA4, 0x55, 0x4E, 0x56, 0xBE, 0x54, 0xB1, 0x54, 0x99, 0x56, 0xA5, 0x55, 0x4D, 0x56, 0xBD, 0x00, 0x7D, 0x87, 0x69, 0x75, 0x5A, 0xF5, 0x44, 0xF5, 0x53, 0x0D, 0x53, 0x0D, 0xB8, 0x26, 0xA5, 0x66, 0xAC, 0xE6, 0xA1, 0x96, 0xA1, 0xD6, 0xA8, 0x36, 0x11, 0xE8, 0x3C, 0x6E, 0xEB, 0x68, 0xEA, 0xF4, 0xEA, 0x62, 0xEB, 0x7A, 0xEB, 0x2E, 0xEB, 0xC9, 0xEA, 0x35, 0xEA, 0xC3, 0xEB, 0xDB, 0xEB, 0x8F, 0x1B, 0xF0, 0x1B, 0x14, 0x1B, 0xFC, 0x1B, 0xEA, 0x1B, 0x76, 0x1B, 0x3F, 0x34, 0x4A, 0x34, 0xBA, 0x35, 0x96, 0x35, 0xFE, 0x68, 0x42, 0x6C, 0xE2, 0x6B, 0xB2, 0x6D, 0xCA, 0x6E, 0x9A, 0x6E, 0x7A, 0x69, 0x66, 0x6A, 0x36, 0x6A, 0xFE, 0xD2, 0xDC, 0xDF, 0x7C, 0xD9, 0x42, 0xD2, 0xA2, 0xDA, 0x12, 0xD4, 0xD2, 0xD0, 0xB2, 0xDB, 0x8A, 0xD9, 0x2A, 0xD6, 0x0A, 0x69, 0x2D, 0x6A, 0x9D, 0x6F, 0x83, 0x6A, 0x63, 0x6D, 0x03, 0xB7, 0x25, 0xB4, 0xF5, 0xB7, 0x5D, 0xB4, 0x13, 0xB7, 0x2B, 0xB5, 0xFB, 0xB7, 0xD7, 0xB4, 0x6F, 0x74, 0x20, 0x77, 0xF0, 0x75, 0x58, 0x77, 0x64, 0x74, 0x8C, 0x75, 0xDC, 0x76, 0x52, 0x76, 0x6A, 0x74, 0x06, 0x77, 0x36, 0x74, 0x6E, 0x77, 0xA1, 0x76, 0x09, 0x74, 0xD9, 0x76, 0x65, 0x76, 0x8D, 0x75, 0xFD, 0xED, 0xA6, 0xE8, 0x56, 0xEB, 0x0E, 0xEC, 0xAE, 0xED, 0x5E, 0xEF, 0x41, 0xEC, 0xE1, 0xEE, 0x31, 0xEF, 0x49, 0xEA, 0xE9, 0xEF, 0x39, 0xEF, 0xC5, 0xEF, 0x95, 0xE9, 0x75, 0xEF, 0x2D, 0xEE, 0x9D, 0xEB, 0x7D, 0xE9, 0xA3, 0xEB, 0xD3, 0xEE, 0x0B, 0xED, 0x6B, 0xE8, 0xDB, 0xEA, 0x27, 0xED, 0x2F, 0x1C, 0x20, 0x1B, 0x28, 0x1A, 0x24, 0x1B, 0x2C, 0x1A, 0x22, 0x1B, 0x2A, 0x1C, 0x26, 0x19, 0x2E, 0x18, 0x21, 0x1E, 0xC9, 0x1D, 0x25, 0x18, 0xCD, 0x1E, 0xC3, 0x1D, 0x4B, 0x1F, 0xC7, 0x1A, 0x4F, 0x9E, 0x40, 0x9F, 0x88, 0x9F, 0x44, 0x9E, 0x8C, 0x9C, 0x82, 0x9B, 0x0A, 0x9E, 0x7A, 0x9D, 0xF6, 0x99, 0xBE, 0x03, 0x58, 0xE6, 0xE2, 0x9B, 0xCD, 0xB7, 0x83, 0x59, 0xF0, 0xEC, 0xE6, 0x9C, 0xCE, 0xDC, 0xC2, 0xBC, 0xE2, 0xFC, 0xF8, 0x82, 0xD8, 0x42, 0xF7, 0x22, 0xD7, 0x62, 0xFD, 0x12, 0xDD, 0x52, 0xF1, 0x32, 0xE1, 0x72, 0xDA, 0x77, 0xB4, 0xEF, 0x91, 0x2B, 0x50, 0x2B, 0x5E, 0x2B, 0x7F, 0x7E, 0xD8, 0xFC, 0xD8, 0x5B, 0xD5, 0x5B, 0x9D, 0x5F, 0x93, 0x5D, 0xEB, 0x5F, 0xE7, 0x5E, 0xAF, 0xDD, 0xA0, 0xDC, 0xC8, 0xD9, 0xFC, 0xB0, 0x19, 0xB5, 0xF9, 0xB6, 0xE5, 0xB6, 0x75, 0xB2, 0x0D, 0xDE, 0x5E, 0xD9, 0x71, 0xDF, 0xA5, 0xDF, 0xDD, 0xDE, 0x4B, 0xF9, 0x29, 0xF3, 0xF3, 0xF9, 0x57, 0xDD, 0xBE, 0xE9, 0x01, 0xF6, 0xC1, 0xC4, 0x6F, 0x9F, 0x43, 0xA6, 0xC3, 0x9D, 0xA3, 0xA4, 0x63, 0x89, 0xE3, 0xBF, 0x27, 0x65, 0xA7, 0xDA, 0x67, 0x08, 0x67, 0x1D, 0xE7, 0xD6, 0x17, 0xB8, 0x17, 0x13, 0x97, 0x9E, 0x00, 0x3F, 0xAC, 0x5C, 0x85, 0x5F, 0x73, 0x5C, 0xFF, 0xBC, 0x49, 0xFC, 0x2B, 0xFC, 0xF7, 0xEC, 0x36, 0xEB, 0x4E, 0xFA, 0xEE, 0xE6, 0xBE, 0xF0, 0x41, 0xE9, 0xE1, 0xF1, 0xB1, 0xEC, 0x49, 0xED, 0xE9, 0xF5, 0xF9, 0xEB, 0x8B, 0xC6, 0xCB, 0xDB, 0x6B, 0xE5, 0x9B, 0xE6, 0x1B, 0x30, 0x81, 0xA0, 0x40, 0xD0, 0xE6, 0xBF, 0x63, 0xB8, 0xAC, 0x02, 0x9A, 0x6A, 0x14, 0x38, 0x6E, 0x77, 0x77, 0xD1, 0x9D, 0x26, 0xA8, 0xB4, 0x62, 0x22, 0x0A, 0xD8, 0x20, 0x82, 0x88, 0x52, 0x4A, 0xC7, 0xB6, 0xD3, 0xBD, 0xB3, 0x6E, 0x36, 0x6A, 0x74, 0x77, 0xA7, 0x48, 0x18, 0xD8, 0xDD, 0xAD, 0x9F, 0x8A, 0xDD, 0x5D, 0xF7, 0x3E, 0xFF, 0xF3, 0xF5, 0x67, 0x82, 0x59, 0x60, 0x82, 0x9E, 0x2E, 0x0C, 0xC6, 0x46, 0x95, 0xE6, 0x61, 0x9B, 0xD0, 0x63, 0x82, 0x47, 0x98, 0x08, 0x6D, 0xDD, 0x1F, 0x8A, 0xEF, 0x40, 0xB7, 0x7A, 0x27, 0xE1, 0xBD, 0xF0, 0xDF, 0x85, 0x1E, 0xE4, 0x1C, 0x88, 0xB1, 0xC2, 0xC8, 0x41, 0xB0, 0xE9, 0xDF, 0x7C, 0xF8, 0x92, 0xF4, 0xE7, 0x03, 0x43, 0x04, 0x16, 0xCF, 0xE8, 0x0B, 0x44, 0x77, 0xB2, 0xB1, 0xE5, 0x4E, 0x68, 0x2B, 0x13, 0x23, 0x6E, 0x44, 0xBB, 0xA9, 0x59, 0x91, 0x93, 0xB1, 0x6C, 0xA2, 0x7A, 0xF5, 0x77, 0x5C, 0x88, 0x8D, 0x72, 0x8C, 0x26, 0xA2, 0x10, 0x53, 0x8B, 0x6E, 0xE2, 0x2A, 0xBC, 0xF1, 0x17, 0x0A, 0x45, 0xE9, 0xCB, 0xEE, 0x4D, 0x81, 0xA7, 0x6A, 0x9F, 0xF7, 0xBC, 0x85, 0xDF, 0x29, 0x14, 0xA5, 0xE7, 0x90, 0x73, 0x92, 0x1E, 0xD1, 0x25, 0x74, 0xA1, 0xE0, 0x7B, 0xE4, 0x77, 0x6C, 0x18, 0x23, 0xF1, 0x9E, 0x86, 0xCF, 0x24, 0xD6, 0x39, 0xFC, 0xC6, 0x8F, 0xA1, 0x75, 0x16, 0xC3, 0x88, 0x49, 0x88, 0xFA, 0x5B, 0x11, 0xE4, 0x5C, 0x75, 0xEE, 0x9E, 0x0F, 0xA4, 0x2D, 0x6C, 0xEC, 0xC9, 0x80, 0x1E, 0x66, 0xD6, 0x94, 0xA2, 0xF0, 0x79, 0xCD, 0x5A, 0xD1, 0x05, 0x44, 0x25, 0x9F, 0x1D, 0x79, 0x16, 0x0D, 0x12, 0x6E, 0xF6, 0x5E, 0x85, 0xE5, 0x51, 0x5C, 0xC7, 0x25, 0x78, 0x00, 0xF6, 0xDD, 0x62, 0x31, 0x9E, 0x89, 0xA6, 0x7E, 0xAF, 0x06, 0xBD, 0xDA, 0x32, 0xEE, 0xED, 0x07, 0x2F, 0x54, 0x2B, 0x7B, 0xC6, 0x41, 0x13, 0x0B, 0x9D, 0x4B, 0xF7, 0x40, 0xBD, 0xD9, 0x43, 0x05, 0x8B, 0xE0, 0x41, 0x0D, 0x19, 0xF9, 0x07, 0x19, 0x90, 0xA6, 0xAC, 0x99, 0x81, 0xAD, 0x65, 0x2A, 0x1D, 0x4F, 0xE3, 0xA3, 0x89, 0x21, 0x16, 0x7A, 0x3C, 0x10, 0xFD, 0xF3, 0x39, 0x07, 0x0C, 0xE9, 0x5F, 0x7A, 0x93, 0x0B, 0x3E, 0x68, 0xDD, 0xDE, 0xBD, 0x01, 0xFC, 0x50, 0xF5, 0xB7, 0x04, 0x82, 0xEC, 0x8A, 0xAC, 0xD9, 0x47, 0xF0, 0xCE, 0x6C, 0xB7, 0x68, 0x3D, 0xB2, 0x42, 0x75, 0x78, 0xED, 0x17, 0xF4, 0x82, 0x60, 0xD4, 0xC2, 0x18, 0xEC, 0x3A, 0xF1, 0x9F, 0xC5, 0x7D, 0x7C, 0x0D, 0xB6, 0xE1, 0x53, 0x04, 0xF8, 0xE4, 0x82, 0xCB, 0xCD, 0x79, 0x60, 0x6E, 0xFF, 0xB9, 0xCE, 0xC7, 0xE0, 0xF1, 0xD6, 0xFE, 0xFC, 0x47, 0x90, 0x65, 0x75, 0x2D, 0x3B, 0x0A, 0x7A, 0x54, 0x34, 0x27, 0x72, 0x09, 0xFC, 0x41, 0x77, 0x6A, 0xCD, 0x04, 0xB4, 0x45, 0x14, 0xBD, 0xD0, 0x18, 0xFB, 0x8F, 0xAC, 0xB3, 0xB4, 0xC7, 0x23, 0xB1, 0xA8, 0xF7, 0xA7, 0xA1, 0xC5, 0xB7, 0x0E, 0xDF, 0xD8, 0x03, 0xB6, 0x9C, 0x7B, 0xDA, 0xA9, 0x01, 0xD1, 0x9E, 0x97, 0xF9, 0xE7, 0xC0, 0xFB, 0xCD, 0x62, 0xA6, 0x07, 0x22, 0x2A, 0xD6, 0x44, 0x64, 0xC2, 0x9D, 0x39, 0x29, 0xDE, 0xD6, 0xE8, 0x80, 0xA4, 0x6E, 0xE1, 0x28, 0xDC, 0x95, 0xF2, 0xB3, 0x04, 0xF1, 0x07, 0x98, 0xDF, 0x87, 0x5B, 0xD0, 0x92, 0xFF, 0x96, 0x5E, 0x4F, 0x00, 0xC9, 0xEB, 0x9C, 0x2E, 0x29, 0x70, 0x7B, 0x00, 0x28, 0x60, 0xC1, 0x8E, 0x2E, 0x35, 0xA3, 0x82, 0x56, 0xD4, 0x19, 0x87, 0xDF, 0x85, 0x4B, 0xF2, 0xE7, 0x78, 0xBF, 0x42, 0x2F, 0xC8, 0x3E, 0x2E, 0x2C, 0xC7, 0x8F, 0x51, 0x3D, 0x56, 0xE3, 0x88, 0x0C, 0xF4, 0xE7, 0x1B, 0x44, 0x78, 0x17, 0xCE, 0xBD, 0x32, 0x84, 0xED, 0x43, 0x22, 0xDA, 0xCF, 0x33, 0x7A, 0xC4, 0xBF, 0xF0, 0x31, 0x3D, 0x03, 0x99, 0x43, 0x9D, 0xA6, 0x2C, 0x90, 0xDA, 0x03, 0xC3, 0xC9, 0x74, 0xE4, 0xFA, 0xAA, 0xE7, 0x64, 0x28, 0xFC, 0xC8, 0x71, 0x02, 0x59, 0x09, 0x9D, 0xB3, 0xA8, 0x26, 0x6F, 0x41, 0x9B, 0x9E, 0xFB, 0x08, 0xAA, 0x45, 0xA7, 0x2F, 0xF9, 0xF3, 0x9D, 0xD9, 0xFE, 0x76, 0x86, 0x5E, 0xC5, 0x4C, 0xCB, 0x37, 0xA0, 0x7C, 0xA8, 0x63, 0x74, 0x24, 0x09, 0x90, 0x7B, 0x0F, 0x4E, 0x22, 0x8D, 0xF1, 0x07, 0xAB, 0xDA, 0xC8, 0xA9, 0xA8, 0xD0, 0x81, 0x4B, 0xBA, 0xC2, 0xCF, 0xCC, 0x1F, 0x93, 0xDB, 0x60, 0xFB, 0x67, 0x2F, 0xD8, 0x65, 0xBA, 0x33, 0x97, 0x1A, 0x69, 0xB9, 0x6A, 0x75, 0x5B, 0x2F, 0x35, 0x45, 0x9A, 0x9C, 0x5B, 0x4F, 0xEA, 0x44, 0x9F, 0xA9, 0xFB, 0xC4, 0x7D, 0xF6, 0xD7, 0xC1, 0x76, 0x82, 0xA5, 0x0B, 0x56, 0x6F, 0x23, 0x0A, 0xF0, 0x4C, 0x07, 0x17, 0xE2, 0x0C, 0x3A, 0xC7, 0x7C, 0x07, 0x71, 0x17, 0x19, 0xF5, 0x7C, 0x3E, 0xD3, 0x57, 0x84, 0x9D, 0x3B, 0x4C, 0x6F, 0xD3, 0xDB, 0xB4, 0x2A, 0xC9, 0x75, 0x5A, 0x8E, 0xFE, 0x1B, 0xD1, 0xAF, 0x9A, 0x4F, 0x46, 0x10, 0x4E, 0xD2, 0x93, 0xE1, 0x34, 0xFE, 0x9F, 0x20, 0x76, 0x55, 0x33, 0xE1, 0x47, 0xB6, 0x39, 0xD8, 0x10, 0x10, 0xB6, 0xD8, 0x7C, 0x0F, 0x21, 0x41, 0xAA, 0x9E, 0xD8, 0x33, 0x65, 0x75, 0xBE, 0xE7, 0xE2, 0xA8, 0xE8, 0xD2, 0x4F, 0xCD, 0x0F, 0x88, 0xEE, 0xBC, 0xB0, 0x9C, 0x83, 0xC4, 0xDC, 0x4C, 0x53, 0x02, 0xC5, 0x73, 0x54, 0x77, 0x0F, 0x8C, 0xC4, 0x31, 0x89, 0x72, 0x55, 0x36, 0x61, 0x45, 0xBF, 0x70, 0xD8, 0x44, 0xF8, 0xE1, 0xA6, 0xE6, 0x62, 0x22, 0x1C, 0x9D, 0xF1, 0xD8, 0x80, 0x09, 0xEE, 0x94, 0x9E, 0x5F, 0x49, 0xDE, 0x6D, 0xD8, 0xD9, 0x74, 0x93, 0xD8, 0x5B, 0xBE, 0x23, 0xBB, 0x14, 0x17, 0xE4, 0x4B, 0xF1, 0x76, 0x7C, 0x6A, 0xE6, 0x98, 0xB0, 0x6C, 0x7C, 0xA6, 0xA2, 0x7B, 0xD5, 0x15, 0xBC, 0x8D, 0xFF, 0xDD, 0x81, 0x47, 0xD8, 0xE1, 0x2F, 0xCD, 0x7B, 0x89, 0x3D, 0x68, 0xC0, 0x93, 0x95, 0x8C, 0xE7, 0x89, 0x7F, 0x67, 0x8F, 0x91, 0xA7, 0x8F, 0x6C, 0x6D, 0xDC, 0x45, 0x2C, 0x6F, 0xA4, 0xB2, 0x9E, 0xE0, 0x0B, 0x2B, 0xB6, 0x10, 0xCE, 0x18, 0x27, 0x7F, 0x7B, 0xC8, 0x63, 0xEC, 0x58, 0x7A, 0x96, 0xD7, 0x64, 0x5C, 0x23, 0x34, 0x70, 0x58, 0x4A, 0x2C, 0x22, 0x4A, 0x2C, 0x26, 0x13, 0x29, 0x68, 0xDA, 0xC3, 0xA5, 0xCC, 0xB4, 0x8B, 0xA7, 0x4E, 0x3F, 0x25, 0x07, 0x4F, 0xDA, 0x34, 0x60, 0xF8, 0xFB, 0x2E, 0x8B, 0xCC, 0x0F, 0xD8, 0xB5, 0xFA, 0xFF, 0xB0, 0x1B, 0xD8, 0xBA, 0xD2, 0xD0, 0x30, 0x07, 0x4C, 0x96, 0x15, 0xE8, 0x79, 0x19, 0x57, 0x8A, 0x7D, 0x1C, 0x36, 0x12, 0xC1, 0x64, 0x90, 0x45, 0x12, 0xD1, 0x82, 0x0A, 0xEF, 0x17, 0xF3, 0x95, 0xB7, 0x95, 0xA7, 0x8A, 0x29, 0xFF, 0x8B, 0xF3, 0xEB, 0x5B, 0x70, 0x7D, 0xBF, 0x32, 0xF3, 0x0D, 0x16, 0xD6, 0x86, 0x20, 0x97, 0xB1, 0xB9, 0x55, 0x5D, 0xA1, 0x37, 0xB0, 0xF8, 0xDC, 0x39, 0x5E, 0x73, 0x71, 0xB9, 0x74, 0xB3, 0xC3, 0x4D, 0x22, 0x9D, 0x1A, 0x6E, 0x39, 0x8D, 0x9C, 0x80, 0xEA, 0x6E, 0x2D, 0xD7, 0xF4, 0x43, 0x6F, 0x8F, 0xFB, 0x28, 0xFA, 0xE0, 0xD4, 0x9A, 0x43, 0x92, 0x5A, 0xF8, 0xB0, 0xF6, 0xB4, 0x68, 0x3E, 0xFC, 0x0B, 0x7A, 0xC3, 0xE6, 0xC2, 0xAF, 0xF6, 0xFD, 0x60, 0x9A, 0xE1, 0x77, 0x5E, 0x07, 0xE9, 0xD5, 0x70, 0x94, 0xFD, 0x47, 0x8A, 0x85, 0xFA, 0xCC, 0xF3, 0x28, 0x17, 0x28, 0xE5, 0x6A, 0x9F, 0xFA, 0x0D, 0x6B, 0x71, 0x6C, 0xAA, 0x3C, 0x8C, 0x3E, 0x52, 0x73, 0x57, 0x1C, 0x48, 0x0E, 0x6A, 0x63, 0x04, 0x6F, 0x48, 0x03, 0x58, 0xC8, 0xBF, 0x49, 0x18, 0x85, 0xB4, 0x32, 0xDB, 0xB0, 0x6B, 0x9E, 0x7B, 0xA8, 0xEF, 0xC8, 0x2D, 0xFB, 0xDD, 0x94, 0x0F, 0x0C, 0x9B, 0x3B, 0x50, 0xC3, 0xA1, 0xFF, 0xAE, 0xE6, 0xAB, 0xF8, 0x2A, 0x9F, 0xFE, 0x27, 0x32, 0x7B, 0x99, 0x41, 0x8D, 0x81, 0xE8, 0x90, 0xA8, 0x41, 0x6B, 0x2C, 0x98, 0x2A, 0x50, 0x23, 0xC1, 0xFC, 0x31, 0x7C, 0xDB, 0x7D, 0x29, 0x74, 0x0B, 0x95, 0xE6, 0xD9, 0x43, 0xE9, 0xB1, 0x2A, 0xBB, 0xB7, 0xD4, 0x58, 0x64, 0xAF, 0x99, 0x9E, 0x1C, 0x80, 0xF7, 0x5F, 0xE9, 0x56, 0x5E, 0xD1, 0x8F, 0xEE, 0xDD, 0x28, 0x55, 0x64, 0x30, 0x55, 0x5B, 0x85, 0x55, 0xEA, 0x75, 0xEA, 0x36, 0x36, 0x5C, 0xAE, 0x07, 0x27, 0x31, 0x52, 0xF1, 0x8D, 0xD0, 0x4D, 0xF4, 0x4A, 0x76, 0x93, 0xE7, 0x68, 0x6A, 0x3B, 0x51, 0x69, 0x97, 0x47, 0x5E, 0x47, 0xD7, 0x9A, 0x85, 0x92, 0xB9, 0xF0, 0xC5, 0x8B, 0x7B, 0x94, 0xF6, 0xE5, 0x9B, 0x8F, 0x7A, 0x4A, 0xBE, 0x14, 0x4E, 0xA9, 0x68, 0x12, 0x1A, 0x64, 0x17, 0xA8, 0x36, 0xF2, 0xDF, 0x6B, 0x3D, 0x01, 0x2B, 0x66, 0xB1, 0xA2, 0x3B, 0xE4, 0x11, 0xF5, 0x51, 0xBC, 0xCD, 0x33, 0x93, 0x9A, 0x4C, 0xFD, 0xB2, 0xD3, 0x93, 0x6D, 0x98, 0xA1, 0xD9, 0x1A, 0x52, 0x89, 0x4C, 0xBE, 0xF0, 0x4D, 0x51, 0xDC, 0x58, 0x75, 0x34, 0x4D, 0x82, 0x55, 0x1D, 0x2A, 0xEF, 0x12, 0x94, 0x16, 0xCF, 0x50, 0x76, 0xF3, 0x79, 0x7A, 0x2E, 0x80, 0xD0, 0x99, 0xDA, 0x0F, 0x7B, 0xB7, 0x50, 0x42, 0x79, 0xB8, 0xFB, 0x4D, 0xF2, 0x39, 0xD3, 0x61, 0xB7, 0x86, 0x6C, 0xC0, 0x7A, 0xCD, 0xA2, 0x48, 0x3D, 0xB2, 0xF4, 0x62, 0x8C, 0xC2, 0xF7, 0xE8, 0xB0, 0xA3, 0x2D, 0x92, 0xD1, 0xAD, 0x5E, 0x65, 0xE1, 0x82, 0xBC, 0x9A, 0x37, 0x4A, 0x1D, 0xDF, 0xA3, 0x74, 0x2A, 0x38, 0x8C, 0x9E, 0x9C, 0xBB, 0x29, 0x78, 0x11, 0xE5, 0xA0, 0x19, 0xEB, 0x16, 0x44, 0x9E, 0x63, 0x8B, 0xED, 0x46, 0x91, 0x1D, 0x78, 0x94, 0x59, 0x27, 0xD9, 0x82, 0x04, 0x9C, 0x3F, 0x29, 0xAF, 0x1F, 0xE0, 0x74, 0x37, 0x8A, 0x07, 0x7B, 0x2A, 0xCB, 0x1C, 0x04, 0x3B, 0x5A, 0x0D, 0x15, 0x8F, 0x99, 0xD3, 0x35, 0xD3, 0x79, 0x43, 0xA8, 0xAF, 0x45, 0x29, 0x7B, 0xBE, 0x51, 0xC3, 0x33, 0x26, 0xB9, 0xE5, 0x93, 0x2D, 0xC2, 0x7A, 0x3B, 0x86, 0xEC, 0x22, 0x16, 0x99, 0xEF, 0x20, 0xFB, 0x11, 0xD9, 0xD9, 0x8B, 0xCA, 0x79, 0x97, 0xB0, 0xAE, 0x6E, 0x89, 0xD7, 0xC0, 0xBF, 0xD2, 0x37, 0x82, 0x59, 0xDD, 0x9E, 0x2A, 0x8C, 0x99, 0xDD, 0x64, 0xC3, 0x6D, 0xA5, 0x72, 0xCB, 0x0F, 0x04, 0x99, 0x90, 0xCD, 0xD9, 0x7E, 0xEE, 0x22, 0x52, 0x26, 0x6E, 0xB0, 0x97, 0x90, 0x47, 0xC9, 0xD1, 0x16, 0x9E, 0xE4, 0x25, 0xE4, 0xF1, 0x40, 0x49, 0xDE, 0x3A, 0xC8, 0xBD, 0x35, 0x2A, 0x33, 0x1A, 0x9E, 0x55, 0xB8, 0x4E, 0xDD, 0x0C, 0x4F, 0x95, 0x4C, 0x54, 0x0C, 0x83, 0x47, 0xA5, 0xCE, 0x96, 0xF0, 0x60, 0xBB, 0xE0, 0x18, 0x61, 0x28, 0x3C, 0xC9, 0x83, 0xCF, 0x8F, 0x82, 0x8A, 0xED, 0xAD, 0xE8, 0x0E, 0xC8, 0xD5, 0x3C, 0x82, 0x1E, 0x0B, 0x8D, 0x3D, 0x3E, 0xA8, 0xBF, 0xC8, 0xA4, 0xB7, 0x7C, 0xCE, 0x70, 0xA1, 0x46, 0x17, 0x14, 0xAA, 0x6E, 0x12, 0x1A, 0xC9, 0x64, 0xB9, 0x31, 0x4E, 0xA6, 0xF2, 0xC5, 0x97, 0xB1, 0xC1, 0x40, 0xAE, 0xE0, 0x17, 0x7A, 0xDF, 0x6D, 0x3D, 0xDF, 0x14, 0x19, 0x61, 0x37, 0x95, 0x16, 0x43, 0x77, 0xCD, 0x9A, 0xA8, 0x47, 0x50, 0xC8, 0xF1, 0xB7, 0xD9, 0x47, 0xE5, 0xAF, 0x5B, 0x7A, 0xB4, 0x4F, 0xC5, 0x55, 0xF9, 0xE5, 0xAA, 0x91, 0x42, 0x67, 0x89, 0xA3, 0xCC, 0x89, 0x5F, 0x98, 0xB6, 0x4C, 0x3C, 0x86, 0x16, 0xEC, 0xFE, 0x2B, 0x48, 0x24, 0xBD, 0x5D, 0x4E, 0x30, 0xAF, 0x50, 0xD6, 0x76, 0x06, 0x1D, 0x0A, 0xAB, 0x4D, 0xDF, 0x53, 0xAD, 0x50, 0x77, 0x7F, 0x4A, 0x76, 0x7F, 0x66, 0x53, 0xD3, 0x07, 0xAD, 0x7D, 0xFA, 0xB8, 0xFC, 0xA9, 0x8A, 0x3F, 0x8A, 0x33, 0xA2, 0xFB, 0xD2, 0x10, 0x69, 0x58, 0xB2, 0x89, 0x08, 0x10, 0x9E, 0xDE, 0xB5, 0x85, 0xBD, 0xC7, 0x00, 0x2E, 0xB3, 0x99, 0x3C, 0x7C, 0x93, 0x8D, 0x82, 0x76, 0x45, 0x76, 0x9B, 0x26, 0x50, 0x05, 0xF0, 0xC4, 0xBE, 0x5B, 0xD9, 0x4C, 0x11, 0xD6, 0x58, 0x90, 0xDE, 0xA1, 0xBF, 0x9F, 0xFB, 0x56, 0x81, 0x67, 0xAC, 0x16, 0x9D, 0x96, 0x9C, 0x52, 0x3F, 0x4E, 0xBC, 0x29, 0x1C, 0x94, 0x4F, 0xDD, 0xB5, 0x9A, 0xCD, 0x12, 0x1E, 0x76, 0xD9, 0xCA, 0x84, 0x91, 0x91, 0x36, 0x11, 0xB4, 0x23, 0x3A, 0xD1, 0x74, 0x21, 0x55, 0x0D, 0xDB, 0xF7, 0xB5, 0x67, 0x31, 0xD5, 0xDC, 0x06, 0x4E, 0xFA, 0xBA, 0xB2, 0xF1, 0xFA, 0x05, 0x8A, 0x51, 0xF9, 0x09, 0x82, 0x6F, 0x92, 0xE4, 0x2C, 0x71, 0xD2, 0x50, 0xA1, 0x50, 0x93, 0xBC, 0xF3, 0x00, 0xBB, 0x51, 0x7A, 0x60, 0xA5, 0x13, 0xE3, 0x4D, 0x2F, 0xB1, 0x59, 0x40, 0xAF, 0x42, 0xD5, 0xA6, 0xEB, 0xA8, 0x3B, 0xB0, 0x59, 0xAF, 0x55, 0xD6, 0xAC, 0x36, 0x9B, 0xFA, 0x6F, 0x1A, 0xBA, 0x61, 0x68, 0x76, 0x90, 0xFC, 0x52, 0xC5, 0x15, 0x36, 0x4A, 0x12, 0x51, 0x78, 0x34, 0x51, 0x23, 0x3C, 0x90, 0x75, 0x6A, 0xE7, 0x3A, 0x76, 0x86, 0xF2, 0xC4, 0x8A, 0x7E, 0xC6, 0x96, 0xBF, 0xC0, 0x66, 0x21, 0xBD, 0x0D, 0x33, 0x37, 0xAD, 0xA3, 0x27, 0xC1, 0x0B, 0x7A, 0x1D, 0x33, 0xF3, 0xFB, 0x2C, 0x1A, 0x10, 0x0D, 0xD9, 0xF1, 0x2D, 0xFB, 0x8C, 0xBC, 0xBD, 0x61, 0x17, 0xDF, 0x4A, 0xE2, 0x54, 0x61, 0x9A, 0xE0, 0x22, 0x74, 0xCB, 0x5F, 0xB9, 0x93, 0xE2, 0x7F, 0x4B, 0xFF, 0x3F, 0x73, 0x31, 0x13, 0x05, 0x23, 0x6D, 0x47, 0xD2, 0xCB, 0xB1, 0xF7, 0x66, 0x41, 0xD4, 0x63, 0x18, 0xEA, 0xBD, 0x97, 0x89, 0x9D, 0x91, 0xD7, 0x53, 0x9A, 0xD0, 0xBE, 0xDB, 0x59, 0x4F, 0xE5, 0x65, 0xED, 0x8E, 0xFC, 0x5E, 0x71, 0x51, 0xDD, 0x9C, 0xF8, 0x5C, 0x41, 0x6D, 0xC9, 0xB4, 0x1D, 0x69, 0x7C, 0x71, 0xC6, 0xFF, 0xB9, 0x8C, 0x7E, 0x26, 0xBC, 0x6E, 0x57, 0x41, 0x5B, 0xE3, 0x17, 0xCD, 0xB9, 0xD4, 0x09, 0xF8, 0x43, 0x97, 0x5F, 0xB9, 0x37, 0x98, 0x52, 0x25, 0x2B, 0x38, 0x00, 0xAD, 0xD0, 0x75, 0x64, 0x39, 0x41, 0x9D, 0xD4, 0xD4, 0x74, 0x08, 0x02, 0x63, 0xFF, 0x2A, 0x2D, 0xA0, 0x80, 0x9D, 0xA9, 0x92, 0x7F, 0x90, 0x89, 0x4B, 0xBE, 0x20, 0x05, 0x3C, 0x65, 0xB7, 0x86, 0x3F, 0x1D, 0x3C, 0x6C, 0x5E, 0xC3, 0x4C, 0x02, 0x37, 0xB4, 0xBB, 0x96, 0x76, 0x50, 0x03, 0x95, 0x33, 0xF3, 0x0D, 0x88, 0xE7, 0xBA, 0x31, 0x99, 0x27, 0xF0, 0x8D, 0xE4, 0x2B, 0xCD, 0x73, 0x2C, 0x26, 0xF6, 0xAC, 0xA2, 0x1B, 0x1B, 0xB2, 0xC3, 0x48, 0xD2, 0x85, 0xFC, 0x58, 0xB9, 0x5F, 0xB0, 0x13, 0x76, 0xB5, 0xB9, 0xC9, 0xDC, 0x86, 0x1C, 0xCC, 0xD6, 0xD2, 0x67, 0xC1, 0xAE, 0xB6, 0xFB, 0xC5, 0x5A, 0xE9, 0x8E, 0x8A, 0xA0, 0x5C, 0x44, 0xB4, 0x31, 0x5D, 0x96, 0xF1, 0x9D, 0x65, 0xC8, 0x6A, 0x8D, 0x31, 0xFD, 0x25, 0x76, 0x93, 0x22, 0x90, 0x62, 0xB6, 0xED, 0x93, 0xEC, 0x21, 0x42, 0x56, 0xD8, 0x08, 0xE6, 0x21, 0x8F, 0xAD, 0xAB, 0x98, 0x3C, 0xE8, 0x8B, 0xE9, 0x6C, 0x5A, 0x09, 0x59, 0xB6, 0xFE, 0x57, 0x3C, 0x46, 0x2B, 0x2C, 0xDF, 0xA0, 0x7F, 0xA2, 0x8A, 0x4E, 0x3F, 0xA2, 0x7B, 0x2A, 0x13, 0x90, 0xC9, 0xEA, 0x6D, 0xA2, 0xBF, 0x87, 0x9A, 0xE5, 0x9D, 0xEC, 0xBD, 0xAD, 0xDB, 0xC4, 0xBF, 0x68, 0x74, 0x79, 0x36, 0x7B, 0x07, 0xCB, 0xB5, 0x1E, 0xCF, 0x40, 0x70, 0x8D, 0x49, 0x04, 0xCD, 0x83, 0x0E, 0xB5, 0xC6, 0x14, 0xBD, 0xCF, 0x33, 0x2C, 0xF3, 0xD1, 0x37, 0x66, 0x4D, 0xD7, 0xC8, 0x74, 0x49, 0xE9, 0x76, 0x84, 0xB1, 0xAA, 0x59, 0x39, 0x35, 0x66, 0xA7, 0xEC, 0xAB, 0xE4, 0x65, 0x80, 0x44, 0xCC, 0xB2, 0x6F, 0x96, 0x9B, 0xB3, 0x75, 0x44, 0x88, 0x55, 0x1B, 0xC3, 0x43, 0x56, 0x99, 0x58, 0xD2, 0x42, 0x08, 0x68, 0xC3, 0x8A, 0xB6, 0x95, 0x3D, 0x2B, 0xAB, 0xD7, 0x2F, 0x2C, 0x0C, 0x53, 0x9D, 0xD3, 0x4D, 0xCC, 0x09, 0xC3, 0xAE, 0xA9, 0x22, 0x75, 0x87, 0x63, 0x8C, 0x65, 0x69, 0x2A, 0x2B, 0xFF, 0x07, 0xE2, 0xE9, 0xE2, 0x2C, 0xE7, 0x58, 0x96, 0xA5, 0x86, 0x59, 0x69, 0x18, 0x35, 0x52, 0x65, 0x12, 0x40, 0x9F, 0x85, 0x76, 0x36, 0x6F, 0x2F, 0xCA, 0x6F, 0xB4, 0x2F, 0x45, 0x73, 0x2A, 0xAB, 0x4F, 0x2A, 0x3F, 0x68, 0x73, 0x4A, 0xC4, 0x68, 0x8B, 0x6A, 0x77, 0xEE, 0xB1, 0xE8, 0x62, 0x59, 0x64, 0xC6, 0xD2, 0x00, 0x85, 0xE8, 0x8F, 0xFC, 0x96, 0xB3, 0x98, 0x4D, 0xA0, 0x2F, 0x59, 0xBD, 0x64, 0xEA, 0x50, 0x13, 0x93, 0xC7, 0xCC, 0x7C, 0xC8, 0xB6, 0x29, 0xB4, 0xC8, 0xA0, 0xAB, 0xBA, 0x64, 0x68, 0xCE, 0xAB, 0x16, 0x27, 0x65, 0x9C, 0xF6, 0x4C, 0xCD, 0x6C, 0x64, 0xA3, 0x6A, 0x5D, 0xC9, 0x96, 0x28, 0xA9, 0x0C, 0xD0, 0xFB, 0x04, 0xC4, 0x88, 0x87, 0xA8, 0xA3, 0x96, 0x47, 0xB2, 0x3B, 0xF9, 0x51, 0xD6, 0x35, 0x8C, 0x10, 0xBD, 0x64, 0xCA, 0xA1, 0x2F, 0x41, 0x9A, 0xE6, 0xBA, 0x22, 0xAB, 0xE3, 0x5D, 0x45, 0xC7, 0x72, 0x9E, 0x1C, 0xB9, 0xA0, 0xC8, 0xD5, 0x96, 0x36, 0xFD, 0x43, 0x76, 0x28, 0xFF, 0x56, 0x59, 0x47, 0x1E, 0x90, 0x2D, 0x2E, 0x68, 0xF1, 0xFB, 0x23, 0x2A, 0x49, 0x2F, 0x5F, 0x21, 0x65, 0x27, 0xB0, 0x3A, 0x9B, 0xE3, 0x4C, 0x38, 0x06, 0x9B, 0x85, 0xD1, 0x95, 0xF0, 0x98, 0x9A, 0xC1, 0x06, 0x2B, 0x70, 0x5B, 0xDE, 0xC3, 0x8A, 0x1C, 0xD0, 0x5D, 0x7C, 0xB7, 0x40, 0x02, 0xBE, 0x02, 0xB8, 0xD9, 0xBD, 0xE0, 0xFE, 0x88, 0x7E, 0x2D, 0x1F, 0x34, 0xF1, 0x1B, 0x54, 0xEE, 0x04, 0x8D, 0x9C, 0xB3, 0xC5, 0x4B, 0x81, 0x07, 0xB6, 0x14, 0xDB, 0x0B, 0xC4, 0x9A, 0x17, 0xF3, 0x1D, 0x81, 0x43, 0xD5, 0x7B, 0xEA, 0xDD, 0x88, 0x8E, 0xDC, 0xB6, 0xF2, 0x1A, 0x7C, 0x9E, 0x78, 0x69, 0xC1, 0x2E, 0xCC, 0x8F, 0x77, 0x3C, 0x3B, 0x10, 0x8D, 0x8C, 0x58, 0xA3, 0x1D, 0x87, 0xC8, 0xFC, 0x06, 0x94, 0x43, 0xE1, 0x2E, 0x67, 0x77, 0xD1, 0x5B, 0x68, 0xBF, 0x75, 0x08, 0xBB, 0x0D, 0x4C, 0x36, 0xC5, 0x98, 0x93, 0xE0, 0xA4, 0xAA, 0xFA, 0xBA, 0x60, 0xD1, 0x73, 0xBD, 0x47, 0x59, 0x38, 0xFB, 0x49, 0x34, 0x3E, 0x9F, 0x64, 0xBC, 0x00, 0xE3, 0xAC, 0x9B, 0xD4, 0xD0, 0x88, 0x8B, 0xE9, 0xF9, 0xC4, 0xDE, 0x2D, 0xBF, 0x15, 0x1C, 0xAC, 0xDF, 0x29, 0x5F, 0x44, 0x23, 0xD3, 0xAC, 0x0C, 0xF8, 0x3F, 0xA0, 0xAD, 0xC6, 0xDF, 0x99, 0x34, 0x50, 0x56, 0x35, 0xB9, 0x36, 0x45, 0x3D, 0x90, 0xFD, 0xB8, 0x6C, 0x94, 0xBC, 0x57, 0xF8, 0x36, 0xEF, 0x9E, 0xB8, 0x13, 0x98, 0x9B, 0xB5, 0x41, 0x00, 0x45, 0xB8, 0xA5, 0x4F, 0x63, 0x8A, 0xB6, 0xF4, 0x2A, 0x8C, 0xA9, 0xB1, 0x4E, 0xDB, 0x44, 0xDE, 0xE8, 0x35, 0x4B, 0x98, 0x7F, 0x12, 0x1E, 0x6D, 0xBC, 0x88, 0xF1, 0x05, 0x2F, 0x55, 0x1C, 0xAA, 0xB9, 0x9D, 0x7D, 0x2C, 0xF3, 0x48, 0xE9, 0x49, 0x9D, 0xA7, 0xE0, 0x7B, 0xDE, 0x7A, 0xD5, 0x39, 0xEE, 0xBA, 0xCC, 0x46, 0x59, 0xFD, 0x81, 0xF5, 0x9A, 0x14, 0x11, 0x6F, 0x73, 0xB3, 0xFC, 0x34, 0x3F, 0xD2, 0x69, 0x8A, 0xC8, 0x1E, 0x27, 0x2D, 0x5D, 0xF9, 0x47, 0x60, 0x89, 0xD1, 0x8F, 0xFF, 0xA7, 0xEE, 0x54, 0x6C, 0xAD, 0xBE, 0x54, 0x6C, 0x9B, 0xF9, 0xB5, 0x74, 0x78, 0xDE, 0x18, 0xF6, 0x59, 0x6E, 0x67, 0x26, 0xC6, 0x99, 0x98, 0xE9, 0xAB, 0x49, 0xDC, 0xFF, 0x52, 0xB3, 0x50, 0x2E, 0xDE, 0xD4, 0x21, 0x5F, 0x2F, 0x6C, 0x5D, 0x66, 0x23, 0x7C, 0x46, 0xDC, 0xB1, 0x5C, 0xCC, 0xEF, 0x87, 0x07, 0x8D, 0x57, 0x30, 0x09, 0xE0, 0xB1, 0xB2, 0x71, 0x35, 0x5B, 0x6B, 0x5A, 0x33, 0xF3, 0x4A, 0xBE, 0x96, 0xEF, 0x61, 0x3D, 0x72, 0x93, 0x0B, 0xAE, 0xA4, 0x39, 0x64, 0x7C, 0xC9, 0x0E, 0xDB, 0x1F, 0xAD, 0x19, 0x92, 0xBE, 0xCF, 0xF7, 0x8A, 0xDC, 0x53, 0x5A, 0xBF, 0x8C, 0x12, 0xDE, 0xA6, 0x92, 0x2C, 0x4B, 0xF8, 0x37, 0x10, 0x7F, 0xE3, 0xD3, 0x8C, 0x16, 0xAC, 0x29, 0x51, 0x55, 0x7F, 0x6C, 0x9D, 0x99, 0x11, 0x55, 0xF2, 0xBB, 0x7E, 0x0B, 0x3F, 0x3D, 0x17, 0x2B, 0xBF, 0x97, 0x32, 0x90, 0xF1, 0xB4, 0x80, 0x0D, 0x73, 0xD4, 0xCC, 0xCE, 0x7C, 0xEA, 0x9B, 0x28, 0x77, 0x57, 0x14, 0x38, 0x4D, 0x15, 0xDE, 0xA6, 0xBB, 0xAC, 0xF6, 0xF2, 0x6F, 0x23, 0x97, 0x4C, 0x84, 0xFF, 0x4F, 0x3D, 0x2C, 0x9D, 0x5E, 0xA3, 0x3D, 0xEA, 0x9B, 0xD1, 0x53, 0x92, 0xD3, 0x96, 0xCD, 0xBF, 0x9A, 0xBB, 0xB0, 0x6E, 0x4C, 0xF2, 0x7F, 0x19, 0x1D, 0xA5, 0xFD, 0x61, 0x76, 0x9A, 0x39, 0xFA, 0x12, 0x1F, 0xB9, 0xAC, 0x5D, 0x35, 0xD5, 0x49, 0x20, 0xEC, 0x62, 0x30, 0xAB, 0x1F, 0xFC, 0x41, 0x74, 0x93, 0xA9, 0x3F, 0x53, 0x00, 0x2D, 0xD1, 0x6F, 0xED, 0xFA, 0x01, 0x89, 0x15, 0x50, 0xD3, 0x29, 0x70, 0x3B, 0x62, 0x52, 0xB5, 0x1A, 0x28, 0x4D, 0x98, 0x50, 0xF4, 0x96, 0x97, 0x17, 0x7A, 0x48, 0xBF, 0x86, 0xA7, 0xDF, 0x78, 0x46, 0x7B, 0x1E, 0xB0, 0x5C, 0x12, 0x27, 0xCB, 0x01, 0x0C, 0xAD, 0x20, 0x61, 0x0C, 0xEF, 0x81, 0x69, 0x2F, 0x6B, 0xC7, 0xBB, 0x90, 0xD3, 0xDF, 0x79, 0x9A, 0x58, 0x22, 0xBF, 0xD6, 0x34, 0x13, 0x9B, 0x80, 0x54, 0x54, 0x36, 0xA1, 0xC3, 0xE2, 0x87, 0x17, 0x29, 0xE1, 0xFE, 0x90, 0x21, 0x39, 0xCF, 0xA1, 0x6B, 0x1B, 0x53, 0xB4, 0x6B, 0xA1, 0xD4, 0x25, 0x6A, 0xD9, 0x04, 0x90, 0xB5, 0x34, 0x15, 0x7C, 0x02, 0x8E, 0x18, 0x3F, 0xE3, 0x9F, 0x02, 0x0E, 0x64, 0x1F, 0xED, 0x74, 0x13, 0xD4, 0xC8, 0xEE, 0x34, 0xBC, 0x60, 0xAE, 0xC1, 0x49, 0x15, 0xEF, 0xA9, 0xF0, 0xB8, 0xA1, 0x45, 0xDE, 0x44, 0x44, 0x70, 0x62, 0xCE, 0x7E, 0xAC, 0x63, 0x3D, 0x3F, 0xDD, 0x00, 0xB5, 0x58, 0x62, 0x2D, 0xF5, 0x82, 0x27, 0x59, 0x4C, 0x13, 0x20, 0xA0, 0xC4, 0x28, 0x89, 0x9F, 0x02, 0x3C, 0xCE, 0x1E, 0xD6, 0x39, 0x44, 0x21, 0x95, 0x75, 0x36, 0x34, 0x4B, 0x8A, 0xA1, 0xAA, 0x8A, 0x24, 0x21, 0x7B, 0xF8, 0x56, 0x61, 0x0B, 0x3B, 0x6C, 0x8F, 0x38, 0xFB, 0x14, 0xED, 0xB8, 0x61, 0xB9, 0xA6, 0x88, 0xD8, 0xB9, 0xF8, 0x8F, 0xE4, 0x02, 0x52, 0x6E, 0xCE, 0x13, 0x2C, 0x86, 0x9C, 0x0C, 0xAB, 0xF9, 0x2B, 0x41, 0xD3, 0xAC, 0xC8, 0x8E, 0xC5, 0x19, 0xDE, 0x92, 0xB3, 0xF5, 0x6F, 0x35, 0x93, 0xA1, 0xCD, 0xE5, 0xA7, 0x14, 0xA3, 0x0E, 0x09, 0x0A, 0x1D, 0x25, 0x87, 0x83, 0x74, 0xD9, 0x53, 0x05, 0xEA, 0xF5, 0xCF, 0x35, 0x4B, 0x69, 0xD7, 0xC5, 0x83, 0x92, 0x0C, 0xCC, 0xC6, 0x7C, 0x9B, 0x60, 0x3C, 0x54, 0x6F, 0xC8, 0xF2, 0x17, 0x80, 0x8B, 0xB2, 0xD2, 0xDB, 0x5E, 0xE5, 0xBD, 0x13, 0x17, 0xD4, 0xDD, 0xCC, 0x76, 0x07, 0x17, 0x96, 0x2F, 0xD6, 0xC6, 0xC7, 0xB4, 0x14, 0x34, 0x2A, 0xBB, 0x83, 0xC6, 0x66, 0xFD, 0x91, 0x9C, 0x5E, 0xB7, 0x5E, 0xFD, 0x92, 0x75, 0x5B, 0x9C, 0x28, 0x09, 0xC5, 0x0F, 0x9B, 0x23, 0xEC, 0x77, 0x78, 0xA2, 0xE1, 0x33, 0xFE, 0x1C, 0xD0, 0x3A, 0x43, 0xDF, 0x3E, 0x50, 0x11, 0x24, 0x2A, 0xAB, 0xDF, 0x56, 0x24, 0x04, 0xE8, 0xB2, 0x97, 0xFA, 0x8E, 0x18, 0xB3, 0x82, 0x25, 0x19, 0x36, 0x41, 0xAB, 0xB3, 0xAA, 0x95, 0x6F, 0xD7, 0xC7, 0x68, 0x46, 0x8A, 0x87, 0x2E, 0x59, 0x28, 0x49, 0x23, 0x1E, 0x5A, 0x38, 0x0A, 0xC6, 0xC2, 0x09, 0x46, 0x45, 0x7C, 0x3B, 0xD0, 0x48, 0xF7, 0xAF, 0xED, 0x46, 0xFD, 0x17, 0xD1, 0xB9, 0xFA, 0x29, 0x55, 0x26, 0x40, 0x59, 0xD9, 0xF6, 0xE2, 0xB5, 0xD1, 0xBA, 0xFC, 0x2E, 0x3D, 0xB8, 0xFB, 0x61, 0x16, 0xA2, 0x5D, 0xB0, 0x7E, 0x8C, 0xFA, 0xB5, 0x54, 0xB8, 0xE4, 0xA8, 0xA4, 0x9A, 0x9A, 0x6C, 0x39, 0x5D, 0xE0, 0x05, 0x3F, 0x34, 0xAE, 0xE4, 0xEF, 0x05, 0xDD, 0x75, 0xD2, 0x76, 0xAA, 0x7D, 0xA9, 0xA8, 0xB2, 0xEE, 0x75, 0xC3, 0x79, 0x5E, 0x59, 0x59, 0x78, 0x45, 0x60, 0x54, 0x6B, 0xBE, 0xBE, 0xE0, 0xEB, 0xAE, 0x71, 0x59, 0xD7, 0x33, 0xC3, 0xD6, 0x04, 0xA8, 0xB9, 0x32, 0xC1, 0xD2, 0xD9, 0xD2, 0xB9, 0xF4, 0x58, 0xCB, 0x4F, 0x02, 0x35, 0xB2, 0xCB, 0xA4, 0x93, 0x9F, 0x03, 0x72, 0x64, 0xE4, 0xC9, 0x8D, 0x70, 0x0C, 0x91, 0x7C, 0x34, 0x08, 0xEC, 0x4A, 0x28, 0x6F, 0xB5, 0x07, 0x0E, 0xEC, 0xB7, 0xA9, 0x11, 0xF1, 0xDC, 0xB7, 0x43, 0xC5, 0x3F, 0xB9, 0xB7, 0xBC, 0x37, 0xE6, 0x24, 0xF2, 0x96, 0x2D, 0xF4, 0x56, 0x6A, 0x79, 0x21, 0xE6, 0xA9, 0xA2, 0x9F, 0xBC, 0x0D, 0x46, 0xEF, 0x05, 0x76, 0xBC, 0xE5, 0xB2, 0xE9, 0x27, 0xBA, 0x09, 0x86, 0xE8, 0xED, 0xAE, 0x40, 0x1F, 0x25, 0x6D, 0x6E, 0x7E, 0x06, 0x37, 0x87, 0x67, 0x57, 0xAB, 0xA0, 0x3D, 0xDB, 0xAB, 0x8A, 0x65, 0xE0, 0x4E, 0xEF, 0x51, 0xD9, 0x1F, 0x40, 0x77, 0x47, 0x85, 0xD2, 0x11, 0x50, 0x9A, 0x39, 0x8A, 0x6A, 0x79, 0x6F, 0x0D, 0xC3, 0xD9, 0xD7, 0xBC, 0x42, 0xA9, 0xD1, 0x89, 0x4C, 0xC1, 0x10, 0xD2, 0xE5, 0xC8, 0x6D, 0x3A, 0x21, 0xB1, 0xA6, 0xD9, 0x84, 0xA8, 0xD8, 0xFF, 0xAE, 0xEA, 0x07, 0x76, 0x67, 0xDB, 0xF2, 0xA2, 0x1F, 0xE8, 0x86, 0xD5, 0x73, 0xB2, 0x87, 0xC3, 0x37, 0x1D, 0xEE, 0x28, 0x30, 0x70, 0xD0, 0x74, 0xAA, 0xC8, 0x0F, 0xD0, 0x19, 0x4C, 0x60, 0x2B, 0x81, 0x11, 0xD2, 0xA8, 0xE3, 0xA0, 0x2C, 0x9B, 0xF0, 0x3B, 0xB2, 0x4C, 0x74, 0x2E, 0xE1, 0x7D, 0xD3, 0x22, 0xB6, 0x28, 0x2C, 0xBD, 0x6A, 0x23, 0x63, 0x13, 0xF0, 0xB5, 0x68, 0x07, 0xC9, 0x5D, 0xD5, 0x98, 0xE5, 0x8C, 0xD5, 0x39, 0x64, 0xC8, 0xBF, 0xC2, 0x3E, 0x26, 0x52, 0xE1, 0x37, 0xD0, 0x6A, 0x41, 0x04, 0x1B, 0x05, 0xAC, 0x94, 0x64, 0x1C, 0x7B, 0x93, 0xDE, 0x87, 0x2F, 0xEB, 0x6A, 0x51, 0xC6, 0x24, 0xEC, 0x6F, 0x14, 0x49, 0x83, 0xF6, 0x9D, 0xAB, 0x94, 0x08, 0xB5, 0x01, 0xFA, 0xC2, 0x08, 0xFE, 0xFA, 0x55, 0x75, 0x99, 0x32, 0x32, 0xD4, 0xA1, 0x5F, 0x2E, 0x40, 0x54, 0x26, 0x25, 0xC2, 0x0A, 0x50, 0xBD, 0x20, 0x99, 0xB5, 0x01, 0x36, 0x48, 0x0A, 0x8F, 0xCD, 0xCF, 0xF9, 0x0F, 0xDB, 0xDD, 0x35, 0x42, 0xF7, 0x31, 0xFE, 0x68, 0xE3, 0x02, 0xD5, 0xA7, 0x7D, 0xF3, 0x2A, 0xCD, 0x64, 0x7B, 0xFD, 0x07, 0x0B, 0x97, 0x89, 0x26, 0xAE, 0x82, 0x32, 0xB7, 0x30, 0xE6, 0x8E, 0xE6, 0x72, 0x33, 0xF4, 0x9C, 0xA9, 0x93, 0x30, 0x0A, 0x7C, 0x67, 0x30, 0x85, 0xFF, 0x1B, 0x58, 0x27, 0x51, 0xF5, 0xD7, 0x15, 0xFF, 0x45, 0xBF, 0x76, 0x3E, 0xCB, 0xFD, 0x1B, 0x3F, 0xA6, 0xE1, 0x56, 0xE6, 0xD6, 0xD0, 0x95, 0x15, 0x6F, 0x34, 0x8E, 0x01, 0xB9, 0x05, 0xE7, 0x64, 0x27, 0x56, 0xBD, 0xCE, 0x9C, 0x2C, 0xF0, 0x73, 0x3C, 0x26, 0xFB, 0x87, 0x1B, 0x98, 0x2D, 0x15, 0xEE, 0x83, 0x76, 0x19, 0x7A, 0xB0, 0x43, 0x01, 0x7F, 0xC9, 0xF8, 0xBE, 0xD6, 0xEA, 0x8D, 0x28, 0xD4, 0x89, 0x96, 0x8E, 0x88, 0x73, 0x6C, 0xA8, 0xCC, 0xF3, 0x09, 0x19, 0x5A, 0x39, 0x22, 0xE3, 0x8B, 0xFF, 0xC9, 0x02, 0x40, 0x15, 0xB5, 0xCA, 0x2F, 0xE3, 0xA1, 0x48, 0xB4, 0xD0, 0x53, 0x1E, 0x42, 0x78, 0x98, 0xC7, 0x09, 0x3B, 0xA0, 0x1B, 0x46, 0x67, 0xD8, 0x00, 0x40, 0x2C, 0x0E, 0xEE, 0x5F, 0xD1, 0x64, 0x8A, 0x2C, 0xEF, 0x0C, 0xA8, 0x6E, 0x3A, 0xFC, 0xBB, 0x81, 0x2E, 0xAE, 0xDD, 0xD7, 0x5D, 0xB1, 0x5D, 0x5F, 0xEC, 0x27, 0x2E, 0x10, 0xA4, 0x07, 0x7B, 0x28, 0x32, 0x9A, 0xC5, 0x89, 0x0B, 0x8B, 0x15, 0x87, 0x48, 0x57, 0x8B, 0x63, 0xA2, 0x20, 0xF8, 0xB0, 0x09, 0x87, 0x3D, 0x02, 0xBC, 0xE0, 0x33, 0x17, 0x56, 0x43, 0x6F, 0x79, 0x7D, 0x27, 0x7E, 0x00, 0xBF, 0xA2, 0x7D, 0xBB, 0x27, 0xF3, 0xD0, 0x60, 0xB8, 0x99, 0xE0, 0xBA, 0xF8, 0x6E, 0xAD, 0x3C, 0xC3, 0x4D, 0x72, 0x9B, 0x95, 0xDF, 0xCB, 0xA5, 0xED, 0x4F, 0xAA, 0x1F, 0x73, 0x73, 0x4D, 0xD3, 0x25, 0x46, 0xDC, 0x22, 0x83, 0x53, 0xC2, 0xA5, 0xDC, 0x44, 0x66, 0xE0, 0xDC, 0x2F, 0xBC, 0x88, 0xFB, 0xF4, 0xC4, 0x2C, 0x34, 0x34, 0xEA, 0xEC, 0x91, 0xBD, 0xB0, 0x73, 0x30, 0xDE, 0xB4, 0x14, 0x3C, 0xBC, 0x99, 0x57, 0x39, 0x0B, 0x28, 0x70, 0x3B, 0x9E, 0x2F, 0x00, 0x7C, 0x6C, 0x2B, 0xD4, 0x8F, 0x78, 0x39, 0xC6, 0x1B, 0x25, 0x3E, 0xBC, 0x59, 0xF3, 0x6F, 0x0A, 0x67, 0x70, 0xAF, 0xD1, 0xD2, 0x73, 0x5E, 0xFC, 0x4B, 0x5C, 0xE7, 0xE3, 0x9E, 0xD4, 0x89, 0xA8, 0x9B, 0x5D, 0x10, 0x31, 0x36, 0x78, 0x43, 0xE3, 0x5E, 0xB4, 0xC9, 0xF7, 0x6E, 0x45, 0x0C, 0x32, 0xC1, 0x6D, 0x4B, 0xDE, 0x6F, 0xA8, 0xD9, 0x26, 0x4C, 0xDD, 0x06, 0x5C, 0x35, 0xEC, 0x91, 0x2C, 0xE3, 0xE5, 0xCF, 0x5B, 0x27, 0xF8, 0xC6, 0x5B, 0x40, 0xEF, 0x3A, 0xFB, 0x51, 0x36, 0x91, 0xFB, 0xE7, 0x18, 0x2C, 0x3C, 0x17, 0x73, 0xBB, 0xD3, 0x82, 0x6F, 0x16, 0xEC, 0xD6, 0xA0, 0xA0, 0xD6, 0x6C, 0xFA, 0xAF, 0xFC, 0x18, 0x7E, 0xD9, 0xF5, 0x53, 0xEE, 0x5F, 0x74, 0xA3, 0x8D, 0x9F, 0x9A, 0x80, 0x2C, 0x0C, 0x43, 0xC4, 0xBF, 0x00, 0xA3, 0xB9, 0x2D, 0x82, 0x56, 0x9E, 0x27, 0xB9, 0xFA, 0x6C, 0xBA, 0xC6, 0x2A, 0xED, 0xD4, 0xB1, 0xB9, 0x0A, 0xC7, 0xA8, 0xA7, 0x1D, 0x5C, 0xF1, 0xB9, 0x3D, 0x87, 0xEB, 0xBF, 0xB2, 0x1F, 0x7C, 0x63, 0xCB, 0x09, 0xDA, 0xCE, 0xDD, 0x52, 0x5F, 0x88, 0x1F, 0xB6, 0xF5, 0x53, 0xCF, 0x84, 0xF7, 0x1A, 0x3E, 0x13, 0xAB, 0x00, 0x7C, 0xDE, 0x68, 0x41, 0x20, 0x6F, 0x1D, 0xF9, 0xF5, 0x0C, 0x92, 0xBD, 0x2A, 0x55, 0xD9, 0x5F, 0xA4, 0x75, 0x8F, 0x74, 0x69, 0xFF, 0xA2, 0x5C, 0x10, 0x14, 0x51, 0x1F, 0x2D, 0xC9, 0xF1, 0xDD, 0x5B, 0x6E, 0xCC, 0xBE, 0x71, 0x77, 0xD4, 0x57, 0x50, 0x36, 0x76, 0xB4, 0xB2, 0x03, 0xD9, 0x6A, 0x3C, 0x5C, 0xF4, 0x0A, 0x18, 0x98, 0x3F, 0x4E, 0x30, 0x82, 0xB7, 0x96, 0x9A, 0x7A, 0xEA, 0x4E, 0x61, 0x5A, 0x9A, 0xB2, 0x2F, 0x40, 0x6F, 0x17, 0x79, 0xB5, 0x7D, 0x89, 0xCE, 0x2C, 0x68, 0x75, 0xDD, 0x75, 0x65, 0xC5, 0xA6, 0x93, 0x65, 0x93, 0x24, 0x0B, 0xDD, 0x74, 0xFA, 0xA9, 0x7C, 0x13, 0xFB, 0x29, 0x4A, 0x7B, 0x14, 0x34, 0xD9, 0x27, 0xAA, 0x04, 0x17, 0x2F, 0xE8, 0x65, 0xDF, 0xF2, 0x0E, 0x90, 0x4B, 0x4E, 0x95, 0x57, 0x18, 0xA7, 0x65, 0xF6, 0x85, 0x15, 0x6D, 0x8F, 0x24, 0xDB, 0xF9, 0x39, 0x48, 0xE0, 0x83, 0xBA, 0x5F, 0xDA, 0xE1, 0x9B, 0xBE, 0x97, 0x5E, 0x93, 0x27, 0xBB, 0x1D, 0xCD, 0x79, 0x2B, 0x98, 0x6F, 0xEF, 0xA6, 0x94, 0x61, 0x0A, 0xD3, 0x17, 0xE2, 0xA9, 0xE0, 0x1D, 0xC3, 0x8F, 0x02, 0x3F, 0xDE, 0x03, 0x92, 0x3C, 0x75, 0xB5, 0x7E, 0x6D, 0xDA, 0xB5, 0xBE, 0x39, 0x15, 0xB5, 0x11, 0xF7, 0xDA, 0x2F, 0x17, 0x48, 0x02, 0xC5, 0xF5, 0xDB, 0x32, 0xFF, 0xFA, 0xF6, 0x94, 0x5E, 0x56, 0x85, 0xB9, 0x1D, 0xCE, 0x19, 0x21, 0x8C, 0xB2, 0xBF, 0xA0, 0x32, 0xC5, 0x45, 0xE6, 0x9F, 0xC5, 0xDD, 0xD0, 0x09, 0x93, 0x34, 0xC1, 0x07, 0xA0, 0xE8, 0xED, 0x26, 0x70, 0x26, 0x97, 0x77, 0xED, 0x3C, 0xD4, 0x06, 0xB0, 0x5D, 0x00, 0xFC, 0x02, 0xE8, 0x2F, 0xBC, 0x85, 0xF8, 0x42, 0x8E, 0x82, 0xE1, 0xC8, 0x37, 0xD8, 0x37, 0xD2, 0x07, 0x1D, 0x40, 0xC6, 0xAF, 0xE6, 0xE3, 0x23, 0x60, 0x13, 0xC7, 0xD9, 0x84, 0x03, 0xE4, 0x69, 0xA1, 0x26, 0xBA, 0xC0, 0xAB, 0x6F, 0xFA, 0xB8, 0x37, 0x19, 0xFA, 0xDA, 0x14, 0x80, 0x4F, 0x17, 0x74, 0xFD, 0x82, 0x96, 0x90, 0x11, 0x45, 0xD1, 0xF0, 0x14, 0xA2, 0x8F, 0xED, 0x83, 0x7F, 0xE3, 0x3D, 0x91, 0xD6, 0xA8, 0x03, 0x76, 0x66, 0xD5, 0x33, 0xAC, 0x14, 0xF9, 0xCF, 0x01, 0xC1, 0x2B, 0x61, 0xCA, 0xFC, 0x1D, 0x61, 0x04, 0x0D, 0xBE, 0x68, 0xE7, 0x18, 0xA5, 0x87, 0x5C, 0xB2, 0xE6, 0xBE, 0x97, 0xBF, 0xEC, 0x38, 0x02, 0x08, 0xC4, 0x99, 0x05, 0x4F, 0xC0, 0x5F, 0x42, 0x47, 0xE6, 0x1C, 0xBC, 0x8E, 0x2F, 0x89, 0x18, 0x8D, 0x64, 0x50, 0x85, 0xAB, 0x84, 0xD8, 0x22, 0x7C, 0x9C, 0x83, 0x17, 0x6E, 0x85, 0xDC, 0x37, 0xAF, 0xC1, 0x15, 0xF0, 0xFB, 0x17, 0x6C, 0xAA, 0xB4, 0x70, 0xEB, 0x65, 0x17, 0x4E, 0x4E, 0xB6, 0x5B, 0xBB, 0x2F, 0xEF, 0xA0, 0xE6, 0x64, 0xDE, 0x7F, 0xE0, 0x42, 0x05, 0x4B, 0x0F, 0x40, 0x59, 0x12, 0xF1, 0xC1, 0x0C, 0xF8, 0x33, 0x7B, 0x7F, 0xF5, 0x0A, 0xB4, 0x95, 0x0C, 0x71, 0xA8, 0xC6, 0x7A, 0xB1, 0xF9, 0xE6, 0x83, 0xF8, 0x62, 0xA4, 0xF9, 0xD9, 0x8B, 0x54, 0xA4, 0x76, 0xEA, 0x45, 0x0E, 0x67, 0x58, 0xC9, 0xF1, 0xD6, 0x59, 0x5C, 0x9D, 0xFE, 0x85, 0xFE, 0x26, 0x70, 0x50, 0x97, 0x47, 0xB9, 0x82, 0x8F, 0x55, 0x2B, 0x23, 0x0E, 0xC3, 0x3B, 0x24, 0x4E, 0xDE, 0x3F, 0xD1, 0x00, 0xBA, 0xD5, 0x31, 0x0A, 0x43, 0x70, 0x4B, 0x0B, 0x17, 0xEC, 0x0F, 0xBA, 0xEC, 0xC9, 0xE3, 0x54, 0xE7, 0x0E, 0xA3, 0x73, 0xAA, 0xB4, 0x07, 0xF5, 0x93, 0x5A, 0xA6, 0x72, 0x93, 0xCA, 0x56, 0xEA, 0x03, 0x79, 0xE7, 0xF3, 0x2A, 0x28, 0x4F, 0x70, 0x51, 0x46, 0x6B, 0x44, 0x10, 0x74, 0x59, 0x71, 0xCE, 0x5B, 0x8E, 0x8E, 0xE2, 0x3F, 0x74, 0x94, 0x62, 0x7B, 0x88, 0x61, 0x16, 0x52, 0xEC, 0x2D, 0x4A, 0x3C, 0x36, 0x49, 0xA9, 0x3D, 0xE1, 0x71, 0xF6, 0x6E, 0x5A, 0x5A, 0xD7, 0xFD, 0xE6, 0x4A, 0xCE, 0xC9, 0x46, 0xE3, 0x1C, 0x84, 0xB7, 0xB3, 0x62, 0x29, 0xB5, 0x02, 0x48, 0xCF, 0xDF, 0x70, 0x70, 0x0A, 0x14, 0x9F, 0xFE, 0x79, 0xB5, 0x29, 0xF2, 0x44, 0xE8, 0xE4, 0xE8, 0x89, 0x45, 0x10, 0x57, 0x2D, 0xCE, 0xE2, 0x13, 0xD1, 0x86, 0x47, 0xEE, 0xA9, 0xB6, 0x17, 0x99, 0xB3, 0xF5, 0x69, 0xD8, 0xC9, 0x65, 0x4D, 0x10, 0xA7, 0xA0, 0xF3, 0x65, 0xB6, 0x19, 0x77, 0xB0, 0xBE, 0x06, 0x3F, 0x0B, 0xEC, 0x28, 0xDD, 0x10, 0x2E, 0x82, 0x96, 0x66, 0xED, 0x5E, 0x65, 0x88, 0x3C, 0x17, 0x07, 0x3B, 0x4E, 0xC5, 0x0A, 0x49, 0x89, 0xE5, 0x78, 0x3C, 0x1C, 0x3D, 0xFB, 0x68, 0x6F, 0xEA, 0xC8, 0xDB, 0xEE, 0x67, 0x9A, 0xD3, 0xD2, 0x2E, 0x00, 0x8D, 0x1E, 0x1C, 0xBC, 0x7F, 0x51, 0xD6, 0x6A, 0x6E, 0x5B, 0xDB, 0x22, 0xEC, 0x2D, 0xB0, 0xA9, 0xEA, 0x56, 0xD8, 0x6D, 0x68, 0x9E, 0xFE, 0xA7, 0xE7, 0x4F, 0x74, 0xAC, 0x74, 0xB1, 0xE3, 0x64, 0xEC, 0x07, 0x65, 0x6F, 0x99, 0x84, 0x5F, 0x45, 0xEF, 0xDD, 0xB3, 0xA5, 0xBD, 0xB9, 0xC0, 0xD9, 0x9F, 0x94, 0x13, 0xF7, 0x6F, 0xE3, 0x1F, 0xB2, 0x1E, 0xA8, 0xCB, 0x5E, 0x4F, 0xFC, 0x04, 0xEB, 0x08, 0x2B, 0x62, 0x27, 0xC4, 0x0F, 0xEF, 0x27, 0xE6, 0xC0, 0x98, 0xD7, 0x1D, 0x22, 0x01, 0x1E, 0xE1, 0x30, 0x9B, 0xF8, 0x00, 0xB9, 0x98, 0x9F, 0x27, 0x1D, 0xC1, 0xFB, 0xB7, 0x8E, 0x92, 0x79, 0xE4, 0x8D, 0xD3, 0xA7, 0x89, 0x08, 0xA2, 0xBE, 0xB1, 0x19, 0x7F, 0x49, 0xF8, 0x65, 0x5D, 0xC7, 0xAB, 0xF1, 0x93, 0xC4, 0x77, 0x9C, 0x8B, 0xBD, 0x0E, 0x7F, 0x85, 0x97, 0x62, 0x36, 0x5E, 0x3B, 0x09, 0x0B, 0x84, 0xB0, 0x2F, 0x20, 0xE4, 0xB0, 0x87, 0x79, 0x20, 0xD1, 0x0B, 0x55, 0xDF, 0x0E, 0xC4, 0x65, 0x8A, 0x9D, 0x27, 0x4F, 0xE2, 0x26, 0x92, 0x63, 0x75, 0x27, 0xB1, 0x76, 0x61, 0x73, 0xE6, 0x0E, 0xAC, 0x95, 0x3D, 0x8E, 0x8F, 0xC4, 0x5E, 0x32, 0x8D, 0xE1, 0xA3, 0x70, 0x2B, 0xF2, 0x93, 0xD7, 0x7C, 0xFC, 0x28, 0x06, 0xD8, 0x1F, 0x24, 0xEC, 0x91, 0x7D, 0xE6, 0xD3, 0x89, 0x3D, 0x30, 0xF7, 0x76, 0x38, 0xB6, 0x32, 0x87, 0x3E, 0x71, 0x15, 0x7D, 0xA4, 0x13, 0xD6, 0x55, 0xA1, 0x22, 0xD5, 0xC2, 0x8C, 0x11, 0xE8, 0x07, 0xD9, 0x00, 0x7A, 0x10, 0x5B, 0x26, 0xCE, 0x0B, 0x7B, 0x83, 0xC9, 0xD9, 0x19, 0x9E, 0x7F, 0xF1, 0x10, 0xA2, 0xD8, 0x3E, 0x19, 0x7F, 0x80, 0x26, 0x9A, 0x5B, 0x10, 0xB3, 0x90, 0x69, 0x37, 0x54, 0x68, 0x7E, 0x99, 0xF4, 0x78, 0x14, 0x6A, 0x53, 0x00, 0xD5, 0x76, 0x21, 0xEF, 0xB3, 0xDE, 0x69, 0x65, 0xA8, 0x5F, 0xFA, 0x63, 0xA4, 0x0D, 0x8D, 0x55, 0x9C, 0x0B, 0x6B, 0xC4, 0x46, 0x88, 0x0D, 0xBC, 0x9C, 0xF1, 0x69, 0xD4, 0x80, 0x7D, 0x05, 0x5E, 0x87, 0x05, 0x99, 0xEF, 0xC0, 0x3F, 0x21, 0xA9, 0x57, 0x3B, 0xD0, 0xF0, 0xC6, 0x8C, 0xFE, 0x8B, 0xC8, 0xED, 0xAA, 0x9E, 0x1A, 0x1C, 0x29, 0x2C, 0x3E, 0xA4, 0xBD, 0x8E, 0x08, 0xF4, 0x08, 0xFC, 0x19, 0xB9, 0xA8, 0x6D, 0xDD, 0xD7, 0x8E, 0x2A, 0xE4, 0xFE, 0x9E, 0x8F, 0xB1, 0x8B, 0xCC, 0x15, 0xFB, 0x56, 0x3C, 0x1D, 0x37, 0x31, 0x17, 0xE2, 0xAF, 0x90, 0x86, 0x2B, 0xA7, 0x51, 0xF7, 0xA3, 0x97, 0xFA, 0x76, 0x20, 0x25, 0x6D, 0x23, 0xAA, 0xF4, 0xC8, 0xE6, 0xDA, 0x25, 0xDA, 0x45, 0xC8, 0x98, 0xD2, 0xD1, 0x50, 0x2E, 0x12, 0xA2, 0xAF, 0x09, 0x1D, 0x89, 0x3A, 0x6B, 0x2C, 0x3C, 0x9E, 0x62, 0x65, 0x82, 0x71, 0xF6, 0x52, 0x5C, 0x8B, 0x0F, 0x9A, 0xF7, 0xE3, 0xFF, 0x90, 0x07, 0x57, 0x38, 0xC8, 0x87, 0x53, 0x58, 0x6F, 0x3A, 0xB2, 0xAB, 0x37, 0xA2, 0x92, 0x85, 0x9F, 0xB6, 0x6A, 0xD5, 0xAF, 0xE0, 0xB3, 0x35, 0x07, 0x41, 0x3B, 0x64, 0x4E, 0x51, 0x7B, 0x48, 0x04, 0xF2, 0x2D, 0x03, 0xF5, 0x88, 0xC2, 0x32, 0x44, 0x16, 0xF6, 0x0A, 0xBC, 0x81, 0x28, 0xB3, 0x18, 0x4F, 0x38, 0xA0, 0xE3, 0xAE, 0x24, 0xA0, 0x0B, 0x2E, 0x9F, 0xE8, 0xE9, 0x41, 0xCC, 0x4F, 0x9D, 0xAE, 0x90, 0xC1, 0xEA, 0xA3, 0x26, 0xEA, 0x36, 0x38, 0xAC, 0x79, 0x31, 0x80, 0xC3, 0xD7, 0x2B, 0x26, 0xEC, 0x85, 0x90, 0x0B, 0x39, 0xF3, 0x3D, 0x0C, 0xB1, 0x74, 0xC9, 0x68, 0xFB, 0xE3, 0xF8, 0x0D, 0x32, 0xD8, 0x22, 0x89, 0x88, 0x40, 0x97, 0x9F, 0xFD, 0x29, 0xAB, 0xE0, 0x7C, 0xEA, 0xB6, 0x15, 0x77, 0xF0, 0xE2, 0xCA, 0xA7, 0x0A, 0x17, 0x00, 0x99, 0xAA, 0x19, 0xEC, 0x6E, 0xD0, 0x09, 0x30, 0x62, 0xD4, 0xE0, 0xC3, 0x90, 0x62, 0xDA, 0x02, 0x6A, 0xF2, 0x90, 0x51, 0x9E, 0x90, 0xDC, 0x7E, 0x24, 0xF9, 0x16, 0x1A, 0x6D, 0xBE, 0x90, 0x3C, 0x0F, 0x9E, 0x38, 0xD3, 0x26, 0xB5, 0xC2, 0x83, 0x8F, 0x18, 0x8B, 0x38, 0xB8, 0x4B, 0xD9, 0x6D, 0xF6, 0x0C, 0xF6, 0x50, 0x99, 0xCA, 0x37, 0xC1, 0x10, 0xC0, 0x9C, 0x3E, 0x87, 0x99, 0x87, 0x1C, 0xA6, 0x4E, 0xA2, 0x09, 0x1E, 0xE3, 0xC8, 0xBF, 0xF0, 0x57, 0x3B, 0x2D, 0x59, 0x0E, 0xDD, 0x34, 0x1B, 0x20, 0x59, 0x28, 0xF0, 0xD4, 0x65, 0xB1, 0x5C, 0x7C, 0xB6, 0x6B, 0x97, 0x70, 0x82, 0x68, 0x42, 0xE9, 0x2C, 0xFE, 0x55, 0xB6, 0x44, 0xC1, 0x63, 0xD6, 0xF1, 0x87, 0xF3, 0x6E, 0xD2, 0x2B, 0xE9, 0xC8, 0x10, 0x4B, 0x6A, 0x13, 0x39, 0xDA, 0xBD, 0x83, 0x2C, 0x43, 0x8F, 0xDB, 0x79, 0x90, 0x61, 0xF0, 0x49, 0xB3, 0x58, 0x72, 0x2D, 0xF4, 0x7A, 0xC0, 0x5D, 0x74, 0x5B, 0xB7, 0xA7, 0x03, 0x63, 0xBF, 0xA9, 0x1F, 0x15, 0x6B, 0x99, 0xAF, 0x72, 0xB5, 0x7C, 0x1E, 0xAD, 0x96, 0x94, 0x70, 0xC7, 0x52, 0x98, 0xF0, 0x65, 0xF0, 0x4D, 0xB2, 0x87, 0x3F, 0xCC, 0xDD, 0x95, 0x0C, 0xC4, 0x8F, 0xDB, 0x8D, 0x25, 0x1D, 0x90, 0x4A, 0x33, 0x3F, 0x72, 0x3E, 0x1C, 0x78, 0xF2, 0xA8, 0xF0, 0x75, 0x41, 0x67, 0xDB, 0x2D, 0xD6, 0x57, 0x1F, 0x5E, 0x74, 0x86, 0xF1, 0xCA, 0x18, 0x21, 0x7D, 0x46, 0xBD, 0x53, 0xA7, 0x72, 0x30, 0xF2, 0xB8, 0x7C, 0x56, 0xF0, 0x6C, 0x72, 0x8B, 0xF0, 0x95, 0xDB, 0x20, 0xB9, 0x80, 0xEC, 0xB3, 0x7D, 0x4F, 0x4E, 0x41, 0x13, 0xCD, 0xB6, 0x92, 0x13, 0xE0, 0xCC, 0xE3, 0xA7, 0x84, 0x9C, 0xAA, 0xD7, 0xAD, 0x03, 0xFC, 0xAB, 0xA5, 0x17, 0x0B, 0xB3, 0xE8, 0x53, 0xF9, 0xF5, 0xD2, 0x78, 0x6A, 0x63, 0x56, 0x65, 0x5A, 0x2C, 0xE9, 0xA3, 0xC9, 0xDB, 0x63, 0x40, 0xBC, 0x96, 0x0E, 0xB8, 0xAD, 0x21, 0xDE, 0xD0, 0xF9, 0xB6, 0x67, 0xC8, 0xE1, 0x98, 0x81, 0x59, 0x24, 0x39, 0x09, 0xEE, 0x3D, 0x91, 0x20, 0x78, 0xD1, 0x1E, 0xD2, 0x72, 0x81, 0x0F, 0x35, 0x44, 0xE4, 0xDF, 0xA2, 0x73, 0x2A, 0x18, 0xC9, 0x2A, 0x6A, 0x4C, 0xA1, 0x24, 0xE5, 0x37, 0xF1, 0x2B, 0xDB, 0x32, 0x70, 0x90, 0xC8, 0x50, 0xAD, 0x75, 0x95, 0x11, 0xC7, 0xF8, 0xD5, 0xB6, 0xF5, 0xC4, 0x1F, 0xEC, 0xB2, 0x59, 0x3A, 0x39, 0x07, 0x7E, 0x76, 0xEC, 0xB5, 0x60, 0x4F, 0xDF, 0xAA, 0xE6, 0x41, 0xBE, 0x53, 0xE7, 0xB6, 0x7C, 0x3B, 0x7A, 0x73, 0x43, 0x96, 0xE8, 0x11, 0xD9, 0x5C, 0xA1, 0x4F, 0xBE, 0x4A, 0xD4, 0xE4, 0x9F, 0x0B, 0xB4, 0x23, 0xF6, 0x68, 0xD7, 0xBA, 0xA6, 0x10, 0xC5, 0x82, 0x2A, 0xDB, 0x41, 0xE2, 0x3B, 0xAE, 0x36, 0x7B, 0x47, 0x1A, 0x21, 0x46, 0xC7, 0x36, 0x08, 0x9C, 0x4E, 0x87, 0xB6, 0x8C, 0x62, 0xAE, 0xF6, 0x43, 0x79, 0xD5, 0xD4, 0xC7, 0x8E, 0xED, 0xE2, 0x1C, 0x72, 0x41, 0x7D, 0x62, 0xB2, 0x07, 0xB1, 0xB1, 0xA4, 0x63, 0x17, 0x9F, 0xB0, 0xCE, 0x8C, 0x73, 0x95, 0x12, 0x02, 0x11, 0x6E, 0xB7, 0x87, 0xF8, 0x4C, 0xEC, 0x34, 0x4F, 0x20, 0x2D, 0x91, 0x03, 0x47, 0x37, 0x64, 0x18, 0x72, 0x37, 0x36, 0x8C, 0x53, 0x0F, 0x72, 0xAF, 0xE7, 0x4E, 0x96, 0xDF, 0x01, 0xE6, 0x08, 0x27, 0x48, 0xDE, 0x01, 0xFA, 0xA4, 0xEB, 0x22, 0x27, 0x70, 0x67, 0xD0, 0x2C, 0x36, 0x1D, 0xBC, 0xE0, 0xE6, 0xC4, 0x6C, 0x01, 0x6F, 0xD8, 0x4D, 0xA2, 0x0D, 0x40, 0x8D, 0xD9, 0x05, 0x2A, 0x07, 0x4C, 0x3A, 0xBA, 0x58, 0xBB, 0x1F, 0xED, 0xAE, 0xAB, 0x53, 0x3D, 0x44, 0x5B, 0xB3, 0xDF, 0xCA, 0x6E, 0xA3, 0xFD, 0x6C, 0x9E, 0x64, 0x14, 0xEA, 0x9F, 0x64, 0x21, 0xCC, 0x46, 0x0D, 0x77, 0x5F, 0x63, 0x03, 0x10, 0xA5, 0xAB, 0x0F, 0x33, 0x1D, 0xF6, 0xB6, 0x3D, 0x44, 0x3D, 0x86, 0x02, 0xCC, 0xD6, 0x52, 0xE1, 0xE0, 0xB3, 0x23, 0x8B, 0xD2, 0x8D, 0x05, 0xB7, 0x6A, 0x77, 0x28, 0x83, 0xD8, 0xEF, 0xD9, 0x4B, 0xA5, 0xCD, 0xFC, 0xB9, 0xFC, 0x66, 0xB1, 0x2D, 0xBD, 0x3F, 0x31, 0x55, 0xF0, 0x92, 0xBC, 0xB5, 0xDB, 0x80, 0x7F, 0x03, 0xFF, 0xE0, 0x52, 0x45, 0x9F, 0x42, 0xBE, 0xDA, 0x3C, 0xA2, 0xCA, 0x60, 0x53, 0xD3, 0x3E, 0xCA, 0x11, 0x0A, 0xEC, 0xBC, 0xAA, 0xE1, 0xAB, 0x7D, 0xAA, 0x8B, 0x14, 0x32, 0xE5, 0xA8, 0x4C, 0x6F, 0xE9, 0x6C, 0xE9, 0x31, 0xA6, 0x5C, 0x14, 0x26, 0x6A, 0x8B, 0x7F, 0x2C, 0x58, 0x24, 0x98, 0xB0, 0xF3, 0x23, 0xDF, 0x87, 0xAE, 0x70, 0xD9, 0x4D, 0x13, 0xD8, 0x39, 0x1B, 0x1D, 0x45, 0xC0, 0x4F, 0x4D, 0x79, 0xD4, 0x4C, 0xA8, 0xB4, 0xA3, 0x4B, 0xFD, 0x4E, 0xBF, 0xB3, 0xAA, 0x49, 0x7E, 0x3F, 0x53, 0x96, 0x51, 0x27, 0xD9, 0x9F, 0x3E, 0x94, 0xBE, 0x24, 0xEC, 0x55, 0x0E, 0x8B, 0x9F, 0xCF, 0xCA, 0xA4, 0x1E, 0x3B, 0xDD, 0x99, 0x37, 0x82, 0xBD, 0x2B, 0x4F, 0xD2, 0xDB, 0x89, 0x2C, 0x9B, 0x60, 0x2A, 0x05, 0x11, 0x98, 0xEE, 0xA7, 0x66, 0x41, 0x67, 0xDA, 0x25, 0x6A, 0xCF, 0xD2, 0xC6, 0xCA, 0xB3, 0xF2, 0xFD, 0x05, 0x32, 0xDD, 0x4A, 0xF1, 0x8D, 0x9C, 0x53, 0x54, 0x94, 0xD0, 0x4F, 0xD7, 0x1F, 0x67, 0xCC, 0x2E, 0x56, 0xA5, 0xEE, 0xD8, 0xCE, 0xE4, 0x4B, 0x66, 0xAC, 0xF8, 0x47, 0x2F, 0xA2, 0x82, 0x6C, 0xE6, 0x53, 0x49, 0xE8, 0x1C, 0xD3, 0x83, 0x94, 0x39, 0x74, 0xB3, 0x8D, 0xA3, 0x3A, 0xD6, 0xF0, 0xBE, 0x02, 0x97, 0x7D, 0xAF, 0x7A, 0x90, 0x9E, 0x25, 0x2E, 0x2C, 0xE1, 0x90, 0x8B, 0x84, 0x13, 0xF2, 0x36, 0xC5, 0xDA, 0xF3, 0xBF, 0x65, 0xC4, 0x6F, 0x6F, 0x65, 0x42, 0x14, 0xEE, 0x2B, 0x24, 0xF4, 0x68, 0xC6, 0xDB, 0x66, 0x0C, 0x15, 0x83, 0xB6, 0x9A, 0xD2, 0x94, 0x03, 0xF4, 0xB2, 0xF5, 0x95, 0x2A, 0xA0, 0x6B, 0x47, 0xF9, 0x75, 0xD9, 0xDD, 0xE6, 0x93, 0xE9, 0x7B, 0xC4, 0x71, 0x35, 0xF3, 0x88, 0x70, 0x41, 0x47, 0xC9, 0xA3, 0xC3, 0x4E, 0xFC, 0x5A, 0x7D, 0xD3, 0xF6, 0xD9, 0x8C, 0xA5, 0xFA, 0xBF, 0x15, 0x35, 0xD4, 0x23, 0x76, 0xB2, 0xCD, 0x2E, 0x2A, 0x00, 0x8B, 0x36, 0x7D, 0x40, 0xCD, 0x85, 0x2D, 0xDB, 0xC2, 0x94, 0xD5, 0xC7, 0x06, 0xCA, 0x67, 0xC9, 0xF4, 0x47, 0xF8, 0x9A, 0x95, 0xE2, 0xED, 0xCD, 0x2E, 0xB8, 0x42, 0x00, 0x56, 0x9D, 0x89, 0xB9, 0xCE, 0x0F, 0x2D, 0xF8, 0xB7, 0x35, 0x95, 0x7E, 0xA3, 0xAD, 0x5B, 0xF1, 0x9D, 0xEA, 0x12, 0x14, 0xDB, 0xBC, 0xA2, 0x56, 0xE0, 0x06, 0x66, 0x09, 0xD4, 0x30, 0x38, 0xB9, 0x61, 0x65, 0x7E, 0x16, 0xE7, 0x73, 0xC9, 0xB8, 0xEC, 0x54, 0xEE, 0x7C, 0xB5, 0x8D, 0xD6, 0x82, 0x47, 0x61, 0x47, 0x54, 0xFE, 0xC0, 0xB4, 0x43, 0xA4, 0xAC, 0x01, 0xA8, 0xDF, 0xBE, 0x47, 0x3C, 0x1C, 0xF8, 0xB8, 0xF2, 0x00, 0x1B, 0x0D, 0x9A, 0xD8, 0x4E, 0x60, 0xF6, 0x80, 0x63, 0xCC, 0x84, 0x34, 0x00, 0xFC, 0x6C, 0x58, 0x94, 0xFB, 0x11, 0x1D, 0x5E, 0xB4, 0x33, 0x2B, 0x0C, 0xE9, 0x53, 0x7C, 0x48, 0xAF, 0x40, 0x74, 0xE8, 0x2A, 0xE5, 0x20, 0x72, 0x38, 0x46, 0x2A, 0x23, 0x10, 0x8F, 0x6D, 0x61, 0xA2, 0x97, 0x70, 0xED, 0x0A, 0x86, 0x5D, 0x0A, 0x09, 0x6D, 0x96, 0x31, 0xF3, 0xC1, 0x5E, 0xD3, 0x66, 0x7A, 0x39, 0x18, 0x55, 0xA7, 0xD1, 0x1F, 0x65, 0x27, 0x15, 0xCE, 0xCA, 0x9C, 0xCE, 0xDC, 0x55, 0xD8, 0x69, 0x8A, 0x69, 0x5F, 0x24, 0x56, 0x39, 0x95, 0xFC, 0x14, 0x5D, 0x22, 0xBD, 0x4C, 0xA4, 0x6F, 0x3D, 0x21, 0xA2, 0xB1, 0xC1, 0x15, 0xB6, 0xFC, 0x37, 0xC8, 0x12, 0xEB, 0x74, 0xFA, 0x3E, 0xC4, 0x37, 0xF9, 0x4E, 0xFD, 0x05, 0x2F, 0xD6, 0x62, 0xFA, 0x85, 0x8A, 0xE8, 0x82, 0xE8, 0x8C, 0x34, 0xD9, 0x70, 0xF9, 0x3E, 0x75, 0x87, 0x38, 0x02, 0xBE, 0xA6, 0x58, 0x2A, 0x38, 0x1A, 0xF5, 0x4D, 0x3A, 0x97, 0xEF, 0xB5, 0x6D, 0xAD, 0xF0, 0x0F, 0xB5, 0x67, 0x45, 0x36, 0x3F, 0x07, 0xFD, 0x69, 0xBD, 0x8D, 0x6E, 0x83, 0x5D, 0x4C, 0xF8, 0xD4, 0x33, 0x68, 0x72, 0xB5, 0x3E, 0xA7, 0x29, 0xB3, 0x25, 0x1F, 0xD0, 0xD5, 0x6B, 0x97, 0xC9, 0xA6, 0xAA, 0x2D, 0x55, 0x1E, 0xD0, 0x6D, 0x79, 0xB6, 0x4C, 0x17, 0x35, 0x52, 0xC2, 0x13, 0x9B, 0x06, 0x14, 0x0A, 0x4B, 0xF9, 0x7D, 0xCB, 0x63, 0xF8, 0x10, 0xAE, 0xB1, 0xFA, 0x45, 0xD7, 0xC2, 0xC7, 0x4D, 0x12, 0xA9, 0x17, 0x90, 0x59, 0x35, 0x27, 0x67, 0x4C, 0xA1, 0x2E, 0x2F, 0x5D, 0xB7, 0x48, 0x7F, 0x5B, 0xF2, 0x46, 0x55, 0x96, 0xB9, 0x0D, 0x5C, 0x26, 0xF7, 0x4A, 0x1F, 0x1A, 0x71, 0x45, 0x62, 0xA2, 0x58, 0xE5, 0x1F, 0x22, 0x0C, 0x11, 0x85, 0x3A, 0xC7, 0xF1, 0x03, 0xC9, 0xC5, 0x56, 0x8D, 0x74, 0x0D, 0xE2, 0x6E, 0x92, 0x46, 0xFD, 0x82, 0x0C, 0xAB, 0x52, 0xB2, 0xC1, 0x1A, 0xB7, 0x5C, 0x9E, 0xF6, 0x73, 0x99, 0x5E, 0x7C, 0x50, 0xB5, 0xBB, 0xE0, 0x16, 0xEF, 0xAF, 0xEC, 0x69, 0x8E, 0x6B, 0x84, 0xAD, 0xF8, 0x71, 0xFA, 0x17, 0xFF, 0x20, 0xE1, 0x74, 0x59, 0x90, 0xF3, 0x3A, 0xBE, 0x0D, 0xF5, 0xD3, 0xAA, 0x96, 0x2E, 0x41, 0x8E, 0x99, 0xA8, 0xE8, 0xD1, 0x90, 0x41, 0xE5, 0x96, 0xEC, 0x83, 0x2D, 0xF7, 0xF5, 0xD5, 0xDA, 0x8B, 0xF5, 0x8B, 0xC4, 0xE1, 0xAA, 0xB1, 0x15, 0x1B, 0x78, 0xB0, 0x4C, 0x59, 0x98, 0x76, 0xD0, 0x4D, 0x5C, 0x95, 0x75, 0xDE, 0x4F, 0x2E, 0x78, 0xAB, 0xCC, 0x74, 0xDE, 0xC0, 0x9F, 0xC0, 0xA0, 0x56, 0x9F, 0x69, 0x31, 0xBA, 0xDB, 0xE4, 0x05, 0xF5, 0x06, 0xDA, 0x5C, 0x71, 0x37, 0xEB, 0xBF, 0xEE, 0x5B, 0x59, 0xF1, 0xDA, 0x2B, 0x6D, 0xDE, 0xC2, 0x1E, 0x95, 0x73, 0xDD, 0x27, 0xEE, 0x6D, 0x59, 0x5A, 0xD9, 0x8B, 0x03, 0x66, 0xE2, 0xB8, 0xDC, 0x93, 0x5B, 0xD6, 0x0A, 0x3A, 0x34, 0x86, 0xCE, 0xDB, 0x99, 0x97, 0xFC, 0x2E, 0xEB, 0xFD, 0x74, 0x22, 0xFA, 0x9F, 0xE9, 0x61, 0xEA, 0x0A, 0x24, 0x2D, 0xDE, 0x51, 0x91, 0xC4, 0x9D, 0x92, 0xD1, 0x5A, 0x3C, 0x9F, 0x93, 0xC0, 0xB6, 0xE8, 0xB9, 0xDC, 0x5F, 0x69, 0x0E, 0x19, 0x7D, 0xBC, 0xE5, 0xE1, 0xC6, 0x9A, 0x71, 0xBC, 0xE6, 0x4D, 0x55, 0xB2, 0xA7, 0x80, 0xB5, 0x13, 0x26, 0x7C, 0x0C, 0xC4, 0x5A, 0x2B, 0xF8, 0xFD, 0x40, 0xB4, 0xE9, 0x07, 0xE6, 0x00, 0x10, 0x5D, 0x34, 0xB1, 0x7C, 0x3F, 0x42, 0xE9, 0x32, 0x0A, 0x6F, 0xC2, 0x19, 0xFC, 0xFB, 0xFA, 0x55, 0xF0, 0xFE, 0xD4, 0xA0, 0x8C, 0x3D, 0x70, 0xE8, 0xFE, 0x5D, 0xEA, 0x76, 0x78, 0xCE, 0x66, 0x6B, 0xF9, 0x30, 0xA8, 0xC4, 0x69, 0x97, 0xB0, 0x10, 0x3C, 0x6A, 0x95, 0xCF, 0x4F, 0x06, 0x8D, 0x4D, 0xCE, 0x31, 0x33, 0x81, 0x3B, 0x85, 0xBD, 0x65, 0x28, 0x53, 0xAA, 0xBD, 0x58, 0xD0, 0x4A, 0x55, 0xF1, 0xBF, 0xE7, 0xEC, 0x27, 0x3E, 0xA5, 0x12, 0xBA, 0x46, 0x62, 0x7E, 0xD8, 0x7E, 0xF5, 0x62, 0x7C, 0x9E, 0x6F, 0x8D, 0xAC, 0x00, 0x2D, 0x75, 0x4A, 0x15, 0x06, 0xC3, 0x6B, 0xAD, 0x86, 0xF0, 0x6D, 0xC1, 0x7B, 0xC6, 0x0F, 0xE9, 0x8B, 0xA0, 0x57, 0xE1, 0xDA, 0xD2, 0x67, 0xD2, 0x4A, 0x8D, 0xAA, 0x60, 0xBD, 0xD8, 0x94, 0xD6, 0x64, 0x8B, 0x04, 0x0D, 0x29, 0x67, 0xB5, 0x3F, 0xF8, 0xB2, 0xB0, 0x3C, 0x55, 0x31, 0xBD, 0x7E, 0xF3, 0x3A, 0xD9, 0x6A, 0xA2, 0xD5, 0x69, 0xB9, 0x70, 0x3C, 0xF2, 0xD2, 0x52, 0xCB, 0xFC, 0x80, 0x48, 0xE3, 0x03, 0x74, 0x25, 0xC8, 0xCB, 0x9F, 0x54, 0x7A, 0x30, 0xFD, 0x98, 0x8A, 0x9F, 0xDF, 0xA6, 0x62, 0x48, 0x5E, 0xF6, 0x74, 0x39, 0x91, 0x6C, 0xAE, 0x15, 0x4A, 0xBC, 0xF7, 0x75, 0xA8, 0x0C, 0x05, 0xDD, 0xBE, 0x1E, 0xD2, 0xDB, 0xF4, 0x93, 0x65, 0x01, 0x82, 0x4B, 0x58, 0xAA, 0xE5, 0x6A, 0xE6, 0x09, 0x3C, 0xC2, 0x78, 0x2D, 0x5D, 0x08, 0xB2, 0x05, 0xF3, 0x4B, 0xA2, 0x73, 0x2D, 0x54, 0x05, 0xF9, 0x53, 0xB2, 0xD2, 0xF0, 0x7B, 0x59, 0xA0, 0x36, 0x25, 0xD1, 0x55, 0x3B, 0x51, 0xE5, 0x14, 0x5A, 0xA3, 0xEC, 0x90, 0x96, 0x6D, 0x4A, 0x96, 0xA6, 0x09, 0xFC, 0x97, 0x76, 0x08, 0xB2, 0xF0, 0x4F, 0x96, 0x73, 0x99, 0x1B, 0x70, 0x9C, 0x71, 0xC0, 0xFF, 0xB7, 0x90, 0xDC, 0x67, 0xC5, 0x8F, 0xCB, 0x97, 0xAA, 0x9E, 0xE7, 0xFD, 0x29, 0xBA, 0x83, 0xA7, 0x66, 0x4D, 0xCA, 0x65, 0x12, 0xA6, 0xA4, 0x6B, 0x32, 0x27, 0x84, 0x06, 0x29, 0x03, 0xD5, 0x6E, 0xBE, 0x8E, 0xD2, 0xE9, 0x92, 0xE5, 0x4B, 0x7F, 0x09, 0x22, 0x49, 0x9D, 0xA5, 0x27, 0x73, 0x1E, 0x7E, 0x68, 0x8C, 0xD1, 0x4D, 0x60, 0x52, 0x8E, 0x5F, 0xC9, 0xEC, 0xBA, 0xCF, 0x2A, 0xAF, 0x3C, 0x41, 0xD5, 0x35, 0xA2, 0x2A, 0x33, 0xAB, 0xA4, 0x3B, 0x61, 0x46, 0xBA, 0x6B, 0xEE, 0xEF, 0xBD, 0x2F, 0x95, 0xCE, 0xBA, 0x5C, 0x9F, 0x93, 0xD2, 0x49, 0xF2, 0x11, 0x4B, 0x2F, 0x0A, 0xC2, 0xA9, 0xBB, 0x96, 0x62, 0x66, 0x00, 0x09, 0x30, 0x7E, 0x4F, 0xD7, 0x82, 0xC2, 0x9C, 0xC2, 0xE2, 0xEC, 0xB6, 0xEB, 0x8A, 0x92, 0xBC, 0xB5, 0x8D, 0xB7, 0x70, 0xAB, 0xCC, 0xFA, 0xAA, 0x8A, 0x04, 0xC3, 0xF4, 0xB1, 0x45, 0x6F, 0xF7, 0x2E, 0x53, 0x8E, 0xCB, 0xF6, 0xDD, 0x68, 0x25, 0x79, 0xA9, 0x34, 0x58, 0x2A, 0x10, 0x84, 0xD2, 0x17, 0x2C, 0xEF, 0x33, 0x27, 0x91, 0x56, 0x13, 0x1E, 0x5D, 0x05, 0x36, 0x69, 0xCD, 0x9A, 0x97, 0x71, 0xB6, 0x08, 0x33, 0x6A, 0x57, 0x71, 0x16, 0x03, 0x76, 0x65, 0x46, 0x9C, 0x1B, 0x31, 0xD2, 0xFC, 0xE7, 0x9C, 0x73, 0x41, 0xC3, 0xB3, 0xDE, 0x70, 0xC5, 0x6B, 0xE7, 0x6A, 0xD2, 0x78, 0xFB, 0x16, 0x0F, 0x97, 0x3C, 0xE7, 0x95, 0x59, 0x8E, 0x13, 0xAC, 0xE7, 0x9D, 0x36, 0xD9, 0xCA, 0xDF, 0xC4, 0xBB, 0xAD, 0x69, 0x6E, 0x6A, 0x85, 0x4F, 0x09, 0x87, 0xD6, 0x1C, 0x80, 0xEE, 0x02, 0x8A, 0xD2, 0x08, 0xC8, 0x2B, 0xA6, 0x23, 0xDF, 0x14, 0xBC, 0x1E, 0xB4, 0x38, 0x6B, 0x11, 0x98, 0xBF, 0x6E, 0x50, 0x33, 0x16, 0x4C, 0x5A, 0x0C, 0x48, 0x38, 0xC0, 0x7D, 0x8B, 0xED, 0xEC, 0x7B, 0x20, 0xDE, 0xD8, 0x91, 0x3F, 0x14, 0xF0, 0x50, 0xDF, 0x6B, 0x6C, 0xA3, 0xC7, 0xB2, 0xF7, 0xAA, 0xC7, 0x90, 0x0B, 0x79, 0x61, 0x25, 0x5B, 0xF0, 0x75, 0x31, 0xFC, 0xBC, 0x44, 0xCC, 0x2F, 0xD0, 0x38, 0xB3, 0x0D, 0x8D, 0x5C, 0x77, 0x4C, 0xCD, 0x47, 0x0C, 0x16, 0x67, 0x49, 0xC6, 0x40, 0x5E, 0xE6, 0x6D, 0x6C, 0x26, 0x38, 0xD7, 0xC8, 0x83, 0x69, 0x07, 0x74, 0xAA, 0x77, 0x8D, 0xE3, 0xC5, 0xE6, 0x8C, 0x57, 0x95, 0x5A, 0xF0, 0x9C, 0x73, 0xB9, 0x38, 0x8F, 0x1F, 0x16, 0x33, 0x2B, 0xF7, 0x3E, 0x1D, 0xB1, 0xBB, 0x3D, 0xD3, 0x8A, 0x8C, 0x5A, 0x97, 0xA8, 0x1E, 0x81, 0xFD, 0x5B, 0x3C, 0x5F, 0x5C, 0x04, 0xB7, 0x99, 0x7B, 0xB2, 0xBB, 0xC1, 0x6A, 0xC3, 0x3E, 0x86, 0x0F, 0x9C, 0x56, 0xFC, 0x6B, 0x38, 0xAC, 0x12, 0xD1, 0x03, 0x95, 0x6F, 0xE4, 0x9A, 0xB4, 0x8B, 0xC5, 0x5B, 0x24, 0xA2, 0xA8, 0xB9, 0xB9, 0x72, 0xE1, 0xC9, 0xDD, 0x43, 0x32, 0x44, 0xFC, 0x84, 0xB5, 0xD7, 0x55, 0x28, 0x79, 0x65, 0x91, 0x40, 0xBC, 0x03, 0x35, 0x34, 0x1F, 0xCA, 0x3A, 0x40, 0xE6, 0x86, 0x65, 0x4C, 0x0C, 0x70, 0x4B, 0x79, 0xB5, 0x3E, 0x20, 0x6B, 0x3C, 0xB3, 0xAC, 0xD2, 0x5D, 0xFB, 0x22, 0x6D, 0x6A, 0x51, 0xAF, 0x7A, 0x7A, 0xC4, 0x40, 0xEE, 0x50, 0xB9, 0xF5, 0xAE, 0x55, 0x19, 0xF3, 0x45, 0xAD, 0x6B, 0xD7, 0xAB, 0x0C, 0x99, 0x9B, 0x8B, 0xFC, 0xC4, 0x73, 0x31, 0xAE, 0xF9, 0x04, 0x76, 0x1A, 0x44, 0x1B, 0x5E, 0x62, 0xF6, 0x02, 0x97, 0x15, 0xAE, 0xF5, 0x96, 0x85, 0x97, 0xE8, 0x43, 0x15, 0xD7, 0xF2, 0xE8, 0x54, 0xF7, 0xA2, 0x85, 0x59, 0x29, 0x07, 0x39, 0x7A, 0x61, 0x7A, 0xE4, 0xCE, 0x3A, 0x5D, 0xAF, 0xBC, 0x67, 0x6D, 0x83, 0xF2, 0xBA, 0x30, 0x68, 0x51, 0xB3, 0xE8, 0x1B, 0xFE, 0xCE, 0x3C, 0x91, 0x1D, 0x07, 0xBD, 0x30, 0x72, 0x67, 0xF6, 0x01, 0xC7, 0x65, 0x09, 0xF5, 0x16, 0x95, 0xED, 0x54, 0x7D, 0xC5, 0x91, 0xD2, 0xE3, 0xA9, 0x5E, 0x85, 0x48, 0xC1, 0xF4, 0x83, 0xBB, 0x72, 0x7E, 0x64, 0x5D, 0xDF, 0xD1, 0xA4, 0x63, 0xD5, 0xDF, 0xD7, 0x7C, 0x53, 0x76, 0x48, 0xC6, 0x2F, 0xBA, 0x2D, 0x1E, 0x46, 0xCE, 0x33, 0xFF, 0xCD, 0x2E, 0x80, 0x37, 0x1A, 0xBD, 0x65, 0x52, 0x80, 0x8B, 0x32, 0x41, 0xDD, 0xEB, 0xC6, 0x03, 0xC4, 0xCB, 0x8A, 0x4F, 0x35, 0xF6, 0x29, 0x49, 0x85, 0x95, 0xA5, 0xC4, 0xC1, 0x15, 0x39, 0xC7, 0xF3, 0x12, 0xB6, 0x8B, 0x75, 0x98, 0xEE, 0xA0, 0xF7, 0x12, 0x65, 0x81, 0xF4, 0xF1, 0xA2, 0x2A, 0xB1, 0x25, 0xF9, 0xDB, 0x82, 0x62, 0x3D, 0xE0, 0x7C, 0xE3, 0x56, 0x46, 0x0E, 0xBC, 0x62, 0xBE, 0xF6, 0xEC, 0xE6, 0x34, 0x02, 0x67, 0xDB, 0x6F, 0x72, 0xDA, 0x0F, 0xBF, 0x6A, 0x30, 0xE2, 0x08, 0x42, 0xBB, 0x2A, 0xBA, 0xD2, 0x9E, 0xF8, 0x67, 0x15, 0xF6, 0x70, 0x36, 0x7B, 0x3E, 0xCC, 0x92, 0x73, 0xAD, 0x1C, 0x02, 0x15, 0x43, 0xB9, 0xBD, 0x66, 0x23, 0x85, 0x4F, 0x78, 0x33, 0x0D, 0x2B, 0x58, 0x5F, 0xDE, 0x0A, 0xFE, 0xB8, 0xA3, 0x32, 0xD8, 0x0B, 0xB4, 0x6F, 0x0F, 0x80, 0x16, 0x1E, 0x7E, 0x5C, 0x1F, 0x09, 0xFC, 0x0B, 0x05, 0xCA, 0x3F, 0x02, 0x9B, 0xFD, 0xAF, 0x16, 0x54, 0x01, 0x93, 0xBC, 0x82, 0x33, 0x9B, 0x80, 0xE9, 0x0E, 0xF3, 0xE5, 0x3A, 0xDE, 0x0D, 0xD3, 0x15, 0xC2, 0x02, 0x5E, 0xA6, 0x41, 0x2E, 0x3B, 0x87, 0x87, 0xD0, 0xBD, 0xDD, 0xE7, 0xC9, 0x01, 0x60, 0x63, 0x5B, 0x24, 0x7E, 0xF5, 0x10, 0x5B, 0x77, 0x08, 0xBD, 0x19, 0x82, 0x95, 0x9B, 0x23, 0x65, 0x7E, 0xD7, 0x0B, 0x86, 0xC3, 0x95, 0x9E, 0xB7, 0x33, 0x47, 0x43, 0x3A, 0xFB, 0x1A, 0xB9, 0x21, 0x38, 0xCF, 0x04, 0x10, 0x6E, 0x07, 0xAC, 0x17, 0xB4, 0xF0, 0xEF, 0xF3, 0xBA, 0xA9, 0x57, 0x47, 0x4E, 0x0B, 0x19, 0xDE, 0x9E, 0x56, 0x5F, 0xFE, 0xBB, 0x98, 0xB7, 0xB5, 0x42, 0x3A, 0x62, 0x6F, 0x55, 0x19, 0x8F, 0x04, 0xB7, 0xFC, 0xCB, 0x0F, 0xC6, 0x31, 0xCF, 0xE5, 0x19, 0x61, 0xE8, 0x2A, 0x7B, 0x2F, 0x59, 0x15, 0x14, 0x6E, 0x32, 0x4E, 0x38, 0x16, 0x28, 0x5A, 0xB0, 0x8A, 0x5F, 0xC4, 0x7B, 0x42, 0x66, 0x1C, 0xC9, 0x55, 0xD8, 0x71, 0xAF, 0xB7, 0x54, 0x4B, 0x8D, 0x63, 0xBE, 0xD5, 0xFC, 0x14, 0x0D, 0xDF, 0x3B, 0xBB, 0x6C, 0x38, 0xEB, 0xBF, 0xA5, 0x25, 0xAF, 0x88, 0xB6, 0xF7, 0xB8, 0xAA, 0x1B, 0xC0, 0xFB, 0xEC, 0x27, 0xCA, 0x7C, 0x60, 0x8D, 0xC9, 0x10, 0xC1, 0x49, 0x70, 0xF4, 0x82, 0x0D, 0xFC, 0x78, 0xDE, 0x1B, 0xF2, 0x6E, 0x57, 0xA7, 0x6E, 0x0A, 0xB7, 0xBB, 0x25, 0x42, 0x9D, 0x10, 0xA3, 0xA9, 0xB9, 0x26, 0x4F, 0x09, 0xD6, 0x97, 0xA6, 0x49, 0x46, 0x6D, 0x49, 0xCC, 0x33, 0x66, 0xBF, 0x78, 0x68, 0x74, 0xE1, 0xD4, 0x01, 0xFB, 0x85, 0xD2, 0x6F, 0xC8, 0x31, 0x93, 0x40, 0x81, 0x1C, 0x0C, 0xF9, 0xFF, 0xC3, 0xF5, 0xBC, 0x17, 0xE4, 0xA5, 0x2E, 0xEB, 0xBC, 0xE9, 0x5C, 0xA7, 0xE6, 0xBC, 0xAC, 0x9F, 0xD1, 0x9C, 0xEA, 0xBF, 0xE9, 0xBF, 0xF6, 0x18, 0x96, 0xCE, 0x53, 0xA2, 0x5B, 0x9C, 0x72, 0x3B, 0x25, 0x7B, 0x3D, 0xCD, 0x74, 0x43, 0xF9, 0x90, 0xFD, 0x59, 0x69, 0x2F, 0x36, 0xC3, 0x74, 0xBE, 0x80, 0x0B, 0x76, 0x1B, 0xC8, 0xF8, 0xEE, 0xBC, 0x67, 0x64, 0x40, 0x67, 0x43, 0xA9, 0x84, 0x73, 0xBC, 0x79, 0x4E, 0xC1, 0xBD, 0xA8, 0x6B, 0xD5, 0x29, 0xD9, 0x9F, 0x82, 0x6E, 0x94, 0xD4, 0x69, 0xD7, 0x6D, 0xAE, 0xCA, 0x4D, 0x53, 0x18, 0x7B, 0x7C, 0xD1, 0x9E, 0x17, 0x7C, 0x73, 0xF0, 0x93, 0x5E, 0xC4, 0x97, 0x98, 0x4D, 0x13, 0x68, 0x21, 0x73, 0xC3, 0x36, 0x7E, 0x28, 0x30, 0x84, 0x38, 0xD7, 0x79, 0xBF, 0x66, 0x2D, 0xE7, 0x7D, 0xD3, 0xE7, 0xF2, 0x49, 0x51, 0x6C, 0x75, 0x60, 0xC1, 0xA6, 0x3D, 0x63, 0x4B, 0x0E, 0x64, 0x65, 0xFB, 0x9E, 0xCF, 0x8D, 0x51, 0x6F, 0x70, 0x3F, 0xA6, 0xED, 0x15, 0xF5, 0x3A, 0x88, 0x64, 0xB3, 0x88, 0x39, 0xE6, 0x13, 0x04, 0xD7, 0x21, 0x91, 0xD1, 0x2F, 0xBE, 0x06, 0x70, 0x84, 0xEE, 0x0C, 0x5C, 0xE6, 0x5A, 0x24, 0xFF, 0xE9, 0x43, 0xD2, 0xD2, 0xC2, 0x6F, 0x77, 0x6C, 0x4A, 0x9B, 0xBD, 0x4B, 0xD9, 0x70, 0x20, 0xB5, 0x71, 0xE3, 0xDB, 0xF2, 0xF6, 0xB4, 0x59, 0x2E, 0x8F, 0x72, 0x9F, 0xA5, 0xDD, 0xB1, 0x9D, 0xA6, 0xD2, 0x70, 0x2E, 0x19, 0xAF, 0x17, 0x87, 0x70, 0x77, 0x2C, 0x98, 0x26, 0xD8, 0xC9, 0x65, 0xC0, 0x63, 0x03, 0x23, 0xA1, 0x81, 0xC4, 0xA5, 0xBD, 0x39, 0x60, 0x72, 0x38, 0xB7, 0x9D, 0x0F, 0x98, 0xEC, 0xFC, 0x50, 0x0F, 0xF2, 0xE6, 0x6E, 0xDC, 0x55, 0x3E, 0x92, 0xDB, 0xE5, 0x12, 0x94, 0xAB, 0xE6, 0x9E, 0xB6, 0x7E, 0xAB, 0x4A, 0xE5, 0x9E, 0x33, 0x1A, 0x23, 0xDE, 0xC8, 0x3D, 0x32, 0xEF, 0x86, 0xC0, 0x9D, 0xDB, 0x04, 0xCC, 0x3A, 0xC1, 0x23, 0xE2, 0xE3, 0x95, 0x3D, 0x53, 0xB1, 0xD3, 0xE1, 0x53, 0xDA, 0x6C, 0x51, 0x93, 0x9D, 0x59, 0x75, 0x87, 0xE1, 0x65, 0x1B, 0xF4, 0x65, 0xCE, 0xD0, 0xF8, 0x95, 0xE2, 0xDC, 0x11, 0xE0, 0x12, 0xEB, 0xA1, 0xAA, 0x45, 0xBC, 0x1F, 0x86, 0xC3, 0xC4, 0x46, 0xBC, 0x45, 0x73, 0x07, 0x04, 0x73, 0xB9, 0xB7, 0xC1, 0x57, 0xC7, 0x3F, 0xB0, 0x39, 0xF1, 0x57, 0x8F, 0x4E, 0x66, 0x0E, 0xEC, 0x1F, 0x6C, 0xB5, 0x24, 0xEF, 0xEF, 0x34, 0xAC, 0x3D, 0x84, 0xA7, 0xAE, 0x7F, 0x55, 0x1A, 0x8E, 0x6A, 0x57, 0x8E, 0xD5, 0x7B, 0xC1, 0x4D, 0x56, 0x8D, 0xCA, 0xB3, 0xA0, 0xB5, 0x41, 0x9E, 0xE8, 0x2E, 0x4F, 0x3B, 0x77, 0x17, 0xFB, 0x88, 0xFB, 0x0A, 0xEC, 0x39, 0x7E, 0x59, 0xDA, 0x1D, 0xF7, 0xA8, 0xBB, 0x50, 0xBC, 0x68, 0xFF, 0xD4, 0x16, 0x40, 0x60, 0xBD, 0x43, 0x5A, 0x73, 0x91, 0x99, 0xB2, 0xFE, 0x74, 0xC9, 0x0D, 0xD2, 0x66, 0xE5, 0xA2, 0x1C, 0x01, 0x36, 0xD2, 0xEA, 0xAB, 0x32, 0x00, 0x5A, 0x61, 0x70, 0x4F, 0x44, 0xF2, 0x9E, 0xCF, 0x95, 0xB1, 0x3A, 0xEE, 0x0B, 0x5E, 0xF9, 0xB1, 0xD7, 0x9A, 0xBC, 0x38, 0x61, 0xF7, 0x42, 0xE5, 0xEA, 0xB0, 0x84, 0x96, 0x09, 0x52, 0x76, 0x47, 0x52, 0x4D, 0x9A, 0x68, 0xFA, 0x86, 0xE1, 0x25, 0xA9, 0xFC, 0xF1, 0x2B, 0x7D, 0x72, 0x0C, 0x09, 0xDC, 0x1A, 0x56, 0x74, 0xC1, 0xAE, 0x86, 0x1A, 0x91, 0x11, 0xE0, 0x30, 0x2F, 0x90, 0xF5, 0xE7, 0x3E, 0xE2, 0xBD, 0xEC, 0x5F, 0x92, 0xFD, 0x27, 0xEE, 0x6C, 0xD7, 0x95, 0x8C, 0xE1, 0x61, 0xE7, 0x9B, 0x5D, 0xD5, 0x2E, 0x3B, 0x9A, 0xAA, 0x9F, 0xCA, 0x5E, 0x6C, 0x58, 0x53, 0x7C, 0x53, 0xF8, 0x62, 0x25, 0x99, 0x5D, 0x4C, 0x3B, 0xDA, 0x2C, 0x52, 0x04, 0x22, 0xFB, 0x8C, 0xBA, 0x85, 0xCF, 0x01, 0xF1, 0xFC, 0x76, 0xD6, 0x91, 0xFB, 0x8E, 0xFB, 0xA3, 0x7F, 0x57, 0xE1, 0x9B, 0x38, 0xAF, 0xAE, 0xAB, 0xB9, 0x01, 0x61, 0x4C, 0xF3, 0xD4, 0x0C, 0xE1, 0x0E, 0xC7, 0x6A, 0x5C, 0xF5, 0x64, 0xC3, 0xDA, 0xE2, 0x00, 0xC9, 0x1B, 0x97, 0x61, 0xD9, 0x6B, 0xF8, 0x1B, 0x6C, 0xFE, 0x29, 0xB6, 0xA1, 0x87, 0x4D, 0xAC, 0x44, 0xC3, 0xC0, 0xB1, 0x06, 0xF1, 0xEC, 0x76, 0xDE, 0x62, 0x8E, 0xCF, 0xB1, 0xCC, 0x8A, 0xC3, 0xB1, 0x0F, 0x8F, 0x38, 0x17, 0x6F, 0x0F, 0x9B, 0xD6, 0xD4, 0xA3, 0xBF, 0xB8, 0xBD, 0xA4, 0xDA, 0x4D, 0x7B, 0x65, 0x83, 0x4F, 0xD1, 0x0B, 0x79, 0x97, 0xCB, 0xEA, 0xAC, 0xF3, 0xEC, 0x17, 0xDB, 0x1B, 0x8A, 0x58, 0x2C, 0xC0, 0xB4, 0x5A, 0xB4, 0x16, 0xD4, 0x18, 0xAD, 0x62, 0xF3, 0x79, 0x9A, 0xFB, 0xB2, 0xD4, 0xE3, 0x71, 0x83, 0xA7, 0x58, 0xAE, 0x65, 0xD2, 0xAF, 0xC6, 0x6A, 0xDE, 0xE3, 0xD4, 0x80, 0x2C, 0x37, 0x70, 0x16, 0xE7, 0x0B, 0x39, 0x06, 0xC2, 0x78, 0xF7, 0x0F, 0x1E, 0x81, 0x9F, 0x83, 0x3E, 0xAB, 0xBC, 0xD1, 0xDB, 0x60, 0xA3, 0xFD, 0x67, 0x7C, 0x26, 0x98, 0x6B, 0x1E, 0x89, 0x67, 0x83, 0x8A, 0xDB, 0xBB, 0x92, 0x57, 0xC2, 0x3E, 0x27, 0xE3, 0x53, 0x8F, 0x22, 0xA3, 0x1A, 0x82, 0xB9, 0x8B, 0xE0, 0xDF, 0x59, 0xC1, 0xBC, 0xC7, 0xC8, 0x41, 0x7C, 0x1F, 0x98, 0x8F, 0xB0, 0xE1, 0x6E, 0x70, 0x04, 0xB2, 0xDA, 0x6B, 0x1E, 0x9A, 0x02, 0x6F, 0xB7, 0x17, 0x60, 0x1D, 0x50, 0xBE, 0xB9, 0x1F, 0xBE, 0x01, 0x0A, 0xB8, 0x11, 0x93, 0x38, 0x5F, 0x24, 0x38, 0xF6, 0x3A, 0xB9, 0x53, 0x30, 0xBE, 0x6E, 0x72, 0x5A, 0x1C, 0xDF, 0x2A, 0xA3, 0x94, 0xAB, 0xA7, 0xDF, 0xA2, 0x86, 0x40, 0x2F, 0xE5, 0xB8, 0x6F, 0x33, 0x74, 0x89, 0x98, 0xE8, 0x69, 0x8D, 0xFC, 0x45, 0x03, 0xED, 0x83, 0xB0, 0xDD, 0xF0, 0x80, 0xF9, 0x1E, 0xEC, 0x2D, 0x6C, 0x70, 0xED, 0x75, 0xBC, 0x40, 0xF7, 0xF8, 0x98, 0x2E, 0x29, 0x42, 0x3D, 0xB2, 0x26, 0x24, 0x35, 0x51, 0xBE, 0x4E, 0x37, 0x9E, 0x73, 0x47, 0x62, 0x00, 0xCB, 0x78, 0x9F, 0x04, 0x3F, 0x43, 0xBD, 0xA0, 0x49, 0x4C, 0x90, 0xE7, 0x29, 0x84, 0x8F, 0xB7, 0xD8, 0x9F, 0xC4, 0x46, 0x22, 0x1F, 0xCD, 0x65, 0x58, 0x05, 0x7C, 0xFC, 0x7A, 0x5C, 0x9C, 0x7B, 0xE1, 0xBD, 0x7E, 0xD7, 0xC4, 0x83, 0xFA, 0xA8, 0xEA, 0xB7, 0x29, 0x5B, 0x33, 0x5C, 0xD2, 0xC7, 0xA4, 0xFD, 0x55, 0x8F, 0x04, 0x0B, 0x78, 0xCE, 0xB2, 0xCE, 0x7D, 0x47, 0xC0, 0x7D, 0xC2, 0xD3, 0xAB, 0xB3, 0x11, 0x53, 0x6A, 0xA1, 0x83, 0x16, 0xBD, 0x80, 0xFE, 0x36, 0xEF, 0xC0, 0x68, 0xC4, 0xF9, 0x6A, 0x79, 0x6C, 0x5C, 0x4D, 0x5E, 0xAF, 0x20, 0xE1, 0x7C, 0xD9, 0xFD, 0xAA, 0xD0, 0xE4, 0x93, 0xF9, 0x2F, 0x35, 0x01, 0x69, 0xAE, 0x59, 0x47, 0xA0, 0x11, 0xDC, 0xC3, 0xE9, 0x63, 0xF7, 0xCD, 0x02, 0xDE, 0xC8, 0xAC, 0x57, 0x4D, 0x82, 0x5F, 0x32, 0x2B, 0x1D, 0x70, 0xB4, 0x15, 0xBB, 0x62, 0x31, 0x15, 0x83, 0x11, 0xFA, 0xA2, 0x6D, 0xEC, 0xC4, 0x0E, 0xB0, 0x67, 0x53, 0x82, 0x5B, 0xE3, 0xBF, 0x2A, 0x6D, 0xD2, 0xD1, 0xAA, 0x3D, 0xEA, 0x67, 0xA9, 0xD2, 0xA2, 0x7F, 0x10, 0x97, 0x53, 0x99, 0x73, 0x20, 0x74, 0x24, 0x80, 0xA9, 0x17, 0x7B, 0xE6, 0xC1, 0x7D, 0x2C, 0xE5, 0xB0, 0x04, 0xED, 0xC2, 0x2B, 0x2D, 0xFC, 0x30, 0x2D, 0xD2, 0x77, 0xA1, 0x39, 0xD6, 0xE3, 0xB8, 0xE5, 0xD1, 0xD2, 0x84, 0xD1, 0x47, 0xDE, 0x54, 0xF4, 0x25, 0x15, 0x35, 0x3D, 0x53, 0xE5, 0xA7, 0x0E, 0xA9, 0xF2, 0x01, 0x58, 0x4E, 0x70, 0xE1, 0xF2, 0x10, 0x10, 0x98, 0xA3, 0x8B, 0xF5, 0xE8, 0x84, 0xCB, 0x85, 0xB9, 0x0E, 0xE3, 0xD1, 0x7B, 0x04, 0x6A, 0x91, 0x8E, 0x5D, 0x42, 0xC7, 0x5E, 0xF0, 0x8D, 0x9D, 0x7C, 0x5E, 0xDC, 0x3D, 0x3B, 0x61, 0xEC, 0x89, 0x83, 0x65, 0x27, 0x93, 0x24, 0x5D, 0xEE, 0x0A, 0xFF, 0x14, 0x59, 0xC3, 0x68, 0xEE, 0x1D, 0x8E, 0x73, 0xD9, 0xA2, 0xE0, 0x1E, 0xDE, 0x9B, 0x2C, 0x9E, 0xFB, 0x27, 0xB8, 0x50, 0x1C, 0xE2, 0x30, 0x1F, 0x9B, 0x46, 0x06, 0x58, 0x8E, 0xC0, 0xE7, 0xA0, 0xFB, 0xCF, 0x7F, 0x43, 0x67, 0x27, 0xAC, 0x3B, 0xBA, 0x19, 0x35, 0x49, 0x76, 0xAC, 0x9C, 0x83, 0x46, 0xA7, 0x3E, 0x54, 0x5B, 0xA2, 0x03, 0x9C, 0x13, 0x30, 0x1F, 0xBD, 0xC5, 0x8B, 0x0B, 0xED, 0xC3, 0x96, 0x82, 0x8B, 0x3C, 0x5A, 0x71, 0x4F, 0x50, 0x62, 0x3F, 0x9D, 0x98, 0x00, 0x6E, 0x35, 0x5F, 0x4C, 0x44, 0x82, 0x8B, 0x4E, 0xBB, 0x42, 0x1F, 0xA0, 0xCD, 0xDD, 0x6A, 0x78, 0x1E, 0x64, 0x5B, 0x91, 0x0A, 0xB7, 0xC0, 0x1B, 0xD5, 0x5E, 0xC8, 0x6A, 0xB8, 0x0B, 0x0A, 0x47, 0x1E, 0xC2, 0xCF, 0x42, 0x1F, 0xA3, 0x2D, 0xF0, 0x33, 0x8F, 0xFD, 0xD8, 0x0B, 0x78, 0x8E, 0xDD, 0x11, 0xBC, 0x11, 0xDA, 0x69, 0xF6, 0xEC, 0xFF, 0xD9, 0x3F, 0xA7, 0x93, 0x81, 0x3F, 0x2C, 0xD5, 0x35, 0x1D, 0xCC, 0x64, 0xDE, 0x94, 0x6D, 0x85, 0xF6, 0xD1, 0x2F, 0x95, 0x79, 0xF0, 0x0C, 0xEA, 0x15, 0xB0, 0x0C, 0x99, 0x42, 0x12, 0x21, 0x61, 0xA8, 0x2D, 0x2E, 0x77, 0x3F, 0x8F, 0x51, 0xE8, 0x48, 0x3B, 0x1C, 0x0F, 0x84, 0x13, 0xCC, 0x4E, 0xE2, 0x2D, 0x50, 0xEF, 0xE9, 0xCF, 0x3C, 0x37, 0xF5, 0xEC, 0xCE, 0x24, 0x60, 0x98, 0x22, 0xB0, 0x34, 0x1C, 0xB4, 0x91, 0xAE, 0x50, 0x4C, 0x81, 0xFC, 0x44, 0xAD, 0xDC, 0x4F, 0x70, 0x8C, 0x60, 0xE4, 0xDE, 0x6D, 0x88, 0x82, 0x2E, 0x77, 0x2F, 0xC7, 0x0C, 0x71, 0x2B, 0x3B, 0x19, 0x3E, 0x03, 0x49, 0x33, 0x7B, 0x80, 0x23, 0xB0, 0xDF, 0xA9, 0xDD, 0xDC, 0x29, 0xB9, 0xF3, 0xDB, 0xCF, 0xF0, 0xC6, 0x64, 0x76, 0x95, 0x04, 0x02, 0x96, 0xE9, 0x73, 0x65, 0xEB, 0x40, 0x91, 0x32, 0x86, 0x93, 0x01, 0x55, 0x49, 0xE1, 0xBD, 0xB3, 0xE1, 0x3F, 0x82, 0x2E, 0x8F, 0x11, 0xE8, 0x59, 0xD2, 0xD3, 0xEE, 0x24, 0xF6, 0x02, 0xDD, 0x61, 0x3E, 0x12, 0x3F, 0x00, 0x97, 0x9F, 0x78, 0xCC, 0xC1, 0x2B, 0x26, 0xB7, 0xFE, 0xE1, 0x46, 0x15, 0xFD, 0x2B, 0x82, 0x79, 0x48, 0xEE, 0x58, 0xE9, 0x2B, 0xA0, 0x3D, 0xE3, 0x45, 0xDA, 0x09, 0xF0, 0x87, 0xFA, 0x40, 0xF0, 0x01, 0x98, 0x94, 0xBC, 0x75, 0x2F, 0x46, 0xD5, 0xF4, 0x7A, 0xBB, 0xF3, 0xD8, 0x35, 0x6C, 0x9E, 0xB9, 0x13, 0x1E, 0x02, 0x3F, 0x3D, 0x9E, 0x9C, 0xF6, 0xAD, 0x65, 0x76, 0x4B, 0x3C, 0xE7, 0x75, 0xDD, 0xD4, 0x02, 0x77, 0xEE, 0xEF, 0xB2, 0x46, 0xE9, 0x28, 0xC0, 0xA8, 0x60, 0x6B, 0x2A, 0x0D, 0xC6, 0x66, 0x2D, 0xD9, 0x33, 0x05, 0x9E, 0xA5, 0xEC, 0x70, 0xFB, 0x8B, 0x1E, 0xE4, 0x53, 0x76, 0x1D, 0xD8, 0x45, 0x6C, 0xD0, 0xFC, 0x20, 0x7E, 0x08, 0x99, 0x7B, 0x7C, 0x42, 0x5A, 0x4B, 0xCF, 0x94, 0xE6, 0x5A, 0x0E, 0xBF, 0xDD, 0x23, 0xFF, 0x1E, 0x37, 0xA7, 0x7E, 0xB9, 0x18, 0xE1, 0xF5, 0x95, 0x0B, 0x52, 0xFC, 0xC0, 0x49, 0xF9, 0x93, 0x82, 0x1C, 0xA0, 0x9E, 0xF4, 0x41, 0x37, 0x10, 0xF5, 0x16, 0x64, 0xD9, 0xD5, 0x63, 0x37, 0xF0, 0x26, 0x73, 0x1D, 0xCE, 0x20, 0x3B, 0xFA, 0x17, 0xA7, 0x3D, 0x1B, 0x88, 0x68, 0x3A, 0xCA, 0x61, 0x7A, 0xB7, 0xE6, 0xE7, 0x73, 0x77, 0xB5, 0x0D, 0x8A, 0x7E, 0xF0, 0x0E, 0xD4, 0xD9, 0x25, 0x9F, 0x02, 0x4E, 0x96, 0x38, 0x06, 0x16, 0x40, 0x54, 0x66, 0xBC, 0x9B, 0x39, 0x6A, 0x27, 0x02, 0xED, 0xBA, 0xB1, 0x67, 0x04, 0xC7, 0xFC, 0x3A, 0x5E, 0x82, 0x64, 0xF4, 0x6C, 0x64, 0xBF, 0x24, 0xFC, 0x6B, 0xF0, 0xE1, 0xEF, 0x4A, 0x6E, 0xCE, 0xFB, 0x4A, 0x37, 0xA4, 0x6E, 0x16, 0x4B, 0xA9, 0x2E, 0xCE, 0x82, 0x54, 0x39, 0x39, 0xC8, 0x9B, 0x1E, 0x18, 0x49, 0x9A, 0x01, 0x7F, 0x5D, 0x8F, 0x12, 0x7F, 0xC1, 0x8D, 0xB6, 0x5F, 0x48, 0x47, 0xE0, 0xBB, 0xD9, 0x65, 0x72, 0x03, 0x70, 0xA1, 0xBB, 0x9B, 0x79, 0xCA, 0x7B, 0xD2, 0x30, 0x91, 0xBE, 0x06, 0x16, 0xE7, 0x36, 0x51, 0xAE, 0x50, 0x97, 0x68, 0x3D, 0xB9, 0x07, 0x3A, 0x96, 0xBA, 0x91, 0x18, 0x84, 0x2D, 0xF6, 0x98, 0x11, 0x65, 0xF0, 0x21, 0xB7, 0x85, 0x44, 0x1D, 0x74, 0xC4, 0xF6, 0x28, 0x71, 0x1D, 0xFC, 0x69, 0x76, 0x90, 0x78, 0x01, 0xE6, 0x76, 0x79, 0x50, 0xDF, 0xE9, 0x29, 0xF5, 0x63, 0xC8, 0x77, 0xD4, 0x37, 0x7D, 0x0E, 0x39, 0x8A, 0x6A, 0x11, 0xCE, 0x22, 0x22, 0xC9, 0xB2, 0x94, 0x19, 0x84, 0x2D, 0xB1, 0x23, 0x68, 0x11, 0x61, 0x8A, 0xDD, 0x71, 0xBD, 0x46, 0xEC, 0x42, 0xE4, 0xB6, 0x38, 0xC1, 0xC0, 0x43, 0xCD, 0x1C, 0x88, 0x2C, 0x68, 0x6B, 0xF7, 0x3C, 0xD2, 0x4C, 0x76, 0xB7, 0xF6, 0x3E, 0x11, 0x20, 0x5D, 0x9F, 0x33, 0x9A, 0x18, 0x29, 0xBA, 0x2F, 0x58, 0x80, 0xB7, 0x08, 0xAE, 0x26, 0x9D, 0xC5, 0x45, 0xFC, 0xE6, 0xDD, 0x03, 0x78, 0x36, 0x75, 0xCE, 0x75, 0x21, 0x31, 0x0A, 0xC3, 0x6C, 0x77, 0x12, 0x01, 0xF0, 0x23, 0xB3, 0x25, 0x44, 0x12, 0xD4, 0xD7, 0x79, 0x85, 0x10, 0x67, 0x9A, 0x55, 0x3B, 0xE1, 0xB7, 0xB5, 0xBA, 0xAC, 0xDB, 0xF8, 0x5C, 0x55, 0x0B, 0x23, 0xC1, 0xDE, 0xC9, 0xAD, 0x13, 0x83, 0xB1, 0xDB, 0x92, 0x91, 0xBB, 0x1D, 0x71, 0x23, 0xB6, 0xCA, 0xA5, 0x0D, 0x3F, 0x49, 0x04, 0xDA, 0x7A, 0x12, 0xCB, 0x90, 0x0C, 0xB3, 0xF5, 0x44, 0x38, 0x3C, 0xA4, 0xED, 0x10, 0xB1, 0xAA, 0x28, 0xA0, 0x2A, 0x11, 0xB7, 0xCD, 0xBB, 0x9E, 0xE9, 0x8A, 0x69, 0xB2, 0x27, 0x33, 0x33, 0xB0, 0x55, 0xDA, 0x90, 0xF8, 0x1B, 0xD8, 0x3A, 0x65, 0xEA, 0xAE, 0x25, 0x58, 0x93, 0x18, 0x75, 0x49, 0xC3, 0xD5, 0xD4, 0x0A, 0xDB, 0x15, 0x84, 0x09, 0xBA, 0xD6, 0x6C, 0x37, 0x11, 0x02, 0xDB, 0xB4, 0xAD, 0xC6, 0x2B, 0xEA, 0x94, 0x95, 0xF3, 0xB0, 0xB6, 0x4A, 0x53, 0x5D, 0x2A, 0xE6, 0x54, 0xD4, 0x41, 0xAF, 0x40, 0xAF, 0xE7, 0x2E, 0x8E, 0x5B, 0x87, 0x3E, 0xD5, 0xDD, 0xDF, 0x71, 0x0F, 0xDB, 0x25, 0xFF, 0xEE, 0x62, 0x80, 0x87, 0x31, 0xFE, 0xB6, 0x0E, 0xC4, 0x14, 0x6C, 0x98, 0x59, 0x34, 0x11, 0x0C, 0x6F, 0x6D, 0x53, 0xE2, 0x43, 0x3A, 0x0C, 0x2B, 0xE2, 0xB0, 0x35, 0x4D, 0x36, 0xBA, 0x69, 0xE8, 0x91, 0xEA, 0xC9, 0xD4, 0x4A, 0x34, 0xB2, 0xC4, 0x39, 0x56, 0x8F, 0xF2, 0xF4, 0xB1, 0x3B, 0xB6, 0x62, 0xC3, 0xD4, 0xCF, 0x57, 0xDE, 0xC6, 0x97, 0xB0, 0x5B, 0x6C, 0x2D, 0x88, 0x21, 0x58, 0xB7, 0x19, 0x40, 0x04, 0xC1, 0x64, 0x8B, 0x13, 0x1E, 0xD4, 0xDB, 0x53, 0x11, 0x89, 0x3E, 0xE8, 0x9A, 0xA4, 0xDD, 0x86, 0x4A, 0x9B, 0x3A, 0xC9, 0xB7, 0xA8, 0x6D, 0xD5, 0x97, 0x58, 0x2B, 0x74, 0x6D, 0x61, 0xF4, 0xF6, 0x57, 0x68, 0xBF, 0x2E, 0x66, 0xE5, 0x63, 0x7C, 0x82, 0xD0, 0xCB, 0xD6, 0x09, 0xFF, 0x88, 0x73, 0xCD, 0x14, 0xC4, 0x6E, 0xB8, 0xB5, 0xF1, 0x8A, 0xE2, 0x74, 0x62, 0x69, 0x19, 0x24, 0xBD, 0x98, 0x74, 0x5E, 0x7B, 0x53, 0xEC, 0x90, 0x72, 0x98, 0x5E, 0x2D, 0xF8, 0x9C, 0x96, 0x10, 0xBF, 0x87, 0x0D, 0xE4, 0x76, 0xEE, 0xD8, 0xC3, 0x70, 0x81, 0xD8, 0x95, 0x34, 0xF5, 0x15, 0x38, 0x63, 0x73, 0x8E, 0xDA, 0x0A, 0xD4, 0x99, 0x99, 0x51, 0x93, 0x81, 0xBC, 0xA6, 0xA5, 0x32, 0x80, 0x7B, 0xB9, 0x74, 0x92, 0x44, 0x0F, 0x58, 0xAB, 0x8F, 0x8A, 0x0C, 0x40, 0x1F, 0xFC, 0x1E, 0xFB, 0x1E, 0x6C, 0x8E, 0x15, 0xF2, 0x53, 0xA0, 0xFD, 0x3B, 0xCE, 0x30, 0xA3, 0xA1, 0xAE, 0x95, 0x99, 0x54, 0x35, 0xB4, 0xC4, 0x46, 0x4E, 0x0D, 0x07, 0x55, 0xA6, 0x27, 0xC9, 0x6E, 0x70, 0x63, 0xDD, 0x4B, 0xE9, 0x04, 0xE2, 0x52, 0x91, 0x46, 0xD4, 0x44, 0x2E, 0x54, 0x35, 0x09, 0x8A, 0x89, 0xBB, 0x98, 0x84, 0x9D, 0x47, 0xCC, 0x38, 0x1C, 0xC1, 0x1C, 0xC3, 0x4D, 0x76, 0x8C, 0xA7, 0x85, 0xD8, 0x90, 0x95, 0x87, 0xA8, 0x3D, 0xF0, 0x3B, 0x9B, 0x10, 0xF2, 0x08, 0x04, 0x99, 0x4A, 0x49, 0x08, 0xBC, 0x55, 0x5B, 0x26, 0x59, 0x28, 0xB1, 0x2B, 0x58, 0x27, 0x3C, 0x2F, 0xBA, 0xA5, 0x34, 0x64, 0xAB, 0x85, 0xA6, 0xD8, 0x70, 0xBE, 0x13, 0x6B, 0x7E, 0x48, 0xCA, 0xCC, 0x60, 0x56, 0x6F, 0x9F, 0x4A, 0x8F, 0x24, 0x4F, 0xAE, 0xB4, 0xA1, 0x66, 0xA2, 0x47, 0x6D, 0x36, 0x93, 0xE9, 0xB0, 0xBB, 0xA9, 0x88, 0xDC, 0x07, 0xD9, 0xD5, 0x38, 0x8A, 0x17, 0xA6, 0x67, 0xE7, 0xC7, 0x08, 0x5D, 0xD4, 0xFB, 0x14, 0x9B, 0xD9, 0x51, 0x0A, 0x17, 0xA4, 0x91, 0xC9, 0x90, 0xFA, 0xC6, 0x78, 0xD3, 0x07, 0x44, 0xA9, 0xDB, 0x46, 0x53, 0x4A, 0x7E, 0xC2, 0x0A, 0x15, 0xF9, 0x0A, 0x3F, 0x64, 0xB3, 0x92, 0x14, 0xC0, 0x57, 0x4D, 0xF3, 0xC9, 0x20, 0xC8, 0xBF, 0xCA, 0x47, 0x24, 0xCE, 0x4D, 0xCC, 0xCB, 0x17, 0x80, 0xD9, 0x35, 0xB2, 0x7A, 0x3E, 0x95, 0x31, 0x14, 0xB6, 0x64, 0x2C, 0xD4, 0x77, 0xA3, 0x70, 0x7A, 0x9C, 0x1C, 0x0F, 0xB8, 0x4A, 0xAD, 0x17, 0x0D, 0x5D, 0xFE, 0x85, 0xEC, 0x26, 0x0D, 0x6C, 0x86, 0x90, 0xA9, 0x48, 0xA4, 0xA9, 0x96, 0xDC, 0x06, 0x45, 0x55, 0xFC, 0x11, 0xED, 0xAA, 0xF0, 0xCD, 0x0D, 0x14, 0xCC, 0x28, 0xD9, 0x26, 0x1B, 0xC1, 0xBC, 0xCB, 0x0F, 0x81, 0x2E, 0xD1, 0x92, 0xEC, 0x25, 0x91, 0xBE, 0x54, 0x49, 0xBA, 0xAF, 0xFF, 0x5B, 0xF2, 0x9B, 0xF4, 0xDB, 0xF2, 0x14, 0x92, 0xA4, 0x87, 0x5B, 0xB7, 0x90, 0xDB, 0xD1, 0xC9, 0xA6, 0xF1, 0xA4, 0x17, 0x44, 0x57, 0x4E, 0x14, 0x3E, 0x6D, 0xFC, 0xAA, 0x7F, 0xC9, 0xDE, 0xA9, 0xF5, 0x96, 0xC6, 0x31, 0xD9, 0xE5, 0x13, 0xA1, 0x00, 0x7A, 0x58, 0xC1, 0xC9, 0x88, 0x7F, 0x94, 0x63, 0x56, 0x96, 0xBF, 0x8C, 0xD4, 0x2B, 0xB3, 0x96, 0x5B, 0x90, 0x5B, 0x98, 0x3E, 0x6B, 0x31, 0xE9, 0x8C, 0xD6, 0x98, 0x06, 0x92, 0x8E, 0x50, 0x59, 0xC5, 0x4A, 0xE1, 0xE1, 0xAE, 0x75, 0xFA, 0xD3, 0x6C, 0x5C, 0xCB, 0x7D, 0xB1, 0x90, 0xC9, 0xAF, 0x1B, 0x0B, 0xE4, 0xD3, 0xA3, 0xCA, 0xEA, 0x0F, 0xDE, 0xA3, 0xC6, 0xE5, 0xF6, 0xF9, 0xDD, 0x23, 0x43, 0x34, 0xCA, 0xE5, 0x93, 0x49, 0x53, 0x76, 0xB7, 0x35, 0x4B, 0x2E, 0xC0, 0xD6, 0x9A, 0xEE, 0x26, 0x0D, 0xA0, 0x8B, 0x25, 0x05, 0x19, 0x64, 0x62, 0x67, 0x36, 0xA9, 0xF9, 0x90, 0xD4, 0x2D, 0xE2, 0x2B, 0x65, 0x29, 0xA7, 0xC1, 0x65, 0xB2, 0x2D, 0x69, 0x4C, 0xE4, 0x21, 0x31, 0xC5, 0x8D, 0x08, 0x48, 0x12, 0xB4, 0xF1, 0x90, 0xE5, 0x9F, 0xF9, 0xA3, 0x01, 0x2F, 0xEB, 0x36, 0x3A, 0x06, 0x48, 0x30, 0xF5, 0xA1, 0xDA, 0x01, 0xB4, 0x24, 0x42, 0xFB, 0x98, 0xFB, 0x3C, 0xB3, 0x58, 0x7D, 0x89, 0x17, 0x2D, 0x88, 0x53, 0x94, 0x02, 0x86, 0xDC, 0x66, 0x69, 0x17, 0x68, 0x7F, 0xF0, 0x9C, 0xD8, 0x08, 0xEC, 0xF5, 0x8F, 0x11, 0x24, 0x81, 0xEF, 0x97, 0x8F, 0x65, 0x1A, 0x41, 0xA5, 0xF5, 0x26, 0xDA, 0x04, 0xB4, 0x36, 0x1D, 0x4D, 0xA5, 0x01, 0x5F, 0x8B, 0x8E, 0xA7, 0xB7, 0xE1, 0x50, 0x86, 0x4E, 0xB5, 0x05, 0x47, 0xD8, 0x62, 0x79, 0x0C, 0xF6, 0x8E, 0x53, 0x2D, 0x79, 0x82, 0xBD, 0x3F, 0xF0, 0x44, 0x84, 0x63, 0xF3, 0xFC, 0x7E, 0x0B, 0x26, 0xA3, 0x53, 0x9C, 0xDF, 0x32, 0xE1, 0xB0, 0xA3, 0xB5, 0x01, 0xF5, 0x08, 0x7C, 0x63, 0x72, 0x9E, 0xF2, 0x00, 0xF7, 0x17, 0xC4, 0x68, 0xFE, 0x08, 0x93, 0xB5, 0x27, 0x95, 0x8C, 0x20, 0x86, 0xFF, 0x57, 0xE6, 0xC2, 0xFF, 0x99, 0xF6, 0x5E, 0xFC, 0x84, 0xD1, 0x1F, 0xD8, 0x24, 0x3C, 0x4B, 0xDD, 0xF5, 0x0F, 0x65, 0xA5, 0x04, 0xBB, 0x9C, 0x64, 0x0C, 0x91, 0xC7, 0xD6, 0x4E, 0x54, 0x37, 0x94, 0x6E, 0x72, 0x94, 0xB2, 0x00, 0xF5, 0xF9, 0xD6, 0x9A, 0x29, 0x2A, 0xF7, 0x74, 0x56, 0xF1, 0x55, 0x31, 0x9F, 0xB9, 0x2E, 0x3D, 0x23, 0x6D, 0x4E, 0x53, 0x8B, 0xBD, 0xC5, 0xD3, 0xC3, 0xD3, 0x85, 0xD6, 0x02, 0xFE, 0x96, 0x8B, 0xAC, 0x13, 0xFD, 0xDC, 0xB9, 0x96, 0x19, 0x86, 0x45, 0x59, 0x2F, 0xA2, 0xDA, 0xE1, 0x59, 0x26, 0x77, 0x28, 0x13, 0xB0, 0x29, 0x6F, 0x99, 0xDA, 0x3F, 0xEB, 0xB5, 0x26, 0x49, 0xE1, 0x9D, 0x61, 0x4B, 0xDB, 0x4B, 0x69, 0xCD, 0x9B, 0x94, 0x53, 0xE2, 0x99, 0xCA, 0x94, 0xFD, 0xE3, 0x04, 0x3F, 0xA5, 0xA2, 0xCD, 0xB1, 0xFC, 0x5F, 0x82, 0x54, 0xA7, 0x76, 0xFA, 0x12, 0xFE, 0xCF, 0xEA, 0x02, 0x95, 0x0B, 0xEB, 0xFE, 0xBF, 0x35, 0x13, 0xEC, 0xCE, 0x1D, 0xA9, 0x7A, 0x5D, 0xB2, 0x42, 0x7D, 0x47, 0x5E, 0x5F, 0x60, 0x49, 0x99, 0x4B, 0x44, 0x7A, 0xF7, 0xE4, 0xAB, 0xA2, 0x43, 0x19, 0xC7, 0xC3, 0x0C, 0x05, 0x62, 0xF5, 0xB8, 0xCD, 0xE3, 0xF9, 0x2A, 0x89, 0xAD, 0x93, 0x39, 0xCD, 0x90, 0x3D, 0x56, 0x5B, 0xA8, 0x44, 0xC4, 0xCE, 0x24, 0x8E, 0xFC, 0x0D, 0x9E, 0xD3, 0x8B, 0x54, 0x6D, 0x35, 0x17, 0xD5, 0x9D, 0xF2, 0xD8, 0x0A, 0x3D, 0xD5, 0x22, 0x99, 0x52, 0x4C, 0x24, 0x1F, 0x11, 0x76, 0xE4, 0xF6, 0xED, 0xCB, 0x65, 0xFF, 0xEA, 0x6E, 0xF9, 0x46, 0xF3, 0x3D, 0xE5, 0x3B, 0x97, 0x95, 0xD2, 0x7B, 0xE9, 0x95, 0x56, 0x13, 0xA8, 0x9D, 0x48, 0xB9, 0x89, 0x0F, 0xF9, 0x1C, 0xBC, 0xAF, 0xEF, 0x57, 0x36, 0xB4, 0xF4, 0x2B, 0x4B, 0x65, 0x5F, 0x1A, 0xC6, 0x13, 0xAF, 0x24, 0x8B, 0xAA, 0xE6, 0x26, 0x39, 0x0A, 0x8F, 0x14, 0x8F, 0x09, 0x2D, 0x60, 0x5B, 0xB3, 0x75, 0x9B, 0xF6, 0xF2, 0xC7, 0x2A, 0x6F, 0x2C, 0x73, 0xA3, 0xD7, 0x32, 0xF1, 0x96, 0xEF, 0xA9, 0xD5, 0xE8, 0x9C, 0xFF, 0xA7, 0xAE, 0x82, 0x5F, 0xB3, 0xC6, 0xE5, 0xFF, 0x4C, 0xBC, 0x2B, 0x13, 0xE9, 0x47, 0x24, 0x0F, 0xC1, 0x96, 0x64, 0x94, 0xA6, 0xDC, 0x4A, 0x58, 0xA9, 0x51, 0xA5, 0xED, 0x0E, 0xF1, 0x55, 0xD4, 0x71, 0x6A, 0x7D, 0x40, 0x49, 0x11, 0xF7, 0x84, 0x53, 0x84, 0x20, 0x8A, 0xD7, 0x62, 0x65, 0xCF, 0x64, 0x03, 0xB3, 0x4C, 0x9C, 0xE8, 0x68, 0xC0, 0x33, 0x63, 0x6E, 0xDE, 0x09, 0x4E, 0x8B, 0x74, 0x4E, 0xCE, 0x08, 0xEE, 0x13, 0x74, 0xB5, 0xEE, 0x2D, 0x2F, 0x35, 0xEE, 0x9B, 0x66, 0x3E, 0xB0, 0x77, 0x2F, 0xAA, 0xD8, 0x0B, 0xDC, 0xF4, 0xF1, 0x95, 0x1C, 0x06, 0x87, 0x2F, 0xFD, 0xCA, 0xFE, 0x06, 0x6E, 0x5A, 0x16, 0x33, 0xDB, 0x81, 0x52, 0xE3, 0x2F, 0xF4, 0x62, 0x40, 0x91, 0x61, 0x9E, 0x7B, 0x1B, 0x3D, 0x28, 0x6D, 0xCA, 0xEA, 0x40, 0x53, 0x50, 0x33, 0xED, 0x55, 0xD4, 0x29, 0x6E, 0xAA, 0x7A, 0x0F, 0xCA, 0x0D, 0x0E, 0x95, 0xBF, 0x44, 0xEE, 0x6F, 0x3C, 0x29, 0x31, 0x82, 0x07, 0x97, 0x5E, 0x60, 0x6B, 0xA1, 0xB5, 0x96, 0x49, 0xCC, 0x2C, 0x70, 0xA3, 0x71, 0x2B, 0xF5, 0x0B, 0xB8, 0xAF, 0xAD, 0xCB, 0xB5, 0xE3, 0xBF, 0x91, 0xD0, 0x99, 0xF7, 0x18, 0x1D, 0x52, 0x92, 0x5E, 0x4A, 0xCB, 0x62, 0x1F, 0xA8, 0xE2, 0xA8, 0xAB, 0xC1, 0xED, 0x72, 0x37, 0xE2, 0xBA, 0xCF, 0x68, 0x71, 0x3F, 0x76, 0x77, 0xE9, 0x2B, 0x36, 0x09, 0xEE, 0xB7, 0x8C, 0xA2, 0xDF, 0x80, 0xF7, 0x8C, 0x73, 0xA9, 0x3B, 0xE0, 0x44, 0x8D, 0x44, 0x8F, 0xC8, 0x8D, 0x44, 0x9E, 0x99, 0xEE, 0x92, 0xFB, 0xD0, 0xE3, 0xF4, 0x7D, 0xE2, 0xB1, 0xB1, 0x94, 0xF2, 0x8F, 0xA0, 0x3E, 0x78, 0x93, 0xAC, 0x8E, 0xF9, 0xB1, 0x71, 0xBC, 0x38, 0x94, 0x7C, 0xB9, 0xD4, 0x97, 0x75, 0x43, 0x9D, 0x2D, 0xDD, 0xE8, 0x2B, 0xD0, 0x2E, 0x63, 0x3D, 0x75, 0x06, 0x34, 0xD0, 0x7C, 0xC8, 0x29, 0xD4, 0xAD, 0x16, 0x5E, 0xCF, 0x28, 0xD0, 0x74, 0xF2, 0x7E, 0x68, 0xAE, 0xAA, 0xE6, 0xC7, 0xFC, 0x54, 0xD6, 0xCB, 0xF2, 0x83, 0xBE, 0xC8, 0x22, 0x44, 0x77, 0x36, 0x24, 0x8A, 0x7E, 0xF3, 0x37, 0x2E, 0x69, 0xE4, 0xFF, 0xC0, 0x3A, 0x2D, 0x3E, 0xD0, 0x4D, 0xD0, 0x29, 0x63, 0x90, 0x3A, 0x02, 0xCE, 0x57, 0xFD, 0xCB, 0x59, 0x59, 0x30, 0x5C, 0x70, 0x34, 0x63, 0xA5, 0xFE, 0x2C, 0x57, 0xA9, 0xB1, 0xCD, 0x1A, 0x11, 0xBD, 0x43, 0x39, 0x23, 0x3D, 0x33, 0xC8, 0x4A, 0xFA, 0x45, 0xE1, 0xB2, 0xE1, 0x84, 0x88, 0x27, 0x7C, 0xBF, 0x44, 0xC0, 0x2F, 0x25, 0x82, 0x2C, 0xCA, 0x68, 0x19, 0xEC, 0x69, 0xEC, 0x46, 0x55, 0x82, 0x33, 0x95, 0x63, 0x73, 0x3C, 0xCA, 0x07, 0x04, 0xF7, 0x74, 0x8F, 0x4A, 0x30, 0xDE, 0x47, 0x75, 0x4F, 0x81, 0x65, 0x74, 0xBF, 0x82, 0xCA, 0x66, 0x03, 0x23, 0xA4, 0xA4, 0xA6, 0x6E, 0x7D, 0x9D, 0xC8, 0x57, 0x32, 0xB0, 0xF8, 0x13, 0x5F, 0x4D, 0x6A, 0x2D, 0x78, 0x34, 0x04, 0xEB, 0x8D, 0x9D, 0xA8, 0x4C, 0x70, 0xA6, 0x3C, 0x39, 0x3B, 0xBA, 0xDE, 0x91, 0x9F, 0xAD, 0xDB, 0x5A, 0x2D, 0x02, 0x16, 0xAA, 0x89, 0xB2, 0x45, 0x31, 0x65, 0x0A, 0xEF, 0xFC, 0xF5, 0xBB, 0x07, 0xA5, 0x4B, 0x32, 0x62, 0xD7, 0x59, 0x8A, 0x5C, 0xE5, 0xA3, 0x17, 0x2F, 0xE1, 0xEB, 0x29, 0xB1, 0x45, 0x30, 0x9D, 0x06, 0xBF, 0x32, 0xDE, 0x49, 0x89, 0xC0, 0x05, 0xA2, 0x98, 0xEA, 0xA5, 0x89, 0x1F, 0xB1, 0xE9, 0x65, 0xFB, 0x93, 0xA8, 0x64, 0x97, 0x82, 0xD6, 0x94, 0x95, 0x07, 0xBE, 0xE4, 0x80, 0xA9, 0xFE, 0xDB, 0x4F, 0xEB, 0xC8, 0x34, 0xCE, 0xEA, 0x3A, 0xE5, 0x31, 0xCE, 0xC9, 0x85, 0x3F, 0x45, 0xDF, 0xB9, 0xFF, 0x99, 0xEB, 0xF8, 0xAF, 0x79, 0x42, 0xA3, 0x3A, 0x66, 0x31, 0xEF, 0xB2, 0x30, 0xA9, 0x2A, 0x94, 0xB3, 0x00, 0x0B, 0x2B, 0x4D, 0xE3, 0x1A, 0x26, 0x6F, 0xC8, 0xBF, 0xCF, 0x8D, 0x3F, 0xF0, 0x2A, 0xBB, 0x8D, 0xFB, 0x79, 0x87, 0xB3, 0xF6, 0x28, 0x8F, 0xF0, 0xBE, 0xA7, 0x0C, 0xE0, 0x5D, 0x5B, 0xF8, 0x49, 0x94, 0xC9, 0xFB, 0x6C, 0xEE, 0xC3, 0xAF, 0x02, 0x86, 0x1B, 0xF9, 0x31, 0x43, 0x80, 0xB1, 0x82, 0xAE, 0xCA, 0x43, 0xF0, 0x0D, 0xCC, 0xBC, 0x64, 0x0E, 0x7C, 0x2B, 0x69, 0x30, 0x4F, 0x07, 0xC7, 0x1F, 0xA8, 0xC9, 0xFA, 0x0F, 0x8E, 0xD8, 0xEE, 0xAA, 0xDD, 0x0B, 0xBB, 0x7B, 0x77, 0x2A, 0xFE, 0x41, 0xC0, 0xC2, 0x0F, 0xA2, 0x0D, 0xA0, 0x87, 0xF9, 0x0C, 0x7E, 0x2C, 0x20, 0x34, 0x1A, 0x4A, 0x9F, 0x05, 0x3C, 0xD8, 0x95, 0x15, 0x33, 0xE9, 0x3C, 0x64, 0x4A, 0xB1, 0x23, 0x95, 0x97, 0xB4, 0x34, 0xB7, 0x85, 0xDC, 0x7B, 0xE0, 0x78, 0x96, 0x1D, 0x61, 0xB8, 0xDD, 0x28, 0xBD, 0x19, 0x7B, 0xE4, 0x3D, 0x56, 0x21, 0x45, 0x6D, 0x16, 0xCA, 0x85, 0xFF, 0x20, 0xB5, 0xD9, 0x23, 0xBE, 0x0B, 0x38, 0xD6, 0xF0, 0x3E, 0x5D, 0x08, 0xEC, 0xE3, 0x7B, 0x94, 0x1B, 0x49, 0x56, 0xC1, 0xCB, 0x8A, 0xB6, 0x8A, 0x96, 0x24, 0x38, 0xE7, 0x86, 0x08, 0x9C, 0xC3, 0x47, 0x67, 0x1E, 0xE7, 0x2F, 0xD8, 0x36, 0xA8, 0xF9, 0x45, 0xD1, 0xAB, 0xD7, 0x2A, 0x26, 0xE1, 0x67, 0x1D, 0xFF, 0x08, 0xDB, 0xE0, 0x87, 0x66, 0x15, 0xFC, 0xA9, 0x60, 0x9A, 0xE1, 0x45, 0x9A, 0x01, 0x62, 0xF9, 0x39, 0x65, 0x5E, 0xEA, 0x64, 0x78, 0x73, 0x61, 0xB7, 0x72, 0x75, 0xDC, 0x45, 0xFD, 0x5D, 0x19, 0x2F, 0xEC, 0x72, 0xE6, 0x76, 0xB1, 0xE7, 0x36, 0x0F, 0x0D, 0xCA, 0x66, 0xAE, 0x2A, 0x93, 0xD7, 0x52, 0xCD, 0x8E, 0x95, 0xC2, 0x24, 0x74, 0xA5, 0x19, 0x9F, 0x79, 0x05, 0xDE, 0x32, 0x3C, 0x4E, 0x27, 0x00, 0x11, 0x74, 0x4D, 0xD9, 0xC4, 0x1C, 0x4B, 0x70, 0x77, 0xE1, 0xFA, 0xCC, 0x5F, 0xB1, 0x09, 0xFA, 0xC0, 0xF4, 0xBA, 0x7D, 0x61, 0x19, 0xF7, 0x95, 0xC0, 0xD6, 0x78, 0x8D, 0xA1, 0xE4, 0xF8, 0x6A, 0x4C, 0x3E, 0x9F, 0xB5, 0x70, 0xBC, 0x2E, 0xB4, 0xC2, 0x2A, 0xCD, 0xC4, 0xCC, 0x69, 0x68, 0x85, 0xE1, 0x09, 0x3A, 0x14, 0xD8, 0x46, 0xCD, 0x2E, 0x9B, 0x58, 0x74, 0x0E, 0x34, 0x2C, 0x5C, 0x94, 0x7F, 0x36, 0x76, 0x5F, 0xCE, 0xC7, 0x9C, 0x25, 0xA1, 0x68, 0x46, 0xA0, 0x6E, 0x74, 0x40, 0xA2, 0xFA, 0xBC, 0x72, 0xC2, 0xAA, 0xCB, 0xB2, 0xE7, 0xC2, 0x07, 0x8E, 0xAD, 0xC2, 0xFF, 0xFF, 0x34, 0xAB, 0x67, 0x3A, 0x21, 0xCA, 0x68, 0x24, 0xBD, 0x1D, 0x58, 0x47, 0x94, 0x96, 0x36, 0x57, 0x36, 0xF1, 0x26, 0x16, 0x2E, 0x2C, 0x7D, 0x1D, 0x7B, 0x20, 0x27, 0xBB, 0xE0, 0x75, 0xE8, 0xBB, 0x8C, 0xD1, 0xD9, 0xF5, 0xFE, 0x26, 0xEA, 0x47, 0x9A, 0x02, 0xCF, 0x1C, 0xD9, 0x7B, 0x71, 0x97, 0xE3, 0x56, 0xE1, 0x1C, 0xA2, 0xC0, 0xEC, 0x09, 0xD3, 0x0E, 0xF5, 0x1A, 0xC5, 0xD0, 0xBE, 0xC0, 0x6A, 0x20, 0xB4, 0xED, 0x4C, 0xA2, 0x6D, 0xFC, 0xB5, 0xC6, 0xDC, 0xA4, 0xA9, 0x11, 0x5E, 0x55, 0xBC, 0xE4, 0xFC, 0x3D, 0x75, 0xC5, 0xEF, 0x92, 0x29, 0x5F, 0x6D, 0x9E, 0x6D, 0x4A, 0x96, 0x5B, 0x97, 0xAE, 0x24, 0x6D, 0x8B, 0xDD, 0x0A, 0xD9, 0x08, 0xCE, 0x3D, 0x93, 0x9D, 0x02, 0x92, 0x7B, 0xC6, 0xC0, 0x8A, 0xBF, 0x90, 0xB7, 0x04, 0x70, 0x6B, 0x3D, 0x93, 0x96, 0x91, 0xC8, 0x6D, 0xF8, 0x90, 0x76, 0xFD, 0xE0, 0x9D, 0xAA, 0xB9, 0x69, 0x0F, 0x03, 0x7F, 0x16, 0x0B, 0x39, 0x8B, 0x7C, 0x5D, 0x73, 0x8D, 0x39, 0xBD, 0xEE, 0xC6, 0xDA, 0x47, 0xDC, 0x2D, 0x76, 0x1B, 0xA4, 0x65, 0xDC, 0xDB, 0x26, 0x53, 0x05, 0x9B, 0x79, 0x0E, 0x0B, 0x8E, 0xF0, 0xC7, 0xF0, 0xFC, 0xB9, 0xAF, 0x5B, 0xAA, 0xE1, 0x79, 0x09, 0x65, 0xF5, 0x6F, 0x20, 0xE4, 0x00, 0x5E, 0x69, 0x05, 0xD6, 0xEE, 0x2E, 0x2C, 0xBA, 0x08, 0x26, 0x6E, 0x1A, 0xAE, 0x97, 0x83, 0xFE, 0x6E, 0x35, 0xDA, 0xDD, 0xC0, 0x55, 0xBB, 0x79, 0xD2, 0xF5, 0xC0, 0x04, 0xE3, 0x3E, 0xC1, 0x14, 0x5E, 0xE6, 0x82, 0x60, 0xE6, 0x0E, 0xEF, 0x10, 0xF7, 0x5E, 0xF3, 0x2C, 0xF2, 0x57, 0x3C, 0x59, 0xE7, 0x45, 0xE8, 0xC3, 0x81, 0x0A, 0x0B, 0xDC, 0x75, 0x17, 0x5A, 0x64, 0x8E, 0x8D, 0xF6, 0xD9, 0x9A, 0xF3, 0x00, 0x79, 0xE4, 0xFA, 0x38, 0xBD, 0x1F, 0xDE, 0x6E, 0xAB, 0x95, 0xBC, 0x04, 0xDD, 0x8D, 0x39, 0xEC, 0x35, 0x60, 0xD8, 0x02, 0x2B, 0xA6, 0x96, 0x07, 0x72, 0x7E, 0x35, 0x95, 0x0B, 0xFD, 0xE2, 0x92, 0x6A, 0x13, 0x58, 0x41, 0xF8, 0x8E, 0xF2, 0x55, 0x4C, 0xC7, 0x2E, 0xB0, 0x30, 0x95, 0xBA, 0xE7, 0xB3, 0x2F, 0x67, 0x3C, 0xB1, 0xC5, 0xE5, 0x4C, 0xFA, 0x5A, 0x54, 0x64, 0x3B, 0x4A, 0xA2, 0x87, 0x76, 0x18, 0xFB, 0xB3, 0x79, 0x40, 0xD0, 0x02, 0x3B, 0x86, 0xE2, 0xA1, 0x5C, 0x7E, 0xE3, 0x6B, 0xC5, 0xB4, 0xF8, 0xB5, 0x35, 0x27, 0x64, 0x46, 0xE1, 0x6E, 0x65, 0x62, 0xF1, 0xE1, 0x5D, 0x19, 0x05, 0xE5, 0x82, 0x68, 0x9F, 0x3D, 0xD9, 0xFB, 0xE9, 0xEB, 0x2B, 0xF5, 0x9A, 0x3F, 0xF8, 0x1D, 0x9B, 0x33, 0x92, 0x10, 0x38, 0xC9, 0xF8, 0x10, 0x9B, 0x00, 0x54, 0x2E, 0xD8, 0xCF, 0x04, 0xF3, 0x38, 0x9C, 0x59, 0x4D, 0x16, 0x19, 0xA3, 0x62, 0x2F, 0xD5, 0xDC, 0x4E, 0x4F, 0xD9, 0x3F, 0xB2, 0xCC, 0x5C, 0x49, 0xEF, 0x14, 0x14, 0x38, 0x49, 0xCB, 0x7C, 0x4C, 0xB2, 0x5E, 0x09, 0xBD, 0x5C, 0xF7, 0x6B, 0xB6, 0xD2, 0x96, 0xB6, 0xB1, 0x92, 0x29, 0x48, 0xAF, 0xF1, 0x2D, 0x76, 0x3D, 0xF0, 0x77, 0xC1, 0x59, 0xC6, 0x8B, 0x17, 0x9E, 0x76, 0xBE, 0x71, 0x5F, 0x5E, 0x60, 0xEC, 0xFE, 0x1A, 0xDB, 0xEC, 0xB7, 0xFB, 0x7E, 0x95, 0x0E, 0xEA, 0xA6, 0xEC, 0xC8, 0xC8, 0xBF, 0xAE, 0x0A, 0xDA, 0x28, 0xCA, 0x6A, 0x90, 0x4E, 0x76, 0x2D, 0xD7, 0x8C, 0xE2, 0x77, 0xDA, 0xFE, 0x16, 0xDF, 0x47, 0xAF, 0x98, 0xA0, 0xAC, 0x23, 0xB8, 0xDE, 0x00, 0x62, 0x96, 0xF0, 0x82, 0xD2, 0x66, 0x35, 0xCA, 0x4A, 0x6A, 0x62, 0x2D, 0xAB, 0x2B, 0x0A, 0xD4, 0xA1, 0xB7, 0x4A, 0x2F, 0x64, 0xDF, 0xDD, 0xBE, 0x38, 0xFF, 0x85, 0x76, 0xDD, 0x06, 0xF7, 0xEC, 0x29, 0x8A, 0xDD, 0x2E, 0xAC, 0x66, 0xAA, 0xA0, 0xDA, 0xCE, 0x55, 0xDC, 0x8D, 0xE5, 0x9B, 0x3A, 0xB2, 0x86, 0x20, 0x65, 0xB8, 0x99, 0xB1, 0xE7, 0xED, 0x49, 0xA8, 0xEB, 0x9D, 0x91, 0x34, 0x29, 0xEA, 0x67, 0x57, 0x74, 0xE2, 0xD3, 0xE0, 0xC9, 0xCD, 0x13, 0x93, 0x46, 0x05, 0x94, 0xD7, 0xCC, 0x4A, 0xB2, 0x5B, 0xFB, 0xBD, 0x24, 0x26, 0x79, 0xDB, 0x0A, 0xC7, 0xEC, 0x4B, 0x29, 0xB7, 0xAD, 0x96, 0x2A, 0x4E, 0xA5, 0x1D, 0x37, 0x1C, 0x27, 0xB2, 0xE1, 0xFC, 0x9E, 0xE7, 0xC9, 0xFA, 0x72, 0xA9, 0x04, 0xDB, 0x9E, 0xDA, 0xB4, 0xD4, 0xA8, 0xD8, 0x4E, 0x36, 0x6D, 0x69, 0xB0, 0x4B, 0x93, 0x30, 0xF5, 0x82, 0x7F, 0x47, 0xB5, 0x24, 0xB5, 0x76, 0x8D, 0xB8, 0xF8, 0x7E, 0xDA, 0xAC, 0xE5, 0x66, 0xD9, 0x77, 0xD2, 0xCE, 0x5B, 0x5E, 0x53, 0x68, 0x39, 0x1D, 0x06, 0x15, 0xC2, 0x1F, 0x5C, 0x9F, 0xB9, 0x17, 0x59, 0x6B, 0x2E, 0x1B, 0xD7, 0xD1, 0xFD, 0x19, 0x3C, 0x1D, 0x31, 0xD8, 0x7E, 0x1C, 0x9C, 0x12, 0x3C, 0xAD, 0x71, 0x1E, 0x40, 0xFA, 0xDF, 0xAA, 0x8A, 0xE5, 0xE9, 0xBC, 0x6F, 0x17, 0xFD, 0xE1, 0x05, 0x3A, 0xAF, 0xC8, 0x5E, 0xCB, 0x73, 0xB6, 0xF4, 0x53, 0xAC, 0xE0, 0xDE, 0x34, 0x70, 0x14, 0xF6, 0x73, 0xF3, 0xE6, 0x06, 0xB0, 0x23, 0xB8, 0x82, 0x84, 0xD5, 0x47, 0x8E, 0xE2, 0x67, 0x23, 0x6D, 0xDA, 0xFC, 0xB1, 0x94, 0x3D, 0x82, 0x86, 0x19, 0xA8, 0x8B, 0xDF, 0xEF, 0xCA, 0x30, 0xF8, 0xB6, 0xF7, 0xDA, 0xC2, 0x7F, 0xD0, 0x39, 0xA7, 0x9A, 0xAC, 0xFD, 0x60, 0xA9, 0xC5, 0x25, 0x79, 0x1F, 0xEF, 0xE3, 0x82, 0x8B, 0x42, 0x8A, 0xFB, 0x61, 0xEE, 0x50, 0xFE, 0x1D, 0x2E, 0x91, 0x58, 0x7A, 0x64, 0x06, 0xFF, 0x63, 0xE4, 0xC7, 0xD6, 0xBD, 0xCC, 0xAC, 0x3D, 0x97, 0xEB, 0x27, 0x91, 0xEF, 0xFD, 0xA6, 0x54, 0x64, 0x11, 0x9E, 0xAB, 0x13, 0x0B, 0x43, 0xB0, 0x60, 0xA7, 0x85, 0x99, 0xF7, 0xE0, 0x77, 0x16, 0x98, 0x3C, 0x02, 0x78, 0xBF, 0xE0, 0x8C, 0xD0, 0x9B, 0xB7, 0x74, 0xAE, 0x29, 0xBF, 0x84, 0x9B, 0x16, 0xCF, 0xEF, 0x0A, 0x95, 0x5E, 0x88, 0xAC, 0x6A, 0x39, 0x25, 0xC6, 0x03, 0x5F, 0xD5, 0xFE, 0x11, 0xB4, 0x6C, 0x11, 0x97, 0xDF, 0x61, 0x7E, 0xAE, 0x76, 0x2D, 0xB8, 0x42, 0x7E, 0x59, 0x96, 0x9D, 0xA9, 0xC2, 0xB6, 0x58, 0x48, 0xE4, 0x56, 0xE0, 0x6B, 0x83, 0xC5, 0xC2, 0x51, 0xBC, 0xE4, 0xB9, 0x55, 0xFC, 0x68, 0x6E, 0x54, 0xAC, 0x4F, 0x67, 0xBA, 0xE6, 0xD7, 0xC1, 0x6D, 0x2D, 0xCE, 0x2A, 0x93, 0xA0, 0x90, 0xDA, 0x4D, 0xB2, 0x34, 0xBF, 0x8E, 0x72, 0x63, 0x51, 0xBD, 0x37, 0x53, 0x60, 0xCE, 0x57, 0x3A, 0xCD, 0xCE, 0xB4, 0x25, 0x6E, 0x59, 0xAE, 0x90, 0x3D, 0x82, 0x47, 0x1A, 0x4E, 0x12, 0x9C, 0xE1, 0xF5, 0xCE, 0xCB, 0xE3, 0x3B, 0x71, 0xC3, 0x0E, 0x4F, 0xE9, 0x3C, 0x9D, 0x1D, 0x1F, 0xFE, 0xBC, 0x65, 0x63, 0xC6, 0xF4, 0x20, 0xCB, 0xDA, 0x43, 0x6A, 0xCA, 0x6F, 0xA0, 0xAC, 0x47, 0x36, 0xB0, 0xC6, 0x3E, 0x3F, 0x5F, 0xA8, 0x73, 0x0E, 0xC8, 0x68, 0xA7, 0xEE, 0x58, 0x6D, 0x97, 0x69, 0xE0, 0xDF, 0x46, 0x4E, 0x82, 0x7C, 0x60, 0xFA, 0xFC, 0x0B, 0xFC, 0x79, 0xDC, 0xC3, 0x31, 0x3E, 0x47, 0xEC, 0x0B, 0xC4, 0xE1, 0xD1, 0x2D, 0x1B, 0xF5, 0x9D, 0xBB, 0xF3, 0x6B, 0xFD, 0x32, 0xBC, 0xB6, 0xC4, 0x96, 0x1D, 0x52, 0x65, 0x7B, 0xB3, 0xF9, 0xE3, 0x24, 0x1C, 0xE7, 0xF2, 0x0C, 0x1F, 0x06, 0xB4, 0xDE, 0x2B, 0xDB, 0x82, 0x1C, 0x33, 0xDE, 0x2F, 0x20, 0x81, 0x10, 0x83, 0x31, 0xFC, 0x49, 0x5C, 0xE2, 0x4C, 0x57, 0x62, 0x74, 0xA4, 0xEA, 0x88, 0x59, 0x72, 0xDE, 0xA1, 0xD9, 0xE5, 0x6B, 0x52, 0x5B, 0xE3, 0xD7, 0x29, 0x1E, 0x72, 0xC4, 0xC9, 0x29, 0xBC, 0x7F, 0x3C, 0x65, 0xEA, 0x8D, 0x90, 0xFB, 0x60, 0x37, 0x77, 0xBA, 0xC7, 0x3B, 0x24, 0x9C, 0x77, 0xC1, 0xDE, 0x0F, 0xFD, 0x0D, 0x48, 0xCC, 0xF7, 0x63, 0x55, 0xC0, 0xAD, 0xD3, 0xD3, 0x63, 0xDF, 0x27, 0x9F, 0xEE, 0x18, 0x9F, 0xF0, 0x33, 0xF5, 0x6A, 0x71, 0x5F, 0xF2, 0x69, 0xEE, 0x28, 0x79, 0x51, 0xDA, 0x2E, 0x1E, 0xC9, 0xD5, 0x72, 0x5B, 0x01, 0x79, 0x70, 0x03, 0x68, 0x0E, 0xAE, 0x76, 0xCF, 0x82, 0xBF, 0x83, 0x69, 0x76, 0x47, 0xD1, 0x36, 0x10, 0x31, 0xB7, 0xC5, 0x78, 0x20, 0x76, 0x2A, 0x26, 0xA6, 0x1D, 0x8F, 0x6D, 0xF3, 0x8E, 0x8B, 0xC7, 0x5E, 0x16, 0x85, 0x24, 0x9E, 0xC7, 0x4E, 0xCB, 0x3A, 0x52, 0x3A, 0xB1, 0x75, 0x69, 0xD1, 0x9C, 0x22, 0x6C, 0x42, 0x60, 0x21, 0x80, 0x20, 0x3F, 0xDC, 0x6E, 0xC3, 0x5C, 0x78, 0x93, 0x5D, 0x34, 0x7A, 0x08, 0x12, 0x98, 0x0F, 0xC1, 0x56, 0x43, 0x4E, 0x27, 0x6C, 0xA2, 0xFD, 0xA4, 0xC9, 0xAD, 0x53, 0x63, 0x87, 0x8B, 0x9D, 0x0A, 0x7E, 0x26, 0xEC, 0x13, 0x44, 0x4A, 0x43, 0x92, 0x55, 0x7C, 0x38, 0xA5, 0x29, 0x8D, 0xA1, 0x23, 0x03, 0x8B, 0x79, 0x39, 0xC4, 0x45, 0x37, 0x09, 0x3C, 0x05, 0x4D, 0xB2, 0x0B, 0x44, 0x17, 0xC1, 0xE9, 0x66, 0x3F, 0xB0, 0xB9, 0xD0, 0xC9, 0xFE, 0xAF, 0x91, 0x37, 0x32, 0xD0, 0x16, 0xF3, 0x43, 0x07, 0xD2, 0xCD, 0xF2, 0x9E, 0xC7, 0x27, 0x2B, 0x0D, 0xC5, 0x0F, 0x93, 0x34, 0x52, 0x5D, 0x72, 0x42, 0x6A, 0x99, 0xC8, 0x2C, 0x68, 0x06, 0xF7, 0x13, 0x7F, 0x88, 0xFB, 0x52, 0xE8, 0x14, 0xDE, 0x67, 0x97, 0x8B, 0x4E, 0x40, 0x04, 0xE6, 0x13, 0xB1, 0x11, 0xB0, 0x65, 0x9F, 0x6B, 0xE4, 0xFC, 0xA2, 0x99, 0x4D, 0xA3, 0x63, 0x6A, 0x73, 0xCF, 0xE4, 0x89, 0xE3, 0x76, 0x67, 0xE6, 0x88, 0xCE, 0x25, 0xEA, 0xD3, 0x27, 0x24, 0x95, 0xA4, 0x7C, 0x50, 0xC8, 0x76, 0x45, 0x72, 0x51, 0xD1, 0x01, 0x77, 0x04, 0x12, 0x92, 0x5F, 0xEC, 0x1E, 0x21, 0x3F, 0xD1, 0x7D, 0xE6, 0x1E, 0xD8, 0x48, 0x38, 0xB2, 0xEF, 0xF3, 0x41, 0x4D, 0xED, 0xD1, 0xC6, 0xD0, 0xE8, 0xC1, 0x8A, 0x23, 0xB9, 0xBE, 0xB1, 0x8A, 0x22, 0x4A, 0x70, 0x30, 0xE1, 0x5F, 0xEE, 0x88, 0xA4, 0x09, 0x29, 0xCE, 0xBA, 0x1B, 0x3B, 0xEF, 0x71, 0xBE, 0xC8, 0x0B, 0xDD, 0xED, 0x21, 0x5F, 0xE6, 0x80, 0xDD, 0x73, 0xE4, 0x1B, 0xB6, 0xCA, 0x1C, 0xC1, 0x0C, 0xE0, 0xA2, 0x5E, 0xCF, 0x83, 0x40, 0xC7, 0xC6, 0x86, 0x6D, 0xD1, 0xD6, 0x4D, 0x71, 0xFA, 0x96, 0xC3, 0xEF, 0xAB, 0x17, 0x0B, 0x76, 0x24, 0x6C, 0x28, 0xF1, 0x4E, 0x1A, 0x99, 0x9C, 0xA7, 0xCF, 0xD8, 0xBD, 0x94, 0x13, 0xAC, 0x19, 0xE3, 0x36, 0x06, 0x9A, 0xC6, 0x92, 0x76, 0x0F, 0xD1, 0x91, 0xF8, 0x02, 0x8B, 0x61, 0xD8, 0x46, 0xF8, 0x4B, 0xCF, 0x90, 0x83, 0x23, 0xFB, 0xF3, 0x1A, 0x12, 0xA3, 0x36, 0x1C, 0x61, 0x72, 0xC3, 0x0E, 0xFB, 0x37, 0xFB, 0xB0, 0x50, 0xFC, 0xF1, 0x2A, 0x5D, 0xE2, 0xF5, 0xE4, 0x35, 0x85, 0xA5, 0xBB, 0x8C, 0x39, 0x93, 0x75, 0x80, 0x6B, 0x23, 0xD8, 0x25, 0x3C, 0x6C, 0x9F, 0x80, 0x1A, 0xE1, 0x1F, 0x2C, 0x2E, 0x63, 0x0C, 0xB2, 0xB5, 0x6F, 0x3F, 0x6F, 0x66, 0xE4, 0xB4, 0xA6, 0xC9, 0xBC, 0xAB, 0x87, 0x76, 0xE4, 0x55, 0x00, 0xA7, 0xE2, 0x9F, 0x8B, 0x56, 0x82, 0x0D, 0xC9, 0x3B, 0x53, 0x35, 0x50, 0x71, 0xEA, 0xC5, 0xC0, 0xCF, 0xF0, 0x75, 0xAE, 0x9F, 0xDB, 0x23, 0xF4, 0x08, 0xAF, 0xC1, 0x8E, 0xC5, 0xA7, 0x00, 0x06, 0xE6, 0x73, 0xF0, 0x22, 0x60, 0x5D, 0x8F, 0x6F, 0x9A, 0x7B, 0x72, 0x4C, 0x7D, 0x1A, 0xA7, 0x37, 0x75, 0x5C, 0x6E, 0x05, 0x6F, 0x02, 0xC7, 0x45, 0xF4, 0x11, 0xB0, 0xE7, 0x9E, 0x4E, 0x79, 0x0A, 0x6A, 0x81, 0x59, 0x41, 0xB3, 0xE1, 0x75, 0xE0, 0x4C, 0xB7, 0x19, 0xE8, 0x01, 0x30, 0xD4, 0xF6, 0x23, 0xD6, 0x0E, 0x7A, 0x98, 0xD5, 0xE2, 0x9B, 0x41, 0xDB, 0x23, 0x17, 0x52, 0x86, 0x63, 0x63, 0x6A, 0xF7, 0xA7, 0x3E, 0x40, 0x0F, 0xE8, 0x6D, 0x38, 0xFE, 0xE8, 0x75, 0xC1, 0x5B, 0xEE, 0x65, 0xF4, 0x59, 0x52, 0x1D, 0x40, 0xA1, 0x59, 0xBB, 0x67, 0x40, 0x65, 0x48, 0xA6, 0xAB, 0x17, 0xF2, 0x07, 0x5E, 0x6F, 0xAB, 0xC0, 0xA2, 0xA1, 0x60, 0x33, 0x0E, 0x3E, 0x0A, 0xFC, 0xDC, 0xC9, 0x4D, 0xF2, 0x17, 0x7E, 0xAB, 0x91, 0xA5, 0xCC, 0x10, 0xF8, 0x66, 0xFB, 0xA5, 0xBE, 0x62, 0xCD, 0xF9, 0x01, 0x9C, 0x7B, 0x4C, 0x7F, 0x42, 0x06, 0xEF, 0x32, 0x75, 0x76, 0xD7, 0x4C, 0x68, 0x28, 0x91, 0xEA, 0xF2, 0x02, 0xC9, 0x46, 0xD7, 0xDA, 0xA6, 0x62, 0x8B, 0xE0, 0x00, 0xB3, 0x58, 0xEC, 0x3E, 0x04, 0xB4, 0x4F, 0x4B, 0x48, 0x48, 0x1F, 0x5A, 0x75, 0x23, 0x89, 0xA7, 0xE4, 0x67, 0x7C, 0x49, 0x39, 0x2E, 0xAB, 0xA2, 0xBB, 0xD2, 0x3E, 0x48, 0xD6, 0xC5, 0xD7, 0xF2, 0x46, 0x0A, 0x5D, 0x76, 0xCD, 0x03, 0xF7, 0x33, 0x09, 0x2E, 0xAF, 0x11, 0x3F, 0x7C, 0x8D, 0x2D, 0x80, 0x4D, 0x46, 0x8C, 0xCD, 0x38, 0xD8, 0x05, 0x68, 0xA0, 0x75, 0x71, 0xFC, 0xCD, 0xBC, 0xC3, 0x15, 0x4B, 0x12, 0xF3, 0xB2, 0x7D, 0xB5, 0xEF, 0x92, 0xFB, 0x74, 0x43, 0xA9, 0x82, 0xB4, 0xA9, 0xEA, 0xE4, 0xB8, 0x57, 0x5C, 0x4F, 0xB9, 0xD7, 0x4E, 0x5B, 0xE0, 0x86, 0xB0, 0xC9, 0xA5, 0x06, 0x99, 0x4E, 0xFA, 0xDA, 0x62, 0xE8, 0x1F, 0xE4, 0xBE, 0x99, 0xFA, 0xFF, 0xA9, 0x1F, 0x2D, 0xA7, 0xE3, 0x6E, 0x57, 0x8D, 0x2F, 0x5F, 0x95, 0x38, 0xAF, 0xB4, 0x24, 0xFD, 0x4F, 0xB2, 0x7D, 0x81, 0x11, 0x79, 0x24, 0x35, 0x2C, 0xBB, 0x2F, 0xF6, 0x0F, 0x27, 0x4F, 0x3B, 0x77, 0xC7, 0x66, 0x20, 0x40, 0xA6, 0x72, 0x09, 0x86, 0x6F, 0xD2, 0x2A, 0x5B, 0x3E, 0xFA, 0x09, 0xAD, 0x32, 0xEB, 0xC3, 0x6E, 0xC1, 0xB6, 0x2D, 0x2F, 0xE3, 0xD2, 0x5A, 0xDC, 0xCB, 0x3E, 0x26, 0xEC, 0xAE, 0x3B, 0x9E, 0x5E, 0x95, 0x54, 0x58, 0xE1, 0x4E, 0xDC, 0x49, 0xB9, 0x5D, 0xF8, 0xE0, 0xF0, 0x6F, 0x8E, 0x55, 0x76, 0xDD, 0x8E, 0x11, 0xBC, 0xC7, 0xAA, 0xEA, 0x95, 0xFF, 0x60, 0x3D, 0xBF, 0xD8, 0x56, 0x8D, 0xBE, 0xC6, 0x38, 0xE6, 0x63, 0xB1, 0x17, 0x70, 0x64, 0xD3, 0xB3, 0xB8, 0x94, 0xA3, 0x13, 0xCB, 0x5E, 0xC5, 0x3F, 0x69, 0xA7, 0xB4, 0xB6, 0x89, 0xA7, 0xEA, 0x6F, 0xE3, 0x59, 0x29, 0x3B, 0xCB, 0x7F, 0x1F, 0x4E, 0x4C, 0xEB, 0xCB, 0xCF, 0xDB, 0x9E, 0xC1, 0xE3, 0x6B, 0x97, 0xAF, 0xBC, 0x07, 0x47, 0x0A, 0xF8, 0xB6, 0x17, 0xD0, 0x41, 0x7C, 0x85, 0x79, 0x2C, 0xF6, 0x07, 0xAE, 0x68, 0x1E, 0x8B, 0x9F, 0x8A, 0x32, 0x28, 0x0B, 0xC0, 0x37, 0x1C, 0x36, 0x4D, 0xDF, 0x82, 0x3D, 0x4C, 0x30, 0x26, 0x6E, 0x63, 0x64, 0xD2, 0x85, 0xD8, 0x91, 0x58, 0x52, 0xAA, 0x6C, 0xFB, 0x04, 0x4C, 0xC5, 0x0D, 0x74, 0x99, 0x82, 0xC7, 0xF1, 0x24, 0xB6, 0xE1, 0x44, 0x10, 0x4F, 0x67, 0x96, 0x41, 0x74, 0xF2, 0x8A, 0x1B, 0xEA, 0xD1, 0xAC, 0xA4, 0xB0, 0xE2, 0xFB, 0x28, 0x9B, 0xD2, 0xA7, 0xAE, 0x45, 0x11, 0xCE, 0x50, 0xA2, 0x1D, 0x8D, 0xE1, 0x26, 0xC4, 0xBD, 0x41, 0x23, 0x79, 0xD4, 0x4E, 0x63, 0x6C, 0x04, 0x70, 0xC5, 0xC5, 0x15, 0x9F, 0x0B, 0xBA, 0xD8, 0xBC, 0xC0, 0x1F, 0x00, 0x5F, 0xCC, 0xC6, 0x12, 0xCE, 0xC0, 0xE5, 0xAA, 0x0C, 0xF8, 0x3D, 0x62, 0x5F, 0x74, 0x13, 0x6E, 0x45, 0xA2, 0x55, 0xCF, 0xE1, 0xD3, 0xC8, 0x73, 0xEC, 0x04, 0x32, 0x03, 0x75, 0x88, 0xFD, 0x89, 0x1C, 0x40, 0xE2, 0xB7, 0x4F, 0x44, 0x13, 0x10, 0xF3, 0x95, 0x47, 0xB1, 0x6E, 0x78, 0xBE, 0x4D, 0x09, 0x2E, 0x82, 0xE6, 0x98, 0xDE, 0xC0, 0x9F, 0x80, 0x25, 0xD5, 0x15, 0xD0, 0x02, 0xFE, 0xED, 0xFC, 0x93, 0x50, 0x18, 0x7F, 0x86, 0xE2, 0x0D, 0x14, 0xC7, 0xEC, 0x40, 0x4F, 0xC1, 0x23, 0xE8, 0x6D, 0x87, 0x3A, 0xE1, 0x73, 0x64, 0xF5, 0xD6, 0x43, 0xC8, 0x33, 0xFC, 0xF2, 0x8A, 0x37, 0x58, 0x0C, 0xF2, 0xC0, 0x86, 0xC0, 0x83, 0xA0, 0xF7, 0xA6, 0xFF, 0xE1, 0xBD, 0xD0, 0xDC, 0xEA, 0x6F, 0x40, 0x97, 0xC2, 0x27, 0xDF, 0x14, 0x34, 0x93, 0x71, 0xE5, 0xC9, 0x60, 0xAC, 0x24, 0x09, 0x59, 0x03, 0x2D, 0x15, 0x71, 0x63, 0x2E, 0xC1, 0xB3, 0xD9, 0xA7, 0xDB, 0x26, 0x21, 0x41, 0xB4, 0x7C, 0x45, 0x16, 0x66, 0x85, 0x15, 0xDA, 0x44, 0xE2, 0x5E, 0x70, 0x8E, 0xE9, 0x5B, 0xBC, 0x15, 0xDA, 0x5A, 0x79, 0x8B, 0x57, 0x95, 0x75, 0x3F, 0x2F, 0x11, 0x58, 0xA0, 0xCB, 0x93, 0x3E, 0x05, 0x64, 0x9A, 0x60, 0x28, 0x01, 0xDC, 0xA7, 0x5C, 0x10, 0x55, 0x09, 0xED, 0x92, 0x6E, 0x09, 0x28, 0x86, 0x1F, 0x0A, 0x42, 0x56, 0x38, 0xA2, 0xEF, 0x09, 0x9E, 0x8D, 0x1F, 0xEE, 0x80, 0x78, 0x9B, 0x7E, 0xC5, 0x1B, 0xA1, 0xB4, 0x4A, 0x82, 0x1B, 0x5B, 0xDA, 0xA8, 0xCF, 0xE7, 0xE9, 0x0A, 0xF3, 0x25, 0xE9, 0xC0, 0x12, 0x7D, 0x1C, 0xE4, 0x09, 0xDC, 0xC8, 0x1C, 0x11, 0x19, 0x0A, 0x3E, 0x57, 0x7F, 0xF3, 0xDF, 0x0D, 0xC7, 0x48, 0x06, 0x57, 0x4C, 0x44, 0xDB, 0xA9, 0x74, 0x9B, 0xAD, 0xF8, 0x6C, 0xE4, 0x8F, 0xE9, 0x77, 0xBC, 0x0A, 0xD2, 0x55, 0xD6, 0x70, 0x7E, 0xD6, 0xAF, 0xD4, 0xBB, 0x71, 0x2B, 0xAB, 0xA2, 0x24, 0x06, 0x3C, 0x7E, 0x49, 0x36, 0x38, 0x19, 0xD8, 0x98, 0xF7, 0x2B, 0xE2, 0x0A, 0x18, 0x99, 0x79, 0xC0, 0x3F, 0x06, 0xFA, 0xA9, 0xB8, 0xB2, 0xFC, 0x18, 0x9A, 0xCA, 0xF0, 0x6D, 0x16, 0x63, 0xBF, 0xD1, 0x6A, 0xD3, 0xCF, 0x78, 0x11, 0xD4, 0x5D, 0xB6, 0x93, 0xCB, 0x6F, 0x87, 0xB2, 0xCD, 0xB9, 0x89, 0x4D, 0x1B, 0x44, 0x6A, 0x9E, 0x51, 0x75, 0x0B, 0x8F, 0xE1, 0x7D, 0x2B, 0x79, 0x1E, 0xE1, 0x03, 0x5A, 0xE7, 0x5A, 0xFA, 0x03, 0x10, 0xAA, 0xD9, 0xB5, 0xC2, 0x1A, 0x75, 0x61, 0x85, 0x36, 0x3E, 0xD8, 0x7F, 0x58, 0xE8, 0xFF, 0x1F, 0x66, 0x43, 0xFF, 0x95, 0x1E, 0x11, 0xC6, 0x47, 0x7F, 0xCC, 0x31, 0x64, 0xAF, 0x1D, 0x56, 0x4A, 0xA6, 0xF0, 0x77, 0xC5, 0xFF, 0x07, 0x56, 0xD2, 0x57, 0x92, 0x02, 0x22, 0x9F, 0x50, 0x77, 0x52, 0xDE, 0xFA, 0x7F, 0x21, 0x07, 0x38, 0x0D, 0xCB, 0x7D, 0x48, 0x7F, 0xDE, 0x46, 0xEB, 0x7A, 0x32, 0x8C, 0x97, 0x6E, 0x9A, 0x4A, 0x46, 0xF1, 0x9A, 0x8B, 0xA7, 0xB1, 0x9B, 0x92, 0x26, 0x66, 0x8E, 0xE3, 0x9B, 0xA4, 0xA4, 0x08, 0x63, 0xE9, 0xF7, 0x69, 0x73, 0x78, 0xB7, 0xA9, 0x6E, 0x4E, 0x53, 0xE4, 0x10, 0xF2, 0x22, 0x6F, 0xB8, 0x7F, 0x1B, 0xE9, 0x02, 0xAC, 0x5D, 0xBE, 0x82, 0x1C, 0x02, 0x9C, 0xB0, 0xE6, 0x11, 0x7F, 0x80, 0x5A, 0x53, 0x67, 0xE2, 0x1F, 0xA0, 0x2F, 0x58, 0xC7, 0x78, 0x83, 0xCD, 0xBA, 0xF3, 0x74, 0x00, 0xEC, 0x28, 0x98, 0x45, 0xC1, 0x30, 0xC1, 0x19, 0x24, 0x33, 0xE1, 0x3B, 0x11, 0x26, 0xC4, 0x47, 0x38, 0xC7, 0x6F, 0x29, 0xD1, 0x04, 0x63, 0xCE, 0x0F, 0x88, 0x1A, 0x88, 0xB4, 0x8E, 0x24, 0x9A, 0xC0, 0x2A, 0x53, 0x27, 0xA2, 0x0D, 0xF4, 0xC9, 0x5F, 0x45, 0xDB, 0xD1, 0x0A, 0x6D, 0x10, 0x65, 0x4B, 0x07, 0xF3, 0xB5, 0xA4, 0x39, 0x6D, 0xCE, 0x99, 0x4A, 0x88, 0xC8, 0xAE, 0x83, 0x59, 0xC4, 0x16, 0x22, 0x74, 0x8B, 0x33, 0xE1, 0x8C, 0x8F, 0x73, 0xCE, 0x22, 0xA2, 0x11, 0x77, 0x6B, 0x90, 0x90, 0x42, 0x87, 0x4C, 0xC3, 0x89, 0x1C, 0xB0, 0xB0, 0x60, 0x32, 0xF9, 0x5E, 0x6A, 0x90, 0x1E, 0x48, 0xAE, 0x90, 0x58, 0x32, 0xAB, 0x09, 0x17, 0x91, 0x3A, 0xCD, 0x00, 0xBF, 0x29, 0xE8, 0x08, 0x47, 0xF0, 0x4A, 0x3E, 0xB6, 0xF9, 0x08, 0x5E, 0x4E, 0x65, 0x38, 0x83, 0xC4, 0x32, 0xF4, 0xAE, 0x75, 0x3A, 0x81, 0x41, 0x7F, 0x4C, 0x19, 0x22, 0x03, 0x1C, 0xC8, 0x9B, 0x49, 0x5C, 0xD0, 0x6E, 0x51, 0xF3, 0xF0, 0x7F, 0x1A, 0x09, 0x1D, 0x87, 0xAF, 0x56, 0x7E, 0x49, 0xA9, 0xC0, 0xCD, 0x64, 0xDF, 0xC3, 0x1C, 0xF0, 0x19, 0xE2, 0x28, 0xDF, 0xED, 0xF8, 0x06, 0xFE, 0x77, 0xE7, 0xA9, 0xF8, 0x2F, 0x9C, 0xFE, 0xFF, 0xC3, 0x08, 0x58, 0x6A, 0x1A, 0x4F, 0x48, 0xC0, 0x07, 0xB9, 0xAB, 0x88, 0x89, 0x05, 0x22, 0xF5, 0x6A, 0x7C, 0x43, 0xEE, 0x5F, 0xEA, 0x1F, 0x56, 0x95, 0x75, 0x22, 0xB9, 0x1F, 0x93, 0x6A, 0x63, 0x42, 0x5F, 0x63, 0x02, 0x65, 0xF8, 0x26, 0x47, 0xEC, 0xB1, 0xE8, 0xAA, 0x53, 0x0D, 0xDE, 0x4E, 0x46, 0x59, 0x4F, 0x24, 0xDC, 0x91, 0x25, 0xA6, 0x46, 0x44, 0x2A, 0xF8, 0x45, 0x5F, 0x84, 0xE7, 0x56, 0xBE, 0x52, 0x56, 0xE2, 0x53, 0xCB, 0x2C, 0x89, 0x07, 0x58, 0x62, 0xE1, 0xB2, 0xA4, 0x3C, 0xF4, 0x62, 0xCE, 0xBF, 0x7D, 0x59, 0xE8, 0x27, 0xED, 0xF7, 0x4D, 0x97, 0xB0, 0x78, 0x59, 0xB9, 0x93, 0x1F, 0x9E, 0x42, 0xCF, 0xB5, 0x2A, 0x27, 0xE6, 0x20, 0xDD, 0x26, 0x67, 0x88, 0x50, 0x68, 0x64, 0xB6, 0x14, 0xB7, 0x6D, 0xBC, 0x2F, 0xFF, 0x89, 0xD5, 0xD6, 0xC6, 0x12, 0x19, 0x98, 0x61, 0x85, 0x65, 0xB2, 0x10, 0xA5, 0x0B, 0xFF, 0xEE, 0x3B, 0x80, 0x3E, 0xCD, 0xFA, 0xE3, 0x6B, 0x88, 0x7E, 0x53, 0xAA, 0x9D, 0x0D, 0xF0, 0xC5, 0xCC, 0x51, 0xAB, 0x72, 0xFC, 0x07, 0xBA, 0xC1, 0x84, 0x24, 0x36, 0x43, 0xB3, 0x32, 0x1B, 0x95, 0xAE, 0x87, 0x66, 0x29, 0xE5, 0xB2, 0xE3, 0x87, 0xB5, 0xA4, 0x9B, 0x84, 0x17, 0x0F, 0x26, 0xAD, 0x17, 0x2D, 0x4A, 0x5A, 0xBA, 0x6F, 0xB6, 0x60, 0x61, 0x4A, 0x95, 0x6F, 0x0E, 0x7F, 0x3C, 0xC7, 0xCA, 0xC9, 0x96, 0x5E, 0xC7, 0x1D, 0xB4, 0xB2, 0xA2, 0x7C, 0x78, 0x05, 0x26, 0x8E, 0xE4, 0x3D, 0xDE, 0x5B, 0x5D, 0x88, 0x7C, 0x52, 0x52, 0x81, 0xF4, 0xAF, 0xD4, 0x37, 0xB9, 0x0B, 0xBB, 0x25, 0x5E, 0x9F, 0x6A, 0x95, 0x68, 0x29, 0x1C, 0xC5, 0x99, 0x11, 0x8A, 0xB0, 0xAB, 0xB8, 0xBC, 0x4D, 0x45, 0x8C, 0x88, 0x97, 0xBB, 0x8C, 0x4F, 0xBD, 0x01, 0x56, 0x59, 0x0D, 0xA3, 0x86, 0x01, 0x51, 0x26, 0x9E, 0xA4, 0x1E, 0x48, 0xD5, 0xE9, 0xA5, 0xDB, 0x81, 0x4B, 0x92, 0x8F, 0xE2, 0x4B, 0x60, 0x33, 0x72, 0x53, 0x64, 0x0C, 0x19, 0xC4, 0x47, 0x0B, 0xA6, 0x42, 0x4D, 0xA1, 0xE3, 0xF9, 0x02, 0xE8, 0x84, 0xCF, 0x59, 0xC6, 0x18, 0xEA, 0x5E, 0xB6, 0x89, 0xCA, 0x03, 0xAF, 0x5A, 0x4D, 0x27, 0x8F, 0x83, 0x8B, 0x4D, 0x62, 0xC9, 0x68, 0xE0, 0x45, 0xFA, 0x45, 0xC9, 0x4E, 0xD2, 0x44, 0x1C, 0x21, 0x52, 0x92, 0x2C, 0xEC, 0x2D, 0x90, 0x90, 0x66, 0x71, 0x87, 0xD8, 0xF9, 0xC4, 0xEE, 0x90, 0x65, 0xCC, 0x0B, 0x7C, 0xB7, 0xCF, 0x68, 0xBA, 0x0B, 0x1B, 0xBF, 0x8C, 0xA5, 0x62, 0xE1, 0x08, 0xAB, 0x03, 0x64, 0x29, 0x78, 0xC5, 0xA4, 0x89, 0xDC, 0x0A, 0xDA, 0x68, 0x26, 0x89, 0x3D, 0x45, 0xB8, 0x68, 0xA1, 0xF0, 0x92, 0xB0, 0x1B, 0x4C, 0x62, 0xCF, 0x0B, 0xDC, 0xE2, 0x0C, 0xF8, 0x3B, 0xF9, 0x4D, 0xC1, 0xFF, 0x98, 0xED, 0xF4, 0xE0, 0xC6, 0x6C, 0xDA, 0x9B, 0x5C, 0xBF, 0xAC, 0x98, 0x5A, 0x8B, 0x3C, 0xB5, 0x6A, 0x23, 0x0B, 0x21, 0x3F, 0x93, 0xE7, 0xE4, 0x66, 0xD0, 0x53, 0x75, 0x50, 0x84, 0xA8, 0xE3, 0xFF, 0xEF, 0x7E, 0xAC, 0x8C, 0x01, 0x39, 0xAC, 0xB1, 0x7C, 0x41, 0xEC, 0x09, 0xE6, 0x9D, 0xE4, 0x58, 0xB0, 0x2D, 0xFD, 0x54, 0x98, 0xBD, 0xE1, 0x03, 0x75, 0x89, 0xC9, 0x5F, 0x36, 0x83, 0xFC, 0x89, 0x21, 0x56, 0xC1, 0x24, 0x02, 0x5D, 0x32, 0x69, 0x20, 0xDD, 0xC0, 0x8D, 0x8A, 0x76, 0x91, 0x89, 0x5E, 0xC4, 0x2F, 0x13, 0x8C, 0xC9, 0xEA, 0x01, 0xE7, 0xF2, 0x3D, 0x75, 0x5D, 0x87, 0x0F, 0x31, 0x61, 0xEA, 0xBB, 0x7B, 0xE6, 0xD2, 0xDB, 0xE5, 0x4B, 0x37, 0xC4, 0x51, 0x61, 0xC2, 0xF5, 0x4B, 0x97, 0x91, 0x85, 0xC4, 0x22, 0x4B, 0x19, 0xB9, 0x06, 0xDE, 0x6B, 0x62, 0x4C, 0xCE, 0x07, 0xFD, 0x14, 0x7D, 0x42, 0xAA, 0xE4, 0x17, 0xBB, 0x84, 0x6D, 0x2A, 0x1C, 0xE0, 0x7D, 0x60, 0x7E, 0xE5, 0x76, 0xC4, 0xC4, 0xD2, 0x99, 0x99, 0x37, 0x82, 0x4A, 0xA9, 0x26, 0xCD, 0xE6, 0x0D, 0x1E, 0xD4, 0x70, 0x89, 0x68, 0x49, 0x36, 0x99, 0x40, 0x6A, 0x2D, 0x87, 0x90, 0xA6, 0xF0, 0x49, 0xE3, 0x02, 0x72, 0x28, 0xB8, 0x45, 0x15, 0x2F, 0xD8, 0x51, 0x3B, 0x97, 0xAF, 0x65, 0xA7, 0x57, 0x5A, 0xF3, 0x56, 0x31, 0x17, 0x4A, 0xFC, 0x63, 0x70, 0x7A, 0x6D, 0x1E, 0x14, 0x98, 0x4A, 0xA1, 0x19, 0xD6, 0xEB, 0x63, 0xC9, 0x26, 0x59, 0xD1, 0x92, 0x4A, 0xD2, 0x97, 0xAA, 0xB3, 0x38, 0x4A, 0x4E, 0x40, 0x4C, 0x8C, 0xD7, 0x12, 0x6F, 0x41, 0x3F, 0x59, 0x50, 0xE6, 0x94, 0x98, 0x7A, 0x0A, 0xD1, 0xEE, 0x8D, 0xDD, 0xC9, 0x71, 0x56, 0x6F, 0x88, 0xCF, 0x8D, 0x2A, 0x54, 0xCC, 0x4B, 0x9A, 0xB3, 0x7B, 0xAB, 0xD4, 0x2C, 0x25, 0x78, 0xED, 0x2B, 0xD1, 0xC4, 0xB4, 0xD2, 0x25, 0x20, 0xBF, 0x9C, 0xBB, 0xD5, 0x22, 0x8D, 0x0E, 0xE4, 0x25, 0x1B, 0xDD, 0xA5, 0xF6, 0xF1, 0x5E, 0x89, 0x4E, 0xEA, 0x52, 0x13, 0x97, 0x10, 0x9D, 0xE9, 0x66, 0x49, 0xAF, 0x38, 0x02, 0xD5, 0xE8, 0x94, 0xA1, 0x51, 0x88, 0xDC, 0x30, 0x6D, 0xDE, 0x6E, 0x4F, 0x49, 0x2A, 0x27, 0x7F, 0x1D, 0x24, 0xC4, 0xB8, 0x3D, 0x8B, 0xF5, 0xFC, 0x79, 0xBC, 0x2C, 0x8B, 0x2D, 0xF4, 0x2C, 0x60, 0xB4, 0xF1, 0x04, 0xCA, 0x05, 0x58, 0x2A, 0x5A, 0xA5, 0x75, 0xE5, 0x3E, 0x23, 0x66, 0xA9, 0x5F, 0x00, 0x33, 0x53, 0x3D, 0x94, 0xB3, 0x01, 0x36, 0x62, 0x97, 0x2C, 0x18, 0x0C, 0xDE, 0x55, 0x27, 0x7E, 0x08, 0x2A, 0xD7, 0x2D, 0x11, 0xCE, 0x07, 0x99, 0xC5, 0x2C, 0x33, 0x00, 0xFC, 0xB1, 0x48, 0xA6, 0x1E, 0x02, 0xF9, 0xC6, 0xBE, 0xD4, 0x54, 0x80, 0x27, 0xDC, 0x95, 0xBE, 0x19, 0xBB, 0x83, 0x7F, 0x57, 0xF5, 0xE3, 0xDE, 0xC9, 0xB4, 0xFC, 0x2C, 0x3E, 0xE6, 0xA0, 0x52, 0x8A, 0x63, 0xCD, 0x3B, 0xC5, 0x62, 0x4F, 0xB4, 0x7B, 0xAD, 0xAB, 0x60, 0x00, 0x49, 0x5C, 0x62, 0xC8, 0x94, 0x42, 0x9B, 0x2C, 0x2E, 0x51, 0xBD, 0xA0, 0x85, 0xB1, 0x9C, 0xFC, 0x0A, 0x14, 0xB3, 0x89, 0x1A, 0x3F, 0x81, 0x17, 0xFA, 0x45, 0xF9, 0x9B, 0x0D, 0x49, 0x0A, 0x96, 0xCF, 0x67, 0xFE, 0x3B, 0x98, 0x28, 0xB9, 0x48, 0x2B, 0x77, 0x54, 0x8B, 0xCA, 0xC9, 0x7F, 0x6B, 0x52, 0x05, 0x21, 0x38, 0xB9, 0x64, 0x34, 0x93, 0x02, 0xD7, 0x5B, 0x3C, 0xA5, 0xCA, 0x40, 0x9D, 0x71, 0x05, 0xF9, 0x0C, 0x68, 0xE0, 0xCF, 0x54, 0x1F, 0x51, 0x38, 0x23, 0x03, 0xCA, 0xB9, 0xB2, 0xD5, 0x89, 0x0D, 0xB2, 0x08, 0x49, 0xE8, 0x81, 0x74, 0x49, 0xA2, 0xC8, 0x79, 0xC7, 0x48, 0xD1, 0x32, 0x36, 0x77, 0xCD, 0x78, 0xF6, 0x0C, 0x75, 0x7F, 0xF1, 0x34, 0x66, 0x06, 0xBA, 0xD1, 0x82, 0x43, 0x61, 0xD0, 0x78, 0xE3, 0x04, 0xF2, 0x0A, 0x50, 0x4D, 0xED, 0x56, 0xCF, 0xCE, 0x78, 0x0C, 0x9B, 0x2B, 0x82, 0xB5, 0x5F, 0x13, 0xDA, 0xA4, 0x27, 0x35, 0x1B, 0xC2, 0x8B, 0xC5, 0xA7, 0x14, 0xAF, 0xB7, 0xD7, 0x08, 0xCB, 0x24, 0xBD, 0x6B, 0x46, 0xB0, 0xEB, 0x58, 0xEF, 0x45, 0x3E, 0x74, 0x07, 0x76, 0xCE, 0x7C, 0x80, 0xF2, 0x87, 0x52, 0x8D, 0x1E, 0x93, 0x6D, 0x80, 0x9E, 0x12, 0xA8, 0x1E, 0xE4, 0xDF, 0x85, 0x7B, 0xE5, 0x3F, 0x73, 0x37, 0x25, 0x74, 0x4B, 0xA3, 0xB3, 0xDE, 0xED, 0xFF, 0x26, 0x5E, 0xA2, 0x95, 0x6C, 0x37, 0x16, 0x2E, 0x54, 0x4E, 0xF3, 0x0E, 0x63, 0xA7, 0x09, 0xBF, 0x2F, 0x04, 0x69, 0x3D, 0xFE, 0xD9, 0xDC, 0x89, 0x72, 0x86, 0x7A, 0x8C, 0x12, 0xC8, 0x5C, 0x40, 0x44, 0xE7, 0xAA, 0xF6, 0x55, 0xCC, 0x87, 0xDE, 0xCA, 0xB7, 0x96, 0x64, 0x25, 0x99, 0x49, 0x2E, 0x14, 0x18, 0x86, 0xFF, 0x15, 0x9D, 0xC9, 0x8E, 0xD9, 0xD6, 0x29, 0x78, 0xA5, 0xB9, 0xB2, 0xDA, 0x88, 0x9D, 0x29, 0xFE, 0xEC, 0xB8, 0x9E, 0xEE, 0x23, 0xCE, 0x9A, 0xB5, 0x51, 0x8B, 0xA0, 0xEF, 0x46, 0x0E, 0x24, 0x0B, 0x80, 0x28, 0xB7, 0xA8, 0x2A, 0xE6, 0x76, 0xAA, 0x4F, 0xFE, 0x9A, 0xC3, 0xFF, 0x45, 0xDF, 0xC9, 0x7E, 0x13, 0x9F, 0x1C, 0xF2, 0x5C, 0xA7, 0x4A, 0x64, 0xFC, 0x4F, 0xA9, 0x0F, 0x25, 0xEF, 0xF4, 0x3C, 0x2E, 0x6B, 0x4F, 0xCD, 0x75, 0x34, 0x17, 0xFC, 0xE5, 0x34, 0x9B, 0x4D, 0x62, 0x68, 0xDE, 0x24, 0x43, 0x6F, 0x7A, 0x02, 0xAF, 0x00, 0x96, 0x16, 0xA6, 0x24, 0x08, 0x52, 0x3E, 0xE5, 0xBE, 0x4B, 0xB2, 0x88, 0xD1, 0x67, 0xB5, 0x26, 0xC7, 0x86, 0x54, 0x6A, 0x7B, 0x52, 0xDE, 0xF8, 0x1F, 0x52, 0x1D, 0x4D, 0x0B, 0xF6, 0xC2, 0x64, 0x4B, 0x38, 0x84, 0xC3, 0x6B, 0x81, 0x8A, 0x7B, 0xD4, 0x6C, 0x2A, 0xE3, 0xCF, 0xE3, 0x19, 0xC6, 0x51, 0xEF, 0x78, 0x27, 0xC0, 0xF7, 0x05, 0x72, 0x8E, 0x5B, 0x8A, 0x8D, 0xFE, 0x3D, 0x97, 0x1B, 0xB3, 0x28, 0x93, 0xE6, 0x7E, 0xD9, 0x7B, 0x31, 0xFD, 0x31, 0x0F, 0xF0, 0xCB, 0x53, 0xAD, 0x00, 0xC6, 0x7A, 0x01, 0xD2, 0x6A, 0xC0, 0xCA, 0x71, 0x88, 0xC0, 0x15, 0x18, 0x69, 0xE6, 0xC6, 0x18, 0xF2, 0x3E, 0x18, 0x96, 0x50, 0xE7, 0x79, 0x83, 0xBC, 0x97, 0xF9, 0x22, 0x24, 0x27, 0xB9, 0x4D, 0x3F, 0x05, 0x39, 0x15, 0x65, 0x95, 0xF1, 0x17, 0xC9, 0x0B, 0xB6, 0x49, 0x5F, 0x85, 0x24, 0x6F, 0xF1, 0x52, 0x52, 0xF0, 0x63, 0x8F, 0x57, 0xD2, 0x35, 0xD0, 0x5D, 0x87, 0x5F, 0x82, 0x61, 0xE0, 0x1A, 0xB3, 0x18, 0xFA, 0x1B, 0xB0, 0xCF, 0xF0, 0x1E, 0x55, 0xCB, 0xFB, 0xC7, 0x7B, 0x95, 0xE7, 0x4E, 0x3F, 0x4B, 0x94, 0xE7, 0x0C, 0xA5, 0x5D, 0x23, 0xF6, 0x67, 0x2C, 0xA2, 0xC2, 0xF7, 0x68, 0x35, 0x72, 0x72, 0xDB, 0xE6, 0x52, 0xC5, 0x0D, 0xBC, 0xDB, 0xFD, 0xB4, 0xE4, 0x39, 0xAA, 0x74, 0x50, 0xB0, 0x03, 0x10, 0x6D, 0xB6, 0x8D, 0xBE, 0x02, 0x1C, 0x33, 0x7C, 0x4E, 0xA9, 0x81, 0x11, 0x3C, 0x59, 0xEE, 0x62, 0xF1, 0xEF, 0xC4, 0xAA, 0xEC, 0xE9, 0xA2, 0xFF, 0x0E, 0xA2, 0xBA, 0xC3, 0x42, 0xFF, 0xA0, 0x56, 0xCD, 0x52, 0xD6, 0x6B, 0xF3, 0x18, 0x85, 0x84, 0xBE, 0xEC, 0x0E, 0x48, 0xA4, 0x44, 0x92, 0xFD, 0x77, 0x16, 0x84, 0x6F, 0x98, 0xFE, 0xA3, 0xCB, 0x41, 0x23, 0xC3, 0x26, 0x0A, 0xE4, 0x7D, 0x4B, 0xCB, 0xD7, 0xAF, 0xD7, 0xAC, 0x8F, 0xDF, 0x93, 0x15, 0xA0, 0xFA, 0x1C, 0xDE, 0xAB, 0x9B, 0xA0, 0x70, 0x0B, 0x5A, 0xA3, 0xD6, 0x49, 0xED, 0x36, 0x2B, 0xE5, 0xAF, 0x84, 0x90, 0x07, 0x57, 0xFC, 0x90, 0xCE, 0xB0, 0x2F, 0x67, 0xCD, 0x51, 0x07, 0x53, 0x2D, 0x0D, 0xFF, 0x8F, 0x41, 0xB2, 0x70, 0x68, 0x72, 0xD1, 0xC3, 0xB0, 0x7A, 0xEC, 0xF6, 0x98, 0x08, 0x0B, 0x46, 0x4B, 0x77, 0x37, 0x48, 0x77, 0x77, 0x6E, 0x63, 0xDD, 0xFB, 0x72, 0xFB, 0x62, 0xC5, 0x18, 0xDD, 0x21, 0x20, 0x82, 0x28, 0x76, 0x77, 0xC7, 0xB5, 0x8E, 0xDD, 0xDD, 0x79, 0xEC, 0x6E, 0xEF, 0xF9, 0x03, 0x9E, 0x5F, 0x3C, 0xEF, 0x8B, 0x88, 0xA8, 0x59, 0xDA, 0x52, 0xE8, 0xBA, 0x72, 0x45, 0xDF, 0xE6, 0xDE, 0x85, 0xE2, 0x85, 0x3D, 0x96, 0xDD, 0x6B, 0x2B, 0x77, 0x77, 0xD4, 0x74, 0x24, 0xE6, 0x35, 0xB6, 0xBC, 0x6E, 0xC9, 0x48, 0x5C, 0xDF, 0x08, 0xD4, 0x4B, 0x83, 0x77, 0xD7, 0x2E, 0xAF, 0x5E, 0xE8, 0x94, 0x59, 0x3D, 0x16, 0xF7, 0x64, 0x14, 0xE8, 0xCA, 0x90, 0x15, 0x54, 0xBA, 0x36, 0x0A, 0xDA, 0xA9, 0x64, 0xF4, 0xCD, 0x1D, 0x62, 0x88, 0x4B, 0xBB, 0xBD, 0x07, 0xA6, 0x33, 0xC7, 0xB5, 0x3F, 0x59, 0xF2, 0x30, 0xCF, 0xAF, 0xE5, 0x54, 0xC7, 0x9B, 0x84, 0x9E, 0xC6, 0x55, 0xCD, 0x94, 0x40, 0x55, 0xED, 0x5B, 0xE3, 0x43, 0xA7, 0xD0, 0x6A, 0x07, 0x62, 0x14, 0x23, 0x55, 0x97, 0x85, 0x9C, 0xA3, 0xFE, 0xAD, 0xB5, 0x83, 0x7A, 0x45, 0x57, 0x36, 0xBC, 0xE4, 0xAE, 0x65, 0xFD, 0x5C, 0xD3, 0xC9, 0x7B, 0x50, 0x44, 0x1B, 0x3E, 0x25, 0x34, 0xCF, 0xF8, 0x31, 0x50, 0x29, 0x3A, 0x10, 0xD3, 0xDD, 0xF3, 0x4E, 0xD2, 0xE2, 0xBF, 0xB4, 0xCD, 0x41, 0xF6, 0xD9, 0xC1, 0xAB, 0xF6, 0xAE, 0x72, 0x27, 0xED, 0x6A, 0xF5, 0x44, 0xB0, 0xDC, 0xFC, 0xAE, 0xEE, 0x1B, 0x64, 0x26, 0xB4, 0x5B, 0x8F, 0x89, 0xB4, 0xAC, 0x6F, 0xAB, 0xF9, 0x62, 0xA8, 0x68, 0xFE, 0xB0, 0x9D, 0xE4, 0x63, 0xC6, 0xD8, 0xA5, 0x97, 0x65, 0x99, 0x31, 0x4E, 0x3D, 0x96, 0xF2, 0x65, 0xFE, 0xCB, 0x5A, 0xFB, 0x14, 0x4F, 0x1D, 0xF2, 0x6A, 0x0D, 0xC0, 0x52, 0xFA, 0x78, 0xC3, 0x2D, 0x70, 0xAD, 0xC5, 0x4C, 0xDD, 0x03, 0x88, 0xCA, 0xBB, 0xBB, 0x2E, 0x4B, 0xD1, 0xCF, 0x3C, 0xBF, 0x2A, 0x4E, 0x99, 0x54, 0xE0, 0xBC, 0xBC, 0x4B, 0x79, 0x28, 0x4D, 0xB5, 0x34, 0x0A, 0x90, 0x2F, 0xF6, 0xEC, 0x06, 0x40, 0xAA, 0xFF, 0x50, 0xCB, 0x4B, 0x10, 0x72, 0x10, 0xD6, 0x32, 0xC0, 0xB3, 0x74, 0x6B, 0xC3, 0x1A, 0x68, 0x82, 0x85, 0x9F, 0xEE, 0x04, 0x44, 0xE3, 0x2F, 0x5A, 0x4B, 0x45, 0x1B, 0x2B, 0xCF, 0x8F, 0x70, 0x50, 0x55, 0x7E, 0xE0, 0xD0, 0x46, 0x34, 0x2D, 0xD5, 0xB9, 0xBF, 0x12, 0xF9, 0x19, 0xAD, 0xEF, 0xEA, 0x44, 0x56, 0xFA, 0xDD, 0x6A, 0x09, 0x87, 0x7F, 0x3A, 0x4C, 0x36, 0x9D, 0x82, 0xBE, 0xD3, 0xE7, 0x18, 0x70, 0xA8, 0xC4, 0x22, 0x59, 0xB7, 0x0E, 0xA2, 0xF2, 0x1B, 0x56, 0x7F, 0x23, 0x1F, 0x54, 0x4C, 0x59, 0x39, 0x40, 0x96, 0xE6, 0x8F, 0x19, 0xCC, 0x23, 0x0E, 0xA5, 0xB6, 0xF6, 0x45, 0xE3, 0x23, 0xD1, 0x1E, 0x9D, 0x17, 0x31, 0x2B, 0x5F, 0x69, 0xF3, 0x03, 0x55, 0xB8, 0xBD, 0xC8, 0x64, 0x42, 0xA6, 0xD1, 0x5E, 0x1B, 0x32, 0xA0, 0x0D, 0x16, 0x99, 0xBA, 0x1A, 0x68, 0x21, 0x7F, 0xCB, 0xAA, 0x1F, 0xC6, 0x88, 0x4A, 0xFE, 0x8A, 0x90, 0xEA, 0xA1, 0xFC, 0x9C, 0x65, 0xD1, 0x86, 0xE2, 0xD4, 0xEC, 0xDE, 0x21, 0x5D, 0x60, 0xD4, 0xE6, 0xCE, 0x12, 0x72, 0xA7, 0x8F, 0x5D, 0xF3, 0x36, 0xAC, 0xCD, 0x7E, 0xB2, 0x29, 0x0D, 0xA5, 0xD2, 0x2E, 0x18, 0xAC, 0xA0, 0xAF, 0xFF, 0xED, 0x2A, 0x85, 0x26, 0x73, 0x45, 0xAB, 0x86, 0x9A, 0xE8, 0xE5, 0xC7, 0x57, 0x94, 0x34, 0xEC, 0xCF, 0x9B, 0xB8, 0xCC, 0xAA, 0xCE, 0x2E, 0xE5, 0x4C, 0xAF, 0x47, 0x4D, 0x6C, 0xD4, 0xC7, 0x8E, 0xFF, 0xE9, 0x6F, 0xF9, 0x76, 0x36, 0xCF, 0x22, 0x57, 0xDA, 0x27, 0x9B, 0x46, 0xA9, 0xD2, 0x69, 0xD7, 0xF5, 0xAF, 0x60, 0x7F, 0x8B, 0x04, 0x9D, 0x17, 0xF8, 0x8C, 0x53, 0xBF, 0x8A, 0xD5, 0xC9, 0x2D, 0x67, 0x0C, 0xFF, 0x68, 0xA7, 0xE4, 0x34, 0x2E, 0x5B, 0xDC, 0x1C, 0x94, 0x32, 0x69, 0xC9, 0xCA, 0xFA, 0xF5, 0x51, 0x70, 0x07, 0xAB, 0xA6, 0xC0, 0xB7, 0xB3, 0x69, 0x93, 0xF6, 0x99, 0xFD, 0xCE, 0x9A, 0xDD, 0xEA, 0x30, 0xBA, 0x9D, 0x7E, 0x37, 0x5C, 0x65, 0xA1, 0xD1, 0x4D, 0x02, 0x8F, 0x71, 0x0E, 0x8F, 0xAC, 0xEC, 0xEB, 0x2F, 0xD7, 0x2F, 0xAF, 0xED, 0xE9, 0xCF, 0xFE, 0x3E, 0xB0, 0xB2, 0x1D, 0x49, 0x3A, 0xBB, 0x44, 0xD9, 0xEC, 0x10, 0xF1, 0xA9, 0xE3, 0x69, 0x9D, 0xA7, 0xF7, 0xB5, 0x26, 0xA5, 0x7E, 0xA6, 0x43, 0x45, 0x8D, 0x4A, 0x7D, 0x9F, 0xBE, 0x41, 0x5F, 0x0B, 0x9B, 0x2C, 0xEE, 0x6A, 0x1F, 0x80, 0xEB, 0x2A, 0x07, 0x77, 0xAA, 0xB8, 0xBD, 0x45, 0x47, 0xB7, 0xA6, 0xF2, 0xDA, 0x32, 0xF1, 0xF5, 0x3C, 0x81, 0x43, 0xC2, 0x84, 0x91, 0x12, 0xE1, 0x94, 0x50, 0xE6, 0xB2, 0x5D, 0x62, 0x99, 0x57, 0x52, 0x57, 0x9A, 0xB4, 0xC5, 0xBA, 0xA0, 0xE1, 0x5F, 0x85, 0xD6, 0xA2, 0xD4, 0xB8, 0x1B, 0x68, 0x35, 0x9B, 0x6B, 0x98, 0x0C, 0x22, 0x95, 0x2F, 0x76, 0x9C, 0x11, 0x99, 0x17, 0xE1, 0x5B, 0x92, 0x44, 0x3D, 0x19, 0xF9, 0xEB, 0x3E, 0x8A, 0x6B, 0xE2, 0x8C, 0x23, 0xE3, 0x24, 0x1D, 0xA1, 0x63, 0x96, 0x4D, 0x96, 0x3E, 0xF3, 0x14, 0x74, 0xAD, 0x95, 0xF3, 0xAD, 0xCF, 0x34, 0x60, 0x4A, 0xD4, 0x62, 0xAF, 0x91, 0x00, 0x4E, 0x9B, 0x95, 0xE8, 0x3F, 0x80, 0xA5, 0x4C, 0x70, 0x7B, 0x9C, 0xDC, 0x50, 0x74, 0x73, 0xF3, 0x58, 0xB9, 0x3C, 0xBD, 0x65, 0x5D, 0x90, 0xFC, 0x7A, 0x5C, 0xF1, 0x4A, 0x4B, 0x85, 0x2E, 0x74, 0xDA, 0xC0, 0x38, 0xE5, 0x04, 0x4F, 0xDB, 0xCE, 0xFB, 0xCA, 0xCD, 0xD6, 0xDD, 0x0D, 0x93, 0x00, 0xE3, 0x7F, 0x54, 0x3A, 0x38, 0xD1, 0x0C, 0xD5, 0x3F, 0x06, 0x43, 0x2B, 0xCC, 0xB7, 0xFE, 0x81, 0xF7, 0x17, 0x4D, 0xDF, 0x78, 0x09, 0x9E, 0x92, 0x7E, 0x6B, 0xCD, 0x3F, 0x70, 0x70, 0x1C, 0x38, 0x7C, 0x1F, 0x3A, 0x13, 0x5A, 0xD7, 0xBF, 0x0B, 0xCA, 0xF2, 0xCC, 0xEF, 0x48, 0x80, 0xC6, 0x5A, 0xDD, 0xAD, 0x6F, 0x03, 0xBB, 0xFF, 0xBB, 0xD0, 0x09, 0x8C, 0x32, 0x2B, 0xD0, 0x5F, 0x01, 0x2D, 0x2B, 0xCC, 0xB7, 0x7C, 0xC2, 0x6F, 0x16, 0x9C, 0xD8, 0x38, 0x1E, 0xEB, 0x4B, 0x7F, 0xB1, 0x1A, 0x51, 0x6F, 0x8E, 0x95, 0x2C, 0x7F, 0xAC, 0xFA, 0x12, 0x32, 0xBD, 0xDF, 0x16, 0x7D, 0xE6, 0xD1, 0xD1, 0xBE, 0x07, 0x29, 0xB0, 0x12, 0xD5, 0xC7, 0x41, 0xAB, 0x2C, 0x92, 0xAA, 0x3F, 0x81, 0x26, 0x33, 0xAE, 0x7E, 0x15, 0xF8, 0x77, 0x05, 0xB8, 0xB9, 0xDB, 0xF0, 0xBA, 0x90, 0xB1, 0xBE, 0x47, 0x77, 0x37, 0xBD, 0x63, 0x95, 0x97, 0xA6, 0x25, 0x76, 0xFC, 0xD0, 0x73, 0xD2, 0x2B, 0xD8, 0xA7, 0xAF, 0x1E, 0x2F, 0x75, 0xB7, 0xED, 0x98, 0xA9, 0xFA, 0x9F, 0x55, 0x77, 0xFD, 0x24, 0xB8, 0xC3, 0xC2, 0x54, 0xBD, 0x11, 0x3C, 0x66, 0xB6, 0x4C, 0x5F, 0x05, 0x8E, 0x2D, 0x8B, 0xD9, 0x74, 0xA3, 0xFE, 0x59, 0xFE, 0xD5, 0xF5, 0x39, 0xB5, 0x07, 0xD2, 0xFD, 0x46, 0x3A, 0x8C, 0x6F, 0x63, 0xDF, 0x0F, 0x7E, 0x33, 0xCC, 0x0B, 0x59, 0xD5, 0xDB, 0xA1, 0x79, 0xE5, 0x3E, 0xB5, 0xFD, 0x34, 0x1E, 0x63, 0x3D, 0xA5, 0xEE, 0x04, 0xD2, 0x4B, 0x99, 0x5C, 0xCD, 0x86, 0xFE, 0x5A, 0x68, 0xA1, 0xB7, 0x00, 0xFE, 0x2D, 0xB9, 0xB5, 0xE9, 0x77, 0x6B, 0x4D, 0x9E, 0x60, 0x7D, 0x44, 0x33, 0x2B, 0xAD, 0x72, 0x64, 0x45, 0xFD, 0x97, 0xD8, 0x0F, 0x83, 0xED, 0x26, 0xB7, 0x90, 0x8F, 0xBD, 0x29, 0xFA, 0x23, 0x1E, 0xA3, 0xDA, 0x25, 0xE4, 0x6C, 0xEB, 0x4F, 0x75, 0x1C, 0x94, 0xA4, 0x9C, 0xAE, 0x5E, 0x00, 0xF9, 0x2D, 0x3C, 0xA9, 0xBB, 0x0C, 0x5C, 0x2C, 0x39, 0xB8, 0x39, 0xB7, 0x3B, 0x2B, 0xAF, 0x7C, 0x5D, 0x68, 0x87, 0x21, 0x25, 0x6D, 0xC4, 0xD4, 0x7C, 0x67, 0xF1, 0xB1, 0xC1, 0xBA, 0xFA, 0xE5, 0x41, 0xB2, 0x5E, 0x81, 0x71, 0xB6, 0x7B, 0x79, 0xDB, 0x7B, 0xCD, 0x04, 0x9B, 0xE7, 0xB5, 0xEF, 0x54, 0x5E, 0xD4, 0x75, 0x86, 0xE3, 0x10, 0xD3, 0xBC, 0x41, 0xD7, 0x0E, 0x1C, 0x3C, 0xE0, 0xC6, 0x5F, 0x5D, 0x12, 0xB4, 0xB1, 0x40, 0x64, 0x55, 0x09, 0xF4, 0x51, 0x24, 0x6D, 0x9C, 0xEA, 0xEA, 0x3A, 0xD9, 0x73, 0xE1, 0x3C, 0xA9, 0x5C, 0xB9, 0x58, 0x42, 0xE6, 0x9E, 0x83, 0xC2, 0x14, 0x73, 0x83, 0x12, 0xD0, 0xAB, 0xC0, 0x65, 0xC7, 0xBD, 0xD8, 0x54, 0x28, 0xD6, 0x7A, 0x00, 0xFB, 0x05, 0xFD, 0xBB, 0xFB, 0x4F, 0xD5, 0x4A, 0xFE, 0xAC, 0x75, 0x9F, 0xF9, 0xB6, 0x22, 0xC7, 0x25, 0xAB, 0x44, 0xE5, 0x12, 0xAE, 0xFE, 0x82, 0x94, 0x90, 0x5B, 0x88, 0x9B, 0x14, 0xA1, 0x4A, 0xB3, 0xEC, 0x5E, 0xD0, 0x00, 0xA6, 0x05, 0x9C, 0x42, 0xF9, 0xD0, 0x86, 0x45, 0x37, 0xD5, 0xE7, 0xE0, 0x42, 0xEB, 0x99, 0xD8, 0x35, 0x78, 0x78, 0xD7, 0x68, 0xA6, 0x25, 0x74, 0x7B, 0xAD, 0x84, 0xB3, 0x18, 0x96, 0x74, 0x9D, 0x14, 0x10, 0xF0, 0x1F, 0x9D, 0xB3, 0xF8, 0x05, 0x12, 0x2A, 0x8C, 0x90, 0xBB, 0x22, 0x87, 0x33, 0x3A, 0x81, 0x3B, 0xA8, 0xB9, 0xFF, 0x01, 0xE4, 0x2B, 0x32, 0xB2, 0x28, 0x50, 0xDD, 0x82, 0x48, 0xAD, 0x1A, 0xB0, 0xAD, 0x48, 0xC1, 0x8E, 0x84, 0x8A, 0x05, 0x3A, 0xCD, 0xC8, 0x25, 0xB6, 0xB9, 0x76, 0x4F, 0x47, 0x34, 0x8F, 0xD0, 0xD4, 0x6A, 0x1E, 0x8A, 0x28, 0xA4, 0x46, 0x00, 0x4B, 0x3F, 0x12, 0x11, 0x99, 0x42, 0x60, 0x2E, 0x36, 0xE0, 0x0F, 0x22, 0xFD, 0xAA, 0x25, 0x0E, 0xD7, 0xD4, 0x5C, 0xB4, 0xD4, 0xCA, 0x11, 0x5B, 0x8A, 0x5C, 0xDB, 0x36, 0x54, 0x86, 0x36, 0x7A, 0x8E, 0xD8, 0x30, 0x85, 0xF5, 0xF3, 0xDA, 0xAD, 0xB8, 0x0E, 0xA6, 0x16, 0x4D, 0xAE, 0xE0, 0x94, 0xD1, 0x9A, 0x3F, 0x41, 0xF2, 0x48, 0x7F, 0x22, 0x7D, 0x99, 0x12, 0xD2, 0xF0, 0xFD, 0xA3, 0x91, 0x7C, 0xAC, 0xD3, 0x61, 0xAB, 0x3A, 0x5D, 0x65, 0xCB, 0xF8, 0x83, 0x75, 0xA3, 0x66, 0x5B, 0x73, 0x4B, 0xDB, 0x7B, 0x66, 0xAC, 0xFC, 0x58, 0x19, 0xD8, 0x39, 0xAD, 0x63, 0x72, 0x95, 0xA1, 0xD5, 0x59, 0x63, 0xCB, 0x1F, 0x6C, 0x8C, 0xE5, 0x15, 0x48, 0xFE, 0xAA, 0x73, 0x48, 0xB3, 0x56, 0x0C, 0x18, 0x7E, 0xF8, 0x97, 0x23, 0x93, 0x88, 0xED, 0x0E, 0xFB, 0xD5, 0x51, 0xAA, 0xC7, 0x56, 0x63, 0xB0, 0x15, 0xE8, 0xE2, 0x2D, 0xE2, 0x12, 0xAB, 0xE1, 0x03, 0xCB, 0xEB, 0x2B, 0x8C, 0x83, 0xF3, 0x5A, 0xC3, 0xD8, 0x9B, 0x7A, 0x5F, 0x10, 0x41, 0xBC, 0x53, 0x5D, 0x49, 0xBC, 0x4E, 0xF1, 0xD8, 0xD6, 0xDC, 0x74, 0xAA, 0x7C, 0x7F, 0x5D, 0x90, 0x7F, 0x3E, 0xBC, 0x4D, 0x6B, 0xE3, 0x70, 0x5D, 0x1D, 0xA1, 0x3E, 0x66, 0x15, 0x86, 0x1D, 0x45, 0xC9, 0x4D, 0x77, 0x8A, 0x8D, 0x1B, 0xFE, 0x0C, 0x25, 0x97, 0xEB, 0xD7, 0xCC, 0x6B, 0x7A, 0xCD, 0xBA, 0x36, 0xCC, 0xC1, 0xAE, 0xF0, 0x26, 0x2E, 0x5D, 0xC7, 0x25, 0x44, 0x05, 0xDD, 0x16, 0xE9, 0x15, 0xF2, 0x88, 0x26, 0xA1, 0xDF, 0x2E, 0x58, 0xA2, 0x77, 0x5E, 0xB4, 0x50, 0x1D, 0x83, 0xB5, 0x5A, 0xDD, 0xC3, 0x5E, 0xA1, 0xC7, 0x36, 0xE9, 0x8B, 0x05, 0xBB, 0xE7, 0x0F, 0x8D, 0x2D, 0x3B, 0xBB, 0x35, 0xB2, 0xD9, 0x81, 0x35, 0xBC, 0xCE, 0x02, 0xCF, 0xE5, 0x6E, 0x5A, 0xC1, 0xE7, 0x70, 0x45, 0x66, 0xFD, 0xC1, 0xA9, 0x53, 0xE5, 0x21, 0xAD, 0x45, 0x7E, 0x23, 0x30, 0xD5, 0xB0, 0x62, 0xD1, 0x5B, 0x75, 0x06, 0xEE, 0x6F, 0x7D, 0x11, 0xA7, 0xA9, 0x26, 0xED, 0x48, 0x90, 0x5D, 0x2E, 0x79, 0x3C, 0x02, 0xC9, 0x1F, 0x55, 0xBE, 0x6E, 0xCF, 0x51, 0x7A, 0x70, 0x99, 0xC4, 0x0F, 0x60, 0x93, 0xB0, 0x47, 0x20, 0x81, 0x52, 0xA5, 0x11, 0x59, 0x62, 0xA4, 0x58, 0xE1, 0x1F, 0x78, 0x52, 0x4D, 0x01, 0x8E, 0x39, 0x4E, 0xC4, 0xA7, 0x42, 0xE3, 0xAD, 0x6E, 0xE0, 0x77, 0xA0, 0xD6, 0xCD, 0xF1, 0xE2, 0x4E, 0xFE, 0xB2, 0xE5, 0x6F, 0xA5, 0x98, 0x88, 0xD2, 0xFA, 0x4E, 0x2E, 0x96, 0xEC, 0x20, 0x8C, 0xCA, 0x4C, 0xF9, 0x7C, 0xBE, 0x15, 0x18, 0xA4, 0x5C, 0x9C, 0xF1, 0x0E, 0x5E, 0x07, 0xBA, 0xF9, 0x8B, 0x54, 0xFF, 0x40, 0x5D, 0x0E, 0x5F, 0xB0, 0x63, 0xB0, 0xBB, 0x55, 0x3E, 0xBE, 0x0C, 0x16, 0x6E, 0xEC, 0x13, 0x94, 0x80, 0xE0, 0x10, 0x5F, 0xF4, 0x09, 0xFC, 0xD9, 0x7C, 0x49, 0xDA, 0x0C, 0xC7, 0xE1, 0x33, 0xE5, 0x0F, 0x11, 0x33, 0xEE, 0x7A, 0x60, 0x3C, 0xC2, 0x4C, 0xD3, 0xC1, 0x63, 0x90, 0xD5, 0x7E, 0x22, 0x55, 0x31, 0x62, 0x72, 0xE0, 0x61, 0x3A, 0x24, 0x99, 0xF1, 0x11, 0x97, 0x23, 0xEE, 0xEB, 0x30, 0xDE, 0x56, 0x4D, 0xE2, 0xB2, 0x72, 0x41, 0x2B, 0xD9, 0xDB, 0x38, 0x2C, 0xEE, 0x20, 0x33, 0x54, 0xCF, 0x65, 0xF9, 0xC4, 0x6E, 0x0E, 0x4D, 0x39, 0x0E, 0xDF, 0x93, 0x56, 0x0B, 0x05, 0x61, 0x59, 0x7E, 0x6D, 0xAA, 0xF1, 0x2A, 0x9E, 0x43, 0x28, 0x56, 0x84, 0x7A, 0x32, 0xD6, 0xE3, 0x25, 0xC8, 0x9A, 0xB5, 0x1B, 0x39, 0x9C, 0xDA, 0x13, 0xFD, 0x23, 0x7C, 0x57, 0xD3, 0x81, 0xFA, 0xF9, 0xA2, 0xA2, 0x1A, 0x47, 0x74, 0xB5, 0x94, 0x51, 0x1D, 0x54, 0xB5, 0x59, 0xFE, 0x47, 0x3F, 0x35, 0x4D, 0x02, 0x12, 0x1A, 0x7B, 0x3F, 0x4F, 0xF4, 0x00, 0x16, 0xEF, 0x30, 0x1E, 0x8B, 0x41, 0x5F, 0x33, 0x6A, 0xF0, 0x22, 0xE4, 0xDF, 0x35, 0xDD, 0x55, 0xE5, 0x1D, 0xEE, 0x7D, 0x6A, 0xDE, 0x9C, 0x36, 0x41, 0xDD, 0x6D, 0xA1, 0x63, 0x33, 0x84, 0x32, 0x24, 0xB3, 0x1A, 0x4A, 0xAA, 0x16, 0xC9, 0x27, 0xD4, 0xBA, 0xA6, 0xD6, 0x01, 0xA7, 0x0D, 0x90, 0xAF, 0x08, 0x55, 0x13, 0x91, 0xF6, 0xC7, 0xB0, 0x00, 0xD5, 0x12, 0x86, 0x16, 0x67, 0xA2, 0x33, 0x46, 0xC6, 0xB1, 0x33, 0x07, 0x13, 0x7A, 0x17, 0x71, 0xCD, 0x96, 0x5A, 0xD6, 0x5D, 0x16, 0x4C, 0x5A, 0xF2, 0x17, 0xB2, 0x5F, 0xFC, 0x57, 0x87, 0x8A, 0x1D, 0x2E, 0xF3, 0x6F, 0x99, 0x95, 0xEA, 0x02, 0xD8, 0xD4, 0x96, 0xF8, 0xFE, 0x8D, 0xFA, 0x68, 0x54, 0xF6, 0x7B, 0x31, 0x57, 0x75, 0x09, 0x63, 0x18, 0x97, 0xA1, 0xDE, 0x2B, 0x09, 0x56, 0xD1, 0xDA, 0x80, 0x9E, 0x27, 0x9C, 0xC4, 0x91, 0x39, 0xA6, 0x93, 0x7C, 0xC5, 0xE0, 0x6F, 0xD8, 0x46, 0x04, 0xF7, 0x0D, 0xB1, 0xE6, 0x49, 0x0F, 0x77, 0x0A, 0x52, 0x8E, 0x29, 0x77, 0x35, 0x86, 0xFB, 0xBC, 0x47, 0x3E, 0xE8, 0x64, 0x0E, 0xA3, 0x31, 0x06, 0x66, 0x66, 0x45, 0xC1, 0x71, 0x94, 0xBD, 0x62, 0x13, 0x73, 0xC3, 0x36, 0xCF, 0x9E, 0xA9, 0x55, 0xCB, 0x37, 0xF2, 0x4C, 0x01, 0xFC, 0xF9, 0xAB, 0x0F, 0x41, 0xAB, 0x44, 0xF4, 0xE5, 0x36, 0xCC, 0xBB, 0xD2, 0xB4, 0xDE, 0xD2, 0xE4, 0x57, 0x4A, 0x51, 0x8B, 0xDE, 0xE7, 0x23, 0xB2, 0xD5, 0xB0, 0xC0, 0xA1, 0x16, 0x9B, 0x8F, 0xED, 0xB7, 0xBA, 0x83, 0xD7, 0xA3, 0x4B, 0x56, 0x05, 0x23, 0x2F, 0xCB, 0x4E, 0xF7, 0xCD, 0x47, 0x3E, 0x33, 0xAF, 0xD5, 0x8D, 0x41, 0x1E, 0xF2, 0x04, 0xB0, 0x00, 0x4D, 0x15, 0xBE, 0x67, 0x19, 0xD1, 0x5F, 0xD2, 0xCC, 0xD4, 0x4E, 0xF5, 0x54, 0x85, 0x8B, 0x3F, 0x80, 0x6D, 0x01, 0x4E, 0x38, 0x68, 0x08, 0x27, 0xF0, 0x16, 0xE3, 0x28, 0x71, 0x06, 0x4A, 0x5E, 0xE1, 0x0C, 0x45, 0xF1, 0x4F, 0xF7, 0xD4, 0x41, 0xF7, 0x85, 0xAB, 0x6A, 0x23, 0x61, 0xAE, 0xC4, 0x03, 0x3E, 0x8D, 0x38, 0xC8, 0x8E, 0xB2, 0x92, 0x91, 0x0F, 0x4A, 0xBB, 0x94, 0x27, 0x2A, 0x0E, 0x38, 0xCF, 0x37, 0x13, 0x03, 0x21, 0xC8, 0x7E, 0x0B, 0x7E, 0x1F, 0xFE, 0x8B, 0x21, 0x23, 0x30, 0xD8, 0x7F, 0x88, 0xA3, 0x7C, 0x00, 0x84, 0x76, 0xDD, 0x02, 0x8E, 0x01, 0x67, 0xAB, 0x6F, 0x83, 0x7D, 0x50, 0x04, 0xB8, 0x05, 0x3A, 0x05, 0x87, 0x33, 0x7D, 0xE0, 0x67, 0xF0, 0x9F, 0xA4, 0x0B, 0xE8, 0x45, 0x04, 0xF4, 0x59, 0x8D, 0x2D, 0x40, 0x32, 0xED, 0xAB, 0xF0, 0x3E, 0x64, 0x01, 0x23, 0x82, 0x88, 0x83, 0x7F, 0x2C, 0x0B, 0x55, 0xFC, 0x45, 0x04, 0x76, 0x20, 0x8A, 0xA3, 0xC4, 0x68, 0xFD, 0x05, 0xE5, 0x6D, 0xFC, 0x9D, 0x72, 0x27, 0x28, 0xC7, 0xC1, 0xCA, 0xB9, 0xD0, 0x47, 0xEC, 0x55, 0xD2, 0x3B, 0x74, 0xB2, 0xFA, 0x96, 0x2F, 0xA2, 0xDE, 0xA3, 0x9A, 0x6B, 0x8F, 0xE2, 0x00, 0xF2, 0x86, 0x61, 0x4B, 0x78, 0x23, 0xA2, 0x81, 0x0A, 0x99, 0xB9, 0xF1, 0x5E, 0xEB, 0x2D, 0x79, 0xA6, 0x11, 0xD5, 0xEE, 0x57, 0x5C, 0xAF, 0x8E, 0x53, 0x78, 0x03, 0x2C, 0xFD, 0x40, 0xC5, 0x59, 0xF0, 0xBB, 0xF6, 0xDF, 0x64, 0x1B, 0xA4, 0x80, 0x94, 0xFA, 0xBC, 0x54, 0x43, 0xEA, 0x4B, 0xF6, 0x51, 0x78, 0x05, 0xDA, 0xC3, 0x98, 0x43, 0x78, 0x21, 0xC3, 0xFD, 0xF6, 0x92, 0xCD, 0x2D, 0xEB, 0x5A, 0x0D, 0xD2, 0x0F, 0xCD, 0x73, 0xB5, 0x17, 0xE5, 0x17, 0x1A, 0x43, 0xE5, 0x61, 0x4A, 0xBC, 0x6E, 0x45, 0x85, 0x25, 0xB8, 0xA0, 0x86, 0x95, 0x64, 0x0B, 0x9F, 0xD4, 0x87, 0x78, 0xF7, 0xA8, 0x23, 0xF1, 0x21, 0xBB, 0xBB, 0x78, 0xA6, 0xCA, 0x8F, 0xF1, 0x17, 0xE1, 0x83, 0x1C, 0xE8, 0x55, 0x8B, 0x35, 0xFD, 0x41, 0xAD, 0x5B, 0xA4, 0xA3, 0x97, 0xC8, 0x74, 0xB6, 0xB2, 0xB5, 0x5D, 0x53, 0xE4, 0x98, 0x22, 0xA3, 0xCD, 0xAF, 0xAC, 0x13, 0x00, 0x1A, 0xCF, 0x24, 0xDE, 0x86, 0x43, 0x6A, 0x6E, 0x79, 0xDB, 0xA9, 0x47, 0x91, 0x6B, 0xEC, 0xD6, 0xE3, 0xA1, 0xAA, 0xDB, 0x96, 0x5F, 0xFF, 0xDB, 0x75, 0xA1, 0xD7, 0x20, 0xE2, 0xAE, 0x1C, 0x6E, 0x3E, 0x22, 0x09, 0x5A, 0x9E, 0xA8, 0xF1, 0x90, 0x51, 0x97, 0x5E, 0x96, 0xF6, 0xCB, 0x6F, 0xF5, 0xFC, 0x28, 0xCD, 0x52, 0xFE, 0x69, 0x77, 0x48, 0x8C, 0x84, 0x4E, 0xD5, 0x77, 0x7B, 0xCF, 0x55, 0xED, 0xD6, 0x22, 0x76, 0x67, 0x70, 0x2B, 0x35, 0xC2, 0x70, 0x26, 0x1C, 0x91, 0x57, 0x3D, 0xE7, 0x85, 0xAF, 0x36, 0xDA, 0x36, 0x4D, 0x14, 0xF3, 0xD7, 0x56, 0x91, 0xDE, 0xD2, 0x95, 0x2B, 0xA3, 0x24, 0x3D, 0xF2, 0xBA, 0x65, 0x7F, 0x95, 0x7C, 0x51, 0x1A, 0xBB, 0xFF, 0x4D, 0x58, 0x0E, 0xB1, 0x9A, 0x76, 0x7A, 0xB3, 0x54, 0x6A, 0xFD, 0x02, 0x7B, 0x3F, 0x7C, 0x22, 0x36, 0x93, 0xD1, 0x47, 0xD0, 0xD1, 0xE9, 0xBD, 0xC1, 0xDA, 0xA9, 0x15, 0x51, 0x2D, 0x54, 0x8D, 0x2B, 0xDB, 0x46, 0x53, 0x42, 0xDA, 0xF0, 0x96, 0xCA, 0xA6, 0x11, 0x4A, 0xE1, 0xA7, 0xD2, 0x09, 0x44, 0x9C, 0xE4, 0x79, 0xA2, 0x1B, 0x41, 0x93, 0xDF, 0xF6, 0xB6, 0x23, 0xBA, 0x81, 0x7E, 0xBB, 0x34, 0xD2, 0x0F, 0xBC, 0x65, 0xC9, 0x26, 0x09, 0xA8, 0xB0, 0xCB, 0x93, 0xB8, 0xC2, 0x7F, 0xD3, 0x40, 0x12, 0xA1, 0xC2, 0xAD, 0x64, 0x06, 0xDE, 0x20, 0x7E, 0x2E, 0xDD, 0x8F, 0xB3, 0x64, 0x2D, 0x25, 0x9B, 0x71, 0x47, 0xC5, 0xDA, 0x84, 0x74, 0x5C, 0x01, 0xB4, 0x79, 0x71, 0x88, 0x34, 0xC8, 0xC1, 0x6E, 0x36, 0xF1, 0x05, 0xBA, 0x62, 0x59, 0x49, 0x86, 0xC1, 0x0B, 0x3B, 0x93, 0x31, 0x91, 0xA2, 0xB0, 0x1E, 0xC6, 0xBC, 0x94, 0x43, 0xD8, 0x20, 0x36, 0x19, 0x74, 0x16, 0xEB, 0x30, 0x0F, 0xC8, 0x58, 0xFC, 0x0D, 0xA3, 0xC2, 0x36, 0xF1, 0x96, 0xD8, 0x65, 0x78, 0xBF, 0xD7, 0x5F, 0xF8, 0x6F, 0xF8, 0xBE, 0xDD, 0x2C, 0x62, 0x1F, 0x7C, 0xD2, 0x52, 0x47, 0xCE, 0x82, 0xF7, 0xB4, 0x42, 0xAA, 0x66, 0xF5, 0xE5, 0xBA, 0x10, 0x15, 0x80, 0x79, 0x60, 0x33, 0x54, 0x3B, 0xB0, 0x62, 0x51, 0x86, 0xDA, 0x05, 0x4B, 0x28, 0xBA, 0xAB, 0x2E, 0x57, 0xDF, 0x8F, 0x93, 0x61, 0x91, 0x6A, 0x0B, 0x2F, 0x7B, 0x7C, 0x13, 0xDA, 0x6A, 0x17, 0x46, 0x74, 0x23, 0xF5, 0x96, 0x1B, 0x88, 0xDF, 0x88, 0x45, 0xFB, 0x7C, 0xB4, 0xD1, 0xB0, 0xDE, 0x34, 0x09, 0x4D, 0x37, 0x44, 0xA0, 0xC1, 0xE8, 0x12, 0xFD, 0x14, 0x01, 0x45, 0x65, 0xA9, 0x9B, 0x55, 0x70, 0x4B, 0x75, 0x58, 0x73, 0x2A, 0x4E, 0xAF, 0x3E, 0x40, 0xE8, 0xBC, 0x02, 0x70, 0x89, 0xDA, 0xCF, 0x2E, 0x86, 0xD0, 0xA1, 0xF6, 0x96, 0x9B, 0x89, 0x1F, 0x48, 0x74, 0x73, 0x15, 0x7C, 0xB8, 0x71, 0x45, 0xF5, 0x65, 0xF8, 0x61, 0x43, 0x28, 0xFC, 0x15, 0xE1, 0xD6, 0x45, 0xF1, 0x21, 0x74, 0xB6, 0x49, 0x5B, 0x38, 0x0A, 0xFD, 0x54, 0xBD, 0x32, 0x2E, 0x40, 0x1D, 0xA4, 0xFD, 0xE2, 0xF9, 0x1E, 0x77, 0xC6, 0x1E, 0xD9, 0x4D, 0x26, 0x44, 0xE8, 0x26, 0x4B, 0x92, 0xF8, 0x82, 0x64, 0x36, 0x9F, 0x82, 0x64, 0x3D, 0x13, 0x8D, 0x2C, 0xE8, 0xDF, 0xCE, 0x9F, 0x70, 0x29, 0xDC, 0xDA, 0xEE, 0xC5, 0x1B, 0x83, 0x24, 0x34, 0xDF, 0xCF, 0x5F, 0x81, 0x7A, 0xD7, 0x73, 0x63, 0xAF, 0xA8, 0x46, 0x8C, 0x63, 0x3D, 0x99, 0xD8, 0x53, 0x62, 0x9D, 0xED, 0x10, 0x91, 0xAA, 0x0A, 0xB4, 0xF4, 0x22, 0x5E, 0x20, 0x59, 0x4D, 0x4B, 0xA0, 0xF1, 0x43, 0x0B, 0x0D, 0xAB, 0x21, 0xE1, 0x40, 0x36, 0xE4, 0x07, 0xCF, 0xE9, 0x15, 0x72, 0xFE, 0xC0, 0xBB, 0x3B, 0xBF, 0xE7, 0x4F, 0x47, 0xF6, 0xB4, 0x2C, 0x8B, 0x4D, 0x55, 0x85, 0xD4, 0xB6, 0x7B, 0xCE, 0xC0, 0x56, 0x68, 0x22, 0x6C, 0x85, 0x84, 0xAB, 0x6A, 0xAB, 0xE5, 0x14, 0xE2, 0x2A, 0x92, 0xD3, 0xD0, 0x00, 0x76, 0xAD, 0x19, 0xAD, 0x3B, 0x02, 0xEE, 0x5B, 0xF9, 0x07, 0xEA, 0x80, 0xB8, 0x43, 0x22, 0x2E, 0x03, 0xF6, 0xEF, 0x3B, 0x98, 0xF7, 0x1E, 0xC9, 0xEE, 0xF4, 0x8C, 0x8D, 0x43, 0x6F, 0x35, 0xF0, 0xBD, 0x7C, 0x30, 0xA6, 0xF6, 0xB0, 0xED, 0x3A, 0x62, 0x9A, 0xDA, 0x99, 0xFE, 0x8B, 0x38, 0x82, 0x14, 0x37, 0x5C, 0x32, 0xE5, 0x56, 0xFA, 0x1A, 0x3E, 0x19, 0x37, 0xB1, 0x4F, 0x40, 0x4F, 0xAA, 0xE7, 0xF1, 0xF6, 0x72, 0xB3, 0xF5, 0xBD, 0xC2, 0x1F, 0x79, 0xAB, 0x74, 0x75, 0x92, 0xA6, 0x98, 0x37, 0xDA, 0x68, 0x39, 0xE6, 0xE1, 0xAB, 0x51, 0x02, 0xF9, 0x36, 0x0A, 0x8D, 0x15, 0x78, 0x9B, 0x3E, 0x41, 0x33, 0x06, 0x52, 0xD7, 0x6A, 0x8D, 0x99, 0xBC, 0xDB, 0xDA, 0x44, 0xC3, 0x4F, 0xC1, 0x19, 0xB0, 0x41, 0x2F, 0x17, 0x57, 0x70, 0x0B, 0x75, 0x90, 0xF4, 0x75, 0x5E, 0xB1, 0xB6, 0x5A, 0x31, 0x75, 0xF1, 0x51, 0xCD, 0x3A, 0xE5, 0x6F, 0xF7, 0x8D, 0x1A, 0x7B, 0xF0, 0x90, 0x0D, 0x4E, 0xBE, 0x81, 0x06, 0xE9, 0x69, 0xE4, 0x55, 0x78, 0x54, 0x1D, 0x66, 0xC8, 0x91, 0x7D, 0x26, 0x9F, 0xEB, 0x43, 0xE5, 0xBF, 0x15, 0x8F, 0x75, 0x4E, 0xCA, 0x65, 0x55, 0x1A, 0xAD, 0x14, 0xF4, 0xCA, 0xBD, 0xA2, 0xE9, 0x80, 0xEC, 0xA3, 0x35, 0x1A, 0x7B, 0xE8, 0x8B, 0xBB, 0x90, 0xBC, 0x0D, 0x67, 0xD9, 0xEC, 0x20, 0xF7, 0xC1, 0x42, 0xFA, 0x56, 0x72, 0x13, 0xAC, 0xAC, 0x59, 0xAF, 0xAB, 0x47, 0xB3, 0x48, 0x1B, 0xED, 0x1A, 0x95, 0xA3, 0x62, 0xA9, 0x76, 0xAC, 0x4A, 0xCD, 0xAE, 0xD0, 0xEC, 0x57, 0x3B, 0xE6, 0x74, 0x91, 0x3F, 0x55, 0xBB, 0xA3, 0x1A, 0xC8, 0x3D, 0x2A, 0x6F, 0xF7, 0x9D, 0xE4, 0x52, 0xE4, 0x99, 0xAD, 0x39, 0xD9, 0x8F, 0xCC, 0xB7, 0x9C, 0x41, 0xF6, 0xC3, 0xFB, 0xAA, 0x57, 0x6A, 0x37, 0x69, 0x77, 0x62, 0x1D, 0x9A, 0xCD, 0xDA, 0x43, 0xB2, 0x6C, 0xF2, 0x87, 0xA6, 0x8F, 0x79, 0x8F, 0xEC, 0xD0, 0x70, 0xB3, 0x03, 0xC9, 0x4A, 0x32, 0x28, 0x1A, 0x24, 0x83, 0x71, 0xA6, 0x47, 0x28, 0x59, 0xA6, 0x92, 0xDA, 0xA6, 0x92, 0xD5, 0xC8, 0x52, 0x4B, 0x06, 0xD9, 0x05, 0x5F, 0xD7, 0x7F, 0xD7, 0x18, 0xEA, 0x70, 0x35, 0x85, 0x5C, 0x5F, 0xAB, 0x92, 0x1C, 0x25, 0xDE, 0xD6, 0xDC, 0x60, 0x7E, 0x26, 0x10, 0x63, 0x7A, 0x76, 0x3C, 0xD1, 0xAB, 0xDF, 0x19, 0x7D, 0x85, 0x58, 0xAE, 0xD9, 0xE6, 0x11, 0x45, 0x4E, 0xC7, 0x26, 0xD9, 0xCE, 0x26, 0xF9, 0xA8, 0x19, 0xFD, 0x26, 0xD9, 0xFC, 0x1F, 0xB5, 0x99, 0xDC, 0xDC, 0x51, 0xA0, 0xBA, 0x44, 0xEC, 0x6B, 0xBB, 0x2D, 0x19, 0x43, 0x84, 0xB7, 0x24, 0x55, 0x22, 0xF8, 0xF7, 0xC6, 0x09, 0x59, 0x0D, 0xF8, 0xE3, 0x5A, 0x9F, 0x68, 0x47, 0x62, 0xAE, 0x21, 0xDB, 0x3D, 0x9B, 0x38, 0x82, 0xB7, 0xD9, 0x54, 0x92, 0x71, 0xA8, 0x96, 0x9E, 0x4E, 0x92, 0xF0, 0x49, 0xED, 0x15, 0x72, 0x7A, 0xFF, 0x7B, 0x94, 0x4B, 0xE4, 0xF6, 0xB2, 0xC4, 0x7E, 0xF8, 0xD7, 0xAE, 0x57, 0xE5, 0x56, 0xF8, 0x92, 0xB6, 0xED, 0x99, 0x3A, 0x5C, 0xDB, 0xE4, 0x1A, 0x15, 0x86, 0xEF, 0xAF, 0x31, 0xB9, 0x95, 0x10, 0x6D, 0xC4, 0x7D, 0xEB, 0x13, 0xA4, 0x13, 0x7A, 0x9D, 0x76, 0x9B, 0x14, 0xC0, 0xDB, 0xB5, 0x39, 0x04, 0x7B, 0xE5, 0x28, 0x24, 0x11, 0x3F, 0x3C, 0xB4, 0x57, 0x32, 0x1B, 0xF7, 0x5F, 0x9A, 0x53, 0x21, 0xC4, 0x69, 0x3D, 0x85, 0x19, 0x2B, 0xF1, 0xBC, 0x36, 0x41, 0xE4, 0x69, 0x1C, 0xAE, 0xB3, 0x76, 0xAB, 0x25, 0x38, 0x1A, 0x0B, 0xEB, 0x7A, 0x72, 0x96, 0xCA, 0x89, 0x86, 0x93, 0xF9, 0xF0, 0x4A, 0x82, 0xD3, 0x52, 0x52, 0xB9, 0x1A, 0xD2, 0x34, 0x39, 0x54, 0xB9, 0x08, 0xBF, 0xD7, 0x1F, 0xE7, 0x3D, 0x2C, 0xAB, 0xAF, 0x55, 0x0A, 0xC1, 0x0C, 0x6A, 0x4D, 0xB9, 0xC4, 0x3A, 0x92, 0x62, 0xF8, 0x24, 0xA7, 0xB8, 0xEA, 0x74, 0xDD, 0xCA, 0x1F, 0x56, 0x5B, 0xB4, 0x96, 0xE0, 0x3E, 0xEA, 0x88, 0x86, 0x80, 0x30, 0x7C, 0x79, 0xD3, 0x0A, 0xDE, 0x4C, 0xE8, 0x5E, 0xC3, 0x66, 0x81, 0x8D, 0xF0, 0x72, 0x9D, 0x44, 0x64, 0x2A, 0xFB, 0x65, 0xEA, 0x90, 0x8E, 0x49, 0xFF, 0x64, 0xEC, 0x97, 0x3B, 0x45, 0x64, 0x19, 0xD4, 0xCA, 0x00, 0x97, 0x1F, 0x3A, 0x1F, 0x30, 0xD4, 0xEA, 0x9A, 0xE6, 0x2D, 0x94, 0x47, 0xA3, 0x68, 0x58, 0xD0, 0x39, 0x3C, 0xB3, 0xE1, 0x8B, 0x54, 0x05, 0x4E, 0xA8, 0xF7, 0x91, 0xDB, 0xF1, 0x56, 0xD7, 0xE6, 0x2A, 0xA2, 0x4A, 0x03, 0x6A, 0x6A, 0x94, 0x07, 0xD3, 0x37, 0x56, 0x5F, 0x02, 0x47, 0x87, 0xB7, 0xE8, 0x7F, 0x82, 0xEF, 0x5D, 0x3E, 0x68, 0x9F, 0x41, 0xC3, 0xD6, 0x3E, 0x9A, 0xC3, 0xD0, 0x0F, 0xDA, 0xA0, 0x26, 0x0E, 0xA6, 0xE0, 0x81, 0xF5, 0x1A, 0x38, 0x15, 0x70, 0xAF, 0xBD, 0x8F, 0xAC, 0xE1, 0x06, 0x99, 0x42, 0x90, 0xAB, 0xC5, 0x3B, 0x8C, 0x5B, 0xD1, 0xB2, 0xB4, 0xF9, 0xD5, 0xFE, 0x68, 0x79, 0xF8, 0x74, 0x7D, 0x3B, 0xF2, 0xD6, 0x75, 0xBF, 0x76, 0x1B, 0x32, 0xD6, 0xFA, 0x88, 0x66, 0x08, 0xD6, 0xD3, 0xA7, 0x69, 0x3C, 0xE1, 0x64, 0x74, 0x7F, 0x9D, 0x9E, 0x34, 0x28, 0x30, 0xD3, 0x6F, 0x72, 0x23, 0x77, 0x65, 0x4D, 0x2C, 0x71, 0xB5, 0xE8, 0x75, 0xF5, 0x09, 0x62, 0x20, 0xA5, 0xE9, 0xBF, 0x18, 0x6B, 0xC3, 0xFE, 0xE8, 0x19, 0xEA, 0xCF, 0x6E, 0x0E, 0x5A, 0x04, 0xE5, 0x5B, 0x7F, 0xD7, 0xD4, 0xC0, 0xDF, 0xE9, 0x0E, 0x1A, 0x3B, 0x38, 0x1F, 0xA1, 0xD4, 0x2E, 0xAF, 0xC9, 0x90, 0x1D, 0x34, 0x51, 0x8D, 0x75, 0x9C, 0x22, 0x63, 0x71, 0x35, 0xA7, 0x28, 0xC6, 0x70, 0x58, 0xFF, 0x3D, 0xC5, 0x4E, 0x7F, 0x58, 0xBB, 0x29, 0x6C, 0x83, 0xAE, 0x8E, 0x9C, 0xEF, 0x5A, 0xAA, 0x75, 0x54, 0x3D, 0xB0, 0x6E, 0xD4, 0xF0, 0x91, 0x22, 0xDA, 0x23, 0x0D, 0x05, 0x4E, 0x84, 0x6E, 0x9B, 0xAE, 0xB6, 0xB8, 0x4B, 0xCD, 0x6B, 0x5C, 0x9B, 0x69, 0xAC, 0x4F, 0xD5, 0x23, 0x8D, 0xF3, 0x0B, 0xCF, 0x1A, 0x7C, 0xEA, 0x38, 0x29, 0x97, 0x74, 0xBF, 0x6B, 0xC6, 0x84, 0xFE, 0xD0, 0x7E, 0xD6, 0x85, 0xBB, 0xD8, 0x69, 0xEE, 0x62, 0xEE, 0x56, 0xDB, 0x35, 0x89, 0xC8, 0x6A, 0x5A, 0x98, 0x66, 0x06, 0xEC, 0x04, 0xEE, 0x35, 0xB1, 0x7B, 0x46, 0x8B, 0xCF, 0x19, 0x0F, 0x77, 0xDE, 0x61, 0x6D, 0xAF, 0x8E, 0x6C, 0x9F, 0x5C, 0xF0, 0x40, 0x7F, 0xB6, 0x79, 0x67, 0xF2, 0x4B, 0xDD, 0x9A, 0xFA, 0x9C, 0x90, 0x5D, 0xDA, 0x75, 0x86, 0xC7, 0x4E, 0x4F, 0x35, 0xBB, 0xF0, 0x60, 0xC6, 0x53, 0x8D, 0x17, 0xF2, 0x80, 0x3A, 0x44, 0xFE, 0x82, 0x27, 0x80, 0xAC, 0x9A, 0xF5, 0xCB, 0x7E, 0x0A, 0xDF, 0x55, 0xBF, 0xEC, 0xAF, 0x61, 0x2E, 0x33, 0x1C, 0xEF, 0x49, 0x29, 0xE8, 0xD6, 0x2F, 0xEF, 0xB0, 0x4E, 0xBC, 0xAF, 0x43, 0x9B, 0xCE, 0x06, 0xAF, 0xD2, 0x6E, 0xA8, 0xE1, 0x3B, 0x1E, 0xD5, 0x1C, 0x26, 0xA2, 0x18, 0x51, 0x1A, 0x5B, 0x74, 0x2E, 0xD5, 0x99, 0x7C, 0x0A, 0x3D, 0x92, 0x8D, 0xEA, 0xF5, 0x64, 0x2E, 0xE5, 0x4F, 0xEA, 0xBE, 0xCF, 0x46, 0xCB, 0x4B, 0x3A, 0xBC, 0xB8, 0x0F, 0x73, 0x69, 0x2D, 0x4F, 0x04, 0x40, 0xA2, 0x7F, 0x63, 0x9D, 0xD8, 0x2A, 0x78, 0x65, 0x6D, 0x8D, 0x2C, 0xC8, 0x69, 0x81, 0xE1, 0xAD, 0x92, 0xB4, 0xEC, 0xD3, 0x85, 0x80, 0x4A, 0x8A, 0x8D, 0xD6, 0x0C, 0x4A, 0x96, 0x2E, 0xE9, 0xF9, 0xC1, 0xAD, 0xE6, 0xA5, 0x75, 0x29, 0xF8, 0xF5, 0xE5, 0xC1, 0xED, 0xEE, 0xC2, 0xFD, 0xB9, 0x7F, 0xB5, 0xD8, 0x8A, 0x47, 0x12, 0xE4, 0x0D, 0xFF, 0x93, 0xBE, 0x0C, 0xB6, 0x32, 0xFD, 0x54, 0x38, 0x3A, 0xDE, 0x34, 0xB4, 0x00, 0xF5, 0x96, 0x0F, 0x75, 0x73, 0xC1, 0xA7, 0x94, 0x11, 0xED, 0x04, 0x08, 0x96, 0xB8, 0x75, 0x1F, 0x13, 0xFF, 0xC3, 0x31, 0x74, 0x5A, 0x49, 0x4F, 0x94, 0x2D, 0x6B, 0x7D, 0x29, 0xFB, 0x95, 0x93, 0xD2, 0xBC, 0x50, 0x61, 0x96, 0x60, 0xD7, 0xF0, 0xB7, 0xB2, 0x36, 0xE8, 0xA6, 0xA9, 0x04, 0xD8, 0xE9, 0xF8, 0xD9, 0x10, 0x08, 0x9E, 0x61, 0xA4, 0x6A, 0xFF, 0x85, 0x2A, 0xA9, 0xFE, 0x9A, 0x77, 0xD0, 0xA0, 0xD8, 0xBB, 0x4B, 0x04, 0x7C, 0xAF, 0xFA, 0xD4, 0x31, 0x1A, 0x9A, 0x5D, 0xD2, 0xD6, 0x6A, 0x01, 0x1D, 0xCA, 0x52, 0x37, 0x05, 0xC0, 0x79, 0x71, 0x65, 0xF5, 0x39, 0xF0, 0xBA, 0xC0, 0xDB, 0x35, 0x4F, 0x61, 0xAD, 0x53, 0xBC, 0xFE, 0x3B, 0x3C, 0x87, 0x71, 0x58, 0x7B, 0x0C, 0xBA, 0xF2, 0x5F, 0x0F, 0x6F, 0x42, 0xBB, 0x84, 0xEB, 0x3B, 0x19, 0x18, 0x8F, 0x7D, 0xBC, 0x7D, 0x11, 0xD6, 0x55, 0x5C, 0xD2, 0x92, 0x83, 0x25, 0x67, 0xDB, 0x35, 0xFE, 0xAD, 0xBE, 0x17, 0x7B, 0xBF, 0x0E, 0x50, 0x6B, 0x02, 0x27, 0xD5, 0x40, 0xAA, 0x28, 0x27, 0x4F, 0xFD, 0x01, 0x24, 0x83, 0x71, 0x55, 0xBB, 0x12, 0xF6, 0xA2, 0x9E, 0xD0, 0x1C, 0x83, 0x76, 0x09, 0xAC, 0x3A, 0xC2, 0xF4, 0x6C, 0xF6, 0xB4, 0x36, 0x1F, 0xFD, 0xEC, 0x22, 0x4E, 0xB3, 0x5A, 0xE7, 0x93, 0x39, 0xA9, 0x61, 0x40, 0x4B, 0x8F, 0x5D, 0x55, 0xFB, 0x9E, 0xAC, 0x0D, 0x9C, 0x5C, 0x33, 0x1D, 0xFF, 0xDB, 0xB1, 0x5D, 0x8F, 0xA1, 0x75, 0x0C, 0x91, 0xB6, 0x1A, 0xC6, 0xA9, 0x1A, 0xCD, 0x56, 0x68, 0x19, 0x37, 0xA0, 0x3D, 0xA2, 0xDE, 0xBB, 0xE2, 0x47, 0xEB, 0xB4, 0xBA, 0x84, 0x82, 0xDD, 0x4D, 0x03, 0xB5, 0xB3, 0x32, 0x0E, 0x35, 0x8C, 0xAB, 0x59, 0x10, 0x47, 0xAF, 0x4D, 0x34, 0xCC, 0x0D, 0xD8, 0x6D, 0x24, 0xC8, 0xFB, 0x8B, 0xD6, 0xEB, 0xFD, 0x55, 0x1B, 0x2C, 0xB7, 0x6A, 0x59, 0xF0, 0x76, 0xCA, 0x33, 0xCD, 0x20, 0xA4, 0xE0, 0xBE, 0x6A, 0x9F, 0xDE, 0x76, 0xB0, 0x72, 0x42, 0xCB, 0xD9, 0x96, 0x07, 0x05, 0xCF, 0x9B, 0xEC, 0x9B, 0x9A, 0x32, 0x16, 0xD7, 0x67, 0xD6, 0x6F, 0x8A, 0xD9, 0x68, 0xBA, 0x51, 0xB3, 0xCE, 0x3F, 0xD7, 0x18, 0xAC, 0xB3, 0x72, 0x78, 0xA8, 0x9F, 0xAB, 0x6E, 0xB3, 0xA4, 0x68, 0x13, 0xE1, 0x1B, 0x94, 0x12, 0x4D, 0x2D, 0x14, 0xC5, 0x93, 0xB5, 0x6E, 0x5A, 0x72, 0xA7, 0x82, 0xD1, 0x62, 0xD5, 0xED, 0x92, 0x9F, 0xD7, 0x78, 0xB9, 0xBD, 0x22, 0xCD, 0xBF, 0x3E, 0xBD, 0xF9, 0x64, 0xCC, 0x74, 0xD3, 0xED, 0xBA, 0xFB, 0xBE, 0x25, 0x46, 0xD8, 0x60, 0xE1, 0xB0, 0x57, 0x4F, 0xC1, 0x4A, 0xE8, 0xA7, 0xB4, 0x01, 0xF0, 0x27, 0x8B, 0xAF, 0x1A, 0x09, 0x34, 0x9F, 0x69, 0x3D, 0x32, 0x9A, 0x99, 0x52, 0x3C, 0x65, 0xF9, 0x61, 0x96, 0x30, 0x6B, 0xF4, 0x80, 0x19, 0x67, 0x54, 0xE2, 0x86, 0xDE, 0x69, 0xBC, 0x07, 0x11, 0x33, 0x3A, 0xE7, 0x0A, 0xF5, 0xDE, 0xDB, 0x9A, 0xC7, 0x48, 0x0E, 0xDA, 0x09, 0x6A, 0xCE, 0x2A, 0xBA, 0xA8, 0x67, 0xF4, 0x2B, 0x81, 0x17, 0xE6, 0x0B, 0xB5, 0x8F, 0xC1, 0x67, 0x95, 0x3B, 0x56, 0xDC, 0xE1, 0x8C, 0x2B, 0xCA, 0x1B, 0x3A, 0xC9, 0xBD, 0x97, 0xB9, 0x7E, 0xE9, 0x51, 0x81, 0x6B, 0xC2, 0xAE, 0x25, 0x3C, 0x51, 0x52, 0xF8, 0xA3, 0x0E, 0x3B, 0x49, 0x9E, 0x4F, 0x62, 0x53, 0xBE, 0x6C, 0xB5, 0xDD, 0xD6, 0x1A, 0x85, 0xD2, 0x40, 0x4B, 0xD1, 0x57, 0x83, 0x3E, 0xE6, 0x87, 0xB4, 0x77, 0xC1, 0x57, 0x15, 0xBE, 0xC3, 0xD7, 0x84, 0xBC, 0x82, 0x97, 0x83, 0x3B, 0xC4, 0x71, 0x99, 0x8B, 0xFA, 0xD7, 0x49, 0x06, 0x13, 0x18, 0x3D, 0xC9, 0xB2, 0xD0, 0x70, 0xB4, 0xBD, 0x58, 0xBE, 0xDE, 0x87, 0xD9, 0xD8, 0xAD, 0x9C, 0x6F, 0x77, 0xA5, 0x66, 0x36, 0xB0, 0x9C, 0x76, 0x52, 0xCF, 0x04, 0x4D, 0x16, 0x12, 0xED, 0x55, 0xF0, 0x75, 0x19, 0x65, 0xF9, 0x05, 0x85, 0x32, 0x3F, 0x76, 0xD9, 0x2F, 0x65, 0x60, 0x46, 0x5C, 0x1F, 0xA2, 0x1C, 0x89, 0x57, 0x75, 0xD3, 0x81, 0xA1, 0xB0, 0x3B, 0x6D, 0x99, 0x60, 0x9A, 0xF7, 0x3F, 0x0D, 0x77, 0xC1, 0x55, 0x76, 0x23, 0xC6, 0x5D, 0xE0, 0x19, 0xFA, 0x38, 0x7D, 0x18, 0x78, 0xCF, 0xE2, 0x9E, 0xF6, 0x18, 0xF8, 0xBC, 0xEC, 0xD3, 0x90, 0x02, 0x1D, 0x9B, 0xB7, 0x69, 0x40, 0x82, 0x0A, 0x53, 0x7F, 0xF4, 0x1E, 0x41, 0x43, 0xE2, 0x9E, 0x77, 0x05, 0xA1, 0x93, 0xC3, 0xC0, 0x56, 0x0D, 0x72, 0xD6, 0x7B, 0x76, 0x43, 0x2E, 0x42, 0xB5, 0x93, 0x18, 0x79, 0xD0, 0x6B, 0xDA, 0x2F, 0xFD, 0x6C, 0xC8, 0xCD, 0xE2, 0x81, 0x76, 0x15, 0x78, 0xAF, 0xAC, 0x70, 0x30, 0x97, 0xDC, 0x9F, 0xF7, 0x70, 0xA9, 0x2F, 0x29, 0x4E, 0xBD, 0xB4, 0xE4, 0x06, 0xB1, 0x34, 0xB6, 0xB0, 0xF3, 0x39, 0xBE, 0x3E, 0x14, 0x69, 0x5D, 0x84, 0x41, 0x5E, 0x78, 0xFD, 0x1F, 0x55, 0x8B, 0x9D, 0x93, 0xD1, 0x1A, 0xFE, 0x49, 0xDB, 0xAB, 0x7B, 0x00, 0x49, 0x2C, 0xFA, 0xB4, 0x1A, 0xF0, 0x78, 0xF1, 0x93, 0x65, 0x48, 0x8D, 0x45, 0xEE, 0xC1, 0xFE, 0x72, 0x23, 0x2F, 0xAD, 0xB1, 0xC7, 0x64, 0x68, 0x8F, 0xA5, 0x77, 0x3A, 0xEA, 0xEE, 0x87, 0x5C, 0x6A, 0x19, 0xD6, 0x48, 0xBC, 0xAC, 0xEA, 0xFB, 0x70, 0x67, 0xDB, 0xB3, 0xD5, 0x4F, 0xD0, 0xBF, 0x68, 0x65, 0xBA, 0x8D, 0x50, 0x9F, 0x45, 0xB8, 0x36, 0x07, 0xEC, 0x2E, 0x1E, 0x37, 0xB0, 0xB9, 0x89, 0x96, 0x8B, 0xF6, 0xFB, 0x35, 0x6C, 0x4B, 0x15, 0xF4, 0xA4, 0xD6, 0x5E, 0x88, 0x5D, 0xD5, 0x31, 0xAD, 0xC6, 0x3E, 0xE4, 0x52, 0xF3, 0x27, 0xFD, 0x72, 0x4F, 0x6E, 0x7D, 0x16, 0x69, 0x67, 0x7B, 0xAC, 0x7A, 0x07, 0x7A, 0x82, 0x16, 0xA1, 0xD3, 0x41, 0x5B, 0x2D, 0xA6, 0x6A, 0x1D, 0x41, 0x76, 0xF1, 0xF5, 0xA5, 0x7E, 0x1D, 0x13, 0x72, 0x75, 0x7D, 0x0B, 0xDB, 0x22, 0x52, 0x57, 0x77, 0xCB, 0x9B, 0x36, 0xC6, 0x06, 0xB5, 0x0F, 0xD4, 0x1D, 0x0D, 0x69, 0x68, 0x49, 0x35, 0x96, 0xBB, 0xDF, 0xAC, 0x9F, 0xAD, 0x89, 0xB7, 0xB7, 0xAE, 0x36, 0xA8, 0xD2, 0x69, 0x2D, 0xBA, 0x02, 0xE8, 0x90, 0xF9, 0x5B, 0xED, 0x68, 0x30, 0x20, 0x7F, 0xD2, 0xA6, 0x95, 0x95, 0xEE, 0x19, 0x03, 0xEB, 0x5E, 0x30, 0xDB, 0x12, 0x9E, 0x8D, 0x7C, 0xAF, 0xA2, 0x44, 0xE2, 0xCB, 0x47, 0x71, 0xC9, 0x00, 0x8F, 0xBE, 0xAF, 0xFC, 0x37, 0x6E, 0xB3, 0x3A, 0xB2, 0x45, 0xA7, 0x19, 0x4D, 0xF5, 0xB3, 0xE5, 0x79, 0xE6, 0x43, 0xD5, 0xC1, 0x80, 0xDF, 0x82, 0x8D, 0xBA, 0xA3, 0xA0, 0x24, 0x3F, 0x6C, 0xA3, 0xA1, 0x0A, 0xC9, 0xC8, 0x5F, 0xFB, 0x84, 0x73, 0x2F, 0xFE, 0xD7, 0x88, 0x92, 0xD7, 0x1D, 0xA1, 0x18, 0x8A, 0x14, 0xE8, 0xFD, 0x7B, 0xFB, 0xA6, 0x88, 0x5A, 0x5D, 0x77, 0xB4, 0x0F, 0x4A, 0xC7, 0x59, 0xC5, 0xD7, 0xC9, 0x14, 0x05, 0x16, 0xD5, 0xD5, 0xF3, 0x00, 0x8E, 0xD9, 0x76, 0xDD, 0x59, 0x30, 0xBE, 0xA0, 0x78, 0xFD, 0x31, 0xC1, 0xA9, 0x8C, 0x13, 0x6B, 0x98, 0xC2, 0x7B, 0xF1, 0x0F, 0x57, 0xCA, 0x45, 0x97, 0x22, 0xC2, 0x07, 0x1D, 0x24, 0x5E, 0xFE, 0x97, 0x7A, 0xC7, 0x4A, 0x5B, 0x5D, 0x6B, 0xDB, 0x36, 0xCA, 0xD3, 0x18, 0x3F, 0xEA, 0xC6, 0x2A, 0x33, 0x28, 0xD3, 0xAB, 0xC7, 0x00, 0x0D, 0x0B, 0x4F, 0xEB, 0xEE, 0x81, 0xE6, 0x79, 0xB1, 0xEB, 0xCE, 0xC8, 0x2C, 0xD3, 0x35, 0xAB, 0x05, 0xB2, 0x93, 0xF1, 0xFE, 0xC3, 0x17, 0xE4, 0x07, 0x22, 0xFA, 0x07, 0x6E, 0x28, 0x52, 0x02, 0xFE, 0xD7, 0xB3, 0x4A, 0x71, 0xC5, 0x75, 0xB0, 0xB5, 0x42, 0xB9, 0xD1, 0xF2, 0x48, 0xED, 0x7A, 0x20, 0xC8, 0x62, 0x97, 0xE1, 0x07, 0x30, 0x6C, 0xCE, 0xD2, 0x3D, 0x01, 0xDE, 0xE5, 0x46, 0xAE, 0x7D, 0x01, 0xBE, 0x4C, 0x7D, 0x39, 0xF2, 0x2F, 0x64, 0x17, 0xBB, 0x6B, 0x79, 0x23, 0xB4, 0x32, 0xBC, 0x7D, 0xE9, 0x7B, 0xC8, 0x14, 0x90, 0xD9, 0x33, 0x13, 0xF2, 0x71, 0x1B, 0xDB, 0xB2, 0x04, 0xFC, 0xC3, 0xC8, 0xAE, 0xB5, 0x07, 0x51, 0x8B, 0x0F, 0x86, 0x15, 0xE0, 0x4C, 0xF3, 0x51, 0xBA, 0xED, 0xC0, 0xF3, 0xDC, 0xF9, 0xAB, 0x3F, 0xE0, 0xF4, 0x54, 0xE1, 0x4A, 0x36, 0xE6, 0x14, 0x1B, 0x3A, 0xF4, 0x3F, 0xB5, 0x36, 0xEC, 0xDD, 0xD2, 0x99, 0xAA, 0xC7, 0xFE, 0xF2, 0xEE, 0x3C, 0x74, 0xBF, 0x6B, 0x71, 0x8B, 0x10, 0x89, 0x65, 0xFC, 0x32, 0x6D, 0x83, 0x94, 0x94, 0x31, 0x86, 0x24, 0x30, 0x7F, 0x61, 0x97, 0x4E, 0x00, 0xDC, 0xCF, 0xA9, 0x58, 0x55, 0x66, 0xD8, 0x9C, 0x16, 0xBD, 0xE2, 0x8F, 0x7E, 0x63, 0x9C, 0x71, 0x70, 0x93, 0x76, 0x59, 0xB8, 0x73, 0xDF, 0x59, 0x72, 0xBD, 0x1F, 0xB5, 0xCB, 0x15, 0x87, 0x5D, 0xC6, 0xB7, 0xF8, 0xAA, 0xFA, 0xAD, 0xA6, 0x9B, 0x70, 0xB8, 0x94, 0x32, 0x5B, 0xFF, 0x07, 0xAC, 0x5E, 0xD8, 0xA4, 0x9B, 0x07, 0x1C, 0xC8, 0x96, 0xAC, 0x5A, 0x58, 0xB7, 0x25, 0x35, 0x7B, 0xC5, 0xAE, 0x5A, 0x87, 0xD8, 0xFB, 0x83, 0x7E, 0xC6, 0xD2, 0xB0, 0x17, 0x7D, 0x9E, 0x7A, 0xC4, 0x57, 0xD6, 0xB5, 0x48, 0x63, 0xE3, 0xAC, 0x6D, 0xF1, 0xC1, 0xA4, 0x56, 0x71, 0xA6, 0x78, 0xC4, 0x9E, 0x92, 0xA5, 0xDF, 0x06, 0x0E, 0x2C, 0x3C, 0xA5, 0x3D, 0x0A, 0x34, 0xE4, 0x94, 0x8E, 0xB4, 0x34, 0xBF, 0x48, 0xB5, 0x1F, 0x3E, 0xD2, 0x28, 0x8B, 0x9D, 0xB5, 0x6C, 0x4B, 0x9D, 0x7B, 0x98, 0xA2, 0xF7, 0x7F, 0x35, 0x76, 0x3E, 0x19, 0x5D, 0x7F, 0x74, 0x3B, 0x9C, 0x3D, 0x5B, 0xA2, 0xF1, 0xAB, 0x56, 0xE7, 0x6A, 0xFE, 0x20, 0x27, 0x28, 0xBB, 0xF4, 0x02, 0x70, 0x83, 0xF9, 0x3C, 0x2D, 0x06, 0x94, 0x6C, 0xDE, 0x57, 0x15, 0x9E, 0x2F, 0x1B, 0xBE, 0xCD, 0x6D, 0x2E, 0xDE, 0xD2, 0xB2, 0x45, 0xC0, 0xAE, 0x04, 0xF1, 0x2A, 0xB1, 0x3F, 0xA7, 0x97, 0xBB, 0x48, 0x16, 0x2C, 0x4C, 0x4C, 0xCF, 0x56, 0xEE, 0x93, 0xC2, 0x7E, 0xEF, 0x91, 0x58, 0xE5, 0x5F, 0x8B, 0x08, 0xB5, 0x1F, 0xE8, 0x60, 0x1D, 0x86, 0x81, 0x90, 0xD5, 0xC6, 0x81, 0x8A, 0x3F, 0xCC, 0xAC, 0xA1, 0x48, 0x76, 0x06, 0x67, 0x72, 0xB3, 0x0D, 0x8F, 0xCE, 0x3F, 0xA4, 0x3E, 0x26, 0xD4, 0x89, 0x0C, 0x55, 0xD9, 0x92, 0x0B, 0x52, 0x28, 0xF5, 0x86, 0xE2, 0xB5, 0x82, 0xF0, 0xFD, 0x05, 0x3F, 0x05, 0x47, 0x39, 0x0C, 0xAB, 0xC7, 0x43, 0xD9, 0x56, 0x3A, 0xAC, 0x04, 0x7A, 0xB6, 0xFE, 0xAF, 0x92, 0x2B, 0xD2, 0xB0, 0x01, 0xBC, 0xE2, 0xAD, 0xEC, 0x5B, 0xC3, 0x9E, 0xAA, 0x5D, 0xCA, 0x45, 0x48, 0x0C, 0xBF, 0x5A, 0x29, 0x62, 0x41, 0xE2, 0x4A, 0x00, 0x4C, 0x71, 0x94, 0x7F, 0x82, 0x26, 0xFA, 0xEA, 0xE0, 0x62, 0x78, 0xAA, 0xC3, 0x54, 0xD5, 0x25, 0x58, 0xCE, 0xB8, 0x82, 0xA5, 0xC2, 0x3D, 0x6B, 0x4E, 0x15, 0x39, 0xAB, 0xF6, 0xF4, 0x9F, 0x2D, 0xF3, 0x57, 0xB5, 0xD4, 0x61, 0x2C, 0x50, 0xED, 0x04, 0x1D, 0xE5, 0x76, 0xA9, 0x9E, 0xB2, 0x0E, 0x8A, 0x16, 0xAA, 0x3C, 0x53, 0xAB, 0xE4, 0x66, 0x68, 0xB7, 0x6F, 0x31, 0x3C, 0x1D, 0xF9, 0x60, 0x5F, 0xAF, 0xDA, 0x85, 0xA4, 0x30, 0x82, 0xB0, 0x14, 0x64, 0xDC, 0xAA, 0x13, 0x05, 0x33, 0x8D, 0x63, 0x7A, 0x25, 0x25, 0x14, 0x43, 0x83, 0x69, 0x62, 0xA5, 0x9F, 0xAE, 0x1B, 0xF6, 0xE4, 0x8C, 0xD2, 0xA6, 0xB2, 0x50, 0xC1, 0x71, 0xCD, 0x84, 0xE4, 0x15, 0xB2, 0x52, 0x9C, 0xE7, 0x9B, 0x0F, 0x9D, 0x52, 0x5D, 0xB3, 0x5F, 0xA8, 0x1A, 0x41, 0x1E, 0x5B, 0x1E, 0xC1, 0xF2, 0x10, 0xFB, 0x11, 0x51, 0xDE, 0x81, 0x96, 0x33, 0x4B, 0x0A, 0x8A, 0x6D, 0x9A, 0xAA, 0x4D, 0x66, 0xE5, 0x6F, 0xEA, 0x3B, 0x20, 0x13, 0x7B, 0x8B, 0xE9, 0x41, 0xE5, 0x2A, 0xFE, 0xE6, 0xEA, 0xAF, 0x89, 0xD9, 0x52, 0x5C, 0xBB, 0xCF, 0x7B, 0x1F, 0x24, 0xC5, 0x56, 0xD8, 0x35, 0xA9, 0x06, 0x50, 0xD4, 0x72, 0x10, 0x93, 0x20, 0xD1, 0xC3, 0xD5, 0x39, 0xBF, 0xFA, 0x23, 0xBA, 0xE2, 0x0B, 0x03, 0x7B, 0x8E, 0x18, 0xDD, 0xCA, 0x8C, 0x1D, 0x8F, 0x80, 0x4F, 0xAC, 0xA2, 0x56, 0x76, 0xE5, 0x64, 0x1E, 0xD1, 0xF0, 0x24, 0x51, 0x22, 0xE9, 0x36, 0x9E, 0xF2, 0xFA, 0x0E, 0x39, 0x11, 0x5F, 0xEC, 0x6A, 0x55, 0x6B, 0x54, 0x02, 0xCB, 0x4B, 0x58, 0x17, 0xA2, 0x59, 0x0E, 0x67, 0x6F, 0x58, 0xF9, 0xBF, 0x0E, 0xB8, 0x80, 0x36, 0xD4, 0xAB, 0xF7, 0x2B, 0xE5, 0x2E, 0x5D, 0xAC, 0x2C, 0x66, 0xC2, 0x3D, 0x0D, 0x15, 0xAE, 0xDC, 0x93, 0x6D, 0x97, 0x13, 0x2F, 0x48, 0xA6, 0xD5, 0x3D, 0xF3, 0x4E, 0x06, 0xEF, 0x6A, 0xC7, 0xDA, 0xDD, 0x56, 0x6D, 0x54, 0xBB, 0x30, 0x9C, 0xB0, 0x23, 0xC8, 0xE6, 0x21, 0x61, 0xB6, 0x71, 0x93, 0xAE, 0x7D, 0x4F, 0x7E, 0xFB, 0xDA, 0x72, 0xDD, 0x97, 0xD2, 0xBF, 0x56, 0xAC, 0x53, 0x5C, 0x61, 0x52, 0x07, 0x2E, 0x97, 0xC7, 0x70, 0x6B, 0xBB, 0xAB, 0x13, 0x26, 0x48, 0x68, 0x8D, 0x0D, 0x3E, 0x9F, 0xC0, 0x12, 0xDD, 0x65, 0x7B, 0xB6, 0x6A, 0xBD, 0x7A, 0x07, 0x83, 0xC0, 0x3E, 0x20, 0xC7, 0x56, 0x3D, 0x13, 0x9E, 0x2D, 0xA4, 0xF5, 0xCD, 0x14, 0x7D, 0x29, 0xF3, 0x31, 0x21, 0x92, 0xD5, 0xCC, 0xD5, 0x50, 0x9A, 0xAC, 0x89, 0xEB, 0xC0, 0xBC, 0xAD, 0x1C, 0x2F, 0x5C, 0x99, 0xAC, 0x07, 0xBF, 0x4A, 0xB5, 0xBE, 0x55, 0xE8, 0x7E, 0xA5, 0x85, 0x83, 0x10, 0x73, 0x03, 0xCD, 0xAD, 0x82, 0x70, 0x7F, 0x68, 0xD2, 0x0A, 0x33, 0x9E, 0x82, 0x65, 0xDB, 0x93, 0x2D, 0x88, 0xE3, 0xAC, 0xAE, 0x79, 0x25, 0xDA, 0x21, 0x70, 0x07, 0x77, 0x49, 0x27, 0x8A, 0xDE, 0x57, 0xD6, 0xCA, 0xB7, 0x4A, 0x37, 0x25, 0xAF, 0x02, 0x27, 0x28, 0x8A, 0x7D, 0x74, 0x68, 0x1C, 0xF0, 0xC6, 0xBE, 0x49, 0xFD, 0x19, 0x0A, 0x63, 0x74, 0xE3, 0x14, 0xE8, 0xCC, 0xB0, 0x80, 0xED, 0x2A, 0xFE, 0xDC, 0xFD, 0x9E, 0x9B, 0x2B, 0xBD, 0x55, 0xFD, 0x59, 0xA0, 0x53, 0x14, 0x28, 0x57, 0x89, 0x4B, 0x95, 0x60, 0x85, 0x8F, 0xAC, 0x18, 0x68, 0x4A, 0x0E, 0x01, 0xFE, 0x02, 0xCF, 0xFB, 0x94, 0x23, 0x5B, 0xA1, 0xA7, 0xF6, 0x96, 0xEA, 0x83, 0x70, 0x06, 0x63, 0x2E, 0x3E, 0x15, 0x56, 0x0F, 0x88, 0x2B, 0x57, 0xA2, 0x93, 0x3A, 0x3C, 0xD9, 0x67, 0xD1, 0xA5, 0x06, 0x35, 0x2F, 0x17, 0x7D, 0xA7, 0x48, 0x15, 0xF6, 0xA9, 0x46, 0x95, 0x57, 0x48, 0xA7, 0xA2, 0x17, 0x92, 0xFA, 0x94, 0x1E, 0xA8, 0xC4, 0xC7, 0x16, 0x91, 0x21, 0xBB, 0xEC, 0xAE, 0xAA, 0x57, 0x21, 0xCE, 0x96, 0xBB, 0xF0, 0x29, 0xF0, 0xAB, 0x81, 0x33, 0xE5, 0x0A, 0xDD, 0xB5, 0x36, 0x0A, 0x73, 0xBD, 0xEE, 0xB0, 0xCE, 0x87, 0xD3, 0xAA, 0x6D, 0x91, 0xEB, 0x05, 0x36, 0x1A, 0xA8, 0xEC, 0x88, 0xF8, 0x21, 0xB9, 0x20, 0x11, 0x53, 0x88, 0x70, 0x57, 0xEF, 0x0A, 0xC4, 0x53, 0xA5, 0xB7, 0xE3, 0xA9, 0x97, 0x22, 0x57, 0x2D, 0x65, 0xF8, 0x7C, 0x84, 0x3E, 0xE0, 0x5B, 0x7A, 0xA9, 0xE1, 0x68, 0x6B, 0x64, 0x65, 0x44, 0xFD, 0x61, 0xED, 0xC3, 0x2A, 0xA7, 0x5A, 0x93, 0x7C, 0x3C, 0xEF, 0x4E, 0x0D, 0x5E, 0xFA, 0x50, 0x74, 0xCF, 0x70, 0x39, 0xA1, 0x48, 0xBE, 0x4B, 0x1B, 0xE8, 0x15, 0x06, 0xBF, 0xC3, 0x8A, 0x6D, 0xDF, 0xA8, 0xBB, 0x51, 0x85, 0xE5, 0x62, 0x7C, 0x11, 0x12, 0xB0, 0x24, 0xB6, 0x24, 0xB1, 0x67, 0x59, 0x73, 0x4E, 0xF9, 0x86, 0xCE, 0xBB, 0xDA, 0x6A, 0x16, 0xAB, 0xED, 0x87, 0x2C, 0x88, 0xDB, 0xDF, 0x3C, 0x5C, 0x3A, 0x59, 0xF8, 0xBC, 0x5E, 0x18, 0x7F, 0x4F, 0x3E, 0xA1, 0xFA, 0x8A, 0xE7, 0x30, 0xBC, 0x8A, 0x50, 0xD8, 0x1E, 0x50, 0xB7, 0xA9, 0x16, 0x59, 0x26, 0xE3, 0xE1, 0x48, 0x6E, 0xCF, 0xF6, 0xE2, 0xCC, 0xE5, 0xAC, 0xC6, 0xFA, 0xB2, 0x9D, 0x03, 0xF7, 0x89, 0x21, 0xE6, 0xBE, 0xDE, 0x17, 0x92, 0xA5, 0x9C, 0xF3, 0x5D, 0xCB, 0x4B, 0xF2, 0x84, 0x5E, 0xAD, 0xC5, 0xF1, 0x19, 0x32, 0x53, 0xED, 0x09, 0xCF, 0xA5, 0x30, 0x53, 0x93, 0x62, 0xF7, 0xB7, 0xDA, 0xA4, 0x3A, 0x6B, 0x79, 0x12, 0xCF, 0x40, 0xA0, 0xEE, 0x84, 0xA2, 0x83, 0xEB, 0x86, 0xEA, 0x6F, 0x96, 0xD9, 0xAE, 0xF2, 0xC6, 0x77, 0x32, 0xDD, 0x96, 0xF3, 0x24, 0x61, 0x9C, 0xFC, 0xA5, 0x6E, 0xC5, 0xCD, 0x82, 0x47, 0x5D, 0x69, 0x71, 0xB1, 0xB2, 0xF4, 0x86, 0x2F, 0x9E, 0x1F, 0x61, 0xBA, 0xF6, 0x8E, 0xDD, 0x71, 0xB5, 0x4A, 0x5D, 0xC4, 0x38, 0x87, 0x97, 0x23, 0xBD, 0xBD, 0x27, 0x95, 0xEB, 0x8B, 0x80, 0x26, 0x1B, 0xE5, 0xA3, 0xB2, 0x35, 0x64, 0x35, 0x80, 0xB3, 0xB6, 0xCB, 0xC6, 0x83, 0x5E, 0xDC, 0xCB, 0xA5, 0xE1, 0x50, 0x9B, 0xF0, 0x7E, 0x3C, 0x0D, 0xE9, 0x93, 0xF6, 0x7A, 0x6D, 0x52, 0xE7, 0x2A, 0xB3, 0xEC, 0x4C, 0xB8, 0x2F, 0xE8, 0x6D, 0x79, 0x9E, 0x98, 0x00, 0x8D, 0xED, 0xA9, 0x92, 0x19, 0x99, 0x97, 0x1A, 0x1B, 0xE5, 0xF9, 0x9C, 0x22, 0x32, 0x5D, 0x21, 0x13, 0x58, 0x49, 0xE9, 0xCA, 0x13, 0xA2, 0x93, 0x25, 0xA5, 0x20, 0x5F, 0x3A, 0x90, 0xB0, 0x08, 0xDE, 0xA3, 0x08, 0xF3, 0x4A, 0x53, 0x7D, 0x06, 0x2E, 0xDB, 0x51, 0xF1, 0x89, 0x90, 0x83, 0x25, 0x86, 0xBF, 0x82, 0xB6, 0x75, 0xDD, 0x13, 0x53, 0x44, 0x2D, 0x0D, 0x27, 0x24, 0xC7, 0x25, 0x77, 0xB1, 0xCB, 0x32, 0xA9, 0x9C, 0x23, 0x2E, 0x52, 0xA4, 0x28, 0x8E, 0x17, 0xD7, 0x02, 0x5E, 0x40, 0x59, 0x42, 0x2E, 0x74, 0x0F, 0xD4, 0x7B, 0xB1, 0x55, 0x30, 0xB4, 0xCC, 0xF6, 0x33, 0x76, 0x0D, 0xB6, 0xB5, 0x8C, 0xC6, 0x6F, 0xC2, 0x85, 0xED, 0x01, 0x82, 0x61, 0xD8, 0xBD, 0x16, 0x14, 0x35, 0x21, 0x3A, 0xB5, 0x87, 0xE4, 0x10, 0xB2, 0x54, 0x28, 0x93, 0xDD, 0x43, 0x1D, 0x8A, 0x9A, 0x14, 0xEF, 0x51, 0x55, 0xFC, 0x38, 0x68, 0x1A, 0x3A, 0xCE, 0x6B, 0x48, 0xE5, 0x82, 0x30, 0x6D, 0xDF, 0x63, 0x07, 0xE1, 0xEF, 0x96, 0xB6, 0xF8, 0x0D, 0xF8, 0x44, 0x9B, 0x2D, 0x6F, 0xBB, 0xE6, 0xA0, 0x89, 0x2D, 0x08, 0xD2, 0xDC, 0x41, 0x2B, 0xC5, 0x0B, 0xC8, 0x0F, 0x02, 0x5F, 0xA9, 0x8C, 0x5C, 0x5C, 0x98, 0x25, 0xFF, 0x4A, 0x58, 0xC6, 0x1E, 0x01, 0x59, 0x98, 0xC9, 0x73, 0x07, 0xFA, 0x41, 0x65, 0x65, 0xBB, 0x04, 0xDB, 0x8E, 0x2C, 0xB7, 0x1C, 0x8B, 0x3F, 0x86, 0xFF, 0xB4, 0x58, 0x70, 0x1A, 0x6A, 0x2F, 0x99, 0x9C, 0x79, 0xC3, 0xB5, 0x63, 0x90, 0x73, 0xC2, 0xD6, 0x9A, 0x9D, 0xFC, 0x73, 0x12, 0x27, 0xE3, 0xB4, 0x42, 0x1B, 0xD9, 0x67, 0xBD, 0x2A, 0x56, 0x08, 0xEC, 0xD3, 0x64, 0x78, 0xB4, 0xA3, 0xBB, 0xD5, 0x4F, 0x6D, 0x2D, 0xB1, 0xF5, 0xA8, 0x3F, 0xFD, 0x02, 0xFE, 0x0E, 0xF9, 0xBB, 0x51, 0x56, 0x95, 0xD0, 0xF1, 0xA4, 0xBA, 0x96, 0x6B, 0x68, 0xBB, 0x0F, 0x8B, 0x04, 0xF2, 0x96, 0x56, 0xBE, 0x83, 0x78, 0x54, 0xE3, 0xB7, 0x82, 0x2C, 0xD9, 0xBC, 0xDA, 0x91, 0x58, 0x2F, 0x60, 0x81, 0xC1, 0xE8, 0xB1, 0x00, 0x95, 0xE2, 0xC7, 0x6C, 0xEE, 0x60, 0xFD, 0xE8, 0x49, 0xFA, 0x2E, 0xFC, 0x3B, 0x62, 0xD6, 0xB8, 0x9A, 0x1D, 0x30, 0xB0, 0xC0, 0x90, 0xCB, 0xA9, 0xEB, 0xEB, 0x85, 0x34, 0xFC, 0x92, 0x9E, 0xA9, 0xDC, 0x62, 0x91, 0x73, 0xC7, 0xF8, 0xBC, 0x65, 0x52, 0xBC, 0xE9, 0xF9, 0xE2, 0x53, 0xCA, 0x21, 0x93, 0xB5, 0xFB, 0x35, 0xD4, 0x91, 0xE4, 0xD8, 0x5A, 0x60, 0x06, 0x55, 0x9A, 0xA5, 0x1D, 0xFE, 0x15, 0xB1, 0x6B, 0xF8, 0xCC, 0x9A, 0x3F, 0xF2, 0x4E, 0xCF, 0xA9, 0xE2, 0x0C, 0xAF, 0x81, 0xFE, 0xF0, 0x72, 0x96, 0xA5, 0x71, 0xCE, 0x09, 0x95, 0x4B, 0x1E, 0xE6, 0x16, 0x48, 0xE9, 0xED, 0xCB, 0xA2, 0xB3, 0x94, 0xE2, 0x7A, 0x6B, 0x8F, 0xE9, 0xC8, 0x0B, 0xCD, 0x29, 0xDB, 0xB3, 0x18, 0x57, 0x75, 0x96, 0x61, 0x83, 0xBF, 0x47, 0xA2, 0x9A, 0x33, 0xD5, 0x93, 0x8B, 0x8C, 0x86, 0x42, 0x55, 0x7F, 0x79, 0x01, 0x34, 0x5D, 0x95, 0xCE, 0xEA, 0xE1, 0xED, 0x56, 0xC5, 0x73, 0x1F, 0xE6, 0x07, 0xA9, 0x36, 0x0A, 0x1F, 0xC6, 0xD8, 0xAA, 0x11, 0x69, 0x81, 0xFB, 0x6B, 0x7C, 0x8E, 0x72, 0x81, 0x8D, 0x81, 0x08, 0x06, 0x5D, 0xE8, 0xA1, 0xC4, 0x7E, 0x68, 0x5A, 0xA3, 0x19, 0xC2, 0x64, 0x8D, 0xD7, 0x41, 0x88, 0x9C, 0x23, 0x02, 0x73, 0x90, 0x5E, 0xFE, 0x79, 0xAE, 0x1A, 0xA5, 0x89, 0xEA, 0xF2, 0x98, 0x68, 0xB7, 0x34, 0x76, 0xF1, 0x5E, 0xD5, 0x11, 0xF9, 0x13, 0xF7, 0x2E, 0xEC, 0x18, 0xD0, 0x6E, 0x83, 0x12, 0x0B, 0xA0, 0x89, 0xF4, 0x1C, 0x62, 0x04, 0x1A, 0xAC, 0x43, 0xC1, 0x3D, 0xA2, 0x50, 0xED, 0x49, 0x88, 0x2A, 0x99, 0xA7, 0x8C, 0x84, 0x5E, 0xCA, 0x38, 0x55, 0x57, 0xE1, 0xD5, 0x8A, 0xA0, 0xDC, 0x61, 0x04, 0x55, 0xEE, 0x5C, 0x3C, 0x46, 0x35, 0x06, 0x78, 0xEC, 0x0E, 0x62, 0x7C, 0x28, 0xC2, 0xA6, 0x19, 0x7F, 0x07, 0xBD, 0xA6, 0x13, 0x44, 0x17, 0xEC, 0x55, 0xF3, 0x52, 0xE9, 0x0A, 0x46, 0x6B, 0x6C, 0x94, 0xFF, 0x42, 0xCE, 0xCA, 0x29, 0x60, 0x28, 0xF4, 0xAB, 0x6A, 0x3A, 0x84, 0xC1, 0xDF, 0x73, 0xCE, 0xC2, 0x5A, 0x64, 0x79, 0xD4, 0x53, 0x34, 0x0D, 0x09, 0x70, 0xD7, 0x61, 0x14, 0xF8, 0xB3, 0xCD, 0x4E, 0xFC, 0x1A, 0xBC, 0x85, 0x3E, 0x44, 0xB4, 0xC1, 0x6D, 0xD5, 0x67, 0xE4, 0x06, 0x62, 0x16, 0xF1, 0x4D, 0xF1, 0x37, 0x91, 0x24, 0x8F, 0x56, 0x1E, 0xC0, 0xFF, 0x65, 0x36, 0x83, 0x0E, 0xB8, 0x2E, 0xEB, 0x19, 0xB4, 0x09, 0xFB, 0x16, 0x3D, 0x19, 0x39, 0xA3, 0x5E, 0xE1, 0x0E, 0xA8, 0xEF, 0xA2, 0xCB, 0x6C, 0x86, 0xF1, 0xE3, 0x48, 0x06, 0xBD, 0x99, 0xE8, 0x81, 0x0F, 0xEA, 0xFD, 0xA4, 0x49, 0xC6, 0x27, 0xD8, 0x0E, 0x19, 0x61, 0x6C, 0x95, 0x6E, 0x54, 0xF0, 0xAA, 0x85, 0x95, 0xF6, 0xCA, 0xFD, 0xFA, 0xF5, 0xD9, 0x6B, 0xC0, 0x95, 0xDA, 0x5B, 0xD1, 0xC7, 0x11, 0x37, 0x32, 0xD8, 0x3D, 0x56, 0xDD, 0xA7, 0x8E, 0xB7, 0x29, 0xC4, 0xF7, 0x20, 0x97, 0xE9, 0xA9, 0xC4, 0x20, 0x7C, 0x5C, 0xBF, 0x4E, 0xB2, 0xB0, 0x95, 0xA7, 0x5E, 0x25, 0xAD, 0x69, 0x09, 0x96, 0xE4, 0xCA, 0x4B, 0x9A, 0x66, 0x55, 0x60, 0x8A, 0x27, 0xF5, 0xBE, 0x59, 0x9B, 0x81, 0x73, 0x35, 0x4B, 0xA2, 0x1D, 0x60, 0x83, 0x7E, 0x8E, 0xDB, 0x46, 0x75, 0x36, 0xF6, 0xDE, 0xFA, 0x17, 0xBE, 0x12, 0x8D, 0xA3, 0xCF, 0x24, 0x86, 0xE1, 0xDD, 0x3A, 0x40, 0xBC, 0x75, 0xC9, 0x06, 0x55, 0xA4, 0x74, 0x5C, 0x4F, 0xA3, 0x98, 0x2D, 0x2B, 0xEB, 0x1C, 0x55, 0xBE, 0x40, 0x61, 0xDF, 0x3A, 0x26, 0xA3, 0x03, 0xC8, 0x68, 0x90, 0x44, 0x86, 0xC3, 0xF3, 0x8D, 0x09, 0x6E, 0xE6, 0xEA, 0x69, 0x44, 0xBE, 0xF5, 0x4B, 0xBC, 0x06, 0xDD, 0x40, 0xB7, 0x27, 0x7A, 0xE1, 0xCD, 0x1A, 0x0F, 0xD1, 0xFD, 0xA1, 0xD7, 0xE8, 0x67, 0xF1, 0xF5, 0x65, 0xEF, 0xC4, 0x22, 0x69, 0x57, 0x5F, 0x6F, 0x69, 0x9E, 0x1C, 0xEC, 0xF2, 0x4B, 0xDB, 0xAC, 0x5C, 0xD9, 0xD2, 0x19, 0x3E, 0x08, 0x1D, 0x35, 0xAD, 0x75, 0x6B, 0x55, 0xED, 0x24, 0x5B, 0x6D, 0x32, 0x70, 0xA6, 0x6A, 0x2E, 0x5D, 0x4E, 0x34, 0xC2, 0xDB, 0xF4, 0xE1, 0x3A, 0xEB, 0xA2, 0x2F, 0x2A, 0x91, 0x66, 0x6F, 0xF9, 0x31, 0xB1, 0x2F, 0x79, 0x8D, 0xED, 0x5F, 0x31, 0x85, 0x2C, 0xE5, 0xB6, 0x66, 0xF4, 0x13, 0xEF, 0x85, 0x25, 0x91, 0x0A, 0x02, 0x96, 0xFC, 0x76, 0x85, 0x88, 0x93, 0x8A, 0xE3, 0x56, 0xE7, 0x48, 0x7B, 0x70, 0x01, 0xF5, 0x21, 0x99, 0x0A, 0xFD, 0xAD, 0x79, 0x48, 0xBE, 0x66, 0x2E, 0x87, 0x51, 0xD2, 0xA2, 0x6A, 0xB3, 0x28, 0x98, 0x10, 0xF3, 0x7E, 0x54, 0x84, 0x11, 0x7E, 0xC2, 0x03, 0x19, 0x4C, 0xFC, 0x81, 0x64, 0x63, 0x84, 0x33, 0xFE, 0xAF, 0xBC, 0xCA, 0xE5, 0x33, 0xD1, 0x00, 0x44, 0x5A, 0x7D, 0x21, 0x27, 0x81, 0x77, 0x69, 0x89, 0x64, 0x08, 0x54, 0x4B, 0x6C, 0xC0, 0xB7, 0x0A, 0x07, 0xC0, 0x4D, 0xF8, 0x68, 0xD1, 0x09, 0xC1, 0x36, 0xEC, 0x9E, 0xD4, 0xAE, 0xEC, 0x2E, 0xF6, 0x43, 0x6E, 0x97, 0xBE, 0x17, 0x7B, 0xA1, 0x38, 0x16, 0x76, 0x0B, 0x8F, 0x00, 0x3C, 0x5D, 0x4E, 0x11, 0x61, 0xE0, 0x35, 0xEB, 0x48, 0xE2, 0x09, 0xB4, 0x8E, 0x76, 0x80, 0x74, 0x81, 0xC7, 0xE1, 0x6B, 0xD5, 0x99, 0xCA, 0x70, 0x70, 0x99, 0xDA, 0x16, 0xB0, 0x13, 0x04, 0xAA, 0x61, 0xF0, 0x74, 0xE9, 0x0A, 0xF5, 0x2F, 0x68, 0x67, 0xDA, 0x31, 0xCC, 0x17, 0x0E, 0x0A, 0xD3, 0x62, 0xEB, 0xE1, 0x52, 0xD7, 0x24, 0xFC, 0x03, 0xAC, 0xB4, 0x5E, 0x45, 0x9C, 0x84, 0xCB, 0xE8, 0x33, 0x49, 0x3B, 0x38, 0x13, 0xB9, 0xA7, 0x72, 0x53, 0x1B, 0x95, 0x29, 0xE8, 0x5A, 0xF5, 0x6E, 0x5E, 0xA0, 0xCA, 0x52, 0xFD, 0xB1, 0xB8, 0x55, 0xB5, 0x16, 0x1B, 0x9D, 0x8A, 0xA8, 0x45, 0x6A, 0x45, 0xF8, 0x26, 0xCC, 0x47, 0xB5, 0xD4, 0x6D, 0x34, 0xBE, 0x11, 0x9D, 0x64, 0x7D, 0x95, 0xD8, 0x06, 0xBF, 0xA6, 0x4F, 0x23, 0xED, 0x61, 0x29, 0x9A, 0x83, 0x34, 0x18, 0x72, 0xE5, 0x96, 0x48, 0x81, 0xFE, 0x22, 0x27, 0x1A, 0x79, 0xA1, 0x3B, 0x5C, 0x54, 0x80, 0x86, 0x68, 0x37, 0xA4, 0x42, 0x2A, 0x84, 0xBC, 0x1D, 0x51, 0xA6, 0x1E, 0xC4, 0x9F, 0xB9, 0xFE, 0xC2, 0x45, 0xAA, 0x7A, 0xEB, 0x76, 0x62, 0x25, 0x52, 0x40, 0x3B, 0xFC, 0xDF, 0x85, 0x5C, 0xB4, 0x12, 0xF6, 0x6E, 0x4A, 0x91, 0xD5, 0xC1, 0xFC, 0x86, 0x93, 0x55, 0xA1, 0xF0, 0xED, 0xBA, 0xC3, 0x05, 0x6B, 0x91, 0xA5, 0x26, 0x65, 0xCA, 0x0A, 0xB4, 0xA5, 0xBA, 0x21, 0x7C, 0xA5, 0xEA, 0x87, 0x96, 0x74, 0x9D, 0x82, 0xBB, 0xA8, 0x7F, 0x5A, 0x7D, 0x23, 0x3A, 0x91, 0xF5, 0xB4, 0x34, 0xD2, 0x03, 0x8E, 0x87, 0xE8, 0x50, 0x67, 0x57, 0x90, 0xF4, 0x07, 0xF4, 0xB8, 0xC3, 0xBA, 0x4A, 0x0D, 0x2F, 0x6A, 0x45, 0x0B, 0x9E, 0x23, 0x94, 0xA6, 0xF8, 0xE4, 0x4E, 0x34, 0xA9, 0x4E, 0x10, 0x7A, 0x4D, 0xD5, 0x6C, 0x30, 0x38, 0xDF, 0xC4, 0x3E, 0xE0, 0xAE, 0x56, 0x32, 0x02, 0x43, 0x3E, 0xD3, 0x26, 0x90, 0x8E, 0xB0, 0x13, 0xB0, 0x16, 0xBC, 0x3C, 0x30, 0x55, 0xF2, 0x16, 0xFC, 0xD4, 0xB7, 0x9F, 0x8D, 0x41, 0xCD, 0xDD, 0xC3, 0xF9, 0x8F, 0x61, 0x6D, 0xDB, 0xD7, 0xA4, 0x14, 0x64, 0x63, 0xE3, 0xF3, 0x90, 0x70, 0x15, 0xC3, 0x78, 0xDE, 0x59, 0x81, 0xAD, 0x21, 0xD2, 0xAC, 0xC2, 0x89, 0x32, 0x34, 0x9C, 0x7A, 0x9B, 0xA4, 0xC1, 0xF3, 0x40, 0xA7, 0x3A, 0xA0, 0x98, 0x2A, 0x5E, 0x6B, 0xA2, 0x94, 0x0F, 0xB0, 0x96, 0x19, 0xF5, 0xEC, 0xD4, 0x7C, 0xA4, 0xDA, 0x9F, 0x0B, 0x24, 0x32, 0xF5, 0xFB, 0x05, 0x44, 0x28, 0x43, 0x67, 0x2B, 0xC1, 0x9D, 0x5E, 0x6B, 0xCE, 0x28, 0xF4, 0x0C, 0x67, 0x0D, 0x15, 0xF8, 0x41, 0x19, 0x20, 0x2F, 0x41, 0x13, 0x94, 0x27, 0x4C, 0x91, 0xCC, 0x60, 0xD1, 0x61, 0xE3, 0x65, 0xF6, 0x3A, 0x66, 0x71, 0x75, 0x1C, 0xCF, 0x39, 0x7F, 0xB7, 0xC1, 0x4B, 0xE8, 0x9B, 0xF8, 0x44, 0x77, 0x4D, 0x7C, 0x3D, 0x78, 0x99, 0xB6, 0x43, 0xB6, 0xC5, 0xA9, 0x58, 0x63, 0x50, 0xDE, 0x62, 0x48, 0xC8, 0xDF, 0xE0, 0x72, 0xAA, 0x1F, 0x79, 0x14, 0x62, 0x2B, 0x00, 0xA3, 0xAB, 0x60, 0xB2, 0xE0, 0x7E, 0xF5, 0x28, 0xE1, 0xA5, 0xCA, 0x21, 0xFD, 0x05, 0xF1, 0xFD, 0xFC, 0x02, 0xDD, 0x5D, 0xE9, 0x70, 0xD2, 0x78, 0xED, 0x37, 0x79, 0x5F, 0xD0, 0x28, 0xCD, 0x67, 0x65, 0x81, 0x53, 0xA6, 0xC6, 0x07, 0xCC, 0x60, 0x3C, 0x27, 0x6F, 0x40, 0xB9, 0xD4, 0xEB, 0xE4, 0x56, 0xE8, 0x88, 0x9C, 0x61, 0xF0, 0x94, 0x8B, 0xF9, 0x8F, 0xF4, 0x3C, 0xC5, 0x83, 0x0A, 0xBA, 0xAE, 0x0E, 0x40, 0x73, 0x2F, 0x69, 0xEF, 0x82, 0x81, 0x89, 0x06, 0x6D, 0x36, 0x34, 0x36, 0x68, 0xA7, 0x46, 0x0E, 0x29, 0x9C, 0x1B, 0xC9, 0xC7, 0xD0, 0x15, 0xAB, 0x7A, 0x72, 0x17, 0xF4, 0x81, 0x16, 0x49, 0x8E, 0x40, 0xBF, 0x45, 0xD7, 0x75, 0xD7, 0xD0, 0x31, 0xBC, 0x64, 0x5D, 0x08, 0xDA, 0x5E, 0xB6, 0x5F, 0xCB, 0x57, 0xC5, 0x64, 0x2F, 0xD7, 0x9C, 0x51, 0x29, 0xE3, 0x9E, 0x68, 0x0C, 0xE8, 0xD3, 0xE0, 0xEB, 0xE4, 0x67, 0x54, 0xEA, 0xB2, 0x85, 0xEC, 0x47, 0x62, 0xAC, 0x1E, 0x90, 0x83, 0x30, 0x8F, 0x96, 0x4B, 0x0E, 0xC3, 0xD3, 0xC4, 0x8D, 0x5A, 0x42, 0xF3, 0x0F, 0xB7, 0x51, 0xF3, 0x4B, 0xF3, 0xB3, 0x64, 0xA9, 0xC6, 0x5A, 0x93, 0x9E, 0xF9, 0x81, 0x84, 0xC8, 0xAA, 0x38, 0x11, 0xB9, 0x19, 0x3F, 0x11, 0x5C, 0x47, 0xB6, 0x62, 0x39, 0xCE, 0x26, 0x12, 0x41, 0x6B, 0xAC, 0xA4, 0x64, 0x27, 0xBC, 0x97, 0x66, 0x41, 0xAE, 0x84, 0xBE, 0x88, 0xCD, 0x35, 0x15, 0xB5, 0xC7, 0xAA, 0x04, 0xE4, 0xA1, 0xDA, 0xB1, 0xC5, 0xE3, 0xC9, 0xC0, 0x1A, 0x2C, 0xD3, 0x9E, 0xF8, 0xA7, 0x7A, 0x43, 0xDC, 0x2B, 0x62, 0x48, 0x5F, 0x1A, 0x34, 0x42, 0x3C, 0x22, 0x49, 0x27, 0x07, 0x32, 0x4A, 0xB5, 0x83, 0x61, 0x22, 0x1B, 0xE0, 0x77, 0x54, 0x25, 0xB9, 0x11, 0x3A, 0x22, 0x3C, 0x42, 0x1E, 0x6C, 0x7D, 0xCB, 0x7A, 0x41, 0x06, 0x36, 0x1F, 0x2A, 0x4E, 0x24, 0x2E, 0x34, 0x76, 0x66, 0x9E, 0x27, 0x84, 0xF5, 0xB3, 0xE3, 0xF2, 0x08, 0xBF, 0x9A, 0x96, 0xC0, 0x59, 0x04, 0x57, 0x67, 0xB7, 0x68, 0x17, 0x39, 0x53, 0xBD, 0xDB, 0x72, 0x05, 0x49, 0x20, 0x0B, 0x29, 0x17, 0xC9, 0x0D, 0x50, 0x03, 0xFF, 0x5F, 0xE2, 0xD2, 0x92, 0x09, 0xAC, 0x0C, 0x82, 0xDE, 0xD5, 0x59, 0x64, 0x41, 0x94, 0xB5, 0x73, 0x33, 0xB3, 0x89, 0xB1, 0xCD, 0x05, 0xB1, 0x1E, 0xF8, 0xCD, 0xBA, 0xA3, 0xFE, 0xBB, 0x09, 0x33, 0x03, 0xEA, 0xB0, 0x84, 0xB8, 0x8D, 0xFD, 0x63, 0x39, 0x91, 0xAC, 0x42, 0x52, 0x28, 0x6C, 0x72, 0x08, 0x62, 0x73, 0xDA, 0x3B, 0xDC, 0x8A, 0xDF, 0x57, 0xAC, 0x6F, 0x7D, 0x53, 0x1E, 0x55, 0xA0, 0x6E, 0x4E, 0x65, 0x31, 0x52, 0x57, 0x35, 0x1C, 0xE7, 0xAC, 0x89, 0x5E, 0x50, 0x7B, 0x81, 0xFF, 0x35, 0x60, 0x9A, 0x71, 0x44, 0xF2, 0xD7, 0x22, 0x33, 0xBD, 0xBD, 0x22, 0x96, 0xCE, 0xD4, 0x7A, 0x00, 0xFF, 0x58, 0x24, 0x6A, 0x4A, 0xC1, 0x87, 0x55, 0x3F, 0xDB, 0xB2, 0x2B, 0x0F, 0x96, 0x5F, 0x6B, 0x11, 0xB3, 0xEE, 0xE6, 0x8D, 0x6B, 0xFC, 0xC4, 0xB9, 0x96, 0xFC, 0xA3, 0x7E, 0x88, 0x6F, 0x8C, 0x0E, 0x30, 0xDD, 0x15, 0x0D, 0xFA, 0x7D, 0xAB, 0xFE, 0x2E, 0xBD, 0xE4, 0x30, 0xA2, 0x3B, 0xAF, 0xCC, 0xA4, 0x1F, 0xD7, 0xCE, 0x02, 0x53, 0x28, 0x7F, 0x69, 0xB2, 0x20, 0xDB, 0xAA, 0xD2, 0x96, 0x4B, 0xBC, 0xE6, 0xB2, 0x67, 0x4D, 0x77, 0x05, 0xB1, 0xB9, 0x60, 0xC3, 0x80, 0xC8, 0x3E, 0xF9, 0x4F, 0x1D, 0x53, 0xFC, 0x2B, 0x5A, 0x69, 0x9A, 0x2B, 0x73, 0xF3, 0xAB, 0xA8, 0x2E, 0x50, 0xA4, 0x38, 0x1C, 0xD6, 0x81, 0x40, 0x9F, 0x65, 0xAE, 0xE6, 0x25, 0x78, 0x97, 0x72, 0x50, 0xB3, 0x18, 0x62, 0xB2, 0x63, 0x9B, 0xEE, 0x48, 0xC7, 0x95, 0xBA, 0x37, 0x2E, 0x96, 0xC9, 0x72, 0x2A, 0xEB, 0x8B, 0x14, 0x76, 0xC9, 0xD2, 0xDA, 0x52, 0x65, 0x64, 0x14, 0xA5, 0x46, 0x05, 0xE8, 0x7D, 0xDF, 0x1B, 0xAE, 0x82, 0x8B, 0x16, 0x15, 0xE8, 0xEC, 0xC0, 0xCF, 0x96, 0xEF, 0x35, 0xC7, 0xA0, 0x12, 0x6A, 0x82, 0xC6, 0x07, 0x32, 0x56, 0xDE, 0x6E, 0x14, 0x41, 0x51, 0x25, 0x73, 0xEA, 0xFF, 0x40, 0xFF, 0x64, 0x1F, 0xAB, 0x0B, 0x81, 0x17, 0x25, 0x3B, 0x98, 0x82, 0xE1, 0xBD, 0x91, 0x2C, 0x23, 0x82, 0x58, 0xF9, 0x0E, 0x1B, 0xE2, 0xE0, 0x0B, 0x8B, 0x06, 0xB4, 0x4F, 0x61, 0x1F, 0x86, 0x87, 0x66, 0x0D, 0xB4, 0x9F, 0x6A, 0xD0, 0x38, 0x42, 0x35, 0x95, 0xCD, 0x0D, 0x7C, 0x7C, 0x59, 0x71, 0x71, 0x7D, 0x28, 0x2E, 0xCA, 0xAA, 0xAA, 0x8D, 0xC0, 0x4E, 0x24, 0x26, 0xD7, 0x54, 0x60, 0xD5, 0x91, 0xBA, 0xEA, 0x83, 0xD8, 0x14, 0xBF, 0xF9, 0xFA, 0x5F, 0xAA, 0xE5, 0x8B, 0x2C, 0xB5, 0xDB, 0x91, 0x3C, 0xCB, 0x4B, 0x9A, 0x6E, 0xE8, 0x17, 0x35, 0x5A, 0x63, 0x07, 0x71, 0xCB, 0xB0, 0x7A, 0xF3, 0xEA, 0xF4, 0x42, 0xCF, 0xDA, 0x17, 0x86, 0xEE, 0x4C, 0x5F, 0x13, 0x5B, 0x7F, 0x35, 0xA1, 0xC3, 0x48, 0xEA, 0x12, 0x23, 0x4A, 0x0D, 0x5F, 0x34, 0x31, 0xBE, 0x14, 0x7D, 0x11, 0x9E, 0x64, 0xFF, 0x4B, 0xAB, 0x47, 0x0B, 0xE9, 0xCF, 0x35, 0xCD, 0xB0, 0x39, 0x85, 0xD4, 0x38, 0x41, 0xF6, 0x65, 0x36, 0x75, 0x29, 0x0D, 0x59, 0xF9, 0x4D, 0xB5, 0x51, 0x75, 0xE7, 0x32, 0xEA, 0x6A, 0x2E, 0xD4, 0xFA, 0x26, 0xAC, 0xA8, 0xBE, 0x56, 0x33, 0x2A, 0xFC, 0xA6, 0x21, 0x55, 0x7F, 0xC5, 0xFB, 0x8A, 0xEE, 0x25, 0xA9, 0xB6, 0xDB, 0xA6, 0x65, 0xAB, 0x9C, 0x68, 0x2F, 0x34, 0x75, 0xB0, 0x9D, 0xC5, 0x36, 0x8D, 0x33, 0xF8, 0xA8, 0x0C, 0xAF, 0xB5, 0x6C, 0x0F, 0x2A, 0xE0, 0x98, 0x2E, 0xB4, 0xD6, 0xA4, 0x37, 0xD5, 0xA8, 0x9A, 0x96, 0x25, 0xCC, 0xAB, 0x1E, 0xA9, 0xB7, 0x8D, 0x18, 0x6D, 0xF0, 0x34, 0xDE, 0xF6, 0xDE, 0xA9, 0x7B, 0xA9, 0x55, 0xD9, 0x7E, 0xD0, 0x26, 0xAA, 0xC7, 0xD0, 0x2A, 0x35, 0x52, 0x38, 0xD6, 0x22, 0x5C, 0xB3, 0x00, 0xDC, 0x92, 0x7F, 0x71, 0x99, 0x6F, 0x49, 0x70, 0xE6, 0xE9, 0xFE, 0x1B, 0x65, 0xA9, 0x29, 0x7B, 0x97, 0x14, 0x57, 0x06, 0x45, 0xDF, 0xEA, 0x3C, 0x59, 0x85, 0x06, 0x56, 0xB4, 0x86, 0xF0, 0x6E, 0xB9, 0xDF, 0xAF, 0xFF, 0x57, 0xB4, 0xDD, 0xE6, 0x46, 0xF5, 0x5D, 0xB9, 0x9E, 0x3A, 0x59, 0x87, 0x00, 0xEC, 0x85, 0x43, 0xDA, 0x69, 0xE0, 0x60, 0x81, 0xD5, 0xD2, 0x8B, 0x15, 0x51, 0x99, 0x37, 0xFA, 0x1A, 0x98, 0x03, 0x49, 0x81, 0x3D, 0xDE, 0x55, 0xC9, 0x51, 0x1B, 0x3A, 0x70, 0xDE, 0xE4, 0x20, 0xA0, 0x85, 0x2E, 0xB4, 0xF4, 0x18, 0xAE, 0x8F, 0x96, 0xA8, 0x6C, 0x27, 0x54, 0x77, 0x2A, 0x00, 0xEA, 0x0E, 0x1D, 0x0B, 0x38, 0x62, 0xBE, 0xF4, 0x3F, 0x6A, 0x6F, 0x7E, 0x5C, 0x7F, 0x7D, 0x55, 0x4B, 0xC6, 0x99, 0xDE, 0xCB, 0xDC, 0x7F, 0x13, 0x7B, 0xBA, 0xFF, 0xE2, 0x3F, 0x8F, 0x2A, 0x6F, 0x0F, 0x16, 0x4D, 0x0E, 0x3A, 0xDD, 0x9C, 0x2A, 0x89, 0xF7, 0x38, 0x52, 0xD7, 0x20, 0xFB, 0xC7, 0xD6, 0xBD, 0x3A, 0x58, 0xD9, 0x41, 0x53, 0xEB, 0xE2, 0x40, 0x07, 0x8B, 0x7D, 0xDA, 0xC9, 0xE0, 0xA5, 0x5C, 0x51, 0xDF, 0x28, 0xD1, 0xFD, 0x74, 0x62, 0x89, 0xB5, 0xC4, 0x33, 0x31, 0xBE, 0xB3, 0x57, 0xF2, 0x3C, 0xB2, 0xB1, 0x2D, 0x41, 0x56, 0x18, 0xB8, 0xAE, 0x29, 0x4E, 0x31, 0xDE, 0x23, 0xAA, 0xF6, 0xA0, 0x92, 0x63, 0x9B, 0x66, 0xB8, 0x0A, 0x1C, 0xA3, 0xCF, 0xD6, 0x31, 0x40, 0x23, 0xA5, 0x59, 0xF3, 0x1B, 0xBC, 0x9D, 0xFD, 0x72, 0xC9, 0x15, 0xC5, 0xBD, 0x34, 0xDF, 0xEE, 0x14, 0x65, 0x43, 0xDC, 0x8F, 0x8E, 0x26, 0xE5, 0xEE, 0x88, 0xDD, 0xAD, 0x22, 0xA0, 0x30, 0x90, 0xD6, 0x98, 0x07, 0x72, 0xDD, 0x7F, 0xD5, 0x8E, 0x05, 0x5F, 0xD8, 0xE2, 0x06, 0x31, 0xF8, 0x86, 0xEE, 0xA3, 0x7D, 0x0F, 0xDE, 0xA1, 0x74, 0x6B, 0x9E, 0x80, 0x57, 0xB2, 0x97, 0xF5, 0x9C, 0x45, 0xFB, 0xD3, 0x8A, 0xBA, 0xEC, 0xD0, 0x96, 0xD8, 0x9F, 0xED, 0x9D, 0xC8, 0xBB, 0xB0, 0x8E, 0x96, 0x33, 0xC8, 0x4E, 0xFF, 0xF6, 0x86, 0x7F, 0x90, 0x57, 0xEE, 0x8D, 0x26, 0x0D, 0x92, 0x69, 0x2B, 0x34, 0xD0, 0xA1, 0xAF, 0xB4, 0xCF, 0xDA, 0xFF, 0x41, 0x66, 0x94, 0x00, 0xCD, 0x09, 0x70, 0x67, 0xB6, 0xB6, 0x9B, 0xA1, 0x39, 0x91, 0x96, 0xD7, 0x71, 0x47, 0x13, 0x92, 0xE0, 0xD3, 0xFA, 0x88, 0x54, 0x46, 0xCC, 0x6D, 0x9E, 0x43, 0x64, 0xF9, 0xF1, 0x1B, 0xA8, 0xD8, 0x3F, 0x6E, 0x5A, 0x93, 0xA7, 0x6A, 0xB3, 0xCD, 0x61, 0xFD, 0x27, 0xF8, 0x2E, 0x2D, 0x5F, 0x3B, 0x0C, 0x79, 0x59, 0x0C, 0x68, 0xD6, 0x81, 0xEA, 0x8C, 0x1D, 0x5D, 0x36, 0x35, 0x4E, 0x29, 0xFB, 0x3A, 0xFC, 0x8C, 0x7E, 0xF1, 0x09, 0xAD, 0x12, 0xC3, 0xD6, 0x88, 0xDE, 0xA6, 0x0C, 0xDD, 0x76, 0xFF, 0x71, 0xF5, 0xA5, 0xE4, 0x57, 0xD7, 0x26, 0xD3, 0x38, 0xAC, 0xD7, 0xFA, 0x93, 0xFE, 0x39, 0x52, 0x43, 0xDD, 0xAB, 0x6D, 0x85, 0xBC, 0x2D, 0x16, 0x68, 0x3A, 0x40, 0xFF, 0xB4, 0x53, 0x9D, 0xC5, 0x0D, 0xD2, 0x94, 0x5F, 0xED, 0x37, 0x1B, 0x62, 0xE3, 0x5A, 0x5A, 0xC7, 0xD6, 0x0E, 0x46, 0x44, 0x37, 0xB9, 0x19, 0x15, 0xBE, 0x5F, 0xEA, 0x61, 0x5D, 0xBF, 0xF3, 0x90, 0xC9, 0x93, 0x98, 0x6B, 0x9D, 0xAE, 0x7F, 0x8B, 0xCE, 0xA2, 0xB2, 0xB4, 0x6A, 0xC8, 0xC7, 0xFC, 0x88, 0x06, 0x02, 0x47, 0xA5, 0x52, 0xD6, 0x08, 0x8B, 0x53, 0x12, 0xCC, 0x47, 0x72, 0x4B, 0x9F, 0x45, 0xD5, 0x0F, 0x3D, 0xA8, 0x30, 0x0B, 0x31, 0x5B, 0xBA, 0x88, 0x95, 0xEF, 0xD5, 0xDB, 0xBD, 0x8D, 0x6B, 0xE5, 0x34, 0xDC, 0xF2, 0xAF, 0x30, 0x99, 0x91, 0x6D, 0x02, 0x64, 0x0D, 0xE6, 0xCD, 0xFA, 0x23, 0xCA, 0xA7, 0x0B, 0x86, 0xB4, 0x47, 0xC0, 0xEC, 0x14, 0xF5, 0xAA, 0x93, 0xE5, 0xE2, 0xF8, 0x31, 0x2B, 0x2E, 0x56, 0xB6, 0x45, 0x9A, 0x06, 0x0F, 0xB3, 0x2E, 0x07, 0x95, 0xF4, 0xCF, 0xE0, 0xC8, 0xBC, 0x36, 0x76, 0x9D, 0xE6, 0x8B, 0x9D, 0xA2, 0x5A, 0x94, 0xA2, 0xCF, 0x0C, 0x2B, 0x13, 0x4F, 0x2E, 0xB3, 0xE8, 0xD0, 0x9F, 0x02, 0x68, 0x0B, 0xA3, 0xB4, 0x57, 0xC0, 0xC8, 0x14, 0x9F, 0x95, 0x27, 0xD8, 0x95, 0x71, 0xCD, 0xCB, 0xBF, 0x72, 0xC0, 0x28, 0xC6, 0xC0, 0xEB, 0xFF, 0x5A, 0xE1, 0xD0, 0xDB, 0x2A, 0x58, 0xE8, 0x3D, 0xBA, 0xF3, 0xBC, 0x28, 0xD3, 0xF1, 0x6C, 0xF3, 0x72, 0xA9, 0x9D, 0xE5, 0x1A, 0x93, 0x95, 0xA2, 0x8C, 0x72, 0x54, 0x7F, 0x02, 0x48, 0xB3, 0x68, 0xD3, 0xBE, 0x06, 0x9D, 0x52, 0x96, 0xAE, 0x40, 0xF9, 0x6B, 0xE2, 0x2A, 0x87, 0xEE, 0x0A, 0x27, 0x47, 0x6A, 0x97, 0x6A, 0x45, 0x03, 0x41, 0x76, 0x4B, 0xF6, 0x48, 0xC6, 0x79, 0x5D, 0xE8, 0x68, 0x96, 0x1E, 0x76, 0x4C, 0x69, 0x92, 0xC8, 0x77, 0xD1, 0xEF, 0xD5, 0xAC, 0x57, 0x26, 0x52, 0xD9, 0xFA, 0xED, 0x80, 0x9C, 0x16, 0xA1, 0xFD, 0x04, 0x52, 0x52, 0x42, 0x86, 0x95, 0xD2, 0xA0, 0x58, 0xCD, 0x60, 0x92, 0x2C, 0x3C, 0x3C, 0xA4, 0x9F, 0x23, 0x6F, 0x0F, 0xF8, 0xDA, 0xF3, 0x51, 0x61, 0xE9, 0xF5, 0xAD, 0xBD, 0x49, 0xF1, 0xCD, 0xE9, 0x4F, 0xC3, 0x2B, 0x80, 0xC1, 0x28, 0x31, 0xDE, 0x05, 0x3A, 0xA8, 0x4A, 0x7D, 0x3A, 0xF0, 0x90, 0x12, 0xAF, 0x3D, 0x0E, 0x4E, 0x4B, 0xDA, 0x33, 0x74, 0x0C, 0x7C, 0x13, 0xF3, 0xBF, 0x81, 0xAB, 0x90, 0x4B, 0x58, 0x7A, 0x9F, 0x01, 0x62, 0x06, 0x04, 0xF6, 0x4C, 0x85, 0x2A, 0x3C, 0x6F, 0xB5, 0xDD, 0x85, 0xBC, 0x9C, 0xDE, 0x36, 0xB8, 0x40, 0x51, 0x56, 0xCE, 0xC6, 0x2C, 0x70, 0x19, 0xD5, 0x4F, 0xF7, 0x09, 0xF4, 0xB0, 0x70, 0xD5, 0x92, 0xE0, 0xE8, 0x64, 0xCF, 0x65, 0x13, 0x70, 0xFB, 0xD8, 0x47, 0x4B, 0xE7, 0xE3, 0x79, 0xE1, 0x9B, 0x7A, 0xED, 0x30, 0x6E, 0xC0, 0xBC, 0x2E, 0x85, 0xDA, 0xC2, 0xFD, 0x6E, 0xEB, 0x59, 0xB4, 0x77, 0xD1, 0xEE, 0x06, 0x2D, 0xE2, 0xC8, 0x38, 0x6D, 0x0C, 0x83, 0x04, 0x94, 0x0F, 0xBA, 0x4D, 0x60, 0x96, 0xF9, 0x35, 0xAD, 0x07, 0x70, 0x2B, 0xC9, 0x7C, 0x60, 0xBF, 0xFE, 0x59, 0x0C, 0xD2, 0xFF, 0x4D, 0x3F, 0x25, 0x3C, 0x78, 0x09, 0x47, 0xEB, 0xEB, 0x7F, 0xBC, 0x53, 0x42, 0x7C, 0x75, 0x0F, 0x6E, 0x1D, 0xC0, 0x70, 0x87, 0x94, 0x86, 0xE7, 0xE8, 0x1D, 0x46, 0x88, 0x31, 0x09, 0xFA, 0x43, 0xD9, 0xAE, 0xAB, 0x01, 0xD3, 0xCD, 0x77, 0x69, 0x3E, 0x01, 0x4B, 0x92, 0xD6, 0x0E, 0x04, 0xD4, 0x1E, 0x8D, 0x5E, 0xDE, 0x0F, 0x1B, 0xAF, 0x84, 0xE5, 0x2F, 0xF1, 0x37, 0x2C, 0xF6, 0xFF, 0xD8, 0xB1, 0x5E, 0x47, 0x71, 0xEF, 0x6D, 0xBD, 0x47, 0x52, 0x1D, 0xBE, 0x36, 0xBC, 0x51, 0x57, 0x30, 0xE6, 0x19, 0xA3, 0x61, 0x31, 0x45, 0xAB, 0xE3, 0x81, 0xE1, 0xE6, 0x0D, 0x9A, 0x13, 0x40, 0xD6, 0xF2, 0xEE, 0x8A, 0x8C, 0x8C, 0xF7, 0x5D, 0xB3, 0x99, 0x7B, 0xF2, 0xA6, 0x1B, 0xD6, 0x54, 0x8D, 0x94, 0xC4, 0xCA, 0x4F, 0xF0, 0x56, 0x56, 0x3E, 0x29, 0x33, 0x88, 0x62, 0xB8, 0x59, 0x89, 0x4D, 0xB2, 0x0D, 0xA2, 0x34, 0xEF, 0x40, 0x68, 0x44, 0x5E, 0x6E, 0x9F, 0xA9, 0x12, 0x02, 0xB1, 0x8C, 0x5B, 0xD8, 0x64, 0x50, 0x3B, 0xEC, 0x5F, 0xAC, 0x2F, 0x2E, 0xED, 0x78, 0x52, 0x36, 0x52, 0x9E, 0xA7, 0x5B, 0xC3, 0xBC, 0xC1, 0x8E, 0x52, 0x5C, 0xE3, 0x6C, 0xE4, 0xEE, 0x2D, 0xDD, 0x22, 0x38, 0x26, 0xDC, 0x9A, 0x70, 0x42, 0x66, 0x29, 0xCD, 0xF3, 0x9E, 0x0E, 0x15, 0x28, 0x43, 0xED, 0x5E, 0xA9, 0x62, 0xC0, 0x34, 0x46, 0x96, 0xFA, 0x3B, 0xE4, 0x3A, 0x50, 0x92, 0xD7, 0xCD, 0x5D, 0xDA, 0x7A, 0xB9, 0xC8, 0xC8, 0xEF, 0xD6, 0x5A, 0x97, 0x0F, 0x88, 0xFE, 0x95, 0x05, 0xB3, 0xE3, 0x24, 0x23, 0x25, 0x22, 0xBE, 0xB3, 0x8C, 0x95, 0xE0, 0x21, 0xF9, 0xAC, 0x38, 0xE7, 0x4D, 0x07, 0x8F, 0x82, 0x91, 0x76, 0x2D, 0x2A, 0x2A, 0x54, 0x62, 0x79, 0x42, 0xFD, 0x13, 0x3A, 0xDB, 0x3F, 0x3F, 0xFB, 0x91, 0x72, 0x57, 0x4B, 0x64, 0xFE, 0x3F, 0xCA, 0x3A, 0x72, 0x4F, 0xA9, 0x1F, 0x38, 0x57, 0xDC, 0xC3, 0x8C, 0x01, 0x9F, 0x14, 0x1B, 0xB8, 0x4D, 0xE0, 0xB5, 0xF8, 0x7B, 0xE2, 0x25, 0x50, 0xBF, 0xD7, 0x0D, 0xB0, 0x08, 0xF6, 0xB6, 0xB3, 0x55, 0xCD, 0x82, 0xFD, 0x2C, 0xC3, 0xB1, 0xB9, 0xB0, 0x47, 0xAF, 0x5F, 0xC6, 0x66, 0x22, 0xB9, 0x69, 0x6D, 0xAE, 0x27, 0x1E, 0x83, 0x47, 0x15, 0x5D, 0xC7, 0x1E, 0x8A, 0x36, 0x54, 0x84, 0x63, 0x9E, 0xC5, 0x33, 0x38, 0x93, 0xD4, 0x1B, 0xE2, 0xE3, 0x45, 0x35, 0x2A, 0xC2, 0xEB, 0x18, 0xF0, 0x0B, 0x9D, 0x6E, 0xBB, 0x56, 0x35, 0x13, 0xBE, 0x49, 0xDF, 0x85, 0x05, 0xC1, 0x05, 0x3D, 0x59, 0xA9, 0xF7, 0x4C, 0x50, 0xC3, 0xEC, 0xEC, 0x6A, 0xE3, 0xA0, 0xBA, 0xB9, 0xB0, 0xC4, 0x70, 0x45, 0x58, 0x58, 0xD6, 0xAE, 0x8F, 0x29, 0x24, 0xD9, 0xDB, 0xB5, 0x78, 0xCC, 0x46, 0xE1, 0x51, 0x82, 0xE7, 0xF1, 0x06, 0xE8, 0x57, 0xED, 0xB0, 0x79, 0xAF, 0x9A, 0x87, 0x88, 0xE8, 0x1C, 0x8C, 0x03, 0x83, 0xDD, 0x91, 0xC9, 0x45, 0xED, 0x44, 0x6D, 0x7B, 0x26, 0xA3, 0xE5, 0xAD, 0x4A, 0x99, 0xFF, 0xBF, 0xA6, 0x78, 0x41, 0x58, 0xA9, 0x53, 0xFD, 0x9B, 0x82, 0x02, 0x96, 0xC4, 0x94, 0xBF, 0xB8, 0x5A, 0x68, 0xAB, 0xCF, 0x73, 0xEF, 0x06, 0x6A, 0xB1, 0xB7, 0x36, 0x42, 0x95, 0x2B, 0xEA, 0x45, 0xF7, 0xC7, 0x3A, 0xE1, 0xBE, 0xAE, 0xFC, 0xC4, 0xB7, 0x4B, 0xD5, 0xA6, 0xEA, 0x74, 0x4D, 0x2F, 0x0D, 0xB9, 0x9B, 0x37, 0xBD, 0x6B, 0x1F, 0xBF, 0xB9, 0xF8, 0x53, 0xFB, 0x82, 0xFC, 0x1F, 0xCC, 0xE1, 0xA6, 0x09, 0x31, 0x16, 0x02, 0xA8, 0x26, 0xD6, 0x7D, 0x27, 0x10, 0x49, 0x3C, 0xB0, 0x49, 0x56, 0x79, 0xA3, 0xB7, 0xE8, 0x53, 0xB0, 0x83, 0xF0, 0x8E, 0xB6, 0xD6, 0xC4, 0x8D, 0x23, 0x62, 0x63, 0x76, 0x5A, 0xDB, 0xF2, 0x70, 0xF8, 0x9F, 0x9C, 0x5B, 0x4B, 0xF7, 0x70, 0x7F, 0x15, 0xBD, 0xE9, 0xC1, 0xF2, 0x36, 0x31, 0xED, 0xDB, 0x3C, 0xA3, 0xEA, 0x05, 0x61, 0xB5, 0xD5, 0x1E, 0xBB, 0x94, 0xEB, 0x35, 0xD5, 0x36, 0x56, 0x2A, 0x77, 0x55, 0x34, 0x6D, 0x17, 0xF6, 0x12, 0xDE, 0xDA, 0x7B, 0x8D, 0x53, 0x95, 0x25, 0x6E, 0xAA, 0xE0, 0xFE, 0x2F, 0x7F, 0x0F, 0xDE, 0xC9, 0x6F, 0x29, 0x4D, 0x12, 0xDB, 0x08, 0x9F, 0x33, 0x25, 0x45, 0x9F, 0xA4, 0x33, 0xB9, 0xF5, 0x31, 0x43, 0xCA, 0x19, 0xA2, 0x36, 0xCF, 0x71, 0x48, 0x80, 0xBC, 0xC9, 0xEE, 0x2F, 0x75, 0x29, 0x90, 0x61, 0x79, 0x15, 0xDB, 0x09, 0xE2, 0x3D, 0x37, 0x98, 0x85, 0xC5, 0x7F, 0x1A, 0x3E, 0xB3, 0x8B, 0x2A, 0x62, 0xB0, 0xCF, 0xDC, 0x24, 0xF6, 0x11, 0xD1, 0x1E, 0x41, 0x28, 0x2F, 0xA9, 0x48, 0x28, 0x3E, 0x2A, 0xBC, 0x1C, 0xD7, 0xA1, 0xB0, 0x97, 0x96, 0x7A, 0xE6, 0xC3, 0xA7, 0x94, 0x7E, 0xB6, 0x3B, 0xD4, 0x01, 0x60, 0xAC, 0x65, 0x11, 0xB6, 0x19, 0xB2, 0xEE, 0xDC, 0x50, 0x7A, 0x8F, 0x1B, 0x5B, 0xBF, 0xAE, 0x62, 0x27, 0xBF, 0x54, 0xDD, 0xCD, 0xAE, 0x15, 0xE5, 0x08, 0x84, 0xBC, 0xBF, 0x25, 0x60, 0x21, 0x43, 0xE4, 0x22, 0xEB, 0x8A, 0xBB, 0x2D, 0x9F, 0xA6, 0x38, 0xE2, 0xA9, 0x83, 0x63, 0xC0, 0x85, 0xB6, 0x88, 0x7A, 0x1E, 0xB4, 0x98, 0xFE, 0x1E, 0xDB, 0x09, 0x1D, 0x68, 0x73, 0x2D, 0x52, 0x29, 0x66, 0x98, 0x1A, 0x4A, 0x2F, 0x2A, 0xD3, 0x54, 0x73, 0x98, 0x53, 0x81, 0xB9, 0xFC, 0x50, 0xCE, 0x74, 0xE0, 0x6B, 0xC1, 0x1C, 0x81, 0x11, 0x3C, 0x1C, 0x7B, 0x5A, 0xFA, 0x08, 0x52, 0x79, 0x2E, 0x80, 0xEE, 0x43, 0x3F, 0x6D, 0xED, 0xD5, 0x93, 0x61, 0x0A, 0x7D, 0x29, 0x76, 0x1E, 0xB6, 0x6B, 0xF9, 0x3B, 0x7F, 0x10, 0x5B, 0x60, 0x0C, 0x2A, 0x8E, 0xC1, 0x62, 0xE1, 0x91, 0xF2, 0x67, 0xD8, 0x02, 0x9E, 0x81, 0x5D, 0xA2, 0xE6, 0xE7, 0x33, 0xF9, 0x8E, 0xAA, 0x3F, 0x31, 0x42, 0xC9, 0x43, 0x55, 0xA2, 0x47, 0x22, 0xD4, 0x84, 0x1C, 0xB3, 0xD9, 0xA4, 0x9E, 0x0A, 0x1F, 0xA3, 0x27, 0x63, 0x1F, 0xE1, 0xDC, 0xE6, 0x80, 0xDC, 0x42, 0xE3, 0x5F, 0x86, 0xEF, 0x85, 0x09, 0x86, 0x0F, 0x10, 0x5A, 0x36, 0x5E, 0xBF, 0x89, 0x7B, 0x95, 0x79, 0x58, 0xFB, 0x30, 0x6F, 0x09, 0x6F, 0x81, 0xA6, 0x64, 0x71, 0xA5, 0x24, 0x9E, 0x98, 0xE9, 0x1E, 0x09, 0xA5, 0xAB, 0xAA, 0x6D, 0x6C, 0xD4, 0xB3, 0x91, 0x22, 0xDA, 0x1F, 0xDC, 0x0C, 0x96, 0x34, 0x51, 0xB2, 0x2E, 0xB4, 0xC8, 0xF5, 0x21, 0xF9, 0x86, 0xA6, 0x16, 0x30, 0xA7, 0xA4, 0xA4, 0xE1, 0x0C, 0x47, 0x59, 0xC9, 0xAF, 0x0B, 0xC8, 0xAD, 0xE3, 0x4E, 0x36, 0xDE, 0x8C, 0xAE, 0x13, 0x2F, 0xD3, 0x31, 0xDD, 0x00, 0x68, 0x21, 0x86, 0x58, 0x1F, 0x50, 0x5B, 0x20, 0xBF, 0x69, 0x67, 0xF1, 0x10, 0x58, 0xD3, 0xB0, 0x2F, 0xB3, 0xA1, 0x17, 0xD3, 0xAE, 0xC9, 0x5B, 0xD0, 0x3D, 0xA0, 0x7C, 0x5D, 0x3C, 0xAB, 0x83, 0xA8, 0xAA, 0xAC, 0x88, 0x6F, 0xB5, 0xC8, 0x79, 0xCC, 0xB1, 0x6E, 0x58, 0x19, 0xB5, 0x4B, 0x3C, 0xDB, 0xE8, 0xEA, 0xE6, 0x01, 0xDE, 0x20, 0x3C, 0xAC, 0x8F, 0xA8, 0xCD, 0xD0, 0x3A, 0xDA, 0x5B, 0x3C, 0x07, 0x6E, 0xAD, 0x3B, 0x93, 0x39, 0x75, 0xC5, 0x02, 0x0D, 0x98, 0xB3, 0x71, 0xD9, 0x4D, 0x45, 0x5D, 0xE1, 0xF5, 0xBE, 0x6C, 0xF6, 0xBC, 0xF2, 0xAC, 0xAE, 0xFB, 0x39, 0xE3, 0xAA, 0xB4, 0xAD, 0xD1, 0x91, 0x2F, 0x44, 0x5B, 0x6B, 0xFD, 0xDD, 0xC4, 0x60, 0x13, 0xB9, 0xDA, 0x66, 0x9E, 0x7A, 0x9A, 0x6A, 0x3C, 0x3D, 0x1D, 0xE7, 0xC0, 0x03, 0xCD, 0xAD, 0x62, 0x51, 0xF6, 0x3E, 0xDD, 0x11, 0xF1, 0xB9, 0x82, 0xD3, 0x20, 0x2C, 0x9D, 0x5D, 0xA6, 0xE2, 0x21, 0x32, 0x13, 0x6B, 0x42, 0x9E, 0x49, 0x71, 0x92, 0xFB, 0x34, 0xAA, 0x0E, 0x7C, 0x26, 0xDA, 0xE5, 0xB6, 0x0D, 0x7D, 0x27, 0x5F, 0x6D, 0x53, 0x80, 0xF1, 0x80, 0x62, 0xBA, 0x0A, 0x47, 0x41, 0xA2, 0x71, 0x17, 0xFF, 0x66, 0x89, 0xAB, 0x76, 0xAF, 0xE0, 0x67, 0xC5, 0x39, 0x00, 0x13, 0xDD, 0x67, 0xFF, 0xE1, 0x04, 0x49, 0x3E, 0xF1, 0x9C, 0x73, 0x77, 0xCB, 0xF5, 0xC2, 0x5D, 0x8B, 0x11, 0xE0, 0x91, 0x34, 0xD6, 0x3D, 0x18, 0xC5, 0x95, 0xD6, 0x36, 0x31, 0x58, 0x22, 0x18, 0x40, 0x0F, 0xC4, 0x31, 0xC8, 0xAC, 0x6E, 0x72, 0xD5, 0x4B, 0x0E, 0x4B, 0x9B, 0xC8, 0xBD, 0xC4, 0x27, 0x95, 0x37, 0x04, 0xA8, 0xF0, 0x10, 0xBB, 0x5C, 0x3C, 0x43, 0xF2, 0x77, 0x4E, 0x9B, 0xF4, 0x87, 0x2C, 0x27, 0x26, 0x4B, 0x79, 0x57, 0x21, 0x72, 0xC7, 0xD1, 0xC9, 0xC0, 0x3D, 0x1B, 0x6F, 0xCC, 0x0D, 0xB2, 0xA7, 0x4F, 0xC6, 0x8D, 0xD0, 0xFA, 0x9A, 0x14, 0x66, 0xA3, 0xCC, 0x89, 0x68, 0x60, 0x5F, 0x55, 0xC4, 0x2B, 0x78, 0xDC, 0x4F, 0x4A, 0x2A, 0xAB, 0x46, 0x38, 0x13, 0x08, 0xC8, 0xF6, 0x96, 0xA4, 0x80, 0x79, 0xD1, 0x22, 0xC5, 0x31, 0x68, 0x86, 0xFB, 0x54, 0x64, 0x2D, 0xB4, 0xDE, 0x66, 0x1A, 0x66, 0x03, 0x7D, 0xA7, 0xBD, 0xC7, 0xFB, 0xE1, 0xF9, 0x86, 0x67, 0x15, 0x81, 0xE8, 0x1F, 0x7C, 0x36, 0x93, 0xAF, 0x8A, 0x93, 0x6D, 0xAA, 0x3A, 0xAB, 0x8A, 0x67, 0x6E, 0xE7, 0xF3, 0x54, 0x69, 0x59, 0x17, 0xC5, 0x81, 0x2A, 0x6A, 0xE4, 0x15, 0xC5, 0x64, 0x74, 0xC0, 0xCD, 0x1A, 0xE1, 0x23, 0x02, 0xEB, 0x4D, 0x98, 0x2D, 0xBC, 0x8C, 0x76, 0x12, 0xDF, 0x0D, 0xC7, 0xEB, 0xEF, 0x95, 0x4D, 0xD5, 0xA7, 0x62, 0x36, 0x15, 0xAD, 0xBA, 0x26, 0x49, 0x2C, 0x9B, 0xA1, 0x3D, 0x57, 0xD9, 0xC5, 0xFD, 0xAA, 0xD9, 0x9F, 0x15, 0x23, 0x8A, 0x26, 0x33, 0x23, 0xE3, 0xE5, 0x4A, 0x3C, 0xCA, 0x55, 0x8A, 0xF8, 0xA8, 0x68, 0xD6, 0xB1, 0x98, 0x23, 0xE2, 0x4A, 0x33, 0xE2, 0xD7, 0xE1, 0x7C, 0xDD, 0xE5, 0xE2, 0x9D, 0x8D, 0xD1, 0xE8, 0x9A, 0xB2, 0x1B, 0x0D, 0x0B, 0x45, 0x3A, 0x66, 0x6F, 0x5D, 0x5D, 0x45, 0x30, 0x67, 0x8D, 0xA9, 0x3C, 0xD3, 0x43, 0x98, 0x5C, 0x9D, 0x16, 0xB1, 0x56, 0x76, 0x52, 0xEB, 0xE2, 0xF2, 0x10, 0xFE, 0xA0, 0xBE, 0x6A, 0xF5, 0x15, 0x73, 0x40, 0x36, 0xD2, 0x4A, 0xF0, 0x0F, 0x70, 0x9E, 0xB6, 0xB4, 0x28, 0xAE, 0x6B, 0x08, 0xF9, 0x5D, 0x6A, 0xEA, 0x58, 0x29, 0x9E, 0x59, 0x99, 0xDE, 0xDA, 0x5A, 0x9E, 0x5B, 0xD5, 0xD8, 0x94, 0x96, 0xBE, 0x59, 0x20, 0xA9, 0xCB, 0x0A, 0x63, 0xC8, 0x42, 0x0C, 0x02, 0x17, 0x6F, 0x78, 0x35, 0x9E, 0x6C, 0x3D, 0x05, 0x33, 0x47, 0x6D, 0x68, 0xCB, 0x89, 0xD1, 0x70, 0xA1, 0xB6, 0xA1, 0xE0, 0xE7, 0xB2, 0xBB, 0x68, 0x48, 0xF1, 0xE7, 0x7E, 0xAD, 0x70, 0x7F, 0xC5, 0xF8, 0x9E, 0xF2, 0xD2, 0xC5, 0x6C, 0xA4, 0xFD, 0x62, 0xBA, 0x1D, 0xDF, 0xD8, 0x3C, 0x2A, 0x4C, 0x20, 0x3D, 0x5C, 0xD3, 0xE6, 0x6A, 0x01, 0xA7, 0x11, 0xFB, 0xAC, 0x07, 0xB1, 0xBF, 0xD0, 0x76, 0xBA, 0x13, 0x31, 0x11, 0xAE, 0x34, 0x24, 0x02, 0xC9, 0x39, 0x6F, 0x11, 0x47, 0x20, 0xAF, 0x28, 0x4E, 0x18, 0x09, 0xAC, 0x2F, 0x9F, 0x53, 0x7E, 0x14, 0xE4, 0xB3, 0x72, 0x33, 0x0E, 0x41, 0xCF, 0x78, 0x8E, 0x11, 0xD6, 0xC8, 0x4D, 0xD1, 0x6A, 0x97, 0x3E, 0xF5, 0x7A, 0xB9, 0xD1, 0x6A, 0x35, 0x2E, 0x05, 0x52, 0x68, 0x93, 0x09, 0x4F, 0x50, 0xA5, 0x1B, 0x23, 0x8F, 0x28, 0xE9, 0x06, 0x87, 0xE5, 0x6B, 0x2A, 0x06, 0x04, 0x0F, 0x14, 0x37, 0xD8, 0x7B, 0xCA, 0xBE, 0x00, 0x93, 0xB8, 0x4F, 0xD3, 0x7F, 0x80, 0x43, 0x42, 0x30, 0xC2, 0x1A, 0xFE, 0x28, 0x9D, 0xE5, 0xB2, 0x47, 0x9D, 0xA6, 0xF8, 0x64, 0x75, 0x08, 0x2F, 0x00, 0x2D, 0x69, 0x74, 0x22, 0x00, 0x9A, 0x82, 0xB7, 0x4A, 0x16, 0x54, 0xE9, 0xC0, 0x65, 0xD2, 0x99, 0xBC, 0x41, 0x81, 0x99, 0xEC, 0xB4, 0x90, 0x5E, 0x1A, 0xAA, 0x48, 0x12, 0x8F, 0xA4, 0x9D, 0x03, 0x62, 0xA5, 0x6B, 0x22, 0xCC, 0xE1, 0x89, 0xF2, 0xE7, 0x2E, 0x97, 0x54, 0x2F, 0x81, 0x0E, 0xAB, 0x7B, 0x78, 0x14, 0x34, 0x96, 0x16, 0x46, 0x44, 0x41, 0x3D, 0xD8, 0x0C, 0xE1, 0x28, 0x49, 0x13, 0x70, 0x5E, 0xA4, 0x96, 0xFD, 0xCD, 0xBF, 0x27, 0x11, 0xC9, 0xB7, 0x95, 0xBC, 0x90, 0x11, 0xCA, 0xF0, 0xB4, 0x79, 0x8A, 0x6F, 0x40, 0x71, 0xF8, 0x3C, 0xC8, 0x09, 0x8C, 0x72, 0x59, 0xAB, 0xEA, 0x82, 0x52, 0xAC, 0xDE, 0xE0, 0xBE, 0xD0, 0x3F, 0xB4, 0x7C, 0x22, 0x13, 0xFA, 0x8D, 0x26, 0xF0, 0x0E, 0xC1, 0x4C, 0xC5, 0x6B, 0x41, 0x39, 0xBC, 0x81, 0x07, 0x8B, 0x96, 0x20, 0x85, 0xC5, 0x27, 0x24, 0x3F, 0x90, 0x13, 0xA9, 0xC5, 0xF2, 0xBB, 0xC8, 0xCB, 0x30, 0x03, 0x68, 0x44, 0x36, 0xBA, 0x14, 0xAA, 0x8A, 0xE0, 0x2F, 0x56, 0xA7, 0x71, 0x2F, 0x98, 0x43, 0x8B, 0x27, 0x38, 0xB0, 0x03, 0xFC, 0x88, 0x53, 0x4D, 0xBE, 0x97, 0x2D, 0xE7, 0x2D, 0x27, 0x2F, 0x72, 0x68, 0x42, 0x57, 0x12, 0x28, 0x8A, 0x10, 0xAF, 0x22, 0xE7, 0xA4, 0x0C, 0xC8, 0xEE, 0xE1, 0xDF, 0xC3, 0xD2, 0x80, 0xD7, 0x98, 0x97, 0xCB, 0x18, 0x95, 0x3D, 0x5A, 0x63, 0xA5, 0xC3, 0x7D, 0xE0, 0x07, 0xB4, 0x59, 0x04, 0x09, 0x3B, 0x21, 0xF9, 0x6C, 0x69, 0x9D, 0x9D, 0xF4, 0x27, 0xE7, 0x74, 0xED, 0x16, 0x76, 0x39, 0x5F, 0x6A, 0xF2, 0x2E, 0xC8, 0x10, 0xE5, 0x19, 0x9D, 0x92, 0x35, 0xD2, 0xAF, 0xFA, 0x25, 0xA1, 0x20, 0x10, 0x45, 0xDE, 0x72, 0x2E, 0x40, 0x1F, 0xAB, 0x67, 0x5B, 0x39, 0xE1, 0xEE, 0x48, 0x2C, 0xF5, 0x0E, 0xD1, 0x09, 0xCF, 0x07, 0x8F, 0xB1, 0xA0, 0xB6, 0x65, 0xD2, 0xE3, 0x55, 0x8F, 0x5B, 0xF7, 0xB3, 0x6D, 0x79, 0x79, 0x4D, 0xEF, 0xF2, 0xAE, 0x09, 0xB1, 0x7A, 0x45, 0xE2, 0x61, 0xE9, 0xA2, 0x9A, 0x17, 0x41, 0xBB, 0x94, 0x23, 0xBA, 0x4D, 0x4E, 0x5B, 0xD0, 0x1A, 0xAC, 0xDC, 0xCA, 0x1A, 0xB7, 0x40, 0x06, 0xA9, 0x5F, 0x89, 0x41, 0x78, 0x3C, 0x50, 0xC9, 0x8C, 0xEF, 0x1D, 0x96, 0xCE, 0x67, 0x5F, 0xE8, 0x59, 0xC1, 0xEC, 0xE4, 0x6A, 0x3B, 0x9D, 0x73, 0xD3, 0x04, 0xCA, 0x16, 0x2C, 0x61, 0xA6, 0xF8, 0x41, 0xFD, 0x3F, 0xC1, 0xAE, 0x8A, 0x3B, 0xD5, 0x4C, 0xD7, 0x71, 0xC8, 0x15, 0xFC, 0x96, 0xD5, 0x11, 0xEC, 0x03, 0x3A, 0x9E, 0x36, 0x9F, 0x58, 0x0B, 0x7D, 0x43, 0x8B, 0xD4, 0x9E, 0xB9, 0x56, 0xD2, 0x12, 0x55, 0x5B, 0x51, 0x2F, 0xAB, 0x47, 0xE5, 0x59, 0x9E, 0x99, 0xBF, 0x42, 0x05, 0xB2, 0x8A, 0x92, 0x2C, 0xD4, 0x54, 0xDE, 0xE8, 0x90, 0x58, 0xF5, 0x6D, 0x51, 0x99, 0x13, 0x13, 0x2F, 0x91, 0x87, 0x32, 0xEC, 0x89, 0x02, 0xC0, 0x83, 0x72, 0x89, 0x38, 0x0E, 0x2A, 0xA0, 0x1A, 0xE4, 0x7C, 0x89, 0x5E, 0xF4, 0x19, 0x71, 0xAF, 0xF8, 0x8B, 0x95, 0x8E, 0x8C, 0xB0, 0xCE, 0xE6, 0x5F, 0x41, 0xA7, 0x73, 0x89, 0xC4, 0x47, 0xE8, 0x75, 0xA1, 0x75, 0xB0, 0x40, 0xBD, 0x40, 0xB2, 0xC3, 0xC9, 0x1F, 0xFF, 0x5B, 0xB1, 0x89, 0x51, 0x42, 0xC4, 0x80, 0xA3, 0xA8, 0xEE, 0xC4, 0x29, 0xF0, 0xBB, 0xE2, 0x34, 0x64, 0xCB, 0xFE, 0x9F, 0xB0, 0x18, 0x9A, 0xC6, 0x9D, 0xC6, 0x14, 0x40, 0x67, 0xF9, 0xBF, 0xF3, 0x6A, 0xE1, 0x0A, 0xD1, 0x95, 0x84, 0xAF, 0x48, 0xBF, 0x74, 0x46, 0xD0, 0x65, 0x55, 0xB2, 0x9C, 0xE5, 0x14, 0x86, 0xED, 0x02, 0xE2, 0x18, 0xAB, 0x09, 0x37, 0xF0, 0x3A, 0xB5, 0x9D, 0x38, 0x0B, 0xE1, 0x72, 0x9E, 0xE2, 0xBB, 0x78, 0x8C, 0xA0, 0x5A, 0x79, 0x4A, 0xB2, 0xAE, 0x62, 0x00, 0x38, 0x22, 0xFB, 0x9E, 0xFB, 0x07, 0x1A, 0xA3, 0x98, 0x95, 0xA0, 0x84, 0x07, 0x95, 0x61, 0x41, 0xDB, 0xD1, 0x4E, 0x00, 0x77, 0xEA, 0xC5, 0x78, 0xE0, 0x73, 0xC6, 0x4F, 0x82, 0x0A, 0xB5, 0x51, 0x6F, 0x10, 0xD7, 0xA0, 0xEB, 0xD2, 0x71, 0xF2, 0x30, 0xD0, 0x9F, 0xF7, 0x49, 0xFE, 0x19, 0x9A, 0x56, 0x1E, 0xAF, 0x9C, 0x07, 0x3D, 0xCF, 0x69, 0x04, 0x1A, 0xE1, 0xF0, 0x78, 0x16, 0x64, 0x84, 0x9B, 0x83, 0xC7, 0x22, 0xDF, 0xE1, 0x9D, 0x4E, 0xAF, 0x31, 0x17, 0x58, 0x66, 0x35, 0x9F, 0x58, 0x00, 0x5B, 0x52, 0xEF, 0x12, 0xCF, 0xA0, 0xEF, 0xE2, 0xF7, 0x52, 0x6F, 0x7C, 0x88, 0x73, 0x4B, 0x56, 0x89, 0xDF, 0x28, 0x8D, 0x91, 0x37, 0xE1, 0xD1, 0x59, 0x4C, 0xA5, 0x0F, 0x6E, 0x16, 0x97, 0x03, 0x56, 0x63, 0xEE, 0xC1, 0xB3, 0x90, 0x72, 0xD5, 0x17, 0xA7, 0x8D, 0xEA, 0x1F, 0xC8, 0x5D, 0xC6, 0x0D, 0xC2, 0x0C, 0xD6, 0x52, 0x57, 0x12, 0x7F, 0xA0, 0xD7, 0x12, 0x47, 0x71, 0x45, 0x4D, 0x07, 0xFB, 0xB4, 0xE4, 0xA9, 0x31, 0xB3, 0xB8, 0x57, 0x16, 0x64, 0x78, 0x9A, 0xA1, 0x53, 0xB8, 0xE8, 0x97, 0xC4, 0x5E, 0x03, 0x86, 0xB4, 0x35, 0x41, 0xFF, 0x83, 0xD7, 0x10, 0x90, 0xE3, 0x07, 0xF5, 0x1E, 0x55, 0x38, 0x23, 0xF7, 0xBF, 0x5D, 0x67, 0xA8, 0x09, 0xE4, 0x02, 0xE8, 0x88, 0x88, 0x2E, 0x5A, 0xD8, 0x3C, 0x86, 0xE3, 0x2B, 0x5E, 0xDE, 0x68, 0x28, 0x71, 0x97, 0x66, 0xD4, 0x6F, 0xC9, 0xE8, 0x91, 0xAB, 0x6B, 0x27, 0xC7, 0x5C, 0x54, 0xFE, 0xAA, 0xDE, 0x19, 0xB0, 0x0F, 0xB6, 0xD2, 0x7A, 0x39, 0xD2, 0xD5, 0x22, 0xB5, 0xD8, 0xF2, 0x37, 0x31, 0x11, 0x99, 0x4E, 0x9D, 0x4B, 0xDA, 0x40, 0xBD, 0xFC, 0x2D, 0x42, 0x63, 0x57, 0x02, 0xFB, 0x82, 0xE8, 0x64, 0x07, 0x58, 0xA4, 0x91, 0x74, 0xB7, 0xC6, 0xA7, 0x77, 0xCB, 0x6A, 0x1A, 0xC5, 0x8B, 0xCB, 0x15, 0x0F, 0x4D, 0xD7, 0xFD, 0xF3, 0xA0, 0x26, 0x7D, 0x82, 0xA3, 0x99, 0x7A, 0x0A, 0x56, 0x67, 0xF9, 0x01, 0x7F, 0x85, 0x64, 0x50, 0xBE, 0x93, 0x8E, 0x10, 0x21, 0x18, 0xD4, 0x1B, 0x72, 0x7F, 0xB2, 0x1A, 0xB5, 0xBB, 0x8B, 0x38, 0x45, 0xAB, 0x34, 0xBF, 0xCA, 0xE9, 0x19, 0x0B, 0x34, 0x02, 0x56, 0xC4, 0xE2, 0xA5, 0xE4, 0x45, 0xAE, 0xB5, 0x7F, 0x20, 0x59, 0x26, 0xDC, 0xE3, 0xF0, 0x84, 0x0C, 0x93, 0x5D, 0xA7, 0xAF, 0x24, 0x63, 0x81, 0x59, 0x16, 0xDB, 0xC8, 0x44, 0x90, 0xCF, 0xAF, 0xD3, 0xCE, 0x2C, 0x29, 0x60, 0x4A, 0xC8, 0xBD, 0xE5, 0xC1, 0x85, 0xBF, 0x49, 0x80, 0xF9, 0x2A, 0x3D, 0x93, 0x1C, 0xC7, 0x39, 0xB6, 0x98, 0x45, 0xEC, 0x13, 0x08, 0xFD, 0x4C, 0xC4, 0x1A, 0xC9, 0x02, 0x87, 0xF5, 0xC4, 0x0F, 0x45, 0x01, 0xFD, 0x0F, 0xE9, 0x0E, 0x5C, 0xA6, 0xC4, 0x91, 0xB1, 0xE0, 0x03, 0xCE, 0x13, 0x42, 0xC3, 0x1E, 0x5D, 0xE1, 0x4B, 0x4C, 0xE0, 0x8C, 0x2B, 0x78, 0x82, 0x9F, 0xE6, 0x9D, 0x4A, 0x97, 0xE3, 0x9D, 0xC2, 0xA4, 0xC5, 0x56, 0xF8, 0x76, 0xF1, 0x6F, 0x5F, 0x1D, 0xFE, 0x59, 0xB6, 0xDE, 0xE1, 0x24, 0x31, 0xAC, 0x7C, 0x64, 0x89, 0x92, 0x73, 0xC1, 0x7E, 0xCA, 0x63, 0x32, 0x0A, 0xCA, 0xAD, 0x9A, 0xA1, 0x56, 0x08, 0xC3, 0xCB, 0xD4, 0xEA, 0xB7, 0xA2, 0x7D, 0x79, 0x2D, 0xEA, 0x6F, 0x52, 0x59, 0x5A, 0x0D, 0x16, 0x26, 0x13, 0x47, 0x8B, 0xB0, 0x33, 0x8A, 0xD1, 0x7E, 0x7E, 0x78, 0x81, 0x72, 0x68, 0xD1, 0x52, 0x22, 0x13, 0xE4, 0x32, 0x26, 0x11, 0x3F, 0xA1, 0x38, 0x6A, 0xD6, 0x7F, 0xD4, 0x10, 0x1B, 0x44, 0xEF, 0x2B, 0x6C, 0xCB, 0xBE, 0xA9, 0x82, 0x95, 0xAA, 0xDC, 0xAD, 0x2A, 0x2D, 0x38, 0x3B, 0x65, 0x8B, 0xEA, 0x13, 0xA8, 0x8C, 0xFC, 0xAD, 0x3E, 0x07, 0x4D, 0xF3, 0x7B, 0x8C, 0x1D, 0x83, 0xBA, 0x1C, 0x13, 0x89, 0x39, 0xD0, 0x39, 0x46, 0x1A, 0xF1, 0x16, 0x3A, 0x44, 0x85, 0xC9, 0x64, 0x68, 0x47, 0xF9, 0x44, 0x04, 0x45, 0x77, 0x95, 0xBE, 0x42, 0x36, 0xAB, 0x8E, 0xE5, 0x6C, 0x44, 0xFD, 0x55, 0xB7, 0x92, 0x50, 0xF4, 0x8D, 0xEA, 0x70, 0xE4, 0x54, 0xD5, 0x27, 0x95, 0x97, 0xDF, 0x61, 0x2C, 0x0C, 0x25, 0x16, 0xED, 0xC7, 0x5F, 0x20, 0x53, 0x18, 0x13, 0x89, 0x77, 0xF0, 0x34, 0x6A, 0x3C, 0x59, 0x01, 0xF5, 0x57, 0x78, 0xC3, 0xA3, 0xF5, 0xE3, 0x8A, 0x52, 0x60, 0x44, 0x47, 0x66, 0x55, 0x23, 0xA3, 0xB5, 0x4B, 0x13, 0xEE, 0x23, 0x67, 0x35, 0xEB, 0x23, 0x47, 0xA3, 0x7F, 0x48, 0xAA, 0xDF, 0x88, 0xDA, 0x88, 0x6D, 0x70, 0xF8, 0x07, 0xDF, 0x89, 0x06, 0x58, 0x46, 0x13, 0x3F, 0x60, 0x5F, 0xCA, 0x46, 0x52, 0x03, 0x15, 0x57, 0x6C, 0x02, 0x4F, 0xD6, 0xED, 0x2D, 0xB4, 0x80, 0xF2, 0x6B, 0xA3, 0x33, 0x7F, 0xC2, 0x8E, 0x35, 0x67, 0x13, 0xEB, 0x91, 0x79, 0xD5, 0x6F, 0x22, 0xF8, 0x68, 0x8A, 0x7E, 0x81, 0xEF, 0x54, 0xF5, 0x24, 0x32, 0xD8, 0xBE, 0x0B, 0xD7, 0xAA, 0x02, 0xE9, 0x4A, 0xE2, 0x27, 0x9C, 0x49, 0x31, 0x27, 0x3B, 0x21, 0x5A, 0xF9, 0x6A, 0xA0, 0xBF, 0xF5, 0x65, 0x51, 0x2F, 0x68, 0xDE, 0x32, 0x2D, 0x73, 0x17, 0xF8, 0xB4, 0x31, 0x3D, 0xF1, 0x09, 0x3C, 0xAE, 0x2E, 0x30, 0x7C, 0x1D, 0x42, 0x1A, 0x51, 0xEF, 0xD9, 0xAA, 0x41, 0x6D, 0xAA, 0x5D, 0x19, 0xEE, 0xA9, 0x0E, 0xA0, 0x4F, 0x21, 0xEE, 0xC1, 0x35, 0x16, 0x77, 0xC8, 0x0E, 0xF0, 0x6B, 0x09, 0xAF, 0xB1, 0x3C, 0x2F, 0x36, 0xCF, 0xBF, 0x3E, 0xB8, 0xC8, 0x35, 0x23, 0xBB, 0xF6, 0x68, 0xE9, 0xCA, 0x04, 0x53, 0xCD, 0xE3, 0xCA, 0xEF, 0xA1, 0x0E, 0xD5, 0x4D, 0x9C, 0x4A, 0xAF, 0x78, 0xFD, 0x52, 0x61, 0x80, 0x9D, 0xB5, 0x56, 0x2D, 0xDB, 0x48, 0x9B, 0xA8, 0x49, 0x52, 0x7E, 0x36, 0xAF, 0x27, 0xFF, 0x01, 0x0B, 0x8A, 0xE9, 0xF5, 0x21, 0x25, 0x0B, 0xF2, 0xC6, 0xD5, 0xB6, 0x96, 0xD5, 0xA4, 0xD1, 0x4D, 0x2E, 0x95, 0xFB, 0x63, 0x5B, 0x8C, 0xEB, 0xAB, 0xBC, 0x43, 0x33, 0x0D, 0x3B, 0xF9, 0x51, 0x5E, 0x0C, 0xDD, 0x17, 0x71, 0x8A, 0x1D, 0x43, 0xEB, 0x22, 0x7F, 0x47, 0xAB, 0xD7, 0xB8, 0x02, 0x3D, 0x16, 0x59, 0xE4, 0x61, 0x70, 0x6F, 0x91, 0x79, 0xAD, 0x37, 0xF3, 0x57, 0x8E, 0xA6, 0xE6, 0x0D, 0xBB, 0x3D, 0x75, 0x8A, 0xB1, 0x8F, 0x3B, 0x27, 0xE6, 0x65, 0x75, 0x28, 0xBF, 0x2D, 0x54, 0xA7, 0x3F, 0x25, 0x6A, 0xF7, 0xFC, 0xA1, 0x4B, 0x93, 0xEE, 0xB3, 0xE3, 0x69, 0xAE, 0x28, 0xD3, 0xE9, 0x01, 0x9A, 0x29, 0x60, 0x1C, 0xC5, 0x91, 0xDC, 0x0E, 0x59, 0x14, 0x5E, 0x33, 0x6E, 0xE3, 0x7B, 0x66, 0x5B, 0x57, 0xDF, 0x15, 0x74, 0x26, 0x73, 0x0C, 0xF7, 0x44, 0x07, 0x16, 0xDF, 0xD0, 0xDF, 0x93, 0x80, 0x21, 0x7E, 0xBA, 0xFB, 0x32, 0x85, 0xE7, 0x7D, 0xED, 0x26, 0x85, 0xC2, 0x7E, 0x8C, 0x46, 0x0D, 0x6C, 0xA2, 0x3F, 0x26, 0x5F, 0x80, 0xB7, 0x29, 0x57, 0xC8, 0xB5, 0x50, 0x6E, 0x7E, 0x9B, 0xE1, 0x9B, 0xB4, 0x27, 0x9B, 0xAD, 0xBF, 0x2D, 0x1B, 0x49, 0x9E, 0xA7, 0x8F, 0x51, 0x4C, 0x8E, 0x7E, 0xA3, 0x5B, 0xAB, 0xF4, 0x0D, 0x1E, 0xAD, 0x1B, 0x0B, 0xF8, 0x78, 0xF6, 0x6A, 0xCD, 0x41, 0x9A, 0x7D, 0x96, 0xC6, 0x1B, 0x7C, 0x67, 0x19, 0x46, 0x5E, 0x84, 0xA2, 0xA8, 0x2E, 0xE4, 0x1A, 0xA8, 0x22, 0x73, 0xB7, 0xC1, 0x0E, 0xE2, 0x66, 0x8D, 0xD5, 0x8F, 0x87, 0x13, 0x92, 0x8E, 0xEA, 0xE2, 0xE1, 0xC6, 0xA8, 0x2D, 0xDA, 0x0F, 0xF0, 0xCF, 0xC0, 0xF3, 0xDA, 0x7C, 0xF8, 0x97, 0x67, 0x9C, 0xA6, 0x0B, 0x3E, 0x69, 0x3F, 0x89, 0xFC, 0x03, 0x4F, 0xB5, 0x9C, 0x46, 0x9E, 0x82, 0x30, 0xEA, 0x44, 0x72, 0x27, 0x14, 0x96, 0xB9, 0x53, 0x27, 0x27, 0xF8, 0x19, 0x66, 0x5A, 0x92, 0x90, 0x25, 0x66, 0x6B, 0x27, 0x13, 0x41, 0x91, 0xF1, 0x9A, 0x33, 0x78, 0x62, 0x20, 0x4D, 0x53, 0x89, 0x51, 0x3C, 0x8E, 0x90, 0x1F, 0x54, 0x7A, 0xBB, 0x49, 0xE4, 0x2D, 0x64, 0x02, 0x7D, 0x21, 0x79, 0x07, 0xAA, 0xA1, 0x44, 0x90, 0x37, 0xC0, 0xD7, 0xD9, 0x97, 0xB5, 0xCE, 0xD5, 0xE2, 0x94, 0xB3, 0x9A, 0x2E, 0x43, 0x7E, 0x5C, 0x82, 0xC6, 0x5D, 0xCF, 0x8C, 0xA4, 0x91, 0xAB, 0xB5, 0x37, 0x03, 0xAD, 0x49, 0x90, 0x5C, 0xE6, 0x31, 0x8B, 0x54, 0x62, 0xFF, 0xB3, 0x31, 0x90, 0x57, 0x90, 0x7D, 0x54, 0x93, 0x66, 0x06, 0xC4, 0xB6, 0x48, 0x26, 0x7F, 0x80, 0x6D, 0x59, 0xFF, 0x6A, 0x94, 0xF5, 0xEA, 0xB4, 0x42, 0x4D, 0x4C, 0xDD, 0xC5, 0xB8, 0x23, 0xA4, 0xD4, 0xD4, 0x1E, 0x79, 0x8A, 0xA4, 0x56, 0xBF, 0x0D, 0x60, 0x90, 0x14, 0xDD, 0x7E, 0x77, 0x09, 0xE9, 0x49, 0x34, 0xD9, 0x30, 0x48, 0x2D, 0xBA, 0x9C, 0xBA, 0x87, 0x3C, 0x03, 0x6D, 0xB4, 0xA0, 0x90, 0xFF, 0x82, 0xD2, 0xD4, 0x3B, 0x3D, 0xBB, 0x73, 0xCB, 0x13, 0x67, 0x75, 0xCD, 0x2A, 0x74, 0x89, 0xB1, 0x68, 0x3F, 0x5C, 0xD2, 0x1D, 0xFA, 0xAD, 0xE5, 0x6C, 0xC5, 0xB0, 0xCF, 0xE5, 0x06, 0x53, 0x95, 0xC6, 0x25, 0xDA, 0xB4, 0x41, 0x90, 0x67, 0x75, 0xC8, 0x30, 0x4B, 0x96, 0x40, 0xB1, 0xD0, 0x2A, 0x95, 0x47, 0x17, 0x06, 0x68, 0x0A, 0xC1, 0xF0, 0xD4, 0xC7, 0x5D, 0x27, 0x8B, 0x5A, 0x13, 0x7A, 0x3A, 0xFE, 0x94, 0xFA, 0x47, 0x23, 0x6D, 0xEC, 0x0A, 0xFF, 0xD0, 0x89, 0xCD, 0x00, 0xAB, 0xD7, 0xB7, 0xB4, 0xFE, 0x06, 0xF7, 0xB0, 0x4B, 0xBB, 0xC9, 0x56, 0x64, 0x65, 0xF5, 0x49, 0x7F, 0x51, 0x9E, 0x48, 0x79, 0xA9, 0x2D, 0x06, 0xC2, 0xCD, 0x4B, 0x35, 0x99, 0x20, 0x99, 0xF2, 0xA9, 0xE3, 0x42, 0x45, 0x44, 0xC2, 0xF8, 0xF6, 0x64, 0xA6, 0x3A, 0x7A, 0x6E, 0x8B, 0x9C, 0x7D, 0x28, 0x24, 0xBC, 0xF1, 0x32, 0xB7, 0xD3, 0xB7, 0xB3, 0xEE, 0xAA, 0xE0, 0x82, 0x4B, 0x5F, 0x8D, 0x44, 0x52, 0x6E, 0x1D, 0xAD, 0x07, 0x15, 0x28, 0xF5, 0x89, 0x36, 0x00, 0x38, 0x61, 0xB1, 0x51, 0x13, 0x0B, 0x1E, 0x4C, 0xFE, 0xDE, 0x76, 0x8B, 0xB3, 0x29, 0x2E, 0xAD, 0x35, 0x85, 0x27, 0x88, 0xAC, 0x68, 0xB6, 0xE4, 0xEF, 0x0C, 0x5A, 0xDB, 0xD0, 0x2D, 0x3C, 0xE4, 0x93, 0x55, 0x7B, 0x50, 0x92, 0xEB, 0xE2, 0x6C, 0x6C, 0x94, 0xBD, 0xB4, 0xDE, 0xA1, 0x1F, 0xA5, 0xDC, 0x4D, 0x3B, 0xAA, 0x9D, 0x0C, 0x46, 0x52, 0xF6, 0x6B, 0x7C, 0xC1, 0xA7, 0x89, 0xCB, 0x5B, 0x59, 0xA2, 0xEA, 0xD8, 0x19, 0xCD, 0x1A, 0x71, 0x6E, 0x44, 0x60, 0xE3, 0xA0, 0x64, 0x71, 0x60, 0x6F, 0x7D, 0xB7, 0xF4, 0x82, 0xB7, 0xB5, 0xE9, 0xBA, 0x7C, 0x8B, 0xF3, 0xA7, 0xEA, 0xAD, 0x4A, 0xA6, 0x4D, 0x80, 0x4E, 0x0F, 0x3C, 0xA5, 0xFB, 0x6B, 0xAE, 0x81, 0x03, 0x54, 0x73, 0x8D, 0x0D, 0xF8, 0x32, 0x61, 0x7D, 0x4B, 0xA7, 0xB2, 0x2A, 0xE6, 0x62, 0xD3, 0x7E, 0xE5, 0x8A, 0x70, 0xA0, 0x61, 0xBD, 0xB2, 0x3E, 0xC0, 0xB2, 0xEE, 0x3E, 0xE0, 0xE6, 0x59, 0x6D, 0xB2, 0x03, 0x67, 0x3A, 0x0F, 0x54, 0xCF, 0x02, 0x8F, 0xDA, 0x30, 0x75, 0x8E, 0xE0, 0x1B, 0xBA, 0x87, 0x66, 0x0B, 0x78, 0x93, 0xF2, 0x51, 0xB3, 0x00, 0x3C, 0x93, 0x38, 0xAE, 0xE9, 0x8B, 0xAA, 0x35, 0x06, 0x68, 0x4C, 0x51, 0x85, 0x86, 0xDF, 0xAC, 0xAF, 0x41, 0xB7, 0x07, 0xA8, 0x6A, 0x97, 0xA0, 0x15, 0x9E, 0x66, 0x35, 0xFE, 0xC8, 0x6B, 0xA7, 0x0B, 0x86, 0x3E, 0xC4, 0xDA, 0x7A, 0xA7, 0x6E, 0x3C, 0x74, 0x92, 0xD6, 0xA3, 0x59, 0x05, 0x3E, 0xA7, 0x54, 0x69, 0xCC, 0x40, 0x63, 0x5C, 0x76, 0x63, 0xB2, 0xC6, 0x2C, 0xEA, 0x79, 0x03, 0x8D, 0xAC, 0x08, 0x4B, 0xAE, 0xDB, 0x46, 0x6C, 0x0A, 0x68, 0x31, 0xB5, 0xE0, 0x6B, 0x3D, 0x73, 0x8D, 0x62, 0x6C, 0xAE, 0x53, 0x8A, 0x21, 0x57, 0x35, 0xC9, 0x6A, 0xAF, 0x6E, 0x22, 0xCC, 0xA4, 0x1E, 0xD5, 0x6C, 0x03, 0x6F, 0x5A, 0x1C, 0xD4, 0x58, 0x82, 0xFE, 0x31, 0x2F, 0xEA, 0x3F, 0x56, 0x2B, 0xA3, 0x32, 0xEB, 0x0F, 0x1B, 0x86, 0x42, 0x93, 0xEA, 0x3E, 0xE8, 0xCE, 0xF8, 0xAB, 0x4D, 0xE7, 0x34, 0xAF, 0x3D, 0xCA, 0x8C, 0x3E, 0x04, 0xCF, 0xA9, 0xC7, 0x60, 0xAE, 0x66, 0x5A, 0x45, 0x69, 0x7F, 0xC3, 0xEF, 0xA8, 0x45, 0x9A, 0xF5, 0xE0, 0x5D, 0x8B, 0x3C, 0x0D, 0x05, 0xF8, 0x19, 0x33, 0xB0, 0xFC, 0x7A, 0xCE, 0xAF, 0xC8, 0xB7, 0x83, 0x13, 0xF2, 0xEF, 0x05, 0x3D, 0xEE, 0xB7, 0x2D, 0xE6, 0x79, 0xBF, 0xE9, 0x86, 0xCB, 0x47, 0x39, 0xBF, 0x6F, 0x8F, 0x65, 0xDD, 0xB3, 0xBF, 0xD9, 0x28, 0xE7, 0x17, 0x5A, 0xE6, 0x1B, 0x93, 0xA5, 0xFF, 0x98, 0x97, 0xEB, 0x6A, 0x94, 0x86, 0x05, 0xFF, 0x68, 0xDE, 0x81, 0xB4, 0xE8, 0x8D, 0x83, 0xBF, 0x0B, 0xE5, 0xE1, 0x45, 0x03, 0xC7, 0x8A, 0x8F, 0x06, 0x7E, 0xEA, 0x73, 0x2D, 0x5B, 0xE3, 0x53, 0xD1, 0x75, 0x9E, 0x39, 0xCF, 0x75, 0xA4, 0x2D, 0x80, 0xE3, 0x68, 0x0F, 0x35, 0xCE, 0x17, 0x5C, 0xA6, 0x77, 0x1B, 0xC5, 0x32, 0x93, 0x45, 0xA1, 0xAE, 0x55, 0x79, 0x75, 0x61, 0xE7, 0x7F, 0x54, 0x70, 0x54, 0xF6, 0x80, 0x67, 0x59, 0x7F, 0x58, 0x6B, 0xFF, 0xB1, 0x8A, 0x8E, 0x20, 0x8F, 0x25, 0x29, 0xCC, 0xB5, 0xBE, 0x23, 0x1D, 0x9F, 0xAA, 0x5A, 0xDC, 0xEE, 0xB6, 0xEC, 0xE7, 0x8F, 0xB3, 0xBB, 0xD7, 0xE0, 0x21, 0x7A, 0x47, 0x2F, 0x35, 0xDA, 0xCA, 0x6B, 0x28, 0x87, 0x74, 0x18, 0xE0, 0x65, 0xF1, 0x48, 0xF3, 0x06, 0xCC, 0x89, 0x92, 0xF5, 0xAF, 0x67, 0x5B, 0x84, 0x65, 0xF6, 0x0E, 0x55, 0x21, 0x81, 0xC2, 0x6E, 0x90, 0x9B, 0xE4, 0x63, 0x6A, 0x3F, 0xCF, 0xD7, 0xBA, 0xA3, 0xCD, 0x0A, 0x51, 0xA8, 0x9D, 0x57, 0xDD, 0x05, 0x29, 0x42, 0xBF, 0x50, 0xAD, 0x50, 0x6C, 0xA6, 0x2D, 0xD4, 0x85, 0x01, 0x6D, 0xD4, 0xA7, 0x9A, 0x3B, 0x20, 0x27, 0x2A, 0xA4, 0x2F, 0x89, 0xBF, 0x2A, 0xF4, 0xE8, 0x92, 0x19, 0x82, 0x1E, 0xFF, 0xCB, 0x5D, 0x76, 0x22, 0x27, 0xAF, 0xDA, 0xB6, 0x57, 0xE2, 0x66, 0x37, 0xB0, 0xA9, 0x56, 0xAA, 0x72, 0x38, 0x5E, 0x9B, 0x2C, 0xFF, 0xCA, 0xE8, 0x31, 0x74, 0x2B, 0x5F, 0xD2, 0x96, 0x6A, 0xEF, 0x03, 0x5F, 0xA8, 0xF5, 0xFF, 0x99, 0xE4, 0x44, 0x9E, 0x5F, 0x32, 0x2C, 0xDD, 0x12, 0xCA, 0xEA, 0x36, 0xCA, 0x68, 0x7E, 0xF7, 0x3B, 0x7C, 0x64, 0x97, 0x3D, 0xCD, 0x5A, 0xDF, 0xC9, 0xFB, 0x5C, 0xE2, 0x1B, 0xB7, 0x2B, 0x06, 0x16, 0xD5, 0x9A, 0xF2, 0x00, 0x7B, 0xAB, 0x77, 0xFA, 0xDF, 0xC0, 0x77, 0xDA, 0x71, 0x6D, 0x03, 0x18, 0x46, 0x1D, 0xAB, 0xD1, 0x82, 0xF9, 0x51, 0x61, 0x5D, 0x47, 0xC0, 0x0B, 0xA1, 0xFC, 0xCE, 0xF7, 0xB0, 0x8F, 0xBF, 0xA9, 0xBD, 0x1B, 0xBA, 0xEC, 0x39, 0xAB, 0xE5, 0x24, 0x14, 0xE3, 0xD4, 0xDE, 0x70, 0x13, 0x7C, 0x6A, 0x1F, 0x61, 0x6A, 0x04, 0x9F, 0x58, 0x25, 0xEA, 0x5F, 0x83, 0x6B, 0x68, 0xB8, 0xB6, 0x12, 0xCC, 0xA5, 0x9C, 0xD0, 0x64, 0x80, 0x6E, 0x11, 0xA2, 0xCE, 0x0F, 0xD8, 0xFC, 0xE0, 0x5B, 0x1D, 0x57, 0x30, 0xAB, 0x00, 0xAF, 0xB6, 0x0C, 0xF5, 0x53, 0x4F, 0x5D, 0x33, 0xA1, 0x42, 0x9C, 0x8A, 0x1A, 0x58, 0xC8, 0x35, 0xDB, 0x5E, 0xD3, 0x19, 0xB8, 0x8C, 0x31, 0xDA, 0x60, 0x09, 0x4D, 0xA7, 0xBE, 0xD5, 0x32, 0xC1, 0x08, 0x4A, 0x9D, 0x26, 0x18, 0x78, 0x1E, 0x7E, 0xAF, 0xF3, 0xBC, 0x4E, 0x1C, 0xE8, 0xDD, 0x31, 0x48, 0xEE, 0xF6, 0x75, 0x6B, 0x0B, 0x21, 0xD8, 0x9E, 0x41, 0x4D, 0x4B, 0x70, 0xCC, 0x65, 0x76, 0x7D, 0x87, 0x3A, 0xCA, 0x3E, 0xC3, 0xA4, 0x41, 0xD6, 0x59, 0xE2, 0x86, 0x38, 0xA8, 0x88, 0x5A, 0xA8, 0x05, 0x41, 0x2A, 0xC5, 0x4C, 0x13, 0x02, 0x74, 0x76, 0x8F, 0x14, 0x43, 0x49, 0x6F, 0xEA, 0x94, 0xA5, 0xCB, 0x32, 0xCE, 0xA9, 0x7B, 0x2A, 0x76, 0xE4, 0xB7, 0x0B, 0x1E, 0xB2, 0xC7, 0x94, 0x36, 0x16, 0xE6, 0xF2, 0x28, 0xAC, 0xC5, 0xB1, 0xCD, 0xE2, 0x25, 0xFC, 0x40, 0x8F, 0x14, 0x30, 0x50, 0xBA, 0xDE, 0xE6, 0x09, 0x7A, 0x52, 0x99, 0x40, 0x5F, 0xA3, 0xDE, 0x05, 0x9C, 0xEF, 0x76, 0xCE, 0x5B, 0x94, 0x1B, 0x5B, 0xA3, 0x2E, 0x78, 0x55, 0xD8, 0x88, 0x2E, 0x2C, 0x75, 0x2B, 0x7B, 0x26, 0x38, 0x5B, 0xB9, 0x85, 0xC5, 0xC8, 0x6F, 0xE1, 0x40, 0xDC, 0x17, 0x31, 0xEB, 0x44, 0xFB, 0x45, 0x05, 0x1E, 0x5E, 0xC0, 0x16, 0x79, 0x9E, 0xCD, 0x39, 0xD4, 0x04, 0xD8, 0xD2, 0x6B, 0xD5, 0xFD, 0x60, 0x66, 0xDB, 0xA9, 0x8C, 0x13, 0x95, 0x15, 0xD5, 0x44, 0x0E, 0x9F, 0x4D, 0x85, 0x76, 0x14, 0xAA, 0xB9, 0x72, 0xEE, 0xA6, 0xB2, 0xD3, 0xFC, 0xC7, 0xB9, 0x3D, 0xEC, 0x56, 0xD1, 0xFF, 0x16, 0x67, 0x08, 0x1B, 0xA4, 0x2F, 0xDC, 0x2F, 0x03, 0x96, 0xCA, 0x64, 0x9B, 0x3E, 0xB4, 0x04, 0x5C, 0x40, 0x2F, 0x53, 0x0F, 0x80, 0x57, 0x9A, 0xFF, 0x4A, 0xC1, 0x44, 0xEF, 0x75, 0xEF, 0x32, 0xDE, 0x88, 0x2B, 0x01, 0x87, 0xBC, 0xCD, 0xD2, 0x63, 0x6C, 0x46, 0x49, 0x8C, 0xEC, 0x7E, 0xF6, 0x11, 0xE6, 0x88, 0xFC, 0x4E, 0xF4, 0x02, 0x81, 0x9B, 0x72, 0xBB, 0x7B, 0x95, 0x72, 0x18, 0x4C, 0xB7, 0xC9, 0x40, 0xCB, 0xC0, 0x4F, 0x74, 0x73, 0xF5, 0x15, 0xC8, 0xB3, 0xF1, 0x45, 0x42, 0x24, 0x14, 0xA1, 0xEB, 0x48, 0xAD, 0x86, 0xA6, 0x2A, 0xFA, 0xB2, 0xDF, 0xC1, 0x55, 0xAC, 0x71, 0x85, 0xDF, 0x60, 0xD7, 0xAC, 0x5B, 0x15, 0xCF, 0xE1, 0x94, 0xA8, 0x75, 0xBC, 0x67, 0x70, 0xB7, 0xDB, 0x4F, 0x65, 0x04, 0xEC, 0x6B, 0xFD, 0x18, 0xD5, 0x42, 0xEB, 0x69, 0xEB, 0x30, 0x17, 0x48, 0xD0, 0xF8, 0x21, 0xE6, 0xB4, 0x26, 0x5D, 0x7B, 0x23, 0x49, 0x4A, 0x8E, 0xC8, 0x37, 0x66, 0xA6, 0x93, 0x13, 0x2A, 0x1F, 0xE7, 0x9F, 0xC3, 0x5F, 0x66, 0xFE, 0x29, 0x0F, 0xC7, 0x5D, 0x22, 0xAF, 0x71, 0x1F, 0xA8, 0x07, 0xDC, 0x46, 0x29, 0x27, 0xA0, 0x13, 0xAD, 0xDD, 0xD0, 0x0D, 0x70, 0x36, 0xCD, 0x12, 0xD3, 0x41, 0x5D, 0xB5, 0xB7, 0xA2, 0x79, 0x0D, 0x97, 0x71, 0xC7, 0x04, 0xAB, 0xFA, 0x04, 0x99, 0x79, 0xFA, 0x1C, 0xD3, 0xAA, 0xCA, 0x75, 0x79, 0xA3, 0x8D, 0xE9, 0x99, 0xF2, 0xD2, 0xA3, 0xFA, 0x13, 0x91, 0x7F, 0x73, 0xCD, 0x34, 0xCE, 0x2E, 0xCF, 0x14, 0xF7, 0xD5, 0xD3, 0xAC, 0x92, 0xD0, 0x33, 0xC8, 0x58, 0x6A, 0x09, 0x76, 0x10, 0xDA, 0x69, 0xDA, 0x12, 0x29, 0xE9, 0xFA, 0x47, 0x7D, 0x21, 0x6E, 0x6A, 0xC7, 0x02, 0x49, 0x51, 0xAA, 0x43, 0xCB, 0xB5, 0x4A, 0x6A, 0x8E, 0xB2, 0xB1, 0x25, 0x73, 0x46, 0xC9, 0xA9, 0x5A, 0x87, 0x88, 0x1A, 0x0E, 0x5F, 0x7F, 0xDC, 0xA5, 0x48, 0x51, 0x8F, 0x9D, 0x65, 0xB4, 0xA1, 0x47, 0x90, 0x1E, 0x4A, 0x13, 0x76, 0x0D, 0x3A, 0x63, 0x34, 0x46, 0xE8, 0x97, 0x85, 0xAB, 0xB6, 0xC4, 0xA4, 0xF7, 0xD5, 0x48, 0xA7, 0x27, 0x67, 0x77, 0xEF, 0xAA, 0xD8, 0x90, 0xF5, 0xA8, 0x5D, 0x98, 0x7E, 0xAA, 0x78, 0x4B, 0x23, 0x1E, 0x36, 0xA9, 0xEA, 0xA2, 0x71, 0xBA, 0xF3, 0x17, 0xC5, 0x42, 0xC2, 0x8F, 0x31, 0x1A, 0x5D, 0x86, 0x2E, 0xB0, 0x38, 0x8D, 0xDD, 0x81, 0x6E, 0xB7, 0xFC, 0x5D, 0xF1, 0x36, 0x25, 0x5F, 0xFF, 0x89, 0x99, 0x93, 0xF9, 0x07, 0x94, 0xB2, 0x3B, 0x0A, 0xD8, 0x55, 0xDF, 0xB9, 0x81, 0x65, 0xB4, 0xDC, 0x38, 0xC1, 0x59, 0x16, 0x1C, 0xF9, 0x46, 0xBA, 0x9F, 0xDF, 0xE1, 0xFA, 0x03, 0xDA, 0x20, 0xBD, 0x64, 0xBD, 0x57, 0xB5, 0x51, 0x19, 0x41, 0xFB, 0x86, 0x55, 0x00, 0x5B, 0x1A, 0x1F, 0x94, 0x44, 0xE5, 0x4A, 0xB5, 0xFE, 0x65, 0xB1, 0x45, 0x15, 0x8A, 0x93, 0x95, 0x86, 0xF2, 0x02, 0x76, 0x45, 0x55, 0x2C, 0xAB, 0x35, 0xFB, 0x25, 0xBF, 0x9B, 0x7B, 0x2F, 0xEA, 0xA5, 0x74, 0xB4, 0x28, 0xDF, 0xAD, 0x12, 0x72, 0x97, 0xE7, 0x59, 0x6F, 0x50, 0x69, 0x01, 0x1A, 0x6D, 0x2F, 0x56, 0x04, 0xC6, 0xD5, 0x6E, 0xCD, 0x5F, 0x58, 0x69, 0x4B, 0xBC, 0x2C, 0xFA, 0x9B, 0xF5, 0x3F, 0x39, 0xB5, 0x2C, 0x91, 0x73, 0x9D, 0x59, 0xC1, 0x3C, 0xC9, 0xDF, 0x97, 0x85, 0x72, 0x0F, 0x89, 0x56, 0x44, 0xB5, 0x88, 0x4F, 0x49, 0x37, 0xBB, 0xC5, 0x82, 0xAB, 0x95, 0x2E, 0xD6, 0x46, 0x15, 0x0B, 0xFC, 0x9B, 0x56, 0x8B, 0xF1, 0xC1, 0x9B, 0xC6, 0x19, 0x59, 0x7B, 0x84, 0xFB, 0x31, 0xBF, 0xBC, 0x7E, 0x71, 0xBE, 0xE4, 0x5E, 0xB1, 0x4A, 0x72, 0xBD, 0xA2, 0xB1, 0xA2, 0x40, 0x16, 0x9A, 0xE9, 0x57, 0x75, 0x4A, 0xBE, 0x3E, 0xD2, 0x20, 0x52, 0x29, 0x4B, 0x5D, 0x4F, 0x83, 0x7E, 0xA0, 0x99, 0x75, 0x8C, 0xAA, 0x0A, 0x7C, 0x49, 0x2B, 0xC6, 0x7A, 0xA1, 0x70, 0x1D, 0x27, 0xED, 0x34, 0xB8, 0x40, 0xE5, 0x95, 0xCD, 0x05, 0xAF, 0x8B, 0x2B, 0x0A, 0xAE, 0x40, 0x9A, 0x72, 0x5D, 0x99, 0x2B, 0xB4, 0x34, 0xC3, 0x8D, 0xED, 0x03, 0xDD, 0x8D, 0xA8, 0x15, 0x72, 0x61, 0x6B, 0xD7, 0x60, 0xE0, 0x31, 0xF4, 0xD2, 0xEA, 0xA5, 0x0A, 0x87, 0xFA, 0x68, 0xF3, 0xB1, 0x07, 0x10, 0xA4, 0x3D, 0x91, 0xFC, 0x9E, 0xF4, 0x40, 0xBA, 0x32, 0x3A, 0x89, 0x15, 0x22, 0xDB, 0x3C, 0x3B, 0x82, 0x52, 0x06, 0x96, 0x98, 0xE3, 0x16, 0xE9, 0xB9, 0xCC, 0x6B, 0x58, 0x58, 0xF8, 0x45, 0xC1, 0xB0, 0xEA, 0x8B, 0x4B, 0x1D, 0xB0, 0x01, 0xD9, 0x68, 0xC5, 0x55, 0x0D, 0xC0, 0x7E, 0xD4, 0xB5, 0xB8, 0x3D, 0xD4, 0xA6, 0x63, 0x24, 0x48, 0xEA, 0xC6, 0xC1, 0xCE, 0x69, 0x41, 0xA6, 0xE5, 0x82, 0x88, 0xEC, 0x83, 0x35, 0x2E, 0xA5, 0xB1, 0x45, 0x79, 0x86, 0x7B, 0x69, 0xED, 0x95, 0xD5, 0xBA, 0x8A, 0x70, 0x1A, 0xFF, 0x09, 0xE9, 0xE8, 0x7C, 0x14, 0x20, 0x55, 0x4D, 0x8C, 0xA3, 0xAA, 0xBD, 0xF0, 0x19, 0x2A, 0x05, 0xAF, 0x80, 0x06, 0x34, 0x1B, 0xE3, 0x83, 0xDB, 0x2F, 0x80, 0x3B, 0x52, 0x6A, 0x5A, 0x85, 0xFC, 0x05, 0x59, 0xBC, 0xA6, 0x81, 0x12, 0x56, 0xC1, 0xC3, 0xFA, 0xD6, 0xD4, 0xF7, 0x15, 0x95, 0x35, 0xC7, 0xC3, 0x24, 0xFC, 0x00, 0xDD, 0x6E, 0xE7, 0x60, 0x20, 0x0E, 0x73, 0x64, 0x84, 0xAB, 0x0E, 0x23, 0x49, 0x94, 0x2E, 0x5C, 0x0B, 0xAD, 0x24, 0xC4, 0x71, 0xBE, 0xFD, 0xC3, 0xC0, 0xB8, 0xA4, 0x3D, 0x4B, 0x16, 0x72, 0x98, 0x19, 0xC6, 0x8E, 0x3B, 0x45, 0x9B, 0xF2, 0xAB, 0x5A, 0xC7, 0xA5, 0x06, 0x94, 0xB3, 0x1A, 0x82, 0x42, 0xFF, 0xE1, 0x1D, 0xAA, 0xAE, 0x71, 0xFA, 0x0D, 0x4C, 0xC3, 0x71, 0xCB, 0xA7, 0xAA, 0x5D, 0xC8, 0x4E, 0x8A, 0x03, 0xDE, 0x0A, 0xAD, 0x33, 0x6C, 0xE7, 0x2E, 0x4E, 0x93, 0xA3, 0xDB, 0x79, 0x63, 0xB3, 0xEB, 0x44, 0xDB, 0xF9, 0x64, 0xE1, 0xC2, 0x8A, 0x05, 0xC2, 0x75, 0x65, 0xF1, 0x19, 0xDE, 0x92, 0x83, 0xAC, 0x37, 0x61, 0xDB, 0x14, 0xD7, 0xF8, 0xFB, 0x9D, 0xF7, 0x21, 0x42, 0xE9, 0x5D, 0x2B, 0x96, 0x7A, 0x8F, 0xD2, 0x83, 0x36, 0x0D, 0xB7, 0x01, 0xDA, 0x74, 0x16, 0xAC, 0xB9, 0x79, 0xBD, 0x70, 0x18, 0x9B, 0x53, 0xFC, 0x97, 0x70, 0x34, 0xE7, 0x55, 0xB9, 0xB2, 0xF4, 0x3E, 0xFF, 0x22, 0x4B, 0x93, 0xF6, 0x5B, 0x9C, 0xC7, 0xDD, 0x1B, 0x5E, 0x25, 0xBF, 0x2E, 0x0A, 0x73, 0xB1, 0x85, 0xBF, 0xCB, 0x53, 0xAD, 0x0A, 0xD4, 0x03, 0xC0, 0x5C, 0xEA, 0x39, 0xDC, 0x0D, 0x0C, 0x26, 0xEA, 0xCA, 0x72, 0x2B, 0x2D, 0xC0, 0xBA, 0x0A, 0x94, 0x55, 0x28, 0xF0, 0x61, 0x4F, 0xAA, 0xFA, 0x51, 0xB2, 0x80, 0x5B, 0xC3, 0xF7, 0x4F, 0x5D, 0x2B, 0x14, 0x8B, 0xAC, 0xC2, 0x93, 0x65, 0x2D, 0xD2, 0x14, 0x17, 0x37, 0x18, 0x57, 0x4E, 0xB0, 0x8A, 0x56, 0x37, 0x80, 0x93, 0xA8, 0x23, 0x78, 0x2C, 0x78, 0x17, 0x63, 0x15, 0x99, 0x04, 0xE9, 0xCA, 0x7D, 0xA5, 0x19, 0x22, 0x3F, 0xEE, 0xA6, 0x4A, 0xBA, 0x78, 0x4F, 0xD1, 0x89, 0xAA, 0xBF, 0xA5, 0x99, 0xA9, 0x73, 0xF9, 0xC5, 0xB2, 0xEB, 0x61, 0x80, 0xB4, 0x42, 0x71, 0xC6, 0xF9, 0x12, 0x6C, 0x06, 0x5C, 0xB6, 0x62, 0xFC, 0x47, 0xDD, 0xA1, 0x76, 0xE2, 0x72, 0x28, 0x01, 0x59, 0x99, 0xF7, 0x4C, 0xC9, 0x95, 0xFB, 0x17, 0x85, 0x01, 0xD6, 0x1C, 0x55, 0x99, 0x14, 0x78, 0x5A, 0x64, 0xC3, 0xFC, 0x04, 0x66, 0xA7, 0x38, 0xF0, 0x1C, 0xC1, 0xFB, 0xA1, 0x0D, 0x92, 0x7A, 0x88, 0xE3, 0xCC, 0x85, 0xCE, 0x42, 0xF5, 0x8C, 0xD7, 0xEA, 0x3E, 0x48, 0x47, 0x05, 0xF1, 0x95, 0x90, 0x1A, 0x2E, 0xCF, 0xC9, 0xC7, 0xE7, 0x49, 0x0B, 0xF3, 0x0F, 0x63, 0x4B, 0xD8, 0x01, 0x25, 0x66, 0x58, 0x76, 0x41, 0x66, 0xE5, 0x24, 0x35, 0x9A, 0x3C, 0x95, 0x3B, 0x4A, 0xF5, 0x35, 0xE4, 0x89, 0xF8, 0x9E, 0x6A, 0xAA, 0xD3, 0x77, 0xA8, 0x1B, 0xF1, 0x67, 0x2C, 0x51, 0x6F, 0x85, 0xA7, 0x52, 0xBD, 0xF0, 0x7B, 0x50, 0x2D, 0x32, 0x2D, 0xE3, 0xAE, 0xF1, 0xB5, 0xE4, 0x66, 0xEE, 0x62, 0x23, 0x9D, 0x35, 0xA7, 0x68, 0x8A, 0xE1, 0x56, 0xFE, 0xBC, 0xF2, 0x66, 0xDD, 0xC3, 0xC4, 0x1F, 0x55, 0x17, 0x35, 0x27, 0x82, 0x7F, 0x88, 0x19, 0xF8, 0x47, 0xA7, 0x04, 0x88, 0x83, 0xBE, 0x61, 0xD8, 0xA8, 0xCF, 0xC2, 0x46, 0xCA, 0x55, 0xC2, 0x0C, 0xD2, 0x40, 0xDC, 0xF4, 0xD8, 0x96, 0x0C, 0x71, 0x73, 0x76, 0x6B, 0x13, 0xC1, 0xAC, 0x2D, 0x68, 0xA8, 0x7F, 0x9D, 0x77, 0xBD, 0xCC, 0xA1, 0x96, 0x92, 0xC8, 0x67, 0x6F, 0xAD, 0xBE, 0x1A, 0x3C, 0x47, 0x54, 0xA7, 0x0D, 0x71, 0x3C, 0x08, 0x85, 0xAB, 0x4B, 0x2D, 0x4F, 0xAA, 0xEF, 0xC0, 0x6F, 0x28, 0x35, 0x44, 0x28, 0x04, 0x02, 0x35, 0xA9, 0x0F, 0x7A, 0x3E, 0x09, 0x65, 0x99, 0xAF, 0x3A, 0x2F, 0x95, 0xDD, 0xCB, 0xFB, 0xD3, 0x36, 0x3D, 0xB7, 0xAA, 0xE4, 0x62, 0x53, 0x48, 0xE2, 0x0D, 0xD6, 0x50, 0x1D, 0x2D, 0x18, 0x17, 0xA5, 0xEB, 0x4F, 0x38, 0x9E, 0x83, 0xE8, 0x58, 0xBB, 0xE5, 0x80, 0xFA, 0x21, 0x12, 0x47, 0x89, 0x27, 0x72, 0x21, 0x09, 0x9C, 0x2C, 0x7E, 0x9D, 0xF1, 0x46, 0x72, 0x56, 0x92, 0x9A, 0x4B, 0x67, 0xAD, 0x91, 0xBA, 0x17, 0xFE, 0x2C, 0xF0, 0x91, 0x2D, 0x2D, 0xDB, 0x9A, 0x84, 0x29, 0xDE, 0xB1, 0xCD, 0x82, 0x8B, 0xA1, 0x19, 0xFC, 0x11, 0xC7, 0xA3, 0xAA, 0x60, 0xE9, 0x21, 0xC6, 0x74, 0xEC, 0x98, 0xD2, 0x9C, 0xF2, 0x05, 0xBF, 0x0B, 0x90, 0x20, 0x20, 0x48, 0xCD, 0xEF, 0x11, 0xBD, 0x16, 0xCE, 0x2C, 0x7A, 0xCF, 0x3C, 0x2A, 0x7A, 0xF0, 0x9F, 0x9C, 0x6C, 0xC9, 0x01, 0x96, 0x4B, 0xA2, 0x46, 0xCE, 0xE1, 0x56, 0x05, 0xDB, 0x83, 0x13, 0x45, 0xE3, 0x1D, 0x77, 0xA3, 0xB7, 0xE5, 0xAE, 0x96, 0xBF, 0xB1, 0xED, 0xC0, 0x58, 0xCA, 0x43, 0xFC, 0x15, 0xE8, 0xA5, 0x18, 0xE0, 0x94, 0x55, 0x78, 0x08, 0x5E, 0x73, 0x37, 0x32, 0xAB, 0x2B, 0x39, 0x02, 0xAF, 0xAA, 0x55, 0xB9, 0x0B, 0x45, 0x2B, 0x78, 0x8D, 0xF1, 0xBB, 0xA4, 0x4B, 0x84, 0x65, 0x41, 0x9B, 0x94, 0xA7, 0x25, 0xA7, 0x1D, 0xB7, 0xA3, 0x52, 0xC5, 0x65, 0xC6, 0x28, 0x6C, 0x15, 0xF0, 0x8D, 0xF2, 0x88, 0x18, 0x0F, 0xDE, 0x96, 0x1D, 0x63, 0x76, 0xF0, 0x3E, 0xF2, 0x37, 0xB1, 0x3B, 0x04, 0x87, 0xCA, 0x27, 0x70, 0xDD, 0x44, 0xB5, 0xD9, 0x42, 0x81, 0x8F, 0xC4, 0x21, 0x9E, 0x26, 0xFE, 0x22, 0x7D, 0x15, 0x14, 0xAB, 0xB8, 0xA0, 0x58, 0xE8, 0xB8, 0x09, 0x9D, 0x03, 0x18, 0x18, 0x33, 0xB0, 0x15, 0xE0, 0x31, 0xCA, 0x67, 0xC2, 0x01, 0x4A, 0x10, 0x5F, 0x2B, 0xA7, 0xC9, 0xA9, 0x5C, 0x76, 0xE5, 0x4A, 0xC5, 0xB4, 0xB2, 0x29, 0xEC, 0xDD, 0x4A, 0x8F, 0x9C, 0x29, 0x3C, 0x6B, 0x65, 0x4D, 0x3C, 0x5D, 0x34, 0x08, 0x10, 0x81, 0x8F, 0x14, 0x73, 0x40, 0xC2, 0x71, 0x05, 0x72, 0x16, 0xA2, 0x31, 0xA6, 0x61, 0x1B, 0xA0, 0x62, 0xCA, 0x47, 0x22, 0x13, 0x02, 0xC5, 0xDF, 0x4B, 0x8E, 0xA9, 0xA6, 0x71, 0xEC, 0xCA, 0x3B, 0xD1, 0xAF, 0xC5, 0x7B, 0x99, 0xB7, 0xD1, 0x63, 0x99, 0x8F, 0x39, 0xBD, 0x68, 0x61, 0xAC, 0x51, 0x58, 0x87, 0xF2, 0x03, 0x63, 0xE4, 0x85, 0xC8, 0xBF, 0x8E, 0x85, 0x48, 0x07, 0x3C, 0x64, 0x79, 0x1B, 0x3B, 0x08, 0x9D, 0xA7, 0x9C, 0x21, 0xB4, 0x10, 0x20, 0xCE, 0x28, 0x3C, 0xA1, 0xFF, 0xC0, 0x46, 0x4B, 0x7E, 0xE8, 0x65, 0x45, 0x6F, 0x2B, 0x06, 0x75, 0xAE, 0x19, 0xA2, 0xAA, 0x20, 0xCD, 0xFE, 0x98, 0x99, 0x02, 0x0D, 0x39, 0xDE, 0xFF, 0x85, 0xAC, 0x0B, 0xAB, 0x5B, 0xD4, 0x84, 0x54, 0xA2, 0xEE, 0x96, 0x72, 0xEC, 0x1A, 0xEC, 0x49, 0xA9, 0x23, 0x76, 0x42, 0xF9, 0x82, 0xF2, 0xFC, 0x0D, 0x0D, 0x7A, 0xD6, 0xB2, 0xA2, 0x5F, 0xF5, 0x51, 0x45, 0xBE, 0xE5, 0x13, 0x6B, 0xC3, 0xD2, 0xCF, 0xB1, 0xDE, 0x1B, 0x9B, 0x16, 0xAF, 0xE3, 0xCB, 0xF4, 0x7A, 0x7F, 0x86, 0x6C, 0x0A, 0x59, 0xBF, 0xC8, 0x0C, 0xF1, 0x55, 0x69, 0x2C, 0xAD, 0xB0, 0x27, 0xB0, 0x86, 0x12, 0x4B, 0xDC, 0x87, 0x82, 0xB8, 0x21, 0x79, 0xBE, 0x1D, 0x21, 0x95, 0x0E, 0x85, 0x9D, 0xAD, 0x87, 0xF2, 0x93, 0x4A, 0x0F, 0x37, 0xBD, 0x4E, 0x3B, 0xC5, 0xEC, 0xA9, 0x4F, 0x5F, 0xFC, 0x9E, 0x37, 0xAE, 0xE6, 0x6F, 0xFF, 0x00, 0x69, 0x8D, 0xF6, 0x9F, 0x45, 0xF9, 0xF0, 0x1F, 0xF5, 0x52, 0xCB, 0x89, 0xD8, 0x33, 0xF8, 0x14, 0x65, 0x0C, 0xF1, 0x1B, 0xB2, 0x16, 0x6D, 0x07, 0x34, 0x99, 0x29, 0x55, 0x1B, 0x00, 0x20, 0xB7, 0xB2, 0x98, 0x00, 0x6E, 0x15, 0x71, 0x33, 0x7A, 0xC1, 0x95, 0xE5, 0x36, 0x31, 0x61, 0xB0, 0x3D, 0xDB, 0xDA, 0xBF, 0x0A, 0xF5, 0xE1, 0xCB, 0x1D, 0x4E, 0xAA, 0xBF, 0x48, 0x4D, 0xF4, 0xDD, 0xF8, 0x46, 0xE5, 0x78, 0x8B, 0x07, 0x84, 0x08, 0x20, 0x84, 0x66, 0xF2, 0xA1, 0xFC, 0x04, 0x76, 0x93, 0x5C, 0x59, 0xE4, 0x5B, 0x2C, 0x56, 0x1C, 0x29, 0x83, 0x32, 0x20, 0xE5, 0x39, 0xE6, 0x9F, 0xC5, 0xA7, 0xC0, 0xAD, 0xDC, 0x20, 0xBF, 0xCB, 0x48, 0xAC, 0x70, 0xAF, 0x83, 0x54, 0xBD, 0x5C, 0xF6, 0x9D, 0xBE, 0x0F, 0x1F, 0x50, 0xBE, 0xA1, 0x4C, 0x27, 0x20, 0xD0, 0x85, 0x73, 0x43, 0x22, 0x29, 0xFB, 0x56, 0xB1, 0x56, 0xB2, 0xB2, 0xD2, 0xAA, 0x28, 0x48, 0x56, 0xC0, 0x56, 0xA6, 0xA7, 0xCB, 0x5F, 0x70, 0x2F, 0x46, 0x43, 0x80, 0x8B, 0xE0, 0x87, 0x5F, 0x1A, 0x1C, 0x25, 0x91, 0x3A, 0x54, 0xA9, 0x17, 0x2B, 0x3A, 0xE8, 0x4F, 0xF0, 0x26, 0xE0, 0xFE, 0x7F, 0x3D, 0xAC, 0x01, 0xAF, 0x70, 0xBC, 0x05, 0xA5, 0xDC, 0xF0, 0x8A, 0x7C, 0xE1, 0x53, 0xBE, 0x65, 0xFE, 0x69, 0xF1, 0x6A, 0x61, 0x7E, 0x6A, 0xB2, 0xF4, 0xA2, 0xE8, 0x57, 0xD4, 0x7C, 0xC5, 0x5A, 0xC9, 0x17, 0x3F, 0x17, 0xA8, 0x40, 0x0E, 0x3A, 0xAC, 0x56, 0xBD, 0x05, 0x3C, 0x2D, 0x6D, 0x70, 0x13, 0x38, 0x4C, 0xD1, 0x10, 0x43, 0x50, 0x58, 0xD5, 0x6B, 0x6E, 0xB0, 0x64, 0x5D, 0xF9, 0x68, 0x7E, 0x8A, 0xAC, 0x2A, 0xF7, 0xA0, 0xB0, 0x44, 0xBE, 0x24, 0x45, 0x2B, 0xFE, 0xAA, 0x88, 0x8A, 0x3C, 0x2C, 0xCF, 0x55, 0xC6, 0xFA, 0xCD, 0x06, 0x3B, 0x80, 0x4E, 0x87, 0xB3, 0xAA, 0x0D, 0xE0, 0x1A, 0xCB, 0x68, 0xBC, 0x09, 0x72, 0xA3, 0xF4, 0x11, 0xC7, 0x21, 0x16, 0x7B, 0x09, 0x7B, 0x0B, 0x1C, 0x50, 0x3A, 0x9F, 0x6B, 0x09, 0x7F, 0xCF, 0x09, 0xE3, 0x0F, 0xC3, 0xF7, 0x92, 0x4B, 0x45, 0xDD, 0xC8, 0x8C, 0x48, 0x6B, 0x59, 0x34, 0xFC, 0xDE, 0xB7, 0x16, 0xB8, 0x03, 0x1F, 0x70, 0xD0, 0xA8, 0x60, 0x78, 0xB2, 0x25, 0x03, 0x1F, 0x80, 0x1A, 0x28, 0x26, 0xE2, 0x23, 0x94, 0xCF, 0xEC, 0x67, 0x56, 0x69, 0x03, 0x8A, 0xB2, 0xD8, 0x03, 0x9A, 0xF9, 0x59, 0x17, 0xB9, 0x32, 0x32, 0x3C, 0x71, 0x97, 0x70, 0x36, 0xA1, 0x8E, 0x98, 0x2F, 0x0D, 0xC4, 0xE7, 0xFB, 0xB8, 0x03, 0xB3, 0xD5, 0x74, 0xFB, 0xA3, 0xAA, 0x30, 0x44, 0xFC, 0x9F, 0xC3, 0xCD, 0xD0, 0x75, 0x4A, 0x1C, 0x69, 0x0B, 0x39, 0x55, 0x2C, 0xA9, 0x70, 0x34, 0x3D, 0x2C, 0x4A, 0x66, 0xDE, 0xAC, 0x69, 0xCF, 0x72, 0xE3, 0x58, 0x19, 0xC7, 0x27, 0xDC, 0xE3, 0xFF, 0xD1, 0xBF, 0x08, 0xF7, 0x96, 0x24, 0x6A, 0xC3, 0xBD, 0x3B, 0x94, 0x38, 0xFE, 0xCC, 0x3E, 0x43, 0x35, 0x11, 0xED, 0xA3, 0x17, 0xE2, 0x7B, 0xE0, 0x59, 0x16, 0x6F, 0xC9, 0x44, 0xF0, 0x47, 0xD9, 0x95, 0xB2, 0x0B, 0xCD, 0x4F, 0x0B, 0x57, 0x56, 0x6E, 0x6E, 0x9A, 0x9E, 0xF1, 0x57, 0x15, 0x5C, 0xEF, 0x10, 0xC7, 0xE6, 0x8F, 0x37, 0x8D, 0x09, 0x1D, 0x11, 0xFD, 0x30, 0xF0, 0xBD, 0x20, 0xC5, 0x31, 0xF2, 0x89, 0x7D, 0x22, 0x7A, 0x52, 0xD5, 0x42, 0xB7, 0xC3, 0xF7, 0xC2, 0x91, 0x16, 0x5D, 0x24, 0x1B, 0xBC, 0x5C, 0xCE, 0xC5, 0x12, 0x32, 0xBD, 0x8A, 0x47, 0xAB, 0x5B, 0x73, 0x9E, 0x64, 0x29, 0xD5, 0xFC, 0xA2, 0xF9, 0x89, 0xE6, 0x6A, 0xA2, 0xFC, 0xEF, 0x70, 0xBA, 0xFA, 0x07, 0x6B, 0x9F, 0xD7, 0x49, 0xEC, 0x30, 0x7F, 0xA6, 0xDD, 0x3C, 0xFC, 0xAE, 0x34, 0x9E, 0x66, 0x47, 0x74, 0x28, 0xBE, 0x9A, 0x1F, 0x23, 0x9E, 0x00, 0xA6, 0x72, 0x23, 0x7A, 0x3B, 0xEF, 0x44, 0xE1, 0x1B, 0x34, 0xAE, 0xB0, 0x33, 0x6B, 0x14, 0x3A, 0x5C, 0x7A, 0x35, 0x81, 0x81, 0x9E, 0x67, 0xD6, 0x86, 0x89, 0x55, 0x9B, 0x39, 0xBB, 0xBD, 0x4A, 0xD5, 0x2F, 0x84, 0xE1, 0x76, 0x93, 0x70, 0xA3, 0x6C, 0x0B, 0x4D, 0x4E, 0xA8, 0x95, 0xD7, 0x2C, 0x82, 0x89, 0x27, 0xA0, 0x4B, 0x49, 0x3A, 0x74, 0xA4, 0x6C, 0x46, 0x9E, 0x3F, 0xF4, 0xB8, 0x22, 0x23, 0xA3, 0x00, 0x6E, 0x65, 0x35, 0xC4, 0xAB, 0x11, 0x0B, 0xCE, 0xF5, 0xD0, 0x1E, 0xD4, 0x57, 0xB0, 0xC0, 0x6B, 0x8E, 0x7A, 0xB4, 0xF8, 0x92, 0x9D, 0x1F, 0xEE, 0xA4, 0x88, 0xA6, 0xDD, 0x23, 0x98, 0xC0, 0x01, 0x8B, 0x83, 0xC4, 0x73, 0xF0, 0x54, 0xF1, 0x80, 0xD2, 0xBA, 0x4A, 0x9F, 0xDB, 0x0C, 0x14, 0x72, 0x1D, 0xD3, 0xFA, 0xC0, 0x6C, 0xFE, 0xF6, 0x38, 0x77, 0x48, 0x24, 0x1C, 0x0C, 0x59, 0x0B, 0x7F, 0x11, 0x3F, 0xF2, 0x9A, 0xA1, 0xF2, 0x94, 0xAD, 0xB1, 0xEB, 0xC5, 0x6E, 0x28, 0x4F, 0xD1, 0xD3, 0x88, 0x1C, 0x10, 0xA6, 0x78, 0x11, 0x5F, 0x21, 0x97, 0xE2, 0x21, 0x19, 0x24, 0x92, 0xE5, 0xC6, 0xC8, 0xBF, 0x88, 0x3F, 0xA6, 0xFC, 0x52, 0x66, 0x49, 0x85, 0x31, 0xC7, 0x80, 0xFB, 0xB2, 0x9E, 0xE0, 0x2B, 0xD0, 0x5D, 0xF9, 0x07, 0xCF, 0xFB, 0x28, 0xA1, 0x6C, 0xB6, 0x3B, 0x82, 0xF5, 0x82, 0x36, 0xF4, 0x3A, 0x22, 0x17, 0xFC, 0x4C, 0x01, 0xC8, 0xBF, 0xA1, 0xA4, 0xFC, 0xE3, 0xE2, 0xDB, 0x40, 0x5A, 0x76, 0xA9, 0x54, 0x0B, 0xBC, 0x49, 0xAE, 0x94, 0x0F, 0x80, 0x9E, 0x8B, 0xD9, 0xCA, 0x3A, 0xF0, 0x59, 0xD0, 0x07, 0xF0, 0x0C, 0x64, 0xE7, 0x99, 0x82, 0x9C, 0x87, 0x64, 0x76, 0x32, 0x8C, 0x0B, 0x15, 0xD3, 0xE5, 0x44, 0x25, 0x14, 0xF9, 0x1F, 0xE5, 0x0F, 0xF9, 0xE6, 0x85, 0x88, 0xE6, 0xE0, 0x61, 0x19, 0xD5, 0xE2, 0x42, 0x2C, 0x34, 0xB1, 0x4E, 0x4A, 0x60, 0xE3, 0x23, 0xF3, 0xE4, 0x3B, 0xD5, 0xFD, 0x41, 0x54, 0x60, 0x97, 0xEA, 0xAC, 0xC7, 0x2E, 0xC4, 0x02, 0x6D, 0xB4, 0xBD, 0x8A, 0xB9, 0xC0, 0xDD, 0xF4, 0x49, 0x84, 0x1C, 0x52, 0x50, 0xEC, 0x48, 0x0E, 0xF8, 0x2D, 0xF7, 0x25, 0xFF, 0x8F, 0x61, 0x79, 0xC6, 0x28, 0x11, 0x43, 0x0F, 0x27, 0x7C, 0x93, 0x08, 0x74, 0xB1, 0x51, 0x76, 0xB2, 0xF7, 0x9A, 0x7F, 0x02, 0x15, 0xCA, 0x3B, 0xC4, 0x1E, 0x0F, 0x2B, 0x58, 0x8E, 0x2D, 0xB0, 0x45, 0xD4, 0xEF, 0x90, 0x3E, 0x5A, 0x2F, 0xA1, 0x82, 0xDA, 0x2C, 0xB6, 0x91, 0x0D, 0xE0, 0xCE, 0x9C, 0xDF, 0xBC, 0xD6, 0x7A, 0x5D, 0xFA, 0x15, 0xC1, 0x48, 0xAD, 0x29, 0x1E, 0x16, 0xFB, 0xD6, 0x8C, 0x8B, 0x7C, 0x21, 0x9B, 0x5C, 0x3D, 0x2B, 0xE0, 0xBE, 0xE2, 0xA2, 0xCE, 0xC9, 0x63, 0x01, 0x74, 0x83, 0x98, 0x6C, 0x7B, 0x41, 0xBD, 0x17, 0x15, 0xD1, 0xA4, 0x04, 0x0C, 0x6D, 0xB5, 0xC8, 0x21, 0x87, 0x40, 0x63, 0xB6, 0x8F, 0x51, 0x9D, 0x71, 0x25, 0xAD, 0xD2, 0x70, 0x20, 0x47, 0x97, 0x30, 0x49, 0xBF, 0xA5, 0x60, 0x65, 0xD4, 0x79, 0xDD, 0xEB, 0xD2, 0x83, 0x01, 0xF5, 0xDA, 0x7B, 0xCC, 0x6F, 0xAE, 0x46, 0xCD, 0x5B, 0x5E, 0x8D, 0xD5, 0x13, 0xCD, 0x68, 0xE9, 0x3C, 0x8A, 0x80, 0xD4, 0x28, 0xBE, 0x2C, 0xDC, 0x40, 0x26, 0x03, 0xFD, 0x99, 0x67, 0x0D, 0x13, 0xF3, 0xA8, 0xA9, 0x33, 0xF5, 0xB4, 0x42, 0x9B, 0xB8, 0x6D, 0xBA, 0xC2, 0xD2, 0x49, 0x11, 0x4B, 0xB5, 0xA6, 0x4A, 0x1F, 0xFF, 0x73, 0x9A, 0x03, 0x55, 0x1B, 0x5C, 0x77, 0x6B, 0x9C, 0x04, 0xB5, 0xD6, 0x5C, 0x72, 0x58, 0x56, 0x46, 0xA5, 0x90, 0xC5, 0xCA, 0x83, 0xE6, 0x4A, 0x32, 0x0C, 0x74, 0x4B, 0x3F, 0xAA, 0x8D, 0x2A, 0x19, 0x49, 0xBA, 0xAB, 0xD9, 0x57, 0x3E, 0x3A, 0x36, 0x5D, 0xA3, 0x64, 0xDA, 0x87, 0xDB, 0x90, 0x57, 0xAA, 0x72, 0xFC, 0xAE, 0x90, 0x09, 0xBC, 0x83, 0xAE, 0x9B, 0xC9, 0x3C, 0xD1, 0x2B, 0xEB, 0xF7, 0x64, 0xB4, 0xFC, 0x12, 0xF5, 0x11, 0xE9, 0x07, 0xB4, 0xFE, 0x77, 0xA1, 0x27, 0xB8, 0x27, 0xBD, 0x93, 0x18, 0x61, 0x25, 0x24, 0x7E, 0x22, 0xE2, 0xD8, 0xBF, 0x17, 0x6B, 0x89, 0x08, 0xAE, 0x2A, 0xB4, 0x9D, 0xF0, 0xE5, 0x5F, 0xF2, 0xDD, 0x47, 0xD8, 0x8B, 0x2A, 0x5C, 0x79, 0x44, 0xBB, 0xB4, 0xDD, 0x86, 0x49, 0xFC, 0xAB, 0x0C, 0xA5, 0xB5, 0x93, 0xE6, 0x60, 0x28, 0x85, 0x4A, 0xBA, 0x41, 0xF3, 0xD2, 0x7B, 0xB0, 0x6C, 0xFE, 0xD3, 0xC4, 0x40, 0xF5, 0x25, 0xC1, 0x9E, 0xE8, 0x52, 0x2C, 0x52, 0x64, 0x0A, 0x69, 0xC6, 0xAE, 0x4B, 0xA4, 0x3E, 0x1D, 0x78, 0x9A, 0xCC, 0xC3, 0x65, 0x1F, 0x7E, 0x47, 0x11, 0x6A, 0x53, 0x4D, 0x2C, 0x01, 0xD4, 0xB4, 0x3F, 0xE4, 0x54, 0x70, 0x03, 0xA5, 0x9F, 0x0C, 0x82, 0xDC, 0x52, 0x66, 0xA9, 0xE8, 0xB2, 0x77, 0x09, 0x1C, 0xF4, 0x89, 0x3C, 0x37, 0xD2, 0xA0, 0xBA, 0x2F, 0x7F, 0x1F, 0x1C, 0xA9, 0xDE, 0xA2, 0x74, 0xF3, 0x9E, 0x82, 0x15, 0x00, 0x63, 0x9C, 0x7F, 0xE1, 0x34, 0xE0, 0x89, 0x4D, 0x12, 0x91, 0x07, 0x76, 0xD1, 0x27, 0xFC, 0x47, 0xBD, 0xA3, 0x1C, 0x26, 0x73, 0xA1, 0xB9, 0x49, 0xEB, 0xE1, 0x9B, 0x48, 0x53, 0xFC, 0x0A, 0xC4, 0x0B, 0x21, 0x23, 0x93, 0xD0, 0x3C, 0xA4, 0x3C, 0xB0, 0x57, 0x15, 0x81, 0x24, 0x78, 0xF1, 0xD5, 0x16, 0xC8, 0xDF, 0xCE, 0x2B, 0xB0, 0x52, 0x78, 0x9D, 0xF5, 0x6D, 0x82, 0x06, 0xAD, 0xA6, 0xAD, 0x22, 0xCD, 0xA1, 0xE9, 0x14, 0x90, 0xD4, 0x82, 0x67, 0x12, 0x4F, 0x43, 0x16, 0xA4, 0x75, 0xEC, 0x54, 0x38, 0x80, 0x18, 0x09, 0x1F, 0x41, 0x22, 0xF1, 0x07, 0x81, 0x24, 0xEA, 0x88, 0xBD, 0xF3, 0x6A, 0x56, 0x25, 0xA8, 0x6B, 0x9C, 0x77, 0xAB, 0xCF, 0xA1, 0x0F, 0xAC, 0xDB, 0xF0, 0x77, 0x30, 0x49, 0xF3, 0x21, 0x1D, 0xA1, 0xF9, 0x94, 0xD1, 0xE4, 0x6A, 0x90, 0x48, 0xD8, 0x09, 0xA6, 0x55, 0x6B, 0x17, 0x6F, 0x03, 0x3F, 0x19, 0xDC, 0xC3, 0x3B, 0x21, 0xA6, 0x6E, 0x7B, 0x60, 0x34, 0xE2, 0xAB, 0xB9, 0xE7, 0x89, 0xA0, 0xA7, 0x09, 0xB6, 0xF3, 0x56, 0x75, 0x90, 0x3A, 0xCF, 0xFA, 0x12, 0xBE, 0x1D, 0xF1, 0xA7, 0xB9, 0x92, 0x56, 0x90, 0xBB, 0xC5, 0x51, 0x72, 0x0F, 0x98, 0x12, 0x23, 0x6D, 0x9F, 0x94, 0x6E, 0x13, 0x29, 0x6F, 0xE9, 0xC9, 0xF6, 0x0B, 0xFE, 0xD2, 0xE4, 0x91, 0xDF, 0xEF, 0x3F, 0xB5, 0xFE, 0x43, 0x49, 0x9A, 0xFB, 0x1B, 0xD3, 0x81, 0xCA, 0xA7, 0x0E, 0x03, 0xD5, 0x27, 0xB9, 0x57, 0xE8, 0xC7, 0x75, 0x52, 0xC9, 0x4D, 0xF3, 0x33, 0x9A, 0x06, 0xC5, 0x47, 0xB3, 0x4D, 0xE4, 0x61, 0x60, 0x73, 0x4C, 0x7D, 0xF3, 0xC7, 0x9C, 0x47, 0x91, 0x73, 0x9A, 0x9A, 0xF3, 0x8F, 0x05, 0x3F, 0x6E, 0xD8, 0x55, 0x1C, 0xEC, 0x77, 0xB0, 0x0E, 0x2E, 0x67, 0xBB, 0x7F, 0xA8, 0x39, 0xCF, 0x8E, 0x5E, 0x34, 0xB6, 0xDA, 0x93, 0xDF, 0x64, 0x59, 0xA8, 0xB3, 0x94, 0xBE, 0xB3, 0x38, 0xAC, 0x29, 0x55, 0xF6, 0x2F, 0xBC, 0x4E, 0x2E, 0x03, 0x5D, 0x17, 0x3B, 0x37, 0x4A, 0x8B, 0x6E, 0x46, 0xD8, 0x35, 0x78, 0x94, 0x4E, 0x08, 0xF6, 0xAA, 0x3B, 0x58, 0xBE, 0xDC, 0xF7, 0xA8, 0xE9, 0x04, 0x2B, 0xD8, 0x7D, 0xBE, 0x71, 0x0B, 0xD7, 0xCB, 0x61, 0xA3, 0x01, 0x17, 0x6E, 0xB6, 0x7C, 0xA7, 0xDD, 0x29, 0xF7, 0xA6, 0x3C, 0xD2, 0xD8, 0x01, 0xD9, 0x16, 0xBE, 0xA4, 0x1A, 0x5C, 0x11, 0xC5, 0xAD, 0x67, 0x55, 0x94, 0x87, 0xAE, 0xAB, 0xBD, 0xCB, 0x14, 0x07, 0xBC, 0x33, 0x1D, 0xAC, 0x9A, 0xEC, 0x63, 0x53, 0x63, 0xC7, 0x6D, 0x71, 0x5D, 0x51, 0x8D, 0x09, 0x0C, 0x0E, 0x33, 0xF5, 0x8D, 0x12, 0x06, 0xA3, 0x53, 0xEB, 0xA3, 0xD0, 0x52, 0x7F, 0x91, 0xAF, 0x80, 0x77, 0x14, 0x80, 0xAC, 0x00, 0x3F, 0x45, 0x3D, 0xAE, 0xF5, 0xE5, 0xB0, 0x43, 0x2C, 0x6A, 0x38, 0xDC, 0xC5, 0xFE, 0x67, 0x8D, 0x1B, 0xF9, 0x26, 0xAF, 0x3B, 0xD5, 0x7B, 0x85, 0x43, 0x2E, 0x81, 0x86, 0x32, 0xF1, 0x71, 0xFB, 0xBD, 0x3A, 0x48, 0xD6, 0x60, 0x95, 0xA5, 0x59, 0xA3, 0xDC, 0x41, 0x3B, 0xFB, 0x9F, 0x87, 0x12, 0xEA, 0xE2, 0xFF, 0xF2, 0x9A, 0x1E, 0xE9, 0x5E, 0xB3, 0x43, 0x6C, 0x13, 0xDC, 0x60, 0x5C, 0x25, 0x96, 0xF8, 0xCF, 0xAF, 0x66, 0x4B, 0xB4, 0x5E, 0x53, 0x0C, 0x2A, 0xE9, 0x43, 0xE7, 0x5A, 0x7D, 0x8E, 0x3C, 0xC0, 0xC1, 0x47, 0xDB, 0xAF, 0x9C, 0x6C, 0x75, 0x5B, 0x13, 0x02, 0x9C, 0xA4, 0xFB, 0x93, 0x7D, 0xE0, 0x52, 0xEA, 0x52, 0xB2, 0x18, 0xFC, 0x1A, 0x0E, 0x1B, 0x7E, 0x28, 0x2F, 0x86, 0xCC, 0xAB, 0x9E, 0x06, 0xF8, 0xFB, 0x7D, 0x31, 0x00, 0xC0, 0x4C, 0xCF, 0x3A, 0x3D, 0x17, 0x40, 0x9D, 0x37, 0xE8, 0xE6, 0x83, 0xB3, 0xEC, 0x3F, 0x69, 0x9E, 0x82, 0x6A, 0xAB, 0x6E, 0xCD, 0x5F, 0xE0, 0x46, 0xBA, 0x25, 0xD9, 0x0F, 0x6E, 0xA7, 0xF6, 0x92, 0x00, 0xB8, 0x23, 0xF4, 0x7F, 0xBA, 0x07, 0x68, 0x7E, 0x50, 0xA2, 0x1E, 0x42, 0xC5, 0xBE, 0xE1, 0x7A, 0x03, 0x72, 0xCB, 0xE3, 0xA1, 0x2E, 0x19, 0xE9, 0x77, 0x06, 0xB4, 0x59, 0x88, 0x87, 0x7D, 0xAD, 0xA6, 0x05, 0xAE, 0xB2, 0x72, 0x25, 0x7F, 0x43, 0x45, 0xB4, 0xCB, 0xE4, 0x36, 0x70, 0x2B, 0xB5, 0x92, 0xEC, 0x00, 0x05, 0x61, 0x9B, 0xB5, 0xFF, 0x90, 0x73, 0x02, 0x63, 0xB5, 0x1B, 0xF1, 0x37, 0x7E, 0xCF, 0xB4, 0x6B, 0xF0, 0x74, 0xF7, 0x24, 0x6D, 0x8D, 0xBA, 0xD9, 0xC9, 0x52, 0x3B, 0x59, 0xB5, 0xD6, 0xFE, 0x95, 0x86, 0x8F, 0xBC, 0xB2, 0x52, 0x6A, 0x46, 0x43, 0xBF, 0x69, 0xFB, 0xC9, 0x93, 0xE0, 0x2E, 0xAA, 0x13, 0xB9, 0x09, 0x74, 0x0E, 0x71, 0xED, 0xFF, 0x90, 0xA6, 0x0C, 0xA4, 0x2E, 0x59, 0x95, 0x59, 0xE2, 0xF5, 0xA7, 0x6B, 0x51, 0x5E, 0xB1, 0xCB, 0xC3, 0xB6, 0xE3, 0x45, 0x6F, 0xEC, 0x33, 0x9A, 0xE7, 0x57, 0xE4, 0x33, 0xF6, 0xD7, 0xC9, 0x39, 0x67, 0xA8, 0x3E, 0x86, 0x7F, 0x24, 0xD8, 0xC2, 0x01, 0xED, 0x12, 0xC5, 0xA3, 0x05, 0xBF, 0x34, 0x91, 0xC0, 0xC1, 0x60, 0x5A, 0xEF, 0x40, 0xF6, 0x3A, 0xFF, 0xCD, 0x3D, 0xB1, 0xB9, 0x7F, 0xBC, 0x0C, 0x9D, 0xA2, 0x42, 0x95, 0xEB, 0x81, 0xD6, 0xA7, 0xA5, 0xBB, 0x17, 0xE5, 0x37, 0x5E, 0x60, 0xEE, 0xB5, 0x7A, 0x57, 0x7B, 0x89, 0xA7, 0xA4, 0xC6, 0x1A, 0x9A, 0xA5, 0x42, 0xF3, 0x2E, 0x6D, 0x95, 0x52, 0xB6, 0x90, 0xD0, 0x4C, 0x07, 0xED, 0x83, 0xA6, 0x77, 0xBF, 0x28, 0x24, 0xFC, 0xF3, 0x3A, 0xF7, 0x15, 0x8F, 0xF7, 0x2A, 0x6A, 0x57, 0x94, 0xA6, 0xBB, 0xC9, 0x5A, 0xA6, 0x54, 0xCE, 0x58, 0x74, 0xB5, 0x81, 0x56, 0xA5, 0xB6, 0xB2, 0x36, 0x3D, 0x15, 0x28, 0xA9, 0x6A, 0x03, 0x5D, 0x56, 0x67, 0xF1, 0x5D, 0x4B, 0x03, 0x66, 0x5A, 0x08, 0xC8, 0x4B, 0x60, 0x9D, 0x7F, 0x57, 0x27, 0x52, 0x16, 0xE1, 0xD3, 0xD1, 0xCE, 0x2B, 0xBF, 0xE2, 0x59, 0xD9, 0xEA, 0x5C, 0xF9, 0xC6, 0x95, 0xD7, 0x14, 0x5A, 0x35, 0xC1, 0xFE, 0x57, 0xFD, 0x42, 0xDE, 0x36, 0xCB, 0xCE, 0x9A, 0x35, 0xA2, 0x87, 0x34, 0x83, 0xBE, 0x48, 0x7E, 0x96, 0xDA, 0xAB, 0xD9, 0x07, 0x0C, 0x50, 0x7D, 0xFE, 0x33, 0x79, 0xC1, 0xFF, 0x65, 0xDB, 0x77, 0x96, 0xC0, 0x67, 0x5D, 0xCB, 0xF3, 0xAA, 0xD1, 0x1E, 0x40, 0x73, 0x0B, 0xD7, 0xDB, 0xB9, 0xB3, 0xE1, 0x2E, 0xDF, 0xDF, 0xFE, 0x7C, 0xED, 0x25, 0xE1, 0x17, 0xEB, 0xDF, 0xC6, 0x2C, 0x69, 0x36, 0x63, 0x9A, 0x0E, 0x51, 0xCE, 0xA7, 0xCF, 0xD1, 0x14, 0x82, 0x73, 0x69, 0xFE, 0x24, 0x00, 0xBE, 0xF0, 0x3F, 0xDF, 0x6A, 0xC6, 0xA7, 0xF8, 0x58, 0x35, 0x3F, 0x16, 0x8C, 0x77, 0x0F, 0x69, 0xDC, 0x20, 0x6C, 0x77, 0xD2, 0xD7, 0x0F, 0x8B, 0x23, 0xED, 0x47, 0x4C, 0x46, 0xA9, 0xBF, 0x7D, 0x46, 0xF5, 0x68, 0xF9, 0x0D, 0x9B, 0x79, 0xDA, 0x55, 0x40, 0x81, 0x65, 0x80, 0x66, 0x16, 0xC8, 0xA6, 0x6D, 0x26, 0xCB, 0xC0, 0x5B, 0xFE, 0x5D, 0x4D, 0x47, 0xA4, 0xAE, 0xDE, 0x57, 0x1A, 0x2F, 0xC9, 0x6A, 0xDD, 0x59, 0x0D, 0x76, 0xF2, 0xB9, 0x4E, 0x9B, 0xEB, 0x94, 0xF2, 0xE3, 0x76, 0xB7, 0x6A, 0x84, 0x0A, 0xB5, 0xED, 0xDF, 0x06, 0x42, 0xB9, 0xDC, 0xDA, 0x57, 0xAB, 0x03, 0x7E, 0x5A, 0x96, 0xFC, 0x97, 0x35, 0xF2, 0x5F, 0xD6, 0x25, 0xE0, 0x7A, 0xBF, 0x57, 0x0D, 0xFF, 0x82, 0xFE, 0xDE, 0xDB, 0xEA, 0x77, 0x81, 0x67, 0x3D, 0x0C, 0x75, 0x1C, 0x28, 0xD4, 0xD9, 0xB3, 0x96, 0x06, 0xDE, 0xB2, 0xDD, 0x66, 0xFC, 0x03, 0xBA, 0x59, 0x9E, 0x30, 0x2C, 0x03, 0x4E, 0x30, 0xA6, 0x68, 0xAF, 0x82, 0x61, 0xF4, 0x97, 0x1A, 0x57, 0xB0, 0x82, 0x1E, 0x4B, 0xC2, 0xA0, 0xC0, 0xDF, 0xB3, 0xFE, 0x8E, 0x3A, 0xC6, 0x6B, 0x57, 0xFD, 0x54, 0xD5, 0x58, 0xF7, 0x8C, 0xBA, 0x51, 0xE8, 0x0E, 0xE7, 0x6F, 0x35, 0x7F, 0x50, 0xAA, 0x83, 0xC2, 0x38, 0x17, 0xBE, 0x60, 0xBD, 0xCB, 0xD0, 0x09, 0x09, 0x2C, 0x9F, 0xE9, 0x1C, 0xC1, 0x75, 0xF4, 0x3A, 0x0D, 0x1F, 0x8C, 0xA3, 0x8F, 0x26, 0x97, 0x83, 0xD4, 0x96, 0x96, 0xFC, 0xE6, 0x38, 0x5B, 0xDD, 0xD3, 0xC2, 0x79, 0x69, 0xF3, 0x00, 0x4A, 0x49, 0x4E, 0xF6, 0x43, 0xB6, 0x4F, 0x79, 0x57, 0xE1, 0xD7, 0x9C, 0x35, 0x6C, 0x69, 0xF9, 0x8B, 0xE8, 0x3E, 0xE1, 0x6C, 0x4E, 0x9D, 0x9B, 0x13, 0x30, 0x5F, 0x7C, 0xDB, 0xAA, 0x15, 0x2D, 0x56, 0xD8, 0x53, 0xC3, 0xD4, 0x35, 0xC0, 0xE8, 0x66, 0xD7, 0xCC, 0xE2, 0x0C, 0x9A, 0x26, 0x2E, 0x27, 0x2F, 0xCF, 0x4C, 0x5E, 0x55, 0x40, 0x16, 0xCF, 0x64, 0xCF, 0x2B, 0x9D, 0x5D, 0x9E, 0x99, 0xBD, 0x8F, 0xB9, 0x8A, 0x9D, 0x18, 0x55, 0xC9, 0xBF, 0xCC, 0x6F, 0x77, 0xFB, 0x4B, 0xF1, 0x51, 0x9A, 0x61, 0xB5, 0x1B, 0xF9, 0x47, 0x71, 0x97, 0x5A, 0xAD, 0x4E, 0x02, 0x2A, 0x4C, 0xEA, 0xE4, 0xD8, 0xD2, 0x79, 0xF8, 0x8B, 0xF4, 0xAC, 0x8A, 0x2C, 0xF9, 0xD4, 0x9C, 0x02, 0xE6, 0xA1, 0xCA, 0xB0, 0xC2, 0xBD, 0x55, 0xAC, 0x8C, 0xDB, 0x15, 0xC1, 0xFC, 0x2B, 0x11, 0x1E, 0xBC, 0x7A, 0x71, 0xB9, 0x4B, 0xBF, 0x22, 0x54, 0x9E, 0x62, 0x65, 0x44, 0x74, 0xCA, 0x9D, 0xD4, 0x53, 0xEA, 0x60, 0xE0, 0x50, 0xF5, 0xFA, 0xD8, 0x95, 0x3C, 0x27, 0xEC, 0x73, 0xD2, 0x5A, 0xDE, 0x27, 0xD1, 0xB8, 0x8C, 0x83, 0xC2, 0xCC, 0xD2, 0x0D, 0x79, 0x2F, 0x44, 0xEC, 0xB4, 0xAF, 0x65, 0x89, 0x92, 0x67, 0x61, 0x3C, 0xAE, 0x4C, 0x1E, 0xED, 0xE2, 0x2B, 0x7F, 0xA1, 0xC4, 0xAD, 0x04, 0x48, 0x3F, 0xD0, 0xFE, 0x1F, 0xA5, 0x07, 0x27, 0x1B, 0xBF, 0x44, 0x5E, 0x57, 0xFC, 0xAD, 0xDA, 0x18, 0xC7, 0x96, 0x03, 0xC2, 0x29, 0xA9, 0xB0, 0xB2, 0xA4, 0xDC, 0x3D, 0xA7, 0x4E, 0x79, 0x29, 0xB5, 0xAB, 0x84, 0x07, 0x50, 0x42, 0x1E, 0x57, 0x71, 0x80, 0xB7, 0x2E, 0xA4, 0x5C, 0x01, 0xF6, 0x5A, 0x65, 0xA2, 0x73, 0x40, 0x0E, 0x15, 0xC1, 0xE8, 0x60, 0x8C, 0xE1, 0xEF, 0x30, 0xB6, 0x7A, 0x1D, 0xF4, 0x73, 0xF1, 0x5C, 0xF5, 0x54, 0xDE, 0xB1, 0x24, 0xB5, 0xEA, 0x4F, 0xC9, 0x98, 0xCC, 0xDF, 0xAA, 0xDC, 0x54, 0xAB, 0x22, 0x73, 0x74, 0x49, 0xE8, 0x42, 0x76, 0x18, 0x72, 0xD1, 0xB9, 0x4E, 0x4E, 0xC2, 0x22, 0x46, 0x3B, 0x8A, 0x40, 0xBE, 0x94, 0x2B, 0xD8, 0x01, 0x70, 0x88, 0xCC, 0x0F, 0xFE, 0xBB, 0x66, 0x23, 0xE8, 0x14, 0x39, 0xDD, 0xC8, 0xE1, 0x37, 0xC6, 0x2B, 0x0D, 0x39, 0xC5, 0x16, 0xE9, 0x33, 0x74, 0x41, 0xA9, 0xEB, 0x0A, 0x3C, 0x35, 0x49, 0xA1, 0x6A, 0xD6, 0x36, 0x9C, 0xE1, 0x14, 0x2D, 0xAF, 0x42, 0x03, 0x2D, 0x03, 0xD0, 0x6A, 0xE8, 0xB6, 0x85, 0x01, 0xFB, 0x03, 0x5E, 0xC3, 0x57, 0x04, 0x04, 0xB4, 0x4E, 0x51, 0xDA, 0x84, 0x09, 0x9A, 0x4E, 0x70, 0xCF, 0xC7, 0x3A, 0xD5, 0x1F, 0x2D, 0xBA, 0x91, 0x1A, 0x60, 0xDA, 0x9C, 0x9A, 0x92, 0x77, 0xAF, 0x9A, 0x15, 0xDA, 0xCB, 0xAC, 0xD7, 0x3C, 0x75, 0x1C, 0x94, 0x5D, 0x55, 0x7D, 0xA3, 0x3D, 0x45, 0xB3, 0x60, 0xD1, 0xC2, 0x7F, 0xB1, 0xAF, 0xE0, 0x4B, 0x9C, 0xEE, 0x57, 0xBB, 0xE4, 0xA7, 0xFC, 0x58, 0xC8, 0xDC, 0xAE, 0x42, 0x76, 0x57, 0xF4, 0xB7, 0xB6, 0xBE, 0x02, 0x76, 0xD2, 0xFD, 0xE6, 0xD9, 0xC9, 0xB3, 0x72, 0x9E, 0xD4, 0xE1, 0x21, 0x5B, 0x2B, 0x57, 0x18, 0xC2, 0x1C, 0xAF, 0x4B, 0xDF, 0x61, 0x1B, 0xA9, 0x6B, 0x91, 0xD7, 0xF0, 0x77, 0xB3, 0x20, 0xEC, 0x3C, 0xF8, 0xCD, 0xF4, 0xBC, 0x24, 0x2E, 0x5E, 0xA4, 0x66, 0x94, 0x82, 0xA9, 0x3B, 0x85, 0x1F, 0xCB, 0x6F, 0xE7, 0xB4, 0x94, 0x5E, 0x63, 0x5E, 0x2C, 0xBA, 0x91, 0xCE, 0xE5, 0x0E, 0x57, 0xEC, 0x0E, 0x3B, 0x27, 0x7E, 0xCC, 0xAD, 0x73, 0x7E, 0x00, 0x72, 0x25, 0x73, 0x18, 0x67, 0x54, 0x54, 0xF9, 0x6F, 0x2A, 0x1D, 0xB3, 0x51, 0xAE, 0x32, 0x68, 0xF3, 0x6E, 0x66, 0x62, 0x08, 0x50, 0x38, 0x3D, 0xF7, 0xBD, 0xA0, 0xA6, 0x24, 0xB7, 0xE8, 0x6E, 0xA9, 0x5D, 0x45, 0x63, 0xB9, 0x3E, 0x2D, 0xA7, 0x6A, 0x0F, 0x9B, 0x17, 0xF6, 0x45, 0x64, 0xCB, 0xEF, 0x73, 0x11, 0x03, 0xB5, 0xD2, 0x42, 0xC6, 0x2D, 0xF4, 0x82, 0xE2, 0x0A, 0x75, 0x3C, 0x36, 0x1B, 0x48, 0x26, 0x7F, 0x67, 0xDC, 0x2C, 0x79, 0x0D, 0xB9, 0xE4, 0xC4, 0x96, 0xB3, 0xF8, 0x44, 0xC1, 0x66, 0x66, 0x64, 0xF1, 0xA5, 0xD2, 0x43, 0x55, 0xFC, 0x94, 0x23, 0x2C, 0x35, 0x7F, 0x7E, 0xE8, 0x16, 0x41, 0xBF, 0xE8, 0x86, 0x73, 0xB4, 0xF2, 0x87, 0x3C, 0x8C, 0xD1, 0x89, 0xAE, 0x53, 0x9E, 0xA6, 0xCE, 0xC4, 0xE8, 0xC0, 0x7D, 0xEC, 0x43, 0xB2, 0x92, 0xEB, 0x06, 0x44, 0x65, 0x78, 0xF2, 0xA6, 0x71, 0x4F, 0xE7, 0x6A, 0xF9, 0x9F, 0x8B, 0xA2, 0x8B, 0x3E, 0x0B, 0x5F, 0x26, 0x17, 0x57, 0x46, 0x4B, 0x66, 0x84, 0x48, 0xF8, 0x51, 0x32, 0x95, 0xD3, 0x0A, 0x65, 0xB3, 0x32, 0x88, 0x21, 0x44, 0x0F, 0x01, 0xEB, 0xA8, 0xB3, 0x31, 0x36, 0x18, 0xA3, 0xD6, 0xC6, 0xA7, 0xC9, 0x9E, 0x2B, 0xF2, 0x52, 0x24, 0xB2, 0x38, 0xCE, 0xA5, 0xAC, 0x7C, 0xB9, 0xA8, 0x30, 0xA7, 0x80, 0xA5, 0x40, 0x92, 0xA6, 0x97, 0xC3, 0xCA, 0x90, 0xE0, 0x0E, 0xDE, 0x5C, 0xC0, 0xD7, 0x09, 0x57, 0x46, 0x83, 0x54, 0x46, 0x02, 0xFA, 0x0B, 0xE4, 0x51, 0x9E, 0x61, 0x57, 0x41, 0x3D, 0xBA, 0x65, 0xF1, 0x15, 0xF4, 0xB3, 0x6C, 0x4B, 0xC2, 0x5B, 0x14, 0xA8, 0x9A, 0x99, 0xEE, 0x8C, 0xA6, 0xE5, 0xFB, 0xE7, 0x3E, 0x40, 0x3E, 0x27, 0x3A, 0x95, 0x1E, 0x41, 0x5A, 0x83, 0x0B, 0xB8, 0x69, 0x88, 0x87, 0x93, 0xB5, 0xD2, 0x01, 0x7A, 0x63, 0x79, 0x45, 0x15, 0x01, 0xCD, 0xA4, 0x70, 0xF0, 0x58, 0x70, 0x1D, 0x12, 0x13, 0x19, 0x6D, 0x58, 0x25, 0x95, 0xC7, 0x0E, 0xEA, 0x2F, 0x33, 0x0F, 0xA4, 0xB0, 0x75, 0x66, 0x79, 0x1E, 0xD9, 0x2D, 0x9A, 0x80, 0x44, 0xA7, 0x92, 0xD1, 0x44, 0x7D, 0x70, 0x21, 0x47, 0x8B, 0x89, 0x1D, 0x79, 0xCA, 0x29, 0xC8, 0x71, 0xFA, 0x23, 0x95, 0x0C, 0x1A, 0xB2, 0x60, 0xE3, 0x4B, 0xC0, 0x3D, 0xD0, 0xEC, 0xB0, 0x91, 0x26, 0x6B, 0x11, 0x75, 0xB1, 0xAC, 0x21, 0xB4, 0x62, 0x45, 0x52, 0x64, 0x6D, 0x5F, 0x2E, 0x2D, 0x53, 0x6F, 0xFC, 0x37, 0x61, 0xB8, 0x48, 0xA8, 0x7F, 0x12, 0x3C, 0xBB, 0x4A, 0x42, 0x1E, 0x5D, 0xB4, 0x5B, 0x71, 0x5A, 0x95, 0x42, 0x3B, 0xA3, 0xC2, 0x60, 0x73, 0x73, 0x06, 0x7E, 0x18, 0xDC, 0x0F, 0x58, 0x84, 0x88, 0xBB, 0xAA, 0x84, 0x39, 0x91, 0xAD, 0xED, 0x7B, 0x4B, 0xFF, 0x89, 0x77, 0x6C, 0xFE, 0x90, 0xC5, 0x4A, 0x8F, 0x6C, 0x50, 0xC5, 0xDB, 0x15, 0x4E, 0x37, 0x31, 0x83, 0x10, 0xF6, 0x03, 0x1D, 0xB2, 0x28, 0x40, 0x51, 0xA7, 0x6E, 0xA2, 0x1E, 0x53, 0x49, 0x60, 0xCC, 0xEC, 0x26, 0x7E, 0x1A, 0x3C, 0x88, 0xA5, 0x33, 0xC7, 0x25, 0x31, 0xE5, 0x06, 0xE6, 0xC7, 0x74, 0x47, 0xF6, 0xF4, 0xAA, 0x29, 0xB9, 0x21, 0xF9, 0x59, 0xDC, 0xE1, 0xE2, 0xBF, 0x93, 0xB6, 0x08, 0xD9, 0x15, 0xA7, 0x82, 0xD6, 0xCA, 0x34, 0xDC, 0x02, 0xC7, 0x10, 0x78, 0x86, 0x84, 0x6A, 0x79, 0x55, 0x6D, 0x2F, 0x3F, 0x49, 0xF9, 0x84, 0x7D, 0x51, 0x46, 0xA1, 0xAC, 0xD2, 0x0D, 0x59, 0x2F, 0xA4, 0xE5, 0xE5, 0xBE, 0x79, 0xE9, 0x2C, 0xB3, 0x4A, 0x7D, 0xD1, 0xD5, 0xBC, 0xDD, 0x55, 0x96, 0xE5, 0x60, 0xC2, 0x39, 0x7E, 0x35, 0x3B, 0x33, 0x48, 0x27, 0x9D, 0xC3, 0xAF, 0x77, 0x2C, 0x86, 0xB4, 0x52, 0xCC, 0xB2, 0x4B, 0x3D, 0x56, 0x71, 0x81, 0x82, 0x60, 0xEF, 0x00, 0x1F, 0x48, 0x98, 0xFF, 0xA8, 0x74, 0xA6, 0xB8, 0xB4, 0xC8, 0x50, 0x3E, 0x99, 0xE9, 0x59, 0x66, 0x57, 0xB9, 0x37, 0xCF, 0x93, 0xB9, 0xB5, 0xCA, 0x3E, 0x5E, 0xCF, 0xE5, 0xF1, 0x36, 0x05, 0xEE, 0x10, 0x0F, 0x8A, 0x5A, 0x17, 0x7D, 0x82, 0xC6, 0xC9, 0x83, 0x2C, 0x0B, 0x55, 0x1F, 0x95, 0x77, 0x29, 0xF1, 0xF8, 0x34, 0xE0, 0xA7, 0xE2, 0x79, 0xD6, 0x49, 0xCE, 0x04, 0x61, 0x6F, 0xDE, 0x43, 0xEE, 0xAE, 0x8A, 0xC9, 0xC5, 0xA9, 0x7C, 0x9B, 0x1C, 0xB7, 0xF2, 0x8B, 0x42, 0x8F, 0xB8, 0xEB, 0xEC, 0x1B, 0x62, 0xB3, 0xC0, 0x69, 0x22, 0x3F, 0xE9, 0xED, 0x45, 0x67, 0xC1, 0x26, 0xC5, 0x6F, 0xCB, 0x5C, 0xD5, 0x1F, 0x60, 0x17, 0x25, 0x19, 0x4F, 0x02, 0x15, 0xF2, 0x05, 0xE9, 0xB3, 0xA4, 0x2C, 0xFE, 0xEA, 0xEC, 0x1C, 0xA9, 0x7F, 0xD9, 0xF7, 0x82, 0x60, 0x99, 0x79, 0x56, 0x7E, 0xA9, 0x9F, 0x3C, 0x33, 0x96, 0xCA, 0x02, 0x14, 0xFE, 0x01, 0xFD, 0xC2, 0x24, 0x25, 0xCB, 0xD1, 0x06, 0x0C, 0x06, 0x86, 0x2D, 0x25, 0x6A, 0x73, 0xB0, 0x84, 0x12, 0xF1, 0x9F, 0xF9, 0x35, 0xD2, 0x15, 0xC9, 0x6B, 0xE1, 0xC3, 0x3C, 0x4E, 0xFA, 0x73, 0x58, 0x55, 0xB6, 0x38, 0x67, 0x07, 0x2C, 0xCC, 0xF0, 0x29, 0xAA, 0x87, 0xD3, 0x63, 0xA2, 0x2B, 0xEF, 0xC2, 0x36, 0x01, 0x87, 0x04, 0x08, 0x3C, 0xCF, 0xD1, 0x15, 0x9C, 0x00, 0xE5, 0x58, 0x86, 0xAA, 0x63, 0xC1, 0xC7, 0x16, 0x9F, 0xF1, 0x0F, 0xE0, 0x36, 0x69, 0x62, 0xC2, 0x68, 0xED, 0x2E, 0xCE, 0x83, 0x94, 0x04, 0x2D, 0xAF, 0x18, 0xCA, 0x8A, 0x21, 0x77, 0x64, 0xAC, 0x2F, 0x38, 0x81, 0x7F, 0x8C, 0x39, 0x5C, 0xFE, 0x11, 0xDB, 0x19, 0xB0, 0x98, 0x5F, 0xAB, 0x5E, 0xB4, 0x28, 0x09, 0xF8, 0x84, 0x2C, 0xA2, 0x93, 0xEA, 0x6A, 0xA8, 0xC2, 0x22, 0x9E, 0x48, 0x03, 0x87, 0x24, 0x99, 0xB1, 0x79, 0xF5, 0xA3, 0xD8, 0x7B, 0x92, 0x72, 0x6B, 0x5B, 0x8B, 0x9A, 0x32, 0xF0, 0x9A, 0xD4, 0x8C, 0xD9, 0x79, 0xC7, 0x0C, 0x4F, 0x16, 0x7F, 0x2F, 0x1B, 0xD4, 0xB1, 0xFD, 0x1F, 0xF3, 0x7E, 0x10, 0x7C, 0x87, 0xED, 0xE0, 0x44, 0xB4, 0x83, 0xD6, 0xAF, 0x3E, 0x00, 0x1D, 0x34, 0x4F, 0x22, 0xDA, 0xC0, 0x3A, 0x71, 0x56, 0x74, 0x5B, 0xFB, 0x3C, 0xD6, 0x9A, 0x78, 0x5E, 0xCB, 0xA6, 0x82, 0xF1, 0xA9, 0x0D, 0x8D, 0xA6, 0x14, 0x20, 0x67, 0xB8, 0xEE, 0xAF, 0xE8, 0xFA, 0xD2, 0x5D, 0x46, 0x8E, 0xBF, 0x9C, 0x1F, 0xA6, 0x09, 0xB5, 0xBF, 0x0C, 0x7A, 0xAA, 0x30, 0xEA, 0xB0, 0xFA, 0x05, 0x3C, 0x66, 0x61, 0x2C, 0x71, 0x08, 0xC4, 0xC5, 0x77, 0xB9, 0xDF, 0x53, 0x97, 0xF1, 0x52, 0x78, 0x87, 0x33, 0x29, 0xA5, 0xCE, 0x82, 0xE1, 0xDC, 0x67, 0xE9, 0xEF, 0x45, 0x78, 0xD1, 0xCB, 0x58, 0xB5, 0x74, 0x46, 0x45, 0xA4, 0xEF, 0x17, 0x65, 0x02, 0xE7, 0xA2, 0x43, 0x1E, 0xF2, 0x8F, 0xF8, 0x3B, 0xFD, 0x29, 0x16, 0x28, 0x5F, 0x4D, 0xC9, 0xC4, 0xF7, 0x2B, 0x2D, 0xC5, 0x1F, 0xD9, 0x45, 0xD9, 0x47, 0x39, 0x13, 0xAA, 0x56, 0xE7, 0xAD, 0x2E, 0x99, 0xCC, 0xDD, 0x5A, 0x74, 0x23, 0xA3, 0x43, 0xE0, 0x54, 0x6E, 0xBF, 0x78, 0x86, 0x78, 0x25, 0xEB, 0xA7, 0xEF, 0x0A, 0x05, 0x8B, 0x9F, 0x63, 0xBF, 0x1B, 0xD1, 0x49, 0x65, 0xF4, 0x42, 0xCC, 0x41, 0x71, 0xD2, 0xE2, 0x1C, 0xBE, 0x1D, 0x70, 0x15, 0xFB, 0x96, 0xAF, 0x29, 0xA1, 0xB3, 0x64, 0x95, 0x03, 0x65, 0x53, 0x8B, 0x28, 0x6C, 0x43, 0xA5, 0x53, 0xFA, 0x66, 0xEE, 0x61, 0xB6, 0x32, 0x4A, 0x2B, 0xBC, 0xC8, 0xF3, 0xF7, 0xB9, 0x29, 0x17, 0x89, 0x48, 0xFB, 0x3C, 0xC4, 0x5D, 0xEE, 0x43, 0xB7, 0xC0, 0xE8, 0xCA, 0x47, 0x16, 0xDD, 0xF8, 0x59, 0x70, 0x32, 0xCF, 0x58, 0x1C, 0xC0, 0xFA, 0x53, 0x39, 0xAF, 0xF4, 0x14, 0xC7, 0x22, 0xAF, 0xA7, 0xD2, 0x87, 0x67, 0x95, 0xD2, 0x5A, 0x35, 0x51, 0x90, 0x14, 0xC9, 0xE7, 0xEF, 0x13, 0x91, 0x3E, 0x88, 0x6C, 0x94, 0x54, 0x68, 0xFF, 0x3F, 0x78, 0xBD, 0xE2, 0x18, 0x3D, 0x05, 0x63, 0x00, 0x3B, 0x2C, 0x56, 0x12, 0xE3, 0xC1, 0x5A, 0xEE, 0x94, 0xFC, 0x2C, 0xE1, 0xAF, 0x8A, 0x83, 0x45, 0x3E, 0xE2, 0x86, 0xDC, 0xA3, 0x65, 0x69, 0x92, 0x43, 0x49, 0x5F, 0x99, 0xCB, 0xA5, 0xF7, 0x22, 0x6C, 0x79, 0x21, 0x72, 0x86, 0x4F, 0x8A, 0x74, 0x9C, 0xA2, 0x77, 0x91, 0x05, 0x1C, 0x05, 0x78, 0xD0, 0xB7, 0x63, 0x6E, 0x60, 0x8C, 0xC5, 0x26, 0x22, 0x16, 0xDC, 0xC7, 0xD9, 0x99, 0xDD, 0x07, 0x5A, 0x95, 0xBD, 0xCD, 0x9F, 0x0F, 0x0A, 0xB3, 0xD7, 0x14, 0x67, 0x81, 0x7D, 0x89, 0x2F, 0x2A, 0x62, 0x40, 0x45, 0x44, 0x3C, 0x47, 0x01, 0xEA, 0x7D, 0x1B, 0xC5, 0x67, 0xC0, 0xAD, 0x8B, 0x04, 0xD0, 0x4F, 0x70, 0x15, 0x7D, 0x3D, 0x96, 0x09, 0x6E, 0xB7, 0x68, 0xFF, 0xCF, 0xFC, 0x1E, 0xB6, 0x7B, 0x86, 0x81, 0x78, 0x55, 0x32, 0x3B, 0xFB, 0x34, 0x21, 0xCC, 0x66, 0x17, 0xE8, 0xF1, 0xEC, 0xA4, 0xC3, 0x65, 0xCE, 0xEA, 0x37, 0x11, 0xA9, 0xEC, 0x06, 0xD5, 0x01, 0xEF, 0x3E, 0xD1, 0x05, 0x54, 0x61, 0x5F, 0x07, 0x7D, 0x80, 0xD9, 0xB4, 0xEF, 0x58, 0x33, 0x44, 0xB7, 0x08, 0x22, 0x5E, 0x83, 0x6D, 0xAC, 0x1F, 0xA9, 0x5F, 0x6A, 0xD6, 0x96, 0x4C, 0xCC, 0x4C, 0x30, 0x6E, 0xCF, 0x7E, 0x9E, 0x67, 0x34, 0xAC, 0x49, 0x2A, 0x28, 0xC1, 0x75, 0x16, 0x61, 0x9B, 0x58, 0x47, 0xC9, 0x73, 0xDE, 0x3B, 0x44, 0x47, 0xB1, 0x97, 0xF6, 0x15, 0xB0, 0x3D, 0xF2, 0x88, 0x16, 0x82, 0x9D, 0x83, 0xB8, 0xE6, 0x4C, 0xD2, 0x0B, 0xAC, 0x64, 0x25, 0x25, 0xF5, 0x37, 0x47, 0x16, 0x0A, 0xD3, 0xEE, 0x35, 0xFE, 0x95, 0xB9, 0x20, 0x47, 0x52, 0x27, 0x89, 0xDB, 0x52, 0x74, 0xD0, 0xF8, 0x3C, 0x74, 0x25, 0xF3, 0xBE, 0xBE, 0xCA, 0x5B, 0x23, 0x7A, 0x4D, 0xEC, 0xB1, 0xF3, 0x80, 0x63, 0xD1, 0x11, 0x6A, 0x08, 0xF6, 0x1B, 0x6A, 0x5A, 0x08, 0x91, 0x1C, 0x30, 0x8C, 0xCD, 0x96, 0x18, 0xD3, 0xCC, 0xCB, 0x36, 0x48, 0x0E, 0x64, 0x6E, 0xC9, 0x5E, 0x2F, 0x9B, 0x90, 0xF7, 0x20, 0x11, 0x97, 0x8F, 0x2D, 0xCE, 0x0D, 0x7F, 0xA5, 0x1C, 0x53, 0x01, 0x78, 0x5E, 0x82, 0x96, 0x73, 0x1E, 0xDA, 0xDF, 0x56, 0x55, 0x89, 0x0F, 0xD3, 0x9E, 0xE0, 0x76, 0xF2, 0x01, 0x0B, 0x0A, 0x11, 0xA3, 0x8C, 0x67, 0x55, 0x0B, 0xEB, 0xB3, 0x97, 0x96, 0x7A, 0x88, 0x26, 0xE5, 0x99, 0xB2, 0x6F, 0x8A, 0xF3, 0x8B, 0x8E, 0x24, 0x96, 0x49, 0x5D, 0xCB, 0xC7, 0x86, 0x79, 0xCB, 0x5F, 0xB1, 0xD6, 0x7B, 0xFA, 0x82, 0xFB, 0xF9, 0xA3, 0x6C, 0x0F, 0xAA, 0x72, 0xA4, 0x21, 0xB4, 0x08, 0x7C, 0x81, 0xE2, 0x80, 0xC5, 0x24, 0x22, 0x1C, 0x08, 0x61, 0x4E, 0xE2, 0xA6, 0x17, 0xCF, 0x2B, 0x62, 0xF1, 0x34, 0xA5, 0xAE, 0x99, 0xCF, 0x04, 0xBC, 0x8A, 0xE6, 0x84, 0x58, 0xD1, 0x23, 0xD6, 0xA5, 0xD0, 0xE9, 0x32, 0x3F, 0x2E, 0xE1, 0x61, 0x00, 0xB6, 0x0A, 0x8F, 0xD9, 0x06, 0xA0, 0xBF, 0x65, 0x6F, 0x68, 0x66, 0xF8, 0x04, 0xE5, 0x4D, 0x8B, 0x69, 0x44, 0x2A, 0xB8, 0xA0, 0x7C, 0x3A, 0x6B, 0x1A, 0x73, 0x6F, 0xC1, 0x0F, 0xF6, 0xAB, 0x2A, 0x46, 0xC6, 0x75, 0x2E, 0xC9, 0x75, 0x88, 0x73, 0x11, 0x68, 0xF9, 0xE9, 0x21, 0x33, 0x24, 0x2C, 0x61, 0x8D, 0xA7, 0x9B, 0x52, 0x26, 0xD9, 0x64, 0xBB, 0x1F, 0x6D, 0x56, 0x60, 0xB4, 0x12, 0x7C, 0x3C, 0xB0, 0xD6, 0xC2, 0x97, 0x40, 0xC0, 0xAE, 0xD2, 0x57, 0xE5, 0x73, 0xF8, 0x83, 0xF9, 0xA6, 0xCA, 0x49, 0xA2, 0x29, 0x69, 0xDF, 0xD9, 0xDB, 0xC5, 0x19, 0x31, 0xE7, 0x78, 0x3C, 0x09, 0x18, 0x7C, 0x4A, 0x74, 0x57, 0x7A, 0xD8, 0x93, 0x54, 0x40, 0xF2, 0xB5, 0x76, 0x39, 0x68, 0xB8, 0xF2, 0x26, 0x6D, 0x23, 0x3E, 0x0F, 0xF4, 0xB4, 0x60, 0x11, 0x9B, 0xC1, 0x63, 0xA5, 0xB4, 0xE2, 0x46, 0x45, 0x7A, 0xEE, 0x8E, 0x32, 0x77, 0x65, 0x6C, 0xCA, 0x1F, 0x66, 0xB0, 0x12, 0x8C, 0x21, 0x39, 0x89, 0xCA, 0x23, 0x21, 0xA1, 0x42, 0x37, 0x80, 0xEE, 0x39, 0x41, 0x8E, 0x00, 0xDD, 0x76, 0x96, 0xE8, 0x24, 0x70, 0x11, 0x6D, 0x13, 0xEE, 0x03, 0x36, 0x59, 0xA8, 0x88, 0x2F, 0xE0, 0xFE, 0xA2, 0x6F, 0x05, 0xBF, 0xD4, 0x5F, 0x72, 0x9D, 0x8B, 0x0B, 0xD4, 0x4E, 0x29, 0xDB, 0xCA, 0x43, 0x55, 0x8D, 0x31, 0x38, 0xEB, 0x0D, 0x7A, 0x27, 0x38, 0x91, 0x8F, 0x21, 0x3F, 0xDD, 0x82, 0x65, 0xF5, 0xF0, 0x4B, 0x9B, 0x77, 0xC8, 0x1D, 0x68, 0x05, 0x2D, 0x16, 0x2F, 0x05, 0x1F, 0x58, 0xE4, 0x92, 0x91, 0x60, 0x43, 0xC1, 0x8F, 0x3C, 0x4F, 0xFD, 0x9E, 0x6C, 0xA0, 0xA0, 0x57, 0x77, 0x31, 0xF9, 0x4A, 0xA9, 0xBF, 0xB6, 0x70, 0xB1, 0x91, 0x69, 0x24, 0x8B, 0x03, 0x0D, 0xBC, 0x4D, 0x78, 0xBE, 0xDB, 0x17, 0x19, 0x45, 0xF5, 0xC7, 0x66, 0x39, 0x72, 0x14, 0x7E, 0x42, 0x5D, 0x83, 0x6B, 0xA1, 0x39, 0xE6, 0xEB, 0x48, 0x02, 0x4C, 0xCD, 0xFB, 0x91, 0x75, 0xB6, 0x4E, 0x99, 0x55, 0x92, 0xB7, 0xAA, 0x16, 0x4E, 0xB2, 0x2E, 0x5E, 0x6F, 0xFC, 0x15, 0x19, 0x58, 0x19, 0xA6, 0xFF, 0x5F, 0x00, 0xC1, 0x3D, 0xAC, 0xB9, 0xE0, 0x91, 0x2F, 0x3D, 0x84, 0xFB, 0xD9, 0x78, 0x20, 0x23, 0xC8, 0x16, 0xCA, 0x09, 0xBC, 0x1B, 0x72, 0x58, 0x78, 0x88, 0xDC, 0x08, 0x2E, 0x28, 0x1C, 0x84, 0x2E, 0xA7, 0xBA, 0xE5, 0xA4, 0x43, 0xCC, 0x4C, 0x46, 0xD2, 0x07, 0x48, 0x98, 0x87, 0x2E, 0xFE, 0x0B, 0x5A, 0x51, 0x1C, 0x18, 0xD8, 0x82, 0xD8, 0x55, 0x64, 0xBA, 0x77, 0xAB, 0x98, 0x9C, 0xB7, 0x36, 0x33, 0xB0, 0x7E, 0x71, 0x03, 0xE5, 0x09, 0x31, 0x47, 0xBE, 0x6A, 0xE1, 0x6D, 0x62, 0xB9, 0x52, 0x95, 0xBF, 0x4C, 0xB9, 0x3E, 0x3B, 0x20, 0xAB, 0x41, 0x79, 0x24, 0x6F, 0x52, 0x52, 0x04, 0x10, 0x50, 0x94, 0x1D, 0xB5, 0x04, 0xF4, 0x2A, 0x1B, 0x0E, 0xB8, 0x0F, 0xBD, 0x65, 0xF9, 0xB8, 0x59, 0xA3, 0xF9, 0xBC, 0x3A, 0x6B, 0x14, 0x0B, 0x96, 0xFC, 0xA6, 0x7C, 0xC6, 0x5F, 0x28, 0xF6, 0x9B, 0x7B, 0x12, 0xDD, 0x40, 0x61, 0x2E, 0x57, 0xBA, 0xA2, 0x88, 0x92, 0x29, 0x94, 0x7D, 0x2B, 0x71, 0x4C, 0x9C, 0x2D, 0x3F, 0x51, 0x3E, 0x1C, 0x29, 0x50, 0x5A, 0xB2, 0xC6, 0x05, 0xD0, 0x41, 0x67, 0xCE, 0x12, 0xD7, 0x03, 0x48, 0x88, 0x70, 0xAC, 0x35, 0xAA, 0x3E, 0x23, 0xEB, 0xA7, 0x06, 0xE2, 0xC7, 0x95, 0x17, 0xCC, 0x3B, 0x89, 0x5E, 0xD0, 0x29, 0xA7, 0x49, 0x78, 0xA6, 0x72, 0x5C, 0xFA, 0x39, 0xB1, 0x9A, 0xD9, 0x9D, 0xD8, 0x22, 0xCD, 0xAB, 0xB2, 0x8E, 0xD0, 0xC8, 0xED, 0xB9, 0x47, 0xFC, 0x7D, 0x95, 0xAB, 0x04, 0x79, 0xAE, 0xDF, 0xE0, 0x64, 0xF1, 0x5B, 0xEB, 0xEB, 0x6A, 0x50, 0xE1, 0x4C, 0x5D, 0x8A, 0x1F, 0x04, 0xFA, 0x2D, 0xC6, 0x10, 0xDB, 0xC0, 0x91, 0xEC, 0x54, 0x1E, 0xCA, 0x55, 0xA5, 0xBC, 0x12, 0x4C, 0xE7, 0x97, 0xC4, 0xB9, 0x8B, 0x86, 0x84, 0xF3, 0xC3, 0xC7, 0x4B, 0x93, 0x44, 0x97, 0xFC, 0x43, 0x15, 0x1C, 0x09, 0xDB, 0x2D, 0x1A, 0xEA, 0x97, 0x7D, 0xB5, 0x7E, 0xA5, 0x4E, 0x50, 0xA2, 0xD4, 0x87, 0xF8, 0x79, 0x90, 0x6A, 0x51, 0x42, 0xDC, 0x07, 0x2F, 0x66, 0xFE, 0xAC, 0xA2, 0x4B, 0xBD, 0x93, 0xDB, 0xB9, 0x16, 0xB2, 0xFC, 0x98, 0x50, 0x01, 0x53, 0x3E, 0x2E, 0xCC, 0x20, 0x96, 0xC9, 0x9F, 0xF9, 0x93, 0xB2, 0x03, 0x8A, 0xE5, 0x2E, 0x37, 0xC1, 0xA3, 0xCA, 0x1A, 0x6B, 0xAE, 0x7A, 0x11, 0xD0, 0x43, 0xFD, 0x88, 0xBF, 0x04, 0x85, 0x16, 0x23, 0xE4, 0x3C, 0xF0, 0x44, 0xA6, 0x1D, 0x73, 0x39, 0xB2, 0x38, 0xF9, 0x33, 0xBB, 0x11, 0xFE, 0xB1, 0x98, 0xCF, 0xC5, 0xE1, 0x9D, 0x21, 0x37, 0x04, 0xA7, 0x60, 0xD0, 0xAF, 0x4D, 0x1A, 0x08, 0xBB, 0x39, 0x9D, 0x02, 0xCB, 0xA0, 0x11, 0xAB, 0x83, 0xAA, 0xCB, 0xE0, 0x27, 0xEA, 0x0D, 0xFC, 0x27, 0xB8, 0xDE, 0xE2, 0x00, 0x99, 0x01, 0xB6, 0xA6, 0x75, 0x94, 0xBF, 0x24, 0xBB, 0x93, 0x48, 0xA6, 0x82, 0xB8, 0x1D, 0xFD, 0xA1, 0xEA, 0x3B, 0x7E, 0x39, 0x64, 0x01, 0xFF, 0x1E, 0xC6, 0xF1, 0x4E, 0x97, 0x08, 0xD5, 0x0C, 0xE7, 0x45, 0x80, 0x1D, 0x1A, 0x6F, 0x3D, 0x43, 0x05, 0xC1, 0x63, 0xA9, 0x6B, 0x89, 0x89, 0xE0, 0x39, 0x8B, 0x72, 0xD2, 0x08, 0xA6, 0xA5, 0x58, 0x94, 0x8E, 0x37, 0x06, 0x26, 0x1E, 0xAF, 0xD8, 0x5F, 0x2D, 0x5C, 0x7C, 0xBB, 0x2A, 0x53, 0x2F, 0x0D, 0xB1, 0xE2, 0xC7, 0x6B, 0x8E, 0x78, 0x87, 0x88, 0xE5, 0x84, 0xC4, 0x4D, 0xA1, 0x94, 0xA8, 0x99, 0x36, 0x7D, 0xAA, 0x64, 0xF8, 0x20, 0x55, 0x4C, 0xFC, 0x0D, 0xDE, 0x30, 0x5F, 0xF9, 0x5F, 0xCA, 0x33, 0x93, 0x56, 0x6A, 0xE7, 0xA7, 0x9C, 0x4B, 0xA0, 0x93, 0xB7, 0x32, 0xA8, 0x51, 0xFF, 0x10, 0x6B, 0x72, 0xDE, 0x84, 0xB4, 0x12, 0x83, 0x45, 0xBE, 0xDE, 0xDB, 0x89, 0xE1, 0xF2, 0xC1, 0x45, 0x76, 0xC4, 0x29, 0x8E, 0x3B, 0x3D, 0x9C, 0x38, 0x20, 0x2E, 0x34, 0xDF, 0x42, 0x5C, 0x91, 0x5F, 0x37, 0x3B, 0x4E, 0x3C, 0x50, 0xFE, 0x2F, 0x29, 0x0F, 0xFF, 0x27, 0x2B, 0x3A, 0xCE, 0x0A, 0x8F, 0xCE, 0x1D, 0x1B, 0xF1, 0x0A, 0xBB, 0x5F, 0xB8, 0x28, 0x08, 0xC5, 0xEE, 0x96, 0xB6, 0x7A, 0xD3, 0xF1, 0xC5, 0xCC, 0x02, 0xC7, 0x41, 0x7C, 0x13, 0xF7, 0x91, 0xE5, 0x10, 0x11, 0x21, 0x39, 0x6A, 0xD1, 0x46, 0x0C, 0x28, 0x2E, 0x2E, 0xC4, 0x89, 0x93, 0x40, 0x7D, 0xC2, 0x4A, 0x55, 0x59, 0x41, 0x65, 0xAC, 0xB3, 0xCA, 0xBD, 0xE8, 0x77, 0xF8, 0xBF, 0x2A, 0x7D, 0x59, 0x46, 0xC0, 0x51, 0xD5, 0xBB, 0xCA, 0x2B, 0x5E, 0x0C, 0xF5, 0xCE, 0x2A, 0xCC, 0xF1, 0x06, 0xB6, 0x4B, 0xE0, 0xCD, 0x80, 0xF0, 0x33, 0xB2, 0x04, 0x8A, 0x82, 0x90, 0x28, 0xCF, 0x99, 0x97, 0x12, 0xDB, 0xC1, 0xE4, 0xF8, 0x1E, 0x38, 0xB2, 0x8C, 0x1F, 0x03, 0xC2, 0x6B, 0x2A, 0xA6, 0x47, 0x44, 0x22, 0xDD, 0xCC, 0x1B, 0x01, 0x72, 0xD4, 0xB7, 0xEA, 0xAB, 0xC7, 0x38, 0xD5, 0x22, 0xFE, 0x7C, 0xC7, 0x2C, 0xF5, 0x47, 0xF1, 0x3C, 0xC6, 0x63, 0x1C, 0x92, 0x9F, 0xA2, 0xBA, 0x12, 0xB9, 0x40, 0x9B, 0x85, 0x1F, 0xB1, 0x03, 0x3C, 0x1A, 0x97, 0x07, 0xC4, 0x56, 0x85, 0x47, 0x57, 0x81, 0xD6, 0x1C, 0x8B, 0xD0, 0x6C, 0x28, 0x83, 0x37, 0xC7, 0xFF, 0x2E, 0xCC, 0x12, 0xB4, 0xBB, 0x1F, 0x43, 0xC7, 0x88, 0x6E, 0x38, 0x16, 0xAA, 0xC3, 0xA4, 0xCF, 0x19, 0x5F, 0x70, 0x3F, 0xE5, 0x4C, 0xEA, 0x4A, 0x22, 0x1B, 0x9C, 0x65, 0xF1, 0x88, 0x38, 0x0F, 0xBE, 0x8D, 0xD7, 0xC9, 0x6D, 0x45, 0x5E, 0x51, 0x21, 0x8A, 0xF1, 0xA2, 0x67, 0xC1, 0x7C, 0x20, 0x52, 0xBC, 0xCD, 0xF7, 0x3A, 0x34, 0x59, 0xEA, 0xED, 0xB6, 0x1F, 0xE6, 0xC8, 0x36, 0x3A, 0x9C, 0x54, 0x8D, 0x52, 0x24, 0x32, 0x86, 0xB0, 0x37, 0x00, 0x95, 0xFA, 0x89, 0x28, 0x05, 0x0B, 0x29, 0x62, 0xE2, 0x3B, 0xF8, 0x24, 0xEE, 0x84, 0xC4, 0x5B, 0xB9, 0x35, 0xEA, 0x93, 0x74, 0x3F, 0x60, 0x16, 0xB4, 0x53, 0xFE, 0x18, 0xE0, 0x79, 0x7F, 0x55, 0x9E, 0x06, 0xAA, 0x5C, 0x4B, 0xC1, 0xF7, 0xC0, 0x3E, 0xFB, 0xD5, 0x68, 0x20, 0x38, 0x89, 0xA1, 0xC7, 0x6A, 0xC0, 0x38, 0x9A, 0x0F, 0x51, 0x01, 0x36, 0x52, 0xCE, 0x93, 0x4E, 0xE0, 0xA6, 0xC5, 0xCB, 0x45, 0xF3, 0x55, 0xC3, 0x91, 0x7B, 0x25, 0x01, 0xAA, 0xA0, 0xA0, 0x05, 0x32, 0x35, 0xDA, 0xE4, 0xFD, 0xAF, 0xE2, 0x24, 0x72, 0xDC, 0xE5, 0x2D, 0x58, 0x81, 0x30, 0x1C, 0xC2, 0x11, 0x04, 0x8E, 0xB1, 0x0A, 0xC6, 0x7C, 0xA1, 0x00, 0x9A, 0x9E, 0xE0, 0x80, 0x6B, 0x28, 0x4F, 0xC8, 0x7C, 0x50, 0x12, 0x9D, 0x2E, 0x18, 0xD0, 0xFA, 0x86, 0xFD, 0x23, 0x92, 0x91, 0x0F, 0x03, 0xD7, 0x48, 0xAB, 0x08, 0x0F, 0x1F, 0x99, 0x42, 0x8F, 0x35, 0xBA, 0x3E, 0x04, 0x9E, 0xA8, 0x43, 0x16, 0x1D, 0x82, 0x3F, 0xA0, 0x14, 0xEB, 0x4E, 0x6C, 0x0A, 0xF4, 0x89, 0x76, 0x87, 0x00, 0xC0, 0x1D, 0x94, 0xA3, 0x24, 0x01, 0xBA, 0x87, 0x1B, 0x1B, 0x28, 0x29, 0xEC, 0xA0, 0xD5, 0xF5, 0xBF, 0xD2, 0x21, 0x1F, 0xAC, 0x6E, 0x62, 0xF6, 0x7D, 0x8F, 0xD2, 0x9A, 0xD7, 0x85, 0x2E, 0x4E, 0x60, 0xB5, 0xAA, 0xEC, 0xB9, 0xD5, 0x4D, 0x7D, 0x56, 0xD5, 0x39, 0x4A, 0x89, 0x76, 0x92, 0xB8, 0x62, 0x61, 0x26, 0x79, 0x54, 0x31, 0xD1, 0x6C, 0x2E, 0x19, 0x04, 0x4C, 0x0E, 0xD5, 0xD4, 0x9E, 0xCF, 0x10, 0x05, 0x5C, 0xAC, 0x4D, 0xCB, 0xF6, 0xF4, 0x79, 0x53, 0x73, 0x22, 0x7F, 0x8E, 0xC7, 0x21, 0xE3, 0xFC, 0xE2, 0x3D, 0x4E, 0x5F, 0x0D, 0x44, 0xE5, 0x04, 0x1B, 0x85, 0x6E, 0x0D, 0x77, 0x3E, 0xB5, 0x4D, 0xD3, 0x2A, 0x31, 0x9A, 0xF3, 0x49, 0x89, 0xE2, 0xE5, 0x42, 0x7B, 0xE2, 0x0B, 0x70, 0x2A, 0x78, 0x75, 0xCD, 0xC9, 0xDC, 0xE3, 0xFE, 0xA5, 0x35, 0xF1, 0x05, 0xC9, 0xBE, 0xE1, 0xD5, 0x8F, 0x8A, 0xB7, 0xBB, 0xBF, 0x32, 0xD4, 0x97, 0xEF, 0x77, 0xE4, 0xEA, 0xFB, 0x59, 0xF7, 0x6D, 0xA6, 0xEB, 0x16, 0xF2, 0x47, 0xD1, 0x0C, 0x9A, 0x85, 0xD2, 0xDB, 0x16, 0x9B, 0x49, 0x73, 0xE5, 0x15, 0xF3, 0x6A, 0x62, 0x33, 0xA8, 0x0B, 0x72, 0xAF, 0xD6, 0x14, 0xCF, 0xF2, 0xFF, 0xA1, 0xFF, 0x55, 0x1A, 0xEA, 0x33, 0x53, 0x9F, 0x51, 0xF1, 0xCC, 0xAD, 0x5A, 0x77, 0x81, 0xF5, 0xC7, 0x21, 0x5C, 0xB7, 0x80, 0xBB, 0xD0, 0x5A, 0xAC, 0xB5, 0x12, 0x02, 0xF4, 0x7C, 0xB2, 0x5D, 0x1E, 0x42, 0xF9, 0x49, 0x5C, 0x05, 0x5A, 0x2D, 0xBE, 0x12, 0x26, 0xF0, 0x57, 0x90, 0xBD, 0x2E, 0xA0, 0x72, 0x91, 0xEF, 0x2D, 0xED, 0x57, 0xA6, 0xC8, 0x63, 0xAC, 0x36, 0xB0, 0x2A, 0xD4, 0x65, 0xBD, 0x66, 0x80, 0xBB, 0xDA, 0xFE, 0x99, 0x46, 0x24, 0xC8, 0xB0, 0x7E, 0x47, 0x5E, 0x90, 0x4C, 0xB0, 0x74, 0x23, 0xC7, 0x2B, 0xD4, 0xB4, 0xF9, 0xC4, 0x1A, 0x70, 0x36, 0xD5, 0x83, 0xA8, 0x86, 0x9C, 0x82, 0x42, 0xC8, 0x7F, 0x79, 0xE3, 0x7C, 0x7B, 0x49, 0x31, 0x3F, 0xCC, 0xB3, 0x8A, 0xF8, 0x21, 0x80, 0x5C, 0x53, 0x88, 0x56, 0xD1, 0x34, 0x87, 0x39, 0x84, 0x51, 0xFC, 0xCC, 0x66, 0x02, 0x51, 0x25, 0x93, 0x5A, 0x1E, 0x21, 0xD4, 0xCA, 0x46, 0xDA, 0x07, 0xA2, 0x1D, 0x2C, 0xA1, 0x39, 0x13, 0x03, 0x90, 0x75, 0xA0, 0x01, 0x3B, 0x2B, 0x59, 0xE5, 0xFB, 0x10, 0x2B, 0x96, 0xCD, 0xF3, 0x1C, 0xC4, 0x58, 0xB2, 0xEB, 0x2E, 0x0D, 0xD8, 0x27, 0xD9, 0x1B, 0xFB, 0x3A, 0xDC, 0x5A, 0xBE, 0xCC, 0xFA, 0x7F, 0x38, 0x47, 0x71, 0x9F, 0x31, 0x8B, 0xA0, 0x01, 0x26, 0x7A, 0x3B, 0xD1, 0x0D, 0x56, 0xD3, 0xDE, 0x13, 0x67, 0xC1, 0x0F, 0xBE, 0x6B, 0xD5, 0xAF, 0x01, 0x8D, 0xCF, 0x24, 0xF5, 0x1A, 0x30, 0xCA, 0x23, 0x4A, 0xDD, 0x0D, 0x06, 0x3B, 0x97, 0x61, 0x74, 0x60, 0xB7, 0xDD, 0x25, 0xEC, 0x3D, 0xB0, 0xC2, 0x7A, 0x35, 0x1E, 0x02, 0xDC, 0x67, 0xAC, 0x23, 0x66, 0x82, 0x65, 0x96, 0xD6, 0xFF, 0xB5, 0xBD, 0x97, 0xCE, 0x27, 0x47, 0x83, 0x5B, 0xFD, 0x7C, 0x54, 0x04, 0xFA, 0xC0, 0xDB, 0x0F, 0x79, 0x8B, 0xEE, 0x76, 0xE7, 0xA2, 0x7F, 0x23, 0x6F, 0x9C, 0xA7, 0xA9, 0xEA, 0xE1, 0xEF, 0x0E, 0xAB, 0xB1, 0x5B, 0x30, 0x66, 0xFD, 0x12, 0x3F, 0x02, 0xE9, 0xAC, 0x9D, 0x09, 0x3F, 0x28, 0xC8, 0xF2, 0x3C, 0x71, 0x07, 0xDC, 0x42, 0xDF, 0x44, 0xBA, 0x82, 0x4A, 0xEF, 0x87, 0xDD, 0x9E, 0x49, 0x11, 0x1E, 0xEA, 0x8E, 0x6D, 0xA9, 0xEB, 0x5D, 0x16, 0xB7, 0x4D, 0xCE, 0xEA, 0x70, 0xEC, 0x6E, 0x7A, 0x94, 0xBF, 0xC5, 0xEE, 0x5B, 0xBD, 0x63, 0xE9, 0x4E, 0xCB, 0x44, 0xE3, 0xB5, 0xAA, 0x7B, 0xE6, 0xFF, 0xD3, 0x4B, 0x44, 0x9F, 0xCC, 0x5E, 0x69, 0x1E, 0x2A, 0xC6, 0x9B, 0x4D, 0x20, 0xF7, 0x03, 0x81, 0xDE, 0x33, 0x3B, 0x90, 0x34, 0x0F, 0xF7, 0x25, 0x6D, 0xAA, 0x8C, 0x0B, 0xCE, 0x8B, 0x5B, 0x72, 0x72, 0x7E, 0x39, 0x70, 0x1A, 0x8F, 0x14, 0xBE, 0xB2, 0xBE, 0x55, 0x37, 0x58, 0x3E, 0x48, 0xDB, 0x57, 0x33, 0x83, 0x93, 0x6D, 0xFE, 0x42, 0x77, 0x53, 0x12, 0xB0, 0x70, 0x50, 0x93, 0xAC, 0xF8, 0xBA, 0x70, 0x11, 0xE9, 0x0D, 0x8E, 0xF2, 0x0A, 0x68, 0x3D, 0x9B, 0xED, 0xEF, 0x76, 0xAB, 0x79, 0x47, 0xAE, 0x8D, 0xD3, 0x8E, 0xC6, 0xEF, 0x05, 0xEF, 0xEC, 0x89, 0xFA, 0x37, 0xA5, 0xC5, 0x0C, 0x53, 0xED, 0x6A, 0xA6, 0x15, 0x75, 0xA6, 0x71, 0x25, 0xF7, 0x8C, 0x45, 0xA5, 0x6E, 0xB1, 0x54, 0x6E, 0xFE, 0x9B, 0xDC, 0xAF, 0xBC, 0x6F, 0x7E, 0x9B, 0x58, 0x07, 0x1E, 0x74, 0x5B, 0xDB, 0x52, 0x58, 0xB0, 0xC8, 0x65, 0x67, 0xE3, 0x9D, 0xA2, 0x41, 0xA7, 0xB4, 0x7A, 0xA0, 0xCC, 0xD3, 0xFE, 0x52, 0xAD, 0x77, 0xE5, 0x15, 0xCB, 0xE1, 0x9A, 0x5D, 0x55, 0xB9, 0x94, 0x93, 0xD5, 0x65, 0x82, 0xF1, 0x94, 0xC3, 0x5A, 0x9D, 0x6C, 0x3B, 0xE5, 0x3E, 0xB9, 0x18, 0xE8, 0xA1, 0x3C, 0x24, 0x32, 0xA1, 0x50, 0xB7, 0xE9, 0x8D, 0x75, 0xA5, 0x6E, 0x2E, 0x44, 0xFD, 0x95, 0x0A, 0x33, 0xC7, 0x27, 0xB5, 0x06, 0x16, 0xCD, 0xCE, 0xB6, 0x46, 0x5A, 0xB5, 0xDA, 0x32, 0xA5, 0xBA, 0x91, 0xB7, 0x84, 0xD6, 0xAA, 0x5F, 0x2A, 0xC2, 0xE9, 0x63, 0x34, 0x43, 0xF2, 0xCF, 0xB4, 0x17, 0xC4, 0x73, 0x90, 0x4A, 0x3B, 0x43, 0xB8, 0x40, 0x32, 0xD7, 0xD9, 0xF5, 0xA3, 0x99, 0x8F, 0x9D, 0x0F, 0xD6, 0xB6, 0x57, 0x45, 0x38, 0x96, 0x98, 0x06, 0xB9, 0xD1, 0x76, 0xD3, 0x8C, 0x32, 0x7E, 0x0D, 0xC3, 0xC2, 0x30, 0x55, 0x78, 0xCF, 0xB2, 0x4F, 0x67, 0x2E, 0x79, 0xCE, 0xB0, 0x25, 0x6F, 0x28, 0xE7, 0x58, 0x2E, 0x23, 0xD6, 0x83, 0x62, 0xCB, 0x22, 0xC2, 0x03, 0x12, 0xB9, 0x38, 0x98, 0xDC, 0xF8, 0x57, 0x9D, 0x77, 0x56, 0x1F, 0x10, 0x2E, 0x71, 0x8C, 0xAA, 0xCE, 0x16, 0xDD, 0xB3, 0x9F, 0x6F, 0xE0, 0x4A, 0x6A, 0x19, 0xAF, 0x74, 0xDF, 0xA4, 0xD1, 0x96, 0xAE, 0x5A, 0x7F, 0xD9, 0x67, 0x86, 0x88, 0xD4, 0x28, 0x1F, 0x30, 0x7A, 0x89, 0x2D, 0x60, 0x03, 0xA3, 0x9F, 0x28, 0x81, 0xA2, 0x5C, 0xC4, 0xD5, 0xD1, 0xB2, 0x69, 0x4E, 0xFB, 0x0C, 0x15, 0xB2, 0xC1, 0x45, 0x27, 0xF4, 0x5D, 0xF2, 0x0A, 0xBB, 0x5F, 0xBA, 0x1B, 0xF2, 0x47, 0x56, 0xB3, 0x74, 0x0B, 0xE4, 0xBF, 0x69, 0x6A, 0xED, 0x4C, 0x45, 0xFB, 0x7F, 0xBB, 0xF6, 0x02, 0x3A, 0xAB, 0x59, 0xC4, 0x77, 0xB0, 0xDD, 0x2A, 0x9B, 0x58, 0x09, 0x8D, 0x77, 0x29, 0xD2, 0xBF, 0x00, 0xAC, 0x9C, 0x87, 0x75, 0x7B, 0x40, 0x2B, 0x47, 0x40, 0x47, 0x05, 0x5B, 0x17, 0x5D, 0xD3, 0x9C, 0x02, 0x99, 0x76, 0xDE, 0xDA, 0x29, 0xC0, 0x25, 0xC6, 0x90, 0x36, 0x09, 0x30, 0x59, 0x35, 0x69, 0x5C, 0xC1, 0x42, 0xAB, 0x56, 0x32, 0x1B, 0x5C, 0x6E, 0xD5, 0x46, 0x7C, 0x01, 0xFF, 0x4F, 0x98, 0x3F, 0x00, 0x67, 0xD6, 0x86, 0x6D, 0xB0, 0x68, 0x6C, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0x76, 0x32, 0xB1, 0x35, 0xB1, 0x3D, 0xB1, 0x35, 0xC9, 0xC4, 0xE7, 0xFD, 0xBF, 0x3A, 0xDB, 0x7A, 0x56, 0x69, 0x95, 0xDD, 0x7D, 0xF7, 0x35, 0x0C, 0x04, 0x04, 0xC4, 0x03, 0xE4, 0x06, 0xD4, 0x00, 0x74, 0x0E, 0x4C, 0x02, 0xAC, 0x07, 0x9C, 0x01, 0xBC, 0x00, 0x02, 0x0B, 0x22, 0x0E, 0x12, 0x08, 0xD2, 0x0D, 0xF2, 0x0C, 0xCA, 0x00, 0x6A, 0x05, 0x5A, 0x0A, 0xBA, 0x0B, 0x86, 0x05, 0xA6, 0x02, 0x16, 0x0F, 0x36, 0x09, 0x0E, 0x02, 0xCE, 0x0F, 0xEE, 0x05, 0xDE, 0x02, 0x7E, 0x03, 0x41, 0x05, 0x61, 0x0A, 0x51, 0x00, 0xB1, 0x09, 0x89, 0x06, 0xA9, 0x08, 0x19, 0x03, 0x39, 0x06, 0x05, 0x04, 0xC5, 0x0B, 0xE5, 0x01, 0xD5, 0x0C, 0x75, 0x03, 0x4D, 0x05, 0x6D, 0x0A, 0x5D, 0x08, 0xBD, 0x05, 0x83, 0x0E, 0xA3, 0x0C, 0x13, 0x07, 0x33, 0x09, 0x0B, 0x0A, 0x2B, 0x08, 0xEB, 0x0B, 0xDB, 0x01, 0xFB, 0x08, 0xC7, 0x00, 0x67, 0x03, 0x57, 0x0E, 0x77, 0x08, 0x8F, 0x0F, 0xAF, 0x0D, 0x9F, 0x0E, 0xBF, 0x88, 0x00, 0x8F, 0x20, 0x8D, 0x10, 0x8E, 0x30, 0x84, 0xF0, 0x8D, 0xC8, 0x83, 0xE8, 0x81, 0xD8, 0x82, 0x78, 0x87, 0x44, 0x8B, 0x64, 0x89, 0x54, 0x86, 0x74, 0x80, 0x8C, 0x8F, 0xAC, 0x8D, 0x9C, 0x81, 0xBC, 0x84, 0x82, 0x88, 0x22, 0x87, 0x12, 0x85, 0x32, 0x86, 0x0A, 0x82, 0x2A, 0x88, 0xEA, 0x87, 0xDA, 0x8D, 0xFA, 0x82, 0xC6, 0x82, 0xE6, 0x88, 0x56, 0x87, 0x76, 0x89, 0x4E, 0x89, 0x6E, 0x86, 0x5E, 0x8C, 0xBE, 0x87, 0x81, 0x8B, 0xA1, 0x8D, 0x91, 0x81, 0xB1, 0x8C, 0x89, 0x8C, 0xA9, 0x80, 0x19, 0x87, 0x39, 0x85, 0x05, 0x89, 0x25, 0x86, 0x15, 0x82, 0x35, 0x80, 0xF5, 0x85, 0xCD, 0x8B, 0xED, 0x85, 0xDD, 0x81, 0xFD, 0x8C, 0xC3, 0x82, 0xE3, 0x84, 0xD3, 0x80, 0x73, 0x8D, 0x4B, 0x83, 0x6B, 0x85, 0x5B, 0x81, 0x7B, 0x8C, 0x47, 0x82, 0x67, 0x84, 0x57, 0x80, 0xB7, 0x8B, 0x8F, 0x8B, 0xAF, 0x8D, 0x9F, 0x85, 0xBF, 0x46, 0x80, 0x46, 0xA0, 0x4A, 0x90, 0x4C, 0xB0, 0x40, 0x88, 0x48, 0x28, 0x4F, 0x18, 0x47, 0x38, 0x43, 0x04, 0x43, 0x24, 0x45, 0x14, 0x49, 0x34, 0x4E, 0x0C, 0x4E, 0x2C, 0x46, 0x1C, 0x4A, 0x3C, 0x4C, 0x02, 0x4C, 0x22, 0x44, 0x12, 0x44, 0x32, 0x40, 0xF2, 0x4D, 0xCA, 0x4F, 0xEA, 0x4F, 0xDA, 0x47, 0xFA, 0x49, 0xC6, 0x4B, 0xE6, 0x4B, 0xD6, 0x43, 0xF6, 0x4E, 0xCE, 0x43, 0xEE, 0x4D, 0xDE, 0x4D, 0xFE, 0x46, 0xC1, 0x4D, 0xE1, 0x4D, 0xD1, 0x4D, 0xF1, 0x46, 0xC9, 0x4D, 0xE9, 0x4D, 0xD9, 0x4D, 0xF9, 0x46, 0xC5, 0x43, 0xE5, 0x43, 0xD5, 0x43, 0xF5, 0x41, 0xCD, 0x4B, 0xED, 0x47, 0xDD, 0x47, 0xFD, 0x45, 0xC3, 0x4F, 0x13, 0x40, 0x33, 0x40, 0x0B, 0x44, 0x2B, 0x4C, 0x1B, 0x4C, 0x3B, 0x4C, 0x07, 0x4A, 0x27, 0x46, 0x17, 0x4E, 0x37, 0x4E, 0x0F, 0x45, 0x2F, 0x4D, 0x1F, 0x43, 0x3F, 0xC3, 0x00, 0xC7, 0xA0, 0xC0, 0x90, 0xC8, 0xB0, 0xC8, 0x88, 0xC2, 0xA8, 0xCA, 0x98, 0xCE, 0xB8, 0xCE, 0x84, 0xC5, 0xA4, 0xC3, 0x94, 0xC7, 0xB4, 0xCB, 0x4C, 0xC8, 0x6C, 0xCC, 0x5C, 0xCA, 0x7C, 0xC2, 0x42, 0xC9, 0x62, 0xC5, 0x52, 0xC3, 0x72, 0xC3, 0xCA, 0xC8, 0xEA, 0xCC, 0xDA, 0xCA, 0xFA, 0x97, 0x8D, 0x8B, 0xCD, 0x87, 0xAD, 0x8F, 0xED, 0x87, 0x5D, 0x84, 0x3D, 0x8C, 0x7D, 0x82, 0x03, 0x86, 0x43, 0x8E, 0x23, 0x91, 0x63, 0x89, 0x13, 0x9D, 0x53, 0x8B, 0x33, 0x97, 0x73, 0x9F, 0x8B, 0x84, 0xCB, 0x9C, 0xAB, 0x8A, 0xEB, 0x9A, 0x9B, 0x91, 0xDB, 0x95, 0xBB, 0x83, 0xFB, 0x9D, 0x47, 0x80, 0x27, 0x98, 0x67, 0x8C, 0x17, 0x9A, 0x57, 0x9E, 0x37, 0x99, 0x77, 0x95, 0x0F, 0x9B, 0x4F, 0x9F, 0xAF, 0x98, 0xEF, 0x94, 0x9F, 0x86, 0xDF, 0x81, 0xBF, 0x95, 0xFF, 0x55, 0x80, 0x4F, 0x20, 0x48, 0x60, 0x4C, 0x10, 0x46, 0x50, 0x51, 0x30, 0x55, 0x70, 0x43, 0x08, 0x5F, 0xC8, 0x44, 0xA8, 0x52, 0xE8, 0x4A, 0x98, 0x49, 0xD8, 0x4D, 0xB8, 0x5B, 0xF8, 0x4B, 0x44, 0x44, 0x24, 0x42, 0x64, 0x46, 0x14, 0x51, 0x54, 0x55, 0x34, 0x53, 0x74, 0x5B, 0x8C, 0x50, 0xCC, 0x54, 0xAC, 0x52, 0xEC, 0x4A, 0x9C, 0x51, 0xDC, 0x55, 0xBC, 0x53, 0xFC, 0x43, 0x42, 0x40, 0x22, 0x44, 0x62, 0x5C, 0x12, 0x5A, 0x52, 0x5E, 0x32, 0x49, 0x72, 0x59, 0x0A, 0x53, 0x4A, 0x47, 0x2A, 0x5F, 0xEA, 0x50, 0x9A, 0x4C, 0xDA, 0x52, 0xBA, 0x46, 0xFA, 0x46, 0x86, 0x49, 0xC6, 0x55, 0xA6, 0x5D, 0xE6, 0x9F, 0x2C, 0xAF, 0x6C, 0x80, 0xEC, 0xA0, 0x1C, 0xA8, 0x9C, 0xB8, 0x5C, 0x94, 0xDC, 0xB4, 0x3C, 0xBC, 0xBC, 0xA2, 0x7C, 0xB2, 0xFC, 0xB2, 0x02, 0x86, 0x82, 0x96, 0x42, 0x8E, 0xC2, 0x8E, 0x22, 0x81, 0xA2, 0x91, 0x62, 0x89, 0xE2, 0x1F, 0x25, 0x72, 0x25, 0x4B, 0xA5, 0x2A, 0xA5, 0x4B, 0x65, 0x3A, 0x65, 0x7B, 0xE5, 0x46, 0xE5, 0x7B, 0x15, 0x66, 0x15, 0x57, 0x95, 0x36, 0x95, 0xBF, 0xAA, 0x1C, 0xAA, 0x9E, 0xAA, 0x5D, 0xAA, 0x6F, 0x6A, 0x3C, 0x6A, 0xBE, 0x6A, 0x7D, 0x6A, 0x5F, 0xEA, 0x02, 0xEA, 0x01, 0xEA, 0x03, 0x1A, 0x40, 0x1A, 0x42, 0x1A, 0xC1, 0x1A, 0xC3, 0x9A, 0x20, 0x9A, 0xA2, 0x9A, 0xA1, 0x9A, 0x23, 0x5A, 0x60, 0x5A, 0x62, 0x5A, 0xE1, 0x5A, 0x63, 0xDA, 0xE0, 0xDA, 0x12, 0xDA, 0x11, 0xDA, 0xE3, 0x3A, 0x10, 0x3A, 0x12, 0x3A, 0x11, 0x3A, 0x13, 0xBA, 0x90, 0xBA, 0x92, 0xBA, 0x91, 0xBA, 0x13, 0x7A, 0x90, 0x7A, 0x92, 0x7A, 0x91, 0x7A, 0xE3, 0xFA, 0x10, 0xFA, 0x12, 0xFA, 0x11, 0xFA, 0xE3, 0x06, 0x10, 0x06, 0xE2, 0x06, 0xE1, 0x06, 0x63, 0x86, 0x60, 0x86, 0x62, 0x86, 0xA1, 0x86, 0x23, 0x46, 0xA0, 0x46, 0x22, 0x46, 0x21, 0x46, 0x43, 0xC6, 0x40, 0xC6, 0x42, 0xC6, 0x81, 0xC6, 0x03, 0xC6, 0xDF, 0x26, 0xFC, 0x26, 0x7E, 0x26, 0x7D, 0x26, 0x1F, 0xA6, 0x3C, 0xA6, 0xDE, 0xA6, 0x5D, 0xA6, 0xAF, 0x66, 0x9C, 0x66, 0x1E, 0x66, 0xED, 0x66, 0xCF, 0xE6, 0xAC, 0xE6, 0xCE, 0xE6, 0x4D, 0xE6, 0x77, 0x16, 0x0C, 0x16, 0xF6, 0x16, 0x75, 0x16, 0x97, 0x96, 0xD4, 0x96, 0x56, 0x96, 0x15, 0x96, 0x27, 0x56, 0xA4, 0x56, 0x26, 0x56, 0x45, 0x56, 0xFB, 0xD6, 0xF8, 0xD6, 0xBA, 0xD6, 0xD9, 0xD6, 0x1B, 0x36, 0x18, 0x36, 0x6A, 0x36, 0x29, 0x36, 0x0B, 0xB6, 0x08, 0xB6, 0x72, 0xB6, 0x31, 0xB6, 0x13, 0x76, 0xE0, 0x76, 0xA2, 0x76, 0xC1, 0x76, 0xFD, 0x76, 0x9F, 0xF6, 0xDC, 0xF6, 0x9E, 0xF6, 0x6D, 0xF6, 0x8F, 0x0E, 0x8C, 0x0E, 0xF6, 0x0E, 0x35, 0x0E, 0x67, 0x8E, 0x64, 0x8E, 0x26, 0x8E, 0x85, 0x8E, 0x3B, 0x4E, 0xD8, 0x4E, 0x1A, 0x4E, 0xA9, 0x4E, 0x0B, 0xCE, 0xF0, 0xCE, 0x32, 0xCE, 0x91, 0xCE, 0xA3, 0x2E, 0x40, 0x2E, 0xFC, 0x2E, 0x3E, 0x2E, 0x1D, 0x2E, 0x4F, 0xAE, 0x8C, 0xAE, 0x76, 0xAE, 0x55, 0xAE, 0x27, 0x6E, 0xC4, 0x6E, 0x06, 0x6E, 0x39, 0x6E, 0x6B, 0xEE, 0x28, 0xEE, 0x8A, 0xEE, 0xB1, 0xEE, 0x13, 0x1E, 0xA0, 0x1E, 0x82, 0x1E, 0xBE, 0x1E, 0x9D, 0x1E, 0x4F, 0x9E, 0x8C, 0x9E, 0x36, 0x9E, 0x15, 0x9E, 0x47, 0x5E, 0x04, 0x5E, 0xDA, 0x5E, 0xE9, 0x5E, 0x0B, 0xDE, 0x70, 0xDE, 0x92, 0xDE, 0xA1, 0xDE, 0xFD, 0xDE, 0xEF, 0x3E, 0xEC, 0x3E, 0x4E, 0x3E, 0xB5, 0x3E, 0x67, 0xBE, 0x24, 0xBE, 0xFA, 0xBE, 0x59, 0xBE, 0xCB, 0x7E, 0x08, 0x7E, 0xD2, 0x7E, 0x61, 0x7E, 0x03, 0x7E, 0xEF, 0xFE, 0xEC, 0xFE, 0x8E, 0xFE, 0x35, 0xFE, 0x27, 0x01, 0x84, 0x01, 0x3A, 0x01, 0xE9, 0x01, 0xBF, 0x03, 0x61, 0x02, 0xC5, 0x02, 0x03, 0x02, 0xBB, 0x03, 0x9F, 0x82, 0x18, 0x82, 0xAC, 0x82, 0x4A, 0x83, 0x76, 0x83, 0xB1, 0x82, 0x55, 0x82, 0xE3, 0x83, 0x27, 0x43, 0x40, 0x42, 0xF8, 0x43, 0xBC, 0x42, 0x5A, 0x43, 0x6E, 0x43, 0xA9, 0x43, 0xCD, 0x42, 0x0B, 0x43, 0xB7, 0xC2, 0xD0, 0xC3, 0x94, 0xC2, 0x62, 0xC3, 0xC6, 0xC3, 0x81, 0xC3, 0xF9, 0xC3, 0xBD, 0xC2, 0x5B, 0xC3, 0xEF, 0x22, 0x68, 0x22, 0x2C, 0x22, 0x8A, 0x23, 0x76, 0x23, 0xB1, 0x22, 0xD5, 0x22, 0x93, 0x22, 0x67, 0xA2, 0x20, 0xA3, 0x44, 0xA3, 0x02, 0xA3, 0x7A, 0xA2, 0x5E, 0xA2, 0x59, 0xA2, 0x1D, 0xA2, 0x6B, 0xA2, 0x4F, 0x63, 0x48, 0x62, 0x0C, 0x63, 0x72, 0x63, 0xD6, 0x63, 0x51, 0x63, 0x95, 0x62, 0xE3, 0x62, 0x27, 0xE3, 0xC0, 0xE3, 0x84, 0xE3, 0x02, 0xE2, 0x7A, 0xE2, 0x5E, 0xE3, 0x59, 0xE3, 0x9D, 0xE2, 0xEB, 0xE3, 0x2F, 0x12, 0x28, 0x12, 0x4C, 0x13, 0x8A, 0x12, 0x76, 0x13, 0x71, 0x12, 0x35, 0x13, 0xD3, 0x12, 0x17, 0x93, 0x10, 0x92, 0x64, 0x93, 0xA2, 0x92, 0xC6, 0x93, 0x41, 0x93, 0x85, 0x92, 0x03, 0x92, 0x7B, 0x93, 0xFF, 0xA5, 0x70, 0xA4, 0xB8, 0xA6, 0x34, 0xA7, 0xDC, 0xA5, 0xD2, 0xA5, 0xDA, 0xA4, 0x56, 0xA5, 0x9E, 0xA6, 0x91, 0xA6, 0x19, 0xA7, 0x15, 0xA6, 0xED, 0xA6, 0xE3, 0xA6, 0x6B, 0xA7, 0x67, 0xA6, 0xAF, 0x66, 0xA0, 0x66, 0x28, 0x67, 0x24, 0x65, 0xCC, 0x67, 0xC2, 0x65, 0xCA, 0x66, 0x46, 0x67, 0x4E, 0x64, 0x41, 0x64, 0x89, 0x65, 0x85, 0x66, 0x0D, 0x65, 0x03, 0x65, 0x0B, 0x66, 0xFB, 0x67, 0xF7, 0x65, 0x7F, 0xE4, 0xF0, 0xE4, 0x78, 0xE7, 0x74, 0xE5, 0xBC, 0xE6, 0x72, 0xE4, 0xBA, 0xE7, 0xB6, 0xE5, 0x3E, 0xE7, 0xB1, 0xE6, 0xB9, 0xE4, 0xB5, 0xE4, 0x3D, 0xE4, 0x33, 0xE7, 0x3B, 0xE7, 0x37, 0xE5, 0xDF, 0x17, 0x30, 0x15, 0x38, 0x15, 0x34, 0x15, 0xDC, 0x15, 0x32, 0x15, 0x3A, 0x15, 0x36, 0x15, 0xDE, 0x17, 0x31, 0x15, 0x39, 0x17, 0x35, 0x17, 0x3D, 0x14, 0xB3, 0x14, 0xBB, 0x16, 0xB7, 0x16, 0x3F, 0x97, 0xB0, 0x97, 0xB8, 0x97, 0x74, 0x94, 0xBC, 0x96, 0x72, 0x95, 0x7A, 0x97, 0xF6, 0x94, 0x7E, 0x96, 0xF1, 0x97, 0x05, 0x94, 0x0D, 0x96, 0x03, 0x97, 0x8B, 0x94, 0x87, 0x95, 0x8F, 0x57, 0x40, 0x56, 0x48, 0x57, 0xC4, 0x56, 0xCC, 0x55, 0x22, 0x56, 0x2A, 0x57, 0xA6, 0x56, 0xAE, 0x56, 0x61, 0x56, 0x69, 0x57, 0xE5, 0x56, 0xED, 0x55, 0x13, 0x55, 0x9B, 0x56, 0x97, 0x57, 0x9F, 0xD7, 0xD0, 0xD4, 0xD8, 0xD7, 0x34, 0xD5, 0x3C, 0xD6, 0xB2, 0xD7, 0x7A, 0xD5, 0xF6, 0xD6, 0x7E, 0xD7, 0x09, 0xD7, 0x85, 0xD7, 0x4D, 0xD6, 0xC3, 0xD6, 0x2B, 0xD4, 0xA7, 0xD4, 0xAF, 0x36, 0x60, 0x37, 0xE8, 0x35, 0x14, 0x35, 0x1C, 0x37, 0x52, 0x35, 0xDA, 0x36, 0x36, 0x36, 0x3E, 0x35, 0x71, 0x36, 0xF9, 0x36, 0x0D, 0x36, 0x83, 0x35, 0x4B, 0x35, 0xC7, 0x35, 0x2F, 0xB6, 0xA0, 0xB7, 0xE8, 0xB4, 0x14, 0xB4, 0xFC, 0x69, 0xA5, 0x6A, 0xB5, 0x6F, 0x6D, 0x6E, 0x7D, 0x69, 0xE3, 0x6D, 0x0B, 0x6A, 0x1B, 0x6B, 0x87, 0x6D, 0x57, 0x6A, 0x4F, 0x6F, 0xDF, 0xEE, 0x20, 0xEA, 0x30, 0xEF, 0xA8, 0xED, 0x78, 0xE8, 0xE4, 0xE8, 0xF4, 0xEB, 0x1C, 0xEE, 0x82, 0xEA, 0x52, 0xE8, 0x4A, 0xEB, 0xDA, 0xEA, 0x26, 0xEA, 0xB6, 0xEC, 0xAE, 0xEF, 0x7E, 0xEE, 0xE1, 0xE9, 0x09, 0xEE, 0x99, 0xE8, 0x45, 0xE8, 0x55, 0xEF, 0xCD, 0xEB, 0xFD, 0xD3, 0x47, 0xD3, 0xE7, 0xDC, 0xD7, 0xD5, 0xF7, 0xF3, 0x4B, 0xF2, 0x57, 0xC2, 0xAF, 0xD5, 0x7E, 0xFC, 0x7E, 0xF3, 0xFE, 0xBA, 0xFE, 0xE7, 0x01, 0xBE, 0x81, 0xB0, 0x81, 0xD9, 0x41, 0xD4, 0x41, 0xDD, 0xC1, 0xD2, 0xC1, 0xCB, 0x21, 0x96, 0x21, 0xEF, 0xA1, 0xA1, 0x61, 0xA8, 0x61, 0xC5, 0xE1, 0xCC, 0xE1, 0xBD, 0x11, 0xF2, 0x11, 0xBB, 0x91, 0xB6, 0x91, 0x8F, 0x51, 0x91, 0xD1, 0xE8, 0xD1, 0x85, 0x31, 0xCC, 0x31, 0x83, 0xB1, 0xF2, 0xB1, 0xEB, 0x71, 0x96, 0x71, 0xEF, 0xF1, 0xC1, 0x09, 0x88, 0x09, 0xF9, 0x89, 0xB4, 0x89, 0xAD, 0x49, 0xE2, 0x49, 0xCB, 0xC9, 0x86, 0xC9, 0xE7, 0x29, 0xDE, 0xA9, 0xE0, 0xA9, 0x89, 0x69, 0x84, 0x69, 0xB5, 0xE9, 0x9C, 0xE9, 0x83, 0x19, 0xCA, 0x19, 0xFB, 0x99, 0xD6, 0x99, 0xB7, 0x59, 0xC1, 0xD9, 0xF0, 0xD9, 0x99, 0x39, 0xA4, 0x39, 0x8D, 0xB9, 0xBC, 0xB9, 0xC3, 0x79, 0xCA, 0x79, 0xFB, 0xF9, 0x96, 0xF9, 0xD7, 0xDF, 0xFC, 0xBF, 0x43, 0x7E, 0x4F, 0x2C, 0xC0, 0x2D, 0xA8, 0x2C, 0x64, 0x2E, 0xEC, 0x2C, 0x12, 0x2F, 0x9A, 0x2F, 0xD6, 0x2C, 0xDE, 0x2D, 0xB1, 0x2D, 0x79, 0x2D, 0xFD, 0x5A, 0x06, 0x5E, 0x96, 0x58, 0x8E, 0x59, 0xFE, 0xBD, 0x82, 0xBA, 0xA2, 0xB9, 0x92, 0xBB, 0x72, 0xB0, 0x4A, 0xB6, 0x6A, 0xB5, 0x5A, 0xB7, 0x7A, 0xB7, 0xC6, 0xBA, 0xE6, 0xB9, 0xD6, 0xBB, 0xF6, 0xBD, 0x2E, 0xB2, 0x1E, 0xBE, 0x3E, 0xB5, 0x01, 0xB7, 0xA1, 0xB8, 0x91, 0xB2, 0xB1, 0xBA, 0x89, 0xB5, 0xA9, 0xBB, 0x59, 0xB0, 0x79, 0xB8, 0x45, 0xB6, 0x65, 0xB9, 0x55, 0xBD, 0x75, 0xBD, 0xCD, 0xB8, 0xED, 0xBC, 0xDD, 0xBA, 0xFD, 0xB2, 0xC3, 0xB5, 0xE3, 0xB3, 0xD3, 0xB7, 0xF3, 0xBD, 0x2B, 0xB4, 0x1B, 0xB2, 0x3B, 0xBA, 0x07, 0xB1, 0x27, 0xB9, 0x17, 0xBD, 0x37, 0xB3, 0x0F, 0xB7, 0xAF, 0xB0, 0x9F, 0xB8, 0xBF, 0x70, 0x80, 0x7C, 0xA0, 0x72, 0x90, 0x76, 0xB0, 0x7A, 0x88, 0x7E, 0xA8, 0x71, 0x98, 0x79, 0xB8, 0x71, 0x84, 0x7D, 0xA4, 0x7D, 0x94, 0x73, 0xB4, 0xF5, 0x07, 0xF7, 0x8F, 0xEE, 0x9F, 0xDC, 0x3F, 0xDB, 0xC7, 0xB8, 0xC7, 0xBA, 0xC7, 0xB9, 0xC7, 0xDB, 0x27, 0xB8, 0x27, 0xBA, 0x27, 0xB9, 0x27, 0x5B, 0xA7, 0x38, 0xA7, 0xDA, 0xA7, 0xD9, 0xA7, 0x1B, 0x67, 0x98, 0x67, 0x9A, 0x67, 0x19, 0x67, 0xAB, 0xE7, 0x68, 0xE7, 0xAA, 0xE7, 0x29, 0xE7, 0x8B, 0x17, 0x88, 0x17, 0x0A, 0x17, 0xF1, 0x17, 0x33, 0x97, 0x30, 0x97, 0x52, 0x97, 0x91, 0x97, 0x63, 0x57, 0xA0, 0x57, 0xC2, 0x57, 0x81, 0x57, 0xBF, 0xAE, 0x3E, 0xAE, 0xB9, 0xAF, 0x3D, 0xAF, 0xDB, 0xAF, 0x9F, 0x6E, 0x98, 0x6E, 0x1C, 0x6E, 0x6A, 0x6F, 0x2E, 0x6E, 0x29, 0x6E, 0x4D, 0x6F, 0x8B, 0x6F, 0xF7, 0xEE, 0x70, 0xEF, 0xB4, 0xEE, 0xD2, 0xEF, 0x96, 0xEE, 0x11, 0xEF, 0xE5, 0xEE, 0xA3, 0xEE, 0xC7, 0x1E, 0x40, 0x1E, 0x04, 0x1E, 0x7C, 0x1F, 0x3A, 0x1F, 0x9E, 0x1F, 0x99, 0x1E, 0xED, 0x1E, 0xAB, 0x1E, 0x8F, 0x9F, 0x88, 0x9F, 0xF4, 0x9F, 0xB2, 0x9E, 0x56, 0x9E, 0x91, 0x9E, 0xE5, 0x9E, 0xA3, 0x9E, 0x47, 0x9E, 0x7F, 0xFE, 0xF2, 0xFC, 0xF5, 0xF8, 0xDB, 0xFC, 0xF7, 0xFA, 0x85, 0xEA, 0xC5, 0xF4, 0xA5, 0xE0, 0x65, 0xF3, 0x15, 0xED, 0x55, 0xF1, 0x35, 0xE6, 0x75, 0xEC, 0xF5, 0xE7, 0x1F, 0xCF, 0x3F, 0xF7, 0x7F, 0x8D, 0xFF, 0x2E, 0xDF, 0xC8, 0xDE, 0x0C, 0xDF, 0xB2, 0xDF, 0x56, 0xDE, 0x11, 0xDE, 0xA5, 0xDE, 0x43, 0xDE, 0xFB, 0xDE, 0x5F, 0x3E, 0x98, 0x3E, 0x6C, 0x3E, 0xCA, 0x3E, 0x76, 0x3F, 0x31, 0x3F, 0x95, 0x3F, 0x63, 0x3E, 0x47, 0x3F, 0xBF, 0xBE, 0x38, 0xBF, 0x9C, 0xBE, 0xAA, 0xBF, 0xFE, 0x7C, 0xE3, 0x7D, 0xAB, 0x7F, 0x27, 0x7C, 0x4F, 0xFC, 0x00, 0x01, 0x9E, 0x08, 0x50, 0x18, 0xD0, 0x38, 0x30, 0x14, 0xB0, 0x34, 0x70, 0x2C, 0xF0, 0x1C, 0x08, 0x22, 0x88, 0x32, 0x48, 0x2A, 0xC8, 0x2A, 0x28, 0x06, 0xA8, 0x16, 0x68, 0x0E, 0xE8, 0x0E, 0x18, 0x01, 0x98, 0x11, 0x58, 0x31, 0xD8, 0x1F, 0x70, 0x72, 0x70, 0x4B, 0xF0, 0x6A, 0xF0, 0x2B, 0x08, 0x3A, 0x08, 0x07, 0x88, 0x26, 0x88, 0x47, 0x48, 0x36, 0x48, 0x0F, 0xC8, 0x4E, 0xC8, 0x37, 0x00, 0xF7, 0xFD, 0xA1, 0x06, 0xA0, 0x81, 0xA0, 0x45, 0xA0, 0xC3, 0xA0, 0xC7, 0x61, 0xA0, 0x60, 0xA4, 0x61, 0x62, 0x61, 0xE6, 0x60, 0x11, 0x61, 0x95, 0x61, 0x53, 0x60, 0x57, 0xE0, 0x30, 0xE0, 0xB4, 0xE0, 0xB2, 0xE1, 0xB6, 0x01, 0xCC, 0x37, 0x84, 0x2F, 0x82, 0x3F, 0x42, 0x20, 0x43, 0xB0, 0x40, 0xA8, 0x44, 0xB8, 0x40, 0xA4, 0x45, 0xB4, 0x47, 0x6C, 0x40, 0xBC, 0x47, 0x62, 0x41, 0x72, 0x43, 0x6A, 0x47, 0x7A, 0x45, 0xE6, 0x46, 0xF6, 0x41, 0xEE, 0x43, 0xFE, 0x46, 0x11, 0x42, 0x09, 0x46, 0x19, 0x41, 0x05, 0x47, 0x95, 0x40, 0x8D, 0x42, 0x9D, 0x46, 0x83, 0x45, 0x93, 0x47, 0x4B, 0x44, 0x5B, 0x40, 0x47, 0x41, 0x57, 0x43, 0x4F, 0x47, 0x5F, 0xC7, 0xC0, 0xC2, 0xD0, 0xC1, 0xC8, 0xC3, 0xD8, 0xC5, 0x24, 0xC4, 0x34, 0xC2, 0x2C, 0xC1, 0xFC, 0x83, 0x45, 0x8E, 0x65, 0x89, 0x55, 0x85, 0x75, 0x89, 0x4D, 0x8B, 0x6D, 0x8F, 0xDD, 0x80, 0x7D, 0x8F, 0xC3, 0x8C, 0xE3, 0x8A, 0xD3, 0x86, 0xF3, 0x82, 0xCB, 0x89, 0xEB, 0x8D, 0xDB, 0x83, 0xFB, 0x89, 0xC7, 0x8F, 0x17, 0x88, 0x37, 0x88, 0x0F, 0x82, 0x2F, 0x8A, 0x1F, 0x8E, 0x3F, 0x4E, 0x00, 0x45, 0x20, 0x4D, 0x10, 0x4B, 0x30, 0x4B, 0x08, 0x4F, 0xA8, 0x48, 0x98, 0x44, 0xB8, 0x44, 0x84, 0x4A, 0xA4, 0x46, 0x94, 0x41, 0xB4, 0x4E, 0x8C, 0x4D, 0xAC, 0x43, 0x9C, 0x4B, 0xBC, 0x4B, 0x42, 0x40, 0x62, 0x48, 0x52, 0x4C, 0x72, 0x44, 0x4A, 0x4A, 0x6A, 0x46, 0x5A, 0x41, 0x7A, 0x46, 0x46, 0x45, 0x66, 0x4D, 0x56, 0x4B, 0x76, 0x4D, 0x4E, 0x4F, 0xEE, 0x40, 0xDE, 0x48, 0xFE, 0x40, 0xC1, 0x42, 0xE1, 0x4A, 0xD1, 0x46, 0xF1, 0x42, 0xC9, 0x49, 0xE9, 0x45, 0xD9, 0x43, 0xF9, 0x41, 0xC5, 0x47, 0xE5, 0x4F, 0x35, 0x40, 0x0D, 0x44, 0x2D, 0x4C, 0x1D, 0x4A, 0x3D, 0x4A, 0x03, 0x41, 0x23, 0x49, 0x13, 0x45, 0x33, 0x4D, 0x0B, 0x4B, 0x2B, 0x47, 0x9B, 0x40, 0xFB, 0x9B, 0x0E, 0x99, 0x4E, 0x85, 0x2E, 0x95, 0x6E, 0x95, 0x1E, 0x83, 0x5E, 0x8B, 0x3E, 0x9B, 0x7E, 0x8B, 0x01, 0x8F, 0x41, 0x9F, 0xA1, 0x90, 0xE1, 0x80, 0x91, 0x98, 0xD1, 0x94, 0xB1, 0x8C, 0xF1, 0x84, 0x89, 0x92, 0xC9, 0x8A, 0xA9, 0x9A, 0xE9, 0x92, 0x99, 0x8E, 0xD9, 0x9E, 0xB9, 0x81, 0xF9, 0x9E, 0x85, 0x99, 0xC5, 0x85, 0xA5, 0x95, 0xE5, 0x99, 0x95, 0x83, 0xD5, 0x93, 0xB5, 0x8B, 0xF5, 0x8D, 0x8D, 0x87, 0xCD, 0x17, 0xC0, 0xF9, 0x2F, 0x76, 0x01, 0xF6, 0x00, 0xF6, 0x01, 0x0E, 0x20, 0x0E, 0x61, 0x8E, 0x60, 0x8E, 0x61, 0x4E, 0x10, 0x4E, 0x51, 0xCE, 0x50, 0xCE, 0x51, 0x2E, 0x30, 0x2E, 0x31, 0xAE, 0x30, 0xAE, 0x31, 0x6E, 0x70, 0x6E, 0x71, 0xEE, 0x70, 0xEE, 0x31, 0x1E, 0x70, 0x1E, 0x71, 0x9E, 0x70, 0x00, 0xE9, 0xC1, 0x79, 0xC5, 0x78, 0xC3, 0x78, 0x47, 0xF9, 0xC0, 0xF8, 0x44, 0xF9, 0x42, 0xF9, 0x46, 0xF8, 0x41, 0xF8, 0x45, 0xF8, 0x83, 0xF9, 0x87, 0x04, 0x80, 0x04, 0x04, 0x05, 0x02, 0x05, 0xFA, 0x05, 0xBE, 0x04, 0xF9, 0x04, 0xFD, 0x04, 0x7B, 0x05, 0xDF, 0x85, 0xB8, 0x85, 0xBC, 0x84, 0x3A, 0x85, 0x5E, 0x84, 0xD9, 0x01, 0xB4, 0x6F, 0x15, 0x7E, 0x14, 0x61, 0x16, 0x71, 0x12, 0x69, 0x14, 0xB9, 0x15, 0xA5, 0x17, 0xB5, 0x13, 0xAD, 0x15, 0xBD, 0x14, 0xA3, 0x16, 0xB3, 0x02, 0xF0, 0xFE, 0x54, 0x9C, 0x42, 0xDC, 0x5C, 0xBC, 0x4C, 0xFC, 0x8F, 0x04, 0x89, 0x84, 0xB1, 0x44, 0x91, 0xC4, 0xBE, 0x24, 0x81, 0xA4, 0xBE, 0x64, 0x9E, 0xE4, 0xB6, 0x14, 0x8E, 0x94, 0xB6, 0x54, 0x96, 0xD4, 0xBA, 0x34, 0xA6, 0xB4, 0x86, 0x74, 0xBA, 0xF4, 0x8A, 0x0C, 0xAA, 0x8C, 0x8A, 0x4C, 0xB2, 0xCC, 0x82, 0x2C, 0xA2, 0xAC, 0x82, 0x6C, 0xBC, 0xEC, 0xAC, 0x1C, 0xAC, 0x9C, 0x8C, 0x5C, 0xB4, 0xDC, 0xA4, 0x3C, 0x84, 0xBC, 0xB8, 0x7C, 0x98, 0xFC, 0x88, 0x02, 0x88, 0x82, 0xB0, 0x42, 0x90, 0x42, 0xBF, 0xC2, 0x97, 0x22, 0x9F, 0xA2, 0xAF, 0x62, 0x8F, 0xE2, 0x9B, 0x12, 0xA7, 0x92, 0x87, 0x52, 0xBB, 0xD2, 0xB3, 0x32, 0xAB, 0xB2, 0xB3, 0x72, 0x93, 0xF2, 0x9D, 0x0A, 0x83, 0x8A, 0x9D, 0x4A, 0xAD, 0xCA, 0xA5, 0x2A, 0xB5, 0xAA, 0xA5, 0x6A, 0x85, 0xEA, 0x89, 0x1A, 0x99, 0x9A, 0x89, 0x5A, 0xB1, 0xDA, 0x81, 0x3A, 0x81, 0xBA, 0xBE, 0x7A, 0x9E, 0xFA, 0x96, 0x06, 0xB6, 0x86, 0x96, 0x46, 0x86, 0xC6, 0xAA, 0x26, 0x9A, 0xA6, 0x8A, 0x66, 0xB2, 0xE6, 0x82, 0x16, 0x82, 0x96, 0xBC, 0x56, 0xAC, 0xD6, 0xB4, 0x36, 0xB4, 0xB6, 0x24, 0x80, 0xFB, 0xA3, 0x3A, 0xA0, 0x3A, 0xC2, 0x3A, 0x41, 0x3A, 0x03, 0x3A, 0x5F, 0xBA, 0x7C, 0xBA, 0x3E, 0xBA, 0xDD, 0xBA, 0xAF, 0x7A, 0x1C, 0x7A, 0x6E, 0x7A, 0xAD, 0x7A, 0x0F, 0xFA, 0x4C, 0xFA, 0x0E, 0xFA, 0xF5, 0xFA, 0x57, 0x06, 0x34, 0x06, 0x56, 0x06, 0x95, 0x06, 0x27, 0x86, 0x64, 0x86, 0x26, 0x86, 0x45, 0x86, 0xFB, 0x46, 0xF8, 0x46, 0x7A, 0x46, 0x39, 0x46, 0x1B, 0xC6, 0x98, 0xC6, 0xEA, 0xC6, 0xA9, 0xC6, 0x4B, 0x26, 0x48, 0x26, 0x0A, 0x26, 0xF1, 0x26, 0x33, 0xA6, 0xD0, 0xA6, 0x52, 0xA6, 0x11, 0xA6, 0xA3, 0x66, 0x20, 0x66, 0x42, 0x66, 0x81, 0x66, 0xBF, 0xCC, 0x3E, 0xCC, 0xB9, 0xCD, 0x3D, 0xCD, 0xDB, 0xCD, 0x9F, 0x2D, 0x58, 0x2C, 0x9C, 0x2C, 0x1A, 0x2C, 0xAE, 0x2D, 0x69, 0xFE, 0x57, 0xF2, 0x1B, 0x5B, 0x15, 0x5A, 0xED, 0x5A, 0xE3, 0x59, 0xEB, 0x58, 0x67, 0x59, 0xAF, 0xD9, 0xA0, 0xDB, 0xA8, 0xDA, 0x24, 0xDB, 0xFC, 0xFE, 0xFF, 0x93, 0x7F, 0xCA, 0x0E, 0xD2, 0x4E, 0xC2, 0x2E, 0xCC, 0x6E, 0xD8, 0x1E, 0xD8, 0x5E, 0xD0, 0xDE, 0xDF, 0xBE, 0xCF, 0xFE, 0xDD, 0x81, 0xDB, 0xC1, 0xD3, 0xA1, 0xC3, 0xE1, 0xD9, 0x91, 0xD5, 0xD1, 0xD9, 0xB1, 0xC9, 0xF1, 0xD6, 0x89, 0xDE, 0xC9, 0xCE, 0xA9, 0xC6, 0xE9, 0xC2, 0x99, 0xCA, 0xD9, 0xD2, 0xB9, 0xDC, 0xF9, 0xD8, 0x85, 0xD4, 0xC5, 0xC4, 0xA5, 0xD8, 0xE5, 0xC0, 0x95, 0xD0, 0x55, 0xDF, 0x35, 0xCF, 0x75, 0xC7, 0x0D, 0xD7, 0x4D, 0xC7, 0x2D, 0xDB, 0x6D, 0xC3, 0x1D, 0xD3, 0x5D, 0xC3, 0x3D, 0xC3, 0x7D, 0xD5, 0x03, 0xCD, 0x43, 0xCD, 0x23, 0xD5, 0x63, 0xD9, 0x13, 0xC5, 0x53, 0xC5, 0x33, 0xD9, 0x73, 0xD1, 0x0B, 0xD9, 0x4B, 0xD9, 0x2B, 0x09, 0x40, 0x7D, 0x24, 0x6F, 0x25, 0xEF, 0x24, 0xEF, 0x05, 0x1F, 0x24, 0x1F, 0x25, 0x9F, 0x24, 0x9F, 0x45, 0x5F, 0x64, 0x5F, 0x65, 0xDF, 0x14, 0xDF, 0x25, 0x3F, 0x14, 0x3F, 0x55, 0xBF, 0x54, 0xBF, 0x15, 0x7F, 0x74, 0x7F, 0x75, 0xFF, 0x0C, 0xFF, 0xF5, 0x00, 0xAC, 0x00, 0xED, 0x80, 0x9C, 0x80, 0xED, 0x40, 0xBC, 0x40, 0xFD, 0xC0, 0x82, 0xC0, 0xFD, 0x20, 0xA2, 0x20, 0xE3, 0xA0, 0x92, 0xA0, 0xE3, 0x60, 0xF2, 0x60, 0x8B, 0xE0, 0xCA, 0xE0, 0x8B, 0x10, 0x9A, 0x10, 0xDB, 0x90, 0x7A, 0x00, 0xED, 0x19, 0x43, 0x9D, 0x43, 0x5B, 0x42, 0x9F, 0xC2, 0xD8, 0xC3, 0x3C, 0xC2, 0xBA, 0xC2, 0xDE, 0xC2, 0x79, 0xC3, 0xFD, 0xC2, 0xFB, 0xC3, 0x7F, 0x22, 0x84, 0x23, 0x42, 0x23, 0x46, 0x23, 0x21, 0x22, 0x25, 0x23, 0xA3, 0x01, 0xA4, 0x87, 0x8B, 0x52, 0x88, 0x4A, 0x8A, 0x5A, 0x8A, 0x46, 0x8D, 0x56, 0x8F, 0xCE, 0x8C, 0xDE, 0x8C, 0xC1, 0x8D, 0xD1, 0x8B, 0x29, 0x88, 0x39, 0x88, 0x25, 0x89, 0x35, 0x8B, 0xAD, 0x88, 0x3D, 0x8F, 0xA3, 0x8E, 0xB3, 0x8D, 0xAB, 0x8F, 0xBB, 0x8B, 0x67, 0x8E, 0x77, 0x8D, 0x6F, 0x8F, 0x7F, 0x4D, 0xE0, 0x4A, 0xF0, 0x49, 0xE8, 0x4B, 0xF8, 0x4E, 0x14, 0x4A, 0x0C, 0x49, 0x1C, 0x4D, 0x82, 0x48, 0x92, 0x4C, 0x8A, 0x4E, 0x9A, 0x49, 0x86, 0x4F, 0x56, 0x4C, 0x4E, 0x4E, 0x5E, 0x4A, 0x41, 0x4B, 0xD1, 0x48, 0xC9, 0x4A, 0xD9, 0x4C, 0xC5, 0x4D, 0xD5, 0x4F, 0x2D, 0x48, 0x3D, 0x48, 0x23, 0x49, 0x33, 0x4D, 0x2B, 0x4F, 0x3B, 0x4D, 0xA7, 0x4A, 0xB7, 0x4E, 0xAF, 0x4D, 0xBF, 0xCE, 0xA0, 0xCF, 0x70, 0xCC, 0x68, 0xCA, 0x78, 0xC8, 0x64, 0xCD, 0x74, 0xCB, 0x6C, 0xCF, 0x7C, 0xC9, 0xE2, 0xCC, 0xF2, 0xCE, 0xEA, 0xC9, 0xFA, 0xC8, 0xE6, 0x03, 0xF0, 0xBD, 0x3F, 0xFB, 0x27, 0x47, 0x28, 0x27, 0x38, 0x67, 0x28, 0x17, 0x24, 0x57, 0x34, 0x37, 0x34, 0x77, 0x34, 0x0F, 0x2C, 0x4F, 0x3C, 0x2F, 0x3C, 0x6F, 0x2C, 0x1F, 0x3C, 0x5F, 0x3C, 0x3F, 0x3C, 0x7F, 0xAC, 0x00, 0xBC, 0x40, 0xBC, 0x20, 0xBC, 0x60, 0xAC, 0x10, 0xBC, 0x50, 0xAC, 0x30, 0xAC, 0x70, 0xA4, 0x08, 0xB4, 0x48, 0xA4, 0x28, 0xA4, 0x68, 0xA8, 0x18, 0xA8, 0x58, 0xB0, 0x38, 0xB0, 0xB8, 0xBF, 0xF8, 0xAB, 0x84, 0xAF, 0xC4, 0xB7, 0xA4, 0xBB, 0xE4, 0x5F, 0x29, 0x67, 0xA9, 0x47, 0x69, 0x5B, 0xE9, 0x53, 0x19, 0x73, 0x99, 0x53, 0x59, 0x43, 0xD9, 0x4D, 0x39, 0x6D, 0xB9, 0x75, 0x79, 0x55, 0xF9, 0x69, 0x05, 0x59, 0x85, 0x49, 0x45, 0x51, 0xC5, 0x5E, 0x25, 0x5E, 0xA5, 0x4E, 0x65, 0x56, 0xE5, 0x5A, 0x15, 0x6A, 0x95, 0x72, 0x55, 0x62, 0xD5, 0x6C, 0x35, 0x4C, 0xB5, 0x64, 0x75, 0x78, 0xF5, 0x70, 0xF5, 0x4F, 0x0D, 0x5F, 0x8D, 0x4F, 0x4D, 0x67, 0xCD, 0x73, 0x2D, 0x73, 0xAD, 0x43, 0x6D, 0x6D, 0xED, 0x79, 0x1D, 0x79, 0x9D, 0x49, 0x5D, 0x61, 0xDD, 0x4E, 0x3D, 0x76, 0xBD, 0x46, 0x7D, 0x6A, 0xFD, 0x42, 0x03, 0x7C, 0x83, 0x4C, 0x43, 0x44, 0xC3, 0x48, 0x23, 0x50, 0x23, 0x7F, 0xA3, 0x4F, 0x63, 0x07, 0x80, 0xF3, 0x4C, 0x4D, 0xF6, 0x4D, 0xD5, 0x4D, 0xA7, 0xCD, 0xA4, 0xCD, 0x86, 0xCD, 0x79, 0xCD, 0x1B, 0x00, 0xD2, 0xAB, 0xB4, 0x24, 0xB4, 0xCC, 0xB4, 0x42, 0xB6, 0x8A, 0xB5, 0x06, 0xB5, 0xF6, 0xB5, 0xBE, 0xB5, 0xB1, 0xB7, 0xB9, 0xB4, 0x35, 0xB4, 0x5D, 0xB6, 0x53, 0xB6, 0x9B, 0xB6, 0x17, 0x02, 0x68, 0x8F, 0xD5, 0xA1, 0xD6, 0x91, 0xD4, 0x31, 0xDB, 0x09, 0xDD, 0x29, 0xDE, 0x19, 0xDC, 0xF9, 0xAB, 0xF3, 0xAD, 0x8B, 0xA3, 0xCB, 0xA5, 0xAB, 0xA1, 0xEB, 0xB2, 0x9B, 0xA2, 0xDB, 0xA4, 0xBB, 0xB0, 0x7B, 0xBB, 0x07, 0xB3, 0x47, 0xB5, 0x27, 0xB1, 0x67, 0xA6, 0x17, 0xAA, 0x57, 0xAC, 0x37, 0xA8, 0xB7, 0xAF, 0xF7, 0x5F, 0x1F, 0x5B, 0x9F, 0x53, 0x5F, 0x5D, 0xDF, 0xC5, 0x2F, 0xF2, 0x5F, 0xC6, 0xBF, 0xF2, 0x7F, 0x6D, 0xF6, 0xA3, 0xF7, 0x2B, 0xF7, 0xC7, 0xF7, 0x4F, 0x0D, 0x80, 0x0F, 0x08, 0x0F, 0xF8, 0x0F, 0x74, 0x0F, 0xFC, 0x1D, 0x64, 0x1E, 0xB4, 0x1F, 0xAC, 0x1E, 0x3C, 0x19, 0x22, 0x19, 0x32, 0x18, 0xCA, 0x19, 0x5A, 0x1B, 0x46, 0x01, 0xD0, 0x3F, 0x76, 0x78, 0x62, 0x04, 0x6C, 0x44, 0x68, 0xC4, 0x7F, 0xA4, 0x7B, 0xE4, 0x65, 0x94, 0x65, 0xD4, 0x71, 0xB4, 0x76, 0xF4, 0x7C, 0x8C, 0x7C, 0xCC, 0x78, 0xAC, 0x60, 0x6C, 0x7B, 0x1C, 0x6B, 0x5C, 0x7D, 0x3C, 0x65, 0x7C, 0x7E, 0x02, 0x76, 0x42, 0x6A, 0x22, 0x7C, 0x62, 0x78, 0xE2, 0x67, 0x92, 0x7F, 0xD2, 0x67, 0xB2, 0x13, 0x60, 0x01, 0xCC, 0x53, 0x0E, 0x53, 0x75, 0x53, 0x17, 0xD3, 0x14, 0xD3, 0xA6, 0xD3, 0xC5, 0xD3, 0x7B, 0x33, 0x78, 0x33, 0xDA, 0x33, 0x19, 0x33, 0x2B, 0xB3, 0xC8, 0xB3, 0x8A, 0xB3, 0xF1, 0xB3, 0xD3, 0x73, 0x50, 0x73, 0xE2, 0x73, 0xA1, 0x73, 0x43, 0x73, 0x3F, 0xF3, 0xFC, 0xF3, 0xBE, 0xF3, 0xDD, 0x00, 0x17, 0x60, 0xFF, 0xED, 0xFA, 0xBB, 0xF9, 0xF7, 0xFD, 0x02, 0xC3, 0x82, 0xDD, 0x42, 0xED, 0xC2, 0xC5, 0x22, 0xD5, 0xA2, 0xE5, 0x62, 0xF9, 0xE2, 0xF1, 0x12, 0xE9, 0x92, 0xC9, 0x52, 0xD1, 0xD2, 0xFE, 0x32, 0xC1, 0xB2, 0xFE, 0x72, 0xFE, 0xF2, 0xCE, 0x0A, 0xEE, 0x8A, 0xCE, 0x4A, 0xCE, 0xCA, 0xE6, 0x2A, 0xF6, 0xAA, 0xD6, 0x6A, 0xD6, 0xEA, 0xC6, 0x1A, 0xE6, 0x9A, 0xE6, 0x5A, 0xE6, 0xDA, 0xFA, 0x3A, 0xE6, 0xBA, 0xE6, 0x7A, 0xE6, 0xFA, 0xFA, 0x06, 0xE6, 0x86, 0xE6, 0x46, 0xE6, 0xC6, 0x06, 0xC0, 0x08, 0xB4, 0x36, 0xB3, 0x37, 0x37, 0xB7, 0x70, 0xB6, 0x74, 0xB6, 0x72, 0xB7, 0x76, 0xB6, 0xF1, 0xB6, 0xF5, 0xB7, 0x0B, 0xB6, 0xF7, 0x77, 0x88, 0x76, 0x8C, 0x77, 0x8A, 0x77, 0x8E, 0x76, 0x49, 0x77, 0xCD, 0x76, 0xCB, 0x77, 0xCF, 0xF6, 0xA8, 0xF6, 0xAC, 0xF7, 0x6A, 0xF6, 0xAE, 0xF6, 0xE9, 0xF6, 0x1D, 0xF6, 0x1B, 0xF7, 0xEF, 0x0F, 0x58, 0x0E, 0x5C, 0x0F, 0xDA, 0x0E, 0x5E, 0x0E, 0x39, 0x0F, 0xBD, 0x0F, 0x7B, 0x0E, 0x3F, 0x8F, 0x04, 0x8E, 0x02, 0x8F, 0x86, 0xFE, 0x80, 0xFE, 0x11, 0xFB, 0x13, 0xF1, 0x67, 0xF2, 0x18, 0xE6, 0x58, 0xEE, 0x38, 0xE1, 0x78, 0xE1, 0x04, 0xE5, 0x44, 0xED, 0x24, 0xE3, 0x64, 0x03, 0x60, 0x04, 0x7A, 0xA7, 0x05, 0xA7, 0x87, 0x67, 0xA4, 0x67, 0x16, 0x67, 0x55, 0x67, 0x97, 0xE7, 0xF4, 0xE7, 0x4E, 0xE7, 0x2D, 0xE7, 0x7F, 0x2F, 0xB8, 0x2E, 0x7C, 0x2E, 0x7E, 0x5D, 0x02, 0x5D, 0x8A, 0x5E, 0x46, 0x5C, 0x4E, 0x5D, 0xC1, 0x5D, 0x29, 0x5E, 0xA5, 0x5C, 0xAD, 0x5E, 0x63, 0x5D, 0xEB, 0x5E, 0x17, 0x5E, 0x1F, 0xDD, 0x90, 0xDF, 0x58, 0xDF, 0xD4, 0xDD, 0xDC, 0xDF, 0xB2, 0xDE, 0x7A, 0xDE, 0xF6, 0xDC, 0x7E, 0xDF, 0x89, 0xDC, 0x85, 0xDF, 0x4D, 0xDD, 0xC3, 0xDF, 0x2B, 0xDF, 0xA7, 0xDF, 0x6F, 0x3E, 0xE0, 0x3F, 0x18, 0x3F, 0x94, 0x3F, 0x5C, 0x3C, 0xD2, 0x3F, 0x3A, 0x3F, 0xB6, 0x3F, 0xBE, 0x3F, 0x09, 0x3C, 0x85, 0x3E, 0x4D, 0x3C, 0xC3, 0x3E, 0x2B, 0x3D, 0xA7, 0x3F, 0x6F, 0xFE, 0x25, 0xF8, 0x6B, 0xFA, 0xB7, 0x12, 0x60, 0x01, 0xCC, 0x2F, 0x1E, 0x2F, 0xBD, 0xAF, 0x40, 0xAF, 0xE2, 0x00, 0x07, 0xF8, 0xFD, 0x0F, 0xED, 0x9F, 0xCE, 0xBF, 0xC2, 0x7F, 0xC7, 0x6F, 0x34, 0x6F, 0x8E, 0x6F, 0x6D, 0x6F, 0xEF, 0xEF, 0x82, 0xEF, 0xE1, 0xEF, 0x33, 0x1F, 0x48, 0x1F, 0x1A, 0x1F, 0x79, 0x1F, 0x47, 0x9F, 0x54, 0x9F, 0x0E, 0x9F, 0x6D, 0x9F, 0xEF, 0x5F, 0x42, 0x5F, 0x11, 0x5F, 0xB3, 0xDF, 0x28, 0xDF, 0x5A, 0xDF, 0x85, 0xDF, 0x27, 0x3F, 0x74, 0x3F, 0x2E, 0x3F, 0x5D, 0x3F, 0xFF, 0x23, 0x00, 0x62, 0x40, 0x91, 0x40, 0x33, 0xC0, 0x88, 0xC0, 0x2A, 0x80, 0xEB, 0x7F, 0x0B, 0x04, 0x1F, 0xC4, 0x18, 0xA4, 0x1C, 0xE4, 0x1C, 0x94, 0x0E, 0xD4, 0x11, 0xB4, 0x15, 0xF4, 0x15, 0x8C, 0x07, 0x2C, 0x00, 0x6C, 0x08, 0x1C, 0x1C, 0x5C, 0x0A, 0x3C, 0x0E, 0xFC, 0x37, 0x04, 0x2A, 0x84, 0x06, 0x44, 0x0E, 0xC4, 0x2E, 0x24, 0x31, 0xA4, 0x19, 0x64, 0x25, 0xE4, 0x15, 0x14, 0x03, 0x94, 0x0B, 0x54, 0x3B, 0xD4, 0x3F, 0x68, 0x3E, 0xE8, 0x40, 0xE8, 0x61, 0x18, 0x08, 0x00, 0xFD, 0xE3, 0x60, 0x16, 0x60, 0x51, 0x61, 0x35, 0x60, 0xB3, 0x61, 0x77, 0xE1, 0x88, 0xE0, 0x4C, 0xE1, 0x2A, 0xE0, 0x2E, 0xE0, 0xE9, 0xE1, 0x9D, 0xE0, 0x5B, 0xE1, 0x5F, 0x10, 0xB8, 0x11, 0xFC, 0x10, 0x06, 0x11, 0x41, 0x11, 0x25, 0x10, 0xA3, 0x11, 0x67, 0x91, 0x10, 0x91, 0x54, 0x90, 0xD2, 0x91, 0x36, 0x90, 0x71, 0x91, 0x0D, 0x90, 0x8B, 0x91, 0x8F, 0x51, 0x28, 0x51, 0x6C, 0x50, 0xEA, 0x51, 0xEE, 0x51, 0x59, 0x51, 0x3D, 0x00, 0xB7, 0xFE, 0x07, 0x9A, 0x00, 0x5A, 0x30, 0xDA, 0x28, 0x3A, 0x24, 0xBA, 0x0C, 0x7A, 0x3C, 0xFA, 0x6F, 0x0C, 0x14, 0x0C, 0x75, 0x8C, 0x2C, 0x8C, 0x2D, 0x4C, 0xFC, 0xFF, 0xD8, 0x7F, 0x82, 0x45, 0x85, 0x65, 0x83, 0x55, 0x8F, 0x75, 0x87, 0xCD, 0x82, 0xED, 0x8E, 0xDD, 0x89, 0xFD, 0x8E, 0xC3, 0x87, 0x13, 0x88, 0x33, 0x84, 0x0B, 0x86, 0x2B, 0x81, 0x1B, 0x85, 0x3B, 0x83, 0x07, 0x8F, 0xA7, 0x84, 0x97, 0x82, 0xB7, 0x82, 0x8F, 0x09, 0xB8, 0xF2, 0x73, 0xF1, 0x77, 0x09, 0x88, 0x08, 0x4C, 0x08, 0xCA, 0x08, 0x4E, 0x09, 0xA9, 0x08, 0x6D, 0x09, 0xEB, 0x09, 0xEF, 0x88, 0x98, 0x89, 0x5C, 0x89, 0xDA, 0x89, 0x5E, 0x89, 0xB9, 0x89, 0x7D, 0x89, 0x7F, 0x11, 0xFF, 0x90, 0x08, 0x93, 0x84, 0x92, 0x8C, 0x91, 0x42, 0x92, 0x4A, 0x93, 0xC6, 0x92, 0xCE, 0x91, 0x21, 0x92, 0x29, 0x93, 0xA5, 0x92, 0xAD, 0x92, 0x63, 0x92, 0x6B, 0x93, 0xE7, 0x92, 0xEF, 0x52, 0x10, 0x52, 0x18, 0x53, 0x94, 0x52, 0x9C, 0x50, 0x52, 0x52, 0x5A, 0x53, 0xD6, 0x50, 0x5E, 0x53, 0x31, 0x50, 0x39, 0x51, 0xB5, 0x50, 0x3D, 0x53, 0x73, 0x50, 0x7B, 0x51, 0xF7, 0x50, 0x7F, 0xD2, 0x08, 0xD0, 0x04, 0xD2, 0x0C, 0xD1, 0x82, 0xD2, 0x8A, 0xD3, 0x46, 0xD2, 0x4E, 0xD1, 0xC1, 0xD0, 0xC9, 0xD1, 0x25, 0xD0, 0x2D, 0xD0, 0x23, 0xD3, 0xAB, 0xD2, 0xA7, 0xD3, 0xAF, 0x31, 0x60, 0x31, 0x68, 0x33, 0xE4, 0x32, 0xEC, 0x32, 0x12, 0x30, 0x1A, 0x31, 0x16, 0x33, 0x1E, 0x31, 0x91, 0x31, 0x99, 0x33, 0x55, 0x32, 0x9D, 0x33, 0x53, 0x33, 0xDB, 0x30, 0xD7, 0x31, 0xDF, 0xB0, 0x30, 0xB0, 0x38, 0xB2, 0x34, 0xB1, 0x3C, 0xB0, 0xB2, 0xB0, 0xBA, 0xB2, 0xB6, 0x01, 0x2E, 0x7C, 0x0E, 0x36, 0x4F, 0xB6, 0x2E, 0xB6, 0x37, 0x76, 0x1E, 0x76, 0x5F, 0xF6, 0x3E, 0xF6, 0x2F, 0x0E, 0x7E, 0x8E, 0x00, 0x8E, 0x01, 0x4E, 0x20, 0x4E, 0x21, 0xCE, 0x60, 0xCE, 0x61, 0x2E, 0x10, 0x2E, 0x51, 0xAE, 0x50, 0xAE, 0xD1, 0xFF, 0xC8, 0x1F, 0xC1, 0x3D, 0xCE, 0x03, 0xC9, 0x23, 0xC9, 0x13, 0xC5, 0x33, 0x09, 0xB8, 0xF1, 0xA5, 0x79, 0x63, 0x78, 0xA7, 0xF9, 0x60, 0xF8, 0x64, 0xF9, 0x62, 0xF9, 0x66, 0xF9, 0xE1, 0xF8, 0xE5, 0xF8, 0xE3, 0xF9, 0xE7, 0x04, 0xE0, 0x05, 0xE4, 0x05, 0x12, 0x04, 0xE6, 0x05, 0x11, 0x04, 0x15, 0x04, 0x13, 0x05, 0x7F, 0x0B, 0x21, 0x0A, 0x29, 0x0A, 0x25, 0x0A, 0xFD, 0x16, 0x46, 0x14, 0x56, 0x14, 0x4E, 0x14, 0xFE, 0x2D, 0x82, 0x28, 0xA2, 0x28, 0x92, 0x28, 0xF2, 0x1B, 0x70, 0xE7, 0x2B, 0x88, 0x26, 0x88, 0xCE, 0x8B, 0xC1, 0x8B, 0xC9, 0x8B, 0xC5, 0x89, 0xCD, 0x8A, 0xC3, 0x8A, 0xCB, 0x8A, 0xC7, 0x88, 0x4F, 0x4B, 0x40, 0x4B, 0x48, 0x49, 0x44, 0x4A, 0x4C, 0x48, 0x42, 0x48, 0x8A, 0x4B, 0x86, 0x49, 0x8E, 0x48, 0x81, 0x48, 0x09, 0x4B, 0x05, 0x49, 0x0D, 0x48, 0x7D, 0x4B, 0xF3, 0x4B, 0xFB, 0x49, 0xF7, 0x4A, 0xBF, 0xC9, 0x70, 0xC9, 0x78, 0x02, 0x6E, 0xFD, 0x67, 0x59, 0x16, 0x59, 0x67, 0xD9, 0x46, 0xD9, 0x5B, 0x39, 0x3A, 0x39, 0x1B, 0xB9, 0x6A, 0xB9, 0x33, 0x79, 0x72, 0x79, 0x53, 0xF9, 0x62, 0xF9, 0x7D, 0x05, 0x7C, 0x05, 0x5D, 0x85, 0x6C, 0x85, 0x75, 0x45, 0x74, 0x45, 0x55, 0xC5, 0x24, 0xC5, 0x79, 0x25, 0x38, 0x25, 0x69, 0xA5, 0x48, 0xA5, 0x31, 0x65, 0x10, 0x65, 0x21, 0x65, 0x7F, 0xE5, 0x1E, 0xE5, 0x7F, 0x2A, 0xEC, 0x2A, 0x2E, 0x2A, 0x8D, 0x2A, 0x37, 0xAA, 0x34, 0x00, 0xF2, 0x97, 0xA9, 0x1E, 0xAA, 0x11, 0xA8, 0xE9, 0xAA, 0x65, 0xAA, 0xAD, 0xA8, 0x23, 0xAB, 0x2B, 0xA8, 0xC7, 0xA8, 0x4F, 0x68, 0x80, 0x69, 0x08, 0x6B, 0xF8, 0x6B, 0xF4, 0x68, 0xBC, 0x6A, 0xB2, 0x69, 0x3A, 0x69, 0xD6, 0x6B, 0x5E, 0x6A, 0x51, 0x6A, 0x99, 0x6A, 0x15, 0x69, 0xED, 0x6A, 0xE3, 0x68, 0x6B, 0x6A, 0xA7, 0x69, 0x2F, 0xE8, 0xC0, 0xEB, 0xC8, 0xE8, 0x44, 0xEA, 0x8C, 0xEA, 0x02, 0xEB, 0x0A, 0xE8, 0xFA, 0xEA, 0x76, 0xEA, 0x3E, 0xEB, 0x31, 0xEB, 0x39, 0xE8, 0xD5, 0xEA, 0x9D, 0xEB, 0x93, 0xEB, 0x9B, 0xE8, 0x17, 0xEA, 0xEF, 0x18, 0x60, 0x1B, 0x68, 0x18, 0xA4, 0x19, 0x2C, 0x1A, 0x22, 0x18, 0xCA, 0x1A, 0x46, 0x19, 0x8E, 0x19, 0x81, 0x18, 0x09, 0x1A, 0xF9, 0x1B, 0xF5, 0x18, 0xBD, 0x1A, 0xB3, 0x19, 0x3B, 0x1B, 0x37, 0x1A, 0x5F, 0x9B, 0x50, 0x9B, 0x58, 0x9A, 0x94, 0x99, 0x1C, 0x99, 0x12, 0x9A, 0xEA, 0x9B, 0xE6, 0x98, 0x6E, 0x98, 0xA1, 0x9B, 0xA9, 0x9A, 0x25, 0x99, 0xCD, 0x9B, 0xC3, 0x9A, 0x4B, 0x9B, 0x47, 0x9A, 0x8F, 0x5A, 0x80, 0x58, 0x08, 0x59, 0xF8, 0x5B, 0xF4, 0x5A, 0xBC, 0x59, 0x72, 0x5A, 0xBA, 0x5B, 0xB6, 0x58, 0xDE, 0x5B, 0x31, 0x58, 0xD9, 0x59, 0xD5, 0x58, 0x9D, 0x5B, 0x53, 0x58, 0x9B, 0x5A, 0x17, 0x5B, 0xEF, 0xDB, 0xE0, 0xDB, 0xE8, 0xDA, 0x64, 0xDB, 0xAC, 0xDB, 0xA2, 0xDB, 0xAA, 0xDA, 0x26, 0xDB, 0xFE, 0xB6, 0x83, 0xB7, 0x93, 0xB3, 0x8B, 0xB1, 0x9B, 0xB4, 0x87, 0xB0, 0x17, 0xB3, 0x0F, 0xB1, 0x1F, 0xB4, 0xFF, 0x76, 0xE0, 0x73, 0xF0, 0x75, 0xE8, 0x76, 0x78, 0x75, 0x64, 0x77, 0x74, 0x75, 0x6C, 0x76, 0xBC, 0x77, 0x62, 0xF8, 0xFF, 0xD3, 0x9F, 0xD2, 0xD9, 0xDC, 0xB9, 0xCC, 0xF9, 0xC8, 0x85, 0xC8, 0xC5, 0xC0, 0x25, 0xDF, 0x65, 0xDB, 0x15, 0xC7, 0x55, 0xCB, 0x35, 0xC3, 0x75, 0xD5, 0x0D, 0xD5, 0x4D, 0xC5, 0x2D, 0xC9, 0x6D, 0xDE, 0x1D, 0xDE, 0x5D, 0xD6, 0x3D, 0xC6, 0x7D, 0xCA, 0x03, 0xD2, 0x43, 0xC2, 0x23, 0xCC, 0x63, 0xC4, 0x13, 0xC4, 0x53, 0xC8, 0x33, 0xD0, 0xB3, 0xDF, 0xF3, 0xD3, 0x8B, 0xD7, 0xCB, 0xC7, 0xAB, 0xDB, 0xEB, 0xD5, 0x9B, 0xC3, 0xDB, 0xDD, 0xBB, 0x0D, 0xB0, 0xE3, 0xB2, 0xF8, 0x38, 0xFB, 0x34, 0xF9, 0xDC, 0xF9, 0x32, 0xF8, 0xDA, 0xFB, 0xD6, 0xF9, 0x5E, 0xF9, 0xD1, 0xF8, 0x59, 0xFB, 0x55, 0xF9, 0x9D, 0xFB, 0x53, 0xFA, 0x5B, 0xF8, 0x97, 0x03, 0x2E, 0x7E, 0xB2, 0x00, 0xD3, 0x80, 0xD2, 0x80, 0xA3, 0x40, 0xE2, 0x40, 0xE3, 0xC0, 0xA2, 0xC0, 0x83, 0x20, 0xC2, 0x20, 0xC3, 0xA0, 0x82, 0xA0, 0xBD, 0x60, 0x82, 0x60, 0xFD, 0xE0, 0xFC, 0xE0, 0x9D, 0x10, 0xBC, 0x10, 0xBD, 0x90, 0xBC, 0x90, 0xED, 0x50, 0xDC, 0x50, 0xDD, 0xD0, 0x1C, 0xC0, 0xB5, 0x8F, 0x13, 0xA6, 0x13, 0x96, 0x13, 0xB6, 0x15, 0x8E, 0x1D, 0xAE, 0x1D, 0x9E, 0x1D, 0xBE, 0x19, 0x81, 0x1D, 0xA1, 0x1D, 0x91, 0x1D, 0xB1, 0x19, 0x89, 0x1D, 0xA9, 0x1D, 0x99, 0x1D, 0xB9, 0x19, 0x85, 0x1D, 0xA5, 0x1D, 0x95, 0x13, 0xB5, 0x15, 0x8D, 0x13, 0xAD, 0x13, 0x9D, 0x13, 0xBD, 0x05, 0x30, 0x00, 0x5D, 0xC0, 0xA5, 0xBF, 0x1D, 0x8B, 0x1B, 0xAB, 0x17, 0x9B, 0x17, 0xBB, 0x13, 0x87, 0x1F, 0xA7, 0x1F, 0x97, 0x1F, 0xB7, 0x1B, 0x4F, 0x10, 0x6F, 0x10, 0x5F, 0x10, 0xBF, 0x9F, 0x40, 0x98, 0x60, 0x08, 0xB8, 0xF3, 0x0F, 0x12, 0x89, 0x13, 0x8D, 0x13, 0x8B, 0x13, 0x8F, 0x92, 0x48, 0x92, 0x4C, 0x92, 0x4A, 0x93, 0xFE, 0x24, 0x93, 0x25, 0x9B, 0x25, 0x97, 0x25, 0x9F, 0xA4, 0x90, 0xA7, 0x98, 0xA7, 0x54, 0xA4, 0x9C, 0xA6, 0x52, 0xA4, 0x5A, 0xA6, 0x56, 0xA6, 0x9E, 0xA5, 0x51, 0xA5, 0x59, 0xA5, 0x55, 0xA5, 0x5D, 0xA4, 0x53, 0x03, 0x1C, 0xA0, 0x3A, 0xFD, 0x32, 0x83, 0x26, 0xC3, 0x26, 0xA3, 0x26, 0xE3, 0x32, 0x93, 0x36, 0xD3, 0x36, 0xB3, 0x36, 0xF3, 0x2A, 0x8B, 0x36, 0xCB, 0x36, 0xAB, 0x36, 0xEB, 0x2A, 0x9B, 0x36, 0xDB, 0x36, 0xBB, 0x36, 0xFB, 0x2A, 0x87, 0x36, 0xC7, 0x36, 0xA7, 0x36, 0xE7, 0x2A, 0x97, 0x36, 0xD7, 0x36, 0xB7, 0x36, 0xF7, 0x2A, 0x8F, 0x36, 0xCF, 0x36, 0xAF, 0x36, 0xEF, 0x2A, 0x9F, 0x36, 0xDF, 0x36, 0xBF, 0x26, 0xFF, 0xB2, 0x80, 0xA6, 0xC0, 0xA6, 0xA0, 0xA6, 0xE0, 0xB2, 0x90, 0xA6, 0xD0, 0xA6, 0xB0, 0xBA, 0xF0, 0xA2, 0x88, 0xBA, 0xC8, 0xBA, 0xA8, 0xBA, 0xE8, 0xA2, 0x98, 0xBA, 0xD8, 0xAA, 0xB8, 0xAA, 0xF8, 0xBC, 0x84, 0xAA, 0xC4, 0xAA, 0xA4, 0xAA, 0xE4, 0xBC, 0x94, 0xAA, 0xD4, 0xAA, 0xB4, 0xAA, 0xF4, 0xBC, 0x8C, 0xAA, 0xCC, 0xAA, 0xAC, 0xAA, 0xEC, 0xBC, 0x9C, 0xAA, 0xDC, 0x0A, 0xE0, 0x00, 0xE7, 0x15, 0x54, 0x15, 0xD6, 0x15, 0xD5, 0x15, 0x17, 0x95, 0xD4, 0x95, 0xD6, 0x95, 0x35, 0x95, 0x97, 0x55, 0x34, 0x55, 0x36, 0x55, 0xB5, 0x55, 0x57, 0xD5, 0xB4, 0xD5, 0xB6, 0xD5, 0x75, 0xD5, 0xD7, 0x35, 0x74, 0x80, 0x2B, 0xBF, 0xBE, 0xE6, 0xB6, 0x96, 0x01, 0x60, 0x00, 0x8D, 0xB5, 0x77, 0x75, 0x4C, 0x75, 0x4E, 0x75, 0xCD, 0x75, 0x0F, 0xF5, 0x2C, 0xF5, 0xAE, 0xF5, 0xAD, 0xF5, 0xCF, 0x0D, 0xEC, 0x0D, 0xEE, 0x0D, 0x1D, 0x0D, 0xAF, 0x8D, 0x9C, 0x8D, 0x5E, 0x8D, 0xDD, 0x8D, 0xEF, 0x4D, 0xBC, 0x80, 0x3B, 0xBF, 0xAF, 0xE9, 0xAB, 0x59, 0xA0, 0x39, 0xB0, 0x79, 0xB0, 0x05, 0xB8, 0x45, 0xA4, 0x25, 0xB4, 0x65, 0xB4, 0x15, 0xBC, 0x55, 0xA2, 0x35, 0xB2, 0x75, 0xB2, 0x0D, 0xBA, 0x4D, 0xA6, 0x2D, 0xB6, 0x6D, 0xB6, 0x1D, 0xBE, 0x5D, 0xB1, 0x3D, 0xA9, 0x7D, 0xB1, 0x03, 0xA5, 0x43, 0xB5, 0x23, 0xAD, 0x63, 0xAD, 0x13, 0xB3, 0x53, 0xAB, 0x33, 0xA7, 0x73, 0xBB, 0x0B, 0xAF, 0xCB, 0xA0, 0xAB, 0xB0, 0xEB, 0xA0, 0x9B, 0xA4, 0xDB, 0xB4, 0xBB, 0xBC, 0xFB, 0xB4, 0x87, 0xAA, 0xC7, 0xBA, 0xA7, 0xB6, 0xE7, 0xBA, 0x97, 0xA1, 0xD7, 0xB1, 0xB7, 0xB9, 0xF7, 0x11, 0xC0, 0x7D, 0x8F, 0xBE, 0xCE, 0xBE, 0xB7, 0x5F, 0xBC, 0xBF, 0xFC, 0x7E, 0xF5, 0xF7, 0x03, 0xF5, 0x8B, 0xF4, 0x87, 0xF6, 0x8F, 0x0D, 0x40, 0x0E, 0x48, 0x0F, 0xC4, 0x0E, 0xCC, 0x0D, 0x22, 0x0E, 0x2A, 0x0D, 0xA6, 0x0C, 0xAE, 0x0C, 0x61, 0x0C, 0x69, 0x01, 0x98, 0xBF, 0x33, 0x4C, 0x30, 0x6C, 0x38, 0x5C, 0x3C, 0xFC, 0x07, 0x70, 0xF1, 0x5B, 0x8E, 0x54, 0x8F, 0x5C, 0x8E, 0xD2, 0x8D, 0x3A, 0x8C, 0x36, 0x8D, 0x3E, 0x8E, 0xB1, 0x8E, 0xB9, 0x8F, 0x75, 0x8E, 0xBD, 0x8D, 0xF3, 0x8E, 0xFB, 0x8D, 0xF7, 0x4F, 0x00, 0x4D, 0x88, 0x4C, 0x84, 0x4E, 0x8C, 0x4D, 0x42, 0x4E, 0x4A, 0x4F, 0xC6, 0x4C, 0xCE, 0x4E, 0x21, 0x4C, 0x29, 0x4E, 0x25, 0x4F, 0x2D, 0x4F, 0xA3, 0x4F, 0x6B, 0x4C, 0x67, 0x4D, 0x6F, 0xCD, 0xE0, 0xCE, 0xE8, 0xCF, 0x14, 0xCE, 0x1C, 0xCC, 0x92, 0xCC, 0x9A, 0xCD, 0x96, 0xCF, 0x9E, 0xCD, 0x51, 0xCD, 0xD9, 0xCC, 0xD5, 0xCD, 0xDD, 0xCC, 0x33, 0xCE, 0x3B, 0x01, 0xEE, 0xFE, 0x27, 0x00, 0xEB, 0x3D, 0x7F, 0x77, 0xFD, 0x7E, 0x5F, 0xE0, 0x5D, 0xF0, 0x5B, 0xE8, 0x5F, 0xF8, 0x59, 0x14, 0x5E, 0x0C, 0x59, 0x1C, 0x5D, 0x02, 0x5F, 0x92, 0x58, 0x8A, 0x5A, 0x9A, 0x5A, 0x86, 0x5D, 0x96, 0x5B, 0x8E, 0x07, 0x5C, 0xFE, 0x48, 0x2B, 0xCA, 0x2B, 0xA9, 0x2B, 0x2B, 0xAB, 0xE8, 0xAB, 0x1A, 0x00, 0xD2, 0x6F, 0xAE, 0xE1, 0xAC, 0xE9, 0xAE, 0xE5, 0xAD, 0xED, 0xAE, 0x13, 0xAE, 0x1B, 0xAD, 0x17, 0xAF, 0x1F, 0x6D, 0x90, 0x6E, 0x98, 0x6D, 0x94, 0x6D, 0x9C, 0x6C, 0x52, 0x6C, 0x5A, 0x6E, 0x56, 0x6D, 0x9E, 0x6F, 0x51, 0x6F, 0xD9, 0x6C, 0xD5, 0x6C, 0x5D, 0x6D, 0xD3, 0x6D, 0xDB, 0x6D, 0xD7, 0x6F, 0xDF, 0xEC, 0x30, 0xEC, 0x38, 0xEC, 0x34, 0xEC, 0xDC, 0xED, 0x32, 0xEE, 0x3A, 0xEE, 0x36, 0xEE, 0xDE, 0xED, 0x31, 0xEE, 0x39, 0xEE, 0x35, 0xEE, 0xDD, 0xED, 0x33, 0xEE, 0x3B, 0x02, 0x48, 0x7F, 0x77, 0xC0, 0x78, 0xE0, 0x70, 0xD0, 0x70, 0x70, 0x7B, 0x48, 0x7F, 0x68, 0x7F, 0x58, 0x7F, 0x78, 0x7D, 0x44, 0x77, 0x64, 0x7B, 0x54, 0x7B, 0x74, 0xF9, 0x87, 0xE6, 0x8F, 0xF5, 0x9F, 0xAA, 0x3F, 0xE7, 0xC7, 0x94, 0xC7, 0x16, 0xC7, 0x15, 0xC7, 0x27, 0x27, 0x64, 0x27, 0xA6, 0x27, 0xA5, 0x27, 0x47, 0xA7, 0xC4, 0xA7, 0x46, 0xA7, 0x85, 0xA7, 0x7B, 0x67, 0xF8, 0x67, 0x7A, 0x67, 0xB9, 0x67, 0x5B, 0xE7, 0xD8, 0xE7, 0x5A, 0xE7, 0x99, 0xE7, 0x6B, 0x17, 0xE8, 0x17, 0x6A, 0x17, 0xA9, 0x17, 0x4B, 0x97, 0x48, 0x97, 0x8A, 0x97, 0x09, 0x97, 0x73, 0x57, 0xB0, 0x57, 0x32, 0x57, 0xD1, 0x57, 0x13, 0xD7, 0x10, 0xD7, 0x62, 0xD7, 0xA1, 0xD7, 0xC3, 0x37, 0x40, 0x37, 0x02, 0x37, 0xFE, 0x37, 0xBD, 0x37, 0xEF, 0xB7, 0x5C, 0xB7, 0x1E, 0xB7, 0xED, 0xB7, 0x4F, 0x77, 0xCC, 0x77, 0x4E, 0x77, 0x0D, 0x77, 0xD7, 0xF7, 0x34, 0xF7, 0x56, 0xF7, 0x15, 0xF7, 0x27, 0x0F, 0xA4, 0x00, 0xE2, 0x17, 0x3E, 0xEC, 0x3E, 0xE2, 0x3E, 0x6A, 0x3F, 0x66, 0x3E, 0xAE, 0x3E, 0xA1, 0x3C, 0x29, 0x3D, 0x25, 0x3C, 0xCD, 0x3E, 0xC3, 0x3C, 0x4B, 0x3D, 0x87, 0x3F, 0x8F, 0xFC, 0x05, 0xFE, 0x2B, 0xF8, 0xD7, 0xEF, 0x6F, 0xCF, 0xDF, 0xD7, 0x17, 0xF6, 0x17, 0xD7, 0x97, 0xA6, 0x97, 0xDB, 0x57, 0xDA, 0x57, 0xEB, 0xD7, 0x8A, 0xD7, 0xE3, 0x7F, 0xC4, 0xFF, 0x0C, 0xFE, 0xE5, 0xFD, 0xDB, 0x7C, 0xC3, 0x7C, 0x53, 0x7B, 0x4B, 0x7E, 0x9B, 0x7F, 0x87, 0x7B, 0x97, 0x7E, 0x8F, 0x78, 0x1F, 0xF9, 0x00, 0xFA, 0xE0, 0xFF, 0xF0, 0xF9, 0xE8, 0xFA, 0xF8, 0xFB, 0xC9, 0xF2, 0xE9, 0xF8, 0x59, 0xF7, 0x79, 0xF1, 0x45, 0xF1, 0x65, 0xF2, 0x55, 0xF8, 0xB5, 0xF3, 0x8D, 0xFD, 0xAD, 0xF1, 0x9D, 0xFA, 0xFD, 0xFB, 0x07, 0xEE, 0x47, 0xFA, 0x27, 0xE2, 0x67, 0xF8, 0x7F, 0xF8, 0x6F, 0x6F, 0xE1, 0xC6, 0x02, 0x04, 0x78, 0xA0, 0x60, 0xC8, 0x40, 0x40, 0xC0, 0x40, 0xFF, 0x87, 0xF7, 0x7F, 0xF7, 0x0F, 0x06, 0xF8, 0x00, 0x4F, 0x08, 0x28, 0x18, 0x68, 0x08, 0x18, 0x18, 0x58, 0x04, 0x38, 0x04, 0x78, 0x18, 0x04, 0x04, 0x44, 0x14, 0x24, 0x14, 0x64, 0x04, 0x14, 0x0C, 0x54, 0x0C, 0x34, 0x0C, 0x74, 0x0C, 0x0C, 0x1C, 0x4C, 0x1C, 0x2C, 0x02, 0x6C, 0x1C, 0x1C, 0x02, 0x5C, 0x12, 0x3C, 0x12, 0x7C, 0x02, 0x02, 0x12, 0x42, 0x0A, 0x22, 0x0A, 0x62, 0x12, 0x12, 0x1A, 0x52, 0x1A, 0x32, 0x1A, 0x72, 0x1A, 0x0A, 0x06, 0x4A, 0x06, 0x2A, 0x16, 0x6A, 0x06, 0x1A, 0x16, 0x5A, 0x0E, 0x3A, 0x0E, 0x7A, 0x16, 0x06, 0x0E, 0x46, 0x1E, 0x26, 0x1E, 0xD0, 0x0D, 0x10, 0x60, 0x15, 0x60, 0x13, 0x60, 0x7F, 0xC3, 0x21, 0xC2, 0x29, 0xC2, 0x25, 0xC1, 0x2D, 0xC0, 0x23, 0xC1, 0x2B, 0xC3, 0x27, 0x03, 0xB6, 0x02, 0x64, 0x04, 0x15, 0x84, 0x14, 0x84, 0x25, 0x44, 0x54, 0x44, 0x55, 0xC4, 0x54, 0xC4, 0x15, 0x24, 0x34, 0x24, 0x35, 0x80, 0x3B, 0xAC, 0x22, 0xA3, 0x23, 0x6B, 0x00, 0x96, 0x82, 0x35, 0x14, 0x0C, 0x14, 0x4D, 0x94, 0x4C, 0x94, 0x75, 0x54, 0x2C, 0x54, 0x2D, 0xD4, 0x2C, 0xD4, 0x4D, 0x34, 0x6C, 0x34, 0x6D, 0xB4, 0x1C, 0xB4, 0x2D, 0x74, 0x1C, 0x74, 0x5D, 0xF4, 0x5C, 0xF4, 0x6D, 0xC0, 0x4E, 0xA0, 0x07, 0x28, 0x07, 0x3B, 0x00, 0x7B, 0xD0, 0xC7, 0xCC, 0xC7, 0xDC, 0xC3, 0x22, 0xC0, 0x32, 0xC0, 0x2A, 0xC4, 0xDA, 0xC7, 0x26, 0xC4, 0x36, 0xC4, 0x2E, 0xC2, 0x3E, 0xC0, 0x21, 0xC2, 0x31, 0xC6, 0x29, 0xC6, 0x39, 0xC4, 0x25, 0xC1, 0x35, 0xC1, 0x2D, 0xC1, 0xFD, 0x83, 0x47, 0x8A, 0x67, 0x8A, 0x57, 0x86, 0x77, 0x8C, 0x4F, 0x86, 0x6F, 0x86, 0x5F, 0x8E, 0x7F, 0x42, 0x40, 0x4E, 0x60, 0x41, 0x50, 0x01, 0xF0, 0x07, 0x4A, 0x42, 0x4B, 0xC2, 0x4A, 0xC2, 0x73, 0x22, 0x2A, 0x22, 0x2B, 0xA2, 0x6A, 0xA2, 0x0B, 0x62, 0x6A, 0x62, 0x6B, 0xE2, 0x1A, 0xE2, 0x4B, 0x12, 0x1A, 0x12, 0x5B, 0x92, 0x5A, 0x92, 0x2B, 0x52, 0x3A, 0x52, 0x3B, 0xD2, 0x3A, 0xD2, 0x1B, 0x32, 0x7A, 0x32, 0x7B, 0xB2, 0x06, 0xB2, 0x5B, 0x72, 0x86, 0xFF, 0xDA, 0xC1, 0x1D, 0x05, 0x23, 0x85, 0x13, 0x45, 0x13, 0xC5, 0x3D, 0x25, 0x33, 0xA5, 0x33, 0x65, 0x33, 0xE5, 0x23, 0x15, 0x0B, 0x95, 0x0B, 0x55, 0x2B, 0xD5, 0x13, 0x35, 0x2B, 0xB5, 0x2B, 0x75, 0x1B, 0xF5, 0x33, 0x0D, 0x1B, 0x8D, 0x3B, 0x4D, 0x3B, 0xCD, 0x5F, 0x5A, 0x0E, 0x5A, 0x0F, 0xDA, 0x0E, 0xDA, 0x57, 0x3A, 0x4E, 0x3A, 0x4F, 0xBA, 0x2E, 0xBA, 0x7F, 0xF4, 0x5C, 0xF4, 0x5E, 0xF4, 0xDD, 0xF4, 0x6F, 0x0C, 0xDC, 0x0C, 0x3E, 0x0C, 0x3D, 0x0C, 0xEF, 0x8C, 0xBC, 0x8C, 0xBE, 0x8C, 0xBD, 0x8C, 0x9F, 0x4C, 0x7C, 0x4C, 0x7E, 0x4C, 0x7D, 0x4C, 0x5F, 0xCC, 0xFC, 0xCC, 0xFE, 0xCC, 0xFD, 0xCC, 0xDF, 0x2C, 0x02, 0x2C, 0x81, 0x2C, 0x03, 0x2C, 0x3F, 0xAC, 0x42, 0xAC, 0x41, 0xAC, 0x83, 0x6C, 0xC0, 0x6C, 0xC2, 0x6C, 0xC1, 0x6C, 0x43, 0xEC, 0x20, 0x80, 0x95, 0x20, 0x84, 0x7D, 0x84, 0x03, 0x94, 0x43, 0x94, 0x23, 0x8C, 0x63, 0x94, 0x13, 0x8C, 0x53, 0x9C, 0x33, 0x9C, 0x73, 0x8C, 0x0B, 0x82, 0x4B, 0x82, 0x2B, 0x82, 0x6B, 0x9C, 0x1B, 0x92, 0x5B, 0x92, 0x3B, 0x92, 0x7B, 0x92, 0x07, 0x8A, 0x47, 0x8A, 0x27, 0x9A, 0x67, 0x0A, 0xE0, 0x10, 0x32, 0xFF, 0x39, 0x04, 0xEC, 0x7F, 0x0E, 0x31, 0xF3, 0x9F, 0x43, 0xC4, 0xFD, 0x1F, 0x1C, 0x42, 0xF1, 0x3F, 0x87, 0x40, 0x12, 0x52, 0x12, 0x4A, 0x12, 0x5A, 0x10, 0x46, 0x16, 0x56, 0x16, 0x4E, 0x16, 0x5E, 0x12, 0x41, 0x11, 0x51, 0x11, 0x49, 0x15, 0x59, 0x16, 0x45, 0x15, 0x55, 0x13, 0x4D, 0x13, 0x5D, 0x11, 0x43, 0x17, 0x53, 0x17, 0x4B, 0x17, 0x5B, 0x15, 0xC7, 0x10, 0xD7, 0x10, 0xCF, 0x10, 0x5F, 0x97, 0xC0, 0x94, 0xD0, 0x94, 0xC8, 0x92, 0xD8, 0x90, 0xC4, 0x92, 0xD4, 0x96, 0xCC, 0x96, 0xDC, 0x94, 0xC2, 0x06, 0xAC, 0x05, 0x39, 0x52, 0x5B, 0xD2, 0xB8, 0xD2, 0xBA, 0xD2, 0xB9, 0xD2, 0x3B, 0x32, 0x78, 0x32, 0x7A, 0x32, 0xF9, 0x32, 0xBB, 0xB2, 0xF8, 0xB2, 0x06, 0xB2, 0x05, 0xB2, 0x7B, 0x72, 0x04, 0x72, 0x86, 0x72, 0x85, 0x72, 0xFB, 0xF2, 0x44, 0xF2, 0x46, 0xF2, 0x45, 0xF2, 0x87, 0x0A, 0xC4, 0x0A, 0xC6, 0x0A, 0x25, 0x0A, 0x47, 0x8A, 0x24, 0x8A, 0xA6, 0x8A, 0xA5, 0x80, 0xBD, 0x80, 0x54, 0xC9, 0x4C, 0xA9, 0x4C, 0xE9, 0x58, 0x99, 0x5C, 0xD9, 0x5C, 0xB9, 0x5C, 0xF9, 0x54, 0x85, 0x42, 0xC5, 0x42, 0xA5, 0x52, 0xE5, 0x4C, 0x95, 0x52, 0xD5, 0x4A, 0xB5, 0x4A, 0xF5, 0x5C, 0x8D, 0x4A, 0xCD, 0x5A, 0xAD, 0x5A, 0xED, 0x42, 0x9D, 0x46, 0xDD, 0x46, 0xBD, 0x46, 0xFD, 0x4A, 0x83, 0x56, 0xC3, 0x56, 0xA3, 0x4E, 0xE3, 0x5A, 0x93, 0x4E, 0xD3, 0x1E, 0x60, 0x0F, 0x37, 0x5A, 0xF4, 0x5A, 0x0E, 0x5A, 0x0D, 0x5A, 0xB7, 0xDA, 0x8C, 0xDA, 0x8E, 0xDA, 0x8D, 0xDA, 0xF7, 0x3A, 0x4C, 0x3A, 0x4E, 0x3A, 0xCD, 0x3A, 0x0F, 0xBA, 0xCC, 0xBA, 0x2E, 0xBA, 0x2D, 0xBA, 0x8F, 0x7A, 0x2C, 0x7A, 0xAE, 0x80, 0x6E, 0xF0, 0xA4, 0xCF, 0xA6, 0xEF, 0xA6, 0xDF, 0xA6, 0xFF, 0xD7, 0x80, 0xDD, 0xC0, 0xDD, 0xA0, 0xC3, 0xE0, 0xC5, 0x90, 0xC3, 0xD0, 0xC3, 0xB0, 0xD3, 0xF0, 0xD5, 0x88, 0xD3, 0xC8, 0xCB, 0xA8, 0xCB, 0xE8, 0x9F, 0x31, 0xB7, 0xB1, 0xB7, 0x71, 0xB7, 0xF1, 0xBB, 0x09, 0x8F, 0x89, 0x8F, 0x49, 0x2F, 0x60, 0x2F, 0xE0, 0x35, 0xF5, 0x35, 0xED, 0x33, 0xFD, 0x34, 0xE3, 0x33, 0xF3, 0x07, 0x54, 0x83, 0x2F, 0x73, 0x01, 0xF3, 0x00, 0xF3, 0x7E, 0xF3, 0x1F, 0x0B, 0x41, 0x8B, 0x40, 0x8B, 0x41, 0x4B, 0x20, 0x4B, 0x21, 0xCB, 0x20, 0xCB, 0x21, 0x2B, 0x60, 0x2B, 0x61, 0xAB, 0x10, 0xAB, 0x61, 0x6B, 0x10, 0x6B, 0x51, 0xEB, 0x50, 0xEB, 0x11, 0x1B, 0x30, 0x1B, 0x31, 0x9B, 0x30, 0x9B, 0x31, 0x5B, 0x70, 0x5B, 0x71, 0xDB, 0x70, 0xDB, 0x71, 0x3B, 0x08, 0x40, 0x33, 0x88, 0xB4, 0x9B, 0xB0, 0x87, 0xB4, 0x97, 0xB2, 0x8F, 0xB2, 0x9F, 0x74, 0x80, 0x76, 0x90, 0x76, 0x88, 0x76, 0x98, 0x76, 0x84, 0x71, 0x94, 0x71, 0x8C, 0x71, 0x9C, 0x71, 0x82, 0x75, 0x92, 0x75, 0x8A, 0x73, 0x9A, 0x75, 0x86, 0x73, 0x96, 0x77, 0x8E, 0x77, 0x9E, 0x73, 0x41, 0x70, 0x51, 0x70, 0x49, 0x70, 0xF9, 0xED, 0x8A, 0xE8, 0xAA, 0xE8, 0x9A, 0xE8, 0xBA, 0xE0, 0x86, 0xE4, 0xA6, 0xE4, 0x96, 0xEC, 0xB6, 0xE8, 0x8E, 0xEC, 0xAE, 0xE2, 0x9E, 0xE2, 0xBE, 0xE4, 0x81, 0xEA, 0xA1, 0xFA, 0x5F, 0x31, 0x40, 0xF3, 0x54, 0xF3, 0x4C, 0xF3, 0x5C, 0xF5, 0x42, 0xF7, 0x52, 0xF7, 0xCA, 0xF0, 0x5A, 0xF3, 0xC6, 0xF0, 0xD6, 0xF4, 0xCE, 0xF4, 0x5E, 0xF7, 0xC1, 0xF2, 0xD1, 0xF2, 0xC9, 0xF2, 0xD9, 0xF0, 0xC5, 0xF6, 0xD5, 0xF6, 0xCD, 0xF6, 0xDD, 0xF2, 0xC3, 0xF1, 0xD3, 0xF1, 0xCB, 0xF5, 0xDB, 0xF6, 0xC7, 0xF5, 0xD7, 0xF3, 0xCF, 0xF3, 0xDF, 0x09, 0xC0, 0x0F, 0xD0, 0x0F, 0xC8, 0x0F, 0xD8, 0x0D, 0x24, 0x08, 0x34, 0xF8, 0xAF, 0x18, 0xFC, 0x8F, 0x31, 0x14, 0x05, 0x1D, 0x04, 0x13, 0x05, 0x1B, 0x07, 0x17, 0x07, 0x1F, 0x86, 0x90, 0x84, 0x98, 0x84, 0x94, 0x84, 0x1C, 0x85, 0x92, 0x86, 0x9A, 0x86, 0x96, 0x86, 0x1E, 0x87, 0x91, 0x85, 0x99, 0x85, 0x95, 0x87, 0x9D, 0x84, 0x93, 0x87, 0x5B, 0x84, 0x57, 0x84, 0x9F, 0x46, 0x50, 0x46, 0x58, 0x46, 0x54, 0x46, 0x9C, 0x45, 0x52, 0x45, 0x5A, 0x45, 0x56, 0x45, 0x5E, 0x44, 0x51, 0x47, 0x59, 0x47, 0xD5, 0x44, 0x5D, 0x46, 0xD3, 0x44, 0xDB, 0x46, 0xD7, 0x46, 0x5F, 0xC5, 0xD0, 0xC5, 0xD8, 0xC5, 0xD4, 0xC5, 0x5C, 0xC7, 0xD2, 0xC7, 0xDA, 0xC7, 0xD6, 0xC7, 0xDE, 0xC6, 0x31, 0xC4, 0x39, 0xC4, 0x35, 0x02, 0x9A, 0x01, 0x23, 0x60, 0x19, 0x68, 0x8A, 0xBF, 0x4F, 0x60, 0x4A, 0x70, 0x4E, 0x68, 0x4E, 0x78, 0x48, 0x64, 0x49, 0x74, 0x49, 0x6C, 0x49, 0x7C, 0x4A, 0x62, 0x4D, 0x72, 0x4D, 0x6A, 0x4B, 0x7A, 0x4E, 0x66, 0x4B, 0x76, 0x4F, 0x6E, 0x4F, 0xFE, 0x9B, 0xC2, 0x9E, 0xE2, 0x91, 0xD2, 0x91, 0xF2, 0x92, 0xCA, 0x99, 0xEA, 0x99, 0xDA, 0x99, 0xFA, 0x2F, 0x8D, 0x2B, 0xCD, 0x2B, 0xAD, 0x3B, 0xED, 0x2D, 0x9D, 0x3B, 0xDD, 0x27, 0xBD, 0x27, 0xFD, 0x3D, 0x83, 0x27, 0xC3, 0x37, 0xA3, 0x37, 0xE3, 0x23, 0x93, 0x2F, 0xD3, 0x2F, 0xB3, 0x2F, 0xF3, 0x2B, 0x8B, 0x3F, 0xCB, 0x3F, 0xAB, 0x3F, 0xEB, 0x3B, 0x5B, 0x20, 0x3B, 0x30, 0x7B, 0x00, 0x50, 0x0D, 0x04, 0x73, 0x82, 0x72, 0x06, 0x73, 0x81, 0x72, 0x85, 0x73, 0x83, 0x73, 0x87, 0xF2, 0x40, 0xF2, 0x44, 0xF2, 0x42, 0xF2, 0x46, 0xF2, 0x41, 0xF3, 0x45, 0xF3, 0xC3, 0xF2, 0x47, 0x0B, 0xC0, 0x0A, 0xC4, 0xFE, 0xFF, 0xD5, 0x40, 0xA2, 0x30, 0xA2, 0x70, 0xBC, 0x08, 0xB2, 0x48, 0xB2, 0x28, 0xB2, 0x68, 0xB2, 0x18, 0xAA, 0x58, 0xAA, 0x38, 0xBA, 0x78, 0xAA, 0x04, 0xBA, 0x44, 0xBA, 0x24, 0xA6, 0x64, 0xBA, 0x14, 0xA6, 0x54, 0xB6, 0x34, 0xB6, 0x74, 0xA6, 0x0C, 0xAE, 0x4C, 0xAE, 0x2C, 0xAE, 0x6C, 0xAE, 0x1C, 0xBE, 0x5C, 0xBE, 0x3C, 0xBE, 0x7C, 0xBE, 0x02, 0xA1, 0x42, 0xA1, 0x22, 0xB1, 0xE2, 0x37, 0x60, 0x15, 0x50, 0xAA, 0x4C, 0xAA, 0x5C, 0xA8, 0x42, 0x06, 0x34, 0x83, 0xE4, 0xAA, 0xA5, 0x6A, 0x94, 0x6A, 0x95, 0xEA, 0x94, 0xEA, 0xE5, 0x1A, 0xD4, 0x1A, 0xD5, 0x9A, 0xB4, 0x9A, 0x95, 0x5A, 0xB4, 0x5A, 0xF5, 0xDA, 0xF4, 0xDA, 0xD5, 0x3A, 0x8C, 0x3A, 0x8D, 0xBA, 0x8C, 0xBA, 0xF5, 0x7A, 0xCC, 0x7A, 0xCD, 0xFA, 0xCC, 0xFA, 0x8D, 0x06, 0xAC, 0x06, 0xAD, 0x86, 0xEC, 0x86, 0xCD, 0x46, 0xEC, 0x46, 0x9D, 0xC6, 0x9C, 0xC6, 0xAD, 0x26, 0xDC, 0x26, 0xDD, 0xA6, 0xDC, 0xA6, 0x9D, 0x66, 0xBC, 0x66, 0x3D, 0x40, 0x2F, 0xD8, 0x6D, 0xC1, 0x6F, 0xD1, 0x07, 0x2C, 0x03, 0x7B, 0xAD, 0x04, 0xAD, 0x86, 0xAD, 0x85, 0xAD, 0xFB, 0x6D, 0x44, 0x6D, 0x46, 0x6D, 0x45, 0x6D, 0x87, 0xED, 0xC4, 0xED, 0xC6, 0xED, 0xC5, 0xED, 0x47, 0x1D, 0x24, 0x1D, 0x26, 0x1D, 0xA5, 0x1D, 0x7F, 0x3A, 0x49, 0x3B, 0xCD, 0x3A, 0xCB, 0x3A, 0x8F, 0xBB, 0xC8, 0xBB, 0xCC, 0xBB, 0xCA, 0xBB, 0x4E, 0x01, 0xAD, 0xC0, 0xA2, 0xBB, 0xA2, 0xFB, 0xAC, 0x87, 0xB2, 0xC7, 0xB2, 0xA7, 0xAA, 0xE7, 0xBC, 0x97, 0xAA, 0xD7, 0xBA, 0xB7, 0xBA, 0xF7, 0x02, 0xB0, 0x0F, 0xD8, 0xF4, 0xD5, 0xF4, 0x5D, 0xFE, 0xA2, 0xFD, 0x65, 0xFB, 0xAB, 0xF6, 0xD7, 0x75, 0x3F, 0x5D, 0xBF, 0x5D, 0x7F, 0x7D, 0xFF, 0xCD, 0x00, 0xFD, 0x80, 0xC3, 0x40, 0xC3, 0xC0, 0xED, 0x20, 0xE3, 0xA0, 0xE3, 0x60, 0xE3, 0xE0, 0xDD, 0x10, 0xD3, 0x90, 0xD3, 0x50, 0xD3, 0xD0, 0xC3, 0x30, 0xF3, 0xB0, 0xF3, 0x70, 0xCB, 0xF0, 0xE3, 0x08, 0xCB, 0x88, 0xEB, 0x48, 0xEB, 0xC8, 0xD3, 0x28, 0xDB, 0xA8, 0xDB, 0x68, 0xDB, 0xE8, 0xF3, 0x18, 0x3B, 0xC0, 0x19, 0xDA, 0xC7, 0x5E, 0xC6, 0x39, 0xC6, 0x3D, 0xC6, 0x3B, 0xC7, 0x5F, 0x27, 0x38, 0x27, 0xBC, 0x26, 0xBA, 0x26, 0xFE, 0x4D, 0x72, 0x4F, 0x7A, 0x4F, 0x76, 0x4F, 0xBE, 0x4D, 0xF1, 0x4C, 0xF9, 0x4C, 0xF5, 0x4C, 0x7D, 0x4C, 0xF3, 0x4E, 0xFB, 0x4E, 0xF7, 0x4D, 0x7F, 0xCE, 0xF0, 0xCD, 0xF8, 0xCF, 0xFC, 0x9A, 0xF9, 0x9A, 0x15, 0x98, 0x0D, 0x98, 0xED, 0x9F, 0xFD, 0x9E, 0x13, 0x9C, 0x0B, 0x9C, 0x1B, 0x98, 0x07, 0x9A, 0x17, 0x9A, 0x0F, 0x9A, 0x1F, 0xFA, 0x0D, 0xFC, 0x5B, 0x18, 0xB0, 0x16, 0x0C, 0x2F, 0x80, 0x2C, 0x88, 0x2E, 0x84, 0x2E, 0x8C, 0x2C, 0x82, 0x2E, 0x8A, 0x2D, 0x86, 0xFD, 0x67, 0x0D, 0xE2, 0x4B, 0xE1, 0x4B, 0xE3, 0xCB, 0x10, 0x80, 0xBD, 0x20, 0x72, 0x79, 0x62, 0x05, 0x72, 0x45, 0x72, 0x25, 0x6A, 0x65, 0x72, 0x15, 0x6A, 0x55, 0x7A, 0x35, 0x7A, 0x75, 0x6A, 0x0D, 0x66, 0x4D, 0x66, 0x2D, 0x66, 0x6D, 0x66, 0x1D, 0x76, 0x5D, 0x76, 0x3D, 0x6E, 0x7D, 0x16, 0xB0, 0x18, 0xC8, 0x6D, 0xC4, 0x6F, 0xCC, 0x6D, 0xC2, 0x6F, 0x2A, 0x6C, 0x26, 0x6C, 0xCE, 0x6F, 0x21, 0x6E, 0x29, 0x6E, 0x25, 0x6E, 0x2D, 0x6C, 0x23, 0x6D, 0x2B, 0x6D, 0x27, 0x6F, 0x2F, 0xEE, 0x20, 0xEF, 0x28, 0xEF, 0xA4, 0xEC, 0x2C, 0xED, 0xA2, 0xEC, 0xAA, 0xEE, 0xA6, 0xEE, 0x2E, 0xEF, 0xA1, 0xED, 0xA9, 0xED, 0xA5, 0xED, 0xAD, 0xEE, 0xA3, 0xEF, 0xAB, 0xEF, 0x67, 0xEC, 0xAF, 0x1D, 0x60, 0x1C, 0x68, 0x1C, 0x64, 0x1E, 0xAC, 0x1F, 0x62, 0x1E, 0x6A, 0x1D, 0x66, 0xFD, 0xFF, 0x37, 0x83, 0x6C, 0xC0, 0x66, 0x80, 0xF3, 0x47, 0xE7, 0x7F, 0xDD, 0x0C, 0xF2, 0x8E, 0x77, 0x4E, 0xF0, 0x4E, 0xF4, 0x4F, 0xF2, 0x4F, 0x76, 0x4F, 0x09, 0x4E, 0x0D, 0x00, 0x85, 0x60, 0xFF, 0x8C, 0xF0, 0xCC, 0xF0, 0xAC, 0xE8, 0xEC, 0xE0, 0x9C, 0xE8, 0xDC, 0xE8, 0xBC, 0xF8, 0xFC, 0xF0, 0x82, 0xF8, 0xC2, 0xE4, 0xA2, 0xE4, 0xE2, 0xE8, 0x92, 0xF4, 0xD2, 0xF4, 0xB2, 0xF4, 0xF2, 0xF8, 0x8A, 0xEC, 0xCA, 0xEC, 0xAA, 0xEC, 0xEA, 0xE4, 0x9A, 0xFC, 0xDA, 0xFC, 0xBA, 0xE2, 0xFA, 0xF4, 0x86, 0xE2, 0xC6, 0xF2, 0xA6, 0xF2, 0xE6, 0xEC, 0x96, 0xEA, 0xD6, 0xEA, 0xB6, 0xEA, 0xF6, 0xE2, 0x8E, 0xFA, 0xCE, 0xFA, 0xAE, 0xFA, 0xEE, 0x12, 0xE0, 0x0C, 0x36, 0xF7, 0xB5, 0xF7, 0x57, 0x0F, 0xB4, 0x0F, 0x76, 0x0F, 0x75, 0x0F, 0xD7, 0x80, 0x4A, 0x60, 0xFF, 0x58, 0xFF, 0x78, 0xFB, 0xC4, 0xF0, 0xE4, 0xF0, 0xD4, 0xF0, 0x74, 0xF7, 0xCC, 0xF8, 0xEC, 0xF8, 0xDC, 0xF4, 0x7C, 0xFF, 0x97, 0xE9, 0xAF, 0x33, 0x60, 0x2D, 0x78, 0x78, 0x61, 0x79, 0x71, 0x79, 0x69, 0x79, 0x79, 0x7A, 0x65, 0x7D, 0x75, 0x7D, 0x6D, 0x7D, 0x7D, 0xFE, 0xC7, 0xF6, 0xCF, 0xED, 0x5F, 0xFB, 0xBF, 0xBF, 0x6F, 0xEC, 0x6F, 0x1E, 0x6F, 0x1D, 0x6F, 0x2F, 0xEF, 0x9C, 0xEF, 0x9E, 0xEF, 0x9D, 0xEF, 0xFF, 0x3E, 0xB8, 0x3E, 0xBC, 0x00, 0xBE, 0xF0, 0xF6, 0xC9, 0xFD, 0xE9, 0xFD, 0xD9, 0x03, 0x68, 0x05, 0x3C, 0x5F, 0xBE, 0x5F, 0xBD, 0x5F, 0x1F, 0xDF, 0x7C, 0xDF, 0x7E, 0xDF, 0x7D, 0xDF, 0x5F, 0x3F, 0xFC, 0x3F, 0xFE, 0x3F, 0xBF, 0x7E, 0xBE, 0x7F, 0xFE, 0xFF, 0x0F, 0xC0, 0x7F, 0x41, 0xA0, 0x40, 0xA0, 0x01, 0xA0, 0x1F, 0x60, 0x41, 0xE0, 0x40, 0xE0, 0x01, 0x10, 0x20, 0x10, 0x21, 0x90, 0x20, 0x90, 0x41, 0x50, 0x20, 0x50, 0x21, 0xD0, 0x20, 0xD0, 0x41, 0x80, 0x23, 0x08, 0x81, 0x05, 0x81, 0x0D, 0x82, 0x03, 0x81, 0x0B, 0x81, 0x07, 0x81, 0x0F, 0x42, 0x00, 0x43, 0x08, 0x43, 0x04, 0x43, 0x0C, 0x41, 0x02, 0x43, 0x0A, 0x43, 0x06, 0x43, 0x0E, 0x41, 0x01, 0x43, 0x09, 0x43, 0x05, 0x43, 0x0D, 0x41, 0x03, 0x43, 0x0B, 0x43, 0x07, 0x43, 0x0F, 0xC1, 0x80, 0xC0, 0x88, 0xC0, 0x84, 0xC0, 0x0C, 0xC3, 0x82, 0xC0, 0x8A, 0xC0, 0x86, 0xC0, 0x0E, 0xC3, 0x81, 0xC0, 0x89, 0xC0, 0x85, 0xC0, 0x0D, 0xC3, 0x83, 0xC0, 0x8B, 0xC0, 0x87, 0xC0, 0x0F, 0x23, 0x80, 0x22, 0x88, 0x22, 0x84, 0x22, 0x8C, 0x00, 0xDA, 0x81, 0x28, 0x62, 0x28, 0xE2, 0x08, 0x12, 0x28, 0x92, 0x28, 0x52, 0x28, 0xD2, 0x08, 0x32, 0x28, 0xB2, 0x28, 0x72, 0x28, 0xF2, 0x08, 0x0A, 0x18, 0x8A, 0x18, 0x4A, 0x18, 0xCA, 0x28, 0x2A, 0x18, 0xAA, 0x18, 0x6A, 0x18, 0xEA, 0x28, 0x1A, 0x18, 0x9A, 0x18, 0x5A, 0x18, 0xA0, 0x1E, 0x80, 0xA1, 0x8B, 0xA1, 0x87, 0xA1, 0x8F, 0x62, 0x80, 0x63, 0x88, 0x63, 0x84, 0x63, 0x8C, 0x61, 0x82, 0x63, 0x8A, 0x63, 0x86, 0x63, 0x8E, 0x61, 0x81, 0x63, 0x89, 0x63, 0x85, 0x63, 0x8D, 0x61, 0x83, 0x63, 0x8B, 0x63, 0x87, 0x63, 0x8F, 0xE1, 0x40, 0xE0, 0x48, 0xE0, 0x44, 0xE0, 0x8C, 0xE3, 0x42, 0x00, 0xFA, 0x41, 0x04, 0xEE, 0x38, 0x1E, 0x04, 0x9E, 0x04, 0x5E, 0x04, 0xDE, 0x38, 0x3E, 0x04, 0xBE, 0x04, 0x7E, 0x04, 0x60, 0x3B, 0x80, 0x24, 0x90, 0x24, 0x88, 0x24, 0x98, 0x20, 0x84, 0x24, 0x94, 0x24, 0x8C, 0x24, 0x9C, 0x20, 0x82, 0x24, 0x92, 0x24, 0x8A, 0x24, 0x9A, 0x20, 0x86, 0x24, 0x96, 0x24, 0x8E, 0x24, 0x9E, 0x20, 0x81, 0x22, 0x91, 0x22, 0x89, 0x22, 0x99, 0x24, 0x85, 0x22, 0x95, 0x22, 0x8D, 0x22, 0x9D, 0x24, 0x83, 0x22, 0x93, 0x22, 0x8B, 0x22, 0x9B, 0x24, 0x87, 0x22, 0x97, 0x22, 0x8F, 0x22, 0x9F, 0xA4, 0x80, 0xA6, 0x90, 0xA6, 0x88, 0xA6, 0x98, 0xA2, 0x84, 0xA6, 0x94, 0xA6, 0x8C, 0xA6, 0x9C, 0xA2, 0x82, 0xA6, 0x92, 0xA6, 0x8A, 0xA6, 0x9A, 0xA2, 0x86, 0xA6, 0x96, 0xA6, 0x8E, 0xA6, 0x9E, 0xA2, 0x81, 0xA1, 0x91, 0xA1, 0x89, 0x01, 0xAC, 0x07, 0x30, 0xB4, 0x32, 0xB4, 0x31, 0xB4, 0xD3, 0x80, 0x86, 0x20, 0x43, 0x17, 0x43, 0x37, 0x4D, 0x0F, 0x43, 0x2F, 0x43, 0x1F, 0x43, 0x3F, 0xCD, 0x00, 0xCB, 0x20, 0xCB, 0x10, 0xCB, 0x30, 0xC3, 0x08, 0xCB, 0x28, 0xCB, 0x18, 0xCB, 0x38, 0xC3, 0x04, 0xCB, 0x24, 0xCB, 0x14, 0xCB, 0x34, 0xC3, 0x0C, 0xCB, 0x2C, 0xCB, 0x1C, 0xCB, 0x3C, 0xC3, 0x02, 0xC7, 0x22, 0xC7, 0x12, 0xC7, 0x32, 0xCB, 0x0A, 0xC7, 0x2A, 0xC7, 0x1A, 0xC7, 0x3A, 0xCB, 0x06, 0xC7, 0x26, 0xC7, 0x16, 0xC7, 0x36, 0xCB, 0x0E, 0xC7, 0x2E, 0xC7, 0x1E, 0xC7, 0x3E, 0xCB, 0x01, 0xCF, 0x21, 0xCF, 0x11, 0xCF, 0x31, 0xC7, 0x09, 0xCF, 0x29, 0xCF, 0x19, 0xCF, 0x39, 0xC7, 0x05, 0xCF, 0x25, 0xCF, 0x15, 0xCF, 0x35, 0xC7, 0x0D, 0xCF, 0x2D, 0xCF, 0x1D, 0xCF, 0x3D, 0xC7, 0x83, 0xC0, 0xA3, 0xC0, 0x93, 0xC0, 0x33, 0xCF, 0x8B, 0xC0, 0xAB, 0xC0, 0x9B, 0xC0, 0x3B, 0xCF, 0x87, 0xC0, 0xA7, 0xC0, 0x97, 0xC0, 0x37, 0xCF, 0x8F, 0xC0, 0xAF, 0xC0, 0x9F, 0xC0, 0x3F, 0x2F, 0x80, 0x28, 0xA0, 0x28, 0x90, 0x28, 0xF0, 0x5B, 0x10, 0x51, 0x50, 0xF1, 0xFF, 0xB6, 0x22, 0x20, 0x89, 0x28, 0x89, 0x24, 0x89, 0x2C, 0x88, 0x22, 0x89, 0x2A, 0x89, 0x26, 0x89, 0x2E, 0x88, 0x21, 0x89, 0x29, 0x89, 0x25, 0x89, 0x2D, 0x88, 0x23, 0x89, 0x2B, 0x89, 0x27, 0x89, 0x2F, 0x48, 0x20, 0x4B, 0x28, 0x4B, 0x24, 0x4B, 0x2C, 0x4A, 0x22, 0x4B, 0x2A, 0x4B, 0x26, 0x4B, 0x2E, 0x4A, 0x21, 0x4B, 0x29, 0x4B, 0x25, 0x4B, 0x2D, 0x4A, 0x23, 0x4B, 0x2B, 0x4B, 0x27, 0x4B, 0x2F, 0xCA, 0xA0, 0x00, 0xD6, 0x83, 0x14, 0x99, 0x25, 0x59, 0x14, 0x59, 0x15, 0xD9, 0x14, 0xD9, 0x25, 0x39, 0x14, 0x39, 0x15, 0xB9, 0x14, 0xB9, 0x25, 0x79, 0x14, 0x79, 0x15, 0xF9, 0x14, 0xF9, 0x25, 0x05, 0x54, 0x05, 0x55, 0x85, 0x54, 0x85, 0x65, 0x45, 0x54, 0x40, 0x43, 0x48, 0x55, 0x5C, 0x56, 0x42, 0x55, 0x52, 0x55, 0x4A, 0x55, 0x5A, 0x56, 0x46, 0x55, 0x56, 0x55, 0x4E, 0x55, 0x5E, 0x56, 0x41, 0x53, 0x51, 0x53, 0x49, 0x53, 0x59, 0x51, 0x45, 0x53, 0x55, 0x53, 0x4D, 0x53, 0x5D, 0x51, 0x43, 0x53, 0x53, 0x53, 0x4B, 0x03, 0x14, 0x04, 0x34, 0x75, 0x35, 0xF5, 0x34, 0xF5, 0x15, 0x0D, 0x74, 0x0D, 0x75, 0x8D, 0x74, 0xC0, 0x76, 0x80, 0xAE, 0xA9, 0xAE, 0x99, 0xAE, 0xB9, 0xAA, 0x85, 0xAE, 0xA5, 0xAE, 0x95, 0xAE, 0xB5, 0xAA, 0x8D, 0xAE, 0xAD, 0xAE, 0x9D, 0xAE, 0xBD, 0xAA, 0x83, 0xA1, 0xA3, 0xA1, 0x93, 0xA1, 0xB3, 0xA6, 0x8B, 0xA1, 0xAB, 0xA1, 0x9B, 0xA1, 0xBB, 0xA6, 0x87, 0xA1, 0xA7, 0xA1, 0x97, 0xA1, 0xB7, 0xA6, 0x8F, 0xA1, 0xAF, 0xA1, 0x9F, 0xA1, 0xBF, 0x66, 0x80, 0x69, 0xA0, 0x69, 0x90, 0x69, 0xB0, 0x6E, 0x88, 0x69, 0xA8, 0x69, 0x98, 0x69, 0xB8, 0x6E, 0x84, 0x69, 0xA4, 0x69, 0x94, 0x69, 0xB4, 0x0E, 0x58, 0x0E, 0x34, 0x8D, 0x33, 0x8D, 0xD7, 0x4D, 0xB0, 0x4C, 0xB4, 0x4C, 0xB2, 0x4C, 0x36, 0x4C, 0xB1, 0x4C, 0xB5, 0x4C, 0xB3, 0x00, 0xED, 0x00, 0xCB, 0x4C, 0xCB, 0x2C, 0xCB, 0x6C, 0xC3, 0x1C, 0xCB, 0x5C, 0xCB, 0x3C, 0xCB, 0x7C, 0xC3, 0x02, 0xDB, 0x42, 0xDB, 0x22, 0xDB, 0x62, 0xD3, 0x12, 0xDB, 0x52, 0xDB, 0x32, 0xDB, 0x72, 0xD3, 0x0A, 0xDB, 0x4A, 0xDB, 0x2A, 0xDB, 0x6A, 0xD3, 0x1A, 0xDB, 0x5A, 0xDB, 0x3A, 0xDB, 0x7A, 0xD3, 0x06, 0xC7, 0x46, 0xC7, 0x26, 0xC7, 0x66, 0xCB, 0x16, 0xC7, 0x56, 0xC7, 0x36, 0xC7, 0x76, 0xCB, 0x0E, 0xC7, 0x4E, 0xC7, 0x2E, 0xC7, 0x6E, 0xCB, 0x1E, 0xC7, 0x5E, 0xC7, 0x3E, 0xC7, 0x7E, 0xCB, 0x01, 0xD7, 0x41, 0xD7, 0x21, 0xD7, 0x61, 0xDB, 0x11, 0xD7, 0x51, 0xD7, 0x31, 0xD7, 0x71, 0xDB, 0x09, 0xD7, 0x49, 0xD7, 0x29, 0xD7, 0x69, 0xDB, 0x19, 0xD7, 0x59, 0xD7, 0x39, 0xD7, 0x79, 0xDB, 0x05, 0xCF, 0x45, 0xCF, 0x25, 0xCF, 0x65, 0xC7, 0x15, 0xCF, 0x55, 0xEF, 0xBF, 0xD5, 0x00, 0xCF, 0x4D, 0xCF, 0x2D, 0xCF, 0x6D, 0xC7, 0x1D, 0xCF, 0x5D, 0xCF, 0x3D, 0xCF, 0x7D, 0xC7, 0x03, 0xDF, 0x43, 0xDF, 0x23, 0xDF, 0x63, 0xD7, 0x13, 0xDF, 0x53, 0xDF, 0x33, 0xDF, 0x73, 0xD7, 0x0B, 0xDF, 0x4B, 0xDF, 0x2B, 0xDF, 0x6B, 0xD7, 0x1B, 0xDF, 0x5B, 0xDF, 0x3B, 0xDF, 0x7B, 0xD7, 0x87, 0xC0, 0xC7, 0xC0, 0xA7, 0xC0, 0x67, 0xCF, 0x97, 0xC0, 0xD7, 0xC0, 0xB7, 0xC0, 0x77, 0xCF, 0x8F, 0xC0, 0xCF, 0xC0, 0xAF, 0xC0, 0x6F, 0xCF, 0x9F, 0xC0, 0xDF, 0xC0, 0xBF, 0xC0, 0x7F, 0x2F, 0x80, 0x30, 0xC0, 0x30, 0xA0, 0x30, 0x60, 0x3F, 0x90, 0x30, 0xD0, 0x30, 0xB0, 0xF0, 0xFF, 0xEF, 0x00, 0x85, 0x41, 0xFB, 0xC1, 0x84, 0xC1, 0x86, 0xC1, 0x85, 0xC1, 0xFB, 0x21, 0x44, 0x21, 0x46, 0x21, 0x45, 0x21, 0x07, 0xA1, 0x44, 0xA1, 0x46, 0xA1, 0x45, 0xA1, 0x07, 0x61, 0x44, 0x61, 0x46, 0x61, 0x45, 0x61, 0x07, 0xE1, 0x44, 0xE1, 0x46, 0xE1, 0x45, 0xE1, 0x07, 0x11, 0xC4, 0x11, 0xC6, 0x11, 0xC5, 0x11, 0x87, 0x91, 0xC4, 0x91, 0xC6, 0x91, 0xC5, 0x91, 0x87, 0x51, 0xC4, 0x51, 0xC6, 0x51, 0xC5, 0x51, 0x87, 0xD1, 0xC4, 0xD1, 0xC6, 0xD1, 0xC5, 0xD1, 0x87, 0x31, 0x24, 0x31, 0x26, 0x31, 0x25, 0x31, 0x47, 0x80, 0xDD, 0xC0, 0x24, 0xB6, 0x24, 0xF6, 0x28, 0x8E, 0x24, 0xCE, 0x24, 0xAE, 0x24, 0xEE, 0x28, 0x9E, 0x24, 0xDE, 0x24, 0xBE, 0x24, 0xFE, 0x28, 0x81, 0x34, 0xC1, 0x34, 0xA1, 0x34, 0xE1, 0x4F, 0x22, 0x69, 0xA2, 0x69, 0x62, 0x69, 0xE2, 0x9F, 0x24, 0xD2, 0x24, 0xD3, 0xFF, 0xAA, 0x01, 0x69, 0xB2, 0x69, 0x72, 0x69, 0xF2, 0x9F, 0x14, 0xB2, 0x14, 0xB3, 0x94, 0xB2, 0x94, 0xE3, 0x54, 0xB2, 0x54, 0xB3, 0xD4, 0xB2, 0xD4, 0xE3, 0x34, 0xB2, 0x34, 0xB3, 0xB4, 0xB2, 0xB4, 0xE3, 0x74, 0xB2, 0x74, 0xB3, 0xF4, 0xB2, 0xF4, 0xE3, 0x0C, 0xF2, 0x0C, 0xF3, 0x8C, 0xF2, 0x8C, 0x93, 0x4C, 0xF2, 0x4C, 0xF3, 0xCC, 0xF2, 0xCC, 0x93, 0x2C, 0xF2, 0x2C, 0xF3, 0xAC, 0xF2, 0xAC, 0x93, 0x6C, 0xF2, 0x6C, 0xF3, 0xEC, 0xF2, 0xEC, 0x93, 0x1C, 0x8A, 0x1C, 0x8B, 0x9C, 0x8A, 0x9C, 0xD3, 0x5C, 0x8A, 0x5C, 0x8B, 0xDC, 0x8A, 0xDC, 0xD3, 0x3C, 0x8A, 0x3C, 0x8B, 0xBC, 0x8A, 0xBC, 0xD3, 0x7C, 0x8A, 0x7C, 0x8B, 0xFC, 0x8A, 0xFC, 0xD3, 0x02, 0xCA, 0x02, 0xCB, 0x82, 0xCA, 0x82, 0xB3, 0x42, 0xCA, 0x42, 0xCB, 0xC2, 0xCA, 0xC2, 0xB3, 0x22, 0xCA, 0x22, 0xCB, 0xA2, 0xCA, 0xA2, 0xB3, 0x62, 0xCA, 0x62, 0xCB, 0xE2, 0xCA, 0xE2, 0xB3, 0xFF, 0xCF, 0x6A, 0x40, 0xFD, 0xBF, 0xAB, 0x06, 0xD5, 0x95, 0x17, 0x55, 0xD4, 0x55, 0xD6, 0x55, 0xD5, 0x55, 0x17, 0xD5, 0xD4, 0xD5, 0xD6, 0xD5, 0xD5, 0xD5, 0x17, 0x35, 0x34, 0x35, 0x36, 0x35, 0x35, 0x35, 0x97, 0xB5, 0x34, 0xB5, 0x36, 0xB5, 0x35, 0xB5, 0x97, 0x75, 0x34, 0x75, 0x36, 0x75, 0x35, 0x75, 0x97, 0xF5, 0x34, 0xF5, 0x36, 0xF5, 0x35, 0xF5, 0x97, 0x0D, 0xB4, 0x0D, 0xB6, 0x0D, 0xB5, 0x0D, 0x57, 0x8D, 0xB4, 0x8D, 0xB6, 0x8D, 0xB5, 0x8D, 0x57, 0x4D, 0xB4, 0x4D, 0xB6, 0x4D, 0xB5, 0x4D, 0x57, 0xCD, 0xB4, 0xCD, 0xB6, 0xCD, 0xB5, 0xCD, 0x57, 0x2D, 0x74, 0x2D, 0x76, 0x2D, 0x75, 0x2D, 0xD7, 0xAD, 0x74, 0xAD, 0x76, 0xAD, 0x75, 0xAD, 0xD7, 0x6D, 0x74, 0x6D, 0x76, 0x6D, 0x75, 0x6D, 0xD7, 0xED, 0x74, 0xED, 0x76, 0xED, 0x75, 0xED, 0xD7, 0x1D, 0xF4, 0x1D, 0xF6, 0x1D, 0xF5, 0x1D, 0x37, 0x9D, 0xF4, 0x9D, 0xF6, 0x9D, 0xF5, 0x9D, 0x37, 0x5D, 0xF4, 0x5D, 0xF6, 0x5D, 0xF5, 0x5D, 0x37, 0xDD, 0xF4, 0xDD, 0xF6, 0xDD, 0xF5, 0xDD, 0x37, 0x3D, 0x0C, 0x3D, 0x0E, 0x3D, 0x0D, 0x3D, 0xB7, 0x80, 0x6E, 0xE0, 0xD0, 0xDB, 0xD0, 0x7B, 0xDB, 0xC7, 0xD0, 0xE7, 0xD0, 0xD7, 0xD0, 0x77, 0xFB, 0x8B, 0xE1, 0x97, 0xC3, 0xAF, 0x86, 0x5F, 0xB7, 0xFD, 0x8C, 0xFD, 0x8E, 0xFD, 0x8D, 0xFD, 0x77, 0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8D, 0x03, 0x77, 0xFF, 0xAB, 0x05, 0x30, 0x0E, 0x39, 0x0E, 0x35, 0x0E, 0xDD, 0x0D, 0x33, 0x0D, 0x3B, 0x0D, 0x37, 0x0D, 0xDF, 0x8F, 0x30, 0x8D, 0x38, 0x8D, 0x34, 0x8D, 0xDC, 0x8F, 0x32, 0x8D, 0x3A, 0x01, 0xCA, 0xC1, 0xFD, 0x18, 0xD3, 0x98, 0xD3, 0x58, 0xD3, 0xD8, 0xFD, 0x38, 0xF3, 0xB8, 0xF3, 0x78, 0xF3, 0xF8, 0xC3, 0x04, 0xF3, 0x84, 0xF3, 0x44, 0xF3, 0xC4, 0xC3, 0x24, 0xF3, 0xA4, 0xF3, 0x64, 0xF3, 0xE4, 0x03, 0x60, 0x29, 0x70, 0x9E, 0x6A, 0x9E, 0x7A, 0x98, 0x66, 0x99, 0x76, 0x99, 0x6E, 0x99, 0x7E, 0x9C, 0x61, 0x99, 0x71, 0x99, 0x69, 0x99, 0x79, 0x9C, 0x65, 0x99, 0x75, 0x99, 0x6D, 0x99, 0x7D, 0x9C, 0x63, 0x99, 0x73, 0x99, 0x6B, 0x99, 0x7B, 0x9C, 0x67, 0x9D, 0x77, 0x9D, 0x6F, 0x05, 0xB4, 0x03, 0x56, 0xC0, 0x4E, 0xD0, 0xFA, 0xFB, 0x69, 0x81, 0x75, 0xC1, 0x75, 0xA1, 0x75, 0xE1, 0x69, 0x91, 0x75, 0xD1, 0x75, 0xB1, 0x75, 0xF1, 0x69, 0x89, 0x6D, 0xC9, 0x6D, 0xA9, 0x6D, 0xE9, 0x79, 0x99, 0x6D, 0xD9, 0x6D, 0xB9, 0x6D, 0xF9, 0x79, 0x85, 0x6D, 0xC5, 0x6D, 0xA5, 0x6D, 0xE5, 0x79, 0x95, 0x6D, 0xD5, 0x6D, 0xB5, 0x6D, 0xF5, 0x79, 0x8D, 0x7D, 0xCD, 0x7D, 0xAD, 0x7D, 0xED, 0xEF, 0x3A, 0xFB, 0xBA, 0xFB, 0x7A, 0xFB, 0xFA, 0xDF, 0x0D, 0xF6, 0x0D, 0xF7, 0x8D, 0xF6, 0x8D, 0xBF, 0x9B, 0xEC, 0x9B, 0xEE, 0x9B, 0xED, 0x9B, 0x7F, 0xB7, 0x38, 0xB6, 0x3C, 0xB6, 0x3A, 0xB6, 0x5E, 0xB6, 0x39, 0xB6, 0x3D, 0xB6, 0x3B, 0xB6, 0x5F, 0x76, 0x38, 0xFE, 0x7F, 0xEC, 0xD5, 0x85, 0x61, 0xA3, 0x50, 0x00, 0x00, 0xD0, 0xAD, 0x2E, 0x9E, 0x6E, 0xD5, 0x18, 0xD0, 0xAD, 0x8A, 0x93, 0x45, 0x82, 0xBB, 0x3B, 0xDF, 0x3F, 0x37, 0x48, 0x79, 0x4B, 0xBC, 0xCF, 0xF7, 0xE7, 0xF7, 0xB3, 0xD8, 0xFF, 0xEC, 0x6F, 0xFB, 0xD7, 0x5E, 0x9C, 0x9D, 0x73, 0x73, 0x64, 0x07, 0xB8, 0x3B, 0xF7, 0xE6, 0xCA, 0x2E, 0xF0, 0x76, 0xDE, 0xCD, 0x93, 0x3D, 0xE0, 0xEF, 0xFC, 0x9B, 0x2F, 0xFB, 0x20, 0xD8, 0x07, 0xF7, 0x40, 0x09, 0x60, 0xB8, 0x0F, 0xEF, 0xA1, 0x12, 0xC2, 0x68, 0x1F, 0xDD, 0x23, 0x25, 0x82, 0xF1, 0x3E, 0xBE, 0xC7, 0x4A, 0x0C, 0x93, 0x43, 0xF2, 0x48, 0xD4, 0x04, 0xA5, 0x87, 0xF4, 0x91, 0xAA, 0x29, 0xCA, 0x0E, 0xD9, 0x23, 0x53, 0x33, 0x94, 0x1F, 0xF2, 0x47, 0xAE, 0xE6, 0xA8, 0x38, 0x16, 0xCF, 0x42, 0x2B, 0x70, 0x79, 0x2C, 0x9F, 0xA5, 0x56, 0xE2, 0xEA, 0x58, 0x3D, 0x2B, 0xAD, 0xC2, 0xF5, 0xB1, 0x7E, 0xD6, 0x5A, 0x8D, 0x9B, 0x53, 0xF3, 0x6A, 0xF4, 0x86, 0xB4, 0xA7, 0xF6, 0xD5, 0xEA, 0x2D, 0xE9, 0x4E, 0xDD, 0xAB, 0xD3, 0x3B, 0xD2, 0x9F, 0xFA, 0x57, 0xAF, 0xF7, 0x64, 0x38, 0x0F, 0xC2, 0x60, 0x0C, 0x74, 0x3C, 0x8F, 0xC2, 0x68, 0x8C, 0x74, 0x3A, 0x4F, 0xC2, 0x64, 0x4C, 0x74, 0x3E, 0xCF, 0xC2, 0x6C, 0xCC, 0x74, 0xB9, 0x2C, 0xE2, 0x62, 0x2E, 0x0C, 0x5C, 0x80, 0x08, 0x4C, 0xC0, 0xE0, 0x05, 0x8A, 0xD0, 0x84, 0x0C, 0x5D, 0x90, 0x88, 0x4C, 0xC4, 0xF0, 0x15, 0x4B, 0xD8, 0xC2, 0x9C, 0x5C, 0x89, 0x44, 0x2C, 0xC2, 0xE9, 0x95, 0x4A, 0xD4, 0xA2, 0x9C, 0x5D, 0x99, 0xC4, 0x2C, 0xC6, 0xF9, 0x17, 0xFF, 0xE1, 0x6F, 0xBE, 0xAE, 0x5F, 0xEB, 0xCF, 0xFA, 0xDE, 0xFE, 0xDF, 0xFE, 0xDF, 0xFE, 0xDF, 0xFE, 0xDF, 0xFE, 0xDF, 0xFE, 0xDF, 0xFE, 0xFF, 0x8B, 0xFF, 0xAF, 0xFF, 0x19, 0xAD, 0xEB, 0xB8, 0xAA, 0xEF, 0xFE, 0x8D, 0xE3, 0x97, 0xB3, 0xC5, 0xD6, 0x85, 0x79, 0x63, 0x63, 0x77, 0xA1, 0x6C, 0x60, 0x3B, 0xEC, 0x46, 0x41, 0x8E, 0x08, 0x43, 0xA4, 0xDB, 0xE6, 0x10, 0x02, 0x82, 0x88, 0x5D, 0x48, 0x89, 0x8D, 0xDD, 0x84, 0x1C, 0xD2, 0x0E, 0x7E, 0xF6, 0xC2, 0x5C, 0x27, 0x76, 0xEB, 0xF5, 0x3B, 0xEF, 0xC7, 0xFB, 0x8F, 0xB9, 0xDD, 0x7D, 0x6F, 0x7B, 0x72, 0xEA, 0xFB, 0xBA, 0xC8, 0xF3, 0xA1, 0x01, 0x00, 0x40, 0xDA, 0x02, 0xE8, 0x56, 0x9E, 0xB4, 0x34, 0x3B, 0x3A, 0x81, 0x34, 0x03, 0xD7, 0xCF, 0x45, 0x5B, 0x18, 0x20, 0x1A, 0x30, 0x62, 0xB8, 0xB8, 0x72, 0x63, 0xC7, 0x5F, 0xC4, 0x54, 0x5A, 0x42, 0x3C, 0xD1, 0x15, 0xE2, 0x7B, 0xFF, 0xD6, 0x1B, 0xAF, 0xF6, 0xEA, 0xA2, 0x0E, 0xED, 0xF1, 0x6B, 0x89, 0x38, 0xA5, 0xDF, 0xA5, 0x76, 0xA2, 0x01, 0x26, 0xAA, 0x39, 0x8D, 0x54, 0xF2, 0x0B, 0xEB, 0x3F, 0x77, 0xF4, 0xC8, 0xD6, 0x1D, 0xE3, 0x07, 0xEB, 0x0E, 0x8F, 0x1C, 0xEA, 0x8E, 0x15, 0xBA, 0xC3, 0xE1, 0x43, 0x31, 0xEE, 0x76, 0xFF, 0x9A, 0xBA, 0xA3, 0xC5, 0x35, 0x31, 0xCF, 0xE3, 0xEF, 0x3B, 0xDA, 0x4C, 0x52, 0x87, 0x3C, 0x60, 0x2D, 0x71, 0xCA, 0xBA, 0x1B, 0xDA, 0xD3, 0x3E, 0xDD, 0x3E, 0xCA, 0x1D, 0x29, 0x7E, 0xF1, 0x49, 0x86, 0xAB, 0xE8, 0x13, 0x49, 0xFA, 0xF8, 0xE8, 0x8E, 0x50, 0x77, 0x75, 0xC8, 0x14, 0x60, 0xC8, 0x14, 0xDD, 0x63, 0xF8, 0x8D, 0x04, 0x6A, 0x05, 0x06, 0x15, 0xEB, 0x0E, 0x03, 0xC4, 0xE8, 0xE9, 0x43, 0x9C, 0x75, 0x47, 0xB7, 0x49, 0xE2, 0xFE, 0xEF, 0x2C, 0xFF, 0xB6, 0xC3, 0x56, 0xA5, 0xE3, 0x9C, 0x3B, 0xDA, 0xFD, 0x4E, 0xFB, 0x5E, 0x3B, 0x4E, 0x18, 0x45, 0xEF, 0xF1, 0xE9, 0x99, 0x62, 0xF0, 0x86, 0x54, 0x8A, 0x81, 0x3F, 0x92, 0x21, 0x67, 0xB5, 0x1F, 0x59, 0x53, 0xFD, 0xBC, 0x18, 0xF8, 0xDC, 0xDC, 0xED, 0xDA, 0x1E, 0xDA, 0x05, 0x10, 0x66, 0x12, 0x1D, 0xC6, 0x79, 0x44, 0x8A, 0x2E, 0xF6, 0x2E, 0xF6, 0xBA, 0x43, 0x7B, 0x07, 0xA8, 0x3B, 0x68, 0x56, 0x9D, 0xD6, 0xFE, 0x99, 0x95, 0xE8, 0x91, 0x51, 0x6C, 0x21, 0x06, 0x5B, 0xE4, 0xDD, 0x80, 0x58, 0xAC, 0xDD, 0x85, 0xC7, 0x57, 0x38, 0x8A, 0x46, 0x44, 0x0E, 0x50, 0xC9, 0xC5, 0x6E, 0xDA, 0x4F, 0xF8, 0x44, 0x35, 0x02, 0x68, 0x77, 0x81, 0x74, 0x18, 0x64, 0x2E, 0x0F, 0xD2, 0x1D, 0x91, 0x57, 0x45, 0x5B, 0x2C, 0x3A, 0x24, 0x7A, 0x6D, 0xF0, 0xDA, 0xA0, 0x3B, 0xC6, 0xD7, 0x11, 0x77, 0x7F, 0xD6, 0x57, 0x7C, 0xEF, 0xEB, 0xE0, 0xE3, 0x73, 0x3E, 0x4A, 0x5C, 0x14, 0x7E, 0xBC, 0x8E, 0x5E, 0x53, 0xFB, 0xE1, 0xE1, 0x6B, 0xB5, 0x1F, 0x68, 0x84, 0x18, 0xD9, 0x56, 0x35, 0x3A, 0x91, 0x09, 0x89, 0xDA, 0x5F, 0x67, 0x50, 0x93, 0x96, 0x03, 0xD5, 0x5B, 0x92, 0xCE, 0x81, 0x80, 0x73, 0xA0, 0xD9, 0x9D, 0x55, 0x9E, 0xCF, 0x7A, 0x4E, 0x02, 0x75, 0x72, 0x56, 0x64, 0x8B, 0x2E, 0x03, 0x23, 0x06, 0xEA, 0x0E, 0x9F, 0xF2, 0xE2, 0xBE, 0xAD, 0xA3, 0xB7, 0x6A, 0xDF, 0x7D, 0xEA, 0x37, 0x29, 0x62, 0x44, 0xFF, 0x9C, 0x2D, 0x62, 0xCC, 0x63, 0xED, 0xC7, 0x9D, 0xD3, 0x5E, 0xC2, 0x19, 0x35, 0xAE, 0x9E, 0x1A, 0x9D, 0xA2, 0x46, 0x7A, 0x93, 0x6B, 0x6E, 0x6B, 0x3F, 0x95, 0xEA, 0xD6, 0x32, 0x55, 0x9E, 0x31, 0x61, 0x18, 0xE9, 0xD7, 0x06, 0xF0, 0x6B, 0xA3, 0x5F, 0x97, 0xD4, 0xF2, 0xA2, 0x2D, 0x36, 0x56, 0x12, 0x8D, 0x58, 0xD2, 0x45, 0xCC, 0x8B, 0x31, 0x80, 0xDA, 0x4B, 0xCE, 0x3D, 0x23, 0xAE, 0x29, 0xD3, 0xEB, 0x6F, 0x0A, 0x51, 0xD7, 0xF5, 0x55, 0x57, 0x4E, 0x9F, 0xBE, 0x45, 0x5C, 0xBB, 0x63, 0x42, 0xA9, 0xB8, 0xBA, 0x54, 0x5B, 0xC9, 0xAF, 0xC9, 0x94, 0xB1, 0xFA, 0x71, 0xC6, 0x26, 0x75, 0xDF, 0x23, 0x75, 0xBB, 0x0B, 0xD0, 0xCF, 0x9E, 0x5C, 0xD3, 0x0D, 0x98, 0xB5, 0x4D, 0x77, 0x2D, 0xF9, 0x90, 0xB4, 0xFF, 0xD8, 0x12, 0xA9, 0xD4, 0x1D, 0x9B, 0xDF, 0x88, 0x25, 0x09, 0xEB, 0xF6, 0x98, 0xAA, 0xB7, 0xB6, 0x27, 0x53, 0x69, 0x44, 0x85, 0xDD, 0xE4, 0x96, 0xDD, 0x73, 0x6E, 0xE8, 0xE7, 0x66, 0x80, 0x5A, 0x31, 0x4C, 0xDC, 0x1A, 0x56, 0x6E, 0x97, 0x98, 0xBE, 0xF3, 0xBD, 0xCF, 0x5D, 0x9C, 0xF3, 0xE7, 0xC7, 0x99, 0x73, 0xD5, 0x6C, 0x1B, 0xD5, 0x44, 0xC0, 0xAA, 0x8D, 0x58, 0xC5, 0x69, 0x98, 0x13, 0x79, 0x60, 0x10, 0x10, 0xF5, 0x0F, 0x32, 0xAF, 0x3A, 0x90, 0x52, 0x9D, 0x3C, 0x71, 0x0B, 0x38, 0x79, 0xD7, 0x12, 0x90, 0x55, 0x6C, 0x6E, 0x0D, 0x90, 0x85, 0xD6, 0x0D, 0x1B, 0x8B, 0xD9, 0x8D, 0xEA, 0xFA, 0x88, 0x07, 0xBD, 0xAB, 0x07, 0x8B, 0xBB, 0x83, 0x2A, 0x27, 0x8A, 0xDB, 0x13, 0xCB, 0x7B, 0x89, 0x19, 0x9E, 0x7F, 0xDB, 0x41, 0x32, 0xA3, 0x44, 0x3F, 0x3E, 0xB4, 0x48, 0x35, 0x51, 0x3D, 0xB7, 0x06, 0xB0, 0x58, 0x43, 0x7E, 0x55, 0x13, 0xB0, 0x05, 0xF9, 0x70, 0x6D, 0x9D, 0x75, 0x53, 0x5C, 0x49, 0xD2, 0x16, 0x89, 0x47, 0x8C, 0x20, 0x81, 0x6C, 0x3B, 0xFD, 0xAB, 0x70, 0xF8, 0x98, 0x3E, 0x47, 0x5E, 0x6B, 0x29, 0x3B, 0xC6, 0xD4, 0x7E, 0x2C, 0xEE, 0x7F, 0x54, 0x2D, 0x46, 0xDC, 0x15, 0x5D, 0xA1, 0x54, 0xDC, 0x72, 0x09, 0xD5, 0xC4, 0xB4, 0xAA, 0x40, 0x8D, 0x79, 0x7F, 0xDD, 0xB1, 0xAB, 0x81, 0x7E, 0x9C, 0xB3, 0x55, 0x3D, 0x39, 0x4D, 0xBD, 0xDD, 0x5A, 0x7D, 0xD7, 0x56, 0xAF, 0x4D, 0x7E, 0x94, 0x31, 0x29, 0xC3, 0x64, 0xB6, 0x4A, 0x4E, 0x6C, 0x76, 0xF9, 0x42, 0xB2, 0x7C, 0x61, 0x46, 0x41, 0x83, 0xAB, 0xE4, 0xB0, 0x71, 0x0E, 0x57, 0x7A, 0xAF, 0x3C, 0xEF, 0x25, 0xD7, 0xAB, 0x36, 0x6F, 0x61, 0x20, 0xB9, 0x6B, 0x9E, 0xEE, 0xCA, 0xCC, 0xD2, 0xD7, 0xEE, 0x3A, 0xAE, 0x6E, 0x9D, 0xAF, 0xA6, 0xBD, 0x55, 0x65, 0x47, 0xCD, 0x27, 0x22, 0x79, 0xC0, 0xEE, 0xAF, 0x5F, 0x87, 0x2B, 0x8F, 0xD5, 0xC7, 0xBB, 0x54, 0x12, 0xB0, 0x68, 0x72, 0xA3, 0x9E, 0xE8, 0xDA, 0x3A, 0xAA, 0xBB, 0x68, 0x04, 0x20, 0x86, 0xEC, 0x14, 0x2D, 0xD1, 0x67, 0x09, 0xF0, 0xF6, 0x0F, 0x72, 0xDD, 0x18, 0x60, 0x6F, 0x2D, 0xBD, 0xBE, 0x11, 0xEA, 0xF8, 0x64, 0xD5, 0x16, 0x6A, 0xC7, 0xA9, 0xAA, 0xEE, 0x50, 0x53, 0xFC, 0xC9, 0xEC, 0xD3, 0xDA, 0x3B, 0x6B, 0xA5, 0xFE, 0x74, 0x5A, 0x25, 0xC5, 0xDF, 0xFA, 0x88, 0xD5, 0xFB, 0x1E, 0x74, 0x15, 0x1D, 0x27, 0xB8, 0xF4, 0x27, 0x1B, 0x1D, 0x9F, 0x76, 0xBC, 0xBC, 0xAF, 0xDC, 0x1E, 0xE8, 0x5B, 0xD3, 0x81, 0xB4, 0x45, 0x25, 0xE7, 0x5A, 0xED, 0x49, 0xD2, 0xB7, 0x3D, 0x70, 0x67, 0x38, 0x99, 0xD8, 0xA5, 0x76, 0x98, 0x29, 0x96, 0x5C, 0x1E, 0xA6, 0x7B, 0xD6, 0xBB, 0xAB, 0xAB, 0x07, 0x03, 0xB6, 0x31, 0x64, 0xF2, 0x53, 0xDD, 0xB5, 0x71, 0x35, 0xD0, 0xEA, 0x0A, 0xB9, 0xC9, 0x85, 0xCC, 0xBF, 0xAC, 0xDD, 0xAF, 0xEF, 0xA9, 0xDA, 0x7F, 0x5A, 0xAA, 0x96, 0xFE, 0x4C, 0x56, 0xF1, 0xAF, 0xE2, 0xAF, 0x3F, 0x0F, 0x93, 0x33, 0x7B, 0x9E, 0x12, 0x6D, 0x01, 0x88, 0x56, 0x09, 0x2A, 0x60, 0x77, 0x9A, 0x24, 0xCB, 0x9D, 0xAE, 0x5F, 0x43, 0x0C, 0xAA, 0x0E, 0x5C, 0xCF, 0x20, 0x23, 0xAE, 0x54, 0xB4, 0x32, 0x91, 0x5C, 0x6C, 0x05, 0x6C, 0x48, 0x22, 0xE3, 0x62, 0x75, 0x4F, 0xBC, 0x93, 0x1A, 0x3B, 0x0E, 0x08, 0x7D, 0x4D, 0xC6, 0x54, 0x24, 0x2F, 0x5B, 0x69, 0xFF, 0xE5, 0x64, 0x91, 0x16, 0xA4, 0x78, 0xEB, 0xA0, 0xBA, 0x2B, 0x44, 0x6C, 0x17, 0xEA, 0x35, 0x8C, 0xAC, 0xE8, 0xD6, 0xCA, 0x4D, 0xBB, 0xBD, 0x6B, 0xAB, 0x80, 0xAA, 0x1A, 0x55, 0x92, 0x53, 0x1A, 0xAA, 0xFE, 0x9B, 0x81, 0x5B, 0xB3, 0xC8, 0x79, 0xB3, 0x01, 0xD9, 0xB3, 0xE0, 0x67, 0xE0, 0xD0, 0x51, 0x32, 0xCC, 0x7C, 0x7B, 0x4D, 0x82, 0xBE, 0x62, 0xF1, 0x2E, 0x91, 0xFC, 0x63, 0xEC, 0xFB, 0x5F, 0x87, 0x3B, 0x54, 0x4D, 0x54, 0xA3, 0xBF, 0x13, 0x1B, 0xF5, 0x1C, 0xBD, 0x45, 0x04, 0xAA, 0x34, 0x56, 0xFF, 0xDD, 0x8E, 0xDE, 0x06, 0xEA, 0x2B, 0x21, 0x8E, 0xAB, 0xA2, 0xBA, 0xAE, 0xD5, 0x2B, 0x7B, 0xAD, 0x01, 0xCE, 0xAD, 0x26, 0x7D, 0x9D, 0xB4, 0xE0, 0xF7, 0x19, 0x70, 0xA4, 0x3B, 0xE9, 0x7F, 0x91, 0xD4, 0x57, 0xFD, 0xE8, 0xA9, 0x9E, 0xEB, 0xA6, 0xA6, 0x52, 0x75, 0x9B, 0xA6, 0x36, 0xF7, 0x53, 0x81, 0xFF, 0xB4, 0x43, 0x4D, 0x79, 0x05, 0xF4, 0x5C, 0xF1, 0xFE, 0x9E, 0xC1, 0x81, 0xEA, 0xA4, 0x26, 0xC0, 0xAF, 0xE6, 0x82, 0xE3, 0x68, 0xE0, 0x66, 0x3C, 0x39, 0x23, 0x07, 0x38, 0xD3, 0x98, 0x74, 0x99, 0x4D, 0x4E, 0x9A, 0xA9, 0xCF, 0x36, 0x40, 0xED, 0x64, 0x03, 0x7C, 0x56, 0xAC, 0xD7, 0x30, 0x40, 0xAC, 0xD8, 0xC2, 0xAD, 0x85, 0x38, 0xFD, 0xD9, 0xD8, 0x9D, 0xA2, 0x11, 0xBD, 0x37, 0xBE, 0x7F, 0x0E, 0xCA, 0xFD, 0xE1, 0xEF, 0xE7, 0x8F, 0x5A, 0x2F, 0xD5, 0xEE, 0x7B, 0xD5, 0x41, 0x45, 0xBF, 0xEE, 0x14, 0x27, 0xF5, 0xBA, 0xD4, 0x54, 0x9C, 0xDE, 0xC7, 0x44, 0x6D, 0x66, 0xBD, 0x52, 0xC9, 0xA9, 0x95, 0xB4, 0xEF, 0x55, 0xA2, 0xDA, 0x56, 0x05, 0x6C, 0xEA, 0x90, 0xCD, 0xBF, 0x00, 0x26, 0xAF, 0xD6, 0x3D, 0xBE, 0xFD, 0xC5, 0xF1, 0x49, 0x33, 0xFC, 0x45, 0xDF, 0x93, 0x36, 0x15, 0xC4, 0x8C, 0xBE, 0xCD, 0x2C, 0xC4, 0x13, 0x83, 0xFF, 0xBE, 0xA3, 0x55, 0x96, 0x3A, 0xB8, 0xA2, 0x3A, 0x29, 0xED, 0xDA, 0x3B, 0xD1, 0xF9, 0x55, 0x5E, 0x03, 0x71, 0xE6, 0x90, 0xBC, 0x23, 0x10, 0x93, 0x33, 0x06, 0x89, 0xDE, 0xF5, 0x49, 0xD7, 0xC7, 0xDA, 0x0F, 0x6C, 0xAD, 0xF6, 0x36, 0x02, 0x83, 0x63, 0xC8, 0x46, 0xFD, 0x81, 0xE9, 0x69, 0xBA, 0x23, 0x64, 0xB6, 0x68, 0x17, 0xEB, 0xFE, 0x40, 0x9C, 0x32, 0xC1, 0xD0, 0x4F, 0xDC, 0xE6, 0xD2, 0xF9, 0x43, 0x8A, 0xF5, 0x1B, 0xD7, 0xFE, 0xEB, 0x8E, 0x01, 0x47, 0x54, 0xC7, 0x4F, 0x6E, 0x5F, 0x13, 0x5D, 0x4B, 0x72, 0xB3, 0x44, 0xCF, 0xDC, 0xFC, 0x50, 0x71, 0xF6, 0xBD, 0x94, 0x31, 0x62, 0xF0, 0x82, 0x54, 0x8A, 0x01, 0x21, 0xA4, 0xD7, 0x70, 0xED, 0xCF, 0x49, 0x54, 0x13, 0xFE, 0x50, 0xC7, 0x9C, 0x05, 0x46, 0xF9, 0xEA, 0x8E, 0xB0, 0x8F, 0xC5, 0x21, 0xAF, 0xFC, 0xCB, 0x8B, 0x06, 0x2B, 0xE7, 0x50, 0x71, 0x7B, 0x97, 0xBE, 0xFD, 0xC5, 0x34, 0x3B, 0x9B, 0x31, 0xDA, 0xAD, 0xBF, 0x4F, 0x9D, 0xF6, 0xE6, 0x55, 0x1B, 0xD1, 0x3D, 0x26, 0x7F, 0xBF, 0x18, 0xF8, 0xAE, 0x28, 0x45, 0x0C, 0x38, 0x95, 0x7C, 0x5F, 0x5C, 0x38, 0x6F, 0x69, 0xB0, 0x18, 0x31, 0x30, 0x7C, 0x82, 0x68, 0x94, 0xE7, 0x9C, 0xD0, 0x6E, 0xEC, 0x48, 0x75, 0x95, 0x9D, 0x3A, 0xAC, 0x08, 0x70, 0xBC, 0x43, 0x3A, 0xB6, 0x02, 0xA6, 0xB5, 0xD4, 0x3D, 0x71, 0x71, 0xA2, 0xDB, 0xB7, 0xDE, 0x47, 0xC4, 0x1D, 0x6B, 0xBC, 0x13, 0xC5, 0xE3, 0xA7, 0xDD, 0x1D, 0xB5, 0xDF, 0xE7, 0x73, 0xD5, 0xFB, 0xCE, 0xA9, 0x5F, 0xC5, 0xB0, 0xC6, 0xC7, 0x66, 0x88, 0x46, 0x63, 0xC6, 0x46, 0x71, 0xD1, 0x97, 0xEB, 0xED, 0x20, 0xAE, 0x5C, 0x38, 0x4C, 0x8C, 0x68, 0x6D, 0x84, 0x59, 0x3D, 0x8F, 0x55, 0xD0, 0xEE, 0x72, 0x5B, 0x35, 0xA9, 0xB3, 0xBA, 0x78, 0x27, 0xD0, 0x7B, 0x1C, 0x39, 0x33, 0x01, 0x70, 0x1E, 0xA3, 0x3B, 0xD6, 0x9C, 0x14, 0x07, 0x35, 0x4F, 0x7C, 0x27, 0x86, 0xDD, 0x4B, 0xE8, 0x23, 0xEE, 0xB9, 0xB0, 0xFC, 0xB4, 0xF6, 0x5D, 0x92, 0xBE, 0x79, 0x20, 0x86, 0xC7, 0xE5, 0x3C, 0x15, 0xA3, 0x97, 0xA4, 0x25, 0x89, 0x4B, 0x4E, 0xCF, 0xBB, 0x2A, 0x26, 0xBC, 0x5C, 0x24, 0x72, 0xC9, 0xB8, 0xA8, 0x49, 0x62, 0x94, 0xAB, 0xEE, 0x88, 0x98, 0x4C, 0x2E, 0x1D, 0xAA, 0xDD, 0x0D, 0xD6, 0x6A, 0xEA, 0x0D, 0x35, 0xE3, 0x34, 0xD0, 0xF2, 0x3E, 0x19, 0xB2, 0x06, 0x70, 0xDD, 0x4A, 0xCE, 0xB6, 0x04, 0x22, 0xDE, 0x90, 0x55, 0x27, 0x77, 0x31, 0x6C, 0x0E, 0x94, 0x6E, 0x74, 0x6E, 0xDA, 0x03, 0xF1, 0xF2, 0xEE, 0xCC, 0x5D, 0x22, 0x19, 0x13, 0x58, 0x30, 0x5D, 0x5C, 0x5D, 0x16, 0x72, 0x52, 0x4C, 0x3E, 0x12, 0x31, 0x56, 0x5C, 0x13, 0x19, 0x9B, 0x25, 0x26, 0x76, 0x71, 0x71, 0x15, 0xD7, 0x46, 0xB8, 0x64, 0x89, 0x2B, 0xDF, 0x68, 0x2B, 0xB9, 0x0B, 0xB9, 0x6A, 0xAB, 0x7E, 0x9C, 0x5E, 0x55, 0xDD, 0xB6, 0x4F, 0x3D, 0xD6, 0x5E, 0x4D, 0x6F, 0x0B, 0xD8, 0x37, 0x20, 0xE3, 0xBD, 0x00, 0x63, 0x22, 0x39, 0xDB, 0x05, 0x48, 0xCD, 0x94, 0x6E, 0x07, 0xDF, 0xA2, 0x52, 0xED, 0x17, 0x7E, 0x5F, 0x1C, 0xFE, 0xC1, 0x23, 0x72, 0xD3, 0xCD, 0x78, 0x8F, 0x8A, 0x17, 0xC9, 0xB4, 0xE2, 0xC4, 0x3D, 0x90, 0xAF, 0xED, 0x6F, 0x81, 0xBB, 0xC5, 0xE4, 0xD5, 0xD0, 0x6B, 0xA7, 0xAB, 0xE9, 0x1B, 0xD5, 0xB4, 0x5A, 0x6A, 0xCA, 0x5E, 0x32, 0xA9, 0x29, 0xF4, 0x3E, 0x0B, 0x75, 0xDF, 0x79, 0xB5, 0xE0, 0x3B, 0xB5, 0xF0, 0x77, 0xC0, 0xA6, 0x07, 0xB9, 0xBD, 0x3B, 0x10, 0x63, 0x4D, 0x96, 0xEC, 0x06, 0xD6, 0x6D, 0x27, 0x8F, 0x16, 0x00, 0x17, 0x56, 0xEA, 0x39, 0x88, 0xAC, 0xDD, 0x19, 0x20, 0xF3, 0x2E, 0xD7, 0xE9, 0x2E, 0x66, 0x4F, 0xAE, 0xB3, 0x57, 0x3C, 0xB0, 0xC7, 0xE2, 0xA0, 0x98, 0x79, 0xA0, 0xD2, 0x59, 0x71, 0xDB, 0x99, 0x0F, 0x0E, 0x89, 0x9B, 0x0F, 0x02, 0x62, 0xEA, 0x97, 0x50, 0xF9, 0xE7, 0x59, 0x64, 0x7B, 0x9C, 0x9A, 0xB5, 0x4B, 0x35, 0x2D, 0x55, 0x4B, 0x3F, 0x05, 0x7A, 0x16, 0x91, 0x5F, 0x99, 0x4B, 0x41, 0xC9, 0x24, 0xD9, 0xF2, 0xD6, 0xD2, 0xEF, 0xD2, 0x5B, 0x92, 0x40, 0xA1, 0xD4, 0x68, 0xC4, 0x37, 0x71, 0x40, 0xC7, 0x39, 0xA4, 0xA9, 0x10, 0x68, 0x3C, 0x99, 0xCC, 0x69, 0x5C, 0xCF, 0xD0, 0x52, 0x3E, 0xA7, 0x1F, 0x2C, 0xFE, 0xD1, 0xDA, 0xEC, 0xCE, 0x29, 0xE5, 0x37, 0x58, 0x49, 0xFF, 0x1D, 0xD0, 0xFA, 0x2A, 0x99, 0x72, 0x0F, 0xA8, 0xBA, 0x8D, 0x4C, 0xBD, 0xF3, 0xE7, 0x8E, 0xB4, 0x22, 0xFD, 0xF8, 0x40, 0xB2, 0x9A, 0xA7, 0xF2, 0x72, 0x84, 0xFA, 0xFB, 0x72, 0xA0, 0xF1, 0x38, 0xE9, 0x37, 0x3C, 0x3E, 0x31, 0xEE, 0xDC, 0x28, 0xE9, 0xC7, 0x45, 0xB4, 0xBD, 0x25, 0xE6, 0xB6, 0xD0, 0x53, 0xC5, 0x96, 0x60, 0xE0, 0xFB, 0x7E, 0x64, 0xAA, 0x6B, 0xE5, 0x8B, 0x8B, 0x26, 0x93, 0xDB, 0xB7, 0x02, 0xDD, 0x4E, 0x91, 0xBB, 0x03, 0x80, 0x4F, 0x97, 0x91, 0x19, 0xAE, 0x40, 0x9F, 0x2C, 0x32, 0xB5, 0x12, 0xD0, 0xF8, 0xB0, 0xD9, 0x53, 0x40, 0x33, 0x6B, 0x32, 0xCD, 0x0A, 0xA8, 0x5B, 0x87, 0x7A, 0x1E, 0xF3, 0x87, 0xF6, 0x0F, 0xA9, 0xE7, 0xE7, 0xA8, 0x65, 0xB6, 0xAA, 0xF4, 0x6A, 0xA5, 0x7C, 0xE9, 0x25, 0x3A, 0xF6, 0x8F, 0xCF, 0x16, 0x17, 0x17, 0x02, 0xE2, 0xA6, 0xB6, 0xE2, 0x54, 0xA7, 0xF5, 0xB3, 0x1A, 0x54, 0x20, 0xC9, 0xB9, 0x77, 0x81, 0x4B, 0x81, 0xE4, 0x5A, 0x23, 0x90, 0xD6, 0x81, 0x4C, 0xEA, 0x04, 0x18, 0xCF, 0x90, 0x1B, 0xE5, 0xBD, 0xC2, 0x9E, 0xCC, 0x38, 0x09, 0xF4, 0xBB, 0x45, 0xA6, 0x1E, 0x03, 0x9A, 0x7C, 0x48, 0xA6, 0x6F, 0xD6, 0x73, 0xD0, 0xA6, 0xFF, 0x23, 0x8F, 0x9E, 0xD1, 0x5E, 0x49, 0x96, 0xFA, 0x8B, 0xB5, 0x4A, 0x8A, 0x3F, 0xC4, 0x8A, 0x55, 0xF2, 0x0F, 0xDA, 0x8B, 0xC3, 0x42, 0x83, 0xBE, 0x22, 0x9B, 0xD7, 0x9B, 0xF2, 0x54, 0x77, 0xCC, 0x0F, 0xB1, 0xE8, 0x47, 0x76, 0xB8, 0x3A, 0x71, 0xD5, 0xC0, 0x38, 0x92, 0x2C, 0x1F, 0xDF, 0xC0, 0x4D, 0x9C, 0xB7, 0x0D, 0xB8, 0x7E, 0x90, 0x8C, 0xBC, 0x50, 0x69, 0x6E, 0xD1, 0x79, 0x32, 0xEA, 0x14, 0xB0, 0xB6, 0x2E, 0x19, 0x77, 0x1C, 0x30, 0x2E, 0x34, 0x3B, 0x1A, 0x88, 0x6E, 0x4B, 0x2E, 0x7E, 0x05, 0x04, 0x2F, 0x24, 0xA3, 0x0F, 0x90, 0x05, 0x6D, 0xB5, 0x7B, 0xBF, 0x9F, 0xAA, 0xFD, 0xDF, 0x6A, 0xAB, 0xA7, 0x46, 0x93, 0xB5, 0x3D, 0xAA, 0x55, 0x8A, 0xBD, 0x2A, 0xB7, 0xFB, 0x54, 0xEC, 0xBE, 0x42, 0x1C, 0x3A, 0x05, 0x10, 0x7B, 0x8D, 0x17, 0x6D, 0x6E, 0x01, 0xA2, 0x7B, 0xA2, 0x4A, 0xBA, 0x4C, 0x54, 0x83, 0x7E, 0x04, 0xEE, 0x37, 0x21, 0xE7, 0x05, 0x00, 0xA6, 0x3E, 0xE4, 0xFC, 0xB9, 0xC0, 0x71, 0x7B, 0x72, 0xE1, 0x33, 0x60, 0x65, 0x28, 0x19, 0xF1, 0x89, 0x9E, 0x2C, 0x8C, 0x20, 0xAF, 0xF7, 0x78, 0xBF, 0xFF, 0xE8, 0x47, 0xF5, 0xB2, 0x93, 0xBA, 0x75, 0x82, 0xEA, 0xBE, 0x58, 0xB4, 0xB8, 0xD9, 0xD4, 0xF1, 0xDF, 0xBF, 0xEF, 0x2F, 0xF2, 0x07, 0x7A, 0x74, 0x7A, 0xFF, 0xFD, 0x7E, 0x92, 0x85, 0xEA, 0x3A, 0x19, 0xF8, 0x66, 0x1D, 0xE9, 0xD1, 0x0D, 0xB8, 0x1C, 0x4B, 0x7A, 0x76, 0x05, 0xF2, 0x4A, 0x48, 0x6F, 0xF3, 0xED, 0x2C, 0x83, 0xD9, 0x5D, 0xE4, 0xCB, 0x91, 0x00, 0xF0, 0xFA, 0x73, 0x52, 0xBC, 0x15, 0xAE, 0x1E, 0x7A, 0xA9, 0x86, 0xDF, 0x56, 0xAD, 0xA3, 0x55, 0xE0, 0xDF, 0xBB, 0xF6, 0x9E, 0x6A, 0x34, 0xDB, 0xA1, 0xFD, 0xFB, 0x7B, 0xEC, 0xBD, 0xD4, 0x71, 0x57, 0x81, 0x67, 0x3F, 0x92, 0x53, 0xBF, 0xF8, 0xE4, 0xE3, 0xBB, 0x7D, 0xC8, 0x51, 0x6F, 0x81, 0x52, 0x2B, 0xD2, 0x00, 0x96, 0xFD, 0xED, 0x1C, 0x76, 0x4E, 0x5D, 0xD5, 0x57, 0x9D, 0xE8, 0xA6, 0x56, 0x39, 0xF1, 0xBF, 0x9D, 0x83, 0x54, 0xF5, 0x99, 0x0D, 0x60, 0x09, 0xDD, 0xD3, 0x2D, 0x41, 0x05, 0x44, 0x9B, 0xA3, 0xEA, 0x60, 0x5F, 0xE0, 0x57, 0x77, 0x72, 0x58, 0x39, 0xD2, 0xBE, 0xBA, 0x3E, 0x3A, 0x79, 0x82, 0x6A, 0x0B, 0xC0, 0xAA, 0x0A, 0x69, 0x69, 0x76, 0xC8, 0xBB, 0xF7, 0xCF, 0x43, 0xFD, 0x4C, 0xD3, 0x4C, 0xA2, 0x01, 0x83, 0xCA, 0xC4, 0x8D, 0x79, 0xDD, 0x4A, 0xC5, 0x43, 0xB7, 0x2D, 0xCB, 0x89, 0xEF, 0xC6, 0x35, 0x1D, 0x27, 0x92, 0x16, 0xC3, 0xD4, 0x4E, 0x31, 0xAA, 0x2D, 0x1E, 0xED, 0x14, 0x47, 0xFE, 0x5C, 0xFA, 0x93, 0xE8, 0x50, 0x66, 0xA2, 0xE8, 0xF8, 0x63, 0x76, 0x1B, 0x71, 0xFA, 0x0C, 0x72, 0x54, 0x6F, 0xED, 0x4F, 0xFB, 0x5A, 0xF5, 0x69, 0xA1, 0x5A, 0x77, 0x04, 0x6C, 0xF6, 0x91, 0x55, 0xEA, 0x03, 0x33, 0x9E, 0x92, 0xC0, 0x90, 0xE6, 0x4E, 0x49, 0xE2, 0xF4, 0x43, 0x86, 0x70, 0x71, 0xC3, 0xBB, 0xC1, 0xCD, 0xC4, 0x2D, 0x7B, 0x46, 0xED, 0x23, 0xCB, 0x5F, 0x23, 0x7B, 0xD4, 0xD1, 0x6E, 0xA3, 0x18, 0xD5, 0xCE, 0x51, 0x1D, 0x73, 0xE3, 0x9A, 0x8F, 0xE8, 0x92, 0x69, 0xDA, 0x20, 0x1A, 0x5A, 0x9A, 0x66, 0x8A, 0xCE, 0x4F, 0xF7, 0xAF, 0x16, 0x67, 0xA6, 0x93, 0x63, 0xBD, 0xB5, 0xEB, 0xB6, 0x5D, 0x0D, 0x6D, 0xA0, 0x0E, 0xFC, 0x02, 0xB0, 0xAB, 0x4B, 0xB6, 0xF8, 0x05, 0x70, 0xF6, 0x24, 0x81, 0x0A, 0x1F, 0x05, 0x6C, 0x12, 0x5D, 0xC6, 0x1A, 0xE2, 0xC4, 0xF4, 0xDA, 0x53, 0x6C, 0xC5, 0xFD, 0x99, 0x2E, 0x95, 0xC9, 0x26, 0x6B, 0xCC, 0x5D, 0x7F, 0xED, 0xF6, 0xF9, 0x58, 0x9D, 0x78, 0xED, 0xC7, 0xAA, 0xA2, 0xE1, 0x65, 0xF6, 0x5D, 0x71, 0x96, 0x75, 0x41, 0x05, 0xD1, 0x7D, 0x68, 0x6A, 0xB6, 0x18, 0xF0, 0x7F, 0xA9, 0x14, 0x7D, 0x03, 0xC8, 0x09, 0x7B, 0xB5, 0xEB, 0x3D, 0x4F, 0x9D, 0xBF, 0x5F, 0xED, 0xEF, 0x07, 0x8C, 0xEE, 0x42, 0x36, 0x9F, 0x02, 0x18, 0x4E, 0x93, 0x00, 0x10, 0x35, 0x54, 0x1C, 0x39, 0x68, 0x6E, 0x91, 0xE8, 0xFB, 0xD5, 0xBC, 0xCB, 0xE2, 0xD1, 0x2C, 0xFF, 0x11, 0xE4, 0x07, 0xEB, 0x48, 0xD7, 0xC5, 0xDA, 0x1F, 0x53, 0xF0, 0xEA, 0x95, 0xE8, 0xD2, 0xAC, 0xE0, 0x7B, 0xD1, 0xCF, 0x50, 0xB4, 0x50, 0xF4, 0x1D, 0x91, 0xB2, 0x43, 0x9C, 0x37, 0x3F, 0xA3, 0x8A, 0x18, 0x32, 0x36, 0xA2, 0x4C, 0x5C, 0xF8, 0x84, 0x9C, 0xFC, 0x4A, 0xBB, 0xC1, 0x05, 0x6A, 0xF4, 0x0B, 0x75, 0x55, 0x1D, 0xD5, 0xA9, 0x16, 0x30, 0x5A, 0x4F, 0xED, 0x88, 0xFF, 0x5D, 0xB4, 0xDB, 0x1D, 0xB5, 0x5C, 0x9C, 0x3F, 0x2F, 0x66, 0x98, 0xB8, 0xFB, 0x61, 0xCC, 0x2F, 0xDA, 0x37, 0x6E, 0x54, 0x67, 0x66, 0x9D, 0x2D, 0x12, 0xE7, 0x2D, 0x2F, 0x3C, 0x0B, 0xD1, 0x3D, 0x35, 0x5C, 0x0C, 0x77, 0x5A, 0x35, 0x4E, 0x34, 0x1E, 0x8D, 0x98, 0x02, 0x71, 0xD6, 0x9F, 0xE7, 0x20, 0xAF, 0x00, 0xED, 0x2D, 0x69, 0xA2, 0x26, 0x52, 0x4D, 0x7F, 0xAC, 0x8E, 0xF7, 0x00, 0x9C, 0xCD, 0x7D, 0x4B, 0x27, 0x20, 0x6E, 0x8A, 0x74, 0x6A, 0x1D, 0xD9, 0x98, 0x27, 0xCE, 0xED, 0xBC, 0xBE, 0x81, 0x58, 0xD0, 0x3A, 0xB9, 0x9B, 0xF6, 0x57, 0x7D, 0x72, 0x3F, 0x5D, 0x0C, 0x3B, 0x9E, 0x6F, 0x14, 0x23, 0x1A, 0x24, 0xE7, 0x88, 0x31, 0x43, 0x42, 0x43, 0xC5, 0xA5, 0x58, 0xF0, 0xB3, 0x18, 0xD3, 0x37, 0xFC, 0xB8, 0x18, 0x91, 0xA1, 0x3B, 0x8C, 0x95, 0xC8, 0xC0, 0x36, 0xDA, 0x5B, 0xF6, 0x42, 0xDD, 0xF0, 0x93, 0x9A, 0xD1, 0x5D, 0x5D, 0xF8, 0x1D, 0x30, 0x36, 0x8B, 0x8C, 0x6C, 0x0F, 0xF8, 0x46, 0xE8, 0xD7, 0x65, 0x7B, 0x99, 0xE8, 0x74, 0x77, 0x7B, 0xBE, 0x78, 0xFF, 0xC5, 0xDE, 0x4D, 0x3F, 0x5D, 0x85, 0xBC, 0x26, 0xB9, 0xA8, 0x9E, 0x98, 0xB0, 0x2F, 0xF4, 0x86, 0x98, 0x64, 0xB9, 0xB0, 0x86, 0xB8, 0x7A, 0x40, 0xC4, 0x5D, 0x71, 0x59, 0xEF, 0xA5, 0x59, 0x62, 0xAC, 0x8D, 0xD3, 0x5B, 0x71, 0x45, 0xEB, 0x31, 0x7F, 0x88, 0xCB, 0x7E, 0x20, 0x63, 0xAC, 0xB5, 0xB7, 0x76, 0x86, 0x9A, 0x76, 0x41, 0xDD, 0xF1, 0x42, 0x4D, 0x5F, 0x0A, 0xD8, 0x98, 0x7B, 0x8B, 0x5B, 0x03, 0x21, 0xB7, 0xC8, 0xE9, 0xE7, 0x80, 0x94, 0xBA, 0xD2, 0x6F, 0xB7, 0x3F, 0xFF, 0x33, 0x91, 0xCC, 0x4F, 0x3D, 0xF7, 0x59, 0xA3, 0xA5, 0xE4, 0xC1, 0x47, 0x11, 0x97, 0x30, 0x9B, 0xDC, 0x74, 0x6C, 0x41, 0x12, 0x40, 0xA6, 0x2E, 0xF7, 0xDC, 0x27, 0xA6, 0x39, 0x79, 0xED, 0x14, 0x93, 0xDA, 0x02, 0xE2, 0x66, 0x2F, 0xA8, 0x3D, 0xD4, 0x64, 0x4B, 0x32, 0x71, 0x38, 0xB4, 0x7F, 0x53, 0xDD, 0x32, 0x57, 0x3D, 0x5C, 0xA2, 0xE6, 0xCF, 0x07, 0x3A, 0x5D, 0x27, 0x0F, 0x24, 0x00, 0x1E, 0xD1, 0xE4, 0xA1, 0xA6, 0xC0, 0x8A, 0x6A, 0x64, 0x4E, 0x02, 0x90, 0x17, 0xA5, 0xE7, 0x20, 0xB2, 0xDD, 0x43, 0x80, 0xBC, 0xD5, 0xC6, 0xA2, 0xB7, 0x98, 0xE5, 0x56, 0xB1, 0x8D, 0x78, 0x30, 0xAC, 0x62, 0x86, 0x98, 0x99, 0x51, 0xA9, 0x85, 0xB8, 0xAD, 0x79, 0xB9, 0x15, 0x62, 0xFA, 0x72, 0x68, 0xD3, 0x52, 0x4D, 0xF9, 0x8D, 0xDC, 0xF0, 0xBB, 0x7E, 0x9C, 0x5A, 0x41, 0x3D, 0xB0, 0x5A, 0x35, 0x8D, 0x57, 0x2F, 0x4D, 0xAD, 0x7C, 0xB8, 0x6A, 0xB1, 0xB9, 0xF1, 0x1D, 0x30, 0xE8, 0x26, 0x49, 0xB6, 0x4F, 0x09, 0xE8, 0x79, 0xBA, 0x33, 0xF9, 0xF1, 0x07, 0x7B, 0x16, 0x0C, 0x6E, 0xF2, 0x76, 0x24, 0x69, 0xA2, 0x65, 0xC3, 0xBC, 0xA6, 0x64, 0xCE, 0x1C, 0xA0, 0x6F, 0x2D, 0xF2, 0xD0, 0x76, 0xE0, 0xA3, 0x3D, 0xE4, 0x81, 0xF1, 0x40, 0x63, 0xB3, 0x3B, 0xBF, 0x2B, 0x9F, 0xD5, 0xEC, 0x0C, 0x99, 0xD1, 0x15, 0x68, 0xF9, 0x84, 0x4C, 0x4D, 0x04, 0x6A, 0xFF, 0x42, 0xA6, 0x59, 0xFF, 0xF3, 0x79, 0x6C, 0xB7, 0xA3, 0x9A, 0xDF, 0x52, 0x2D, 0xB5, 0x52, 0x1F, 0x75, 0x05, 0xCA, 0x79, 0x4B, 0x1F, 0xF8, 0x6C, 0x93, 0xE9, 0xAC, 0x18, 0xB2, 0x31, 0x30, 0x96, 0x6C, 0x61, 0xB5, 0xE9, 0xC8, 0xA7, 0xBE, 0x64, 0x8A, 0x8F, 0xFE, 0x15, 0x20, 0xB7, 0x3C, 0x69, 0xD4, 0xEA, 0xE4, 0x7C, 0x72, 0x65, 0x14, 0xB0, 0xE8, 0x0A, 0x99, 0x36, 0x1E, 0x98, 0x50, 0x9E, 0xDC, 0xBC, 0x0A, 0xB0, 0xFE, 0xC4, 0xAC, 0x13, 0xD0, 0x62, 0xA0, 0xD9, 0x2B, 0xE6, 0x9D, 0xBD, 0xC9, 0xF4, 0x02, 0xFD, 0xCB, 0x9F, 0x74, 0x8B, 0xDC, 0x6E, 0xD4, 0x5E, 0xEE, 0x8F, 0xEA, 0xC5, 0x8E, 0xEA, 0xC3, 0x2E, 0x2A, 0x29, 0x9E, 0x7F, 0x21, 0xDA, 0xBA, 0x27, 0xD6, 0x15, 0x67, 0x1B, 0x01, 0x71, 0xB5, 0xBB, 0xF8, 0x85, 0x45, 0x5C, 0xA6, 0xF8, 0x83, 0xBD, 0x71, 0x06, 0xF0, 0xD2, 0x8F, 0x8C, 0xE8, 0x0A, 0x5C, 0x6C, 0x6A, 0xB6, 0xB4, 0x52, 0x41, 0x41, 0x3C, 0x19, 0x79, 0x1F, 0x58, 0x65, 0x43, 0x2E, 0x59, 0x09, 0x44, 0xD6, 0x21, 0x63, 0x53, 0x81, 0xD8, 0x03, 0x64, 0x54, 0x2B, 0x7D, 0xCF, 0x88, 0x2F, 0x4F, 0x1E, 0x3D, 0xAC, 0xBD, 0x33, 0x57, 0xD4, 0xB2, 0xBD, 0xAA, 0xF6, 0xBF, 0xDE, 0xAF, 0xEE, 0x7C, 0x23, 0x76, 0xFC, 0x31, 0x3C, 0x92, 0x6C, 0xF1, 0xAE, 0x5B, 0x8E, 0xEE, 0x08, 0x9A, 0x5A, 0x67, 0x22, 0x39, 0x34, 0x7E, 0xE4, 0xCF, 0x72, 0x7B, 0x95, 0xCB, 0xC0, 0xC3, 0x22, 0x39, 0x25, 0x49, 0xF5, 0xBF, 0x08, 0xDC, 0xFF, 0x84, 0x0C, 0xAD, 0x01, 0xE4, 0xAF, 0x20, 0xE7, 0x56, 0x05, 0xB2, 0x1E, 0x92, 0xF3, 0xB3, 0x81, 0x5D, 0xCD, 0xCD, 0x3E, 0x06, 0xA2, 0xD3, 0xF5, 0xEF, 0x47, 0xC9, 0x0F, 0xDA, 0xFD, 0x7D, 0x96, 0xAA, 0xDD, 0x7B, 0xCD, 0xD4, 0xEC, 0xDB, 0x6A, 0x84, 0xA7, 0xD8, 0xE0, 0x48, 0xEB, 0x9F, 0xC5, 0x11, 0x1F, 0x00, 0xE2, 0x67, 0xD3, 0xC4, 0x7E, 0xAB, 0x3F, 0x76, 0x11, 0x83, 0x13, 0x81, 0x76, 0x3F, 0xBF, 0xFF, 0xBE, 0x3A, 0x72, 0xA6, 0xEA, 0x98, 0x08, 0xFC, 0xF6, 0x80, 0x34, 0x78, 0x01, 0xD7, 0x6B, 0x90, 0xEE, 0x25, 0x40, 0xBE, 0x2B, 0x39, 0x6B, 0x3D, 0x90, 0xBB, 0x8C, 0xF4, 0x18, 0x4C, 0xFE, 0x50, 0xE9, 0xFD, 0xFE, 0x6D, 0xA3, 0x5A, 0xD8, 0x5B, 0x5D, 0xFF, 0x50, 0x35, 0x5C, 0x53, 0xDB, 0xFC, 0x87, 0x73, 0x50, 0xCC, 0x7A, 0x75, 0x81, 0x0D, 0xD0, 0x7C, 0x9C, 0x5E, 0x71, 0x8C, 0x85, 0xAA, 0x85, 0xA1, 0x19, 0xEA, 0xB8, 0xC8, 0xDA, 0x43, 0x6F, 0x5D, 0x24, 0x87, 0x2F, 0xAE, 0xED, 0x71, 0x6B, 0x24, 0x39, 0xC6, 0x83, 0xD4, 0x67, 0x7D, 0x1B, 0xAC, 0x9E, 0x2B, 0x54, 0xD3, 0x13, 0x54, 0xEF, 0x26, 0x6A, 0x9B, 0x0A, 0x2A, 0xF0, 0xEF, 0x5D, 0x5F, 0x45, 0x0D, 0x59, 0xAB, 0x92, 0x40, 0xD3, 0xB1, 0x6A, 0xA7, 0x0E, 0x2A, 0x20, 0xF6, 0xB7, 0x55, 0x07, 0xEE, 0x03, 0x1E, 0x17, 0x91, 0x76, 0xAD, 0x7E, 0xBD, 0xAF, 0x8F, 0x5E, 0x7D, 0xA1, 0xEE, 0x09, 0x56, 0x17, 0x7D, 0xAC, 0xF6, 0x5F, 0xA3, 0x02, 0xFF, 0xBB, 0xC6, 0xBF, 0xA8, 0xFD, 0xF2, 0x25, 0x6A, 0x83, 0xB3, 0xAA, 0xE5, 0x15, 0xB5, 0xA3, 0x9F, 0x4A, 0xF6, 0xF5, 0x07, 0xC4, 0xA1, 0x93, 0xD5, 0xFE, 0x53, 0x80, 0xC6, 0x0E, 0x7A, 0x0E, 0xEA, 0xDB, 0x43, 0xAF, 0x3E, 0xB9, 0xAE, 0xD8, 0xFB, 0xC6, 0xE4, 0x1B, 0xA2, 0x01, 0x63, 0xBD, 0xC5, 0xA5, 0x5F, 0x0C, 0xA9, 0x21, 0xEE, 0xDF, 0x36, 0x7C, 0x33, 0x59, 0xBF, 0x32, 0xD9, 0xA3, 0xB2, 0x5E, 0xB3, 0x49, 0xAE, 0x6A, 0x09, 0xB5, 0x6B, 0xDC, 0x8B, 0x03, 0xA2, 0x75, 0xC3, 0xAF, 0xDA, 0x88, 0x9F, 0xD7, 0x2F, 0x29, 0x13, 0xC7, 0x74, 0x35, 0x51, 0x1C, 0x9B, 0x68, 0xEE, 0x26, 0x69, 0xDF, 0xDE, 0x59, 0x75, 0xEE, 0xAA, 0xB6, 0x5D, 0x6A, 0x2E, 0xDF, 0x21, 0xAD, 0x00, 0x0C, 0xD9, 0x45, 0x02, 0x9F, 0x76, 0x71, 0xDA, 0x20, 0x3A, 0xDE, 0x9C, 0xD1, 0x53, 0xDC, 0xB0, 0x60, 0x54, 0xBC, 0x98, 0x79, 0xC2, 0xE9, 0x15, 0xD9, 0xCA, 0x99, 0xB4, 0xAB, 0xA0, 0x5D, 0xAB, 0x3C, 0xB5, 0xDB, 0x14, 0xD5, 0xAE, 0xDC, 0xDD, 0x27, 0xE2, 0xD8, 0x21, 0xA7, 0xAB, 0x89, 0x93, 0x1F, 0x9A, 0xBE, 0x13, 0xA7, 0x9C, 0x3C, 0xBA, 0x5D, 0x9C, 0xEA, 0x4D, 0xDA, 0x35, 0xD1, 0xEE, 0xA8, 0x18, 0xD5, 0x79, 0xA2, 0x6A, 0x97, 0x00, 0x74, 0x6E, 0x46, 0x36, 0xBF, 0x0E, 0x8C, 0x99, 0xA8, 0x5F, 0x97, 0xE0, 0x28, 0xD1, 0x61, 0x8D, 0xF3, 0x79, 0xD1, 0xB5, 0xA9, 0x5F, 0x80, 0x78, 0x60, 0x82, 0xDB, 0x61, 0xB2, 0xCD, 0x00, 0xF2, 0xF3, 0x0C, 0xED, 0x7E, 0xBA, 0x43, 0xB5, 0x0D, 0xF8, 0x63, 0x9D, 0x38, 0x69, 0xD0, 0x85, 0x6E, 0xE2, 0xF4, 0x77, 0x79, 0x5B, 0x44, 0x43, 0xCA, 0xB1, 0x67, 0x10, 0xAF, 0xEF, 0x7E, 0x01, 0x11, 0xE4, 0xC0, 0xDF, 0xB4, 0x3B, 0xD6, 0x43, 0x35, 0x50, 0x0D, 0x5A, 0xA0, 0x36, 0x5C, 0x08, 0x4C, 0x9D, 0xA4, 0x3B, 0xE6, 0xFB, 0x89, 0x9F, 0x1A, 0x83, 0xCE, 0x8B, 0x3E, 0xAF, 0x43, 0x7E, 0x13, 0x0F, 0x9D, 0x09, 0x9D, 0x44, 0xB6, 0xBD, 0x49, 0x3A, 0x15, 0x68, 0x7F, 0x4C, 0xA9, 0x3A, 0x01, 0x57, 0xDF, 0x8A, 0x2E, 0x1F, 0x9C, 0x28, 0x83, 0xD8, 0x29, 0xB7, 0x87, 0x38, 0x13, 0x9B, 0x32, 0x45, 0x1F, 0xAB, 0x54, 0x8A, 0xB3, 0x53, 0xC9, 0x21, 0xC5, 0xDA, 0x9B, 0x30, 0x59, 0x9D, 0x3D, 0x57, 0x35, 0x5E, 0x55, 0xC7, 0x77, 0x02, 0x86, 0xDC, 0xD1, 0x1D, 0xE1, 0x13, 0xC4, 0x3E, 0x30, 0xBE, 0x14, 0x7D, 0xEB, 0x45, 0x56, 0x13, 0x33, 0xDF, 0x44, 0xF7, 0xD7, 0x6E, 0x54, 0x23, 0xD5, 0x79, 0xEC, 0xCF, 0xB1, 0x10, 0x13, 0x73, 0xAB, 0x8B, 0x9E, 0x7D, 0xF3, 0x2E, 0x8A, 0xB3, 0x8B, 0x93, 0x6B, 0x8B, 0xC1, 0xF3, 0x33, 0xF4, 0x9C, 0xF6, 0x38, 0xBC, 0x82, 0x38, 0xF7, 0x27, 0x72, 0xF8, 0x56, 0xED, 0x4D, 0x2C, 0x51, 0x03, 0x3B, 0xAB, 0x4B, 0x4E, 0xA8, 0xF6, 0x07, 0x81, 0xC9, 0xA1, 0x64, 0x93, 0x95, 0x40, 0xE8, 0x3F, 0xA4, 0x53, 0xE9, 0x5C, 0xE2, 0x37, 0xA2, 0xEF, 0xA0, 0x84, 0xEF, 0xC5, 0xA3, 0x43, 0x56, 0x0D, 0xD4, 0xFE, 0x32, 0x37, 0x35, 0x88, 0xA6, 0x6E, 0x62, 0x70, 0xEC, 0xBE, 0x31, 0xE2, 0x42, 0x87, 0xD4, 0x8F, 0x21, 0x3E, 0x8F, 0x96, 0x3E, 0x23, 0x2B, 0xCC, 0x0F, 0x12, 0x23, 0x2E, 0x2F, 0xFC, 0x52, 0x5C, 0xF8, 0x25, 0x39, 0xE2, 0x81, 0xF6, 0x7C, 0x66, 0xA8, 0x31, 0x55, 0xD5, 0xC4, 0x4F, 0xD4, 0xC8, 0x2A, 0x40, 0xBF, 0x4F, 0x48, 0xEF, 0xF5, 0x80, 0x63, 0x6B, 0xFD, 0xBA, 0x24, 0x7F, 0x25, 0x4E, 0x9C, 0x98, 0x32, 0x44, 0x3C, 0xB5, 0x66, 0x73, 0x44, 0x59, 0x6F, 0x80, 0x4C, 0xB9, 0x93, 0xDB, 0x58, 0x8C, 0xAD, 0x70, 0x74, 0x98, 0x18, 0x66, 0xCC, 0x30, 0x89, 0xE1, 0xB5, 0xE6, 0xD9, 0x8A, 0xD1, 0x97, 0x8D, 0x7D, 0xC5, 0xF0, 0x43, 0x8B, 0x4D, 0xE2, 0xA2, 0x11, 0x73, 0x1D, 0x44, 0x23, 0xC8, 0xB1, 0xE3, 0xB5, 0x17, 0x7A, 0x5F, 0x5D, 0x99, 0xAE, 0xA6, 0xED, 0x55, 0xB7, 0xDE, 0x03, 0xDA, 0x05, 0x92, 0x61, 0x6E, 0x80, 0x21, 0x8A, 0x74, 0xEA, 0x04, 0x2C, 0xB7, 0x96, 0x7E, 0x87, 0xB2, 0x63, 0x63, 0xC4, 0xA7, 0xE5, 0x8E, 0x85, 0x14, 0x79, 0xD4, 0x8A, 0x25, 0x33, 0xCF, 0xC6, 0x3E, 0x82, 0xBC, 0xB6, 0xBD, 0xB1, 0x9A, 0xB8, 0x76, 0xCD, 0x4A, 0x2B, 0x71, 0xD9, 0x10, 0xEF, 0xEB, 0xE2, 0xEA, 0xD5, 0xCE, 0x14, 0xE5, 0xFD, 0x58, 0xDC, 0x64, 0xA1, 0x6E, 0x70, 0x20, 0xFD, 0x75, 0x07, 0x57, 0xDF, 0x57, 0xD3, 0x9B, 0xA9, 0x3B, 0x47, 0xAB, 0xF9, 0x2B, 0x55, 0x53, 0x4C, 0xB9, 0x51, 0x36, 0x3F, 0x91, 0xC7, 0xA7, 0x03, 0x61, 0x25, 0xDF, 0x24, 0x6D, 0x3E, 0x05, 0xEC, 0x7D, 0xDE, 0x2B, 0x0B, 0x70, 0x36, 0xDE, 0x4C, 0x6A, 0xFD, 0x1A, 0x20, 0xCF, 0xCD, 0xAF, 0x5A, 0x59, 0xCC, 0xE9, 0x0D, 0x88, 0xFB, 0x32, 0xD5, 0x1D, 0xFB, 0x3F, 0x08, 0x16, 0x37, 0xEB, 0xCF, 0xFE, 0x9F, 0xE7, 0x0E, 0x5F, 0x35, 0xE9, 0x25, 0xB9, 0xDC, 0x1F, 0xDA, 0xAF, 0xAE, 0xEE, 0x38, 0xA8, 0xE6, 0xE6, 0xA9, 0xE7, 0x3B, 0xA9, 0x5F, 0x9B, 0x8B, 0x9D, 0x6E, 0x3D, 0x6A, 0xF5, 0xC4, 0x1E, 0xF0, 0xFC, 0x68, 0x87, 0xFF, 0x8F, 0xB1, 0x40, 0x5A, 0x04, 0x70, 0x75, 0xDD, 0x92, 0x58, 0x53, 0x81, 0x83, 0x63, 0x69, 0x31, 0x99, 0xF1, 0xAE, 0xE2, 0xD7, 0xF1, 0xCE, 0xE4, 0x96, 0x75, 0x80, 0x75, 0x25, 0xB3, 0x93, 0x80, 0x1E, 0xF6, 0x64, 0xDA, 0x76, 0xA0, 0x81, 0x25, 0x99, 0x5E, 0x0F, 0x68, 0x3E, 0x92, 0x4C, 0x33, 0xAF, 0xB6, 0x48, 0x24, 0xD3, 0x3D, 0x00, 0x14, 0x90, 0x29, 0x2F, 0xFF, 0x3C, 0x07, 0x6D, 0xDB, 0xA0, 0xE6, 0xFC, 0xAE, 0x5E, 0xA8, 0xAC, 0xFE, 0x11, 0x21, 0x3E, 0x5D, 0x4F, 0x02, 0x16, 0x3E, 0x79, 0x77, 0x44, 0x87, 0x8E, 0xF3, 0x76, 0x90, 0x35, 0xF6, 0x27, 0x86, 0xB5, 0xCD, 0x20, 0xE3, 0xE3, 0x52, 0xF5, 0xFD, 0x82, 0x69, 0x04, 0xBE, 0xBE, 0x46, 0xC6, 0x37, 0xAD, 0xFE, 0x43, 0xC1, 0x8F, 0x64, 0x8C, 0x2D, 0xB0, 0xA0, 0x88, 0x5C, 0x3E, 0x1E, 0x88, 0xEB, 0x43, 0x2E, 0x59, 0x01, 0xB8, 0xD6, 0x27, 0x97, 0xBD, 0x05, 0x3C, 0xB2, 0xC8, 0xB8, 0x0A, 0x80, 0xCD, 0x57, 0xE4, 0x8A, 0x9B, 0xE4, 0x96, 0xE1, 0xDA, 0xCB, 0xBE, 0xA0, 0x9E, 0x0F, 0x55, 0x1F, 0x5E, 0x13, 0x1F, 0x36, 0x23, 0xC5, 0xF3, 0xAD, 0xC8, 0x4A, 0x01, 0xC0, 0xFA, 0x9E, 0x64, 0x85, 0x39, 0x03, 0x0F, 0x59, 0x5D, 0x25, 0x81, 0xC5, 0xCF, 0xCA, 0xBF, 0x22, 0x67, 0x95, 0x0B, 0x37, 0x00, 0xE4, 0xC9, 0xCA, 0x8B, 0xFA, 0xD7, 0xB0, 0x21, 0x49, 0xB7, 0x30, 0xE0, 0xCE, 0x39, 0x32, 0x38, 0x0F, 0x28, 0xB9, 0x4D, 0xCE, 0xED, 0x02, 0xE4, 0xAF, 0x37, 0x6B, 0x02, 0x32, 0xFB, 0x93, 0x0B, 0x06, 0x03, 0xE1, 0x4F, 0xC9, 0x88, 0x5E, 0x80, 0x11, 0xA4, 0xFC, 0x7B, 0xD4, 0x51, 0xBB, 0xE7, 0xAC, 0xD4, 0x47, 0x9F, 0x8A, 0x0F, 0x2F, 0x69, 0xFF, 0xE2, 0x40, 0x75, 0xEB, 0x1B, 0xF5, 0xFF, 0x89, 0xB9, 0x0F, 0x78, 0x2C, 0xF7, 0xF7, 0x0F, 0xE0, 0x9F, 0xD3, 0x1E, 0x1A, 0x52, 0x49, 0x49, 0x45, 0x59, 0xA5, 0x24, 0x15, 0x5A, 0x88, 0x8C, 0xB2, 0x52, 0x68, 0x52, 0xCA, 0x2A, 0xDA, 0x56, 0x44, 0x93, 0x6C, 0x8A, 0x22, 0x29, 0x12, 0x92, 0x3D, 0xD2, 0xA4, 0x5D, 0x4A, 0x3B, 0x4D, 0x15, 0x2D, 0xED, 0xA1, 0x3D, 0xFD, 0xBF, 0xD7, 0xFF, 0x3A, 0xBF, 0x7D, 0xFA, 0x1D, 0xFE, 0xF3, 0xF7, 0x7A, 0xF9, 0xBD, 0xCF, 0xCD, 0x73, 0xEE, 0xEB, 0xBA, 0xEF, 0xE7, 0x7E, 0x7C, 0x3F, 0xCF, 0x75, 0x7B, 0x8E, 0xB7, 0xE8, 0xBC, 0x6D, 0x69, 0xBF, 0xBB, 0x5D, 0xCB, 0x69, 0xDB, 0x7E, 0x4B, 0x07, 0x0B, 0xB1, 0x32, 0x4D, 0x30, 0x1B, 0xF6, 0xDB, 0x76, 0x71, 0xB5, 0xD5, 0x19, 0xDE, 0xD7, 0xC5, 0xDF, 0xAF, 0xAB, 0xD6, 0x9B, 0x81, 0x9F, 0xE2, 0xBC, 0xDB, 0x37, 0xED, 0xE5, 0x54, 0xFD, 0x56, 0x6C, 0xBB, 0x03, 0x67, 0xB2, 0x45, 0x9F, 0xD9, 0xC0, 0x91, 0xFD, 0x22, 0xC9, 0xA5, 0x01, 0x45, 0x8F, 0xC4, 0x91, 0xC8, 0x88, 0xFB, 0x72, 0x9D, 0xC0, 0xC7, 0x3F, 0x8B, 0x7C, 0xC7, 0xEB, 0x3D, 0xAE, 0x7E, 0x65, 0x77, 0xCB, 0xB0, 0x81, 0x51, 0xEC, 0x0C, 0x2B, 0x16, 0x20, 0xF5, 0xE2, 0xC9, 0x61, 0x69, 0x4A, 0x19, 0x64, 0x48, 0x52, 0xB3, 0xFD, 0xDD, 0x78, 0x3D, 0x85, 0x5A, 0x0C, 0x0B, 0x90, 0xBA, 0x35, 0xAC, 0xE9, 0x01, 0xA0, 0x4E, 0xAC, 0x39, 0x16, 0x92, 0xED, 0x63, 0xAB, 0x5B, 0x8B, 0xDF, 0x5D, 0xF3, 0x80, 0x8B, 0x87, 0xC5, 0xFB, 0x7F, 0xF1, 0xCF, 0xCF, 0xB7, 0x01, 0x40, 0x5D, 0xEC, 0x57, 0x3B, 0xB2, 0x8A, 0xE7, 0x1F, 0x28, 0x6E, 0xC1, 0xAE, 0x89, 0x65, 0xED, 0x9A, 0xB0, 0xCA, 0xBD, 0xFE, 0xCD, 0x7A, 0x2F, 0xC9, 0x7A, 0x74, 0x22, 0xB9, 0x8F, 0x5E, 0x87, 0x59, 0x35, 0x03, 0x16, 0x20, 0xB5, 0xEF, 0xB1, 0xBA, 0x23, 0x81, 0x37, 0x17, 0x84, 0xA8, 0xF3, 0x7C, 0xB7, 0x06, 0x00, 0xEE, 0xF3, 0x3C, 0x08, 0x65, 0xB7, 0xD9, 0xA8, 0x32, 0xD6, 0x61, 0x14, 0xDB, 0x27, 0x9B, 0x05, 0x7E, 0x6D, 0x94, 0x24, 0xBB, 0xA2, 0x13, 0xBB, 0x66, 0x16, 0xCB, 0x8F, 0x60, 0xBB, 0xBA, 0xB1, 0x4A, 0xF7, 0x7F, 0xF7, 0x05, 0xCB, 0x73, 0x20, 0xE0, 0xB8, 0x2F, 0xBB, 0x55, 0x93, 0x75, 0x29, 0x63, 0xD5, 0xC2, 0xFE, 0x27, 0x72, 0xD0, 0xAF, 0x6D, 0xF9, 0x91, 0x15, 0xE9, 0x7B, 0x22, 0x40, 0x0E, 0x2C, 0x65, 0xFB, 0x5B, 0x03, 0x92, 0xCD, 0x39, 0x07, 0xF5, 0x13, 0x57, 0xA5, 0xDC, 0x16, 0x60, 0x34, 0xCD, 0x5F, 0xD0, 0x7F, 0xF4, 0xF8, 0xD1, 0xE4, 0xF4, 0x9A, 0x71, 0x4D, 0xC9, 0x35, 0x7B, 0xF4, 0xBA, 0x93, 0x39, 0x27, 0xC7, 0xC9, 0x89, 0x1C, 0x74, 0x5D, 0xE4, 0xA0, 0xEB, 0xBC, 0x4F, 0xD5, 0x40, 0xB6, 0x69, 0x3E, 0x2B, 0xF5, 0xE5, 0xFB, 0x41, 0xB2, 0x8F, 0xC9, 0x53, 0x7B, 0x52, 0xC5, 0xA1, 0x6A, 0x05, 0xA9, 0xFE, 0xF3, 0xC4, 0x35, 0x72, 0xB4, 0xB8, 0xEA, 0x14, 0x7F, 0x4F, 0x95, 0x1A, 0x8A, 0xAC, 0xB6, 0x0E, 0xD0, 0x42, 0xAC, 0x3B, 0x3D, 0xAF, 0x00, 0x2A, 0x8E, 0x22, 0x57, 0x9C, 0x00, 0x46, 0xA5, 0xD1, 0xFE, 0x34, 0x37, 0x98, 0xDC, 0x22, 0xA7, 0xBD, 0xB3, 0x9C, 0x49, 0x86, 0xEB, 0x1B, 0xBE, 0x27, 0xD3, 0x1F, 0x4D, 0xCE, 0x12, 0xFB, 0xF1, 0x10, 0x79, 0xEB, 0x15, 0xD7, 0x1D, 0xA5, 0xC5, 0x76, 0x88, 0x67, 0xFB, 0x5A, 0xBD, 0xB4, 0x22, 0xD5, 0x9B, 0xD4, 0x9C, 0x27, 0x35, 0x13, 0x4F, 0xCB, 0x91, 0x7A, 0x77, 0x39, 0x8F, 0x8D, 0x2D, 0x11, 0xD9, 0xE9, 0x14, 0xD7, 0x1F, 0x5A, 0xC1, 0x1A, 0xDF, 0x65, 0x07, 0x14, 0x02, 0x8A, 0x0B, 0xC4, 0xFE, 0x6B, 0x01, 0x7D, 0x75, 0x3E, 0x97, 0x8E, 0xE9, 0xA4, 0xB1, 0xC2, 0xEC, 0xDE, 0xE4, 0x6C, 0x8D, 0x39, 0x03, 0xC9, 0x7C, 0xF5, 0xE9, 0x7D, 0xC5, 0x79, 0xD4, 0x17, 0xC7, 0x25, 0xC1, 0x75, 0x8D, 0x26, 0xB2, 0xBD, 0xE6, 0x7D, 0x5B, 0x46, 0x0E, 0x0E, 0x7C, 0xD2, 0x84, 0xD4, 0x0A, 0xAC, 0x78, 0x49, 0x8E, 0x93, 0x29, 0xF5, 0x22, 0x4D, 0xAE, 0xEE, 0xCB, 0x26, 0xC7, 0x8B, 0xF3, 0xDD, 0x3F, 0x02, 0x7C, 0x1E, 0xD4, 0x59, 0xE3, 0x5A, 0x56, 0xF7, 0x27, 0xD0, 0x7B, 0x95, 0x78, 0x7E, 0xC4, 0xB6, 0x89, 0x0A, 0xF7, 0x31, 0x37, 0x9A, 0x34, 0x96, 0xB5, 0xFF, 0x49, 0xDA, 0x57, 0xCE, 0x8B, 0x26, 0xF3, 0xE5, 0xE7, 0x8A, 0x5C, 0xD7, 0x52, 0xBC, 0x1E, 0x67, 0x55, 0x70, 0x7D, 0x9B, 0xE9, 0xAC, 0xDA, 0x9B, 0x77, 0x3D, 0x48, 0x9D, 0x23, 0x97, 0x63, 0xC8, 0xF1, 0x1A, 0x87, 0xF4, 0x49, 0xCB, 0x31, 0x07, 0xEE, 0x92, 0x56, 0xC6, 0x79, 0xAB, 0x48, 0x6B, 0xB1, 0x6E, 0x0D, 0x5C, 0x03, 0xCE, 0xC7, 0xFB, 0xD9, 0xF1, 0xDD, 0x59, 0xD7, 0x65, 0xAC, 0xCC, 0x29, 0xC0, 0x62, 0x2B, 0xF7, 0xE1, 0x96, 0x45, 0x1A, 0x96, 0xBB, 0xF4, 0x21, 0xDD, 0x0C, 0x16, 0xCC, 0x23, 0x0B, 0x5A, 0x2F, 0x89, 0x13, 0xD7, 0xC4, 0x63, 0x31, 0xEB, 0x8B, 0xE2, 0xFA, 0xB3, 0xC7, 0xB0, 0x5A, 0x4E, 0x37, 0xBD, 0x49, 0x2B, 0x94, 0xDE, 0x24, 0x6D, 0x35, 0x0E, 0x66, 0x90, 0x76, 0x23, 0xF2, 0x76, 0x92, 0xD3, 0x86, 0xA4, 0x06, 0x93, 0x33, 0x7C, 0xC5, 0x75, 0xE1, 0x02, 0x9E, 0xCB, 0x69, 0xB1, 0x16, 0x25, 0xAC, 0xCB, 0x06, 0x76, 0xB4, 0x36, 0x60, 0xB4, 0x5E, 0xE4, 0xD4, 0x75, 0x80, 0x3D, 0x5D, 0x9F, 0xE8, 0xAA, 0xBC, 0x22, 0x82, 0x74, 0x72, 0xF4, 0x9B, 0x41, 0x66, 0xDD, 0x59, 0xF5, 0x8A, 0xEB, 0xAE, 0xAC, 0x65, 0x97, 0xA8, 0xDE, 0xE8, 0x48, 0x4E, 0xD3, 0x28, 0xAD, 0x20, 0x1D, 0x2E, 0x1F, 0x5C, 0x4D, 0xDA, 0x2B, 0xE6, 0xF5, 0x01, 0x99, 0x99, 0xFC, 0x93, 0x9C, 0xBB, 0x94, 0x73, 0xE1, 0x1C, 0xF1, 0xBC, 0x0E, 0xF7, 0xE3, 0x7A, 0x46, 0xD3, 0xD9, 0x49, 0x77, 0xD9, 0x65, 0xE7, 0xD8, 0xA1, 0x62, 0x7B, 0xCA, 0x3B, 0x91, 0xA9, 0xAF, 0x03, 0x13, 0x77, 0xF1, 0x79, 0x89, 0x0C, 0x20, 0xED, 0x1E, 0x87, 0x5F, 0x25, 0xF7, 0x17, 0x6E, 0x7C, 0xF8, 0xE4, 0x08, 0x68, 0xBE, 0x33, 0xFA, 0xDC, 0x3A, 0x72, 0xCD, 0xEB, 0x63, 0xC1, 0xA4, 0xCB, 0xA5, 0x94, 0xB6, 0xA4, 0xA7, 0xC4, 0x4E, 0x27, 0x72, 0x71, 0x7B, 0xDF, 0x0F, 0xE4, 0x8A, 0xAE, 0xFE, 0x31, 0xA4, 0xAF, 0x85, 0xF7, 0x40, 0xD2, 0x5B, 0x5C, 0x67, 0xA3, 0x3E, 0x81, 0x9F, 0x8F, 0x6B, 0xEC, 0x12, 0x3F, 0x36, 0xB2, 0x05, 0xBB, 0xBD, 0x9C, 0x0D, 0xEC, 0x08, 0x98, 0x14, 0x8B, 0x5C, 0xF6, 0x05, 0x58, 0x2E, 0xF7, 0xB9, 0x27, 0xD0, 0x57, 0x2D, 0xAB, 0xEF, 0xC5, 0xCF, 0xC0, 0xAE, 0xC0, 0x0C, 0x94, 0xED, 0x51, 0x0F, 0x11, 0x73, 0x9D, 0x09, 0xEB, 0xF6, 0x83, 0x32, 0x04, 0x02, 0xE6, 0x91, 0x41, 0x2F, 0xA2, 0x3B, 0x93, 0xAB, 0xA4, 0x02, 0x41, 0xAE, 0xDC, 0xE0, 0xA3, 0x42, 0x06, 0x22, 0x48, 0x9A, 0x5C, 0xAE, 0x61, 0xDE, 0x8D, 0x5C, 0xF3, 0x4D, 0x5C, 0xBB, 0x2D, 0xC1, 0xF9, 0x7C, 0x13, 0x1B, 0x7B, 0x8C, 0xDD, 0x96, 0xC6, 0xE6, 0x6E, 0x66, 0xF7, 0xCB, 0x00, 0x03, 0xA6, 0x8A, 0x5C, 0x62, 0x06, 0xCC, 0x35, 0xDE, 0xF7, 0x25, 0xF4, 0x02, 0x90, 0x34, 0x5A, 0x39, 0x0D, 0xB5, 0x1A, 0xCD, 0x8F, 0x8D, 0xE0, 0xC7, 0x9C, 0x1C, 0xD3, 0x52, 0x89, 0xDC, 0x7F, 0x0A, 0x20, 0xD3, 0xD2, 0xD8, 0x64, 0x2D, 0xB0, 0x6D, 0xD9, 0xC4, 0x7A, 0x36, 0xBE, 0x94, 0x8D, 0x13, 0xAB, 0x99, 0x79, 0x31, 0xF8, 0x67, 0xF1, 0x6C, 0x92, 0x2D, 0x5B, 0x58, 0xC8, 0x1E, 0x97, 0x62, 0x1F, 0x7E, 0x26, 0xAF, 0x7D, 0xB9, 0xB9, 0x0B, 0xB0, 0x2E, 0xD9, 0xE4, 0x77, 0xD9, 0x0A, 0x08, 0xDF, 0x0B, 0xE4, 0x9D, 0x1B, 0xEF, 0x5C, 0xA0, 0x6B, 0x1E, 0x72, 0xFC, 0x8B, 0xC8, 0x55, 0xD1, 0x40, 0xE4, 0x48, 0xAE, 0xA7, 0x51, 0x22, 0x72, 0xD1, 0x25, 0xA0, 0xD3, 0x31, 0x91, 0x2D, 0x87, 0x00, 0x9D, 0x23, 0xC4, 0xB9, 0x15, 0xDB, 0x3D, 0x9E, 0x8B, 0xC7, 0x25, 0x03, 0xBD, 0xC4, 0x7B, 0x9E, 0x4D, 0xDB, 0x79, 0x0E, 0xB3, 0x41, 0xDC, 0xAB, 0x49, 0xD0, 0x02, 0xD7, 0xB7, 0x67, 0x0B, 0xE3, 0xD9, 0x33, 0x01, 0xE4, 0xE7, 0xC0, 0x9A, 0x5A, 0xB2, 0x26, 0xEF, 0x73, 0x13, 0xF2, 0xE0, 0x95, 0x1F, 0xF7, 0x80, 0x11, 0xDA, 0x8B, 0xF5, 0x3E, 0x07, 0x03, 0x2B, 0xDD, 0x80, 0x8F, 0x9D, 0x67, 0x3E, 0xDC, 0x5A, 0x05, 0x7C, 0x7F, 0x23, 0x8E, 0x2B, 0x15, 0xB8, 0xFE, 0x42, 0xE4, 0xE4, 0x1F, 0xC0, 0x81, 0x3B, 0x22, 0xD3, 0x7A, 0x00, 0x31, 0xB7, 0x28, 0x27, 0x03, 0x01, 0x22, 0x83, 0x06, 0xAA, 0x02, 0xEB, 0xBE, 0x89, 0xEF, 0xDB, 0xD2, 0x73, 0x2B, 0xAE, 0x93, 0xCB, 0x80, 0xF3, 0x7B, 0xCE, 0x1F, 0x9C, 0xC7, 0x44, 0x7D, 0x03, 0xF6, 0xEC, 0x76, 0xF2, 0xC5, 0xB0, 0xAA, 0x1B, 0x64, 0x4D, 0xDD, 0x37, 0x79, 0xF2, 0xC8, 0x96, 0xDF, 0xE7, 0x10, 0xF3, 0x48, 0xA5, 0x3E, 0x4E, 0x3F, 0xC4, 0x6F, 0xB8, 0xBB, 0xB6, 0xD2, 0xA0, 0xAB, 0x3F, 0xD1, 0x3F, 0x92, 0x3C, 0xF4, 0x71, 0x59, 0x45, 0xBB, 0x34, 0x5A, 0x2F, 0x5C, 0x15, 0x81, 0x97, 0x1B, 0xC4, 0xEB, 0xF1, 0x06, 0x70, 0x45, 0x99, 0x67, 0xE6, 0x65, 0x59, 0x62, 0xEE, 0xD1, 0x1C, 0x38, 0x50, 0x25, 0x9C, 0x0E, 0xE4, 0x89, 0x15, 0xDC, 0x45, 0x82, 0xA7, 0x7C, 0x6E, 0x22, 0xCD, 0x14, 0xEC, 0x00, 0xD7, 0xD7, 0x26, 0x1F, 0x99, 0xDD, 0xFC, 0x4E, 0xD6, 0xBC, 0xF8, 0x92, 0x4F, 0x1E, 0x2D, 0xE0, 0xFA, 0x89, 0xD9, 0xEC, 0xD2, 0x65, 0xA4, 0xA4, 0xA7, 0xAC, 0x0D, 0x39, 0x69, 0x7B, 0x1B, 0xF1, 0x8E, 0x53, 0xFF, 0x37, 0xD3, 0xA1, 0xA0, 0xB4, 0x1B, 0x64, 0xD0, 0x46, 0x7F, 0x10, 0xF5, 0xD1, 0x44, 0x1D, 0x20, 0xC7, 0x54, 0xB3, 0xC6, 0x21, 0xC0, 0x63, 0xF1, 0xDA, 0x36, 0x29, 0x6E, 0x5F, 0x56, 0xB3, 0x47, 0x6C, 0x5F, 0x06, 0xCE, 0x88, 0xAC, 0x6F, 0xF7, 0x8E, 0xFF, 0x1E, 0xC5, 0x56, 0x9C, 0xAB, 0x72, 0x39, 0x50, 0xDD, 0x89, 0xD7, 0x9D, 0x41, 0xAA, 0x7D, 0x90, 0x27, 0x4F, 0x1D, 0xE0, 0xBA, 0x49, 0x56, 0xEC, 0x12, 0x3B, 0x76, 0xB2, 0x35, 0x0B, 0x90, 0x63, 0x2A, 0x49, 0xCD, 0xF6, 0x4A, 0xEB, 0xC8, 0x98, 0x14, 0x09, 0x69, 0x32, 0xC8, 0xAD, 0xCD, 0xCF, 0xAE, 0x53, 0x79, 0x1D, 0x55, 0xED, 0xC5, 0x02, 0xA4, 0x66, 0x22, 0x3B, 0x3A, 0x07, 0x78, 0xF3, 0x4E, 0xAC, 0x2F, 0x23, 0x79, 0xC5, 0x1F, 0x13, 0xFA, 0xD0, 0xF3, 0xFA, 0x59, 0x00, 0xA8, 0x56, 0x7C, 0x6D, 0x4D, 0x9E, 0x3F, 0xF6, 0x7B, 0x0E, 0x0C, 0x62, 0x97, 0x7D, 0x63, 0xCD, 0x42, 0x58, 0xF9, 0x72, 0x16, 0x60, 0xC9, 0xD1, 0x29, 0x6C, 0xE0, 0x27, 0x76, 0xD9, 0x68, 0x96, 0x1F, 0xC1, 0xB6, 0xC8, 0x65, 0x65, 0x8F, 0xB3, 0x2A, 0x47, 0x58, 0x80, 0x54, 0x2A, 0xBC, 0x57, 0xFF, 0xF4, 0x0E, 0x00, 0x5C, 0x53, 0xE2, 0xEF, 0xE6, 0xCA, 0xB1, 0xFE, 0xA9, 0xAC, 0x55, 0x0A, 0xDB, 0x43, 0x8A, 0x05, 0x7E, 0xED, 0x7A, 0x67, 0x36, 0x60, 0x34, 0x1B, 0x92, 0xD3, 0x80, 0xFC, 0x71, 0x99, 0xBD, 0x5D, 0xCA, 0xDF, 0x2D, 0x99, 0xC5, 0x06, 0x95, 0xB0, 0x53, 0xE4, 0xD8, 0xDE, 0x93, 0x1A, 0x93, 0x7F, 0x1A, 0x9F, 0x83, 0x58, 0xFA, 0xFF, 0x66, 0x9B, 0x01, 0xB2, 0x5D, 0x1D, 0xDB, 0x66, 0x15, 0xD0, 0x46, 0xAC, 0xB3, 0x32, 0x49, 0x80, 0x4C, 0x12, 0x3D, 0xA6, 0xE9, 0xAD, 0x61, 0xDD, 0xC9, 0x7E, 0x21, 0xC3, 0x26, 0x93, 0x93, 0x16, 0x6A, 0x2E, 0x24, 0xD7, 0xB4, 0x1F, 0x3C, 0x9F, 0xCC, 0xBA, 0x34, 0x58, 0xBC, 0x8A, 0x5A, 0x8F, 0xFC, 0xDC, 0x49, 0x65, 0xE4, 0xDF, 0xCD, 0x81, 0xFE, 0xF0, 0xEB, 0x7B, 0x08, 0x5B, 0x93, 0x43, 0x76, 0x7C, 0x5C, 0x35, 0x8F, 0x94, 0x1E, 0x26, 0xEE, 0x7B, 0x3D, 0xE4, 0xFA, 0x52, 0x5E, 0xAC, 0xC4, 0x0E, 0xA0, 0xED, 0x76, 0x91, 0xC3, 0xBA, 0x03, 0x3D, 0xF2, 0xC4, 0xF7, 0x0F, 0x00, 0x43, 0x68, 0xBE, 0x02, 0x59, 0x95, 0x51, 0x3D, 0xC9, 0xA9, 0x17, 0x86, 0x5C, 0x24, 0x03, 0x63, 0xB5, 0x3E, 0x92, 0x69, 0xC5, 0x23, 0x5E, 0x89, 0x7D, 0x89, 0x1E, 0xD4, 0x84, 0xB4, 0x0F, 0xA5, 0xAE, 0x6C, 0xCB, 0x47, 0xFF, 0xDC, 0xC7, 0xE3, 0x30, 0xB2, 0x93, 0x6C, 0xB5, 0x16, 0xD9, 0x7D, 0xDC, 0x15, 0x0B, 0x80, 0xFB, 0x6E, 0x67, 0x0C, 0x9E, 0xB7, 0xA8, 0xB2, 0x4A, 0xAB, 0xD9, 0x5E, 0x49, 0x80, 0x9C, 0x98, 0x47, 0x75, 0x2D, 0x06, 0x34, 0x97, 0xD3, 0x3E, 0x7A, 0x77, 0x1F, 0xA3, 0x46, 0xDA, 0x6A, 0x8C, 0x98, 0x4D, 0x7A, 0x66, 0x8D, 0x31, 0x24, 0xD3, 0xFD, 0x0C, 0xBE, 0x88, 0x7D, 0x5D, 0x12, 0x79, 0xE7, 0x35, 0xD7, 0x53, 0xFF, 0xCA, 0x76, 0x31, 0x60, 0x81, 0xEF, 0x79, 0x64, 0xF3, 0xEB, 0x77, 0xE5, 0xC8, 0x5E, 0x7A, 0x37, 0x0A, 0x48, 0xB9, 0x07, 0xC7, 0x9E, 0x90, 0x6A, 0x6D, 0x45, 0x6F, 0x67, 0xB8, 0x6E, 0x9F, 0x2B, 0xAC, 0xDA, 0x19, 0x56, 0xCE, 0x10, 0x90, 0xFF, 0x4D, 0xCC, 0xBD, 0xB2, 0x01, 0xF5, 0x1A, 0x71, 0x9E, 0xFA, 0x2A, 0xE8, 0x8D, 0x12, 0xB9, 0x15, 0x18, 0x17, 0x6D, 0x21, 0xB6, 0x5B, 0x19, 0x2D, 0x2D, 0xD2, 0xBF, 0x47, 0xDB, 0x99, 0x3B, 0xCC, 0x6B, 0x45, 0x7E, 0xBB, 0x26, 0xD6, 0xEE, 0x6C, 0xAE, 0x3B, 0x2A, 0x95, 0xED, 0x3B, 0x85, 0x6D, 0xAD, 0x79, 0x77, 0x08, 0xD9, 0x3B, 0xE6, 0xF6, 0x49, 0xB2, 0x8F, 0xE5, 0xD1, 0x38, 0x72, 0xC8, 0x1D, 0xCE, 0x85, 0x9A, 0x97, 0xC5, 0x79, 0x68, 0x0B, 0x3E, 0x7E, 0x77, 0x56, 0x23, 0x9D, 0x55, 0xCA, 0x03, 0xFA, 0x96, 0x89, 0xEF, 0x6B, 0x01, 0xC3, 0x78, 0xAA, 0x89, 0xE9, 0x97, 0xC8, 0xE1, 0xDF, 0xA6, 0x6F, 0x24, 0xED, 0xBF, 0xCF, 0xAC, 0x27, 0x73, 0x52, 0xA7, 0xCF, 0x11, 0xFD, 0x8B, 0xC9, 0xAB, 0x41, 0x22, 0xD7, 0x35, 0x6B, 0xF6, 0xED, 0x12, 0x39, 0x2C, 0xF3, 0xF1, 0x4B, 0x52, 0x41, 0xF5, 0xF6, 0x4F, 0x72, 0xC0, 0x80, 0x32, 0x3D, 0x72, 0xE4, 0xAD, 0x83, 0x4D, 0x48, 0x3D, 0x85, 0x82, 0xC7, 0xA4, 0x6E, 0x08, 0xE7, 0x72, 0x50, 0xEF, 0xFE, 0xEC, 0x08, 0x39, 0xD6, 0xF6, 0x23, 0xAB, 0xE4, 0x01, 0xE8, 0x6C, 0xFB, 0x3D, 0x9F, 0xEE, 0x20, 0x87, 0x1D, 0x72, 0x54, 0x24, 0x9D, 0x56, 0xB9, 0x8C, 0x24, 0x73, 0x57, 0x7B, 0xC8, 0x71, 0xFD, 0xC5, 0xC3, 0xDF, 0x2A, 0x93, 0xB3, 0x76, 0x56, 0x5D, 0x21, 0xAD, 0xFB, 0x9C, 0xFA, 0x46, 0xEA, 0xDB, 0x1E, 0x49, 0x21, 0xC7, 0xF5, 0x2E, 0xCA, 0x21, 0x4D, 0x6F, 0x64, 0x8E, 0x21, 0xCD, 0x16, 0x6C, 0x4F, 0x22, 0x2D, 0x47, 0xFD, 0xAD, 0x0F, 0xB5, 0x54, 0x76, 0xDC, 0x6E, 0x76, 0x46, 0x3A, 0xEB, 0xFE, 0x95, 0x35, 0x19, 0x0A, 0x18, 0xBA, 0x70, 0x3F, 0xAB, 0xD4, 0x48, 0xBB, 0x51, 0x01, 0xAD, 0xBF, 0x2C, 0x00, 0xB2, 0xAB, 0x57, 0x7F, 0x78, 0xE0, 0x04, 0x9A, 0x1D, 0xBD, 0x38, 0xEA, 0x46, 0xFA, 0xA4, 0x1F, 0xCD, 0x22, 0xE7, 0xAE, 0xCC, 0x7B, 0x41, 0x4E, 0xD7, 0xD8, 0xE1, 0x40, 0x3A, 0x74, 0xD8, 0x99, 0x41, 0xCE, 0x78, 0xB8, 0xAD, 0x2D, 0x39, 0x33, 0x2C, 0xBA, 0x3B, 0xE9, 0x20, 0xAE, 0x23, 0xC5, 0x4A, 0xAE, 0xA3, 0x63, 0xCB, 0x5A, 0x38, 0xB0, 0x4B, 0xAB, 0xD8, 0xE0, 0xDF, 0x5D, 0x3D, 0x08, 0x50, 0x93, 0x11, 0xFB, 0xDE, 0x02, 0xB8, 0xE4, 0x9E, 0xFF, 0x00, 0xC8, 0x74, 0xD9, 0xD2, 0xAE, 0xF8, 0x0E, 0xB0, 0x3E, 0x31, 0x61, 0xEC, 0xCE, 0xAF, 0xC0, 0xDB, 0x71, 0x5B, 0x3A, 0x04, 0xC6, 0x81, 0x66, 0x3A, 0xEB, 0x57, 0x29, 0x92, 0x6B, 0x75, 0xD6, 0xD9, 0x92, 0xCB, 0xBD, 0x43, 0x86, 0xF3, 0xBD, 0xE1, 0x55, 0x27, 0xC8, 0x65, 0x53, 0x7C, 0xFC, 0xC8, 0xA5, 0xA9, 0x46, 0x4F, 0xC8, 0x15, 0x17, 0xC5, 0xB5, 0xED, 0xCB, 0x75, 0x0C, 0x8D, 0x58, 0x6F, 0x15, 0x36, 0x36, 0x99, 0x4D, 0xEE, 0xCA, 0xEE, 0x5D, 0x41, 0x56, 0xBF, 0xC9, 0x7C, 0x0E, 0x98, 0xC7, 0xA5, 0xEE, 0xF2, 0x7D, 0x02, 0x84, 0x9D, 0x57, 0x5D, 0x2F, 0xE1, 0xDD, 0xDF, 0xB0, 0xD8, 0xAF, 0xD5, 0xF2, 0x4E, 0x46, 0x47, 0x8E, 0x15, 0x85, 0x00, 0x9D, 0xCC, 0xEB, 0xEB, 0x73, 0xA6, 0x81, 0x67, 0x5A, 0x67, 0xD9, 0xAD, 0x27, 0xD9, 0xF8, 0x95, 0x6C, 0x5C, 0x7F, 0x76, 0xC3, 0x3A, 0x36, 0xF2, 0xA6, 0xB8, 0xB6, 0x9B, 0x83, 0x7F, 0x36, 0x9C, 0x4D, 0x76, 0x62, 0xD3, 0x5B, 0xB2, 0x07, 0x12, 0xC9, 0x87, 0xD1, 0x15, 0xBD, 0xC8, 0x63, 0x3F, 0xCE, 0xDC, 0x07, 0xB4, 0x9F, 0xAD, 0x5B, 0x57, 0xBA, 0x0A, 0xF0, 0xBD, 0x00, 0x44, 0xBD, 0x1C, 0x90, 0xB7, 0xF3, 0x10, 0x90, 0xB4, 0xF1, 0xE8, 0xA4, 0xA4, 0xDE, 0x40, 0xD0, 0x21, 0xB1, 0xAF, 0x07, 0xC0, 0xEC, 0x53, 0x62, 0xE5, 0x1B, 0x03, 0x68, 0xB6, 0x15, 0xF5, 0x2C, 0x01, 0xC9, 0x4D, 0x22, 0xF7, 0xC8, 0x01, 0x5D, 0x77, 0x8B, 0xED, 0xA1, 0x40, 0x37, 0x6D, 0xF1, 0x8E, 0xD8, 0x86, 0x73, 0x50, 0xA8, 0xB7, 0xB8, 0x66, 0x3E, 0x81, 0x7B, 0x77, 0x64, 0x77, 0x4B, 0x90, 0xEF, 0xAD, 0xCA, 0xB6, 0x91, 0xD5, 0x51, 0x17, 0xAD, 0xC9, 0x72, 0xF5, 0xDB, 0xC5, 0x64, 0xF6, 0xD7, 0xC7, 0x05, 0x80, 0xEC, 0xAA, 0x79, 0x57, 0xAB, 0xEB, 0x00, 0xD7, 0xE1, 0x40, 0xE5, 0x21, 0x93, 0xE4, 0xF0, 0xC9, 0xC0, 0xAD, 0xE2, 0xF3, 0xDA, 0x41, 0xE7, 0x81, 0xD3, 0xB7, 0xC5, 0x79, 0xAE, 0x03, 0x0E, 0x27, 0x89, 0xEB, 0x56, 0x98, 0x2E, 0x72, 0x98, 0xFB, 0x5B, 0xC0, 0xAF, 0x8C, 0xE7, 0x30, 0xFE, 0x41, 0xE2, 0xF9, 0x91, 0x07, 0x96, 0x27, 0xD1, 0xE7, 0x1D, 0x00, 0x0F, 0x33, 0xE1, 0xDB, 0xBF, 0xFB, 0xFB, 0xF5, 0x0E, 0xE4, 0x8B, 0x80, 0xC3, 0xB9, 0xE4, 0xFD, 0xE6, 0x57, 0x1F, 0x93, 0x67, 0xAF, 0x3C, 0x98, 0x4D, 0x96, 0x0C, 0xAA, 0xD7, 0x25, 0x13, 0xDC, 0x7F, 0x9F, 0x03, 0x88, 0x9C, 0x21, 0xE9, 0x37, 0x3E, 0x0C, 0xF4, 0xEE, 0x44, 0x7D, 0xC9, 0x15, 0x72, 0xEF, 0xF3, 0xF9, 0x77, 0x49, 0xFA, 0xBB, 0x42, 0xE0, 0x99, 0x82, 0xC8, 0xFE, 0x5B, 0x3B, 0x5C, 0xBD, 0x2D, 0xF2, 0x98, 0xD1, 0x5E, 0xE0, 0x88, 0xB8, 0xC6, 0x6D, 0xBE, 0x0A, 0xE7, 0x8B, 0xDC, 0xA1, 0x05, 0x14, 0x88, 0xFE, 0x66, 0x18, 0x03, 0x69, 0x4B, 0x84, 0x39, 0xA2, 0x7E, 0x24, 0x00, 0x3C, 0xD3, 0x3D, 0xBC, 0x96, 0xBC, 0xDF, 0xE7, 0xDA, 0x61, 0xF2, 0x42, 0x69, 0xED, 0x4F, 0x72, 0x5F, 0x16, 0xD7, 0x8D, 0x28, 0x63, 0x17, 0x4A, 0xB3, 0x0A, 0x7B, 0xC9, 0x71, 0xFB, 0x7E, 0x13, 0x13, 0xCC, 0xA1, 0xA5, 0xE3, 0x26, 0x74, 0xBB, 0x2C, 0x8E, 0xA8, 0x52, 0xE3, 0x80, 0xEE, 0x63, 0xEA, 0x03, 0xB5, 0xE3, 0x0F, 0xFF, 0xC3, 0xBC, 0x63, 0x33, 0xF0, 0xB2, 0x87, 0xB8, 0x06, 0x14, 0x81, 0xBB, 0x9F, 0xC4, 0xEF, 0x8F, 0x4F, 0xC0, 0x75, 0xF1, 0x9A, 0xA7, 0xFC, 0x52, 0xA1, 0x4C, 0xF3, 0x8F, 0x67, 0xAF, 0xCB, 0xF8, 0x3E, 0x98, 0xEB, 0xB5, 0x7D, 0x64, 0x65, 0xBB, 0x67, 0x47, 0xC8, 0x43, 0xF2, 0xBC, 0x97, 0xF0, 0x54, 0xD6, 0xA9, 0x8C, 0x35, 0x9D, 0xCC, 0x02, 0xA4, 0xF6, 0x76, 0x72, 0xF0, 0x98, 0x3E, 0x2F, 0xC9, 0xF0, 0x11, 0x12, 0xC7, 0xC9, 0x0D, 0xF5, 0x6D, 0x17, 0xB7, 0xAB, 0xE4, 0x3E, 0xDA, 0xB9, 0xB3, 0x0A, 0x71, 0x2C, 0x40, 0xCA, 0x5B, 0xB1, 0xFD, 0xB7, 0x03, 0x4F, 0x44, 0xE2, 0x1C, 0x10, 0x74, 0xAF, 0xFE, 0x6A, 0x0C, 0x00, 0x54, 0x0D, 0x7D, 0x99, 0x41, 0x1E, 0x1B, 0xC1, 0x8F, 0x8E, 0x3E, 0xCD, 0x3A, 0x45, 0xB1, 0x06, 0x2D, 0xD9, 0x9E, 0xB7, 0x59, 0x80, 0x25, 0xB5, 0x53, 0xD9, 0xB5, 0xDD, 0x58, 0x2F, 0x99, 0x3F, 0x5F, 0xE7, 0x9B, 0x7E, 0x65, 0xDB, 0x0F, 0x62, 0xEF, 0xD5, 0xBF, 0x3C, 0x06, 0x00, 0xA7, 0x8E, 0xFF, 0x9E, 0x83, 0xF7, 0xB1, 0xF3, 0x36, 0xB3, 0x86, 0x76, 0x6C, 0x87, 0x8E, 0x2C, 0xF0, 0x6B, 0xD7, 0xA8, 0xB1, 0x01, 0x32, 0xEC, 0xDA, 0xEB, 0x0D, 0xCF, 0x1F, 0x15, 0xC9, 0xBC, 0x95, 0xDE, 0x95, 0x5D, 0x72, 0x9C, 0x35, 0x2E, 0x64, 0x3B, 0x66, 0xFC, 0x5F, 0xE5, 0xA0, 0x5F, 0xED, 0xB5, 0xAD, 0x06, 0xD0, 0x56, 0x83, 0xB6, 0xBB, 0xAA, 0x77, 0x55, 0x17, 0xB3, 0x1D, 0x5F, 0x5D, 0x34, 0xF5, 0x15, 0xEB, 0xEC, 0x3B, 0x7B, 0x39, 0x7E, 0xDC, 0xEA, 0xCD, 0xB2, 0x67, 0xC9, 0xDD, 0xE7, 0x64, 0x66, 0x92, 0x4F, 0x8F, 0x4B, 0xD4, 0x92, 0xE2, 0xB1, 0x55, 0xEC, 0xAF, 0xBF, 0xEA, 0xA6, 0xB2, 0x8F, 0xF6, 0xB0, 0xBF, 0xEE, 0xA3, 0x7D, 0x06, 0x20, 0x41, 0x29, 0x19, 0xD2, 0x5B, 0xBA, 0x3E, 0x26, 0x15, 0x27, 0xF4, 0x15, 0xEF, 0x22, 0x64, 0x5F, 0xCE, 0xD6, 0xE2, 0xC7, 0xAD, 0xC9, 0xEE, 0xE3, 0x4C, 0x66, 0xC4, 0x2B, 0x0C, 0x21, 0x5F, 0xEA, 0x49, 0x7F, 0xE4, 0x7D, 0x4A, 0xA8, 0xFD, 0xAA, 0xFE, 0x17, 0x4B, 0xF6, 0xD9, 0x35, 0xF6, 0x5E, 0xFD, 0x9F, 0xF5, 0xD1, 0xF1, 0x37, 0xA0, 0x03, 0xE5, 0x3F, 0xB4, 0x74, 0xEE, 0x3D, 0x80, 0xEC, 0x17, 0xA1, 0x60, 0x48, 0x9A, 0x9B, 0xF6, 0x5F, 0x4B, 0x06, 0x56, 0x28, 0x65, 0x93, 0xBB, 0xC2, 0xFB, 0x5C, 0x17, 0xE7, 0xE0, 0xC1, 0xAB, 0x65, 0xF2, 0x2F, 0x78, 0x9F, 0x32, 0x37, 0xFE, 0xB9, 0xFE, 0x4F, 0x0D, 0xF6, 0x65, 0x31, 0x5B, 0xBD, 0x85, 0xBD, 0xB9, 0xEB, 0x57, 0x7D, 0x48, 0xEC, 0x60, 0x25, 0x53, 0x80, 0x4E, 0xD3, 0xC4, 0x67, 0x16, 0x7E, 0x02, 0x4A, 0x77, 0xE8, 0xE7, 0xBD, 0xEE, 0x0F, 0x58, 0x46, 0x9A, 0x87, 0xAA, 0x8D, 0x21, 0x57, 0xA8, 0x0F, 0x76, 0x22, 0xD3, 0x57, 0x0D, 0xE9, 0x27, 0x1E, 0xBF, 0xA0, 0x2E, 0x4A, 0xE5, 0xF7, 0x3C, 0xA8, 0x68, 0xCA, 0x4A, 0xE4, 0xB0, 0xC0, 0x2B, 0x17, 0xB6, 0xFA, 0x2E, 0x7B, 0xD3, 0x83, 0x6C, 0xD2, 0xEC, 0xAC, 0x21, 0xD9, 0x31, 0xFA, 0x5F, 0xFB, 0x90, 0x93, 0x62, 0x25, 0xCB, 0x01, 0xE9, 0x37, 0x22, 0x8F, 0x99, 0x02, 0xB2, 0x0F, 0xE8, 0xE7, 0x5D, 0xAC, 0xB4, 0xA7, 0x91, 0x23, 0x8C, 0x0C, 0x32, 0xC8, 0xF9, 0x93, 0x74, 0xF5, 0xC8, 0xF4, 0x00, 0xFD, 0x1F, 0xE2, 0xDF, 0x2B, 0xFD, 0x2E, 0x37, 0x64, 0x29, 0xD7, 0x1D, 0x7E, 0xF2, 0xF5, 0x24, 0x52, 0x79, 0xD4, 0x73, 0x53, 0x12, 0xB8, 0xE3, 0x41, 0xB6, 0x19, 0x72, 0xEE, 0x0A, 0x29, 0xFD, 0xEA, 0x68, 0x0C, 0xD9, 0x4B, 0xF6, 0xD0, 0x46, 0x52, 0xDE, 0xF7, 0xEF, 0x9E, 0x07, 0x59, 0x56, 0xD1, 0x8A, 0x1D, 0x72, 0x0C, 0x68, 0x2E, 0xEA, 0xCB, 0x5E, 0x03, 0x94, 0x5E, 0x8A, 0xB9, 0xA4, 0x0A, 0xA0, 0x4B, 0x77, 0x9D, 0xA1, 0xBE, 0xD5, 0xF2, 0x24, 0x39, 0x7B, 0x9D, 0x75, 0x11, 0x99, 0x35, 0xD4, 0xA6, 0x59, 0xFD, 0x00, 0xE0, 0xBD, 0xFE, 0xB4, 0x9C, 0x07, 0x86, 0xA0, 0x59, 0x8E, 0xFB, 0x65, 0x3B, 0xD2, 0xE0, 0xC5, 0xF9, 0x9F, 0xA4, 0xCC, 0xC4, 0xC3, 0x99, 0x64, 0xFF, 0x73, 0x07, 0x1D, 0xC8, 0x41, 0x55, 0xBB, 0xBE, 0x93, 0x23, 0x64, 0x53, 0x8E, 0xF1, 0x3D, 0x63, 0x91, 0xA9, 0x97, 0x82, 0xF3, 0xE9, 0x7C, 0x56, 0x23, 0x8A, 0x35, 0xB8, 0xC9, 0x4E, 0x55, 0x66, 0x07, 0xEA, 0x00, 0xA3, 0x29, 0xFF, 0xA2, 0x65, 0xC2, 0xFC, 0x11, 0x1F, 0xF6, 0x01, 0x36, 0x3F, 0x5C, 0x8F, 0xDD, 0x1A, 0x0C, 0x24, 0x6C, 0x73, 0x6F, 0x79, 0xF9, 0x1A, 0x70, 0xA7, 0xE7, 0xC2, 0x4D, 0x87, 0xFB, 0x83, 0x66, 0x6B, 0x9E, 0x85, 0x29, 0xA4, 0xBD, 0x6B, 0xC6, 0x19, 0x52, 0xBF, 0x3C, 0xC9, 0x94, 0x34, 0x96, 0xDF, 0x51, 0x40, 0x1A, 0xFC, 0xC8, 0xB0, 0x24, 0xF5, 0xA7, 0xC4, 0xE7, 0x90, 0xC6, 0x62, 0x4E, 0xD7, 0xC3, 0x19, 0x7C, 0x1E, 0x96, 0xB2, 0x7A, 0xE6, 0xAC, 0x79, 0x29, 0x3B, 0xAF, 0x8A, 0x0D, 0xDA, 0x44, 0x3E, 0xED, 0x62, 0x63, 0x0A, 0x4C, 0xB9, 0x5D, 0x94, 0x00, 0x74, 0x29, 0x59, 0x1F, 0xB7, 0x43, 0x0A, 0xF0, 0xAC, 0x5F, 0xDF, 0x77, 0x43, 0x04, 0x50, 0xBA, 0x2B, 0xE4, 0xF5, 0xAA, 0x38, 0x50, 0x76, 0x92, 0x5C, 0xF9, 0x9D, 0xF4, 0x2F, 0x5D, 0x7A, 0x84, 0x9C, 0xEF, 0xE1, 0x11, 0x4C, 0xBA, 0x47, 0x2D, 0xF2, 0x23, 0x5D, 0x67, 0x2E, 0xBD, 0x4D, 0xCE, 0x75, 0x9D, 0xB3, 0x85, 0x74, 0xDE, 0xF4, 0xB7, 0x5C, 0x38, 0x74, 0x2B, 0x3B, 0x21, 0x81, 0xF5, 0x52, 0x60, 0xE3, 0xAE, 0x90, 0xAF, 0x7E, 0xEE, 0xF0, 0x24, 0xCF, 0xA9, 0x26, 0xBC, 0x01, 0xB4, 0x6C, 0x62, 0xC2, 0x5C, 0xEA, 0x80, 0xE5, 0x63, 0xFB, 0x5F, 0xEF, 0x32, 0x4A, 0x3E, 0x23, 0x6D, 0x71, 0xA7, 0x74, 0xD9, 0xEA, 0x84, 0x4D, 0xA9, 0x95, 0x80, 0x54, 0xB0, 0xC8, 0x10, 0xF2, 0xE0, 0x2C, 0xB3, 0x8F, 0x8D, 0xD1, 0x66, 0xA3, 0xB4, 0xD8, 0x70, 0x69, 0x36, 0x64, 0x19, 0xBB, 0x6E, 0x97, 0x78, 0xCE, 0x0E, 0x80, 0xE7, 0xA5, 0x46, 0xEC, 0xA6, 0x73, 0x20, 0x6D, 0xB6, 0x65, 0x91, 0x77, 0x8A, 0xD2, 0x9E, 0x92, 0xE7, 0x3E, 0x15, 0x77, 0x21, 0x8B, 0x9C, 0x0F, 0xE9, 0x00, 0x3D, 0xF2, 0x7D, 0x7C, 0xB3, 0xB2, 0x00, 0xC7, 0x7A, 0xC0, 0x7F, 0xAD, 0x5C, 0xDF, 0xD8, 0x02, 0x20, 0xBC, 0x72, 0xAB, 0x7B, 0x88, 0x99, 0x70, 0x85, 0x38, 0x77, 0x83, 0x01, 0xBF, 0x87, 0x22, 0x87, 0xF4, 0x07, 0xCC, 0xC4, 0xC4, 0x20, 0xD0, 0x1C, 0x50, 0x16, 0x2B, 0xC3, 0xDA, 0x3C, 0xA0, 0x33, 0xFD, 0x3D, 0x8C, 0x2C, 0xD0, 0x65, 0xA5, 0xD8, 0xFE, 0xC0, 0x39, 0x68, 0x65, 0x1B, 0x71, 0x8D, 0xA8, 0x72, 0xFD, 0x54, 0x09, 0x76, 0x6B, 0x08, 0x79, 0xED, 0x7E, 0x56, 0x0C, 0x79, 0x52, 0xAF, 0x78, 0x06, 0x59, 0x94, 0x50, 0xBE, 0x8F, 0x4C, 0x59, 0x7D, 0xE3, 0x3B, 0x39, 0xC7, 0xFA, 0x92, 0x3C, 0x60, 0x7E, 0x1C, 0x38, 0x32, 0x57, 0x7B, 0x82, 0x5F, 0x13, 0xE0, 0xD8, 0x83, 0x1D, 0x86, 0x8B, 0x9F, 0x00, 0x47, 0xC5, 0xFA, 0xE9, 0xD1, 0x16, 0x28, 0x39, 0x28, 0xE6, 0x91, 0x2B, 0x81, 0x64, 0x27, 0x91, 0x2F, 0x06, 0x00, 0x71, 0x22, 0x09, 0xD0, 0x6F, 0xE2, 0x08, 0x6B, 0x91, 0x8F, 0x5D, 0x01, 0xFF, 0x79, 0xE2, 0x79, 0x19, 0x07, 0x2C, 0xF5, 0x13, 0x16, 0x89, 0xCC, 0x78, 0x15, 0x00, 0xBE, 0xFF, 0x4C, 0xCE, 0x24, 0xAF, 0x78, 0xE4, 0xCD, 0x26, 0x8F, 0x1C, 0x2F, 0xDA, 0x4D, 0x16, 0xAA, 0x9D, 0x6B, 0x4E, 0x26, 0xAD, 0x79, 0x90, 0x40, 0xAE, 0x8B, 0x7D, 0x37, 0x96, 0x9C, 0xDA, 0x8C, 0xEE, 0x5B, 0x0D, 0x1D, 0x0F, 0xBC, 0xED, 0x36, 0xE6, 0x86, 0xE3, 0x70, 0xE0, 0xBD, 0x4D, 0x9A, 0xF9, 0xB4, 0x62, 0xB1, 0x2D, 0xF2, 0xA0, 0xDD, 0xED, 0xD6, 0x29, 0xF7, 0x44, 0xFE, 0x31, 0xD8, 0x04, 0x5C, 0xF0, 0x12, 0xC7, 0xBA, 0x19, 0x38, 0x21, 0x56, 0xF0, 0xD1, 0xF3, 0x80, 0x43, 0x6F, 0xC4, 0xAC, 0xB6, 0x0A, 0xD8, 0xE3, 0x20, 0xF2, 0x91, 0x16, 0x90, 0xF1, 0x52, 0x5C, 0x0B, 0xE3, 0x3E, 0x79, 0x6E, 0xA5, 0xE3, 0xC5, 0x45, 0xB3, 0x82, 0x8D, 0x64, 0xD9, 0xAE, 0xC2, 0x49, 0x64, 0xE1, 0xC7, 0xF3, 0xE6, 0x64, 0x5A, 0xE6, 0xBB, 0x7C, 0x72, 0x35, 0x7F, 0x1E, 0x09, 0x8E, 0x07, 0x59, 0x63, 0x1F, 0xB2, 0xE7, 0x25, 0xD0, 0xAB, 0xB0, 0xA5, 0xBE, 0x99, 0xE4, 0x0F, 0x71, 0x44, 0x6F, 0x07, 0x6E, 0xFA, 0xC7, 0xFB, 0x62, 0x9A, 0x57, 0xD8, 0xBE, 0x81, 0xC0, 0xB3, 0x09, 0xE2, 0xB5, 0xB0, 0x1A, 0xB8, 0xBB, 0x58, 0xCC, 0x9E, 0xAF, 0x00, 0xD7, 0x4A, 0xC4, 0x6B, 0xB0, 0x1D, 0x70, 0xAE, 0x8B, 0x48, 0x30, 0xB2, 0x17, 0xAB, 0xF3, 0x6C, 0x00, 0xA0, 0xF4, 0x50, 0xBE, 0x0B, 0xB9, 0xE7, 0xD0, 0xF9, 0x77, 0x64, 0xCE, 0xC2, 0x9F, 0xC9, 0xA4, 0x7F, 0x00, 0xEF, 0x75, 0xDA, 0x5B, 0x76, 0x54, 0x39, 0x3B, 0xF0, 0x10, 0x4B, 0x2B, 0x8C, 0x71, 0x2A, 0x40, 0x9F, 0x26, 0x58, 0x53, 0xD7, 0xA4, 0x2D, 0xE8, 0x6A, 0x5C, 0xD2, 0xCC, 0xA7, 0xD5, 0xE2, 0x7F, 0xB7, 0xBE, 0x36, 0xBB, 0xCB, 0x76, 0xBC, 0x0A, 0xBC, 0x11, 0x93, 0x1F, 0x19, 0xCF, 0xA3, 0x93, 0x0B, 0x6E, 0x02, 0xC0, 0x7E, 0x9C, 0xEF, 0x49, 0xEE, 0x79, 0xCF, 0x8F, 0x0E, 0x3C, 0xCF, 0x4E, 0x6D, 0xCE, 0x0E, 0x19, 0xCC, 0x4A, 0x7E, 0x63, 0x81, 0x7F, 0x35, 0x44, 0x82, 0xF5, 0xDC, 0x0D, 0x70, 0x9D, 0x86, 0x5B, 0x5A, 0x7C, 0xFE, 0x38, 0x00, 0x94, 0x65, 0xF2, 0x77, 0xD7, 0x5E, 0x64, 0xA7, 0xAF, 0x60, 0x07, 0x9E, 0x60, 0x7F, 0x53, 0x62, 0x81, 0x5F, 0x1B, 0xDC, 0x8C, 0xF5, 0x8F, 0x62, 0xC3, 0xD9, 0x06, 0xF5, 0x51, 0x56, 0xFF, 0x79, 0x08, 0x00, 0x84, 0x73, 0xFE, 0x83, 0x43, 0x2E, 0xAB, 0xAE, 0xCC, 0xA2, 0xEC, 0xFF, 0x37, 0x07, 0xB1, 0xAC, 0xDC, 0x43, 0x56, 0xC7, 0x8E, 0x9D, 0xB2, 0x8D, 0xF5, 0x4F, 0x64, 0x77, 0x47, 0xB3, 0x77, 0xBB, 0xB3, 0x0D, 0xF9, 0x7A, 0xDF, 0x9C, 0x7D, 0xE2, 0xC6, 0x36, 0xA4, 0x8F, 0x9E, 0x52, 0xAC, 0x4E, 0x18, 0x6B, 0x77, 0x9D, 0xF5, 0xF5, 0x60, 0xB3, 0x16, 0xB3, 0x55, 0x65, 0x7F, 0x5E, 0xFF, 0xE3, 0x04, 0xF6, 0xE9, 0x19, 0xB6, 0x6A, 0x45, 0xC3, 0xFB, 0xE8, 0xB4, 0xB1, 0xD9, 0x48, 0x52, 0xC7, 0x1A, 0x20, 0x6D, 0xB4, 0x58, 0xEF, 0x0D, 0x12, 0x13, 0xC9, 0xAC, 0xA7, 0x00, 0x79, 0x6B, 0xFC, 0xAF, 0xEB, 0x7F, 0xE8, 0xCC, 0xD6, 0x5E, 0x64, 0x6F, 0x7D, 0x64, 0xAF, 0x7C, 0x69, 0x78, 0x1F, 0x6D, 0xE6, 0xB5, 0xA9, 0x25, 0xE5, 0x27, 0x4B, 0xDF, 0x16, 0x79, 0x51, 0x6D, 0x92, 0x05, 0x7F, 0xDF, 0x2B, 0xAE, 0xC7, 0x26, 0x32, 0x7D, 0xB1, 0xCC, 0x72, 0xF2, 0xF6, 0xA1, 0x8E, 0x47, 0x79, 0x9F, 0x6D, 0x22, 0x59, 0xE0, 0x7D, 0x0A, 0x5B, 0x13, 0xC4, 0x5E, 0x3F, 0xCA, 0x5E, 0x4C, 0x65, 0xCB, 0xAF, 0xFC, 0x69, 0x1F, 0xB3, 0x81, 0x26, 0x83, 0x44, 0x5D, 0x15, 0xA0, 0x7D, 0x38, 0x7D, 0x5F, 0xCE, 0x57, 0xEE, 0x27, 0xA9, 0xE7, 0xAB, 0xD8, 0x96, 0xF4, 0xDC, 0xA4, 0xF2, 0x81, 0xCC, 0xF8, 0xA8, 0xD4, 0x85, 0xBC, 0x5B, 0xAD, 0xDC, 0xE7, 0xCB, 0x02, 0xD0, 0xFC, 0x47, 0xE3, 0xA1, 0x3C, 0x29, 0x79, 0xA4, 0x3A, 0x9C, 0x04, 0x2E, 0xB9, 0xB2, 0x67, 0xD2, 0xD9, 0xE3, 0x66, 0x6C, 0xD9, 0x2F, 0xF3, 0x69, 0x0B, 0x27, 0x56, 0xA6, 0x98, 0x95, 0x0A, 0x05, 0x3A, 0xD3, 0xBB, 0x1A, 0x34, 0x71, 0xD5, 0x18, 0x42, 0x6A, 0xDA, 0x6B, 0xDF, 0x24, 0x5D, 0x26, 0xEB, 0xA4, 0x7D, 0x32, 0x04, 0x76, 0x6C, 0x1C, 0x99, 0x55, 0x7B, 0x16, 0xA8, 0xB4, 0xD1, 0x9D, 0x7E, 0xA3, 0x16, 0x94, 0x1D, 0xCE, 0x9F, 0xF2, 0x27, 0x35, 0x3E, 0x1C, 0xCD, 0x20, 0x7B, 0x46, 0x1F, 0xBD, 0x40, 0x36, 0xFB, 0x5E, 0x7A, 0x89, 0x94, 0xA8, 0xCD, 0xFA, 0x4E, 0xF6, 0x96, 0xCA, 0x58, 0x02, 0xF2, 0x0F, 0xFA, 0xE8, 0x75, 0x8B, 0x55, 0x96, 0x63, 0xC7, 0x58, 0xB3, 0x4A, 0x7A, 0xC0, 0x80, 0x8A, 0x9F, 0xCD, 0x01, 0xE9, 0xD1, 0xD6, 0x5B, 0x6F, 0x27, 0x00, 0xE6, 0xC1, 0xD6, 0x9D, 0xCB, 0x3B, 0x03, 0xA1, 0x2A, 0x76, 0x01, 0x65, 0x27, 0x81, 0xC3, 0x7A, 0x53, 0x75, 0xF7, 0xF0, 0x67, 0x03, 0xEE, 0x65, 0xC4, 0x91, 0xE6, 0xDE, 0x49, 0xC3, 0x48, 0xDD, 0xDB, 0xDB, 0xE7, 0x90, 0x83, 0x33, 0xB6, 0xF1, 0x7C, 0xAE, 0x20, 0x21, 0x8B, 0x1C, 0x76, 0x3C, 0x76, 0x1A, 0x39, 0x3C, 0xE4, 0x6F, 0xF5, 0x7B, 0xDE, 0x66, 0xFB, 0x5D, 0x63, 0xB5, 0x06, 0xB3, 0xE3, 0xF3, 0xC8, 0x1F, 0xA3, 0x3C, 0x3C, 0xC8, 0xCB, 0xC3, 0x8D, 0x8C, 0x00, 0xA3, 0x09, 0xA9, 0x86, 0x80, 0x74, 0x99, 0x77, 0xD7, 0x18, 0x3B, 0x60, 0x8E, 0xB9, 0x97, 0xC9, 0x2A, 0x69, 0x20, 0x33, 0xCC, 0xC7, 0xD7, 0x67, 0x16, 0xF0, 0x75, 0xE7, 0xF2, 0xD6, 0xCB, 0x8C, 0x41, 0x7F, 0x97, 0xB5, 0xD5, 0x45, 0x9E, 0x74, 0xF6, 0x9E, 0xD9, 0x85, 0x9C, 0xB5, 0xCC, 0xBE, 0x15, 0xE9, 0x30, 0x60, 0x9A, 0x03, 0x69, 0x5F, 0x6F, 0xB5, 0x15, 0x64, 0x95, 0xC8, 0x9D, 0x73, 0xB9, 0x5E, 0xEF, 0xF3, 0xEC, 0xB0, 0xE6, 0xEC, 0x38, 0x5B, 0xF2, 0xB1, 0xE7, 0x92, 0xF3, 0xE4, 0x15, 0xB3, 0x10, 0x19, 0xF2, 0xA0, 0x5D, 0xA8, 0x15, 0xA0, 0x60, 0x1F, 0x78, 0x72, 0xEA, 0x47, 0xC0, 0xB5, 0x50, 0x7E, 0x60, 0xC7, 0x4E, 0xDD, 0xB6, 0xC6, 0xCF, 0x6F, 0xB5, 0xAE, 0xB3, 0x5A, 0x80, 0xD7, 0xA6, 0x4C, 0xA0, 0x8B, 0xD6, 0xAD, 0x94, 0x4D, 0x36, 0x40, 0xDB, 0xF6, 0x22, 0xFF, 0x44, 0xF0, 0xBE, 0xC2, 0xAC, 0xD8, 0x35, 0x03, 0xD9, 0xD5, 0x6E, 0x6C, 0x60, 0x35, 0xEB, 0xF7, 0xE8, 0x6F, 0x79, 0x6C, 0xB0, 0x26, 0x3B, 0xA6, 0x98, 0xBC, 0xBA, 0x20, 0xC0, 0x8F, 0x3C, 0x59, 0x1B, 0x3A, 0x83, 0x2C, 0xC9, 0x4C, 0x5A, 0x44, 0xA6, 0x46, 0xE4, 0x04, 0x03, 0xCD, 0x42, 0xDC, 0x27, 0x6F, 0xA9, 0x03, 0xAC, 0x14, 0x01, 0x8F, 0xD8, 0x2E, 0xEE, 0x6B, 0x8F, 0x03, 0xFE, 0xBE, 0x6B, 0xCD, 0x7C, 0x26, 0x0B, 0xF5, 0xAB, 0x9A, 0x52, 0x96, 0x5B, 0x3A, 0x43, 0xCC, 0x61, 0x8A, 0x01, 0x67, 0x71, 0xAC, 0xF3, 0x6D, 0x80, 0x2E, 0xCB, 0x45, 0x2E, 0x1A, 0x0D, 0x48, 0x89, 0x99, 0xAB, 0xFF, 0x26, 0xB1, 0x1D, 0x2F, 0xE6, 0x66, 0x9F, 0x39, 0x07, 0x79, 0xBA, 0x88, 0x35, 0x58, 0x9A, 0xEB, 0x8F, 0xEC, 0x4B, 0x9E, 0x79, 0xBC, 0x7A, 0x0B, 0x79, 0xE8, 0x72, 0x98, 0x31, 0x99, 0xD7, 0x36, 0xE5, 0x32, 0xB9, 0x3D, 0x21, 0x3F, 0x83, 0x0C, 0xED, 0x77, 0x2C, 0x97, 0xB4, 0x57, 0x38, 0x3C, 0x12, 0xD0, 0x5C, 0x01, 0xE4, 0x25, 0xAB, 0x3E, 0x77, 0x4D, 0x00, 0x0A, 0x57, 0x84, 0xC2, 0x61, 0x25, 0x50, 0x6C, 0x7F, 0xE7, 0xCD, 0xF4, 0xE1, 0x40, 0xB6, 0x98, 0xE1, 0xDA, 0xA6, 0x02, 0x89, 0x2D, 0xC4, 0xA4, 0xE6, 0x13, 0x10, 0xB6, 0x5F, 0xE4, 0x8C, 0x72, 0x60, 0xAD, 0xA2, 0xB8, 0x6E, 0x36, 0x03, 0xAB, 0xD3, 0x85, 0xC5, 0xC0, 0xF2, 0xF6, 0xE2, 0xE7, 0x94, 0x51, 0x1E, 0x03, 0xC0, 0xD1, 0x79, 0x21, 0x89, 0xE4, 0x11, 0xAF, 0x48, 0x6D, 0x72, 0xB7, 0x53, 0x6A, 0x00, 0x99, 0x32, 0xA7, 0x30, 0x8E, 0x0C, 0x92, 0x3A, 0xAF, 0x42, 0xBA, 0x77, 0xBA, 0x39, 0x9D, 0xB4, 0x56, 0xB8, 0x6D, 0x07, 0x48, 0xFF, 0x00, 0xAE, 0xD9, 0x0E, 0x96, 0x34, 0xDB, 0x0E, 0xDC, 0x68, 0x13, 0x2A, 0x63, 0x40, 0xF7, 0xE7, 0xDE, 0x56, 0x2D, 0xD4, 0xF3, 0x00, 0x2E, 0x8B, 0x7B, 0xB2, 0x23, 0x46, 0x00, 0xA7, 0x5B, 0x89, 0xD7, 0xCD, 0x62, 0xA0, 0x74, 0x9D, 0x98, 0x8D, 0x46, 0x02, 0xFB, 0x44, 0x1E, 0x53, 0xCF, 0x00, 0xF2, 0x56, 0x89, 0x4C, 0xEC, 0xC9, 0x9F, 0x0D, 0xD0, 0xD2, 0x3F, 0x96, 0xB5, 0x3A, 0x0B, 0xD4, 0x87, 0x7F, 0xE4, 0x4B, 0x72, 0x57, 0xCB, 0xD4, 0x3A, 0x32, 0x65, 0x72, 0xC1, 0x78, 0x32, 0x38, 0xBC, 0xB2, 0x39, 0xE9, 0x56, 0xF3, 0x22, 0x8E, 0x9C, 0x54, 0xF5, 0xF9, 0x1C, 0x69, 0xA6, 0xF9, 0xB7, 0x2B, 0x5C, 0xD5, 0x7F, 0xD8, 0xD7, 0xD6, 0x1F, 0x44, 0x2A, 0x5D, 0xA7, 0x7C, 0x93, 0xB6, 0x2B, 0xAD, 0xFB, 0x7F, 0x24, 0xC5, 0x6B, 0xEE, 0x24, 0xF0, 0x56, 0xE4, 0x42, 0x99, 0x2C, 0xE0, 0x8E, 0xB8, 0x4F, 0x29, 0xF9, 0x00, 0xA8, 0x14, 0x73, 0x3A, 0xE9, 0xB7, 0xC0, 0x05, 0xF1, 0x9E, 0x55, 0x56, 0x09, 0x28, 0x17, 0xF3, 0x2B, 0xB9, 0x57, 0x65, 0xF5, 0x91, 0x7B, 0x01, 0x20, 0x43, 0x27, 0x75, 0x35, 0x99, 0xEC, 0x9F, 0xF3, 0x9D, 0x0C, 0xAD, 0xBB, 0x39, 0x95, 0x9C, 0xB7, 0xE1, 0x53, 0x2E, 0x69, 0x69, 0xC3, 0x75, 0x07, 0x5F, 0x63, 0x7B, 0x4B, 0xB2, 0x54, 0xAF, 0xF3, 0xD0, 0xB6, 0x77, 0x78, 0xC2, 0x0A, 0x90, 0x71, 0xE1, 0x8D, 0xC9, 0x1F, 0xAF, 0xB4, 0xC8, 0xCC, 0x80, 0x94, 0x51, 0x00, 0xB0, 0x5D, 0x7A, 0xD7, 0x23, 0x32, 0x3E, 0xF0, 0xB5, 0x14, 0xB9, 0xA0, 0x09, 0x3F, 0xCA, 0x6C, 0x12, 0xDB, 0xEF, 0x2D, 0xDB, 0xA4, 0xF6, 0xDF, 0xCC, 0x61, 0x36, 0xB0, 0x2B, 0x03, 0x1B, 0x9F, 0x83, 0xB6, 0xD5, 0x67, 0x3A, 0x01, 0x40, 0x7A, 0xDC, 0xF9, 0x09, 0xE4, 0x92, 0x99, 0xFC, 0x53, 0xF3, 0x1B, 0x6C, 0x8F, 0x02, 0x16, 0xF8, 0x73, 0x83, 0x02, 0x58, 0xBF, 0x30, 0x36, 0x8C, 0x6D, 0x60, 0x1F, 0x67, 0xDD, 0x00, 0xC0, 0xCB, 0x84, 0xBF, 0x6B, 0x71, 0x98, 0xED, 0x61, 0xCA, 0x02, 0x0D, 0xD7, 0xE7, 0x1A, 0x1B, 0x08, 0x36, 0xA8, 0xCB, 0xFF, 0x6C, 0x0E, 0x92, 0xF9, 0xC8, 0xAA, 0x57, 0xB3, 0xD6, 0x99, 0xEC, 0x0A, 0x6F, 0x36, 0xD5, 0x8E, 0xBD, 0xD5, 0xEA, 0xCF, 0xF3, 0xC7, 0x57, 0x39, 0xF6, 0x55, 0x25, 0xFB, 0x70, 0x4F, 0xC3, 0xD7, 0xFD, 0xAE, 0xAB, 0xD8, 0x81, 0x87, 0x59, 0xAB, 0x1C, 0xD6, 0xDF, 0x86, 0xDD, 0x69, 0xC2, 0xDE, 0xEC, 0xF5, 0xEB, 0xFA, 0x5F, 0xBC, 0xD9, 0x17, 0x5F, 0xD8, 0x9B, 0xB2, 0xEC, 0xD5, 0x81, 0x0D, 0xEF, 0xA3, 0xFD, 0x65, 0x76, 0x40, 0x08, 0x6B, 0xFE, 0x98, 0xF5, 0x79, 0xC3, 0xEE, 0x3C, 0xC8, 0x5E, 0xBB, 0xF5, 0xAF, 0xF5, 0x3F, 0x8D, 0x66, 0x1F, 0x97, 0xB1, 0x95, 0xA5, 0xEC, 0x85, 0x1A, 0xB6, 0x7C, 0x6F, 0xC3, 0xFB, 0x68, 0x21, 0xC3, 0xAA, 0x1E, 0x67, 0xC7, 0x4B, 0xB0, 0xCB, 0x82, 0xD9, 0x34, 0x3F, 0xF6, 0xAA, 0x32, 0x4B, 0x5F, 0xEF, 0x6E, 0xB0, 0x77, 0xC6, 0xB0, 0x17, 0xDA, 0xB1, 0xE5, 0x1D, 0xD9, 0x63, 0x26, 0xEC, 0xA1, 0xA1, 0x6C, 0x63, 0xAE, 0x46, 0xD5, 0x93, 0xAC, 0x91, 0x09, 0xBB, 0x68, 0x6C, 0x8B, 0xCF, 0x64, 0x5A, 0x51, 0x8B, 0x85, 0xDF, 0xE5, 0x81, 0x8B, 0x8A, 0x4D, 0x27, 0xD5, 0xA9, 0x80, 0xEE, 0x07, 0x0E, 0xBB, 0xB3, 0x93, 0x04, 0xCE, 0x1F, 0x65, 0x0F, 0x15, 0xB0, 0xFB, 0x73, 0xD9, 0x92, 0x8D, 0x6C, 0xD1, 0xA4, 0x86, 0xF6, 0xF1, 0x5B, 0x3F, 0xE0, 0xB7, 0x14, 0xDA, 0xEE, 0x94, 0x2C, 0x25, 0x72, 0x82, 0xA4, 0x86, 0x5E, 0x6C, 0xCB, 0x84, 0x8F, 0x45, 0x80, 0x4B, 0x9C, 0x7C, 0x49, 0xCD, 0x56, 0x20, 0xA1, 0xB5, 0x92, 0x42, 0xE5, 0x29, 0xE0, 0x70, 0x40, 0xBF, 0xD7, 0x17, 0xFE, 0x33, 0x53, 0xAB, 0x06, 0x1F, 0x8E, 0x25, 0x65, 0x87, 0x1F, 0xB6, 0x21, 0x9B, 0x86, 0x17, 0x7D, 0x23, 0x81, 0xFC, 0xE3, 0x6C, 0xCE, 0x33, 0x36, 0x33, 0xE8, 0xCF, 0xFA, 0x68, 0x16, 0xC0, 0xCA, 0xEB, 0xB0, 0x72, 0x29, 0x40, 0xB7, 0xC0, 0xBB, 0x66, 0x40, 0xF7, 0x37, 0x5A, 0xF9, 0x67, 0xAE, 0x03, 0x46, 0x4A, 0xA3, 0x46, 0xEC, 0xAF, 0x02, 0xFC, 0x2A, 0xF5, 0xB6, 0x14, 0x34, 0x05, 0x0A, 0x14, 0x0C, 0xCE, 0xA4, 0xD7, 0x01, 0xCF, 0xF6, 0x1B, 0xD8, 0x26, 0xAF, 0x03, 0xDD, 0xB7, 0xB4, 0xDC, 0x3A, 0x9C, 0x54, 0x5F, 0xB4, 0x39, 0x8C, 0x94, 0x8B, 0x8A, 0xED, 0x42, 0xF6, 0xAE, 0x88, 0xB2, 0x24, 0x15, 0x2E, 0x86, 0xBE, 0x25, 0x15, 0x95, 0xFE, 0x60, 0x7E, 0x3B, 0x85, 0xED, 0x55, 0xC1, 0x6A, 0xB6, 0x26, 0xAB, 0x7B, 0x5B, 0x5E, 0x27, 0x4B, 0x6D, 0x86, 0x5B, 0x03, 0xC3, 0x2C, 0x36, 0xBE, 0x03, 0xBA, 0xFE, 0x98, 0x9B, 0xBC, 0x7A, 0x02, 0x60, 0xE7, 0xE0, 0xB8, 0x66, 0xD9, 0x44, 0x20, 0xC1, 0xD6, 0x39, 0xDE, 0x5D, 0x11, 0xB8, 0xFC, 0xD6, 0xB9, 0x97, 0xF3, 0x7F, 0xBE, 0x2F, 0x71, 0x3C, 0x34, 0x5D, 0x9F, 0x9C, 0xD1, 0xDD, 0x26, 0x8E, 0xB4, 0x78, 0x32, 0x51, 0x85, 0x9C, 0xB8, 0xC2, 0xFC, 0x19, 0x69, 0xBD, 0xC5, 0xE2, 0x21, 0x69, 0xF1, 0xF0, 0x6F, 0xF5, 0x3B, 0x2D, 0x64, 0x7B, 0xAD, 0x66, 0x07, 0x59, 0x93, 0x37, 0x02, 0x26, 0x14, 0x93, 0x65, 0x73, 0x17, 0x47, 0x91, 0x59, 0x53, 0xE8, 0x5D, 0x4B, 0x07, 0xE9, 0x25, 0x59, 0xE6, 0x41, 0x80, 0xAD, 0x65, 0xDB, 0x9B, 0xF0, 0x69, 0xF9, 0x24, 0xA2, 0x23, 0xD0, 0xAA, 0x8F, 0xD3, 0xD5, 0x30, 0x03, 0xA0, 0xCB, 0xCB, 0x12, 0x8D, 0xA0, 0xF5, 0x80, 0xF4, 0xDD, 0xFA, 0xFA, 0x55, 0x77, 0xC1, 0xB9, 0x47, 0x97, 0x5D, 0x72, 0x99, 0x5D, 0x5C, 0xC0, 0x2E, 0x5A, 0xC5, 0x7A, 0xCC, 0x13, 0xCF, 0xB7, 0x39, 0xF8, 0xBC, 0x27, 0xB2, 0x2A, 0xF7, 0xC8, 0xD2, 0xC7, 0x33, 0xF4, 0xC8, 0x03, 0xEF, 0xFC, 0xDB, 0x93, 0x29, 0x0E, 0x41, 0x6B, 0xC9, 0xE8, 0x85, 0xF1, 0x9B, 0x48, 0x87, 0xE4, 0x90, 0x69, 0x80, 0xAE, 0x3A, 0xE0, 0x10, 0x2E, 0x79, 0x7E, 0x89, 0x32, 0xB0, 0xD0, 0x64, 0xC9, 0x09, 0x97, 0xDF, 0x84, 0x8E, 0xFB, 0xF5, 0xE7, 0xEC, 0x10, 0x8A, 0xC9, 0xC0, 0xEC, 0xE9, 0xC0, 0xEC, 0x15, 0xE2, 0x7E, 0x65, 0x95, 0x7C, 0xA5, 0xDE, 0x17, 0x71, 0xFC, 0xFE, 0x80, 0xB4, 0x83, 0xC8, 0x45, 0xA9, 0x40, 0xB7, 0x77, 0x62, 0xF6, 0x56, 0xC0, 0x39, 0xC8, 0xD9, 0x81, 0xF3, 0x18, 0xF0, 0xE0, 0xA4, 0x8E, 0x3B, 0x79, 0xE0, 0xEA, 0xA2, 0x77, 0xE4, 0x9E, 0x0B, 0x01, 0x57, 0xC9, 0x6D, 0x7B, 0x22, 0x74, 0xC8, 0xB0, 0x89, 0x09, 0x7A, 0xE4, 0x92, 0xBD, 0x59, 0x6B, 0x49, 0x9B, 0x92, 0x02, 0x47, 0x40, 0x6E, 0x29, 0xB0, 0x3D, 0x5F, 0xEE, 0xE3, 0xE4, 0x63, 0x40, 0x5A, 0x0B, 0xEF, 0xF1, 0x13, 0x4A, 0x81, 0xF4, 0xE6, 0x07, 0xCD, 0x8C, 0xC3, 0x80, 0x34, 0x53, 0x91, 0x2D, 0x3F, 0x03, 0x1B, 0x9C, 0x44, 0x7E, 0x37, 0x06, 0x56, 0x64, 0x8B, 0xAC, 0x33, 0x18, 0x58, 0x2E, 0xEA, 0xEB, 0x5E, 0x04, 0x7C, 0x06, 0x88, 0xEC, 0xE7, 0x04, 0x2C, 0x59, 0x2A, 0xB6, 0x71, 0xAF, 0x7E, 0xC4, 0x63, 0x00, 0x38, 0x64, 0xE1, 0x7D, 0x8F, 0x2C, 0xB8, 0x17, 0x38, 0x86, 0xDC, 0x9E, 0x1D, 0xF3, 0x99, 0x0C, 0x7D, 0x9F, 0xF0, 0x85, 0x74, 0x53, 0x2E, 0x7C, 0x41, 0x4E, 0x53, 0x2E, 0x9F, 0x44, 0x5A, 0xBD, 0xBE, 0x10, 0x47, 0x02, 0x27, 0x22, 0xFA, 0x0D, 0xD5, 0x09, 0x07, 0x4E, 0xBB, 0x7A, 0xED, 0xD4, 0x18, 0x01, 0x9C, 0xBA, 0x76, 0xA0, 0xA7, 0xDA, 0x3B, 0x61, 0xB5, 0xC8, 0x3D, 0x6D, 0x80, 0xD2, 0xBE, 0x62, 0x0E, 0xE3, 0x03, 0xE4, 0xCF, 0x17, 0xE7, 0x7C, 0x03, 0x90, 0x9D, 0x20, 0x8E, 0xBD, 0x25, 0x90, 0xA9, 0x26, 0x66, 0xA5, 0xE7, 0x80, 0xED, 0x22, 0x8B, 0x29, 0xE6, 0x94, 0xD5, 0x7B, 0xF5, 0x00, 0x80, 0xBC, 0xA1, 0x01, 0x6A, 0xE4, 0xF6, 0xE2, 0xD8, 0x81, 0x64, 0xCC, 0xB0, 0x1D, 0x25, 0xE4, 0x9C, 0x4F, 0x7B, 0xB2, 0xC9, 0x29, 0x23, 0x2B, 0x65, 0xC8, 0x11, 0xA3, 0x6E, 0x7D, 0x27, 0xD5, 0xDB, 0x3F, 0xDE, 0x45, 0x02, 0xB5, 0xF6, 0x3D, 0x4D, 0x15, 0xFA, 0x00, 0xCF, 0x5A, 0x2E, 0xDE, 0x2D, 0x53, 0x05, 0xBC, 0x88, 0xD8, 0xDF, 0xB5, 0xCB, 0x7E, 0xE0, 0x79, 0x85, 0x78, 0xEF, 0x13, 0x0E, 0xDC, 0x8E, 0x11, 0xBF, 0x4F, 0xFA, 0x01, 0x17, 0x26, 0xF0, 0xB5, 0x78, 0xFA, 0x2C, 0x7B, 0xB4, 0x4C, 0xCC, 0xB5, 0x23, 0x00, 0x41, 0x7D, 0x6B, 0xB9, 0x5C, 0xDB, 0x40, 0x80, 0xEA, 0xB7, 0x8F, 0x35, 0x24, 0x37, 0x39, 0xEE, 0x94, 0x20, 0x9D, 0xFD, 0x4F, 0xEF, 0x25, 0x27, 0xC9, 0x54, 0xF7, 0x26, 0xB5, 0xAA, 0xDF, 0xDC, 0x27, 0xFB, 0xBD, 0xE2, 0xBD, 0x48, 0x74, 0x65, 0x41, 0xEF, 0x22, 0x0B, 0x59, 0xB7, 0xA9, 0xEC, 0x56, 0x8D, 0x86, 0xAC, 0xB3, 0x1F, 0x0D, 0xD9, 0x5A, 0x2B, 0x5E, 0xF7, 0x63, 0xEA, 0x00, 0x20, 0x49, 0x73, 0xE7, 0x26, 0x72, 0x4E, 0xE5, 0x85, 0x64, 0xD2, 0xA6, 0xE0, 0xF9, 0x52, 0x52, 0x33, 0x92, 0x1F, 0x2D, 0x79, 0x98, 0x05, 0x7E, 0xED, 0x82, 0x10, 0x76, 0xBD, 0x45, 0xE3, 0x73, 0x50, 0x52, 0x4A, 0x6A, 0x31, 0x00, 0xB8, 0xAD, 0xAA, 0x58, 0x48, 0x4E, 0xAD, 0xA9, 0x0B, 0x24, 0x07, 0x1B, 0xF1, 0xA3, 0x5A, 0xC4, 0xB0, 0xC0, 0x9F, 0xEB, 0xB5, 0x9F, 0x5D, 0x7E, 0x83, 0x0D, 0x65, 0x1B, 0xD4, 0x87, 0x97, 0x7A, 0x66, 0x28, 0x00, 0xCC, 0x98, 0xF7, 0xD6, 0x81, 0x1C, 0x1C, 0xF1, 0x7B, 0x7D, 0x5B, 0x16, 0x68, 0xB8, 0x2E, 0xB7, 0xD8, 0x40, 0xB0, 0x31, 0xAD, 0xFF, 0x67, 0x73, 0x50, 0x67, 0x4B, 0x56, 0xF1, 0x3E, 0x6B, 0xA6, 0xCA, 0x06, 0x34, 0x65, 0x93, 0x96, 0xB0, 0x95, 0xDE, 0xFF, 0x26, 0x7F, 0x14, 0xB1, 0x2F, 0xAE, 0xB0, 0xD7, 0xB3, 0xD8, 0x4B, 0x29, 0x8D, 0xC8, 0x1F, 0x9E, 0xAC, 0x7C, 0x0A, 0x6B, 0x3A, 0x95, 0x0D, 0x9C, 0xCE, 0x6E, 0x7B, 0xCE, 0x5E, 0xB5, 0xFE, 0x83, 0xFA, 0xC3, 0xD9, 0xE7, 0xCE, 0xEC, 0xA5, 0x2D, 0xEC, 0x39, 0x2D, 0xF6, 0xE4, 0x8F, 0x86, 0xF7, 0xD1, 0x3C, 0x8B, 0xED, 0x1D, 0xC0, 0x1A, 0x5D, 0x67, 0xFD, 0xC7, 0xB0, 0xDB, 0x6E, 0xB1, 0x97, 0xE5, 0xFF, 0x2E, 0xFF, 0xDC, 0x63, 0x1F, 0x3D, 0x67, 0x2F, 0x64, 0xB0, 0x27, 0xB5, 0xD8, 0x92, 0x43, 0x6C, 0x71, 0x59, 0xE3, 0xF3, 0x47, 0x2F, 0x16, 0x63, 0xBF, 0xB0, 0xDE, 0x39, 0xEC, 0xF6, 0xDE, 0xC0, 0xB7, 0x1F, 0xC0, 0x39, 0x77, 0xE0, 0xEB, 0x25, 0x70, 0x56, 0xBD, 0xCB, 0x9E, 0xDB, 0xCC, 0xEE, 0x4B, 0x62, 0xF3, 0xBD, 0xD9, 0x5C, 0x3B, 0x36, 0x6B, 0x7B, 0xE3, 0xFB, 0x90, 0xEF, 0xC6, 0x8E, 0xE8, 0xC1, 0x2E, 0xB9, 0x0D, 0xBC, 0x9E, 0x0B, 0x24, 0x79, 0x01, 0xF7, 0x54, 0x80, 0xFD, 0x97, 0x80, 0x9B, 0x07, 0x80, 0x77, 0xD7, 0x81, 0x8A, 0x36, 0xE0, 0xDC, 0x73, 0x9A, 0xCD, 0xBD, 0xCA, 0xA6, 0x37, 0x63, 0x53, 0xBF, 0xB3, 0x29, 0x41, 0x8D, 0xEF, 0xA3, 0x9B, 0x19, 0xF0, 0x51, 0x17, 0xD0, 0xBE, 0x05, 0xD4, 0x7C, 0x01, 0x1C, 0x22, 0x80, 0x2B, 0x2B, 0x80, 0xB0, 0xA4, 0x16, 0xC1, 0xA7, 0x0B, 0x80, 0xC2, 0x8C, 0xD6, 0x03, 0x8F, 0xEC, 0x07, 0x1E, 0xF7, 0x6F, 0xE7, 0x78, 0xE0, 0x2C, 0xE8, 0x3E, 0x60, 0x9F, 0xFC, 0x00, 0x70, 0xDD, 0xE6, 0x6C, 0x92, 0x09, 0xBB, 0x55, 0x81, 0x4D, 0xB8, 0xDD, 0xB8, 0x3E, 0x9E, 0xBE, 0x96, 0xF0, 0x01, 0x9A, 0x9F, 0xA8, 0xE8, 0x0B, 0xF4, 0xB4, 0x90, 0x8F, 0xDE, 0x7F, 0x01, 0x30, 0x78, 0xAD, 0x7C, 0x25, 0xBB, 0x02, 0x58, 0xEC, 0xAE, 0x76, 0x6F, 0xE7, 0x31, 0x20, 0xE5, 0xCE, 0xA0, 0xF9, 0x09, 0x62, 0xFB, 0x62, 0xC2, 0x40, 0x8F, 0x38, 0x4F, 0x50, 0x76, 0x78, 0x1F, 0x79, 0x83, 0x54, 0xA8, 0x08, 0x29, 0x21, 0xA5, 0x7D, 0x36, 0x9D, 0x25, 0x81, 0xD5, 0xAF, 0x48, 0xC9, 0x96, 0x2B, 0x25, 0xC8, 0xCE, 0x1D, 0xFE, 0xAC, 0xFE, 0xEB, 0x90, 0x3E, 0x4B, 0xC8, 0xB3, 0x2F, 0xB5, 0x0D, 0xC8, 0x5C, 0x95, 0x81, 0xAD, 0x81, 0xBE, 0x6E, 0xEB, 0xE2, 0x81, 0x6E, 0xB2, 0x56, 0x16, 0x9E, 0x65, 0x80, 0xF9, 0x69, 0x8B, 0xF3, 0x6E, 0x2D, 0x81, 0xA0, 0x90, 0x89, 0xCF, 0x66, 0xC5, 0x01, 0xFB, 0x9F, 0x4C, 0x4C, 0x9E, 0x6E, 0x4D, 0xFB, 0xB0, 0x91, 0xB3, 0x1E, 0x48, 0x5A, 0x7C, 0x35, 0x77, 0x25, 0x0D, 0xAF, 0x99, 0x3C, 0x22, 0x75, 0x2D, 0x0D, 0xC3, 0x48, 0xFD, 0x30, 0xC3, 0x50, 0x52, 0xF7, 0x8F, 0xEA, 0x2B, 0x92, 0x2F, 0x3F, 0xC8, 0x6D, 0x20, 0x8F, 0x38, 0x8F, 0xE9, 0x46, 0x66, 0xBF, 0xB5, 0xAD, 0x23, 0x13, 0x67, 0xBB, 0x9E, 0x24, 0x9D, 0x14, 0xF4, 0xEE, 0x01, 0x86, 0x32, 0x00, 0x00, 0x04, 0xBE, 0x03, 0x9A, 0xC5, 0x4E, 0x7C, 0xB9, 0x7C, 0x17, 0xD0, 0x39, 0x7F, 0x47, 0xF5, 0x52, 0x1B, 0x40, 0xA6, 0xCD, 0x13, 0xE3, 0x05, 0x05, 0x40, 0x13, 0x19, 0x91, 0x77, 0xBC, 0x78, 0xDF, 0xCE, 0xB5, 0xEC, 0xEC, 0xE3, 0xAC, 0x63, 0x13, 0xD6, 0xBE, 0xF6, 0x6F, 0xF5, 0x9B, 0xDB, 0x92, 0x2F, 0x76, 0xC9, 0x36, 0x23, 0xCB, 0x32, 0x4C, 0x64, 0xC9, 0xD4, 0x81, 0x8E, 0x1E, 0x64, 0xE4, 0xD9, 0x45, 0x8B, 0x49, 0x3F, 0x77, 0xFF, 0x91, 0xA4, 0x9D, 0x89, 0xDF, 0x09, 0x60, 0x80, 0x1B, 0x30, 0x39, 0xB3, 0xC3, 0x10, 0x9A, 0xBF, 0xCC, 0x36, 0x9A, 0x5D, 0x3B, 0x39, 0x00, 0x70, 0x0C, 0x4E, 0x2F, 0xB6, 0x5C, 0x2C, 0xAC, 0x7F, 0xEE, 0x65, 0x1E, 0x00, 0x4C, 0xBD, 0x27, 0x66, 0x6C, 0x97, 0x3A, 0x74, 0xD0, 0x17, 0xEB, 0xBD, 0xD1, 0x67, 0x40, 0xE6, 0x8D, 0x98, 0xCF, 0x5C, 0x01, 0x7A, 0xAC, 0x15, 0xEE, 0xE4, 0x1C, 0x34, 0x59, 0x4A, 0xCC, 0x10, 0x35, 0x40, 0xF5, 0x17, 0xC9, 0x2C, 0x23, 0x8F, 0xFC, 0x30, 0x9F, 0x42, 0x6E, 0x5B, 0xE3, 0x64, 0x4A, 0x86, 0x0F, 0x5F, 0xB8, 0x95, 0xF4, 0xB1, 0x59, 0xF5, 0x82, 0x74, 0xA8, 0x49, 0x18, 0x4F, 0x5A, 0x2F, 0x4C, 0x1F, 0x44, 0x02, 0x51, 0x7E, 0xD2, 0xE5, 0xFA, 0x6B, 0x80, 0x4D, 0xDD, 0x9C, 0x5D, 0xB4, 0x3B, 0x02, 0x9B, 0x15, 0x77, 0xFB, 0x0E, 0xCD, 0x13, 0xDB, 0x2E, 0xCF, 0xB3, 0x87, 0x7C, 0x00, 0x42, 0x17, 0x88, 0x99, 0x57, 0x00, 0xB0, 0x6A, 0x99, 0xC8, 0xF1, 0x19, 0x80, 0x9F, 0xC8, 0x1B, 0x2A, 0xAE, 0x80, 0x2F, 0xDD, 0xCF, 0x3D, 0x02, 0x38, 0x05, 0x8B, 0xF9, 0xE1, 0xCF, 0xC7, 0x2F, 0x38, 0x8F, 0x1D, 0x51, 0xB5, 0x9C, 0x47, 0x26, 0xF5, 0x9C, 0xD7, 0x83, 0x0C, 0xE9, 0xBE, 0x28, 0x83, 0xF4, 0x3E, 0xB6, 0xAE, 0x25, 0x69, 0x9F, 0xBD, 0xD3, 0x93, 0x34, 0x0E, 0x2C, 0x72, 0x23, 0xB5, 0xB5, 0x0F, 0xCD, 0x23, 0x81, 0x3D, 0xB3, 0x7B, 0x6E, 0x56, 0x69, 0x0B, 0xEC, 0x7D, 0xE0, 0x5C, 0xD1, 0xFB, 0x30, 0xB0, 0x6F, 0x69, 0xFA, 0x6B, 0x99, 0x1C, 0xB1, 0xDD, 0xB4, 0xB6, 0x6F, 0x37, 0x7F, 0x80, 0xFE, 0xCB, 0x87, 0x5D, 0x34, 0x80, 0x74, 0x3F, 0x71, 0xCC, 0x69, 0x40, 0xF2, 0x05, 0x91, 0x37, 0x7C, 0x80, 0xED, 0x49, 0xF5, 0xF5, 0xED, 0x56, 0x01, 0x09, 0xBE, 0x22, 0x1B, 0x97, 0xE7, 0xFB, 0xCC, 0x3A, 0x06, 0x00, 0x5B, 0x3D, 0xDC, 0x1D, 0xC9, 0xF5, 0x91, 0x8B, 0x4E, 0x93, 0x3E, 0x3F, 0x82, 0x5E, 0x93, 0x0E, 0xBF, 0xED, 0xB6, 0x22, 0x87, 0x8F, 0x3B, 0x39, 0x81, 0x54, 0xA9, 0xA8, 0x98, 0x4C, 0x4A, 0xCF, 0xBA, 0xE4, 0x48, 0x02, 0x97, 0xBB, 0x74, 0xAC, 0x6F, 0xD9, 0x0C, 0xB8, 0xD2, 0xD7, 0xDE, 0x1E, 0x00, 0x2A, 0x1F, 0xA6, 0xC6, 0x91, 0xD7, 0x16, 0xD7, 0xF6, 0x21, 0xCF, 0xBF, 0xE0, 0xE7, 0xFE, 0xC4, 0x5C, 0xF6, 0xC0, 0x5B, 0x76, 0xEF, 0x70, 0xB6, 0x58, 0x87, 0xDC, 0x1A, 0xED, 0x31, 0x00, 0x00, 0x42, 0x8E, 0x2C, 0x6A, 0x47, 0xFA, 0x55, 0x06, 0xBB, 0x90, 0xB3, 0x22, 0x73, 0x03, 0x49, 0xF5, 0x01, 0x17, 0xD7, 0x93, 0xF2, 0xB1, 0xD7, 0x7A, 0x92, 0xAD, 0xF0, 0xF6, 0x33, 0x09, 0x7C, 0x9B, 0xC3, 0xF2, 0xDE, 0x48, 0x47, 0x4B, 0x36, 0x25, 0xFD, 0xDF, 0xAD, 0xAF, 0x75, 0x0B, 0xD9, 0x47, 0xC1, 0xEC, 0x8D, 0x19, 0x64, 0x84, 0xE4, 0xE2, 0x08, 0x00, 0x08, 0xFC, 0x1A, 0xB4, 0x86, 0x9C, 0xF5, 0x2C, 0xEF, 0x05, 0xA9, 0x2E, 0x77, 0xF9, 0x27, 0xD9, 0x47, 0xE6, 0xCD, 0xCD, 0x86, 0xFE, 0xA6, 0x73, 0xDB, 0xC3, 0x86, 0x0F, 0x6D, 0x7C, 0x0E, 0x5A, 0xF3, 0x32, 0x98, 0x8E, 0x0B, 0x0E, 0xB1, 0xB9, 0xAE, 0xA4, 0xC6, 0xD3, 0xAB, 0x7B, 0x48, 0xE9, 0x05, 0x8D, 0xCF, 0x1F, 0x0B, 0xEA, 0xD9, 0xE5, 0x63, 0xD8, 0xD0, 0xD1, 0x0D, 0xEF, 0xC3, 0x01, 0x59, 0xA5, 0x00, 0x30, 0xFC, 0xE1, 0xF5, 0x07, 0xA4, 0xB4, 0x46, 0xE3, 0xEA, 0xB3, 0xAC, 0x03, 0xD8, 0x40, 0xB0, 0x9B, 0xBF, 0xFF, 0xCF, 0xE6, 0xA0, 0x76, 0x3F, 0xD9, 0xDE, 0x60, 0xC7, 0xF5, 0x63, 0x03, 0x4C, 0xD8, 0xD8, 0x50, 0xF6, 0xE2, 0x1F, 0xE4, 0xA0, 0xCF, 0x1A, 0xEC, 0xD3, 0x76, 0xEC, 0xB9, 0x48, 0x76, 0x6F, 0x7F, 0xB6, 0x28, 0xA1, 0xE1, 0xEB, 0x4B, 0xB3, 0x6F, 0xAC, 0xDC, 0x75, 0x56, 0x33, 0x81, 0x5D, 0xFD, 0x92, 0x8D, 0x7D, 0xC1, 0x5E, 0x48, 0x63, 0xE9, 0xEB, 0xEB, 0x4E, 0xF6, 0xBA, 0x0B, 0x7B, 0x3E, 0x8A, 0xCD, 0xEF, 0xC2, 0xE6, 0x2A, 0xB2, 0x59, 0x0E, 0x8D, 0x5F, 0x6F, 0xFB, 0xB4, 0x60, 0x87, 0xB8, 0xB0, 0x81, 0x4E, 0x6C, 0x6C, 0x39, 0xF0, 0x22, 0x1D, 0xC8, 0x19, 0x09, 0xFC, 0xEC, 0x2B, 0xBE, 0x0A, 0x81, 0x1B, 0xF7, 0xC1, 0xC7, 0xDF, 0x9B, 0x2D, 0xCC, 0x60, 0x77, 0xA5, 0xB3, 0xE9, 0xAF, 0xD8, 0x1D, 0x3D, 0x1B, 0xDF, 0x87, 0x42, 0x22, 0x3B, 0x38, 0x9E, 0xF5, 0xEF, 0x0A, 0x3C, 0x2D, 0x01, 0x12, 0xB3, 0x81, 0xEA, 0x95, 0x40, 0xEE, 0x68, 0xE0, 0x72, 0x04, 0xF0, 0xB4, 0x06, 0xA8, 0x50, 0x00, 0x9F, 0xF7, 0x52, 0x36, 0xF3, 0x35, 0xBB, 0x79, 0x06, 0x1B, 0x97, 0xCB, 0xC6, 0x6A, 0x34, 0xBE, 0x8F, 0x1E, 0xBE, 0xC0, 0xD3, 0x34, 0x40, 0xFD, 0x03, 0x70, 0x65, 0x2D, 0x30, 0xB1, 0x02, 0xB8, 0x76, 0x0A, 0x88, 0x74, 0x06, 0x4E, 0x6D, 0x02, 0xF2, 0xE4, 0x81, 0x63, 0x41, 0xC0, 0x7D, 0x45, 0xA0, 0xF8, 0x23, 0xB8, 0x7E, 0x04, 0xBB, 0xE5, 0x22, 0x1B, 0x39, 0x88, 0x8D, 0xE8, 0xCF, 0x86, 0xF5, 0x68, 0x5C, 0x1F, 0xEF, 0x96, 0x02, 0xAD, 0x17, 0x00, 0x95, 0x96, 0x40, 0x7F, 0x55, 0xE0, 0xA4, 0x23, 0x60, 0xDE, 0x11, 0x38, 0xD8, 0x0D, 0xF0, 0x0A, 0x07, 0x4A, 0x16, 0x00, 0x69, 0xB5, 0x40, 0x01, 0x4D, 0xF8, 0xAF, 0x00, 0x59, 0x7D, 0xC0, 0x79, 0x27, 0x93, 0x8D, 0xBE, 0xC5, 0xAE, 0x79, 0x05, 0xD6, 0x88, 0x5D, 0x35, 0xBB, 0x61, 0x7D, 0x7C, 0xF1, 0x62, 0x2F, 0x16, 0xB3, 0x47, 0x9A, 0x00, 0x7D, 0x86, 0xB7, 0x48, 0xC8, 0x19, 0x01, 0xE8, 0x76, 0xEE, 0x20, 0x97, 0x5C, 0x0A, 0xB8, 0xAA, 0x75, 0x35, 0xDF, 0x5C, 0x0D, 0x6C, 0xCC, 0xE9, 0x56, 0x11, 0x59, 0x08, 0x1C, 0x3A, 0x2C, 0xD3, 0x2B, 0xA4, 0x27, 0xF0, 0xE1, 0x48, 0xF7, 0xB2, 0x35, 0x6B, 0x41, 0xF7, 0xF8, 0xB6, 0x84, 0x5A, 0x90, 0x80, 0x58, 0xA5, 0xD9, 0xF6, 0xAC, 0xCF, 0x9F, 0xDC, 0xBF, 0xFD, 0x19, 0xC5, 0x5E, 0xDA, 0xC0, 0xEE, 0x6F, 0x2F, 0xBB, 0x9E, 0xDC, 0xFE, 0xA3, 0x6F, 0x01, 0x20, 0xB9, 0xC3, 0x47, 0x6C, 0x75, 0x5B, 0x35, 0x2A, 0xD4, 0xAD, 0x0E, 0x30, 0x28, 0x1B, 0xE9, 0xEA, 0x60, 0x02, 0x78, 0x0D, 0x18, 0x2D, 0x67, 0xE7, 0x0F, 0xEC, 0x2E, 0xD5, 0x6B, 0x62, 0x1D, 0x0B, 0xDC, 0x2B, 0xD3, 0x3F, 0x30, 0xC1, 0x1D, 0x94, 0x73, 0xE6, 0x18, 0xDE, 0x24, 0xB5, 0x9D, 0x26, 0xAF, 0x22, 0xE5, 0x0F, 0x58, 0xAF, 0x24, 0xFB, 0xEE, 0xD6, 0x7D, 0x4A, 0xAA, 0xFD, 0xF6, 0xAB, 0x3E, 0x2E, 0x8E, 0xF9, 0xED, 0x16, 0x59, 0xFC, 0x51, 0xD9, 0x80, 0x8C, 0x3D, 0xAB, 0x63, 0x41, 0x06, 0xCD, 0xB0, 0xEE, 0x49, 0x4E, 0x75, 0xD0, 0xCE, 0x02, 0x34, 0x27, 0xF2, 0xA3, 0x17, 0x7C, 0x07, 0x9A, 0x2C, 0x32, 0x72, 0x77, 0xDD, 0x03, 0x74, 0x1A, 0x11, 0xBD, 0x6E, 0xD6, 0x1B, 0x40, 0xBA, 0xED, 0xA9, 0xA3, 0xD3, 0x37, 0x00, 0x32, 0x39, 0xF5, 0xF5, 0x53, 0x0F, 0xF2, 0xBE, 0x67, 0x84, 0xB0, 0x13, 0xE5, 0xC1, 0x2A, 0xB2, 0xE6, 0x5D, 0xFF, 0xB9, 0xFE, 0xD9, 0x08, 0xA9, 0xA1, 0x64, 0x41, 0x4F, 0x8D, 0x56, 0x64, 0x70, 0x84, 0x45, 0x27, 0xD2, 0xAF, 0x85, 0xED, 0x09, 0xD2, 0x75, 0xCA, 0xDC, 0x44, 0x72, 0x62, 0xFC, 0x82, 0x6A, 0x40, 0x4A, 0x1F, 0x98, 0x30, 0x57, 0x22, 0xC3, 0x6C, 0x2F, 0x60, 0xFB, 0xCD, 0x2E, 0x48, 0xBF, 0x1A, 0x98, 0xD2, 0x3E, 0xF6, 0xF0, 0xA8, 0xEE, 0xC2, 0x41, 0x67, 0x12, 0x74, 0x42, 0x00, 0xDB, 0x45, 0xE2, 0x3C, 0xEC, 0x05, 0x0C, 0xAF, 0x0B, 0xF5, 0x01, 0xB9, 0xBD, 0x62, 0x2E, 0x13, 0x25, 0x9C, 0x2E, 0x5C, 0x0B, 0xF4, 0x5E, 0xFD, 0x9F, 0xB9, 0x70, 0x14, 0xD7, 0x2F, 0xBF, 0xDC, 0xC3, 0x94, 0xCC, 0x3D, 0x3C, 0xF4, 0x07, 0x19, 0x3A, 0xD1, 0x6C, 0x08, 0xE9, 0xAB, 0x35, 0x25, 0x90, 0x74, 0x92, 0x9A, 0x9B, 0x4D, 0x5A, 0xE6, 0x2E, 0x9F, 0x4B, 0xEA, 0xF9, 0xC6, 0x74, 0x20, 0x81, 0x40, 0xD3, 0x4E, 0xA6, 0x1A, 0x31, 0x40, 0xF0, 0x4C, 0x3B, 0x57, 0xA5, 0xE1, 0xC2, 0x33, 0x09, 0x67, 0xFA, 0x7E, 0x10, 0x8E, 0x3F, 0x17, 0x20, 0xBF, 0x12, 0x58, 0xB3, 0x41, 0xCC, 0xDC, 0xCE, 0x01, 0xCB, 0xC5, 0xFA, 0xDA, 0x63, 0x3C, 0xE0, 0x2E, 0xFA, 0xE9, 0x16, 0x0F, 0xCC, 0x13, 0x73, 0xA2, 0xEE, 0xAF, 0x01, 0x3B, 0x4F, 0x91, 0xA3, 0x8B, 0xCA, 0x75, 0x7A, 0x0D, 0x00, 0x80, 0xF0, 0xB8, 0x21, 0x0F, 0xC9, 0x75, 0x81, 0x96, 0x3D, 0x48, 0xEF, 0x9B, 0x53, 0xA3, 0xC8, 0x39, 0xD7, 0x9D, 0xCC, 0x48, 0x8B, 0x9C, 0xA8, 0x50, 0x52, 0x23, 0x35, 0xE5, 0x05, 0xD9, 0xB3, 0x36, 0xF3, 0x26, 0x09, 0xA4, 0x5F, 0x97, 0x8E, 0x90, 0x2A, 0x00, 0x32, 0xE5, 0x6C, 0x0F, 0xB7, 0xB9, 0x2D, 0x7C, 0x11, 0x3B, 0xB7, 0xE9, 0x2D, 0x20, 0xFD, 0x44, 0xF9, 0x46, 0x0C, 0x02, 0xD2, 0xE6, 0xF0, 0xB9, 0xDE, 0xAA, 0xC1, 0x46, 0x2F, 0x63, 0xA3, 0x3A, 0xB3, 0x61, 0x3A, 0x64, 0xC4, 0x72, 0xF3, 0xE5, 0x00, 0xB0, 0xE6, 0xAB, 0x65, 0x19, 0xE9, 0x5D, 0x3C, 0xAD, 0x33, 0x39, 0xD7, 0xC8, 0x69, 0x2C, 0x69, 0x69, 0x12, 0x7F, 0x91, 0x94, 0x72, 0x2B, 0xDE, 0x49, 0x4A, 0xBA, 0x14, 0xAD, 0x25, 0x81, 0x7D, 0xE5, 0xEC, 0xB1, 0xFD, 0xEC, 0x09, 0x8B, 0xC9, 0x4B, 0xC8, 0xD3, 0x33, 0x37, 0xF6, 0x23, 0x4F, 0xE6, 0x9C, 0x32, 0x20, 0x8F, 0xD5, 0x71, 0xBD, 0x3D, 0x0B, 0xD9, 0xAC, 0xA5, 0xEC, 0xAE, 0x34, 0x36, 0x2D, 0x89, 0x5C, 0x1B, 0x65, 0xB5, 0x10, 0x00, 0x7C, 0x55, 0xA7, 0x1E, 0x25, 0x9D, 0x57, 0xCE, 0x95, 0x23, 0xAD, 0x2C, 0x92, 0x8F, 0x91, 0x92, 0xA3, 0x4B, 0x8A, 0xC9, 0x16, 0xF6, 0x27, 0x76, 0x91, 0x40, 0xC5, 0x5A, 0xF6, 0x85, 0x03, 0xFB, 0xBE, 0x25, 0x5B, 0xE7, 0x6D, 0x67, 0x4B, 0x7E, 0x28, 0xDD, 0x5E, 0x41, 0x7E, 0xBB, 0xF8, 0x63, 0x13, 0xF9, 0x61, 0x31, 0xD7, 0x7B, 0x26, 0xCD, 0x5E, 0x89, 0x64, 0xCF, 0x9F, 0x65, 0xCF, 0x46, 0x91, 0xCB, 0xCD, 0xA7, 0x99, 0x03, 0xC0, 0x3C, 0x25, 0xC7, 0xE6, 0xE4, 0xA4, 0x91, 0x3B, 0xBD, 0x49, 0xA9, 0x41, 0x45, 0x2E, 0x64, 0x93, 0x31, 0x67, 0x3C, 0x1B, 0xFA, 0x1B, 0x77, 0xD1, 0x53, 0x36, 0xE6, 0x52, 0xE3, 0x73, 0x90, 0x9B, 0x87, 0x9B, 0x07, 0x00, 0x4C, 0xF3, 0xDA, 0xB9, 0x8D, 0xEC, 0x3C, 0x28, 0x3F, 0xF6, 0xBF, 0x9A, 0x3F, 0x96, 0x82, 0x5D, 0x51, 0xC1, 0x86, 0xB0, 0x0D, 0xEA, 0xC3, 0x76, 0x5D, 0xCA, 0x39, 0x00, 0x50, 0xA8, 0x39, 0xDB, 0x96, 0x04, 0xFE, 0xE7, 0x72, 0xD0, 0x56, 0xD7, 0xFF, 0xD9, 0x1C, 0xD4, 0xB2, 0x1D, 0xDB, 0x1B, 0xEC, 0xA0, 0x48, 0x36, 0xC0, 0x9A, 0x0D, 0x1B, 0x04, 0xBC, 0x8F, 0x06, 0x72, 0xDE, 0xFE, 0xDD, 0xFC, 0x65, 0x01, 0x7B, 0xED, 0x18, 0x5B, 0x52, 0xC2, 0x66, 0xB7, 0x62, 0xE3, 0x3D, 0xD8, 0xB8, 0x13, 0xFF, 0x85, 0xB9, 0x83, 0x1D, 0xAB, 0xFC, 0x88, 0x0D, 0x5A, 0xC3, 0xAE, 0xB7, 0x01, 0x6A, 0x66, 0x03, 0xDB, 0xC2, 0x81, 0xEF, 0xE7, 0x81, 0x6F, 0x4F, 0x81, 0x4A, 0xBE, 0x97, 0x87, 0xB3, 0x69, 0x6C, 0x4E, 0x15, 0xBB, 0x29, 0x87, 0x8D, 0x4E, 0x64, 0x23, 0xA5, 0x1A, 0xDF, 0x47, 0xDF, 0x68, 0x56, 0x69, 0x12, 0xBB, 0xEE, 0x21, 0xF0, 0x40, 0x06, 0x48, 0x68, 0x07, 0xDC, 0x0B, 0xA0, 0x7B, 0xF0, 0xC0, 0x99, 0x6F, 0x40, 0xB5, 0x0E, 0x70, 0xB6, 0x12, 0x9C, 0xBB, 0x7A, 0xB1, 0x9B, 0x8B, 0xD8, 0xA8, 0xFD, 0x6C, 0xA8, 0x39, 0xBB, 0x2E, 0xB2, 0xF1, 0x7D, 0xF4, 0xBC, 0x0E, 0xDC, 0x90, 0x02, 0x94, 0x87, 0x01, 0xE5, 0x6D, 0x00, 0xE3, 0xA1, 0xC0, 0xF5, 0x1A, 0x20, 0xEA, 0x0A, 0x50, 0x91, 0x02, 0x24, 0x66, 0x01, 0x87, 0xE3, 0x81, 0x1A, 0x37, 0x20, 0xF7, 0x2F, 0xF7, 0xEE, 0x3E, 0xB1, 0xD1, 0x5E, 0x6C, 0x50, 0x11, 0xBB, 0x74, 0x29, 0xBB, 0xCC, 0xA0, 0x71, 0x7D, 0xBC, 0xCF, 0x01, 0x24, 0xF2, 0x81, 0xB3, 0x57, 0x01, 0xF9, 0x74, 0xBA, 0x0F, 0x00, 0x8C, 0x09, 0x05, 0x72, 0xED, 0x01, 0xB7, 0x18, 0x20, 0x67, 0x35, 0x10, 0xFD, 0x0D, 0x28, 0xB8, 0x04, 0xDC, 0xC8, 0x07, 0xD2, 0x38, 0x8F, 0x21, 0x66, 0x1A, 0x1B, 0x3C, 0x94, 0x5D, 0xD6, 0x8C, 0xF5, 0x90, 0x67, 0xDD, 0xAF, 0x34, 0xAC, 0x8F, 0xEF, 0x67, 0xD8, 0x8A, 0xA5, 0x6C, 0x59, 0x57, 0xA0, 0xB7, 0x2D, 0x90, 0x25, 0x0F, 0x8C, 0x09, 0x03, 0x76, 0x5C, 0x06, 0x1C, 0x4B, 0x81, 0xC4, 0x1A, 0x20, 0x4C, 0x11, 0xD8, 0x30, 0x05, 0x38, 0x54, 0x08, 0x44, 0x2B, 0x00, 0x6F, 0xB7, 0x03, 0xC1, 0xAA, 0xE0, 0x9C, 0xA1, 0xC8, 0xBA, 0xC7, 0xB3, 0x4E, 0x57, 0xD9, 0xB9, 0x0D, 0x9C, 0x17, 0x9E, 0x7F, 0xC7, 0x16, 0x5D, 0x64, 0x77, 0xBF, 0x07, 0xA4, 0x3E, 0x01, 0x49, 0x8B, 0x00, 0xED, 0x99, 0x40, 0xDC, 0x32, 0xC0, 0x61, 0x01, 0x10, 0xF6, 0x11, 0x08, 0x0E, 0x04, 0xD6, 0xDD, 0x05, 0xF2, 0x57, 0x01, 0x2B, 0x3D, 0x80, 0xAA, 0xA3, 0x42, 0xCE, 0x5B, 0x58, 0x52, 0xC3, 0xCE, 0x0D, 0x64, 0xA7, 0x1B, 0x80, 0x7D, 0xFE, 0xEF, 0xFB, 0xB8, 0xA0, 0xCA, 0x16, 0xCD, 0x60, 0xD3, 0x15, 0xD8, 0x88, 0x75, 0xDD, 0x7E, 0x00, 0xCD, 0x5E, 0x7A, 0x24, 0x03, 0x9D, 0xAB, 0x55, 0x9E, 0xDB, 0xBF, 0x06, 0x46, 0xBD, 0x52, 0x8D, 0xB4, 0x7D, 0x04, 0xB8, 0xA6, 0xA9, 0x2D, 0xB5, 0xEA, 0x0C, 0xC4, 0x9F, 0x1B, 0x94, 0x39, 0x3E, 0x1E, 0x38, 0x25, 0xA7, 0xFE, 0xD8, 0x44, 0x28, 0xE6, 0x53, 0x69, 0x7A, 0xF6, 0xA4, 0x6A, 0x6F, 0xDD, 0x75, 0x64, 0x6F, 0xDB, 0x31, 0xA9, 0xA4, 0x8C, 0x8B, 0x2E, 0xC8, 0x6E, 0xA6, 0xFF, 0x72, 0xFC, 0xF7, 0xD8, 0x22, 0x65, 0x36, 0xEC, 0x61, 0x9F, 0x95, 0x64, 0xA0, 0x7F, 0xFF, 0x8F, 0xE4, 0xE2, 0xB0, 0x91, 0x57, 0x49, 0xAB, 0xE3, 0x1A, 0x97, 0x01, 0xF9, 0x69, 0xFC, 0xA8, 0xE9, 0x2A, 0x40, 0xF3, 0xC5, 0xA3, 0x92, 0x27, 0x6B, 0x02, 0x1D, 0x8F, 0x06, 0x38, 0x9B, 0x6F, 0x00, 0xA4, 0x9A, 0x15, 0xD9, 0x99, 0x76, 0x07, 0xBA, 0xC6, 0xBD, 0x71, 0x1A, 0x37, 0x13, 0x68, 0x3B, 0x4F, 0xCC, 0xA5, 0xCE, 0x70, 0xAD, 0x71, 0xA3, 0xDB, 0xE5, 0x91, 0xDA, 0x79, 0x1D, 0x5E, 0x93, 0xC3, 0x12, 0xFF, 0x5A, 0xFF, 0x2C, 0x5B, 0x14, 0xC8, 0xAE, 0x92, 0xEA, 0x77, 0x81, 0x0C, 0x74, 0x50, 0x7F, 0x42, 0x3A, 0xC5, 0x1B, 0x18, 0x92, 0x53, 0x92, 0x2C, 0x7C, 0xC9, 0x09, 0x5B, 0x67, 0x3F, 0x22, 0x81, 0xB1, 0xBD, 0x5A, 0x0F, 0x1E, 0xD5, 0x0F, 0x30, 0x37, 0xB4, 0x88, 0xD6, 0x90, 0x14, 0xAE, 0x5F, 0xBD, 0x7C, 0x80, 0x0A, 0x60, 0x71, 0xB7, 0xA4, 0x58, 0xB5, 0x1B, 0x60, 0x79, 0xEB, 0x83, 0xBE, 0xF2, 0x2B, 0x40, 0xBF, 0xA0, 0xBE, 0x5E, 0xF9, 0x0C, 0xD0, 0xEF, 0x8E, 0x98, 0xCB, 0xF8, 0x02, 0xB2, 0xC7, 0xC4, 0x7D, 0xCC, 0x07, 0x3C, 0x0F, 0x1A, 0x78, 0xF6, 0x12, 0xF8, 0x7F, 0x85, 0x9A, 0x6C, 0xE0, 0x6C, 0xC5, 0xB1, 0xE4, 0xAA, 0xAA, 0xA1, 0xAA, 0xE4, 0x5C, 0xCD, 0x71, 0xCE, 0xA4, 0xED, 0xA7, 0x49, 0xA6, 0xE4, 0x58, 0x8B, 0x39, 0x69, 0xA4, 0x1A, 0x7C, 0xF8, 0x08, 0xB0, 0xE8, 0x4D, 0xBB, 0xB5, 0xBD, 0xEF, 0x01, 0x3E, 0x75, 0xE3, 0xB3, 0xA5, 0x52, 0x00, 0x6F, 0xBF, 0xB5, 0x2F, 0x3B, 0x8E, 0x12, 0xDB, 0x61, 0xFB, 0x82, 0x24, 0x1E, 0x0A, 0x9B, 0xD7, 0xF5, 0x69, 0x9D, 0x02, 0x2C, 0x99, 0x2C, 0xE6, 0x2F, 0x1D, 0x01, 0x97, 0x8B, 0xE2, 0x9E, 0xEC, 0x21, 0xDA, 0xA3, 0xF8, 0x0C, 0xCB, 0x46, 0x60, 0x52, 0x57, 0xFA, 0x1C, 0x44, 0xDE, 0xE9, 0x56, 0x91, 0x00, 0xE0, 0x73, 0x5C, 0x45, 0x91, 0xF4, 0xDA, 0xA0, 0xBF, 0x82, 0x74, 0x1C, 0x6A, 0xBC, 0x9B, 0x9C, 0x32, 0x6E, 0xF2, 0x13, 0x72, 0x74, 0x8F, 0xF9, 0x4D, 0x49, 0x49, 0x8F, 0x30, 0x5F, 0xB2, 0xE9, 0xFC, 0xD8, 0x44, 0x12, 0xD8, 0x7C, 0xA7, 0x53, 0x17, 0x32, 0x3E, 0xD3, 0xA4, 0x84, 0x8C, 0x3B, 0x1C, 0x18, 0x4F, 0x6E, 0xFC, 0x5A, 0xB8, 0x10, 0xE4, 0xA1, 0x9F, 0xD7, 0xC9, 0x30, 0x5F, 0x3E, 0xF7, 0x2B, 0xFD, 0x58, 0xEF, 0xE1, 0xAC, 0xA7, 0x1E, 0x19, 0x08, 0x95, 0x68, 0xD0, 0xD6, 0x06, 0xFD, 0x56, 0xA4, 0xA3, 0x83, 0xC9, 0x36, 0x72, 0x46, 0x07, 0x9B, 0x62, 0x52, 0x7D, 0xF0, 0x1A, 0xAE, 0x87, 0xC4, 0xC5, 0x6C, 0xCA, 0x0E, 0x76, 0xD7, 0x73, 0x36, 0xB7, 0x39, 0x9B, 0x53, 0x6B, 0x36, 0x81, 0xCC, 0x9F, 0xEF, 0xF1, 0x85, 0x2C, 0xDC, 0x51, 0x18, 0x0B, 0x92, 0x73, 0x17, 0x32, 0x4D, 0xD8, 0x38, 0x2B, 0x36, 0xBA, 0x1D, 0x1B, 0x19, 0x4D, 0x7A, 0x6E, 0xD6, 0x57, 0x01, 0x80, 0x39, 0x65, 0xA6, 0x9D, 0x49, 0x87, 0x35, 0x36, 0xD7, 0xC9, 0xDF, 0x24, 0xE3, 0x5C, 0x49, 0x20, 0xF5, 0x20, 0xBB, 0xFB, 0x01, 0x5B, 0x58, 0xC2, 0x9E, 0x6E, 0xC7, 0x56, 0x78, 0xB0, 0x97, 0x8F, 0x4E, 0xF0, 0x25, 0xAF, 0x5D, 0x0A, 0xFF, 0x48, 0xDE, 0x4A, 0x3C, 0x30, 0x0A, 0x24, 0xB8, 0xDE, 0xA5, 0x2C, 0xF6, 0xF4, 0x07, 0xB6, 0x68, 0x36, 0x5B, 0x58, 0x4B, 0x3A, 0x7F, 0x33, 0xDD, 0x07, 0x00, 0x8E, 0x7E, 0xB6, 0x5C, 0x0F, 0x89, 0xF7, 0x41, 0x7D, 0xD8, 0xA4, 0x0E, 0x25, 0x81, 0x6C, 0x47, 0xF6, 0x6C, 0xED, 0x9F, 0xFD, 0xE6, 0x75, 0xDF, 0xC8, 0xC6, 0xF9, 0x37, 0x26, 0x07, 0xBD, 0xD7, 0x23, 0x67, 0xBE, 0x9F, 0x5E, 0xCA, 0xFB, 0xC9, 0x0F, 0x60, 0x53, 0x13, 0xD8, 0x53, 0x67, 0x1A, 0x9B, 0x3F, 0x3C, 0xF5, 0xD9, 0xC5, 0xA9, 0x6C, 0x48, 0x50, 0xC3, 0xFB, 0x69, 0xB1, 0x2B, 0x2D, 0x03, 0x00, 0x9A, 0xF4, 0xD8, 0xF5, 0x18, 0xBC, 0xBF, 0xB9, 0xFF, 0xDD, 0x3C, 0x14, 0x08, 0x76, 0x5B, 0x83, 0x73, 0x61, 0xE3, 0xAA, 0xF4, 0x66, 0xA1, 0x70, 0x85, 0x0D, 0x50, 0x65, 0x57, 0xD9, 0x03, 0xF7, 0x84, 0x54, 0xF7, 0xDD, 0x14, 0xFE, 0xBA, 0x9A, 0x0D, 0xFC, 0x98, 0x0A, 0x14, 0x8C, 0x00, 0xE7, 0x8E, 0x47, 0x6C, 0xB8, 0x3B, 0xBB, 0x38, 0x99, 0x5D, 0x68, 0xF7, 0x5F, 0xC8, 0x1F, 0x67, 0x84, 0x25, 0x40, 0x0F, 0x49, 0xE0, 0x44, 0x36, 0x30, 0xD2, 0x0A, 0x3C, 0x8F, 0xE9, 0x0F, 0x54, 0x87, 0x00, 0x09, 0x9A, 0xC0, 0x89, 0x15, 0xC0, 0xC3, 0x7E, 0x40, 0x1E, 0xEF, 0x1F, 0x99, 0xA5, 0x6C, 0x54, 0x20, 0xBB, 0xF4, 0x28, 0xEB, 0x1A, 0x0C, 0xF6, 0xBF, 0x90, 0xC7, 0xE4, 0xC6, 0x01, 0x67, 0xDD, 0x85, 0x9E, 0xC0, 0x1E, 0x29, 0x60, 0x74, 0x31, 0x90, 0xDE, 0x0E, 0x98, 0x64, 0x02, 0xE4, 0x2D, 0x05, 0x22, 0x52, 0x80, 0x13, 0xAB, 0x81, 0x07, 0x5D, 0x81, 0xDD, 0xB6, 0xE0, 0xFA, 0xDB, 0xD9, 0xE0, 0x99, 0xAC, 0xC7, 0x19, 0xD6, 0xB1, 0x92, 0x9D, 0x9D, 0xD0, 0xB8, 0x3E, 0xDE, 0xDE, 0x07, 0xDA, 0x9D, 0x05, 0x0E, 0xD7, 0x01, 0x72, 0xF6, 0x40, 0xAE, 0x24, 0x30, 0xFA, 0x11, 0xB0, 0xDD, 0x1A, 0x98, 0xFC, 0x06, 0x48, 0xBB, 0x07, 0xAC, 0xFD, 0x09, 0x14, 0xEF, 0x06, 0xEE, 0xDC, 0x00, 0x62, 0x72, 0xC1, 0xF5, 0x75, 0xD8, 0x45, 0x71, 0xAC, 0x73, 0x39, 0x6B, 0xFB, 0x9E, 0xB5, 0x2B, 0x6F, 0x58, 0x1F, 0x3F, 0x86, 0xB0, 0x85, 0xA6, 0xEC, 0xDE, 0xD3, 0x40, 0xF7, 0x62, 0x20, 0xC5, 0x09, 0xD0, 0x92, 0x03, 0xE2, 0x94, 0x01, 0x6B, 0x33, 0x20, 0xBA, 0x1B, 0xB0, 0x6C, 0x17, 0x10, 0xDC, 0x06, 0x38, 0xF0, 0x06, 0x58, 0x67, 0x03, 0x7C, 0xEA, 0x0C, 0xF0, 0xE7, 0x8F, 0x00, 0xB7, 0x50, 0x76, 0xFA, 0x2B, 0x76, 0xE2, 0x04, 0xB0, 0x9B, 0x1B, 0xD6, 0x47, 0x85, 0x24, 0x9B, 0xB5, 0x95, 0x8D, 0x9F, 0x05, 0x48, 0x7C, 0x00, 0xA2, 0x67, 0x00, 0xEA, 0xE5, 0x40, 0xD0, 0x6E, 0x60, 0xBC, 0x23, 0xE0, 0x17, 0x0A, 0x2C, 0xFC, 0x00, 0xF8, 0x8C, 0x07, 0x72, 0x4B, 0x80, 0x45, 0x1D, 0x80, 0xCA, 0x32, 0xC0, 0xDD, 0x8C, 0xF7, 0x35, 0xEB, 0x03, 0x6B, 0x73, 0x8B, 0x9D, 0x20, 0x05, 0xB6, 0x17, 0xFB, 0xCB, 0xFA, 0xBB, 0xD9, 0xEC, 0x87, 0x6C, 0xBC, 0x05, 0x1B, 0x1A, 0x0E, 0x34, 0xEB, 0x00, 0x2C, 0xBF, 0x04, 0x28, 0x76, 0x02, 0x3C, 0x6D, 0x00, 0xA3, 0x64, 0x60, 0x51, 0x29, 0xB0, 0x60, 0x0F, 0x30, 0xAF, 0x39, 0x90, 0xE8, 0x05, 0xB8, 0x9A, 0x00, 0xA7, 0x63, 0x80, 0xB9, 0x03, 0x81, 0x9F, 0x83, 0x80, 0xA9, 0x3C, 0x0F, 0x82, 0xE5, 0x70, 0xD6, 0xE0, 0x2D, 0x6B, 0xE8, 0xFE, 0xC7, 0x7D, 0x9C, 0x63, 0x91, 0xE3, 0xCE, 0xC6, 0x75, 0x65, 0x83, 0x59, 0xF8, 0x8D, 0x6F, 0x26, 0x43, 0xCE, 0xED, 0x01, 0x74, 0xF1, 0x94, 0x34, 0xB6, 0xFB, 0x08, 0x68, 0x77, 0xE9, 0xD6, 0xCB, 0x72, 0x01, 0x30, 0xE3, 0x9A, 0xEC, 0x08, 0xE3, 0xBB, 0x40, 0x48, 0xCF, 0x5E, 0x03, 0x0D, 0xE2, 0x80, 0xA2, 0x7D, 0x72, 0x55, 0xFA, 0x27, 0x81, 0x87, 0x81, 0x3D, 0xEF, 0x8F, 0x8D, 0xA6, 0x1A, 0x5D, 0x4C, 0x0D, 0xFA, 0x91, 0xAD, 0x3A, 0x1A, 0xD4, 0x90, 0x80, 0x2E, 0xC8, 0xBF, 0xCB, 0x3F, 0xB1, 0x6C, 0x8E, 0x15, 0x1B, 0xF3, 0x9E, 0xF5, 0x7B, 0xDB, 0xAA, 0x2D, 0xE9, 0x1D, 0xAC, 0x70, 0x8A, 0xB4, 0x8F, 0x54, 0xF6, 0x22, 0x4D, 0x13, 0x06, 0x2A, 0x03, 0x6D, 0x0B, 0xF9, 0x51, 0xC6, 0x1F, 0x80, 0x66, 0x3F, 0xB5, 0x7C, 0xC6, 0x5A, 0x03, 0xED, 0x77, 0x2C, 0xD8, 0x37, 0x5A, 0x02, 0xE8, 0x94, 0xBE, 0xE3, 0x8B, 0xD6, 0x3D, 0xA0, 0x73, 0x93, 0x2B, 0x3E, 0xC3, 0xC6, 0x00, 0x92, 0xAD, 0x44, 0xDE, 0x91, 0xE3, 0x63, 0xD6, 0x56, 0x6D, 0x52, 0x4B, 0x0E, 0x18, 0xD7, 0x6A, 0x00, 0xA9, 0x3C, 0xE0, 0xE2, 0x5E, 0x70, 0x7D, 0x29, 0x36, 0xE2, 0x12, 0xBB, 0xE2, 0x4D, 0x8F, 0x14, 0x72, 0xD9, 0x62, 0xB9, 0x56, 0xE4, 0x74, 0x1B, 0x8D, 0x3D, 0xA4, 0xE9, 0xE8, 0x91, 0xF3, 0x48, 0x6D, 0xA5, 0xF1, 0xFC, 0x48, 0xE8, 0x5C, 0x6D, 0xF1, 0x44, 0xED, 0x0A, 0x60, 0xB0, 0x71, 0xDC, 0x2C, 0xF9, 0x23, 0xC0, 0xD8, 0x9C, 0x65, 0xC9, 0xB2, 0xEA, 0x80, 0x61, 0x6C, 0x46, 0xAE, 0x4C, 0x3F, 0x60, 0xDC, 0xA5, 0x9B, 0xED, 0xA4, 0xDF, 0x00, 0xBA, 0xFB, 0xC4, 0xF9, 0x18, 0x08, 0x0C, 0x48, 0xAE, 0xAF, 0xEF, 0x79, 0x02, 0x90, 0x0D, 0x15, 0xF9, 0x30, 0x0B, 0x90, 0x13, 0xEB, 0xBF, 0xDC, 0xF0, 0xEC, 0x03, 0xE0, 0xE7, 0xDD, 0x82, 0x0D, 0xA8, 0x52, 0xF0, 0x26, 0x17, 0xAB, 0xCA, 0x9F, 0x26, 0xA7, 0x3C, 0x1E, 0xF1, 0x8C, 0x34, 0x9E, 0x38, 0x46, 0x85, 0xD4, 0x30, 0xB7, 0x9E, 0x4F, 0x76, 0x91, 0x99, 0xFB, 0x80, 0x04, 0xE6, 0xEE, 0x94, 0xF0, 0x68, 0xB3, 0x0B, 0x70, 0xB7, 0xD7, 0x7D, 0x04, 0x00, 0xAE, 0x5D, 0x96, 0x9A, 0x92, 0x2E, 0x41, 0x19, 0xDF, 0x48, 0x27, 0xF3, 0xEB, 0x63, 0x48, 0x67, 0x5E, 0xEF, 0x61, 0xD3, 0x81, 0x1D, 0x7B, 0x81, 0xD5, 0x5F, 0x47, 0x06, 0xA2, 0xDB, 0x68, 0x40, 0x78, 0xB8, 0x8F, 0x3C, 0x39, 0xCB, 0x7A, 0xB0, 0x3D, 0x39, 0x63, 0xF6, 0x68, 0x02, 0xA6, 0x33, 0xF5, 0xB3, 0xC8, 0x41, 0x31, 0x53, 0xCA, 0x48, 0xC0, 0xFF, 0x2D, 0x1B, 0xB0, 0x80, 0x5D, 0xF5, 0x80, 0x5D, 0xB3, 0x4A, 0x73, 0x20, 0xB9, 0x1C, 0x4B, 0x2A, 0xC9, 0xD5, 0xBD, 0x93, 0x47, 0x90, 0xDE, 0x5F, 0x2E, 0xED, 0x20, 0x7D, 0x8A, 0xB9, 0xAE, 0x7B, 0x15, 0x6B, 0x1B, 0xCB, 0xDA, 0x8D, 0xE5, 0x3E, 0xF8, 0xFE, 0x9C, 0xFD, 0x79, 0xCD, 0x1A, 0x90, 0x1B, 0x75, 0x5F, 0x92, 0xE6, 0x87, 0xC6, 0x8E, 0x00, 0xD7, 0x49, 0x61, 0xD7, 0xC6, 0xB2, 0xE1, 0xCD, 0xD9, 0x18, 0x67, 0x36, 0xD6, 0x91, 0xDD, 0xD2, 0x47, 0xA7, 0x1F, 0x99, 0xB2, 0x71, 0xEA, 0x0B, 0x72, 0x43, 0x4D, 0x46, 0x53, 0x32, 0x41, 0x95, 0xEB, 0x45, 0x15, 0xB3, 0x41, 0x35, 0xAC, 0x97, 0x23, 0xEB, 0x69, 0x4E, 0x3A, 0xAA, 0x0C, 0xEB, 0x08, 0x00, 0xB3, 0x0E, 0xEA, 0x8E, 0x24, 0xAD, 0x62, 0x0C, 0xE6, 0x83, 0x8F, 0xCF, 0x81, 0x8D, 0x70, 0x61, 0xE3, 0x8B, 0xD9, 0xB4, 0xB6, 0x6C, 0x96, 0x33, 0x9B, 0x27, 0xC1, 0xE6, 0xEA, 0x0C, 0xBB, 0x4A, 0x9E, 0xDE, 0x31, 0xFF, 0x0B, 0x79, 0x69, 0x72, 0xE9, 0x23, 0x90, 0xAF, 0xB8, 0x5E, 0xD1, 0x1B, 0x36, 0x27, 0x82, 0x8D, 0x6A, 0xC3, 0x6E, 0xB8, 0x4F, 0x3A, 0x40, 0x17, 0x00, 0x60, 0x7D, 0x70, 0x9C, 0x27, 0x09, 0xAC, 0xDF, 0xC7, 0xC6, 0x69, 0xB2, 0x29, 0x23, 0xD8, 0xB4, 0x27, 0x0D, 0xCD, 0x25, 0x56, 0x6E, 0x6C, 0x52, 0xFE, 0x1F, 0xAD, 0xF3, 0x9F, 0x87, 0xB3, 0xD7, 0xC0, 0x5E, 0xA9, 0x25, 0x2D, 0x74, 0xCC, 0xF8, 0x3C, 0x23, 0xFC, 0x27, 0x9B, 0x38, 0x9C, 0x4D, 0xB5, 0xFE, 0xAF, 0xE6, 0x8F, 0x89, 0x8E, 0x6C, 0x08, 0xDB, 0xC0, 0x5C, 0x16, 0xF2, 0x0C, 0x00, 0x80, 0x6D, 0x43, 0xD8, 0xBC, 0x2D, 0xFF, 0x53, 0x73, 0xA1, 0xFF, 0xCD, 0x1C, 0x74, 0x69, 0x35, 0x7B, 0x74, 0x33, 0xA0, 0x55, 0x09, 0x64, 0x15, 0x01, 0x96, 0x6F, 0x80, 0x2A, 0x21, 0xD5, 0x2D, 0x13, 0x5F, 0x37, 0xE3, 0x81, 0x6C, 0x4B, 0xF0, 0xFD, 0x0D, 0x17, 0x76, 0x49, 0x27, 0xD6, 0x65, 0x09, 0x3B, 0xA5, 0x82, 0x9D, 0xA4, 0xFD, 0x5F, 0xC8, 0x1F, 0xBE, 0xC0, 0x11, 0x3B, 0xA0, 0x57, 0x0B, 0x20, 0x73, 0x0D, 0x30, 0xBC, 0x10, 0x88, 0x6F, 0x0F, 0x18, 0x6A, 0x01, 0xDB, 0x37, 0x02, 0xAE, 0xFE, 0x40, 0xB9, 0x33, 0xF0, 0x48, 0x0F, 0x88, 0x58, 0x01, 0xAE, 0x3F, 0x92, 0x9D, 0x67, 0xCA, 0x4E, 0x5F, 0xCC, 0x5A, 0xBB, 0xB1, 0xE6, 0xBB, 0x1B, 0xD7, 0x47, 0x85, 0x36, 0xD0, 0x3C, 0x14, 0x38, 0xF8, 0x06, 0x90, 0xDD, 0x03, 0xA4, 0xAA, 0x00, 0x43, 0x6F, 0x00, 0x9B, 0x0E, 0x00, 0x26, 0x4E, 0xC0, 0x86, 0x17, 0x80, 0xCB, 0x75, 0x20, 0x38, 0x11, 0x38, 0xD6, 0x0B, 0x08, 0x69, 0x0F, 0x9E, 0x33, 0x14, 0xB2, 0x73, 0x34, 0x59, 0xDB, 0xE6, 0xAC, 0x59, 0x25, 0x6B, 0xDC, 0xC0, 0x3E, 0xBE, 0x0F, 0x65, 0x33, 0xC6, 0xB1, 0x79, 0x65, 0x80, 0xD4, 0x52, 0x20, 0xCE, 0x10, 0x18, 0x74, 0x9B, 0xD6, 0x34, 0x60, 0x6C, 0x1E, 0xB0, 0x44, 0x07, 0xB0, 0x74, 0x02, 0x16, 0x2F, 0x02, 0x2E, 0x48, 0x00, 0x0B, 0x9C, 0x80, 0x97, 0xB7, 0x01, 0x27, 0xEE, 0x07, 0x53, 0xEE, 0xB0, 0x56, 0xD3, 0x58, 0xA3, 0x53, 0xAC, 0x7E, 0x03, 0xE7, 0x41, 0xD9, 0xDA, 0xEC, 0x66, 0x43, 0x36, 0x44, 0x11, 0x68, 0x1D, 0x04, 0xAC, 0xFB, 0x01, 0x28, 0x7D, 0x01, 0x16, 0x7B, 0x02, 0xBA, 0x7D, 0x01, 0x0F, 0x7F, 0x60, 0xC2, 0x49, 0xC0, 0xF5, 0x0B, 0x70, 0xC2, 0x16, 0x70, 0x9C, 0x01, 0x9C, 0x93, 0x04, 0xA6, 0x73, 0x0E, 0x84, 0x75, 0x32, 0x6B, 0x7A, 0x9D, 0x1D, 0xF5, 0x84, 0xD5, 0x49, 0xFC, 0xF7, 0x7D, 0x64, 0xFD, 0x60, 0xD3, 0x66, 0xB1, 0x61, 0x61, 0x6C, 0xC0, 0x1D, 0x76, 0x41, 0x2E, 0xD0, 0xC7, 0x18, 0x70, 0x6B, 0x07, 0x8C, 0xD1, 0x04, 0xE6, 0xA8, 0x00, 0x96, 0xE1, 0x80, 0x8D, 0x2C, 0x10, 0xA2, 0x0F, 0x4C, 0x1D, 0x05, 0x1C, 0xBE, 0x20, 0xB6, 0x9B, 0x80, 0xF3, 0xCE, 0x25, 0x76, 0x6C, 0x14, 0xAB, 0x2D, 0xC9, 0x0E, 0xF5, 0xFC, 0xE3, 0x3E, 0x32, 0xF7, 0xB3, 0x69, 0xCF, 0xD8, 0x50, 0x3F, 0x76, 0x45, 0x6B, 0xD6, 0xAB, 0x3B, 0x3B, 0xE7, 0x33, 0xD0, 0xBD, 0x08, 0x98, 0x69, 0x08, 0xE8, 0x9C, 0x04, 0xEC, 0x2E, 0x00, 0xD6, 0x83, 0x00, 0xCB, 0xF7, 0xC0, 0x3A, 0x69, 0xA1, 0x0E, 0x90, 0xDF, 0x0E, 0x18, 0xFF, 0x1F, 0xCC, 0xDD, 0x05, 0x58, 0x57, 0xD9, 0xBE, 0xC6, 0xF1, 0xAF, 0xD8, 0x4A, 0xA7, 0x82, 0x41, 0x97, 0x45, 0xB7, 0x23, 0x16, 0x60, 0xD0, 0x18, 0x83, 0x38, 0x7A, 0xEC, 0x56, 0xCE, 0x98, 0x80, 0x48, 0xD9, 0x89, 0xDD, 0xDD, 0xED, 0xB4, 0x63, 0x77, 0xE7, 0x74, 0x77, 0x77, 0xDA, 0x72, 0x59, 0xCF, 0x7B, 0x63, 0x98, 0x9E, 0xA7, 0xEE, 0xD9, 0xC6, 0xC7, 0x80, 0xF5, 0xBE, 0x3C, 0x7B, 0xED, 0xFF, 0xFE, 0xD1, 0x2E, 0xF0, 0x61, 0x29, 0x74, 0xD4, 0x79, 0x20, 0x2E, 0x4A, 0x86, 0xBE, 0x27, 0x83, 0xFC, 0xAA, 0xF6, 0xB8, 0xB4, 0x42, 0x6E, 0x7B, 0x4F, 0xCE, 0x8C, 0xAC, 0x9A, 0x3F, 0xF9, 0x49, 0x39, 0xF8, 0x6B, 0x99, 0xD3, 0x14, 0xEC, 0xDF, 0x83, 0x8C, 0xCF, 0x20, 0x2C, 0xA0, 0xDA, 0xA0, 0x2E, 0xA9, 0x90, 0xD9, 0xAF, 0x46, 0x68, 0xFB, 0x32, 0xC8, 0xF7, 0xAE, 0x17, 0xD8, 0x26, 0x1F, 0xB6, 0xBC, 0x56, 0x2F, 0x21, 0x6E, 0x35, 0x5C, 0x2E, 0xAF, 0xF5, 0x7D, 0xEB, 0x6A, 0x26, 0xAB, 0x66, 0x56, 0xDC, 0x7E, 0x23, 0x04, 0xB7, 0x94, 0x81, 0xCF, 0xC8, 0xAB, 0x6B, 0xD0, 0x3E, 0xEC, 0x29, 0xA7, 0x0D, 0x93, 0x85, 0xB9, 0xB2, 0xF8, 0x81, 0x7C, 0x74, 0xA1, 0x65, 0x6F, 0x63, 0xC6, 0x7D, 0x67, 0x5B, 0x63, 0xFC, 0x41, 0xEF, 0x4E, 0x46, 0x1D, 0xD1, 0xCB, 0xA0, 0xD6, 0xA7, 0x41, 0x03, 0x42, 0xDF, 0x04, 0x4B, 0xFF, 0x3E, 0xE3, 0x5B, 0x1E, 0x06, 0x5B, 0xDB, 0x25, 0xB7, 0x02, 0x3F, 0x04, 0x9B, 0x1F, 0x8F, 0x25, 0xF8, 0x39, 0x81, 0xF5, 0x07, 0x3F, 0xD9, 0xFB, 0x98, 0x35, 0x3C, 0x2A, 0x2A, 0xFC, 0xEE, 0xE9, 0x1C, 0x78, 0xC5, 0x4A, 0xD7, 0xC7, 0x96, 0xE9, 0x7A, 0xA0, 0xF4, 0x49, 0x59, 0xF8, 0xB6, 0x2C, 0x9B, 0x2A, 0x7B, 0x64, 0x35, 0x2A, 0x30, 0xA6, 0x04, 0xBA, 0x0F, 0x34, 0xC6, 0x38, 0x37, 0x0B, 0x34, 0xFA, 0x6F, 0x8D, 0x0A, 0x33, 0x42, 0x64, 0xEF, 0x5A, 0xA5, 0x8D, 0xBE, 0x82, 0xB8, 0xC9, 0x71, 0xED, 0x6C, 0x86, 0x42, 0xEB, 0xA3, 0xC3, 0xA2, 0xEA, 0x8E, 0xAF, 0xF4, 0xCB, 0xA5, 0xC3, 0xAA, 0xDB, 0x42, 0x9B, 0xF2, 0x53, 0x1F, 0x5B, 0xA4, 0xC1, 0x23, 0x4D, 0x6E, 0xDF, 0x04, 0x08, 0x8D, 0xA9, 0xA8, 0xB0, 0xA8, 0x0E, 0x4D, 0xB7, 0x56, 0x54, 0xD4, 0xCB, 0x04, 0x17, 0x97, 0x8A, 0x0A, 0xEB, 0xE1, 0x65, 0x0F, 0xD0, 0xFE, 0x8B, 0x90, 0x53, 0x17, 0x59, 0xE5, 0x19, 0x7B, 0x8D, 0x6D, 0x7C, 0xD8, 0xD8, 0x25, 0x3F, 0x70, 0x95, 0x31, 0x6A, 0x77, 0xF0, 0x45, 0xA3, 0xCB, 0xFB, 0x1D, 0xBA, 0x18, 0xA1, 0xFB, 0x30, 0xA4, 0xA5, 0xC5, 0xE7, 0xC6, 0x8C, 0x81, 0xE1, 0xE3, 0x8C, 0x29, 0xDB, 0x07, 0x6F, 0x32, 0x26, 0xF7, 0x5D, 0x3A, 0xC8, 0xD8, 0x79, 0xF3, 0xB1, 0x97, 0x8C, 0x29, 0xF5, 0x6F, 0xD7, 0x37, 0xC6, 0x06, 0x69, 0x2F, 0x04, 0xC7, 0xC8, 0x16, 0xDE, 0xC6, 0x22, 0x2C, 0xCC, 0xBA, 0x4C, 0xBA, 0xEE, 0xBD, 0xD1, 0xF8, 0xD8, 0xF6, 0x26, 0x63, 0x8D, 0x29, 0x25, 0x2D, 0x36, 0x18, 0x63, 0x1D, 0xC2, 0x5C, 0x8C, 0xD0, 0xCB, 0x59, 0x0E, 0x68, 0x27, 0x07, 0xB5, 0x46, 0x9E, 0x95, 0x7D, 0xD6, 0x78, 0xAD, 0x32, 0x3E, 0x1A, 0x9E, 0x71, 0xDC, 0x38, 0xE4, 0xCC, 0xE2, 0xBE, 0xC6, 0xCC, 0xFB, 0x47, 0x1D, 0x8D, 0x43, 0x17, 0x29, 0x37, 0xF3, 0xA8, 0x8C, 0x5A, 0x52, 0x21, 0xFD, 0x8D, 0x13, 0xDF, 0x74, 0xD7, 0x2A, 0xAF, 0x7A, 0x7D, 0x64, 0x4C, 0xF3, 0x09, 0x4E, 0x35, 0x46, 0xDF, 0x8C, 0x5A, 0x6C, 0x84, 0x61, 0x5F, 0xCB, 0x5C, 0x5B, 0x39, 0x61, 0x84, 0xCC, 0x6B, 0x2D, 0xF3, 0x43, 0xE5, 0xC4, 0x10, 0xAE, 0x18, 0x17, 0x56, 0xEF, 0x39, 0xC8, 0x58, 0x72, 0x7C, 0xDB, 0x12, 0x63, 0xDE, 0xD6, 0xED, 0x03, 0x8C, 0x93, 0x47, 0x2B, 0x37, 0x77, 0x86, 0xEC, 0xB1, 0x55, 0x66, 0xB6, 0x37, 0xF6, 0xC5, 0x6F, 0x33, 0x40, 0x46, 0x42, 0xE8, 0x3D, 0x63, 0x4C, 0x52, 0xCC, 0x70, 0x23, 0x8C, 0xAB, 0x29, 0x0B, 0xBE, 0x96, 0x25, 0x43, 0xE5, 0xCC, 0x0A, 0x39, 0xDF, 0x4D, 0x2E, 0x4C, 0x96, 0x0B, 0x9A, 0x59, 0x9D, 0x34, 0x6E, 0x6F, 0x9B, 0xE5, 0x69, 0xDC, 0xE3, 0x5E, 0x7E, 0xE3, 0x97, 0xF3, 0xCF, 0xCE, 0x57, 0xE5, 0xAC, 0x13, 0xB2, 0x34, 0x53, 0x4E, 0x78, 0xC4, 0x98, 0xF9, 0x5A, 0x78, 0x30, 0x40, 0x5C, 0x4E, 0xCC, 0x1E, 0x94, 0x7B, 0x4C, 0x16, 0xF5, 0x96, 0xF3, 0xEC, 0xE4, 0xA2, 0x30, 0xB9, 0xF1, 0x09, 0xB9, 0x35, 0x4C, 0x9E, 0xDB, 0x29, 0xAF, 0xDD, 0xA8, 0x53, 0xDB, 0x78, 0xEB, 0x5E, 0xF6, 0x60, 0xE3, 0xFB, 0xAE, 0x27, 0x2A, 0x8C, 0x77, 0xB2, 0x95, 0xF7, 0xD5, 0x45, 0xF9, 0xC2, 0x24, 0xB9, 0xE7, 0x0D, 0xB9, 0xCF, 0xDE, 0x18, 0x7B, 0x27, 0x1E, 0x1D, 0xA5, 0xC5, 0x72, 0x7A, 0x1F, 0xB9, 0x30, 0x45, 0xAE, 0x3D, 0xFA, 0x4F, 0xE7, 0x8F, 0x6E, 0x5F, 0xCA, 0x45, 0xE5, 0xFF, 0x64, 0x0E, 0x2A, 0x42, 0xC7, 0x9C, 0x4B, 0x72, 0xC3, 0x8B, 0xFF, 0xC9, 0x73, 0xD0, 0xED, 0x6C, 0x70, 0x39, 0x0B, 0x47, 0x52, 0xA1, 0x71, 0x1A, 0x6C, 0xCE, 0x82, 0x56, 0x0D, 0x60, 0xE9, 0x30, 0x88, 0x07, 0xCC, 0x5E, 0xC8, 0x7E, 0x00, 0x7B, 0x57, 0xEB, 0xD7, 0xE3, 0xCE, 0x50, 0xB1, 0x0F, 0x06, 0x8F, 0xD3, 0x1A, 0xD9, 0x2E, 0x32, 0xDD, 0x4E, 0x26, 0xDE, 0x95, 0xD1, 0x33, 0xE5, 0xDF, 0xED, 0xB1, 0xAD, 0x01, 0xD4, 0x3E, 0x09, 0xCF, 0x25, 0x82, 0x53, 0x16, 0x2C, 0x1B, 0x00, 0xCD, 0xBE, 0x83, 0x79, 0xCF, 0x40, 0xFC, 0x30, 0x18, 0xEA, 0x09, 0x49, 0xB3, 0x2B, 0x7D, 0x0A, 0x5E, 0x9E, 0x02, 0x43, 0x12, 0xE1, 0x41, 0x1C, 0xE4, 0xF4, 0x41, 0x73, 0x97, 0x8B, 0xEC, 0xDA, 0x5C, 0xC6, 0x7A, 0xC9, 0xB0, 0xFB, 0x7F, 0xAF, 0xC7, 0xE6, 0x0C, 0x59, 0xFE, 0xA5, 0x2C, 0xBB, 0x02, 0x75, 0x27, 0xC2, 0xE3, 0x83, 0xC0, 0x7D, 0x2E, 0x8C, 0xEA, 0x08, 0xB1, 0x65, 0x30, 0xE0, 0x16, 0x74, 0x9C, 0x0D, 0x83, 0x5E, 0xD7, 0x6C, 0xD8, 0xF7, 0x53, 0xB8, 0x12, 0x0F, 0xDD, 0x35, 0x97, 0x91, 0xD2, 0x4C, 0x76, 0x3C, 0x26, 0x23, 0x5E, 0x97, 0x41, 0x8D, 0xFF, 0x5E, 0x8F, 0x2D, 0x7D, 0xE4, 0xCC, 0xD3, 0xB2, 0x30, 0x45, 0x8E, 0x1A, 0x04, 0xDE, 0x8D, 0x61, 0xF0, 0x3C, 0x88, 0xFE, 0x16, 0xCC, 0x77, 0xD4, 0x8D, 0xBD, 0x08, 0xC9, 0x89, 0x50, 0xD4, 0x19, 0xBA, 0x77, 0x86, 0x5D, 0x73, 0x21, 0xDD, 0x02, 0x9D, 0x87, 0xF1, 0x32, 0xDA, 0x53, 0x86, 0xF4, 0x94, 0x81, 0xDF, 0xFE, 0x79, 0x8F, 0xED, 0xDD, 0xE4, 0x1C, 0x07, 0x59, 0xB0, 0x4D, 0x16, 0x5A, 0xCA, 0x81, 0xA7, 0xA0, 0x49, 0x28, 0xF4, 0xDA, 0x04, 0xE1, 0xDD, 0x20, 0xA7, 0x0D, 0x44, 0xAD, 0x81, 0x4E, 0xB3, 0x20, 0x3F, 0x15, 0x92, 0x57, 0xC3, 0xF6, 0x7B, 0xD0, 0x59, 0xFB, 0x81, 0x98, 0xD7, 0x64, 0x58, 0xAC, 0x6C, 0x61, 0x25, 0x7D, 0x0A, 0xE5, 0x6F, 0xF6, 0xC1, 0x05, 0x39, 0xEB, 0x73, 0x59, 0xF0, 0x8A, 0x2C, 0xB9, 0x2C, 0xFF, 0x7D, 0x44, 0xA6, 0xB7, 0x00, 0xC7, 0xA6, 0x95, 0x7E, 0x00, 0x41, 0x75, 0x21, 0xAD, 0x1C, 0xA2, 0x1B, 0x43, 0x87, 0x32, 0x28, 0xEC, 0x00, 0xED, 0x87, 0xC2, 0xE6, 0x1A, 0x10, 0xE3, 0x07, 0x9F, 0x4C, 0x83, 0xF0, 0x2F, 0x94, 0xD1, 0xF2, 0x86, 0xF4, 0x7B, 0x44, 0xBA, 0x53, 0xB5, 0xC7, 0xC6, 0x1F, 0xE4, 0x8C, 0x06, 0xB2, 0xC0, 0x4A, 0x16, 0xF5, 0x97, 0x93, 0x2E, 0xCA, 0x8C, 0x09, 0xB2, 0x4B, 0x24, 0x58, 0x96, 0x42, 0xE2, 0x08, 0xF0, 0x5F, 0x02, 0xAD, 0x0B, 0xA0, 0xE3, 0x22, 0x88, 0xDD, 0x0E, 0x93, 0x0F, 0x42, 0xD4, 0x32, 0x58, 0x5B, 0x0C, 0x41, 0xED, 0xE1, 0xC2, 0x11, 0x08, 0x8E, 0x50, 0x56, 0x80, 0xC4, 0x63, 0x86, 0x74, 0x7B, 0x20, 0xF7, 0x97, 0xA3, 0xB9, 0xE3, 0x79, 0x99, 0x3F, 0x47, 0x16, 0xD5, 0x90, 0x85, 0xD9, 0x32, 0xA3, 0x9A, 0xEC, 0xDA, 0x42, 0x76, 0xF8, 0x14, 0x2C, 0x6A, 0x43, 0xEB, 0xE7, 0xC0, 0xAB, 0x33, 0x44, 0x6D, 0x84, 0xF6, 0x8B, 0x2A, 0x8D, 0x86, 0xE1, 0xB5, 0x20, 0x6C, 0x1D, 0x2C, 0x76, 0x84, 0xE6, 0xBB, 0xE1, 0xD9, 0xB7, 0x21, 0xF0, 0x65, 0xF8, 0x2C, 0x1A, 0x7C, 0x9E, 0x50, 0x6E, 0xE3, 0x11, 0xD2, 0xF1, 0x03, 0x39, 0xF7, 0x19, 0x94, 0x7F, 0x50, 0x4E, 0xF9, 0x42, 0x96, 0xEC, 0x90, 0x19, 0x6E, 0xB2, 0x6B, 0x1D, 0xD9, 0x71, 0xBD, 0xC5, 0x5B, 0xC6, 0xE0, 0x2D, 0x0E, 0x36, 0x46, 0x1D, 0x66, 0xAE, 0xA9, 0xD1, 0x36, 0x20, 0xC8, 0xDB, 0x02, 0xEA, 0xB5, 0xCE, 0x3A, 0xD7, 0x78, 0x18, 0xD8, 0xC6, 0x94, 0x5E, 0x6F, 0xB8, 0x14, 0xEC, 0xDE, 0xDA, 0xBF, 0xC5, 0x69, 0x0C, 0xD8, 0xBC, 0xF1, 0x46, 0x33, 0xFB, 0x97, 0xA1, 0x6E, 0xF3, 0x8A, 0x0A, 0xC7, 0x31, 0xDA, 0x0B, 0x0E, 0xCB, 0xAD, 0xE6, 0x1B, 0xA1, 0x08, 0x94, 0xFF, 0x8A, 0x9C, 0x5A, 0x4B, 0xA6, 0x07, 0xC9, 0xCE, 0x57, 0x2C, 0x07, 0x1B, 0xDB, 0x9E, 0xB3, 0x2A, 0x32, 0x36, 0x9F, 0xDF, 0xC4, 0xD1, 0xE8, 0xB8, 0xB8, 0x59, 0x84, 0x11, 0x42, 0x13, 0x6A, 0x17, 0xD6, 0xEA, 0x0E, 0x21, 0x83, 0x82, 0xCF, 0x42, 0xA5, 0xB5, 0x7B, 0x2D, 0x36, 0x36, 0x1B, 0x56, 0x1C, 0x8C, 0x71, 0xD7, 0xBE, 0x57, 0x8D, 0x01, 0x99, 0x2F, 0x6E, 0x35, 0x7A, 0x7B, 0x68, 0x2F, 0xB8, 0xCE, 0x97, 0xD6, 0xEB, 0x7E, 0xD9, 0xA3, 0x6C, 0xB9, 0xEC, 0x54, 0xEE, 0xD2, 0xC1, 0x98, 0x32, 0xC1, 0xFA, 0xB2, 0xB1, 0x5D, 0x8C, 0x53, 0x3F, 0x63, 0x73, 0x2F, 0xCF, 0x8E, 0xC6, 0xEA, 0xB3, 0x63, 0xDA, 0x18, 0xE1, 0x91, 0x1C, 0x64, 0xA4, 0x8C, 0xAA, 0xE9, 0xDF, 0xC3, 0x18, 0x39, 0xA4, 0x87, 0xB7, 0x31, 0xF8, 0x99, 0xB1, 0x89, 0xC6, 0x90, 0xDD, 0x7B, 0x87, 0x18, 0x5B, 0x6D, 0x3D, 0xBF, 0xD9, 0xD8, 0xBC, 0x4C, 0xF9, 0x9E, 0xC1, 0xB2, 0x41, 0xCE, 0x2F, 0x7B, 0x24, 0xD7, 0x68, 0x30, 0xDA, 0x98, 0xFE, 0xA2, 0xCD, 0x6D, 0x63, 0xCC, 0xBC, 0xA6, 0x2F, 0x19, 0x5B, 0xE4, 0xF9, 0x06, 0x1B, 0x21, 0xF1, 0x9E, 0xEC, 0x9C, 0x2E, 0xBB, 0xD6, 0x47, 0xA6, 0xCB, 0x2E, 0x3B, 0xEB, 0x4E, 0x37, 0xB6, 0xDF, 0x91, 0x35, 0xCE, 0x98, 0x94, 0xD3, 0xBF, 0xCC, 0x18, 0x9B, 0x7A, 0xA0, 0xB3, 0x31, 0x7C, 0xD3, 0xC1, 0x89, 0xC6, 0xB0, 0x77, 0x94, 0xDF, 0xDC, 0x47, 0x7A, 0x3D, 0x62, 0xEC, 0x7E, 0xCB, 0xF9, 0x16, 0x40, 0x37, 0x2B, 0xBB, 0x9A, 0xC6, 0xD8, 0x82, 0xA6, 0x4B, 0x8C, 0x75, 0x9A, 0xC7, 0x45, 0x18, 0x21, 0xE5, 0x71, 0x99, 0xFE, 0x9E, 0xEC, 0x96, 0x23, 0xBB, 0xFF, 0x28, 0x7B, 0xAC, 0x47, 0x3E, 0x94, 0x59, 0x53, 0xDA, 0x36, 0x34, 0xA6, 0x6D, 0x1E, 0xFD, 0x0A, 0xC6, 0xA7, 0x56, 0x64, 0x1B, 0x3B, 0xF7, 0x3D, 0xD3, 0xD6, 0x98, 0x35, 0x4E, 0xF9, 0x21, 0x9F, 0xC9, 0x56, 0xF5, 0x8D, 0xDD, 0x5E, 0x76, 0x7A, 0x19, 0x20, 0xEE, 0x80, 0xE7, 0x38, 0x23, 0xA4, 0x7E, 0x29, 0x33, 0xF3, 0x65, 0xCF, 0x1A, 0x72, 0xD4, 0x72, 0xF9, 0x78, 0xBC, 0x1C, 0xDF, 0x5A, 0x4E, 0x18, 0x83, 0x1C, 0x29, 0x73, 0xAD, 0x65, 0xBE, 0xC7, 0xEE, 0xAF, 0x8C, 0xC5, 0x2B, 0x96, 0xBC, 0x6D, 0x9C, 0xBE, 0x56, 0xB9, 0x63, 0xFD, 0xE4, 0x88, 0x7B, 0x32, 0x35, 0xDB, 0xD8, 0xE1, 0x92, 0xEF, 0x2E, 0x94, 0xFB, 0xBA, 0xEC, 0x1E, 0x25, 0xC7, 0x54, 0xBD, 0x92, 0x28, 0xF6, 0x92, 0xD3, 0x1B, 0x21, 0x67, 0xC8, 0x69, 0xDB, 0xE5, 0xCC, 0x0B, 0x72, 0x47, 0x8F, 0xB4, 0x0C, 0xE3, 0xB6, 0x45, 0x39, 0x75, 0x8D, 0x37, 0x3F, 0x7D, 0xEA, 0x0D, 0x8C, 0xFD, 0x94, 0xBB, 0xDB, 0x45, 0x4E, 0x1D, 0x26, 0x27, 0xA5, 0xCA, 0xB4, 0xA7, 0x01, 0x60, 0xE4, 0x4C, 0x39, 0xC9, 0x4F, 0x16, 0xAD, 0x91, 0x33, 0xBC, 0xE4, 0x74, 0x1B, 0xB9, 0xA6, 0xF6, 0x5F, 0xDD, 0xA1, 0x87, 0xEE, 0x91, 0x5B, 0x96, 0xFF, 0x9D, 0xF9, 0xE3, 0xAB, 0x74, 0x39, 0x52, 0xF3, 0x27, 0x85, 0xC3, 0xE4, 0xCC, 0xB3, 0x72, 0xF9, 0x8C, 0xFF, 0xA4, 0x39, 0x68, 0x5F, 0xB8, 0x5C, 0x14, 0x24, 0xA7, 0x2D, 0x80, 0x5A, 0xE5, 0x30, 0xF5, 0x16, 0x38, 0x87, 0xC0, 0xF0, 0x25, 0x10, 0x9A, 0x03, 0xFD, 0xBA, 0x69, 0x1E, 0xCA, 0x7A, 0x16, 0x9E, 0x7A, 0x16, 0xB2, 0x63, 0xE0, 0xEB, 0x4E, 0x90, 0xD6, 0x51, 0x6B, 0x25, 0x7C, 0x25, 0x23, 0x03, 0x65, 0xAB, 0xDB, 0xD2, 0x3F, 0x59, 0xFE, 0x55, 0x8F, 0x39, 0x45, 0x72, 0x5A, 0xA1, 0x9C, 0xF2, 0x96, 0x1C, 0xE9, 0x00, 0x5E, 0x2F, 0x43, 0xBF, 0xEB, 0x10, 0xD2, 0x04, 0xFA, 0x3E, 0x06, 0x6D, 0x1B, 0x40, 0xF2, 0x27, 0xB0, 0xE7, 0x63, 0xC8, 0x78, 0x17, 0xD6, 0x8F, 0x83, 0x2E, 0x13, 0x50, 0xFE, 0x0F, 0x32, 0xF8, 0xA6, 0x0C, 0xBC, 0x2B, 0xBD, 0x52, 0xFF, 0xBC, 0xC7, 0x86, 0x7E, 0x72, 0xEA, 0xA3, 0x72, 0xF2, 0x3C, 0x59, 0xBA, 0x52, 0xA6, 0xCC, 0x04, 0x97, 0x8F, 0xA0, 0xC7, 0x03, 0x68, 0xE1, 0x0D, 0xBD, 0x0E, 0x42, 0x78, 0x73, 0x68, 0xFB, 0x1D, 0x94, 0x7C, 0x0A, 0x9D, 0x37, 0xC0, 0x9A, 0x0A, 0x88, 0x99, 0xAC, 0x35, 0x43, 0x1F, 0x95, 0xCD, 0xBF, 0x97, 0x3E, 0x65, 0xD2, 0x1D, 0xF9, 0x9B, 0xFC, 0xA9, 0x72, 0xBA, 0x8F, 0x2C, 0x70, 0x97, 0x25, 0xFB, 0xE4, 0xC4, 0x1F, 0x64, 0xE7, 0x73, 0x60, 0x97, 0x09, 0xA9, 0xFD, 0x20, 0x20, 0x17, 0xB2, 0x0E, 0x54, 0x7A, 0x1C, 0x62, 0x77, 0x41, 0xC1, 0xBB, 0x95, 0x5E, 0x83, 0x95, 0x0F, 0x21, 0x7C, 0x2F, 0xBA, 0xDF, 0x07, 0x49, 0xBF, 0x64, 0xE9, 0x5E, 0x5D, 0xBA, 0x3E, 0xF7, 0xFB, 0x3D, 0x66, 0x1C, 0x91, 0x85, 0x01, 0x72, 0xCA, 0x2A, 0x59, 0x52, 0x5F, 0x76, 0x49, 0x90, 0x09, 0x7D, 0xA1, 0xCE, 0x17, 0xD0, 0xAE, 0x2B, 0xB8, 0x3E, 0x0F, 0x49, 0x9B, 0xC0, 0xAF, 0x3B, 0x84, 0x1F, 0x83, 0xB1, 0xAE, 0x10, 0xB6, 0x1A, 0x56, 0x4D, 0x84, 0xC0, 0x3B, 0x70, 0xBD, 0x10, 0xFC, 0xDF, 0x51, 0x86, 0xC7, 0x72, 0xD9, 0x28, 0x50, 0x3A, 0x5C, 0xAC, 0xDA, 0xA3, 0xEC, 0x9C, 0x9C, 0xE2, 0x24, 0x0B, 0x1F, 0xCA, 0xB2, 0xB6, 0xB2, 0x6B, 0x90, 0x4C, 0x78, 0x43, 0xC6, 0xAF, 0x92, 0xB1, 0xB5, 0xA1, 0xC1, 0x3E, 0x08, 0x7B, 0x06, 0xBC, 0xF7, 0x40, 0xCB, 0x49, 0x30, 0xA2, 0x08, 0x9A, 0xCD, 0x80, 0xA5, 0xD5, 0xC0, 0xF3, 0x30, 0x9C, 0xDC, 0x08, 0x5E, 0x4B, 0x94, 0xE5, 0x76, 0x5B, 0x3A, 0x6E, 0x94, 0x96, 0x73, 0x64, 0xB9, 0x1E, 0x3D, 0xC8, 0x2B, 0x93, 0x85, 0x47, 0x65, 0x69, 0x82, 0xEC, 0xFA, 0xB4, 0x4C, 0x72, 0x95, 0x6D, 0x7E, 0x90, 0x71, 0x61, 0x32, 0xE8, 0x27, 0x70, 0x29, 0x80, 0x80, 0x03, 0x10, 0x34, 0x02, 0x7C, 0x2E, 0xC3, 0x40, 0x1B, 0x70, 0xDB, 0x08, 0xB3, 0xDE, 0x02, 0x97, 0x7E, 0xF0, 0x5C, 0x2C, 0x34, 0xAC, 0x0D, 0xDF, 0x3E, 0x00, 0xC7, 0x05, 0x28, 0xFF, 0x79, 0x59, 0xB3, 0x8E, 0x2C, 0x79, 0x07, 0xE5, 0xBF, 0x28, 0x4B, 0xEE, 0x21, 0xFB, 0xC9, 0x24, 0x2B, 0x19, 0x1F, 0x25, 0xDB, 0xCE, 0x90, 0xC1, 0xB3, 0xA4, 0x9F, 0x03, 0x38, 0xCE, 0x07, 0xF7, 0x62, 0x08, 0x0E, 0x80, 0x46, 0xDF, 0x41, 0x76, 0x22, 0xB8, 0x5C, 0x87, 0xE2, 0x36, 0x60, 0xEB, 0x0F, 0xDB, 0x5F, 0x04, 0xAB, 0xCF, 0xE0, 0xDA, 0x06, 0xB0, 0xD4, 0x3E, 0xA5, 0xFA, 0x0D, 0x09, 0xB2, 0x08, 0x94, 0xFB, 0xB3, 0x9C, 0xFE, 0x94, 0x4C, 0x7A, 0x4E, 0xC6, 0x4F, 0x43, 0xDE, 0x91, 0xE1, 0xCB, 0xA5, 0x4F, 0x4F, 0xA9, 0xC3, 0x39, 0x0F, 0x6A, 0x7F, 0xEF, 0x1F, 0x60, 0xB7, 0x1D, 0x2C, 0x9F, 0xEE, 0x9A, 0x5B, 0x27, 0x19, 0xAC, 0x9D, 0x73, 0x8F, 0x57, 0x1B, 0x03, 0x56, 0xEB, 0x56, 0x9F, 0x04, 0xA8, 0x57, 0xEB, 0xF4, 0x24, 0x63, 0x2D, 0xA7, 0x5B, 0xF5, 0x8D, 0xBF, 0xDF, 0x63, 0xFA, 0x1A, 0xD9, 0x29, 0x52, 0xC6, 0x27, 0x21, 0x37, 0xC8, 0xA8, 0x86, 0xD2, 0xED, 0x2B, 0x1B, 0x3D, 0x25, 0x1E, 0xAF, 0x4B, 0xCF, 0xF1, 0xB2, 0xC1, 0x7A, 0xEF, 0x3D, 0x18, 0x5F, 0x4C, 0x9A, 0x6A, 0x74, 0x9A, 0x3B, 0x78, 0xA2, 0xD1, 0xFE, 0xBD, 0xF2, 0x21, 0x46, 0x87, 0x4F, 0x8E, 0xBF, 0x68, 0xB4, 0x5A, 0xFE, 0x7D, 0x85, 0xB1, 0x8E, 0xC3, 0xEF, 0xF5, 0x48, 0x8C, 0x95, 0x6D, 0x8E, 0xD5, 0x68, 0x62, 0x8C, 0xD7, 0x7E, 0x21, 0xE2, 0xA9, 0x5A, 0xAB, 0x8D, 0xF5, 0xFA, 0x7A, 0x68, 0xA7, 0x10, 0x10, 0x21, 0x03, 0x8D, 0x46, 0x0F, 0xE9, 0x1B, 0x66, 0xE5, 0x69, 0xF4, 0x9C, 0x9B, 0xF8, 0xAE, 0xB1, 0xA9, 0xCF, 0xBF, 0x16, 0x1B, 0x5D, 0x16, 0xCF, 0x3B, 0x6B, 0x6C, 0xB2, 0xE2, 0xA4, 0x9D, 0xD1, 0xA5, 0xE6, 0x0F, 0xFA, 0x48, 0xDF, 0xF3, 0xEA, 0x51, 0xEB, 0x6B, 0x63, 0x5A, 0x9E, 0x56, 0x69, 0x9F, 0x59, 0x7B, 0xA8, 0x31, 0xC1, 0x5D, 0x7F, 0x6F, 0xB5, 0xC3, 0xF1, 0x23, 0x63, 0x1D, 0x2B, 0xAF, 0x2B, 0xE8, 0x5F, 0x5E, 0x92, 0xC1, 0x6B, 0x64, 0xC8, 0x5E, 0xE4, 0x7C, 0x19, 0xBC, 0x96, 0xAB, 0xC6, 0x66, 0xDF, 0xB5, 0xCB, 0x35, 0x06, 0xDE, 0xED, 0x7D, 0xDE, 0xE8, 0xB3, 0x7A, 0xC1, 0x6D, 0xA3, 0xDF, 0xEE, 0xD3, 0xBB, 0x8C, 0xEE, 0xDB, 0x4E, 0x77, 0x33, 0xBA, 0xBE, 0xA1, 0x1E, 0xB6, 0xCF, 0x1B, 0x3B, 0x79, 0xD4, 0xF5, 0x80, 0x4A, 0xF3, 0xAA, 0xED, 0x36, 0x06, 0x8F, 0x73, 0xB5, 0x32, 0x42, 0xD0, 0x13, 0x32, 0x6C, 0xAC, 0x8C, 0xDC, 0x20, 0xA3, 0x57, 0xC8, 0x98, 0x6D, 0xC8, 0x77, 0x91, 0xE7, 0x65, 0x78, 0xCF, 0xA4, 0x0F, 0x8D, 0xA1, 0xDD, 0xFA, 0xBE, 0x6D, 0x6C, 0xF1, 0xF1, 0xC2, 0x77, 0x8C, 0xAD, 0xDA, 0x9C, 0x18, 0x6F, 0xF4, 0xBD, 0x7F, 0x78, 0x19, 0xC6, 0x3C, 0xF5, 0x70, 0xFD, 0xDC, 0x98, 0x18, 0x5F, 0xA7, 0x0C, 0x20, 0x64, 0x6C, 0x53, 0x2F, 0x94, 0x9B, 0x29, 0xA3, 0x86, 0xC8, 0xA4, 0xC6, 0xB2, 0xCB, 0x4D, 0x99, 0x12, 0x2D, 0xD3, 0x2C, 0x91, 0x2F, 0x23, 0xBF, 0x90, 0xC9, 0xB7, 0x64, 0xFB, 0x51, 0x63, 0xAA, 0x19, 0x53, 0x86, 0xF4, 0x1E, 0x67, 0x0C, 0x19, 0x7C, 0xB4, 0xA5, 0xB1, 0xC7, 0x0C, 0xE5, 0xB7, 0xF8, 0x5A, 0xFA, 0xEF, 0x34, 0xB6, 0xF2, 0x77, 0x47, 0x47, 0x64, 0x1B, 0x99, 0x90, 0x22, 0x93, 0x9D, 0x65, 0xC6, 0xC7, 0x72, 0x64, 0xA6, 0x1C, 0x53, 0x2E, 0xFF, 0x5D, 0x2A, 0xC7, 0xD6, 0x43, 0x0E, 0x95, 0x63, 0x12, 0xE4, 0x36, 0xB7, 0x5E, 0xEB, 0x8C, 0x05, 0xFD, 0x56, 0x8D, 0x36, 0xCE, 0x19, 0xA3, 0xDC, 0x09, 0x5F, 0xCB, 0xDC, 0x1C, 0x99, 0x3A, 0x44, 0x46, 0xBB, 0xA2, 0x97, 0xD7, 0x49, 0xA6, 0x27, 0xCA, 0x31, 0x6F, 0xCB, 0x49, 0x1F, 0xC8, 0xFC, 0x64, 0xE4, 0xAB, 0xB2, 0xE8, 0xA2, 0x9C, 0xDA, 0x43, 0x16, 0xEF, 0x94, 0x77, 0x7D, 0xFB, 0x8C, 0xD1, 0x55, 0xB0, 0x7F, 0x3F, 0xC6, 0xE7, 0xAB, 0xCE, 0x1B, 0x0F, 0x3D, 0xE4, 0xEB, 0x2F, 0xCA, 0x99, 0xD1, 0x32, 0xF9, 0x32, 0x9A, 0x43, 0x63, 0xE4, 0x84, 0x1C, 0x59, 0xBC, 0x44, 0xCE, 0x6D, 0xFD, 0xFF, 0x39, 0x07, 0x2D, 0xB9, 0x2A, 0xA7, 0x8F, 0x94, 0x45, 0x82, 0xC2, 0x93, 0x32, 0xC5, 0x0E, 0xAC, 0xED, 0x20, 0xB5, 0x1B, 0x38, 0xDF, 0x83, 0xCC, 0x48, 0x08, 0x8D, 0x82, 0xB8, 0x24, 0x28, 0x48, 0x32, 0xD7, 0x1F, 0x6C, 0xCA, 0x80, 0xD0, 0x13, 0xE8, 0x7E, 0xDF, 0x5A, 0xFA, 0x58, 0x4B, 0x77, 0x64, 0xC3, 0x76, 0xF0, 0x67, 0x3D, 0x66, 0x0F, 0x94, 0x45, 0x54, 0x35, 0xF5, 0xA0, 0x4C, 0x7A, 0x03, 0xEA, 0xBC, 0x51, 0x69, 0x13, 0x70, 0x5C, 0x0C, 0x5D, 0xDD, 0xA0, 0xB9, 0x1B, 0x44, 0xF8, 0xC2, 0x78, 0xDF, 0x4A, 0xAB, 0xE9, 0xFD, 0x75, 0x2D, 0xB3, 0xB5, 0xA6, 0xEF, 0x1B, 0x55, 0xF3, 0x5D, 0x5D, 0xA5, 0x43, 0xCD, 0xDF, 0xEF, 0x31, 0x6F, 0x94, 0x2C, 0xAA, 0x85, 0x14, 0x14, 0xEE, 0x94, 0x9D, 0x5E, 0x93, 0xED, 0x7D, 0xA1, 0xBA, 0x1F, 0xC4, 0xC7, 0x81, 0xDD, 0x77, 0x10, 0x6D, 0xAF, 0x8C, 0x56, 0xA3, 0x61, 0xF4, 0x68, 0xCD, 0x1B, 0xAB, 0x47, 0x81, 0xDF, 0x73, 0x70, 0x37, 0x13, 0x3C, 0x1A, 0xA0, 0xFC, 0x11, 0xD2, 0x21, 0x4F, 0x5A, 0xF6, 0xAE, 0xDA, 0x63, 0xC1, 0x12, 0x59, 0x32, 0x5E, 0x16, 0x51, 0xD5, 0xE4, 0x7B, 0xB2, 0x7D, 0x9E, 0x8C, 0x17, 0xC4, 0x44, 0x82, 0xAD, 0x05, 0x04, 0x6F, 0x56, 0x0F, 0x7F, 0x17, 0x18, 0xE2, 0x02, 0x0D, 0x81, 0x45, 0x6F, 0x81, 0xEB, 0x3C, 0xB8, 0x6A, 0x5B, 0xE9, 0x38, 0x94, 0x3F, 0x40, 0x5A, 0x8E, 0x97, 0x35, 0x33, 0x64, 0xB9, 0xD6, 0xA7, 0xCC, 0xF6, 0xF7, 0xF3, 0xF3, 0x77, 0xC9, 0xC4, 0x4E, 0x55, 0xF3, 0xE3, 0x2E, 0xC9, 0xA0, 0x14, 0xB0, 0xBC, 0x02, 0x01, 0xD3, 0xD5, 0xA3, 0x69, 0x1A, 0xF4, 0x49, 0x03, 0xFB, 0xD9, 0x30, 0x67, 0x3F, 0xD8, 0xCD, 0x80, 0xC3, 0x7B, 0xC0, 0xBE, 0x02, 0xE5, 0x5B, 0xC8, 0x9A, 0x0D, 0x24, 0xC8, 0xB2, 0xFB, 0xBF, 0x9F, 0x9F, 0x35, 0x4D, 0x76, 0xFE, 0xB7, 0x8C, 0xA7, 0xAA, 0xA1, 0xB3, 0xA5, 0xCF, 0x55, 0xA8, 0xBF, 0x09, 0xDC, 0x16, 0x82, 0xEF, 0x14, 0xDD, 0x79, 0xBB, 0x4F, 0x82, 0xFA, 0xC7, 0xA0, 0xF4, 0x5B, 0xA8, 0xB3, 0x03, 0x0E, 0x1C, 0xAC, 0xF4, 0x3C, 0xFC, 0xB0, 0x11, 0x6A, 0x74, 0x53, 0xEE, 0x1F, 0xDD, 0x6F, 0xFB, 0x0A, 0xBA, 0xBF, 0x2F, 0xBB, 0x7E, 0x28, 0xDB, 0xCD, 0xAB, 0x9A, 0x1F, 0xFD, 0x8D, 0x0C, 0x28, 0x92, 0xAE, 0x26, 0xEB, 0x31, 0xB0, 0xDB, 0x05, 0xBE, 0x25, 0x60, 0x59, 0x06, 0xC9, 0x11, 0x50, 0xE3, 0xC8, 0xFF, 0xAD, 0xBD, 0xC5, 0x5F, 0x5E, 0x49, 0x96, 0x7F, 0xD6, 0xA3, 0xE7, 0x45, 0x99, 0x72, 0x46, 0x76, 0xF8, 0x57, 0xD5, 0xFC, 0x47, 0x96, 0xCA, 0x56, 0x35, 0xA5, 0xDB, 0x15, 0x69, 0xBD, 0x09, 0x6A, 0xAC, 0xD5, 0xD7, 0x80, 0xF0, 0x4F, 0x00, 0x4E, 0x42, 0xC7, 0x0E, 0xE8, 0x11, 0x36, 0x47, 0x2E, 0x88, 0x94, 0xC7, 0x2A, 0xE4, 0x83, 0xF0, 0x3F, 0xEE, 0x91, 0xD6, 0x59, 0x76, 0x3C, 0x2C, 0xE3, 0xA9, 0x6A, 0xF0, 0x3B, 0xB2, 0xD1, 0x2E, 0x69, 0x13, 0xCE, 0x6F, 0x0E, 0xF7, 0x46, 0xB2, 0x75, 0x96, 0x1C, 0x74, 0x4E, 0x96, 0x26, 0xC9, 0x67, 0x56, 0xC8, 0xAF, 0x76, 0xFE, 0x71, 0x8F, 0x84, 0x0F, 0xFF, 0x7C, 0x1F, 0xB8, 0x7D, 0x2E, 0x2D, 0xD3, 0x6B, 0x5C, 0x47, 0x4D, 0x06, 0x4A, 0xCB, 0x5E, 0xB2, 0xE6, 0x8E, 0x26, 0xF5, 0x8D, 0xD5, 0x53, 0x22, 0x57, 0x1A, 0xA1, 0x7B, 0x03, 0x59, 0x24, 0xD8, 0xF5, 0xBD, 0xBC, 0x7C, 0xF9, 0xB7, 0x3D, 0x92, 0x2C, 0x7E, 0x3F, 0x3F, 0xBC, 0x91, 0x74, 0xDD, 0x62, 0xB1, 0x1B, 0xFD, 0x49, 0xE0, 0x36, 0x40, 0xBA, 0x8E, 0x92, 0x2E, 0x0B, 0x64, 0xFD, 0x8F, 0x1B, 0x2D, 0x37, 0xD6, 0xDB, 0x17, 0x56, 0xDB, 0x58, 0x67, 0x78, 0xE6, 0x00, 0x63, 0x8D, 0xD7, 0xD4, 0xA3, 0x5A, 0xDC, 0xE2, 0xAC, 0x2A, 0xE7, 0x67, 0xEF, 0x2F, 0x7A, 0xFC, 0x26, 0x3F, 0xE2, 0x67, 0x59, 0xB3, 0x49, 0xA3, 0x5C, 0x23, 0xB8, 0xF3, 0xF7, 0x6C, 0x7A, 0x4F, 0xDA, 0xBB, 0x86, 0xB8, 0x62, 0x6C, 0x94, 0xE1, 0x66, 0xAC, 0xBF, 0x77, 0xCA, 0x7D, 0x63, 0xBD, 0x26, 0xB3, 0xD5, 0xF3, 0xB8, 0x7A, 0xD4, 0xBD, 0x50, 0xD1, 0xDF, 0xC8, 0xFA, 0x5F, 0xF6, 0x88, 0xF6, 0x90, 0x16, 0x9B, 0x7F, 0xBD, 0xBE, 0x87, 0xA7, 0xF4, 0x9E, 0x2B, 0x7D, 0x57, 0x4B, 0xBF, 0x7C, 0xE4, 0x14, 0x64, 0x4D, 0xE9, 0xD3, 0xAA, 0xEE, 0x41, 0x63, 0xC3, 0xEB, 0x3D, 0x8B, 0x8D, 0xCE, 0x76, 0x03, 0x8F, 0x18, 0x6D, 0xAF, 0x2F, 0xB8, 0x66, 0x74, 0x6E, 0xA9, 0x1E, 0x0E, 0x7D, 0x2A, 0xA6, 0x19, 0xEB, 0x95, 0x9B, 0x1E, 0xB1, 0x2B, 0x50, 0xFE, 0x81, 0xFF, 0xCD, 0x1F, 0x20, 0x7D, 0xDE, 0x93, 0x81, 0x5D, 0x65, 0x8B, 0x99, 0xB2, 0xD5, 0x26, 0x19, 0x74, 0x51, 0x06, 0xC7, 0x20, 0x9B, 0xC9, 0xA0, 0xB3, 0x32, 0xD0, 0x22, 0xFB, 0x73, 0xA3, 0xAF, 0x57, 0x5F, 0x30, 0x6E, 0x3B, 0x7C, 0xCD, 0xE8, 0xBE, 0x51, 0x3D, 0x1A, 0x9B, 0x7C, 0xC0, 0xF1, 0x96, 0xB1, 0x7A, 0x7D, 0xE5, 0x83, 0xD7, 0x28, 0x19, 0xB0, 0x5D, 0xB6, 0xB2, 0x90, 0xA1, 0x3D, 0x64, 0xC4, 0x46, 0x19, 0x75, 0x4B, 0xC6, 0xE4, 0xC9, 0xC4, 0xC5, 0x32, 0xA9, 0x8E, 0x4C, 0xFC, 0x51, 0x46, 0x38, 0x27, 0x27, 0x1A, 0x83, 0x77, 0xAA, 0x47, 0xC8, 0x4A, 0xE5, 0x37, 0x77, 0x95, 0xCD, 0x2F, 0xA8, 0x87, 0xD7, 0x14, 0xE9, 0xB3, 0x1E, 0x00, 0x9A, 0x97, 0xCA, 0x90, 0x83, 0x32, 0xCA, 0x49, 0x76, 0x7A, 0x5F, 0xA6, 0xEC, 0x92, 0x19, 0x6D, 0x65, 0xD6, 0x0D, 0xD9, 0x7D, 0xBE, 0x1C, 0xFE, 0x8E, 0x1C, 0x11, 0x21, 0x87, 0xDF, 0x94, 0x85, 0x76, 0x6B, 0xED, 0x30, 0xDE, 0xD4, 0x3C, 0x32, 0xAD, 0xA5, 0x72, 0x73, 0x93, 0x65, 0xB0, 0xB5, 0x6C, 0xA9, 0x7C, 0xC2, 0xF3, 0x65, 0xA7, 0x5C, 0x99, 0x6E, 0x21, 0x47, 0x85, 0xC8, 0x71, 0xFB, 0x64, 0x7E, 0x9E, 0x2C, 0x1D, 0x29, 0xA7, 0x9F, 0xFB, 0xAB, 0x79, 0xE8, 0xBF, 0xF8, 0xAC, 0x67, 0x28, 0xB1, 0x02, 0x00, 0x00, 0x60, 0xDF, 0xB6, 0xCD, 0xDA, 0xB6, 0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0x36, 0x96, 0xDA, 0xB6, 0x6D, 0xDB, 0xB6, 0x6D, 0x77, 0xBE, 0xFD, 0x65, 0x4F, 0xC2, 0x0F, 0xFA, 0xDA, 0xFA, 0xBF, 0x48, 0x03, 0xD4, 0x04, 0x86, 0x03, 0x1B, 0x81, 0xFB, 0xA0, 0x04, 0xE6, 0x03, 0xDB, 0x80, 0x33, 0xC1, 0xC3, 0xE0, 0x47, 0x28, 0x31, 0x54, 0x01, 0xEA, 0x07, 0xAD, 0x80, 0xAE, 0xC1, 0x24, 0x9C, 0x15, 0x6E, 0x0C, 0x4F, 0x84, 0x77, 0xC3, 0x2F, 0x10, 0x07, 0x29, 0x81, 0x74, 0x43, 0x16, 0x20, 0xE7, 0x50, 0x10, 0x4D, 0x8B, 0xD6, 0x46, 0x47, 0xA2, 0x9B, 0xD1, 0x87, 0x98, 0x82, 0x15, 0xC0, 0xDA, 0x61, 0x73, 0xB0, 0x63, 0xD8, 0x17, 0x3C, 0x19, 0x5E, 0x05, 0x1F, 0x88, 0xAF, 0xC6, 0x6F, 0x12, 0x2C, 0x91, 0x93, 0x68, 0x4E, 0x4C, 0x25, 0xF6, 0x13, 0x6F, 0xC9, 0x90, 0x2C, 0x4B, 0xF6, 0x26, 0x97, 0x92, 0x97, 0x29, 0x9C, 0xCA, 0x4C, 0x35, 0xA4, 0xC6, 0x53, 0x3B, 0xA9, 0xE7, 0xB4, 0x4D, 0x17, 0xA7, 0xBB, 0xD2, 0xF3, 0xE9, 0xB3, 0x0C, 0xC8, 0xA4, 0x65, 0x6A, 0x33, 0x23, 0x99, 0xCD, 0xCC, 0x43, 0x56, 0x65, 0x0B, 0xB2, 0xED, 0xD9, 0xB9, 0xEC, 0x71, 0xF6, 0x2B, 0x97, 0x9C, 0xAB, 0xC6, 0x0D, 0xE1, 0xD6, 0x71, 0x77, 0x78, 0x81, 0xCF, 0xC3, 0xB7, 0xE2, 0x67, 0xF0, 0x87, 0xF8, 0x8F, 0x42, 0x62, 0xA1, 0xA2, 0xD0, 0x5F, 0x58, 0x29, 0x5C, 0x17, 0x19, 0x31, 0x87, 0xD8, 0x4C, 0x9C, 0x22, 0xEE, 0x13, 0xDF, 0x48, 0xA1, 0x54, 0x56, 0xEA, 0x2D, 0x2D, 0x95, 0x2E, 0xCB, 0x84, 0x9C, 0x45, 0x6E, 0x24, 0x4F, 0x90, 0x77, 0xC9, 0x2F, 0x15, 0x57, 0x29, 0xA9, 0x74, 0x57, 0x16, 0x29, 0x17, 0x54, 0x44, 0xCD, 0xA0, 0xD6, 0x57, 0xC7, 0xAA, 0xDB, 0xD5, 0xA7, 0x9A, 0xA5, 0x15, 0xD3, 0xBA, 0x68, 0xF3, 0xB5, 0xB3, 0x3A, 0xA2, 0xE7, 0xD7, 0xFB, 0xE9, 0x3B, 0xF4, 0xEF, 0x46, 0x4E, 0xA3, 0xBB, 0xB1, 0xC9, 0xF8, 0x60, 0x66, 0x32, 0x3B, 0x9A, 0xAB, 0xCD, 0x57, 0x56, 0x1A, 0xAB, 0xB5, 0xB5, 0xD4, 0x7A, 0x62, 0x27, 0xB3, 0x9B, 0xDA, 0xF3, 0xED, 0x7B, 0x4E, 0xE4, 0xD4, 0x77, 0xE6, 0x3A, 0x37, 0x5C, 0xC7, 0xAD, 0xE9, 0x4E, 0x77, 0x2F, 0x79, 0x9A, 0x57, 0xD9, 0x9B, 0xE8, 0x9D, 0xF1, 0x45, 0xBF, 0xAC, 0x3F, 0xC6, 0x3F, 0x1E, 0xD0, 0x41, 0x89, 0x60, 0x78, 0x70, 0x30, 0xC4, 0xC2, 0xC2, 0xE1, 0xA0, 0x70, 0x4F, 0x04, 0x46, 0xF9, 0xA2, 0xBE, 0xD1, 0x8E, 0xE8, 0x5B, 0x9C, 0x33, 0xEE, 0x11, 0x6F, 0x8E, 0x7F, 0xB1, 0x69, 0x0E, 0xC0, 0x61, 0x84, 0x61, 0xBB, 0x8D, 0xDD, 0x26, 0x69, 0xEC, 0x34, 0xB6, 0x9D, 0xC6, 0xB6, 0x6D, 0xDB, 0x36, 0x1B, 0xDB, 0x6C, 0xDC, 0xD8, 0xB6, 0xED, 0xA4, 0xB1, 0x6D, 0xDB, 0x77, 0xE7, 0xFA, 0xC7, 0xB7, 0xA3, 0x1D, 0xFB, 0x9C, 0xE7, 0xCC, 0xFB, 0x4C, 0xC2, 0x4E, 0xE2, 0x4A, 0xD2, 0x48, 0x72, 0x4F, 0xCA, 0x4C, 0xEA, 0x48, 0x5A, 0x4B, 0x7A, 0x4D, 0x46, 0x4F, 0x66, 0x4B, 0x56, 0x49, 0x76, 0x4E, 0x4E, 0x4D, 0x6E, 0x49, 0x5E, 0x4A, 0x7E, 0x4C, 0x41, 0x41, 0x61, 0x46, 0xF1, 0x97, 0xE2, 0x80, 0x92, 0x84, 0xD2, 0x98, 0xB2, 0x80, 0x72, 0x97, 0x8A, 0x88, 0xCA, 0x80, 0x2A, 0x97, 0x6A, 0x9B, 0x9A, 0x80, 0x5A, 0x97, 0xFA, 0x0F, 0xF5, 0x06, 0x0D, 0x1E, 0x8D, 0x36, 0x4D, 0x16, 0xCD, 0x1A, 0x2D, 0x0E, 0xAD, 0x16, 0x6D, 0x06, 0xED, 0x2A, 0x1D, 0x16, 0x9D, 0x06, 0x5D, 0x3A, 0xDD, 0x32, 0x3D, 0x26, 0xBD, 0x3A, 0x7D, 0x1A, 0xFD, 0x12, 0x03, 0x06, 0x83, 0x1A, 0x43, 0x2A, 0xC3, 0x12, 0x23, 0x3A, 0xA3, 0x2A, 0x63, 0x0A, 0xE3, 0x22, 0x13, 0x3A, 0x93, 0x2A, 0x53, 0x0A, 0xD3, 0x22, 0x33, 0x3A, 0xB3, 0x2A, 0x73, 0x0A, 0xF3, 0x12, 0x0B, 0x06, 0x8B, 0x1A, 0x4B, 0x2A, 0xCB, 0x12, 0x2B, 0x26, 0xAB, 0x3A, 0x6B, 0x1A, 0xEB, 0x32, 0x1B, 0x16, 0x9B, 0x06, 0x5B, 0x26, 0xDB, 0x2E, 0x3B, 0x25, 0xBB, 0x3D, 0x7B, 0x33, 0xFB, 0x27, 0x87, 0x08, 0x47, 0x14, 0xC7, 0x3C, 0x27, 0x36, 0xA7, 0x01, 0x67, 0x09, 0xE7, 0x15, 0x17, 0x3B, 0x97, 0x2F, 0xD7, 0x20, 0xF7, 0x37, 0x6E, 0x65, 0xEE, 0x4C, 0xEE, 0xBD, 0x5F, 0x54, 0xBF, 0x1C, 0x7F, 0xB5, 0xF1, 0x80, 0xF2, 0x48, 0xF0, 0xC4, 0xF1, 0x2C, 0xF3, 0x12, 0xF2, 0x9A, 0xF3, 0x56, 0xF3, 0x3E, 0xF1, 0xF1, 0xF1, 0x85, 0xF2, 0x4D, 0xF3, 0x63, 0xF0, 0xEB, 0xF1, 0x17, 0xF3, 0x5F, 0x09, 0x70, 0x08, 0xF8, 0x0B, 0x8C, 0x08, 0x22, 0x09, 0x6A, 0x08, 0xE6, 0x09, 0x9E, 0x08, 0x31, 0x09, 0x79, 0x0A, 0xF5, 0x0B, 0xC3, 0x0B, 0x2B, 0x0B, 0x67, 0x0B, 0x1F, 0x88, 0xD0, 0x89, 0xB8, 0x89, 0x74, 0x8B, 0xC2, 0x88, 0x2A, 0x88, 0x66, 0x88, 0xEE, 0x89, 0xD1, 0x88, 0xB9, 0x88, 0x75, 0x89, 0x43, 0x8B, 0xCB, 0x8B, 0xA7, 0x8B, 0xEF, 0x49, 0xD0, 0x48, 0xB8, 0x48, 0x74, 0x49, 0xC2, 0x48, 0x2A, 0x48, 0x66, 0x4A, 0xEE, 0x4B, 0xD1, 0x4A, 0xB9, 0x49, 0xF5, 0x4A, 0xC3, 0x49, 0x2B, 0x4B, 0x67, 0x4B, 0x1F, 0xC9, 0x30, 0xCA, 0x78, 0xC9, 0x0C, 0xCA, 0x7E, 0x97, 0x55, 0x97, 0xCD, 0x97, 0x3D, 0x97, 0x63, 0x93, 0xF3, 0x97, 0x1B, 0x93, 0x47, 0x93, 0xD7, 0x93, 0x2F, 0x95, 0xBF, 0x53, 0xE0, 0x55, 0x08, 0x53, 0x98, 0x53, 0xC4, 0x53, 0x34, 0x53, 0xAC, 0x53, 0x7C, 0x57, 0x12, 0x53, 0x8A, 0x57, 0x5A, 0x57, 0x26, 0x53, 0x76, 0x50, 0xEE, 0x50, 0x81, 0x52, 0x51, 0x50, 0xC9, 0x52, 0x39, 0x54, 0x65, 0x54, 0xF5, 0x52, 0x1D, 0x52, 0x43, 0x56, 0xD3, 0x52, 0xFB, 0xAB, 0x76, 0xA3, 0xCE, 0xAD, 0x1E, 0xA2, 0x3E, 0xAB, 0x81, 0xA3, 0x61, 0xAA, 0x51, 0xAB, 0xF1, 0xA6, 0x29, 0xAA, 0x19, 0xAF, 0xB9, 0xA6, 0x45, 0xA2, 0x65, 0xA6, 0x55, 0xAE, 0x75, 0xA5, 0xCD, 0xAC, 0xED, 0xA6, 0xDD, 0xAE, 0xFD, 0xA5, 0x23, 0xA4, 0x13, 0xAA, 0x33, 0xAE, 0x8B, 0xA8, 0xAB, 0xA4, 0x9B, 0xAA, 0xBB, 0xA6, 0x47, 0xA0, 0x67, 0xA4, 0x57, 0xAC, 0x77, 0xA6, 0x4F, 0xAF, 0xEF, 0xA4, 0xDF, 0xAC, 0xFF, 0x66, 0xC0, 0x67, 0x10, 0x6C, 0x30, 0x62, 0x88, 0x60, 0x28, 0x6F, 0x98, 0x64, 0xB8, 0x6C, 0x84, 0x6B, 0x64, 0x60, 0x54, 0x64, 0x74, 0x62, 0x4C, 0x6B, 0xEC, 0x60, 0xDC, 0x64, 0xFC, 0x6A, 0xC2, 0x6B, 0x12, 0x68, 0x32, 0x6C, 0x0A, 0x6F, 0x2A, 0x67, 0x9A, 0x68, 0xBA, 0x6C, 0x86, 0x6B, 0xA6, 0x6F, 0x56, 0x64, 0x76, 0x62, 0x4E, 0x6B, 0xEE, 0x60, 0xDE, 0x64, 0xFE, 0x6A, 0xC1, 0x6B, 0x11, 0x68, 0x31, 0x6C, 0x09, 0x6F, 0x29, 0x67, 0x99, 0x68, 0xB9, 0x6C, 0x85, 0x6B, 0xA5, 0x6F, 0x55, 0x68, 0x75, 0x6C, 0x4D, 0x6B, 0xED, 0x60, 0xDD, 0x68, 0xFD, 0x62, 0xC3, 0x6B, 0x13, 0x68, 0x33, 0x64, 0x0B, 0x67, 0x2B, 0x67, 0x9B, 0x68, 0xBB, 0x64, 0x87, 0x63, 0xA7, 0x67, 0x57, 0x68, 0x77, 0x6C, 0x4F, 0x63, 0x6F, 0x6F, 0xDF, 0x68, 0xFF, 0xE2, 0xC0, 0xE3, 0x10, 0xE0, 0x30, 0xE8, 0x08, 0xE7, 0x28, 0xEB, 0x98, 0xE0, 0xB8, 0xE8, 0x84, 0xE3, 0xA4, 0xE7, 0x54, 0xE0, 0x74, 0xE4, 0x4C, 0xE3, 0x6C, 0xEF, 0xDC, 0xE0, 0xFC, 0xE2, 0xC2, 0xE3, 0x12, 0xE0, 0x32, 0xE8, 0x0A, 0xE7, 0x2A, 0xEB, 0x9A, 0xE0, 0xBA, 0xE4, 0x86, 0xE3, 0xA6, 0xE7, 0x56, 0xE0, 0x76, 0xEC, 0x4E, 0xE3, 0x6E, 0xEF, 0xDE, 0xE8, 0xFE, 0xE2, 0xC1, 0xE3, 0x11, 0xE0, 0x31, 0xE4, 0x09, 0xE7, 0x29, 0xEB, 0x99, 0xE8, 0xB9, 0xE4, 0x85, 0xE3, 0xA5, 0xEF, 0x55, 0xE8, 0x75, 0xEC, 0x4D, 0xEB, 0xED, 0xE0, 0xDD, 0xE8, 0xFD, 0xEA, 0xC3, 0xE3, 0x13, 0xE0, 0x33, 0xE0, 0x0B, 0xED, 0x2B, 0xE5, 0x1B, 0xE3, 0x3B, 0xEB, 0x87, 0xEA, 0xA7, 0xEE, 0x97, 0xE9, 0xB7, 0xE9, 0x4F, 0xE4, 0x6F, 0xE2, 0x5F, 0xE2, 0x7F, 0x16, 0x40, 0x17, 0xE0, 0x18, 0xD0, 0x18, 0xF0, 0x1C, 0xC8, 0x1D, 0xE8, 0x1B, 0xD8, 0x1B, 0x04, 0x11, 0x24, 0x16, 0x14, 0x11, 0x34, 0x19, 0x8C, 0x18, 0xAC, 0x18, 0x9C, 0x1C, 0xBC, 0xFC, 0x1B, 0xE7, 0xB7, 0xEE, 0xEF, 0xDC, 0xDF, 0x7B, 0x21, 0x64, 0x21, 0xE6, 0x21, 0xE5, 0x21, 0x97, 0xA1, 0x0C, 0xA1, 0x4E, 0xA1, 0x8D, 0xA1, 0xCF, 0x61, 0x5C, 0x61, 0x3E, 0x61, 0xDD, 0xE1, 0x60, 0xE1, 0xC2, 0xE1, 0x21, 0xE1, 0xA3, 0x11, 0xF0, 0x11, 0x32, 0x11, 0xB1, 0x11, 0x73, 0x91, 0xA8, 0x91, 0xAA, 0x91, 0x69, 0x91, 0xAB, 0x51, 0xB8, 0x51, 0x7A, 0x51, 0x79, 0x51, 0x7B, 0xD1, 0xA4, 0xD1, 0x66, 0xD1, 0xA5, 0xD1, 0x67, 0x31, 0xB4, 0x31, 0xB6, 0x31, 0x35, 0x31, 0xB7, 0xB1, 0x2C, 0xB1, 0xAE, 0xB1, 0x2D, 0xB1, 0x2F, 0x71, 0xDC, 0x71, 0x3E, 0x71, 0x5D, 0xF1, 0x20, 0xF1, 0x82, 0xF1, 0x41, 0xF1, 0x83, 0x09, 0x50, 0x09, 0xE2, 0x09, 0xE1, 0x09, 0xE3, 0x89, 0x08, 0x89, 0x32, 0x89, 0xB1, 0x89, 0x33, 0x49, 0xC8, 0x49, 0x4A, 0x49, 0x49, 0x49, 0x0B, 0xC9, 0xE8, 0xC9, 0xEA, 0xC9, 0xE9, 0xC9, 0xAB, 0x29, 0x38, 0x29, 0xDA, 0x29, 0xD9, 0x29, 0x9B, 0xA9, 0x04, 0xA9, 0xFA, 0xA9, 0x79, 0xA9, 0xBB, 0x69, 0x44, 0x69, 0x46, 0x69, 0x85, 0x69, 0x07, 0xE9, 0x64, 0xE9, 0xA6, 0xE9, 0xC5, 0xE9, 0xC7, 0x19, 0x14, 0x19, 0x16, 0x19, 0xA5, 0x19, 0xA7, 0x99, 0x54, 0x99, 0x56, 0x99, 0xE5, 0x99, 0xE7, 0x59, 0x34, 0x59, 0x36, 0x59, 0x95, 0x59, 0x17, 0xD9, 0x74, 0xD9, 0xB6, 0xD9, 0x55, 0xD9, 0x57, 0x7F, 0x98, 0xFE, 0xB8, 0xFF, 0xE9, 0xCC, 0x01, 0xCF, 0x91, 0xC8, 0x89, 0xC9, 0x99, 0xCF, 0xC5, 0xCA, 0xD5, 0xCD, 0x2D, 0xCC, 0x3D, 0xC9, 0xA3, 0xCB, 0x73, 0xCE, 0x6B, 0xCD, 0xFB, 0xCC, 0x17, 0xCE, 0x0F, 0xCF, 0x9F, 0x2A, 0x40, 0x29, 0x50, 0x2F, 0xF8, 0x53, 0xB0, 0x57, 0x48, 0x51, 0x68, 0x53, 0x58, 0x57, 0xF8, 0x54, 0xF4, 0xAB, 0x28, 0xA0, 0x68, 0xE8, 0x2F, 0xFC, 0x5F, 0xF9, 0xBF, 0xC9, 0x7F, 0x57, 0x8B, 0xF1, 0x8B, 0x8D, 0x8A, 0x4B, 0x8A, 0x2F, 0x4A, 0x98, 0x4A, 0x5C, 0x4B, 0xDA, 0x4B, 0x41, 0x4A, 0x85, 0x4B, 0xC3, 0x4B, 0xA7, 0xCA, 0x7E, 0x94, 0xA9, 0x95, 0x65, 0x96, 0x6D, 0x97, 0x93, 0x94, 0x5B, 0x94, 0x57, 0x96, 0xDF, 0x56, 0xB0, 0x55, 0x78, 0x55, 0x74, 0x57, 0x42, 0x54, 0x8A, 0x57, 0x46, 0x57, 0xCE, 0x56, 0xA1, 0x57, 0x69, 0x56, 0xE5, 0x54, 0xED, 0x55, 0x53, 0x54, 0x5B, 0x57, 0xD7, 0x56, 0x3F, 0xD4, 0x70, 0xD5, 0xF8, 0xD6, 0xF4, 0xD7, 0x42, 0xD7, 0x4A, 0xD7, 0xC6, 0xD5, 0x2E, 0xD4, 0x61, 0xD5, 0xE9, 0xD6, 0xE5, 0xD7, 0x1D, 0xD5, 0xD3, 0xD4, 0xDB, 0xD7, 0x37, 0xD6, 0xBF, 0x34, 0xF0, 0x36, 0x04, 0x36, 0x0C, 0x37, 0xC2, 0x37, 0xCA, 0x37, 0x26, 0x35, 0xAE, 0x34, 0xE1, 0x37, 0x19, 0x36, 0x15, 0x37, 0x9D, 0x35, 0x33, 0x34, 0xBB, 0x34, 0xB7, 0x36, 0x7F, 0xB6, 0x08, 0xB6, 0x84, 0xB6, 0x4C, 0xB4, 0x22, 0xB5, 0xAA, 0xB4, 0x66, 0xB4, 0x6E, 0xB5, 0x11, 0xB7, 0x99, 0xB7, 0x55, 0xB6, 0xDD, 0xB4, 0xB3, 0xB5, 0x7B, 0xB5, 0xF7, 0x74, 0x40, 0x76, 0x48, 0x74, 0xC4, 0x74, 0xCC, 0x77, 0x62, 0x76, 0xEA, 0x74, 0xE6, 0x75, 0x1E, 0x76, 0x51, 0x77, 0xD9, 0x77, 0x35, 0x76, 0xBD, 0x76, 0xF3, 0x75, 0x07, 0x77, 0x8F, 0xF6, 0x7C, 0xEB, 0x51, 0xEA, 0xC9, 0xE8, 0xD9, 0xEB, 0xA5, 0xE9, 0x75, 0xE9, 0xED, 0xEA, 0x83, 0xEA, 0x93, 0xEB, 0x4B, 0xEB, 0xDB, 0xE9, 0xA7, 0xEA, 0x77, 0xEA, 0xEF, 0x18, 0x80, 0x1C, 0x90, 0x1D, 0x48, 0x1D, 0xD8, 0x1E, 0xA4, 0x1C, 0x74, 0x1C, 0x6C, 0x1F, 0x82, 0x18, 0x92, 0x19, 0x4A, 0x19, 0xDA, 0x1A, 0xA6, 0x18, 0x76, 0x18, 0x6E, 0x1B, 0x01, 0x1F, 0x91, 0x19, 0x49, 0x19, 0xD9, 0x1A, 0xA5, 0x18, 0x75, 0x18, 0x6D, 0x1B, 0x83, 0x18, 0x93, 0x19, 0x4B, 0x19, 0xDB, 0x1A, 0xA7, 0x18, 0x77, 0x1C, 0x6F, 0x9F, 0x80, 0x98, 0x90, 0x99, 0x48, 0x9D, 0xD8, 0x9E, 0xA4, 0x9C, 0x74, 0x9C, 0xEC, 0x98, 0x82, 0x9C, 0x92, 0x9D, 0x4A, 0x9D, 0xDA, 0x99, 0xA6, 0x9A, 0x76, 0x9A, 0xEE, 0x98, 0x81, 0x9A, 0x91, 0x9B, 0x49, 0x9B, 0xD9, 0x99, 0xA5, 0x9A, 0x75, 0x9E, 0xED, 0x9C, 0x83, 0x9A, 0x93, 0x9B, 0x4B, 0x9B, 0xDB, 0x99, 0xA7, 0x9E, 0x77, 0x9E, 0xEF, 0xFC, 0x07, 0xF5, 0x4F, 0xEE, 0x5F, 0xDA, 0xBF, 0x9D, 0x05, 0xEA, 0x05, 0xE7, 0x85, 0xCE, 0x45, 0xA8, 0x45, 0xB9, 0xC5, 0xB4, 0xC5, 0x9D, 0x25, 0xAA, 0x25, 0xA7, 0xA5, 0x8E, 0x65, 0xA8, 0x65, 0xB9, 0xE5, 0xB4, 0xE5, 0x9D, 0x15, 0xAA, 0x15, 0xA7, 0x95, 0x8E, 0x55, 0xC8, 0x55, 0xD9, 0xD5, 0xB4, 0xD5, 0x9D, 0x35, 0xAA, 0x35, 0xA7, 0xB5, 0x8E, 0x75, 0xC8, 0x75, 0xD9, 0xF5, 0xD4, 0xF5, 0xED, 0x0D, 0xAA, 0x0D, 0xA7, 0x8D, 0x8E, 0x4D, 0xC8, 0x4D, 0xD9, 0xCD, 0xD4, 0xCD, 0xED, 0x2D, 0xCA, 0x2D, 0xC7, 0xAD, 0xF6, 0x6D, 0xC8, 0x6D, 0xD9, 0xED, 0xD4, 0xED, 0xED, 0x1D, 0xCA, 0x1D, 0xC7, 0x9D, 0xF6, 0x5D, 0x88, 0x5D, 0x99, 0xDD, 0x94, 0xDD, 0xED, 0x3D, 0xCA, 0x3D, 0xC7, 0xBD, 0xF6, 0x7D, 0x88, 0x7D, 0x99, 0xFD, 0x94, 0xFD, 0xF5, 0x03, 0xCC, 0x03, 0xD9, 0x83, 0xE0, 0x83, 0xB6, 0x83, 0xAB, 0x43, 0xD2, 0x43, 0xAD, 0xC3, 0xF8, 0xC3, 0xE1, 0xC3, 0x8F, 0x23, 0xE6, 0x23, 0x8B, 0xA3, 0x9C, 0xA3, 0x85, 0x63, 0xF8, 0x63, 0x81, 0x63, 0xB7, 0xE3, 0xCA, 0xE3, 0xBD, 0x13, 0xCC, 0x13, 0xD9, 0x93, 0xE0, 0x93, 0xB6, 0x93, 0xEB, 0x53, 0xB2, 0x53, 0xED, 0xD3, 0xC4, 0xD3, 0xD1, 0xD3, 0xAF, 0x33, 0xD6, 0x33, 0xAB, 0xB3, 0xBC, 0xB3, 0xA5, 0xF3, 0x6F, 0xE7, 0x42, 0xE7, 0x1E, 0xE7, 0xD5, 0xE7, 0x07, 0x17, 0x38, 0x17, 0x0A, 0x17, 0xA1, 0x17, 0x5D, 0x17, 0xF7, 0x97, 0x54, 0x97, 0xFA, 0x97, 0x29, 0x97, 0x13, 0x57, 0x60, 0x57, 0x1C, 0x57, 0x76, 0x57, 0x45, 0x57, 0x6B, 0xD7, 0xC8, 0xD7, 0x62, 0xD7, 0x3E, 0xD7, 0xF5, 0xD7, 0xA7, 0x37, 0x84, 0x37, 0xAA, 0x37, 0x51, 0x37, 0x7D, 0x37, 0x2F, 0xB7, 0xF4, 0xB7, 0x26, 0xB7, 0x99, 0xB7, 0x73, 0x77, 0x30, 0x77, 0xBC, 0x77, 0xCE, 0x77, 0xE5, 0x77, 0x3B, 0xF7, 0x18, 0xF7, 0x32, 0xF7, 0xC1, 0xF7, 0x6D, 0xF7, 0xD7, 0x0F, 0x64, 0x0F, 0x3A, 0x0F, 0x89, 0x0F, 0xA3, 0x8F, 0x20, 0x8F, 0x6C, 0x8F, 0xD6, 0x8F, 0x05, 0x8F, 0x2B, 0x4F, 0x88, 0x4F, 0xA2, 0x4F, 0xDE, 0x4F, 0x75, 0x4F, 0x27, 0xCF, 0x04, 0xCF, 0xAA, 0xCF, 0x51, 0xCF, 0x7D, 0xCF, 0x2F, 0x2F, 0xF4, 0x2F, 0xA6, 0x2F, 0x59, 0x2F, 0x73, 0xAF, 0xB0, 0xAF, 0x7C, 0xAF, 0xAE, 0xAF, 0x15, 0xAF, 0x7B, 0x6F, 0x58, 0x6F, 0x72, 0x6F, 0x21, 0x6F, 0x1D, 0x6F, 0x77, 0xEF, 0x94, 0xEF, 0xFA, 0xEF, 0x29, 0xEF, 0x93, 0x1F, 0xE0, 0x1F, 0x5C, 0x1F, 0xF6, 0x1F, 0xC5, 0x1F, 0x1B, 0x9F, 0xA8, 0x9F, 0x92, 0x9F, 0x01, 0x9F, 0x2D, 0x9F, 0x97, 0x5F, 0xA4, 0x5F, 0x5A, 0x5F, 0x09, 0x5F, 0xFF, 0xAB, 0x20, 0xB2, 0x80, 0x98, 0x83, 0x64, 0x83, 0xCC, 0x82, 0x42, 0x82, 0x72, 0x82, 0xDA, 0x80, 0xE6, 0x83, 0x2E, 0x82, 0xC1, 0x81, 0xF1, 0x82, 0x39, 0x82, 0x15, 0x83, 0xAD, 0x81, 0x23, 0x82, 0x0B, 0x81, 0xBB, 0x83, 0x57, 0x80, 0x6F, 0x43, 0xA0, 0x41, 0x48, 0x40, 0xF8, 0x40, 0xD4, 0x42, 0x1C, 0x42, 0x62, 0x43, 0xCA, 0x42, 0x06, 0x41, 0x36, 0x43, 0x9E, 0x41, 0x11, 0x42, 0x29, 0x43, 0x85, 0x41, 0x75, 0x42, 0xDD, 0x40, 0x93, 0x41, 0x6B, 0x42, 0xC7, 0x40, 0xF7, 0x43, 0x3F, 0xC1, 0xD0, 0xC0, 0xE8, 0xC3, 0x24, 0xC1, 0x8C, 0xC2, 0x7C, 0xC0, 0x32, 0xC1, 0x9A, 0xC2, 0x66, 0xC2, 0x4E, 0xC3, 0x41, 0xC0, 0x71, 0xC0, 0x59, 0xC3, 0xE5, 0xC1, 0x2D, 0xC0, 0xC3, 0xC1, 0xF3, 0xC2, 0x3B, 0xC1, 0x17, 0xC3, 0xAF, 0x23, 0x20, 0x23, 0x88, 0x20, 0x78, 0x22, 0x54, 0x21, 0xEC, 0x7D, 0xC3, 0xF8, 0x26, 0xFD, 0xCD, 0xFF, 0x5B, 0xE3, 0xB7, 0xD3, 0xEF, 0xF8, 0xDF, 0x95, 0xBE, 0x87, 0x7E, 0xEF, 0xF8, 0x7E, 0x83, 0x48, 0x8A, 0xA8, 0x89, 0x18, 0x8B, 0xD8, 0x8F, 0xF8, 0x8C, 0x44, 0x83, 0x64, 0x80, 0x94, 0x82, 0x34, 0x86, 0xF4, 0x85, 0xCC, 0x82, 0x6C, 0x81, 0x9C, 0x8D, 0x3C, 0xF7, 0x03, 0xFA, 0x07, 0xF7, 0x0F, 0xFB, 0x1F, 0x45, 0x00, 0xE5, 0xBF, 0xA3, 0x08, 0xA1, 0xB8, 0xA3, 0x54, 0xA0, 0xEC, 0xA0, 0xA2, 0x03, 0x8C, 0xF7, 0x47, 0x6D, 0x40, 0x3D, 0x41, 0xC3, 0x47, 0x53, 0x42, 0x0B, 0x45, 0xEB, 0x40, 0xBB, 0x41, 0x27, 0x43, 0xD7, 0x42, 0x8F, 0x43, 0x1F, 0x40, 0x7F, 0xC1, 0xA0, 0xC3, 0x30, 0xC2, 0x48, 0xC3, 0x98, 0xC4, 0x04, 0xC3, 0x64, 0xC7, 0xB4, 0xC2, 0xCC, 0xC5, 0x5C, 0xC0, 0x82, 0xC3, 0xE2, 0xC3, 0x72, 0xC6, 0x2A, 0xC5, 0xDA, 0xC4, 0x46, 0xC1, 0x96, 0xC0, 0x0E, 0xC5, 0x1E, 0xC0, 0x01, 0xC3, 0xE1, 0xC7, 0xF1, 0xC5, 0x69, 0xC7, 0x79, 0xC1, 0x65, 0xC7, 0x75, 0xC1, 0xAD, 0xC3, 0xBD, 0xC6, 0xA3, 0xC3, 0xB3, 0xC6, 0x2B, 0xC3, 0x3B, 0xC6, 0x27, 0xC5, 0x37, 0xC2, 0xCF, 0xC3, 0xDF, 0x22, 0xC0, 0x23, 0xD0, 0x22, 0x48, 0x27, 0x58, 0x22, 0x44, 0x23, 0x54, 0x24, 0x8C, 0x23, 0x9C, 0xFA, 0x89, 0xF0, 0x53, 0xF2, 0x67, 0xD8, 0xCF, 0x21, 0x22, 0x48, 0x22, 0x21, 0xA2, 0x00, 0xA2, 0x6E, 0xA2, 0x0F, 0x80, 0xF2, 0x1E, 0xC4, 0xCD, 0xC4, 0x8F, 0x24, 0x2C, 0x24, 0x8E, 0x24, 0x35, 0x24, 0x97, 0xA4, 0xB4, 0xA4, 0x56, 0xA4, 0xA5, 0xA4, 0xC7, 0x64, 0x64, 0x64, 0xC6, 0x64, 0x05, 0x64, 0x3B, 0xE4, 0x04, 0xE4, 0xBA, 0xE4, 0x59, 0xE4, 0x6B, 0x14, 0x58, 0x14, 0x6A, 0x14, 0x29, 0x14, 0xFF, 0x28, 0x51, 0x28, 0x15, 0x28, 0xE3, 0x28, 0xA7, 0xA8, 0xBE, 0x51, 0x49, 0x51, 0x45, 0x50, 0x8D, 0x50, 0x43, 0x53, 0x8B, 0x52, 0x07, 0x53, 0xF7, 0xD3, 0x80, 0xD2, 0xF0, 0xD3, 0xF8, 0xD1, 0x74, 0xD2, 0xBC, 0xD3, 0x72, 0xD3, 0x7A, 0xD0, 0xB6, 0xD0, 0x3E, 0xD1, 0xB1, 0xD1, 0x39, 0xD3, 0xD5, 0xD3, 0xDD, 0xD2, 0x33, 0xD2, 0xDB, 0xD1, 0x57, 0xD1, 0x5F, 0x30, 0xD0, 0x30, 0x58, 0x31, 0x94, 0x31, 0x1C, 0x33, 0x92, 0x33, 0x9A, 0x32, 0x16, 0x31, 0xEE, 0x33, 0x11, 0x33, 0x19, 0x32, 0xE5, 0x31, 0x6D, 0x33, 0x13, 0x30, 0xEB, 0x32, 0x67, 0x33, 0xAF, 0xB3, 0xE0, 0xB0, 0x68, 0xB2, 0xA4, 0xB3, 0x2C, 0xB3, 0x62, 0xB0, 0xAA, 0xB2, 0x26, 0xB3, 0x2E, 0xB0, 0xA1, 0xB2, 0x29, 0xB1, 0x25, 0xB0, 0xCD, 0xB2, 0x23, 0xB3, 0xCB, 0xB3, 0xC7, 0xB2, 0x4F, 0x71, 0x7C, 0xE7, 0x90, 0x01, 0x48, 0x3F, 0xCE, 0x09, 0xCF, 0x29, 0xC9, 0x19, 0xCE, 0x39, 0xCC, 0x05, 0xC9, 0x25, 0xC4, 0x15, 0xC0, 0xD5, 0xCD, 0xF5, 0xCE, 0xCD, 0xC5, 0xED, 0xCE, 0xDD, 0xC4, 0x7D, 0xFF, 0x8B, 0xE9, 0x97, 0xFD, 0xAF, 0xAA, 0x5F, 0xE7, 0x3C, 0x54, 0x3C, 0xE6, 0x3C, 0x7F, 0x79, 0xF6, 0x79, 0x89, 0x78, 0x0D, 0x78, 0x73, 0x78, 0x37, 0xF8, 0x70, 0xF8, 0x34, 0xF8, 0x52, 0xF9, 0x16, 0xF8, 0x51, 0xF9, 0x15, 0xF9, 0xE3, 0xF8, 0xA7, 0x04, 0x10, 0x04, 0xA4, 0x04, 0xC2, 0x05, 0x86, 0x05, 0x21, 0x05, 0x85, 0x05, 0x03, 0x05, 0x7B, 0x04, 0xBF, 0x84, 0x78, 0x84, 0xBC, 0x84, 0xDA, 0x84, 0x9E, 0x85, 0xD9, 0x84, 0x5D, 0x84, 0xEB, 0x85, 0x6F, 0x45, 0x18, 0x44, 0xEC, 0x44, 0x2A, 0x45, 0xCE, 0x45, 0xA9, 0x44, 0x2D, 0x44, 0x8B, 0x45, 0x0F, 0xC5, 0x48, 0xC4, 0x8C, 0xC4, 0xF2, 0xC4, 0xB6, 0xC5, 0x09, 0xC4, 0x75, 0xC4, 0xB3, 0xC4, 0x57, 0x25, 0xB0, 0x24, 0xD4, 0x25, 0x52, 0x24, 0x16, 0x24, 0x51, 0x25, 0x15, 0x25, 0xE3, 0x25, 0x67, 0xA4, 0x10, 0xA5, 0x64, 0xA4, 0xA2, 0xA4, 0xC6, 0x01, 0xFE, 0x8B, 0x4B, 0x87, 0x4A, 0x0F, 0xC9, 0x40, 0xCA, 0x08, 0xCB, 0x04, 0xC9, 0xF4, 0xC9, 0x82, 0xCA, 0xF2, 0xC9, 0xFA, 0xCA, 0x76, 0xCA, 0xBE, 0xCB, 0x71, 0xCB, 0x79, 0xCA, 0xB5, 0xCA, 0x3D, 0xCB, 0x73, 0xC8, 0xBB, 0xC9, 0x37, 0xC9, 0x3F, 0x28, 0xB0, 0x28, 0x38, 0x29, 0xD4, 0x29, 0xDC, 0x28, 0x32, 0x2A, 0xDA, 0x2B, 0x56, 0x2B, 0x5E, 0x2A, 0xD1, 0x2A, 0xD9, 0x28, 0x55, 0x28, 0x9D, 0x29, 0x53, 0x29, 0x5B, 0x2A, 0x97, 0x2A, 0x1F, 0xAB, 0x50, 0xA8, 0x98, 0xA9, 0x14, 0x03, 0x2E, 0x40, 0xAA, 0x6A, 0xA2, 0x5A, 0xA8, 0xBA, 0xAF, 0x46, 0xAC, 0x66, 0xA4, 0x96, 0xAF, 0xB6, 0xAB, 0xFE, 0x53, 0xDD, 0x40, 0x3D, 0x57, 0x7D, 0x13, 0xF0, 0x01, 0x35, 0x8D, 0x44, 0x8D, 0x69, 0x4D, 0x04, 0x4D, 0x71, 0xCD, 0x60, 0xCD, 0x1E, 0xCD, 0x77, 0x2D, 0x0E, 0x2D, 0x67, 0xAD, 0x1A, 0xAD, 0x73, 0x6D, 0x0A, 0x6D, 0x63, 0xED, 0x5C, 0xED, 0x75, 0x1D, 0x4C, 0x1D, 0x65, 0x9D, 0x38, 0x9D, 0x09, 0x5D, 0x68, 0x5D, 0x21, 0x5D, 0x3F, 0xDD, 0x76, 0xDD, 0x47, 0x3D, 0x26, 0x3D, 0x5B, 0xBD, 0x52, 0xBD, 0x03, 0x7D, 0x42, 0x7D, 0x6D, 0xFD, 0x34, 0xFD, 0x79, 0x03, 0x44, 0x03, 0x49, 0x83, 0xDF, 0x06, 0xBD, 0x06, 0xEF, 0x86, 0x1C, 0x86, 0x4E, 0x86, 0x55, 0x86, 0xA7, 0x46, 0xA4, 0x46, 0xFA, 0x46, 0x59, 0x46, 0x4B, 0xC6, 0x3F, 0x8C, 0x65, 0x8C, 0xC3, 0x8C, 0x07, 0x8C, 0xBF, 0x4C, 0xB8, 0x4C, 0x5C, 0x4C, 0x6A, 0x4C, 0xCE, 0x4C, 0xC9, 0x4C, 0x0D, 0x4D, 0xB3, 0x01, 0x3F, 0x40, 0x31, 0x93, 0x35, 0x0B, 0x37, 0x1B, 0x30, 0xFB, 0x32, 0xE7, 0x34, 0x77, 0x36, 0xAF, 0x36, 0x3F, 0xB5, 0x20, 0xB5, 0xD0, 0xB7, 0xC8, 0xB4, 0x58, 0xB4, 0x44, 0xB2, 0x94, 0xB2, 0x0C, 0xB1, 0xEC, 0xB5, 0x7C, 0xB3, 0x62, 0xB3, 0x72, 0xB0, 0xAA, 0xB0, 0x3A, 0xB4, 0xFE, 0x69, 0xAD, 0x6D, 0x9D, 0x62, 0x3D, 0x6B, 0x03, 0x6F, 0x23, 0x6A, 0xE3, 0x6F, 0xD3, 0x6E, 0xF3, 0x60, 0xCB, 0x60, 0x6B, 0x69, 0x5B, 0x64, 0xBB, 0x65, 0x87, 0x6D, 0xA7, 0x6C, 0x17, 0x63, 0x37, 0x6A, 0x0F, 0x6E, 0xCF, 0x6B, 0xEF, 0x6E, 0x5F, 0x67, 0x7F, 0xE1, 0x40, 0xEE, 0x60, 0xE0, 0x90, 0xE9, 0xB0, 0xE8, 0x88, 0xE4, 0x28, 0xE9, 0x18, 0xEC, 0xD8, 0xE5, 0xF8, 0xEC, 0xC4, 0xEC, 0x64, 0xE3, 0x54, 0xEC, 0xB4, 0xE3, 0x8C, 0xE3, 0xAC, 0xE2, 0x1C, 0xEB, 0x3C, 0xEA, 0x02, 0x0E, 0x18, 0x83, 0x9B, 0x4B, 0xAD, 0xCB, 0xA9, 0x2B, 0xA9, 0xAB, 0x81, 0x6B, 0x9E, 0xEB, 0x8E, 0xDB, 0x4F, 0x37, 0x03, 0xB7, 0x5C, 0xB7, 0x6D, 0x77, 0x42, 0x77, 0x3D, 0xF7, 0x1C, 0xF7, 0x2D, 0x0F, 0x7C, 0x0F, 0x5D, 0x8F, 0x3F, 0x1E, 0x1B, 0x9E, 0x78, 0x9E, 0xDA, 0x9E, 0x59, 0x9E, 0x6B, 0x5E, 0xD8, 0x5E, 0x9A, 0x5E, 0xE9, 0x5E, 0xCB, 0xDE, 0x98, 0xDE, 0x6A, 0xDE, 0x29, 0xDE, 0x0B, 0x3E, 0x68, 0x3E, 0xCA, 0x3E, 0x89, 0x3E, 0x73, 0xBE, 0xC8, 0xBE, 0xF2, 0xBE, 0xB1, 0xBE, 0x53, 0x7E, 0xDF, 0xFC, 0xA4, 0xFD, 0x22, 0xFD, 0xC6, 0xFC, 0x61, 0xFD, 0xC5, 0xFD, 0x43, 0xFD, 0x87, 0x02, 0x20, 0x02, 0x84, 0x02, 0x02, 0x03, 0x7A, 0x03, 0xBE, 0x02, 0x79, 0x03, 0x7D, 0x02, 0xDB, 0x03, 0x5F, 0x83, 0x38, 0x83, 0xDC, 0x82, 0x9A, 0x82, 0xEE, 0x83, 0x99, 0x83, 0x1D, 0x82, 0xAB, 0x83, 0x2F, 0x7F, 0xD3, 0xFC, 0xB6, 0xFC, 0x5D, 0xFA, 0xFB, 0x28, 0x84, 0x34, 0xC4, 0x28, 0x24, 0x3F, 0x64, 0x3B, 0x14, 0x3F, 0x54, 0x3B, 0x34, 0x23, 0x74, 0x39, 0x0C, 0x3D, 0x4C, 0x39, 0x2C, 0x21, 0x6C, 0x3A, 0xFC, 0x5B, 0xB8, 0x54, 0x78, 0x78, 0xF8, 0x50, 0x04, 0x44, 0x84, 0x60, 0x84, 0x5F, 0x44, 0x67, 0xC4, 0x5B, 0x24, 0x47, 0xA4, 0x6B, 0x64, 0x7D, 0xE4, 0x75, 0x14, 0x5D, 0x94, 0x55, 0x54, 0x69, 0xD4, 0x61, 0x34, 0x71, 0xB4, 0x7E, 0x74, 0x76, 0xF4, 0x5A, 0x0C, 0x66, 0x8C, 0x4A, 0x4C, 0x42, 0xCC, 0x74, 0x2C, 0x42, 0xAC, 0x44, 0x6C, 0x48, 0x6C, 0x7F, 0x1C, 0x48, 0xDC, 0xAF, 0x38, 0x8F, 0xB8, 0xA6, 0xB8, 0xBB, 0x78, 0x86, 0x78, 0xEB, 0xF8, 0xD2, 0xF8, 0x83, 0x04, 0xA2, 0x04, 0xBD, 0x84, 0xCC, 0x84, 0xE5, 0x44, 0xD4, 0x44, 0x85, 0xC4, 0xE8, 0xC4, 0xD1, 0x24, 0xA8, 0x24, 0xC1, 0x24, 0xDF, 0xA4, 0xF6, 0xA4, 0xA7, 0x64, 0x96, 0x64, 0xB7, 0xE4, 0xEE, 0x14, 0x98, 0x14, 0xF9, 0x94, 0xB4, 0x94, 0xED, 0x54, 0xCA, 0x54, 0x87, 0xD4, 0xD6, 0x34, 0xD0, 0x34, 0x89, 0xB4, 0xF8, 0xB4, 0x95, 0xF4, 0x9F, 0xE9, 0x16, 0xE9, 0xB5, 0xE9, 0x2F, 0x19, 0xFC, 0x19, 0x61, 0x19, 0x33, 0x99, 0x98, 0x99, 0x7A, 0x99, 0xC5, 0x99, 0x57, 0x59, 0x6C, 0x59, 0xBE, 0x59, 0x43, 0xD9, 0xDF, 0xB2, 0x55, 0xB2, 0xB3, 0xB2, 0xF7, 0xFE, 0x50, 0xFF, 0x71, 0xFC, 0xD3, 0x96, 0x03, 0x9A, 0x23, 0x9E, 0x13, 0x97, 0xB3, 0x94, 0x8B, 0x9F, 0x6B, 0x92, 0x5B, 0x91, 0x7B, 0x9F, 0xC7, 0x9D, 0x17, 0x98, 0x37, 0x9A, 0x8F, 0x94, 0xAF, 0x96, 0xFF, 0x27, 0xFF, 0xA0, 0x80, 0xA6, 0xC0, 0xA9, 0xA0, 0xAD, 0x10, 0xB4, 0x50, 0xBC, 0x30, 0xB6, 0x70, 0xA1, 0x08, 0xB7, 0xC8, 0xA8, 0xA8, 0xAC, 0xE8, 0xE6, 0x2F, 0xC7, 0x5F, 0xDF, 0xBF, 0x83, 0xC5, 0x08, 0xC5, 0x4A, 0xC5, 0xE9, 0xC5, 0xDB, 0x25, 0xE4, 0x25, 0x36, 0x25, 0x0D, 0x25, 0xAF, 0xA5, 0x02, 0xA5, 0x61, 0x80, 0x3B, 0xA0, 0x95, 0x69, 0x95, 0xE5, 0x97, 0x1D, 0x97, 0xD3, 0x97, 0xBB, 0x94, 0xB7, 0x57, 0x80, 0x55, 0x88, 0x57, 0xC4, 0x54, 0x2C, 0x54, 0xE2, 0x54, 0x1A, 0x56, 0x96, 0x54, 0x5E, 0x56, 0xB1, 0x56, 0x79, 0x55, 0xF5, 0x55, 0xC3, 0x56, 0xCB, 0x55, 0xA7, 0x54, 0xAF, 0xD7, 0x10, 0xD7, 0x58, 0xD6, 0xD4, 0xD4, 0x3C, 0xD5, 0xF2, 0xD6, 0xFE, 0xAE, 0x1D, 0xAF, 0xFB, 0x51, 0xA7, 0x51, 0x97, 0x0B, 0x98, 0x03, 0x5D, 0xBD, 0x4B, 0x7D, 0x47, 0x03, 0x78, 0x83, 0x64, 0x43, 0x7C, 0xC3, 0x72, 0x23, 0x41, 0xA3, 0x69, 0x63, 0x65, 0xE3, 0x7D, 0x13, 0x77, 0x53, 0x50, 0xD3, 0x58, 0x33, 0x72, 0xB3, 0x7A, 0x73, 0x6E, 0xF3, 0x51, 0x0B, 0x5D, 0x8B, 0x6B, 0x4B, 0x57, 0x2B, 0x42, 0xAB, 0x4E, 0x6B, 0x75, 0x1B, 0x48, 0x9B, 0x42, 0x5B, 0x41, 0xDB, 0x7D, 0xBB, 0x68, 0x7B, 0x6A, 0xFB, 0x49, 0x07, 0x57, 0x47, 0x54, 0xC7, 0x46, 0x27, 0x7D, 0x67, 0x40, 0xE7, 0x5C, 0x17, 0x49, 0x97, 0x6B, 0xD7, 0x70, 0x37, 0x56, 0xB7, 0x55, 0x77, 0x67, 0x0F, 0x62, 0x8F, 0x41, 0x4F, 0x7D, 0x2F, 0x44, 0xAF, 0x6A, 0x6F, 0x49, 0xEF, 0x6B, 0x9F, 0x4C, 0x5F, 0x4E, 0xDF, 0x4D, 0xBF, 0x50, 0x7F, 0x72, 0xFF, 0xD1, 0x00, 0xE7, 0x40, 0xD4, 0xC0, 0xE6, 0x20, 0xC3, 0x60, 0xD0, 0xE0, 0xC2, 0x10, 0xF9, 0x90, 0xE7, 0xD0, 0xC4, 0x30, 0x01, 0x60, 0x0A, 0x03, 0x23, 0xE8, 0x23, 0x16, 0x23, 0xED, 0xA3, 0xDF, 0x47, 0x0D, 0x46, 0xEB, 0xC7, 0xA0, 0xC6, 0x34, 0xC6, 0x2A, 0xC6, 0x3E, 0xC7, 0x15, 0xC6, 0x0B, 0xC7, 0x9F, 0x26, 0x24, 0x27, 0xB2, 0x27, 0xAE, 0x27, 0x85, 0x26, 0x53, 0x26, 0x4F, 0xA6, 0x7E, 0x4D, 0xC5, 0x4D, 0xED, 0x4D, 0xB3, 0x4D, 0x87, 0x4F, 0x6F, 0xCC, 0x30, 0xCC, 0x04, 0xCD, 0x2C, 0x02, 0x86, 0xE0, 0x33, 0x3B, 0x3B, 0x47, 0x32, 0xE7, 0x3E, 0x37, 0x3E, 0x4F, 0x30, 0xEF, 0x38, 0x3F, 0xF4, 0x0F, 0xEB, 0x9F, 0xCD, 0xBF, 0xDE, 0x05, 0xD4, 0x05, 0xF3, 0x85, 0x8E, 0x45, 0xC4, 0x45, 0xA3, 0xC5, 0xE6, 0x25, 0xF8, 0x25, 0xBD, 0xA5, 0x7A, 0xC0, 0x0D, 0x34, 0x97, 0xAB, 0x56, 0xC0, 0x56, 0x54, 0x57, 0xCA, 0x56, 0x3E, 0x57, 0x15, 0x57, 0xFF, 0xAE, 0xBE, 0xAE, 0xC9, 0xAE, 0x15, 0xAC, 0x3D, 0xAD, 0x4B, 0xAD, 0xE7, 0xAC, 0xDF, 0x6D, 0x88, 0x6F, 0x64, 0x6D, 0x5C, 0x6F, 0x8A, 0x6C, 0xA6, 0x6F, 0x5E, 0x6C, 0x09, 0x6E, 0xA5, 0x6C, 0x9D, 0x6D, 0xF3, 0x6D, 0x27, 0x6D, 0x9F, 0xEC, 0xF0, 0xEC, 0x24, 0xEC, 0x1C, 0xED, 0x72, 0xEF, 0x7A, 0xEC, 0xD6, 0xEF, 0x5E, 0xEE, 0x51, 0xEC, 0x19, 0xEE, 0x65, 0xED, 0x2D, 0xED, 0x23, 0xEF, 0x4B, 0xED, 0x87, 0xEC, 0xF7, 0xEC, 0xBF, 0x1D, 0xB0, 0x1E, 0xD8, 0x1D, 0x94, 0x1D, 0xEC, 0x1F, 0x12, 0x1C, 0x6A, 0x1C, 0x26, 0x1D, 0x4E, 0x1D, 0xC1, 0x1E, 0x09, 0x1D, 0xF9, 0x1E, 0xB5, 0x1E, 0xDD, 0x1D, 0xD3, 0x1D, 0x5B, 0x1C, 0x17, 0x1C, 0x6F, 0x9E, 0x60, 0x9D, 0x28, 0x9D, 0xC4, 0x9C, 0x8C, 0x9E, 0x42, 0x9C, 0xF2, 0x9D, 0x7A, 0x9C, 0x36, 0x9C, 0x5E, 0x9D, 0x51, 0x9D, 0x99, 0x9C, 0xE5, 0x9E, 0xAD, 0x9D, 0xA3, 0x9F, 0x2B, 0x9C, 0x47, 0x9D, 0x0F, 0x5F, 0x80, 0x5D, 0xF0, 0x5C, 0xB8, 0x5F, 0x34, 0x5C, 0x5C, 0x01, 0x3E, 0x60, 0x72, 0x99, 0x7B, 0xB9, 0x7E, 0x85, 0x71, 0xA5, 0x78, 0x15, 0x73, 0x35, 0x7A, 0x0D, 0x71, 0xCD, 0x7F, 0xED, 0x75, 0xDD, 0x7C, 0x7D, 0x7B, 0x43, 0x77, 0x63, 0x71, 0x53, 0x74, 0xB3, 0x7D, 0x8B, 0x7B, 0xAB, 0x76, 0x9B, 0x78, 0x3B, 0x7D, 0x07, 0x77, 0x27, 0x7A, 0x17, 0x78, 0xD7, 0x75, 0xF7, 0x72, 0xCF, 0x7A, 0xEF, 0x70, 0x5F, 0x79, 0x7F, 0xF2, 0x40, 0xF2, 0xA0, 0xFF, 0x90, 0xF5, 0xB0, 0xFC, 0x88, 0xFA, 0x28, 0xFF, 0x18, 0xF5, 0x38, 0xF2, 0x04, 0xF1, 0xC4, 0x0F, 0x78, 0x40, 0xEB, 0xD3, 0xC3, 0x33, 0xE3, 0xB3, 0xCD, 0x73, 0xE9, 0xF3, 0xC1, 0x0B, 0xD1, 0x8B, 0xEE, 0x4B, 0xC6, 0xCB, 0xD2, 0x2B, 0xCA, 0xAB, 0xDC, 0x6B, 0xD4, 0xEB, 0xC8, 0x1B, 0xE4, 0x9B, 0xC0, 0x9B, 0xEF, 0x5B, 0xDB, 0xDB, 0xD3, 0x3B, 0xF3, 0xBB, 0xFD, 0x7B, 0xC5, 0xFB, 0xC9, 0x07, 0xD9, 0x87, 0xE1, 0x47, 0xCE, 0xC7, 0xFA, 0x27, 0xE6, 0xA7, 0xCA, 0x67, 0xC2, 0xE7, 0xF4, 0x17, 0xFC, 0x97, 0xF8, 0xD7, 0xEF, 0xAF, 0xBE, 0xFF, 0xC9, 0x7F, 0x1E, 0x10, 0x4F, 0x90, 0x26, 0x90, 0x3B, 0x50, 0x06, 0x80, 0xFE, 0xA5, 0xA0, 0x87, 0x60, 0xC4, 0x60, 0xFA, 0x60, 0xD9, 0x60, 0x2B, 0xE0, 0xE8, 0xE0, 0x4A, 0xE0, 0x71, 0xE0, 0x93, 0x10, 0x70, 0x10, 0x62, 0x10, 0x41, 0x10, 0x3D, 0x10, 0x1F, 0x90, 0x5C, 0x90, 0x6E, 0x90, 0x0D, 0x90, 0x37, 0x50, 0x74, 0x50, 0x56, 0x50, 0x25, 0x50, 0x07, 0xD0, 0x44, 0xD0, 0xBA, 0xD0, 0x99, 0xD0, 0xCB, 0x30, 0x68, 0x30, 0x8A, 0x30, 0xB1, 0x30, 0x13, 0xB0, 0xB0, 0xB0, 0xA2, 0xB0, 0x41, 0xB0, 0x3D, 0xB0, 0x9F, 0x70, 0xDC, 0x70, 0xEE, 0x70, 0x8D, 0x70, 0xB7, 0xF0, 0xF4, 0xF0, 0xD6, 0xF0, 0xA5, 0xF0, 0x87, 0x08, 0xC4, 0x08, 0xFA, 0x08, 0xD9, 0x08, 0x6B, 0xDF, 0x30, 0xBF, 0xA9, 0x7C, 0x4B, 0xF8, 0x36, 0xFD, 0x1D, 0xE1, 0xBB, 0x04, 0xC0, 0xFA, 0x01, 0x44, 0x50, 0x60, 0xD5, 0x7B, 0x21, 0xB6, 0x22, 0x3E, 0x22, 0x31, 0x23, 0xD9, 0x23, 0x55, 0x22, 0x9D, 0x21, 0x53, 0x20, 0x9B, 0x20, 0xE7, 0x23, 0x6F, 0xFF, 0xC0, 0xFB, 0xA1, 0xF9, 0x23, 0xF5, 0xC7, 0x02, 0xCA, 0x0F, 0x14, 0x39, 0x94, 0x68, 0x94, 0x31, 0x54, 0x68, 0x54, 0x61, 0xD4, 0x40, 0xD4, 0x6E, 0xD4, 0x77, 0x34, 0x2E, 0x34, 0x37, 0xB4, 0x06, 0xB4, 0x5B, 0x74, 0x7A, 0x74, 0x6B, 0xF4, 0x32, 0xF4, 0x23, 0x0C, 0x52, 0x0C, 0x43, 0x8C, 0x1C, 0x8C, 0x0D, 0x4C, 0x6C, 0x4C, 0x75, 0xCC, 0x64, 0xCC, 0x39, 0x2C, 0x24, 0x2C, 0x19, 0xAC, 0x48, 0xAC, 0x11, 0x6C, 0x28, 0x6C, 0x21, 0x6C, 0x7F, 0xEC, 0x2E, 0xEC, 0x37, 0x1C, 0x4E, 0x1C, 0x57, 0x9C, 0x06, 0x9C, 0x1B, 0x5C, 0x7A, 0x5C, 0x6B, 0xDC, 0x32, 0xDC, 0x23, 0x3C, 0x52, 0x3C, 0x43, 0xBC, 0x5C, 0xBC, 0x4D, 0x7C, 0x1C, 0x7C, 0x0D, 0xFC, 0x34, 0xFC, 0x75, 0x02, 0x22, 0x02, 0x33, 0x82, 0x0A, 0x82, 0x5B, 0x42, 0x76, 0x42, 0x6F, 0xC2, 0xDE, 0x9F, 0xD0, 0x3F, 0xA5, 0x7F, 0xC6, 0xFF, 0x5C, 0x22, 0xC2, 0x25, 0x32, 0x20, 0x2A, 0x26, 0x3A, 0x27, 0x66, 0x22, 0x76, 0x23, 0xEE, 0x20, 0x01, 0x23, 0x11, 0x23, 0x89, 0x26, 0x99, 0x23, 0xC5, 0x24, 0xD5, 0x21, 0x2D, 0x00, 0xA8, 0x4E, 0x47, 0xE6, 0x44, 0xD6, 0x4A, 0xF6, 0x49, 0x2E, 0x4C, 0x1E, 0x4E, 0x3E, 0x4D, 0x81, 0x4A, 0xA1, 0x49, 0x91, 0x0B, 0x2C, 0x77, 0x6A, 0x4A, 0x07, 0xCA, 0x26, 0xCA, 0x77, 0x2A, 0x41, 0xAA, 0x50, 0xAA, 0x49, 0x6A, 0x14, 0x6A, 0x75, 0x60, 0xB7, 0xEF, 0xD3, 0x50, 0xD1, 0xD8, 0xD1, 0x34, 0xD2, 0xBC, 0xD1, 0x0A, 0xD0, 0x86, 0xD0, 0x4E, 0xD0, 0xFD, 0xA0, 0x53, 0xA7, 0xCB, 0xA6, 0xDB, 0xA3, 0xA7, 0x04, 0x68, 0xDE, 0x40, 0xFF, 0xCA, 0xC0, 0xCF, 0x10, 0xC2, 0x30, 0xCE, 0x88, 0xCC, 0xA8, 0xC6, 0x98, 0xC5, 0xB8, 0xCB, 0x44, 0xC1, 0x64, 0xCB, 0x54, 0xCF, 0xF4, 0xC2, 0xCC, 0xC7, 0x1C, 0xCC, 0x3C, 0xC6, 0x82, 0xC4, 0xA2, 0xC2, 0x92, 0xC9, 0xB2, 0xC3, 0x4A, 0xC6, 0x6A, 0xCD, 0x5A, 0xC7, 0xFA, 0xCC, 0xC6, 0xC3, 0x16, 0xC4, 0x36, 0xCA, 0xFE, 0x9D, 0x5D, 0x99, 0x3D, 0x83, 0x7D, 0x9B, 0x83, 0x94, 0xC3, 0x8A, 0xA3, 0x96, 0xE3, 0x89, 0x93, 0x87, 0x33, 0x90, 0x73, 0x84, 0xEB, 0x3B, 0x97, 0x32, 0x57, 0x06, 0xD7, 0x16, 0x37, 0x29, 0xB7, 0x15, 0x77, 0x2D, 0xF7, 0xD3, 0x2F, 0x9E, 0x5F, 0x41, 0xBF, 0x46, 0x78, 0xBE, 0xF3, 0x28, 0xF3, 0x64, 0xF0, 0x6C, 0xF3, 0x92, 0xF1, 0x5A, 0xF3, 0xD6, 0xF1, 0x3E, 0xF3, 0xF1, 0xF2, 0x05, 0xF3, 0x8D, 0xF1, 0x23, 0xF1, 0xAB, 0xF2, 0x67, 0xF1, 0xEF, 0x0A, 0x50, 0x0A, 0xD8, 0x0A, 0xD4, 0x09, 0x3C, 0x08, 0x72, 0x0A, 0x7A, 0x0B, 0xF6, 0x08, 0x81, 0x0B, 0x89, 0x09, 0x45, 0x0A, 0x4D, 0x09, 0xFF, 0x10, 0x56, 0x15, 0x4E, 0x17, 0xDE, 0x10, 0xF9, 0x29, 0x62, 0x22, 0x52, 0x02, 0xB0, 0x9B, 0x41, 0xD4, 0x59, 0xB4, 0x45, 0xF4, 0x5D, 0x8C, 0x5F, 0x2C, 0x58, 0x6C, 0x44, 0x1C, 0x01, 0x58, 0xED, 0x49, 0xE2, 0xCB, 0x12, 0xB8, 0x12, 0xFA, 0x12, 0x85, 0x12, 0xC7, 0x92, 0x34, 0x92, 0xF6, 0x92, 0x0D, 0x92, 0xCF, 0x52, 0x3C, 0x52, 0x01, 0x52, 0x83, 0xD2, 0xB0, 0xD2, 0xB2, 0xD2, 0x09, 0xD2, 0x8B, 0x32, 0x38, 0x32, 0x7A, 0x32, 0x05, 0x32, 0xC7, 0xB2, 0x34, 0xB2, 0x0E, 0xB2, 0x8D, 0xB2, 0xAF, 0x72, 0xBC, 0x72, 0x41, 0x72, 0xC3, 0xF2, 0x08, 0xF2, 0xF2, 0xF2, 0xC9, 0xF2, 0xAB, 0x0A, 0xF8, 0x0A, 0x46, 0x0A, 0x25, 0x0A, 0xE7, 0x00, 0xB3, 0x5D, 0x15, 0xDB, 0x15, 0xBF, 0x94, 0x84, 0x95, 0xC2, 0x95, 0xA6, 0x94, 0x51, 0x94, 0xD5, 0x95, 0xB3, 0x95, 0x77, 0x55, 0xC8, 0x55, 0xAC, 0x55, 0x6A, 0x55, 0x1E, 0x55, 0xB9, 0x55, 0xFD, 0x55, 0x07, 0xD5, 0xE0, 0xD4, 0xE4, 0xD4, 0x92, 0xD4, 0x56, 0xD4, 0xF1, 0xD5, 0x8D, 0xD5, 0x4B, 0xD5, 0x2F, 0x35, 0x98, 0x35, 0xDC, 0x35, 0xBA, 0x34, 0xC1, 0x01, 0x5A, 0x47, 0x6B, 0xCE, 0x69, 0x61, 0x68, 0x69, 0x6B, 0xE5, 0x69, 0x1D, 0x6A, 0x53, 0x6B, 0xDB, 0x6B, 0x37, 0x68, 0xBF, 0xE8, 0xF0, 0xEA, 0x04, 0xE9, 0x8C, 0xE8, 0x22, 0xE8, 0x2A, 0xE8, 0xA6, 0xFC, 0xCF, 0xFD, 0x6E, 0xAC, 0x57, 0xA2, 0x77, 0xA1, 0xCF, 0xA4, 0xEF, 0xAA, 0xDF, 0xAE, 0xFF, 0x65, 0x20, 0x6C, 0x10, 0x66, 0x30, 0x61, 0x88, 0x6C, 0xA8, 0x62, 0x98, 0x61, 0xB8, 0x69, 0x44, 0x64, 0x64, 0x6A, 0x54, 0x66, 0x74, 0x66, 0x4C, 0x63, 0x6C, 0x63, 0x5C, 0x65, 0x7C, 0x65, 0xC2, 0x60, 0xE2, 0x60, 0x52, 0x67, 0x72, 0x67, 0xCA, 0x62, 0xEA, 0x62, 0xDA, 0x64, 0xFA, 0x64, 0xC6, 0x61, 0xE6, 0x6E, 0xD6, 0x6A, 0xF6, 0x6A, 0xCE, 0x6D, 0xEE, 0x6D, 0xDE, 0x61, 0xFE, 0x01, 0x2C, 0x78, 0x3F, 0x8B, 0x6E, 0x4B, 0x10, 0x4B, 0x01, 0xCB, 0x00, 0xCB, 0x3E, 0x2B, 0x70, 0x2B, 0x21, 0xAB, 0x60, 0xAB, 0x01, 0x6B, 0x48, 0x6B, 0x11, 0xEB, 0xDF, 0xD6, 0x43, 0x36, 0x50, 0x00, 0x9B, 0x43, 0x6D, 0x86, 0x6D, 0xA1, 0x6D, 0xC5, 0x6C, 0xC3, 0x6C, 0x47, 0xEC, 0x60, 0xEC, 0xC4, 0xED, 0xC2, 0xEC, 0x46, 0xEC, 0x61, 0xEC, 0xC5, 0xED, 0xC3, 0xEC, 0x47, 0x1C, 0x60, 0x1C, 0xC4, 0x1C, 0x42, 0x1D, 0x86, 0x1D, 0xA1, 0x1D, 0x45, 0x1D, 0x43, 0x1C, 0x87, 0x9C, 0x20, 0x9D, 0x44, 0x9C, 0x7E, 0x3B, 0x0D, 0x38, 0x43, 0x38, 0x0B, 0x39, 0x07, 0x3A, 0xF7, 0xB9, 0x80, 0xBA, 0x08, 0xB8, 0xF8, 0xBB, 0x74, 0xBB, 0x7C, 0xBA, 0xF2, 0xBA, 0xFA, 0xB8, 0x76, 0xB8, 0xBE, 0xB9, 0x71, 0xB9, 0x79, 0xB8, 0xB5, 0xB8, 0x3D, 0xB9, 0xB3, 0xB9, 0xBB, 0xB8, 0x37, 0xB8, 0xDF, 0x79, 0x30, 0x79, 0x38, 0x78, 0xD4, 0x78, 0x5C, 0x79, 0xD2, 0x7A, 0x5A, 0x7B, 0x96, 0x7B, 0x9E, 0x7A, 0x51, 0x78, 0x99, 0x79, 0xFD, 0xF5, 0xDA, 0xF7, 0x26, 0xF6, 0x36, 0xF0, 0xCE, 0xF5, 0xDE, 0xF4, 0xC1, 0xF3, 0xD1, 0xF2, 0xC9, 0xF0, 0x59, 0xF6, 0xC5, 0xF0, 0x55, 0xF1, 0x4D, 0xF4, 0x9D, 0xF3, 0x43, 0xF2, 0x93, 0xF5, 0x8B, 0xF2, 0x1B, 0x07, 0xA8, 0x2C, 0xE6, 0xFF, 0xDB, 0x7F, 0x20, 0x00, 0x2C, 0x80, 0x3F, 0xC0, 0x37, 0xA0, 0x23, 0xE0, 0x35, 0x90, 0x23, 0xD0, 0x35, 0xB0, 0x21, 0xF0, 0x36, 0x88, 0x21, 0xC8, 0x3E, 0xA8, 0x0E, 0xA0, 0x32, 0x5B, 0xB0, 0x7B, 0x70, 0x5B, 0xF0, 0xFB, 0x6F, 0xDE, 0xDF, 0xFE, 0xBF, 0xFB, 0x42, 0x20, 0x42, 0x44, 0x43, 0xC2, 0x42, 0x46, 0x43, 0xE1, 0x43, 0x65, 0x42, 0x63, 0x42, 0x67, 0xC2, 0x90, 0xC3, 0x94, 0xC2, 0x92, 0xC2, 0x16, 0xC3, 0x31, 0xC2, 0x35, 0xC2, 0x33, 0xC2, 0xD7, 0x22, 0x70, 0x23, 0x74, 0x22, 0x72, 0x22, 0xB6, 0x23, 0x7F, 0x46, 0x1A, 0x46, 0x16, 0x44, 0xEE, 0x47, 0x91, 0x46, 0x99, 0x44, 0xFD, 0x8D, 0x3A, 0x8A, 0xA6, 0x88, 0x36, 0x07, 0x16, 0xFD, 0x69, 0x0C, 0x55, 0x8C, 0x55, 0x4C, 0x79, 0xCC, 0x79, 0x2C, 0x4D, 0xAC, 0x75, 0x6C, 0x65, 0xEC, 0x45, 0x1C, 0x6D, 0x9C, 0x4D, 0x5C, 0x55, 0xDC, 0x65, 0x3C, 0x5D, 0xBC, 0x6D, 0x7C, 0x55, 0xFC, 0x65, 0x02, 0x5D, 0x82, 0x4D, 0x42, 0x65, 0xC2, 0x45, 0x22, 0x6D, 0xA2, 0x75, 0x62, 0x45, 0xE2, 0x59, 0x12, 0x75, 0x92, 0x65, 0x52, 0x59, 0xD2, 0x49, 0x32, 0x65, 0xB2, 0x79, 0x72, 0x71, 0xF2, 0x61, 0x0A, 0x69, 0x8A, 0x71, 0x4A, 0x61, 0xCA, 0x6E, 0xEA, 0x4F, 0x60, 0xD3, 0xE7, 0xA4, 0x6E, 0xA6, 0xE1, 0xA5, 0x69, 0xA5, 0x65, 0x00, 0x44, 0xC6, 0x48, 0x57, 0x4D, 0x4F, 0x4A, 0x9F, 0xCF, 0x40, 0xCE, 0x90, 0xCF, 0x88, 0xC9, 0x98, 0xC8, 0x84, 0xCB, 0x94, 0xC8, 0x0C, 0xCD, 0x1C, 0xCC, 0x02, 0xCF, 0x12, 0xC8, 0xF2, 0xCB, 0xEA, 0xCC, 0x7A, 0xCB, 0xE6, 0xC8, 0x76, 0xCD, 0x6E, 0xC8, 0xBE, 0xFD, 0x43, 0xFF, 0xC7, 0xE6, 0x4F, 0xF9, 0x9F, 0xE3, 0x1C, 0xB2, 0x1C, 0xA3, 0x9C, 0xBC, 0x9C, 0xCD, 0x5C, 0xDC, 0x5C, 0x8D, 0xDC, 0x94, 0xDC, 0x7F, 0x79, 0xC8, 0x79, 0xB2, 0x79, 0x91, 0x00, 0x9B, 0xA1, 0xF2, 0x85, 0xF2, 0xFD, 0xF3, 0x3B, 0xF3, 0x5F, 0x0B, 0xB8, 0x0A, 0xBC, 0x0B, 0xBA, 0x0A, 0x41, 0x0A, 0x05, 0x0B, 0x83, 0x0B, 0x87, 0x8A, 0xA0, 0x8B, 0x24, 0x8A, 0x22, 0x8B, 0x26, 0xFF, 0x7E, 0x07, 0xB6, 0x7D, 0xFC, 0xDF, 0xF9, 0x62, 0xB4, 0x62, 0xD5, 0xE2, 0xB4, 0xE2, 0x95, 0x12, 0xEC, 0x12, 0xED, 0x92, 0xEC, 0x92, 0xCD, 0x52, 0xC2, 0x52, 0x83, 0xD2, 0xFC, 0xD2, 0xBD, 0x32, 0x92, 0x32, 0xD3, 0xB2, 0x62, 0x80, 0xD0, 0x94, 0xE5, 0x96, 0xE5, 0xE5, 0xE5, 0xE7, 0x15, 0x34, 0x15, 0x36, 0x15, 0x55, 0x15, 0x57, 0x95, 0x0C, 0x95, 0xF6, 0x95, 0xB5, 0x95, 0xB7, 0x55, 0xCC, 0x55, 0xCE, 0x55, 0x8D, 0x55, 0x8F, 0xD5, 0xEC, 0xD5, 0xEE, 0xD5, 0xAD, 0xD5, 0xAF, 0x35, 0xDC, 0x35, 0x3E, 0x35, 0x5D, 0x35, 0x5F, 0xB5, 0xFC, 0xB5, 0x81, 0xB5, 0xFD, 0x75, 0x10, 0x75, 0xA2, 0x75, 0xA1, 0x75, 0xA3, 0xF5, 0x70, 0xF5, 0xD2, 0xF5, 0xD1, 0xF5, 0xD3, 0x0D, 0x48, 0x0D, 0x8A, 0x0D, 0x49, 0x0D, 0x8B, 0x8D, 0x18, 0x8D, 0x1A, 0x8D, 0x99, 0x8D, 0x1B, 0x4D, 0x04, 0x4D, 0x06, 0x4D, 0x05, 0x4D, 0x07, 0xCD, 0xE4, 0xCD, 0x16, 0xCD, 0xE5, 0xCD, 0x17, 0x2D, 0xF4, 0x2D, 0x0E, 0x2D, 0x0D, 0x2D, 0x8F, 0xAD, 0x1C, 0xAD, 0x9E, 0xAD, 0x9D, 0xAD, 0x5F, 0x6D, 0x82, 0x6D, 0xC1, 0x6D, 0xC3, 0xED, 0xB0, 0xED, 0xD2, 0xED, 0xB1, 0xED, 0xB3, 0x1D, 0xA8, 0x1D, 0x6A, 0x1D, 0xE9, 0x1D, 0xEB, 0x9D, 0x04, 0x9D, 0x86, 0x9D, 0x45, 0x9D, 0xC7, 0xC0, 0xC6, 0xB7, 0xED, 0xAA, 0xED, 0xBA, 0xEF, 0x66, 0xEF, 0xF6, 0x04, 0x98, 0x0D, 0xD2, 0x23, 0xDC, 0x13, 0xDA, 0x33, 0xD6, 0xFB, 0xBD, 0x57, 0xA1, 0x37, 0xB9, 0x77, 0xB9, 0x0F, 0xB7, 0x4F, 0xAF, 0xAF, 0xA0, 0xEF, 0x10, 0x58, 0xF9, 0xB6, 0xFD, 0x75, 0xFD, 0x0F, 0x03, 0x2C, 0x03, 0x0E, 0x03, 0x55, 0x03, 0xA7, 0x83, 0xE4, 0x83, 0xC6, 0x83, 0x79, 0x83, 0x9B, 0x43, 0x38, 0x43, 0xEA, 0x43, 0xC9, 0x43, 0x73, 0xC3, 0x88, 0xC3, 0x32, 0xC3, 0x11, 0xC3, 0xC3, 0x23, 0x10, 0x23, 0x82, 0x23, 0x7E, 0x23, 0x1D, 0x23, 0xAF, 0xA3, 0xEC, 0xA3, 0xCE, 0xA3, 0x75, 0xA3, 0x57, 0x63, 0xB4, 0x63, 0x56, 0x63, 0x25, 0x63, 0x87, 0xE3, 0xC4, 0xE3, 0x06, 0xE3, 0x39, 0xE3, 0x1B, 0x13, 0xD8, 0x13, 0xEA, 0x13, 0x29, 0x13, 0xFF, 0x26, 0x7F, 0x4C, 0xCA, 0x4F, 0xC6, 0x4C, 0x4E, 0x4C, 0xC1, 0x4D, 0x89, 0x4F, 0x85, 0x4C, 0x0D, 0x4C, 0x83, 0x4D, 0xF3, 0x4F, 0xFB, 0x4E, 0x77, 0x4C, 0xBF, 0xCE, 0x70, 0xCC, 0xB8, 0xCE, 0x34, 0xCE, 0xDC, 0xCD, 0x32, 0xCE, 0xDA, 0xCD, 0x56, 0xCD, 0x9E, 0xCF, 0x51, 0xCD, 0x59, 0xCC, 0x15, 0xCF, 0x1D, 0xCC, 0x93, 0xCC, 0x1B, 0xCE, 0xE7, 0xCD, 0x6F, 0xFD, 0xC3, 0xFF, 0xA7, 0xFD, 0x2F, 0xF3, 0xDF, 0xCA, 0x02, 0xE6, 0x82, 0xEA, 0x42, 0xF2, 0xC2, 0xBF, 0xC5, 0x1F, 0x8B, 0x0A, 0x8B, 0x71, 0x8B, 0x53, 0x4B, 0xDF, 0x96, 0xA4, 0x97, 0x22, 0x96, 0x46, 0x97, 0x61, 0x96, 0xC5, 0x96, 0x43, 0x96, 0x07, 0x56, 0xC0, 0x57, 0x04, 0x57, 0x02, 0x56, 0x7A, 0x56, 0xBE, 0x56, 0x79, 0x56, 0xBD, 0x57, 0xDB, 0x01, 0xD2, 0x73, 0xAE, 0xB9, 0xAF, 0x35, 0xAF, 0x3D, 0xAE, 0xB3, 0xAE, 0x3B, 0xAF, 0xD7, 0xAF, 0xDF, 0x6E, 0x30, 0x6E, 0xD8, 0x6F, 0x54, 0x6F, 0x5C, 0x6D, 0xD2, 0x6D, 0xDA, 0x6C, 0x56, 0x6C, 0x9E, 0x6D, 0x51, 0x6D, 0x59, 0x6C, 0x95, 0x6E, 0x1D, 0x6F, 0x93, 0x6F, 0x9B, 0x6E, 0xFF, 0xDD, 0x3E, 0xD8, 0x21, 0xD9, 0x31, 0xDE, 0x29, 0xD8, 0xD9, 0xDB, 0x25, 0xDA, 0x35, 0xD8, 0xCD, 0x03, 0x5A, 0x00, 0xC1, 0x9E, 0xC6, 0x5E, 0xC2, 0xDE, 0xF8, 0x3E, 0xF8, 0xFE, 0xAF, 0x7D, 0x97, 0xFD, 0xCA, 0xFD, 0xC3, 0x03, 0x82, 0x03, 0xF5, 0x83, 0xF8, 0x83, 0xD1, 0x43, 0xB0, 0x43, 0xEE, 0x43, 0xE7, 0xC3, 0xCA, 0xC3, 0xC3, 0x23, 0x82, 0x23, 0xF5, 0xA3, 0xF8, 0xA3, 0xB1, 0x63, 0xF0, 0xE3, 0x5F, 0xC7, 0x2E, 0xC7, 0x55, 0xC7, 0x47, 0x27, 0x84, 0x27, 0x1A, 0x27, 0x09, 0x27, 0xE3, 0x00, 0xF9, 0x79, 0x4F, 0xDD, 0x4E, 0x6B, 0x4E, 0x4F, 0xCE, 0x88, 0xCF, 0xB4, 0xCF, 0x92, 0xCF, 0xA6, 0xCE, 0x61, 0xCE, 0x05, 0xCE, 0x3D, 0xCF, 0x1B, 0xCE, 0x2F, 0x2E, 0xC8, 0x2F, 0xF4, 0x2F, 0xD2, 0x2F, 0xE6, 0x2F, 0x11, 0x2E, 0x45, 0x2F, 0xFD, 0x2E, 0x5B, 0x2F, 0x6F, 0xAF, 0x68, 0xAE, 0x4C, 0xAE, 0x72, 0xAE, 0x56, 0xAE, 0x7F, 0x5C, 0x4B, 0x5F, 0x87, 0x5C, 0x77, 0x5F, 0xBF, 0xDC, 0x30, 0xDF, 0x58, 0xDF, 0xFC, 0x05, 0xD8, 0x8F, 0x7D, 0xAB, 0x74, 0x1B, 0x7D, 0x3B, 0x7C, 0x07, 0x7A, 0xC7, 0x7D, 0xE7, 0x72, 0x57, 0x75, 0x77, 0x7C, 0x4F, 0x74, 0xAF, 0x7D, 0x9F, 0x72, 0x3F, 0xF3, 0x00, 0xF7, 0x20, 0xFC, 0xE0, 0xFB, 0xD0, 0xF2, 0x70, 0xFB, 0x48, 0xF3, 0x68, 0xF6, 0x98, 0xF7, 0xB8, 0xF6, 0x84, 0xF6, 0x24, 0xF7, 0x14, 0xFE, 0x34, 0xF0, 0xF4, 0xF9, 0xCC, 0xF1, 0xEC, 0xF8, 0x5C, 0xF9, 0x7C, 0xF4, 0xF2, 0xF3, 0x45, 0xFB, 0x25, 0xE5, 0x65, 0xE6, 0x15, 0xFE, 0x55, 0xE4, 0xD5, 0xEF, 0xB5, 0xED, 0xF5, 0xFE, 0x8D, 0xFE, 0xCD, 0xE2, 0xAD, 0xF0, 0x6D, 0xF3, 0x1D, 0xEB, 0x5D, 0xF9, 0x3D, 0xE6, 0x7D, 0x14, 0x28, 0x00, 0xBC, 0x1F, 0x1E, 0x1F, 0xF5, 0x1F, 0x97, 0x9F, 0x94, 0x9F, 0x46, 0x9F, 0x7F, 0x3E, 0x57, 0xBE, 0x50, 0xBF, 0x64, 0xBF, 0xC2, 0xBF, 0x06, 0xFE, 0x27, 0xFF, 0xB9, 0x40, 0x9C, 0x41, 0xAA, 0x41, 0x4E, 0x40, 0x89, 0x41, 0x75, 0x40, 0x53, 0x41, 0xE7, 0xC0, 0x10, 0xC0, 0x44, 0xC1, 0x02, 0xC0, 0xDA, 0xC1, 0x1E, 0xC0, 0xE9, 0xC1, 0x2D, 0xC1, 0x0B, 0xC1, 0xB7, 0x20, 0xB0, 0x20, 0x94, 0x20, 0x62, 0x20, 0x46, 0x20, 0xC1, 0x21, 0x79, 0x20, 0xDD, 0x21, 0xEB, 0x20, 0xCF, 0xA1, 0xC8, 0xA1, 0x0C, 0xA0, 0xB2, 0xA0, 0x96, 0xA0, 0x91, 0xA1, 0xA5, 0xA1, 0x43, 0xA0, 0x7B, 0xA1, 0xDF, 0x60, 0xD8, 0x60, 0x1C, 0x60, 0xCA, 0x61, 0x0E, 0x81, 0xD2, 0xAF, 0x05, 0x9B, 0x02, 0x3B, 0x0B, 0x07, 0x0F, 0x27, 0x0A, 0x17, 0x00, 0xD7, 0x01, 0xF7, 0x08, 0xCF, 0x08, 0x38, 0x40, 0x31, 0xFC, 0x2E, 0x02, 0x2E, 0x82, 0x1A, 0x42, 0x02, 0xC2, 0xE4, 0x37, 0x18, 0xA0, 0xEF, 0xFB, 0x7E, 0x6B, 0xFD, 0x76, 0xFF, 0x9D, 0xEE, 0xBB, 0xC5, 0xF7, 0xC2, 0xEF, 0x5B, 0x88, 0xD8, 0x88, 0x2A, 0x88, 0x71, 0x88, 0xE3, 0x48, 0xD0, 0x48, 0x82, 0x48, 0x3E, 0x48, 0x2D, 0x48, 0x77, 0xC8, 0x74, 0xC0, 0xDA, 0x2F, 0x44, 0xDE, 0xFA, 0x81, 0xF3, 0x43, 0xF5, 0x47, 0xFC, 0x8F, 0x09, 0x14, 0x68, 0x60, 0xEB, 0xFB, 0xA2, 0xB4, 0xA2, 0xDC, 0xA3, 0x32, 0xA0, 0x5A, 0xA1, 0xFE, 0x45, 0xDD, 0x41, 0xC3, 0x43, 0x53, 0x47, 0x4B, 0x44, 0x9B, 0x46, 0x87, 0x43, 0x17, 0x41, 0x0F, 0x40, 0xEF, 0x40, 0x7F, 0xC6, 0x60, 0xC6, 0xB0, 0xC5, 0x28, 0xC3, 0x38, 0xC0, 0xFC, 0x89, 0xA9, 0x8D, 0x99, 0x86, 0x39, 0x8F, 0x85, 0x88, 0x25, 0x89, 0x15, 0x82, 0xD5, 0x8B, 0xF5, 0x81, 0xCD, 0x81, 0xED, 0x8C, 0x5D, 0x83, 0x7D, 0x86, 0x43, 0x8E, 0x63, 0x88, 0xF3, 0x07, 0x67, 0x15, 0x17, 0x0D, 0x57, 0x01, 0x37, 0x1A, 0x77, 0x04, 0x0F, 0x02, 0x8F, 0x1F, 0xCF, 0x0F, 0x6F, 0x18, 0x1F, 0x19, 0x5F, 0x0B, 0xBF, 0x08, 0xFF, 0x8A, 0x80, 0x83, 0x20, 0x90, 0x60, 0x82, 0x10, 0x9D, 0x50, 0x9F, 0xB0, 0x8C, 0xF0, 0xFE, 0x27, 0x2F, 0xB0, 0xEF, 0xE7, 0x00, 0x0B, 0x30, 0x25, 0xAA, 0x21, 0x7A, 0x23, 0x16, 0x21, 0x8E, 0x25, 0x5E, 0x21, 0x21, 0x26, 0xB1, 0x21, 0x69, 0x21, 0x05, 0x23, 0x95, 0x26, 0x4D, 0x21, 0xDD, 0x21, 0xA3, 0x26, 0x73, 0x21, 0xEB, 0x21, 0x87, 0x23, 0x57, 0x21, 0xCF, 0x21, 0x3F, 0xA1, 0x60, 0xA1, 0xF0, 0xA5, 0x18, 0x05, 0x56, 0xBD, 0x2E, 0x65, 0x09, 0xE5, 0x1D, 0x15, 0x0F, 0x55, 0x18, 0xD5, 0x1C, 0x35, 0x1E, 0xB5, 0x39, 0x75, 0x1D, 0xF5, 0x07, 0x8D, 0x18, 0x4D, 0x02, 0xCD, 0x06, 0x2D, 0x39, 0xAD, 0x23, 0x6D, 0x27, 0x1D, 0x0C, 0x9D, 0x22, 0xC0, 0xFF, 0x63, 0x7A, 0x66, 0x7A, 0x5F, 0xFA, 0x11, 0x06, 0x14, 0x06, 0x5D, 0x86, 0x52, 0x86, 0x7B, 0x46, 0x3E, 0xC6, 0x08, 0xC6, 0x05, 0x26, 0x42, 0x26, 0x2B, 0xA6, 0x26, 0x66, 0x50, 0x66, 0x69, 0xE6, 0x54, 0xE6, 0x5D, 0x16, 0x5A, 0x16, 0x0F, 0x96, 0x01, 0x56, 0x44, 0x56, 0x4D, 0xD6, 0x22, 0xD6, 0x1B, 0xB6, 0x5F, 0x6C, 0xA1, 0x6C, 0x73, 0xEC, 0x78, 0xEC, 0xE6, 0xEC, 0xF5, 0x40, 0xAB, 0x97, 0xE0, 0x48, 0xE2, 0xD8, 0xE2, 0xA4, 0xE2, 0x74, 0xE1, 0xEC, 0xE6, 0x82, 0xE3, 0x52, 0xE1, 0xCA, 0xE1, 0x3A, 0xE5, 0x66, 0xE5, 0xF6, 0xE3, 0x1E, 0xFB, 0x85, 0xFA, 0x4B, 0xEF, 0x57, 0xE9, 0xAF, 0x7B, 0x1E, 0x5E, 0x9E, 0x70, 0x9E, 0x79, 0x5E, 0x3C, 0x5E, 0x73, 0x80, 0xFB, 0xEF, 0x7C, 0x62, 0x7C, 0xF1, 0x7C, 0x6B, 0xFC, 0xA4, 0xFC, 0x76, 0xFC, 0xAD, 0x02, 0xE0, 0x02, 0x32, 0x02, 0xA9, 0x02, 0x3B, 0x82, 0xD4, 0x82, 0x2E, 0x82, 0xDD, 0x42, 0xB0, 0x42, 0x4A, 0x42, 0xD9, 0x42, 0x47, 0xC2, 0x4C, 0xC2, 0xDE, 0xC2, 0x43, 0x22, 0x48, 0x22, 0x9A, 0x22, 0x85, 0x22, 0x97, 0xA2, 0x9C, 0xA2, 0x41, 0xA2, 0x93, 0x62, 0x18, 0x62, 0x86, 0x62, 0x15, 0x62, 0x8F, 0xE2, 0xFC, 0xE2, 0x91, 0xE2, 0x0B, 0x12, 0x04, 0x12, 0x96, 0x12, 0x0D, 0x12, 0x5F, 0x92, 0x12, 0x92, 0x89, 0x92, 0x9B, 0x52, 0x14, 0x52, 0x4E, 0x52, 0x9D, 0xD2, 0x30, 0xD2, 0x8A, 0xFF, 0xB3, 0xD3, 0x33, 0xC9, 0xF8, 0xC8, 0x0C, 0xCB, 0xFE, 0x90, 0xD5, 0x91, 0x2D, 0x96, 0xBD, 0x95, 0xE3, 0x91, 0x0B, 0x95, 0x9B, 0x93, 0xC7, 0x93, 0x37, 0x97, 0xAF, 0x97, 0xFF, 0x50, 0x10, 0x57, 0x48, 0x54, 0xD8, 0x54, 0xA4, 0x54, 0x74, 0x56, 0xEC, 0x56, 0x82, 0x53, 0x52, 0x51, 0xCA, 0x05, 0xD6, 0x39, 0x9B, 0x72, 0x80, 0xF2, 0x84, 0x0A, 0xA6, 0x8A, 0x91, 0x4A, 0x95, 0xCA, 0x8B, 0xAA, 0xB0, 0x6A, 0x9C, 0xEA, 0x9A, 0x1A, 0x99, 0x9A, 0xA3, 0x5A, 0xA7, 0x3A, 0x8C, 0xBA, 0xB2, 0x7A, 0x8E, 0xFA, 0x99, 0x06, 0x9B, 0x46, 0xA0, 0xC6, 0xA4, 0x26, 0x96, 0xA6, 0xB1, 0x66, 0xB5, 0xE6, 0x9B, 0x96, 0xA8, 0x56, 0xBC, 0xD6, 0xBA, 0x36, 0xB9, 0xB6, 0xA3, 0x76, 0x87, 0x0E, 0xB4, 0x8E, 0xA2, 0x4E, 0x96, 0xCE, 0xA1, 0x2E, 0xA3, 0xAE, 0x97, 0xEE, 0xA0, 0x1E, 0xA2, 0x9E, 0x86, 0x5E, 0x01, 0xC0, 0x78, 0x76, 0xFD, 0x00, 0xFD, 0x31, 0x03, 0x54, 0x03, 0x1D, 0x83, 0x62, 0x83, 0x6B, 0x43, 0x4E, 0xC3, 0x40, 0xC3, 0x71, 0x23, 0x54, 0x23, 0x1D, 0xA3, 0xBF, 0x46, 0x57, 0xC6, 0x1C, 0xC6, 0xFE, 0xC6, 0xA3, 0x26, 0xC8, 0x26, 0x9A, 0x26, 0xF9, 0x26, 0xA7, 0xA6, 0xCC, 0xA6, 0x5E, 0xA6, 0xFD, 0x66, 0xF0, 0x66, 0x4A, 0x66, 0x99, 0x66, 0x07, 0xE6, 0xCC, 0xE6, 0x81, 0xE6, 0x33, 0x16, 0x04, 0x16, 0x36, 0x16, 0xED, 0x96, 0xB0, 0x96, 0x6A, 0x96, 0x45, 0x96, 0x77, 0x56, 0x02, 0x56, 0x31, 0x56, 0xEB, 0xD6, 0x54, 0xD6, 0x6E, 0xD6, 0x83, 0x36, 0x28, 0x36, 0xFA, 0x36, 0x55, 0x36, 0x6F, 0xB6, 0xE2, 0xB6, 0x29, 0xB6, 0x7B, 0x76, 0x8C, 0x76, 0xBE, 0x76, 0xE3, 0xF6, 0x98, 0xF6, 0xA6, 0xF6, 0xF5, 0x0E, 0x20, 0x0E, 0x32, 0x0E, 0x19, 0x0E, 0x47, 0x8E, 0x2C, 0x8E, 0x01, 0x8E, 0x53, 0x40, 0x95, 0x37, 0x77, 0x6A, 0x74, 0x06, 0x73, 0x96, 0x73, 0xCE, 0x74, 0x3E, 0x76, 0x61, 0x75, 0x09, 0x74, 0x99, 0x72, 0xC5, 0x71, 0x35, 0x73, 0x6D, 0x70, 0x03, 0x71, 0x93, 0x71, 0x4B, 0x77, 0x3B, 0x70, 0x67, 0x72, 0xF7, 0x75, 0x1F, 0xF3, 0x40, 0xF7, 0x30, 0xF2, 0xA8, 0xF6, 0x78, 0xF3, 0x14, 0x03, 0x7A, 0xFC, 0x96, 0x17, 0xB5, 0x97, 0x9B, 0x57, 0xBF, 0x37, 0xA2, 0xB7, 0x96, 0x77, 0xB1, 0xF7, 0xAD, 0x0F, 0xAF, 0x4F, 0x84, 0xCF, 0xA2, 0xEF, 0x4F, 0x5F, 0x1B, 0xDF, 0x16, 0x3F, 0x08, 0x3F, 0x79, 0xA0, 0xC5, 0x1F, 0xFA, 0x33, 0xF9, 0xFB, 0xF8, 0x8F, 0x06, 0xA0, 0x06, 0xE8, 0x05, 0x94, 0x05, 0x3C, 0x06, 0x0A, 0x04, 0x46, 0x05, 0x2E, 0x05, 0x11, 0x05, 0xD9, 0x04, 0xB5, 0x06, 0x43, 0x04, 0xCB, 0x05, 0x67, 0x04, 0x1F, 0xFC, 0x66, 0xF8, 0xED, 0xF5, 0x7B, 0x28, 0x04, 0x39, 0x44, 0x3B, 0xA4, 0x38, 0xE4, 0x36, 0x94, 0x27, 0x34, 0x2C, 0x74, 0x3E, 0x0C, 0x3F, 0xCC, 0x3C, 0xAC, 0x3E, 0xEC, 0x33, 0x5C, 0x3C, 0x3C, 0x31, 0x7C, 0x23, 0x82, 0x22, 0xC2, 0x31, 0xA2, 0x33, 0x12, 0x3A, 0x52, 0x21, 0x32, 0x2B, 0xF2, 0x30, 0x8A, 0x21, 0xCA, 0x33, 0x6A, 0x30, 0x1A, 0x31, 0x5A, 0x23, 0xBA, 0x20, 0xFA, 0x29, 0x46, 0x39, 0xA6, 0x2E, 0x16, 0x11, 0x20, 0xF5, 0x68, 0x1C, 0x79, 0x5C, 0x70, 0xDC, 0x4E, 0x3C, 0x6F, 0x7C, 0x66, 0xFC, 0x73, 0x82, 0x4A, 0x42, 0x6D, 0xE2, 0xF7, 0x44, 0xAB, 0xC4, 0xE1, 0x24, 0x92, 0x24, 0xFF, 0xA4, 0x8D, 0x64, 0xCE, 0xE4, 0xE4, 0xE4, 0xDB, 0x14, 0xD9, 0x94, 0xB2, 0x54, 0xA8, 0x54, 0xC3, 0xD4, 0xAE, 0x34, 0xAC, 0x34, 0x97, 0xB4, 0xD9, 0x74, 0xDA, 0xF4, 0xB0, 0xF4, 0x7D, 0x60, 0x21, 0x67, 0x66, 0x3C, 0x66, 0x2A, 0x66, 0x56, 0x66, 0xC1, 0x64, 0x19, 0x67, 0x75, 0x67, 0x63, 0x67, 0xBB, 0x64, 0xCF, 0xFC, 0xA1, 0xFA, 0xF3, 0xFB, 0xCF, 0x56, 0x0E, 0x57, 0x4E, 0x52, 0xCE, 0x65, 0xAE, 0x78, 0x6E, 0x5E, 0xEE, 0x5B, 0x9E, 0x72, 0x5E, 0x55, 0x3E, 0x74, 0xBE, 0x7E, 0x7E, 0x6B, 0xC1, 0x8F, 0x02, 0xCB, 0x82, 0xFE, 0x42, 0x9C, 0x42, 0xE7, 0xC2, 0x89, 0x22, 0x92, 0x22, 0xEF, 0xA2, 0xF9, 0xBF, 0xD4, 0x7F, 0x83, 0x80, 0x96, 0xCE, 0x58, 0x1C, 0x0E, 0xAC, 0x61, 0xB6, 0x92, 0xE8, 0x92, 0xFD, 0x52, 0xAE, 0xD2, 0xF8, 0xD2, 0xA3, 0x32, 0x9E, 0xB2, 0xC4, 0xB2, 0x93, 0x72, 0xBE, 0xF2, 0xE4, 0xF2, 0xB3, 0x0A, 0xFE, 0x8A, 0x94, 0x8A, 0xF3, 0x4A, 0x81, 0xCA, 0xD4, 0xCA, 0x8B, 0x2A, 0xA1, 0xAA, 0xB4, 0xAA, 0xCB, 0x6A, 0xE1, 0xEA, 0x8C, 0xEA, 0xEB, 0x1A, 0xD1, 0x9A, 0xAC, 0x9A, 0xDB, 0x5A, 0xF1, 0xDA, 0x3F, 0xB5, 0xF7, 0x75, 0x92, 0xC0, 0xFE, 0x7D, 0x04, 0xB8, 0x9A, 0x5F, 0xFF, 0xDC, 0x20, 0xDB, 0x50, 0xD8, 0xF0, 0xD6, 0xA8, 0xD0, 0x58, 0xDC, 0xF8, 0xD1, 0xA4, 0xD4, 0x54, 0xD6, 0x0C, 0xD2, 0xAC, 0xDA, 0x5C, 0xD9, 0x02, 0xDE, 0xA2, 0xD1, 0x52, 0xD3, 0x0A, 0x05, 0xEC, 0xDE, 0xFA, 0x36, 0xD8, 0x36, 0xAD, 0xB6, 0xD2, 0xB6, 0xA7, 0x76, 0x91, 0xF6, 0xC4, 0xF6, 0x9D, 0x0E, 0xFA, 0x0E, 0xDF, 0x8E, 0x89, 0x4E, 0xEC, 0x4E, 0xF3, 0xCE, 0xA6, 0x2E, 0xC8, 0x2E, 0xA5, 0xAE, 0xBC, 0xAE, 0xAB, 0x6E, 0xDE, 0xEE, 0xA8, 0xEE, 0xB5, 0x1E, 0xCA, 0x1E, 0xF7, 0x9E, 0xA1, 0x5E, 0xB4, 0x5E, 0xE3, 0xDE, 0xFA, 0x3E, 0xB0, 0x3E, 0x85, 0xBE, 0xDC, 0xBE, 0xAB, 0x7E, 0xDE, 0xFE, 0xE8, 0xFE, 0x8D, 0x01, 0x9A, 0x01, 0xAF, 0x81, 0xF1, 0x41, 0x9C, 0x41, 0xCB, 0xC1, 0xB6, 0x21, 0xB8, 0x21, 0xCD, 0xA1, 0xD2, 0xA1, 0x97, 0x61, 0x89, 0xE1, 0x8C, 0xE1, 0xD3, 0x11, 0xAE, 0x91, 0x88, 0x91, 0xB5, 0x51, 0xEA, 0x51, 0xAF, 0xD1, 0x89, 0x31, 0xDC, 0x31, 0x9B, 0xB1, 0xAE, 0x71, 0xC4, 0x71, 0xFD, 0xF1, 0xDA, 0x09, 0xB0, 0x09, 0xA5, 0x89, 0xA2, 0x89, 0xA7, 0x49, 0xF1, 0xC9, 0x8C, 0xC9, 0xF3, 0x29, 0xDE, 0xA9, 0xF8, 0xFF, 0xB9, 0x7D, 0xC3, 0xA6, 0xD7, 0x66, 0xE8, 0x66, 0x02, 0x66, 0xFE, 0xCD, 0x92, 0xCF, 0x7A, 0xCD, 0x4E, 0xCD, 0x11, 0xCD, 0xB9, 0xCE, 0x8D, 0xCD, 0xE3, 0x03, 0xDB, 0x77, 0xF8, 0x1F, 0xCE, 0x3F, 0xFB, 0x7F, 0x03, 0x0B, 0x58, 0x0B, 0xB6, 0x0B, 0x03, 0x8B, 0x58, 0x8B, 0x76, 0x8B, 0x03, 0x4B, 0xD8, 0x4B, 0xF6, 0x4B, 0x43, 0xCB, 0xB8, 0xCB, 0x8E, 0xCB, 0xA3, 0x2B, 0x84, 0x2B, 0xAE, 0x2B, 0x93, 0xAB, 0x24, 0x00, 0x11, 0xE7, 0xD7, 0xA8, 0xD7, 0x02, 0xD7, 0x56, 0xD7, 0x99, 0xD6, 0x23, 0xD6, 0xF7, 0x36, 0xB8, 0x37, 0x92, 0x36, 0x2E, 0x36, 0x45, 0x37, 0x73, 0x36, 0x9F, 0xB7, 0x14, 0xB7, 0xCA, 0x81, 0x1A, 0xAE, 0xB7, 0xDD, 0xBA, 0x83, 0xB2, 0x63, 0xBB, 0x33, 0xB2, 0x4B, 0xBC, 0xEB, 0xBB, 0xBB, 0xB2, 0xC7, 0xBA, 0x17, 0xB6, 0xD7, 0xBD, 0xB7, 0xB5, 0xF7, 0xB5, 0x4F, 0xB0, 0xCF, 0xB7, 0xAF, 0xB7, 0xEF, 0xB7, 0x9F, 0xB3, 0xDF, 0xBD, 0xBF, 0xB5, 0xFF, 0x05, 0x50, 0x90, 0xFF, 0x40, 0xFF, 0xC0, 0xFF, 0x20, 0xF7, 0xA0, 0xE7, 0x60, 0xE7, 0x10, 0xF4, 0xF0, 0xE7, 0xA1, 0xE0, 0xA1, 0xE1, 0x61, 0xE0, 0x61, 0xC1, 0x61, 0xFF, 0xE1, 0xFE, 0x11, 0xC4, 0x11, 0xE9, 0x91, 0xC8, 0x91, 0xE9, 0x51, 0xC8, 0x51, 0xF1, 0xD1, 0xC8, 0xD1, 0xF1, 0x31, 0xEC, 0x31, 0xE5, 0xB1, 0xE4, 0xB1, 0xD5, 0x71, 0xD4, 0x71, 0xC5, 0xF1, 0xE4, 0xF1, 0xE5, 0x09, 0xE2, 0x09, 0xC3, 0x89, 0xC2, 0x89, 0x03, 0xC0, 0xC8, 0xFA, 0x93, 0x7F, 0x27, 0x0F, 0xA7, 0xE8, 0xA7, 0xEC, 0xA7, 0xEA, 0xA7, 0x9E, 0xA7, 0x99, 0xA7, 0x1D, 0xA7, 0x1B, 0xA7, 0x9F, 0x67, 0x04, 0x67, 0x02, 0x67, 0x86, 0x67, 0x41, 0x67, 0x85, 0x67, 0x43, 0x67, 0x47, 0xE7, 0xB0, 0xE7, 0x54, 0xE7, 0x52, 0xE7, 0x36, 0xE7, 0x31, 0xE7, 0x35, 0xE7, 0xB3, 0xE7, 0x77, 0x17, 0xA8, 0x17, 0x6C, 0x17, 0xEA, 0x17, 0x1E, 0x17, 0x99, 0x17, 0x9D, 0x17, 0x9B, 0x97, 0x20, 0x97, 0x44, 0x97, 0xC2, 0xC0, 0x7A, 0x0E, 0xBD, 0x2C, 0xBD, 0x1C, 0xBF, 0xBC, 0xB8, 0x42, 0xBC, 0x62, 0xBC, 0x52, 0xBA, 0x72, 0xB9, 0x4A, 0xBD, 0x6A, 0xBD, 0x5A, 0xBB, 0xFA, 0xB8, 0x26, 0xB8, 0x16, 0xB8, 0x36, 0x06, 0x78, 0x5A, 0x72, 0x3D, 0x76, 0x7D, 0x71, 0x83, 0x78, 0xC3, 0x78, 0xA3, 0x7C, 0xE3, 0x7A, 0x93, 0x76, 0xD3, 0x7E, 0xB3, 0x71, 0x0B, 0x72, 0x4B, 0x74, 0x2B, 0x72, 0x6B, 0x76, 0x1B, 0x71, 0x5B, 0x71, 0x3B, 0x7D, 0x7B, 0x7B, 0x87, 0x7A, 0xC7, 0x7E, 0xA7, 0x79, 0xE7, 0x73, 0x97, 0x73, 0xD7, 0x77, 0x77, 0x70, 0x0F, 0x73, 0x4F, 0x7D, 0x2F, 0x71, 0x6F, 0x74, 0xEF, 0x73, 0x9F, 0x78, 0x5F, 0x76, 0xDF, 0x7B, 0xBF, 0x74, 0x7F, 0xF9, 0x00, 0xF9, 0x80, 0xFB, 0xC0, 0xF4, 0x20, 0x01, 0x2C, 0x6E, 0xB7, 0x87, 0x98, 0x87, 0xC2, 0x87, 0xF6, 0x87, 0xB9, 0x87, 0x13, 0xA0, 0xC1, 0x63, 0x3C, 0xD2, 0x3D, 0x0A, 0x3F, 0x6A, 0x3D, 0x3A, 0x3E, 0x86, 0x3F, 0xE6, 0x3E, 0x36, 0x3F, 0x4E, 0x3D, 0x1E, 0x3C, 0xBE, 0x3F, 0xA1, 0x3C, 0x51, 0x3D, 0x09, 0x3C, 0xA9, 0x3F, 0xD9, 0x3D, 0x85, 0x3C, 0x65, 0x3F, 0x35, 0x3C, 0x8D, 0x3F, 0xED, 0x3E, 0xBD, 0x3C, 0x23, 0x3F, 0x53, 0x3C, 0xF3, 0x3D, 0xAB, 0x02, 0xDB, 0x3C, 0xF8, 0x39, 0xF3, 0xB9, 0xFE, 0x79, 0xEC, 0x79, 0xE7, 0xF9, 0xF9, 0x05, 0xE9, 0x85, 0xFC, 0x85, 0xF7, 0x45, 0xE5, 0xC5, 0xE6, 0x25, 0xF8, 0x25, 0xF3, 0xA5, 0xFE, 0x65, 0xEC, 0x65, 0xE7, 0xE5, 0xE5, 0x15, 0xE9, 0x95, 0x1C, 0x28, 0xF7, 0xAA, 0xAF, 0x36, 0xAF, 0xBF, 0x5F, 0xB3, 0x5E, 0x1B, 0x5E, 0xC7, 0x5F, 0xF7, 0x5E, 0x5F, 0xDF, 0x7E, 0xBC, 0x51, 0x02, 0x0B, 0x5E, 0xFD, 0xCD, 0xFE, 0x2D, 0xF4, 0x2D, 0xE7, 0xAD, 0xE9, 0x6D, 0xEA, 0xED, 0xF0, 0xED, 0xE3, 0x1D, 0xED, 0x9D, 0xE6, 0x5D, 0xF8, 0x5D, 0xFB, 0xDD, 0xE9, 0x3D, 0xF2, 0xBD, 0xE0, 0xBD, 0xED, 0x7D, 0xEE, 0xFD, 0xF4, 0x03, 0xF4, 0x03, 0xEB, 0x83, 0xF1, 0x43, 0xE2, 0xC3, 0xE0, 0xC3, 0xFD, 0x23, 0xEE, 0xA3, 0xE4, 0xA3, 0xE7, 0x63, 0xF9, 0xE3, 0xEA, 0x13, 0xFA, 0x93, 0xE0, 0x93, 0xFD, 0x53, 0xEE, 0xD3, 0xEC, 0xD3, 0xEF, 0x33, 0xF5, 0xB3, 0xFA, 0x73, 0xF8, 0x73, 0xEB, 0xF3, 0xE9, 0xEB, 0xFB, 0x17, 0xD9, 0x17, 0xEF, 0x97, 0xDA, 0x97, 0xDD, 0x57, 0xE8, 0x57, 0xCE, 0x57, 0xF3, 0xD7, 0xF4, 0xD7, 0xD1, 0xD7, 0x97, 0x8D, 0xA9, 0x33, 0xD3, 0xFF, 0xBC, 0xFA, 0x81, 0x40, 0x06, 0x01, 0x01, 0x05, 0xF9, 0x8F, 0xEF, 0xBF, 0xF9, 0x87, 0x00, 0xBE, 0xFF, 0x79, 0x5E, 0x13, 0x00, 0xD2, 0x0B, 0x0A, 0x0A, 0x2A, 0x08, 0x1A, 0x08, 0xDA, 0x07, 0x06, 0x06, 0x26, 0x04, 0x16, 0x04, 0xD6, 0x0F, 0x0E, 0x01, 0x2E, 0x0C, 0x1E, 0x0C, 0x3E, 0x08, 0x01, 0x09, 0x21, 0x02, 0x11, 0x02, 0x31, 0x04, 0x09, 0x05, 0x29, 0x06, 0x19, 0x0A, 0x39, 0x0C, 0x05, 0x0D, 0x25, 0x0E, 0x15, 0x06, 0x35, 0x02, 0x0D, 0x0B, 0x2D, 0x01, 0x1D, 0x0E, 0x3D, 0x06, 0x03, 0x07, 0x23, 0x09, 0x13, 0x09, 0x33, 0x0E, 0x0B, 0x0F, 0x2B, 0x0D, 0x1B, 0x05, 0x3B, 0x01, 0x87, 0x00, 0x27, 0x03, 0x17, 0x0D, 0x37, 0x09, 0xFF, 0x1D, 0x5E, 0x16, 0x3E, 0x06, 0x7E, 0x1A, 0x01, 0x11, 0x41, 0x0E, 0x21, 0x0E, 0x61, 0xE6, 0x1B, 0xD2, 0x37, 0x85, 0x6F, 0xF1, 0xDF, 0x66, 0xBF, 0x23, 0x7F, 0x57, 0xFC, 0x9E, 0xF0, 0x7D, 0x0E, 0x11, 0x05, 0x51, 0x09, 0x31, 0x11, 0xF1, 0x1F, 0x12, 0x2A, 0x92, 0x32, 0x52, 0x32, 0xD2, 0x02, 0x32, 0x1A, 0xB2, 0x2A, 0x72, 0x0A, 0xF2, 0xE2, 0x0F, 0xF4, 0x1F, 0x6A, 0x40, 0x2B, 0x58, 0x42, 0xC1, 0x44, 0x51, 0x47, 0x49, 0x43, 0x59, 0x41, 0xC5, 0x42, 0xD5, 0x40, 0xCD, 0x40, 0x5D, 0x45, 0xC3, 0x46, 0xD3, 0x42, 0xCB, 0x44, 0x5B, 0x43, 0xC7, 0x41, 0xD7, 0x46, 0xCF, 0x42, 0x5F, 0xC7, 0xC0, 0xC3, 0xD0, 0xC1, 0xC8, 0xC6, 0xD8, 0xC4, 0xC4, 0xC7, 0xD4, 0xC5, 0xCC, 0xC1, 0xDC, 0xC2, 0x22, 0xC0, 0xD2, 0xC3, 0xCA, 0xC5, 0xDA, 0xC6, 0x26, 0xC4, 0x36, 0xC0, 0xCE, 0xC3, 0xDE, 0xC1, 0x21, 0x02, 0xFC, 0x20, 0x1F, 0x67, 0x0F, 0x97, 0x18, 0xD7, 0x08, 0xB7, 0x10, 0x77, 0x1F, 0x8F, 0x04, 0xCF, 0x18, 0xAF, 0x08, 0xEF, 0x00, 0x9F, 0x14, 0xDF, 0x14, 0xFF, 0x2F, 0xFE, 0x21, 0x01, 0x39, 0xD0, 0x09, 0x8A, 0x09, 0x8E, 0x09, 0x29, 0x08, 0xCD, 0x09, 0x4B, 0x09, 0x4F, 0x7E, 0x52, 0xFE, 0xB4, 0xF8, 0x59, 0xF6, 0xF3, 0x94, 0x88, 0x8A, 0xC8, 0x8A, 0xA8, 0x9C, 0xE8, 0x8C, 0x98, 0x86, 0xD8, 0x9A, 0xB8, 0x82, 0xF8, 0x82, 0x84, 0x16, 0xB0, 0x84, 0x2A, 0x92, 0x4B, 0x52, 0x3A, 0x52, 0x5B, 0xD2, 0x6A, 0xD2, 0x2B, 0x32, 0x7A, 0x32, 0x7B, 0xB2, 0x1A, 0xB2, 0x6B, 0x72, 0x46, 0x72, 0x07, 0xF2, 0x5A, 0xF2, 0x5B, 0x0A, 0x26, 0x0A, 0x47, 0x8A, 0x7A, 0x8A, 0x3B, 0x4A, 0x66, 0x4A, 0x27, 0xCA, 0x06, 0xCA, 0x7B, 0x2A, 0x16, 0x2A, 0x17, 0xAA, 0x46, 0xAA, 0x07, 0x6A, 0x36, 0x6A, 0x57, 0xEA, 0x26, 0xEA, 0x27, 0x1A, 0x76, 0x1A, 0x37, 0x9A, 0x16, 0x9A, 0x67, 0x5A, 0x0E, 0x5A, 0x77, 0xDA, 0x56, 0xDA, 0x17, 0x3A, 0x4E, 0x3A, 0x4F, 0xBA, 0x36, 0xBA, 0x57, 0x7A, 0x6E, 0x7A, 0x2F, 0xFA, 0x76, 0xFA, 0x77, 0x86, 0x5F, 0x0C, 0xDE, 0x0C, 0x1D, 0x0C, 0x1F, 0x8C, 0x3C, 0x8C, 0x3E, 0x8C, 0x5D, 0x8C, 0x9F, 0x4C, 0xBC, 0x4C, 0x7E, 0x4C, 0xDD, 0x4C, 0x5F, 0xCC, 0xFC, 0xCC, 0xFE, 0xCC, 0x3D, 0x2C, 0xA0, 0x2C, 0x02, 0x2C, 0x01, 0x2C, 0xBD, 0xAC, 0x60, 0xAC, 0x82, 0xAC, 0x81, 0xAC, 0xFD, 0x6C, 0xE0, 0x6C, 0x42, 0x6C, 0xC1, 0x6C, 0x03, 0xEC, 0x10, 0xEC, 0x22, 0xEC, 0xBF, 0xD9, 0x07, 0x39, 0xA0, 0x38, 0x44, 0x39, 0x42, 0x38, 0x86, 0x38, 0xA1, 0x39, 0xC5, 0x38, 0x43, 0x81, 0x6E, 0x00, 0xC3, 0x25, 0xCE, 0x15, 0xCE, 0x35, 0xCA, 0x0D, 0xCB, 0x2D, 0xC9, 0x1D, 0x01, 0xF8, 0x03, 0xFC, 0x2F, 0xA9, 0x5F, 0x91, 0xBF, 0xC6, 0x79, 0x10, 0x78, 0xA4, 0x79, 0xA2, 0x78, 0x26, 0x79, 0xBF, 0xF1, 0xCA, 0xF0, 0xC6, 0xF0, 0x4E, 0xF1, 0x7D, 0xE7, 0x93, 0xE3, 0x8B, 0xE5, 0x9B, 0x06, 0xDA, 0x81, 0x3C, 0xD0, 0xFE, 0x67, 0x04, 0x90, 0x05, 0x14, 0x04, 0xE2, 0x05, 0xE6, 0x04, 0x7F, 0x08, 0x2A, 0x0A, 0x26, 0x0A, 0xCE, 0x0B, 0xA1, 0x08, 0x29, 0x0B, 0x25, 0x09, 0xFD, 0x13, 0x46, 0x13, 0x56, 0x11, 0x4E, 0x16, 0x5E, 0x10, 0x41, 0x17, 0x51, 0x15, 0x49, 0x11, 0x59, 0x12, 0xC5, 0x10, 0x55, 0x13, 0x4D, 0x13, 0x5D, 0x16, 0xC3, 0x14, 0xD3, 0x10, 0x4B, 0x17, 0x5B, 0x11, 0xC7, 0x12, 0xD7, 0x14, 0xCF, 0x00, 0xCA, 0x3F, 0x8E, 0x84, 0x96, 0x44, 0xA6, 0xC4, 0xBA, 0x24, 0xAE, 0xA4, 0xB6, 0x64, 0xB6, 0xE4, 0x86, 0x14, 0x9E, 0x94, 0xAE, 0xD4, 0x1F, 0xA9, 0x4D, 0x69, 0x7C, 0x69, 0x3D, 0xE9, 0x1C, 0xE9, 0x2D, 0x19, 0x42, 0x19, 0x7D, 0x99, 0x5C, 0x99, 0x1D, 0xD9, 0x9F, 0xB2, 0x06, 0xB2, 0xF9, 0xB2, 0xBB, 0x72, 0x44, 0x72, 0x46, 0x72, 0x05, 0x72, 0x7B, 0xF2, 0xC4, 0xF2, 0xC6, 0xF2, 0x85, 0xF2, 0xFB, 0x0A, 0xA4, 0x0A, 0x26, 0x0A, 0x45, 0x0A, 0x87, 0x8A, 0x64, 0x8A, 0xA6, 0x8A, 0xC5, 0x8A, 0x47, 0x4A, 0xE4, 0x4A, 0xE6, 0x4A, 0x25, 0x4A, 0xC7, 0xCA, 0x14, 0xCA, 0x16, 0x40, 0xF7, 0x3F, 0x51, 0xA1, 0x52, 0xB1, 0x54, 0x29, 0x53, 0x39, 0x53, 0xA5, 0x56, 0xB5, 0x52, 0xAD, 0x50, 0x3D, 0x57, 0xA3, 0x51, 0xB3, 0x51, 0xAB, 0x54, 0xBB, 0x50, 0xA7, 0x55, 0xB7, 0x55, 0xAF, 0x02, 0x3A, 0x02, 0xBD, 0x86, 0x9D, 0x46, 0xB5, 0xC6, 0xB5, 0x26, 0x83, 0xA6, 0xBD, 0x66, 0xAD, 0xE6, 0x8D, 0x16, 0xA3, 0x96, 0xA3, 0x56, 0x9D, 0xD6, 0xAD, 0x36, 0x93, 0xB6, 0x93, 0x76, 0xBD, 0xF6, 0x9D, 0x0E, 0x8B, 0x8E, 0xB3, 0x4E, 0x83, 0xCE, 0x83, 0x2E, 0xAB, 0xAE, 0x8B, 0x6E, 0x13, 0xD0, 0xFC, 0xD9, 0xF4, 0x5C, 0xF5, 0x9A, 0xF5, 0x9E, 0x00, 0xCF, 0x70, 0xD7, 0x6F, 0xD1, 0x7F, 0x36, 0xE0, 0x34, 0xF0, 0x30, 0x68, 0x35, 0x78, 0x35, 0xE4, 0x32, 0xF4, 0x34, 0x6C, 0x37, 0x7C, 0x33, 0xE2, 0x36, 0xF2, 0x32, 0xEA, 0x30, 0x7A, 0x37, 0xFE, 0x65, 0xEC, 0x63, 0xDC, 0x69, 0xFC, 0x61, 0xC2, 0x6B, 0xE2, 0x6B, 0xD2, 0x65, 0xF2, 0x65, 0xCA, 0x67, 0xEA, 0x67, 0xDA, 0x63, 0x06, 0x62, 0xC6, 0x6F, 0xE6, 0x6F, 0xD6, 0x6B, 0x0E, 0x6A, 0x2E, 0x00, 0xF8, 0x46, 0x9F, 0x05, 0x98, 0x85, 0x90, 0x45, 0x90, 0x45, 0xBF, 0x25, 0x84, 0xA5, 0xB0, 0x65, 0xB0, 0xE5, 0xA0, 0x15, 0xA4, 0x95, 0x88, 0xD5, 0x6F, 0xAB, 0x21, 0x6B, 0x28, 0x6B, 0x51, 0xEB, 0x50, 0xEB, 0x61, 0x1B, 0x68, 0x1B, 0x71, 0x9B, 0x30, 0x9B, 0x11, 0x5B, 0x58, 0x5B, 0x09, 0xDB, 0x70, 0xDB, 0x31, 0x3B, 0x38, 0x3B, 0x49, 0xBB, 0x08, 0xC0, 0x3C, 0xE0, 0xED, 0xA5, 0xEC, 0xA3, 0xEC, 0x27, 0x1C, 0x10, 0x00, 0xF7, 0x88, 0x76, 0x98, 0x74, 0xFC, 0xEE, 0x28, 0xEB, 0x18, 0xE3, 0x38, 0xED, 0x84, 0xE8, 0x24, 0xE7, 0x14, 0xEB, 0x34, 0xE3, 0x8C, 0xE4, 0x2C, 0xEF, 0x1C, 0xEF, 0x3C, 0xEB, 0x82, 0xEC, 0xA2, 0xE8, 0x92, 0xE0, 0x32, 0xE7, 0x8A, 0xE2, 0xAA, 0xE4, 0x9A, 0xE8, 0x3A, 0xEF, 0x86, 0xEA, 0xA6, 0xEC, 0x96, 0xE4, 0xB6, 0xE0, 0x8E, 0xE6, 0xAE, 0xE2, 0x9E, 0xE2, 0xBE, 0x08, 0x58, 0x88, 0x9A, 0x47, 0xAA, 0xC7, 0x92, 0x27, 0xA6, 0xA7, 0xBA, 0x67, 0x9A, 0xE7, 0xB2, 0x17, 0x96, 0x97, 0x06, 0x50, 0xF8, 0x57, 0xBD, 0xB1, 0xBD, 0x35, 0xBD, 0x33, 0xBD, 0xD7, 0x7C, 0x70, 0x7C, 0xB4, 0x7D, 0xB2, 0x7C, 0xD6, 0x7D, 0xF1, 0x7C, 0x75, 0x7C, 0xB3, 0x7D, 0x37, 0xFC, 0xF0, 0xFD, 0x74, 0xFD, 0xFE, 0xF8, 0x6D, 0xF9, 0x13, 0xF8, 0xEB, 0xF9, 0xE7, 0xFA, 0x6F, 0x07, 0x10, 0x06, 0x18, 0x04, 0xE4, 0x05, 0xEC, 0x04, 0x12, 0x05, 0x1A, 0x06, 0xE6, 0x07, 0xEE, 0x06, 0x11, 0x07, 0x19, 0x05, 0x15, 0x04, 0xED, 0x07, 0x93, 0x04, 0x1B, 0x07, 0x17, 0x01, 0x4E, 0x42, 0xFA, 0xDB, 0xF4, 0xF7, 0xDF, 0xDF, 0x87, 0x21, 0xE4, 0x21, 0x66, 0x80, 0x95, 0x1C, 0x85, 0x52, 0x84, 0x9A, 0x87, 0x96, 0x84, 0x9E, 0x84, 0x51, 0x86, 0x59, 0x84, 0x95, 0x85, 0x9D, 0x86, 0x53, 0x85, 0x5B, 0x85, 0x97, 0x87, 0x9F, 0x45, 0xD0, 0x44, 0x58, 0x47, 0x54, 0x44, 0x9C, 0x47, 0xD2, 0x46, 0xDA, 0x44, 0x56, 0x46, 0x5E, 0x02, 0x75, 0xDF, 0x36, 0xAA, 0x3A, 0xEA, 0x2A, 0x9A, 0x3E, 0xDA, 0x3E, 0xBA, 0x26, 0xFA, 0x3A, 0x86, 0x21, 0xC6, 0x21, 0xA6, 0x36, 0xE6, 0x26, 0x96, 0x29, 0xD6, 0x31, 0xB6, 0x2E, 0xF6, 0x2E, 0x8E, 0x39, 0xCE, 0x29, 0xAE, 0x21, 0xEE, 0x3E, 0x9E, 0x25, 0xDE, 0x25, 0xBE, 0x31, 0xFE, 0x21, 0x81, 0x35, 0xC1, 0x35, 0xA1, 0x29, 0xE1, 0x31, 0x91, 0x3D, 0xD1, 0x2D, 0xB1, 0x39, 0xF1, 0x39, 0x89, 0x23, 0xC9, 0x3D, 0xA9, 0x35, 0xE9, 0x05, 0xF0, 0x15, 0xCF, 0xE4, 0xB6, 0xE4, 0xD7, 0x14, 0xAE, 0x14, 0xAF, 0x94, 0xF6, 0x94, 0xB7, 0xD4, 0x5F, 0xA9, 0xDE, 0xA9, 0x1D, 0xA9, 0x1F, 0x69, 0x3C, 0x69, 0x3E, 0x69, 0x5D, 0x69, 0x9F, 0xE9, 0xBC, 0xE9, 0x7E, 0xE9, 0xDD, 0xE9, 0x5F, 0x19, 0x7C, 0x19, 0xFE, 0x19, 0x3D, 0x99, 0x20, 0x99, 0x02, 0x99, 0x01, 0x99, 0xBD, 0x59, 0x60, 0x59, 0x82, 0x59, 0x81, 0x59, 0xFD, 0xD9, 0xE0, 0xD9, 0x42, 0xD9, 0xC1, 0xD9, 0x03, 0x7F, 0x20, 0xFE, 0x08, 0x03, 0x16, 0x33, 0x98, 0x03, 0x99, 0x23, 0x9A, 0x13, 0x92, 0x33, 0x94, 0x0B, 0x9D, 0x2B, 0x96, 0x1B, 0x9A, 0x3B, 0x92, 0x07, 0x93, 0x27, 0x9E, 0x17, 0x0E, 0x74, 0x04, 0xD8, 0x7C, 0x89, 0xFC, 0x88, 0xFC, 0xB1, 0x02, 0xB8, 0x02, 0xA9, 0x82, 0xC8, 0x82, 0xF1, 0x42, 0x84, 0x42, 0xE9, 0xC2, 0xA8, 0xC2, 0xC9, 0xA2, 0x6F, 0x45, 0x32, 0x45, 0xD1, 0x45, 0x53, 0x40, 0x47, 0x90, 0xFD, 0x1B, 0xFB, 0x77, 0xBA, 0x18, 0xB1, 0x58, 0xBE, 0x38, 0xAE, 0x78, 0xA6, 0x04, 0xB9, 0x44, 0xA1, 0x24, 0xBE, 0x64, 0xAE, 0xF4, 0x47, 0xA9, 0x62, 0x69, 0x42, 0xE9, 0x7C, 0x19, 0x4A, 0x99, 0x52, 0x59, 0x52, 0xD9, 0xBF, 0x72, 0xD4, 0x72, 0x15, 0xC0, 0x70, 0x16, 0x2A, 0xD0, 0x2B, 0x54, 0x01, 0xC7, 0x59, 0xAA, 0xC4, 0xA8, 0x54, 0x03, 0x2C, 0x67, 0xB9, 0x0A, 0xB3, 0x4A, 0xBD, 0x2A, 0xBD, 0x6A, 0xA5, 0x1A, 0xAB, 0x5A, 0x13, 0x30, 0x9D, 0xD5, 0x1A, 0x9C, 0x1A, 0xAD, 0x9A, 0xCC, 0x9A, 0xF5, 0x5A, 0xDC, 0x5A, 0xED, 0xDA, 0xAC, 0xDA, 0x8D, 0x3A, 0xBC, 0x3A, 0x9D, 0xBA, 0x3F, 0x75, 0x9B, 0xF5, 0xF8, 0xF5, 0x7A, 0xF5, 0x39, 0xF5, 0x5B, 0x0D, 0x84, 0x0D, 0xFA, 0x0D, 0xB9, 0x0D, 0x3B, 0x8D, 0x3F, 0x1B, 0x0D, 0x1A, 0xF3, 0x1A, 0x77, 0x9B, 0x88, 0x9A, 0x0C, 0x81, 0x92, 0xB0, 0xD7, 0x4C, 0xDC, 0x6C, 0xDC, 0x5C, 0xD8, 0xBC, 0xDF, 0x42, 0xDA, 0x62, 0xD2, 0x52, 0xD4, 0x72, 0xD8, 0x4A, 0xD6, 0x6A, 0xDA, 0xFA, 0xB7, 0xF5, 0xA8, 0x8D, 0xBC, 0xCD, 0xAC, 0xAD, 0xA4, 0xED, 0xB8, 0x9D, 0xA2, 0xDD, 0xA2, 0xBD, 0x14, 0x28, 0xFF, 0x54, 0x1D, 0x96, 0x1D, 0x65, 0x1D, 0xA7, 0x9D, 0xD4, 0x9D, 0x56, 0x9D, 0xE5, 0x9D, 0xE7, 0x5D, 0x34, 0x5D, 0xD6, 0x5D, 0x95, 0x5D, 0x17, 0xDD, 0xB4, 0xDD, 0xB6, 0xDD, 0x55, 0xDD, 0x97, 0x3D, 0xF4, 0x3D, 0x76, 0x3D, 0xD5, 0x3D, 0x57, 0xBD, 0x0C, 0xBD, 0xF6, 0xBD, 0x35, 0xBD, 0x37, 0x7D, 0x8C, 0x7D, 0x0E, 0x7D, 0x75, 0x7D, 0xB7, 0xFD, 0x4C, 0xFD, 0x4E, 0xFD, 0xF5, 0xFD, 0x77, 0x40, 0x4D, 0x70, 0x1E, 0x68, 0x18, 0xB8, 0x1F, 0x64, 0x1D, 0x74, 0x19, 0x6C, 0x1C, 0x7C, 0x1C, 0x62, 0x1B, 0x72, 0x1D, 0x6A, 0x1E, 0x7A, 0x1A, 0x66, 0x1F, 0x76, 0x1F, 0x6E, 0x19, 0x7E, 0x1E, 0xE1, 0x1C, 0xF1, 0x18, 0x69, 0x1D, 0x79, 0x19, 0xE5, 0x1A, 0xF5, 0x1C, 0x6D, 0x1B, 0x7D, 0x1B, 0xE3, 0x1E, 0xF3, 0x1A, 0xEB, 0x18, 0x7B, 0x1F, 0xFF, 0x35, 0xEE, 0x33, 0xDE, 0x39, 0xFE, 0x31, 0xC1, 0x3B, 0xE1, 0x3B, 0xD1, 0x35, 0xF1, 0x39, 0xC9, 0x37, 0xE9, 0x37, 0xD9, 0x3D, 0x05, 0x32, 0xC5, 0x3F, 0xE5, 0x3F, 0xD5, 0x3B, 0x0D, 0x3A, 0x2D, 0x30, 0x1D, 0x38, 0xDD, 0x37, 0x03, 0x36, 0x23, 0x34, 0x13, 0x34, 0xD3, 0x3F, 0x0B, 0x3E, 0x2B, 0x3C, 0x1B, 0x3C, 0x3B, 0x30, 0x07, 0x39, 0x27, 0x32, 0xF7, 0x7B, 0x6E, 0x68, 0x1E, 0x6A, 0x5E, 0x74, 0x3E, 0x14, 0xF0, 0x24, 0xE8, 0x7F, 0x62, 0xFF, 0xC2, 0xFE, 0x8D, 0x2C, 0xC0, 0x2C, 0x48, 0x2C, 0x84, 0x2F, 0x8C, 0x2E, 0xC2, 0x2D, 0x4A, 0x2E, 0x46, 0x2C, 0x8E, 0x2F, 0xC1, 0x2F, 0x49, 0x2D, 0x45, 0x2D, 0x4D, 0x2C, 0x23, 0x2C, 0x4B, 0x2F, 0x47, 0x2F, 0x4F, 0xAE, 0x7C, 0x5B, 0x91, 0x5D, 0x89, 0x59, 0x99, 0x5A, 0x45, 0x5C, 0x95, 0x5B, 0x8D, 0x5D, 0x9D, 0x59, 0x43, 0x5A, 0x93, 0x5F, 0x8B, 0x5F, 0x9B, 0x5D, 0x47, 0x5E, 0x57, 0x58, 0x4F, 0x58, 0x9F, 0xDB, 0xF8, 0xB1, 0xA1, 0xB4, 0x91, 0xB8, 0x31, 0xBF, 0x89, 0xBA, 0xA9, 0xBC, 0x99, 0xB4, 0xB9, 0xB0, 0x85, 0xB6, 0xA5, 0xB2, 0x95, 0xB2, 0xB5, 0xB8, 0x8D, 0xBE, 0xAD, 0xBA, 0x9D, 0xBA, 0xBD, 0xB4, 0x83, 0xB1, 0xA3, 0xBE, 0x93, 0xB6, 0xB3, 0xBC, 0x8B, 0xB5, 0xAB, 0xB1, 0x9B, 0xBE, 0xBB, 0xBA, 0x87, 0xBD, 0xA7, 0xB9, 0x97, 0xB9, 0xB7, 0xB6, 0x8F, 0xB3, 0xAF, 0xB5, 0x9F, 0xB5, 0xBF, 0x7E, 0x80, 0x7B, 0xA0, 0x73, 0x90, 0x7D, 0xB0, 0x71, 0x88, 0x7F, 0xA8, 0x7B, 0xF8, 0xE7, 0x70, 0x0B, 0x28, 0x08, 0x7A, 0x47, 0xB9, 0x47, 0xDB, 0xC7, 0x84, 0xC7, 0xFA, 0xC7, 0x79, 0xC7, 0x3B, 0x27, 0x3F, 0x4F, 0x0C, 0x4F, 0xF2, 0x4F, 0x76, 0x4F, 0x89, 0x4F, 0x8D, 0x4E, 0x0B, 0x4E, 0xF7, 0xCF, 0x48, 0xCE, 0x8C, 0x01, 0x17, 0x3A, 0x38, 0x27, 0x3D, 0x37, 0x39, 0xFF, 0x7B, 0x7E, 0x78, 0x41, 0x76, 0x61, 0x76, 0x51, 0x7C, 0x71, 0x74, 0x49, 0x71, 0x69, 0x7E, 0x59, 0x72, 0x79, 0x72, 0x45, 0x79, 0x65, 0x71, 0x55, 0x7A, 0x75, 0x7A, 0x4D, 0x75, 0x6D, 0x79, 0x5D, 0x7E, 0x7D, 0x76, 0x43, 0x0D, 0x74, 0x83, 0x8A, 0x9B, 0xF3, 0x5B, 0xDA, 0x5B, 0x9B, 0xDB, 0xCA, 0xDB, 0xCB, 0x3B, 0xBA, 0x3B, 0x5B, 0xA0, 0x1A, 0x5C, 0xDD, 0xD3, 0xDF, 0xDB, 0xDD, 0xD7, 0xDC, 0x5F, 0x3F, 0x30, 0x3C, 0x38, 0x3C, 0xD4, 0x3E, 0xDC, 0x3C, 0x32, 0x01, 0xBE, 0x52, 0xF7, 0x78, 0xF7, 0xC4, 0xFC, 0xE4, 0xF4, 0x54, 0xFF, 0x74, 0xFF, 0xCC, 0xF2, 0xEC, 0xFC, 0xDC, 0xF8, 0xFC, 0xF0, 0xC2, 0xFA, 0xE2, 0xFA, 0xD2, 0xF4, 0xF2, 0xF8, 0xCA, 0xFE, 0xEA, 0xF6, 0xDA, 0xFC, 0xFA, 0xFC, 0xC6, 0xF1, 0xE6, 0xFE, 0xD6, 0xF2, 0xF6, 0xF2, 0xCE, 0xF9, 0xEE, 0x01, 0x78, 0xC5, 0xEB, 0x07, 0xD7, 0x87, 0xD7, 0x47, 0xFB, 0xC7, 0xDB, 0xE7, 0xAF, 0x4F, 0xEF, 0xCF, 0x8E, 0xCF, 0x8F, 0x2F, 0x9E, 0x2F, 0x9F, 0xAF, 0xCE, 0xAF, 0xCF, 0xAF, 0xFF, 0xFD, 0x00, 0xFE, 0xF3, 0x81, 0xF8, 0x81, 0x74, 0x83, 0x7C, 0x81, 0xF2, 0x81, 0xFA, 0x81, 0x76, 0xFF, 0x0F, 0x16, 0xED, 0x01, 0xC1, 0x91, 0x34, 0x0C, 0xC0, 0x70, 0xC7, 0x29, 0xAB, 0x6D, 0xDB, 0x76, 0x97, 0x5D, 0xD1, 0x89, 0x3A, 0x36, 0x4F, 0x14, 0xDB, 0x27, 0xDA, 0x7F, 0x67, 0xE6, 0x14, 0x1F, 0x9E, 0xD7, 0xBE, 0x60, 0x67, 0x41, 0x2B, 0x58, 0x75, 0x2C, 0x38, 0x58, 0xC7, 0xAF, 0xA3, 0x0A, 0x76, 0x04, 0xD6, 0xF9, 0xEB, 0xAC, 0xBA, 0x16, 0x5C, 0xAC, 0xEB, 0xD7, 0x55, 0x75, 0xDB, 0xDC, 0x9C, 0x3B, 0xEC, 0xAE, 0x79, 0x6C, 0x1E, 0xCE, 0x13, 0xF6, 0xD4, 0xBC, 0x36, 0x2F, 0xE7, 0x0D, 0x7B, 0x6B, 0x90, 0x0D, 0xE2, 0xA0, 0x30, 0x54, 0x83, 0xED, 0x30, 0x0F, 0x47, 0xE0, 0x3A, 0x62, 0x47, 0x78, 0x24, 0x82, 0xD4, 0x51, 0x3B, 0xCA, 0xA3, 0x11, 0xB4, 0x8E, 0xD9, 0x31, 0x1E, 0x8B, 0x60, 0x75, 0xDC, 0x81, 0x0B, 0x78, 0x14, 0x6F, 0x10, 0x0E, 0x42, 0x20, 0xA2, 0x44, 0x83, 0x74, 0x90, 0x02, 0x19, 0x25, 0x1B, 0x94, 0x83, 0x12, 0xA8, 0x28, 0xD5, 0xA0, 0x9D, 0xB4, 0x48, 0xC7, 0xE8, 0x26, 0xE3, 0x64, 0x44, 0x26, 0xC6, 0x34, 0x17, 0x9D, 0xC0, 0x0A, 0x62, 0x8B, 0x4D, 0x50, 0xFC, 0x89, 0x4B, 0xB1, 0xA5, 0xE6, 0xB2, 0x0B, 0xFC, 0x08, 0xE2, 0xCB, 0xAD, 0x15, 0xD7, 0x8A, 0xB4, 0x12, 0x5F, 0x69, 0xAD, 0xBA, 0x56, 0xA5, 0xD5, 0xF8, 0x6A, 0x6B, 0xCD, 0xB5, 0x26, 0xAD, 0xC5, 0xD7, 0x5A, 0x40, 0x0A, 0xE4, 0xF5, 0xC4, 0x7A, 0x7B, 0xC3, 0xBD, 0x21, 0x6F, 0x24, 0x36, 0xDA, 0x9B, 0xEE, 0x4D, 0x79, 0x33, 0xB1, 0xD9, 0xDE, 0x72, 0x6F, 0xC9, 0x5B, 0x89, 0xAD, 0xF6, 0xB6, 0x67, 0x5B, 0xD9, 0x4E, 0x6E, 0x77, 0x76, 0x3C, 0x3B, 0xCA, 0x4E, 0x72, 0xA7, 0xB3, 0xEB, 0xD9, 0x55, 0x76, 0x93, 0xBB, 0x1D, 0x20, 0x05, 0xCA, 0x5E, 0x72, 0xAF, 0xB3, 0xEF, 0xDD, 0x57, 0xF7, 0x53, 0xFB, 0xDD, 0x03, 0xEF, 0x81, 0x7A, 0x90, 0x3A, 0xE8, 0x1E, 0x7A, 0x0F, 0xD5, 0xC3, 0xD4, 0x61, 0xF7, 0xC8, 0x7B, 0xA4, 0x1E, 0xA5, 0x8E, 0xBA, 0xC7, 0xD0, 0xB1, 0x76, 0x9C, 0x3E, 0xEE, 0x9D, 0x40, 0x27, 0x1A, 0xD0, 0x82, 0xDE, 0x29, 0x74, 0xAA, 0x9D, 0xA6, 0xC1, 0xAF, 0x00, 0x3A, 0xD3, 0xCE, 0xD2, 0x67, 0xBD, 0x73, 0xF8, 0x5C, 0x07, 0x05, 0x40, 0xFF, 0x02, 0xBE, 0xD0, 0x2F, 0x32, 0x17, 0xFD, 0x4B, 0xF8, 0x52, 0xBF, 0xCC, 0x5C, 0xF6, 0xAF, 0xE0, 0x2B, 0xFD, 0x2A, 0x73, 0xD5, 0xBF, 0x46, 0xAE, 0x8D, 0xEB, 0xEC, 0xF5, 0xE0, 0x06, 0xB9, 0x31, 0x6E, 0xB2, 0x37, 0x83, 0x5B, 0xE4, 0xD6, 0xB8, 0xCD, 0x02, 0x33, 0x40, 0xEE, 0x8C, 0xBB, 0xEC, 0xDD, 0xE0, 0x1E, 0xBD, 0x37, 0xEF, 0x73, 0xF7, 0xC3, 0x07, 0x14, 0xFC, 0x0D, 0x72, 0x0F, 0xC3, 0x47, 0xF4, 0xD1, 0x7C, 0xCC, 0x3D, 0x0E, 0x9F, 0xD0, 0x27, 0xF3, 0x29, 0xF7, 0x34, 0x7C, 0xC6, 0x9E, 0xAD, 0xE7, 0xFC, 0xF3, 0xE8, 0x05, 0x7B, 0xB1, 0x5E, 0xF2, 0x2F, 0xA3, 0x57, 0x0C, 0xF8, 0x7F, 0xFE, 0x75, 0xF4, 0x86, 0xBD, 0x59, 0x6F, 0xF9, 0xB7, 0x11, 0x90, 0x03, 0xDF, 0x7B, 0xE1, 0x7D, 0xFC, 0x81, 0x7F, 0xF8, 0x3E, 0x0A, 0x1F, 0xE3, 0x4F, 0xFC, 0xD3, 0xF7, 0x59, 0xF8, 0x1C, 0x03, 0x3B, 0xF0, 0x7D, 0x15, 0xBE, 0xC6, 0xDF, 0xC4, 0xB7, 0xFF, 0xBB, 0xF8, 0x3D, 0xF9, 0x21, 0xFE, 0x6D, 0x00, 0x04, 0xEB, 0x67, 0x8B, 0xEC, 0x84, 0x23, 0x38, 0x3F, 0x57, 0xE4, 0x26, 0x3C, 0xC9, 0x07, 0xF8, 0x12, 0x3F, 0x15, 0x48, 0x21, 0x20, 0x94, 0x84, 0xA9, 0x48, 0x8A, 0x01, 0xB1, 0x24, 0x4E, 0x25, 0x52, 0x0A, 0x48, 0x25, 0x69, 0x2A, 0x53, 0x72, 0x50, 0x2E, 0xCB, 0x33, 0x85, 0x52, 0x82, 0x4A, 0x59, 0x99, 0xA9, 0x94, 0x1A, 0x54, 0xCB, 0xEA, 0x4C, 0xA3, 0xB4, 0xA0, 0x56, 0xD6, 0x66, 0x3A, 0x0D, 0xEC, 0xBF, 0xA2, 0xCF, 0x0D, 0xDA, 0x08, 0x19, 0x15, 0x63, 0x6E, 0xD2, 0x66, 0x08, 0x18, 0xC2, 0xDC, 0xA2, 0xAD, 0x90, 0x55, 0xB1, 0xE6, 0xFF, 0xB1, 0x64, 0x0E, 0x06, 0x8C, 0x44, 0x01, 0x14, 0x2C, 0x22, 0x76, 0x52, 0x50, 0xB8, 0xFC, 0x5A, 0xC4, 0xB6, 0xED, 0x06, 0x62, 0xE7, 0x6A, 0x8A, 0x9D, 0x4E, 0xCE, 0x55, 0xBC, 0x37, 0x33, 0x0E, 0x85, 0x83, 0x72, 0x8C, 0x1C, 0x07, 0xA7, 0xC2, 0x49, 0x39, 0x47, 0xCE, 0x83, 0x4B, 0xE1, 0xA2, 0x5C, 0x23, 0xD7, 0xC1, 0xAD, 0x70, 0x53, 0xEE, 0x91, 0xFB, 0xE0, 0x51, 0x7A, 0x68, 0xCF, 0xD8, 0x73, 0xA4, 0x94, 0x14, 0x4D, 0x8D, 0xA9, 0x23, 0xAD, 0xA4, 0x69, 0x7A, 0x4C, 0x1F, 0x19, 0x25, 0x43, 0x33, 0x63, 0xE6, 0xC8, 0xAA, 0x58, 0x86, 0x9D, 0xB0, 0x27, 0x4E, 0xC5, 0x31, 0xDC, 0x84, 0x3B, 0xF1, 0x2A, 0x9E, 0xE1, 0x27, 0xFC, 0x09, 0xA8, 0x00, 0x03, 0x26, 0xE0, 0x04, 0xD5, 0x90, 0x85, 0x53, 0x78, 0x46, 0x6A, 0xC4, 0xA2, 0x29, 0x3A, 0x63, 0x35, 0x66, 0xF1, 0x14, 0x9F, 0x89, 0x9A, 0xB0, 0x64, 0x4A, 0xCE, 0x82, 0x46, 0xE0, 0x84, 0x99, 0x70, 0x11, 0x35, 0x22, 0x27, 0xCE, 0xC4, 0x8B, 0xA4, 0x91, 0x38, 0x69, 0x26, 0x5D, 0x64, 0x8D, 0xCC, 0xC9, 0x33, 0xF9, 0xE2, 0xD5, 0x7A, 0x79, 0xEF, 0xDC, 0x7B, 0xF5, 0x69, 0x7D, 0xBC, 0x6F, 0xEE, 0xBB, 0xFA, 0xB5, 0x7E, 0xDE, 0x3F, 0xF7, 0x5F, 0x03, 0xDA, 0x00, 0x1F, 0x98, 0x07, 0xAE, 0x41, 0x5D, 0x10, 0x04, 0x17, 0xC1, 0x5B, 0x48, 0x17, 0x02, 0xA1, 0x45, 0xE8, 0x16, 0xD6, 0x85, 0x41, 0x78, 0x11, 0xBE, 0x45, 0x74, 0x11, 0x10, 0x59, 0x44, 0x6E, 0x51, 0x7D, 0x14, 0x46, 0x97, 0xD1, 0x7B, 0x4C, 0x1F, 0x83, 0xB1, 0x65, 0xEC, 0x1E, 0xD7, 0xC7, 0x61, 0x7C, 0x19, 0xBF, 0x27, 0xF4, 0x09, 0x98, 0x58, 0x26, 0xEE, 0x49, 0x43, 0x12, 0x25, 0x57, 0xC9, 0x47, 0xCA, 0x90, 0x42, 0xA9, 0x55, 0xEA, 0x91, 0x36, 0xA4, 0x51, 0x7A, 0x95, 0x7E, 0x64, 0x0C, 0x19, 0x94, 0x59, 0x65, 0x1E, 0x59, 0x63, 0x16, 0x67, 0xD7, 0xD9, 0x67, 0xCE, 0x98, 0xC3, 0xB9, 0x75, 0xEE, 0x99, 0x37, 0xE6, 0x71, 0x7E, 0x9D, 0x7F, 0x16, 0x8C, 0x05, 0x5C, 0x58, 0x17, 0x9E, 0x45, 0x53, 0x91, 0x14, 0x37, 0xC5, 0x57, 0xC9, 0x54, 0x22, 0xA5, 0x4D, 0xE9, 0x55, 0x36, 0x95, 0x49, 0x79, 0x53, 0x7E, 0x55, 0x4C, 0x15, 0x52, 0xD9, 0x54, 0x5E, 0x55, 0x73, 0x55, 0xA8, 0x6E, 0xAB, 0xEF, 0x9A, 0xB9, 0x26, 0xD4, 0xB6, 0xB5, 0x77, 0xDD, 0x5C, 0x17, 0xEA, 0xDB, 0xDF, 0x3D, 0xC1, 0xDC, 0x10, 0x1A, 0xDB, 0xC6, 0xBB, 0x69, 0x69, 0x8A, 0xCD, 0x5D, 0xF3, 0xD3, 0xB2, 0xB4, 0xC4, 0xD6, 0xEE, 0xFF, 0x07, 0xD8, 0xB5, 0x3F, 0x1D, 0x4B, 0x47, 0xEC, 0xEC, 0x3A, 0x9F, 0xAE, 0xB5, 0x2B, 0x75, 0xF7, 0xDD, 0x6F, 0xCF, 0xDA, 0x93, 0x7A, 0xFB, 0xDE, 0xB7, 0x6F, 0xED, 0x4B, 0xFD, 0x7D, 0xFF, 0x3B, 0xB0, 0x0E, 0xA4, 0xC1, 0x7E, 0xF0, 0x1D, 0xDA, 0x86, 0xF2, 0xF0, 0xC7, 0xF0, 0x17, 0x4F, 0xE6, 0x60, 0xF6, 0x48, 0x00, 0x40, 0xC1, 0x56, 0xFE, 0xD8, 0x68, 0x29, 0x36, 0xAA, 0x88, 0x6D, 0x27, 0x6B, 0xC7, 0x36, 0x0B, 0x89, 0x8D, 0x12, 0x6E, 0x3F, 0x5D, 0x15, 0xEF, 0xCD, 0xCC, 0xDE, 0xCB, 0xF1, 0x6A, 0xBC, 0x80, 0x77, 0xEF, 0xE3, 0xF8, 0x34, 0x3E, 0xC0, 0xB7, 0xF7, 0x73, 0xFC, 0x1A, 0x3F, 0xE0, 0xDF, 0x07, 0xB8, 0x01, 0x6D, 0x00, 0x0C, 0x1C, 0x82, 0x5C, 0xB6, 0x27, 0x80, 0xC1, 0x43, 0x88, 0x1B, 0xD2, 0x86, 0xC0, 0xD0, 0x21, 0xCC, 0x0D, 0x6B, 0xC3, 0x60, 0xF8, 0x10, 0xE1, 0x45, 0x74, 0x11, 0x28, 0x72, 0x8C, 0xF2, 0xA2, 0xBA, 0x28, 0x14, 0x3D, 0xC6, 0x78, 0x31, 0x5D, 0x0C, 0x8A, 0x1D, 0xE3, 0xBC, 0xB8, 0x2E, 0x0E, 0xC5, 0x8F, 0x09, 0x7E, 0x42, 0x9F, 0x80, 0x13, 0xA7, 0x24, 0x3F, 0xA9, 0x4F, 0xC2, 0xC9, 0x13, 0x6B, 0x2C, 0xF4, 0x29, 0x38, 0x75, 0x4A, 0xF3, 0xD3, 0xFA, 0x34, 0x9C, 0x3E, 0xB1, 0x3D, 0xC1, 0x90, 0x41, 0x32, 0xE7, 0xAC, 0x20, 0x6B, 0xC8, 0x22, 0xD9, 0x73, 0x4E, 0x90, 0x33, 0xE4, 0x90, 0xDC, 0x39, 0x2F, 0xC8, 0x1B, 0xF2, 0x48, 0xFE, 0x5C, 0x10, 0x16, 0x8C, 0x05, 0xB4, 0x70, 0x29, 0x0A, 0x8B, 0xC6, 0x22, 0x5A, 0xBC, 0x94, 0x84, 0x25, 0x63, 0x09, 0x2D, 0x5D, 0xCA, 0xC2, 0xB2, 0xB1, 0x8C, 0x96, 0x2F, 0x15, 0x51, 0xC5, 0x54, 0xC1, 0x2A, 0xD7, 0xAA, 0xA8, 0x6A, 0xAA, 0x62, 0xD5, 0x6B, 0x4D, 0x54, 0x33, 0xD5, 0xB0, 0xDA, 0x15, 0x10, 0x01, 0x26, 0x00, 0x03, 0xAE, 0xA0, 0x18, 0x34, 0x83, 0x38, 0x78, 0x83, 0xC4, 0x90, 0x19, 0xC2, 0xA1, 0x1B, 0x2C, 0x86, 0xCD, 0x30, 0x0E, 0xDF, 0x10, 0x31, 0x62, 0x46, 0x70, 0xE4, 0x86, 0x4A, 0x50, 0x0B, 0x4A, 0xA0, 0x77, 0x4C, 0x82, 0x59, 0x30, 0x02, 0xBB, 0xE3, 0x12, 0xDC, 0x82, 0x13, 0xF8, 0x9D, 0x90, 0x10, 0x16, 0x82, 0x20, 0xEE, 0xA4, 0x94, 0xB4, 0x92, 0x24, 0xF9, 0xA0, 0xA4, 0x94, 0x95, 0x22, 0xA9, 0x07, 0x2D, 0xA5, 0xAD, 0x34, 0x49, 0x3F, 0x18, 0x29, 0x63, 0x65, 0x48, 0xE6, 0x51, 0x97, 0xD5, 0x6D, 0x75, 0xAA, 0xFE, 0x6C, 0xC8, 0x1A, 0xB6, 0x06, 0xD5, 0x78, 0x36, 0x65, 0x4D, 0x5B, 0x93, 0x6A, 0x3E, 0x5B, 0xB2, 0x96, 0xAD, 0x45, 0xB5, 0x9E, 0x6D, 0x79, 0xDB, 0xDE, 0xA6, 0xDB, 0xAF, 0x8E, 0xBC, 0x63, 0xEF, 0xD0, 0x9D, 0x57, 0x57, 0xDE, 0xB5, 0x77, 0xE9, 0xEE, 0xAB, 0x27, 0xEF, 0xD9, 0x7B, 0x74, 0xEF, 0xD5, 0x57, 0xF4, 0x1D, 0x7D, 0xA6, 0xFF, 0x1E, 0x28, 0x06, 0x8E, 0x01, 0xC3, 0xF6, 0x04, 0xC5, 0xD0, 0x31, 0x64, 0x86, 0xEF, 0x91, 0x62, 0xE4, 0x18, 0x31, 0xA3, 0xF7, 0x58, 0x39, 0x76, 0x8E, 0xEB, 0xE3, 0xCF, 0x44, 0x39, 0x71, 0x4E, 0xEA, 0x93, 0xCF, 0x54, 0x39, 0x75, 0x4E, 0xEB, 0xD3, 0xCF, 0x4C, 0x39, 0x73, 0xCE, 0xEA, 0xB3, 0xCF, 0x5C, 0x35, 0x77, 0xCD, 0x1B, 0xAC, 0x0B, 0x51, 0x2D, 0x5C, 0x8B, 0xC6, 0xE2, 0xFB, 0xFF, 0x05, 0xA8, 0x56, 0xAE, 0x55, 0x63, 0xF5, 0x5D, 0xAB, 0xD7, 0xEE, 0x75, 0x73, 0xFD, 0xDB, 0xA8, 0x37, 0xEE, 0x4D, 0x73, 0xF3, 0xDB, 0xAA, 0xB7, 0xEE, 0x6D, 0x73, 0xFB, 0xDB, 0xA9, 0x77, 0xEE, 0x5D, 0x73, 0xF7, 0xFB, 0x47, 0x10, 0x3C, 0x60, 0x29, 0x14, 0x05, 0x00, 0x00, 0x5D, 0x53, 0x76, 0xB3, 0xA6, 0xEC, 0xF6, 0x94, 0xDD, 0x71, 0xB6, 0x6D, 0xFB, 0xF3, 0xF9, 0x9F, 0xB9, 0xB7, 0xA2, 0xAA, 0x38, 0x2A, 0xB1, 0x0A, 0x57, 0x55, 0x55, 0x1D, 0xD5, 0x58, 0x95, 0xAB, 0xA9, 0x6A, 0x8E, 0x5A, 0xAC, 0xC6, 0xD5, 0x55, 0x75, 0x47, 0x3D, 0x56, 0xE7, 0x1A, 0xEA, 0x86, 0xB3, 0x11, 0x6F, 0xF0, 0x4D, 0x75, 0xD3, 0xD9, 0x8C, 0x37, 0xF9, 0x96, 0xBA, 0xE5, 0x6C, 0xC5, 0x5B, 0x7C, 0x5B, 0xDD, 0x76, 0xB6, 0xE3, 0x6D, 0xBE, 0xA3, 0xE9, 0xB8, 0x3A, 0x89, 0x8E, 0xD0, 0xD5, 0x74, 0x5D, 0xDD, 0x44, 0x57, 0xE8, 0x69, 0x7A, 0xAE, 0x5E, 0xA2, 0x27, 0xF4, 0x35, 0x7D, 0x57, 0x3F, 0xD1, 0x17, 0x06, 0xDA, 0x81, 0x7B, 0x90, 0x1C, 0x88, 0x43, 0xED, 0xD0, 0x3D, 0x4C, 0x0E, 0xC5, 0x91, 0x76, 0xE4, 0x1E, 0x25, 0x47, 0xE2, 0x58, 0x3B, 0x76, 0x8F, 0x93, 0x63, 0x71, 0xA2, 0x9B, 0x78, 0x26, 0xA9, 0x89, 0x34, 0xD5, 0x4D, 0x3D, 0xD3, 0xD4, 0x54, 0x9A, 0xE9, 0x66, 0x9E, 0x59, 0x6A, 0x26, 0xCD, 0x75, 0x73, 0xCF, 0x3C, 0x35, 0x97, 0x16, 0xFA, 0x85, 0x77, 0x91, 0x5E, 0xC8, 0x4B, 0xFD, 0xD2, 0xBB, 0x4C, 0x2F, 0xE5, 0x95, 0x7E, 0xE5, 0x5D, 0xA5, 0x57, 0xF2, 0x5A, 0xBF, 0xF6, 0xAE, 0xD3, 0x6B, 0x79, 0x63, 0xD8, 0xF8, 0x36, 0x99, 0x0D, 0xD8, 0x1A, 0xB6, 0xBE, 0x6D, 0x66, 0x0B, 0x76, 0x86, 0x9D, 0x6F, 0x97, 0xD9, 0x81, 0xBD, 0x61, 0xEF, 0xDB, 0x67, 0xF6, 0xE0, 0x60, 0x3C, 0xF8, 0x0F, 0xD9, 0x03, 0x3C, 0x1A, 0x8F, 0xFE, 0x63, 0xF6, 0x08, 0x4F, 0xC6, 0x93, 0xFF, 0x94, 0x3D, 0xC1, 0xB3, 0xF1, 0xEC, 0x3F, 0x67, 0xCF, 0xF0, 0x62, 0xBA, 0x04, 0x2E, 0xB9, 0x0B, 0xBA, 0x9A, 0xAE, 0x81, 0x6B, 0xEE, 0x8A, 0x6E, 0xA6, 0x5B, 0xE0, 0x96, 0xBB, 0xA1, 0xBB, 0xE9, 0x1E, 0xB8, 0xE7, 0xEE, 0xE8, 0x61, 0x7E, 0x04, 0x1F, 0xF9, 0x07, 0x7E, 0x9A, 0x9F, 0xC1, 0x67, 0xFE, 0x89, 0x5F, 0xE6, 0x57, 0xF0, 0x95, 0x7F, 0xE1, 0xB7, 0xF9, 0x1D, 0x7C, 0xE7, 0xDF, 0xF8, 0x63, 0xF9, 0x84, 0x3E, 0x85, 0x0F, 0xF9, 0x5A, 0xBE, 0xA1, 0x6F, 0xE1, 0x4B, 0x7E, 0x96, 0x5F, 0xE8, 0x57, 0xF8, 0x11, 0xCE, 0xC2, 0x85, 0xB8, 0x02, 0x47, 0x78, 0x2B, 0x1F, 0xE6, 0x8B, 0x3C, 0x15, 0xAC, 0x42, 0x58, 0x28, 0x0A, 0x54, 0xB4, 0x8A, 0x61, 0xB1, 0x28, 0x52, 0xC9, 0x2A, 0x85, 0xA5, 0xA2, 0x44, 0x65, 0x9B, 0x1C, 0x91, 0x4B, 0x32, 0x03, 0x36, 0x10, 0x01, 0x25, 0xC0, 0xA0, 0x0D, 0x46, 0x60, 0x09, 0x32, 0x64, 0x43, 0x11, 0x54, 0x42, 0x0C, 0xDB, 0x71, 0x14, 0x97, 0xB1, 0x42, 0xEC, 0x24, 0x4A, 0xCA, 0x44, 0xA1, 0x76, 0x1A, 0xA5, 0x65, 0xAA, 0x30, 0x3B, 0x8B, 0xB2, 0x32, 0x53, 0x94, 0x3F, 0xE5, 0x9F, 0x5D, 0xFB, 0x70, 0xCB, 0xF1, 0xFF, 0xDF, 0x07, 0x7E, 0x96, 0x06, 0xED, 0x90, 0xCC, 0x94, 0x32, 0x52, 0x08, 0xD1, 0x9E, 0x54, 0x46, 0x66, 0x46, 0x99, 0x45, 0x76, 0xC8, 0xC8, 0xC8, 0x5B, 0xDB, 0x4E, 0x49, 0x46, 0x1A, 0x1A, 0xCA, 0xCA, 0xAA, 0xEC, 0x55, 0x08, 0x65, 0xEF, 0x91, 0xEC, 0x4D, 0x56, 0xB2, 0xAB, 0xF3, 0xD7, 0xF3, 0xB8, 0x8F, 0xDF, 0x5F, 0xF1, 0xFD, 0x58, 0x8F, 0xEB, 0xBC, 0xD7, 0xF9, 0xD2, 0x7A, 0x5E, 0xD7, 0xEB, 0xB8, 0xC3, 0x6B, 0x0B, 0x6B, 0x49, 0x17, 0x86, 0xB3, 0xF0, 0x7F, 0xF3, 0xFF, 0x7F, 0xF3, 0xFF, 0x7F, 0xF3, 0xFF, 0x7F, 0xF3, 0xFF, 0x7F, 0xF3, 0xFF, 0x7F, 0xF3, 0xFF, 0x7F, 0xF3, 0xFF, 0xFF, 0xE2, 0xFC, 0x27, 0x87, 0xA4, 0x03, 0x1E, 0xFF, 0x91, 0xDD, 0x4C, 0x81, 0xD1, 0x15, 0x24, 0x00, 0xCC, 0x6F, 0x2D, 0xDA, 0x7D, 0x9B, 0x1A, 0x28, 0xFA, 0x66, 0x8F, 0x8D, 0x15, 0xA7, 0x77, 0xF7, 0x9B, 0x23, 0x26, 0x24, 0x0E, 0x49, 0x14, 0x53, 0xCB, 0x87, 0xDC, 0x14, 0xB3, 0x47, 0x0E, 0x3A, 0x25, 0x16, 0xBC, 0xED, 0x77, 0x86, 0x6C, 0x6C, 0x54, 0xD5, 0xCA, 0xD9, 0xAA, 0xDA, 0x0E, 0x20, 0xFB, 0x64, 0x3D, 0x7A, 0x22, 0x06, 0x9E, 0x3E, 0xFF, 0x4D, 0x9C, 0xF3, 0xF9, 0x70, 0x4B, 0xF1, 0xBF, 0x8E, 0x3B, 0x2F, 0x89, 0x51, 0xD9, 0xA9, 0xBB, 0xC5, 0xE5, 0xD5, 0xE4, 0xF4, 0x46, 0x80, 0xED, 0x67, 0xB2, 0x9F, 0x27, 0x30, 0x2C, 0x8B, 0x04, 0x80, 0x45, 0x3B, 0xC5, 0x8E, 0xAE, 0xF3, 0x0C, 0xC4, 0x61, 0x3E, 0x13, 0x29, 0x06, 0xAA, 0x8F, 0x8A, 0x15, 0xE3, 0x7B, 0xF9, 0xCC, 0x12, 0x53, 0xAE, 0xFA, 0x54, 0x88, 0xD9, 0x29, 0x43, 0x52, 0xC4, 0xD3, 0x16, 0xDE, 0x9E, 0x64, 0xF3, 0xD4, 0xBF, 0x95, 0xF6, 0xA9, 0x9F, 0x0C, 0x01, 0xD2, 0xDF, 0xF4, 0xBA, 0x9B, 0x38, 0xB7, 0xE6, 0x78, 0xB4, 0x18, 0x96, 0x99, 0xAB, 0x29, 0x2E, 0xFB, 0x9E, 0xA6, 0x22, 0xAE, 0x5E, 0x9D, 0x50, 0x23, 0xAE, 0xFD, 0x48, 0x2E, 0xBA, 0x05, 0x74, 0x5D, 0x48, 0x0E, 0x9B, 0x02, 0x0C, 0x9B, 0x42, 0x1A, 0x03, 0x98, 0x53, 0x4A, 0x02, 0xFA, 0xDF, 0xC2, 0xEE, 0x8B, 0xBD, 0x2F, 0xCD, 0xB5, 0x11, 0x03, 0x1E, 0x05, 0x3C, 0x22, 0xF5, 0xDC, 0x57, 0x7F, 0x1C, 0xEC, 0x2E, 0x39, 0x79, 0xC4, 0x88, 0x71, 0x62, 0xF6, 0x33, 0x9F, 0xC3, 0xE2, 0x55, 0xBD, 0xC1, 0xCB, 0xC8, 0x16, 0x7B, 0x48, 0x57, 0x94, 0x3B, 0x41, 0xFA, 0xBD, 0x8B, 0xC6, 0x8B, 0x11, 0xCF, 0xF6, 0xEE, 0x17, 0x57, 0x85, 0xA7, 0xC5, 0x88, 0x71, 0x1B, 0xE3, 0xBB, 0x89, 0xEB, 0x67, 0x47, 0x8D, 0x15, 0x37, 0x4C, 0x23, 0x23, 0x6D, 0x81, 0x2E, 0x4E, 0xA4, 0x5F, 0x2D, 0x30, 0x62, 0x1B, 0xE9, 0x3D, 0x5A, 0x65, 0x71, 0xE0, 0x62, 0x12, 0x50, 0xBD, 0xB1, 0xEC, 0x86, 0x68, 0xB7, 0x28, 0xAC, 0xB7, 0xE8, 0x8F, 0x99, 0x09, 0xE2, 0xFC, 0xB1, 0xFE, 0xBD, 0xC4, 0xA4, 0xBB, 0xBE, 0xF7, 0xC4, 0x1C, 0xCB, 0x11, 0xED, 0xC4, 0xC7, 0x4B, 0x87, 0x36, 0xFF, 0x91, 0x02, 0x90, 0x33, 0xED, 0x2F, 0xAB, 0x8B, 0xD1, 0x26, 0x79, 0xA7, 0xC5, 0xB5, 0x1B, 0xD2, 0xFE, 0x13, 0x13, 0xDD, 0x62, 0xC7, 0x8B, 0x9B, 0x35, 0xC3, 0xAB, 0xC4, 0xA4, 0x8C, 0x90, 0x4F, 0x62, 0xF2, 0x75, 0x32, 0xB6, 0x18, 0xB0, 0xB0, 0x24, 0x17, 0xAA, 0x00, 0x7D, 0xB3, 0x49, 0x7F, 0x28, 0xF5, 0x09, 0xE8, 0x43, 0x36, 0x2F, 0x00, 0x62, 0x56, 0x93, 0xC6, 0xE8, 0x36, 0x3B, 0x02, 0x24, 0xE0, 0xD3, 0x20, 0x7C, 0xAD, 0x38, 0x3B, 0x7A, 0x96, 0xB5, 0x98, 0xF4, 0xD5, 0xEF, 0x89, 0x98, 0xB3, 0xCC, 0xB7, 0x56, 0x1E, 0xF7, 0x6B, 0x92, 0x5B, 0x93, 0x47, 0x5D, 0x20, 0xFD, 0x53, 0x0F, 0x07, 0x89, 0xEB, 0x9B, 0xA6, 0x29, 0xFA, 0x4E, 0xAF, 0xFC, 0x23, 0xA6, 0xDA, 0x2E, 0xB1, 0x11, 0xB7, 0x3A, 0xCE, 0x5E, 0x24, 0xA6, 0xBF, 0x9E, 0x32, 0x1B, 0xF3, 0xC8, 0x8C, 0x79, 0xE4, 0xC6, 0xEE, 0x40, 0x87, 0x0D, 0xE4, 0xCA, 0xD6, 0x80, 0xAB, 0x29, 0x39, 0xEB, 0x2A, 0xE0, 0xBF, 0x99, 0x1C, 0x7B, 0x42, 0xBF, 0xC9, 0x9C, 0x26, 0x24, 0xD0, 0xA0, 0xD7, 0xA6, 0x6C, 0xD1, 0x15, 0x71, 0x19, 0x62, 0xD0, 0xC7, 0x88, 0xE3, 0xE2, 0x7A, 0xFB, 0xA9, 0xFE, 0x62, 0xCE, 0xE7, 0x31, 0xB3, 0x45, 0x72, 0x71, 0xE1, 0xE9, 0xBB, 0xE2, 0xA6, 0xB0, 0xD4, 0x16, 0x62, 0x7A, 0xCE, 0x8A, 0x24, 0xB5, 0xD1, 0x64, 0xE6, 0x89, 0x85, 0x6A, 0xF5, 0x9E, 0x91, 0xDB, 0x9E, 0x06, 0x99, 0xA9, 0x3C, 0x21, 0xB3, 0x9F, 0xF8, 0x03, 0x20, 0x73, 0xEE, 0xFA, 0x43, 0xD7, 0x95, 0xCC, 0xCA, 0x21, 0xD3, 0x4E, 0x00, 0xED, 0x0C, 0xC8, 0x0D, 0xF5, 0x01, 0xE7, 0xB6, 0x64, 0x04, 0x80, 0xF1, 0x36, 0xE4, 0xBC, 0xB1, 0xC0, 0x7C, 0x6F, 0xB2, 0xBB, 0x15, 0x90, 0x68, 0x45, 0xA2, 0x83, 0x59, 0x5C, 0x3A, 0x49, 0x60, 0x4C, 0xF0, 0xC6, 0x64, 0x31, 0x02, 0x31, 0xDE, 0xE2, 0xF6, 0xD1, 0xFE, 0xB8, 0x2F, 0xFD, 0x4C, 0x1E, 0xBA, 0x7B, 0x9E, 0xE5, 0x30, 0x32, 0x63, 0x78, 0x78, 0x6D, 0x03, 0x92, 0xBB, 0x6A, 0xE7, 0x6C, 0xD0, 0xAC, 0x47, 0xE6, 0xD6, 0xF3, 0x87, 0xD2, 0xEB, 0x3A, 0x2B, 0xFC, 0xD1, 0x38, 0x95, 0xDC, 0x91, 0x34, 0xDE, 0xCA, 0x18, 0x64, 0xB6, 0xBD, 0x3F, 0x3A, 0x6E, 0x20, 0x33, 0x9C, 0xC9, 0x6D, 0x1D, 0x80, 0x76, 0x7D, 0xC9, 0x74, 0x02, 0xF6, 0xE9, 0x64, 0xAA, 0x35, 0x30, 0xF4, 0x29, 0xB9, 0xAA, 0x04, 0x98, 0x33, 0x5E, 0xB1, 0xAE, 0x65, 0xD9, 0x64, 0xBF, 0xFE, 0x80, 0x62, 0x1D, 0xDD, 0x3E, 0xEC, 0xDB, 0x28, 0x2E, 0xEA, 0xB6, 0x6D, 0x84, 0x98, 0x13, 0xB8, 0xE1, 0x7D, 0x3A, 0x0D, 0xE2, 0xC9, 0xFC, 0x2F, 0xD3, 0x01, 0x90, 0x47, 0x0A, 0xFD, 0xA1, 0x71, 0x84, 0x2C, 0x38, 0xDF, 0x5F, 0x15, 0x10, 0xDD, 0xC6, 0x8A, 0x79, 0x19, 0x8E, 0x6D, 0xC5, 0xFD, 0xEC, 0xE9, 0x2A, 0xEE, 0xAB, 0xEC, 0x3A, 0x4C, 0xDC, 0xFB, 0x89, 0xDC, 0x7D, 0x13, 0x30, 0x5D, 0x4E, 0xEE, 0x5A, 0x0C, 0xD8, 0x19, 0x93, 0x39, 0xA7, 0x80, 0xA1, 0x6B, 0xC8, 0x2C, 0x13, 0x20, 0x48, 0x3E, 0x77, 0xDF, 0x81, 0x88, 0xEF, 0xE4, 0x36, 0x77, 0xBD, 0xA1, 0xEB, 0x86, 0x90, 0x09, 0x0F, 0x80, 0xDD, 0xE3, 0xC9, 0x44, 0x9F, 0x56, 0xC6, 0xA7, 0x5A, 0x3B, 0x1C, 0x02, 0xAE, 0x75, 0xFE, 0xBB, 0xC3, 0xD1, 0x1D, 0x20, 0x2F, 0xF5, 0xB6, 0x3A, 0x2C, 0x16, 0x8E, 0xEA, 0x38, 0x40, 0x3C, 0x31, 0xC3, 0x34, 0x56, 0x3C, 0x3A, 0xDB, 0xA8, 0xBD, 0x78, 0x58, 0xBD, 0x79, 0x43, 0xB1, 0xE0, 0xB7, 0xC1, 0x1F, 0x31, 0xBF, 0x47, 0xC3, 0x51, 0xE2, 0x81, 0x2C, 0x32, 0x2F, 0x1E, 0x30, 0xE9, 0x4A, 0x16, 0xDC, 0x02, 0x6C, 0x1E, 0x90, 0xC7, 0x83, 0x55, 0x27, 0x78, 0x04, 0xD4, 0x99, 0x07, 0x04, 0xDE, 0x26, 0xCF, 0xBF, 0x00, 0x16, 0x4C, 0x20, 0x1F, 0xEF, 0x03, 0x22, 0x8A, 0xFF, 0x5C, 0x24, 0xCD, 0x56, 0xAD, 0xBB, 0xBC, 0xDA, 0x85, 0x04, 0x0A, 0xC6, 0x02, 0xE4, 0xA4, 0xEB, 0x87, 0xFF, 0x02, 0xAE, 0x20, 0xCF, 0xB9, 0x2B, 0xFF, 0x35, 0x3A, 0x40, 0x16, 0x7E, 0x85, 0xB5, 0xE6, 0x69, 0xF2, 0xF4, 0x46, 0x40, 0x6D, 0x27, 0x79, 0xE2, 0x38, 0xA0, 0x32, 0x9A, 0x3C, 0x66, 0x04, 0xD4, 0x6B, 0x4B, 0x1E, 0xBE, 0x59, 0x67, 0x6B, 0xF2, 0xE0, 0x89, 0x3A, 0xD7, 0x92, 0xF9, 0x37, 0xC9, 0xA3, 0xDB, 0x80, 0x56, 0xAF, 0xC8, 0xD3, 0x06, 0x40, 0x77, 0x13, 0xF2, 0xBC, 0x35, 0xD0, 0x5B, 0x93, 0xBC, 0x1E, 0x06, 0x8C, 0x5C, 0x4B, 0x3E, 0xEF, 0xA7, 0xD4, 0x3F, 0x30, 0xF6, 0x77, 0x2B, 0xB2, 0xA9, 0xD1, 0xBC, 0x82, 0xE3, 0x97, 0x49, 0xC3, 0x8E, 0x9B, 0xCD, 0xBD, 0xCD, 0x48, 0xA3, 0xB3, 0x5B, 0xCF, 0xB6, 0x48, 0x22, 0xBD, 0x83, 0x46, 0x27, 0xE9, 0xAE, 0xD9, 0x74, 0x9E, 0xDC, 0xBF, 0x1A, 0x18, 0x74, 0x8D, 0x3C, 0xBA, 0x44, 0xBD, 0x56, 0xD6, 0x75, 0xB8, 0x15, 0x60, 0x69, 0x5D, 0xE7, 0x06, 0xA0, 0x4D, 0x07, 0xF2, 0x50, 0x0F, 0xC0, 0x18, 0x64, 0x81, 0x63, 0xBD, 0xA5, 0xE2, 0x81, 0x6A, 0xF5, 0xD0, 0xD6, 0x7F, 0xC9, 0x7D, 0x79, 0x64, 0x21, 0x81, 0x26, 0x3A, 0x64, 0xF1, 0x5F, 0xC0, 0xEA, 0x2C, 0x79, 0x7D, 0x95, 0xE2, 0xFF, 0xF6, 0x94, 0x40, 0x9F, 0x3C, 0x92, 0xD4, 0xBB, 0x3E, 0xF8, 0xDA, 0x8D, 0x18, 0x12, 0x58, 0xBA, 0xF5, 0xBF, 0x97, 0xE2, 0x46, 0x1F, 0x40, 0x8C, 0xBE, 0xA7, 0x1F, 0x4B, 0xBA, 0xDB, 0x0E, 0x89, 0x05, 0x4A, 0xED, 0xC8, 0x94, 0x73, 0x1A, 0x49, 0x51, 0x55, 0xE4, 0xEE, 0x24, 0xED, 0x0F, 0xFE, 0x59, 0xE4, 0xDE, 0xF7, 0xDA, 0x7F, 0x7D, 0x62, 0xEB, 0x54, 0x7C, 0xBC, 0xB8, 0x5F, 0x47, 0x6B, 0xBA, 0x4B, 0x02, 0xB9, 0x67, 0x9A, 0xE6, 0x55, 0x7B, 0x25, 0x32, 0xF7, 0xAA, 0xA6, 0x67, 0x8F, 0x90, 0x3A, 0x3D, 0xC8, 0x0B, 0xCF, 0xD5, 0x5E, 0x68, 0xF6, 0x26, 0xAF, 0x5B, 0x00, 0x96, 0x65, 0xE4, 0xE3, 0x17, 0x40, 0x8F, 0x4E, 0x24, 0xBB, 0x00, 0xF6, 0xAF, 0x9E, 0x92, 0x04, 0x46, 0x99, 0xED, 0x7A, 0x29, 0x86, 0x67, 0xFB, 0x78, 0x8A, 0x61, 0x27, 0x01, 0x71, 0xE2, 0x2F, 0xED, 0x93, 0xA4, 0xD3, 0x9C, 0x01, 0x75, 0xF9, 0xEF, 0xCE, 0xD7, 0xB9, 0xE1, 0x73, 0x80, 0x7D, 0x9F, 0xC8, 0x2D, 0x47, 0x94, 0xC7, 0x2E, 0x4F, 0x25, 0xB3, 0xC6, 0xA8, 0x6E, 0x0D, 0xEE, 0x49, 0xE6, 0xA4, 0xA9, 0x1D, 0x1E, 0xDF, 0x81, 0xDC, 0x7E, 0x48, 0xED, 0xF1, 0xF0, 0x79, 0x75, 0x96, 0xAB, 0x9D, 0x1B, 0xF0, 0xBE, 0xCE, 0xB3, 0x80, 0xFB, 0x7E, 0x72, 0xC7, 0x64, 0xF2, 0xFA, 0x28, 0xBC, 0xD6, 0x1D, 0x4D, 0x96, 0xEB, 0x03, 0xA6, 0xFD, 0xC9, 0x5F, 0x65, 0x40, 0xDB, 0x8E, 0x9F, 0x32, 0x49, 0xC0, 0xC6, 0xE2, 0xCC, 0x53, 0x71, 0x6C, 0x7C, 0x04, 0xC4, 0x05, 0x9F, 0x8D, 0x21, 0x4E, 0xFD, 0xA0, 0x4F, 0xD2, 0x18, 0x43, 0xA8, 0xA1, 0x47, 0xDA, 0xAF, 0xEA, 0xA7, 0x07, 0x90, 0x99, 0xBB, 0x5D, 0xC2, 0x80, 0x7B, 0xE3, 0x7E, 0x47, 0x47, 0x1D, 0x6F, 0x9E, 0x5D, 0xB0, 0x8A, 0x5C, 0x73, 0x0B, 0x58, 0x67, 0x4D, 0x26, 0x25, 0x02, 0x4B, 0x6A, 0xC9, 0xD4, 0xCF, 0xC0, 0xCC, 0xAD, 0xE4, 0xD6, 0xF3, 0xC0, 0x84, 0x3B, 0x64, 0xFA, 0x47, 0x60, 0xF4, 0xE0, 0x3A, 0x49, 0x3E, 0x7A, 0x0A, 0x68, 0x3F, 0x24, 0x2B, 0x7F, 0x01, 0x8D, 0x4F, 0xFE, 0xA8, 0x24, 0x81, 0x96, 0x47, 0xEF, 0x7C, 0x13, 0x1D, 0x2B, 0x32, 0xBB, 0x88, 0x93, 0x62, 0x02, 0xBE, 0x92, 0x4D, 0xDF, 0xFA, 0xBE, 0x05, 0x24, 0x8F, 0xF7, 0xD1, 0x0A, 0x26, 0xDB, 0x2C, 0xF4, 0x0E, 0x56, 0x73, 0x25, 0x6D, 0x26, 0x79, 0xBA, 0x36, 0x36, 0x25, 0x57, 0x77, 0xB6, 0x36, 0x05, 0xFE, 0x9D, 0x7E, 0xB9, 0xC9, 0xDF, 0x01, 0xB8, 0xBE, 0xFE, 0xDF, 0x90, 0xC5, 0xA7, 0x54, 0x93, 0x0B, 0x0C, 0xC9, 0x65, 0x5B, 0x80, 0xD4, 0xEE, 0xE4, 0xDA, 0x64, 0x60, 0x4D, 0x67, 0x32, 0xA1, 0x04, 0x08, 0x1B, 0x40, 0x6E, 0x58, 0x0C, 0xCC, 0x37, 0x25, 0x37, 0x3D, 0x22, 0x3F, 0x15, 0x01, 0x9A, 0xFD, 0x6A, 0x2C, 0x49, 0x40, 0xAB, 0xE6, 0xE9, 0x6B, 0xD1, 0xB4, 0xE6, 0x44, 0x86, 0xE8, 0x76, 0x20, 0x5C, 0x47, 0xF4, 0xCD, 0x34, 0xAB, 0x11, 0x47, 0xEC, 0x04, 0xC4, 0xE1, 0x05, 0xEA, 0x83, 0x48, 0x33, 0x5B, 0xAF, 0x81, 0xCA, 0x09, 0xA4, 0xB5, 0xAD, 0x7B, 0x82, 0x31, 0xC8, 0x20, 0xB6, 0x8D, 0x05, 0xC8, 0x7D, 0x59, 0x3D, 0x96, 0x03, 0x5F, 0xF8, 0xF9, 0xC2, 0xA8, 0x34, 0xE0, 0xD6, 0x95, 0xEA, 0x83, 0x33, 0x87, 0x01, 0xC7, 0x03, 0xC9, 0x45, 0x5B, 0x94, 0x74, 0x76, 0x0E, 0x27, 0x23, 0x75, 0x80, 0x2D, 0x86, 0xE4, 0xF2, 0xA9, 0xC0, 0xDA, 0x44, 0x72, 0xD5, 0x26, 0xB2, 0x26, 0x17, 0xA8, 0x17, 0xF3, 0x79, 0x0F, 0x65, 0x1D, 0xEB, 0xAF, 0xF8, 0x89, 0xE6, 0xFD, 0xB6, 0x36, 0x23, 0x55, 0x5A, 0xF7, 0x6E, 0xED, 0xF7, 0x93, 0x54, 0x5F, 0xE1, 0xB5, 0xA2, 0x51, 0x14, 0x09, 0xF8, 0x44, 0xD5, 0x3F, 0x4A, 0x36, 0x55, 0xEF, 0x73, 0x54, 0xF9, 0x32, 0x69, 0x5A, 0xCF, 0xFD, 0x32, 0x40, 0x76, 0x75, 0x70, 0x85, 0xE8, 0x0A, 0xDB, 0x41, 0xDA, 0xAF, 0xC9, 0xE4, 0x56, 0x9D, 0x5E, 0x4B, 0xBE, 0xE2, 0xD0, 0xA5, 0x14, 0xF8, 0x5A, 0x50, 0x15, 0x3D, 0xB0, 0x1A, 0x78, 0x30, 0xA2, 0xA6, 0x70, 0xFC, 0x5E, 0xE0, 0xBC, 0x01, 0x7F, 0x4E, 0x2D, 0x02, 0x0E, 0xFE, 0x25, 0xE7, 0xCC, 0x04, 0x76, 0xF8, 0x93, 0x8B, 0xF2, 0xC9, 0xF9, 0x65, 0x80, 0xE9, 0x4D, 0xB2, 0x5F, 0x4F, 0xA0, 0x5F, 0x4F, 0xC5, 0xDC, 0x9F, 0xD8, 0x9B, 0x04, 0xF4, 0x3F, 0x05, 0x07, 0x8B, 0x5E, 0x0F, 0x02, 0xBA, 0x88, 0xFE, 0x18, 0xA1, 0x4A, 0x6A, 0x2B, 0xAD, 0x9C, 0x3A, 0x00, 0x92, 0x93, 0xBB, 0x0F, 0xC9, 0x15, 0xB3, 0x7B, 0x0D, 0x72, 0x14, 0x0B, 0x4A, 0xFB, 0xF5, 0x22, 0x1B, 0x55, 0x7D, 0xFF, 0xEE, 0x94, 0x53, 0x3D, 0x1C, 0x20, 0x3D, 0x9B, 0x3D, 0x7A, 0x2C, 0x4E, 0xD4, 0x3C, 0x7F, 0x53, 0x0C, 0x9E, 0x76, 0x78, 0x80, 0x18, 0x7A, 0x67, 0x67, 0xAC, 0x18, 0x19, 0x9F, 0x7A, 0x48, 0x5C, 0xAE, 0x4C, 0xCA, 0xD7, 0x78, 0xCB, 0x4D, 0xE4, 0x80, 0xD7, 0xC0, 0xC0, 0xF6, 0x64, 0xCF, 0x16, 0xC0, 0xF8, 0x44, 0x12, 0x00, 0xFE, 0xB3, 0x17, 0x7B, 0x05, 0xCE, 0xE8, 0x21, 0x4E, 0xE8, 0x3D, 0xFA, 0x34, 0x69, 0xA0, 0xBD, 0xD2, 0xAB, 0xDF, 0x6E, 0xC9, 0x5B, 0xEC, 0x86, 0xAD, 0x16, 0xB7, 0x19, 0x0F, 0xFE, 0x2E, 0x1E, 0xB9, 0xEF, 0x6D, 0x43, 0x9A, 0x5E, 0xAF, 0x2D, 0xE8, 0xF6, 0xEC, 0x93, 0x09, 0x40, 0xFA, 0xFB, 0x5D, 0xCB, 0x12, 0xE7, 0x3C, 0x3A, 0x3E, 0x5B, 0x5C, 0x5A, 0x98, 0xAB, 0x23, 0x2E, 0xEB, 0x98, 0xBA, 0x57, 0x5C, 0x55, 0x98, 0x50, 0x22, 0xAE, 0x55, 0x23, 0x97, 0xBB, 0x02, 0xCD, 0xEB, 0x93, 0x41, 0xE7, 0x00, 0xE7, 0x96, 0xE4, 0xE0, 0x1D, 0x80, 0xEF, 0x62, 0x12, 0x00, 0xA2, 0x7D, 0xC5, 0xAE, 0xDB, 0x17, 0xBE, 0x10, 0x03, 0x9A, 0x06, 0x0E, 0x17, 0xA7, 0xBF, 0x1B, 0x67, 0x27, 0x26, 0x4D, 0x1B, 0x21, 0x19, 0x59, 0x5F, 0x86, 0x9E, 0x13, 0x4B, 0xE7, 0xFB, 0xE4, 0x91, 0x2D, 0x5B, 0x90, 0x36, 0xBE, 0x65, 0x7F, 0x20, 0xFD, 0x77, 0x8B, 0x20, 0x46, 0x74, 0xDA, 0xFB, 0x9F, 0xB8, 0xF2, 0x7E, 0xDA, 0x12, 0x71, 0x6D, 0x49, 0xBC, 0xA9, 0x98, 0xF0, 0x29, 0xAA, 0xBB, 0x98, 0x98, 0x4D, 0xAE, 0xF5, 0x00, 0x0C, 0xA7, 0x90, 0x61, 0x15, 0x80, 0xB5, 0x0B, 0xE9, 0xF7, 0x0D, 0xF0, 0x9B, 0x40, 0xB6, 0x8C, 0x03, 0x42, 0x77, 0x91, 0x40, 0xE3, 0xF4, 0x65, 0xDE, 0xE2, 0x40, 0xF3, 0x85, 0x5A, 0xE2, 0x24, 0x8D, 0x89, 0x4B, 0xC4, 0x94, 0x7A, 0x3E, 0xBD, 0xC4, 0x9C, 0xC9, 0xC3, 0x17, 0x8B, 0x4F, 0x5D, 0x06, 0x4F, 0xFA, 0x53, 0x1F, 0x20, 0x67, 0x55, 0x5C, 0x6A, 0x2E, 0x46, 0x1D, 0xCC, 0x4B, 0x16, 0x63, 0x7F, 0xA4, 0x85, 0x88, 0xEB, 0xD3, 0xD6, 0x9C, 0x17, 0x37, 0xAD, 0x0F, 0x7F, 0x2A, 0x6E, 0x3E, 0x17, 0xF2, 0x4C, 0x4C, 0x96, 0x79, 0xBF, 0x07, 0x68, 0x74, 0x9B, 0x5C, 0x9E, 0x04, 0x74, 0xB7, 0x27, 0xC7, 0xE5, 0x02, 0x63, 0x9B, 0x93, 0x63, 0x77, 0x68, 0xEC, 0x0A, 0xBC, 0x44, 0x02, 0x30, 0x4F, 0xB0, 0x11, 0xDD, 0xF5, 0xA3, 0xFE, 0x8A, 0x33, 0xBD, 0x67, 0x7F, 0x13, 0x13, 0x5F, 0x4E, 0xFF, 0x2D, 0xEE, 0xC0, 0x68, 0x67, 0xB2, 0xCB, 0x4E, 0xD2, 0xA2, 0x51, 0x99, 0x0A, 0x40, 0xC6, 0xCC, 0x3F, 0x6C, 0x22, 0x26, 0x1C, 0xD8, 0x6A, 0x27, 0x26, 0x75, 0x59, 0xD9, 0x4D, 0x4C, 0x39, 0x1A, 0xFA, 0x44, 0x4C, 0x3B, 0x36, 0xB3, 0x44, 0x4C, 0x7F, 0x34, 0x39, 0x1F, 0xE2, 0x6F, 0x32, 0xC5, 0x05, 0xD0, 0xBF, 0x4C, 0xAE, 0x3F, 0x0A, 0x74, 0x71, 0x20, 0x23, 0x47, 0x03, 0xDE, 0x0D, 0xC9, 0x19, 0x46, 0xC0, 0x14, 0x5B, 0xD2, 0xF4, 0x23, 0x10, 0x3B, 0x83, 0x04, 0xCC, 0xFF, 0x26, 0xA6, 0x88, 0xFE, 0x4B, 0xE3, 0x76, 0x89, 0x61, 0xB5, 0xB1, 0x4D, 0xC5, 0xF4, 0x8E, 0x6B, 0x5D, 0x44, 0x72, 0x9E, 0xE6, 0xC9, 0x62, 0x71, 0xD3, 0x89, 0x14, 0x57, 0x31, 0xFD, 0xC4, 0x8A, 0x43, 0xEA, 0x77, 0xC9, 0x8C, 0xA3, 0x0B, 0x5B, 0xAB, 0x98, 0x91, 0xDB, 0x5C, 0x83, 0xA2, 0x54, 0xDE, 0x92, 0xD9, 0x33, 0xC7, 0xE6, 0x00, 0xE4, 0x76, 0x17, 0x7F, 0xE8, 0xE6, 0x90, 0x99, 0xDF, 0xC8, 0x74, 0x02, 0xFA, 0x67, 0xC9, 0x94, 0x4B, 0x80, 0xE5, 0x28, 0x32, 0xB1, 0x2D, 0xD0, 0x4B, 0x85, 0x8C, 0x74, 0x00, 0x26, 0x14, 0x93, 0x93, 0x76, 0x01, 0xD1, 0x8D, 0x48, 0x00, 0xD8, 0x7E, 0x9D, 0xD4, 0x79, 0xD0, 0xDF, 0x31, 0xD3, 0x59, 0x72, 0xD4, 0xE5, 0xAC, 0x79, 0xE2, 0x8E, 0xDB, 0xB9, 0xCB, 0xEF, 0x1F, 0x03, 0xC8, 0x2D, 0xCB, 0xF7, 0x94, 0xF4, 0x74, 0x20, 0xB7, 0x3E, 0x8E, 0x50, 0xD3, 0x58, 0x4A, 0xEE, 0x9A, 0x31, 0x4F, 0x4B, 0x2B, 0x8B, 0xDC, 0xBD, 0x62, 0xAC, 0x1F, 0x40, 0xEE, 0x09, 0xF5, 0x3F, 0xD9, 0xC4, 0x89, 0xDC, 0x7E, 0x2D, 0x60, 0x80, 0x59, 0x32, 0x99, 0xF5, 0x64, 0xFC, 0x30, 0xF3, 0xA1, 0xB2, 0x06, 0x32, 0x27, 0x0D, 0xD0, 0x2D, 0x24, 0x33, 0x77, 0x02, 0x16, 0x4F, 0xEA, 0xFC, 0x09, 0x38, 0x3B, 0x90, 0x89, 0x83, 0x00, 0xFF, 0x54, 0x32, 0x92, 0xC0, 0x52, 0x2B, 0xD2, 0x3F, 0x17, 0x48, 0xEE, 0x41, 0x02, 0x9A, 0x38, 0xFE, 0x4F, 0xF4, 0x5D, 0x73, 0xF2, 0x97, 0xF8, 0xBC, 0xA6, 0xF0, 0x48, 0xBA, 0x4A, 0x33, 0x0D, 0x32, 0xEF, 0xFD, 0x24, 0x2B, 0x80, 0x3C, 0xB6, 0x60, 0xA2, 0xB5, 0xEE, 0x62, 0x32, 0xFF, 0x61, 0x5F, 0x48, 0x2E, 0xF8, 0xE0, 0x58, 0x21, 0xE6, 0xDB, 0xDA, 0x24, 0x89, 0x79, 0xEA, 0xDD, 0x26, 0x8A, 0x07, 0x0C, 0xAD, 0x8E, 0x88, 0x7B, 0x97, 0x92, 0xB9, 0xE3, 0x00, 0xED, 0xB7, 0x75, 0x0E, 0x02, 0xCC, 0xAB, 0xC9, 0x5D, 0x00, 0x5C, 0x9E, 0x91, 0xD9, 0xBD, 0x81, 0x31, 0xE3, 0xC9, 0x8C, 0xFF, 0x80, 0x10, 0xDD, 0xBA, 0x1C, 0xD0, 0x68, 0x41, 0xAC, 0x03, 0x99, 0x12, 0x01, 0xEC, 0xB8, 0xF9, 0x72, 0x78, 0xEA, 0x60, 0xE0, 0xE4, 0x39, 0xAB, 0xDB, 0x80, 0xCF, 0xAB, 0x07, 0xA5, 0xB6, 0xF2, 0xBA, 0xBC, 0x12, 0xD7, 0xC9, 0x57, 0x2C, 0xF4, 0xEC, 0x90, 0x23, 0x9E, 0xB0, 0x36, 0x2E, 0x13, 0x8F, 0x76, 0x6E, 0xE1, 0x2D, 0x1E, 0xCA, 0x33, 0xDC, 0x26, 0x16, 0xAC, 0x6F, 0x14, 0x28, 0xE6, 0xDD, 0xD2, 0xF7, 0x13, 0x0F, 0xF4, 0x24, 0xF3, 0x76, 0x01, 0x6A, 0xD3, 0xC8, 0xFC, 0xE1, 0x40, 0xFB, 0x95, 0xE4, 0xC1, 0x9D, 0x80, 0xF3, 0x4B, 0xB2, 0x30, 0x4B, 0xFB, 0x9D, 0xA7, 0x32, 0x79, 0xF2, 0x15, 0x30, 0xEB, 0x08, 0x59, 0x32, 0x08, 0x58, 0xF1, 0xF3, 0x6F, 0xFC, 0xFB, 0x2F, 0x40, 0x6C, 0xEF, 0x1D, 0x95, 0x95, 0x7D, 0x81, 0x7D, 0xFF, 0x80, 0x3B, 0xF9, 0x73, 0x7F, 0x95, 0xEE, 0x56, 0x69, 0x67, 0x1F, 0x4A, 0x16, 0x5D, 0x04, 0x9A, 0x3D, 0xA9, 0xF3, 0x29, 0xD0, 0x60, 0x0E, 0x59, 0x18, 0x04, 0xD4, 0x7B, 0x4D, 0x9E, 0x8C, 0x05, 0x94, 0x5E, 0x91, 0xC7, 0xF2, 0x01, 0x84, 0x90, 0x47, 0x26, 0x00, 0xC8, 0x23, 0x0F, 0xD9, 0x01, 0x6A, 0x1A, 0x64, 0x7E, 0x6B, 0xF2, 0xE8, 0x64, 0x40, 0x59, 0x89, 0x3C, 0xF9, 0x00, 0x30, 0x9B, 0x44, 0x9E, 0xE9, 0x04, 0xD8, 0x27, 0x90, 0x57, 0x43, 0x01, 0xCF, 0x86, 0xE4, 0xDD, 0xFB, 0xC0, 0xC4, 0x77, 0x24, 0x09, 0x2C, 0x1C, 0x79, 0xFE, 0x58, 0xED, 0x5B, 0x20, 0xCE, 0xCF, 0xEF, 0x91, 0xE4, 0x7D, 0x25, 0x00, 0x39, 0xD3, 0xE9, 0x58, 0xF7, 0x0E, 0xAF, 0xF7, 0xFD, 0x22, 0x33, 0xE7, 0x1B, 0xEC, 0x9F, 0xFA, 0x8A, 0xCC, 0x3F, 0x03, 0xB8, 0xB7, 0x20, 0x0F, 0x7D, 0xD0, 0x58, 0xE1, 0x6A, 0x45, 0xE6, 0x3D, 0x6D, 0xBC, 0xC6, 0xE1, 0x1F, 0xB9, 0xFF, 0x0B, 0x60, 0x7A, 0x88, 0x2C, 0x30, 0x00, 0x8C, 0x46, 0x91, 0x79, 0x33, 0x01, 0x63, 0x90, 0xFB, 0x8A, 0xC9, 0x42, 0x02, 0x00, 0x79, 0x31, 0x54, 0xE3, 0x89, 0x4E, 0x26, 0x79, 0xA3, 0x01, 0xD0, 0xF5, 0x0F, 0xF9, 0xF8, 0x01, 0xE0, 0xB8, 0x94, 0x24, 0x1B, 0x6A, 0xF4, 0x0B, 0xB9, 0x75, 0x83, 0x04, 0xE6, 0x2F, 0x8E, 0x5E, 0x22, 0x6E, 0x2A, 0x06, 0xC4, 0xDC, 0x61, 0xE2, 0x70, 0xFF, 0xF4, 0x22, 0xE0, 0xB7, 0x1A, 0xB9, 0x7A, 0x36, 0x90, 0x61, 0x44, 0x66, 0xBC, 0x52, 0x1D, 0x1B, 0x3A, 0x96, 0xDC, 0xFE, 0xB4, 0x41, 0xC1, 0xB4, 0x19, 0xE4, 0xCE, 0x98, 0x06, 0xFE, 0x23, 0xF3, 0xEA, 0xBC, 0xDB, 0x40, 0x69, 0x90, 0x4F, 0x9D, 0xA9, 0x80, 0x6B, 0x53, 0x72, 0x57, 0x62, 0x9D, 0x20, 0x77, 0x1C, 0x25, 0x4B, 0xC6, 0x00, 0x2A, 0x9F, 0xC8, 0x9B, 0xAF, 0x95, 0xE7, 0x34, 0x34, 0x23, 0x9F, 0xD4, 0xE5, 0xB6, 0x6F, 0x49, 0x12, 0xE8, 0xD8, 0xE3, 0xF1, 0x53, 0xD1, 0x37, 0x7B, 0xD7, 0x38, 0x71, 0xD1, 0xA9, 0xF1, 0x06, 0x62, 0xD4, 0x74, 0x40, 0x8C, 0xCE, 0x6D, 0xB2, 0x86, 0x1C, 0xD8, 0x6C, 0x48, 0x98, 0xE4, 0xED, 0x83, 0xAC, 0x5A, 0x00, 0xB7, 0x67, 0xD6, 0x26, 0xAE, 0x28, 0x02, 0x76, 0x1F, 0x20, 0x37, 0x34, 0x02, 0x62, 0x97, 0x91, 0xC9, 0xD1, 0xC0, 0xA2, 0xA5, 0xE4, 0xD6, 0x24, 0x60, 0x7A, 0x2A, 0x99, 0x7E, 0x0A, 0xF0, 0x8F, 0x22, 0x33, 0x36, 0x02, 0x7E, 0xC9, 0x75, 0x99, 0xE4, 0xDD, 0xA6, 0x40, 0xBD, 0x32, 0xF2, 0x15, 0x00, 0xAD, 0x40, 0x45, 0xBF, 0x6E, 0xC6, 0x9B, 0xAE, 0xA2, 0x8D, 0xEA, 0xE9, 0x61, 0xE2, 0x98, 0x25, 0x11, 0xFF, 0x89, 0xD3, 0x87, 0x1B, 0xFE, 0x14, 0x67, 0xF4, 0x6A, 0x1C, 0x4B, 0x9A, 0xA5, 0x7B, 0xCF, 0xAD, 0x5F, 0x9F, 0x74, 0xAC, 0xE7, 0x35, 0xB4, 0xC5, 0x5D, 0x32, 0x76, 0x57, 0xC7, 0x63, 0x00, 0xF9, 0xD1, 0x69, 0x9C, 0x33, 0x70, 0x7B, 0x6A, 0xED, 0xE8, 0xC5, 0x4D, 0x95, 0xFE, 0x16, 0x2C, 0x26, 0x97, 0xC5, 0x01, 0x69, 0x03, 0xC8, 0xB5, 0xA7, 0x81, 0xB5, 0x55, 0xE4, 0xBA, 0xE7, 0x40, 0xF8, 0x20, 0x32, 0xD1, 0x13, 0x58, 0xB8, 0x89, 0xDC, 0x50, 0x4C, 0xBE, 0xEA, 0x02, 0xA8, 0x58, 0x91, 0x7F, 0x35, 0x80, 0xFA, 0x4F, 0xBE, 0x14, 0x91, 0x40, 0x93, 0x99, 0x57, 0x0F, 0x88, 0xF6, 0x5F, 0xB3, 0x3C, 0x49, 0xED, 0x84, 0x41, 0x4F, 0x7C, 0xD5, 0x48, 0xDD, 0x7A, 0xDE, 0xB6, 0x00, 0x65, 0x5D, 0xCB, 0xEB, 0x4F, 0x21, 0xDB, 0x74, 0xF4, 0x38, 0x81, 0x72, 0xB2, 0xDB, 0x12, 0x37, 0x27, 0x80, 0xEC, 0x5C, 0x6A, 0xF7, 0x49, 0xCC, 0xBE, 0xD2, 0x6D, 0x2A, 0x50, 0x33, 0xF6, 0x47, 0xE8, 0xB0, 0xDE, 0xC0, 0x03, 0x4B, 0x2E, 0x9D, 0xDE, 0x19, 0x38, 0xDD, 0x95, 0x9C, 0x6F, 0x0E, 0xEC, 0x09, 0x20, 0x97, 0x26, 0x00, 0x69, 0xE3, 0xC9, 0x98, 0xA9, 0x40, 0xC2, 0x39, 0x72, 0xB9, 0x36, 0xF9, 0x3D, 0x02, 0x50, 0x0F, 0xFE, 0x93, 0x4A, 0x02, 0x6A, 0xD9, 0x8F, 0xCF, 0x93, 0x06, 0xB6, 0x9A, 0xAD, 0x0E, 0xD5, 0x93, 0x6C, 0x5F, 0x1E, 0xBD, 0x8C, 0x6C, 0x76, 0xC3, 0xB6, 0x5F, 0xCB, 0x27, 0x92, 0x87, 0x47, 0x00, 0xE2, 0xE0, 0x6A, 0xA5, 0x51, 0xA4, 0x71, 0x9C, 0xDB, 0x5E, 0xC9, 0x5D, 0x1C, 0x9D, 0x6B, 0x44, 0xEB, 0xED, 0xF6, 0x7A, 0xDA, 0xFB, 0xC9, 0x0D, 0x27, 0x2D, 0x57, 0x49, 0xCE, 0x8B, 0xB7, 0xFC, 0x05, 0xD4, 0xDC, 0xFE, 0xBE, 0xD4, 0x6B, 0x2C, 0xF0, 0xE4, 0x2A, 0x33, 0x47, 0x1A, 0x01, 0x57, 0xB4, 0xC8, 0x09, 0x33, 0x80, 0xE3, 0x24, 0xA7, 0x27, 0x01, 0xFB, 0xA6, 0x92, 0x73, 0x46, 0xD5, 0xFC, 0x21, 0x01, 0xE5, 0x55, 0x2F, 0xA7, 0x8A, 0x5A, 0x2E, 0x17, 0x83, 0x48, 0xFD, 0x8D, 0xFA, 0x1B, 0x13, 0x0F, 0x4B, 0xB6, 0xCD, 0xEE, 0x3F, 0x5F, 0x74, 0x85, 0x7E, 0xB4, 0x38, 0xD0, 0xAD, 0x5E, 0x05, 0xA9, 0xBF, 0xAB, 0x57, 0x05, 0x40, 0x1A, 0xC3, 0x79, 0x90, 0xD8, 0x39, 0xDA, 0x6E, 0x8C, 0xE8, 0x8A, 0xEE, 0xD9, 0xCD, 0x8B, 0xC8, 0x85, 0xB3, 0x9B, 0x17, 0xA9, 0xDD, 0x26, 0xD3, 0x69, 0x2E, 0x8F, 0x63, 0x89, 0x7A, 0x47, 0x3D, 0x80, 0x79, 0x9F, 0xA7, 0x5B, 0x57, 0x01, 0x6F, 0xF2, 0xFF, 0xF4, 0x77, 0x9F, 0xDF, 0x80, 0xF7, 0xFB, 0x91, 0x7D, 0x6B, 0x81, 0x92, 0xDB, 0xE4, 0xC8, 0xF6, 0x64, 0xC4, 0x5B, 0x40, 0x65, 0x20, 0x39, 0x69, 0x2A, 0xD0, 0xE5, 0x1B, 0xE9, 0xB6, 0x01, 0x18, 0x30, 0x8B, 0x04, 0x80, 0x59, 0x11, 0x62, 0x8F, 0xB4, 0xC0, 0x64, 0xD1, 0x6F, 0xC6, 0x88, 0x5B, 0x62, 0xD0, 0x19, 0xDF, 0xA1, 0x62, 0xA2, 0xFE, 0xD0, 0x14, 0x71, 0x87, 0xD2, 0x10, 0x25, 0xF1, 0xD8, 0x8A, 0x21, 0xDD, 0xC9, 0xC6, 0x37, 0xAB, 0x6E, 0x38, 0x84, 0x55, 0x3B, 0x03, 0xA4, 0x5B, 0xF3, 0xF2, 0xC5, 0xE2, 0xF8, 0xF0, 0x0B, 0x0F, 0xC5, 0xA0, 0xE2, 0xA3, 0x31, 0xE2, 0xC2, 0xFA, 0xBB, 0xBA, 0x8B, 0x61, 0x15, 0x69, 0xB5, 0x62, 0x74, 0x24, 0xB9, 0xFC, 0x1D, 0xA0, 0xE4, 0x4F, 0x2E, 0x38, 0x0B, 0x74, 0xD8, 0x4B, 0x0E, 0xBA, 0x09, 0xF4, 0x2F, 0x25, 0x4D, 0x75, 0x80, 0xC9, 0x77, 0x48, 0xA0, 0x7D, 0xD7, 0xE0, 0xB9, 0xA2, 0x4F, 0xC2, 0xB8, 0x45, 0xA2, 0x7F, 0xE0, 0x98, 0x6A, 0x71, 0xC3, 0xE6, 0x21, 0x83, 0xC5, 0x1D, 0x4B, 0x87, 0xFE, 0x15, 0x8F, 0x9C, 0x1E, 0xD1, 0x85, 0x34, 0x73, 0x26, 0xBB, 0xBA, 0x7E, 0x0A, 0x00, 0xC8, 0xD1, 0x23, 0xAE, 0xDF, 0x11, 0x67, 0xB9, 0x9D, 0x9C, 0x29, 0x86, 0x36, 0xCC, 0x4D, 0x17, 0xA3, 0xF6, 0x6E, 0x75, 0x15, 0x57, 0xAC, 0x48, 0xD4, 0x17, 0x57, 0xA7, 0x92, 0xB1, 0xCE, 0x00, 0x40, 0x46, 0x06, 0x03, 0x66, 0x5D, 0xC8, 0xFE, 0x95, 0x80, 0xCF, 0x0A, 0xD2, 0x7A, 0x25, 0x10, 0xF8, 0x90, 0x04, 0xEA, 0x6F, 0x5C, 0xAA, 0x24, 0xF6, 0x5E, 0x13, 0xF4, 0x4D, 0x9C, 0x1A, 0x3A, 0xED, 0xAA, 0x18, 0xFF, 0x77, 0x62, 0x95, 0xB8, 0xE3, 0xD8, 0x68, 0x2F, 0xF1, 0x4C, 0x93, 0x91, 0x59, 0xA4, 0xFE, 0x21, 0xB2, 0xC7, 0xFD, 0x47, 0x1B, 0x21, 0xFD, 0x23, 0x8B, 0xE2, 0xC5, 0xFF, 0x62, 0xF7, 0x1D, 0x15, 0x97, 0xF7, 0xDC, 0x5A, 0x24, 0xAE, 0x99, 0xBD, 0x3E, 0x5F, 0x8C, 0xEF, 0x1D, 0xB3, 0x44, 0x4C, 0x08, 0x21, 0x13, 0x86, 0x01, 0x90, 0xB5, 0xC5, 0x03, 0xA6, 0xA5, 0xE4, 0xF8, 0x95, 0xC0, 0x80, 0x62, 0x72, 0xA8, 0x12, 0x30, 0x76, 0x2B, 0x09, 0x00, 0xCB, 0x76, 0x8A, 0x0E, 0xA9, 0x4B, 0xA7, 0x8A, 0xE3, 0xDF, 0x87, 0xAE, 0x14, 0xA3, 0x3B, 0x2D, 0xF9, 0x23, 0x66, 0x7D, 0x58, 0xBC, 0x54, 0xBC, 0xD4, 0x7C, 0x86, 0xDF, 0x6F, 0x17, 0x80, 0x9C, 0x64, 0x74, 0x69, 0xB7, 0x18, 0xBE, 0x36, 0x7F, 0x81, 0xB8, 0x5A, 0x39, 0x3D, 0x58, 0x5C, 0xA7, 0x15, 0xB7, 0x43, 0xDC, 0xF0, 0x5F, 0xF8, 0x4F, 0x71, 0x93, 0x67, 0x68, 0x23, 0x71, 0xF3, 0x40, 0x72, 0xD3, 0x5C, 0x00, 0xF2, 0x98, 0xD1, 0x80, 0x51, 0x1B, 0x32, 0x72, 0x37, 0x60, 0xF3, 0x9B, 0x0C, 0x48, 0x01, 0x46, 0xFF, 0x24, 0x9B, 0x1C, 0x01, 0xA2, 0xF6, 0x92, 0x56, 0x70, 0x74, 0x5E, 0x3A, 0x81, 0x04, 0x46, 0xD4, 0xAC, 0xBC, 0x20, 0x86, 0x7D, 0x5B, 0x6D, 0x23, 0x66, 0xB7, 0x5B, 0x7B, 0x50, 0xBC, 0x6F, 0xB2, 0x6A, 0x75, 0x59, 0x31, 0x40, 0xFE, 0x77, 0xE1, 0x68, 0x98, 0x18, 0xE7, 0x91, 0xDE, 0x51, 0xDC, 0xB8, 0x79, 0xCD, 0x68, 0x71, 0x4B, 0x76, 0xD8, 0x41, 0x31, 0x45, 0x79, 0x8E, 0xB6, 0x98, 0x56, 0x34, 0xD5, 0x43, 0xDC, 0x1A, 0x40, 0xA6, 0xA4, 0x00, 0x90, 0x35, 0xFD, 0x03, 0x9A, 0xC7, 0x90, 0xAB, 0xAE, 0x02, 0x36, 0x8D, 0xC8, 0x09, 0xEF, 0x80, 0x09, 0xC1, 0xE4, 0xD4, 0x7D, 0x0D, 0xFB, 0x4C, 0x4E, 0x26, 0x01, 0x9D, 0x35, 0x29, 0x7F, 0x45, 0x77, 0xAB, 0xCD, 0x22, 0x42, 0x8D, 0x93, 0xDF, 0x8A, 0x3B, 0xF2, 0x33, 0x07, 0x8B, 0x3F, 0x6C, 0x32, 0xED, 0x4E, 0x55, 0x03, 0xE4, 0xBA, 0x36, 0xE9, 0x46, 0x62, 0xEA, 0xF2, 0x15, 0x06, 0x62, 0xFA, 0xF9, 0x45, 0x06, 0x78, 0x4B, 0x66, 0xCE, 0x0C, 0x7A, 0xAD, 0xEC, 0x49, 0x66, 0x1D, 0x1C, 0x13, 0x02, 0x90, 0xD9, 0xCF, 0xFD, 0xA1, 0x31, 0x9F, 0xCC, 0x34, 0x25, 0xD3, 0x09, 0x00, 0x75, 0xEE, 0x05, 0x0C, 0xDB, 0x91, 0x9B, 0xA7, 0x03, 0xDD, 0x6D, 0xC8, 0x88, 0x89, 0xC0, 0x08, 0x77, 0x32, 0x24, 0x1F, 0x98, 0xE5, 0x46, 0x02, 0x40, 0xCE, 0x5B, 0xB2, 0xBD, 0x93, 0x5D, 0xF5, 0xD6, 0xCF, 0x92, 0x67, 0x69, 0xEF, 0xAC, 0x15, 0x4F, 0xB6, 0xDA, 0xBF, 0xA4, 0x3C, 0x0B, 0xF8, 0xED, 0xBA, 0xFF, 0xDA, 0xF6, 0x1E, 0x06, 0x41, 0x64, 0xFA, 0xF3, 0x70, 0x7D, 0x80, 0xDC, 0x79, 0x28, 0xA4, 0x4D, 0x83, 0xDD, 0x75, 0x76, 0x19, 0x5D, 0x26, 0x39, 0xB7, 0xEF, 0xB8, 0x6A, 0x9D, 0x62, 0x72, 0xFB, 0x47, 0x7F, 0xF3, 0x56, 0x99, 0x64, 0xD6, 0x9D, 0x71, 0x36, 0xB2, 0xF7, 0x92, 0x4E, 0x72, 0xDB, 0x6F, 0x00, 0xA8, 0x33, 0x1A, 0x30, 0x7C, 0x40, 0x66, 0x3C, 0x02, 0xAC, 0x06, 0x93, 0xA9, 0x17, 0x00, 0xCF, 0xE7, 0x64, 0x64, 0x3F, 0x60, 0x4E, 0x28, 0xE9, 0x5F, 0x0C, 0x6C, 0x98, 0x4E, 0x8E, 0xEB, 0xDE, 0xAE, 0x53, 0x9A, 0x1F, 0x09, 0x38, 0x18, 0x9C, 0x2A, 0xB8, 0xEB, 0x02, 0x1C, 0xFE, 0x7D, 0x7C, 0x44, 0xEA, 0x7D, 0xA0, 0x7C, 0xDC, 0xC9, 0x4B, 0xE1, 0xFF, 0xE9, 0x3F, 0x23, 0x0F, 0xE8, 0x8D, 0xAB, 0x04, 0xC8, 0x82, 0xA5, 0x93, 0xCF, 0x1A, 0xAF, 0x21, 0x73, 0xA7, 0x4F, 0x8A, 0xB6, 0xEC, 0x49, 0x6E, 0xFF, 0xE1, 0xB8, 0x12, 0x20, 0xF7, 0xDD, 0xB7, 0xDE, 0x0E, 0xB1, 0xC0, 0x5A, 0x47, 0xCC, 0xBD, 0x47, 0xEE, 0xFC, 0x06, 0x40, 0x8E, 0xA7, 0x00, 0x8D, 0x65, 0x5F, 0xE8, 0x18, 0xD0, 0x55, 0x8D, 0xDC, 0xBB, 0x53, 0xB9, 0x9E, 0x63, 0x2C, 0x99, 0x61, 0x06, 0x04, 0xAD, 0xAB, 0x73, 0xA4, 0x7A, 0xE9, 0x32, 0x75, 0x32, 0x5F, 0xBB, 0x55, 0xFE, 0xFA, 0xD3, 0x0F, 0x7B, 0x64, 0xD4, 0x00, 0x07, 0x82, 0x3A, 0xBB, 0x03, 0x2E, 0x73, 0xAF, 0x94, 0xE8, 0x3F, 0x52, 0xAE, 0x79, 0x14, 0x76, 0x73, 0x5B, 0xA7, 0x51, 0x00, 0x79, 0xBA, 0xAC, 0xDD, 0x59, 0xF1, 0xF8, 0x4D, 0x63, 0x7F, 0xF1, 0xC8, 0xCA, 0xE6, 0x87, 0xC4, 0x43, 0x4D, 0x9B, 0x58, 0x8A, 0xF9, 0x7F, 0x1A, 0x42, 0xCC, 0xEB, 0xA4, 0xD7, 0x40, 0xDC, 0xBF, 0x81, 0xDC, 0x3F, 0x1D, 0x00, 0xC8, 0xC3, 0x73, 0x80, 0x06, 0x0D, 0xC8, 0xA3, 0xBF, 0x80, 0x8E, 0xEF, 0xC9, 0x33, 0x81, 0x80, 0x93, 0x1B, 0x79, 0xF2, 0x0D, 0x30, 0x2D, 0x89, 0xBC, 0x71, 0x13, 0x98, 0x9B, 0xF8, 0x6E, 0xD3, 0xAB, 0x45, 0xC0, 0x12, 0xEB, 0x6D, 0x8B, 0x5E, 0x3C, 0x06, 0xB2, 0x06, 0x02, 0x17, 0xE3, 0xFC, 0x4B, 0x4E, 0xAB, 0x00, 0x51, 0xCE, 0x17, 0x4F, 0x1C, 0x7D, 0x0E, 0x38, 0x7D, 0x24, 0x8F, 0xBF, 0x00, 0x3A, 0x78, 0xD7, 0xD9, 0x19, 0x30, 0x7A, 0x42, 0x1E, 0xD5, 0x53, 0x5D, 0xD7, 0x66, 0x02, 0x79, 0x70, 0x91, 0x7E, 0xA4, 0x69, 0x14, 0x79, 0xE0, 0x45, 0x23, 0x3F, 0xD3, 0x1A, 0x72, 0x9F, 0xAD, 0xD6, 0x1E, 0xA3, 0x72, 0x72, 0x6F, 0x1B, 0xF2, 0x48, 0x06, 0x00, 0x90, 0x45, 0xBD, 0x80, 0x7A, 0xD6, 0xE4, 0x05, 0x6F, 0xA0, 0xBD, 0x3D, 0x79, 0xCD, 0x0F, 0x70, 0x36, 0x25, 0x1F, 0xBD, 0x07, 0x7C, 0xDA, 0x55, 0x2E, 0x91, 0x1D, 0xF3, 0x91, 0x38, 0x79, 0xF1, 0xE7, 0x6A, 0x60, 0xF1, 0x2F, 0xFF, 0x88, 0x6A, 0x07, 0x20, 0x6B, 0x23, 0xF0, 0x77, 0x59, 0x80, 0xCE, 0xBE, 0x0B, 0xC0, 0xEB, 0xA0, 0xA7, 0xE1, 0xBB, 0x36, 0x2B, 0x47, 0xC5, 0x1F, 0x27, 0xB7, 0xFD, 0x68, 0x50, 0x3A, 0xB7, 0x11, 0xB9, 0x6B, 0xB6, 0xE6, 0xAD, 0x31, 0xC5, 0xE4, 0x6E, 0x5D, 0xED, 0x11, 0x3E, 0xE1, 0x75, 0xF9, 0x0C, 0xE0, 0x32, 0x90, 0xCC, 0x75, 0xAD, 0xB7, 0xC7, 0xCD, 0x8F, 0xDC, 0xF9, 0x5E, 0xBD, 0xDC, 0x71, 0x11, 0xB9, 0xA3, 0x9C, 0x3C, 0x63, 0x02, 0x00, 0xE4, 0x25, 0x6F, 0xA0, 0x7E, 0x1C, 0x79, 0x2F, 0x45, 0xA5, 0xA8, 0xD1, 0x72, 0xF2, 0xA5, 0x16, 0xD0, 0x75, 0xF6, 0xCF, 0x15, 0x24, 0xE0, 0xE1, 0x53, 0xA2, 0x2E, 0x06, 0xF4, 0x5A, 0xD5, 0x59, 0x8C, 0x7E, 0xA6, 0x7F, 0x4A, 0xCC, 0x8C, 0x68, 0xA3, 0x46, 0x4E, 0xFC, 0x18, 0x9B, 0x66, 0x01, 0x72, 0x7F, 0xE7, 0x88, 0x65, 0xC0, 0x95, 0x22, 0x72, 0x59, 0x14, 0x90, 0xD3, 0x83, 0xDC, 0xD0, 0x1B, 0x58, 0x19, 0x45, 0x26, 0x1F, 0x01, 0x42, 0x2E, 0x91, 0x5B, 0x17, 0x02, 0x72, 0xBE, 0x96, 0x1E, 0x0A, 0xF8, 0xAF, 0xAF, 0xF3, 0x1F, 0x30, 0xA2, 0xB2, 0x4E, 0x92, 0x57, 0x1F, 0x01, 0x00, 0x59, 0x36, 0x0A, 0x50, 0x7D, 0x43, 0x7E, 0x6E, 0x09, 0xE8, 0x39, 0xFE, 0x39, 0x4A, 0x02, 0x26, 0x01, 0xB7, 0xCB, 0xC5, 0xBE, 0x23, 0x32, 0xE6, 0x8A, 0xD3, 0xF4, 0x87, 0x67, 0x89, 0xA1, 0x36, 0x80, 0x18, 0xED, 0x60, 0x62, 0x47, 0xFA, 0xD5, 0x1F, 0x9E, 0x61, 0x69, 0x4A, 0x2E, 0xBF, 0xDE, 0xB5, 0x01, 0x40, 0x7E, 0xBA, 0xE7, 0xA7, 0x03, 0xDC, 0x19, 0x59, 0x33, 0x32, 0xA4, 0x23, 0x70, 0xD0, 0x8B, 0x8C, 0x6E, 0x0C, 0xA4, 0x1B, 0x91, 0x6B, 0x7C, 0x80, 0x75, 0x01, 0x64, 0x5C, 0x28, 0x10, 0xD1, 0x90, 0x4C, 0xB0, 0x06, 0x16, 0x05, 0x91, 0xEB, 0x7F, 0x92, 0x8F, 0x4E, 0x03, 0x00, 0xF9, 0x79, 0x37, 0xA0, 0x76, 0xF8, 0x4F, 0xFB, 0xEA, 0x3D, 0x80, 0x56, 0xFD, 0x17, 0x8B, 0xC8, 0x36, 0x39, 0xBA, 0x1E, 0x87, 0x87, 0x90, 0x80, 0x57, 0xFF, 0xD0, 0xCD, 0xA2, 0x9F, 0x5E, 0x1B, 0x1F, 0x71, 0x62, 0x85, 0x5E, 0x7F, 0xD2, 0x2C, 0xB5, 0x9F, 0xAA, 0xDA, 0x72, 0xD2, 0x63, 0xA1, 0xC7, 0x25, 0x4B, 0x63, 0x72, 0x49, 0xEB, 0x0E, 0xBD, 0x01, 0x72, 0x5B, 0x57, 0x2B, 0x1D, 0xF1, 0xDB, 0xD0, 0x81, 0xB9, 0x40, 0xF9, 0xFC, 0x9A, 0x9D, 0x93, 0x97, 0x02, 0xC5, 0xED, 0xC9, 0x99, 0x2B, 0x80, 0xFC, 0xE6, 0xE4, 0xC2, 0x45, 0xC0, 0x36, 0x2F, 0x32, 0x3C, 0x1B, 0xD8, 0xE8, 0x4D, 0x46, 0xCD, 0x21, 0x3F, 0x2C, 0x06, 0x54, 0x2A, 0x6A, 0x2B, 0xAB, 0xDD, 0x80, 0x7A, 0xD9, 0x2F, 0x6B, 0x48, 0x40, 0x27, 0xB8, 0xB8, 0x89, 0xD8, 0x4D, 0x23, 0xF1, 0xA5, 0xE8, 0x8E, 0xC1, 0x4E, 0xA4, 0xAA, 0x96, 0xC7, 0x57, 0xF5, 0x27, 0x92, 0x87, 0xFE, 0x52, 0x1B, 0x49, 0x9A, 0xCE, 0xEB, 0x55, 0x05, 0x90, 0xDD, 0xF5, 0x5C, 0x5C, 0x45, 0xEB, 0x19, 0xB6, 0xA3, 0xB4, 0x3A, 0x91, 0x09, 0x8D, 0x2D, 0xEC, 0x25, 0xE7, 0x9E, 0xB3, 0x2C, 0x13, 0xBF, 0x4C, 0x73, 0x54, 0x03, 0x5E, 0x16, 0x56, 0xDB, 0xF4, 0xFF, 0x03, 0xDC, 0xFA, 0x4A, 0xFA, 0xBD, 0x02, 0xCE, 0xA6, 0x90, 0x01, 0x07, 0x81, 0x82, 0x32, 0x72, 0xDA, 0xD9, 0xDA, 0x17, 0xBF, 0x9E, 0x02, 0x2A, 0x47, 0x3E, 0xBD, 0xE6, 0x6C, 0x40, 0xCD, 0xE2, 0xB6, 0x09, 0xA9, 0x55, 0x5A, 0xBF, 0x4B, 0xEE, 0x2A, 0x12, 0xB0, 0xFA, 0x6F, 0xB1, 0x06, 0xD9, 0x28, 0xD5, 0xC2, 0xD7, 0xCA, 0x9B, 0xC4, 0x48, 0xB7, 0x0C, 0x80, 0x04, 0xFA, 0x8A, 0x34, 0xC9, 0x75, 0x4A, 0x15, 0x2D, 0x3B, 0xF6, 0xCC, 0x13, 0x9D, 0x6D, 0xBA, 0x2D, 0x34, 0x31, 0x20, 0x43, 0xBA, 0xE8, 0xDF, 0xAA, 0xFF, 0x95, 0x4C, 0xCB, 0x6F, 0x5F, 0xA3, 0xD8, 0xA5, 0x6D, 0x67, 0x6C, 0xE5, 0x41, 0x7E, 0x6F, 0x05, 0x00, 0x95, 0xAE, 0xD5, 0xCB, 0xED, 0xC7, 0x01, 0x8F, 0x12, 0x6A, 0x9E, 0x7A, 0xD8, 0x35, 0x58, 0x79, 0xC3, 0x89, 0xEC, 0xBB, 0xB2, 0xAA, 0x59, 0xB5, 0x23, 0xA0, 0xEA, 0x55, 0xD6, 0x86, 0x19, 0x40, 0x03, 0xBD, 0x53, 0xD6, 0xA4, 0x96, 0x87, 0x96, 0xC7, 0x2A, 0x7B, 0x12, 0xB0, 0x38, 0xDC, 0x4B, 0x4F, 0x74, 0xD9, 0xD9, 0xE8, 0x9E, 0xE8, 0x71, 0x0F, 0x20, 0x1B, 0xA4, 0xBA, 0x42, 0x34, 0x86, 0x8D, 0xAF, 0x68, 0x31, 0xA1, 0xEB, 0x41, 0xD1, 0xA1, 0xB8, 0x93, 0x9E, 0xE8, 0x8A, 0xF6, 0x3B, 0x54, 0x26, 0x91, 0x11, 0x30, 0x9B, 0xA4, 0xE2, 0x43, 0xA6, 0xD3, 0xCC, 0x07, 0x20, 0x0B, 0xA6, 0x9A, 0xDE, 0x36, 0x3F, 0x45, 0x7E, 0x74, 0x00, 0x00, 0x36, 0xFF, 0xF1, 0xC1, 0xBC, 0x03, 0xF0, 0x81, 0x35, 0x65, 0xDD, 0x5E, 0x93, 0x8B, 0xAD, 0x01, 0x80, 0x0C, 0xFE, 0x09, 0xE8, 0xFD, 0x24, 0xDD, 0x82, 0x00, 0xB7, 0x20, 0x52, 0xAB, 0x2D, 0xE0, 0x0F, 0x12, 0xE8, 0xF0, 0x60, 0x5C, 0x82, 0x38, 0x20, 0x59, 0x91, 0xFD, 0xA3, 0xFD, 0x9E, 0x88, 0xF1, 0xC3, 0x06, 0x1D, 0x11, 0x77, 0xDA, 0x0D, 0x32, 0x15, 0xCF, 0xAA, 0x0F, 0x76, 0x20, 0x1B, 0xFF, 0xA9, 0xFA, 0x6D, 0x1B, 0xFA, 0xB7, 0x12, 0x20, 0x6D, 0x63, 0x9E, 0x14, 0x8A, 0x43, 0xBA, 0x5C, 0xDA, 0x2C, 0xFA, 0x87, 0x9F, 0x54, 0x12, 0xA7, 0x9F, 0xDA, 0x7F, 0x4C, 0x9C, 0xF7, 0x3C, 0xBB, 0x9E, 0x18, 0x3A, 0x99, 0x0C, 0x53, 0xAC, 0x83, 0x4B, 0x4C, 0x00, 0xCD, 0x39, 0xA4, 0xFB, 0x46, 0xC0, 0x6B, 0x2B, 0xD9, 0xFA, 0x1E, 0x30, 0xA6, 0x92, 0x04, 0x34, 0xD3, 0xA6, 0x5F, 0x17, 0x7B, 0x7F, 0x98, 0x21, 0x19, 0x01, 0x53, 0x27, 0x7A, 0x90, 0x6D, 0x1A, 0x24, 0x64, 0xFB, 0x0C, 0x92, 0xBC, 0x63, 0x76, 0xC0, 0x48, 0xB1, 0xF8, 0xED, 0x68, 0x7F, 0xD2, 0xD4, 0x8A, 0x46, 0x9D, 0x4F, 0x7F, 0x99, 0x0D, 0x90, 0x7D, 0x1F, 0xDC, 0x6E, 0x22, 0x06, 0x1C, 0x2A, 0x9C, 0x28, 0x06, 0x15, 0x16, 0x38, 0x8B, 0x0B, 0x7B, 0x65, 0x7F, 0x11, 0xC3, 0xFC, 0x93, 0x0B, 0xC4, 0xA8, 0x26, 0x64, 0x4C, 0x47, 0x00, 0x72, 0x7C, 0x1D, 0x50, 0x1B, 0x4D, 0x0E, 0x3F, 0x03, 0xB8, 0x6E, 0x23, 0xBB, 0x7B, 0x01, 0xBE, 0x71, 0x24, 0x00, 0x2C, 0x50, 0x17, 0x5D, 0xDF, 0xCF, 0xEB, 0x2F, 0x8E, 0xCF, 0x0D, 0x3A, 0x2E, 0x2E, 0x38, 0x36, 0x3F, 0x42, 0xCC, 0x6A, 0x37, 0xAF, 0x9B, 0x58, 0x5A, 0x11, 0xB4, 0x91, 0x6C, 0x7E, 0x80, 0xEC, 0x91, 0xF3, 0xD4, 0x11, 0x20, 0xFD, 0xB7, 0x5D, 0x6C, 0x23, 0xCE, 0x8A, 0x3C, 0x62, 0x27, 0x86, 0x36, 0xDD, 0xB1, 0x56, 0x8C, 0x1C, 0x97, 0xFC, 0x52, 0x5C, 0xF6, 0x61, 0x9D, 0xBB, 0xB8, 0xB2, 0x8A, 0x5C, 0x99, 0x0C, 0x00, 0xE4, 0xAA, 0x61, 0x80, 0xB2, 0x3D, 0x19, 0xD2, 0x16, 0xE8, 0x64, 0x4E, 0x0E, 0xA9, 0x02, 0x06, 0x8C, 0x21, 0x01, 0x20, 0x62, 0x9A, 0x68, 0x5D, 0xB3, 0x34, 0x5F, 0x1C, 0xD7, 0x7F, 0x51, 0xB4, 0x18, 0x3A, 0x2F, 0xCC, 0x57, 0xCC, 0xD6, 0x8D, 0xFC, 0x24, 0x5E, 0xAF, 0x8A, 0x28, 0xAD, 0x35, 0x82, 0xF4, 0x27, 0xDC, 0x7C, 0x28, 0xCE, 0xF6, 0x3C, 0xD9, 0x47, 0xFC, 0x6F, 0xE2, 0x6E, 0x5F, 0x71, 0x59, 0xB3, 0x14, 0x73, 0x71, 0xD5, 0xDD, 0xF8, 0x72, 0x71, 0xAD, 0x67, 0xE4, 0x77, 0x31, 0x7E, 0x11, 0xB9, 0xB6, 0x05, 0x00, 0x39, 0xAE, 0xAF, 0x30, 0x52, 0x0B, 0xE8, 0xA0, 0x4C, 0x0E, 0x4D, 0x07, 0x86, 0x5E, 0x25, 0x01, 0x60, 0xB9, 0x0B, 0xD9, 0x2A, 0xA1, 0xEB, 0xF5, 0xA5, 0x85, 0x92, 0x07, 0x44, 0xC6, 0xDC, 0x17, 0x17, 0xB7, 0x5B, 0x35, 0x4C, 0xDC, 0x1E, 0xBA, 0x36, 0x55, 0x2C, 0xFF, 0x1A, 0xB7, 0xFB, 0xCD, 0x2F, 0x80, 0x9C, 0x7F, 0xF7, 0xCC, 0x2A, 0x31, 0xDC, 0x67, 0x6F, 0x3F, 0x71, 0x55, 0xCB, 0x94, 0xA3, 0x62, 0xDC, 0xB8, 0x35, 0x7B, 0xC4, 0xF5, 0xB3, 0xC2, 0x9D, 0xC4, 0xC4, 0xF2, 0x45, 0x59, 0xE2, 0xC6, 0xEE, 0x64, 0xC2, 0x71, 0x45, 0xFF, 0x86, 0xFD, 0x0A, 0x97, 0x6B, 0x03, 0xE6, 0xCB, 0x49, 0xDF, 0x8B, 0xC0, 0xF0, 0xEE, 0x64, 0x97, 0x6E, 0x40, 0xE8, 0x3E, 0x12, 0xD0, 0x8C, 0x5E, 0xAF, 0x27, 0x3A, 0xAD, 0x58, 0x17, 0x26, 0xCE, 0xFB, 0xB7, 0x21, 0x41, 0xDC, 0xA9, 0x93, 0x9C, 0x2B, 0x7E, 0x3D, 0x9E, 0x16, 0x75, 0x93, 0x90, 0xD7, 0x18, 0x95, 0xBF, 0x58, 0x5C, 0xEB, 0x9B, 0xDA, 0x57, 0x4C, 0x9C, 0xB9, 0x72, 0xA5, 0xB8, 0xD9, 0x33, 0xAC, 0x99, 0x98, 0x94, 0x15, 0xBC, 0x44, 0x4C, 0x99, 0x30, 0x65, 0x92, 0x98, 0x6A, 0x49, 0x6E, 0xFA, 0x0C, 0x40, 0x6E, 0x9B, 0xAA, 0x30, 0x61, 0x1A, 0x60, 0xF6, 0x88, 0x0C, 0xF7, 0x04, 0x5C, 0xCF, 0x91, 0x53, 0xFB, 0x6B, 0xCF, 0x9A, 0x6C, 0x49, 0x02, 0x40, 0x9A, 0xA7, 0x68, 0xB9, 0x3E, 0xAD, 0x4A, 0x9C, 0xDC, 0x2A, 0xFD, 0xB1, 0x78, 0x58, 0x7F, 0x87, 0xCD, 0x93, 0x21, 0xC0, 0xAB, 0x88, 0x1D, 0xA6, 0x87, 0xC7, 0x40, 0x7A, 0xAE, 0x6C, 0xCE, 0x53, 0xBC, 0x66, 0x94, 0xB6, 0x98, 0xB6, 0x63, 0xDE, 0x6A, 0x31, 0xA3, 0xC3, 0x54, 0x4B, 0x31, 0x33, 0x6C, 0xEC, 0x4A, 0x31, 0xAB, 0x64, 0xCC, 0x1C, 0xF5, 0xAE, 0x8A, 0xF9, 0x92, 0xF6, 0x1D, 0x80, 0xDC, 0x36, 0x52, 0x61, 0xC6, 0x7D, 0xA0, 0xE5, 0x0B, 0x32, 0xE1, 0x17, 0xE0, 0xA4, 0x41, 0x2E, 0xC8, 0x06, 0x66, 0x5E, 0x24, 0xC7, 0xA4, 0x03, 0xAB, 0xE7, 0x92, 0x5D, 0x0B, 0xD5, 0xAF, 0x64, 0x3A, 0xFF, 0x68, 0x03, 0xD8, 0x38, 0x1E, 0xEC, 0x5D, 0xEA, 0x05, 0x64, 0x9F, 0xCF, 0x6F, 0x98, 0xB2, 0x06, 0xB8, 0xB7, 0x3F, 0xDF, 0x66, 0x85, 0x57, 0x83, 0xD3, 0xE4, 0xDE, 0xCE, 0xF3, 0xAF, 0xD5, 0xBF, 0x47, 0xEE, 0x76, 0x09, 0x70, 0x03, 0xC8, 0xDC, 0xFC, 0x29, 0x21, 0x46, 0x9B, 0xC8, 0xEC, 0xD4, 0x29, 0xF1, 0x9D, 0xAC, 0xC9, 0x8C, 0x3E, 0x53, 0x42, 0x7A, 0x18, 0x92, 0xA9, 0x39, 0xC3, 0x6D, 0xDB, 0xFC, 0x52, 0xAC, 0x23, 0xBB, 0xB1, 0xA2, 0x7F, 0xB7, 0x85, 0xC2, 0xDC, 0xF5, 0x40, 0x73, 0x23, 0x32, 0x3B, 0x12, 0x70, 0x94, 0x19, 0x99, 0x03, 0x4C, 0xBA, 0x5E, 0xE7, 0x29, 0x20, 0x74, 0x49, 0x55, 0x6D, 0xCE, 0x0D, 0x60, 0xD5, 0xB9, 0xE2, 0x03, 0xC9, 0x93, 0x80, 0x6C, 0x63, 0x8B, 0x46, 0xCA, 0x57, 0xBA, 0xEB, 0x9D, 0x99, 0xD2, 0x46, 0xA9, 0x99, 0xE5, 0xF9, 0x1F, 0x45, 0xDE, 0x6D, 0x4C, 0x00, 0xB2, 0x28, 0xB9, 0xE5, 0x75, 0xF1, 0x58, 0x85, 0xA1, 0x99, 0x78, 0xF8, 0x71, 0xA3, 0xEE, 0xE2, 0x41, 0x73, 0x9D, 0xC1, 0x62, 0xBE, 0x91, 0x46, 0xBE, 0x78, 0x60, 0xB0, 0x8E, 0xBB, 0xB8, 0xB7, 0x9A, 0xDC, 0x53, 0x04, 0x40, 0x1E, 0x33, 0x41, 0xE1, 0xA9, 0x36, 0x80, 0x66, 0x21, 0x79, 0xA2, 0x01, 0xE0, 0x74, 0x92, 0x2C, 0xEA, 0xA4, 0xDC, 0x7F, 0x74, 0x5A, 0x95, 0xDF, 0xE5, 0x42, 0x60, 0x9C, 0xEE, 0x93, 0x5D, 0xCF, 0xFA, 0x02, 0x81, 0xAD, 0xB6, 0x36, 0x78, 0x94, 0x02, 0x6C, 0x50, 0x02, 0x4E, 0xA7, 0x8C, 0xFC, 0x76, 0xE8, 0x2E, 0x90, 0x54, 0xFF, 0xDC, 0xC9, 0x03, 0x2F, 0x9A, 0x26, 0x4D, 0x98, 0x4A, 0x1E, 0xF8, 0x00, 0xB8, 0x19, 0x92, 0xF9, 0x6B, 0x1B, 0x99, 0xB8, 0xED, 0x27, 0xF7, 0x6D, 0x03, 0x64, 0x22, 0xE7, 0x55, 0x00, 0x66, 0x63, 0xC9, 0x03, 0x49, 0x40, 0xEB, 0x5B, 0xE4, 0x7E, 0x75, 0xC0, 0xD8, 0x90, 0xCC, 0xA5, 0x9C, 0xB3, 0x29, 0xFA, 0x0B, 0xBF, 0x2B, 0x2C, 0x6D, 0xA8, 0x55, 0xA2, 0x5C, 0x43, 0x5E, 0xEF, 0x06, 0x58, 0x1F, 0xFB, 0x31, 0xE0, 0xC1, 0x0D, 0xC0, 0xF9, 0xF4, 0xD3, 0xF0, 0xAF, 0x37, 0x01, 0x97, 0xDF, 0x87, 0x0F, 0x57, 0x6A, 0x00, 0x93, 0x66, 0x4E, 0x6A, 0xF6, 0xEB, 0x3A, 0xB0, 0xFE, 0x21, 0xF0, 0x7D, 0x82, 0x9F, 0x47, 0x4E, 0x28, 0xF0, 0x7C, 0xF1, 0xD5, 0xC5, 0x99, 0xF3, 0x80, 0x3D, 0xDD, 0xC9, 0xCD, 0x19, 0x40, 0x74, 0x30, 0x99, 0x76, 0x07, 0x08, 0x76, 0x26, 0x33, 0xF6, 0xE1, 0x4B, 0xA0, 0x13, 0x99, 0x79, 0x18, 0xCF, 0xFD, 0x34, 0xC9, 0xAC, 0x06, 0x4A, 0xA6, 0x43, 0x86, 0xD7, 0x69, 0xA1, 0xB4, 0xA6, 0xFF, 0x2E, 0x32, 0x73, 0x0D, 0x79, 0x2E, 0x57, 0xD1, 0x7F, 0xC3, 0x5B, 0xE1, 0xBD, 0x67, 0x40, 0x23, 0xAB, 0xEA, 0x2B, 0xAF, 0xA7, 0x00, 0xC6, 0x53, 0x3E, 0xBC, 0x24, 0x81, 0x4E, 0xF6, 0xE7, 0xC7, 0x88, 0xFD, 0xE6, 0xAC, 0x35, 0xA0, 0x0F, 0x30, 0xDB, 0x7F, 0x48, 0x2C, 0xD9, 0xCE, 0x28, 0xAA, 0xA5, 0xB9, 0x2A, 0x19, 0x58, 0x16, 0xF3, 0x5F, 0x23, 0xD9, 0x75, 0xC2, 0xB2, 0x53, 0xC0, 0xAB, 0xD6, 0x5F, 0x9B, 0x84, 0x74, 0x05, 0x4E, 0xAC, 0x27, 0xC3, 0x67, 0x74, 0xC8, 0xDB, 0x3B, 0x9F, 0x0C, 0xF3, 0x00, 0x12, 0x8A, 0xC9, 0xB8, 0xD1, 0x40, 0xA4, 0x25, 0xB9, 0xEE, 0x0D, 0xB0, 0x78, 0x0B, 0x99, 0xE8, 0x05, 0xCC, 0xFC, 0x4B, 0x6E, 0x28, 0x23, 0x6F, 0xFE, 0xA7, 0xE8, 0x7F, 0x7A, 0x47, 0xFC, 0x37, 0xE6, 0x63, 0x19, 0x50, 0xFF, 0xED, 0xBB, 0x7D, 0xFF, 0xC2, 0x81, 0xA6, 0xBD, 0xAE, 0xEE, 0x22, 0x81, 0x6E, 0xD9, 0xE9, 0x05, 0xA4, 0x8A, 0xCE, 0x80, 0xE0, 0xD9, 0x57, 0x49, 0xE3, 0xD6, 0xBE, 0x06, 0x00, 0x09, 0x44, 0xAC, 0x36, 0x1E, 0x25, 0x53, 0xDC, 0x77, 0x89, 0xC5, 0x7B, 0x72, 0x9D, 0xA1, 0x4B, 0x7D, 0x80, 0x3C, 0xDC, 0xD5, 0x76, 0x19, 0xF0, 0x51, 0xA3, 0xFA, 0xD0, 0xC8, 0x85, 0xC0, 0x75, 0x77, 0xCE, 0x9D, 0xBC, 0x05, 0x38, 0x36, 0x81, 0x0C, 0xBE, 0x00, 0xEC, 0x8A, 0x26, 0x43, 0x55, 0x80, 0xE4, 0x33, 0x64, 0xC4, 0x6B, 0x20, 0x5E, 0x9B, 0x8C, 0x4A, 0x24, 0x9F, 0xA6, 0x02, 0x00, 0xF9, 0x65, 0x1D, 0xA0, 0x7C, 0xF5, 0x9D, 0x57, 0xE5, 0x09, 0x40, 0x63, 0xCA, 0xC3, 0x08, 0x52, 0x9F, 0xEA, 0x11, 0x79, 0x39, 0x24, 0x60, 0x35, 0x3D, 0xAA, 0x80, 0x34, 0x0C, 0xB4, 0x55, 0x76, 0x7F, 0x4B, 0x6A, 0xD9, 0xF5, 0xA9, 0x68, 0xD0, 0x9C, 0x6C, 0xF5, 0xD3, 0x73, 0x82, 0x52, 0x2B, 0xD2, 0x3D, 0xD6, 0xF5, 0x87, 0x85, 0x3A, 0x19, 0xB9, 0xAA, 0xCD, 0x02, 0x2D, 0xD9, 0x85, 0x52, 0xE9, 0x58, 0x0E, 0x90, 0x57, 0x0F, 0xB4, 0xDF, 0x0B, 0xFC, 0x3C, 0xFB, 0xE3, 0x88, 0xFB, 0x3B, 0xA0, 0xDC, 0xAA, 0x36, 0x78, 0xD0, 0x21, 0xE0, 0xCA, 0x18, 0xD2, 0x77, 0x23, 0x70, 0xCA, 0x96, 0xF4, 0xDF, 0x01, 0x1C, 0x68, 0x23, 0xD7, 0x6A, 0xB5, 0xAB, 0x2B, 0xD2, 0x01, 0x15, 0x8B, 0xCF, 0x2F, 0x2B, 0x8D, 0x81, 0xFA, 0xD6, 0xF7, 0x8E, 0xFC, 0x6D, 0x0A, 0x68, 0xED, 0x3F, 0xEB, 0x4D, 0x36, 0x9C, 0xDB, 0x40, 0x23, 0x36, 0x88, 0x04, 0xBA, 0x5D, 0xED, 0x1B, 0x28, 0xBA, 0xEB, 0xA8, 0xBE, 0x12, 0x07, 0xCD, 0x56, 0x7E, 0x4F, 0xB6, 0xB9, 0xEC, 0x96, 0x02, 0x90, 0x76, 0x37, 0x1C, 0xAF, 0x8B, 0x3D, 0x8B, 0x6D, 0xB5, 0xD4, 0x27, 0x92, 0xE1, 0xD5, 0xE6, 0xA3, 0x24, 0xA7, 0xC6, 0x77, 0x7C, 0x26, 0x5E, 0x7C, 0x66, 0xAE, 0xEB, 0xFE, 0x86, 0xE4, 0x3C, 0x00, 0xF8, 0xF8, 0xBB, 0xFA, 0x8B, 0xDD, 0x19, 0xC8, 0x3E, 0x91, 0xBD, 0x6B, 0x91, 0x5A, 0xF5, 0xD5, 0x6D, 0xA4, 0x67, 0x75, 0x55, 0xAE, 0xF4, 0x37, 0xD0, 0x2E, 0x9F, 0xFF, 0x63, 0x40, 0x9D, 0x9D, 0xCE, 0xCF, 0xAD, 0x6E, 0x0F, 0xE8, 0xAE, 0xCC, 0x79, 0x4F, 0x2A, 0x37, 0x32, 0x0C, 0x99, 0x05, 0x52, 0xB3, 0x4D, 0xFB, 0x68, 0x73, 0x7B, 0xCA, 0x3A, 0x2C, 0x01, 0xD1, 0xF3, 0x90, 0x68, 0xD2, 0xCB, 0x3E, 0x50, 0xEC, 0xBC, 0xA8, 0x2B, 0x45, 0xE7, 0xB1, 0x16, 0x67, 0x5B, 0x6C, 0x20, 0x03, 0x4D, 0xF4, 0x9A, 0x2B, 0x75, 0x23, 0x57, 0xD5, 0x33, 0xCB, 0x02, 0xC8, 0xF4, 0x60, 0xD3, 0x53, 0xE2, 0xC1, 0x03, 0x6D, 0x34, 0xBB, 0xE7, 0x93, 0x55, 0xC3, 0x01, 0xC9, 0x7F, 0x0F, 0x76, 0x38, 0x0D, 0x7C, 0x18, 0xC5, 0xF0, 0xCE, 0x39, 0xEF, 0x1E, 0xFE, 0x38, 0x0C, 0xA8, 0xCF, 0xBB, 0x52, 0xF1, 0x33, 0xA7, 0xCE, 0xD2, 0x03, 0x9F, 0xAA, 0xFF, 0x00, 0xBA, 0x4E, 0x11, 0x20, 0x01, 0x93, 0x81, 0x6E, 0x39, 0xA2, 0xDD, 0xFB, 0x86, 0xEF, 0x45, 0x57, 0x00, 0xA4, 0xCA, 0x06, 0x7B, 0x1D, 0xB1, 0x65, 0x7F, 0xAB, 0x7E, 0xA2, 0xE5, 0x6A, 0xF3, 0x0C, 0xD1, 0x6E, 0xA3, 0xD9, 0x3D, 0xD1, 0x15, 0xC6, 0xB7, 0xF5, 0x0B, 0xC8, 0xF9, 0x17, 0xF4, 0x0B, 0x24, 0xAF, 0xDE, 0xD5, 0xFA, 0x84, 0x98, 0x7E, 0xB9, 0xF5, 0x15, 0x31, 0x7F, 0xBE, 0x91, 0xA7, 0x78, 0x53, 0xB5, 0x25, 0x4D, 0x5E, 0x93, 0xDF, 0xA7, 0x48, 0x9A, 0x96, 0x0A, 0x88, 0x53, 0xF4, 0x15, 0x4A, 0x97, 0xD5, 0x3C, 0xD2, 0x18, 0x80, 0x57, 0x47, 0x12, 0xE8, 0x38, 0xCB, 0xF7, 0x93, 0xD8, 0x67, 0xD4, 0x28, 0x47, 0xD1, 0x1F, 0x23, 0xD4, 0x48, 0xED, 0x5D, 0xAB, 0x5F, 0x0D, 0xD8, 0x29, 0x79, 0x87, 0xEF, 0x30, 0x35, 0xF1, 0x42, 0x8B, 0xC1, 0x0B, 0x48, 0x3D, 0xDB, 0xAF, 0xB6, 0x36, 0x66, 0xBF, 0x1D, 0x01, 0xB2, 0xEB, 0xDF, 0x67, 0x2F, 0x45, 0x1B, 0xF3, 0x1B, 0x73, 0xC5, 0xBE, 0x3D, 0xCF, 0x24, 0x8B, 0xC3, 0x9B, 0x1C, 0xE9, 0x29, 0x8E, 0xBF, 0xBD, 0x6F, 0x96, 0x38, 0xA5, 0x1F, 0x39, 0xF3, 0x29, 0x00, 0xD4, 0x59, 0xA6, 0xB0, 0xD7, 0x19, 0xA0, 0xC7, 0x75, 0xD2, 0xE4, 0x01, 0xD0, 0xEF, 0x00, 0x09, 0x34, 0x4E, 0x98, 0xBC, 0x59, 0xEC, 0xF5, 0xDA, 0xFF, 0x81, 0xE8, 0xAF, 0x36, 0x6E, 0x05, 0x69, 0x3C, 0x6B, 0xED, 0xA3, 0x21, 0x7A, 0x92, 0xB7, 0xC7, 0x06, 0xF8, 0x88, 0x25, 0x23, 0xC7, 0x87, 0x93, 0xAD, 0x83, 0x7E, 0xE9, 0x39, 0xF5, 0xFE, 0x6C, 0x09, 0x90, 0x16, 0xF7, 0xEE, 0x7F, 0x13, 0xBD, 0x4E, 0x5C, 0x9C, 0x23, 0x8E, 0xA8, 0x77, 0xFC, 0xAD, 0x18, 0xA0, 0x9F, 0xE7, 0x21, 0x4E, 0xCB, 0xDC, 0x1E, 0x2F, 0x06, 0xB7, 0x25, 0xE7, 0xF6, 0x00, 0x80, 0x3A, 0x37, 0x2A, 0x1C, 0x58, 0x0A, 0x74, 0xBB, 0x49, 0x9A, 0x4E, 0x04, 0x06, 0x99, 0x90, 0x80, 0x46, 0xFB, 0x59, 0x96, 0xA2, 0x6B, 0xB3, 0x49, 0xAF, 0xC4, 0x80, 0xE9, 0x13, 0xD4, 0xC4, 0x90, 0xD0, 0x99, 0x79, 0x62, 0x56, 0xFD, 0xA0, 0x43, 0xE2, 0x15, 0xED, 0x69, 0xB6, 0xA4, 0xE5, 0xB5, 0xBF, 0x95, 0x9E, 0x07, 0x5F, 0xC4, 0x02, 0xA4, 0x4B, 0xE8, 0x75, 0x91, 0x23, 0xF4, 0x0B, 0xBB, 0x88, 0x01, 0x1D, 0x0F, 0x7A, 0x89, 0x33, 0x3C, 0x77, 0x8E, 0x14, 0xE7, 0xF9, 0xA5, 0x27, 0x89, 0x0B, 0xEF, 0x92, 0x0B, 0xCE, 0x03, 0x90, 0xE3, 0x2C, 0x85, 0x21, 0x95, 0x80, 0x66, 0x18, 0x69, 0xFB, 0x13, 0xE8, 0x67, 0x4E, 0x02, 0x98, 0xB5, 0x60, 0x83, 0xE8, 0x38, 0x34, 0xE8, 0x9A, 0x38, 0x2E, 0x7E, 0x86, 0xA3, 0x38, 0xDF, 0x24, 0x64, 0xB1, 0xB8, 0x4D, 0x63, 0x61, 0x37, 0xF1, 0xE6, 0xFB, 0x85, 0xF3, 0xC4, 0xBF, 0x1A, 0xB3, 0x07, 0x3F, 0xB0, 0x04, 0xC8, 0x41, 0x4F, 0x8B, 0xEF, 0x8B, 0x13, 0x94, 0x8F, 0x1C, 0x17, 0x83, 0x32, 0x76, 0xAF, 0x10, 0x43, 0x2E, 0x67, 0x2C, 0x15, 0x97, 0xDC, 0xDB, 0x90, 0x23, 0x46, 0xC8, 0xF1, 0x1E, 0x45, 0xFF, 0xD2, 0x86, 0x0A, 0x17, 0xBB, 0x03, 0xDA, 0x77, 0xC8, 0xFE, 0x19, 0x80, 0xC7, 0x67, 0x12, 0x00, 0xC2, 0xBA, 0x89, 0x5D, 0x94, 0x17, 0xAC, 0x12, 0x87, 0xAE, 0x58, 0xB8, 0x47, 0x0C, 0xBD, 0x10, 0x7A, 0x51, 0xCC, 0xB6, 0x8B, 0x98, 0x23, 0x3E, 0xF0, 0x8B, 0x2E, 0xFA, 0x9E, 0x0A, 0xFC, 0xE9, 0x17, 0xFA, 0xEE, 0xCA, 0x50, 0x80, 0x1C, 0x6F, 0x75, 0xD2, 0x44, 0x9C, 0x35, 0x79, 0x4F, 0x99, 0xB8, 0x68, 0x6B, 0x46, 0x95, 0x18, 0xBE, 0x71, 0xC3, 0x19, 0x31, 0x7A, 0xD7, 0xEA, 0x8F, 0xE2, 0xF2, 0x30, 0x32, 0x46, 0xF1, 0xF1, 0xE0, 0xB2, 0x04, 0x85, 0x31, 0x2A, 0x80, 0x5A, 0x05, 0xD9, 0xD7, 0x18, 0x18, 0xDC, 0x86, 0x34, 0x9E, 0x0E, 0xCC, 0xDD, 0x4B, 0x02, 0x4D, 0x7A, 0x45, 0xE5, 0x88, 0xEE, 0x35, 0xD1, 0x5E, 0xE2, 0x5C, 0x87, 0x15, 0xE1, 0xE2, 0x0E, 0x8F, 0xD8, 0x12, 0xF1, 0x5D, 0xD2, 0xBA, 0xD1, 0x0F, 0xAB, 0x81, 0x9F, 0x5B, 0x56, 0x9C, 0x3D, 0x75, 0x14, 0x20, 0xE7, 0x5E, 0xC8, 0x8D, 0x15, 0x23, 0x02, 0xD2, 0x76, 0x2B, 0x3A, 0x12, 0x26, 0x89, 0xAB, 0xB2, 0xA2, 0x1E, 0x8A, 0xB1, 0x87, 0x97, 0x50, 0x8C, 0x5B, 0x44, 0xC6, 0xB6, 0x54, 0xF4, 0xAF, 0xCD, 0x51, 0x18, 0xDF, 0x0F, 0x50, 0x2A, 0x25, 0xC7, 0x9D, 0x01, 0x06, 0xA6, 0x91, 0xC3, 0x42, 0xD5, 0xAE, 0x4F, 0x5C, 0x4A, 0x02, 0x40, 0xC2, 0x71, 0xB1, 0x87, 0x47, 0xC2, 0x1C, 0x71, 0x52, 0xC4, 0xC6, 0xF8, 0xDF, 0xC7, 0x80, 0xEC, 0xDA, 0xD4, 0x29, 0x65, 0x45, 0xC0, 0x93, 0xE8, 0x94, 0x2F, 0x47, 0x3B, 0x00, 0x5F, 0xED, 0x93, 0x5E, 0x64, 0x9D, 0x04, 0xC8, 0xD5, 0x57, 0x12, 0xF2, 0xC4, 0x84, 0x7D, 0x11, 0xCB, 0xC5, 0xC4, 0x92, 0xD0, 0xF5, 0xE2, 0x46, 0xFF, 0xA0, 0x48, 0x31, 0x69, 0xC8, 0xC4, 0xB1, 0xE2, 0x96, 0xB9, 0xE4, 0xC6, 0x1B, 0x00, 0xE4, 0xB6, 0x4F, 0x0A, 0x53, 0x96, 0x00, 0xAA, 0x55, 0x8A, 0xF3, 0x43, 0x87, 0x28, 0x72, 0xA6, 0x26, 0x30, 0x21, 0x92, 0x9C, 0xDC, 0x57, 0xFF, 0x5A, 0x48, 0x5D, 0xB6, 0xEE, 0xA3, 0xD3, 0x37, 0x49, 0xE9, 0x71, 0x5B, 0xA0, 0xF3, 0xAE, 0xDD, 0xA5, 0x27, 0x87, 0x03, 0x89, 0xC7, 0x76, 0x6E, 0xD9, 0xEC, 0x07, 0xDC, 0x78, 0xBA, 0xE3, 0xD7, 0x12, 0x65, 0xE0, 0xB3, 0xE5, 0x3E, 0x8F, 0x79, 0x5E, 0x00, 0x99, 0x59, 0x3B, 0x79, 0x98, 0x98, 0xBD, 0x23, 0xE0, 0xBA, 0x46, 0x7D, 0x32, 0xAB, 0x83, 0xBF, 0x57, 0x63, 0x13, 0x32, 0x7D, 0x94, 0xDF, 0xAA, 0x46, 0xB3, 0xEA, 0x54, 0xF2, 0xBE, 0xAC, 0x23, 0x52, 0xFE, 0x2A, 0xFA, 0xB7, 0xFD, 0x52, 0xB8, 0xA3, 0x05, 0xA0, 0x3D, 0x81, 0xCC, 0x68, 0x0F, 0xF4, 0x74, 0x26, 0xD3, 0xE7, 0x01, 0x83, 0x7B, 0x92, 0xD9, 0x7D, 0x81, 0xA9, 0x6B, 0x5E, 0xE8, 0x67, 0x6E, 0x07, 0x16, 0xA9, 0x1F, 0x0D, 0x8B, 0x77, 0x00, 0x36, 0x8D, 0xB4, 0x08, 0x50, 0x6F, 0x69, 0x99, 0x7A, 0xAC, 0x46, 0xAF, 0xBF, 0xE1, 0xD8, 0x33, 0x83, 0x8F, 0xF9, 0xB5, 0x4C, 0x69, 0xBC, 0xF2, 0x4B, 0xEB, 0xE3, 0xE6, 0x7A, 0x8E, 0x00, 0x79, 0x04, 0xF5, 0xB3, 0xC4, 0x43, 0x7D, 0x54, 0xEE, 0x89, 0xF9, 0xEF, 0xEB, 0xB5, 0x11, 0x0F, 0x54, 0x28, 0xDC, 0x77, 0x41, 0xB3, 0xBF, 0x98, 0xDB, 0x8F, 0x94, 0xAF, 0x60, 0x80, 0xCC, 0x0B, 0x52, 0x78, 0x98, 0x40, 0x83, 0xFD, 0xE4, 0xD1, 0xF1, 0x40, 0xF7, 0xD1, 0x64, 0x71, 0x26, 0x5E, 0xBA, 0x3F, 0x78, 0x59, 0x5C, 0x32, 0x07, 0xF0, 0x7A, 0x76, 0x13, 0xF7, 0x2E, 0x03, 0x83, 0x06, 0x6C, 0xD2, 0xBC, 0x3E, 0x0E, 0x88, 0xDA, 0x07, 0x1C, 0xD0, 0xF0, 0xBC, 0xB6, 0x67, 0x2C, 0xB0, 0xB9, 0xFF, 0xC9, 0x6B, 0xDB, 0x83, 0x80, 0xB9, 0xDD, 0x7E, 0x98, 0xEF, 0x76, 0xD1, 0x32, 0x19, 0x72, 0x8D, 0xDC, 0xD5, 0x1A, 0x70, 0x59, 0x4E, 0xEE, 0x76, 0xAD, 0x6F, 0xE1, 0x6E, 0x4D, 0xEE, 0x08, 0x50, 0xCF, 0x70, 0x6C, 0x5F, 0xA7, 0xB3, 0x5A, 0x85, 0xCD, 0x3E, 0x72, 0xFB, 0x25, 0xD5, 0xF0, 0x6E, 0xB7, 0xC8, 0x9C, 0x30, 0xF2, 0xF0, 0x3D, 0x45, 0x7F, 0xE1, 0x6F, 0x85, 0x17, 0x94, 0x55, 0xDB, 0x2B, 0xDF, 0x25, 0xAF, 0x07, 0x03, 0xED, 0xF4, 0x3E, 0xD8, 0xDE, 0x33, 0xA9, 0xB3, 0xF5, 0x9D, 0xC2, 0x37, 0x23, 0x80, 0xF6, 0x8B, 0xF3, 0xDC, 0x3E, 0xBB, 0x03, 0x03, 0xAC, 0x82, 0xD6, 0x57, 0x98, 0x03, 0x61, 0xBB, 0x80, 0x0F, 0x1D, 0x7C, 0xBE, 0x6E, 0x59, 0x00, 0x3C, 0xD5, 0xBC, 0xBC, 0x65, 0x43, 0x29, 0x70, 0xDC, 0xFA, 0x63, 0x0F, 0xD9, 0x1B, 0x8E, 0x0F, 0x20, 0xD7, 0x6D, 0x06, 0xC2, 0xFE, 0x91, 0x1B, 0x82, 0x81, 0xB9, 0x8E, 0xE4, 0xE6, 0x3A, 0x27, 0x17, 0x93, 0x49, 0x25, 0x80, 0x7F, 0x2E, 0xB9, 0xA5, 0x25, 0x30, 0x46, 0xA9, 0xCE, 0x5E, 0x5C, 0x5A, 0xBC, 0x56, 0xD1, 0x7F, 0x7D, 0x9C, 0x58, 0x3D, 0xE6, 0x5E, 0x17, 0x40, 0xDD, 0xAE, 0xA2, 0x53, 0xF9, 0x3D, 0x40, 0x2F, 0xAA, 0x4C, 0xAF, 0x72, 0x3C, 0x60, 0x70, 0xFE, 0xD4, 0xBC, 0x3F, 0x71, 0x40, 0xF7, 0x76, 0xAB, 0x77, 0xFE, 0x33, 0x07, 0xFC, 0x94, 0xED, 0x14, 0xFB, 0x42, 0x7F, 0x01, 0xB2, 0xFF, 0xAC, 0x95, 0x57, 0x00, 0x8E, 0xCF, 0x35, 0x88, 0x76, 0x06, 0x3E, 0x69, 0x3E, 0xB7, 0x5D, 0x54, 0x0C, 0x9C, 0xBB, 0x45, 0x4E, 0x8D, 0x01, 0x0E, 0x2C, 0x23, 0x17, 0x98, 0x01, 0x19, 0xAF, 0xC8, 0xB0, 0x04, 0x20, 0x61, 0x07, 0x19, 0x35, 0x05, 0x58, 0xA9, 0x4D, 0xC6, 0x14, 0x01, 0xE1, 0x66, 0xE4, 0xF2, 0xF5, 0xF4, 0xBE, 0xE5, 0x0B, 0x00, 0x5C, 0xFF, 0xD4, 0x49, 0x7C, 0x7F, 0xF6, 0xF1, 0x14, 0xA0, 0xBE, 0xD9, 0x7D, 0x97, 0x8F, 0x87, 0x00, 0xD5, 0x61, 0xE7, 0xCF, 0xD4, 0x78, 0x03, 0xCD, 0x36, 0x6E, 0x1D, 0x41, 0x02, 0xD6, 0xCB, 0x43, 0x5F, 0x91, 0x16, 0x0B, 0x1C, 0x76, 0x01, 0x92, 0x43, 0x5B, 0x34, 0x1D, 0x48, 0x0E, 0x7D, 0xE2, 0x1B, 0xD9, 0x41, 0xAE, 0x84, 0x36, 0xB8, 0x1D, 0x06, 0xC8, 0xBD, 0x7B, 0xFB, 0xB5, 0x01, 0xBE, 0xAE, 0xAA, 0xF9, 0xEE, 0xB0, 0x12, 0x78, 0x70, 0x9C, 0xF4, 0xFE, 0x0A, 0x94, 0xB8, 0x93, 0x23, 0xA7, 0x01, 0xC7, 0x66, 0x91, 0xFE, 0x63, 0x80, 0xBD, 0x87, 0xC9, 0x69, 0xCD, 0x81, 0xCC, 0xBF, 0xE4, 0xAC, 0xA0, 0xEA, 0xF7, 0x4F, 0x56, 0x00, 0xC0, 0xD7, 0x92, 0x97, 0xBE, 0x40, 0xFD, 0xA5, 0xF7, 0xE7, 0xBC, 0x55, 0x06, 0x54, 0x8C, 0x8A, 0xAB, 0x2A, 0x23, 0x00, 0x0D, 0xA7, 0xDC, 0xAB, 0xB5, 0xD3, 0x80, 0x66, 0x3F, 0xC2, 0xC2, 0x48, 0xDD, 0x47, 0x1D, 0xD7, 0xB9, 0x97, 0x90, 0xCA, 0x11, 0xEE, 0x36, 0x2A, 0xA7, 0xC9, 0xC6, 0x46, 0x1E, 0xDE, 0x00, 0xE9, 0x1E, 0xE6, 0xE8, 0x66, 0xEE, 0x49, 0x46, 0xFB, 0x36, 0xB3, 0x52, 0x3F, 0x4C, 0xAE, 0xFB, 0x64, 0x6E, 0x02, 0x90, 0x57, 0xDE, 0x98, 0x0C, 0x72, 0xF6, 0x27, 0xB9, 0x19, 0x00, 0x2A, 0x3A, 0xD6, 0x06, 0xDA, 0xB8, 0x00, 0xF7, 0xCF, 0x92, 0x0E, 0xC3, 0x55, 0xFE, 0x5E, 0x79, 0x4A, 0xBA, 0xCF, 0x02, 0x8A, 0x96, 0x93, 0x03, 0x3A, 0x55, 0x7D, 0x7C, 0x3D, 0x0D, 0xA8, 0x3F, 0xEA, 0x71, 0xE9, 0x3B, 0x37, 0x40, 0xE3, 0x7C, 0x89, 0x6E, 0x45, 0x29, 0xA0, 0x92, 0x9A, 0xB7, 0xEC, 0xC7, 0x77, 0x40, 0x47, 0x79, 0xD5, 0x47, 0x12, 0x68, 0x7D, 0xA7, 0xCF, 0x16, 0xD1, 0x31, 0x46, 0xE7, 0x92, 0xD8, 0x6B, 0x0A, 0x40, 0xB6, 0xB0, 0x74, 0x7E, 0x2F, 0xBA, 0x5D, 0xED, 0x61, 0x6C, 0xD6, 0x44, 0xA6, 0x55, 0x93, 0x67, 0xAD, 0x66, 0x91, 0x61, 0x7B, 0x0D, 0xBA, 0x02, 0x64, 0xFA, 0x20, 0x93, 0xB1, 0x62, 0xFE, 0x13, 0xD3, 0x5F, 0x5D, 0x9E, 0x93, 0xDF, 0x2E, 0x03, 0x46, 0x9B, 0x49, 0xDE, 0x56, 0xD7, 0x00, 0xBE, 0x2C, 0x20, 0x2D, 0x4E, 0x00, 0xE5, 0xA9, 0x64, 0xE7, 0xB4, 0xF7, 0xD1, 0x1F, 0x56, 0x01, 0x9A, 0x9B, 0xAF, 0xDF, 0xFB, 0xD8, 0x17, 0x50, 0xF3, 0x3B, 0x72, 0xE7, 0xCB, 0x5E, 0x40, 0xFD, 0x54, 0xCA, 0xDB, 0x7F, 0x9F, 0x00, 0x6D, 0xC3, 0x49, 0x3E, 0xA4, 0xEA, 0x34, 0xB3, 0x22, 0x23, 0x55, 0x12, 0xF0, 0x70, 0x02, 0x44, 0xB7, 0x93, 0xA2, 0xD1, 0xDE, 0x1E, 0xAD, 0x45, 0xDB, 0x0B, 0x96, 0xAF, 0x45, 0xBB, 0x78, 0xF3, 0x6B, 0x4D, 0x55, 0xC9, 0xA0, 0x5B, 0x8D, 0xD4, 0x24, 0x2F, 0x4F, 0x69, 0x55, 0x23, 0xA6, 0x9E, 0x6A, 0xD5, 0x47, 0xDC, 0xBD, 0xBD, 0xD5, 0x23, 0xB1, 0xF4, 0x75, 0x6B, 0xFD, 0x0E, 0xD9, 0x64, 0xE5, 0x57, 0xA0, 0xD9, 0x48, 0xB2, 0x26, 0xAE, 0xDE, 0xBB, 0xB2, 0x73, 0x15, 0xE5, 0x40, 0x03, 0xF7, 0xC2, 0xB1, 0x15, 0x56, 0x80, 0xCA, 0xB7, 0xEC, 0xF4, 0xAA, 0x31, 0x80, 0x7A, 0xFC, 0xA2, 0xD7, 0x24, 0xD0, 0xA2, 0x9D, 0x5B, 0x90, 0xD8, 0xAD, 0x4A, 0x3B, 0x5E, 0x74, 0xD6, 0x05, 0xC4, 0x9E, 0x8D, 0xC5, 0xE6, 0x37, 0x2D, 0xD5, 0xC5, 0x4E, 0xC7, 0xCC, 0xC2, 0x45, 0x57, 0x18, 0x39, 0x89, 0x9E, 0xD1, 0xCD, 0x22, 0xB5, 0x9D, 0xC8, 0xE0, 0xA7, 0xDA, 0x92, 0x19, 0xED, 0x61, 0x78, 0x44, 0x4C, 0x5A, 0xD4, 0x74, 0xB1, 0x98, 0xB3, 0xB4, 0xE9, 0x6E, 0xF1, 0xA8, 0x91, 0xE1, 0x24, 0xF1, 0xA6, 0x4B, 0x93, 0x62, 0x72, 0x48, 0x09, 0x00, 0xD4, 0x79, 0x59, 0x61, 0xCF, 0xE1, 0x80, 0xC9, 0x16, 0x52, 0x92, 0xB7, 0x93, 0x68, 0x11, 0xD2, 0x3F, 0x44, 0xEC, 0xEB, 0xD8, 0x5F, 0x59, 0xF4, 0x47, 0x1F, 0x4F, 0x71, 0x85, 0xB5, 0x97, 0xB5, 0xB8, 0x1D, 0x7D, 0x1E, 0x88, 0xC5, 0x31, 0x7D, 0x0C, 0x49, 0x1D, 0xB7, 0xCF, 0xAE, 0x9D, 0xDD, 0x6A, 0x47, 0x03, 0xA4, 0xA5, 0xD5, 0x0B, 0x2B, 0xD1, 0x34, 0xF8, 0x8E, 0x9D, 0xD8, 0xAE, 0x57, 0x89, 0x86, 0xD8, 0xE3, 0x52, 0xA1, 0x48, 0xD7, 0xE0, 0xC3, 0xD3, 0xC4, 0x7E, 0x4B, 0xC9, 0x61, 0x51, 0x00, 0x50, 0x67, 0xA0, 0x42, 0x17, 0x2D, 0xA0, 0xCD, 0x20, 0x52, 0xD2, 0x88, 0xBE, 0x62, 0xE7, 0x75, 0x03, 0x3E, 0x89, 0xBD, 0x5D, 0x87, 0x3C, 0x12, 0xC7, 0x4F, 0x1A, 0x68, 0x49, 0xEA, 0x5E, 0x5E, 0x39, 0xA3, 0xCF, 0x64, 0xC9, 0xDB, 0xB5, 0x86, 0x4C, 0x11, 0x2F, 0xEC, 0x1A, 0xEA, 0x47, 0x36, 0x79, 0xFF, 0xFD, 0x51, 0x0F, 0xBF, 0xBF, 0xD1, 0x00, 0x69, 0x61, 0x52, 0x56, 0x26, 0x1A, 0x35, 0xBB, 0xFA, 0x53, 0xB4, 0x36, 0x3B, 0x1B, 0x29, 0xBA, 0x86, 0x1F, 0x13, 0xD9, 0x6F, 0x4C, 0xDE, 0x3A, 0xD1, 0x67, 0x1A, 0x39, 0xF2, 0xB4, 0xA2, 0x7F, 0x44, 0xB8, 0x42, 0xD7, 0x51, 0x40, 0x5B, 0x2D, 0xB2, 0xF5, 0x1B, 0xC0, 0xF3, 0x08, 0x09, 0xB4, 0xF3, 0x1A, 0xA1, 0x2B, 0x3A, 0xD9, 0xFB, 0x56, 0x89, 0x01, 0x3D, 0x7D, 0x6A, 0xC9, 0xA6, 0xE1, 0x2B, 0x2A, 0xBD, 0x8B, 0x25, 0xE7, 0x0C, 0x1F, 0x15, 0x22, 0x96, 0xDC, 0x19, 0x1D, 0x4B, 0x1A, 0xF7, 0xF9, 0x39, 0xDF, 0x61, 0xE2, 0x37, 0xE9, 0x61, 0x57, 0xA3, 0x7B, 0x23, 0xC4, 0xCE, 0x56, 0x25, 0x0D, 0x44, 0x97, 0x21, 0xA7, 0x96, 0x8B, 0x7D, 0xE7, 0x1C, 0x9C, 0x25, 0xFA, 0x3C, 0xC9, 0x8D, 0x16, 0xC7, 0x4C, 0x24, 0x47, 0x17, 0x2A, 0xFA, 0xFD, 0xCC, 0x15, 0xF6, 0xEF, 0x0A, 0xB4, 0x71, 0x27, 0xE5, 0x9C, 0xB6, 0x5F, 0x36, 0x09, 0x68, 0xC4, 0x06, 0x2A, 0x8B, 0x8E, 0x89, 0x63, 0x17, 0x88, 0xFE, 0xE1, 0x63, 0x46, 0x8A, 0xF3, 0xAA, 0x26, 0xAD, 0x14, 0x73, 0xB6, 0x4E, 0x54, 0x12, 0xAF, 0xB8, 0x06, 0x16, 0x88, 0x3F, 0xC2, 0x46, 0xBF, 0x7C, 0x1D, 0x03, 0x90, 0xBD, 0x6B, 0xAE, 0xC4, 0x8B, 0x2E, 0x2B, 0x8B, 0x22, 0xC4, 0xFE, 0xDD, 0x0F, 0x7B, 0x89, 0x23, 0x96, 0xED, 0x59, 0x25, 0x8E, 0xFF, 0x96, 0xAD, 0x2D, 0x4E, 0xDE, 0x4F, 0x4E, 0xEF, 0xA9, 0xE8, 0x9F, 0xB4, 0x45, 0xE1, 0xCC, 0x9D, 0x0A, 0xDB, 0x07, 0x01, 0x03, 0x74, 0x49, 0x40, 0xC9, 0x61, 0x5A, 0xBA, 0x68, 0x3B, 0x2F, 0xB0, 0x9D, 0xE8, 0xB7, 0x2E, 0x30, 0x53, 0x9C, 0x9B, 0x3B, 0xAB, 0xBD, 0x98, 0xB5, 0x30, 0xB8, 0x52, 0xBC, 0xFB, 0x62, 0xDE, 0xF4, 0x2F, 0xDB, 0x80, 0xEF, 0x4B, 0x67, 0xB8, 0xDD, 0xAB, 0x02, 0x48, 0xDF, 0x96, 0x45, 0xCD, 0xC4, 0x21, 0x29, 0x07, 0x6B, 0xC5, 0x71, 0x11, 0x7B, 0x42, 0xC4, 0xC9, 0xDD, 0x32, 0xA7, 0x8B, 0x33, 0xDB, 0x27, 0xAB, 0x89, 0x73, 0xF3, 0xC9, 0x79, 0x61, 0x8A, 0xDE, 0x59, 0x27, 0x15, 0x2E, 0xB0, 0x53, 0xE8, 0xF1, 0x0E, 0xF0, 0xA8, 0x47, 0x1A, 0x3F, 0xC3, 0xA7, 0x80, 0x3E, 0x24, 0xD0, 0x76, 0xEC, 0x9C, 0x14, 0xB1, 0x4F, 0x8B, 0x10, 0x7B, 0x71, 0xDE, 0x95, 0x45, 0x07, 0xC5, 0xEC, 0x0D, 0x11, 0x3B, 0xFE, 0x2E, 0x06, 0x1E, 0xAD, 0x8B, 0x9A, 0x7A, 0x6F, 0x09, 0x50, 0x39, 0x7F, 0x89, 0xD2, 0x19, 0x55, 0x80, 0x0C, 0x5A, 0x94, 0x17, 0x2C, 0x4E, 0x9F, 0x96, 0xDD, 0x42, 0x9C, 0xFB, 0x29, 0x4D, 0x55, 0x5C, 0x74, 0x28, 0xBE, 0xBF, 0x18, 0xA6, 0xB7, 0x3C, 0x5E, 0x8C, 0x08, 0x23, 0xA3, 0xD2, 0x14, 0xBD, 0xA1, 0xA7, 0x14, 0xC6, 0x74, 0x56, 0x38, 0xA8, 0x0F, 0xD0, 0x3F, 0x8E, 0xB4, 0x7B, 0x02, 0x8C, 0xBF, 0x41, 0x02, 0xC0, 0xB2, 0x57, 0x62, 0x8F, 0x86, 0xCB, 0x42, 0x6A, 0x5F, 0x02, 0x13, 0x96, 0xAD, 0x72, 0x7F, 0xDB, 0x03, 0x48, 0x0A, 0x5C, 0xEB, 0x7B, 0xAF, 0x0F, 0x70, 0xBF, 0x4D, 0xEC, 0xB9, 0x82, 0x49, 0xC0, 0x17, 0xA3, 0xB5, 0xF7, 0x73, 0xB2, 0x00, 0x72, 0xE5, 0xE5, 0x0D, 0xF9, 0x62, 0x8C, 0xFB, 0x6A, 0x03, 0x71, 0xC5, 0xEF, 0x88, 0x18, 0x71, 0x55, 0xF9, 0xA2, 0xA7, 0x62, 0xAC, 0x73, 0xB0, 0x81, 0x18, 0xE7, 0x40, 0xC6, 0xB5, 0x57, 0xF4, 0xAE, 0xBD, 0xA8, 0x30, 0xA1, 0x9F, 0xC2, 0xF0, 0x43, 0x80, 0x75, 0x38, 0x39, 0xE1, 0x0A, 0x30, 0xD2, 0x83, 0x1C, 0x37, 0x5D, 0xA7, 0x7C, 0x5A, 0xBB, 0x4F, 0x61, 0x06, 0xC9, 0xC0, 0x86, 0x19, 0xA5, 0x6D, 0x80, 0xF6, 0x86, 0x5B, 0xA7, 0xEF, 0xDF, 0x06, 0x44, 0x36, 0x4C, 0xDD, 0x98, 0xF8, 0x0D, 0x28, 0xB1, 0x4E, 0x3E, 0xBE, 0x70, 0x13, 0xF0, 0x26, 0x7E, 0xDB, 0xB2, 0xA0, 0xE7, 0x40, 0xED, 0x99, 0x6D, 0x6A, 0x01, 0x71, 0x00, 0x99, 0xB6, 0x65, 0xF4, 0x07, 0x88, 0x9F, 0x87, 0x4D, 0x85, 0x78, 0x61, 0x50, 0x33, 0x88, 0xAE, 0x5E, 0x5F, 0xC4, 0xD4, 0xAB, 0xB5, 0x6B, 0x14, 0xFB, 0x62, 0xE4, 0xD6, 0x72, 0x85, 0x99, 0x2D, 0x81, 0x7A, 0x15, 0x64, 0x4A, 0x2A, 0x60, 0xE1, 0x43, 0xA6, 0xED, 0x03, 0xEC, 0x6A, 0x7F, 0xEF, 0x4A, 0x7F, 0x07, 0xF8, 0x9C, 0xBA, 0x33, 0x21, 0xE5, 0x11, 0x10, 0x70, 0x77, 0x47, 0x78, 0xE4, 0x42, 0x60, 0xC5, 0x3D, 0xCB, 0xCE, 0x9A, 0xF7, 0xDA, 0x5E, 0x39, 0xD0, 0x4A, 0x75, 0x7F, 0x33, 0xD5, 0x43, 0x9D, 0xF7, 0x67, 0x6A, 0x96, 0x1A, 0x6E, 0x7F, 0xE3, 0x7C, 0x20, 0x49, 0xF3, 0x8D, 0xFA, 0x60, 0xB2, 0x60, 0x2F, 0x00, 0x90, 0x07, 0x52, 0x14, 0xEE, 0xDB, 0xA3, 0x70, 0x4F, 0x8D, 0xC2, 0x5C, 0x9F, 0x7A, 0x9E, 0x28, 0x23, 0x77, 0x3C, 0xAA, 0x4D, 0xDA, 0xFE, 0x0E, 0x8A, 0xDB, 0x96, 0x28, 0xCC, 0x2B, 0x56, 0x78, 0xB8, 0x05, 0xD0, 0xFA, 0xF8, 0xAF, 0x59, 0xA7, 0x6E, 0x03, 0xE6, 0x71, 0x0F, 0x26, 0x9D, 0xDD, 0x0D, 0x74, 0xEC, 0x58, 0xD4, 0xA2, 0xC4, 0x0A, 0x70, 0x1A, 0x19, 0x6B, 0x7E, 0xCE, 0x05, 0x98, 0x3D, 0x12, 0xD8, 0x1A, 0xDF, 0x73, 0x53, 0x66, 0x20, 0x90, 0xA4, 0x71, 0xB8, 0x7C, 0x8B, 0x37, 0x30, 0xBF, 0xC5, 0x1B, 0xBF, 0xB4, 0x58, 0x0C, 0x1A, 0x93, 0x48, 0x66, 0xF6, 0x03, 0xFA, 0x97, 0x93, 0x19, 0x27, 0x00, 0x4F, 0xCB, 0x3A, 0x97, 0x02, 0xAE, 0x59, 0x75, 0x86, 0x02, 0x8E, 0xEE, 0x8A, 0x6C, 0xBB, 0x8A, 0x4C, 0x8F, 0xFC, 0xD7, 0x2D, 0xDF, 0x13, 0x00, 0xAA, 0x03, 0x8F, 0x75, 0x16, 0x7F, 0x16, 0x9D, 0x9E, 0x03, 0x28, 0xC7, 0x7D, 0x2B, 0xB8, 0x70, 0x19, 0xD0, 0xF5, 0x2E, 0x6B, 0x77, 0xB5, 0xB6, 0xCE, 0x87, 0xE7, 0x7F, 0x3C, 0x0C, 0x01, 0x1A, 0xF6, 0xD8, 0xB9, 0xE4, 0x69, 0x6F, 0xA0, 0xAB, 0xD1, 0xAC, 0xB6, 0x2F, 0x65, 0xDF, 0x6C, 0x29, 0x50, 0xBE, 0xAC, 0x7F, 0xF9, 0x1A, 0x37, 0xE0, 0x7E, 0x52, 0x61, 0x8B, 0x65, 0x7B, 0x80, 0x23, 0x97, 0xDF, 0x14, 0xC7, 0x14, 0x00, 0x5B, 0xAE, 0x93, 0x2B, 0x42, 0x80, 0xA8, 0xB6, 0x75, 0xEE, 0x07, 0x42, 0x63, 0xC8, 0xD5, 0x13, 0x80, 0xF9, 0xD6, 0x64, 0xEC, 0x58, 0x60, 0x7A, 0x17, 0x32, 0xEE, 0x18, 0x30, 0xB1, 0x27, 0x19, 0xAF, 0xFE, 0x5B, 0xEB, 0xF4, 0x47, 0x00, 0xF8, 0x1D, 0x53, 0x92, 0x2C, 0x7E, 0xC8, 0xBA, 0xBC, 0x10, 0x50, 0xDB, 0xF6, 0xD0, 0xEC, 0xD6, 0x60, 0x40, 0x69, 0xCE, 0xC5, 0x19, 0x8F, 0x2B, 0x01, 0xA0, 0xE0, 0x65, 0xC5, 0x76, 0xA0, 0x89, 0xC5, 0xAA, 0xA9, 0x55, 0xEB, 0x00, 0xDB, 0x31, 0x7D, 0x75, 0xFF, 0x5D, 0x01, 0x26, 0x2B, 0x03, 0xFF, 0xD4, 0x7A, 0xED, 0x5A, 0x58, 0x03, 0xFC, 0x89, 0xDB, 0xD5, 0x6D, 0xAE, 0x05, 0xF0, 0x2C, 0xF5, 0xC9, 0xB6, 0xE9, 0x5D, 0x80, 0xCB, 0x05, 0x3F, 0x73, 0x26, 0x18, 0x00, 0xF9, 0xF3, 0xC9, 0x09, 0x5B, 0x80, 0x1D, 0x86, 0xE4, 0x8C, 0xCE, 0x40, 0x6A, 0x2B, 0x72, 0x4E, 0x1E, 0xB0, 0xAE, 0x90, 0x5C, 0x68, 0x03, 0xAC, 0x78, 0x4B, 0x2E, 0xBA, 0xF0, 0x6B, 0xFC, 0x95, 0x57, 0x00, 0xF0, 0x75, 0xCB, 0xED, 0x4B, 0x80, 0xEA, 0xF3, 0x07, 0x9F, 0xEE, 0xB4, 0x03, 0xEA, 0xBD, 0x3B, 0xBF, 0xAB, 0xEC, 0x13, 0x00, 0x1C, 0x1C, 0xF2, 0xCE, 0x56, 0x4C, 0xB9, 0xF0, 0x67, 0x13, 0x60, 0x10, 0xBF, 0xC0, 0x9A, 0x6C, 0x76, 0xAF, 0xCB, 0x28, 0xBD, 0x22, 0x12, 0x98, 0xF2, 0x5A, 0x3F, 0x87, 0xEC, 0xBB, 0xD7, 0xC7, 0xB4, 0xDD, 0x0D, 0x32, 0xEE, 0xAD, 0x43, 0x1A, 0x40, 0x9E, 0x38, 0x28, 0x5F, 0x7D, 0xBF, 0xEE, 0x56, 0xDE, 0x77, 0x3C, 0x04, 0xDC, 0xFB, 0x45, 0xF6, 0x3C, 0x89, 0x1F, 0x97, 0x2A, 0x49, 0x97, 0x11, 0x40, 0x61, 0x11, 0xD9, 0xB7, 0x2F, 0x70, 0xF8, 0x02, 0xE9, 0xD3, 0x11, 0xD8, 0xD3, 0x9A, 0xF4, 0xFB, 0xEF, 0xBB, 0xD3, 0xFD, 0xB6, 0x80, 0x4A, 0xE3, 0xA7, 0x61, 0x0F, 0xDB, 0x00, 0x1A, 0x5A, 0xA5, 0x0E, 0x72, 0x25, 0x02, 0x1C, 0xB2, 0x7A, 0x76, 0x43, 0xDC, 0x6A, 0xF4, 0xB9, 0x00, 0x50, 0x6D, 0xB6, 0xA8, 0x07, 0x09, 0x4F, 0x93, 0x8D, 0xEE, 0x53, 0x48, 0xC0, 0xC1, 0x0C, 0x20, 0xD5, 0x54, 0x7A, 0x6F, 0x11, 0xDD, 0x16, 0x77, 0xBB, 0x69, 0x94, 0x4A, 0x46, 0xCF, 0x6F, 0xB4, 0x59, 0xF2, 0x26, 0xF7, 0x36, 0x3E, 0x62, 0xDE, 0xA5, 0x16, 0x9F, 0x2D, 0x57, 0x90, 0x24, 0x00, 0xFC, 0x4C, 0x26, 0xCD, 0xA2, 0x81, 0xC7, 0xD3, 0xC8, 0xF6, 0xC9, 0xC0, 0xED, 0x50, 0xB2, 0x8B, 0x1A, 0x50, 0xBA, 0x92, 0xEC, 0x79, 0xFC, 0x43, 0x44, 0xF9, 0x6C, 0x40, 0xF3, 0xC2, 0xCD, 0x7E, 0xE5, 0x6B, 0x01, 0x95, 0x59, 0xC7, 0xFE, 0x3E, 0xA9, 0x13, 0xC8, 0xD6, 0x7A, 0x1B, 0x02, 0x28, 0x0D, 0x8C, 0xAE, 0xAE, 0x8E, 0x00, 0xF4, 0x6D, 0x47, 0xFE, 0x21, 0xD5, 0x6F, 0x9A, 0xCE, 0x41, 0x0C, 0x09, 0xF4, 0xF2, 0x05, 0x48, 0x83, 0xD8, 0x9E, 0xDD, 0x45, 0xE7, 0xBD, 0x16, 0x95, 0x2D, 0x37, 0x91, 0x41, 0x93, 0x1A, 0xC6, 0x6B, 0x79, 0x93, 0xE1, 0xAA, 0x86, 0xE3, 0x00, 0x32, 0xA9, 0xBC, 0x65, 0x6B, 0xF1, 0x98, 0x6F, 0xF3, 0xAE, 0x62, 0xD9, 0xE8, 0xE6, 0x5E, 0x66, 0x41, 0xE4, 0xBF, 0xE6, 0x80, 0x64, 0xB2, 0xE9, 0x50, 0xE0, 0x43, 0x1A, 0xD9, 0xE2, 0xCD, 0xE3, 0xE1, 0xCF, 0xCE, 0x01, 0x1A, 0xB3, 0xCE, 0xB4, 0x78, 0xFC, 0x16, 0x50, 0x0A, 0xCE, 0x5D, 0xF2, 0xD2, 0x1B, 0xC0, 0xC9, 0x84, 0xC5, 0x55, 0x2D, 0x01, 0xB5, 0x2E, 0xE3, 0xB6, 0x92, 0x80, 0xC9, 0xA3, 0xD6, 0x13, 0x45, 0xE7, 0xCE, 0x80, 0x68, 0x57, 0x2B, 0x36, 0x9B, 0xD1, 0x69, 0xA0, 0xD8, 0xD3, 0xAC, 0x6D, 0x7D, 0xB1, 0xF7, 0x0A, 0x93, 0xED, 0xFA, 0x2E, 0x64, 0x48, 0xAE, 0xAE, 0xB2, 0xE4, 0xC8, 0x46, 0x86, 0x7F, 0xC5, 0xB4, 0xB5, 0x06, 0x93, 0xC5, 0x3D, 0x63, 0x1A, 0x67, 0x88, 0x17, 0xD4, 0x9A, 0x2C, 0x11, 0x1F, 0xFA, 0x37, 0xF5, 0x35, 0xCC, 0x22, 0xBF, 0xEF, 0x04, 0xAE, 0x2E, 0x7D, 0x76, 0x1E, 0x50, 0x35, 0xC9, 0xBF, 0xF4, 0xDC, 0x15, 0x50, 0x9A, 0xB2, 0xE5, 0xEB, 0xA7, 0x66, 0x80, 0x72, 0xF4, 0xDC, 0x40, 0x12, 0x68, 0x72, 0xDA, 0x2D, 0x4E, 0xB4, 0x98, 0xD1, 0x78, 0xB7, 0x68, 0xBD, 0x1B, 0x10, 0xBB, 0x4C, 0x16, 0x0D, 0xF3, 0xDA, 0x8E, 0x15, 0x3B, 0x7B, 0xB7, 0x4A, 0x12, 0x5D, 0x61, 0xB8, 0x46, 0x4B, 0x95, 0x1C, 0xD5, 0x52, 0x4B, 0x55, 0x23, 0x9A, 0x9C, 0x43, 0x8D, 0x68, 0x80, 0x5C, 0x7E, 0x4D, 0xAF, 0x83, 0xB8, 0xA1, 0x91, 0xFE, 0x6C, 0x31, 0x2B, 0x4B, 0x7F, 0xB7, 0x98, 0xDF, 0x5F, 0x5F, 0x5D, 0xBC, 0x10, 0xA2, 0x37, 0x92, 0x74, 0x2B, 0x04, 0x24, 0xD9, 0xBE, 0x56, 0x68, 0x0C, 0xA0, 0x4D, 0x43, 0x12, 0x68, 0x38, 0xDA, 0x2E, 0x46, 0xEC, 0x74, 0xC4, 0xD6, 0x4B, 0x1C, 0x30, 0xBB, 0x7B, 0xBE, 0x18, 0xF0, 0xD3, 0xF6, 0x80, 0x18, 0xB3, 0xDB, 0x76, 0xBF, 0x98, 0xF1, 0xC8, 0x76, 0x9B, 0x78, 0xD6, 0xCE, 0xBA, 0x2B, 0xA9, 0x36, 0xF9, 0xCD, 0xA4, 0xF6, 0x33, 0x49, 0xE5, 0x3E, 0x35, 0xA3, 0xDB, 0xF4, 0x79, 0x31, 0x10, 0x20, 0x9B, 0x3D, 0xBF, 0x7F, 0x56, 0x6C, 0x62, 0x76, 0xB5, 0xB9, 0xD8, 0xF0, 0xC3, 0xB9, 0x74, 0xB1, 0x59, 0xC8, 0xC9, 0x8B, 0x62, 0xDB, 0xAD, 0x64, 0xEF, 0x67, 0x8A, 0x7E, 0x87, 0x69, 0x0A, 0x8D, 0xDE, 0x03, 0x1D, 0x14, 0xEF, 0xEF, 0xEC, 0xD7, 0xCB, 0x4C, 0x6C, 0x7F, 0xCF, 0x49, 0x4F, 0xEC, 0xDF, 0xCA, 0xF6, 0x88, 0x38, 0x4E, 0xC7, 0xE9, 0x98, 0x18, 0xD9, 0xD2, 0x79, 0x81, 0x98, 0xDE, 0xD7, 0x39, 0x54, 0x2C, 0xBE, 0xEF, 0x78, 0x95, 0xD4, 0x5A, 0xF3, 0xB1, 0x61, 0xBB, 0xC3, 0xB5, 0x57, 0x00, 0xD2, 0xF4, 0xD1, 0xA3, 0xB7, 0xA2, 0x61, 0xF5, 0x2D, 0x57, 0xB1, 0xD1, 0xC9, 0x8B, 0x3D, 0xC4, 0xC6, 0xCA, 0x85, 0xAB, 0x44, 0xD3, 0xD4, 0xA3, 0x3F, 0xC5, 0x2E, 0x67, 0xC8, 0x3E, 0xBF, 0x14, 0xFD, 0x2E, 0x37, 0x14, 0x5A, 0x4E, 0x06, 0xCC, 0xB6, 0x92, 0x92, 0x06, 0xAE, 0x11, 0x4D, 0xD6, 0xF5, 0x9E, 0x2C, 0x7A, 0x5C, 0xED, 0x95, 0x26, 0xFA, 0x7B, 0xBA, 0x4E, 0x17, 0x63, 0x06, 0xBA, 0xF5, 0x16, 0xB3, 0x0D, 0x7A, 0x6F, 0x17, 0xCF, 0xEB, 0xF7, 0xD9, 0x46, 0x36, 0x3E, 0xF8, 0xF5, 0x71, 0x67, 0x9F, 0xAA, 0x64, 0x80, 0xEC, 0xA0, 0x7E, 0xA7, 0x95, 0x68, 0x90, 0x5C, 0xBA, 0x16, 0xE2, 0xEE, 0x22, 0x5D, 0xB1, 0xED, 0xDA, 0xE3, 0xFB, 0xC5, 0x6E, 0x73, 0xF3, 0xEB, 0x8B, 0x8E, 0x83, 0xC9, 0x81, 0x8A, 0xF9, 0x4A, 0x8F, 0xED, 0x0A, 0xED, 0x2C, 0x80, 0x36, 0x77, 0x49, 0x49, 0x43, 0x9B, 0x89, 0x66, 0x53, 0x3C, 0x4B, 0x44, 0xFB, 0x83, 0x03, 0x32, 0xC4, 0xF1, 0x11, 0x7D, 0x27, 0x90, 0xBA, 0x46, 0x61, 0xE9, 0x5E, 0xA6, 0x92, 0xB7, 0x4D, 0x19, 0x9C, 0x22, 0x96, 0xE6, 0x0E, 0x9B, 0x2E, 0x56, 0xAA, 0xF6, 0xB5, 0x7B, 0xA3, 0x05, 0x90, 0x0E, 0x65, 0x25, 0xC3, 0xC4, 0xE6, 0x2C, 0xF2, 0x16, 0x2D, 0x5B, 0x1F, 0x2D, 0x16, 0xED, 0x4E, 0xE6, 0xF5, 0x12, 0xDD, 0x3E, 0xEF, 0xEE, 0x27, 0xF6, 0x0B, 0x22, 0x87, 0xE5, 0x28, 0xFA, 0x07, 0xDC, 0x50, 0xD8, 0x5B, 0x0B, 0x30, 0x89, 0x22, 0x8D, 0x2B, 0x00, 0x77, 0x15, 0xD2, 0x72, 0x7F, 0xBB, 0x5E, 0x76, 0x93, 0x49, 0xA0, 0x47, 0xF5, 0xF0, 0x3E, 0xA2, 0x6F, 0x47, 0x5F, 0x15, 0x71, 0xCE, 0x18, 0x7F, 0x5F, 0x31, 0x6B, 0x90, 0xBF, 0xA6, 0x78, 0x63, 0x6F, 0xC0, 0x9F, 0x0F, 0x91, 0xC0, 0xE7, 0x3D, 0xA3, 0x06, 0xDC, 0xFD, 0x09, 0x90, 0x83, 0xA6, 0x9F, 0x6A, 0x2E, 0xF6, 0x88, 0x38, 0x78, 0x4D, 0xEC, 0xDD, 0x6B, 0xEF, 0x70, 0x71, 0x40, 0x5C, 0xCE, 0x5B, 0x71, 0x44, 0x8B, 0x74, 0x8A, 0x63, 0x0E, 0xD6, 0x1C, 0x0E, 0x3C, 0x0F, 0x40, 0x6E, 0x1B, 0xA1, 0x70, 0x9A, 0x81, 0xC2, 0xEE, 0x87, 0x00, 0xE7, 0x6A, 0x52, 0xD2, 0xC4, 0x4A, 0xB1, 0xE3, 0xE3, 0x09, 0x16, 0xE2, 0x80, 0x4B, 0x81, 0xF9, 0x62, 0xF0, 0xC2, 0xE9, 0x17, 0xC4, 0xAC, 0x67, 0xB3, 0xD7, 0x54, 0xFE, 0x02, 0x6E, 0xDF, 0x09, 0x8E, 0xBA, 0xA3, 0x0D, 0x7C, 0xFB, 0x1E, 0x94, 0x7A, 0xCA, 0x04, 0xA8, 0xB9, 0x39, 0x69, 0x6F, 0x6E, 0x1C, 0x40, 0x0E, 0x0F, 0xC8, 0x5E, 0x27, 0xFA, 0x37, 0xD8, 0x1A, 0x20, 0x4E, 0x8E, 0xDA, 0x94, 0x23, 0x06, 0xAD, 0x58, 0x33, 0x46, 0x9C, 0x53, 0xF5, 0xEF, 0xCD, 0x9C, 0x9D, 0x00, 0xE4, 0xB6, 0xB9, 0x0A, 0x17, 0x9A, 0x29, 0x1C, 0x68, 0x00, 0xD8, 0xFB, 0x91, 0x56, 0x13, 0x80, 0x61, 0x23, 0x49, 0x40, 0x55, 0x37, 0xE4, 0xA5, 0x68, 0xB3, 0x6F, 0x61, 0xD0, 0x07, 0x27, 0x60, 0xCC, 0xFD, 0xC5, 0xA3, 0xEF, 0xFB, 0x02, 0xAB, 0x73, 0x97, 0x4E, 0xBF, 0x74, 0x1F, 0x28, 0x69, 0xBB, 0xF8, 0xE7, 0x81, 0x3C, 0xA0, 0x22, 0x2C, 0xD2, 0x31, 0x6D, 0x23, 0xF0, 0xF3, 0x64, 0xB4, 0x47, 0xFC, 0x59, 0xC8, 0x6B, 0x4E, 0x58, 0x66, 0x20, 0x2E, 0x55, 0x89, 0x98, 0x2D, 0x86, 0x7B, 0x84, 0xAE, 0x16, 0x23, 0xA3, 0xE6, 0x5C, 0x15, 0x63, 0x1A, 0xFE, 0x1D, 0x1A, 0x6D, 0x0F, 0x00, 0x7C, 0x14, 0x15, 0x0F, 0x91, 0xCB, 0xEF, 0x28, 0x0C, 0xBD, 0x02, 0x98, 0x2D, 0x24, 0x27, 0x3F, 0x01, 0xDC, 0xFA, 0xFD, 0xCE, 0xF3, 0xFE, 0x0E, 0x04, 0x7E, 0xBA, 0x5D, 0xD6, 0xC8, 0x16, 0x58, 0xF1, 0xF4, 0xC8, 0x7F, 0x80, 0xE9, 0xA5, 0xF8, 0x98, 0xEC, 0xEE, 0x40, 0x88, 0x43, 0xEC, 0x89, 0xF8, 0xCF, 0x40, 0xA1, 0xC7, 0x9A, 0x01, 0x0B, 0x7B, 0x02, 0xEF, 0xCE, 0x6C, 0x78, 0x37, 0xB1, 0x00, 0xF8, 0x1D, 0x99, 0x76, 0x38, 0x60, 0x08, 0x40, 0x26, 0xB6, 0x1E, 0xDD, 0x56, 0xDC, 0xA8, 0x3B, 0x32, 0x1F, 0xA2, 0xE9, 0x90, 0x09, 0x10, 0xFD, 0xBC, 0xD6, 0x41, 0xBC, 0xFB, 0xEB, 0xE9, 0xBA, 0xB5, 0x00, 0x50, 0xAD, 0xBE, 0xBE, 0x5C, 0x24, 0x93, 0xFB, 0x43, 0x7C, 0xB5, 0x79, 0x01, 0x60, 0x30, 0xFF, 0x8F, 0xFF, 0xC6, 0xEF, 0x40, 0x87, 0x5B, 0x6F, 0xA7, 0x6E, 0xFC, 0x05, 0x38, 0xF8, 0x17, 0xEB, 0xAF, 0x07, 0xD0, 0x77, 0xEE, 0xA6, 0x9B, 0xC1, 0x47, 0x80, 0x45, 0x17, 0x2D, 0xEF, 0xE9, 0xA7, 0xB4, 0x3C, 0x96, 0x9D, 0xA9, 0x9A, 0xD4, 0xF2, 0x46, 0x46, 0xEE, 0xB6, 0x74, 0xA0, 0xF9, 0xC6, 0x87, 0x79, 0xD9, 0x3F, 0x54, 0x9B, 0x18, 0xE8, 0xFD, 0x1C, 0xB7, 0xEB, 0x21, 0x00, 0x90, 0xBB, 0x37, 0x02, 0x4A, 0x95, 0xE4, 0x8E, 0x7A, 0x40, 0xBD, 0x71, 0x64, 0xCE, 0x1C, 0xB9, 0x76, 0x24, 0xB7, 0xFD, 0x51, 0xD2, 0xD0, 0x78, 0x40, 0x66, 0x36, 0xFB, 0xB9, 0x3C, 0xB5, 0x0A, 0x00, 0x7E, 0x3D, 0xCB, 0x2C, 0x15, 0xAB, 0x1A, 0x6F, 0xCF, 0x11, 0x2B, 0x3E, 0xEC, 0x3C, 0x0A, 0x68, 0x9C, 0x7D, 0x1A, 0xB0, 0xFF, 0x0D, 0xA0, 0xAD, 0x51, 0x3A, 0xE6, 0x50, 0x67, 0xA0, 0xB1, 0xC6, 0xBE, 0x2F, 0x47, 0x36, 0x00, 0x5D, 0x0E, 0x85, 0xF7, 0xCF, 0x3F, 0x0D, 0x8C, 0x59, 0x00, 0xAC, 0x3B, 0xD8, 0xE9, 0x47, 0x62, 0x13, 0x20, 0xD1, 0x2A, 0xD7, 0x74, 0x95, 0x11, 0xB0, 0xF8, 0xD5, 0xF3, 0xC0, 0xD8, 0x3F, 0xC0, 0xC4, 0xA1, 0x64, 0xE2, 0x4B, 0xA0, 0xDF, 0x0F, 0x72, 0x8B, 0x29, 0xE0, 0x75, 0x9E, 0x4C, 0x7A, 0x0E, 0xF4, 0xFA, 0xAF, 0xCE, 0x32, 0xC0, 0xE5, 0x44, 0x9D, 0x47, 0xEB, 0x0C, 0x25, 0x37, 0x0F, 0xAD, 0x9C, 0xB5, 0x2B, 0x11, 0x00, 0xBE, 0x8C, 0xDC, 0x77, 0x4C, 0x7C, 0x6D, 0x97, 0x6F, 0x21, 0x96, 0xFD, 0x39, 0x7A, 0x06, 0x50, 0xFA, 0x59, 0x3A, 0xAC, 0x28, 0x5E, 0xF2, 0xA1, 0x9E, 0xA5, 0x87, 0x01, 0xE5, 0xAB, 0xC9, 0xDA, 0xD7, 0x7E, 0x03, 0x46, 0xB5, 0x53, 0x1E, 0xDE, 0x5D, 0x08, 0xF4, 0x5F, 0x02, 0x5C, 0xFD, 0xEA, 0xB2, 0x62, 0x89, 0x0A, 0x70, 0x99, 0xFB, 0x2D, 0xE6, 0x56, 0x00, 0xC7, 0x8C, 0x5E, 0x44, 0xCF, 0x77, 0x07, 0x52, 0x1D, 0x6A, 0xF5, 0x42, 0x97, 0x03, 0xE1, 0x3B, 0xC9, 0x25, 0x36, 0xC0, 0x92, 0xB5, 0x64, 0x98, 0x26, 0x30, 0xFF, 0x8D, 0xE2, 0xBD, 0x69, 0xC1, 0x5B, 0xC9, 0xC8, 0x05, 0xC0, 0x8C, 0x20, 0x32, 0xEA, 0xFE, 0x97, 0x8E, 0x47, 0xAC, 0x01, 0xE0, 0x43, 0xD1, 0xE9, 0x6F, 0xE2, 0x43, 0xE7, 0xC2, 0x6A, 0x40, 0x29, 0xEB, 0xE2, 0xF7, 0xE2, 0x38, 0xC9, 0x05, 0x6A, 0x97, 0x97, 0x8B, 0xDB, 0x9E, 0x96, 0x75, 0x13, 0x97, 0xFD, 0x7C, 0xD3, 0x17, 0x68, 0x7C, 0xDE, 0x37, 0xEB, 0xEB, 0x6B, 0xC0, 0xD1, 0x12, 0xF8, 0x3A, 0xDC, 0xC1, 0x2B, 0xD0, 0xBA, 0x4E, 0xE5, 0x2C, 0xDD, 0x31, 0x35, 0x40, 0x79, 0xFF, 0xC7, 0xB7, 0x7D, 0xEB, 0xBC, 0x64, 0xF3, 0x63, 0xDF, 0xC8, 0x7A, 0xC0, 0xFE, 0xF1, 0xE4, 0xD0, 0x00, 0x60, 0x7B, 0x6F, 0xD2, 0xEF, 0x1A, 0xB0, 0xB5, 0x33, 0x39, 0xEE, 0x31, 0xB0, 0xC9, 0x98, 0x0C, 0xEC, 0x09, 0xC4, 0xAB, 0x91, 0x53, 0x3B, 0x7E, 0x6E, 0x7D, 0x41, 0x19, 0x00, 0x9E, 0x04, 0x96, 0x98, 0x02, 0xAA, 0xEF, 0x2F, 0x1F, 0x2B, 0x1D, 0x2B, 0xF9, 0xE0, 0xD7, 0x2B, 0xD3, 0xC5, 0xCC, 0xE0, 0x3B, 0x46, 0x62, 0xFC, 0x94, 0xF7, 0x06, 0xE2, 0xB4, 0xCD, 0xFF, 0x4E, 0x02, 0x6D, 0x4D, 0x2D, 0x16, 0x90, 0x40, 0xBF, 0x77, 0x00, 0x69, 0xFB, 0x62, 0xC0, 0xDA, 0xD6, 0xDD, 0xC8, 0x55, 0xA5, 0xD6, 0x9E, 0x92, 0xCF, 0xDF, 0x75, 0x39, 0x00, 0x54, 0xAE, 0xFE, 0xA9, 0x67, 0xB3, 0x15, 0xB8, 0x19, 0x4D, 0xB6, 0x7B, 0x04, 0x94, 0x24, 0x92, 0x56, 0x8D, 0x81, 0xC2, 0x60, 0xB2, 0x67, 0x34, 0x70, 0x64, 0x00, 0xE9, 0xDC, 0x04, 0xD8, 0xFF, 0x9C, 0xF4, 0x88, 0x7E, 0x17, 0x78, 0xED, 0x2A, 0xA0, 0x76, 0xE8, 0x56, 0xB3, 0xAB, 0x6F, 0xEB, 0xEC, 0x7B, 0x72, 0xCD, 0x8D, 0xC9, 0x00, 0xB0, 0xC3, 0xFB, 0xF6, 0x03, 0x71, 0xDD, 0xA9, 0x27, 0xB5, 0xE2, 0xDC, 0x35, 0x3F, 0xEE, 0x03, 0x7A, 0x43, 0xBC, 0x7C, 0x49, 0xA0, 0x93, 0x01, 0x20, 0xBA, 0xED, 0x15, 0x1D, 0xCA, 0x2C, 0x6D, 0x0D, 0x5F, 0xC8, 0x6E, 0xB9, 0xF6, 0x10, 0xC9, 0x9B, 0xCB, 0x0C, 0xA7, 0x89, 0x47, 0x2E, 0xEB, 0xCF, 0x6C, 0x74, 0x9C, 0x24, 0x01, 0xA0, 0xAA, 0x2D, 0xD9, 0x78, 0x20, 0xF0, 0xF8, 0x37, 0x69, 0x38, 0x1B, 0xB8, 0x73, 0x93, 0x34, 0x32, 0x01, 0xAE, 0x9C, 0x22, 0xCD, 0x36, 0x3F, 0xD9, 0x78, 0xD7, 0x1F, 0xD0, 0x28, 0x3B, 0x77, 0xF5, 0xE6, 0x35, 0x40, 0xD9, 0x68, 0x9F, 0xD7, 0x1D, 0x7D, 0x40, 0x69, 0xD5, 0xE6, 0x6D, 0x8F, 0xB6, 0x01, 0xC0, 0x7F, 0x86, 0xDF, 0xE2, 0x01, 0xF5, 0x15, 0x43, 0x16, 0x93, 0x80, 0xF1, 0x03, 0xD5, 0x53, 0xA2, 0xFD, 0x75, 0x80, 0xD4, 0x71, 0xB0, 0xB4, 0x12, 0xED, 0x5A, 0x9B, 0xF8, 0x37, 0x9E, 0x4F, 0x4E, 0x32, 0xD4, 0xB6, 0x51, 0x39, 0x42, 0x86, 0x9D, 0x69, 0xD8, 0x0C, 0x20, 0x53, 0xA2, 0x1B, 0x15, 0x8B, 0xB7, 0xE2, 0xF4, 0x4F, 0x35, 0x3B, 0x43, 0x7E, 0xD1, 0x04, 0x9A, 0xCD, 0x21, 0xFF, 0xFD, 0x04, 0x00, 0x92, 0xD4, 0x71, 0x06, 0x2A, 0x23, 0x48, 0xED, 0x88, 0x1B, 0xBD, 0xEF, 0xCD, 0x01, 0xEA, 0xDB, 0x1F, 0x8A, 0xBB, 0xD3, 0x03, 0xA8, 0x77, 0x32, 0xC3, 0xE5, 0x61, 0x22, 0x00, 0xAC, 0x28, 0xAC, 0x98, 0x00, 0xE0, 0xC2, 0xD8, 0x4E, 0x24, 0xD0, 0xB4, 0xA9, 0xDB, 0x56, 0x8A, 0x2F, 0x01, 0xB1, 0x7B, 0x8C, 0xD8, 0xF0, 0x87, 0x59, 0x03, 0xB1, 0x6B, 0x4D, 0xF3, 0x87, 0x3A, 0xCE, 0xA4, 0xCF, 0x57, 0x0D, 0x37, 0xCD, 0x9D, 0xE4, 0xFC, 0x91, 0x0D, 0x82, 0x01, 0x72, 0xA5, 0x8E, 0xAE, 0xAE, 0xB8, 0xA3, 0x40, 0xDB, 0x4B, 0x3C, 0xB8, 0x59, 0x6B, 0xA9, 0x78, 0x79, 0xA4, 0x4E, 0xB8, 0x58, 0xA6, 0xA4, 0x67, 0xAE, 0x37, 0x88, 0xFC, 0xDA, 0x02, 0x28, 0x5A, 0x76, 0xDF, 0x1A, 0xA8, 0xF7, 0x60, 0xE7, 0x8C, 0x07, 0xDF, 0x01, 0x6C, 0x5A, 0x37, 0xFC, 0x4D, 0x09, 0x00, 0x04, 0x5D, 0x26, 0x81, 0x86, 0xBA, 0x9E, 0x2E, 0x62, 0xAB, 0x09, 0xDD, 0x87, 0x90, 0xAA, 0x3D, 0x1A, 0x0D, 0x01, 0x24, 0xB7, 0x1F, 0xAF, 0x96, 0x44, 0x1A, 0xA6, 0x18, 0xA6, 0x18, 0xDC, 0x21, 0xED, 0xEC, 0x01, 0x80, 0x74, 0x85, 0x4E, 0x0F, 0x75, 0x0F, 0x72, 0x8C, 0x91, 0xBA, 0x87, 0xDA, 0x40, 0x72, 0xC1, 0x6A, 0xB5, 0x81, 0x00, 0x19, 0xAB, 0xD5, 0x60, 0x80, 0x98, 0xE2, 0xA8, 0xA1, 0x2C, 0xEE, 0x18, 0xA5, 0xE1, 0x24, 0x1E, 0x6C, 0xD9, 0xA0, 0x54, 0x3C, 0xBF, 0xBD, 0xC1, 0x77, 0x39, 0x9B, 0x02, 0x80, 0x3A, 0xD3, 0x14, 0xAA, 0xF7, 0x02, 0xCC, 0xF6, 0x90, 0x80, 0xD1, 0xE7, 0xF6, 0x33, 0xC5, 0x1E, 0xBB, 0x3A, 0xD4, 0x88, 0x03, 0x56, 0x77, 0x1C, 0x2C, 0x4E, 0xF2, 0xE9, 0x14, 0x27, 0x2E, 0x4F, 0xB7, 0x38, 0x21, 0xA6, 0xD3, 0xBC, 0x5A, 0x3C, 0x51, 0xBF, 0xED, 0x4D, 0xF1, 0x61, 0x5A, 0xEB, 0xF2, 0x9A, 0xBE, 0x40, 0xD5, 0x0B, 0xC3, 0x07, 0x6F, 0xD5, 0x00, 0x52, 0x4F, 0xF7, 0xFE, 0x6D, 0x51, 0xE3, 0xCC, 0xF5, 0x5A, 0xB1, 0x7E, 0x72, 0x49, 0x57, 0x51, 0x2D, 0xA5, 0xC8, 0x49, 0x54, 0x49, 0x26, 0xBB, 0x7D, 0x53, 0xF4, 0x77, 0x31, 0x57, 0x68, 0x38, 0x1F, 0x30, 0xB2, 0x20, 0x81, 0xA6, 0x09, 0x1D, 0x06, 0x89, 0x56, 0x23, 0x3A, 0x1C, 0x15, 0xFB, 0xA6, 0x76, 0x88, 0x13, 0xC7, 0x47, 0x76, 0x4E, 0x15, 0xA3, 0x2B, 0x3A, 0x5D, 0x12, 0xD3, 0x0D, 0x2D, 0x37, 0x8B, 0x27, 0xAE, 0xB7, 0xFF, 0x2C, 0x3E, 0xDE, 0x6B, 0x74, 0xE8, 0xAF, 0x25, 0xF0, 0xF7, 0x61, 0xD3, 0x49, 0x4F, 0xF7, 0x03, 0xA4, 0xF6, 0xCD, 0x9B, 0xB1, 0x62, 0x83, 0xE4, 0xD2, 0xD1, 0xA2, 0x7A, 0xF7, 0xA2, 0x89, 0x62, 0xBD, 0xE6, 0xC7, 0xCB, 0xC4, 0xFA, 0xBE, 0xA4, 0xED, 0x51, 0x45, 0x7F, 0xB7, 0xBE, 0x0A, 0x5B, 0x67, 0x02, 0xC6, 0xAF, 0x49, 0x40, 0x57, 0xA9, 0xEB, 0x1A, 0xD1, 0x7C, 0x80, 0x55, 0x77, 0xD1, 0xEB, 0x53, 0xA7, 0x99, 0xE2, 0xF8, 0x87, 0xDD, 0x83, 0xC5, 0x88, 0x7A, 0x3D, 0x94, 0xC5, 0xF4, 0xE9, 0xD6, 0x13, 0xC5, 0x33, 0xDE, 0xDD, 0xA3, 0xC9, 0xFA, 0x5B, 0xDE, 0xEA, 0x99, 0xB9, 0x7D, 0xAB, 0xAF, 0x38, 0xEF, 0xBB, 0xFF, 0x45, 0xD4, 0x9C, 0x73, 0x71, 0xAD, 0xA8, 0x7E, 0xA4, 0xB0, 0x42, 0x54, 0x4A, 0x39, 0xDE, 0x5B, 0xD4, 0x59, 0x9D, 0x1F, 0x28, 0xB6, 0x2A, 0x26, 0x5D, 0xFE, 0xFF, 0xF9, 0x4F, 0x8E, 0x42, 0xB3, 0x96, 0x80, 0x59, 0x4F, 0x12, 0xC0, 0x2F, 0xA7, 0x86, 0xA2, 0x71, 0x23, 0x9B, 0x07, 0xA2, 0xB3, 0x89, 0x7D, 0x86, 0x38, 0x2A, 0xDC, 0xAE, 0x44, 0x5C, 0xD4, 0xC2, 0xE5, 0x91, 0x98, 0xFE, 0xCC, 0xE9, 0x99, 0x78, 0xA1, 0x85, 0x5B, 0x50, 0x75, 0x24, 0xF0, 0x71, 0xBF, 0xCD, 0xFB, 0x67, 0x31, 0x00, 0x69, 0x79, 0xE5, 0xB2, 0x91, 0xD8, 0xB0, 0xE4, 0x64, 0x5D, 0xFE, 0x7F, 0x5C, 0xDD, 0x77, 0x5C, 0x8F, 0xEF, 0x1B, 0xC7, 0xFD, 0x57, 0x7B, 0x2A, 0x91, 0x22, 0xAB, 0x88, 0xA8, 0x64, 0x67, 0x53, 0x29, 0x14, 0x15, 0xCA, 0xCC, 0xC8, 0xAE, 0x88, 0xCC, 0xC8, 0x56, 0xF6, 0x48, 0x44, 0xC8, 0x96, 0x15, 0xDA, 0x94, 0x99, 0xBD, 0xF7, 0x2C, 0xD9, 0x7C, 0xED, 0x4D, 0x64, 0xDF, 0xD7, 0xF1, 0x3B, 0xEF, 0xFD, 0xC7, 0xC7, 0xF3, 0xD1, 0x7C, 0x5F, 0x9F, 0x75, 0x9E, 0xC7, 0x75, 0x1C, 0xD7, 0x23, 0xDA, 0xF1, 0x9C, 0xCA, 0xE9, 0x28, 0x56, 0x69, 0x99, 0xE1, 0x2F, 0xD6, 0x36, 0xDA, 0x19, 0x2A, 0x36, 0xD0, 0xD1, 0xBA, 0x8C, 0x4F, 0x54, 0xBE, 0x57, 0xA4, 0xB2, 0xD9, 0x09, 0xA8, 0xAC, 0x3D, 0x0E, 0x36, 0xE1, 0xE0, 0x3E, 0x40, 0x3B, 0xF6, 0x33, 0xE5, 0x3F, 0xB7, 0x91, 0xC7, 0x81, 0x06, 0xFF, 0xF9, 0xEC, 0x13, 0xBB, 0xBB, 0xFB, 0x34, 0xD7, 0xEE, 0xDB, 0x90, 0x09, 0x13, 0xBD, 0xB7, 0xCA, 0xC7, 0x1B, 0x1D, 0xFD, 0xDE, 0x8B, 0x97, 0xDB, 0x04, 0x86, 0x3C, 0xFF, 0x0A, 0x6F, 0x7E, 0x75, 0x08, 0xBE, 0x6A, 0x8B, 0xBC, 0x72, 0xC7, 0x1F, 0x2E, 0x2D, 0xD6, 0xDD, 0x95, 0x96, 0x82, 0xF8, 0x6A, 0x47, 0x43, 0xB1, 0xE9, 0xBF, 0xCD, 0xFE, 0xAA, 0x5F, 0xB5, 0x61, 0xBB, 0xD8, 0x2E, 0xF2, 0xEF, 0xAB, 0xC0, 0x29, 0x2A, 0xBF, 0xD3, 0x54, 0x65, 0xDF, 0x4C, 0xA5, 0xCB, 0x31, 0x68, 0xD8, 0x56, 0xAD, 0x41, 0xC1, 0x43, 0x45, 0xE7, 0xFE, 0x9D, 0x3B, 0x8B, 0x1D, 0x6F, 0x76, 0xAB, 0x26, 0x46, 0x15, 0xF6, 0x6C, 0xF5, 0x25, 0x0C, 0x92, 0xFE, 0xF4, 0xE9, 0xF5, 0xAC, 0x33, 0x9C, 0x1C, 0x19, 0xB2, 0xFA, 0x5A, 0x2D, 0xF8, 0x50, 0xD0, 0xA7, 0x74, 0x6E, 0x28, 0xFC, 0x48, 0xEF, 0x36, 0x26, 0xB5, 0x23, 0x52, 0x97, 0x95, 0xD9, 0xD8, 0x57, 0xEC, 0xD4, 0x2A, 0xD9, 0x44, 0xEC, 0x16, 0xB0, 0xEC, 0x97, 0xD8, 0x77, 0xC1, 0xA2, 0x08, 0x71, 0xA0, 0x63, 0x71, 0x6C, 0xC8, 0x47, 0x54, 0x3D, 0xF6, 0x47, 0x39, 0xC4, 0x4A, 0xE9, 0xFF, 0x19, 0x9C, 0x5E, 0x69, 0x8F, 0xED, 0x30, 0xF0, 0x9E, 0xF7, 0x7B, 0x09, 0x18, 0x79, 0x0E, 0x1D, 0xF1, 0xF9, 0x27, 0x34, 0x7A, 0x36, 0xF4, 0x73, 0x61, 0x21, 0x04, 0x97, 0x0C, 0xDD, 0x72, 0xE1, 0x16, 0xCC, 0xD4, 0x8D, 0xD8, 0x9F, 0xFF, 0x01, 0x0E, 0x8E, 0x1B, 0x32, 0x2A, 0xED, 0x07, 0x7C, 0x78, 0x3A, 0x7C, 0xD8, 0xEA, 0x7A, 0xF0, 0xDD, 0x6C, 0xC2, 0xC1, 0x85, 0xFB, 0x90, 0xF9, 0xE8, 0xA5, 0xE9, 0x97, 0xC5, 0xA8, 0x4D, 0x93, 0x5E, 0x88, 0xE3, 0xA2, 0x27, 0x1C, 0x10, 0x27, 0x3C, 0x1E, 0xB9, 0x40, 0x8C, 0x31, 0xF9, 0xFC, 0x38, 0x6A, 0x31, 0xC0, 0x77, 0xAB, 0xA8, 0xD6, 0xE2, 0x6F, 0x8B, 0x71, 0x85, 0xE2, 0xDF, 0xD9, 0xE3, 0x2B, 0x80, 0x49, 0xE9, 0x92, 0x19, 0xA1, 0x1B, 0xC1, 0x2D, 0xEB, 0x65, 0xDB, 0xF6, 0x01, 0xD0, 0xF5, 0xDA, 0x31, 0x1D, 0xB3, 0xD6, 0x10, 0xDD, 0x73, 0xAB, 0x07, 0x54, 0xC9, 0x98, 0xDE, 0x77, 0x65, 0x28, 0x0C, 0x9E, 0x3B, 0xA5, 0x5D, 0x9C, 0x2F, 0x64, 0x37, 0x8E, 0xE9, 0x15, 0x55, 0x0F, 0x9E, 0xB4, 0x8A, 0xCD, 0xEB, 0x5F, 0x17, 0x4A, 0x5A, 0x2E, 0xCB, 0xEC, 0x65, 0x81, 0xF4, 0x98, 0x96, 0x74, 0x33, 0x14, 0x17, 0x79, 0x06, 0xEF, 0x42, 0xCC, 0x0C, 0x78, 0x21, 0x2E, 0x9E, 0xEA, 0x35, 0x50, 0x5C, 0x92, 0xF5, 0xE1, 0x6E, 0xEC, 0x11, 0x80, 0xCF, 0x63, 0xE7, 0x38, 0x8A, 0x9F, 0xB2, 0xE6, 0x9E, 0x16, 0xDF, 0xEF, 0x5F, 0x60, 0x02, 0xFA, 0x75, 0xFF, 0x1B, 0x37, 0x37, 0x01, 0xCA, 0x5D, 0xBE, 0x35, 0x7C, 0xDE, 0x03, 0xA8, 0x9E, 0x98, 0x1D, 0x37, 0x6B, 0x00, 0x34, 0x32, 0x8A, 0x9B, 0x11, 0x1A, 0x0D, 0x61, 0x7B, 0x1C, 0x5B, 0x9B, 0xE7, 0x94, 0x75, 0x5D, 0x9D, 0x04, 0x65, 0xAE, 0x25, 0xD4, 0x5A, 0x55, 0x06, 0x2A, 0x59, 0xDD, 0xD9, 0x90, 0x54, 0x13, 0x2A, 0x84, 0xBE, 0x5F, 0xB7, 0x6E, 0x00, 0xC8, 0x15, 0x92, 0x1B, 0xBE, 0xC9, 0x9A, 0xAD, 0xF5, 0x9C, 0xD6, 0x83, 0x89, 0xF6, 0xDA, 0x5E, 0xA7, 0x69, 0xA6, 0xD5, 0x27, 0x6B, 0xF3, 0xC0, 0xF2, 0x82, 0x56, 0x7B, 0x8D, 0x7E, 0xEF, 0x9F, 0x10, 0x0F, 0xF0, 0x36, 0x3E, 0x31, 0x53, 0x7C, 0xBC, 0x63, 0x85, 0xB7, 0x58, 0xD0, 0x6C, 0x75, 0x14, 0xE8, 0x16, 0x5D, 0x2C, 0xBD, 0x6E, 0x9A, 0xA6, 0xEB, 0x3E, 0xAB, 0xCD, 0x61, 0x60, 0x78, 0x22, 0xF9, 0xF9, 0xD6, 0xFF, 0xA0, 0x9A, 0xC5, 0xE8, 0xA0, 0x0D, 0xB3, 0xC1, 0x7F, 0x0C, 0x4C, 0xB3, 0xA9, 0x6A, 0x1B, 0x1B, 0x0E, 0x73, 0x8B, 0x92, 0xAD, 0xA2, 0x97, 0x43, 0xCC, 0x85, 0x82, 0x67, 0x93, 0x36, 0xC0, 0xB0, 0x1F, 0x3F, 0xEB, 0xCC, 0xEA, 0x02, 0xBD, 0x16, 0x68, 0xD7, 0xE1, 0x56, 0x86, 0xAE, 0x5F, 0xB5, 0xFB, 0xEF, 0x06, 0xED, 0x6D, 0xB4, 0xBE, 0xCB, 0x5A, 0x68, 0xBB, 0x4A, 0xF3, 0x15, 0x78, 0xE6, 0x6B, 0x8F, 0xC7, 0xA6, 0x97, 0x15, 0x36, 0x2C, 0x06, 0x78, 0x98, 0xB6, 0xC5, 0x54, 0xBC, 0xED, 0xB7, 0x75, 0x8E, 0x78, 0x26, 0x78, 0x7B, 0x2D, 0x20, 0x3B, 0x3B, 0x61, 0xD7, 0x2D, 0x80, 0x4D, 0x29, 0x7B, 0xD3, 0xC4, 0x85, 0xD3, 0x8E, 0xF8, 0x82, 0xF9, 0x8F, 0xD0, 0x57, 0xC7, 0x9E, 0x83, 0xFB, 0x55, 0x38, 0x34, 0xB5, 0x61, 0x5A, 0x58, 0x0A, 0x1C, 0x5E, 0xB4, 0xC6, 0xB9, 0xDF, 0x4E, 0xC8, 0x69, 0x51, 0xF8, 0xA9, 0xBF, 0xE6, 0xDA, 0x9B, 0x3F, 0xC6, 0x0C, 0x8D, 0x81, 0x39, 0xB5, 0xB4, 0x1A, 0xFC, 0x25, 0x4C, 0xD2, 0xCE, 0x71, 0x46, 0xA5, 0xC0, 0xF8, 0xF7, 0x5A, 0xFF, 0x72, 0x02, 0x8C, 0x6E, 0xAB, 0xBD, 0x4E, 0xDE, 0x81, 0xCC, 0xC8, 0x27, 0x34, 0x7F, 0x76, 0x21, 0xCD, 0x02, 0xA0, 0xA8, 0x7C, 0xE6, 0x63, 0xF1, 0xFC, 0xBA, 0x4C, 0x5F, 0xD0, 0x9D, 0xB3, 0xB7, 0x63, 0xB6, 0x26, 0x6C, 0xD8, 0x92, 0x1B, 0x27, 0x2E, 0xEE, 0x75, 0xE2, 0x93, 0x38, 0x25, 0xE3, 0x96, 0x3A, 0xC3, 0xB2, 0xB9, 0x7B, 0x1E, 0x6A, 0xE8, 0xC0, 0xFD, 0xAE, 0x75, 0x5F, 0x06, 0xE6, 0xC2, 0xC3, 0x0F, 0xCB, 0xBE, 0xB5, 0xCB, 0x80, 0x82, 0x32, 0x77, 0x0E, 0xFB, 0xF4, 0x84, 0xD3, 0x4F, 0xBF, 0x45, 0xF8, 0xF8, 0x40, 0xA6, 0xD6, 0x93, 0xF6, 0x7E, 0x0B, 0x9B, 0xB4, 0x79, 0x58, 0x87, 0xB5, 0xB0, 0x46, 0xAB, 0x0F, 0x03, 0x2C, 0x21, 0x31, 0x47, 0xAB, 0x8F, 0x9E, 0x42, 0xBC, 0x56, 0x0F, 0x74, 0x7F, 0xFA, 0xE4, 0xEC, 0xA1, 0xB3, 0x00, 0xD7, 0x2D, 0x0F, 0x39, 0x81, 0xCE, 0x99, 0x43, 0xA3, 0x0E, 0x7A, 0x01, 0x6C, 0xE3, 0x70, 0xA2, 0xB8, 0xB4, 0xF6, 0x89, 0x30, 0x31, 0x26, 0xF4, 0x46, 0xA8, 0x38, 0xB8, 0xFC, 0xAB, 0x23, 0x60, 0x50, 0xBF, 0x79, 0xD0, 0xB7, 0xA9, 0xE0, 0xF4, 0x0B, 0x4A, 0x46, 0xBB, 0x3C, 0x6D, 0xEA, 0x08, 0x7F, 0xFA, 0x4C, 0xDE, 0x57, 0xFF, 0x7F, 0xF3, 0xB2, 0xB3, 0x3F, 0xEB, 0x79, 0xC1, 0xDB, 0xF6, 0x25, 0x0B, 0x9D, 0x43, 0xE1, 0x46, 0xE4, 0xBF, 0xE7, 0x55, 0x9F, 0xC1, 0xB1, 0x78, 0xB9, 0x82, 0x17, 0x0E, 0x68, 0x3B, 0x63, 0xAD, 0x16, 0x90, 0x93, 0xA8, 0xED, 0x69, 0xB5, 0x21, 0xAD, 0xB7, 0xD6, 0xFF, 0xDF, 0x7C, 0x9F, 0xD3, 0x5B, 0x40, 0x5F, 0xEF, 0xD4, 0xE6, 0xE3, 0x83, 0x40, 0xB7, 0x56, 0xFA, 0x90, 0x13, 0x15, 0x00, 0x56, 0xFF, 0x38, 0x53, 0x4F, 0x9C, 0x59, 0xFE, 0xCA, 0x36, 0x31, 0xE2, 0xF2, 0x33, 0x2F, 0xC0, 0x26, 0x50, 0xDB, 0x4F, 0xA1, 0xD4, 0x2B, 0x4E, 0x8B, 0x8D, 0x5B, 0x4B, 0x6E, 0xC3, 0x69, 0xF6, 0x9D, 0xCA, 0x14, 0x6B, 0x8F, 0xF6, 0x73, 0x13, 0x23, 0xF9, 0x78, 0xC5, 0x34, 0xAB, 0x7C, 0xF1, 0x82, 0x6E, 0x29, 0x33, 0x13, 0x6D, 0xA5, 0xFD, 0xDB, 0xC4, 0x20, 0x0F, 0x5E, 0x65, 0x68, 0x3B, 0x76, 0x2E, 0x14, 0x7E, 0xD4, 0xF6, 0x3B, 0x67, 0xB8, 0x56, 0x4E, 0x3B, 0x37, 0x5D, 0x00, 0xE7, 0x23, 0xB4, 0xF3, 0xDE, 0x51, 0xD7, 0x86, 0x9C, 0x77, 0x00, 0xC3, 0x6D, 0x79, 0x0D, 0x4E, 0xCF, 0x05, 0xDD, 0x96, 0x9B, 0xFB, 0x9E, 0x0D, 0x02, 0x9D, 0x81, 0x0B, 0xCB, 0x5C, 0xD3, 0x01, 0x18, 0x1B, 0xF3, 0x6C, 0x0A, 0xE8, 0x44, 0x04, 0x7D, 0x91, 0x5C, 0xF3, 0x5C, 0xDD, 0x08, 0xD1, 0xFD, 0x8C, 0xE4, 0x18, 0xE8, 0x39, 0xD6, 0x70, 0xF8, 0xA5, 0xAD, 0x86, 0x51, 0x60, 0xA6, 0xAD, 0x6C, 0xBD, 0xDF, 0x1B, 0x59, 0x22, 0x5D, 0x6A, 0x57, 0xF3, 0xC6, 0xE2, 0x26, 0x3F, 0xD3, 0x11, 0xE2, 0x85, 0xDF, 0x26, 0xAE, 0x16, 0xDA, 0x74, 0xB2, 0x78, 0x31, 0x18, 0xF6, 0x96, 0xFA, 0xC7, 0xA0, 0x26, 0xFC, 0xF9, 0xAB, 0x99, 0x0D, 0x9F, 0xB5, 0xBE, 0xA2, 0xCE, 0x8C, 0xE3, 0x63, 0x2E, 0xB4, 0x01, 0xFD, 0x4E, 0xA9, 0x2F, 0xCF, 0x3B, 0x69, 0xB6, 0x4A, 0xFC, 0x71, 0xAD, 0x13, 0xC0, 0xD4, 0x43, 0xCF, 0xBA, 0x89, 0xBD, 0xEF, 0x48, 0xAE, 0x65, 0x43, 0xF7, 0x0F, 0x62, 0x85, 0x0E, 0x20, 0xBA, 0xC4, 0x95, 0xD2, 0x8E, 0xAB, 0xDC, 0x53, 0xCB, 0x83, 0x36, 0xA7, 0xB4, 0xBA, 0xF0, 0x0F, 0x18, 0x68, 0x3B, 0x8E, 0xFF, 0x29, 0xFD, 0x0D, 0xFA, 0xDA, 0x3C, 0x6F, 0xB4, 0xBE, 0xDE, 0x5D, 0xA4, 0x7B, 0xBD, 0xD5, 0x30, 0x5D, 0xDC, 0xFA, 0xDA, 0x10, 0xF1, 0xFC, 0x68, 0xFD, 0x55, 0xE2, 0xAD, 0x81, 0x86, 0x63, 0x4C, 0xB4, 0x67, 0xE9, 0x95, 0x37, 0xC8, 0x4E, 0xFB, 0xE1, 0x36, 0xEC, 0xB5, 0xB8, 0x14, 0x0B, 0x7A, 0x77, 0xD6, 0xF7, 0xBA, 0xE6, 0x0D, 0x30, 0xE7, 0xE9, 0x63, 0x33, 0x31, 0x5C, 0xEA, 0x40, 0x4C, 0x1E, 0xB7, 0xEB, 0x2F, 0x96, 0x76, 0x74, 0x6B, 0x29, 0x5A, 0xB4, 0xB4, 0xBB, 0xA7, 0x3D, 0xAA, 0x51, 0xA6, 0x51, 0x3A, 0x0B, 0xB5, 0xAA, 0x22, 0xB5, 0x74, 0xAA, 0xC9, 0x25, 0xAD, 0xFA, 0x1D, 0x8F, 0xAA, 0x83, 0xD0, 0xDB, 0xAF, 0xA3, 0x75, 0x26, 0x42, 0xB2, 0x75, 0xD6, 0xE9, 0x68, 0x8F, 0xFA, 0x24, 0x53, 0x9D, 0x72, 0xC8, 0x6A, 0x75, 0x5F, 0xA7, 0x40, 0xDC, 0x16, 0xA8, 0xF3, 0x57, 0xCC, 0xAC, 0xA1, 0xEB, 0x2A, 0x1E, 0x9C, 0xA0, 0xDB, 0x5E, 0xBC, 0x50, 0x5B, 0x57, 0x7B, 0x8C, 0x1C, 0x42, 0x40, 0x3E, 0xB2, 0xEA, 0x0E, 0x56, 0xDD, 0x25, 0xCD, 0x6C, 0x7A, 0x95, 0x10, 0xB1, 0x7A, 0xD3, 0xAA, 0x9B, 0xB5, 0xDA, 0x61, 0x95, 0x07, 0xA5, 0x3B, 0x69, 0x7B, 0xF8, 0xE1, 0x5E, 0x87, 0x75, 0xDF, 0x69, 0xE9, 0x4F, 0x47, 0x76, 0xB2, 0xD0, 0x3E, 0x86, 0xD9, 0x5B, 0x1C, 0x66, 0xAB, 0x3A, 0xC8, 0x1E, 0x31, 0xB7, 0x6E, 0x65, 0x6F, 0xF1, 0xC6, 0xDC, 0x32, 0xB1, 0xDF, 0xDE, 0xC1, 0xEB, 0x2D, 0xE6, 0x75, 0x9E, 0x7E, 0x84, 0x5F, 0xF6, 0x06, 0x5B, 0xAE, 0x5F, 0x95, 0x0C, 0xB8, 0xE8, 0xAE, 0x3C, 0x75, 0x53, 0x99, 0x9F, 0xA1, 0x54, 0x7D, 0x28, 0xD1, 0xA9, 0x13, 0xE8, 0xAC, 0x94, 0xCF, 0x41, 0xB5, 0x24, 0xB1, 0xEA, 0xA5, 0x2A, 0xEB, 0xC5, 0x06, 0x4B, 0x1D, 0x1A, 0x68, 0x3D, 0xBD, 0x9D, 0x3D, 0x7E, 0xEA, 0x9C, 0xD2, 0x7C, 0x3B, 0x22, 0x5A, 0xDF, 0x5E, 0x3E, 0x1F, 0x5B, 0x54, 0xDD, 0x40, 0xDC, 0x38, 0xA0, 0xEA, 0x58, 0x31, 0x2F, 0xA6, 0xCA, 0x20, 0xB1, 0xA0, 0xBB, 0xD5, 0xEC, 0xCF, 0xB7, 0xE0, 0x63, 0x1D, 0xF3, 0xA8, 0x07, 0x4E, 0xF2, 0xBB, 0x75, 0x1F, 0x9E, 0x6F, 0x2F, 0xC2, 0xC9, 0x36, 0xCA, 0x23, 0x15, 0x94, 0x79, 0x3D, 0x44, 0xB9, 0xD5, 0xDC, 0x0E, 0x88, 0x9D, 0x95, 0x96, 0x4E, 0x50, 0xFE, 0xAD, 0x7C, 0xAD, 0x9C, 0x7B, 0x95, 0x8E, 0xA2, 0x8B, 0x9E, 0x7D, 0xBC, 0xE8, 0xF9, 0xB9, 0xE6, 0x0C, 0xB1, 0x5F, 0xE7, 0xDA, 0xCF, 0xC5, 0x19, 0x06, 0x4E, 0xA5, 0xC5, 0x8D, 0xB3, 0xAB, 0x77, 0x13, 0x0F, 0xC4, 0x3B, 0x38, 0x8A, 0x0F, 0xFD, 0x6C, 0xEE, 0xBC, 0x79, 0x09, 0xDF, 0x97, 0x99, 0x76, 0xBC, 0xF5, 0x05, 0x95, 0xFB, 0x4E, 0x79, 0xA0, 0x96, 0x32, 0xC7, 0x5B, 0x99, 0xD6, 0x53, 0x94, 0x9B, 0xDB, 0x1E, 0x10, 0xEB, 0x64, 0x28, 0x6D, 0x2E, 0x43, 0x25, 0x53, 0xF9, 0x9A, 0x89, 0x6F, 0x6D, 0x07, 0xD1, 0xD1, 0xA7, 0x76, 0x90, 0xD8, 0xCA, 0xD4, 0xC5, 0x45, 0xEC, 0x6D, 0xE2, 0x9A, 0x20, 0x4E, 0x39, 0xED, 0xFA, 0x44, 0xDC, 0xD0, 0xD6, 0x65, 0x94, 0x78, 0x64, 0xB4, 0xCB, 0xEA, 0x2F, 0x49, 0xF0, 0x38, 0xB6, 0x66, 0x9F, 0xBB, 0xF6, 0xF0, 0xE3, 0x66, 0xE5, 0x8D, 0x67, 0x1B, 0x22, 0x75, 0x69, 0x6A, 0x66, 0xA8, 0x08, 0x19, 0x2D, 0x94, 0xA9, 0xF1, 0xA2, 0x85, 0xEB, 0x56, 0x47, 0xD1, 0x2E, 0x55, 0xAB, 0x49, 0xCC, 0x55, 0x7E, 0x93, 0x10, 0x65, 0xBD, 0x76, 0x60, 0xA5, 0xD5, 0x85, 0xC6, 0xFD, 0xA1, 0x8E, 0xE4, 0x51, 0xA9, 0x72, 0xDD, 0x7F, 0xA2, 0x7B, 0x78, 0xC3, 0x60, 0xB1, 0x6B, 0x5C, 0xFD, 0x89, 0xE2, 0xD8, 0x6F, 0xEE, 0x07, 0xC4, 0x75, 0xE9, 0x8D, 0xF7, 0x7C, 0x3F, 0x02, 0xF9, 0x7E, 0xCD, 0xDA, 0x3E, 0xBA, 0x0E, 0xCF, 0x87, 0x35, 0xBA, 0x7C, 0xA1, 0x31, 0xFC, 0xE9, 0x59, 0xB7, 0x51, 0x9E, 0x03, 0xF2, 0x9C, 0x6F, 0xDF, 0x92, 0x26, 0x56, 0x0C, 0xDF, 0xB0, 0x5A, 0xAC, 0xB9, 0x6B, 0x7D, 0x3D, 0xD1, 0xCD, 0x65, 0x75, 0x92, 0xE8, 0x5E, 0xE9, 0xE7, 0x73, 0xAF, 0x1E, 0xA8, 0x7A, 0xEC, 0x9E, 0xD2, 0xAF, 0x97, 0xB2, 0xE6, 0x7E, 0xA8, 0x29, 0xCF, 0x0F, 0x06, 0x85, 0x1E, 0xE5, 0x45, 0xA7, 0x41, 0xAD, 0x1A, 0x8A, 0x1D, 0xFE, 0x79, 0xB6, 0xFF, 0xEC, 0x0B, 0x43, 0x7B, 0x7B, 0x7C, 0x7D, 0xB2, 0x13, 0x16, 0xCF, 0xF7, 0x39, 0x52, 0xB8, 0x00, 0xF6, 0xA7, 0xFA, 0x34, 0xBE, 0xB8, 0x02, 0xDE, 0x85, 0x7B, 0x8F, 0xCE, 0xBA, 0x00, 0x25, 0xA6, 0x5E, 0x1B, 0x53, 0x7C, 0x91, 0x6B, 0xD2, 0x66, 0x27, 0x26, 0x8A, 0xAD, 0x4E, 0x24, 0x5C, 0x10, 0xDB, 0x75, 0x5D, 0xF8, 0x5A, 0x0C, 0xB8, 0x37, 0xA7, 0xAC, 0x18, 0xBC, 0xB4, 0xB8, 0x92, 0xFF, 0x60, 0x80, 0x9F, 0x55, 0x02, 0x3A, 0x8A, 0xBF, 0xFB, 0x75, 0x59, 0x8F, 0xB8, 0xA4, 0x63, 0x14, 0x94, 0xCD, 0xFE, 0x3A, 0xA4, 0x46, 0x00, 0x34, 0x59, 0xFB, 0x2E, 0x0C, 0x4C, 0xD6, 0x06, 0xCD, 0x7D, 0x78, 0x15, 0xEA, 0x5D, 0xEC, 0x3C, 0xEF, 0xA2, 0xA6, 0xFF, 0xBC, 0xAE, 0x43, 0x0E, 0x1F, 0x86, 0xE8, 0xEB, 0xDD, 0x87, 0xED, 0x1D, 0x01, 0x99, 0xC7, 0x3B, 0x8F, 0xDC, 0xDA, 0x08, 0x1E, 0x5F, 0xE8, 0xFC, 0x6A, 0x85, 0x0E, 0x14, 0x3F, 0x1F, 0x12, 0x11, 0x37, 0x53, 0x72, 0x86, 0x2F, 0x19, 0x1B, 0x28, 0x0E, 0x73, 0x1F, 0xD5, 0x43, 0x1C, 0x5E, 0x79, 0xE4, 0x29, 0x71, 0xC4, 0xD3, 0x61, 0xE3, 0xC4, 0xA8, 0x88, 0xD7, 0x47, 0xFB, 0x0C, 0x03, 0x78, 0x97, 0xD2, 0x67, 0xAE, 0xF8, 0x7E, 0xEB, 0x00, 0x23, 0xF1, 0x43, 0xD3, 0x21, 0xA3, 0xC5, 0x17, 0xA6, 0xDD, 0xFF, 0x83, 0xCA, 0xE6, 0x05, 0xAE, 0x5E, 0x07, 0xA1, 0x59, 0x74, 0xD6, 0x14, 0xEB, 0x09, 0xD0, 0xDF, 0x61, 0xA5, 0x2D, 0x54, 0x4C, 0x19, 0x71, 0x65, 0xDE, 0x64, 0xE8, 0xB5, 0x31, 0x6C, 0xCA, 0xA4, 0x30, 0xD8, 0xDE, 0x6F, 0xD8, 0xD8, 0x70, 0x5B, 0xB8, 0xFD, 0x62, 0xC4, 0x97, 0x5E, 0x4B, 0xE0, 0xCB, 0xFB, 0x59, 0xB3, 0x03, 0x37, 0x4A, 0xCE, 0x82, 0xFE, 0x1D, 0x0F, 0x8A, 0xB1, 0xAB, 0xDA, 0xBD, 0x14, 0x67, 0xD7, 0xF3, 0x2A, 0x11, 0xE7, 0xE4, 0x35, 0xB1, 0x12, 0xE7, 0x2D, 0x7A, 0xDE, 0x63, 0xCC, 0x49, 0x80, 0xE7, 0xF5, 0xC7, 0xB9, 0x89, 0x8F, 0xEF, 0x8D, 0x5B, 0x2B, 0x16, 0x5D, 0x98, 0x98, 0x28, 0x5E, 0xAF, 0x36, 0x61, 0x00, 0x98, 0x86, 0xE7, 0xBF, 0x19, 0xEF, 0x06, 0xA5, 0x5D, 0x37, 0xFD, 0x8C, 0x94, 0xF3, 0x7D, 0x9F, 0x71, 0xE1, 0x5D, 0xE6, 0x40, 0x8F, 0xC0, 0x32, 0xAD, 0xC0, 0xA0, 0x7B, 0x3C, 0x60, 0xFC, 0x6C, 0xD2, 0x80, 0x85, 0x6F, 0xA1, 0xD2, 0xDF, 0xD3, 0x15, 0xE6, 0x7A, 0x42, 0xD5, 0xB6, 0x1F, 0xE6, 0x2F, 0x38, 0x0A, 0x0E, 0x73, 0xB4, 0x7A, 0x2C, 0x0E, 0xEC, 0xCE, 0x68, 0x2E, 0x82, 0x8A, 0x4B, 0x35, 0xA5, 0x5E, 0xAA, 0xA4, 0x5D, 0xA1, 0x91, 0x0B, 0x15, 0x03, 0x34, 0x75, 0x9E, 0x5D, 0x9D, 0xDD, 0x1F, 0xE0, 0xBE, 0xD5, 0x1C, 0x7B, 0xF1, 0xB6, 0xC9, 0xBC, 0x11, 0xE2, 0x99, 0x65, 0xF3, 0xBE, 0x80, 0xE1, 0xCC, 0xBD, 0x97, 0xE7, 0x99, 0x83, 0xEE, 0x8F, 0x8D, 0x0F, 0x17, 0xAE, 0xD2, 0xBC, 0x3B, 0xFF, 0xBF, 0xA5, 0xC5, 0x60, 0xF3, 0x2C, 0xD4, 0x77, 0xBE, 0x23, 0x78, 0x3D, 0x85, 0xC8, 0x31, 0x76, 0x53, 0x46, 0x87, 0xC1, 0xE4, 0xA6, 0x0B, 0x2A, 0x0E, 0xF9, 0x0F, 0xC6, 0x4D, 0x3C, 0x3F, 0x6C, 0xF0, 0x6F, 0x08, 0xFB, 0x52, 0x5C, 0x7D, 0xF8, 0x7E, 0xE8, 0xAB, 0xBD, 0xE7, 0x65, 0x3A, 0xD9, 0x39, 0x54, 0xEB, 0xBB, 0x64, 0x41, 0x97, 0x43, 0x9A, 0x65, 0x21, 0xB0, 0x40, 0xEB, 0xBF, 0x54, 0x81, 0x8E, 0x45, 0x9A, 0x46, 0xF7, 0xAE, 0x2C, 0xCF, 0x46, 0xF2, 0xB7, 0x25, 0xCD, 0x12, 0xCF, 0x75, 0x4F, 0x5A, 0x2B, 0x66, 0x0F, 0x5D, 0x76, 0x02, 0x74, 0xD2, 0xD7, 0xBB, 0xAD, 0x88, 0x04, 0x98, 0xBF, 0x78, 0x9D, 0xA1, 0x38, 0xF1, 0x5E, 0x6A, 0x22, 0xE8, 0xFD, 0xEC, 0x76, 0x30, 0x7D, 0x09, 0xB8, 0x9C, 0x86, 0x9D, 0xDF, 0x9D, 0x56, 0x76, 0x9B, 0x00, 0x19, 0xA3, 0xE7, 0x1C, 0xF3, 0xD3, 0x83, 0xDD, 0x0F, 0xCF, 0x15, 0xFA, 0x4A, 0x1D, 0xD4, 0xF4, 0xEB, 0x89, 0xC0, 0xE9, 0x30, 0xE7, 0x9B, 0x36, 0xBB, 0x9F, 0x09, 0xE3, 0xF7, 0x68, 0xF3, 0xEB, 0x75, 0x30, 0x56, 0xBB, 0xFF, 0x03, 0x27, 0x43, 0x94, 0x8D, 0x56, 0x93, 0xF7, 0x80, 0x48, 0x6D, 0x8D, 0x1C, 0x56, 0xE9, 0xEE, 0x8A, 0x2D, 0x2B, 0x00, 0xAE, 0x86, 0x6C, 0x4D, 0x15, 0x0F, 0x5C, 0xDB, 0xF4, 0x0B, 0x68, 0xB3, 0x69, 0xBB, 0xBC, 0xC3, 0x60, 0xA1, 0xE3, 0xE6, 0x2C, 0x71, 0xA2, 0xCB, 0x9E, 0xDA, 0xE2, 0x90, 0xCB, 0x47, 0x0D, 0xC4, 0x0E, 0x3B, 0xCF, 0x3D, 0x00, 0xEB, 0xF5, 0x70, 0xC9, 0xC2, 0x71, 0x73, 0x8B, 0x34, 0xB8, 0x31, 0x6E, 0xDA, 0xE9, 0xFA, 0x8B, 0xE1, 0x72, 0xFE, 0x99, 0x9A, 0xF5, 0xEA, 0xC0, 0xD1, 0xF7, 0xC5, 0x95, 0xEA, 0xF7, 0x87, 0xB4, 0x8E, 0x5A, 0x7D, 0xF1, 0x12, 0x56, 0x6B, 0x3B, 0x65, 0x93, 0x1D, 0x90, 0x18, 0xAD, 0xBD, 0x6F, 0xCA, 0x43, 0xFC, 0x5C, 0xAD, 0x9F, 0xEC, 0x0C, 0x0B, 0xB5, 0x7A, 0xC0, 0x67, 0x52, 0x81, 0x4B, 0xE6, 0x5E, 0x80, 0xD3, 0x9D, 0xD3, 0xEB, 0x88, 0xBB, 0x8B, 0x52, 0x77, 0x82, 0x5E, 0xDD, 0x95, 0x7A, 0xBB, 0xFD, 0x01, 0xA6, 0x4D, 0xCE, 0x18, 0x28, 0x86, 0x25, 0x1E, 0x6B, 0x2E, 0x06, 0xB7, 0xBD, 0xF9, 0x55, 0x6C, 0xE6, 0xF2, 0x64, 0x2C, 0xE8, 0x2D, 0x87, 0x37, 0xF3, 0xAA, 0x0C, 0xAB, 0x2E, 0xAB, 0xB8, 0xF5, 0xE8, 0x1E, 0x15, 0x8B, 0xE1, 0xF3, 0xB1, 0xFC, 0xED, 0x15, 0x26, 0xC2, 0xB3, 0xE1, 0x5F, 0xEF, 0xDB, 0xB6, 0x85, 0x8B, 0x5F, 0xFE, 0xE8, 0x96, 0xE9, 0x0C, 0xB9, 0xDA, 0x0E, 0x68, 0xDD, 0x09, 0xB2, 0xDB, 0x69, 0xEB, 0x48, 0x1A, 0xA4, 0x55, 0xD7, 0xF6, 0x94, 0x05, 0xB0, 0x53, 0x7B, 0x5E, 0x6A, 0x44, 0x5F, 0xCF, 0x38, 0x14, 0x01, 0x90, 0x77, 0x2D, 0x67, 0x01, 0xE8, 0xE9, 0x6E, 0xCC, 0xCE, 0x2A, 0x01, 0xFD, 0x98, 0x85, 0x5F, 0xF6, 0x57, 0x04, 0x18, 0x9B, 0x75, 0xA2, 0x93, 0xD8, 0xAF, 0xC5, 0xAD, 0x62, 0xB1, 0xED, 0xE9, 0x0F, 0x75, 0xC4, 0x2A, 0xB7, 0xFF, 0xB7, 0x0F, 0xEF, 0x47, 0x56, 0x29, 0xDB, 0xD2, 0x03, 0x4D, 0xB4, 0x33, 0xBE, 0x41, 0x2B, 0xF4, 0x9D, 0xE5, 0xE3, 0x75, 0x97, 0x8D, 0xBB, 0x8B, 0x37, 0xA2, 0x0D, 0xB7, 0xC2, 0x8F, 0x97, 0xDF, 0x6F, 0x1A, 0x99, 0x41, 0x91, 0x9C, 0x8B, 0x02, 0xD7, 0x83, 0x94, 0xE7, 0x37, 0x68, 0xE7, 0xD9, 0x83, 0xE1, 0xA4, 0x76, 0x8E, 0x64, 0xA2, 0x7F, 0x7A, 0xD0, 0x51, 0x07, 0xD0, 0x09, 0xDA, 0xDD, 0xEB, 0x80, 0x11, 0xE8, 0xF5, 0x5C, 0x71, 0xED, 0x50, 0x06, 0xC0, 0x34, 0x9F, 0xD3, 0xEB, 0xC5, 0xB0, 0x23, 0x85, 0x0B, 0xC5, 0xC0, 0xC5, 0xBF, 0xDB, 0x83, 0x8E, 0xBB, 0xB3, 0xFF, 0xFF, 0xEA, 0xA1, 0xA6, 0xE6, 0xDA, 0xBD, 0x33, 0x8F, 0xB1, 0x70, 0x35, 0xBB, 0xAB, 0xAD, 0x86, 0x13, 0x40, 0x67, 0xA6, 0xB6, 0x1A, 0xC5, 0xE2, 0x8B, 0xD4, 0x41, 0x59, 0x38, 0x8A, 0xDB, 0x2B, 0x82, 0x78, 0xBD, 0x13, 0xE2, 0xDD, 0x7F, 0xF3, 0xD9, 0x0F, 0xBF, 0x64, 0x2F, 0x02, 0xBE, 0x8F, 0x53, 0x7E, 0xD8, 0x25, 0xE6, 0x5D, 0x3C, 0x1E, 0x0E, 0xBA, 0x95, 0x36, 0x7C, 0x3A, 0xAA, 0x0F, 0x7A, 0x2D, 0xE6, 0x9B, 0x9F, 0xDD, 0x00, 0x30, 0xB6, 0x7A, 0xD1, 0x65, 0xB1, 0xD7, 0x0A, 0xF9, 0x2E, 0xFD, 0x00, 0xF7, 0xDB, 0xA2, 0x49, 0x68, 0x75, 0xED, 0xE8, 0x8D, 0x83, 0x74, 0xEE, 0xEB, 0x5E, 0xD5, 0x8E, 0xC3, 0xDA, 0xDC, 0x45, 0x5F, 0xDB, 0xE9, 0xEA, 0x76, 0x54, 0x79, 0x1D, 0xCD, 0x94, 0x23, 0xB7, 0x28, 0xE3, 0xCF, 0x29, 0xF7, 0x2C, 0x55, 0xDE, 0x71, 0x54, 0x3E, 0x79, 0xA6, 0x7C, 0x6B, 0x81, 0x78, 0xAE, 0x78, 0x0C, 0xEC, 0xEA, 0x70, 0x4A, 0x7A, 0xBC, 0xA6, 0x89, 0x66, 0xE7, 0xFE, 0x00, 0x4C, 0xAD, 0x50, 0x74, 0x54, 0x1C, 0xD8, 0xE6, 0xA7, 0x3B, 0xE8, 0x17, 0xB5, 0xAB, 0x2B, 0xF9, 0xBA, 0xF3, 0x9C, 0xB3, 0x45, 0xC3, 0xC7, 0xE5, 0x96, 0x69, 0xD5, 0xDC, 0x40, 0x83, 0x81, 0xA0, 0x1D, 0x47, 0x7D, 0xE3, 0x64, 0xD1, 0xF9, 0x32, 0x88, 0x3E, 0xAF, 0x94, 0xA1, 0x28, 0x67, 0xA0, 0x4C, 0x4A, 0x55, 0x66, 0xF4, 0x54, 0x1E, 0x1E, 0xA4, 0xBC, 0x68, 0xA7, 0xBC, 0x79, 0x5D, 0xFE, 0x2D, 0x7F, 0x1F, 0x44, 0xBD, 0xA5, 0xEA, 0xEF, 0xB3, 0x80, 0xAD, 0x53, 0xD9, 0x24, 0xD1, 0xF9, 0xB6, 0x75, 0x90, 0xF6, 0xF9, 0x10, 0x0F, 0xCC, 0xB4, 0xEA, 0xCD, 0x72, 0x7E, 0xF7, 0xC7, 0x48, 0xEF, 0x26, 0x78, 0xB8, 0xBB, 0x99, 0xF4, 0x25, 0x98, 0x79, 0xB3, 0xBC, 0xA1, 0xB8, 0x36, 0xD0, 0x7A, 0xB6, 0x98, 0x33, 0xC9, 0xE2, 0xC8, 0xBF, 0x58, 0xB8, 0xB8, 0xD0, 0xD0, 0xFF, 0x9D, 0x13, 0x3C, 0xC8, 0xD4, 0xCD, 0xBB, 0x37, 0x1C, 0x3E, 0x87, 0xC1, 0xF9, 0xFD, 0x6A, 0x9F, 0x3D, 0x36, 0x41, 0x79, 0xA8, 0xAD, 0x32, 0xAF, 0xA1, 0x28, 0x37, 0xDB, 0x57, 0x20, 0x4A, 0xCF, 0xAA, 0x94, 0xC9, 0xFF, 0xAA, 0xD1, 0xDF, 0x65, 0xDB, 0x8A, 0xD5, 0xFB, 0xD8, 0x94, 0xD6, 0x3E, 0x7F, 0xB9, 0x4D, 0x7F, 0x83, 0xDA, 0xDA, 0x4C, 0x2B, 0x30, 0xE8, 0x02, 0xD2, 0xD3, 0xF9, 0x3C, 0xAC, 0xA1, 0xE1, 0x2C, 0xF9, 0xFA, 0x34, 0x57, 0xBB, 0x3B, 0xE2, 0xBA, 0x56, 0xD6, 0xF7, 0xC4, 0x7D, 0xF7, 0x2D, 0x7C, 0xFF, 0x9E, 0x86, 0x6B, 0xC1, 0x06, 0x7B, 0x5F, 0x01, 0xCF, 0x66, 0xEA, 0x2C, 0xBC, 0x63, 0x08, 0x3F, 0x4A, 0xE0, 0x58, 0x14, 0x2A, 0xF7, 0x97, 0x32, 0xE7, 0xA0, 0x32, 0xA3, 0xAE, 0x28, 0x37, 0x9B, 0x67, 0x20, 0x56, 0x2D, 0xA3, 0x04, 0xB0, 0x6D, 0x24, 0x56, 0x5C, 0x68, 0xBD, 0x5F, 0x7B, 0xF4, 0x0F, 0x37, 0xCD, 0x35, 0x3C, 0xA7, 0xB9, 0xBA, 0xD3, 0x5D, 0xDD, 0x48, 0xAD, 0xA7, 0x52, 0x65, 0xE0, 0x45, 0xF5, 0x7D, 0x93, 0xCF, 0xD9, 0xB9, 0x8A, 0x6B, 0x8F, 0x94, 0xFB, 0x4F, 0xCC, 0x7B, 0x67, 0xB9, 0xA4, 0x78, 0x18, 0xDC, 0x2C, 0x30, 0xFE, 0xF1, 0xA4, 0x10, 0xDE, 0x95, 0x83, 0x4B, 0x25, 0xF0, 0xBF, 0x63, 0x5C, 0xA6, 0x4C, 0x7B, 0xAD, 0x4C, 0xF5, 0x55, 0x6E, 0x6D, 0xFB, 0xFF, 0xAF, 0x0B, 0x1D, 0x6A, 0x2B, 0x4B, 0x01, 0x96, 0xAF, 0xFE, 0xF7, 0xB8, 0xBC, 0xB1, 0x3D, 0x24, 0xD6, 0x78, 0x5F, 0x31, 0x50, 0x6C, 0x7D, 0xD2, 0x46, 0x9B, 0xBF, 0x54, 0xFB, 0x36, 0xC0, 0x10, 0x75, 0x1C, 0x11, 0x76, 0x5D, 0xC5, 0xE4, 0x93, 0xE5, 0xF5, 0x7F, 0xB4, 0x81, 0xBC, 0x28, 0xDB, 0x6B, 0xCF, 0x6B, 0xC2, 0x1D, 0xCB, 0x32, 0x79, 0x37, 0x36, 0xC3, 0x97, 0x45, 0x16, 0x87, 0x4F, 0x54, 0x53, 0xDF, 0xBB, 0xBD, 0x99, 0x72, 0x7D, 0x63, 0x94, 0xAB, 0x95, 0x6A, 0x1E, 0xA5, 0xD3, 0x4B, 0xEB, 0x0D, 0x55, 0x52, 0xF9, 0xCE, 0x96, 0x4A, 0xD7, 0x73, 0x20, 0x9F, 0x07, 0x70, 0xAC, 0x2E, 0x56, 0x4A, 0xB3, 0x4F, 0x16, 0x1B, 0xD5, 0x74, 0x28, 0xAB, 0xF5, 0xAD, 0x9C, 0xFA, 0x0C, 0x82, 0x3F, 0x7E, 0x30, 0xD6, 0xB9, 0xBA, 0xD3, 0xFB, 0x6B, 0xB0, 0xBC, 0x66, 0xF5, 0x2A, 0x4F, 0x7E, 0x42, 0x76, 0x13, 0xFB, 0xF4, 0x3B, 0x96, 0x50, 0x74, 0xA6, 0xCA, 0x83, 0x13, 0x5B, 0xA1, 0xE4, 0x7D, 0xE5, 0xEA, 0x59, 0xFF, 0xDB, 0xF7, 0x2B, 0xD9, 0x6E, 0x98, 0x2D, 0x96, 0x0D, 0x59, 0xFD, 0x5B, 0xB4, 0x36, 0x59, 0xB6, 0x5B, 0xAC, 0xBA, 0x79, 0xE9, 0x10, 0xD1, 0xC9, 0xF8, 0xE7, 0xB6, 0x46, 0x5B, 0x01, 0xFE, 0x3A, 0x34, 0xDA, 0x2D, 0xFE, 0x89, 0x69, 0xBA, 0x52, 0xFC, 0xDE, 0xC9, 0x3E, 0x17, 0xEC, 0x5C, 0x8B, 0xF7, 0x82, 0x49, 0x8E, 0x9B, 0xDD, 0x97, 0x62, 0x70, 0x5A, 0xE2, 0x7C, 0xEF, 0xBD, 0x33, 0x78, 0xDE, 0x70, 0x89, 0x79, 0x90, 0x09, 0xA1, 0xE3, 0x6A, 0xAF, 0xBD, 0xF9, 0x1B, 0x66, 0xBD, 0xA9, 0x7B, 0xF7, 0x92, 0x2E, 0xA4, 0xAD, 0x70, 0xBD, 0x7C, 0xDC, 0x17, 0x1E, 0xBD, 0xAE, 0x5D, 0x2D, 0xA3, 0x2B, 0xFC, 0x6C, 0xE7, 0xB6, 0x6B, 0xBD, 0xBD, 0xE4, 0x34, 0x2E, 0xBD, 0xF8, 0xBC, 0xD8, 0xCC, 0x29, 0x2E, 0x4E, 0x6C, 0xD1, 0x7C, 0x66, 0x35, 0xD1, 0x63, 0xDD, 0xD4, 0xAF, 0x62, 0xFB, 0x41, 0xEF, 0x7F, 0x78, 0x2E, 0x05, 0xF8, 0xB4, 0xCE, 0xB3, 0x1A, 0x62, 0x80, 0x57, 0xAE, 0xF8, 0xFE, 0x95, 0x97, 0x29, 0xE8, 0xDF, 0x7E, 0xB6, 0xDD, 0xC1, 0x10, 0x6A, 0xB5, 0x2A, 0x72, 0x03, 0xA3, 0xA1, 0x2D, 0x87, 0x5C, 0xED, 0x0C, 0xB5, 0xBA, 0x35, 0xCB, 0xC8, 0xAF, 0x01, 0x3E, 0xE3, 0x5B, 0x06, 0xA4, 0xAF, 0x82, 0xE1, 0xCE, 0xAD, 0x6F, 0xED, 0xB0, 0x87, 0x14, 0x9A, 0x59, 0x25, 0x8F, 0x81, 0x9B, 0x59, 0x8D, 0x9D, 0xE3, 0x57, 0xC2, 0xD7, 0x0E, 0xBE, 0x61, 0x33, 0x16, 0x48, 0x4E, 0x7F, 0xFF, 0x08, 0x07, 0x71, 0xC0, 0x86, 0x41, 0xF1, 0x88, 0x05, 0xFD, 0xC6, 0x8B, 0x83, 0xEF, 0xF5, 0xAA, 0x24, 0x86, 0xB5, 0x7A, 0x1A, 0xD8, 0xA5, 0x01, 0xC0, 0x93, 0x27, 0x9D, 0xD7, 0x89, 0x8F, 0x87, 0x77, 0xFE, 0x2D, 0x3E, 0x18, 0xDA, 0x25, 0x46, 0xBC, 0x95, 0xE9, 0x9B, 0x00, 0xA5, 0x1A, 0x9E, 0x3E, 0xD5, 0xFC, 0x04, 0x54, 0xDD, 0x99, 0x92, 0x5A, 0xD9, 0x06, 0x5A, 0xCD, 0x9B, 0xDD, 0x01, 0xCA, 0xF7, 0xEB, 0x71, 0x62, 0xD2, 0x66, 0x08, 0x08, 0x09, 0x2A, 0x19, 0xE9, 0x07, 0x2B, 0xB2, 0xBA, 0x1C, 0x18, 0x30, 0x03, 0x4E, 0xA5, 0x06, 0x1F, 0xEC, 0x76, 0x11, 0x3E, 0x1C, 0x19, 0xE6, 0xD1, 0xDE, 0x46, 0x72, 0xA6, 0x66, 0xBA, 0x8F, 0x17, 0x67, 0xF6, 0xAA, 0xB3, 0x0F, 0x71, 0x43, 0xD5, 0x5A, 0xE2, 0xEC, 0x19, 0xF6, 0x88, 0xB1, 0xA9, 0xF7, 0xBF, 0x0C, 0x69, 0x04, 0x50, 0xF4, 0x72, 0xA8, 0x95, 0x78, 0xBB, 0xF7, 0x90, 0x40, 0xF1, 0xC2, 0xB1, 0xC1, 0xB3, 0xC4, 0x43, 0x13, 0x42, 0xB7, 0x83, 0xDE, 0xE9, 0x9D, 0xEB, 0xFB, 0x7A, 0x83, 0xEE, 0xA9, 0x25, 0x4D, 0x7A, 0xDB, 0x83, 0xDD, 0xC1, 0x21, 0x55, 0xBC, 0xB2, 0xC1, 0xC7, 0x18, 0x00, 0x66, 0xFE, 0x01, 0xA3, 0xA7, 0x43, 0xDE, 0xC4, 0x24, 0x42, 0xF9, 0x13, 0x39, 0xCF, 0xC6, 0x4E, 0x85, 0x2A, 0xFB, 0x9E, 0x4D, 0x1E, 0x7B, 0x11, 0x9C, 0xBA, 0xFE, 0x7B, 0x38, 0xDD, 0x08, 0xAA, 0x2E, 0xD6, 0x72, 0xE7, 0x82, 0xFD, 0x51, 0x2D, 0xB7, 0x40, 0xF3, 0x85, 0xE6, 0x59, 0x4D, 0x34, 0xB3, 0x0A, 0x97, 0x46, 0xFF, 0x01, 0xB8, 0x99, 0x11, 0x73, 0x55, 0x3C, 0x5F, 0x2F, 0xA6, 0x91, 0x98, 0x3B, 0x73, 0xC2, 0x15, 0x71, 0xC3, 0xE6, 0xC8, 0x93, 0xA0, 0xAB, 0xB3, 0x60, 0xEE, 0x98, 0x63, 0x00, 0x13, 0xF5, 0x26, 0x7D, 0x03, 0xF3, 0x25, 0xDD, 0x42, 0xC6, 0x97, 0x82, 0xC6, 0xAB, 0xA1, 0xF7, 0x3E, 0xEB, 0x17, 0xFD, 0x67, 0x43, 0x44, 0xC9, 0x84, 0xA8, 0xAE, 0xC5, 0x10, 0x76, 0x62, 0xDF, 0xD2, 0x80, 0x93, 0x30, 0xE0, 0xCE, 0xF3, 0x0E, 0x41, 0x1E, 0xFA, 0x0B, 0xFA, 0x69, 0x3D, 0xD7, 0x7E, 0x79, 0xD0, 0x43, 0xDB, 0x57, 0x22, 0x93, 0xA1, 0xFB, 0x18, 0xED, 0x0C, 0xF8, 0x0E, 0x04, 0xA6, 0x6B, 0x7D, 0x98, 0x37, 0xD0, 0xA9, 0xAB, 0x66, 0xF8, 0xCD, 0x5F, 0xF3, 0x66, 0x01, 0x5C, 0xAA, 0xB5, 0x68, 0xAC, 0x78, 0xD8, 0x6C, 0xDE, 0x73, 0x71, 0xB3, 0xFF, 0x74, 0x0F, 0xD0, 0xB1, 0x9D, 0x5F, 0x6B, 0xCA, 0x0A, 0x80, 0xF1, 0x1F, 0x66, 0x4D, 0x16, 0xC3, 0x6C, 0x97, 0x8F, 0x10, 0x7D, 0x7F, 0x26, 0x7F, 0x83, 0x2A, 0x65, 0x60, 0x45, 0x8B, 0x8A, 0x8F, 0xBD, 0x66, 0xC2, 0x86, 0x29, 0x63, 0xDA, 0xB9, 0xEB, 0xC0, 0xFA, 0x17, 0xB9, 0xBD, 0x1B, 0x19, 0xC1, 0xCA, 0x6B, 0x2F, 0x17, 0x37, 0xF9, 0x0C, 0x73, 0x74, 0xFE, 0xF5, 0x6D, 0xD3, 0x01, 0x26, 0x68, 0xFB, 0x59, 0x87, 0x20, 0x88, 0xD2, 0xF6, 0xB7, 0x80, 0xD3, 0x30, 0x7C, 0x9A, 0xD6, 0x87, 0x59, 0x0B, 0xE1, 0x45, 0x32, 0xCB, 0xBE, 0x7A, 0x7E, 0x65, 0x11, 0xC0, 0xA9, 0x46, 0xAB, 0x1C, 0xC5, 0x3D, 0xF5, 0x13, 0x5C, 0xC4, 0x04, 0xAB, 0x05, 0xD5, 0x01, 0xC7, 0x49, 0x23, 0x16, 0xCC, 0x02, 0x18, 0xE6, 0x9E, 0x54, 0x4A, 0x0C, 0x1E, 0x98, 0xEA, 0x2D, 0x7A, 0x3E, 0xCB, 0xBB, 0x2E, 0xC2, 0x81, 0xE9, 0x15, 0xDF, 0xD4, 0x76, 0x83, 0xA3, 0x4B, 0x22, 0x7E, 0x56, 0x71, 0x85, 0xFC, 0x84, 0x8C, 0x3B, 0x15, 0x0C, 0x21, 0xEF, 0xFC, 0xF3, 0x7A, 0x95, 0x0A, 0x60, 0xE7, 0xB7, 0xBF, 0x46, 0x0E, 0xD7, 0x21, 0x69, 0x91, 0xF6, 0xFE, 0x6C, 0x01, 0x8B, 0xB4, 0x1D, 0xDA, 0xB5, 0x11, 0xCC, 0x9D, 0xAC, 0xED, 0x90, 0xB7, 0x21, 0xEE, 0x92, 0xD6, 0x41, 0x69, 0x78, 0xD1, 0x2B, 0xA5, 0x2E, 0xC0, 0x81, 0x34, 0x55, 0x77, 0xAD, 0xD7, 0x5D, 0xDD, 0x16, 0xF4, 0x0D, 0xE3, 0x72, 0x93, 0xD2, 0x01, 0xA2, 0x56, 0x6C, 0x3C, 0x24, 0x86, 0x58, 0xA6, 0x2F, 0x14, 0x3D, 0xFF, 0x1D, 0xBB, 0x2E, 0x3A, 0xFD, 0x52, 0xFD, 0x09, 0xB8, 0x75, 0xCB, 0x26, 0xCE, 0xFC, 0x16, 0xDC, 0x5D, 0x1D, 0xFA, 0xD5, 0xA0, 0x04, 0xEE, 0x59, 0xEF, 0x5A, 0xAA, 0x77, 0x14, 0x0A, 0x0D, 0x9E, 0x56, 0xD4, 0x3D, 0x0F, 0xA7, 0xB3, 0x4B, 0x52, 0xF5, 0x2F, 0x41, 0x8E, 0xB6, 0x26, 0x1B, 0x3D, 0x81, 0x1D, 0x5A, 0x7D, 0x68, 0x5E, 0x15, 0xB6, 0x9A, 0xC9, 0xDF, 0xB8, 0x85, 0x4D, 0x07, 0xB5, 0x0E, 0x46, 0xE0, 0xE9, 0xE4, 0xF4, 0x46, 0x00, 0x7B, 0x8C, 0xB6, 0x17, 0x83, 0xEE, 0xCF, 0x65, 0x2D, 0xB6, 0x5C, 0x01, 0x3D, 0xE7, 0x29, 0xD3, 0x76, 0x6C, 0x03, 0x18, 0xF6, 0x37, 0xAF, 0x9C, 0xD8, 0xF9, 0xCB, 0x79, 0x37, 0xB1, 0x81, 0xDF, 0xBD, 0x67, 0xA2, 0xF5, 0xB4, 0x37, 0x7F, 0x45, 0xF8, 0x6A, 0x54, 0x79, 0x8C, 0xF8, 0x63, 0x71, 0xC8, 0x13, 0xF1, 0xE7, 0x80, 0x75, 0x43, 0x10, 0x2B, 0x5C, 0x3B, 0x2A, 0x7E, 0x70, 0xFA, 0xD2, 0x4F, 0x2C, 0xD8, 0xA9, 0xD6, 0xC6, 0x73, 0x71, 0xCA, 0xE3, 0xEF, 0x95, 0x87, 0xAF, 0x8A, 0x87, 0x02, 0xF6, 0xAE, 0x01, 0xD8, 0x58, 0x75, 0xCF, 0x5C, 0x30, 0x2C, 0x37, 0x6F, 0x6F, 0xFA, 0x2D, 0x80, 0x31, 0x59, 0x87, 0x9D, 0xC4, 0x3E, 0xB1, 0x6A, 0x5E, 0xE7, 0x1D, 0xF6, 0xEE, 0x87, 0xE8, 0xAC, 0xAF, 0x7E, 0x1A, 0xAD, 0x0E, 0x30, 0xFC, 0x6E, 0xD6, 0x0D, 0x39, 0x3B, 0xFC, 0x0B, 0x62, 0xCF, 0xD3, 0xCA, 0xB8, 0xE7, 0xCA, 0xD4, 0x1A, 0xCA, 0xBB, 0xFE, 0xCA, 0xFF, 0x73, 0x4E, 0x77, 0x5C, 0xF9, 0xB9, 0x8E, 0xF2, 0xF5, 0x1B, 0x31, 0x6D, 0x40, 0x9E, 0xF4, 0xE7, 0x36, 0x26, 0xA6, 0xEC, 0xDD, 0xA9, 0x59, 0x67, 0xCA, 0x8C, 0xFC, 0x2A, 0xEA, 0x71, 0xB8, 0xF9, 0x58, 0xEC, 0x12, 0xF0, 0xF3, 0xA0, 0xD8, 0x58, 0x3A, 0xEC, 0x40, 0xC5, 0xCF, 0xDA, 0x6E, 0xB0, 0x0A, 0x3D, 0x64, 0x87, 0x36, 0x30, 0x6C, 0x27, 0xD6, 0xB9, 0x02, 0x62, 0x97, 0x39, 0xCA, 0x51, 0x9D, 0x94, 0x49, 0xAD, 0x94, 0x99, 0x05, 0xCA, 0x22, 0x4B, 0x65, 0x49, 0x7D, 0xA5, 0xFA, 0x8D, 0xBF, 0x0F, 0x89, 0x9B, 0x1A, 0x1D, 0x6A, 0x06, 0xBA, 0x1B, 0xE6, 0xF7, 0x3D, 0x61, 0x0F, 0x30, 0x76, 0xEC, 0xED, 0x8D, 0x62, 0xAF, 0x2F, 0x9F, 0x3A, 0x03, 0x3D, 0x3C, 0xDC, 0xFF, 0x44, 0x82, 0xEA, 0xB4, 0x8B, 0x16, 0xCF, 0xB5, 0x0A, 0xC4, 0x56, 0xDF, 0x16, 0x99, 0x66, 0xFC, 0xD3, 0xB1, 0x14, 0xEB, 0xFC, 0x01, 0xB1, 0x53, 0x3D, 0x65, 0x28, 0xCA, 0xD8, 0x3D, 0xCA, 0x0D, 0xE7, 0x94, 0x39, 0x25, 0xCA, 0x6B, 0x27, 0x95, 0x85, 0xEF, 0x95, 0xFF, 0x99, 0x20, 0x55, 0x55, 0x23, 0x10, 0xC1, 0xF4, 0x9B, 0x71, 0x0F, 0xB1, 0x4A, 0xB8, 0x49, 0x05, 0xAD, 0x77, 0xF2, 0xA9, 0xFE, 0x52, 0xDD, 0x4F, 0xDA, 0xBD, 0x0F, 0xF6, 0x0C, 0x02, 0xCD, 0xEB, 0x41, 0x26, 0x22, 0x0C, 0x59, 0xA3, 0xDF, 0x4C, 0x9C, 0xEA, 0x62, 0xDA, 0x41, 0x4C, 0x0A, 0x33, 0x1E, 0xF2, 0x07, 0x48, 0x3B, 0xA0, 0x3F, 0xF1, 0xFD, 0x7F, 0x70, 0xB4, 0x32, 0xD1, 0x0F, 0x9F, 0xC3, 0x2D, 0x13, 0xB8, 0x56, 0x07, 0x5E, 0x56, 0x83, 0x63, 0xDB, 0xE1, 0x7B, 0x10, 0xEC, 0x55, 0x13, 0x57, 0x32, 0xD7, 0x2A, 0xD3, 0xDA, 0x89, 0x72, 0x33, 0x2B, 0x0B, 0x22, 0x80, 0xA9, 0xB7, 0x68, 0x33, 0xCB, 0x44, 0xAB, 0xB3, 0x0C, 0xFC, 0x5C, 0xF3, 0xF5, 0x1A, 0x68, 0x1F, 0xDF, 0x6B, 0x39, 0x82, 0x22, 0xED, 0x38, 0x76, 0x06, 0xA8, 0xDA, 0x81, 0x81, 0xB1, 0xBA, 0xFD, 0xC4, 0xC9, 0xF5, 0xCC, 0xAA, 0x89, 0xAB, 0xC2, 0x8C, 0x23, 0xFF, 0x5E, 0x81, 0xCC, 0x05, 0x7A, 0x2B, 0xDF, 0x2E, 0x81, 0x93, 0xB5, 0xA1, 0xA8, 0x00, 0xEE, 0xC6, 0xC2, 0x85, 0x77, 0xF0, 0x61, 0x18, 0xEC, 0x2F, 0x54, 0x3F, 0xBB, 0x7B, 0xBC, 0x72, 0xE7, 0x12, 0xE5, 0xD6, 0x4D, 0xA2, 0xDC, 0x4C, 0xEE, 0x80, 0x68, 0x69, 0xA4, 0x04, 0x33, 0x4F, 0x93, 0xA5, 0xA2, 0x7D, 0x25, 0x53, 0x6D, 0xED, 0xD5, 0xEB, 0xDC, 0xF8, 0x93, 0xCE, 0x49, 0xED, 0xF1, 0x59, 0xD5, 0x21, 0x11, 0xB4, 0x8F, 0xFD, 0xFB, 0xAD, 0x17, 0x61, 0xE2, 0x27, 0xD3, 0x41, 0xE2, 0xAA, 0x97, 0x06, 0xE5, 0xBF, 0x7E, 0x80, 0x8C, 0x02, 0xFD, 0xF8, 0xFF, 0xFA, 0xC2, 0xD9, 0xEE, 0x70, 0x3B, 0x1E, 0x9E, 0xEE, 0x86, 0xE3, 0x0B, 0xE1, 0x87, 0x15, 0xA4, 0x9F, 0x53, 0x3F, 0xB3, 0x29, 0x51, 0xB9, 0xF6, 0xB9, 0x72, 0xB5, 0xA5, 0x28, 0x37, 0xF3, 0xA7, 0x20, 0x9A, 0x78, 0x2B, 0x0D, 0x5B, 0x80, 0xFC, 0x35, 0x04, 0x28, 0xFB, 0xD2, 0xA4, 0x50, 0xAB, 0xCE, 0x2B, 0xBA, 0xC5, 0xE9, 0x0D, 0x97, 0x8F, 0xDB, 0x7C, 0xD4, 0x1B, 0xAC, 0x7D, 0x7D, 0x59, 0xAF, 0x2C, 0xF8, 0x79, 0x0E, 0xC6, 0x9A, 0x19, 0xDB, 0xBF, 0x79, 0x0E, 0xF1, 0xD6, 0x86, 0x53, 0x1E, 0x95, 0x86, 0xDD, 0x91, 0x46, 0x65, 0x6F, 0xBB, 0xC3, 0xD9, 0x10, 0xBD, 0x68, 0x39, 0xDB, 0x7B, 0x15, 0xA9, 0xD7, 0x6B, 0x7F, 0xB2, 0xCA, 0xD9, 0x88, 0x72, 0xD9, 0x3D, 0x65, 0x52, 0x63, 0xE5, 0xAA, 0x68, 0xE5, 0xCF, 0x15, 0x55, 0x17, 0x00, 0xFC, 0x2D, 0x6B, 0x77, 0x5C, 0xFC, 0xBD, 0xB3, 0x5A, 0x96, 0xF8, 0xBD, 0x25, 0xE8, 0xAC, 0xB3, 0xA9, 0xF9, 0x5D, 0xA6, 0xB7, 0x73, 0xAC, 0xFE, 0x7E, 0x6F, 0x05, 0x8D, 0x86, 0x59, 0x35, 0xFE, 0x64, 0x00, 0xFE, 0xEF, 0x2D, 0x6F, 0x3F, 0x5D, 0x09, 0x43, 0xE7, 0x19, 0x77, 0x29, 0x30, 0x85, 0xD8, 0x64, 0xB3, 0xC6, 0x57, 0x0C, 0x61, 0xCB, 0x59, 0x93, 0xF2, 0x67, 0x5A, 0xC1, 0x85, 0x35, 0xC6, 0x6D, 0x0F, 0xFC, 0x86, 0x8F, 0xB9, 0xE6, 0xB7, 0xD4, 0xDF, 0x93, 0x34, 0xDF, 0xBC, 0x3E, 0x57, 0x2C, 0xB5, 0x79, 0xF1, 0x6C, 0xB1, 0xFC, 0xB3, 0x79, 0xF7, 0x44, 0xFB, 0xAE, 0xF3, 0xCA, 0x8B, 0xD5, 0xF2, 0xBF, 0xDC, 0xA8, 0xF9, 0x19, 0xA0, 0x58, 0xD7, 0x31, 0x4B, 0xFC, 0x5C, 0xC9, 0xE9, 0xB1, 0xF8, 0xAA, 0xD8, 0x2E, 0x00, 0x4A, 0x35, 0x79, 0x9C, 0x0C, 0x26, 0x03, 0xAB, 0xEA, 0x3C, 0xF0, 0x82, 0xEA, 0xDD, 0xCA, 0x9B, 0x14, 0x66, 0x42, 0x8B, 0xD8, 0x72, 0xA1, 0x97, 0x8E, 0x42, 0xCF, 0xF1, 0x65, 0xFC, 0x4E, 0x24, 0x43, 0xB4, 0x8D, 0x75, 0xF2, 0x81, 0x15, 0x52, 0xA7, 0x5A, 0x76, 0xCE, 0x76, 0x86, 0x73, 0x11, 0x66, 0x23, 0xB7, 0x5F, 0x81, 0xCF, 0x13, 0xCA, 0xBD, 0x48, 0xCA, 0x81, 0x7F, 0x26, 0x4E, 0xE5, 0xD4, 0xDF, 0x73, 0x6C, 0xB0, 0x7C, 0x5A, 0x1B, 0xB1, 0x69, 0xE5, 0x89, 0xDB, 0xC4, 0xD6, 0x9E, 0xE3, 0x8E, 0x89, 0x9E, 0xAB, 0x9F, 0xFF, 0x6B, 0xB2, 0x09, 0xE0, 0x79, 0xA7, 0xC6, 0x2F, 0xC4, 0xA7, 0xDE, 0x8D, 0x6B, 0x8A, 0x8F, 0x7C, 0x9A, 0x58, 0x89, 0xB7, 0x66, 0x54, 0x4A, 0x02, 0x9B, 0x69, 0xE7, 0x3C, 0xC1, 0xF0, 0x8A, 0x53, 0xF6, 0xB1, 0x8A, 0xE0, 0x18, 0xEA, 0xA8, 0x97, 0x56, 0x02, 0xAD, 0x0F, 0x38, 0x7E, 0xDA, 0xF0, 0x0E, 0x06, 0x9A, 0x3B, 0x6D, 0x58, 0x79, 0x0A, 0x12, 0xCC, 0x1C, 0xE7, 0xC4, 0xBB, 0xC0, 0xD1, 0x66, 0x55, 0x4B, 0xE6, 0x6C, 0x83, 0x77, 0x8F, 0x6B, 0xFF, 0x8C, 0x59, 0x0A, 0xFF, 0x8E, 0x74, 0x9A, 0x38, 0x70, 0xAB, 0xE4, 0xF5, 0x5A, 0xD8, 0xF9, 0xA2, 0xD8, 0x6F, 0x7C, 0x80, 0x91, 0xD8, 0xFF, 0x64, 0xA7, 0x2C, 0x31, 0xD4, 0xFD, 0xE1, 0x22, 0x9F, 0x83, 0x00, 0xF7, 0x07, 0x78, 0x9F, 0x16, 0x0B, 0xE2, 0xBC, 0x4B, 0x8B, 0x57, 0x03, 0x3C, 0xFB, 0x88, 0xA7, 0x0C, 0x5B, 0xBB, 0x8A, 0xFB, 0xDC, 0x1B, 0x34, 0x01, 0xA3, 0x7D, 0xAB, 0x23, 0x2B, 0xE5, 0x40, 0xB5, 0xFD, 0xE3, 0xFF, 0x42, 0xD9, 0x21, 0x5E, 0xBB, 0x23, 0x66, 0x83, 0xE7, 0x5F, 0x8F, 0xDE, 0x03, 0x67, 0xC0, 0xF4, 0xE8, 0x96, 0x63, 0x7B, 0xB9, 0xC2, 0xBE, 0xD5, 0x6D, 0xFE, 0x75, 0xF9, 0x0C, 0x8F, 0x1D, 0xFD, 0xBC, 0x5A, 0xFF, 0x82, 0x3F, 0x0F, 0x87, 0x9E, 0xAC, 0xD1, 0x48, 0xF2, 0x62, 0x6A, 0x81, 0x18, 0x67, 0xA6, 0x8C, 0x3D, 0xA1, 0x9C, 0xF6, 0xA8, 0xD0, 0x3A, 0x38, 0x14, 0xE0, 0x7A, 0x93, 0x9E, 0x7E, 0xE2, 0xB9, 0xB0, 0xEE, 0x1D, 0xC5, 0xC3, 0xD9, 0x41, 0x46, 0xE2, 0x2E, 0x0B, 0xFF, 0x5A, 0xE2, 0x72, 0x4F, 0xBF, 0x1E, 0x62, 0x4C, 0x6D, 0xDF, 0x16, 0x60, 0x71, 0xA1, 0x57, 0x64, 0xF3, 0x46, 0x32, 0xCF, 0x04, 0x80, 0x51, 0xDB, 0x40, 0x2F, 0x2F, 0xB8, 0x62, 0xB8, 0x11, 0x58, 0xB7, 0xDE, 0xD4, 0xB0, 0xFF, 0x1C, 0xB0, 0x5B, 0x79, 0xE3, 0x4A, 0x5F, 0x3D, 0xA8, 0x39, 0xEA, 0xB7, 0xE5, 0xD0, 0xD2, 0xE0, 0xA8, 0xF5, 0x7A, 0xC7, 0x6E, 0x82, 0xCA, 0x49, 0x5A, 0xC7, 0xBB, 0x9F, 0x66, 0x8C, 0xA6, 0xAD, 0xAA, 0x83, 0x26, 0xA4, 0x5E, 0x7D, 0x1D, 0x61, 0x0A, 0x70, 0x3E, 0x27, 0x72, 0x98, 0x78, 0x24, 0x22, 0x7C, 0x91, 0xB8, 0x63, 0x48, 0x68, 0x77, 0x71, 0xD1, 0xA5, 0xDE, 0xCD, 0xC5, 0xF1, 0x4B, 0x7A, 0xDB, 0x8A, 0x43, 0xB6, 0x87, 0x26, 0x82, 0x41, 0xE9, 0x8E, 0x19, 0x03, 0x4E, 0x43, 0xCD, 0x59, 0xE0, 0xDF, 0xDC, 0x22, 0xC2, 0x7F, 0x0F, 0x84, 0x04, 0x0C, 0x38, 0x26, 0x33, 0xE9, 0x3E, 0x97, 0xB7, 0x7C, 0x6E, 0x76, 0x0B, 0x42, 0x66, 0xDD, 0x29, 0x6A, 0xD1, 0x0B, 0xBA, 0x0F, 0xFF, 0xF9, 0xC6, 0x67, 0x2E, 0x04, 0xE5, 0x6A, 0x75, 0xC6, 0x47, 0x08, 0xB6, 0xD3, 0xEA, 0xD3, 0x5A, 0x10, 0x34, 0x56, 0xF3, 0x19, 0x74, 0xF6, 0xD6, 0x9E, 0x97, 0x31, 0x17, 0xDE, 0x4D, 0x4E, 0x02, 0x38, 0x31, 0x7D, 0x7A, 0xAE, 0x98, 0xD1, 0x32, 0xBA, 0x95, 0x98, 0xE8, 0x36, 0x22, 0x55, 0x9C, 0x58, 0x71, 0xC8, 0x57, 0x71, 0x70, 0xFD, 0xB0, 0xB5, 0x62, 0x77, 0x9F, 0x09, 0x51, 0xA2, 0x47, 0xC2, 0x9C, 0x23, 0x60, 0x9A, 0x07, 0x33, 0x12, 0xCB, 0x44, 0x36, 0xD8, 0x02, 0x8B, 0xC2, 0x42, 0x0A, 0x1C, 0x6B, 0xC2, 0x92, 0x72, 0x29, 0x2B, 0x1D, 0xCE, 0xC0, 0x82, 0xFC, 0x5B, 0xC9, 0xD5, 0xB6, 0xC3, 0x8C, 0x86, 0x25, 0xBD, 0x9C, 0x66, 0xC1, 0x04, 0x6D, 0x8D, 0xAE, 0xDF, 0x00, 0x86, 0x6A, 0x3D, 0xE9, 0x96, 0x93, 0x60, 0x48, 0x94, 0xD6, 0x8F, 0x49, 0x01, 0xF9, 0xDB, 0xA6, 0x6D, 0xA6, 0x9E, 0x7E, 0xBC, 0xA0, 0x34, 0xC0, 0xC1, 0x35, 0x0B, 0xEB, 0x8A, 0x1B, 0xE3, 0x67, 0x06, 0x89, 0xB1, 0x36, 0xD1, 0x1D, 0xC5, 0xE1, 0x1D, 0xC6, 0xFE, 0x14, 0x7B, 0xF6, 0x8F, 0xA9, 0x2A, 0x7A, 0xDD, 0x88, 0xFF, 0x29, 0xBA, 0x55, 0x4A, 0x19, 0x2A, 0xCA, 0x23, 0x67, 0xD3, 0xC2, 0x3A, 0x0F, 0xF6, 0x58, 0x75, 0x3B, 0x6D, 0x9A, 0xAE, 0x79, 0x6B, 0x55, 0x5D, 0xFD, 0x4F, 0x90, 0x3A, 0xE9, 0xAA, 0xAB, 0xFE, 0x4B, 0xD8, 0x3C, 0xF9, 0x7B, 0x59, 0xE3, 0x17, 0xB0, 0xE2, 0x97, 0x9C, 0xBF, 0xC0, 0x8C, 0x2A, 0x5A, 0x1F, 0xE6, 0x15, 0x4C, 0x7B, 0xAD, 0xCD, 0xF5, 0xB7, 0x6B, 0x6A, 0x73, 0x21, 0x7B, 0x9B, 0xA3, 0xBB, 0x56, 0x5C, 0x07, 0x48, 0xEF, 0x91, 0xD8, 0x53, 0x4C, 0x78, 0x3D, 0x7F, 0x16, 0x10, 0x36, 0x51, 0x2F, 0x6E, 0x22, 0xC0, 0xA0, 0xD9, 0xF3, 0x13, 0x44, 0xFF, 0xAA, 0xEB, 0x3A, 0x88, 0xF5, 0xBA, 0xA4, 0x2D, 0x16, 0x4B, 0xFD, 0x38, 0xE0, 0x26, 0xC2, 0xB1, 0x0F, 0x36, 0x7F, 0xC4, 0x33, 0x43, 0x7A, 0x38, 0x88, 0xE7, 0x3B, 0xAC, 0x68, 0x28, 0x9E, 0xCA, 0x3C, 0x59, 0x57, 0x3C, 0xD2, 0xF6, 0xD3, 0x72, 0x31, 0x5D, 0x3A, 0x18, 0xC0, 0xBA, 0x3B, 0xCA, 0xB5, 0x06, 0xCA, 0xD5, 0x7D, 0xB4, 0x9D, 0x73, 0xD1, 0xFE, 0x84, 0x4D, 0x66, 0x00, 0x9B, 0xA6, 0xAF, 0x29, 0x02, 0x1D, 0xBF, 0xD9, 0x11, 0x89, 0xA5, 0x81, 0xD2, 0xA3, 0xE6, 0xAC, 0xF6, 0x01, 0xE8, 0x9D, 0x95, 0xDA, 0x43, 0xF4, 0x5C, 0x7C, 0xE8, 0x97, 0xE8, 0xF8, 0xDF, 0xD5, 0x6F, 0x22, 0xDC, 0xFA, 0xA3, 0xBC, 0x5F, 0xD9, 0xE1, 0x88, 0xF8, 0xAA, 0x45, 0xC8, 0x7D, 0xF1, 0xCD, 0xC3, 0x95, 0x0B, 0xC4, 0xD7, 0x8E, 0xA7, 0x87, 0x8A, 0xCF, 0x7C, 0x3E, 0xFD, 0x11, 0x6F, 0x2C, 0x55, 0xB9, 0x47, 0x47, 0x29, 0xF3, 0xF2, 0x94, 0x7B, 0xF3, 0xC5, 0xCC, 0xA2, 0x54, 0xF9, 0x88, 0xC4, 0x06, 0x9B, 0xCB, 0x80, 0xCE, 0x89, 0xC9, 0x51, 0x5B, 0x36, 0x00, 0x0C, 0xBD, 0x94, 0x55, 0x28, 0x76, 0xB6, 0x3B, 0x33, 0x49, 0x6C, 0x54, 0x7C, 0xBF, 0x91, 0x68, 0x1F, 0xF0, 0xA3, 0x8B, 0x88, 0xAC, 0x92, 0x2D, 0x0C, 0x42, 0xC4, 0x86, 0xAD, 0x40, 0x1C, 0xE0, 0xAC, 0x5C, 0x64, 0xAA, 0xDC, 0x35, 0x4A, 0xF9, 0xC2, 0x0C, 0xB1, 0xBF, 0xCA, 0xFD, 0x30, 0x49, 0xF9, 0x6E, 0xA2, 0xF2, 0xB9, 0xA5, 0x98, 0x62, 0x91, 0xD6, 0x07, 0x74, 0x3C, 0xE6, 0x07, 0xED, 0x36, 0x00, 0x18, 0xB3, 0x34, 0xAF, 0xB5, 0xD8, 0x27, 0xE1, 0xB2, 0x85, 0xD8, 0xCE, 0xF1, 0x5D, 0x7B, 0xB1, 0x8E, 0xC5, 0xAF, 0xB9, 0xA2, 0x99, 0xF3, 0x1F, 0x07, 0x30, 0x19, 0x86, 0x74, 0x2C, 0x0C, 0x40, 0x6C, 0x30, 0x55, 0xD9, 0x6B, 0xBD, 0x72, 0x54, 0x65, 0xE5, 0xBA, 0x50, 0x65, 0xF6, 0x3C, 0xE5, 0x2B, 0x4B, 0xF1, 0x8F, 0xAA, 0x0F, 0xF9, 0x79, 0x54, 0xF9, 0x3D, 0x5F, 0x4C, 0x2A, 0x93, 0xFD, 0x17, 0x78, 0x35, 0xAD, 0xE2, 0xC1, 0x52, 0x00, 0xE1, 0xF6, 0x57, 0x6F, 0x89, 0x81, 0x87, 0x9E, 0xE7, 0x8B, 0x8D, 0xA7, 0x7D, 0x4A, 0x12, 0xAB, 0x14, 0x7E, 0x7B, 0x2A, 0x42, 0x89, 0xA7, 0x5E, 0xA8, 0xD1, 0x73, 0xF8, 0xD3, 0xB2, 0x6A, 0x69, 0xF5, 0xFB, 0x1B, 0x5D, 0x57, 0x06, 0xDD, 0x53, 0x0E, 0xEE, 0xA4, 0x5C, 0x50, 0xA0, 0xDC, 0xF0, 0x4F, 0xB9, 0x7F, 0xBA, 0xF2, 0xD9, 0x3D, 0xE5, 0xFB, 0xD2, 0xCA, 0xAF, 0xFA, 0x50, 0x1C, 0xC6, 0x17, 0xD0, 0x2C, 0x06, 0xCB, 0x68, 0xF8, 0x7E, 0x0A, 0x1C, 0x1A, 0xC0, 0xB7, 0x68, 0x70, 0xB3, 0x85, 0x2F, 0x3B, 0xA0, 0xA5, 0x05, 0x7C, 0x76, 0x83, 0x4E, 0x7B, 0xE1, 0xE3, 0x36, 0xE8, 0x0B, 0x7C, 0xAA, 0x03, 0x63, 0x7F, 0xC3, 0xEB, 0x1B, 0xB0, 0xB0, 0x33, 0x3C, 0x3D, 0x0C, 0x9B, 0x7F, 0xE9, 0xD6, 0x2F, 0x8A, 0x85, 0xBD, 0x31, 0x70, 0xAD, 0x09, 0x9C, 0xD7, 0x87, 0x53, 0x35, 0xE0, 0x41, 0x65, 0xC8, 0x0D, 0x87, 0xB7, 0xF2, 0x2E, 0xB2, 0x82, 0xBF, 0x95, 0x61, 0xEB, 0x5F, 0xB5, 0xCF, 0x6E, 0xA9, 0xAF, 0xFC, 0x16, 0x01, 0x00, 0xC5, 0x85, 0x60, 0x78, 0x18, 0xBE, 0x7B, 0x40, 0x85, 0x8F, 0x50, 0xB2, 0x06, 0x6A, 0x2F, 0x81, 0xAF, 0x59, 0xE0, 0x7E, 0x05, 0xBE, 0x2C, 0x81, 0x0E, 0x09, 0xF0, 0xE9, 0x01, 0xF4, 0xFA, 0x07, 0x5F, 0x66, 0xC1, 0x98, 0x73, 0xF0, 0x66, 0x1C, 0x2C, 0x2A, 0x0F, 0x4F, 0xCB, 0xC2, 0xD6, 0xDF, 0xBA, 0x1D, 0x0A, 0x7F, 0x41, 0xDE, 0x5C, 0xB8, 0x74, 0x07, 0xAE, 0xA6, 0x40, 0x7E, 0x04, 0x3C, 0xCB, 0x84, 0xF4, 0x2F, 0x50, 0x32, 0x18, 0x36, 0x75, 0x54, 0xB9, 0xC9, 0xE1, 0xCA, 0x55, 0x03, 0x95, 0xDF, 0x6F, 0xA2, 0x8E, 0xC3, 0x41, 0xF9, 0xAD, 0x29, 0x58, 0xAC, 0x83, 0x1F, 0x9D, 0xA0, 0xDA, 0x0D, 0xF8, 0x7E, 0x1D, 0xEA, 0x2D, 0x80, 0xAF, 0xD9, 0xE0, 0xD5, 0x48, 0x33, 0x13, 0xBA, 0x9F, 0x87, 0x6F, 0xDF, 0x61, 0x74, 0x2E, 0xBC, 0x32, 0x80, 0x85, 0x85, 0x70, 0x7F, 0x1E, 0x6C, 0xBD, 0xCF, 0xBE, 0x9B, 0x76, 0x70, 0xF0, 0x2F, 0x9C, 0x6B, 0x08, 0x77, 0xDF, 0xC1, 0xBE, 0xCF, 0xF0, 0xBE, 0x0D, 0x6C, 0x57, 0x75, 0x07, 0xCB, 0x1B, 0x2A, 0x97, 0x74, 0x57, 0x2E, 0x7C, 0xA6, 0xFC, 0x31, 0x1C, 0x00, 0xBE, 0xAF, 0x54, 0x16, 0x5B, 0x2B, 0x7F, 0x0C, 0x06, 0xEB, 0x61, 0xF0, 0xFD, 0x0F, 0xD4, 0x6E, 0x00, 0x1F, 0xD7, 0x42, 0xF3, 0xA5, 0xF0, 0xCA, 0x02, 0x02, 0x47, 0xC1, 0xBD, 0x76, 0x30, 0xE8, 0x1E, 0xDC, 0xE8, 0x0E, 0x53, 0xA3, 0xE0, 0xDC, 0x12, 0x58, 0x65, 0x04, 0x47, 0x2B, 0xC1, 0xBE, 0x4A, 0x70, 0xB0, 0x03, 0xDC, 0xFD, 0x06, 0x7B, 0x3C, 0xE0, 0xDB, 0x36, 0x58, 0xDD, 0x49, 0xE5, 0x2D, 0x28, 0x50, 0xC6, 0x6F, 0x43, 0x69, 0xA0, 0xFC, 0xAA, 0x6F, 0xF2, 0x08, 0x34, 0xCD, 0xF5, 0xAC, 0xC4, 0xF7, 0xBB, 0x4D, 0x5D, 0xC4, 0xE7, 0xB3, 0x41, 0xFF, 0x3F, 0xE3, 0x49, 0xCF, 0xCB, 0x41, 0x45, 0x0C, 0x77, 0x3D, 0x6A, 0x04, 0xF5, 0x5C, 0xF5, 0xCE, 0xDE, 0x49, 0x05, 0x6F, 0x7F, 0xB8, 0x58, 0x02, 0x3D, 0x9F, 0xC2, 0x91, 0x87, 0x30, 0xB2, 0x39, 0x64, 0xDF, 0x86, 0xF9, 0xFB, 0x21, 0x6D, 0x13, 0xA4, 0x07, 0xC1, 0xEE, 0xFB, 0x50, 0xB4, 0x00, 0xB6, 0xDA, 0xC0, 0x8F, 0x03, 0x2C, 0x4B, 0x5A, 0x26, 0x79, 0x46, 0xFF, 0xE2, 0x26, 0x88, 0xD6, 0x81, 0xD3, 0x5D, 0xC5, 0x4A, 0x4B, 0xA6, 0xCF, 0x11, 0xAB, 0x0C, 0x78, 0x33, 0xB2, 0xB2, 0xAA, 0x7B, 0xEE, 0x56, 0x88, 0x14, 0x9F, 0x5E, 0xAE, 0xE0, 0x29, 0x16, 0xDD, 0xB0, 0x95, 0x8F, 0x3B, 0x5E, 0xAF, 0x00, 0x46, 0x7F, 0x4B, 0xC7, 0x5E, 0x29, 0x05, 0x95, 0x5F, 0x9B, 0x19, 0x9F, 0x36, 0x81, 0x46, 0x8B, 0x0D, 0xDE, 0xE7, 0xBE, 0x82, 0x4E, 0x76, 0x90, 0xBA, 0x11, 0x06, 0x3D, 0x85, 0x4D, 0xFB, 0x60, 0x56, 0x4B, 0x58, 0xBF, 0x14, 0xD2, 0xFC, 0x61, 0x75, 0x57, 0x28, 0x2A, 0xAF, 0x7B, 0x20, 0xFE, 0x0F, 0x94, 0x38, 0x96, 0xBF, 0x3D, 0xE3, 0x9F, 0xE4, 0x39, 0x5D, 0x1C, 0x9D, 0x2D, 0x36, 0x5E, 0x32, 0xB2, 0xA3, 0xD8, 0x6C, 0x6D, 0xF8, 0x4F, 0xB1, 0xC5, 0xC9, 0x87, 0xFF, 0x9C, 0xFB, 0x02, 0x3C, 0x8C, 0xA8, 0x65, 0x28, 0x16, 0x86, 0x39, 0x55, 0x14, 0xAF, 0x45, 0xD7, 0xE8, 0x20, 0x9E, 0xDA, 0x65, 0x67, 0x0F, 0xFA, 0x76, 0x79, 0xC1, 0xA0, 0x37, 0xA9, 0xEC, 0xCE, 0x74, 0x67, 0x99, 0x4E, 0x99, 0x8C, 0x5C, 0xD3, 0x07, 0x9A, 0xF4, 0x35, 0xA9, 0x30, 0xBF, 0x09, 0x04, 0x4D, 0xB7, 0x58, 0x35, 0xE3, 0x20, 0xC4, 0xCC, 0xB1, 0x36, 0x9D, 0xBE, 0x11, 0x76, 0x75, 0x2F, 0x7D, 0x2E, 0x66, 0x36, 0x14, 0x5E, 0xB0, 0x5A, 0x3B, 0x76, 0x35, 0x94, 0xF8, 0x34, 0x3C, 0xDD, 0xEF, 0xB6, 0xE4, 0x75, 0x72, 0xF1, 0x35, 0x16, 0x83, 0x8D, 0xDA, 0x8D, 0x17, 0xBB, 0x19, 0x78, 0x0E, 0x11, 0xBB, 0xE7, 0xDF, 0xF9, 0xD3, 0xF2, 0x14, 0xC0, 0xCD, 0xFF, 0x5A, 0xBA, 0x88, 0x17, 0x4D, 0x9B, 0xE6, 0x89, 0x47, 0xCB, 0xD4, 0x7F, 0x2D, 0xE6, 0x54, 0x71, 0xF5, 0x17, 0x53, 0x9E, 0x57, 0x1F, 0x28, 0xC6, 0x3E, 0x2B, 0xD3, 0x1C, 0x4A, 0xBF, 0x0A, 0x7B, 0x0A, 0xA5, 0x67, 0xB9, 0xF8, 0xF6, 0x09, 0x80, 0xA6, 0xDB, 0xDC, 0xCC, 0xBA, 0xDF, 0x81, 0x88, 0xBD, 0x6E, 0xB7, 0x3A, 0xF7, 0x83, 0x8D, 0x0D, 0xEB, 0x76, 0xF1, 0x6B, 0x06, 0x97, 0x73, 0x1A, 0x1C, 0x6F, 0x73, 0x18, 0xBE, 0x05, 0x79, 0xB7, 0xA8, 0x3A, 0x4E, 0xF2, 0x86, 0xD6, 0x04, 0x71, 0xDC, 0x6B, 0x94, 0x65, 0x94, 0xA3, 0x1E, 0x5F, 0x7D, 0xD7, 0x61, 0x21, 0xC0, 0xA5, 0xC1, 0x1D, 0x4E, 0x88, 0x47, 0xAB, 0x77, 0x58, 0x22, 0xA6, 0x37, 0xF0, 0x30, 0x10, 0x57, 0x6D, 0x68, 0x6E, 0x2B, 0x4E, 0x1B, 0xD5, 0x7C, 0xBE, 0x18, 0xD6, 0xBE, 0xD9, 0x56, 0xD0, 0xF7, 0x0B, 0xAC, 0x58, 0xBF, 0x21, 0x54, 0x5B, 0x09, 0x00, 0xBD, 0xEB, 0x82, 0x51, 0xB3, 0xF6, 0xFA, 0x41, 0x5D, 0xC1, 0x2A, 0x63, 0x71, 0x61, 0xC7, 0x42, 0xB0, 0x76, 0x38, 0x5C, 0xAD, 0xFD, 0x51, 0xA8, 0xFC, 0xE6, 0x7D, 0x19, 0xDF, 0x52, 0x50, 0xD3, 0x5E, 0xBB, 0xDF, 0xB7, 0x75, 0x87, 0xD6, 0xD4, 0x7A, 0x91, 0x03, 0x03, 0xA1, 0x72, 0xB1, 0x76, 0x5C, 0xBD, 0x54, 0x1D, 0x34, 0x28, 0xE6, 0xCC, 0xB5, 0xDE, 0xBF, 0x00, 0x8E, 0x57, 0xE9, 0xE7, 0x26, 0x66, 0x55, 0xEB, 0x99, 0x27, 0xAE, 0x1E, 0x1C, 0x78, 0x45, 0x9C, 0x1A, 0xE9, 0x17, 0x20, 0x0E, 0xEC, 0xD5, 0xAE, 0xB7, 0x18, 0xF4, 0xBD, 0xE3, 0x7C, 0x60, 0xAC, 0x47, 0x4C, 0x97, 0x78, 0xB0, 0xBE, 0x03, 0x9E, 0x91, 0xC6, 0x16, 0x2D, 0x8F, 0x43, 0xE0, 0x98, 0x20, 0xFD, 0xBA, 0x15, 0x34, 0x33, 0x16, 0x9F, 0xAA, 0xD5, 0x0A, 0xBA, 0xDA, 0x1C, 0x3B, 0x53, 0xCB, 0x1C, 0x3A, 0xDF, 0xFD, 0xE8, 0xE9, 0x3A, 0x08, 0xFC, 0x1D, 0xB4, 0x39, 0x50, 0xAC, 0xE6, 0x6D, 0xAD, 0x13, 0xBF, 0x0B, 0x3A, 0x6A, 0x7D, 0xA0, 0x8E, 0x1D, 0xC1, 0x57, 0xEB, 0xC9, 0xFA, 0x3E, 0x3D, 0xF6, 0x31, 0xD2, 0x01, 0xE0, 0xD0, 0xD2, 0xD1, 0x87, 0xC5, 0x2D, 0xB9, 0x83, 0x17, 0x8B, 0x73, 0x5E, 0x85, 0xE8, 0x89, 0x11, 0xE3, 0x82, 0xCF, 0x88, 0xDD, 0x1E, 0x76, 0xBD, 0xA2, 0xF6, 0x9B, 0x3E, 0x5F, 0x45, 0xF7, 0xE4, 0x31, 0xCD, 0x45, 0x18, 0x15, 0x60, 0xB6, 0xD7, 0xFE, 0x14, 0xC4, 0x0C, 0xF4, 0x5D, 0x60, 0x55, 0x05, 0x26, 0x15, 0xCC, 0xCB, 0x2D, 0xF5, 0x05, 0x62, 0xAE, 0x1F, 0x7E, 0x60, 0xDE, 0x04, 0x26, 0x36, 0x7E, 0x93, 0x57, 0x6A, 0x30, 0x8C, 0xAE, 0xA8, 0xED, 0x48, 0xB7, 0x60, 0xA8, 0x76, 0x3D, 0x6E, 0xF5, 0x86, 0x10, 0x12, 0xAB, 0xF5, 0x63, 0xAA, 0x69, 0xDE, 0xD4, 0x3C, 0x75, 0x38, 0x61, 0x6A, 0x1F, 0x80, 0xCC, 0x73, 0x53, 0x3F, 0x8A, 0x89, 0x0F, 0xA3, 0x4A, 0xC4, 0xE8, 0xB7, 0x43, 0xB7, 0x88, 0xFD, 0xCA, 0x87, 0x0E, 0x04, 0xDD, 0x14, 0xFF, 0x84, 0x21, 0xAF, 0x01, 0x1A, 0x8E, 0x8C, 0xBE, 0x2F, 0x96, 0x7B, 0xBD, 0xA0, 0xB2, 0x08, 0xCB, 0x5F, 0x56, 0x58, 0xAB, 0x33, 0x18, 0xD6, 0x04, 0x74, 0xAC, 0x0C, 0x90, 0x14, 0x3C, 0xED, 0xA3, 0xB8, 0x32, 0x3F, 0xA7, 0xB5, 0xB8, 0xFC, 0xEE, 0x7F, 0x5F, 0xC4, 0x78, 0xED, 0xF1, 0x10, 0x67, 0x18, 0x6B, 0xE7, 0x84, 0xBF, 0x60, 0xE2, 0x5E, 0xED, 0x9C, 0x36, 0x05, 0xA2, 0x4D, 0xB5, 0xF9, 0xFA, 0xC9, 0x7D, 0x13, 0xE7, 0x35, 0x01, 0x48, 0xA9, 0x36, 0xC7, 0x42, 0x9C, 0x73, 0x75, 0x72, 0x39, 0x71, 0xC4, 0x9E, 0x71, 0xED, 0xC5, 0x9E, 0xCE, 0xD1, 0xF6, 0xA2, 0x47, 0xFE, 0xDC, 0x64, 0xB1, 0xDA, 0xC0, 0xB5, 0xA6, 0x22, 0x6C, 0xEB, 0xA3, 0xDC, 0xB5, 0xAF, 0xFA, 0x74, 0x31, 0xF3, 0x72, 0xD7, 0x77, 0xE2, 0x5E, 0xC3, 0x98, 0xD5, 0x62, 0xCE, 0x96, 0x9C, 0x18, 0x31, 0xAB, 0xE6, 0x9D, 0x48, 0x71, 0xA7, 0xDA, 0x67, 0x59, 0x39, 0x48, 0xB9, 0x64, 0x91, 0x72, 0xB1, 0xA7, 0x98, 0xD6, 0x68, 0xF9, 0x30, 0x80, 0xA4, 0x71, 0x4B, 0x32, 0xC4, 0x98, 0xCB, 0x73, 0x36, 0x89, 0x83, 0x7D, 0x17, 0x44, 0x8B, 0x01, 0x56, 0x6B, 0xDF, 0x8B, 0x0D, 0x6E, 0xA5, 0x37, 0x15, 0xCB, 0x7E, 0xCC, 0xD7, 0x15, 0xE1, 0xF4, 0x52, 0xBD, 0xEB, 0xE2, 0xE5, 0x4F, 0xF5, 0x2C, 0xC5, 0x5B, 0xFE, 0x21, 0x77, 0xC4, 0x3B, 0x47, 0x16, 0x2E, 0x14, 0x0B, 0xEF, 0x1D, 0x2A, 0x10, 0x0B, 0x36, 0xBE, 0x36, 0x17, 0x2F, 0x57, 0x50, 0xB9, 0x07, 0x02, 0x94, 0x7B, 0x5E, 0x2B, 0x77, 0x35, 0x11, 0xB7, 0x7E, 0x5E, 0x7F, 0x01, 0x60, 0xFE, 0xDE, 0x95, 0x57, 0xC5, 0xA8, 0x17, 0xAB, 0xE7, 0x8B, 0x21, 0x65, 0x76, 0xFA, 0x88, 0x5E, 0xBF, 0x0E, 0xD5, 0x11, 0x6B, 0x0F, 0xBF, 0xB6, 0x53, 0xB4, 0xA8, 0xF8, 0xB8, 0xBB, 0x08, 0xDF, 0x7F, 0x57, 0x28, 0x40, 0xCD, 0x7F, 0x96, 0x29, 0x43, 0xDF, 0x2A, 0x97, 0xCF, 0x50, 0xA6, 0x55, 0x52, 0xBE, 0x6F, 0x8F, 0xA8, 0xEA, 0x40, 0x3E, 0xDF, 0x55, 0xDE, 0x1B, 0xAE, 0xBC, 0xB5, 0x4F, 0x5C, 0xBD, 0x31, 0xA5, 0x04, 0x60, 0x6A, 0xD9, 0xCD, 0x55, 0xC5, 0x61, 0xB9, 0x19, 0x67, 0xC5, 0x2E, 0xF5, 0x4E, 0x7D, 0x16, 0x9B, 0x47, 0x3F, 0x3C, 0x2A, 0x56, 0xCB, 0x78, 0xFB, 0x51, 0x84, 0xB7, 0xDE, 0x74, 0x35, 0xD6, 0x83, 0xAF, 0x73, 0x1C, 0x4E, 0x02, 0x94, 0x8C, 0xF6, 0x7E, 0x2E, 0xFE, 0x7E, 0xDF, 0xD7, 0x5A, 0xFC, 0xE3, 0x14, 0xA5, 0xF2, 0x27, 0x6C, 0x08, 0x46, 0xF5, 0x5F, 0x3E, 0x28, 0xD5, 0xF1, 0xFC, 0x0A, 0x57, 0xF9, 0x5F, 0xEF, 0x28, 0xBF, 0xD4, 0x11, 0x17, 0x9D, 0xDB, 0xDD, 0x1A, 0x60, 0xDC, 0x94, 0xBD, 0x71, 0x62, 0xBF, 0xD1, 0xE7, 0x7B, 0x89, 0x3E, 0xA5, 0x8B, 0x0A, 0x45, 0xE7, 0x6E, 0x4F, 0xE7, 0x8A, 0x16, 0xC7, 0x5F, 0xB4, 0x03, 0xFD, 0x66, 0xF0, 0x3A, 0xBD, 0x74, 0x4B, 0x80, 0x4F, 0x27, 0x9C, 0xBC, 0xC5, 0xAF, 0xCF, 0xBD, 0xCF, 0x88, 0x25, 0xE7, 0x7B, 0x5E, 0x10, 0x7F, 0xD5, 0x1E, 0x76, 0x08, 0xB1, 0x72, 0xFC, 0x33, 0xF1, 0x8F, 0xDD, 0xA6, 0x6C, 0xC4, 0xA4, 0xE3, 0x4F, 0xC4, 0xBF, 0x11, 0x6F, 0x2C, 0xC4, 0xDF, 0x93, 0x7F, 0x4F, 0x46, 0x5C, 0xFF, 0xE7, 0x25, 0x3C, 0xF9, 0x03, 0x00, 0x8F, 0x57, 0x81, 0xE9, 0x6D, 0xCD, 0x95, 0x60, 0xB7, 0x1B, 0x1E, 0x74, 0x03, 0xA7, 0x7E, 0x50, 0x14, 0x08, 0x8D, 0x96, 0xC3, 0x9D, 0xDF, 0xE0, 0x59, 0x0C, 0x37, 0xD7, 0x40, 0xE7, 0x6B, 0x70, 0x3D, 0x1F, 0x06, 0xBA, 0xC3, 0x95, 0xD1, 0x10, 0x1D, 0x0F, 0x17, 0x27, 0x43, 0x7C, 0x3A, 0x9C, 0xDE, 0x0D, 0x5B, 0x0B, 0xE0, 0xE8, 0x24, 0x38, 0x9C, 0x06, 0xB9, 0xC5, 0x70, 0xFD, 0x3C, 0xEC, 0x5E, 0x05, 0x4F, 0xE6, 0xC3, 0xC6, 0x74, 0xF8, 0xBC, 0x18, 0x92, 0xA2, 0xE1, 0xF7, 0x54, 0x58, 0x11, 0x01, 0x7F, 0xE3, 0xE1, 0xBF, 0x4C, 0x00, 0x78, 0x34, 0x4D, 0xA6, 0xA2, 0xF0, 0x58, 0x0F, 0xCA, 0x0C, 0x80, 0x07, 0xCB, 0xC1, 0x61, 0x07, 0xDC, 0xEB, 0x0B, 0x75, 0x0F, 0x43, 0xC1, 0x59, 0x68, 0x5D, 0x1D, 0x6E, 0x75, 0x81, 0x80, 0x5A, 0x70, 0x3D, 0x03, 0xFA, 0xD9, 0xC1, 0x95, 0x5D, 0x10, 0xBD, 0x00, 0x2E, 0x4E, 0x85, 0x65, 0xEB, 0xE1, 0x94, 0x0F, 0xEC, 0xAA, 0x0C, 0x47, 0x82, 0xE0, 0x54, 0x2F, 0xC8, 0xBE, 0x0C, 0xF7, 0x02, 0x60, 0x6B, 0x4B, 0x78, 0x7B, 0x1B, 0x92, 0x4A, 0xE0, 0xF7, 0x77, 0x58, 0x52, 0x0B, 0x55, 0x7F, 0x6C, 0x51, 0xBE, 0xDC, 0x04, 0x00, 0x4F, 0x63, 0x95, 0x8F, 0xBA, 0x82, 0x91, 0x31, 0x3C, 0x8E, 0x07, 0xBB, 0x32, 0x70, 0xFF, 0x10, 0xD4, 0x2A, 0x82, 0xBB, 0xA9, 0xD0, 0x6C, 0x1A, 0xDC, 0x89, 0x02, 0xBF, 0x1D, 0x70, 0xAB, 0x19, 0xF4, 0xED, 0x0A, 0x57, 0x1B, 0xC1, 0xC4, 0x4A, 0x70, 0xD6, 0x1D, 0x96, 0x35, 0x86, 0xA3, 0x1F, 0x20, 0xFD, 0x14, 0x1C, 0x78, 0x09, 0x57, 0x6D, 0x61, 0xD7, 0x2C, 0x78, 0x56, 0x17, 0x92, 0x5B, 0xC3, 0xF7, 0xA6, 0xB0, 0xF0, 0x9B, 0xCA, 0x9D, 0x5E, 0x55, 0x39, 0x73, 0xAB, 0xF2, 0xED, 0x32, 0x00, 0x78, 0x19, 0xAC, 0x7C, 0xB2, 0x0E, 0x65, 0x16, 0x98, 0x8D, 0x83, 0x47, 0x4D, 0xC0, 0xDE, 0x16, 0x0A, 0x06, 0x42, 0xFD, 0xB1, 0x20, 0x55, 0xBC, 0x57, 0x17, 0x38, 0x31, 0x01, 0x82, 0xEB, 0x42, 0xEE, 0x3E, 0x08, 0x33, 0x02, 0xE9, 0xBA, 0xCE, 0xB0, 0x84, 0xDD, 0x6E, 0xB0, 0x79, 0x20, 0xEC, 0xB8, 0x04, 0xA7, 0xD3, 0x61, 0xE3, 0x31, 0x78, 0xB9, 0x0E, 0x96, 0x0D, 0x55, 0x79, 0x33, 0xAC, 0x94, 0xB3, 0xE7, 0x2A, 0xE3, 0x02, 0x94, 0xAF, 0x1D, 0x00, 0xE0, 0xD5, 0x4D, 0xE5, 0x03, 0x3B, 0x65, 0xC1, 0x28, 0xD0, 0x5D, 0x0A, 0x37, 0x36, 0x82, 0x4D, 0x00, 0x5C, 0xFC, 0x06, 0xB5, 0x06, 0xC3, 0x91, 0xC6, 0xD0, 0xE4, 0x32, 0x64, 0x34, 0x03, 0xDF, 0xE9, 0xB0, 0xE9, 0x36, 0x84, 0x14, 0xC1, 0xAA, 0xF6, 0x30, 0x7A, 0x3D, 0x24, 0xC6, 0x41, 0xE2, 0x36, 0x48, 0x9C, 0x07, 0xF9, 0x17, 0x61, 0xE5, 0x1B, 0x78, 0xF5, 0x03, 0x16, 0xFD, 0x90, 0x3C, 0x03, 0xB3, 0xE9, 0x53, 0x44, 0xA3, 0xDD, 0xD1, 0x9E, 0xA2, 0xCD, 0x96, 0xF1, 0x09, 0x62, 0x85, 0xAA, 0x8F, 0xC2, 0xCD, 0x8F, 0x01, 0xDC, 0x3F, 0x6F, 0x38, 0x44, 0xBC, 0xFD, 0xCF, 0x64, 0xA5, 0x78, 0xF1, 0xB8, 0x49, 0x8A, 0x78, 0xCC, 0x14, 0x0C, 0xC2, 0x0D, 0x06, 0x1D, 0x5C, 0x0C, 0xE5, 0x5D, 0x74, 0xDB, 0xA5, 0x37, 0x00, 0x17, 0x6B, 0x48, 0xEE, 0x0A, 0xAD, 0x06, 0x80, 0xAC, 0xC6, 0xFE, 0x69, 0x30, 0xF3, 0x39, 0x84, 0x8D, 0x87, 0x69, 0x87, 0x20, 0x61, 0x15, 0xC4, 0xF9, 0x40, 0xFE, 0x6E, 0x88, 0x6D, 0x08, 0x2F, 0xC7, 0x98, 0xD5, 0x9C, 0x68, 0x2E, 0x79, 0xF6, 0xED, 0x22, 0xCB, 0x8B, 0x35, 0xD7, 0x0E, 0x9A, 0x26, 0xD6, 0xFD, 0xD5, 0xDF, 0x41, 0xAC, 0x7F, 0xBB, 0x70, 0x99, 0x3D, 0x00, 0x77, 0xD6, 0x57, 0x6D, 0x2C, 0x5E, 0x6A, 0x54, 0xC9, 0x49, 0x3C, 0xEA, 0x59, 0x2E, 0x4D, 0xCC, 0xB9, 0x57, 0xA6, 0xB1, 0xB8, 0xB5, 0x37, 0x80, 0xF1, 0x8F, 0x55, 0xBA, 0x60, 0x73, 0x13, 0xA6, 0xBB, 0x80, 0xCB, 0x2F, 0x99, 0xBF, 0x43, 0xDB, 0x8B, 0x06, 0x7D, 0x46, 0x9A, 0xC1, 0x80, 0xE3, 0x46, 0xB7, 0x46, 0xB8, 0xC2, 0x52, 0x7D, 0xC3, 0xDC, 0x88, 0x7F, 0x70, 0x38, 0xDF, 0xA0, 0xCB, 0x30, 0x47, 0x78, 0xF1, 0xD1, 0xC6, 0x2F, 0x64, 0x35, 0x52, 0x7F, 0x65, 0x7A, 0xFD, 0x14, 0xBD, 0x6E, 0xB7, 0x0D, 0x13, 0xDB, 0x86, 0xB7, 0x31, 0x11, 0x7D, 0x3C, 0xAE, 0xA7, 0xD4, 0xF9, 0x04, 0x70, 0xB1, 0x5C, 0x3D, 0x2B, 0x31, 0x7F, 0x9D, 0xF3, 0x37, 0x31, 0x7B, 0x71, 0x4D, 0x7B, 0x71, 0x4B, 0xB7, 0xCA, 0xE1, 0xE2, 0x62, 0x5B, 0xDB, 0x73, 0xE2, 0xB8, 0xC5, 0xA5, 0x6C, 0x40, 0xB7, 0x49, 0x9F, 0x5E, 0x60, 0x11, 0x5D, 0xDE, 0xAC, 0x73, 0x01, 0xD4, 0x1D, 0x58, 0x65, 0x89, 0x5F, 0x23, 0xE8, 0xE1, 0xEF, 0xF0, 0xC3, 0xBB, 0x08, 0xE6, 0x3E, 0xAD, 0xEE, 0xEC, 0xD5, 0x06, 0xF6, 0x9E, 0xB5, 0x2F, 0x68, 0xED, 0x09, 0x4F, 0x92, 0x6B, 0x24, 0xD8, 0x77, 0x95, 0xBC, 0xF6, 0x9F, 0x40, 0x1C, 0x30, 0x49, 0x19, 0x1A, 0xA8, 0xEC, 0x53, 0xF3, 0xEC, 0xAA, 0x36, 0x41, 0x00, 0x27, 0x1D, 0x3D, 0x7A, 0x88, 0x7B, 0xF7, 0x37, 0xFF, 0x20, 0x6E, 0x5E, 0x5D, 0xFF, 0x81, 0x38, 0x2F, 0xA5, 0xEE, 0x2F, 0x71, 0xD4, 0x48, 0xD7, 0xF7, 0x62, 0xAF, 0x03, 0x6E, 0x7A, 0xA2, 0xF7, 0xBF, 0x5A, 0x79, 0x60, 0xF9, 0x11, 0x00, 0x7C, 0x0A, 0xC0, 0xE8, 0xBF, 0xE6, 0x21, 0x1E, 0x67, 0xC0, 0xEA, 0xD3, 0x84, 0x8E, 0x2D, 0xEA, 0x40, 0xD9, 0xDF, 0xBB, 0x22, 0xDD, 0x0D, 0xC1, 0x76, 0x77, 0xA1, 0x5F, 0xC3, 0x11, 0x50, 0x5D, 0xEB, 0x37, 0xB8, 0xD7, 0xD7, 0xFD, 0x53, 0xCB, 0x4D, 0xEB, 0xCB, 0xFD, 0x02, 0x87, 0x40, 0x6D, 0x2E, 0x34, 0x11, 0xEC, 0xD1, 0x9C, 0x9B, 0xFF, 0x2F, 0x60, 0x16, 0xC0, 0x11, 0xFF, 0xAE, 0xBE, 0xE2, 0xF6, 0xEA, 0xBE, 0x77, 0xC4, 0x85, 0x8F, 0xBC, 0x4E, 0x88, 0x51, 0x27, 0x5B, 0x46, 0x8B, 0x3D, 0x7A, 0x37, 0x73, 0x15, 0x7D, 0xF2, 0x9A, 0x1E, 0x11, 0xDD, 0x07, 0x78, 0xC8, 0xFA, 0x3A, 0x03, 0x9A, 0x35, 0xD3, 0x5F, 0xE7, 0x5A, 0x0E, 0xBC, 0xAF, 0xF8, 0x8C, 0xAF, 0x9A, 0x08, 0x3E, 0xFA, 0x93, 0x86, 0x94, 0xB7, 0x87, 0xF6, 0xF1, 0x69, 0x75, 0xCA, 0xCD, 0x85, 0x0E, 0x63, 0xEE, 0xDD, 0xB3, 0x19, 0x01, 0xED, 0xD3, 0xB4, 0xEB, 0xE6, 0x0A, 0xA0, 0xAD, 0xCC, 0x83, 0x62, 0xA1, 0xB5, 0x56, 0x97, 0x35, 0xB8, 0x05, 0xAD, 0xBA, 0x69, 0x96, 0x3B, 0x70, 0xBA, 0xBF, 0x19, 0x40, 0x76, 0xC0, 0xC0, 0x2D, 0x62, 0xD2, 0xC9, 0x1E, 0xBF, 0xC4, 0xC9, 0x2B, 0x02, 0xBA, 0x8A, 0xFD, 0xFE, 0x6B, 0x3F, 0x49, 0xF4, 0x0B, 0xF1, 0xB2, 0x12, 0x9B, 0x1E, 0xF2, 0x0D, 0x15, 0xAB, 0xC7, 0xF5, 0x3E, 0x2B, 0xC2, 0x80, 0x3A, 0xA5, 0x6E, 0x9A, 0x47, 0xC2, 0xF0, 0x7B, 0xAD, 0xD3, 0x39, 0x05, 0x61, 0x75, 0xA2, 0x82, 0x01, 0xC2, 0x33, 0xB7, 0x8F, 0x17, 0xC3, 0xF4, 0x6E, 0xB9, 0x8A, 0x23, 0xAC, 0xD4, 0x7E, 0xD2, 0x3F, 0x47, 0x7B, 0xDF, 0x24, 0x43, 0x17, 0x5D, 0x6D, 0xFE, 0xF3, 0x4D, 0x53, 0xEA, 0x23, 0xB3, 0xEC, 0xA3, 0x91, 0xB7, 0x00, 0xB6, 0xBF, 0x1F, 0xF9, 0x5A, 0x5C, 0x50, 0x73, 0x60, 0x05, 0x31, 0xF2, 0x46, 0xAF, 0x4D, 0x62, 0xB7, 0x1E, 0x41, 0xBD, 0x45, 0xAF, 0x91, 0xDD, 0x9C, 0x80, 0xD1, 0xCE, 0x2F, 0x07, 0xE7, 0x03, 0x40, 0xD4, 0x0F, 0x30, 0xF4, 0x81, 0x18, 0x67, 0xBB, 0x7C, 0x80, 0xD9, 0xB7, 0xBC, 0x7D, 0xC4, 0xD8, 0x2E, 0xA3, 0x9F, 0x8A, 0x71, 0xF5, 0xB6, 0xE4, 0x8B, 0x53, 0x07, 0x9E, 0xD9, 0x28, 0xCE, 0xB2, 0x53, 0xC7, 0x31, 0xAE, 0xAF, 0x72, 0x78, 0xB8, 0x32, 0xC2, 0x49, 0xDC, 0x5D, 0x3A, 0x26, 0x0A, 0x60, 0x8D, 0xCD, 0xA4, 0xEE, 0xE2, 0x14, 0x8F, 0x11, 0x2F, 0xC4, 0x81, 0xE1, 0xC3, 0xBA, 0x8A, 0x01, 0x11, 0x11, 0xA1, 0x62, 0xA3, 0xC2, 0x89, 0x5D, 0x45, 0x9B, 0x9D, 0xF3, 0xD3, 0x44, 0x58, 0x56, 0xCE, 0x22, 0x4B, 0x5C, 0x95, 0x5E, 0x3B, 0x49, 0xDC, 0x14, 0xE7, 0x3B, 0x43, 0x4C, 0x79, 0x1D, 0x31, 0x4E, 0xDC, 0x7E, 0x79, 0x67, 0x9E, 0x98, 0xD2, 0xE3, 0xD8, 0x45, 0x71, 0x8D, 0x87, 0xCA, 0x5D, 0xF2, 0x44, 0x39, 0x7D, 0x82, 0x72, 0xCA, 0x0F, 0x71, 0x4B, 0xE8, 0x9C, 0xF1, 0x00, 0x8B, 0xBA, 0xCE, 0x9C, 0x21, 0x46, 0xBD, 0x8C, 0xB1, 0x13, 0x7B, 0xB9, 0x4E, 0xFE, 0x23, 0x7A, 0x4E, 0x59, 0xD4, 0x46, 0xAC, 0x59, 0x79, 0xA3, 0x99, 0x08, 0xBB, 0x0A, 0xC1, 0x38, 0x0E, 0xF6, 0xF6, 0x2E, 0x37, 0x1C, 0x60, 0x7F, 0x44, 0xA3, 0x6C, 0xF1, 0x74, 0x8B, 0x3E, 0x7D, 0xC4, 0xF3, 0x56, 0xB3, 0x3B, 0x8A, 0x57, 0xFC, 0x32, 0xBD, 0xC5, 0xF3, 0xBB, 0x4E, 0xDF, 0x17, 0xCF, 0xCC, 0x54, 0xB9, 0xFB, 0xFC, 0x95, 0xAB, 0x4C, 0x95, 0xAB, 0x7D, 0xC4, 0xE4, 0xF8, 0x65, 0x27, 0x01, 0xA6, 0xC5, 0x2D, 0xE8, 0x2E, 0x0E, 0x5D, 0xB0, 0x78, 0x86, 0x18, 0xE8, 0xB3, 0xC1, 0x55, 0x74, 0xCF, 0xCC, 0xD8, 0x21, 0x56, 0x69, 0x7F, 0xE2, 0x87, 0x08, 0x57, 0x26, 0xEA, 0x25, 0xE9, 0x36, 0x81, 0x87, 0x7E, 0x4E, 0x7E, 0x00, 0x9F, 0x96, 0x04, 0x1A, 0x8B, 0xBF, 0x3D, 0xFA, 0xF5, 0x40, 0xAC, 0xBB, 0x6A, 0x21, 0xEA, 0x7A, 0x1C, 0xF5, 0xF1, 0xAB, 0x3B, 0x4B, 0xC4, 0x7F, 0x92, 0x07, 0x14, 0x3F, 0x54, 0x9E, 0xFF, 0xA5, 0x3C, 0x73, 0x49, 0x5C, 0xF2, 0x37, 0xB9, 0x3D, 0xC0, 0xD8, 0xB9, 0x6B, 0x5A, 0x89, 0x7D, 0x8A, 0x77, 0x36, 0x12, 0xDB, 0x25, 0x1F, 0x9A, 0x2E, 0xD6, 0xEB, 0x70, 0xF3, 0x84, 0x68, 0xE9, 0x53, 0xF4, 0x07, 0x0C, 0x23, 0xE1, 0xBE, 0xAD, 0xD5, 0x29, 0x80, 0x67, 0x59, 0x6E, 0x47, 0xC4, 0xD7, 0xD7, 0x55, 0x7D, 0xFC, 0xB9, 0x55, 0xBF, 0x4F, 0xE2, 0xA7, 0xA3, 0x73, 0x27, 0x88, 0xDF, 0xFD, 0x37, 0x5A, 0x88, 0xDF, 0x9E, 0xE4, 0xF7, 0x16, 0x7F, 0x85, 0x7D, 0xAA, 0x27, 0xFE, 0x50, 0xC7, 0xC3, 0xE7, 0x44, 0xE5, 0xC7, 0x66, 0xE2, 0xCC, 0x99, 0x29, 0xD6, 0x00, 0x11, 0xB1, 0x19, 0x46, 0x62, 0xF0, 0xDC, 0x13, 0xD9, 0x62, 0xF3, 0x1D, 0xD7, 0xED, 0xC5, 0x4A, 0x89, 0xB7, 0xCF, 0x82, 0xFE, 0x1A, 0x28, 0x98, 0x6C, 0x70, 0xD8, 0x68, 0x09, 0xDC, 0x6B, 0x50, 0xA9, 0x31, 0xC0, 0xE3, 0xED, 0x8D, 0x74, 0xC5, 0x97, 0x4D, 0x7C, 0xBF, 0x8B, 0xEF, 0x7D, 0x42, 0x41, 0x4C, 0x18, 0xAF, 0x23, 0x7E, 0x31, 0x59, 0x6E, 0x22, 0x16, 0xCF, 0xD8, 0x74, 0x0F, 0xF1, 0xD8, 0xF1, 0xC7, 0xE2, 0x4F, 0xC3, 0xF7, 0x59, 0x62, 0xC9, 0x7D, 0xC9, 0x97, 0x8E, 0x82, 0x78, 0x6D, 0x19, 0x00, 0x5C, 0x2E, 0x05, 0x06, 0x69, 0x70, 0xE1, 0x23, 0x94, 0x5D, 0x09, 0xE7, 0xFE, 0x82, 0x3D, 0x70, 0xCA, 0x0F, 0x5C, 0x5C, 0x20, 0x7F, 0x0C, 0xB8, 0xAF, 0x84, 0x03, 0x29, 0xE0, 0x75, 0x05, 0xF2, 0x8C, 0xA1, 0x4B, 0x26, 0xEC, 0x0D, 0x86, 0x41, 0x2F, 0x20, 0xEB, 0x07, 0xC4, 0x54, 0x83, 0x4C, 0x17, 0x48, 0x1C, 0x08, 0xE9, 0x11, 0x90, 0x6E, 0x05, 0x3B, 0x9E, 0xC2, 0xC9, 0x89, 0xB0, 0xA1, 0x2A, 0x14, 0x98, 0xC3, 0x8A, 0x00, 0x78, 0xB1, 0x1E, 0x16, 0x84, 0x4B, 0x2F, 0x0A, 0xE6, 0xDE, 0x83, 0xEF, 0x1F, 0xE1, 0xC6, 0x0E, 0x00, 0xB8, 0x62, 0xA5, 0xBC, 0x98, 0x03, 0x66, 0x11, 0x70, 0xC1, 0x0B, 0x2A, 0xFA, 0x81, 0xCC, 0x53, 0x9C, 0x5C, 0xE1, 0x68, 0x01, 0x34, 0xF8, 0x02, 0x07, 0x22, 0xA0, 0xCD, 0x01, 0xC8, 0xBD, 0x08, 0x81, 0x59, 0x90, 0x53, 0x00, 0x83, 0xDA, 0x42, 0xD6, 0x18, 0x98, 0x5C, 0x04, 0x19, 0xD7, 0x61, 0x8D, 0x2B, 0xEC, 0xC9, 0x86, 0x7D, 0x81, 0xB0, 0xB5, 0x0D, 0x5C, 0x8E, 0x86, 0xD5, 0xD6, 0xF0, 0x78, 0x1A, 0xC8, 0xFC, 0xE5, 0x53, 0x0B, 0x98, 0xD9, 0x16, 0xFE, 0x45, 0xC0, 0xD4, 0xFF, 0x34, 0x7F, 0xC1, 0xED, 0x11, 0x00, 0x70, 0xBD, 0xA5, 0xF2, 0xD2, 0x5C, 0xA0, 0x07, 0x5C, 0xD8, 0x02, 0x56, 0x97, 0xE1, 0xDC, 0x0D, 0xB0, 0xCF, 0x83, 0x13, 0x83, 0xC1, 0xAD, 0x07, 0x1C, 0x4C, 0x80, 0x56, 0x5E, 0xB0, 0x3F, 0x1A, 0x02, 0x82, 0x21, 0xD7, 0x03, 0x06, 0xFF, 0x85, 0x8C, 0x07, 0x30, 0xAD, 0x3D, 0xA4, 0xAD, 0x85, 0x0D, 0xAF, 0x20, 0xB5, 0x19, 0xE4, 0xBF, 0x83, 0x75, 0x49, 0x50, 0x34, 0x07, 0xE2, 0xDF, 0xC0, 0xDB, 0x3C, 0x98, 0x75, 0x07, 0x7E, 0xC7, 0xC1, 0xF8, 0xFF, 0xD5, 0x01, 0x10, 0x7D, 0x5B, 0x59, 0x58, 0x02, 0x00, 0xB7, 0x76, 0x29, 0xAF, 0x2D, 0x57, 0x5E, 0x7A, 0x06, 0x7A, 0x6D, 0x34, 0xFD, 0xC1, 0x76, 0x29, 0x1C, 0x3F, 0x00, 0x4E, 0x3D, 0x20, 0x67, 0x33, 0xB8, 0x4F, 0x82, 0xD4, 0x72, 0xE0, 0x73, 0x0C, 0xD6, 0xCF, 0x82, 0x9E, 0x0E, 0x90, 0xB4, 0x14, 0x22, 0x67, 0x69, 0x1A, 0xC3, 0x12, 0x6F, 0x58, 0x71, 0x18, 0xF6, 0xDE, 0x81, 0x65, 0x5D, 0xE1, 0xBE, 0x15, 0xCC, 0x0E, 0x81, 0xE2, 0x2E, 0x30, 0xAE, 0x50, 0xE5, 0x4E, 0x7C, 0x8B, 0xD2, 0x4F, 0xA4, 0x6A, 0x51, 0x6D, 0x00, 0x28, 0xBC, 0xAC, 0xBC, 0xF6, 0x4C, 0x79, 0x7A, 0x83, 0xF2, 0xD0, 0x6A, 0x30, 0x1B, 0x05, 0x7B, 0x4D, 0xA1, 0x72, 0x5B, 0xD8, 0x66, 0x01, 0x2E, 0x3F, 0x61, 0x45, 0x67, 0x68, 0xB1, 0x01, 0xE2, 0xAC, 0xC1, 0xB7, 0x09, 0x4C, 0xFD, 0x04, 0x7D, 0xDB, 0x6A, 0x96, 0xC0, 0x8C, 0xE9, 0x30, 0xA3, 0x00, 0xD2, 0x76, 0xC1, 0x6C, 0xA0, 0xC8, 0x0D, 0xA6, 0x7D, 0x85, 0xEF, 0xF3, 0x60, 0xFC, 0x72, 0xC9, 0xD5, 0x19, 0x38, 0xE2, 0x8D, 0x68, 0xF9, 0x35, 0xE2, 0xAF, 0x68, 0xE5, 0x77, 0xC7, 0x09, 0x00, 0x6E, 0x76, 0x56, 0x9E, 0xBB, 0xAD, 0x3C, 0xF8, 0x55, 0x99, 0x71, 0x07, 0x48, 0x82, 0xAD, 0xB2, 0xCF, 0x2F, 0x84, 0xC4, 0xA1, 0x50, 0xF5, 0x1A, 0x4C, 0x5D, 0x0A, 0x75, 0x37, 0x42, 0x94, 0x35, 0xB4, 0x31, 0x83, 0xE1, 0x5D, 0x20, 0xF8, 0x87, 0x34, 0xE6, 0x21, 0xBA, 0x31, 0x84, 0x47, 0xC1, 0xF6, 0xB6, 0x10, 0xD5, 0x1C, 0x6E, 0xE6, 0xEA, 0xEB, 0x0C, 0x7F, 0x26, 0x79, 0x65, 0x07, 0x0D, 0xEC, 0x2F, 0xDA, 0x0D, 0xEC, 0xB5, 0x45, 0xAC, 0x36, 0xAB, 0xC7, 0x06, 0xB1, 0x7A, 0xD3, 0xAB, 0xDB, 0xAD, 0x03, 0x01, 0x2E, 0x9D, 0xB6, 0x3A, 0x2B, 0x1E, 0xB9, 0x63, 0xE1, 0x24, 0x66, 0x55, 0x2C, 0xB5, 0x4F, 0xDC, 0x62, 0x6E, 0xB4, 0x55, 0x5C, 0xBC, 0x0B, 0xC0, 0x60, 0xF7, 0x94, 0xB3, 0x60, 0xF1, 0x19, 0xA7, 0x70, 0x03, 0x70, 0x98, 0x0B, 0x7D, 0x83, 0xC1, 0x7D, 0x8D, 0x6E, 0x64, 0xEF, 0x99, 0xD0, 0xF9, 0x07, 0x77, 0x7A, 0xF9, 0xC2, 0x04, 0x7B, 0xE8, 0xF9, 0x0D, 0xB6, 0xD5, 0x82, 0x1E, 0x46, 0x70, 0xF5, 0xB7, 0xFE, 0x8D, 0xCE, 0xE1, 0x48, 0x5E, 0x0F, 0x8F, 0xE5, 0x62, 0x9D, 0x6C, 0xEF, 0xDE, 0xA2, 0x6B, 0xAA, 0x07, 0xA2, 0x5B, 0x9B, 0xF3, 0xFD, 0xAA, 0x0D, 0x04, 0x38, 0x13, 0x6E, 0x3F, 0x44, 0xDC, 0xF7, 0xD1, 0xA1, 0xA6, 0xB8, 0xF5, 0x95, 0x5D, 0xAC, 0xB8, 0xF8, 0x6C, 0x85, 0x10, 0x31, 0xA6, 0xB0, 0x4C, 0xB8, 0x38, 0x68, 0x8C, 0xF1, 0x48, 0x31, 0xF0, 0x1B, 0x98, 0x75, 0x33, 0xEB, 0xEB, 0x73, 0x1A, 0x6A, 0xB5, 0xB6, 0xB0, 0x6E, 0x53, 0x1D, 0xDA, 0x8F, 0x28, 0x43, 0x8B, 0x39, 0x30, 0xBA, 0xB6, 0x8D, 0x6F, 0xF3, 0x89, 0xB0, 0x7E, 0x79, 0x99, 0x30, 0xF7, 0xCA, 0x70, 0x6E, 0x65, 0xD9, 0xBA, 0xF6, 0xF1, 0xF0, 0xD7, 0xCC, 0x39, 0xCF, 0xB0, 0x0B, 0x52, 0x8F, 0xB5, 0x33, 0xB7, 0x12, 0x3D, 0x52, 0xCD, 0x63, 0xC4, 0x36, 0x03, 0xF2, 0xFF, 0x35, 0x1C, 0x03, 0x70, 0xE4, 0x41, 0xE3, 0xA9, 0xE2, 0xAE, 0x82, 0x7A, 0xB5, 0xC4, 0x84, 0x13, 0x2E, 0x2F, 0xC4, 0x29, 0xD4, 0x4C, 0x12, 0x43, 0x71, 0xD8, 0x2D, 0xFA, 0x1F, 0x75, 0x88, 0x11, 0x9B, 0xFB, 0x55, 0x8D, 0x05, 0xDD, 0x12, 0x00, 0x68, 0x78, 0x1E, 0x4C, 0x87, 0xD4, 0x3D, 0x5F, 0xF7, 0x2F, 0x58, 0x8E, 0x1C, 0xD0, 0xBF, 0x76, 0x09, 0x58, 0xB7, 0x49, 0x36, 0xAA, 0x99, 0x01, 0xE5, 0xBC, 0x4F, 0x3B, 0x56, 0x5B, 0x07, 0x15, 0x7D, 0x4A, 0xAA, 0x4A, 0x7D, 0x62, 0xAF, 0xF5, 0xF5, 0x6B, 0x7C, 0x86, 0x4A, 0x23, 0xB4, 0xC7, 0xE5, 0x8B, 0xFA, 0x7F, 0xC0, 0xEA, 0x26, 0x1E, 0x38, 0xE5, 0x55, 0x06, 0x60, 0xDF, 0x12, 0x9F, 0xC9, 0x62, 0x72, 0xAD, 0x16, 0x35, 0xC4, 0x19, 0x76, 0x4D, 0x2B, 0x88, 0x43, 0x72, 0xEA, 0xEF, 0x16, 0x03, 0x16, 0xBA, 0xD5, 0x10, 0x9B, 0xFD, 0x72, 0x59, 0x2C, 0x3A, 0x17, 0x35, 0x72, 0x11, 0xC1, 0xBD, 0x40, 0xFF, 0x4F, 0x85, 0x9B, 0xD0, 0x72, 0x52, 0xB3, 0xDB, 0xE6, 0x65, 0xA1, 0x75, 0xEE, 0x70, 0x0F, 0xC3, 0x2D, 0xE0, 0xA1, 0x9B, 0xBC, 0x5B, 0xA7, 0x0C, 0x78, 0x95, 0x3B, 0xF7, 0x09, 0xC0, 0xC3, 0xF1, 0xFB, 0x7C, 0xB1, 0xF9, 0x34, 0x6D, 0x36, 0x5D, 0x17, 0xEA, 0x3B, 0x6A, 0xAF, 0x93, 0x48, 0x70, 0xFB, 0xAE, 0xCD, 0x85, 0x96, 0x65, 0xC7, 0xCB, 0x59, 0x22, 0xEC, 0xD2, 0xED, 0x3E, 0x41, 0x5C, 0xF4, 0xCC, 0xFF, 0x9C, 0x38, 0xBA, 0x6D, 0x5B, 0x6F, 0xB1, 0x7B, 0x71, 0xCB, 0x31, 0xA2, 0xE7, 0x76, 0xF7, 0x0F, 0xA2, 0x5B, 0x5A, 0xF3, 0xED, 0xA2, 0x55, 0x9E, 0xDF, 0x75, 0x11, 0x82, 0xAF, 0x94, 0x69, 0x26, 0xF6, 0xA8, 0xD4, 0xEC, 0xB0, 0xD8, 0x35, 0x2C, 0x2C, 0x48, 0xEC, 0xE2, 0x96, 0xA4, 0xEE, 0x41, 0xC1, 0xB1, 0x16, 0x62, 0x50, 0x42, 0x71, 0x63, 0xD1, 0x57, 0x5D, 0x7F, 0x82, 0xB7, 0x9E, 0xD2, 0xEB, 0x9C, 0x98, 0x3A, 0xAE, 0x7F, 0x2C, 0xC0, 0xFA, 0x9C, 0x01, 0x1E, 0xE2, 0xF4, 0xB4, 0xEE, 0x51, 0xE2, 0xA0, 0x0A, 0x01, 0xC3, 0x44, 0x7F, 0xD7, 0x0E, 0x6F, 0xC5, 0xA6, 0xF3, 0x3A, 0x4E, 0x14, 0xED, 0xB7, 0x74, 0xEF, 0x29, 0x42, 0xE8, 0x31, 0xA3, 0xE1, 0xE2, 0xC0, 0x89, 0xE5, 0x2B, 0x8A, 0x61, 0xFB, 0x9B, 0xAE, 0x46, 0x74, 0x8A, 0xE8, 0x28, 0x46, 0x8E, 0x4D, 0x2C, 0x10, 0x87, 0x7D, 0xCC, 0xDD, 0x20, 0x46, 0xAE, 0xF9, 0x79, 0x59, 0x1C, 0xDC, 0x41, 0xE5, 0x77, 0xEE, 0xA1, 0x0C, 0xC8, 0x11, 0x37, 0x77, 0x1C, 0x91, 0x05, 0xB0, 0x74, 0x67, 0xE4, 0x42, 0x71, 0x6C, 0xC4, 0x80, 0x86, 0x62, 0xAF, 0x3E, 0x21, 0xAF, 0x44, 0xEF, 0x86, 0x7D, 0xE7, 0x8B, 0xCE, 0x2B, 0x23, 0x7E, 0x8B, 0x3A, 0x35, 0xC6, 0x87, 0x81, 0x69, 0x5D, 0x98, 0xBA, 0xD6, 0xE2, 0xFF, 0xEC, 0x20, 0x39, 0x1E, 0x16, 0xE3, 0xDD, 0x3A, 0xB8, 0x88, 0x09, 0x69, 0x7D, 0xB3, 0xC4, 0xC5, 0x2B, 0x52, 0x1E, 0x8B, 0x0B, 0x6E, 0xA6, 0xFD, 0x12, 0x97, 0xFC, 0x50, 0xB9, 0xB3, 0x1D, 0x94, 0x23, 0xDF, 0x2B, 0xC3, 0xEE, 0x8A, 0x6B, 0x1C, 0x63, 0xB6, 0x02, 0xCC, 0x32, 0x1E, 0x1F, 0x24, 0x0E, 0xF3, 0x1C, 0x65, 0x21, 0x76, 0xDE, 0x33, 0xFA, 0x8C, 0xD8, 0xB8, 0xFF, 0xB4, 0x83, 0x62, 0xA5, 0x4A, 0x4B, 0xE3, 0x44, 0x58, 0x5F, 0xC3, 0x7C, 0xBD, 0xB8, 0xD5, 0xAA, 0xC6, 0x2E, 0x31, 0x75, 0x61, 0xB3, 0x15, 0x62, 0xDA, 0xDD, 0xAE, 0x8B, 0xC5, 0xCC, 0x8D, 0x51, 0xCB, 0xC4, 0xDC, 0x83, 0xA9, 0x93, 0xC4, 0x7D, 0x9D, 0x72, 0x3F, 0x21, 0x7E, 0x50, 0xB9, 0xE9, 0x49, 0xCA, 0xF8, 0x23, 0xCA, 0xF9, 0xC6, 0x62, 0x42, 0xDC, 0xDC, 0x57, 0x00, 0xE3, 0x9F, 0xCC, 0x78, 0x20, 0xF6, 0xD9, 0x3D, 0xEB, 0xB9, 0xE8, 0x53, 0x69, 0x59, 0x96, 0xE8, 0x3A, 0x64, 0xEB, 0x20, 0xD1, 0x68, 0x57, 0x96, 0x3D, 0x98, 0xDC, 0x87, 0x63, 0x73, 0xCB, 0x9E, 0x03, 0xB8, 0xEA, 0x5F, 0x6F, 0xB5, 0x58, 0xD4, 0xA7, 0x8B, 0xB3, 0xF8, 0x24, 0x2A, 0x72, 0x9A, 0xF8, 0x29, 0x2A, 0xC9, 0x12, 0xF1, 0xE6, 0xA1, 0xEA, 0xE2, 0x97, 0x41, 0x17, 0x56, 0x8A, 0xDF, 0x1B, 0xA9, 0xDC, 0x77, 0x45, 0xCA, 0xB3, 0xFF, 0x29, 0xB3, 0xAE, 0x8B, 0xB3, 0x8D, 0x12, 0xE6, 0x02, 0x44, 0x44, 0x25, 0x9C, 0x15, 0xBB, 0x3E, 0xDA, 0xF4, 0x5C, 0x6C, 0x65, 0x92, 0x6D, 0x23, 0x56, 0x7B, 0x79, 0xAE, 0x17, 0x48, 0x7D, 0x7D, 0xA5, 0xA1, 0xE1, 0xE3, 0x52, 0xDB, 0xE0, 0x7A, 0x54, 0x8D, 0x0A, 0x00, 0xB7, 0x6B, 0x36, 0x19, 0x24, 0xDE, 0xED, 0xD2, 0xB5, 0xBD, 0xF8, 0xE4, 0x63, 0x98, 0xAF, 0xF8, 0x32, 0x67, 0x7E, 0xB4, 0xF8, 0x6E, 0xD3, 0xFA, 0xAF, 0x88, 0x19, 0x47, 0x63, 0xC5, 0x6F, 0x8F, 0x8B, 0x7B, 0x8A, 0xDF, 0xBB, 0xA8, 0xFC, 0x6F, 0xF9, 0xCA, 0xD7, 0x41, 0x62, 0xF4, 0xBB, 0xF5, 0x35, 0x01, 0x42, 0xFB, 0xA4, 0x8A, 0xF8, 0x7D, 0x3B, 0xE4, 0x27, 0xBA, 0x4D, 0x3D, 0xF3, 0x05, 0xF4, 0x83, 0x4C, 0x22, 0xCF, 0x9E, 0x86, 0x52, 0x7D, 0xE0, 0x62, 0x91, 0xCD, 0x2E, 0x9D, 0x71, 0x70, 0x35, 0xB7, 0x4E, 0x0A, 0xC0, 0xCD, 0x2B, 0x2D, 0xBB, 0x89, 0x85, 0x8E, 0x41, 0x75, 0xC5, 0x7B, 0xE1, 0x83, 0xBB, 0x89, 0x4F, 0xE7, 0x4D, 0xDA, 0x29, 0xBE, 0xDA, 0x91, 0x78, 0x47, 0x7C, 0x67, 0xBB, 0xB9, 0x1E, 0x62, 0xDF, 0xE3, 0x9B, 0xC4, 0xE2, 0xB6, 0x9F, 0x3C, 0xC5, 0x6F, 0xBB, 0x25, 0x1F, 0x8A, 0x5B, 0x8B, 0x87, 0xD7, 0x02, 0xC0, 0xFE, 0xBA, 0x40, 0x7B, 0x59, 0x47, 0xC0, 0x2C, 0x0D, 0x72, 0x7A, 0x82, 0x4D, 0x1C, 0xA4, 0xEB, 0x80, 0xFD, 0x67, 0xD8, 0x31, 0x0C, 0x5C, 0xC2, 0x61, 0xCB, 0x34, 0x70, 0xEF, 0x04, 0x1B, 0x0C, 0xC1, 0xAB, 0x18, 0xD6, 0xBA, 0x41, 0xB0, 0x01, 0xAC, 0xFE, 0x01, 0xC3, 0x2E, 0xC2, 0x9A, 0x5E, 0x30, 0xB3, 0x2C, 0x24, 0x5F, 0x82, 0xF5, 0x86, 0x90, 0x74, 0x1A, 0xF6, 0x1E, 0x81, 0x65, 0xDE, 0x70, 0xD1, 0x06, 0xE6, 0x67, 0xC3, 0xBD, 0xDD, 0x30, 0x63, 0x3D, 0xBC, 0x3E, 0x2C, 0xEB, 0x34, 0x7C, 0xBA, 0x0E, 0x27, 0x4C, 0x00, 0xE0, 0x40, 0x9C, 0x72, 0xDF, 0x3F, 0xD0, 0xFB, 0x0E, 0x39, 0x67, 0xA1, 0x8C, 0x2E, 0x64, 0xD6, 0x87, 0xCA, 0xE5, 0x60, 0x67, 0x36, 0x38, 0xE5, 0x40, 0x4A, 0x79, 0x68, 0xB8, 0x09, 0xD6, 0x5F, 0x04, 0x8F, 0xDB, 0x90, 0xBC, 0x09, 0x82, 0x8E, 0xC3, 0xEA, 0x0A, 0x10, 0x1E, 0x0E, 0x6B, 0xA2, 0x61, 0xCE, 0x23, 0x48, 0xAE, 0x04, 0xDB, 0x0A, 0x61, 0x85, 0x3F, 0xE4, 0x67, 0xC2, 0xA2, 0x7D, 0x70, 0x7B, 0x1D, 0xCC, 0xEA, 0x0D, 0xCF, 0x73, 0x60, 0x62, 0x0C, 0x7C, 0x99, 0x0B, 0x63, 0xE6, 0xC2, 0xAF, 0x56, 0x52, 0xCD, 0x03, 0xC0, 0xE1, 0x7E, 0xCA, 0xBC, 0x67, 0xCA, 0xBD, 0xD9, 0x60, 0x7C, 0x12, 0xB2, 0xC3, 0xC0, 0xC6, 0x09, 0x76, 0x07, 0x43, 0x75, 0x0F, 0xD8, 0x5A, 0x0D, 0xEA, 0x8D, 0x86, 0x0D, 0x97, 0xA1, 0x4D, 0x28, 0xAC, 0x7D, 0x02, 0xC1, 0x5B, 0x60, 0x95, 0x39, 0x8C, 0xF0, 0xD7, 0xEC, 0x07, 0x8B, 0xD7, 0x6B, 0x96, 0x82, 0xCC, 0x4F, 0x90, 0xE0, 0x02, 0x57, 0x83, 0x21, 0xB6, 0x04, 0x9E, 0xEC, 0x87, 0x89, 0xC9, 0xF0, 0xE9, 0x27, 0x8C, 0xEA, 0x07, 0x7F, 0xBF, 0xC0, 0xC8, 0xA3, 0xAA, 0x0E, 0xB9, 0xE4, 0x00, 0x00, 0x67, 0x02, 0x95, 0x87, 0x0E, 0x2A, 0xF3, 0xEA, 0x2A, 0xF7, 0xD9, 0x40, 0xA9, 0xE1, 0xB0, 0xFB, 0x0D, 0x54, 0xBA, 0x0E, 0xEB, 0xAB, 0x40, 0xED, 0xA7, 0x10, 0x5F, 0x13, 0x9A, 0xD4, 0x81, 0x59, 0xEF, 0xC1, 0xE7, 0x08, 0x4C, 0x8D, 0x87, 0xDE, 0xAB, 0x61, 0x5A, 0x55, 0x98, 0x3C, 0x09, 0x66, 0x75, 0x85, 0x1D, 0x27, 0x61, 0x46, 0x21, 0x5C, 0x2D, 0x81, 0xE8, 0xC3, 0xF0, 0x6A, 0x1E, 0x44, 0x5E, 0x50, 0xB9, 0x23, 0x22, 0x95, 0xC3, 0x0D, 0x95, 0xD7, 0xDA, 0x02, 0xC0, 0xD5, 0x89, 0xCA, 0x93, 0xB5, 0x94, 0x39, 0xDF, 0x94, 0x3B, 0xE3, 0x40, 0x6F, 0x1E, 0x24, 0x7B, 0x82, 0x55, 0x3C, 0xCC, 0x1F, 0x09, 0x55, 0x2B, 0xC0, 0xA4, 0x51, 0x50, 0x67, 0x1B, 0x44, 0x5E, 0x82, 0x16, 0x59, 0x10, 0xB6, 0x0F, 0xFC, 0x63, 0xE9, 0x12, 0xDE, 0x17, 0x86, 0x37, 0x84, 0xF0, 0x2B, 0x90, 0x5C, 0x0D, 0x46, 0xB9, 0xC1, 0x85, 0x40, 0x88, 0x1C, 0x05, 0x6F, 0xAB, 0x43, 0x78, 0x57, 0x95, 0x3B, 0xF8, 0x95, 0xA8, 0xD7, 0x34, 0x34, 0x41, 0x34, 0xFC, 0x75, 0xA9, 0x15, 0x00, 0x9C, 0x0F, 0x55, 0x1E, 0xE8, 0xAD, 0xDC, 0xD3, 0x58, 0xB9, 0xAE, 0xB6, 0x72, 0x61, 0x26, 0x98, 0xE4, 0x43, 0xF4, 0x78, 0x28, 0x3B, 0x0B, 0x86, 0xBA, 0x81, 0x63, 0x04, 0xAB, 0x7A, 0x77, 0x85, 0x06, 0x3B, 0x59, 0xD9, 0xBD, 0x36, 0xB4, 0x75, 0x82, 0x6E, 0x2E, 0x10, 0xDA, 0x55, 0xBD, 0x76, 0x97, 0x5C, 0x85, 0xDE, 0x65, 0xE0, 0xC8, 0x22, 0xE8, 0xFB, 0x04, 0x3E, 0xB9, 0x1B, 0xB4, 0x0F, 0xE9, 0x25, 0xB9, 0x26, 0xC1, 0xDD, 0xAE, 0x8B, 0x96, 0x76, 0x81, 0x11, 0x62, 0xD9, 0xC7, 0x67, 0x22, 0x8D, 0x17, 0x02, 0x9C, 0xDC, 0xAA, 0x3F, 0x4D, 0xCC, 0x19, 0x69, 0xD8, 0x55, 0x4C, 0x99, 0xA1, 0xFF, 0x40, 0x5C, 0x72, 0x5E, 0xBF, 0xAC, 0x38, 0xE9, 0xB7, 0xDE, 0x51, 0x71, 0xF0, 0x3E, 0x30, 0x70, 0x84, 0xE0, 0x16, 0x60, 0x1B, 0xCA, 0x48, 0xDF, 0x70, 0xA8, 0x55, 0x1B, 0x7C, 0xC2, 0xA0, 0x95, 0x01, 0x78, 0x8D, 0x85, 0xDE, 0x3D, 0xC1, 0x3B, 0x03, 0x16, 0xB5, 0x82, 0xB6, 0xEB, 0x20, 0x6F, 0x37, 0x78, 0x6F, 0x87, 0x0F, 0x9F, 0x4D, 0x0C, 0xBC, 0xDA, 0x49, 0x6E, 0x99, 0x3E, 0x1E, 0xE9, 0x62, 0xD9, 0x3F, 0x2D, 0xC6, 0x8A, 0xE5, 0x5D, 0x8E, 0x4D, 0xA9, 0xD0, 0x1E, 0xE0, 0x48, 0xE7, 0x0A, 0x03, 0xC4, 0xDD, 0xF7, 0x6D, 0xE6, 0x8B, 0xCB, 0x66, 0xDB, 0x7E, 0x17, 0x67, 0x8C, 0x28, 0x73, 0x57, 0x0C, 0xF3, 0x34, 0xCB, 0x12, 0xBB, 0xEE, 0x33, 0x16, 0x69, 0x63, 0x09, 0x7A, 0x2B, 0xF4, 0xED, 0x9A, 0x4E, 0x80, 0x2A, 0xB3, 0x75, 0x37, 0x34, 0xBA, 0x0C, 0xCD, 0xC7, 0xE8, 0x5D, 0xAF, 0x3F, 0x06, 0xFA, 0xA4, 0x19, 0xD9, 0xD5, 0x4D, 0x86, 0x85, 0xD6, 0x86, 0x0B, 0x9D, 0x75, 0x61, 0x9F, 0xB5, 0xD1, 0x8E, 0xCA, 0x47, 0xE0, 0xF9, 0x18, 0xAB, 0x24, 0x8B, 0x04, 0xA4, 0x1E, 0xDC, 0x6A, 0xB5, 0x42, 0xAC, 0x7E, 0xB1, 0xEC, 0x47, 0xC4, 0x75, 0x07, 0xFE, 0xD6, 0x9E, 0x0C, 0x90, 0xFB, 0xD2, 0x55, 0x5F, 0x5C, 0xBB, 0xAC, 0xE6, 0x6A, 0x31, 0xEE, 0x6D, 0xCD, 0x72, 0xE2, 0x48, 0x37, 0xFB, 0x3C, 0xB1, 0x7B, 0x6C, 0x85, 0xDE, 0xA2, 0xE7, 0x4A, 0xEB, 0xDF, 0xA2, 0xDB, 0x52, 0x9B, 0x81, 0x22, 0x00, 0x38, 0x2C, 0x03, 0x13, 0xD3, 0xDA, 0x01, 0x55, 0x5B, 0x82, 0x95, 0x5B, 0x8F, 0x68, 0xDB, 0xF6, 0x50, 0xBE, 0x79, 0x7C, 0x3F, 0xEB, 0x03, 0x9A, 0x07, 0x0E, 0x1B, 0x58, 0xD5, 0x00, 0x3B, 0xCB, 0x57, 0xB1, 0xA6, 0x8D, 0xA1, 0x7C, 0x27, 0xED, 0x3A, 0xB2, 0x4A, 0x60, 0xBD, 0x54, 0xEB, 0x7F, 0x18, 0x82, 0x45, 0xA2, 0x56, 0x87, 0x74, 0xC9, 0x3E, 0xDE, 0x14, 0x80, 0xF4, 0x2E, 0xCD, 0x4F, 0x89, 0x09, 0x4B, 0x1B, 0xFD, 0x10, 0x27, 0xDE, 0xAD, 0x3B, 0x43, 0xED, 0x37, 0xB5, 0xFC, 0x45, 0x9F, 0x63, 0xD5, 0x87, 0x8B, 0xF5, 0xD6, 0x3B, 0xB4, 0x13, 0x2B, 0x37, 0xA9, 0x71, 0x57, 0x84, 0xFA, 0x3D, 0x4C, 0x12, 0x0C, 0x8A, 0x35, 0x03, 0xEB, 0x27, 0x01, 0x34, 0x48, 0x0E, 0x3D, 0x2B, 0xBA, 0x8D, 0x5E, 0xD2, 0x53, 0xAC, 0x7F, 0xEE, 0xE8, 0x22, 0xD1, 0x75, 0xE5, 0xEB, 0xD3, 0x62, 0x2D, 0xD5, 0x6F, 0xC0, 0x69, 0xA9, 0xB2, 0x86, 0x76, 0x5D, 0xAE, 0xAE, 0xFB, 0xAE, 0xC3, 0xDE, 0x4F, 0x00, 0x36, 0x3F, 0xF1, 0x4B, 0x15, 0x67, 0xDD, 0xF6, 0x16, 0x18, 0x36, 0xAD, 0x79, 0x2F, 0x31, 0x30, 0xAD, 0xE1, 0x23, 0xB1, 0xD9, 0x3A, 0xB7, 0xCD, 0xA2, 0xE3, 0xF5, 0xFA, 0x96, 0xA2, 0x5E, 0x42, 0x8B, 0x68, 0xD0, 0xFF, 0x02, 0x2D, 0x6F, 0x94, 0x7E, 0x00, 0x9A, 0x63, 0x1B, 0xB7, 0x10, 0x5B, 0x3C, 0x1A, 0x90, 0x2B, 0xBA, 0xAF, 0x98, 0x1F, 0x21, 0x36, 0x9B, 0x72, 0xA0, 0xB6, 0xE8, 0x5E, 0xF3, 0x86, 0x9D, 0x58, 0x7F, 0xB4, 0xCA, 0x77, 0xFE, 0xA8, 0xAC, 0x9D, 0x2C, 0x6E, 0xB6, 0x0C, 0x76, 0x00, 0x58, 0x69, 0xD0, 0x53, 0x24, 0x5A, 0xCF, 0xFF, 0xAE, 0x18, 0x82, 0xF7, 0x17, 0xD1, 0x7B, 0x68, 0xEB, 0x9A, 0xA2, 0x9B, 0xBE, 0xC7, 0x35, 0xD1, 0x3A, 0xBA, 0xE3, 0x3F, 0x11, 0xBA, 0x2C, 0x34, 0x7D, 0x25, 0x06, 0x6E, 0xB5, 0x75, 0x14, 0x3B, 0x2F, 0x52, 0x13, 0x58, 0x7F, 0x9F, 0xA1, 0x29, 0x62, 0xC0, 0xD0, 0x71, 0x9D, 0xC5, 0x8E, 0xA7, 0xF7, 0x5F, 0x13, 0xFD, 0x3B, 0x5C, 0x8C, 0x12, 0x3B, 0x75, 0x53, 0xF9, 0xEE, 0xC1, 0xCA, 0x86, 0x4D, 0xC4, 0xD5, 0xC7, 0x06, 0x64, 0x00, 0xCC, 0x9D, 0x3C, 0xD0, 0x57, 0x8C, 0xA8, 0xDA, 0xB3, 0xA9, 0xD8, 0x25, 0xA7, 0x6B, 0xAA, 0xD8, 0xC2, 0x2E, 0xB8, 0xBC, 0x58, 0xED, 0x50, 0xDF, 0x61, 0x22, 0x0C, 0x4B, 0xD1, 0xBB, 0xA7, 0xBF, 0x08, 0x22, 0x16, 0x59, 0x7D, 0x00, 0x18, 0xDE, 0xB3, 0xFA, 0x04, 0x71, 0x14, 0x3E, 0x15, 0xC5, 0xA8, 0x16, 0xA3, 0x2A, 0x8B, 0x13, 0x7F, 0x27, 0x9B, 0x8B, 0xD1, 0xD9, 0x3B, 0xD6, 0x8A, 0x93, 0x54, 0xBD, 0xC1, 0xF8, 0x56, 0xCA, 0xC1, 0x37, 0x94, 0x9D, 0xF2, 0xC5, 0xA5, 0x85, 0x51, 0x77, 0xD5, 0x77, 0x0D, 0xCF, 0x14, 0xFB, 0xB5, 0x1C, 0x7C, 0x44, 0xEC, 0xD0, 0x76, 0x58, 0xA4, 0x58, 0xA7, 0xF9, 0x38, 0x17, 0xB1, 0x8C, 0xFF, 0xCC, 0x5F, 0x22, 0x2C, 0xD6, 0x2D, 0xBD, 0x42, 0x4C, 0x34, 0xA9, 0x35, 0x58, 0x4C, 0x3E, 0xD5, 0x7C, 0x9E, 0xB8, 0xC5, 0xAC, 0x5B, 0x05, 0x71, 0x5B, 0x4A, 0x68, 0x7B, 0x31, 0x35, 0x2B, 0x31, 0x5A, 0xDC, 0x93, 0xBB, 0x37, 0x43, 0x4C, 0x7F, 0xAB, 0x72, 0x77, 0xC6, 0x2A, 0x17, 0x0E, 0x55, 0x8E, 0xF9, 0x26, 0xCE, 0xBD, 0x3A, 0x75, 0x1D, 0x40, 0x64, 0xDD, 0xE8, 0x7B, 0x62, 0xB0, 0xF3, 0x24, 0x5F, 0xB1, 0xF9, 0xF4, 0xB9, 0xAD, 0x45, 0xC7, 0xF0, 0x55, 0x3B, 0x45, 0xD8, 0xDA, 0xC7, 0xD8, 0xD5, 0x34, 0x05, 0x32, 0x7B, 0x57, 0xEB, 0x02, 0xB0, 0xFF, 0x7D, 0x73, 0x73, 0xF1, 0xC2, 0xAF, 0x9E, 0xB7, 0xC5, 0x1B, 0x76, 0xA3, 0x13, 0xC4, 0xBB, 0x3A, 0x89, 0xE3, 0xC5, 0x47, 0x23, 0xF2, 0xF6, 0x88, 0x8F, 0x3D, 0xF2, 0x67, 0x8B, 0x6F, 0x55, 0x5F, 0x8A, 0x07, 0x1D, 0x94, 0xE7, 0x7D, 0x94, 0xAB, 0xEB, 0x8B, 0x93, 0xEF, 0xCC, 0xAF, 0x03, 0x30, 0xA0, 0xF1, 0xFC, 0x0F, 0xA2, 0xEF, 0xF6, 0x55, 0x0F, 0xC5, 0x46, 0x47, 0x52, 0x7D, 0x44, 0xB3, 0xA5, 0x79, 0x97, 0xA1, 0xCC, 0x0B, 0x38, 0x19, 0x5B, 0xDE, 0x5F, 0xBF, 0x2B, 0x9C, 0x39, 0xEC, 0x76, 0x0F, 0xC9, 0x4F, 0xF1, 0x29, 0x11, 0xAF, 0x76, 0x0F, 0xF9, 0x2D, 0xDE, 0xAC, 0x3C, 0x72, 0xB7, 0x58, 0x70, 0x79, 0xFE, 0x58, 0xF1, 0x41, 0xF6, 0xCE, 0xB6, 0xE2, 0xB3, 0xF7, 0xC7, 0x76, 0x88, 0x9F, 0xA7, 0xFE, 0x18, 0x20, 0x16, 0x3F, 0x57, 0xF9, 0x3F, 0x3F, 0x2A, 0x6F, 0x1C, 0x13, 0x47, 0xD9, 0xAE, 0x6A, 0x00, 0xD0, 0xC3, 0x37, 0x65, 0xBD, 0xE8, 0x55, 0x3F, 0xA7, 0x40, 0xAC, 0xDA, 0xFD, 0xB0, 0x0D, 0x98, 0x8F, 0x82, 0xC3, 0x91, 0xE6, 0xEB, 0x4A, 0x3D, 0x81, 0xE3, 0xB6, 0x8E, 0xDE, 0x00, 0xA7, 0x47, 0x36, 0xEE, 0x28, 0x9E, 0x7F, 0xE2, 0x7B, 0x5F, 0xBC, 0x9C, 0x1B, 0x12, 0x21, 0x5E, 0xAF, 0x13, 0xF1, 0x41, 0xBC, 0xED, 0x39, 0xE9, 0x8B, 0x58, 0x64, 0xBE, 0x52, 0x57, 0x7C, 0x94, 0x93, 0x71, 0x40, 0xFC, 0x6F, 0xDC, 0xF1, 0x21, 0xE2, 0xA7, 0x90, 0x4F, 0x21, 0x62, 0xB1, 0x5C, 0xBF, 0x25, 0xAE, 0x14, 0xD3, 0x8A, 0x00, 0x60, 0x67, 0x19, 0x65, 0x4A, 0x6B, 0xD0, 0x6F, 0x0D, 0xEB, 0x2C, 0xC0, 0xBC, 0x14, 0x24, 0x55, 0x05, 0x5B, 0x7B, 0x88, 0xBF, 0x06, 0x55, 0x47, 0xC0, 0x7C, 0x1B, 0xA8, 0x9D, 0x07, 0x71, 0xFD, 0xA0, 0x51, 0x3A, 0x4C, 0x07, 0x3C, 0xC6, 0xEA, 0x7E, 0x9A, 0x7A, 0x0E, 0x82, 0x36, 0xE9, 0x1D, 0x9C, 0xFE, 0x08, 0x46, 0x94, 0xE8, 0xB6, 0x8E, 0x6D, 0x0D, 0x0B, 0x66, 0x50, 0x2F, 0xAE, 0x07, 0x6C, 0x93, 0xBA, 0x23, 0x02, 0x0E, 0xBB, 0xC3, 0xD4, 0x51, 0x70, 0x75, 0x1E, 0x44, 0x37, 0x80, 0x87, 0x19, 0x30, 0xA6, 0x19, 0xBC, 0xAF, 0x0F, 0x59, 0xA6, 0x00, 0xB0, 0xDB, 0x49, 0xB9, 0xF5, 0x92, 0x72, 0xD3, 0x54, 0x30, 0x38, 0x04, 0xAB, 0xFC, 0xA0, 0x4C, 0x25, 0x48, 0xB0, 0x85, 0x8A, 0xDF, 0x61, 0x5E, 0x1E, 0xD4, 0xFC, 0x07, 0xB1, 0x09, 0xD0, 0xE0, 0x1D, 0x4C, 0xAD, 0x0C, 0xAD, 0xEF, 0xEA, 0xB5, 0x98, 0x62, 0x00, 0xC1, 0x87, 0xF4, 0x0A, 0xA6, 0x97, 0x81, 0x31, 0x83, 0x74, 0x56, 0xC4, 0x76, 0x86, 0xC4, 0x89, 0x30, 0xEB, 0x0B, 0x64, 0x3E, 0x86, 0x69, 0x19, 0x70, 0xCE, 0x15, 0xA2, 0xEF, 0x40, 0xD1, 0x66, 0x90, 0xA9, 0xFC, 0x9B, 0x13, 0x30, 0x7C, 0x34, 0x94, 0x24, 0xC3, 0xBE, 0xE1, 0x00, 0x90, 0x31, 0x50, 0x99, 0x6A, 0xA4, 0xDC, 0xD2, 0x1A, 0x38, 0x0C, 0x6B, 0x2E, 0x80, 0xE9, 0x7D, 0x58, 0x7E, 0x14, 0xCA, 0x97, 0x83, 0xF9, 0x73, 0xA1, 0xFA, 0x22, 0x88, 0x7D, 0x00, 0xF5, 0x5B, 0xC0, 0xD4, 0x24, 0x68, 0xD3, 0x4E, 0xEF, 0xDB, 0xE4, 0xCF, 0xD0, 0x33, 0x44, 0x3F, 0x49, 0xEA, 0x8F, 0x49, 0xF1, 0x14, 0xCE, 0x6A, 0x09, 0x9B, 0xB6, 0xC1, 0x4C, 0x4F, 0x38, 0xE6, 0xA8, 0xEA, 0xAF, 0x3B, 0x0F, 0x61, 0xF4, 0x3A, 0x78, 0x5D, 0x04, 0x11, 0xCE, 0xF0, 0x63, 0x0F, 0x0C, 0x3E, 0x0E, 0xFF, 0xEA, 0x81, 0xAA, 0xED, 0x61, 0xEF, 0x29, 0x65, 0xFA, 0x32, 0xE5, 0x8E, 0x43, 0xCA, 0x2D, 0x4B, 0x41, 0x27, 0x04, 0x12, 0xCF, 0x40, 0xD9, 0xCA, 0x30, 0xB3, 0x18, 0x2A, 0x15, 0xC3, 0x84, 0x3D, 0xE0, 0xBC, 0x0F, 0x86, 0x67, 0x43, 0x93, 0x35, 0x7A, 0x47, 0x87, 0x79, 0x42, 0xC7, 0xC9, 0xFA, 0xBA, 0xE1, 0x3D, 0x20, 0x2C, 0x19, 0xC2, 0x33, 0x60, 0x99, 0x07, 0x44, 0xA6, 0xC3, 0xE1, 0xCF, 0x10, 0x71, 0x09, 0x1E, 0x24, 0x41, 0x98, 0x25, 0xFC, 0xFE, 0x06, 0xA1, 0x67, 0x55, 0x1D, 0xD2, 0xE7, 0xA2, 0xF2, 0x4C, 0x1D, 0x00, 0x38, 0x35, 0x53, 0x99, 0x93, 0xA4, 0xDC, 0xB6, 0x4B, 0xB9, 0xA2, 0xAD, 0x32, 0xAE, 0x2C, 0x98, 0xDA, 0xC2, 0xE8, 0xC6, 0x50, 0xF6, 0x81, 0xEA, 0x11, 0x56, 0x9B, 0x0F, 0x3D, 0x57, 0x81, 0xDB, 0x7E, 0xDD, 0xE8, 0xE0, 0x13, 0xD0, 0x7A, 0x97, 0xCE, 0xD4, 0x6E, 0xB2, 0xEF, 0x9F, 0x83, 0x6E, 0x6D, 0x60, 0x4E, 0x01, 0xC8, 0xAA, 0x98, 0x3B, 0x0B, 0x7A, 0x07, 0xC3, 0x43, 0x7B, 0xE8, 0x13, 0xA2, 0x72, 0x7B, 0xCC, 0x57, 0x06, 0x3D, 0x52, 0x9E, 0xA8, 0x05, 0x00, 0x87, 0x1A, 0x2A, 0xD3, 0xDE, 0x28, 0xD7, 0x5A, 0x2B, 0xE7, 0xED, 0x52, 0x8E, 0x5B, 0x0A, 0x94, 0x81, 0xD0, 0x41, 0x60, 0xFC, 0x00, 0xBA, 0x9A, 0x43, 0xF9, 0x30, 0x9D, 0xAA, 0xED, 0xAB, 0x83, 0xE3, 0x2E, 0x1A, 0x79, 0x4D, 0x83, 0x46, 0x9B, 0xC1, 0xA3, 0x00, 0x02, 0xEE, 0x41, 0xDB, 0x64, 0x98, 0xB2, 0x0B, 0xBC, 0x7E, 0x40, 0x6A, 0x35, 0xF0, 0x2D, 0x07, 0x45, 0x01, 0x10, 0x50, 0x53, 0xE5, 0xFA, 0x25, 0x2A, 0xDB, 0x87, 0x28, 0x0F, 0xAB, 0x5C, 0x0E, 0xD6, 0x57, 0xA6, 0x96, 0x55, 0x2E, 0x77, 0x65, 0x84, 0x38, 0xCD, 0x55, 0xB7, 0xA7, 0x38, 0xF4, 0x06, 0x00, 0x74, 0xF9, 0x82, 0x2A, 0x47, 0xAA, 0x40, 0xA9, 0x45, 0x3C, 0x6A, 0x1C, 0x01, 0x15, 0x9F, 0x40, 0x83, 0x5D, 0x50, 0xC7, 0x16, 0xEA, 0x6F, 0x81, 0x76, 0x43, 0xA0, 0xC1, 0x21, 0x88, 0x5E, 0x08, 0x75, 0x63, 0x61, 0x27, 0xD0, 0x70, 0x10, 0x14, 0xCE, 0x86, 0x66, 0x4B, 0x55, 0x6E, 0xD3, 0x51, 0xCA, 0x46, 0xA5, 0x44, 0xDD, 0x16, 0xFB, 0x37, 0x94, 0xAE, 0x06, 0x90, 0xEB, 0x57, 0xFA, 0xBC, 0xB8, 0x39, 0xA4, 0x54, 0x7F, 0x31, 0xF6, 0x52, 0x99, 0x23, 0xE2, 0x18, 0x1D, 0x33, 0x0F, 0xB1, 0xFB, 0x5F, 0xE3, 0x58, 0xD1, 0xFB, 0x84, 0xC1, 0x7D, 0x51, 0xAD, 0x65, 0xBA, 0x56, 0x4E, 0xDD, 0xC0, 0x5A, 0x17, 0x6A, 0x9E, 0x05, 0x97, 0xE5, 0xE0, 0x38, 0x13, 0xFC, 0xC3, 0xC1, 0x61, 0x0A, 0xC4, 0x9A, 0x40, 0x85, 0x97, 0x90, 0x75, 0x4E, 0xF7, 0xAC, 0x4D, 0x14, 0xDC, 0xCD, 0xD3, 0x9F, 0x68, 0xD5, 0x1E, 0xA9, 0x0B, 0xBF, 0x96, 0x73, 0x17, 0x8D, 0x07, 0xD8, 0x56, 0x13, 0x4D, 0x52, 0x72, 0x46, 0xD8, 0x5F, 0x00, 0xC8, 0xFC, 0x53, 0xBD, 0x8B, 0xB8, 0x2C, 0xDF, 0xE1, 0xBB, 0x38, 0x75, 0xA5, 0x43, 0x7B, 0x31, 0x74, 0x5D, 0xB9, 0xF7, 0x62, 0xA7, 0x52, 0x56, 0xF1, 0xA2, 0xFB, 0x01, 0xF3, 0x2A, 0xA2, 0x43, 0xB6, 0x49, 0x53, 0x11, 0x00, 0xAC, 0xCA, 0x82, 0xD9, 0xA5, 0xDA, 0xB6, 0xA5, 0xC2, 0xA0, 0x74, 0x48, 0xF0, 0x61, 0xFD, 0xF3, 0x50, 0xCE, 0x6F, 0x5E, 0x2B, 0x80, 0xF2, 0x99, 0x87, 0x4C, 0xC4, 0xB2, 0xF5, 0x9E, 0x56, 0x14, 0x4B, 0xAF, 0x51, 0xEB, 0x97, 0xE5, 0x61, 0xA5, 0x49, 0x9C, 0x56, 0x27, 0xDF, 0xDE, 0xD3, 0xAC, 0xEE, 0x66, 0x80, 0x9D, 0x43, 0x1B, 0xB4, 0x12, 0xE7, 0xD9, 0xBA, 0x7D, 0x10, 0x47, 0x5E, 0x71, 0x5A, 0x26, 0x06, 0x1F, 0xB1, 0xF7, 0x13, 0x5B, 0xE5, 0xD9, 0x35, 0x14, 0x9D, 0x5E, 0xD9, 0xDE, 0x12, 0x2D, 0x47, 0x56, 0x7C, 0x27, 0x82, 0xBD, 0xA1, 0x71, 0x45, 0xB1, 0xFC, 0x3D, 0x17, 0x0F, 0xB1, 0x62, 0x9D, 0x9E, 0xA5, 0x44, 0xDB, 0x81, 0x33, 0x67, 0x89, 0x15, 0x47, 0xE5, 0x35, 0x16, 0x6D, 0x5E, 0x5D, 0xCF, 0x16, 0xAD, 0xEF, 0xAA, 0x7C, 0xCB, 0xC6, 0xA2, 0x66, 0x84, 0x98, 0x92, 0xDF, 0xC2, 0x0D, 0x60, 0xB5, 0x89, 0xD7, 0x6A, 0x71, 0xEA, 0xDA, 0xE6, 0x41, 0x62, 0xFF, 0xC1, 0x0D, 0x9A, 0x8A, 0x1D, 0xEA, 0xB8, 0x84, 0x89, 0xF5, 0xF3, 0x6A, 0xEE, 0x11, 0xED, 0x7A, 0xD6, 0x4A, 0x12, 0xA1, 0xC1, 0x08, 0x9D, 0xAE, 0xE8, 0x82, 0x8B, 0x5D, 0xE9, 0x2F, 0x00, 0x4E, 0x15, 0x1B, 0xDF, 0x17, 0x6B, 0x0D, 0xEF, 0xBB, 0x5E, 0xAC, 0x3E, 0x3F, 0xBA, 0xA7, 0x58, 0x33, 0x3C, 0x67, 0x8E, 0xE8, 0x18, 0x75, 0xE2, 0x8F, 0xE8, 0xB0, 0x5F, 0xE5, 0x97, 0x5F, 0xA0, 0x2C, 0x67, 0x27, 0xAE, 0xFA, 0xDB, 0xF1, 0x27, 0xC0, 0xE2, 0x8F, 0x9D, 0x7D, 0xC4, 0x91, 0x96, 0x3E, 0xB1, 0x62, 0x70, 0xE5, 0x56, 0x86, 0x62, 0xCB, 0x8B, 0xEE, 0xFB, 0xC4, 0x1A, 0xC5, 0x4D, 0x3B, 0x8B, 0xC6, 0x97, 0x3C, 0xA3, 0x44, 0xF0, 0x9C, 0x6B, 0xF2, 0x56, 0x6C, 0x1E, 0x50, 0x3E, 0x5C, 0x6C, 0xD6, 0xDD, 0xD3, 0x59, 0x6C, 0xDA, 0x69, 0xE0, 0x59, 0xB1, 0xC1, 0xEB, 0xB1, 0x5B, 0x45, 0xF7, 0x0A, 0x69, 0x2F, 0xC5, 0x86, 0x6D, 0x0F, 0x3E, 0x43, 0x34, 0x52, 0xF9, 0xB5, 0x6F, 0x2A, 0x1D, 0x4A, 0x89, 0x09, 0x9B, 0x7A, 0x35, 0x06, 0x98, 0xF6, 0xBD, 0x57, 0x3F, 0x31, 0x34, 0x21, 0xF0, 0xA6, 0xE8, 0xFB, 0xC6, 0xB7, 0xB9, 0xD8, 0x60, 0x4B, 0xC7, 0x0C, 0xB1, 0x7C, 0x7A, 0xB7, 0x8E, 0x22, 0x84, 0x54, 0x31, 0x78, 0x2B, 0xF6, 0x3C, 0x57, 0x36, 0x16, 0xB1, 0xBD, 0x53, 0x9A, 0xD8, 0x23, 0xD0, 0xB3, 0xB3, 0xD8, 0xA5, 0x71, 0x44, 0xA8, 0x18, 0xDC, 0x31, 0x72, 0x08, 0x62, 0xEA, 0xA6, 0xFA, 0x62, 0xE7, 0x2F, 0xD7, 0x5C, 0xC5, 0x70, 0x3B, 0x95, 0x1F, 0x68, 0xA9, 0x6C, 0x58, 0x59, 0x9C, 0x37, 0x75, 0xD8, 0x1F, 0x80, 0xD1, 0x29, 0x03, 0xFF, 0x8A, 0xDD, 0x77, 0xF4, 0xC9, 0x14, 0xDB, 0xDC, 0xE8, 0x73, 0x40, 0xAC, 0xF1, 0x22, 0xBC, 0x9B, 0xA8, 0xE3, 0x31, 0x66, 0x3B, 0x18, 0xDF, 0x83, 0x98, 0x04, 0xCB, 0xC1, 0x00, 0xB3, 0x1D, 0xAB, 0x9D, 0x13, 0x17, 0xAF, 0x6B, 0xEC, 0x20, 0x26, 0xBE, 0xEA, 0xFE, 0x52, 0x5C, 0x39, 0xAB, 0x6F, 0x94, 0xB8, 0xE8, 0xE6, 0x96, 0x0F, 0xE2, 0xC2, 0xB7, 0x7B, 0x06, 0x88, 0x2B, 0x17, 0xAB, 0xDC, 0x84, 0x28, 0xE5, 0xEC, 0xAD, 0xCA, 0x90, 0x6F, 0xE2, 0xF4, 0x36, 0xE3, 0x6B, 0x00, 0x0C, 0xD6, 0x1D, 0x79, 0x4F, 0xEC, 0x64, 0x16, 0xF5, 0x48, 0xAC, 0x5F, 0x65, 0xCA, 0x65, 0xB1, 0x92, 0xE9, 0xA2, 0x8E, 0x22, 0xAC, 0xEA, 0x59, 0xA6, 0xA3, 0xEE, 0x18, 0xD8, 0xB2, 0xA5, 0x76, 0x2C, 0xC0, 0xAE, 0x8F, 0xAD, 0xA6, 0x88, 0xD9, 0x63, 0x82, 0x4A, 0x8B, 0x79, 0x9F, 0xC3, 0xE3, 0xC5, 0x4B, 0x83, 0x17, 0x7D, 0x14, 0x6F, 0xDD, 0xDA, 0x17, 0x21, 0xDE, 0x1E, 0x7E, 0xB4, 0x50, 0xBC, 0xA7, 0xEA, 0x63, 0x0A, 0x3C, 0x94, 0xE7, 0x26, 0x28, 0x17, 0x3F, 0x15, 0xC7, 0x26, 0xCC, 0xF2, 0x07, 0xE8, 0x71, 0x72, 0xE6, 0x57, 0xD1, 0xC3, 0x6A, 0x49, 0x2B, 0xD1, 0x75, 0xC2, 0xC6, 0x1C, 0x11, 0x76, 0x3D, 0x31, 0x6C, 0x6A, 0xB3, 0x11, 0xF6, 0x9F, 0xA9, 0xE9, 0x0D, 0x9A, 0x55, 0x9A, 0xE5, 0x88, 0x07, 0xEA, 0x06, 0x4C, 0x17, 0x4F, 0x37, 0x0D, 0x4D, 0x12, 0x2F, 0xB4, 0x18, 0x35, 0x5C, 0xBC, 0x66, 0xBB, 0x64, 0x98, 0x58, 0x58, 0x7E, 0xB7, 0x93, 0xAA, 0xBF, 0xF2, 0x9B, 0x89, 0xCF, 0x17, 0x9E, 0xEE, 0x2A, 0x16, 0x7B, 0xA9, 0xFC, 0xBF, 0x0F, 0x95, 0x97, 0xFA, 0x8A, 0x43, 0x1B, 0x2F, 0xBB, 0x05, 0x10, 0xA0, 0xB7, 0x3E, 0x47, 0x6C, 0xA6, 0xBF, 0xA7, 0xB2, 0x68, 0x3A, 0x36, 0x63, 0x19, 0xD8, 0xCC, 0x85, 0xEC, 0xA9, 0x76, 0xF1, 0xC6, 0x77, 0x61, 0x5F, 0x33, 0xB7, 0x69, 0x00, 0x79, 0x23, 0x5A, 0xAD, 0x17, 0x0F, 0x6C, 0xEF, 0x52, 0x51, 0x3C, 0x69, 0x16, 0x2A, 0x70, 0xCE, 0x68, 0xC4, 0x1B, 0xF1, 0xF2, 0xF0, 0xD9, 0xB3, 0xC5, 0x1B, 0x1F, 0x96, 0x7F, 0x10, 0xEF, 0x4E, 0xCB, 0xFA, 0x28, 0x3E, 0xDC, 0x9E, 0xFF, 0x4F, 0x7C, 0xBF, 0xE8, 0xFD, 0x22, 0xF1, 0x6B, 0x90, 0xE4, 0x43, 0x89, 0x9D, 0xB8, 0x6E, 0x35, 0x00, 0xAC, 0x4C, 0x55, 0xC6, 0xCF, 0x54, 0xCE, 0x6B, 0x0A, 0x86, 0xC7, 0x61, 0x86, 0x07, 0x98, 0xE7, 0xC2, 0xC4, 0x0C, 0xB0, 0xF6, 0x87, 0x31, 0x2F, 0xA0, 0xCA, 0x56, 0x18, 0xBE, 0x4F, 0xCE, 0x84, 0x0C, 0x4A, 0x0F, 0xBD, 0x21, 0x75, 0x88, 0x49, 0xC4, 0xE0, 0x9F, 0xE0, 0xE5, 0x6F, 0x66, 0x1A, 0x16, 0x21, 0xAF, 0x5C, 0xC3, 0xD7, 0x23, 0xBA, 0xC2, 0x38, 0x77, 0xDD, 0x2B, 0xA3, 0x2E, 0x40, 0xC2, 0x7E, 0x88, 0x2A, 0x80, 0xDD, 0x36, 0x30, 0xBA, 0x05, 0x1C, 0xFB, 0x0C, 0x23, 0xF7, 0xC2, 0x2D, 0x2F, 0x18, 0xB1, 0x03, 0x5E, 0x5C, 0x84, 0x2D, 0x9B, 0x00, 0x60, 0xCD, 0x20, 0xE5, 0xB2, 0xAB, 0xCA, 0x05, 0x05, 0xA0, 0xB3, 0x02, 0x66, 0xAD, 0x00, 0x93, 0x3A, 0x30, 0xE9, 0x01, 0x58, 0x99, 0xC2, 0x58, 0x23, 0xA8, 0xF8, 0x10, 0x22, 0xBE, 0x41, 0x8D, 0x0F, 0xFA, 0xAF, 0x86, 0x98, 0x42, 0x03, 0x5F, 0x93, 0x65, 0x83, 0xFC, 0xA0, 0x6D, 0xA1, 0x99, 0xE9, 0xB0, 0x17, 0xD0, 0x27, 0xC7, 0xE0, 0xDE, 0xF0, 0x5C, 0x98, 0xF2, 0x56, 0x67, 0xDF, 0xC8, 0xE3, 0xB0, 0xDE, 0x0A, 0xA2, 0xF4, 0x61, 0x7F, 0x17, 0x18, 0x39, 0x1E, 0xAE, 0x8E, 0x80, 0xE1, 0x2F, 0xE1, 0xD9, 0x78, 0x18, 0xA6, 0x07, 0xC5, 0x16, 0xB0, 0xB3, 0x1C, 0x00, 0x6C, 0x5A, 0xA9, 0x4C, 0x9A, 0xAA, 0x5C, 0x72, 0x4A, 0x39, 0x3B, 0x11, 0x0C, 0x96, 0xC1, 0xE4, 0x02, 0x28, 0x65, 0x04, 0x63, 0x5B, 0x43, 0xF9, 0xFA, 0x10, 0x31, 0x00, 0xAA, 0xDF, 0xD6, 0x5F, 0x3E, 0xA8, 0x32, 0xD4, 0xDF, 0x60, 0x72, 0x60, 0xC0, 0x66, 0x68, 0x67, 0x64, 0xFA, 0x76, 0xC8, 0x14, 0x18, 0x90, 0xA2, 0x1F, 0x15, 0x9E, 0x06, 0x73, 0xDD, 0x20, 0xB2, 0x19, 0xEC, 0x19, 0x06, 0x23, 0x4B, 0xC3, 0x85, 0x0A, 0x30, 0xBC, 0x0C, 0x3C, 0x9D, 0x06, 0x43, 0x4C, 0xA0, 0x38, 0x10, 0x42, 0x42, 0xE0, 0xD7, 0x76, 0xC8, 0x38, 0x06, 0x00, 0x3B, 0xAB, 0x2B, 0xD7, 0x4F, 0x54, 0xAE, 0xD0, 0x51, 0x2E, 0x88, 0x55, 0x4E, 0x39, 0x08, 0x46, 0x47, 0x20, 0xD2, 0x19, 0xAC, 0xDE, 0x43, 0xFF, 0x69, 0x50, 0x39, 0x4F, 0xCF, 0xB2, 0x9B, 0x3F, 0x38, 0x57, 0x31, 0x6A, 0xD7, 0xD5, 0x0D, 0x5A, 0xE4, 0x18, 0xF6, 0xED, 0x66, 0x05, 0x3D, 0x2B, 0x61, 0xDC, 0xDD, 0x5E, 0xF6, 0x6A, 0xE8, 0xE9, 0x08, 0x3B, 0x1D, 0xA1, 0x4F, 0x1C, 0x5C, 0xD9, 0x06, 0xA1, 0x46, 0xF0, 0x6D, 0x21, 0x74, 0x1F, 0x05, 0x7F, 0x42, 0x21, 0x70, 0xB1, 0xDA, 0x77, 0xF7, 0x77, 0x06, 0x80, 0xEC, 0x2D, 0xCA, 0xED, 0xF5, 0x95, 0xCB, 0xDF, 0x28, 0x67, 0x7C, 0x51, 0x8E, 0xBC, 0x0F, 0xC4, 0x40, 0xDF, 0xB1, 0x60, 0x92, 0x02, 0x81, 0x9F, 0xA0, 0xDC, 0x40, 0xBD, 0xE1, 0x3E, 0x31, 0x60, 0x6F, 0xA0, 0xBF, 0xC6, 0xEB, 0x1E, 0x34, 0x78, 0xA8, 0x53, 0xD6, 0x33, 0x12, 0xFC, 0x97, 0x43, 0x5B, 0x3B, 0x18, 0x7F, 0x10, 0x7C, 0x5C, 0x20, 0xE5, 0xBE, 0x66, 0x11, 0x5C, 0xAA, 0x09, 0xFE, 0x65, 0xE1, 0xAF, 0x2B, 0xB4, 0xB3, 0x57, 0xF9, 0x1E, 0xF7, 0x94, 0xB9, 0x0B, 0x51, 0xC7, 0x51, 0x41, 0xB9, 0xB9, 0xBD, 0x72, 0x61, 0x92, 0x72, 0x62, 0xBC, 0x72, 0xC0, 0x7C, 0x65, 0xE7, 0x2A, 0xA0, 0xB7, 0x11, 0xDA, 0x9C, 0x07, 0xF3, 0x8B, 0xBA, 0xF1, 0x8D, 0xEB, 0x82, 0x6D, 0x91, 0x6E, 0xA3, 0x06, 0x3F, 0xC1, 0x65, 0x1F, 0xD4, 0x5D, 0x06, 0x3E, 0x9B, 0xA0, 0xBE, 0x2F, 0x8C, 0xB6, 0x87, 0x7A, 0x0D, 0x61, 0x83, 0x99, 0xE6, 0x34, 0xB8, 0xD0, 0x0C, 0xDC, 0x35, 0x25, 0xB7, 0x41, 0x9E, 0xB2, 0x5E, 0x8C, 0x72, 0x6F, 0x0E, 0x00, 0x64, 0xAE, 0x53, 0x26, 0x8F, 0x53, 0xC6, 0x0E, 0x51, 0x8E, 0x74, 0x52, 0x76, 0x9B, 0xA5, 0xF4, 0x2A, 0xAF, 0xF3, 0x5A, 0xAC, 0x57, 0x1F, 0xF4, 0x6B, 0xB1, 0xB8, 0xC6, 0x33, 0x28, 0xFD, 0x0C, 0xAA, 0xCD, 0x06, 0xC7, 0x8D, 0x50, 0xE5, 0x2C, 0x78, 0x5D, 0xD5, 0x8C, 0x81, 0xD1, 0x3F, 0xC1, 0x6E, 0x2C, 0x6C, 0xD9, 0xA6, 0xF9, 0x06, 0x2E, 0x0F, 0x81, 0x2A, 0x32, 0x87, 0x2A, 0x0D, 0x95, 0x6E, 0xAA, 0xFC, 0xCA, 0x76, 0xCA, 0xAC, 0x54, 0xE3, 0xA9, 0x00, 0x69, 0x2B, 0x8C, 0xDF, 0x8B, 0x89, 0x6B, 0x4C, 0x86, 0x88, 0x53, 0xAD, 0x4C, 0xF7, 0x8B, 0x03, 0x4E, 0x18, 0xCC, 0x17, 0xFD, 0x82, 0x8C, 0xEA, 0x88, 0xEE, 0x5F, 0xD8, 0x2C, 0x3A, 0x5C, 0x05, 0x00, 0xEB, 0xE6, 0x60, 0x7C, 0x07, 0x4A, 0x6B, 0x56, 0xDB, 0x0D, 0xE6, 0x29, 0xE0, 0x1B, 0x08, 0x66, 0xA6, 0x30, 0xE5, 0x10, 0x18, 0x1E, 0x82, 0x3D, 0xFB, 0x41, 0xFF, 0x2F, 0xDC, 0xAE, 0xA8, 0xD9, 0x12, 0x7E, 0x16, 0x69, 0xE6, 0xAB, 0x7C, 0xA3, 0x71, 0xCA, 0x3D, 0xCF, 0xCA, 0x9B, 0x03, 0xEC, 0xF8, 0x52, 0xE1, 0xBA, 0x38, 0x7F, 0x70, 0x65, 0x77, 0x71, 0xF4, 0x6B, 0xDB, 0xDF, 0x62, 0xB7, 0xAC, 0xB2, 0xD5, 0x45, 0x8F, 0xB7, 0x26, 0x7F, 0x44, 0x97, 0x21, 0x06, 0xD5, 0xC4, 0x72, 0xB6, 0x3A, 0x87, 0x44, 0x00, 0x00, 0xD0, 0x31, 0x75, 0x6C, 0x21, 0x82, 0xEF, 0x37, 0xE4, 0xE3, 0x8E, 0x53, 0x9C, 0x45, 0x5E, 0xEC, 0x69, 0x23, 0xC0, 0x8D, 0xDF, 0xCA, 0x7F, 0xE6, 0x28, 0xFF, 0x29, 0xC5, 0xED, 0x53, 0x6B, 0x1D, 0x01, 0x58, 0xDB, 0xC2, 0xE5, 0x95, 0x38, 0x63, 0x76, 0x6D, 0x6B, 0x71, 0xA8, 0x91, 0xFD, 0x5F, 0xD1, 0x7F, 0xB6, 0x9D, 0x85, 0xE8, 0xEE, 0x6F, 0xDD, 0x44, 0xAC, 0x32, 0xD3, 0xF2, 0x93, 0x68, 0xD0, 0xC1, 0xEA, 0xA9, 0x08, 0xC6, 0xFD, 0x2C, 0xC6, 0x88, 0x06, 0x27, 0x6B, 0x07, 0x89, 0xFA, 0xC3, 0xFD, 0x9A, 0x21, 0xF6, 0x9E, 0x68, 0x2A, 0x1A, 0xBC, 0xDA, 0x16, 0x27, 0xEA, 0xAD, 0x38, 0x3F, 0x4B, 0x34, 0x18, 0xA1, 0xF2, 0x41, 0xA9, 0x4C, 0x1E, 0xD1, 0xC4, 0x00, 0x60, 0xD9, 0xCE, 0xE6, 0x2F, 0xC4, 0x09, 0xD7, 0x1A, 0x7D, 0x15, 0x7B, 0x0F, 0x72, 0xBD, 0x2F, 0x7A, 0xBE, 0xAD, 0x61, 0x2A, 0x3A, 0xE7, 0xD9, 0x6F, 0x15, 0xAD, 0x36, 0x54, 0x5B, 0x26, 0x42, 0xF5, 0x71, 0xBA, 0x47, 0x45, 0xBB, 0xA5, 0x56, 0xF3, 0xC4, 0xB2, 0x3D, 0x1B, 0xF6, 0x14, 0xAD, 0x2E, 0x77, 0xB9, 0x24, 0x5A, 0xE8, 0x4F, 0x14, 0xB0, 0xAC, 0x92, 0xF8, 0x4C, 0xB4, 0x2A, 0x93, 0xFF, 0x0F, 0x31, 0xFD, 0x5F, 0x05, 0xD1, 0x54, 0xD5, 0x85, 0x18, 0x1C, 0x17, 0x97, 0x5F, 0x69, 0x7F, 0x19, 0x60, 0xAE, 0x91, 0x5F, 0x3F, 0x31, 0xCC, 0xC5, 0xA3, 0xBB, 0x18, 0x18, 0xD4, 0x74, 0x8C, 0xD8, 0x64, 0x73, 0x43, 0x33, 0xB1, 0xCA, 0xA9, 0x86, 0xAF, 0x45, 0xBD, 0x93, 0xCD, 0xA3, 0x44, 0x68, 0x1C, 0x63, 0xF6, 0x43, 0x74, 0x2B, 0xB4, 0x33, 0x12, 0x9D, 0xB7, 0x78, 0x08, 0xD4, 0x2A, 0xE9, 0xDF, 0x51, 0x74, 0x74, 0x1D, 0x9D, 0x8C, 0x78, 0x35, 0xD5, 0x1E, 0xF1, 0x97, 0x3A, 0x8E, 0x1A, 0xAB, 0xFF, 0x64, 0x8B, 0x95, 0x32, 0x25, 0x1F, 0xCA, 0x9A, 0x89, 0x8B, 0x3E, 0x75, 0xCB, 0x06, 0x98, 0xF4, 0xA7, 0xDB, 0x23, 0xB1, 0x6F, 0x8D, 0x4E, 0xD5, 0x44, 0x9F, 0xB2, 0xAA, 0xBB, 0x53, 0xA7, 0x42, 0xFB, 0x2E, 0x62, 0x99, 0x79, 0x81, 0x4B, 0x44, 0xE8, 0x1A, 0x61, 0x64, 0x29, 0x06, 0x96, 0x94, 0xBD, 0x2E, 0xFA, 0xB7, 0xA9, 0x3D, 0x49, 0xF4, 0xF3, 0x6E, 0x7B, 0x43, 0x6C, 0x5F, 0x6D, 0x58, 0x35, 0xB1, 0xC3, 0xE8, 0x28, 0x33, 0x35, 0x59, 0x4B, 0xEB, 0x2C, 0xFA, 0x5C, 0x3A, 0x75, 0x51, 0x0C, 0x6C, 0xFE, 0xE7, 0xAB, 0xD8, 0xE4, 0xFF, 0xEA, 0xD7, 0x35, 0x16, 0xE3, 0x0E, 0xAB, 0xFE, 0x4F, 0xE4, 0x92, 0xD0, 0x26, 0x62, 0x90, 0x53, 0xEF, 0xB1, 0x62, 0x0B, 0x9B, 0x90, 0x23, 0xA2, 0xC3, 0xD2, 0xC1, 0xFD, 0x44, 0x18, 0xD1, 0x84, 0x6F, 0x86, 0x26, 0x30, 0xDA, 0xBC, 0xCC, 0x41, 0x80, 0x31, 0x9B, 0xAA, 0x99, 0x8A, 0xE3, 0xFD, 0x1A, 0x3C, 0x10, 0x27, 0xF4, 0xEA, 0x2A, 0x30, 0xF1, 0xC6, 0xC4, 0x1B, 0xE2, 0xCC, 0x15, 0x1B, 0xFE, 0x89, 0x71, 0xB5, 0x53, 0x6A, 0x8B, 0x0B, 0x1D, 0x7E, 0x6C, 0x12, 0xE7, 0x8F, 0x54, 0xF9, 0x13, 0xAF, 0x29, 0x03, 0xB3, 0xC5, 0x29, 0xF6, 0x63, 0x8F, 0x01, 0x0C, 0xA8, 0x3E, 0xD2, 0x58, 0xEC, 0x50, 0x38, 0xAA, 0x58, 0xAC, 0x6B, 0x18, 0x33, 0x57, 0x2C, 0x97, 0x35, 0x67, 0x06, 0xE8, 0xC4, 0x41, 0x42, 0x86, 0xF5, 0x0F, 0xFC, 0x61, 0x4D, 0x81, 0xF3, 0x10, 0x80, 0x2D, 0xD1, 0x6D, 0xA3, 0xC5, 0xD4, 0x40, 0x35, 0x07, 0x4A, 0x8F, 0x0E, 0x4F, 0x14, 0x73, 0x76, 0x8F, 0xDB, 0x2D, 0x9E, 0xA9, 0x95, 0xBA, 0x53, 0x3C, 0x17, 0xA3, 0x9E, 0x8F, 0xAB, 0xF7, 0x7E, 0x3D, 0x41, 0xFC, 0xA1, 0xF2, 0xF3, 0xBC, 0x94, 0xF3, 0xAA, 0x8B, 0x51, 0xCF, 0x67, 0xBE, 0x04, 0xE8, 0x5E, 0x25, 0xD6, 0x5F, 0x6C, 0x75, 0x6E, 0x89, 0x8D, 0xE8, 0x54, 0xBC, 0xCE, 0x4D, 0x84, 0xED, 0xF6, 0x66, 0x17, 0x4B, 0x87, 0x40, 0xF6, 0x0A, 0xA7, 0x33, 0x00, 0x7B, 0xFD, 0x9A, 0x3F, 0x15, 0x73, 0x43, 0xBB, 0x54, 0x15, 0x0F, 0x96, 0xEF, 0x33, 0x49, 0x3C, 0xBD, 0x6A, 0xCC, 0x15, 0xF1, 0x92, 0xF3, 0x62, 0x67, 0xF1, 0x56, 0xCD, 0xDD, 0xA9, 0x62, 0xD1, 0x9B, 0x43, 0x45, 0xE2, 0xB3, 0x43, 0x17, 0x3C, 0xC5, 0xAF, 0xC3, 0x54, 0xFE, 0xAF, 0x76, 0xCA, 0x8B, 0x0D, 0xC4, 0xC1, 0x53, 0x13, 0xBD, 0x00, 0x3A, 0x2D, 0xDD, 0x30, 0x4C, 0x6C, 0x12, 0xBF, 0x7B, 0xA2, 0x68, 0xE4, 0x29, 0x1D, 0x1A, 0xDB, 0x43, 0x90, 0xB9, 0xAF, 0x52, 0x2D, 0x63, 0x6F, 0xC8, 0x31, 0xA8, 0x37, 0x16, 0x60, 0x6F, 0x89, 0x97, 0x91, 0x98, 0x9B, 0x1C, 0x34, 0x5D, 0x3C, 0xF0, 0x3B, 0xE4, 0xBB, 0x78, 0x6A, 0xC3, 0xA8, 0xE6, 0xE2, 0xF9, 0x77, 0xF3, 0xBC, 0xC5, 0xAB, 0x97, 0x57, 0x34, 0x15, 0xEF, 0x8C, 0xDF, 0x6B, 0x25, 0xDE, 0x7B, 0xA5, 0x1E, 0x97, 0x77, 0x3E, 0xEF, 0x7C, 0xC4, 0xAF, 0xEA, 0x38, 0xF8, 0x39, 0x47, 0x89, 0x1B, 0x21, 0xCC, 0x27, 0x97, 0xFF, 0x74, 0xFE, 0x0F, 0x82, 0xE0, 0x01, 0x58, 0xA8, 0x00, 0x00, 0x00, 0xD8, 0x3D, 0xDB, 0xB6, 0xB3, 0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0xED, 0x0E, 0xD9, 0xB6, 0x6D, 0xDB, 0xB6, 0xED, 0xFE, 0x26, 0x02, 0x45, 0x80, 0x4E, 0xC0, 0x7C, 0xE0, 0x24, 0xF0, 0x1D, 0x4C, 0xC0, 0x6A, 0xE0, 0x10, 0x70, 0x1D, 0x78, 0x07, 0x22, 0xA0, 0xDC, 0x50, 0x4B, 0x68, 0x3A, 0x74, 0x10, 0x7A, 0x07, 0xDB, 0x70, 0x39, 0xB8, 0x0F, 0xBC, 0x0C, 0xBE, 0x82, 0x00, 0x48, 0x66, 0xA4, 0x21, 0x32, 0x1E, 0xD9, 0x89, 0x3C, 0x47, 0x65, 0xB4, 0x18, 0xDA, 0x05, 0x5D, 0x84, 0x9E, 0x41, 0x7F, 0x61, 0x69, 0xB0, 0x5A, 0xD8, 0x70, 0x6C, 0x23, 0x76, 0x1F, 0x67, 0xF0, 0xFC, 0x78, 0x5B, 0x7C, 0x36, 0x7E, 0x14, 0xFF, 0x4C, 0x04, 0x44, 0x65, 0x62, 0x20, 0xB1, 0x9A, 0xB8, 0x49, 0x62, 0x64, 0x4E, 0xB2, 0x39, 0x39, 0x95, 0xDC, 0x4F, 0xBE, 0xA5, 0x2C, 0xAA, 0x2C, 0xD5, 0x9B, 0x5A, 0x4A, 0x5D, 0xA6, 0x01, 0x3A, 0x33, 0xDD, 0x90, 0x1E, 0x4F, 0xEF, 0xA4, 0x9F, 0x33, 0x0A, 0x53, 0x9C, 0xE9, 0xCA, 0x2C, 0x66, 0xCE, 0x32, 0xBF, 0xD9, 0xB4, 0x6C, 0x1D, 0x76, 0x14, 0xBB, 0x85, 0x7D, 0xC4, 0xF1, 0x5C, 0x21, 0xAE, 0x03, 0x37, 0x8F, 0x3B, 0xC1, 0x7D, 0xE7, 0x13, 0xBE, 0x3A, 0x3F, 0x94, 0x5F, 0xCF, 0xDF, 0x15, 0x68, 0x21, 0x9F, 0xD0, 0x46, 0x98, 0x25, 0x1C, 0x11, 0x3E, 0x89, 0x81, 0x58, 0x59, 0x1C, 0x28, 0xAE, 0x16, 0x6F, 0x4A, 0xB8, 0x94, 0x4B, 0x6A, 0x21, 0x4D, 0x93, 0x0E, 0x48, 0xEF, 0x65, 0x47, 0x2E, 0x2F, 0xF7, 0x95, 0x57, 0xC8, 0xD7, 0x14, 0x58, 0xC9, 0xA6, 0x34, 0x55, 0x26, 0x2B, 0x7B, 0x95, 0xD7, 0xAA, 0xA9, 0x96, 0x51, 0x7B, 0xA9, 0x4B, 0xD5, 0xCB, 0x1A, 0xAC, 0x15, 0xD5, 0x86, 0x68, 0xFB, 0xB4, 0xBF, 0x7A, 0x7E, 0xBD, 0xAF, 0xBE, 0x43, 0xFF, 0x66, 0xE4, 0x30, 0xBA, 0x1B, 0x1B, 0x8D, 0x0F, 0x66, 0x26, 0xB3, 0xA3, 0xB9, 0xDA, 0x7C, 0x65, 0xA5, 0xB1, 0x5A, 0x5B, 0x4B, 0xAD, 0x27, 0x76, 0x68, 0x37, 0xB5, 0x17, 0xDB, 0xF7, 0x1C, 0xDB, 0xA9, 0xEF, 0xCC, 0x75, 0x6E, 0xB8, 0xAA, 0x5B, 0xD3, 0x9D, 0xEE, 0x5E, 0xF2, 0x04, 0xAF, 0xB2, 0x37, 0xC9, 0x3B, 0xEB, 0x53, 0x7E, 0x39, 0x7F, 0xAC, 0x7F, 0x3C, 0x40, 0x83, 0x92, 0xC1, 0x88, 0xE0, 0x50, 0x08, 0x84, 0x45, 0xC2, 0xC1, 0xE1, 0xBE, 0xF0, 0x4F, 0x94, 0x3F, 0xEA, 0x17, 0xED, 0x8C, 0x7E, 0xC4, 0xB9, 0xE3, 0x5E, 0xF1, 0xD6, 0xF8, 0x4B, 0x92, 0x3D, 0xE9, 0x96, 0x6C, 0x4C, 0x52, 0xD8, 0x3A, 0x07, 0xE8, 0xBA, 0xFA, 0x00, 0x4E, 0x36, 0x66, 0x1B, 0x9B, 0x8D, 0x6D, 0xA7, 0xB1, 0x6D, 0xDB, 0xB6, 0xCD, 0xC6, 0x36, 0x1B, 0x37, 0xB6, 0x6D, 0x3B, 0x69, 0x6C, 0xDB, 0xF6, 0xDE, 0xFD, 0xF6, 0x60, 0xF5, 0x7F, 0x47, 0xEF, 0xD8, 0x33, 0xBF, 0xB9, 0xBA, 0x26, 0xA3, 0x27, 0xB3, 0x25, 0xAB, 0x24, 0x3B, 0x27, 0xA7, 0x26, 0xB7, 0x24, 0x2F, 0x25, 0x3F, 0xA6, 0xA0, 0xA0, 0x30, 0xA3, 0xF8, 0x4B, 0x71, 0x40, 0x49, 0x42, 0x69, 0x4C, 0x59, 0x40, 0xB9, 0x4B, 0x45, 0x44, 0x65, 0x40, 0x95, 0x4B, 0xB5, 0x4D, 0x4D, 0x40, 0xAD, 0x4B, 0xFD, 0x87, 0x7A, 0x83, 0x06, 0x8F, 0x46, 0x9B, 0x26, 0x8B, 0x66, 0x8D, 0x16, 0x87, 0x56, 0x8B, 0x36, 0x83, 0x76, 0x95, 0x0E, 0x8B, 0x4E, 0x83, 0x2E, 0x9D, 0x6E, 0x99, 0x1E, 0x93, 0x5E, 0x9D, 0x3E, 0x8D, 0x7E, 0x89, 0x01, 0x83, 0x41, 0x8D, 0x21, 0x95, 0x61, 0x89, 0x11, 0x9D, 0x51, 0x95, 0x31, 0x85, 0x71, 0x91, 0x09, 0x9D, 0x49, 0x95, 0x29, 0x85, 0x69, 0x91, 0x19, 0x9D, 0x59, 0x95, 0x39, 0x85, 0x79, 0x89, 0x05, 0x83, 0x45, 0x8D, 0x25, 0x95, 0x65, 0x89, 0x15, 0x93, 0x55, 0x9D, 0x35, 0x8D, 0x75, 0x99, 0x0D, 0x8B, 0x4D, 0x83, 0x2D, 0x93, 0x6D, 0x97, 0x9D, 0x92, 0xDD, 0x9E, 0xBD, 0x99, 0xFD, 0x93, 0x43, 0x84, 0x23, 0x8A, 0x63, 0x9E, 0x13, 0x9B, 0xD3, 0x80, 0xB3, 0x84, 0xF3, 0x8A, 0x8B, 0x9D, 0xCB, 0x97, 0x6B, 0x90, 0xFB, 0x3B, 0xB7, 0x32, 0x77, 0x26, 0xF7, 0xDE, 0x2F, 0xAA, 0x5F, 0x8E, 0xBF, 0xDA, 0x78, 0x40, 0x78, 0x24, 0x78, 0xE2, 0x78, 0x96, 0x79, 0x09, 0x79, 0xCD, 0x79, 0xAB, 0x79, 0x9F, 0xF8, 0xF8, 0xF8, 0x42, 0xF9, 0xA6, 0xF9, 0x31, 0xF8, 0xF5, 0xF8, 0x8B, 0xF9, 0xAF, 0x04, 0x38, 0x04, 0xFC, 0x05, 0x46, 0x04, 0x11, 0x05, 0x35, 0x04, 0xF3, 0x04, 0x4F, 0x84, 0x98, 0x84, 0x3C, 0x85, 0xFA, 0x85, 0xE1, 0x84, 0x95, 0x85, 0xB3, 0x85, 0x0F, 0x44, 0xE8, 0x44, 0xDC, 0x44, 0xBA, 0x45, 0xA1, 0x45, 0x15, 0x44, 0x33, 0x44, 0xF7, 0xC4, 0x68, 0xC4, 0x5C, 0xC4, 0xBA, 0xC4, 0xA1, 0xC4, 0xE5, 0xC5, 0xD3, 0xC5, 0xF7, 0x24, 0x68, 0x24, 0x5C, 0x24, 0xBA, 0x24, 0xA1, 0x25, 0x15, 0x24, 0x33, 0x25, 0xF7, 0xA5, 0x68, 0xA5, 0xDC, 0xA4, 0x7A, 0xA5, 0x61, 0xA5, 0x95, 0xA5, 0xB3, 0xA5, 0x8F, 0x64, 0x18, 0x65, 0xBC, 0x64, 0x06, 0x65, 0x7F, 0xC8, 0xAA, 0xCB, 0xE6, 0xCB, 0x9E, 0xCB, 0xB1, 0xC9, 0xF9, 0xCB, 0x8D, 0xC9, 0xA3, 0xC9, 0xEB, 0xC9, 0x97, 0xCA, 0xDF, 0x29, 0xF0, 0x2A, 0x84, 0x29, 0xCC, 0x29, 0xE2, 0x29, 0x9A, 0x29, 0xD6, 0x29, 0xBE, 0x2B, 0x89, 0x29, 0xC5, 0x2B, 0xAD, 0x2B, 0x93, 0x29, 0x3B, 0x28, 0x77, 0xA8, 0x40, 0xAA, 0x28, 0xA8, 0x64, 0xA9, 0x1C, 0xAA, 0x32, 0xAA, 0x7A, 0xA9, 0x0E, 0xA9, 0x21, 0xA9, 0x69, 0xA9, 0xFD, 0x55, 0xBB, 0x51, 0xE7, 0x56, 0x0F, 0x51, 0x9F, 0xD5, 0xC0, 0xD1, 0x30, 0xD5, 0xA8, 0xD5, 0x78, 0xD3, 0x14, 0xD5, 0x8C, 0xD7, 0x5C, 0xD3, 0x22, 0xD1, 0x32, 0xD3, 0x2A, 0xD7, 0xBA, 0xD2, 0x66, 0xD6, 0x76, 0xD3, 0x6E, 0xD7, 0xFE, 0xD2, 0x11, 0xD2, 0x09, 0xD5, 0x19, 0xD7, 0x45, 0xD0, 0x55, 0xD2, 0x4D, 0xD5, 0x5D, 0xD3, 0x23, 0xD0, 0x33, 0xD2, 0x2B, 0xD6, 0x3B, 0xD3, 0xA7, 0xD7, 0x77, 0xD2, 0x6F, 0xD6, 0x7F, 0x33, 0xE0, 0x33, 0x08, 0x36, 0x18, 0x31, 0x84, 0x37, 0x94, 0x37, 0x4C, 0x32, 0x5C, 0x36, 0xC2, 0x35, 0x32, 0x30, 0x2A, 0x32, 0x3A, 0x31, 0xA6, 0x35, 0x76, 0x30, 0x6E, 0x32, 0x7E, 0x35, 0xE1, 0x35, 0x09, 0x34, 0x19, 0x36, 0x85, 0x33, 0x95, 0x33, 0x4D, 0x34, 0x5D, 0x36, 0xC3, 0x35, 0xD3, 0x37, 0x2B, 0x32, 0x3B, 0x31, 0xA7, 0x35, 0x77, 0x30, 0x6F, 0x32, 0x7F, 0xB5, 0xE0, 0xB5, 0x08, 0xB4, 0x18, 0xB6, 0x84, 0xB3, 0x94, 0xB3, 0x4C, 0xB4, 0x5C, 0xB6, 0xC2, 0xB5, 0xD2, 0xB7, 0x2A, 0xB4, 0x3A, 0xB6, 0xA6, 0xB5, 0x76, 0xB0, 0x6E, 0xB4, 0x7E, 0xB1, 0xE1, 0xB5, 0x09, 0xB4, 0x19, 0xB2, 0x85, 0xB5, 0x95, 0xB3, 0x4D, 0xB4, 0x5D, 0xB2, 0xC3, 0xB1, 0xD3, 0xB3, 0x2B, 0xB4, 0x3B, 0xB6, 0xA7, 0xB1, 0xB7, 0xB7, 0x6F, 0xB4, 0x7F, 0x71, 0xE0, 0x71, 0x08, 0x70, 0x18, 0x74, 0x84, 0x75, 0x94, 0x75, 0x4C, 0x70, 0x5C, 0x74, 0xC2, 0x71, 0xD2, 0x73, 0x2A, 0x70, 0x3A, 0x72, 0xA6, 0x71, 0xB6, 0x77, 0x6E, 0x70, 0x7E, 0x71, 0xE1, 0x71, 0x09, 0x70, 0x19, 0x74, 0x85, 0x75, 0x95, 0x75, 0x4D, 0x70, 0x5D, 0x72, 0xC3, 0x71, 0xD3, 0x73, 0x2B, 0x70, 0x3B, 0x76, 0xA7, 0x71, 0xB7, 0x77, 0x6F, 0x74, 0x7F, 0xF1, 0xE0, 0xF1, 0x08, 0xF0, 0x18, 0xF2, 0x84, 0xF5, 0x94, 0xF5, 0x4C, 0xF4, 0x5C, 0xF2, 0xC2, 0xF1, 0xD2, 0xF7, 0x2A, 0xF4, 0x3A, 0xF6, 0xA6, 0xF5, 0x76, 0xF0, 0x6E, 0xF4, 0x7E, 0xF5, 0xE1, 0xF1, 0x09, 0xF0, 0x19, 0xF0, 0x85, 0xF2, 0x95, 0xF2, 0x8D, 0xF1, 0x9D, 0xF5, 0x43, 0xF5, 0x53, 0xF7, 0xCB, 0xF4, 0xDB, 0xF4, 0x27, 0xF2, 0x37, 0xF1, 0x2F, 0xF1, 0x3F, 0x0B, 0xA0, 0x0B, 0x70, 0x0C, 0x68, 0x0C, 0x78, 0x0E, 0xE4, 0x0E, 0xF4, 0x0D, 0xEC, 0x0D, 0x02, 0x0F, 0x12, 0x0B, 0x8A, 0x08, 0x9A, 0x0C, 0x46, 0x08, 0x56, 0x0C, 0x4E, 0x0E, 0x5E, 0xFE, 0x8D, 0xF3, 0x5B, 0xF7, 0x77, 0xEE, 0xEF, 0xBD, 0x10, 0xB2, 0x10, 0xF3, 0x90, 0xF2, 0x90, 0xCB, 0x50, 0x86, 0x50, 0xA7, 0xD0, 0xC6, 0xD0, 0xE7, 0x30, 0xAE, 0x30, 0x9F, 0xB0, 0xEE, 0x70, 0xD0, 0x70, 0xE1, 0xF0, 0x90, 0xF0, 0xD1, 0x08, 0xB8, 0x08, 0x99, 0x88, 0xD8, 0x88, 0xB9, 0x48, 0xD4, 0x48, 0xD5, 0xC8, 0xB4, 0xC8, 0xD5, 0x28, 0xDC, 0x28, 0xBD, 0xA8, 0xBC, 0xA8, 0xBD, 0x68, 0xD2, 0x68, 0xB3, 0xE8, 0xD2, 0xE8, 0xB3, 0x18, 0xDA, 0x18, 0xDB, 0x98, 0x9A, 0x98, 0xDB, 0x58, 0x96, 0x58, 0xD7, 0xD8, 0x96, 0xD8, 0x97, 0x38, 0xEE, 0x38, 0x9F, 0xB8, 0xAE, 0xF8, 0x6F, 0xF1, 0x82, 0xF1, 0x41, 0xF1, 0x83, 0x09, 0x90, 0x09, 0xE2, 0x09, 0xE1, 0x09, 0xE3, 0x89, 0xF0, 0x89, 0x32, 0x89, 0xB1, 0x89, 0x33, 0x49, 0x48, 0x49, 0x4A, 0x49, 0x49, 0x49, 0x0B, 0xC9, 0xE8, 0xC9, 0xEA, 0xC9, 0xE9, 0xC9, 0xAB, 0x29, 0x38, 0x29, 0xDA, 0x29, 0xD9, 0x29, 0x9B, 0xA9, 0x04, 0xA9, 0xFA, 0xA9, 0x79, 0xA9, 0xBB, 0x69, 0x44, 0x69, 0x46, 0x69, 0x85, 0x69, 0x07, 0xE9, 0x64, 0xE9, 0xA6, 0xE9, 0xC5, 0xE9, 0xC7, 0x19, 0x14, 0x19, 0x16, 0x19, 0xA5, 0x19, 0xA7, 0x99, 0x54, 0x99, 0x56, 0x99, 0xE5, 0x99, 0xE7, 0x59, 0x34, 0x59, 0x36, 0x59, 0x95, 0x59, 0x17, 0xD9, 0x74, 0xD9, 0xB6, 0xD9, 0x55, 0xD9, 0x57, 0x7F, 0x98, 0xFE, 0xB8, 0xFF, 0xE9, 0xCC, 0x01, 0xCB, 0x91, 0xC8, 0x89, 0xC9, 0x99, 0xCF, 0xC5, 0xCA, 0xD5, 0xCD, 0x2D, 0xCC, 0x3D, 0xC9, 0xA3, 0xCB, 0x73, 0xCE, 0x6B, 0xCD, 0xFB, 0xCC, 0x17, 0xCE, 0x0F, 0xCF, 0x9F, 0x2A, 0x40, 0x29, 0x50, 0x2F, 0xF8, 0x53, 0xB0, 0x57, 0x48, 0x51, 0x68, 0x53, 0x58, 0x57, 0xF8, 0x54, 0xF4, 0xAB, 0x28, 0xA0, 0x68, 0xE8, 0x2F, 0xDC, 0x5F, 0xF9, 0xBF, 0xC9, 0x7F, 0x57, 0x8B, 0xF1, 0x8B, 0x8D, 0x8A, 0x4B, 0x8A, 0x2F, 0x4A, 0x98, 0x4A, 0x5C, 0x4B, 0xDA, 0x4B, 0xBF, 0x95, 0x0A, 0x97, 0x86, 0x97, 0x4E, 0x95, 0x21, 0x97, 0xA9, 0x95, 0x65, 0x96, 0x6D, 0x97, 0x93, 0x94, 0x5B, 0x94, 0x57, 0x96, 0xDF, 0x56, 0xB0, 0x55, 0x78, 0x55, 0x74, 0x57, 0x82, 0x57, 0x8A, 0x57, 0x46, 0x57, 0xCE, 0x56, 0xA1, 0x57, 0x69, 0x56, 0xE5, 0x54, 0xED, 0x55, 0x53, 0x54, 0x5B, 0x57, 0xD7, 0x56, 0x3F, 0xD4, 0x70, 0xD5, 0xF8, 0xD6, 0xF4, 0xD7, 0x42, 0xD5, 0x4A, 0xD7, 0xC6, 0xD5, 0x2E, 0xD4, 0x61, 0xD5, 0xE9, 0xD6, 0xE5, 0xD7, 0x1D, 0xD5, 0xD3, 0xD4, 0xDB, 0xD7, 0x37, 0xD6, 0xBF, 0x34, 0xF0, 0x36, 0x04, 0x36, 0x0C, 0x37, 0xC2, 0x35, 0xCA, 0x37, 0x26, 0x35, 0xAE, 0x34, 0xE1, 0x37, 0x19, 0x36, 0x15, 0x37, 0x9D, 0x35, 0x33, 0x34, 0xBB, 0x34, 0xB7, 0x36, 0x7F, 0xB6, 0x08, 0xB6, 0x84, 0xB6, 0x4C, 0xB4, 0x22, 0xB6, 0xAA, 0xB4, 0x66, 0xB4, 0x6E, 0xB5, 0x11, 0xB7, 0x99, 0xB7, 0x55, 0xB6, 0xDD, 0xB4, 0xB3, 0xB5, 0x7B, 0xB5, 0xF7, 0x74, 0x40, 0x74, 0x48, 0x74, 0xC4, 0x74, 0xCC, 0x77, 0x62, 0x76, 0xEA, 0x74, 0xE6, 0x75, 0x1E, 0x76, 0x51, 0x77, 0xD9, 0x77, 0x35, 0x76, 0xBD, 0x76, 0xF3, 0x75, 0x07, 0x77, 0x8F, 0xF6, 0x7C, 0xEF, 0x51, 0xEA, 0xC9, 0xE8, 0xD9, 0xEB, 0xA5, 0xE9, 0x75, 0xE9, 0xED, 0xEA, 0x83, 0xEC, 0x93, 0xEB, 0x4B, 0xEB, 0xDB, 0xE9, 0xA7, 0xEA, 0x77, 0xEA, 0xEF, 0x18, 0x80, 0x18, 0x90, 0x1D, 0x48, 0x1D, 0xD8, 0x1E, 0xA4, 0x1C, 0x74, 0x1C, 0x6C, 0x1F, 0x02, 0x1F, 0x92, 0x19, 0x4A, 0x19, 0xDA, 0x1A, 0xA6, 0x18, 0x76, 0x18, 0x6E, 0x1B, 0x01, 0x1B, 0x91, 0x19, 0x49, 0x19, 0xD9, 0x1A, 0xA5, 0x18, 0x75, 0x18, 0x6D, 0x1B, 0x03, 0x1F, 0x93, 0x19, 0x4B, 0x19, 0xDB, 0x1A, 0xA7, 0x18, 0x77, 0x1C, 0x6F, 0x9F, 0x00, 0x9F, 0x90, 0x99, 0x48, 0x9D, 0xD8, 0x9E, 0xA4, 0x9C, 0x74, 0x9C, 0xEC, 0x98, 0x82, 0x98, 0x92, 0x9D, 0x4A, 0x9D, 0xDA, 0x99, 0xA6, 0x9A, 0x76, 0x9A, 0xEE, 0x98, 0x81, 0x9C, 0x91, 0x9B, 0x49, 0x9B, 0xD9, 0x99, 0xA5, 0x9A, 0x75, 0x9E, 0xED, 0x9C, 0x83, 0x9C, 0x93, 0x9B, 0x4B, 0x9B, 0xDB, 0x99, 0xA7, 0x9E, 0x77, 0x9E, 0xEF, 0xFC, 0x07, 0xF9, 0x4F, 0xEE, 0x5F, 0xDA, 0xBF, 0x9D, 0x05, 0xEA, 0x05, 0xE7, 0x85, 0xCE, 0x45, 0xC8, 0x45, 0xB9, 0xC5, 0xB4, 0xC5, 0x9D, 0x25, 0xAA, 0x25, 0xA7, 0xA5, 0x8E, 0x65, 0xC8, 0x65, 0xB9, 0xE5, 0xB4, 0xE5, 0x9D, 0x15, 0xAA, 0x15, 0xA7, 0x95, 0x8E, 0x55, 0x88, 0x55, 0xD9, 0xD5, 0xB4, 0xD5, 0x9D, 0x35, 0xAA, 0x35, 0xA7, 0xB5, 0x8E, 0x75, 0x88, 0x75, 0xD9, 0xF5, 0xD4, 0xF5, 0xED, 0x0D, 0xAA, 0x0D, 0xA7, 0x8D, 0x8E, 0x4D, 0x88, 0x4D, 0xD9, 0xCD, 0xD4, 0xCD, 0xED, 0x2D, 0xCA, 0x2D, 0xC7, 0xAD, 0xF6, 0x6D, 0x88, 0x6D, 0xD9, 0xED, 0xD4, 0xED, 0xED, 0x1D, 0xCA, 0x1D, 0xC7, 0x9D, 0xF6, 0x5D, 0xF0, 0x5D, 0x99, 0xDD, 0x94, 0xDD, 0xED, 0x3D, 0xCA, 0x3D, 0xC7, 0xBD, 0xF6, 0x7D, 0xF0, 0x7D, 0x99, 0xFD, 0x94, 0xFD, 0xF5, 0x03, 0xCC, 0x03, 0xD9, 0x83, 0xE0, 0x83, 0xB6, 0x83, 0xAB, 0x43, 0xD2, 0x43, 0xAD, 0xC3, 0xF8, 0xC3, 0xE1, 0xC3, 0x8F, 0x23, 0xE6, 0x23, 0x8B, 0xA3, 0x9C, 0xA3, 0x85, 0x63, 0xB8, 0x63, 0x81, 0x63, 0xB7, 0xE3, 0xCA, 0xE3, 0xBD, 0x13, 0xCC, 0x13, 0xD9, 0x93, 0xE0, 0x93, 0xB6, 0x93, 0xEB, 0x53, 0xB2, 0x53, 0xED, 0xD3, 0xC4, 0xD3, 0xD1, 0xD3, 0xAF, 0x33, 0xD6, 0x33, 0xAB, 0xB3, 0xBC, 0xB3, 0xA5, 0xF3, 0xEF, 0xE7, 0x42, 0xE7, 0x1E, 0xE7, 0xD5, 0xE7, 0x07, 0x17, 0x38, 0x17, 0x0A, 0x17, 0xA1, 0x17, 0x5D, 0x17, 0xF7, 0x97, 0x54, 0x97, 0xFA, 0x97, 0x29, 0x97, 0x13, 0x57, 0xA0, 0x57, 0x1C, 0x57, 0x76, 0x57, 0x45, 0x57, 0x6B, 0xD7, 0x48, 0xD7, 0x62, 0xD7, 0x3E, 0xD7, 0xF5, 0xD7, 0xA7, 0x37, 0x84, 0x37, 0xAA, 0x37, 0x51, 0x37, 0x7D, 0x37, 0x2F, 0xB7, 0xF4, 0xB7, 0x26, 0xB7, 0x99, 0xB7, 0x73, 0x77, 0xD0, 0x77, 0xBC, 0x77, 0xCE, 0x77, 0xE5, 0x77, 0x3B, 0xF7, 0x18, 0xF7, 0x32, 0xF7, 0xC1, 0xF7, 0x6D, 0xF7, 0xD7, 0x0F, 0x64, 0x0F, 0x3A, 0x0F, 0x89, 0x0F, 0xA3, 0x8F, 0xDF, 0x1E, 0xD9, 0x1E, 0xAD, 0x1F, 0x0B, 0x1E, 0x57, 0x9E, 0x10, 0x9E, 0x44, 0x9F, 0xBC, 0x9F, 0xEA, 0x9E, 0x4E, 0x9E, 0x09, 0x9E, 0x55, 0x9F, 0xA3, 0x9E, 0xFB, 0x9E, 0x5F, 0x5E, 0xE8, 0x5F, 0x4C, 0x5F, 0xB2, 0x5E, 0xE6, 0x5E, 0x61, 0x5E, 0xF9, 0x5E, 0x5D, 0x5F, 0x2B, 0x5E, 0xF7, 0xDE, 0xB0, 0xDE, 0xE4, 0xDE, 0x42, 0xDE, 0x3A, 0xDE, 0xEE, 0xDE, 0x29, 0xDF, 0xF5, 0xDF, 0x53, 0xDE, 0x27, 0x3F, 0xC0, 0x3E, 0xB8, 0x3E, 0xEC, 0x3F, 0x8A, 0x3F, 0x36, 0x3E, 0x51, 0x3F, 0x25, 0x3F, 0x03, 0x3E, 0x5B, 0x3E, 0x2F, 0xBF, 0x48, 0xBF, 0xB4, 0xBE, 0x12, 0xBE, 0xFE, 0xD7, 0x1B, 0x1F, 0x59, 0xBE, 0x99, 0x7F, 0xCB, 0xFE, 0x36, 0x0B, 0x02, 0x01, 0xC2, 0x09, 0x62, 0x03, 0x92, 0x0F, 0xB2, 0x08, 0x0A, 0x0B, 0xCA, 0x0B, 0xEA, 0x08, 0x5A, 0x0C, 0xBA, 0x06, 0x86, 0x00, 0x26, 0x04, 0xE6, 0x0E, 0x56, 0x01, 0xB6, 0x0D, 0x8E, 0x06, 0x2E, 0x01, 0xEE, 0x03, 0x5E, 0x0B, 0x7E, 0x08, 0x81, 0x0D, 0x21, 0x0B, 0x11, 0x04, 0xD1, 0x0C, 0x71, 0x06, 0x49, 0x08, 0xA9, 0x0C, 0x19, 0x06, 0xD9, 0x09, 0x79, 0x03, 0x45, 0x06, 0xA5, 0x09, 0x15, 0x03, 0xD5, 0x0F, 0xF5, 0x04, 0x4D, 0x03, 0xAD, 0x0F, 0x9D, 0x04, 0x3D, 0x0A, 0xFD, 0x01, 0xC3, 0x04, 0x63, 0x0A, 0x93, 0x09, 0x33, 0x0D, 0x0B, 0x0E, 0xCB, 0x01, 0x6B, 0x0D, 0x9B, 0x07, 0xBB, 0x00, 0x07, 0x0B, 0xC7, 0x0B, 0xE7, 0x04, 0x57, 0x0C, 0xB7, 0x0E, 0x8F, 0x04, 0x2F, 0x02, 0xEF, 0x09, 0x5F, 0x05, 0xBF, 0xF7, 0x1D, 0xE3, 0xBB, 0xF4, 0x77, 0xFF, 0xEF, 0x8D, 0xDF, 0x4F, 0x7F, 0xE0, 0xFF, 0x50, 0xFA, 0x11, 0xFA, 0xA3, 0xE3, 0xC7, 0x0D, 0x02, 0x29, 0x82, 0x26, 0x42, 0x2C, 0x42, 0x3F, 0xC2, 0x33, 0x22, 0x0D, 0xA2, 0x01, 0x62, 0x0A, 0xE2, 0x18, 0xE2, 0x17, 0x12, 0x0B, 0x92, 0x05, 0x52, 0x36, 0xD2, 0x1C, 0x32, 0x14, 0x32, 0x37, 0xB2, 0x3D, 0x72, 0x11, 0x40, 0xF9, 0x1F, 0x28, 0x42, 0x28, 0xEE, 0x28, 0x15, 0x28, 0x3B, 0xA8, 0xE8, 0x00, 0xE3, 0xFD, 0x51, 0x1B, 0x50, 0x4F, 0xD0, 0xF0, 0xD1, 0x94, 0xD0, 0x42, 0xD1, 0x3A, 0xD0, 0x6E, 0xD0, 0xC9, 0xD0, 0xB5, 0xD0, 0xE3, 0xD0, 0x07, 0xD0, 0x5F, 0x30, 0xE8, 0x30, 0x8C, 0x30, 0xD2, 0x30, 0x26, 0x31, 0x41, 0x31, 0xD9, 0x31, 0xAD, 0x30, 0x73, 0x31, 0x17, 0xB0, 0x60, 0xB1, 0xF8, 0xB0, 0x9C, 0xB1, 0x4A, 0xB1, 0x36, 0xB1, 0x51, 0xB0, 0x25, 0xB0, 0x43, 0xB1, 0x07, 0x70, 0x40, 0x71, 0xF8, 0x71, 0x7C, 0x71, 0xDA, 0x71, 0x5E, 0x70, 0xD9, 0x71, 0x5D, 0x70, 0xEB, 0x70, 0xAF, 0xF1, 0xE8, 0xF0, 0xAC, 0xF1, 0xCA, 0xF0, 0x8E, 0xF1, 0x49, 0xF1, 0x8D, 0xF0, 0xF3, 0xF0, 0xB7, 0x08, 0xF0, 0x08, 0xB4, 0x08, 0xD2, 0x09, 0x96, 0x08, 0xD1, 0x08, 0x15, 0x09, 0xE3, 0x08, 0xA7, 0x7E, 0xC2, 0xFF, 0x94, 0xFC, 0x19, 0xF6, 0x73, 0x88, 0x08, 0x82, 0x48, 0x88, 0x28, 0x80, 0xA8, 0x9B, 0xE8, 0x03, 0xA0, 0xBC, 0x07, 0x71, 0x33, 0xF1, 0x23, 0x09, 0x0B, 0x89, 0x23, 0x49, 0x0D, 0xC9, 0x25, 0x29, 0x2D, 0xA9, 0x15, 0x69, 0x29, 0xE9, 0x31, 0x19, 0x19, 0x99, 0x31, 0x59, 0x01, 0xD9, 0x0E, 0x39, 0x01, 0xB9, 0x2E, 0x79, 0x16, 0xF9, 0x1A, 0x05, 0x16, 0x85, 0x1A, 0x45, 0x0A, 0xC5, 0x3F, 0x4A, 0x14, 0x4A, 0x05, 0xCA, 0x38, 0xCA, 0x29, 0xAA, 0xEF, 0x54, 0x52, 0x54, 0x11, 0x54, 0x23, 0xD4, 0x50, 0xD4, 0xA2, 0xD4, 0xC1, 0xD4, 0xFD, 0x34, 0x20, 0x34, 0xFC, 0x34, 0x7E, 0x34, 0x9D, 0x34, 0xEF, 0xB4, 0xDC, 0xB4, 0x1E, 0xB4, 0x2D, 0xB4, 0x4F, 0x74, 0x6C, 0x74, 0xCE, 0x74, 0xF5, 0x74, 0xB7, 0xF4, 0x8C, 0xF4, 0x76, 0xF4, 0x55, 0xF4, 0x17, 0x0C, 0x34, 0x0C, 0x56, 0x0C, 0x65, 0x0C, 0xC7, 0x8C, 0xE4, 0x8C, 0xA6, 0x8C, 0x45, 0x8C, 0xFB, 0x4C, 0xC4, 0x4C, 0x86, 0x4C, 0x79, 0x4C, 0xDB, 0xCC, 0x04, 0xCC, 0xBA, 0xCC, 0xD9, 0xCC, 0xEB, 0x2C, 0x38, 0x2C, 0x9A, 0x2C, 0xE9, 0x2C, 0xCB, 0xAC, 0x18, 0xAC, 0xAA, 0xAC, 0xC9, 0xAC, 0x0B, 0x6C, 0xA8, 0x6C, 0x4A, 0x6C, 0x09, 0x6C, 0xB3, 0xEC, 0x48, 0xEC, 0xF2, 0xEC, 0xB1, 0xEC, 0x53, 0x1C, 0x3F, 0x38, 0x64, 0x00, 0xD2, 0x8F, 0x73, 0xC2, 0x71, 0x4A, 0x72, 0x86, 0x73, 0x0E, 0x73, 0x41, 0x70, 0x09, 0x71, 0x05, 0x70, 0x75, 0x73, 0xBD, 0x73, 0x73, 0x71, 0xBB, 0x73, 0x37, 0x71, 0xDF, 0xFF, 0x62, 0xFA, 0x65, 0xFF, 0xAB, 0xEA, 0xD7, 0x39, 0x0F, 0x15, 0x8F, 0x39, 0xCF, 0x5F, 0x9E, 0x7D, 0x5E, 0x22, 0x5E, 0x03, 0xDE, 0x1C, 0xDE, 0x0D, 0x3E, 0x1C, 0x3E, 0x0D, 0xBE, 0x54, 0xBE, 0x05, 0x7E, 0x54, 0x7E, 0x45, 0xFE, 0x38, 0xFE, 0x29, 0x01, 0x78, 0x01, 0x29, 0x81, 0x70, 0x81, 0x61, 0x41, 0x08, 0x41, 0x61, 0xC1, 0x40, 0xC1, 0x1E, 0xC1, 0x2F, 0x21, 0x1E, 0x21, 0x2F, 0xA1, 0x36, 0xA1, 0x67, 0x61, 0x36, 0x61, 0x17, 0xE1, 0x7A, 0xE1, 0x5B, 0x11, 0x06, 0x11, 0x3B, 0x91, 0x4A, 0x91, 0x73, 0x51, 0x2A, 0x51, 0x0B, 0xD1, 0x62, 0xD1, 0x43, 0x31, 0x12, 0x31, 0x23, 0xB1, 0x3C, 0xB1, 0x6D, 0x71, 0x02, 0x71, 0x1D, 0xF1, 0x2C, 0xF1, 0x55, 0x09, 0x2C, 0x09, 0x75, 0x89, 0x14, 0x89, 0x05, 0x49, 0x54, 0x49, 0x45, 0xC9, 0x78, 0xC9, 0x19, 0x29, 0x04, 0x29, 0x19, 0xA9, 0x28, 0xA9, 0x71, 0x80, 0xFF, 0xE2, 0xD2, 0xA1, 0xD2, 0x43, 0x32, 0x10, 0x32, 0xC2, 0x32, 0x41, 0x32, 0x7D, 0xB2, 0x20, 0xB2, 0x7C, 0xB2, 0xBE, 0xB2, 0x9D, 0xB2, 0xEF, 0x72, 0xDC, 0x72, 0x9E, 0x72, 0xAD, 0x72, 0xCF, 0xF2, 0x1C, 0xF2, 0x6E, 0xF2, 0x4D, 0xF2, 0x0F, 0x0A, 0x2C, 0x0A, 0x4E, 0x0A, 0x75, 0x0A, 0x37, 0x8A, 0x8C, 0x8A, 0xF6, 0x8A, 0xD5, 0x8A, 0x97, 0x4A, 0xB4, 0x4A, 0x36, 0x4A, 0x15, 0x4A, 0x67, 0xCA, 0x54, 0xCA, 0x96, 0xCA, 0xA5, 0xCA, 0xC7, 0x2A, 0x14, 0x2A, 0x66, 0x2A, 0xC5, 0x80, 0x0B, 0x90, 0xAA, 0x9A, 0xA8, 0x16, 0xAA, 0xEE, 0xAB, 0x11, 0xAB, 0x19, 0xA9, 0xE5, 0xAB, 0xED, 0xAA, 0xFF, 0x54, 0x37, 0x50, 0xCF, 0x55, 0xDF, 0x04, 0x7C, 0x40, 0x4D, 0x23, 0x51, 0x63, 0x5A, 0x13, 0x5E, 0x53, 0x5C, 0x33, 0x58, 0xB3, 0x47, 0xF3, 0x5D, 0x8B, 0x43, 0xCB, 0x59, 0xAB, 0x46, 0xEB, 0x5C, 0x9B, 0x42, 0xDB, 0x58, 0x3B, 0x57, 0x7B, 0x5D, 0x07, 0x53, 0x47, 0x59, 0x27, 0x4E, 0x67, 0x42, 0x17, 0x4A, 0x57, 0x48, 0xD7, 0x4F, 0xB7, 0x5D, 0xF7, 0x51, 0x8F, 0x49, 0xCF, 0x56, 0xAF, 0x54, 0xEF, 0x40, 0x9F, 0x50, 0x5F, 0x5B, 0x3F, 0x4D, 0x7F, 0xDE, 0x00, 0xC1, 0x40, 0xD2, 0xE0, 0xB7, 0x41, 0xAF, 0xC1, 0xBB, 0x21, 0x87, 0xA1, 0x93, 0x61, 0x95, 0xE1, 0xA9, 0x11, 0xA9, 0x91, 0xBE, 0x51, 0x96, 0xD1, 0x92, 0x31, 0xB2, 0xB1, 0x8C, 0x71, 0x98, 0xF1, 0x80, 0xF1, 0x97, 0x09, 0x97, 0x89, 0x8B, 0x49, 0x8D, 0xC9, 0x99, 0x29, 0x99, 0xA9, 0xA1, 0x69, 0x36, 0xE0, 0x07, 0x28, 0x66, 0xB2, 0x66, 0xE1, 0x66, 0x03, 0x66, 0x5F, 0xE6, 0x9C, 0xE6, 0xCE, 0xE6, 0xD5, 0xE6, 0xA7, 0x16, 0xA4, 0x16, 0xFA, 0x16, 0x99, 0x16, 0x8B, 0x96, 0x88, 0x96, 0x52, 0x96, 0x21, 0x96, 0xBD, 0x96, 0x6F, 0x56, 0x6C, 0x56, 0x0E, 0x56, 0x15, 0x56, 0x87, 0xD6, 0x3F, 0xAD, 0xB5, 0xAD, 0x53, 0xAC, 0x67, 0x6D, 0xE0, 0x6C, 0x44, 0x6D, 0xFC, 0x6D, 0xDA, 0x6D, 0x1E, 0x6C, 0x19, 0x6C, 0x2D, 0x6D, 0x8B, 0x6C, 0xB7, 0xEC, 0xB0, 0xED, 0x94, 0xED, 0x62, 0xEC, 0x46, 0xED, 0xC1, 0xEC, 0x79, 0xED, 0xDD, 0xED, 0xEB, 0xEC, 0x2F, 0x1C, 0xC8, 0x1D, 0x0C, 0x1C, 0x32, 0x1D, 0x16, 0x1D, 0x11, 0x1D, 0x25, 0x1D, 0x83, 0x1D, 0xBB, 0x1C, 0x9F, 0x9D, 0x98, 0x9D, 0x6C, 0x9C, 0x8A, 0x9D, 0x76, 0x9C, 0x71, 0x9C, 0x55, 0x9C, 0x63, 0x9D, 0x47, 0x5D, 0xC0, 0x00, 0x63, 0x70, 0x73, 0xA9, 0x75, 0x39, 0x75, 0x25, 0x75, 0x35, 0x70, 0xCD, 0x73, 0xDD, 0x71, 0xFB, 0xE9, 0x66, 0xE0, 0x96, 0xEB, 0xB6, 0xED, 0x4E, 0xE8, 0xAE, 0xE7, 0x9E, 0xE3, 0xBE, 0xE5, 0x81, 0xEF, 0xA1, 0xEB, 0xF1, 0xC7, 0x63, 0xC3, 0x13, 0xCF, 0x53, 0xDB, 0x33, 0xCB, 0x73, 0xCD, 0x0B, 0xDB, 0x4B, 0xD3, 0x2B, 0xDD, 0x6B, 0xD9, 0x1B, 0xD3, 0x5B, 0xCD, 0x3B, 0xC5, 0x7B, 0xC1, 0x07, 0xCD, 0x47, 0xD9, 0x27, 0xD1, 0x67, 0xCE, 0x17, 0xC9, 0x57, 0xDE, 0x37, 0xD6, 0x77, 0xCA, 0xEF, 0xBB, 0x9F, 0xB4, 0x5F, 0xA4, 0xDF, 0x98, 0x3F, 0x8C, 0xBF, 0xB8, 0x7F, 0xA8, 0xFF, 0x50, 0x00, 0x78, 0x80, 0x50, 0x40, 0x60, 0x40, 0x6F, 0xC0, 0x57, 0x20, 0x6F, 0xA0, 0x4F, 0x60, 0x7B, 0xE0, 0x6B, 0x10, 0x67, 0x90, 0x5B, 0x50, 0x53, 0xD0, 0x7D, 0x30, 0x73, 0xB0, 0x43, 0x70, 0x75, 0xF0, 0xE5, 0x6F, 0x9A, 0xDF, 0x96, 0xBF, 0x4B, 0x7F, 0x1F, 0x85, 0x90, 0x86, 0x18, 0x85, 0xE4, 0x87, 0x6C, 0x87, 0xE2, 0x87, 0x6A, 0x87, 0x66, 0x84, 0x2E, 0x87, 0xA1, 0x87, 0x29, 0x87, 0x25, 0x84, 0x4D, 0x87, 0x7F, 0x0F, 0x97, 0x0A, 0x0F, 0x0F, 0x1F, 0x8A, 0x00, 0x8F, 0x10, 0x8C, 0xF0, 0x8B, 0xE8, 0x8C, 0x78, 0x8B, 0xE4, 0x88, 0x74, 0x8D, 0xAC, 0x8F, 0xBC, 0x8E, 0xA2, 0x8B, 0xB2, 0x8A, 0x2A, 0x8D, 0x3A, 0x8C, 0x26, 0x8E, 0xD6, 0x8F, 0xCE, 0x8E, 0x5E, 0x8B, 0xC1, 0x8C, 0x51, 0x89, 0x49, 0x88, 0x99, 0x8E, 0x85, 0x8F, 0x95, 0x88, 0x0D, 0x89, 0xED, 0x8F, 0xFB, 0x16, 0xF7, 0x2B, 0xCE, 0x23, 0xAE, 0x29, 0xEE, 0x2E, 0x9E, 0x21, 0xDE, 0x3A, 0xBE, 0x34, 0xFE, 0x20, 0x81, 0x28, 0x41, 0x2F, 0x21, 0x33, 0x61, 0x39, 0x11, 0x35, 0x51, 0x21, 0x31, 0x3A, 0x71, 0x34, 0x09, 0x32, 0x49, 0x30, 0xC9, 0x37, 0xA9, 0x3D, 0xE9, 0x29, 0x99, 0x25, 0xD9, 0x2D, 0xB9, 0x3B, 0x05, 0x3A, 0x45, 0x3E, 0x25, 0x2D, 0x65, 0x3B, 0x95, 0x32, 0xD5, 0x21, 0xB5, 0x35, 0x0D, 0x24, 0x4D, 0x22, 0x2D, 0x3E, 0x6D, 0x25, 0xFD, 0x67, 0xBA, 0x45, 0x7A, 0x6D, 0xFA, 0x4B, 0x06, 0x7F, 0x46, 0x58, 0xC6, 0x4C, 0x26, 0x66, 0xA6, 0x5E, 0x66, 0x71, 0xE6, 0x55, 0x16, 0x5B, 0x96, 0x6F, 0xD6, 0x50, 0xF6, 0xF7, 0x6C, 0x95, 0xEC, 0xAC, 0xEC, 0xBD, 0x3F, 0xD4, 0x7F, 0x1C, 0xFF, 0xB4, 0xE5, 0x80, 0xE4, 0x88, 0xE7, 0xC4, 0xE5, 0x2C, 0xE5, 0xE2, 0xE7, 0x9A, 0xE4, 0x56, 0xE4, 0xDE, 0xE7, 0x71, 0xE7, 0x05, 0xE6, 0x8D, 0xE6, 0x23, 0xE6, 0xAB, 0xE5, 0xFF, 0xC9, 0x3F, 0x28, 0xA0, 0x29, 0x70, 0x2A, 0x68, 0x2B, 0x04, 0x29, 0x14, 0x2F, 0x8C, 0x2D, 0x5C, 0x28, 0xC2, 0x2D, 0x32, 0x2A, 0x2A, 0x2B, 0xBA, 0xF9, 0xCB, 0xF1, 0xD7, 0xF7, 0xEF, 0x60, 0x31, 0x7C, 0xB1, 0x52, 0x71, 0x7A, 0xF1, 0x76, 0x09, 0x79, 0x89, 0x4D, 0x49, 0x43, 0xC9, 0x6B, 0xA9, 0x40, 0x69, 0x18, 0xE0, 0x0E, 0x68, 0x65, 0x5A, 0x65, 0xF9, 0x65, 0xC7, 0xE5, 0xF4, 0xE5, 0x2E, 0xE5, 0xED, 0x15, 0xA0, 0x15, 0xE2, 0x15, 0x31, 0x15, 0x0B, 0x95, 0x38, 0x95, 0x86, 0x95, 0x25, 0x95, 0x97, 0x55, 0xAC, 0x55, 0x5E, 0x55, 0x7D, 0xD5, 0x30, 0xD5, 0x72, 0xD5, 0x29, 0xD5, 0xEB, 0x35, 0xC4, 0x35, 0x96, 0x35, 0x35, 0x35, 0x4F, 0xB5, 0xBC, 0xB5, 0xBF, 0x6B, 0xC7, 0xEB, 0x90, 0xEB, 0x34, 0xEA, 0x72, 0x01, 0x73, 0xA0, 0xAB, 0x77, 0xA9, 0xEF, 0x68, 0x00, 0x6B, 0x90, 0x6C, 0x88, 0x6F, 0x58, 0x6E, 0x24, 0x68, 0x34, 0x6D, 0xAC, 0x6C, 0xBC, 0x6F, 0xE2, 0x6E, 0x0A, 0x6A, 0x1A, 0x6B, 0x46, 0x6A, 0x56, 0x6F, 0xCE, 0x6D, 0x3E, 0x6A, 0xA1, 0x6B, 0x71, 0x6D, 0xE9, 0x6A, 0x85, 0x6F, 0xD5, 0x69, 0xAD, 0x6E, 0xFB, 0xD6, 0xA6, 0xD0, 0x56, 0xD0, 0x76, 0xDF, 0x2E, 0xDA, 0x9E, 0xDA, 0x7E, 0xD2, 0xC1, 0xD5, 0x11, 0xD5, 0xB1, 0xD1, 0x49, 0xDF, 0x19, 0xD0, 0x39, 0xD7, 0x45, 0xD2, 0xE5, 0xDA, 0x35, 0xDC, 0x8D, 0xD5, 0x6D, 0xD5, 0xDD, 0xD9, 0x83, 0xD0, 0x63, 0xD0, 0x53, 0xDF, 0x0B, 0xDE, 0xAB, 0xDA, 0x5B, 0xD2, 0xFB, 0xDA, 0x27, 0xD3, 0x97, 0xD3, 0x77, 0xD3, 0x2F, 0xD4, 0x9F, 0xDC, 0x7F, 0x34, 0xC0, 0x39, 0x10, 0x35, 0xB0, 0x39, 0xC8, 0x30, 0x18, 0x34, 0xB8, 0x30, 0x44, 0x3E, 0xE4, 0x39, 0x34, 0x31, 0x4C, 0x00, 0x98, 0xC2, 0xC0, 0x08, 0xFA, 0x88, 0xC5, 0x48, 0xFB, 0xE8, 0x8F, 0x51, 0x83, 0xD1, 0xFA, 0x31, 0xC8, 0x31, 0x8D, 0xB1, 0x8A, 0xB1, 0xCF, 0x71, 0x85, 0xF1, 0xC2, 0xF1, 0xA7, 0x09, 0xC9, 0x89, 0xEC, 0x89, 0xEB, 0x49, 0xA1, 0xC9, 0x94, 0xC9, 0x93, 0xA9, 0x5F, 0x53, 0x71, 0x53, 0x7B, 0xD3, 0x6C, 0xD3, 0xE1, 0xD3, 0x1B, 0x33, 0x0C, 0x33, 0x41, 0x33, 0x8B, 0x80, 0x21, 0xF8, 0xCC, 0xCE, 0xCE, 0x91, 0xCC, 0xB9, 0xCF, 0x8D, 0xCF, 0x13, 0xCC, 0x3B, 0xCE, 0x0F, 0xFD, 0xC3, 0xFA, 0x67, 0xF3, 0xAF, 0x77, 0x01, 0x75, 0xC1, 0x7C, 0xA1, 0x63, 0x11, 0x61, 0xD1, 0x68, 0xB1, 0x79, 0x09, 0x6E, 0x49, 0x6F, 0xA9, 0x1E, 0x70, 0x03, 0xCD, 0xE5, 0xAA, 0x15, 0xD0, 0x15, 0xD5, 0x95, 0xB2, 0x95, 0xCF, 0x55, 0xC5, 0xD5, 0xBF, 0xAB, 0xAF, 0x6B, 0xB2, 0x6B, 0x05, 0x6B, 0x4F, 0xEB, 0x52, 0xEB, 0x39, 0xEB, 0x77, 0x1B, 0xE2, 0x1B, 0x59, 0x1B, 0xD7, 0x9B, 0x22, 0x9B, 0xE9, 0x9B, 0x17, 0x5B, 0x82, 0x5B, 0x29, 0x5B, 0x67, 0xDB, 0x7C, 0xDB, 0x49, 0xDB, 0x27, 0x3B, 0x3C, 0x3B, 0x09, 0x3B, 0x47, 0xBB, 0xDC, 0xBB, 0x1E, 0xBB, 0xF5, 0xBB, 0x97, 0x7B, 0x14, 0x7B, 0x86, 0x7B, 0x59, 0x7B, 0x4B, 0xFB, 0x48, 0xFB, 0x52, 0xFB, 0x21, 0xFB, 0x3D, 0xFB, 0x6F, 0x07, 0xAC, 0x07, 0x76, 0x07, 0x65, 0x07, 0xFB, 0x87, 0x04, 0x87, 0x1A, 0x87, 0x49, 0x87, 0x53, 0x47, 0x30, 0x47, 0x42, 0x47, 0xBE, 0x47, 0xAD, 0x47, 0x77, 0xC7, 0x74, 0xC7, 0x16, 0xC7, 0x05, 0xC7, 0x9B, 0x27, 0x58, 0x27, 0x4A, 0x27, 0x31, 0x27, 0xA3, 0xA7, 0xE0, 0xA7, 0x7C, 0xA7, 0x1E, 0xA7, 0x0D, 0xA7, 0x57, 0x67, 0x54, 0x67, 0x26, 0x67, 0xB9, 0x67, 0x6B, 0xE7, 0xE8, 0xE7, 0x0A, 0xE7, 0x51, 0xE7, 0xC3, 0x17, 0xA0, 0x17, 0x3C, 0x17, 0xEE, 0x17, 0x0D, 0x17, 0x57, 0x80, 0x0F, 0x98, 0x5C, 0xE6, 0x5E, 0xAE, 0x5F, 0x61, 0x5C, 0x29, 0x5E, 0xC5, 0x5C, 0x8D, 0x5E, 0x83, 0x5F, 0xF3, 0x5F, 0x7B, 0x5D, 0x37, 0x5F, 0xDF, 0xDE, 0xD0, 0xDD, 0x58, 0xDC, 0x14, 0xDD, 0x6C, 0xDF, 0xE2, 0xDE, 0xAA, 0xDD, 0x26, 0xDE, 0x4E, 0xDF, 0xC1, 0xDE, 0x89, 0xDE, 0x05, 0xDE, 0x75, 0xDD, 0xBD, 0xDC, 0xB3, 0xDE, 0x3B, 0xDC, 0x57, 0xDE, 0x9F, 0x3C, 0x90, 0x3C, 0xE8, 0x3F, 0x64, 0x3D, 0x2C, 0x3F, 0xA2, 0x3E, 0xCA, 0x3F, 0x46, 0x3D, 0x8E, 0x3C, 0x81, 0x3F, 0xF1, 0x03, 0x1E, 0xD0, 0xFA, 0xF4, 0xF0, 0xCC, 0xF8, 0x6C, 0xF3, 0x5C, 0xFA, 0x7C, 0xF0, 0x42, 0xF4, 0xA2, 0xFB, 0x92, 0xF1, 0xB2, 0xF4, 0x8A, 0xF2, 0x2A, 0xF7, 0x1A, 0xF5, 0x3A, 0xF2, 0x06, 0xF1, 0x26, 0xF0, 0xE6, 0xFB, 0xD6, 0xF6, 0xF6, 0xF4, 0xCE, 0xFC, 0x6E, 0xFF, 0x5E, 0xF1, 0x7E, 0xF2, 0x41, 0xF6, 0x61, 0xF8, 0x91, 0xF3, 0xB1, 0xFE, 0x89, 0xF9, 0xA9, 0xF2, 0x99, 0xF0, 0x39, 0xFD, 0x05, 0xF7, 0x25, 0xFE, 0xF5, 0xFB, 0xAB, 0xEF, 0x3F, 0xFE, 0xF3, 0x00, 0xFD, 0xBA, 0xE9, 0xDB, 0x1D, 0x08, 0x03, 0x40, 0xFF, 0x52, 0x90, 0x43, 0x50, 0x62, 0x50, 0x7D, 0xD0, 0x6C, 0xD0, 0x15, 0x30, 0x74, 0x30, 0x25, 0xB0, 0x38, 0xB0, 0x49, 0x70, 0x58, 0x70, 0x31, 0xF0, 0x20, 0xF0, 0x1E, 0xF0, 0x0F, 0x08, 0x2E, 0x08, 0x37, 0x88, 0x06, 0x88, 0x1B, 0x48, 0x3A, 0x48, 0x2B, 0xC8, 0x12, 0xC8, 0x03, 0x28, 0x22, 0x28, 0x5D, 0xA8, 0x4C, 0xA8, 0x65, 0x68, 0x34, 0x68, 0x45, 0xE8, 0x58, 0xE8, 0x09, 0x18, 0x18, 0x18, 0x51, 0x98, 0x20, 0x98, 0x1E, 0x98, 0x4F, 0x58, 0x6E, 0x58, 0x77, 0xD8, 0x46, 0xD8, 0x5B, 0x38, 0x7A, 0x38, 0x6B, 0xB8, 0x52, 0xB8, 0x43, 0x78, 0x62, 0x78, 0x7D, 0xF8, 0x6C, 0xF8, 0xB5, 0xEF, 0x98, 0xDF, 0x55, 0xBE, 0x27, 0x7C, 0x9F, 0xFE, 0x01, 0xFF, 0x43, 0x02, 0x60, 0xFD, 0x00, 0x02, 0x08, 0xB0, 0xEA, 0xBD, 0x10, 0x5A, 0x11, 0x1E, 0x11, 0x99, 0x11, 0xED, 0x11, 0x2B, 0x11, 0xCF, 0x90, 0x28, 0x90, 0x4C, 0x90, 0xF2, 0x91, 0xB6, 0x91, 0xF1, 0x90, 0x35, 0x91, 0x53, 0x91, 0x17, 0x50, 0x90, 0x51, 0xE4, 0x50, 0xA2, 0x51, 0xC6, 0x50, 0xA1, 0x50, 0x85, 0x51, 0x03, 0x51, 0xBB, 0x51, 0xDF, 0xD1, 0xB8, 0xD0, 0xDC, 0xD0, 0x1A, 0xD0, 0x6E, 0xD1, 0xE9, 0xD1, 0xAD, 0xD1, 0xCB, 0xD0, 0x8F, 0x30, 0x48, 0x31, 0x0C, 0x31, 0x72, 0x30, 0x36, 0x30, 0xB1, 0x31, 0xD5, 0x31, 0x93, 0x31, 0xE7, 0xB0, 0x10, 0xB1, 0x64, 0xB0, 0x22, 0xB1, 0x46, 0xB0, 0x21, 0xB1, 0x85, 0xB0, 0xFD, 0xB1, 0xBB, 0xB0, 0xDF, 0x70, 0x38, 0x71, 0x5C, 0x71, 0x1A, 0x70, 0x6E, 0x70, 0xE9, 0x71, 0xAD, 0x71, 0xCB, 0x70, 0x8F, 0xF0, 0x48, 0xF1, 0x0C, 0xF1, 0x72, 0xF1, 0x36, 0xF1, 0x71, 0xF0, 0x35, 0xF0, 0xD3, 0xF0, 0xD7, 0x09, 0x88, 0x08, 0xCC, 0x08, 0x2A, 0x08, 0x6E, 0x09, 0xD9, 0x09, 0xBD, 0x09, 0x7B, 0x7F, 0x42, 0xFD, 0x94, 0xFE, 0x19, 0xFF, 0x73, 0x89, 0x08, 0x97, 0xC8, 0x80, 0xA8, 0x98, 0xE8, 0x9C, 0x98, 0x89, 0xD8, 0x8D, 0xB8, 0x83, 0x04, 0x94, 0x44, 0x8C, 0x24, 0x9A, 0x64, 0x8E, 0x14, 0x93, 0x54, 0x87, 0xB4, 0x00, 0xA0, 0x3A, 0x1D, 0x99, 0x13, 0x59, 0x2B, 0xD9, 0x27, 0xB9, 0x30, 0x79, 0x38, 0xF9, 0x34, 0x05, 0x2A, 0x85, 0x26, 0x45, 0x2E, 0xB0, 0xDC, 0xA9, 0x29, 0x1D, 0x28, 0x9B, 0x28, 0xDF, 0xA9, 0x04, 0xA9, 0x42, 0xA9, 0x26, 0xA9, 0x51, 0xA8, 0xD5, 0x81, 0xDD, 0xBE, 0x4F, 0x43, 0x45, 0x63, 0x47, 0xD3, 0x48, 0xF3, 0x46, 0x2B, 0x40, 0x1B, 0x42, 0x3B, 0x41, 0x87, 0x4C, 0xA7, 0x4E, 0x97, 0x4D, 0xB7, 0x47, 0x4F, 0x09, 0xD0, 0xBC, 0x81, 0xFE, 0x95, 0x81, 0x9F, 0x21, 0x84, 0x61, 0x9C, 0x11, 0x89, 0x51, 0x8D, 0x31, 0x8B, 0x71, 0x97, 0x89, 0x82, 0xC9, 0x96, 0xA9, 0x9E, 0xE9, 0x85, 0x99, 0x8F, 0x39, 0x98, 0x79, 0x8C, 0x05, 0x91, 0x45, 0x85, 0x25, 0x93, 0x65, 0x87, 0x95, 0x8C, 0xD5, 0x9A, 0xB5, 0x8E, 0xF5, 0x99, 0x8D, 0x87, 0x2D, 0x88, 0x6D, 0x94, 0xFD, 0x07, 0xBB, 0x32, 0x7B, 0x06, 0xFB, 0x36, 0x07, 0x29, 0x87, 0x15, 0x47, 0x2D, 0xC7, 0x13, 0x27, 0x0F, 0x67, 0x20, 0xE7, 0x08, 0xD7, 0x0F, 0x2E, 0x65, 0xAE, 0x0C, 0xAE, 0x2D, 0x6E, 0x52, 0x6E, 0x2B, 0xEE, 0x5A, 0xEE, 0xA7, 0x5F, 0x3C, 0xBF, 0x82, 0x7E, 0x8D, 0xF0, 0xFC, 0xE0, 0x51, 0xE6, 0xC9, 0xE0, 0xD9, 0xE6, 0x25, 0xE3, 0xB5, 0xE6, 0xAD, 0xE3, 0x7D, 0xE6, 0xE3, 0xE5, 0x0B, 0xE6, 0x1B, 0xE3, 0x47, 0xE4, 0x57, 0xE5, 0xCF, 0xE2, 0xDF, 0x15, 0xA0, 0x14, 0xB0, 0x15, 0xA8, 0x13, 0x78, 0x10, 0xE4, 0x14, 0xF4, 0x16, 0xEC, 0x11, 0x02, 0x13, 0x12, 0x13, 0x8A, 0x14, 0x9A, 0x12, 0x46, 0x16, 0x56, 0x15, 0x4E, 0x17, 0xDE, 0x10, 0xF9, 0x29, 0x62, 0x22, 0x52, 0x02, 0xB0, 0x9B, 0x41, 0xD4, 0x59, 0xB4, 0x45, 0xF4, 0x5D, 0x8C, 0x5F, 0x2C, 0x58, 0x6C, 0x44, 0x1C, 0x1E, 0x58, 0xED, 0x49, 0xE2, 0xCB, 0x12, 0xB8, 0x12, 0xFA, 0x12, 0x85, 0x12, 0xC7, 0x92, 0x34, 0x92, 0xF6, 0x92, 0x0D, 0x92, 0xCF, 0x52, 0x3C, 0x52, 0x01, 0x52, 0x83, 0xD2, 0x30, 0xD2, 0xB2, 0xD2, 0x09, 0xD2, 0x8B, 0x32, 0x38, 0x32, 0x7A, 0x32, 0x05, 0x32, 0xC7, 0xB2, 0x34, 0xB2, 0x0E, 0xB2, 0x8D, 0xB2, 0xAF, 0x72, 0xBC, 0x72, 0x41, 0x72, 0xC3, 0xF2, 0xF0, 0xF2, 0xF2, 0xF2, 0xC9, 0xF2, 0xAB, 0x0A, 0xF8, 0x0A, 0x46, 0x0A, 0x25, 0x0A, 0xE7, 0x00, 0xB3, 0x5D, 0x15, 0xDB, 0x15, 0xBF, 0x94, 0x84, 0x95, 0xC2, 0x95, 0xA6, 0x94, 0x51, 0x94, 0xD5, 0x95, 0xB3, 0x95, 0x77, 0x55, 0xC8, 0x55, 0xAC, 0x55, 0x6A, 0x55, 0x1E, 0x55, 0xB9, 0x55, 0xFD, 0x55, 0x07, 0xD5, 0x60, 0xD5, 0xE4, 0xD4, 0x92, 0xD4, 0x56, 0xD4, 0xF1, 0xD5, 0x8D, 0xD5, 0x4B, 0xD5, 0x2F, 0x35, 0x98, 0x35, 0xDC, 0x35, 0xBA, 0x34, 0xC1, 0x00, 0x5A, 0x47, 0x6B, 0xCE, 0x69, 0x61, 0x68, 0x69, 0x6B, 0xE5, 0x69, 0x1D, 0x6A, 0x53, 0x6B, 0xDB, 0x6B, 0x37, 0x68, 0xBF, 0xE8, 0xF0, 0xEA, 0x04, 0xE9, 0x8C, 0xE8, 0xC2, 0xEB, 0x2A, 0xE8, 0xA6, 0xFC, 0xB7, 0xDF, 0x8D, 0xF5, 0x4A, 0xF4, 0x2E, 0xF4, 0x99, 0xF4, 0x5D, 0xF5, 0xDB, 0xF5, 0xBF, 0x0C, 0x84, 0x0D, 0xC2, 0x0C, 0x26, 0x0C, 0x91, 0x0C, 0x55, 0x0C, 0x33, 0x0C, 0x37, 0x8D, 0x88, 0x8C, 0x4C, 0x8D, 0xCA, 0x8C, 0xCE, 0x8C, 0x69, 0x8C, 0x6D, 0x8C, 0xAB, 0x8C, 0xAF, 0x4C, 0x18, 0x4C, 0x1C, 0x4C, 0xEA, 0x4C, 0xEE, 0x4C, 0x59, 0x4C, 0x5D, 0x4C, 0x9B, 0x4C, 0x9F, 0xCC, 0x38, 0xCC, 0xDC, 0xCD, 0x5A, 0xCD, 0x5E, 0xCD, 0xB9, 0xCD, 0xBD, 0xCD, 0x3B, 0xCC, 0x3F, 0x80, 0x05, 0xEF, 0x67, 0xD1, 0x6D, 0xF9, 0xCD, 0x52, 0xC0, 0x32, 0xC0, 0xB2, 0xCF, 0x0A, 0xCC, 0x4A, 0xC8, 0x2A, 0xD8, 0x6A, 0xC0, 0x1A, 0xC2, 0x5A, 0xC4, 0xFA, 0xB7, 0xF5, 0x90, 0x0D, 0x24, 0xC0, 0xE6, 0x50, 0x9B, 0x61, 0x5B, 0x28, 0x5B, 0x31, 0xDB, 0x30, 0xDB, 0x11, 0x3B, 0x68, 0x3B, 0x71, 0xBB, 0x30, 0xBB, 0x11, 0x7B, 0x68, 0x7B, 0x71, 0xFB, 0x30, 0xFB, 0x11, 0x07, 0x68, 0x07, 0x31, 0x87, 0x50, 0x87, 0x61, 0x47, 0x28, 0x47, 0x51, 0xC7, 0x10, 0xC7, 0x21, 0x27, 0x08, 0x27, 0x11, 0xA7, 0xDF, 0x4E, 0x03, 0xCE, 0xE0, 0xCE, 0x42, 0xCE, 0x81, 0xCE, 0x7D, 0x2E, 0x20, 0x2E, 0x02, 0x2E, 0xFE, 0x2E, 0xDD, 0x2E, 0x9F, 0xAE, 0xBC, 0xAE, 0x3E, 0xAE, 0x1D, 0xAE, 0x6F, 0x6E, 0x5C, 0x6E, 0x1E, 0x6E, 0x2D, 0x6E, 0x4F, 0xEE, 0x6C, 0xEE, 0x2E, 0xEE, 0x0D, 0xEE, 0x77, 0x1E, 0x4C, 0x1E, 0x0E, 0x1E, 0x35, 0x1E, 0x57, 0x9E, 0xB4, 0x9E, 0xD6, 0x9E, 0xE5, 0x9E, 0xA7, 0x5E, 0x14, 0x5E, 0x66, 0x5E, 0x7F, 0xBD, 0xF6, 0xBD, 0x89, 0xBD, 0x0D, 0xBC, 0x73, 0xBD, 0x37, 0x7D, 0xF0, 0x7C, 0xB4, 0x7C, 0x32, 0x7C, 0x96, 0x7D, 0x31, 0x7C, 0x55, 0x7C, 0x13, 0x7D, 0xE7, 0xFC, 0x10, 0xFD, 0x64, 0xFD, 0xA2, 0xFC, 0xC6, 0x01, 0x2A, 0x8B, 0xF9, 0xFF, 0xF6, 0x1F, 0x08, 0x00, 0x0D, 0xE0, 0x0F, 0xF0, 0x0D, 0xE8, 0x08, 0x78, 0x0D, 0xE4, 0x08, 0x74, 0x0D, 0x6C, 0x08, 0xBC, 0x0D, 0x62, 0x08, 0xB2, 0x0F, 0xAA, 0x03, 0xA8, 0xCC, 0x16, 0xEC, 0x1E, 0xDC, 0x16, 0xFC, 0xFE, 0x9B, 0xF7, 0xB7, 0xFF, 0xEF, 0xBE, 0x10, 0xF0, 0x10, 0xD1, 0x90, 0xB0, 0x90, 0xD1, 0x50, 0xB8, 0x50, 0x99, 0xD0, 0x98, 0xD0, 0x99, 0x30, 0xA4, 0x30, 0xA5, 0xB0, 0xA4, 0xB0, 0xC5, 0x70, 0x8C, 0x70, 0x8D, 0xF0, 0x8C, 0xF0, 0xB5, 0x08, 0xDC, 0x08, 0x9D, 0x88, 0x9C, 0x88, 0xED, 0xC8, 0x9F, 0x91, 0x86, 0x91, 0x05, 0x91, 0xFB, 0x51, 0xA4, 0x51, 0x26, 0x51, 0x7F, 0xA3, 0x8E, 0xA2, 0x29, 0xA2, 0xCD, 0x81, 0x45, 0x7F, 0x1A, 0x43, 0x15, 0x63, 0x15, 0x53, 0x1E, 0x73, 0x1E, 0x4B, 0x13, 0x6B, 0x1D, 0x5B, 0x19, 0x7B, 0x11, 0x47, 0x1B, 0x67, 0x13, 0x57, 0x15, 0x77, 0x19, 0x4F, 0x17, 0x6F, 0x1B, 0x5F, 0x15, 0x7F, 0x99, 0x40, 0x97, 0x60, 0x93, 0x50, 0x99, 0x70, 0x91, 0x48, 0x9B, 0x68, 0x9D, 0x58, 0x91, 0x78, 0x96, 0x44, 0x9D, 0x64, 0x99, 0x54, 0x96, 0x74, 0x92, 0x4C, 0x99, 0x6C, 0x9E, 0x5C, 0x9C, 0x7C, 0x98, 0x42, 0x9A, 0x62, 0x9C, 0x52, 0x98, 0xB2, 0x9B, 0xFA, 0x13, 0xD8, 0xF4, 0x39, 0xA9, 0x9B, 0x69, 0x78, 0x69, 0x5A, 0x69, 0x19, 0x00, 0x91, 0x31, 0xD2, 0x55, 0xD3, 0x93, 0xD2, 0xE7, 0x33, 0x90, 0x32, 0xE4, 0x33, 0x62, 0x32, 0x26, 0x32, 0x61, 0x33, 0x25, 0x32, 0x43, 0x33, 0x07, 0xB3, 0xC0, 0xB2, 0x04, 0xB2, 0xFC, 0xB2, 0x3A, 0xB3, 0xDE, 0xB2, 0x39, 0xB2, 0x5D, 0xB3, 0x1B, 0xB2, 0x6F, 0xFF, 0xD0, 0xFF, 0xB1, 0xF9, 0x53, 0xFE, 0xE7, 0x38, 0x87, 0x2C, 0xC7, 0x28, 0x27, 0x2F, 0x67, 0x33, 0x17, 0x37, 0x57, 0x23, 0x37, 0x25, 0xF7, 0x5F, 0x1E, 0x52, 0x9E, 0x6C, 0x5E, 0x24, 0xC0, 0x66, 0xC8, 0x7C, 0xA1, 0x7C, 0xFF, 0xFC, 0xCE, 0xFC, 0xD7, 0x02, 0xAE, 0x02, 0xEF, 0x82, 0xAE, 0xC2, 0x6F, 0x85, 0x82, 0x85, 0xC1, 0x85, 0x43, 0x45, 0x50, 0x45, 0x12, 0x45, 0x91, 0x45, 0x93, 0x7F, 0x7F, 0x00, 0xDB, 0x3E, 0xFE, 0xEF, 0x7C, 0x31, 0x5A, 0xB1, 0x6A, 0x71, 0x5A, 0xF1, 0x4A, 0x09, 0x76, 0x89, 0x76, 0x49, 0x76, 0xC9, 0x66, 0x29, 0x61, 0xA9, 0x41, 0x69, 0x7E, 0xE9, 0x5E, 0x19, 0x49, 0x99, 0x69, 0x59, 0x31, 0x40, 0x68, 0xCA, 0x72, 0xCB, 0xF2, 0xF2, 0xF2, 0xF3, 0x0A, 0x9A, 0x0A, 0x9B, 0x8A, 0xAA, 0x8A, 0xAB, 0x4A, 0x86, 0x4A, 0xFB, 0xCA, 0xDA, 0xCA, 0xDB, 0x2A, 0xE6, 0x2A, 0xE7, 0xAA, 0xC6, 0xAA, 0xC7, 0x6A, 0xF6, 0x6A, 0xF7, 0xEA, 0xD6, 0xEA, 0xD7, 0x1A, 0xEE, 0x1A, 0x9F, 0x9A, 0xAE, 0x9A, 0xAF, 0x5A, 0xFE, 0xDA, 0xC0, 0xDA, 0xFE, 0x3A, 0xF0, 0x3A, 0xD1, 0xBA, 0xD0, 0xBA, 0xD1, 0x7A, 0xD8, 0x7A, 0xE9, 0xFA, 0xE8, 0xFA, 0xE9, 0x06, 0xC4, 0x06, 0xC5, 0x86, 0xA4, 0x86, 0xC5, 0x46, 0x8C, 0x46, 0x8D, 0xC6, 0xCC, 0xC6, 0x8D, 0x26, 0x82, 0x26, 0x83, 0xA6, 0x82, 0xA6, 0x83, 0x66, 0xF2, 0x66, 0x8B, 0xE6, 0xF2, 0xE6, 0x8B, 0x16, 0xFA, 0x16, 0x87, 0x96, 0x86, 0x96, 0xC7, 0x56, 0x8E, 0x56, 0xCF, 0xD6, 0xCE, 0xD6, 0xAF, 0x36, 0xC1, 0xB6, 0xE0, 0xB6, 0xE1, 0x76, 0x98, 0x76, 0xE9, 0xF6, 0xD8, 0xF6, 0xD9, 0x0E, 0xD4, 0x0E, 0xB5, 0x8E, 0xF4, 0x8E, 0xF5, 0x4E, 0x82, 0x4E, 0xC3, 0xCE, 0xA2, 0xCE, 0x63, 0x60, 0xE3, 0xDB, 0x76, 0xD5, 0x76, 0xDD, 0x77, 0xB3, 0x77, 0x7B, 0x02, 0xCC, 0xFE, 0xD6, 0x23, 0xDC, 0x13, 0xDA, 0x33, 0xD6, 0xFB, 0xA3, 0x57, 0xA1, 0x37, 0xB9, 0x77, 0xB9, 0x0F, 0xB7, 0x4F, 0xAF, 0xAF, 0xA0, 0xEF, 0x10, 0x58, 0xF9, 0xB6, 0xFD, 0x75, 0xFD, 0x0F, 0x03, 0x2C, 0x03, 0x0E, 0x03, 0x55, 0x03, 0xA7, 0x83, 0xE4, 0x83, 0xC6, 0x83, 0x79, 0x83, 0x9B, 0x43, 0x38, 0x43, 0xEA, 0x43, 0xC9, 0x43, 0x73, 0xC3, 0x08, 0xC3, 0x32, 0xC3, 0x11, 0xC3, 0xC3, 0x23, 0xE0, 0x23, 0x82, 0x23, 0x7E, 0x23, 0x1D, 0x23, 0xAF, 0xA3, 0xEC, 0xA3, 0xCE, 0xA3, 0x75, 0xA3, 0x57, 0x63, 0xB4, 0x63, 0x56, 0x63, 0x25, 0x63, 0x87, 0xE3, 0xC4, 0xE3, 0x06, 0xE3, 0x39, 0xE3, 0x1B, 0x13, 0xD8, 0x13, 0xEA, 0x13, 0x29, 0x13, 0xFF, 0x26, 0x91, 0x27, 0xE5, 0x27, 0x63, 0x26, 0x27, 0xA6, 0x60, 0xA7, 0xC4, 0xA7, 0x42, 0xA6, 0x06, 0xA6, 0x41, 0xA7, 0xF9, 0xA7, 0x7D, 0xA7, 0x3B, 0xA6, 0x5F, 0x67, 0x38, 0x66, 0x5C, 0x67, 0x1A, 0x67, 0xEE, 0x66, 0x19, 0x67, 0xED, 0x66, 0xAB, 0x66, 0xCF, 0xE7, 0xA8, 0xE6, 0x2C, 0xE6, 0x8A, 0xE7, 0x0E, 0xE6, 0x49, 0xE6, 0x0D, 0xE7, 0xF3, 0xE6, 0xB7, 0xFE, 0xE1, 0xFF, 0xD3, 0xFE, 0x97, 0xF9, 0x6F, 0x65, 0x01, 0x73, 0x41, 0x75, 0x21, 0x79, 0xE1, 0xDF, 0x22, 0xF2, 0xA2, 0xC2, 0x62, 0xDC, 0xE2, 0xD4, 0xD2, 0xF7, 0x25, 0xE9, 0xA5, 0x88, 0xA5, 0xD1, 0x65, 0xE8, 0x65, 0xB1, 0xE5, 0x90, 0xE5, 0x81, 0x15, 0xB0, 0x15, 0xC1, 0x95, 0x80, 0x95, 0x9E, 0x95, 0xAF, 0x55, 0x9E, 0x55, 0xEF, 0xD5, 0x76, 0x80, 0xF4, 0x9C, 0x6B, 0xEE, 0x6B, 0xCD, 0x6B, 0x8F, 0xEB, 0xAC, 0xEB, 0xCE, 0xEB, 0xF5, 0xEB, 0xB7, 0x1B, 0x8C, 0x1B, 0xF6, 0x1B, 0xD5, 0x1B, 0x57, 0x9B, 0x74, 0x9B, 0x36, 0x9B, 0x15, 0x9B, 0x67, 0x5B, 0x54, 0x5B, 0x16, 0x5B, 0xA5, 0x5B, 0xC7, 0xDB, 0xE4, 0xDB, 0xA6, 0xDB, 0x7F, 0xB7, 0x0F, 0x76, 0x48, 0x76, 0x8C, 0x77, 0x0A, 0x76, 0xF6, 0x76, 0x89, 0x76, 0x0D, 0x76, 0xF3, 0x80, 0x16, 0x40, 0xB0, 0xA7, 0xB1, 0x97, 0xB0, 0x37, 0xBE, 0x0F, 0xB6, 0xFF, 0x6B, 0xDF, 0x65, 0xBF, 0x72, 0xFF, 0xF0, 0x80, 0xE0, 0x40, 0xFD, 0x20, 0xFE, 0x60, 0xF4, 0x10, 0xF4, 0x90, 0xFB, 0xD0, 0xF9, 0xB0, 0xF2, 0xF0, 0xF0, 0x88, 0xE0, 0x48, 0xFD, 0x28, 0xFE, 0x68, 0xEC, 0x18, 0xEC, 0xF8, 0xD7, 0xB1, 0xCB, 0x71, 0xD5, 0xF1, 0xD1, 0x09, 0xE1, 0x89, 0xC6, 0x49, 0xC2, 0xC9, 0x38, 0x40, 0x7E, 0xDE, 0x53, 0xB7, 0xD3, 0x9A, 0xD3, 0x93, 0x33, 0xE2, 0x33, 0xED, 0xB3, 0xE4, 0xB3, 0xA9, 0x73, 0xE8, 0x73, 0x81, 0x73, 0xCF, 0xF3, 0x86, 0xF3, 0x8B, 0x0B, 0xF2, 0x0B, 0xFD, 0x8B, 0xF4, 0x8B, 0xF9, 0x4B, 0xF8, 0x4B, 0xD1, 0x4B, 0xBF, 0xCB, 0xD6, 0xCB, 0xDB, 0x2B, 0x9A, 0x2B, 0x93, 0xAB, 0x9C, 0xAB, 0x95, 0x6B, 0xE4, 0x6B, 0xE9, 0xEB, 0x90, 0xEB, 0xEE, 0xEB, 0x97, 0x1B, 0xE6, 0x1B, 0xEB, 0x9B, 0xBF, 0x00, 0xFB, 0xB1, 0x6F, 0x95, 0x6E, 0xA3, 0x6F, 0x87, 0xEF, 0x40, 0xEE, 0xB8, 0xEF, 0x5C, 0xEE, 0xAA, 0xEE, 0x8E, 0xEF, 0x89, 0xEE, 0xB5, 0xEF, 0x53, 0xEE, 0x67, 0x1E, 0x60, 0x1F, 0x84, 0x1F, 0x7C, 0x1F, 0x5A, 0x1E, 0x6E, 0x1F, 0x69, 0x1E, 0xCD, 0x1E, 0xF3, 0x1E, 0xD7, 0x9E, 0xD0, 0x9E, 0xE4, 0x9E, 0xC2, 0x9F, 0x06, 0x9E, 0x3E, 0x9F, 0x39, 0x9E, 0x1D, 0x9F, 0x2B, 0x9F, 0x8F, 0x5E, 0x7E, 0xBE, 0x68, 0xBF, 0xA4, 0xBC, 0xCC, 0xBC, 0xC2, 0xBD, 0x8A, 0xBC, 0xFA, 0xBD, 0xB6, 0xBD, 0xDE, 0xBF, 0xD1, 0xBF, 0x59, 0xBC, 0x15, 0xBE, 0x6D, 0xBE, 0x63, 0xBD, 0x2B, 0xBF, 0xC7, 0xBC, 0x8F, 0x02, 0x05, 0x80, 0xF7, 0xC3, 0xE3, 0xA3, 0xFE, 0xE3, 0xF2, 0x93, 0xF2, 0xD3, 0xE8, 0xF3, 0xCF, 0xE7, 0xCA, 0x17, 0xEA, 0x97, 0xEC, 0x57, 0xF8, 0xD7, 0xC0, 0x7F, 0xFC, 0xE7, 0xFA, 0xE6, 0xFC, 0xAD, 0xFA, 0xDB, 0x09, 0x08, 0x31, 0x88, 0x0E, 0x48, 0x2A, 0xC8, 0x1C, 0x28, 0x3C, 0xA8, 0x28, 0x68, 0x00, 0x68, 0x3B, 0xE8, 0x03, 0x18, 0x3D, 0x98, 0x25, 0x58, 0x21, 0xD8, 0x16, 0x38, 0x16, 0xB8, 0x12, 0x78, 0x0C, 0xF8, 0x08, 0x04, 0x18, 0x04, 0x0F, 0x84, 0x3B, 0x44, 0x1D, 0xC4, 0x39, 0x24, 0x39, 0xA4, 0x01, 0x64, 0x16, 0xE4, 0x12, 0x14, 0x12, 0x94, 0x34, 0x54, 0x08, 0x54, 0x2F, 0xD4, 0x1B, 0x34, 0x1B, 0xB4, 0x03, 0x74, 0x39, 0xF4, 0x21, 0x50, 0xFA, 0xB5, 0x60, 0x52, 0x60, 0x66, 0x61, 0xE1, 0x60, 0x45, 0x61, 0x03, 0x60, 0x3B, 0x60, 0x1F, 0xE1, 0x18, 0xE1, 0xAC, 0x81, 0xCD, 0xBF, 0x0B, 0x8F, 0x0B, 0xAF, 0x06, 0x9F, 0x00, 0x3F, 0xF9, 0x1D, 0x1A, 0xE8, 0xFB, 0xBE, 0xDF, 0x5B, 0xBF, 0xDF, 0xFF, 0xA0, 0xFB, 0x61, 0xF1, 0xA3, 0xF0, 0xC7, 0x16, 0x02, 0x36, 0x82, 0x0A, 0x42, 0x1C, 0xC2, 0x38, 0x22, 0x14, 0xA2, 0x20, 0xA2, 0x0F, 0x62, 0x0B, 0xE2, 0x1D, 0x12, 0x1D, 0xB0, 0xF6, 0x0B, 0x91, 0xB6, 0x90, 0x71, 0x90, 0x55, 0x91, 0xE3, 0x91, 0x27, 0x50, 0xA0, 0x80, 0xAD, 0xEF, 0x8B, 0xD2, 0x8A, 0x72, 0x8F, 0xCA, 0x80, 0x6A, 0x85, 0xFA, 0x17, 0x75, 0x07, 0x0D, 0x0F, 0x4D, 0x1D, 0x2D, 0x11, 0x6D, 0x1A, 0x1D, 0x16, 0x5D, 0x04, 0x3D, 0x00, 0xBD, 0x03, 0xFD, 0x19, 0x83, 0x19, 0xC3, 0x16, 0xA3, 0x0C, 0xE3, 0x00, 0xF3, 0x27, 0xA6, 0x36, 0x66, 0x1A, 0xE6, 0x3C, 0x16, 0x02, 0x96, 0x24, 0x56, 0x08, 0x56, 0x2F, 0xD6, 0x07, 0x36, 0x07, 0xB6, 0x33, 0x76, 0x0D, 0xF6, 0x19, 0x0E, 0x39, 0x8E, 0x21, 0xCE, 0x1F, 0x9C, 0x55, 0x5C, 0x34, 0x5C, 0x05, 0xDC, 0x68, 0xDC, 0x11, 0x3C, 0x70, 0x3C, 0x7E, 0x3C, 0x3F, 0xBC, 0x61, 0x7C, 0x24, 0x7C, 0x2D, 0xFC, 0x22, 0xFC, 0x2B, 0x02, 0x0E, 0x82, 0x40, 0x82, 0x09, 0x42, 0x74, 0x42, 0x7D, 0xC2, 0x32, 0xC2, 0xFB, 0x9F, 0xBC, 0xC0, 0xBE, 0x9F, 0x03, 0x2C, 0xC0, 0x94, 0xA8, 0x86, 0xE8, 0x8D, 0x58, 0x84, 0x38, 0x96, 0x78, 0x85, 0x84, 0x98, 0xC4, 0x86, 0xA4, 0x85, 0x14, 0x94, 0x54, 0x9A, 0x34, 0x85, 0x74, 0x87, 0x8C, 0x9A, 0xCC, 0x85, 0xAC, 0x87, 0x1C, 0x96, 0x5C, 0x85, 0x3C, 0x87, 0xFC, 0x84, 0x82, 0x85, 0xC2, 0x97, 0x62, 0x14, 0x58, 0xF5, 0xBA, 0x94, 0x25, 0x94, 0x77, 0x54, 0x3C, 0x54, 0x61, 0x54, 0x73, 0xD4, 0x78, 0xD4, 0xE6, 0xD4, 0x75, 0xD4, 0x1F, 0x34, 0x62, 0x34, 0x09, 0x34, 0x1B, 0xB4, 0xE4, 0xB4, 0x8E, 0xB4, 0x9D, 0x74, 0xD0, 0x74, 0x8A, 0x00, 0xFF, 0x8F, 0xE9, 0x99, 0xE9, 0x7D, 0xE9, 0x47, 0x18, 0x50, 0x18, 0x74, 0x19, 0x4A, 0x19, 0xEE, 0x19, 0xF9, 0x18, 0x23, 0x18, 0x17, 0x98, 0x08, 0x99, 0xAC, 0x98, 0x9A, 0x98, 0x41, 0x98, 0xA5, 0x99, 0x53, 0x99, 0x77, 0x59, 0x68, 0x59, 0x3C, 0x58, 0x06, 0x58, 0x11, 0x58, 0x35, 0x59, 0x8B, 0x58, 0x6F, 0xD8, 0x7E, 0xB1, 0x85, 0xB2, 0xCD, 0xB1, 0xE3, 0xB1, 0x9B, 0xB3, 0xD7, 0x03, 0xAD, 0x5E, 0x82, 0x23, 0x89, 0x63, 0x8B, 0x93, 0x8A, 0xD3, 0x85, 0xB3, 0x9B, 0x0B, 0x96, 0x4B, 0x85, 0x2B, 0x87, 0xEB, 0x94, 0x9B, 0x95, 0xDB, 0x8F, 0x7B, 0xEC, 0x17, 0xEA, 0x2F, 0xBD, 0x5F, 0xA5, 0xBF, 0xEE, 0x79, 0x78, 0x79, 0xC2, 0x79, 0xE6, 0x79, 0xF1, 0x78, 0xCD, 0x01, 0xEE, 0xBF, 0xF3, 0x89, 0xF1, 0xC5, 0xF3, 0xAD, 0xF1, 0x93, 0xF2, 0xDB, 0xF1, 0xB7, 0x0A, 0x80, 0x09, 0xC8, 0x08, 0xA4, 0x0A, 0xEC, 0x08, 0x52, 0x0B, 0xBA, 0x08, 0x76, 0x0B, 0xC1, 0x08, 0x29, 0x09, 0x65, 0x0B, 0x1D, 0x09, 0x33, 0x09, 0x7B, 0x0B, 0x0F, 0x89, 0x20, 0x8A, 0x68, 0x8A, 0x14, 0x8A, 0x5C, 0x8A, 0x72, 0x8A, 0x06, 0x89, 0x4E, 0x8A, 0x61, 0x88, 0x19, 0x8A, 0x55, 0x88, 0x3D, 0x8A, 0xF3, 0x8B, 0x47, 0x8A, 0x2F, 0x48, 0x10, 0x48, 0x58, 0x4A, 0x34, 0x48, 0x7C, 0x49, 0x4A, 0x48, 0x26, 0x4A, 0x6E, 0x4A, 0x51, 0x48, 0x39, 0x49, 0x75, 0x4A, 0x43, 0x4B, 0x2B, 0xFE, 0xD7, 0xE9, 0x99, 0x64, 0x7C, 0x64, 0x86, 0x65, 0x91, 0x65, 0x75, 0x64, 0x8B, 0x65, 0x6F, 0xE5, 0x78, 0xE4, 0x42, 0xE5, 0xE6, 0xE4, 0xF1, 0xE4, 0xCD, 0xE5, 0xEB, 0xE5, 0x3F, 0x14, 0xC4, 0x15, 0x12, 0x15, 0x36, 0x15, 0x29, 0x15, 0x9D, 0x15, 0xBB, 0x95, 0x60, 0x95, 0x54, 0x94, 0x72, 0x81, 0x75, 0xCE, 0xA6, 0x1C, 0xA0, 0x3C, 0xA1, 0x82, 0xA9, 0x62, 0xA4, 0x52, 0xA5, 0xF2, 0xA2, 0x2A, 0xAC, 0x1A, 0xA7, 0xBA, 0xA6, 0x46, 0xA6, 0xE6, 0xA8, 0xD6, 0xA9, 0x0E, 0xAD, 0xAE, 0xAC, 0x9E, 0xA3, 0x7E, 0xA6, 0xC1, 0xA6, 0x11, 0xA8, 0x31, 0xA9, 0x89, 0xA5, 0x69, 0xAC, 0x59, 0xAD, 0xF9, 0xA6, 0x25, 0xAA, 0x15, 0xAF, 0xB5, 0xAE, 0x4D, 0xAE, 0xED, 0xA8, 0xDD, 0xA1, 0x03, 0xA5, 0xA3, 0xA8, 0x93, 0xA5, 0x73, 0xA8, 0xCB, 0xA8, 0xEB, 0xA5, 0x3B, 0xA8, 0x87, 0xA0, 0xA7, 0xA1, 0x57, 0x00, 0x30, 0x9E, 0x5D, 0x3F, 0x40, 0x7F, 0xCC, 0x00, 0xD5, 0x40, 0xC7, 0xA0, 0xD8, 0xE0, 0xDA, 0x90, 0xD3, 0x30, 0xD0, 0x70, 0xDC, 0x08, 0xD5, 0x48, 0xC7, 0xE8, 0xAF, 0xD1, 0x95, 0x31, 0x87, 0xB1, 0xBF, 0xF1, 0xA8, 0x09, 0x92, 0x89, 0xA6, 0x49, 0xBE, 0xC9, 0xA9, 0x29, 0xB3, 0xA9, 0x97, 0x69, 0xBF, 0x19, 0x9C, 0x99, 0x92, 0x59, 0xA6, 0xD9, 0x81, 0x39, 0xB3, 0x79, 0xA0, 0xF9, 0x8C, 0x05, 0x81, 0x85, 0x8D, 0x45, 0xBB, 0x25, 0x8C, 0xA5, 0x9A, 0x65, 0x91, 0xE5, 0x9D, 0x95, 0x80, 0x55, 0x8C, 0xD5, 0xBA, 0x35, 0x95, 0xB5, 0x9B, 0xF5, 0xA0, 0x0D, 0x8A, 0x8D, 0xBE, 0x4D, 0x95, 0xCD, 0x9B, 0xAD, 0xB8, 0x6D, 0x8A, 0xED, 0x9E, 0x1D, 0xA3, 0x9D, 0xAF, 0xDD, 0xB8, 0x3D, 0xA6, 0xBD, 0xA9, 0x7D, 0xBD, 0xC3, 0x37, 0x07, 0x19, 0x87, 0x0C, 0x87, 0x23, 0x47, 0x16, 0xC7, 0x00, 0xC7, 0x29, 0xA0, 0xCA, 0x9B, 0x3B, 0x35, 0x3A, 0x83, 0x3A, 0xCB, 0x39, 0x67, 0x3A, 0x1F, 0xBB, 0xB0, 0xBA, 0x04, 0xBA, 0x4C, 0xB9, 0xE2, 0xB8, 0x9A, 0xB9, 0x36, 0xB8, 0x7D, 0x73, 0x93, 0x71, 0x4B, 0x77, 0x3B, 0x70, 0x67, 0x72, 0xF7, 0x75, 0x1F, 0xF3, 0x40, 0xF7, 0x30, 0xF2, 0xA8, 0xF6, 0x78, 0xF3, 0x14, 0x03, 0x7A, 0xFC, 0x96, 0x17, 0xB5, 0x97, 0x9B, 0x57, 0xBF, 0x37, 0x82, 0xB7, 0x96, 0x77, 0xB1, 0xF7, 0xAD, 0x0F, 0xAF, 0x4F, 0x84, 0xCF, 0xA2, 0xEF, 0x4F, 0x5F, 0x1B, 0xDF, 0x16, 0x3F, 0x70, 0x3F, 0x79, 0xA0, 0xC5, 0x1F, 0xFA, 0x33, 0xF9, 0xFB, 0xF8, 0x8F, 0x06, 0xA0, 0x06, 0xE8, 0x05, 0x94, 0x05, 0x3C, 0x06, 0x0A, 0x04, 0x46, 0x05, 0x2E, 0x05, 0x11, 0x05, 0xD9, 0x04, 0xB5, 0x06, 0x83, 0x07, 0xCB, 0x05, 0x67, 0x04, 0x1F, 0xFC, 0x66, 0xF8, 0xED, 0xF5, 0x7B, 0x28, 0x04, 0x29, 0x44, 0x3B, 0xA4, 0x38, 0xE4, 0x36, 0x94, 0x27, 0x34, 0x2C, 0x74, 0x3E, 0x0C, 0x3F, 0xCC, 0x3C, 0xAC, 0x3E, 0xEC, 0x33, 0x5C, 0x3C, 0x3C, 0x31, 0x7C, 0x23, 0x82, 0x22, 0xC2, 0x31, 0xA2, 0x33, 0x12, 0x2A, 0x52, 0x21, 0x32, 0x2B, 0xF2, 0x30, 0x8A, 0x21, 0xCA, 0x33, 0x6A, 0x30, 0x1A, 0x21, 0x5A, 0x23, 0xBA, 0x20, 0xFA, 0x29, 0x46, 0x39, 0xA6, 0x2E, 0x16, 0x01, 0x20, 0xF5, 0x68, 0x1C, 0x79, 0x5C, 0x70, 0xDC, 0x4E, 0x3C, 0x6F, 0x7C, 0x66, 0xFC, 0x73, 0x82, 0x4A, 0x42, 0x6D, 0xE2, 0x8F, 0x44, 0xAB, 0xC4, 0xE1, 0x24, 0x92, 0x24, 0xFF, 0xA4, 0x8D, 0x64, 0xCE, 0xE4, 0xE4, 0xE4, 0xDB, 0x14, 0xD9, 0x94, 0xB2, 0x54, 0xC8, 0x54, 0xC3, 0xD4, 0xAE, 0x34, 0xAC, 0x34, 0x97, 0xB4, 0xD9, 0x74, 0xDA, 0xF4, 0xB0, 0xF4, 0x7D, 0x60, 0x21, 0x67, 0x66, 0x3C, 0x66, 0x2A, 0x66, 0x56, 0x66, 0x41, 0x67, 0x19, 0x67, 0x75, 0x67, 0x63, 0x67, 0xBB, 0x64, 0xCF, 0xFC, 0xA1, 0xFA, 0xF3, 0xFB, 0xCF, 0x56, 0x0E, 0x57, 0x4E, 0x52, 0xCE, 0x65, 0xAE, 0x78, 0x6E, 0x5E, 0xEE, 0x5B, 0x9E, 0x72, 0x5E, 0x55, 0x3E, 0x54, 0xBE, 0x7E, 0x7E, 0x6B, 0x01, 0x72, 0x81, 0x65, 0x41, 0x7F, 0x21, 0x4E, 0xA1, 0x73, 0xE1, 0x44, 0x11, 0x49, 0x91, 0x77, 0xD1, 0xFC, 0x5F, 0xEA, 0xBF, 0x41, 0x40, 0x4B, 0x67, 0x2C, 0x0E, 0x07, 0xD6, 0x30, 0x5B, 0x49, 0x74, 0xC9, 0x7E, 0x29, 0x57, 0x69, 0x7C, 0xE9, 0x51, 0x19, 0x4F, 0x59, 0x62, 0xD9, 0x49, 0x39, 0x5F, 0x79, 0x72, 0xF9, 0x59, 0x05, 0x7F, 0x45, 0x4A, 0xC5, 0x79, 0xA5, 0x40, 0x65, 0x6A, 0xE5, 0x45, 0x95, 0x50, 0x55, 0x5A, 0xD5, 0x65, 0xB5, 0x70, 0x75, 0x46, 0xF5, 0x75, 0x8D, 0x68, 0x4D, 0x56, 0xCD, 0x6D, 0xAD, 0x78, 0xED, 0x9F, 0xDA, 0xFB, 0x3A, 0x49, 0x60, 0xFF, 0x3E, 0x02, 0x5C, 0xCD, 0xAF, 0x7F, 0x6E, 0x90, 0x6D, 0x28, 0x6C, 0x78, 0x6B, 0x54, 0x68, 0x2C, 0x6E, 0xFC, 0x68, 0x52, 0x6A, 0x2A, 0x6B, 0xFE, 0xD6, 0xAC, 0xDA, 0x5C, 0xD9, 0x02, 0xD6, 0xA2, 0xD1, 0x52, 0xD3, 0x0A, 0x09, 0xEC, 0xDE, 0xFA, 0x36, 0x98, 0x36, 0xAD, 0xB6, 0xD2, 0xB6, 0xA7, 0x76, 0x91, 0xF6, 0xC4, 0xF6, 0x9D, 0x0E, 0xFA, 0x0E, 0xDF, 0x8E, 0x89, 0x4E, 0xEC, 0x4E, 0xF3, 0xCE, 0xA6, 0x2E, 0x88, 0x2E, 0xA5, 0xAE, 0xBC, 0xAE, 0xAB, 0x6E, 0xDE, 0xEE, 0xA8, 0xEE, 0xB5, 0x1E, 0xCA, 0x1E, 0xF7, 0x9E, 0xA1, 0x5E, 0xB4, 0x5E, 0xE3, 0xDE, 0xFA, 0x3E, 0xD0, 0x3E, 0x85, 0xBE, 0xDC, 0xBE, 0xAB, 0x7E, 0xDE, 0xFE, 0xE8, 0xFE, 0x8D, 0x01, 0x9A, 0x01, 0xAF, 0x81, 0xF1, 0x41, 0x9C, 0x41, 0xCB, 0xC1, 0xB6, 0x21, 0xD8, 0x21, 0xCD, 0xA1, 0xD2, 0xA1, 0x97, 0x61, 0x89, 0xE1, 0x8C, 0xE1, 0xD3, 0x11, 0xAE, 0x91, 0x88, 0x91, 0xB5, 0x51, 0xEA, 0x51, 0xAF, 0xD1, 0x89, 0x31, 0xDC, 0x31, 0x9B, 0xB1, 0xAE, 0x71, 0x84, 0x71, 0xFD, 0xF1, 0xDA, 0x09, 0xD0, 0x09, 0xA5, 0x89, 0xA2, 0x89, 0xA7, 0x49, 0xF1, 0xC9, 0x8C, 0xC9, 0xF3, 0x29, 0xDE, 0xA9, 0xF8, 0xFF, 0xB6, 0x6F, 0xD8, 0xF4, 0xDA, 0x0C, 0xDD, 0x4C, 0xC0, 0xCC, 0xBF, 0x59, 0xF2, 0x59, 0xAF, 0xD9, 0xA9, 0x39, 0xA2, 0x39, 0xD7, 0xB9, 0xB1, 0x79, 0x7C, 0x60, 0xFB, 0x0E, 0xFF, 0xC3, 0xF9, 0x67, 0xFF, 0x6F, 0x60, 0x01, 0x6B, 0xC1, 0x76, 0x61, 0x60, 0x11, 0x6B, 0xD1, 0x6E, 0x71, 0x60, 0x09, 0x7B, 0xC9, 0x7E, 0x69, 0x68, 0x19, 0x77, 0xD9, 0x71, 0x79, 0x74, 0x85, 0x70, 0xC5, 0x75, 0x65, 0x72, 0x95, 0x04, 0x20, 0xE2, 0xFC, 0x1A, 0xF5, 0x5A, 0xE0, 0xDA, 0xEA, 0x3A, 0xD3, 0x7A, 0xC4, 0xFA, 0xDE, 0x06, 0xF7, 0x46, 0xD2, 0xC6, 0xC5, 0xA6, 0xE8, 0x66, 0xCE, 0xE6, 0xF3, 0x96, 0xE2, 0x56, 0x39, 0x50, 0xC3, 0xF5, 0xB6, 0x5B, 0x77, 0x50, 0x76, 0x6C, 0x77, 0x46, 0x76, 0x89, 0x77, 0x7D, 0x77, 0x57, 0xF6, 0x58, 0xF7, 0xC2, 0xF6, 0xBA, 0xF7, 0xB6, 0xF6, 0xBE, 0xF6, 0x09, 0xF6, 0xF9, 0xF6, 0xF5, 0xF6, 0xFD, 0xF6, 0x73, 0xF6, 0xBB, 0xF7, 0xB7, 0xF6, 0xBF, 0x00, 0x0A, 0xF2, 0x1F, 0xE8, 0x1F, 0xF8, 0x1F, 0xE4, 0x1E, 0xF4, 0x1C, 0xEC, 0x1C, 0x82, 0x1C, 0xFE, 0x3C, 0x14, 0x3C, 0x34, 0x3C, 0x0C, 0x3C, 0x2C, 0x38, 0xEC, 0x3F, 0xDC, 0x3F, 0x02, 0x3F, 0x22, 0x3D, 0x12, 0x39, 0x32, 0x3D, 0x0A, 0x39, 0x2A, 0x3E, 0x1A, 0x39, 0x3A, 0x3E, 0x86, 0x39, 0xA6, 0x3C, 0x96, 0x3C, 0xB6, 0x3A, 0x8E, 0x3A, 0xAE, 0x38, 0x9E, 0x3C, 0xBE, 0x3C, 0x41, 0x38, 0x61, 0x38, 0x51, 0x38, 0x71, 0x00, 0x18, 0x59, 0x7F, 0xF2, 0xEF, 0xE4, 0xE1, 0x14, 0xFD, 0x94, 0xFD, 0x54, 0xFD, 0xD4, 0xF3, 0x34, 0xF3, 0xB4, 0xE3, 0x74, 0xE3, 0xF4, 0xF3, 0x8C, 0xE0, 0x4C, 0xE0, 0xCC, 0xF0, 0x2C, 0xE8, 0xAC, 0xF0, 0x6C, 0xE8, 0xEC, 0xE8, 0x1C, 0xE6, 0x9C, 0xEA, 0x5C, 0xEA, 0xDC, 0xE6, 0x3C, 0xE6, 0xBC, 0xE6, 0x7C, 0xF6, 0xFC, 0xEE, 0x02, 0xF5, 0x82, 0xED, 0x42, 0xFD, 0xC2, 0xE3, 0x22, 0xF3, 0xA2, 0xF3, 0x62, 0xF3, 0xF2, 0xDB, 0x25, 0xD1, 0xA5, 0x30, 0xB0, 0x9E, 0x43, 0x2F, 0x4B, 0x2F, 0xC7, 0x2F, 0x2F, 0xAE, 0x10, 0xAE, 0x18, 0xAF, 0x94, 0xAE, 0x5C, 0xAE, 0x52, 0xAF, 0x5A, 0xAF, 0xD6, 0xAE, 0x3E, 0xAE, 0x09, 0xAE, 0x05, 0xAE, 0x8D, 0x01, 0x9E, 0x96, 0x5C, 0x8F, 0x5D, 0x5F, 0xDC, 0x20, 0xDC, 0x30, 0xDE, 0x28, 0xDF, 0xB8, 0xDE, 0xA4, 0xDD, 0xB4, 0xDF, 0x6C, 0xDC, 0x7E, 0xBB, 0x25, 0xBA, 0x15, 0xB9, 0x35, 0xBB, 0x8D, 0xB8, 0xAD, 0xB8, 0x9D, 0xBE, 0xBD, 0xBD, 0x43, 0xBD, 0x63, 0xBF, 0xD3, 0xBC, 0xF3, 0xB9, 0xCB, 0xB9, 0xEB, 0xBB, 0x3B, 0xB8, 0x87, 0xBE, 0xA7, 0xBE, 0x97, 0xB8, 0x37, 0xBA, 0xF7, 0xB9, 0x4F, 0xBC, 0x2F, 0xBB, 0xEF, 0xBD, 0x5F, 0xBA, 0xBF, 0x7C, 0x80, 0x78, 0xC0, 0x7D, 0x60, 0x7A, 0x90, 0x00, 0x16, 0xB7, 0xDB, 0x43, 0xCC, 0x43, 0xE1, 0x43, 0xFB, 0xC3, 0xDC, 0xC3, 0x09, 0xD0, 0xE0, 0x31, 0x1E, 0xE9, 0x1E, 0x85, 0x1F, 0xB5, 0x1E, 0x1D, 0x1F, 0xC3, 0x1F, 0x73, 0x1F, 0x9B, 0x1F, 0xA7, 0x1E, 0x0F, 0x1E, 0xDF, 0x9F, 0x50, 0x9E, 0xA8, 0x9E, 0x04, 0x9E, 0xD4, 0x9F, 0xEC, 0x9E, 0x42, 0x9E, 0xB2, 0x9F, 0x1A, 0x9E, 0xC6, 0x9F, 0x76, 0x9F, 0x5E, 0x9E, 0x91, 0x9E, 0x29, 0x9E, 0xF9, 0x9E, 0x55, 0x81, 0x6D, 0x1E, 0xFC, 0x9C, 0xF9, 0x5C, 0xFF, 0x3C, 0xF6, 0xBC, 0xF3, 0xFC, 0xFC, 0x82, 0xF8, 0x42, 0xFE, 0xC2, 0xFB, 0xA2, 0xF2, 0x62, 0xF3, 0x12, 0xFC, 0x92, 0xF9, 0x52, 0xFF, 0x32, 0xF6, 0xB2, 0xF3, 0xF2, 0xF2, 0x8A, 0xF8, 0x4A, 0x0E, 0x94, 0x7B, 0xD5, 0x57, 0x9B, 0xD7, 0xDF, 0xAF, 0x59, 0xAF, 0x0D, 0xAF, 0xE3, 0xAF, 0x7B, 0xAF, 0xAF, 0x6F, 0xC8, 0x6F, 0x94, 0xC0, 0x82, 0x57, 0x7F, 0xB3, 0x7F, 0x0B, 0x7D, 0xCB, 0x79, 0x6B, 0x7A, 0x9B, 0x7A, 0x3B, 0x7C, 0xFB, 0x78, 0x47, 0x7B, 0xA7, 0x79, 0x17, 0x7E, 0xD7, 0x7E, 0x77, 0x7A, 0x8F, 0x7C, 0x2F, 0x78, 0x6F, 0x7B, 0x9F, 0x7B, 0x3F, 0xFD, 0x00, 0xF9, 0xC0, 0xFA, 0x60, 0xFC, 0x90, 0xF8, 0x30, 0xF8, 0x70, 0xFF, 0x88, 0xFB, 0x28, 0xF9, 0xE8, 0xF9, 0x58, 0xFE, 0xB8, 0xFA, 0x84, 0xFA, 0x24, 0xF8, 0x64, 0xFF, 0x94, 0xFB, 0x34, 0xFB, 0xF4, 0xFB, 0x4C, 0xFD, 0xAC, 0xFE, 0x1C, 0xFE, 0xDC, 0xFA, 0x7C, 0xFA, 0xFA, 0xF1, 0x45, 0xF6, 0xC5, 0xFB, 0xA5, 0xF6, 0x65, 0xF7, 0x15, 0xFA, 0x95, 0xF3, 0xD5, 0xFC, 0x35, 0xFD, 0x75, 0xF4, 0xF5, 0x65, 0x63, 0xEA, 0xCC, 0xF4, 0xDF, 0x7D, 0x30, 0xE0, 0xFF, 0xF3, 0xF3, 0xDE, 0xDF, 0xFE, 0xCF, 0xF3, 0xFF, 0xF9, 0x0F, 0x0E, 0xFC, 0x80, 0xC3, 0xFF, 0x2D, 0xE0, 0x5B, 0x2F, 0x08, 0x08, 0x88, 0x20, 0x48, 0x20, 0x48, 0x1F, 0x28, 0x28, 0xA8, 0x10, 0x68, 0x10, 0x68, 0x3F, 0x18, 0x38, 0x98, 0x30, 0x58, 0x30, 0xD8, 0x20, 0x38, 0x04, 0xB8, 0x08, 0x78, 0x08, 0xF8, 0x10, 0x04, 0x24, 0x84, 0x18, 0x44, 0x28, 0xC4, 0x30, 0x24, 0x14, 0xA4, 0x38, 0x64, 0x18, 0xE4, 0x08, 0x14, 0x0C, 0x94, 0x04, 0x54, 0x38, 0xD4, 0x18, 0x34, 0x2C, 0xB4, 0x24, 0x74, 0x24, 0xF4, 0x38, 0x0C, 0x1C, 0x8C, 0x34, 0x4C, 0x14, 0xCC, 0x04, 0x2C, 0x3C, 0xAC, 0x0C, 0x6C, 0x34, 0xEC, 0x24, 0xDC, 0x0F, 0x38, 0x59, 0xB8, 0x18, 0xB8, 0x69, 0x78, 0x04, 0x78, 0x39, 0xF8, 0x38, 0xF8, 0x99, 0xEF, 0x88, 0xDF, 0x15, 0xBE, 0xC7, 0x7F, 0x9F, 0xFD, 0x81, 0xF4, 0x43, 0xF1, 0x47, 0xC2, 0x8F, 0x39, 0x04, 0x14, 0x04, 0x25, 0x84, 0x44, 0x84, 0x7F, 0x88, 0xA8, 0x88, 0xCA, 0x88, 0xC9, 0x88, 0x0B, 0x48, 0x68, 0x48, 0xAA, 0x48, 0x29, 0x48, 0x8B, 0xC8, 0xE8, 0xC8, 0x6A, 0x40, 0x2B, 0x58, 0x42, 0xC1, 0x44, 0x51, 0x47, 0x49, 0x43, 0x59, 0x41, 0xC5, 0x42, 0xD5, 0x40, 0xCD, 0x40, 0x5D, 0x45, 0xC3, 0x46, 0xD3, 0x42, 0xCB, 0x44, 0x5B, 0x43, 0xC7, 0x41, 0xD7, 0x46, 0xCF, 0x42, 0x5F, 0xC7, 0xC0, 0xC3, 0xD0, 0xC1, 0xC8, 0xC6, 0xD8, 0xC4, 0xC4, 0xC7, 0xD4, 0xC5, 0xCC, 0xC1, 0xDC, 0xC2, 0x22, 0xC0, 0xD2, 0xC3, 0xCA, 0xC5, 0xDA, 0xC6, 0x26, 0xC4, 0x36, 0xC0, 0xCE, 0xC3, 0xDE, 0xC1, 0x21, 0x02, 0xFC, 0x20, 0x1F, 0x67, 0x0F, 0x97, 0x18, 0xD7, 0x08, 0xB7, 0x10, 0x77, 0x1F, 0x8F, 0x04, 0xCF, 0x18, 0xAF, 0x08, 0xEF, 0x00, 0x9F, 0x14, 0xDF, 0x14, 0xFF, 0x2F, 0xFE, 0x21, 0x01, 0x39, 0xD0, 0x09, 0x8A, 0x09, 0x8E, 0x09, 0x29, 0x08, 0xCD, 0x09, 0x4B, 0x09, 0x4F, 0x7E, 0x52, 0xFE, 0xB4, 0xF8, 0x59, 0xF6, 0xF3, 0x94, 0x88, 0x8A, 0xC8, 0x8A, 0xA8, 0x9C, 0xE8, 0x8C, 0x98, 0x86, 0xD8, 0x9A, 0xB8, 0x82, 0xF8, 0x82, 0x84, 0x16, 0xB0, 0x84, 0x2A, 0x92, 0x4B, 0x52, 0x3A, 0x52, 0x5B, 0xD2, 0x6A, 0xD2, 0x2B, 0x32, 0x7A, 0x32, 0x7B, 0xB2, 0x1A, 0xB2, 0x6B, 0x72, 0x46, 0x72, 0x07, 0xF2, 0x5A, 0xF2, 0x5B, 0x0A, 0x26, 0x0A, 0x47, 0x8A, 0x7A, 0x8A, 0x3B, 0x4A, 0x66, 0x4A, 0x27, 0xCA, 0x06, 0xCA, 0x7B, 0x2A, 0x16, 0x2A, 0x17, 0xAA, 0x46, 0xAA, 0x07, 0x6A, 0x36, 0x6A, 0x57, 0xEA, 0x26, 0xEA, 0x27, 0x1A, 0x76, 0x1A, 0x37, 0x9A, 0x16, 0x9A, 0x67, 0x5A, 0x0E, 0x5A, 0x77, 0xDA, 0x56, 0xDA, 0x17, 0x3A, 0x4E, 0x3A, 0x4F, 0xBA, 0x36, 0xBA, 0x57, 0x7A, 0x6E, 0x7A, 0x2F, 0xFA, 0x76, 0xFA, 0x77, 0x86, 0x5F, 0x0C, 0xDE, 0x0C, 0x1D, 0x0C, 0x1F, 0x8C, 0x3C, 0x8C, 0x3E, 0x8C, 0x5D, 0x8C, 0x9F, 0x4C, 0xBC, 0x4C, 0x7E, 0x4C, 0xDD, 0x4C, 0x5F, 0xCC, 0xFC, 0xCC, 0xFE, 0xCC, 0x3D, 0x2C, 0x20, 0x2C, 0x02, 0x2C, 0x01, 0x2C, 0xBD, 0xAC, 0xA0, 0xAC, 0x82, 0xAC, 0x81, 0xAC, 0xFD, 0x6C, 0x60, 0x6C, 0x42, 0x6C, 0xC1, 0x6C, 0x03, 0xEC, 0xE0, 0xEC, 0x22, 0xEC, 0xBF, 0xD9, 0x07, 0x39, 0x20, 0x39, 0x44, 0x39, 0x42, 0x38, 0x86, 0x38, 0xA1, 0x38, 0xC5, 0x38, 0x43, 0x81, 0x6E, 0x00, 0xCD, 0x25, 0xCE, 0x15, 0xCE, 0x35, 0xCA, 0x0D, 0xC3, 0x2D, 0xC9, 0x1D, 0x01, 0xF8, 0x03, 0xDC, 0x2F, 0xA9, 0x5F, 0x91, 0xBF, 0xC6, 0x79, 0xE0, 0x79, 0xA4, 0x79, 0xA2, 0x78, 0x26, 0x79, 0xBF, 0xF3, 0xCA, 0xF0, 0xC6, 0xF0, 0x4E, 0xF1, 0xFD, 0xE0, 0x93, 0xE3, 0x8B, 0xE5, 0x9B, 0x06, 0xDA, 0x81, 0x3C, 0xD0, 0xFE, 0x67, 0x04, 0x90, 0x04, 0x14, 0x04, 0xE2, 0x05, 0xE6, 0x04, 0x91, 0x05, 0x15, 0x05, 0x13, 0x05, 0xE7, 0x85, 0x50, 0x84, 0x94, 0x85, 0x92, 0x84, 0xFE, 0x09, 0xA3, 0x09, 0xAB, 0x08, 0x27, 0x0B, 0x2F, 0x88, 0xA0, 0x8B, 0xA8, 0x8A, 0xA4, 0x88, 0x2C, 0x89, 0x62, 0x88, 0xAA, 0x89, 0xA6, 0x89, 0x2E, 0x8B, 0x61, 0x8A, 0x69, 0x88, 0xA5, 0x8B, 0xAD, 0x88, 0x63, 0x89, 0x6B, 0x8A, 0x67, 0x00, 0xE5, 0x1F, 0x47, 0x42, 0x4B, 0x22, 0x53, 0x62, 0x5D, 0x12, 0x57, 0x52, 0x5B, 0x32, 0x5B, 0x72, 0x43, 0x0A, 0x4F, 0x4A, 0x57, 0xEA, 0x8F, 0xD4, 0xA6, 0x34, 0xBE, 0xB4, 0x9E, 0x74, 0x8E, 0xF4, 0x96, 0x0C, 0xA1, 0x8C, 0xBE, 0x4C, 0xAE, 0xCC, 0x8E, 0xEC, 0x4F, 0x59, 0x03, 0xD9, 0x7C, 0xD9, 0x5D, 0x39, 0x22, 0x39, 0x23, 0xB9, 0x02, 0xB9, 0x3D, 0x79, 0x62, 0x79, 0x63, 0xF9, 0x42, 0xF9, 0x7D, 0x05, 0x52, 0x05, 0x13, 0x85, 0x22, 0x85, 0x43, 0x45, 0x32, 0x45, 0x53, 0xC5, 0x62, 0xC5, 0x23, 0x25, 0x72, 0x25, 0x73, 0xA5, 0x12, 0xA5, 0x63, 0x65, 0x0A, 0x65, 0x0B, 0xA0, 0xFB, 0x9F, 0xA8, 0x50, 0xA9, 0x58, 0xAA, 0x94, 0xA9, 0x9C, 0xA9, 0x52, 0xAB, 0x5A, 0xA9, 0x56, 0xA8, 0x9E, 0xAB, 0xD1, 0xA8, 0xD9, 0xA8, 0x55, 0xAA, 0x5D, 0xA8, 0xD3, 0xAA, 0xDB, 0xAA, 0x57, 0x01, 0x1D, 0x81, 0x5E, 0xC3, 0x4E, 0xA3, 0x5A, 0xE3, 0x5A, 0x93, 0x41, 0xD3, 0x5E, 0xB3, 0x56, 0xF3, 0x46, 0x8B, 0x51, 0xCB, 0x51, 0xAB, 0x4E, 0xEB, 0x56, 0x9B, 0x49, 0xDB, 0x49, 0xBB, 0x5E, 0xFB, 0x4E, 0x87, 0x45, 0xC7, 0x59, 0xA7, 0x41, 0xE7, 0x41, 0x97, 0x55, 0xD7, 0x45, 0xB7, 0x09, 0x68, 0xFE, 0x6C, 0x7A, 0xAE, 0x7A, 0xCD, 0x7A, 0x4F, 0x80, 0x67, 0xB8, 0xEB, 0xB7, 0xE8, 0x3F, 0x1B, 0x70, 0x1A, 0x78, 0x18, 0xB4, 0x1A, 0xBC, 0x1A, 0x72, 0x19, 0x7A, 0x1A, 0xB6, 0x1B, 0xBE, 0x19, 0x71, 0x1B, 0x79, 0x19, 0x75, 0x18, 0xBD, 0x1B, 0xFF, 0x32, 0xF6, 0x31, 0xEE, 0x34, 0xFE, 0x30, 0xE1, 0x35, 0xF1, 0x35, 0xE9, 0x32, 0xF9, 0x32, 0xE5, 0x33, 0xF5, 0x33, 0xED, 0x31, 0xFB, 0x66, 0xC6, 0x6F, 0xE6, 0x6F, 0xD6, 0x6B, 0x0E, 0x62, 0x2E, 0x00, 0xF8, 0x46, 0x9F, 0x05, 0xA8, 0x85, 0x90, 0x45, 0x90, 0x45, 0xBF, 0x25, 0xB8, 0xA5, 0xB0, 0x65, 0xB0, 0xE5, 0xA0, 0x15, 0x84, 0x95, 0x88, 0xD5, 0x6F, 0xAB, 0x21, 0x6B, 0x48, 0x6B, 0x51, 0xEB, 0x50, 0xEB, 0x61, 0x1B, 0x28, 0x1B, 0x71, 0x9B, 0x30, 0x9B, 0x11, 0x5B, 0x18, 0x5B, 0x09, 0xDB, 0x70, 0xDB, 0x31, 0x3B, 0x58, 0x3B, 0x49, 0xBB, 0x08, 0xC0, 0x3C, 0xE0, 0xEC, 0xA5, 0xEC, 0xA3, 0xEC, 0x27, 0x1C, 0xE0, 0x01, 0xF7, 0x88, 0x76, 0x98, 0x74, 0xFC, 0xE1, 0x28, 0xEB, 0x18, 0xE3, 0x38, 0xED, 0x84, 0xE0, 0x24, 0xE7, 0x14, 0xEB, 0x34, 0xE3, 0x8C, 0xE8, 0x2C, 0xEF, 0x1C, 0xEF, 0x3C, 0xEB, 0x82, 0xE4, 0xA2, 0xE8, 0x92, 0xE0, 0x32, 0xE7, 0x8A, 0xE2, 0xAA, 0xE4, 0x9A, 0xE8, 0x3A, 0xEF, 0x86, 0xEA, 0xA6, 0xEC, 0x96, 0xE4, 0xB6, 0xE0, 0x8E, 0xE6, 0xAE, 0xE2, 0x9E, 0xE2, 0xBE, 0x08, 0x58, 0x88, 0x9A, 0x47, 0xAA, 0xC7, 0x92, 0x27, 0xA6, 0xA7, 0xBA, 0x67, 0x9A, 0xE7, 0xB2, 0x17, 0x96, 0x97, 0x06, 0x50, 0xF8, 0x57, 0xBD, 0xB1, 0xBD, 0x35, 0xBD, 0x33, 0xBD, 0xD7, 0x7C, 0x70, 0x7C, 0xB4, 0x7D, 0xB2, 0x7C, 0xD6, 0x7D, 0xF1, 0x7C, 0x75, 0x7C, 0xB3, 0x7D, 0x37, 0xFC, 0xF0, 0xFD, 0x74, 0xFD, 0xFE, 0xF8, 0x6D, 0xF9, 0x13, 0xF8, 0xEB, 0xF9, 0xE7, 0xFA, 0x6F, 0x07, 0x10, 0x06, 0x18, 0x04, 0xE4, 0x05, 0xEC, 0x04, 0x12, 0x05, 0x1A, 0x06, 0xE6, 0x07, 0xEE, 0x06, 0x11, 0x07, 0x19, 0x05, 0x15, 0x04, 0xED, 0x07, 0x93, 0x04, 0x1B, 0x07, 0x17, 0x01, 0x4E, 0x42, 0xFA, 0xDB, 0xF4, 0xF7, 0xDF, 0xDF, 0x87, 0x21, 0xE4, 0x21, 0x66, 0x80, 0x95, 0x1C, 0x85, 0x52, 0x84, 0x9A, 0x87, 0x96, 0x84, 0x9E, 0x84, 0x51, 0x86, 0x59, 0x84, 0x95, 0x85, 0x9D, 0x86, 0x53, 0x85, 0x5B, 0x85, 0x97, 0x87, 0x9F, 0x45, 0xD0, 0x44, 0x58, 0x47, 0x54, 0x44, 0x9C, 0x47, 0xD2, 0x46, 0xDA, 0x44, 0x56, 0x46, 0x5E, 0x02, 0x75, 0xDF, 0x36, 0xAA, 0x3A, 0xEA, 0x2A, 0x9A, 0x3E, 0xDA, 0x3E, 0xBA, 0x26, 0xFA, 0x3A, 0x86, 0x21, 0xC6, 0x21, 0xA6, 0x36, 0xE6, 0x26, 0x96, 0x29, 0xD6, 0x31, 0xB6, 0x2E, 0xF6, 0x2E, 0x8E, 0x39, 0xCE, 0x29, 0xAE, 0x21, 0xEE, 0x3E, 0x9E, 0x25, 0xDE, 0x25, 0xBE, 0x31, 0xFE, 0x21, 0x81, 0x35, 0xC1, 0x35, 0xA1, 0x29, 0xE1, 0x31, 0x91, 0x3D, 0xD1, 0x2D, 0xB1, 0x39, 0xF1, 0x39, 0x89, 0x23, 0xC9, 0x3D, 0xA9, 0x35, 0xE9, 0x05, 0xF0, 0x15, 0xCF, 0xE4, 0xB6, 0xE4, 0xD7, 0x14, 0xAE, 0x14, 0xAF, 0x94, 0xF6, 0x94, 0xB7, 0xD4, 0x5F, 0xA9, 0xDE, 0xA9, 0x1D, 0xA9, 0x1F, 0x69, 0x3C, 0x69, 0x3E, 0x69, 0x5D, 0x69, 0x9F, 0xE9, 0xBC, 0xE9, 0x7E, 0xE9, 0xDD, 0xE9, 0x5F, 0x19, 0x7C, 0x19, 0xFE, 0x19, 0x3D, 0x99, 0xDF, 0x32, 0x05, 0x32, 0x03, 0x32, 0x7B, 0xB3, 0x40, 0xB3, 0x04, 0xB3, 0x02, 0xB3, 0xFA, 0xB3, 0xC1, 0xB2, 0x85, 0xB2, 0x83, 0xB3, 0x07, 0xFE, 0x80, 0xFF, 0x11, 0x06, 0x2C, 0x66, 0x30, 0x07, 0x22, 0x47, 0x34, 0x27, 0x24, 0x67, 0x28, 0x17, 0x2A, 0x57, 0x2C, 0x37, 0x34, 0x77, 0x24, 0x0F, 0x3A, 0x4F, 0x3C, 0x2F, 0x1C, 0xE8, 0x08, 0x30, 0xF9, 0x12, 0xF9, 0x11, 0xF9, 0x63, 0x05, 0xB0, 0x05, 0x52, 0x05, 0x91, 0x05, 0xE3, 0x85, 0xF0, 0x85, 0xD2, 0x85, 0x51, 0x85, 0x93, 0x45, 0xDF, 0x8B, 0x64, 0x8A, 0xA2, 0x8B, 0xA6, 0x80, 0x8E, 0x20, 0xFB, 0x37, 0xF6, 0xEF, 0x74, 0x31, 0x42, 0xB1, 0x7C, 0x71, 0x5C, 0xF1, 0x4C, 0x09, 0x52, 0x89, 0x42, 0x49, 0x7C, 0xC9, 0x5C, 0x29, 0x72, 0xA9, 0x62, 0x69, 0x42, 0xE9, 0x7C, 0x19, 0x4A, 0x99, 0x52, 0x59, 0x52, 0xD9, 0xBF, 0x72, 0xD4, 0x72, 0x15, 0xC0, 0x70, 0x16, 0x2A, 0xD0, 0x2B, 0x54, 0x01, 0xC7, 0x59, 0xAA, 0xC4, 0xA8, 0x54, 0x03, 0x2C, 0x67, 0xB9, 0x0A, 0xB3, 0x4A, 0xBD, 0x2A, 0xBD, 0x6A, 0xA5, 0x1A, 0xAB, 0x5A, 0x13, 0x30, 0x9D, 0xD5, 0x1A, 0x9C, 0x1A, 0xAD, 0x9A, 0xCC, 0x9A, 0xF5, 0x5A, 0xDC, 0x5A, 0xED, 0xDA, 0xAC, 0xDA, 0x8D, 0x3A, 0xBC, 0x3A, 0x9D, 0xBA, 0x3F, 0x75, 0x9B, 0xF5, 0xF8, 0xF5, 0x7A, 0xF5, 0x39, 0xF5, 0x5B, 0x0D, 0x84, 0x0D, 0xFA, 0x0D, 0xB9, 0x0D, 0x3B, 0x8D, 0x3F, 0x1B, 0x0D, 0x1A, 0xF3, 0x1A, 0x77, 0x9B, 0x88, 0x9A, 0x0C, 0x81, 0x92, 0xB0, 0xD7, 0x4C, 0xDC, 0x6C, 0xDC, 0x5C, 0xD8, 0xBC, 0xDF, 0x42, 0xDA, 0x62, 0xD2, 0x52, 0xD4, 0x72, 0xD8, 0x4A, 0xD6, 0x6A, 0xDA, 0xFA, 0xB7, 0xF5, 0xA8, 0x8D, 0xBC, 0xCD, 0xAC, 0xAD, 0xA4, 0xED, 0xB8, 0x9D, 0xA2, 0xDD, 0xA2, 0xBD, 0x14, 0x28, 0xFF, 0x54, 0x1D, 0x96, 0x1D, 0x65, 0x1D, 0xA7, 0x9D, 0xD4, 0x9D, 0x56, 0x9D, 0xE5, 0x9D, 0xE7, 0x5D, 0x34, 0x5D, 0xD6, 0x5D, 0x95, 0x5D, 0x17, 0xDD, 0xB4, 0xDD, 0xB6, 0xDD, 0x55, 0xDD, 0x97, 0x3D, 0xF4, 0x3D, 0x76, 0x3D, 0xD5, 0x3D, 0x57, 0xBD, 0x0C, 0xBD, 0xF6, 0xBD, 0x35, 0xBD, 0x37, 0x7D, 0x8C, 0x7D, 0x0E, 0x7D, 0x75, 0x7D, 0xB7, 0xFD, 0x4C, 0xFD, 0x4E, 0xFD, 0xF5, 0xFD, 0x77, 0x40, 0x4D, 0x70, 0x1E, 0x68, 0x18, 0xB8, 0x1F, 0x64, 0x1D, 0x74, 0x19, 0x6C, 0x1C, 0x7C, 0x1C, 0x62, 0x1B, 0x72, 0x1D, 0x6A, 0x1E, 0x7A, 0x1A, 0x66, 0x1F, 0x76, 0x1F, 0x6E, 0x19, 0x7E, 0x1E, 0xE1, 0x1C, 0xF1, 0x18, 0x69, 0x1D, 0x79, 0x19, 0xE5, 0x1A, 0xF5, 0x1C, 0x6D, 0x1B, 0x7D, 0x1B, 0xE3, 0x1E, 0xF3, 0x1A, 0xEB, 0x18, 0x7B, 0x1F, 0xFF, 0x35, 0xEE, 0x33, 0xDE, 0x39, 0xFE, 0x31, 0xC1, 0x3B, 0xE1, 0x3B, 0xD1, 0x35, 0xF1, 0x39, 0xC9, 0x37, 0xE9, 0x37, 0xD9, 0x3D, 0xF5, 0x6D, 0x8A, 0x7F, 0xCA, 0x7F, 0xAA, 0x77, 0x1A, 0x64, 0x5A, 0x60, 0x3A, 0x70, 0xBA, 0x6F, 0x06, 0x74, 0x46, 0x68, 0x26, 0x68, 0xA6, 0x7F, 0x16, 0x6C, 0x56, 0x78, 0x36, 0x78, 0x76, 0x60, 0x0E, 0x62, 0x4E, 0x64, 0xEE, 0xF7, 0xDC, 0xD0, 0x3C, 0xE4, 0xBC, 0xE8, 0x7C, 0x28, 0xE0, 0x49, 0x50, 0xFF, 0xC4, 0xFE, 0x85, 0xFD, 0x1B, 0x59, 0x80, 0x5E, 0x90, 0x58, 0x08, 0x5F, 0x18, 0x5D, 0x84, 0x5D, 0x94, 0x5C, 0x8C, 0x58, 0x1C, 0x5F, 0x82, 0x5B, 0x92, 0x5A, 0x8A, 0x5A, 0x9A, 0x58, 0x86, 0x5F, 0x96, 0x5E, 0x8E, 0x5E, 0x9E, 0x5C, 0xF9, 0xBE, 0x22, 0xBB, 0x12, 0xB3, 0x32, 0xB5, 0x8A, 0xB0, 0x2A, 0xB7, 0x1A, 0xBB, 0x3A, 0xB3, 0x86, 0xB8, 0x26, 0xBF, 0x16, 0xBF, 0x36, 0xBB, 0x8E, 0xB4, 0xAE, 0xB0, 0x9E, 0xB0, 0x3E, 0xB7, 0x81, 0xBC, 0xA1, 0xB4, 0x91, 0xB8, 0x31, 0xBF, 0x89, 0xBA, 0xA9, 0xBC, 0x99, 0xB4, 0xB9, 0xB0, 0x85, 0xB6, 0xA5, 0xB2, 0x95, 0xB2, 0xB5, 0xB8, 0x8D, 0xBE, 0xAD, 0xBA, 0x9D, 0xBA, 0xBD, 0xB4, 0x83, 0xB1, 0xA3, 0xBE, 0x93, 0xB6, 0xB3, 0xBC, 0x8B, 0xB5, 0xAB, 0xB1, 0x9B, 0xBE, 0xBB, 0xBA, 0x87, 0xBD, 0xA7, 0xB9, 0x97, 0xB9, 0xB7, 0xB6, 0x8F, 0xB3, 0xAF, 0xB5, 0x9F, 0xB5, 0xBF, 0x7E, 0x80, 0x7B, 0xA0, 0x73, 0x90, 0x7D, 0xB0, 0x71, 0x88, 0x7F, 0xA8, 0x7B, 0xF8, 0xE7, 0x70, 0x0B, 0x28, 0x08, 0x7A, 0x47, 0xB9, 0x47, 0xDB, 0xC7, 0x84, 0xC7, 0xFA, 0xC7, 0x79, 0xC7, 0x3B, 0x27, 0x3F, 0x4F, 0x0C, 0x4F, 0xF2, 0x4F, 0x76, 0x4F, 0x89, 0x4F, 0x8D, 0x4E, 0x0B, 0x4E, 0xF7, 0xCF, 0x48, 0xCE, 0x8C, 0x01, 0x17, 0x3A, 0x38, 0x27, 0x3D, 0x37, 0x39, 0xFF, 0x7B, 0x7E, 0x78, 0x41, 0x76, 0x61, 0x76, 0x51, 0x7C, 0x71, 0x74, 0x49, 0x71, 0x69, 0x7E, 0x59, 0x72, 0x79, 0x72, 0x45, 0x79, 0x65, 0x71, 0x55, 0x7A, 0x75, 0x7A, 0x4D, 0x75, 0x6D, 0x79, 0x5D, 0x7E, 0x7D, 0x76, 0x43, 0x0D, 0x74, 0x83, 0x8A, 0x9B, 0xF3, 0x5B, 0xDA, 0x5B, 0x9B, 0xDB, 0xCA, 0xDB, 0xCB, 0x3B, 0xBA, 0x3B, 0x5B, 0xA0, 0x1A, 0x5C, 0xDD, 0xD3, 0xDF, 0xDB, 0xDD, 0xD7, 0xDC, 0x5F, 0x3F, 0x30, 0x3C, 0x38, 0x3C, 0xD4, 0x3E, 0xDC, 0x3C, 0x32, 0x01, 0xBE, 0x52, 0xF7, 0x78, 0xF7, 0xC4, 0xFC, 0xE4, 0xF4, 0x54, 0xFF, 0x74, 0xFF, 0xCC, 0xF2, 0xEC, 0xFC, 0xDC, 0xF8, 0xFC, 0xF0, 0xC2, 0xFA, 0xE2, 0xFA, 0xD2, 0xF4, 0xF2, 0xF8, 0xCA, 0xFE, 0xEA, 0xF6, 0xDA, 0xFC, 0xFA, 0xFC, 0xC6, 0xF1, 0xE6, 0xFE, 0xD6, 0xF2, 0xF6, 0xF2, 0xCE, 0xF9, 0xEE, 0x01, 0x78, 0xC5, 0xEB, 0x07, 0xD7, 0x87, 0xD7, 0x47, 0xFB, 0xC7, 0xDB, 0xE7, 0xAF, 0x4F, 0xEF, 0xCF, 0x8E, 0xCF, 0x8F, 0x2F, 0x9E, 0x2F, 0x9F, 0xAF, 0xCE, 0xAF, 0xCF, 0xAF, 0xFF, 0xC1, 0xB2, 0x3D, 0x18, 0x48, 0x60, 0x05, 0x61, 0x00, 0xBE, 0xB5, 0x8D, 0xB3, 0x6D, 0x63, 0x6D, 0xDB, 0x4E, 0x2B, 0x59, 0xDB, 0x6A, 0xE7, 0xD6, 0xB6, 0xDA, 0x49, 0x5E, 0x30, 0x4D, 0x0C, 0xBE, 0xF9, 0xFF, 0xAF, 0x7F, 0x62, 0x34, 0x20, 0x08, 0xFA, 0xBB, 0xF5, 0x17, 0x44, 0x00, 0xF9, 0x13, 0xF2, 0x0B, 0xDD, 0x82, 0x0A, 0xA1, 0x7E, 0x68, 0x0D, 0xB6, 0x05, 0x13, 0xC2, 0xFC, 0xB0, 0x1A, 0x98, 0x11, 0x84, 0x70, 0x3F, 0xBC, 0x86, 0xD8, 0x42, 0x08, 0x11, 0x7E, 0x44, 0x0D, 0x09, 0x41, 0x8A, 0x90, 0x01, 0x64, 0x1D, 0x05, 0x41, 0x89, 0x50, 0x01, 0x54, 0x1D, 0x0D, 0x41, 0x8B, 0xD0, 0x01, 0x74, 0x1D, 0x03, 0xC1, 0x88, 0x30, 0x01, 0x4C, 0x1D, 0x0B, 0xC5, 0x8A, 0xB1, 0x41, 0x6C, 0x03, 0x07, 0xC5, 0x89, 0x71, 0x41, 0x5C, 0x03, 0x0F, 0xC5, 0x8B, 0xF1, 0x41, 0x7C, 0x83, 0x00, 0x25, 0x88, 0x09, 0x41, 0x42, 0x83, 0x08, 0x23, 0x4A, 0x88, 0x21, 0x62, 0x93, 0x04, 0x23, 0x49, 0x48, 0x21, 0x52, 0x93, 0x0C, 0x23, 0x4B, 0xC8, 0x21, 0x72, 0x93, 0x02, 0xA3, 0x48, 0x28, 0x21, 0x4A, 0x93, 0x0A, 0xA7, 0x4A, 0xA9, 0x61, 0x6A, 0x8B, 0x06, 0xA7, 0x49, 0x69, 0x61, 0x5A, 0x8B, 0x0E, 0x07, 0x56, 0x10, 0xA6, 0xB7, 0x18, 0x70, 0x86, 0x94, 0x11, 0x66, 0xB4, 0x98, 0x08, 0x70, 0x23, 0x88, 0x30, 0xDB, 0xDB, 0x88, 0x6D, 0xD9, 0x76, 0x64, 0xBB, 0xBD, 0x83, 0xD8, 0x91, 0xED, 0x44, 0x76, 0xDA, 0xBB, 0x88, 0x5D, 0xD9, 0x6E, 0x64, 0xB7, 0x0D, 0xA4, 0x40, 0xBE, 0x17, 0xDD, 0xEB, 0xEC, 0x23, 0xF7, 0xE5, 0xFB, 0xD1, 0xFD, 0xCE, 0x01, 0xF2, 0x40, 0x7E, 0x10, 0x3D, 0xE8, 0x1C, 0x22, 0x0F, 0xE5, 0x87, 0xD1, 0xC3, 0xCE, 0x11, 0xEA, 0x48, 0x71, 0x14, 0x3B, 0xEA, 0x1E, 0xA3, 0x8E, 0x15, 0xC7, 0xB1, 0xE3, 0xEE, 0x09, 0xEA, 0x44, 0x71, 0x12, 0x3B, 0xE9, 0x02, 0x29, 0x50, 0x9C, 0xC6, 0x4E, 0xBB, 0x67, 0xE8, 0x33, 0xE5, 0x59, 0xFC, 0xAC, 0x77, 0x8E, 0x3E, 0x57, 0x9E, 0xC7, 0xCF, 0x7B, 0x17, 0xE8, 0x0B, 0xE5, 0x45, 0xFC, 0xA2, 0x77, 0x89, 0xBE, 0x54, 0x5E, 0xC6, 0x2F, 0x7B, 0x57, 0x98, 0x2B, 0xD5, 0x55, 0xE2, 0xAA, 0x7F, 0x8D, 0xB9, 0x56, 0x01, 0x2D, 0xE8, 0xDF, 0x60, 0x6E, 0x54, 0x37, 0x09, 0x70, 0x2B, 0xC0, 0xDC, 0xAA, 0x6E, 0x13, 0xB7, 0xFD, 0x3B, 0xEC, 0x9D, 0x1A, 0x7C, 0x00, 0x0C, 0xEE, 0xB1, 0xF7, 0xEA, 0xFB, 0xE4, 0xFD, 0xE0, 0x01, 0xFB, 0xA0, 0x7E, 0x48, 0x3E, 0x0C, 0x1E, 0xB1, 0x8F, 0xEA, 0xC7, 0xE4, 0xE3, 0xE0, 0x09, 0xF7, 0xA4, 0x79, 0x4A, 0x3D, 0x0D, 0x9F, 0x71, 0xCF, 0x9A, 0xE7, 0xD4, 0xF3, 0xF0, 0x05, 0xF7, 0xA2, 0x79, 0x49, 0x01, 0x33, 0xC0, 0xBD, 0x6A, 0x5E, 0x53, 0xAF, 0xC3, 0x37, 0xFC, 0x9B, 0xF6, 0x2D, 0xFD, 0x36, 0x7A, 0xC7, 0x83, 0xBB, 0x41, 0xFA, 0x7D, 0xF4, 0x81, 0xFF, 0xD0, 0x7E, 0xA4, 0x3F, 0x46, 0x9F, 0xF8, 0x4F, 0xED, 0x67, 0xFA, 0x73, 0xF4, 0x45, 0xF8, 0xD2, 0x7D, 0x65, 0xBE, 0xC6, 0xDF, 0x84, 0x6F, 0xDD, 0x77, 0xE6, 0x7B, 0xFC, 0x43, 0x00, 0xFE, 0x9F, 0xF9, 0x19, 0xB3, 0x08, 0x2C, 0x1D, 0x2B, 0xC3, 0x1A, 0x03, 0x39, 0xD0, 0xB3, 0xB3, 0xEC, 0x09, 0x87, 0xC8, 0xD1, 0x73, 0xB2, 0x9C, 0x09, 0x97, 0xC8, 0xD5, 0x73, 0xB3, 0xDC, 0x09, 0xB0, 0x03, 0x3D, 0x2F, 0xCB, 0x9B, 0xF0, 0x49, 0x7C, 0x03, 0x3F, 0xC7, 0x9F, 0x0A, 0x48, 0xFF, 0x4F, 0x00, 0x24, 0xA1, 0x41, 0x98, 0x13, 0x4E, 0x45, 0x24, 0x91, 0x41, 0x94, 0x13, 0x4D, 0xC5, 0x64, 0xB1, 0x51, 0x9C, 0x17, 0xCF, 0x24, 0x64, 0x89, 0x51, 0x92, 0x97, 0xCC, 0xA4, 0x64, 0xA9, 0x51, 0x9A, 0x97, 0xCE, 0xC0, 0x2D, 0xC1, 0x28, 0xCB, 0xCB, 0x66, 0x72, 0x0A, 0xF8, 0xFA, 0x2B, 0xC8, 0xE7, 0x0A, 0x8A, 0xC2, 0xA4, 0x28, 0x28, 0xE6, 0x4A, 0x8A, 0xD2, 0xA4, 0x2C, 0x28, 0xE7, 0x2A, 0x8A, 0xCA, 0xA4, 0x2A, 0xA8, 0xE6, 0x6A, 0x2A, 0xB0, 0xFF, 0xA2, 0x7A, 0xA1, 0xA1, 0x6A, 0xCC, 0x9A, 0xA2, 0x66, 0xA1, 0xA5, 0x6A, 0xCD, 0xC0, 0x10, 0x16, 0x3A, 0xAA, 0xCE, 0xAC, 0x2B, 0xEA, 0x16, 0x7A, 0x9A, 0xDE, 0xA2, 0x2F, 0xE9, 0x97, 0x06, 0x9A, 0xC1, 0x62, 0x28, 0x19, 0x96, 0x46, 0x9A, 0xD1, 0x62, 0x2C, 0x19, 0x97, 0x26, 0x9A, 0xC9, 0x02, 0x2E, 0x0B, 0x4B, 0x33, 0xDD, 0x6C, 0x35, 0x97, 0xCD, 0x2B, 0x0B, 0xDD, 0x62, 0xB5, 0x94, 0x2D, 0x2B, 0x2B, 0xDD, 0x6A, 0xB5, 0x96, 0xAD, 0x2B, 0x1B, 0xDD, 0x66, 0xB5, 0x95, 0x6D, 0x2B, 0x3B, 0xC3, 0x6E, 0xB3, 0x57, 0xEC, 0x6B, 0x07, 0xC3, 0x61, 0x73, 0x54, 0x1C, 0x6B, 0x27, 0xC3, 0x69, 0x73, 0x56, 0x9C, 0x6B, 0x17, 0xC3, 0x65, 0x73, 0x55, 0x5C, 0x6B, 0x37, 0xD3, 0x6D, 0x77, 0x57, 0xDD, 0x1B, 0x0F, 0xD3, 0x63, 0xF7, 0x54, 0x3D, 0x1B, 0x2F, 0xD3, 0x6B, 0xF7, 0x56, 0xBD, 0x1B, 0x1F, 0xD3, 0x67, 0xF7, 0x55, 0x7D, 0x9B, 0x3F, 0xFE, 0x66, 0xD1, 0x1C, 0x10, 0x53, 0x0F, 0x00, 0x38, 0x7C, 0x8C, 0x6C, 0x77, 0xA1, 0x6C, 0xDB, 0x35, 0x23, 0xD7, 0xCB, 0x43, 0x7F, 0x9B, 0xED, 0x3E, 0xB3, 0xBD, 0x9D, 0xE2, 0x4D, 0xA7, 0xF8, 0xE1, 0xFB, 0x24, 0x7E, 0xC7, 0x97, 0x0D, 0x78, 0x16, 0x90, 0x04, 0x1C, 0x81, 0x65, 0xE0, 0x2C, 0x28, 0x09, 0x3A, 0x82, 0xCB, 0xE0, 0x59, 0x48, 0x12, 0x72, 0x84, 0x96, 0xA1, 0xB3, 0xB0, 0x34, 0xEC, 0x0C, 0x03, 0x5F, 0x3E, 0xA0, 0x34, 0xE2, 0x8C, 0x00, 0x91, 0xF3, 0xA8, 0x34, 0xEA, 0x8C, 0x02, 0xD1, 0xF3, 0x98, 0x34, 0xE6, 0x8C, 0x01, 0xB1, 0xF3, 0xB8, 0x2C, 0xEE, 0x8A, 0x83, 0xF1, 0x8B, 0x84, 0x2C, 0xE1, 0x4A, 0x80, 0x89, 0x8B, 0xA4, 0x2C, 0xE9, 0x4A, 0x82, 0xC9, 0x8B, 0x94, 0x2C, 0xE5, 0x4A, 0x81, 0xA9, 0x8B, 0xB4, 0x3C, 0xED, 0x4E, 0x43, 0xE9, 0xCB, 0x8C, 0x3C, 0xE3, 0xCE, 0x40, 0x99, 0xCB, 0xAC, 0x3C, 0xEB, 0xCE, 0x42, 0xD9, 0xCB, 0x9C, 0x3C, 0xE7, 0xCE, 0x41, 0xB9, 0xCB, 0xBC, 0x22, 0xEF, 0xC9, 0xC3, 0xF9, 0xAB, 0x82, 0xA2, 0xE0, 0x29, 0xC0, 0x85, 0xAB, 0xA2, 0xA2, 0xE8, 0x29, 0xC2, 0xC5, 0xAB, 0x92, 0xA2, 0xE4, 0x29, 0xC1, 0xA5, 0xAB, 0xB2, 0xB2, 0xEC, 0x2D, 0x23, 0xE5, 0xEB, 0x8A, 0xB2, 0xE2, 0xAD, 0x20, 0x95, 0xEB, 0xAA, 0xB2, 0xEA, 0xAD, 0x22, 0xD5, 0xEB, 0x9A, 0xB2, 0xE6, 0xAD, 0x21, 0xB5, 0xEB, 0xBA, 0xAA, 0xEE, 0xAB, 0xA3, 0xF5, 0x9B, 0x86, 0xAA, 0xE1, 0x6B, 0xA0, 0x8D, 0x9B, 0x35, 0xD5, 0x9A, 0x6F, 0x0D, 0x5D, 0xBB, 0x59, 0x57, 0xAD, 0xFB, 0xD6, 0xD1, 0x2F, 0xCA, 0xAF, 0xDE, 0xF0, 0x6F, 0x60, 0x1B, 0xB7, 0x9B, 0xEA, 0x4D, 0xFF, 0x26, 0xB6, 0x79, 0xBB, 0xA5, 0xDE, 0xF2, 0x6F, 0x61, 0x5F, 0x3C, 0x41, 0xBD, 0xED, 0xDF, 0xC6, 0xB6, 0x6F, 0x77, 0x34, 0x3B, 0x81, 0x1D, 0x7C, 0xE7, 0x6E, 0x57, 0xB3, 0x1B, 0xD8, 0xC5, 0xFF, 0x3A, 0x00, 0xBE, 0x77, 0xB7, 0xAF, 0xF9, 0xFA, 0x24, 0xF0, 0xFD, 0xBB, 0xA6, 0xB6, 0x19, 0x6C, 0x12, 0xCD, 0xFB, 0x96, 0xB6, 0x15, 0x6C, 0x11, 0xAD, 0xFB, 0xB6, 0xB6, 0x1D, 0x6C, 0x13, 0xED, 0xFB, 0x8E, 0xB6, 0x13, 0xEC, 0x10, 0x9D, 0xFB, 0xAE, 0xAE, 0x1B, 0xEA, 0x92, 0xDD, 0x87, 0x9E, 0xAE, 0x17, 0xEA, 0x91, 0xBD, 0x87, 0xBE, 0xAE, 0x1F, 0xEA, 0x93, 0xFD, 0x87, 0x81, 0x6E, 0x10, 0x1A, 0x90, 0x83, 0x87, 0xA1, 0x7E, 0x18, 0x1E, 0x52, 0xC3, 0xC7, 0x7F, 0xFA, 0x2F, 0x9E, 0x40, 0xFD, 0x7B, 0x1C, 0xE9, 0x47, 0xE1, 0x11, 0x35, 0x7A, 0x1C, 0xEB, 0xC7, 0xE1, 0x31, 0x35, 0x7E, 0x9C, 0x18, 0x26, 0x91, 0x09, 0x3D, 0x79, 0x9A, 0x1A, 0xA6, 0x91, 0x29, 0x3D, 0x7D, 0x9A, 0x19, 0x66, 0x91, 0x19, 0x3D, 0x7B, 0x9A, 0x1B, 0xE6, 0x91, 0x39, 0x3D, 0x7F, 0x5A, 0x18, 0x17, 0xD1, 0x05, 0xB3, 0x78, 0x3E, 0x30, 0x1E, 0x44, 0x0F, 0x98, 0x83, 0xE7, 0xAF, 0xC7, 0x22, 0x7A, 0xC8, 0x1C, 0x3E, 0x1F, 0x19, 0x8F, 0xA2, 0x47, 0xCC, 0xD1, 0xF3, 0x17, 0x4F, 0x88, 0x1D, 0xB3, 0xC7, 0x2F, 0x4B, 0xD3, 0x32, 0xB6, 0x64, 0x97, 0x2F, 0x80, 0x09, 0x88, 0x01, 0xEC, 0x97, 0x23, 0x68, 0x02, 0x63, 0x20, 0x0B, 0xBE, 0x40, 0x66, 0x28, 0x0E, 0x71, 0xD0, 0x2B, 0x6C, 0x86, 0xE3, 0x30, 0x07, 0xBF, 0x22, 0x66, 0x24, 0x8E, 0x70, 0xC8, 0x2B, 0x6A, 0x46, 0xE3, 0x28, 0x87, 0xBE, 0x62, 0x16, 0x2C, 0x81, 0xF1, 0xD8, 0x1B, 0x6E, 0xC1, 0x13, 0x38, 0x8F, 0xBF, 0x11, 0x16, 0x22, 0x41, 0xF0, 0xC4, 0x1B, 0x69, 0x21, 0x13, 0x24, 0x4F, 0xBE, 0x51, 0x56, 0x2A, 0x49, 0x09, 0xD4, 0x3B, 0x6D, 0xA5, 0x93, 0xB4, 0x40, 0xBF, 0x33, 0x56, 0x26, 0xC9, 0x08, 0xCC, 0x3B, 0x6B, 0x65, 0x93, 0xAC, 0xC0, 0xBE, 0x73, 0x36, 0x2E, 0xC5, 0x89, 0xDC, 0x07, 0x6F, 0xE3, 0x53, 0xBC, 0xC8, 0x7F, 0x08, 0x36, 0x21, 0x25, 0x88, 0xC2, 0x87, 0x68, 0x13, 0x53, 0xA2, 0x28, 0x7E, 0xAC, 0xEC, 0xAB, 0xF4, 0x6A, 0xB5, 0xFA, 0x3C, 0xB1, 0x9F, 0xFC, 0xE7, 0xD1, 0x1E, 0xF0, 0x5B, 0x0B, 0xA3, 0x20, 0x80, 0xAF, 0xA7, 0x6E, 0x8C, 0xAE, 0xA8, 0xB6, 0x77, 0xD4, 0x6B, 0x2B, 0xA8, 0x11, 0xDB, 0x76, 0x72, 0x15, 0xF3, 0xE9, 0xFB, 0xE9, 0xAD, 0xE2, 0x9C, 0x99, 0xF9, 0x1F, 0x40, 0x4F, 0x50, 0x0F, 0x5E, 0x87, 0x0F, 0xE0, 0x27, 0xB8, 0x87, 0xAC, 0x23, 0x07, 0xC8, 0x13, 0xD2, 0x43, 0x37, 0xD0, 0x43, 0x14, 0x42, 0x65, 0x6C, 0x03, 0x3B, 0xC4, 0x20, 0x4C, 0xC6, 0x37, 0xF0, 0x43, 0x1C, 0xC2, 0x65, 0x62, 0x83, 0x38, 0x24, 0x20, 0x42, 0x26, 0x37, 0xC9, 0x23, 0x12, 0x26, 0x15, 0xE0, 0x05, 0x8F, 0x28, 0x98, 0x52, 0xE8, 0x4D, 0xFA, 0x88, 0x86, 0x69, 0x85, 0xD9, 0x64, 0x8E, 0x18, 0x98, 0x51, 0xD8, 0x2D, 0xF6, 0x98, 0x45, 0x58, 0x95, 0xDB, 0xE2, 0x8E, 0x39, 0x84, 0x53, 0xF9, 0x2D, 0xFE, 0x98, 0x47, 0x78, 0x55, 0xD8, 0x12, 0x8E, 0x05, 0x44, 0x50, 0xC5, 0x6D, 0xF1, 0x44, 0x44, 0x45, 0x4D, 0xDA, 0x96, 0x4E, 0x24, 0x54, 0xD2, 0x5C, 0xDB, 0xAE, 0x13, 0x17, 0xEA, 0xD2, 0xDC, 0xDB, 0xEE, 0x13, 0x37, 0xEA, 0xD6, 0x3C, 0x3B, 0x9E, 0x53, 0x0F, 0x06, 0xBA, 0x90, 0x1D, 0xEF, 0xA9, 0x17, 0xF3, 0xEA, 0xFF, 0xBF, 0x80, 0x9D, 0x97, 0xD3, 0x17, 0xEC, 0x45, 0x7F, 0xDD, 0x7D, 0x3D, 0x7B, 0xC5, 0x5F, 0xFB, 0x6F, 0xBB, 0x6F, 0x67, 0x6F, 0xF8, 0x5B, 0xFF, 0x7D, 0xF7, 0xFD, 0xEC, 0x1D, 0x7F, 0xEF, 0x03, 0x0F, 0x70, 0xF6, 0x81, 0x7F, 0xF4, 0x3F, 0x0D, 0x9F, 0xE7, 0x9F, 0xC4, 0xE7, 0xE0, 0xCB, 0x00, 0x4C, 0x00, 0xF1, 0x35, 0xF8, 0x36, 0x7C, 0x9F, 0x7F, 0x13, 0xDF, 0x83, 0x1F, 0x03, 0xF0, 0x83, 0xC4, 0xCF, 0xC0, 0x67, 0xF4, 0x5D, 0xF8, 0x48, 0xDF, 0xD0, 0x6F, 0x04, 0x82, 0x90, 0xF4, 0x0F, 0x03, 0xC6, 0xC0, 0x45, 0x80, 0x0C, 0x0C, 0x83, 0x46, 0x60, 0x08, 0xC9, 0xE0, 0x30, 0x64, 0x0A, 0x5D, 0x86, 0xA8, 0xD0, 0x28, 0x6C, 0x02, 0x8A, 0x90, 0x0A, 0x8F, 0x22, 0xA6, 0xC8, 0x65, 0x84, 0x02, 0x7B, 0x82, 0x29, 0x7A, 0x19, 0xA5, 0xA2, 0xA3, 0x98, 0x39, 0x76, 0x15, 0xA3, 0x63, 0xE3, 0xB8, 0x19, 0x48, 0x42, 0x3A, 0x3E, 0x4E, 0x98, 0x13, 0x57, 0x09, 0x3A, 0x31, 0x4E, 0x9A, 0x81, 0x25, 0xA4, 0x93, 0xE3, 0x94, 0x25, 0x75, 0x9D, 0x62, 0x52, 0x93, 0xB4, 0x25, 0x7D, 0x9D, 0x66, 0xD2, 0x93, 0x8C, 0x25, 0x73, 0x9D, 0x61, 0x32, 0x93, 0xAC, 0x25, 0x7B, 0x9D, 0x65, 0xB2, 0x93, 0x9C, 0x35, 0x77, 0x93, 0x63, 0x73, 0xD3, 0xBC, 0x35, 0x7F, 0x93, 0x67, 0xC1, 0x9A, 0x60, 0x2D, 0xDC, 0x14, 0xD8, 0xC2, 0xB4, 0x68, 0x2D, 0xDE, 0x14, 0xD9, 0xE2, 0xB4, 0x64, 0x2B, 0xDD, 0x96, 0xB8, 0xD2, 0xAC, 0x6C, 0x2B, 0xDF, 0x96, 0xB9, 0xF2, 0xAC, 0x62, 0xAB, 0xDC, 0x56, 0xB8, 0xCA, 0xAC, 0x6A, 0xAB, 0xDE, 0x56, 0xB9, 0xEA, 0xAC, 0x66, 0xAF, 0xDD, 0xD5, 0xF8, 0xDA, 0xBC, 0x6E, 0xAF, 0xDF, 0xD5, 0xF9, 0xFA, 0xBC, 0x61, 0x6F, 0xDC, 0x35, 0xF8, 0xC6, 0xBC, 0x69, 0x6F, 0xDE, 0x35, 0xF9, 0xE6, 0xBC, 0xE5, 0x68, 0xDD, 0xB7, 0x84, 0xD6, 0xA2, 0xED, 0x68, 0xDF, 0x03, 0x41, 0xB0, 0xE8, 0x38, 0x3A, 0xF7, 0x1D, 0xA1, 0xB3, 0xE8, 0x3A, 0xBA, 0xF7, 0x5D, 0xA1, 0xBB, 0xE8, 0x39, 0x41, 0x37, 0x22, 0xF6, 0x96, 0xB2, 0x53, 0x7E, 0x90, 0x45, 0x79, 0xA9, 0x38, 0xC1, 0x86, 0x20, 0x2A, 0x4B, 0xD5, 0xA9, 0x3E, 0xA8, 0xA2, 0xBA, 0xD4, 0xF6, 0xB4, 0x47, 0x4D, 0xD2, 0x56, 0xFA, 0x9E, 0xFE, 0xA8, 0x4B, 0xFA, 0x3F, 0xF6, 0xEE, 0xC2, 0xAB, 0xEA, 0xED, 0x51, 0x02, 0xF8, 0xD0, 0x88, 0x60, 0x00, 0xB6, 0xA8, 0xD7, 0x16, 0xBB, 0x03, 0x04, 0xEC, 0x6E, 0x6C, 0x41, 0x50, 0x30, 0x29, 0xA5, 0xBB, 0x15, 0x10, 0x24, 0x04, 0x11, 0x41, 0x3A, 0x4C, 0x6C, 0x41, 0x45, 0xB1, 0xAE, 0xDD, 0x71, 0x11, 0xBB, 0x13, 0x91, 0xCE, 0x03, 0xF3, 0xCE, 0x5E, 0xDF, 0x3F, 0xE3, 0xFD, 0x56, 0x7D, 0xD6, 0xAC, 0x9A, 0x39, 0xB9, 0xB7, 0x49, 0x63, 0x99, 0x41, 0x99, 0x67, 0xD9, 0xC5, 0xB2, 0xC6, 0x72, 0x83, 0x72, 0xCF, 0xF2, 0x8B, 0xE5, 0x8D, 0x15, 0x86, 0x15, 0x5E, 0x15, 0x05, 0x15, 0xB2, 0x4A, 0xC3, 0x4A, 0xAF, 0xCA, 0x82, 0x4A, 0x59, 0x95, 0x61, 0x95, 0x57, 0x55, 0x41, 0x95, 0xAC, 0xDA, 0xB0, 0xDA, 0xAB, 0xBA, 0xA0, 0x5A, 0x56, 0x33, 0xB1, 0xC6, 0xBB, 0xE6, 0x52, 0x4D, 0x53, 0xED, 0xC4, 0x5A, 0xEF, 0xDA, 0x4B, 0xB5, 0x4D, 0x75, 0x13, 0xEB, 0xBC, 0xEB, 0x2E, 0xD5, 0x35, 0xD5, 0x4F, 0xAC, 0xF7, 0xAE, 0xBF, 0x54, 0xDF, 0xD4, 0x60, 0xD4, 0xE0, 0xD3, 0x70, 0xB9, 0xA1, 0xB9, 0xD1, 0xA8, 0xD1, 0xA7, 0xF1, 0x72, 0x63, 0xB3, 0xCC, 0x48, 0xE6, 0x23, 0xBB, 0x2C, 0x6B, 0x6E, 0x32, 0x6A, 0xF2, 0x69, 0xBA, 0xDC, 0xD4, 0xDC, 0x6C, 0xDC, 0xEC, 0xDB, 0x5C, 0xD8, 0x4C, 0x1A, 0xD3, 0x97, 0x85, 0xFF, 0x3B, 0xFF, 0xFF, 0x77, 0xFE, 0xFF, 0xEF, 0xFC, 0xFF, 0xDF, 0xF9, 0xFF, 0xBF, 0xF3, 0xFF, 0x7F, 0xE7, 0xFF, 0xFF, 0xCE, 0xFF, 0xFF, 0x8F, 0xE7, 0x3F, 0x19, 0x33, 0x1D, 0x98, 0xE8, 0x49, 0x6E, 0x5F, 0x08, 0x58, 0x80, 0xDC, 0x1C, 0x04, 0x6C, 0x0E, 0x22, 0xFB, 0x26, 0x02, 0x3B, 0x12, 0x49, 0x00, 0x88, 0x1A, 0x27, 0xD4, 0xFE, 0x2F, 0xE6, 0x85, 0xD0, 0x04, 0x91, 0xC6, 0xC2, 0xD9, 0xDD, 0xA3, 0x9F, 0x0B, 0xB7, 0xC4, 0x47, 0x9E, 0x13, 0x6E, 0x97, 0x7F, 0xD1, 0x0B, 0x53, 0xE8, 0xAD, 0x2B, 0xBC, 0xBD, 0x68, 0x43, 0x1B, 0xB2, 0x07, 0xAA, 0x7E, 0x59, 0x40, 0xE4, 0xE6, 0x8F, 0x0E, 0xAF, 0x3E, 0x5C, 0x02, 0x64, 0xF7, 0x1D, 0x46, 0xDF, 0x7F, 0x07, 0xD4, 0xEF, 0xB7, 0xFF, 0x54, 0xA0, 0x04, 0xD4, 0x39, 0x3B, 0xF4, 0x23, 0x13, 0x09, 0x8C, 0x1B, 0x49, 0xFA, 0x01, 0x58, 0xD5, 0x44, 0xDA, 0x44, 0x03, 0x36, 0xD1, 0xA4, 0x05, 0x5A, 0x67, 0x39, 0xA6, 0x4A, 0x3B, 0x62, 0x9B, 0x84, 0x6D, 0x53, 0xA2, 0x93, 0xA5, 0x1D, 0xBB, 0x43, 0x85, 0xB3, 0x3E, 0x45, 0xBE, 0x17, 0xDA, 0x14, 0x47, 0x0C, 0x12, 0xBA, 0x39, 0x86, 0xD4, 0x0B, 0x73, 0x56, 0xBB, 0x94, 0x0A, 0x8B, 0xAA, 0xEC, 0x9F, 0x92, 0x43, 0x8C, 0x9A, 0x16, 0x5A, 0xE0, 0x7B, 0x31, 0x20, 0x8B, 0x75, 0x5E, 0xF4, 0x70, 0x3A, 0x50, 0xAF, 0xEF, 0x64, 0x7D, 0xF1, 0x31, 0x50, 0x4B, 0x27, 0x87, 0x63, 0xEF, 0x81, 0xBA, 0xB6, 0xCE, 0x36, 0x64, 0x0A, 0x81, 0x31, 0xDF, 0xC8, 0xA0, 0x05, 0xC0, 0xAA, 0x7C, 0xD2, 0x63, 0x3E, 0xB0, 0xD9, 0x9B, 0x5C, 0xF7, 0x0E, 0xF0, 0x5E, 0x20, 0xED, 0xD8, 0xAF, 0x24, 0xD4, 0x4D, 0x8A, 0x4D, 0xA4, 0xB4, 0x63, 0x85, 0x70, 0xE6, 0xB6, 0xC8, 0x10, 0xE1, 0x56, 0xBF, 0x5D, 0x7E, 0x42, 0x3F, 0xEC, 0x38, 0x26, 0x2C, 0xA4, 0x7D, 0x3B, 0x61, 0xD9, 0x53, 0x8F, 0x16, 0xE5, 0x7B, 0x00, 0x99, 0xAE, 0x67, 0xFC, 0xE3, 0x63, 0x40, 0xFD, 0x68, 0xF7, 0xB0, 0x8B, 0x6E, 0x40, 0xCD, 0x67, 0xF7, 0xCD, 0x87, 0xED, 0xE5, 0x2E, 0xF5, 0x70, 0x3D, 0x30, 0x41, 0xEE, 0x04, 0x4F, 0x0D, 0x32, 0xCD, 0x08, 0x18, 0xFB, 0x87, 0x4C, 0xEE, 0x0D, 0xCC, 0xDC, 0x2E, 0x3D, 0x2F, 0x9B, 0x3F, 0x91, 0x2E, 0x65, 0x80, 0x7B, 0x3F, 0x72, 0xC4, 0x2D, 0x20, 0xE6, 0x16, 0x09, 0xA8, 0xAD, 0x3E, 0xB0, 0x4A, 0x38, 0x3E, 0x39, 0x72, 0x82, 0x70, 0xDA, 0xF9, 0xA8, 0x39, 0xC2, 0xAD, 0xC5, 0xBB, 0x8A, 0x85, 0xFB, 0x5A, 0xF8, 0x6B, 0x09, 0x1F, 0xAD, 0xF7, 0xDA, 0x22, 0x6C, 0x4C, 0x09, 0xF0, 0x78, 0xF6, 0x12, 0xA8, 0xE9, 0xE9, 0xD7, 0xFE, 0x7C, 0x16, 0x50, 0x65, 0xE5, 0x1B, 0x97, 0x9D, 0x0A, 0x54, 0xCE, 0xF6, 0x5B, 0xB6, 0x77, 0x3B, 0x50, 0x91, 0xE4, 0xE7, 0x19, 0xF2, 0x9F, 0xDC, 0x09, 0x7E, 0xE6, 0x64, 0x76, 0x33, 0x30, 0xFA, 0x93, 0xF4, 0xBC, 0xCC, 0x6A, 0x4B, 0x46, 0x1C, 0x02, 0x36, 0x74, 0x25, 0xBD, 0x9C, 0x00, 0x2F, 0x27, 0x72, 0xF9, 0x5A, 0x20, 0x2A, 0x94, 0xD4, 0x74, 0xD7, 0x74, 0x4F, 0x21, 0x09, 0x0C, 0x9E, 0xBF, 0xDF, 0x5D, 0x38, 0x69, 0x45, 0xF4, 0x48, 0xA1, 0x8D, 0x65, 0xB8, 0xA5, 0x30, 0x85, 0x3E, 0x4E, 0xC2, 0x72, 0xFF, 0x9D, 0xD9, 0xC5, 0x17, 0x81, 0xDA, 0x9E, 0x3B, 0x66, 0xE5, 0x8F, 0x07, 0x2A, 0x5C, 0x82, 0xCF, 0xA5, 0x65, 0xCA, 0xBD, 0xBE, 0x43, 0x33, 0x72, 0x37, 0x50, 0x39, 0x34, 0xF8, 0x8E, 0x9F, 0xA1, 0x3C, 0xCF, 0x09, 0x9E, 0xE6, 0x94, 0x23, 0x57, 0x39, 0xE8, 0x3E, 0x79, 0xF4, 0x02, 0x30, 0xAA, 0x17, 0x79, 0x38, 0x0B, 0x30, 0x01, 0x79, 0xC0, 0x01, 0xB0, 0xD8, 0x4D, 0x06, 0x76, 0x07, 0xBC, 0xDF, 0x93, 0x16, 0x00, 0xF6, 0x64, 0x91, 0xA3, 0x6B, 0x55, 0xBE, 0x88, 0x1D, 0x3A, 0xF2, 0xAF, 0x1A, 0x21, 0x60, 0x82, 0xBD, 0xEA, 0x42, 0x5B, 0x95, 0x08, 0x15, 0x61, 0xC1, 0x8A, 0x10, 0xFC, 0xDC, 0x09, 0x34, 0xE8, 0x44, 0xBA, 0x9E, 0x6D, 0x00, 0x2A, 0x74, 0x22, 0x26, 0x27, 0xBC, 0x01, 0x2A, 0x67, 0x85, 0x57, 0x04, 0xF7, 0x96, 0xDB, 0x62, 0x57, 0xA5, 0x73, 0x27, 0xA0, 0x62, 0xD8, 0xAE, 0xB6, 0x9B, 0x0F, 0xCB, 0xBD, 0x18, 0xE6, 0x66, 0xF6, 0x4B, 0xEE, 0x81, 0xB0, 0xA9, 0xE4, 0xE9, 0xF7, 0xC0, 0xD0, 0xD3, 0xE4, 0x89, 0x9B, 0xD2, 0x8E, 0x4C, 0x43, 0xC0, 0xFC, 0x3A, 0x99, 0xF0, 0x1A, 0x70, 0x31, 0x95, 0x5E, 0xA7, 0x88, 0x5B, 0xD2, 0x1E, 0xA9, 0xBF, 0xFD, 0xAA, 0x93, 0x9D, 0xA4, 0x1D, 0x99, 0xA6, 0x42, 0xDB, 0x87, 0x11, 0x0F, 0x84, 0xE5, 0x4F, 0x12, 0x37, 0x9D, 0x5E, 0x0D, 0x54, 0x74, 0x88, 0x1F, 0x1A, 0x5E, 0x01, 0x54, 0x66, 0xC5, 0x15, 0x38, 0x4F, 0x92, 0x67, 0xDD, 0x58, 0xC5, 0xF5, 0xF3, 0xE5, 0xE6, 0xEF, 0x19, 0xBF, 0xFC, 0x90, 0x5C, 0xFF, 0x18, 0xED, 0xF9, 0x1B, 0xE4, 0x4E, 0x8E, 0x7A, 0x32, 0xCD, 0x5A, 0xEE, 0x82, 0x48, 0x47, 0x32, 0xFF, 0x05, 0x30, 0x28, 0x81, 0xCC, 0x5B, 0x20, 0xED, 0x38, 0xBF, 0x4E, 0xA3, 0xE3, 0xEC, 0x8E, 0x64, 0xD6, 0x14, 0xC0, 0xF1, 0x1B, 0x99, 0xF1, 0x05, 0x08, 0xFC, 0x42, 0x7A, 0x1D, 0x95, 0x76, 0x98, 0x00, 0x38, 0x1D, 0x49, 0x02, 0x13, 0x13, 0xCF, 0x17, 0x08, 0xFD, 0x90, 0x73, 0xE2, 0x98, 0x25, 0x50, 0xAE, 0x96, 0x6D, 0xB4, 0xDD, 0x0F, 0xF8, 0x73, 0x32, 0xFD, 0xDB, 0x72, 0x4D, 0xE0, 0xD7, 0x8C, 0x54, 0xAF, 0x19, 0xAA, 0x72, 0x83, 0x0F, 0xDC, 0x37, 0xF4, 0x01, 0x7E, 0xC7, 0x26, 0x8E, 0x1E, 0x39, 0x12, 0x28, 0x39, 0x94, 0xA0, 0x33, 0x50, 0x05, 0xF8, 0xD3, 0x36, 0x7E, 0x78, 0xEF, 0x10, 0xB9, 0x0A, 0x71, 0xAE, 0xE4, 0xA5, 0xA7, 0x80, 0xFE, 0x58, 0xB2, 0x90, 0x80, 0x41, 0x2F, 0xA1, 0xFA, 0xFC, 0x99, 0xF3, 0xC9, 0x8B, 0xA7, 0x80, 0x4D, 0x85, 0x64, 0x7E, 0x2F, 0xC0, 0x2F, 0x85, 0x3C, 0xF7, 0x17, 0xD8, 0xFB, 0x97, 0xCC, 0x9B, 0x01, 0x1C, 0xF1, 0x24, 0x13, 0x7E, 0x00, 0xB7, 0xD3, 0x0C, 0xCE, 0x02, 0x0F, 0x87, 0x34, 0xE4, 0x0C, 0xD8, 0xA6, 0x33, 0xAF, 0x72, 0xFF, 0x99, 0x0B, 0xFF, 0xFC, 0xD4, 0x99, 0xFD, 0xE7, 0xD8, 0x11, 0x33, 0xBD, 0x2B, 0x3A, 0xE6, 0x3F, 0x23, 0xB2, 0xBA, 0x76, 0x36, 0xD3, 0xF9, 0xFB, 0xED, 0x5B, 0xAA, 0x79, 0x7B, 0x75, 0x9D, 0x31, 0xDF, 0x2D, 0x93, 0x3E, 0x6B, 0xFB, 0x6B, 0x8F, 0xFF, 0x71, 0x60, 0x7F, 0xCB, 0x56, 0x3F, 0xDB, 0x06, 0xFE, 0x44, 0x7C, 0x68, 0x4B, 0xEF, 0x36, 0xE5, 0x3F, 0xBB, 0xC7, 0x2D, 0x91, 0xFA, 0xF5, 0xB5, 0xC9, 0x6B, 0x45, 0xC0, 0x84, 0x81, 0xE4, 0x9D, 0x95, 0xC0, 0xD4, 0x15, 0xE4, 0x83, 0xF3, 0xC0, 0xAA, 0x25, 0x64, 0xD1, 0x66, 0xC0, 0x2E, 0x9C, 0xFC, 0xB3, 0x5D, 0xCB, 0xD1, 0x0F, 0x2F, 0x63, 0x9A, 0x27, 0x00, 0x69, 0xED, 0xFA, 0x8C, 0xE2, 0x5A, 0xE0, 0xBC, 0x6F, 0xFF, 0x7A, 0xF2, 0x7C, 0xD7, 0xA8, 0x1B, 0x80, 0xFB, 0x88, 0xDA, 0xEB, 0x39, 0x77, 0x80, 0x85, 0xB2, 0xCA, 0xAC, 0xCC, 0x4F, 0x80, 0xF1, 0xED, 0x92, 0x16, 0xA9, 0xAB, 0x81, 0xD1, 0x6F, 0x7F, 0x4D, 0x49, 0xBA, 0x0A, 0x0C, 0xEB, 0xF6, 0xBB, 0x4D, 0x42, 0x7F, 0x60, 0x10, 0x4A, 0x4E, 0xEF, 0xED, 0x0C, 0xF4, 0xFF, 0xF8, 0x27, 0x7A, 0x8F, 0x17, 0xD0, 0xD7, 0xE1, 0x4F, 0x44, 0xF4, 0x30, 0xF2, 0x7A, 0x03, 0xD0, 0x7F, 0x8E, 0xBC, 0x7F, 0x3A, 0x30, 0xEA, 0x17, 0xF9, 0xB8, 0x5E, 0x7A, 0x7D, 0xDE, 0xF4, 0x03, 0xE6, 0xCE, 0x27, 0x6B, 0x62, 0x74, 0xC3, 0x4C, 0xC3, 0x8A, 0xD4, 0x48, 0xC0, 0xF7, 0x97, 0xED, 0x6F, 0x52, 0x6F, 0x4F, 0xCA, 0xF7, 0x2E, 0x77, 0x49, 0x0B, 0x04, 0x9C, 0x01, 0xC8, 0xC0, 0xB7, 0xDD, 0x74, 0x81, 0xFC, 0x3E, 0x35, 0xB2, 0x98, 0x85, 0x80, 0xEF, 0xAD, 0xAA, 0x8E, 0xFB, 0xFE, 0x00, 0x1B, 0x56, 0xD6, 0x44, 0xC7, 0xC7, 0x01, 0x2B, 0x2A, 0x6B, 0xCF, 0xC6, 0x39, 0x03, 0xF3, 0xAF, 0xD5, 0xEC, 0xDB, 0xB3, 0x0A, 0x98, 0x3E, 0xB1, 0xF2, 0x4A, 0xF4, 0x10, 0xC0, 0x38, 0xAF, 0x22, 0x23, 0xB2, 0x0B, 0x60, 0x70, 0xA6, 0xA2, 0x57, 0x44, 0x0F, 0xF2, 0xF6, 0x38, 0xA0, 0xFF, 0x78, 0x79, 0xBF, 0x31, 0x30, 0xCC, 0x98, 0x7C, 0xB5, 0x11, 0x18, 0xFF, 0x95, 0x2C, 0x77, 0xC3, 0x56, 0x13, 0xBD, 0x8F, 0x9F, 0x49, 0x60, 0x45, 0x62, 0x0A, 0xE5, 0xCE, 0x0D, 0x74, 0x01, 0x48, 0xE5, 0x5B, 0x7B, 0x43, 0x7A, 0xC8, 0xDD, 0xEA, 0x33, 0x3C, 0x40, 0x7D, 0x1A, 0xE9, 0x87, 0x16, 0x67, 0x80, 0xF7, 0x3D, 0xAB, 0x76, 0x7A, 0xBC, 0x03, 0x0E, 0xCD, 0xA8, 0x33, 0xDD, 0xD5, 0x17, 0x08, 0x51, 0xAD, 0x6E, 0x8C, 0x70, 0x07, 0x9C, 0x56, 0xD7, 0x6E, 0x8D, 0x58, 0x02, 0x6C, 0xFC, 0x5C, 0xE7, 0x18, 0xDE, 0x16, 0x30, 0x6B, 0x57, 0xBB, 0x2D, 0xEC, 0x10, 0xB0, 0x4C, 0xA3, 0x56, 0x2D, 0x34, 0x15, 0x58, 0x38, 0xAB, 0x26, 0x21, 0x24, 0x44, 0xDE, 0x1F, 0xA0, 0xD1, 0xBF, 0x4D, 0x20, 0x59, 0xDC, 0x01, 0x18, 0x70, 0x8E, 0x2C, 0x79, 0x00, 0x0C, 0x79, 0x54, 0x5A, 0x42, 0x02, 0x46, 0x8F, 0x2E, 0x3A, 0x09, 0xD7, 0xEA, 0x99, 0x37, 0x92, 0xEA, 0x81, 0x7E, 0xE8, 0xAC, 0x40, 0x4E, 0x0B, 0x58, 0x85, 0x96, 0xD5, 0xE4, 0x86, 0x3F, 0x2D, 0xAB, 0xD5, 0xD2, 0xC5, 0x0E, 0xB5, 0x74, 0x80, 0x3D, 0x7F, 0xBA, 0x2C, 0x56, 0x05, 0xEE, 0xC6, 0xD7, 0x1A, 0xB8, 0x9E, 0x02, 0x0E, 0xC6, 0x57, 0x1F, 0xF7, 0x8B, 0x07, 0xA2, 0x65, 0xB5, 0xA1, 0x81, 0xFD, 0x01, 0xFF, 0x13, 0xD5, 0x91, 0x01, 0x45, 0x80, 0xF3, 0xBC, 0xDA, 0xE9, 0x01, 0xBB, 0x80, 0xAD, 0xAC, 0xF5, 0x0C, 0x50, 0x03, 0xAC, 0xA2, 0x6A, 0x76, 0xFA, 0xCF, 0x21, 0x8B, 0x08, 0x74, 0xB8, 0x40, 0xFE, 0xEA, 0x09, 0x74, 0x0B, 0xAA, 0x5D, 0x4B, 0x02, 0xFA, 0x43, 0x1E, 0xBA, 0x0B, 0x4D, 0x10, 0x1E, 0x27, 0x5C, 0x07, 0xC5, 0xE7, 0x42, 0xCF, 0x58, 0x80, 0x34, 0x81, 0xBE, 0x81, 0x7A, 0x33, 0x69, 0xFB, 0x51, 0xBD, 0x59, 0x55, 0x8F, 0xF4, 0x3D, 0xA1, 0xAA, 0x07, 0x90, 0x79, 0xEF, 0xD4, 0xBF, 0x02, 0xBF, 0x82, 0x6A, 0xAF, 0x9A, 0xAF, 0x00, 0x6E, 0x3F, 0xA8, 0xBD, 0x6D, 0x73, 0x19, 0x38, 0x2E, 0xAB, 0x1F, 0xE5, 0x98, 0x0B, 0x24, 0xB7, 0x6E, 0x9C, 0xE9, 0x9A, 0x01, 0x44, 0x16, 0x34, 0x76, 0x70, 0x2B, 0x00, 0x02, 0xCF, 0xD7, 0x5F, 0x74, 0xF3, 0x00, 0x3C, 0xFE, 0xAB, 0x6B, 0x70, 0x9B, 0x4E, 0xFE, 0x28, 0x01, 0xDA, 0x2C, 0x6B, 0x6E, 0x4F, 0x02, 0xBA, 0x1F, 0x5F, 0x99, 0x0B, 0x87, 0x46, 0x1F, 0x2E, 0x15, 0x4E, 0xCE, 0xB3, 0x54, 0x22, 0x3B, 0x15, 0xAF, 0x2C, 0x56, 0xF5, 0x24, 0x07, 0x58, 0x4E, 0xF7, 0xD4, 0x18, 0x44, 0xAE, 0xDC, 0xA6, 0x31, 0x48, 0x35, 0x8B, 0xB4, 0xFB, 0xA1, 0x9A, 0xA5, 0x5C, 0x48, 0x7A, 0x25, 0x2B, 0x17, 0x02, 0x64, 0x9A, 0xA9, 0x5A, 0x0B, 0x23, 0x5F, 0xB2, 0x66, 0x39, 0x00, 0x7C, 0x6D, 0xD5, 0xB8, 0x67, 0x99, 0x15, 0x70, 0x7F, 0x7A, 0xBD, 0x91, 0xC5, 0xBF, 0x40, 0xFE, 0xA6, 0x7A, 0x0D, 0xEB, 0x1A, 0xE0, 0x50, 0x53, 0x7D, 0xD5, 0x16, 0x55, 0xE0, 0xC0, 0xB0, 0xC6, 0x1F, 0x36, 0x37, 0x81, 0x3D, 0x1E, 0x4D, 0x29, 0x76, 0x71, 0x64, 0x53, 0x06, 0xA0, 0xF1, 0xF4, 0xF3, 0x02, 0x12, 0xE8, 0x93, 0x56, 0x38, 0x4C, 0x38, 0xC4, 0xDF, 0xA7, 0x8F, 0x70, 0x46, 0x8A, 0xAE, 0xA9, 0x70, 0xCD, 0x3F, 0xD2, 0xF3, 0xD0, 0x4E, 0x47, 0x6D, 0x20, 0x69, 0x66, 0xA8, 0x36, 0x50, 0xF9, 0x0A, 0x69, 0xB7, 0x4A, 0xF9, 0x8A, 0xD2, 0x7A, 0xD2, 0x7D, 0x83, 0xD2, 0x7A, 0x80, 0x0C, 0x99, 0xA4, 0x34, 0x58, 0x78, 0xEB, 0x93, 0x4A, 0x26, 0xD0, 0x3C, 0xAA, 0xEA, 0xFC, 0x98, 0x1E, 0xC0, 0x97, 0x3B, 0x8D, 0x53, 0x66, 0x2D, 0x06, 0x9E, 0x3D, 0x6B, 0xF6, 0x34, 0x1D, 0x0E, 0x5C, 0xD3, 0x6D, 0xF8, 0xB9, 0xC2, 0x10, 0x38, 0xF3, 0xA3, 0xE1, 0xEB, 0x1A, 0x27, 0xE0, 0x50, 0x52, 0xC3, 0x92, 0xB5, 0xA9, 0x7F, 0x07, 0x91, 0x80, 0x76, 0xC1, 0xFD, 0x7B, 0xC2, 0x9E, 0xD1, 0x49, 0xFA, 0xC2, 0xA1, 0x5B, 0x17, 0xCC, 0x23, 0xD5, 0x6E, 0xCC, 0xB8, 0x0E, 0x90, 0x3D, 0x30, 0x62, 0xBA, 0xFA, 0x48, 0x72, 0xC1, 0x34, 0xF5, 0x91, 0xCA, 0xD7, 0x49, 0xF3, 0x48, 0xE5, 0xEB, 0x4A, 0xED, 0x48, 0x9B, 0x7A, 0xA5, 0x76, 0x8A, 0xE3, 0x48, 0xE7, 0x3A, 0xC5, 0x71, 0x00, 0xE9, 0xFF, 0x46, 0xE1, 0x8D, 0xF0, 0xE8, 0x62, 0x65, 0x25, 0xE1, 0x8B, 0x4D, 0xCA, 0xDD, 0x81, 0x66, 0x59, 0x4D, 0xF2, 0x60, 0x3F, 0xE0, 0xA7, 0x95, 0x2C, 0xC7, 0xD0, 0x15, 0x78, 0x79, 0x45, 0xD6, 0x30, 0x4D, 0x1D, 0x78, 0x30, 0x80, 0x51, 0x73, 0x8E, 0x01, 0x85, 0x45, 0x4D, 0xAD, 0xE6, 0xE7, 0x90, 0x07, 0x16, 0x01, 0xFA, 0x72, 0x23, 0xB5, 0x00, 0x13, 0x90, 0x0E, 0x79, 0x80, 0x85, 0x5C, 0x0B, 0x00, 0x76, 0xB7, 0x49, 0x40, 0xBC, 0xA6, 0xC2, 0x56, 0x13, 0x76, 0x8F, 0x17, 0x4E, 0x3C, 0x1F, 0x61, 0x2F, 0x9C, 0xB6, 0x26, 0xE6, 0x94, 0x70, 0x0B, 0xA2, 0x36, 0x08, 0x1D, 0xD5, 0xF6, 0xA8, 0x51, 0xBA, 0x07, 0x41, 0x78, 0xEB, 0xA5, 0x55, 0x32, 0xA9, 0x77, 0xB7, 0x7A, 0xB0, 0x05, 0x48, 0x9D, 0x3B, 0x7C, 0xB4, 0xE1, 0xC2, 0xC7, 0x19, 0x80, 0x4C, 0x66, 0xAF, 0xF7, 0x60, 0x1C, 0x50, 0xFF, 0xC7, 0xEE, 0x60, 0x41, 0x1F, 0xA0, 0xCE, 0xC7, 0x5E, 0x43, 0x3A, 0x67, 0x07, 0xFC, 0x26, 0xE3, 0x95, 0x80, 0x89, 0x95, 0xA4, 0xDB, 0x26, 0xC0, 0xD2, 0x97, 0xDC, 0x76, 0x06, 0xB0, 0x19, 0x42, 0xF6, 0x4F, 0x07, 0x76, 0xF5, 0x20, 0x01, 0xC5, 0xD7, 0xD1, 0x51, 0x42, 0xE3, 0x31, 0x11, 0x93, 0x84, 0x93, 0x43, 0xA3, 0xD7, 0x08, 0xB7, 0xEF, 0x8D, 0x18, 0x4F, 0x61, 0xC7, 0xD0, 0x67, 0xC2, 0xF4, 0x77, 0xAE, 0x73, 0xC9, 0xBE, 0xBD, 0xCB, 0xF4, 0xCD, 0x3A, 0x91, 0xC3, 0x4B, 0xA8, 0x6E, 0xD6, 0xE3, 0xC7, 0x50, 0x40, 0x76, 0xD3, 0xC5, 0xF1, 0xA1, 0x09, 0x50, 0xF7, 0xD6, 0x71, 0xC8, 0x45, 0x2F, 0xA0, 0xB6, 0xD1, 0x71, 0x78, 0x6E, 0x5F, 0x79, 0x9E, 0xE3, 0xB4, 0x88, 0x4C, 0x53, 0x02, 0x06, 0x1A, 0x90, 0x49, 0x4D, 0xD2, 0xCF, 0x8D, 0xF2, 0xAE, 0x03, 0xD6, 0xA5, 0x90, 0x0E, 0xD3, 0x80, 0x6D, 0x1B, 0xC8, 0xBE, 0x29, 0x40, 0xD4, 0x46, 0x12, 0x00, 0x12, 0xCA, 0x84, 0xE3, 0xAA, 0x23, 0xBA, 0x0B, 0x8D, 0x8B, 0xA2, 0xE2, 0x85, 0xDB, 0x11, 0xB6, 0x5F, 0xE8, 0xD5, 0x7E, 0xA7, 0xB9, 0xF0, 0x4A, 0xD1, 0xC6, 0x5F, 0xC2, 0xAA, 0x69, 0x5E, 0x2A, 0x55, 0xA3, 0x80, 0xA6, 0x09, 0xDE, 0x41, 0x8F, 0xB5, 0x81, 0xFA, 0xCD, 0x6E, 0xFA, 0x17, 0xD7, 0x03, 0xB5, 0x2E, 0x6E, 0xED, 0x0E, 0x3B, 0xC8, 0xED, 0xEA, 0xBE, 0xE6, 0xC0, 0x6A, 0xA0, 0xA6, 0xD6, 0xBD, 0x82, 0xCC, 0xCA, 0x00, 0xF4, 0x37, 0x91, 0x69, 0x83, 0x00, 0x83, 0xD9, 0x64, 0xD0, 0x32, 0x60, 0xFD, 0x08, 0xD2, 0x2B, 0x1F, 0xB0, 0x9F, 0x45, 0x6E, 0xF1, 0x03, 0x82, 0x3C, 0xA4, 0x1D, 0x69, 0x89, 0xC2, 0xB6, 0xC7, 0xF7, 0xE6, 0x0A, 0x27, 0x8E, 0x8C, 0xB4, 0x12, 0x6E, 0xDF, 0x1C, 0xDA, 0x28, 0x4C, 0x54, 0xF0, 0x1D, 0x26, 0x7C, 0x98, 0xE1, 0xA1, 0x26, 0x6C, 0xCE, 0x0D, 0x18, 0xFA, 0x54, 0xDC, 0x83, 0xB6, 0xFA, 0x9C, 0x38, 0x1F, 0x00, 0x54, 0xFD, 0xEB, 0xB3, 0x3C, 0x3B, 0x03, 0xA8, 0x0C, 0xF7, 0xDD, 0xB9, 0xD7, 0x07, 0xA8, 0xC8, 0xF6, 0x3D, 0x17, 0x52, 0x2F, 0xF7, 0xBC, 0xAF, 0x1D, 0x79, 0x24, 0x0F, 0xE8, 0xDB, 0x8A, 0xCC, 0xD4, 0x03, 0x0C, 0xE2, 0xC8, 0x8C, 0x6F, 0xC0, 0x9C, 0x37, 0xA4, 0xEF, 0x0B, 0x60, 0xDB, 0x3D, 0x32, 0x78, 0x04, 0xE0, 0x3D, 0x5B, 0xDA, 0x91, 0x61, 0x23, 0xD4, 0x4D, 0x4B, 0x0B, 0x10, 0x1A, 0x2E, 0x4B, 0x58, 0x28, 0x74, 0xAA, 0x08, 0x2F, 0x17, 0x26, 0xC7, 0xBB, 0xF9, 0x0B, 0xEB, 0x12, 0x43, 0x14, 0x8A, 0xB3, 0x80, 0xDA, 0xC2, 0xE0, 0xAE, 0x79, 0xCD, 0x40, 0x79, 0x75, 0x50, 0x7A, 0xDA, 0x1E, 0xA0, 0x22, 0x25, 0x78, 0x5E, 0xE4, 0x4A, 0xA0, 0x72, 0x78, 0xB0, 0xB2, 0x5F, 0x07, 0x79, 0xF6, 0x0C, 0xF2, 0x76, 0xDA, 0x2F, 0x57, 0x2F, 0x48, 0x95, 0x3C, 0x7E, 0x1B, 0xE8, 0x3D, 0x98, 0x3C, 0x9C, 0x0A, 0x8C, 0x3F, 0x4D, 0x26, 0x3F, 0x01, 0x16, 0x2B, 0x92, 0xB1, 0x0D, 0xC0, 0x96, 0x11, 0x64, 0xD0, 0x12, 0xC0, 0x2F, 0x99, 0x5C, 0x3D, 0x1C, 0x88, 0xCF, 0x21, 0xA7, 0x9D, 0x1D, 0x39, 0x3B, 0x45, 0x9F, 0x04, 0x0C, 0x7C, 0x8E, 0x5C, 0x15, 0x06, 0x6F, 0x48, 0xEF, 0x23, 0xBC, 0x10, 0xE5, 0x3F, 0xF9, 0x4F, 0x08, 0x40, 0xA5, 0x48, 0xC5, 0xB3, 0x3D, 0x81, 0xB2, 0x6F, 0xE1, 0xB3, 0x12, 0x4A, 0x81, 0x8A, 0xEF, 0xE1, 0xC3, 0x83, 0x5E, 0x02, 0x95, 0x3D, 0x77, 0xF5, 0x72, 0xBA, 0x02, 0x94, 0x67, 0x86, 0x0D, 0xD8, 0x32, 0x17, 0xA8, 0x78, 0x1C, 0xBA, 0xD3, 0xEC, 0x99, 0xDC, 0x7D, 0xA1, 0x7E, 0xE4, 0xE9, 0x2F, 0x40, 0xCF, 0x59, 0xE4, 0x09, 0xB9, 0xE3, 0xA6, 0xCA, 0x73, 0x98, 0xE2, 0xF2, 0x89, 0x47, 0xC8, 0xD4, 0x96, 0xC0, 0xA6, 0xCE, 0xE4, 0x9E, 0x5D, 0x80, 0xEF, 0x7B, 0x72, 0xA5, 0x25, 0x90, 0x3A, 0x8E, 0x04, 0x5A, 0xAE, 0x29, 0x88, 0x13, 0x1A, 0x6D, 0xBB, 0xF0, 0x43, 0xE8, 0x35, 0xF4, 0x7C, 0x91, 0xB0, 0x79, 0xD9, 0xBE, 0x0F, 0x27, 0x57, 0x00, 0xE5, 0x66, 0x71, 0xCF, 0x22, 0x36, 0x01, 0x55, 0xB5, 0xB1, 0x57, 0x9C, 0x87, 0x01, 0x15, 0xE9, 0x31, 0x9F, 0xD6, 0x5D, 0x06, 0x2A, 0x8B, 0x62, 0x3C, 0x97, 0x27, 0xC9, 0xD5, 0x8C, 0xF6, 0x5F, 0xD0, 0x0F, 0xA8, 0x98, 0x1D, 0xD5, 0x6B, 0xDA, 0x74, 0xB9, 0x8B, 0x77, 0x17, 0x90, 0x17, 0x87, 0x01, 0xBA, 0x2D, 0xC9, 0xFC, 0x52, 0x60, 0x78, 0x0C, 0x79, 0xA1, 0x1B, 0x60, 0xB4, 0x99, 0x3C, 0xF6, 0x0D, 0xB0, 0x3C, 0x41, 0xA6, 0xB4, 0x03, 0x7C, 0xAE, 0x90, 0x1E, 0xB5, 0x40, 0xCA, 0x68, 0xD2, 0xFA, 0x12, 0x70, 0xD2, 0x9A, 0x04, 0x0C, 0x34, 0x6F, 0xBC, 0x16, 0x3E, 0x3F, 0x7F, 0x63, 0xD1, 0xF1, 0x4F, 0x40, 0x55, 0x69, 0xBA, 0xF9, 0xF6, 0x21, 0x40, 0x89, 0x61, 0xFA, 0xC8, 0xE5, 0xDD, 0x81, 0x1F, 0x99, 0xA9, 0x5D, 0x67, 0xE8, 0x00, 0xBF, 0xB4, 0x0F, 0x58, 0x1A, 0xCE, 0x00, 0x7E, 0x97, 0xEC, 0xFF, 0x3A, 0x22, 0x10, 0xF8, 0xD3, 0x63, 0xDF, 0xD7, 0x01, 0xC9, 0x72, 0x0D, 0xE2, 0xFB, 0xF6, 0x36, 0x91, 0xBB, 0x31, 0xF6, 0x26, 0x79, 0xF9, 0x01, 0xD0, 0x66, 0xB9, 0xDC, 0x3D, 0xC0, 0x50, 0x65, 0xF2, 0xCA, 0x6C, 0xC0, 0xC4, 0x51, 0x6E, 0xA9, 0xCE, 0xF2, 0x59, 0x5E, 0x64, 0xC1, 0x00, 0xC0, 0x21, 0x9F, 0x3C, 0xBD, 0x04, 0x88, 0x33, 0x22, 0xF3, 0x4C, 0x81, 0x43, 0xBF, 0xAB, 0xE7, 0x1D, 0x6A, 0x02, 0x2E, 0x5D, 0x1E, 0x65, 0x01, 0x98, 0xBA, 0xBE, 0xCC, 0xEA, 0xBE, 0x55, 0x6D, 0x42, 0xCD, 0x8A, 0x33, 0xE7, 0xBA, 0x1B, 0xB7, 0x3E, 0x5D, 0x12, 0x79, 0xE4, 0x6A, 0xB7, 0x76, 0xDA, 0x17, 0x7F, 0x94, 0x64, 0xDE, 0xED, 0xB2, 0x52, 0x77, 0xEB, 0xB7, 0xED, 0x29, 0x97, 0xDB, 0xCF, 0xD3, 0xD1, 0xFF, 0xBE, 0x25, 0xC9, 0x46, 0xDB, 0x52, 0xBB, 0xF5, 0x8F, 0xFB, 0x09, 0x19, 0x5A, 0x65, 0x6D, 0x97, 0xFF, 0x48, 0x88, 0xEF, 0xAB, 0x11, 0xDB, 0xE6, 0xEA, 0xCF, 0x39, 0xB1, 0x97, 0xA4, 0x7B, 0x90, 0xB6, 0xB2, 0xDC, 0x1B, 0xC0, 0xD0, 0x52, 0xF2, 0xFA, 0x3B, 0xC0, 0x78, 0x0F, 0x79, 0x5F, 0x03, 0x98, 0x79, 0x95, 0x7C, 0xA4, 0x0B, 0x58, 0xC7, 0x92, 0x2F, 0xF6, 0x03, 0x3B, 0x3E, 0x91, 0x75, 0x9B, 0x80, 0x60, 0x95, 0x08, 0xCF, 0x8A, 0x78, 0xE0, 0xB4, 0x2F, 0x50, 0xFD, 0xE7, 0xFA, 0xDE, 0x1B, 0x7E, 0x80, 0xEB, 0xD4, 0x06, 0xF5, 0xAC, 0x05, 0xC0, 0xA2, 0x88, 0xAA, 0xDE, 0x99, 0xB9, 0x80, 0xC9, 0xA5, 0x92, 0x29, 0x29, 0xCF, 0x80, 0xB1, 0xD3, 0x7E, 0x59, 0x25, 0xCD, 0x06, 0x86, 0x2F, 0xF9, 0x1D, 0xBF, 0x6F, 0x3B, 0x30, 0x78, 0xCC, 0x9F, 0x1F, 0x71, 0x83, 0x01, 0x7D, 0xD5, 0xD2, 0x33, 0x31, 0xDE, 0x40, 0x7F, 0xBD, 0xD2, 0xE0, 0x28, 0x7D, 0xF2, 0x46, 0x4B, 0xE5, 0x96, 0x2D, 0xF7, 0x92, 0xB7, 0xE6, 0x00, 0x03, 0xB5, 0xC8, 0x07, 0xB7, 0x80, 0x31, 0x41, 0x64, 0x51, 0x6F, 0xC0, 0x38, 0x91, 0xFC, 0xF6, 0x5B, 0x23, 0x73, 0x41, 0x76, 0x6D, 0x11, 0x09, 0x38, 0xEE, 0xCE, 0xAE, 0xA8, 0xF9, 0x02, 0x44, 0x95, 0x02, 0x75, 0x99, 0x5A, 0x46, 0xA7, 0x67, 0x29, 0x2F, 0x25, 0xD3, 0x03, 0x73, 0xDE, 0x02, 0xB7, 0x76, 0x34, 0x9A, 0x85, 0x54, 0x02, 0x91, 0xC5, 0x75, 0x3D, 0x62, 0x3D, 0x00, 0xC7, 0x36, 0x75, 0xB9, 0xB1, 0x53, 0x01, 0x8B, 0x07, 0x75, 0x6D, 0x62, 0x86, 0x01, 0xCB, 0x8D, 0xEA, 0x4E, 0x44, 0x6D, 0x04, 0x16, 0x2A, 0xD6, 0x45, 0x46, 0x0E, 0x04, 0x66, 0xFE, 0xA8, 0xD9, 0x16, 0x11, 0x05, 0x4C, 0x89, 0xAE, 0xFC, 0xB6, 0xAB, 0x0D, 0x79, 0x27, 0x5D, 0x6D, 0x40, 0x8B, 0x0C, 0xF2, 0xE1, 0x01, 0x40, 0xFF, 0x23, 0xF9, 0xF2, 0x0C, 0x30, 0x38, 0x80, 0x2C, 0x3F, 0x02, 0x8C, 0x9A, 0x51, 0xA9, 0x45, 0xB6, 0x5E, 0x30, 0x53, 0xF5, 0xD4, 0xA2, 0x3A, 0x1F, 0xC0, 0x65, 0x4D, 0x57, 0x5D, 0x12, 0x48, 0xDE, 0x01, 0x90, 0x96, 0xAB, 0x76, 0x9A, 0xEA, 0x77, 0x27, 0x53, 0x8A, 0xD6, 0x77, 0x02, 0x9A, 0x4A, 0x64, 0x09, 0x16, 0x5D, 0x80, 0x42, 0xE5, 0xAA, 0x2D, 0xBE, 0x79, 0x40, 0x8A, 0x7E, 0xAD, 0x63, 0x70, 0x3E, 0x10, 0xE2, 0x54, 0x3D, 0x6D, 0x47, 0x6F, 0xC0, 0xCD, 0xBD, 0xE6, 0x49, 0xF0, 0x6C, 0xC0, 0x36, 0xAF, 0xD6, 0x23, 0xE8, 0x0C, 0x60, 0x3D, 0xB7, 0x76, 0x50, 0xE0, 0x17, 0xC0, 0x7C, 0x53, 0x8D, 0x52, 0x80, 0x23, 0xF9, 0xA4, 0x2D, 0xD0, 0x56, 0x9B, 0x2C, 0xFE, 0x0B, 0x74, 0xDE, 0x4C, 0x56, 0xAD, 0x00, 0xF4, 0x02, 0xFE, 0x4E, 0x22, 0x81, 0x51, 0x37, 0x0A, 0xBE, 0x0A, 0x57, 0xEF, 0x30, 0x33, 0x12, 0xFA, 0x3C, 0xEF, 0x3E, 0x80, 0x34, 0x2A, 0xDB, 0x94, 0xDA, 0xBF, 0x17, 0xE9, 0x31, 0xAA, 0xCF, 0x74, 0x80, 0xF4, 0xAF, 0x6C, 0x97, 0x2E, 0xCC, 0x1F, 0x04, 0x00, 0x3F, 0xC3, 0x65, 0xB6, 0x56, 0x5F, 0x80, 0x7F, 0x2F, 0xD4, 0x3C, 0xB1, 0xB3, 0x06, 0x8E, 0x6D, 0xAC, 0x8F, 0x72, 0x6A, 0x06, 0x12, 0x1F, 0xCA, 0xCE, 0xBA, 0x7D, 0x01, 0x22, 0x2C, 0x1A, 0x13, 0xDC, 0xAD, 0x00, 0xFF, 0xDE, 0xF5, 0x69, 0x6E, 0x07, 0x01, 0xF7, 0xF1, 0xF5, 0xCA, 0xAE, 0x15, 0xE4, 0xDB, 0xDB, 0x80, 0x66, 0x19, 0x59, 0x75, 0x08, 0xD0, 0x4A, 0x2E, 0x6F, 0x22, 0x81, 0xDE, 0xB1, 0x77, 0x87, 0x08, 0x4D, 0x36, 0xEC, 0xF8, 0x2C, 0x5C, 0xFF, 0x4D, 0x35, 0x50, 0xE8, 0x9A, 0x03, 0x90, 0xC6, 0x11, 0x03, 0xC2, 0xD4, 0x9E, 0x93, 0x0E, 0x66, 0x2A, 0xCF, 0x55, 0x41, 0xFA, 0x41, 0x39, 0x14, 0x72, 0x0F, 0x4C, 0x54, 0xB4, 0x1B, 0xA7, 0x42, 0x56, 0x06, 0x03, 0xC0, 0xF7, 0xF9, 0x4D, 0x15, 0x4B, 0xCB, 0x80, 0x87, 0xB3, 0x1A, 0xB6, 0xAC, 0x0D, 0x02, 0xCE, 0xFF, 0xA9, 0xFD, 0xB8, 0xFE, 0x25, 0x70, 0x64, 0x4C, 0x7D, 0xCF, 0x4D, 0xD3, 0x80, 0xE4, 0xE2, 0xC6, 0xA2, 0xAD, 0xEB, 0x80, 0xD8, 0xDF, 0x4D, 0xF3, 0x6C, 0x56, 0x92, 0xE5, 0x87, 0x00, 0x8D, 0x33, 0xF5, 0xED, 0x48, 0x40, 0x67, 0xDE, 0xF3, 0x8B, 0xC2, 0xA1, 0x91, 0x69, 0x3D, 0x85, 0x93, 0x3E, 0xAD, 0xD6, 0x21, 0xB5, 0xF5, 0x16, 0xFB, 0x01, 0x64, 0xCF, 0xC1, 0x63, 0xA7, 0xB6, 0x28, 0x21, 0x57, 0x8E, 0x57, 0x9A, 0xA7, 0xBC, 0x96, 0xB4, 0x79, 0xA4, 0xBC, 0x56, 0xA9, 0x3D, 0xE9, 0x36, 0x51, 0xF1, 0x22, 0x40, 0xFA, 0xF8, 0x2B, 0xBA, 0x0A, 0xF3, 0xBF, 0x62, 0xFF, 0xCC, 0x2F, 0x24, 0x09, 0x00, 0x3F, 0x7F, 0x35, 0x69, 0x4D, 0x5B, 0x0F, 0xFC, 0xF7, 0xBB, 0xD9, 0x6C, 0x41, 0x08, 0x70, 0xF3, 0xA6, 0xEC, 0xB6, 0xE9, 0x15, 0xE0, 0xFC, 0xB6, 0xC6, 0xA8, 0x15, 0x91, 0xC0, 0xB1, 0x8B, 0x8D, 0x59, 0xAB, 0x63, 0x1B, 0x23, 0x49, 0xA0, 0x65, 0xC1, 0xC7, 0x24, 0x52, 0x37, 0x5E, 0x73, 0xF8, 0xD9, 0x1E, 0x22, 0x0F, 0xCB, 0xF0, 0xD3, 0x27, 0x3B, 0xCF, 0x1C, 0x36, 0x04, 0x10, 0x79, 0xE9, 0x5D, 0xE1, 0xE4, 0x95, 0xAD, 0x77, 0xAB, 0xCC, 0x27, 0x57, 0x75, 0x54, 0xF6, 0x50, 0xCC, 0x23, 0xB7, 0xFE, 0xA3, 0x98, 0xA7, 0x50, 0x44, 0x3A, 0xC5, 0x28, 0x14, 0xE1, 0x2D, 0xE9, 0x6D, 0x88, 0xF5, 0x00, 0x99, 0x33, 0x5C, 0xB9, 0xB5, 0xF0, 0xD1, 0x0A, 0x6C, 0x99, 0x70, 0x99, 0x6C, 0x8E, 0x06, 0x80, 0xCA, 0x79, 0xE4, 0xF8, 0x4A, 0xE0, 0xCD, 0x72, 0xD9, 0x53, 0xE3, 0x4B, 0xC0, 0xE3, 0x9A, 0xE6, 0xD7, 0x53, 0xFF, 0x02, 0x37, 0x57, 0xD2, 0x67, 0x96, 0xEF, 0xA7, 0x7C, 0x12, 0xE8, 0x78, 0xF9, 0x8A, 0x8D, 0xB0, 0x77, 0x4C, 0xD8, 0x72, 0xE1, 0x20, 0x9A, 0x40, 0x38, 0x51, 0x19, 0x72, 0xFB, 0x8C, 0xEF, 0x3C, 0x5D, 0xA5, 0x9C, 0x9C, 0x63, 0xAA, 0x52, 0xAE, 0x78, 0x97, 0x5C, 0xB9, 0x4F, 0xF1, 0xAE, 0xC2, 0x6A, 0x72, 0xE3, 0x0F, 0x85, 0xD5, 0xC8, 0x24, 0x1D, 0xD2, 0x90, 0x09, 0x90, 0x1E, 0x07, 0x00, 0x61, 0xB4, 0x19, 0x56, 0x0B, 0x4F, 0x8F, 0x56, 0x78, 0x25, 0x7C, 0x96, 0xA1, 0xD8, 0xBF, 0x43, 0x1F, 0xB2, 0xCA, 0x16, 0x00, 0x1A, 0x7B, 0x37, 0x4D, 0xE8, 0x3F, 0x06, 0xF8, 0x69, 0xC7, 0xB8, 0xE1, 0xED, 0x80, 0xD7, 0x63, 0x39, 0x6F, 0xCC, 0x79, 0x32, 0x45, 0xEC, 0x38, 0x4C, 0xC6, 0xDF, 0x04, 0x86, 0xFD, 0x20, 0xFD, 0x00, 0x2C, 0x90, 0x91, 0xD6, 0xEB, 0x00, 0xEB, 0x75, 0xE4, 0xEA, 0x10, 0x4D, 0x7B, 0x1B, 0x3B, 0x12, 0x00, 0xC2, 0x5F, 0x0B, 0x75, 0x06, 0xEC, 0x19, 0x20, 0x34, 0x41, 0xF4, 0x4A, 0xA1, 0xAD, 0x55, 0x84, 0x74, 0xEE, 0xFE, 0xDC, 0x15, 0x24, 0x4C, 0xA1, 0x97, 0xAA, 0xF0, 0xD6, 0x48, 0xCB, 0x33, 0x64, 0x07, 0xA5, 0xAA, 0x32, 0x0B, 0x90, 0x7A, 0x15, 0xE2, 0x26, 0xF7, 0xB5, 0x2F, 0xD0, 0x14, 0x6D, 0xDB, 0xE7, 0x51, 0x22, 0xD0, 0x70, 0xDF, 0x66, 0xC1, 0x65, 0x7D, 0xA0, 0xBE, 0x95, 0x8D, 0x27, 0x99, 0x5E, 0x05, 0x74, 0xE8, 0x46, 0xA6, 0x6C, 0x04, 0x06, 0x97, 0x92, 0x3E, 0x7D, 0x01, 0xD3, 0x24, 0xD2, 0x5E, 0x1B, 0xB0, 0x8A, 0x27, 0xED, 0xBA, 0xB7, 0x76, 0xDA, 0x22, 0xFA, 0x00, 0xEC, 0xB9, 0x2F, 0xD4, 0x9C, 0xB0, 0xA7, 0x8D, 0xD0, 0xE8, 0x5A, 0xC4, 0x4F, 0xE1, 0xF6, 0x2F, 0xA1, 0x07, 0x85, 0x6E, 0x93, 0x77, 0xF5, 0x15, 0x66, 0x2E, 0x75, 0x89, 0x21, 0x7B, 0xBF, 0x2C, 0x3F, 0x66, 0x76, 0x85, 0xD4, 0x77, 0x68, 0xBA, 0x6B, 0x56, 0x50, 0xB2, 0x1A, 0x68, 0x32, 0x75, 0x0A, 0x7F, 0x5C, 0x04, 0xD4, 0xBF, 0x72, 0xF8, 0xAF, 0x40, 0x06, 0xD4, 0xFE, 0x70, 0x28, 0x3A, 0x29, 0xEE, 0x63, 0x97, 0xB6, 0x3D, 0x22, 0xB3, 0x37, 0x00, 0xBA, 0xCD, 0x64, 0x6A, 0x1C, 0x30, 0xC4, 0x89, 0x4C, 0x6C, 0x01, 0x4C, 0xFC, 0x4A, 0x06, 0x4C, 0x03, 0xCC, 0xAD, 0x48, 0xBB, 0x97, 0x80, 0x53, 0x4F, 0x69, 0xC7, 0xFE, 0xC7, 0xC2, 0x4E, 0x21, 0x89, 0x4B, 0x84, 0xC6, 0x29, 0xB1, 0x3F, 0x85, 0x2E, 0x4E, 0xE1, 0x79, 0x42, 0xCF, 0xE0, 0x90, 0x20, 0xE1, 0x55, 0x7D, 0xEB, 0x36, 0xE4, 0xF8, 0xED, 0xF5, 0x93, 0x57, 0x15, 0xD7, 0xB7, 0x05, 0x9A, 0x57, 0x79, 0xD6, 0x3E, 0x6B, 0x0F, 0xD4, 0x1F, 0x72, 0x2E, 0xBA, 0x24, 0xB7, 0x76, 0x9F, 0x73, 0xFC, 0x31, 0x27, 0xB9, 0x35, 0x2E, 0xDF, 0x53, 0xA7, 0x01, 0x75, 0xED, 0x5C, 0x67, 0x91, 0x87, 0x6E, 0x02, 0x3A, 0x77, 0xC8, 0xB4, 0x4D, 0xC0, 0xB0, 0x31, 0x72, 0xCB, 0x01, 0xC3, 0x58, 0xD2, 0xDF, 0x16, 0x58, 0x37, 0x8E, 0xF4, 0xD4, 0x02, 0xC4, 0xDE, 0xD1, 0x5B, 0x81, 0x98, 0xBE, 0xA4, 0xDA, 0x93, 0x76, 0x4D, 0x69, 0x9D, 0x49, 0xC0, 0x28, 0x31, 0x5D, 0x4D, 0xE8, 0xF7, 0x29, 0x49, 0xBA, 0x8F, 0x9D, 0x8D, 0xBB, 0x2C, 0x7C, 0x3C, 0xD7, 0xE9, 0xAA, 0xB0, 0x29, 0x20, 0xA0, 0xED, 0x7F, 0xFE, 0x40, 0xBD, 0x85, 0x57, 0x71, 0xC1, 0x4F, 0xA0, 0xFA, 0x95, 0xE7, 0xE2, 0x43, 0x1B, 0xE5, 0x8E, 0xF6, 0x2A, 0xDA, 0x7F, 0x0A, 0xA8, 0x7A, 0xED, 0xBD, 0x36, 0xA2, 0xAB, 0xDC, 0x33, 0x5E, 0x3F, 0xC8, 0xE3, 0x37, 0x00, 0x35, 0x92, 0x39, 0x53, 0x80, 0x21, 0xD1, 0x64, 0xDA, 0x2C, 0xC0, 0xE8, 0x31, 0x19, 0x1E, 0x01, 0x58, 0xBE, 0x22, 0x3D, 0x22, 0x01, 0x57, 0x23, 0x72, 0x8D, 0x17, 0xB0, 0xA7, 0x35, 0x39, 0xB2, 0xDF, 0x3F, 0xBB, 0x52, 0x3B, 0x90, 0x80, 0x81, 0xDF, 0xD1, 0x7E, 0xC2, 0xD0, 0x3E, 0x99, 0x42, 0x44, 0x1F, 0xCC, 0xEA, 0x22, 0xAC, 0xCB, 0xF7, 0x4F, 0x7A, 0x17, 0x01, 0xD4, 0x0F, 0x0A, 0xA8, 0xB8, 0x28, 0xEE, 0x5D, 0x61, 0x01, 0x83, 0xB2, 0xFC, 0xE4, 0xCE, 0x08, 0xEC, 0x1E, 0xF3, 0x8F, 0xDC, 0xA9, 0x81, 0x83, 0x02, 0x9B, 0xE4, 0x0E, 0x0D, 0xB8, 0xEC, 0xE6, 0x2F, 0xD7, 0xDE, 0xBF, 0x91, 0x3C, 0x75, 0x05, 0x50, 0x99, 0x4E, 0xE6, 0xEE, 0x01, 0x06, 0x94, 0x92, 0x39, 0x1D, 0x00, 0xA3, 0xCB, 0x64, 0xC6, 0x31, 0xC0, 0xD4, 0x97, 0x0C, 0xB8, 0x08, 0xB8, 0x4E, 0x21, 0xCD, 0x9F, 0x02, 0x09, 0x21, 0xE4, 0x12, 0x83, 0x5E, 0x65, 0x07, 0x3E, 0x91, 0x80, 0xE1, 0xAD, 0xB3, 0x4A, 0x42, 0xFF, 0xFF, 0x4E, 0x0E, 0x12, 0xE6, 0x14, 0x1C, 0x52, 0xAE, 0x36, 0x04, 0xC8, 0xB0, 0x25, 0xF9, 0x8E, 0x40, 0xF9, 0xF0, 0xD0, 0x35, 0xC9, 0x2E, 0x72, 0xCF, 0x86, 0xDE, 0x0C, 0x7B, 0x01, 0x54, 0xB5, 0x0B, 0x1D, 0xE5, 0xB6, 0x4C, 0x9E, 0x1D, 0x42, 0xA6, 0xD8, 0x3C, 0x96, 0x7B, 0x67, 0x67, 0xFC, 0xFA, 0x56, 0xE2, 0x7E, 0xB8, 0xB3, 0x15, 0x79, 0xF6, 0x1E, 0xA0, 0xE4, 0x28, 0xDF, 0x13, 0x01, 0xF4, 0x2F, 0x24, 0x73, 0xFB, 0x03, 0x13, 0xDB, 0x93, 0xE9, 0xE1, 0xC0, 0x72, 0x07, 0x72, 0xDF, 0x0E, 0x60, 0xFB, 0x54, 0xD2, 0x74, 0x29, 0x90, 0x76, 0x84, 0x74, 0x1E, 0xDF, 0xC6, 0x28, 0x39, 0x83, 0x04, 0x0C, 0xEE, 0x15, 0xA4, 0x09, 0x13, 0xB6, 0xE4, 0x87, 0x08, 0x9B, 0xFD, 0x4E, 0x6F, 0xCC, 0xEB, 0x0C, 0x54, 0x6A, 0x45, 0xF5, 0x8D, 0xBB, 0x05, 0xD4, 0x68, 0xC6, 0x8C, 0xF1, 0x98, 0x08, 0x54, 0x8C, 0x8F, 0xF2, 0xDC, 0xF2, 0x19, 0xA8, 0xCC, 0x8B, 0xF4, 0x58, 0x9D, 0x2D, 0x77, 0x45, 0xE4, 0xD4, 0xC5, 0x85, 0x72, 0x7B, 0xEC, 0xDE, 0x34, 0xE7, 0x03, 0x50, 0x31, 0x33, 0x3C, 0x81, 0xCC, 0xFF, 0x05, 0xA0, 0x8C, 0x3C, 0x97, 0x02, 0xF4, 0xFB, 0x40, 0x9E, 0x29, 0x02, 0x0C, 0xF2, 0xC8, 0x0B, 0xD3, 0xD4, 0x7A, 0x19, 0x2B, 0x93, 0xC9, 0xA6, 0x80, 0xD3, 0x07, 0xD2, 0xED, 0x1E, 0x90, 0x50, 0x4D, 0x7A, 0x39, 0xAA, 0x75, 0xCF, 0xFA, 0x42, 0x02, 0x6A, 0x23, 0xFE, 0xED, 0x20, 0xBC, 0x37, 0xE9, 0x92, 0xD6, 0x31, 0x00, 0xEF, 0xC7, 0x9D, 0xB9, 0xE6, 0xEF, 0x01, 0xFC, 0x49, 0x4D, 0x9A, 0xB9, 0x7E, 0x3F, 0x50, 0x92, 0x93, 0xD4, 0x6D, 0x89, 0xB2, 0xDC, 0xF3, 0xFB, 0x27, 0x4D, 0xBB, 0x07, 0x94, 0x9E, 0x8E, 0x7F, 0x69, 0xB8, 0x10, 0x28, 0x1B, 0x17, 0x77, 0x61, 0xB4, 0x22, 0x50, 0xAE, 0x1A, 0x3B, 0x78, 0xD0, 0x05, 0x79, 0x76, 0x8A, 0x99, 0x4F, 0x16, 0x5C, 0x01, 0x00, 0xF2, 0x8A, 0x27, 0xA0, 0x6B, 0x49, 0x16, 0x06, 0x00, 0x23, 0x7E, 0x92, 0x57, 0x77, 0x2A, 0x39, 0x19, 0x1D, 0x21, 0xF3, 0x2E, 0x4B, 0x3F, 0x7F, 0xF5, 0x44, 0x3E, 0x10, 0xF6, 0x98, 0x3C, 0x9F, 0x08, 0x24, 0x8D, 0xFC, 0xA6, 0x77, 0xEA, 0x04, 0x70, 0x78, 0xEF, 0xF0, 0x46, 0x60, 0xB2, 0xF9, 0x83, 0xEE, 0xDA, 0x03, 0x74, 0x1B, 0xFF, 0x04, 0x5F, 0x4B, 0xED, 0xBA, 0x4D, 0x53, 0xE7, 0xD7, 0x9D, 0xC3, 0xED, 0x3B, 0xD7, 0xB4, 0xD9, 0xFC, 0xFD, 0x6A, 0xA6, 0x4F, 0x87, 0x6B, 0xDA, 0xB3, 0xBE, 0xA9, 0xA5, 0xF8, 0xE9, 0x78, 0xB4, 0x0D, 0xFC, 0xF6, 0x39, 0x49, 0xAF, 0x75, 0x6C, 0x9B, 0x7F, 0xBF, 0x7F, 0x49, 0x30, 0x6C, 0x39, 0xA3, 0xCD, 0xFC, 0xEF, 0x37, 0xF6, 0x9E, 0x6C, 0xD1, 0xA5, 0x8D, 0xF5, 0xCF, 0x57, 0x7B, 0xDE, 0x4B, 0xF7, 0x20, 0x40, 0xDE, 0x5B, 0xA3, 0xB8, 0x41, 0xA7, 0x84, 0xBC, 0x11, 0x0E, 0x0C, 0x57, 0x26, 0xEF, 0x86, 0x02, 0xC6, 0x5B, 0xC9, 0x87, 0x8D, 0xC0, 0x9A, 0x0D, 0x64, 0x71, 0x19, 0xB0, 0x4E, 0xA1, 0x3E, 0xBF, 0x76, 0x22, 0xB0, 0xF9, 0x59, 0x76, 0x5C, 0x69, 0x4F, 0x20, 0x6D, 0x30, 0xF0, 0xF3, 0x6A, 0x94, 0xD7, 0x65, 0x00, 0xC7, 0x57, 0x94, 0x7C, 0x3C, 0x1E, 0x0A, 0xD8, 0x2A, 0x56, 0x57, 0x25, 0x76, 0x03, 0x56, 0xC7, 0xD5, 0xAF, 0x4E, 0xB8, 0x06, 0xCC, 0x5B, 0x54, 0xEB, 0xB3, 0x37, 0x15, 0x98, 0x7C, 0xA1, 0x3C, 0x35, 0xB6, 0x35, 0x60, 0x78, 0xA4, 0xC2, 0x29, 0x7A, 0x19, 0x30, 0xEE, 0x70, 0x45, 0x8F, 0xDD, 0x3F, 0x80, 0x51, 0xB9, 0xE5, 0xAE, 0xE1, 0x97, 0xC8, 0xEB, 0x97, 0x14, 0x7C, 0x95, 0xE4, 0xDE, 0x9D, 0xA6, 0x75, 0x53, 0xE5, 0x1B, 0xF9, 0xE8, 0x08, 0x30, 0x70, 0x00, 0xF9, 0xD2, 0x09, 0x18, 0x1B, 0x44, 0xFE, 0x2C, 0x04, 0x8C, 0xB4, 0xCB, 0x9E, 0x90, 0x72, 0x1B, 0xB3, 0xAF, 0x96, 0x6D, 0x04, 0xDC, 0xF6, 0xB6, 0xDB, 0x5D, 0xF5, 0x02, 0x38, 0xE8, 0x0F, 0x90, 0x31, 0xD1, 0x69, 0x69, 0x80, 0xAC, 0x77, 0xED, 0xBC, 0xB8, 0x74, 0xE0, 0xA4, 0x43, 0xF5, 0x1F, 0xFF, 0x5F, 0xC0, 0x9E, 0xE7, 0xB5, 0x39, 0x21, 0x26, 0x80, 0xF7, 0xE9, 0x2A, 0xFD, 0x9D, 0xA7, 0x01, 0x87, 0x87, 0x75, 0xE3, 0x77, 0x34, 0x02, 0x1B, 0x1D, 0xEA, 0xB6, 0xED, 0x50, 0x04, 0xCC, 0xF2, 0x6B, 0xAC, 0x83, 0x08, 0x2C, 0x1F, 0x5D, 0xA3, 0x1E, 0x78, 0x81, 0xBC, 0x67, 0x01, 0xA8, 0xBF, 0x20, 0x9F, 0x26, 0x01, 0xBA, 0x9D, 0xC9, 0xF7, 0x73, 0x80, 0xCE, 0x6D, 0xC8, 0x9A, 0x66, 0xA0, 0x8F, 0xD3, 0x87, 0x5D, 0xCD, 0xE1, 0xC0, 0xC4, 0xBC, 0x8C, 0x45, 0xB5, 0xEF, 0x00, 0x6B, 0xDF, 0xD9, 0xB9, 0x64, 0x97, 0x52, 0xDF, 0x29, 0x00, 0x39, 0x3F, 0x21, 0x50, 0x43, 0xBF, 0x3D, 0x79, 0xA0, 0x85, 0x79, 0xBA, 0xC8, 0x85, 0xB5, 0x16, 0xF6, 0xC0, 0x97, 0x49, 0xB2, 0xC4, 0x75, 0x01, 0xC0, 0x95, 0x07, 0x35, 0x1A, 0x76, 0x5D, 0x80, 0xC3, 0x81, 0x0D, 0x7A, 0xCE, 0xAD, 0x80, 0x84, 0x9F, 0x4D, 0x21, 0x6E, 0x37, 0x80, 0xB0, 0xB7, 0x8D, 0x13, 0xDC, 0x62, 0x00, 0xDF, 0xC9, 0xF5, 0xDA, 0xAE, 0x8F, 0x00, 0x97, 0x8C, 0xFA, 0x1E, 0xAE, 0x81, 0x64, 0xD1, 0x24, 0x40, 0x7D, 0x1F, 0xF9, 0xB5, 0x02, 0xD0, 0x78, 0x49, 0x92, 0x80, 0xD6, 0xD5, 0x0F, 0x42, 0x0C, 0xB7, 0x3C, 0xD9, 0x59, 0x38, 0xC7, 0xD6, 0xBE, 0x86, 0xD4, 0x3B, 0xB2, 0x22, 0xA4, 0x53, 0x20, 0x39, 0xD4, 0xC6, 0xDC, 0xAF, 0xAF, 0x2A, 0xB9, 0x2D, 0x57, 0x5F, 0x4D, 0xD1, 0x86, 0xDC, 0xD1, 0xD8, 0xFB, 0x09, 0x40, 0x26, 0xB4, 0x6D, 0xA9, 0x37, 0x2E, 0x8E, 0xAC, 0x5E, 0x08, 0x00, 0xDF, 0xC7, 0xCB, 0x02, 0x97, 0xE8, 0x00, 0x8F, 0x8E, 0x34, 0x7E, 0x5D, 0xB3, 0x1A, 0xB8, 0x68, 0x53, 0xFB, 0xC4, 0xE2, 0x5F, 0xE0, 0xE8, 0xF6, 0x7A, 0x65, 0xEB, 0x0D, 0x40, 0xEA, 0xEE, 0xC6, 0x9C, 0x4D, 0x7B, 0x81, 0xB8, 0x80, 0x26, 0xED, 0x2D, 0x0A, 0xE4, 0x0F, 0x43, 0x40, 0xBD, 0x50, 0xEA, 0x57, 0xFE, 0xF1, 0x35, 0x42, 0xD8, 0xBF, 0xBE, 0x50, 0x41, 0x38, 0x7A, 0x89, 0xE7, 0x5D, 0xE1, 0x3C, 0x9D, 0x36, 0x4F, 0x84, 0xEB, 0x34, 0x00, 0x72, 0x5A, 0xD7, 0xFE, 0x3D, 0xD5, 0xD6, 0x93, 0xB6, 0x4D, 0x8A, 0x03, 0x55, 0x46, 0x90, 0x7E, 0x15, 0x4A, 0x0F, 0x01, 0x72, 0xD7, 0x55, 0xD5, 0x97, 0xC2, 0xFC, 0x18, 0x60, 0x8A, 0x1A, 0xD9, 0xE4, 0x0B, 0x00, 0x7F, 0xFE, 0x36, 0x75, 0x35, 0x2E, 0x04, 0x8A, 0x7B, 0x34, 0x39, 0xCF, 0x5A, 0x0C, 0xDC, 0x5B, 0xD5, 0xFC, 0x6B, 0xE1, 0x20, 0xA0, 0x20, 0x49, 0x66, 0xB9, 0x64, 0x37, 0x70, 0x72, 0x91, 0x2C, 0x7D, 0xF9, 0x2E, 0xB2, 0x31, 0x1A, 0x50, 0x7F, 0x5E, 0x12, 0x42, 0x02, 0xED, 0x87, 0xDC, 0xFA, 0x2E, 0x1C, 0xBC, 0x3F, 0x66, 0x95, 0x70, 0xDC, 0x94, 0x19, 0x16, 0xA4, 0xC2, 0x9F, 0xA9, 0x4D, 0x00, 0xD9, 0xE3, 0xC2, 0xC0, 0xED, 0xEA, 0x79, 0xA4, 0x69, 0xB2, 0xA2, 0xA6, 0x52, 0x12, 0xB9, 0x65, 0x9C, 0x52, 0x92, 0x02, 0x49, 0x17, 0x99, 0xC2, 0x15, 0x80, 0xF4, 0x99, 0x89, 0xF7, 0xC2, 0x6C, 0x43, 0xC5, 0x58, 0xE1, 0xBD, 0x32, 0x40, 0x3F, 0x8F, 0xAC, 0x73, 0x07, 0x80, 0x86, 0xE9, 0xBC, 0x3A, 0xFC, 0x03, 0xF0, 0x69, 0x73, 0xB3, 0xF5, 0xF8, 0x53, 0xC0, 0xF3, 0xBF, 0xCD, 0xC7, 0x8C, 0xB4, 0x80, 0xBB, 0x4E, 0x2C, 0x9E, 0x92, 0x59, 0x96, 0x4B, 0x02, 0x6D, 0xFB, 0xFD, 0xD7, 0x8B, 0xD4, 0xAE, 0xD4, 0x2C, 0xCD, 0x12, 0x19, 0xFD, 0x96, 0x6C, 0xEB, 0x49, 0xEA, 0xDC, 0x1C, 0x38, 0x0A, 0x10, 0xD9, 0xA4, 0x51, 0xDD, 0x8F, 0x9C, 0x6A, 0xAB, 0x3C, 0x50, 0x69, 0x37, 0x69, 0x5A, 0xAF, 0xD8, 0x01, 0x25, 0xA4, 0x55, 0x3B, 0x94, 0x00, 0xA4, 0xDD, 0x0C, 0x40, 0xE8, 0x56, 0x20, 0xB9, 0xEB, 0x92, 0x64, 0xEE, 0x2E, 0x85, 0x96, 0xC2, 0x07, 0x77, 0x01, 0xB5, 0x52, 0xF2, 0xBB, 0x12, 0xD0, 0x79, 0x1A, 0x49, 0xB6, 0x52, 0x00, 0x2A, 0xE3, 0xC9, 0x41, 0xDF, 0x81, 0x0F, 0xA9, 0xFC, 0x3E, 0x6C, 0xD0, 0xEB, 0x9F, 0xA4, 0x96, 0x99, 0x96, 0xD9, 0x39, 0x1F, 0xB2, 0xB5, 0x51, 0x6B, 0x23, 0xCF, 0x3E, 0xA4, 0xD2, 0xC6, 0x5E, 0x1B, 0xFB, 0x14, 0x92, 0xC0, 0xF8, 0x61, 0x00, 0xD9, 0xF7, 0x89, 0xF6, 0x5B, 0xA1, 0x09, 0x54, 0xE7, 0xE2, 0x29, 0xB9, 0xC4, 0x05, 0x4F, 0x45, 0x36, 0x73, 0x02, 0x84, 0x5B, 0x7E, 0x4A, 0x6E, 0xFF, 0x24, 0xE9, 0x7B, 0x52, 0xF2, 0x40, 0xB6, 0xE4, 0x19, 0x0D, 0xA8, 0x0B, 0x1F, 0x2A, 0xA0, 0x97, 0xE2, 0x21, 0xF2, 0xD3, 0x41, 0xA0, 0x55, 0x05, 0x59, 0xAD, 0x08, 0x00, 0xCD, 0x51, 0xCD, 0xC7, 0xBA, 0xDC, 0x94, 0xEE, 0x41, 0xCA, 0x99, 0xE4, 0x3E, 0x2F, 0xA0, 0xA7, 0x3D, 0x19, 0x74, 0x01, 0x30, 0x6C, 0x24, 0xD7, 0xDE, 0x02, 0xD6, 0xDE, 0x22, 0xCD, 0xD3, 0x14, 0x87, 0xAD, 0x1B, 0x46, 0x02, 0x40, 0x54, 0x47, 0xA1, 0xB6, 0x5E, 0x8C, 0x9E, 0xD0, 0x04, 0x51, 0xEF, 0x85, 0xF6, 0xDD, 0x22, 0xBB, 0x09, 0xBD, 0xF5, 0x42, 0x0A, 0x85, 0x29, 0xF4, 0xA8, 0x13, 0xDE, 0x0A, 0xB2, 0x00, 0xA9, 0x5C, 0x51, 0x76, 0x4F, 0xD8, 0x03, 0xE4, 0x92, 0x55, 0xE5, 0xE1, 0x90, 0x6B, 0x6D, 0x57, 0xFC, 0x1B, 0x68, 0x2A, 0xB5, 0x8E, 0xB9, 0x33, 0x1A, 0x68, 0xF8, 0x65, 0xED, 0x45, 0x66, 0x44, 0x48, 0xAB, 0xD3, 0x95, 0x80, 0x8E, 0x37, 0xC8, 0xDD, 0x0B, 0x81, 0x71, 0x9F, 0x49, 0x8B, 0x56, 0xC0, 0xFA, 0x23, 0xE4, 0x86, 0x07, 0x72, 0xED, 0xA4, 0x1D, 0x49, 0xDA, 0x42, 0xED, 0x75, 0xF1, 0xBF, 0x85, 0x53, 0x5D, 0xE3, 0x5E, 0x09, 0xBD, 0x36, 0x44, 0xAB, 0x0A, 0xBD, 0x1F, 0x44, 0xB4, 0x17, 0xA6, 0xA6, 0xBB, 0xB6, 0x13, 0x3E, 0xF9, 0x68, 0x71, 0x88, 0x6C, 0x53, 0x52, 0xF7, 0xC5, 0xD2, 0x58, 0x16, 0x08, 0x90, 0xB6, 0x8B, 0xDF, 0xD8, 0x02, 0x4D, 0x9F, 0x36, 0xFF, 0xBE, 0x43, 0xA0, 0xC1, 0x77, 0x73, 0xCF, 0x0B, 0x79, 0x40, 0xFD, 0xE4, 0xCD, 0x8F, 0xC8, 0xAC, 0xA7, 0xD2, 0x8E, 0xD4, 0x91, 0x80, 0x9E, 0x11, 0x19, 0x67, 0x02, 0x8C, 0x5D, 0x4B, 0x6E, 0x1A, 0x0F, 0x58, 0x65, 0x92, 0x36, 0xC3, 0x81, 0x4D, 0x57, 0xA5, 0x1D, 0xE9, 0x16, 0x42, 0x05, 0xB5, 0xD4, 0x4E, 0xC2, 0x29, 0x4F, 0x93, 0x17, 0x09, 0x7D, 0x7D, 0xF7, 0x4F, 0x16, 0x7A, 0x4C, 0x89, 0xCF, 0x13, 0x5E, 0x7C, 0x6D, 0xB3, 0x8A, 0xEC, 0x12, 0x54, 0xB3, 0x6A, 0x6D, 0x0A, 0xD9, 0x6F, 0x0B, 0xB9, 0x66, 0xC8, 0xC7, 0x42, 0xA0, 0x69, 0x9E, 0xFD, 0xCA, 0xFB, 0x3D, 0x80, 0xFA, 0xE7, 0xB6, 0x53, 0xCE, 0x27, 0x00, 0x75, 0xFB, 0x6C, 0x65, 0xB9, 0xA3, 0xE5, 0xAE, 0xB5, 0x6F, 0x4B, 0x1E, 0xD4, 0x91, 0x76, 0x64, 0x8C, 0x00, 0xBA, 0x9C, 0x23, 0x53, 0xBA, 0x02, 0xC3, 0xFD, 0x48, 0x9F, 0x67, 0xC0, 0x8A, 0x6F, 0xA4, 0xC3, 0x72, 0xC0, 0x6E, 0x22, 0x39, 0xAC, 0x02, 0xD8, 0x33, 0x83, 0xD4, 0x3C, 0xAB, 0xAA, 0x97, 0x6A, 0x44, 0xB6, 0x55, 0x37, 0xBE, 0x9B, 0x42, 0x12, 0xF0, 0xFF, 0x9B, 0xBA, 0x4E, 0x18, 0x66, 0x98, 0xBA, 0x43, 0x78, 0x43, 0xDB, 0xCD, 0x82, 0x1C, 0x2E, 0x6B, 0xEA, 0xBC, 0xFA, 0xD8, 0xAF, 0x49, 0x40, 0x53, 0x7B, 0xE7, 0x53, 0x0F, 0x8C, 0x80, 0xBA, 0xA7, 0xDB, 0x27, 0x9D, 0xDF, 0x22, 0x77, 0xD4, 0xF6, 0x80, 0x23, 0x7E, 0x72, 0xEF, 0x38, 0x3E, 0x4A, 0x1E, 0x27, 0x77, 0xAE, 0x93, 0x15, 0x79, 0x78, 0x95, 0xB4, 0x23, 0x27, 0x12, 0xE8, 0x38, 0x98, 0x4C, 0xBD, 0x02, 0x0C, 0xFF, 0x4B, 0xFA, 0x7D, 0x00, 0x56, 0x6D, 0x21, 0x1D, 0xBB, 0x01, 0x8E, 0xCD, 0xE4, 0xFA, 0xE1, 0x40, 0xB8, 0x36, 0x09, 0x00, 0x87, 0x0B, 0x85, 0x86, 0xC5, 0x47, 0x52, 0x84, 0x3B, 0x13, 0xB2, 0x35, 0x84, 0xA9, 0x5B, 0xD2, 0x8E, 0x09, 0xDF, 0x24, 0x05, 0xAC, 0xA9, 0x37, 0x06, 0x9A, 0x1D, 0xBC, 0x55, 0x1F, 0xF5, 0x01, 0xEA, 0xCD, 0x5C, 0x1F, 0x9C, 0x1F, 0x05, 0xD4, 0x36, 0xB9, 0x16, 0xE7, 0x18, 0xC9, 0x3D, 0xEC, 0x3E, 0x29, 0xA1, 0x16, 0xA8, 0x5B, 0xE6, 0x5E, 0x13, 0x3E, 0x11, 0xA8, 0x49, 0x70, 0x3F, 0x42, 0x1E, 0xBD, 0x21, 0xED, 0x38, 0xA2, 0x05, 0x74, 0x98, 0x42, 0xA6, 0xFD, 0x0B, 0x8C, 0x94, 0xEF, 0xC8, 0x20, 0x60, 0xF4, 0x8B, 0xF4, 0xD9, 0x04, 0x38, 0x3E, 0x26, 0xCD, 0xA7, 0x03, 0x51, 0x17, 0x48, 0x83, 0x13, 0xAA, 0xD7, 0x53, 0xC3, 0x49, 0x60, 0x5C, 0xDD, 0xC9, 0x07, 0xC2, 0x00, 0xFD, 0x63, 0x51, 0xC2, 0xA3, 0xBB, 0x73, 0xA6, 0x0A, 0x9B, 0x37, 0x87, 0xD5, 0x3C, 0x0B, 0x00, 0x6A, 0x26, 0xF8, 0xCD, 0xCE, 0x53, 0x00, 0xAA, 0x66, 0xFB, 0x5C, 0xCD, 0x18, 0x0A, 0x54, 0xA4, 0xF9, 0xFE, 0x88, 0xB6, 0x92, 0xBB, 0xC9, 0x4F, 0x33, 0xB0, 0x3F, 0x50, 0x7E, 0xD3, 0xF7, 0xAC, 0xDB, 0x12, 0xA0, 0x72, 0x9C, 0x6F, 0x7B, 0x52, 0x9C, 0x91, 0x00, 0x79, 0xAA, 0x1A, 0x50, 0xB5, 0x22, 0x0F, 0x8D, 0x02, 0x86, 0xCF, 0x20, 0x53, 0x67, 0x02, 0x53, 0x97, 0x93, 0xA1, 0xB3, 0x01, 0xC7, 0x7B, 0xE4, 0xCE, 0xC1, 0x40, 0xD0, 0x07, 0x72, 0xED, 0x03, 0x20, 0xA5, 0x1D, 0x09, 0x8C, 0xD4, 0xC8, 0xBF, 0x2F, 0x8C, 0xD1, 0x3A, 0xF9, 0x42, 0xF8, 0xFB, 0x9F, 0x5C, 0xB5, 0x97, 0x9E, 0x40, 0x75, 0x53, 0x44, 0xD8, 0xA9, 0x05, 0x40, 0xF9, 0xA1, 0x1D, 0xE1, 0x09, 0x17, 0x81, 0xCA, 0x16, 0x3B, 0x5E, 0xED, 0x7C, 0x02, 0x54, 0x94, 0xEE, 0xE8, 0xEF, 0xAA, 0x03, 0x94, 0x2F, 0x0F, 0xDE, 0xB8, 0xF5, 0xB3, 0x3C, 0x4F, 0x0B, 0x56, 0xB4, 0xB8, 0x06, 0x54, 0x4E, 0x0D, 0x7A, 0x45, 0x9E, 0x9E, 0x25, 0xED, 0xC8, 0x73, 0x06, 0x94, 0xFA, 0xC8, 0xB3, 0x17, 0x30, 0x70, 0x28, 0x79, 0x72, 0x31, 0x60, 0xE0, 0x41, 0xA6, 0x1E, 0x05, 0x6C, 0xFB, 0x90, 0x49, 0x6A, 0x0A, 0x26, 0xBE, 0x43, 0x49, 0x3B, 0x0D, 0x20, 0xBD, 0x17, 0x09, 0x00, 0x57, 0x5B, 0x7E, 0x3D, 0x05, 0x1C, 0x5B, 0x9E, 0xFB, 0xF9, 0xA4, 0x3D, 0x50, 0x7A, 0xE6, 0x58, 0xBB, 0x3D, 0x47, 0x80, 0x8A, 0x87, 0x89, 0x1D, 0x3C, 0x43, 0x81, 0xCA, 0xBD, 0xD1, 0xFB, 0x36, 0xB5, 0x00, 0xAA, 0xD6, 0x45, 0xEB, 0xAE, 0x32, 0x97, 0xE7, 0xF7, 0x51, 0x6B, 0x17, 0x0D, 0x93, 0xDB, 0x72, 0x77, 0xF5, 0xF4, 0xE7, 0x72, 0xFB, 0x46, 0xD8, 0x1A, 0xE6, 0x03, 0x15, 0x2B, 0xC2, 0xBD, 0xC8, 0xFC, 0x55, 0xD2, 0x8E, 0x4B, 0xA5, 0x90, 0x3C, 0x04, 0xF4, 0x5D, 0x2C, 0xD7, 0x1F, 0x30, 0x7A, 0x41, 0x9E, 0x39, 0x08, 0x58, 0x5F, 0x21, 0x4F, 0x3D, 0x02, 0xBC, 0x46, 0xD6, 0x98, 0x9C, 0x51, 0x00, 0x76, 0x6D, 0x7B, 0xD7, 0xE2, 0xE4, 0x46, 0x20, 0xEE, 0x85, 0x51, 0xBC, 0x76, 0xE2, 0xA4, 0x4D, 0x97, 0x7E, 0x68, 0x3D, 0x6A, 0x7B, 0xF7, 0xF7, 0xCB, 0xC2, 0x79, 0x9A, 0x9B, 0xDB, 0xCC, 0xFD, 0xBD, 0xF3, 0x48, 0x8C, 0xCE, 0xC6, 0x56, 0xFD, 0x3F, 0xFB, 0xA5, 0xF7, 0x6F, 0x1D, 0xD1, 0x2A, 0xEE, 0xCB, 0xFB, 0x64, 0x65, 0xCD, 0x76, 0xAD, 0x0C, 0xBE, 0x0D, 0xDB, 0x7F, 0x56, 0xAD, 0xB4, 0x55, 0x9F, 0x6F, 0xED, 0xE2, 0xEF, 0x2B, 0xEB, 0x6A, 0x1D, 0xFD, 0x3E, 0x2B, 0x6E, 0xAD, 0xCA, 0xC2, 0xD6, 0x66, 0xBF, 0x4A, 0xA2, 0xDF, 0x90, 0x85, 0x5D, 0xA5, 0xFE, 0xAB, 0xB9, 0x0A, 0xEF, 0x30, 0x81, 0xBC, 0x11, 0x02, 0xF4, 0xFB, 0x46, 0xDE, 0xCA, 0x01, 0x0C, 0xA2, 0xC9, 0x47, 0x77, 0x80, 0x39, 0xB2, 0x06, 0xEF, 0xA2, 0xB9, 0xC0, 0xF8, 0x6B, 0x15, 0xD5, 0xE5, 0xF2, 0x3C, 0xC4, 0xE5, 0xDC, 0xD4, 0xAF, 0x9F, 0x81, 0xA0, 0x36, 0xC0, 0xDB, 0xE2, 0xED, 0xC6, 0xE7, 0x55, 0x80, 0x53, 0x0E, 0xF5, 0x93, 0x8F, 0xDA, 0x00, 0x7E, 0x9F, 0xCA, 0xC7, 0xC5, 0x77, 0x05, 0xB6, 0x04, 0x34, 0xEC, 0x8C, 0x72, 0x06, 0xCC, 0xDA, 0x36, 0xE8, 0xEE, 0xF6, 0x07, 0x4C, 0x83, 0xEA, 0xBD, 0x22, 0x2C, 0x80, 0x79, 0x6F, 0xEA, 0x7A, 0x85, 0xEB, 0x01, 0xD3, 0xF3, 0xAA, 0x97, 0x87, 0x99, 0x03, 0x26, 0x63, 0x2B, 0xB5, 0x77, 0x26, 0xCB, 0x7B, 0x03, 0x00, 0xDC, 0x23, 0xEF, 0x14, 0x01, 0x1A, 0xAF, 0xC9, 0xA7, 0x5A, 0x2D, 0x75, 0x5A, 0x4D, 0x25, 0x5F, 0xEE, 0x05, 0x06, 0x8F, 0x6E, 0xFE, 0xE7, 0x77, 0x05, 0xD0, 0xF1, 0xF0, 0x87, 0xB7, 0xB2, 0xAD, 0x40, 0xEF, 0xAA, 0x63, 0x2B, 0x2A, 0xBB, 0x00, 0x6B, 0xA6, 0xCF, 0xB4, 0x6A, 0xBC, 0x05, 0xC4, 0xD9, 0x01, 0xE4, 0xF6, 0x19, 0x29, 0xDD, 0x80, 0x86, 0x1E, 0xD5, 0x7A, 0x71, 0xBD, 0x81, 0x5B, 0x3D, 0xAB, 0x7A, 0xB9, 0x35, 0x03, 0x39, 0x63, 0x1A, 0xE7, 0xBA, 0x3F, 0x01, 0xF6, 0x4C, 0x68, 0xEC, 0xE8, 0xA5, 0x0B, 0x04, 0xDE, 0xAB, 0x6B, 0xE5, 0x39, 0x1A, 0x70, 0x1F, 0x54, 0xFB, 0xD7, 0xE3, 0x01, 0x60, 0xBF, 0xBE, 0x6E, 0x96, 0x87, 0x33, 0xB0, 0xF1, 0x72, 0x5D, 0x4B, 0xF7, 0xE7, 0xE4, 0xC3, 0x68, 0x40, 0x75, 0x9E, 0xBC, 0x37, 0x17, 0x50, 0x9F, 0x45, 0x7E, 0x1A, 0x01, 0x68, 0xDB, 0xD7, 0x35, 0x57, 0x0D, 0x01, 0x3A, 0x2C, 0x2E, 0x1E, 0xD0, 0x6C, 0x0D, 0x0C, 0x98, 0x9B, 0xB2, 0xAF, 0x61, 0x23, 0x30, 0xDB, 0x7E, 0xDA, 0x31, 0x12, 0x70, 0xB3, 0xED, 0x56, 0x22, 0xEE, 0x41, 0xDB, 0x06, 0x03, 0x64, 0xD8, 0x4A, 0x07, 0x6B, 0x61, 0xC1, 0x59, 0xEB, 0x06, 0xA0, 0x61, 0x5C, 0x73, 0x7B, 0xD3, 0x25, 0xC0, 0x7F, 0xC1, 0xCD, 0xAA, 0xAB, 0xAA, 0x80, 0xCB, 0x35, 0x35, 0x79, 0x6B, 0x67, 0x02, 0xB9, 0xF3, 0xEB, 0x3E, 0x58, 0xE5, 0x01, 0x69, 0xC1, 0x8D, 0xF6, 0x9B, 0xC6, 0x01, 0x7B, 0x87, 0x35, 0x1D, 0xDF, 0x12, 0x00, 0x84, 0x3B, 0x35, 0x77, 0xDC, 0xBA, 0x95, 0x7C, 0xED, 0x0E, 0xA8, 0x57, 0x91, 0x25, 0x39, 0x72, 0x6D, 0x9A, 0xD4, 0x9A, 0xF6, 0x00, 0x9A, 0x16, 0xEF, 0x9B, 0xC9, 0x2E, 0x79, 0x9A, 0x0B, 0x0F, 0xDF, 0x27, 0x81, 0x11, 0xAE, 0x2E, 0x81, 0x64, 0xFF, 0xD6, 0xE3, 0x8F, 0xB6, 0x8D, 0x20, 0xBB, 0xFC, 0x59, 0x75, 0x1F, 0x20, 0x67, 0x07, 0x4C, 0xBF, 0xA7, 0xFE, 0x94, 0x0C, 0x5E, 0x3A, 0x70, 0xBC, 0xC8, 0x69, 0x9D, 0xFE, 0x39, 0x2E, 0x7C, 0xD8, 0xAB, 0xB5, 0x1E, 0xD0, 0xD4, 0xA5, 0x79, 0xCC, 0xF8, 0x9F, 0xC0, 0xBB, 0xBC, 0x86, 0xAA, 0xC9, 0xBF, 0xC4, 0xB7, 0x3C, 0xDF, 0xCD, 0xB1, 0x02, 0xAE, 0x29, 0xCB, 0x3E, 0x2F, 0x18, 0x0B, 0x9C, 0xFB, 0xD9, 0xA4, 0x6E, 0xDA, 0x03, 0x38, 0x32, 0x5A, 0xF6, 0x67, 0xF9, 0x14, 0xB2, 0x34, 0x13, 0xD0, 0xC8, 0x21, 0x49, 0x40, 0xC9, 0xF1, 0xE3, 0x6A, 0x52, 0xA7, 0x40, 0xEB, 0xF0, 0x99, 0x7F, 0x44, 0x1E, 0xF8, 0x8F, 0xF7, 0x4C, 0x79, 0x7E, 0x36, 0xE8, 0x61, 0xBB, 0x08, 0x91, 0x17, 0xD6, 0x00, 0xA4, 0xE1, 0xC3, 0xFE, 0xEB, 0x54, 0xC2, 0xC9, 0xF5, 0x1F, 0x01, 0x45, 0x19, 0xE9, 0x6F, 0xA0, 0x60, 0x06, 0x90, 0x91, 0x15, 0xCA, 0xB9, 0xC2, 0x23, 0xAD, 0x95, 0x06, 0x0B, 0x8B, 0xAE, 0x02, 0x03, 0x0A, 0x48, 0xEA, 0x29, 0x2E, 0x00, 0xCA, 0x1D, 0xC8, 0x11, 0xF3, 0x80, 0x37, 0x1B, 0x9B, 0x0F, 0x8D, 0x9D, 0x00, 0x3C, 0x99, 0xC2, 0x5B, 0x86, 0x65, 0x68, 0xBA, 0xE9, 0x43, 0x9A, 0xC8, 0x9A, 0xBE, 0x92, 0x80, 0xEA, 0x82, 0xCF, 0x79, 0xA4, 0xD6, 0x9B, 0x96, 0x87, 0xAE, 0x2D, 0x26, 0xDB, 0xF5, 0xD2, 0xFA, 0x15, 0x94, 0x41, 0x02, 0x83, 0x37, 0x4E, 0x2A, 0x14, 0x8E, 0x19, 0x06, 0x90, 0xDD, 0xBF, 0xF5, 0x2A, 0x54, 0xF9, 0x43, 0xCE, 0xD7, 0xC1, 0x73, 0xC5, 0x9F, 0xE4, 0x86, 0x2C, 0xC5, 0x9F, 0x0A, 0x07, 0x49, 0xF7, 0x72, 0x85, 0xC9, 0x00, 0x19, 0xF0, 0x41, 0xE1, 0xA6, 0x70, 0xFF, 0x1B, 0x85, 0x55, 0xC2, 0x73, 0x63, 0x31, 0x51, 0xF8, 0xE2, 0x1C, 0xD0, 0xB6, 0x84, 0x2C, 0xF3, 0x06, 0x44, 0xA6, 0x4F, 0x4F, 0x55, 0xE0, 0xAF, 0x11, 0x39, 0x20, 0x1A, 0x78, 0x97, 0x48, 0x0E, 0xCE, 0xFD, 0x5A, 0x40, 0x02, 0x1D, 0x56, 0xDE, 0xBE, 0x47, 0xB6, 0x09, 0xD5, 0x4C, 0x8A, 0x6F, 0x23, 0x72, 0xCF, 0x9E, 0x6B, 0x77, 0x91, 0xEA, 0x8F, 0x7B, 0x3D, 0x00, 0x44, 0x1E, 0x3A, 0xA3, 0xD5, 0x42, 0x72, 0xF2, 0x7B, 0x40, 0x21, 0x8F, 0x5C, 0x30, 0x47, 0xC1, 0x18, 0x9D, 0xC8, 0xD5, 0xCF, 0xD1, 0x09, 0x20, 0x6D, 0xD3, 0x01, 0xA1, 0xC7, 0x40, 0x49, 0xFF, 0x34, 0xC9, 0xAC, 0xF6, 0x92, 0x79, 0x0A, 0x92, 0x4F, 0x2E, 0x02, 0x0A, 0x03, 0xC9, 0x2F, 0xAA, 0x40, 0xDB, 0x43, 0x64, 0xDD, 0x33, 0x00, 0x68, 0xEE, 0xC3, 0xAF, 0x1D, 0xF3, 0x9E, 0x18, 0x91, 0x5A, 0xCA, 0x5A, 0xCA, 0x59, 0xE3, 0x49, 0x95, 0xF1, 0xDA, 0x69, 0x5B, 0xA7, 0x91, 0x30, 0xEE, 0x61, 0xA4, 0x73, 0x8D, 0xA2, 0xBF, 0x33, 0x40, 0xF6, 0x5E, 0xA5, 0x75, 0x00, 0x13, 0x48, 0x13, 0x28, 0xDE, 0x15, 0x79, 0xDE, 0x6D, 0x40, 0xB8, 0x22, 0x41, 0xD2, 0xEA, 0x3F, 0x49, 0xBB, 0x00, 0x49, 0xB7, 0x27, 0x92, 0x51, 0xBB, 0x24, 0x73, 0x52, 0x25, 0xF3, 0xCD, 0x24, 0x1F, 0x6E, 0x94, 0x7C, 0x1B, 0x00, 0x28, 0x2A, 0x91, 0xBF, 0xBB, 0x8A, 0x94, 0x30, 0x04, 0x10, 0xEE, 0xCD, 0x04, 0xD4, 0xDA, 0x93, 0xFE, 0x47, 0x81, 0xC1, 0x1F, 0xC8, 0xA5, 0xCF, 0x80, 0xA5, 0xCF, 0xC8, 0x35, 0x63, 0xF0, 0xCB, 0xE2, 0x27, 0x09, 0x00, 0xBB, 0x8A, 0x85, 0x6D, 0xBE, 0x45, 0x7D, 0x15, 0x1A, 0xE7, 0xC5, 0x8E, 0x17, 0xDA, 0x7F, 0x8B, 0x4E, 0x14, 0xFA, 0x21, 0xF4, 0x9B, 0x30, 0x85, 0x5E, 0x33, 0x85, 0xB7, 0x55, 0xA4, 0xFB, 0x4F, 0xFD, 0x2D, 0x13, 0x08, 0xC9, 0x49, 0xC6, 0x24, 0xE4, 0x9A, 0xFA, 0x96, 0xF6, 0x15, 0x2E, 0x8F, 0x7E, 0x33, 0x40, 0xB8, 0x82, 0x64, 0xE2, 0x75, 0x00, 0x90, 0xFB, 0x11, 0x50, 0xEC, 0x45, 0xEE, 0xFC, 0x0F, 0x18, 0x1C, 0x43, 0xCE, 0xF7, 0x03, 0xD6, 0x2E, 0x22, 0x6D, 0x96, 0x2A, 0xA5, 0x9A, 0xEB, 0x4B, 0x3B, 0xF6, 0xF4, 0x10, 0xB6, 0x28, 0x89, 0xBB, 0x2F, 0x9C, 0x31, 0x33, 0x6E, 0xB4, 0xD0, 0xFB, 0xB3, 0x74, 0x3F, 0xF3, 0xAA, 0x8A, 0xD6, 0x15, 0xEE, 0x1F, 0x1E, 0xF8, 0x50, 0x58, 0x6A, 0xBD, 0x7C, 0x29, 0xD9, 0x3B, 0xB4, 0xF9, 0xCB, 0x24, 0x7B, 0xB2, 0x6F, 0x01, 0x39, 0x79, 0x59, 0xD5, 0x35, 0x80, 0x5C, 0xA3, 0xF1, 0x6E, 0xA8, 0xD0, 0x4C, 0xEF, 0xE1, 0x29, 0xA0, 0xB9, 0x93, 0x59, 0x17, 0x32, 0xD9, 0x4A, 0xDA, 0x91, 0xE2, 0x02, 0x60, 0x21, 0x19, 0x3D, 0x1B, 0xE8, 0xF7, 0x98, 0x5C, 0x68, 0x0D, 0xAC, 0x4F, 0x26, 0x37, 0xBF, 0x03, 0xAC, 0x53, 0xC9, 0x7E, 0x67, 0x81, 0x50, 0xB1, 0x03, 0x40, 0xE2, 0x01, 0xE1, 0x94, 0xF0, 0x44, 0x63, 0xA1, 0x77, 0xE6, 0xBE, 0x56, 0x42, 0x8F, 0x36, 0xF1, 0x4A, 0xC2, 0xB4, 0xA6, 0xC0, 0x70, 0x72, 0xC0, 0x24, 0xD2, 0x78, 0x3E, 0xD9, 0xBB, 0x35, 0x39, 0xF3, 0x60, 0xB3, 0x2E, 0x40, 0x5A, 0x9A, 0x7F, 0xB2, 0x85, 0x50, 0xEB, 0xD1, 0x4C, 0xA0, 0x49, 0xC9, 0xD2, 0xF0, 0x6A, 0x21, 0xD0, 0xF0, 0xD7, 0x22, 0x8C, 0x4C, 0xA1, 0xB4, 0x23, 0xAD, 0x2D, 0xA0, 0x30, 0x87, 0xDC, 0x1B, 0x04, 0xF4, 0xF1, 0x22, 0x2D, 0x3E, 0x02, 0x16, 0xBB, 0xC8, 0xAD, 0xB9, 0xC0, 0xE6, 0xBB, 0xF2, 0x1D, 0xD9, 0x40, 0x78, 0x95, 0xB4, 0x23, 0x75, 0xBA, 0xD0, 0xE0, 0x46, 0xEA, 0x41, 0xA1, 0xD7, 0xE9, 0x64, 0x67, 0x61, 0x58, 0x8F, 0xC4, 0x26, 0xE1, 0x09, 0xED, 0x90, 0x07, 0x64, 0xBF, 0x3D, 0xE4, 0x0C, 0xB1, 0x17, 0xE4, 0xFA, 0xF2, 0x9F, 0x76, 0x42, 0xEB, 0xFC, 0xA7, 0x0A, 0x80, 0xEC, 0x8B, 0x95, 0xE9, 0xD5, 0x57, 0x40, 0xBD, 0xDD, 0xFA, 0xA2, 0xB3, 0x9D, 0xE4, 0x46, 0x59, 0xFB, 0x91, 0x69, 0x4B, 0xA5, 0x1D, 0x19, 0xB9, 0x92, 0x89, 0xB7, 0x81, 0x5E, 0xAB, 0x48, 0xDF, 0x59, 0xC0, 0xFC, 0x50, 0xD2, 0xE6, 0x2C, 0x60, 0x17, 0x42, 0xDA, 0x2F, 0xEF, 0x64, 0xEB, 0xF4, 0x57, 0xDA, 0x91, 0xA1, 0x46, 0xB6, 0xB3, 0x9A, 0x7C, 0x30, 0x65, 0xA7, 0xC8, 0x01, 0xF3, 0x53, 0xA6, 0x0B, 0x13, 0xCA, 0xD3, 0x3A, 0x08, 0xAF, 0x8F, 0xD9, 0xFD, 0x2F, 0x39, 0x20, 0x9E, 0x9C, 0x7F, 0xB0, 0x3C, 0x0D, 0x20, 0x37, 0xF3, 0x85, 0xE8, 0x2F, 0xDC, 0xF8, 0xEB, 0x9A, 0x12, 0x50, 0xDF, 0x6B, 0xA3, 0xF7, 0x99, 0x0D, 0x40, 0xDD, 0xAD, 0xCD, 0x36, 0x07, 0xB3, 0xE5, 0xCE, 0xD9, 0x52, 0x40, 0x66, 0x1A, 0x49, 0xFD, 0xD9, 0x15, 0x92, 0xA9, 0xF9, 0x40, 0xCF, 0x7F, 0x49, 0xCF, 0x6F, 0xC0, 0xB2, 0xEE, 0xA4, 0xD3, 0x5B, 0xC0, 0x6E, 0x2A, 0x69, 0x79, 0x0B, 0x08, 0xFE, 0x41, 0xAA, 0x8C, 0x04, 0x32, 0x8C, 0xC9, 0x31, 0x98, 0xD2, 0x78, 0xE0, 0x15, 0x09, 0x04, 0xAD, 0xCB, 0xEE, 0x20, 0xCC, 0x92, 0xA5, 0x06, 0x09, 0xBF, 0xDE, 0xD8, 0x53, 0x52, 0x79, 0x19, 0x20, 0xED, 0xA6, 0x3C, 0xED, 0x03, 0x34, 0x24, 0xDB, 0x5E, 0x29, 0x38, 0x0E, 0xD4, 0x39, 0xDA, 0x7E, 0x38, 0xDE, 0x45, 0x6E, 0xB0, 0xFD, 0x81, 0xD4, 0x5B, 0x40, 0xED, 0x77, 0x87, 0xC7, 0xB1, 0x19, 0xF2, 0x7C, 0x61, 0x5B, 0x3D, 0x79, 0x70, 0x8E, 0xD4, 0x7F, 0x64, 0xB4, 0x64, 0x8E, 0x0B, 0xD0, 0xF9, 0x04, 0x99, 0x96, 0x02, 0x4C, 0xEC, 0x40, 0xFA, 0xDE, 0x04, 0x6C, 0x6A, 0xC9, 0xA0, 0x39, 0x80, 0x97, 0x1A, 0x39, 0xAF, 0x1F, 0x90, 0x24, 0x17, 0x18, 0xD8, 0xF5, 0xF4, 0x76, 0x61, 0xF8, 0xAC, 0xA3, 0xCE, 0xC2, 0xEF, 0xA3, 0xB3, 0x7D, 0x5E, 0x77, 0x01, 0x2A, 0x9E, 0xC5, 0xB8, 0x5F, 0xDB, 0x08, 0xD4, 0x36, 0x3A, 0xA5, 0x1C, 0xB3, 0x94, 0x3B, 0xD0, 0x5D, 0xF7, 0x40, 0x84, 0xDC, 0xD7, 0x1E, 0xAD, 0x23, 0x9C, 0x80, 0x9A, 0x7A, 0x8F, 0x51, 0x7E, 0x0B, 0x80, 0x6A, 0x25, 0x8F, 0x8E, 0xCE, 0x93, 0x81, 0xAA, 0x67, 0x1E, 0x4E, 0x64, 0xAE, 0xA2, 0xD4, 0x7F, 0x22, 0x5B, 0xF2, 0xF8, 0x71, 0x40, 0x6F, 0x12, 0x99, 0xFD, 0x1E, 0x30, 0xDE, 0x4F, 0xA6, 0xDC, 0x05, 0x2C, 0x8A, 0xC9, 0xDD, 0x37, 0x01, 0xCF, 0x73, 0xA4, 0xFF, 0x17, 0x20, 0x26, 0x96, 0x54, 0x56, 0x07, 0x2E, 0xF4, 0x7B, 0xE4, 0x02, 0xEC, 0xEB, 0x98, 0x76, 0xE7, 0x60, 0x01, 0x50, 0x71, 0x2F, 0xDD, 0x3A, 0x24, 0x04, 0xA8, 0xD9, 0x91, 0x62, 0x1E, 0x9C, 0x20, 0xCF, 0x33, 0x76, 0x4C, 0x74, 0x0C, 0x05, 0xCA, 0x35, 0x77, 0x7A, 0x6C, 0x58, 0x29, 0xCF, 0xEB, 0x76, 0xAE, 0x5E, 0xDD, 0x02, 0xA8, 0x5C, 0xB2, 0x73, 0xC6, 0xE2, 0x52, 0xB9, 0x57, 0x76, 0x1C, 0x9E, 0x65, 0x04, 0x54, 0xBC, 0x0E, 0xBE, 0x4C, 0x9E, 0x1D, 0x29, 0xF5, 0xE7, 0x4F, 0x93, 0x2C, 0xA8, 0x06, 0x74, 0xA6, 0x90, 0xE7, 0x4C, 0x00, 0xE3, 0x6C, 0x79, 0x3E, 0xD2, 0x72, 0xC8, 0xD4, 0x1C, 0x32, 0x2F, 0x17, 0xD8, 0xB8, 0xE5, 0xEF, 0xB6, 0xB3, 0xDF, 0x01, 0x5B, 0x97, 0xC7, 0x69, 0x47, 0x87, 0x02, 0xBE, 0xDF, 0xFA, 0x1C, 0x04, 0xFA, 0xFC, 0xBA, 0x38, 0x57, 0xF9, 0x80, 0xF6, 0xCC, 0xD2, 0xB5, 0x17, 0x3B, 0x00, 0xED, 0xDB, 0x94, 0x5A, 0xE4, 0x26, 0xAA, 0xFF, 0x69, 0x91, 0xFC, 0xF9, 0x50, 0x52, 0xA0, 0xD2, 0x0F, 0x8D, 0xF0, 0x2F, 0xB7, 0xF7, 0xEF, 0x00, 0x34, 0x0E, 0x7C, 0x75, 0x8E, 0x0F, 0x06, 0x5A, 0xBC, 0xFB, 0x6E, 0x1C, 0xD7, 0x1A, 0x50, 0x6F, 0xFE, 0xF1, 0x36, 0x46, 0x06, 0xB4, 0x4A, 0x2A, 0xB9, 0xB6, 0x7B, 0x14, 0x79, 0x59, 0x5D, 0xEA, 0x2F, 0x8C, 0x90, 0xBC, 0xF6, 0x55, 0x69, 0xB7, 0x6E, 0x16, 0xF9, 0xAF, 0x29, 0x30, 0xAA, 0x99, 0x7C, 0xF8, 0x1C, 0x18, 0x93, 0x5A, 0xF1, 0xE9, 0x85, 0x2E, 0xA0, 0x9B, 0xF7, 0xF9, 0xE6, 0x67, 0x07, 0xA0, 0xC5, 0x89, 0x8B, 0x51, 0x1F, 0x3E, 0x00, 0x9B, 0x72, 0x81, 0x6B, 0x9F, 0x66, 0x04, 0x9E, 0x52, 0x01, 0x72, 0xBB, 0x56, 0xC7, 0x66, 0x6D, 0x02, 0xC2, 0x6D, 0xAB, 0x3E, 0xEE, 0xDB, 0x01, 0x38, 0x2C, 0xA8, 0x7B, 0x15, 0xF8, 0x06, 0xD8, 0x70, 0xB2, 0x6E, 0x6B, 0x50, 0x2C, 0xB0, 0xE6, 0x49, 0x8D, 0x45, 0xA0, 0x3B, 0xB0, 0x4C, 0xB3, 0xBA, 0x24, 0x60, 0x3F, 0xB0, 0x70, 0x59, 0xF5, 0x2A, 0xFF, 0x8F, 0xC0, 0xEC, 0xE5, 0x55, 0x37, 0xFD, 0x16, 0x90, 0x37, 0x1E, 0x03, 0x8A, 0x5D, 0xC9, 0xBB, 0x39, 0x80, 0xAA, 0x81, 0xBC, 0xB7, 0x5A, 0x65, 0x46, 0xEB, 0x17, 0xE4, 0xCB, 0x0A, 0xA0, 0x53, 0xFA, 0xDF, 0xA5, 0x9F, 0x66, 0x02, 0x2A, 0x5D, 0x9F, 0xB7, 0xFE, 0x7B, 0x0E, 0x50, 0xCD, 0xBD, 0xB0, 0xA2, 0x6E, 0x25, 0x30, 0x70, 0xA7, 0x4D, 0x7E, 0xCD, 0x67, 0xC0, 0x43, 0x11, 0x90, 0xED, 0x5A, 0xF4, 0x21, 0x69, 0x20, 0x50, 0x5B, 0x48, 0x46, 0xBB, 0x01, 0x0F, 0x3B, 0x54, 0xF7, 0xF6, 0x7D, 0x03, 0x1C, 0xAD, 0xA9, 0x7F, 0xB2, 0xC1, 0x14, 0x48, 0x1E, 0x21, 0xFB, 0x63, 0x73, 0x01, 0x88, 0xD9, 0xC6, 0x54, 0xFB, 0x7F, 0x80, 0x1D, 0xED, 0x64, 0xA9, 0xF6, 0xAA, 0x80, 0xD7, 0xE4, 0x86, 0xFD, 0x76, 0x49, 0x80, 0xD3, 0x8F, 0x86, 0x61, 0x76, 0x76, 0xE4, 0x63, 0x7B, 0x40, 0xED, 0x15, 0x59, 0x54, 0x0C, 0x68, 0xDC, 0x20, 0xBF, 0x55, 0x02, 0xCA, 0x9D, 0xFF, 0x96, 0x95, 0x59, 0x01, 0x6A, 0x6D, 0x1F, 0x95, 0x35, 0xBC, 0x03, 0x5A, 0x4D, 0x49, 0x6B, 0x55, 0xBF, 0x04, 0xD0, 0x8F, 0x5C, 0xA9, 0xDC, 0xB4, 0x17, 0x30, 0x3B, 0x02, 0xC8, 0x9E, 0x75, 0x78, 0xEE, 0xF5, 0x18, 0x68, 0x5A, 0xEC, 0x7A, 0xC7, 0xD6, 0x02, 0x68, 0xEE, 0x72, 0xDE, 0xDE, 0xEA, 0x3D, 0x20, 0xB3, 0xAE, 0xFC, 0x77, 0xED, 0x56, 0xA0, 0xE8, 0x4D, 0xF3, 0x9E, 0x29, 0x87, 0x81, 0x3B, 0x59, 0xB4, 0x9C, 0x77, 0x04, 0xB8, 0x30, 0x4A, 0x56, 0xBA, 0xA8, 0x0A, 0xC8, 0x3D, 0x24, 0xAB, 0x59, 0x16, 0x09, 0x64, 0x76, 0x96, 0xFD, 0xB7, 0x52, 0x11, 0xD8, 0xBF, 0x4F, 0xF6, 0x63, 0x55, 0x26, 0xF9, 0xCE, 0x14, 0x68, 0x91, 0x4D, 0xFE, 0x69, 0x00, 0x54, 0x1C, 0xAB, 0x77, 0xCA, 0x7A, 0x00, 0xCA, 0x65, 0xFF, 0x81, 0xD4, 0x54, 0x54, 0x59, 0x92, 0x1D, 0x46, 0x2A, 0xFC, 0xD3, 0xA9, 0xC2, 0xC1, 0x97, 0xD4, 0xAD, 0x1F, 0x34, 0x06, 0x20, 0x01, 0x73, 0x5F, 0xE1, 0x14, 0xE3, 0xA9, 0x4A, 0xAD, 0xC6, 0x90, 0xFE, 0x9D, 0x07, 0xB9, 0x8A, 0x9C, 0xDD, 0x53, 0xDF, 0x5B, 0x78, 0x73, 0x59, 0x6F, 0xF7, 0xAE, 0x37, 0x49, 0xB2, 0x4D, 0x17, 0xA0, 0xE4, 0x20, 0x39, 0x72, 0x00, 0x50, 0x7C, 0x95, 0x36, 0x63, 0xD2, 0x81, 0x87, 0x23, 0x48, 0x83, 0xAF, 0x50, 0xBA, 0xBE, 0x86, 0x34, 0x9E, 0x08, 0x9C, 0xDF, 0x48, 0x4E, 0x55, 0x23, 0x2B, 0xE6, 0x00, 0x1A, 0x67, 0xEA, 0xEA, 0x48, 0x40, 0xA5, 0x57, 0x91, 0x35, 0xD9, 0x32, 0xB8, 0xA5, 0x72, 0xEE, 0x3F, 0x64, 0xAB, 0x8B, 0x5A, 0xE3, 0xB6, 0xAB, 0x90, 0x6A, 0x85, 0x7D, 0xE2, 0x3A, 0x7A, 0x93, 0xC0, 0x54, 0x3B, 0x80, 0x1C, 0xB6, 0xA2, 0xFF, 0x62, 0x35, 0x3B, 0x72, 0x4D, 0x96, 0x42, 0x2F, 0x8C, 0x24, 0x7D, 0xCA, 0x00, 0x80, 0x8C, 0xBE, 0x80, 0x30, 0x61, 0x4E, 0x7B, 0x44, 0x09, 0x8B, 0x37, 0x01, 0x2D, 0xB3, 0xC8, 0x32, 0x5F, 0x40, 0x64, 0xB2, 0xDB, 0x62, 0xA0, 0xF4, 0x1A, 0xD9, 0xB7, 0x2B, 0xF0, 0xD6, 0x8B, 0xD4, 0x0F, 0x05, 0x9E, 0xBB, 0x90, 0x43, 0x77, 0xD5, 0xA6, 0x91, 0x80, 0x66, 0xDC, 0xEB, 0x5E, 0xF2, 0xFE, 0x2C, 0x8D, 0x55, 0x67, 0x2B, 0x49, 0xAD, 0x75, 0x2D, 0xEE, 0xBA, 0x7F, 0x26, 0x81, 0x9E, 0xC6, 0x46, 0x6B, 0x84, 0x03, 0xD2, 0x01, 0xB2, 0xAB, 0x79, 0xD7, 0x2E, 0x42, 0x13, 0x35, 0x85, 0x04, 0x3C, 0x23, 0x57, 0x65, 0xE1, 0x99, 0xC8, 0xAE, 0x0A, 0x80, 0x30, 0xD8, 0x51, 0x32, 0x61, 0x1B, 0x74, 0x84, 0xF9, 0xF9, 0x80, 0xF0, 0xA9, 0x3E, 0xA0, 0x60, 0x40, 0x7E, 0xD6, 0x04, 0x5A, 0xE4, 0x93, 0xD5, 0x6F, 0x00, 0xC5, 0xE1, 0x24, 0xD9, 0xF6, 0x03, 0x50, 0xD9, 0x9E, 0xEC, 0x5C, 0xF0, 0x9E, 0xA4, 0x96, 0x81, 0x96, 0xC1, 0xA5, 0xDB, 0xA4, 0xE6, 0x96, 0x16, 0xC5, 0x3B, 0xAB, 0x49, 0xA0, 0xAB, 0xDF, 0x82, 0x8F, 0x72, 0x67, 0xF6, 0x68, 0xAD, 0xF5, 0x8A, 0x6C, 0xBD, 0x46, 0xE7, 0x1F, 0xB5, 0x8D, 0xE4, 0xB8, 0x89, 0x00, 0x40, 0xCE, 0x30, 0x90, 0x5C, 0x39, 0x58, 0xD2, 0xEE, 0xB0, 0xA4, 0xBF, 0x9B, 0x64, 0x98, 0x87, 0x64, 0xD6, 0x23, 0xC9, 0xB3, 0x1D, 0x24, 0xEF, 0x77, 0x93, 0x7C, 0x75, 0x18, 0xC0, 0x03, 0xF2, 0xFB, 0x73, 0x40, 0x71, 0x23, 0x59, 0xDD, 0x11, 0xB8, 0xF1, 0x8E, 0xD4, 0x0C, 0xD0, 0x0C, 0x88, 0x77, 0x21, 0x81, 0xD6, 0xE7, 0xCC, 0xB3, 0x84, 0xED, 0xEC, 0x7A, 0x77, 0x23, 0x35, 0xCB, 0x34, 0xCB, 0x00, 0xB2, 0x6B, 0xA1, 0xFA, 0x56, 0xE1, 0xF8, 0x79, 0x80, 0x70, 0xD6, 0x30, 0xC9, 0x65, 0x66, 0x92, 0x56, 0xFD, 0x24, 0x1D, 0x1E, 0x4B, 0xFA, 0x41, 0x32, 0xB2, 0x54, 0x32, 0x23, 0x4D, 0xF2, 0x94, 0x94, 0xF9, 0xEF, 0x01, 0xC9, 0xA7, 0x9F, 0x25, 0xDF, 0x77, 0x06, 0xC8, 0x5D, 0xEE, 0x80, 0x30, 0x74, 0xA5, 0xA4, 0x6F, 0x12, 0xA0, 0xD3, 0x97, 0x5C, 0x78, 0x08, 0x58, 0x78, 0x88, 0x9C, 0x6B, 0x06, 0x58, 0x80, 0x04, 0x80, 0xA0, 0x0E, 0x42, 0x4D, 0x95, 0x70, 0x65, 0xA1, 0xC1, 0xDE, 0x78, 0x3D, 0xE1, 0x52, 0xA3, 0xA4, 0x5C, 0xA1, 0xD7, 0x8A, 0x90, 0xBB, 0xC2, 0x14, 0xBA, 0x87, 0x08, 0x0B, 0x63, 0x2D, 0x40, 0x76, 0xB8, 0x5F, 0x7B, 0xCF, 0xF0, 0x33, 0xA9, 0x73, 0xB2, 0x21, 0x77, 0xE4, 0x49, 0xB9, 0xDB, 0xC9, 0x51, 0xFE, 0x24, 0x40, 0x1A, 0x07, 0x56, 0x8D, 0x13, 0x4E, 0xCE, 0x21, 0x77, 0x43, 0xEA, 0x0F, 0x0F, 0x93, 0x0C, 0xDD, 0x0F, 0x68, 0x5A, 0x90, 0xF3, 0xAA, 0x80, 0xE5, 0xC3, 0x48, 0xF3, 0x39, 0xC0, 0xEA, 0x97, 0xD2, 0x8E, 0x10, 0x21, 0x5A, 0x9A, 0x47, 0xE4, 0x09, 0xA7, 0x16, 0x46, 0x1B, 0x0B, 0xDD, 0xBB, 0x84, 0x1B, 0x08, 0x7D, 0x96, 0x87, 0xEF, 0x16, 0x26, 0xEF, 0xF6, 0x5D, 0x25, 0x2C, 0xF0, 0xB7, 0x4E, 0x22, 0x75, 0xA3, 0xAA, 0x0A, 0x46, 0xC6, 0x90, 0x1D, 0xED, 0x18, 0x32, 0x2A, 0x94, 0x54, 0x7C, 0x42, 0x9A, 0xCC, 0x6A, 0x4C, 0x07, 0xC8, 0x29, 0xB7, 0x7E, 0x78, 0x0B, 0x67, 0x56, 0x93, 0x51, 0x45, 0x52, 0xFF, 0xEE, 0xD7, 0x92, 0x11, 0x89, 0x80, 0x96, 0x0F, 0xB9, 0xA0, 0x0C, 0x58, 0x59, 0x46, 0x5A, 0xE4, 0x01, 0x66, 0xAE, 0xD2, 0x8E, 0xDD, 0xBD, 0x85, 0xB8, 0x1E, 0x13, 0x29, 0x9C, 0xB2, 0x3E, 0x26, 0x5C, 0xE8, 0x71, 0x35, 0x6A, 0xB6, 0xD0, 0x6B, 0x70, 0xB4, 0x8B, 0xF0, 0xC0, 0x87, 0x80, 0x47, 0xC2, 0xDB, 0xF1, 0xD6, 0x7F, 0xC8, 0x0E, 0x7B, 0xEB, 0x72, 0xC6, 0x54, 0x90, 0xED, 0xA7, 0x93, 0xE3, 0x53, 0x49, 0x80, 0x9C, 0x66, 0xF2, 0xA7, 0x5E, 0x38, 0xA7, 0xFD, 0x9B, 0xC5, 0xC2, 0xB9, 0x9F, 0xC8, 0xD8, 0x95, 0x52, 0x7F, 0xF4, 0x37, 0xC9, 0xA8, 0xE1, 0x40, 0x1B, 0x07, 0x72, 0xC1, 0x6B, 0x60, 0xAD, 0x32, 0x69, 0x29, 0x9C, 0x41, 0x76, 0xFD, 0x04, 0x04, 0xBF, 0x90, 0xF6, 0xEC, 0x2D, 0x16, 0x9A, 0x44, 0xC7, 0x2F, 0x16, 0x7A, 0xEA, 0xC5, 0x99, 0x09, 0xBD, 0xD6, 0xEF, 0x6D, 0x2D, 0x3C, 0x72, 0xCC, 0x5F, 0x4B, 0x58, 0xB2, 0xD4, 0x2A, 0x82, 0xEC, 0x6E, 0x28, 0xEF, 0xEF, 0x4A, 0x42, 0xF4, 0x6E, 0x29, 0x8B, 0x12, 0xCE, 0x7F, 0xFB, 0xA6, 0x5C, 0xB8, 0xD0, 0xFA, 0x91, 0x83, 0x70, 0x51, 0x1E, 0x99, 0xA0, 0x27, 0xF5, 0xEF, 0xD5, 0x97, 0x8C, 0x1D, 0x0B, 0xE8, 0x5C, 0x20, 0x17, 0x3C, 0x00, 0xAC, 0x2D, 0xC9, 0x75, 0xDA, 0x80, 0x65, 0x14, 0xD9, 0xB9, 0x10, 0x08, 0xCB, 0x95, 0x76, 0x24, 0xED, 0x10, 0x8E, 0xF8, 0x9C, 0xB2, 0x48, 0xE8, 0x39, 0x33, 0xF1, 0xAD, 0x30, 0xA5, 0xEB, 0x3E, 0x57, 0xE1, 0x95, 0xD4, 0x60, 0x5D, 0x52, 0xFB, 0x4B, 0xCD, 0x9B, 0xB5, 0x26, 0x24, 0x44, 0x4F, 0xA7, 0xDF, 0x96, 0x42, 0xD3, 0x97, 0xC5, 0xFD, 0x84, 0xCB, 0xDA, 0xDF, 0xF9, 0x28, 0xF7, 0xCB, 0xB2, 0xF2, 0x82, 0x85, 0x40, 0xD3, 0xAA, 0x15, 0x6A, 0x64, 0x4A, 0x5B, 0xA9, 0x3F, 0xA9, 0x37, 0x24, 0x2F, 0x01, 0x3A, 0x5E, 0xA4, 0xFF, 0x00, 0x60, 0x0E, 0xC8, 0xCD, 0x4E, 0xC0, 0xFA, 0x2F, 0xA4, 0x55, 0xBE, 0xA2, 0xAE, 0xCB, 0x05, 0x69, 0x47, 0x66, 0x0F, 0x52, 0xF3, 0xDE, 0xB8, 0x1D, 0x29, 0xE7, 0x45, 0xF6, 0x36, 0x4C, 0x5D, 0x2C, 0xCC, 0xDA, 0x2D, 0xDD, 0x4B, 0x7E, 0x54, 0x84, 0x9D, 0x6F, 0x5A, 0x04, 0x34, 0x4D, 0xB4, 0xAB, 0x79, 0xFB, 0x12, 0x20, 0xCD, 0x1E, 0xDC, 0xB5, 0x94, 0x67, 0x67, 0x73, 0xAD, 0x8B, 0xA1, 0x40, 0x43, 0xA9, 0xF9, 0xE3, 0x13, 0x8E, 0x40, 0xFD, 0x5D, 0xCB, 0x71, 0xD9, 0x03, 0xE5, 0x96, 0xAD, 0x3B, 0x45, 0x66, 0x74, 0x96, 0xFA, 0x53, 0x13, 0x21, 0x69, 0x01, 0x74, 0xD9, 0x49, 0xC6, 0xFD, 0x0B, 0x18, 0xEB, 0x91, 0x7E, 0x1E, 0x80, 0x85, 0x13, 0xE9, 0x12, 0x01, 0x38, 0xDD, 0x21, 0x97, 0x5C, 0x01, 0xA2, 0x5F, 0x92, 0xC3, 0xFA, 0x8E, 0x9D, 0x95, 0x32, 0x80, 0x04, 0x82, 0x67, 0x64, 0x05, 0x0B, 0x3F, 0xE5, 0xED, 0xEF, 0xFC, 0x6C, 0x3D, 0x50, 0xDE, 0x23, 0xA4, 0xFA, 0x46, 0x18, 0x50, 0x3B, 0xDA, 0xE5, 0xE0, 0x99, 0xE5, 0x40, 0xDD, 0x99, 0xCD, 0x1B, 0xB3, 0x2F, 0xC8, 0x73, 0xAF, 0xAD, 0xB9, 0x09, 0xE5, 0xF2, 0x3C, 0xDC, 0xB6, 0x43, 0xD4, 0x06, 0xA0, 0xFE, 0x88, 0x5D, 0x46, 0xE0, 0x00, 0x79, 0xD6, 0xB4, 0x7B, 0x42, 0x1E, 0xD6, 0x95, 0xFA, 0x0F, 0x75, 0x93, 0x3C, 0x18, 0x0F, 0xE8, 0x55, 0x91, 0xC9, 0xE1, 0x80, 0x71, 0x03, 0x99, 0x1E, 0x00, 0xCC, 0x1D, 0x42, 0xEE, 0x5E, 0x09, 0xD8, 0x56, 0x48, 0x7F, 0xAE, 0xBB, 0xE3, 0xDE, 0x8F, 0xCB, 0xFD, 0x6B, 0x80, 0x9C, 0xC6, 0xCB, 0x63, 0x80, 0x9D, 0xEB, 0xE2, 0x1E, 0x64, 0x28, 0x89, 0x13, 0x37, 0xD6, 0xCD, 0xEF, 0x0C, 0x20, 0x6B, 0x8A, 0xAD, 0xF4, 0xD6, 0x07, 0x2A, 0x27, 0x84, 0xF5, 0x77, 0x71, 0x07, 0x2A, 0xB2, 0xBD, 0xA7, 0x6E, 0x39, 0x2D, 0xCF, 0x67, 0xBD, 0x6F, 0x59, 0x66, 0x02, 0x55, 0xD7, 0xBD, 0x0B, 0x56, 0xCE, 0x05, 0xAA, 0x3B, 0x7A, 0xFF, 0x58, 0x90, 0x20, 0xCF, 0xFB, 0xBD, 0xBD, 0xA4, 0x3F, 0x1F, 0x04, 0xC8, 0xD3, 0x26, 0x92, 0x67, 0x3A, 0x02, 0x7A, 0xD7, 0xC8, 0x53, 0xBB, 0x81, 0xB1, 0xA6, 0xE4, 0xD9, 0x78, 0xC0, 0x24, 0x8C, 0xBC, 0x9C, 0xAA, 0x5C, 0x3F, 0x7D, 0xEF, 0xF7, 0xC7, 0x67, 0xAF, 0x02, 0x33, 0x62, 0x6E, 0x24, 0x67, 0xB8, 0x01, 0x5B, 0x6F, 0xF7, 0xFD, 0xA0, 0x7C, 0xA4, 0x47, 0xEC, 0xC9, 0xFD, 0x80, 0xF6, 0xBE, 0x37, 0xEB, 0x4E, 0x8F, 0x03, 0x3A, 0xE4, 0xFF, 0xF5, 0x3D, 0xB8, 0x02, 0x68, 0xFB, 0xE5, 0x5B, 0xCF, 0x24, 0x73, 0x40, 0x65, 0xE8, 0xF7, 0x5B, 0xB1, 0x8F, 0x01, 0xD5, 0xBD, 0x3F, 0xFF, 0x8D, 0xB1, 0x00, 0xD4, 0xCF, 0xFC, 0x6A, 0x13, 0x39, 0x0B, 0xD0, 0xF0, 0xF9, 0x95, 0x10, 0xBE, 0x1F, 0x68, 0xDB, 0xF2, 0xCF, 0xCD, 0x9D, 0xCE, 0x64, 0xC1, 0x69, 0xA9, 0xBF, 0xF0, 0x3E, 0x24, 0x2D, 0x01, 0xDD, 0xB9, 0xE4, 0xF5, 0xA5, 0xC0, 0x80, 0x59, 0xE4, 0xC3, 0x57, 0x40, 0x3B, 0xDD, 0xCF, 0xFF, 0x3D, 0xEC, 0x07, 0x00, 0x4F, 0xBA, 0x3F, 0xA9, 0x16, 0x9E, 0xE9, 0x59, 0xF4, 0x00, 0x58, 0x18, 0x0C, 0x1C, 0x55, 0xEF, 0x67, 0x7A, 0xD8, 0x0C, 0x38, 0xAC, 0xF5, 0x75, 0x67, 0xD2, 0x1E, 0x60, 0x57, 0x79, 0x43, 0x70, 0xE4, 0x69, 0xC0, 0xF9, 0x4F, 0xED, 0x8B, 0x80, 0xCF, 0xC0, 0xC6, 0xC1, 0x75, 0xF1, 0xAE, 0x2B, 0x01, 0x8B, 0xB5, 0x75, 0xFB, 0x5D, 0xC7, 0x02, 0xAB, 0x23, 0xEB, 0x66, 0xBB, 0xDC, 0x01, 0x96, 0x47, 0xD5, 0x0D, 0x73, 0x31, 0x05, 0x16, 0x6D, 0xAC, 0xB5, 0x73, 0xDE, 0x23, 0xEF, 0x6B, 0x06, 0x14, 0x4F, 0x91, 0xB7, 0x8C, 0x81, 0x16, 0x2A, 0xE4, 0xBD, 0x9F, 0x40, 0x9B, 0x35, 0xE4, 0xAB, 0x5D, 0x80, 0x62, 0xEE, 0xFB, 0x0E, 0xC5, 0x77, 0x00, 0xE0, 0xEA, 0xFD, 0x37, 0x1B, 0x85, 0x67, 0xAD, 0xCA, 0xEB, 0x01, 0xA5, 0x1D, 0x7E, 0x25, 0x15, 0x57, 0x81, 0x65, 0xCF, 0x80, 0xF2, 0x6F, 0x06, 0x8A, 0xB1, 0xED, 0x80, 0xBF, 0xBB, 0x4A, 0x3A, 0x85, 0x66, 0x02, 0xB7, 0x5E, 0x35, 0x46, 0xB8, 0x1A, 0x02, 0xA7, 0xC2, 0x6B, 0xFC, 0xAC, 0x76, 0x03, 0xA9, 0x46, 0xB2, 0x92, 0xD5, 0x05, 0x40, 0xDC, 0x44, 0x99, 0xBF, 0xB9, 0x33, 0x10, 0x3E, 0x5F, 0xE6, 0x64, 0x31, 0x18, 0x08, 0xCA, 0x94, 0x1D, 0xB0, 0x74, 0x04, 0xBC, 0xBE, 0x36, 0xDE, 0xB4, 0xDC, 0x41, 0x3E, 0xFA, 0x08, 0xA8, 0x97, 0x90, 0x45, 0xA3, 0x81, 0x16, 0x9A, 0x4D, 0xA9, 0x9F, 0xAA, 0x00, 0xE0, 0x6B, 0xDF, 0x5F, 0x77, 0x85, 0xD7, 0x9B, 0xCB, 0x0D, 0x85, 0xA9, 0x05, 0xB5, 0x3D, 0x01, 0xE5, 0xF7, 0x5B, 0x6F, 0x34, 0x28, 0x03, 0x63, 0x95, 0x55, 0xD6, 0xD7, 0x84, 0x01, 0xF6, 0x81, 0x40, 0xF3, 0x9C, 0x35, 0x1E, 0x5B, 0x4C, 0xE4, 0x5E, 0x3C, 0xDB, 0x72, 0xFD, 0x3E, 0xA0, 0x66, 0x59, 0x75, 0xE1, 0xCA, 0x7F, 0x81, 0x37, 0x2D, 0x6B, 0x1F, 0x4D, 0x55, 0x06, 0x6E, 0x2B, 0x93, 0x06, 0x91, 0xC0, 0xA5, 0x11, 0xA4, 0xB1, 0x0C, 0x38, 0x5D, 0x49, 0x4E, 0xBD, 0x0A, 0x1C, 0xF5, 0x27, 0x67, 0xA6, 0x00, 0x19, 0x26, 0xE4, 0xEC, 0x46, 0xF2, 0xDD, 0x3B, 0x40, 0xE3, 0x0D, 0x59, 0xFA, 0x7F, 0x7C, 0xDC, 0x07, 0x38, 0x97, 0xDF, 0x1F, 0x3F, 0xFE, 0xA7, 0x95, 0xDD, 0xB0, 0x4A, 0x09, 0x91, 0x99, 0x51, 0xCA, 0x96, 0x16, 0x6D, 0x33, 0x84, 0x52, 0x42, 0x29, 0xED, 0x34, 0xA4, 0x4D, 0xDA, 0x9B, 0x52, 0x69, 0xA0, 0x41, 0x43, 0x2A, 0xDA, 0x5B, 0x88, 0xA6, 0xF6, 0x90, 0x0A, 0xA5, 0xA5, 0x90, 0x86, 0xDD, 0xFF, 0xBC, 0x7E, 0x2F, 0xFF, 0xEB, 0xF3, 0x1D, 0xBF, 0xDF, 0xF7, 0x73, 0x5D, 0xB7, 0xC7, 0x45, 0x1F, 0xEF, 0xD7, 0xF1, 0xBE, 0xCF, 0x7D, 0xCE, 0xF3, 0x3E, 0xF7, 0xE1, 0x03, 0x00, 0x7C, 0xA9, 0xAA, 0x53, 0x23, 0x0B, 0x2F, 0xB5, 0xCC, 0x05, 0xA4, 0xCE, 0xEE, 0xAB, 0xF9, 0xBB, 0x1B, 0x90, 0xB7, 0x9C, 0x2C, 0xEE, 0xBC, 0x01, 0xFD, 0x65, 0xBA, 0x71, 0xA4, 0x8B, 0x3F, 0x9D, 0x41, 0xDB, 0xB4, 0xFE, 0x71, 0xE6, 0x62, 0x24, 0x5F, 0x15, 0xD9, 0xF1, 0x1D, 0x68, 0x7E, 0x4D, 0x30, 0x57, 0x22, 0x1F, 0x8C, 0x33, 0x9D, 0xAA, 0x2D, 0x56, 0xDC, 0x1B, 0x94, 0x3A, 0xB4, 0x05, 0xBE, 0x8B, 0x6B, 0x41, 0xBF, 0x08, 0x78, 0x2D, 0xD6, 0x40, 0x8D, 0x8E, 0x01, 0x8F, 0xC5, 0x35, 0x68, 0xF6, 0x05, 0x28, 0x14, 0x7D, 0xAE, 0xE7, 0x02, 0xE0, 0xBA, 0xB0, 0x77, 0x9A, 0x98, 0x75, 0xCB, 0x00, 0x85, 0x9C, 0x9A, 0x1E, 0xF4, 0xFA, 0xD2, 0x05, 0xF7, 0xC4, 0xFA, 0x8E, 0x54, 0xB1, 0x54, 0x8F, 0x14, 0x27, 0xFA, 0x5C, 0xC9, 0x33, 0x7C, 0x32, 0xD9, 0xAD, 0xA3, 0xF8, 0x66, 0xA1, 0xDD, 0x6F, 0xAA, 0xA3, 0x5D, 0x6F, 0x64, 0x48, 0xFB, 0x73, 0x7C, 0x3D, 0xA5, 0x41, 0x9F, 0x2F, 0xDC, 0x0E, 0x90, 0x5B, 0x7D, 0xD9, 0x0C, 0x15, 0xB6, 0xE8, 0x35, 0x20, 0x11, 0x29, 0x92, 0x56, 0x2F, 0x40, 0xA3, 0x1F, 0xAF, 0x38, 0x01, 0x75, 0x67, 0xC5, 0x18, 0x9F, 0x09, 0x7C, 0x52, 0x15, 0x2B, 0x5C, 0x69, 0xC0, 0x6B, 0xB1, 0x36, 0xAE, 0x3B, 0xAD, 0x66, 0x04, 0xFD, 0x6B, 0x87, 0xC4, 0x47, 0x62, 0x24, 0x96, 0x7B, 0x22, 0x1B, 0x79, 0xA4, 0x59, 0xE4, 0xAF, 0x12, 0x19, 0xD9, 0x59, 0x62, 0xA4, 0xA2, 0x75, 0x42, 0xA7, 0x4C, 0xB2, 0xCB, 0x30, 0x40, 0xCC, 0x58, 0x13, 0x35, 0xFC, 0x61, 0x2C, 0x66, 0x29, 0x13, 0xAE, 0xE3, 0xF3, 0x9C, 0x9D, 0x5D, 0xC9, 0xAE, 0x72, 0x64, 0x93, 0x25, 0xD9, 0xAC, 0x14, 0xF6, 0xF9, 0x68, 0xB6, 0xEC, 0x93, 0x40, 0xDC, 0xA9, 0xD4, 0xC8, 0x02, 0xB4, 0xCF, 0xE9, 0x6F, 0x31, 0x00, 0xB4, 0x88, 0xA4, 0xA1, 0x78, 0xE5, 0xB9, 0x48, 0xD9, 0x4A, 0x1F, 0x95, 0x3E, 0x9E, 0x3A, 0x26, 0xEA, 0xE7, 0xCB, 0x7C, 0x59, 0x74, 0x9D, 0xEA, 0x76, 0x38, 0xE9, 0x7A, 0x99, 0x54, 0x1B, 0x27, 0xD7, 0x20, 0xFE, 0xBD, 0x49, 0x71, 0x0C, 0xC4, 0xBB, 0x6A, 0xDE, 0x7A, 0xC7, 0x37, 0x60, 0x35, 0xEB, 0x93, 0xC8, 0x46, 0x78, 0xB2, 0x2B, 0x7A, 0xB3, 0x5B, 0x02, 0xD9, 0xD4, 0x15, 0xEC, 0x85, 0x56, 0xEF, 0x36, 0xB1, 0x2F, 0x97, 0xB2, 0xE5, 0x0F, 0x04, 0x22, 0x11, 0x54, 0x75, 0x01, 0x2E, 0x88, 0x3B, 0x36, 0xF9, 0xDD, 0xF2, 0xBB, 0xD7, 0x7C, 0xA1, 0xBA, 0xCA, 0xF7, 0xBD, 0xA7, 0x93, 0x8A, 0x7B, 0x34, 0x44, 0x7B, 0x65, 0x57, 0xC9, 0xAE, 0x02, 0xC4, 0xBB, 0xF8, 0x4C, 0xCA, 0x9E, 0xEC, 0x19, 0x02, 0x90, 0x03, 0x7F, 0xB0, 0xDE, 0xF6, 0x6C, 0x30, 0xD8, 0xC8, 0x03, 0x6C, 0x8C, 0x3A, 0xBB, 0x2D, 0x90, 0x3D, 0x9C, 0xC5, 0x66, 0x9D, 0x66, 0x6F, 0x9E, 0x62, 0x1F, 0x04, 0xB2, 0xAF, 0xA4, 0xE9, 0x63, 0xF4, 0x5D, 0x80, 0x9C, 0xA3, 0xC2, 0xCE, 0x6A, 0x06, 0xDA, 0xB7, 0x88, 0xD4, 0x95, 0x03, 0x0C, 0x13, 0xE3, 0x99, 0x89, 0xF1, 0x3F, 0x39, 0x68, 0xF1, 0x3E, 0x52, 0x21, 0x65, 0x5D, 0x32, 0x69, 0xB9, 0x77, 0xFF, 0xDF, 0x7F, 0x5A, 0x01, 0x44, 0x97, 0xED, 0x2E, 0xE3, 0x1C, 0x14, 0xE5, 0x4D, 0x9E, 0x0D, 0xA5, 0xEF, 0x53, 0x9D, 0x51, 0x3B, 0xDD, 0x79, 0xBD, 0xC8, 0xA2, 0x49, 0x3F, 0x97, 0xF7, 0x4A, 0x12, 0x67, 0x5F, 0xCC, 0xD5, 0xC6, 0xE2, 0x00, 0x44, 0xBF, 0x55, 0x69, 0xF5, 0x87, 0x48, 0xDB, 0xCA, 0xE0, 0x9F, 0xA6, 0xD5, 0x25, 0x87, 0x01, 0xC5, 0xAF, 0x62, 0x6E, 0xCE, 0x05, 0x46, 0xC4, 0x89, 0xB3, 0xF1, 0x05, 0x08, 0x0E, 0xE4, 0x76, 0xC4, 0x44, 0x93, 0xF2, 0x27, 0x39, 0x0F, 0xD9, 0x9E, 0x38, 0xEC, 0x44, 0x06, 0x2D, 0x39, 0xBB, 0x8E, 0x5C, 0x64, 0x1A, 0xEF, 0x45, 0x1E, 0xE8, 0x1B, 0x75, 0x9B, 0xBC, 0xF0, 0x2A, 0x58, 0xBC, 0xDB, 0x9A, 0x53, 0x1B, 0xED, 0xAC, 0xC2, 0xC4, 0xD9, 0xCD, 0x6B, 0x9C, 0x60, 0xD6, 0xBD, 0xB5, 0xEE, 0x74, 0xD6, 0xF8, 0x3D, 0xDB, 0x43, 0x8C, 0x5B, 0x2B, 0x93, 0xB9, 0xFE, 0x82, 0xCD, 0xEC, 0x4A, 0x55, 0x40, 0xA1, 0x42, 0xB4, 0xE3, 0x14, 0xE0, 0x2E, 0xEE, 0xF3, 0xAD, 0x57, 0x00, 0x13, 0xDC, 0x5A, 0x73, 0xA1, 0x07, 0x29, 0xE3, 0xB5, 0xC6, 0x94, 0xEC, 0xAF, 0xBF, 0x65, 0x0A, 0x39, 0x67, 0xF2, 0x86, 0xB9, 0xE4, 0x52, 0xF3, 0xB5, 0x24, 0xF6, 0x0E, 0x5D, 0x42, 0xE2, 0x52, 0xE9, 0xA4, 0x51, 0xE2, 0x1E, 0xE6, 0x58, 0xBD, 0xBD, 0x99, 0xF8, 0xF9, 0xE5, 0xC4, 0xCF, 0x6E, 0xB0, 0x89, 0xEB, 0x9A, 0x8D, 0x64, 0xCD, 0x57, 0xFF, 0xD8, 0x43, 0xF6, 0x14, 0x75, 0xD6, 0x7A, 0x81, 0x7B, 0xD9, 0x02, 0x76, 0xAD, 0x04, 0xA0, 0xA4, 0x2E, 0xDA, 0x91, 0x0C, 0x8C, 0x12, 0xE7, 0xC5, 0xEB, 0x28, 0x30, 0xA6, 0x1B, 0xB7, 0x23, 0x4E, 0x81, 0xDD, 0xE4, 0x40, 0xF6, 0xD3, 0xDC, 0x74, 0x8B, 0x8C, 0xDA, 0xB7, 0x61, 0x03, 0xB9, 0x78, 0xC8, 0x66, 0x12, 0x87, 0x3C, 0x56, 0x48, 0x91, 0xF7, 0xB6, 0x4D, 0x7A, 0x28, 0x7A, 0x9F, 0xF8, 0x99, 0x0C, 0x9F, 0x73, 0xDD, 0x5E, 0x19, 0xAD, 0x2E, 0xAE, 0x72, 0x27, 0x6D, 0x52, 0xDF, 0xC6, 0x92, 0x8E, 0x83, 0x45, 0xAA, 0x6E, 0x4D, 0xDB, 0x6B, 0xD4, 0xD8, 0xF5, 0x6F, 0x80, 0xF6, 0xB2, 0x22, 0xAB, 0x75, 0x03, 0xC6, 0x88, 0xF6, 0x8C, 0x7D, 0x04, 0x04, 0x8A, 0xF7, 0x43, 0x7D, 0x2D, 0x10, 0xB3, 0x91, 0xDB, 0x11, 0x7F, 0x9F, 0xB4, 0x8E, 0xDD, 0x7E, 0x83, 0x8C, 0xF6, 0xD8, 0x66, 0x40, 0xEE, 0xF6, 0xD9, 0x6A, 0x46, 0x5E, 0xBC, 0x1D, 0x23, 0xAE, 0xBE, 0x36, 0x2B, 0x6B, 0x2E, 0x84, 0x6E, 0xE4, 0xBA, 0x7D, 0xE4, 0x7E, 0x49, 0x93, 0x0E, 0x8F, 0xCA, 0xDC, 0xC8, 0x01, 0x9D, 0x9E, 0xE6, 0x91, 0x83, 0x12, 0x6F, 0x3B, 0x90, 0x2E, 0x3B, 0x45, 0x0E, 0x9B, 0x01, 0xBE, 0xDA, 0x32, 0xD8, 0x6D, 0x1B, 0xE8, 0xC9, 0xA8, 0x58, 0x0F, 0x3A, 0x06, 0x0C, 0x10, 0xEB, 0x3B, 0xE3, 0xC3, 0x80, 0xF1, 0xA2, 0xDF, 0x85, 0xFB, 0x2B, 0x8C, 0x09, 0xA3, 0x3A, 0x00, 0x92, 0x0A, 0x49, 0xD3, 0x9F, 0x49, 0xA5, 0xE4, 0xC2, 0xFC, 0x9D, 0xDE, 0x64, 0xFA, 0xC6, 0x6D, 0x43, 0xC8, 0xEA, 0x3D, 0x71, 0xBB, 0x7F, 0x77, 0x00, 0xEA, 0x54, 0x23, 0x1A, 0x4A, 0xCE, 0x80, 0xF2, 0x68, 0x69, 0x51, 0x21, 0x39, 0x7C, 0xD7, 0xCD, 0x4B, 0xE4, 0x88, 0x37, 0x17, 0xFC, 0x85, 0xA5, 0xEE, 0x91, 0x99, 0xFB, 0x81, 0xE6, 0xD1, 0x5E, 0xED, 0x44, 0x1E, 0xEB, 0xCB, 0xF5, 0x93, 0x16, 0xB1, 0x7B, 0xA7, 0x00, 0x1D, 0xA2, 0x44, 0x7E, 0x7F, 0x05, 0xD8, 0x89, 0xFC, 0x3F, 0xF1, 0x32, 0x10, 0x26, 0xF2, 0x6E, 0xC4, 0x60, 0x60, 0x5A, 0xB9, 0xC8, 0x94, 0xCB, 0x81, 0x35, 0xD4, 0xDF, 0xD1, 0xC9, 0xE1, 0x80, 0x04, 0xB9, 0x62, 0x5A, 0x52, 0xD0, 0xE7, 0x68, 0xE0, 0x85, 0xDA, 0xCA, 0x80, 0xC2, 0x30, 0xE0, 0xD7, 0xA7, 0xC5, 0x5E, 0x97, 0xDF, 0x03, 0xBF, 0xBB, 0xCC, 0xB9, 0x9B, 0xA5, 0x07, 0x34, 0x2D, 0x1E, 0x8D, 0x74, 0x7A, 0x32, 0x72, 0x71, 0x6C, 0xFA, 0xBE, 0x4B, 0x40, 0xFD, 0xD5, 0x71, 0xE7, 0x13, 0xFC, 0x84, 0x37, 0x26, 0x68, 0xAC, 0x4B, 0x01, 0x1A, 0x4C, 0x42, 0xC4, 0xFB, 0x76, 0x88, 0x47, 0x9F, 0x7F, 0x9E, 0x27, 0x0F, 0x02, 0x34, 0xC5, 0xA8, 0x99, 0x22, 0x09, 0x58, 0x88, 0xFD, 0x63, 0x94, 0x21, 0xFA, 0xE9, 0x88, 0x7E, 0x53, 0x06, 0x84, 0x8A, 0xF5, 0xB1, 0xD5, 0xEB, 0x81, 0x48, 0xC3, 0x57, 0xEF, 0xAC, 0x2A, 0x81, 0x1D, 0xD3, 0xB3, 0x3D, 0x80, 0x68, 0xFF, 0x0D, 0xFA, 0x7B, 0x3E, 0x03, 0x1F, 0xBE, 0xAC, 0xD6, 0x5F, 0xE4, 0x04, 0xEA, 0x63, 0x29, 0x33, 0x24, 0x80, 0x3F, 0xB9, 0xAB, 0xEB, 0xE7, 0xCF, 0x16, 0xF6, 0x9A, 0xD1, 0x12, 0x11, 0x0C, 0xD4, 0x99, 0xCC, 0x91, 0x9D, 0x50, 0x28, 0x3C, 0x35, 0x27, 0x7A, 0x4C, 0x81, 0x30, 0x62, 0xCE, 0xDF, 0x51, 0x6D, 0x81, 0x3F, 0xA6, 0x91, 0xE2, 0x7A, 0x3C, 0x31, 0x1A, 0x00, 0x84, 0x97, 0xC0, 0x7E, 0x04, 0x34, 0x45, 0xDF, 0xCE, 0x0C, 0x06, 0x8C, 0xF4, 0x44, 0x2E, 0xAA, 0x07, 0xCC, 0x44, 0xFF, 0xBC, 0x74, 0x14, 0xB0, 0x1C, 0xFC, 0xEA, 0x46, 0x66, 0x07, 0xC0, 0xF0, 0xC9, 0xF9, 0x2B, 0x89, 0xCA, 0x80, 0xFF, 0x08, 0xA3, 0xDD, 0x8A, 0xF7, 0x3B, 0xFD, 0x39, 0xF4, 0x18, 0x68, 0x37, 0xF4, 0x62, 0x54, 0xDA, 0x7D, 0x40, 0x2B, 0xA4, 0xC6, 0x3E, 0x79, 0x13, 0xD0, 0xB9, 0xB1, 0x66, 0x45, 0xFC, 0x62, 0x40, 0xFE, 0xD9, 0x97, 0x13, 0x6B, 0x92, 0x00, 0xC5, 0xFA, 0xAF, 0x8D, 0xAB, 0x4B, 0x01, 0xE5, 0x83, 0x95, 0x77, 0xE2, 0x92, 0x80, 0x76, 0x46, 0xDF, 0x9C, 0x62, 0x63, 0x01, 0xB5, 0xE6, 0xAA, 0x63, 0x4B, 0x3D, 0xC5, 0xA8, 0xAB, 0xC3, 0xF5, 0x2F, 0xBD, 0x61, 0xAF, 0x4E, 0x01, 0xE4, 0x66, 0x8B, 0xE7, 0x64, 0x17, 0x24, 0x3B, 0xC9, 0x77, 0xFA, 0xF5, 0xFD, 0xD6, 0x6C, 0x00, 0x78, 0xA0, 0x75, 0x69, 0x17, 0x79, 0xFE, 0xDD, 0x95, 0x44, 0xF2, 0xA0, 0xE9, 0xAD, 0x3B, 0x80, 0xDD, 0x3D, 0x20, 0x51, 0x5F, 0xBD, 0x68, 0xEF, 0x69, 0xE0, 0x40, 0xC4, 0xFD, 0xE0, 0x4D, 0x0A, 0xC0, 0xBA, 0x7B, 0x4D, 0xFE, 0xAB, 0x06, 0x00, 0xF3, 0x1E, 0x35, 0x6A, 0x88, 0x13, 0x82, 0x89, 0x31, 0xF5, 0xEA, 0xE1, 0x1F, 0x81, 0x60, 0xAF, 0xBA, 0xAF, 0x53, 0x56, 0x03, 0x63, 0x95, 0xEB, 0x8E, 0x4F, 0xB9, 0x02, 0xF8, 0xCF, 0xAC, 0x8B, 0x9F, 0x52, 0x09, 0xF8, 0xB8, 0xD4, 0x2D, 0x9E, 0xB2, 0x5D, 0xD4, 0xFB, 0x09, 0x48, 0x88, 0x3C, 0x9A, 0xD7, 0x06, 0x90, 0x55, 0x13, 0x39, 0x68, 0x2C, 0xD0, 0x46, 0xA1, 0xB6, 0xE5, 0xF1, 0x7A, 0x00, 0x28, 0xB2, 0xBD, 0x3F, 0x8B, 0x3C, 0x75, 0xF1, 0xC1, 0x52, 0x32, 0xD9, 0xFC, 0x95, 0x11, 0xB9, 0x48, 0xFB, 0x7D, 0x7F, 0xC0, 0x66, 0x0A, 0x50, 0xD2, 0xD1, 0x7C, 0xF8, 0xAA, 0x05, 0xC0, 0xBB, 0xE8, 0xBB, 0x31, 0xD1, 0x76, 0x40, 0x4E, 0x69, 0xE3, 0x88, 0xE9, 0x11, 0x40, 0x66, 0x74, 0x9D, 0x6A, 0xD0, 0x37, 0x60, 0x4F, 0x2F, 0xD1, 0x3F, 0x97, 0x01, 0x09, 0xAE, 0xCD, 0x15, 0x6E, 0x5F, 0x80, 0x0D, 0xBB, 0x9A, 0xEA, 0x3D, 0x7C, 0x80, 0xB8, 0xAF, 0x4D, 0x0D, 0x5E, 0xF2, 0xC0, 0xB2, 0xD5, 0x4D, 0xD7, 0xBD, 0x45, 0x36, 0x79, 0x40, 0xF9, 0xE7, 0xBD, 0x98, 0x15, 0x13, 0x81, 0x36, 0x53, 0x6B, 0x8C, 0x5F, 0xED, 0x03, 0x80, 0x67, 0xEB, 0xDE, 0xA6, 0x93, 0xD9, 0x4F, 0xCB, 0x8B, 0xC9, 0x84, 0xBB, 0x5F, 0xAF, 0x92, 0xB3, 0x2F, 0xD1, 0xDD, 0x79, 0xFB, 0xCD, 0x56, 0x1A, 0xBF, 0x74, 0x80, 0x11, 0x9E, 0x40, 0xA3, 0xAE, 0x6B, 0xD7, 0x90, 0x8B, 0x40, 0xB3, 0xCA, 0x71, 0xCF, 0xB1, 0x46, 0x40, 0x55, 0x42, 0xF5, 0x44, 0x0F, 0x65, 0xE0, 0x59, 0xCD, 0xCF, 0x66, 0xE7, 0x93, 0x40, 0xCE, 0x04, 0x31, 0x6E, 0x3D, 0x06, 0x2E, 0x8A, 0x79, 0xB5, 0x57, 0x3D, 0x90, 0x25, 0x66, 0x72, 0xEB, 0x2C, 0xE0, 0xB8, 0xD0, 0x6E, 0x21, 0x70, 0x48, 0x64, 0x3F, 0x47, 0x71, 0xDD, 0xBF, 0x9B, 0x04, 0x28, 0x75, 0x6A, 0x90, 0xA3, 0x3B, 0x1D, 0x0C, 0x7F, 0x93, 0xF4, 0xC3, 0x57, 0x88, 0x2B, 0x0A, 0x94, 0xB7, 0x80, 0x1D, 0x2B, 0x1B, 0x2F, 0x91, 0x93, 0xAD, 0x9A, 0x57, 0x02, 0x8A, 0x6B, 0xFA, 0x74, 0x6C, 0x39, 0x02, 0x58, 0x0C, 0x01, 0x1A, 0x9D, 0x75, 0x7F, 0x3A, 0x66, 0x2B, 0x88, 0x91, 0x6C, 0x5A, 0x7F, 0x33, 0xDA, 0x55, 0x59, 0x98, 0xBC, 0xC0, 0x6C, 0x07, 0xE8, 0x39, 0xCB, 0x3E, 0xD3, 0x2A, 0xE1, 0xFB, 0xDF, 0x01, 0x06, 0x3F, 0x81, 0x4F, 0x09, 0x62, 0xA6, 0x74, 0x02, 0x5E, 0x89, 0xC4, 0xA2, 0x25, 0xA4, 0x1C, 0xD4, 0xCD, 0x99, 0x76, 0xBF, 0x89, 0xB5, 0xF7, 0x05, 0xC0, 0x4D, 0x5F, 0x31, 0xCE, 0x1D, 0x14, 0xA9, 0x69, 0x22, 0x20, 0xFF, 0xBD, 0xEC, 0x7A, 0xC3, 0x4D, 0x40, 0x76, 0xFA, 0xCD, 0x4F, 0x7F, 0xA7, 0x01, 0xC0, 0x2E, 0xF1, 0xC4, 0x98, 0x0C, 0x2D, 0x24, 0x3B, 0xF4, 0xB3, 0x13, 0xDF, 0x25, 0xE1, 0xDA, 0x71, 0x3B, 0x40, 0xEB, 0x21, 0x06, 0xBA, 0xE4, 0x80, 0x43, 0x8A, 0x2F, 0x24, 0xD7, 0x89, 0x99, 0x71, 0x05, 0x78, 0x04, 0x8A, 0x61, 0x4F, 0xD6, 0xB1, 0xCF, 0xC6, 0x00, 0x12, 0x62, 0xA6, 0x69, 0xB1, 0x05, 0x14, 0xEA, 0x39, 0x07, 0x01, 0x0D, 0x62, 0xEE, 0x52, 0xDC, 0x0F, 0x54, 0x4E, 0x16, 0xAF, 0xF4, 0x0C, 0xA0, 0x15, 0x18, 0x95, 0xA7, 0x9F, 0x68, 0x86, 0x82, 0x86, 0x41, 0x81, 0x98, 0xF7, 0xA5, 0x1D, 0x24, 0x27, 0xEF, 0xB3, 0xA2, 0xCF, 0x25, 0x2D, 0x27, 0xCF, 0x27, 0x95, 0xCD, 0xFB, 0xDC, 0x25, 0x55, 0xED, 0x41, 0xEB, 0x65, 0xEB, 0xDA, 0xED, 0x22, 0xAD, 0xAB, 0x01, 0xD2, 0xFD, 0x25, 0x1B, 0x11, 0xCB, 0xC6, 0x2D, 0x67, 0x53, 0x74, 0xD9, 0xF3, 0x05, 0x6C, 0x59, 0x38, 0xFB, 0x45, 0x4F, 0xB0, 0x5E, 0x24, 0xC0, 0x5D, 0x80, 0xA4, 0x02, 0xB7, 0x4B, 0x7A, 0x0B, 0x7B, 0x4F, 0xEC, 0x3B, 0x56, 0xF0, 0x55, 0xF0, 0x3D, 0xAC, 0x27, 0xF2, 0x60, 0x96, 0xE4, 0xC6, 0x59, 0xA1, 0xF4, 0x55, 0x85, 0xD5, 0xCE, 0x43, 0xC9, 0x36, 0x67, 0x24, 0xA2, 0x45, 0x0E, 0x31, 0x91, 0x95, 0x07, 0x3D, 0x97, 0x5A, 0x0D, 0x90, 0xB6, 0x1A, 0xAC, 0xDB, 0x37, 0x36, 0xE8, 0x29, 0x1B, 0xE3, 0xC4, 0xC6, 0x8F, 0x64, 0xD3, 0x3C, 0xD8, 0xC2, 0x99, 0xEC, 0xE3, 0x4E, 0x6C, 0xC9, 0x1F, 0xB6, 0x62, 0x86, 0x20, 0x40, 0xE4, 0xA0, 0x08, 0x20, 0x63, 0x91, 0x98, 0x09, 0x22, 0xDA, 0x44, 0x2C, 0xD2, 0xF9, 0x3F, 0x75, 0xBF, 0x0E, 0x51, 0x20, 0xA5, 0xDA, 0x00, 0xA4, 0x92, 0x3A, 0xD9, 0x6E, 0x2D, 0x40, 0x1A, 0x3E, 0x62, 0xED, 0x7C, 0xD9, 0x11, 0xCF, 0xD8, 0x60, 0xB0, 0x73, 0x14, 0xD9, 0x38, 0x1B, 0x36, 0xF1, 0x1B, 0x9B, 0x51, 0xC0, 0x5E, 0xF0, 0x63, 0x6F, 0x75, 0x62, 0x1F, 0xB6, 0x67, 0x5F, 0xCD, 0xA6, 0x8F, 0x53, 0xE4, 0x00, 0x32, 0x7C, 0x0A, 0xDB, 0x1F, 0x80, 0xCD, 0x12, 0x71, 0xF6, 0xBF, 0x03, 0x03, 0xBE, 0xD3, 0xF3, 0xAC, 0x7F, 0x72, 0x50, 0x54, 0x31, 0xA9, 0x14, 0xB1, 0xF1, 0x28, 0x57, 0x07, 0xFE, 0x5B, 0x60, 0x7D, 0xE5, 0x62, 0x23, 0x32, 0x53, 0x2B, 0x18, 0xE4, 0x93, 0xB0, 0x11, 0xA2, 0x77, 0xB4, 0x9F, 0x5B, 0x1D, 0xD9, 0x53, 0xE4, 0x01, 0xF9, 0xC7, 0x75, 0xCD, 0x26, 0x62, 0x95, 0x4F, 0x52, 0xAC, 0x50, 0xEA, 0xFD, 0xE1, 0x79, 0xB0, 0xB3, 0x78, 0x17, 0xA6, 0xCF, 0xE2, 0xEF, 0x9F, 0xB8, 0x9F, 0x75, 0x94, 0x04, 0xFA, 0x8A, 0x7C, 0x33, 0xB8, 0xBF, 0xF0, 0x95, 0xE8, 0xE3, 0x3B, 0x81, 0x71, 0x99, 0xDC, 0x8E, 0xF9, 0x6B, 0x49, 0xB9, 0x13, 0x6B, 0x6F, 0x53, 0xFB, 0x7A, 0x25, 0x52, 0x1E, 0x9B, 0x06, 0x80, 0xEB, 0x2F, 0x07, 0x7D, 0x0E, 0xA4, 0x8D, 0x98, 0xB3, 0x83, 0x3C, 0x1F, 0x38, 0x46, 0xAC, 0xD7, 0x74, 0xB4, 0x6E, 0xF2, 0xB1, 0xD5, 0x16, 0x7D, 0xD3, 0xF4, 0xCF, 0xB6, 0x1E, 0x22, 0xB7, 0x48, 0xED, 0x15, 0x67, 0x58, 0x9A, 0xEB, 0x6B, 0x9E, 0x66, 0xDB, 0x89, 0xB4, 0x3E, 0xE7, 0x23, 0xB8, 0xB7, 0x45, 0xB1, 0x51, 0x79, 0x80, 0x8C, 0x78, 0x41, 0x57, 0x0B, 0x60, 0x90, 0xB3, 0x58, 0x4F, 0x92, 0x02, 0x42, 0x0B, 0x44, 0x76, 0x02, 0x30, 0x91, 0xE6, 0x77, 0x48, 0xFA, 0xAD, 0x72, 0x27, 0x7B, 0x9E, 0x3D, 0x24, 0x49, 0xBA, 0x7D, 0x38, 0xAB, 0x49, 0x2E, 0x36, 0x59, 0x7F, 0x87, 0x4C, 0x59, 0xBB, 0x20, 0x9E, 0xCC, 0x9E, 0x43, 0xFB, 0xAC, 0xD5, 0x0E, 0xD5, 0x34, 0x99, 0x8B, 0xAF, 0x4B, 0x5C, 0x11, 0x3F, 0x7F, 0x6B, 0x5D, 0xB5, 0x74, 0xB6, 0xC3, 0x09, 0x56, 0x75, 0x97, 0xB8, 0xFB, 0xD8, 0x06, 0x3E, 0xBB, 0xD2, 0xEC, 0xB2, 0xB6, 0x80, 0x5C, 0xB1, 0x78, 0x3F, 0x86, 0x03, 0x43, 0xD6, 0x89, 0x0C, 0xB7, 0x1B, 0x98, 0x30, 0x5B, 0xFC, 0x0C, 0x19, 0xBC, 0x0F, 0x15, 0x00, 0x56, 0x16, 0x90, 0x0E, 0xCD, 0xAB, 0xFD, 0xC8, 0x99, 0x27, 0x56, 0x1E, 0x26, 0x97, 0x2E, 0x5F, 0x1D, 0x43, 0xEE, 0xCF, 0x5B, 0x64, 0x49, 0xDE, 0xDD, 0x1E, 0x22, 0xBE, 0x5F, 0xE1, 0x7B, 0x8B, 0x8D, 0xE9, 0xE0, 0xD6, 0xFA, 0x33, 0x59, 0xF5, 0x92, 0xDF, 0xB7, 0xC9, 0xAE, 0x6E, 0x1F, 0x35, 0x48, 0xDD, 0xF3, 0x22, 0x07, 0xF6, 0xE4, 0xFA, 0x8B, 0x22, 0xD9, 0xB8, 0x28, 0x40, 0xFE, 0xAA, 0xC8, 0x26, 0x00, 0x3C, 0x45, 0xDE, 0xF0, 0x3D, 0x2E, 0x14, 0xEB, 0x70, 0x5D, 0xF2, 0x81, 0xC8, 0x52, 0x6E, 0xC7, 0xBA, 0x0E, 0xA4, 0xED, 0xC7, 0xF5, 0x0F, 0xC8, 0xD9, 0x81, 0x6B, 0x07, 0x90, 0xDB, 0x33, 0x79, 0xFF, 0xD8, 0x95, 0x02, 0xFA, 0xBD, 0x35, 0x93, 0x3F, 0x0D, 0x35, 0x83, 0x8A, 0xB8, 0xAE, 0x4D, 0x58, 0xCD, 0x67, 0x52, 0xF7, 0x4C, 0xD9, 0x33, 0xD2, 0xF0, 0xD2, 0x8B, 0x62, 0xB2, 0x47, 0xD0, 0x83, 0x89, 0x7C, 0x27, 0x20, 0x72, 0xC6, 0x60, 0x70, 0x1E, 0x33, 0x67, 0xD7, 0xBE, 0x05, 0x94, 0x7F, 0x89, 0xF7, 0xC5, 0x03, 0x30, 0x17, 0xEB, 0x01, 0x7E, 0xE7, 0x01, 0x3F, 0x91, 0x03, 0xC2, 0xFC, 0x80, 0xB1, 0x03, 0xB9, 0x1D, 0x5B, 0xEB, 0xC8, 0x1E, 0xB6, 0x9C, 0x4F, 0x67, 0x9E, 0xDD, 0x78, 0x95, 0xCC, 0x18, 0xB6, 0x5A, 0x8E, 0xFC, 0x5D, 0xBE, 0x28, 0xEC, 0x6B, 0x25, 0x50, 0x97, 0x1B, 0x34, 0xF2, 0xD5, 0x23, 0x50, 0x0E, 0x3A, 0x78, 0xF7, 0x18, 0x69, 0xBD, 0x2B, 0xE7, 0x39, 0x69, 0x67, 0x70, 0x69, 0x12, 0xE9, 0xE4, 0x72, 0xDA, 0x89, 0xEC, 0xE7, 0x2B, 0xF2, 0x58, 0x3B, 0xF0, 0x55, 0x3F, 0x88, 0xDD, 0xFE, 0x1C, 0x90, 0xFB, 0x22, 0x72, 0xC6, 0x17, 0xC0, 0x5C, 0xB4, 0x73, 0x54, 0x3A, 0x10, 0x2C, 0x72, 0xD6, 0x78, 0x25, 0x20, 0x24, 0x5B, 0x5C, 0x5F, 0xB3, 0x54, 0x6B, 0x22, 0x82, 0xA9, 0x5E, 0xFB, 0xF7, 0x89, 0xE1, 0xE4, 0x12, 0xC5, 0xF5, 0x3D, 0x8A, 0x3F, 0x03, 0x8F, 0x52, 0x67, 0x9C, 0x39, 0x4B, 0xEB, 0x4E, 0xE3, 0x43, 0x6A, 0xB3, 0x16, 0x01, 0x7F, 0xB4, 0x22, 0xDC, 0x8E, 0x9F, 0x05, 0x1A, 0xF2, 0x46, 0xEF, 0x39, 0xB8, 0x01, 0x68, 0x91, 0x1D, 0xBE, 0x66, 0x8F, 0x2B, 0xD0, 0x6C, 0xE0, 0x1E, 0xBE, 0x3D, 0x04, 0x68, 0x7A, 0xEA, 0xB5, 0x66, 0x7D, 0xA5, 0xF0, 0xB0, 0x8F, 0xD4, 0x3F, 0xCF, 0x4D, 0x93, 0xDB, 0x82, 0xDD, 0x05, 0xC8, 0x95, 0x89, 0x7C, 0x76, 0x05, 0xD0, 0x17, 0xEF, 0xFB, 0xAE, 0x1B, 0x40, 0xCF, 0x78, 0xD1, 0xDE, 0xF3, 0xC0, 0x00, 0x3D, 0x91, 0x5F, 0x5D, 0x81, 0xD1, 0x45, 0x8F, 0x64, 0x7B, 0x15, 0x01, 0xB1, 0x1B, 0x0F, 0xD5, 0x00, 0x93, 0xB5, 0x56, 0x1C, 0xDC, 0x56, 0x0B, 0x3C, 0x5E, 0xBF, 0xA0, 0x65, 0x6E, 0x12, 0xF0, 0xD7, 0x79, 0xF1, 0xBE, 0xE0, 0x05, 0x40, 0x4B, 0xC2, 0x32, 0xC5, 0x30, 0x61, 0xFD, 0xC9, 0x39, 0xEA, 0xA1, 0xCD, 0xC0, 0x9F, 0x9A, 0x89, 0x56, 0x41, 0x36, 0xC2, 0x9D, 0x93, 0x4A, 0x47, 0x5F, 0x16, 0x86, 0x87, 0x5F, 0xF3, 0x78, 0x2A, 0x1C, 0x3A, 0xF9, 0xA4, 0x58, 0x8F, 0xBA, 0xCA, 0xF5, 0x8F, 0x2E, 0x67, 0x8F, 0x57, 0xB0, 0xC7, 0x7A, 0x02, 0x1A, 0xA2, 0xBF, 0x9E, 0x96, 0x05, 0x54, 0xA5, 0xAA, 0x77, 0x9F, 0x04, 0xA0, 0x38, 0xA1, 0xE0, 0xF5, 0x1E, 0x7A, 0x96, 0xB5, 0x38, 0x5D, 0x6D, 0x55, 0x77, 0xC0, 0xD5, 0x5E, 0x27, 0x46, 0x6E, 0x7E, 0xFB, 0xC5, 0xBB, 0xAF, 0x02, 0xCA, 0x69, 0x47, 0x5C, 0x92, 0x6A, 0x81, 0xAE, 0xD7, 0x6A, 0x4D, 0x77, 0xDC, 0x04, 0x74, 0xEA, 0x7F, 0x6F, 0x5F, 0xF3, 0x1B, 0xE8, 0xDA, 0xA9, 0x7A, 0xEC, 0x52, 0x5F, 0x40, 0x5D, 0xFF, 0xFB, 0xFB, 0x05, 0xD5, 0x80, 0x86, 0x62, 0xD5, 0xAC, 0xF9, 0x59, 0xC2, 0xDB, 0x55, 0x7F, 0xE6, 0x99, 0x03, 0x9A, 0xF7, 0x7F, 0x4C, 0xA0, 0xDF, 0x17, 0x38, 0x2B, 0x03, 0x9E, 0x0D, 0xFA, 0xB0, 0x17, 0xD5, 0xD9, 0x6B, 0x3A, 0xE4, 0xBB, 0x45, 0xE7, 0x66, 0x92, 0x97, 0xFA, 0xA6, 0xCF, 0x27, 0x53, 0xBB, 0x1F, 0x69, 0x24, 0x37, 0x7A, 0x65, 0x03, 0x30, 0x30, 0x01, 0x56, 0x44, 0xC9, 0x87, 0x6F, 0x18, 0x0A, 0x6C, 0x5F, 0x9E, 0x7D, 0x62, 0xF1, 0x43, 0x20, 0x2E, 0xB3, 0xFE, 0xE6, 0xC2, 0x5E, 0xC0, 0x3C, 0xF9, 0x96, 0x37, 0xB3, 0x5E, 0x02, 0x93, 0x36, 0x89, 0xFC, 0x39, 0x1F, 0x18, 0x97, 0xD2, 0xF0, 0x36, 0x60, 0x04, 0xE5, 0xA0, 0x86, 0x05, 0xB4, 0x7B, 0x2A, 0xC0, 0xBE, 0xC1, 0x63, 0x4C, 0x3F, 0xC0, 0x77, 0x61, 0xC3, 0xAC, 0x31, 0xE2, 0x59, 0xEF, 0xF5, 0x5B, 0x00, 0xC4, 0xEC, 0x9D, 0x53, 0x0B, 0xC8, 0x8C, 0x17, 0x77, 0xC3, 0x2A, 0xA0, 0xFA, 0x96, 0xF9, 0x87, 0xC8, 0xEB, 0x6E, 0x37, 0x8C, 0xC9, 0x94, 0x4E, 0xD7, 0x8F, 0x92, 0x6B, 0x2D, 0xF2, 0x8D, 0xC8, 0x19, 0x0A, 0x8F, 0x1E, 0x01, 0xDA, 0xB7, 0x81, 0xDB, 0x5F, 0xF4, 0x65, 0x66, 0x9B, 0x02, 0xF7, 0x90, 0x11, 0x1F, 0x76, 0x11, 0xB8, 0xF2, 0xB3, 0x26, 0x66, 0xFC, 0x04, 0xE0, 0xF8, 0xCC, 0xBF, 0x83, 0x47, 0x25, 0x03, 0x7B, 0xDD, 0x45, 0x3F, 0xBD, 0x07, 0x6C, 0x2A, 0x15, 0xFD, 0x72, 0x25, 0xB0, 0x56, 0xAC, 0xFD, 0x38, 0xEF, 0x07, 0x56, 0x06, 0xFF, 0x35, 0xEC, 0xDF, 0x03, 0x58, 0x26, 0xDF, 0x32, 0x69, 0xC0, 0x5F, 0x91, 0x83, 0x26, 0x03, 0x0A, 0x62, 0x5C, 0x79, 0x69, 0x05, 0x60, 0xEB, 0xFB, 0xC4, 0x27, 0x32, 0x80, 0x84, 0x4C, 0xE1, 0xBA, 0x17, 0x13, 0x00, 0xE0, 0xF0, 0x81, 0xE7, 0xAF, 0xC9, 0xB8, 0x11, 0xAF, 0x3F, 0x93, 0x53, 0x4D, 0xCB, 0x1E, 0x91, 0xFD, 0xC6, 0x7D, 0xCE, 0x07, 0x8C, 0xFC, 0x80, 0xEF, 0xBA, 0xF6, 0xBA, 0xB4, 0x16, 0x5F, 0x15, 0x92, 0xD4, 0x69, 0x70, 0x3B, 0xA0, 0x3C, 0xA7, 0xD4, 0xDB, 0xE9, 0x00, 0x50, 0xA4, 0xF9, 0xFB, 0x48, 0x9F, 0x26, 0x20, 0x47, 0xF4, 0xF1, 0x1E, 0x06, 0x40, 0xB6, 0xC8, 0xC2, 0x06, 0x51, 0xC0, 0x09, 0x91, 0xFD, 0x8D, 0x73, 0x81, 0x23, 0x4B, 0xC4, 0xD7, 0x3B, 0x01, 0x07, 0xC4, 0xDA, 0x3B, 0x5D, 0x0F, 0xE5, 0x91, 0x80, 0xB2, 0xF6, 0x8F, 0x1E, 0x9F, 0x4E, 0x00, 0x92, 0x2A, 0x0F, 0x3F, 0x7F, 0xB1, 0x04, 0x80, 0x13, 0xAF, 0x2B, 0xFB, 0x92, 0x6B, 0x96, 0xFD, 0x98, 0x4E, 0x86, 0xBC, 0xF8, 0xFD, 0x90, 0xEC, 0xEF, 0xD2, 0x30, 0x1E, 0x50, 0xB2, 0xA0, 0x55, 0x4F, 0xF9, 0x6B, 0x56, 0x2B, 0x81, 0xE6, 0x27, 0x01, 0x03, 0x4D, 0x0C, 0x80, 0xC6, 0x15, 0xDB, 0x2F, 0x18, 0x50, 0x1E, 0x32, 0xBE, 0xBB, 0x4E, 0xAF, 0x12, 0x68, 0x5C, 0x5B, 0x1F, 0xA1, 0xE5, 0x03, 0x54, 0xFC, 0x16, 0xE3, 0xD7, 0x64, 0xE0, 0xA9, 0x9B, 0x18, 0x3F, 0x8D, 0x80, 0xFB, 0x33, 0xC4, 0x38, 0x26, 0x01, 0xDC, 0x12, 0x33, 0x7E, 0xC7, 0x91, 0xC0, 0x8D, 0x65, 0x62, 0x7E, 0xD9, 0xDB, 0x62, 0xD3, 0xF4, 0x18, 0x50, 0xFC, 0xF0, 0xE2, 0xCA, 0xEF, 0xA7, 0x80, 0xEC, 0xBA, 0x73, 0x43, 0xEA, 0xDE, 0x00, 0xC0, 0x86, 0x21, 0x8D, 0x8A, 0x64, 0xB0, 0xC2, 0xDF, 0xA1, 0x82, 0x06, 0xBB, 0x3D, 0x74, 0x85, 0x4A, 0x25, 0x03, 0xC2, 0x05, 0x5A, 0x15, 0x2A, 0xD7, 0xC5, 0xBB, 0xBB, 0x0A, 0x90, 0x16, 0xF9, 0x24, 0xC4, 0x1F, 0x52, 0xA0, 0x27, 0x05, 0x5D, 0x60, 0x4B, 0x66, 0x37, 0x01, 0xE4, 0xEB, 0x78, 0x40, 0x5A, 0xCC, 0xE7, 0x8D, 0xCE, 0xFC, 0xB9, 0x98, 0xDB, 0xC2, 0x80, 0x3A, 0x71, 0xEE, 0x65, 0xF6, 0x01, 0x5F, 0xE7, 0x89, 0x44, 0xF1, 0x9D, 0x73, 0x90, 0x82, 0x5F, 0x99, 0x18, 0xA1, 0xE4, 0x86, 0xCB, 0x0D, 0xBF, 0x9A, 0xF0, 0x77, 0x1B, 0x20, 0x7D, 0x68, 0xDB, 0xC8, 0x96, 0x28, 0x00, 0x98, 0x70, 0x9B, 0xEA, 0x22, 0xB9, 0x77, 0x5F, 0x12, 0x37, 0x25, 0xC5, 0x59, 0x96, 0xAE, 0x96, 0x2B, 0x03, 0x8D, 0x82, 0xA7, 0x01, 0x72, 0x88, 0x2D, 0x3B, 0x6E, 0x20, 0x1B, 0x6B, 0xCF, 0xA6, 0x66, 0xB0, 0xB9, 0x7D, 0xD8, 0x37, 0x5F, 0x04, 0xCF, 0x45, 0xFE, 0xF9, 0x0C, 0x48, 0x88, 0x76, 0xB7, 0x7C, 0x14, 0xDA, 0x71, 0xFE, 0xC1, 0x62, 0x36, 0x57, 0x53, 0xB4, 0xCA, 0x41, 0xD6, 0x81, 0x7E, 0x83, 0x02, 0x80, 0xC1, 0xC4, 0xC3, 0xA4, 0x64, 0xB4, 0x75, 0x17, 0x92, 0x5F, 0x47, 0x22, 0x43, 0xD2, 0x8D, 0x54, 0xB1, 0x00, 0x48, 0xB3, 0x8B, 0xEC, 0xE0, 0x31, 0xEC, 0x84, 0x9E, 0xEC, 0xC2, 0xAB, 0x6C, 0xFC, 0x23, 0xF6, 0xB8, 0x0C, 0x9B, 0x6F, 0xCE, 0x96, 0x54, 0xB1, 0xEF, 0xBF, 0xB2, 0x95, 0x97, 0x04, 0xE2, 0x4E, 0xBE, 0xF6, 0x15, 0x90, 0x62, 0x2B, 0xEA, 0xD8, 0x49, 0x47, 0xCF, 0x70, 0xA6, 0xBA, 0x92, 0x9D, 0x1D, 0xE2, 0x48, 0x40, 0x7A, 0xA6, 0xF0, 0x14, 0x4E, 0x01, 0xA2, 0x9D, 0xAD, 0xF5, 0x3A, 0xEE, 0x64, 0x2D, 0xD6, 0xB2, 0xAE, 0xD2, 0xAC, 0xFF, 0x4D, 0x76, 0x46, 0x06, 0x1B, 0x77, 0x99, 0x4D, 0x3A, 0xCE, 0x9E, 0x18, 0xCA, 0xE6, 0xD6, 0xB3, 0xF7, 0xFB, 0xB2, 0xCF, 0x0E, 0xB1, 0x6F, 0xD2, 0xE9, 0x63, 0xE0, 0xFA, 0x7F, 0xCF, 0x31, 0xFD, 0x01, 0xF4, 0xF6, 0xE6, 0xFC, 0xE3, 0xB6, 0x8C, 0x0D, 0xDC, 0xD1, 0x9A, 0x3F, 0x4A, 0x48, 0xE9, 0x1B, 0x5B, 0x0C, 0xFE, 0x57, 0x0E, 0x9A, 0x3F, 0x7B, 0xFE, 0x6C, 0xF2, 0x48, 0x97, 0xA0, 0x46, 0x32, 0xF7, 0xC4, 0xC8, 0x5A, 0x91, 0x6E, 0x2D, 0xBF, 0x7F, 0x30, 0xB3, 0x14, 0xE9, 0xAF, 0xE1, 0x77, 0x81, 0x61, 0x83, 0xE8, 0x2B, 0x1D, 0x5A, 0x22, 0xF4, 0x3A, 0xF0, 0x3C, 0xA8, 0x25, 0x32, 0xBD, 0xFF, 0x35, 0xFE, 0xFE, 0x90, 0x09, 0xAC, 0xC3, 0x29, 0xC0, 0x46, 0xCC, 0x9B, 0x76, 0x45, 0x40, 0xDF, 0x72, 0xD1, 0x0E, 0x77, 0x60, 0xF4, 0x6A, 0x71, 0xAD, 0xC5, 0x03, 0x41, 0x59, 0xF4, 0x7D, 0x12, 0x59, 0xEB, 0x65, 0xFF, 0x57, 0x3B, 0xA6, 0xCE, 0x9D, 0x9F, 0x49, 0x66, 0x45, 0xFB, 0x89, 0xDE, 0xDC, 0xA1, 0x4B, 0x5D, 0x7B, 0xDB, 0x73, 0xB4, 0x6F, 0xBB, 0x7E, 0x8A, 0xC1, 0x30, 0xAE, 0xDB, 0x6D, 0x0E, 0xAB, 0xD9, 0x91, 0x55, 0x14, 0xBD, 0x30, 0xA8, 0x35, 0xFD, 0x8E, 0xF9, 0xCD, 0xDA, 0xCA, 0x03, 0xB6, 0x62, 0xFD, 0xC8, 0x3E, 0x0D, 0x70, 0x52, 0x16, 0x6D, 0x0D, 0x04, 0x7C, 0x2D, 0x38, 0x07, 0x05, 0x6E, 0x6B, 0x5D, 0x9F, 0xFA, 0x49, 0x76, 0x5B, 0x75, 0xA6, 0x88, 0xEC, 0x8F, 0x83, 0x39, 0x64, 0x74, 0xE4, 0xDE, 0xDB, 0xE4, 0x21, 0x99, 0x99, 0x7A, 0xE4, 0xA9, 0x9E, 0xFE, 0x6A, 0xA2, 0x1D, 0xD1, 0x55, 0x43, 0x7B, 0xB8, 0x70, 0xBD, 0xAE, 0x16, 0x6C, 0x5B, 0x43, 0xF2, 0xDF, 0x8F, 0x88, 0xB9, 0x00, 0x19, 0x2E, 0xC9, 0x46, 0x9E, 0x63, 0xFB, 0xED, 0x01, 0x9C, 0xC4, 0xFC, 0xA6, 0xB3, 0x06, 0xF0, 0x1F, 0x24, 0xC6, 0x20, 0x17, 0x60, 0xDC, 0x23, 0x6E, 0xC7, 0xF2, 0x05, 0x64, 0x9F, 0xD2, 0x98, 0xA7, 0xA4, 0xF7, 0x9D, 0xA5, 0x69, 0xE4, 0xD2, 0x83, 0x4B, 0xEE, 0x90, 0x7B, 0x1F, 0xCD, 0x89, 0x21, 0x9F, 0xBE, 0xF2, 0x53, 0x16, 0xBD, 0xAB, 0xA2, 0x31, 0xD4, 0xB8, 0xF2, 0x3F, 0xEB, 0xFE, 0xF9, 0xC1, 0x7E, 0x1D, 0x45, 0x4A, 0x1D, 0x13, 0x75, 0xCB, 0xB9, 0xEE, 0xEC, 0xD5, 0xEC, 0x62, 0x33, 0xD6, 0xFE, 0x3E, 0x30, 0x54, 0x9C, 0x4F, 0xB7, 0x0C, 0x60, 0xB0, 0xD8, 0x87, 0x6A, 0x95, 0x00, 0x04, 0xA5, 0xB4, 0xBE, 0x1F, 0x5D, 0x49, 0xAB, 0xEA, 0x98, 0x75, 0xE4, 0xF8, 0xA5, 0xCB, 0xD6, 0x92, 0x5B, 0x73, 0x62, 0x8C, 0xC8, 0x2B, 0x63, 0x67, 0x7E, 0x17, 0xF9, 0xED, 0x6B, 0x93, 0xAA, 0xA3, 0x1D, 0xD7, 0xB5, 0x48, 0xFD, 0xBA, 0x9D, 0x04, 0xDE, 0xDC, 0x21, 0x15, 0x16, 0x3F, 0xDB, 0x4B, 0xAA, 0xE6, 0xDF, 0xBB, 0x4D, 0x6A, 0x8A, 0xFE, 0x11, 0xD3, 0x8F, 0xEB, 0x2E, 0xB9, 0xC0, 0xC6, 0xF8, 0x82, 0x5D, 0x07, 0xA8, 0x88, 0xF7, 0x7D, 0xB8, 0x37, 0xE0, 0xFE, 0x4C, 0xAC, 0x93, 0xE5, 0x00, 0xFE, 0x9F, 0xB8, 0x1D, 0xAB, 0x15, 0xC9, 0x1E, 0xCF, 0x62, 0xB3, 0xC8, 0x30, 0xBF, 0x65, 0xD5, 0x64, 0x46, 0x61, 0xF4, 0x64, 0xF2, 0xD7, 0xF0, 0x70, 0x8D, 0x52, 0xDA, 0x11, 0x51, 0xE6, 0xF1, 0xE8, 0x61, 0x0E, 0x28, 0x7B, 0xBF, 0xB8, 0xF9, 0x85, 0xEC, 0xFA, 0xFE, 0x8A, 0x35, 0x69, 0x90, 0x71, 0xCE, 0x8B, 0xEC, 0xA1, 0x77, 0xF2, 0x03, 0x69, 0x29, 0x9E, 0x8F, 0x6E, 0x8C, 0xE0, 0xBA, 0x1B, 0x66, 0x83, 0xAD, 0x67, 0xD7, 0x9C, 0x00, 0xD4, 0xC5, 0xBA, 0xE3, 0x3C, 0x1F, 0xC0, 0x4E, 0xBC, 0xDF, 0x3E, 0xCA, 0xC0, 0xD8, 0x19, 0xA2, 0x1F, 0xED, 0x97, 0x69, 0x3F, 0x81, 0x72, 0x32, 0x54, 0x9A, 0xD7, 0xBC, 0xA9, 0x6C, 0x04, 0xE6, 0x6C, 0x99, 0x9B, 0x7A, 0xEF, 0x09, 0x70, 0x43, 0x7E, 0xCC, 0xC7, 0x23, 0x86, 0x40, 0xFD, 0x03, 0x97, 0xB9, 0x69, 0xAE, 0x40, 0xE3, 0x6D, 0xFF, 0x03, 0xA9, 0xC5, 0x40, 0xFD, 0x73, 0x2F, 0x8B, 0xA4, 0x7C, 0xD0, 0x7B, 0x9C, 0x9D, 0xB0, 0x8D, 0x74, 0x6E, 0xD8, 0x54, 0x4B, 0x0E, 0x3C, 0xB9, 0x66, 0x28, 0x39, 0x58, 0x8C, 0xF9, 0xBB, 0xCF, 0x00, 0x80, 0xF0, 0x1C, 0xD8, 0xB5, 0x6C, 0xE2, 0x05, 0x40, 0x31, 0x57, 0xAC, 0x97, 0x0D, 0x01, 0x44, 0xB7, 0x15, 0xBF, 0x1C, 0xCA, 0x39, 0x31, 0xEE, 0x19, 0x60, 0xDF, 0xF6, 0xDA, 0x1F, 0x83, 0x17, 0xC0, 0xAC, 0x84, 0xC4, 0x50, 0x20, 0xE0, 0xDA, 0xEC, 0xA8, 0xD5, 0x5A, 0xC0, 0xF5, 0xE0, 0x49, 0xCB, 0x66, 0xEE, 0x07, 0xEA, 0x25, 0x22, 0x22, 0x47, 0x7F, 0x03, 0x8D, 0x28, 0xB1, 0x3E, 0x9B, 0x81, 0x86, 0x8D, 0x53, 0xCF, 0x05, 0xE6, 0x02, 0x8D, 0xA7, 0xFD, 0x23, 0x7D, 0x36, 0x09, 0x35, 0xC7, 0x74, 0xF1, 0x78, 0x03, 0x34, 0xAC, 0x19, 0x6B, 0x36, 0x74, 0x3C, 0x50, 0x5F, 0x1E, 0x24, 0x46, 0xD1, 0x43, 0xC5, 0x00, 0x20, 0xAC, 0x66, 0x0F, 0xBF, 0x63, 0xD3, 0x8A, 0x01, 0x89, 0x35, 0x22, 0x1F, 0x69, 0x03, 0xC0, 0x0B, 0x87, 0xDD, 0xF7, 0xC9, 0xD3, 0xEE, 0xB1, 0xCB, 0x00, 0x29, 0xCB, 0xF8, 0x51, 0x33, 0x85, 0x36, 0x47, 0x95, 0x73, 0x01, 0xA9, 0x21, 0x5B, 0x3A, 0xD0, 0x4E, 0x86, 0xED, 0x47, 0x37, 0xC5, 0x01, 0x3A, 0x7A, 0x9F, 0x26, 0xAE, 0x3D, 0x0A, 0xE8, 0x8E, 0x6C, 0x38, 0xB1, 0xE4, 0x37, 0xD0, 0xFD, 0xC7, 0xEF, 0x9F, 0x33, 0x25, 0x00, 0x6D, 0xE9, 0xDA, 0x92, 0x49, 0x51, 0xC2, 0xD0, 0xDA, 0xDF, 0xE1, 0x36, 0xC2, 0x17, 0x3F, 0xB5, 0x26, 0xA5, 0x03, 0x3A, 0xFD, 0x7E, 0xA5, 0x85, 0x89, 0xF5, 0xCE, 0xAC, 0x43, 0x5C, 0x37, 0xFB, 0x09, 0x7B, 0x76, 0x32, 0xF9, 0xF3, 0x74, 0x96, 0x1C, 0x79, 0xFF, 0xE5, 0x61, 0x57, 0x32, 0x3D, 0x8F, 0x32, 0x16, 0xB0, 0xA1, 0x68, 0x7B, 0x0F, 0x72, 0x41, 0xED, 0xBE, 0x54, 0x40, 0x7D, 0x22, 0x30, 0x5D, 0x4A, 0xD6, 0x69, 0x41, 0x37, 0x60, 0x65, 0xFD, 0xBE, 0xCD, 0x53, 0xBA, 0x03, 0xCB, 0xB4, 0xBE, 0xD5, 0x84, 0xE7, 0x02, 0x73, 0xC4, 0x7C, 0x1F, 0x6A, 0x06, 0x84, 0xE8, 0x35, 0x5C, 0xF4, 0x79, 0x01, 0x04, 0x34, 0x35, 0x1F, 0x77, 0x4D, 0x01, 0xFC, 0xA7, 0x35, 0x1B, 0x0E, 0xED, 0x0F, 0xF8, 0xAD, 0x69, 0xDA, 0x39, 0xEC, 0x38, 0xE0, 0xE3, 0xD8, 0xB4, 0x6D, 0x78, 0xA5, 0xC8, 0x41, 0xAD, 0xFD, 0xF4, 0x66, 0x32, 0x20, 0xA1, 0xDA, 0x10, 0x79, 0x6B, 0x15, 0x00, 0x3C, 0x34, 0xBF, 0x38, 0x8A, 0x3C, 0x69, 0x97, 0x3D, 0x87, 0xDC, 0x72, 0xF2, 0xB4, 0x33, 0x19, 0x39, 0xEE, 0x8C, 0x29, 0x39, 0x61, 0xD6, 0xF5, 0x3C, 0x40, 0xEA, 0x02, 0x90, 0x5D, 0xA7, 0xB1, 0xD2, 0x5F, 0x06, 0xB8, 0x70, 0x72, 0xAB, 0xC2, 0xC8, 0x10, 0xE0, 0xAC, 0xFF, 0x5B, 0xE3, 0xE1, 0x33, 0x81, 0x74, 0x43, 0x71, 0xDE, 0x13, 0x80, 0xC4, 0x42, 0x31, 0x36, 0xEA, 0x00, 0x71, 0xE2, 0xDA, 0x32, 0xFD, 0x03, 0xAC, 0x10, 0x33, 0x9E, 0xF9, 0x66, 0x60, 0xE9, 0x11, 0xD1, 0x3F, 0xF7, 0x00, 0x8B, 0x44, 0x7B, 0xAD, 0xC4, 0x6C, 0x5B, 0xB4, 0x12, 0x50, 0x10, 0xFD, 0xA4, 0x64, 0x2C, 0x00, 0x14, 0xDB, 0x17, 0x0D, 0x03, 0xA4, 0xC6, 0x5E, 0x5E, 0x51, 0x74, 0x01, 0x00, 0x76, 0x8F, 0x2D, 0xF2, 0x24, 0xE7, 0x65, 0x3C, 0xDA, 0x4E, 0x06, 0x94, 0x3E, 0x56, 0x23, 0x9D, 0x1F, 0xBE, 0xDA, 0x05, 0xC8, 0xBB, 0x03, 0x2F, 0x2B, 0x7B, 0xEE, 0xB0, 0x3E, 0x07, 0x14, 0x3F, 0x5B, 0xAB, 0x67, 0x71, 0x09, 0x78, 0xD1, 0xFD, 0x89, 0xBB, 0xC9, 0x75, 0xA0, 0x70, 0xDF, 0x4F, 0x4B, 0xA3, 0xE7, 0xC0, 0xE5, 0xB6, 0xE2, 0x79, 0x54, 0x33, 0x70, 0xAC, 0x9B, 0x98, 0xA1, 0xF2, 0x81, 0x34, 0x4F, 0x91, 0x37, 0x7E, 0x00, 0x07, 0x06, 0x8B, 0xEB, 0x47, 0x1F, 0xD8, 0x27, 0x32, 0xA1, 0x8E, 0xB8, 0x0E, 0x3E, 0x4E, 0x04, 0x94, 0x2C, 0xBF, 0x5C, 0xAE, 0x58, 0x05, 0xC8, 0x5C, 0xC8, 0x9B, 0x58, 0xFA, 0x18, 0x00, 0x92, 0xA7, 0x94, 0xB6, 0x27, 0x17, 0x4E, 0xAA, 0x50, 0x25, 0x7D, 0x24, 0x3F, 0x6D, 0x22, 0xED, 0x23, 0xBE, 0xCF, 0x27, 0x69, 0x1F, 0x0B, 0x60, 0x10, 0x08, 0xFC, 0x5A, 0x37, 0x5C, 0x49, 0xB3, 0x11, 0xF8, 0x3D, 0x62, 0x8D, 0xAF, 0x7A, 0x0C, 0xD0, 0xB0, 0xE2, 0xE6, 0x1B, 0x15, 0x79, 0xE0, 0x57, 0x4A, 0x83, 0x8D, 0xF2, 0x10, 0xA0, 0x64, 0x52, 0x73, 0x37, 0xA5, 0x1C, 0xE0, 0x9E, 0xAD, 0x48, 0x18, 0xD7, 0x80, 0x5B, 0x5A, 0x62, 0xFC, 0xA8, 0x06, 0xAE, 0x8B, 0x5C, 0xA6, 0xF8, 0x1B, 0xB8, 0x2C, 0xD6, 0x4E, 0xDB, 0x0D, 0xFD, 0x33, 0xBC, 0x71, 0x0C, 0xA0, 0xFC, 0xEA, 0xFE, 0xD9, 0x9A, 0x28, 0x40, 0x66, 0xD1, 0x91, 0x4F, 0xD5, 0x1F, 0x01, 0x60, 0xE9, 0xC8, 0x5A, 0x65, 0x72, 0x54, 0xC6, 0xAF, 0x8F, 0xA4, 0xC5, 0xA9, 0xC6, 0x33, 0xA4, 0xEC, 0xF8, 0xBF, 0xA1, 0x40, 0xFB, 0x71, 0xC0, 0xDF, 0x39, 0x86, 0x43, 0x65, 0x6C, 0x85, 0xF5, 0x3E, 0x59, 0x92, 0xB9, 0xC2, 0x36, 0x6B, 0x2C, 0x51, 0x05, 0xEA, 0x61, 0x67, 0xE1, 0x28, 0x34, 0x2C, 0x6D, 0x5D, 0x09, 0x6D, 0x6A, 0x27, 0x99, 0x2D, 0x9C, 0x22, 0x66, 0xF6, 0x3B, 0x40, 0xCD, 0x57, 0x31, 0xC7, 0x7D, 0x07, 0x3E, 0x88, 0xBE, 0x29, 0xF5, 0x10, 0x28, 0x11, 0x73, 0x8E, 0xCC, 0xC8, 0x57, 0x94, 0x8E, 0xE6, 0x2B, 0x98, 0x9C, 0x56, 0xAA, 0x8B, 0x07, 0xA0, 0x1A, 0x7B, 0xBC, 0x3E, 0x57, 0x08, 0xDF, 0x41, 0x4D, 0xFE, 0xA4, 0xD1, 0xC6, 0xA6, 0x72, 0x52, 0x42, 0xBB, 0x39, 0x03, 0x90, 0x88, 0x00, 0x8D, 0x7E, 0x4E, 0x00, 0xE9, 0x60, 0xC7, 0x86, 0x84, 0xB1, 0xCB, 0x97, 0xB3, 0xA9, 0x73, 0xD9, 0x5B, 0xBE, 0xEC, 0x7B, 0x65, 0x40, 0xD2, 0x97, 0xF3, 0x8E, 0xC4, 0x48, 0x16, 0x1A, 0x2C, 0xC0, 0x5E, 0x2C, 0x10, 0xAD, 0x9A, 0x2D, 0x35, 0x7B, 0xC3, 0xDB, 0x96, 0xA3, 0x00, 0x10, 0xC8, 0xF9, 0x03, 0xC6, 0x07, 0x58, 0x80, 0x25, 0xE5, 0xD7, 0xB1, 0xDA, 0x09, 0xAC, 0xA3, 0x04, 0xEB, 0x3F, 0x99, 0x9D, 0x77, 0x8F, 0xDD, 0xD6, 0x6A, 0x46, 0x1A, 0x7B, 0x57, 0x8E, 0xFD, 0x50, 0x27, 0x10, 0x4F, 0xC8, 0xBF, 0x3D, 0x02, 0x24, 0xC4, 0x7A, 0xCF, 0xCF, 0x81, 0x42, 0x31, 0x92, 0x36, 0xA8, 0x00, 0xDB, 0xBD, 0xA9, 0x0E, 0x16, 0x4E, 0x30, 0x26, 0x01, 0x0B, 0x7B, 0x16, 0xF8, 0x6F, 0xDB, 0x9D, 0x66, 0x8D, 0x8E, 0xB2, 0x4E, 0x57, 0x59, 0x5F, 0x2D, 0x76, 0x9A, 0x3E, 0x1B, 0x17, 0xC9, 0xEE, 0xFF, 0xCB, 0x9E, 0x7A, 0xC1, 0xDE, 0x95, 0x60, 0x9F, 0xB7, 0x61, 0xDF, 0xD8, 0xB1, 0xE5, 0xF5, 0xF4, 0xD1, 0x6F, 0xDC, 0x3F, 0xF9, 0x47, 0x4F, 0xCC, 0x9B, 0x7D, 0x6C, 0x81, 0x3E, 0xB6, 0x9C, 0x7F, 0x06, 0xF7, 0x64, 0xBD, 0x0F, 0xB3, 0x21, 0xFA, 0xD4, 0x2A, 0xC9, 0xEE, 0xEB, 0x9C, 0xFE, 0x57, 0xFE, 0x98, 0x95, 0x3F, 0x2B, 0x9F, 0x3C, 0xD8, 0x30, 0xDA, 0x8D, 0xBC, 0x1C, 0x33, 0xE4, 0xA6, 0xE8, 0xA3, 0x19, 0x95, 0xFE, 0xC6, 0x19, 0xA2, 0x8F, 0xE4, 0xFD, 0x79, 0xD5, 0x2D, 0x8F, 0xBE, 0xDE, 0x3C, 0xB8, 0xEB, 0x10, 0x21, 0x25, 0xBD, 0x6C, 0x31, 0x6F, 0x5C, 0x03, 0xBF, 0x4E, 0x37, 0x76, 0xC0, 0x63, 0xC0, 0xC4, 0x41, 0xAC, 0x0D, 0x74, 0x01, 0xFA, 0x0B, 0x75, 0xE3, 0x01, 0xF7, 0x4A, 0xCE, 0x41, 0x63, 0x87, 0xB7, 0xAE, 0x7F, 0xB4, 0xFC, 0xAF, 0x76, 0x84, 0x75, 0x9F, 0xB3, 0x91, 0xCC, 0x0C, 0xF7, 0x68, 0x20, 0x9F, 0x78, 0x3A, 0xDE, 0x16, 0x66, 0xD4, 0x19, 0xE9, 0x45, 0x73, 0xDD, 0xCE, 0x8D, 0x6C, 0x3B, 0x2B, 0x56, 0x46, 0x3C, 0x5F, 0xF1, 0x6E, 0x4D, 0xAF, 0x01, 0xE7, 0x58, 0xC7, 0xAB, 0x80, 0xC9, 0x3D, 0x31, 0xD6, 0x2C, 0x01, 0x1C, 0x6C, 0x44, 0x6F, 0x38, 0x0D, 0x0C, 0x4F, 0x14, 0x29, 0x59, 0x15, 0x18, 0x9F, 0xC4, 0xED, 0x58, 0x21, 0x4D, 0x6A, 0x19, 0x9F, 0x1E, 0x4C, 0x8E, 0x74, 0x99, 0xF9, 0x9D, 0x8C, 0xBC, 0xBE, 0x63, 0x26, 0x99, 0xB6, 0x69, 0xA2, 0x36, 0x99, 0x31, 0xC4, 0x6B, 0x9C, 0xC8, 0x83, 0xDF, 0xBF, 0xC6, 0x19, 0xCF, 0xE4, 0x7A, 0x6A, 0x4D, 0xEC, 0x3F, 0x47, 0x73, 0x10, 0x49, 0x87, 0xFF, 0x7A, 0x80, 0x0C, 0x1C, 0xCD, 0x86, 0xCB, 0xB1, 0x83, 0x9C, 0x00, 0xB3, 0x43, 0x62, 0xAC, 0x9B, 0x06, 0xF4, 0x13, 0xF9, 0x47, 0xDF, 0x04, 0x08, 0x78, 0xDB, 0x9A, 0x53, 0xDB, 0x93, 0x12, 0xB5, 0x31, 0x52, 0xE4, 0xD0, 0x25, 0xD1, 0x17, 0xC9, 0x48, 0xBD, 0xF9, 0xDD, 0xC9, 0x0C, 0xD9, 0xF1, 0x9E, 0xE4, 0xD3, 0xB5, 0xC3, 0xCE, 0x8A, 0x6B, 0x34, 0xA1, 0xFE, 0x4A, 0xF7, 0xD7, 0x5C, 0x0B, 0xA8, 0x3E, 0xC8, 0xBE, 0x77, 0x67, 0x4B, 0xB2, 0x48, 0x3A, 0x26, 0x95, 0x03, 0xE4, 0xC4, 0xFE, 0xEC, 0x94, 0xA9, 0xAC, 0x23, 0xE5, 0xC3, 0x67, 0xA2, 0xDF, 0x78, 0x01, 0xCE, 0x61, 0x22, 0x1F, 0x5A, 0x03, 0xE3, 0x9E, 0x72, 0x3B, 0x16, 0xDC, 0x20, 0xA5, 0x8E, 0xC6, 0x4A, 0x91, 0xA1, 0x27, 0x66, 0xC5, 0x90, 0x7B, 0xFD, 0x66, 0x25, 0x90, 0x37, 0x52, 0x42, 0x45, 0xBB, 0xBB, 0xC8, 0xD6, 0x07, 0xF6, 0x7A, 0xDC, 0x2C, 0x49, 0xAF, 0xA5, 0x67, 0x5B, 0xAE, 0x47, 0x02, 0x8F, 0x4D, 0xD8, 0x07, 0x9A, 0x6C, 0x81, 0x35, 0x29, 0x23, 0x5E, 0x27, 0x32, 0x05, 0x9C, 0xC7, 0x26, 0x83, 0xBD, 0xC7, 0x46, 0x4A, 0x01, 0xB2, 0x8E, 0xE2, 0xAA, 0x30, 0x00, 0x86, 0x88, 0x7E, 0xE1, 0xB9, 0x57, 0x38, 0x51, 0xBC, 0x2F, 0xD7, 0x80, 0x70, 0x91, 0xCF, 0x00, 0x35, 0xFB, 0x45, 0xA1, 0xE4, 0x54, 0xEF, 0x29, 0x24, 0x4E, 0x7A, 0x85, 0xBC, 0xFC, 0xDE, 0x0C, 0x54, 0x84, 0x0E, 0xB5, 0x79, 0x42, 0xEB, 0x20, 0x9B, 0x1C, 0x2D, 0x6E, 0xBD, 0x02, 0x5A, 0x1A, 0xCD, 0x4C, 0x2E, 0x3D, 0x05, 0x44, 0xDB, 0x5A, 0xB2, 0x2D, 0xC9, 0x4E, 0x7A, 0x27, 0x46, 0x92, 0x5A, 0xE7, 0xD3, 0x8B, 0xC8, 0x6E, 0x1A, 0xE2, 0x2A, 0x8B, 0xE6, 0xBA, 0xB1, 0xAD, 0xC6, 0xC8, 0xB3, 0x2B, 0xF6, 0xB2, 0xCB, 0xF6, 0x03, 0x6A, 0xE2, 0x39, 0x9E, 0x6B, 0x3C, 0xE0, 0x95, 0x2F, 0xB2, 0x8C, 0x2A, 0x10, 0x2C, 0xCE, 0x8B, 0xC9, 0x65, 0xCB, 0xF1, 0xE3, 0x0A, 0x9E, 0x9D, 0x02, 0xC2, 0x7D, 0xFC, 0xA7, 0xDE, 0xA8, 0x01, 0xCE, 0x0E, 0x1F, 0x68, 0x7B, 0xA0, 0x17, 0xF0, 0xC3, 0xCF, 0xFC, 0xD4, 0xF6, 0x1B, 0x40, 0x8B, 0x91, 0xC3, 0xA8, 0xC4, 0x5A, 0xA0, 0x61, 0xC0, 0xE0, 0xBE, 0x9B, 0xEF, 0x82, 0xD6, 0xA3, 0xA4, 0xD6, 0xE6, 0x92, 0x7D, 0x56, 0xAC, 0xDC, 0x4B, 0xDA, 0xAC, 0x59, 0x9A, 0x45, 0xDA, 0x8B, 0x7E, 0x9B, 0x10, 0x0B, 0x1E, 0x7D, 0xEC, 0xD8, 0x2D, 0xC7, 0xD9, 0x4D, 0x15, 0xEC, 0x7A, 0x0D, 0x40, 0xC1, 0x4E, 0x7C, 0x5E, 0x09, 0xB4, 0xD3, 0xFB, 0x72, 0x74, 0xE6, 0x7A, 0x40, 0xE7, 0xD0, 0xD1, 0x89, 0x6D, 0x57, 0x03, 0xC1, 0x0E, 0xAB, 0x5D, 0x00, 0xB7, 0xB3, 0x81, 0x36, 0xD1, 0xD1, 0x40, 0xE6, 0x18, 0xEF, 0x94, 0xC9, 0x4B, 0x81, 0x6F, 0xF9, 0xBE, 0xEB, 0x7C, 0x35, 0x41, 0x7D, 0xEE, 0x99, 0x4B, 0x2A, 0xD0, 0xBC, 0x77, 0x9C, 0xDF, 0xB0, 0xE5, 0x40, 0x53, 0xB9, 0xCF, 0x93, 0xA1, 0x57, 0x80, 0xE6, 0xFD, 0x1E, 0x97, 0x5C, 0x92, 0x85, 0xEE, 0x9E, 0x97, 0x9C, 0x1E, 0x01, 0x8D, 0xDF, 0xBD, 0x3F, 0x8B, 0x51, 0x38, 0x11, 0x00, 0x84, 0x5D, 0xD9, 0x94, 0x55, 0x60, 0xC3, 0xC8, 0x2A, 0xCB, 0xC4, 0x05, 0x64, 0xEE, 0x82, 0xD8, 0x39, 0x64, 0x92, 0x7C, 0x78, 0x22, 0xB9, 0x28, 0x29, 0xE0, 0x15, 0x60, 0xDA, 0x1E, 0x00, 0x80, 0x58, 0x27, 0x40, 0xFE, 0xF3, 0x72, 0xAB, 0x25, 0xF6, 0x40, 0xE7, 0xD7, 0xCF, 0x74, 0x17, 0x7C, 0x05, 0x74, 0x67, 0x37, 0xF4, 0x9B, 0xAD, 0x00, 0x18, 0xB9, 0x34, 0x3B, 0x8C, 0xAB, 0x05, 0x7A, 0x48, 0x36, 0x75, 0xF2, 0x75, 0x04, 0x8C, 0x7E, 0x35, 0x4C, 0xF3, 0xBE, 0x0C, 0x18, 0x2B, 0x36, 0x84, 0x7B, 0x27, 0x01, 0x06, 0x83, 0x1A, 0xE6, 0x7A, 0x8B, 0xEB, 0xF0, 0xD4, 0x03, 0xAE, 0x9B, 0xA5, 0x0D, 0x76, 0x1F, 0xF9, 0xFE, 0x69, 0xFA, 0x0C, 0xF2, 0xDA, 0xF8, 0x1D, 0xB7, 0xC9, 0x9D, 0x63, 0xE2, 0x3C, 0xC9, 0xE8, 0x5E, 0xCB, 0xCD, 0xC8, 0x30, 0xC3, 0xD5, 0x67, 0x01, 0xE5, 0x11, 0x40, 0x60, 0xB4, 0xB4, 0xF1, 0x04, 0x1D, 0xBA, 0x5A, 0x56, 0x76, 0xF4, 0x99, 0x2C, 0x3C, 0xF8, 0x78, 0x89, 0xD7, 0x34, 0x20, 0xE2, 0x71, 0x63, 0x9C, 0xD7, 0x67, 0x20, 0xE8, 0x49, 0xA3, 0xA3, 0x4B, 0x18, 0xE0, 0xAF, 0x22, 0xCE, 0x8B, 0x1D, 0xE0, 0xEB, 0x25, 0xD6, 0x0D, 0x73, 0x00, 0x1F, 0x3A, 0x2F, 0xF9, 0x80, 0xB7, 0x84, 0xF8, 0xBA, 0xBA, 0xC8, 0x41, 0xB2, 0x5C, 0x3F, 0xCF, 0x88, 0xAC, 0xAE, 0xBF, 0x19, 0x4C, 0xE6, 0x1D, 0x38, 0xD9, 0x44, 0xA6, 0xF6, 0x3F, 0xFA, 0x95, 0x5C, 0x52, 0x71, 0x68, 0x21, 0x39, 0xA1, 0x26, 0xED, 0x22, 0x39, 0xAA, 0xF4, 0xE8, 0x2E, 0x12, 0xD8, 0xDF, 0x4B, 0xD9, 0xBE, 0xDF, 0x6E, 0xE0, 0xD0, 0xAF, 0xF9, 0xAF, 0xFB, 0x0C, 0x07, 0xD2, 0x9D, 0x0A, 0x0C, 0xAC, 0x7C, 0x81, 0x7D, 0x97, 0xEB, 0x96, 0xF7, 0x2E, 0x01, 0xB6, 0x44, 0xB5, 0x4C, 0x35, 0x37, 0x06, 0x56, 0xB4, 0x13, 0xFD, 0x71, 0x06, 0xB0, 0xF0, 0xAA, 0xC8, 0x1D, 0x6A, 0xC0, 0x02, 0x37, 0x91, 0x3B, 0x06, 0x02, 0x73, 0xAF, 0x88, 0xAF, 0x8F, 0x11, 0xBB, 0x40, 0x43, 0x80, 0x36, 0x62, 0x7C, 0x79, 0x5B, 0x02, 0x00, 0x8F, 0x32, 0xEE, 0xF8, 0x02, 0x52, 0x07, 0x33, 0x57, 0xDE, 0x3A, 0x03, 0x00, 0xEB, 0x3B, 0xDF, 0x9A, 0x43, 0x4E, 0x94, 0xB8, 0xF5, 0x9E, 0x1C, 0xBA, 0x27, 0xEF, 0x01, 0x69, 0xAD, 0x5D, 0xA8, 0x46, 0x02, 0x85, 0xA6, 0xC6, 0x92, 0xBA, 0xDE, 0x40, 0xC1, 0xBC, 0x79, 0x4E, 0x1D, 0x3B, 0x01, 0xF9, 0x93, 0x2F, 0x35, 0x75, 0x08, 0x07, 0xAE, 0x0D, 0xAE, 0x92, 0xEC, 0xE0, 0x0D, 0x64, 0xE9, 0x37, 0xEF, 0x52, 0xEF, 0x06, 0xA4, 0xC9, 0x8A, 0x7B, 0x3B, 0x47, 0x60, 0xAF, 0xB8, 0x07, 0x50, 0x56, 0x06, 0x76, 0x8B, 0x7B, 0xA7, 0xB6, 0xD5, 0xC0, 0x8E, 0x3A, 0xF1, 0x75, 0xB1, 0x30, 0xF5, 0xE5, 0x24, 0x20, 0xEF, 0xF0, 0x6E, 0x56, 0x69, 0x36, 0x20, 0xBB, 0xE6, 0x7C, 0xEC, 0xCB, 0xF6, 0x00, 0xB0, 0xF5, 0xF7, 0x4B, 0x63, 0x32, 0x42, 0xE2, 0x95, 0x3A, 0xE9, 0x62, 0x5E, 0x9C, 0x42, 0x1A, 0x5E, 0x2E, 0x31, 0x26, 0x71, 0xF4, 0xA3, 0x0A, 0xA0, 0xF0, 0x02, 0x78, 0x9F, 0xDE, 0xF7, 0xA6, 0x8C, 0x3D, 0x50, 0xF1, 0x79, 0x71, 0x92, 0xE4, 0x37, 0xE1, 0xFA, 0x33, 0x19, 0x12, 0x9E, 0x40, 0xF9, 0x8B, 0x8F, 0x26, 0x00, 0xF0, 0xDC, 0xBF, 0xE1, 0x94, 0x54, 0x57, 0xA0, 0x50, 0xCC, 0x25, 0x32, 0xED, 0x80, 0x2B, 0x62, 0x8E, 0x91, 0x9C, 0x0B, 0x5C, 0x58, 0x24, 0x66, 0xFA, 0x52, 0xE0, 0x8C, 0x18, 0xEB, 0xDB, 0xA8, 0x56, 0xBD, 0xAB, 0xB7, 0x05, 0xE4, 0x6F, 0xE5, 0x8E, 0xFB, 0x1A, 0x00, 0x48, 0xF6, 0x4C, 0x92, 0xAC, 0x48, 0x07, 0x80, 0x99, 0xBB, 0x3F, 0x87, 0x92, 0xAE, 0x2A, 0xDF, 0xFA, 0x91, 0x3A, 0x7D, 0xAA, 0xCA, 0x48, 0xD9, 0x43, 0xBF, 0x1D, 0x49, 0xA0, 0xA1, 0xA9, 0x73, 0x2E, 0xD9, 0xD8, 0xDF, 0x7D, 0x29, 0xD9, 0x64, 0x14, 0x93, 0x03, 0xDE, 0x77, 0xFB, 0x92, 0x6C, 0xD6, 0x29, 0x35, 0x22, 0x9B, 0xAE, 0xD5, 0x17, 0x91, 0x3F, 0x77, 0x88, 0xFA, 0x0B, 0x81, 0x8A, 0x2C, 0x1E, 0x0B, 0x5F, 0xCF, 0x12, 0x4E, 0x03, 0x5E, 0xB4, 0x17, 0x73, 0xDF, 0xA0, 0xA2, 0xB5, 0x4D, 0xE7, 0x01, 0xE5, 0x09, 0x87, 0xCE, 0xFD, 0xF8, 0x00, 0x00, 0xF3, 0xE6, 0xFE, 0xD8, 0x42, 0x0E, 0xD9, 0xF7, 0xCB, 0x89, 0xD4, 0x0C, 0xFF, 0xF5, 0x8A, 0x04, 0x7E, 0x0F, 0x05, 0xB8, 0x4E, 0xFB, 0x7D, 0x6C, 0x9F, 0xA7, 0xAC, 0x7F, 0x34, 0x1B, 0x93, 0xC2, 0xEE, 0xFF, 0xC5, 0x16, 0xA4, 0xB0, 0x1F, 0x0A, 0x01, 0x49, 0x1B, 0x11, 0x77, 0x6C, 0x01, 0xC4, 0xFE, 0x93, 0x7F, 0x58, 0x36, 0xB3, 0xBC, 0x79, 0x02, 0x20, 0x31, 0x7A, 0xC9, 0x95, 0xFA, 0x03, 0x00, 0xE0, 0x36, 0xA2, 0xF1, 0x32, 0xA9, 0x9D, 0xF9, 0xDF, 0xF9, 0x43, 0xA6, 0x0F, 0xAB, 0x79, 0x94, 0xB5, 0x0D, 0x67, 0xFD, 0x1E, 0xB2, 0x91, 0x77, 0xD9, 0xAD, 0x7E, 0xEC, 0xB1, 0xAF, 0xEC, 0xBD, 0x5A, 0xF6, 0x83, 0x9D, 0x20, 0x4A, 0xE4, 0x9F, 0x27, 0x80, 0xC4, 0x5A, 0x91, 0x7F, 0xB6, 0x08, 0xC5, 0xCA, 0x48, 0x4B, 0x3F, 0x60, 0xCD, 0x11, 0xAE, 0xE3, 0xAB, 0xC3, 0x76, 0x37, 0xFE, 0xEF, 0xFA, 0xF0, 0x61, 0xDB, 0x66, 0xB1, 0x46, 0x47, 0x58, 0x27, 0x5F, 0xD6, 0x57, 0x9A, 0x9D, 0x5A, 0xC0, 0xC6, 0x75, 0xFA, 0x8F, 0x1C, 0x74, 0x82, 0xBD, 0xDB, 0xC0, 0x96, 0xD4, 0xB3, 0xE5, 0xB7, 0xD9, 0x4F, 0x2F, 0xE9, 0xA3, 0xA7, 0xEC, 0x3F, 0xF3, 0xBD, 0xAE, 0xD0, 0xC4, 0x02, 0xE8, 0x75, 0x8A, 0x73, 0x4F, 0xBF, 0x2B, 0xEC, 0x30, 0x07, 0x71, 0x36, 0x32, 0xFF, 0x79, 0x3E, 0xB6, 0x34, 0x9C, 0x6C, 0xB7, 0x66, 0xD7, 0xE9, 0x7F, 0xCD, 0x1D, 0xE1, 0x47, 0x56, 0x1F, 0x21, 0x23, 0xB4, 0x23, 0xB4, 0xC9, 0x03, 0x65, 0x6E, 0xD9, 0x64, 0xDE, 0x0B, 0x27, 0x91, 0xFA, 0x64, 0xB6, 0x7E, 0x92, 0x34, 0xA0, 0x79, 0x09, 0xF5, 0x7B, 0x35, 0xF7, 0x91, 0xCD, 0xDB, 0xD5, 0xFD, 0x49, 0x7E, 0x1E, 0xE5, 0xBE, 0x01, 0xDC, 0x8E, 0x3C, 0x40, 0x47, 0xA4, 0x66, 0xDB, 0xB6, 0x80, 0xA1, 0x9D, 0xB8, 0xC6, 0x9B, 0x01, 0xA7, 0x67, 0xDC, 0x0E, 0x57, 0xBA, 0xBF, 0xD7, 0x02, 0x42, 0xF6, 0x0A, 0x01, 0x2C, 0xD2, 0x23, 0xD5, 0x3E, 0x9F, 0x58, 0xF9, 0xAF, 0xED, 0x98, 0x2B, 0xB1, 0x67, 0x1F, 0x99, 0x2A, 0xE7, 0x53, 0x41, 0xA6, 0x07, 0x0F, 0xBF, 0x40, 0x3E, 0xFE, 0xD3, 0x2B, 0x99, 0xFC, 0x39, 0x5D, 0x77, 0x24, 0xD7, 0x55, 0x9C, 0xCC, 0x4A, 0x59, 0xB3, 0x74, 0x8C, 0x6C, 0x06, 0xC8, 0x51, 0xC7, 0x59, 0xC7, 0x33, 0x80, 0x9E, 0xAE, 0x58, 0xBF, 0x58, 0x0A, 0x58, 0x2F, 0x13, 0x63, 0xCD, 0x73, 0xA0, 0x5F, 0xB1, 0xC8, 0x67, 0xED, 0x81, 0x11, 0x0D, 0xAD, 0xF9, 0x23, 0x8B, 0x54, 0xEC, 0xB3, 0xE7, 0x03, 0x39, 0x58, 0xE5, 0xE0, 0x5E, 0x72, 0xDA, 0xEB, 0x69, 0xF7, 0xC8, 0xE4, 0x61, 0xFE, 0xE9, 0xE4, 0xF1, 0xAC, 0xA1, 0x22, 0x4F, 0xCA, 0x7A, 0x7C, 0x8A, 0x36, 0x30, 0xE2, 0x5A, 0x1D, 0x52, 0xD8, 0x7F, 0x8E, 0xDA, 0x7D, 0x24, 0x1D, 0xEE, 0x92, 0x00, 0xE9, 0xD6, 0x86, 0x1D, 0xFD, 0x92, 0xED, 0xBB, 0x1D, 0xD0, 0xF3, 0x11, 0xEF, 0x8B, 0x36, 0xD0, 0xDF, 0x91, 0x73, 0xD0, 0x70, 0xB1, 0x4E, 0xA7, 0xD1, 0x1E, 0x18, 0x7B, 0xBD, 0xB5, 0x3D, 0x2E, 0x64, 0xC0, 0xDC, 0x30, 0x53, 0x32, 0xF8, 0xD0, 0xF4, 0x70, 0xF2, 0xB8, 0x9A, 0xF7, 0x1A, 0xF2, 0x99, 0x8C, 0xBD, 0x12, 0x59, 0x1F, 0xDC, 0x75, 0x1B, 0x49, 0xC7, 0xDB, 0x32, 0xF6, 0x65, 0x32, 0xFB, 0xCC, 0x89, 0xA4, 0xC3, 0xAF, 0x10, 0x20, 0x7D, 0xFB, 0xB2, 0x63, 0xEF, 0xB1, 0x7D, 0xE3, 0x00, 0x63, 0x91, 0xA7, 0xAC, 0xEE, 0x02, 0x76, 0xF6, 0xA2, 0x3D, 0x6F, 0x80, 0x91, 0x62, 0xDC, 0x55, 0x6D, 0x0F, 0x04, 0xD3, 0xF9, 0x47, 0x9B, 0xB8, 0xD9, 0xA5, 0x64, 0xC8, 0xC9, 0x71, 0x9F, 0xC8, 0xDD, 0x6B, 0xFC, 0x8E, 0x90, 0x39, 0xB3, 0x3C, 0x45, 0xBF, 0x52, 0xF2, 0xA9, 0xB7, 0x31, 0xCE, 0xA9, 0x56, 0x06, 0x5D, 0xE9, 0x5F, 0x8A, 0x6F, 0x90, 0x18, 0x70, 0xEB, 0x3A, 0x09, 0xE4, 0x1A, 0xB1, 0x57, 0xDF, 0x93, 0xD2, 0xA2, 0x1F, 0x4D, 0xDE, 0xCD, 0x75, 0xC3, 0x2C, 0xD8, 0xD0, 0x9E, 0x6C, 0xF8, 0x76, 0xD6, 0xC9, 0x1B, 0xB0, 0x11, 0xEF, 0x87, 0xDD, 0x53, 0xBA, 0xAB, 0x15, 0x6B, 0x39, 0x41, 0x80, 0x3F, 0xAD, 0xB7, 0xC1, 0xB2, 0x63, 0xC8, 0x50, 0x32, 0x44, 0xC7, 0xD7, 0x83, 0x3C, 0xFE, 0xC1, 0x45, 0xB7, 0xB4, 0x0E, 0x28, 0x79, 0xD2, 0x6D, 0x41, 0xAE, 0x3E, 0xD0, 0x22, 0xA9, 0x7E, 0xED, 0x72, 0x1D, 0xD0, 0x7C, 0xA4, 0x73, 0x73, 0x96, 0x1A, 0x28, 0x1F, 0x9F, 0x3F, 0x6C, 0x4A, 0x6A, 0x9E, 0x49, 0xB5, 0x22, 0xB5, 0x9C, 0xF7, 0x6E, 0x20, 0x75, 0x82, 0xC4, 0x2A, 0x70, 0x2A, 0xD7, 0x9B, 0xE7, 0xCA, 0x46, 0xDE, 0x60, 0xE7, 0xC8, 0xB1, 0xB3, 0xF7, 0xB1, 0xFD, 0xCC, 0x80, 0xBE, 0xFD, 0x79, 0x1D, 0x71, 0xE8, 0xCF, 0xAA, 0x20, 0xC0, 0x34, 0xD6, 0xBD, 0xF4, 0x56, 0x09, 0x10, 0x36, 0xA1, 0xCF, 0xCB, 0xAC, 0xCD, 0x40, 0x9A, 0xBA, 0x41, 0xCE, 0x5E, 0x77, 0xA0, 0x4C, 0x57, 0xA3, 0x78, 0x55, 0x37, 0xA0, 0xF9, 0x83, 0x56, 0xF1, 0xBA, 0x60, 0x61, 0x9C, 0xF5, 0xB1, 0x18, 0x2B, 0xD0, 0xC8, 0x67, 0x15, 0xAD, 0x4B, 0xF6, 0x7A, 0x3D, 0xAF, 0x8A, 0xB4, 0xEE, 0x37, 0x33, 0x8F, 0xB4, 0x29, 0x12, 0xF9, 0x66, 0x17, 0x38, 0xEF, 0x54, 0xB2, 0x6B, 0x65, 0xD8, 0xD8, 0x4C, 0x76, 0xD1, 0x36, 0xB2, 0xF1, 0xD2, 0xBC, 0xC3, 0xE4, 0x83, 0x00, 0xF7, 0xBB, 0x40, 0x87, 0xCA, 0x8D, 0x0A, 0x80, 0x44, 0xC8, 0xF0, 0xD8, 0xF9, 0x7F, 0x00, 0xD7, 0xA6, 0xBE, 0xCD, 0x53, 0x4B, 0x80, 0x5D, 0x3F, 0x1D, 0x97, 0x05, 0x6B, 0x03, 0x2F, 0x57, 0x3A, 0xAF, 0x1F, 0x55, 0x06, 0x34, 0x9D, 0x77, 0x6D, 0x70, 0xA2, 0x1D, 0xA9, 0x1D, 0x87, 0xFF, 0xA4, 0x1D, 0x2B, 0xCD, 0x1B, 0xDD, 0xDF, 0x5B, 0x0F, 0xA5, 0xD7, 0x1C, 0xD6, 0x62, 0x35, 0x5A, 0xF8, 0x6E, 0x84, 0x99, 0xD9, 0x1B, 0xA0, 0xE5, 0xFA, 0x88, 0xB0, 0x7F, 0x79, 0x3E, 0x37, 0x9D, 0xDD, 0xD7, 0x83, 0x4D, 0x7C, 0x4C, 0x96, 0x28, 0xC7, 0xFE, 0x20, 0xB3, 0x3D, 0xA7, 0xAA, 0x91, 0x2B, 0xA5, 0x3C, 0x13, 0xC8, 0x49, 0x31, 0x83, 0x4B, 0x81, 0x2E, 0xE3, 0x00, 0x00, 0x98, 0x5D, 0x0D, 0xC8, 0x48, 0x4F, 0x7E, 0x17, 0xB1, 0x10, 0xD0, 0x98, 0x74, 0xA9, 0x24, 0x34, 0x1C, 0xD0, 0xF6, 0xA9, 0x76, 0x1D, 0x3F, 0x0D, 0xE8, 0xEE, 0xDA, 0xD2, 0xD1, 0x7D, 0x89, 0x44, 0x1A, 0xAD, 0x69, 0xF5, 0x73, 0x00, 0xCC, 0x8C, 0x45, 0xDF, 0x33, 0x15, 0x76, 0x10, 0xCE, 0x00, 0x8C, 0x8F, 0x8A, 0xAF, 0x8B, 0xEB, 0x33, 0xB3, 0xB5, 0x1D, 0xA7, 0xEE, 0x80, 0xED, 0x43, 0xBE, 0x08, 0xDA, 0x67, 0x4F, 0x66, 0xB5, 0x5B, 0x5B, 0x2E, 0xA8, 0x58, 0x6D, 0x3D, 0x77, 0x82, 0x10, 0x11, 0x8A, 0xD3, 0xA3, 0x48, 0xFF, 0xBD, 0x91, 0x2F, 0x48, 0xC0, 0xFD, 0x90, 0x44, 0x9F, 0x91, 0x29, 0x40, 0xF0, 0xD4, 0x88, 0x67, 0xCE, 0x53, 0x81, 0xD0, 0x84, 0x73, 0x9D, 0xEC, 0xA7, 0x01, 0x21, 0x3B, 0xAA, 0xF6, 0x3B, 0xEA, 0x01, 0x81, 0xBD, 0x1B, 0xDD, 0xAC, 0x43, 0x00, 0x6F, 0x7A, 0x1E, 0x14, 0x09, 0xB8, 0x8B, 0x6B, 0x59, 0x7F, 0x83, 0x50, 0x64, 0xEF, 0xEE, 0x57, 0x81, 0x91, 0x62, 0x06, 0x31, 0x94, 0xFD, 0xE7, 0xEF, 0x18, 0xE5, 0x87, 0x91, 0x1F, 0x0A, 0xAE, 0x46, 0x92, 0x97, 0x1E, 0x1E, 0xED, 0x00, 0x48, 0x18, 0x26, 0xE8, 0x24, 0xD7, 0x09, 0x3B, 0xCF, 0x31, 0x4C, 0xCE, 0x01, 0x80, 0x51, 0x51, 0xBB, 0xBD, 0x49, 0x67, 0xB9, 0xAD, 0x9B, 0x49, 0x60, 0xDD, 0xD1, 0x36, 0x51, 0x66, 0xBB, 0x81, 0xF8, 0xAE, 0xC1, 0x7E, 0x5D, 0xD3, 0x81, 0x1D, 0x7E, 0xA7, 0x2D, 0xBB, 0x9C, 0x06, 0xB6, 0xDE, 0xAA, 0xD0, 0xEF, 0xE2, 0x07, 0xAC, 0xDE, 0xD0, 0xF0, 0x48, 0xCB, 0x1E, 0x58, 0x3C, 0x91, 0xF7, 0xC5, 0xCC, 0x14, 0xF3, 0xAC, 0xD2, 0x0C, 0xA1, 0xA4, 0xC8, 0x21, 0x5B, 0x80, 0x69, 0xA2, 0x8F, 0xB7, 0x13, 0x77, 0xF7, 0x4F, 0x4E, 0x00, 0x40, 0xE3, 0xCF, 0xD7, 0xD7, 0xC9, 0xC2, 0x98, 0xBC, 0x3F, 0x80, 0xE4, 0x88, 0xE4, 0x92, 0xCB, 0x03, 0x01, 0x6C, 0x8E, 0xEE, 0x7B, 0x65, 0xBF, 0x10, 0xBE, 0xDF, 0x2E, 0x8F, 0x24, 0x7B, 0x7F, 0x3C, 0xEF, 0x4A, 0x6A, 0xCD, 0xCD, 0x0E, 0x20, 0x81, 0xB3, 0x36, 0xBA, 0x2F, 0xE5, 0x7A, 0x00, 0x67, 0x7A, 0x86, 0x2C, 0x90, 0x52, 0x00, 0x4E, 0x6F, 0x4A, 0x95, 0x00, 0x80, 0xCC, 0xA2, 0x12, 0x6D, 0xF2, 0xC8, 0xF8, 0x66, 0x25, 0xA9, 0x5A, 0x60, 0x7F, 0xA9, 0xC8, 0x19, 0x53, 0x80, 0xAD, 0x34, 0xC6, 0x15, 0x01, 0x9B, 0xC5, 0xB5, 0x2D, 0x91, 0x0F, 0x6C, 0xD8, 0x26, 0xAE, 0x5B, 0x29, 0xB1, 0x0A, 0xA0, 0x05, 0x00, 0xCF, 0xB7, 0xBD, 0x4E, 0x02, 0x64, 0xC2, 0x8F, 0xEF, 0x7A, 0x68, 0x01, 0x00, 0x31, 0xFD, 0x1E, 0x24, 0x93, 0x63, 0x94, 0x1F, 0x1E, 0x22, 0x7B, 0x2F, 0x7E, 0x34, 0x96, 0xEC, 0xD0, 0xAB, 0x68, 0x1A, 0x09, 0x3C, 0x19, 0x89, 0x58, 0xF2, 0xE1, 0x77, 0xC7, 0x29, 0x64, 0xD1, 0xDA, 0x59, 0x29, 0x20, 0xBF, 0xA7, 0xC6, 0x93, 0xB7, 0xD5, 0xAF, 0xC9, 0x90, 0x77, 0x0C, 0xAA, 0x6C, 0xC9, 0x1B, 0xBC, 0xB2, 0x80, 0xAC, 0xFE, 0x6C, 0x66, 0x3D, 0x7B, 0xBC, 0x3F, 0xF9, 0x61, 0xFA, 0x4F, 0x19, 0xA0, 0x8D, 0xDD, 0x85, 0x8D, 0xE5, 0xEF, 0x00, 0x60, 0x7D, 0x75, 0x89, 0x3E, 0x39, 0xFE, 0xF5, 0x9B, 0x49, 0xA4, 0xF5, 0xCC, 0xF2, 0x47, 0xA4, 0x8A, 0xC5, 0x57, 0x4B, 0x12, 0xF8, 0x12, 0xC4, 0xD6, 0x2C, 0xEC, 0x3A, 0x91, 0xFC, 0x3E, 0xC5, 0x6D, 0x14, 0x59, 0x6D, 0xB6, 0xE8, 0x06, 0x59, 0xDB, 0x33, 0xAD, 0x33, 0x59, 0x13, 0xFE, 0xE0, 0x0C, 0x59, 0xDD, 0x5C, 0x5D, 0x4A, 0x7E, 0x7C, 0xCF, 0x75, 0x5F, 0xC5, 0xB3, 0x4F, 0x35, 0xD8, 0xA2, 0x73, 0x64, 0x81, 0x43, 0xFD, 0x44, 0x40, 0xFA, 0x7E, 0xE2, 0xA8, 0x2F, 0x37, 0x01, 0x20, 0xBC, 0xDF, 0x97, 0x36, 0xA4, 0x83, 0xEB, 0xB7, 0x58, 0xB2, 0x7D, 0xEA, 0x0F, 0x59, 0x12, 0xA8, 0xD3, 0x64, 0xC5, 0x2C, 0xE1, 0xC2, 0xDA, 0xE4, 0xB1, 0x81, 0x59, 0x6C, 0xEC, 0x0D, 0x36, 0x45, 0x82, 0xCD, 0x1F, 0xCD, 0xBE, 0xEF, 0x04, 0x48, 0x88, 0x55, 0xA9, 0xA6, 0x40, 0x00, 0x87, 0xFE, 0xEF, 0x39, 0xE8, 0xA0, 0x54, 0xDD, 0x21, 0x00, 0x98, 0xD5, 0xBE, 0xF6, 0x26, 0x39, 0x20, 0xE9, 0x77, 0x0A, 0xA9, 0x31, 0xAC, 0xE5, 0xC1, 0x7F, 0xE6, 0x10, 0xB9, 0x9D, 0x6C, 0x57, 0x57, 0xD6, 0x51, 0x85, 0x0D, 0x28, 0x60, 0xE7, 0x5E, 0x65, 0xB7, 0x38, 0xB1, 0x69, 0x7F, 0xD9, 0x3B, 0xEE, 0x6C, 0xF9, 0x69, 0x81, 0x98, 0x11, 0xEA, 0x1C, 0x00, 0x89, 0x2F, 0x22, 0xFF, 0xB4, 0x00, 0x92, 0xDC, 0x0E, 0x44, 0x97, 0x50, 0x2E, 0x04, 0x86, 0xED, 0x69, 0xE9, 0x4F, 0x76, 0x89, 0xFC, 0xEF, 0x1C, 0x24, 0x95, 0xCF, 0xAA, 0x26, 0xB1, 0xE6, 0xD3, 0x58, 0x57, 0x5B, 0xD6, 0xBF, 0x82, 0x9D, 0x1E, 0xC2, 0xC6, 0x0D, 0xF9, 0xF7, 0x1C, 0x94, 0xE9, 0xCB, 0xDE, 0xA9, 0x65, 0xDF, 0x95, 0xB1, 0x15, 0x3F, 0xD9, 0x2F, 0xD5, 0xF4, 0x71, 0x68, 0x1F, 0x80, 0xB4, 0xD8, 0xC4, 0x39, 0x48, 0x17, 0x80, 0xF9, 0x7E, 0xD6, 0xE6, 0x2C, 0xDB, 0x9F, 0x5B, 0x85, 0xA0, 0x9F, 0x6C, 0xC4, 0x42, 0x52, 0xF2, 0xE4, 0x72, 0x90, 0xFD, 0xB1, 0x24, 0x93, 0x0C, 0x46, 0x30, 0xC8, 0xCD, 0xF9, 0x1E, 0xB7, 0xC8, 0x03, 0x93, 0x06, 0x85, 0x93, 0x79, 0x15, 0xBD, 0x52, 0x84, 0xDF, 0x3F, 0x40, 0xF7, 0xBB, 0x10, 0x0D, 0x55, 0x2A, 0x06, 0xAD, 0x39, 0xE4, 0x03, 0xDB, 0x46, 0xCC, 0xDF, 0x83, 0x5F, 0x71, 0x3B, 0xAC, 0x0D, 0x80, 0xCE, 0x4B, 0xC4, 0x4F, 0x3B, 0x0E, 0xD0, 0x13, 0xF9, 0x42, 0xA7, 0x3F, 0xD0, 0x5B, 0x89, 0xDB, 0xE1, 0x4C, 0x7F, 0xCF, 0x79, 0x14, 0xE0, 0x32, 0x8D, 0xDB, 0x31, 0x69, 0x23, 0x1B, 0xEB, 0x4A, 0xF6, 0x5F, 0xB0, 0xC2, 0x88, 0x0C, 0x51, 0x0D, 0xFC, 0x4B, 0xEE, 0x34, 0xF2, 0xD0, 0x26, 0x0F, 0x8E, 0x73, 0x59, 0x43, 0x3E, 0x9E, 0x6C, 0x34, 0x85, 0xAC, 0xBD, 0xDB, 0xC9, 0x86, 0xA4, 0x67, 0x73, 0xE4, 0xBF, 0x1F, 0xAE, 0xD1, 0x00, 0x39, 0x22, 0x8E, 0x35, 0x9B, 0x02, 0xE8, 0x45, 0x88, 0x5E, 0x30, 0x06, 0xB0, 0xB4, 0xE2, 0x76, 0xD8, 0xB7, 0x15, 0xF3, 0xEC, 0x72, 0xA0, 0x7F, 0x1C, 0xD7, 0x0F, 0xB5, 0x63, 0xE3, 0xAE, 0x91, 0x4E, 0x13, 0xE6, 0x96, 0x93, 0x81, 0x99, 0xC1, 0x1F, 0xC8, 0xE4, 0x03, 0x43, 0x56, 0x91, 0x67, 0x6B, 0x6C, 0xDB, 0x09, 0x47, 0x54, 0x34, 0x76, 0xB3, 0xE4, 0x5A, 0xCA, 0x05, 0x2D, 0x6B, 0x49, 0xA0, 0x66, 0x3F, 0xFB, 0x79, 0x00, 0x49, 0x87, 0x8B, 0x3A, 0x40, 0x0E, 0xD6, 0x66, 0x1D, 0x3E, 0x00, 0x1D, 0x24, 0xC5, 0x9C, 0x68, 0x0B, 0x68, 0x7B, 0x8B, 0xF6, 0x54, 0x01, 0x7D, 0x3A, 0x8B, 0xB5, 0x14, 0x00, 0xCE, 0x19, 0xAD, 0xED, 0x88, 0x61, 0x27, 0x39, 0x90, 0xC3, 0xF3, 0x43, 0xC4, 0xDA, 0xAC, 0xC2, 0x90, 0xA8, 0xA1, 0x2E, 0x74, 0x4D, 0xE2, 0x40, 0x3B, 0xA7, 0xDD, 0xE4, 0x93, 0x2F, 0x7A, 0x9B, 0xC9, 0x3F, 0xBD, 0xD5, 0xF4, 0x85, 0x9C, 0x7B, 0xBE, 0xB1, 0x8F, 0xE4, 0xD9, 0x7B, 0x8B, 0x49, 0x3A, 0xDC, 0x2C, 0x00, 0x72, 0xF8, 0x60, 0xD6, 0xD3, 0x81, 0x75, 0xA4, 0xF5, 0x05, 0x91, 0x5F, 0x2D, 0x7C, 0x81, 0x1E, 0x3F, 0xC4, 0x3A, 0x99, 0x0F, 0xD0, 0xF7, 0x2E, 0x3F, 0x2F, 0x1C, 0x94, 0xCA, 0xED, 0x08, 0x8B, 0x22, 0xC7, 0xAC, 0x73, 0x73, 0x26, 0xE3, 0x87, 0x38, 0x2C, 0x25, 0xAF, 0xF6, 0xD7, 0xAB, 0x25, 0xAB, 0x25, 0xDA, 0xEA, 0x95, 0xF5, 0x06, 0x5A, 0xBE, 0x49, 0xC9, 0x3F, 0x9C, 0x02, 0xCE, 0x3D, 0xB3, 0xD9, 0xF3, 0x51, 0xA4, 0xD4, 0x87, 0xAC, 0x9D, 0xA4, 0xDC, 0x40, 0x71, 0xD5, 0xB5, 0xB6, 0xC3, 0xE7, 0x2F, 0x3B, 0x5A, 0x93, 0x0D, 0xFC, 0xCC, 0xF6, 0x1B, 0x0F, 0xE8, 0x89, 0x7E, 0xD1, 0xE3, 0x0C, 0xD0, 0xAB, 0x4C, 0xF4, 0x93, 0xCD, 0x80, 0xB3, 0x68, 0x1F, 0x60, 0xBA, 0x7B, 0xF8, 0x5A, 0x72, 0x6A, 0x5E, 0x4F, 0x1F, 0xCA, 0x23, 0x69, 0x66, 0x5D, 0x76, 0x3D, 0xDE, 0x09, 0xDC, 0xDD, 0x22, 0x79, 0xE4, 0xF2, 0x2D, 0xE0, 0xC7, 0x0F, 0x20, 0xBB, 0x0C, 0x68, 0x36, 0x91, 0xCD, 0x48, 0xDF, 0x07, 0x5A, 0xA7, 0x93, 0x4C, 0x32, 0x27, 0x3B, 0x86, 0x6E, 0x2B, 0x25, 0xB5, 0x1A, 0x36, 0x36, 0x93, 0xDA, 0x9D, 0xE9, 0xEF, 0xAD, 0x73, 0xBD, 0xA9, 0xCD, 0xEC, 0xE4, 0x64, 0x76, 0xC2, 0x1F, 0x36, 0xA8, 0x81, 0xED, 0x9B, 0x0E, 0xE8, 0x89, 0x7E, 0x69, 0x7A, 0x0B, 0xB0, 0x8A, 0x78, 0xBC, 0x00, 0xB0, 0x72, 0xE9, 0xDA, 0x92, 0xF6, 0x08, 0x18, 0x37, 0xB7, 0xCD, 0x9E, 0xFD, 0x07, 0x81, 0xAD, 0xEB, 0xA4, 0xF7, 0x25, 0x8C, 0x00, 0x0A, 0xB2, 0x81, 0x38, 0x4D, 0xA0, 0xFE, 0x22, 0xB0, 0x98, 0x72, 0xC6, 0x05, 0x2D, 0xE5, 0xF9, 0x1E, 0xA0, 0x2B, 0x5E, 0x6F, 0xE2, 0x15, 0xB2, 0xE7, 0xC1, 0xE0, 0x3F, 0xA4, 0x55, 0x9F, 0xA0, 0x4E, 0x20, 0x45, 0x3F, 0x5C, 0xF3, 0x9C, 0xEB, 0xAC, 0xCA, 0x67, 0x97, 0x7C, 0x64, 0xE7, 0x9A, 0xB0, 0x13, 0x27, 0x93, 0x6F, 0xD2, 0xDD, 0xBF, 0x90, 0x67, 0x22, 0xAC, 0x14, 0x01, 0x99, 0xE6, 0xB9, 0xF9, 0x40, 0xBB, 0xBF, 0xFA, 0x06, 0x13, 0x55, 0x80, 0x01, 0x99, 0xDD, 0xC2, 0xC6, 0x0D, 0x02, 0x62, 0x0A, 0x0C, 0xAE, 0x8C, 0x9E, 0x08, 0x5C, 0x93, 0x35, 0x0E, 0xF7, 0x54, 0x07, 0xAA, 0xDD, 0x2D, 0x76, 0x3A, 0xE9, 0x03, 0x7F, 0x37, 0x5A, 0x7D, 0xE2, 0xBF, 0x60, 0x37, 0xC0, 0xAE, 0xCB, 0x47, 0xD2, 0x65, 0x56, 0x97, 0x7D, 0x20, 0xCF, 0x74, 0xDE, 0x43, 0x0E, 0x14, 0xA3, 0xD6, 0xDE, 0xE3, 0xE0, 0x51, 0x47, 0x8A, 0xDD, 0xD9, 0x93, 0xAC, 0xBD, 0xB0, 0x2E, 0x95, 0x2C, 0x9A, 0x36, 0x77, 0x18, 0x99, 0x7E, 0x3A, 0x20, 0x9E, 0x8C, 0x1C, 0x34, 0x40, 0x89, 0x1C, 0xBD, 0xDB, 0xE1, 0x09, 0x20, 0x67, 0x0A, 0x00, 0x40, 0xD0, 0x55, 0x40, 0xEE, 0xA3, 0x9F, 0xDC, 0x28, 0xA1, 0xDA, 0xC8, 0xC3, 0xD1, 0x23, 0xE6, 0x02, 0x9D, 0x8F, 0xBE, 0xDC, 0xE9, 0x7A, 0x10, 0xE8, 0x66, 0x5D, 0x5F, 0xE6, 0xD8, 0x13, 0x30, 0xA8, 0x10, 0x7D, 0xAD, 0x01, 0x30, 0xBA, 0x21, 0xAE, 0xC9, 0x6D, 0x40, 0x77, 0x31, 0x36, 0x58, 0xFA, 0x01, 0xFA, 0xE7, 0x85, 0x62, 0x7D, 0x31, 0xA3, 0x06, 0x9C, 0x7F, 0x82, 0xC9, 0xBA, 0xB8, 0xA3, 0xDD, 0xC8, 0x07, 0xC9, 0x3B, 0xF6, 0x92, 0xE9, 0x6A, 0xCB, 0xAE, 0x03, 0x92, 0x7E, 0x51, 0x11, 0x13, 0xF3, 0x01, 0x20, 0xB0, 0x31, 0x68, 0x3D, 0x39, 0xA4, 0x65, 0xDC, 0x43, 0x12, 0x70, 0xBD, 0x03, 0x38, 0x4C, 0x06, 0x46, 0x2D, 0xF3, 0xB7, 0x32, 0xAD, 0x07, 0xFC, 0x92, 0x53, 0x96, 0x1B, 0x3C, 0x02, 0x02, 0xA7, 0x16, 0x9F, 0x37, 0x38, 0x0C, 0xF8, 0x5E, 0xF9, 0xF3, 0x50, 0x7F, 0x3D, 0x30, 0x52, 0x4F, 0xAC, 0x17, 0xCE, 0x01, 0x06, 0x09, 0xDB, 0xDD, 0x03, 0xFA, 0x8B, 0xBE, 0xAD, 0xBE, 0x43, 0x28, 0x27, 0x72, 0xC9, 0xD2, 0x7F, 0x72, 0x50, 0x81, 0x22, 0x59, 0xDC, 0xFD, 0x7C, 0x2F, 0xF2, 0x94, 0xFE, 0x01, 0x39, 0x40, 0xCA, 0x62, 0xE5, 0xD2, 0x6D, 0x34, 0x1B, 0x84, 0x4D, 0xAC, 0xDA, 0xFE, 0x14, 0x00, 0x5C, 0x3A, 0xAC, 0xAF, 0x25, 0x4D, 0xE4, 0x96, 0x4C, 0x22, 0x81, 0xA8, 0x9F, 0x92, 0xC7, 0x35, 0xD6, 0x02, 0x2B, 0x06, 0xBA, 0x65, 0xCA, 0xFC, 0x05, 0x56, 0xDE, 0x4E, 0x6A, 0x2F, 0x73, 0x13, 0x58, 0x31, 0xAE, 0xE8, 0xA7, 0xF4, 0x24, 0x60, 0xE9, 0xF3, 0xBA, 0x3F, 0x72, 0xF6, 0xC0, 0x7C, 0x79, 0xF1, 0xC4, 0xE2, 0x32, 0x30, 0xE9, 0x12, 0x5F, 0x6B, 0xE3, 0xEF, 0x0B, 0x25, 0x80, 0x20, 0x91, 0x3F, 0x24, 0x07, 0x8B, 0x1C, 0xB4, 0x13, 0x00, 0x6A, 0x14, 0x9E, 0x27, 0x90, 0xD7, 0xFA, 0x5C, 0x6F, 0x4B, 0x6E, 0xCD, 0x3A, 0x59, 0x29, 0x50, 0x9F, 0xEA, 0x9B, 0x95, 0x29, 0xC4, 0xE0, 0x73, 0xA7, 0x4D, 0x48, 0xDD, 0xC4, 0x63, 0x5F, 0x48, 0xC9, 0x1D, 0x87, 0x32, 0x49, 0xE0, 0xE0, 0x60, 0xC3, 0x1D, 0x20, 0x2F, 0xF9, 0x4F, 0x22, 0x93, 0x1E, 0xAC, 0x70, 0x21, 0x77, 0x47, 0x9F, 0x91, 0x22, 0x93, 0xCC, 0x2A, 0x73, 0xC9, 0x44, 0x3F, 0xAE, 0xBF, 0xC6, 0x8E, 0x5D, 0xFA, 0x8B, 0x5D, 0x1C, 0x4D, 0xFE, 0x4A, 0xAF, 0xB0, 0x04, 0x80, 0xFB, 0xA3, 0x9E, 0xBF, 0x01, 0x24, 0xFB, 0x24, 0x9F, 0x29, 0x1C, 0x08, 0x00, 0x73, 0xDC, 0xF2, 0x9D, 0xC9, 0x11, 0x77, 0x0B, 0xA6, 0x90, 0xDD, 0x6B, 0x0A, 0xAB, 0x49, 0xE0, 0xC6, 0x49, 0xF6, 0xE6, 0x54, 0xC5, 0x42, 0x32, 0x27, 0xCD, 0x29, 0x83, 0xBC, 0xFE, 0x62, 0x62, 0x2C, 0x79, 0x65, 0xD9, 0xDA, 0x26, 0xF2, 0xE2, 0xF2, 0x93, 0xED, 0x41, 0xAE, 0x7E, 0x62, 0x47, 0x9E, 0x9B, 0xDC, 0x9A, 0x7B, 0xD2, 0xD8, 0xD4, 0xAE, 0xEC, 0xDE, 0x95, 0xE4, 0xCB, 0xB4, 0xCA, 0x22, 0x40, 0xEA, 0x5A, 0xC6, 0xD7, 0xD7, 0x13, 0x41, 0xAD, 0x2B, 0x7F, 0xAA, 0x48, 0x7A, 0x87, 0x3C, 0x3B, 0x4D, 0x9A, 0x0C, 0x2C, 0x6E, 0x4F, 0x4A, 0xDD, 0x79, 0x33, 0x8B, 0x04, 0x4A, 0x6B, 0xA4, 0x64, 0xC9, 0xB2, 0x1A, 0x23, 0x17, 0xF2, 0x7D, 0xA0, 0x9B, 0x2D, 0x59, 0x1E, 0x39, 0xAF, 0x23, 0xC8, 0xC2, 0xBD, 0xE7, 0xC8, 0x77, 0x03, 0xAF, 0x1A, 0x81, 0xEC, 0x55, 0x6C, 0x40, 0x16, 0x27, 0x72, 0xDD, 0x27, 0xED, 0xD8, 0xFC, 0x70, 0x36, 0xE7, 0x0E, 0x79, 0x65, 0x6F, 0xED, 0x24, 0x00, 0x58, 0x5B, 0x5C, 0x1E, 0x4A, 0x06, 0x74, 0x2E, 0xB5, 0x25, 0x2D, 0x03, 0x2A, 0x7E, 0x90, 0x0A, 0xCB, 0xBF, 0xFD, 0x25, 0x81, 0xFA, 0x54, 0x09, 0x03, 0x52, 0xDC, 0x95, 0xB5, 0xB0, 0x4E, 0x39, 0x6C, 0xE8, 0x6B, 0x36, 0xF6, 0x3D, 0x9B, 0xFA, 0x80, 0x3D, 0x5B, 0xC7, 0xBE, 0x05, 0xFB, 0x47, 0x0E, 0x90, 0xC8, 0xE6, 0xBC, 0x01, 0x34, 0xFF, 0x66, 0x6B, 0xBA, 0x92, 0x89, 0x21, 0xDC, 0x8E, 0x90, 0xD0, 0x6F, 0x97, 0x48, 0x9B, 0x8B, 0x3F, 0x26, 0x93, 0xED, 0xAE, 0x34, 0xF9, 0xFD, 0x67, 0x0E, 0x69, 0x7F, 0x9D, 0xB5, 0xA8, 0x60, 0x87, 0x49, 0xB2, 0x21, 0xA9, 0xEC, 0xFC, 0x4C, 0x76, 0xF3, 0x0F, 0xF6, 0xE0, 0x06, 0x36, 0x3F, 0x8B, 0x2D, 0xF9, 0xC4, 0xD6, 0x3E, 0x00, 0x24, 0xEF, 0x71, 0x7B, 0x24, 0xDE, 0xB2, 0xD3, 0x8B, 0xEA, 0xCD, 0x01, 0xC0, 0xB9, 0xAC, 0xD1, 0x8A, 0x54, 0x1B, 0xF7, 0xDF, 0x39, 0x48, 0x51, 0x8F, 0xD5, 0x7A, 0xCC, 0xDA, 0x04, 0xB0, 0x23, 0x0F, 0xB1, 0xC1, 0x60, 0x67, 0x0D, 0x61, 0x57, 0x49, 0xFD, 0x7B, 0x0E, 0x3A, 0x3E, 0x97, 0x2D, 0x18, 0xC2, 0xBE, 0x9E, 0xC3, 0x7E, 0xF6, 0x63, 0x2B, 0xDF, 0xD1, 0xC7, 0x5E, 0xCA, 0x40, 0x7B, 0x31, 0x5F, 0xE8, 0x86, 0xFD, 0x93, 0x83, 0xBA, 0xBB, 0xB0, 0x66, 0x49, 0xAC, 0xAD, 0x0E, 0xDB, 0x5F, 0x92, 0x5B, 0x37, 0xEE, 0x35, 0x29, 0xD5, 0x18, 0xDA, 0x48, 0x0E, 0x5C, 0x12, 0x0C, 0x32, 0x18, 0x01, 0x8D, 0xE4, 0xBA, 0x25, 0x2E, 0x45, 0xE4, 0x01, 0x3B, 0xDB, 0x5B, 0x64, 0xC1, 0x64, 0xFD, 0x77, 0x64, 0xF9, 0xEF, 0x8E, 0x0A, 0xE4, 0x9F, 0xB7, 0xCA, 0x92, 0xA4, 0x98, 0xE7, 0xAE, 0xB1, 0xF4, 0xD7, 0x0E, 0xFA, 0x76, 0xE0, 0x56, 0x99, 0x26, 0x00, 0x1D, 0x4D, 0xC4, 0xDA, 0xEE, 0x76, 0x40, 0x47, 0x64, 0x6B, 0x9D, 0xAF, 0x80, 0xF1, 0x34, 0xAE, 0x6F, 0xD5, 0x42, 0x7F, 0x7F, 0x07, 0x70, 0xF6, 0x6F, 0x6D, 0xC7, 0x15, 0x36, 0x74, 0x27, 0xE9, 0x1C, 0x3D, 0x61, 0x32, 0x19, 0x64, 0x34, 0xE6, 0x23, 0x99, 0xF8, 0xD7, 0xB9, 0x94, 0x3C, 0x3E, 0xDE, 0xDA, 0x84, 0x7C, 0x52, 0xA7, 0x7D, 0x89, 0xAC, 0x59, 0xD6, 0x7E, 0xDA, 0xBF, 0xD7, 0x07, 0xEA, 0x77, 0x91, 0x74, 0x38, 0x4D, 0x06, 0x48, 0x9B, 0x3A, 0x40, 0xCE, 0x45, 0xB4, 0x23, 0x0F, 0xA0, 0xDF, 0xD2, 0xD4, 0x49, 0x07, 0xF4, 0x77, 0xB4, 0xE6, 0xC4, 0x53, 0x22, 0x7F, 0xB4, 0x03, 0x1C, 0x56, 0xB7, 0xE6, 0xC3, 0xF6, 0x6C, 0x98, 0x03, 0xE9, 0xEC, 0x1E, 0x16, 0x41, 0x8E, 0xAE, 0xF1, 0xD7, 0x20, 0x53, 0xE3, 0x1D, 0x7F, 0x90, 0x17, 0xA3, 0x8D, 0x3E, 0x93, 0x1F, 0x0B, 0xD5, 0x0D, 0xB8, 0x96, 0xFC, 0xB4, 0x16, 0x6B, 0x12, 0xF8, 0x50, 0xC7, 0xBE, 0x6D, 0xCB, 0x8A, 0x76, 0x0C, 0x07, 0xC8, 0xBE, 0x23, 0xD9, 0xDE, 0x9A, 0x80, 0x72, 0x0C, 0xAF, 0xBB, 0x74, 0x5B, 0x21, 0xDA, 0x33, 0x00, 0x30, 0x0A, 0xE2, 0xF6, 0xF4, 0x7E, 0xC1, 0xF9, 0xC3, 0x69, 0x3B, 0xB7, 0x23, 0x64, 0x3D, 0xE9, 0x19, 0x3B, 0x7C, 0x2F, 0xB9, 0xFC, 0xBD, 0xF5, 0x15, 0xF2, 0xE8, 0xD1, 0x6E, 0xC6, 0xE4, 0x13, 0x69, 0xC5, 0xF5, 0xE4, 0x9F, 0x05, 0x6D, 0xD0, 0x30, 0x89, 0xEB, 0xBD, 0xB4, 0x61, 0xF3, 0xCA, 0xD8, 0x1C, 0x3B, 0x92, 0x0E, 0x97, 0x31, 0x00, 0xD9, 0xEF, 0x0D, 0xEB, 0x92, 0xC3, 0xF6, 0x31, 0x07, 0x34, 0xC4, 0xFB, 0x62, 0xF4, 0x06, 0xD0, 0x39, 0x20, 0xDA, 0xB3, 0x02, 0xE8, 0xE1, 0x21, 0x7A, 0x6B, 0x35, 0x60, 0x7D, 0x90, 0xBE, 0x57, 0x27, 0xAE, 0x5F, 0x28, 0xE9, 0x7B, 0xDB, 0x42, 0x97, 0xDC, 0x16, 0xDF, 0xDE, 0xBF, 0xBA, 0x1C, 0x38, 0x5B, 0x06, 0xBC, 0x5C, 0x0E, 0x3C, 0x6D, 0x10, 0x07, 0xED, 0x4B, 0x39, 0x05, 0xE4, 0xEB, 0x80, 0xEA, 0x9D, 0x3E, 0x77, 0x13, 0xE4, 0xCD, 0xF4, 0x1A, 0x52, 0xF6, 0xD2, 0xC1, 0xB6, 0xA4, 0x82, 0xAA, 0xD8, 0xF7, 0xB3, 0x91, 0xEB, 0xBA, 0x29, 0x82, 0x4D, 0x02, 0x6B, 0xC7, 0xDA, 0x95, 0x02, 0x6A, 0xC7, 0x44, 0x3B, 0x02, 0x01, 0x3D, 0x91, 0xA3, 0xB5, 0x2D, 0x01, 0x03, 0x3A, 0xEF, 0xE8, 0x71, 0x55, 0xAF, 0x47, 0xC5, 0x79, 0x20, 0xA4, 0x06, 0xC8, 0xD5, 0x02, 0x56, 0xB9, 0x02, 0xA7, 0x3C, 0x80, 0x13, 0x0D, 0x40, 0x9A, 0x29, 0x50, 0x3C, 0x0C, 0x38, 0xAC, 0x0D, 0xFC, 0xCA, 0x03, 0xF6, 0xF6, 0xE0, 0x7D, 0x62, 0xEB, 0xA7, 0x90, 0xAA, 0x5B, 0x96, 0xB7, 0x25, 0x35, 0x06, 0x2E, 0x7A, 0x4D, 0x76, 0xD2, 0x11, 0xB9, 0x67, 0x04, 0xC0, 0xCF, 0x8E, 0xD8, 0x00, 0x55, 0xD6, 0x47, 0x99, 0x1D, 0xD1, 0x9F, 0x75, 0xBE, 0x48, 0x36, 0x2F, 0xD7, 0x3C, 0x0C, 0x28, 0x29, 0x9C, 0x6B, 0x00, 0x7A, 0xEE, 0x00, 0xD6, 0x2A, 0x03, 0xC3, 0xAA, 0x81, 0x68, 0x0B, 0x60, 0xB6, 0x16, 0x10, 0xD5, 0x02, 0xA4, 0xBF, 0x05, 0x22, 0x7B, 0x02, 0x2F, 0xCB, 0x85, 0x3F, 0xE9, 0x7B, 0x00, 0x7A, 0x0A, 0x29, 0xCE, 0x75, 0x7F, 0x2F, 0x53, 0xD2, 0xD0, 0xD7, 0xCD, 0x9C, 0x34, 0x9A, 0x36, 0xFC, 0x16, 0x48, 0xD1, 0xCF, 0x63, 0x7B, 0x72, 0x9D, 0xC5, 0xCA, 0xEC, 0xDC, 0xBF, 0xEC, 0xE4, 0x52, 0xF2, 0xDB, 0x56, 0xEF, 0x0C, 0xF2, 0xDE, 0xE8, 0xBE, 0xBC, 0x1F, 0x23, 0x52, 0x6F, 0x16, 0x39, 0xEE, 0x27, 0xA0, 0x3A, 0x42, 0x72, 0x67, 0x40, 0x47, 0xC0, 0xA9, 0x52, 0xDE, 0xC2, 0x67, 0x39, 0x30, 0x7D, 0x40, 0xFB, 0x09, 0x6E, 0x1D, 0x81, 0xC3, 0xCB, 0xD4, 0x9F, 0x0D, 0xED, 0x00, 0xBC, 0x54, 0xE9, 0x38, 0xDB, 0xF9, 0x32, 0xD0, 0x70, 0xBD, 0xB3, 0xAC, 0x8E, 0x33, 0xE8, 0x9A, 0xAC, 0x06, 0x48, 0x87, 0xF6, 0x6D, 0xAE, 0x92, 0x76, 0x8D, 0x0A, 0x7E, 0x64, 0x9F, 0x1C, 0xB1, 0x1F, 0x5B, 0x0B, 0xBC, 0x2B, 0x51, 0x82, 0xE5, 0xFD, 0xE3, 0xE5, 0x6E, 0x8B, 0x12, 0xC8, 0x9B, 0x4B, 0xC2, 0xDF, 0x90, 0x7B, 0xBE, 0xBB, 0x9D, 0x20, 0x27, 0xA5, 0xD8, 0x98, 0x93, 0xC3, 0xF5, 0x2C, 0x0A, 0x48, 0x00, 0xF4, 0xD9, 0x18, 0x40, 0xFE, 0xF7, 0x10, 0xF4, 0x33, 0x02, 0xD4, 0x4F, 0x6C, 0x76, 0xB0, 0xB5, 0x04, 0x34, 0xAF, 0xDF, 0xFC, 0xD2, 0x2B, 0x12, 0xE8, 0x6A, 0xF4, 0xFD, 0xB6, 0x49, 0x2C, 0xA0, 0x6B, 0x2B, 0xFA, 0xD6, 0x3C, 0x61, 0xB3, 0xC8, 0x1D, 0xB4, 0x3F, 0x68, 0xB0, 0xF8, 0xFC, 0x0C, 0xD0, 0x35, 0x51, 0xF8, 0x49, 0xAC, 0xC6, 0x5B, 0x71, 0xFD, 0xCC, 0x0A, 0xF2, 0xEB, 0xE0, 0xD4, 0x14, 0x32, 0x7F, 0xD4, 0xA6, 0x67, 0xE4, 0x9E, 0x1B, 0xF3, 0x1C, 0x04, 0xC7, 0xA7, 0xDD, 0x0C, 0x0C, 0x01, 0x24, 0x16, 0x8F, 0xCC, 0xF3, 0x58, 0x00, 0x00, 0xD6, 0xBF, 0x47, 0x6E, 0x21, 0x01, 0xE7, 0x29, 0x80, 0x51, 0x32, 0x30, 0x4C, 0x61, 0x78, 0x15, 0xED, 0xC8, 0x1C, 0xBE, 0x67, 0xF5, 0xB7, 0xF6, 0xA3, 0x00, 0xCF, 0x9A, 0x9C, 0x9D, 0xED, 0x54, 0x00, 0x8F, 0xA2, 0xEA, 0x75, 0x4A, 0x1F, 0x81, 0x41, 0x9E, 0xA2, 0x3F, 0x5A, 0x00, 0xF6, 0x79, 0x7C, 0xAD, 0x59, 0x9F, 0x11, 0xEB, 0x1E, 0x8E, 0x40, 0x9F, 0xD1, 0xE2, 0x7E, 0x4E, 0xB4, 0xE9, 0x6A, 0x31, 0xB7, 0x23, 0xAF, 0x81, 0x7C, 0x38, 0x94, 0x9F, 0x87, 0x1D, 0x4A, 0xD9, 0x75, 0x17, 0x90, 0xBC, 0xBC, 0xE0, 0x43, 0xDC, 0x09, 0x00, 0xF0, 0xD5, 0x8C, 0x89, 0x20, 0xAD, 0x22, 0x96, 0x59, 0x92, 0xAA, 0x3F, 0x66, 0xED, 0x27, 0x81, 0xC9, 0x7A, 0x32, 0xEA, 0x12, 0x26, 0xC0, 0x8C, 0x76, 0xFD, 0xC2, 0x00, 0x20, 0x22, 0x6F, 0xCE, 0x24, 0x72, 0xBA, 0xD6, 0x89, 0x43, 0xE4, 0xCC, 0xEE, 0x15, 0x03, 0xC9, 0x69, 0xDD, 0xB8, 0xFE, 0xA8, 0x1F, 0xEC, 0x20, 0x19, 0xD6, 0xC5, 0x95, 0x6C, 0x51, 0x7E, 0x2C, 0x0D, 0x00, 0xE5, 0xBB, 0x8B, 0xF6, 0x91, 0xD9, 0x2E, 0xE7, 0x07, 0x93, 0x31, 0x8F, 0x0E, 0x6B, 0x90, 0x63, 0xAE, 0x1D, 0x7E, 0x45, 0x5A, 0xBF, 0x4E, 0x1F, 0x4C, 0x2A, 0xE6, 0xA5, 0xBC, 0x24, 0x81, 0xC4, 0x2B, 0x72, 0x93, 0xC9, 0x04, 0x1B, 0xF3, 0xC7, 0x20, 0xDF, 0x7A, 0xA9, 0x90, 0x1B, 0x13, 0x22, 0x07, 0x82, 0x34, 0x4C, 0xAE, 0x24, 0xD7, 0x98, 0xDD, 0x2D, 0x27, 0xD7, 0x75, 0xE1, 0xBA, 0x8B, 0x16, 0xB2, 0xE1, 0x63, 0xD9, 0x49, 0x6D, 0xC9, 0x4F, 0x93, 0x4A, 0x0E, 0x00, 0x40, 0xEE, 0xCA, 0xC7, 0x46, 0xE4, 0x36, 0x8F, 0x6B, 0xBF, 0xC9, 0xD0, 0x41, 0x97, 0xB2, 0xC8, 0xBE, 0xEE, 0x97, 0x73, 0x49, 0xB5, 0x5E, 0xD7, 0xE6, 0x93, 0xC0, 0x45, 0x53, 0xF6, 0x4C, 0x9F, 0xCE, 0xD3, 0xC8, 0xAC, 0x4D, 0x83, 0x3A, 0x93, 0xA7, 0xFB, 0x8D, 0x4D, 0x20, 0x4F, 0x4A, 0x2F, 0x78, 0xCE, 0xEB, 0x3D, 0x69, 0xD3, 0xC8, 0xE3, 0x8B, 0x73, 0x36, 0x83, 0x9C, 0xC3, 0x75, 0x0F, 0x94, 0xB2, 0xEB, 0xDF, 0xB2, 0xEB, 0x0E, 0x92, 0xF7, 0x2F, 0x7F, 0x08, 0x01, 0x80, 0x54, 0xF3, 0xA7, 0xED, 0xC8, 0x99, 0x3B, 0xEF, 0xB5, 0x90, 0xAE, 0x53, 0xEE, 0x47, 0x90, 0x3A, 0x0F, 0x1E, 0xA5, 0x92, 0xC0, 0xE3, 0x4A, 0xF6, 0xC9, 0xD5, 0x8E, 0x1B, 0xC8, 0xA7, 0xE3, 0xAD, 0xAB, 0xC8, 0xE7, 0xAB, 0x3C, 0xBF, 0x90, 0xCF, 0xAE, 0xCD, 0x3C, 0x08, 0x72, 0xCA, 0xB6, 0x3F, 0x20, 0x27, 0x64, 0x37, 0x91, 0x8F, 0x27, 0xDD, 0x59, 0x4B, 0x3E, 0x7C, 0xD5, 0x3C, 0x86, 0xBC, 0xD3, 0xC0, 0xF5, 0x4F, 0xBD, 0x62, 0x4F, 0x6E, 0x24, 0x4F, 0x77, 0xAC, 0xBC, 0x06, 0x00, 0x8B, 0xCA, 0x5E, 0xF7, 0x27, 0xDD, 0xDC, 0x8B, 0xF5, 0x48, 0x03, 0xDB, 0x37, 0x5B, 0x48, 0x89, 0xCA, 0x8A, 0x8F, 0x24, 0xF0, 0x3B, 0x5B, 0xAE, 0x75, 0x26, 0x32, 0x59, 0xC8, 0x8E, 0x08, 0x67, 0x27, 0xB8, 0xB2, 0xB1, 0xCB, 0xD9, 0x83, 0x89, 0x6C, 0x56, 0x21, 0xFB, 0x52, 0x9F, 0xFD, 0xA1, 0xC5, 0x8A, 0x5C, 0xDC, 0x0D, 0x28, 0xBE, 0xC1, 0xED, 0x78, 0xF1, 0x97, 0x5C, 0x6F, 0x58, 0x75, 0x00, 0x00, 0xFC, 0x86, 0x7C, 0x1A, 0x4A, 0x9A, 0x5F, 0xFE, 0x9E, 0x42, 0x2A, 0xFA, 0xD7, 0x97, 0x08, 0x78, 0x1D, 0xC8, 0x93, 0xED, 0x32, 0x93, 0xB5, 0x2D, 0x67, 0x3D, 0x9F, 0xB0, 0xE3, 0xEE, 0xB1, 0x0B, 0xCA, 0xD8, 0x2D, 0x36, 0x6C, 0xAA, 0x12, 0x7B, 0x5E, 0x8E, 0x7D, 0xA1, 0xC7, 0x7E, 0xA7, 0xCC, 0x20, 0xE4, 0x76, 0x90, 0x12, 0x29, 0x13, 0xD2, 0x7E, 0x5D, 0x03, 0x00, 0xEB, 0x93, 0xF5, 0xFE, 0x64, 0xBB, 0xB4, 0x7F, 0xF2, 0x8F, 0x74, 0x3C, 0xAB, 0x3E, 0x9C, 0xB5, 0x94, 0x65, 0x5D, 0x8D, 0x58, 0x9F, 0x24, 0x36, 0x18, 0x6C, 0xE4, 0x36, 0x76, 0x8D, 0x1C, 0x9B, 0xD4, 0x85, 0x3D, 0x3A, 0x90, 0xBD, 0x79, 0x89, 0x7D, 0x9E, 0xCB, 0x7E, 0xDD, 0xCE, 0x56, 0x45, 0x83, 0xC6, 0xB8, 0x40, 0x40, 0x71, 0x86, 0x78, 0x06, 0xE0, 0x0A, 0x68, 0x8A, 0x6B, 0x48, 0x6B, 0x19, 0xA0, 0xC5, 0xFB, 0xA3, 0xC5, 0x7C, 0xCB, 0xF6, 0x30, 0x16, 0xFF, 0x6E, 0x03, 0xD8, 0xDB, 0x70, 0x2B, 0xBD, 0x75, 0xD9, 0xF1, 0x36, 0xA4, 0xE3, 0x15, 0xBF, 0xD5, 0x64, 0x30, 0x86, 0xAC, 0x23, 0x37, 0x6F, 0xB5, 0xB5, 0x21, 0x8F, 0x15, 0x1A, 0xEC, 0x21, 0x6F, 0x2B, 0x76, 0xCC, 0x25, 0xCB, 0x83, 0x95, 0xD2, 0xC9, 0x5F, 0x77, 0x65, 0x17, 0xB4, 0xE6, 0x9F, 0xD3, 0x7F, 0xEF, 0x91, 0x74, 0x58, 0x8D, 0x03, 0xF0, 0x4C, 0xE4, 0x8E, 0x53, 0x80, 0xCA, 0x72, 0x51, 0xEF, 0x04, 0xD0, 0x59, 0xF4, 0x21, 0x9D, 0x48, 0x40, 0x7B, 0xBA, 0x68, 0xC7, 0x04, 0xC0, 0xF0, 0xA8, 0xF8, 0xF7, 0x7D, 0x80, 0x55, 0x3C, 0xD7, 0xF7, 0xF1, 0x64, 0xC3, 0xEE, 0x90, 0x36, 0x87, 0x02, 0x9F, 0x92, 0xFE, 0xCB, 0x87, 0x4D, 0x20, 0x93, 0xE2, 0x7B, 0x07, 0x93, 0x59, 0x4B, 0x75, 0x6C, 0xC8, 0x67, 0xE6, 0xED, 0xE3, 0xC9, 0x6F, 0x3F, 0x14, 0x46, 0x73, 0x4D, 0xA9, 0x94, 0x9F, 0xB3, 0x48, 0xA0, 0xEA, 0x3B, 0x2B, 0xF2, 0x86, 0x3B, 0x40, 0x9A, 0x5F, 0x06, 0xDA, 0x88, 0xFC, 0xD6, 0xF1, 0x1E, 0xD0, 0x29, 0x4B, 0xF4, 0x86, 0x42, 0xA0, 0xCB, 0x3C, 0xD1, 0x8E, 0x12, 0xA0, 0x9B, 0xAB, 0x68, 0x87, 0x3B, 0x60, 0x9E, 0xCD, 0xF5, 0x3D, 0x35, 0xD9, 0xD0, 0x5C, 0xD2, 0x76, 0x6F, 0x90, 0x39, 0x39, 0xF1, 0xC5, 0x20, 0x5F, 0x32, 0xF9, 0x59, 0x8F, 0xA7, 0x64, 0x5E, 0xB1, 0xA6, 0x0D, 0xF9, 0xC9, 0x44, 0x81, 0xC4, 0xDF, 0xC6, 0x36, 0x5B, 0x1B, 0x34, 0xC0, 0x39, 0x24, 0x96, 0x7D, 0x22, 0x47, 0xD2, 0xD1, 0xE7, 0x2E, 0x40, 0xF6, 0x3E, 0xCF, 0xF6, 0x88, 0x06, 0xE4, 0x45, 0x9E, 0x51, 0x6F, 0x00, 0x3A, 0xB7, 0x15, 0xF3, 0xBC, 0x16, 0xD0, 0xD5, 0x52, 0xB4, 0x43, 0x07, 0x30, 0xB8, 0x29, 0xDE, 0x2F, 0x59, 0xC0, 0x7A, 0x10, 0x7D, 0xAF, 0xEE, 0x76, 0xE7, 0xBE, 0xA4, 0x77, 0xB1, 0xE5, 0x52, 0x32, 0x56, 0x5A, 0xFF, 0x3E, 0x79, 0xC2, 0x4D, 0xA5, 0x03, 0xF9, 0xB8, 0x1E, 0xA0, 0xA7, 0xC3, 0xB5, 0xCB, 0x81, 0xAF, 0x29, 0x5C, 0xEF, 0x45, 0x07, 0xF6, 0x7C, 0x17, 0x36, 0x3B, 0x81, 0x94, 0xD8, 0x28, 0xF2, 0x58, 0x28, 0xD7, 0xB7, 0x9E, 0xCB, 0xDA, 0x3E, 0x63, 0xCD, 0xD7, 0x03, 0xCA, 0xCD, 0xE2, 0xFD, 0xD9, 0x0B, 0x68, 0x89, 0xF3, 0xA9, 0x75, 0x45, 0x28, 0x2D, 0xE6, 0x02, 0x5B, 0x80, 0x7E, 0x1F, 0x0F, 0xE8, 0x96, 0x62, 0xDC, 0x51, 0x64, 0x89, 0xAF, 0xC1, 0x41, 0xC0, 0xB7, 0x1D, 0xC0, 0xEA, 0xED, 0xC0, 0xE3, 0x60, 0xE0, 0x68, 0x21, 0x70, 0x2B, 0x1B, 0xB8, 0xAB, 0x0B, 0xE4, 0xE6, 0x02, 0xDF, 0xD4, 0x81, 0x8B, 0xA3, 0xB9, 0x6E, 0xC6, 0x31, 0x52, 0x72, 0x54, 0xA2, 0x02, 0xD9, 0xE6, 0xCE, 0xD6, 0x3F, 0xA4, 0x6C, 0x1F, 0xB1, 0x1E, 0xB5, 0x1F, 0x7C, 0x15, 0x0C, 0x62, 0x5D, 0x46, 0xB3, 0xFD, 0x4A, 0x59, 0x07, 0x35, 0x56, 0x53, 0xD8, 0x8E, 0x9F, 0x72, 0x43, 0x3D, 0xA6, 0x26, 0x08, 0xE8, 0x79, 0x1B, 0xB8, 0x6C, 0x02, 0xB8, 0x2D, 0x02, 0x0E, 0x24, 0x03, 0xD3, 0x5C, 0x81, 0x7D, 0x51, 0xC0, 0xCE, 0x58, 0x20, 0x51, 0x0E, 0xB8, 0xE5, 0x09, 0x6C, 0x37, 0x00, 0xBE, 0xC6, 0x01, 0x9B, 0x22, 0x41, 0xFD, 0x22, 0x3E, 0x7A, 0x06, 0xA9, 0xB8, 0x7E, 0x72, 0x19, 0xD9, 0x6E, 0x5D, 0xD8, 0x5F, 0xB2, 0xFD, 0x27, 0x91, 0x7F, 0xFA, 0x81, 0xAF, 0xC2, 0x13, 0xAC, 0xD7, 0x54, 0x76, 0x98, 0x39, 0xEB, 0x90, 0x49, 0xFE, 0xA9, 0xD7, 0x2B, 0x21, 0x73, 0xAF, 0x01, 0x00, 0x90, 0x94, 0x00, 0x68, 0x4F, 0x01, 0x22, 0x8F, 0x02, 0x76, 0x39, 0xC0, 0x94, 0x3C, 0x20, 0xE0, 0x28, 0x30, 0x51, 0x0D, 0xD8, 0xB0, 0x14, 0x98, 0xB4, 0x0E, 0xB8, 0x7E, 0x1D, 0x08, 0x2E, 0x00, 0x2A, 0x03, 0x01, 0xBF, 0x65, 0xA0, 0x9F, 0x5B, 0xAA, 0x6F, 0x1D, 0xA9, 0xDE, 0xD3, 0xF1, 0x2B, 0xA9, 0x51, 0x60, 0x1F, 0x44, 0x76, 0x12, 0xF9, 0x3A, 0x2A, 0x81, 0xEB, 0xCD, 0x3B, 0xC6, 0x4E, 0xBB, 0x46, 0xB6, 0x98, 0xF8, 0x04, 0x90, 0x25, 0xEF, 0x06, 0xEB, 0x90, 0x57, 0x76, 0x5B, 0xC6, 0x91, 0xF1, 0x86, 0xDA, 0xAF, 0x48, 0xAF, 0x66, 0x40, 0x21, 0x0B, 0xF0, 0x1C, 0x06, 0xF4, 0x8E, 0x03, 0x86, 0x3D, 0x07, 0x46, 0x77, 0x03, 0x06, 0x52, 0x46, 0x4B, 0x96, 0x99, 0xD6, 0xF7, 0x20, 0x70, 0x65, 0xA4, 0x6C, 0x9E, 0xA3, 0x3E, 0xF0, 0xDD, 0x53, 0xF6, 0xA8, 0x01, 0xED, 0x1F, 0x7F, 0xD8, 0xF6, 0x07, 0xD7, 0xE8, 0x5E, 0xCA, 0x1A, 0xDA, 0x4A, 0x8C, 0x25, 0xBB, 0x89, 0xBC, 0x9F, 0x20, 0xC9, 0x5F, 0xDB, 0xF1, 0x9A, 0x6C, 0x88, 0x5C, 0x6F, 0x4F, 0x3E, 0xD7, 0x9F, 0x3D, 0x93, 0x3C, 0x2F, 0x37, 0x26, 0x9F, 0xDC, 0x14, 0xEC, 0x12, 0x4F, 0x8E, 0xDB, 0x6C, 0x79, 0x14, 0x26, 0x80, 0x23, 0x74, 0x78, 0xBE, 0x03, 0x00, 0xD8, 0x1D, 0x03, 0xE4, 0x3F, 0xD9, 0x4E, 0x30, 0xCB, 0x06, 0x54, 0x1C, 0x17, 0x98, 0x74, 0x37, 0x04, 0xBA, 0xE8, 0x9C, 0xB9, 0xA2, 0xB3, 0x1C, 0xD0, 0xB2, 0x28, 0xFB, 0xA6, 0x79, 0x0C, 0xE8, 0x74, 0xAE, 0xB1, 0x47, 0xBB, 0x61, 0x80, 0xE6, 0x08, 0x3E, 0xB7, 0x1A, 0xDF, 0x45, 0xFF, 0x90, 0x01, 0xD4, 0xC7, 0x88, 0x11, 0xFB, 0x8F, 0x58, 0x8D, 0x7F, 0xC8, 0xED, 0x38, 0x21, 0x4B, 0xBE, 0x7A, 0xB2, 0x33, 0x99, 0xBC, 0x54, 0x17, 0xF7, 0x8D, 0xDC, 0x6A, 0x36, 0x75, 0x24, 0x19, 0x7C, 0xCA, 0x2B, 0x08, 0x90, 0x54, 0x75, 0x76, 0xE9, 0xBF, 0x1C, 0x00, 0xF4, 0x3F, 0xF4, 0xED, 0x48, 0x02, 0x0E, 0x79, 0x40, 0x87, 0xD5, 0x80, 0xB3, 0x8E, 0x53, 0xA2, 0x4C, 0x1A, 0xD0, 0xCF, 0x72, 0x96, 0xBA, 0x44, 0x03, 0xE0, 0xA2, 0x72, 0xB4, 0x37, 0x40, 0x7B, 0xCF, 0xDE, 0x1D, 0x20, 0xED, 0x4D, 0xFF, 0x7C, 0x20, 0x0D, 0x2F, 0x70, 0x3B, 0x74, 0x47, 0xB7, 0x6A, 0xCE, 0xD7, 0xED, 0xA5, 0xFB, 0x00, 0xF0, 0xD3, 0xF9, 0x7A, 0x38, 0x99, 0x1F, 0x94, 0x56, 0x47, 0xEE, 0x2A, 0xDF, 0xE2, 0x45, 0x4E, 0xBD, 0xBD, 0xB0, 0x2F, 0xE9, 0x7A, 0x7A, 0xC6, 0x05, 0xB2, 0x5B, 0xFA, 0x0C, 0x57, 0x12, 0x4F, 0xC2, 0x86, 0x10, 0xC0, 0x98, 0xAE, 0x2A, 0x66, 0x64, 0x60, 0x91, 0xED, 0x38, 0xD2, 0xE7, 0x4C, 0x68, 0x29, 0xE9, 0xB7, 0x62, 0x77, 0x28, 0xE9, 0xAB, 0x54, 0x28, 0x4D, 0xFA, 0xD4, 0xD5, 0x2F, 0x24, 0x1D, 0x7B, 0x73, 0x7D, 0x0B, 0x0D, 0xD6, 0x7C, 0x05, 0x59, 0x73, 0xFB, 0x6E, 0x10, 0x00, 0xBC, 0xEC, 0x76, 0x5B, 0x92, 0x4C, 0x4F, 0x3B, 0xA9, 0x4B, 0xCE, 0x5B, 0xB1, 0x67, 0x24, 0x39, 0xB2, 0x29, 0x71, 0x12, 0x69, 0x78, 0x73, 0x87, 0x27, 0x09, 0xEC, 0x38, 0xCD, 0xAE, 0x7B, 0xA0, 0x6C, 0x41, 0xAE, 0xBA, 0x61, 0xF2, 0x99, 0x5C, 0xD9, 0x7B, 0x68, 0x2A, 0xB9, 0x60, 0xEC, 0xB4, 0x1F, 0xE4, 0xC2, 0xB3, 0xBB, 0x2E, 0x92, 0x73, 0x06, 0x5D, 0x8A, 0x20, 0xE7, 0x3D, 0x6D, 0x1C, 0x45, 0x46, 0xE4, 0x73, 0x7D, 0x77, 0x0F, 0x76, 0xE8, 0x33, 0xB2, 0xB8, 0xE1, 0x59, 0x18, 0x00, 0x5C, 0x78, 0x70, 0xB7, 0x96, 0x5C, 0x79, 0xE6, 0x6C, 0x77, 0x72, 0x74, 0xF5, 0xE9, 0x68, 0xD2, 0x72, 0xEC, 0xE9, 0x31, 0x64, 0x9B, 0x65, 0x59, 0x6F, 0x49, 0x20, 0x73, 0xB3, 0xD2, 0x62, 0xF2, 0xD8, 0xA2, 0x1E, 0xED, 0xC9, 0xF4, 0xB7, 0x83, 0x67, 0x93, 0x87, 0xDF, 0xFB, 0x07, 0x90, 0x07, 0xC3, 0xA6, 0x6D, 0x27, 0x0F, 0xAC, 0xDB, 0x79, 0x8B, 0x4C, 0x9C, 0x7F, 0xE6, 0x1E, 0xB9, 0xD3, 0xB5, 0x65, 0x3A, 0xB9, 0x6D, 0x55, 0x6B, 0x2E, 0xDB, 0xC5, 0xCE, 0x19, 0x43, 0xE6, 0x54, 0x94, 0x7C, 0xE2, 0x9F, 0xF2, 0x41, 0x47, 0x32, 0x64, 0x2C, 0xEF, 0x2A, 0xB6, 0xFB, 0x96, 0x9F, 0x41, 0xAA, 0x6A, 0x17, 0x6C, 0x26, 0x81, 0x3B, 0x66, 0x58, 0x4A, 0x3E, 0xE8, 0x4B, 0x69, 0x18, 0x28, 0xEA, 0x64, 0x33, 0x09, 0xE4, 0x22, 0xBF, 0x83, 0xE4, 0xFD, 0xC9, 0x33, 0x74, 0xC9, 0x7B, 0xB7, 0x37, 0x3E, 0x20, 0xEF, 0x9B, 0x64, 0x96, 0x93, 0xB7, 0x9E, 0x5E, 0x0B, 0x06, 0xD9, 0xF8, 0xEB, 0x3B, 0x79, 0x85, 0x73, 0x07, 0xD2, 0x47, 0xB0, 0xBB, 0xA6, 0x90, 0x87, 0xEA, 0x3E, 0x0C, 0x00, 0x80, 0x59, 0x6D, 0x5E, 0x8C, 0x25, 0x07, 0x29, 0x3F, 0xBD, 0x4F, 0x76, 0x7D, 0xFF, 0x72, 0x2E, 0x09, 0x94, 0xEE, 0x61, 0xAB, 0xFC, 0x34, 0x07, 0x93, 0xCD, 0x15, 0x3D, 0x5B, 0xE7, 0x7F, 0x6F, 0x4D, 0x76, 0xFC, 0x75, 0x76, 0x69, 0x18, 0xBB, 0xAF, 0x1D, 0x7B, 0x3A, 0x94, 0x7D, 0x34, 0x9B, 0xAD, 0xBC, 0x41, 0x36, 0x1C, 0xE4, 0xFA, 0x8F, 0xDF, 0xB1, 0x79, 0x72, 0xE4, 0xD2, 0xE5, 0xB4, 0x4F, 0x0A, 0x18, 0xE1, 0x5D, 0xF6, 0x94, 0x34, 0x88, 0xFF, 0xBC, 0x81, 0x6C, 0xB3, 0xEA, 0x8F, 0x90, 0xBF, 0x5F, 0xC5, 0x85, 0xED, 0x65, 0xCF, 0x0E, 0x0D, 0x63, 0xFD, 0x0F, 0xB3, 0x63, 0xDB, 0xB0, 0x0B, 0xBF, 0xB3, 0x5B, 0xB5, 0xD8, 0x94, 0x2E, 0xEC, 0x99, 0x7A, 0xF6, 0xD1, 0x25, 0xF6, 0xF3, 0x3D, 0x01, 0xE7, 0xB2, 0x55, 0xC0, 0x6F, 0x5A, 0x3B, 0x80, 0xDF, 0x98, 0x1F, 0x4B, 0x01, 0xC0, 0x7C, 0xE1, 0xEF, 0x7D, 0xA4, 0x92, 0xD9, 0x3F, 0x39, 0x48, 0xA9, 0x9A, 0xD5, 0x05, 0x6B, 0x17, 0xC9, 0xBA, 0x29, 0xB1, 0xC1, 0xF8, 0x77, 0xE7, 0x5F, 0x66, 0xD7, 0x8D, 0x64, 0x93, 0x0E, 0xB3, 0x47, 0xBA, 0xB0, 0x17, 0x9F, 0xB3, 0x8F, 0x2D, 0xD9, 0x4F, 0x2A, 0xEC, 0x8F, 0xE7, 0xA0, 0xB1, 0xCC, 0x1C, 0x90, 0xEB, 0x2C, 0x7E, 0x6A, 0x2F, 0x40, 0xC5, 0x4B, 0x3C, 0x13, 0x88, 0x07, 0xD4, 0x44, 0x5E, 0xE8, 0xB4, 0x19, 0xE8, 0xB4, 0x59, 0xCC, 0xB7, 0x6A, 0x80, 0xB6, 0x1A, 0xFD, 0xD5, 0x4D, 0xC0, 0x82, 0xD6, 0x53, 0xD0, 0x2E, 0xDF, 0xE1, 0x3A, 0xA9, 0x5B, 0xDA, 0xBF, 0x94, 0x74, 0xB3, 0xB4, 0x7B, 0x4E, 0x86, 0x59, 0xD9, 0x65, 0x90, 0xF1, 0x71, 0xC6, 0x72, 0x64, 0xC6, 0x74, 0x1D, 0x7B, 0xF2, 0xF6, 0x36, 0x25, 0x03, 0xB2, 0xB4, 0x5E, 0xC6, 0x97, 0xFC, 0x19, 0x20, 0x95, 0xD5, 0x14, 0x02, 0x9A, 0x6F, 0x2A, 0x7F, 0x58, 0x90, 0x32, 0xC1, 0x22, 0xF5, 0xB6, 0xB6, 0xB6, 0x63, 0x12, 0xA0, 0x7C, 0x58, 0xB4, 0xA7, 0x07, 0xA0, 0xD2, 0xC8, 0xF3, 0xBE, 0x7A, 0x83, 0x98, 0x67, 0x25, 0x81, 0xCE, 0xA2, 0x9E, 0xF2, 0x77, 0xC0, 0x4C, 0x99, 0x5E, 0x47, 0xF6, 0x88, 0xD3, 0x03, 0x52, 0x2B, 0xA0, 0x5F, 0x3A, 0xE9, 0x59, 0x64, 0xA3, 0x41, 0x4E, 0x3C, 0x60, 0xBF, 0x9A, 0xDC, 0xBB, 0x5C, 0xDF, 0x8A, 0xBC, 0xD8, 0x45, 0x4D, 0x9A, 0x7C, 0xDA, 0xDC, 0xE6, 0x16, 0xF9, 0x2D, 0x58, 0x5A, 0x89, 0x14, 0xE7, 0x23, 0xB9, 0x2A, 0x90, 0x6C, 0xE3, 0x5C, 0x26, 0x47, 0xCA, 0xC7, 0x89, 0x5C, 0xE8, 0x05, 0x1E, 0xEB, 0xBB, 0x02, 0x52, 0xA7, 0xC4, 0x1C, 0xB8, 0x1F, 0x50, 0x51, 0x14, 0xF3, 0xF9, 0x48, 0x40, 0x75, 0xA4, 0x78, 0x5F, 0xD4, 0x81, 0x8E, 0xC5, 0x22, 0x9F, 0x9D, 0x03, 0x74, 0xF9, 0xF9, 0x1C, 0xFA, 0x76, 0x21, 0xBB, 0xC6, 0x3B, 0x77, 0x23, 0x3D, 0xAF, 0xDA, 0x7D, 0x26, 0x17, 0xC5, 0xF7, 0xDC, 0x4F, 0x26, 0x7F, 0xD7, 0x9B, 0x49, 0xE6, 0x2F, 0x53, 0xF4, 0x20, 0x2B, 0x94, 0xA4, 0xBF, 0x90, 0x7F, 0x67, 0x4B, 0x19, 0x57, 0xDF, 0x04, 0xD5, 0x4F, 0x7A, 0xA1, 0x4D, 0xCA, 0xE5, 0xE4, 0xAC, 0x27, 0xA5, 0x44, 0xEE, 0x33, 0x57, 0x05, 0xAF, 0x8F, 0x19, 0xB3, 0x86, 0x9A, 0x80, 0xD4, 0x6C, 0x71, 0x1E, 0x36, 0x01, 0x2A, 0x89, 0xE2, 0x3C, 0x05, 0x01, 0x6A, 0x41, 0x62, 0xCD, 0x40, 0x19, 0xE8, 0xF4, 0x81, 0xDB, 0xD1, 0xFB, 0x20, 0xA9, 0x75, 0x98, 0xCF, 0x93, 0xFB, 0x20, 0xA3, 0x21, 0x64, 0x4C, 0x42, 0xA7, 0x7C, 0xF2, 0x94, 0x2F, 0x8E, 0xFE, 0xC8, 0x05, 0xEE, 0x17, 0x03, 0x1F, 0xAF, 0x02, 0x9F, 0x9F, 0x00, 0xAF, 0x5D, 0x38, 0x7F, 0x14, 0x9D, 0x27, 0x65, 0xFB, 0x9F, 0xF4, 0x22, 0x51, 0x9A, 0x6A, 0x00, 0x72, 0xAA, 0xC8, 0x63, 0xE9, 0x5C, 0xDF, 0xEC, 0x07, 0x6B, 0x6E, 0xC1, 0x9A, 0x3A, 0x01, 0x92, 0x8B, 0xC5, 0xF9, 0xD8, 0x09, 0xA8, 0xD6, 0x88, 0xA7, 0xD8, 0xD9, 0x40, 0x87, 0xF3, 0xF4, 0x5A, 0x52, 0x81, 0x5D, 0xC6, 0x90, 0x3D, 0xCE, 0xA8, 0xB6, 0x69, 0xAA, 0x03, 0x02, 0x57, 0x02, 0x4F, 0xAD, 0x81, 0x45, 0xAA, 0xC0, 0xED, 0x3D, 0xC0, 0xC1, 0xA9, 0xC0, 0x0D, 0x2D, 0x20, 0xDF, 0x11, 0xB8, 0xD4, 0x03, 0x78, 0x7F, 0x13, 0x38, 0x31, 0x18, 0x68, 0xF1, 0x07, 0x92, 0x39, 0x97, 0x61, 0x75, 0x25, 0xC8, 0xD5, 0xD1, 0x37, 0x49, 0xC9, 0xF6, 0x22, 0xF7, 0x38, 0x73, 0x5D, 0x67, 0x0B, 0xD6, 0x61, 0x0B, 0xDB, 0x5B, 0x97, 0x35, 0x6D, 0x66, 0xBB, 0x0E, 0x21, 0x9B, 0x07, 0x03, 0x0A, 0x03, 0x81, 0x67, 0xA9, 0x80, 0xF1, 0x64, 0x20, 0xEB, 0x03, 0x30, 0x34, 0x08, 0x48, 0x39, 0x0B, 0x84, 0x47, 0x00, 0x49, 0xDB, 0x81, 0x2D, 0x1D, 0x80, 0x6D, 0xA7, 0x80, 0xF3, 0x15, 0xC0, 0xBA, 0x44, 0xA0, 0xEC, 0x38, 0xB0, 0xC4, 0x1B, 0x68, 0x39, 0x06, 0x84, 0xCE, 0xE3, 0xE7, 0x72, 0xBE, 0xEE, 0xA4, 0xCC, 0x3B, 0x8F, 0xD1, 0xA4, 0xEC, 0x28, 0x91, 0x7F, 0x1C, 0xB8, 0x8E, 0xC7, 0x0B, 0x76, 0xD8, 0x65, 0xD6, 0xB9, 0x80, 0x35, 0x0B, 0x23, 0x5F, 0x64, 0xAA, 0x8D, 0x21, 0xCF, 0x9C, 0x01, 0x00, 0x60, 0x57, 0x15, 0xA0, 0x99, 0x09, 0xCC, 0x1E, 0x09, 0x58, 0x2D, 0x01, 0x42, 0x67, 0x03, 0xEE, 0xEF, 0x80, 0xC0, 0x03, 0xC0, 0xBC, 0x51, 0x40, 0xC0, 0x49, 0xE0, 0x44, 0x2E, 0xE0, 0xBD, 0x17, 0x78, 0xF1, 0x00, 0x70, 0xF1, 0x04, 0x1A, 0x25, 0x00, 0x8B, 0x7B, 0xA0, 0xBA, 0xC3, 0x7A, 0xD4, 0x93, 0x72, 0x1B, 0x8D, 0x1B, 0x49, 0x85, 0x30, 0xB1, 0x0F, 0xA9, 0x07, 0xD7, 0x9B, 0xD9, 0xC8, 0xFA, 0xAF, 0x23, 0x3F, 0x16, 0xBB, 0x77, 0x26, 0xEF, 0x55, 0xF2, 0x3A, 0x62, 0xA6, 0x8A, 0xE1, 0x15, 0x72, 0xD5, 0xFC, 0x4E, 0x87, 0x49, 0x5F, 0x17, 0x00, 0xD7, 0x00, 0xDA, 0x55, 0xAE, 0x63, 0x47, 0xEB, 0xE1, 0xC0, 0x40, 0x59, 0xC0, 0xB6, 0x19, 0x98, 0xF5, 0x06, 0xB0, 0x6C, 0x00, 0xD2, 0xAB, 0x25, 0x27, 0x98, 0x64, 0x01, 0x25, 0xBD, 0x64, 0x1F, 0x6B, 0x77, 0x00, 0xEA, 0x06, 0x49, 0x76, 0xE3, 0x1A, 0x6D, 0x3D, 0xC0, 0x0E, 0x64, 0x95, 0x45, 0xBF, 0xDE, 0xE4, 0x09, 0xDE, 0xAF, 0xBD, 0x96, 0xFC, 0x72, 0x69, 0x71, 0x34, 0x79, 0x67, 0x74, 0x78, 0x2E, 0x79, 0x74, 0x87, 0x47, 0x1C, 0xB9, 0xCC, 0xD9, 0xF1, 0x35, 0x39, 0x5A, 0x3C, 0x7B, 0x23, 0x2D, 0xED, 0xD5, 0x76, 0x92, 0xFC, 0x9F, 0x81, 0x35, 0x20, 0x3F, 0xD3, 0xCA, 0x4B, 0xAB, 0x02, 0x50, 0xA9, 0x9C, 0x58, 0xD7, 0x61, 0x1D, 0xD0, 0x65, 0xC4, 0xA1, 0x95, 0x0A, 0x1B, 0x01, 0x1D, 0xCD, 0xD7, 0xE7, 0xDB, 0x00, 0xE8, 0xD8, 0xBB, 0x2E, 0x0E, 0x03, 0x01, 0x39, 0x7E, 0x16, 0x0E, 0x99, 0xB7, 0xEC, 0xFF, 0x7F, 0x4F, 0x75, 0xA0, 0x18, 0x20, 0x8F, 0xAA, 0x91, 0x0F, 0x63, 0xB7, 0x49, 0x90, 0x99, 0xC5, 0xD1, 0x69, 0x64, 0xEC, 0xB4, 0x71, 0x53, 0xC8, 0xD1, 0xAF, 0x87, 0xC5, 0x92, 0xBD, 0xB5, 0x6C, 0xDF, 0x90, 0x2A, 0x8D, 0xD6, 0x7F, 0x48, 0xA0, 0x8F, 0x69, 0x9B, 0x95, 0xA4, 0xE5, 0x2D, 0xCB, 0x3F, 0xA4, 0x95, 0xEE, 0xF8, 0x14, 0xD2, 0xA2, 0x7C, 0x5B, 0x16, 0xD9, 0x4B, 0x84, 0x43, 0xD2, 0x28, 0xB4, 0x36, 0x99, 0xEC, 0xB8, 0x8D, 0xEB, 0x2B, 0x7F, 0x67, 0x95, 0x0E, 0x93, 0xBF, 0x77, 0x9C, 0xB1, 0x05, 0x80, 0x8A, 0x99, 0x17, 0xFA, 0x90, 0x17, 0xF7, 0xEC, 0xAB, 0x20, 0x37, 0x5A, 0xAD, 0x2C, 0x21, 0xC7, 0x1F, 0x9F, 0xBA, 0x8B, 0xB4, 0xDF, 0x3E, 0x2E, 0x94, 0xEC, 0xD0, 0x21, 0xA8, 0x13, 0x09, 0xF8, 0x1A, 0x4B, 0x0D, 0x23, 0x47, 0xF8, 0xAB, 0x39, 0x92, 0x2E, 0x77, 0x6C, 0x3D, 0xC8, 0x01, 0x75, 0xA1, 0xE7, 0x49, 0x87, 0x63, 0x1B, 0x4C, 0xC9, 0xBE, 0x4F, 0x73, 0x08, 0xD8, 0x6D, 0xFC, 0x36, 0x85, 0x34, 0x7F, 0xC2, 0xF5, 0x75, 0x47, 0xB1, 0x9D, 0x57, 0x93, 0xE5, 0x4D, 0xB9, 0x65, 0x00, 0x70, 0x7F, 0x71, 0xCE, 0x07, 0x72, 0xCF, 0x46, 0xDE, 0xCD, 0x12, 0xF1, 0x67, 0xEB, 0x14, 0x72, 0x40, 0xBB, 0xD5, 0x61, 0x64, 0x47, 0xFF, 0x38, 0x0B, 0x12, 0x88, 0x19, 0x2F, 0x91, 0x43, 0xCE, 0xEF, 0xAD, 0x9C, 0x4C, 0x4E, 0x8D, 0xD1, 0xB7, 0x20, 0xC3, 0xD5, 0x07, 0xED, 0x25, 0xFD, 0xDB, 0x4D, 0xFA, 0x40, 0x06, 0x5C, 0x5A, 0x63, 0x49, 0xFA, 0xAD, 0x3C, 0xA9, 0x49, 0x06, 0xFA, 0x56, 0x6E, 0x27, 0x47, 0xD9, 0x70, 0x7D, 0xBB, 0x19, 0x6C, 0xCF, 0x21, 0x64, 0xD1, 0xE1, 0x07, 0x23, 0x00, 0xE0, 0xC4, 0xC3, 0x7C, 0x45, 0x32, 0x6A, 0xC3, 0x89, 0x5A, 0xD2, 0xCD, 0xF1, 0xC8, 0x5A, 0x52, 0xFF, 0x70, 0x9A, 0x0B, 0x09, 0xA4, 0x39, 0xB3, 0x07, 0xF7, 0xB4, 0x5F, 0x45, 0xA6, 0xFA, 0x98, 0x5D, 0x20, 0xF7, 0xF6, 0x77, 0xBC, 0x4C, 0xEE, 0x6E, 0xF0, 0xDB, 0x4C, 0x26, 0xD4, 0x87, 0xE9, 0x91, 0x1B, 0x0A, 0x0F, 0xFA, 0x93, 0x6B, 0x3E, 0x67, 0x54, 0x91, 0x6B, 0x4B, 0xEA, 0xCC, 0xC8, 0x38, 0x5F, 0xAE, 0x3F, 0x6B, 0x10, 0xEB, 0x93, 0x4F, 0x9E, 0x5B, 0xFB, 0x9C, 0xEA, 0x61, 0x1D, 0xE7, 0x42, 0x8C, 0xAE, 0xB8, 0x11, 0x47, 0x5A, 0x8C, 0xBE, 0x16, 0x4D, 0xCA, 0x4A, 0x5F, 0x4D, 0x20, 0x81, 0x5C, 0x1B, 0xA9, 0xF7, 0x64, 0xC1, 0x2E, 0xE3, 0x1C, 0xF2, 0x76, 0x3B, 0x87, 0x78, 0xB2, 0xA0, 0xCC, 0xBF, 0x91, 0xCC, 0x8F, 0x9B, 0xF2, 0x85, 0xCC, 0x1B, 0x1F, 0x57, 0x43, 0xE6, 0x7B, 0xA5, 0xAB, 0x92, 0x17, 0xA2, 0xCE, 0x7F, 0x06, 0x79, 0xBD, 0x4A, 0x9D, 0xCC, 0xBA, 0xCD, 0xF5, 0x93, 0xDE, 0xB2, 0xB1, 0xEB, 0xC9, 0xDD, 0x5D, 0xDF, 0x6E, 0x02, 0x80, 0x89, 0x0A, 0x4F, 0x42, 0x48, 0xBB, 0xA4, 0xA2, 0x32, 0x52, 0xBD, 0xE3, 0xE3, 0xAD, 0x24, 0xF0, 0x5A, 0x9B, 0xFD, 0xD8, 0x41, 0x77, 0x3E, 0xF9, 0xE3, 0x92, 0xE3, 0x4F, 0xB2, 0xE1, 0xA6, 0xBF, 0x0E, 0xF8, 0x79, 0x94, 0x39, 0xD9, 0x92, 0xB3, 0x8A, 0xF7, 0xED, 0x54, 0xEC, 0x79, 0x40, 0xB6, 0x14, 0x65, 0x6C, 0x23, 0xEB, 0xC7, 0x17, 0x84, 0x92, 0x3F, 0x9F, 0x55, 0x2C, 0x20, 0x2B, 0x75, 0xB9, 0xFE, 0x83, 0x42, 0xF6, 0xC4, 0x2D, 0x32, 0x32, 0xE2, 0xE3, 0x17, 0x00, 0x18, 0x70, 0xB6, 0xE4, 0x01, 0xA9, 0xE3, 0xFD, 0x3E, 0x9C, 0x94, 0x58, 0xFE, 0xCB, 0x84, 0xA4, 0x3A, 0x5A, 0xD1, 0xAC, 0xBD, 0x21, 0xEB, 0xE1, 0xC5, 0x86, 0x44, 0xB3, 0x53, 0x07, 0xB2, 0x8B, 0x37, 0xB1, 0xF1, 0xD6, 0x6C, 0x8A, 0x0F, 0x9B, 0x9D, 0xC3, 0xDE, 0x3B, 0x0A, 0x72, 0xC6, 0xFB, 0x7C, 0xFE, 0xBC, 0xA9, 0x56, 0xC2, 0x0F, 0x28, 0x9E, 0x4A, 0xED, 0x18, 0x19, 0x55, 0x35, 0x0E, 0x00, 0x0C, 0x17, 0xD4, 0xE6, 0x92, 0x72, 0xE2, 0x0E, 0x5E, 0x62, 0xA1, 0xC4, 0x42, 0x80, 0x67, 0x7E, 0xD2, 0x72, 0x15, 0xEB, 0x72, 0x91, 0x1D, 0x35, 0x9F, 0x0D, 0x06, 0x1B, 0x91, 0xCB, 0x46, 0x8F, 0x64, 0x37, 0xF6, 0x60, 0xF7, 0xE4, 0xB0, 0x47, 0x0C, 0xD9, 0x0B, 0x89, 0xEC, 0x03, 0x0D, 0x90, 0x28, 0xDF, 0x47, 0x36, 0x87, 0xFC, 0x7A, 0x0D, 0xCA, 0x1D, 0xAE, 0x80, 0xB4, 0xB8, 0x7F, 0x56, 0x3C, 0x0B, 0x28, 0x9E, 0x15, 0x63, 0x9B, 0x16, 0xA0, 0xAC, 0x25, 0xE6, 0xFF, 0x4F, 0x40, 0xBB, 0x4F, 0x62, 0x7E, 0x7B, 0x03, 0xA8, 0x0F, 0xA0, 0x36, 0x4B, 0x86, 0x1A, 0x0C, 0x23, 0xBB, 0x1E, 0x33, 0x70, 0x22, 0xCD, 0x57, 0xF6, 0x90, 0x26, 0x87, 0x57, 0x99, 0x56, 0x91, 0x73, 0x26, 0x19, 0x2C, 0x24, 0xE3, 0xCF, 0xE8, 0x82, 0x3C, 0x61, 0xA5, 0xB1, 0x9A, 0x2C, 0x88, 0x97, 0x4B, 0x20, 0xDF, 0x5C, 0x91, 0xE9, 0xF7, 0x37, 0x1A, 0xA8, 0xDD, 0x2F, 0xFD, 0xAE, 0xE6, 0x1D, 0x68, 0x3C, 0xEF, 0x54, 0xE6, 0x43, 0x2A, 0xD5, 0xFC, 0x93, 0xFA, 0xDA, 0xCD, 0x07, 0xE4, 0x9C, 0x44, 0x7B, 0xB4, 0x01, 0xC5, 0x6C, 0xD1, 0x9E, 0x54, 0x40, 0x39, 0x55, 0xE4, 0x90, 0x25, 0x40, 0x7B, 0x1E, 0x73, 0xD0, 0x5D, 0x95, 0xD4, 0x2C, 0xD7, 0xDF, 0x44, 0x1A, 0x06, 0x98, 0x1F, 0x21, 0x87, 0x5E, 0xB4, 0x6C, 0x4F, 0x46, 0xD9, 0x18, 0x9E, 0x24, 0xF7, 0xB4, 0xED, 0xBA, 0x99, 0x3C, 0xDF, 0xAC, 0xAC, 0x47, 0x3E, 0x71, 0x94, 0xD9, 0x40, 0x56, 0x26, 0x4B, 0x9E, 0xFC, 0x69, 0x0B, 0xB4, 0x48, 0x2B, 0x44, 0x94, 0x4F, 0x06, 0x44, 0x8D, 0x87, 0x8F, 0x3A, 0x82, 0x14, 0xAF, 0xD7, 0xAD, 0x1E, 0x9C, 0x42, 0x4F, 0xB0, 0x72, 0x8F, 0x00, 0xC5, 0xE9, 0xA2, 0x3D, 0xD9, 0xDC, 0x9E, 0x76, 0x61, 0x40, 0xDB, 0x33, 0xE2, 0xF3, 0x0D, 0x40, 0xA7, 0x37, 0xF4, 0x7A, 0x1D, 0xFE, 0xE8, 0x7D, 0x20, 0xBB, 0x3D, 0x31, 0x9F, 0x4F, 0x0E, 0x1D, 0xDF, 0x6B, 0x06, 0xB9, 0xB4, 0xCA, 0x68, 0x3F, 0x99, 0xDA, 0xBB, 0x73, 0x17, 0x32, 0x77, 0x51, 0x9B, 0xAF, 0xE4, 0xFB, 0xFA, 0x36, 0xB2, 0x75, 0xB3, 0x81, 0x26, 0x19, 0x85, 0xD5, 0x65, 0xCF, 0x41, 0xF3, 0x4A, 0xF5, 0x83, 0x36, 0x20, 0x0D, 0x4E, 0xDE, 0x22, 0x25, 0xC4, 0x1E, 0x48, 0x83, 0xB7, 0x5C, 0xBF, 0xDB, 0x19, 0x56, 0xE7, 0x1B, 0x2B, 0x27, 0x01, 0x28, 0x8A, 0xFC, 0xA5, 0x64, 0x02, 0x28, 0x99, 0x88, 0x3C, 0xD4, 0x19, 0x68, 0x47, 0xEB, 0x2F, 0x68, 0x3B, 0xB4, 0x73, 0x15, 0x69, 0xE0, 0xA5, 0x7B, 0x41, 0xAC, 0x1D, 0x78, 0x04, 0x44, 0x71, 0xA6, 0x88, 0xE9, 0xAB, 0xFC, 0xAD, 0x61, 0x13, 0x70, 0xAC, 0x0C, 0x28, 0xEF, 0x05, 0xE4, 0x26, 0x02, 0x2F, 0xAE, 0x01, 0xA5, 0x65, 0xC0, 0x7D, 0xDA, 0x9F, 0xAB, 0x05, 0xE4, 0xBA, 0x81, 0x5E, 0x3B, 0xEF, 0xC0, 0x43, 0x12, 0x58, 0xF7, 0x8E, 0xA4, 0xC3, 0x3C, 0x1F, 0x20, 0x0D, 0x75, 0xD9, 0xEE, 0x16, 0xAC, 0xDE, 0x73, 0x56, 0x71, 0x16, 0x20, 0x27, 0xCE, 0xB3, 0xFC, 0x60, 0x80, 0xEE, 0xCB, 0x81, 0x76, 0xDB, 0x15, 0xFA, 0x0A, 0x7D, 0x7A, 0xBF, 0x01, 0x2A, 0x5C, 0x00, 0xEF, 0x69, 0xC0, 0x83, 0xFB, 0xC0, 0x3C, 0xE1, 0x8D, 0x6C, 0x60, 0x57, 0x7B, 0xE0, 0x42, 0x67, 0xE0, 0x92, 0x26, 0x90, 0x61, 0x09, 0xBC, 0xAA, 0x05, 0x76, 0xCF, 0x07, 0x6A, 0x43, 0x80, 0x8D, 0x4F, 0xB8, 0xEE, 0x6C, 0x43, 0x76, 0xFC, 0x1D, 0x92, 0x0E, 0xE7, 0x9E, 0x00, 0x69, 0xEB, 0xC0, 0xF6, 0xFA, 0xC6, 0x1A, 0xAF, 0x67, 0xB5, 0x7F, 0x91, 0xCD, 0x55, 0xF2, 0xD7, 0xC8, 0xE2, 0x63, 0x80, 0x4C, 0x14, 0x50, 0x38, 0x1A, 0xE8, 0x5E, 0x08, 0x64, 0xEB, 0x01, 0xAE, 0x16, 0xC0, 0xBE, 0x70, 0x20, 0x38, 0x06, 0xD8, 0x16, 0x07, 0xAC, 0xFC, 0x04, 0xAC, 0xD2, 0x07, 0x4E, 0xEC, 0x05, 0xA2, 0x43, 0x80, 0xE7, 0x4D, 0x40, 0x98, 0x39, 0xF0, 0xE3, 0x13, 0xE0, 0x1E, 0xC9, 0x75, 0x07, 0xB0, 0x70, 0x8C, 0x22, 0xE9, 0x70, 0x8F, 0x06, 0xC8, 0xE1, 0xF3, 0xD8, 0x81, 0x1D, 0xD8, 0x3E, 0x76, 0x64, 0xC5, 0x17, 0x5D, 0x0B, 0x32, 0x6F, 0xAD, 0x52, 0x38, 0x79, 0x6C, 0x19, 0x00, 0x00, 0x09, 0x74, 0x77, 0x71, 0x05, 0x98, 0x79, 0x0A, 0x30, 0x3F, 0x0C, 0x8C, 0x4D, 0x07, 0x06, 0xF6, 0x06, 0xBC, 0x85, 0x61, 0x8B, 0x81, 0x11, 0x1F, 0x81, 0x94, 0x49, 0x40, 0xDF, 0x1C, 0xE0, 0x56, 0x18, 0x60, 0x25, 0x05, 0x7C, 0xED, 0x0D, 0xE8, 0xED, 0xE3, 0xBA, 0x5D, 0xBF, 0xB3, 0x5A, 0x87, 0x48, 0x3A, 0xA6, 0xEC, 0x00, 0x40, 0x5A, 0x91, 0x4D, 0x4D, 0x5E, 0x63, 0xC9, 0x92, 0x24, 0xD7, 0x44, 0xF2, 0xBA, 0xBD, 0x55, 0x28, 0xB9, 0xA7, 0x40, 0xF7, 0x1C, 0xB9, 0xD8, 0x56, 0x75, 0x15, 0xE9, 0x4B, 0x5F, 0x05, 0x60, 0x45, 0xCF, 0xC7, 0xF6, 0x03, 0xA6, 0x83, 0x01, 0xCB, 0xD5, 0x80, 0xA1, 0x2F, 0x30, 0xFE, 0x20, 0xD0, 0xB5, 0x0F, 0x90, 0xB2, 0x0F, 0x50, 0x99, 0x00, 0xBC, 0xB8, 0x29, 0x3D, 0x5F, 0x41, 0x19, 0xF8, 0xED, 0x25, 0xBD, 0x94, 0x6B, 0x49, 0xF9, 0xB0, 0x00, 0x2B, 0xE1, 0x29, 0x56, 0xA1, 0x5B, 0xF7, 0xCF, 0x6F, 0x32, 0x22, 0x4B, 0x06, 0xCF, 0xFE, 0x48, 0x5E, 0x8F, 0x19, 0x7B, 0x9D, 0x4C, 0x92, 0x72, 0x99, 0x4B, 0xCE, 0xF5, 0xEC, 0xFD, 0x89, 0x74, 0xDB, 0xA6, 0xB3, 0x9F, 0x34, 0xBE, 0xD8, 0x36, 0x80, 0xE4, 0xFF, 0x54, 0xD6, 0x00, 0x8A, 0x1E, 0x96, 0x4A, 0x0A, 0x85, 0x40, 0x87, 0xFC, 0x31, 0x19, 0x80, 0x70, 0x76, 0xC2, 0x1F, 0x90, 0x87, 0x6F, 0x4D, 0x24, 0x15, 0x03, 0x7E, 0xFA, 0x93, 0x54, 0xEB, 0xBF, 0x6D, 0x1E, 0xBC, 0xCF, 0x14, 0x00, 0x7E, 0xCA, 0xA5, 0x9C, 0x27, 0x0B, 0xD6, 0xAF, 0xCD, 0x22, 0x0F, 0xF4, 0x9D, 0x3E, 0x96, 0x9C, 0xFF, 0xD4, 0xF7, 0x10, 0xE9, 0x3E, 0xCB, 0x79, 0x12, 0x69, 0xBA, 0xDD, 0x22, 0x95, 0x94, 0x7A, 0x6E, 0x5E, 0x4D, 0x02, 0x7A, 0xBA, 0xB2, 0x33, 0x49, 0xCD, 0x94, 0x1E, 0x17, 0xC8, 0x2E, 0xC5, 0x63, 0x3E, 0x92, 0x1A, 0x73, 0x57, 0xC7, 0x91, 0x9D, 0xBF, 0x5F, 0x5D, 0x46, 0xAA, 0xCE, 0xF9, 0x16, 0x45, 0xD2, 0xDF, 0x34, 0x25, 0x25, 0x2D, 0x59, 0x78, 0x91, 0x9F, 0xA7, 0x67, 0xE4, 0x03, 0x40, 0xF1, 0xD5, 0xD3, 0xAA, 0x64, 0xE6, 0xBB, 0x1D, 0x04, 0x96, 0x8F, 0x8F, 0x5A, 0x48, 0xFA, 0xAD, 0x0D, 0x9E, 0x45, 0xF6, 0xB4, 0x19, 0x35, 0x81, 0x94, 0x0E, 0xF5, 0x1A, 0x4D, 0x02, 0x2E, 0xD3, 0xA5, 0xC6, 0x91, 0xD6, 0x63, 0xD4, 0xF2, 0x49, 0x8B, 0x7D, 0x8E, 0xED, 0x49, 0x73, 0xB7, 0x09, 0x77, 0x49, 0xC3, 0xDF, 0xAB, 0x3E, 0x91, 0xA6, 0xA6, 0x97, 0xAD, 0x48, 0x83, 0x63, 0xF7, 0xFF, 0x90, 0xBA, 0x43, 0xB9, 0xBE, 0x5A, 0x04, 0xAB, 0xD4, 0x48, 0xBE, 0x0C, 0xBA, 0x5C, 0x05, 0x00, 0x39, 0xAF, 0x2E, 0xE4, 0x91, 0x9B, 0xB3, 0xF7, 0x4E, 0x25, 0x83, 0x53, 0x56, 0x2D, 0x21, 0xAD, 0x8F, 0x46, 0x17, 0x93, 0x0A, 0x37, 0x17, 0x38, 0x93, 0xC0, 0x0C, 0x13, 0x76, 0xC2, 0xFA, 0xB6, 0xFB, 0x48, 0xDF, 0xDF, 0xDD, 0x2F, 0x92, 0x1E, 0x5D, 0xFA, 0x4D, 0x25, 0x87, 0x74, 0x9C, 0x7A, 0x82, 0x74, 0x79, 0x17, 0x69, 0xCB, 0xF9, 0xEC, 0xAC, 0x3F, 0x39, 0x70, 0x7B, 0x41, 0x31, 0x69, 0xCB, 0xF3, 0x3E, 0xCC, 0x37, 0xB1, 0xBA, 0x73, 0xC8, 0xBC, 0x8B, 0x05, 0x93, 0x00, 0xE0, 0x80, 0xE3, 0x95, 0x12, 0x72, 0xC6, 0xDC, 0x23, 0x16, 0xE4, 0x20, 0xFF, 0xE4, 0x44, 0x52, 0xE3, 0x6E, 0x92, 0x1E, 0x09, 0xEC, 0x1A, 0xC3, 0x6E, 0x7B, 0xA6, 0xBA, 0x85, 0xDC, 0xBA, 0xDE, 0x7C, 0x37, 0xB9, 0xE5, 0x5B, 0xEF, 0x97, 0xE4, 0xA6, 0x5E, 0x3E, 0x5D, 0xC8, 0xA8, 0x5B, 0x51, 0x69, 0xE4, 0xA2, 0xED, 0xFB, 0xBF, 0x90, 0xF3, 0x0B, 0xD3, 0x07, 0x90, 0x73, 0xF3, 0xAA, 0x62, 0x40, 0x6E, 0xE6, 0xFA, 0x41, 0x03, 0x59, 0x87, 0x58, 0x32, 0x23, 0xF8, 0x91, 0x13, 0x00, 0x2C, 0xD1, 0xCB, 0x75, 0x26, 0xDD, 0x67, 0x5E, 0x3C, 0x43, 0x1A, 0xCC, 0x39, 0x77, 0x9E, 0x04, 0xCE, 0x6E, 0x64, 0xCF, 0x1D, 0x52, 0xBA, 0x49, 0x9E, 0xFF, 0x6C, 0x7A, 0x19, 0xE4, 0xF3, 0x41, 0x2F, 0xC9, 0xB3, 0x2E, 0x01, 0xB9, 0xBC, 0xD3, 0x6E, 0xE2, 0x5A, 0x32, 0xEB, 0xE1, 0xAC, 0x32, 0x90, 0x95, 0xBB, 0x2E, 0x90, 0xA7, 0x56, 0x65, 0x3D, 0x25, 0x33, 0x36, 0xDE, 0x1B, 0x4C, 0x1E, 0x9D, 0xC7, 0xF5, 0xE3, 0xD3, 0xD9, 0x99, 0xAF, 0xC8, 0xCD, 0x51, 0xAF, 0x97, 0x02, 0xC0, 0x98, 0xC4, 0xA2, 0x58, 0xD2, 0xF2, 0xCE, 0x5D, 0x1F, 0x52, 0xC9, 0xFF, 0x5E, 0x30, 0x09, 0x3C, 0x59, 0x27, 0xAB, 0x4D, 0xBE, 0xD2, 0x33, 0x36, 0x25, 0x3F, 0x2E, 0x73, 0x1D, 0x4E, 0xFE, 0x18, 0x38, 0xFA, 0x35, 0xF9, 0x5B, 0x35, 0x6C, 0x0F, 0x59, 0xFB, 0x6C, 0x95, 0x0F, 0xC8, 0x59, 0x3B, 0xB7, 0x91, 0xD5, 0xDD, 0xD3, 0xC3, 0xC9, 0x4F, 0xC7, 0x6E, 0xEC, 0x27, 0xDF, 0x4B, 0x3D, 0xF9, 0x42, 0x96, 0x84, 0x37, 0x68, 0x90, 0xB7, 0x97, 0x73, 0x3B, 0xF6, 0x86, 0x93, 0x53, 0x3C, 0x3F, 0xF4, 0x00, 0x00, 0xBB, 0x31, 0xAF, 0xC6, 0x93, 0x1A, 0x13, 0x4A, 0xBC, 0x48, 0xDA, 0x3F, 0xC4, 0x8A, 0xA7, 0xEF, 0x19, 0xEC, 0x40, 0x3F, 0xD6, 0xE7, 0x0C, 0x1B, 0xDC, 0x96, 0x9D, 0xF9, 0x9B, 0x8D, 0x3B, 0xCE, 0x6E, 0x5F, 0x04, 0xF2, 0x42, 0x6A, 0xEB, 0xF7, 0x65, 0x9F, 0x26, 0x9B, 0x9F, 0x14, 0x3A, 0x90, 0x0D, 0x75, 0xC5, 0x59, 0xFC, 0xF5, 0xBA, 0xFE, 0x64, 0x51, 0x25, 0xB5, 0x63, 0xD0, 0x9B, 0xCA, 0x42, 0x00, 0xD0, 0x95, 0xAB, 0x4E, 0x21, 0x21, 0xAE, 0x26, 0xC9, 0x82, 0x36, 0x1A, 0xF4, 0xFF, 0xE9, 0xAF, 0x04, 0x48, 0x9B, 0x30, 0x76, 0x58, 0x23, 0xEB, 0x9F, 0xC8, 0x06, 0x83, 0x9D, 0xE9, 0xC9, 0x2E, 0xD1, 0x65, 0x37, 0x5F, 0x03, 0x59, 0xB8, 0xAF, 0x0F, 0xC8, 0x21, 0x22, 0x71, 0x93, 0x53, 0x2F, 0xA8, 0x91, 0xCD, 0x03, 0x6E, 0x7F, 0x20, 0x1B, 0xDB, 0xBC, 0x06, 0x48, 0xAF, 0xDA, 0x43, 0xA0, 0xB9, 0xB7, 0x11, 0x80, 0x98, 0x4F, 0xA5, 0x9B, 0x00, 0xE9, 0x26, 0x71, 0xEF, 0xBB, 0x10, 0x90, 0x11, 0x79, 0x46, 0x76, 0x38, 0x20, 0x3B, 0x9C, 0xDA, 0x2A, 0x95, 0xDB, 0x56, 0x82, 0xEC, 0x90, 0xD0, 0x21, 0x81, 0xD4, 0x45, 0x27, 0x2B, 0x31, 0xEF, 0x4D, 0xEC, 0xD7, 0x53, 0x9E, 0x7E, 0x67, 0xE1, 0x86, 0x7F, 0x14, 0x68, 0x4C, 0xD4, 0x9A, 0x37, 0x50, 0x9D, 0x32, 0x38, 0xB6, 0x85, 0x75, 0xF1, 0x23, 0x8F, 0x8F, 0xD6, 0x38, 0x45, 0xE6, 0x2E, 0x53, 0x3E, 0x47, 0xBE, 0x4E, 0x92, 0x5F, 0xF3, 0x47, 0x17, 0xF8, 0xA1, 0x24, 0x5F, 0xF4, 0x61, 0x07, 0xD0, 0xF4, 0xB1, 0xED, 0xCF, 0xE7, 0xE1, 0x80, 0xC8, 0x5A, 0xE2, 0xDA, 0x55, 0x89, 0xE2, 0x9F, 0x42, 0x7E, 0x34, 0x20, 0xA9, 0x25, 0xDA, 0x13, 0x01, 0x48, 0x47, 0x88, 0xF6, 0xCC, 0x06, 0x64, 0x66, 0x8B, 0xD7, 0x7F, 0x03, 0x28, 0xEA, 0xD0, 0xEB, 0xB4, 0xDD, 0xDB, 0x76, 0x2F, 0xD9, 0x75, 0xA9, 0xFA, 0x6B, 0x31, 0x77, 0x7F, 0xED, 0x3B, 0x54, 0x4E, 0xE4, 0x0B, 0xF5, 0x64, 0x7F, 0x9E, 0x33, 0xB1, 0xA0, 0xA1, 0x63, 0x03, 0xB9, 0x6B, 0xA6, 0xE6, 0x2C, 0xF2, 0xCC, 0x5F, 0x95, 0x85, 0x64, 0xD1, 0x13, 0xE5, 0xAE, 0x75, 0xB7, 0x81, 0x2F, 0x1B, 0x15, 0x8E, 0x7C, 0x4C, 0x04, 0x1A, 0xC6, 0xB7, 0x5D, 0xFD, 0x9C, 0xFF, 0x52, 0xD4, 0xF4, 0xBC, 0xF1, 0x64, 0x5B, 0xB1, 0x8E, 0xD1, 0xA9, 0xF5, 0xDD, 0x6F, 0x9F, 0xC4, 0xCA, 0x48, 0x00, 0x52, 0x4B, 0xC5, 0x1C, 0xD0, 0x22, 0x6C, 0x11, 0x9F, 0xD7, 0x02, 0x32, 0xB4, 0xCF, 0x17, 0xF2, 0x57, 0x14, 0xB7, 0x91, 0x9D, 0xF2, 0x55, 0x17, 0x8A, 0x76, 0xCC, 0x71, 0xB8, 0x2C, 0x37, 0x47, 0xE4, 0x92, 0x8C, 0x80, 0xBE, 0xDC, 0x8E, 0x45, 0x5D, 0xBA, 0x74, 0x21, 0x93, 0xDF, 0xA9, 0x1F, 0x27, 0xAF, 0x4D, 0x51, 0xF2, 0x68, 0x2A, 0x05, 0xDE, 0x5E, 0x52, 0x7C, 0xF2, 0xC5, 0x11, 0xF8, 0x53, 0xAA, 0xFC, 0xE8, 0xE9, 0x1E, 0x40, 0x64, 0x3C, 0xE5, 0x6B, 0x3F, 0x49, 0x85, 0x77, 0x07, 0xE2, 0x48, 0x3A, 0x74, 0x6D, 0x01, 0xB2, 0x53, 0x3D, 0xDB, 0x2E, 0x9B, 0x95, 0x9A, 0x0E, 0x48, 0x4D, 0x17, 0xDE, 0x14, 0xDE, 0xFC, 0x3F, 0xF9, 0x74, 0xBC, 0xBC, 0x1A, 0xA9, 0x61, 0xA2, 0xB4, 0x48, 0xF4, 0xA2, 0x4A, 0x9B, 0x5B, 0x92, 0x95, 0xE2, 0xDF, 0x3B, 0xFB, 0xFE, 0x05, 0x1A, 0x3F, 0x01, 0x4B, 0x82, 0x64, 0xE4, 0x3E, 0xCC, 0x02, 0x92, 0xCD, 0xA4, 0x36, 0x3C, 0xF3, 0x00, 0x2E, 0x0C, 0x00, 0x0A, 0xE5, 0x80, 0xE7, 0xA1, 0xC0, 0xE5, 0x25, 0x40, 0xAD, 0x15, 0x90, 0xF5, 0x1E, 0xF4, 0xB3, 0xEE, 0x8F, 0xEF, 0x44, 0x02, 0x51, 0xDD, 0x49, 0x3A, 0x4C, 0x87, 0x03, 0xA4, 0x5E, 0x2D, 0xDB, 0x55, 0x8A, 0xED, 0x90, 0xCA, 0xCA, 0x26, 0xB0, 0x80, 0xC4, 0x50, 0xC9, 0xAE, 0x64, 0xC7, 0xFB, 0xC0, 0x67, 0x2B, 0xC0, 0x3C, 0x13, 0x78, 0xB2, 0x91, 0xF6, 0x82, 0x00, 0x37, 0x23, 0x81, 0xC9, 0x3B, 0x81, 0x93, 0xFE, 0xC0, 0xAA, 0x2F, 0xC0, 0x41, 0x45, 0xDA, 0x3B, 0x0B, 0x6C, 0xF3, 0x07, 0x0A, 0x1B, 0x80, 0x58, 0x29, 0xE0, 0x4B, 0x01, 0x30, 0x7F, 0x38, 0xBF, 0x56, 0xD0, 0x16, 0xD6, 0xFD, 0x0C, 0x49, 0x87, 0xBD, 0x05, 0x40, 0x5A, 0x1D, 0x62, 0x4D, 0x3E, 0xB3, 0xBA, 0x04, 0x9A, 0x2F, 0xB6, 0xFD, 0x40, 0xBE, 0xE1, 0x69, 0x07, 0x85, 0x9A, 0x40, 0x1B, 0x33, 0xE0, 0xBC, 0x1B, 0xA0, 0xDB, 0x13, 0x48, 0x3D, 0x01, 0xD8, 0x0D, 0x03, 0xD6, 0x6E, 0x06, 0x3C, 0xA7, 0x00, 0xF3, 0xED, 0x80, 0x19, 0x9B, 0x81, 0xF0, 0x2C, 0x60, 0xD7, 0x2C, 0x60, 0xEC, 0x28, 0xE0, 0xA6, 0x1C, 0xE0, 0x36, 0x13, 0x78, 0xBF, 0x1F, 0x70, 0xBE, 0xC2, 0x75, 0x7B, 0xEF, 0x64, 0xCD, 0x1E, 0x91, 0x74, 0x0C, 0x7D, 0x0D, 0x90, 0x2E, 0x17, 0x58, 0xFB, 0xC7, 0xE4, 0x8F, 0x5A, 0xD3, 0x79, 0xE4, 0x93, 0xD7, 0x5A, 0x9D, 0xC8, 0x73, 0x4F, 0x15, 0x7A, 0x93, 0x7B, 0x3F, 0x48, 0xDC, 0x21, 0x57, 0x54, 0x02, 0x6D, 0x9D, 0x80, 0x49, 0x2A, 0x80, 0xDE, 0x6D, 0xC0, 0xF3, 0x26, 0x60, 0xB7, 0x06, 0xE8, 0x97, 0x09, 0x04, 0x96, 0x00, 0xD6, 0xE5, 0x40, 0x82, 0x25, 0x60, 0x62, 0x0B, 0x5C, 0xEE, 0x08, 0x74, 0x1B, 0x0D, 0x94, 0x2E, 0x01, 0x3A, 0x65, 0x03, 0x7C, 0xED, 0xB1, 0xED, 0xBB, 0x93, 0x74, 0x04, 0xCA, 0x02, 0xA4, 0xBF, 0x36, 0xF9, 0xF9, 0xBD, 0x5B, 0x1A, 0xF9, 0xD0, 0xB5, 0xDF, 0x50, 0x32, 0xEB, 0xB1, 0x99, 0x11, 0xB9, 0x79, 0x87, 0x4E, 0x37, 0x72, 0xE6, 0xD9, 0xB6, 0x8B, 0x49, 0x77, 0x7B, 0xE9, 0x4B, 0x64, 0xAF, 0x41, 0x40, 0x5B, 0x19, 0x40, 0x47, 0x1A, 0x30, 0x5D, 0x01, 0x74, 0x78, 0x05, 0x04, 0xCC, 0x00, 0xE4, 0x2C, 0x81, 0xCD, 0xB9, 0x00, 0x5E, 0x00, 0xD7, 0x27, 0x0B, 0x01, 0x54, 0x7F, 0xFB, 0x7F, 0xE7, 0x8F, 0xA6, 0xE5, 0x4B, 0xD4, 0x01, 0xE0, 0x57, 0x97, 0x25, 0x4B, 0xC8, 0x27, 0xF3, 0x26, 0xE7, 0x92, 0x67, 0x1D, 0xBD, 0x87, 0x93, 0x1B, 0x1F, 0x3B, 0xE9, 0x90, 0xE1, 0xA3, 0x7A, 0xDC, 0x23, 0x5D, 0xBD, 0x34, 0x2D, 0x48, 0xFD, 0xEE, 0x0A, 0xE3, 0xF1, 0x1F, 0xFF, 0xF1, 0x19, 0x05, 0x46, 0x5D, 0x63, 0x57, 0x36, 0xB3, 0x57, 0x35, 0xD9, 0xAA, 0xC2, 0xFF, 0x77, 0x3B, 0x6A, 0x77, 0xEF, 0x90, 0x06, 0x80, 0x0F, 0x0F, 0x76, 0xC4, 0x93, 0xD7, 0xFE, 0xAE, 0xB0, 0x26, 0x13, 0xDF, 0x85, 0x1E, 0x23, 0xA7, 0x45, 0x8E, 0x8C, 0x24, 0x07, 0xBF, 0xB0, 0x79, 0x4F, 0xEA, 0x7B, 0x1B, 0x39, 0x90, 0x40, 0xB7, 0x30, 0x56, 0xE1, 0xA3, 0xEA, 0x54, 0x52, 0x7A, 0xB3, 0x79, 0x4F, 0x12, 0x35, 0x1E, 0xFA, 0x84, 0x44, 0xDA, 0x72, 0x02, 0x92, 0x52, 0x27, 0x57, 0x90, 0xC0, 0xB3, 0xDB, 0xA0, 0xCF, 0xDB, 0xFF, 0xDF, 0xDA, 0xF1, 0xD6, 0x25, 0x2D, 0x1B, 0x00, 0x1E, 0x1A, 0x1D, 0xF1, 0x27, 0x0F, 0xAB, 0x6C, 0xAC, 0x27, 0xA3, 0x22, 0x78, 0xD6, 0xF4, 0x48, 0x08, 0xF0, 0x27, 0x8D, 0xAF, 0x8F, 0xB0, 0x27, 0x01, 0xD7, 0x97, 0x6C, 0x9F, 0xB1, 0xD2, 0xDB, 0x49, 0x03, 0x23, 0xB5, 0x18, 0xB2, 0x53, 0x95, 0x5D, 0x15, 0xA9, 0x21, 0xE9, 0x57, 0x4F, 0x76, 0xF0, 0xE6, 0x76, 0xA8, 0xF5, 0x3C, 0x99, 0x45, 0xAA, 0xE4, 0x14, 0x76, 0x23, 0x55, 0xFB, 0x72, 0x7D, 0xC5, 0x63, 0xAC, 0xF4, 0x22, 0xF2, 0xE1, 0xDD, 0xF3, 0x46, 0x00, 0x70, 0x21, 0x34, 0xEB, 0x37, 0xB9, 0x7A, 0x7D, 0x62, 0x0A, 0x19, 0xD8, 0x7B, 0x79, 0x33, 0xD9, 0xD3, 0x3F, 0xF2, 0x37, 0x29, 0x6B, 0x3C, 0xED, 0x29, 0x09, 0x8C, 0x4B, 0x41, 0x12, 0x39, 0x4A, 0xBF, 0x1D, 0x89, 0xC1, 0x16, 0x3D, 0xDE, 0x90, 0x8E, 0x53, 0x86, 0x78, 0x92, 0xD6, 0x07, 0x82, 0x09, 0x58, 0x3C, 0x8E, 0x7A, 0x4A, 0x5A, 0xCE, 0xC9, 0xB0, 0x21, 0x2D, 0xF4, 0xF2, 0xC6, 0x93, 0xE6, 0x77, 0xB9, 0x7E, 0xF7, 0x48, 0x56, 0x23, 0x95, 0xBC, 0x7A, 0x2C, 0x4F, 0x19, 0x00, 0xF6, 0xE8, 0x5F, 0x52, 0x21, 0x27, 0xCF, 0x3B, 0xFC, 0x9D, 0x74, 0x32, 0x49, 0x1A, 0x42, 0xAA, 0xBC, 0x4F, 0xD8, 0x48, 0x02, 0x9B, 0x17, 0x4B, 0x06, 0x90, 0xEB, 0x3E, 0x29, 0x65, 0x92, 0xAB, 0x66, 0x18, 0xCE, 0x24, 0xA3, 0x9C, 0x2D, 0xE7, 0x90, 0xB3, 0xB7, 0x7A, 0x04, 0x90, 0x53, 0x9D, 0xE6, 0xE4, 0x92, 0x11, 0x3F, 0x37, 0x45, 0x92, 0x61, 0x96, 0x47, 0x09, 0xF8, 0xDF, 0x7B, 0xF0, 0x86, 0x0C, 0xBB, 0xC9, 0xF5, 0x3D, 0x8A, 0xD9, 0x9E, 0xB7, 0xC9, 0xB4, 0x65, 0x45, 0xD3, 0x01, 0x20, 0x4A, 0x27, 0xB7, 0x0F, 0x39, 0xEC, 0xCF, 0xF9, 0x07, 0x64, 0x37, 0xCF, 0xEC, 0x68, 0x12, 0xC8, 0x92, 0x07, 0x3B, 0x43, 0x65, 0x13, 0x99, 0xAD, 0x6C, 0x76, 0x17, 0x64, 0x1B, 0x17, 0x7D, 0xF2, 0x74, 0x8C, 0x77, 0x0C, 0x99, 0xD9, 0x3C, 0x31, 0x95, 0xCC, 0x50, 0x89, 0x74, 0x27, 0x8F, 0x66, 0x27, 0xDE, 0x20, 0xD3, 0x72, 0x4E, 0xA5, 0x90, 0xBB, 0x8F, 0x17, 0xB6, 0x05, 0xC9, 0x79, 0x0C, 0xEB, 0x4F, 0xB2, 0x13, 0x63, 0xC8, 0xB5, 0xD5, 0xAF, 0x7B, 0x83, 0x5A, 0xDB, 0xA6, 0xE8, 0x04, 0x69, 0x6E, 0x7A, 0xA7, 0x8C, 0x54, 0x34, 0xBD, 0x7B, 0x98, 0x04, 0x1E, 0x5D, 0x56, 0x7A, 0x43, 0xBE, 0xB4, 0x37, 0x5D, 0x48, 0x96, 0x79, 0x0D, 0xF4, 0x22, 0x3F, 0x4F, 0xF2, 0x4F, 0x22, 0xBF, 0x3C, 0x9F, 0x64, 0x47, 0x7E, 0xBA, 0x19, 0x6B, 0x41, 0x7E, 0x74, 0xD9, 0xBE, 0x9C, 0x2C, 0xBD, 0x7A, 0xF4, 0x16, 0x59, 0x72, 0xF2, 0xCA, 0x49, 0xF2, 0xE5, 0x94, 0x07, 0xDA, 0xE4, 0xD3, 0x9D, 0x3F, 0x12, 0xC9, 0x5C, 0x3D, 0x6E, 0x47, 0x62, 0x0F, 0x32, 0xEC, 0xD8, 0xFB, 0x0C, 0x00, 0xB0, 0xF9, 0xF0, 0x3A, 0x98, 0x54, 0x1F, 0xFB, 0xF6, 0x18, 0x09, 0x54, 0xCD, 0x96, 0x89, 0x26, 0x5B, 0xFC, 0x0C, 0x5B, 0xF7, 0xF1, 0x0C, 0xCA, 0x64, 0x7D, 0x0D, 0xD8, 0x60, 0xB0, 0xB3, 0x83, 0xD8, 0x55, 0xD3, 0x40, 0xCA, 0xEC, 0x70, 0x23, 0x9B, 0xB3, 0x0F, 0x6C, 0x00, 0x19, 0x98, 0xBD, 0x89, 0x6C, 0x68, 0xB9, 0xD5, 0x86, 0xAC, 0xD3, 0x7E, 0x71, 0x01, 0x64, 0x7C, 0x4D, 0x04, 0x79, 0x37, 0x8A, 0xDA, 0xD1, 0x3F, 0x8D, 0x76, 0x4C, 0x00, 0xDA, 0xBE, 0x35, 0x77, 0x04, 0x9C, 0x44, 0x96, 0xCB, 0x14, 0x82, 0xEE, 0xB8, 0x97, 0x01, 0xA4, 0x6D, 0x30, 0x3B, 0x3C, 0x97, 0x0D, 0xC8, 0xF8, 0x8F, 0xFD, 0xD1, 0xCF, 0xD9, 0xD8, 0x05, 0x20, 0x67, 0x6F, 0x25, 0xD0, 0x32, 0x7D, 0xDF, 0x0C, 0xB2, 0x79, 0xD3, 0x91, 0x27, 0x20, 0x47, 0x9C, 0x4F, 0x23, 0x1B, 0x4E, 0x14, 0x64, 0x93, 0x75, 0xDD, 0x5F, 0x78, 0x81, 0x9C, 0xF7, 0x7D, 0x3D, 0x09, 0x0B, 0x8C, 0xC1, 0x5A, 0x9C, 0xC3, 0xFF, 0x47, 0x10, 0x3C, 0x00, 0x0B, 0x15, 0x00, 0x00, 0x00, 0xBB, 0x67, 0xDB, 0x76, 0xB6, 0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0xDD, 0x21, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0xDD, 0xDF, 0x9E, 0x02, 0x22, 0x50, 0x04, 0xE8, 0x04, 0xCC, 0x07, 0x4E, 0x02, 0xDF, 0xC1, 0x04, 0xAC, 0x06, 0x0E, 0x01, 0xD7, 0x81, 0x77, 0x20, 0x02, 0xCA, 0x0D, 0xB5, 0x84, 0xA6, 0x43, 0x07, 0xA1, 0x77, 0xB0, 0x0D, 0x97, 0x83, 0xFB, 0xC0, 0xCB, 0xE0, 0x2B, 0x08, 0x80, 0x64, 0x46, 0x1A, 0x22, 0xE3, 0x91, 0x9D, 0xC8, 0x73, 0x54, 0x46, 0x8B, 0xA1, 0x5D, 0xD0, 0x45, 0xE8, 0x19, 0xF4, 0x17, 0x96, 0x06, 0xAB, 0x85, 0x0D, 0xC7, 0x36, 0x62, 0xF7, 0x71, 0x06, 0xCF, 0x8F, 0xB7, 0xC5, 0x67, 0xE3, 0x47, 0xF1, 0xCF, 0x44, 0x40, 0x54, 0x26, 0x06, 0x12, 0xAB, 0x89, 0x9B, 0x24, 0x46, 0xE6, 0x24, 0x9B, 0x93, 0x53, 0xC9, 0xFD, 0xE4, 0x5B, 0xCA, 0xA2, 0xCA, 0x52, 0xBD, 0xA9, 0xA5, 0xD4, 0x65, 0x1A, 0xA0, 0x33, 0xD3, 0x0D, 0xE9, 0xF1, 0xF4, 0x4E, 0xFA, 0x39, 0xA3, 0x30, 0xC5, 0x99, 0xAE, 0xCC, 0x62, 0xE6, 0x2C, 0xF3, 0x9B, 0x4D, 0xCB, 0xD6, 0x61, 0x47, 0xB1, 0x5B, 0xD8, 0x47, 0x1C, 0xCF, 0x15, 0xE2, 0x3A, 0x70, 0xF3, 0xB8, 0x13, 0xDC, 0x77, 0x3E, 0xE1, 0xAB, 0xF3, 0x43, 0xF9, 0xF5, 0xFC, 0x5D, 0x81, 0x16, 0xF2, 0x09, 0x6D, 0x84, 0x59, 0xC2, 0x11, 0xE1, 0x93, 0x18, 0x88, 0x95, 0xC5, 0x81, 0xE2, 0x6A, 0xF1, 0xA6, 0x84, 0x4B, 0xB9, 0xA4, 0x16, 0xD2, 0x34, 0xE9, 0x80, 0xF4, 0x5E, 0x76, 0xE4, 0xF2, 0x72, 0x5F, 0x79, 0x85, 0x7C, 0x4D, 0x81, 0x95, 0x6C, 0x4A, 0x53, 0x65, 0xB2, 0xB2, 0x57, 0x79, 0xAD, 0x9A, 0x6A, 0x19, 0xB5, 0x97, 0xBA, 0x54, 0xBD, 0xAC, 0xC1, 0x5A, 0x51, 0x6D, 0x88, 0xB6, 0x4F, 0xFB, 0xAB, 0xE7, 0xD7, 0xFB, 0xEA, 0x3B, 0xF4, 0x6F, 0x46, 0x0E, 0xA3, 0xBB, 0xB1, 0xD1, 0xF8, 0x60, 0x66, 0x32, 0x3B, 0x9A, 0xAB, 0xCD, 0x57, 0x56, 0x1A, 0xAB, 0xB5, 0xB5, 0xD4, 0x7A, 0x62, 0x87, 0x76, 0x53, 0x7B, 0xB1, 0x7D, 0xCF, 0xB1, 0x9D, 0xFA, 0xCE, 0x5C, 0xE7, 0x86, 0xAB, 0xBA, 0x35, 0xDD, 0xE9, 0xEE, 0x25, 0x4F, 0xF0, 0x2A, 0x7B, 0x93, 0xBC, 0xB3, 0x3E, 0xE5, 0x97, 0xF3, 0xC7, 0xFA, 0xC7, 0x03, 0x34, 0x28, 0x19, 0x8C, 0x08, 0x0E, 0x85, 0x40, 0x58, 0x24, 0x1C, 0x1C, 0xEE, 0x0B, 0xFF, 0x44, 0xF9, 0xA3, 0x7E, 0xD1, 0xCE, 0xE8, 0x47, 0x9C, 0x3B, 0xEE, 0x15, 0x6F, 0x8D, 0xBF, 0x24, 0xD9, 0x93, 0x6E, 0x49, 0x0A, 0x1B, 0xE7, 0x00, 0x1E, 0x07, 0x00, 0xA0, 0xD9, 0xC6, 0x6C, 0x6C, 0x37, 0xB6, 0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0x8D, 0xC6, 0xB6, 0x6D, 0xDB, 0x6A, 0x6C, 0xDB, 0xBE, 0x39, 0xDF, 0xED, 0x6E, 0x30, 0xF8, 0x3C, 0x7C, 0xFF, 0x7B, 0x83, 0x7A, 0x92, 0x5B, 0x52, 0x3A, 0x52, 0x5B, 0xD2, 0x6A, 0xD2, 0x4B, 0x32, 0x2A, 0x32, 0x4B, 0xB2, 0x72, 0xB2, 0x53, 0x72, 0x72, 0x72, 0x33, 0xF2, 0x12, 0xF2, 0x23, 0x0A, 0x62, 0x0A, 0x63, 0x8A, 0x42, 0x8A, 0x7D, 0x4A, 0x42, 0x4A, 0x03, 0xCA, 0x3C, 0xCA, 0x5D, 0x2A, 0x7C, 0x2A, 0x5D, 0xAA, 0xBF, 0x54, 0x5B, 0xD4, 0xB8, 0xD4, 0xDA, 0xD4, 0xD9, 0xD4, 0x1B, 0x34, 0xD8, 0x34, 0x5A, 0x34, 0x99, 0x34, 0xFF, 0x68, 0x31, 0x69, 0x35, 0x68, 0x33, 0x68, 0xD7, 0xE8, 0x30, 0xE8, 0xD4, 0xE9, 0xD2, 0xE9, 0x56, 0xE9, 0xD1, 0xE9, 0xD5, 0xE8, 0xD3, 0xE8, 0x57, 0x19, 0xD0, 0x18, 0x54, 0x19, 0x52, 0x19, 0x56, 0x18, 0xD1, 0x18, 0x55, 0x19, 0x53, 0x19, 0x57, 0x98, 0xD0, 0x98, 0x54, 0x99, 0x52, 0x99, 0x56, 0x99, 0xD1, 0x99, 0xD5, 0x98, 0xD3, 0x98, 0x57, 0x59, 0x30, 0x58, 0xD4, 0x59, 0xD2, 0x59, 0xD6, 0x58, 0x31, 0x59, 0x35, 0x58, 0xB3, 0x58, 0xF7, 0xD9, 0x28, 0xD8, 0xEC, 0xD9, 0x5A, 0xD9, 0xBE, 0xD9, 0x45, 0xD8, 0xA3, 0xD9, 0x17, 0x39, 0xB0, 0x38, 0x0C, 0x38, 0xCA, 0x38, 0x6E, 0x38, 0xD9, 0x38, 0x7D, 0x39, 0x87, 0xB9, 0x7E, 0x73, 0x29, 0x73, 0x65, 0x71, 0x1D, 0x70, 0x53, 0x72, 0x3B, 0x72, 0x77, 0xF0, 0x00, 0xF1, 0x48, 0xF0, 0xC4, 0xF3, 0xAC, 0xF1, 0x12, 0xF0, 0x9A, 0xF3, 0xD6, 0xF2, 0xBE, 0xF0, 0xF1, 0xF1, 0x85, 0xF1, 0xCD, 0xF2, 0xA3, 0xF3, 0xEB, 0xF1, 0x97, 0xF2, 0xDF, 0x08, 0xB0, 0x0B, 0xF8, 0x0B, 0x8C, 0x09, 0x22, 0x08, 0x6A, 0x08, 0xE6, 0x0B, 0x9E, 0x09, 0x31, 0x0A, 0x79, 0x0A, 0x0D, 0x0A, 0xC3, 0x08, 0x2B, 0x0B, 0xE7, 0x08, 0x1F, 0x89, 0xD0, 0x8A, 0xB8, 0x89, 0xF4, 0x8A, 0x42, 0x8A, 0x2A, 0x88, 0x66, 0x8A, 0x1E, 0x88, 0x51, 0x8B, 0xB9, 0x88, 0xF5, 0x88, 0x43, 0x88, 0xCB, 0x8B, 0x67, 0x88, 0x1F, 0x48, 0x50, 0x4B, 0xB8, 0x48, 0xF4, 0x48, 0x42, 0x4A, 0x2A, 0x48, 0x66, 0x49, 0x1E, 0x4A, 0xD1, 0x48, 0xB9, 0x49, 0xF5, 0x4B, 0x43, 0x4B, 0x2B, 0x4B, 0xE7, 0x48, 0x9F, 0xC8, 0x30, 0xC8, 0x78, 0xC9, 0x0C, 0xCB, 0xC2, 0xC9, 0xAA, 0xCB, 0x16, 0xC8, 0x5E, 0xCA, 0xB1, 0xCA, 0xF9, 0xCB, 0x4D, 0xC8, 0xA3, 0xCA, 0xEB, 0xC9, 0x97, 0xCB, 0x3F, 0x28, 0xF0, 0x2A, 0x84, 0x2B, 0x2C, 0x28, 0xE2, 0x2A, 0x9A, 0x29, 0x36, 0x28, 0x7E, 0x2A, 0x89, 0x29, 0x25, 0x28, 0x6D, 0x2A, 0x93, 0x2A, 0x3B, 0x28, 0x77, 0xA9, 0x80, 0xAB, 0x28, 0xA8, 0x64, 0xAB, 0x1C, 0xAB, 0x32, 0xA8, 0x7A, 0xA9, 0x8E, 0xA8, 0x21, 0xAA, 0x69, 0xA9, 0x95, 0xA8, 0xDD, 0xA9, 0x73, 0xA9, 0x87, 0xAA, 0xCF, 0x6B, 0x60, 0x6B, 0x98, 0x6A, 0xD4, 0x6B, 0x7C, 0x68, 0x8A, 0x6A, 0x26, 0x68, 0x6E, 0x68, 0x11, 0x6B, 0x99, 0x69, 0x55, 0x6A, 0xDD, 0x68, 0x33, 0x69, 0xBB, 0x69, 0x77, 0x6A, 0xFF, 0xE8, 0x08, 0xE9, 0x84, 0xE9, 0x4C, 0xEA, 0xC2, 0xEB, 0x2A, 0xE9, 0xA6, 0xE9, 0x6E, 0xE8, 0xE1, 0xEB, 0x19, 0xE9, 0x95, 0xEA, 0x5D, 0xE8, 0xD3, 0xE9, 0x3B, 0xE9, 0xB7, 0xEA, 0x7F, 0x18, 0xF0, 0x19, 0x04, 0x1B, 0x8C, 0x19, 0xC2, 0x1A, 0xCA, 0x1B, 0x26, 0x1B, 0xAE, 0x19, 0xE1, 0x18, 0x19, 0x18, 0x15, 0x1B, 0x9D, 0x19, 0xD3, 0x18, 0x3B, 0x18, 0xB7, 0x18, 0xBF, 0x9B, 0xF0, 0x9A, 0x04, 0x9A, 0x8C, 0x9A, 0xC2, 0x98, 0xCA, 0x99, 0x26, 0x99, 0xAE, 0x99, 0xE1, 0x98, 0xE9, 0x9B, 0x15, 0x9B, 0x9D, 0x99, 0xD3, 0x98, 0x3B, 0x98, 0xB7, 0x98, 0xBF, 0x5B, 0xF0, 0x5A, 0x04, 0x5A, 0x8C, 0x5A, 0xC2, 0x58, 0xCA, 0x59, 0x26, 0x59, 0xAE, 0x59, 0xE1, 0x58, 0xE9, 0x5B, 0x15, 0x59, 0x9D, 0x5A, 0xD3, 0x58, 0x3B, 0x58, 0x37, 0x5B, 0xBF, 0xD9, 0xF0, 0xDA, 0x04, 0xDA, 0x8C, 0xD8, 0x42, 0xDB, 0xCA, 0xD9, 0x26, 0xD9, 0xAE, 0xDA, 0x61, 0xDB, 0xE9, 0xD9, 0x15, 0xD9, 0x9D, 0xDA, 0x53, 0xDB, 0xDB, 0xDB, 0x37, 0xDB, 0xBF, 0x39, 0xF0, 0x38, 0x04, 0x38, 0x0C, 0x3B, 0x42, 0x3B, 0xCA, 0x3A, 0x26, 0x3A, 0xAE, 0x38, 0x61, 0x3B, 0xE9, 0x39, 0x15, 0x3A, 0x9D, 0x38, 0x53, 0x3B, 0xDB, 0x3B, 0x37, 0x39, 0xBF, 0xB9, 0xF0, 0xB8, 0x04, 0xB8, 0x0C, 0xBB, 0x42, 0xBB, 0xCA, 0xBA, 0x26, 0xBA, 0xAE, 0xBA, 0x61, 0xBB, 0xE9, 0xB9, 0x15, 0xBA, 0x9D, 0xBA, 0x53, 0xBB, 0xDB, 0xBB, 0x37, 0xBB, 0xBF, 0x79, 0xF0, 0x78, 0x04, 0x78, 0x8C, 0x78, 0x42, 0x7B, 0xCA, 0x7A, 0x26, 0x79, 0xAE, 0x7A, 0x61, 0x7B, 0xE9, 0x7B, 0x15, 0x79, 0x9D, 0x7A, 0xD3, 0x78, 0x3B, 0x78, 0x37, 0x7B, 0xBF, 0xFB, 0xF0, 0xF8, 0x04, 0xF8, 0x0C, 0xF9, 0x42, 0xF8, 0x4A, 0xF9, 0xC6, 0xFA, 0xCE, 0xFB, 0xA1, 0xF8, 0xA9, 0xFB, 0x65, 0xF9, 0x6D, 0xFB, 0x13, 0xFA, 0x9B, 0xF8, 0x97, 0xF9, 0x5F, 0x04, 0xD0, 0x06, 0x38, 0x06, 0x34, 0x07, 0xBC, 0x06, 0x72, 0x05, 0xFA, 0x06, 0xF6, 0x07, 0x81, 0x06, 0x89, 0x05, 0x45, 0x06, 0x4D, 0x07, 0xC3, 0x07, 0x2B, 0x06, 0xA7, 0x04, 0xAF, 0x85, 0x60, 0x87, 0xE8, 0x86, 0xE4, 0x85, 0x1C, 0x84, 0x92, 0x86, 0x9A, 0x87, 0x56, 0x86, 0x5E, 0x87, 0xD1, 0x87, 0x39, 0x85, 0x35, 0x87, 0xBD, 0x86, 0x73, 0x86, 0xFB, 0x84, 0xF7, 0x46, 0x00, 0x47, 0x08, 0x47, 0x84, 0x46, 0x8C, 0x47, 0xC2, 0x44, 0xCA, 0x44, 0xC6, 0x45, 0x2E, 0x44, 0xA1, 0x44, 0xA9, 0x46, 0xA5, 0x47, 0xFD, 0x8B, 0xC6, 0x89, 0xD6, 0x8B, 0xCE, 0x8F, 0x3E, 0x88, 0x21, 0x89, 0x31, 0x8B, 0x29, 0x8F, 0xB9, 0x88, 0xA5, 0x89, 0xB5, 0x8D, 0xAD, 0x8B, 0xBD, 0x8F, 0x63, 0x8E, 0x73, 0x8D, 0x6B, 0x8B, 0x7B, 0x8B, 0xE7, 0x8A, 0xF7, 0x89, 0xEF, 0x49, 0xF8, 0x95, 0x20, 0x98, 0x10, 0x94, 0x30, 0x9C, 0x08, 0x9E, 0x28, 0x9E, 0x18, 0x91, 0x38, 0x99, 0x04, 0x9B, 0x24, 0x93, 0x14, 0x97, 0x34, 0x07, 0x50, 0x31, 0xA5, 0xE4, 0xE4, 0xE4, 0xE5, 0x14, 0xB4, 0x14, 0xF5, 0x94, 0x8C, 0x94, 0x7F, 0xA9, 0xD8, 0xA9, 0xDA, 0xA9, 0x39, 0xA9, 0xDB, 0x69, 0xF8, 0x69, 0xFA, 0x69, 0xF9, 0x69, 0xFB, 0xE9, 0x84, 0xE9, 0x46, 0xE9, 0x45, 0xE9, 0x47, 0x19, 0xA4, 0x19, 0xA6, 0x19, 0xA5, 0x19, 0xA7, 0x99, 0xE4, 0x99, 0x16, 0x99, 0xE5, 0x99, 0xE7, 0x59, 0x94, 0x59, 0x56, 0x59, 0x95, 0x59, 0x97, 0xD9, 0xD4, 0xD9, 0x36, 0xD9, 0xD5, 0xD9, 0x57, 0x39, 0xB4, 0x39, 0xB6, 0x39, 0x35, 0x39, 0x37, 0x7F, 0x19, 0xFF, 0xBA, 0xFF, 0xED, 0xCE, 0x05, 0xC9, 0x95, 0xC8, 0x8D, 0xCD, 0x5D, 0xCC, 0xC3, 0xCC, 0xD3, 0xCD, 0x2B, 0xCA, 0x3B, 0xCB, 0xA7, 0xCD, 0x77, 0xCE, 0x6F, 0xCF, 0xFF, 0x2E, 0x10, 0x2E, 0x88, 0x28, 0x98, 0x29, 0x44, 0x2E, 0x54, 0x2F, 0xFC, 0x5B, 0x78, 0x50, 0x44, 0x5E, 0x64, 0x53, 0xD4, 0x50, 0xF4, 0x52, 0xCC, 0x5D, 0x1C, 0x50, 0x3C, 0x52, 0x02, 0x53, 0x22, 0x5F, 0x92, 0x52, 0xF2, 0xAF, 0x14, 0xAF, 0xD4, 0xA8, 0xB4, 0xAC, 0xF4, 0xAA, 0x8C, 0xB1, 0xCC, 0xB5, 0xAC, 0xB3, 0xFC, 0x57, 0xB9, 0x70, 0x79, 0x44, 0xF9, 0x4C, 0x05, 0x52, 0x85, 0x5A, 0x45, 0x56, 0xC5, 0x6E, 0x25, 0x71, 0xA5, 0x45, 0x65, 0x75, 0xE5, 0x7D, 0x15, 0x6B, 0x95, 0x57, 0x55, 0x6F, 0x35, 0x68, 0xB5, 0x78, 0x75, 0x4C, 0xF5, 0x7C, 0x0D, 0x5A, 0x8D, 0x66, 0x4D, 0x6E, 0xCD, 0x41, 0x2D, 0x79, 0xAD, 0x75, 0x6D, 0x7D, 0xED, 0x53, 0x1D, 0x67, 0x9D, 0x6F, 0xDD, 0x60, 0x3D, 0x44, 0xBD, 0x74, 0x7D, 0x7C, 0xFD, 0x72, 0x03, 0x66, 0x83, 0x6E, 0x43, 0x41, 0xC3, 0x49, 0x23, 0x75, 0xA3, 0x7D, 0x63, 0x73, 0xE3, 0x5B, 0x13, 0x6F, 0x53, 0x60, 0xD3, 0x68, 0x33, 0x4C, 0xB3, 0x7C, 0x73, 0x72, 0xF3, 0x7A, 0x0B, 0x5E, 0x8B, 0x61, 0x4B, 0x69, 0xCB, 0x45, 0x2B, 0x7D, 0xAB, 0x4B, 0x6B, 0x7B, 0xEB, 0x77, 0x9B, 0x60, 0x5B, 0x58, 0xDB, 0x54, 0x3B, 0x42, 0xBB, 0x4A, 0x7B, 0x66, 0xFB, 0x4E, 0x07, 0x51, 0x87, 0x79, 0x47, 0x75, 0xC7, 0x5D, 0x27, 0x6B, 0xA7, 0x57, 0x67, 0x5F, 0x17, 0x58, 0x97, 0x44, 0x57, 0x6C, 0xD7, 0x62, 0x37, 0x46, 0xB7, 0x4E, 0x77, 0x7E, 0xF7, 0x71, 0x0F, 0x55, 0x8F, 0x7D, 0x4F, 0x73, 0xCF, 0x7B, 0x2F, 0x5F, 0x6F, 0x70, 0xEF, 0x78, 0xDF, 0xEF, 0x3E, 0xA5, 0xBE, 0xCC, 0xBE, 0x83, 0x7E, 0xEA, 0x7E, 0x97, 0xFE, 0x9E, 0x01, 0xF0, 0x01, 0xB9, 0x81, 0xF4, 0x81, 0xBD, 0x41, 0xCA, 0x41, 0xA7, 0xC1, 0xAE, 0x21, 0xB0, 0x21, 0xD9, 0xA1, 0xB4, 0xA1, 0xDD, 0x61, 0x8A, 0x61, 0xC7, 0xE1, 0xCE, 0x11, 0xD0, 0x11, 0x99, 0x91, 0xD4, 0x91, 0x9D, 0x51, 0xF2, 0x51, 0x87, 0xD1, 0x8E, 0x31, 0x90, 0x31, 0x99, 0xB1, 0xD4, 0xB1, 0x9D, 0x71, 0xF2, 0x71, 0x87, 0xF1, 0x8E, 0x09, 0xD0, 0x09, 0x99, 0x89, 0xD4, 0x89, 0x9D, 0x49, 0xF2, 0x49, 0xC7, 0xC9, 0xCE, 0x29, 0xD0, 0x29, 0x99, 0xA9, 0xB4, 0xA9, 0xDD, 0x69, 0x8A, 0x69, 0xC7, 0xE9, 0xAE, 0x19, 0xB0, 0x19, 0xD9, 0x99, 0xB4, 0x99, 0xBD, 0x59, 0xCA, 0x59, 0xA7, 0xD9, 0xAE, 0x39, 0xF0, 0x39, 0xB9, 0xB9, 0xF4, 0xB9, 0xBD, 0x79, 0xCA, 0x79, 0xE7, 0xF9, 0xEE, 0x05, 0xF0, 0x05, 0xB9, 0x85, 0xF4, 0x85, 0xBD, 0x45, 0xAA, 0x45, 0xE7, 0xC5, 0xEE, 0x25, 0xF0, 0x25, 0xB9, 0xA5, 0xF4, 0xA5, 0xBD, 0x65, 0xAA, 0x65, 0xE7, 0xE5, 0xEE, 0x15, 0xF0, 0x15, 0xB9, 0x95, 0xF4, 0x95, 0xBD, 0x55, 0xCA, 0x55, 0xA7, 0xD5, 0xAE, 0x35, 0xF0, 0x35, 0xB9, 0xB5, 0xF4, 0xB5, 0xBD, 0x75, 0xCA, 0x75, 0xA7, 0xF5, 0xAE, 0x7F, 0x60, 0xFF, 0x64, 0xFF, 0xA5, 0xFF, 0xDB, 0xDB, 0xA0, 0xDC, 0x70, 0xDA, 0xE8, 0xDA, 0x04, 0xDB, 0x94, 0xDD, 0x4C, 0xDB, 0xDC, 0xDD, 0xA2, 0xDC, 0x72, 0xDA, 0xEA, 0xDA, 0x06, 0xDB, 0x96, 0xDD, 0x4E, 0xDB, 0xDE, 0xDD, 0xA1, 0xD8, 0x71, 0xDC, 0xE9, 0xDC, 0x05, 0xDB, 0x95, 0xDD, 0x4D, 0xDB, 0xDD, 0xDD, 0xA3, 0xD8, 0x73, 0xDC, 0xEB, 0xDC, 0x07, 0xDD, 0x97, 0xD9, 0x4F, 0xDD, 0xDF, 0x3D, 0xA0, 0x38, 0x70, 0x3C, 0xE8, 0x3C, 0x04, 0x3D, 0x94, 0x39, 0x4C, 0x3D, 0xDC, 0x3C, 0xC2, 0x38, 0x92, 0x3D, 0x0A, 0x3E, 0xEA, 0x38, 0xBA, 0x39, 0x26, 0x39, 0xD6, 0x3A, 0x4E, 0x38, 0x1E, 0x3D, 0xFE, 0x3A, 0x61, 0x3A, 0xB1, 0x38, 0xC9, 0x3D, 0x59, 0x3E, 0x85, 0x39, 0x15, 0x38, 0x75, 0x3B, 0xAD, 0x3E, 0x3D, 0x38, 0xC3, 0x38, 0x93, 0x3D, 0x0B, 0x3E, 0xEB, 0x38, 0xBB, 0x3D, 0x27, 0x3D, 0xD7, 0x3E, 0x4F, 0x3A, 0x1F, 0x3F, 0xFF, 0xB9, 0x60, 0xB9, 0xB0, 0xBA, 0xC8, 0xBF, 0x58, 0xBD, 0xFC, 0x7D, 0x29, 0x74, 0xE9, 0x71, 0x59, 0x7B, 0x79, 0x74, 0x85, 0x7D, 0xA5, 0x70, 0x15, 0x76, 0xD5, 0x73, 0xF5, 0x78, 0x4D, 0x79, 0xAD, 0x7F, 0x9D, 0x7A, 0x3D, 0x75, 0x03, 0x0C, 0x18, 0xB3, 0x76, 0x37, 0xC5, 0x37, 0x1B, 0xB7, 0x88, 0xB7, 0x62, 0xB7, 0x3E, 0xB7, 0x8D, 0xB7, 0xE7, 0x77, 0x04, 0x77, 0xAA, 0x77, 0xD1, 0x77, 0x03, 0x77, 0x6F, 0xF7, 0x74, 0xF7, 0x26, 0xF7, 0x59, 0xF7, 0x0B, 0x0F, 0x90, 0x0F, 0xBC, 0x0F, 0xCE, 0x0F, 0x95, 0x0F, 0x7B, 0x8F, 0xE8, 0x8F, 0x32, 0x8F, 0xC1, 0x8F, 0x1D, 0x8F, 0xB7, 0x4F, 0xA4, 0x4F, 0x3A, 0x4F, 0x49, 0x4F, 0xE3, 0xCF, 0xBF, 0x9E, 0x59, 0x9F, 0xAD, 0x9F, 0x0B, 0x9F, 0xD7, 0x5F, 0xE0, 0x5F, 0x44, 0x5F, 0xBC, 0x5F, 0x1A, 0x5E, 0xCE, 0x5E, 0xF1, 0x5F, 0x55, 0x5F, 0xA3, 0x5F, 0x07, 0x5E, 0xDF, 0xDE, 0xE8, 0xDE, 0x4C, 0xDF, 0xB2, 0xDF, 0x16, 0xDE, 0xA1, 0xDE, 0xF9, 0xDE, 0x5D, 0xDF, 0xAB, 0xDE, 0x0F, 0x3E, 0x30, 0x3F, 0xE4, 0x3E, 0x42, 0x3F, 0xBA, 0x3E, 0x1E, 0x3E, 0x29, 0x3E, 0xF5, 0x3F, 0x53, 0x3F, 0xA7, 0xBF, 0x40, 0xBE, 0x38, 0xBF, 0xEC, 0xBF, 0x4A, 0xBF, 0xB6, 0xBE, 0x51, 0xBE, 0x25, 0xBF, 0x03, 0xBE, 0xDB, 0xBE, 0xAF, 0x7F, 0x48, 0x7E, 0xB4, 0x7E, 0x12, 0x7F, 0xC6, 0xFE, 0xC7, 0x32, 0x62, 0xFE, 0x65, 0xFE, 0x2B, 0xE7, 0xD7, 0x3C, 0x10, 0x18, 0x10, 0x07, 0x90, 0x0D, 0x50, 0x01, 0xD0, 0x0A, 0x30, 0x34, 0x30, 0x2F, 0xB0, 0x23, 0x70, 0x29, 0xF0, 0x06, 0x08, 0x3C, 0x88, 0x10, 0x88, 0x3B, 0x48, 0x15, 0xC8, 0x2E, 0x28, 0x2A, 0xA8, 0x04, 0xA8, 0x0F, 0x68, 0x3D, 0xE8, 0x31, 0x18, 0x16, 0x98, 0x2C, 0x58, 0x10, 0x58, 0x2B, 0xD8, 0x05, 0x38, 0x01, 0xB8, 0x32, 0x78, 0x38, 0x78, 0x37, 0xF8, 0x1D, 0x04, 0x29, 0x84, 0x26, 0x44, 0x2C, 0xC4, 0x20, 0xC4, 0x0B, 0x24, 0x35, 0xA4, 0x3E, 0x64, 0x32, 0xE4, 0x38, 0xE4, 0x17, 0x14, 0x23, 0x94, 0x29, 0x54, 0x16, 0xD4, 0x2C, 0x34, 0x28, 0x34, 0x3B, 0xB4, 0x35, 0x74, 0x3E, 0xF4, 0x32, 0x0C, 0x34, 0x0C, 0x2F, 0x8C, 0x13, 0x4C, 0x29, 0xCC, 0x26, 0x2C, 0x22, 0xAC, 0x08, 0xAC, 0x27, 0x6C, 0x0D, 0xEC, 0xC1, 0x6F, 0xF4, 0xDF, 0xD2, 0xBF, 0xFD, 0x7F, 0x37, 0xFF, 0x3E, 0x87, 0xC3, 0x83, 0x53, 0x82, 0x0B, 0x83, 0xEB, 0x82, 0xBB, 0x83, 0x27, 0x81, 0xD7, 0x84, 0x8F, 0x83, 0x1F, 0x84, 0x7F, 0x45, 0xA0, 0x46, 0x30, 0x40, 0x48, 0x45, 0x98, 0x40, 0xF8, 0x41, 0x64, 0x46, 0xB4, 0x40, 0xCC, 0x41, 0x5C, 0x40, 0x82, 0x40, 0xE2, 0x42, 0xB2, 0x47, 0x2A, 0x06, 0x50, 0x1E, 0x0E, 0x59, 0x08, 0xD9, 0x1D, 0xB9, 0x0A, 0x79, 0x0F, 0x05, 0x0D, 0xC0, 0x78, 0x7F, 0x94, 0x26, 0x94, 0x33, 0x54, 0x3C, 0x54, 0x25, 0xD4, 0x30, 0xD4, 0x2E, 0xD4, 0x3B, 0x34, 0x52, 0x34, 0x2D, 0xB4, 0x78, 0xB4, 0x21, 0xB4, 0x37, 0x74, 0x5A, 0x74, 0x23, 0xF4, 0x74, 0xF4, 0x69, 0x0C, 0x60, 0x0C, 0x36, 0x0C, 0x2B, 0x8C, 0x3C, 0x8C, 0x65, 0x4C, 0x68, 0x4C, 0x3E, 0x4C, 0x67, 0xCC, 0x72, 0xCC, 0x6D, 0x2C, 0x64, 0x2C, 0x09, 0xAC, 0x30, 0xAC, 0x21, 0x6C, 0x60, 0x6C, 0x7E, 0x6C, 0x5F, 0xEC, 0x4E, 0xEC, 0x37, 0x1C, 0x36, 0x1C, 0x17, 0x9C, 0x06, 0x9C, 0x5B, 0x5C, 0x5A, 0x5C, 0x6B, 0xDC, 0x0A, 0xDC, 0x53, 0x3C, 0x12, 0x3C, 0x23, 0xBC, 0x7C, 0xBC, 0x1D, 0x7C, 0x5C, 0x7C, 0x2D, 0xFC, 0x0C, 0xFC, 0x55, 0x02, 0x54, 0x02, 0x45, 0x82, 0x78, 0x82, 0x99, 0x3F, 0xB0, 0x7F, 0x24, 0xFF, 0x84, 0xFF, 0x19, 0x21, 0x04, 0x23, 0x14, 0x22, 0x0C, 0x20, 0xEC, 0x25, 0xFC, 0x02, 0x50, 0xDE, 0x83, 0xA8, 0x95, 0xE8, 0x99, 0x98, 0x99, 0xD8, 0x91, 0xB8, 0x8E, 0xF8, 0x9A, 0x84, 0x86, 0xC4, 0x8A, 0xA4, 0x9C, 0xE4, 0x94, 0x94, 0x94, 0xD4, 0x98, 0xB4, 0x90, 0x74, 0x8F, 0x0C, 0x9F, 0x4C, 0x97, 0x2C, 0x9B, 0x6C, 0x83, 0x1C, 0x93, 0x5C, 0x8D, 0x3C, 0x95, 0x7C, 0x89, 0x02, 0x99, 0x42, 0x81, 0x22, 0x9E, 0x62, 0x86, 0xF2, 0x37, 0xA5, 0x14, 0x65, 0x24, 0xE5, 0x18, 0x15, 0x04, 0x95, 0x28, 0x55, 0x30, 0xD5, 0x20, 0x35, 0x10, 0x35, 0x3F, 0xB5, 0x1F, 0x75, 0x37, 0xF5, 0x27, 0x0D, 0x17, 0x8D, 0x07, 0x4D, 0x1B, 0xCD, 0x0B, 0x2D, 0x2B, 0xAD, 0x33, 0x6D, 0x23, 0xED, 0x3D, 0x1D, 0x03, 0x9D, 0x1D, 0x5D, 0x0D, 0xDD, 0x15, 0x3D, 0x35, 0xBD, 0x15, 0x7D, 0x05, 0xFD, 0x29, 0x03, 0x19, 0x83, 0x29, 0x43, 0x31, 0xC3, 0x21, 0x23, 0x11, 0xA3, 0x21, 0x63, 0x3E, 0xE3, 0x2E, 0x13, 0x3E, 0x93, 0x2E, 0x53, 0x0E, 0xD3, 0x26, 0x33, 0x36, 0xB3, 0x26, 0x73, 0x06, 0xF3, 0x1A, 0x0B, 0x3A, 0x8B, 0x2A, 0x4B, 0x0A, 0xCB, 0x32, 0x2B, 0x0A, 0xAB, 0x12, 0x6B, 0x22, 0xEB, 0x3C, 0x1B, 0x22, 0x9B, 0x3C, 0x5B, 0x1C, 0xDB, 0x0C, 0x3B, 0x1C, 0xBB, 0x0C, 0x80, 0xF4, 0x93, 0x1C, 0x30, 0x1C, 0x92, 0x1C, 0x11, 0x1C, 0xA3, 0x9C, 0x60, 0x9C, 0x42, 0x9C, 0x01, 0x9C, 0xBD, 0x9C, 0x9F, 0x5C, 0x9C, 0x5C, 0xEE, 0x5C, 0x2D, 0x5C, 0x8F, 0xDC, 0x8C, 0xDC, 0xF6, 0xDC, 0x35, 0xDC, 0x97, 0x3C, 0x94, 0x3C, 0xE6, 0x3C, 0x25, 0x3C, 0x87, 0xBC, 0x84, 0xBC, 0x06, 0xBC, 0xB9, 0xBC, 0x5B, 0x7C, 0xD8, 0x7C, 0x1A, 0x7C, 0x69, 0x7C, 0xCB, 0xFC, 0x28, 0xFC, 0x8A, 0xFC, 0xF1, 0xFC, 0x33, 0x02, 0xB0, 0x02, 0x52, 0x02, 0x11, 0x02, 0xA3, 0x82, 0x60, 0x82, 0xC2, 0x82, 0x81, 0x82, 0x7D, 0x82, 0x3F, 0x42, 0x3C, 0x42, 0x5E, 0x42, 0x1D, 0x42, 0xAF, 0xC2, 0xAC, 0xC2, 0x2E, 0xC2, 0x8D, 0xC2, 0xF7, 0x22, 0xF4, 0x22, 0x76, 0x22, 0xD5, 0x22, 0x97, 0xA2, 0x94, 0xA2, 0x16, 0xA2, 0xA5, 0xA2, 0xC7, 0x62, 0xC4, 0x62, 0x46, 0x62, 0xF9, 0x62, 0xBB, 0xE2, 0xF8, 0xE2, 0x3A, 0xE2, 0xD9, 0xE2, 0xFF, 0x24, 0x30, 0x25, 0xD4, 0x25, 0x52, 0x25, 0x96, 0x25, 0x51, 0x24, 0x15, 0x25, 0x13, 0x24, 0xE7, 0xA4, 0xE0, 0xA5, 0x64, 0xA4, 0xA2, 0xA5, 0x26, 0x01, 0xFC, 0x17, 0x97, 0x0E, 0x93, 0x1E, 0x91, 0x01, 0x93, 0x11, 0x96, 0x09, 0x92, 0x19, 0x90, 0x05, 0x92, 0xE5, 0x93, 0xF5, 0x95, 0xED, 0x96, 0xFD, 0x94, 0xE3, 0x92, 0xF3, 0x94, 0x6B, 0x97, 0x7B, 0x95, 0x67, 0x97, 0x77, 0x93, 0x6F, 0x91, 0x7F, 0x52, 0x60, 0x56, 0x70, 0x52, 0x68, 0x50, 0xB8, 0x53, 0x64, 0x50, 0xB4, 0x57, 0xAC, 0x55, 0xBC, 0x56, 0xA2, 0x51, 0xB2, 0x51, 0xAA, 0x52, 0xBA, 0x50, 0xA6, 0x54, 0xB6, 0x54, 0x2E, 0x57, 0x3E, 0x55, 0x21, 0x57, 0x31, 0x53, 0x29, 0x05, 0x6C, 0x01, 0x12, 0x55, 0x13, 0xD5, 0x22, 0xD5, 0x43, 0x35, 0x22, 0x35, 0x23, 0xB5, 0x02, 0xB5, 0x7D, 0xF5, 0x3F, 0xEA, 0x06, 0xEA, 0x79, 0xEA, 0xDB, 0x80, 0x3D, 0xA0, 0xA6, 0x91, 0xA4, 0x31, 0xAB, 0x09, 0xAB, 0x29, 0xAE, 0x19, 0xAC, 0xD9, 0xA7, 0xF9, 0xA9, 0xC5, 0xAE, 0xE5, 0xAC, 0x55, 0xA7, 0x75, 0xA9, 0x4D, 0xAE, 0x6D, 0xAC, 0x9D, 0xA7, 0xBD, 0xA9, 0x83, 0xA1, 0xA3, 0xAC, 0x13, 0xAF, 0x33, 0xA5, 0x0B, 0xA1, 0x2B, 0xA4, 0xEB, 0xA7, 0xDB, 0xA9, 0xFB, 0xAC, 0xC7, 0xA8, 0x67, 0xAB, 0x57, 0xAE, 0x77, 0xA4, 0x4F, 0xA0, 0xAF, 0xAD, 0x9F, 0xAE, 0xBF, 0x68, 0x00, 0x6F, 0x20, 0x69, 0x10, 0x62, 0xD0, 0x6F, 0xF0, 0x69, 0xC8, 0x6E, 0xE8, 0x64, 0x58, 0x63, 0x78, 0x6E, 0x44, 0x62, 0xA4, 0x6F, 0x94, 0x6D, 0xB4, 0x6A, 0x8C, 0x64, 0x2C, 0x63, 0x1C, 0x6E, 0x3C, 0x64, 0xFC, 0x63, 0xC2, 0x69, 0xE2, 0x62, 0x52, 0x67, 0x72, 0x61, 0x4A, 0x6A, 0x6A, 0x68, 0x9A, 0x03, 0xD8, 0x07, 0xC8, 0x66, 0xB2, 0x66, 0x11, 0x66, 0x43, 0x66, 0x3F, 0xE6, 0x1C, 0xE6, 0xCE, 0xE6, 0xB5, 0xE6, 0xE7, 0x16, 0x24, 0x16, 0xFA, 0x16, 0x59, 0x16, 0x2B, 0x96, 0x08, 0x96, 0x52, 0x96, 0xA1, 0x96, 0xFD, 0x96, 0x1F, 0x56, 0xAC, 0x56, 0x0E, 0x56, 0x55, 0x56, 0xC7, 0xD6, 0x7F, 0xAC, 0xB5, 0xAD, 0x53, 0xAD, 0xE7, 0x6D, 0x60, 0x6C, 0x44, 0x6D, 0xFC, 0x6D, 0x3A, 0x6D, 0x9E, 0x6C, 0xE9, 0x6D, 0x2D, 0x6D, 0x8B, 0x6D, 0x77, 0xEC, 0xB0, 0xEC, 0x94, 0xED, 0x62, 0xED, 0xC6, 0xED, 0x41, 0xEC, 0x79, 0xED, 0xDD, 0xED, 0x1B, 0xEC, 0xAF, 0x1C, 0xC8, 0x1C, 0x0C, 0x1C, 0xB2, 0x1C, 0x56, 0x1C, 0x11, 0x1C, 0x25, 0x1D, 0x83, 0x1D, 0x7B, 0x1C, 0x5F, 0x9D, 0x98, 0x9C, 0x6C, 0x9C, 0x4A, 0x9D, 0xF6, 0x9C, 0xB1, 0x9D, 0x55, 0x9C, 0xE3, 0x9C, 0xC7, 0x5D, 0x40, 0x00, 0x8B, 0xC1, 0xCD, 0xA5, 0xDE, 0xE5, 0xDC, 0x95, 0xC4, 0xD5, 0xC0, 0x35, 0xDF, 0x75, 0xCF, 0xED, 0x8F, 0x9B, 0x81, 0x5B, 0x9E, 0xDB, 0xAE, 0x3B, 0x81, 0xBB, 0x9E, 0x7B, 0xAE, 0xFB, 0x8E, 0x07, 0x9E, 0x87, 0xAE, 0xC7, 0x5F, 0x8F, 0x2D, 0x4F, 0x5C, 0x4F, 0x6D, 0xCF, 0x6C, 0xCF, 0x0D, 0x2F, 0x2C, 0x2F, 0x4D, 0xAF, 0x0C, 0xAF, 0x35, 0x6F, 0x0C, 0x6F, 0x35, 0xEF, 0x54, 0xEF, 0x65, 0x1F, 0x54, 0x1F, 0x65, 0x9F, 0x24, 0x9F, 0x05, 0x5F, 0x44, 0x5F, 0x79, 0xDF, 0x38, 0xDF, 0x19, 0xBF, 0xDF, 0x7E, 0xD2, 0x7E, 0x51, 0x7E, 0x13, 0xFE, 0x50, 0xFE, 0xE2, 0xFE, 0x61, 0xFE, 0x23, 0x01, 0xA0, 0x01, 0x42, 0x01, 0x81, 0x01, 0xFD, 0x01, 0x3F, 0x81, 0xBC, 0x81, 0x3E, 0x81, 0x9D, 0x81, 0xEF, 0x41, 0x1C, 0x41, 0x6E, 0x41, 0x2D, 0x41, 0x8F, 0xC1, 0x4C, 0xC1, 0x0E, 0xC1, 0xB5, 0xC1, 0xD7, 0x21, 0xD4, 0x21, 0x96, 0x21, 0xE5, 0x21, 0x27, 0xA1, 0x24, 0xA1, 0x46, 0xA1, 0x05, 0xA1, 0xBB, 0x61, 0x78, 0x61, 0xDA, 0x61, 0x99, 0x61, 0x6B, 0xE1, 0x68, 0xE1, 0xCA, 0xE1, 0x89, 0xE1, 0xB3, 0x11, 0xBF, 0x23, 0xA4, 0x22, 0x22, 0x22, 0x46, 0x22, 0x41, 0x23, 0x05, 0x23, 0xFD, 0x22, 0xBB, 0x23, 0x3F, 0xA2, 0xD8, 0xA3, 0x5C, 0xA3, 0x1A, 0xA3, 0x6E, 0xA3, 0x69, 0xA3, 0xAD, 0xA2, 0xCB, 0xA3, 0x8F, 0x63, 0x88, 0x62, 0xF4, 0x63, 0x72, 0x62, 0x36, 0x62, 0x31, 0x62, 0x55, 0x62, 0x13, 0x63, 0x67, 0xE3, 0x60, 0xE3, 0x24, 0xE2, 0x42, 0xE3, 0x06, 0xE3, 0x7F, 0xC5, 0x73, 0xC7, 0x7B, 0xC4, 0xB7, 0xC4, 0x3F, 0x24, 0xD0, 0x27, 0x58, 0x27, 0x94, 0x27, 0x1C, 0x25, 0x12, 0x26, 0xEA, 0x25, 0x66, 0x25, 0xAE, 0x25, 0xA1, 0x24, 0x29, 0x24, 0xC5, 0x24, 0x8D, 0x27, 0x83, 0x27, 0x0B, 0x26, 0xFB, 0x26, 0x77, 0x26, 0xBF, 0xA4, 0x30, 0xA7, 0xB8, 0xA5, 0xF4, 0xA6, 0x42, 0xA6, 0xCA, 0xA7, 0xA6, 0xA7, 0xEE, 0xA6, 0x51, 0xA4, 0x39, 0xA4, 0xB5, 0xA7, 0x03, 0xA5, 0x4B, 0xA4, 0x27, 0xA4, 0xAF, 0x67, 0xFC, 0xC9, 0xB0, 0xC8, 0xA8, 0xCF, 0x78, 0xCB, 0xE4, 0xCF, 0x0C, 0xCF, 0x9C, 0xCB, 0xC2, 0xC8, 0xD2, 0xCB, 0x2A, 0xCD, 0xBA, 0xC9, 0x66, 0xCD, 0xF6, 0xCD, 0x1E, 0xC9, 0xF9, 0x9D, 0xA3, 0x92, 0x93, 0x9D, 0x73, 0xF0, 0x97, 0xEA, 0xAF, 0xE3, 0xDF, 0x8E, 0x5C, 0xA0, 0x5C, 0xF1, 0xDC, 0xF8, 0xDC, 0xD5, 0x3C, 0xBC, 0x3C, 0x93, 0xBC, 0xAA, 0xBC, 0xC7, 0x7C, 0xAE, 0xFC, 0xC0, 0xFC, 0xF1, 0x02, 0x84, 0x02, 0xB5, 0x82, 0xBF, 0x05, 0x47, 0x85, 0xD4, 0x85, 0x4E, 0x85, 0x1D, 0x45, 0x40, 0x45, 0xE2, 0x45, 0x71, 0x45, 0xCB, 0xC5, 0x38, 0xC5, 0x46, 0xC5, 0x15, 0xC5, 0x77, 0x25, 0xEC, 0x25, 0xBE, 0x25, 0xC3, 0xA5, 0xB0, 0xA5, 0x4A, 0xA5, 0x19, 0xA5, 0xBB, 0x65, 0x64, 0x65, 0x36, 0x65, 0x4D, 0x65, 0xEF, 0xE5, 0x02, 0xE5, 0xE1, 0x80, 0xED, 0x80, 0x5A, 0xA1, 0x55, 0x51, 0x50, 0x71, 0x5A, 0x49, 0x57, 0xE9, 0x52, 0xD9, 0x59, 0x05, 0x5C, 0x25, 0x5E, 0x15, 0x5B, 0xB5, 0x5C, 0x8D, 0x5D, 0x6D, 0x58, 0x5D, 0x56, 0x7D, 0x5D, 0xC3, 0x52, 0xE3, 0x55, 0x33, 0x50, 0x0B, 0x55, 0x2B, 0x57, 0x9B, 0x5A, 0xBB, 0x59, 0x47, 0x54, 0x67, 0x59, 0x57, 0x57, 0xF7, 0x52, 0xCF, 0x5B, 0x1F, 0x52, 0x3F, 0xD9, 0x80, 0xD4, 0xA0, 0xD1, 0x90, 0x07, 0x58, 0x0E, 0xB4, 0x8D, 0x2E, 0x8D, 0x5D, 0x4D, 0x20, 0x4D, 0x92, 0x4D, 0x09, 0x4D, 0x6B, 0xCD, 0xF8, 0xCD, 0xA6, 0xCD, 0xD5, 0xCD, 0x8F, 0x2D, 0x5C, 0x2D, 0x41, 0x2D, 0x13, 0xAD, 0x88, 0xAD, 0xEA, 0xAD, 0x79, 0xAD, 0x27, 0x6D, 0xB4, 0x6D, 0xAE, 0x6D, 0x3D, 0xED, 0xB0, 0xED, 0x3A, 0xED, 0xB5, 0x1D, 0xBF, 0x3A, 0x14, 0x3A, 0x0A, 0x3B, 0x1E, 0x3B, 0x45, 0x3B, 0xD3, 0x3A, 0xCF, 0xBA, 0x38, 0xBB, 0xA2, 0xBB, 0xB6, 0xBA, 0xE9, 0xBA, 0x03, 0xBA, 0x17, 0x7A, 0x88, 0x7B, 0x5C, 0x7B, 0x46, 0x7B, 0x31, 0x7B, 0xAD, 0x7A, 0xBB, 0xFB, 0xE0, 0xFB, 0x0C, 0xFA, 0x1A, 0xFB, 0x41, 0xFB, 0x55, 0xFB, 0xCB, 0xFA, 0xDF, 0x07, 0x64, 0x06, 0x72, 0x07, 0xEE, 0x06, 0x85, 0x06, 0x53, 0x06, 0x4F, 0x86, 0x38, 0x86, 0xA2, 0x87, 0xB6, 0x87, 0xE9, 0x87, 0x83, 0x86, 0x97, 0x47, 0xC8, 0x46, 0x3C, 0x47, 0xA6, 0x46, 0xF1, 0x01, 0x4B, 0x61, 0x68, 0x0C, 0x6D, 0xCC, 0x62, 0xAC, 0x73, 0x1C, 0x6E, 0xDC, 0x60, 0xBC, 0x71, 0x02, 0x7C, 0x42, 0x63, 0xA2, 0x6A, 0xE2, 0x7B, 0x52, 0x61, 0xB2, 0x68, 0xF2, 0x65, 0x4A, 0x72, 0x2A, 0x67, 0xEA, 0x76, 0x5A, 0x68, 0x3A, 0x75, 0xFA, 0x6C, 0x86, 0x7B, 0x26, 0x7E, 0xE6, 0x60, 0x96, 0x75, 0x36, 0x62, 0x76, 0x6B, 0x8E, 0x7E, 0x2E, 0x68, 0x6E, 0x05, 0xB0, 0x10, 0x7C, 0xE6, 0xE7, 0x17, 0x88, 0x17, 0xDC, 0x17, 0x26, 0x17, 0xF1, 0x17, 0x1D, 0x17, 0x47, 0x96, 0x30, 0x97, 0x6C, 0x96, 0xFA, 0x97, 0x51, 0x96, 0xCD, 0x97, 0xBB, 0x56, 0xE0, 0x57, 0x8C, 0x56, 0x5A, 0x57, 0x61, 0x56, 0xF5, 0x56, 0x1B, 0x01, 0xDB, 0x40, 0x73, 0xAD, 0x66, 0x1D, 0x78, 0x5D, 0x75, 0xBD, 0x62, 0xFD, 0xFB, 0x9F, 0xE2, 0xBF, 0x92, 0x7F, 0xEF, 0x1B, 0xB2, 0x1B, 0x85, 0x1B, 0x2F, 0x9B, 0x52, 0x9B, 0xB9, 0x9B, 0x0F, 0x5B, 0xE2, 0x5B, 0xD9, 0x5B, 0xB7, 0xDB, 0x22, 0xDB, 0x19, 0xDB, 0x57, 0x3B, 0x82, 0x3B, 0xA9, 0x3B, 0x17, 0xBB, 0x7C, 0xBB, 0xC9, 0xBB, 0x67, 0x7B, 0x3C, 0x7B, 0x89, 0x7B, 0x27, 0xFB, 0x5C, 0xFB, 0x1E, 0xFB, 0x8D, 0xFB, 0xD7, 0x07, 0xE4, 0x07, 0x86, 0x07, 0xD9, 0x07, 0xAB, 0x87, 0x88, 0x87, 0x52, 0x87, 0xA1, 0x87, 0x7D, 0x87, 0x1F, 0x47, 0x2C, 0x47, 0x76, 0x47, 0x15, 0x47, 0x87, 0xC7, 0xF8, 0xC7, 0x1A, 0xC7, 0xC9, 0xC7, 0x33, 0x27, 0x50, 0x27, 0x42, 0x27, 0xBE, 0x27, 0xED, 0x27, 0x0F, 0xA7, 0xB4, 0xA7, 0x16, 0xA7, 0x85, 0xA7, 0xDB, 0x67, 0x98, 0x67, 0x4A, 0x67, 0xB1, 0x67, 0xE3, 0xE7, 0xA0, 0xE7, 0x7C, 0xE7, 0x1E, 0xE7, 0x4D, 0xE7, 0x37, 0x17, 0x94, 0x17, 0x26, 0x17, 0x79, 0x17, 0x1B, 0x97, 0x68, 0x97, 0x0A, 0x97, 0xD1, 0x97, 0xA3, 0x57, 0xC0, 0x57, 0x3C, 0x57, 0xEE, 0x57, 0x4D, 0x57, 0x37, 0x80, 0x3D, 0x60, 0x72, 0x9D, 0x77, 0xBD, 0x79, 0x83, 0x7E, 0xA3, 0x78, 0x13, 0x7B, 0x33, 0x7E, 0x0B, 0x7A, 0xCB, 0x7F, 0xEB, 0x75, 0xDB, 0x7A, 0x7B, 0x7F, 0x47, 0x7B, 0x67, 0x71, 0x57, 0x7C, 0xB7, 0x7B, 0x8F, 0x73, 0xAF, 0x76, 0x9F, 0x74, 0x3F, 0xFB, 0x00, 0xFD, 0x20, 0xFA, 0x10, 0xF8, 0xD0, 0xF3, 0xF0, 0xF6, 0xC8, 0xF2, 0xE8, 0xF0, 0x58, 0xFD, 0x78, 0xF6, 0x44, 0xFC, 0xA4, 0xFF, 0x94, 0xFD, 0xB4, 0xF6, 0x8C, 0xF2, 0x2C, 0xFF, 0x1C, 0xFD, 0x3C, 0xF6, 0x02, 0xFA, 0xC2, 0x0F, 0xD8, 0x01, 0xED, 0x2F, 0x4F, 0xAF, 0x0C, 0xAF, 0x36, 0xAF, 0xE5, 0xAF, 0x47, 0x6F, 0x84, 0x6F, 0xBA, 0x6F, 0x99, 0x6F, 0xAB, 0xEF, 0xC8, 0xEF, 0x72, 0xEF, 0xD1, 0xEF, 0x63, 0x1F, 0x60, 0x1F, 0x02, 0x1F, 0xBE, 0x1F, 0x1D, 0x1F, 0x2F, 0x9F, 0x4C, 0x9F, 0xF6, 0x9F, 0x55, 0x9F, 0x67, 0x5F, 0xA4, 0x5F, 0x86, 0x5F, 0xB9, 0x5F, 0x9B, 0xDF, 0x18, 0xDF, 0x2A, 0xDF, 0x89, 0xDF, 0xB3, 0x3F, 0x30, 0x3F, 0xE2, 0x3F, 0x21, 0x3F, 0x03, 0xFF, 0x83, 0xFF, 0x3C, 0xBF, 0x3C, 0x7F, 0xB5, 0xFC, 0x7A, 0x00, 0xA2, 0x07, 0xD0, 0xBF, 0x1C, 0xE8, 0x18, 0x98, 0x08, 0x58, 0x1F, 0x38, 0x07, 0x78, 0x1D, 0x04, 0x0D, 0x44, 0x09, 0x24, 0x1E, 0x64, 0x1A, 0x14, 0x1A, 0x54, 0x0C, 0x34, 0x08, 0xB4, 0x0F, 0xF4, 0x0B, 0x8C, 0x13, 0xCC, 0x0D, 0xAC, 0x09, 0xEC, 0x0E, 0x9C, 0x16, 0xDC, 0x0A, 0xBC, 0x0C, 0xFC, 0x08, 0x82, 0x10, 0x42, 0x17, 0x22, 0x0B, 0x62, 0x0D, 0x12, 0x15, 0x52, 0x11, 0x32, 0x0E, 0x72, 0x0A, 0x0A, 0x0A, 0x4A, 0x14, 0x2A, 0x08, 0xAA, 0x0F, 0xEA, 0x1B, 0x9A, 0x0B, 0xDA, 0x1D, 0xBA, 0x19, 0xFA, 0x1E, 0x86, 0x0E, 0xC6, 0x1A, 0xA6, 0x1C, 0xE6, 0x18, 0x96, 0x08, 0x56, 0x1F, 0x36, 0x07, 0x76, 0xE3, 0x37, 0xC6, 0x6F, 0x95, 0xDF, 0x89, 0xBF, 0x67, 0xE1, 0x60, 0xE1, 0x24, 0x00, 0xAC, 0x1F, 0x82, 0x07, 0x02, 0x58, 0xBD, 0x17, 0x7C, 0x3B, 0xFC, 0x33, 0x02, 0x13, 0x82, 0x3D, 0x42, 0x35, 0xC2, 0x05, 0x22, 0x39, 0xA2, 0x09, 0x62, 0x01, 0xE2, 0x2E, 0x12, 0x2E, 0x92, 0x26, 0x52, 0x1A, 0xD2, 0x32, 0x32, 0x12, 0xB2, 0x1C, 0x72, 0x0C, 0xF2, 0x04, 0x0A, 0x04, 0x8A, 0x30, 0x4A, 0x20, 0x4A, 0x2F, 0xCA, 0x27, 0x2A, 0x27, 0xAA, 0x1B, 0x6A, 0x13, 0xEA, 0x3D, 0x1A, 0x1D, 0x9A, 0x35, 0x5A, 0x05, 0xDA, 0x09, 0x3A, 0x09, 0xBA, 0x21, 0x7A, 0x2E, 0xFA, 0x16, 0x06, 0x16, 0x86, 0x3A, 0x46, 0x0A, 0xC6, 0x02, 0x26, 0x02, 0xA6, 0x0C, 0x66, 0x14, 0xE6, 0x18, 0x16, 0x38, 0x96, 0x10, 0x96, 0x3F, 0x56, 0x0F, 0xD6, 0x07, 0x36, 0x07, 0xB6, 0x2B, 0x76, 0x13, 0xF6, 0x1D, 0x0E, 0x1D, 0x8E, 0x35, 0x4E, 0x05, 0xCE, 0x09, 0x2E, 0x09, 0xAE, 0x21, 0x6E, 0x1E, 0xEE, 0x36, 0x1E, 0x36, 0x9E, 0x06, 0x5E, 0x3A, 0xDE, 0x26, 0x3E, 0x21, 0xBE, 0x19, 0x7E, 0x15, 0xFE, 0x3D, 0x01, 0x1B, 0x81, 0x37, 0x41, 0xFF, 0x1F, 0x88, 0x3F, 0xD2, 0x7F, 0x12, 0xFE, 0xAC, 0x12, 0xE2, 0x10, 0x1A, 0x10, 0x96, 0x12, 0x5E, 0x12, 0x31, 0x12, 0xB9, 0x11, 0x75, 0x11, 0x03, 0x13, 0x8B, 0x11, 0xC7, 0x10, 0x2F, 0x90, 0x60, 0x90, 0xE8, 0x90, 0x14, 0x02, 0xA8, 0x4E, 0x4B, 0xEA, 0x44, 0xDA, 0x4E, 0xFA, 0x4D, 0x26, 0x4C, 0x16, 0x41, 0x36, 0x4B, 0x8E, 0x42, 0xAE, 0x49, 0x9E, 0x07, 0x30, 0x77, 0x2A, 0x0A, 0x07, 0x8A, 0x16, 0x8A, 0x4F, 0x4A, 0x41, 0xCA, 0x30, 0xCA, 0x69, 0x2A, 0x64, 0x2A, 0x75, 0x80, 0xB7, 0x1F, 0x52, 0x53, 0x52, 0xDB, 0x51, 0x37, 0x53, 0x7F, 0xD0, 0x08, 0xD0, 0x84, 0xD2, 0x4C, 0xD1, 0x22, 0xD1, 0xAA, 0xD3, 0xE6, 0xD0, 0x1E, 0xD0, 0x51, 0x00, 0x68, 0xDE, 0x44, 0xF7, 0x4E, 0xCF, 0x4F, 0x1F, 0x4A, 0x3F, 0xC9, 0x80, 0xC8, 0xA0, 0xC6, 0x90, 0xCD, 0xB0, 0xCF, 0x48, 0xCE, 0x68, 0xCB, 0xD8, 0xC8, 0xF8, 0xC6, 0xC4, 0xC7, 0x14, 0xCC, 0x34, 0xC1, 0x8C, 0xC0, 0xAC, 0xC2, 0x9C, 0xC5, 0xBC, 0xC7, 0x42, 0xCA, 0x62, 0xCD, 0xD2, 0xC0, 0xF2, 0xCA, 0xCA, 0xC3, 0x1A, 0xC4, 0x3A, 0xCE, 0x06, 0xC7, 0xA6, 0xCC, 0x96, 0xC9, 0xB6, 0xCB, 0x4E, 0xC2, 0x6E, 0xC5, 0x5E, 0xCF, 0xFE, 0xC2, 0xC1, 0xC3, 0x11, 0xC8, 0x31, 0xC6, 0x09, 0xC7, 0xA9, 0xCC, 0x99, 0xC9, 0xB9, 0xC3, 0x45, 0xC2, 0x65, 0xC5, 0x55, 0xCF, 0xF5, 0xC2, 0xCD, 0xC3, 0x1D, 0xC4, 0x3D, 0xC6, 0x03, 0xC7, 0xA3, 0xCC, 0x93, 0xC9, 0xB3, 0xCB, 0x4B, 0xCA, 0x6B, 0xCD, 0xDB, 0xC0, 0xFB, 0xCA, 0xC7, 0xCB, 0x17, 0xCC, 0x37, 0xC1, 0x8F, 0xC0, 0xAF, 0xCA, 0x9F, 0xCD, 0xBF, 0x2F, 0x40, 0x21, 0x60, 0x2B, 0xD0, 0x20, 0xF0, 0x24, 0xC8, 0x21, 0xE8, 0x2D, 0xD8, 0x27, 0x04, 0x22, 0x24, 0x26, 0x14, 0x25, 0x34, 0x23, 0x8C, 0x24, 0xAC, 0x2A, 0x9C, 0x21, 0xBC, 0x25, 0xF2, 0x47, 0xC4, 0x44, 0xA4, 0x0C, 0xC0, 0x6E, 0x7A, 0x51, 0x67, 0xD1, 0x36, 0xD1, 0x4F, 0x31, 0x7E, 0xB1, 0x60, 0xB1, 0x31, 0x71, 0x58, 0x80, 0xB5, 0x27, 0x8B, 0xAF, 0x49, 0xE0, 0x48, 0xE8, 0x4B, 0x14, 0x49, 0x9C, 0x4A, 0x52, 0x4B, 0xDA, 0x4B, 0x36, 0x49, 0xBE, 0x4A, 0xF1, 0x48, 0x05, 0x48, 0x0D, 0x4B, 0x43, 0x49, 0xCB, 0x4A, 0x27, 0x4A, 0xAF, 0xC8, 0x60, 0xCB, 0xE8, 0xC9, 0x14, 0xCA, 0x9C, 0xCA, 0x52, 0xCB, 0x3A, 0xC8, 0x36, 0xCB, 0xBE, 0xCB, 0xF1, 0xCA, 0x05, 0xC9, 0x8D, 0xCA, 0xC3, 0xCA, 0xCB, 0xCB, 0xA7, 0xC8, 0xFF, 0x53, 0xC0, 0x53, 0x30, 0x52, 0x28, 0x53, 0xB8, 0x04, 0x30, 0xDB, 0x55, 0xB1, 0x53, 0xF1, 0x47, 0x49, 0x58, 0x29, 0x42, 0x69, 0x46, 0x19, 0x59, 0x59, 0x5D, 0x39, 0x47, 0x79, 0x5F, 0x85, 0x4C, 0xC5, 0x5A, 0xA5, 0x5E, 0xE5, 0x59, 0x95, 0x4B, 0xD5, 0x5F, 0x75, 0x58, 0x0D, 0x5A, 0x4D, 0x4E, 0x2D, 0x59, 0x6D, 0x5D, 0x1D, 0x4F, 0xDD, 0x58, 0xBD, 0x5C, 0xFD, 0x5A, 0x83, 0x49, 0xC3, 0x5D, 0xA3, 0x47, 0x13, 0x04, 0x40, 0xEB, 0x18, 0xCD, 0x05, 0x2D, 0x74, 0x2D, 0x6D, 0xAD, 0x7C, 0xAD, 0x63, 0x6D, 0x2A, 0x6D, 0x7B, 0xED, 0x26, 0xED, 0x37, 0x1D, 0x5E, 0x9D, 0x20, 0x9D, 0x31, 0x5D, 0x58, 0x5D, 0x05, 0xDD, 0xD4, 0xFF, 0xE1, 0xEF, 0xC6, 0x7A, 0x65, 0x7A, 0x57, 0xFA, 0x8C, 0xFA, 0xAE, 0xFA, 0x9D, 0xFA, 0x3F, 0x06, 0xC2, 0x06, 0xE1, 0x06, 0x53, 0x86, 0x88, 0x86, 0x2A, 0x86, 0x99, 0x86, 0xDB, 0x46, 0x84, 0x46, 0xA6, 0x46, 0x15, 0x46, 0x17, 0xC6, 0xD4, 0xC6, 0x36, 0xC6, 0x35, 0xC6, 0x37, 0x26, 0xF4, 0x26, 0x0E, 0x26, 0x0D, 0x26, 0x0F, 0xA6, 0xCC, 0xA6, 0x2E, 0xA6, 0x2D, 0xA6, 0x2F, 0x66, 0xEC, 0x66, 0xEE, 0x66, 0xED, 0x66, 0xEF, 0xE6, 0x5C, 0xE6, 0xDE, 0xE6, 0x5D, 0xE6, 0x5F, 0x00, 0x83, 0xF7, 0xB3, 0xE8, 0xB5, 0xFC, 0x65, 0x29, 0x60, 0x19, 0x60, 0x39, 0x60, 0x05, 0x62, 0x25, 0x64, 0x15, 0x6C, 0x35, 0x64, 0x0D, 0x66, 0x2D, 0x62, 0x1D, 0x62, 0x3D, 0x62, 0x03, 0x0E, 0x60, 0x73, 0x98, 0xCD, 0xA8, 0x2D, 0x84, 0xAD, 0x98, 0x6D, 0xB8, 0xED, 0x98, 0x1D, 0xA4, 0x9D, 0xB8, 0x5D, 0xB8, 0xDD, 0x98, 0x3D, 0xA4, 0xBD, 0xB8, 0x7D, 0xB8, 0xFD, 0x98, 0x03, 0xA4, 0x83, 0x98, 0x43, 0x98, 0xC3, 0xA8, 0x23, 0x84, 0xA3, 0xA8, 0x63, 0xA8, 0xE3, 0x88, 0x13, 0x98, 0x93, 0x88, 0x53, 0x88, 0xD3, 0x90, 0x33, 0xA8, 0xB3, 0x90, 0x73, 0xA0, 0xF3, 0x80, 0x0B, 0x90, 0x8B, 0x80, 0x8B, 0xBF, 0x4B, 0xAF, 0xCB, 0xB7, 0x2B, 0xAF, 0xAB, 0x8F, 0x6B, 0x97, 0xEB, 0x87, 0x1B, 0xA7, 0x9B, 0x87, 0x5B, 0x9B, 0xDB, 0x8B, 0x3B, 0xAB, 0xBB, 0x8B, 0x7B, 0x93, 0xFB, 0x83, 0x07, 0xA3, 0x87, 0x83, 0x47, 0x9D, 0xC7, 0x8D, 0x27, 0x8D, 0xA7, 0xB5, 0x67, 0xA5, 0xE7, 0xB9, 0x17, 0xB9, 0x97, 0x99, 0x57, 0x89, 0xD7, 0xA1, 0x37, 0x91, 0xB7, 0x81, 0x77, 0x9E, 0xF7, 0xB6, 0x0F, 0xAE, 0x8F, 0x96, 0x4F, 0xA6, 0xCF, 0x9A, 0x2F, 0xBA, 0xAF, 0x8A, 0x6F, 0x92, 0xEF, 0x82, 0x1F, 0x82, 0x9F, 0xAC, 0x5F, 0xB4, 0xDF, 0x24, 0x80, 0xCA, 0x62, 0xFE, 0x21, 0xFE, 0x43, 0x01, 0xC0, 0x01, 0xFC, 0x01, 0xBE, 0x01, 0x5D, 0x01, 0xEF, 0x81, 0xEC, 0x81, 0xAE, 0x81, 0x4D, 0x81, 0xF7, 0x41, 0xF4, 0x41, 0xF6, 0x41, 0x0D, 0x00, 0x2A, 0xB3, 0x06, 0xBB, 0x07, 0x77, 0x04, 0x7F, 0x86, 0xF0, 0x86, 0xF8, 0x87, 0x0C, 0x84, 0x82, 0x86, 0x8A, 0x86, 0x86, 0x87, 0x8E, 0x87, 0xC1, 0x84, 0xC9, 0x84, 0xC5, 0x86, 0xCD, 0x85, 0x23, 0x86, 0x2B, 0x85, 0x27, 0x87, 0xAF, 0x44, 0xA0, 0x47, 0x68, 0x44, 0x64, 0x46, 0x6C, 0x44, 0xE2, 0x44, 0xEA, 0x44, 0xE6, 0x46, 0xEE, 0x46, 0xFD, 0x89, 0x32, 0x8C, 0x2A, 0x8C, 0x3A, 0x8C, 0x26, 0x89, 0x36, 0x89, 0x2E, 0x89, 0x3E, 0x89, 0x21, 0x8F, 0x31, 0x07, 0x18, 0xFD, 0x79, 0x2C, 0x65, 0xAC, 0x55, 0x6C, 0x65, 0xEC, 0x65, 0x1C, 0x75, 0x9C, 0x75, 0x5C, 0x75, 0xDC, 0x55, 0x3C, 0x4D, 0xBC, 0x4D, 0x7C, 0x4D, 0xFC, 0x75, 0x02, 0x6D, 0x82, 0x6D, 0x42, 0x4D, 0xC2, 0x75, 0x22, 0x6D, 0xA2, 0x4D, 0x62, 0x75, 0xE2, 0x55, 0x12, 0x4D, 0x92, 0x75, 0x52, 0x55, 0xD2, 0x45, 0x32, 0x55, 0xB2, 0x65, 0x72, 0x45, 0xF2, 0x59, 0x0A, 0x45, 0x8A, 0x79, 0x4A, 0x69, 0xCA, 0x71, 0x2A, 0x49, 0xAA, 0x71, 0x6A, 0x51, 0xEA, 0x7E, 0xDA, 0x1F, 0x80, 0xD3, 0xE7, 0xA6, 0x6D, 0xA7, 0xE3, 0xA6, 0x6B, 0xA5, 0x67, 0x02, 0x88, 0x8C, 0x9E, 0xA1, 0x9A, 0x91, 0x9C, 0xB1, 0x98, 0x89, 0x98, 0x29, 0x9F, 0x19, 0x9B, 0x39, 0x95, 0x05, 0x9D, 0x25, 0x91, 0x15, 0x96, 0x35, 0x9C, 0x0D, 0x92, 0x2D, 0x90, 0xED, 0x97, 0xDD, 0x9D, 0xFD, 0x91, 0xC3, 0x9E, 0xE3, 0x9A, 0xD3, 0x94, 0x73, 0xFF, 0x97, 0xEE, 0xAF, 0xCD, 0xDF, 0xCA, 0xBF, 0xA7, 0xB9, 0xA4, 0xB9, 0x46, 0xB9, 0xF9, 0xB9, 0xDB, 0x79, 0x38, 0x79, 0x1A, 0x79, 0xA9, 0x79, 0x4B, 0xF9, 0x88, 0xF9, 0xB2, 0xF9, 0x51, 0x00, 0x36, 0x83, 0x17, 0x08, 0x15, 0xF8, 0x17, 0x74, 0x17, 0xBC, 0x17, 0x72, 0x16, 0x7A, 0x17, 0xF6, 0x14, 0xFD, 0x2A, 0x12, 0x2C, 0x0A, 0x2E, 0x1A, 0x29, 0x86, 0x28, 0x96, 0x28, 0x8E, 0x2A, 0x9E, 0x2E, 0x81, 0x03, 0xB8, 0x7D, 0x42, 0xC9, 0x62, 0x29, 0x6A, 0xA9, 0x6A, 0x69, 0x7A, 0xE9, 0x7A, 0x19, 0x56, 0x99, 0x76, 0x59, 0x4E, 0xD9, 0x76, 0x39, 0x41, 0xB9, 0x41, 0x79, 0x41, 0xF9, 0x41, 0x05, 0x71, 0x85, 0x69, 0x45, 0x29, 0x80, 0xD0, 0x14, 0x95, 0x96, 0x95, 0x95, 0x95, 0x97, 0x55, 0xD4, 0x55, 0x36, 0x55, 0x35, 0x55, 0x37, 0xD5, 0xF4, 0xD5, 0xF6, 0xD5, 0xF5, 0xD5, 0xF7, 0x35, 0x4C, 0x35, 0xCE, 0x35, 0xCD, 0x35, 0xCF, 0xB5, 0x6C, 0xB5, 0xEE, 0xB5, 0xED, 0xB5, 0xEF, 0x75, 0x5C, 0x75, 0x3E, 0x75, 0x3D, 0x75, 0x3F, 0xF5, 0xFC, 0xF5, 0x81, 0xF5, 0x83, 0x0D, 0xA0, 0x0D, 0xA2, 0x0D, 0x61, 0x0D, 0xE3, 0x8D, 0xD0, 0x8D, 0xD2, 0x8D, 0x31, 0x8D, 0xB3, 0x4D, 0x08, 0x4D, 0x8A, 0x4D, 0xC9, 0x4D, 0x2B, 0xCD, 0xE8, 0xCD, 0x1A, 0xCD, 0x59, 0xCD, 0x5B, 0x2D, 0xF8, 0x2D, 0x06, 0x2D, 0x85, 0x2D, 0x47, 0xAD, 0x64, 0xAD, 0x16, 0xAD, 0x95, 0xAD, 0x57, 0x6D, 0x74, 0x6D, 0x0E, 0x6D, 0x4D, 0x6D, 0xCF, 0xED, 0xEC, 0xED, 0x9E, 0xED, 0xDD, 0xED, 0x3F, 0x1D, 0x82, 0x1D, 0xC1, 0x1D, 0xA3, 0x9D, 0x50, 0x9D, 0xD2, 0x9D, 0x71, 0x9D, 0xF3, 0x5D, 0x28, 0x5D, 0x6A, 0x5D, 0x19, 0x5D, 0x9B, 0xDD, 0xF8, 0xDD, 0x86, 0xDD, 0xC5, 0xDD, 0xA7, 0x00, 0xC7, 0xB7, 0xED, 0xA9, 0xEF, 0x79, 0xEC, 0x65, 0xEB, 0xF5, 0x04, 0x30, 0xFB, 0x57, 0x9F, 0x70, 0x5F, 0x58, 0xDF, 0x44, 0x3F, 0x5C, 0xBF, 0x42, 0x7F, 0x4A, 0xFF, 0xDA, 0x00, 0xCE, 0x80, 0xDE, 0x40, 0xE1, 0xC0, 0x31, 0xC0, 0xF2, 0x6D, 0x07, 0x1B, 0x06, 0x9F, 0x86, 0x98, 0x87, 0x1C, 0x86, 0x6A, 0x86, 0xCE, 0x87, 0xC9, 0x86, 0x8D, 0x87, 0xF3, 0x87, 0xB7, 0x47, 0xB0, 0x47, 0xD4, 0x47, 0x52, 0x46, 0x16, 0x46, 0xE1, 0x47, 0x65, 0x46, 0x23, 0x47, 0x47, 0xC7, 0x40, 0xC7, 0x04, 0xC7, 0xFC, 0xC6, 0xBA, 0xC6, 0xDE, 0xC7, 0xD9, 0xC6, 0x9D, 0xC7, 0x1B, 0xC6, 0x6F, 0x26, 0x68, 0x26, 0xAC, 0x26, 0xCA, 0x26, 0x8E, 0x27, 0x89, 0x26, 0x0D, 0x26, 0x73, 0x27, 0xB7, 0xA6, 0xB0, 0xA6, 0xD4, 0xA7, 0x52, 0xA7, 0x96, 0xA6, 0x91, 0xA6, 0xE5, 0xA7, 0x63, 0xA7, 0xA7, 0x66, 0xA0, 0x67, 0xC4, 0x67, 0x42, 0x67, 0x86, 0x66, 0x81, 0x67, 0xF9, 0x67, 0x7D, 0x67, 0xBB, 0x66, 0xDF, 0xE7, 0xD8, 0xE7, 0x5C, 0xE7, 0x9A, 0xE7, 0x1E, 0xE6, 0x19, 0xE6, 0xED, 0xE6, 0x6B, 0xE6, 0x2F, 0x17, 0x28, 0x17, 0x2C, 0x16, 0x4A, 0x17, 0x8E, 0x16, 0x89, 0x17, 0x0D, 0x17, 0xF3, 0x17, 0x77, 0x96, 0xF0, 0x96, 0xB4, 0x97, 0xB2, 0x96, 0xD6, 0x97, 0x31, 0x96, 0x55, 0x97, 0x53, 0x96, 0x97, 0x56, 0x90, 0x56, 0x14, 0x56, 0xE2, 0x57, 0x66, 0x56, 0x7F, 0xAF, 0x4A, 0xAF, 0x46, 0xAE, 0x8E, 0xAF, 0x41, 0xAE, 0x89, 0xAD, 0x85, 0xAE, 0x0D, 0xAD, 0x83, 0xAC, 0x0B, 0xAE, 0x07, 0xAC, 0xF7, 0xAD, 0xFF, 0xFC, 0xE3, 0xF9, 0xE7, 0xFD, 0xAF, 0x13, 0x40, 0x7A, 0x8E, 0x0D, 0xF7, 0x8D, 0xD6, 0x8D, 0xE7, 0x4D, 0x96, 0x4D, 0xE7, 0xCD, 0xC6, 0xCD, 0xFB, 0x2D, 0x86, 0x2D, 0xFB, 0xAD, 0xDA, 0xAD, 0x9B, 0x6D, 0xDA, 0x6D, 0x9B, 0xED, 0xAA, 0xED, 0x8B, 0x1D, 0xCA, 0x1D, 0x8B, 0x9D, 0xF2, 0x9D, 0xD3, 0x5D, 0xB2, 0x5D, 0xD3, 0xDD, 0x92, 0xDD, 0xA3, 0x3D, 0xE2, 0x3D, 0xE3, 0xBD, 0xC2, 0xBD, 0x83, 0x7D, 0xC2, 0x7D, 0x83, 0xFD, 0x7C, 0x40, 0x0B, 0xC0, 0x3F, 0xD0, 0x38, 0x48, 0x3C, 0x98, 0x3C, 0x04, 0x39, 0xE4, 0x3E, 0x74, 0x39, 0xAC, 0x3E, 0x3C, 0x3E, 0xC2, 0x3F, 0x52, 0x3F, 0x4A, 0x38, 0x1A, 0x3F, 0x06, 0x3E, 0xE6, 0x3A, 0x76, 0x3E, 0xAE, 0x3E, 0x3E, 0x3E, 0xC1, 0x3F, 0x51, 0x3F, 0x49, 0x38, 0x99, 0x38, 0x05, 0x39, 0xE5, 0x3E, 0x75, 0x39, 0xAD, 0x39, 0x3D, 0x39, 0x23, 0x38, 0xD3, 0x38, 0x4B, 0x3C, 0x9B, 0x04, 0x90, 0x9F, 0xF7, 0xDC, 0xED, 0xBC, 0xEE, 0xFC, 0xEC, 0x82, 0xE8, 0x42, 0xFB, 0x22, 0xE5, 0x62, 0xE6, 0x12, 0xF2, 0x52, 0xE0, 0xD2, 0xF3, 0xB2, 0xE9, 0xF2, 0xEA, 0x8A, 0xEC, 0x4A, 0xFF, 0x2A, 0xE3, 0x6A, 0xF1, 0x1A, 0xF6, 0x5A, 0xF4, 0xDA, 0xEF, 0xBA, 0xFD, 0xFA, 0xFE, 0x86, 0xFA, 0xC6, 0xE4, 0x26, 0xF7, 0x66, 0xFD, 0x16, 0xE9, 0x56, 0xFA, 0x36, 0xF4, 0xB6, 0xF7, 0xF6, 0xED, 0x8E, 0xE9, 0xCE, 0xFA, 0xAE, 0x04, 0xC0, 0x7E, 0xAC, 0x7B, 0xA5, 0xFB, 0x98, 0xFB, 0xD1, 0x07, 0xA0, 0x07, 0xAE, 0x07, 0x97, 0x87, 0x9A, 0x87, 0xD3, 0x47, 0xC2, 0x47, 0xED, 0xC7, 0xD4, 0xC7, 0xB9, 0x27, 0xE8, 0x27, 0xE1, 0x27, 0xDF, 0xA7, 0xB6, 0xA7, 0xFB, 0x67, 0xEA, 0x67, 0xB3, 0xE7, 0xFC, 0xE7, 0x8D, 0x17, 0xD4, 0x17, 0xB9, 0x97, 0x88, 0x97, 0xA1, 0x97, 0xEF, 0x57, 0xF6, 0x57, 0xC7, 0xD7, 0xEA, 0xD7, 0x93, 0xB7, 0x3F, 0x6F, 0xDA, 0x6F, 0xA9, 0x6F, 0x73, 0xEF, 0x30, 0xEF, 0x22, 0xEF, 0x7E, 0xEF, 0x1D, 0xEF, 0x8F, 0x1F, 0x74, 0x1F, 0x16, 0x1F, 0x45, 0x1F, 0xDB, 0x9F, 0x98, 0x9F, 0xCA, 0x9F, 0xB1, 0x9F, 0xE3, 0x80, 0x02, 0xC0, 0xFB, 0xE5, 0xF1, 0xD5, 0xF8, 0x75, 0xFD, 0x4D, 0xF1, 0x6D, 0xF4, 0xFD, 0xF7, 0x7B, 0xFD, 0x07, 0xE5, 0x47, 0xF6, 0x27, 0xE2, 0x67, 0xE8, 0x7F, 0xF0, 0x9F, 0xF3, 0x97, 0xF3, 0xAF, 0xDA, 0x5F, 0x67, 0x40, 0x44, 0x40, 0x3A, 0x40, 0x69, 0x40, 0x0B, 0xC0, 0xB0, 0xC0, 0xA2, 0xC0, 0x01, 0xC0, 0x9D, 0xC0, 0x4F, 0x20, 0x74, 0x20, 0x96, 0x20, 0x45, 0x20, 0x3B, 0xA0, 0x98, 0xA0, 0x4A, 0xA0, 0xB1, 0xA0, 0x63, 0x60, 0x20, 0x60, 0x3C, 0x60, 0xEE, 0x60, 0x0D, 0x60, 0x97, 0xE0, 0x64, 0xE0, 0x06, 0xE0, 0xD9, 0xE0, 0xAB, 0x10, 0x88, 0x10, 0xD2, 0x10, 0xA1, 0x10, 0xFD, 0x10, 0x1F, 0x90, 0xAC, 0x90, 0x0E, 0x90, 0x95, 0x90, 0xC7, 0x80, 0xD2, 0xAF, 0x05, 0x95, 0x0A, 0x35, 0x0F, 0x0D, 0x03, 0x2D, 0x0A, 0x1D, 0x00, 0xDD, 0x05, 0xFD, 0x0C, 0xC3, 0x00, 0x63, 0x0D, 0x70, 0xFE, 0x7D, 0x58, 0x1C, 0x58, 0x35, 0xD8, 0x44, 0xD8, 0xE9, 0xDF, 0x90, 0x80, 0xBE, 0xEF, 0xFB, 0xBB, 0xFD, 0xF7, 0x23, 0x1C, 0x2D, 0x9C, 0x05, 0x5C, 0x11, 0xDC, 0x0E, 0x3C, 0x16, 0xBC, 0x0A, 0x7C, 0x3C, 0xFC, 0x24, 0x02, 0x04, 0x82, 0x20, 0x82, 0x0F, 0x42, 0x1B, 0xC2, 0x03, 0x22, 0x2D, 0xC0, 0xF6, 0x8B, 0x10, 0x77, 0x90, 0xB0, 0x91, 0x54, 0x91, 0x12, 0x90, 0xA6, 0x90, 0x21, 0x00, 0xAE, 0xEF, 0x8B, 0xDC, 0x8E, 0xFC, 0x88, 0x42, 0x8F, 0x62, 0x85, 0x52, 0x82, 0xB2, 0x87, 0x8A, 0x8B, 0xAA, 0x8E, 0x9A, 0x84, 0x3A, 0x8B, 0x06, 0x8D, 0x26, 0x82, 0x16, 0x80, 0xD6, 0x85, 0xF6, 0x8A, 0xCE, 0x84, 0x6E, 0x8B, 0x5E, 0x81, 0x7E, 0x84, 0xF1, 0x07, 0x43, 0x1B, 0x23, 0x1D, 0x63, 0x11, 0x13, 0x1E, 0x53, 0x12, 0x33, 0x14, 0xB3, 0x1F, 0xF3, 0x0B, 0x8B, 0x1D, 0xCB, 0x19, 0xAB, 0x0E, 0xEB, 0x02, 0x9B, 0x0C, 0xDB, 0x10, 0xFB, 0x2F, 0xF6, 0x3F, 0x1C, 0x54, 0x1C, 0x05, 0x9C, 0x18, 0x9C, 0x31, 0x5C, 0x50, 0x5C, 0x7E, 0x5C, 0x3F, 0xDC, 0x51, 0x3C, 0x44, 0x3C, 0x2D, 0xBC, 0x62, 0xBC, 0x1B, 0x7C, 0x76, 0xFC, 0x40, 0xFC, 0x29, 0x02, 0x34, 0x02, 0x7D, 0x82, 0x0A, 0x82, 0xC7, 0x3F, 0xBC, 0x00, 0xBF, 0x5F, 0x00, 0xAC, 0x00, 0x53, 0xC2, 0x3A, 0xC2, 0x0F, 0x22, 0x11, 0xA2, 0x38, 0xA2, 0x75, 0x62, 0x22, 0x62, 0x1B, 0xE2, 0x36, 0x12, 0x60, 0x12, 0x69, 0x92, 0x54, 0x92, 0x3D, 0x52, 0x2A, 0x52, 0x17, 0xD2, 0x3E, 0x32, 0x68, 0x32, 0x15, 0xB2, 0x5C, 0xB2, 0x33, 0x72, 0x66, 0x72, 0x5F, 0xF2, 0x71, 0x80, 0xD5, 0xEB, 0x52, 0x94, 0x51, 0x3C, 0x50, 0xF2, 0x50, 0x86, 0x53, 0x2E, 0x50, 0xE1, 0x52, 0x99, 0x53, 0x35, 0x50, 0x7D, 0x51, 0x8B, 0x51, 0x27, 0x52, 0x6F, 0xD1, 0x90, 0xD1, 0x38, 0xD2, 0x74, 0xD3, 0x42, 0xD2, 0x2A, 0x02, 0xF8, 0x7F, 0x4A, 0xC7, 0x44, 0xE7, 0x4B, 0x37, 0x46, 0x8F, 0x4C, 0xAF, 0x4B, 0x5F, 0x4E, 0xFF, 0xC8, 0xC0, 0xC7, 0x10, 0xC9, 0xB0, 0xCC, 0x48, 0xC0, 0x68, 0xC5, 0xD8, 0xC2, 0x04, 0xC4, 0x24, 0xCD, 0x94, 0xC6, 0xB4, 0xCF, 0x4C, 0xC3, 0xEC, 0xC1, 0x3C, 0xC4, 0x02, 0xCF, 0xA2, 0xC9, 0x52, 0xCC, 0x72, 0xC7, 0xCA, 0xCD, 0x1A, 0xC6, 0xBA, 0xC0, 0x86, 0xCB, 0x66, 0xCE, 0xD6, 0x08, 0x68, 0xF5, 0x12, 0xEC, 0xC9, 0xEC, 0x3B, 0x1C, 0x94, 0x1C, 0x2E, 0x1C, 0xBD, 0x9C, 0xD0, 0x9C, 0x2A, 0x9C, 0xB9, 0x9C, 0xE7, 0x5C, 0x2C, 0x5C, 0x7E, 0x5C, 0x13, 0xDC, 0x28, 0xDC, 0x7A, 0xDC, 0xE5, 0xDC, 0x8F, 0x3C, 0xBC, 0x3C, 0x11, 0x3C, 0x8B, 0xBC, 0xB8, 0xBC, 0xE6, 0x00, 0xEE, 0x7F, 0xF2, 0x89, 0xF1, 0x25, 0xF0, 0x6D, 0xF0, 0x93, 0xF0, 0xDB, 0xF1, 0xB7, 0x0B, 0x80, 0x08, 0xC8, 0x08, 0xA4, 0x09, 0xEC, 0x09, 0x52, 0x09, 0xBA, 0x08, 0xF6, 0x0A, 0x41, 0x09, 0x29, 0x09, 0xE5, 0x08, 0x9D, 0x08, 0x33, 0x0A, 0x7B, 0x0B, 0x8F, 0x88, 0x20, 0x88, 0x68, 0x8A, 0x14, 0x89, 0x5C, 0x8B, 0x72, 0x88, 0x06, 0x89, 0x4E, 0x8B, 0xA1, 0x8B, 0x19, 0x8A, 0x55, 0x89, 0x3D, 0x8B, 0xF3, 0x8B, 0x47, 0x89, 0x2F, 0x4B, 0xE0, 0x4B, 0x58, 0x4A, 0x34, 0x49, 0xFC, 0x48, 0x4A, 0x48, 0x26, 0x49, 0x6E, 0x4B, 0x91, 0x4B, 0x39, 0x49, 0x75, 0x4B, 0x43, 0x4A, 0x2B, 0xFE, 0x8F, 0x4E, 0xCF, 0x28, 0xE3, 0x23, 0x33, 0x2A, 0x8B, 0x24, 0xAB, 0x23, 0x5B, 0x2A, 0x7B, 0x2F, 0xC7, 0x23, 0x17, 0x26, 0xB7, 0x20, 0x8F, 0x2B, 0x6F, 0x2E, 0xDF, 0x28, 0xFF, 0xA5, 0x20, 0xAE, 0x90, 0xA4, 0xB0, 0xAD, 0x48, 0xA1, 0xE8, 0xAC, 0xD8, 0xAB, 0x04, 0xAD, 0xA4, 0xA2, 0x94, 0x07, 0xB0, 0x73, 0x56, 0xE5, 0x00, 0xE5, 0x29, 0x15, 0x0C, 0x15, 0x23, 0x95, 0x1A, 0x95, 0x37, 0x55, 0x61, 0xD5, 0x78, 0xD5, 0x0D, 0x35, 0x52, 0x35, 0x47, 0xB5, 0x6E, 0x75, 0x48, 0x75, 0x65, 0xF5, 0x5C, 0xF5, 0x0B, 0x0D, 0x56, 0x8D, 0x40, 0x8D, 0x69, 0x4D, 0x4C, 0x4D, 0x63, 0xCD, 0x5A, 0xCD, 0x0F, 0x2D, 0x51, 0xAD, 0x04, 0xAD, 0x4D, 0x6D, 0x32, 0x6D, 0x47, 0xED, 0x2E, 0x1D, 0x08, 0x1D, 0x45, 0x9D, 0x6C, 0x9D, 0x63, 0x5D, 0x06, 0x5D, 0x2F, 0xDD, 0x61, 0x3D, 0x78, 0x3D, 0x0D, 0xBD, 0x42, 0x00, 0xE3, 0xD9, 0xF4, 0x03, 0xF4, 0x27, 0x0C, 0x50, 0x0C, 0x74, 0x0C, 0x4A, 0x0D, 0x6E, 0x0D, 0x39, 0x0C, 0x03, 0x0D, 0x27, 0x8D, 0x50, 0x8C, 0x74, 0x8C, 0x4A, 0x8C, 0x6E, 0x8C, 0xD9, 0x8D, 0xFD, 0x8D, 0xC7, 0x4D, 0x10, 0x4D, 0x34, 0x4D, 0x0A, 0x4C, 0xCE, 0x4D, 0x99, 0x4C, 0xBD, 0x4C, 0x07, 0xCD, 0x60, 0xCC, 0x94, 0xCC, 0xB2, 0xCC, 0x8E, 0xCC, 0x99, 0xCC, 0x03, 0xCD, 0xE7, 0x2C, 0xF0, 0x2D, 0x6C, 0x2C, 0x3A, 0x2D, 0xA1, 0x2C, 0xD5, 0x2C, 0x8B, 0x2D, 0x1F, 0xAC, 0x04, 0xAC, 0x62, 0xAD, 0x36, 0xAD, 0x29, 0xAD, 0xDD, 0xAC, 0x87, 0x6D, 0x90, 0x6D, 0xF4, 0x6D, 0x6A, 0x6C, 0x3E, 0x6C, 0xC5, 0x6D, 0x53, 0x6D, 0x0F, 0xEC, 0x18, 0xEC, 0x7C, 0xED, 0x26, 0xED, 0x31, 0xEC, 0x4D, 0xED, 0x1B, 0x1D, 0x7E, 0x39, 0xC8, 0x38, 0x64, 0x3A, 0x9C, 0x38, 0x32, 0x3B, 0x06, 0x38, 0xCE, 0x00, 0xAA, 0xBC, 0xB9, 0x53, 0xB3, 0x33, 0xB0, 0xB3, 0x9C, 0x73, 0x96, 0xF3, 0xA9, 0x0B, 0x8B, 0x4B, 0xA0, 0xCB, 0x8C, 0x2B, 0xB6, 0xAB, 0x99, 0x6B, 0x93, 0xDB, 0x2F, 0x37, 0x19, 0xB7, 0x0C, 0xB7, 0x23, 0x77, 0x46, 0x77, 0x5F, 0xF7, 0x09, 0x0F, 0x34, 0x0F, 0x23, 0x8F, 0x5A, 0x8F, 0x0F, 0x4F, 0x31, 0x40, 0x8F, 0xDF, 0xF1, 0xA2, 0xF2, 0x72, 0xF3, 0x1A, 0xF4, 0x86, 0xF7, 0xD6, 0xF2, 0x2E, 0xF5, 0xBE, 0xF7, 0xE1, 0xF5, 0x89, 0xF4, 0x59, 0xF1, 0xFD, 0xE3, 0x6B, 0xE3, 0xDB, 0xE6, 0x07, 0xEA, 0x27, 0x0F, 0x68, 0xF1, 0xC7, 0xFE, 0x8C, 0xFE, 0x3E, 0xFE, 0xE3, 0x01, 0x28, 0x01, 0x7A, 0x01, 0x15, 0x01, 0xCF, 0x81, 0x02, 0x81, 0xD1, 0x81, 0xAB, 0x41, 0x84, 0x41, 0x36, 0x41, 0xED, 0xC1, 0xA0, 0xC1, 0x72, 0xC1, 0x99, 0xC1, 0x47, 0x21, 0xF4, 0x21, 0x5E, 0x21, 0x23, 0xA1, 0x88, 0xA1, 0xDA, 0xA1, 0xA5, 0xA1, 0xF7, 0x61, 0x3C, 0x61, 0xE1, 0x61, 0x8B, 0xE1, 0x78, 0xE1, 0xE6, 0xE1, 0x8D, 0xE1, 0xDF, 0x11, 0xE2, 0x11, 0x49, 0x11, 0x5B, 0x91, 0xE4, 0x91, 0x8E, 0x91, 0xDD, 0x51, 0x10, 0x51, 0x0A, 0x51, 0xD9, 0x51, 0xC7, 0xD1, 0xF4, 0xD1, 0x9E, 0xD1, 0xC3, 0x31, 0xF0, 0x31, 0x1A, 0x31, 0x85, 0x31, 0x2F, 0xB1, 0xCA, 0xB1, 0x0D, 0x71, 0xF0, 0x00, 0x52, 0x8F, 0xC7, 0x93, 0xC5, 0x07, 0xC7, 0xEF, 0x25, 0xF0, 0x26, 0x64, 0x25, 0xBC, 0x26, 0xAA, 0x24, 0xD6, 0x27, 0xC1, 0x25, 0x59, 0x25, 0x8D, 0x26, 0x13, 0x27, 0xFB, 0x27, 0x6F, 0xA5, 0x70, 0xA4, 0xA4, 0xA4, 0xDC, 0xA7, 0xCA, 0xA6, 0x56, 0xA4, 0x81, 0xA7, 0x19, 0xA6, 0xF5, 0xA4, 0x63, 0xA6, 0xBB, 0xA4, 0xCF, 0x67, 0xD0, 0x64, 0x84, 0x67, 0x1C, 0x02, 0x0C, 0x39, 0x2B, 0xF3, 0x39, 0x4B, 0x31, 0xAB, 0x3A, 0x1B, 0x32, 0xDB, 0x38, 0xBB, 0x37, 0x07, 0x2B, 0xC7, 0x25, 0x67, 0xEE, 0x2F, 0xE5, 0xDF, 0x90, 0xBF, 0x3B, 0xB9, 0x9C, 0xB9, 0xC9, 0xB9, 0xD7, 0x79, 0xE2, 0x79, 0xF9, 0x79, 0x1F, 0xF9, 0xCA, 0xF9, 0x35, 0x05, 0x10, 0x05, 0xFA, 0x05, 0xED, 0x85, 0x48, 0x85, 0x96, 0x85, 0x83, 0x45, 0xD8, 0x45, 0xCE, 0x45, 0x53, 0xC5, 0xC4, 0xC5, 0xDE, 0xC5, 0x8B, 0x25, 0x54, 0x25, 0x41, 0x80, 0x96, 0xCE, 0x50, 0x1A, 0x01, 0xB0, 0x61, 0xD6, 0xB2, 0x98, 0xB2, 0xC3, 0x72, 0xCE, 0xF2, 0x84, 0xF2, 0x93, 0x0A, 0x9E, 0x8A, 0xA4, 0x8A, 0xB3, 0x4A, 0xBE, 0xCA, 0x94, 0xCA, 0x8B, 0x2A, 0xFE, 0xAA, 0xD4, 0xAA, 0xCB, 0x6A, 0x81, 0xEA, 0xB4, 0xEA, 0xAB, 0x1A, 0xA1, 0x9A, 0xF4, 0x9A, 0xEB, 0x5A, 0xE1, 0xDA, 0xCC, 0xDA, 0xDB, 0x3A, 0xD1, 0xBA, 0xEC, 0xBA, 0xFB, 0x7A, 0xF1, 0xFA, 0xBF, 0xF5, 0x8F, 0x0D, 0x92, 0x00, 0xFF, 0x7D, 0x06, 0x70, 0xB5, 0xA0, 0xF1, 0xB5, 0x49, 0xB6, 0xA9, 0xA8, 0xE9, 0xA3, 0x59, 0xA1, 0xB9, 0xB4, 0xF9, 0xAB, 0x45, 0xA9, 0xA5, 0xA2, 0xF5, 0x57, 0xAB, 0x6A, 0x6B, 0x75, 0x1B, 0x48, 0x9B, 0x46, 0x5B, 0x5D, 0x3B, 0x38, 0xC0, 0x7B, 0x1B, 0x3B, 0xA0, 0x3A, 0xB4, 0x3A, 0xCA, 0x3B, 0x5E, 0x3A, 0x45, 0x3A, 0x93, 0x3A, 0xF7, 0xBA, 0xE8, 0xBA, 0x7C, 0xBB, 0xA6, 0xBA, 0xB1, 0xBA, 0xCD, 0xBB, 0x5B, 0x7A, 0xC0, 0x7A, 0x94, 0x7A, 0xF2, 0x7B, 0x6E, 0x7A, 0x79, 0x7B, 0xA3, 0x7B, 0x37, 0xFA, 0x28, 0xFA, 0xDC, 0xFB, 0x46, 0xFA, 0x51, 0xFB, 0x8D, 0xFB, 0x1B, 0x07, 0x80, 0x07, 0x14, 0x06, 0xF2, 0x06, 0x6E, 0x06, 0x79, 0x07, 0x63, 0x06, 0xB7, 0x86, 0xA8, 0x87, 0xBC, 0x86, 0x26, 0x87, 0xB1, 0x87, 0x2D, 0x87, 0x3B, 0x46, 0xA0, 0x47, 0x34, 0x47, 0xCA, 0x47, 0xDE, 0x46, 0x25, 0x46, 0x33, 0x47, 0xCF, 0xC7, 0x38, 0xC7, 0x22, 0xC7, 0x36, 0xC6, 0xA9, 0xC6, 0xBD, 0xC6, 0xA7, 0x26, 0x70, 0x26, 0x6C, 0x26, 0x7A, 0x26, 0xE1, 0x27, 0xF5, 0x27, 0xEB, 0xA7, 0x80, 0xA7, 0x94, 0xA6, 0x8A, 0xA7, 0x5E, 0xA6, 0xC5, 0xA7, 0x33, 0xA7, 0x2F, 0x67, 0x78, 0x67, 0x12, 0xFE, 0x87, 0xFB, 0x86, 0xCF, 0x6E, 0xCC, 0xD1, 0xCE, 0x05, 0xCC, 0x2D, 0xCD, 0x93, 0xCD, 0x7B, 0xCD, 0xCF, 0x2C, 0x10, 0x2E, 0xB8, 0x2E, 0x4C, 0x2C, 0xE2, 0x01, 0xDC, 0x77, 0x74, 0x09, 0x7B, 0xC9, 0x7E, 0x69, 0x68, 0x19, 0x73, 0xD9, 0x76, 0x79, 0x68, 0x05, 0x73, 0xC5, 0x6E, 0x65, 0x68, 0x15, 0x6B, 0xD5, 0x7E, 0x75, 0x64, 0x0D, 0x67, 0xCD, 0x71, 0x6D, 0x7C, 0x9D, 0x60, 0xDD, 0x75, 0x7D, 0xFA, 0x1F, 0x31, 0x80, 0x88, 0x8B, 0x1B, 0x54, 0x1B, 0x81, 0x1B, 0xFF, 0x36, 0x19, 0x37, 0x23, 0x37, 0x0F, 0xB6, 0xB8, 0xB6, 0x92, 0xB7, 0xAE, 0xB6, 0x45, 0xB7, 0x73, 0xB7, 0x5F, 0x77, 0x14, 0x77, 0x2A, 0x01, 0x35, 0x5C, 0x6F, 0xB7, 0x7D, 0x0F, 0x79, 0xCF, 0x76, 0x6F, 0x6C, 0x9F, 0x68, 0xDF, 0x77, 0x7F, 0xFD, 0x80, 0xE5, 0x20, 0xFC, 0xA0, 0xF7, 0x60, 0xE7, 0xE0, 0xE7, 0x10, 0xFF, 0x90, 0xEF, 0x50, 0xEF, 0xD0, 0xEF, 0x30, 0xF7, 0xB0, 0xF7, 0x70, 0xE7, 0xF0, 0x07, 0x40, 0x41, 0xFE, 0x23, 0xFD, 0x23, 0xFF, 0xA3, 0xBC, 0xA3, 0xBE, 0xA3, 0xBD, 0x63, 0xA0, 0xE3, 0x3F, 0xC7, 0x82, 0xC7, 0x86, 0xC7, 0x81, 0xC7, 0x85, 0xC7, 0x83, 0xC7, 0x87, 0x27, 0xA0, 0x27, 0x24, 0x27, 0x22, 0x27, 0xA6, 0x27, 0xA1, 0x27, 0xA5, 0x27, 0x63, 0x27, 0xA7, 0xA7, 0x50, 0xA7, 0x14, 0xA7, 0x92, 0xA7, 0x56, 0xA7, 0xD1, 0xA7, 0x55, 0xA7, 0xD3, 0xA7, 0xD7, 0x67, 0xF0, 0x67, 0xF4, 0x67, 0x0A, 0x67, 0x0E, 0x00, 0x46, 0x36, 0x9E, 0x2D, 0x9D, 0x3D, 0x9D, 0xA3, 0x9D, 0xB3, 0x9D, 0xAB, 0x9F, 0x7B, 0x9E, 0x67, 0x9D, 0x77, 0x9D, 0x6F, 0x9D, 0x7F, 0x5F, 0xE0, 0x5F, 0x08, 0x5C, 0x18, 0x5E, 0x04, 0x5D, 0x14, 0x5D, 0x8C, 0x5C, 0x9C, 0x5C, 0x42, 0x5D, 0x52, 0x5E, 0x4A, 0x5D, 0xDA, 0x5C, 0xC6, 0x5E, 0xD6, 0x5D, 0xCE, 0x5F, 0x3E, 0x5C, 0xA1, 0x5C, 0xB1, 0x5E, 0xA9, 0x5F, 0x79, 0x5C, 0x65, 0x5D, 0x75, 0x5F, 0x6D, 0x5F, 0xFF, 0xBA, 0x26, 0xBC, 0x16, 0x06, 0xD8, 0x73, 0xD8, 0x75, 0xF9, 0xF5, 0xE4, 0xF5, 0xD5, 0x0D, 0xFC, 0x0D, 0xC3, 0x8D, 0xD2, 0x8D, 0xCB, 0x4D, 0xDA, 0x4D, 0xFB, 0xCD, 0xC6, 0xCD, 0xD7, 0x2D, 0xFE, 0xAD, 0xC0, 0xAD, 0x31, 0x80, 0xA7, 0x65, 0xB7, 0x13, 0xB7, 0x57, 0x77, 0xF0, 0x77, 0x0C, 0x77, 0xCA, 0x77, 0xAE, 0x77, 0xE9, 0x77, 0x9D, 0x77, 0x5B, 0xF7, 0xBF, 0xEE, 0x09, 0xEF, 0x45, 0xEE, 0xCD, 0xEE, 0x23, 0xEF, 0xAB, 0xEE, 0x67, 0xEF, 0xEF, 0x1F, 0x50, 0x1E, 0xD8, 0x1E, 0x34, 0x1F, 0x7C, 0x1E, 0x72, 0x1F, 0x06, 0x1E, 0x8E, 0x1E, 0x21, 0x1F, 0xA9, 0x1E, 0x25, 0x1E, 0x8D, 0x1E, 0x7D, 0x1E, 0x93, 0x1E, 0x2B, 0x1E, 0xFB, 0x1F, 0x57, 0x1F, 0xAF, 0x9F, 0xC0, 0x9E, 0x70, 0x9E, 0x18, 0x9F, 0x24, 0x00, 0xC6, 0xED, 0xF6, 0x14, 0xFB, 0x54, 0xF4, 0xD4, 0xF9, 0xB4, 0xF0, 0x74, 0x06, 0x68, 0xF0, 0xE8, 0xCF, 0xB4, 0xCF, 0xC2, 0xCF, 0x5A, 0xCF, 0x8E, 0xCF, 0x11, 0xCF, 0x79, 0xCF, 0xAD, 0xCF, 0x33, 0xCF, 0x47, 0xCF, 0x9F, 0x2F, 0xC8, 0x2F, 0x94, 0x2F, 0x02, 0x2F, 0xEA, 0x2F, 0x76, 0x2F, 0xA1, 0x2F, 0x39, 0x2F, 0x4D, 0x2F, 0x93, 0x2F, 0xFB, 0x2F, 0x6F, 0xAF, 0x88, 0xAF, 0xE4, 0xAF, 0x7C, 0xAF, 0xAA, 0x00, 0x37, 0x0F, 0x7E, 0xCD, 0x7A, 0x6D, 0x7C, 0x9D, 0x78, 0xDD, 0x7B, 0x7D, 0x7D, 0x43, 0x78, 0x23, 0x7B, 0xE3, 0x7D, 0x53, 0x79, 0xB3, 0x79, 0x0B, 0x7E, 0xCB, 0x7A, 0x6B, 0x7C, 0x9B, 0x78, 0xDB, 0x7B, 0x7B, 0x7B, 0x47, 0x78, 0x27, 0x03, 0x94, 0x7B, 0xD5, 0x77, 0x9B, 0xF7, 0x90, 0xF7, 0xEC, 0xF7, 0xA6, 0xF7, 0xC9, 0xF7, 0x83, 0xF7, 0xF7, 0x0F, 0xA4, 0x0F, 0x0A, 0x80, 0xC1, 0xAB, 0x7F, 0xD8, 0x7F, 0x84, 0x7D, 0xE4, 0x7E, 0xB4, 0x7C, 0xCC, 0x7C, 0x1C, 0x7F, 0x7C, 0x7D, 0xA2, 0x7E, 0x52, 0x7F, 0x0A, 0x7F, 0x6A, 0x7F, 0x3A, 0x7D, 0x46, 0x7D, 0x16, 0x7E, 0x76, 0x7C, 0x2E, 0x7C, 0x9E, 0x7F, 0x01, 0x7D, 0x61, 0x7E, 0x31, 0x7C, 0x49, 0x7C, 0x19, 0x7C, 0xB9, 0x7F, 0xC5, 0x7F, 0x95, 0x7D, 0xF5, 0x7D, 0xAD, 0x7D, 0xDD, 0x7C, 0x43, 0x7C, 0xE3, 0x7F, 0xB3, 0x7D, 0xCB, 0x7D, 0x9B, 0x7D, 0xFB, 0x7D, 0xA7, 0x7D, 0xD7, 0x7E, 0x8F, 0x7E, 0xEF, 0x7C, 0xBF, 0xFC, 0xC0, 0xFD, 0x90, 0xFE, 0xF0, 0xFE, 0xA8, 0xFD, 0xD8, 0xFD, 0x84, 0xFD, 0xE4, 0xFE, 0xB4, 0xFE, 0xCC, 0xFE, 0x9C, 0xFC, 0xFC, 0xD8, 0x98, 0x3A, 0xFF, 0x8F, 0x77, 0x17, 0x83, 0x00, 0xFD, 0xF7, 0xAF, 0x75, 0xFE, 0xF5, 0xFF, 0xFE, 0xFC, 0x97, 0xE7, 0x81, 0x00, 0xBF, 0x80, 0x43, 0x5C, 0x60, 0x0E, 0x10, 0x15, 0x50, 0x7B, 0xB0, 0x48, 0xF0, 0x42, 0x88, 0x2E, 0xC8, 0x25, 0xA8, 0x0B, 0x18, 0x20, 0x58, 0xF4, 0xDF, 0xD4, 0x70, 0xFC, 0xF0, 0xCA, 0x08, 0x66, 0x88, 0x1E, 0x48, 0x51, 0xC8, 0x59, 0x28, 0x55, 0xA8, 0x9D, 0x68, 0x13, 0xE8, 0x6B, 0x18, 0x47, 0x98, 0xF7, 0x58, 0x3F, 0x38, 0xD0, 0xB8, 0xA8, 0x78, 0xF8, 0xF8, 0x14, 0x04, 0x8C, 0x7F, 0x38, 0x09, 0x05, 0x88, 0xC4, 0x89, 0x65, 0x49, 0x94, 0x49, 0xD5, 0xC9, 0xB4, 0xC9, 0xF5, 0x28, 0x0C, 0x29, 0x8D, 0xA8, 0x00, 0x0A, 0x46, 0x63, 0x44, 0x6B, 0x48, 0xA7, 0x4F, 0xAF, 0xC3, 0xA0, 0xC9, 0xA8, 0xCA, 0xA4, 0xC0, 0x2C, 0xCD, 0x22, 0xCA, 0xCA, 0xCF, 0xC6, 0xCE, 0x4E, 0xCF, 0x41, 0xC6, 0x89, 0xCB, 0x85, 0xCC, 0x0D, 0xC1, 0xFD, 0xC1, 0x73, 0xCD, 0xBB, 0xCB, 0x37, 0xCF, 0x3F, 0x20, 0xD0, 0x20, 0x58, 0x28, 0x94, 0x2C, 0x1C, 0x2A, 0xE2, 0x21, 0x6A, 0x2D, 0xA6, 0x2F, 0xAE, 0x22, 0x21, 0x29, 0xC9, 0x2F, 0xC5, 0x2A, 0x4D, 0x2B, 0x43, 0x2A, 0x8B, 0x2F, 0x87, 0x29, 0x8F, 0xAC, 0x00, 0xA7, 0x08, 0xAD, 0x04, 0xA1, 0x0C, 0xA6, 0x02, 0xA2, 0x0A, 0xAC, 0x06, 0xA4, 0x0E, 0xAC, 0x01, 0xAC, 0x09, 0xA2, 0x05, 0xA6, 0x0D, 0xAE, 0x03, 0xA5, 0x0B, 0xAB, 0x07, 0xAF, 0x8F, 0x6C, 0x80, 0x6E, 0x88, 0x6D, 0x44, 0x60, 0x4C, 0x6A, 0x42, 0x6D, 0xCA, 0x68, 0xC6, 0x61, 0x2E, 0x60, 0x21, 0x61, 0xA9, 0x68, 0xA5, 0x6D, 0x6D, 0x66, 0xE3, 0x68, 0xEB, 0x67, 0x17, 0x6D, 0x9F, 0xE9, 0x50, 0xE6, 0xD8, 0xE6, 0x34, 0xE6, 0xBC, 0x06, 0xE8, 0xA3, 0x5F, 0xEE, 0x08, 0x1E, 0xC4, 0x9E, 0x1C, 0x5E, 0xB2, 0xDE, 0x26, 0x3E, 0xDE, 0xBE, 0xC9, 0x7E, 0xD5, 0xFE, 0xA3, 0x01, 0xFB, 0x81, 0x5F, 0xC1, 0xE8, 0x21, 0xF4, 0xA1, 0x12, 0x61, 0x06, 0xE1, 0x6E, 0x11, 0xB1, 0x91, 0x85, 0x51, 0x6D, 0xD1, 0x93, 0x31, 0xDB, 0xB1, 0x77, 0xF1, 0xC0, 0x09, 0xC8, 0x89, 0x44, 0x49, 0x8C, 0xC9, 0xFC, 0x29, 0xB2, 0xA9, 0x9A, 0x69, 0xA6, 0xE9, 0x8E, 0x19, 0xDE, 0x99, 0xA1, 0x59, 0x71, 0xD9, 0xE9, 0x39, 0x79, 0x7F, 0x4B, 0x73, 0xAB, 0xF3, 0xEA, 0xF3, 0x9B, 0x0B, 0xDA, 0x00, 0x2D, 0xB0, 0xAB, 0xB8, 0xAB, 0xA4, 0xB3, 0xB4, 0xBD, 0xAC, 0xA5, 0xBC, 0xB1, 0xA2, 0xA6, 0xB2, 0xBC, 0xAA, 0xA0, 0x3A, 0xAB, 0x26, 0xA9, 0x36, 0xB2, 0x2E, 0xA0, 0xDE, 0xB5, 0xC1, 0xAA, 0x51, 0xB7, 0x49, 0xA1, 0x59, 0xA8, 0x85, 0xB9, 0x95, 0xA4, 0x0D, 0xA5, 0x1D, 0xA4, 0xFD, 0xAE, 0x63, 0xBB, 0x73, 0xA2, 0xAB, 0xB9, 0x3B, 0xB7, 0x27, 0xA2, 0xD7, 0xA1, 0x4F, 0xA3, 0x9F, 0x7F, 0x80, 0x74, 0x10, 0x76, 0xF0, 0x71, 0x68, 0x63, 0x78, 0x70, 0xA4, 0x6A, 0x34, 0x65, 0xCC, 0x77, 0xDC, 0x7C, 0x42, 0x69, 0x92, 0x77, 0x8A, 0x62, 0x1A, 0x75, 0x06, 0x68, 0xE6, 0x7A, 0x76, 0x73, 0x6E, 0x62, 0xBE, 0x63, 0xA1, 0x62, 0x31, 0x73, 0x29, 0x7A, 0xD9, 0x77, 0xC5, 0x61, 0xD5, 0x64, 0x4D, 0x73, 0x5D, 0xFE, 0x9F, 0xD8, 0x06, 0xDF, 0x26, 0xFB, 0x16, 0xC3, 0x36, 0xF5, 0x0E, 0xF9, 0x2E, 0xC9, 0x1E, 0xD1, 0x3E, 0xE1, 0x01, 0xE1, 0x21, 0xD1, 0x11, 0xC9, 0x31, 0xF9, 0x09, 0xCD, 0x29, 0xD3, 0x19, 0xC7, 0xB9, 0xC0, 0x85, 0xE4, 0xA5, 0xF2, 0x95, 0xFE, 0xB5, 0xF5, 0x8D, 0xE7, 0x6D, 0xC4, 0x5D, 0xC6, 0x7D, 0xC5, 0x43, 0xF7, 0xE3, 0xFC, 0xD3, 0xF1, 0xF3, 0xE7, 0x2B, 0xF2, 0x1B, 0xF5, 0xBB, 0xE8, 0x87, 0xC1, 0xA7, 0xEF, 0x57, 0xF6, 0x77, 0xE7, 0xCF, 0xC6, 0xFF, 0xFA, 0x96, 0x9B, 0x37, 0xA0, 0x07, 0xE0, 0x2B, 0x90, 0x13, 0xD0, 0x3D, 0xB0, 0x0D, 0xF0, 0x65, 0x88, 0x59, 0xC8, 0x09, 0xA8, 0x21, 0xE8, 0x1E, 0x98, 0x36, 0xD8, 0xC6, 0xDF, 0xD5, 0x70, 0xA5, 0xF0, 0x05, 0x08, 0xD9, 0x88, 0x69, 0x48, 0x89, 0xC8, 0xD1, 0x28, 0x61, 0xA8, 0x81, 0x68, 0x3E, 0xE8, 0xEE, 0x18, 0x4E, 0x98, 0x76, 0x58, 0x96, 0xD8, 0x26, 0x38, 0x06, 0xB8, 0xDA, 0x78, 0xEA, 0xF8, 0x4A, 0x04, 0x72, 0x7F, 0xA4, 0x08, 0xC5, 0x88, 0x84, 0x89, 0xF9, 0x49, 0x78, 0x48, 0x39, 0xC8, 0x58, 0xC8, 0x19, 0x28, 0x68, 0x28, 0x29, 0xA8, 0x48, 0xA8, 0x09, 0x68, 0x70, 0x68, 0x31, 0xE8, 0x50, 0xE8, 0x11, 0x18, 0x60, 0x19, 0xA1, 0x98, 0xC0, 0x99, 0x41, 0x58, 0x80, 0x59, 0x81, 0xD8, 0x80, 0xD8, 0x81, 0x38, 0x80, 0x39, 0x41, 0xB9, 0xC0, 0xB9, 0xA1, 0x78, 0x7E, 0xF3, 0x22, 0xF2, 0xA1, 0xF1, 0x63, 0x0B, 0xFC, 0x11, 0x24, 0x15, 0xA2, 0x12, 0xA6, 0x17, 0x61, 0x11, 0xE5, 0x14, 0xE3, 0x13, 0x17, 0x96, 0x90, 0x90, 0x94, 0x93, 0x52, 0x96, 0xD6, 0x94, 0xD1, 0x97, 0x35, 0x95, 0xB3, 0x96, 0x77, 0x54, 0x70, 0x57, 0xF4, 0x53, 0x0A, 0x51, 0x8E, 0x56, 0x49, 0x52, 0xCD, 0x50, 0xCB, 0x53, 0x2F, 0xD5, 0xA8, 0xD5, 0x6C, 0xD1, 0xEA, 0xD6, 0x1E, 0x02, 0x54, 0xFC, 0x25, 0xBD, 0x4D, 0xFD, 0x43, 0x83, 0x4B, 0xC3, 0x47, 0xA3, 0x2F, 0x13, 0x30, 0x53, 0x38, 0x33, 0x74, 0x73, 0x02, 0x0B, 0x0A, 0x4B, 0x06, 0x2B, 0x4E, 0x6B, 0x41, 0x1B, 0x09, 0x5B, 0x05, 0x3B, 0x75, 0x7B, 0x3D, 0x07, 0x53, 0x47, 0x6B, 0x27, 0x47, 0x67, 0x37, 0x17, 0x2F, 0x57, 0x3F, 0xB7, 0x40, 0xF7, 0x10, 0x8F, 0x50, 0xCF, 0x30, 0xAF, 0x30, 0xEF, 0x30, 0x9F, 0x50, 0xDF, 0x20, 0xBF, 0x00, 0x7F, 0x9F, 0x00, 0xCF, 0x40, 0xD7, 0x20, 0xC7, 0x60, 0xDB, 0x10, 0x8B, 0x50, 0xE3, 0x30, 0xBD, 0x70, 0x8D, 0x08, 0xE5, 0x48, 0xD9, 0x28, 0xF1, 0x68, 0xC1, 0x18, 0xEE, 0x58, 0xD6, 0x38, 0xFA, 0x78, 0xCA, 0x04, 0xE2, 0x44, 0xBC, 0x24, 0xCC, 0x64, 0x94, 0x14, 0xF8, 0x54, 0x98, 0x34, 0x88, 0x74, 0xD0, 0x0C, 0xA0, 0x8C, 0x9F, 0xCC, 0xAF, 0x2C, 0xC0, 0x55, 0x98, 0xF3, 0x93, 0x0B, 0x9C, 0x07, 0x9E, 0x0F, 0x5D, 0x80, 0x50, 0x88, 0x56, 0x84, 0x5B, 0x4C, 0x5A, 0x42, 0x57, 0xCA, 0x51, 0x26, 0x5C, 0x2E, 0x57, 0xA1, 0x5D, 0x69, 0x59, 0xE5, 0x5E, 0x1D, 0x5A, 0x93, 0x5C, 0x5B, 0x58, 0xD7, 0x50, 0x3F, 0xD0, 0xB0, 0xD0, 0xB8, 0xDF, 0xF4, 0xD0, 0x02, 0xDA, 0x8A, 0xDA, 0x46, 0xDA, 0xCE, 0xDE, 0x21, 0xD9, 0xA9, 0xD5, 0x65, 0xD3, 0xED, 0xD7, 0x93, 0xD0, 0x5B, 0xD8, 0xD7, 0xDC, 0x3F, 0x36, 0xB0, 0x3E, 0x78, 0x3E, 0xF4, 0x31, 0x02, 0x3D, 0x8A, 0x35, 0x46, 0x3E, 0xCE, 0x3A, 0x21, 0x3C, 0xA9, 0x30, 0xA5, 0x33, 0x6D, 0x31, 0xE3, 0x32, 0xEB, 0x37, 0x17, 0x31, 0x9F, 0xB8, 0x90, 0xB9, 0x98, 0xBF, 0x54, 0xBA, 0x5C, 0xB9, 0x52, 0xBB, 0xDA, 0xB0, 0xD6, 0xB4, 0xDE, 0xF2, 0xAF, 0x65, 0xA3, 0x65, 0xB3, 0x79, 0xAB, 0x71, 0xBB, 0x6E, 0xA7, 0x66, 0xB7, 0x62, 0xAF, 0x74, 0xBF, 0xE0, 0xE0, 0xEF, 0x61, 0xFA, 0x51, 0xD2, 0x71, 0xF4, 0x49, 0xE8, 0xA9, 0xEF, 0x99, 0xEB, 0xB9, 0xCD, 0x85, 0xF1, 0xA5, 0xE6, 0x95, 0xDC, 0xB5, 0xF0, 0x0D, 0xFB, 0x2D, 0xF5, 0x1D, 0xFE, 0x3D, 0xD2, 0x03, 0xC8, 0xC3, 0xD3, 0xE3, 0xD1, 0xD3, 0xF2, 0xF3, 0xF0, 0x4B, 0xD3, 0x6B, 0xC1, 0x5B, 0xFC, 0xBB, 0xCF, 0x87, 0xC5, 0xA7, 0xCA, 0x17, 0xFF, 0x37, 0xD5, 0xCF, 0xFF, 0xFC, 0x14, 0xC4, 0x3D, 0xA0, 0x13, 0xAE, 0x03, 0xDA, 0x60, 0x1F, 0x58, 0x13, 0x78, 0x19, 0x44, 0x0E, 0x64, 0x02, 0x54, 0x28, 0xB4, 0x27, 0x8C, 0x1D, 0xAC, 0xF1, 0x6F, 0x0D, 0x38, 0x59, 0x78, 0x61, 0x04, 0x0E, 0x44, 0x3A, 0x24, 0x12, 0x64, 0x6C, 0x14, 0x24, 0x54, 0x48, 0xD4, 0x1F, 0xB4, 0x67, 0xF4, 0x2B, 0x8C, 0x43, 0xCC, 0x4D, 0xAC, 0x25, 0xEC, 0x29, 0x9C, 0x61, 0xDC, 0x6E, 0xBC, 0x16, 0xFC, 0x3A, 0x82, 0xF2, 0x3F, 0x05, 0x84, 0xD9, 0x44, 0x29, 0xC4, 0x71, 0x24, 0x11, 0xA4, 0x41, 0x64, 0xDE, 0xE4, 0xAE, 0x14, 0xF6, 0x94, 0x96, 0x54, 0x26, 0xD4, 0xFA, 0x34, 0x5A, 0xB4, 0xAA, 0x74, 0x4A, 0xF4, 0x72, 0x0C, 0xD2, 0x8C, 0x12, 0x4C, 0x62, 0xCC, 0x22, 0x2C, 0x42, 0xAC, 0x82, 0x6C, 0x02, 0xEC, 0xFC, 0x1C, 0x7C, 0x9C, 0x7C, 0x5C, 0x7C, 0xDC, 0x7C, 0x3C, 0x80, 0x84, 0xC5, 0xC7, 0xCF, 0x2F, 0x28, 0x20, 0x2C, 0x28, 0x26, 0x24, 0x29, 0x2C, 0x2B, 0xA2, 0x28, 0xAA, 0x26, 0xA6, 0x23, 0x6E, 0x24, 0x61, 0x25, 0xE9, 0x28, 0xE5, 0x25, 0x1D, 0x2C, 0x13, 0x27, 0x9B, 0x21, 0x57, 0x2C, 0xDF, 0xA0, 0xD0, 0xAB, 0x38, 0xAD, 0xB4, 0xA9, 0x7C, 0xA1, 0xF2, 0xAE, 0x06, 0xA5, 0x8E, 0xAE, 0x41, 0xAA, 0xC9, 0xAC, 0x25, 0xA4, 0xAD, 0xA0, 0xA3, 0xAB, 0x6B, 0xAD, 0xE7, 0xA1, 0x1F, 0x6A, 0x90, 0x68, 0xF8, 0xD7, 0xA8, 0xC2, 0xB8, 0xD9, 0xA4, 0xCF, 0x74, 0xD2, 0x6C, 0xD9, 0x7C, 0xC7, 0xE2, 0xCC, 0xF2, 0xDE, 0xEA, 0xC3, 0x06, 0xCC, 0x16, 0xCE, 0x0E, 0xCD, 0x1E, 0xDF, 0x81, 0xCC, 0x91, 0xDE, 0x89, 0xDD, 0x99, 0xCF, 0x45, 0xCC, 0x55, 0xD6, 0x4D, 0xC5, 0x5D, 0xCB, 0xC3, 0xC0, 0xD3, 0xCC, 0xCB, 0xDA, 0xDB, 0xC1, 0xC7, 0xD5, 0xD7, 0xD3, 0xCF, 0xC7, 0x3F, 0x20, 0x20, 0x28, 0x30, 0x34, 0x28, 0x3C, 0x38, 0x32, 0x24, 0x3A, 0x34, 0x36, 0x2C, 0x2E, 0x3C, 0x3E, 0x22, 0x3E, 0x32, 0x21, 0x2A, 0x21, 0x3A, 0x21, 0x26, 0x21, 0x36, 0x21, 0x2E, 0x21, 0x3E, 0x3E, 0x21, 0x3E, 0x31, 0x3E, 0x29, 0x3E, 0x39, 0x3E, 0x25, 0x3E, 0x35, 0x21, 0x2D, 0x21, 0x3D, 0x31, 0x23, 0x29, 0x33, 0x39, 0x2B, 0x35, 0x3B, 0x2D, 0x27, 0xE3, 0x6F, 0x56, 0x2E, 0xE0, 0xC9, 0x20, 0x3F, 0xAF, 0xA0, 0xA0, 0xB0, 0xB0, 0xA8, 0xA8, 0xB8, 0xB8, 0xA4, 0xA4, 0xB4, 0xA4, 0xAC, 0xB4, 0xBC, 0xB4, 0xA2, 0xA4, 0xB2, 0xA4, 0xAA, 0xB8, 0xBA, 0xA8, 0xA6, 0xB0, 0x36, 0xBF, 0x2E, 0xB7, 0x3E, 0xA7, 0x21, 0xB3, 0x31, 0xAD, 0x29, 0xB9, 0x39, 0xA1, 0x25, 0xB6, 0x35, 0xB2, 0x2D, 0xB4, 0x3D, 0xA0, 0xC3, 0xA7, 0xD3, 0xBD, 0xCB, 0xA9, 0xDB, 0xA6, 0xC7, 0xBC, 0xD7, 0xB0, 0x4F, 0xAB, 0x5F, 0x65, 0x40, 0x6E, 0x50, 0x72, 0x48, 0x78, 0x98, 0x77, 0x84, 0x7D, 0x94, 0x69, 0x8C, 0x66, 0x9C, 0x7C, 0x82, 0x70, 0x12, 0x77, 0x0A, 0x63, 0x1A, 0x79, 0x06, 0x6E, 0x16, 0x6A, 0x0E, 0x6C, 0xFE, 0xD7, 0xFC, 0xE7, 0xC2, 0xEB, 0xE2, 0xE3, 0xD2, 0xED, 0xF2, 0xD5, 0xCA, 0xF9, 0xEA, 0xE9, 0xDA, 0xF1, 0xFA, 0xD1, 0xBF, 0xC3, 0x8D, 0x83, 0xCD, 0xC3, 0xAD, 0xA3, 0xED, 0x93, 0x9D, 0xB3, 0xDD, 0xCB, 0xBD, 0x9B, 0xFD, 0x87, 0x83, 0x97, 0xC3, 0xCF, 0xE3, 0x5F, 0x27, 0xE0, 0xA7, 0x30, 0x67, 0x88, 0xE7, 0xE8, 0x17, 0x78, 0x97, 0xA4, 0x57, 0x34, 0xD7, 0x2C, 0x37, 0xBC, 0xB7, 0x62, 0x77, 0xF2, 0xF7, 0x9A, 0x0F, 0xC6, 0x8F, 0x76, 0xFF, 0x8D, 0x7D, 0xBB, 0x8E, 0x4B, 0x73, 0x7D, 0xF8, 0x38, 0x7E, 0xAF, 0xBB, 0xBB, 0xCD, 0x75, 0xDB, 0xAD, 0x87, 0xB9, 0xEE, 0x19, 0xEB, 0xBD, 0xAC, 0xB1, 0x30, 0xB1, 0xD6, 0x65, 0x0F, 0xDB, 0x95, 0x38, 0x1F, 0x87, 0x85, 0x31, 0xC5, 0x8E, 0x83, 0x1E, 0xC5, 0xEE, 0x0E, 0x0C, 0xEC, 0xEE, 0x56, 0x24, 0xAE, 0xE5, 0xF3, 0x2B, 0xAE, 0xFB, 0x74, 0x1F, 0xDE, 0xFF, 0x7E, 0x3F, 0x4A, 0x37, 0x8C, 0xDE, 0x1B, 0xB3, 0x1A, 0x77, 0x99, 0xF0, 0x64, 0x04, 0x4D, 0xC6, 0x32, 0xD3, 0x59, 0xA5, 0xEC, 0x46, 0xCE, 0x00, 0xF8, 0x47, 0x63, 0x4E, 0xEB, 0x5B, 0xF9, 0xBD, 0x41, 0x5B, 0x01, 0xA8, 0xEE, 0xFB, 0xBE, 0xA0, 0xA9, 0xA4, 0x54, 0xAA, 0x55, 0x08, 0xFC, 0x4D, 0xF1, 0x8C, 0x4F, 0xFF, 0xBE, 0x95, 0x5D, 0x5A, 0x71, 0x27, 0x55, 0x8E, 0x59, 0x82, 0x5E, 0xD4, 0x2C, 0x22, 0x9D, 0x25, 0xBF, 0xE8, 0x3C, 0x89, 0xFA, 0x1F, 0x38, 0x71, 0x13, 0x81, 0x27, 0x29, 0xC7, 0x86, 0xDC, 0xD1, 0x8A, 0xC9, 0xC8, 0xD6, 0xB6, 0xDA, 0x05, 0xD5, 0x1B, 0x00, 0xCF, 0x5F, 0x50, 0x27, 0xA3, 0xEC, 0x5D, 0x5F, 0x0D, 0xFA, 0xDE, 0xA0, 0x16, 0xB5, 0xC5, 0x43, 0xA8, 0x32, 0x08, 0x6D, 0xE7, 0xDC, 0x8D, 0x7D, 0x6F, 0x81, 0xB5, 0xEA, 0x4B, 0x6B, 0x44, 0x2B, 0xCA, 0x35, 0x1C, 0x99, 0xCF, 0x88, 0x2E, 0xDB, 0x0A, 0x96, 0xA2, 0x15, 0x05, 0x9A, 0xA9, 0x6F, 0xA2, 0x87, 0x23, 0xDB, 0x6B, 0x94, 0xC0, 0xF7, 0x18, 0x5E, 0x35, 0x44, 0x66, 0x27, 0x01, 0x9E, 0xDF, 0x19, 0x33, 0xA0, 0x7F, 0x3D, 0xFA, 0x3A, 0xEA, 0x9B, 0x77, 0x38, 0x46, 0x34, 0x4F, 0x1A, 0xBD, 0x48, 0x11, 0x70, 0x6B, 0xB8, 0xBB, 0x23, 0x9A, 0x6F, 0xE4, 0x2E, 0x7C, 0xA7, 0xCB, 0x12, 0xD6, 0x5F, 0x15, 0xBE, 0x3A, 0xCD, 0x4F, 0xA0, 0x8D, 0x0D, 0x2F, 0xC2, 0x64, 0xB4, 0xDC, 0x2E, 0x7B, 0xE8, 0xAC, 0x0C, 0x3E, 0xDE, 0xF3, 0x16, 0x5E, 0x78, 0xCD, 0x23, 0x48, 0x38, 0xC7, 0x39, 0x17, 0x47, 0xB8, 0x30, 0xA9, 0xF0, 0x62, 0x30, 0x87, 0xEE, 0x50, 0x74, 0xA9, 0xE4, 0x09, 0xFD, 0x1D, 0xE0, 0xF9, 0x5D, 0x8D, 0x25, 0x57, 0xE7, 0xE7, 0x60, 0xD1, 0xF7, 0xEA, 0xD5, 0xE4, 0x9B, 0x1E, 0x32, 0x81, 0x36, 0x43, 0xA7, 0xE1, 0x7B, 0xF7, 0x4C, 0x9F, 0x62, 0x93, 0x8E, 0x0B, 0x4B, 0x5C, 0x59, 0x34, 0x6D, 0x78, 0x41, 0x21, 0xDE, 0x9B, 0x23, 0xA7, 0x20, 0x51, 0x6B, 0xBB, 0x21, 0x6B, 0x3D, 0xBC, 0x20, 0x44, 0x88, 0x9C, 0x12, 0x71, 0x55, 0x3A, 0x6C, 0x4B, 0x2F, 0xC4, 0xC3, 0x8B, 0xA4, 0xB5, 0x06, 0xC4, 0xDB, 0x6F, 0x0C, 0xE8, 0xF6, 0xD7, 0xAB, 0xB5, 0x01, 0x8A, 0x38, 0x12, 0x39, 0x3E, 0xE2, 0xE4, 0xB7, 0xE9, 0x5D, 0x7B, 0x01, 0x3A, 0x25, 0xC0, 0xF3, 0x93, 0x31, 0xC2, 0xBE, 0x6F, 0xAD, 0xA3, 0x24, 0x46, 0xFA, 0x5C, 0x63, 0x1C, 0x42, 0xF9, 0xDB, 0xF8, 0xA4, 0x33, 0xAE, 0xBA, 0x26, 0x8E, 0x16, 0xC7, 0xCB, 0x50, 0x2E, 0x97, 0xCC, 0x3A, 0x8B, 0x28, 0x35, 0x7E, 0xC9, 0x93, 0x38, 0xEB, 0x84, 0xB9, 0xF0, 0xE2, 0x55, 0x87, 0x8A, 0xE6, 0x5A, 0xDA, 0x92, 0x62, 0xDD, 0x03, 0x81, 0x0B, 0x06, 0xCF, 0xC1, 0x8A, 0x84, 0x33, 0xF3, 0x76, 0xCE, 0xCE, 0x5C, 0x1B, 0xAD, 0x2D, 0x15, 0x1E, 0x04, 0xA0, 0x9A, 0xCE, 0x28, 0x7B, 0x61, 0x96, 0x1F, 0x5F, 0x77, 0xD1, 0x2B, 0x66, 0x19, 0x40, 0xE1, 0x42, 0xC0, 0xDF, 0x72, 0x4A, 0x78, 0xB9, 0x3A, 0xD9, 0x1A, 0xAD, 0x68, 0x77, 0xA2, 0x8F, 0xD7, 0xDF, 0x6D, 0x2D, 0x19, 0x70, 0x02, 0x3C, 0x3F, 0x5A, 0x9F, 0x44, 0xE9, 0x53, 0x96, 0x18, 0xDA, 0x3A, 0x3E, 0x9B, 0xAA, 0xF0, 0x66, 0x97, 0xA9, 0x62, 0x45, 0x0D, 0x7C, 0xAF, 0xF1, 0x22, 0xDA, 0x99, 0x9C, 0x3B, 0x41, 0x39, 0xBD, 0x3E, 0xBA, 0x00, 0x5E, 0x04, 0x74, 0x68, 0xBC, 0xD8, 0x2F, 0xBA, 0x46, 0xFB, 0xC4, 0x85, 0xB7, 0x41, 0xBD, 0xCE, 0xB0, 0x82, 0x8C, 0xFD, 0xF2, 0x3B, 0xAA, 0x43, 0x35, 0x16, 0xB1, 0x65, 0x99, 0xB0, 0xA2, 0xFC, 0xCD, 0x89, 0x2B, 0x9F, 0x0A, 0xC9, 0x2D, 0x4E, 0x7B, 0x1A, 0x33, 0x60, 0x05, 0x27, 0xC6, 0x9A, 0xB0, 0xC4, 0x62, 0x53, 0xF6, 0xBA, 0xE7, 0xF8, 0xF2, 0x81, 0x3A, 0x00, 0x45, 0x9D, 0x77, 0x6D, 0x8A, 0xF6, 0xDC, 0x1B, 0x26, 0x78, 0xDC, 0xE4, 0x2B, 0x80, 0x22, 0x2A, 0x2E, 0xD6, 0x33, 0xF1, 0x64, 0xFA, 0x5A, 0xF0, 0x1F, 0x78, 0xC6, 0x1F, 0xA2, 0x6F, 0x3D, 0xC1, 0x59, 0xB5, 0x7E, 0xFB, 0x73, 0xAB, 0x00, 0x9C, 0x6D, 0xC9, 0x6C, 0x8F, 0x72, 0xDD, 0xFD, 0x32, 0xC9, 0x41, 0x91, 0xF0, 0x20, 0x9E, 0x64, 0x3A, 0x74, 0x64, 0xE3, 0xAA, 0xE7, 0x0B, 0x5A, 0x1C, 0x96, 0x74, 0x4E, 0x81, 0x15, 0x24, 0xB6, 0xB8, 0xE3, 0x8C, 0x59, 0x08, 0xB2, 0x5E, 0xD5, 0xCC, 0x2F, 0xEF, 0x14, 0xAC, 0x48, 0xED, 0x38, 0xA1, 0x82, 0x7C, 0xB4, 0x7C, 0xFA, 0xA5, 0xBC, 0x48, 0x1B, 0x58, 0xD1, 0x9A, 0x74, 0x4F, 0x10, 0xF9, 0x4C, 0xBB, 0x8F, 0xC2, 0x01, 0x50, 0xA1, 0xCE, 0xEB, 0xA6, 0x7E, 0x2A, 0xCE, 0xF0, 0x65, 0x62, 0xE1, 0x45, 0x4B, 0xCE, 0xB9, 0xCD, 0xDB, 0x4C, 0x76, 0x2C, 0x97, 0x7A, 0x90, 0x5D, 0x0E, 0x50, 0x10, 0x37, 0x58, 0x29, 0xDB, 0x3D, 0x73, 0x3C, 0x95, 0xEF, 0x80, 0x56, 0x8C, 0x60, 0x5B, 0x07, 0xBB, 0x75, 0xC7, 0xAA, 0xC1, 0x3F, 0x46, 0xAB, 0x44, 0x6D, 0x34, 0xDA, 0x36, 0xEE, 0x93, 0x9E, 0xE5, 0x3E, 0xEF, 0x3E, 0xB0, 0x0D, 0x82, 0xEF, 0xF4, 0x5E, 0xA2, 0x93, 0x36, 0x69, 0x77, 0xFB, 0xFC, 0x9B, 0xBA, 0x51, 0x1D, 0x66, 0xB0, 0xC2, 0xC1, 0x50, 0xB9, 0x66, 0x76, 0x26, 0xF2, 0xD1, 0xB9, 0xEE, 0xD4, 0x99, 0xB0, 0x22, 0x6E, 0xA6, 0xA0, 0x0F, 0xF2, 0x99, 0xBC, 0x1F, 0x91, 0x09, 0x2B, 0x2A, 0xE4, 0x6E, 0xC7, 0x4C, 0xF7, 0xFC, 0x54, 0x6C, 0x9A, 0x6F, 0x33, 0xD2, 0x1B, 0xCB, 0x5D, 0x4C, 0x64, 0xBD, 0x9E, 0x94, 0xF0, 0xFF, 0x54, 0xAC, 0xBD, 0xE0, 0xB8, 0x69, 0x14, 0x7A, 0x38, 0x99, 0x34, 0xD5, 0x4E, 0xE4, 0x33, 0x27, 0x26, 0x80, 0xE2, 0xAC, 0xB4, 0xDB, 0xF9, 0xA5, 0xB0, 0x36, 0x03, 0x28, 0xF2, 0x05, 0xE5, 0xD3, 0x30, 0xA7, 0x0F, 0x29, 0x9B, 0xB9, 0x02, 0x54, 0xEF, 0x57, 0x86, 0x67, 0x52, 0x90, 0x74, 0x71, 0xC0, 0x03, 0x98, 0xD5, 0xF4, 0x2B, 0xF9, 0xB3, 0x72, 0xD7, 0xA5, 0x77, 0xD2, 0x6F, 0x73, 0xAF, 0xAC, 0x96, 0x84, 0x17, 0xBE, 0xBB, 0x9D, 0xFC, 0xEF, 0xC5, 0x1B, 0xF6, 0x1B, 0xBD, 0x8A, 0xC2, 0x01, 0x88, 0x47, 0x75, 0x98, 0x7B, 0xB2, 0x92, 0x62, 0x07, 0x57, 0x27, 0xCC, 0xDB, 0xED, 0xBC, 0x1F, 0x56, 0x14, 0x3C, 0x3B, 0xA4, 0x89, 0x7C, 0xA5, 0x3F, 0x4A, 0x3F, 0xCC, 0x5D, 0x74, 0xCA, 0x58, 0x79, 0x6D, 0x7B, 0xFB, 0xA5, 0x38, 0x2A, 0x99, 0x92, 0x0A, 0x20, 0xC8, 0x53, 0x2F, 0x1E, 0xFB, 0x52, 0x1C, 0xA1, 0x67, 0x40, 0x0F, 0xA7, 0xB6, 0xFB, 0x21, 0xE9, 0x4B, 0xA1, 0x90, 0x96, 0x3F, 0x0E, 0xA0, 0xC2, 0x45, 0x84, 0xD6, 0xEE, 0x5E, 0xBD, 0xAF, 0x67, 0x9F, 0x49, 0xC9, 0x6A, 0x78, 0x31, 0xBC, 0xD8, 0xBC, 0xD2, 0xD2, 0xE1, 0xC5, 0x77, 0x5E, 0x5B, 0x8B, 0xAD, 0x00, 0x8A, 0x92, 0x96, 0x86, 0x33, 0x43, 0x9B, 0xC0, 0x7F, 0xE0, 0xE1, 0xEC, 0x04, 0x50, 0x7D, 0xAE, 0x25, 0xD6, 0xC9, 0xA4, 0x88, 0x07, 0x21, 0x18, 0xF2, 0x70, 0xDC, 0x5E, 0x96, 0x23, 0x77, 0x11, 0x12, 0xFB, 0x28, 0xD1, 0x50, 0x1F, 0x6B, 0x71, 0x2D, 0x4A, 0xA5, 0xE6, 0x68, 0x5C, 0x99, 0x1C, 0xEC, 0xDD, 0xE4, 0x5B, 0x87, 0xB7, 0xEE, 0xD8, 0x7A, 0x67, 0xEE, 0x18, 0x82, 0x6C, 0x6C, 0x08, 0xAA, 0xE1, 0x2E, 0x98, 0x47, 0x09, 0xD1, 0x8A, 0xE2, 0xC8, 0x57, 0xF8, 0xCB, 0x00, 0x22, 0xD5, 0x04, 0xF7, 0xF4, 0x5F, 0xC5, 0x56, 0x58, 0x31, 0x38, 0x9D, 0x50, 0x22, 0x80, 0xD9, 0xDE, 0xC6, 0x2F, 0xB9, 0x54, 0xD6, 0xDE, 0x04, 0x40, 0xE5, 0xB7, 0x68, 0x06, 0xEA, 0x9E, 0x34, 0xA7, 0x3E, 0xDC, 0x62, 0xF9, 0x0C, 0xA0, 0x08, 0x3F, 0x4B, 0xD9, 0x9F, 0x5B, 0x44, 0x3F, 0xD4, 0x2F, 0x06, 0x78, 0x7E, 0x05, 0x63, 0xFB, 0x1A, 0xB4, 0xCB, 0xDC, 0xCA, 0x8E, 0xD7, 0xBA, 0xB4, 0x17, 0x31, 0xEA, 0x20, 0xF7, 0x30, 0x0D, 0x01, 0x6F, 0x5E, 0x84, 0xE2, 0x65, 0xAD, 0x5C, 0x6D, 0xCC, 0x2D, 0x59, 0x04, 0x3F, 0xC8, 0x7F, 0xB8, 0xF8, 0x90, 0x75, 0x9C, 0xF1, 0xCD, 0x43, 0xD1, 0xEB, 0xF3, 0x4B, 0x11, 0x04, 0x3B, 0x77, 0x38, 0x02, 0x72, 0x0F, 0xB3, 0x40, 0x3D, 0x19, 0xF9, 0x4A, 0x26, 0xA3, 0x7A, 0x14, 0xF2, 0x48, 0xE7, 0x6C, 0x23, 0xBB, 0x66, 0xC5, 0xBA, 0x91, 0xD9, 0x23, 0x1F, 0x8B, 0x15, 0xD5, 0x1A, 0x00, 0x22, 0x82, 0xAA, 0x22, 0x79, 0x89, 0x72, 0x69, 0xF4, 0xD2, 0xB9, 0xF3, 0x2B, 0x1B, 0x82, 0x60, 0x45, 0xC7, 0x7D, 0x87, 0x31, 0x0F, 0x8B, 0xC0, 0xD5, 0x51, 0xA9, 0x69, 0x4A, 0x4D, 0xBA, 0x00, 0xAA, 0x7A, 0xAC, 0x35, 0x74, 0x2C, 0x01, 0xF0, 0xFC, 0x6A, 0x58, 0x53, 0x06, 0x3D, 0x87, 0xBC, 0x59, 0x2F, 0xE1, 0x6B, 0xAF, 0x6F, 0x8E, 0x4A, 0x24, 0x31, 0x70, 0x9F, 0xDF, 0xCA, 0x60, 0x93, 0x88, 0xB5, 0x51, 0x13, 0xC3, 0xDF, 0x70, 0x37, 0x04, 0x8F, 0x5B, 0x6D, 0x97, 0x9F, 0xAA, 0x3C, 0x97, 0x89, 0xDD, 0x9D, 0x23, 0x38, 0x3B, 0xC1, 0x11, 0x72, 0x0F, 0x23, 0x62, 0x20, 0x82, 0xFC, 0x8B, 0xFB, 0x4A, 0xC8, 0x23, 0x5D, 0xFA, 0x5B, 0x45, 0x89, 0x6D, 0x8A, 0x4B, 0x15, 0x84, 0x45, 0x42, 0xB6, 0x89, 0x11, 0x1E, 0x00, 0x88, 0x2C, 0x4F, 0xE3, 0xEA, 0x47, 0x64, 0x9B, 0x2B, 0xCE, 0xF9, 0x6F, 0xEE, 0x7A, 0x2B, 0x01, 0x98, 0xA8, 0x08, 0x11, 0xEA, 0xFB, 0xA2, 0x6F, 0x1B, 0x98, 0x63, 0xAE, 0x00, 0x05, 0xEB, 0x14, 0xE0, 0xF9, 0x5D, 0x75, 0xDC, 0x2B, 0xCC, 0xA4, 0xD2, 0x52, 0x6C, 0x72, 0x1A, 0x69, 0x6D, 0x75, 0x32, 0x43, 0xBE, 0xDC, 0x45, 0x4C, 0x86, 0x55, 0x8C, 0x39, 0xC9, 0x58, 0x5D, 0x5B, 0x45, 0xC3, 0x51, 0x63, 0x17, 0x6E, 0x0B, 0x77, 0x41, 0x0B, 0xB4, 0xA9, 0x9C, 0x8D, 0x5F, 0xEC, 0x3B, 0x63, 0x3D, 0xF2, 0x91, 0xFC, 0x36, 0xB6, 0x1A, 0xD7, 0xE3, 0xEC, 0x94, 0x88, 0x4C, 0x15, 0x47, 0x0D, 0xC3, 0xEB, 0x57, 0xF4, 0xA6, 0xEB, 0xF5, 0xE1, 0xAC, 0xE1, 0xEF, 0x5C, 0x39, 0x46, 0xFD, 0xDF, 0x94, 0xE0, 0xF6, 0x84, 0x85, 0x79, 0x78, 0xBA, 0x13, 0x80, 0xAA, 0xF0, 0x6E, 0x78, 0x3A, 0xB4, 0x1E, 0xF0, 0xFC, 0xA9, 0x74, 0x1F, 0xAD, 0x3D, 0x50, 0xEF, 0xDF, 0x65, 0x30, 0xF9, 0x14, 0xBE, 0x97, 0xED, 0x24, 0x0A, 0xBF, 0x7C, 0xE8, 0x36, 0xCB, 0x9E, 0xE6, 0xF8, 0xF2, 0x55, 0xF1, 0xBB, 0x1D, 0x55, 0xB2, 0xFF, 0x5B, 0x0C, 0xDD, 0xF4, 0x39, 0xB2, 0xDB, 0x56, 0x2A, 0x4F, 0xCE, 0x50, 0x76, 0x42, 0x02, 0xD9, 0x1D, 0x4F, 0xA6, 0x01, 0x2E, 0xB9, 0x34, 0xE3, 0x38, 0x0B, 0x11, 0xFB, 0x6B, 0x5E, 0x6B, 0x02, 0x17, 0xC4, 0x68, 0xA6, 0x1B, 0x71, 0x17, 0xE3, 0x53, 0x43, 0xA5, 0x13, 0x6B, 0xF2, 0xFB, 0x9B, 0x2F, 0x30, 0x0D, 0x01, 0x8A, 0x91, 0x3C, 0xCE, 0x2D, 0xC0, 0xF3, 0xA7, 0xC3, 0x68, 0x64, 0x0F, 0xA3, 0xAF, 0x43, 0x7D, 0x49, 0x8D, 0x31, 0xA6, 0x51, 0x72, 0x51, 0x95, 0xF1, 0xC5, 0x59, 0x39, 0xB4, 0xEE, 0x1E, 0x1F, 0xEE, 0x86, 0xEA, 0xA1, 0xBE, 0x40, 0x2B, 0xD4, 0x60, 0x9F, 0xD9, 0x7A, 0xCB, 0xD7, 0xB6, 0xC6, 0x4E, 0x4B, 0x20, 0xF7, 0x75, 0xE2, 0x2F, 0x73, 0xFD, 0xFB, 0xA2, 0xCE, 0x64, 0x37, 0xD6, 0x1F, 0x1F, 0x36, 0x00, 0x50, 0x85, 0x0A, 0xF5, 0xDB, 0x07, 0xE2, 0xC1, 0xDF, 0x0E, 0x4F, 0xF3, 0x0C, 0x5A, 0x55, 0x65, 0x2C, 0x3D, 0xB2, 0xF9, 0x29, 0x63, 0x05, 0x4A, 0xF1, 0xDD, 0xB3, 0x27, 0xCE, 0xB3, 0xDF, 0x05, 0x85, 0x8B, 0xA6, 0x16, 0x57, 0x04, 0xB5, 0xCD, 0x63, 0x2C, 0xE1, 0x6E, 0x28, 0x84, 0x7C, 0x1C, 0xFD, 0xC9, 0x70, 0x1B, 0x40, 0x35, 0x8C, 0x80, 0xBF, 0x31, 0xE4, 0x1F, 0x6E, 0xCA, 0x94, 0x69, 0xD3, 0x66, 0xCC, 0x98, 0x35, 0x6B, 0xCE, 0x9C, 0x79, 0xF3, 0x16, 0x2C, 0x58, 0xB4, 0x68, 0xC9, 0x92, 0x65, 0xCB, 0x56, 0xAC, 0x58, 0xB5, 0x6A, 0xCD, 0x9A, 0x75, 0xEB, 0x36, 0x6C, 0xD8, 0xB4, 0x89, 0x9F, 0x5F, 0x50, 0x50, 0x58, 0x78, 0xCB, 0x96, 0x6D, 0xDB, 0x76, 0xEC, 0xD8, 0xB5, 0x6B, 0xCF, 0x9E, 0x7D, 0xFB, 0x44, 0x44, 0xC4, 0xC4, 0x24, 0x24, 0xA4, 0xA4, 0x64, 0x64, 0xE4, 0xE4, 0x14, 0x14, 0x94, 0x94, 0x30, 0x18, 0x65, 0xE5, 0x43, 0x87, 0x8E, 0x1C, 0x39, 0x76, 0xEC, 0xC4, 0x89, 0x53, 0xA7, 0xCE, 0x9C, 0x39, 0x77, 0x4E, 0x55, 0x55, 0x5D, 0xFD, 0xC2, 0x85, 0x4B, 0x97, 0xAE, 0x5C, 0xB9, 0x76, 0x4D, 0x43, 0x43, 0x4B, 0x4B, 0x47, 0x07, 0x8B, 0xBD, 0x79, 0xF3, 0xF6, 0x6D, 0x3D, 0x3D, 0x03, 0x03, 0x23, 0x23, 0x63, 0x63, 0x53, 0x53, 0x73, 0xF3, 0xBB, 0x77, 0xEF, 0xDF, 0x7F, 0xF8, 0xF0, 0xF1, 0xE3, 0xA7, 0x4F, 0x2D, 0x2C, 0xAC, 0xAC, 0x6C, 0x6C, 0xEC, 0xEC, 0xF0, 0x78, 0x07, 0x07, 0x27, 0x27, 0x17, 0x17, 0x37, 0xB7, 0x97, 0x2F, 0x5F, 0xBF, 0x76, 0x77, 0xF7, 0xF0, 0xF0, 0xF4, 0xF4, 0xF2, 0x22, 0x12, 0x7D, 0x7C, 0xFC, 0xFC, 0x48, 0xA4, 0xC0, 0xC0, 0xE0, 0xE0, 0x90, 0x10, 0x32, 0x39, 0x3C, 0x3C, 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x9E, 0x42, 0x49, 0x4C, 0x4C, 0x4A, 0xA2, 0x52, 0x53, 0x53, 0xD3, 0xD3, 0x33, 0x33, 0xB3, 0xB3, 0x73, 0x73, 0xF3, 0xF3, 0x0B, 0x0B, 0x8B, 0x8B, 0x4B, 0x4B, 0xCB, 0xCB, 0x2B, 0x2B, 0xAB, 0xAA, 0x6A, 0x6A, 0xE8, 0xF4, 0xFA, 0xFA, 0xC6, 0xC6, 0xE6, 0xE6, 0xD6, 0xD6, 0xF6, 0xF6, 0xCE, 0xCE, 0xEE, 0xEE, 0xDE, 0xDE, 0xFE, 0xFE, 0xC1, 0xC1, 0xE1, 0xE1, 0xD1, 0xD1, 0xF1, 0x71, 0x06, 0x83, 0xC9, 0x64, 0xB3, 0x3F, 0x5D, 0xFE, 0x26, 0x3A, 0x77, 0x4C, 0x90, 0x8F, 0x30, 0x2A, 0x47, 0x44, 0x16, 0xCC, 0x5D, 0x30, 0xF7, 0x80, 0xF2, 0x39, 0xCC, 0xD9, 0x23, 0xA7, 0x55, 0x4E, 0x9D, 0xE5, 0x13, 0x50, 0xC2, 0x61, 0xEF, 0xEA, 0xEA, 0xF2, 0x61, 0x34, 0x74, 0x6F, 0x6A, 0xE2, 0x34, 0x4C, 0x6E, 0x1A, 0xE8, 0xF3, 0xA9, 0x68, 0xE0, 0xB0, 0x3A, 0x26, 0x7C, 0x5A, 0x37, 0x34, 0x70, 0x26, 0x7C, 0x37, 0xF5, 0xAF, 0x1B, 0xE0, 0xF4, 0xBE, 0x0C, 0x22, 0x3B, 0xF9, 0x76, 0xF0, 0x61, 0x71, 0x3A, 0x77, 0xF9, 0xCC, 0x75, 0xB4, 0xB1, 0x3A, 0x7C, 0x1F, 0xFF, 0x2D, 0xEE, 0x03, 0xDB, 0x64, 0x95, 0xEC, 0x36, 0x0C, 0x05, 0xD0, 0xEF, 0xD2, 0x1E, 0x34, 0x5E, 0x40, 0x47, 0x64, 0xE8, 0xFB, 0xD3, 0xB3, 0x95, 0xD4, 0x24, 0x7B, 0x24, 0xA5, 0xDC, 0xEA, 0x31, 0x33, 0xEC, 0xBF, 0x86, 0xB9, 0x1D, 0xA7, 0xB9, 0xC1, 0xE3, 0x73, 0x61, 0x84, 0x87, 0xCF, 0xD1, 0x87, 0xB7, 0x9D, 0x2D, 0xD7, 0xA5, 0x51, 0xCB, 0x86, 0x0F, 0x4F, 0x97, 0x77, 0x2F, 0x4F, 0xA7, 0x87, 0x27, 0x43, 0x38, 0xB7, 0x5A, 0x79, 0x5D, 0x90, 0xC8, 0x5F, 0xBC, 0x92, 0xEA, 0xF5, 0x86, 0x50, 0x41, 0x58, 0xB2, 0xC7, 0xF8, 0x9E, 0x64, 0x84, 0x53, 0x2A, 0x86, 0x9C, 0x5A, 0x7F, 0xFF, 0xDA, 0xD9, 0x21, 0xA7, 0xD0, 0x5F, 0xCA, 0x5C, 0x87, 0xBC, 0x51, 0xCE, 0x0D, 0x7E, 0xF9, 0x48, 0xA2, 0x6E, 0xE3, 0xFB, 0x8D, 0x5F, 0xA6, 0x7B, 0x65, 0xD7, 0xDA, 0x87, 0xD2, 0x38, 0x6F, 0x37, 0xAD, 0x36, 0x63, 0x70, 0xC7, 0x91, 0x68, 0xFD, 0x74, 0xFA, 0x72, 0x78, 0xDE, 0x1E, 0x1E, 0x1F, 0x9D, 0xBE, 0x5C, 0x10, 0xF7, 0x70, 0x7A, 0xFC, 0xF2, 0x74, 0xEF, 0x8E, 0x0F, 0xEF, 0x96, 0xBD, 0x56, 0x9B, 0xA6, 0x09, 0xAE, 0x1F, 0x46, 0x5B, 0x84, 0x5E, 0xF9, 0xFC, 0xB3, 0x1E, 0x47, 0x80, 0x58, 0x12, 0x71, 0x21, 0x93, 0xAD, 0x61, 0x74, 0x5E, 0x35, 0xA1, 0x34, 0x75, 0x68, 0xCA, 0xB6, 0x9C, 0x06, 0xB1, 0x6D, 0x48, 0x24, 0x19, 0xFD, 0x48, 0x97, 0x35, 0x79, 0xD7, 0x74, 0x36, 0x58, 0xDD, 0x0F, 0xF2, 0x1F, 0x0F, 0xBA, 0xFD, 0x5E, 0x87, 0x6F, 0xDF, 0x7F, 0x2C, 0x53, 0x5D, 0xAF, 0x73, 0x6F, 0x87, 0x7E, 0xFB, 0xCA, 0x14, 0xE3, 0xA0, 0xB6, 0x05, 0x89, 0x44, 0x82, 0xA6, 0x3B, 0xAF, 0xAC, 0x0F, 0xA6, 0x85, 0x8A, 0xA5, 0x1B, 0x8A, 0xB2, 0x61, 0x44, 0xD3, 0x0B, 0x2D, 0xD6, 0xA6, 0x80, 0xD2, 0x2D, 0x43, 0xA2, 0x54, 0x2C, 0x0A, 0xFF, 0x2B, 0x0D, 0x43, 0xD7, 0x68, 0xC7, 0x7D, 0xDA, 0x75, 0x92, 0x22, 0x8E, 0x21, 0x8E, 0x23, 0x4E, 0x20, 0x4E, 0x22, 0x2E, 0x46, 0x5C, 0x82, 0xB8, 0x14, 0x71, 0x19, 0xE2, 0x90, 0x79, 0xC4, 0x14, 0x71, 0x0C, 0x71, 0x1C, 0x71, 0x02, 0x71, 0x12, 0x71, 0x31, 0xE2, 0x12, 0xC4, 0xA5, 0x88, 0xCB, 0x10, 0x87, 0xCC, 0x23, 0xA1, 0x88, 0x63, 0x88, 0xE3, 0x88, 0x13, 0x88, 0x93, 0x88, 0x8B, 0x11, 0x97, 0x20, 0x2E, 0x45, 0x5C, 0x86, 0x38, 0x64, 0x1E, 0x29, 0x45, 0x1C, 0x43, 0x1C, 0x47, 0x9C, 0x18, 0x9D, 0xD9, 0xB4, 0xFB, 0xDA, 0x86, 0x6E, 0x15, 0x56, 0xA5, 0x6E, 0x0A, 0x47, 0xA4, 0xFC, 0xF0, 0x76, 0x5F, 0xAF, 0x4B, 0x13, 0x0A, 0xE5, 0x55, 0x58, 0x75, 0xB6, 0x55, 0x7E, 0xB8, 0x17, 0xAA, 0xED, 0x1B, 0x1D, 0xCA, 0x82, 0x4C, 0x77, 0x36, 0x9F, 0xFF, 0xDA, 0xF9, 0xEF, 0xFB, 0xFC, 0x57, 0x93, 0xE1, 0x2A, 0x87, 0x6F, 0xD3, 0xEF, 0xF7, 0xE9, 0xF7, 0x07, 0x81, 0x6B, 0x42, 0xE0, 0x6E, 0xCC, 0x20, 0x29, 0x00, 0x03, 0xE0, 0x00, 0x02, 0x40, 0x02, 0xC4, 0x00, 0x09, 0x40, 0x0A, 0x90, 0x01, 0x40, 0xE7, 0x98, 0x02, 0x30, 0x00, 0x0E, 0x20, 0x00, 0x24, 0x40, 0x0C, 0x90, 0x00, 0xA4, 0x00, 0x19, 0x00, 0x74, 0x4E, 0x28, 0x00, 0x03, 0xE0, 0x00, 0x02, 0x40, 0x02, 0xC4, 0x00, 0x09, 0x40, 0x0A, 0x90, 0x01, 0x40, 0xE7, 0x94, 0x02, 0x30, 0x00, 0x0E, 0x30, 0x74, 0xFE, 0xF0, 0x56, 0x9B, 0x62, 0x7B, 0x3B, 0x96, 0x1B, 0xE7, 0xB4, 0x77, 0x84, 0x8B, 0xF4, 0x2F, 0x21, 0xF5, 0x75, 0xC5, 0xB8, 0xAD, 0x45, 0x61, 0xF8, 0xF9, 0x06, 0xF7, 0xA0, 0x0A, 0xB0, 0x4E, 0x0E, 0xFD, 0x37, 0x66, 0x62, 0x6F, 0x79, 0xD6, 0x70, 0x9C, 0x9E, 0x3E, 0x65, 0x02, 0x3F, 0x0E, 0x55, 0x3F, 0x1F, 0xDC, 0x6F, 0xFF, 0xD5, 0x0F, 0xFF, 0xB8, 0xFE, 0x9A, 0x99, 0x73, 0x37, 0xBF, 0x7A, 0x72, 0xF3, 0xD3, 0x75, 0x7C, 0xFD, 0xE3, 0x67, 0x6F, 0x3E, 0x3B, 0x26, 0xA0, 0xFD, 0x41, 0xE3, 0x78, 0xCB, 0x27, 0xED, 0xD4, 0xE2, 0x7B, 0xEA, 0xF2, 0xD9, 0x3D, 0xAA, 0xA0, 0xE2, 0xA1, 0xCF, 0xF6, 0x43, 0x9E, 0xAD, 0x87, 0x38, 0x26, 0x0F, 0x76, 0xA6, 0x70, 0x85, 0x25, 0xDE, 0xC0, 0xFC, 0x41, 0xCE, 0x1A, 0xE1, 0x7B, 0xF2, 0x7D, 0x36, 0x78, 0x16, 0x42, 0x0A, 0x14, 0xE9, 0xC5, 0x6F, 0x4A, 0x01, 0x77, 0xB2, 0xA0, 0xE5, 0xC1, 0x8F, 0x14, 0x70, 0x12, 0x4E, 0x06, 0x64, 0x83, 0x1E, 0x2C, 0x50, 0x0A, 0x98, 0x81, 0xEC, 0x1B, 0xD9, 0xFE, 0x2D, 0x98, 0x8F, 0x73, 0x75, 0x75, 0x83, 0x59, 0xD7, 0x0D, 0xE6, 0x28, 0xA5, 0xA4, 0xBE, 0xC1, 0xC2, 0x10, 0xAC, 0xF9, 0x3D, 0x94, 0x9A, 0xB3, 0x8B, 0x60, 0xD1, 0x08, 0x36, 0xF2, 0x90, 0xDC, 0x55, 0x70, 0xFF, 0xF6, 0x63, 0xAB, 0x0D, 0x74, 0x81, 0x04, 0xDA, 0xB4, 0x91, 0x02, 0xF3, 0x7D, 0xC6, 0x60, 0x26, 0xA4, 0x40, 0x0C, 0x28, 0x03, 0x33, 0xF8, 0x69, 0x4D, 0x60, 0x0E, 0x92, 0xAC, 0x21, 0x8A, 0x09, 0x69, 0xE0, 0x02, 0xC2, 0x40, 0x91, 0x0D, 0xAC, 0x53, 0x15, 0x44, 0xDC, 0x60, 0xFE, 0xCF, 0xC1, 0xF6, 0x84, 0x0F, 0x2F, 0x16, 0x9F, 0x9E, 0x13, 0xA6, 0x9F, 0x38, 0xA6, 0x28, 0xE5, 0x02, 0x5A, 0x19, 0x2C, 0x6F, 0x30, 0xE7, 0xF9, 0x73, 0xC7, 0x2A, 0x76, 0x3C, 0x40, 0xE9, 0x83, 0x9C, 0xCC, 0x5B, 0x11, 0x47, 0x56, 0x47, 0x1B, 0x0B, 0x29, 0xE5, 0xE1, 0x2A, 0xC7, 0xA0, 0x40, 0x2C, 0x10, 0xCE, 0xF7, 0x2E, 0x49, 0x30, 0xC1, 0x1A, 0x43, 0x1A, 0x78, 0x80, 0x20, 0x65, 0x60, 0x82, 0x0C, 0x47, 0x6B, 0x41, 0x28, 0xA8, 0x24, 0x45, 0x16, 0xF4, 0xAB, 0x94, 0x39, 0x70, 0x05, 0xA5, 0x37, 0x58, 0xFC, 0xEB, 0x84, 0x85, 0xE2, 0x4E, 0xA9, 0xC6, 0x84, 0xAD, 0x3C, 0xC1, 0x24, 0x50, 0x4A, 0x06, 0xD4, 0x32, 0x58, 0x08, 0x27, 0xAC, 0x38, 0x61, 0x85, 0xD1, 0x12, 0x03, 0x29, 0x9C, 0x30, 0x7B, 0x4D, 0x18, 0x13, 0x15, 0x33, 0x74, 0x00, 0x6D, 0x80, 0xF7, 0xE4, 0xD4, 0x82, 0x0E, 0x30, 0x02, 0xDA, 0xF9, 0x49, 0x62, 0x24, 0x02, 0xE4, 0x80, 0x11, 0xF6, 0x6E, 0xA0, 0x05, 0xA2, 0xC1, 0x70, 0xA6, 0xB4, 0x80, 0x39, 0x19, 0xE0, 0x05, 0x72, 0xC0, 0x70, 0x9D, 0x2A, 0x20, 0xFC, 0x06, 0x4B, 0x1C, 0xFC, 0xDD, 0xEA, 0xDD, 0xC0, 0xBD, 0xDF, 0xCC, 0xDA, 0x70, 0x1E, 0xD3, 0x1F, 0x3D, 0x36, 0x56, 0x0F, 0xAE, 0x5B, 0x9F, 0x7B, 0xE5, 0xB1, 0x27, 0xA6, 0x2E, 0xA3, 0xA6, 0x5C, 0xF5, 0xC8, 0xD7, 0x2D, 0x14, 0x1C, 0x7B, 0xF0, 0xA3, 0x0A, 0x64, 0xF9, 0x22, 0xA9, 0x00, 0xA1, 0x40, 0x17, 0x48, 0xF2, 0xEB, 0x0A, 0x7A, 0x41, 0x35, 0x48, 0x03, 0x21, 0xC0, 0x1A, 0x68, 0x00, 0x69, 0x92, 0xA4, 0xDE, 0xFC, 0xC3, 0x7B, 0x0B, 0xD4, 0x49, 0xBD, 0x48, 0xE2, 0x24, 0x48, 0x02, 0x2B, 0xB9, 0xCD, 0xEA, 0x93, 0x73, 0x34, 0xE7, 0x53, 0x67, 0x4D, 0x6F, 0x90, 0xB0, 0x98, 0xC4, 0xE1, 0x7B, 0xF1, 0xCF, 0xFD, 0xE2, 0x65, 0xFD, 0xB0, 0x11, 0x75, 0x3F, 0x33, 0x8C, 0x16, 0xF5, 0x73, 0xB4, 0x6F, 0x03, 0x3F, 0x61, 0x60, 0x2F, 0x71, 0x44, 0xF0, 0x6C, 0x02, 0x94, 0x80, 0x30, 0x60, 0x09, 0x34, 0x80, 0x5C, 0xEC, 0x47, 0x7A, 0xD2, 0x0E, 0xB2, 0x81, 0x13, 0x1D, 0x20, 0x49, 0x84, 0xCD, 0x9B, 0x14, 0x49, 0xD2, 0x64, 0xBE, 0x9F, 0x24, 0x01, 0x54, 0x48, 0xBC, 0xC8, 0x17, 0x45, 0x06, 0xB8, 0x22, 0x5A, 0x73, 0xD0, 0x7E, 0xBD, 0x25, 0xF7, 0x66, 0x9A, 0x7B, 0xCE, 0x2E, 0xFA, 0x30, 0xAA, 0x71, 0xF7, 0xE1, 0xA3, 0xB7, 0x55, 0xF2, 0xA3, 0xE9, 0xDF, 0x66, 0xDF, 0x0B, 0x7C, 0x43, 0x90, 0x5A, 0x30, 0x06, 0x5A, 0x40, 0x2A, 0x70, 0x03, 0x3A, 0x40, 0xE6, 0xAF, 0x5A, 0x29, 0x88, 0x05, 0xC6, 0x0B, 0x4D, 0x81, 0x74, 0xE0, 0x0A, 0x8C, 0x68, 0x12, 0x01, 0xB2, 0x64, 0x5E, 0x2C, 0x50, 0x25, 0x45, 0xE6, 0xC5, 0x92, 0x24, 0x05, 0xCC, 0x08, 0xE7, 0x6C, 0x7E, 0x49, 0x16, 0x7B, 0xA4, 0xE2, 0xB3, 0x7D, 0x5C, 0x83, 0x3F, 0xA1, 0x0F, 0x6E, 0x26, 0x0F, 0xAD, 0xDB, 0x37, 0x95, 0x7E, 0x93, 0x09, 0xDD, 0xFD, 0xEE, 0xC8, 0x78, 0x1A, 0x09, 0x62, 0x48, 0x00, 0x73, 0x20, 0xC6, 0x4F, 0x26, 0x68, 0x07, 0x35, 0xA0, 0x8D, 0x0C, 0x69, 0x50, 0xFD, 0xAA, 0x54, 0xC0, 0xE4, 0x95, 0x27, 0x88, 0x91, 0x5F, 0x16, 0x25, 0x4A, 0xE4, 0xFD, 0xD4, 0x48, 0x92, 0x26, 0xF9, 0xA2, 0x08, 0x51, 0x21, 0x81, 0x6C, 0xFB, 0x47, 0x36, 0xDB, 0xA3, 0xB2, 0xDF, 0x7A, 0x7C, 0x91, 0xA7, 0x12, 0x76, 0xF1, 0x51, 0xEC, 0xAF, 0xF2, 0x23, 0x58, 0xFC, 0x2B, 0x5B, 0x5F, 0xB1, 0x61, 0x64, 0x0B, 0x10, 0x4D, 0x1C, 0x98, 0x01, 0x51, 0x66, 0x7B, 0xF5, 0xCA, 0x02, 0xE8, 0xFC, 0x3B, 0xE1, 0x76, 0x82, 0xEB, 0x38, 0xAF, 0x2B, 0x01, 0x78, 0x2B, 0x59, 0x81, 0x21, 0xCE, 0xE4, 0xFE, 0x37, 0xF6, 0x3A, 0x55, 0x36, 0x8E, 0xF9, 0x23, 0xB8, 0x0F, 0xD3, 0x07, 0xF7, 0x94, 0xE3, 0x8A, 0x28, 0x51, 0xB2, 0xFB, 0x1F, 0x02, 0x2C, 0x80, 0xF6, 0x0A, 0x4A, 0xC1, 0xF1, 0x27, 0x19, 0x5A, 0xB7, 0xB9, 0x9D, 0xD8, 0x4E, 0x6D, 0xA7, 0xCF, 0x8E, 0xD4, 0x88, 0x2E, 0x36, 0x41, 0x06, 0xE9, 0xC9, 0x9D, 0x14, 0x59, 0x85, 0x9A, 0xE6, 0x88, 0xCF, 0x14, 0x1F, 0x90, 0xF1, 0x8F, 0x3E, 0xD2, 0xDF, 0x15, 0x21, 0xF9, 0xF1, 0xD6, 0x74, 0x64, 0x8D, 0xBA, 0x24, 0x6D, 0xA0, 0x88, 0x27, 0x10, 0x26, 0xD5, 0x0D, 0xD2, 0x80, 0xFB, 0x9A, 0xEE, 0x13, 0x1C, 0xDF, 0x51, 0xE8, 0xED, 0xA1, 0x3D, 0xDB, 0xD1, 0x1D, 0xD5, 0xCC, 0x8A, 0x06, 0x42, 0x59, 0x38, 0x69, 0x20, 0x4A, 0x64, 0xD5, 0xFA, 0x2E, 0xF2, 0x03, 0x54, 0x19, 0x9F, 0x7C, 0x22, 0xAE, 0x6C, 0x7D, 0xE2, 0xB3, 0xB9, 0x9C, 0xAD, 0xA0, 0xFA, 0x37, 0x30, 0x8F, 0x29, 0xCC, 0x02, 0xAD, 0xA8, 0xA0, 0xF8, 0x0E, 0x50, 0xBD, 0x6F, 0xC9, 0x75, 0xC7, 0xD7, 0x1C, 0x7D, 0x61, 0x20, 0x03, 0x04, 0xB9, 0xB3, 0x19, 0x52, 0x0A, 0xE2, 0xAC, 0x81, 0xE6, 0x6B, 0xB5, 0xF4, 0x1D, 0x87, 0x6E, 0x47, 0x6E, 0xFD, 0xBC, 0x6B, 0xCB, 0x04, 0x84, 0x83, 0x1C, 0x50, 0x05, 0xDA, 0x48, 0x82, 0x51, 0x52, 0xAC, 0x0A, 0x23, 0xFE, 0xEB, 0x2A, 0xC9, 0x00, 0x15, 0x26, 0xA7, 0x9F, 0xB4, 0xCB, 0xCF, 0x5F, 0x72, 0x7D, 0xD9, 0x69, 0x5E, 0xDD, 0xF3, 0x4B, 0xE0, 0xA6, 0xD2, 0x39, 0x50, 0xE2, 0x9B, 0x98, 0xF3, 0xA7, 0xAE, 0x3A, 0xEF, 0x7B, 0x9D, 0x7C, 0xB7, 0x19, 0x71, 0x80, 0x0D, 0x90, 0xDD, 0x6D, 0x18, 0x88, 0x00, 0x6E, 0xC0, 0x88, 0x16, 0xD9, 0xD3, 0xB8, 0x13, 0x5D, 0x38, 0x29, 0xA0, 0x09, 0xCC, 0xC9, 0x00, 0x37, 0x12, 0xA4, 0x40, 0x08, 0x09, 0xD2, 0x8B, 0x01, 0x79, 0x88, 0xBE, 0xA9, 0x64, 0x66, 0xF6, 0xA9, 0xB8, 0xA4, 0xE3, 0x53, 0x76, 0x1D, 0xF3, 0x4F, 0xF7, 0xA5, 0x39, 0xDC, 0x94, 0x29, 0xD6, 0x06, 0x99, 0x7F, 0x28, 0x07, 0x5D, 0x9C, 0xAA, 0x6F, 0x91, 0x2A, 0x33, 0x73, 0xA1, 0x13, 0x6B, 0xAE, 0xD3, 0x04, 0x66, 0x40, 0x65, 0x0D, 0xB3, 0x58, 0xB3, 0x9B, 0xAE, 0xFB, 0x0C, 0x52, 0x2B, 0xC2, 0x58, 0x73, 0x5D, 0x11, 0x23, 0x4A, 0x12, 0x68, 0x00, 0xD3, 0x1F, 0xFF, 0x98, 0x1F, 0xA2, 0x24, 0x41, 0x1C, 0xE2, 0x24, 0xD6, 0x95, 0xAD, 0xAB, 0x06, 0xD9, 0x0C, 0xCD, 0xF7, 0x92, 0xB0, 0xAF, 0xF0, 0x4D, 0x49, 0xE3, 0x3B, 0x55, 0xFD, 0x5E, 0x4D, 0xF6, 0xBB, 0x44, 0xDF, 0xB3, 0x0C, 0x26, 0xC0, 0x15, 0xDA, 0xBC, 0xAF, 0x8E, 0xBC, 0x17, 0xCD, 0xBD, 0x4C, 0xCA, 0x80, 0x73, 0x23, 0xBB, 0x36, 0x0F, 0xED, 0xFA, 0x6D, 0xEF, 0xF5, 0x53, 0x03, 0x84, 0x81, 0x12, 0xD0, 0xFE, 0xAB, 0x2A, 0x77, 0x13, 0x67, 0xA4, 0x81, 0xDA, 0xBA, 0x13, 0x25, 0x0D, 0xDC, 0x19, 0x5D, 0xFC, 0x8C, 0x0E, 0xE3, 0xAD, 0x1C, 0xFD, 0x20, 0x16, 0x87, 0x28, 0xF4, 0x74, 0xE3, 0x95, 0xDF, 0xF1, 0xE6, 0x77, 0x74, 0xCF, 0xDA, 0xF4, 0xB4, 0x1B, 0x60, 0xE4, 0x6E, 0x67, 0x79, 0xD5, 0x20, 0x1D, 0xD8, 0x3D, 0xF8, 0x66, 0x95, 0xAA, 0x03, 0x6B, 0xA0, 0x01, 0x84, 0x9C, 0x1B, 0x5D, 0x18, 0x19, 0x60, 0x01, 0x46, 0xDE, 0x8B, 0x50, 0x07, 0x1B, 0xC4, 0x02, 0x32, 0x40, 0x0B, 0x58, 0x00, 0x37, 0xD2, 0x20, 0x84, 0x24, 0x48, 0x21, 0x05, 0x4A, 0x41, 0x2B, 0x33, 0xCB, 0x8F, 0x1B, 0x6A, 0x74, 0x47, 0x37, 0x71, 0xE5, 0x24, 0x66, 0xD1, 0xBA, 0x7B, 0x6F, 0x47, 0x69, 0x95, 0xBE, 0xDB, 0x38, 0x59, 0xB3, 0x71, 0x33, 0x33, 0x2D, 0x60, 0x0A, 0x74, 0xA7, 0x54, 0x20, 0x65, 0x15, 0x89, 0x82, 0x4A, 0x26, 0x4F, 0x64, 0x48, 0x13, 0x79, 0x37, 0x81, 0x63, 0xA0, 0x8B, 0xF8, 0x22, 0x16, 0x45, 0x06, 0x8C, 0x90, 0x78, 0x7F, 0xC5, 0x27, 0xD6, 0xC7, 0x1E, 0x70, 0x7A, 0x8D, 0xC1, 0x00, 0x9A, 0xCC, 0xAC, 0xBE, 0x6B, 0x81, 0x58, 0x3D, 0x99, 0x45, 0x5F, 0x3D, 0xF6, 0x19, 0xBF, 0x2A, 0x04, 0x77, 0xE7, 0x86, 0xCA, 0x92, 0x41, 0x2A, 0xA6, 0x5C, 0x3D, 0xF7, 0xBC, 0x56, 0xAB, 0x44, 0x3D, 0x40, 0x1E, 0x10, 0xAB, 0x1F, 0x96, 0x57, 0x95, 0xAC, 0x1B, 0x44, 0x15, 0xAF, 0x2A, 0x51, 0x20, 0xB1, 0x5A, 0xE6, 0x04, 0x39, 0x20, 0x9A, 0x18, 0x39, 0xC0, 0x87, 0x34, 0x99, 0xFD, 0xED, 0x90, 0x04, 0x29, 0x24, 0x48, 0xAE, 0xAB, 0x22, 0x09, 0xCA, 0x49, 0x33, 0xB4, 0xFE, 0x86, 0x36, 0xDE, 0x1F, 0x89, 0x6B, 0x24, 0x76, 0x1F, 0x87, 0x91, 0x9F, 0xF6, 0xA5, 0xEE, 0xC5, 0xA0, 0xFD, 0xB5, 0xC5, 0x4A, 0x3D, 0xEF, 0x9A, 0xE9, 0xB5, 0x33, 0xB0, 0x03, 0x24, 0xD7, 0x5A, 0xE0, 0x20, 0x6A, 0xAD, 0x9C, 0x05, 0x5C, 0xD7, 0xFD, 0xD9, 0x8A, 0x60, 0xD5, 0xAF, 0x29, 0xD0, 0x5E, 0x0C, 0xB0, 0x43, 0x84, 0xD8, 0x22, 0x49, 0x03, 0x17, 0x12, 0xC4, 0xD7, 0x55, 0x93, 0xDA, 0x59, 0x33, 0xB3, 0xB5, 0x3D, 0x00, 0x60, 0xF2, 0x3A, 0x56, 0xA8, 0x83, 0x1C, 0x86, 0xA5, 0xBC, 0x11, 0x7B, 0xAD, 0x01, 0x59, 0x6B, 0x0F, 0x38, 0x77, 0x58, 0x37, 0x05, 0x74, 0x0D, 0x94, 0x5A, 0x4B, 0xBB, 0xDB, 0x8A, 0xA0, 0xC8, 0x6A, 0x25, 0xCE, 0x90, 0x5A, 0xAC, 0xE6, 0xD4, 0x0C, 0xD4, 0xBC, 0x3F, 0x2F, 0x0A, 0x54, 0x82, 0x26, 0xE3, 0x9C, 0xE5, 0x94, 0x34, 0x10, 0x23, 0x05, 0x54, 0x49, 0x03, 0x13, 0xD2, 0xC0, 0x39, 0xCE, 0xF4, 0x7C, 0xAC, 0x2E, 0x75, 0xFD, 0x68, 0x5C, 0xE3, 0xFE, 0x24, 0x38, 0x75, 0xF9, 0xF9, 0x4E, 0xFB, 0xC5, 0xA3, 0xA3, 0x8C, 0x70, 0x9C, 0x22, 0xD8, 0xF7, 0x8F, 0xA8, 0x30, 0x33, 0x3F, 0x74, 0xA0, 0x5C, 0xBD, 0x7A, 0xDB, 0x2E, 0x62, 0x20, 0xE5, 0x9D, 0xA4, 0xD4, 0x9A, 0xA0, 0x0E, 0x68, 0x01, 0x95, 0xE4, 0x80, 0x5C, 0x85, 0x14, 0x45, 0x94, 0xEC, 0x7E, 0xF6, 0x90, 0x00, 0x75, 0x88, 0x93, 0x04, 0x7D, 0x48, 0x80, 0x39, 0xC4, 0xFF, 0xC7, 0x41, 0x89, 0x92, 0x01, 0x92, 0x0C, 0x4D, 0x9E, 0x98, 0x62, 0xAE, 0x33, 0x6C, 0x6B, 0xB9, 0x72, 0x5A, 0x0D, 0xE6, 0xF2, 0x1A, 0x4C, 0xE2, 0x2A, 0xFC, 0xF1, 0x86, 0xBB, 0xD1, 0x3D, 0xD0, 0x02, 0xDC, 0x5F, 0xA7, 0x0E, 0x30, 0xFF, 0xB9, 0x0A, 0xAC, 0x81, 0x96, 0xC4, 0x40, 0xD8, 0xAF, 0x29, 0xC5, 0x88, 0xAE, 0xAB, 0x04, 0x25, 0x6B, 0x7C, 0x2B, 0xA8, 0x03, 0x26, 0xDF, 0xA3, 0x48, 0x85, 0x0C, 0xB0, 0x02, 0xEE, 0xA4, 0x41, 0x28, 0xC8, 0x43, 0x8C, 0x0C, 0xA8, 0x06, 0x1D, 0xCC, 0x4C, 0x9F, 0xCC, 0xDC, 0x2E, 0xB7, 0xF8, 0x94, 0x5F, 0x3E, 0xCE, 0xE8, 0xF8, 0x95, 0xA6, 0x62, 0x2A, 0x08, 0xC3, 0x1C, 0x80, 0xEE, 0x56, 0xFF, 0xCE, 0xD9, 0x60, 0x37, 0xB3, 0xCB, 0xE7, 0xFB, 0x00, 0x2A, 0x40, 0xCE, 0x7B, 0x0D, 0xCB, 0x35, 0x6F, 0xD8, 0x01, 0xAA, 0x64, 0x5F, 0x19, 0x91, 0x85, 0x2E, 0xD6, 0x26, 0xC0, 0xD7, 0xAA, 0x5C, 0x87, 0x34, 0x68, 0x23, 0x0D, 0x46, 0xC9, 0xAC, 0xC1, 0x54, 0x40, 0x94, 0x24, 0x59, 0xCD, 0xA6, 0x39, 0x43, 0xB3, 0x27, 0xB4, 0xC4, 0x41, 0x2D, 0xAF, 0xD0, 0x6E, 0x78, 0x0E, 0xEE, 0xBC, 0x12, 0x9F, 0x56, 0xFC, 0x17, 0xFD, 0x5D, 0x95, 0x29, 0xCF, 0x40, 0x5B, 0x2D, 0x5A, 0xBF, 0xA7, 0x88, 0x7B, 0xFD, 0x6E, 0x5F, 0xEB, 0xE8, 0x01, 0x27, 0xD7, 0xDE, 0xAA, 0x41, 0x0E, 0x51, 0x10, 0xF9, 0xB3, 0x6D, 0x5F, 0xF1, 0xD4, 0xBB, 0x51, 0x70, 0x01, 0x79, 0x40, 0x05, 0x68, 0x21, 0x03, 0xE6, 0x6E, 0xDF, 0x8C, 0x04, 0x90, 0x43, 0x9C, 0x0C, 0xD0, 0x24, 0x05, 0xDC, 0x98, 0x99, 0x7F, 0x74, 0xAE, 0x61, 0xA7, 0x56, 0xA5, 0x9F, 0xC8, 0x2B, 0x34, 0x79, 0x9E, 0x1E, 0x58, 0xFB, 0xFB, 0xCB, 0xC9, 0x69, 0x7C, 0x43, 0xDE, 0x5C, 0x05, 0x76, 0x66, 0x05, 0xC6, 0xDF, 0x13, 0x5A, 0x35, 0x51, 0x10, 0x02, 0x34, 0x57, 0x58, 0xFB, 0xEB, 0x97, 0xF5, 0xBD, 0xCB, 0x3A, 0x9E, 0x35, 0x22, 0xAB, 0xE3, 0x3A, 0x64, 0x98, 0xD9, 0xEA, 0x0C, 0xDD, 0x40, 0x1C, 0x12, 0xA4, 0xD7, 0x0F, 0x28, 0x24, 0xC8, 0x80, 0x3E, 0x24, 0x16, 0xC3, 0x74, 0x95, 0x99, 0xB1, 0x9F, 0xDD, 0xDB, 0x27, 0xAE, 0x02, 0xAA, 0x8A, 0xAD, 0x86, 0xE5, 0x17, 0xA9, 0x40, 0x4D, 0x61, 0xEF, 0xA0, 0xB3, 0x57, 0x81, 0xB9, 0x8B, 0xAC, 0xE2, 0xDD, 0x0C, 0xEA, 0xF9, 0x1F, 0xC5, 0xB9, 0xF7, 0xD6, 0x24, 0x04, 0x54, 0xAD, 0x0A, 0xCA, 0x35, 0x2B, 0x0B, 0x31, 0x52, 0xBF, 0xF6, 0x41, 0x05, 0xF4, 0x90, 0xF8, 0x31, 0xC9, 0xFA, 0x21, 0xB9, 0x72, 0x55, 0x52, 0x20, 0x8D, 0x14, 0x28, 0x07, 0x6D, 0x0C, 0x2D, 0x3F, 0x5A, 0x97, 0xE5, 0xEC, 0xD0, 0xF8, 0x44, 0xB2, 0x71, 0x50, 0x26, 0xC2, 0xD1, 0x3D, 0x98, 0xBD, 0x25, 0x5F, 0x61, 0xB9, 0xD2, 0x39, 0x2B, 0x34, 0x15, 0x32, 0xAB, 0x47, 0x0B, 0x50, 0xB1, 0x4A, 0xCF, 0x41, 0xAD, 0x87, 0x2F, 0x75, 0x7F, 0xAD, 0x45, 0x86, 0xF0, 0x26, 0x86, 0xB4, 0x83, 0x1A, 0x52, 0xA4, 0xDF, 0xF4, 0x21, 0x4E, 0x0A, 0xCC, 0x21, 0xB5, 0xAA, 0x73, 0x80, 0x08, 0x71, 0x92, 0xA4, 0xD7, 0xC6, 0xCB, 0x19, 0x5A, 0x3D, 0x69, 0x99, 0x5F, 0xA7, 0xFF, 0x96, 0x4E, 0xBD, 0xE4, 0x14, 0xC6, 0x27, 0xAA, 0x33, 0xC3, 0x13, 0xA1, 0x85, 0x7F, 0x97, 0xCE, 0x3B, 0xAC, 0xC8, 0x75, 0x1E, 0xDD, 0xCF, 0xC6, 0x72, 0x2F, 0x9D, 0xEB, 0x20, 0xF7, 0x80, 0xF4, 0x1F, 0x8D, 0x42, 0xF7, 0x6A, 0x8B, 0xFB, 0x8D, 0x1F, 0xA2, 0x64, 0x4D, 0x8F, 0x75, 0x78, 0xEF, 0x02, 0xEC, 0x00, 0x1F, 0x90, 0x4A, 0x06, 0x54, 0x82, 0x76, 0x30, 0x42, 0x92, 0x4F, 0x85, 0x84, 0x04, 0x10, 0x21, 0x05, 0xD4, 0x81, 0x05, 0x33, 0xEB, 0x27, 0x25, 0xB1, 0x4B, 0x43, 0x9F, 0x04, 0x4B, 0xAE, 0x09, 0xE5, 0xB2, 0xCD, 0xB7, 0x11, 0x64, 0x3E, 0x75, 0xA9, 0x8F, 0xBD, 0xF7, 0x02, 0x76, 0x67, 0x16, 0x7F, 0x8B, 0x7A, 0xF2, 0xF8, 0xA4, 0x39, 0xB0, 0xE7, 0xB2, 0x01, 0xA1, 0x40, 0x13, 0xBF, 0x37, 0x0D, 0x4A, 0x80, 0x3B, 0xC0, 0xA2, 0x55, 0x57, 0x0E, 0xC0, 0xF7, 0x90, 0xAC, 0xAE, 0xB8, 0xF4, 0xBE, 0x23, 0x7F, 0x0F, 0x37, 0xF5, 0xF7, 0xC4, 0x56, 0x6B, 0x69, 0x08, 0xE2, 0x4D, 0x8A, 0x34, 0x88, 0xDC, 0x8B, 0xEB, 0xAF, 0xCE, 0x70, 0xEF, 0xB4, 0x1C, 0x3C, 0xED, 0xC6, 0x3C, 0x99, 0xD5, 0xC1, 0x83, 0xF5, 0x27, 0xB3, 0xBE, 0xC6, 0x1A, 0x4D, 0x51, 0x1F, 0x12, 0x1F, 0xBB, 0xC2, 0x27, 0xDF, 0x87, 0x69, 0x6B, 0x46, 0x53, 0xE6, 0xE3, 0xAC, 0xCA, 0xB8, 0xE4, 0x90, 0xC6, 0x2F, 0xCE, 0x01, 0x7E, 0x7F, 0xB9, 0x0E, 0xC2, 0x80, 0xDE, 0x85, 0xD4, 0x20, 0x05, 0x68, 0xAF, 0xA2, 0x3E, 0xC0, 0x13, 0x28, 0x11, 0x27, 0x46, 0xF6, 0x23, 0x86, 0xDE, 0xBF, 0xB8, 0x08, 0x60, 0xC4, 0x05, 0xD8, 0x90, 0x24, 0xB2, 0x36, 0x65, 0x01, 0x82, 0xC5, 0x69, 0xBF, 0x1F, 0x17, 0xA0, 0x55, 0x7B, 0xBE, 0x37, 0xE5, 0x26, 0x45, 0xD1, 0x18, 0x8E, 0xBF, 0x43, 0xAB, 0xD7, 0xD2, 0xA9, 0x97, 0x33, 0x33, 0x7F, 0xC6, 0x06, 0x10, 0x8E, 0xFD, 0x3A, 0xE0, 0xB0, 0x3C, 0x5C, 0xDE, 0xFB, 0x1A, 0x37, 0x70, 0xE2, 0x3D, 0x60, 0xDC, 0xD6, 0x3E, 0xEA, 0x26, 0x89, 0xBE, 0x11, 0x59, 0x0D, 0x9B, 0x91, 0x58, 0x24, 0xD9, 0x7D, 0x74, 0x80, 0x74, 0xA2, 0x6B, 0x3B, 0x3C, 0x24, 0x41, 0x28, 0xC8, 0x61, 0x66, 0x82, 0xB0, 0x38, 0xA1, 0xA9, 0xD6, 0x27, 0xFA, 0x8A, 0x8E, 0x4F, 0xCB, 0xE5, 0xEC, 0xCD, 0xCA, 0x0B, 0xF3, 0x8A, 0x1B, 0xAA, 0xA2, 0xE4, 0x3B, 0x91, 0x3D, 0xC5, 0xC9, 0xD9, 0xFF, 0x99, 0xBE, 0xCD, 0xDE, 0x5B, 0xB4, 0x4E, 0x32, 0xA0, 0x14, 0x84, 0x01, 0x73, 0xA0, 0xFA, 0xBE, 0xCA, 0x02, 0xD3, 0xA0, 0x07, 0xF8, 0x5A, 0x04, 0xEE, 0x5B, 0x99, 0x06, 0x59, 0x20, 0x82, 0x9C, 0x55, 0x87, 0x4A, 0xE4, 0xD7, 0x55, 0x81, 0xF8, 0xB5, 0xDB, 0xF8, 0xBD, 0x43, 0x0B, 0x50, 0xCA, 0xCC, 0xF4, 0x3F, 0x03, 0x2C, 0xE2, 0x12, 0x53, 0xBE, 0xBD, 0x94, 0xF8, 0xF7, 0x51, 0x9C, 0xAD, 0x1A, 0x58, 0xCA, 0x1B, 0xFB, 0x27, 0xBF, 0x33, 0x83, 0xD8, 0x38, 0xBF, 0x7A, 0xA5, 0x52, 0x30, 0x4E, 0x0C, 0x54, 0x81, 0x20, 0x6E, 0xC0, 0x82, 0x34, 0x08, 0x52, 0x37, 0x03, 0x82, 0xE8, 0xBC, 0x3B, 0xB5, 0x18, 0x60, 0x44, 0x9B, 0x28, 0x90, 0x22, 0xB9, 0xD8, 0xCC, 0xDE, 0x50, 0x2C, 0x9C, 0x18, 0xD1, 0x3D, 0x84, 0x99, 0x99, 0xFD, 0x27, 0x33, 0x95, 0x6F, 0x30, 0xDF, 0x09, 0x2D, 0x02, 0x7B, 0xCE, 0xCA, 0xC2, 0x01, 0x67, 0xC9, 0xB7, 0xD0, 0xDC, 0xE2, 0xB5, 0xE7, 0xA4, 0xCC, 0xEC, 0x09, 0xC4, 0xD9, 0x5B, 0xE5, 0x75, 0x1A, 0x84, 0x92, 0x01, 0x9E, 0xC0, 0x0C, 0xA8, 0x92, 0x00, 0x7E, 0x88, 0x01, 0x4C, 0x56, 0xC1, 0x79, 0xDB, 0x39, 0xC9, 0xD9, 0x13, 0x79, 0x9E, 0x5F, 0xC3, 0xED, 0x00, 0x6B, 0x72, 0x80, 0xD6, 0x0F, 0xCC, 0x80, 0xC7, 0x8F, 0x21, 0xE5, 0x49, 0x64, 0x15, 0xF3, 0x01, 0x29, 0xCC, 0xCC, 0xBF, 0xB3, 0xFF, 0xD1, 0x7E, 0x32, 0xD3, 0xBA, 0x62, 0x12, 0x8B, 0x00, 0x5E, 0x8F, 0x89, 0x98, 0xC4, 0xDC, 0xED, 0x5F, 0xA6, 0xF0, 0xFE, 0x87, 0xD6, 0xD9, 0xEF, 0x29, 0x24, 0x6F, 0xA5, 0x99, 0x59, 0x32, 0x33, 0x01, 0x66, 0x44, 0x80, 0x18, 0x38, 0x5C, 0x1F, 0xE6, 0xBE, 0x22, 0x16, 0x20, 0x0D, 0x04, 0x39, 0xC3, 0xE8, 0x82, 0xD1, 0xB1, 0x6E, 0x47, 0x81, 0x3B, 0x90, 0x02, 0x7B, 0x51, 0xED, 0x24, 0x4E, 0xF2, 0xCD, 0xEC, 0xD3, 0xEF, 0x8D, 0x81, 0x53, 0x24, 0x48, 0x03, 0x6D, 0x66, 0x16, 0xFF, 0x19, 0x67, 0x8E, 0x91, 0xFF, 0xA9, 0x6F, 0x02, 0x82, 0x8D, 0x47, 0x2B, 0x9A, 0x19, 0xD5, 0x4F, 0x5C, 0x47, 0xF8, 0x54, 0x60, 0x8D, 0x33, 0x3E, 0xB9, 0xC6, 0x40, 0x73, 0xCE, 0xF7, 0x86, 0xFB, 0xEC, 0x78, 0x0F, 0x26, 0x3B, 0x40, 0x1A, 0x9C, 0x9B, 0x02, 0x18, 0x1B, 0x75, 0x1D, 0x92, 0x24, 0x1C, 0xBF, 0x57, 0x5F, 0x82, 0xD3, 0x8D, 0x3F, 0xED, 0xD7, 0xC9, 0xF7, 0xDA, 0xDA, 0x7B, 0xBC, 0xED, 0x75, 0xB0, 0x88, 0xAF, 0x71, 0xA3, 0x6B, 0x42, 0xCB, 0x5F, 0x8B, 0xC0, 0x8D, 0x81, 0x10, 0x90, 0x77, 0x68, 0xF9, 0x5A, 0x04, 0xD2, 0xF5, 0x3B, 0xD0, 0xD4, 0xFB, 0x53, 0x71, 0x59, 0x08, 0xF6, 0x26, 0x86, 0x1D, 0x41, 0x65, 0x7D, 0xFC, 0xD2, 0xF2, 0x55, 0x9C, 0xB3, 0xF6, 0xE9, 0xC1, 0xD1, 0x10, 0x72, 0x8F, 0x0D, 0x90, 0x0D, 0x82, 0x98, 0x82, 0xC3, 0x74, 0x3B, 0x40, 0x35, 0x68, 0x27, 0x09, 0xA2, 0xC0, 0x91, 0xF7, 0x4A, 0x5B, 0x06, 0x4E, 0xAD, 0x97, 0x1C, 0xF4, 0x77, 0x59, 0x01, 0x5F, 0x04, 0x70, 0x59, 0xCB, 0xE1, 0x01, 0x51, 0xC4, 0x81, 0x37, 0x59, 0x85, 0x5B, 0x87, 0x99, 0xD5, 0x93, 0x59, 0x5E, 0xDD, 0x78, 0x36, 0x7C, 0x75, 0xEA, 0xA7, 0xF3, 0x0A, 0x19, 0x9E, 0xD6, 0x3A, 0xB6, 0x67, 0x98, 0xD7, 0xC6, 0xE4, 0xF0, 0xD5, 0x8E, 0x5D, 0x9C, 0xAF, 0x27, 0x5B, 0x7E, 0x9D, 0x01, 0xC3, 0x78, 0xC4, 0xC9, 0xE1, 0x2F, 0x0A, 0x28, 0x03, 0xD1, 0xC0, 0x6F, 0x04, 0x18, 0x39, 0xFD, 0x5E, 0x4D, 0x25, 0x9F, 0x29, 0x93, 0xAB, 0x0D, 0x48, 0x01, 0xBE, 0x72, 0xD1, 0xFA, 0xFF, 0x8F, 0x93, 0xF6, 0x73, 0xD1, 0x22, 0x49, 0x94, 0xEC, 0x56, 0xCE, 0x81, 0x07, 0x33, 0xEB, 0x27, 0xB3, 0xCA, 0x4B, 0x26, 0x3F, 0x5E, 0x18, 0x60, 0xA5, 0xD7, 0x8C, 0xA2, 0x4F, 0xCE, 0xC6, 0xC6, 0x68, 0x58, 0xE7, 0x68, 0x7C, 0x53, 0xEF, 0xCC, 0xE2, 0xF5, 0x58, 0x5D, 0x9F, 0x37, 0xD0, 0xBA, 0x18, 0x41, 0x02, 0x1B, 0x70, 0x4F, 0x14, 0xE5, 0xC0, 0xF2, 0x5D, 0x63, 0x73, 0x40, 0x0F, 0x71, 0x10, 0x09, 0x64, 0x1D, 0x7B, 0xE5, 0xEA, 0x9B, 0x2C, 0xC8, 0x6E, 0xF3, 0x75, 0x3F, 0x42, 0x59, 0x08, 0x69, 0x50, 0x6B, 0x43, 0x57, 0x45, 0xF6, 0xE9, 0xA7, 0xAE, 0x3F, 0x99, 0xCC, 0x6C, 0x9E, 0xCC, 0x3C, 0xAF, 0xF0, 0x7A, 0xE6, 0xB5, 0x8E, 0x6B, 0x2C, 0xB1, 0xAD, 0xF6, 0x46, 0x3F, 0x6E, 0xC2, 0x67, 0x81, 0x8D, 0xF1, 0xF5, 0xDE, 0xA6, 0x73, 0xF7, 0xC4, 0x6D, 0x21, 0x3B, 0x2C, 0x8E, 0xA5, 0x04, 0xED, 0xA0, 0x04, 0x58, 0xBE, 0x7B, 0xDB, 0x3E, 0x20, 0x12, 0x58, 0x00, 0x59, 0x1B, 0xEB, 0x48, 0xA0, 0xF6, 0xDE, 0x28, 0x45, 0xAF, 0x11, 0x72, 0xDE, 0x68, 0x91, 0x24, 0x41, 0x6C, 0x0D, 0x9B, 0xB3, 0x5B, 0x5C, 0x72, 0xF6, 0x04, 0xB8, 0xAE, 0x02, 0x04, 0x6B, 0xD3, 0xCF, 0x93, 0x59, 0xEA, 0x95, 0x13, 0x9F, 0xFC, 0x66, 0x3C, 0x9F, 0xD6, 0xEB, 0xB4, 0xA3, 0xBE, 0xFD, 0x4B, 0x9D, 0x34, 0x6C, 0xC0, 0xEB, 0x9B, 0x99, 0x3D, 0x0B, 0x67, 0xAF, 0x8D, 0x80, 0x08, 0x98, 0xB9, 0x97, 0x19, 0xA2, 0xEF, 0x65, 0xAD, 0x12, 0x84, 0x01, 0x4B, 0xE2, 0xC0, 0xE3, 0x9D, 0x92, 0x2B, 0x90, 0xB5, 0xAB, 0xCC, 0x04, 0xEE, 0x2B, 0xA5, 0x06, 0x66, 0xC4, 0x89, 0x10, 0x5D, 0x18, 0x99, 0xD5, 0xDB, 0xDA, 0x1A, 0x9F, 0x45, 0x9C, 0x18, 0x69, 0x90, 0xCA, 0xCC, 0xE4, 0xCE, 0x8C, 0xEF, 0xBE, 0xFF, 0x55, 0xAA, 0x5F, 0x62, 0x85, 0x3F, 0xAE, 0x8E, 0x88, 0x71, 0xD5, 0x27, 0xD6, 0x46, 0xE0, 0xF9, 0xA9, 0x19, 0xD6, 0x99, 0x1F, 0xC7, 0x4F, 0x11, 0xC0, 0x74, 0x1D, 0xA8, 0x0D, 0xA8, 0x7C, 0x33, 0xFC, 0x23, 0xC7, 0xD6, 0x03, 0x4D, 0x5D, 0xD5, 0xD8, 0x6B, 0x2C, 0x39, 0x19, 0xE0, 0x42, 0xF2, 0x17, 0xBB, 0x7C, 0x1D, 0x64, 0x81, 0x72, 0x22, 0x20, 0x8B, 0x9C, 0x1F, 0x7B, 0x85, 0xBE, 0x33, 0xD3, 0x27, 0x25, 0x37, 0x3C, 0x13, 0x7E, 0x36, 0x9C, 0x75, 0xD5, 0x24, 0x1A, 0xC7, 0x2A, 0x34, 0xE2, 0xED, 0x1F, 0xBF, 0xE2, 0xF0, 0x05, 0xAB, 0x67, 0xC3, 0xD9, 0xFB, 0xE5, 0xDB, 0xB8, 0x17, 0x40, 0xCE, 0xFE, 0x53, 0x6C, 0x2F, 0x06, 0x9C, 0xB5, 0x8C, 0xEA, 0xBD, 0x4E, 0x38, 0xC8, 0x5C, 0x85, 0x5B, 0xEF, 0x13, 0x1C, 0x95, 0xF7, 0xC9, 0x9F, 0xCA, 0xDA, 0x94, 0xC6, 0x1A, 0x5A, 0x06, 0x74, 0x76, 0x71, 0x2E, 0xD6, 0x44, 0xEF, 0x42, 0x86, 0x14, 0x59, 0x63, 0xD1, 0xD6, 0x62, 0x9C, 0x87, 0xA1, 0xD9, 0xB7, 0x2A, 0xA5, 0xE4, 0x1B, 0x5A, 0x4A, 0x3F, 0xA1, 0xF5, 0xC1, 0x1B, 0xA5, 0x76, 0x29, 0x67, 0x7F, 0x9D, 0xA9, 0x6F, 0x68, 0x19, 0xF2, 0xEA, 0x6A, 0xDD, 0x76, 0x87, 0x56, 0x87, 0x8B, 0xA4, 0xAC, 0xD6, 0xCC, 0xC0, 0xE9, 0x15, 0x5A, 0x31, 0x34, 0x03, 0xE9, 0x6B, 0xBD, 0xE8, 0xF7, 0x09, 0x57, 0x2A, 0xB0, 0x06, 0xA2, 0xEB, 0x0D, 0x5D, 0x25, 0x06, 0xBA, 0xD6, 0xA1, 0xA2, 0xFC, 0xE8, 0x4B, 0x45, 0x48, 0xEF, 0x87, 0x51, 0x0B, 0x23, 0x4A, 0x0E, 0x29, 0x10, 0xCA, 0xD0, 0xFC, 0x93, 0xE7, 0xEA, 0x8A, 0x8F, 0x7E, 0xEF, 0x7D, 0x5E, 0x23, 0x2D, 0x8F, 0xE1, 0x25, 0xED, 0x99, 0x7F, 0xF8, 0x69, 0xFB, 0xC4, 0x55, 0xC1, 0xED, 0x93, 0xEC, 0xC7, 0x4F, 0x33, 0xAF, 0xA3, 0xBF, 0x60, 0x14, 0x75, 0x59, 0x80, 0x74, 0x10, 0x44, 0x19, 0x68, 0x0F, 0x48, 0x01, 0x36, 0x40, 0x8A, 0x7F, 0x3D, 0x40, 0x26, 0xD0, 0x7B, 0xF4, 0x16, 0x78, 0x16, 0x1A, 0x05, 0x69, 0x20, 0x84, 0x1C, 0xE0, 0x43, 0x92, 0x14, 0x99, 0x1F, 0xCF, 0xE5, 0xCA, 0x40, 0x0B, 0x39, 0xA0, 0x9A, 0x38, 0x51, 0x92, 0x60, 0x8A, 0xA1, 0xC5, 0x27, 0xFD, 0x32, 0x95, 0x8F, 0xE3, 0xB5, 0xF8, 0x8F, 0xD9, 0x55, 0xE1, 0x38, 0x78, 0x3C, 0x81, 0x23, 0x06, 0x64, 0x27, 0x83, 0xEC, 0x32, 0xE6, 0xFD, 0xE6, 0x46, 0xD4, 0xDA, 0x3F, 0x15, 0x6F, 0xF3, 0xD4, 0xBB, 0xDD, 0xD7, 0x00, 0x87, 0xFB, 0x83, 0x52, 0xE0, 0x02, 0xA4, 0x49, 0x00, 0x4B, 0x10, 0x0E, 0xEC, 0xD9, 0x8C, 0x81, 0x70, 0x70, 0x78, 0xEF, 0xE9, 0xC0, 0x0F, 0xB0, 0x01, 0xB1, 0xAA, 0xBA, 0x02, 0xF4, 0x21, 0x4A, 0x02, 0x4C, 0x70, 0x44, 0x2B, 0x50, 0x23, 0x07, 0x48, 0x81, 0x33, 0x24, 0x81, 0x28, 0x30, 0x63, 0x66, 0xF9, 0xF1, 0xB9, 0xC2, 0xCF, 0x47, 0xEA, 0x8A, 0xA3, 0xEF, 0x76, 0xC3, 0xBF, 0xD5, 0x19, 0x6D, 0x89, 0xCF, 0xD6, 0x46, 0x97, 0x8F, 0xCC, 0x6C, 0xF6, 0x79, 0x90, 0x30, 0xB3, 0xE4, 0x07, 0x71, 0xA0, 0x80, 0xBF, 0xA9, 0xAC, 0x07, 0xE4, 0x01, 0x66, 0xAB, 0xD7, 0x55, 0x50, 0x05, 0xD2, 0x80, 0x37, 0xD0, 0x04, 0x87, 0x29, 0x55, 0x81, 0x10, 0x60, 0xB1, 0x8A, 0x4C, 0xC8, 0x59, 0x57, 0x4A, 0x9C, 0x14, 0x70, 0x05, 0x71, 0x53, 0x64, 0x48, 0x93, 0x22, 0x0E, 0x32, 0x40, 0x15, 0x33, 0xAB, 0x4F, 0xCE, 0x95, 0xFA, 0xFA, 0x1F, 0x52, 0x16, 0x9E, 0x38, 0x44, 0x13, 0x11, 0x0C, 0xF2, 0x56, 0xB4, 0xA5, 0x56, 0xA8, 0x18, 0xB1, 0xF7, 0x7F, 0xC2, 0x98, 0xD5, 0x6F, 0xB4, 0x73, 0xA4, 0x70, 0x7B, 0x39, 0xC2, 0x1A, 0x55, 0xE2, 0x40, 0x8C, 0xBF, 0x47, 0xAA, 0x40, 0x2A, 0xF0, 0x00, 0x7A, 0x67, 0x9E, 0x20, 0xE4, 0xBD, 0x60, 0x68, 0xBC, 0x6F, 0x50, 0x72, 0x6D, 0xCD, 0x05, 0x94, 0x82, 0x4C, 0x12, 0x8B, 0xFD, 0x34, 0x29, 0xC0, 0xE8, 0x9B, 0x1E, 0xE2, 0xE4, 0x10, 0x26, 0x79, 0x8C, 0xA1, 0xF5, 0x27, 0xFB, 0xD2, 0xBF, 0xC3, 0xDA, 0xE8, 0x4B, 0xDB, 0x3E, 0xA5, 0x57, 0x29, 0x36, 0xEA, 0xAE, 0x85, 0x1D, 0x4B, 0x0D, 0x7A, 0xAB, 0x98, 0x57, 0xBF, 0x51, 0xBE, 0xFA, 0x0D, 0x97, 0xF7, 0xB7, 0xD3, 0x05, 0x2A, 0x81, 0xDB, 0xBB, 0x55, 0xCB, 0x06, 0x56, 0x40, 0x86, 0x9C, 0xFD, 0x6A, 0xDF, 0x6A, 0x34, 0x6A, 0xB1, 0xF6, 0x8E, 0xE5, 0xEF, 0x7F, 0xEC, 0x9E, 0xEC, 0xD4, 0x80, 0x1F, 0x52, 0x6B, 0x42, 0x73, 0x50, 0x03, 0xE6, 0x80, 0x1E, 0xF0, 0x7F, 0x84, 0xDD, 0x09, 0xB2, 0x1D, 0x39, 0x88, 0x05, 0xD0, 0xAD, 0xE4, 0x0A, 0x32, 0xC4, 0x0C, 0xFB, 0xDF, 0x58, 0x97, 0xEF, 0xCD, 0x70, 0x89, 0xA8, 0xD7, 0xDD, 0x31, 0x9D, 0x1A, 0x3C, 0x7C, 0xF3, 0x5F, 0xA6, 0x24, 0x04, 0xB8, 0x9D, 0xEC, 0x77, 0x9E, 0x82, 0x19, 0xC6, 0x6C, 0x9E, 0xF4, 0x37, 0xA2, 0x76, 0x8E, 0xE3, 0xE9, 0x7A, 0xA5, 0x0C, 0xBB, 0xB2, 0x69, 0x7C, 0x79, 0x5D, 0xF8, 0xBA, 0xF4, 0xF0, 0xE1, 0xDC, 0x49, 0x34, 0xC6, 0x4C, 0x77, 0xB2, 0xF6, 0x80, 0x4C, 0xA0, 0xBD, 0x53, 0xDA, 0x6B, 0xC7, 0xA6, 0x20, 0xD6, 0x5E, 0x4B, 0x0D, 0x9C, 0x21, 0xBE, 0x50, 0xB2, 0x72, 0x85, 0x51, 0xA0, 0x7B, 0x55, 0xE3, 0x11, 0x15, 0x12, 0xC0, 0x04, 0xF8, 0x47, 0x91, 0x24, 0x45, 0x82, 0x18, 0x19, 0x90, 0xFC, 0x9C, 0xC5, 0xF9, 0x7D, 0x29, 0xD0, 0xF6, 0xA6, 0x1B, 0xF6, 0xD4, 0xD5, 0x48, 0xBC, 0x4F, 0xE1, 0x8E, 0x4C, 0xE6, 0xFF, 0xD8, 0x6E, 0xE8, 0xEA, 0xE8, 0x99, 0x26, 0x0A, 0x22, 0xC0, 0xE9, 0x95, 0x83, 0x95, 0x95, 0xD1, 0x39, 0xC0, 0x89, 0xFC, 0xAE, 0xB7, 0xD5, 0x4F, 0xD9, 0x4E, 0xAD, 0xEA, 0x4B, 0xD1, 0x85, 0x11, 0x5F, 0xF4, 0xAF, 0x93, 0x84, 0xEC, 0xC3, 0xFE, 0xA2, 0x80, 0x1F, 0x46, 0x4E, 0xD0, 0x11, 0xF8, 0x6F, 0xD9, 0x7B, 0xF6, 0x7B, 0x32, 0x9E, 0x9A, 0x37, 0x45, 0x50, 0x2B, 0xE2, 0xCE, 0xE3, 0x4B, 0xA2, 0x90, 0x60, 0xFE, 0x44, 0x2E, 0xBF, 0xBD, 0x46, 0x43, 0xF9, 0xFB, 0xED, 0x3B, 0xEB, 0xE1, 0x58, 0xAF, 0xE6, 0xA3, 0xDF, 0x6A, 0xB1, 0x8E, 0x48, 0x03, 0x8E, 0xDF, 0x8F, 0xE6, 0x18, 0xA8, 0x03, 0x82, 0xB8, 0x92, 0x03, 0x6C, 0x6E, 0x42, 0x41, 0x91, 0xDE, 0xA5, 0x0B, 0x49, 0x7A, 0xDD, 0xC9, 0x17, 0x10, 0xA2, 0x41, 0x8C, 0x08, 0x10, 0x27, 0x0A, 0xF4, 0x00, 0x4B, 0xC6, 0x4C, 0x1F, 0xEB, 0x57, 0xD5, 0xB0, 0x5D, 0x93, 0x7F, 0x97, 0xCF, 0x7C, 0x55, 0x9A, 0xAF, 0x21, 0x66, 0xD2, 0x1C, 0x57, 0x50, 0xA5, 0x75, 0x75, 0xAA, 0x44, 0xAC, 0x27, 0xD4, 0xBF, 0x55, 0x7B, 0x40, 0x9F, 0x75, 0x4C, 0xEF, 0xBB, 0x37, 0x2F, 0x89, 0xF6, 0xFD, 0xAA, 0x6B, 0x5D, 0xA7, 0xAF, 0xB3, 0x6E, 0x99, 0x8B, 0xF8, 0x7E, 0xE0, 0x56, 0x19, 0x72, 0xDE, 0x55, 0x54, 0x6E, 0xAB, 0xC6, 0xD8, 0x48, 0xAF, 0xED, 0x48, 0x81, 0xF1, 0x45, 0x2E, 0xBE, 0x0D, 0x88, 0x01, 0x35, 0xC6, 0xCC, 0x9E, 0x12, 0xB4, 0xAA, 0xA6, 0xBC, 0xD6, 0x71, 0xC5, 0x2C, 0xA7, 0xF1, 0x3D, 0xE9, 0xF8, 0xC3, 0x31, 0xAE, 0x1F, 0x38, 0x68, 0x99, 0x31, 0x66, 0xEE, 0x74, 0xF2, 0x7B, 0x42, 0xBF, 0xD7, 0xA8, 0xAE, 0xCC, 0x58, 0xDE, 0x3B, 0xAC, 0x32, 0x60, 0x05, 0xCE, 0x2E, 0xF3, 0xD3, 0x3B, 0x06, 0x4A, 0x4E, 0xDD, 0x57, 0x9E, 0xBD, 0x8F, 0x89, 0x09, 0x6A, 0xBD, 0x1C, 0x47, 0x88, 0x93, 0x02, 0xBF, 0xAB, 0xA8, 0x76, 0xDD, 0xC4, 0x59, 0xCB, 0x52, 0xFD, 0x78, 0x2B, 0x9A, 0x32, 0x68, 0xFE, 0xA4, 0xBD, 0xD1, 0xF3, 0xE4, 0xBC, 0x75, 0x1D, 0x3D, 0xF3, 0x8D, 0x19, 0xB6, 0xCE, 0x06, 0x4E, 0x28, 0x63, 0xD8, 0xDD, 0x71, 0xF9, 0x3C, 0xBB, 0x10, 0xE1, 0x5C, 0x55, 0x14, 0xF1, 0xDA, 0x4A, 0xF5, 0xDB, 0x77, 0x48, 0x20, 0x96, 0x77, 0x92, 0xD6, 0x74, 0xDD, 0x16, 0x0F, 0x30, 0x05, 0xE7, 0xDC, 0x4F, 0x73, 0x28, 0xF0, 0xF3, 0xE3, 0x63, 0xE7, 0x01, 0xBA, 0xEE, 0x0F, 0x9A, 0x0D, 0x88, 0x43, 0x9C, 0xCC, 0x8F, 0xEE, 0xCA, 0xF9, 0x10, 0xD0, 0x45, 0x14, 0xD4, 0x80, 0x8E, 0x6F, 0xB3, 0xC8, 0x98, 0x05, 0x66, 0x17, 0x44, 0x73, 0x7A, 0x00, 0x8B, 0xF7, 0xB8, 0xB7, 0xED, 0xE2, 0xDB, 0xA2, 0x0B, 0x47, 0x5A, 0xBE, 0xDE, 0xC4, 0x0C, 0xF7, 0x75, 0x8C, 0x59, 0x1B, 0x63, 0x66, 0xAB, 0xB1, 0x34, 0x3F, 0x1A, 0x44, 0xFF, 0x2A, 0xE4, 0x36, 0x50, 0x43, 0x94, 0x38, 0xB1, 0x95, 0x8F, 0x2D, 0x22, 0xC0, 0x9A, 0xE4, 0x8D, 0x1F, 0x92, 0xBF, 0x6A, 0xB6, 0x6D, 0xE1, 0x64, 0x7E, 0x54, 0x95, 0x66, 0x93, 0x24, 0x46, 0x82, 0x0C, 0x68, 0x63, 0xCC, 0xF2, 0xB1, 0x7A, 0x4B, 0xFD, 0x71, 0x7F, 0xC5, 0xF5, 0xFE, 0x9C, 0x59, 0xE2, 0x40, 0x34, 0x8D, 0xB7, 0x93, 0x16, 0xCE, 0x37, 0x15, 0xAC, 0x7A, 0xDF, 0x29, 0xDB, 0xEF, 0x10, 0xFC, 0x5D, 0xC3, 0x7D, 0xD7, 0x22, 0x01, 0xEA, 0x80, 0xEF, 0xC3, 0xD7, 0x05, 0x6C, 0xF8, 0xE1, 0x23, 0x99, 0xC0, 0xE6, 0xBE, 0x84, 0x9F, 0xB3, 0x4E, 0x07, 0x01, 0x4C, 0x80, 0x04, 0x51, 0x60, 0x7E, 0x27, 0x56, 0x94, 0x78, 0x80, 0x3C, 0xA4, 0x40, 0x05, 0x68, 0x07, 0xF3, 0xE5, 0x5E, 0x8A, 0xE4, 0xAF, 0x7F, 0x0B, 0x52, 0xC0, 0x0E, 0x63, 0x56, 0x8F, 0xCD, 0x6B, 0x36, 0x38, 0x7E, 0x5E, 0x75, 0x08, 0x38, 0x77, 0xE2, 0xD6, 0x29, 0x70, 0x8F, 0xA2, 0x35, 0x4F, 0xBC, 0x9A, 0xCD, 0x17, 0xD9, 0x4A, 0x0B, 0xAD, 0x12, 0xA5, 0x7C, 0xED, 0x0B, 0x56, 0x82, 0x24, 0xC2, 0x98, 0xC5, 0xF9, 0xBE, 0xEA, 0x75, 0x10, 0x0F, 0xE0, 0x09, 0x24, 0xEF, 0x23, 0xB4, 0x0F, 0xB0, 0x20, 0x07, 0xA8, 0x03, 0xBB, 0x1E, 0x20, 0x7F, 0xEB, 0x30, 0x58, 0x09, 0xBE, 0xCB, 0x43, 0x3D, 0xC0, 0x02, 0xB8, 0x83, 0x68, 0x50, 0x01, 0x3A, 0x49, 0x91, 0x26, 0x4E, 0xE4, 0x3E, 0xD9, 0x88, 0x33, 0x66, 0x8D, 0xCE, 0x94, 0xCA, 0xFF, 0x6E, 0xD3, 0xA4, 0xF8, 0x46, 0xD6, 0xC2, 0x5B, 0x37, 0xB9, 0xA8, 0xD5, 0x79, 0xCE, 0xAB, 0xB1, 0x1B, 0xA1, 0xC6, 0xAF, 0x7A, 0x39, 0xFB, 0x1B, 0x83, 0x03, 0xF4, 0xDC, 0xAB, 0xD5, 0xB7, 0xA6, 0xD7, 0x2E, 0x6A, 0x49, 0x90, 0xC4, 0x03, 0xA8, 0xAD, 0x96, 0xC5, 0xFE, 0xDD, 0xC1, 0x79, 0x12, 0xB8, 0xDE, 0x55, 0x7C, 0x2D, 0x77, 0x68, 0xBD, 0x41, 0x1E, 0x52, 0xA0, 0x48, 0xF7, 0x5E, 0x27, 0x49, 0x92, 0x20, 0xDF, 0x92, 0xEF, 0x40, 0x82, 0x71, 0x9B, 0xC7, 0xEC, 0xB5, 0xF4, 0xFF, 0xD6, 0xBC, 0xA8, 0x0C, 0x7E, 0x8D, 0x12, 0xDC, 0x64, 0xC7, 0x60, 0x9B, 0xBF, 0xEB, 0x37, 0x72, 0x5D, 0xA9, 0xCC, 0xF7, 0x68, 0x7C, 0x59, 0x34, 0x72, 0xBE, 0x94, 0x85, 0xDF, 0xF7, 0xE3, 0x1D, 0x2B, 0xBD, 0x68, 0xC0, 0xF6, 0x6D, 0xB9, 0xAE, 0xCB, 0xA5, 0x8F, 0x22, 0x73, 0x07, 0xEB, 0x5C, 0x99, 0x20, 0xFF, 0x12, 0x2D, 0x6F, 0xCA, 0xFD, 0x64, 0x29, 0xF1, 0x03, 0xC2, 0x41, 0x09, 0x19, 0xD0, 0xBA, 0x38, 0x44, 0xC8, 0xF0, 0x3E, 0x36, 0x11, 0xB3, 0x3C, 0x5C, 0x34, 0x75, 0xC5, 0x0C, 0xC9, 0xB4, 0x19, 0x1E, 0x39, 0x3C, 0xF0, 0xAA, 0xEE, 0xC0, 0x1F, 0x72, 0xE6, 0xEE, 0x82, 0xF2, 0x95, 0x17, 0x8A, 0x2F, 0xE1, 0xE5, 0x77, 0xD2, 0xE7, 0xDB, 0xE0, 0x7C, 0xAB, 0xD7, 0x18, 0xB0, 0x73, 0x9F, 0x86, 0x6D, 0xEE, 0x1C, 0x77, 0xAD, 0xEC, 0xB4, 0x1A, 0x90, 0x20, 0xBE, 0x68, 0xE0, 0x01, 0x66, 0x5D, 0x2B, 0x64, 0x83, 0x56, 0xD2, 0xF7, 0xB1, 0xF4, 0x10, 0x09, 0xA0, 0x46, 0x9C, 0x08, 0x10, 0xFB, 0x91, 0xB1, 0x34, 0x63, 0xCC, 0xE4, 0xB1, 0x40, 0x47, 0x6C, 0xCB, 0x7B, 0x42, 0x1E, 0x91, 0x37, 0xDB, 0x9F, 0xCA, 0xB7, 0x78, 0xA1, 0xEE, 0x25, 0xF8, 0x6D, 0xA6, 0xF0, 0x90, 0x69, 0x5C, 0x89, 0xC7, 0x94, 0x75, 0x0D, 0xF5, 0x5D, 0x3C, 0x7D, 0x6F, 0xF7, 0x3E, 0x20, 0x15, 0x88, 0x30, 0x74, 0xC5, 0xD0, 0xAD, 0x7C, 0xA0, 0xF4, 0x1A, 0xDF, 0xB1, 0x4A, 0x1D, 0xC5, 0xC1, 0xC9, 0x45, 0x00, 0x21, 0x3C, 0xDC, 0x12, 0x7F, 0x23, 0xF8, 0xFB, 0x29, 0x70, 0x03, 0x51, 0x20, 0x49, 0xEF, 0x4A, 0x88, 0x0F, 0x5F, 0x04, 0xF1, 0x9D, 0x16, 0x64, 0xCC, 0xF4, 0x99, 0x78, 0xDB, 0xEB, 0xD1, 0x7C, 0xAB, 0xFF, 0x3E, 0xA2, 0xA5, 0xAF, 0xB7, 0x61, 0x1F, 0xA4, 0xCA, 0xF0, 0x37, 0x36, 0x47, 0x82, 0xCF, 0xD9, 0x30, 0x66, 0x15, 0xEB, 0x00, 0x25, 0x09, 0xDA, 0x56, 0x9E, 0x45, 0xD6, 0xA6, 0x75, 0x97, 0x80, 0x3A, 0x98, 0x6F, 0x01, 0xF8, 0x9E, 0xE2, 0x59, 0xB1, 0xFE, 0xD6, 0x4E, 0x46, 0x37, 0x56, 0x0D, 0x91, 0x1D, 0x70, 0x7A, 0xD5, 0x7E, 0x2B, 0xE8, 0x20, 0x46, 0x74, 0x37, 0xA5, 0xAC, 0x13, 0xBD, 0x13, 0x59, 0x45, 0xE6, 0xF5, 0xA3, 0x26, 0x5A, 0x0F, 0x63, 0xB6, 0xEB, 0x84, 0x30, 0x0B, 0x46, 0xCA, 0x90, 0x4A, 0x4B, 0xE3, 0xB5, 0x7A, 0x22, 0xED, 0x54, 0xC5, 0xEA, 0x5C, 0x5C, 0xDD, 0xC9, 0xEF, 0xFA, 0x0D, 0x89, 0x35, 0xCF, 0xA4, 0xEE, 0x5A, 0xD5, 0x13, 0xF7, 0x2E, 0xB2, 0xED, 0x83, 0x3F, 0xE4, 0x3A, 0x6B, 0xC5, 0xAB, 0xEB, 0x02, 0xA1, 0xC8, 0xF1, 0x3B, 0x7B, 0x66, 0x5F, 0x28, 0x64, 0x95, 0x0F, 0x1C, 0xA0, 0x43, 0x94, 0x9C, 0x85, 0x90, 0xBD, 0xC7, 0xD3, 0x1B, 0x2B, 0xA2, 0x3F, 0x6E, 0x46, 0x43, 0x18, 0x34, 0xFF, 0xDD, 0x3E, 0xDC, 0xFA, 0x7A, 0x63, 0xD5, 0xAC, 0x09, 0xAC, 0x9A, 0xAD, 0x08, 0xBC, 0xAC, 0x6E, 0x3B, 0x88, 0x4D, 0xDA, 0x75, 0x1E, 0xF6, 0x01, 0xB1, 0x66, 0x74, 0x28, 0x11, 0x05, 0xC7, 0x48, 0x82, 0x6F, 0x75, 0x0B, 0x86, 0x2E, 0x06, 0x34, 0x89, 0x2F, 0xC8, 0xEB, 0xC4, 0x65, 0xBB, 0x5F, 0x71, 0x77, 0x28, 0x0A, 0xB0, 0x20, 0x4E, 0x6C, 0xF1, 0xAB, 0xAA, 0x31, 0xF6, 0xA5, 0x94, 0x13, 0x25, 0x73, 0x5F, 0x43, 0x65, 0xFC, 0xAD, 0x79, 0xB1, 0x37, 0x4E, 0x61, 0x6A, 0xD4, 0x11, 0x64, 0x37, 0xDA, 0x10, 0xB3, 0xFE, 0xF6, 0xF2, 0x89, 0xE7, 0x40, 0xE2, 0xAA, 0xE4, 0xAE, 0x6F, 0xE1, 0xD4, 0x35, 0xAE, 0xA9, 0x0C, 0xF4, 0xF9, 0xD1, 0x67, 0x61, 0xB1, 0x5A, 0x36, 0x1B, 0x78, 0xDC, 0x6F, 0xDC, 0x1A, 0xD0, 0x0D, 0xC2, 0xC0, 0x17, 0xDD, 0x88, 0xB5, 0x5C, 0xE8, 0xAA, 0x43, 0x4E, 0x62, 0xBF, 0xCB, 0x91, 0xC1, 0xAC, 0x6E, 0x2B, 0xFB, 0x75, 0x18, 0x08, 0x72, 0x16, 0x71, 0xB7, 0xF8, 0x67, 0xFE, 0xFE, 0x9C, 0xF5, 0xBC, 0x51, 0x86, 0x6F, 0x4D, 0x3A, 0x5E, 0x0C, 0x19, 0xF8, 0x35, 0xCA, 0x59, 0x5C, 0xB5, 0x4F, 0xEA, 0xBE, 0x5B, 0x06, 0x0E, 0x71, 0x20, 0x6B, 0x23, 0x56, 0xEB, 0x4B, 0x8B, 0x06, 0x35, 0x77, 0x40, 0xC7, 0xEF, 0x46, 0xA0, 0x21, 0x61, 0xE0, 0xAC, 0x39, 0x1E, 0x16, 0x6B, 0x82, 0x82, 0x81, 0x53, 0xC4, 0x17, 0x9B, 0xDA, 0xD5, 0xCC, 0xA4, 0x48, 0x10, 0x23, 0x42, 0x6A, 0x4D, 0x68, 0xAA, 0xA7, 0xE2, 0x4D, 0x9D, 0x47, 0xFB, 0xB5, 0x6C, 0x7C, 0xD0, 0x1A, 0xC3, 0x12, 0x4A, 0x98, 0xE8, 0x9E, 0x61, 0x53, 0x50, 0x60, 0xC9, 0xB2, 0xBA, 0x9B, 0x53, 0x3E, 0x27, 0xCE, 0xFD, 0xB6, 0x8C, 0x04, 0xD9, 0x64, 0x95, 0xF9, 0xEB, 0x7E, 0xF5, 0x16, 0x88, 0xEF, 0x4D, 0x58, 0xF7, 0x69, 0x29, 0x67, 0x5D, 0xD6, 0x25, 0xF0, 0x64, 0x24, 0x03, 0xA4, 0x83, 0x50, 0x72, 0x80, 0x17, 0x71, 0x12, 0x8B, 0x75, 0xD9, 0x9F, 0xBB, 0x4D, 0x23, 0x89, 0x80, 0x0C, 0x62, 0xA0, 0x14, 0x74, 0x31, 0x68, 0x8D, 0x12, 0x21, 0xEF, 0xAB, 0x81, 0x4C, 0x13, 0xE5, 0xA2, 0x72, 0x12, 0x57, 0x98, 0x28, 0x45, 0x3B, 0xEA, 0xCA, 0x67, 0x25, 0xAF, 0x59, 0x60, 0x5E, 0x7B, 0x19, 0xD0, 0xFE, 0xD2, 0x55, 0xDF, 0xF5, 0x07, 0xB0, 0x21, 0x02, 0x64, 0xC0, 0x21, 0x62, 0x77, 0x0D, 0x9B, 0xF5, 0xAE, 0x1E, 0xFD, 0xEE, 0xE7, 0x81, 0xF6, 0xBD, 0x84, 0xA6, 0xAC, 0x94, 0xD2, 0x59, 0xA3, 0x52, 0x1C, 0x78, 0xFD, 0xFF, 0x41, 0xDB, 0x35, 0xBD, 0x41, 0x7C, 0x07, 0x8D, 0x14, 0xE8, 0x61, 0xD0, 0xE6, 0x09, 0x7F, 0x5B, 0xFB, 0x5A, 0x3B, 0x2B, 0xE3, 0x29, 0xCE, 0xBC, 0x8B, 0xF7, 0x1C, 0xC5, 0xFD, 0xAD, 0xE2, 0xDA, 0x33, 0x42, 0xF4, 0xDE, 0xA3, 0xD9, 0x9A, 0x88, 0x10, 0x8C, 0xC4, 0x77, 0x3E, 0x76, 0x12, 0x4D, 0xFC, 0xFE, 0x8F, 0x16, 0xC0, 0xAF, 0x7C, 0x51, 0x71, 0xC3, 0xD0, 0xAF, 0x04, 0x70, 0x72, 0x78, 0x6C, 0x75, 0x41, 0x20, 0xBF, 0x5F, 0xAC, 0x88, 0x26, 0x38, 0xE7, 0x2E, 0xFF, 0x2B, 0x07, 0xD9, 0x24, 0x49, 0x83, 0x3A, 0xA0, 0x05, 0x7C, 0xDF, 0x8E, 0x93, 0x24, 0xC8, 0xF7, 0xFF, 0x82, 0xC8, 0xBD, 0xEB, 0x94, 0x46, 0xCC, 0xEA, 0xDF, 0xFB, 0x27, 0xC5, 0x91, 0x7D, 0xFA, 0x8D, 0xEC, 0x67, 0xCE, 0xCB, 0x96, 0x61, 0x6D, 0x53, 0x2E, 0x48, 0x8D, 0x57, 0x5A, 0xC4, 0xB5, 0x47, 0x8B, 0xDE, 0x87, 0xC0, 0x8E, 0x3B, 0xC9, 0x6A, 0x0D, 0x74, 0xEE, 0x24, 0x62, 0xEB, 0x2E, 0x5D, 0xBF, 0x29, 0x05, 0x3D, 0xA4, 0x57, 0x6B, 0x7B, 0x03, 0x5F, 0x99, 0x7A, 0x69, 0x92, 0xA4, 0x48, 0x2E, 0x8A, 0xC4, 0xAF, 0xB6, 0x8B, 0xD8, 0x75, 0x59, 0xBF, 0x30, 0xD2, 0xC0, 0x82, 0x41, 0x93, 0xC7, 0xF2, 0xAD, 0xB0, 0x47, 0xFB, 0x95, 0xF2, 0xA7, 0xEA, 0xD5, 0x2E, 0x06, 0x8D, 0xAF, 0x34, 0xA9, 0x3F, 0x74, 0x35, 0xFE, 0x3C, 0x79, 0xAE, 0xFB, 0xCE, 0xD0, 0x5F, 0x9D, 0xEA, 0x41, 0xB2, 0xC8, 0xB9, 0x23, 0x28, 0xE4, 0xE8, 0xFD, 0x13, 0x8E, 0xDC, 0xD1, 0x4D, 0x07, 0xF5, 0x71, 0x40, 0xEA, 0xDA, 0xC3, 0x24, 0x71, 0x32, 0xAB, 0x93, 0x53, 0xC9, 0xCA, 0x05, 0xFF, 0xEE, 0x1C, 0x73, 0x32, 0x40, 0x94, 0x18, 0xC9, 0x1B, 0xD5, 0xBB, 0x73, 0xAC, 0xF4, 0xA9, 0xF3, 0x4A, 0xDB, 0x7F, 0xDB, 0xED, 0x4E, 0x28, 0xF6, 0x41, 0x16, 0x48, 0xF3, 0x4A, 0x61, 0x51, 0x6E, 0x65, 0xB3, 0xF5, 0xAE, 0xB1, 0xAD, 0xD5, 0x39, 0x16, 0x64, 0x80, 0x92, 0x2F, 0xAC, 0x4D, 0xF6, 0xE4, 0xB4, 0x3D, 0xB2, 0xA3, 0xE5, 0x4E, 0xD8, 0x0E, 0xC9, 0x01, 0x7E, 0x56, 0x0A, 0x73, 0x0F, 0xDB, 0x38, 0xA0, 0x92, 0xC4, 0x22, 0x49, 0x83, 0x56, 0x52, 0x60, 0x74, 0x61, 0x44, 0x7E, 0x8D, 0x86, 0x69, 0xC6, 0x0C, 0xD7, 0xC1, 0x47, 0xEC, 0x49, 0x79, 0x55, 0xFE, 0xAD, 0x50, 0xF3, 0xD7, 0xCD, 0x10, 0xB3, 0xE2, 0x99, 0x23, 0x87, 0x7B, 0x16, 0x74, 0xB6, 0xE7, 0xF9, 0xDD, 0xDE, 0x5F, 0xF1, 0xAB, 0x55, 0xDD, 0xD7, 0xF0, 0x0C, 0x59, 0x1B, 0x0E, 0x92, 0x76, 0x7F, 0xEE, 0xF4, 0xC3, 0xD7, 0xD5, 0x80, 0xAD, 0x87, 0x7B, 0x88, 0xAE, 0xAB, 0x81, 0x7D, 0xDD, 0xE4, 0xA4, 0xC8, 0x00, 0x11, 0xD2, 0xEB, 0xEB, 0x0C, 0xE2, 0x37, 0x3A, 0xA4, 0x56, 0xA9, 0xE1, 0x17, 0x35, 0x7F, 0xC2, 0xDE, 0xD4, 0x7E, 0xF4, 0xBC, 0xC1, 0x46, 0xE2, 0xAE, 0xC1, 0x3C, 0xA6, 0xE1, 0xF7, 0xBD, 0x03, 0x9F, 0xE4, 0x29, 0xA4, 0x09, 0xD2, 0xEE, 0xB2, 0x97, 0xB9, 0x4E, 0x03, 0xFA, 0xEA, 0xAA, 0x46, 0xE9, 0x22, 0x09, 0xB2, 0x80, 0x27, 0xD0, 0xFE, 0xD1, 0x3D, 0x69, 0x03, 0xF2, 0x10, 0x05, 0xDE, 0xC0, 0xF6, 0x4C, 0xCE, 0xBD, 0xDA, 0x09, 0xB1, 0x45, 0x90, 0x22, 0x0D, 0x5A, 0x48, 0xAD, 0xEE, 0x81, 0xB3, 0x3E, 0xD9, 0xB3, 0xB9, 0x8B, 0xB5, 0xC4, 0x19, 0x33, 0x5C, 0x0D, 0x9C, 0x14, 0x8E, 0xD3, 0xCC, 0xBF, 0x47, 0xF5, 0x79, 0x3D, 0x1B, 0x1F, 0x68, 0x13, 0x7C, 0x30, 0x83, 0x93, 0x11, 0x70, 0x54, 0xCF, 0xC3, 0x98, 0x55, 0xEF, 0xA3, 0xFA, 0x80, 0x3A, 0xA4, 0xD7, 0x73, 0xD5, 0x40, 0x0B, 0xC8, 0x1E, 0x67, 0x59, 0x20, 0x65, 0xB5, 0xA8, 0xAE, 0x82, 0x0C, 0x37, 0x20, 0xB6, 0xC6, 0xFC, 0x25, 0xD9, 0xFF, 0x56, 0x24, 0x88, 0x93, 0xBC, 0x29, 0x05, 0xFD, 0x31, 0x24, 0x89, 0xFF, 0x6A, 0x5C, 0x1C, 0x30, 0xC5, 0x98, 0xE5, 0x53, 0xFE, 0x66, 0x0F, 0x7B, 0x61, 0xF3, 0x3A, 0x75, 0x96, 0x16, 0x3E, 0x96, 0xC6, 0x5D, 0x5F, 0x18, 0x1E, 0x52, 0x5D, 0x57, 0x03, 0xB5, 0x3E, 0x67, 0x67, 0x6D, 0x30, 0x53, 0xD7, 0x1C, 0xCC, 0x59, 0xEF, 0xA2, 0x26, 0x7E, 0x9F, 0x1E, 0xFA, 0xCB, 0x13, 0x91, 0x6A, 0x10, 0x09, 0xB4, 0xEE, 0x94, 0x49, 0x0C, 0xB0, 0x26, 0x4A, 0x8C, 0x38, 0x91, 0x5F, 0xFF, 0x2F, 0xD6, 0x14, 0x37, 0x25, 0x43, 0x9A, 0x04, 0x11, 0xE0, 0x7B, 0x5E, 0x5E, 0x33, 0x66, 0xF5, 0x54, 0x61, 0xAE, 0x72, 0xC8, 0xDB, 0xFF, 0xC6, 0xAC, 0xE4, 0x6D, 0x71, 0x6C, 0xEC, 0x93, 0xD5, 0x38, 0x2A, 0x88, 0x59, 0x05, 0xC7, 0x48, 0xEC, 0x01, 0x4C, 0xF6, 0x6B, 0xE5, 0x3C, 0x20, 0x88, 0xEE, 0xCA, 0x96, 0x5C, 0x31, 0xFB, 0x1E, 0x12, 0xD2, 0x64, 0x0A, 0x64, 0x02, 0x53, 0xC6, 0x6C, 0x9F, 0x2F, 0x3E, 0x02, 0xE4, 0x21, 0xF5, 0xEB, 0x81, 0x0D, 0xD2, 0xAB, 0xF0, 0x27, 0x80, 0x7C, 0x38, 0xD9, 0x4F, 0x6A, 0xDE, 0x3F, 0x52, 0x93, 0x31, 0xEB, 0x27, 0x02, 0x33, 0xA3, 0xDD, 0x50, 0xCD, 0x97, 0xF3, 0xAA, 0xE6, 0x53, 0xF3, 0x4E, 0x73, 0x85, 0xF5, 0xC2, 0x6B, 0x65, 0x1C, 0x3B, 0xE4, 0x40, 0x4A, 0xC8, 0x76, 0xBA, 0xF6, 0xCB, 0x59, 0xEC, 0x99, 0x32, 0x79, 0x40, 0x28, 0xB0, 0x7D, 0x94, 0x5C, 0x29, 0xB6, 0x2F, 0x3C, 0xBE, 0x8A, 0xEC, 0x8E, 0x32, 0x82, 0x24, 0xD7, 0x05, 0xA6, 0x34, 0x38, 0x44, 0x6A, 0x5D, 0x6E, 0x06, 0x48, 0x52, 0x87, 0x38, 0x59, 0xAF, 0xD8, 0xF9, 0x8E, 0x25, 0x45, 0x9A, 0x04, 0x39, 0xEB, 0x4E, 0x5D, 0xEE, 0x3B, 0xF5, 0x9A, 0x27, 0xEB, 0x2E, 0x40, 0x08, 0x6C, 0xCA, 0x9E, 0xCE, 0xB7, 0xB3, 0xF0, 0x2D, 0x55, 0x1C, 0x3A, 0x7D, 0x0C, 0x7F, 0xD6, 0x92, 0xFB, 0x73, 0x66, 0x7B, 0x0D, 0x38, 0x8C, 0xD9, 0x2E, 0x3E, 0x14, 0x90, 0xFE, 0xFB, 0x46, 0xE9, 0x0A, 0xD6, 0xB7, 0x97, 0xD7, 0x06, 0x56, 0x40, 0x56, 0xB5, 0xD3, 0x75, 0x96, 0xBF, 0xCE, 0x9C, 0x02, 0x7C, 0x57, 0xD5, 0x0B, 0x31, 0xA2, 0x3F, 0xF6, 0x41, 0x4E, 0xC2, 0x88, 0x2E, 0xCE, 0xFA, 0x21, 0x0A, 0xB2, 0x10, 0xB3, 0xC6, 0x3C, 0x9C, 0x29, 0xC7, 0x88, 0x72, 0xE9, 0x47, 0xE3, 0xAD, 0x40, 0x15, 0x5F, 0xB6, 0xE1, 0xF0, 0x2C, 0x08, 0xB8, 0x87, 0xA2, 0xC9, 0x3D, 0xED, 0x9E, 0x25, 0xD4, 0xFB, 0x0A, 0xEA, 0xAB, 0x3C, 0xF0, 0xBE, 0xF3, 0xAE, 0x11, 0xC0, 0x1D, 0xA8, 0xDE, 0xA7, 0x94, 0x9E, 0x0F, 0xFE, 0xC7, 0x06, 0x1A, 0x40, 0x18, 0xB4, 0x26, 0x71, 0xC0, 0x59, 0x03, 0x99, 0x4D, 0x80, 0x1E, 0x20, 0x49, 0x82, 0xD8, 0xC2, 0x49, 0x02, 0x8D, 0x3D, 0x1E, 0x67, 0xB1, 0x0A, 0xA1, 0xF7, 0xEC, 0xB9, 0x34, 0x06, 0x0D, 0x47, 0x81, 0x38, 0xF2, 0xA8, 0xBE, 0x6A, 0xF3, 0xE8, 0xC1, 0xA4, 0xCC, 0x96, 0x57, 0x2D, 0x91, 0x08, 0xAC, 0x3F, 0x94, 0x07, 0xCE, 0x9C, 0x9C, 0x8E, 0x66, 0xF1, 0xA3, 0x30, 0x19, 0xDF, 0xF9, 0x55, 0x30, 0xAA, 0x77, 0x75, 0x6D, 0x93, 0x08, 0xA0, 0x0D, 0xE4, 0x80, 0x63, 0x40, 0x04, 0xE8, 0x01, 0xB2, 0x4F, 0x94, 0x06, 0x32, 0x81, 0x17, 0xB0, 0x01, 0x2E, 0x20, 0x0C, 0xE4, 0x47, 0x81, 0x72, 0xD2, 0xA0, 0xED, 0xEE, 0xD0, 0x3A, 0x44, 0x84, 0x18, 0x71, 0x62, 0x37, 0x2A, 0xC0, 0x92, 0x41, 0xD3, 0xFF, 0x75, 0x26, 0xFC, 0x48, 0x21, 0x9D, 0x80, 0xD8, 0xB9, 0x1F, 0x65, 0xB9, 0x4C, 0xDF, 0x79, 0xB4, 0xA1, 0x23, 0x0C, 0x9A, 0xD7, 0x4A, 0x56, 0x04, 0x69, 0xA0, 0xE7, 0x2E, 0xFC, 0x2C, 0x01, 0x91, 0xC0, 0x0D, 0x58, 0x10, 0x5D, 0x18, 0x71, 0x92, 0xA4, 0x81, 0x1B, 0x71, 0xD2, 0x20, 0x94, 0x14, 0x48, 0x5D, 0x21, 0x54, 0x32, 0xA0, 0x13, 0x8C, 0x12, 0x67, 0x24, 0x0F, 0x09, 0x20, 0xEB, 0x1B, 0xA8, 0xCD, 0xA0, 0xD9, 0xB3, 0xA3, 0x25, 0xFD, 0x6A, 0x30, 0x4F, 0xD4, 0xFD, 0xF4, 0x1B, 0xD3, 0xFE, 0x0F, 0xAD, 0x93, 0x68, 0x51, 0xB5, 0xC2, 0x76, 0x76, 0x57, 0x26, 0x9F, 0x6B, 0xAA, 0x47, 0xF2, 0xD5, 0xDB, 0xAF, 0x3A, 0x70, 0x01, 0xCA, 0x5A, 0xDB, 0x19, 0x50, 0x1F, 0x87, 0x14, 0xD3, 0x1A, 0x07, 0x78, 0x82, 0x2C, 0x50, 0x46, 0x0A, 0xF4, 0x21, 0x0E, 0xC6, 0x08, 0xE7, 0x55, 0x1C, 0x27, 0x0D, 0x24, 0x80, 0x1A, 0x19, 0x60, 0x05, 0x9C, 0x04, 0x49, 0x25, 0x0D, 0xCA, 0x41, 0x2B, 0x98, 0x43, 0x0A, 0x47, 0xCB, 0x57, 0x14, 0x31, 0xF3, 0xC7, 0xE4, 0xD5, 0xF3, 0x37, 0x23, 0x64, 0xB8, 0xFB, 0x41, 0xCC, 0x8A, 0x59, 0x2C, 0x61, 0x7D, 0xBF, 0x06, 0xE2, 0x8E, 0xA5, 0x53, 0x9D, 0x31, 0xF3, 0xD8, 0x4F, 0x27, 0x6F, 0xC5, 0x56, 0x15, 0x47, 0xBE, 0x4E, 0x2C, 0x80, 0x1E, 0x70, 0x8A, 0x18, 0xD0, 0x04, 0x5D, 0x08, 0x61, 0x1C, 0x50, 0x24, 0x0C, 0xA8, 0xF3, 0x87, 0x18, 0x70, 0x07, 0x2A, 0xE0, 0xF4, 0xFD, 0x1A, 0x98, 0x21, 0xDF, 0x7F, 0x3C, 0xC4, 0xC8, 0x00, 0x29, 0x60, 0x87, 0x34, 0x19, 0xE0, 0xFA, 0x8B, 0x02, 0xF9, 0x3D, 0x9D, 0x81, 0x1D, 0xC6, 0xA9, 0x47, 0xE3, 0x0D, 0x9D, 0x27, 0xFA, 0x3D, 0x85, 0x2C, 0xAE, 0x8F, 0xE1, 0x4A, 0xB4, 0xFF, 0x30, 0xA9, 0x7C, 0x1F, 0xA6, 0x5C, 0x67, 0x01, 0x8F, 0x95, 0x46, 0xD3, 0xFE, 0x16, 0xCD, 0xFB, 0x41, 0x72, 0x05, 0xDA, 0x77, 0x55, 0xDA, 0x18, 0xE8, 0xBA, 0x33, 0x90, 0xC5, 0x90, 0xFB, 0x21, 0x09, 0x64, 0x65, 0xC5, 0x64, 0x95, 0xE4, 0xD9, 0x01, 0x52, 0x24, 0x89, 0x93, 0xB3, 0x50, 0x12, 0xBF, 0xAA, 0x96, 0x87, 0x14, 0x71, 0x60, 0x49, 0x94, 0xCC, 0x5A, 0x06, 0xF2, 0x31, 0x7C, 0xDB, 0xFF, 0x7E, 0xD0, 0xF4, 0x55, 0xAF, 0xA7, 0xED, 0x35, 0x57, 0xA4, 0x59, 0x5D, 0x78, 0xB9, 0x1F, 0x28, 0x5E, 0xB0, 0xB9, 0x87, 0x09, 0x09, 0x9D, 0x5C, 0xF3, 0x4A, 0x5C, 0xF9, 0xFC, 0x3B, 0xB0, 0xBA, 0xFF, 0xED, 0xC4, 0x5A, 0x34, 0x05, 0x0C, 0xC3, 0xA4, 0x6B, 0xA5, 0x48, 0x05, 0x5E, 0x40, 0xF5, 0x2E, 0x1E, 0x8A, 0xB5, 0x0C, 0xE8, 0x87, 0x13, 0xF9, 0x85, 0xFF, 0xD8, 0xCB, 0x78, 0x80, 0x30, 0xE2, 0x8B, 0x20, 0x09, 0xD2, 0x40, 0x35, 0x83, 0x56, 0x8F, 0xC7, 0x3B, 0x56, 0x8F, 0xE4, 0x2B, 0xDA, 0x18, 0x12, 0x2F, 0xF6, 0x94, 0xBD, 0x35, 0xF5, 0x04, 0xAB, 0xF6, 0xE2, 0xED, 0x10, 0x43, 0xC5, 0x52, 0xE4, 0x73, 0xDE, 0xFA, 0x82, 0x16, 0xBD, 0xEE, 0xD4, 0xBF, 0x3A, 0xBD, 0xFC, 0x9E, 0x35, 0xFF, 0x0A, 0x1E, 0x56, 0xA3, 0xC0, 0x01, 0x5E, 0xC0, 0x1C, 0xB8, 0x82, 0xFA, 0x2A, 0x8A, 0x0E, 0xF8, 0x9E, 0xDF, 0x22, 0x5F, 0xE4, 0x67, 0x75, 0x74, 0x4B, 0x91, 0x43, 0x92, 0x0C, 0x50, 0x25, 0x49, 0x06, 0x98, 0x01, 0x27, 0x31, 0x20, 0x93, 0x34, 0x29, 0xA2, 0x8B, 0x04, 0x23, 0x8C, 0x59, 0x63, 0x50, 0x49, 0xD8, 0x53, 0xE7, 0x1F, 0xFA, 0x3A, 0xA8, 0xD7, 0x08, 0x1E, 0xCE, 0x4A, 0xA6, 0xF0, 0x92, 0x45, 0x9A, 0x7A, 0x5D, 0x3D, 0xC5, 0xD9, 0xB3, 0x37, 0x56, 0x12, 0x3E, 0x0E, 0xB0, 0x04, 0x12, 0xBF, 0x66, 0x57, 0xD5, 0x1A, 0x5D, 0xDB, 0xC0, 0xE5, 0x46, 0x8B, 0x9C, 0x1F, 0x75, 0x9D, 0x46, 0xEA, 0x7B, 0xC8, 0xD6, 0xE8, 0xA4, 0xB0, 0xD5, 0x93, 0xDB, 0x2B, 0xAB, 0xDD, 0x40, 0x65, 0xC5, 0x53, 0x89, 0x2D, 0x9C, 0x0C, 0x88, 0x62, 0xCC, 0xE6, 0xD1, 0x7A, 0x27, 0xE4, 0x0F, 0x55, 0x7E, 0xFD, 0x9D, 0x3D, 0x63, 0x8D, 0x1C, 0xC3, 0x37, 0xDC, 0x25, 0x0B, 0x6F, 0x84, 0xEE, 0x7B, 0x52, 0xF2, 0xA1, 0xA3, 0xD7, 0x74, 0x69, 0x7B, 0x7B, 0xD5, 0x21, 0x5B, 0x02, 0x59, 0x47, 0xCA, 0x18, 0x60, 0x0D, 0x74, 0x55, 0x97, 0x9C, 0x35, 0xEF, 0xA4, 0x8B, 0x28, 0xA8, 0x26, 0x7E, 0xD3, 0x67, 0x55, 0xB3, 0x18, 0x90, 0x43, 0x1A, 0xA8, 0x92, 0x04, 0x26, 0xC0, 0x0F, 0x09, 0xD2, 0xE4, 0x67, 0x91, 0x69, 0x81, 0x52, 0x04, 0x6D, 0xCE, 0xE3, 0xF5, 0xCE, 0xC9, 0xA7, 0xED, 0x8D, 0x89, 0xAB, 0x3B, 0xD6, 0xA3, 0x99, 0xAC, 0x1B, 0xE6, 0x60, 0x12, 0x09, 0xD6, 0x3C, 0xD7, 0xFD, 0x70, 0x43, 0x79, 0x75, 0xDD, 0x94, 0x7B, 0xAF, 0x1B, 0xE1, 0xF9, 0x75, 0xE3, 0xB9, 0xD3, 0x36, 0xB2, 0xF3, 0x35, 0x2B, 0x39, 0xE9, 0x3F, 0x47, 0xFA, 0xAE, 0xB2, 0xF7, 0x55, 0xD3, 0x6E, 0x03, 0x52, 0x40, 0x29, 0x99, 0x55, 0x56, 0x72, 0x56, 0x8A, 0x2C, 0x48, 0x92, 0x21, 0x7D, 0x23, 0x01, 0xD4, 0x19, 0x33, 0x41, 0xB9, 0x86, 0x21, 0x5F, 0x3B, 0xD3, 0x4F, 0xC7, 0x5B, 0x82, 0x39, 0x12, 0x1A, 0x83, 0xCF, 0xC0, 0x24, 0x7E, 0xB2, 0x23, 0x82, 0x61, 0x72, 0x9D, 0xD4, 0x0B, 0xCA, 0x2B, 0xAB, 0xA0, 0xA7, 0x6B, 0x7D, 0x5E, 0x0C, 0xD4, 0x59, 0x55, 0xDA, 0xBD, 0xC6, 0x0D, 0x1A, 0xA8, 0x58, 0x43, 0x40, 0xED, 0x4E, 0x33, 0xF4, 0xBE, 0x52, 0x3B, 0x20, 0x06, 0xF4, 0x2E, 0x83, 0x34, 0x30, 0x7E, 0x1F, 0xC3, 0x25, 0xC8, 0xBA, 0x40, 0xF4, 0x04, 0x61, 0x3F, 0xF0, 0xBC, 0x09, 0x05, 0x39, 0x8C, 0x99, 0x3E, 0x31, 0xAF, 0x0A, 0x72, 0x40, 0xDE, 0xF2, 0x78, 0xBF, 0xC6, 0x3E, 0xA8, 0x54, 0xC7, 0xFE, 0x22, 0xF0, 0x8C, 0x56, 0x25, 0x8E, 0x6B, 0x79, 0xDF, 0xA5, 0x47, 0xAF, 0x02, 0xBE, 0x90, 0xB5, 0x79, 0x58, 0x15, 0xB2, 0x66, 0x77, 0xB9, 0x74, 0x38, 0xD0, 0x5F, 0x37, 0x16, 0x3A, 0x77, 0x62, 0xB6, 0x48, 0x3A, 0x08, 0xE2, 0x8B, 0xDA, 0x31, 0x5B, 0xED, 0x85, 0x7A, 0x48, 0x03, 0x5B, 0x67, 0x87, 0x3C, 0xA0, 0x74, 0x7D, 0xB9, 0x43, 0xD6, 0x0A, 0x9D, 0x0E, 0x3A, 0x19, 0xB3, 0xEF, 0x42, 0x20, 0xD1, 0x23, 0xA0, 0x76, 0x4D, 0x95, 0xB0, 0x63, 0xEC, 0x7C, 0x6A, 0xB6, 0x5F, 0x33, 0x31, 0x1A, 0x71, 0x15, 0x09, 0x79, 0xEE, 0x86, 0x9A, 0xDE, 0xAF, 0xF1, 0x06, 0x66, 0xEB, 0x32, 0xA5, 0x41, 0x92, 0x48, 0x52, 0x7B, 0xD0, 0xE3, 0xAA, 0x00, 0x9A, 0x5F, 0x0F, 0x67, 0x80, 0x10, 0xD0, 0x72, 0x27, 0x22, 0x7B, 0x65, 0xC5, 0x74, 0x80, 0xAD, 0x0E, 0xB6, 0xD8, 0x4D, 0x17, 0x43, 0x9A, 0x24, 0x91, 0x1F, 0x7D, 0x19, 0xF3, 0x05, 0xCD, 0x1F, 0x97, 0xF7, 0xF8, 0xA0, 0xCD, 0x22, 0xE7, 0xAA, 0x7E, 0x37, 0x51, 0x7C, 0x78, 0x7C, 0x90, 0x39, 0x1C, 0xC1, 0x7D, 0xA3, 0xAD, 0xBF, 0x6A, 0x20, 0xF7, 0xB4, 0xFF, 0xFA, 0x75, 0x47, 0xA1, 0x0E, 0xCE, 0x59, 0xC5, 0x1B, 0x06, 0x42, 0x49, 0x81, 0xB6, 0x55, 0xA3, 0xD0, 0xE0, 0x14, 0x51, 0x72, 0xD6, 0x7D, 0x89, 0x02, 0x25, 0xB9, 0x16, 0x03, 0x59, 0xCF, 0xB8, 0x1D, 0x12, 0x3B, 0x76, 0x64, 0x57, 0xE0, 0xCA, 0x6A, 0x2E, 0x50, 0x52, 0xA0, 0x0F, 0x83, 0x16, 0xE8, 0x1D, 0x66, 0x01, 0xC2, 0xD1, 0x7C, 0x3C, 0xDE, 0x74, 0x4C, 0x92, 0x60, 0xD9, 0xA3, 0x45, 0x2A, 0xD7, 0x23, 0x45, 0x1A, 0x7A, 0x04, 0x67, 0x80, 0x9F, 0xA5, 0xA2, 0xDF, 0x8A, 0xF4, 0x7D, 0xCE, 0x65, 0xED, 0xFE, 0x5B, 0x80, 0x37, 0x90, 0x5A, 0x29, 0xC8, 0x00, 0x23, 0x64, 0x40, 0x93, 0x52, 0x90, 0x06, 0x62, 0x88, 0x91, 0xFA, 0xF5, 0x46, 0xFB, 0x55, 0x0B, 0x27, 0x6B, 0xE7, 0x6B, 0x0A, 0xDC, 0xC9, 0x80, 0x10, 0xA2, 0xE4, 0x2C, 0x0A, 0x94, 0x33, 0x66, 0x89, 0x2E, 0x45, 0x8D, 0x27, 0xEA, 0xD5, 0x51, 0xAC, 0xA3, 0xE6, 0x4F, 0x9F, 0xD7, 0x8B, 0x7F, 0x10, 0xE5, 0x9F, 0xA0, 0x1D, 0xA1, 0x0B, 0xDC, 0x74, 0x7E, 0x31, 0xAB, 0x7B, 0x4E, 0xA0, 0xBE, 0x7E, 0xEE, 0xF3, 0x93, 0x3A, 0x59, 0xC3, 0x0A, 0x33, 0x80, 0xED, 0x23, 0xCF, 0xDE, 0x0B, 0xCC, 0xAF, 0xFE, 0xA8, 0x00, 0x75, 0x40, 0xC8, 0x8F, 0x71, 0x1D, 0xBD, 0xD7, 0xC3, 0xFE, 0x75, 0xD9, 0xBB, 0x7E, 0x69, 0x3F, 0x20, 0x88, 0x37, 0x49, 0x22, 0xC0, 0xFA, 0x47, 0x1A, 0x6D, 0xEA, 0x3A, 0x38, 0x95, 0xD7, 0x1F, 0xDC, 0xED, 0xE9, 0x79, 0xED, 0x08, 0x7E, 0xA9, 0xC6, 0x02, 0xFA, 0xB7, 0x74, 0x46, 0xEF, 0x7C, 0xED, 0xA1, 0x53, 0xD7, 0xD2, 0x69, 0xAF, 0xAD, 0x16, 0xF9, 0xEC, 0x35, 0x97, 0x6B, 0xB5, 0xED, 0x56, 0x91, 0x43, 0x0A, 0xF4, 0xC7, 0x90, 0x58, 0xEC, 0xAB, 0xF1, 0x95, 0xE4, 0x0E, 0x07, 0xBD, 0x9A, 0xCD, 0xD5, 0x80, 0x29, 0x19, 0xE0, 0xB5, 0x0E, 0x47, 0x87, 0x38, 0x19, 0x50, 0x41, 0x66, 0x6D, 0x8B, 0x9B, 0x41, 0xEB, 0x2B, 0x15, 0x64, 0xC7, 0x51, 0x8D, 0x90, 0xFD, 0xB4, 0xBE, 0x5A, 0x86, 0x26, 0x0D, 0x0B, 0xB4, 0x9A, 0x0F, 0x4F, 0x6B, 0x9E, 0x57, 0x71, 0x50, 0xEA, 0x9A, 0x29, 0xF7, 0xE5, 0xAA, 0xBE, 0x86, 0xE9, 0x1A, 0xD2, 0x20, 0x0A, 0xE8, 0xAC, 0xB1, 0x55, 0x03, 0xBE, 0x53, 0x91, 0xC4, 0x3A, 0xDD, 0x38, 0x89, 0x45, 0x83, 0x14, 0x50, 0x0A, 0xC6, 0xEE, 0x5C, 0x45, 0x06, 0xE8, 0xE6, 0x29, 0x2C, 0x80, 0x28, 0x50, 0x62, 0x02, 0xFC, 0x90, 0x04, 0xA1, 0x24, 0x41, 0x1E, 0xD2, 0xA0, 0x0A, 0xF4, 0x17, 0xB3, 0x79, 0xC4, 0x30, 0x9D, 0xC4, 0x51, 0x39, 0x8F, 0x35, 0xA1, 0xFD, 0xA9, 0x79, 0x4D, 0x1B, 0x73, 0xF0, 0xB4, 0x90, 0x97, 0x0B, 0xC7, 0x67, 0xA7, 0xEB, 0xC7, 0x98, 0x17, 0x31, 0xC6, 0x6C, 0x95, 0x49, 0xE9, 0xB9, 0xB3, 0x13, 0xAD, 0xC0, 0xF7, 0x80, 0x8D, 0x5A, 0x33, 0x0A, 0x0A, 0xB8, 0xDD, 0x68, 0x13, 0x27, 0x71, 0x63, 0x05, 0x5A, 0x18, 0xC8, 0xD5, 0xA6, 0x50, 0x3B, 0x66, 0x09, 0xB4, 0x80, 0x11, 0x6F, 0x10, 0x4E, 0x0A, 0xA4, 0x10, 0x27, 0x05, 0x2A, 0xC1, 0xB7, 0xDD, 0xF8, 0xCA, 0x95, 0x30, 0x67, 0xC9, 0x5F, 0xB7, 0xC4, 0xC7, 0x8E, 0x87, 0x4E, 0x15, 0x7B, 0x92, 0x13, 0x6C, 0xD1, 0xF5, 0x92, 0xFF, 0xA0, 0xA6, 0x83, 0xAE, 0xCE, 0x9F, 0x0D, 0x3D, 0x12, 0xFC, 0x56, 0x3B, 0x33, 0x89, 0x0D, 0x74, 0xC0, 0xD9, 0x2D, 0x51, 0xBD, 0xBA, 0xFD, 0x1D, 0xF4, 0x01, 0x25, 0x20, 0x03, 0x44, 0x91, 0x20, 0x49, 0x02, 0xA4, 0x80, 0x0A, 0xC6, 0xC7, 0x81, 0x36, 0xF0, 0x00, 0xD1, 0x77, 0x0C, 0xCA, 0x40, 0x2B, 0x98, 0x8F, 0xEF, 0x0B, 0x34, 0xD2, 0x40, 0x84, 0x34, 0xD0, 0x02, 0x56, 0x5F, 0xD0, 0xE4, 0x1A, 0x95, 0x6C, 0x76, 0x77, 0xF4, 0xA8, 0x24, 0x9E, 0x87, 0x28, 0x94, 0x6C, 0xC5, 0x20, 0x27, 0xE2, 0xAB, 0x48, 0xA8, 0x56, 0x2B, 0x6C, 0x5F, 0xE5, 0xF9, 0xF9, 0xE6, 0x87, 0x82, 0x2F, 0x23, 0xD4, 0x01, 0xBC, 0x81, 0xAC, 0x69, 0x2F, 0xB5, 0x76, 0x91, 0xA1, 0xC0, 0x85, 0x1C, 0x62, 0x24, 0x41, 0xD4, 0x9D, 0xE7, 0x0F, 0x86, 0x5E, 0x14, 0x84, 0x80, 0x5A, 0x2D, 0x4E, 0x93, 0x0C, 0x6F, 0x01, 0x09, 0xA0, 0x46, 0x1A, 0x98, 0x93, 0x5E, 0x4F, 0x6E, 0x81, 0x3A, 0x5F, 0xD0, 0xF4, 0x11, 0x7F, 0xCD, 0xFB, 0xB1, 0x7E, 0xC7, 0xE2, 0x0B, 0x1A, 0x52, 0x42, 0x1E, 0xF8, 0xF1, 0x91, 0xF8, 0x30, 0xA8, 0xFF, 0x21, 0x02, 0xB9, 0x47, 0xDD, 0xED, 0x3C, 0xAA, 0xDF, 0xC6, 0x86, 0xDF, 0xC8, 0xB3, 0x92, 0xC7, 0x44, 0x98, 0xBA, 0x8E, 0x06, 0xE7, 0x4B, 0xC6, 0x06, 0x90, 0xBE, 0xBB, 0xB6, 0xB2, 0xD6, 0xB4, 0xCC, 0x21, 0x4A, 0x56, 0xBA, 0x57, 0xC8, 0xF7, 0x44, 0x7D, 0xC9, 0x71, 0x15, 0x90, 0x0D, 0x26, 0x56, 0xE6, 0x7B, 0x80, 0x1D, 0xE0, 0x06, 0x42, 0x88, 0x92, 0x26, 0x05, 0x52, 0x40, 0x91, 0xB6, 0x2F, 0x68, 0xF6, 0xB8, 0xBF, 0x15, 0xF1, 0x87, 0x31, 0xD4, 0x23, 0xE4, 0x19, 0xF4, 0x59, 0x64, 0xE1, 0xD8, 0xE0, 0x89, 0xB5, 0xC4, 0x94, 0x97, 0x2B, 0xC2, 0x0A, 0xDB, 0xBD, 0x49, 0xAB, 0x7B, 0xA0, 0xD0, 0x39, 0x2B, 0xCD, 0xCC, 0xCF, 0x41, 0x19, 0xB0, 0xBA, 0xD7, 0x81, 0x1A, 0x12, 0x60, 0x56, 0x76, 0xEC, 0xD4, 0xFD, 0x43, 0xA2, 0x76, 0xAE, 0x04, 0x9C, 0x02, 0x76, 0x40, 0xCD, 0xFD, 0xD3, 0x5D, 0x57, 0x22, 0xD3, 0x40, 0x1D, 0xB0, 0xC7, 0x44, 0x9D, 0x24, 0xB5, 0x50, 0x22, 0xA4, 0x81, 0xD6, 0x17, 0x34, 0x7F, 0xF4, 0xBC, 0x95, 0xFA, 0x44, 0xBE, 0x52, 0x7A, 0x8D, 0x61, 0x6A, 0x7E, 0x29, 0xE6, 0x81, 0x63, 0x5C, 0x36, 0x9E, 0x12, 0xDB, 0xF3, 0x0B, 0xF7, 0xD5, 0x40, 0x37, 0xBF, 0xE0, 0x9D, 0x72, 0xFF, 0xBE, 0xD2, 0x02, 0x36, 0x2B, 0xF3, 0x2A, 0x6B, 0x27, 0x17, 0xA0, 0x48, 0x10, 0x4B, 0x72, 0x7E, 0x31, 0x77, 0x12, 0x2A, 0xF2, 0xCE, 0xFB, 0x66, 0xAF, 0xDB, 0xC3, 0x00, 0x42, 0xB4, 0xD6, 0x65, 0x40, 0x92, 0x01, 0xE1, 0x24, 0xC8, 0x80, 0x0C, 0x50, 0xF3, 0x45, 0xED, 0xEF, 0x13, 0x19, 0xF2, 0x46, 0xCF, 0x95, 0x4A, 0x2B, 0x2D, 0x5C, 0x99, 0x2A, 0x2F, 0xD4, 0x83, 0x55, 0xCA, 0x11, 0x57, 0x0A, 0x2D, 0x6C, 0xD7, 0x25, 0x7F, 0x5B, 0xF2, 0xEE, 0x75, 0x1F, 0x27, 0xE0, 0x9C, 0xB5, 0xB9, 0xD5, 0xBB, 0x19, 0xA0, 0x57, 0x71, 0x75, 0x10, 0x6F, 0x72, 0x80, 0x25, 0x19, 0xE0, 0x87, 0x0C, 0xA8, 0x55, 0x7F, 0xD5, 0xDF, 0x71, 0xC4, 0xF7, 0x01, 0x7D, 0xA5, 0x2A, 0xC8, 0xEF, 0x2D, 0x59, 0x80, 0x39, 0x24, 0xD7, 0xC5, 0xA8, 0x7D, 0x51, 0x4B, 0xEC, 0x82, 0xA3, 0x9E, 0x92, 0x57, 0x23, 0xAF, 0xA1, 0x42, 0xBC, 0x59, 0x2F, 0x09, 0xC1, 0x49, 0x45, 0x0A, 0xE7, 0xB9, 0xAA, 0x2B, 0x6A, 0x36, 0x74, 0xEC, 0xDC, 0x63, 0x11, 0x54, 0x41, 0x93, 0x24, 0xCA, 0x38, 0x55, 0xAD, 0x2A, 0x96, 0xFC, 0x95, 0x34, 0x1A, 0x20, 0xB2, 0x0A, 0x64, 0x94, 0x38, 0x59, 0xC5, 0x79, 0xF1, 0xED, 0xE2, 0xFB, 0xBE, 0x19, 0x1D, 0xBF, 0x33, 0xDD, 0x7B, 0xF7, 0x97, 0x01, 0x8A, 0xF4, 0x21, 0x09, 0xC6, 0xC1, 0x9E, 0xC6, 0x2B, 0x07, 0xA8, 0x7C, 0x51, 0xAB, 0x5D, 0x2A, 0xFA, 0xF8, 0xBC, 0x15, 0xF2, 0x34, 0xBA, 0x39, 0x11, 0x35, 0x31, 0xC4, 0x43, 0x0A, 0xE5, 0x51, 0xE5, 0xD7, 0x14, 0x43, 0xAF, 0x7D, 0xA7, 0xB2, 0x0B, 0x51, 0x3C, 0x81, 0xE6, 0x9A, 0xE4, 0xA8, 0x40, 0xE2, 0x6F, 0xCE, 0xE3, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x8C, 0xFD, 0x6D, 0x92, 0x25, 0x3B, 0xCA, 0xB4, 0x8D, 0x4E, 0xA5, 0x46, 0x70, 0x4C, 0x7C, 0xC3, 0xFC, 0x27, 0x76, 0x3A, 0x1C, 0xA9, 0x13, 0xEC, 0x5E, 0xD6, 0xCF, 0xFB, 0xEB, 0xB2, 0x95, 0x3B, 0x77, 0x65, 0x25, 0xA5, 0x50, 0x48, 0xE0, 0x38, 0x63, 0x8E, 0x58, 0x00, 0xDA, 0xE0, 0xFC, 0x65, 0xF7, 0x12, 0xCB, 0xC1, 0xDC, 0x80, 0x7A, 0x57, 0x91, 0x79, 0x72, 0xCB, 0xD5, 0x40, 0xEC, 0x0C, 0x44, 0x02, 0x25, 0xF3, 0x9C, 0x42, 0xDC, 0x48, 0x80, 0x15, 0x10, 0x6E, 0x14, 0xA0, 0x0D, 0x7B, 0xFB, 0x5A, 0x8E, 0x76, 0x6B, 0x3F, 0xF6, 0x85, 0xCB, 0x0C, 0x1E, 0x39, 0x2E, 0x82, 0x7B, 0xA2, 0xB5, 0x03, 0x07, 0x4B, 0xFB, 0x18, 0x2E, 0x07, 0x8E, 0xB3, 0x46, 0x05, 0x97, 0xFE, 0xD0, 0xE5, 0x5B, 0xEC, 0x0C, 0xD1, 0x1A, 0x10, 0x60, 0x0D, 0x5D, 0xEE, 0x36, 0xB2, 0x7A, 0xE8, 0x1A, 0x19, 0xF3, 0x53, 0xC9, 0xEC, 0x57, 0xB4, 0x67, 0x01, 0x37, 0x2F, 0xE7, 0xA1, 0x53, 0xE1, 0xCE, 0x2B, 0xFB, 0xAF, 0x0A, 0xD8, 0xAE, 0xAD, 0xF0, 0xAF, 0xD6, 0x76, 0x5E, 0xCB, 0x30, 0x6F, 0xD0, 0xF6, 0x10, 0x10, 0xF4, 0xC7, 0x0A, 0x2B, 0xB6, 0x35, 0x3C, 0x99, 0x2E, 0x61, 0xD0, 0x08, 0x12, 0x23, 0x11, 0xDD, 0x15, 0x02, 0xFE, 0x3D, 0x74, 0xC6, 0x97, 0xB2, 0x9A, 0x00, 0x73, 0x40, 0xCE, 0xAF, 0xE9, 0x16, 0x0D, 0xAD, 0x1F, 0x6D, 0x6F, 0xBC, 0x27, 0xA1, 0x53, 0x83, 0x1B, 0xCB, 0x76, 0xDC, 0x87, 0x42, 0x12, 0x2B, 0x7B, 0xD8, 0x80, 0x90, 0xAF, 0x54, 0x6D, 0xC3, 0x1A, 0x7E, 0xFE, 0x87, 0x56, 0x81, 0x1B, 0xB9, 0xB4, 0x0A, 0xD6, 0x41, 0x23, 0x5C, 0x9E, 0x4A, 0x6B, 0x0C, 0x6A, 0x8B, 0xB2, 0xEF, 0x0D, 0x1A, 0x9D, 0x50, 0x93, 0x68, 0x45, 0x25, 0x13, 0xFE, 0x7E, 0x95, 0x3F, 0xF4, 0x8F, 0x7B, 0x8C, 0x96, 0xFA, 0xAF, 0x21, 0xB1, 0x3A, 0x05, 0x9A, 0x9E, 0x3F, 0xBA, 0xBD, 0xB6, 0xE5, 0xAC, 0x28, 0x40, 0xF1, 0x2B, 0x68, 0x02, 0xF0, 0x01, 0xDE, 0xBB, 0x63, 0xB5, 0xFC, 0x7A, 0xAC, 0x41, 0x1F, 0x39, 0x43, 0xC8, 0xB1, 0x0E, 0xCD, 0xB5, 0xD2, 0x40, 0xDC, 0xA0, 0xF5, 0x45, 0x03, 0x42, 0x6E, 0xD0, 0x50, 0x84, 0xFA, 0xB6, 0xAA, 0x74, 0x74, 0x74, 0x3A, 0xA1, 0xFB, 0x2E, 0x20, 0xE3, 0xEB, 0x9F, 0xA3, 0x7F, 0xB2, 0x57, 0x4D, 0xAD, 0x95, 0x85, 0x5C, 0xB6, 0xC9, 0xBC, 0xC6, 0x60, 0xE6, 0x4E, 0x07, 0xD1, 0x92, 0x94, 0x9D, 0x3D, 0x47, 0xB6, 0xA1, 0x7B, 0x02, 0xD2, 0x1A, 0xE2, 0xA6, 0x8D, 0x68, 0x2C, 0xCD, 0xA9, 0x0F, 0x53, 0x2E, 0x7B, 0x47, 0x0A, 0x92, 0x79, 0x6C, 0x48, 0x9E, 0xB7, 0x02, 0x22, 0x80, 0x73, 0xED, 0x5B, 0xD4, 0x90, 0x05, 0x03, 0x8C, 0x81, 0xE0, 0x1B, 0x34, 0xDE, 0x8F, 0xE7, 0x70, 0xC8, 0x11, 0xBD, 0x59, 0x48, 0x47, 0x76, 0x94, 0x0A, 0xD9, 0x21, 0xE1, 0x71, 0x69, 0x37, 0xDE, 0xD9, 0x21, 0xA9, 0x59, 0xD3, 0x50, 0x9A, 0x7A, 0x3C, 0xF7, 0x99, 0x7F, 0xF4, 0x58, 0xE6, 0x08, 0xB1, 0xCC, 0x97, 0x56, 0x3F, 0x2A, 0xE9, 0xAF, 0x59, 0xF3, 0x3A, 0x1E, 0xE1, 0x21, 0xA4, 0x1C, 0xD6, 0x1C, 0x45, 0xCB, 0x1D, 0xD1, 0xD6, 0x09, 0x97, 0x1A, 0x05, 0xD4, 0x3E, 0xD3, 0xFA, 0x0C, 0x3A, 0x53, 0x43, 0x01, 0xD1, 0x1B, 0x35, 0xF9, 0xA7, 0x0C, 0xDF, 0xC7, 0xF7, 0xFE, 0xFC, 0x2E, 0xD8, 0x8C, 0xA8, 0xE1, 0x15, 0x70, 0xD4, 0x18, 0x0F, 0x4D, 0x64, 0x3F, 0x81, 0x68, 0xBC, 0x93, 0xDF, 0xE3, 0xAF, 0x5F, 0xBE, 0x75, 0x8F, 0xED, 0x17, 0xC0, 0x1A, 0x7C, 0xE6, 0x96, 0xEE, 0xBE, 0xDD, 0xDB, 0x57, 0xB8, 0x0C, 0x38, 0xFC, 0xBF, 0xE7, 0xA6, 0x2F, 0x43, 0xE0, 0xF4, 0x59, 0x2F, 0x08, 0x59, 0xE5, 0x50, 0xFA, 0x55, 0x94, 0x6B, 0x08, 0x37, 0xA4, 0xA1, 0x0D, 0x5B, 0x9F, 0x0A, 0xB0, 0x17, 0x38, 0x1D, 0xE3, 0x66, 0x28, 0xE9, 0x13, 0x35, 0x39, 0x19, 0xC4, 0xF0, 0xED, 0x9A, 0x1F, 0x6E, 0xC8, 0x98, 0x47, 0x21, 0x9F, 0x1D, 0xD6, 0xA5, 0xA8, 0x7D, 0x9F, 0xA2, 0x1B, 0xB0, 0xA9, 0xEC, 0x4A, 0x02, 0x6C, 0x65, 0xD2, 0x34, 0x66, 0x65, 0x4A, 0x75, 0xD9, 0xAE, 0x2A, 0xE0, 0x0D, 0x49, 0x80, 0xBC, 0x41, 0x0D, 0x5F, 0x35, 0xF6, 0xF8, 0x8B, 0x81, 0x3E, 0xC9, 0x03, 0xDF, 0x07, 0xD0, 0x80, 0xE4, 0x29, 0xE2, 0xE2, 0x00, 0x54, 0x00, 0x33, 0xC0, 0xB9, 0x51, 0x40, 0x38, 0x90, 0x02, 0x94, 0x2E, 0x2D, 0x57, 0xDE, 0xA0, 0xD9, 0x77, 0x85, 0xA5, 0x53, 0xF0, 0x65, 0x22, 0xFA, 0xC4, 0x1C, 0xC9, 0xF5, 0x09, 0x21, 0xC5, 0x21, 0x84, 0x4C, 0xC5, 0xA1, 0x4D, 0x28, 0x5A, 0x43, 0xC4, 0xFD, 0x6C, 0xEE, 0x9E, 0xA8, 0x55, 0xC7, 0x93, 0x46, 0x29, 0x90, 0xEB, 0xED, 0x75, 0xB6, 0x57, 0xAD, 0x2C, 0xD9, 0x0F, 0x5D, 0x4C, 0x11, 0x77, 0xEE, 0x54, 0x6F, 0xCD, 0x2F, 0x96, 0xFD, 0x95, 0xC5, 0x15, 0xF8, 0xB3, 0x01, 0x39, 0x0A, 0x48, 0x02, 0xE6, 0x80, 0x07, 0x10, 0x09, 0x64, 0xAD, 0x1C, 0xC8, 0x69, 0x58, 0x23, 0x57, 0x46, 0x84, 0x00, 0x79, 0x2B, 0xCD, 0xFF, 0xD1, 0x77, 0x3E, 0x72, 0x58, 0x02, 0x57, 0x8D, 0x74, 0x47, 0x85, 0xE3, 0xEE, 0x98, 0x8A, 0xB7, 0xB2, 0x53, 0xAF, 0x97, 0x9A, 0xCA, 0x84, 0x65, 0xC1, 0x22, 0xEF, 0xDA, 0xCB, 0x3C, 0xF7, 0x50, 0x91, 0xF9, 0x37, 0xA5, 0xB5, 0xD1, 0x9C, 0xED, 0x05, 0x4C, 0xC0, 0xF1, 0xD5, 0x43, 0x20, 0x3F, 0xE4, 0x03, 0x46, 0xD3, 0x48, 0x42, 0xF8, 0xAE, 0xE9, 0x99, 0x87, 0xB4, 0x98, 0x69, 0x33, 0x3E, 0x80, 0x18, 0xA0, 0x35, 0xD7, 0x58, 0x9C, 0x86, 0x36, 0x12, 0x48, 0x69, 0x04, 0x50, 0xD2, 0x4B, 0x2D, 0x6E, 0xD4, 0x62, 0xBF, 0x0E, 0xC6, 0xD3, 0xCA, 0xC7, 0x5A, 0x44, 0xD2, 0x7A, 0x8E, 0x36, 0x1F, 0x3D, 0x9E, 0xE3, 0xEA, 0xAE, 0xBA, 0xDE, 0xA1, 0x5E, 0xF3, 0xC6, 0x16, 0x09, 0xA8, 0x4E, 0x31, 0xCA, 0xDD, 0x56, 0x64, 0x49, 0x05, 0xF4, 0xAC, 0x59, 0xB2, 0xB6, 0xE6, 0x1C, 0x79, 0xE3, 0xFC, 0x30, 0x2E, 0x79, 0xCD, 0x6A, 0xF9, 0x97, 0x02, 0xF6, 0x77, 0xDA, 0x17, 0x9D, 0xD9, 0x45, 0xA5, 0x15, 0xA6, 0x02, 0x8A, 0x3B, 0x14, 0x17, 0x5B, 0x41, 0xD9, 0x10, 0x01, 0xD4, 0x00, 0xA3, 0x1B, 0xB4, 0x5C, 0x41, 0xC3, 0x05, 0x9E, 0x0F, 0x54, 0x7D, 0xA4, 0x0E, 0x15, 0xAF, 0x4B, 0x1F, 0x1C, 0xB3, 0xDF, 0xA1, 0x3E, 0xDF, 0xA1, 0xB6, 0xF4, 0x1C, 0x7B, 0xF6, 0x00, 0x37, 0x8E, 0x2E, 0x5B, 0x55, 0x9B, 0xF5, 0x39, 0x59, 0x56, 0x6E, 0x47, 0xD6, 0x98, 0x01, 0x03, 0x24, 0x1B, 0xF4, 0xCB, 0x3A, 0xFB, 0x96, 0x7D, 0x46, 0x85, 0xDC, 0xDF, 0xAE, 0x44, 0x05, 0xD4, 0xCD, 0xA5, 0x29, 0x60, 0x06, 0x04, 0x03, 0xE9, 0x40, 0x71, 0x23, 0x5B, 0x22, 0x7A, 0x0C, 0x20, 0x01, 0x98, 0x00, 0x39, 0x80, 0x52, 0x07, 0xAD, 0xF6, 0x12, 0x1B, 0xA6, 0xF0, 0x22, 0x81, 0x57, 0x68, 0x15, 0xAE, 0x93, 0x9C, 0x38, 0xA8, 0x9A, 0x0E, 0xFD, 0xA8, 0x51, 0xB3, 0xEA, 0xAC, 0x7E, 0x95, 0x5F, 0xCD, 0x99, 0xB2, 0x0D, 0x09, 0x67, 0x7E, 0x64, 0x3C, 0xA6, 0xC3, 0x03, 0x28, 0x73, 0xBA, 0xD4, 0xC9, 0x3D, 0xE7, 0x9F, 0xF9, 0x76, 0x66, 0x5D, 0x33, 0x1B, 0x1B, 0x46, 0xBF, 0x3C, 0xD6, 0xA2, 0xB1, 0xEB, 0xF4, 0xF5, 0xD3, 0x1E, 0x01, 0xB0, 0xC6, 0x36, 0x9F, 0x88, 0xBB, 0xD4, 0x18, 0x56, 0x99, 0x92, 0xBE, 0xA2, 0x86, 0xB6, 0x45, 0x39, 0x77, 0x3A, 0xA0, 0xF4, 0xFD, 0xCE, 0xB1, 0x0C, 0xBA, 0xC6, 0xE2, 0x7B, 0x57, 0xDB, 0x23, 0x3C, 0x75, 0x75, 0x33, 0xE8, 0xEE, 0x5D, 0xAC, 0xED, 0x2F, 0x38, 0x8F, 0xF4, 0xBB, 0xD2, 0x96, 0xAB, 0x83, 0x9A, 0x97, 0x76, 0x80, 0x75, 0x56, 0x99, 0x43, 0x96, 0xEA, 0x23, 0x1A, 0xB4, 0x20, 0x8D, 0x75, 0xC2, 0x8E, 0x8B, 0x68, 0xD8, 0xAF, 0xAE, 0xDC, 0x5A, 0xBA, 0xAE, 0xBA, 0x41, 0x23, 0xAC, 0x2A, 0xA2, 0x15, 0x34, 0x68, 0x3A, 0xF2, 0x14, 0x4E, 0x02, 0xE5, 0x38, 0xB6, 0x56, 0x3F, 0x42, 0xF6, 0xB3, 0x33, 0x8A, 0x80, 0xA2, 0xDD, 0x56, 0xFF, 0xCB, 0x1E, 0x61, 0xCF, 0x81, 0x6F, 0xC4, 0x0D, 0x0C, 0xDF, 0xC3, 0xCA, 0x4C, 0x53, 0x1C, 0x9E, 0x46, 0x88, 0x46, 0xB3, 0x77, 0x87, 0x72, 0x96, 0x43, 0xC3, 0x57, 0xDF, 0xBF, 0x2F, 0xEC, 0xB9, 0xA7, 0x0E, 0x44, 0xAD, 0xC9, 0x24, 0xD9, 0xB0, 0x2D, 0x86, 0x5B, 0xEF, 0xEB, 0xBC, 0x41, 0x63, 0xCC, 0x1E, 0x53, 0xDE, 0x41, 0x43, 0x3F, 0xB6, 0x47, 0xA7, 0x16, 0x19, 0x49, 0x3A, 0x56, 0x08, 0x2C, 0x96, 0x0B, 0xA4, 0xC6, 0x0A, 0x5A, 0xD6, 0xBA, 0x82, 0x36, 0x74, 0xDD, 0xDB, 0xF7, 0x78, 0x7E, 0x66, 0x20, 0x9F, 0x6A, 0x60, 0x1E, 0xD0, 0xBD, 0x00, 0x5B, 0x1E, 0x62, 0x7A, 0x66, 0x35, 0x46, 0xD6, 0xC5, 0xF2, 0xF8, 0xB6, 0xD4, 0x6D, 0x50, 0x43, 0x1A, 0xBE, 0x0C, 0xD0, 0x12, 0x60, 0x5F, 0x10, 0x80, 0xAA, 0xB1, 0xBE, 0x28, 0x6F, 0xA5, 0xA1, 0x5C, 0xA0, 0x8E, 0x1A, 0x0B, 0x47, 0x8E, 0xBE, 0xC5, 0xC3, 0x8C, 0x13, 0xA8, 0x7D, 0xB0, 0x20, 0x41, 0x58, 0x7C, 0x8D, 0x6F, 0xF3, 0x2D, 0x21, 0xDD, 0x4F, 0x46, 0xCD, 0x4F, 0x9C, 0xEB, 0xF1, 0xB4, 0xF9, 0x3C, 0x53, 0x4D, 0x75, 0x9B, 0xCB, 0x1A, 0x95, 0xD7, 0x70, 0x07, 0x6C, 0x37, 0xE1, 0x08, 0xA0, 0xAB, 0xA6, 0x9F, 0xB1, 0x3A, 0xC1, 0xF4, 0x87, 0x95, 0x05, 0xF3, 0x4A, 0xEF, 0xD2, 0x0F, 0x48, 0x35, 0x72, 0x89, 0x9A, 0xDF, 0x4A, 0x6B, 0xF5, 0x90, 0xFC, 0x19, 0x40, 0x1E, 0x1C, 0x36, 0x32, 0xBE, 0x6D, 0x0F, 0x92, 0x25, 0x14, 0x8C, 0xBD, 0x2A, 0xF1, 0xE4, 0x45, 0x0D, 0xFB, 0x64, 0x3F, 0xCB, 0x6F, 0x94, 0x74, 0x76, 0xE9, 0xB2, 0x37, 0x0E, 0x70, 0xE4, 0xD7, 0xB8, 0x85, 0x03, 0x94, 0x4C, 0x8B, 0x21, 0xF2, 0xF5, 0xB7, 0xD7, 0xA9, 0x86, 0xAF, 0x95, 0x3D, 0xD7, 0x6A, 0x10, 0x20, 0xD1, 0xB0, 0x05, 0x9F, 0x51, 0xD6, 0xB3, 0x8E, 0x7B, 0xB6, 0x9B, 0x98, 0x17, 0x64, 0x22, 0xA8, 0xE1, 0x37, 0x68, 0xF6, 0x4F, 0xD0, 0x91, 0xF3, 0x4F, 0xCE, 0x7F, 0x80, 0xD4, 0x90, 0xBB, 0xA2, 0x30, 0xA5, 0x85, 0x9A, 0x88, 0x76, 0xA6, 0x4E, 0x7A, 0xC3, 0xB0, 0xCE, 0x7B, 0xFF, 0x6E, 0x8E, 0x22, 0x9A, 0x72, 0x4C, 0x89, 0x86, 0x02, 0xE4, 0xEB, 0xA8, 0xEF, 0x8D, 0xFA, 0x5B, 0x32, 0xFA, 0x34, 0xC1, 0xB6, 0x2A, 0x5A, 0xD5, 0x08, 0x5F, 0xE3, 0xB9, 0xAA, 0x61, 0x80, 0x1D, 0x20, 0x57, 0x0D, 0x94, 0x03, 0x90, 0x04, 0xD4, 0x01, 0x13, 0xC0, 0x15, 0x88, 0x02, 0xEA, 0x4C, 0x64, 0x35, 0x72, 0xA2, 0x5E, 0xB5, 0xF4, 0x46, 0xCD, 0x11, 0xAE, 0x8A, 0x7F, 0xFC, 0xFD, 0x0B, 0xFE, 0x3D, 0x9F, 0x5F, 0x32, 0xDA, 0x91, 0x3B, 0xC8, 0xEC, 0xB5, 0xCC, 0xC8, 0x2B, 0x58, 0x6C, 0x97, 0xA1, 0x3D, 0xD3, 0x7F, 0x65, 0x6B, 0x95, 0xD7, 0x76, 0xB6, 0x8C, 0xA0, 0x53, 0x1B, 0x36, 0x73, 0x4B, 0xC4, 0xB3, 0x58, 0x67, 0xD9, 0x08, 0x40, 0x57, 0x17, 0x00, 0x5F, 0xAC, 0xCE, 0x29, 0x93, 0x55, 0x39, 0x69, 0x64, 0x00, 0xC5, 0x3F, 0x9C, 0x4B, 0x28, 0x01, 0xF6, 0x46, 0x00, 0x72, 0x96, 0xF0, 0x9B, 0x96, 0x25, 0xCB, 0x8B, 0x5A, 0xA0, 0x21, 0x4A, 0xCE, 0x28, 0x50, 0xA5, 0x22, 0xFD, 0x4D, 0x56, 0x7D, 0xB4, 0x37, 0xDC, 0x8E, 0xA8, 0x6B, 0x4E, 0xEE, 0x2F, 0x0B, 0xF9, 0x31, 0x57, 0xC7, 0xE7, 0x9E, 0xB5, 0x90, 0x05, 0xD4, 0xBA, 0x14, 0xF8, 0x92, 0xBD, 0xAA, 0xCC, 0x1C, 0xB5, 0xE6, 0x54, 0x66, 0x78, 0x4D, 0x58, 0x02, 0xBA, 0x26, 0x32, 0x52, 0x34, 0xA4, 0xC1, 0x0B, 0xD2, 0xF0, 0x46, 0xAD, 0x54, 0x8F, 0x00, 0x7A, 0x91, 0x80, 0xD1, 0xAF, 0x72, 0x5E, 0x00, 0xEE, 0x40, 0xD8, 0x0D, 0x5A, 0x7E, 0x4E, 0xAD, 0x44, 0xF5, 0x82, 0xE6, 0xDF, 0xC3, 0xA8, 0x68, 0xF5, 0x11, 0xC6, 0xA3, 0x90, 0x8A, 0xBF, 0x26, 0x12, 0x1E, 0x96, 0x96, 0x63, 0x57, 0x33, 0xDA, 0xD9, 0xC8, 0xB8, 0x17, 0xC7, 0x1F, 0x4A, 0x27, 0xFE, 0x55, 0xF3, 0xED, 0x4F, 0xEF, 0x06, 0x96, 0x35, 0x6F, 0xC8, 0xC1, 0x80, 0xC5, 0xAC, 0xC8, 0x7B, 0x83, 0x62, 0xE6, 0xF0, 0x7D, 0x65, 0xFB, 0xCD, 0x1B, 0xD2, 0xD0, 0x5F, 0xCA, 0xA3, 0x46, 0x2A, 0x50, 0xD2, 0xE0, 0xF9, 0x29, 0x6B, 0xA2, 0xEE, 0x8F, 0xD5, 0x1B, 0xB4, 0xFA, 0xF2, 0x6A, 0x9E, 0xFB, 0xD0, 0xD1, 0x42, 0xD2, 0x43, 0x78, 0x15, 0x24, 0xA3, 0x38, 0xCB, 0x8E, 0xE7, 0xC9, 0xAD, 0xF3, 0x69, 0xBB, 0x58, 0xE0, 0x40, 0x9D, 0x79, 0xFC, 0x57, 0x5B, 0x2D, 0x18, 0xB1, 0xEA, 0x26, 0xA7, 0x41, 0xB3, 0x0B, 0x81, 0x96, 0x5A, 0xC8, 0xB3, 0x61, 0x80, 0x32, 0x40, 0xBC, 0xFA, 0x95, 0x05, 0x30, 0xFD, 0xDD, 0xE7, 0x04, 0xF8, 0xBE, 0xEB, 0x37, 0x6A, 0x99, 0xB6, 0xEA, 0x2F, 0x48, 0xC3, 0x80, 0x64, 0xE0, 0x9D, 0xD4, 0xE4, 0x7C, 0x6A, 0xC8, 0x74, 0xF9, 0x1A, 0xF2, 0xCE, 0x9F, 0xA7, 0x7E, 0xD8, 0xF5, 0xEB, 0xB6, 0x5B, 0x6E, 0x27, 0xC7, 0xBD, 0xEA, 0x70, 0x57, 0x58, 0xF6, 0xE3, 0xB9, 0x4F, 0xFA, 0xE6, 0x4B, 0xFB, 0xB9, 0x52, 0xDC, 0x64, 0x3F, 0x66, 0xCB, 0xBF, 0x01, 0x27, 0x7E, 0xA3, 0xF5, 0x63, 0x0A, 0xA3, 0x39, 0x40, 0xB9, 0x3A, 0xDB, 0x2F, 0x68, 0x8D, 0xA6, 0x38, 0x0D, 0x69, 0x24, 0x50, 0xB4, 0xF4, 0xF2, 0xB2, 0xA6, 0x82, 0xFB, 0x82, 0x02, 0x14, 0x3F, 0x4E, 0x6A, 0x7A, 0x6E, 0xD0, 0xDE, 0x65, 0x00, 0x62, 0x0F, 0x15, 0x3C, 0xAC, 0xEE, 0xDF, 0xFB, 0x33, 0x4D, 0x5A, 0x32, 0x52, 0xFF, 0x81, 0xA9, 0x21, 0x59, 0x24, 0x64, 0xAD, 0x24, 0xDD, 0xA6, 0xA3, 0x34, 0x8D, 0x94, 0x89, 0xA6, 0x18, 0x47, 0x1B, 0x7C, 0xD3, 0xF5, 0x09, 0x24, 0x03, 0xB1, 0x24, 0x3D, 0xD9, 0xD7, 0xEC, 0xE4, 0x95, 0x6A, 0x38, 0x0D, 0x69, 0x24, 0xA0, 0x04, 0x98, 0x02, 0xF1, 0x1A, 0x32, 0x15, 0xD0, 0x86, 0x1B, 0x90, 0xD4, 0x28, 0xA0, 0xF2, 0x7C, 0xB6, 0xAA, 0xA7, 0x41, 0x01, 0xB0, 0x34, 0x12, 0x10, 0x05, 0x94, 0x1B, 0x05, 0x98, 0x03, 0x9E, 0x1D, 0x34, 0x86, 0x2F, 0x61, 0xEE, 0x7C, 0x07, 0x1A, 0x57, 0x32, 0xB0, 0xC4, 0x38, 0x15, 0x91, 0x0F, 0xC6, 0xB5, 0xD8, 0x63, 0x8A, 0xE3, 0x65, 0xA7, 0xBD, 0x43, 0xD6, 0xBD, 0x3C, 0x57, 0xA2, 0x3B, 0x96, 0x67, 0x4E, 0x35, 0x1C, 0x98, 0x35, 0x77, 0x1C, 0x9D, 0xC6, 0xBE, 0xC7, 0xD4, 0xF0, 0x46, 0x01, 0x42, 0x8D, 0xFA, 0xA5, 0x3D, 0xD6, 0x55, 0xA9, 0xF3, 0x55, 0xA9, 0x5B, 0x37, 0xDB, 0xB2, 0xD5, 0x4E, 0xAC, 0x00, 0x71, 0xC3, 0x00, 0x96, 0xF5, 0x32, 0x7D, 0xCF, 0xA7, 0x74, 0xB8, 0x90, 0x03, 0x16, 0xCB, 0xEF, 0xF5, 0x79, 0x94, 0xBE, 0x0A, 0xE8, 0x91, 0xC0, 0xFD, 0x44, 0xBD, 0x11, 0xFD, 0xCC, 0xD1, 0x94, 0xF8, 0xF9, 0xEE, 0x91, 0xDA, 0xD3, 0x6B, 0xCD, 0x1B, 0xB4, 0x44, 0xC8, 0xB5, 0x24, 0xDE, 0x0A, 0x94, 0x2E, 0x77, 0x8A, 0x02, 0xB2, 0x7E, 0x5D, 0x82, 0x4E, 0x43, 0xD6, 0x59, 0x3F, 0xB7, 0x7E, 0x7B, 0x05, 0x8F, 0x76, 0x57, 0xFB, 0xEE, 0x9B, 0x6C, 0x68, 0x23, 0x67, 0xF0, 0x4E, 0xFD, 0x08, 0x9E, 0xF0, 0x8D, 0x9A, 0xBE, 0xA8, 0x89, 0x7F, 0x87, 0x59, 0xF8, 0x2A, 0x9F, 0xF8, 0x2E, 0xED, 0x5A, 0xF9, 0xBD, 0x38, 0x4B, 0x19, 0xC5, 0xE7, 0xB0, 0xCE, 0x0A, 0xC8, 0xCC, 0x0F, 0xF1, 0xB6, 0x4C, 0xE0, 0x95, 0xCB, 0x0E, 0x9A, 0xA7, 0x6E, 0x6D, 0x50, 0x4E, 0x53, 0x9C, 0x5A, 0x6D, 0x2B, 0x65, 0x73, 0x58, 0xEF, 0xB9, 0x38, 0x0D, 0x5A, 0x87, 0x2C, 0x02, 0xE4, 0xCC, 0x6B, 0x7E, 0x5C, 0x59, 0x68, 0x3F, 0xE7, 0xE4, 0x2B, 0x55, 0xAB, 0x2B, 0x07, 0x49, 0x2B, 0x07, 0x59, 0x2B, 0x07, 0x49, 0x6B, 0x63, 0xF0, 0x95, 0x8A, 0xB4, 0x1B, 0x35, 0xFB, 0xC2, 0xF5, 0xAD, 0x27, 0xFB, 0x2E, 0x51, 0xF3, 0x5D, 0x40, 0x92, 0x78, 0x73, 0xA9, 0xF5, 0x16, 0xA9, 0x78, 0xFF, 0x25, 0x8D, 0x5B, 0x7B, 0xD4, 0x73, 0x90, 0x9D, 0x77, 0x71, 0x5F, 0xE9, 0x46, 0x27, 0x40, 0x19, 0x60, 0x59, 0x66, 0x43, 0x05, 0xC8, 0x12, 0xB3, 0xD7, 0xDA, 0x8D, 0x8F, 0x2C, 0x6B, 0x5C, 0x5B, 0xC6, 0x24, 0xEB, 0x40, 0x1C, 0xEB, 0x9C, 0x6A, 0x8D, 0x68, 0x64, 0xA3, 0x64, 0x56, 0xEC, 0xF8, 0x34, 0x6A, 0xB5, 0x68, 0x13, 0xC0, 0x39, 0x21, 0x05, 0x98, 0xDF, 0xA0, 0xF9, 0xF7, 0xE6, 0xCC, 0xA3, 0xDF, 0xAD, 0xFD, 0x1C, 0xFD, 0x64, 0x6B, 0xE2, 0x3D, 0x3A, 0x24, 0x0D, 0x3F, 0x47, 0x3F, 0xA4, 0x99, 0xE3, 0x0A, 0x56, 0x3C, 0x6E, 0xED, 0x76, 0xB6, 0x69, 0x37, 0xCD, 0xAD, 0xA7, 0xBC, 0xB1, 0x4D, 0x31, 0x6D, 0x25, 0x14, 0x14, 0x90, 0xF5, 0x68, 0x84, 0x01, 0xA5, 0x40, 0xF8, 0x3A, 0x87, 0x1D, 0x40, 0x62, 0xC2, 0x63, 0x4E, 0x29, 0xF4, 0x5C, 0x35, 0x62, 0xFB, 0x21, 0x71, 0x51, 0x07, 0x9C, 0x81, 0x90, 0x86, 0x35, 0x7C, 0x7D, 0x51, 0x81, 0xEB, 0x3A, 0x70, 0xDE, 0xF3, 0xF9, 0xD7, 0x56, 0xF0, 0x9D, 0x1A, 0xBA, 0x51, 0xAA, 0x0B, 0xC7, 0xA7, 0x4D, 0x4C, 0x98, 0x14, 0x9B, 0x4A, 0x5B, 0xDE, 0x4A, 0xDC, 0x95, 0xB6, 0x2B, 0x79, 0xBC, 0x4C, 0xE7, 0x7C, 0xAD, 0xAD, 0x2D, 0xA3, 0xE2, 0x1F, 0xD3, 0x6D, 0xCB, 0xA6, 0x03, 0x29, 0x37, 0xCC, 0x1B, 0x09, 0x38, 0x35, 0xB4, 0x11, 0xAB, 0x8F, 0xAC, 0x61, 0x2B, 0xF4, 0x22, 0x80, 0x35, 0x5C, 0x81, 0xE0, 0xA5, 0x8C, 0x3C, 0x5B, 0x62, 0xD5, 0xD8, 0x17, 0x8D, 0x58, 0x97, 0xD9, 0xB7, 0xD2, 0xA6, 0x5B, 0x02, 0x2B, 0x7D, 0x89, 0x0F, 0x12, 0xFB, 0xD2, 0x93, 0xAA, 0xF9, 0xFD, 0x1B, 0x95, 0x10, 0x6A, 0x60, 0x24, 0xB8, 0xFA, 0xB8, 0x0E, 0xE1, 0xB2, 0xC7, 0x0D, 0x5A, 0xAC, 0xF2, 0x67, 0xAE, 0xD1, 0xEA, 0x0C, 0xB8, 0x00, 0x42, 0xC0, 0xE1, 0x39, 0x8D, 0xB7, 0x56, 0x5B, 0x6F, 0xE4, 0xFC, 0x95, 0x92, 0x1B, 0xB4, 0xA4, 0x3C, 0x4B, 0x8A, 0xEB, 0x34, 0x37, 0x33, 0xCD, 0x5B, 0x3F, 0x02, 0x94, 0x01, 0x3F, 0xAB, 0x44, 0x60, 0x40, 0xF9, 0xAD, 0x0D, 0x70, 0x23, 0x00, 0x52, 0x80, 0xA9, 0x91, 0x80, 0x04, 0x60, 0xD4, 0x41, 0xEB, 0xBE, 0x82, 0x8C, 0x2F, 0x21, 0xA9, 0x05, 0xA7, 0x56, 0x57, 0xED, 0x01, 0x95, 0x98, 0xE8, 0xDF, 0x32, 0x6F, 0xBD, 0x0E, 0xFB, 0x11, 0xBE, 0xC4, 0x30, 0x2B, 0x68, 0x14, 0xB3, 0xC9, 0x57, 0x08, 0xA0, 0x5A, 0x62, 0x3E, 0x5A, 0xA9, 0xDD, 0x86, 0x2F, 0x83, 0x9B, 0x38, 0xEB, 0xE0, 0x5F, 0x8D, 0x95, 0x38, 0x8B, 0xB3, 0xE6, 0x44, 0x74, 0x40, 0x55, 0xEF, 0x72, 0x98, 0x8F, 0x27, 0xD7, 0xD2, 0x67, 0x38, 0xE0, 0xB5, 0x94, 0xF2, 0xA7, 0xA1, 0x0D, 0x7F, 0x4F, 0x22, 0xA0, 0x00, 0x31, 0xF0, 0x34, 0xB8, 0x3A, 0xBD, 0x4C, 0x3C, 0xE9, 0xF3, 0xED, 0xB3, 0xB6, 0xD8, 0x37, 0x27, 0xAC, 0x53, 0x31, 0x24, 0x6B, 0x8C, 0x71, 0x23, 0xE1, 0x33, 0x14, 0x0A, 0x66, 0x5B, 0x4D, 0x2A, 0x67, 0x5A, 0x46, 0x99, 0x37, 0x18, 0x90, 0xC6, 0xC9, 0x65, 0x35, 0xE1, 0xF3, 0x54, 0xE6, 0xB5, 0xB6, 0xAA, 0x04, 0x82, 0x1A, 0xDC, 0xD8, 0xB6, 0xF8, 0x67, 0x3E, 0x44, 0xB6, 0x73, 0x39, 0x04, 0x88, 0x03, 0xDA, 0x30, 0x59, 0x73, 0x5F, 0xA4, 0x11, 0x33, 0x86, 0xE9, 0x2B, 0x86, 0x35, 0xEB, 0x81, 0x7C, 0x6E, 0xD4, 0x08, 0x51, 0x6B, 0x41, 0x24, 0xF3, 0xDC, 0xD4, 0xDC, 0xFB, 0x06, 0x4E, 0x28, 0xAF, 0x70, 0x8B, 0xD5, 0xA8, 0x6C, 0xB6, 0xFD, 0x3C, 0x3F, 0xB0, 0x46, 0xF1, 0x12, 0xC8, 0xEE, 0xFB, 0xA7, 0xFE, 0xDA, 0xD4, 0x08, 0xC8, 0xD5, 0xD8, 0xEF, 0xAB, 0x47, 0x3D, 0xBC, 0x61, 0xC0, 0xCF, 0x4A, 0xBB, 0xD0, 0x1C, 0xE9, 0xE1, 0xEB, 0x90, 0xC2, 0x0E, 0x48, 0x02, 0x5A, 0xEB, 0x0A, 0x1F, 0x40, 0x48, 0x23, 0x80, 0xD4, 0x75, 0x5B, 0xD7, 0x69, 0x89, 0x72, 0xC7, 0x84, 0x8C, 0x12, 0x41, 0x61, 0xEE, 0xC0, 0xB4, 0x88, 0x27, 0xC3, 0xCD, 0xCD, 0x12, 0x07, 0x76, 0x85, 0xFD, 0xA8, 0x3A, 0x8F, 0x9A, 0xB1, 0xCB, 0x96, 0x45, 0xD2, 0x6A, 0x02, 0x8E, 0x15, 0xB4, 0x35, 0x01, 0x2B, 0x18, 0xB0, 0x6A, 0x18, 0xE0, 0x8D, 0x90, 0xA5, 0xFE, 0x63, 0x40, 0xF2, 0xC7, 0x08, 0x67, 0xA7, 0xD5, 0x3F, 0xD9, 0xF1, 0xA1, 0x98, 0x79, 0xA1, 0x38, 0xEB, 0x65, 0xCA, 0xAB, 0xFD, 0x67, 0x37, 0xBB, 0x9C, 0x46, 0xFD, 0xEA, 0x79, 0x21, 0xA0, 0xE4, 0x06, 0x4D, 0x3A, 0x68, 0xB8, 0xBB, 0x57, 0xD8, 0x28, 0xAF, 0x50, 0x51, 0x5B, 0x72, 0x10, 0xA4, 0x6E, 0xA1, 0x48, 0x35, 0x96, 0x5E, 0x95, 0xF7, 0xCE, 0x74, 0x2C, 0xE7, 0xEE, 0xE5, 0xE3, 0xAC, 0xF9, 0xCB, 0xAD, 0xCF, 0x80, 0x7C, 0x5F, 0x04, 0x7C, 0x0D, 0xD9, 0xB2, 0x25, 0x83, 0x97, 0x00, 0x54, 0x1A, 0xCB, 0xED, 0x5A, 0xEE, 0x8A, 0xE1, 0x8E, 0x0F, 0x22, 0xF2, 0xE4, 0x05, 0x72, 0x00, 0x13, 0xC0, 0x0B, 0x48, 0x5E, 0x9A, 0x03, 0x6A, 0x04, 0x40, 0x02, 0xF0, 0x69, 0xE4, 0x3A, 0xE4, 0xBE, 0x4D, 0x4D, 0x5F, 0xD0, 0xFC, 0xFB, 0x1F, 0x66, 0xFA, 0x96, 0x0B, 0xA7, 0x5B, 0x15, 0x83, 0xA4, 0xA2, 0x0A, 0x42, 0x3B, 0x42, 0xB0, 0xCE, 0x9E, 0x4C, 0x46, 0x2B, 0x06, 0x5A, 0x33, 0x76, 0xCA, 0xDB, 0x38, 0x61, 0x99, 0xD2, 0x5E, 0xDC, 0xD8, 0x31, 0xA0, 0xD1, 0x28, 0x40, 0xBC, 0xC1, 0x2B, 0xF3, 0x34, 0x0C, 0x1D, 0xE5, 0xF5, 0x9B, 0xD9, 0x68, 0xFB, 0x40, 0x26, 0x71, 0xC8, 0x5B, 0x98, 0xE7, 0xDA, 0x32, 0x02, 0x9C, 0x1B, 0x05, 0x84, 0x01, 0x49, 0x8D, 0x5A, 0xEF, 0x85, 0x06, 0xF9, 0x0D, 0x9A, 0x8D, 0x9E, 0x32, 0x3D, 0x73, 0x54, 0xC8, 0xC9, 0x3E, 0x5D, 0x72, 0xA2, 0x9A, 0x93, 0x85, 0xDD, 0x27, 0x79, 0xF4, 0xFD, 0x58, 0xFD, 0xAF, 0x95, 0xC6, 0xBF, 0x6A, 0x52, 0x2F, 0xBC, 0x8D, 0x9D, 0x5A, 0xCB, 0x55, 0xBE, 0xAC, 0x19, 0x26, 0xA1, 0x46, 0x02, 0x3A, 0x3C, 0x9B, 0x7B, 0xC1, 0xBD, 0x95, 0x16, 0xAF, 0x47, 0x87, 0x0E, 0x90, 0x57, 0x73, 0xC0, 0x0C, 0xA8, 0x00, 0xCE, 0x40, 0x18, 0x90, 0x0A, 0x14, 0x35, 0xA2, 0x93, 0x21, 0x0D, 0x72, 0x80, 0x1B, 0xA2, 0x1D, 0x34, 0x7F, 0x41, 0x73, 0xE9, 0x46, 0x63, 0xB8, 0x61, 0xE1, 0xE8, 0x41, 0x78, 0x3C, 0x55, 0x0B, 0x2F, 0x3F, 0x93, 0x2E, 0x8E, 0xD8, 0x10, 0xC8, 0x8B, 0xEE, 0x3B, 0x3B, 0xDF, 0xFB, 0xCD, 0xEA, 0x83, 0xE0, 0x35, 0xA2, 0xD5, 0x14, 0xE0, 0xD5, 0x88, 0x5D, 0xAB, 0xE1, 0x58, 0x1A, 0x6C, 0xC0, 0xC9, 0x86, 0xEC, 0xFE, 0xE1, 0x59, 0x96, 0xB9, 0xC2, 0x38, 0xF5, 0x99, 0x73, 0xF2, 0x75, 0x5C, 0x90, 0x00, 0x8C, 0x01, 0xF7, 0xA5, 0x49, 0x53, 0xA0, 0x4E, 0xC3, 0xE7, 0xCD, 0x94, 0x4E, 0x23, 0x01, 0x7E, 0x4B, 0x6D, 0xA9, 0x87, 0x96, 0xA6, 0x23, 0x8F, 0xE2, 0xCA, 0x8C, 0x96, 0x76, 0x96, 0x3C, 0xFD, 0x7C, 0xE6, 0x50, 0x27, 0x7C, 0x98, 0xE9, 0xDB, 0x5C, 0x02, 0x79, 0xFD, 0x35, 0x3C, 0x91, 0x7F, 0x59, 0x23, 0x07, 0x10, 0x8D, 0x14, 0xC0, 0xF5, 0x7F, 0x08, 0x61, 0x18, 0xF0, 0x31, 0xA5, 0x51, 0x5F, 0x13, 0x64, 0x76, 0x60, 0xB8, 0xE6, 0x6F, 0xAD, 0x01, 0xC4, 0x5E, 0x7F, 0x87, 0x1B, 0x05, 0x90, 0x03, 0xAC, 0x80, 0x70, 0x23, 0x01, 0x0D, 0xC0, 0xB2, 0x83, 0x96, 0x2F, 0x68, 0x3B, 0x76, 0x29, 0x5F, 0x80, 0xF0, 0x2A, 0x96, 0x42, 0x93, 0x95, 0x11, 0x9E, 0xC0, 0xA0, 0x96, 0x72, 0xEC, 0xF4, 0xAD, 0x01, 0x25, 0x6B, 0xCB, 0xB1, 0x5F, 0x5E, 0x26, 0xB2, 0x8C, 0x81, 0xCF, 0xDC, 0x9C, 0xA2, 0x66, 0x2A, 0xA6, 0x6A, 0xDD, 0xAB, 0x57, 0xE5, 0x45, 0x14, 0xD0, 0x86, 0x9D, 0xA5, 0xE0, 0xA3, 0x55, 0x10, 0xE1, 0xA5, 0xE7, 0x13, 0xA0, 0xB8, 0x51, 0xBF, 0xF4, 0x7C, 0x0A, 0xF0, 0x69, 0x38, 0x20, 0xD2, 0xA8, 0xBB, 0xD2, 0x6A, 0x07, 0x6D, 0xBC, 0x3E, 0x55, 0x02, 0x93, 0xE7, 0x2D, 0xDB, 0x62, 0xCF, 0x91, 0x98, 0xF0, 0x9C, 0xAD, 0x18, 0xD2, 0x2C, 0x3B, 0xF3, 0xC4, 0xA5, 0xBB, 0x5D, 0x5F, 0x96, 0xA6, 0x63, 0x85, 0x8B, 0x05, 0x78, 0xD7, 0xFA, 0xFE, 0x65, 0x5E, 0x6F, 0x74, 0xFC, 0xDA, 0x8C, 0xA9, 0xE1, 0x00, 0xE7, 0x7C, 0xF8, 0xD4, 0xD7, 0x33, 0x78, 0x1A, 0x09, 0x84, 0x01, 0x29, 0xBF, 0x5E, 0x9C, 0x05, 0x90, 0x34, 0x0A, 0xE0, 0x00, 0x44, 0x57, 0xDF, 0xA3, 0x76, 0xD4, 0xEC, 0xC0, 0xA6, 0x89, 0x77, 0xD4, 0x90, 0x1D, 0x12, 0x0B, 0xD4, 0xC5, 0xFC, 0x43, 0x95, 0x71, 0x2F, 0x98, 0xF5, 0x7C, 0xCA, 0xEA, 0x6A, 0x3F, 0xF4, 0x6B, 0x5C, 0xC8, 0x3E, 0xB7, 0x59, 0x63, 0x58, 0x14, 0xC9, 0x3B, 0x83, 0xBE, 0x6E, 0x6A, 0x99, 0x82, 0x59, 0xF2, 0x8E, 0x1D, 0x01, 0xA6, 0xC0, 0x3D, 0x8D, 0x55, 0x23, 0xBD, 0x21, 0x40, 0x64, 0x23, 0x7E, 0x8D, 0x6B, 0x8B, 0x79, 0x2E, 0x39, 0x05, 0x90, 0x37, 0xA2, 0x51, 0x8D, 0x9C, 0x9F, 0xD8, 0xD6, 0x52, 0x33, 0xFA, 0x9A, 0x3E, 0x49, 0x77, 0xD0, 0xD0, 0xCD, 0x58, 0x07, 0xF7, 0xCE, 0x60, 0x45, 0x47, 0x1A, 0x25, 0x44, 0x18, 0xEE, 0xC3, 0xBB, 0x75, 0x8D, 0x0F, 0x1C, 0x99, 0x8E, 0xE5, 0xB9, 0x2D, 0xB1, 0xBC, 0x4A, 0x76, 0x8B, 0x98, 0xCE, 0x07, 0xF4, 0x8D, 0xD1, 0xBB, 0x29, 0x87, 0xBA, 0x98, 0x49, 0x31, 0x53, 0x80, 0x69, 0xCD, 0xA9, 0x60, 0x20, 0xAB, 0x61, 0x0B, 0xB1, 0x33, 0xB5, 0x2B, 0xBF, 0x6D, 0x00, 0x6B, 0xC3, 0x1B, 0xB6, 0x10, 0x2B, 0x6D, 0x72, 0x6E, 0xD4, 0xF8, 0x85, 0x0B, 0x3D, 0xD9, 0xFC, 0xF9, 0x76, 0x30, 0x63, 0x06, 0xD2, 0x49, 0x42, 0x6F, 0x95, 0x75, 0x56, 0xC9, 0x6F, 0x9D, 0x2B, 0xE6, 0xDC, 0x28, 0x5F, 0x35, 0x63, 0x7B, 0xEF, 0xB3, 0x1F, 0x23, 0x3B, 0xB4, 0x21, 0x04, 0xB0, 0x34, 0x1C, 0x78, 0x59, 0x1B, 0x99, 0xD5, 0x96, 0x38, 0x40, 0xEA, 0x3A, 0x3A, 0xC9, 0x7A, 0x68, 0x0D, 0x20, 0x5B, 0x4F, 0x6B, 0x43, 0x7D, 0x1D, 0x6C, 0xA9, 0x11, 0xEB, 0xC5, 0x69, 0x8D, 0x02, 0x8A, 0xA7, 0x88, 0xF2, 0x48, 0xA3, 0xD6, 0xFB, 0x33, 0x6E, 0xD0, 0x04, 0x47, 0x10, 0x37, 0xD8, 0x4D, 0xC8, 0xDF, 0xF3, 0x89, 0x94, 0x35, 0xF2, 0x42, 0x4E, 0xD8, 0x67, 0xCD, 0x51, 0xAB, 0x13, 0xC7, 0xA9, 0xE3, 0xB7, 0x26, 0x32, 0x63, 0xCB, 0xFB, 0xE6, 0x27, 0x66, 0xE0, 0x54, 0xE3, 0x34, 0x02, 0xB8, 0x79, 0x8C, 0xBA, 0xCB, 0x89, 0xD6, 0x4B, 0xC0, 0x1B, 0xB1, 0xB0, 0xEA, 0xEE, 0xF7, 0x4C, 0xAA, 0x35, 0xF7, 0x3F, 0x55, 0xC0, 0xFD, 0x57, 0xB2, 0x5B, 0x01, 0x0A, 0x80, 0x1D, 0x10, 0x6A, 0x18, 0xA0, 0xA7, 0xE1, 0x4B, 0x81, 0x4A, 0x37, 0x6A, 0xFA, 0x96, 0x9A, 0x7E, 0x6B, 0x84, 0xC7, 0x01, 0x37, 0x0E, 0xC3, 0x79, 0xD0, 0x19, 0x7F, 0x4D, 0x32, 0x3C, 0xA0, 0x3D, 0x73, 0xD1, 0x7F, 0x47, 0xAD, 0x68, 0x45, 0xAD, 0xA1, 0xDB, 0x84, 0x28, 0x7F, 0x4C, 0xF7, 0x7E, 0xD3, 0xF8, 0x6D, 0x9A, 0x6B, 0x32, 0x37, 0xCE, 0x42, 0x2C, 0x0D, 0x4C, 0xAE, 0x21, 0xAC, 0xDA, 0x21, 0x39, 0x40, 0xDE, 0x94, 0x99, 0x18, 0x60, 0x05, 0x84, 0x03, 0xC5, 0x7D, 0x8A, 0x55, 0x80, 0x04, 0xE0, 0xB3, 0x0E, 0xB3, 0x06, 0x68, 0x00, 0x66, 0x80, 0x57, 0x47, 0xCD, 0x5E, 0xD4, 0xB8, 0x90, 0x8A, 0xFC, 0xBB, 0x4B, 0x51, 0x0B, 0x88, 0x82, 0xBA, 0xC2, 0x15, 0xED, 0x45, 0xE7, 0x3E, 0xA2, 0xE5, 0xBA, 0xA3, 0x96, 0xF6, 0x63, 0x3E, 0xA0, 0xE8, 0xCA, 0x75, 0x24, 0x90, 0x71, 0xF1, 0x4B, 0x0A, 0x13, 0x80, 0x1B, 0x10, 0xA7, 0x21, 0xAB, 0x18, 0xC7, 0xB3, 0x19, 0x58, 0x64, 0xE6, 0x25, 0x34, 0x80, 0xB4, 0xE5, 0x97, 0x50, 0x80, 0x1C, 0x40, 0xA9, 0x51, 0x80, 0xD9, 0xBA, 0xAF, 0xC7, 0xF6, 0xA8, 0x68, 0xDC, 0x1D, 0xE1, 0x6D, 0x6B, 0x7B, 0x4C, 0x59, 0x7F, 0x07, 0xEB, 0x57, 0x6D, 0x89, 0xF6, 0x38, 0x09, 0x72, 0xEC, 0x19, 0x72, 0xFE, 0xD1, 0x67, 0x9A, 0xE8, 0xB8, 0xAE, 0x6F, 0x5F, 0x18, 0x1A, 0x79, 0x67, 0x34, 0x29, 0xFC, 0x07, 0xDE, 0xFF, 0xA0, 0xD8, 0x1A, 0xBE, 0xF6, 0xF9, 0x23, 0xF8, 0x54, 0x0A, 0x78, 0x01, 0xD2, 0x20, 0x47, 0x5A, 0xAF, 0x0E, 0xC0, 0xFD, 0xBF, 0xE3, 0xAA, 0xA3, 0x5D, 0x05, 0x26, 0xDC, 0x7F, 0xF2, 0x95, 0x0A, 0x7C, 0x95, 0xF9, 0xCE, 0xD2, 0x89, 0x32, 0xCF, 0x29, 0xF8, 0x79, 0x11, 0x8D, 0x65, 0x90, 0x25, 0xB4, 0x7C, 0xCE, 0x75, 0x7E, 0x91, 0x78, 0x3E, 0x0B, 0xD4, 0xB0, 0x17, 0xB4, 0x80, 0x80, 0x83, 0xF3, 0x56, 0x94, 0x5F, 0xEC, 0x1C, 0xE2, 0x1E, 0x5C, 0x86, 0x23, 0x90, 0x6E, 0x46, 0xA7, 0x4B, 0x1E, 0xD1, 0x51, 0xF8, 0x5C, 0xF5, 0x15, 0x79, 0x27, 0x22, 0xCF, 0x5E, 0xE9, 0x46, 0x08, 0xA1, 0x05, 0x90, 0x0A, 0x58, 0x01, 0xB7, 0xB0, 0x5D, 0x06, 0x38, 0x03, 0x88, 0xD6, 0x41, 0x40, 0xEB, 0xED, 0xCD, 0x79, 0xFE, 0x4C, 0x5C, 0xEC, 0x65, 0xCE, 0x6C, 0x4D, 0x22, 0x61, 0x01, 0xCE, 0xAA, 0xA9, 0x06, 0xAF, 0xB3, 0x4F, 0x34, 0x0A, 0xC8, 0x33, 0x85, 0x88, 0xF4, 0xD3, 0xA1, 0x92, 0x80, 0xB4, 0x55, 0xA0, 0x7D, 0xBB, 0x5A, 0x67, 0x37, 0xBA, 0xBE, 0x22, 0x5C, 0x63, 0xF0, 0x96, 0x88, 0xA0, 0x6E, 0x14, 0x82, 0xC6, 0x70, 0x27, 0x04, 0xE2, 0xD4, 0x1B, 0x1E, 0xF8, 0x91, 0x3E, 0xD2, 0x12, 0x46, 0xD0, 0x81, 0x57, 0x0A, 0x49, 0x5F, 0x80, 0xF1, 0x56, 0xFF, 0xA0, 0x82, 0x85, 0x93, 0x09, 0x50, 0xE0, 0x5B, 0x34, 0x3B, 0xA0, 0x06, 0x50, 0x87, 0x50, 0xF8, 0xBF, 0x77, 0x9B, 0x7C, 0x1E, 0x40, 0x67, 0x3C, 0x89, 0xF2, 0x22, 0x12, 0xCB, 0x43, 0x9F, 0x7C, 0x75, 0xE6, 0x46, 0x83, 0x1B, 0x67, 0x7E, 0xDA, 0x0A, 0x56, 0xF1, 0xC6, 0xF2, 0x3B, 0x3D, 0xEB, 0x3B, 0x87, 0x22, 0x1D, 0x41, 0xAB, 0x4F, 0x35, 0x4A, 0x4A, 0x70, 0x97, 0xC9, 0x17, 0x34, 0x14, 0xF4, 0x8C, 0x91, 0xCF, 0x54, 0x45, 0xFA, 0xA4, 0x04, 0xBF, 0x25, 0xA4, 0xA4, 0x49, 0xDB, 0x1F, 0x4C, 0xE8, 0xB5, 0x97, 0xF6, 0x6F, 0xFD, 0x01, 0xE7, 0xAA, 0x7F, 0x84, 0xFD, 0xE4, 0x43, 0x1C, 0x40, 0x05, 0xB8, 0x4F, 0xB0, 0x15, 0x40, 0xD2, 0xFF, 0x83, 0x23, 0xA0, 0xD1, 0x01, 0x75, 0xEA, 0xC5, 0x98, 0xAF, 0x41, 0xE2, 0x19, 0x27, 0x59, 0x43, 0x47, 0xEF, 0xE7, 0xF4, 0xD4, 0x62, 0x80, 0x15, 0xA0, 0x6C, 0x78, 0x23, 0x00, 0x21, 0xC0, 0x1C, 0x08, 0x9E, 0xFF, 0xBB, 0x35, 0x94, 0x97, 0x6F, 0x29, 0x2F, 0x29, 0xA9, 0x9F, 0xB7, 0xD2, 0xE4, 0x2B, 0x3F, 0xFC, 0x65, 0x3E, 0xBE, 0xF3, 0x41, 0xE2, 0xE7, 0x90, 0x74, 0x5B, 0x58, 0x62, 0x4F, 0x89, 0x56, 0x78, 0x6F, 0xA5, 0x1A, 0xF9, 0xDF, 0x1F, 0x9A, 0x77, 0xCF, 0x3F, 0xEF, 0xA1, 0x53, 0x69, 0xD0, 0x7D, 0x73, 0x01, 0xD2, 0x6F, 0x71, 0x03, 0xF8, 0x9E, 0x0C, 0x08, 0x78, 0x49, 0xD6, 0x5B, 0xB5, 0x1D, 0x5E, 0xF8, 0xF2, 0x9E, 0x9A, 0x48, 0x80, 0xCE, 0x6E, 0xAD, 0x5D, 0x36, 0xA6, 0xBF, 0xE6, 0x77, 0xDA, 0x4A, 0x08, 0xA4, 0x00, 0x95, 0x8D, 0xF5, 0xC5, 0x68, 0x78, 0x23, 0xEC, 0x2D, 0xB8, 0x0E, 0x1A, 0x7D, 0x93, 0xFE, 0x53, 0xFD, 0x1B, 0x86, 0x61, 0x16, 0x30, 0x43, 0x27, 0x0C, 0xC3, 0xF0, 0x63, 0xB8, 0x1B, 0x72, 0x4B, 0x8F, 0xD9, 0x50, 0x9D, 0x2B, 0x9E, 0xFA, 0xDB, 0x5C, 0x7B, 0x1A, 0xDD, 0x0B, 0xF3, 0xED, 0x1A, 0x34, 0x40, 0x13, 0xB8, 0x37, 0x15, 0x93, 0x39, 0x74, 0xFA, 0x1E, 0xBD, 0xAB, 0x91, 0x02, 0x78, 0x00, 0x87, 0xA7, 0xCC, 0xCA, 0x78, 0xEA, 0xFF, 0x79, 0xFD, 0x9E, 0x65, 0xAB, 0xC9, 0xF1, 0x42, 0x17, 0xAC, 0xB1, 0x8E, 0x92, 0x71, 0x80, 0xCC, 0xBD, 0x17, 0xAE, 0x03, 0x13, 0xCD, 0x4F, 0x75, 0x6E, 0xD0, 0xF8, 0xAD, 0x34, 0xFD, 0x8E, 0x63, 0x86, 0x17, 0x1C, 0x21, 0x84, 0xAC, 0x7D, 0x53, 0x44, 0xEC, 0x32, 0xA4, 0xEB, 0x45, 0x55, 0x43, 0x76, 0x2B, 0xB5, 0x34, 0x91, 0xCF, 0x40, 0x6D, 0xDD, 0xF2, 0xE4, 0x00, 0xE4, 0xF3, 0x76, 0x28, 0xDA, 0xD1, 0x4A, 0x20, 0x02, 0x70, 0x03, 0xAE, 0x1C, 0xB5, 0x0A, 0xE0, 0xEA, 0xA0, 0x2D, 0xCF, 0xE0, 0xB3, 0xD4, 0x47, 0xF6, 0xAB, 0x4B, 0x47, 0xAA, 0x91, 0x0B, 0x05, 0x68, 0xCC, 0x05, 0x17, 0x17, 0xF2, 0xCB, 0x6F, 0x97, 0x1B, 0x09, 0xE4, 0x5B, 0x69, 0xF2, 0x82, 0xE6, 0xDF, 0x6B, 0xEB, 0x1E, 0xDB, 0xD0, 0x07, 0xA4, 0x47, 0xFA, 0x5F, 0x85, 0x90, 0xB8, 0x72, 0x47, 0x59, 0x8D, 0x70, 0x50, 0x93, 0x5D, 0xFE, 0x64, 0x9A, 0x0E, 0x61, 0xAC, 0x7F, 0xE9, 0xE3, 0x7C, 0x57, 0xE3, 0xA4, 0xE9, 0x97, 0x6F, 0x31, 0xCB, 0xCA, 0x26, 0xC0, 0xF1, 0xE9, 0x88, 0x72, 0x62, 0x4D, 0xF5, 0x54, 0x40, 0x75, 0x4E, 0x2D, 0xF3, 0x86, 0x39, 0xE0, 0x3C, 0x61, 0xB1, 0xE0, 0xF3, 0x93, 0xDB, 0x7A, 0x2D, 0x5C, 0x1C, 0x20, 0x79, 0x85, 0x30, 0xA6, 0x98, 0xEC, 0xBC, 0x95, 0xA6, 0x2F, 0x68, 0xA6, 0xDF, 0xC3, 0xF7, 0x1D, 0x72, 0x95, 0x1C, 0xD2, 0x2B, 0x63, 0xC8, 0x7C, 0x80, 0xC8, 0x60, 0x24, 0x07, 0x38, 0x66, 0xCB, 0xAC, 0xAD, 0x89, 0x0E, 0x32, 0xFA, 0x4C, 0x71, 0xF8, 0x1A, 0x93, 0x12, 0x34, 0x67, 0xE3, 0xAE, 0xD0, 0x8C, 0xA4, 0x73, 0x43, 0x00, 0x1B, 0xF9, 0x0B, 0x7B, 0x52, 0xDE, 0x90, 0xBF, 0x7E, 0x0C, 0x7E, 0x38, 0xF6, 0xC3, 0xC6, 0x23, 0x7D, 0x95, 0x0A, 0xBD, 0xA1, 0x0D, 0x5F, 0x55, 0x9D, 0x95, 0x75, 0xE1, 0x58, 0x9E, 0xE3, 0xB5, 0x0E, 0x76, 0x07, 0x90, 0xF7, 0x22, 0xB0, 0x17, 0x34, 0xD8, 0x06, 0xBF, 0x6B, 0xD5, 0x37, 0xA4, 0x20, 0x93, 0x20, 0xB2, 0xA2, 0xF6, 0x58, 0x66, 0x87, 0x5D, 0xA0, 0xD2, 0x58, 0x69, 0x4B, 0xB2, 0x2C, 0xCF, 0x11, 0xCF, 0x3A, 0x4C, 0xA9, 0xE3, 0x00, 0xD2, 0xAF, 0xBF, 0x7A, 0x3D, 0x99, 0x6F, 0x6A, 0xC3, 0x88, 0xB2, 0xBF, 0x2C, 0x46, 0x35, 0xFA, 0x62, 0x30, 0xDE, 0x74, 0x63, 0x7C, 0x12, 0xAD, 0x51, 0xC3, 0x56, 0x80, 0xCB, 0xC4, 0x5E, 0x62, 0x66, 0x6B, 0xA5, 0xE5, 0x9A, 0x2D, 0x6E, 0x3F, 0x74, 0xC1, 0x11, 0xBF, 0xEB, 0x3F, 0x1D, 0xB4, 0x3B, 0x2D, 0xAA, 0xBE, 0x3D, 0x4D, 0x9D, 0x5E, 0xD0, 0x0C, 0x7B, 0x3F, 0x6E, 0x7D, 0xA6, 0x10, 0x92, 0xB8, 0xA2, 0x43, 0x32, 0x04, 0x37, 0x82, 0xAD, 0x83, 0x79, 0x3A, 0x56, 0x1E, 0x93, 0x36, 0xD0, 0x75, 0xFC, 0x21, 0x1C, 0xD0, 0x3E, 0xD5, 0x46, 0x1F, 0x24, 0x52, 0x80, 0xE3, 0x1D, 0xD7, 0x1C, 0xE6, 0x65, 0x4F, 0x11, 0x90, 0x73, 0x2F, 0x64, 0x99, 0x43, 0x65, 0xC5, 0xA7, 0x80, 0x21, 0x14, 0xA8, 0x9B, 0x66, 0xD1, 0x05, 0x6F, 0x2C, 0x6F, 0x05, 0x2E, 0xC0, 0x12, 0x88, 0x68, 0xF0, 0x52, 0xEF, 0xCB, 0x0F, 0xD3, 0xA7, 0x7C, 0x41, 0x8B, 0xCF, 0xD1, 0xC4, 0xE5, 0x6D, 0x6D, 0x43, 0x23, 0x2F, 0x5A, 0xBD, 0xF6, 0x3F, 0x28, 0x1B, 0xDD, 0x7B, 0xE1, 0x94, 0x2C, 0xF3, 0x7A, 0x11, 0xE4, 0x99, 0x2F, 0x82, 0x10, 0xC0, 0xCF, 0xDC, 0xBE, 0x28, 0x66, 0x57, 0xA2, 0xE9, 0x34, 0xFC, 0xD6, 0x33, 0x8F, 0x00, 0x46, 0xCB, 0x74, 0x82, 0x9E, 0x0C, 0xA2, 0x69, 0xDB, 0xDE, 0x99, 0x96, 0x9F, 0x8C, 0xC9, 0x5A, 0x57, 0xA7, 0x41, 0x8D, 0x75, 0xA4, 0x28, 0x5A, 0x83, 0x1A, 0x69, 0xCD, 0x79, 0x6C, 0x44, 0xCC, 0x7B, 0x35, 0xD1, 0x8D, 0xDB, 0x5F, 0xC9, 0xF3, 0x2B, 0x41, 0xDB, 0x78, 0x42, 0xA5, 0xC7, 0xFE, 0x1B, 0x55, 0xE7, 0x0E, 0x0D, 0x82, 0x31, 0x9D, 0x16, 0x9B, 0x1A, 0x43, 0x9F, 0x20, 0xAF, 0x41, 0x22, 0xF2, 0x47, 0x42, 0xEB, 0x7C, 0x88, 0x3D, 0x1F, 0xE5, 0x69, 0x40, 0x35, 0xE6, 0xDA, 0xE1, 0x98, 0x89, 0xDF, 0xB3, 0xB6, 0x27, 0x53, 0x40, 0x18, 0x60, 0x02, 0xE4, 0x00, 0x46, 0x33, 0x4C, 0x96, 0x8D, 0x9A, 0x70, 0x5A, 0x41, 0x93, 0xFB, 0x13, 0x56, 0x92, 0xB4, 0x11, 0xD5, 0xD0, 0x39, 0x8A, 0x94, 0xEC, 0x06, 0xAD, 0x5E, 0xD0, 0x22, 0xD1, 0x9B, 0xC7, 0xDF, 0x93, 0xAD, 0x5F, 0xE1, 0xDD, 0x35, 0xB1, 0x02, 0x58, 0x90, 0xAD, 0x4E, 0x47, 0xF3, 0x8B, 0xAE, 0xA6, 0x02, 0x10, 0x09, 0x96, 0x21, 0xF5, 0x96, 0xFB, 0x02, 0x4D, 0xA0, 0x64, 0x9E, 0xD1, 0x22, 0x66, 0xBF, 0x03, 0xC7, 0x72, 0x58, 0x38, 0xB3, 0x23, 0x51, 0x65, 0x1E, 0x65, 0x65, 0x5D, 0x93, 0xDC, 0x00, 0x5D, 0xCB, 0x32, 0x2E, 0xAA, 0x61, 0x0D, 0x5F, 0x88, 0xB9, 0x9F, 0x11, 0x03, 0x1C, 0x0D, 0x5D, 0x8A, 0xBA, 0x6C, 0x2C, 0x33, 0xEC, 0x67, 0x9F, 0x10, 0x07, 0x4F, 0xA8, 0xDA, 0x27, 0xEA, 0x88, 0x60, 0x4C, 0x5D, 0x91, 0x36, 0xF8, 0xCE, 0xC0, 0x3B, 0x99, 0x3F, 0xF8, 0x7B, 0x8F, 0x92, 0xCE, 0x27, 0x94, 0xB6, 0x43, 0x98, 0xCB, 0x54, 0x9E, 0xA5, 0x01, 0x51, 0xC0, 0xDD, 0x21, 0x3C, 0xD7, 0xA4, 0xF0, 0x35, 0xBB, 0xCF, 0x73, 0x3D, 0xA9, 0xFC, 0xC3, 0x2F, 0x8C, 0x0A, 0x38, 0xD9, 0x70, 0x80, 0x05, 0xB0, 0x55, 0x1F, 0x0C, 0x6E, 0xE8, 0x8A, 0x61, 0xAE, 0x37, 0x28, 0xAD, 0xA8, 0xC9, 0x4A, 0x63, 0x55, 0x63, 0x7C, 0xEA, 0x8B, 0x2E, 0xA2, 0x46, 0xA3, 0x3A, 0x60, 0x7F, 0xD6, 0x57, 0xFE, 0x5D, 0x39, 0x05, 0xFF, 0x1B, 0xD9, 0xBB, 0xAE, 0xC0, 0xB7, 0x43, 0x47, 0xD6, 0x5B, 0x86, 0x6F, 0xD3, 0x30, 0x26, 0x3D, 0xAB, 0x7E, 0xD6, 0x50, 0xE9, 0x10, 0xEA, 0x4C, 0xF2, 0x4B, 0x4E, 0x51, 0xAD, 0xC4, 0x14, 0xB5, 0x69, 0xAD, 0x21, 0xFF, 0x0A, 0x18, 0xAF, 0x10, 0xC6, 0x7A, 0x4C, 0xB5, 0x51, 0x0B, 0x39, 0xA1, 0xA7, 0x91, 0xBF, 0x0E, 0xB8, 0xFC, 0xEB, 0x26, 0x26, 0x8D, 0x02, 0xF2, 0xDC, 0xA0, 0x31, 0x9A, 0xA2, 0xB2, 0x3E, 0x44, 0xF1, 0xB8, 0xB4, 0xEB, 0x21, 0x5C, 0x3C, 0xF9, 0x6A, 0xD4, 0x0A, 0x95, 0x1F, 0xD2, 0x39, 0x27, 0xBB, 0xD6, 0xFD, 0xD3, 0x46, 0xBE, 0x0E, 0xB3, 0xAA, 0x00, 0xE6, 0xFF, 0x96, 0xC1, 0xF2, 0x2A, 0xEC, 0x5E, 0xB6, 0xD0, 0x56, 0x3F, 0x12, 0xDF, 0x3E, 0x80, 0xD5, 0x31, 0x2C, 0x3E, 0x17, 0x63, 0xC8, 0x8F, 0x1C, 0xA7, 0xF3, 0xCC, 0x12, 0x79, 0xAD, 0xF7, 0xA9, 0x03, 0x3B, 0xC7, 0x29, 0x02, 0x58, 0x01, 0xE1, 0x0D, 0x5E, 0x5E, 0xB2, 0x07, 0x90, 0x65, 0x92, 0x9E, 0xEF, 0xF9, 0x94, 0xEF, 0x3A, 0x10, 0xC7, 0xBF, 0xBD, 0xDF, 0x62, 0x1E, 0x3B, 0xBC, 0x18, 0x75, 0xDA, 0x14, 0x3C, 0x6B, 0x21, 0xA8, 0x37, 0xA4, 0x4D, 0x37, 0x57, 0x5B, 0x89, 0x48, 0xF2, 0x51, 0xC9, 0xC6, 0x6F, 0x88, 0xD3, 0x47, 0x7F, 0xD2, 0x77, 0x85, 0x1F, 0x07, 0x0D, 0xAD, 0xE9, 0x28, 0x72, 0x72, 0x06, 0x34, 0x64, 0xDE, 0x4D, 0xF5, 0xCC, 0xFA, 0x93, 0x36, 0xB8, 0x61, 0x31, 0x8B, 0x59, 0x74, 0x00, 0x4D, 0xC0, 0x6B, 0x55, 0xF4, 0xE2, 0xE6, 0x9A, 0x00, 0x51, 0xC0, 0xA4, 0x41, 0x80, 0x36, 0xD8, 0x7F, 0xB8, 0xFA, 0xB9, 0xDD, 0xA0, 0x29, 0x8C, 0x4C, 0x9C, 0xBE, 0x6D, 0x4C, 0x8B, 0x46, 0x4E, 0x8D, 0x2A, 0x70, 0xB1, 0x09, 0xEF, 0x7C, 0xA4, 0x42, 0xA1, 0x2F, 0x3E, 0x72, 0xDD, 0xA6, 0x23, 0x68, 0xF2, 0x0A, 0x3A, 0xFD, 0xC6, 0xA3, 0x4E, 0xBF, 0xF2, 0x6B, 0xAD, 0xF1, 0x40, 0xB4, 0x42, 0x71, 0x2C, 0xBB, 0x8E, 0x2B, 0x0E, 0xD0, 0x73, 0xE5, 0x9A, 0x9E, 0xCB, 0x57, 0x9F, 0x47, 0x4F, 0x59, 0x39, 0x45, 0xF2, 0x42, 0x3F, 0x32, 0x89, 0x7E, 0x80, 0x3A, 0xAB, 0x6F, 0x9D, 0x1A, 0x0E, 0x30, 0x01, 0xB2, 0x92, 0xEA, 0xA9, 0x8D, 0x03, 0x44, 0xC3, 0x08, 0x50, 0x5E, 0x2B, 0xAD, 0x6E, 0xD0, 0x6C, 0xAB, 0x39, 0xC6, 0xD8, 0xCF, 0x08, 0x86, 0xD8, 0x80, 0x3B, 0x05, 0x53, 0x8A, 0x5B, 0x76, 0xF0, 0x2C, 0xB5, 0xBF, 0x33, 0xC7, 0x98, 0x9B, 0x7B, 0x53, 0xED, 0xF5, 0x60, 0xB7, 0x7A, 0x76, 0xE6, 0x32, 0x22, 0x99, 0x2D, 0x64, 0x14, 0x73, 0x98, 0x67, 0xC8, 0xDC, 0xCC, 0xD4, 0x01, 0xB6, 0x86, 0x00, 0x64, 0x0D, 0x07, 0xC4, 0xF7, 0xB8, 0xEC, 0x46, 0x6C, 0xAC, 0x7B, 0xC0, 0xCA, 0x6E, 0x6B, 0x36, 0x64, 0xA5, 0xBC, 0x65, 0x66, 0x20, 0x47, 0x77, 0x2B, 0x82, 0xE6, 0xDF, 0xE3, 0x49, 0x51, 0x2B, 0x68, 0x78, 0x3C, 0xF5, 0x38, 0x4E, 0xC9, 0x4E, 0xC8, 0x8C, 0x68, 0x42, 0x76, 0x1D, 0xF7, 0x60, 0xBB, 0xAF, 0x52, 0xF6, 0x27, 0x2C, 0xCE, 0x57, 0x14, 0x8A, 0x00, 0xE4, 0xEA, 0xAF, 0x3B, 0x68, 0x34, 0xE4, 0x9A, 0xFA, 0xFA, 0x29, 0x8A, 0xA7, 0xE3, 0x9A, 0xE5, 0x7C, 0x7B, 0xCA, 0xDA, 0xEC, 0x59, 0x06, 0xD6, 0x68, 0x7C, 0x79, 0xC7, 0x6B, 0xDE, 0x46, 0xCC, 0x06, 0xA4, 0x2F, 0xDD, 0x9A, 0x00, 0xE6, 0x40, 0xE8, 0x84, 0x3B, 0x60, 0xBF, 0xCA, 0x30, 0xF9, 0x82, 0x16, 0xE8, 0x24, 0x3B, 0xF6, 0x82, 0xC6, 0x9F, 0xD2, 0x0C, 0xED, 0x18, 0xC5, 0x85, 0x74, 0x12, 0xA3, 0xEE, 0x79, 0xAC, 0x1B, 0xA0, 0x35, 0x91, 0x16, 0xDA, 0x41, 0xA3, 0x31, 0x82, 0x18, 0x49, 0x9F, 0x51, 0xD3, 0x7F, 0x7B, 0xCC, 0xEB, 0xA7, 0x58, 0x9B, 0xBD, 0x8C, 0x25, 0x36, 0x4C, 0x13, 0x87, 0x61, 0xA9, 0xD2, 0x5A, 0x69, 0x0C, 0x50, 0xCE, 0x4F, 0xB6, 0x8E, 0xF6, 0x2A, 0x80, 0xD5, 0xAF, 0x79, 0xC6, 0x36, 0x3B, 0xE9, 0x49, 0xD7, 0xA8, 0xD5, 0x00, 0x28, 0x56, 0x4B, 0x12, 0x2D, 0xE9, 0xBA, 0xDC, 0xA0, 0xE5, 0x97, 0x09, 0x72, 0x8F, 0x1B, 0xB4, 0x91, 0xBD, 0x8D, 0x12, 0xB4, 0x30, 0x09, 0xE1, 0x34, 0x6C, 0x8C, 0x23, 0x47, 0xC9, 0x08, 0x9A, 0x36, 0x11, 0xA6, 0x91, 0x89, 0xE4, 0x55, 0x18, 0x13, 0xFB, 0x93, 0x61, 0xDB, 0xDB, 0x48, 0x9E, 0xAF, 0x04, 0xAD, 0x35, 0xD6, 0x20, 0x9D, 0x97, 0x1E, 0x56, 0x80, 0x68, 0xE1, 0x34, 0x0A, 0xF0, 0x9C, 0x22, 0x7B, 0x0D, 0xA0, 0x76, 0xD7, 0xBB, 0xED, 0xF1, 0x3E, 0xAB, 0xA3, 0x21, 0x1B, 0xD1, 0x38, 0xEB, 0x56, 0x7A, 0x80, 0xBB, 0x8A, 0xCF, 0xDB, 0xD4, 0xEA, 0xCB, 0x71, 0x84, 0x25, 0x9C, 0x73, 0xFE, 0x72, 0xDE, 0xF6, 0x1D, 0xA6, 0x04, 0x3D, 0x5E, 0x4C, 0xA8, 0x36, 0xA1, 0x74, 0x6C, 0x54, 0x81, 0x06, 0x8C, 0x8E, 0x56, 0x4C, 0xCF, 0x09, 0x79, 0xEA, 0x56, 0xA6, 0x7B, 0xE6, 0x28, 0xE0, 0x60, 0xEF, 0xA7, 0xF1, 0x8A, 0xF4, 0x97, 0xF0, 0x2F, 0x9A, 0xB7, 0x52, 0xF5, 0xD9, 0xDF, 0xCA, 0x6B, 0x91, 0x68, 0x00, 0xF2, 0x6B, 0x26, 0x7F, 0xE7, 0x2C, 0x5F, 0xAB, 0x99, 0xAE, 0x06, 0x77, 0xCD, 0xE5, 0x97, 0x60, 0x4B, 0x40, 0xAF, 0x80, 0x72, 0xE3, 0x00, 0xC2, 0x00, 0x1F, 0x80, 0x04, 0x60, 0x06, 0x5E, 0x73, 0x59, 0xCE, 0x57, 0x00, 0xC2, 0xCA, 0x98, 0xEF, 0x63, 0x28, 0xF3, 0x63, 0xA3, 0x32, 0x47, 0x4F, 0x81, 0xF4, 0x26, 0xAF, 0xDC, 0x13, 0xEC, 0xB7, 0x0F, 0x40, 0xFE, 0xD5, 0xB9, 0xFC, 0xEE, 0xFD, 0xAF, 0xB2, 0xCF, 0x0A, 0x98, 0x34, 0x68, 0xC2, 0xB9, 0xC3, 0xDB, 0xB5, 0xED, 0x57, 0xE3, 0x0B, 0x05, 0xF4, 0xD6, 0xC4, 0xFD, 0xBF, 0xBA, 0x02, 0x7F, 0x67, 0xAB, 0x3D, 0xF7, 0xC6, 0x0E, 0x40, 0x2B, 0xB7, 0x16, 0x7B, 0xBC, 0xBD, 0x4D, 0x44, 0xCC, 0xEB, 0x11, 0x49, 0x63, 0x7B, 0xCD, 0x5A, 0x63, 0xCD, 0x7C, 0x62, 0xBA, 0x41, 0xA3, 0x15, 0x34, 0x28, 0xB0, 0xB2, 0x33, 0x91, 0x4E, 0x78, 0x22, 0x2D, 0x19, 0x5B, 0xA2, 0x5A, 0x17, 0xF2, 0xE3, 0x0B, 0x9A, 0x6D, 0xCD, 0xF2, 0xAD, 0x7D, 0x3C, 0x2D, 0xE6, 0x3D, 0xA8, 0x11, 0xE3, 0xA0, 0x66, 0x07, 0x85, 0xA6, 0x53, 0x00, 0x59, 0x83, 0x1B, 0x01, 0xB8, 0xA1, 0x24, 0xE5, 0x8C, 0x02, 0x15, 0xCB, 0x5F, 0xE1, 0x4F, 0x5E, 0x55, 0x26, 0x09, 0x57, 0xD9, 0xB1, 0xDB, 0x0B, 0x62, 0x30, 0x7C, 0xD9, 0x68, 0xDE, 0xF1, 0x73, 0xDD, 0x9C, 0xF6, 0x5D, 0xB4, 0x5E, 0x94, 0x01, 0xB9, 0x60, 0x80, 0x0A, 0x38, 0xCB, 0xFB, 0xF2, 0x10, 0x20, 0x75, 0x83, 0xC6, 0xDF, 0x05, 0x8A, 0xFF, 0x8E, 0xB5, 0xF2, 0xED, 0x82, 0xF9, 0x1D, 0xD4, 0x52, 0xD0, 0x91, 0x17, 0x91, 0x70, 0x56, 0x8C, 0xC0, 0xB3, 0x76, 0xE4, 0xB5, 0x2F, 0x7E, 0xA4, 0x35, 0xAB, 0xE0, 0x9E, 0x52, 0xF5, 0x1E, 0xD4, 0xB8, 0x63, 0xC7, 0x04, 0x98, 0x35, 0x18, 0xD0, 0x00, 0x8C, 0xFA, 0x00, 0xDC, 0x91, 0x64, 0x46, 0xB4, 0xB8, 0x03, 0x9A, 0x9D, 0x8C, 0x93, 0xAB, 0xB0, 0x90, 0x96, 0x6B, 0xCC, 0xA7, 0xDB, 0x96, 0xAC, 0xCA, 0x18, 0x60, 0x99, 0x46, 0x6E, 0x55, 0x8D, 0x68, 0x2C, 0x3B, 0x1D, 0x49, 0xC0, 0xAC, 0xC1, 0x80, 0x9E, 0xD5, 0x32, 0x68, 0x00, 0x37, 0xFC, 0xAD, 0x34, 0x79, 0x2B, 0x4D, 0xBE, 0xCB, 0x83, 0x7F, 0x9A, 0xE5, 0xE3, 0xF4, 0x2F, 0xF0, 0xEC, 0xE1, 0x15, 0x90, 0x82, 0x1B, 0x61, 0x2A, 0x2E, 0x37, 0xE5, 0x63, 0x5E, 0xB6, 0xF8, 0xB2, 0x89, 0x94, 0x67, 0xA2, 0x37, 0x3B, 0x5E, 0xF9, 0x00, 0x27, 0xA7, 0x75, 0xB1, 0xDB, 0xB2, 0x23, 0xC9, 0x39, 0x65, 0xC0, 0x46, 0x27, 0xB4, 0xFE, 0x37, 0xCD, 0x98, 0xD3, 0x85, 0x53, 0xEE, 0x33, 0xB4, 0xD3, 0x41, 0x0E, 0x68, 0xFE, 0xBF, 0xEF, 0xA0, 0x2B, 0xDB, 0x16, 0x0D, 0x5F, 0xF9, 0x23, 0xE3, 0x1F, 0x3E, 0xC6, 0xE1, 0x37, 0x68, 0x8A, 0x89, 0xC5, 0x6F, 0x1C, 0x46, 0x8B, 0x2D, 0x4E, 0x7C, 0x41, 0x73, 0x0B, 0xEC, 0xCE, 0x66, 0x68, 0xC8, 0xA4, 0x7E, 0x15, 0xDE, 0x59, 0x8C, 0x7B, 0xA5, 0xBD, 0xE3, 0x29, 0xCF, 0x8C, 0x9A, 0xC7, 0x9A, 0xBA, 0xDC, 0x60, 0x05, 0x4E, 0x2E, 0x51, 0xB5, 0xAC, 0x61, 0x15, 0x06, 0x3C, 0x85, 0xB6, 0xBE, 0xC2, 0x56, 0xB7, 0xBA, 0xCE, 0xD0, 0x93, 0x4C, 0xD7, 0x04, 0x23, 0x40, 0x1C, 0x60, 0x69, 0x50, 0xE3, 0x34, 0x18, 0x90, 0x86, 0x26, 0x60, 0x17, 0xD6, 0x58, 0x4D, 0xD1, 0xE2, 0xCB, 0x13, 0x4A, 0x6F, 0xD0, 0xFE, 0x4E, 0x68, 0xF9, 0x85, 0xE4, 0x1F, 0x6B, 0x9B, 0x6A, 0x7E, 0x1E, 0x08, 0xD9, 0xCD, 0x23, 0xDC, 0x49, 0x2F, 0x86, 0xAA, 0xD3, 0x72, 0x04, 0xCD, 0x73, 0x05, 0x4D, 0x3F, 0xC4, 0x7B, 0x03, 0xC4, 0xDD, 0xE5, 0x8D, 0x01, 0x37, 0x40, 0xEC, 0xBA, 0x0B, 0x8E, 0x2C, 0xB7, 0x17, 0x50, 0x72, 0xE5, 0xD7, 0x1D, 0x42, 0xFA, 0x6B, 0x8D, 0xF3, 0xB7, 0x26, 0x9F, 0xFB, 0xEB, 0xEA, 0x56, 0x20, 0x5E, 0x46, 0x03, 0xB2, 0xD6, 0xCF, 0x7E, 0x11, 0xEC, 0xC4, 0x5A, 0xAD, 0xD3, 0x7F, 0xAE, 0xB2, 0x8A, 0x2F, 0x4B, 0xE7, 0xB3, 0x5F, 0x04, 0xFE, 0xE9, 0xF8, 0xAC, 0xE2, 0xCB, 0x3F, 0x66, 0xA1, 0x05, 0xB4, 0xBA, 0xAA, 0x27, 0xDA, 0x13, 0x6E, 0xD1, 0xD7, 0x6E, 0xCC, 0xFD, 0x0A, 0x26, 0x9F, 0xD3, 0x18, 0x77, 0xEE, 0x56, 0xE8, 0xDD, 0x1E, 0x3B, 0xA3, 0x31, 0x85, 0x74, 0x40, 0xBE, 0xE2, 0x9E, 0x25, 0xA0, 0x01, 0x84, 0xBF, 0x17, 0xEC, 0x6C, 0xBB, 0x3C, 0x8C, 0x05, 0xA7, 0x7F, 0x8A, 0x3D, 0x7F, 0x9D, 0xA0, 0x4E, 0x6B, 0x33, 0x53, 0x40, 0x0D, 0x10, 0xDB, 0xAE, 0x1B, 0xEB, 0x53, 0xAE, 0xE3, 0x5A, 0x01, 0xE9, 0x0D, 0x06, 0x42, 0x01, 0xAB, 0x35, 0xEC, 0xBD, 0x51, 0x6F, 0xA5, 0xC5, 0xBF, 0xEA, 0x55, 0x20, 0xFD, 0x92, 0xE7, 0x82, 0x92, 0xC3, 0xF1, 0xE6, 0xC7, 0x72, 0x95, 0xC0, 0x5F, 0x8C, 0x04, 0x59, 0x03, 0x96, 0x79, 0xF9, 0xE4, 0x5D, 0x66, 0xD7, 0x5B, 0x5A, 0x9A, 0x73, 0x91, 0x22, 0x1A, 0x07, 0x90, 0x04, 0x0E, 0xED, 0x2B, 0xCC, 0xFD, 0x22, 0x40, 0xA3, 0x03, 0xC7, 0x5F, 0x83, 0x5C, 0x0E, 0xA7, 0x77, 0x79, 0xD2, 0xAA, 0xAC, 0xD5, 0x25, 0xA3, 0x3B, 0x6F, 0xD4, 0xE0, 0xC6, 0x59, 0xD7, 0x4D, 0x59, 0x7D, 0xF7, 0xD1, 0x58, 0x5F, 0xB4, 0x03, 0xA8, 0x34, 0x0A, 0x48, 0xBE, 0x41, 0xC3, 0x9C, 0xB2, 0xB0, 0x77, 0xE4, 0x80, 0x3A, 0x8C, 0xBA, 0x7D, 0xD6, 0x0A, 0x55, 0x35, 0x36, 0xCC, 0xA6, 0x57, 0x46, 0xB2, 0x82, 0x7C, 0x26, 0xD4, 0x72, 0xE5, 0x86, 0x4E, 0xBC, 0xA7, 0xAD, 0xDF, 0x89, 0x8A, 0xB7, 0xA0, 0x34, 0xF2, 0xE2, 0x00, 0xD1, 0x70, 0x06, 0x22, 0xF1, 0xDA, 0xA4, 0x86, 0x10, 0xBE, 0x68, 0x8E, 0x17, 0x6C, 0x45, 0x1F, 0xD7, 0xE4, 0xB9, 0xB0, 0xA2, 0x87, 0x60, 0x16, 0x19, 0xEC, 0x4C, 0xEF, 0xF0, 0x74, 0xC0, 0xA3, 0x41, 0x8D, 0xD3, 0x10, 0xE0, 0x1E, 0xF7, 0x0F, 0x6D, 0x97, 0xBE, 0xF9, 0xD6, 0xCD, 0x6A, 0x9C, 0xE5, 0xB0, 0xFA, 0x56, 0x5A, 0xBD, 0x3D, 0x4D, 0x18, 0x6E, 0x26, 0xD6, 0xAD, 0xD9, 0xFE, 0x49, 0xDC, 0x15, 0x02, 0xDA, 0x70, 0x94, 0x6A, 0xBD, 0xA7, 0x8D, 0x4B, 0x2E, 0x13, 0xD7, 0x25, 0x58, 0xF6, 0x9C, 0x9E, 0x55, 0x29, 0x6B, 0xD8, 0xBC, 0xCE, 0x16, 0x6B, 0x3F, 0x80, 0x11, 0x90, 0x37, 0x14, 0x31, 0x2B, 0xF1, 0x35, 0xDC, 0x65, 0xEC, 0xE5, 0x04, 0x32, 0x97, 0x0A, 0x86, 0xA7, 0xCD, 0x58, 0xD8, 0xFF, 0xC8, 0xBD, 0x2E, 0x78, 0x23, 0xCF, 0xAF, 0x32, 0xFB, 0x2A, 0x39, 0x78, 0x2C, 0x15, 0x8C, 0x74, 0xD0, 0x3E, 0x11, 0xDD, 0x37, 0xC8, 0x5E, 0x3E, 0x3F, 0xB5, 0x43, 0xF4, 0x4F, 0x12, 0x03, 0x0A, 0x0C, 0xAF, 0x7E, 0x9C, 0xBD, 0x94, 0x50, 0x9B, 0x0B, 0xEE, 0xC6, 0x2D, 0xFB, 0x65, 0x02, 0x30, 0x34, 0x4E, 0xFE, 0xDF, 0x39, 0x4E, 0x67, 0xCF, 0x63, 0x02, 0x5C, 0x01, 0x09, 0x80, 0x1B, 0x7E, 0x73, 0xBD, 0x7A, 0xCD, 0x6D, 0x12, 0x9F, 0xE2, 0xEF, 0x3B, 0xE3, 0x09, 0xC1, 0x6B, 0x4D, 0x72, 0x21, 0x9F, 0x7A, 0x3D, 0x6D, 0x70, 0x83, 0x14, 0x38, 0xD9, 0xF0, 0x46, 0x01, 0x7C, 0x00, 0x8D, 0xF5, 0x74, 0xC7, 0x0F, 0x4F, 0x4B, 0xBE, 0x28, 0xC0, 0xF9, 0x06, 0x8D, 0xBE, 0xBB, 0x67, 0xFA, 0x6B, 0x96, 0xC2, 0x65, 0x3A, 0xE3, 0x2B, 0x7E, 0x66, 0x32, 0x0C, 0xED, 0x48, 0xBF, 0xC7, 0x53, 0x3C, 0x5A, 0x27, 0xF5, 0xD3, 0x7A, 0x68, 0x0C, 0xF3, 0xC7, 0xE9, 0xA2, 0x4F, 0xB5, 0xAB, 0x70, 0xCC, 0x0A, 0x1C, 0x9F, 0xE2, 0x48, 0x67, 0xC0, 0x0E, 0x20, 0x39, 0x05, 0x7E, 0xAE, 0xFF, 0xBD, 0x0A, 0xD4, 0xDB, 0xF6, 0xF4, 0x66, 0x50, 0x7C, 0x5E, 0x2C, 0x8F, 0xCF, 0x4A, 0x8E, 0xC7, 0xFF, 0x30, 0x08, 0x0B, 0x20, 0xCE, 0x9E, 0x9C, 0x34, 0xEB, 0x8A, 0xB5, 0x6E, 0xC5, 0xC9, 0xF3, 0x3B, 0xF9, 0xDC, 0xA0, 0xF1, 0xBA, 0x46, 0x41, 0x22, 0xCB, 0x92, 0xFF, 0xFC, 0x2B, 0x08, 0x04, 0x7A, 0x3E, 0x93, 0x31, 0x22, 0x30, 0x03, 0x02, 0x32, 0xC3, 0x35, 0x4A, 0x77, 0xEB, 0x0A, 0x0F, 0x6F, 0xFA, 0xAE, 0x6E, 0xF6, 0x32, 0x9A, 0x6E, 0xC5, 0x4A, 0x80, 0x08, 0x40, 0x01, 0x9C, 0x06, 0x39, 0xA0, 0x0A, 0x98, 0x5C, 0x5F, 0x83, 0x97, 0x0B, 0x7F, 0x39, 0x30, 0x7B, 0x77, 0xFA, 0x5C, 0x93, 0xB0, 0xD9, 0xD7, 0x0C, 0xDB, 0x02, 0x5C, 0x7F, 0xD6, 0x41, 0x01, 0x4F, 0x20, 0xED, 0x97, 0x48, 0xCD, 0xD7, 0xB3, 0x5E, 0x6B, 0x7A, 0x3C, 0xDD, 0xA0, 0xC9, 0xBF, 0xE4, 0x21, 0x1E, 0x45, 0x23, 0x4B, 0x32, 0x84, 0xB7, 0x6C, 0x38, 0xDC, 0xA6, 0x20, 0xDD, 0xC3, 0x86, 0x59, 0x86, 0x1C, 0x2D, 0x4E, 0xDB, 0x2A, 0x18, 0x99, 0xA9, 0x21, 0xAD, 0xFB, 0xA2, 0x9C, 0xED, 0x80, 0xEC, 0x00, 0x65, 0x43, 0x1A, 0xB6, 0xCE, 0x1A, 0x92, 0x53, 0xB0, 0x90, 0x86, 0xC7, 0xFA, 0x9E, 0x71, 0x6F, 0xB2, 0x9F, 0x67, 0x5A, 0x64, 0x4F, 0x0C, 0xD1, 0x03, 0xD0, 0x1E, 0x1F, 0x4E, 0x8D, 0x5F, 0x52, 0x5B, 0x69, 0xA8, 0x37, 0x04, 0x10, 0xFF, 0xA1, 0xA6, 0xE4, 0x00, 0xCC, 0x6E, 0xD0, 0xF4, 0xEB, 0xF9, 0x0C, 0x9A, 0x2B, 0xCD, 0x34, 0xBF, 0x72, 0xB1, 0xAA, 0x75, 0xF2, 0x9A, 0xBF, 0x6D, 0xC7, 0x55, 0xB1, 0xDF, 0x9C, 0x1A, 0x6F, 0x4F, 0xCF, 0x21, 0x0D, 0xD0, 0x17, 0x1F, 0x97, 0x7E, 0xDA, 0xB2, 0x1F, 0xCF, 0xBC, 0x77, 0x73, 0x01, 0xCE, 0xFD, 0xA2, 0x02, 0x11, 0x40, 0x55, 0xBF, 0x2F, 0xF1, 0xF6, 0x7C, 0x6F, 0x5D, 0xFF, 0x20, 0x4F, 0xCF, 0x5F, 0xFC, 0xDF, 0x12, 0x57, 0xBE, 0x6C, 0x8E, 0xE8, 0x2C, 0x16, 0x6A, 0x00, 0x2C, 0xC0, 0xF1, 0x5F, 0xA3, 0xDB, 0x14, 0xE0, 0x03, 0xE8, 0x6A, 0xE0, 0xB3, 0x6A, 0x1C, 0x40, 0xBC, 0x71, 0x1A, 0x01, 0x84, 0xDE, 0xA0, 0xD9, 0x37, 0x8A, 0x37, 0x9E, 0x22, 0xA1, 0xDF, 0x6C, 0xCE, 0x5F, 0xBE, 0xBB, 0x84, 0xB0, 0xB5, 0x18, 0x21, 0x57, 0xD1, 0xD2, 0xE3, 0x24, 0x46, 0xD6, 0x71, 0xFB, 0x0E, 0x49, 0xDE, 0xC6, 0xA2, 0x8E, 0x88, 0x57, 0xBB, 0x57, 0x10, 0xFE, 0x0D, 0xA8, 0x21, 0x05, 0x50, 0x5F, 0xD5, 0x82, 0x01, 0x25, 0x80, 0x15, 0xA0, 0x0F, 0x89, 0x33, 0xF6, 0x93, 0xC7, 0x47, 0x87, 0x10, 0xDB, 0x11, 0x82, 0x1D, 0xBD, 0x5D, 0xC6, 0xD2, 0x84, 0x1B, 0x20, 0x8D, 0x7E, 0xF1, 0x94, 0x35, 0xCE, 0x82, 0xDE, 0x1D, 0x83, 0x00, 0x49, 0xC0, 0xAC, 0x21, 0x80, 0x36, 0xB8, 0x7E, 0x58, 0xA0, 0x7B, 0x75, 0xD0, 0x1C, 0x7B, 0xBE, 0x16, 0xF6, 0x2D, 0xCE, 0xE1, 0x08, 0xA0, 0x21, 0x90, 0x30, 0x3B, 0xA3, 0x3E, 0x92, 0x86, 0x7F, 0x77, 0xFF, 0xD5, 0x8E, 0xC7, 0x1F, 0x14, 0x5F, 0xEE, 0x38, 0x77, 0x80, 0x19, 0xBF, 0x35, 0x37, 0xCC, 0x00, 0xF6, 0x6E, 0x34, 0x38, 0x80, 0x35, 0x88, 0x3B, 0x35, 0x14, 0x00, 0x1E, 0x4F, 0x7D, 0x49, 0x92, 0x2B, 0x9D, 0x57, 0xED, 0xF7, 0xC1, 0xAC, 0x5F, 0x9D, 0x9A, 0x32, 0x41, 0xA1, 0x79, 0x46, 0x29, 0x6B, 0x70, 0x83, 0x1A, 0x7E, 0xBF, 0x65, 0xAE, 0x26, 0x93, 0xC6, 0x01, 0xB4, 0xC1, 0x0E, 0x50, 0x83, 0x1B, 0xFE, 0xF6, 0xB4, 0x18, 0x5D, 0xC5, 0x9C, 0xF4, 0x4F, 0x05, 0xC3, 0x30, 0x9C, 0x70, 0xC6, 0xC5, 0xE6, 0x57, 0x37, 0xDF, 0x8D, 0x8C, 0x99, 0xF2, 0xF0, 0x05, 0x53, 0x5B, 0x6E, 0x30, 0x96, 0xD3, 0x00, 0xC8, 0xA8, 0xE1, 0x00, 0xD7, 0x14, 0x6E, 0x88, 0xAE, 0x69, 0x82, 0xD9, 0x88, 0x06, 0x03, 0xBC, 0xCC, 0xC7, 0x85, 0xE6, 0x6E, 0x6D, 0x2B, 0x85, 0xA1, 0x04, 0x98, 0x36, 0x72, 0x8B, 0xD4, 0x16, 0x12, 0xF0, 0xDD, 0x8F, 0xB1, 0x3D, 0xF2, 0x0A, 0x08, 0x6F, 0xAC, 0x8E, 0xD6, 0xE3, 0x37, 0x68, 0xD9, 0x41, 0x43, 0x59, 0x40, 0xAA, 0x70, 0xB8, 0xF5, 0xFA, 0x2A, 0x07, 0x16, 0x0C, 0xDD, 0x9B, 0x19, 0xF2, 0x6F, 0xCA, 0xD8, 0x0A, 0xCB, 0x7F, 0xF9, 0x9A, 0x54, 0x07, 0x6D, 0x15, 0xB2, 0xD3, 0x56, 0x32, 0xA8, 0x21, 0x02, 0x1C, 0x5A, 0x13, 0xE4, 0x65, 0x55, 0xC5, 0x63, 0x46, 0x92, 0x75, 0x29, 0x61, 0x64, 0xB9, 0xEB, 0xF3, 0x0A, 0x85, 0x6C, 0xCF, 0xFC, 0xDF, 0xBA, 0x21, 0xA0, 0xD6, 0xDB, 0xD3, 0x1B, 0xBC, 0xDF, 0x9E, 0x0D, 0x69, 0xDC, 0xF0, 0xBE, 0x3D, 0xAD, 0xBE, 0xC3, 0x6D, 0x99, 0xC1, 0x54, 0x39, 0xF8, 0xCB, 0x09, 0x29, 0x69, 0xD7, 0xDD, 0x03, 0x2F, 0x64, 0x83, 0xE6, 0x4A, 0x2C, 0x20, 0x43, 0x83, 0x41, 0x2E, 0x51, 0x07, 0x4D, 0x72, 0x3B, 0xD0, 0x51, 0xCD, 0x69, 0x1F, 0x45, 0x40, 0x26, 0xE0, 0xEB, 0x95, 0x75, 0x74, 0x56, 0xA0, 0x6A, 0x8D, 0x20, 0x8F, 0x03, 0x28, 0xCF, 0x0B, 0xA6, 0x06, 0x70, 0x96, 0xBE, 0xC5, 0x2E, 0x7C, 0xFE, 0x86, 0x49, 0x8D, 0xD3, 0xA0, 0x05, 0x59, 0xA2, 0x70, 0x5B, 0x07, 0x59, 0x03, 0x68, 0x6B, 0xAF, 0xD6, 0xE1, 0xF8, 0xD6, 0xA3, 0x78, 0x99, 0xB6, 0x86, 0x61, 0x7E, 0xA5, 0x32, 0xFC, 0xE8, 0x84, 0xAA, 0xA3, 0x9C, 0x58, 0xB6, 0x81, 0x15, 0xC7, 0x35, 0xCD, 0xF6, 0x75, 0x3B, 0x27, 0xBC, 0x57, 0xF4, 0xC9, 0xF5, 0xFA, 0xB6, 0xE9, 0x48, 0x1D, 0xB4, 0xFC, 0x75, 0x56, 0x77, 0x52, 0x9D, 0xE9, 0xAA, 0x90, 0x0A, 0xB0, 0xCC, 0xE7, 0x66, 0x3B, 0x03, 0x70, 0xCC, 0x4F, 0xBB, 0x04, 0x10, 0x7B, 0xCD, 0xEC, 0x5C, 0xCF, 0xCA, 0x6D, 0x4B, 0x36, 0x64, 0xDE, 0x02, 0xCE, 0xD6, 0xFE, 0x39, 0xA0, 0x7C, 0xA3, 0x46, 0xFF, 0xAA, 0xDB, 0xBB, 0xFC, 0x5B, 0x9C, 0xF4, 0xBD, 0x4D, 0x0F, 0xD3, 0xF7, 0x2A, 0xE8, 0x27, 0x53, 0x7B, 0xFE, 0x56, 0x11, 0xD2, 0x1D, 0x21, 0xE1, 0x43, 0x38, 0x64, 0xB5, 0x3C, 0xD0, 0xEF, 0x09, 0x9A, 0xD6, 0xD6, 0xAC, 0x09, 0xF0, 0x32, 0xF8, 0xD5, 0x03, 0x9C, 0x5C, 0x59, 0x5E, 0x03, 0x74, 0x4E, 0x08, 0x1A, 0xC9, 0xBA, 0xE1, 0x46, 0x44, 0x3B, 0x14, 0xA7, 0x51, 0x0B, 0xDA, 0xA0, 0x1F, 0xDA, 0xAB, 0xD4, 0xA9, 0xE8, 0x63, 0x5A, 0x6B, 0x2C, 0x97, 0x28, 0x72, 0xB9, 0x1B, 0x70, 0xDC, 0xA0, 0xFD, 0x59, 0x0D, 0xA1, 0x2C, 0x3E, 0xF6, 0x38, 0x2E, 0xC2, 0x0E, 0x60, 0x86, 0xBF, 0x58, 0xF6, 0x7E, 0xE9, 0x67, 0xBC, 0x3F, 0xE3, 0x5D, 0xD9, 0x97, 0x36, 0x2E, 0xF6, 0x48, 0xFA, 0x03, 0x18, 0x2F, 0x83, 0x93, 0x9C, 0x0F, 0xCA, 0x59, 0x5A, 0x31, 0x35, 0x80, 0xF2, 0xD7, 0x10, 0xC2, 0x9D, 0xBF, 0x16, 0x40, 0x15, 0xF0, 0x46, 0xFC, 0x84, 0x37, 0xF6, 0x3B, 0xC0, 0x00, 0xCA, 0xC6, 0x88, 0xE4, 0xDA, 0xEA, 0xF0, 0xB6, 0xD8, 0x41, 0x93, 0xEF, 0xD0, 0xC1, 0xA7, 0xBE, 0xB5, 0x75, 0xC2, 0xFF, 0xA9, 0xE1, 0x78, 0xEB, 0x02, 0xBF, 0xC8, 0x7E, 0xD3, 0x7D, 0x10, 0x69, 0xFF, 0x21, 0x8B, 0xE9, 0x6C, 0x52, 0x53, 0x09, 0xCB, 0xEF, 0xE6, 0x77, 0xF6, 0xE8, 0xE6, 0xBB, 0xC6, 0x12, 0xD0, 0x5A, 0x45, 0x03, 0x6A, 0xAC, 0x85, 0x27, 0x06, 0x90, 0xCC, 0x82, 0x02, 0x2F, 0x43, 0x31, 0x0B, 0x40, 0x19, 0x70, 0x99, 0x15, 0x13, 0x3B, 0x2B, 0xC9, 0x48, 0x0D, 0x9B, 0x63, 0xB6, 0xCF, 0x1A, 0xB3, 0xAF, 0xD6, 0x50, 0x40, 0x62, 0x2E, 0x7B, 0xDA, 0xB6, 0x93, 0x76, 0xA3, 0xA6, 0xFF, 0xA2, 0x7B, 0x32, 0xF9, 0x6B, 0x83, 0x2F, 0x54, 0xF1, 0xDC, 0xE0, 0x43, 0x14, 0x84, 0x32, 0x73, 0x45, 0x1F, 0x21, 0x0C, 0xAD, 0xD0, 0x44, 0x2D, 0x49, 0xD8, 0x47, 0x35, 0x99, 0x89, 0x0E, 0x3D, 0xD3, 0xC6, 0x4D, 0x02, 0xE0, 0xEB, 0x1E, 0xD1, 0x70, 0x07, 0xD4, 0x1A, 0x01, 0x84, 0xCD, 0xC1, 0xDA, 0xA1, 0x00, 0xE9, 0xD4, 0x05, 0xDE, 0xF8, 0x64, 0x43, 0x14, 0xA0, 0x0B, 0x06, 0x4E, 0x35, 0x74, 0xC1, 0x1A, 0xBE, 0xA4, 0x6A, 0x0E, 0x68, 0x36, 0xBC, 0x71, 0x00, 0x69, 0xEC, 0x11, 0x10, 0xE6, 0x37, 0x68, 0x48, 0xA2, 0x79, 0x12, 0xB2, 0xB6, 0xC2, 0xDF, 0x69, 0x33, 0xB3, 0xCB, 0x04, 0x4C, 0x30, 0x89, 0x4A, 0x41, 0x87, 0x3C, 0x34, 0x6A, 0x19, 0xC6, 0xBD, 0x99, 0xED, 0x44, 0x87, 0xCD, 0x9B, 0x94, 0xDD, 0xBC, 0x85, 0x2E, 0x8D, 0x5A, 0x1A, 0x20, 0x39, 0xA5, 0xF1, 0xDA, 0x10, 0x9E, 0x9F, 0x0C, 0x78, 0xBA, 0xC0, 0x2E, 0xDF, 0x3D, 0xE9, 0xF3, 0xB2, 0x8B, 0x13, 0x6B, 0xE8, 0x32, 0xF5, 0x90, 0x5F, 0xFE, 0x00, 0xD4, 0x58, 0xFE, 0x00, 0xC1, 0x40, 0x66, 0x23, 0x1A, 0x04, 0x78, 0x6C, 0xA7, 0x8F, 0x39, 0x81, 0x8B, 0x0F, 0x3C, 0xA8, 0xA9, 0x18, 0x16, 0x91, 0x21, 0xDF, 0x4A, 0xA3, 0x54, 0xA8, 0x21, 0x2D, 0xBA, 0x61, 0x3C, 0xFE, 0x7D, 0x1F, 0x10, 0xC2, 0x73, 0xDC, 0xA6, 0x71, 0xC2, 0x59, 0x6A, 0x48, 0xBF, 0xFD, 0x28, 0x76, 0x6B, 0x24, 0x04, 0x18, 0x03, 0xDA, 0x38, 0x34, 0x2C, 0xA5, 0x99, 0x00, 0x2A, 0x40, 0x1B, 0xA1, 0xB3, 0xB6, 0xF2, 0xB4, 0x3B, 0xD6, 0x0B, 0x8E, 0xE6, 0x04, 0xEE, 0x48, 0xC0, 0x75, 0xB5, 0x6C, 0xCB, 0x42, 0x4C, 0x14, 0xAF, 0x7D, 0x40, 0x01, 0xA3, 0xB9, 0x71, 0x48, 0x02, 0x2C, 0x00, 0x35, 0xB8, 0x61, 0x79, 0x83, 0x16, 0xE8, 0xC0, 0xFE, 0x5E, 0x91, 0x82, 0xDD, 0x8C, 0x09, 0x2D, 0x19, 0x8E, 0xAA, 0x0A, 0x0A, 0x03, 0x15, 0x68, 0x59, 0x39, 0x1F, 0x54, 0xAB, 0xE6, 0xEB, 0x93, 0x97, 0xDC, 0xEA, 0x29, 0x22, 0x6E, 0xDD, 0x8E, 0x81, 0x38, 0x80, 0x15, 0xC0, 0x36, 0xAD, 0x1D, 0x3C, 0x1B, 0x35, 0xE7, 0xD0, 0x53, 0xF6, 0xA7, 0x9A, 0x49, 0xB4, 0x62, 0x80, 0x97, 0x3A, 0x83, 0x03, 0xA0, 0xFA, 0x35, 0x77, 0x20, 0x00, 0xE3, 0x1F, 0xFE, 0x3A, 0xE1, 0x53, 0xD5, 0x71, 0x6A, 0xE1, 0x2A, 0x3E, 0xBC, 0x21, 0x4B, 0xA6, 0x55, 0x37, 0x68, 0xF9, 0x3D, 0x97, 0x26, 0x7D, 0xC9, 0x3E, 0x3A, 0xC6, 0xAF, 0x58, 0x7C, 0x61, 0xF2, 0x14, 0xFE, 0x56, 0x4F, 0x30, 0x52, 0x6A, 0xED, 0x15, 0x1C, 0xDB, 0xAD, 0x69, 0xD5, 0x20, 0xB1, 0x7D, 0xCD, 0xB5, 0x15, 0x31, 0x17, 0x1C, 0xC9, 0x5C, 0x4D, 0x05, 0x90, 0x76, 0x98, 0x08, 0x88, 0x86, 0x26, 0x40, 0x35, 0x83, 0xE6, 0x06, 0x48, 0x63, 0x8F, 0x5D, 0x54, 0x07, 0x7C, 0x1B, 0xD6, 0x4A, 0xA3, 0x80, 0x8A, 0xDB, 0xEB, 0x06, 0xB0, 0x01, 0x72, 0x11, 0x8D, 0xDC, 0x5F, 0x5C, 0xCE, 0x15, 0x6F, 0xA5, 0xD5, 0x67, 0x0B, 0x6C, 0x82, 0x41, 0x05, 0x64, 0x86, 0xD2, 0x5A, 0x12, 0xA6, 0x72, 0x55, 0xA0, 0xE4, 0xC0, 0x1F, 0x34, 0x82, 0x90, 0x50, 0x81, 0x85, 0x0E, 0xDB, 0xD6, 0xA8, 0x75, 0x41, 0xE2, 0x65, 0x5D, 0x62, 0x35, 0x7C, 0x46, 0x01, 0x56, 0xB3, 0x13, 0xD6, 0x0F, 0x40, 0x4B, 0x04, 0xEE, 0x0C, 0x48, 0xCC, 0x56, 0x29, 0xC9, 0x59, 0x6A, 0x7B, 0xBE, 0x86, 0xB6, 0xB2, 0x60, 0x7B, 0xFC, 0x40, 0xFE, 0xA8, 0xA6, 0x6C, 0xBB, 0xDC, 0x3C, 0x4B, 0xA7, 0x70, 0x80, 0x53, 0xCB, 0xD0, 0x59, 0xD7, 0xB8, 0xA0, 0x7B, 0x45, 0xBC, 0x41, 0x23, 0x2C, 0x2A, 0x69, 0x57, 0x6A, 0x2B, 0x74, 0xE3, 0x65, 0xE5, 0x27, 0x1C, 0x0A, 0x75, 0x48, 0xB6, 0x2A, 0xE1, 0x36, 0xA3, 0x8E, 0x45, 0xCF, 0x36, 0x1D, 0x3A, 0xC6, 0x58, 0xA4, 0x51, 0xFA, 0x8C, 0x0E, 0xD3, 0xDA, 0x59, 0xCD, 0x80, 0x23, 0x53, 0x5E, 0x78, 0x72, 0x3D, 0x27, 0x0D, 0xD2, 0xD9, 0x2D, 0xF4, 0x9C, 0xD2, 0x64, 0x9E, 0x20, 0xA8, 0x66, 0xED, 0xA9, 0x6C, 0xBE, 0x4B, 0x5D, 0x80, 0xD8, 0x46, 0x3A, 0x35, 0x8D, 0xE2, 0x69, 0xD9, 0x34, 0x1B, 0x37, 0x0E, 0xA0, 0x04, 0x70, 0xAC, 0x23, 0x87, 0xAE, 0x3D, 0x8D, 0x08, 0x7B, 0xBE, 0xDA, 0xB7, 0x99, 0x91, 0xF9, 0xE8, 0x91, 0xE2, 0x36, 0x09, 0x26, 0x33, 0x24, 0xE6, 0x8B, 0xD0, 0x88, 0x18, 0x31, 0x15, 0xDE, 0x67, 0xD5, 0x8B, 0x4B, 0x9F, 0x81, 0x59, 0xBF, 0x21, 0x73, 0x8A, 0x5F, 0xB4, 0x71, 0xA8, 0xDF, 0x90, 0x0C, 0x5C, 0x1F, 0xB3, 0x20, 0x40, 0xF4, 0xE5, 0xBD, 0x9E, 0xCB, 0x6F, 0x3E, 0xA3, 0x8C, 0xAA, 0xD9, 0x66, 0x26, 0xFA, 0x63, 0x80, 0x48, 0x38, 0x90, 0x67, 0x41, 0x1A, 0x0E, 0xD4, 0x4E, 0x47, 0x0A, 0x20, 0xD1, 0x30, 0x80, 0xAB, 0x41, 0x00, 0xD9, 0xFC, 0x4E, 0xA3, 0x1B, 0x34, 0xFE, 0x2A, 0x02, 0x7A, 0xEC, 0x9F, 0x2A, 0x12, 0x1D, 0x2F, 0x68, 0x5F, 0x0A, 0x48, 0x5B, 0xBD, 0xE8, 0x28, 0x5C, 0x48, 0xEF, 0x37, 0xF1, 0x73, 0x54, 0xEA, 0xF8, 0x97, 0x6F, 0x91, 0x06, 0x02, 0x43, 0x40, 0x15, 0xE0, 0x0E, 0x5C, 0xD7, 0x37, 0xCE, 0x51, 0x9E, 0x22, 0x5A, 0x4F, 0xF0, 0x92, 0x35, 0x87, 0xCE, 0x44, 0x99, 0xAE, 0x37, 0xA4, 0xAE, 0x83, 0x56, 0x34, 0xAA, 0xE6, 0x01, 0x96, 0xB4, 0xB1, 0xDE, 0x89, 0x52, 0x80, 0xCB, 0x0C, 0x6F, 0x64, 0x83, 0x00, 0x53, 0x40, 0x13, 0xB0, 0x00, 0xEA, 0xDC, 0xA0, 0x09, 0xCC, 0x20, 0x8F, 0xFF, 0x23, 0xAC, 0xDE, 0xF1, 0x22, 0xF0, 0x83, 0xCD, 0x8C, 0x93, 0xE0, 0x66, 0x83, 0x97, 0xA8, 0xBB, 0x66, 0xD7, 0x89, 0x77, 0xC6, 0x7B, 0x24, 0xDC, 0xE3, 0xF9, 0xF7, 0xA8, 0x6C, 0x73, 0x3C, 0x1D, 0xBE, 0xD0, 0x12, 0xC0, 0x89, 0xD9, 0x4B, 0xA0, 0x05, 0xD0, 0x53, 0x0D, 0xCF, 0xE1, 0x19, 0x7C, 0x66, 0x62, 0x4E, 0x79, 0x95, 0x86, 0x69, 0xA9, 0x57, 0x08, 0x10, 0xFD, 0x39, 0xA6, 0x18, 0xD0, 0x86, 0x15, 0xE0, 0x17, 0xFB, 0x0F, 0x5B, 0x23, 0xBE, 0x2C, 0x81, 0x88, 0x1B, 0x34, 0x45, 0xDB, 0xC0, 0xCD, 0xA8, 0x72, 0x8E, 0x5E, 0x02, 0x77, 0x41, 0x59, 0x92, 0xB4, 0x9F, 0xA0, 0x40, 0x32, 0x1B, 0x55, 0x98, 0xD8, 0x55, 0xBC, 0xA7, 0xD1, 0xCF, 0x59, 0x8D, 0xC3, 0x0B, 0x1E, 0x1E, 0x13, 0x09, 0x24, 0x01, 0xD2, 0x3F, 0x2A, 0x0F, 0xC0, 0x71, 0xD3, 0xBC, 0xB3, 0xBA, 0x1E, 0x01, 0x1C, 0xFA, 0x3B, 0x1B, 0x23, 0xCF, 0xF1, 0x92, 0xDB, 0xF5, 0xDE, 0x66, 0x1E, 0x80, 0x14, 0xA0, 0x34, 0x3F, 0xED, 0x97, 0xA1, 0x52, 0xC3, 0x01, 0x37, 0xE0, 0xED, 0x26, 0xDC, 0x38, 0xC0, 0x59, 0x73, 0x65, 0xA3, 0x80, 0xBC, 0x87, 0xA8, 0xB7, 0xD2, 0x0C, 0x8A, 0xA1, 0x60, 0x7C, 0xA3, 0xF2, 0x90, 0xC5, 0x97, 0x66, 0x2B, 0x0A, 0xF8, 0xFB, 0x85, 0x42, 0xE4, 0xFB, 0x2D, 0x15, 0xCA, 0x84, 0x94, 0x2D, 0xBB, 0x15, 0xF9, 0x93, 0x6F, 0x93, 0xE2, 0x81, 0xE4, 0xCE, 0xAD, 0x33, 0x52, 0xAC, 0x00, 0xE3, 0x8B, 0xD1, 0xA0, 0xAE, 0x0F, 0x58, 0x01, 0xD4, 0x47, 0x9E, 0x50, 0x40, 0x78, 0x46, 0x99, 0x18, 0xE1, 0x15, 0x47, 0x5C, 0xCD, 0x3A, 0xAE, 0x0C, 0xB0, 0x01, 0xA4, 0x00, 0x07, 0x20, 0x05, 0xA8, 0x01, 0x26, 0x8D, 0x02, 0xDC, 0x80, 0xD4, 0x4E, 0xAD, 0x27, 0xC0, 0xDC, 0x38, 0x13, 0xC4, 0x0D, 0x9A, 0xDF, 0x62, 0xD2, 0x41, 0xF3, 0xCF, 0x98, 0xA3, 0x4A, 0x71, 0x90, 0x20, 0x99, 0xD6, 0xA4, 0xAA, 0x5D, 0x22, 0x66, 0xC3, 0x1D, 0xC7, 0x19, 0x15, 0x5E, 0xD1, 0xA9, 0xBB, 0x95, 0x59, 0x30, 0xC6, 0xC7, 0xFE, 0xDE, 0xFE, 0x51, 0xD5, 0xCB, 0x49, 0x01, 0xE9, 0x9F, 0x5F, 0x09, 0xB8, 0x02, 0xC2, 0xC0, 0xB1, 0xB9, 0xC6, 0xD4, 0xE6, 0x52, 0x13, 0x7F, 0xEF, 0x93, 0xD6, 0x93, 0xF4, 0x8A, 0x0B, 0xE0, 0x14, 0x9E, 0x79, 0x9F, 0xCE, 0xF0, 0xEA, 0x80, 0xD4, 0x84, 0x52, 0xC3, 0xE7, 0x49, 0x3B, 0x1A, 0xC5, 0x0D, 0x02, 0x32, 0x1B, 0x04, 0x44, 0x00, 0xEF, 0x92, 0x43, 0xDA, 0x51, 0x0B, 0xDC, 0xD1, 0x4B, 0xB1, 0x1A, 0x24, 0xC7, 0x9B, 0x20, 0xB2, 0xDA, 0x39, 0x4B, 0x3F, 0x90, 0xE2, 0x93, 0xA3, 0x76, 0x15, 0xB2, 0xE5, 0x56, 0xA4, 0xDB, 0x0A, 0x26, 0x7A, 0xC5, 0xDD, 0xD5, 0x41, 0x00, 0xDF, 0xE2, 0x9C, 0x03, 0xC7, 0x10, 0x11, 0x53, 0x80, 0x68, 0xAA, 0x94, 0xA5, 0xE6, 0x1B, 0x44, 0x03, 0x38, 0xDA, 0xD1, 0x3A, 0x00, 0xE9, 0x14, 0xB5, 0x11, 0x03, 0xDE, 0x71, 0x25, 0x06, 0x24, 0x01, 0x6B, 0x78, 0x00, 0xD1, 0xA8, 0xDB, 0x85, 0xE4, 0x80, 0x9C, 0x05, 0x02, 0xD8, 0x1A, 0x01, 0x88, 0x00, 0x7E, 0x97, 0x1A, 0x9A, 0x09, 0x98, 0xA0, 0x50, 0x88, 0xA3, 0xFF, 0x38, 0x21, 0x56, 0xF6, 0x6F, 0x27, 0x17, 0xEC, 0x9A, 0x51, 0x38, 0x41, 0x86, 0x23, 0x09, 0x50, 0xD6, 0xE9, 0x8D, 0x2D, 0x82, 0x91, 0x3F, 0xAF, 0x72, 0x2C, 0xED, 0xE1, 0x55, 0x48, 0xCB, 0xAB, 0x50, 0x65, 0x4E, 0xC9, 0x70, 0x5E, 0x9D, 0xE3, 0xD1, 0x30, 0xE0, 0xD8, 0xCA, 0x94, 0x33, 0x70, 0x64, 0x56, 0x5C, 0x9C, 0x80, 0xB0, 0x69, 0xB5, 0x24, 0xF1, 0xEB, 0xAC, 0xCB, 0x8D, 0x35, 0x8E, 0xBB, 0xD6, 0x00, 0xB5, 0xA3, 0x8D, 0x7B, 0x7C, 0x6A, 0xA4, 0x03, 0x23, 0x25, 0x8A, 0xA0, 0xD5, 0xA7, 0x51, 0x93, 0xA8, 0x2F, 0xE3, 0xCD, 0x47, 0x90, 0xF4, 0x10, 0xFD, 0xAA, 0xEC, 0x47, 0x04, 0x69, 0x52, 0xFD, 0x70, 0x8E, 0x05, 0x0E, 0xFD, 0x2E, 0x73, 0x7C, 0x88, 0xAE, 0xA0, 0xD9, 0x99, 0x9D, 0x5C, 0x11, 0x80, 0x37, 0xC4, 0xE6, 0x5F, 0x46, 0x0D, 0x38, 0xB1, 0x06, 0xBC, 0x46, 0x83, 0x00, 0xF5, 0x99, 0xAF, 0xCF, 0xDD, 0x58, 0x5C, 0x0D, 0x59, 0x9E, 0x23, 0xB9, 0x46, 0x7B, 0x49, 0x23, 0x96, 0x98, 0x45, 0x00, 0x51, 0xC0, 0x18, 0x70, 0xFB, 0xA5, 0x74, 0x93, 0x1F, 0xF3, 0xD7, 0x42, 0x3B, 0x68, 0x8C, 0xA9, 0x51, 0x7C, 0x6C, 0x78, 0x1C, 0xDA, 0x17, 0xBB, 0xEF, 0xCA, 0x83, 0xA0, 0x11, 0x21, 0x77, 0x2B, 0x9D, 0xFE, 0x2E, 0xD3, 0x51, 0x54, 0x71, 0x5E, 0x9D, 0xB2, 0xC2, 0xB3, 0xD6, 0x1F, 0xD5, 0x38, 0x80, 0x78, 0xC7, 0x67, 0x69, 0xF1, 0xA4, 0xC1, 0xD4, 0x60, 0x80, 0x56, 0x9A, 0x5F, 0x0C, 0x60, 0x6A, 0x1C, 0x80, 0xAC, 0x51, 0x80, 0x26, 0x50, 0x31, 0x23, 0xA2, 0xB5, 0xA6, 0xF0, 0x72, 0xC3, 0x97, 0x27, 0x18, 0x03, 0x14, 0x0D, 0x05, 0x8E, 0xFD, 0xEF, 0xA1, 0x4D, 0x08, 0x1A, 0x7D, 0xED, 0x2A, 0x9C, 0x01, 0xC7, 0x73, 0x41, 0x26, 0x57, 0x32, 0xBE, 0x7B, 0x02, 0x57, 0xE2, 0xE7, 0x08, 0xA3, 0x0B, 0x2D, 0x18, 0x8F, 0x40, 0xF8, 0x9C, 0x69, 0xCF, 0xBB, 0xB6, 0x22, 0x6B, 0xDD, 0x6B, 0x35, 0x7C, 0x29, 0x8B, 0x0D, 0x90, 0xC6, 0x89, 0x86, 0x02, 0xDC, 0x90, 0x9A, 0x3D, 0x4A, 0xB6, 0xBD, 0xBA, 0x76, 0xBB, 0xBA, 0xCC, 0x70, 0xE9, 0x32, 0xF1, 0xA8, 0xF5, 0x47, 0x6F, 0x37, 0x6B, 0x4E, 0xC0, 0xD6, 0xE8, 0x0D, 0x8F, 0x1F, 0x69, 0x61, 0x69, 0x28, 0xAD, 0x93, 0x1A, 0xF3, 0xD7, 0xCA, 0xCE, 0x52, 0x5F, 0xF0, 0xD2, 0x03, 0x16, 0x6A, 0x84, 0x1A, 0xA8, 0x46, 0x21, 0xF5, 0x9F, 0xDD, 0x21, 0x15, 0xFD, 0x90, 0xA7, 0xC2, 0xAA, 0xE9, 0xB7, 0xEB, 0x50, 0xC7, 0x27, 0x69, 0xAA, 0x9A, 0xDC, 0xE6, 0xC1, 0x34, 0x74, 0x4A, 0x17, 0x83, 0x00, 0xE3, 0x2D, 0xB2, 0x9E, 0x15, 0x2C, 0xD9, 0xBA, 0x20, 0xFB, 0x51, 0x2D, 0x30, 0x01, 0xF2, 0x3D, 0xD0, 0x3F, 0x64, 0x69, 0x74, 0x1A, 0x02, 0xC8, 0x01, 0x6C, 0xCF, 0x8B, 0xA0, 0xF9, 0x45, 0x5D, 0xEA, 0x34, 0x25, 0x20, 0x5E, 0xD0, 0xE4, 0xF3, 0xB7, 0x3A, 0x36, 0x4B, 0x2C, 0xC4, 0xFA, 0x75, 0xB2, 0xBB, 0x04, 0x74, 0xF4, 0xCE, 0xF0, 0x76, 0x50, 0x6A, 0x7B, 0xC8, 0x33, 0x9A, 0x09, 0x34, 0xF6, 0xFC, 0x90, 0xC3, 0x80, 0x2F, 0x5F, 0xA5, 0x58, 0x1A, 0x56, 0xB2, 0x65, 0xB9, 0x42, 0x80, 0xDB, 0xFA, 0xB4, 0xB6, 0x2C, 0x6A, 0x9C, 0x8B, 0x33, 0x7F, 0x22, 0x3E, 0x83, 0x14, 0xF3, 0xFF, 0x71, 0x6E, 0x24, 0x10, 0xB2, 0xCB, 0x2C, 0x2B, 0xC4, 0x0C, 0x90, 0x36, 0x18, 0x38, 0xBB, 0x94, 0x4C, 0x8D, 0x98, 0x32, 0x6F, 0x66, 0x0C, 0xA6, 0x29, 0xF3, 0xAF, 0x0C, 0xE5, 0x69, 0x68, 0xEB, 0x66, 0x74, 0x61, 0x50, 0xBB, 0xE7, 0x94, 0xD0, 0x07, 0xD6, 0xC0, 0x4D, 0xAE, 0x6A, 0x4E, 0x7B, 0x93, 0x66, 0xC5, 0xD8, 0xCF, 0x0D, 0x18, 0x93, 0x62, 0x08, 0x38, 0x31, 0x75, 0xB3, 0x99, 0x80, 0xC4, 0x1C, 0x38, 0x65, 0x05, 0xB0, 0xCE, 0x91, 0x8B, 0xA2, 0xCB, 0x5B, 0xA1, 0x00, 0x31, 0x80, 0x56, 0xA3, 0x99, 0x09, 0x10, 0xD4, 0x48, 0x20, 0xA5, 0xE1, 0x8D, 0x04, 0x2A, 0xE7, 0x5E, 0xC6, 0xD1, 0xD0, 0xC6, 0x01, 0xA8, 0x71, 0x68, 0x79, 0xDA, 0xFB, 0x8D, 0x9A, 0x7D, 0x7E, 0xE7, 0xF2, 0xD7, 0x58, 0x20, 0x5F, 0x5E, 0xCD, 0x20, 0xEF, 0x6B, 0xDB, 0xF3, 0x30, 0x43, 0x85, 0x9F, 0x14, 0x3F, 0x0E, 0xFA, 0x21, 0x8E, 0x59, 0x6B, 0xA7, 0xB7, 0x09, 0x29, 0xAD, 0x77, 0x28, 0xCF, 0x50, 0xD0, 0xAA, 0xB8, 0x9F, 0xB5, 0x4B, 0x0B, 0x01, 0xE7, 0x2D, 0x04, 0x40, 0x6B, 0xAE, 0xA3, 0xE3, 0x0D, 0x6B, 0x70, 0xC3, 0x01, 0xE1, 0xA9, 0x22, 0xA0, 0xFD, 0x56, 0x58, 0xB2, 0x6D, 0x13, 0x60, 0x77, 0x57, 0x95, 0x35, 0x64, 0xBE, 0xC8, 0x63, 0xD5, 0xB8, 0xF3, 0xE9, 0xDD, 0x6E, 0xD0, 0xFC, 0x5F, 0xC5, 0x77, 0x2B, 0xBF, 0x41, 0x43, 0xA3, 0xAC, 0x62, 0x63, 0x3B, 0x72, 0x5B, 0xB2, 0x3F, 0xD8, 0xC1, 0xA1, 0x8D, 0x92, 0x6A, 0x4E, 0x33, 0x3E, 0x3B, 0x68, 0x6B, 0x2E, 0x6F, 0x05, 0x90, 0x09, 0xE8, 0x1A, 0xC4, 0xC9, 0x35, 0xFF, 0xDA, 0x16, 0x7B, 0x1E, 0xDC, 0x7C, 0xB2, 0xD8, 0x80, 0x93, 0x2B, 0x68, 0xE7, 0xCC, 0xE0, 0x71, 0xC3, 0x6C, 0x3D, 0x8B, 0xD1, 0xA8, 0x25, 0x50, 0x60, 0xA0, 0x6C, 0x1E, 0x47, 0x24, 0xF6, 0x0B, 0x7D, 0xD7, 0x41, 0xA7, 0x88, 0x57, 0xF5, 0x46, 0x2D, 0xBE, 0xE3, 0xAC, 0x47, 0x7D, 0x5E, 0x00, 0x96, 0xF6, 0x8F, 0xBF, 0xCC, 0x42, 0x21, 0x78, 0x37, 0xC5, 0xA7, 0xFD, 0xA2, 0x21, 0x6A, 0x81, 0x36, 0x4F, 0x37, 0xD2, 0x5A, 0x5D, 0x8C, 0xC2, 0xB3, 0x0F, 0x43, 0xCE, 0xAC, 0xE1, 0x5D, 0x0B, 0x83, 0x52, 0xE0, 0xC4, 0xAA, 0xAA, 0x17, 0xE0, 0x3B, 0xBE, 0x05, 0xC8, 0xF2, 0x3E, 0xC9, 0x86, 0x37, 0x2C, 0xE6, 0xE3, 0x96, 0x36, 0xBB, 0x32, 0xEA, 0xB5, 0xB8, 0xFE, 0x98, 0xF6, 0xAC, 0xB2, 0xC6, 0x98, 0x55, 0xC3, 0x80, 0xB0, 0xA5, 0x44, 0xBF, 0x48, 0xA0, 0xEC, 0x06, 0x2D, 0x3F, 0x61, 0x02, 0xDD, 0xB1, 0x21, 0x54, 0x3D, 0xB8, 0x0C, 0xAD, 0x9F, 0x5C, 0x86, 0x82, 0xAE, 0x77, 0xCE, 0x94, 0x02, 0x07, 0x56, 0xAD, 0x29, 0xF4, 0x96, 0x35, 0x44, 0xA4, 0x6E, 0x4E, 0xAA, 0x96, 0x61, 0x53, 0x02, 0xBC, 0xE4, 0xC2, 0xC4, 0xCB, 0xA6, 0x40, 0x1A, 0x01, 0xB8, 0xCC, 0xBD, 0x2D, 0x1A, 0x6A, 0x7B, 0x10, 0x66, 0x23, 0x00, 0x8B, 0xE9, 0x3A, 0x21, 0x8D, 0xDC, 0xC3, 0xDB, 0x6A, 0x19, 0x5A, 0xE7, 0xAA, 0xB3, 0x68, 0x83, 0x81, 0x54, 0x20, 0xCE, 0xAA, 0xC8, 0x70, 0x6F, 0xCC, 0x2F, 0x68, 0xF5, 0xCF, 0xDA, 0x8C, 0xD6, 0x3A, 0xCD, 0xF0, 0xAE, 0xA0, 0xDF, 0x6D, 0x28, 0x90, 0xFE, 0xD3, 0xC4, 0x62, 0x48, 0x69, 0xDF, 0xE2, 0x40, 0x3E, 0x6D, 0x7B, 0xA0, 0xF3, 0x30, 0x7C, 0x88, 0x77, 0x1F, 0x8E, 0xD3, 0xC8, 0x59, 0x8E, 0x32, 0x1D, 0xD3, 0xFB, 0x86, 0xA9, 0xE4, 0x48, 0x38, 0x86, 0x00, 0xEC, 0xF3, 0x7A, 0xA1, 0x0D, 0xB6, 0xD5, 0x9B, 0xC8, 0x7B, 0x3F, 0x98, 0x69, 0xC4, 0x8C, 0x99, 0xAC, 0x25, 0x9E, 0xB1, 0x13, 0x5E, 0x03, 0xDB, 0xBD, 0x61, 0x8D, 0x03, 0x18, 0xCF, 0xF0, 0x9A, 0x01, 0xC9, 0x1D, 0x34, 0x39, 0xDF, 0xDA, 0xD2, 0xCA, 0x4F, 0xD8, 0x77, 0xA2, 0xBA, 0x9A, 0x84, 0x52, 0x5E, 0x5A, 0xE0, 0x59, 0x4B, 0x87, 0xF0, 0x90, 0x09, 0xAF, 0x44, 0x52, 0x04, 0x6B, 0xA7, 0x88, 0x28, 0x66, 0xFD, 0xB3, 0x3A, 0x5A, 0x79, 0xCE, 0x68, 0x77, 0x72, 0x3E, 0x1F, 0x9E, 0x41, 0x79, 0x07, 0xAD, 0x12, 0xF0, 0x86, 0x06, 0x20, 0x34, 0x07, 0x10, 0x98, 0x01, 0xBC, 0x6C, 0x4E, 0xDC, 0x01, 0x6B, 0xE4, 0xF3, 0xA3, 0x9E, 0x65, 0x37, 0x61, 0xC0, 0x4E, 0x23, 0x01, 0x8F, 0x35, 0x1C, 0xEA, 0xD5, 0x7C, 0x16, 0x0E, 0x70, 0xAC, 0x21, 0x8D, 0x02, 0xE4, 0x05, 0x0D, 0x8E, 0x26, 0xCE, 0x78, 0x20, 0x93, 0x30, 0x04, 0x54, 0xBE, 0xDB, 0x14, 0xCE, 0xEE, 0xF8, 0xDB, 0xC2, 0xFE, 0xB6, 0x4A, 0x0D, 0xCB, 0x95, 0xED, 0xC7, 0x8C, 0x9F, 0x29, 0x51, 0x8B, 0xB7, 0xA8, 0x6A, 0x68, 0xBA, 0xF3, 0x69, 0x40, 0x69, 0xB9, 0x39, 0x9C, 0xF1, 0x64, 0x20, 0x83, 0x36, 0x83, 0x76, 0x00, 0xCA, 0x19, 0x26, 0xA6, 0xD5, 0x00, 0xD6, 0xA8, 0xBB, 0xB6, 0xD6, 0x50, 0xF5, 0x5A, 0xE3, 0x1A, 0xD8, 0x01, 0x31, 0xC0, 0x14, 0xC8, 0x1B, 0x18, 0x6D, 0x9C, 0x59, 0x33, 0x8C, 0x25, 0xA3, 0x88, 0x7C, 0x65, 0xFB, 0x0E, 0x1A, 0x7F, 0x2A, 0x2B, 0x0D, 0x74, 0xAD, 0xB8, 0xF7, 0xEB, 0xB6, 0x0C, 0xBE, 0x60, 0x19, 0xD8, 0xC7, 0xAB, 0x3E, 0x30, 0x67, 0xB7, 0x02, 0xC4, 0x74, 0x83, 0xF1, 0x11, 0xB4, 0x2E, 0xB4, 0x75, 0x26, 0xAE, 0x25, 0xDA, 0x02, 0x64, 0x02, 0xB7, 0xBB, 0x38, 0x6A, 0xD6, 0x59, 0xEE, 0x90, 0xC3, 0x74, 0x40, 0xEA, 0xF6, 0x12, 0x7C, 0x90, 0xD7, 0x40, 0x3A, 0x0B, 0x08, 0xA6, 0x73, 0x15, 0xC6, 0x99, 0x31, 0x37, 0x9F, 0x4B, 0x45, 0xE9, 0xD7, 0x24, 0x91, 0x46, 0xE9, 0x1C, 0xB3, 0x25, 0xDA, 0x10, 0x80, 0x13, 0xA0, 0x6A, 0x30, 0xC0, 0x04, 0x98, 0xDC, 0xA0, 0xC9, 0x1B, 0x6B, 0x6F, 0x9F, 0x1A, 0x32, 0x86, 0x03, 0x1D, 0x1D, 0xFA, 0x7E, 0xB8, 0xA5, 0x20, 0xE4, 0xF0, 0xF2, 0x16, 0x2B, 0x9E, 0x19, 0x22, 0x59, 0x69, 0x35, 0x7E, 0x2E, 0x4D, 0xDE, 0x09, 0x6B, 0x02, 0xAE, 0xF6, 0xD8, 0x6E, 0x62, 0xAB, 0xBF, 0x25, 0xE4, 0x1A, 0x23, 0x0E, 0xE3, 0xC8, 0x08, 0x40, 0xCE, 0x1C, 0x6B, 0x4F, 0x32, 0xEB, 0x2C, 0xBA, 0xA4, 0xC4, 0xA7, 0x00, 0xB7, 0x39, 0xA9, 0xEC, 0x26, 0x13, 0x8D, 0x81, 0x8C, 0xBB, 0x47, 0x08, 0x40, 0x0E, 0x88, 0xCD, 0x1C, 0x5D, 0x58, 0x23, 0x1A, 0x04, 0xF8, 0xF6, 0xE8, 0x3F, 0x40, 0x65, 0x07, 0x4D, 0x91, 0xDE, 0x48, 0xC5, 0x85, 0x3D, 0x08, 0xC9, 0xC3, 0xE2, 0x2F, 0x17, 0x69, 0x3D, 0x37, 0x3B, 0xC2, 0x70, 0x00, 0xF0, 0xDE, 0xAB, 0x43, 0x3B, 0x33, 0xB4, 0xAB, 0x52, 0xB1, 0xEA, 0x9F, 0x39, 0xDB, 0x3B, 0x43, 0x00, 0x79, 0xA5, 0xF2, 0xF9, 0xEC, 0x09, 0xCD, 0x97, 0xBE, 0xC5, 0xBA, 0xAB, 0xDA, 0xBA, 0xEE, 0xF3, 0xB4, 0x40, 0xA9, 0xF8, 0x61, 0x64, 0x6E, 0x8D, 0x94, 0x59, 0x11, 0x3E, 0xF1, 0x3F, 0x1C, 0xAE, 0x12, 0x08, 0x6B, 0x10, 0xE0, 0x0D, 0xCD, 0xC6, 0x69, 0x38, 0x90, 0x79, 0x57, 0x1A, 0x4E, 0x66, 0xA7, 0x1C, 0x5D, 0xFF, 0xD0, 0x6D, 0x90, 0x88, 0x7D, 0x21, 0x54, 0x37, 0x74, 0x93, 0xA5, 0x62, 0x26, 0x86, 0x39, 0x5E, 0xBA, 0x42, 0x48, 0xDC, 0xEE, 0x0C, 0xD1, 0x3B, 0xEF, 0xDF, 0x4D, 0x22, 0x97, 0x10, 0xA6, 0x5F, 0x04, 0x7A, 0xA6, 0xFD, 0x50, 0x39, 0x20, 0xD1, 0x21, 0xB4, 0x5D, 0x69, 0x07, 0x0E, 0xCD, 0x7A, 0x9B, 0x3A, 0x20, 0xD5, 0x20, 0x40, 0xF9, 0xCF, 0xD3, 0x2A, 0x5E, 0xC1, 0xD4, 0xD7, 0xE4, 0xE6, 0x48, 0xA0, 0x62, 0x3B, 0x95, 0x25, 0xA0, 0x05, 0x38, 0x35, 0xB8, 0xA1, 0x8D, 0x3D, 0xE1, 0x4C, 0x80, 0x8A, 0x0E, 0x9A, 0x7F, 0x29, 0xDB, 0x60, 0xFA, 0xD4, 0x43, 0x27, 0x7C, 0x54, 0xA5, 0x4E, 0x16, 0x1E, 0xAB, 0xE4, 0xF6, 0x21, 0x97, 0xCE, 0x4F, 0x27, 0x26, 0xB2, 0xEF, 0x52, 0x9E, 0xC8, 0xDB, 0xA6, 0x3B, 0xBB, 0x1F, 0xB3, 0x89, 0xA0, 0x12, 0xC0, 0x17, 0xBD, 0x37, 0x3A, 0xFC, 0xBE, 0x5D, 0xF7, 0xE8, 0xE6, 0x15, 0x01, 0xA4, 0xB3, 0xDE, 0x29, 0x00, 0xEB, 0xF5, 0xED, 0x00, 0x48, 0xE6, 0x2C, 0x0B, 0x69, 0x70, 0x23, 0xB9, 0xF7, 0xC9, 0xDB, 0xBD, 0x56, 0x40, 0xF8, 0xB4, 0xB5, 0x90, 0x03, 0x28, 0x03, 0xDE, 0xC8, 0xDB, 0x2C, 0x23, 0x8D, 0xFE, 0x62, 0x55, 0x83, 0x81, 0x0C, 0xE0, 0x19, 0xE0, 0x57, 0x07, 0x2D, 0xE0, 0xFB, 0xE2, 0xFE, 0xAF, 0x08, 0xC3, 0xDE, 0xFE, 0xEA, 0x9F, 0xEC, 0x81, 0xB3, 0x57, 0x32, 0x12, 0xCC, 0x61, 0x9D, 0x86, 0xCD, 0xB6, 0xCE, 0xD9, 0x2B, 0xED, 0xB9, 0xB2, 0xCC, 0x23, 0x52, 0xFD, 0xAA, 0xFA, 0xCA, 0xF3, 0x77, 0x5B, 0x76, 0x7D, 0x6B, 0x18, 0x80, 0x2E, 0xA9, 0x69, 0x08, 0xE0, 0x34, 0x61, 0x09, 0xF8, 0x32, 0x6B, 0x7A, 0x0D, 0xAF, 0x0C, 0x58, 0x23, 0x0F, 0x50, 0x34, 0xC7, 0x96, 0x93, 0x00, 0xD2, 0x50, 0x6D, 0xC8, 0x5A, 0xCB, 0xB2, 0x86, 0x86, 0xDA, 0x92, 0x27, 0x48, 0xFE, 0xD3, 0xCF, 0x9D, 0xFC, 0xDE, 0xD8, 0xE7, 0x50, 0x87, 0x10, 0xFE, 0xC2, 0xD4, 0xEA, 0xF8, 0x08, 0x0F, 0x94, 0xB8, 0xE9, 0x8C, 0xA9, 0xBC, 0xAA, 0xAB, 0xB7, 0x8C, 0xE5, 0xBE, 0xD4, 0x66, 0xF1, 0x37, 0xFC, 0x6F, 0x17, 0xB3, 0x27, 0xAE, 0xC8, 0xE5, 0x21, 0x21, 0x34, 0x33, 0x49, 0x6C, 0x53, 0x64, 0x2C, 0x2B, 0x01, 0xC4, 0xA7, 0x41, 0x80, 0x74, 0x94, 0x5F, 0x8A, 0xEE, 0xD9, 0x9B, 0xCE, 0x06, 0x15, 0x4B, 0x20, 0xCF, 0x54, 0x50, 0x11, 0x01, 0x62, 0x80, 0xD6, 0x82, 0x01, 0xA2, 0x0D, 0x6E, 0x38, 0xE0, 0x7A, 0x83, 0xD6, 0xB6, 0x43, 0xF4, 0xE7, 0xD4, 0x51, 0xE8, 0x9E, 0xF5, 0x2F, 0x5B, 0xC1, 0x50, 0xE8, 0xB0, 0x23, 0x1B, 0xA3, 0x37, 0x53, 0x53, 0xD3, 0x38, 0xC1, 0x77, 0x93, 0xB1, 0x4F, 0xC7, 0x0D, 0xF1, 0xE9, 0x20, 0xE7, 0x8D, 0xE3, 0xB3, 0x5D, 0xA0, 0x1A, 0x96, 0x80, 0x6C, 0x77, 0xF3, 0x04, 0x84, 0x77, 0xB4, 0x1A, 0x0C, 0x48, 0x23, 0xDF, 0xA5, 0x6A, 0x25, 0x59, 0x96, 0xE6, 0x85, 0x7D, 0x49, 0x5F, 0x04, 0x08, 0x5F, 0x83, 0xA6, 0xAB, 0xE1, 0xEB, 0x0A, 0x5A, 0xC0, 0x6D, 0xAD, 0xA7, 0x1B, 0x34, 0x3D, 0xFF, 0x02, 0x25, 0xF6, 0x17, 0x34, 0xFD, 0x12, 0x22, 0xAD, 0x88, 0x3C, 0x85, 0x04, 0x93, 0x05, 0xD2, 0xA8, 0x46, 0x58, 0xFB, 0x6C, 0xE3, 0x1A, 0x95, 0xB7, 0xD2, 0xFE, 0x6E, 0xD5, 0x6B, 0x80, 0x96, 0x18, 0x40, 0x31, 0xFD, 0xC0, 0x6A, 0x1B, 0xE8, 0x3B, 0x40, 0x39, 0xD3, 0x5D, 0x7E, 0x66, 0x9E, 0xC1, 0xF6, 0x60, 0xD9, 0x65, 0xB0, 0xA6, 0x06, 0x8C, 0xB4, 0xFE, 0x5F, 0xD6, 0xBA, 0x96, 0xCC, 0x96, 0x0D, 0x10, 0x06, 0x6C, 0x99, 0x58, 0x95, 0x36, 0x08, 0xC8, 0xB3, 0x6C, 0x22, 0x1B, 0x2E, 0x40, 0xF9, 0x0D, 0x1A, 0x7A, 0x07, 0x70, 0x5C, 0x52, 0xB4, 0xAB, 0xB0, 0xC3, 0xD0, 0xC4, 0xD0, 0x6A, 0x86, 0xC3, 0xB7, 0x25, 0xA6, 0xB1, 0x49, 0xFF, 0xCE, 0x1C, 0xF3, 0xED, 0xA9, 0xCB, 0x76, 0x88, 0xEB, 0x3E, 0x12, 0x4B, 0x8F, 0xB7, 0xEE, 0xC3, 0x47, 0xA6, 0xCA, 0x5B, 0x5E, 0x06, 0x7E, 0x9D, 0x27, 0x12, 0xB8, 0x61, 0xCA, 0xF8, 0xE5, 0xD8, 0xE2, 0xC0, 0xCC, 0x79, 0xDC, 0x53, 0xA2, 0xFD, 0xD9, 0x04, 0x00, 0xA5, 0x6B, 0xB4, 0x7D, 0x00, 0xDA, 0x88, 0x02, 0x2A, 0x1A, 0x0A, 0x64, 0x00, 0x41, 0xEB, 0x46, 0xC0, 0xEF, 0x58, 0xD0, 0x41, 0xE3, 0xEF, 0x54, 0x5B, 0x85, 0xDB, 0x66, 0x78, 0x4D, 0x53, 0x4D, 0xF1, 0x36, 0xC4, 0xF2, 0xF6, 0x26, 0x0C, 0xA8, 0x87, 0xDC, 0xA6, 0x71, 0x82, 0x2D, 0xC1, 0x32, 0xEB, 0x38, 0x49, 0x7E, 0xB9, 0x6F, 0x20, 0x64, 0xF6, 0x6E, 0x66, 0xB4, 0x1E, 0x66, 0x4A, 0x26, 0xCE, 0xBA, 0x3F, 0xC5, 0x0A, 0xAF, 0xD8, 0xCC, 0xCE, 0xC5, 0x96, 0x0D, 0xD9, 0x2C, 0xB7, 0xDE, 0x50, 0x38, 0x4F, 0xAF, 0x0B, 0x6F, 0xA4, 0x01, 0x55, 0xEB, 0x80, 0xCF, 0x40, 0x5C, 0x10, 0xE0, 0x0C, 0x18, 0x01, 0xCA, 0x80, 0x09, 0x50, 0x72, 0x83, 0x26, 0xFF, 0x54, 0x21, 0x44, 0x70, 0x47, 0xF3, 0xFF, 0xB7, 0xD2, 0x44, 0x11, 0x34, 0x25, 0x2C, 0x94, 0x16, 0x2C, 0x6B, 0x38, 0xB4, 0x3C, 0x78, 0x11, 0x44, 0x6C, 0x27, 0x52, 0xF2, 0x69, 0xA5, 0x46, 0x72, 0x63, 0x17, 0xE3, 0x9C, 0xF6, 0x66, 0x95, 0xD6, 0x1C, 0xD3, 0x74, 0x72, 0x26, 0x91, 0xAC, 0x00, 0x6D, 0x9C, 0x33, 0x05, 0xC4, 0xC7, 0xE7, 0x33, 0x14, 0x17, 0xF7, 0x5E, 0x3A, 0x74, 0xB9, 0xF9, 0x7E, 0x79, 0x7B, 0x87, 0x45, 0x05, 0xB8, 0x21, 0x09, 0x38, 0x01, 0x75, 0xE6, 0x28, 0xD9, 0xE3, 0xFD, 0xC5, 0x04, 0xD2, 0x1B, 0xD4, 0xE8, 0x72, 0x3D, 0x6B, 0x07, 0x4D, 0xFF, 0x69, 0xC1, 0xDC, 0x30, 0x90, 0xBB, 0x1A, 0x92, 0x0E, 0xE1, 0x68, 0xDF, 0x15, 0xC5, 0xC3, 0x5D, 0x85, 0x6C, 0x8A, 0xD4, 0xCB, 0x6E, 0x80, 0xFB, 0x70, 0x8B, 0x50, 0xBC, 0x9B, 0x7A, 0xAE, 0xE1, 0xFB, 0xE7, 0x4C, 0x8B, 0xD6, 0xBB, 0x38, 0x44, 0x7E, 0x24, 0xD9, 0x3C, 0x66, 0xD9, 0xCA, 0x77, 0xDF, 0xB4, 0x02, 0x4C, 0x0D, 0x07, 0xD2, 0x6F, 0x5C, 0x67, 0x06, 0xCD, 0xAF, 0xE6, 0x92, 0xD7, 0xBD, 0xBD, 0xA1, 0x06, 0x6C, 0x9D, 0x7D, 0x12, 0x10, 0x2B, 0x1F, 0xE2, 0xB6, 0x1E, 0x4F, 0xBE, 0x2B, 0xCD, 0xFE, 0x49, 0x6B, 0x6F, 0xE3, 0x4B, 0xDD, 0xC7, 0x0B, 0x9A, 0xD3, 0x15, 0x2C, 0x53, 0x96, 0x43, 0x3F, 0x4E, 0x48, 0x14, 0x89, 0xD4, 0x92, 0xC6, 0x2F, 0x71, 0xDF, 0x70, 0x37, 0x18, 0x5D, 0xFF, 0x4C, 0x7D, 0x23, 0x98, 0x4A, 0x77, 0xB9, 0x79, 0xAA, 0x98, 0x4D, 0xAD, 0x22, 0x33, 0x41, 0x2E, 0x31, 0x2B, 0xF3, 0xB1, 0x6E, 0x53, 0xBE, 0x72, 0xB5, 0x31, 0x46, 0xDA, 0x23, 0x53, 0x3C, 0x04, 0x30, 0xF5, 0x26, 0x19, 0xDB, 0x9A, 0x64, 0xAC, 0x40, 0xDE, 0x25, 0xC6, 0x0D, 0x6D, 0x8C, 0x81, 0xC6, 0xC0, 0x58, 0x8C, 0xEF, 0xF1, 0xF4, 0x7F, 0xDA, 0x5D, 0xE5, 0x11, 0x38, 0x59, 0xCB, 0xF7, 0x6E, 0xC4, 0x4D, 0xD4, 0x5C, 0x71, 0xEC, 0x21, 0xC6, 0x8B, 0x9C, 0xEF, 0xDB, 0x24, 0x86, 0xDB, 0x44, 0xE4, 0x32, 0x4E, 0x38, 0xF7, 0x75, 0xBD, 0xC6, 0xAB, 0xB8, 0x4F, 0xC3, 0x56, 0xD3, 0xA9, 0x85, 0x55, 0x06, 0xE8, 0xCC, 0x5E, 0x9E, 0xE4, 0x25, 0x60, 0xF0, 0x35, 0x0C, 0x2B, 0x1B, 0x0C, 0x94, 0xCE, 0x76, 0x9F, 0xE2, 0xD9, 0xC7, 0x1E, 0x31, 0xDF, 0x00, 0xC2, 0x80, 0x0A, 0x60, 0xB5, 0x67, 0xAE, 0x37, 0xB4, 0xC1, 0x40, 0x6A, 0xE3, 0x00, 0x75, 0x4F, 0x9E, 0x75, 0x83, 0x16, 0xD0, 0x89, 0x55, 0x7E, 0x4F, 0x29, 0x19, 0x0D, 0x4B, 0x6A, 0x0E, 0x6D, 0xF9, 0x94, 0x40, 0x10, 0x2B, 0xD5, 0xB7, 0x36, 0x6A, 0x7B, 0xC8, 0x9D, 0x1A, 0x1A, 0xB2, 0x16, 0xA2, 0x77, 0x67, 0x51, 0x6A, 0x78, 0x5F, 0x6B, 0xAE, 0x40, 0x68, 0xA8, 0x78, 0xD0, 0x5D, 0xF5, 0x41, 0x64, 0xFA, 0xBD, 0xCA, 0x9C, 0x04, 0x2B, 0x06, 0x90, 0x02, 0xA7, 0x1A, 0x0C, 0xBC, 0xFC, 0x8D, 0xDF, 0xBD, 0xC9, 0xDE, 0x4F, 0xC0, 0xD5, 0xEC, 0xF9, 0xF0, 0x00, 0x69, 0xB7, 0xE9, 0x1B, 0xE0, 0x02, 0x4C, 0x00, 0x77, 0x20, 0x68, 0x81, 0x1B, 0x0E, 0xA4, 0x74, 0x07, 0xF9, 0x0D, 0x5A, 0x62, 0xA5, 0xD9, 0xAA, 0xE1, 0x1D, 0x6F, 0x39, 0x0C, 0xE1, 0x36, 0x8C, 0xDB, 0x54, 0x2A, 0x77, 0x58, 0x34, 0x46, 0x8D, 0xC0, 0x6B, 0x0D, 0xAA, 0xB9, 0x4D, 0x11, 0x7A, 0x73, 0x5F, 0xB1, 0x3C, 0x48, 0x62, 0x5A, 0x53, 0xC5, 0x59, 0xC6, 0xF1, 0x09, 0x10, 0xAD, 0x3E, 0xC5, 0x9C, 0x17, 0x27, 0xB5, 0x5F, 0x7E, 0x70, 0xF7, 0xF6, 0x36, 0x84, 0xE0, 0xBD, 0x7E, 0xFA, 0xC5, 0x33, 0xBD, 0x40, 0x4C, 0x81, 0xD0, 0xF9, 0x40, 0x8A, 0x02, 0x66, 0x0D, 0x01, 0x34, 0x01, 0x91, 0x3D, 0x61, 0x1C, 0x08, 0xEA, 0xA0, 0xD5, 0xB7, 0xD2, 0x72, 0x5B, 0x6B, 0xF6, 0x4A, 0xA3, 0x20, 0xEC, 0xEA, 0x6C, 0xD8, 0x9D, 0xA3, 0xCF, 0xC4, 0x2C, 0x9D, 0x4F, 0xDB, 0x5E, 0x4D, 0x63, 0x64, 0x27, 0xC6, 0xD9, 0xCD, 0xCC, 0xD4, 0x69, 0xA9, 0xF3, 0xBD, 0xB3, 0x0C, 0xBF, 0x69, 0xBC, 0x0C, 0xC7, 0x35, 0x41, 0xCE, 0x72, 0x57, 0xCE, 0xD9, 0xA4, 0xAE, 0xA7, 0xB1, 0xBE, 0x98, 0xD6, 0x31, 0xE7, 0x7B, 0xC9, 0x1D, 0x3E, 0x2A, 0xB8, 0xC2, 0x62, 0x81, 0x67, 0x5F, 0xD8, 0x1D, 0xF0, 0x02, 0xF6, 0x00, 0x3A, 0x29, 0x40, 0xB5, 0x11, 0xEB, 0x93, 0x01, 0xD6, 0xB8, 0xE7, 0xB4, 0x2B, 0xB1, 0x0B, 0x41, 0xD1, 0xD8, 0x64, 0xBC, 0x08, 0x82, 0x0B, 0xBD, 0x2A, 0x92, 0xC8, 0xC2, 0xF4, 0x54, 0xE3, 0x34, 0x1A, 0xFA, 0x17, 0xDB, 0xC3, 0xB7, 0xE2, 0xBC, 0x23, 0xD2, 0x90, 0x28, 0xFB, 0x99, 0x67, 0x8D, 0x5B, 0xCC, 0xD0, 0xA7, 0xE1, 0x9F, 0xA2, 0x6D, 0x5E, 0x3D, 0xEE, 0xBB, 0x8B, 0xD4, 0x03, 0x08, 0x6B, 0x5C, 0xA7, 0xDF, 0x91, 0xED, 0x8A, 0x77, 0x4A, 0x7C, 0xCB, 0xA8, 0x74, 0x66, 0x42, 0xED, 0x00, 0x79, 0xFD, 0x3D, 0x97, 0xEE, 0x54, 0xA9, 0x11, 0x80, 0x69, 0xC3, 0x00, 0x27, 0x20, 0x0E, 0x50, 0xD4, 0x41, 0xA3, 0x4F, 0x10, 0x69, 0x87, 0x60, 0xAD, 0x29, 0x7F, 0xDA, 0xDB, 0xAF, 0x50, 0xEA, 0x3D, 0x93, 0x36, 0xE0, 0xCC, 0x50, 0x86, 0x75, 0x17, 0xD6, 0x66, 0x30, 0xBB, 0x9F, 0x40, 0x57, 0xBA, 0x9B, 0x6F, 0x66, 0xFB, 0x4C, 0x3B, 0x0D, 0xE2, 0xCE, 0x6F, 0x4D, 0x83, 0x6A, 0x39, 0xAB, 0x3F, 0xD1, 0x80, 0x63, 0x53, 0xD7, 0x16, 0x0D, 0x73, 0xC0, 0x0F, 0x60, 0x39, 0xCF, 0x1A, 0x1C, 0xEB, 0x78, 0x98, 0x79, 0xD5, 0x95, 0x33, 0x43, 0xC4, 0x04, 0x68, 0x02, 0x77, 0xA7, 0x3A, 0x01, 0xF0, 0x45, 0xAD, 0x4F, 0xD4, 0x38, 0x8D, 0x02, 0x5C, 0x3B, 0x68, 0x0C, 0xED, 0xAD, 0xE4, 0x7E, 0x3C, 0x7B, 0x76, 0x08, 0x75, 0xDF, 0x82, 0x42, 0xD7, 0x13, 0xDD, 0xB2, 0x96, 0x32, 0xE4, 0x2F, 0x5A, 0x6B, 0xA5, 0x99, 0xBC, 0x53, 0xCD, 0x4B, 0x03, 0xBE, 0xCE, 0xA7, 0xB8, 0x63, 0xAD, 0xDF, 0x91, 0x4C, 0x97, 0x33, 0xB0, 0xD7, 0xBA, 0x3F, 0xD9, 0x6C, 0x89, 0x96, 0x06, 0x73, 0xC3, 0x1B, 0x05, 0xD8, 0x10, 0x9F, 0xD9, 0xAB, 0x8C, 0x74, 0x08, 0x5F, 0x1D, 0xD1, 0x69, 0x27, 0x21, 0x0B, 0x50, 0x05, 0xA2, 0x51, 0xDC, 0x90, 0xC6, 0x01, 0x52, 0x1A, 0x04, 0xD4, 0x07, 0xFC, 0x2D, 0x10, 0x34, 0xF9, 0xC7, 0x0C, 0xE3, 0x84, 0x1D, 0x34, 0xFF, 0x72, 0x25, 0x82, 0xCA, 0x6F, 0x08, 0x0E, 0x97, 0x52, 0xE8, 0xF7, 0x75, 0xE9, 0x3C, 0xDA, 0x96, 0xDE, 0xDA, 0x7C, 0x11, 0x04, 0xCD, 0x3B, 0xDD, 0x9E, 0xDD, 0xE0, 0x3C, 0xE7, 0x27, 0xA6, 0x00, 0x4C, 0x53, 0x63, 0xC1, 0x4B, 0xE3, 0xB3, 0x9B, 0xFD, 0x85, 0x1B, 0x0E, 0xD8, 0x98, 0x67, 0xA3, 0xCF, 0xBA, 0xED, 0x75, 0xF1, 0xD9, 0x72, 0x29, 0xAE, 0x79, 0xDE, 0xAE, 0x5A, 0x21, 0x14, 0x6A, 0x68, 0xC3, 0x17, 0x56, 0x94, 0xDD, 0x3A, 0x68, 0xFA, 0xA2, 0x45, 0x8A, 0x12, 0x5E, 0x10, 0xE4, 0xEF, 0x48, 0x42, 0x22, 0x27, 0x94, 0x61, 0xD8, 0xAE, 0x3A, 0x76, 0x24, 0x32, 0x3A, 0x8C, 0x4D, 0xB7, 0x20, 0xB2, 0x63, 0xE0, 0xBC, 0xC6, 0x02, 0x24, 0x70, 0xD6, 0xA0, 0x95, 0xAC, 0x2D, 0x02, 0xBC, 0x63, 0x45, 0x76, 0x67, 0xE1, 0x6C, 0x33, 0x13, 0x1F, 0xD9, 0x91, 0xF9, 0xF3, 0x86, 0x1F, 0xB2, 0x02, 0xB1, 0xBD, 0x39, 0xBC, 0x61, 0x13, 0xBE, 0x94, 0xA9, 0xD5, 0x48, 0xFF, 0xE5, 0x3F, 0xC7, 0xF7, 0xD3, 0xF4, 0x9F, 0xE3, 0xB7, 0xC4, 0xDA, 0x55, 0x39, 0xB2, 0xC7, 0x3B, 0xA0, 0x62, 0x20, 0xA5, 0x38, 0x47, 0x26, 0xE1, 0xB6, 0x97, 0xDC, 0x6A, 0x5E, 0xBC, 0x08, 0xE4, 0xA7, 0x6D, 0xC2, 0x9B, 0xCD, 0xD3, 0xF0, 0x46, 0x28, 0xE0, 0x01, 0x58, 0x35, 0x18, 0xF0, 0xBB, 0xFC, 0xE8, 0xB5, 0xE8, 0x8D, 0x46, 0x5A, 0x8F, 0xBF, 0xA1, 0xFE, 0xF1, 0x6E, 0xA2, 0xF2, 0x41, 0x5E, 0xBA, 0x32, 0x78, 0x39, 0xCE, 0xC9, 0x32, 0x75, 0xE1, 0x5F, 0x96, 0x13, 0xB1, 0x86, 0xD4, 0xE8, 0x72, 0xE8, 0xF8, 0x3D, 0x6B, 0x79, 0x0D, 0xA9, 0xF1, 0x1B, 0x34, 0xEF, 0xA0, 0xB5, 0xAB, 0xB2, 0xDA, 0x27, 0xF4, 0x23, 0x95, 0x4F, 0xAF, 0x76, 0xAD, 0x73, 0x0A, 0xE7, 0x34, 0x0D, 0x6E, 0x31, 0x29, 0xB7, 0x73, 0xCE, 0xCE, 0x72, 0x6C, 0x8D, 0x70, 0xFA, 0xB4, 0x2E, 0xA9, 0x9A, 0x87, 0x78, 0x5F, 0xD2, 0xDB, 0x27, 0xD4, 0xE8, 0x10, 0xD6, 0xD2, 0x00, 0x44, 0x0D, 0x87, 0xC4, 0xE1, 0xDA, 0x38, 0xE4, 0x46, 0x94, 0x6B, 0xA9, 0x2C, 0x05, 0x9F, 0x5F, 0x70, 0x83, 0xF6, 0xC2, 0x01, 0x6A, 0x7B, 0x71, 0xD4, 0xFA, 0xC3, 0xCE, 0x8C, 0x79, 0xEA, 0x1C, 0xF3, 0xC6, 0xB6, 0xFD, 0xF5, 0x51, 0x51, 0xA9, 0x14, 0x24, 0x8A, 0xA2, 0x67, 0xE3, 0xB1, 0x60, 0xD9, 0x18, 0xE3, 0xCD, 0x56, 0x31, 0x8E, 0x1C, 0x52, 0xCD, 0x02, 0xF9, 0x2D, 0x20, 0xE7, 0x5E, 0x40, 0x31, 0xEF, 0x35, 0x64, 0x0D, 0x6A, 0x30, 0xC0, 0x3A, 0x9B, 0x1E, 0x69, 0x36, 0x4C, 0x8C, 0xBE, 0x9D, 0x61, 0x42, 0x4D, 0x36, 0x47, 0xE5, 0x59, 0x2C, 0xE7, 0x6E, 0x5A, 0xC7, 0xE1, 0x6C, 0x48, 0x83, 0x1A, 0xBF, 0x26, 0x27, 0x25, 0x01, 0x11, 0xF3, 0x8B, 0x76, 0xB1, 0xFC, 0x78, 0xF2, 0x2D, 0xB5, 0xFD, 0xDE, 0x44, 0x7E, 0x83, 0x0E, 0x52, 0xB7, 0x87, 0x08, 0xCB, 0x80, 0xBA, 0x4E, 0x26, 0x3D, 0xAC, 0x86, 0xB9, 0xAB, 0xC4, 0xFB, 0x74, 0x6B, 0x7F, 0xCF, 0x8B, 0xBD, 0x44, 0x83, 0xAC, 0xB1, 0x48, 0x75, 0xE6, 0x14, 0xD0, 0x43, 0x80, 0x8C, 0x6B, 0xFC, 0xEB, 0x47, 0xE1, 0xEE, 0x87, 0x92, 0x77, 0x4B, 0xB6, 0xE8, 0x10, 0x76, 0xEC, 0x6A, 0x0E, 0x84, 0xE0, 0x5C, 0x73, 0xB2, 0x65, 0x6A, 0x3F, 0xB7, 0xE5, 0x89, 0xE7, 0x2F, 0xEF, 0x25, 0x01, 0xA8, 0x1A, 0xB6, 0x16, 0xDE, 0x9E, 0x7A, 0x4C, 0xAF, 0x7C, 0xD1, 0x41, 0xAB, 0x1D, 0x34, 0x9C, 0xD7, 0xAA, 0x07, 0xFD, 0x70, 0xA0, 0x5A, 0x12, 0xAD, 0xF8, 0x74, 0x5C, 0xDC, 0x23, 0x79, 0x6C, 0x6A, 0x21, 0xCB, 0xAC, 0x49, 0x73, 0xB6, 0x2C, 0x68, 0x00, 0x5E, 0x8D, 0x68, 0xE8, 0x4C, 0xE1, 0x1F, 0xEB, 0xF0, 0x8E, 0x51, 0x82, 0x44, 0xCF, 0x2F, 0x4D, 0x0B, 0x9F, 0x98, 0x3A, 0x71, 0xD8, 0x41, 0x5B, 0x93, 0x2C, 0x95, 0xD6, 0x00, 0xE8, 0x04, 0xE8, 0xE7, 0xFE, 0xBE, 0xAD, 0x5D, 0x96, 0x9F, 0x89, 0x18, 0xC0, 0xD9, 0x38, 0x4B, 0x7D, 0xFB, 0xD6, 0xF2, 0xDA, 0xD4, 0xFC, 0x7C, 0x56, 0x87, 0x19, 0x39, 0xC6, 0xD3, 0x68, 0xE9, 0x57, 0x6E, 0xA1, 0x14, 0x18, 0xB6, 0x72, 0x7D, 0x4B, 0x43, 0xC8, 0xB1, 0xE1, 0xF8, 0x74, 0xB8, 0x1A, 0x36, 0xFB, 0xE3, 0x16, 0x98, 0x3C, 0x55, 0xB7, 0x51, 0x3B, 0x99, 0x30, 0x0D, 0x21, 0xA8, 0x51, 0x4F, 0x20, 0xE0, 0x37, 0x5A, 0x80, 0xDB, 0xBB, 0x0C, 0xBE, 0x3E, 0xA8, 0x78, 0xC1, 0xAE, 0xF5, 0x92, 0xB9, 0xCF, 0x6C, 0x2A, 0x60, 0xB9, 0x5A, 0x19, 0xA3, 0x61, 0x8D, 0x9C, 0xC5, 0xF8, 0xD8, 0xF6, 0xB6, 0xEB, 0x34, 0xED, 0x0C, 0x58, 0xC3, 0x05, 0xA8, 0xB8, 0x41, 0xA3, 0xE1, 0x79, 0xEB, 0x0E, 0xE3, 0xC3, 0x32, 0xC2, 0xE5, 0xB3, 0x12, 0x8F, 0x5C, 0x09, 0xEC, 0x3D, 0x9C, 0xB0, 0x5E, 0xDC, 0xA7, 0x56, 0xF9, 0x8C, 0x1A, 0x1E, 0xBF, 0xC4, 0x8F, 0xF1, 0x54, 0x8A, 0x45, 0x34, 0x1C, 0x70, 0x02, 0x34, 0x00, 0xBB, 0xD2, 0xBB, 0x8E, 0xAB, 0xBC, 0x17, 0x26, 0x20, 0x4B, 0x79, 0x75, 0x86, 0x94, 0x40, 0x5E, 0xBB, 0x86, 0xEE, 0x55, 0xD1, 0x48, 0xFA, 0x7F, 0xFB, 0x78, 0xD7, 0x7A, 0x3C, 0xF3, 0xC7, 0xE3, 0x99, 0xD9, 0x38, 0xEB, 0xF1, 0x94, 0x1B, 0x34, 0xDE, 0x8F, 0x27, 0xCE, 0x1C, 0x02, 0xA9, 0x72, 0x19, 0xE1, 0xE8, 0x18, 0x85, 0x9E, 0x31, 0x29, 0xB4, 0x2D, 0x08, 0xCF, 0x71, 0x82, 0x36, 0xFC, 0x21, 0xF9, 0x25, 0x56, 0xB5, 0x66, 0xD9, 0xF6, 0x54, 0x23, 0x1B, 0xA7, 0x41, 0x00, 0x23, 0xBC, 0x2F, 0x68, 0xE7, 0x4C, 0x51, 0x8F, 0x74, 0xEC, 0xF4, 0xEE, 0x85, 0x1D, 0x73, 0xF6, 0x7D, 0xE6, 0x58, 0x9B, 0x59, 0xFC, 0x72, 0x22, 0xA5, 0xE5, 0xA5, 0x76, 0xFE, 0x87, 0x97, 0x9A, 0xAC, 0x4A, 0x8E, 0x35, 0xA8, 0x11, 0x73, 0x5C, 0x36, 0xAF, 0x21, 0xC6, 0x1C, 0xF9, 0x9D, 0x39, 0xEA, 0xB4, 0x5C, 0x4D, 0x15, 0x9B, 0x42, 0x45, 0x4F, 0xF8, 0x31, 0xE8, 0x78, 0xC3, 0x67, 0x3B, 0x41, 0x35, 0x4B, 0x56, 0x3B, 0x41, 0x18, 0x50, 0x0A, 0x64, 0xC3, 0xB7, 0x11, 0xAF, 0x34, 0x14, 0x88, 0x1B, 0x0B, 0x9B, 0x15, 0x33, 0xD3, 0x25, 0x6E, 0xF6, 0xDB, 0x4B, 0x36, 0x0F, 0x08, 0x7B, 0x8C, 0xAC, 0xFB, 0xC2, 0x0A, 0x97, 0xE5, 0x8C, 0x5A, 0xF0, 0xDA, 0xDB, 0x0E, 0x70, 0xFC, 0xD7, 0x41, 0x4F, 0x80, 0x77, 0xC8, 0x79, 0x4B, 0x4D, 0xBF, 0xCE, 0x15, 0x51, 0xFD, 0x12, 0x6B, 0x95, 0x89, 0xCE, 0x82, 0x43, 0xE8, 0xD1, 0x8B, 0xC4, 0x7A, 0x15, 0xF9, 0x53, 0x89, 0x7B, 0xA0, 0x9B, 0x9D, 0x6A, 0x37, 0x61, 0xD4, 0x5F, 0xB5, 0x72, 0x34, 0xD7, 0xE8, 0x16, 0xCC, 0x16, 0x70, 0x6A, 0x49, 0xD1, 0xAF, 0xAF, 0xE1, 0xAA, 0xF4, 0xD6, 0xF9, 0xE1, 0x2F, 0x71, 0x83, 0x5E, 0x0D, 0xCE, 0xB5, 0x2E, 0x78, 0xC2, 0xE3, 0x7F, 0x2C, 0xB2, 0xF5, 0xF0, 0x66, 0x02, 0x75, 0x11, 0x8D, 0xED, 0x31, 0xB6, 0x7D, 0xC4, 0xEC, 0x46, 0xCD, 0xE0, 0x39, 0x97, 0x0A, 0x0F, 0x00, 0x7E, 0x7B, 0x1C, 0x8A, 0xEC, 0x19, 0xD0, 0xAA, 0x67, 0xE1, 0xF7, 0xB2, 0x44, 0xB0, 0x51, 0x2F, 0xE6, 0xDA, 0xAF, 0x82, 0x43, 0xD3, 0x67, 0x6B, 0x67, 0x72, 0xBC, 0xA1, 0xFB, 0x04, 0x7E, 0x31, 0x9C, 0xC3, 0xF4, 0x1D, 0x65, 0x85, 0xD6, 0xB0, 0x71, 0x01, 0x38, 0xE6, 0x84, 0xF6, 0x6C, 0x48, 0x01, 0x9C, 0xEB, 0x8F, 0xCE, 0x86, 0x34, 0x78, 0x41, 0x01, 0xB1, 0x5F, 0xFD, 0x78, 0x04, 0x98, 0xFC, 0xEA, 0xC7, 0x73, 0x20, 0xDE, 0x52, 0xF3, 0xAF, 0x34, 0x2C, 0xD4, 0x8A, 0xA1, 0x9E, 0xEC, 0xC0, 0x5A, 0xF0, 0x00, 0x50, 0x6B, 0x79, 0x78, 0xE1, 0x1E, 0x2E, 0x81, 0x62, 0x48, 0xC5, 0xBC, 0x49, 0xC5, 0xB2, 0xE8, 0x38, 0xC3, 0x77, 0x36, 0x9E, 0xC9, 0x2F, 0x7B, 0x23, 0xE6, 0x1B, 0xF3, 0xF0, 0x34, 0x67, 0xE1, 0x03, 0x84, 0x4D, 0x7B, 0x6F, 0xEE, 0xEF, 0xDC, 0x09, 0x80, 0xB3, 0x0B, 0xF7, 0x07, 0xE0, 0x02, 0x48, 0x81, 0xC3, 0x33, 0xD8, 0x45, 0xEB, 0x93, 0x4F, 0xDB, 0x21, 0x36, 0x40, 0x7C, 0x81, 0x00, 0x96, 0xC6, 0x99, 0x5F, 0xB4, 0x17, 0xB4, 0x6B, 0xDA, 0x1D, 0x23, 0x97, 0x96, 0x47, 0xBF, 0x48, 0x56, 0x16, 0xEA, 0xC5, 0x50, 0x41, 0xBA, 0xA1, 0x7A, 0x6C, 0x9A, 0x3A, 0x7D, 0x4D, 0x6A, 0x05, 0x8D, 0x3B, 0x68, 0x9E, 0xB3, 0xFD, 0xBE, 0xE4, 0x8D, 0x0B, 0x01, 0x0A, 0x20, 0x5E, 0x69, 0x69, 0xB9, 0x66, 0x1E, 0x57, 0x0B, 0x75, 0x6D, 0xF7, 0x05, 0x9F, 0x88, 0xFE, 0x4E, 0x22, 0xF8, 0xC9, 0xD0, 0xF0, 0xCE, 0x79, 0xE4, 0xA5, 0x80, 0xCB, 0x12, 0x44, 0x78, 0x83, 0x1B, 0xD4, 0x70, 0x40, 0xD6, 0x80, 0xE5, 0x6C, 0x84, 0x01, 0xEE, 0xCB, 0x31, 0x38, 0xE7, 0xA7, 0x77, 0x27, 0xF0, 0xFC, 0x97, 0x5F, 0xE8, 0x05, 0x02, 0x8E, 0xA7, 0xEA, 0x40, 0x91, 0x3D, 0x4F, 0xA0, 0x20, 0x64, 0x1F, 0x22, 0x95, 0xF0, 0x3C, 0x71, 0x8D, 0x56, 0x1F, 0xCD, 0x6D, 0xAB, 0x79, 0xD6, 0x74, 0x84, 0x34, 0x20, 0x0A, 0xB0, 0x3D, 0xB6, 0x6F, 0x1C, 0x1B, 0xE4, 0xAD, 0x0E, 0xA5, 0x69, 0x96, 0x91, 0x31, 0xE5, 0xC9, 0x26, 0xF3, 0x3C, 0x45, 0xCB, 0xF9, 0x30, 0x79, 0xFA, 0x50, 0x53, 0x36, 0x6A, 0x55, 0x49, 0xA5, 0xB1, 0x3A, 0x14, 0xE3, 0x00, 0x19, 0x8D, 0x3D, 0xBF, 0xC5, 0x01, 0x6D, 0x58, 0xA3, 0x5E, 0xD4, 0xEA, 0x5F, 0xC0, 0xB8, 0x0A, 0x09, 0x4F, 0xA3, 0x6F, 0xA9, 0xB1, 0xF2, 0x97, 0x53, 0x3B, 0x92, 0xA8, 0xDB, 0xCA, 0x5D, 0x9A, 0xDC, 0x5A, 0x26, 0xCC, 0xC6, 0x93, 0xB3, 0xD3, 0x43, 0xFA, 0x37, 0x67, 0xCD, 0x9E, 0x05, 0x34, 0x09, 0xA0, 0x0C, 0x48, 0x2D, 0x0F, 0x5E, 0x6D, 0xF8, 0x14, 0xCE, 0xC6, 0x2D, 0x33, 0x2C, 0xEB, 0xA6, 0x67, 0xC8, 0xF4, 0xE6, 0x6E, 0x4F, 0x63, 0x1C, 0xA2, 0x95, 0xE0, 0x5D, 0x4E, 0xA8, 0xA2, 0x0D, 0x6A, 0x9C, 0x06, 0xAF, 0xB1, 0x33, 0x02, 0x84, 0x35, 0x56, 0xF3, 0xB6, 0x29, 0xA0, 0x01, 0x98, 0x01, 0x29, 0x1D, 0xB4, 0x38, 0x5F, 0xCB, 0xA7, 0xB6, 0x1A, 0xD2, 0x59, 0xBE, 0x9C, 0xDA, 0x29, 0xFE, 0xB2, 0xB7, 0x92, 0xB7, 0x39, 0xD3, 0x50, 0x58, 0x14, 0xC2, 0xB1, 0x98, 0xE6, 0xF9, 0xD6, 0x40, 0x7A, 0xEF, 0x6D, 0x5B, 0x63, 0x5C, 0xF3, 0x34, 0x7E, 0xF9, 0x9E, 0x19, 0x35, 0xAE, 0x22, 0xAB, 0x03, 0xEA, 0xB7, 0x10, 0x7F, 0x51, 0x33, 0x2B, 0x2E, 0xDC, 0xEB, 0x4E, 0xA7, 0xEF, 0x90, 0xED, 0x13, 0x7F, 0x34, 0xD6, 0xA2, 0x62, 0x5B, 0x28, 0x40, 0x57, 0x7C, 0x92, 0x81, 0x08, 0xC0, 0x1B, 0x26, 0x80, 0xAE, 0x10, 0x66, 0xDE, 0xA0, 0x41, 0x39, 0x74, 0xEA, 0x6F, 0xCA, 0xDB, 0x97, 0x53, 0x4F, 0x98, 0xC6, 0x0B, 0x14, 0x1C, 0x0C, 0x75, 0xBC, 0xA5, 0x12, 0x6A, 0xEE, 0x12, 0xA3, 0x22, 0xE5, 0x39, 0x5C, 0xA9, 0xE5, 0x2D, 0x23, 0xD7, 0x2B, 0x4F, 0x06, 0x22, 0x81, 0x34, 0x20, 0x14, 0xF0, 0x02, 0x5E, 0xB5, 0xB3, 0x6F, 0x52, 0xCF, 0x65, 0xA7, 0xE2, 0x4E, 0x37, 0xC0, 0x27, 0xBB, 0x25, 0x7B, 0xEF, 0x32, 0xE7, 0xBC, 0x8F, 0x91, 0x4F, 0xBD, 0xA5, 0x09, 0x20, 0x0A, 0xF0, 0xC5, 0x69, 0x50, 0x43, 0x97, 0x1D, 0x75, 0xAE, 0xAE, 0x9E, 0x6C, 0xAC, 0x3F, 0x4C, 0xA7, 0xEF, 0xF5, 0xDF, 0x4A, 0xC3, 0x93, 0x98, 0x9A, 0x50, 0xC8, 0xAA, 0xFC, 0x53, 0x6B, 0x1B, 0x85, 0xAF, 0xD3, 0xB1, 0x70, 0x4B, 0x96, 0x16, 0xE3, 0x67, 0x17, 0x57, 0x5C, 0x7A, 0x85, 0xED, 0xFE, 0xA8, 0xD5, 0x80, 0x21, 0x3E, 0x0D, 0xE8, 0xD2, 0x80, 0x62, 0x20, 0x1C, 0x70, 0x6E, 0xDC, 0x88, 0x48, 0xC7, 0x27, 0xBA, 0x07, 0x81, 0x4E, 0xE3, 0xAA, 0x69, 0x6B, 0xE8, 0xE8, 0x69, 0xA8, 0x2D, 0x10, 0xAD, 0x19, 0x26, 0x01, 0xAE, 0x94, 0xAF, 0xAA, 0x91, 0x17, 0xD3, 0x42, 0x9E, 0x09, 0x30, 0x06, 0x82, 0x66, 0xD0, 0xCC, 0xD7, 0x6E, 0x92, 0x80, 0x34, 0x92, 0x6E, 0xD0, 0xE4, 0xED, 0xFD, 0x66, 0xF0, 0x03, 0x0B, 0x46, 0x91, 0xD4, 0x18, 0xFD, 0xD9, 0xFC, 0x5D, 0xA1, 0x12, 0xCB, 0xB5, 0x0A, 0xEA, 0x81, 0xC8, 0x0E, 0xD6, 0xD6, 0xA8, 0xDD, 0x13, 0xBB, 0x4D, 0xD5, 0x79, 0xE5, 0x94, 0xA3, 0xD5, 0x01, 0xDC, 0x01, 0x5D, 0x66, 0x95, 0x79, 0xA6, 0x5E, 0x37, 0x19, 0xB0, 0x55, 0x61, 0x76, 0x9D, 0xC3, 0xF0, 0xE2, 0xAC, 0x7C, 0x6D, 0xFE, 0x1A, 0xE5, 0xCF, 0x40, 0x56, 0x23, 0x1A, 0xEB, 0xDE, 0x29, 0x07, 0x50, 0x6F, 0x10, 0x20, 0xE7, 0xD7, 0x64, 0xD9, 0x03, 0x18, 0xDF, 0xA0, 0x29, 0xC2, 0x64, 0x7F, 0xD6, 0x56, 0xD5, 0xE5, 0xF5, 0xCF, 0x8E, 0xB0, 0x70, 0xE4, 0x24, 0x88, 0x60, 0x4C, 0xA5, 0xDF, 0xA2, 0x35, 0x0D, 0xE8, 0x72, 0xF7, 0x17, 0x0B, 0xCF, 0x1B, 0x91, 0x38, 0xA0, 0xD5, 0x10, 0x40, 0xBC, 0xB1, 0x2A, 0x04, 0x8C, 0x38, 0xBD, 0xA3, 0x9D, 0x1D, 0xA0, 0x0C, 0x90, 0xDB, 0x3C, 0x45, 0xD3, 0xB4, 0xE9, 0xF8, 0x0D, 0xFA, 0xB2, 0x51, 0xF7, 0xF5, 0x42, 0x88, 0x86, 0x2D, 0xE4, 0xDC, 0x0C, 0xC3, 0x80, 0xF4, 0x85, 0x03, 0x04, 0x2D, 0x53, 0x0F, 0x5D, 0x99, 0x8E, 0xB0, 0xEF, 0x89, 0xF4, 0x22, 0x64, 0xE1, 0x2B, 0xBE, 0xAA, 0x5E, 0x1C, 0xFB, 0x8E, 0x20, 0x22, 0x8E, 0x19, 0xCD, 0x29, 0x6D, 0x13, 0x2A, 0xE8, 0x76, 0x82, 0xDB, 0x4E, 0x0E, 0xAB, 0xFD, 0x51, 0x66, 0x8F, 0xFB, 0x7B, 0x3E, 0x37, 0x7F, 0xED, 0xA4, 0x58, 0x02, 0xC2, 0x00, 0x2F, 0x61, 0x18, 0x31, 0x10, 0xAD, 0xF9, 0x60, 0x9C, 0xCD, 0x9E, 0xA4, 0xE2, 0xD0, 0x5F, 0x59, 0x57, 0xDE, 0xFF, 0x57, 0x7A, 0x2B, 0xF8, 0xA3, 0xEB, 0xC5, 0x97, 0xFC, 0x4E, 0x19, 0x10, 0x6B, 0x78, 0x23, 0x00, 0x15, 0xC0, 0x0F, 0x90, 0x7A, 0x86, 0xD1, 0x67, 0xE5, 0x01, 0x04, 0x48, 0x06, 0x22, 0x80, 0xBA, 0xC2, 0x81, 0xB7, 0xD4, 0xFC, 0x93, 0x78, 0xBB, 0xD8, 0xF7, 0x53, 0x9D, 0xE8, 0x1B, 0xF3, 0xE6, 0x19, 0x48, 0xAD, 0x69, 0xB6, 0x0A, 0x0E, 0x86, 0x43, 0x77, 0xDF, 0x49, 0x8E, 0xA9, 0xEC, 0x93, 0xA5, 0x82, 0x79, 0xCE, 0x90, 0x76, 0x75, 0x28, 0x57, 0x80, 0x52, 0x1D, 0x83, 0xD3, 0x11, 0x31, 0xC0, 0x08, 0xD0, 0x31, 0x55, 0x0A, 0xDD, 0xA2, 0x70, 0x28, 0x4A, 0xE0, 0x99, 0x28, 0x5D, 0xCF, 0x9D, 0x31, 0xD9, 0x06, 0x5A, 0xA5, 0x69, 0x6F, 0x6A, 0x5D, 0x9D, 0x5B, 0xC6, 0x41, 0xD2, 0xD0, 0xB5, 0xB3, 0xD2, 0x0D, 0x53, 0xAD, 0xA1, 0x0E, 0xDE, 0x30, 0x40, 0x03, 0x10, 0x01, 0xD8, 0x00, 0x09, 0x20, 0xB8, 0x83, 0x16, 0x78, 0x61, 0xFE, 0xB9, 0xA8, 0x31, 0x92, 0x94, 0xF0, 0x57, 0x26, 0x86, 0x33, 0x6C, 0x21, 0x76, 0x44, 0xDF, 0x4A, 0xD3, 0x90, 0x79, 0x27, 0x70, 0x5F, 0xB6, 0x7D, 0xF7, 0xF9, 0xF2, 0xE8, 0x00, 0x93, 0x03, 0x69, 0x40, 0x09, 0x90, 0x07, 0x70, 0x03, 0xAC, 0x80, 0xF4, 0xBF, 0x21, 0x3F, 0xB8, 0xF2, 0x03, 0x57, 0x98, 0xD1, 0xC5, 0xDA, 0x37, 0xAE, 0xA2, 0x57, 0xCC, 0x3D, 0xD2, 0x31, 0xA0, 0x01, 0x70, 0x2D, 0x91, 0x91, 0x35, 0x7C, 0x82, 0x04, 0xE0, 0x00, 0xB4, 0x00, 0x97, 0x09, 0x5B, 0x89, 0x3D, 0x4D, 0xC0, 0x0C, 0xC8, 0xBE, 0xB2, 0x23, 0x21, 0xF4, 0x3D, 0x6E, 0x09, 0x73, 0x4D, 0xFD, 0xBB, 0xB2, 0xA3, 0xCC, 0x8E, 0x5D, 0x93, 0x12, 0x97, 0x5D, 0x15, 0xA4, 0x65, 0x98, 0x87, 0x59, 0xBC, 0xEB, 0xCA, 0xA9, 0x9D, 0x02, 0xBC, 0x11, 0x0D, 0x4F, 0x40, 0x03, 0xE0, 0x9D, 0x91, 0x11, 0x80, 0x57, 0x81, 0x8A, 0x19, 0xA0, 0x95, 0x37, 0xD3, 0x06, 0xE9, 0xCC, 0x50, 0x84, 0x36, 0x6A, 0xBD, 0x10, 0xE2, 0x97, 0x37, 0x07, 0x37, 0x04, 0x60, 0x9D, 0x79, 0x4C, 0x23, 0x40, 0x6B, 0x8F, 0x1A, 0x5F, 0xD9, 0x80, 0x00, 0xEC, 0xED, 0x69, 0x85, 0xE9, 0x3E, 0x81, 0x63, 0xAD, 0xB0, 0x7C, 0xA6, 0x30, 0x91, 0xC8, 0xDE, 0xE6, 0x09, 0x14, 0xE5, 0x8A, 0x91, 0x95, 0x21, 0xE9, 0x08, 0xC8, 0x0C, 0x1A, 0xAF, 0xD7, 0xA7, 0xF0, 0x3C, 0x6D, 0xC6, 0x32, 0x03, 0x95, 0x00, 0x5E, 0xA9, 0x2F, 0x57, 0xF2, 0x6D, 0xF5, 0x56, 0x13, 0x4D, 0x1D, 0xA4, 0xE4, 0xB2, 0xDE, 0x09, 0x40, 0x74, 0x39, 0xE5, 0x3B, 0x10, 0x2F, 0x6F, 0xB0, 0xEE, 0x51, 0xDE, 0xA8, 0x35, 0xCF, 0x27, 0x81, 0x10, 0x20, 0xB3, 0xA1, 0x2B, 0xE5, 0x7D, 0x56, 0xCA, 0x5B, 0x81, 0xAA, 0x0E, 0xDA, 0x9F, 0xD0, 0x2A, 0x0C, 0xBE, 0xCA, 0xC3, 0x3A, 0xC1, 0x15, 0x09, 0x39, 0x46, 0x0D, 0xD4, 0x5D, 0x90, 0xFE, 0x29, 0xEE, 0x32, 0xFB, 0x1E, 0x1F, 0xB2, 0xC6, 0x83, 0x85, 0x03, 0xD9, 0x08, 0x05, 0x6C, 0xDD, 0x3A, 0xF7, 0x3C, 0xB1, 0x1B, 0xD0, 0xD3, 0xF0, 0x02, 0x34, 0x66, 0x78, 0xD5, 0x80, 0xB3, 0x6A, 0x6D, 0xBA, 0xCC, 0x60, 0x82, 0x1B, 0xD9, 0xB0, 0x5F, 0x70, 0x20, 0x73, 0x2E, 0x3F, 0xF6, 0x86, 0xAC, 0xDA, 0x4C, 0xAE, 0xA4, 0xDB, 0xCB, 0x42, 0xDD, 0xA0, 0xD1, 0x37, 0x6C, 0xA5, 0x88, 0xBE, 0x74, 0x87, 0x9B, 0xDF, 0xA0, 0x61, 0x8C, 0x19, 0x6E, 0x4E, 0xE4, 0x56, 0x7D, 0x6D, 0x2B, 0x9C, 0x82, 0x6A, 0x66, 0xD4, 0x54, 0x9A, 0xA5, 0x2B, 0x9F, 0xEE, 0x8D, 0x68, 0xF8, 0x4A, 0xEA, 0xF3, 0x7A, 0x92, 0xCF, 0x78, 0x76, 0xE5, 0x19, 0xDC, 0xB2, 0x35, 0xD6, 0x49, 0x42, 0x6A, 0xAA, 0x12, 0x62, 0x8D, 0x66, 0x8B, 0x9A, 0x57, 0x27, 0xA7, 0x75, 0xA0, 0xB8, 0x28, 0xA0, 0x74, 0xA6, 0xE1, 0x85, 0x01, 0xCD, 0xC6, 0x3A, 0x29, 0xB1, 0x00, 0xA4, 0x00, 0x13, 0x60, 0x7A, 0xA3, 0xC6, 0x2F, 0x4E, 0x4E, 0x10, 0x5C, 0xC5, 0x27, 0x12, 0xE0, 0xEF, 0xA4, 0x76, 0x58, 0xB1, 0x63, 0x44, 0x74, 0xE2, 0xB0, 0x2D, 0xAE, 0x64, 0xA5, 0xD4, 0x7C, 0x15, 0x3F, 0xA9, 0xA6, 0xAB, 0x99, 0x9E, 0xF5, 0x60, 0xDA, 0x54, 0xD0, 0x06, 0x03, 0x7E, 0x66, 0xCA, 0x9B, 0x1B, 0x71, 0x00, 0xF3, 0xE5, 0x7E, 0xA2, 0x00, 0x9F, 0xB9, 0x9C, 0x4C, 0x1B, 0xA7, 0x61, 0x0D, 0x6F, 0x70, 0x83, 0x1A, 0x3C, 0xE1, 0xB4, 0x32, 0xB3, 0xD6, 0x90, 0x55, 0x38, 0xBE, 0xD0, 0x55, 0x98, 0xE7, 0x1B, 0x34, 0xE8, 0x10, 0x34, 0xED, 0xF3, 0x08, 0x56, 0xE2, 0x7F, 0xE2, 0x68, 0xC8, 0xB0, 0x6F, 0x47, 0x66, 0x5C, 0x99, 0xAD, 0x8B, 0x1C, 0xA1, 0xE8, 0x91, 0xA7, 0xD5, 0x2A, 0x9B, 0xEB, 0x22, 0x65, 0xAF, 0x72, 0xB7, 0x4E, 0x37, 0xB2, 0x14, 0x3A, 0x87, 0xA7, 0xBD, 0xB7, 0x2C, 0x2B, 0xC1, 0xD0, 0xE9, 0xB4, 0xA7, 0xF2, 0x0E, 0x30, 0x4F, 0xFC, 0x93, 0xAF, 0x03, 0x5E, 0x69, 0x09, 0xA2, 0x79, 0xB5, 0x8E, 0x51, 0x43, 0x56, 0x85, 0xFA, 0x34, 0x1C, 0x60, 0x03, 0xCC, 0x81, 0xB0, 0x06, 0x01, 0x2E, 0xAB, 0xBB, 0xCC, 0x01, 0x55, 0x20, 0xFD, 0x06, 0x0D, 0x66, 0x73, 0x22, 0xF6, 0x9D, 0xD7, 0xEA, 0x60, 0x44, 0x4D, 0x1E, 0xFF, 0xEE, 0xF1, 0xE4, 0x82, 0xCC, 0x28, 0xF4, 0x90, 0xCE, 0xD6, 0x82, 0x2B, 0xCD, 0x39, 0xE7, 0xED, 0x2C, 0x45, 0xC7, 0xAD, 0xD5, 0xBD, 0x31, 0x61, 0xA7, 0x11, 0x33, 0x41, 0x66, 0xB1, 0xF2, 0xAD, 0x0E, 0xE8, 0xBD, 0xE3, 0xDD, 0x8B, 0x78, 0xCD, 0x86, 0x83, 0x5B, 0x14, 0x2C, 0x99, 0xFD, 0x8F, 0xD1, 0x50, 0x01, 0x9C, 0xE6, 0x1F, 0x66, 0x05, 0x44, 0x02, 0x45, 0x8D, 0x98, 0xC3, 0x03, 0x79, 0xF5, 0x03, 0x79, 0xAD, 0x04, 0x64, 0x00, 0x2A, 0x80, 0x30, 0xA0, 0x07, 0x88, 0xF7, 0x26, 0xB0, 0x4F, 0xFF, 0xE2, 0xB7, 0x35, 0x4A, 0xF3, 0xAB, 0x81, 0x4A, 0xDE, 0xC9, 0xCF, 0x82, 0x8C, 0x4D, 0x1A, 0x74, 0xE6, 0xAA, 0xF8, 0x1B, 0xF9, 0x94, 0xF6, 0xF9, 0x36, 0x9A, 0x38, 0xF7, 0x17, 0xD4, 0x39, 0x37, 0x5F, 0x1A, 0xA4, 0xEB, 0x6A, 0xB9, 0x12, 0xAD, 0xDA, 0x48, 0x5D, 0xFE, 0x06, 0x07, 0x78, 0x83, 0x78, 0xE9, 0xC7, 0xA0, 0x2D, 0x3E, 0x2B, 0x17, 0x1B, 0xAB, 0x27, 0x8A, 0x00, 0x56, 0x40, 0xCE, 0x5A, 0x38, 0xB9, 0xFA, 0x2B, 0xB4, 0xB1, 0xD7, 0x9D, 0xCE, 0x4F, 0x79, 0xF3, 0x55, 0x6F, 0x4F, 0x73, 0x2C, 0x31, 0xB3, 0x7F, 0xFA, 0x3D, 0x48, 0xF1, 0x05, 0xED, 0x1C, 0x85, 0x93, 0xB7, 0x69, 0xFB, 0x71, 0x08, 0x0C, 0xD9, 0x19, 0xF9, 0x6F, 0x82, 0x76, 0x28, 0xF8, 0x1C, 0x70, 0x8F, 0x61, 0xBC, 0xEB, 0xDD, 0x68, 0xE6, 0x39, 0x9C, 0xE6, 0xB0, 0x81, 0x5C, 0x0E, 0xB5, 0x74, 0xC1, 0x80, 0x11, 0x50, 0x8D, 0x38, 0x00, 0xF1, 0x14, 0x8C, 0x1F, 0x9A, 0x51, 0xA6, 0x02, 0xA4, 0xE6, 0x23, 0x68, 0x8D, 0x6C, 0x54, 0xAC, 0xD3, 0xAD, 0x02, 0x72, 0x00, 0xB3, 0xF9, 0x83, 0x7C, 0x9D, 0x75, 0x4D, 0xD6, 0xE9, 0x36, 0x80, 0x3A, 0x37, 0x68, 0x81, 0xC1, 0x8B, 0xC7, 0xBE, 0xE1, 0x21, 0x46, 0x8A, 0x59, 0xC6, 0x6A, 0x90, 0x2B, 0x47, 0xC2, 0x71, 0xC1, 0x02, 0xD2, 0x31, 0x31, 0xFC, 0x55, 0x2C, 0x66, 0xD7, 0xA7, 0x2C, 0x7F, 0x65, 0xD7, 0x3F, 0x57, 0xFB, 0x6A, 0xC0, 0xA7, 0x60, 0x24, 0x87, 0x6C, 0x4D, 0x63, 0x3C, 0xE7, 0x7E, 0x5A, 0x5B, 0x9B, 0x49, 0x23, 0xC7, 0xFF, 0x1E, 0xC3, 0x06, 0x22, 0x11, 0x91, 0x61, 0x30, 0x10, 0x73, 0xD0, 0xA3, 0xC7, 0xFA, 0xE9, 0xC7, 0x57, 0x0B, 0xFB, 0x01, 0xC4, 0x00, 0xF3, 0xE5, 0x92, 0x50, 0x0D, 0x07, 0x2C, 0x27, 0x5C, 0x81, 0xE2, 0x0E, 0x1A, 0x1C, 0x87, 0x94, 0x61, 0xE3, 0xCA, 0x5F, 0x9A, 0xF6, 0x7B, 0xC8, 0x03, 0x6F, 0x07, 0xA3, 0xEE, 0x5E, 0xAA, 0x4E, 0xD9, 0xC5, 0xF7, 0xA9, 0x3C, 0x47, 0x87, 0xD4, 0x6A, 0x95, 0x95, 0xD7, 0xB1, 0x9F, 0xBA, 0x1C, 0x4A, 0x12, 0xE0, 0xC6, 0xD1, 0xF9, 0xB4, 0xC5, 0x9B, 0x10, 0x0A, 0x94, 0x77, 0x44, 0x2E, 0x12, 0xE0, 0x9C, 0xB6, 0x1C, 0xDB, 0x59, 0x49, 0x0F, 0xC0, 0x09, 0xFC, 0xE9, 0xC6, 0x01, 0x6E, 0xAC, 0x8D, 0xCE, 0x15, 0x88, 0x95, 0x5F, 0x23, 0x6B, 0xC8, 0x1C, 0xB9, 0x5A, 0x17, 0xD4, 0xF8, 0xCB, 0xAF, 0x21, 0x68, 0x30, 0xB5, 0x52, 0xD2, 0xEF, 0x8E, 0x4E, 0x8C, 0x9E, 0x1F, 0x32, 0xF4, 0x17, 0x9B, 0x05, 0xCE, 0xF7, 0xD6, 0x07, 0x66, 0x16, 0xEC, 0x5A, 0xA6, 0xB3, 0x43, 0x4A, 0x56, 0x27, 0xBB, 0xAC, 0x64, 0x71, 0xD9, 0x6A, 0x71, 0x62, 0xC0, 0x1A, 0xD2, 0xE0, 0x04, 0x5C, 0x66, 0xA6, 0x48, 0x74, 0x76, 0x2E, 0xA6, 0x02, 0x62, 0xB3, 0xFE, 0x21, 0x04, 0x1C, 0x69, 0xD8, 0xAA, 0x9B, 0x9C, 0x86, 0x36, 0xA2, 0x51, 0x80, 0x09, 0xE0, 0xEB, 0x0C, 0x57, 0xD9, 0x30, 0x20, 0xF7, 0xA0, 0xBE, 0xB3, 0x46, 0x45, 0x7B, 0x07, 0xAD, 0xCE, 0x77, 0x73, 0x3A, 0x0E, 0xE3, 0x34, 0x4B, 0x47, 0x36, 0xF2, 0x18, 0xB4, 0x09, 0x45, 0x38, 0x2B, 0x92, 0xF7, 0x30, 0x69, 0xED, 0xF4, 0x61, 0x8D, 0x2B, 0xC1, 0xCA, 0xDD, 0xDE, 0xEC, 0xA0, 0xBE, 0x11, 0x5C, 0xB1, 0xDD, 0xF0, 0x7D, 0x46, 0xE4, 0x74, 0x98, 0xD2, 0xFB, 0x93, 0x01, 0x71, 0xE6, 0x48, 0x90, 0xE3, 0xD3, 0x33, 0x2C, 0x0C, 0x78, 0x49, 0x62, 0x01, 0x4E, 0xAC, 0xA0, 0xED, 0x62, 0x41, 0x01, 0x4A, 0x0D, 0x69, 0xD8, 0xD2, 0xD5, 0x33, 0x50, 0xD1, 0xD0, 0x55, 0x96, 0x5A, 0x17, 0xA8, 0xA0, 0xE7, 0xC3, 0xDB, 0x41, 0xC3, 0x50, 0x1F, 0xB6, 0xA7, 0xB7, 0x82, 0xCB, 0x72, 0xD8, 0x77, 0xB8, 0xF5, 0x53, 0xBD, 0x73, 0x17, 0x32, 0x4B, 0xCE, 0xDF, 0x16, 0xAA, 0xA4, 0x6D, 0x7B, 0xBE, 0x55, 0x30, 0x31, 0xBD, 0xAD, 0xAA, 0xD6, 0x58, 0x4D, 0x6F, 0xE8, 0x3A, 0xAE, 0x11, 0x03, 0x47, 0x00, 0x26, 0x20, 0x6E, 0xE2, 0x47, 0x00, 0xE1, 0xE9, 0xCC, 0x6F, 0x31, 0x92, 0x5F, 0x6A, 0xD3, 0xA0, 0xBF, 0x64, 0x3E, 0xD6, 0x51, 0x8D, 0x58, 0x35, 0x0A, 0x6E, 0xEC, 0xAD, 0xD4, 0x01, 0xBE, 0xC8, 0x46, 0x35, 0x56, 0xED, 0x5A, 0x1C, 0xB0, 0xBA, 0x41, 0xE3, 0xAF, 0x27, 0xEA, 0x74, 0xD7, 0x54, 0x29, 0x63, 0xB2, 0x83, 0xC2, 0xF4, 0x56, 0x8E, 0xE1, 0x37, 0x29, 0x6B, 0x53, 0x67, 0x6D, 0x59, 0xBD, 0x4E, 0xFB, 0xF3, 0xF8, 0x48, 0xEF, 0xF8, 0xF4, 0xCA, 0xBF, 0xAA, 0x7F, 0xBD, 0x22, 0xFA, 0x92, 0xFE, 0xE5, 0x80, 0x35, 0xC8, 0xAF, 0xF2, 0x11, 0xA8, 0xC0, 0x17, 0x55, 0x81, 0x62, 0x20, 0x12, 0xA0, 0x3B, 0x11, 0x42, 0x5F, 0x4E, 0x09, 0x22, 0x7F, 0x05, 0x24, 0x1B, 0xEB, 0x05, 0xE2, 0x09, 0x84, 0x03, 0xC9, 0x0D, 0x03, 0x8A, 0x3B, 0x6B, 0x75, 0x00, 0x21, 0x40, 0xBD, 0xA1, 0x80, 0x64, 0xE3, 0x00, 0x2C, 0xF3, 0x93, 0x6B, 0x07, 0x4D, 0xBA, 0x5B, 0x2F, 0x20, 0xB2, 0xCD, 0xD7, 0xB7, 0x82, 0xD9, 0x95, 0x77, 0x7E, 0x7D, 0x39, 0x2A, 0x1C, 0x8C, 0x10, 0xFA, 0x31, 0x04, 0x6B, 0xCB, 0x95, 0x79, 0x8C, 0xF1, 0x7C, 0x19, 0x3C, 0xEC, 0x58, 0x1F, 0x22, 0x66, 0xB4, 0xF8, 0xCC, 0x68, 0xB9, 0x02, 0x6A, 0x80, 0x30, 0xC0, 0x02, 0x50, 0x02, 0x27, 0xA6, 0xAD, 0x77, 0x36, 0xE2, 0x22, 0xE6, 0xA7, 0x3A, 0x0D, 0xEF, 0xFF, 0xCF, 0x00, 0x12, 0x80, 0x09, 0x90, 0x86, 0x0A, 0x60, 0xB5, 0x9B, 0xC7, 0x1B, 0x01, 0xA4, 0x02, 0x6F, 0x30, 0x7F, 0x83, 0xB2, 0x83, 0x86, 0xF5, 0xA3, 0x16, 0x50, 0xD6, 0x95, 0x77, 0xB7, 0x0C, 0xCE, 0x69, 0x66, 0xD5, 0x2D, 0x7C, 0x86, 0x44, 0xAA, 0x2B, 0xA6, 0x13, 0x1C, 0xB9, 0x53, 0xDD, 0xFE, 0xCE, 0x6B, 0xF4, 0xEA, 0x92, 0x47, 0x3A, 0x22, 0x45, 0x77, 0xE1, 0xB6, 0x1D, 0x4C, 0x01, 0x62, 0xFD, 0x45, 0x02, 0x34, 0x01, 0xAA, 0x86, 0x01, 0xCA, 0x40, 0x5C, 0x18, 0x60, 0x04, 0x70, 0x01, 0x77, 0x3A, 0x6F, 0x44, 0xE3, 0x00, 0xD9, 0xFF, 0x03, 0x09, 0x20, 0x01, 0x98, 0x03, 0x5E, 0x40, 0x04, 0x90, 0x79, 0x67, 0xFC, 0x02, 0x7C, 0x00, 0xA1, 0x86, 0x35, 0x12, 0xD0, 0xD3, 0x70, 0xC0, 0x0C, 0x88, 0xE8, 0xA0, 0xD9, 0x77, 0x32, 0x8B, 0x7E, 0x12, 0xE9, 0xF0, 0x77, 0x5C, 0x53, 0x83, 0x89, 0x5F, 0xA8, 0x23, 0xC8, 0xC6, 0xED, 0x3E, 0x93, 0xBD, 0xEE, 0x74, 0x04, 0xCD, 0xE3, 0xAE, 0xB4, 0xE1, 0xEE, 0x42, 0xE7, 0x3D, 0x58, 0x95, 0x37, 0x99, 0x3D, 0xA1, 0x01, 0xB0, 0x00, 0x64, 0x80, 0xD9, 0xCC, 0x77, 0x3B, 0x03, 0xE1, 0x00, 0x75, 0x7C, 0x24, 0x5F, 0x8B, 0x53, 0xF7, 0xC1, 0xCD, 0x29, 0xEF, 0xA5, 0x73, 0x02, 0x3C, 0x39, 0xC0, 0x0C, 0xC8, 0x69, 0x18, 0xA0, 0x0D, 0xD7, 0xD9, 0x18, 0x7A, 0xBC, 0x11, 0x8D, 0xFB, 0xDF, 0xA2, 0xC1, 0xF3, 0xBF, 0x29, 0x77, 0xD0, 0xFC, 0x3B, 0x72, 0x1C, 0x8B, 0x0F, 0x6C, 0x7F, 0x39, 0x8F, 0xAF, 0x6E, 0x91, 0x48, 0xE9, 0x94, 0x20, 0x11, 0xC6, 0x84, 0x7B, 0xBE, 0x12, 0x1E, 0xCB, 0x7D, 0x4E, 0xDB, 0xF9, 0x31, 0xCF, 0x5F, 0x6A, 0x2B, 0x5A, 0x62, 0x60, 0x5A, 0x33, 0x0E, 0x75, 0x79, 0x18, 0xEB, 0x76, 0x75, 0x5D, 0x19, 0xB8, 0x5D, 0x9A, 0xF3, 0x29, 0xF2, 0x52, 0x05, 0x82, 0x96, 0x05, 0x37, 0x35, 0xAC, 0x51, 0xD3, 0xCB, 0x96, 0x7D, 0xD7, 0xE6, 0x1B, 0x07, 0xE0, 0x06, 0x19, 0xC0, 0x0A, 0x68, 0xDE, 0x17, 0x41, 0x7C, 0x45, 0x3C, 0x49, 0x85, 0x91, 0x37, 0xC7, 0xD0, 0xC0, 0xB4, 0xA5, 0x89, 0x98, 0x7F, 0x38, 0x4C, 0x8A, 0x5F, 0x2F, 0x64, 0x1A, 0x79, 0xFB, 0xB2, 0xA4, 0x3E, 0x2B, 0xD1, 0x9D, 0x09, 0x44, 0xC3, 0x76, 0x0C, 0x56, 0xB4, 0xB8, 0x80, 0xD2, 0x99, 0x58, 0xE5, 0x98, 0x29, 0x4D, 0x3B, 0x2B, 0x67, 0xEB, 0x13, 0x4F, 0x9F, 0x2C, 0x73, 0x28, 0x94, 0xDA, 0x92, 0x94, 0x0B, 0x90, 0x67, 0x4E, 0xB2, 0x91, 0x03, 0x68, 0x35, 0x02, 0x10, 0x07, 0x78, 0x5B, 0x98, 0x36, 0xFC, 0xDC, 0xA0, 0x41, 0x38, 0x54, 0xAA, 0xFF, 0x32, 0xB1, 0x15, 0xBE, 0xA0, 0x7D, 0x0F, 0xBE, 0x22, 0xA3, 0xA9, 0x3D, 0xCB, 0x38, 0xAD, 0xCB, 0xAE, 0x39, 0x83, 0x66, 0x3B, 0x0B, 0x59, 0xB6, 0xBA, 0x52, 0x1A, 0x4E, 0x80, 0x04, 0x40, 0xBC, 0x06, 0xEE, 0xF3, 0x72, 0x7B, 0x5F, 0x2B, 0x75, 0xFC, 0x99, 0x43, 0xEA, 0x48, 0x80, 0x46, 0xC3, 0x80, 0x58, 0xAA, 0x3D, 0x3F, 0x73, 0xA1, 0xA7, 0x34, 0x72, 0xAA, 0x2F, 0xCF, 0x5A, 0x5C, 0x76, 0x00, 0x75, 0x40, 0x7C, 0x95, 0x2A, 0x1A, 0xAC, 0x80, 0xE9, 0x8D, 0x5A, 0xF5, 0xC0, 0xE2, 0xFA, 0x97, 0x5F, 0xD3, 0xC5, 0xD4, 0xE1, 0x66, 0x72, 0x9F, 0xE1, 0x05, 0xD9, 0x6B, 0x73, 0x3C, 0x11, 0x8A, 0x39, 0x23, 0x7C, 0xA3, 0x16, 0xBB, 0x5E, 0x7C, 0x1A, 0x96, 0x40, 0xC8, 0xFC, 0x24, 0x0A, 0xD0, 0x59, 0xE2, 0x60, 0x59, 0x51, 0xAB, 0x95, 0x22, 0xDF, 0x53, 0x85, 0x57, 0x22, 0x7A, 0x0F, 0x2F, 0x35, 0x9D, 0x55, 0x06, 0x8D, 0xB9, 0x9E, 0x38, 0xE6, 0x95, 0xCB, 0x08, 0xF0, 0x04, 0xEA, 0x5E, 0x9D, 0x6A, 0x41, 0xE6, 0x0D, 0x2A, 0x19, 0xA8, 0x0F, 0xFE, 0x44, 0xDE, 0x72, 0x70, 0x75, 0xE2, 0xF0, 0xCF, 0x3E, 0xC7, 0x99, 0x87, 0x86, 0xB4, 0x8B, 0x2A, 0xEA, 0x52, 0x63, 0x16, 0xAC, 0xC7, 0xED, 0xC6, 0xDB, 0x22, 0x98, 0xE5, 0x86, 0x1F, 0x6B, 0x52, 0x43, 0xF8, 0x7A, 0x40, 0x97, 0xA1, 0x50, 0x69, 0x23, 0x66, 0x7C, 0x64, 0xB5, 0x2E, 0x79, 0x00, 0x26, 0x8D, 0x03, 0xA8, 0xCF, 0x4F, 0x29, 0xB3, 0x92, 0x50, 0xCB, 0x8C, 0x5B, 0xB8, 0xB1, 0xB4, 0xC0, 0x16, 0x6B, 0x1E, 0x06, 0x03, 0x59, 0x0D, 0x5E, 0x45, 0x76, 0x59, 0x77, 0x82, 0x17, 0x34, 0xB8, 0x90, 0xE6, 0xC9, 0x6F, 0xF3, 0xE7, 0x53, 0x23, 0x68, 0xBD, 0xAB, 0xA5, 0x87, 0xE3, 0xFF, 0x2E, 0x43, 0xE5, 0x21, 0x74, 0xBC, 0x0A, 0x82, 0xD7, 0x20, 0x8C, 0x8B, 0x28, 0xA0, 0x56, 0x08, 0xAD, 0x21, 0xB9, 0xC6, 0x37, 0x24, 0xA0, 0x3E, 0x6B, 0x48, 0x99, 0x0D, 0x07, 0xB4, 0x00, 0xB6, 0x59, 0xDA, 0x2B, 0x5E, 0xA3, 0xA2, 0xAF, 0xF6, 0x7E, 0xED, 0x63, 0x95, 0x6B, 0x4E, 0x9B, 0x2D, 0x4D, 0xEF, 0x9A, 0x74, 0x96, 0xD2, 0xA0, 0x65, 0x6B, 0xD5, 0xB0, 0x04, 0x5C, 0x80, 0x8A, 0x1B, 0xB4, 0x77, 0xA0, 0xC5, 0xA0, 0x4F, 0xD7, 0xEE, 0x92, 0x87, 0xF0, 0xB6, 0x24, 0x90, 0x09, 0x63, 0x86, 0x72, 0x88, 0x09, 0x3D, 0x99, 0x7E, 0x7E, 0x4C, 0x96, 0x3D, 0x31, 0x87, 0x6F, 0x69, 0xCE, 0x0B, 0x8A, 0xF0, 0x54, 0x67, 0x98, 0xCC, 0x29, 0xFE, 0xD9, 0x08, 0x6A, 0x04, 0x50, 0x07, 0x48, 0x5F, 0xF9, 0x40, 0x01, 0xF2, 0x34, 0x96, 0x1B, 0xAD, 0xF9, 0xCB, 0x9E, 0xCF, 0x8B, 0x42, 0xC5, 0x74, 0x3F, 0xB0, 0x03, 0xB8, 0xAD, 0xF3, 0x30, 0x35, 0xEE, 0x39, 0xDA, 0x01, 0x62, 0x80, 0xA9, 0x51, 0x80, 0x34, 0xCC, 0x3A, 0x68, 0xF2, 0x9D, 0xCD, 0x24, 0xE5, 0xDB, 0xC6, 0x34, 0x30, 0xCB, 0x98, 0x09, 0xA5, 0x15, 0x49, 0x47, 0x77, 0x98, 0x59, 0xBF, 0x56, 0x08, 0x0B, 0x8E, 0x7C, 0x58, 0x4D, 0x68, 0xED, 0xC6, 0x95, 0x98, 0x52, 0xD0, 0x13, 0xCB, 0xA0, 0xDB, 0x01, 0xE1, 0x69, 0x8D, 0x1C, 0x31, 0x1D, 0x5D, 0xB8, 0xE1, 0xD1, 0x38, 0x80, 0x08, 0xC0, 0x07, 0xA0, 0x5C, 0x65, 0xA2, 0x9C, 0xEA, 0x4B, 0x1D, 0x86, 0x54, 0xA8, 0xBC, 0x0F, 0xD9, 0x2F, 0x29, 0xC0, 0x09, 0xA8, 0x03, 0xAE, 0x40, 0x58, 0x23, 0x81, 0xA4, 0x89, 0xD8, 0x05, 0x0F, 0xBA, 0x2B, 0x4D, 0xFF, 0x39, 0xE3, 0xF6, 0xE9, 0x89, 0xAB, 0x81, 0xB7, 0xAB, 0x9A, 0x7F, 0xBF, 0xAD, 0xC0, 0xC6, 0xD3, 0xFA, 0xD7, 0x63, 0xD4, 0xF4, 0xBA, 0xEF, 0x93, 0x63, 0x9F, 0xD4, 0x8E, 0xCD, 0x62, 0x5C, 0xE9, 0xAA, 0x8A, 0x15, 0x70, 0x56, 0xD2, 0x45, 0x57, 0x3E, 0x47, 0x0C, 0x88, 0x98, 0x81, 0x39, 0x34, 0x75, 0x40, 0xA2, 0xAB, 0xAA, 0x95, 0x8D, 0x27, 0x13, 0x9D, 0x86, 0xA3, 0x1E, 0xCB, 0xD1, 0x30, 0x01, 0x56, 0x40, 0x78, 0x3E, 0x9E, 0xB1, 0x67, 0x0E, 0x1E, 0x20, 0x14, 0xF0, 0x86, 0xF9, 0x7A, 0x3C, 0x5F, 0xD0, 0x90, 0xA6, 0xF5, 0x84, 0xE7, 0x90, 0xB9, 0x7D, 0x3A, 0x0E, 0x2B, 0xBE, 0xC3, 0x43, 0x20, 0x16, 0xD6, 0xEC, 0xBE, 0x4F, 0xC3, 0x6F, 0xC2, 0xD5, 0xF9, 0x8D, 0x5D, 0x25, 0x18, 0x07, 0x5A, 0x24, 0xC1, 0x46, 0x37, 0x94, 0x05, 0xC0, 0x6B, 0xF6, 0xA4, 0x24, 0x40, 0xA7, 0x51, 0xC0, 0x93, 0xED, 0xAE, 0xB9, 0x06, 0xB4, 0x66, 0x3B, 0xF8, 0xAF, 0x6E, 0xB1, 0x92, 0xE9, 0x0C, 0x46, 0x67, 0xD5, 0x0C, 0x6A, 0xA6, 0x44, 0x59, 0x00, 0x55, 0x20, 0x12, 0xA8, 0x0B, 0x5F, 0xBB, 0x02, 0x01, 0x56, 0xC0, 0x4B, 0xBE, 0x9F, 0x1B, 0x34, 0xFF, 0x4C, 0x4D, 0xE4, 0x08, 0x66, 0x18, 0xCB, 0xF0, 0x86, 0xC4, 0x17, 0xE9, 0xFB, 0x58, 0xD8, 0x99, 0x94, 0x91, 0x2C, 0x51, 0xE4, 0x6E, 0x6B, 0x4A, 0xBC, 0xE9, 0x4D, 0xF7, 0x66, 0x19, 0x8B, 0x19, 0x47, 0xD2, 0x71, 0x23, 0xA6, 0xDB, 0xC5, 0x29, 0x33, 0xEF, 0x70, 0x8B, 0x78, 0x01, 0xD8, 0x01, 0x98, 0x66, 0xEE, 0xD6, 0x6C, 0xCD, 0xDC, 0x4E, 0x80, 0xEE, 0x27, 0x9D, 0x06, 0x09, 0x29, 0xC3, 0xF3, 0xF7, 0x4B, 0x71, 0x01, 0x71, 0xA6, 0xCA, 0xE6, 0x1C, 0x80, 0x0A, 0x90, 0x04, 0xB4, 0x00, 0xD3, 0x86, 0x37, 0x0C, 0xF0, 0x03, 0x04, 0x01, 0xC5, 0x1D, 0x34, 0x88, 0xD2, 0x84, 0xF2, 0x7B, 0x2E, 0x25, 0xF9, 0x93, 0x11, 0x25, 0x29, 0xF4, 0x7D, 0xD4, 0xD7, 0x70, 0xA4, 0x21, 0x59, 0x5B, 0x1E, 0xCF, 0xAA, 0x63, 0x9A, 0x83, 0x9D, 0x7D, 0x50, 0x7B, 0x9D, 0xEA, 0xFB, 0x78, 0x9D, 0xD3, 0xE0, 0x50, 0x0B, 0x38, 0xB1, 0x15, 0xC2, 0xEB, 0x0C, 0x40, 0x40, 0x08, 0xA0, 0xBA, 0x2E, 0x38, 0xD1, 0x10, 0x40, 0x1A, 0x75, 0x8F, 0xFA, 0x31, 0x0F, 0x55, 0x46, 0xB3, 0xC8, 0x75, 0xCE, 0xAA, 0x52, 0xAD, 0x09, 0xE7, 0xE6, 0x8D, 0x5C, 0x9F, 0x6C, 0x7E, 0xF2, 0x03, 0xA4, 0xDE, 0xA5, 0x96, 0xFF, 0x44, 0x5B, 0x02, 0xFF, 0x6D, 0x43, 0xF2, 0x4F, 0xE0, 0x83, 0x0E, 0xA1, 0x42, 0x28, 0x4A, 0x50, 0xE6, 0x10, 0xEA, 0x86, 0xA2, 0x67, 0x36, 0x6C, 0x0A, 0x6F, 0xE7, 0x70, 0x1F, 0x79, 0x09, 0x77, 0xF5, 0xE9, 0x18, 0x58, 0x6B, 0xB6, 0x30, 0x9F, 0x39, 0x13, 0x40, 0x2F, 0x76, 0x19, 0x6E, 0xD5, 0xFB, 0xB4, 0xD6, 0x90, 0x67, 0xBA, 0x81, 0x99, 0xC7, 0x53, 0xF1, 0x59, 0x35, 0xAC, 0xFB, 0x26, 0x38, 0x80, 0xC7, 0x2C, 0xC6, 0x14, 0xCD, 0x76, 0x10, 0x6E, 0x28, 0x35, 0xB4, 0xC1, 0x80, 0xE4, 0x84, 0x1A, 0x10, 0x72, 0x83, 0xD6, 0xD3, 0x8B, 0x0F, 0xCA, 0xC6, 0xD1, 0xAD, 0x3F, 0x9A, 0x18, 0xFA, 0x76, 0x52, 0x50, 0x57, 0x54, 0x46, 0x49, 0xD7, 0x03, 0x5B, 0x4C, 0xEA, 0x50, 0x0E, 0x19, 0xAD, 0x0E, 0xA9, 0xD0, 0xD9, 0x52, 0x13, 0xD1, 0xE0, 0x69, 0x16, 0x51, 0x0D, 0x6B, 0x08, 0x35, 0x72, 0xEA, 0x6F, 0x59, 0xA6, 0x4C, 0xD4, 0x75, 0x29, 0x75, 0x69, 0xEE, 0x82, 0x3C, 0x36, 0x7D, 0x7F, 0x45, 0x1C, 0xEB, 0x30, 0x09, 0x01, 0xC1, 0x40, 0x9D, 0x8E, 0x96, 0x01, 0xDC, 0xD0, 0x02, 0xDC, 0x1B, 0xD1, 0x10, 0xC0, 0xB4, 0x21, 0xCB, 0x1B, 0xE5, 0x06, 0x8D, 0xCE, 0xB7, 0xB6, 0x0E, 0xC7, 0x57, 0x01, 0x0D, 0x43, 0xFE, 0xDB, 0xCB, 0x3E, 0x23, 0x00, 0x76, 0x86, 0xC6, 0xB0, 0x3E, 0xD0, 0x41, 0x21, 0x34, 0x53, 0x79, 0x0C, 0x26, 0x70, 0x5A, 0xCD, 0x3E, 0xA1, 0x4F, 0x14, 0x37, 0xCB, 0x62, 0x91, 0x80, 0xCC, 0xBF, 0xDA, 0xE1, 0x7B, 0xC4, 0x02, 0xD4, 0x80, 0x67, 0xEE, 0x47, 0x33, 0x65, 0x7D, 0x1F, 0xA5, 0x5A, 0x65, 0x5C, 0x3B, 0x8D, 0x21, 0x59, 0x85, 0xD4, 0xB1, 0x77, 0xB3, 0xB5, 0x71, 0x79, 0x02, 0xC5, 0x53, 0x33, 0x28, 0x07, 0xB0, 0x04, 0x42, 0x1A, 0xD6, 0x60, 0xC0, 0xA3, 0x61, 0x40, 0xDC, 0x64, 0xD6, 0x0D, 0x1A, 0x75, 0x97, 0x0F, 0x4E, 0x68, 0x29, 0xB8, 0x8B, 0x9A, 0x42, 0x6E, 0x65, 0x22, 0x90, 0x29, 0x27, 0x63, 0xA1, 0x08, 0xA1, 0x2E, 0x94, 0x32, 0x66, 0x6F, 0x19, 0xEF, 0x95, 0x76, 0xE6, 0xCC, 0xF8, 0xD4, 0x09, 0x4B, 0x80, 0x79, 0x76, 0x27, 0xFA, 0x98, 0x62, 0x63, 0xAF, 0x52, 0x47, 0x09, 0x9C, 0x35, 0x11, 0xF7, 0xAC, 0x43, 0x1C, 0x27, 0x40, 0x0E, 0xD8, 0xFD, 0xDF, 0xCF, 0x6C, 0x18, 0xF0, 0x04, 0x8A, 0x96, 0xDD, 0x21, 0x01, 0xD2, 0xB0, 0xFC, 0x51, 0x56, 0x77, 0x07, 0x8C, 0x01, 0x5D, 0x3B, 0x5C, 0xE6, 0x0D, 0x1A, 0x63, 0x17, 0x23, 0xFD, 0xC4, 0x2F, 0x44, 0xF6, 0xBD, 0x17, 0x54, 0xD1, 0x56, 0xC6, 0xC7, 0x86, 0xF7, 0xB7, 0x6A, 0x7D, 0x87, 0xF0, 0xF0, 0x9C, 0x2B, 0x8D, 0xD7, 0xDC, 0x90, 0xC4, 0x1A, 0xF9, 0xAB, 0x16, 0x18, 0xE0, 0x3C, 0xDF, 0x94, 0x06, 0x48, 0xAC, 0xEE, 0x32, 0x5E, 0x72, 0xD8, 0xA2, 0x06, 0x03, 0x2A, 0x73, 0x90, 0x86, 0xCD, 0xDB, 0x06, 0x35, 0xDC, 0x47, 0xFA, 0x93, 0x5E, 0xE6, 0x9A, 0x0B, 0x70, 0x06, 0xC2, 0x81, 0xCC, 0xB5, 0xE0, 0x08, 0xD0, 0x68, 0x78, 0x43, 0x00, 0x31, 0x80, 0x13, 0x10, 0x07, 0x3C, 0x3A, 0x68, 0x82, 0xDE, 0x17, 0x96, 0x6F, 0xA6, 0x2B, 0x0F, 0x73, 0x48, 0xE9, 0x04, 0x1B, 0x06, 0x6F, 0xE1, 0x87, 0x7B, 0x76, 0xE5, 0xC1, 0x86, 0x32, 0x61, 0xDD, 0xD8, 0xEF, 0x4E, 0xF5, 0x0C, 0xDC, 0xB0, 0x9C, 0xD0, 0x53, 0x57, 0xF8, 0x14, 0x02, 0xD0, 0xCB, 0xBE, 0xAE, 0x41, 0x9F, 0x06, 0xA8, 0x03, 0xDC, 0x38, 0x39, 0x0B, 0x03, 0xC9, 0x13, 0x51, 0x40, 0x75, 0x7C, 0xE4, 0x8A, 0xC0, 0x09, 0xA8, 0x58, 0x4E, 0x56, 0x35, 0x67, 0x8F, 0xD2, 0x01, 0xD8, 0x96, 0x83, 0x5A, 0x02, 0x26, 0x8D, 0x04, 0xDC, 0x80, 0xE0, 0x99, 0x53, 0x3F, 0x77, 0xA5, 0xE9, 0x0B, 0x93, 0x7C, 0x62, 0xDC, 0x44, 0x25, 0xB1, 0x04, 0x87, 0x5C, 0xA7, 0xD6, 0x1A, 0x4B, 0x6B, 0xA6, 0x1C, 0x63, 0x7C, 0xCD, 0xA7, 0x3F, 0x07, 0x8F, 0x22, 0xBB, 0xBE, 0x9E, 0x9D, 0x77, 0x71, 0x4B, 0x6E, 0x8C, 0xEA, 0x06, 0xBD, 0x62, 0x5E, 0x18, 0x40, 0x31, 0x6E, 0x32, 0xCA, 0x00, 0xD5, 0xDD, 0xBB, 0x01, 0x67, 0xC0, 0x0A, 0x70, 0xDF, 0xBB, 0x1F, 0x50, 0x7A, 0x3A, 0x92, 0xFA, 0xCA, 0x5A, 0xED, 0x44, 0xDF, 0xF1, 0x71, 0xC0, 0x0C, 0x88, 0x04, 0xEA, 0x16, 0x29, 0x14, 0x60, 0x01, 0xE4, 0x00, 0x4A, 0x80, 0x5D, 0x14, 0xE0, 0x09, 0xE4, 0x5D, 0x69, 0x76, 0x83, 0x06, 0x89, 0x5A, 0xF8, 0xB7, 0xE0, 0x3C, 0x20, 0xBA, 0x3A, 0xE6, 0x9D, 0x44, 0xBF, 0xD5, 0x02, 0xEA, 0xB3, 0x6E, 0xCE, 0x2A, 0x9E, 0xAF, 0x32, 0x81, 0xDE, 0xC7, 0x4C, 0x73, 0x2F, 0xED, 0x8E, 0x1D, 0xF0, 0x3A, 0x0B, 0xBC, 0x56, 0xAD, 0x6C, 0x95, 0xD3, 0xF2, 0xCC, 0xD5, 0x64, 0x17, 0x0A, 0x38, 0x37, 0xD6, 0x84, 0xD8, 0xE4, 0x97, 0xC4, 0x47, 0x44, 0xCE, 0x2D, 0xE2, 0xCC, 0xE2, 0x48, 0x10, 0x50, 0x1F, 0xBE, 0xB3, 0x3D, 0xC0, 0x0C, 0xC8, 0x45, 0x00, 0xEA, 0x80, 0x09, 0xE0, 0x0A, 0x04, 0x01, 0x2F, 0x68, 0xFE, 0x45, 0xAB, 0x34, 0xBF, 0xC6, 0x62, 0x93, 0xC0, 0xFF, 0xA6, 0xD9, 0xE6, 0x90, 0xD2, 0x65, 0xC9, 0x44, 0xD0, 0x8E, 0xF7, 0x03, 0x21, 0x5F, 0xD0, 0xB6, 0x70, 0xE8, 0x69, 0x31, 0xE3, 0x3E, 0x9E, 0xB1, 0xEC, 0xDC, 0xF2, 0xCC, 0x51, 0x04, 0x29, 0x00, 0xC5, 0xB5, 0xD9, 0x04, 0xFC, 0x00, 0x99, 0xF3, 0xBF, 0x15, 0x01, 0x5C, 0x73, 0x53, 0xE2, 0x1B, 0xB4, 0x04, 0xB4, 0x91, 0xF5, 0x62, 0xD7, 0x85, 0x93, 0x39, 0x91, 0x40, 0x09, 0x30, 0x05, 0x3C, 0x80, 0x8C, 0xDB, 0x8C, 0x0B, 0x70, 0x36, 0xA2, 0xA1, 0x00, 0x79, 0x83, 0x01, 0x16, 0xC0, 0x6E, 0xD0, 0xE2, 0x53, 0xBD, 0x58, 0xE6, 0x97, 0xBB, 0x65, 0xFE, 0x9B, 0x95, 0xFA, 0xA9, 0x6B, 0xB0, 0xDF, 0x79, 0x1A, 0xB2, 0xD7, 0xC8, 0x78, 0x47, 0xDA, 0x1D, 0x4C, 0xB0, 0xDF, 0x9E, 0xB6, 0x52, 0xA9, 0xBB, 0x35, 0xBC, 0xC1, 0xB9, 0x06, 0xC5, 0x36, 0xA2, 0x91, 0xAB, 0xD1, 0x56, 0x08, 0xA0, 0x5C, 0x8D, 0x4E, 0xD2, 0xD0, 0xF9, 0xA9, 0x74, 0x1A, 0xD0, 0xBC, 0x9E, 0x22, 0x9A, 0x09, 0x35, 0x2E, 0x40, 0x0D, 0xB0, 0x46, 0xAC, 0x79, 0x86, 0x55, 0x73, 0xE4, 0x46, 0x65, 0x43, 0x1B, 0xB2, 0xBA, 0xD1, 0xF4, 0xEE, 0x69, 0x18, 0x4C, 0x90, 0x63, 0x2A, 0xDE, 0xB7, 0x78, 0x71, 0xF2, 0x10, 0x0A, 0x54, 0xE6, 0xA8, 0x13, 0x0B, 0xC6, 0x38, 0xF3, 0x0B, 0x21, 0x58, 0x3F, 0x9D, 0x60, 0xAC, 0xE6, 0x84, 0x92, 0x2A, 0x20, 0xCF, 0x4C, 0x0A, 0x45, 0x01, 0xBC, 0x72, 0xF8, 0x56, 0xCB, 0x85, 0x82, 0xA7, 0xB8, 0x5A, 0x0D, 0x10, 0x6E, 0x68, 0xC3, 0x01, 0x1B, 0x2E, 0x00, 0x38, 0x80, 0x0C, 0x55, 0x50, 0xCA, 0x94, 0x2D, 0x39, 0xAF, 0x94, 0xDD, 0xD5, 0x24, 0x19, 0xA0, 0xDC, 0xA0, 0x75, 0xCB, 0xBD, 0x20, 0x40, 0x18, 0xF0, 0x77, 0x4E, 0xAB, 0xF6, 0x4C, 0xAB, 0x7F, 0x15, 0x2B, 0x76, 0xDF, 0xED, 0x44, 0xDB, 0xC8, 0x40, 0x71, 0xD8, 0x2F, 0xD4, 0x56, 0x08, 0x4E, 0x13, 0x4C, 0xBB, 0x4A, 0x50, 0x76, 0xA6, 0x7C, 0xDC, 0xE5, 0x87, 0x20, 0x59, 0x0C, 0x38, 0x35, 0x43, 0x12, 0xF2, 0xCB, 0x9A, 0xE5, 0x99, 0xC1, 0xCF, 0x00, 0x31, 0x35, 0x6C, 0x42, 0x87, 0x81, 0x92, 0xBC, 0xD5, 0xA1, 0x4B, 0x03, 0x5A, 0x36, 0x65, 0xA9, 0xA2, 0x80, 0x39, 0x90, 0x1D, 0xBC, 0xE3, 0x0B, 0x67, 0xD9, 0xC6, 0x27, 0x90, 0x2F, 0x86, 0x1D, 0x35, 0x86, 0xB4, 0x5B, 0xFF, 0xBC, 0xC1, 0xF2, 0x93, 0x02, 0x0B, 0x14, 0xDE, 0x19, 0x28, 0x25, 0x8A, 0xA3, 0x2E, 0xE4, 0x88, 0x5A, 0x60, 0x53, 0x63, 0xDF, 0x53, 0x2B, 0x0F, 0xCF, 0xDF, 0x3A, 0xFC, 0x47, 0xC2, 0x5B, 0xF3, 0xC7, 0x53, 0x17, 0xAB, 0x12, 0x10, 0x32, 0xA1, 0xB9, 0xA6, 0x56, 0x5E, 0xE4, 0xFC, 0x44, 0x0E, 0xB8, 0xEE, 0x6A, 0xDE, 0xB4, 0x03, 0x64, 0x59, 0x6D, 0x81, 0x3A, 0x33, 0x9C, 0xC9, 0x40, 0xE9, 0x44, 0xAE, 0x07, 0x24, 0x0C, 0xB8, 0x49, 0xB7, 0x97, 0x1C, 0xE2, 0x9E, 0xB7, 0x55, 0xF4, 0x82, 0xA6, 0x5F, 0xB1, 0x9B, 0xBE, 0x26, 0x16, 0x62, 0x54, 0x09, 0x24, 0x04, 0x3B, 0x94, 0x46, 0xA7, 0xE7, 0xB3, 0x15, 0xDE, 0xDB, 0xFA, 0xBC, 0x03, 0x63, 0x4B, 0x80, 0xEF, 0x01, 0xA8, 0xCD, 0xD9, 0xDD, 0x46, 0xC0, 0x39, 0xAB, 0xC2, 0xE7, 0xAB, 0xF4, 0xC4, 0xD3, 0x78, 0x44, 0x1B, 0x72, 0x21, 0x0D, 0x05, 0x74, 0xD8, 0x05, 0xE1, 0x8F, 0x1E, 0x57, 0x58, 0xBF, 0xDB, 0x51, 0x02, 0xC3, 0xC0, 0x78, 0x18, 0xDC, 0x09, 0x90, 0xD6, 0xF0, 0xF5, 0x89, 0x1A, 0xDC, 0xB0, 0x39, 0x4A, 0x50, 0x98, 0xDB, 0xF4, 0x85, 0x3E, 0x43, 0x18, 0x32, 0xFE, 0xB2, 0x42, 0xA1, 0x0C, 0x7B, 0xAB, 0x68, 0x2D, 0x3F, 0x19, 0xFC, 0x6E, 0x4A, 0x21, 0xE9, 0xAF, 0x1C, 0x35, 0xCF, 0xE5, 0x34, 0xC1, 0xAF, 0x6C, 0xE8, 0x37, 0x4C, 0x32, 0x53, 0x3D, 0xB6, 0xDC, 0x0E, 0x22, 0x01, 0x2D, 0x40, 0x62, 0x35, 0xAB, 0x16, 0x70, 0x96, 0x93, 0x8B, 0x6A, 0x83, 0x01, 0x49, 0x40, 0x63, 0x56, 0x5C, 0x5F, 0x4E, 0x49, 0x67, 0x86, 0x5C, 0x0D, 0x30, 0x07, 0x5C, 0x66, 0x5C, 0x8F, 0x03, 0xCC, 0x0D, 0x02, 0x48, 0xE6, 0x8E, 0x5C, 0xB4, 0x2A, 0xCC, 0x7C, 0x83, 0x26, 0x4F, 0x59, 0x95, 0x81, 0x32, 0x44, 0x20, 0x6F, 0xDD, 0x33, 0x30, 0x6E, 0x2A, 0x21, 0x90, 0xD0, 0x32, 0x6A, 0x71, 0x91, 0xCC, 0x8C, 0xDA, 0xB6, 0xD4, 0x7C, 0x89, 0x6B, 0x59, 0xDE, 0x4C, 0x34, 0x25, 0x72, 0x9C, 0x73, 0x82, 0xAB, 0x47, 0x23, 0x81, 0xD2, 0xD5, 0x43, 0xB5, 0xEB, 0xEA, 0xB6, 0xBA, 0x5D, 0x18, 0x20, 0x02, 0xF2, 0xCC, 0x37, 0x81, 0xAC, 0x39, 0x66, 0xEA, 0x80, 0xEB, 0x1A, 0x53, 0xB9, 0x5A, 0x0A, 0x54, 0x1B, 0x02, 0xC8, 0x92, 0xA7, 0x93, 0xCC, 0x4F, 0x16, 0x37, 0x68, 0xFA, 0x8F, 0x12, 0x4F, 0x62, 0x1E, 0x98, 0x68, 0x0A, 0x0A, 0x91, 0x28, 0xB4, 0x08, 0x23, 0xD7, 0x6B, 0x8A, 0x7A, 0x2B, 0xDE, 0x0B, 0x51, 0x6A, 0xA3, 0x88, 0xA7, 0x3E, 0x1A, 0xA4, 0xE4, 0xA5, 0x9C, 0xB9, 0xE6, 0x5F, 0x86, 0xEA, 0x66, 0x05, 0x67, 0x2E, 0xFE, 0xD8, 0xEC, 0xB2, 0x21, 0x5D, 0x1E, 0xA5, 0x06, 0x68, 0xE3, 0xE8, 0x2A, 0xDB, 0xD5, 0xD4, 0x3F, 0xCA, 0xDD, 0x07, 0xEE, 0xEF, 0x39, 0x2A, 0x25, 0x44, 0xEF, 0x52, 0xA6, 0x0C, 0xA4, 0xDD, 0x7B, 0xDB, 0xBA, 0x4B, 0x9E, 0x95, 0xDF, 0x28, 0x20, 0xB9, 0x61, 0x8D, 0x9A, 0xFD, 0xAB, 0xCC, 0x1D, 0x34, 0x6B, 0x79, 0x56, 0x62, 0x20, 0x2A, 0xDB, 0xD7, 0x29, 0x5B, 0xA7, 0xBE, 0x4C, 0x2E, 0x91, 0xE2, 0x8E, 0x8E, 0x2C, 0xA4, 0xB3, 0xF7, 0x70, 0x07, 0xD3, 0xCE, 0x42, 0xEE, 0xC9, 0x04, 0xBE, 0x8C, 0x60, 0xEE, 0x7B, 0x68, 0x65, 0x21, 0xF5, 0xCC, 0xE9, 0xA3, 0x2C, 0xB3, 0x4B, 0xC2, 0xBC, 0xA1, 0x8D, 0x00, 0xC4, 0x67, 0x78, 0x6B, 0x77, 0xC7, 0x9F, 0xD1, 0xCB, 0x3D, 0x8D, 0x14, 0xD0, 0x6C, 0xBC, 0x5A, 0x60, 0xC4, 0x00, 0x57, 0x20, 0x79, 0xE5, 0xBD, 0x73, 0x15, 0xEA, 0xAC, 0x11, 0x80, 0x52, 0xC3, 0x01, 0x6B, 0x84, 0x77, 0xD0, 0xFC, 0xDD, 0xA3, 0xFC, 0xA0, 0xB4, 0xC2, 0xD4, 0x7E, 0xF1, 0x09, 0x91, 0x07, 0x8C, 0x0C, 0x90, 0x50, 0x63, 0x4E, 0x64, 0xB2, 0xF0, 0x3F, 0x94, 0xEC, 0x7B, 0x94, 0x9C, 0x3F, 0xEB, 0xB4, 0x02, 0x90, 0xA7, 0x28, 0x20, 0x7C, 0x4C, 0x55, 0x24, 0x5E, 0xD3, 0x79, 0x05, 0xE0, 0x04, 0x68, 0x4F, 0x13, 0x51, 0x40, 0x0E, 0xC0, 0x0D, 0xA1, 0x46, 0x01, 0xE1, 0xEF, 0x18, 0xD5, 0xF1, 0xE9, 0xF3, 0xBE, 0xF0, 0x5F, 0x93, 0x72, 0xF4, 0x65, 0x17, 0x27, 0x89, 0x71, 0x65, 0x32, 0x05, 0x82, 0x81, 0xA4, 0x46, 0x00, 0xF5, 0xA1, 0xFE, 0x7F, 0xA7, 0x41, 0x0D, 0x6E, 0x28, 0x75, 0xD0, 0x02, 0xCE, 0x2F, 0xAF, 0x71, 0xB1, 0xF7, 0x34, 0xE9, 0xB9, 0x35, 0x21, 0xD8, 0x0A, 0x85, 0xDB, 0x23, 0xB2, 0xCF, 0x0F, 0x62, 0xED, 0xCF, 0xB4, 0x53, 0xB7, 0x35, 0xBD, 0x70, 0x32, 0x57, 0x9A, 0x75, 0xE5, 0xFC, 0xE5, 0xCC, 0x71, 0xD4, 0xB6, 0x84, 0x52, 0xBB, 0x65, 0xF5, 0x9C, 0x35, 0xB7, 0x5E, 0x1A, 0xDE, 0x88, 0xE9, 0xAD, 0x0C, 0xE8, 0x7B, 0x5F, 0x9A, 0xFC, 0xA5, 0xC9, 0x72, 0x8F, 0xBE, 0x7C, 0x99, 0x29, 0x5A, 0x19, 0x6E, 0xF7, 0x86, 0x01, 0x56, 0x80, 0x0A, 0x20, 0x06, 0xA8, 0x03, 0xF9, 0x5E, 0x04, 0x09, 0xE3, 0xEB, 0xB0, 0x6F, 0xA5, 0xB9, 0x2E, 0x37, 0xD2, 0xA4, 0xAE, 0xA9, 0x3A, 0xAA, 0x59, 0x4A, 0xF8, 0xAB, 0x10, 0xE1, 0xB1, 0xDC, 0xFD, 0x51, 0x24, 0x6F, 0xCF, 0x7F, 0xC9, 0x77, 0x5C, 0xB2, 0x19, 0x90, 0x3F, 0x31, 0x6E, 0xBD, 0xCE, 0x14, 0xF3, 0x69, 0x1C, 0xC9, 0x34, 0x1B, 0x95, 0xE4, 0xCC, 0x11, 0xCC, 0xDA, 0x10, 0x05, 0xF4, 0x34, 0x04, 0x88, 0x7B, 0x2E, 0x88, 0xBF, 0x92, 0x30, 0xD1, 0x13, 0xA2, 0x66, 0x6F, 0x58, 0x4E, 0x53, 0x64, 0xC8, 0xFC, 0x63, 0x38, 0x5E, 0x5C, 0x14, 0x90, 0xD2, 0x08, 0xA0, 0xB6, 0x49, 0xBA, 0x76, 0xD0, 0xEA, 0x1F, 0xA3, 0xA4, 0x02, 0x57, 0x48, 0x72, 0xEC, 0x69, 0x82, 0xCA, 0x67, 0x5E, 0xF5, 0xB5, 0xC4, 0xBF, 0xC4, 0xD0, 0x15, 0x54, 0x70, 0x8C, 0xE7, 0x30, 0x24, 0x5D, 0x33, 0x65, 0x4B, 0x9E, 0xAA, 0x7A, 0x26, 0xBA, 0x3D, 0x86, 0xBD, 0xC1, 0x6B, 0x25, 0xB7, 0x99, 0x3C, 0x65, 0x01, 0x68, 0x0D, 0x9A, 0xF5, 0x03, 0x1C, 0xEB, 0x10, 0x6E, 0x20, 0x5A, 0x6F, 0xD7, 0x94, 0xD9, 0xA7, 0x72, 0x47, 0x10, 0x22, 0x25, 0x8A, 0xC0, 0xDC, 0xDF, 0xBA, 0x21, 0x07, 0x30, 0x07, 0x32, 0x3B, 0x4D, 0x66, 0x8D, 0x02, 0xE8, 0xAC, 0x2F, 0x2A, 0x40, 0x0E, 0xDC, 0x73, 0x9A, 0x60, 0xBE, 0xCA, 0x39, 0xF4, 0xB5, 0x17, 0xF3, 0x71, 0x64, 0xD2, 0x8C, 0x51, 0x78, 0x77, 0x6B, 0x5F, 0x25, 0xC7, 0xE9, 0x59, 0x08, 0x5B, 0x7D, 0xD2, 0xE8, 0xC4, 0x53, 0x6D, 0x16, 0xC8, 0xEF, 0x54, 0x44, 0xBF, 0x4C, 0x86, 0x38, 0x3B, 0xB0, 0xEB, 0x90, 0xCB, 0xDA, 0xB0, 0x65, 0xEC, 0xB3, 0x34, 0x3B, 0x1C, 0x00, 0xFD, 0x72, 0xAE, 0xD2, 0xF3, 0xD7, 0x9D, 0xE1, 0xCF, 0xD1, 0x69, 0x5B, 0x90, 0xC5, 0x4B, 0x0B, 0x37, 0x28, 0x01, 0xA9, 0x35, 0x92, 0x32, 0x80, 0x24, 0x20, 0xAA, 0xE1, 0xEB, 0xBF, 0xD9, 0x33, 0x34, 0x40, 0xD4, 0xDE, 0x80, 0x15, 0x4C, 0x17, 0x4F, 0x45, 0x47, 0xDE, 0xA1, 0xEF, 0x90, 0x6B, 0xA7, 0x30, 0x70, 0xCF, 0x13, 0x93, 0x9C, 0xD2, 0x70, 0x4A, 0xB4, 0xD9, 0xF4, 0xE9, 0xBE, 0x1A, 0xA4, 0x8E, 0xCF, 0xE4, 0x40, 0x25, 0x10, 0x34, 0xCB, 0x6F, 0xEF, 0xDC, 0xBE, 0x72, 0x12, 0xC4, 0xAB, 0x7F, 0x64, 0x35, 0x3F, 0x08, 0xCF, 0xB8, 0x0A, 0x37, 0x02, 0x78, 0x5A, 0xC7, 0xDB, 0x46, 0x34, 0xB2, 0x98, 0x74, 0x5E, 0xCE, 0xCE, 0x08, 0xB8, 0xF3, 0x0A, 0x68, 0x29, 0x5B, 0x54, 0x01, 0xA3, 0xC6, 0x52, 0x9D, 0x87, 0x00, 0x79, 0x96, 0x73, 0x31, 0x77, 0xD0, 0x18, 0x5D, 0x0E, 0xC9, 0xDF, 0x52, 0x2B, 0xA3, 0xE1, 0x07, 0x43, 0x46, 0x68, 0x74, 0xC4, 0x0B, 0x21, 0x23, 0xBB, 0x01, 0xC7, 0x6F, 0x57, 0xD9, 0x3E, 0xA8, 0x8D, 0xE9, 0x93, 0xF1, 0x8A, 0x4D, 0xBA, 0x4D, 0xAA, 0x64, 0x9E, 0xD7, 0xE2, 0x00, 0x67, 0x8D, 0xA9, 0x3B, 0x32, 0x3B, 0xD9, 0x39, 0x97, 0x2F, 0xA7, 0x2D, 0x1D, 0xAD, 0x3F, 0x19, 0xDA, 0xBB, 0x60, 0xBE, 0xF6, 0xA5, 0x7C, 0x95, 0x7E, 0x7B, 0xBE, 0x76, 0x0D, 0x17, 0x20, 0xEF, 0xB8, 0x15, 0x01, 0x98, 0x00, 0xB9, 0x08, 0x40, 0xB5, 0x11, 0x80, 0xC9, 0x3A, 0xB2, 0xDC, 0xE7, 0x53, 0x7A, 0x96, 0x52, 0x7E, 0xB7, 0x4E, 0x31, 0xEA, 0xE2, 0x82, 0x7D, 0xAF, 0x4F, 0x0F, 0xC2, 0xAE, 0x60, 0x8A, 0x7F, 0x00, 0xA9, 0xFE, 0x71, 0x32, 0x4B, 0x2B, 0x32, 0x4A, 0x2B, 0x7D, 0x9A, 0x7A, 0x83, 0x4A, 0xF7, 0x70, 0x89, 0x67, 0x62, 0x22, 0xEF, 0xDF, 0xF3, 0xF9, 0x58, 0x31, 0x60, 0xB4, 0xAC, 0x62, 0x78, 0x75, 0x59, 0x38, 0x40, 0x05, 0xF0, 0x6A, 0xA9, 0xBB, 0x07, 0xD9, 0xD4, 0xDE, 0xDF, 0xE5, 0x4F, 0xFB, 0x8E, 0x97, 0x0D, 0x8E, 0x09, 0xF5, 0x01, 0xF5, 0x04, 0xFE, 0x12, 0x34, 0x80, 0x1D, 0x20, 0x02, 0xA8, 0xD3, 0xF8, 0x3E, 0x21, 0xA0, 0x80, 0x03, 0x44, 0x00, 0x33, 0xA0, 0xDA, 0x41, 0xD3, 0xB7, 0xB6, 0x54, 0xBE, 0x9D, 0xEB, 0x1F, 0xFF, 0x07, 0x0A, 0xFF, 0xBE, 0xA8, 0xC2, 0xFB, 0xA7, 0xBC, 0x65, 0x11, 0x82, 0x8E, 0x41, 0xEB, 0xD1, 0x51, 0xBF, 0x7D, 0x60, 0xE8, 0x8D, 0x94, 0xEB, 0x14, 0x6E, 0x36, 0x14, 0x20, 0xBA, 0xC9, 0xF0, 0xA1, 0x62, 0x12, 0x01, 0x98, 0x01, 0x5D, 0xEA, 0x27, 0x17, 0x40, 0x18, 0xE0, 0x6D, 0x82, 0x63, 0xC3, 0xFD, 0x86, 0x10, 0xC2, 0xD7, 0xE7, 0xE2, 0xFD, 0x26, 0xC0, 0xA9, 0x1A, 0xE7, 0x2E, 0x45, 0xD0, 0xA4, 0x00, 0x4F, 0xA0, 0x18, 0x61, 0x22, 0x01, 0x98, 0x01, 0x11, 0x40, 0x15, 0xB0, 0x86, 0x27, 0x90, 0x07, 0x28, 0xE9, 0xA0, 0xD9, 0x0D, 0xDA, 0x76, 0x0B, 0xC6, 0x95, 0xC0, 0x0A, 0xEF, 0xB4, 0x40, 0x57, 0x99, 0xE8, 0x07, 0x17, 0xBB, 0xD3, 0x90, 0xB6, 0xD1, 0xC4, 0xDD, 0xD7, 0xDF, 0x40, 0xE7, 0x79, 0x25, 0x30, 0xFE, 0x4B, 0x2D, 0xD8, 0xBB, 0x3A, 0xDB, 0x4D, 0x4A, 0x2E, 0xF7, 0x12, 0x5B, 0xC3, 0x01, 0xDC, 0x01, 0x4E, 0x80, 0x1A, 0xEC, 0x80, 0x30, 0xE0, 0xFC, 0xD7, 0x91, 0xE7, 0xAF, 0x80, 0x4E, 0x81, 0x48, 0xBE, 0x0B, 0x94, 0xD7, 0xAC, 0x58, 0xF8, 0x01, 0xEE, 0xD2, 0x3C, 0x04, 0x90, 0x02, 0x4C, 0x80, 0xEC, 0x44, 0xF9, 0x69, 0x24, 0x10, 0xDE, 0x41, 0xF3, 0x1D, 0xB4, 0xAF, 0x00, 0xAA, 0x01, 0x5F, 0xEA, 0x9E, 0x86, 0xE4, 0x15, 0x04, 0x6B, 0x46, 0x08, 0x49, 0xC3, 0x72, 0x0D, 0xF6, 0xF1, 0xD5, 0xC8, 0x9E, 0x35, 0xEB, 0xB6, 0xB2, 0x54, 0xBF, 0xFC, 0x7A, 0x14, 0xA7, 0x59, 0x14, 0xF9, 0x8F, 0x9C, 0x1B, 0x2F, 0x63, 0xE9, 0x9D, 0x1B, 0x92, 0x02, 0xD4, 0x81, 0x9B, 0x08, 0x16, 0x5F, 0xD3, 0x90, 0xD8, 0xDF, 0x16, 0x8E, 0x50, 0x18, 0x50, 0x67, 0xEE, 0x18, 0xA6, 0xAB, 0x42, 0xA7, 0x40, 0xE9, 0x3A, 0x65, 0x18, 0xC0, 0x0D, 0x11, 0x40, 0xA3, 0x83, 0x16, 0xFF, 0x04, 0x62, 0xD1, 0x17, 0x34, 0xFB, 0x8A, 0x93, 0x7D, 0x25, 0x38, 0xD2, 0x1A, 0xAF, 0xC4, 0x66, 0x1B, 0xDC, 0x62, 0x48, 0x99, 0x93, 0x78, 0xCF, 0x1E, 0x4D, 0x10, 0x71, 0xB3, 0x75, 0x33, 0x5C, 0xDE, 0x38, 0x3C, 0xA7, 0xDD, 0x79, 0x4E, 0x9D, 0x5E, 0x3A, 0xE0, 0x05, 0x98, 0x4C, 0x31, 0xB7, 0x06, 0x20, 0xD4, 0x58, 0x03, 0x07, 0xDE, 0x4A, 0x0D, 0x44, 0xED, 0x3D, 0xC2, 0xFD, 0xD0, 0x2E, 0x07, 0xF5, 0xEF, 0x94, 0x02, 0x68, 0x02, 0x37, 0xA2, 0x24, 0x80, 0x70, 0xC3, 0x26, 0x38, 0x1A, 0x02, 0x88, 0x02, 0x41, 0x1D, 0xB5, 0x7C, 0x4B, 0x2D, 0xED, 0x75, 0x70, 0xB9, 0x14, 0xBC, 0x5B, 0x25, 0x7B, 0x9A, 0x23, 0x1E, 0x53, 0x63, 0x45, 0x0C, 0x69, 0xCE, 0xFA, 0xCC, 0xF7, 0x26, 0x88, 0xA7, 0xD3, 0x7B, 0x97, 0x90, 0xF7, 0x06, 0x42, 0x37, 0xDC, 0x98, 0x04, 0xA2, 0x36, 0x6F, 0x01, 0x37, 0x99, 0xA5, 0x35, 0xFD, 0xE9, 0x74, 0x49, 0xF9, 0x38, 0x00, 0xA2, 0x25, 0xB3, 0xE2, 0xBF, 0x05, 0x6B, 0x8D, 0xEA, 0xD0, 0x3F, 0xB3, 0xD7, 0xE8, 0xA7, 0x0E, 0xF6, 0x9C, 0xD8, 0xCD, 0x7A, 0x57, 0x3A, 0x0C, 0x48, 0xC3, 0x08, 0xF0, 0x46, 0x9C, 0x46, 0x02, 0xD9, 0xA8, 0xEA, 0xF7, 0x42, 0x83, 0xEE, 0x52, 0xAB, 0x7E, 0xFF, 0x10, 0x5C, 0x12, 0x98, 0x90, 0xD4, 0x71, 0x68, 0x60, 0x54, 0xA2, 0x67, 0x5F, 0x32, 0xC6, 0x4D, 0xAA, 0xB5, 0xA2, 0xAE, 0xBA, 0x33, 0x6A, 0x1B, 0x6A, 0xF2, 0x72, 0x04, 0xA3, 0x33, 0x0F, 0x40, 0x34, 0x67, 0x48, 0xF5, 0xDC, 0x9D, 0x57, 0xF9, 0xC8, 0x02, 0x6E, 0xBE, 0xC2, 0x0D, 0xE0, 0x0E, 0x85, 0x07, 0x40, 0x3B, 0xC1, 0xE1, 0x00, 0x0D, 0xA5, 0x76, 0x5C, 0x01, 0xFD, 0x79, 0x2F, 0x04, 0xA1, 0xBF, 0x39, 0x63, 0xF8, 0x43, 0x11, 0xC2, 0x04, 0x8C, 0x80, 0xEC, 0x0B, 0xFC, 0x31, 0x80, 0xA9, 0xE1, 0x80, 0x48, 0x43, 0x01, 0xA5, 0x46, 0x01, 0xA1, 0x08, 0xDA, 0xDF, 0x7D, 0x33, 0x19, 0xAF, 0x4F, 0x91, 0xFF, 0x00, 0xA5, 0xCF, 0xD2, 0x44, 0x40, 0x45, 0xBF, 0xBD, 0x2D, 0xF5, 0xA0, 0x93, 0x1D, 0x96, 0x43, 0x32, 0x06, 0xA4, 0x0E, 0x85, 0xF7, 0x13, 0x95, 0xF0, 0xF2, 0x46, 0xF6, 0x17, 0x1F, 0xBC, 0x25, 0xD6, 0x14, 0x15, 0xE1, 0x79, 0xD6, 0xF5, 0x00, 0x8C, 0x81, 0xC3, 0xAB, 0x9B, 0x44, 0x00, 0x5D, 0x8E, 0x4E, 0xCF, 0x68, 0xB9, 0xC6, 0x0C, 0x0D, 0x7B, 0x75, 0xDF, 0x74, 0x2C, 0x15, 0x80, 0x7A, 0xFD, 0x7C, 0xC7, 0x5A, 0xC0, 0x1D, 0x28, 0x3A, 0xDF, 0x71, 0xE1, 0x38, 0x40, 0x09, 0xC8, 0x01, 0x54, 0x00, 0x0B, 0xC0, 0x13, 0xC8, 0x1B, 0x34, 0x42, 0x29, 0x99, 0x65, 0xCC, 0xAA, 0xB1, 0x20, 0xCC, 0x90, 0x3A, 0x85, 0xA6, 0x7A, 0x72, 0x1C, 0x5C, 0x2B, 0x3F, 0xC4, 0x41, 0xD0, 0xDE, 0xE9, 0xB6, 0xB6, 0x1A, 0x72, 0x0B, 0x81, 0x9C, 0x00, 0x39, 0x1D, 0x92, 0x04, 0xDE, 0x41, 0xB8, 0x7E, 0x8C, 0x61, 0xE7, 0xD5, 0x9A, 0xE2, 0x07, 0x60, 0x05, 0xC8, 0x00, 0x5E, 0x5F, 0xD4, 0x98, 0x96, 0xB1, 0xC9, 0x7F, 0x7E, 0x1E, 0xF9, 0x6C, 0xFC, 0x34, 0x80, 0xF4, 0xF7, 0x10, 0x00, 0xD2, 0x30, 0x02, 0x5C, 0x97, 0x3A, 0x4C, 0x17, 0xC6, 0x90, 0x59, 0xAC, 0x0E, 0x44, 0x8D, 0xBF, 0x2A, 0x7B, 0x1C, 0x19, 0xD9, 0xA1, 0x53, 0x10, 0x2D, 0x47, 0xB5, 0x76, 0xCA, 0x08, 0x79, 0xD9, 0x0A, 0x14, 0x73, 0x33, 0x47, 0xC6, 0x5B, 0x6A, 0x1B, 0xC6, 0xD3, 0x72, 0xDE, 0xF2, 0xD5, 0x7B, 0x4F, 0x3F, 0xE7, 0x7C, 0x9C, 0x65, 0x81, 0x76, 0x3F, 0x05, 0xE0, 0xF2, 0xEB, 0xD4, 0xC1, 0x0D, 0x9F, 0x51, 0xD3, 0xA7, 0x16, 0xEC, 0xC7, 0x9C, 0xFA, 0xCC, 0xD3, 0x88, 0xBC, 0xB9, 0x02, 0x40, 0x1A, 0xB6, 0xA4, 0xF0, 0x25, 0x0D, 0x6F, 0x64, 0xC3, 0x1A, 0xCF, 0x0A, 0xD1, 0x00, 0xCE, 0x8E, 0x9A, 0xFC, 0x3E, 0xAA, 0x99, 0x43, 0x48, 0xF4, 0x9D, 0x08, 0xDD, 0xB1, 0x5B, 0x73, 0xA2, 0x16, 0xAD, 0x67, 0x8D, 0xDE, 0x5A, 0xCA, 0xBE, 0xBB, 0x65, 0x3D, 0x37, 0x41, 0xFF, 0x3B, 0x84, 0x26, 0xBE, 0xF5, 0xBD, 0x03, 0xEC, 0x0D, 0x10, 0x0C, 0x9F, 0x17, 0x4E, 0x5A, 0xA5, 0xD3, 0xB3, 0xA6, 0x2E, 0x8A, 0x01, 0xDA, 0xB0, 0x46, 0x8D, 0xE1, 0x1F, 0xF7, 0xCA, 0x46, 0xFC, 0x24, 0x40, 0xF9, 0x21, 0x9E, 0x14, 0xC3, 0x6E, 0x7A, 0xD1, 0x00, 0x3D, 0x80, 0x0B, 0x10, 0x01, 0xD4, 0x7A, 0x5B, 0x50, 0x83, 0x15, 0x10, 0x07, 0x8C, 0x3A, 0x68, 0xBA, 0xA3, 0x35, 0xAB, 0xED, 0xDA, 0x85, 0x4C, 0x6D, 0xF3, 0x82, 0x30, 0x54, 0x42, 0xC3, 0x67, 0x99, 0x3D, 0xB6, 0x91, 0xDA, 0xB2, 0x56, 0xCD, 0x6C, 0xEC, 0xD6, 0xBC, 0x02, 0xC2, 0xFF, 0x0E, 0x1D, 0xFA, 0x02, 0xEA, 0xF7, 0x62, 0x74, 0x1C, 0x78, 0xC9, 0xDF, 0xC4, 0x8A, 0x79, 0xB5, 0x92, 0x79, 0x74, 0x39, 0x35, 0xF3, 0x98, 0xC4, 0xD3, 0xA7, 0xD5, 0xAB, 0x21, 0x0D, 0x9A, 0x9F, 0xA2, 0x51, 0xAB, 0x5B, 0xF5, 0xF7, 0x04, 0x12, 0x5B, 0xCE, 0x6B, 0x7A, 0x3A, 0x68, 0xF6, 0x35, 0x7C, 0x7A, 0xD2, 0x0E, 0x1A, 0x9A, 0xF1, 0x38, 0x50, 0x66, 0x37, 0xE8, 0x6F, 0x43, 0x04, 0xAB, 0xC0, 0x97, 0xA0, 0xC3, 0x77, 0x7A, 0xE8, 0x34, 0x5C, 0x80, 0xA8, 0xDD, 0x34, 0xDB, 0x38, 0x8D, 0x31, 0xAD, 0x4D, 0x9F, 0xDE, 0xF8, 0xCD, 0x70, 0xB4, 0x9B, 0xDB, 0xE7, 0x71, 0x68, 0x69, 0xD7, 0xA0, 0xD7, 0x9D, 0x19, 0x4B, 0x1D, 0x49, 0x34, 0x6D, 0x57, 0x2D, 0xB7, 0x23, 0x59, 0xC3, 0xE6, 0x27, 0x23, 0x20, 0x96, 0x83, 0x48, 0x3A, 0x10, 0x09, 0xF8, 0xB2, 0x40, 0x77, 0x9D, 0xDE, 0xE7, 0xA2, 0xFE, 0x0D, 0x74, 0xE0, 0xDA, 0x51, 0x6B, 0x77, 0x48, 0xB4, 0x18, 0x27, 0xE1, 0x80, 0x6B, 0x2E, 0x86, 0xF2, 0xA6, 0x6A, 0x1F, 0x70, 0xB7, 0x27, 0xD8, 0x72, 0xD5, 0xF5, 0x46, 0x08, 0xE0, 0xBE, 0x12, 0xDA, 0x17, 0x02, 0xF8, 0x18, 0xC7, 0x83, 0xC6, 0xC2, 0xA1, 0xB7, 0xF0, 0xC6, 0x79, 0xA5, 0xDB, 0x69, 0x75, 0x72, 0xCE, 0x3C, 0x1E, 0x07, 0x01, 0xBA, 0x7A, 0xF9, 0x28, 0x1B, 0xBA, 0x60, 0xCB, 0x1D, 0x72, 0x8F, 0x70, 0x88, 0x86, 0x00, 0xD2, 0xE0, 0x00, 0xC4, 0x01, 0xE7, 0x1B, 0xB4, 0xF8, 0x96, 0x1A, 0x1D, 0x7B, 0x41, 0x8B, 0xEF, 0xF5, 0xAB, 0x30, 0x1D, 0x2A, 0xC2, 0x24, 0x19, 0x62, 0x08, 0xA8, 0x89, 0xD0, 0x89, 0x63, 0xB7, 0xCC, 0xBE, 0x5B, 0xA4, 0xCE, 0x99, 0x95, 0x82, 0xDB, 0x39, 0xE0, 0x04, 0x44, 0x35, 0xA2, 0x61, 0x8D, 0x9C, 0x53, 0xC1, 0x89, 0x5E, 0x42, 0xA9, 0x17, 0xD7, 0x07, 0x7A, 0xC3, 0xB6, 0x0D, 0x4B, 0xED, 0xDC, 0x83, 0xF1, 0xB2, 0x5C, 0x36, 0x9F, 0xF5, 0xD5, 0x60, 0x40, 0x57, 0x7F, 0x10, 0x67, 0x23, 0x00, 0x39, 0x80, 0xCA, 0x2F, 0xF3, 0xF3, 0x6A, 0xEC, 0x05, 0x1B, 0xCB, 0x66, 0xFF, 0x45, 0x2D, 0x3F, 0xC7, 0x78, 0x39, 0xFE, 0xA2, 0x56, 0x5F, 0x81, 0x02, 0x76, 0x3A, 0xDE, 0xB9, 0xC7, 0x4E, 0x48, 0x1A, 0x1B, 0x23, 0x8D, 0xE5, 0xDF, 0x52, 0x8B, 0x1B, 0x35, 0x8F, 0xDD, 0xF7, 0xF9, 0x12, 0x92, 0x00, 0x2F, 0x50, 0xAD, 0x76, 0x4C, 0x01, 0x6E, 0xEC, 0x74, 0xE8, 0xD6, 0x49, 0xDE, 0x2D, 0x5A, 0xE5, 0xC9, 0xD4, 0x9E, 0xC9, 0x6D, 0xBE, 0xF1, 0x94, 0x4E, 0xD3, 0x3F, 0xDE, 0x78, 0x4D, 0x93, 0x6A, 0x78, 0xC3, 0xB2, 0x11, 0x8D, 0x02, 0x82, 0x6F, 0xB0, 0x01, 0xCA, 0xC6, 0x52, 0x07, 0xA4, 0x01, 0xE1, 0xB3, 0x60, 0xC4, 0x79, 0x83, 0x56, 0x48, 0x3A, 0x86, 0xBF, 0xA0, 0xC5, 0x17, 0x12, 0xC3, 0x3D, 0xB4, 0x12, 0x7F, 0xBF, 0xEC, 0x76, 0x9F, 0xC2, 0xAF, 0xA7, 0x08, 0x6F, 0x9C, 0xAD, 0x8C, 0x27, 0x5F, 0x3D, 0x52, 0x1F, 0x0C, 0x18, 0x83, 0x28, 0xEC, 0x47, 0x41, 0xCE, 0xE3, 0x2F, 0x29, 0xF2, 0xDC, 0x46, 0xD0, 0x5D, 0x80, 0x83, 0xEA, 0xB8, 0x1D, 0xF2, 0xF3, 0x82, 0xD1, 0x68, 0xFB, 0xB0, 0x5E, 0x77, 0xCB, 0xE4, 0x9D, 0x73, 0xBA, 0x9E, 0x27, 0x03, 0x61, 0x0B, 0x01, 0xD4, 0x32, 0x95, 0x57, 0x06, 0x24, 0x01, 0x6E, 0x10, 0x01, 0xE7, 0xCC, 0x4F, 0x1A, 0x1D, 0x34, 0x3B, 0xFF, 0xEA, 0x2B, 0x93, 0x16, 0x66, 0x13, 0xD8, 0xDF, 0xFB, 0x13, 0xF9, 0x04, 0x64, 0x23, 0x94, 0x71, 0x66, 0x0D, 0xC6, 0xAB, 0xB1, 0x6F, 0x05, 0xB9, 0x73, 0xDE, 0x54, 0x73, 0x0B, 0xE8, 0xDC, 0xF5, 0x48, 0x84, 0x0F, 0x39, 0x42, 0xD2, 0x1A, 0x5C, 0x31, 0x2C, 0x2E, 0x21, 0x52, 0x19, 0x2D, 0x4F, 0xCC, 0xF8, 0xC4, 0x37, 0x81, 0x2E, 0x73, 0x74, 0x0D, 0x9D, 0x39, 0x25, 0xA9, 0x6C, 0x59, 0x0E, 0x04, 0xE0, 0xDE, 0xA0, 0xC6, 0x59, 0xDB, 0x6D, 0xAC, 0x27, 0x42, 0x00, 0x8A, 0x69, 0xDA, 0x99, 0x4B, 0x79, 0x92, 0xF1, 0xEA, 0x1A, 0x1D, 0x34, 0xFA, 0xA7, 0x5F, 0x35, 0x40, 0xFF, 0x51, 0x1F, 0x4B, 0xE2, 0x7B, 0xDB, 0x43, 0x06, 0x13, 0x85, 0x7D, 0x99, 0x8C, 0xBE, 0xC3, 0x75, 0xF6, 0x08, 0xAE, 0xC3, 0xAB, 0x71, 0xC5, 0x76, 0xDF, 0x27, 0xDD, 0xB2, 0xE7, 0x9A, 0x05, 0x43, 0x00, 0x31, 0x70, 0x02, 0x20, 0x9A, 0xEA, 0x0B, 0xD5, 0x3F, 0x6B, 0x20, 0xA2, 0xE7, 0x0C, 0xA3, 0x07, 0x38, 0xF4, 0xF2, 0xD3, 0xF8, 0x2B, 0xCE, 0xDE, 0x33, 0x17, 0x40, 0xB2, 0xA1, 0x00, 0x57, 0xC3, 0x1A, 0xDE, 0x48, 0x40, 0x0C, 0x30, 0x02, 0xC2, 0x80, 0x5C, 0xFA, 0xE8, 0x54, 0x20, 0xAC, 0x41, 0x40, 0x9E, 0x57, 0x35, 0xED, 0xA0, 0x41, 0x2D, 0x94, 0xC7, 0xBE, 0x34, 0x11, 0x8B, 0x8D, 0xD7, 0x67, 0x25, 0x61, 0x0F, 0x74, 0x81, 0x11, 0xA3, 0x1A, 0x4E, 0x43, 0x26, 0xBF, 0xBA, 0x7D, 0x4E, 0xB3, 0x7C, 0xBE, 0x90, 0x7C, 0x7D, 0x52, 0x5A, 0xB3, 0x48, 0x63, 0xAD, 0xCD, 0x1B, 0x6D, 0x9F, 0x9D, 0x61, 0xE2, 0xC0, 0x15, 0x22, 0xA8, 0xCD, 0xD7, 0x0A, 0xC9, 0x32, 0xF5, 0x95, 0x46, 0x2E, 0x58, 0x63, 0xE5, 0xA3, 0x82, 0x80, 0xBC, 0x9B, 0x5A, 0x83, 0xB4, 0x21, 0xC0, 0x89, 0x55, 0xEA, 0xA1, 0x39, 0x67, 0x8D, 0xDF, 0xF3, 0x29, 0xFF, 0xA2, 0x9D, 0xBB, 0xF5, 0xA0, 0x67, 0x60, 0x18, 0x05, 0x73, 0x42, 0x23, 0x47, 0x8A, 0x7A, 0x7B, 0x25, 0x7E, 0x4B, 0xE6, 0xE9, 0x36, 0xC1, 0xCD, 0xAC, 0x75, 0x25, 0x72, 0x5D, 0x4F, 0x4A, 0xC3, 0x0E, 0x20, 0xDE, 0x60, 0xE0, 0x75, 0xCD, 0xCA, 0x4D, 0xBC, 0xCD, 0x6E, 0x13, 0x31, 0x7C, 0x8A, 0x00, 0xAE, 0xF5, 0x24, 0xE5, 0x3C, 0xE0, 0xD6, 0x99, 0x2D, 0xCA, 0xA7, 0x41, 0xD1, 0x48, 0x80, 0xA5, 0x61, 0x8D, 0x5A, 0x1A, 0xBF, 0x02, 0xD2, 0x1A, 0x0C, 0x84, 0x00, 0x96, 0x0D, 0x02, 0xBC, 0xF1, 0xDE, 0x9F, 0xA6, 0xF0, 0xA4, 0x96, 0xFC, 0xEE, 0xA1, 0x16, 0x3E, 0x1C, 0x70, 0x7B, 0x7C, 0xB1, 0x9A, 0xB5, 0x6C, 0x48, 0x0C, 0x0B, 0xC6, 0x6A, 0xCC, 0x79, 0x33, 0xDB, 0x46, 0xDE, 0x0E, 0x04, 0xFD, 0x98, 0xED, 0xE3, 0x02, 0xD8, 0xC5, 0x3A, 0xE6, 0x9A, 0xCC, 0x21, 0xFE, 0x6A, 0x40, 0x29, 0x20, 0x6F, 0xCA, 0xCD, 0x4C, 0x8E, 0x70, 0xCD, 0xE5, 0xA4, 0xBC, 0x8E, 0xB2, 0xBB, 0xB2, 0xCA, 0x0B, 0x06, 0x88, 0x03, 0x16, 0xCB, 0x36, 0xAD, 0x1A, 0x07, 0xD0, 0x6C, 0xD0, 0xFC, 0x14, 0x79, 0x83, 0x66, 0x18, 0x1E, 0x12, 0x68, 0x30, 0x23, 0x53, 0x2C, 0x3C, 0xAB, 0x6F, 0xA9, 0x79, 0x31, 0x2C, 0x03, 0x95, 0x7A, 0xC8, 0x92, 0x61, 0xC3, 0x62, 0xEA, 0x0A, 0xDE, 0x7E, 0x15, 0x8C, 0xED, 0x57, 0xDF, 0x2F, 0x48, 0xB6, 0x77, 0xB5, 0x9B, 0x1D, 0x03, 0x12, 0xE8, 0x4F, 0xF6, 0x84, 0xC4, 0xA6, 0xD3, 0xB8, 0x2C, 0x0E, 0x70, 0x6E, 0x7B, 0x2F, 0xCD, 0x79, 0xD0, 0x80, 0x0D, 0x9B, 0xBF, 0xE9, 0x71, 0x68, 0xBF, 0xB0, 0x86, 0x40, 0xC6, 0x1A, 0x7A, 0xCB, 0x02, 0x50, 0xCE, 0x3F, 0xBA, 0xF6, 0x70, 0xA6, 0xEA, 0xEF, 0xB4, 0x1B, 0x34, 0xFF, 0xEA, 0x9E, 0xDE, 0x19, 0x8F, 0x93, 0x34, 0x2C, 0x74, 0xB8, 0x14, 0x35, 0x82, 0xAC, 0x1E, 0xFE, 0x6F, 0x48, 0xC5, 0xC8, 0x5A, 0x69, 0xD4, 0xAC, 0x3C, 0xD3, 0x12, 0xC7, 0x13, 0xC8, 0x68, 0x30, 0xE0, 0xF1, 0xE3, 0x4D, 0x76, 0x83, 0x77, 0x5E, 0x87, 0xEB, 0xAD, 0xFA, 0x02, 0xE5, 0xF3, 0x3D, 0x7A, 0xCF, 0x2E, 0xAF, 0xE9, 0x9B, 0x67, 0xEC, 0x7D, 0x9D, 0xA7, 0x4D, 0x01, 0xF5, 0x86, 0xAD, 0x4F, 0xCB, 0x8F, 0xE0, 0x75, 0x74, 0x37, 0x4E, 0xFD, 0x50, 0xA7, 0xC7, 0xD2, 0xA6, 0xD2, 0x5B, 0x6A, 0x81, 0x7E, 0x45, 0x69, 0x89, 0xBB, 0xE5, 0x3F, 0x4F, 0x38, 0x05, 0xFB, 0xA7, 0x96, 0x2B, 0xC8, 0xF1, 0x82, 0x71, 0x2A, 0x0A, 0xC5, 0x7E, 0x59, 0x6B, 0x9E, 0xBD, 0xEE, 0xB4, 0x9A, 0xC4, 0x0D, 0xC2, 0xFA, 0x89, 0xB1, 0x35, 0xC0, 0x13, 0x88, 0x8C, 0x3D, 0x45, 0x8C, 0xD3, 0xB3, 0x2B, 0x7D, 0xB5, 0xCE, 0x67, 0x61, 0x90, 0xAF, 0x2F, 0xBD, 0x62, 0x56, 0xF1, 0xC5, 0xE7, 0x8E, 0x97, 0x0E, 0x84, 0x00, 0xBE, 0xA1, 0x8D, 0x04, 0x72, 0x99, 0x65, 0xEE, 0xA9, 0x66, 0x27, 0xD6, 0x9C, 0x1B, 0x9B, 0x2D, 0x05, 0x72, 0x6E, 0xD4, 0x12, 0x52, 0x84, 0x92, 0x7D, 0x01, 0x45, 0xF0, 0x2C, 0xF0, 0xB2, 0xC9, 0xB6, 0x59, 0x66, 0x81, 0xB1, 0x92, 0x38, 0x2E, 0x9E, 0x3B, 0xD7, 0xB1, 0xE7, 0xD7, 0x5A, 0xC3, 0xB3, 0xC1, 0x80, 0xDA, 0x7A, 0x15, 0x08, 0x60, 0x63, 0x3F, 0xC2, 0xED, 0x72, 0x36, 0xBC, 0x66, 0x87, 0xA9, 0xA6, 0xD3, 0xF0, 0xB1, 0x55, 0xAD, 0x59, 0xD7, 0xD1, 0x14, 0xC0, 0xF7, 0x3D, 0xC0, 0x17, 0x0A, 0xF0, 0x46, 0x3A, 0x50, 0xD1, 0xD8, 0x77, 0x78, 0x06, 0x22, 0x81, 0x31, 0xEC, 0x0B, 0x41, 0xAB, 0x4F, 0xF5, 0x52, 0xA5, 0xA8, 0x1F, 0x48, 0xFC, 0xAB, 0x42, 0xA2, 0xDB, 0xBF, 0x1B, 0x1C, 0xE1, 0xED, 0x62, 0x89, 0x87, 0xDD, 0xBB, 0xB1, 0x84, 0x7D, 0xEC, 0x6A, 0x6A, 0xCD, 0xAA, 0x65, 0x1A, 0x6F, 0xB6, 0x1F, 0xC9, 0x5F, 0x51, 0x1B, 0xE6, 0x42, 0xF2, 0x32, 0x18, 0xE6, 0x53, 0xBF, 0xEF, 0x0D, 0xFE, 0x10, 0x4F, 0x9B, 0xED, 0x6F, 0x6D, 0x02, 0x9C, 0x00, 0x9D, 0x86, 0xAC, 0x53, 0x61, 0x4D, 0x90, 0x34, 0x1C, 0xE0, 0x02, 0x8C, 0x01, 0xF7, 0x1F, 0x06, 0x30, 0x1A, 0x8D, 0xD3, 0x48, 0xE0, 0xBD, 0x0B, 0xFC, 0xEE, 0x60, 0x31, 0x93, 0x90, 0x06, 0x93, 0xAB, 0xCC, 0xF6, 0x58, 0xE8, 0xD3, 0x2F, 0x25, 0x6E, 0x56, 0x95, 0x31, 0x2A, 0x2C, 0xC1, 0x5B, 0x0A, 0x33, 0x46, 0x89, 0xC7, 0x4B, 0x96, 0xE5, 0x5A, 0x32, 0x65, 0xB3, 0xE9, 0x9C, 0xCF, 0x5F, 0x59, 0x81, 0xE8, 0x5D, 0x39, 0xE3, 0xF6, 0x21, 0x7A, 0x7F, 0x1A, 0x56, 0x06, 0x48, 0xE0, 0x41, 0x2D, 0x3A, 0xCF, 0x9F, 0xAC, 0xF3, 0x27, 0x44, 0x02, 0x6E, 0x0D, 0x6A, 0x68, 0x23, 0x80, 0x94, 0x7B, 0x85, 0x03, 0x58, 0x1A, 0x0C, 0x90, 0xAD, 0x41, 0x91, 0x36, 0xBF, 0x53, 0xEA, 0x06, 0x8D, 0xE0, 0xAB, 0x89, 0x9C, 0x76, 0x78, 0x40, 0xA7, 0x70, 0x42, 0xBF, 0x0A, 0x68, 0x64, 0x41, 0x8E, 0x2A, 0x81, 0x7B, 0x60, 0x24, 0xAC, 0x24, 0x88, 0xA6, 0xFC, 0x56, 0x57, 0xD0, 0xF0, 0xD5, 0x04, 0xDA, 0xBE, 0x66, 0x69, 0x5D, 0x1B, 0x87, 0xA6, 0x8F, 0x23, 0x75, 0x98, 0x68, 0xCC, 0xA4, 0x89, 0xD6, 0x63, 0xE0, 0x60, 0x8F, 0x4F, 0xD9, 0x15, 0x5B, 0x6B, 0xC9, 0x59, 0x4E, 0x7D, 0xF1, 0xE1, 0x29, 0xF9, 0x31, 0x02, 0x24, 0x96, 0xA8, 0xF6, 0x34, 0xA8, 0x91, 0x80, 0x05, 0x90, 0x0C, 0x54, 0x35, 0xB2, 0xC1, 0x40, 0x12, 0x10, 0x39, 0x25, 0xCF, 0x4C, 0x1D, 0x34, 0x46, 0x56, 0xE3, 0x4F, 0xA7, 0xE0, 0x81, 0x04, 0x91, 0x7D, 0xD7, 0xC2, 0xFC, 0xB6, 0x60, 0x4E, 0x46, 0x04, 0xA0, 0x59, 0xAE, 0x88, 0x6E, 0x25, 0xF8, 0xA9, 0x8E, 0xBF, 0xAF, 0x19, 0x91, 0xE9, 0xB7, 0x1D, 0x0E, 0x24, 0x37, 0x1C, 0xA8, 0x9C, 0xE3, 0x9E, 0xC3, 0xCF, 0xDF, 0x64, 0x24, 0x5B, 0x9A, 0x3A, 0x7B, 0x8D, 0xAF, 0xD4, 0x81, 0xD1, 0x5B, 0xF0, 0xA8, 0x56, 0xF4, 0xCD, 0x63, 0x0A, 0x9D, 0x65, 0xE4, 0x4A, 0x80, 0xC7, 0x44, 0xE8, 0x34, 0xD6, 0x61, 0x02, 0xA4, 0x1A, 0x09, 0x70, 0x83, 0x1C, 0x38, 0x05, 0xF0, 0x01, 0xEC, 0x3D, 0x9E, 0xF2, 0x1D, 0x65, 0xC9, 0x31, 0x90, 0x20, 0x52, 0x46, 0x47, 0x9E, 0x3A, 0xE1, 0x84, 0xE7, 0x89, 0xAD, 0x54, 0x18, 0x9D, 0x3A, 0x8C, 0x02, 0x0B, 0xCD, 0xF7, 0x27, 0x0D, 0x13, 0xC2, 0xA1, 0x9F, 0xB5, 0x0B, 0x02, 0xB8, 0x76, 0x45, 0xA5, 0x31, 0x7A, 0xF0, 0x64, 0x65, 0x68, 0x74, 0x09, 0x2D, 0xC7, 0x51, 0x16, 0x20, 0x03, 0x8E, 0x02, 0x4C, 0x80, 0x2F, 0xF1, 0xEF, 0x59, 0x17, 0x24, 0x0A, 0x80, 0x09, 0x10, 0x01, 0xEC, 0xAC, 0x33, 0xCB, 0x01, 0xCC, 0x01, 0xCD, 0x86, 0xCE, 0xEF, 0x0C, 0xBE, 0x41, 0xD3, 0x7F, 0xCA, 0xB0, 0xCB, 0xE1, 0x84, 0x79, 0x8E, 0x7F, 0x96, 0x09, 0x74, 0x1D, 0x5C, 0x71, 0x1B, 0x54, 0xC3, 0xE8, 0x00, 0x0A, 0xBC, 0x5C, 0xB4, 0xFA, 0x5C, 0xBB, 0x3B, 0x7E, 0x78, 0x8A, 0x87, 0x99, 0x7F, 0x8C, 0x75, 0x8D, 0x00, 0xAC, 0xA1, 0x34, 0xF1, 0xEC, 0x02, 0x72, 0xDA, 0xDE, 0xC8, 0x99, 0xD3, 0x64, 0x63, 0x4D, 0x63, 0x2C, 0x01, 0xC2, 0x80, 0xAB, 0xB8, 0xA7, 0x00, 0x94, 0x01, 0x0B, 0xC0, 0x1B, 0xA1, 0x6B, 0xEC, 0x03, 0x4F, 0xE5, 0x2A, 0x5F, 0x10, 0x40, 0xD5, 0xD0, 0x85, 0x04, 0x94, 0x6E, 0xD0, 0xEC, 0x9F, 0xE1, 0x05, 0x82, 0xE2, 0xFA, 0xA1, 0xCF, 0x88, 0xCE, 0x08, 0xD3, 0x31, 0xA2, 0xAA, 0x13, 0x43, 0x84, 0xCE, 0x2B, 0x67, 0x5C, 0x1B, 0x23, 0x5A, 0x49, 0xBA, 0xCF, 0x1C, 0xB5, 0x9A, 0x49, 0x64, 0xB6, 0x42, 0xED, 0x79, 0x21, 0x5B, 0xDA, 0xAD, 0x09, 0x54, 0x47, 0x92, 0xD6, 0x80, 0x5C, 0x3F, 0x00, 0xCB, 0xD4, 0x2E, 0x58, 0x01, 0xEC, 0x00, 0x19, 0xA0, 0x39, 0x5D, 0x1D, 0xE3, 0x9E, 0xDE, 0x02, 0x60, 0x03, 0x44, 0x01, 0xA5, 0x19, 0xD0, 0x24, 0xA0, 0xAC, 0xA1, 0x40, 0x26, 0x10, 0xD1, 0xA0, 0x46, 0xBD, 0x28, 0x77, 0xD0, 0xFC, 0x6B, 0x98, 0x4D, 0x0B, 0x14, 0x9B, 0xB9, 0x3D, 0x49, 0x33, 0x3F, 0x37, 0x18, 0xA5, 0xC2, 0x8F, 0x73, 0xEB, 0x58, 0xF7, 0xC3, 0x9A, 0x6B, 0x4F, 0x3B, 0xFB, 0x52, 0x70, 0x53, 0xB5, 0xCE, 0xB3, 0xE5, 0x87, 0x68, 0xB5, 0xA6, 0xC8, 0x8F, 0xBC, 0xA8, 0xD3, 0xCB, 0x4F, 0xE2, 0x05, 0xB6, 0xED, 0xF4, 0x19, 0x38, 0xE3, 0x6E, 0xEA, 0x6F, 0xF8, 0xA0, 0x69, 0x63, 0xED, 0x9E, 0xC5, 0x8D, 0xE7, 0x52, 0xDF, 0xC8, 0xB9, 0x72, 0xB8, 0x00, 0x6D, 0x38, 0x01, 0x56, 0x0D, 0x03, 0x34, 0x1B, 0xD2, 0x28, 0x20, 0xDE, 0xEB, 0x33, 0x30, 0x11, 0x35, 0x30, 0xA6, 0x80, 0xC9, 0xE1, 0x0A, 0x53, 0x18, 0xEF, 0xA3, 0x47, 0x91, 0xCF, 0x2C, 0xC2, 0x0F, 0xB7, 0x4E, 0x0E, 0x98, 0x8F, 0x68, 0xB9, 0x6C, 0x03, 0xF4, 0x8E, 0x41, 0xD6, 0x4C, 0x96, 0x66, 0x02, 0x41, 0x80, 0x31, 0x20, 0xD6, 0x08, 0xE0, 0x1E, 0x44, 0x44, 0xE6, 0xB8, 0x81, 0xD3, 0x21, 0x7C, 0x86, 0x3C, 0x04, 0xD0, 0x7D, 0x4C, 0x6D, 0x0D, 0x05, 0x39, 0x80, 0x04, 0xE0, 0xBC, 0xDA, 0xED, 0x2E, 0x02, 0x28, 0x99, 0x21, 0x14, 0x03, 0x8C, 0x56, 0x98, 0x08, 0xE0, 0x6C, 0x1C, 0x40, 0x08, 0xF0, 0xB7, 0xD4, 0x12, 0xD3, 0x64, 0xD3, 0xFE, 0xE9, 0xA7, 0xF1, 0xF9, 0xCB, 0xAA, 0xF1, 0xBD, 0x13, 0x04, 0x5B, 0xB5, 0x5D, 0x93, 0x23, 0x3F, 0x44, 0xCB, 0x3A, 0xA1, 0x56, 0xFE, 0x96, 0xE8, 0x47, 0xEF, 0x67, 0xAE, 0x0B, 0xA7, 0x2E, 0xCF, 0x43, 0x65, 0xA0, 0x3A, 0xD8, 0x4C, 0xF3, 0x2A, 0x1E, 0x07, 0x60, 0x9F, 0x7B, 0xE2, 0x1B, 0x00, 0xB4, 0xA7, 0x2A, 0x3A, 0x90, 0x31, 0x4D, 0xD5, 0x48, 0x1B, 0x05, 0x30, 0x37, 0x1C, 0xD0, 0xF5, 0x0A, 0x08, 0x6F, 0xE8, 0x92, 0x96, 0x18, 0xA0, 0xEB, 0x53, 0xBE, 0x37, 0x41, 0x61, 0x16, 0x92, 0xF9, 0x27, 0xBF, 0x4D, 0x92, 0x6F, 0xEA, 0x1B, 0x55, 0x40, 0x74, 0xD5, 0xB3, 0x19, 0x93, 0x19, 0x73, 0x66, 0x22, 0xBB, 0x16, 0x30, 0x2F, 0xED, 0x9A, 0x5B, 0xAA, 0x76, 0x0F, 0x6C, 0xA4, 0x80, 0x64, 0x83, 0xE7, 0x17, 0x0F, 0x75, 0x9C, 0xA4, 0x3F, 0x31, 0x10, 0x63, 0x0C, 0x4D, 0xBC, 0x47, 0x51, 0x72, 0xEE, 0x32, 0xA2, 0x1D, 0x4A, 0x9F, 0xB9, 0xB5, 0x3A, 0x33, 0x1B, 0xEC, 0x39, 0xED, 0xD4, 0x84, 0x01, 0x35, 0xC0, 0xA4, 0x51, 0x40, 0xAC, 0x67, 0x97, 0xA5, 0x71, 0x00, 0xA2, 0xA9, 0xD9, 0xA9, 0xD3, 0xF0, 0xB7, 0x36, 0x11, 0xB5, 0x40, 0x0E, 0x12, 0x15, 0xA7, 0x4F, 0xC5, 0x54, 0x18, 0x92, 0xE7, 0xFE, 0x5D, 0x0D, 0x4E, 0x24, 0x4E, 0xDA, 0x9A, 0x68, 0x46, 0x0A, 0xC3, 0x3F, 0x60, 0xC9, 0x4D, 0xA6, 0xED, 0xE3, 0xED, 0xEC, 0x68, 0x97, 0x58, 0x0A, 0xA9, 0x33, 0xDF, 0xA6, 0x61, 0xEB, 0x5F, 0xF9, 0x2E, 0xAE, 0x31, 0x5C, 0x26, 0xDF, 0xA4, 0x11, 0xA5, 0xE5, 0x51, 0xA4, 0x73, 0x6F, 0x33, 0x06, 0x84, 0x97, 0xBF, 0xA1, 0x4F, 0x63, 0x43, 0x13, 0x20, 0x1C, 0xC8, 0x04, 0xAA, 0x56, 0x6B, 0x81, 0x32, 0x60, 0xD5, 0xC8, 0x86, 0x02, 0x2A, 0x8D, 0x03, 0x58, 0x23, 0x6F, 0xD0, 0xE8, 0xDB, 0xCD, 0x34, 0xF2, 0x1D, 0x6F, 0xF5, 0xBB, 0x2F, 0x22, 0xD3, 0x66, 0x4A, 0x18, 0x56, 0x28, 0x0C, 0x79, 0x9E, 0x4A, 0xF7, 0xDB, 0x1A, 0x82, 0xB5, 0x0F, 0x1D, 0x6F, 0x96, 0x37, 0x4D, 0x2D, 0x0A, 0x09, 0xA0, 0xD1, 0xA0, 0xFF, 0x61, 0x22, 0x17, 0x57, 0x6F, 0xC2, 0x53, 0xAE, 0x1E, 0x0C, 0xE8, 0x32, 0xCB, 0x27, 0x41, 0x40, 0xA5, 0xC3, 0x5B, 0x40, 0x38, 0xE0, 0x0A, 0x58, 0x34, 0x4E, 0x83, 0x1A, 0xDC, 0x08, 0xC0, 0x6B, 0x1E, 0x84, 0xCB, 0x1A, 0xDE, 0xD0, 0x06, 0x03, 0x99, 0xC0, 0x48, 0x55, 0x21, 0x68, 0xFC, 0x5D, 0xCF, 0x35, 0x0D, 0x06, 0x4D, 0x07, 0xD6, 0xDE, 0x26, 0x70, 0x40, 0x37, 0x6F, 0x9F, 0x26, 0x0A, 0x64, 0xF4, 0xD8, 0x51, 0xF4, 0xEF, 0x43, 0x47, 0xFD, 0x14, 0x75, 0xA8, 0xCC, 0xB4, 0x80, 0x64, 0xC3, 0x00, 0x5A, 0x4D, 0xC7, 0xC1, 0x8D, 0xD7, 0x14, 0x30, 0xFB, 0xF7, 0xE3, 0x34, 0x12, 0x20, 0x9F, 0xE9, 0x1D, 0xD2, 0xB9, 0x50, 0x95, 0x80, 0xFB, 0x74, 0x1B, 0xCD, 0x6E, 0x6C, 0x29, 0xC0, 0x6C, 0x75, 0xCC, 0x2E, 0x6B, 0x00, 0x0E, 0x40, 0xAB, 0xE1, 0x80, 0x28, 0x40, 0x01, 0x1C, 0x07, 0xA8, 0x56, 0xC7, 0x6C, 0xC8, 0x3F, 0x61, 0xCC, 0x2F, 0xE6, 0xEF, 0x6C, 0x26, 0xB0, 0x9F, 0x50, 0x47, 0xC7, 0xAC, 0x25, 0x6C, 0xC5, 0xAA, 0xB0, 0x0A, 0xD2, 0xB1, 0x29, 0x90, 0xBE, 0xFE, 0xC5, 0x8F, 0xB4, 0x1A, 0xA5, 0xE4, 0xCC, 0x81, 0xD9, 0x74, 0x00, 0x21, 0x80, 0x6C, 0xDA, 0xB3, 0xC6, 0x99, 0x0F, 0x16, 0xE5, 0x53, 0x95, 0xCD, 0xFE, 0x1A, 0x96, 0xFE, 0x54, 0x80, 0xFA, 0x50, 0x44, 0x69, 0x83, 0x1B, 0xAA, 0x40, 0x3D, 0x07, 0x57, 0x05, 0x2C, 0x80, 0x10, 0x20, 0x09, 0xA8, 0x35, 0xD9, 0x96, 0x13, 0xD0, 0xD3, 0x20, 0x40, 0xAA, 0xA1, 0x0D, 0x9E, 0xFF, 0x2D, 0xA8, 0x83, 0xA6, 0x78, 0x05, 0x94, 0x43, 0x8A, 0x24, 0x81, 0xC9, 0x04, 0xED, 0x71, 0x65, 0x78, 0x2E, 0x4F, 0xF4, 0x0C, 0x03, 0x09, 0xC5, 0x81, 0x3B, 0x73, 0x2A, 0x49, 0x69, 0xBE, 0x09, 0xE4, 0x09, 0x30, 0x28, 0x66, 0xEF, 0x58, 0x0A, 0x10, 0x06, 0x38, 0xCF, 0x17, 0xBD, 0x8F, 0x41, 0xA7, 0x6F, 0x93, 0xE1, 0xA7, 0x2C, 0x3E, 0xDA, 0x9F, 0xFA, 0xB7, 0x78, 0xEA, 0x3B, 0x1E, 0x3D, 0x09, 0xAC, 0x00, 0x19, 0x20, 0x36, 0x23, 0x6A, 0xD2, 0x28, 0xC0, 0xA9, 0x11, 0x6B, 0xFA, 0x12, 0x31, 0xC0, 0xDE, 0x60, 0x80, 0x02, 0x38, 0x7A, 0x9B, 0xE2, 0xE6, 0xA0, 0x13, 0xC9, 0x8E, 0x9A, 0xA1, 0x3B, 0xC3, 0xFF, 0x36, 0xB5, 0x6F, 0x8D, 0xF8, 0x77, 0xBE, 0xB5, 0xF7, 0x67, 0x05, 0x62, 0x7E, 0x04, 0xAF, 0x21, 0xC6, 0xA6, 0xC6, 0x3F, 0xA7, 0xE3, 0xDD, 0x6C, 0x21, 0x2F, 0x43, 0xCF, 0x72, 0x20, 0x13, 0x88, 0x0B, 0x06, 0x9E, 0x8A, 0xED, 0xFD, 0x12, 0xBD, 0xC6, 0xAE, 0xE2, 0xCC, 0x1D, 0xB0, 0x00, 0xD8, 0x66, 0x77, 0x87, 0x30, 0x70, 0xBC, 0x17, 0x90, 0x00, 0x99, 0x0D, 0x6D, 0x70, 0x23, 0x80, 0x3A, 0x8D, 0x9A, 0xD3, 0x93, 0xB9, 0x00, 0xB9, 0x48, 0x40, 0xB9, 0x41, 0x0D, 0x01, 0x8C, 0x81, 0xF0, 0x0E, 0x9A, 0xDF, 0x68, 0x3D, 0xD0, 0xB5, 0x39, 0xFC, 0xFA, 0x9D, 0xBC, 0x9B, 0x7D, 0xAE, 0x5F, 0x53, 0xB6, 0x4F, 0xA0, 0x8F, 0x37, 0xC1, 0x6E, 0xCE, 0x7E, 0x42, 0xC2, 0x23, 0x67, 0xFE, 0xF8, 0x70, 0xC0, 0x0F, 0x20, 0x06, 0x50, 0xE3, 0x38, 0xC0, 0xB1, 0x06, 0xF3, 0x32, 0x90, 0x39, 0x27, 0xB2, 0x1C, 0x69, 0x04, 0x40, 0x0C, 0xB0, 0xFC, 0xF0, 0x3C, 0x53, 0x05, 0x8C, 0x01, 0xBF, 0x28, 0x20, 0x6A, 0x0D, 0x6B, 0x10, 0x80, 0xA8, 0xE1, 0x4B, 0x10, 0x7F, 0x00, 0x6D, 0x58, 0xC3, 0xA5, 0x83, 0x16, 0x28, 0x56, 0xB0, 0xF4, 0xDF, 0x96, 0xFE, 0xC9, 0x97, 0x19, 0x51, 0xB8, 0xF9, 0xA9, 0x77, 0xA7, 0x64, 0x7D, 0x48, 0xBA, 0x27, 0x00, 0x99, 0x3D, 0x3F, 0x34, 0x84, 0x30, 0xC8, 0x21, 0xCF, 0xEE, 0xCF, 0xBA, 0x11, 0x69, 0x9C, 0xD7, 0x11, 0xB8, 0xB4, 0xAE, 0x63, 0x23, 0xB9, 0xF1, 0xC1, 0xB9, 0x64, 0xDA, 0x9B, 0x59, 0x83, 0x01, 0xCD, 0x86, 0x00, 0x16, 0xDD, 0x3C, 0xC1, 0x40, 0xDC, 0x76, 0x6C, 0x01, 0x6E, 0xBF, 0x14, 0x19, 0x20, 0x04, 0x68, 0x00, 0xEE, 0x40, 0x2A, 0x50, 0xD6, 0x6B, 0x85, 0x1B, 0x01, 0x10, 0x03, 0xDC, 0x10, 0xE0, 0x69, 0x22, 0xDF, 0x61, 0xA3, 0x93, 0x2D, 0xCA, 0xD8, 0xE2, 0x32, 0xBE, 0x95, 0x76, 0xDB, 0xF5, 0xCA, 0xA2, 0x3D, 0x08, 0x14, 0x77, 0xD8, 0x9D, 0xE8, 0xE8, 0xA0, 0x2D, 0x1F, 0x7F, 0x7F, 0xAF, 0x74, 0x72, 0x40, 0x04, 0xA0, 0x04, 0xCE, 0x59, 0x19, 0xDD, 0xE1, 0x29, 0x89, 0x0C, 0xD9, 0x94, 0x27, 0xB0, 0x00, 0xCA, 0x8D, 0x02, 0x4C, 0x1A, 0x09, 0x04, 0x2F, 0x3B, 0xBE, 0x3D, 0x39, 0xC4, 0x01, 0x0D, 0xC0, 0x14, 0xF0, 0x46, 0x38, 0x90, 0x01, 0x94, 0x36, 0x72, 0x8E, 0x13, 0x21, 0x5D, 0xEB, 0x8E, 0x01, 0xBD, 0x8F, 0x67, 0x61, 0xC2, 0xDB, 0x17, 0x1F, 0xEB, 0xFB, 0x14, 0x41, 0xB3, 0x6C, 0xDF, 0xF2, 0x09, 0xFC, 0x59, 0x47, 0xBA, 0x67, 0x59, 0xA1, 0xF2, 0x4D, 0x9B, 0x0E, 0xCB, 0xB5, 0xEC, 0xD4, 0x8E, 0xFC, 0xED, 0xCF, 0x44, 0x2F, 0xFF, 0xC9, 0x0A, 0x10, 0xDD, 0x47, 0x10, 0x70, 0xF9, 0x03, 0xF7, 0x2F, 0xA8, 0xAF, 0x05, 0xBA, 0x6E, 0x83, 0xCD, 0xE8, 0xFB, 0x45, 0x6D, 0x73, 0x1A, 0x8B, 0xDD, 0xDF, 0xDA, 0xE6, 0xAF, 0xAB, 0x05, 0x64, 0x4D, 0x6B, 0x2F, 0x61, 0x40, 0x69, 0xAE, 0xD7, 0x20, 0xA0, 0x7A, 0xA1, 0x12, 0x37, 0xB4, 0x41, 0xAB, 0xCF, 0x98, 0xE6, 0xB7, 0x28, 0x23, 0x68, 0x79, 0xF6, 0x9E, 0x86, 0x65, 0x2E, 0x28, 0xEE, 0x11, 0x39, 0x44, 0xBB, 0x45, 0x28, 0xBC, 0xB0, 0xF4, 0x5F, 0xC5, 0xC6, 0xE3, 0xB9, 0xCE, 0x1C, 0xF7, 0xA6, 0xF8, 0xBA, 0xB6, 0x60, 0xB6, 0x87, 0xA5, 0x2D, 0x00, 0x9D, 0xE9, 0x57, 0x20, 0x01, 0xF0, 0xF0, 0x32, 0xC0, 0x8B, 0x0F, 0xC2, 0xE0, 0xDB, 0x42, 0x78, 0x1A, 0x09, 0xB0, 0x2C, 0x28, 0x20, 0x17, 0x05, 0xA8, 0x03, 0x46, 0x8D, 0x00, 0xDC, 0x80, 0x38, 0x40, 0x36, 0x4A, 0xD0, 0x53, 0x70, 0x2E, 0x12, 0x20, 0x6E, 0x14, 0xC0, 0x09, 0x88, 0x03, 0xCA, 0x80, 0x59, 0x07, 0x0D, 0x57, 0x82, 0x3A, 0xF2, 0x89, 0x88, 0x4E, 0xBC, 0xE4, 0x2D, 0x7C, 0xD0, 0xCB, 0xA0, 0xF7, 0xAA, 0x42, 0x0D, 0x51, 0x14, 0x8E, 0x67, 0xCC, 0xF7, 0xD6, 0xB9, 0xBB, 0xCB, 0x80, 0xF2, 0x55, 0xC6, 0x5B, 0x9F, 0xA4, 0xC1, 0x7B, 0xEA, 0x77, 0x02, 0x5E, 0xB7, 0x82, 0x36, 0x4D, 0x6D, 0xBC, 0xA1, 0x06, 0xF0, 0xCF, 0x5E, 0x16, 0x9E, 0xA7, 0x62, 0xB1, 0x99, 0x5D, 0x34, 0x03, 0x72, 0xD7, 0x48, 0x1A, 0x4C, 0x80, 0xEE, 0x5B, 0x83, 0xEE, 0xA9, 0x95, 0x8D, 0x02, 0xCC, 0x81, 0xBC, 0x79, 0x8E, 0x64, 0xFC, 0x4B, 0x67, 0x7D, 0x9B, 0x19, 0x09, 0x36, 0x33, 0x93, 0x1E, 0x38, 0x4B, 0xBD, 0x25, 0x45, 0xE7, 0x45, 0x88, 0xA0, 0xBE, 0xA1, 0x98, 0x2D, 0x79, 0xB9, 0xCA, 0x04, 0xA6, 0xD3, 0x5F, 0x35, 0xBD, 0x71, 0x00, 0x53, 0x40, 0x0E, 0x70, 0xB2, 0xC1, 0x80, 0xEA, 0x8D, 0xCF, 0xCC, 0x93, 0xA5, 0xED, 0x91, 0xAF, 0x0D, 0x6F, 0x30, 0x10, 0x43, 0xC6, 0x8C, 0x3B, 0xCF, 0x3C, 0x7D, 0x95, 0xCD, 0x57, 0xB8, 0x6F, 0x3F, 0xCE, 0x9C, 0xD6, 0x26, 0x42, 0x0D, 0x6D, 0x64, 0xA3, 0x00, 0x25, 0xC0, 0x1A, 0x71, 0x1F, 0x4F, 0xF9, 0x76, 0xB1, 0x0F, 0xD6, 0x8F, 0xAC, 0x17, 0x44, 0x31, 0xFE, 0x6D, 0x42, 0x85, 0xA2, 0xA7, 0x1A, 0x0A, 0x83, 0x21, 0x10, 0x90, 0xD4, 0x19, 0xC9, 0x21, 0xAD, 0x65, 0x0C, 0x26, 0x31, 0x3D, 0xB9, 0x4C, 0x00, 0x6D, 0x30, 0xAD, 0x6E, 0xF5, 0x02, 0x2C, 0xA7, 0x17, 0x77, 0xEC, 0xB1, 0x93, 0x05, 0xF0, 0x9E, 0x41, 0x18, 0x80, 0x17, 0x10, 0x7C, 0x2B, 0xA0, 0x73, 0xA5, 0xB1, 0xCF, 0x71, 0xB0, 0x44, 0x00, 0x3B, 0x20, 0xB9, 0x17, 0x0E, 0x50, 0xB6, 0xC0, 0x40, 0x5A, 0x43, 0xA7, 0x9B, 0x35, 0xBF, 0x95, 0x86, 0x32, 0xC1, 0xE9, 0x09, 0xD0, 0x65, 0x39, 0xA7, 0x8C, 0x47, 0x76, 0x56, 0xC8, 0x31, 0x7F, 0xC3, 0xB5, 0xE5, 0xD2, 0xFC, 0x4B, 0xDC, 0x17, 0xAB, 0xA3, 0x80, 0x81, 0x3C, 0xF3, 0x93, 0xD1, 0x92, 0x4F, 0x2F, 0xD1, 0x9A, 0xE7, 0x74, 0xA7, 0x4A, 0x01, 0x2A, 0x00, 0x67, 0x40, 0x0A, 0xE0, 0x00, 0x48, 0x00, 0x1E, 0x3A, 0x28, 0x7F, 0x77, 0x49, 0x95, 0x8E, 0xD6, 0x7A, 0xDA, 0xE2, 0x00, 0xB9, 0x4C, 0x4C, 0xD9, 0x01, 0xA5, 0x06, 0x03, 0x52, 0x00, 0x67, 0x63, 0x29, 0x73, 0x9C, 0x6F, 0xD0, 0xEC, 0x3B, 0x99, 0x55, 0x17, 0x3B, 0x49, 0xE4, 0xBB, 0x0A, 0x94, 0x04, 0x9A, 0xCB, 0xAA, 0xA0, 0x3A, 0xD4, 0x44, 0x65, 0x97, 0x61, 0x06, 0x40, 0x08, 0x5A, 0xEE, 0x99, 0x2B, 0x4F, 0x8F, 0xFE, 0x26, 0xEA, 0x5C, 0x9D, 0xC4, 0xC3, 0xF4, 0x5C, 0xF4, 0x86, 0x1E, 0x40, 0x80, 0x97, 0x98, 0x3D, 0x32, 0x25, 0x8D, 0x7A, 0x77, 0x23, 0x02, 0xAC, 0xC1, 0xCB, 0xBF, 0xA8, 0xFF, 0xBF, 0x17, 0x98, 0x77, 0xE5, 0x61, 0x9A, 0xA7, 0x44, 0x49, 0xC0, 0x1C, 0x08, 0x06, 0x6A, 0x8D, 0xE1, 0xDB, 0x0F, 0xA4, 0x28, 0xC0, 0x0C, 0x90, 0xCF, 0x4F, 0x2E, 0x1D, 0x34, 0xFF, 0x2A, 0xC4, 0xE5, 0xF6, 0x3D, 0x97, 0x6A, 0x35, 0x14, 0x91, 0x87, 0x0A, 0x63, 0x02, 0xAB, 0x90, 0x97, 0x20, 0xC5, 0xE4, 0x27, 0xCB, 0xE1, 0xDB, 0xA7, 0xBA, 0xB5, 0x7D, 0x19, 0xAB, 0x8C, 0xE7, 0x80, 0x1A, 0xC0, 0xB2, 0xA6, 0x8E, 0x45, 0x63, 0xC9, 0xDB, 0xEE, 0x8A, 0xE3, 0x02, 0xE4, 0x2C, 0x93, 0x2B, 0xFA, 0xA1, 0x47, 0x2A, 0x9E, 0x8E, 0x9A, 0xE6, 0x37, 0xF7, 0x3B, 0xD3, 0x1D, 0x7A, 0xE6, 0x46, 0xE9, 0x3E, 0xA3, 0x7D, 0x1A, 0xA4, 0x0D, 0x6F, 0x18, 0x70, 0xB2, 0x61, 0xF3, 0xBF, 0xBD, 0x2A, 0x7B, 0x06, 0x76, 0xB8, 0x53, 0x5F, 0xBA, 0xC3, 0x0B, 0x35, 0x77, 0x4A, 0x58, 0xED, 0x0B, 0x6E, 0x4E, 0x21, 0x1A, 0x58, 0xA8, 0x6C, 0xB0, 0x0F, 0xA9, 0xC4, 0x6B, 0xF3, 0xE7, 0xE5, 0x93, 0xE5, 0x6E, 0xD0, 0xF3, 0x09, 0xE1, 0x75, 0x9E, 0xD5, 0x02, 0x68, 0xF9, 0x9A, 0x91, 0x01, 0x51, 0xEB, 0x91, 0x5A, 0xB9, 0x30, 0x95, 0xC6, 0x01, 0xC4, 0x00, 0xBD, 0x05, 0x85, 0xD7, 0x73, 0xEA, 0xF3, 0x66, 0x19, 0x36, 0x8B, 0xFB, 0xEC, 0x80, 0x1E, 0xC0, 0x7C, 0x1D, 0x8E, 0x2F, 0x0C, 0xA8, 0xD3, 0xA0, 0x65, 0x9C, 0xDE, 0x60, 0xEB, 0xA0, 0xE5, 0x97, 0x3C, 0x53, 0x45, 0xB6, 0xD6, 0x88, 0x46, 0x8F, 0xB6, 0x2B, 0xEE, 0x58, 0x25, 0x86, 0x7D, 0x59, 0x13, 0x47, 0x06, 0x5F, 0xC6, 0x7D, 0xDC, 0xAC, 0xDC, 0xC6, 0x9A, 0x0E, 0x44, 0x35, 0x68, 0xC9, 0x48, 0x0D, 0xE0, 0x25, 0x21, 0xAA, 0x91, 0xBE, 0x87, 0xDB, 0xEF, 0x78, 0xB0, 0x43, 0x01, 0x31, 0xE0, 0x9C, 0xE9, 0xC0, 0x67, 0xF7, 0x8B, 0x3A, 0x17, 0x57, 0xE9, 0xAD, 0x5D, 0xED, 0xDC, 0xC0, 0xBC, 0x83, 0x90, 0x03, 0x2A, 0x80, 0x73, 0xE3, 0x00, 0xA6, 0x80, 0x54, 0x43, 0x00, 0x55, 0x20, 0xDE, 0x52, 0xAB, 0x91, 0xB5, 0xB5, 0x80, 0x9A, 0xD4, 0xCD, 0xFF, 0x79, 0x67, 0x25, 0x3F, 0x35, 0x73, 0x12, 0xFE, 0xFD, 0x4D, 0xD0, 0xEA, 0xCA, 0xD2, 0x57, 0xF5, 0x7D, 0x52, 0xE3, 0xE9, 0xA7, 0x96, 0x3A, 0x6D, 0x50, 0x69, 0x89, 0x53, 0x84, 0x57, 0x1D, 0xCE, 0x1B, 0x36, 0x6D, 0x57, 0x29, 0xF7, 0x6A, 0x6C, 0xF0, 0x7C, 0xA4, 0x4E, 0x01, 0xF2, 0x7E, 0xD0, 0x48, 0x67, 0xA3, 0x91, 0xAC, 0x1F, 0x9F, 0xBE, 0x4F, 0xAD, 0x9B, 0x7B, 0xCA, 0x72, 0x4D, 0x70, 0x80, 0xE3, 0x97, 0x6B, 0x42, 0xC3, 0x1B, 0xD1, 0xC8, 0x5E, 0x6A, 0x75, 0x86, 0x2F, 0xB5, 0xA4, 0x7F, 0xD5, 0x76, 0x3E, 0x58, 0x7F, 0x4E, 0x89, 0xC1, 0x98, 0x2E, 0x7D, 0x2D, 0xD6, 0xCE, 0x0A, 0x1A, 0xDA, 0x16, 0xB7, 0x9D, 0x1A, 0xBD, 0xA6, 0xD8, 0xBE, 0xA3, 0x2F, 0xDB, 0x82, 0x6B, 0x4F, 0x9E, 0x0E, 0x70, 0xDE, 0xDF, 0x08, 0x10, 0x03, 0xEC, 0x4D, 0x9A, 0x9C, 0xCE, 0x0F, 0x2A, 0x00, 0x1F, 0x80, 0x62, 0xFD, 0x99, 0x02, 0x78, 0x3C, 0x7B, 0x72, 0xF8, 0x72, 0xF4, 0xDD, 0x23, 0xD7, 0x1D, 0xA2, 0xA2, 0x8F, 0xF6, 0x04, 0x98, 0x02, 0x61, 0x40, 0x51, 0xA3, 0x56, 0xB7, 0xB1, 0x00, 0xDC, 0x10, 0x07, 0x94, 0x01, 0xF3, 0x8E, 0x19, 0x41, 0x80, 0x18, 0x8E, 0x9F, 0xCA, 0x70, 0xA7, 0x16, 0xE6, 0xAE, 0x87, 0x7A, 0xCF, 0xE2, 0x12, 0x80, 0xAF, 0x1B, 0x7E, 0xFE, 0xAA, 0x12, 0xDC, 0x33, 0xC0, 0x4D, 0xA2, 0xE6, 0x18, 0xEF, 0x82, 0xAC, 0x4E, 0x7F, 0x02, 0x44, 0xAE, 0x72, 0x08, 0x88, 0xBA, 0x06, 0xF1, 0x40, 0xE5, 0x5C, 0x06, 0xA2, 0x00, 0x25, 0x70, 0x3A, 0xF4, 0xD5, 0xC8, 0x46, 0x0D, 0x61, 0x16, 0xDE, 0xC9, 0xF0, 0x88, 0x20, 0x20, 0x1C, 0x91, 0x3C, 0x05, 0x70, 0x00, 0x2A, 0x80, 0x1F, 0x20, 0x0A, 0x28, 0x6A, 0xE8, 0x74, 0xAB, 0x3B, 0x02, 0x10, 0x01, 0x7C, 0x00, 0xBD, 0x0B, 0x8D, 0xDB, 0xD9, 0x26, 0xBF, 0x21, 0x5C, 0xF5, 0xBD, 0x30, 0x0B, 0x8D, 0x66, 0x8E, 0x11, 0x8C, 0x7D, 0xB4, 0xCE, 0x0F, 0x51, 0xD1, 0xDB, 0x06, 0x26, 0x61, 0x8C, 0x7B, 0xD4, 0x1C, 0xCD, 0xEE, 0xD3, 0x22, 0xD2, 0xD7, 0xA6, 0xA2, 0x05, 0xB0, 0xCC, 0x61, 0xFE, 0x15, 0xF3, 0x4C, 0xEF, 0x79, 0xF3, 0xA4, 0x0A, 0x18, 0xCD, 0x8A, 0x10, 0x57, 0xE3, 0x00, 0xB4, 0x8E, 0x17, 0x21, 0x7F, 0x93, 0x7C, 0xF8, 0x65, 0x34, 0xE8, 0x00, 0xAA, 0xCB, 0x0D, 0x52, 0x80, 0xBA, 0xAB, 0xB7, 0xC1, 0x17, 0xDE, 0x48, 0x40, 0xA8, 0xE1, 0x80, 0x2A, 0xE0, 0x37, 0x68, 0x78, 0xF4, 0x42, 0xF9, 0xAB, 0xE5, 0xA9, 0xF2, 0x27, 0x20, 0x92, 0xA4, 0xEF, 0x45, 0x10, 0x4C, 0xFD, 0x16, 0x0A, 0xC4, 0x4E, 0x0C, 0x5B, 0x5A, 0xFA, 0xC8, 0x0D, 0x99, 0xED, 0xB7, 0xE7, 0x79, 0x9D, 0x28, 0x88, 0x56, 0x23, 0x0F, 0x60, 0xC0, 0x3B, 0xBD, 0x65, 0x23, 0x6E, 0x24, 0x11, 0xB4, 0x97, 0xA9, 0xCE, 0x73, 0x03, 0xA3, 0xA3, 0xFC, 0x16, 0x07, 0xF0, 0x5D, 0xA1, 0x7B, 0x5E, 0x4C, 0xA3, 0xD7, 0x45, 0xFE, 0x6B, 0x1B, 0x77, 0x00, 0x0B, 0x20, 0x75, 0x26, 0x2F, 0x38, 0x00, 0x63, 0xC0, 0x1D, 0x08, 0x6A, 0x68, 0xC3, 0x1A, 0x3E, 0x27, 0xF9, 0x92, 0x74, 0xD0, 0xF4, 0x2B, 0x79, 0x96, 0xF1, 0xA7, 0x7E, 0x11, 0xE7, 0xD9, 0xF9, 0xA9, 0x8C, 0x5A, 0x27, 0x31, 0xAC, 0x5E, 0xF2, 0xDA, 0x52, 0xDB, 0xB8, 0xB1, 0xFB, 0xD9, 0x57, 0x82, 0x02, 0x7C, 0xDD, 0x0C, 0xCC, 0x7F, 0xB8, 0x52, 0xD7, 0x01, 0xC2, 0x1B, 0x09, 0x54, 0x4C, 0x45, 0x56, 0x3A, 0x60, 0x01, 0x68, 0x02, 0x76, 0x1A, 0x02, 0x78, 0x4D, 0x13, 0xB7, 0xB3, 0xCA, 0x52, 0x5A, 0x73, 0x6E, 0x08, 0x1B, 0xA0, 0x7B, 0xA6, 0x56, 0x02, 0xC5, 0x0D, 0x99, 0xC8, 0x6C, 0xD4, 0xBC, 0xF0, 0xD3, 0x7D, 0x79, 0x96, 0x7D, 0xBB, 0x58, 0x52, 0x62, 0xB8, 0xAC, 0xF1, 0x50, 0xC6, 0x07, 0x05, 0x34, 0x16, 0x1C, 0x78, 0xE3, 0xB3, 0xC1, 0x77, 0xBA, 0x83, 0xF6, 0x2E, 0x9F, 0xF6, 0x73, 0xE2, 0x67, 0x28, 0x90, 0xB2, 0xBA, 0x59, 0x57, 0xF7, 0x19, 0xD1, 0xBC, 0x79, 0x89, 0xCE, 0x56, 0xAF, 0x60, 0xC0, 0xCF, 0xEA, 0xF8, 0x92, 0x46, 0x02, 0x44, 0xC0, 0x18, 0x76, 0x8F, 0x90, 0xAC, 0x19, 0x0F, 0xAE, 0xB3, 0xC8, 0x50, 0xD7, 0x81, 0xC8, 0x01, 0x13, 0x20, 0xED, 0x4D, 0x2E, 0x06, 0x7C, 0xE1, 0xAE, 0xDB, 0xEA, 0x4F, 0x09, 0x28, 0x77, 0xD4, 0x1C, 0xEE, 0x13, 0x84, 0xC1, 0x9F, 0xA2, 0xD0, 0xF9, 0x59, 0x5F, 0xAB, 0x32, 0x0D, 0x53, 0xCA, 0x84, 0x70, 0x46, 0xB0, 0x2B, 0xCB, 0xA7, 0x79, 0x91, 0x7A, 0x7E, 0x30, 0x35, 0x3D, 0xE8, 0xFC, 0xCC, 0x64, 0x84, 0xF0, 0x9C, 0x41, 0x27, 0xAB, 0x87, 0x56, 0xA5, 0xA1, 0x4B, 0xB4, 0xEF, 0xF3, 0x12, 0x2A, 0xF4, 0x4B, 0x9E, 0x41, 0xC0, 0xFD, 0x09, 0x47, 0xDF, 0x21, 0xB7, 0x5F, 0x2B, 0xFB, 0x31, 0x15, 0x40, 0x0B, 0xB8, 0x4F, 0xDD, 0x11, 0x40, 0x1A, 0x46, 0x0D, 0x6E, 0xAC, 0x24, 0xA8, 0x26, 0x60, 0x31, 0x47, 0x61, 0x54, 0x7C, 0x56, 0x7D, 0x5C, 0x84, 0x06, 0x6D, 0x92, 0xD1, 0xEE, 0x53, 0x95, 0x50, 0x53, 0xBB, 0x23, 0x8D, 0xC3, 0x8C, 0x8B, 0x8F, 0x9E, 0xD9, 0x99, 0x7D, 0x59, 0xB1, 0x5B, 0xCB, 0x74, 0x75, 0x47, 0xD1, 0x8F, 0x01, 0xA9, 0x59, 0x40, 0x34, 0x8A, 0x67, 0xE7, 0x94, 0x1B, 0xA0, 0xF6, 0xCB, 0x92, 0xC2, 0x1A, 0x09, 0x4C, 0xC3, 0x13, 0x7B, 0xEF, 0x9C, 0x3A, 0xAF, 0xA6, 0x77, 0x2F, 0x0A, 0x80, 0x09, 0x10, 0x06, 0x54, 0xAE, 0x71, 0xF5, 0x05, 0x28, 0x2F, 0xD0, 0x84, 0x31, 0x10, 0xD5, 0x51, 0xCB, 0x21, 0xB9, 0x45, 0xA5, 0xCE, 0x31, 0xF8, 0xDF, 0xD1, 0xDF, 0x81, 0xCB, 0x4A, 0x06, 0x6E, 0x71, 0x66, 0xF0, 0x68, 0x34, 0x99, 0xD6, 0x09, 0xBC, 0xB2, 0x43, 0x4A, 0xB3, 0xC5, 0xCB, 0x02, 0x90, 0x04, 0x8E, 0xCE, 0x8E, 0x38, 0x6D, 0xF0, 0x6A, 0x6F, 0xDA, 0x1E, 0x88, 0x12, 0x00, 0x9D, 0xA5, 0x2C, 0x6D, 0xF0, 0x48, 0xD3, 0xD9, 0x6B, 0x43, 0xEC, 0x1D, 0x8F, 0xDE, 0x28, 0xFB, 0x94, 0x69, 0xB0, 0xC9, 0x01, 0x98, 0x02, 0x11, 0x40, 0x69, 0xAF, 0xC6, 0x06, 0x09, 0xC0, 0x04, 0xC8, 0xF9, 0x91, 0x29, 0x77, 0xED, 0xA0, 0x15, 0xB2, 0xB6, 0x4E, 0x9F, 0x2F, 0x75, 0x9D, 0x18, 0xD3, 0x9F, 0x39, 0xB5, 0xE5, 0x3C, 0x06, 0xA5, 0x92, 0x24, 0x92, 0xAE, 0x51, 0xD0, 0x59, 0xFD, 0x14, 0xA9, 0x91, 0xAD, 0x11, 0xDF, 0x09, 0xA4, 0xAC, 0xB1, 0xE1, 0xB5, 0x86, 0xCB, 0x3A, 0xA0, 0x1D, 0xBB, 0x53, 0x80, 0x07, 0x60, 0x0C, 0x9C, 0x5C, 0x57, 0xF6, 0xF5, 0x67, 0xD6, 0x0D, 0xF6, 0x7A, 0x07, 0x3C, 0x05, 0x3E, 0xCD, 0xFB, 0x90, 0x13, 0x10, 0xB6, 0xE4, 0x19, 0x0A, 0x28, 0x4D, 0x88, 0x01, 0xDC, 0xA0, 0x04, 0x38, 0x80, 0x3B, 0xD6, 0x41, 0x87, 0x97, 0xC9, 0xF7, 0x0F, 0x5F, 0xB0, 0xA7, 0x26, 0x46, 0x3A, 0xD2, 0x1D, 0x0D, 0x11, 0xAA, 0x48, 0x14, 0x14, 0xF5, 0xF6, 0x3C, 0x44, 0x6A, 0xDB, 0x84, 0x8E, 0xDF, 0x1E, 0x25, 0xBA, 0xBA, 0x8D, 0x1A, 0x66, 0x00, 0xEB, 0x14, 0x21, 0x47, 0xDE, 0x4F, 0x53, 0x0C, 0x7A, 0x02, 0x20, 0x9B, 0xAD, 0x68, 0xF5, 0xD2, 0x91, 0x00, 0x9D, 0xD9, 0x6E, 0x2B, 0xFC, 0x52, 0x8E, 0xB7, 0x3D, 0x68, 0x0E, 0x97, 0x75, 0x02, 0x8A, 0xD6, 0xE4, 0xD8, 0x02, 0x74, 0x95, 0x5A, 0xFD, 0x34, 0x12, 0x08, 0x03, 0xD2, 0x81, 0xBA, 0x85, 0xD7, 0xEA, 0xA0, 0xD1, 0x77, 0xE8, 0x08, 0x77, 0x8C, 0x93, 0x3D, 0x7F, 0xEF, 0xCF, 0x6F, 0xD3, 0x2E, 0x4C, 0x30, 0xA4, 0xE8, 0x8D, 0x3C, 0x7A, 0xA5, 0xF1, 0xC8, 0x78, 0xAB, 0xFF, 0x9E, 0x85, 0x11, 0x3F, 0x3C, 0x4D, 0x34, 0xD7, 0x4C, 0x95, 0x9A, 0x55, 0x03, 0x7F, 0x82, 0xBD, 0x99, 0x2A, 0x2F, 0x05, 0x4C, 0x00, 0x69, 0xF0, 0x7A, 0x15, 0xE8, 0x59, 0xCD, 0x8F, 0x7C, 0x57, 0xC7, 0x3A, 0x10, 0x67, 0xEF, 0x5F, 0xB4, 0xF4, 0x19, 0xA6, 0x40, 0xAE, 0x7E, 0x87, 0x73, 0xE3, 0x6B, 0x40, 0x56, 0x63, 0x27, 0xE1, 0xB8, 0xA3, 0xC6, 0xC3, 0xCD, 0xFB, 0xB0, 0x7D, 0xF3, 0x18, 0x23, 0x31, 0xFE, 0x2D, 0x29, 0xF0, 0x67, 0x85, 0x60, 0xFE, 0x5E, 0x22, 0x01, 0x6E, 0xB5, 0x2E, 0x05, 0xB9, 0x6A, 0x9F, 0x4F, 0x76, 0x73, 0xF5, 0x4F, 0x06, 0x68, 0xCC, 0x01, 0xA4, 0x1C, 0x33, 0xB7, 0xC5, 0xD1, 0x70, 0xC0, 0x73, 0xA9, 0x76, 0x64, 0x6A, 0x42, 0xAD, 0xE1, 0x02, 0xC4, 0xB0, 0xC2, 0x7F, 0x3D, 0x1F, 0x78, 0x4D, 0x60, 0x73, 0xEA, 0x4B, 0x93, 0xD8, 0x34, 0xD8, 0x3C, 0xB1, 0xBC, 0x22, 0x19, 0xC8, 0xD3, 0x70, 0xA0, 0xB4, 0x4D, 0x74, 0x6C, 0x99, 0xE8, 0x34, 0xE4, 0x00, 0x2A, 0x1D, 0x34, 0x19, 0xC6, 0xB7, 0x2E, 0x82, 0x36, 0x1F, 0x43, 0x5A, 0xB2, 0x2A, 0x71, 0xE7, 0x71, 0x81, 0x82, 0x1A, 0x92, 0x52, 0xB6, 0xE5, 0x1B, 0xDF, 0xA4, 0xE7, 0xF2, 0xF8, 0x9E, 0xC1, 0x46, 0x12, 0xE0, 0x07, 0xE0, 0x58, 0x4E, 0xFA, 0x01, 0x30, 0x01, 0xB4, 0x7A, 0x53, 0x5D, 0x01, 0x3B, 0x00, 0x2B, 0x40, 0xB1, 0xFA, 0x5D, 0x87, 0x91, 0x86, 0x3E, 0x81, 0x56, 0xF1, 0x30, 0xAD, 0x38, 0xEF, 0x8D, 0x27, 0x0D, 0xCF, 0x29, 0x15, 0x39, 0x05, 0xB0, 0x01, 0x22, 0xAB, 0x9C, 0x62, 0x80, 0x29, 0xE0, 0xD4, 0x28, 0x20, 0x6F, 0xD0, 0xF4, 0x2B, 0x18, 0x4B, 0xF0, 0xBF, 0xF8, 0x0E, 0x47, 0x34, 0xBA, 0xF1, 0xC2, 0x0A, 0x9B, 0x8A, 0x13, 0xC4, 0x65, 0xD1, 0x97, 0x02, 0x87, 0x88, 0x54, 0xF6, 0xA1, 0xA3, 0x76, 0x63, 0x99, 0xE6, 0x9A, 0xDB, 0x13, 0x00, 0x2B, 0x70, 0x64, 0x65, 0x6F, 0x69, 0x3E, 0xD7, 0x6F, 0xBA, 0x08, 0x37, 0xCE, 0x72, 0x95, 0xD1, 0x86, 0x4F, 0xE4, 0x38, 0x09, 0xDB, 0x93, 0x7F, 0x1A, 0x4F, 0x79, 0x76, 0xC9, 0x94, 0x12, 0x0A, 0x03, 0x5A, 0x4B, 0xE1, 0x77, 0x1A, 0xDA, 0xB0, 0x86, 0x34, 0x7C, 0xBE, 0x3B, 0x28, 0xEE, 0xAB, 0xC0, 0xC6, 0xAB, 0x80, 0x82, 0xD0, 0x5D, 0xA0, 0x82, 0xEC, 0x24, 0x73, 0x1B, 0x2A, 0x52, 0xCB, 0x6C, 0x02, 0x59, 0x41, 0xEE, 0xA9, 0x65, 0xDB, 0xD9, 0x84, 0x9E, 0x89, 0xC9, 0xB2, 0x6E, 0x0F, 0xC0, 0x1B, 0x4C, 0xB3, 0x0D, 0x42, 0x72, 0xF4, 0x4D, 0x0C, 0x71, 0xDD, 0xC8, 0xDE, 0x7A, 0x01, 0x12, 0x8D, 0x03, 0xA8, 0x00, 0xA6, 0xAF, 0x4A, 0x72, 0xCF, 0x5F, 0xD3, 0xE8, 0xB0, 0x9F, 0xC1, 0x67, 0x5F, 0x58, 0x39, 0xEB, 0xC7, 0xD5, 0xE9, 0x21, 0x66, 0x40, 0x05, 0x30, 0x05, 0xBC, 0x11, 0x02, 0xA4, 0x03, 0x15, 0x9D, 0x33, 0x3A, 0x00, 0x47, 0x07, 0xCD, 0x5F, 0xD0, 0xD4, 0xD0, 0xFF, 0xA9, 0x5F, 0x26, 0xA6, 0xA7, 0x8E, 0x13, 0xAC, 0xFB, 0x7A, 0x30, 0x5E, 0x90, 0xDC, 0x26, 0x91, 0xC4, 0x61, 0xE3, 0x97, 0x89, 0x8E, 0xBC, 0xEE, 0x66, 0xF3, 0x79, 0xB1, 0x4B, 0x05, 0x94, 0x81, 0xD7, 0x4F, 0x9C, 0x80, 0x28, 0xF0, 0x6E, 0xF4, 0x0C, 0x24, 0x01, 0x75, 0x00, 0xF7, 0x86, 0x00, 0xD1, 0x48, 0x7E, 0x0B, 0xE8, 0xB6, 0x37, 0xFD, 0x09, 0xD9, 0xE4, 0x89, 0x13, 0x94, 0xE7, 0x05, 0xDD, 0x1B, 0x25, 0x08, 0x2C, 0x39, 0x20, 0x0C, 0xE8, 0x45, 0x01, 0x7E, 0x1A, 0x05, 0xE4, 0x99, 0x33, 0xE2, 0xDE, 0x0B, 0x34, 0x76, 0x9F, 0xEC, 0xF7, 0x9C, 0xBA, 0x60, 0x1A, 0x86, 0x0A, 0xA3, 0x23, 0xAC, 0xAD, 0x6F, 0x93, 0x09, 0x37, 0x45, 0xF4, 0xB3, 0x87, 0x6D, 0xBD, 0xF2, 0x89, 0xD9, 0x84, 0x21, 0x05, 0xB8, 0x03, 0xEA, 0xCB, 0x84, 0xCE, 0x00, 0x5D, 0x47, 0xB5, 0xB3, 0x2E, 0xA5, 0xC4, 0xCB, 0xC5, 0xD5, 0x00, 0x71, 0x40, 0x15, 0x30, 0x02, 0x72, 0x9C, 0x92, 0xFD, 0x9D, 0xAE, 0xC4, 0x3B, 0x84, 0x56, 0xF3, 0x98, 0x2B, 0x05, 0x04, 0x01, 0x65, 0xD3, 0x8F, 0x94, 0x1B, 0x42, 0x5B, 0x62, 0xD5, 0x48, 0xC0, 0x0B, 0x78, 0xBB, 0x5A, 0xF6, 0xE8, 0xE2, 0x17, 0xB4, 0xEF, 0xF2, 0x6E, 0x0C, 0x69, 0x3C, 0x09, 0x5A, 0x57, 0x82, 0xFA, 0xA0, 0xEF, 0x82, 0x8D, 0x8A, 0xD7, 0x78, 0xD9, 0x5C, 0xFD, 0x04, 0xAA, 0xF3, 0xBA, 0x5D, 0x01, 0xC4, 0xDA, 0xE7, 0x4F, 0x4E, 0xCB, 0x35, 0xD5, 0xC6, 0x01, 0x8C, 0x1B, 0x3E, 0x63, 0xE7, 0xB2, 0x52, 0x1D, 0xD6, 0x28, 0xE0, 0xBE, 0x57, 0x5E, 0xA9, 0xF0, 0xB6, 0xDC, 0x6D, 0x7F, 0xB1, 0x8B, 0xCA, 0x29, 0xC9, 0xB1, 0x03, 0x44, 0x01, 0x15, 0x8D, 0xF5, 0x29, 0x73, 0x95, 0x5C, 0xF4, 0xE5, 0x9E, 0x11, 0xB4, 0x9A, 0x2B, 0x6D, 0xF9, 0xA9, 0x05, 0xAA, 0x9F, 0x4C, 0x82, 0x37, 0x42, 0x44, 0xE2, 0x82, 0xC9, 0x7A, 0x6F, 0x50, 0x5B, 0xA5, 0x36, 0xFD, 0xB7, 0xA2, 0x80, 0x6C, 0xC4, 0xBA, 0x85, 0x72, 0x2C, 0xC7, 0x37, 0x6A, 0xC4, 0xBC, 0x29, 0x48, 0x00, 0x47, 0x66, 0x7C, 0x34, 0x00, 0x4B, 0xC0, 0xED, 0xAF, 0x28, 0x28, 0x2F, 0x6D, 0xE7, 0xE7, 0x2E, 0xB1, 0x97, 0x43, 0x9C, 0x42, 0x24, 0xEF, 0xE7, 0xF2, 0x30, 0xC0, 0x09, 0x68, 0xC3, 0x1A, 0x1E, 0x40, 0x18, 0x90, 0xCB, 0xDF, 0xFA, 0x10, 0x40, 0x86, 0xA0, 0xD1, 0xBB, 0x14, 0x20, 0x3F, 0x54, 0xA8, 0xAA, 0x38, 0x05, 0x66, 0x49, 0x31, 0xE1, 0x12, 0x11, 0x85, 0x33, 0x55, 0x7B, 0x5C, 0x39, 0xD5, 0x8F, 0x93, 0xDA, 0xA9, 0x69, 0x71, 0x29, 0x5B, 0x48, 0xE0, 0xB3, 0xE7, 0x24, 0x75, 0xF7, 0x22, 0x36, 0x62, 0x3E, 0xC8, 0xB1, 0x0E, 0x1D, 0xA7, 0xE6, 0x68, 0x1F, 0x3A, 0x00, 0x03, 0x4F, 0xBF, 0x20, 0xA3, 0x88, 0x4E, 0xFC, 0xC6, 0x58, 0x5E, 0x21, 0x94, 0x76, 0x0C, 0xE8, 0xCC, 0x30, 0x45, 0x00, 0x65, 0x1D, 0x91, 0x02, 0x28, 0x01, 0x2E, 0x40, 0x1A, 0x46, 0x80, 0x1F, 0x20, 0xBC, 0x83, 0x46, 0xBF, 0x7C, 0x0E, 0x71, 0xBC, 0x75, 0x34, 0x15, 0x8B, 0x40, 0x9C, 0xA0, 0x26, 0x85, 0x13, 0x96, 0xD6, 0x2F, 0x3B, 0xEF, 0x7E, 0xA2, 0x9E, 0x47, 0x1A, 0xFD, 0x98, 0x95, 0x1D, 0x0A, 0x90, 0xAC, 0xE1, 0x65, 0xAB, 0x3F, 0xC8, 0x0D, 0x30, 0x5D, 0x2B, 0x6D, 0x8D, 0xDC, 0x32, 0x02, 0xFC, 0xE5, 0xF0, 0xA6, 0x35, 0x25, 0xD7, 0x7D, 0xE8, 0xC6, 0x8C, 0x0B, 0xBC, 0x4F, 0x7A, 0x6A, 0x67, 0xAB, 0xBE, 0x1C, 0xD0, 0x86, 0x07, 0x10, 0xB5, 0x4E, 0xB9, 0xB6, 0x4E, 0xB9, 0xB6, 0x4E, 0xB9, 0xDA, 0x41, 0xE3, 0x17, 0xB4, 0x50, 0x0C, 0xF3, 0x51, 0xC1, 0x74, 0x24, 0xF4, 0x30, 0xDA, 0x77, 0x46, 0x49, 0xF2, 0x6E, 0xA7, 0x34, 0x38, 0x5E, 0xD0, 0x34, 0x06, 0x33, 0xD9, 0x85, 0x82, 0xD5, 0x45, 0x18, 0x0C, 0xDC, 0x96, 0xA7, 0x6C, 0x88, 0xCC, 0x10, 0x8A, 0x00, 0xB4, 0x67, 0xD9, 0x31, 0x70, 0x96, 0x57, 0x90, 0x33, 0x10, 0x8D, 0x1C, 0x89, 0x36, 0x7B, 0x17, 0xF2, 0x7E, 0x74, 0x69, 0x49, 0x1F, 0xF5, 0x8D, 0x1C, 0x15, 0x05, 0xBC, 0x51, 0xA7, 0xE3, 0x9A, 0x00, 0x35, 0x38, 0x00, 0xC9, 0x95, 0x4C, 0x6B, 0xB8, 0x02, 0xC9, 0x1D, 0x34, 0x28, 0x93, 0x55, 0x1C, 0xF7, 0x92, 0xB0, 0x7F, 0xF5, 0xBD, 0xE8, 0xE8, 0x3B, 0xB6, 0x9D, 0x10, 0x58, 0x59, 0x4A, 0xB5, 0xE4, 0x96, 0x60, 0x83, 0xA7, 0x01, 0x0F, 0xD7, 0xDF, 0xCE, 0xB7, 0xC4, 0x1D, 0xBC, 0x00, 0xC4, 0x1B, 0xD9, 0xA0, 0x09, 0x35, 0x20, 0xAF, 0x3B, 0xC1, 0x48, 0x40, 0x10, 0x7F, 0xC4, 0xAE, 0x54, 0x7F, 0x65, 0x4B, 0xBC, 0x5B, 0x9F, 0x8A, 0x3D, 0xDF, 0x11, 0x56, 0x69, 0x56, 0x52, 0x9D, 0x01, 0x29, 0x80, 0x09, 0xA0, 0x98, 0x60, 0x02, 0xF4, 0x00, 0xD1, 0xA8, 0x46, 0x06, 0x10, 0x06, 0x58, 0x02, 0xEA, 0xF3, 0x53, 0xD9, 0xE9, 0xA8, 0xE9, 0x3F, 0x27, 0x1C, 0x68, 0x59, 0xF1, 0x44, 0xBE, 0xC7, 0x14, 0x1B, 0x3A, 0xBC, 0x3C, 0x24, 0x90, 0x39, 0xA7, 0x1E, 0x90, 0x97, 0xD3, 0x43, 0x47, 0x69, 0x77, 0x96, 0x9D, 0x75, 0x4D, 0xCF, 0x6A, 0x10, 0xE0, 0x7B, 0xB8, 0xE5, 0x68, 0x40, 0xD0, 0xA7, 0x92, 0x3A, 0xFA, 0x57, 0x58, 0x21, 0x7A, 0xB3, 0x1C, 0x5C, 0x86, 0x1D, 0xB8, 0x8D, 0xF9, 0x6C, 0x28, 0xCF, 0xCC, 0x4B, 0xE9, 0x45, 0x4C, 0xE4, 0x69, 0x48, 0xE3, 0x0A, 0x35, 0x02, 0x90, 0x04, 0x2C, 0x1A, 0x06, 0x28, 0xAF, 0x01, 0x57, 0x0D, 0x26, 0xC0, 0xF3, 0x46, 0xCD, 0x90, 0xAA, 0xDD, 0x06, 0xB8, 0xDD, 0xC4, 0xA8, 0x6E, 0xE8, 0x25, 0x2C, 0xC5, 0xB9, 0x32, 0x3B, 0x35, 0x56, 0x7A, 0xAF, 0x50, 0x3B, 0x3F, 0xB4, 0x3C, 0xAE, 0x6C, 0x46, 0x2B, 0x74, 0x46, 0xCB, 0x6A, 0xE6, 0x36, 0xAE, 0xD6, 0x40, 0x5E, 0xC1, 0x6A, 0x0D, 0xB9, 0x88, 0x02, 0x44, 0xFE, 0x5B, 0xB4, 0xCB, 0xF7, 0xAA, 0xD4, 0x98, 0xD1, 0xA2, 0xBC, 0xFD, 0xA3, 0x40, 0x38, 0xE0, 0x4B, 0xED, 0xE6, 0xA7, 0xA1, 0x73, 0x9C, 0xEA, 0x21, 0x80, 0xB4, 0x21, 0xC0, 0xF1, 0xF9, 0x87, 0x65, 0xDE, 0x4F, 0xD3, 0x0D, 0x46, 0x09, 0xDD, 0x8B, 0xCA, 0xFE, 0x7F, 0x83, 0xC6, 0xA7, 0x70, 0xBD, 0x21, 0xFF, 0x5E, 0xA3, 0x75, 0xE7, 0x58, 0x9E, 0x59, 0x94, 0x32, 0xDD, 0x49, 0xEF, 0x92, 0x69, 0x65, 0x12, 0xB6, 0x5C, 0xF4, 0xB3, 0xC1, 0x8D, 0x9A, 0x5A, 0x0E, 0xAE, 0xA7, 0x5C, 0xB8, 0x1D, 0x13, 0x6B, 0xF0, 0x78, 0x3C, 0xED, 0x77, 0x8F, 0x14, 0xC1, 0x19, 0x76, 0xD9, 0x22, 0xC8, 0xBA, 0x63, 0x1E, 0x5A, 0x45, 0x26, 0x9E, 0xD7, 0xD0, 0x73, 0x96, 0x00, 0xBD, 0x00, 0x93, 0x09, 0xCD, 0xA5, 0xB8, 0x71, 0x40, 0x0D, 0x08, 0xBD, 0x51, 0x8B, 0x7F, 0x8A, 0x3F, 0x73, 0x45, 0x0D, 0xCA, 0x48, 0xB7, 0x6C, 0x77, 0x14, 0xC5, 0xA3, 0x9F, 0x05, 0xFF, 0x83, 0xF8, 0x69, 0x07, 0xA3, 0x37, 0x6A, 0x67, 0xF9, 0x7E, 0x35, 0x2C, 0xD7, 0x7C, 0xCA, 0xD3, 0x20, 0xC0, 0x68, 0xE6, 0xFA, 0xFD, 0xFE, 0xF6, 0x36, 0xD3, 0xAB, 0xA7, 0xDE, 0x45, 0xBB, 0x1F, 0x91, 0x59, 0x3F, 0x55, 0x02, 0xC8, 0x80, 0xB3, 0x66, 0x49, 0xA4, 0x2D, 0xC4, 0x34, 0xB8, 0x3B, 0xB2, 0x1C, 0x2B, 0xB9, 0x21, 0x8D, 0x03, 0xB0, 0x37, 0xA8, 0x51, 0x80, 0xF1, 0x8D, 0x5A, 0x7E, 0x42, 0x52, 0xCB, 0x68, 0xB3, 0x34, 0xFB, 0x5C, 0x5C, 0xA3, 0x30, 0xAC, 0xB7, 0xCA, 0x7B, 0x50, 0x4C, 0x76, 0xCE, 0x33, 0x90, 0x39, 0xE5, 0xCE, 0x76, 0xEF, 0xC9, 0x65, 0x87, 0xA7, 0x35, 0x98, 0x2F, 0xE3, 0x2E, 0xCF, 0x85, 0x00, 0xC2, 0x47, 0x3F, 0xD5, 0xDF, 0x2C, 0xC0, 0x5A, 0x33, 0xC3, 0xE9, 0xAF, 0xEC, 0xAB, 0xAF, 0x56, 0x2E, 0x57, 0x69, 0x6F, 0x73, 0x20, 0xCF, 0xC9, 0x5E, 0xA2, 0x0A, 0x44, 0x01, 0xDE, 0x88, 0xD3, 0x10, 0x20, 0x57, 0xDF, 0x0F, 0xEB, 0xAA, 0xA8, 0xAC, 0xE6, 0x1A, 0x56, 0x80, 0x12, 0x60, 0x07, 0x5C, 0x3A, 0x68, 0xD5, 0x63, 0xB3, 0xA3, 0xDD, 0x4E, 0x7C, 0x58, 0x6B, 0x96, 0xE0, 0x80, 0x4B, 0xC4, 0xDD, 0xA1, 0x13, 0x48, 0xFF, 0xCB, 0x18, 0xED, 0xB0, 0x53, 0x91, 0xFC, 0x90, 0xBE, 0x4A, 0x96, 0x33, 0xC9, 0x0F, 0x60, 0x3B, 0x03, 0x74, 0x58, 0xF6, 0x75, 0x3E, 0xBF, 0xA5, 0x62, 0xF3, 0xCE, 0x27, 0x32, 0xC7, 0xBC, 0x93, 0x5C, 0x3D, 0x32, 0xC0, 0x01, 0x1C, 0x07, 0xA8, 0xC1, 0x67, 0x4D, 0x05, 0xD2, 0x86, 0x03, 0x22, 0x80, 0x35, 0x92, 0x3B, 0xE6, 0x2F, 0x92, 0x8D, 0x03, 0x44, 0x00, 0x9E, 0x40, 0x74, 0xEC, 0xA8, 0x83, 0xC6, 0xE7, 0xAB, 0x1A, 0x3B, 0xF1, 0xFF, 0x35, 0x59, 0x8E, 0x28, 0x34, 0x19, 0x53, 0x75, 0xAB, 0x68, 0x5F, 0xB6, 0x63, 0x5A, 0x53, 0x6B, 0xEE, 0x57, 0x01, 0x2F, 0xB7, 0x26, 0x6F, 0x1C, 0x40, 0xBD, 0x71, 0x1A, 0x63, 0x58, 0xAA, 0xBC, 0x77, 0x9D, 0x9C, 0x67, 0xEF, 0x3E, 0x57, 0x45, 0xAE, 0xDE, 0xDF, 0x43, 0xB3, 0x8B, 0x91, 0x80, 0x63, 0x0D, 0xDA, 0xD2, 0xE3, 0x99, 0x0E, 0x3B, 0xA7, 0x11, 0x00, 0x2D, 0x1B, 0x19, 0x8D, 0x46, 0x35, 0x72, 0xA1, 0x00, 0x4B, 0x20, 0xEE, 0xFB, 0xB3, 0xFB, 0xA2, 0x0E, 0xF3, 0xD7, 0x58, 0x60, 0x3A, 0x4C, 0xE8, 0x30, 0x91, 0x2B, 0xDF, 0xAC, 0x42, 0x22, 0x2A, 0xBC, 0x05, 0x99, 0xA6, 0x73, 0xC2, 0x16, 0xC7, 0x93, 0xAC, 0x92, 0x91, 0x35, 0x78, 0x9D, 0xFC, 0xA3, 0x51, 0x40, 0x8D, 0x81, 0x84, 0xFE, 0x5A, 0x38, 0xF9, 0x89, 0x3A, 0xA6, 0x4F, 0x8E, 0xEA, 0x6C, 0x01, 0xD6, 0x06, 0x07, 0xE0, 0xF7, 0x37, 0xBB, 0x6B, 0x44, 0x78, 0x2E, 0x8E, 0xC3, 0x00, 0x09, 0xC0, 0x06, 0x68, 0x23, 0x18, 0xC8, 0x5A, 0x10, 0x20, 0x14, 0xF0, 0x04, 0x22, 0x7A, 0x9D, 0xDF, 0xA0, 0x31, 0x04, 0x6A, 0x54, 0xE8, 0xF3, 0x10, 0xCC, 0x2F, 0x8B, 0x76, 0x36, 0x49, 0x62, 0x34, 0x33, 0x6B, 0xB4, 0xC9, 0x3F, 0x44, 0xB8, 0x62, 0x3A, 0x3C, 0xE8, 0x2C, 0x56, 0x7A, 0x48, 0x6A, 0x6A, 0xDD, 0xD5, 0x1A, 0xBA, 0x2A, 0xE6, 0xAB, 0xA8, 0xC9, 0xFE, 0x67, 0xF7, 0x1A, 0x6F, 0x39, 0x90, 0x9D, 0xB1, 0xA8, 0x32, 0x3A, 0x22, 0x0E, 0xD0, 0xCD, 0xB8, 0xAE, 0xD7, 0x67, 0xE6, 0x74, 0x0E, 0x8A, 0xDD, 0xAC, 0x49, 0x05, 0x70, 0x43, 0x62, 0x55, 0x90, 0x15, 0x48, 0x6B, 0x78, 0x23, 0x1A, 0xD2, 0x38, 0xAB, 0x48, 0x63, 0x1D, 0x34, 0xF9, 0x27, 0x5F, 0xBA, 0x4D, 0x61, 0x77, 0xE8, 0x33, 0xE9, 0x4D, 0x24, 0x28, 0xA8, 0xA0, 0x66, 0x6C, 0x14, 0x8E, 0x22, 0x92, 0xCE, 0x93, 0x9A, 0xC9, 0xB6, 0xA0, 0xF3, 0x75, 0x1A, 0x8B, 0xF9, 0x49, 0x79, 0xBE, 0x3D, 0xD9, 0x66, 0x0B, 0xC2, 0xB9, 0x19, 0x7F, 0x9A, 0x79, 0x4C, 0x0E, 0x80, 0x62, 0xDA, 0x95, 0x38, 0x01, 0xD2, 0xA0, 0x02, 0x44, 0xD7, 0x19, 0xBF, 0xA6, 0xC8, 0x98, 0x13, 0x90, 0x75, 0x76, 0x35, 0xDD, 0x12, 0xD3, 0x86, 0x4C, 0x44, 0x4D, 0xDC, 0xD4, 0xF7, 0x79, 0x8F, 0xA7, 0xFE, 0x33, 0x41, 0x89, 0x40, 0xBE, 0x36, 0xA3, 0x59, 0x33, 0xCE, 0x13, 0x48, 0xEF, 0x51, 0xE1, 0x54, 0x4C, 0x84, 0xBD, 0x88, 0x65, 0x2A, 0x61, 0xC0, 0x51, 0xC9, 0xB3, 0x5F, 0xE7, 0xDB, 0x86, 0x29, 0xA0, 0xD9, 0x18, 0x8F, 0xA9, 0xBC, 0x57, 0xEB, 0xAB, 0xF3, 0xE6, 0x34, 0x87, 0x4C, 0x05, 0xAE, 0xC2, 0xCD, 0x56, 0xEA, 0x5C, 0xA5, 0x11, 0x40, 0x9E, 0xE9, 0x56, 0x41, 0x0A, 0x30, 0x37, 0x62, 0x06, 0xCF, 0x78, 0x86, 0xA4, 0xBC, 0xA1, 0x6B, 0x9C, 0x7D, 0xC3, 0x13, 0x88, 0x7C, 0x46, 0x95, 0x1D, 0x35, 0x38, 0x77, 0x23, 0xDB, 0x68, 0xB0, 0x23, 0x7D, 0x51, 0xFB, 0x42, 0x11, 0x28, 0xAF, 0x09, 0x21, 0x1F, 0x9D, 0x85, 0x5F, 0x36, 0x6C, 0x3A, 0xDF, 0xFA, 0x2A, 0x1A, 0x1F, 0x03, 0x22, 0xE6, 0x6E, 0x96, 0x5B, 0xE1, 0x71, 0xC1, 0x40, 0x8C, 0xC1, 0x8B, 0xF6, 0x1A, 0x78, 0x4A, 0x96, 0xC1, 0x84, 0x5F, 0x75, 0xE0, 0x5C, 0x71, 0xC2, 0x4B, 0x00, 0x7F, 0x03, 0xA3, 0x40, 0xE6, 0x34, 0x96, 0x53, 0x03, 0xAC, 0xE1, 0x8D, 0xDC, 0x2F, 0x84, 0x8B, 0x00, 0xB8, 0x00, 0x12, 0xE0, 0x28, 0x40, 0x0E, 0x98, 0x20, 0x68, 0xEF, 0x36, 0xD0, 0xF1, 0x24, 0x8D, 0x7F, 0x81, 0x81, 0xBC, 0x80, 0xA2, 0xAD, 0x98, 0x4B, 0xBE, 0xEF, 0xE7, 0x1E, 0xC2, 0x65, 0x82, 0x9C, 0x37, 0xFF, 0x6C, 0x5E, 0x51, 0x9A, 0x76, 0x42, 0x2A, 0x80, 0x24, 0xC0, 0x0A, 0x10, 0x2F, 0x89, 0x46, 0x00, 0x6D, 0xB1, 0xF6, 0x7E, 0xC1, 0x3D, 0x15, 0x4F, 0x1B, 0x66, 0x80, 0x9F, 0x86, 0x01, 0x79, 0x76, 0xB3, 0xB9, 0x01, 0xAE, 0x73, 0x57, 0xAA, 0x98, 0xDD, 0xCC, 0x14, 0x00, 0x37, 0x24, 0x01, 0x95, 0x46, 0x02, 0x16, 0x80, 0x2B, 0x10, 0xD2, 0x28, 0xA0, 0x6E, 0xD0, 0x02, 0x43, 0x65, 0x6B, 0xA5, 0x89, 0xAC, 0xFE, 0x19, 0xD4, 0x56, 0xFD, 0x3A, 0xB1, 0x6E, 0x74, 0x86, 0xD5, 0xB2, 0x70, 0x7D, 0x41, 0x8B, 0xAD, 0xBE, 0x7D, 0x8D, 0x75, 0x1F, 0xF4, 0x5D, 0xF9, 0x94, 0x01, 0x23, 0x40, 0x6D, 0xC2, 0x04, 0xA8, 0xF3, 0x76, 0x9E, 0xB7, 0x4F, 0xB7, 0x38, 0xAC, 0x73, 0x39, 0x09, 0xC4, 0x01, 0x9E, 0x8E, 0xB9, 0xBF, 0x25, 0x1A, 0x7A, 0x00, 0x6E, 0x10, 0x4D, 0x33, 0xBF, 0xCA, 0xFE, 0x74, 0x1A, 0x4B, 0x5D, 0xCA, 0x0E, 0x68, 0xC3, 0x0A, 0xF0, 0xD3, 0x20, 0xC0, 0xBC, 0x11, 0x80, 0x1B, 0x50, 0xDC, 0x41, 0xCB, 0x6E, 0x60, 0xA7, 0x17, 0x34, 0x63, 0xD4, 0xDB, 0x0D, 0x55, 0xA0, 0x3E, 0x56, 0x7A, 0x27, 0xA7, 0x04, 0x05, 0x22, 0x9E, 0x92, 0x65, 0xA7, 0x35, 0xAD, 0x46, 0xF8, 0x2F, 0x61, 0x91, 0xCF, 0x88, 0x85, 0xB8, 0xB1, 0x8E, 0x4A, 0xA7, 0x00, 0xD1, 0x8E, 0x96, 0x5E, 0x55, 0xB3, 0x22, 0x3E, 0x42, 0x9D, 0xD6, 0xF2, 0x86, 0x00, 0x57, 0xE2, 0xA3, 0x8E, 0xD8, 0x15, 0x03, 0x2E, 0x80, 0x7A, 0x43, 0x00, 0x89, 0x09, 0x95, 0x46, 0x02, 0x16, 0x40, 0x18, 0x50, 0x36, 0x27, 0x15, 0x13, 0x35, 0xB4, 0xC1, 0xF3, 0x13, 0x33, 0x60, 0x37, 0x68, 0xD5, 0x1F, 0xA8, 0x65, 0x22, 0xF2, 0xB9, 0x54, 0x53, 0x61, 0x3C, 0x6F, 0x1C, 0xEE, 0x53, 0x74, 0x7D, 0xA8, 0xF2, 0x2F, 0xED, 0x6A, 0x72, 0x66, 0x43, 0x01, 0xEF, 0xA4, 0x1A, 0xF3, 0x1A, 0x91, 0xE5, 0x0D, 0x9D, 0xAD, 0x78, 0x69, 0xC0, 0xF4, 0x44, 0xB5, 0xD7, 0xBC, 0xA2, 0xBB, 0x09, 0x45, 0x19, 0x30, 0x03, 0x74, 0x1D, 0xB5, 0xCE, 0x85, 0xAF, 0x6B, 0x8E, 0x02, 0xF5, 0xEE, 0x5A, 0x80, 0xD0, 0xEA, 0x5A, 0x61, 0xC0, 0x03, 0x48, 0x05, 0xCA, 0xD6, 0xA2, 0xE4, 0x86, 0x36, 0x72, 0x8D, 0xD8, 0xEB, 0xA8, 0x49, 0x1F, 0x2F, 0x91, 0x02, 0x4A, 0xA6, 0xFA, 0xD6, 0x98, 0x12, 0xBC, 0x3A, 0xB2, 0x65, 0xF1, 0xC5, 0x8E, 0xC0, 0x5A, 0x21, 0x17, 0xD7, 0x85, 0x3C, 0xDF, 0x4B, 0x8D, 0x3A, 0x14, 0x1C, 0xAB, 0xE3, 0xA7, 0x00, 0xB1, 0xB9, 0x33, 0x13, 0x2D, 0x1F, 0xD0, 0xD8, 0x83, 0xB6, 0xFB, 0xEA, 0xF4, 0xFE, 0x5D, 0x09, 0x88, 0x0B, 0x01, 0xBC, 0x1A, 0x0A, 0x44, 0xF4, 0x32, 0x74, 0xC0, 0x74, 0x56, 0x38, 0xF9, 0x00, 0x92, 0x80, 0xE6, 0x92, 0xC5, 0xDB, 0x92, 0xC5, 0x67, 0x17, 0x0C, 0x74, 0xD5, 0x0D, 0x0C, 0x60, 0x5E, 0x1E, 0x02, 0xDA, 0x41, 0xA3, 0xEF, 0x88, 0x96, 0x9A, 0x43, 0xDA, 0x11, 0x0E, 0x91, 0x5F, 0x31, 0xA1, 0x79, 0xDF, 0x18, 0x67, 0x47, 0x92, 0x6F, 0xBD, 0x68, 0xAD, 0xC1, 0x48, 0xB9, 0x2A, 0x05, 0x52, 0xAB, 0xF7, 0x93, 0x1B, 0x05, 0x68, 0x36, 0xA4, 0x41, 0x80, 0xEB, 0xF4, 0xBB, 0x75, 0x5D, 0xFE, 0x43, 0x27, 0x1B, 0xDC, 0xFB, 0x3B, 0x01, 0x87, 0xC7, 0xB4, 0x54, 0xBA, 0x17, 0x85, 0x6C, 0xD0, 0x92, 0x17, 0xF0, 0xFA, 0x54, 0x40, 0xE9, 0xDC, 0x24, 0xD8, 0x00, 0xB9, 0xF0, 0x46, 0x34, 0x74, 0x42, 0x09, 0xF0, 0x9B, 0xBE, 0x85, 0x5B, 0x66, 0x10, 0xF9, 0x0B, 0x9A, 0x7C, 0x52, 0x2F, 0xFF, 0xF6, 0x36, 0x66, 0xEB, 0xB1, 0x53, 0x86, 0xFB, 0x82, 0xF7, 0x62, 0xC0, 0xFF, 0x70, 0x68, 0x7B, 0x00, 0xBC, 0xFE, 0xCC, 0x31, 0x38, 0x58, 0xFA, 0x19, 0xD0, 0x67, 0xA7, 0x51, 0x05, 0xA4, 0x03, 0x61, 0x40, 0x49, 0x6F, 0x2E, 0xF1, 0x16, 0xC5, 0x2B, 0x65, 0x74, 0x07, 0x3A, 0x9A, 0xCD, 0x15, 0x20, 0x6B, 0xAC, 0x4F, 0x72, 0x1A, 0x0E, 0x68, 0x02, 0x66, 0x80, 0x33, 0x10, 0x06, 0xE4, 0x01, 0x4A, 0xBA, 0x4D, 0xA5, 0x00, 0x96, 0x46, 0xFD, 0x6A, 0x53, 0x39, 0x80, 0x2B, 0x10, 0x02, 0xA4, 0x77, 0xCC, 0xE4, 0x05, 0x0B, 0x9E, 0x39, 0x78, 0x3A, 0x43, 0x71, 0x4E, 0x0B, 0x31, 0xD8, 0x52, 0x54, 0xB4, 0xE6, 0x08, 0xA5, 0x50, 0x95, 0x58, 0xAD, 0x9F, 0xAB, 0xA3, 0xC0, 0xF8, 0xA5, 0x7A, 0xC6, 0x6A, 0xF0, 0x6A, 0x28, 0x60, 0x09, 0x38, 0x01, 0x35, 0xCD, 0x4E, 0xF4, 0x89, 0x04, 0x2A, 0x5F, 0xA5, 0x08, 0x21, 0x3C, 0x80, 0x28, 0xA0, 0x02, 0x18, 0x03, 0xD9, 0xE1, 0xE5, 0x04, 0xCA, 0x3A, 0x76, 0x05, 0x64, 0xC7, 0x80, 0x74, 0x06, 0x46, 0x0D, 0xF0, 0x46, 0x12, 0x50, 0x17, 0x79, 0xBE, 0x93, 0xC4, 0x09, 0x80, 0x0F, 0x20, 0x0C, 0xA8, 0x01, 0x2E, 0x1D, 0x34, 0xBD, 0x41, 0xC3, 0xCC, 0x54, 0x2B, 0xE4, 0x1F, 0x89, 0x31, 0x0C, 0xC3, 0x0A, 0x23, 0x85, 0x9D, 0x3B, 0x95, 0x20, 0x28, 0x10, 0x85, 0x0C, 0xF1, 0x90, 0xFA, 0x76, 0x88, 0x7C, 0xD5, 0xA4, 0x02, 0x3C, 0x1B, 0x0E, 0xA8, 0xAC, 0xF3, 0xDA, 0x52, 0x6F, 0x7B, 0xDD, 0x14, 0xF4, 0x6C, 0x65, 0x39, 0x09, 0xD0, 0x69, 0x70, 0xA3, 0x00, 0x8E, 0xE9, 0xED, 0xC1, 0xEF, 0x25, 0x5C, 0x53, 0x15, 0xAF, 0x0C, 0x64, 0xAE, 0xC3, 0x46, 0x2C, 0xC3, 0x18, 0x07, 0xDC, 0x80, 0x38, 0x8D, 0xFC, 0xD1, 0x53, 0x74, 0x1C, 0xE0, 0x1B, 0x35, 0xFB, 0x7A, 0x3E, 0xBF, 0x58, 0xE8, 0xE9, 0xB6, 0xFF, 0x6F, 0x47, 0x44, 0xC9, 0x58, 0x2A, 0xF0, 0x77, 0x27, 0xFB, 0xC0, 0xA1, 0x48, 0x96, 0x91, 0x8D, 0x46, 0x59, 0x70, 0x0C, 0x93, 0x22, 0x5A, 0x25, 0x60, 0x6B, 0xAC, 0x39, 0xA7, 0xC4, 0xC0, 0x59, 0xF2, 0xB3, 0x92, 0xBF, 0x1C, 0x65, 0xBC, 0x76, 0x73, 0xA6, 0x65, 0x36, 0x6D, 0x80, 0x09, 0xC0, 0xCB, 0xE5, 0xF5, 0xC9, 0xA3, 0x62, 0xB5, 0xB4, 0xB0, 0xFF, 0xB2, 0xBA, 0x5A, 0x6F, 0x5F, 0x4E, 0x40, 0x6D, 0x61, 0x89, 0xBF, 0xC5, 0x01, 0x6D, 0x84, 0x76, 0xD4, 0x1C, 0x76, 0x64, 0x0A, 0xBD, 0x9A, 0x55, 0x8C, 0x94, 0x1A, 0xFB, 0x17, 0xAE, 0xEB, 0xDB, 0x17, 0x26, 0x2D, 0x2E, 0x60, 0x9A, 0x0D, 0xB3, 0x2F, 0x6A, 0x0A, 0x54, 0xAE, 0x3B, 0x7B, 0x36, 0xCE, 0xF2, 0x86, 0x94, 0x06, 0xFD, 0x9A, 0x20, 0xE2, 0x53, 0x51, 0x49, 0x02, 0xF0, 0x85, 0x36, 0xBC, 0x91, 0xB3, 0x47, 0xE8, 0x4C, 0xCF, 0x84, 0x37, 0x7E, 0xFD, 0xF5, 0x01, 0x1D, 0x5A, 0x2E, 0x09, 0x02, 0x68, 0xAC, 0x09, 0xF6, 0xDC, 0x48, 0x20, 0xB7, 0xED, 0x91, 0x4F, 0xDB, 0x23, 0xB6, 0x0E, 0x5A, 0xF4, 0x40, 0x87, 0x84, 0x40, 0x2D, 0xA7, 0xA4, 0xE3, 0x70, 0x57, 0x3C, 0x0A, 0x89, 0x8E, 0xE8, 0x69, 0x35, 0x99, 0xB1, 0x92, 0xB7, 0xEB, 0xF5, 0x79, 0x96, 0x02, 0x2F, 0x56, 0xEC, 0xB4, 0x56, 0xBF, 0x6C, 0x43, 0x0E, 0x90, 0x75, 0x25, 0xEF, 0x73, 0xA6, 0x40, 0x25, 0x10, 0x0C, 0x98, 0x02, 0xEA, 0x80, 0xC4, 0x9E, 0x35, 0xFD, 0x94, 0xDD, 0xB7, 0xF0, 0x32, 0x73, 0xB8, 0x5E, 0x40, 0xAD, 0x57, 0x32, 0x37, 0x8C, 0x01, 0x8F, 0x46, 0x2E, 0xF8, 0x44, 0x74, 0x94, 0x8F, 0x74, 0xD0, 0xB2, 0x47, 0xB9, 0xA3, 0xAB, 0x4C, 0x55, 0x46, 0x1E, 0x52, 0x12, 0xFD, 0xB2, 0xBD, 0xE0, 0xDC, 0x22, 0x3B, 0x79, 0x7B, 0x83, 0xB5, 0x27, 0xB4, 0x9F, 0xD9, 0x1D, 0x91, 0xBA, 0x66, 0x3C, 0xED, 0xC2, 0x94, 0x35, 0x86, 0x43, 0xA9, 0xBC, 0x91, 0x23, 0xA4, 0xB3, 0xB5, 0xC9, 0x72, 0x3E, 0x89, 0x44, 0xC0, 0x59, 0x56, 0xE0, 0x3C, 0x04, 0xF0, 0x74, 0x5E, 0x71, 0xD9, 0x5F, 0xCB, 0x0E, 0x10, 0x32, 0xCF, 0xFD, 0x72, 0x00, 0x33, 0x20, 0x79, 0x5A, 0xE9, 0x1C, 0x5A, 0xE8, 0xEF, 0xAC, 0xEA, 0x4F, 0x0D, 0xC9, 0x0E, 0x5A, 0x21, 0x5B, 0xEF, 0x81, 0x57, 0x65, 0xCF, 0x2B, 0x33, 0xA3, 0xAF, 0x4C, 0x40, 0x19, 0x2D, 0x72, 0xAB, 0x0F, 0x96, 0xDD, 0x9C, 0x8E, 0x8A, 0x54, 0xF2, 0xEE, 0xF8, 0xE1, 0x21, 0xAE, 0xCA, 0xE7, 0x3F, 0x54, 0x7C, 0xCF, 0x5D, 0x35, 0xF2, 0x89, 0x6E, 0x80, 0x16, 0xE0, 0x6F, 0x39, 0xDC, 0xF3, 0x37, 0xFD, 0x5D, 0x3B, 0xD1, 0xAB, 0x0C, 0xEC, 0x4F, 0x17, 0x7D, 0x2E, 0x3D, 0x01, 0xE4, 0x35, 0xEB, 0x69, 0xF9, 0x85, 0xDF, 0xB9, 0xFD, 0x31, 0x5F, 0xAA, 0xE4, 0x80, 0x08, 0x60, 0x0C, 0x78, 0x01, 0xE1, 0x40, 0x9E, 0x25, 0x85, 0x3C, 0x53, 0x11, 0x79, 0x18, 0xB8, 0xC9, 0x21, 0xFD, 0x6B, 0x32, 0x6E, 0xF3, 0x78, 0x83, 0x61, 0xF7, 0xF7, 0x78, 0x12, 0x53, 0x0F, 0xA8, 0x33, 0x3C, 0xE3, 0xC8, 0x4A, 0x32, 0x77, 0xC3, 0x2C, 0xEF, 0x2B, 0xFB, 0xB1, 0xD5, 0xC6, 0xB8, 0x8C, 0xFA, 0xF2, 0x00, 0xB6, 0x12, 0x82, 0xDB, 0x23, 0x3B, 0xEF, 0x83, 0x25, 0xCB, 0x8A, 0x30, 0x96, 0x3A, 0x3D, 0x15, 0xA8, 0x25, 0x67, 0xE7, 0xEC, 0x60, 0xDB, 0x53, 0xE5, 0x21, 0xE6, 0x7C, 0x55, 0x43, 0x40, 0x29, 0xE2, 0x4A, 0x01, 0x88, 0x01, 0xC6, 0x80, 0xE7, 0xD2, 0x58, 0x49, 0xA3, 0xE6, 0x3D, 0x81, 0x18, 0x60, 0x02, 0x44, 0x3A, 0x68, 0xEF, 0xAE, 0x0E, 0xFF, 0xA1, 0xA8, 0xAF, 0x85, 0x25, 0x08, 0x63, 0xCB, 0xBC, 0xB8, 0x4B, 0x40, 0x5D, 0x90, 0x52, 0xFE, 0xCE, 0x62, 0x1A, 0x31, 0x2A, 0xC5, 0x26, 0xFB, 0xD0, 0x21, 0x6F, 0xFE, 0xE6, 0xF4, 0xCB, 0xE1, 0x00, 0x8E, 0xAD, 0x4B, 0xA8, 0x00, 0xD7, 0xBE, 0xE4, 0x89, 0x0C, 0x7C, 0x4E, 0xD2, 0xF5, 0x68, 0x14, 0x10, 0x04, 0x64, 0xE3, 0xCD, 0xB0, 0x7D, 0x59, 0x9E, 0x27, 0xBD, 0x43, 0xD4, 0xDE, 0xB3, 0xD4, 0xE1, 0x3A, 0x0D, 0x59, 0x17, 0xA9, 0x64, 0xA0, 0xAA, 0xAF, 0x4E, 0x09, 0x90, 0x03, 0x6C, 0x6B, 0x6E, 0x76, 0x00, 0xD6, 0x08, 0xEE, 0xA8, 0x31, 0xCE, 0xC3, 0xC9, 0xFF, 0xE4, 0xD3, 0xFB, 0xD8, 0xBF, 0xF8, 0xB2, 0x58, 0x8E, 0x32, 0x5E, 0x64, 0xEF, 0x9A, 0xD9, 0x77, 0xF6, 0x80, 0xBA, 0xC9, 0xED, 0xD7, 0xEB, 0x93, 0xEF, 0x56, 0x35, 0xC5, 0x40, 0xE1, 0x13, 0x96, 0xAB, 0x6A, 0x10, 0xB3, 0xCF, 0xC9, 0xCE, 0x3C, 0x17, 0x57, 0xAD, 0x8A, 0x94, 0x15, 0x20, 0x0E, 0x90, 0x4F, 0x0B, 0xCD, 0x23, 0x40, 0xCA, 0x5F, 0x77, 0xBC, 0xBC, 0x4D, 0xCD, 0xCE, 0x6C, 0x9C, 0xE5, 0xE5, 0x0F, 0xE6, 0x7B, 0xFC, 0x7F, 0x01, 0x24, 0x0D, 0x02, 0xCE, 0xBA, 0xD8, 0xF2, 0x01, 0x54, 0x3B, 0x68, 0x02, 0x29, 0x85, 0xCA, 0xE7, 0x9C, 0xC0, 0x82, 0x81, 0xD9, 0x64, 0x8E, 0xC6, 0x9F, 0xF0, 0x36, 0xA1, 0xB5, 0x76, 0x9B, 0x0C, 0xDC, 0x1A, 0x4B, 0x67, 0x9B, 0x94, 0xAF, 0x3C, 0x64, 0x74, 0xD0, 0x32, 0xD6, 0x68, 0x1D, 0x06, 0xC4, 0x96, 0x73, 0x70, 0x23, 0xEB, 0xEF, 0xA5, 0xE8, 0xEF, 0xC0, 0x25, 0x0A, 0xDC, 0x4F, 0x9E, 0x0D, 0x6E, 0x04, 0x10, 0x04, 0xBC, 0xF0, 0x9E, 0xFC, 0xEB, 0x13, 0x90, 0xD7, 0x31, 0xC6, 0x07, 0xC8, 0x8E, 0x08, 0x33, 0xA0, 0x0A, 0xB8, 0xCD, 0x1D, 0xF2, 0xDE, 0xE3, 0x8E, 0x34, 0x0A, 0x20, 0x5D, 0x17, 0x7F, 0x01, 0xEC, 0x6E, 0x6A, 0x7D, 0x29, 0xE8, 0x1C, 0xF7, 0x91, 0xFC, 0xBA, 0x8D, 0xCB, 0x04, 0x0D, 0x79, 0x8C, 0xDE, 0x4F, 0x51, 0x46, 0xA2, 0x5C, 0xDB, 0xD4, 0x85, 0x7C, 0x56, 0xA4, 0x4E, 0xB3, 0x7C, 0x29, 0x3A, 0x82, 0xD7, 0xD8, 0xB2, 0x86, 0x35, 0xA4, 0x00, 0x6E, 0x88, 0x02, 0x75, 0xA6, 0x99, 0xB7, 0x5F, 0x5D, 0xCA, 0x59, 0xE3, 0x89, 0x62, 0x26, 0xB9, 0x29, 0x80, 0x6B, 0xAD, 0x13, 0xF3, 0xA1, 0xA5, 0x97, 0x81, 0xD4, 0xD5, 0xAE, 0x6E, 0x09, 0xA4, 0xCC, 0x8E, 0x50, 0x2A, 0x80, 0x1B, 0x92, 0x80, 0x06, 0x60, 0xBE, 0xB2, 0xA1, 0x8D, 0xBA, 0x4B, 0xED, 0x6F, 0x72, 0xC8, 0x77, 0x1B, 0x90, 0x0F, 0x5E, 0x78, 0x8D, 0x7A, 0x68, 0x9F, 0x55, 0xA4, 0x6B, 0xA0, 0x86, 0x76, 0x0C, 0x1F, 0x39, 0x35, 0x70, 0x1C, 0x3A, 0x42, 0xEF, 0x1E, 0x35, 0xD3, 0xB6, 0xC2, 0xAB, 0xEB, 0x29, 0x01, 0x5E, 0xCD, 0x89, 0x1C, 0xB3, 0x73, 0x2C, 0x0F, 0x10, 0x06, 0x88, 0x02, 0xDC, 0x10, 0x07, 0x34, 0x81, 0xD7, 0x48, 0xFD, 0x1A, 0x8B, 0x69, 0xCE, 0xB5, 0xBF, 0x8E, 0x8F, 0xD6, 0x17, 0x56, 0x2A, 0xC0, 0x1C, 0xC8, 0xF6, 0xAE, 0x3B, 0x0E, 0x50, 0x83, 0x0D, 0x10, 0x5D, 0x86, 0x76, 0x09, 0xB8, 0x01, 0xC9, 0x1D, 0x34, 0x7F, 0x41, 0xCB, 0xFF, 0x50, 0xFF, 0xAC, 0x87, 0x14, 0x2F, 0xCE, 0xF8, 0xEE, 0x9F, 0x04, 0x0F, 0xB8, 0x82, 0xF5, 0x90, 0x5A, 0xCE, 0x8E, 0x59, 0xD9, 0xCD, 0x2B, 0xB5, 0x0C, 0xAD, 0x5C, 0x00, 0x3B, 0x4B, 0xAB, 0x9C, 0xB3, 0x63, 0x36, 0x65, 0x9E, 0x8B, 0xED, 0x76, 0x2B, 0x5F, 0xF0, 0xAC, 0x68, 0xB9, 0x02, 0x31, 0xA6, 0x87, 0xCA, 0xEB, 0x48, 0x7E, 0x23, 0x06, 0xEE, 0x56, 0xA7, 0xCF, 0x2F, 0x77, 0x4A, 0x23, 0x29, 0x00, 0x2D, 0x20, 0x04, 0xA8, 0xBD, 0xF0, 0x18, 0xE0, 0x86, 0x08, 0xA0, 0x0D, 0x6B, 0x78, 0x75, 0xD4, 0xE2, 0x45, 0xCD, 0x71, 0x2E, 0x19, 0xE2, 0xA1, 0x13, 0x81, 0xB2, 0x58, 0x6B, 0x88, 0xD8, 0x18, 0xBF, 0x6C, 0x50, 0x97, 0xA4, 0xB6, 0x1F, 0xCC, 0xF9, 0xFF, 0xD0, 0xF2, 0xB3, 0x8D, 0x00, 0xBC, 0xD1, 0xB1, 0x60, 0x9D, 0x3A, 0x8F, 0xFC, 0x25, 0xAE, 0x0F, 0x05, 0x92, 0x1B, 0xF5, 0x57, 0x9D, 0xB1, 0xD7, 0xE5, 0xFF, 0xCA, 0x32, 0xEF, 0xB8, 0xAB, 0xF3, 0x1E, 0x19, 0xBA, 0x06, 0x0B, 0xE9, 0x1A, 0x02, 0x94, 0xAB, 0x43, 0x8A, 0x7F, 0x75, 0x48, 0x1D, 0xA0, 0xA8, 0xA3, 0xF6, 0xD7, 0x67, 0xFC, 0xE5, 0x9E, 0x63, 0x5C, 0xA5, 0x0A, 0x2E, 0x3A, 0x71, 0xC2, 0xD1, 0x76, 0x44, 0x6D, 0x50, 0xA8, 0xBD, 0xC6, 0x7E, 0x16, 0xDA, 0x8F, 0x02, 0xD1, 0xC8, 0x00, 0x62, 0x75, 0x6C, 0x4B, 0x02, 0xEC, 0x8D, 0x04, 0xC2, 0xFE, 0x44, 0xE0, 0xFA, 0x84, 0x75, 0xC4, 0x3F, 0x06, 0x4B, 0xA6, 0xCD, 0x6F, 0x91, 0x0F, 0xFE, 0xE7, 0x83, 0x5C, 0x7F, 0x69, 0x6A, 0x7B, 0x66, 0x98, 0xEC, 0x40, 0xE8, 0x52, 0xC7, 0x2B, 0xA0, 0x0C, 0xD8, 0x45, 0x01, 0x6E, 0x40, 0x30, 0x90, 0x32, 0x95, 0xCF, 0xE7, 0x06, 0xAD, 0x50, 0x61, 0x0C, 0x43, 0x3A, 0xAD, 0xF2, 0xAB, 0x49, 0x59, 0xAB, 0x4B, 0x8B, 0x90, 0xB7, 0x55, 0x67, 0x6C, 0xB7, 0xE9, 0x28, 0xA0, 0x10, 0x4F, 0xB3, 0x7D, 0x5A, 0xE2, 0xA1, 0x2B, 0x6F, 0xAF, 0x35, 0xD1, 0x4F, 0x1A, 0x27, 0x3A, 0x30, 0x04, 0x58, 0x35, 0x56, 0xE5, 0xEF, 0x4E, 0xB8, 0xCB, 0x37, 0x2A, 0x71, 0xED, 0x71, 0xDC, 0xC8, 0x35, 0x9E, 0xC6, 0xA7, 0x6B, 0x42, 0xE4, 0xF9, 0x9B, 0x87, 0x2F, 0xEF, 0x51, 0xE4, 0x86, 0x3B, 0x90, 0xD1, 0x01, 0x3D, 0x00, 0xC7, 0x7A, 0x07, 0x48, 0xA3, 0x00, 0x93, 0x46, 0x02, 0xAE, 0xC0, 0x4D, 0x45, 0xDA, 0x19, 0x1D, 0xED, 0xE6, 0x39, 0x87, 0x19, 0xB7, 0x21, 0x75, 0x42, 0x0E, 0x13, 0x87, 0xDA, 0xE5, 0x4A, 0x7C, 0x5A, 0xF7, 0xF1, 0x7E, 0x81, 0x56, 0xAE, 0x17, 0xA8, 0xCF, 0x4F, 0x3F, 0x97, 0x9A, 0x8C, 0xEF, 0x44, 0xAA, 0x6D, 0x5E, 0xC9, 0x0D, 0xA0, 0x04, 0x4E, 0xAD, 0x57, 0xC2, 0x88, 0x6F, 0xFC, 0xBD, 0x39, 0xE3, 0x4F, 0x17, 0x5F, 0x58, 0x16, 0x8C, 0x9B, 0xCB, 0xBC, 0x59, 0xF5, 0x25, 0x8A, 0x1D, 0xB0, 0x03, 0x38, 0xFF, 0x6A, 0x2B, 0xCB, 0x4E, 0x65, 0x32, 0xC0, 0x0A, 0x48, 0x76, 0xD4, 0x68, 0xB6, 0xE4, 0x9D, 0xFA, 0x84, 0x30, 0xD9, 0x26, 0xAE, 0x42, 0x89, 0xC7, 0x9A, 0x71, 0x56, 0x93, 0xE2, 0x76, 0x77, 0x8C, 0x29, 0xEE, 0x8B, 0xA5, 0x1E, 0xD2, 0x9A, 0x32, 0xF7, 0x28, 0xC0, 0x03, 0x50, 0x06, 0x28, 0xD7, 0xD8, 0xDB, 0xFE, 0x16, 0xBB, 0x8B, 0x6B, 0x39, 0x89, 0x56, 0x00, 0x21, 0x80, 0xE7, 0xB2, 0x17, 0xED, 0x93, 0x9B, 0xCC, 0xD1, 0x06, 0xF2, 0x4E, 0xA1, 0xDC, 0x87, 0x7C, 0xCD, 0xD9, 0x99, 0xC7, 0x0E, 0x58, 0x01, 0xE9, 0xFD, 0x02, 0x35, 0x80, 0x62, 0xBD, 0x40, 0x03, 0xD0, 0x58, 0x2F, 0xD0, 0x98, 0x2F, 0x50, 0xE3, 0xF1, 0x02, 0x35, 0x8A, 0x31, 0x97, 0x57, 0xD4, 0xA1, 0x75, 0x8A, 0xC4, 0xAC, 0xC8, 0x3B, 0x81, 0x4B, 0x68, 0x68, 0x39, 0x4C, 0xF7, 0x52, 0x2B, 0x9D, 0xCA, 0x51, 0xAF, 0x1F, 0x9E, 0x30, 0xA4, 0x6B, 0x04, 0xD7, 0x32, 0x73, 0x4D, 0x9F, 0x4F, 0xAD, 0xCA, 0x1C, 0x64, 0x5D, 0x36, 0x95, 0xF7, 0xD4, 0xB0, 0x5E, 0x86, 0x52, 0x4F, 0x76, 0x34, 0x2F, 0xFF, 0x39, 0xDA, 0x1A, 0x91, 0x07, 0x1E, 0xDD, 0x28, 0xC9, 0xBD, 0x1A, 0x05, 0x20, 0x03, 0x58, 0x01, 0x71, 0x40, 0x0D, 0xB0, 0x02, 0x3C, 0x80, 0xB4, 0x8E, 0x9A, 0xBC, 0xA8, 0x65, 0x42, 0x40, 0x1A, 0x89, 0xA2, 0x9D, 0x7D, 0x3B, 0xBA, 0xB6, 0xB5, 0x8F, 0x63, 0xCC, 0x42, 0x26, 0x9A, 0x54, 0xB3, 0xE6, 0x60, 0x07, 0xDB, 0x46, 0x00, 0xF7, 0xED, 0xE6, 0x73, 0xC5, 0x1D, 0x9D, 0xED, 0xC3, 0xCF, 0x50, 0x52, 0x81, 0x38, 0x8D, 0xEA, 0x50, 0x34, 0x4C, 0x00, 0xDE, 0x3A, 0xF1, 0xFB, 0xC9, 0x66, 0x78, 0x45, 0xEE, 0x04, 0x92, 0x61, 0x6C, 0xAD, 0xEF, 0xB2, 0xD8, 0xCF, 0xE7, 0x43, 0xDD, 0x04, 0x88, 0x00, 0x79, 0x6B, 0x37, 0x01, 0x30, 0x03, 0xA2, 0x80, 0x1A, 0x60, 0x09, 0x84, 0xCE, 0xC2, 0xC3, 0xF1, 0x0E, 0x9A, 0xFE, 0x93, 0x7E, 0x30, 0x3B, 0x76, 0x63, 0x57, 0x4B, 0x33, 0xBC, 0x99, 0x0F, 0xB7, 0x39, 0x98, 0xA2, 0xC0, 0x99, 0xCB, 0x72, 0xE2, 0x06, 0x8D, 0x68, 0xB6, 0xF5, 0xD7, 0x59, 0x23, 0xDA, 0xB3, 0x61, 0xF3, 0x13, 0x37, 0xDE, 0xF0, 0x79, 0x1D, 0xC5, 0x62, 0x28, 0xDA, 0x71, 0x7D, 0x16, 0x60, 0xDE, 0x66, 0xFC, 0x59, 0x53, 0x95, 0x01, 0x37, 0xD7, 0x51, 0x02, 0x84, 0x03, 0x7E, 0x00, 0xA3, 0x06, 0x2F, 0x14, 0x10, 0xB9, 0x8C, 0xE3, 0xAB, 0x91, 0x0D, 0xD9, 0x76, 0x3A, 0x8D, 0x00, 0xF4, 0xAE, 0x34, 0xDB, 0xCE, 0xD4, 0x43, 0xA8, 0x66, 0x42, 0x3D, 0xC3, 0x85, 0x70, 0xE2, 0xB9, 0x32, 0x50, 0x3D, 0xB3, 0x54, 0x60, 0xCD, 0xF4, 0xED, 0xAD, 0x69, 0x80, 0x6F, 0xB1, 0xD5, 0x01, 0x44, 0x1B, 0xB9, 0x84, 0xA4, 0xF9, 0x12, 0xB1, 0x4F, 0xFB, 0x82, 0xF4, 0xCA, 0x72, 0xFE, 0x8E, 0x5C, 0x89, 0x22, 0x9A, 0x56, 0x6C, 0x7C, 0x56, 0x51, 0xFD, 0xA2, 0x00, 0x6B, 0xB8, 0x03, 0xD1, 0xC8, 0xBA, 0x4F, 0xF2, 0xAA, 0xA6, 0x1B, 0xC0, 0xD4, 0x28, 0x40, 0x4F, 0xC3, 0x01, 0xD7, 0x8E, 0x1A, 0x14, 0x1B, 0x75, 0xF2, 0xFF, 0x2E, 0x35, 0x69, 0xED, 0x42, 0x38, 0x77, 0x0A, 0xCA, 0xD1, 0x96, 0x2F, 0x3E, 0x4D, 0xD0, 0x79, 0x6B, 0xAE, 0x02, 0xC8, 0xD5, 0x93, 0x5E, 0xD9, 0xE0, 0xD5, 0x5B, 0x97, 0x40, 0x0C, 0xD5, 0xF7, 0xCB, 0x67, 0xF8, 0xEB, 0x01, 0xE3, 0x02, 0x52, 0xE6, 0xEE, 0x72, 0xED, 0xE1, 0xAC, 0x21, 0x0A, 0x70, 0x34, 0xB2, 0x61, 0x0D, 0x07, 0x44, 0x1B, 0x05, 0x18, 0x03, 0xD1, 0x28, 0x7F, 0x4E, 0xE3, 0x80, 0x36, 0x6C, 0x82, 0x09, 0x10, 0x03, 0x2C, 0x3B, 0x68, 0xF1, 0x73, 0xA9, 0x41, 0x3E, 0x94, 0x84, 0x63, 0x8D, 0x79, 0xDB, 0x1B, 0x39, 0x36, 0x64, 0x3D, 0x43, 0x73, 0xE5, 0xFE, 0xD3, 0x7D, 0xC8, 0x6B, 0xD9, 0xB8, 0x28, 0x10, 0xD6, 0x18, 0x31, 0x94, 0x7B, 0x7A, 0x78, 0x6A, 0xE3, 0xE4, 0xA1, 0xE0, 0x81, 0x84, 0x79, 0xE4, 0x20, 0x98, 0x1A, 0x0A, 0xC8, 0x01, 0x8C, 0x00, 0x77, 0x20, 0x12, 0x48, 0x5F, 0x66, 0x7C, 0x06, 0x10, 0x2D, 0xB9, 0x81, 0x03, 0x5A, 0x80, 0x09, 0xE0, 0xA7, 0x11, 0x40, 0x18, 0x90, 0x09, 0x94, 0x74, 0x28, 0xA9, 0xA3, 0xF6, 0xD6, 0x18, 0xEA, 0xF5, 0x0A, 0x3F, 0x9D, 0xEF, 0x2C, 0x6B, 0x82, 0x7D, 0x0C, 0x67, 0x66, 0xC6, 0x4F, 0x15, 0xC6, 0xE5, 0x9B, 0x0C, 0x51, 0xDA, 0x19, 0x22, 0x96, 0x29, 0xBA, 0xBA, 0xA9, 0x21, 0x59, 0xDA, 0x2B, 0xB1, 0x06, 0x03, 0x4A, 0x73, 0xF4, 0xF3, 0x3D, 0x3D, 0xBC, 0x0B, 0xA1, 0x70, 0x47, 0x64, 0xBD, 0xF9, 0x98, 0x1B, 0x35, 0x7F, 0x6B, 0xCF, 0xF7, 0xE6, 0xC3, 0xAE, 0x9F, 0x40, 0xDC, 0x43, 0x04, 0x03, 0x26, 0x80, 0x3B, 0x90, 0x02, 0xD4, 0x35, 0x8B, 0x97, 0x46, 0x02, 0x2C, 0x80, 0x10, 0xA0, 0x17, 0x05, 0xF8, 0x01, 0xE2, 0x06, 0xAD, 0xFA, 0xC5, 0x65, 0xD3, 0xAF, 0x83, 0xB1, 0xD4, 0x24, 0xA4, 0x65, 0x4E, 0x85, 0x4C, 0x14, 0x25, 0x7E, 0x67, 0xA3, 0xE9, 0xB7, 0xBF, 0xE7, 0xDA, 0x67, 0x87, 0xE2, 0x28, 0x50, 0xB4, 0x86, 0x5A, 0x17, 0x50, 0xA7, 0x31, 0x2C, 0x70, 0x3A, 0xC3, 0xF3, 0x94, 0xC1, 0xEF, 0x4E, 0xED, 0xCF, 0xC5, 0x51, 0x4E, 0xA3, 0x1A, 0xDE, 0x50, 0x40, 0x1D, 0x30, 0x05, 0xFC, 0xA2, 0x80, 0x08, 0x20, 0x0D, 0x28, 0x5E, 0xEE, 0x8F, 0x09, 0x08, 0x37, 0x12, 0x50, 0x03, 0x8C, 0x1A, 0xB9, 0xD6, 0x9D, 0x02, 0x57, 0xA9, 0x76, 0x0F, 0x7A, 0xB4, 0x37, 0x35, 0xDC, 0x3F, 0x2D, 0xAB, 0xBB, 0x14, 0xAC, 0xE7, 0x50, 0x08, 0x84, 0xEF, 0x08, 0x9A, 0xC7, 0x9E, 0xEC, 0x70, 0x6A, 0x09, 0x49, 0xB7, 0xCB, 0x92, 0xAC, 0xC7, 0x93, 0xE7, 0x94, 0x4B, 0xE6, 0xBF, 0x52, 0x7B, 0x22, 0xD8, 0xB8, 0x52, 0xAF, 0xD7, 0x9A, 0xDE, 0x4F, 0x67, 0x3A, 0xC8, 0x9D, 0x33, 0x2D, 0x82, 0x9C, 0x01, 0xAB, 0x86, 0x34, 0xA8, 0xE1, 0x3F, 0xAC, 0x85, 0x92, 0xE7, 0x9B, 0x80, 0xB8, 0xA1, 0x0D, 0x69, 0x50, 0x43, 0x01, 0x6E, 0x68, 0x74, 0xD0, 0xA8, 0xAF, 0x65, 0xB0, 0x57, 0xD6, 0xCA, 0xA9, 0xBE, 0x65, 0xEA, 0x74, 0x00, 0x62, 0x67, 0x5E, 0x78, 0x00, 0x7B, 0xA5, 0xD1, 0x2E, 0xE5, 0x9D, 0x5C, 0xCD, 0x2B, 0xF7, 0x7C, 0xE1, 0x4B, 0x84, 0x7B, 0x80, 0xA0, 0x89, 0xBA, 0x65, 0x84, 0xD1, 0x8F, 0x58, 0x78, 0xDF, 0x8E, 0x5E, 0x1D, 0x27, 0x40, 0x0D, 0x10, 0x07, 0xB8, 0xF1, 0xB4, 0x9F, 0xD9, 0x7B, 0xE1, 0xBD, 0x32, 0xBE, 0xF9, 0x14, 0xF3, 0x62, 0x1E, 0x3A, 0xCB, 0x26, 0x4C, 0x80, 0x3A, 0xE0, 0xD4, 0x88, 0x46, 0x4D, 0xC4, 0x01, 0x92, 0xFA, 0x3D, 0x54, 0x1D, 0x34, 0x1E, 0xB3, 0x7D, 0x3C, 0xEB, 0xBB, 0xB4, 0x93, 0x15, 0xCC, 0x87, 0xC4, 0x5B, 0x15, 0x98, 0x1F, 0x0E, 0x33, 0xCC, 0x05, 0xD5, 0xF1, 0x78, 0xEE, 0x95, 0x46, 0x6B, 0x4F, 0x0B, 0x9E, 0x6D, 0x52, 0x76, 0x56, 0x4A, 0x31, 0x1A, 0x3E, 0xFD, 0xBC, 0x6E, 0x0D, 0x45, 0xCF, 0x33, 0x8E, 0x9E, 0x2E, 0x83, 0x42, 0x8D, 0x04, 0xD4, 0x01, 0x33, 0x20, 0xF3, 0x2F, 0xC9, 0x1A, 0xAF, 0x59, 0x9F, 0xEF, 0xA0, 0xA2, 0x86, 0x3A, 0xE0, 0x05, 0xA4, 0xF7, 0xEE, 0xA7, 0x00, 0x25, 0xC0, 0x06, 0x08, 0x01, 0xCA, 0x80, 0x1D, 0xC0, 0x1B, 0xD1, 0x48, 0xED, 0xA0, 0xC9, 0x0B, 0x1A, 0x7F, 0xD7, 0xE4, 0xD9, 0xBC, 0x42, 0x71, 0x4D, 0x02, 0xE5, 0x03, 0x4B, 0xE0, 0xF5, 0xC9, 0x36, 0xF2, 0xB7, 0xF1, 0x82, 0xA6, 0xD3, 0x3C, 0xA1, 0x78, 0x9D, 0x6B, 0xB7, 0x8B, 0x79, 0x4D, 0x2F, 0x34, 0xE1, 0x8E, 0x72, 0xDC, 0xC7, 0x73, 0xA5, 0x2A, 0xB2, 0xD6, 0xD8, 0x98, 0xF3, 0xC3, 0x4B, 0xE3, 0x55, 0x7D, 0x87, 0x58, 0x0F, 0xF1, 0xC1, 0x2F, 0x68, 0xF3, 0x45, 0x90, 0xDC, 0xB7, 0x80, 0x06, 0x2B, 0x20, 0x09, 0x68, 0x00, 0x46, 0x8D, 0x02, 0x3C, 0x81, 0x88, 0x75, 0x91, 0xBF, 0x2B, 0x4D, 0x5F, 0xD0, 0x70, 0xF7, 0x88, 0xE1, 0x78, 0x98, 0xE2, 0xAD, 0x2E, 0xB5, 0x46, 0xE2, 0xA8, 0xDA, 0x07, 0xB5, 0xDA, 0x63, 0x3F, 0x0F, 0x03, 0xB5, 0x5B, 0x89, 0xAB, 0x71, 0x00, 0xF3, 0x06, 0x35, 0x74, 0xA6, 0x61, 0x6B, 0x34, 0x44, 0x63, 0x7C, 0xE2, 0xD4, 0xA0, 0x78, 0x00, 0xD1, 0x48, 0x03, 0xCA, 0xA6, 0xEB, 0x46, 0xDE, 0xAB, 0x41, 0x07, 0x34, 0x6A, 0xD6, 0x9F, 0x22, 0x81, 0xF2, 0x39, 0x75, 0x86, 0x0B, 0x50, 0x05, 0x8C, 0x1B, 0x05, 0x78, 0x02, 0x61, 0x40, 0xDA, 0x2A, 0xC1, 0xDC, 0xA0, 0xD9, 0xA8, 0xAF, 0xD4, 0xE1, 0x61, 0x82, 0x1E, 0xDE, 0xED, 0x8B, 0x94, 0x5D, 0x94, 0x4A, 0x5C, 0xBC, 0x7D, 0xA6, 0x85, 0x8C, 0xB6, 0x10, 0x66, 0xB5, 0x42, 0x25, 0x01, 0x21, 0x80, 0x05, 0xA0, 0xDA, 0xA0, 0xBF, 0x48, 0xCA, 0xCB, 0x07, 0x51, 0x4D, 0x6F, 0xB0, 0x54, 0xC0, 0xB3, 0x61, 0x40, 0xD4, 0xCF, 0x44, 0xC7, 0xF9, 0x3B, 0xDA, 0xFB, 0x3A, 0x99, 0x7D, 0xC7, 0x4D, 0x20, 0x79, 0x7A, 0x21, 0xA8, 0x00, 0xCE, 0x40, 0x28, 0x90, 0x8D, 0x5A, 0x55, 0x04, 0x3E, 0x80, 0x08, 0xA0, 0xDE, 0x41, 0xF3, 0x0E, 0x53, 0x3F, 0xDC, 0xE9, 0x37, 0x84, 0x70, 0xA8, 0x4E, 0x82, 0x2D, 0xB2, 0x56, 0xEB, 0x4A, 0x02, 0x0B, 0x14, 0x63, 0x05, 0x4B, 0x76, 0x6F, 0x99, 0xD0, 0x5F, 0x77, 0x29, 0x45, 0x27, 0xA7, 0xAC, 0x1F, 0x90, 0xC2, 0xFE, 0x23, 0x07, 0x9F, 0xE4, 0xAA, 0xF5, 0xAA, 0x8F, 0x48, 0xF7, 0x5E, 0xED, 0x7D, 0x7C, 0xEA, 0x03, 0xDA, 0xD3, 0xE0, 0x9D, 0x77, 0x66, 0x90, 0x3F, 0x2F, 0x84, 0x7A, 0xD5, 0xE5, 0x37, 0xE6, 0xF1, 0x7A, 0x7E, 0x9C, 0x79, 0x05, 0x71, 0x5D, 0xD3, 0x71, 0x2E, 0xA4, 0x61, 0x80, 0xC6, 0xEC, 0xA8, 0xA4, 0x58, 0xCE, 0x8A, 0xAB, 0xD9, 0x57, 0x47, 0xC2, 0x40, 0x9E, 0xF7, 0xED, 0xEC, 0xF1, 0x49, 0x04, 0x66, 0x38, 0xA2, 0x7B, 0x4F, 0xCD, 0xEE, 0x42, 0x81, 0x87, 0xB5, 0x37, 0x65, 0x0F, 0x93, 0xDA, 0x29, 0x35, 0x1E, 0x47, 0xD6, 0xB7, 0x85, 0xD7, 0x53, 0x33, 0x9A, 0x03, 0xF7, 0x74, 0x9A, 0x1D, 0xD7, 0x73, 0x6F, 0xE7, 0xE3, 0xEA, 0xCD, 0xCF, 0xE4, 0xDB, 0xF3, 0x25, 0xCA, 0xA0, 0x22, 0xF9, 0x7B, 0x74, 0xED, 0x95, 0x12, 0xEC, 0xCC, 0xEB, 0xAD, 0x2C, 0x7D, 0x92, 0x1A, 0x20, 0x0C, 0x70, 0x4C, 0xC8, 0x01, 0x4C, 0x66, 0xC2, 0x89, 0x1B, 0x14, 0xFD, 0xC5, 0x86, 0xFB, 0x0C, 0xAF, 0xBF, 0x13, 0xD2, 0x0D, 0x5A, 0xBE, 0xA0, 0xD5, 0x27, 0x16, 0xFD, 0xD3, 0xE0, 0x7E, 0x8D, 0x37, 0x86, 0x7D, 0x3C, 0x05, 0x7F, 0x15, 0x61, 0xF4, 0x77, 0xFF, 0xEA, 0x2D, 0x9B, 0x3E, 0x1B, 0xF8, 0x75, 0x6D, 0x8E, 0xB6, 0x23, 0xC2, 0x27, 0xA0, 0x43, 0x98, 0xCF, 0xC8, 0x4A, 0x3B, 0x22, 0xBC, 0x46, 0xED, 0x4A, 0x07, 0x86, 0x3B, 0x14, 0xB2, 0xAA, 0x31, 0x41, 0x80, 0x32, 0x20, 0x04, 0x58, 0xE3, 0xF9, 0x37, 0x54, 0x23, 0x7F, 0x80, 0x08, 0x10, 0x5E, 0xD7, 0xBD, 0x5D, 0xD6, 0x58, 0xBD, 0xA9, 0xBC, 0xDA, 0xCA, 0xCB, 0x6E, 0xD0, 0xEA, 0x05, 0x2D, 0x3E, 0x51, 0x83, 0x8D, 0xA0, 0x85, 0x33, 0x32, 0xFA, 0xA9, 0x7D, 0x4B, 0x14, 0xCC, 0x73, 0x4C, 0xC6, 0xF9, 0x6C, 0x9F, 0xD3, 0x64, 0xCC, 0x59, 0x20, 0x7A, 0x2F, 0x3C, 0xA7, 0x3F, 0x89, 0x85, 0xBE, 0x5C, 0xC4, 0xD3, 0x8D, 0xE1, 0x69, 0x33, 0xFE, 0x93, 0xCF, 0xC7, 0x1B, 0x15, 0xB7, 0xE7, 0x46, 0x9D, 0x33, 0x33, 0x71, 0xD1, 0xA0, 0x33, 0x8D, 0x73, 0xD3, 0xA6, 0x1B, 0x2A, 0x6B, 0x83, 0x00, 0xCA, 0x09, 0xA6, 0x99, 0x72, 0x09, 0x5F, 0x99, 0x05, 0x01, 0x42, 0xD7, 0x18, 0x8A, 0x58, 0x73, 0xE4, 0xB3, 0x83, 0xF6, 0x2A, 0x77, 0x0F, 0x43, 0x8B, 0xAB, 0xE9, 0xC8, 0x96, 0x5A, 0xBB, 0xB7, 0x2A, 0xA1, 0x11, 0x34, 0x6D, 0xA8, 0x6E, 0x4D, 0xD6, 0xAC, 0xB7, 0x57, 0x7E, 0xCC, 0x75, 0xD0, 0x3A, 0x37, 0x5A, 0xF1, 0xDA, 0x2D, 0x31, 0x03, 0xE7, 0x6F, 0x70, 0x85, 0xAD, 0x71, 0xB1, 0xF2, 0x1E, 0x09, 0x3D, 0xD3, 0xD6, 0x8A, 0xB3, 0x21, 0x00, 0x69, 0xC3, 0x00, 0x6D, 0x94, 0x6E, 0xD3, 0xCE, 0x06, 0x2F, 0xAC, 0x87, 0x2E, 0x6B, 0xFA, 0x1F, 0x3D, 0x91, 0xDD, 0xD6, 0x71, 0x8E, 0xB7, 0x18, 0xAE, 0x07, 0x1D, 0x34, 0xEA, 0x68, 0xF5, 0xCE, 0xCD, 0xF4, 0xA9, 0x49, 0x5D, 0x61, 0x0C, 0x10, 0x65, 0x30, 0x88, 0x16, 0x83, 0xB6, 0x93, 0xB9, 0x25, 0x4F, 0x32, 0x5E, 0x04, 0x61, 0x6B, 0xB0, 0x83, 0xDC, 0xA0, 0x09, 0xF5, 0x41, 0x2B, 0xA7, 0x04, 0xC0, 0x14, 0xB8, 0xA5, 0xDB, 0x60, 0x40, 0x02, 0xB0, 0xBB, 0x26, 0x13, 0x90, 0x0E, 0xB6, 0xDC, 0x63, 0x45, 0x42, 0x79, 0x30, 0x06, 0x69, 0xDB, 0xEB, 0x94, 0x7F, 0xA6, 0x15, 0xB6, 0x1E, 0x2C, 0x9B, 0x61, 0xA2, 0x68, 0x48, 0xC3, 0xD6, 0xE3, 0xE9, 0x73, 0xEB, 0x4F, 0xD9, 0x9B, 0xD9, 0x7A, 0x3C, 0x0F, 0x50, 0x7C, 0x83, 0xC6, 0x7B, 0x89, 0xE1, 0x02, 0xDB, 0x83, 0xB4, 0x33, 0x08, 0x86, 0x33, 0x2D, 0x1E, 0x62, 0x21, 0xDC, 0x8D, 0xED, 0xCC, 0xA0, 0xF1, 0x78, 0x3C, 0xAF, 0x11, 0x37, 0xC9, 0xBB, 0x01, 0xE7, 0x9D, 0x5B, 0x97, 0x57, 0x04, 0xD7, 0x48, 0xC0, 0x14, 0xD0, 0x03, 0x5C, 0xDD, 0x3E, 0x5B, 0xE3, 0x95, 0x35, 0xFA, 0xAE, 0xD3, 0xE1, 0xB5, 0x7A, 0x52, 0xEE, 0x67, 0xEB, 0xA2, 0xAF, 0x71, 0xD4, 0x1A, 0x47, 0x66, 0x8D, 0x82, 0x6B, 0x3D, 0x9E, 0x36, 0x21, 0xBA, 0xF6, 0x34, 0xDE, 0xCA, 0xCD, 0x15, 0xFA, 0x9A, 0x0B, 0x2E, 0xDF, 0xE3, 0x29, 0x3B, 0x68, 0x10, 0xEF, 0xA8, 0x7F, 0xDD, 0xB3, 0x9C, 0x06, 0xE1, 0x9D, 0x6A, 0xA7, 0x47, 0x09, 0xFD, 0x08, 0xC7, 0x70, 0x98, 0x5D, 0x43, 0x05, 0x75, 0x4C, 0xE2, 0xBF, 0xD7, 0x3D, 0xB6, 0xBE, 0xAB, 0xF4, 0x75, 0x46, 0x3A, 0xED, 0x23, 0xB8, 0xDA, 0xE3, 0x93, 0x02, 0x7E, 0x00, 0x61, 0x7C, 0x67, 0xF5, 0x51, 0xC7, 0xAD, 0x97, 0x3D, 0x42, 0xF7, 0x52, 0x1E, 0x75, 0xF5, 0x41, 0xF6, 0x4E, 0x6B, 0xB0, 0x48, 0x9D, 0xD6, 0xC3, 0xEC, 0x73, 0x4F, 0xD2, 0x03, 0x70, 0x36, 0xF4, 0x7F, 0x3C, 0x9D, 0x01, 0x9C, 0xE5, 0x01, 0xE7, 0xB4, 0x8E, 0x93, 0xF7, 0x3B, 0x5F, 0xCC, 0xF4, 0x5F, 0x7E, 0x81, 0xA4, 0xBF, 0x98, 0x59, 0x15, 0x2C, 0x84, 0x5D, 0x09, 0x8F, 0x5A, 0x17, 0x09, 0x58, 0x12, 0xC7, 0x34, 0x4D, 0xCC, 0x15, 0x5F, 0xB9, 0x47, 0xD3, 0x3F, 0xF3, 0x8F, 0x9B, 0xA8, 0x61, 0xEB, 0x8B, 0x5D, 0xF6, 0x27, 0xD4, 0x3D, 0x80, 0x03, 0xA8, 0x01, 0x27, 0xF0, 0x2D, 0x49, 0x00, 0x96, 0x62, 0xF4, 0xE9, 0xCE, 0xDE, 0xFD, 0xE5, 0x69, 0xEB, 0xFE, 0xDC, 0xEE, 0xEF, 0x34, 0xE3, 0x1C, 0x5D, 0xB2, 0xA3, 0x67, 0x9B, 0x6E, 0xA2, 0x2E, 0x00, 0xB7, 0x06, 0x35, 0x04, 0xC8, 0x58, 0x5E, 0x25, 0x0E, 0x68, 0xCE, 0x2F, 0x1E, 0x9A, 0xC5, 0xEA, 0xD2, 0xA7, 0x54, 0xEA, 0x98, 0xD9, 0xBF, 0x72, 0x98, 0x78, 0x7F, 0x07, 0xA8, 0xBF, 0x7B, 0xA8, 0x7C, 0xB9, 0xCA, 0x42, 0xD5, 0xDF, 0xB5, 0x85, 0x60, 0x8A, 0x93, 0x34, 0xF2, 0x6E, 0x51, 0xDB, 0x20, 0x52, 0xC6, 0x5F, 0xF4, 0xB6, 0x82, 0xBD, 0x1B, 0x9D, 0x75, 0xF6, 0xEF, 0x6B, 0x32, 0x07, 0xA2, 0x21, 0xE7, 0xEF, 0xBF, 0x69, 0xAF, 0xB0, 0x1E, 0xBE, 0xF3, 0xE4, 0xB1, 0xE7, 0x59, 0x8B, 0x9E, 0x1A, 0x47, 0xDB, 0xCA, 0x3F, 0xCB, 0x31, 0x7D, 0x9E, 0x61, 0x21, 0x00, 0xDB, 0xDC, 0x99, 0xCC, 0x01, 0xBD, 0x90, 0x55, 0xBC, 0xB8, 0xEA, 0x11, 0x02, 0x38, 0x1A, 0x6B, 0xDC, 0x57, 0x04, 0xE0, 0x3C, 0xDF, 0xB2, 0x6C, 0x37, 0x68, 0xFE, 0x1E, 0x4E, 0xF9, 0x02, 0x24, 0xC8, 0x00, 0x88, 0x7D, 0x9F, 0xF8, 0x04, 0x2C, 0x0D, 0xCC, 0xD0, 0xCB, 0x49, 0xDE, 0xCD, 0xA3, 0xEB, 0xC0, 0xF1, 0x46, 0xD5, 0xD8, 0x6B, 0x13, 0x7B, 0xF7, 0x42, 0x5C, 0xEC, 0xAE, 0x60, 0xF3, 0x96, 0xD4, 0x3E, 0xC4, 0x9B, 0x27, 0xF3, 0x54, 0xD6, 0x0A, 0x18, 0x37, 0x46, 0x5F, 0x2C, 0x42, 0xF8, 0x6E, 0x9E, 0xF5, 0x9E, 0xFF, 0xAA, 0x8E, 0x96, 0xDD, 0x8B, 0xC0, 0x3A, 0x5F, 0x11, 0x60, 0x0D, 0xE1, 0xF5, 0x58, 0x72, 0x43, 0xD6, 0x06, 0xA5, 0x4B, 0xA8, 0x44, 0x2B, 0xE6, 0xAB, 0xFE, 0x63, 0x37, 0xA0, 0x72, 0x83, 0x16, 0x08, 0x5A, 0xAF, 0x2D, 0x7B, 0xF7, 0x01, 0xBC, 0x06, 0xA8, 0x02, 0xEF, 0x4E, 0x57, 0x18, 0x01, 0x48, 0x74, 0xD3, 0x69, 0xFD, 0xB8, 0xAE, 0x53, 0x3E, 0x81, 0xCA, 0x2B, 0xF9, 0x3C, 0x15, 0x09, 0xA6, 0x9F, 0x02, 0xFE, 0x21, 0x9F, 0xF1, 0xE2, 0xCB, 0xCD, 0x76, 0xB4, 0xE2, 0x8A, 0xA0, 0xF4, 0xAF, 0xCE, 0x86, 0x7C, 0xC4, 0x3B, 0x27, 0xE7, 0x7F, 0x73, 0xC1, 0x57, 0x1A, 0xC2, 0xF3, 0x70, 0xA0, 0xBC, 0x36, 0x7E, 0xD9, 0xE5, 0xE8, 0x06, 0x35, 0x64, 0x9E, 0x7E, 0x75, 0xB9, 0x10, 0xDB, 0xFE, 0xC3, 0x0E, 0x70, 0x1C, 0x60, 0x02, 0xDC, 0x6F, 0xD0, 0xF2, 0x05, 0x0D, 0xA5, 0x04, 0x79, 0x41, 0xD3, 0xAF, 0xC4, 0x9E, 0x3D, 0x81, 0x31, 0xA1, 0xCD, 0x26, 0xEF, 0xEE, 0xDF, 0x18, 0x56, 0xC1, 0x79, 0x57, 0xDA, 0x13, 0xEF, 0x51, 0x07, 0xCD, 0x6F, 0xB5, 0x43, 0x10, 0xAD, 0xE8, 0xA7, 0x4D, 0x3A, 0x76, 0x55, 0x80, 0xE8, 0x4C, 0xFB, 0x9D, 0xF3, 0xA7, 0xDB, 0xF4, 0x57, 0x8E, 0xD4, 0x0F, 0xDD, 0x71, 0x57, 0x4F, 0xB7, 0xC1, 0x1F, 0xF4, 0x55, 0x56, 0x75, 0xE5, 0x89, 0xB5, 0xC1, 0x0C, 0x1C, 0x5E, 0xAA, 0x2E, 0x69, 0xBC, 0x41, 0x11, 0x80, 0xD2, 0x72, 0x94, 0xB2, 0xF9, 0x45, 0x6E, 0x9C, 0x5A, 0x03, 0x23, 0xE3, 0x06, 0xAD, 0xFE, 0xA5, 0xA3, 0x58, 0x2C, 0xDF, 0x0F, 0x72, 0x5C, 0xF6, 0x83, 0xBF, 0xA0, 0x1D, 0x0C, 0x97, 0x75, 0xA7, 0xC4, 0x04, 0xC4, 0x16, 0xC4, 0xF0, 0x99, 0xC5, 0xE2, 0x26, 0xBD, 0xB1, 0x1E, 0xEC, 0xA3, 0xE8, 0x8B, 0x46, 0xE3, 0x39, 0xF5, 0x4B, 0x00, 0xBE, 0xB7, 0xEF, 0x04, 0xA8, 0x56, 0xA7, 0xB9, 0x37, 0x3A, 0xF4, 0xAF, 0xD3, 0x20, 0x9F, 0x39, 0xCE, 0x73, 0x8E, 0xB0, 0xE7, 0x24, 0x6F, 0x04, 0xD0, 0x59, 0x22, 0x72, 0x01, 0xF2, 0x00, 0x11, 0x0B, 0x35, 0x85, 0x4D, 0x5C, 0x80, 0xD1, 0x92, 0x39, 0x1D, 0x80, 0x3E, 0xC8, 0x4A, 0x2C, 0xEB, 0x7B, 0x11, 0x7C, 0x8F, 0x4E, 0x7E, 0x47, 0x84, 0xFC, 0x12, 0x43, 0xCE, 0xF2, 0xBD, 0xFF, 0x2D, 0x71, 0x36, 0xF0, 0x30, 0x98, 0xBB, 0x99, 0x40, 0x33, 0x67, 0xD9, 0x3D, 0xC0, 0x39, 0x1E, 0xCF, 0x7D, 0xB4, 0xC5, 0x97, 0x11, 0x59, 0x59, 0x59, 0xD5, 0x02, 0xDE, 0x30, 0x26, 0xEE, 0xA0, 0xC9, 0x2D, 0xDA, 0x02, 0xBE, 0xDB, 0x91, 0xD6, 0xE3, 0xC9, 0x89, 0x0B, 0x84, 0xFE, 0x4D, 0xA0, 0xB2, 0xD7, 0x6A, 0xAB, 0x05, 0x88, 0x02, 0xDE, 0x08, 0x6B, 0xD0, 0x2F, 0xBC, 0x11, 0x7B, 0x80, 0x2A, 0x10, 0x06, 0xB8, 0x03, 0xAA, 0x6B, 0xF4, 0xEF, 0x99, 0x85, 0x22, 0xB7, 0x1B, 0x34, 0xFA, 0x97, 0x9F, 0xFA, 0x22, 0x3F, 0x75, 0x82, 0xA7, 0x42, 0x46, 0x43, 0x85, 0x43, 0x93, 0x76, 0x2F, 0x9C, 0x55, 0x6F, 0x2D, 0xDA, 0x95, 0xA9, 0xC4, 0x91, 0x76, 0xF7, 0xAD, 0x00, 0x48, 0x61, 0x77, 0x44, 0xFA, 0xD9, 0xB3, 0xEB, 0xE6, 0xE9, 0x80, 0xD8, 0x7B, 0x58, 0xBB, 0xAA, 0x03, 0xB0, 0xAF, 0x22, 0x5D, 0x35, 0x6E, 0xDA, 0x6F, 0xCC, 0xA5, 0xEB, 0x1C, 0x6B, 0xF5, 0xF3, 0x15, 0xCF, 0xA8, 0x9F, 0xF3, 0x96, 0x01, 0x81, 0xA4, 0xD5, 0x52, 0x15, 0x0D, 0x6F, 0x18, 0xE0, 0x67, 0x1E, 0x39, 0xC4, 0x01, 0x8F, 0x65, 0x93, 0xBD, 0xF5, 0x71, 0x3C, 0x4D, 0xFB, 0x9C, 0x6F, 0xD0, 0xF8, 0x53, 0x20, 0x24, 0xC7, 0x9B, 0xF0, 0x06, 0x6D, 0x3E, 0xC1, 0x54, 0xA7, 0x14, 0xD1, 0xF2, 0xD6, 0x2C, 0x2B, 0x75, 0x56, 0x13, 0xD9, 0x34, 0xDE, 0x7B, 0x9A, 0xE4, 0xDF, 0x31, 0x08, 0xF5, 0x7A, 0x84, 0x49, 0x69, 0x96, 0x18, 0x8F, 0xE2, 0x93, 0x50, 0x87, 0xD0, 0x6F, 0xC5, 0x1A, 0xB8, 0x41, 0x4B, 0xE0, 0x89, 0xD0, 0xDB, 0xC5, 0x60, 0xC9, 0x03, 0x08, 0xA8, 0xDB, 0x19, 0xFA, 0xEA, 0x7F, 0xD5, 0x9F, 0x88, 0x1A, 0xD9, 0xB0, 0x46, 0x34, 0x0A, 0x60, 0x05, 0x34, 0x80, 0xE2, 0xE9, 0x6D, 0x42, 0x32, 0xBD, 0xA0, 0x3C, 0x00, 0x6D, 0xF8, 0x79, 0x5D, 0xE0, 0x1D, 0x34, 0xF9, 0x8A, 0xC3, 0x22, 0xD6, 0x02, 0x80, 0x1C, 0x43, 0x19, 0xC3, 0xE3, 0xFB, 0xDF, 0x1C, 0xBD, 0x66, 0xAF, 0x08, 0x7D, 0xB2, 0xBE, 0xFB, 0x80, 0xF4, 0x42, 0x8B, 0x8E, 0x99, 0xCA, 0xDF, 0xEA, 0xBD, 0xBF, 0x26, 0xD3, 0x4B, 0x28, 0x5A, 0x74, 0xE3, 0xEE, 0x68, 0x7A, 0xE6, 0xA7, 0xFB, 0x8A, 0x5E, 0x8B, 0xE5, 0xC0, 0xB9, 0x5A, 0x81, 0xA1, 0x78, 0xB1, 0x37, 0x00, 0xB6, 0x3E, 0x74, 0x45, 0x2A, 0x9F, 0xA1, 0x63, 0x10, 0xB0, 0x16, 0xC5, 0x90, 0x5F, 0x01, 0xD2, 0x38, 0xF3, 0x93, 0xE9, 0x9A, 0x91, 0x69, 0x4B, 0x85, 0xCF, 0x80, 0x27, 0x60, 0x02, 0x3C, 0x1B, 0xCA, 0xF7, 0x74, 0x2A, 0xB4, 0xDC, 0x91, 0xF8, 0xDB, 0x5A, 0xB4, 0x5B, 0x4A, 0xF4, 0xCE, 0x16, 0xB8, 0x45, 0x1A, 0xF5, 0x81, 0xCA, 0x90, 0x02, 0xAE, 0x44, 0x91, 0xB3, 0xD7, 0x19, 0x8D, 0x98, 0x75, 0xFD, 0xAD, 0xD5, 0x00, 0x88, 0x52, 0x1A, 0x8E, 0xF7, 0x74, 0x00, 0x33, 0xE0, 0x1C, 0x1C, 0x6D, 0xB9, 0xAF, 0x59, 0xA6, 0x00, 0x1B, 0x40, 0xD9, 0xFF, 0x5F, 0xC7, 0x5A, 0x3A, 0xF2, 0x9D, 0xB9, 0x7E, 0x27, 0xB8, 0xF0, 0x2B, 0xDF, 0x9B, 0xCA, 0x98, 0x73, 0x41, 0xB7, 0x53, 0x11, 0xC8, 0xD3, 0xE0, 0x86, 0x00, 0x6F, 0xCB, 0x05, 0xDE, 0x73, 0x7F, 0x18, 0x9F, 0x6A, 0x15, 0x22, 0xD4, 0x01, 0x56, 0x40, 0xE2, 0xE5, 0x03, 0x11, 0x33, 0xFB, 0xEA, 0xE9, 0x54, 0x18, 0x54, 0x3C, 0xD6, 0x99, 0xD0, 0x73, 0xB0, 0xA0, 0xCC, 0xB7, 0x95, 0xE1, 0xB7, 0x8C, 0xEF, 0x5D, 0x19, 0x6B, 0x72, 0xA5, 0x5E, 0x7F, 0x89, 0x3C, 0x7F, 0x2D, 0xE8, 0x09, 0x48, 0x17, 0xF5, 0xE5, 0x7B, 0x97, 0x01, 0x12, 0xF8, 0xA2, 0x7D, 0x5F, 0xEC, 0x4B, 0xA5, 0xB4, 0xE3, 0x19, 0x57, 0xAF, 0xC8, 0xE8, 0x55, 0x67, 0x6F, 0x54, 0x00, 0xD6, 0x77, 0x3D, 0x47, 0x13, 0xD1, 0x57, 0xAB, 0x42, 0xD6, 0x63, 0x59, 0xAB, 0x25, 0x70, 0x72, 0xB6, 0xB2, 0x05, 0x2D, 0xB7, 0x25, 0x9A, 0x0F, 0xB3, 0xAE, 0x09, 0xB6, 0xAE, 0x80, 0x3A, 0x40, 0x1F, 0xE2, 0x99, 0x31, 0x9C, 0x02, 0x42, 0xEE, 0x3A, 0xF3, 0xEF, 0xBC, 0x71, 0x82, 0xBF, 0x7F, 0x7D, 0x7B, 0xAA, 0x2B, 0xFC, 0x5E, 0x64, 0xE8, 0xF5, 0xAC, 0xF4, 0xFE, 0xE7, 0x93, 0xAE, 0x31, 0x10, 0x1A, 0x07, 0xB6, 0x4E, 0x59, 0xAA, 0x17, 0xEF, 0x73, 0xF5, 0xBF, 0xCB, 0xE7, 0x74, 0x0C, 0x10, 0xC2, 0x17, 0x11, 0xA7, 0xBE, 0x43, 0xE1, 0x5B, 0x9E, 0xA0, 0xB5, 0xE2, 0x2F, 0xCF, 0x41, 0xAF, 0x1A, 0x72, 0x3E, 0xF8, 0xEB, 0x79, 0x32, 0xFD, 0x6F, 0x5B, 0x67, 0x3C, 0xB1, 0x03, 0xEB, 0xDC, 0xE9, 0x45, 0x97, 0x28, 0xBC, 0x1A, 0x0C, 0xC4, 0xFD, 0xF4, 0xBA, 0x98, 0x01, 0x63, 0x20, 0x76, 0x43, 0xEE, 0x01, 0x78, 0x4D, 0xCD, 0xA7, 0x46, 0x9C, 0x1B, 0xB4, 0xF8, 0xA6, 0xBB, 0x69, 0xE9, 0x16, 0x0E, 0xC1, 0xCF, 0x55, 0xBD, 0x67, 0x67, 0xF4, 0x5B, 0x20, 0x09, 0xFB, 0x75, 0x48, 0xEF, 0xFE, 0xBB, 0xA6, 0x32, 0x5A, 0xC3, 0xBA, 0x9B, 0x01, 0x3B, 0x9A, 0xF7, 0x56, 0x96, 0x9D, 0xEF, 0x28, 0x7C, 0x2A, 0x07, 0x9C, 0x80, 0x36, 0x34, 0x78, 0xD2, 0x92, 0x94, 0x3F, 0x83, 0x89, 0xF3, 0x3A, 0xE8, 0x9E, 0x2C, 0xBB, 0x97, 0x58, 0xAC, 0x23, 0xDB, 0x7D, 0x05, 0xE6, 0xDC, 0x8B, 0xCC, 0xE6, 0x1E, 0xC6, 0xDC, 0x38, 0x0D, 0x59, 0xCA, 0x1B, 0x03, 0xCA, 0x1B, 0xEB, 0x96, 0x6F, 0x0D, 0x65, 0xC0, 0xFC, 0x29, 0x52, 0x3A, 0x68, 0xF9, 0xD9, 0xE4, 0x70, 0x32, 0xA2, 0xD5, 0xFF, 0x29, 0x42, 0xBF, 0x8B, 0xA7, 0x1C, 0x6F, 0x3B, 0x4B, 0xC1, 0xF5, 0x31, 0x9F, 0xEF, 0xC2, 0x9B, 0x14, 0x72, 0xF0, 0x73, 0x5E, 0xB6, 0xFE, 0xDD, 0xA1, 0xAF, 0xBF, 0x38, 0x23, 0x57, 0x88, 0x8D, 0xD1, 0xFB, 0x59, 0x27, 0x40, 0x6C, 0x66, 0x85, 0xD4, 0x01, 0xF2, 0xCE, 0x0A, 0x31, 0xC0, 0xD4, 0x5B, 0xA0, 0xFC, 0xED, 0x8B, 0xF4, 0x8E, 0x30, 0x34, 0xA6, 0x52, 0xCA, 0x1A, 0x60, 0x84, 0xE5, 0x3E, 0x76, 0x34, 0x6F, 0xD8, 0x01, 0x34, 0x00, 0x23, 0x20, 0xEE, 0x76, 0x45, 0x80, 0xD6, 0xF6, 0xE6, 0xB9, 0x03, 0xCA, 0x81, 0xC8, 0xD9, 0xCF, 0xAD, 0xD9, 0x31, 0xC3, 0x50, 0x54, 0xA9, 0x2D, 0x86, 0xEC, 0xCC, 0x8D, 0xB6, 0x9F, 0x49, 0x14, 0xBC, 0x2A, 0x2A, 0xF0, 0xC8, 0x8A, 0x7F, 0x0B, 0x2B, 0x10, 0xAB, 0x23, 0x80, 0xE7, 0xDF, 0x6C, 0x6C, 0x6E, 0x07, 0x24, 0x69, 0x1F, 0x1B, 0xED, 0x6D, 0x58, 0x7B, 0x03, 0x55, 0xFC, 0xEA, 0xF8, 0x62, 0x7E, 0xC0, 0x82, 0x94, 0x16, 0xD2, 0x49, 0x37, 0x33, 0x49, 0xCF, 0xF6, 0x13, 0xED, 0xAD, 0x8F, 0x00, 0x8E, 0xB7, 0x3C, 0x85, 0xFA, 0xCD, 0xA0, 0x7F, 0x8F, 0x6F, 0x8C, 0x37, 0xED, 0x68, 0xAD, 0x33, 0x06, 0x94, 0x96, 0x9B, 0xB9, 0x02, 0xB1, 0xAC, 0x75, 0x34, 0x1A, 0x04, 0xF0, 0x4D, 0xDC, 0x19, 0x10, 0x31, 0x67, 0x7D, 0x1A, 0x21, 0x64, 0xF5, 0x37, 0x2E, 0x24, 0xFA, 0x61, 0xEA, 0x9B, 0x81, 0x60, 0xF2, 0x27, 0x72, 0x25, 0x29, 0x1F, 0x9C, 0xAD, 0xFD, 0x88, 0xBE, 0xA8, 0x4A, 0xEC, 0x1E, 0x9F, 0x67, 0x15, 0x41, 0x6F, 0x5B, 0x9D, 0x76, 0x65, 0xFA, 0xE7, 0x86, 0x5A, 0xCF, 0xC7, 0xC6, 0xAF, 0xD4, 0xFD, 0x00, 0xB7, 0xB3, 0xCE, 0x15, 0xE0, 0xB5, 0xA5, 0xBC, 0xD9, 0x54, 0x39, 0x53, 0x8B, 0xD4, 0x37, 0xEF, 0x08, 0x20, 0x75, 0xA6, 0xB2, 0xB9, 0x41, 0xD9, 0x88, 0x85, 0x02, 0xA4, 0x11, 0x36, 0x3B, 0xB0, 0x4A, 0x80, 0xC8, 0x55, 0x50, 0xD1, 0x5F, 0x05, 0x95, 0xA2, 0xD1, 0x0A, 0x45, 0xFC, 0x97, 0xDF, 0xF8, 0x32, 0x69, 0x0C, 0x73, 0x77, 0x4F, 0xB8, 0x6B, 0x70, 0xE0, 0x24, 0xA8, 0x32, 0xBB, 0x55, 0x64, 0x68, 0x38, 0xF4, 0x99, 0xF8, 0x18, 0x3F, 0x0F, 0xA9, 0x29, 0x87, 0xD2, 0x9A, 0x4F, 0x10, 0xFD, 0x59, 0xE1, 0xE5, 0xB3, 0xB5, 0xE2, 0x91, 0x07, 0xB4, 0x77, 0x3B, 0xBA, 0x2E, 0x14, 0x7E, 0xFF, 0xDA, 0x0E, 0xB0, 0xBF, 0x68, 0x01, 0x0C, 0x54, 0xAD, 0x3B, 0x7A, 0x34, 0xB4, 0x21, 0x0D, 0xBF, 0x31, 0x5F, 0xC3, 0x4A, 0x6A, 0x5D, 0xD5, 0xCF, 0xCE, 0x6F, 0xCC, 0x4F, 0x4E, 0x37, 0x68, 0x8C, 0xAB, 0x7A, 0xC1, 0xBC, 0x55, 0x3C, 0x61, 0x47, 0x24, 0xF1, 0xBD, 0x05, 0x22, 0x04, 0xBE, 0xDF, 0xD1, 0xAE, 0x68, 0xEF, 0x1E, 0x23, 0x23, 0xBF, 0x11, 0x31, 0x5E, 0x9D, 0xDA, 0x0B, 0xE7, 0x59, 0x37, 0xD8, 0x1B, 0x9A, 0xE9, 0x0C, 0x8C, 0x99, 0xB8, 0x18, 0x7D, 0x08, 0x50, 0x4C, 0x29, 0x36, 0x49, 0x07, 0xFB, 0xCF, 0x5C, 0xA4, 0x9E, 0x73, 0xAD, 0x7E, 0xF0, 0xD7, 0x7E, 0x2B, 0x3A, 0x7D, 0x9E, 0x4E, 0x2D, 0x1B, 0x40, 0x9F, 0xBD, 0x68, 0xA5, 0x0B, 0x3E, 0x3B, 0x9F, 0x35, 0x01, 0xAF, 0x86, 0xCC, 0x2F, 0xB2, 0x01, 0x44, 0xF3, 0xD3, 0x7B, 0x75, 0xD6, 0xDF, 0x70, 0xCF, 0xCF, 0x47, 0x46, 0x47, 0xCE, 0xD6, 0xA8, 0x1B, 0x00, 0x4C, 0xD1, 0x6B, 0xA2, 0x81, 0x78, 0x38, 0xCD, 0x4C, 0xDA, 0x53, 0x40, 0xBE, 0x21, 0x17, 0xE3, 0xC0, 0x68, 0x6F, 0x00, 0x82, 0x35, 0x4E, 0xFC, 0xBD, 0x02, 0xFB, 0xD4, 0xFA, 0x74, 0x7B, 0x2D, 0x98, 0xA8, 0x77, 0x76, 0xAA, 0x61, 0x72, 0xE5, 0xF7, 0xDD, 0x37, 0x3A, 0xE0, 0x47, 0x8E, 0x90, 0x12, 0x38, 0x01, 0x30, 0x4F, 0x10, 0x01, 0x67, 0x7D, 0x0B, 0x2D, 0x0F, 0x71, 0x8F, 0x55, 0x24, 0xF6, 0x55, 0x50, 0x91, 0x55, 0x91, 0x2F, 0xA0, 0xE4, 0x06, 0x4D, 0x87, 0xE5, 0xA8, 0x75, 0x32, 0x9B, 0x5D, 0xBE, 0x33, 0x68, 0xF4, 0x08, 0x24, 0x51, 0x85, 0x86, 0xD8, 0xB9, 0x77, 0xA6, 0x68, 0x19, 0xC2, 0x76, 0xA2, 0x1E, 0x46, 0x5F, 0xCF, 0xBE, 0x59, 0x5F, 0xCD, 0xEE, 0xE0, 0xD3, 0x92, 0xF4, 0x40, 0xDB, 0x37, 0x3C, 0x79, 0xA5, 0x5F, 0x69, 0x59, 0x80, 0xF2, 0x9B, 0x08, 0xF8, 0x5C, 0x16, 0xFC, 0xE5, 0x1B, 0xFC, 0x9A, 0x02, 0xEE, 0xE9, 0xBE, 0x0D, 0xC9, 0x86, 0xAE, 0xAD, 0xAD, 0x1A, 0x39, 0x3F, 0xE9, 0xEA, 0xF6, 0x38, 0xD6, 0x38, 0x53, 0xAE, 0x63, 0x02, 0x88, 0x01, 0xFA, 0xBE, 0xF3, 0x06, 0xCD, 0xBE, 0x8A, 0x4A, 0x7D, 0x81, 0xB9, 0xFE, 0xA3, 0x8E, 0xF1, 0xE2, 0x52, 0xDF, 0x2B, 0x00, 0x59, 0x03, 0x47, 0x87, 0x0F, 0xDD, 0xF6, 0x7F, 0xD2, 0xD1, 0x39, 0xE0, 0x67, 0xAD, 0x34, 0x7D, 0x1D, 0xFB, 0xF4, 0x57, 0xCC, 0xEC, 0xD3, 0xEB, 0x1B, 0x49, 0x2A, 0xBD, 0xD2, 0xF8, 0x5D, 0x54, 0xEA, 0x00, 0x22, 0xD3, 0xB4, 0xDC, 0xF8, 0x5A, 0x77, 0x8C, 0x1B, 0xE6, 0x9B, 0x38, 0x50, 0xD3, 0xF5, 0xE9, 0xD0, 0x84, 0x1E, 0xC0, 0x0D, 0x88, 0xD3, 0xB0, 0x46, 0x02, 0xC9, 0x33, 0xC7, 0xA3, 0x02, 0x78, 0x34, 0x96, 0x7B, 0x25, 0x13, 0x70, 0x6C, 0x9E, 0xF1, 0xE2, 0xED, 0x69, 0xFE, 0xF7, 0x22, 0xC0, 0x25, 0x4B, 0xB5, 0x17, 0xDC, 0x97, 0x44, 0x50, 0xCC, 0x82, 0x52, 0x43, 0x0F, 0x98, 0x11, 0x8C, 0x72, 0x4B, 0xF1, 0x02, 0xD8, 0xBD, 0x2A, 0x6F, 0x62, 0x4F, 0x2D, 0x47, 0x96, 0xA0, 0xFB, 0xEC, 0x8D, 0x31, 0x16, 0xCF, 0x0C, 0x2E, 0x01, 0x2A, 0xE0, 0x1C, 0x80, 0x19, 0x98, 0x13, 0x0A, 0xEE, 0x81, 0x53, 0x5F, 0x36, 0x31, 0x69, 0x8E, 0xC3, 0x64, 0x6F, 0xD8, 0x1E, 0x77, 0xD0, 0x38, 0x80, 0xFA, 0x42, 0xCD, 0xE1, 0x1B, 0xA4, 0x80, 0x0A, 0x20, 0x0D, 0x92, 0xF9, 0x13, 0x5C, 0xE7, 0x9A, 0x14, 0xBF, 0x41, 0x8B, 0xAF, 0x33, 0x96, 0x03, 0x99, 0xB4, 0x13, 0x3A, 0xAE, 0x03, 0x44, 0xDA, 0x7D, 0xFF, 0xD6, 0x75, 0x28, 0x6E, 0x83, 0x38, 0xEA, 0x17, 0xC1, 0x96, 0xC2, 0x0F, 0xEF, 0x9F, 0x37, 0x79, 0x3A, 0xFB, 0x74, 0x7F, 0x5E, 0x53, 0x43, 0x29, 0x70, 0x85, 0xFC, 0x24, 0x7F, 0xED, 0x00, 0xFE, 0x5A, 0xED, 0xFD, 0x3E, 0xC8, 0xF6, 0x9C, 0xE9, 0x7A, 0x2A, 0xE2, 0xD8, 0xF6, 0xDC, 0x3A, 0xAE, 0x71, 0x87, 0xE8, 0x01, 0x72, 0x00, 0x2B, 0x20, 0x4F, 0x43, 0x81, 0xA2, 0x39, 0x1F, 0xFC, 0x30, 0xC0, 0x0A, 0x38, 0x03, 0xE9, 0x8D, 0x35, 0x8A, 0x4F, 0xF7, 0xE4, 0xC1, 0x03, 0x14, 0xDF, 0xA0, 0x25, 0xDA, 0x89, 0x35, 0x31, 0xF6, 0xDF, 0x18, 0x2E, 0xC6, 0x9E, 0xDF, 0x19, 0xF3, 0xA0, 0x01, 0xCF, 0x29, 0xF2, 0x43, 0x4A, 0xB5, 0xE3, 0x27, 0x4F, 0xDB, 0x39, 0x5A, 0x95, 0x75, 0x7D, 0xCD, 0x5C, 0x84, 0xF8, 0xE8, 0xCD, 0x3B, 0xCA, 0xBB, 0xC2, 0xBF, 0x9C, 0x24, 0xC5, 0xEB, 0x16, 0xAF, 0x00, 0x68, 0x3C, 0xCF, 0xF2, 0xFC, 0xA8, 0xD4, 0x3B, 0x5A, 0x78, 0x58, 0x9F, 0x61, 0xB7, 0x75, 0xB4, 0x72, 0xCE, 0x4D, 0x21, 0xE9, 0x88, 0x2C, 0x2B, 0x14, 0x52, 0x40, 0x0C, 0x50, 0x05, 0x8C, 0x97, 0x43, 0x2E, 0x1B, 0x60, 0x0D, 0x4D, 0x80, 0x0B, 0x38, 0x32, 0xBD, 0x53, 0xAE, 0x66, 0xDA, 0xA4, 0x83, 0x56, 0xDF, 0x9E, 0x76, 0xC8, 0x61, 0x94, 0x63, 0x6F, 0xA5, 0x21, 0x83, 0x1B, 0x8E, 0x3C, 0xA5, 0xF3, 0x07, 0xB1, 0x2E, 0xDE, 0x89, 0x8C, 0x17, 0x81, 0xD3, 0x28, 0xDE, 0xD9, 0x55, 0xA7, 0xC8, 0x2B, 0x39, 0x69, 0xC7, 0x4E, 0x1C, 0x9F, 0x82, 0xFE, 0xDA, 0x01, 0xEC, 0xD9, 0xAD, 0xF2, 0x3D, 0xCA, 0x21, 0x3E, 0xCF, 0x48, 0x3F, 0xFF, 0x8C, 0x1F, 0xAF, 0x7F, 0x9A, 0xBF, 0xDD, 0x28, 0x64, 0xEE, 0x5B, 0xA7, 0x41, 0x35, 0x87, 0x93, 0xF3, 0xEA, 0xB2, 0xD5, 0x86, 0x51, 0x23, 0x81, 0x94, 0x9B, 0xF2, 0x05, 0x2C, 0x00, 0x2D, 0x40, 0x68, 0x95, 0x89, 0x69, 0x95, 0x89, 0x3B, 0xFD, 0x68, 0xE7, 0x0C, 0x49, 0xF2, 0xC9, 0x79, 0xB8, 0x25, 0xA7, 0xEE, 0xB6, 0x77, 0xBC, 0x18, 0x35, 0xFA, 0x06, 0xB7, 0x9A, 0x16, 0x79, 0xA8, 0xBA, 0xF5, 0x2A, 0x20, 0xCF, 0xEB, 0xC9, 0xB2, 0x0F, 0xBA, 0xA6, 0xAD, 0xC9, 0x6B, 0xF0, 0x52, 0x7D, 0xA3, 0x9E, 0x9E, 0x84, 0xA8, 0xDE, 0x58, 0xF0, 0x73, 0xA3, 0x35, 0x46, 0xCA, 0xDA, 0x3B, 0x09, 0x92, 0xCC, 0x53, 0x02, 0x33, 0x70, 0x4E, 0x43, 0xE6, 0xA9, 0x36, 0xBD, 0x21, 0x0D, 0x6E, 0x28, 0x50, 0x6B, 0xA6, 0xBE, 0xC6, 0x2E, 0x01, 0x2E, 0x73, 0x82, 0x5C, 0xD5, 0xBE, 0xBA, 0x41, 0xA3, 0x7F, 0xD1, 0x3E, 0x02, 0xFA, 0x2D, 0x57, 0x19, 0x2B, 0xCD, 0x48, 0x60, 0xC7, 0x29, 0x57, 0xF8, 0x12, 0xB8, 0x7D, 0x21, 0x68, 0x45, 0x5B, 0x0A, 0xCF, 0x63, 0xAE, 0x56, 0x5B, 0xCD, 0x74, 0x8D, 0xBC, 0x93, 0x3E, 0x05, 0xE4, 0xF9, 0x6B, 0x94, 0xA1, 0xD7, 0xA8, 0x95, 0xA3, 0x01, 0x29, 0x96, 0xB5, 0x12, 0x32, 0x3B, 0x63, 0x15, 0x8E, 0xDE, 0x02, 0xF4, 0x16, 0x63, 0xF9, 0x19, 0xE0, 0xCB, 0x2D, 0x4C, 0xD6, 0x7E, 0x67, 0xD6, 0x48, 0xC0, 0x75, 0xCD, 0xD0, 0x36, 0xC0, 0x05, 0xB0, 0x00, 0xA4, 0x80, 0xB3, 0xA6, 0x6D, 0x1F, 0x01, 0x9C, 0x6F, 0xD0, 0x18, 0x3E, 0x39, 0xC7, 0x90, 0x5D, 0xE4, 0x98, 0xD7, 0x75, 0xCE, 0xB6, 0xB3, 0xA2, 0x2E, 0xC1, 0x75, 0x83, 0xE8, 0x09, 0xB4, 0xDB, 0xCD, 0x2D, 0x6D, 0xD9, 0xDB, 0xC3, 0x51, 0xAC, 0xC5, 0x18, 0x9D, 0xC6, 0x30, 0x02, 0xA0, 0xC9, 0xA8, 0x16, 0x03, 0xE7, 0xBB, 0x85, 0x23, 0x2D, 0x64, 0x1D, 0x56, 0x7D, 0x26, 0x9F, 0xCF, 0x4B, 0xA4, 0xC3, 0x8A, 0x98, 0xF9, 0x7D, 0x9C, 0x9F, 0x2F, 0xA1, 0xDF, 0x81, 0x21, 0x57, 0x05, 0x0E, 0x94, 0x3D, 0xF9, 0x65, 0x43, 0x1A, 0x05, 0x10, 0x35, 0x72, 0xF6, 0x6A, 0x9C, 0x71, 0xDE, 0xD9, 0xBE, 0xC3, 0x28, 0x1A, 0x8D, 0xD4, 0x88, 0xDF, 0x6F, 0xC9, 0x8E, 0x99, 0x40, 0xBF, 0x2D, 0xF1, 0xDD, 0xD0, 0xD3, 0x6B, 0x68, 0xF9, 0xD2, 0xAC, 0x83, 0x15, 0xBD, 0x55, 0x27, 0xF2, 0x5C, 0xAC, 0xED, 0xC1, 0xB1, 0xF3, 0x42, 0xEF, 0x2C, 0xD5, 0x41, 0xAB, 0x8E, 0x48, 0x75, 0xEC, 0xBD, 0x00, 0xEE, 0x48, 0xC6, 0x07, 0x54, 0x82, 0xBF, 0x30, 0x59, 0x87, 0x89, 0xF3, 0x4F, 0xDC, 0x7F, 0xDE, 0x1C, 0x66, 0x3E, 0x7F, 0xE6, 0x5D, 0xD6, 0x29, 0x35, 0x79, 0xE3, 0x24, 0x65, 0xCD, 0xE7, 0xB7, 0x6B, 0x5D, 0x92, 0xB3, 0x51, 0xD3, 0x12, 0x48, 0x6A, 0xD4, 0x6C, 0x76, 0x95, 0x46, 0xDE, 0xD4, 0x5F, 0x34, 0xE8, 0x7E, 0x71, 0xEE, 0x29, 0x5C, 0xD3, 0x64, 0xEC, 0x58, 0x07, 0xED, 0x5D, 0x08, 0x50, 0xC2, 0xAB, 0xF8, 0x8E, 0x69, 0xAA, 0x84, 0x21, 0x3F, 0x6C, 0x38, 0xEE, 0x70, 0xE2, 0x9C, 0x63, 0x85, 0xB4, 0x5E, 0x0F, 0x77, 0xAB, 0x3D, 0x50, 0xF6, 0x9D, 0xA9, 0xEB, 0x2A, 0x67, 0x57, 0x97, 0x3E, 0x01, 0x42, 0x73, 0x87, 0x8A, 0x04, 0x48, 0xD7, 0x68, 0x68, 0x07, 0xF4, 0x39, 0x97, 0x4C, 0xC9, 0x93, 0x34, 0xEE, 0x59, 0xDA, 0x19, 0xD0, 0x86, 0x19, 0x90, 0x3E, 0xBF, 0xA5, 0x72, 0x63, 0x6E, 0x7E, 0x94, 0x80, 0xC9, 0xAF, 0x11, 0x57, 0x0C, 0xC8, 0x12, 0x9D, 0x72, 0x00, 0x11, 0xF7, 0xE9, 0xB4, 0xA1, 0x4F, 0x66, 0xCA, 0x4F, 0x5B, 0xC5, 0x84, 0x99, 0x2B, 0x5A, 0x0C, 0x89, 0x1B, 0x3B, 0xB6, 0x40, 0x88, 0xE8, 0x6E, 0xD0, 0xEC, 0xEC, 0xB3, 0x2D, 0xDF, 0x06, 0x75, 0xB9, 0xD1, 0x5A, 0x3E, 0xF8, 0x37, 0x89, 0x4F, 0x1D, 0x42, 0xEF, 0xD8, 0xD5, 0xCC, 0x9B, 0xD2, 0x2A, 0xEC, 0xCA, 0x99, 0xB2, 0x16, 0x6B, 0x9C, 0x9C, 0x1B, 0xB9, 0x25, 0xA0, 0x01, 0x04, 0xCD, 0x36, 0x19, 0x91, 0x06, 0xFF, 0x82, 0x03, 0xD6, 0x28, 0x5B, 0xA3, 0xBA, 0xD7, 0x6C, 0x18, 0x5F, 0x09, 0x22, 0xF7, 0xA9, 0x4B, 0xB3, 0xE3, 0x2F, 0x68, 0xF9, 0xA5, 0xE2, 0x13, 0xB9, 0x86, 0xB0, 0x4F, 0x8F, 0xC0, 0x8E, 0xE8, 0x76, 0xEC, 0x54, 0xCB, 0xBE, 0x07, 0x90, 0xCA, 0xA6, 0xA8, 0x7B, 0xCF, 0x7B, 0x0E, 0xBE, 0x25, 0xC7, 0x61, 0xFE, 0xDE, 0x69, 0xDB, 0x7A, 0x23, 0x2C, 0x62, 0x8C, 0xB0, 0xF6, 0x37, 0x85, 0xDE, 0xCF, 0x4C, 0xE9, 0x73, 0x4E, 0x85, 0x86, 0x3B, 0xC0, 0x4F, 0xB8, 0x0D, 0x58, 0xAC, 0x95, 0xA6, 0x40, 0xCA, 0x36, 0xE3, 0x69, 0xC8, 0x82, 0xAE, 0xCC, 0xD0, 0x16, 0x71, 0x28, 0xA0, 0xB4, 0x6E, 0xFD, 0x67, 0x29, 0x5F, 0xE8, 0x06, 0x2D, 0xFE, 0xD5, 0x57, 0x1A, 0x93, 0x17, 0xBB, 0xA7, 0xB1, 0xE5, 0x9E, 0x57, 0xF3, 0xBD, 0x50, 0x05, 0xFA, 0x69, 0x21, 0xA4, 0x4F, 0xEC, 0x36, 0xAD, 0x6F, 0xCB, 0xB9, 0x98, 0x8F, 0xE7, 0x91, 0x39, 0xE0, 0x84, 0x69, 0xEA, 0xFF, 0x63, 0x3D, 0x90, 0xA7, 0x83, 0x6D, 0x0A, 0x50, 0xC7, 0x27, 0xD6, 0x3B, 0x5F, 0x6D, 0x09, 0x93, 0xAB, 0xC1, 0x0D, 0x01, 0x24, 0x81, 0xA8, 0x75, 0xFE, 0xE0, 0x86, 0x2E, 0xAC, 0x29, 0xE7, 0xB6, 0x7E, 0xDE, 0x6E, 0xA8, 0x11, 0x03, 0x78, 0xAD, 0xD0, 0x3C, 0x37, 0x68, 0xF9, 0xAF, 0x0C, 0xD6, 0x85, 0xF5, 0xE9, 0xF0, 0x5B, 0xE5, 0x28, 0xF9, 0xBD, 0xE0, 0x54, 0x1D, 0xE3, 0x35, 0xB1, 0xB5, 0x65, 0xA2, 0xC4, 0x22, 0x64, 0xD3, 0xE6, 0x56, 0xEF, 0x4A, 0x7B, 0xF3, 0x39, 0x6D, 0x1C, 0xD3, 0xB6, 0x65, 0x3D, 0xF5, 0xA7, 0x5E, 0x7E, 0xF9, 0x32, 0xB6, 0x3D, 0xF7, 0x63, 0xD5, 0x64, 0xF4, 0xB9, 0x31, 0x3D, 0xE9, 0xD3, 0x56, 0x4E, 0x1D, 0xC0, 0x05, 0x30, 0x5B, 0x53, 0xF8, 0x08, 0xA8, 0x5A, 0xD6, 0x1D, 0xD4, 0xE0, 0x86, 0x0F, 0xBB, 0xE2, 0xE1, 0xD9, 0x36, 0xB4, 0x2E, 0x99, 0x80, 0xD9, 0x1E, 0xAF, 0xF9, 0xF2, 0x76, 0x1D, 0xB4, 0xFA, 0x17, 0x8E, 0xF6, 0x13, 0x37, 0xD8, 0x48, 0xC0, 0x49, 0xB2, 0xBE, 0x43, 0x9B, 0x72, 0xE1, 0xF0, 0x9C, 0x86, 0x14, 0x80, 0x63, 0x6C, 0x48, 0xB8, 0x0C, 0x6F, 0x26, 0xF5, 0x95, 0xE4, 0xE0, 0x1A, 0x5E, 0xC6, 0xF2, 0xA6, 0x8B, 0xC5, 0x99, 0xAD, 0x17, 0x27, 0xAE, 0x58, 0x7E, 0x8C, 0x85, 0x62, 0xEB, 0x47, 0x17, 0x58, 0x23, 0x78, 0xFC, 0x15, 0x8F, 0x94, 0x3B, 0xA0, 0x3C, 0x7B, 0x0A, 0xDC, 0xA6, 0x2B, 0x7D, 0x74, 0xE8, 0x65, 0x9D, 0xFD, 0x43, 0x81, 0x5C, 0xEA, 0x0D, 0x22, 0xC0, 0x18, 0xD8, 0x93, 0x5C, 0x4D, 0x01, 0x61, 0x80, 0x1A, 0x1C, 0x40, 0x64, 0x07, 0x8D, 0x60, 0xFA, 0xE2, 0x24, 0x38, 0xE2, 0x52, 0x8D, 0x9A, 0xA7, 0x89, 0xE0, 0xB1, 0xAA, 0xCE, 0x35, 0xA4, 0x3C, 0x45, 0x0F, 0x0E, 0xF0, 0xAB, 0x50, 0x2C, 0xF6, 0xA4, 0x36, 0x7F, 0x66, 0x16, 0xF9, 0xFC, 0x0D, 0x84, 0xFE, 0xFC, 0x35, 0xFC, 0x6A, 0xB4, 0x9F, 0xF3, 0x56, 0xD0, 0xEB, 0xB3, 0x7B, 0x03, 0xDA, 0xF2, 0x39, 0xE5, 0xF8, 0xB9, 0x57, 0x9D, 0x79, 0x21, 0xF0, 0x57, 0x8B, 0x00, 0x6C, 0x79, 0x41, 0xD5, 0x32, 0x53, 0xAC, 0x57, 0x56, 0x03, 0x48, 0xD6, 0x64, 0xD4, 0x00, 0x4A, 0xE7, 0x44, 0x1B, 0xB2, 0xFB, 0x45, 0xC0, 0x1B, 0x4A, 0x80, 0xC5, 0xFB, 0x96, 0x0E, 0x1A, 0x7D, 0xA3, 0x07, 0xA8, 0xF4, 0xCB, 0x0C, 0x89, 0xC1, 0xD1, 0xF6, 0x1D, 0x43, 0x45, 0x30, 0x21, 0x48, 0xF0, 0x06, 0xE0, 0x8A, 0x1E, 0xF4, 0xE2, 0xBD, 0xD2, 0xF6, 0xD5, 0x73, 0xF8, 0x77, 0xA1, 0x1E, 0xFF, 0xE7, 0x58, 0xE3, 0xAF, 0xFB, 0x89, 0x86, 0xD5, 0x08, 0xBE, 0x65, 0x54, 0xC9, 0x48, 0x70, 0xDA, 0xBF, 0xA9, 0x04, 0x5B, 0xEF, 0xD9, 0x35, 0x38, 0x91, 0x63, 0xCA, 0xA9, 0x74, 0x0C, 0xCE, 0xF0, 0xB7, 0x50, 0x4F, 0x01, 0xB9, 0xA6, 0x37, 0x2A, 0x01, 0xE6, 0x40, 0xBE, 0xA1, 0x2E, 0xB5, 0x3A, 0x97, 0x05, 0x50, 0x03, 0x48, 0x97, 0x5F, 0xA7, 0x03, 0x9E, 0x1D, 0x34, 0xEE, 0x71, 0x64, 0x85, 0xA2, 0x80, 0xD3, 0x5B, 0x69, 0x5A, 0x50, 0x91, 0x7E, 0xE3, 0xB6, 0x03, 0x2E, 0x60, 0x12, 0x85, 0x44, 0xF6, 0xA9, 0xCE, 0x3D, 0x6E, 0x6F, 0xE0, 0x5C, 0xD9, 0xEE, 0x7B, 0x68, 0xB4, 0x40, 0xD0, 0x58, 0xA6, 0x36, 0x34, 0x57, 0xEC, 0xD2, 0x80, 0x93, 0x7F, 0xC6, 0xAB, 0x07, 0xC7, 0xFD, 0x7A, 0x31, 0x08, 0xB9, 0x21, 0x04, 0xCE, 0x18, 0x4F, 0x69, 0xEF, 0xE0, 0x92, 0x1D, 0x34, 0xF5, 0xB5, 0x7E, 0x0E, 0x20, 0x02, 0xE8, 0x69, 0x24, 0xE0, 0xB5, 0xF2, 0x44, 0x0D, 0xDA, 0x8A, 0x86, 0x02, 0x22, 0xE7, 0x5C, 0x25, 0x79, 0x2B, 0x4D, 0xBE, 0x5E, 0xA8, 0xAA, 0xFA, 0x06, 0x8B, 0xBB, 0x16, 0xA6, 0xAB, 0x7A, 0xA2, 0x16, 0x69, 0x8E, 0xE3, 0x6C, 0x39, 0x66, 0x30, 0x27, 0x7D, 0xFF, 0x62, 0x7C, 0x78, 0x4A, 0x20, 0xCF, 0x0D, 0xDA, 0xCD, 0x99, 0xF2, 0x6A, 0x89, 0x12, 0x99, 0x03, 0x88, 0xC5, 0x3A, 0xA0, 0xF7, 0x3E, 0x43, 0x23, 0x22, 0x71, 0xFE, 0xE4, 0x3F, 0xF6, 0xF6, 0xE7, 0xCC, 0xF9, 0x24, 0x4A, 0x01, 0xC7, 0x57, 0xBF, 0xED, 0x98, 0x36, 0xAE, 0x4F, 0x37, 0x70, 0xCE, 0xB2, 0x12, 0x6B, 0xB8, 0x02, 0x21, 0xCB, 0xA2, 0xA1, 0x00, 0x37, 0xC0, 0x0A, 0x90, 0x06, 0x2D, 0x45, 0xDA, 0x91, 0x95, 0xE4, 0x20, 0xFD, 0x6A, 0x03, 0x54, 0x05, 0xB3, 0x6E, 0x32, 0xE4, 0x8E, 0x94, 0xD0, 0x89, 0xA9, 0xD4, 0x83, 0x94, 0x0C, 0x0F, 0x52, 0x37, 0x63, 0x53, 0xC6, 0x74, 0xA1, 0xD6, 0xA5, 0xE6, 0xCB, 0x2B, 0x49, 0x90, 0x67, 0x59, 0x39, 0xA5, 0x68, 0x76, 0x1D, 0x55, 0xE2, 0xCF, 0xA3, 0xD7, 0xFB, 0x3A, 0x64, 0x6F, 0xA3, 0xF3, 0x04, 0xCE, 0xAA, 0x22, 0xDC, 0x67, 0x88, 0x73, 0x4C, 0x91, 0x05, 0xA2, 0x9F, 0x59, 0x14, 0x80, 0xFE, 0xEE, 0x97, 0x77, 0x00, 0x14, 0xD2, 0xB9, 0x73, 0x06, 0x4D, 0x4C, 0x81, 0xAA, 0x04, 0x70, 0xB3, 0x7F, 0x6C, 0x00, 0x05, 0x70, 0x2B, 0xF7, 0x41, 0x80, 0x35, 0xFC, 0x2D, 0x83, 0x0E, 0x9A, 0xF5, 0x9E, 0x86, 0xA0, 0xA5, 0xCE, 0xDE, 0x58, 0x25, 0xC6, 0x33, 0x7E, 0xFC, 0x03, 0x91, 0xA0, 0xEE, 0xEC, 0x36, 0x93, 0x1C, 0x71, 0x83, 0x16, 0xEF, 0x5F, 0x09, 0x11, 0x39, 0x7D, 0x95, 0x2C, 0x9F, 0x49, 0x8E, 0xE7, 0x29, 0x52, 0x88, 0x5D, 0xF0, 0x5F, 0xFE, 0xD6, 0x5F, 0x0B, 0xBA, 0xC9, 0xEC, 0x85, 0x4A, 0x7F, 0x22, 0xD4, 0xCE, 0x02, 0x8E, 0xA5, 0x69, 0x63, 0xAA, 0x75, 0x3C, 0xBB, 0x7D, 0xB5, 0x39, 0x24, 0x25, 0xE5, 0xCC, 0x0B, 0x3B, 0x0B, 0x20, 0x3A, 0xF3, 0xF0, 0xEC, 0x80, 0x55, 0x43, 0x00, 0xE1, 0x3B, 0xA5, 0x6B, 0x4D, 0x19, 0xBC, 0xDF, 0x62, 0x1D, 0x34, 0xFF, 0xA6, 0xC7, 0x12, 0xFB, 0x6E, 0xF2, 0x81, 0x62, 0xC0, 0xEE, 0x85, 0x90, 0x50, 0x5B, 0xA6, 0xEC, 0x57, 0xDA, 0x4A, 0xA7, 0xC5, 0x6E, 0xF3, 0xAC, 0xB7, 0x6D, 0x4E, 0xFF, 0x49, 0xC9, 0x67, 0x6A, 0xFF, 0x76, 0xE4, 0x78, 0xCF, 0x02, 0xF9, 0x6C, 0x0B, 0xAB, 0x9C, 0xE6, 0x5F, 0x77, 0xBB, 0xB4, 0x02, 0x24, 0x16, 0x18, 0xD0, 0x7B, 0xC0, 0x7F, 0x07, 0xBB, 0xE9, 0x8F, 0x68, 0x8D, 0xE2, 0xF5, 0x12, 0x2D, 0x40, 0x15, 0x48, 0x5B, 0xFE, 0xF3, 0x31, 0xA7, 0x8C, 0x7B, 0x00, 0x76, 0x3F, 0x9D, 0xFD, 0xF6, 0x8C, 0xCF, 0x31, 0xCD, 0x47, 0xF3, 0xC5, 0xB7, 0x79, 0x2A, 0xFA, 0xA5, 0x29, 0xE0, 0xE8, 0x66, 0xD2, 0x8D, 0xFE, 0xB7, 0x08, 0xA9, 0xC3, 0xAF, 0x55, 0x6B, 0x0D, 0x59, 0x71, 0x7D, 0xD3, 0x96, 0x6F, 0x5B, 0xC9, 0xA8, 0xA4, 0xDC, 0xFD, 0x39, 0xE8, 0x4F, 0xD2, 0x6A, 0x4F, 0x43, 0x6D, 0x35, 0x4F, 0x5F, 0x3A, 0xAE, 0xD3, 0x48, 0x02, 0xCD, 0x68, 0x29, 0xC0, 0x3E, 0x63, 0x97, 0xCB, 0xB6, 0xC8, 0x6D, 0x95, 0x85, 0xA9, 0xB1, 0x2A, 0xC0, 0x46, 0x73, 0xF7, 0xE3, 0x04, 0xA8, 0x80, 0x43, 0xCB, 0x59, 0xD0, 0xE7, 0xD0, 0x35, 0x7A, 0xE7, 0xB4, 0xFC, 0x5E, 0x04, 0xE9, 0xF6, 0x82, 0xC6, 0x89, 0xD6, 0x7E, 0xFD, 0xD2, 0x5A, 0x8E, 0xEA, 0x6C, 0xF4, 0x25, 0x23, 0x02, 0xD9, 0xDF, 0x94, 0xEE, 0xEB, 0xD9, 0x32, 0xAB, 0xFB, 0xF7, 0x8D, 0x79, 0x61, 0x17, 0x07, 0xF8, 0xCC, 0x6D, 0x88, 0x72, 0x76, 0x4F, 0x54, 0x00, 0x1C, 0xF7, 0x7F, 0x9F, 0xED, 0xD0, 0x92, 0x1D, 0xB4, 0x02, 0xD4, 0x1B, 0xD6, 0x38, 0x80, 0xAD, 0x21, 0x25, 0xBC, 0x6D, 0x15, 0x69, 0x5A, 0x94, 0x9E, 0x06, 0xC9, 0x7C, 0x49, 0xC4, 0xDD, 0xE5, 0xCF, 0x9A, 0x4A, 0x5E, 0x4B, 0xEF, 0x96, 0x73, 0x58, 0xC4, 0xA1, 0x1B, 0xB4, 0xFA, 0xD2, 0x1B, 0x79, 0xFE, 0xCF, 0xE3, 0x09, 0x19, 0x03, 0x2E, 0xFF, 0xD6, 0xD7, 0x18, 0x9C, 0x3C, 0xCE, 0x81, 0xE9, 0x89, 0xEC, 0x2E, 0xEC, 0x67, 0x2C, 0x57, 0xF5, 0x46, 0xB8, 0x4D, 0xF1, 0xE5, 0xF3, 0x6A, 0xD1, 0x37, 0x98, 0xBB, 0x15, 0x2F, 0xFD, 0xD7, 0x9E, 0x15, 0xE0, 0x38, 0x53, 0xAE, 0x31, 0x44, 0xA9, 0x78, 0x3F, 0x03, 0xE4, 0x0D, 0x9A, 0x9F, 0x4C, 0x67, 0x21, 0x2F, 0x18, 0xA8, 0x8E, 0xE4, 0xB9, 0x30, 0x80, 0x0E, 0x20, 0x0D, 0x8F, 0x65, 0x5B, 0xEF, 0x40, 0x1C, 0x40, 0x0D, 0xE0, 0x9C, 0xEF, 0xEE, 0xE2, 0x0E, 0x1A, 0x9F, 0xEF, 0x1A, 0x55, 0xE6, 0xE8, 0x23, 0xD0, 0x1A, 0xE7, 0xB4, 0x3C, 0x81, 0x85, 0x0D, 0xFD, 0x0B, 0x9B, 0x17, 0xC6, 0x08, 0x58, 0x4D, 0xE7, 0x6E, 0x1E, 0x05, 0x76, 0x79, 0xC7, 0x99, 0xA8, 0x0E, 0xDA, 0xA9, 0x86, 0xBD, 0x56, 0x8C, 0x57, 0x04, 0x8B, 0x57, 0xCB, 0x78, 0x55, 0x8F, 0x7B, 0xCC, 0x8B, 0x25, 0x13, 0xF2, 0x99, 0xA3, 0x11, 0x5F, 0xB2, 0x14, 0x9A, 0xA9, 0x7E, 0xD5, 0x5B, 0xB7, 0x9C, 0xBE, 0xD6, 0xBA, 0x9E, 0x7C, 0x6F, 0x84, 0x01, 0xB5, 0x4C, 0x68, 0xF4, 0x42, 0x00, 0xA1, 0xB9, 0x26, 0xCF, 0xFD, 0xD4, 0xD0, 0xBA, 0x41, 0x23, 0x04, 0x8D, 0xF6, 0x4A, 0xC3, 0x53, 0xCA, 0x22, 0x90, 0x9A, 0x70, 0xE2, 0x6F, 0x54, 0xDA, 0x93, 0x2B, 0x79, 0x3C, 0x9E, 0x46, 0xEB, 0x9C, 0x96, 0x7E, 0x9E, 0xE8, 0xB7, 0x15, 0xBA, 0xC0, 0x73, 0x54, 0xE2, 0xB7, 0xFC, 0xDE, 0x90, 0xE6, 0xB8, 0x3B, 0xF2, 0xFB, 0x3D, 0xE3, 0x83, 0xDC, 0xA4, 0xE0, 0x4B, 0x34, 0xC6, 0x01, 0x94, 0x1A, 0x07, 0x10, 0x01, 0x34, 0xFE, 0x02, 0xAA, 0x6F, 0xF5, 0x6A, 0xCD, 0x4A, 0x93, 0x37, 0xD2, 0xE7, 0x9C, 0x59, 0xA1, 0x39, 0x21, 0x96, 0x0F, 0x40, 0xAB, 0x4E, 0x6A, 0xB5, 0xC6, 0xA8, 0xDE, 0x6F, 0x91, 0x1B, 0x34, 0x8C, 0x6B, 0x38, 0xE2, 0x5F, 0xE6, 0x56, 0x57, 0xBF, 0x7F, 0x3A, 0x36, 0x28, 0x39, 0xD9, 0x82, 0x4C, 0xC6, 0x40, 0x05, 0xAB, 0x19, 0x34, 0x59, 0xC5, 0xA8, 0x78, 0x02, 0x8D, 0x98, 0x0E, 0xD8, 0xD7, 0x4A, 0x35, 0xB4, 0x03, 0x6A, 0xF3, 0x61, 0xBD, 0x43, 0xE9, 0xE5, 0xAF, 0xE3, 0xD2, 0xDE, 0x6E, 0x14, 0x6B, 0xE2, 0xA0, 0xFA, 0xAA, 0x82, 0xEB, 0xF4, 0xC2, 0xE2, 0x0E, 0x93, 0x76, 0x0C, 0xC4, 0x97, 0xBB, 0x13, 0x39, 0xA0, 0x0A, 0x38, 0x03, 0x65, 0x33, 0x5B, 0x1E, 0x0D, 0x0F, 0xC0, 0x18, 0xE0, 0x02, 0x68, 0x1D, 0x4E, 0xF2, 0x06, 0x4D, 0xBA, 0xC0, 0x2E, 0x9F, 0xA6, 0x8F, 0x8E, 0x20, 0x21, 0xDE, 0x92, 0x45, 0xAB, 0xC2, 0xFB, 0x32, 0x0C, 0xEA, 0x87, 0x0C, 0xA8, 0xA7, 0xD3, 0xE6, 0xE3, 0x99, 0x2B, 0x35, 0x74, 0x2F, 0x7A, 0x15, 0xB7, 0x0B, 0x4F, 0xFE, 0x40, 0x4F, 0x96, 0x7E, 0xDF, 0x0E, 0xB7, 0x43, 0xE2, 0xAC, 0x54, 0xB8, 0x00, 0x67, 0xD8, 0xC0, 0xE0, 0x3C, 0x39, 0x62, 0x67, 0x0A, 0xF0, 0x92, 0x15, 0xE4, 0x07, 0x7B, 0xB1, 0xB3, 0x7B, 0x3C, 0x28, 0xC0, 0x6C, 0x0F, 0x28, 0x9E, 0x03, 0xBC, 0x8C, 0x81, 0xA8, 0x86, 0x02, 0x96, 0x80, 0xF8, 0x1A, 0x82, 0xC8, 0x40, 0xBE, 0xC7, 0x53, 0xBF, 0xA0, 0x59, 0x60, 0x6B, 0xD3, 0xB2, 0x55, 0x58, 0x21, 0x54, 0xF0, 0x2B, 0x71, 0x83, 0xA0, 0xE8, 0xB9, 0x5F, 0x3C, 0x47, 0xC9, 0xD6, 0xEA, 0x8E, 0x35, 0x3B, 0xAF, 0x0C, 0x81, 0x2C, 0x87, 0x03, 0xD7, 0x9E, 0xE7, 0x59, 0x3A, 0xFB, 0xEC, 0x3C, 0x71, 0x1B, 0x8D, 0x4F, 0x95, 0xFD, 0x80, 0xAC, 0x8C, 0xB8, 0xDD, 0x5C, 0x00, 0x01, 0x76, 0xD6, 0xF8, 0xCB, 0x0F, 0xFA, 0xFC, 0xA8, 0x43, 0xE6, 0x4A, 0x63, 0x03, 0x42, 0x81, 0xD2, 0x75, 0xD4, 0x55, 0x06, 0x4A, 0xE6, 0x32, 0xA2, 0x9A, 0xC3, 0xEC, 0xE3, 0xAC, 0x15, 0x7A, 0x5B, 0x0F, 0xB4, 0x83, 0x66, 0xFF, 0x92, 0xD0, 0x5A, 0x51, 0xFF, 0x81, 0x6A, 0xD7, 0x30, 0xE4, 0x4B, 0x0D, 0xB9, 0xE5, 0xF7, 0xB7, 0x2D, 0x15, 0x24, 0xE5, 0xE2, 0x7B, 0x3C, 0x55, 0x44, 0xE6, 0x30, 0x02, 0xDB, 0x17, 0xF6, 0xFB, 0x06, 0x88, 0xBB, 0x99, 0x05, 0x70, 0xDE, 0x0C, 0x8F, 0x21, 0xCD, 0x8E, 0x5B, 0x4E, 0xBC, 0xBF, 0xAE, 0xFD, 0xC5, 0x5C, 0x9F, 0xCB, 0xCA, 0x93, 0xB3, 0xE4, 0x16, 0x26, 0xAE, 0x42, 0xF0, 0x98, 0x80, 0x2C, 0x4F, 0x18, 0x14, 0x36, 0x25, 0xDD, 0x9A, 0x80, 0x15, 0xE0, 0x31, 0x6F, 0x94, 0x4A, 0x40, 0x34, 0x9C, 0x01, 0x6D, 0x90, 0xF6, 0x77, 0xDE, 0xC5, 0xEF, 0x80, 0xFB, 0x5D, 0x69, 0xDE, 0x03, 0x2F, 0xD0, 0xB2, 0x92, 0x7F, 0x59, 0x0E, 0xF9, 0x52, 0x68, 0x82, 0x20, 0x97, 0xF5, 0x2A, 0x90, 0xAE, 0xDC, 0x1A, 0xB2, 0x1B, 0x5B, 0xD3, 0xC7, 0xB2, 0xF4, 0x2F, 0xAA, 0xBD, 0xC4, 0x86, 0x8D, 0xE7, 0x6D, 0xE6, 0xF4, 0x67, 0x1B, 0xF1, 0xA4, 0x8F, 0xB7, 0x8F, 0x22, 0xDF, 0x65, 0xE5, 0x4D, 0x58, 0xC9, 0x37, 0x9B, 0x37, 0x05, 0xE0, 0x7B, 0xA7, 0x0F, 0x40, 0x0E, 0xC0, 0x76, 0x55, 0xF1, 0xC3, 0x75, 0x8D, 0x9E, 0x57, 0xBE, 0xDE, 0xBC, 0x71, 0x01, 0xE2, 0x80, 0xF9, 0xBC, 0x74, 0x8A, 0x03, 0x6E, 0x8D, 0x35, 0x74, 0x96, 0x0D, 0x38, 0x05, 0xB0, 0x00, 0x51, 0x1D, 0xB4, 0xF8, 0xCC, 0xBE, 0x5C, 0x68, 0xBF, 0x3D, 0xA1, 0xE9, 0xD3, 0xBE, 0x6B, 0xA4, 0x42, 0x0E, 0xE0, 0x81, 0x9A, 0x12, 0xE5, 0xAC, 0x11, 0xC4, 0xCE, 0xA7, 0xD1, 0x7D, 0x7B, 0xE2, 0x49, 0x7C, 0x3F, 0xB7, 0xAF, 0xCC, 0x2F, 0x30, 0xD5, 0xE9, 0xEE, 0xB8, 0xA3, 0xB3, 0x66, 0xE1, 0xC0, 0x46, 0x4D, 0x8B, 0x5F, 0xC5, 0x29, 0x14, 0xD0, 0x02, 0x8C, 0x1B, 0x07, 0x78, 0x47, 0xB2, 0x21, 0xD7, 0xC0, 0xBE, 0x35, 0x27, 0x12, 0x9C, 0x65, 0xEC, 0x67, 0x8D, 0xBA, 0x57, 0xFB, 0x3D, 0xCD, 0xF9, 0x00, 0x46, 0x00, 0x37, 0x0E, 0x03, 0x64, 0x40, 0xDC, 0x95, 0x06, 0xB5, 0xD0, 0x30, 0x98, 0x18, 0x05, 0x76, 0x21, 0x68, 0x39, 0xD9, 0xA0, 0x6A, 0xEB, 0x74, 0xF7, 0x21, 0x9A, 0xFE, 0xB6, 0x33, 0x35, 0xD4, 0x76, 0x1C, 0x88, 0x4F, 0xFC, 0x2D, 0x2A, 0xEB, 0xA0, 0xC9, 0x4B, 0x5A, 0xB4, 0x4A, 0x4D, 0xD6, 0xC5, 0x9B, 0xCE, 0x92, 0xA0, 0x75, 0xD0, 0xE2, 0x06, 0x26, 0x57, 0xB4, 0x12, 0x98, 0x03, 0x5D, 0xE4, 0x15, 0x58, 0xE5, 0xB9, 0x70, 0xDE, 0x45, 0xBC, 0x5C, 0x52, 0xEA, 0x8E, 0xB4, 0x70, 0xC0, 0x6B, 0xBA, 0xA7, 0xB9, 0x4C, 0xA8, 0x01, 0x94, 0xC0, 0x21, 0x80, 0x14, 0x48, 0xED, 0xA0, 0x55, 0x47, 0xAB, 0x1B, 0x60, 0xC2, 0xFE, 0x69, 0xE0, 0xE4, 0x81, 0x9E, 0x25, 0xC3, 0x38, 0x98, 0xAA, 0x4E, 0x5A, 0x2A, 0x5E, 0x85, 0x30, 0xB3, 0xCA, 0xDA, 0x59, 0x0E, 0xB9, 0xEF, 0xFE, 0x18, 0x73, 0x89, 0xE4, 0x49, 0x32, 0xEA, 0xFE, 0x45, 0x19, 0x08, 0x07, 0x52, 0xFF, 0x06, 0x0B, 0x21, 0xD7, 0xF7, 0x7A, 0x7B, 0xB8, 0x73, 0x34, 0xDC, 0x9B, 0x20, 0xDF, 0xC4, 0x04, 0x02, 0xFB, 0x26, 0x7E, 0xC7, 0xB8, 0x0B, 0x4E, 0x17, 0xA2, 0x9A, 0x3E, 0x2E, 0xE6, 0xDB, 0xA6, 0x6D, 0xC2, 0xD7, 0xE4, 0x47, 0x61, 0x80, 0x15, 0x38, 0xB2, 0xA6, 0x4E, 0xE4, 0x9C, 0xB2, 0xCF, 0x77, 0xA5, 0xC9, 0xF6, 0x16, 0xBA, 0xDD, 0x5F, 0xF2, 0xED, 0x69, 0xC7, 0x09, 0x6D, 0x2D, 0xE1, 0x9D, 0x1A, 0xBE, 0xA3, 0x8B, 0x75, 0xA6, 0xBB, 0xCF, 0xCA, 0x72, 0x58, 0x8C, 0x17, 0xC1, 0x2D, 0x07, 0xE4, 0x6B, 0xE6, 0x74, 0x03, 0xA2, 0x80, 0xAB, 0xF7, 0x3B, 0x07, 0x28, 0xE9, 0x5C, 0x52, 0x07, 0xAD, 0x75, 0x33, 0x6F, 0xA2, 0x80, 0x9F, 0xE7, 0x79, 0xFB, 0x54, 0x58, 0xDE, 0x4B, 0x0C, 0x1B, 0x63, 0x9F, 0xE1, 0x56, 0xFF, 0xBF, 0x00, 0xA4, 0xC0, 0x91, 0xC6, 0x69, 0x10, 0x40, 0x05, 0x98, 0x02, 0x91, 0x0D, 0x5E, 0x23, 0x87, 0x56, 0x2D, 0x5E, 0x68, 0x1A, 0xBF, 0xD8, 0xDB, 0xCC, 0xAE, 0xDF, 0x3E, 0xFD, 0xD3, 0xAE, 0x82, 0x0A, 0x2A, 0x70, 0x78, 0x7B, 0x3A, 0xAC, 0xBF, 0x34, 0xB0, 0xE0, 0x2C, 0xF0, 0x22, 0x38, 0x7B, 0xA5, 0xF1, 0x50, 0xA1, 0xE7, 0x4D, 0xC1, 0xD3, 0x55, 0x32, 0xBE, 0x04, 0x37, 0x05, 0x70, 0xF2, 0xFF, 0x2F, 0x80, 0x00, 0x7C, 0xBD, 0x6B, 0x9A, 0x1D, 0x39, 0xCB, 0xB4, 0x3B, 0x15, 0x0F, 0x41, 0x9C, 0x61, 0xFE, 0x13, 0xDB, 0x3B, 0x03, 0xE4, 0x85, 0x9E, 0xF6, 0xF7, 0xFE, 0xBA, 0xAF, 0x55, 0x5D, 0x6D, 0x57, 0x61, 0xA5, 0x52, 0xE2, 0x10, 0x31, 0x83, 0x9B, 0xFD, 0x89, 0x46, 0xC1, 0xE9, 0x89, 0x32, 0xFD, 0xEC, 0xD5, 0xEC, 0x9A, 0x4B, 0x32, 0xCD, 0xDB, 0x61, 0x12, 0x3E, 0xFB, 0xC2, 0x75, 0x95, 0xAD, 0x01, 0x8F, 0xBD, 0xA8, 0x84, 0x1B, 0xA7, 0x41, 0x80, 0x35, 0x8A, 0xFE, 0xA5, 0x35, 0xC7, 0x80, 0xBF, 0x0A, 0x1E, 0x73, 0x2E, 0xB4, 0x09, 0x1A, 0x0A, 0x9E, 0x44, 0x85, 0xAD, 0xFF, 0x04, 0x06, 0x71, 0xBE, 0xA0, 0x7D, 0x59, 0x95, 0xC0, 0x39, 0x49, 0x02, 0x2F, 0xB1, 0x24, 0x9C, 0x5B, 0x68, 0x97, 0xF0, 0x8C, 0x9E, 0xE6, 0xEE, 0x33, 0x5E, 0xC9, 0x33, 0x7B, 0x31, 0xE3, 0xFC, 0x03, 0xA1, 0x3D, 0x89, 0x61, 0x09, 0xE8, 0xF9, 0x85, 0x50, 0xB7, 0x73, 0x07, 0x5E, 0x6A, 0x5B, 0x32, 0x4C, 0x73, 0x8E, 0xA5, 0x2B, 0x23, 0x6E, 0xF9, 0x9C, 0xDA, 0x04, 0x08, 0x07, 0x2C, 0x1A, 0xD4, 0x38, 0x0D, 0x01, 0xE6, 0x0A, 0x4A, 0xF1, 0x8C, 0xFA, 0x27, 0x70, 0xAF, 0xD1, 0x05, 0x04, 0x6F, 0x07, 0x74, 0x95, 0x09, 0x9A, 0x2C, 0x31, 0xAB, 0x90, 0xFA, 0xF6, 0x34, 0xCE, 0xFA, 0x52, 0x43, 0x9C, 0x04, 0xED, 0x0B, 0x17, 0x1C, 0x5F, 0xD4, 0xA0, 0x50, 0x13, 0xBC, 0x15, 0xC0, 0xE2, 0xB1, 0x14, 0xD7, 0xBA, 0x3D, 0x07, 0x63, 0x53, 0xBC, 0x4F, 0x92, 0x56, 0xFB, 0x13, 0x0F, 0x08, 0xC8, 0x09, 0xE1, 0x14, 0x5D, 0x0A, 0x90, 0xC9, 0x95, 0xE4, 0x9C, 0x55, 0xF1, 0x2E, 0xBF, 0xC3, 0xFD, 0xBB, 0x31, 0x3E, 0x1A, 0x9A, 0x00, 0xFB, 0x3E, 0xD1, 0x55, 0x0D, 0x9E, 0x06, 0x18, 0x7B, 0xD4, 0xF7, 0xAA, 0xA1, 0xCF, 0x9F, 0x12, 0xFB, 0x3B, 0xB9, 0x11, 0x34, 0x41, 0xD3, 0x25, 0x05, 0xE9, 0x85, 0xE7, 0x32, 0x9C, 0x3E, 0xB8, 0x45, 0xF7, 0x59, 0xC4, 0x4C, 0x2F, 0x8E, 0xE6, 0xFF, 0x16, 0x52, 0xD6, 0xD5, 0xA7, 0x3C, 0xE7, 0xCA, 0xDB, 0xFA, 0x64, 0x57, 0x97, 0x43, 0x18, 0x48, 0x05, 0x82, 0x00, 0x09, 0x80, 0x0A, 0x18, 0x01, 0xDE, 0x9A, 0x46, 0x3F, 0xC2, 0x27, 0x44, 0xD9, 0x6E, 0xC1, 0xCA, 0x19, 0xB1, 0x7B, 0x5E, 0xB7, 0x4C, 0x3B, 0x1F, 0x52, 0xF5, 0x2F, 0x29, 0xC8, 0x6C, 0x58, 0x23, 0x00, 0xAD, 0xC7, 0x30, 0x21, 0x1B, 0xF4, 0x48, 0x41, 0x32, 0xA0, 0xFC, 0x3C, 0x9E, 0x3C, 0x41, 0xB3, 0x3F, 0x21, 0x78, 0x27, 0x4E, 0x65, 0x5C, 0x10, 0x0A, 0xF4, 0x72, 0x1C, 0xFF, 0xEE, 0x62, 0x47, 0xDB, 0x10, 0x2F, 0xA9, 0x5F, 0xE4, 0x81, 0x60, 0xBD, 0x4E, 0x95, 0xFC, 0xBE, 0x08, 0x8E, 0x4F, 0xB5, 0xAE, 0xDF, 0x90, 0x04, 0x78, 0x43, 0x13, 0xE0, 0x81, 0x03, 0x73, 0xE1, 0x1A, 0x81, 0x50, 0x3B, 0xFB, 0xFA, 0x75, 0xF4, 0x77, 0xF4, 0x6C, 0xA7, 0xCA, 0xBA, 0x5D, 0x8E, 0x25, 0x00, 0xD5, 0x6E, 0x8B, 0x7C, 0x4B, 0xE4, 0x6C, 0x0D, 0x6D, 0x24, 0xA0, 0x01, 0xDC, 0xB2, 0x60, 0x36, 0x64, 0xEA, 0x0E, 0x80, 0xDB, 0x93, 0xEE, 0xE6, 0x69, 0x88, 0x9E, 0xA0, 0x21, 0x91, 0x56, 0x69, 0xCB, 0xB0, 0xF2, 0xBB, 0x9B, 0x2B, 0x42, 0x8F, 0xF4, 0xB8, 0x51, 0xF7, 0x67, 0x58, 0xEF, 0x45, 0xBC, 0xA4, 0xF4, 0x5D, 0x5E, 0x15, 0x13, 0x79, 0xBC, 0x9B, 0xAE, 0xAA, 0xA1, 0x01, 0x71, 0x80, 0xA4, 0x7D, 0xE4, 0x38, 0x0C, 0x8C, 0xD2, 0x44, 0x8C, 0xD2, 0xE6, 0x68, 0x1F, 0x2F, 0xD1, 0x51, 0xED, 0x2F, 0x9E, 0x49, 0xBD, 0xA4, 0xCC, 0x25, 0x67, 0xE7, 0x7F, 0xD5, 0x76, 0x53, 0x4D, 0x24, 0xE0, 0xD5, 0x08, 0x20, 0x0E, 0x90, 0xB5, 0x93, 0xDF, 0xEA, 0x8D, 0x03, 0xB0, 0x03, 0x67, 0x36, 0xB3, 0x9C, 0x4F, 0x80, 0xD1, 0x04, 0x2D, 0xBE, 0xF1, 0x75, 0x0E, 0x5F, 0x5A, 0x73, 0xE6, 0x89, 0x39, 0x4B, 0xB1, 0x7E, 0x6D, 0xC9, 0x88, 0xC3, 0xA3, 0x98, 0xA4, 0x32, 0x87, 0x59, 0x54, 0xF2, 0xDE, 0x49, 0x6C, 0x3A, 0xBD, 0xA6, 0xC6, 0xF4, 0x3C, 0x7A, 0xE8, 0xBA, 0xE7, 0x5D, 0xD5, 0x01, 0x0B, 0x40, 0xAB, 0x91, 0xAD, 0xD7, 0x3A, 0x93, 0xB1, 0x8D, 0x0C, 0x7C, 0x11, 0xFF, 0x83, 0x5D, 0x93, 0x75, 0xC9, 0xDF, 0xE3, 0x2C, 0x77, 0x98, 0x75, 0x2C, 0x6A, 0x9F, 0xB4, 0xBA, 0x07, 0x20, 0xF4, 0xE4, 0xCA, 0x7C, 0x7F, 0xD2, 0x04, 0x2A, 0xE6, 0xEA, 0xD0, 0x60, 0x60, 0x1C, 0x11, 0xE2, 0x00, 0x5A, 0x80, 0x73, 0x7F, 0x4B, 0x4E, 0xCC, 0x12, 0x26, 0xA8, 0x61, 0x2B, 0x66, 0xE1, 0x70, 0xAD, 0x34, 0x4B, 0x34, 0xE5, 0x67, 0x87, 0x2E, 0xA9, 0xFD, 0x58, 0x13, 0x2D, 0x1C, 0xAF, 0x3E, 0x1F, 0xEB, 0x2F, 0xBF, 0x79, 0xAF, 0xE6, 0x35, 0x0A, 0x1C, 0x1D, 0x0A, 0xBE, 0xE3, 0xD9, 0x15, 0x40, 0x14, 0xE0, 0x0A, 0x94, 0x5E, 0x91, 0xFF, 0x6B, 0xFB, 0xC2, 0x33, 0x00, 0x54, 0x1D, 0x2D, 0xBF, 0x55, 0xCC, 0x40, 0x98, 0x3C, 0x77, 0x91, 0xC6, 0x73, 0x5F, 0xB1, 0x83, 0x00, 0x3D, 0x80, 0x10, 0xC0, 0xD1, 0x28, 0x40, 0x1B, 0x6F, 0x37, 0xCC, 0x79, 0xDA, 0x1F, 0x5C, 0x00, 0x55, 0xC0, 0x72, 0x72, 0x56, 0x13, 0x34, 0x54, 0xD6, 0xAB, 0x74, 0x25, 0x1F, 0x99, 0xBD, 0x2F, 0x04, 0x88, 0xAE, 0x95, 0xE3, 0x05, 0xE0, 0xDE, 0x26, 0x8E, 0xA3, 0x9B, 0xF6, 0x06, 0xAD, 0x1E, 0x35, 0xAB, 0x31, 0x15, 0x9D, 0xAD, 0x49, 0xA8, 0xAF, 0xED, 0x0D, 0x61, 0x40, 0x1D, 0xC8, 0xD3, 0x71, 0x6D, 0x35, 0x0A, 0x1E, 0x81, 0x60, 0x05, 0xE6, 0x88, 0x3B, 0xCF, 0x2A, 0xCF, 0xED, 0x82, 0x6E, 0x39, 0xF0, 0xCE, 0xE2, 0xC6, 0x4D, 0xD5, 0xA6, 0x02, 0x77, 0x38, 0x28, 0x80, 0xB4, 0x06, 0x35, 0x6C, 0x87, 0xC9, 0x02, 0xC8, 0xC1, 0x01, 0x9C, 0x00, 0xBE, 0x61, 0x02, 0x58, 0x81, 0x9C, 0x63, 0x9A, 0x1E, 0x64, 0x86, 0x7A, 0x19, 0x85, 0xF8, 0x77, 0x13, 0xD0, 0xE0, 0xD6, 0x3F, 0xF6, 0x3F, 0x58, 0x76, 0xD2, 0x0F, 0xA9, 0xE2, 0x9A, 0x7F, 0x64, 0xA6, 0x3C, 0x9F, 0xE6, 0xEE, 0x49, 0xBD, 0xFB, 0x95, 0x54, 0xEA, 0xA0, 0x8D, 0x0A, 0x74, 0xC3, 0x19, 0x50, 0x07, 0x28, 0x1A, 0x04, 0xD4, 0xE8, 0x3E, 0xD3, 0xCF, 0x2A, 0x6C, 0xAC, 0x67, 0x6A, 0xBC, 0x4C, 0x6F, 0x29, 0x75, 0x99, 0x45, 0xC7, 0xFD, 0x3D, 0x2B, 0x00, 0x77, 0x40, 0x02, 0x20, 0x06, 0x8E, 0x37, 0xA4, 0x11, 0x80, 0x30, 0x10, 0xB9, 0xA7, 0x9A, 0xAB, 0x80, 0x68, 0xD8, 0x13, 0x3B, 0x9D, 0xCA, 0xA8, 0x4E, 0xD0, 0xE8, 0x4F, 0x7D, 0xE7, 0xDE, 0xEE, 0x7F, 0x49, 0xFD, 0x5E, 0x00, 0xC6, 0x8C, 0x7B, 0x41, 0x1A, 0x36, 0x52, 0x31, 0xDC, 0xA5, 0x53, 0xF0, 0xF7, 0xF4, 0xBC, 0x4A, 0xFE, 0xB3, 0x18, 0x35, 0x7F, 0x45, 0xC8, 0xB3, 0x73, 0x30, 0x90, 0x04, 0xE8, 0x28, 0xDC, 0xBC, 0xAD, 0xCC, 0xF6, 0xFC, 0x0F, 0x05, 0x68, 0xEC, 0xA4, 0x2E, 0xD1, 0xAC, 0xE5, 0xDD, 0xEF, 0x57, 0x04, 0xC4, 0x69, 0x08, 0xE0, 0xD5, 0x38, 0x80, 0x65, 0x23, 0x00, 0x3F, 0xCF, 0x14, 0x76, 0x83, 0x15, 0xA0, 0xA7, 0x59, 0x24, 0x1B, 0x61, 0x5B, 0x34, 0x52, 0xCE, 0x04, 0x8D, 0xBF, 0x97, 0xA7, 0xB0, 0x7E, 0x61, 0x52, 0x3B, 0x1F, 0x9C, 0x30, 0xED, 0x49, 0x1E, 0x18, 0xE4, 0x13, 0xC7, 0x10, 0x92, 0x08, 0x54, 0x3E, 0x42, 0x27, 0x8D, 0xF6, 0x24, 0x39, 0x26, 0x25, 0xBD, 0x66, 0xE9, 0x20, 0x52, 0xB0, 0x8B, 0x51, 0x45, 0x80, 0xCA, 0x38, 0xBE, 0x6E, 0x43, 0xF1, 0xC9, 0xBF, 0x30, 0xF5, 0x42, 0x95, 0x9D, 0xD4, 0x3D, 0x31, 0x01, 0x9D, 0x47, 0x70, 0x35, 0x5C, 0x89, 0x3E, 0x07, 0xFB, 0xD3, 0xA8, 0x86, 0xFC, 0x0B, 0x8F, 0x4D, 0x02, 0x3D, 0xFA, 0x55, 0xE2, 0xC0, 0xB4, 0x27, 0x66, 0x00, 0xDE, 0xC8, 0xDB, 0x53, 0x33, 0x41, 0xFB, 0xF5, 0xDA, 0x7E, 0x2F, 0x64, 0x42, 0xBD, 0xB3, 0x20, 0x60, 0x10, 0xD1, 0x8D, 0xE9, 0xCC, 0xF8, 0x23, 0xDD, 0x31, 0xFC, 0x56, 0xF1, 0x5D, 0x08, 0xDE, 0x95, 0x76, 0xDF, 0xF2, 0x93, 0x9D, 0x0F, 0x7B, 0x3C, 0x98, 0x63, 0xC0, 0x80, 0xD8, 0xEA, 0x80, 0x74, 0x06, 0xF2, 0x36, 0x88, 0x3D, 0x03, 0xB3, 0x16, 0xAB, 0xC3, 0x6F, 0x57, 0xDB, 0xE4, 0xEF, 0x15, 0xFB, 0xBD, 0x65, 0x1A, 0xC0, 0x02, 0x9C, 0x6C, 0x48, 0x83, 0x1A, 0xCF, 0x70, 0x90, 0xBD, 0x1A, 0xF6, 0x8F, 0x50, 0x9F, 0xD8, 0xA3, 0x13, 0xA0, 0x40, 0xF2, 0x04, 0x4D, 0x97, 0xEF, 0x00, 0x7D, 0xCF, 0x65, 0x21, 0xBB, 0x01, 0x81, 0x87, 0x44, 0xD9, 0x5A, 0x15, 0x27, 0x30, 0x92, 0x5E, 0x70, 0x0A, 0x3F, 0xD4, 0x37, 0x68, 0x73, 0x71, 0xD6, 0x67, 0x26, 0xAE, 0x66, 0x0A, 0x8E, 0x80, 0xD3, 0xCF, 0x9E, 0xC9, 0xEE, 0xFE, 0xD2, 0x86, 0x3D, 0xB3, 0x9F, 0xAE, 0xFD, 0x2D, 0x6B, 0xCA, 0xCB, 0xEE, 0xE9, 0xE9, 0xBD, 0x54, 0xB3, 0x01, 0x34, 0x9F, 0xAA, 0x91, 0x00, 0x55, 0xC3, 0x1E, 0x04, 0x20, 0x8D, 0x78, 0xBD, 0x25, 0x1C, 0x88, 0x7C, 0x14, 0x25, 0xFD, 0x99, 0x2B, 0x96, 0x09, 0x9A, 0xA1, 0x03, 0x92, 0x13, 0xAF, 0x2D, 0x0F, 0x08, 0xF5, 0x29, 0x46, 0x30, 0x0E, 0xCA, 0x4F, 0x64, 0xDA, 0x13, 0x7C, 0x31, 0x55, 0x87, 0xDA, 0x76, 0x51, 0xBB, 0xD3, 0x4A, 0x6F, 0x16, 0xF0, 0x3A, 0x7D, 0xB1, 0xEE, 0x84, 0xF1, 0xF8, 0xBB, 0x84, 0x3C, 0xB7, 0x77, 0x03, 0x64, 0xEE, 0xEB, 0xBE, 0xA7, 0xB7, 0x5D, 0xE6, 0x4F, 0x59, 0x3A, 0x9A, 0xA5, 0xBB, 0x2B, 0x97, 0x6B, 0x5E, 0x04, 0xFB, 0x60, 0x4F, 0x07, 0x38, 0xD6, 0xC8, 0x0D, 0x32, 0x40, 0x02, 0x08, 0x03, 0xAA, 0x1A, 0x0A, 0x44, 0x01, 0x16, 0x80, 0x12, 0x60, 0x53, 0xD1, 0xB8, 0x2B, 0xCD, 0xBF, 0xFE, 0x97, 0x2A, 0x98, 0xB0, 0xBB, 0xC3, 0x91, 0x8C, 0x03, 0x5A, 0x09, 0xC7, 0x02, 0x5B, 0x2F, 0x39, 0xDE, 0xC4, 0xEE, 0xDF, 0xCE, 0x4D, 0x7C, 0x95, 0xF9, 0xC0, 0xF3, 0xCC, 0x5E, 0x4C, 0xBE, 0x99, 0x9E, 0x79, 0x4B, 0x97, 0x06, 0x03, 0xA2, 0xFB, 0x08, 0x39, 0x53, 0x77, 0x3A, 0x8F, 0x67, 0x4E, 0x65, 0xD4, 0x3B, 0x4C, 0xD3, 0x23, 0xE5, 0x3D, 0xE6, 0xF9, 0x6B, 0xE9, 0xB1, 0xC9, 0xAE, 0x03, 0x38, 0xB5, 0x37, 0x04, 0x88, 0x86, 0x1F, 0xC0, 0xAC, 0x21, 0x0D, 0x07, 0x42, 0xB7, 0xC6, 0x82, 0xF0, 0xE3, 0x73, 0x98, 0x6F, 0x8F, 0x42, 0x63, 0xBE, 0xF3, 0x4C, 0xD0, 0xE2, 0x6B, 0x50, 0xB6, 0x43, 0x28, 0xA9, 0xB3, 0x7C, 0xE7, 0x34, 0x52, 0x82, 0xE4, 0xB1, 0x58, 0xE7, 0xD8, 0xA9, 0x45, 0x35, 0xB4, 0xA5, 0x20, 0xFC, 0xFA, 0xFB, 0x7F, 0x9C, 0x5C, 0xFD, 0xEC, 0xC1, 0x35, 0x69, 0x9F, 0xB9, 0x18, 0x90, 0xF5, 0xEC, 0x30, 0x03, 0x62, 0x5B, 0x57, 0x45, 0x19, 0xE0, 0x03, 0xDC, 0x1B, 0x3A, 0xED, 0x41, 0xE4, 0xF1, 0xC3, 0xD5, 0x9C, 0xCA, 0xD6, 0xCE, 0x13, 0xC9, 0xEC, 0x77, 0xF3, 0xC8, 0x03, 0xEE, 0x1B, 0x96, 0xFF, 0x80, 0x2B, 0x30, 0xAF, 0x21, 0x6D, 0x44, 0xC3, 0x1B, 0xCA, 0x7B, 0x37, 0x49, 0xED, 0x4F, 0x04, 0xF8, 0x0D, 0x5A, 0xFE, 0x71, 0x34, 0x77, 0xCF, 0xE1, 0x16, 0xC7, 0xA5, 0xA3, 0x5D, 0x8C, 0x32, 0x84, 0x89, 0xAD, 0x6F, 0x80, 0xD6, 0xEE, 0xDC, 0x08, 0x56, 0xFD, 0x53, 0xA1, 0x2F, 0x67, 0xEC, 0x2A, 0xE6, 0xA0, 0x65, 0xAD, 0xCD, 0xD4, 0x48, 0x02, 0xC2, 0x01, 0xAB, 0xC6, 0xD2, 0xB5, 0xC2, 0x5D, 0x1E, 0x37, 0x2D, 0xC5, 0xA7, 0x50, 0x7C, 0x8B, 0x4C, 0x3B, 0x25, 0xFF, 0x9C, 0x8B, 0xF4, 0x1A, 0x1C, 0x9C, 0xD8, 0x1D, 0xBB, 0xE6, 0x00, 0xD1, 0x2C, 0x5B, 0x20, 0xAC, 0xC1, 0x8D, 0xD8, 0xD5, 0x12, 0x0D, 0x20, 0x18, 0xF0, 0x04, 0xEC, 0x29, 0xA9, 0x9F, 0x02, 0x98, 0x80, 0xA4, 0x0E, 0x5A, 0x7D, 0xB2, 0x86, 0x8A, 0x73, 0xAC, 0xAA, 0x68, 0xFB, 0x05, 0xD8, 0xF7, 0x78, 0x66, 0x57, 0x52, 0x84, 0xA8, 0xC5, 0xCA, 0xAA, 0x6F, 0x04, 0x09, 0xF7, 0xD3, 0x77, 0xDA, 0x73, 0xB7, 0xAD, 0xD3, 0x1C, 0xE2, 0xE3, 0x76, 0xC4, 0x2B, 0x01, 0x75, 0x80, 0x20, 0x40, 0x0A, 0x20, 0x6B, 0x14, 0x60, 0xA7, 0x31, 0x32, 0xAE, 0xFA, 0x13, 0xF9, 0xD1, 0xDB, 0xD4, 0x20, 0xBE, 0x3B, 0x76, 0xCF, 0xDE, 0x94, 0xDC, 0x01, 0x49, 0x80, 0xA2, 0xC1, 0x0D, 0x6A, 0x38, 0x20, 0x8D, 0x50, 0xA0, 0xBC, 0xC1, 0x40, 0x24, 0x60, 0x06, 0x28, 0x01, 0xB3, 0x96, 0xEF, 0xE1, 0xD6, 0xE0, 0x43, 0x43, 0xB0, 0xC7, 0x66, 0x16, 0xD3, 0xD5, 0x6A, 0x65, 0x2C, 0xD8, 0x97, 0x3B, 0x04, 0x1E, 0x23, 0xFF, 0x16, 0x3F, 0xCD, 0xEE, 0x3C, 0xCF, 0x85, 0x5D, 0xAF, 0x98, 0x23, 0xFF, 0x86, 0x38, 0xE1, 0x60, 0x05, 0xCF, 0x11, 0x05, 0xA6, 0xB9, 0xC6, 0x46, 0x56, 0x2D, 0x00, 0xE5, 0xDF, 0xDA, 0x32, 0x04, 0x9B, 0xF5, 0x31, 0x22, 0x9A, 0xF2, 0x4A, 0xFC, 0xED, 0x33, 0xA5, 0xDF, 0xBC, 0x82, 0x5C, 0x8F, 0x91, 0x6C, 0x98, 0x01, 0xA2, 0x00, 0x57, 0x23, 0x01, 0x11, 0xC0, 0x7C, 0xA7, 0xDC, 0x49, 0x1B, 0x93, 0x44, 0x4E, 0x20, 0xCF, 0xD3, 0xB1, 0x4B, 0xF3, 0xC2, 0xEA, 0xA0, 0xD1, 0x37, 0xEE, 0x99, 0x93, 0xE4, 0x98, 0x9B, 0x60, 0x05, 0xF4, 0x6D, 0xA9, 0xB0, 0xC4, 0xFA, 0xFE, 0xE4, 0xCA, 0xBF, 0xBB, 0x67, 0xE9, 0xDB, 0x11, 0xCF, 0xF5, 0x5C, 0xD8, 0x8F, 0x6C, 0x51, 0x60, 0x4A, 0xC0, 0x0F, 0x60, 0x0D, 0x11, 0x80, 0x13, 0x08, 0xDE, 0x86, 0x7F, 0xCE, 0x00, 0xF7, 0x77, 0xFA, 0x98, 0x08, 0xFA, 0x96, 0xA6, 0x3E, 0xBA, 0x3D, 0x58, 0xCA, 0x00, 0x0B, 0x80, 0x1D, 0x38, 0xD6, 0x38, 0x0F, 0x0C, 0xE0, 0x86, 0x15, 0x90, 0x07, 0x88, 0x00, 0xDC, 0x00, 0x0D, 0x40, 0xE6, 0x53, 0x01, 0xA5, 0x1D, 0x34, 0xFE, 0x4E, 0x17, 0x7C, 0xBB, 0x85, 0xA6, 0xFE, 0xE7, 0x18, 0x08, 0x16, 0xC6, 0x63, 0x25, 0x86, 0x7A, 0x5A, 0xE5, 0x87, 0x3A, 0xF2, 0x6D, 0xFC, 0xF9, 0x78, 0x14, 0xDF, 0x9B, 0x6F, 0xFE, 0x02, 0xC2, 0xD1, 0x1B, 0x15, 0x9E, 0x47, 0x88, 0xE6, 0x17, 0xC0, 0xBD, 0xDE, 0xCA, 0x80, 0x19, 0x3D, 0x56, 0x86, 0xE4, 0x57, 0x75, 0x8D, 0x9A, 0xA6, 0x24, 0x36, 0x9E, 0x3F, 0xFD, 0x87, 0x8D, 0xC4, 0x98, 0x8C, 0xC9, 0x75, 0x75, 0xAC, 0x73, 0xB7, 0x8C, 0x48, 0xCC, 0xAE, 0x07, 0x04, 0x01, 0x6E, 0x1B, 0x31, 0x2A, 0xA0, 0x0C, 0x68, 0x02, 0x21, 0x8D, 0x03, 0x98, 0x01, 0x22, 0x00, 0x15, 0x20, 0x0C, 0x94, 0x75, 0xCC, 0x64, 0x0D, 0x2E, 0x96, 0xB6, 0x70, 0x82, 0x41, 0x5F, 0xC2, 0xD2, 0x70, 0x1C, 0x2C, 0x46, 0x15, 0x87, 0x14, 0x05, 0x1B, 0xC7, 0xD9, 0x76, 0x5E, 0x9E, 0x2A, 0xAF, 0x2B, 0x76, 0xEC, 0xBC, 0x9D, 0x0C, 0x18, 0x38, 0xB4, 0xFB, 0x61, 0xB9, 0x1E, 0x0F, 0xDE, 0x55, 0x10, 0xD1, 0xDB, 0x0B, 0x6A, 0xCF, 0xE5, 0x8F, 0x9F, 0x71, 0x44, 0x4B, 0x40, 0x05, 0x78, 0x8D, 0xCC, 0x49, 0x1A, 0xFC, 0x2F, 0x38, 0x20, 0x8F, 0x51, 0x72, 0x45, 0xE3, 0x00, 0xC1, 0x80, 0x3A, 0x20, 0x8F, 0x55, 0x48, 0xDD, 0x2D, 0x4D, 0xBF, 0x64, 0x37, 0x7F, 0x99, 0x5A, 0xF8, 0xCF, 0x60, 0x82, 0xDC, 0xF4, 0x7B, 0x3A, 0x0D, 0x55, 0x4F, 0x66, 0x4B, 0xDC, 0xFD, 0x2D, 0x71, 0xCA, 0x8A, 0x5C, 0x65, 0x15, 0xE7, 0x25, 0x9E, 0x36, 0xE9, 0xCD, 0x11, 0xC2, 0xC0, 0xE4, 0x18, 0xE0, 0x0A, 0xC8, 0xBC, 0xA9, 0x1C, 0x38, 0x4F, 0xC9, 0x85, 0xA9, 0xA1, 0x7F, 0x3F, 0xD5, 0xDD, 0x7B, 0x55, 0x76, 0xF3, 0x9F, 0x3E, 0xC3, 0x65, 0x69, 0x8D, 0xD7, 0x54, 0xEF, 0x34, 0x12, 0x70, 0x6B, 0x24, 0x10, 0xFA, 0xBA, 0x63, 0x02, 0xE6, 0x8D, 0xF3, 0xE4, 0x48, 0x0C, 0x38, 0x07, 0x20, 0x06, 0x2C, 0x26, 0x68, 0xF6, 0x27, 0x1D, 0x05, 0xBC, 0xF8, 0x72, 0xD8, 0xFA, 0x6D, 0x70, 0xC6, 0x28, 0xB3, 0x1F, 0x37, 0xD4, 0x97, 0x24, 0xFB, 0xA8, 0xD8, 0xAE, 0x81, 0xA5, 0x73, 0xF5, 0x7C, 0x7A, 0xBB, 0x97, 0x81, 0x84, 0xDD, 0x04, 0xBC, 0x19, 0xE0, 0x0D, 0xAE, 0x2D, 0x42, 0x3B, 0xF9, 0xB7, 0xE2, 0x06, 0x3D, 0xBF, 0x35, 0x03, 0x87, 0xF7, 0xF9, 0xD5, 0x0D, 0x20, 0x7F, 0x4A, 0x27, 0x05, 0x58, 0xEE, 0x51, 0x45, 0x49, 0x40, 0x0B, 0x30, 0x6B, 0x24, 0xE0, 0x02, 0x24, 0x6F, 0x39, 0x30, 0xC9, 0x86, 0x3C, 0x06, 0xF1, 0x01, 0xA4, 0x00, 0x35, 0xDF, 0x79, 0x83, 0xE6, 0x5F, 0x2F, 0x5F, 0x9C, 0xFC, 0xD4, 0x99, 0x2C, 0xFD, 0x3B, 0x6A, 0x38, 0x63, 0x82, 0x5D, 0x83, 0x31, 0x17, 0xC3, 0x85, 0xDF, 0x39, 0x15, 0xAF, 0x5E, 0x3F, 0x4B, 0xC9, 0x24, 0xDE, 0x24, 0xC7, 0x36, 0x5C, 0x2B, 0x00, 0xA7, 0x03, 0x1E, 0x7D, 0xBE, 0x0F, 0x72, 0xB6, 0x32, 0x0D, 0x37, 0x24, 0xFB, 0x04, 0xC9, 0x80, 0xF9, 0x7C, 0x9A, 0x4B, 0xEA, 0x6C, 0x97, 0xBB, 0xDC, 0x59, 0x0C, 0x48, 0x01, 0xF6, 0xE8, 0x6A, 0x4B, 0x3D, 0x72, 0xBE, 0xDC, 0x30, 0x20, 0x08, 0x28, 0xDE, 0x9D, 0x47, 0xA6, 0x8F, 0x92, 0x89, 0x00, 0xA7, 0xF6, 0x77, 0x9E, 0x57, 0xC9, 0xC4, 0x02, 0xD3, 0x9E, 0x4C, 0x9F, 0x78, 0x9A, 0x10, 0xEE, 0xEB, 0xD1, 0x43, 0x3E, 0x22, 0x8A, 0x69, 0x4B, 0x22, 0x3C, 0x17, 0x9A, 0x5F, 0xD0, 0x58, 0x15, 0xB3, 0x77, 0xEF, 0x4A, 0xA3, 0xF8, 0x95, 0x60, 0xF3, 0x5A, 0xF8, 0x96, 0x77, 0xD0, 0xF8, 0x19, 0xEC, 0xD4, 0x7D, 0x86, 0x3F, 0x4F, 0xB7, 0x61, 0xAD, 0xA0, 0xE5, 0xBD, 0xD2, 0x5B, 0xEE, 0xC6, 0x52, 0x7F, 0xBA, 0xDD, 0x59, 0x01, 0xA7, 0x9D, 0x92, 0xE6, 0x86, 0x15, 0x10, 0x01, 0xA4, 0x01, 0x35, 0x9D, 0x59, 0x8D, 0xFB, 0xE3, 0x7A, 0xE3, 0xEC, 0xAB, 0xA7, 0x06, 0xC0, 0x0A, 0xE8, 0x79, 0x8F, 0x69, 0xF9, 0x3D, 0x9E, 0xAC, 0x06, 0xEF, 0x70, 0xC2, 0x14, 0x76, 0x95, 0xFF, 0x11, 0xE4, 0x35, 0xE0, 0x9A, 0x45, 0x78, 0x2E, 0x89, 0xB4, 0xFF, 0xBA, 0x44, 0xB0, 0xDE, 0x61, 0x6C, 0x7E, 0xA6, 0x08, 0xE6, 0x92, 0x52, 0x72, 0xB6, 0x74, 0x86, 0x01, 0x87, 0xB6, 0x9A, 0xA1, 0xC9, 0xD3, 0x0C, 0xDC, 0xF0, 0xDC, 0x6B, 0x2B, 0x64, 0x6F, 0x5F, 0x67, 0x92, 0x81, 0x6F, 0x57, 0x01, 0xEF, 0x0B, 0x25, 0x35, 0x38, 0x00, 0xB1, 0x46, 0x01, 0x6A, 0x80, 0xCF, 0x01, 0x89, 0x01, 0xA9, 0x06, 0x6F, 0x55, 0xF8, 0x74, 0xC0, 0x1B, 0xA9, 0x53, 0x76, 0x98, 0xA0, 0xD5, 0x77, 0x8B, 0x2A, 0xF5, 0xCE, 0x41, 0x16, 0xAA, 0x9E, 0x26, 0x5F, 0x3A, 0x4D, 0xA5, 0x30, 0x12, 0x40, 0x81, 0x4A, 0xC1, 0x88, 0x80, 0x74, 0xE2, 0x76, 0x8D, 0x5E, 0x6C, 0xC5, 0xB9, 0x9B, 0x7C, 0xF4, 0x9F, 0xCA, 0x92, 0xDE, 0xA3, 0x63, 0xF0, 0x34, 0x61, 0x01, 0xA4, 0x7B, 0x1A, 0x49, 0x19, 0xC8, 0xB9, 0xB9, 0xDA, 0xD6, 0xD3, 0x11, 0x2C, 0x54, 0x59, 0xE2, 0x2C, 0x71, 0x3B, 0x18, 0x6B, 0x8D, 0xCA, 0xE7, 0x15, 0x62, 0x22, 0x07, 0xFC, 0x00, 0xE9, 0xCF, 0xAA, 0x3F, 0x01, 0x88, 0x00, 0xF7, 0xA5, 0x34, 0xAD, 0xA4, 0x05, 0xA4, 0x00, 0x96, 0x4F, 0x73, 0xC0, 0x14, 0xBF, 0x14, 0x41, 0xF3, 0x9F, 0x35, 0xF1, 0xF7, 0x8F, 0xCB, 0x7F, 0x5C, 0xA1, 0x03, 0xAF, 0xDD, 0xBA, 0x8E, 0x2A, 0xBB, 0x23, 0xD1, 0xAB, 0xF9, 0xAD, 0x3B, 0x57, 0xDA, 0x9D, 0x1C, 0xBA, 0x72, 0x90, 0xBC, 0x05, 0xDD, 0xB0, 0x2D, 0x00, 0x94, 0x5B, 0x75, 0xD7, 0x18, 0xA0, 0xB3, 0xFF, 0x05, 0x4F, 0x00, 0x51, 0x5B, 0x40, 0x61, 0xD6, 0xD6, 0xF6, 0xFD, 0x94, 0x9B, 0x16, 0x13, 0x7F, 0x2D, 0x40, 0xF0, 0x45, 0x1A, 0x38, 0x70, 0xB2, 0xE1, 0x0F, 0x5E, 0xB5, 0xB5, 0xFA, 0x57, 0x0E, 0xB2, 0x9E, 0xA9, 0x85, 0x27, 0xBD, 0x19, 0xD3, 0xA6, 0xEC, 0xF4, 0xA5, 0xD3, 0x8A, 0x30, 0xDF, 0xC9, 0x1C, 0x6D, 0x4E, 0x24, 0x38, 0xA7, 0x1D, 0x85, 0x0D, 0xD2, 0xA9, 0x3F, 0xC8, 0xE2, 0x3A, 0x8E, 0xE0, 0x14, 0xA3, 0x70, 0xFE, 0x66, 0xBB, 0x1F, 0x99, 0xBE, 0xE9, 0x66, 0x51, 0x9E, 0x33, 0xFC, 0xD6, 0xFA, 0x32, 0x1B, 0xCB, 0x32, 0x40, 0x05, 0x30, 0xEE, 0x35, 0xB9, 0x1A, 0x27, 0xE5, 0x5E, 0x67, 0xA6, 0x41, 0xFD, 0xB4, 0x63, 0xDE, 0x73, 0xD9, 0x24, 0x06, 0x8E, 0x02, 0x9A, 0x40, 0x38, 0x90, 0x8D, 0xD2, 0x47, 0x7D, 0xDB, 0x00, 0x11, 0x20, 0xCF, 0xE4, 0x33, 0x1A, 0xF3, 0x45, 0x7B, 0x64, 0x87, 0x12, 0xD0, 0xC9, 0x75, 0x9D, 0x09, 0x1A, 0x2F, 0xD7, 0x40, 0x56, 0x18, 0x15, 0x5B, 0x55, 0x7B, 0x38, 0x31, 0xDE, 0xE7, 0x59, 0xAD, 0x04, 0xFB, 0xA1, 0xAC, 0xBE, 0x95, 0x26, 0xD3, 0x68, 0x25, 0xD9, 0xAC, 0x38, 0x8F, 0xFB, 0xFA, 0xE4, 0xDE, 0xA5, 0xC1, 0x00, 0x3D, 0x83, 0xFB, 0x5C, 0xC0, 0x31, 0x40, 0x64, 0xE7, 0xEC, 0xF3, 0x00, 0xF7, 0xF0, 0x17, 0x4F, 0xAB, 0xCB, 0x01, 0xCE, 0x88, 0x98, 0x3C, 0xCA, 0x2F, 0x2C, 0x80, 0x78, 0x83, 0x1A, 0x07, 0xE0, 0xDA, 0x5F, 0x34, 0x01, 0x2A, 0x1E, 0x83, 0x4A, 0xFF, 0x3F, 0x0C, 0x2A, 0x79, 0xBB, 0x7A, 0x9A, 0xCB, 0xDF, 0xA8, 0x7D, 0xC7, 0x4A, 0xFB, 0x5E, 0x9F, 0x45, 0x8A, 0x86, 0xAB, 0x52, 0xF8, 0x03, 0xA5, 0xA0, 0x05, 0x4C, 0x12, 0xA7, 0xC4, 0x88, 0xFD, 0x26, 0x38, 0xCB, 0x13, 0x5B, 0xFE, 0x4E, 0xD7, 0xCF, 0x24, 0x73, 0x00, 0xA5, 0x80, 0x33, 0x70, 0x9E, 0x21, 0xBC, 0x3A, 0x4F, 0x39, 0xB2, 0x00, 0x5D, 0xCE, 0x15, 0x7A, 0x4F, 0x68, 0xC9, 0xC0, 0x59, 0x11, 0xC1, 0xF4, 0x1D, 0x50, 0xCF, 0xB1, 0x3F, 0x1A, 0x13, 0xDE, 0x7C, 0xF0, 0x64, 0xC4, 0x5D, 0x80, 0x8C, 0xC6, 0xEB, 0x81, 0xDA, 0x60, 0x06, 0xC4, 0x80, 0x8C, 0x09, 0x9A, 0x7E, 0xDA, 0xAC, 0x69, 0x0C, 0xED, 0x24, 0xB6, 0x35, 0x1A, 0x15, 0x3C, 0x07, 0x7B, 0xFE, 0xC0, 0x5E, 0x78, 0xE6, 0x6A, 0x2E, 0x9D, 0x4F, 0xDD, 0x93, 0xD7, 0x58, 0x11, 0xF4, 0x45, 0x77, 0x07, 0xA4, 0x3A, 0x40, 0x82, 0x2F, 0x8E, 0x59, 0xC1, 0x24, 0x21, 0x5D, 0x81, 0x73, 0x76, 0x5F, 0x5A, 0x3E, 0x29, 0x0C, 0xF2, 0x49, 0x5A, 0xCC, 0x38, 0xC9, 0x0C, 0xE0, 0x3F, 0x7E, 0xE2, 0xFA, 0x34, 0x13, 0xDB, 0x64, 0x42, 0x01, 0x61, 0x40, 0x15, 0xB0, 0x46, 0x8C, 0x89, 0x4B, 0x83, 0xA9, 0xC1, 0x00, 0x19, 0x70, 0x06, 0xA7, 0x91, 0x80, 0x56, 0x07, 0xAD, 0xFD, 0xB4, 0x24, 0xD1, 0xF2, 0xCA, 0x33, 0xD1, 0x8B, 0x0B, 0x7B, 0x99, 0x77, 0x1E, 0xAC, 0xDA, 0xC7, 0xD7, 0x21, 0x99, 0x2D, 0xB6, 0x32, 0x43, 0xB5, 0xDD, 0x1B, 0xE6, 0x69, 0xC9, 0x6B, 0xC7, 0x96, 0x67, 0xAE, 0xDA, 0x00, 0x77, 0x63, 0xC7, 0x64, 0x1D, 0x5D, 0xB6, 0x5A, 0x7C, 0x28, 0x50, 0xB1, 0x95, 0xE4, 0xA5, 0x33, 0x43, 0x99, 0x7D, 0x45, 0xD7, 0xBF, 0x72, 0x59, 0x94, 0x93, 0xD4, 0xBD, 0x17, 0xF6, 0xD1, 0x1F, 0x3B, 0x0C, 0x64, 0xBB, 0x83, 0xEB, 0x01, 0x42, 0x80, 0xBC, 0x56, 0x10, 0x80, 0x1E, 0x60, 0x8C, 0xAE, 0xC9, 0x1A, 0xB2, 0xBB, 0x27, 0xF2, 0x00, 0xF1, 0x7C, 0xA7, 0x46, 0xC7, 0xCC, 0xFF, 0xD8, 0x17, 0x33, 0xFF, 0xD2, 0x0B, 0x3A, 0x7B, 0x3E, 0x07, 0xC4, 0x95, 0x53, 0xFB, 0xB2, 0x28, 0x2D, 0xCF, 0x68, 0x93, 0x93, 0xDD, 0x6E, 0x6E, 0xB9, 0x9A, 0x47, 0xD1, 0xC5, 0xDD, 0xF9, 0x42, 0xDF, 0x5D, 0xB5, 0xE5, 0x40, 0xCC, 0x6F, 0xFD, 0xF8, 0xD1, 0xD0, 0x08, 0xE7, 0x13, 0xC0, 0xCB, 0x86, 0x1A, 0x4D, 0x15, 0x58, 0xDA, 0x1F, 0xE4, 0xEF, 0x2A, 0x9A, 0xC6, 0x40, 0x9F, 0x3C, 0x35, 0xE0, 0xE7, 0x1F, 0x53, 0x28, 0x94, 0x80, 0x38, 0xA0, 0x06, 0x58, 0x23, 0x79, 0x0F, 0xB9, 0x1B, 0x01, 0x1A, 0x80, 0x08, 0x30, 0x6D, 0xD1, 0xE5, 0x33, 0xCF, 0x05, 0xD8, 0x2C, 0xB4, 0x40, 0x0E, 0x32, 0x0B, 0x39, 0xC0, 0x1C, 0x5D, 0xC6, 0x40, 0x89, 0x20, 0x08, 0x89, 0x7E, 0xD2, 0x6E, 0xCC, 0x4B, 0xFC, 0x8B, 0x79, 0xDE, 0x3A, 0xCA, 0xB5, 0xA5, 0xA1, 0xC7, 0x78, 0xFE, 0xF6, 0x4B, 0x59, 0x07, 0x6B, 0x72, 0x97, 0x71, 0x3B, 0x88, 0x6E, 0x27, 0x50, 0x67, 0xC0, 0xB9, 0xBB, 0x8B, 0xA2, 0xE1, 0x0C, 0xC8, 0xFC, 0xFB, 0x07, 0x62, 0x3D, 0x42, 0x28, 0x1A, 0x3F, 0xAF, 0x6F, 0xBD, 0x4F, 0x57, 0x48, 0x83, 0x26, 0xBA, 0xBB, 0xAF, 0x4B, 0x1E, 0x9F, 0x38, 0x3F, 0x8D, 0x9A, 0xCD, 0x00, 0x50, 0x07, 0xA2, 0xE1, 0x09, 0x68, 0x01, 0xCC, 0xFF, 0xE8, 0x87, 0x0F, 0xEF, 0x98, 0x25, 0x54, 0x6D, 0x39, 0xDA, 0x0D, 0xBE, 0x1B, 0x0F, 0x0C, 0x85, 0x63, 0x61, 0xEB, 0xD9, 0x32, 0xC5, 0x3F, 0xBB, 0x67, 0xAF, 0x8C, 0xC2, 0x42, 0x7B, 0xAF, 0x9E, 0x42, 0x8F, 0x54, 0xC2, 0xF4, 0x05, 0x8D, 0x19, 0xA0, 0x35, 0x5C, 0x80, 0xD3, 0x8F, 0x82, 0xD4, 0x7E, 0x06, 0x54, 0x01, 0x9E, 0x95, 0x79, 0x80, 0x63, 0x93, 0xE5, 0x1A, 0x61, 0xD7, 0x11, 0x9E, 0xDB, 0xD5, 0x40, 0xE6, 0xED, 0x32, 0x45, 0x06, 0x08, 0x35, 0x02, 0x50, 0x03, 0xEC, 0x34, 0x12, 0x48, 0x19, 0xB9, 0x67, 0x40, 0x09, 0x90, 0x6A, 0x1C, 0x80, 0x04, 0x38, 0xB4, 0x3F, 0x39, 0x75, 0xD0, 0xEA, 0x8F, 0x39, 0x0A, 0x9C, 0xFC, 0x65, 0x27, 0x7C, 0x96, 0x06, 0xFC, 0x29, 0xDD, 0x7B, 0x45, 0x4A, 0x4F, 0xB9, 0x00, 0xD1, 0xFA, 0x12, 0xF1, 0x6A, 0xE6, 0x88, 0x3E, 0xCA, 0xA3, 0x4A, 0xDB, 0x75, 0xFF, 0x48, 0x63, 0xFA, 0xB6, 0xAF, 0x97, 0x20, 0xA0, 0x05, 0x84, 0x77, 0x7C, 0x26, 0xB3, 0x28, 0x00, 0xCB, 0xCF, 0xF2, 0x02, 0x37, 0xE7, 0x7E, 0x37, 0x4C, 0xEE, 0x7A, 0x64, 0x14, 0x80, 0x13, 0x80, 0x09, 0x90, 0x53, 0x6B, 0x61, 0x80, 0xB4, 0x91, 0x00, 0x17, 0x60, 0xF3, 0x1A, 0x20, 0x80, 0xB3, 0x21, 0xC0, 0x89, 0x27, 0xD9, 0xDD, 0x88, 0x7E, 0x45, 0x08, 0x23, 0x68, 0xD1, 0x8F, 0x87, 0x19, 0x34, 0x88, 0x94, 0x57, 0x81, 0xA0, 0x12, 0xCF, 0xE3, 0xD4, 0x82, 0x2C, 0x04, 0xBB, 0xA4, 0xEB, 0xEE, 0xE8, 0x7B, 0x5F, 0x03, 0xB7, 0x9F, 0x6C, 0xFA, 0xA5, 0xBC, 0x0B, 0x04, 0x03, 0x19, 0x1F, 0x06, 0x80, 0x05, 0xDF, 0x62, 0x09, 0x1C, 0x69, 0x4B, 0x1F, 0xDA, 0xEF, 0x06, 0xAE, 0x9F, 0x3A, 0x24, 0xDF, 0x9F, 0x82, 0xFB, 0x91, 0x65, 0xEA, 0x3C, 0xB8, 0x02, 0x76, 0x80, 0x68, 0x64, 0x00, 0xD5, 0xDF, 0x79, 0x0A, 0x20, 0x03, 0x38, 0x00, 0x23, 0x20, 0x19, 0xA8, 0x7A, 0xE0, 0x8D, 0x03, 0x8C, 0x1B, 0xEB, 0x39, 0x80, 0x64, 0xC7, 0x0C, 0x66, 0x5A, 0xE2, 0x50, 0x64, 0x0D, 0x93, 0x35, 0x4C, 0x96, 0x22, 0xF8, 0x0B, 0x38, 0xF1, 0x0A, 0x73, 0xFD, 0x7E, 0x3D, 0x62, 0xC6, 0x74, 0xCA, 0xF3, 0xEA, 0x34, 0xFB, 0xCD, 0xB9, 0xCE, 0x23, 0x27, 0x78, 0x6B, 0xE1, 0xDD, 0x62, 0x40, 0xCD, 0xA7, 0x0F, 0xDF, 0x8D, 0x05, 0xC0, 0x05, 0x89, 0xAE, 0x5B, 0x48, 0xE8, 0xEE, 0x82, 0x74, 0x43, 0x3C, 0x6B, 0x05, 0x92, 0xEF, 0x9B, 0x25, 0x69, 0xFB, 0x73, 0x9D, 0x79, 0x63, 0x0B, 0xE0, 0x09, 0x58, 0x34, 0x12, 0x70, 0x06, 0x82, 0xE6, 0x7F, 0x00, 0x94, 0x00, 0xF7, 0x0D, 0x13, 0x40, 0x1C, 0x60, 0xDB, 0x9F, 0x8A, 0x3A, 0x66, 0xDC, 0xD6, 0x2F, 0xB8, 0x83, 0x7B, 0x3D, 0xBA, 0xC0, 0x47, 0x05, 0xE5, 0x63, 0x67, 0x94, 0x0B, 0x82, 0x3E, 0xC4, 0x57, 0x09, 0xED, 0x97, 0x24, 0xE2, 0x0F, 0x5A, 0xFD, 0x3A, 0x05, 0xB8, 0xCD, 0x9C, 0xC5, 0x3B, 0x3E, 0xDF, 0x32, 0x00, 0xA2, 0x00, 0x22, 0x28, 0xF6, 0x8B, 0xA1, 0x77, 0xD0, 0x15, 0x18, 0x87, 0x10, 0xFD, 0x60, 0x1D, 0xD0, 0x9E, 0x64, 0x92, 0x6E, 0xA9, 0x14, 0x9C, 0xF5, 0x3B, 0x93, 0x80, 0xB8, 0x12, 0x23, 0xAE, 0xCC, 0xFD, 0xA2, 0x49, 0x40, 0x0D, 0x60, 0x01, 0x88, 0x1B, 0xD6, 0x08, 0x80, 0x0B, 0x30, 0x05, 0x6A, 0x84, 0x21, 0x68, 0xE3, 0xCC, 0x7F, 0xB3, 0x41, 0x7F, 0x51, 0x00, 0x73, 0x04, 0xED, 0x37, 0x44, 0x56, 0x5F, 0x21, 0x02, 0xC3, 0x8B, 0x92, 0x85, 0xF0, 0x28, 0x2A, 0x03, 0x2D, 0xD2, 0x57, 0x99, 0x86, 0x39, 0xBC, 0xC8, 0x75, 0x87, 0x32, 0x5A, 0x92, 0x1C, 0x7C, 0x6D, 0x74, 0x44, 0xDE, 0xD6, 0xEA, 0xAD, 0xFC, 0x78, 0x6E, 0x83, 0xD4, 0x33, 0x23, 0x71, 0x00, 0x55, 0xE0, 0xDA, 0x29, 0xCF, 0xD8, 0x58, 0x00, 0x52, 0x0D, 0x01, 0x98, 0x1B, 0x02, 0x98, 0xEC, 0x76, 0xA0, 0xF7, 0xB6, 0xF4, 0x6F, 0x39, 0xC8, 0xD8, 0xCA, 0x74, 0x9C, 0x8D, 0xB3, 0xB5, 0xF5, 0xA3, 0x61, 0x0C, 0x78, 0xDC, 0x2E, 0xB6, 0x0E, 0x9A, 0x7E, 0xD1, 0xF2, 0x5F, 0xE3, 0x50, 0x7D, 0xCA, 0x23, 0x89, 0xEC, 0x6D, 0x29, 0xB2, 0x02, 0x5A, 0x48, 0x23, 0x88, 0xA3, 0x07, 0x9F, 0x6D, 0x35, 0x76, 0xC7, 0x92, 0xE4, 0xC0, 0xBD, 0x63, 0x8F, 0xCC, 0x08, 0x01, 0x94, 0xBB, 0xF9, 0xCE, 0x5F, 0xE7, 0xCC, 0xD7, 0x9F, 0xBA, 0x11, 0x09, 0x70, 0x6E, 0x57, 0x7F, 0x3B, 0x80, 0xFA, 0x0E, 0xA1, 0x12, 0xE0, 0xF6, 0xC8, 0x16, 0xE6, 0x13, 0x26, 0x69, 0x58, 0x23, 0x00, 0x33, 0x20, 0xFD, 0x5F, 0x4E, 0x04, 0x8F, 0x0A, 0xA5, 0xE9, 0xE3, 0xD1, 0x6B, 0x13, 0x34, 0xBB, 0xD1, 0xCA, 0xEC, 0x44, 0xED, 0x87, 0x36, 0xD0, 0xC9, 0x42, 0x87, 0x91, 0x25, 0xFE, 0x6F, 0x2E, 0x08, 0x64, 0xBB, 0x7F, 0x2B, 0xCD, 0x5F, 0x91, 0xBE, 0x6B, 0x57, 0x3B, 0xBD, 0xCA, 0x8F, 0xF0, 0x75, 0x15, 0xE0, 0xB2, 0x13, 0x42, 0x26, 0x00, 0x69, 0x43, 0x00, 0x75, 0x60, 0x6E, 0xC6, 0x53, 0x1A, 0xAA, 0x27, 0xCA, 0x33, 0x82, 0xE2, 0x0D, 0x4D, 0xC0, 0xD7, 0xBD, 0x73, 0xDD, 0xD2, 0x37, 0xB8, 0x76, 0x08, 0xCD, 0xFF, 0xBD, 0xD2, 0xF6, 0xF4, 0x46, 0xC3, 0x0E, 0x70, 0x0B, 0x68, 0x3C, 0x41, 0xF3, 0xDF, 0x12, 0xC3, 0x23, 0x1B, 0xD6, 0x35, 0xCF, 0x2F, 0xE5, 0x8D, 0x95, 0x46, 0xB0, 0x0D, 0x8F, 0xBB, 0xA2, 0xED, 0x0B, 0x9A, 0x9E, 0x77, 0xE6, 0x9F, 0xEE, 0xBF, 0xCB, 0x16, 0xC5, 0x30, 0x03, 0x94, 0x81, 0x33, 0x35, 0x84, 0x47, 0x1A, 0x35, 0x0F, 0x10, 0xE7, 0xF9, 0x94, 0x00, 0xF9, 0x3C, 0x7B, 0x80, 0x1C, 0x80, 0x0D, 0xA0, 0x6C, 0x14, 0xA0, 0xAF, 0xC4, 0xED, 0x20, 0x37, 0xE8, 0xBC, 0x5D, 0x6C, 0xCF, 0x65, 0xDD, 0x1B, 0x07, 0xF0, 0x57, 0x7F, 0x34, 0x00, 0x7D, 0x07, 0xF0, 0x02, 0xC2, 0xA3, 0x9A, 0x31, 0xB1, 0x1B, 0xCC, 0xA8, 0x27, 0x7E, 0x76, 0x32, 0xEC, 0x69, 0x14, 0xFD, 0x20, 0x15, 0xF4, 0x4B, 0xDE, 0x3E, 0x0E, 0x9A, 0x3F, 0xFB, 0x7A, 0xA0, 0x03, 0x7A, 0x00, 0xCE, 0x9D, 0x6E, 0x09, 0x06, 0xD4, 0x00, 0x99, 0x4F, 0xFE, 0xA6, 0xAE, 0xF7, 0x9E, 0x16, 0x02, 0xA8, 0x35, 0x08, 0x90, 0x81, 0x00, 0xEE, 0x8F, 0x0B, 0x48, 0x02, 0x46, 0x0F, 0xA4, 0x61, 0x40, 0xC4, 0xD6, 0xB6, 0xD5, 0x6C, 0x10, 0xC0, 0xF4, 0xB4, 0xF2, 0x2A, 0x90, 0xD1, 0xDF, 0x22, 0x13, 0xB4, 0xFC, 0x6A, 0xC3, 0x91, 0xF5, 0xF5, 0x2A, 0x7B, 0x1A, 0x54, 0x4D, 0xB8, 0x5F, 0x97, 0xC8, 0x07, 0x45, 0x11, 0x92, 0x69, 0x1A, 0x82, 0x1E, 0xAF, 0xCC, 0xB5, 0xA7, 0xED, 0x2E, 0x48, 0xFC, 0x30, 0x5B, 0xC9, 0x88, 0x0F, 0xB0, 0x7D, 0x51, 0xF4, 0x26, 0xAE, 0x42, 0x77, 0x5C, 0x95, 0x81, 0x30, 0xA0, 0x0E, 0x30, 0x31, 0x90, 0xC7, 0xAB, 0x39, 0x1B, 0x41, 0x0D, 0x9F, 0x32, 0xDE, 0x16, 0xB4, 0xB2, 0x18, 0x91, 0x2C, 0x80, 0x1D, 0x10, 0x03, 0xB4, 0x11, 0xB2, 0xD3, 0x50, 0x76, 0x00, 0x65, 0x80, 0x65, 0x5B, 0xC3, 0x05, 0x30, 0x32, 0x28, 0xBF, 0xA0, 0xD5, 0x9F, 0xFC, 0x7A, 0x78, 0xFF, 0x3E, 0xA5, 0x81, 0x52, 0xFA, 0x1F, 0x85, 0x49, 0x14, 0xF6, 0x29, 0x75, 0xF4, 0x5E, 0xB2, 0x43, 0xB5, 0x07, 0x9E, 0x17, 0xAA, 0xEF, 0x9E, 0x36, 0x7B, 0xB0, 0xE5, 0x6E, 0x94, 0x73, 0x01, 0xEC, 0x11, 0x43, 0x75, 0x06, 0xE8, 0x75, 0x38, 0xD7, 0x46, 0x36, 0x04, 0x38, 0x33, 0xB7, 0xDE, 0xE0, 0x01, 0xEF, 0xC7, 0x93, 0x05, 0x08, 0xD9, 0x1B, 0x8F, 0xF8, 0x3B, 0xCC, 0x03, 0xD4, 0x1D, 0xAB, 0x04, 0xB8, 0xE1, 0x0A, 0x64, 0x34, 0xF8, 0x91, 0xC1, 0x56, 0x40, 0x0E, 0xA0, 0x8D, 0x2B, 0xC9, 0x91, 0xE7, 0x4F, 0x14, 0xBC, 0xE9, 0xF3, 0x3B, 0x12, 0xC7, 0x77, 0xA5, 0x2A, 0xC5, 0xB4, 0x8A, 0xB2, 0xB4, 0xA0, 0x15, 0xA1, 0xC1, 0xB1, 0xA4, 0xC7, 0x78, 0x11, 0x2C, 0x69, 0x3A, 0x3D, 0xFD, 0xB6, 0xB3, 0xF5, 0xDF, 0x12, 0xB1, 0x36, 0x78, 0xD7, 0x09, 0xBC, 0x43, 0x58, 0x09, 0x98, 0x00, 0xCA, 0x80, 0x1F, 0x20, 0x14, 0xA0, 0xD8, 0x42, 0xD4, 0x95, 0x80, 0x37, 0xDE, 0xE9, 0xBA, 0x89, 0x8F, 0xE5, 0xEE, 0x66, 0x34, 0x05, 0x82, 0x1A, 0xB5, 0x0B, 0xF1, 0x27, 0xF7, 0xBA, 0xF3, 0x6A, 0xC8, 0x63, 0xB6, 0x18, 0xC0, 0xA9, 0xBD, 0x5E, 0x43, 0x27, 0x68, 0x84, 0x9E, 0x04, 0x96, 0x6F, 0x89, 0x45, 0x32, 0xE4, 0xE2, 0xCB, 0x71, 0x4C, 0x87, 0x61, 0x7D, 0x96, 0x33, 0xA4, 0x2D, 0xB2, 0xC7, 0x68, 0xB2, 0x96, 0x6C, 0xB7, 0xD1, 0x33, 0x43, 0xA0, 0x4B, 0xF0, 0x14, 0x3D, 0x8D, 0x40, 0x01, 0x34, 0x53, 0xFE, 0xBC, 0x47, 0x43, 0x44, 0x1A, 0xB1, 0x7D, 0x3F, 0xA6, 0x80, 0xEB, 0xBE, 0xD5, 0xA9, 0x8B, 0x00, 0x89, 0x6D, 0x77, 0x6D, 0xF5, 0xF3, 0xBC, 0xB0, 0xD1, 0xD0, 0x04, 0x56, 0x7D, 0x53, 0x00, 0xF1, 0xA7, 0x86, 0x10, 0x73, 0x16, 0x07, 0xAC, 0x1A, 0x0C, 0x88, 0x00, 0x47, 0xB6, 0x55, 0x4B, 0xC9, 0x7C, 0xE7, 0x04, 0x8D, 0x21, 0xFE, 0xA2, 0xF6, 0x27, 0x3B, 0xE9, 0x63, 0x86, 0x69, 0x6B, 0xC5, 0x4C, 0x29, 0x66, 0x88, 0xA2, 0x7A, 0x4D, 0xD0, 0xD4, 0xB5, 0xF7, 0xF8, 0xFA, 0x36, 0x74, 0x93, 0xBF, 0x13, 0x22, 0x4F, 0xF7, 0xDC, 0x4C, 0x88, 0xF8, 0x73, 0x00, 0x91, 0x8E, 0x41, 0x0A, 0x10, 0x4F, 0x6B, 0xC2, 0xB1, 0x29, 0x9A, 0xEF, 0xDD, 0x4F, 0xFC, 0x49, 0xE2, 0x3F, 0x45, 0x4F, 0x5F, 0xDE, 0x9B, 0x10, 0x3A, 0x58, 0x0D, 0x7D, 0xE6, 0x40, 0xC8, 0x9E, 0xF0, 0x20, 0x01, 0x4C, 0x81, 0x3C, 0x40, 0x18, 0xE0, 0x04, 0x48, 0x02, 0x4C, 0x3B, 0x92, 0x69, 0x13, 0x34, 0xF9, 0x63, 0x2D, 0xAC, 0xE0, 0x8C, 0x9C, 0x23, 0xEE, 0x7E, 0x8A, 0xC4, 0x10, 0x09, 0x4A, 0x3A, 0x54, 0xE8, 0x89, 0x36, 0xC5, 0xFF, 0x2D, 0xBC, 0xE7, 0x63, 0xDF, 0x49, 0xEC, 0x69, 0x4B, 0xA5, 0x3B, 0x26, 0x9B, 0x40, 0x28, 0x40, 0xA3, 0x8D, 0xC1, 0xD3, 0xD5, 0xBA, 0xBC, 0x5B, 0xA5, 0x36, 0xB4, 0x63, 0x1E, 0x1D, 0x83, 0x22, 0x40, 0x68, 0x8F, 0x39, 0x49, 0x00, 0xCC, 0xC0, 0x32, 0xB3, 0xFF, 0xA9, 0x42, 0xD2, 0x63, 0x42, 0xE3, 0xF9, 0x78, 0xD1, 0x9C, 0x57, 0xB0, 0x29, 0x1A, 0x02, 0x58, 0x43, 0x9E, 0xBE, 0x1C, 0x51, 0x20, 0xAA, 0x83, 0xA6, 0x9F, 0xE7, 0x05, 0x2B, 0x74, 0xAD, 0xCA, 0xA5, 0x07, 0x0C, 0x21, 0xD2, 0x97, 0x5C, 0x50, 0x98, 0xE3, 0xC4, 0xF3, 0x24, 0x0E, 0xAF, 0x3F, 0x3A, 0x5B, 0x92, 0x23, 0x9F, 0xF9, 0xD8, 0x69, 0xE9, 0x8E, 0xE9, 0x55, 0x96, 0x04, 0x3C, 0xB6, 0x77, 0x1B, 0x4F, 0xAD, 0x76, 0xF7, 0x6C, 0xF0, 0x01, 0x88, 0x81, 0x33, 0xA5, 0x33, 0xD9, 0x23, 0x3E, 0x66, 0x1D, 0x9F, 0x04, 0xA8, 0xB6, 0xF2, 0x23, 0xE7, 0xDC, 0xD7, 0x76, 0x73, 0xBC, 0x28, 0x60, 0x0C, 0xF8, 0x69, 0xE4, 0x63, 0x14, 0xD2, 0x30, 0x6F, 0x1C, 0x40, 0x64, 0xAB, 0x46, 0xD5, 0x34, 0x23, 0x10, 0x60, 0x32, 0x2B, 0x0D, 0xCF, 0xA5, 0x57, 0xFC, 0x09, 0x2C, 0xF0, 0x2F, 0x5A, 0x15, 0xA8, 0xDF, 0xCD, 0x45, 0x92, 0xB5, 0x67, 0x50, 0xD5, 0xB0, 0x37, 0x70, 0xAE, 0x76, 0x78, 0xDF, 0xD2, 0x69, 0x72, 0xFF, 0x0A, 0xA1, 0x57, 0x55, 0x3F, 0x81, 0x43, 0x08, 0x4C, 0xFF, 0xF5, 0xAF, 0x13, 0xCA, 0x7C, 0x62, 0xDD, 0x7B, 0x9A, 0xDA, 0xA3, 0x18, 0x29, 0xDB, 0x02, 0x50, 0x1E, 0xE9, 0x3D, 0xA3, 0x7D, 0xD6, 0x10, 0x03, 0x42, 0x9E, 0xF6, 0x15, 0x02, 0xE8, 0x3C, 0x7B, 0xA8, 0xEF, 0x07, 0x79, 0xFE, 0x5B, 0x26, 0x60, 0xB5, 0xBF, 0xD3, 0x64, 0xBE, 0x65, 0x82, 0xE6, 0xDF, 0x12, 0x23, 0xE1, 0xAF, 0x35, 0x41, 0xD1, 0x96, 0xAC, 0xDE, 0x5A, 0xE7, 0x96, 0x8C, 0x27, 0x9E, 0x02, 0xB5, 0xD9, 0xB4, 0x1E, 0xC8, 0xB6, 0x1D, 0x34, 0x7E, 0x86, 0x8A, 0xF3, 0x03, 0xF1, 0xAD, 0x0D, 0x67, 0xFE, 0xD2, 0xC6, 0x76, 0xE5, 0x7B, 0xE4, 0xD7, 0xD5, 0x8A, 0xBE, 0x54, 0x80, 0x64, 0x1E, 0x97, 0x65, 0xFE, 0x99, 0xB5, 0xED, 0xB2, 0x88, 0xF7, 0x82, 0x2B, 0x01, 0x62, 0x1E, 0x5D, 0x9B, 0x12, 0xF1, 0xEE, 0x75, 0xB7, 0x00, 0xEA, 0x9F, 0xA2, 0xAD, 0xD6, 0xA8, 0xD1, 0x83, 0xE5, 0xC6, 0xD9, 0x56, 0x6A, 0x49, 0x80, 0xEB, 0xEE, 0x08, 0x9F, 0x14, 0x64, 0x06, 0x6C, 0x6F, 0x13, 0x72, 0x2F, 0x94, 0xD3, 0x76, 0x0B, 0xE9, 0xB4, 0x64, 0x43, 0x8D, 0x43, 0x00, 0x09, 0x43, 0xF5, 0xAD, 0x6A, 0xB7, 0xC3, 0xAF, 0x7B, 0xF4, 0x54, 0x2B, 0x91, 0x86, 0xED, 0xF4, 0x3F, 0x59, 0x57, 0x96, 0x02, 0x9F, 0xB4, 0xA7, 0x5F, 0x29, 0x3A, 0xE5, 0xF6, 0x01, 0xD1, 0x47, 0xDA, 0xD0, 0x81, 0xA3, 0x4F, 0x85, 0x4F, 0xC6, 0x04, 0x76, 0x5B, 0x4C, 0x15, 0x6D, 0x73, 0xCB, 0xCC, 0x5D, 0x1A, 0x18, 0x81, 0x5D, 0x0A, 0x60, 0x8A, 0x56, 0x52, 0x80, 0x35, 0xE6, 0xEF, 0x3B, 0x04, 0x88, 0x02, 0x36, 0x78, 0xA6, 0x50, 0x85, 0x01, 0x9E, 0x4F, 0x8D, 0x98, 0xA0, 0xE5, 0x97, 0xDD, 0x62, 0xC2, 0x50, 0x4F, 0xC9, 0xCE, 0x41, 0x1E, 0x61, 0x14, 0x9F, 0xA4, 0x0B, 0x05, 0xEE, 0xDD, 0xCD, 0x5A, 0x93, 0x47, 0x7B, 0x46, 0x7C, 0x56, 0x93, 0x22, 0x61, 0x0B, 0x40, 0x98, 0x0A, 0x41, 0x63, 0xC1, 0x27, 0x1E, 0xE3, 0xEB, 0xC9, 0x8B, 0x4E, 0xAB, 0xFC, 0xF4, 0xB3, 0xCA, 0x2E, 0x45, 0x49, 0x87, 0x89, 0x7C, 0x0A, 0xA8, 0xC0, 0x28, 0x2C, 0x73, 0x6C, 0x7B, 0x61, 0xD6, 0xFE, 0xE2, 0xE8, 0x53, 0xD9, 0x4F, 0x3C, 0x28, 0x3A, 0x06, 0xD8, 0x64, 0x56, 0x6F, 0xAD, 0xD7, 0xCE, 0xBF, 0x6B, 0x00, 0x61, 0x0D, 0x01, 0x9C, 0x00, 0x65, 0x80, 0x6B, 0x7F, 0x2A, 0xE9, 0xA0, 0xD5, 0x57, 0x8A, 0x62, 0xCE, 0x6F, 0x6D, 0x31, 0xE9, 0x3C, 0x48, 0x58, 0x77, 0xAC, 0xAD, 0xC8, 0x6C, 0x40, 0x17, 0xA6, 0x9C, 0xE7, 0x71, 0xDC, 0xA5, 0x28, 0x9D, 0x46, 0xCB, 0x1C, 0xC3, 0xA8, 0x3B, 0x66, 0x3D, 0x86, 0xFE, 0xC0, 0xB9, 0xC5, 0xC7, 0x5F, 0x9B, 0x77, 0x5E, 0x9C, 0xEA, 0xB5, 0xD1, 0xC8, 0xF8, 0x89, 0x27, 0xD8, 0x1D, 0xF9, 0x3F, 0xF2, 0xAB, 0xF0, 0xD2, 0xF5, 0x5E, 0xCB, 0xA5, 0x6C, 0xCA, 0x57, 0xC9, 0xA3, 0x74, 0x2A, 0x20, 0xC0, 0x75, 0x8C, 0x63, 0x80, 0x15, 0xB0, 0x1C, 0xE5, 0x22, 0x40, 0xA2, 0x41, 0x00, 0xC9, 0x68, 0x5A, 0x00, 0x1E, 0x40, 0xF4, 0xFF, 0x30, 0x67, 0xDB, 0x3A, 0x5F, 0x97, 0x28, 0x59, 0x7E, 0x9B, 0x58, 0x95, 0xAD, 0xA7, 0xB3, 0xDA, 0x30, 0xEA, 0xF4, 0x5E, 0x96, 0xE3, 0x81, 0x14, 0xF4, 0x2F, 0x13, 0x3C, 0xFA, 0x1D, 0x98, 0x49, 0x6F, 0xAE, 0xFD, 0x3C, 0x79, 0xF8, 0x69, 0x7C, 0xA7, 0x89, 0xCF, 0xCC, 0xFB, 0x10, 0x30, 0x7E, 0xF4, 0xB7, 0x34, 0xB4, 0x94, 0x9D, 0x78, 0x17, 0x2D, 0x21, 0xE7, 0xB8, 0x94, 0xF7, 0x84, 0x9F, 0x9A, 0xE7, 0xEC, 0x8F, 0xD9, 0x21, 0x54, 0x01, 0xC2, 0x80, 0xA2, 0x47, 0xB5, 0x9B, 0x00, 0xBF, 0x51, 0x6E, 0x08, 0x90, 0x04, 0xB8, 0x02, 0x26, 0x5B, 0xB5, 0x9B, 0xB4, 0x83, 0x46, 0xC8, 0x67, 0x28, 0x26, 0xEF, 0xD2, 0x78, 0x89, 0x80, 0xA5, 0x77, 0xC5, 0x5D, 0x1D, 0xC5, 0x95, 0x23, 0xA8, 0xBF, 0xF0, 0xB2, 0xF9, 0x2F, 0x5A, 0xF2, 0xBC, 0xD3, 0x9E, 0x37, 0xB5, 0x39, 0x21, 0x44, 0x49, 0xFA, 0x71, 0x9C, 0x61, 0x78, 0xAE, 0x3B, 0x8B, 0x41, 0x67, 0x97, 0xDA, 0x79, 0x6C, 0xDA, 0xA3, 0x2B, 0x7C, 0xDC, 0x75, 0x6D, 0xDA, 0x4A, 0x13, 0x34, 0x46, 0xE2, 0x8C, 0x90, 0x63, 0x65, 0xFA, 0x2D, 0xED, 0xD9, 0x2C, 0xDE, 0x5E, 0xDF, 0xB3, 0xB0, 0xE3, 0x83, 0xDC, 0x8D, 0xD4, 0x0B, 0xA8, 0xD3, 0x1B, 0x85, 0x02, 0x71, 0x80, 0xB2, 0x86, 0x00, 0x79, 0x00, 0x67, 0x40, 0x13, 0xB0, 0xAE, 0xD4, 0xDE, 0x98, 0x71, 0x57, 0x61, 0x19, 0xE5, 0x74, 0x89, 0x89, 0xD9, 0xD7, 0xD8, 0x4D, 0xA1, 0xAD, 0x14, 0xE1, 0x58, 0x04, 0x56, 0x1F, 0x3C, 0x0C, 0xDD, 0xEF, 0x4F, 0xF5, 0x4E, 0xE7, 0x8D, 0x36, 0x0F, 0x27, 0xE9, 0x18, 0xD6, 0x03, 0x61, 0xB3, 0xDC, 0x7A, 0xAF, 0x1D, 0xBD, 0x12, 0xFB, 0x49, 0x45, 0xF8, 0xAD, 0xE9, 0xFA, 0xD9, 0x6E, 0x57, 0x77, 0x31, 0x34, 0xF8, 0x31, 0x8B, 0x0E, 0x05, 0xD2, 0x7E, 0x2B, 0xC4, 0x3B, 0x9E, 0x09, 0xFC, 0xAC, 0x1E, 0x29, 0x01, 0x2D, 0x20, 0x04, 0xA8, 0x9C, 0xB2, 0x16, 0xA0, 0xDC, 0xD0, 0x86, 0x35, 0x0E, 0x20, 0x05, 0x68, 0x02, 0x39, 0x0F, 0x27, 0x9A, 0xD0, 0x44, 0xB1, 0xAF, 0x89, 0xD5, 0x8A, 0xD9, 0x61, 0x9D, 0xC6, 0xC4, 0xF6, 0x7A, 0x57, 0xFC, 0x98, 0xCA, 0xCB, 0x26, 0xC4, 0xEB, 0x69, 0x48, 0x60, 0x9D, 0x6A, 0xEC, 0xEC, 0x4C, 0x6B, 0xB8, 0x1F, 0x36, 0x0A, 0xCB, 0xB1, 0x38, 0x96, 0x40, 0x24, 0xF6, 0x22, 0x9C, 0x3E, 0x02, 0xE0, 0x69, 0x3A, 0x88, 0x35, 0x15, 0x77, 0x9E, 0xD9, 0x3A, 0x66, 0x80, 0xFC, 0xF6, 0x94, 0x6D, 0xA5, 0x22, 0xEB, 0xF0, 0x5A, 0xEC, 0x6E, 0x37, 0x3D, 0x80, 0x25, 0x90, 0xBE, 0x7B, 0xE6, 0xF4, 0x81, 0x18, 0xC0, 0x0D, 0x6A, 0x70, 0x02, 0xF3, 0xEA, 0x2C, 0xFD, 0xEE, 0x50, 0xE1, 0xD2, 0x37, 0xCE, 0x42, 0xD5, 0xE7, 0xE0, 0x10, 0xE2, 0x65, 0xD8, 0x43, 0x1C, 0x60, 0xE2, 0x96, 0xE6, 0xE4, 0xB9, 0x06, 0x3C, 0x1A, 0x43, 0xAB, 0x45, 0x95, 0xE8, 0xEF, 0xD9, 0x80, 0xF7, 0x3E, 0x3E, 0x3B, 0xC5, 0x9C, 0xE3, 0xB2, 0x76, 0x8F, 0xE8, 0x35, 0x69, 0x3B, 0x80, 0xCF, 0xCE, 0x14, 0x4B, 0xDB, 0xD5, 0xF9, 0xF1, 0xBF, 0x50, 0x40, 0xA3, 0x63, 0x37, 0xCE, 0xEE, 0xF9, 0x68, 0x41, 0x12, 0x01, 0xE6, 0x40, 0x04, 0x50, 0xB2, 0x2B, 0xC3, 0xF9, 0xD6, 0xD1, 0x6B, 0xBF, 0xAA, 0x9D, 0x01, 0x6D, 0xD8, 0xC8, 0xCF, 0xCC, 0xD3, 0x69, 0x3D, 0x06, 0x55, 0xD3, 0x81, 0xB2, 0x94, 0x94, 0xA5, 0x08, 0xB5, 0xAE, 0x13, 0x1F, 0x9C, 0xBC, 0xAB, 0xBE, 0xB6, 0xE6, 0x7B, 0x6E, 0xCD, 0x53, 0x7F, 0x2A, 0xB0, 0xDC, 0x2F, 0x28, 0x31, 0x3C, 0x03, 0xD2, 0x2F, 0x7C, 0xC1, 0xBC, 0x0D, 0xD6, 0x74, 0xD7, 0xE6, 0xF2, 0x03, 0x56, 0x03, 0xAC, 0x6F, 0x3A, 0x4F, 0x6C, 0x53, 0xA2, 0xEB, 0xBD, 0xCF, 0xB4, 0x4B, 0x74, 0x2D, 0x1C, 0x73, 0x72, 0x3B, 0x0C, 0xD6, 0x01, 0x74, 0x4E, 0x81, 0xDC, 0xDB, 0xE3, 0x54, 0xDC, 0xBA, 0xB4, 0x97, 0x33, 0xBF, 0x26, 0x80, 0x39, 0x10, 0x89, 0xBF, 0x81, 0x04, 0xB0, 0x00, 0x92, 0x1A, 0x0C, 0x44, 0x02, 0x5E, 0x0D, 0xFB, 0x7D, 0x91, 0xEE, 0x20, 0x59, 0xF9, 0xD7, 0xD6, 0xED, 0xBF, 0x31, 0x1F, 0x83, 0xF6, 0x68, 0xFF, 0x7A, 0x8C, 0x54, 0x61, 0x11, 0x4A, 0x15, 0x6C, 0x18, 0xB4, 0xEE, 0xD9, 0x75, 0x79, 0x9B, 0xF9, 0x66, 0xAC, 0xBE, 0x26, 0x93, 0xA3, 0xFF, 0x50, 0x40, 0x3D, 0xCF, 0x8D, 0x68, 0xD2, 0xCB, 0xA9, 0xC0, 0x7C, 0xE2, 0x47, 0x94, 0x6A, 0x52, 0x8E, 0x46, 0x00, 0x67, 0xC3, 0x01, 0xAA, 0xFD, 0x29, 0xCF, 0x4E, 0x60, 0xDB, 0x79, 0xE6, 0x25, 0xA6, 0xD5, 0x32, 0x00, 0xB2, 0x27, 0x9F, 0x38, 0x19, 0x95, 0x6A, 0x4C, 0x3A, 0xB2, 0x61, 0xF9, 0x8C, 0x28, 0xD8, 0xFD, 0x96, 0x0E, 0x5A, 0x7C, 0x55, 0xCE, 0x63, 0xBF, 0xB9, 0x7F, 0xC5, 0x1C, 0xAC, 0x7E, 0xCA, 0xC2, 0xDE, 0x17, 0xF0, 0x42, 0x1B, 0x6F, 0x28, 0xAA, 0x7E, 0xBE, 0x73, 0x69, 0x1A, 0x6F, 0xDF, 0xA8, 0x4D, 0xCA, 0x33, 0x76, 0x7D, 0xB3, 0x14, 0x98, 0x8A, 0x66, 0xBD, 0xAA, 0x5D, 0x02, 0x04, 0x3F, 0x35, 0x33, 0x03, 0xCE, 0xAB, 0x0E, 0xAF, 0x0D, 0xDB, 0xB8, 0x7D, 0x8A, 0xD2, 0x71, 0x8A, 0x5D, 0x72, 0xE5, 0x03, 0xB8, 0xEF, 0x3C, 0xDD, 0x61, 0x80, 0x03, 0x70, 0x03, 0xB2, 0x1A, 0x0E, 0x44, 0xC3, 0xF4, 0x1D, 0xF4, 0x04, 0xAA, 0x26, 0x6A, 0x09, 0x35, 0x09, 0x2B, 0xD8, 0x11, 0x48, 0x5E, 0x23, 0x4E, 0xC5, 0x92, 0x46, 0x5B, 0x7F, 0x37, 0x8C, 0xAA, 0x30, 0x0E, 0xAF, 0x19, 0xCB, 0x90, 0x46, 0xFD, 0x31, 0x6F, 0xB0, 0x49, 0x60, 0x75, 0xA6, 0x83, 0x03, 0x38, 0xF7, 0xD9, 0xDD, 0xD3, 0x4D, 0x26, 0x5B, 0xF4, 0x5F, 0x1C, 0x20, 0xDE, 0x51, 0x96, 0xDC, 0xAA, 0x54, 0x66, 0x0D, 0x06, 0xD4, 0x80, 0x6B, 0x1A, 0x1E, 0x13, 0x91, 0x9B, 0x28, 0x99, 0xF7, 0xC8, 0xBE, 0x4E, 0x1A, 0x03, 0x61, 0xBB, 0x2F, 0x46, 0x1C, 0xB0, 0x7C, 0x20, 0x80, 0x1E, 0x40, 0xE6, 0x93, 0x01, 0xA3, 0x3A, 0x8A, 0x8B, 0x39, 0xB6, 0x91, 0xF8, 0x4A, 0x1E, 0x82, 0xFD, 0xE3, 0x40, 0xCD, 0x2A, 0x5B, 0x67, 0x94, 0x46, 0x5B, 0x55, 0xA0, 0xA3, 0xD9, 0xCF, 0x67, 0xFA, 0xDB, 0x30, 0x74, 0x13, 0x8A, 0xB6, 0x7A, 0xE0, 0xEC, 0x9A, 0xF9, 0xDC, 0x23, 0xE3, 0x07, 0xBE, 0xBF, 0xCB, 0xF4, 0xF7, 0x07, 0x30, 0x2F, 0xC3, 0x3A, 0x80, 0xAF, 0x7F, 0x72, 0xBF, 0x15, 0x10, 0x0E, 0x80, 0xCE, 0xAE, 0x72, 0x9C, 0xF8, 0x65, 0x61, 0xEF, 0x8D, 0x4A, 0x6F, 0xC3, 0x99, 0xCD, 0xB4, 0xE2, 0xBC, 0xC2, 0x05, 0x50, 0x06, 0xF2, 0x11, 0x3C, 0xF2, 0x86, 0x15, 0xA0, 0x02, 0x50, 0x01, 0x87, 0x00, 0x72, 0x20, 0xD0, 0xC8, 0x81, 0xE7, 0x49, 0xD0, 0x93, 0x9C, 0x5F, 0x2D, 0x93, 0xD6, 0x91, 0x43, 0xCA, 0x31, 0x2B, 0x4F, 0x84, 0x4C, 0x55, 0xFB, 0x8A, 0x9B, 0xFA, 0xDC, 0x03, 0x9E, 0xBC, 0x90, 0xFF, 0x7C, 0xE2, 0x89, 0xAE, 0xB1, 0x8C, 0x05, 0xC0, 0xB1, 0x93, 0x1A, 0x8A, 0xF4, 0x50, 0xDC, 0x6C, 0xE1, 0xE3, 0xBD, 0x38, 0x83, 0x04, 0xF3, 0x58, 0x1F, 0x80, 0x7C, 0x9E, 0xBD, 0x06, 0x01, 0xD1, 0xB8, 0xA9, 0xB5, 0xF3, 0x7B, 0xA2, 0x0A, 0xDF, 0x82, 0x10, 0x4A, 0x2F, 0x2A, 0x02, 0xA4, 0x61, 0xB2, 0x27, 0x84, 0x29, 0x01, 0xF1, 0x46, 0x02, 0xEC, 0x00, 0x31, 0x70, 0x08, 0xA0, 0x86, 0x4D, 0xD0, 0x08, 0x83, 0x16, 0x25, 0x7F, 0x12, 0x26, 0x20, 0xDF, 0xAB, 0xCD, 0x03, 0x3D, 0x09, 0xA9, 0xD9, 0xA9, 0xD1, 0x80, 0x86, 0x2C, 0x15, 0x4A, 0x0F, 0x32, 0x3E, 0x04, 0xEF, 0x54, 0xD4, 0xAA, 0xC3, 0xC5, 0x4D, 0x21, 0xFA, 0x01, 0x74, 0x2D, 0x07, 0xBF, 0xBE, 0x09, 0xF5, 0x68, 0x93, 0xE4, 0x01, 0x8C, 0x00, 0xF6, 0xA9, 0x29, 0xEF, 0xF2, 0xFA, 0xBB, 0xDF, 0x49, 0x01, 0x1A, 0x5B, 0x59, 0xFF, 0xCE, 0x89, 0x3D, 0xFE, 0xC5, 0xA7, 0xC1, 0x0E, 0x48, 0x01, 0x6E, 0xDB, 0x80, 0x98, 0xA3, 0x21, 0x3B, 0xCD, 0x57, 0x8D, 0x58, 0xFB, 0x5D, 0xBB, 0xB0, 0x23, 0x68, 0x8C, 0xEE, 0xF7, 0x2F, 0x76, 0x79, 0xDB, 0x0E, 0x39, 0x21, 0x9B, 0xE3, 0x14, 0x48, 0x19, 0x66, 0x2B, 0x71, 0x98, 0xE3, 0xB8, 0x64, 0x39, 0x0D, 0x1C, 0x4F, 0x5B, 0x77, 0xFD, 0x66, 0xBA, 0x26, 0x49, 0x85, 0x7B, 0x7E, 0x63, 0xDA, 0xA5, 0x47, 0x97, 0x70, 0xBB, 0x8F, 0x5D, 0xAD, 0x87, 0x04, 0x8C, 0xB6, 0x8B, 0xC2, 0x4D, 0x9B, 0x4C, 0x94, 0x1D, 0xF0, 0x86, 0xC8, 0x0F, 0xDE, 0xC8, 0x9F, 0xD7, 0xE3, 0x38, 0x7D, 0x05, 0x10, 0xBA, 0x4F, 0x82, 0xA4, 0x80, 0x0A, 0x90, 0xF2, 0x74, 0x70, 0xF3, 0xDC, 0x51, 0x81, 0x60, 0xC0, 0x1C, 0xF0, 0x69, 0xF9, 0xD5, 0x0E, 0x9A, 0xA0, 0x62, 0x47, 0xE8, 0xE0, 0x48, 0x6D, 0x41, 0x0E, 0xB6, 0xE9, 0x6C, 0xC2, 0xEC, 0x97, 0x31, 0x84, 0xFC, 0x3D, 0xB0, 0x6C, 0x88, 0x96, 0xD0, 0xB9, 0xF3, 0xAA, 0xDF, 0xE9, 0x3D, 0xA1, 0x6B, 0x2D, 0x53, 0x4A, 0xBE, 0x42, 0x0E, 0xE2, 0xAB, 0xB9, 0x58, 0x3B, 0x5A, 0x9E, 0x80, 0x12, 0x60, 0xF2, 0xE8, 0xE5, 0xCC, 0x44, 0x99, 0x00, 0x3C, 0x05, 0x82, 0x57, 0x43, 0xCE, 0x7F, 0x03, 0x0B, 0x79, 0x67, 0xB2, 0xAE, 0x51, 0xB3, 0x28, 0x50, 0xBC, 0x9B, 0x20, 0xC5, 0x81, 0xE0, 0xFD, 0x24, 0x5A, 0x36, 0x1E, 0x03, 0xAE, 0x53, 0x73, 0x08, 0x9F, 0x80, 0x02, 0xEE, 0x1D, 0x34, 0xFD, 0xD4, 0x85, 0xBE, 0x12, 0x7A, 0x19, 0xF4, 0xD3, 0xF4, 0xFB, 0x91, 0xBC, 0xFB, 0xBA, 0x09, 0x55, 0x4A, 0x0B, 0xBC, 0xC4, 0xA8, 0x1B, 0x5B, 0x8C, 0x97, 0x9C, 0x95, 0xF2, 0xF3, 0x78, 0x5E, 0x27, 0x47, 0xDB, 0x39, 0xF6, 0x4C, 0x80, 0x74, 0x36, 0xF4, 0x3D, 0x1E, 0x6B, 0xBA, 0xC7, 0x51, 0x22, 0xB7, 0xF5, 0x51, 0xC8, 0x3E, 0x79, 0x84, 0x35, 0xBC, 0x71, 0x1E, 0xCF, 0xA3, 0x99, 0xAD, 0x9A, 0x02, 0x01, 0xEF, 0x59, 0x1E, 0x77, 0xA0, 0x64, 0x97, 0x20, 0x54, 0x80, 0x3A, 0xB3, 0x34, 0xB3, 0x61, 0xC0, 0x99, 0x4D, 0x77, 0x0F, 0xA4, 0xC5, 0x1D, 0x25, 0xAC, 0x0E, 0x5A, 0x97, 0xEA, 0x04, 0x2E, 0xEC, 0x2E, 0xBE, 0x1A, 0xFA, 0xB4, 0x35, 0x5F, 0x88, 0x05, 0xFA, 0x4A, 0xA5, 0x1D, 0x79, 0xDE, 0x19, 0xC8, 0x78, 0xDA, 0x6D, 0x8B, 0xCE, 0x18, 0x2B, 0xF6, 0xEB, 0xC8, 0x00, 0xF9, 0xD0, 0xED, 0x73, 0xB7, 0x53, 0x5A, 0x1B, 0xDC, 0x49, 0x55, 0x9A, 0x37, 0x74, 0xAD, 0xAB, 0x64, 0xDC, 0xD4, 0x7E, 0xD6, 0xD3, 0x31, 0xF0, 0x58, 0xD3, 0xCD, 0xFE, 0x73, 0x85, 0x74, 0x43, 0xB6, 0x6E, 0xE7, 0x34, 0x68, 0x1B, 0x03, 0x23, 0x61, 0xCA, 0x09, 0x78, 0xEC, 0x79, 0x7E, 0x3B, 0x80, 0x16, 0x20, 0x01, 0x90, 0x02, 0x87, 0x00, 0x32, 0x20, 0xA2, 0x83, 0xE6, 0xD0, 0xCB, 0xA9, 0xFA, 0xBC, 0x55, 0x5C, 0xFD, 0xCB, 0xDE, 0x86, 0x2B, 0x74, 0x95, 0x29, 0x31, 0xDD, 0x98, 0x8E, 0x12, 0x6D, 0x76, 0x47, 0x2E, 0x3C, 0xEB, 0x85, 0xDF, 0xF9, 0xBB, 0xE9, 0x07, 0x32, 0xDB, 0xAF, 0x31, 0xE1, 0xC1, 0x73, 0x90, 0x98, 0xEB, 0xC2, 0xBB, 0x53, 0x1D, 0xC0, 0x1A, 0xB2, 0xDA, 0x41, 0x50, 0xD1, 0x5C, 0x6D, 0x1D, 0x25, 0x80, 0xF3, 0x9E, 0xC0, 0x96, 0x99, 0x65, 0x9F, 0xF6, 0x2E, 0x7E, 0x5E, 0x04, 0x0A, 0xD0, 0xE3, 0x44, 0xE3, 0xB4, 0xCD, 0x2C, 0xF5, 0x00, 0x62, 0x7B, 0x06, 0x35, 0x1B, 0xEE, 0x40, 0xD4, 0xFB, 0x22, 0x88, 0x3F, 0xD1, 0x09, 0xA5, 0xFA, 0xD6, 0x24, 0x75, 0xD0, 0x0C, 0xA3, 0x2A, 0x54, 0x68, 0x6C, 0xA8, 0xC0, 0x75, 0x8A, 0x14, 0xBF, 0x97, 0x9F, 0x3D, 0x53, 0x4C, 0x8F, 0x92, 0xB2, 0xE9, 0xAE, 0x3E, 0x46, 0x01, 0xBE, 0x66, 0x75, 0xBD, 0x61, 0xBF, 0x63, 0x29, 0x40, 0x1D, 0x9F, 0x68, 0xCC, 0xAB, 0x71, 0x6A, 0x0F, 0x9E, 0x80, 0x4A, 0x83, 0x01, 0x49, 0xE0, 0x0A, 0x75, 0xD5, 0xE3, 0xE2, 0x93, 0xFB, 0x60, 0xE7, 0x06, 0xA4, 0xEC, 0xDA, 0x1E, 0x17, 0x90, 0xF7, 0xC5, 0x03, 0x9C, 0xD8, 0xBB, 0x89, 0x39, 0x20, 0x6F, 0x66, 0x40, 0x26, 0x68, 0xED, 0x46, 0x29, 0xF5, 0x6D, 0x6D, 0xC1, 0xD1, 0x76, 0xA0, 0x98, 0x5D, 0x1C, 0xD3, 0xFA, 0x60, 0xE9, 0xB9, 0x0E, 0x6E, 0x7D, 0x7C, 0xDD, 0x55, 0x95, 0x5B, 0x20, 0x98, 0xC3, 0xE6, 0x3C, 0x82, 0x63, 0xD5, 0xEF, 0x04, 0x8C, 0x6A, 0xAD, 0xD2, 0xAF, 0x5D, 0xD8, 0xFB, 0xA5, 0x66, 0x93, 0xDA, 0xBF, 0xCD, 0xFF, 0x33, 0xC0, 0xE4, 0xB6, 0xE7, 0x9F, 0x38, 0x56, 0x65, 0x69, 0x7E, 0x41, 0x1F, 0xC4, 0x6C, 0x35, 0x93, 0x91, 0x90, 0x9F, 0xFD, 0x01, 0x4E, 0x12, 0x2B, 0xC3, 0x1F, 0x0C, 0x54, 0x67, 0xD7, 0x24, 0xF7, 0xD4, 0x0F, 0x79, 0x43, 0x27, 0xD7, 0x06, 0x44, 0x00, 0xD6, 0xF0, 0x11, 0x8C, 0x9D, 0x73, 0x5A, 0x7D, 0x79, 0x02, 0x71, 0x41, 0xA5, 0x58, 0x7F, 0x87, 0x5B, 0x83, 0x16, 0x29, 0x31, 0x0C, 0x08, 0x50, 0x6E, 0xB6, 0xCE, 0xFA, 0xC8, 0xDC, 0x04, 0x9E, 0x99, 0xE2, 0x78, 0x46, 0x08, 0xC6, 0x61, 0xB7, 0x74, 0x67, 0xFA, 0xC3, 0x7E, 0xE3, 0x9F, 0x72, 0x5F, 0xA9, 0x59, 0xDB, 0xDA, 0x90, 0x1C, 0xF1, 0x19, 0x89, 0x59, 0x07, 0x8E, 0x6E, 0x1B, 0x1E, 0x57, 0xC0, 0x08, 0x08, 0x7E, 0x9C, 0xD0, 0x72, 0x6E, 0x04, 0x2B, 0xD3, 0x1F, 0x57, 0xED, 0xE7, 0x9D, 0x55, 0x38, 0x01, 0x28, 0x03, 0x4E, 0x0D, 0xDF, 0xB0, 0x68, 0x38, 0xE0, 0xD3, 0x43, 0x6E, 0x08, 0xDA, 0xF5, 0x11, 0xB6, 0xCF, 0xA2, 0xD2, 0xF2, 0xF1, 0x2A, 0xD6, 0x6A, 0x05, 0xED, 0x42, 0x81, 0x27, 0x18, 0x3F, 0x43, 0xF8, 0x5F, 0xED, 0x2F, 0x0C, 0x2D, 0xCF, 0x53, 0xF3, 0x8C, 0x92, 0x69, 0xE7, 0x8D, 0x95, 0x1B, 0xF5, 0x9B, 0x52, 0xA1, 0x69, 0x30, 0xDF, 0x9A, 0x41, 0x50, 0x1C, 0xDE, 0x16, 0x95, 0x93, 0xB8, 0x07, 0x90, 0xE2, 0xDF, 0x9A, 0x41, 0x8D, 0xE3, 0x80, 0xD2, 0xAF, 0xA4, 0x90, 0x7F, 0x55, 0x89, 0x7A, 0x20, 0x4D, 0x27, 0xA7, 0x24, 0x40, 0x68, 0x27, 0xD9, 0x1F, 0xDD, 0xA3, 0xE3, 0x80, 0x68, 0x23, 0x1F, 0x48, 0x83, 0x01, 0x55, 0xA0, 0xB4, 0x83, 0x46, 0x2D, 0x96, 0x49, 0x7F, 0x8C, 0x21, 0x3B, 0x8A, 0x1A, 0x19, 0x66, 0xF2, 0x5C, 0x12, 0xBF, 0x82, 0xE7, 0x3A, 0x08, 0x7A, 0x9E, 0x25, 0x32, 0xE4, 0xFE, 0xA8, 0x02, 0xC7, 0x59, 0xF9, 0x51, 0x9C, 0x59, 0x47, 0x6C, 0x75, 0x95, 0x32, 0xC7, 0x77, 0xC5, 0xAD, 0xBF, 0xB3, 0xE3, 0x93, 0x01, 0x48, 0x01, 0x47, 0x7E, 0xF5, 0x66, 0x44, 0xB9, 0x85, 0x22, 0x01, 0xE1, 0x39, 0x2C, 0x00, 0xB6, 0x2E, 0x9D, 0x72, 0x6B, 0x58, 0x57, 0x4C, 0x6B, 0xC6, 0x06, 0x66, 0x36, 0x2F, 0x01, 0x31, 0x20, 0x4E, 0xA7, 0xC2, 0x15, 0x50, 0xDE, 0x10, 0x01, 0xA8, 0x1A, 0x07, 0x60, 0x06, 0x62, 0x56, 0x1A, 0x7F, 0xA2, 0x7C, 0xC7, 0xE4, 0xF3, 0x0F, 0x3C, 0xA7, 0x10, 0xA6, 0x63, 0x9D, 0x21, 0x64, 0x48, 0x2F, 0x33, 0xA1, 0x92, 0x1D, 0xFE, 0x7D, 0x92, 0x92, 0x7F, 0xB8, 0xF8, 0xEC, 0x8B, 0x0C, 0xD2, 0xBB, 0x33, 0x49, 0x0D, 0x58, 0x74, 0x0C, 0x64, 0xAE, 0x02, 0x53, 0x03, 0x5F, 0x5D, 0x57, 0x46, 0x3F, 0xF5, 0x0C, 0x1D, 0x3F, 0x81, 0x8B, 0x63, 0xFB, 0xD4, 0x16, 0x04, 0xB8, 0x02, 0xB9, 0xB2, 0x5E, 0x93, 0x40, 0x19, 0xF3, 0x29, 0x24, 0x1A, 0xF6, 0x1D, 0xD2, 0x0C, 0x98, 0x27, 0x98, 0x19, 0x88, 0xAB, 0xA3, 0xD8, 0xF0, 0x5D, 0x8B, 0x76, 0x07, 0x34, 0x01, 0x9F, 0x2D, 0xD8, 0x3B, 0x68, 0xF2, 0x49, 0x71, 0x9C, 0x33, 0xF3, 0xD8, 0x5D, 0xC6, 0x91, 0x4E, 0x7D, 0x68, 0x20, 0x6D, 0x63, 0xF3, 0x4A, 0x2B, 0x28, 0xC7, 0x98, 0x6F, 0x67, 0x32, 0x7D, 0xFA, 0xAC, 0x62, 0x9A, 0x93, 0x96, 0x93, 0x5A, 0xDD, 0x77, 0x54, 0x9E, 0x1D, 0x26, 0x9A, 0xB4, 0xDE, 0xFC, 0xD6, 0x67, 0x77, 0x30, 0x9F, 0xD8, 0xBA, 0x42, 0x16, 0x80, 0x78, 0x23, 0x1A, 0x8F, 0xCD, 0xA2, 0x4D, 0x0F, 0xDF, 0x72, 0xC0, 0x47, 0x08, 0xF7, 0xFD, 0x32, 0x01, 0x15, 0xE0, 0xEE, 0x85, 0x06, 0xE8, 0x01, 0x24, 0xFE, 0xA1, 0xDD, 0x9D, 0xBA, 0xC5, 0x40, 0x55, 0x4F, 0x07, 0x4D, 0x61, 0x6A, 0xC2, 0x04, 0x91, 0x78, 0x96, 0xB5, 0xA7, 0x89, 0x61, 0xDD, 0x71, 0x06, 0xFA, 0x78, 0xD2, 0x5B, 0xAD, 0xD6, 0xA6, 0xEA, 0xF9, 0xD8, 0x84, 0xD8, 0x1C, 0x24, 0xE6, 0xF1, 0x9C, 0xE9, 0x61, 0xDD, 0xEA, 0x5D, 0xE3, 0x10, 0x75, 0x0B, 0xE3, 0x08, 0xE8, 0xE4, 0xC9, 0xE9, 0x2A, 0x61, 0x6E, 0x3B, 0xB7, 0xF3, 0x1A, 0xF0, 0x2B, 0x50, 0xFE, 0xA8, 0xB5, 0xCF, 0x41, 0xA2, 0x96, 0x83, 0x79, 0x74, 0x05, 0xAF, 0x5F, 0xBE, 0x2C, 0x57, 0x12, 0x30, 0x7A, 0xA3, 0x13, 0x05, 0xAE, 0xC2, 0xB5, 0x03, 0xDE, 0x08, 0x02, 0x3C, 0x1A, 0x02, 0x58, 0x00, 0x31, 0x23, 0xBE, 0xD4, 0x41, 0x33, 0xD4, 0xBE, 0x8F, 0x61, 0x88, 0xE0, 0xA7, 0xDD, 0xAD, 0x0A, 0xFD, 0x34, 0x28, 0x23, 0x74, 0xEE, 0x12, 0xD7, 0x77, 0x35, 0x42, 0xD0, 0xEA, 0xD5, 0x35, 0xE4, 0xD5, 0x19, 0x3C, 0xD3, 0xCE, 0x53, 0x9B, 0xC6, 0x29, 0x65, 0x1B, 0x58, 0xD8, 0x59, 0x37, 0x75, 0x9A, 0x84, 0xEA, 0xF5, 0x9E, 0x7E, 0x24, 0x7F, 0x73, 0x77, 0xE8, 0xEA, 0x69, 0x24, 0x60, 0x02, 0xD4, 0x3A, 0x22, 0x8F, 0x65, 0xFA, 0xED, 0xAF, 0x89, 0xDB, 0x8C, 0x10, 0x33, 0x0C, 0xDE, 0x48, 0xDF, 0x5B, 0x94, 0x25, 0x10, 0x0E, 0xE4, 0x01, 0x22, 0x1B, 0x04, 0xF8, 0x2A, 0xFD, 0x21, 0xD9, 0x8A, 0xA0, 0xA1, 0x5C, 0x12, 0x76, 0x3E, 0xB1, 0x21, 0x66, 0xDE, 0xC3, 0x64, 0xC7, 0x46, 0x96, 0x0E, 0x6B, 0xD8, 0x0B, 0x21, 0x64, 0x5B, 0x59, 0x0E, 0xB7, 0xA7, 0xBE, 0xEE, 0xF3, 0x22, 0x10, 0xDF, 0xED, 0x19, 0x39, 0x47, 0x80, 0xFC, 0x55, 0x33, 0x79, 0x0B, 0x89, 0xD4, 0x6D, 0xDB, 0xD4, 0x79, 0x82, 0xAF, 0x09, 0xC3, 0x76, 0x60, 0x93, 0x41, 0x36, 0x1C, 0x98, 0x73, 0x08, 0x40, 0xF4, 0x58, 0x1C, 0x60, 0x18, 0x6D, 0xC5, 0xA7, 0xA6, 0x14, 0xDB, 0x88, 0x2E, 0x27, 0x73, 0x00, 0x66, 0x80, 0x1F, 0xC0, 0x14, 0x50, 0x06, 0xC4, 0x80, 0x19, 0x57, 0x3D, 0xD2, 0x41, 0x83, 0x05, 0x8D, 0xD9, 0xEB, 0x4C, 0x86, 0x73, 0x9A, 0x6A, 0xC1, 0x07, 0x4B, 0x0B, 0xC5, 0x08, 0x0E, 0xC8, 0xB0, 0x6A, 0x2C, 0x55, 0x60, 0x8D, 0x35, 0x79, 0x31, 0xED, 0xB0, 0x10, 0x63, 0xDA, 0x17, 0xCB, 0x98, 0xF7, 0x9E, 0x4C, 0x87, 0xE6, 0xAC, 0xAD, 0x2D, 0x85, 0x90, 0x5B, 0x65, 0xF5, 0xCC, 0x78, 0xC4, 0x79, 0x26, 0x2F, 0xB4, 0x51, 0x80, 0x2A, 0x10, 0xD3, 0x27, 0x3E, 0x77, 0x00, 0xBE, 0x46, 0x8E, 0x5B, 0xCC, 0x5A, 0x1A, 0x51, 0xCF, 0xE4, 0x3E, 0x01, 0x39, 0xE3, 0xA3, 0xD9, 0xA8, 0xC6, 0xD9, 0x2F, 0xF4, 0x68, 0xE4, 0xCC, 0xCE, 0xCE, 0x91, 0x23, 0xFF, 0x58, 0x60, 0x9C, 0x7F, 0x82, 0xA6, 0x0E, 0x95, 0x21, 0xC6, 0xA5, 0x0A, 0xFD, 0x8F, 0x2C, 0x50, 0x41, 0x2A, 0x81, 0xBA, 0x06, 0xF9, 0x28, 0x71, 0x3C, 0xFA, 0xD3, 0xB1, 0x6B, 0x04, 0x73, 0xDB, 0x8C, 0xDC, 0x49, 0xC8, 0xA9, 0x4A, 0xDD, 0x06, 0x6A, 0xD9, 0xCD, 0xE7, 0xA4, 0x4F, 0x96, 0x63, 0x2E, 0x96, 0xFE, 0x4C, 0x5E, 0xBC, 0x06, 0x65, 0x04, 0x44, 0xFC, 0xBA, 0x70, 0xFD, 0xEE, 0xDD, 0x3E, 0xD5, 0x6D, 0xB9, 0x62, 0xD6, 0x40, 0x34, 0xCA, 0x77, 0x86, 0xE8, 0x0A, 0x7E, 0x5A, 0x83, 0x76, 0x5A, 0x2D, 0x0C, 0xB0, 0x46, 0xF4, 0x77, 0x4A, 0x74, 0xD0, 0x0A, 0x2D, 0x55, 0xAC, 0xEF, 0x4A, 0xC3, 0x39, 0xED, 0x48, 0xDF, 0x51, 0x12, 0x1D, 0xDE, 0x9D, 0x5D, 0x93, 0x7A, 0x3A, 0xFA, 0xF4, 0x79, 0x11, 0x9C, 0xD9, 0x91, 0x67, 0x0E, 0x78, 0x6A, 0xB1, 0xA5, 0xD3, 0x79, 0x32, 0x87, 0xFF, 0xF5, 0x2E, 0x9D, 0xF2, 0x59, 0xD4, 0xF6, 0xCC, 0x8A, 0xC7, 0xCE, 0x2D, 0x1D, 0x70, 0x01, 0x62, 0x10, 0xBF, 0x31, 0x20, 0x05, 0xE6, 0xD5, 0x88, 0x5F, 0x70, 0xBA, 0xD9, 0xFA, 0x0E, 0x20, 0x93, 0xAD, 0x68, 0xA8, 0x00, 0xA9, 0x33, 0xC8, 0x0B, 0x58, 0x3D, 0x38, 0xCF, 0xB0, 0x67, 0x43, 0x14, 0xC8, 0x7E, 0x3C, 0x47, 0xC5, 0xB3, 0xFC, 0xEB, 0xF0, 0x96, 0x53, 0xAB, 0x67, 0x28, 0x48, 0xBB, 0x4B, 0x08, 0xEF, 0x83, 0x49, 0x14, 0x49, 0xE5, 0x2A, 0xAC, 0xB8, 0x3E, 0x87, 0x5B, 0x9B, 0xE2, 0xFF, 0x5C, 0x41, 0xF2, 0x00, 0xAA, 0x3F, 0x39, 0x60, 0xBB, 0xC5, 0x6D, 0xBB, 0x73, 0xD2, 0xBB, 0xF5, 0x90, 0xCE, 0x52, 0x61, 0x32, 0xDE, 0x82, 0xAA, 0x5A, 0x80, 0x49, 0x43, 0x81, 0xDA, 0x79, 0x31, 0xF8, 0x2F, 0x4F, 0x0E, 0x6A, 0x76, 0x72, 0xEC, 0x5B, 0x09, 0xD4, 0x8C, 0x28, 0x37, 0x22, 0xBA, 0xE5, 0x50, 0x00, 0x51, 0x40, 0xCF, 0x86, 0x14, 0xA0, 0x0A, 0x98, 0x01, 0xC5, 0x1D, 0x34, 0xEA, 0x9D, 0xFB, 0x1F, 0xAE, 0xD8, 0x95, 0xD9, 0xDD, 0x01, 0x8C, 0xFA, 0xA1, 0x2A, 0xFA, 0xC3, 0xEB, 0x6C, 0xDB, 0xDD, 0x78, 0x5A, 0xBB, 0x6F, 0x4D, 0xA3, 0xCE, 0xEF, 0x7C, 0x28, 0xB7, 0xCB, 0x20, 0x02, 0xA7, 0xB6, 0xD5, 0x27, 0xEC, 0x77, 0x5F, 0xE7, 0x9B, 0xF8, 0xDD, 0x59, 0x0E, 0xAD, 0x9D, 0x7D, 0xB4, 0x86, 0xE7, 0x5E, 0x69, 0x5B, 0x39, 0xED, 0xF6, 0x5B, 0xD9, 0xAD, 0x23, 0xF1, 0xF9, 0xB5, 0xAE, 0xF0, 0xDF, 0xBB, 0x9C, 0x02, 0x6A, 0x40, 0xEA, 0x96, 0x2D, 0xA6, 0xD3, 0x90, 0x86, 0x35, 0x02, 0xE0, 0x86, 0x55, 0x07, 0x8D, 0xF1, 0x7A, 0x8E, 0x78, 0x82, 0x86, 0x5A, 0xFC, 0x21, 0xE4, 0x35, 0x3A, 0x5A, 0xC7, 0xB3, 0x5A, 0xF3, 0xD4, 0xE6, 0xA8, 0xF1, 0x9C, 0xD3, 0xF8, 0x0A, 0xBE, 0xCD, 0xA5, 0x7C, 0x77, 0xA0, 0x85, 0xF4, 0x17, 0x7F, 0xE6, 0xCF, 0x75, 0x33, 0x6F, 0x57, 0xF4, 0x90, 0x7E, 0xF5, 0x27, 0xB9, 0xA5, 0x94, 0x9C, 0x89, 0x28, 0x02, 0x3C, 0x80, 0x54, 0x60, 0xD2, 0x6A, 0x46, 0xF7, 0xCD, 0x3A, 0x2A, 0xDF, 0x73, 0xD5, 0xEE, 0x88, 0xF4, 0x41, 0x2B, 0xFB, 0xB6, 0x29, 0xA7, 0x6F, 0x9B, 0x06, 0x4C, 0xB7, 0x01, 0x25, 0x60, 0xDC, 0xC8, 0x46, 0x35, 0xA4, 0x61, 0x80, 0x4F, 0x93, 0xA3, 0x76, 0xD0, 0xE4, 0x89, 0x16, 0x06, 0xA3, 0x5C, 0xEB, 0x2B, 0xB1, 0x8B, 0xD3, 0xB7, 0xC3, 0x04, 0x0B, 0xCA, 0x39, 0x24, 0x78, 0x00, 0x2B, 0xD6, 0xE4, 0x85, 0xDA, 0x5B, 0x62, 0xF7, 0xB3, 0xEB, 0x42, 0x5E, 0x8F, 0x41, 0x09, 0x03, 0x22, 0x80, 0x11, 0x50, 0xB7, 0x70, 0xF5, 0x18, 0x82, 0x9A, 0xFD, 0x5A, 0xA7, 0xF4, 0x5A, 0x2D, 0x9B, 0x4E, 0x39, 0x61, 0x46, 0x85, 0x56, 0x61, 0xEF, 0x9C, 0x3D, 0xCE, 0x4A, 0xB1, 0x25, 0x4A, 0xD3, 0x1B, 0xDA, 0xB0, 0xED, 0x50, 0x26, 0x0D, 0x6B, 0xA8, 0xEE, 0x2F, 0x12, 0x01, 0xA7, 0x41, 0x02, 0x18, 0xF7, 0x95, 0xE0, 0x3F, 0xAF, 0x00, 0xEB, 0x37, 0xB2, 0x7E, 0xB5, 0x05, 0xC7, 0x55, 0x10, 0x33, 0x17, 0xD9, 0x1D, 0x88, 0x6A, 0x16, 0x48, 0xA4, 0xBD, 0x96, 0x34, 0xB4, 0x24, 0x2A, 0xE3, 0xEF, 0x0B, 0xEC, 0xD0, 0xF6, 0xA0, 0x96, 0x02, 0x34, 0x01, 0xBF, 0x65, 0xC9, 0x9D, 0x0A, 0x53, 0xFF, 0x8F, 0x64, 0xB0, 0xDF, 0x97, 0xBF, 0xFD, 0xFA, 0xBE, 0xFD, 0xF6, 0x5A, 0xBC, 0xE2, 0xEF, 0x87, 0x1E, 0xED, 0xB3, 0x03, 0x30, 0x01, 0x14, 0x1B, 0x62, 0x80, 0x17, 0x50, 0x04, 0xA4, 0x02, 0xEE, 0xEF, 0x64, 0x65, 0xA3, 0x80, 0xAC, 0x09, 0x9A, 0x7D, 0x15, 0xCF, 0x63, 0xD5, 0xA7, 0x6F, 0x43, 0x19, 0x74, 0xBA, 0x23, 0xAB, 0xCF, 0x9A, 0xA1, 0x5D, 0xF6, 0x0A, 0x04, 0xED, 0xA0, 0xC4, 0x9E, 0xEF, 0x8D, 0x7D, 0xA6, 0x08, 0xEC, 0x29, 0xDB, 0xC6, 0x39, 0x4F, 0xF7, 0xF9, 0xDC, 0xE6, 0xE9, 0x29, 0x16, 0x8D, 0xAD, 0xED, 0x38, 0xD3, 0x54, 0x6F, 0x32, 0x02, 0xC4, 0xF7, 0x89, 0xAF, 0x10, 0x02, 0xCD, 0xF9, 0x49, 0xC7, 0xEB, 0x60, 0xA5, 0x83, 0x5D, 0x81, 0xF1, 0xA3, 0xB5, 0x06, 0x0B, 0x40, 0x04, 0x9C, 0x68, 0x14, 0x20, 0x0A, 0x44, 0xEE, 0xE6, 0x9C, 0x72, 0x20, 0x0A, 0xD0, 0x06, 0x37, 0x94, 0xE7, 0xCE, 0x32, 0x41, 0x7B, 0x5F, 0x01, 0x68, 0x81, 0x51, 0xEA, 0xDE, 0xEE, 0x50, 0x78, 0x54, 0x1E, 0xFA, 0x2E, 0x3E, 0x51, 0xDE, 0xC9, 0xD2, 0xBC, 0x13, 0x51, 0x1F, 0xFD, 0x11, 0x1E, 0x95, 0x49, 0x2E, 0xCF, 0xC4, 0x11, 0xBF, 0x0E, 0x2A, 0x02, 0xB0, 0x02, 0x73, 0x07, 0x3D, 0xF5, 0xAB, 0x60, 0xC7, 0x6D, 0x3F, 0x8C, 0x18, 0xC9, 0xA4, 0x5E, 0x70, 0x2B, 0xC9, 0x7B, 0x10, 0xB4, 0xB8, 0x03, 0x88, 0x31, 0x0B, 0xDC, 0xF6, 0x4D, 0xDF, 0x09, 0x90, 0x06, 0x9F, 0x67, 0xA5, 0x3D, 0x23, 0x7C, 0x21, 0x40, 0x45, 0x83, 0x9E, 0x19, 0xDE, 0x7C, 0x67, 0x78, 0x67, 0x1F, 0x98, 0xA0, 0x05, 0xC6, 0xFE, 0x99, 0xF1, 0x82, 0x15, 0x38, 0x8B, 0x8F, 0xA4, 0x83, 0xB0, 0xB5, 0x52, 0x47, 0x0F, 0xA3, 0x99, 0xE3, 0xE0, 0x2A, 0xE7, 0x1F, 0x41, 0x23, 0xFA, 0x75, 0x4B, 0xF9, 0x1D, 0x78, 0xBB, 0x3E, 0x01, 0x06, 0x78, 0x34, 0x7C, 0xE3, 0x5E, 0x1B, 0x75, 0x1A, 0x23, 0xE7, 0xD5, 0x11, 0xC0, 0x1C, 0xD8, 0xED, 0x67, 0xE6, 0x90, 0xB7, 0x06, 0x93, 0xF4, 0x18, 0x7B, 0x26, 0x30, 0x82, 0x0D, 0xD1, 0x30, 0x03, 0x34, 0x1A, 0xDA, 0x30, 0xC0, 0x63, 0xA2, 0xFC, 0x2F, 0x0B, 0xD9, 0x09, 0x68, 0x02, 0xCE, 0xC0, 0x2D, 0x5F, 0xC8, 0x04, 0x2D, 0xBF, 0xAB, 0x3A, 0xDA, 0x95, 0x15, 0x79, 0x59, 0xFF, 0x5E, 0x63, 0x3D, 0x88, 0x41, 0xD2, 0x87, 0x77, 0x43, 0xE9, 0xC6, 0x18, 0x85, 0xFD, 0xBE, 0x12, 0xD4, 0x3F, 0xAF, 0x04, 0xB3, 0xCB, 0x07, 0xED, 0x32, 0x4F, 0x26, 0x50, 0x0E, 0x24, 0x03, 0x71, 0x80, 0x8C, 0x59, 0x85, 0xBE, 0x4F, 0xC5, 0x64, 0xDB, 0x83, 0xFC, 0x5A, 0x2D, 0x9F, 0x65, 0x7D, 0xA1, 0x3C, 0x4F, 0xDB, 0x9E, 0x12, 0x35, 0x7D, 0xCC, 0xEC, 0x18, 0xA0, 0x6C, 0x04, 0xC0, 0x07, 0x50, 0x7F, 0xE4, 0x88, 0x1F, 0xC5, 0xD1, 0x6A, 0x38, 0xED, 0x3F, 0x6C, 0x1E, 0x79, 0x9A, 0x3D, 0x6D, 0x99, 0x15, 0x7F, 0x43, 0x36, 0xFE, 0xED, 0x70, 0xE4, 0x02, 0x09, 0x12, 0x51, 0xAC, 0x9E, 0x52, 0x8C, 0x52, 0x4A, 0x17, 0x8E, 0xBA, 0x5A, 0x4C, 0x13, 0x34, 0x7F, 0x86, 0xB1, 0xCD, 0xA6, 0x79, 0xEE, 0x1D, 0x4B, 0x05, 0x22, 0x1B, 0x04, 0x78, 0x00, 0x53, 0xD5, 0xA4, 0x25, 0x16, 0xFC, 0x53, 0x0F, 0x1A, 0xC7, 0x9F, 0x49, 0x8C, 0x4D, 0x81, 0x4E, 0xE7, 0x97, 0xDF, 0x6B, 0xCB, 0x03, 0xB0, 0x02, 0x54, 0x00, 0x8E, 0xE7, 0xF1, 0xAC, 0xFD, 0x49, 0x12, 0x08, 0x05, 0xCA, 0x80, 0x2C, 0x20, 0xF4, 0x79, 0x3C, 0xE5, 0x19, 0xB1, 0x77, 0x04, 0xED, 0x0B, 0x45, 0x7E, 0x12, 0xC7, 0x58, 0x5B, 0x18, 0xB7, 0xFB, 0xA4, 0x04, 0x04, 0x76, 0x8B, 0xDA, 0xBF, 0x3A, 0x11, 0x0E, 0x07, 0x2C, 0xE8, 0x7C, 0xD2, 0x65, 0x8B, 0x0D, 0x2E, 0x89, 0xDB, 0x49, 0x8C, 0xB1, 0x6F, 0xD9, 0x5D, 0xA6, 0x06, 0x03, 0xF4, 0xCC, 0x9C, 0x9E, 0x95, 0xE4, 0xA3, 0x73, 0x3B, 0x2E, 0x8A, 0x81, 0xB4, 0x15, 0xBB, 0x79, 0xC7, 0x00, 0x76, 0x67, 0x63, 0x55, 0x1E, 0xB5, 0x68, 0x07, 0x82, 0x01, 0xF3, 0x06, 0x01, 0x5A, 0xFB, 0x53, 0x9C, 0x67, 0x34, 0xBB, 0x1A, 0xBA, 0xDD, 0x1A, 0x93, 0x01, 0x2F, 0x60, 0xB6, 0x03, 0xBE, 0x41, 0xA3, 0x6F, 0x6D, 0x55, 0xDE, 0x3A, 0x14, 0x24, 0xCF, 0xDB, 0x60, 0x9C, 0xC2, 0x71, 0xDA, 0x22, 0xE9, 0xA9, 0x32, 0x45, 0x97, 0xB5, 0xEA, 0x9A, 0xF6, 0xB4, 0x5A, 0x69, 0x0E, 0x1C, 0x0B, 0x56, 0x57, 0x5F, 0x4E, 0x28, 0xB6, 0xDB, 0x27, 0xB6, 0x3F, 0xC0, 0x01, 0xED, 0xF8, 0xD8, 0xD2, 0xA9, 0x43, 0xFD, 0x0A, 0x90, 0x5F, 0x87, 0x3C, 0xDF, 0x66, 0xEF, 0xB9, 0xB4, 0xEA, 0x4C, 0x53, 0xEF, 0x49, 0x74, 0xE6, 0x3D, 0xB3, 0xEE, 0x01, 0x58, 0x35, 0x12, 0xF0, 0xB3, 0x7D, 0x77, 0x8F, 0xBE, 0x0F, 0xF2, 0x13, 0xB4, 0x04, 0x22, 0x80, 0x9C, 0xF0, 0xE6, 0x04, 0x8D, 0xBF, 0x89, 0xC5, 0x23, 0xD6, 0x5D, 0x31, 0xD6, 0x2B, 0x8D, 0x31, 0x22, 0x9B, 0x81, 0xAA, 0x74, 0x46, 0xF7, 0x31, 0x04, 0x5E, 0xF2, 0xEE, 0xDB, 0xE1, 0x59, 0x96, 0x51, 0xC8, 0xDC, 0x80, 0xFC, 0xEE, 0x5B, 0x73, 0xF2, 0x20, 0x02, 0xD8, 0x1E, 0x24, 0xE0, 0x73, 0x2A, 0x99, 0x72, 0xC2, 0xF5, 0x3F, 0x65, 0x40, 0x0B, 0x41, 0x9B, 0xA6, 0xC0, 0xE0, 0x29, 0xA2, 0xCC, 0xD2, 0xDC, 0x93, 0xDD, 0x06, 0x58, 0x02, 0x72, 0x00, 0x6A, 0x1C, 0x69, 0x50, 0xC3, 0x00, 0x7E, 0x66, 0xEB, 0x53, 0x81, 0xC8, 0xFD, 0x45, 0x3D, 0x00, 0x1B, 0x20, 0x0E, 0xA4, 0x4C, 0xD0, 0xE4, 0xD3, 0x4A, 0xE0, 0x9F, 0x76, 0xA6, 0x7D, 0xFD, 0xF9, 0x8A, 0xB1, 0x7F, 0x0A, 0xEC, 0xB9, 0x52, 0x08, 0x9A, 0xB6, 0x91, 0x20, 0xC7, 0xEC, 0x65, 0xCF, 0x4A, 0x9B, 0xAC, 0xCE, 0x63, 0x7E, 0xC4, 0xFE, 0x2F, 0xB3, 0x7D, 0x4D, 0xC0, 0xF5, 0xA7, 0x7A, 0xC6, 0x57, 0x20, 0xEF, 0xF8, 0xCC, 0x98, 0x01, 0x33, 0x52, 0x17, 0xCB, 0x5D, 0xA5, 0x1F, 0xD6, 0xBC, 0x6F, 0x1C, 0x7D, 0x15, 0xE5, 0xE7, 0x2A, 0x6A, 0x80, 0x04, 0xC0, 0x83, 0xE7, 0x49, 0x54, 0x07, 0xF2, 0xEC, 0xE1, 0xEF, 0x4A, 0x20, 0x05, 0xB0, 0x02, 0x34, 0x01, 0xCB, 0xA9, 0x69, 0x4C, 0xD0, 0xF4, 0x53, 0x51, 0x36, 0x9F, 0x44, 0x37, 0x64, 0xA7, 0x5C, 0x14, 0x13, 0x79, 0x61, 0x5F, 0xD2, 0x21, 0xBB, 0x86, 0xE7, 0xA7, 0x3A, 0xFB, 0xCD, 0xFF, 0x4A, 0x73, 0x9C, 0x79, 0x47, 0x3D, 0x73, 0xC5, 0xA3, 0x3F, 0x98, 0xD3, 0x11, 0xD9, 0x10, 0x6E, 0x38, 0xE0, 0x32, 0x53, 0x0D, 0x9D, 0xC0, 0x99, 0x82, 0xD9, 0xA0, 0x76, 0x4D, 0x7E, 0xB2, 0x5E, 0x57, 0x25, 0x18, 0x1B, 0x9D, 0x3E, 0x96, 0x46, 0x4C, 0x7B, 0xC8, 0xC0, 0x0F, 0x60, 0xD2, 0xE0, 0x86, 0x03, 0x91, 0x7B, 0x90, 0x5D, 0xA2, 0x71, 0x80, 0x69, 0xFB, 0xA8, 0x46, 0xCA, 0xDE, 0x82, 0x55, 0x27, 0x68, 0x10, 0x39, 0x2F, 0xAB, 0x4E, 0xEE, 0x27, 0x9A, 0x88, 0x8C, 0x61, 0x51, 0x66, 0x3D, 0x6F, 0xA1, 0xDC, 0xF2, 0x7C, 0xDA, 0x75, 0x39, 0x43, 0xF9, 0xE9, 0x99, 0x58, 0x19, 0x0B, 0xBF, 0xDB, 0xFC, 0x1A, 0x4B, 0x85, 0xD0, 0xEF, 0x64, 0x9D, 0x18, 0xC0, 0x09, 0x10, 0x01, 0x1C, 0xBF, 0x32, 0x2F, 0x75, 0xC9, 0x11, 0x29, 0x54, 0xA0, 0xBF, 0x18, 0x93, 0x02, 0x9B, 0x7A, 0x29, 0xF5, 0xCA, 0x9C, 0x31, 0x56, 0x03, 0x8E, 0x4C, 0x3F, 0xD4, 0x07, 0x05, 0xD6, 0x7C, 0x37, 0x40, 0x0D, 0x03, 0x94, 0x81, 0xA2, 0xA9, 0xF9, 0x6D, 0xF1, 0xFF, 0xE2, 0xC7, 0x14, 0x2C, 0x00, 0x93, 0xF9, 0x16, 0x43, 0xCC, 0x7E, 0x12, 0x26, 0xDE, 0x13, 0x52, 0xF3, 0x49, 0xBF, 0xE3, 0x40, 0xA1, 0xDF, 0x3C, 0x14, 0xC7, 0xE5, 0x1C, 0xC5, 0x9D, 0xDC, 0xCE, 0x81, 0x20, 0xDD, 0xDB, 0x2D, 0xDF, 0x73, 0x33, 0x40, 0xF3, 0xC9, 0xFE, 0x2D, 0x15, 0x05, 0xCC, 0xB7, 0xE4, 0x6C, 0xB3, 0xD3, 0xDF, 0xB8, 0x8F, 0x4D, 0x3C, 0xFB, 0xF9, 0x73, 0x2C, 0x60, 0x79, 0x54, 0x81, 0x1F, 0xC9, 0x5F, 0x7A, 0x9D, 0x03, 0xA3, 0xE1, 0x8D, 0x04, 0x58, 0x1F, 0x05, 0x9D, 0xC1, 0x01, 0xEC, 0xF1, 0x12, 0xE1, 0x86, 0x38, 0x10, 0x31, 0x0B, 0x2D, 0x6E, 0x98, 0xCC, 0x31, 0xEE, 0xFF, 0xCB, 0x7A, 0x1B, 0x05, 0x02, 0xC1, 0x82, 0x43, 0x77, 0x20, 0x68, 0x62, 0x39, 0x92, 0x56, 0xCF, 0xD9, 0x56, 0xF6, 0x25, 0x25, 0x73, 0x47, 0xAB, 0x1C, 0x88, 0x86, 0x13, 0x60, 0xFC, 0x28, 0xB6, 0xAC, 0xA2, 0x1D, 0xF6, 0x73, 0x20, 0xB6, 0xF4, 0x89, 0x2F, 0x97, 0x36, 0x9C, 0xD3, 0xB7, 0xC7, 0x3A, 0xEF, 0xF6, 0xBF, 0x8A, 0x27, 0xA0, 0xDE, 0xD0, 0x46, 0xEC, 0xD4, 0x05, 0x27, 0xA0, 0x83, 0x47, 0x11, 0x8B, 0xE6, 0x0F, 0xAB, 0x27, 0xC9, 0x41, 0x13, 0xB4, 0xFC, 0x13, 0xF0, 0xEB, 0xC4, 0x31, 0xED, 0x38, 0x52, 0x43, 0x0E, 0x9B, 0x4F, 0x56, 0xFF, 0x8E, 0xCB, 0xE6, 0x02, 0xDD, 0x68, 0x91, 0xEF, 0x01, 0x94, 0x43, 0x73, 0x4F, 0x7F, 0x14, 0xE7, 0x26, 0x06, 0xB1, 0xED, 0x14, 0x94, 0x01, 0x6F, 0x98, 0x01, 0xDA, 0x90, 0x04, 0x10, 0x18, 0x07, 0xF0, 0x92, 0x99, 0xB3, 0x09, 0x30, 0x9A, 0x0E, 0x00, 0x14, 0x38, 0x57, 0xA5, 0x8A, 0x78, 0xF7, 0x39, 0x57, 0x3C, 0x60, 0x20, 0xFF, 0x89, 0x49, 0xCB, 0x37, 0x24, 0x00, 0xAB, 0x86, 0x01, 0x7A, 0x00, 0x6E, 0x9C, 0xDC, 0x9F, 0xDC, 0x26, 0x68, 0xF5, 0x77, 0xA5, 0x19, 0x12, 0x76, 0x71, 0xD0, 0x96, 0x80, 0x89, 0x25, 0x85, 0x3A, 0x49, 0x1A, 0x5E, 0x1F, 0xA5, 0xF8, 0x43, 0x64, 0x1E, 0xCF, 0xF7, 0xE5, 0x39, 0x8B, 0x6A, 0xFE, 0x42, 0x9E, 0x23, 0x2E, 0xA0, 0x0D, 0x2E, 0x60, 0x0E, 0x58, 0x61, 0x0D, 0xFA, 0xBD, 0xDE, 0xF3, 0x4E, 0x4F, 0x68, 0x00, 0xA7, 0x76, 0x9E, 0x72, 0x74, 0x05, 0x82, 0xE7, 0xB6, 0xF8, 0x18, 0x49, 0x9E, 0x46, 0x3D, 0x0F, 0xD6, 0x2B, 0xE1, 0xED, 0xFF, 0xBA, 0xAF, 0xC7, 0xCE, 0x28, 0xD5, 0xA3, 0x7D, 0x64, 0x07, 0x10, 0x03, 0x74, 0x9E, 0x9D, 0x79, 0x0F, 0xE8, 0x19, 0x87, 0xE7, 0x3B, 0x57, 0xEC, 0x9F, 0xB2, 0x03, 0x43, 0xAD, 0x15, 0xF5, 0xA7, 0x32, 0x4D, 0xBC, 0x6F, 0xD8, 0x70, 0x06, 0x2A, 0x7D, 0x9D, 0x08, 0xF6, 0x85, 0x80, 0xE7, 0x17, 0x1C, 0x7F, 0xC7, 0x27, 0xC9, 0xEF, 0x02, 0xA8, 0x01, 0x1C, 0x00, 0xF6, 0x8A, 0x04, 0x66, 0xE0, 0x6E, 0x7A, 0x6D, 0x80, 0x99, 0x55, 0xB7, 0xD5, 0xDC, 0x70, 0x62, 0x5F, 0x3D, 0x07, 0x4C, 0x80, 0x0E, 0xB2, 0xA1, 0x0D, 0xDF, 0x30, 0x06, 0xC2, 0x1F, 0x65, 0xF5, 0x6C, 0x30, 0xC0, 0x53, 0x80, 0x36, 0x20, 0x1A, 0x39, 0xDF, 0x19, 0x13, 0x34, 0xFA, 0xBA, 0xF9, 0x32, 0x14, 0xFD, 0xDC, 0xE9, 0xDF, 0x27, 0x2D, 0x88, 0x05, 0x8B, 0xE9, 0xF7, 0xCE, 0x65, 0x62, 0xB4, 0x38, 0x84, 0xC1, 0xE4, 0x84, 0x64, 0xFB, 0xEE, 0xFA, 0xD3, 0xCB, 0x71, 0x93, 0xB3, 0x2B, 0x5A, 0x79, 0x1D, 0x36, 0x2B, 0x80, 0x3C, 0x80, 0x33, 0x10, 0x4B, 0x8B, 0x88, 0xCE, 0x4D, 0x4C, 0xC6, 0x2B, 0x41, 0xD1, 0x2F, 0xCA, 0xC0, 0x53, 0x3A, 0x0A, 0x31, 0x27, 0x3B, 0xE6, 0x02, 0xB0, 0x03, 0xAE, 0xC0, 0x6D, 0x54, 0x6E, 0xD0, 0xE0, 0x99, 0x15, 0x50, 0xDF, 0xA9, 0xAB, 0x63, 0x8D, 0x9B, 0x42, 0x00, 0xDC, 0x9F, 0x0C, 0x8D, 0xCD, 0xAB, 0x78, 0x82, 0xC6, 0x6B, 0x94, 0xCC, 0x92, 0x96, 0xE2, 0x9C, 0x10, 0x23, 0xE7, 0x24, 0xDF, 0x8B, 0x20, 0x4D, 0x02, 0x09, 0x93, 0x0E, 0x5A, 0xBC, 0xF7, 0xF5, 0xBB, 0xEC, 0xBD, 0x63, 0x17, 0x80, 0x3A, 0x20, 0x0D, 0x6A, 0x9C, 0x47, 0x22, 0xE8, 0x08, 0x90, 0x53, 0xC9, 0x9B, 0xC5, 0xE8, 0xC0, 0x3C, 0xDD, 0x67, 0x0D, 0x4C, 0xC9, 0xDD, 0xF3, 0x8B, 0x00, 0x91, 0x06, 0x01, 0xA6, 0x8D, 0x00, 0x34, 0x1B, 0xDA, 0x90, 0x46, 0x3C, 0x99, 0xA1, 0x02, 0x24, 0x00, 0x7E, 0xF2, 0x4B, 0xAF, 0xC2, 0x7E, 0xCC, 0xAF, 0x42, 0x13, 0x34, 0xF9, 0x53, 0x8C, 0x99, 0x4E, 0xFB, 0xFA, 0x51, 0xF8, 0x4F, 0x38, 0x8A, 0x27, 0xF2, 0xD5, 0x52, 0x04, 0xD6, 0x1C, 0xC6, 0x30, 0x0C, 0xD3, 0xC0, 0x0F, 0xAD, 0x3B, 0xC9, 0xA1, 0xFA, 0x08, 0x42, 0xDA, 0x14, 0xDA, 0x67, 0x13, 0xA5, 0x86, 0x3C, 0x33, 0x81, 0xFE, 0x38, 0x90, 0x06, 0x90, 0xBE, 0xEF, 0xF9, 0xB6, 0x3C, 0x53, 0xFC, 0x5A, 0x3A, 0xD0, 0xD3, 0x0E, 0x73, 0xEA, 0x11, 0xDF, 0x3B, 0x8F, 0x85, 0xB5, 0x37, 0xE8, 0x01, 0x37, 0x74, 0xCB, 0xC6, 0xE8, 0x01, 0x5C, 0x01, 0x7B, 0xD5, 0xFA, 0x1A, 0x87, 0x81, 0x95, 0xCD, 0x47, 0xD0, 0xF4, 0xBB, 0x45, 0x15, 0xA1, 0x36, 0x10, 0x89, 0x2E, 0x52, 0x18, 0x3D, 0x7F, 0x3F, 0xB5, 0xF5, 0xA5, 0x36, 0x71, 0xB9, 0xE0, 0xC4, 0xFB, 0x4A, 0x62, 0x2E, 0x02, 0x6F, 0x53, 0xDF, 0x23, 0x9E, 0x36, 0x7D, 0x91, 0x07, 0xC8, 0xDA, 0x9F, 0x24, 0x80, 0x23, 0xAF, 0x6D, 0xC3, 0x1E, 0xC9, 0x29, 0x01, 0x7C, 0xE6, 0x45, 0x97, 0xC2, 0x19, 0xDE, 0xDE, 0xAB, 0xA5, 0x99, 0xA3, 0xA1, 0x80, 0x11, 0xE0, 0xD1, 0x28, 0x20, 0xA4, 0xA1, 0x8D, 0x04, 0xEA, 0xB9, 0x5A, 0x69, 0x34, 0x9E, 0x7F, 0x47, 0x3A, 0x4F, 0x97, 0x52, 0x01, 0x9A, 0x13, 0x34, 0x34, 0x3D, 0xA6, 0x4E, 0x8F, 0xD5, 0xF4, 0x66, 0x06, 0xF4, 0x5A, 0x83, 0xBB, 0xEB, 0x38, 0xBA, 0x30, 0x66, 0x1F, 0x28, 0xF5, 0x5B, 0x59, 0xFA, 0xF4, 0x29, 0xDF, 0x51, 0x9C, 0x91, 0x3A, 0xF7, 0x69, 0xFC, 0xED, 0x8A, 0xE3, 0x88, 0xBF, 0x93, 0xE0, 0x53, 0x29, 0xE0, 0x05, 0x98, 0x00, 0x71, 0xF0, 0x2D, 0xAC, 0x80, 0x0B, 0xC0, 0xCB, 0x1F, 0xE0, 0xDC, 0xCE, 0xFF, 0x7B, 0xBB, 0x88, 0x5F, 0x4B, 0xB2, 0xDD, 0xCB, 0x82, 0x19, 0x20, 0x0C, 0x50, 0x6C, 0xF0, 0x69, 0x14, 0x60, 0x07, 0x48, 0x1B, 0x75, 0x8B, 0xC1, 0xE8, 0xB4, 0x03, 0xA9, 0x40, 0x38, 0x90, 0xF3, 0xF7, 0x49, 0xC7, 0xCC, 0xBF, 0xA3, 0xC6, 0x89, 0x82, 0x92, 0x3B, 0x31, 0x12, 0x43, 0x46, 0x30, 0xFC, 0x67, 0xEE, 0xF6, 0x15, 0x1D, 0xAD, 0x8A, 0x91, 0xCC, 0x9A, 0xB9, 0x7F, 0x50, 0xF6, 0x08, 0x3B, 0x30, 0x6D, 0x54, 0xC8, 0xE5, 0xCC, 0x38, 0xDB, 0xA0, 0x46, 0xCB, 0x1D, 0x08, 0xDE, 0x6D, 0x29, 0xD3, 0x57, 0xC4, 0xFA, 0xEA, 0xDA, 0x8C, 0xD1, 0xE5, 0xE8, 0xE1, 0x6C, 0x41, 0x13, 0xD6, 0x47, 0xEA, 0xDC, 0x00, 0x55, 0x20, 0x18, 0x48, 0x03, 0x4A, 0x1F, 0xE1, 0xF3, 0x03, 0x48, 0xED, 0x59, 0xBC, 0x13, 0x0D, 0x9E, 0x77, 0x36, 0xE0, 0x0C, 0xE8, 0x7C, 0x9A, 0xAE, 0xCA, 0xE8, 0xA0, 0x05, 0x14, 0xBF, 0x8A, 0x57, 0x91, 0x98, 0xD4, 0x71, 0x21, 0x08, 0x46, 0x46, 0x26, 0x7B, 0xBD, 0x79, 0xF5, 0xA8, 0xBC, 0xFC, 0xC3, 0xD7, 0x13, 0x98, 0xDC, 0xEC, 0x6D, 0xD9, 0xB6, 0x8E, 0x88, 0xDF, 0x66, 0x01, 0xF2, 0xC6, 0x01, 0x0E, 0x01, 0xD4, 0x28, 0x1E, 0xED, 0x9A, 0x91, 0xD5, 0x00, 0xA6, 0x5D, 0xEC, 0xF6, 0x55, 0xCB, 0xEF, 0x7F, 0xB0, 0xBF, 0xCA, 0xF7, 0x1D, 0x73, 0x3F, 0x80, 0x34, 0x8E, 0x6E, 0x65, 0x81, 0xB4, 0x86, 0x03, 0xC5, 0xDB, 0xFE, 0x54, 0x1D, 0x70, 0x6B, 0x08, 0x60, 0x0A, 0x28, 0x03, 0xD2, 0x50, 0x03, 0x72, 0x82, 0x96, 0xDF, 0x5B, 0x93, 0x6B, 0x3C, 0x40, 0x18, 0xCE, 0xB1, 0x89, 0xD9, 0x82, 0x74, 0x14, 0xA1, 0x8C, 0x09, 0x81, 0x98, 0x76, 0xE1, 0xCC, 0x95, 0x4D, 0xB3, 0x78, 0x56, 0xDA, 0x5C, 0x87, 0x2D, 0x67, 0xA5, 0xC9, 0x16, 0xD4, 0x10, 0x01, 0xE8, 0x19, 0x75, 0x9B, 0x5F, 0x22, 0x46, 0xA0, 0xA6, 0x03, 0xA3, 0xDE, 0xE0, 0x3D, 0x16, 0xC4, 0xF2, 0x53, 0xD3, 0x3F, 0x33, 0x34, 0xCA, 0xBE, 0x0F, 0x09, 0x75, 0xF6, 0xA7, 0x28, 0x20, 0xA9, 0xC1, 0x8D, 0x7A, 0xC4, 0xE8, 0x1C, 0x48, 0x06, 0x22, 0x00, 0x27, 0x40, 0x02, 0xA0, 0x04, 0x84, 0x81, 0xBC, 0xC7, 0xB4, 0xFA, 0x63, 0x7F, 0x73, 0x06, 0x87, 0x1C, 0x82, 0x73, 0x5A, 0x10, 0x34, 0x68, 0x0B, 0x9A, 0x34, 0x42, 0x52, 0xEB, 0x64, 0x7B, 0x78, 0x04, 0xA6, 0xAF, 0x7B, 0xA1, 0xBD, 0x2D, 0x7D, 0xF6, 0xE1, 0xDA, 0xA8, 0x4F, 0x33, 0xF9, 0xB9, 0xE6, 0x28, 0xAC, 0xC0, 0x34, 0x4B, 0xA7, 0x37, 0xA8, 0x97, 0x96, 0xF5, 0x26, 0xD6, 0xC9, 0x8D, 0x0C, 0xC0, 0xC7, 0x5B, 0xC5, 0x7A, 0xBD, 0xE9, 0x6F, 0x98, 0xC9, 0xFE, 0x2A, 0x59, 0xE5, 0xF4, 0x8E, 0x01, 0x91, 0x80, 0x3B, 0x60, 0x2F, 0x62, 0xFF, 0xB7, 0xD2, 0xED, 0xD7, 0xE0, 0xD1, 0x60, 0x40, 0x0B, 0x60, 0x01, 0x4E, 0x00, 0x7C, 0x80, 0x48, 0xC4, 0xCC, 0x70, 0x7B, 0xE2, 0x38, 0x2B, 0x99, 0x86, 0x7B, 0xE8, 0x37, 0x5E, 0xE5, 0xED, 0x74, 0xE3, 0x28, 0xAA, 0x19, 0xF5, 0x92, 0xA8, 0xE5, 0x24, 0xEE, 0xF5, 0xF4, 0x76, 0xBB, 0xCE, 0x9D, 0x71, 0x4A, 0x4A, 0xA3, 0x68, 0x64, 0x40, 0x36, 0x8A, 0x1A, 0xF2, 0x33, 0xB2, 0xC8, 0x8E, 0x0F, 0x35, 0x30, 0x45, 0xD0, 0x02, 0x35, 0x88, 0xA4, 0xC4, 0xF4, 0x74, 0x8E, 0x67, 0xF4, 0x16, 0xBB, 0x32, 0xDE, 0xCE, 0xA1, 0x94, 0xD3, 0x42, 0xF8, 0x38, 0xC5, 0x45, 0xC3, 0x9E, 0x41, 0x76, 0xEF, 0xFF, 0xA1, 0xA1, 0x04, 0x88, 0x03, 0x3C, 0x2D, 0x3C, 0x05, 0xA4, 0xFE, 0x3E, 0x21, 0xCB, 0x80, 0xA0, 0x11, 0xCE, 0xB4, 0x64, 0x2D, 0x72, 0x45, 0x5F, 0x83, 0x1F, 0x1F, 0x81, 0x74, 0x5A, 0x5A, 0x7B, 0xE0, 0x71, 0xF7, 0x12, 0x28, 0x86, 0xF7, 0x33, 0x96, 0x94, 0x89, 0xC9, 0x5B, 0x20, 0x38, 0x73, 0x36, 0x7D, 0x72, 0x56, 0xB7, 0x43, 0x41, 0xF1, 0xC9, 0xDF, 0x99, 0xC1, 0x29, 0xB6, 0xD3, 0x6F, 0x01, 0xF8, 0xB5, 0xC8, 0xBD, 0xD2, 0x52, 0xE3, 0x0C, 0xC2, 0xF3, 0x7B, 0x2E, 0x61, 0x44, 0xB2, 0xD1, 0x37, 0x69, 0x30, 0xE0, 0x01, 0x58, 0x36, 0xA2, 0x51, 0x80, 0xDB, 0xB6, 0xCA, 0x97, 0x86, 0x79, 0x83, 0x00, 0x71, 0x80, 0x78, 0x37, 0x75, 0x9F, 0xD8, 0xF6, 0xEB, 0x6E, 0x8C, 0xA1, 0x58, 0xAA, 0xF5, 0x1E, 0x30, 0xCA, 0xEF, 0x8B, 0xE6, 0xD4, 0x7D, 0xBE, 0xDA, 0x5E, 0x17, 0xDC, 0x0E, 0xF2, 0x3E, 0x47, 0xD9, 0x7E, 0x1D, 0x20, 0x66, 0xC0, 0x0C, 0xFD, 0x92, 0xDE, 0xB6, 0xDF, 0x33, 0x9D, 0x4E, 0x8D, 0x78, 0xA6, 0xA5, 0xEC, 0x00, 0x2E, 0x3F, 0x21, 0x25, 0xF4, 0xD1, 0x42, 0xF6, 0xBF, 0xB6, 0x47, 0x86, 0x50, 0xFF, 0xB7, 0xB1, 0x66, 0x99, 0xE9, 0x25, 0xDA, 0x5A, 0x62, 0x59, 0x80, 0x31, 0xC0, 0xF3, 0x6A, 0xA9, 0x86, 0x35, 0x74, 0x7B, 0x14, 0x73, 0x02, 0xAE, 0x40, 0x66, 0xE3, 0x75, 0x2C, 0x76, 0x40, 0x0F, 0x30, 0x8A, 0x74, 0x37, 0x66, 0x02, 0x07, 0x0A, 0x66, 0xF4, 0xEB, 0x53, 0xE0, 0x8F, 0x64, 0x43, 0xEB, 0xF2, 0xD1, 0xEE, 0x69, 0xD3, 0xB6, 0xFC, 0xE6, 0xDE, 0x67, 0xAA, 0x67, 0x7A, 0x10, 0xB3, 0xB3, 0x9A, 0x62, 0xE7, 0x0A, 0xCE, 0xA7, 0x3B, 0x7B, 0x73, 0xBA, 0x98, 0xAE, 0x0E, 0xDB, 0x31, 0x7C, 0xAA, 0x03, 0x78, 0xFE, 0xD0, 0x2E, 0xF1, 0x22, 0xD7, 0xBD, 0x81, 0x09, 0x20, 0xE9, 0x2F, 0x2A, 0xBE, 0x85, 0x26, 0x90, 0xDD, 0x9E, 0x2E, 0xDC, 0x0D, 0x76, 0x0A, 0x50, 0x4D, 0x63, 0x15, 0x60, 0x0D, 0xD1, 0x86, 0x34, 0x0C, 0x50, 0x07, 0x22, 0xB7, 0xAE, 0x95, 0x71, 0xE3, 0xE9, 0xE4, 0x63, 0x02, 0x4E, 0xED, 0xEF, 0xCC, 0x79, 0x38, 0xF5, 0x8F, 0x42, 0xE0, 0x76, 0x0D, 0x0F, 0x78, 0x3B, 0xE0, 0x69, 0x30, 0x2A, 0x1C, 0x2A, 0xF8, 0x89, 0x58, 0xD0, 0x58, 0x19, 0x3A, 0x63, 0x83, 0x88, 0xD9, 0x2B, 0x68, 0x55, 0xE3, 0xE1, 0x33, 0x26, 0x55, 0xDC, 0xE7, 0xD4, 0x98, 0xBF, 0xF6, 0xC1, 0x01, 0xB4, 0x43, 0x30, 0xAA, 0x63, 0xDA, 0x7F, 0x7D, 0x79, 0x07, 0xEB, 0x03, 0xCD, 0x3F, 0x40, 0xC3, 0xEE, 0xDA, 0xAD, 0x51, 0xAB, 0xE2, 0x6D, 0x78, 0xE6, 0xBC, 0xB5, 0xA0, 0x32, 0x1B, 0x07, 0x88, 0xF9, 0xF4, 0x0C, 0xC6, 0x7A, 0x02, 0x15, 0x0D, 0x05, 0xC2, 0xF7, 0xA2, 0x95, 0xC6, 0x75, 0x56, 0xB3, 0x8E, 0x99, 0x2D, 0xD7, 0x40, 0x0F, 0xFE, 0xDA, 0x13, 0xD2, 0x04, 0x33, 0xFF, 0x9C, 0x9D, 0xBD, 0x24, 0x54, 0x97, 0xD5, 0x30, 0x61, 0x13, 0xF2, 0x07, 0x6A, 0x66, 0xAF, 0x8E, 0xC9, 0xED, 0xF5, 0x9A, 0x24, 0xEC, 0x73, 0x7B, 0x71, 0x03, 0x54, 0x00, 0x92, 0xC7, 0x80, 0xBA, 0xFA, 0x8B, 0x67, 0x17, 0x16, 0xB5, 0xF6, 0x7C, 0x36, 0xC7, 0x9E, 0xED, 0xE1, 0x99, 0xC8, 0xAE, 0xA7, 0x35, 0xB2, 0x31, 0x37, 0xF8, 0xC3, 0xFD, 0x29, 0x5E, 0xEC, 0x9E, 0x34, 0xB2, 0xE7, 0xEA, 0x9E, 0x0D, 0x06, 0xEC, 0x00, 0xEC, 0x00, 0xE9, 0xE3, 0x98, 0x57, 0xF3, 0x74, 0xFA, 0x37, 0xB8, 0x6E, 0x8C, 0x94, 0x1A, 0xD9, 0xCE, 0x70, 0x14, 0x3B, 0xDA, 0x45, 0x92, 0xBB, 0x17, 0x24, 0x90, 0x29, 0x10, 0xDF, 0xA9, 0xEE, 0xF3, 0x74, 0x24, 0xC8, 0x5C, 0x6D, 0x0D, 0xE0, 0x77, 0x1E, 0xD8, 0x81, 0x78, 0xB3, 0x11, 0x07, 0xA8, 0xA9, 0xDB, 0x1E, 0x20, 0x6D, 0x57, 0xCE, 0xB5, 0x76, 0x94, 0xD5, 0x76, 0x28, 0x62, 0x3E, 0x3D, 0x9A, 0x13, 0x2E, 0x0D, 0x6D, 0x78, 0x23, 0x1E, 0xEB, 0x70, 0xDA, 0x4D, 0x2F, 0x96, 0x8D, 0x03, 0x88, 0x00, 0xC7, 0x9F, 0xAC, 0xBD, 0x00, 0x4E, 0x13, 0xB4, 0xF8, 0x93, 0x85, 0xAD, 0x3E, 0xBF, 0x14, 0xF9, 0xAF, 0x2B, 0x1E, 0x56, 0x07, 0xA8, 0x3C, 0x68, 0x22, 0x3F, 0xE2, 0x8C, 0x76, 0x88, 0xD0, 0x59, 0x62, 0x8F, 0x41, 0xA5, 0x9F, 0x9D, 0x47, 0x7F, 0xE7, 0xC0, 0x8A, 0xF7, 0x0F, 0xAC, 0x01, 0x70, 0x35, 0x64, 0x17, 0x57, 0x44, 0x81, 0x7A, 0x45, 0x39, 0x9E, 0xFF, 0x8F, 0x9E, 0x16, 0xD2, 0xE0, 0x9D, 0xC5, 0x37, 0x05, 0xB2, 0x26, 0x73, 0xD0, 0x48, 0x80, 0xB8, 0xE1, 0x80, 0x18, 0x10, 0x0C, 0x94, 0x3D, 0xF5, 0x74, 0x7D, 0x62, 0x98, 0x80, 0x36, 0x6A, 0x96, 0x1A, 0xAC, 0x8A, 0xF1, 0xCC, 0xFB, 0x57, 0xF3, 0xE2, 0x89, 0x1A, 0x94, 0x3A, 0x7A, 0x8D, 0x15, 0xCF, 0xDF, 0x5A, 0xC8, 0x19, 0xBB, 0x7D, 0x0F, 0xE8, 0x16, 0x1A, 0x5A, 0xBD, 0xA3, 0x47, 0x81, 0x70, 0x20, 0xDF, 0xBE, 0xA7, 0x86, 0x24, 0xC0, 0xDA, 0x58, 0x65, 0x20, 0xF9, 0x79, 0x52, 0x02, 0xC6, 0xF3, 0xD4, 0x3E, 0x7A, 0x4E, 0x0C, 0xA8, 0x3D, 0x95, 0xA2, 0xDC, 0x4F, 0xFB, 0xD1, 0x27, 0x4E, 0xD1, 0x28, 0x80, 0xED, 0xB1, 0x3E, 0x20, 0xA0, 0x0E, 0x90, 0xF1, 0x44, 0xCD, 0x01, 0x35, 0xC0, 0xF8, 0x8D, 0x1A, 0xBC, 0x8A, 0x35, 0xEA, 0x8F, 0xE1, 0xAE, 0x88, 0x9E, 0x04, 0xD3, 0x16, 0x1E, 0x2D, 0x4C, 0x32, 0x44, 0xCF, 0x99, 0x58, 0xB6, 0x39, 0xB5, 0x2E, 0x07, 0x59, 0x7B, 0x27, 0xD8, 0x95, 0x76, 0x4F, 0x82, 0x04, 0x60, 0x02, 0xB0, 0xED, 0xD2, 0xAB, 0x12, 0x70, 0xBF, 0xB8, 0x8A, 0x91, 0x70, 0xFE, 0x03, 0xC2, 0x96, 0xD6, 0x9C, 0xC7, 0xD6, 0xF2, 0xCE, 0x00, 0x34, 0x27, 0xA1, 0xB4, 0x7B, 0x20, 0xE2, 0x03, 0x2E, 0x5A, 0x40, 0xE4, 0x6E, 0x60, 0x3D, 0x09, 0xE8, 0x01, 0xE6, 0x2A, 0xC7, 0xFC, 0xC8, 0xDF, 0x39, 0xE0, 0x09, 0xD8, 0x01, 0xFC, 0x3A, 0x0D, 0x22, 0x68, 0x7E, 0xF0, 0x64, 0xE6, 0xF9, 0xC4, 0xF5, 0x4B, 0xFC, 0x4F, 0x7D, 0x15, 0x10, 0xDC, 0xA2, 0xDA, 0xA4, 0x38, 0xA3, 0x0A, 0xEE, 0x28, 0x35, 0xFB, 0xA5, 0xA1, 0x32, 0xF0, 0x8E, 0xFD, 0xCF, 0x12, 0x63, 0xDD, 0xFF, 0xAC, 0x2A, 0x80, 0x30, 0x40, 0xE7, 0x69, 0x36, 0xF4, 0x46, 0xCE, 0x32, 0x9A, 0x25, 0xB6, 0xBB, 0x37, 0xED, 0x69, 0x31, 0x38, 0x67, 0x2B, 0x76, 0x94, 0x01, 0xC1, 0xFB, 0x19, 0x2C, 0x1A, 0x61, 0x79, 0x20, 0x1C, 0x28, 0x6A, 0xC4, 0x63, 0xD1, 0x7E, 0x80, 0x90, 0xC7, 0x3B, 0xC7, 0x80, 0xC8, 0x47, 0xB7, 0xA1, 0xA1, 0x7A, 0x73, 0xC8, 0x1D, 0x34, 0x42, 0xD0, 0xDC, 0xBF, 0x05, 0xE7, 0x8C, 0xB2, 0x8A, 0x1C, 0x0C, 0x1B, 0xA7, 0x39, 0x5A, 0x55, 0xB9, 0x50, 0x35, 0x72, 0xC5, 0xFF, 0xAD, 0xBA, 0xFD, 0x1B, 0xEC, 0x69, 0xE4, 0xA0, 0xF8, 0x89, 0xB4, 0xF8, 0x2D, 0xEB, 0x13, 0xED, 0xC5, 0x61, 0x0C, 0x90, 0x6C, 0x75, 0x0D, 0x9D, 0x29, 0xF5, 0x5E, 0x93, 0xD5, 0x30, 0xDB, 0xDA, 0x39, 0x42, 0xBF, 0x32, 0xB2, 0xDE, 0x5D, 0x29, 0x75, 0x8F, 0x31, 0xC6, 0xD9, 0x2D, 0xB6, 0xFC, 0x88, 0x78, 0xEB, 0x69, 0x04, 0x10, 0xF3, 0x43, 0x38, 0xA0, 0x06, 0x48, 0x6C, 0x9F, 0x89, 0x6C, 0x04, 0x6D, 0xEB, 0x69, 0xC9, 0x09, 0x1A, 0x7F, 0x4B, 0x8C, 0x04, 0xB9, 0x0E, 0x2A, 0xFE, 0xE3, 0xED, 0x8C, 0xAA, 0x88, 0x04, 0x0A, 0x3D, 0x26, 0x1F, 0x8A, 0x15, 0xCE, 0xE5, 0xCC, 0xBB, 0x80, 0xB7, 0xC6, 0xC9, 0x7E, 0x42, 0x7D, 0x53, 0xAB, 0x63, 0x6A, 0xF4, 0x17, 0x2B, 0x00, 0x3F, 0x00, 0x13, 0x70, 0x1A, 0xF2, 0xB8, 0xF5, 0xCE, 0xEF, 0x92, 0x8F, 0xCF, 0x09, 0xCB, 0x6E, 0xA9, 0x3A, 0xBC, 0xFB, 0xA5, 0x48, 0x77, 0x2D, 0x33, 0xE8, 0x51, 0x37, 0x4F, 0x80, 0xE3, 0xE9, 0xC6, 0x4F, 0xA0, 0x72, 0x5B, 0x3C, 0x50, 0x6C, 0x5B, 0xE0, 0x08, 0xC0, 0x0F, 0x10, 0xA7, 0xBF, 0xF3, 0xAE, 0x34, 0xF9, 0xEA, 0x9C, 0x87, 0xE3, 0x93, 0x35, 0x2C, 0x85, 0x47, 0x76, 0x28, 0x0A, 0x78, 0xC9, 0xDA, 0x7F, 0x2B, 0x43, 0x4D, 0x83, 0xA3, 0xBB, 0x35, 0x73, 0xFB, 0xAF, 0xF3, 0x63, 0xE4, 0x53, 0xF2, 0x1B, 0x2B, 0xF4, 0x0B, 0x0D, 0x80, 0x13, 0x38, 0x67, 0x7B, 0xBD, 0xB8, 0x6F, 0xB1, 0xF2, 0x9A, 0xC4, 0xD2, 0x01, 0xAE, 0x3F, 0xC1, 0x88, 0x35, 0xCD, 0x72, 0x98, 0x56, 0x6B, 0x99, 0x5A, 0x4B, 0x07, 0xF4, 0xD5, 0x30, 0x69, 0xD4, 0xB4, 0xB1, 0x39, 0x40, 0x0A, 0x30, 0x03, 0x5A, 0xBB, 0xA7, 0x85, 0xAA, 0xA1, 0xBB, 0xED, 0x25, 0x0E, 0x60, 0x0A, 0xCC, 0x7D, 0x96, 0x7D, 0x82, 0xA6, 0x3D, 0x8C, 0xED, 0x7F, 0xD4, 0xB0, 0xD2, 0xD4, 0x30, 0xC6, 0xA8, 0x8E, 0xA0, 0x21, 0x0F, 0xC1, 0x28, 0xB5, 0x05, 0xA1, 0x4B, 0x59, 0x9F, 0x0B, 0x7B, 0x2D, 0xFF, 0xF5, 0xDE, 0xC5, 0x66, 0x0E, 0x1A, 0x3A, 0x3B, 0x80, 0x33, 0x30, 0xE5, 0xE0, 0x7A, 0xDF, 0x0E, 0x0E, 0xEC, 0xBB, 0x32, 0x9A, 0x4C, 0x90, 0xBB, 0xAA, 0x5D, 0x57, 0x23, 0xDF, 0xC6, 0x04, 0x6A, 0xC0, 0x39, 0x00, 0x15, 0x90, 0xF3, 0x2D, 0x01, 0xB8, 0x00, 0x91, 0xAF, 0xB1, 0xF8, 0x2E, 0xE7, 0x99, 0x02, 0x11, 0x0D, 0x01, 0x9C, 0x01, 0x25, 0x80, 0x1D, 0x90, 0x02, 0x32, 0x26, 0x68, 0xF6, 0x27, 0x71, 0xDD, 0x80, 0x8D, 0xC3, 0xAF, 0xFD, 0x45, 0xBE, 0xD1, 0x7C, 0xC1, 0x01, 0xBF, 0x0A, 0x95, 0x88, 0x28, 0x9C, 0x47, 0x35, 0xF6, 0x99, 0xC3, 0x9A, 0x95, 0x73, 0x52, 0xCB, 0x7D, 0x48, 0xE2, 0xE7, 0x15, 0x90, 0x05, 0x04, 0x03, 0x56, 0x80, 0xFB, 0x7E, 0x13, 0xD4, 0x94, 0x5E, 0x14, 0xA0, 0x67, 0x6C, 0x4A, 0x1F, 0xE3, 0xBC, 0x23, 0xFB, 0x38, 0x9F, 0xB1, 0xCB, 0x48, 0x21, 0x40, 0x52, 0xC3, 0x1A, 0x01, 0x14, 0xEF, 0x96, 0x60, 0x53, 0x20, 0x0F, 0x10, 0x0C, 0x98, 0x3D, 0x5E, 0xE7, 0x0D, 0x4A, 0xC0, 0x6B, 0xA2, 0xE6, 0x9F, 0x6A, 0x8E, 0x33, 0xCA, 0x4F, 0x5A, 0xF2, 0xC7, 0x0B, 0x66, 0x51, 0xFA, 0x2D, 0x58, 0xC3, 0xFB, 0xC7, 0x1C, 0x6F, 0x15, 0xB3, 0x3E, 0xA9, 0x3F, 0xA2, 0x56, 0xFE, 0x58, 0xFD, 0xCF, 0xAB, 0xCE, 0x63, 0x57, 0xBA, 0xAD, 0x00, 0x15, 0x80, 0x12, 0x98, 0xF3, 0xFF, 0xB5, 0x7B, 0x9B, 0x67, 0x49, 0x76, 0x4F, 0x38, 0x10, 0xB7, 0xDB, 0x23, 0xE6, 0xB9, 0x9E, 0xBE, 0xBB, 0x86, 0x04, 0xA0, 0x07, 0x08, 0x03, 0x66, 0x67, 0x3D, 0xDC, 0x70, 0x80, 0x4E, 0xC3, 0x1F, 0x8F, 0x87, 0x03, 0x14, 0x01, 0x19, 0x40, 0x18, 0x60, 0x02, 0x48, 0x01, 0xDA, 0x28, 0x9F, 0xA0, 0xC5, 0x1F, 0x63, 0x58, 0x3B, 0x8B, 0xC1, 0xF2, 0xD4, 0xBE, 0xE6, 0x04, 0xC7, 0xF1, 0xD6, 0x1D, 0x7A, 0x45, 0xD2, 0x1D, 0xB7, 0x63, 0x2D, 0x93, 0xBC, 0x8C, 0xB6, 0x3E, 0xAC, 0xD7, 0xE7, 0x94, 0x77, 0xEF, 0x7C, 0xBA, 0x01, 0xEA, 0x00, 0xEB, 0xAE, 0xB3, 0x7B, 0x35, 0xA8, 0xBF, 0x73, 0x1E, 0x61, 0x9B, 0x16, 0xDD, 0x00, 0x32, 0x01, 0xF2, 0xF5, 0x78, 0xDB, 0x9C, 0xD7, 0x0C, 0x10, 0x01, 0xEC, 0xEC, 0x0E, 0x3D, 0x27, 0x20, 0xA7, 0x6C, 0x2E, 0x00, 0x9D, 0x46, 0x01, 0x7A, 0x80, 0x20, 0xA0, 0x1A, 0x19, 0x8D, 0x03, 0xB8, 0x03, 0x66, 0x80, 0xFF, 0x92, 0x82, 0x08, 0x5A, 0x7E, 0x4B, 0x2C, 0x09, 0x39, 0x22, 0x36, 0x82, 0x66, 0x4A, 0x3B, 0xF9, 0xA4, 0x30, 0x4E, 0x7B, 0x49, 0xAD, 0x72, 0x9C, 0x1F, 0x88, 0x73, 0x86, 0x7C, 0x9E, 0xB2, 0x67, 0xCC, 0x42, 0x9F, 0xB3, 0x60, 0xEC, 0x69, 0x80, 0x7C, 0x75, 0xB9, 0xAF, 0xE7, 0x02, 0x70, 0x1C, 0xE0, 0x03, 0x4C, 0xA2, 0xC4, 0x0A, 0x60, 0xDE, 0x5E, 0x0D, 0x24, 0x53, 0x5D, 0x9C, 0x16, 0x5D, 0x40, 0x19, 0xF0, 0xA9, 0x46, 0x5D, 0x23, 0x17, 0x40, 0x0B, 0x08, 0x01, 0x52, 0x81, 0xEA, 0x3F, 0x8C, 0x15, 0xF0, 0x46, 0x66, 0xC3, 0x81, 0xB0, 0xA7, 0xBE, 0xD2, 0xB0, 0x6B, 0x92, 0xDC, 0x41, 0xAB, 0xEF, 0xBD, 0x49, 0xC9, 0x3D, 0xD6, 0x03, 0xB1, 0xB9, 0x23, 0x05, 0x89, 0x98, 0xCE, 0x70, 0x9F, 0x64, 0x7C, 0xBF, 0x17, 0xFE, 0x72, 0x08, 0xF5, 0xD5, 0x1C, 0xD4, 0xD2, 0x57, 0x1A, 0x72, 0x9A, 0x9C, 0xE6, 0xC7, 0x46, 0xB4, 0xC6, 0xCA, 0x1A, 0x90, 0xFE, 0x62, 0xE4, 0x16, 0x26, 0x9D, 0x4F, 0x32, 0x2D, 0x93, 0x8F, 0xCA, 0x0F, 0xD7, 0x56, 0x72, 0x9A, 0xC2, 0x93, 0xE5, 0x16, 0xFF, 0xA3, 0x02, 0x94, 0x26, 0x4C, 0xBB, 0x80, 0x14, 0x3E, 0x35, 0x3F, 0x80, 0x14, 0x60, 0x07, 0x6C, 0x1C, 0xB4, 0x0B, 0x90, 0x6C, 0x30, 0x30, 0x9A, 0xD4, 0xA9, 0x80, 0x1F, 0x20, 0xC6, 0xEE, 0x84, 0x11, 0xB4, 0x68, 0x07, 0x5C, 0x4A, 0xE4, 0x47, 0x99, 0x90, 0x4B, 0xF3, 0x9E, 0x91, 0xAD, 0xC4, 0x9F, 0xCC, 0xFC, 0x41, 0x2B, 0x5B, 0xEF, 0x15, 0x52, 0x43, 0xBB, 0xB7, 0x7B, 0xAD, 0x34, 0x5E, 0x42, 0x49, 0xF8, 0x61, 0x56, 0x11, 0x36, 0x19, 0x98, 0x56, 0xDB, 0x4C, 0xC0, 0x0D, 0xA8, 0xF8, 0x7D, 0x27, 0x8C, 0x5F, 0x81, 0xFE, 0xA2, 0x76, 0xB0, 0xFD, 0xF9, 0xFF, 0x66, 0x7E, 0x3F, 0x26, 0x22, 0x77, 0x11, 0x03, 0x35, 0x03, 0x7D, 0x01, 0x44, 0xA3, 0x74, 0x04, 0xF9, 0x01, 0x31, 0xC0, 0x0B, 0x28, 0x02, 0xB2, 0x1A, 0x06, 0x84, 0x00, 0x6E, 0x5B, 0x82, 0x87, 0x27, 0x68, 0xD4, 0x83, 0xA4, 0x02, 0xFD, 0x67, 0x45, 0x11, 0xFD, 0x83, 0x0A, 0x3A, 0xAD, 0x90, 0x0E, 0x1E, 0xE7, 0x75, 0x6D, 0x75, 0x6F, 0x85, 0x1B, 0xD9, 0x5B, 0xF6, 0x8C, 0xBF, 0x07, 0x51, 0xC4, 0x77, 0x84, 0x2D, 0xC6, 0x3A, 0x3F, 0x00, 0xEE, 0x44, 0x77, 0x15, 0x10, 0x0C, 0xF8, 0xFA, 0x16, 0xB9, 0x9E, 0x22, 0x62, 0x80, 0xAE, 0x72, 0x3B, 0x6A, 0x1A, 0x6D, 0x37, 0x3E, 0x82, 0x5E, 0x00, 0x4F, 0x06, 0x91, 0x80, 0x74, 0x20, 0xA2, 0x21, 0x8D, 0x04, 0x92, 0x81, 0xE2, 0x2D, 0x5A, 0xAB, 0x06, 0xF8, 0x20, 0x1A, 0x0C, 0x98, 0x35, 0x08, 0x70, 0x19, 0x7B, 0xF3, 0x8E, 0x19, 0xA3, 0x77, 0xA3, 0x0A, 0x2A, 0x4D, 0x07, 0x92, 0x73, 0x6E, 0xD8, 0xD2, 0x54, 0x03, 0x0D, 0x76, 0xA3, 0x10, 0x84, 0x22, 0xA8, 0x44, 0x1A, 0x0E, 0xB5, 0xFF, 0x9C, 0xBC, 0x28, 0xBA, 0xD5, 0x88, 0x79, 0x68, 0x80, 0xF2, 0x55, 0xD7, 0x59, 0xB3, 0x77, 0xEB, 0x1E, 0x6D, 0xD3, 0x5A, 0xD5, 0xCB, 0x4E, 0x12, 0xE0, 0xDC, 0x9A, 0xA5, 0xF3, 0x56, 0x30, 0x59, 0x5A, 0xC2, 0x9A, 0x8D, 0xDA, 0x5B, 0xBE, 0x12, 0xE0, 0x8D, 0x10, 0x20, 0xCF, 0x5B, 0xCF, 0x51, 0xC0, 0x0C, 0x88, 0x6C, 0x18, 0xE0, 0x07, 0x90, 0xC7, 0xF9, 0x47, 0x1C, 0xC8, 0x09, 0x9A, 0x40, 0x59, 0x31, 0xEE, 0xB8, 0x4A, 0x03, 0xB9, 0xA1, 0x2C, 0x6D, 0xD9, 0x8F, 0x68, 0x2F, 0x19, 0xC5, 0x3F, 0xB1, 0xD7, 0xEA, 0xE4, 0xB8, 0x0B, 0x6D, 0x35, 0xC5, 0x4D, 0xB9, 0x9C, 0xF5, 0x5A, 0x5A, 0x24, 0x03, 0x4E, 0xC0, 0xB9, 0x36, 0x12, 0x00, 0x9D, 0x99, 0xC2, 0x07, 0x4C, 0x01, 0x71, 0x80, 0x15, 0x38, 0xBD, 0xD0, 0xB2, 0xE1, 0x07, 0x10, 0x01, 0x58, 0x01, 0xF2, 0x46, 0x34, 0x12, 0x60, 0x6A, 0x14, 0x20, 0x0E, 0x68, 0x00, 0x9E, 0x40, 0x1A, 0x50, 0xDA, 0xC8, 0xD1, 0x2B, 0x6B, 0x14, 0x40, 0x0E, 0x70, 0x02, 0xD3, 0x3B, 0x1A, 0xDA, 0x95, 0xD4, 0x42, 0xB0, 0x66, 0x3E, 0x3A, 0x09, 0xD5, 0x96, 0x48, 0x94, 0x42, 0x12, 0x39, 0x7B, 0x3E, 0x89, 0x6A, 0x4B, 0xD9, 0x97, 0x68, 0x9E, 0x22, 0xC1, 0xD5, 0x1F, 0x5C, 0x53, 0x4E, 0xDC, 0xC5, 0x36, 0xE9, 0x85, 0x22, 0x5F, 0xBD, 0x14, 0x48, 0x06, 0xD8, 0xDB, 0x10, 0x3F, 0x01, 0xD6, 0x46, 0x01, 0xD9, 0xDF, 0x29, 0xD5, 0x38, 0xF8, 0xA2, 0x09, 0xFE, 0x30, 0xEB, 0x9F, 0x42, 0x7B, 0x07, 0x96, 0x2E, 0xC8, 0x24, 0x01, 0xCA, 0x00, 0x17, 0x40, 0xD2, 0x38, 0xCF, 0xA7, 0x00, 0x84, 0x00, 0x0B, 0xA0, 0xBA, 0x28, 0x71, 0xBC, 0x11, 0x0D, 0x7D, 0xE0, 0x00, 0x15, 0x60, 0xD1, 0x31, 0x83, 0xF4, 0xA3, 0x28, 0xB5, 0x4A, 0x27, 0xE1, 0x1F, 0xE5, 0x64, 0x7B, 0xAD, 0x74, 0xA3, 0x82, 0x2A, 0xBE, 0x38, 0x92, 0x11, 0xCA, 0x38, 0x94, 0xBD, 0xB2, 0xDD, 0xF1, 0xCB, 0x43, 0x4C, 0x35, 0xF8, 0x76, 0x05, 0xE1, 0x6A, 0x0D, 0x63, 0x13, 0x07, 0xF4, 0x03, 0xFF, 0xFD, 0x16, 0x9A, 0xB2, 0xDC, 0xAF, 0x0E, 0x84, 0xB3, 0xE5, 0x87, 0xF9, 0xDF, 0xCD, 0x7F, 0xA5, 0x77, 0xEA, 0x35, 0x31, 0x0F, 0x50, 0xDD, 0x4F, 0x74, 0x80, 0xB2, 0xDE, 0x24, 0xBD, 0x37, 0xC9, 0x02, 0x24, 0xDF, 0xD6, 0xA4, 0xAD, 0x35, 0xA1, 0x06, 0x78, 0x35, 0xB2, 0x41, 0xFB, 0xBF, 0x89, 0x02, 0x53, 0xA8, 0x9A, 0x33, 0x5A, 0x38, 0x8A, 0x9E, 0xDE, 0xFD, 0x17, 0x61, 0x5D, 0x49, 0xD7, 0xEF, 0x9F, 0x56, 0x34, 0x50, 0x8E, 0x23, 0xC4, 0x6C, 0xD4, 0x89, 0xBA, 0x25, 0x81, 0xF5, 0x75, 0xA4, 0x11, 0xC4, 0xCC, 0xA7, 0x60, 0x88, 0x6F, 0xB5, 0x6B, 0xE9, 0x9F, 0x07, 0xA8, 0x02, 0xB4, 0xDA, 0x89, 0xFE, 0x00, 0x46, 0x40, 0x64, 0x7F, 0x67, 0x17, 0x3D, 0xD3, 0x00, 0x65, 0xFC, 0xB7, 0x94, 0x9F, 0x6D, 0x0C, 0x5F, 0x6F, 0xAE, 0x3A, 0xDB, 0xE1, 0x49, 0x14, 0x50, 0x03, 0x8C, 0x1F, 0x04, 0xE0, 0xA7, 0x51, 0x40, 0x59, 0x17, 0x1A, 0x03, 0xF0, 0x03, 0x58, 0x02, 0x6A, 0x00, 0x13, 0x70, 0x12, 0xE0, 0xB3, 0xE5, 0xE6, 0x22, 0x3E, 0x95, 0xD6, 0x43, 0xF5, 0xA7, 0xBE, 0x9A, 0xD2, 0x2D, 0xAB, 0xE0, 0xA4, 0x46, 0x81, 0xE2, 0x91, 0x3B, 0xEA, 0x12, 0x96, 0x98, 0x94, 0x74, 0x9F, 0x56, 0x84, 0xC7, 0x8A, 0x40, 0x1E, 0x4F, 0x80, 0xC3, 0x00, 0x9D, 0x47, 0x30, 0x2E, 0x01, 0x3B, 0xFF, 0x18, 0xC8, 0x57, 0x5E, 0xBD, 0x89, 0x6B, 0xAC, 0x72, 0x8D, 0x58, 0xD4, 0x01, 0x22, 0x00, 0xE7, 0xC6, 0x4C, 0x2E, 0x3C, 0xD6, 0xC3, 0x25, 0xBB, 0x2F, 0x4F, 0x1D, 0x30, 0x02, 0xFC, 0x00, 0x39, 0xA9, 0x91, 0x86, 0xBD, 0x0D, 0xCF, 0x8F, 0x06, 0x59, 0x36, 0x6A, 0xBE, 0x73, 0x4A, 0xC5, 0x91, 0x5F, 0x15, 0x2A, 0x8F, 0x4D, 0xB8, 0x60, 0xF7, 0x5C, 0xDD, 0xA2, 0x86, 0x38, 0x85, 0xD4, 0x07, 0x72, 0x0B, 0xCC, 0x7E, 0x84, 0x4F, 0xBA, 0xF6, 0xB9, 0x42, 0xC9, 0xA4, 0x6D, 0xFF, 0x55, 0x56, 0x51, 0xC0, 0x1F, 0x7F, 0x69, 0x2A, 0xE0, 0x08, 0x40, 0x07, 0x10, 0x07, 0x34, 0x81, 0x23, 0x5B, 0x58, 0x48, 0xB4, 0xC1, 0x00, 0x17, 0x20, 0x0E, 0xA4, 0xEC, 0x24, 0xAE, 0x36, 0x22, 0x9E, 0x2E, 0x46, 0x03, 0x88, 0x00, 0x69, 0x38, 0x03, 0xF9, 0x4C, 0xF3, 0x7A, 0x00, 0x5A, 0x80, 0xF8, 0xFE, 0x74, 0x53, 0x1C, 0xED, 0x55, 0x7C, 0x24, 0x3E, 0xB0, 0xE6, 0xC4, 0x0E, 0x3B, 0xBE, 0x17, 0x4A, 0x34, 0xD4, 0xF2, 0xBC, 0x4C, 0x98, 0x35, 0xF1, 0x7F, 0xCD, 0x14, 0x4F, 0x0C, 0x54, 0x9F, 0xCA, 0x98, 0x00, 0x92, 0x00, 0xC5, 0x53, 0x99, 0x8A, 0x86, 0x4C, 0x2E, 0x64, 0xB7, 0xE9, 0x52, 0x3C, 0x2A, 0x57, 0x04, 0xD0, 0xD3, 0x44, 0xFB, 0x0E, 0x96, 0x5C, 0x2D, 0xBA, 0x99, 0xCD, 0xD2, 0xAD, 0x8C, 0xC0, 0x0E, 0x88, 0xEE, 0xD5, 0x14, 0xE7, 0xFF, 0x30, 0x78, 0xA6, 0x9D, 0xB6, 0xF5, 0x02, 0x92, 0xFB, 0x5B, 0x26, 0xC3, 0x91, 0x50, 0x2E, 0xE1, 0xF4, 0x0F, 0x6E, 0x06, 0x4D, 0x65, 0x17, 0x54, 0xF0, 0x8C, 0x91, 0x3B, 0xC9, 0x4E, 0x26, 0x70, 0x77, 0x2C, 0x8B, 0x4E, 0xDA, 0xF6, 0x29, 0x10, 0x4C, 0xF1, 0x55, 0x9E, 0x09, 0xDC, 0x47, 0xF4, 0xB7, 0x18, 0x70, 0x01, 0xE4, 0xE9, 0x97, 0x75, 0x7F, 0x86, 0x5C, 0x02, 0x60, 0xD9, 0xF9, 0xFE, 0xF3, 0xF4, 0x13, 0xB3, 0xEC, 0x0D, 0xC0, 0x62, 0x8F, 0x98, 0x8B, 0x00, 0xD1, 0xA8, 0x49, 0xED, 0x37, 0x88, 0x01, 0x09, 0x20, 0x6C, 0x27, 0x6A, 0x2B, 0x80, 0x24, 0xC0, 0x0A, 0x50, 0x05, 0xCC, 0x27, 0x9D, 0x39, 0x41, 0xA3, 0x4F, 0x19, 0x81, 0x4B, 0xBF, 0x8E, 0xEE, 0xB0, 0x16, 0xD7, 0x4F, 0x47, 0x77, 0x80, 0x46, 0xA7, 0xF2, 0xB9, 0x9B, 0x93, 0x0B, 0x99, 0x26, 0x1D, 0xF1, 0x97, 0xB7, 0x14, 0x75, 0x6B, 0xBE, 0xDB, 0x34, 0x58, 0xA2, 0xF1, 0xE4, 0xAC, 0x55, 0xB7, 0x1B, 0x88, 0xF3, 0x1E, 0xB9, 0xD4, 0xDA, 0xCA, 0x86, 0xE6, 0xFB, 0x71, 0x21, 0xDD, 0x19, 0x32, 0x5D, 0x8B, 0x58, 0x67, 0xFE, 0xE6, 0xF6, 0x36, 0xBF, 0x86, 0xB9, 0x6E, 0x8F, 0xAC, 0x63, 0xEE, 0xE1, 0xDC, 0xC8, 0x6D, 0x5F, 0x39, 0x5A, 0x3E, 0x69, 0xBB, 0x8F, 0x48, 0x02, 0xD0, 0xF9, 0xCE, 0xB9, 0xAC, 0x27, 0x7F, 0x43, 0x64, 0x72, 0x0C, 0x55, 0x95, 0x13, 0x90, 0x21, 0xD5, 0xC2, 0xBD, 0x53, 0x04, 0xC2, 0xD5, 0x5C, 0xC8, 0xDA, 0x0B, 0x23, 0x2B, 0x98, 0x5B, 0x91, 0xC3, 0xE8, 0xB1, 0x57, 0xE1, 0x25, 0x84, 0x0F, 0x4F, 0x54, 0xA0, 0x80, 0xF3, 0x48, 0x8D, 0x96, 0x01, 0xCE, 0x40, 0xD4, 0xA4, 0xA0, 0x27, 0xA9, 0xBA, 0x85, 0xB3, 0x8F, 0xEC, 0x39, 0xA1, 0xDD, 0x3A, 0x6E, 0x7F, 0xBB, 0xC4, 0x7D, 0x67, 0x87, 0xBC, 0xFA, 0xD7, 0x4D, 0x20, 0x0C, 0x28, 0x7E, 0xFC, 0x76, 0x45, 0x81, 0xB1, 0x21, 0x3C, 0xBC, 0xB3, 0x26, 0x69, 0x80, 0xEB, 0x33, 0xCD, 0xCB, 0x53, 0xFE, 0xEB, 0xA0, 0x09, 0x82, 0xC6, 0xF4, 0x75, 0xC3, 0x13, 0x23, 0x76, 0xC7, 0x71, 0xEF, 0x4C, 0x6A, 0x0F, 0x02, 0x39, 0x1F, 0x9C, 0x14, 0x35, 0x19, 0xD5, 0xF5, 0x22, 0x30, 0x5E, 0x8F, 0xA7, 0x20, 0x76, 0x50, 0x15, 0xDD, 0x13, 0x3E, 0x66, 0xC0, 0x94, 0x5A, 0xCA, 0x01, 0x7B, 0xA6, 0x6A, 0x32, 0x3A, 0xAE, 0x3E, 0x2A, 0x7B, 0x00, 0xD1, 0xF6, 0xB2, 0x71, 0xDD, 0x21, 0x14, 0x07, 0xE8, 0x00, 0x7E, 0xF6, 0xE4, 0x8B, 0xCF, 0xFF, 0xDE, 0xD0, 0x03, 0x98, 0x00, 0xFE, 0x86, 0x90, 0x13, 0x30, 0x6F, 0x10, 0x20, 0x05, 0x50, 0x02, 0xC7, 0xF7, 0x27, 0x8F, 0x0E, 0x9A, 0x7E, 0x9D, 0x2F, 0x98, 0xE2, 0x39, 0xD0, 0x1F, 0x5D, 0x2F, 0x02, 0xE4, 0xBA, 0x2B, 0x2D, 0xF0, 0x3E, 0x67, 0x43, 0x87, 0x0B, 0x12, 0x90, 0x1C, 0xAF, 0x15, 0xC1, 0x64, 0x6D, 0x45, 0x9E, 0xD2, 0x3F, 0x03, 0xCC, 0xFF, 0x7A, 0x89, 0x36, 0xE4, 0x19, 0x1E, 0x11, 0x03, 0x52, 0x00, 0x9E, 0xEF, 0x94, 0x67, 0x40, 0x51, 0x81, 0x48, 0x20, 0xD7, 0x78, 0x8A, 0xDE, 0x82, 0x0D, 0x05, 0x10, 0xB9, 0xE3, 0xCA, 0x0C, 0x88, 0x02, 0x2E, 0xDB, 0xB6, 0x5B, 0xAB, 0xC1, 0xC0, 0xAD, 0x36, 0xE4, 0x23, 0x95, 0x7E, 0xEE, 0x4C, 0x57, 0x07, 0x0D, 0x05, 0x02, 0x65, 0xC5, 0xC9, 0xA3, 0xC1, 0x9A, 0xB8, 0x39, 0x58, 0x6F, 0x1F, 0x86, 0x3A, 0x81, 0x48, 0x7C, 0x9F, 0xE6, 0xC8, 0xB1, 0x54, 0xF5, 0x57, 0xFD, 0xCE, 0x73, 0xE7, 0xD6, 0x53, 0x81, 0x48, 0x40, 0x0B, 0x20, 0x7A, 0x14, 0x20, 0x9E, 0x3A, 0x9C, 0x2A, 0x50, 0x05, 0xDC, 0x76, 0x00, 0xDD, 0x93, 0x41, 0x6E, 0x00, 0x37, 0xE8, 0xEC, 0xF1, 0x38, 0xCE, 0xFD, 0x1A, 0x3A, 0x02, 0x90, 0x01, 0x7C, 0x1A, 0xBE, 0x5F, 0x2E, 0xB3, 0xCD, 0x52, 0x35, 0x64, 0xEF, 0xB6, 0xEF, 0xC9, 0xC3, 0x6F, 0x9E, 0x7E, 0x82, 0xE6, 0x18, 0xF5, 0x14, 0xFE, 0x84, 0x47, 0xB3, 0x2D, 0xEC, 0xC3, 0x0A, 0xA5, 0x28, 0x67, 0xA8, 0x33, 0x38, 0x61, 0x15, 0x90, 0x63, 0xC1, 0x25, 0x6D, 0x15, 0x30, 0x79, 0xDF, 0x9E, 0xF5, 0x08, 0xD0, 0x2A, 0xA0, 0x09, 0x90, 0x6D, 0xBB, 0x79, 0x75, 0x80, 0x05, 0x90, 0xA7, 0x3E, 0x2E, 0xDA, 0x9F, 0x0A, 0x90, 0x47, 0x6B, 0xC4, 0x13, 0x90, 0x06, 0xD7, 0xEF, 0x8B, 0x72, 0xFF, 0xA2, 0xD3, 0x90, 0x00, 0x4C, 0x00, 0x7F, 0xD5, 0x53, 0x72, 0xAB, 0x37, 0xA9, 0x36, 0x18, 0xE0, 0xDC, 0x8A, 0xC5, 0x25, 0xAB, 0x9E, 0xFA, 0x3B, 0x72, 0x04, 0x86, 0xFC, 0x15, 0x15, 0x01, 0xD5, 0xC0, 0x6D, 0x8F, 0x0A, 0xA9, 0xEE, 0x8A, 0x9E, 0x63, 0xA8, 0xDE, 0x1F, 0xE5, 0x83, 0x57, 0x2D, 0x11, 0x30, 0xE7, 0xC7, 0x93, 0xC6, 0xAE, 0x77, 0xD3, 0x34, 0x49, 0x0B, 0xE0, 0x09, 0xD0, 0xB2, 0x34, 0xE1, 0x2B, 0x78, 0xEB, 0x02, 0xC8, 0xD3, 0x58, 0x1C, 0x0A, 0x70, 0xEF, 0xCF, 0x12, 0xCB, 0xFF, 0x94, 0x6D, 0xF7, 0xD6, 0x5A, 0x4E, 0x03, 0xC8, 0xE3, 0x77, 0x94, 0xB6, 0x7D, 0x8C, 0xDF, 0x1F, 0x22, 0x6D, 0x32, 0xB3, 0x80, 0x1D, 0x20, 0x68, 0xC3, 0x79, 0xFF, 0x37, 0x25, 0xC0, 0xAE, 0x63, 0x47, 0x07, 0x2D, 0x71, 0xC5, 0x1A, 0x9F, 0x67, 0xB7, 0xCE, 0xC1, 0x4F, 0xD6, 0xD6, 0x3B, 0x61, 0x99, 0x1F, 0xC8, 0xB8, 0xFF, 0x64, 0x64, 0x6D, 0xE3, 0x55, 0xD5, 0x17, 0xFA, 0x9D, 0x8D, 0xC6, 0xE8, 0x91, 0xB1, 0x0E, 0x7B, 0x32, 0xA1, 0x3F, 0xE5, 0x63, 0xB8, 0xAB, 0xD3, 0x08, 0x0B, 0x58, 0x35, 0x02, 0x70, 0x01, 0xB8, 0x7F, 0x50, 0x23, 0xE0, 0xD0, 0xAE, 0x32, 0x90, 0x35, 0x08, 0x98, 0xB4, 0xAB, 0x8F, 0x27, 0x56, 0x6E, 0xB1, 0xF2, 0xC8, 0xFE, 0x21, 0x14, 0x60, 0x01, 0x8C, 0x81, 0x14, 0xA0, 0x46, 0x6D, 0x8C, 0x1B, 0x93, 0x29, 0xB5, 0xC6, 0xDC, 0xFE, 0x13, 0x50, 0xED, 0xA0, 0x41, 0x8F, 0x2F, 0x4C, 0xDB, 0xED, 0xC2, 0xDB, 0xCD, 0xC1, 0xE1, 0x94, 0xD8, 0x23, 0x3E, 0x5C, 0x02, 0x30, 0x43, 0x72, 0xD1, 0x21, 0x37, 0x17, 0xEF, 0x4A, 0x63, 0xFE, 0x6D, 0x66, 0xF5, 0xB7, 0x4C, 0x60, 0x0A, 0x14, 0x01, 0x16, 0xBB, 0xCF, 0x5C, 0x6C, 0x24, 0x72, 0xB6, 0x1C, 0x2D, 0xD9, 0xE3, 0xA1, 0x33, 0x79, 0xF3, 0x39, 0x10, 0xD8, 0xAA, 0x22, 0x0B, 0xEF, 0x63, 0x97, 0xD5, 0x4C, 0x70, 0xCB, 0xEE, 0x00, 0x1A, 0xBD, 0x53, 0x69, 0x18, 0x03, 0x9E, 0xC0, 0x08, 0xB6, 0xA9, 0x02, 0x21, 0x8D, 0xC7, 0xFD, 0x53, 0x9E, 0xE9, 0x01, 0x31, 0x20, 0x13, 0x41, 0xAB, 0x6E, 0x0D, 0x50, 0xEB, 0x11, 0x2D, 0xEA, 0xDF, 0xD2, 0xBF, 0x2A, 0xDE, 0xE9, 0xA6, 0xE5, 0x4A, 0xFE, 0xE0, 0xF3, 0x17, 0x38, 0x32, 0x43, 0xF6, 0x0E, 0x5E, 0x9C, 0x3B, 0x9A, 0xBE, 0xC5, 0xE3, 0xFC, 0xEA, 0x9D, 0xEE, 0x06, 0x6A, 0x91, 0x9D, 0x7D, 0x97, 0xC1, 0x01, 0xC6, 0x17, 0xE1, 0x0C, 0xB8, 0xBF, 0xD3, 0x01, 0x57, 0xC0, 0x12, 0xD0, 0x00, 0x7C, 0x59, 0x8F, 0xE3, 0x58, 0x81, 0xA4, 0x45, 0xAF, 0x22, 0x31, 0x20, 0xCF, 0xD8, 0x4B, 0x03, 0xDC, 0x50, 0x03, 0x3C, 0x81, 0x28, 0x20, 0x03, 0xA8, 0xD3, 0x18, 0x0F, 0x60, 0x07, 0xA8, 0xA1, 0xDE, 0x31, 0x23, 0x94, 0x3C, 0x85, 0xBF, 0xE1, 0x81, 0xC3, 0x89, 0x17, 0x80, 0x08, 0x74, 0x26, 0xA9, 0x7A, 0x00, 0x9F, 0x5B, 0x0A, 0xD9, 0xE0, 0x03, 0xA8, 0xB9, 0x0D, 0xDD, 0x6C, 0x29, 0xDC, 0xEA, 0x1D, 0x84, 0x71, 0x9A, 0x39, 0xBE, 0x06, 0xD5, 0x1E, 0xF1, 0x3A, 0xBA, 0x86, 0x00, 0xF2, 0x1E, 0x39, 0x15, 0xB8, 0x53, 0xC4, 0x0C, 0xE8, 0x9C, 0x43, 0x69, 0x74, 0x36, 0xE6, 0xE0, 0xBA, 0x9C, 0xC3, 0xDC, 0xFF, 0x35, 0x92, 0x3C, 0x7E, 0x06, 0xB3, 0x8A, 0x0E, 0x03, 0x5C, 0x80, 0xD6, 0xF6, 0x90, 0xD5, 0x03, 0x84, 0x02, 0x5E, 0x80, 0x11, 0xC0, 0x0A, 0x9C, 0x06, 0x05, 0x30, 0xA9, 0xEE, 0xE2, 0xEE, 0x87, 0xAF, 0x1E, 0x53, 0x11, 0xE4, 0x54, 0x0D, 0x06, 0xA6, 0x12, 0xD1, 0x45, 0xA2, 0xFC, 0xA0, 0x81, 0x10, 0x72, 0xD4, 0x92, 0x3A, 0x8F, 0x38, 0xBF, 0xDC, 0x83, 0xFE, 0x44, 0xBC, 0x7A, 0x81, 0xDB, 0x01, 0xD2, 0x00, 0x9D, 0xFA, 0xA2, 0x00, 0xA4, 0x5B, 0x1D, 0xE6, 0x8C, 0xE9, 0xF4, 0x8C, 0x1D, 0x0A, 0xC0, 0xFA, 0x7B, 0x4C, 0xE4, 0x4E, 0xA4, 0x54, 0x02, 0x72, 0x80, 0x65, 0x55, 0xF7, 0x2B, 0x67, 0xC5, 0xD4, 0x95, 0x64, 0xF4, 0x75, 0x81, 0x10, 0xA0, 0x74, 0x8B, 0xFD, 0x7A, 0x00, 0x75, 0x1A, 0x04, 0xA4, 0x00, 0x9E, 0x0D, 0x02, 0xAE, 0xDB, 0xB4, 0x76, 0xD0, 0xB6, 0x8C, 0xFE, 0x71, 0xEB, 0x79, 0x48, 0xB8, 0xE0, 0x31, 0xE3, 0x1D, 0x61, 0xAE, 0xDD, 0x13, 0xAE, 0x6D, 0x7C, 0xE0, 0xF3, 0xF2, 0x7C, 0xF4, 0xE1, 0xEB, 0xDE, 0x16, 0x3B, 0x5A, 0xFE, 0x1B, 0xCB, 0xAC, 0xDB, 0x7E, 0xAE, 0xD2, 0xCF, 0xD7, 0x07, 0xBF, 0xAF, 0xA8, 0x72, 0x20, 0x64, 0xD7, 0xDD, 0x38, 0xB6, 0x11, 0x7A, 0xBC, 0x46, 0xE8, 0x6B, 0x2E, 0xCA, 0xEF, 0xD3, 0x9D, 0xF6, 0xD3, 0x79, 0x97, 0x5B, 0x89, 0xB0, 0x1C, 0xA9, 0xFC, 0x96, 0xC3, 0x67, 0xC0, 0x14, 0xC8, 0x3E, 0xBD, 0x1F, 0x02, 0x48, 0x00, 0x66, 0x40, 0x08, 0x50, 0x05, 0x2C, 0x01, 0x6F, 0xDC, 0x2D, 0x4D, 0x91, 0xD2, 0x77, 0xC3, 0xDF, 0x63, 0xD9, 0x6F, 0x3B, 0xFF, 0x92, 0xF1, 0xC5, 0xD1, 0xCA, 0xEA, 0x09, 0x1C, 0xC6, 0xEE, 0x53, 0xF2, 0xB3, 0xC5, 0xCE, 0xBB, 0xA5, 0xD5, 0xAF, 0x01, 0x8C, 0xFC, 0x3A, 0x4B, 0xE7, 0x24, 0xB4, 0x1D, 0x90, 0x19, 0x7D, 0x7A, 0x3C, 0xD9, 0xE5, 0x00, 0xEA, 0xBD, 0x0B, 0x4D, 0x1D, 0xC4, 0x80, 0x13, 0xF8, 0x22, 0x4D, 0x92, 0x75, 0x9C, 0xBB, 0x66, 0xDD, 0x34, 0x74, 0x04, 0x80, 0xC7, 0xEC, 0x3A, 0xB6, 0x94, 0xBB, 0xCD, 0xE8, 0x44, 0x02, 0xD2, 0x70, 0x02, 0x4A, 0x11, 0x56, 0x49, 0xC0, 0xA5, 0x11, 0x8D, 0x03, 0x68, 0x35, 0x08, 0x30, 0xEF, 0x69, 0x87, 0xE8, 0x98, 0x19, 0x7C, 0x57, 0x4E, 0xA0, 0x2F, 0xC1, 0x0C, 0xF9, 0x65, 0x97, 0x2F, 0xD9, 0x1D, 0x82, 0xAA, 0xC1, 0x1C, 0xB9, 0xCC, 0x12, 0x8F, 0x45, 0x4F, 0xF8, 0xF0, 0xDB, 0x8F, 0x20, 0x8F, 0x66, 0x77, 0xF2, 0xAE, 0xA9, 0xA7, 0x00, 0x33, 0x39, 0x37, 0x0F, 0xAE, 0x9C, 0xC7, 0x46, 0xB9, 0x80, 0x5A, 0x8A, 0xFC, 0xB2, 0x5C, 0xE6, 0xD7, 0x98, 0xEA, 0xB4, 0xCB, 0xBA, 0x01, 0x31, 0xA3, 0x9D, 0xD1, 0xCB, 0x74, 0xA6, 0x71, 0xE6, 0x41, 0xB2, 0x7D, 0xC2, 0x70, 0x03, 0x26, 0x65, 0x2E, 0x0C, 0xC4, 0x5B, 0x7A, 0xF2, 0xC6, 0xD9, 0x2F, 0x85, 0x3C, 0x40, 0x49, 0xBF, 0x06, 0x66, 0x9D, 0x39, 0x36, 0x9D, 0x8A, 0x0F, 0x91, 0xB5, 0xC6, 0xF0, 0x2A, 0x1C, 0xE5, 0x8C, 0x60, 0xC0, 0x0D, 0x6F, 0x9D, 0xD4, 0xFB, 0x30, 0xDE, 0x5E, 0x0E, 0xBA, 0xAD, 0xC2, 0x34, 0xCB, 0xC6, 0x68, 0x06, 0x4C, 0xDA, 0x54, 0xB9, 0x00, 0x59, 0x5F, 0x8C, 0xAE, 0x91, 0xF8, 0xDF, 0x32, 0xCA, 0x79, 0x0A, 0x7B, 0xFD, 0x3B, 0x54, 0x83, 0xCF, 0x94, 0x5F, 0xF6, 0xE2, 0xD3, 0x02, 0x44, 0xF7, 0x58, 0xCC, 0x39, 0x8F, 0xCE, 0x6B, 0xAF, 0x10, 0x62, 0x40, 0x04, 0x30, 0x02, 0x22, 0x7B, 0xD9, 0x34, 0xD8, 0x1A, 0xD5, 0x88, 0x86, 0x35, 0x12, 0x50, 0x02, 0x62, 0x62, 0x16, 0x38, 0xA7, 0xAA, 0x3A, 0x7E, 0x96, 0xD9, 0xDF, 0x5A, 0x18, 0xD2, 0x4A, 0xF0, 0x17, 0x8D, 0x45, 0x7E, 0x46, 0x9F, 0x10, 0x0D, 0xB9, 0xED, 0x27, 0x68, 0x76, 0x13, 0x33, 0x13, 0xB4, 0x0E, 0x8C, 0xF6, 0x2E, 0xC0, 0xFD, 0x49, 0xEA, 0xF7, 0x53, 0xD8, 0x5F, 0x7D, 0xEC, 0x31, 0xE3, 0x9F, 0x92, 0x89, 0x03, 0xAA, 0xC0, 0x99, 0xEA, 0xFB, 0x01, 0xAC, 0xE1, 0xD4, 0xF0, 0x5D, 0x92, 0x9F, 0x88, 0x84, 0xFC, 0xCA, 0x37, 0xF5, 0x57, 0x4C, 0x9A, 0x80, 0x9A, 0x02, 0x5F, 0xC3, 0x04, 0x08, 0x7F, 0x8A, 0x78, 0x04, 0xD0, 0x01, 0xB8, 0x21, 0x01, 0xD8, 0x01, 0x26, 0xD5, 0x5D, 0xD9, 0x51, 0x9A, 0x59, 0x20, 0x42, 0x83, 0x96, 0x48, 0x3B, 0x6C, 0x2B, 0x8A, 0x8C, 0x54, 0xF8, 0x0B, 0x58, 0x51, 0xF3, 0x4D, 0x9B, 0x8C, 0x3C, 0x8A, 0xC5, 0x80, 0xC7, 0xED, 0x52, 0xEC, 0xE8, 0xF6, 0x0C, 0x18, 0x25, 0x4A, 0x95, 0x6A, 0xF8, 0x64, 0x3A, 0xE2, 0xAF, 0x3D, 0x57, 0x26, 0x2D, 0x0A, 0x1E, 0xFD, 0xEB, 0x35, 0xB4, 0x00, 0x3F, 0x80, 0xD8, 0xEC, 0xBB, 0x0D, 0x02, 0xCA, 0xB6, 0xF0, 0xB6, 0xF5, 0xEF, 0x4C, 0x84, 0xBF, 0xE8, 0x48, 0x57, 0x56, 0xBB, 0x15, 0x31, 0x1C, 0x0F, 0x4B, 0x16, 0xFE, 0xF9, 0x25, 0x80, 0x70, 0xA8, 0xDE, 0x9F, 0x02, 0x84, 0x00, 0x55, 0xC0, 0x0C, 0xF0, 0x00, 0x92, 0x71, 0x21, 0x3A, 0x07, 0x20, 0x02, 0x64, 0xF6, 0xB3, 0xEA, 0x2B, 0x04, 0xE1, 0xA7, 0x0D, 0xC3, 0x95, 0x2E, 0xF9, 0xFB, 0x51, 0x3C, 0xBD, 0xFF, 0xD5, 0xA9, 0xEF, 0x1C, 0xD2, 0xF6, 0x67, 0x89, 0x1C, 0xED, 0x2B, 0x91, 0x30, 0xD5, 0xE5, 0x39, 0x5F, 0x4E, 0xB9, 0x6E, 0x26, 0x0F, 0x49, 0xF1, 0x09, 0xB7, 0x29, 0xBF, 0x53, 0x6D, 0x99, 0x7B, 0x60, 0x8E, 0xB9, 0x77, 0x8D, 0x46, 0xAC, 0x1B, 0xCC, 0x8C, 0x23, 0x77, 0x74, 0xA9, 0xAE, 0x4F, 0x9B, 0x07, 0x60, 0x73, 0x9E, 0xED, 0xFF, 0x61, 0xB6, 0xA7, 0xEA, 0x07, 0x5D, 0xBA, 0xF6, 0x47, 0x07, 0x50, 0xDB, 0x6F, 0xD1, 0x93, 0x80, 0x16, 0x10, 0xDC, 0x10, 0xC0, 0x0B, 0xB0, 0x68, 0x38, 0xE0, 0xD1, 0xBF, 0x0A, 0x62, 0x16, 0xD3, 0x7E, 0x30, 0xD2, 0x75, 0x4C, 0xF3, 0x09, 0xF7, 0xA7, 0x16, 0xA0, 0x16, 0x6F, 0x58, 0xE1, 0x09, 0x3B, 0xFC, 0xF3, 0xED, 0x38, 0x05, 0x38, 0x3F, 0x75, 0x75, 0x14, 0xC6, 0x5B, 0xD9, 0x5F, 0x7A, 0xB2, 0x4E, 0xAC, 0xD7, 0x78, 0x9F, 0x2E, 0x45, 0xFE, 0x2E, 0xFC, 0x2E, 0x7E, 0x3B, 0x03, 0x24, 0xDB, 0x31, 0xDE, 0x14, 0x60, 0x01, 0xA8, 0x00, 0xD6, 0x86, 0x03, 0xD6, 0xFF, 0xDF, 0x3C, 0x4C, 0xC4, 0xF8, 0xA3, 0xCF, 0x01, 0x9C, 0x80, 0x72, 0xFC, 0xB5, 0xC4, 0x80, 0x1C, 0xC0, 0x1A, 0x6E, 0x40, 0x48, 0x23, 0x80, 0x54, 0xA0, 0xAC, 0x75, 0xA4, 0x13, 0x20, 0x05, 0xB8, 0x10, 0xB2, 0x71, 0x29, 0xA6, 0xBF, 0x49, 0xC7, 0x82, 0x57, 0x0F, 0xDA, 0xE0, 0x49, 0xBE, 0xD3, 0xBD, 0x94, 0xA2, 0xB1, 0x35, 0x04, 0x05, 0x3C, 0x99, 0xF4, 0xD9, 0x96, 0x99, 0xDB, 0xF2, 0x6D, 0xF8, 0x5E, 0x80, 0x12, 0x38, 0xFA, 0x8F, 0x72, 0x27, 0x07, 0x40, 0x0C, 0x70, 0xC3, 0x1C, 0x08, 0x01, 0x78, 0x4A, 0x9A, 0x04, 0xE8, 0x40, 0x1A, 0x07, 0xB0, 0xF8, 0xC9, 0xCE, 0xEA, 0xAD, 0x37, 0xA5, 0xED, 0xCC, 0x39, 0x37, 0x8C, 0x01, 0x7F, 0x7A, 0x94, 0xC5, 0x01, 0x67, 0xC0, 0xE2, 0xE9, 0xD5, 0x24, 0xE0, 0x38, 0x40, 0x09, 0xC4, 0x39, 0x1D, 0x34, 0xFE, 0x13, 0xDF, 0xC9, 0x58, 0xFE, 0x06, 0xED, 0x2B, 0x50, 0xA1, 0xB0, 0xEE, 0x1C, 0x48, 0x0F, 0x26, 0x75, 0xD2, 0xAF, 0x30, 0x5D, 0xA7, 0xB5, 0x4C, 0xFE, 0xD5, 0x9F, 0x34, 0x9A, 0x3C, 0x22, 0x33, 0x52, 0xFF, 0xB0, 0xEE, 0xF7, 0x86, 0x3A, 0xC0, 0xF3, 0x89, 0x80, 0x28, 0xA0, 0x02, 0x90, 0x29, 0x07, 0x3B, 0xA0, 0xDC, 0x20, 0x40, 0x1C, 0x50, 0x7C, 0xE7, 0x1A, 0x00, 0x5F, 0x2A, 0x97, 0x14, 0x80, 0x3E, 0x9E, 0xA1, 0xD1, 0xA8, 0xC9, 0xB1, 0x0B, 0x10, 0x0C, 0x78, 0x00, 0x9A, 0x00, 0x9F, 0x67, 0x02, 0xC1, 0x80, 0xB0, 0x09, 0x9A, 0x74, 0x7B, 0x45, 0x7C, 0x83, 0x50, 0x12, 0x68, 0x83, 0xCF, 0x38, 0xB8, 0xA7, 0x47, 0x17, 0x1D, 0x8A, 0x50, 0xC5, 0xA9, 0x42, 0x59, 0x03, 0xB3, 0x77, 0xFE, 0x2F, 0xE5, 0x4C, 0xD9, 0xEF, 0x4F, 0x24, 0xE7, 0xB7, 0xBB, 0x97, 0xEA, 0xD6, 0xB1, 0x22, 0xDF, 0x3F, 0x6F, 0xCC, 0x17, 0x05, 0xF0, 0x03, 0xC8, 0x23, 0x9D, 0x6A, 0xD2, 0xA0, 0xE7, 0xD7, 0x3D, 0x57, 0x11, 0x6C, 0xCA, 0x23, 0xE3, 0xF2, 0xB8, 0xEF, 0x95, 0x31, 0xE7, 0xC3, 0x86, 0x04, 0xE0, 0x0A, 0x94, 0x6D, 0x3D, 0x10, 0xE2, 0x86, 0x00, 0xC7, 0x37, 0xC8, 0x00, 0x95, 0x0E, 0x9A, 0x5E, 0xBF, 0xF0, 0xFA, 0xFE, 0xE5, 0xEC, 0xAB, 0x7A, 0x1E, 0x17, 0xBC, 0x4A, 0xB4, 0x47, 0x39, 0xA8, 0xD0, 0x23, 0x4E, 0xAD, 0xE4, 0x54, 0x3A, 0xC6, 0x03, 0xCF, 0xEC, 0xC0, 0x52, 0x7E, 0xC6, 0xED, 0x72, 0x17, 0xF4, 0x15, 0xD0, 0xB3, 0x87, 0x03, 0x35, 0x00, 0x92, 0x06, 0x01, 0x12, 0xFF, 0xF0, 0x13, 0x10, 0x05, 0x48, 0x1A, 0xD9, 0x88, 0xA7, 0xBC, 0xAA, 0xBF, 0xA5, 0x02, 0xFB, 0x82, 0x29, 0x18, 0x8D, 0x13, 0x04, 0xA0, 0x8F, 0x0F, 0xCF, 0x31, 0x40, 0x13, 0x88, 0x68, 0x38, 0xE0, 0xB1, 0xFF, 0x9B, 0x14, 0x60, 0x73, 0xEB, 0xA7, 0x0E, 0x9A, 0x41, 0x08, 0x9E, 0xF4, 0x1B, 0x5B, 0xAC, 0x8A, 0x79, 0x4A, 0x71, 0xE7, 0x24, 0x46, 0xDF, 0x7B, 0x3F, 0xA5, 0x49, 0x82, 0x9F, 0x1D, 0x8E, 0x9E, 0x12, 0x6F, 0x61, 0xFD, 0xE8, 0x9E, 0xD3, 0xCD, 0x04, 0xAA, 0xF6, 0x27, 0x17, 0x40, 0x0F, 0xC0, 0x02, 0x90, 0xEE, 0x5F, 0xFE, 0x24, 0xE0, 0x04, 0xC8, 0x79, 0x86, 0x43, 0x0D, 0x90, 0x06, 0x0B, 0x20, 0xAB, 0x49, 0x44, 0xAF, 0x5D, 0x48, 0xD8, 0x1E, 0x8E, 0x49, 0x7B, 0x7C, 0x77, 0x1D, 0x50, 0x02, 0x72, 0x16, 0xAA, 0x36, 0xE6, 0x8B, 0x09, 0xB8, 0x3F, 0x7B, 0xA1, 0xDE, 0xC6, 0xF3, 0x0E, 0x1A, 0x8C, 0x7B, 0x8A, 0xE3, 0x2B, 0x42, 0x45, 0xC9, 0xF7, 0x94, 0x92, 0x32, 0xDE, 0x42, 0xCE, 0x98, 0xD3, 0x21, 0xC3, 0xBF, 0xA6, 0x32, 0x12, 0xEE, 0x42, 0xAB, 0x9E, 0xA2, 0xF1, 0xEC, 0x69, 0x77, 0xE6, 0x29, 0xF7, 0x26, 0x61, 0xBA, 0xE7, 0xA1, 0x84, 0x66, 0xE3, 0x01, 0x8E, 0x3C, 0xD6, 0x76, 0x04, 0xE4, 0xD3, 0xBE, 0x20, 0x09, 0x1C, 0x6F, 0x3C, 0x46, 0xD8, 0x77, 0xFA, 0x75, 0xCA, 0x23, 0x33, 0xC2, 0x54, 0xBB, 0x8E, 0xC7, 0x06, 0x68, 0x00, 0xAE, 0x40, 0xF9, 0x74, 0xDD, 0x03, 0xD1, 0xF0, 0x02, 0x4C, 0x00, 0x76, 0xE0, 0x18, 0xC0, 0x07, 0x88, 0x9C, 0xA0, 0xC5, 0x97, 0xB0, 0x3D, 0x8E, 0x91, 0xBB, 0xA4, 0xC4, 0xA0, 0x85, 0x08, 0x0E, 0x9F, 0xCE, 0xDD, 0x42, 0x59, 0xC8, 0x8D, 0x72, 0x17, 0x3F, 0xCB, 0xF6, 0xE3, 0xA9, 0xAB, 0x85, 0x03, 0xAF, 0xF7, 0xED, 0x83, 0x1B, 0xD2, 0xB0, 0x3D, 0x02, 0xC0, 0x5B, 0x29, 0xE3, 0x68, 0x23, 0x00, 0x8F, 0xB3, 0xF4, 0x6F, 0x66, 0xA3, 0xF3, 0x00, 0xCE, 0x3C, 0x82, 0x0D, 0xAA, 0xC6, 0x7A, 0x35, 0xDE, 0xF6, 0x4E, 0xBE, 0x59, 0x52, 0xCA, 0xD1, 0xFA, 0x06, 0xC4, 0x01, 0x3F, 0x40, 0x8D, 0x57, 0xB6, 0x00, 0x69, 0x0D, 0x01, 0xDC, 0x01, 0x3D, 0x00, 0x0B, 0x20, 0x0E, 0xD4, 0x9C, 0xD2, 0x12, 0x13, 0x16, 0x59, 0x5F, 0xF5, 0x49, 0x0B, 0x3D, 0xF1, 0x32, 0x67, 0x5F, 0xEA, 0xA1, 0x2A, 0x09, 0x2C, 0x1B, 0xB2, 0x3F, 0xD8, 0xFC, 0x78, 0xB5, 0x58, 0x85, 0x3D, 0x62, 0xDD, 0xB7, 0x6A, 0x3E, 0xD5, 0x5D, 0xDB, 0x83, 0x16, 0x41, 0xC0, 0xF1, 0xED, 0x76, 0x54, 0x3C, 0xE8, 0x2F, 0x1A, 0x10, 0x0A, 0xF0, 0x33, 0xEA, 0x72, 0x62, 0x37, 0xF6, 0x58, 0xED, 0xA1, 0xD0, 0xBB, 0xB6, 0x72, 0xA5, 0x3E, 0xCF, 0x4D, 0x76, 0x0A, 0x01, 0x66, 0x40, 0xF0, 0x4E, 0x8B, 0x2A, 0x01, 0x6E, 0x0D, 0x02, 0xB4, 0x00, 0x0E, 0x80, 0x18, 0xE0, 0x46, 0xCC, 0x39, 0xAD, 0xA0, 0x28, 0xE7, 0xF6, 0xD5, 0x39, 0x4F, 0xF1, 0x67, 0x29, 0x9E, 0x11, 0x58, 0x70, 0xDE, 0xAB, 0x5D, 0xB5, 0x67, 0x62, 0x12, 0xAF, 0xF5, 0x74, 0x9C, 0xCF, 0x56, 0x69, 0x60, 0x95, 0x3B, 0x67, 0xCF, 0x9F, 0x6C, 0xC7, 0x1D, 0x72, 0x02, 0xEC, 0xF5, 0x6C, 0x33, 0x40, 0x0B, 0xF0, 0xB3, 0x67, 0x8F, 0xEC, 0x6C, 0xDF, 0x28, 0x6B, 0x88, 0x00, 0x1C, 0x8D, 0x03, 0xDC, 0xC9, 0x1E, 0x9B, 0xCA, 0xEF, 0xF5, 0x02, 0x9A, 0x56, 0x8C, 0x5D, 0x2E, 0xCF, 0xB3, 0x73, 0xC2, 0x6C, 0x80, 0x15, 0x90, 0x67, 0x23, 0x18, 0x30, 0x07, 0xB4, 0x61, 0x01, 0xCC, 0x4A, 0xA3, 0x1E, 0xBA, 0x26, 0x38, 0x7A, 0x8A, 0xC0, 0x52, 0xDC, 0xFA, 0xF1, 0xA4, 0x10, 0xBC, 0xE4, 0x1D, 0xF3, 0xB1, 0x9A, 0x8A, 0x1A, 0xA4, 0xC9, 0xB7, 0x97, 0xD5, 0x04, 0x8D, 0x9E, 0x0E, 0xAB, 0xAC, 0x3D, 0x89, 0x14, 0x0D, 0x57, 0x80, 0x6A, 0xCF, 0x2C, 0xCD, 0x2F, 0x5F, 0xB6, 0xA3, 0xE5, 0x53, 0xAC, 0xE5, 0xD9, 0xD7, 0x27, 0xA0, 0x00, 0xD3, 0x23, 0x5D, 0x10, 0x40, 0x4D, 0x25, 0x95, 0xB7, 0xD4, 0xEB, 0xD5, 0x8A, 0x3E, 0x4F, 0x53, 0x8B, 0x08, 0x60, 0x07, 0xC8, 0xC7, 0x51, 0x28, 0x08, 0x70, 0x01, 0x94, 0x01, 0x9A, 0xEF, 0x74, 0xA0, 0x7C, 0xBE, 0xA5, 0x83, 0x46, 0x7F, 0xF4, 0x20, 0xDD, 0x18, 0x5F, 0xEE, 0xC3, 0xBF, 0x25, 0x66, 0x44, 0x7D, 0xF3, 0xC8, 0xEE, 0x7F, 0xD7, 0x3E, 0x1A, 0x07, 0x5A, 0x8D, 0x8A, 0x76, 0x6D, 0x00, 0xA4, 0x7B, 0x74, 0xF0, 0x99, 0x0D, 0x7C, 0x74, 0xB4, 0x74, 0x2A, 0x94, 0x73, 0x18, 0xCF, 0x3D, 0x62, 0xAC, 0x05, 0xC8, 0xD3, 0x05, 0x93, 0xF1, 0x3C, 0x9E, 0xF6, 0xD8, 0xF0, 0xE8, 0x76, 0xF6, 0xA0, 0x79, 0x43, 0x5E, 0x2D, 0xED, 0x39, 0x25, 0x74, 0x8A, 0x57, 0xE7, 0x48, 0x26, 0xCF, 0x41, 0xCB, 0xB7, 0x94, 0xC9, 0x7B, 0x8D, 0xF5, 0x04, 0xAC, 0x21, 0x01, 0xB0, 0x01, 0x08, 0x6F, 0xDD, 0x23, 0x07, 0x71, 0x2B, 0xC3, 0xE4, 0x1F, 0xEB, 0x5A, 0x9D, 0x7C, 0xDB, 0x5D, 0x7C, 0xB5, 0x01, 0xF7, 0xB1, 0x76, 0xE6, 0x56, 0x43, 0x32, 0xBC, 0x4D, 0x04, 0xB2, 0xF0, 0xEF, 0x39, 0xED, 0x2E, 0x0E, 0xAE, 0xE5, 0x10, 0x85, 0x6B, 0x11, 0x70, 0xB6, 0x58, 0xDE, 0xB8, 0xF8, 0xD0, 0xF6, 0x53, 0x37, 0x7D, 0xEA, 0x2A, 0x4E, 0x00, 0xE7, 0xFA, 0x16, 0x66, 0x80, 0x9E, 0x92, 0x1D, 0xC7, 0x3C, 0x74, 0xF5, 0x2B, 0x07, 0x63, 0xF7, 0xEC, 0x86, 0xFD, 0x4E, 0x3F, 0xD2, 0x63, 0x09, 0x24, 0x80, 0x1D, 0xA0, 0x78, 0x97, 0x98, 0x28, 0xF7, 0xA7, 0x53, 0x0D, 0xDD, 0xFF, 0xCD, 0xB9, 0x83, 0x86, 0xAC, 0xB5, 0x13, 0xDA, 0x83, 0xD8, 0x7E, 0x1A, 0x7D, 0x0A, 0x03, 0x02, 0x24, 0xF0, 0x18, 0xA9, 0x86, 0xD0, 0xCE, 0xF7, 0x07, 0x4A, 0x75, 0xEF, 0x34, 0x94, 0x3D, 0xE9, 0xC7, 0xD3, 0xD9, 0x05, 0x57, 0x20, 0x1C, 0x29, 0x07, 0x9E, 0xF9, 0x80, 0xFA, 0x65, 0x0C, 0xCF, 0xFD, 0x07, 0x14, 0xFA, 0xFD, 0xE3, 0xC6, 0x75, 0x23, 0xC8, 0x02, 0xA6, 0xC8, 0x52, 0x39, 0x9F, 0x00, 0x76, 0x20, 0x63, 0x6C, 0xB8, 0x7E, 0x19, 0x6D, 0x9C, 0x27, 0x90, 0xFC, 0xCA, 0xDF, 0x9D, 0xDC, 0xFA, 0xF6, 0xFE, 0x35, 0x88, 0x01, 0x7E, 0x80, 0xF2, 0xD3, 0x8A, 0x54, 0x00, 0x33, 0x20, 0x06, 0x68, 0x02, 0x71, 0x80, 0x14, 0x24, 0x30, 0x4E, 0x76, 0xCC, 0x14, 0x39, 0x83, 0xA0, 0xB6, 0xB8, 0x08, 0x84, 0x53, 0x03, 0xC9, 0xA8, 0xB2, 0x16, 0x47, 0xD4, 0x35, 0xBB, 0x71, 0x2C, 0xFE, 0x31, 0xA4, 0xC2, 0x6F, 0x11, 0x4A, 0xA7, 0x19, 0x81, 0x00, 0x99, 0xD3, 0x77, 0xBF, 0x8D, 0x64, 0x76, 0x62, 0x9A, 0x9D, 0x66, 0xCD, 0x09, 0x06, 0x01, 0x6E, 0xC0, 0xE1, 0xC7, 0x55, 0xC0, 0x80, 0x20, 0xC0, 0x14, 0x88, 0xE9, 0xB7, 0xE3, 0xA5, 0x05, 0x68, 0xB7, 0xC8, 0xC2, 0xB5, 0x9F, 0xB2, 0x34, 0x84, 0x97, 0x02, 0x30, 0x02, 0x4A, 0x1E, 0xBF, 0x03, 0x06, 0xC8, 0x81, 0x63, 0xFD, 0x2D, 0x31, 0x9F, 0x00, 0x9B, 0xF7, 0xC0, 0xC8, 0x31, 0xB5, 0x2C, 0xBC, 0xC5, 0xF7, 0x63, 0x86, 0x60, 0x48, 0xD6, 0x44, 0x70, 0x5E, 0x49, 0xF9, 0xEB, 0x18, 0x8A, 0xF4, 0xD0, 0x72, 0xAB, 0x8F, 0xF3, 0x18, 0x7A, 0x32, 0xCD, 0x25, 0xA5, 0xD7, 0x81, 0x29, 0xC0, 0x4B, 0xF8, 0x13, 0x5B, 0x7F, 0x5F, 0x67, 0xFE, 0x51, 0x03, 0x35, 0x01, 0x28, 0xD7, 0xE4, 0xF6, 0xF5, 0xAA, 0xA1, 0x7D, 0xD6, 0x24, 0x07, 0xFC, 0xC3, 0xAD, 0x11, 0x58, 0xA3, 0x3A, 0x37, 0xC6, 0xBD, 0xCE, 0xB1, 0x63, 0x20, 0x87, 0xCE, 0x80, 0x3A, 0x90, 0xA7, 0x13, 0xDD, 0x0A, 0x50, 0x02, 0x72, 0x00, 0x6D, 0x58, 0x00, 0x41, 0x40, 0x0A, 0x50, 0x13, 0x34, 0x87, 0xD0, 0x89, 0x06, 0x12, 0x5F, 0xCB, 0xD9, 0xF9, 0x6F, 0xE6, 0x91, 0x54, 0x5B, 0x43, 0x2C, 0xBB, 0xAD, 0xC2, 0x91, 0x09, 0x7A, 0x0A, 0x77, 0x52, 0xBF, 0x1E, 0x45, 0x8A, 0x3B, 0xA8, 0xE3, 0x07, 0xC8, 0x4E, 0x5B, 0x8F, 0x64, 0x9A, 0xCE, 0x03, 0x4C, 0xBB, 0xD8, 0x8E, 0x4F, 0xF1, 0x77, 0x3A, 0x51, 0x00, 0x52, 0x44, 0xC2, 0x02, 0x90, 0x02, 0xD4, 0x1B, 0x05, 0x64, 0x3F, 0xCE, 0x36, 0x1A, 0x9B, 0xFD, 0xD7, 0xCE, 0x6E, 0x50, 0x9D, 0x5E, 0xA7, 0x00, 0x42, 0xBA, 0x54, 0x97, 0x80, 0x34, 0x3C, 0x80, 0x3C, 0x8D, 0x02, 0xCA, 0x3B, 0x2D, 0xAC, 0x00, 0x05, 0xC0, 0x0E, 0xD8, 0xBC, 0x3B, 0x63, 0x45, 0xA9, 0x66, 0x2E, 0x34, 0xB5, 0x85, 0xF5, 0xA9, 0x6D, 0xB3, 0x91, 0xBB, 0x75, 0xC1, 0x10, 0x1E, 0xB9, 0xA1, 0xEA, 0xF4, 0x16, 0x54, 0xFC, 0x77, 0xA4, 0x1D, 0x95, 0x2C, 0xC6, 0x7D, 0x09, 0xB0, 0xC9, 0x7E, 0xFF, 0xA6, 0x46, 0x50, 0x5B, 0x5E, 0x75, 0xB8, 0x62, 0x20, 0x0C, 0xC8, 0x03, 0xF0, 0xBC, 0xED, 0x0A, 0x90, 0xF3, 0x34, 0x21, 0xCC, 0xB7, 0xC4, 0xAF, 0x62, 0xE7, 0x57, 0x3D, 0xEC, 0xAC, 0xCD, 0x2B, 0x11, 0x72, 0x18, 0x9E, 0x20, 0xD1, 0xCD, 0x04, 0xB8, 0x01, 0xA5, 0x9D, 0xF6, 0x76, 0x80, 0x0C, 0xE0, 0x04, 0x94, 0x00, 0xAB, 0x27, 0xFB, 0x6D, 0x1D, 0xB3, 0xDC, 0x15, 0x62, 0x75, 0x34, 0xC6, 0xB6, 0x3B, 0x99, 0x1E, 0x46, 0x3A, 0xD8, 0xB2, 0x53, 0xB1, 0xDA, 0x8F, 0x3D, 0xA1, 0x8C, 0xFE, 0xC6, 0x4C, 0xFA, 0xA8, 0x3F, 0x32, 0x73, 0xD4, 0x99, 0x63, 0x3A, 0xC0, 0x54, 0x6A, 0x35, 0x10, 0x41, 0xA2, 0xDF, 0x34, 0x0D, 0xDF, 0x5E, 0x8B, 0x4A, 0x20, 0x0E, 0xE0, 0x0D, 0xF2, 0x7F, 0x0C, 0x8F, 0x38, 0x01, 0x31, 0x83, 0x8B, 0xE3, 0x06, 0x3B, 0x9E, 0xE8, 0x76, 0x05, 0xE9, 0xDA, 0x5B, 0x0D, 0xDB, 0x7F, 0x30, 0x22, 0xA8, 0x02, 0x54, 0x6F, 0xEA, 0xEC, 0x80, 0x09, 0xE0, 0x06, 0x44, 0x00, 0x75, 0x7A, 0xC3, 0x37, 0x80, 0x1D, 0x10, 0x05, 0xAC, 0x3A, 0x66, 0xD5, 0xDD, 0x14, 0x02, 0x8D, 0x97, 0xDA, 0xAA, 0x86, 0xC2, 0x88, 0xD9, 0x89, 0x4E, 0x5F, 0x93, 0xE0, 0xBD, 0xAB, 0xB1, 0xA4, 0xF9, 0x64, 0x65, 0x4F, 0x63, 0xC6, 0x4A, 0xF8, 0x0E, 0x76, 0x1D, 0x01, 0x72, 0xBC, 0x44, 0x67, 0xE9, 0x67, 0xFF, 0x7E, 0xF2, 0x9B, 0xC8, 0xD3, 0x0E, 0x96, 0xDC, 0x79, 0xD0, 0x0A, 0x80, 0xA8, 0xE3, 0xF2, 0x54, 0x94, 0x3D, 0x00, 0x6D, 0xE4, 0xF9, 0x6D, 0x5D, 0xDE, 0xA5, 0xA8, 0xBA, 0x25, 0x25, 0xD5, 0x83, 0x5F, 0xA9, 0x5F, 0xA0, 0x26, 0x40, 0x39, 0x02, 0x29, 0x05, 0x64, 0xC7, 0xF3, 0x18, 0x40, 0xD2, 0xB0, 0x46, 0x02, 0xEC, 0x80, 0x12, 0x90, 0x81, 0x98, 0x4D, 0xCF, 0x9A, 0xD8, 0x72, 0x52, 0x21, 0xF2, 0xEF, 0xEC, 0xA1, 0xDC, 0x8D, 0x7B, 0x4A, 0x50, 0x94, 0xB1, 0x84, 0xA6, 0x41, 0xF1, 0x36, 0x5D, 0xF7, 0x57, 0x8F, 0x69, 0x0E, 0xAD, 0xA3, 0x5D, 0xF1, 0xD8, 0xEA, 0x56, 0x02, 0x87, 0x76, 0x9A, 0x8D, 0x1F, 0x0D, 0x08, 0xC9, 0x6D, 0xD7, 0x27, 0xB5, 0xE5, 0xBD, 0x4C, 0x01, 0x5F, 0x4A, 0x69, 0x3C, 0x6D, 0xA0, 0x33, 0xD0, 0xD9, 0x9F, 0xAE, 0xB6, 0x2A, 0xFE, 0x5E, 0xEC, 0x9C, 0x0A, 0x94, 0xEF, 0xF2, 0xDF, 0xDD, 0x28, 0x08, 0x30, 0x06, 0x9C, 0x1A, 0xF2, 0x40, 0x9F, 0x5A, 0x72, 0x76, 0xD0, 0x08, 0xA9, 0x49, 0xC1, 0x5D, 0xDD, 0x9D, 0xBA, 0xE4, 0x56, 0xC8, 0x7A, 0xA8, 0xB4, 0xC1, 0x91, 0x62, 0xFC, 0x34, 0x12, 0x33, 0x09, 0xE6, 0x3B, 0x68, 0x93, 0x15, 0x9A, 0x5F, 0x7E, 0xD2, 0xEE, 0x7E, 0x7D, 0x13, 0x0B, 0x60, 0x5D, 0x5E, 0xCD, 0xBA, 0xF2, 0xBA, 0xA8, 0xB2, 0xAD, 0x1C, 0xAC, 0x68, 0xE3, 0x2A, 0x9F, 0x03, 0xEC, 0xC0, 0x09, 0x80, 0xB4, 0x11, 0x80, 0xF9, 0x4D, 0xEF, 0xCE, 0x35, 0x67, 0xEA, 0xFF, 0xBF, 0x74, 0x6B, 0xDE, 0xC1, 0xB2, 0x13, 0xC0, 0x7C, 0x8A, 0xE9, 0xF4, 0x23, 0x80, 0x0B, 0x90, 0xF8, 0x17, 0x0A, 0x30, 0x06, 0x92, 0x3B, 0x68, 0xDC, 0x85, 0x46, 0xF9, 0x93, 0xD6, 0x12, 0x09, 0x89, 0xA6, 0x47, 0x54, 0x6B, 0xAA, 0x53, 0x03, 0x81, 0x7C, 0x9C, 0x27, 0x7E, 0x4B, 0xE5, 0x09, 0xD6, 0x23, 0x2D, 0xB4, 0x32, 0xB2, 0xF9, 0xB7, 0x67, 0x2A, 0x1C, 0x10, 0x5F, 0x41, 0x63, 0xDD, 0x79, 0x0E, 0x8A, 0x9D, 0xB5, 0xD7, 0x00, 0x64, 0xAE, 0x9D, 0xB9, 0xD5, 0xDF, 0x4D, 0x01, 0xA7, 0x46, 0x7F, 0xCB, 0x24, 0xEF, 0x6F, 0xA6, 0x5B, 0x27, 0xC5, 0x3D, 0x6D, 0x95, 0x13, 0x9F, 0xDB, 0x21, 0x02, 0x54, 0xAF, 0x34, 0xE1, 0xA7, 0x5D, 0x2D, 0x00, 0x62, 0xE0, 0x78, 0x2F, 0x46, 0x06, 0xD2, 0x80, 0xD9, 0x31, 0x26, 0xD3, 0xCD, 0xF2, 0xF5, 0xA2, 0x85, 0xC6, 0xB2, 0x3D, 0xE2, 0x0A, 0x9C, 0xA3, 0x49, 0x20, 0xD8, 0x43, 0x2D, 0x00, 0xE6, 0x86, 0x11, 0x1C, 0xB2, 0x6D, 0x4B, 0x49, 0x4F, 0x13, 0x7C, 0xF2, 0xF8, 0x7A, 0x3D, 0x22, 0x20, 0xFC, 0x74, 0x69, 0xD3, 0x1E, 0xF0, 0x92, 0x03, 0x90, 0x36, 0x02, 0x38, 0xB5, 0x1F, 0x4F, 0x77, 0x40, 0xA5, 0x91, 0x8D, 0x00, 0x62, 0xC4, 0xFB, 0x9E, 0x75, 0x57, 0x2B, 0x8F, 0xB8, 0x26, 0x2B, 0x0E, 0x30, 0xDD, 0x6E, 0x1C, 0x5B, 0x12, 0xF8, 0x0C, 0x66, 0xCC, 0xBB, 0x00, 0x27, 0x40, 0x15, 0xB0, 0x1A, 0xB5, 0xE1, 0x0E, 0x9A, 0xFE, 0x61, 0x0C, 0x5A, 0x4F, 0xD0, 0x50, 0x72, 0x27, 0x85, 0x60, 0xB7, 0xF8, 0x77, 0x86, 0x0C, 0xE8, 0xBD, 0x48, 0xAA, 0x60, 0x4D, 0xBC, 0xD5, 0xBB, 0x78, 0xEE, 0xEA, 0x71, 0x9E, 0x1F, 0xBB, 0x71, 0x26, 0xD5, 0x68, 0x23, 0x93, 0xD4, 0x01, 0xA5, 0x9D, 0xEE, 0xA0, 0xB3, 0x13, 0x40, 0x74, 0x8D, 0x99, 0x9E, 0xA0, 0x05, 0x60, 0x0D, 0xE7, 0x9D, 0xB4, 0x2D, 0xFA, 0xD5, 0xE4, 0xAE, 0xE7, 0xB1, 0xDE, 0x06, 0x2C, 0x1D, 0x27, 0xAF, 0xDA, 0x07, 0x95, 0xD3, 0x50, 0x01, 0xBC, 0x80, 0x90, 0xE7, 0xCA, 0x5E, 0x0D, 0x03, 0x7C, 0x2E, 0x13, 0xDA, 0x41, 0xB3, 0xFB, 0x72, 0x48, 0x45, 0xD9, 0x0E, 0x07, 0x3E, 0xC7, 0x01, 0x85, 0x15, 0xFF, 0x62, 0x82, 0xE4, 0x50, 0x39, 0x7D, 0x8F, 0x95, 0xF1, 0x63, 0xBA, 0x0E, 0xD2, 0x5D, 0x23, 0x95, 0xBF, 0xCB, 0x0F, 0xE1, 0x06, 0x3F, 0xB9, 0x5B, 0xF4, 0xE7, 0xFE, 0x26, 0x48, 0xE2, 0xEF, 0x90, 0xBB, 0xEE, 0xED, 0x4B, 0x1B, 0x64, 0x8F, 0x96, 0x10, 0x03, 0x1A, 0x8D, 0xDA, 0x9F, 0x62, 0x9E, 0xE7, 0xF9, 0xA3, 0x6D, 0xC9, 0x59, 0x74, 0x27, 0x2D, 0xA4, 0xAF, 0x81, 0xEB, 0xAC, 0x77, 0x00, 0x71, 0x20, 0x3A, 0x92, 0x87, 0x1B, 0x32, 0x89, 0x59, 0x20, 0x15, 0x08, 0x07, 0xC6, 0x83, 0x4F, 0x26, 0x68, 0x8E, 0xC3, 0x64, 0x24, 0x06, 0xEE, 0x32, 0x90, 0x48, 0x39, 0x86, 0x03, 0xF1, 0xC1, 0x27, 0xC9, 0x4E, 0x0E, 0xB1, 0x7F, 0x08, 0x9D, 0x5E, 0xB4, 0x57, 0x13, 0x3E, 0x7F, 0xEA, 0x41, 0x24, 0xF7, 0xAF, 0xD0, 0xD8, 0xA6, 0xEB, 0x65, 0xBF, 0xEB, 0x15, 0x4A, 0x57, 0x57, 0x83, 0x26, 0xEF, 0x5B, 0xD7, 0x0D, 0x38, 0xB4, 0xEB, 0x09, 0xE7, 0x6C, 0xE3, 0xD4, 0x7C, 0xB2, 0x42, 0xB7, 0xA6, 0x3B, 0x5E, 0xEF, 0x73, 0xD0, 0xB5, 0x49, 0x0E, 0x4C, 0x13, 0x0C, 0xF5, 0xE9, 0x3E, 0x80, 0xA0, 0x5D, 0x9B, 0x8F, 0xD1, 0x29, 0x76, 0x80, 0x08, 0x38, 0x71, 0x66, 0x54, 0x1F, 0x88, 0xFE, 0xA2, 0x01, 0x36, 0x7B, 0xDA, 0xBD, 0x0E, 0xB4, 0xFD, 0x9D, 0xE1, 0x97, 0x55, 0xC7, 0x1F, 0xC9, 0x86, 0x8D, 0xD1, 0xA4, 0x3B, 0x22, 0x19, 0x77, 0x6D, 0x1A, 0xCF, 0xB6, 0x9D, 0xE0, 0x90, 0x29, 0x6B, 0x4F, 0x0F, 0xFC, 0x2C, 0xFE, 0x2A, 0x40, 0x26, 0xEB, 0x9E, 0xBF, 0xAE, 0x4E, 0xB9, 0xAD, 0xB7, 0xE9, 0xC0, 0xF8, 0x8C, 0xEB, 0x96, 0x12, 0x92, 0xEB, 0xCF, 0x07, 0xF0, 0xF3, 0x69, 0xF2, 0xB2, 0x62, 0xE7, 0xE7, 0x82, 0x57, 0x00, 0x4F, 0x86, 0x62, 0xE4, 0x98, 0xBB, 0x5D, 0x43, 0xBA, 0xF1, 0x4F, 0xF0, 0x2D, 0xB8, 0x15, 0x34, 0xBC, 0x91, 0xD3, 0x0C, 0x43, 0x00, 0x39, 0x20, 0x06, 0x98, 0x03, 0x9E, 0x40, 0x9D, 0x8E, 0x59, 0x22, 0x8F, 0x9F, 0xD0, 0x96, 0x53, 0xCD, 0x95, 0x14, 0x12, 0xB6, 0x16, 0x04, 0x21, 0x24, 0xF5, 0x28, 0x3E, 0x24, 0xC9, 0x96, 0x7B, 0xA9, 0xD5, 0xCF, 0x3D, 0x05, 0x69, 0x4C, 0xBD, 0xFF, 0x74, 0x49, 0xCE, 0xED, 0x6C, 0x3D, 0x4B, 0x0C, 0x5E, 0x6F, 0x95, 0xF1, 0xE4, 0x6F, 0x43, 0xEE, 0xC3, 0x7E, 0x5D, 0xB3, 0xD9, 0x90, 0x9D, 0xD9, 0xB0, 0x04, 0x82, 0x1A, 0x35, 0x07, 0xC1, 0xD9, 0x06, 0xE6, 0xAF, 0x9D, 0xF6, 0x6C, 0xFF, 0xB5, 0x88, 0x56, 0x9F, 0xB3, 0x67, 0xDD, 0xE0, 0x47, 0x42, 0xBF, 0x47, 0xC3, 0x1C, 0x88, 0x04, 0xD2, 0x81, 0xD2, 0x46, 0x20, 0xF4, 0xC7, 0x00, 0x52, 0xC0, 0xE6, 0xC4, 0x01, 0xB9, 0x20, 0xEC, 0xF5, 0xD5, 0x13, 0x64, 0x90, 0x46, 0x85, 0x37, 0x88, 0x20, 0x68, 0xAA, 0x86, 0xDC, 0x8E, 0x64, 0xDB, 0x45, 0xF0, 0x5C, 0x04, 0x9E, 0xA0, 0xCD, 0xC9, 0x0A, 0x9F, 0xF4, 0x6A, 0xAC, 0x44, 0x01, 0x36, 0x37, 0xF1, 0xD1, 0x66, 0xA2, 0xE9, 0xAF, 0xDE, 0xFE, 0x0D, 0xF2, 0x34, 0x72, 0xCF, 0x98, 0x60, 0x16, 0x70, 0x62, 0xB4, 0x47, 0x00, 0x6F, 0xCC, 0xBB, 0x70, 0xB4, 0xEF, 0x63, 0x76, 0x83, 0x3E, 0x40, 0xD0, 0xB4, 0x7C, 0x4E, 0x47, 0x50, 0x77, 0x66, 0x71, 0x02, 0x31, 0x77, 0x6F, 0x05, 0xDC, 0x81, 0x3A, 0xC0, 0x3C, 0x8F, 0x87, 0xFA, 0x53, 0xF5, 0x27, 0x07, 0x28, 0x01, 0xEF, 0x95, 0x26, 0xED, 0x80, 0xA2, 0x08, 0x1A, 0x51, 0x20, 0x09, 0x11, 0xDE, 0xBB, 0x40, 0xF4, 0x3F, 0x1C, 0x77, 0xCB, 0xBE, 0x22, 0xA0, 0xC4, 0xA8, 0xA5, 0x3F, 0xED, 0xDC, 0xBA, 0x0C, 0x5A, 0xBB, 0xEA, 0x8F, 0xEB, 0x0F, 0x6F, 0x29, 0x03, 0xED, 0xD0, 0xCD, 0xBE, 0x7A, 0x6C, 0xA2, 0xBB, 0x47, 0x7E, 0x4A, 0x36, 0x28, 0xB6, 0xA5, 0x40, 0x06, 0x50, 0xDE, 0xE8, 0xFF, 0x66, 0x39, 0x6D, 0xEB, 0xBF, 0xB9, 0x13, 0x94, 0x74, 0xB1, 0x98, 0x74, 0xA7, 0x1F, 0x47, 0x0B, 0x44, 0x02, 0x48, 0xEB, 0xFB, 0x67, 0x02, 0xDA, 0x30, 0x7D, 0x40, 0xCF, 0xA7, 0x00, 0x4A, 0x3A, 0x66, 0xD4, 0x6E, 0x35, 0x84, 0xE3, 0x59, 0xC0, 0x7D, 0xC6, 0x52, 0xF1, 0x47, 0x8E, 0xA1, 0x4D, 0x7A, 0xF7, 0xB7, 0xE6, 0x77, 0x51, 0x29, 0x85, 0xDC, 0xCB, 0x3C, 0x9D, 0xC5, 0x6B, 0x4B, 0xC3, 0x5E, 0x3D, 0xB9, 0xEC, 0x4E, 0x94, 0x10, 0x20, 0x39, 0xFD, 0xFC, 0xD3, 0x1F, 0xBF, 0x7C, 0x33, 0xB9, 0x76, 0xD5, 0x96, 0x0E, 0x30, 0xC3, 0xB4, 0xC1, 0xCF, 0x8C, 0x80, 0x02, 0x71, 0x9E, 0x12, 0xF0, 0x94, 0x3D, 0x6E, 0xE2, 0xC8, 0x7F, 0xAA, 0x1C, 0x72, 0xB3, 0x03, 0x22, 0x9D, 0x2D, 0x6B, 0x58, 0x02, 0x35, 0x9B, 0x9F, 0x02, 0xE6, 0x8D, 0x68, 0x58, 0x83, 0x00, 0xF5, 0xFD, 0xC5, 0x9A, 0x85, 0xF6, 0x37, 0xB3, 0x1D, 0x04, 0x59, 0x04, 0xF4, 0x51, 0x45, 0xF7, 0xC0, 0x77, 0xFA, 0x51, 0x1C, 0x87, 0x3B, 0xCA, 0x0F, 0x7A, 0x70, 0x1F, 0xF8, 0x97, 0xCD, 0x05, 0xA6, 0x17, 0x7A, 0xE1, 0xCC, 0x89, 0x5C, 0x00, 0x9E, 0x02, 0x6D, 0x87, 0xB0, 0x68, 0x3B, 0x2F, 0x44, 0xCD, 0x74, 0x18, 0xEE, 0x11, 0x02, 0x90, 0x6D, 0xAD, 0x47, 0x0B, 0x40, 0x1C, 0x30, 0x01, 0x26, 0x84, 0xB7, 0xE2, 0xCD, 0x33, 0xA1, 0x30, 0x41, 0xF3, 0x4E, 0x7B, 0xAF, 0x16, 0xD5, 0xEF, 0x87, 0x00, 0xA2, 0x1F, 0x52, 0x32, 0x40, 0x09, 0x30, 0x06, 0xBC, 0x11, 0x02, 0xA4, 0xFE, 0x2B, 0xB1, 0x56, 0x1D, 0x34, 0xF9, 0x1B, 0x34, 0x47, 0x5B, 0x37, 0x9A, 0x9F, 0x13, 0x49, 0xA5, 0xEE, 0xE7, 0x0E, 0x12, 0xEC, 0xB5, 0xD9, 0xEE, 0x77, 0xA6, 0x7B, 0x16, 0xEA, 0x4D, 0x74, 0xE7, 0x9C, 0x93, 0xE6, 0x00, 0xE0, 0xEB, 0xA1, 0xE3, 0xA9, 0x2E, 0x4E, 0x29, 0x65, 0x1A, 0x7D, 0xAC, 0x76, 0xE3, 0x84, 0x1E, 0xE0, 0x4C, 0x98, 0xA6, 0x04, 0x4C, 0x80, 0x0A, 0x60, 0xB5, 0x55, 0x69, 0x45, 0x7E, 0x87, 0x67, 0xC2, 0x31, 0xA4, 0xF3, 0xA5, 0x9D, 0x7F, 0x3C, 0x1D, 0x8A, 0xD9, 0xB6, 0xFA, 0x75, 0x60, 0x73, 0xC4, 0x20, 0x40, 0x18, 0xD0, 0x04, 0xFC, 0x00, 0xD1, 0x48, 0xFB, 0x57, 0xF3, 0x6D, 0x74, 0xD0, 0xB4, 0xBB, 0x82, 0xA7, 0x31, 0x6D, 0x4A, 0x21, 0x8C, 0x6C, 0x54, 0x67, 0xB8, 0x39, 0x71, 0xA6, 0x3D, 0xEA, 0x10, 0x89, 0x0E, 0xDA, 0x47, 0xDB, 0x5C, 0x55, 0x62, 0xFD, 0x7B, 0x6F, 0xE6, 0xD8, 0xF5, 0xA7, 0xB0, 0x99, 0xCF, 0x59, 0x25, 0x3C, 0x9A, 0x17, 0x47, 0xEC, 0x0B, 0x16, 0x2F, 0x1B, 0xB1, 0x69, 0xEA, 0xC3, 0x9D, 0x66, 0x27, 0x37, 0x0A, 0xC8, 0x35, 0xE6, 0xA9, 0xBF, 0xB7, 0xC2, 0x58, 0xFD, 0x8C, 0x66, 0x4B, 0xF7, 0x2F, 0xDF, 0x4C, 0x6E, 0x67, 0xA0, 0x38, 0x81, 0xEC, 0x57, 0x05, 0x17, 0x60, 0x01, 0x38, 0x01, 0x56, 0x80, 0x66, 0x43, 0x9F, 0xC9, 0x01, 0xEE, 0xA0, 0xDD, 0xEA, 0xC0, 0x04, 0x0D, 0xA3, 0xD1, 0x69, 0xBD, 0x4D, 0x46, 0xEF, 0xEA, 0x02, 0x4D, 0xE3, 0xA8, 0x6E, 0xB0, 0xA8, 0xEF, 0x05, 0x50, 0xAF, 0x78, 0x09, 0x7F, 0xB0, 0x09, 0xDA, 0x78, 0x36, 0x8D, 0xB6, 0x9B, 0x6D, 0xD7, 0xA3, 0x39, 0xD3, 0xCE, 0x8D, 0x3E, 0x46, 0xCB, 0xF2, 0x0E, 0xFF, 0xFA, 0xDC, 0x00, 0x26, 0x68, 0xD7, 0x11, 0x16, 0x88, 0xB3, 0xA3, 0xB5, 0x95, 0x46, 0x6D, 0x8C, 0x61, 0x79, 0xCA, 0x1F, 0x37, 0xC5, 0x2D, 0x7D, 0x60, 0x65, 0xE9, 0x93, 0x83, 0xEC, 0x2E, 0x52, 0x6B, 0x94, 0xEE, 0xA6, 0x50, 0x21, 0x40, 0x1D, 0x70, 0x02, 0xA2, 0x80, 0xA2, 0xCE, 0xBB, 0xCD, 0x4A, 0xF3, 0xFF, 0x0D, 0x5A, 0x5E, 0x8F, 0xA8, 0x73, 0xB4, 0x3D, 0xAC, 0x18, 0x02, 0xB0, 0x9C, 0xB8, 0x38, 0xD2, 0x08, 0x31, 0x3D, 0x89, 0x21, 0x9A, 0x11, 0xEB, 0x5B, 0xCE, 0x9E, 0x56, 0x09, 0xED, 0x07, 0x52, 0xD7, 0x03, 0xC9, 0xB7, 0x51, 0x63, 0x7B, 0xF4, 0xC7, 0x33, 0x6C, 0xEC, 0xD2, 0x41, 0xCB, 0xC7, 0x69, 0x60, 0x3E, 0x3D, 0x73, 0xD7, 0x57, 0x7E, 0xD4, 0x7E, 0xA3, 0x91, 0x37, 0xDD, 0xE3, 0x8D, 0xB9, 0x01, 0x60, 0xCA, 0x60, 0x35, 0xB7, 0x87, 0x75, 0x24, 0x13, 0xE0, 0x86, 0x12, 0x60, 0x06, 0x78, 0x01, 0x19, 0x40, 0x09, 0xA2, 0x4C, 0xD4, 0x41, 0x8B, 0x1D, 0xB4, 0x0F, 0x8E, 0x37, 0x80, 0xFA, 0x2D, 0xF2, 0x26, 0x94, 0x25, 0xD8, 0x85, 0x60, 0xFC, 0x97, 0xB9, 0x2E, 0x51, 0xA1, 0xCB, 0x2B, 0x50, 0xFF, 0x4A, 0xF9, 0xDE, 0xA4, 0xC1, 0x0C, 0x6F, 0x9E, 0xB5, 0xD9, 0xB3, 0x77, 0xD0, 0xE4, 0xD1, 0xDA, 0xA8, 0x49, 0xC6, 0x01, 0x32, 0xAD, 0x81, 0xB1, 0xFD, 0x85, 0x3D, 0x81, 0x94, 0x1D, 0x3B, 0xAD, 0x35, 0x1B, 0xD3, 0x17, 0x3C, 0xF2, 0x6B, 0x3C, 0xA5, 0xD7, 0x55, 0x7B, 0x3F, 0x89, 0xC5, 0x93, 0xE1, 0x05, 0x9C, 0x80, 0x70, 0x20, 0x03, 0xA8, 0x9C, 0x8E, 0x74, 0x80, 0x05, 0x10, 0x02, 0x6C, 0xDE, 0x9E, 0x79, 0x83, 0x96, 0xD2, 0x56, 0x5A, 0x9F, 0xF9, 0x91, 0xE2, 0x72, 0x41, 0x85, 0x7A, 0xD0, 0xA9, 0x0E, 0x84, 0x7C, 0x20, 0x24, 0x86, 0xC2, 0xDE, 0x7E, 0x04, 0xB6, 0x7F, 0x3D, 0x9E, 0x35, 0x05, 0xDE, 0x18, 0x95, 0x4E, 0x44, 0x72, 0x74, 0xEE, 0xB8, 0xB0, 0xC3, 0xCD, 0x95, 0x73, 0xDE, 0x89, 0xF3, 0xB0, 0x76, 0x24, 0xAB, 0xC1, 0x07, 0x38, 0x04, 0x50, 0x02, 0x42, 0x40, 0xDD, 0x36, 0xAC, 0xF9, 0x6B, 0xE7, 0xED, 0xB9, 0x6E, 0x9E, 0x38, 0x96, 0xAC, 0xF1, 0x0B, 0x21, 0x60, 0xB2, 0xF1, 0xA4, 0x80, 0xD8, 0xF3, 0x3E, 0x20, 0x20, 0x02, 0x28, 0x7D, 0x5E, 0x04, 0xD6, 0x41, 0xAB, 0x15, 0xB4, 0x92, 0xEA, 0x52, 0x75, 0xE0, 0x6D, 0xDB, 0x47, 0xD4, 0x13, 0x8E, 0x0D, 0xA3, 0x02, 0xA7, 0x74, 0xB5, 0x25, 0xCF, 0xFA, 0xF8, 0xDE, 0x61, 0x1F, 0xD8, 0x8D, 0x01, 0x55, 0x3F, 0xBD, 0x4A, 0xBB, 0x87, 0xB7, 0x33, 0x5A, 0x86, 0x3E, 0x29, 0xAF, 0x7D, 0x5D, 0x6F, 0xD0, 0x9C, 0x94, 0x63, 0xF7, 0xC1, 0xE4, 0x7C, 0x3A, 0x00, 0xDB, 0x2F, 0x73, 0x5E, 0x1D, 0xF3, 0x19, 0xE2, 0x9E, 0x92, 0xBE, 0x20, 0xCC, 0x28, 0x84, 0x68, 0xDF, 0x32, 0x19, 0x77, 0xC7, 0x98, 0xF6, 0xB1, 0x02, 0xF2, 0xFB, 0xF4, 0xF5, 0x1C, 0x00, 0x4C, 0x80, 0x04, 0x60, 0x06, 0x44, 0x02, 0xF9, 0x7D, 0xF1, 0xEA, 0xA5, 0x85, 0x9E, 0x75, 0xE4, 0x60, 0xA7, 0xFB, 0x89, 0x0B, 0x9F, 0x98, 0xDA, 0xBB, 0x4D, 0xFF, 0x1E, 0x58, 0x8F, 0xAF, 0xEB, 0x3A, 0x3F, 0x15, 0x4F, 0x9B, 0x8A, 0xA7, 0xF7, 0xA0, 0xCE, 0x35, 0x9F, 0xF7, 0x31, 0x58, 0xFA, 0x35, 0xA2, 0xE8, 0x3D, 0xED, 0x4F, 0x9A, 0x30, 0x15, 0x11, 0x9C, 0xFC, 0x8E, 0x4E, 0xF9, 0x7C, 0x56, 0xDF, 0x73, 0x4C, 0x0B, 0x60, 0xCE, 0xBD, 0x3A, 0xBB, 0xC1, 0x8C, 0x72, 0xCE, 0x04, 0xD3, 0x0C, 0x0E, 0xC8, 0x1C, 0xF3, 0xC7, 0x61, 0x8D, 0x10, 0x3A, 0x95, 0x3D, 0xA6, 0xA2, 0x8D, 0x30, 0xA0, 0xBA, 0x82, 0x79, 0x02, 0x60, 0x03, 0xD4, 0x01, 0x4B, 0x60, 0x72, 0xDD, 0xDA, 0x22, 0xBF, 0x25, 0x5F, 0x8B, 0x95, 0x73, 0x5F, 0xB3, 0xAC, 0x75, 0xF9, 0x64, 0xDE, 0x7D, 0x01, 0xF9, 0x60, 0x49, 0xE4, 0x11, 0x73, 0x27, 0xD3, 0xDC, 0x9E, 0x63, 0x9A, 0xF9, 0x6A, 0x7D, 0x94, 0xBF, 0x0E, 0x69, 0x73, 0x3E, 0xEB, 0x9C, 0xDA, 0x52, 0x35, 0x8F, 0xBF, 0xCD, 0x51, 0xF2, 0x28, 0xED, 0x8F, 0x7A, 0xB6, 0x6C, 0x61, 0x89, 0xF0, 0x2D, 0x3A, 0x71, 0x1A, 0x73, 0xCA, 0x93, 0x79, 0x3A, 0x95, 0x7B, 0x4A, 0x66, 0xDC, 0xF3, 0x66, 0xFA, 0xE4, 0xFC, 0x2A, 0x60, 0x78, 0x1B, 0x21, 0x2F, 0x64, 0x40, 0xC8, 0x3E, 0xB4, 0x9D, 0x00, 0xE8, 0x34, 0xB8, 0x61, 0x00, 0x07, 0xE0, 0xD5, 0x41, 0x1B, 0x39, 0xF3, 0xEE, 0x89, 0x39, 0x0E, 0xED, 0x92, 0x93, 0x78, 0xE7, 0x1E, 0x81, 0xAA, 0xB9, 0x0A, 0xA4, 0xE0, 0x8F, 0x41, 0x21, 0xAA, 0x6A, 0x5F, 0x08, 0xE8, 0x91, 0xD1, 0x4F, 0x19, 0xE1, 0xB1, 0xFE, 0xE5, 0xDF, 0x2E, 0x47, 0x6F, 0xE4, 0x3C, 0x7A, 0x80, 0x56, 0x87, 0xF0, 0xCC, 0x99, 0x78, 0xAE, 0x0E, 0x73, 0x7D, 0xAB, 0x9F, 0x90, 0x2F, 0xCD, 0x1E, 0x78, 0xA7, 0x6F, 0xB3, 0x43, 0x28, 0x00, 0x4F, 0xCA, 0xBB, 0xE1, 0xFC, 0x2A, 0x75, 0x34, 0xA2, 0x91, 0x80, 0x06, 0x90, 0xF6, 0x68, 0xE1, 0x5D, 0x2F, 0x5E, 0xC0, 0x0F, 0xA0, 0x0C, 0x58, 0xDC, 0x0E, 0xEA, 0x0E, 0x9A, 0xDC, 0xA0, 0xBD, 0xEF, 0x50, 0xFD, 0x2E, 0x35, 0x81, 0xD6, 0xC3, 0xEE, 0x88, 0xFF, 0x1A, 0x11, 0xE4, 0xAE, 0x34, 0xF3, 0xAD, 0xFC, 0x85, 0x93, 0xD1, 0x3E, 0x3E, 0x85, 0x01, 0xE5, 0x0D, 0x05, 0x72, 0x3E, 0x3D, 0xAA, 0x7D, 0x3E, 0x27, 0x8F, 0xD5, 0x2A, 0x4C, 0x3D, 0x77, 0x36, 0x86, 0xAD, 0xF7, 0x4E, 0x46, 0xF8, 0x62, 0xDE, 0x6B, 0xC2, 0xFC, 0x16, 0x39, 0x7F, 0x51, 0x02, 0xC6, 0x00, 0x3D, 0xE7, 0xBB, 0xD4, 0x06, 0x35, 0x04, 0xA8, 0x7C, 0x62, 0x58, 0x0D, 0xDE, 0x61, 0x3E, 0xF1, 0x98, 0xFB, 0x1F, 0xC0, 0x68, 0xA2, 0xA6, 0xFF, 0x13, 0xB5, 0xFC, 0x0A, 0xB0, 0x81, 0xB7, 0x67, 0x04, 0xE4, 0xCE, 0x82, 0xD0, 0x17, 0x2D, 0x0E, 0xCD, 0x13, 0x45, 0x0B, 0xE4, 0xF2, 0xF2, 0x5C, 0x6D, 0xDD, 0xA3, 0x7B, 0x66, 0xCF, 0x94, 0x48, 0x04, 0x90, 0xB5, 0x85, 0xCB, 0xD8, 0x81, 0xCC, 0xBE, 0xB0, 0xDB, 0x3C, 0x60, 0xFA, 0x73, 0x01, 0xAB, 0xDB, 0x72, 0x45, 0xFC, 0xF7, 0xF6, 0x5F, 0xF7, 0x4F, 0xB1, 0xC9, 0x87, 0x5F, 0xCF, 0x83, 0x2D, 0xD4, 0xAF, 0x06, 0x50, 0x00, 0xC7, 0x1B, 0xBA, 0x3F, 0xB1, 0x02, 0x56, 0x40, 0x0A, 0x10, 0xBE, 0xBF, 0x28, 0x0E, 0xF0, 0xD9, 0x9F, 0x52, 0x27, 0x68, 0xF6, 0xA7, 0x12, 0xFD, 0xDC, 0xEF, 0x52, 0x43, 0x01, 0xDE, 0x20, 0x0E, 0x97, 0xD2, 0x55, 0x4F, 0xC1, 0x44, 0x44, 0xC4, 0xB2, 0x87, 0x52, 0x7B, 0x97, 0x1A, 0x35, 0xCA, 0x1E, 0x93, 0x21, 0x01, 0x28, 0x00, 0x21, 0x60, 0x9A, 0xE1, 0x27, 0x79, 0x19, 0x57, 0x50, 0xA1, 0x7A, 0x4B, 0x57, 0x44, 0x6D, 0x26, 0x49, 0x82, 0x7F, 0x2B, 0xEE, 0xDC, 0x16, 0xE0, 0x11, 0xC1, 0xD1, 0xC7, 0x9B, 0x86, 0x80, 0xF9, 0x44, 0x8D, 0x33, 0xB0, 0xFD, 0x89, 0x6D, 0x3F, 0x84, 0xA9, 0x8D, 0x03, 0x38, 0x01, 0x12, 0x00, 0xF3, 0x13, 0x35, 0x9E, 0xA8, 0x39, 0x9C, 0xB0, 0xB5, 0x26, 0x6A, 0xDF, 0x8C, 0x14, 0x8D, 0x03, 0xAA, 0xC5, 0xF7, 0x64, 0x2A, 0x17, 0x76, 0x1C, 0x08, 0xA6, 0x29, 0x89, 0xCF, 0x03, 0xFA, 0xD8, 0xD0, 0xC4, 0xE3, 0xA8, 0x72, 0xEF, 0xD3, 0x80, 0x07, 0x90, 0x32, 0xF9, 0x7F, 0x80, 0xA7, 0x42, 0x75, 0x56, 0xC1, 0xD2, 0x6E, 0x6F, 0xD1, 0xC9, 0x9F, 0xAB, 0xDF, 0xD4, 0xD0, 0xE2, 0xBE, 0x5E, 0x0C, 0x79, 0x91, 0x5A, 0x99, 0x22, 0xBF, 0x9A, 0x7C, 0xF5, 0xF8, 0xF9, 0x13, 0xEF, 0x4A, 0x7E, 0x45, 0x23, 0xE7, 0x07, 0x04, 0xDC, 0x80, 0x62, 0x20, 0x0D, 0x70, 0x07, 0x24, 0x00, 0x2A, 0x40, 0x08, 0x48, 0x9F, 0xA0, 0xC5, 0xFB, 0x7C, 0x42, 0x7D, 0x34, 0xBB, 0xC9, 0x4F, 0x09, 0x25, 0x6D, 0xD5, 0x76, 0x04, 0x70, 0xB8, 0x72, 0x10, 0x4F, 0xD0, 0x9E, 0xA9, 0x28, 0xDF, 0x41, 0xBB, 0x85, 0xE0, 0x86, 0x29, 0x10, 0x0C, 0x54, 0x74, 0xD0, 0x66, 0x98, 0x56, 0xA6, 0x1A, 0x79, 0x5D, 0x8B, 0x11, 0xAD, 0xAC, 0xDF, 0x24, 0xFE, 0x58, 0x92, 0xC6, 0xD5, 0x8F, 0xB1, 0x71, 0x3F, 0xD9, 0x15, 0x55, 0xA6, 0xAD, 0x89, 0x75, 0xCE, 0x33, 0x1B, 0x53, 0x0D, 0xDF, 0xF0, 0x7A, 0xE7, 0x8A, 0x1A, 0x8F, 0x9D, 0x7B, 0x34, 0x9C, 0x80, 0x98, 0x25, 0x3D, 0xF3, 0x77, 0x4B, 0x2B, 0xB3, 0x0F, 0x29, 0x25, 0x10, 0x79, 0xD1, 0x4F, 0x7D, 0x80, 0x30, 0xA6, 0x23, 0x0A, 0xDB, 0x07, 0x33, 0x8C, 0x31, 0xA1, 0xC0, 0xCE, 0xFC, 0x1A, 0x92, 0x95, 0xCE, 0xF3, 0x49, 0x7B, 0x9F, 0x97, 0x7F, 0xB9, 0xE7, 0xB3, 0xEE, 0xC7, 0x74, 0xFE, 0xB1, 0xEF, 0xF8, 0xC5, 0xF4, 0xE7, 0x49, 0xA3, 0xFA, 0x89, 0x9C, 0xF3, 0xDB, 0x35, 0xB5, 0xD9, 0xC6, 0x78, 0x94, 0xFF, 0x78, 0x65, 0xD2, 0x38, 0xE2, 0x35, 0x32, 0x1B, 0xFE, 0xDC, 0xF8, 0x19, 0x90, 0x86, 0xD1, 0x8E, 0xA8, 0x10, 0x40, 0x02, 0x9C, 0xD3, 0x28, 0xC0, 0x6E, 0xD4, 0xEA, 0x4F, 0x7D, 0x79, 0xA0, 0x42, 0xF1, 0x4B, 0xB7, 0xA5, 0x8A, 0x28, 0x63, 0x57, 0x73, 0x1C, 0xAA, 0x4C, 0xDB, 0x06, 0xCD, 0x67, 0x2C, 0xEA, 0x4D, 0x0E, 0xE9, 0x4C, 0x2B, 0xED, 0xA0, 0x71, 0x35, 0x12, 0xA0, 0x41, 0x01, 0xC2, 0x40, 0xCA, 0xEF, 0x70, 0x36, 0xB7, 0x7A, 0x18, 0x1D, 0xFC, 0x2C, 0x1B, 0x7A, 0x8C, 0x6B, 0x46, 0xC3, 0x46, 0xA9, 0xCF, 0x6E, 0x29, 0x7F, 0x56, 0x87, 0x33, 0x20, 0xFA, 0x34, 0xCC, 0x2B, 0x10, 0xDE, 0xD0, 0x86, 0xED, 0x5D, 0x97, 0x9F, 0x8E, 0x07, 0xF5, 0x67, 0xC5, 0x3D, 0xAF, 0xFB, 0xA3, 0x80, 0xCD, 0xAB, 0xC0, 0x50, 0x25, 0x0E, 0x4E, 0xA4, 0x83, 0x05, 0xBE, 0x64, 0x74, 0x18, 0xB7, 0x31, 0x32, 0x68, 0x9F, 0x9B, 0xA2, 0xD0, 0x2E, 0x0A, 0xDF, 0x22, 0x91, 0x35, 0xE1, 0xE3, 0xFC, 0x34, 0xC0, 0xD0, 0x1A, 0x1A, 0xF0, 0x9B, 0x5C, 0xA4, 0x06, 0x9F, 0x7F, 0xE0, 0x76, 0x6D, 0xCF, 0x9B, 0x60, 0x9C, 0x02, 0x8C, 0x7F, 0x1D, 0x2C, 0x76, 0xAF, 0x0F, 0x41, 0x9D, 0x0D, 0x90, 0xBF, 0x22, 0x89, 0xFE, 0x13, 0x32, 0x03, 0x24, 0x1E, 0x07, 0x2A, 0xFB, 0x87, 0x75, 0xCB, 0x11, 0x80, 0x1D, 0xF0, 0x02, 0x2A, 0x80, 0x2C, 0x20, 0xE4, 0xD1, 0x4F, 0x23, 0x40, 0x02, 0xA8, 0x9C, 0xA0, 0xD1, 0xF7, 0xFE, 0x74, 0xAB, 0x9E, 0xE9, 0x19, 0x9B, 0xC5, 0x51, 0x17, 0x70, 0xA8, 0x13, 0x6A, 0xE1, 0x62, 0xC9, 0xD9, 0x8F, 0x3C, 0xAD, 0x4D, 0xCD, 0xCE, 0xBF, 0xE6, 0x63, 0x29, 0x00, 0xC9, 0x86, 0x3C, 0x2B, 0xED, 0xF9, 0x64, 0xFA, 0xFB, 0x5D, 0x20, 0xAD, 0xF4, 0x73, 0x9D, 0xE3, 0x99, 0x7C, 0x98, 0x23, 0x9A, 0x4E, 0x47, 0x51, 0xC7, 0x40, 0x64, 0x37, 0x30, 0x04, 0x03, 0x6E, 0x8F, 0x4A, 0x33, 0x03, 0xEC, 0x0D, 0x6B, 0x04, 0xA0, 0x8D, 0xF4, 0xFD, 0x23, 0xCD, 0xEF, 0x90, 0xC0, 0xBF, 0xCF, 0xB7, 0x44, 0x13, 0x34, 0xFE, 0x66, 0x3C, 0xA9, 0xEA, 0xAB, 0x0B, 0x78, 0xC4, 0x04, 0x0D, 0xA9, 0xB7, 0xA3, 0xD0, 0xE6, 0x8B, 0x44, 0xAC, 0xC5, 0xF1, 0xD6, 0x55, 0xFF, 0x36, 0xB5, 0x9C, 0xA0, 0xF1, 0x6B, 0x83, 0xCA, 0xBC, 0x47, 0xB1, 0x99, 0xF6, 0xAF, 0x56, 0xD5, 0xA0, 0xE7, 0x98, 0xBB, 0xDA, 0x62, 0x30, 0x30, 0xB6, 0x1C, 0xFF, 0xDE, 0x8C, 0xA5, 0x4C, 0xCA, 0x71, 0xD2, 0x50, 0xB1, 0x0D, 0x24, 0x39, 0x01, 0x19, 0x38, 0xC0, 0x03, 0x6D, 0x48, 0xE3, 0xE9, 0x6E, 0x98, 0xD4, 0x31, 0x31, 0x70, 0xAC, 0xBF, 0x58, 0xFB, 0x99, 0x57, 0x5B, 0x67, 0xA4, 0x5F, 0xD4, 0x04, 0xEA, 0xC9, 0x59, 0xB8, 0xEE, 0xA6, 0x4C, 0xD4, 0x70, 0xC7, 0x3F, 0xFC, 0x5D, 0x03, 0xCB, 0x12, 0xE3, 0x91, 0x44, 0x78, 0x02, 0x9D, 0x96, 0x88, 0xB2, 0xCB, 0xBB, 0xA9, 0x5D, 0xDD, 0x51, 0x80, 0x07, 0x0A, 0x90, 0x35, 0x76, 0x40, 0xF7, 0xF8, 0xCF, 0xEC, 0xF6, 0x23, 0xF1, 0x32, 0xD7, 0xC9, 0x11, 0xC2, 0xC2, 0x8A, 0xFB, 0xCD, 0xEF, 0xF8, 0x3D, 0x58, 0xC8, 0x79, 0xF4, 0x26, 0x05, 0xB0, 0x04, 0x94, 0x01, 0x89, 0x86, 0x37, 0x0A, 0xB0, 0xC6, 0x3D, 0x23, 0x1D, 0x80, 0x68, 0xBE, 0xF8, 0x98, 0x46, 0x39, 0xE0, 0x73, 0x90, 0xB1, 0x09, 0x9A, 0x7E, 0xAE, 0x5A, 0x95, 0xF6, 0xF7, 0xA4, 0xA6, 0x7D, 0x29, 0xF8, 0xBA, 0x78, 0xE2, 0x7B, 0x30, 0x8C, 0xB3, 0x2B, 0x90, 0x8E, 0x33, 0xBD, 0xE1, 0xBD, 0xA9, 0xAF, 0x85, 0xF8, 0x5D, 0xDB, 0xFC, 0x1C, 0x3A, 0x14, 0xD0, 0x37, 0x47, 0xB1, 0x64, 0x28, 0xD0, 0xF4, 0x3A, 0x3D, 0x1D, 0x3F, 0x0B, 0xF1, 0xEC, 0x84, 0xE0, 0x1C, 0xDF, 0xEA, 0x36, 0xD7, 0xFB, 0x72, 0x97, 0xB9, 0x09, 0x61, 0x3B, 0x5B, 0xF3, 0x97, 0x72, 0x0F, 0x7B, 0x9B, 0x02, 0xEA, 0x0D, 0x6B, 0x14, 0x30, 0x82, 0x88, 0x74, 0x00, 0xF1, 0xC6, 0xD9, 0xE5, 0xB0, 0x62, 0x20, 0x02, 0xC8, 0xE8, 0x6F, 0xA9, 0x09, 0x1A, 0xA6, 0x8A, 0x0F, 0xF9, 0x04, 0xED, 0x0B, 0xA1, 0x54, 0xB4, 0x55, 0x01, 0x63, 0x8B, 0x39, 0x86, 0x62, 0x9E, 0x3B, 0xEE, 0x3C, 0xA9, 0x18, 0x1E, 0x78, 0x4F, 0x6A, 0x7B, 0x8F, 0xC2, 0xD9, 0x75, 0xCD, 0xAF, 0x87, 0xDC, 0xB9, 0x1F, 0x80, 0x15, 0xB0, 0xB9, 0x8A, 0xE7, 0xCF, 0x9B, 0x7F, 0x4A, 0xDF, 0x76, 0x85, 0x32, 0x94, 0xFA, 0x13, 0x4F, 0x0B, 0x2E, 0x02, 0x2A, 0xAB, 0x9D, 0x86, 0x6F, 0x33, 0x48, 0x04, 0x40, 0xD1, 0x87, 0x94, 0x04, 0xC4, 0x00, 0xD6, 0x06, 0x35, 0x02, 0xB0, 0x69, 0x22, 0x31, 0x40, 0xA2, 0x41, 0x00, 0xF5, 0x77, 0x66, 0xC3, 0x0A, 0x08, 0x9A, 0xEF, 0xEC, 0xA0, 0xF9, 0x67, 0x4D, 0x49, 0xA2, 0xAB, 0x02, 0x6A, 0x04, 0x6B, 0x15, 0x2E, 0x87, 0x36, 0x6C, 0x0A, 0x24, 0xE1, 0xB2, 0x60, 0x84, 0x48, 0xB2, 0xD3, 0x43, 0xF2, 0x8C, 0x2D, 0xA6, 0x6F, 0xD3, 0x44, 0xCD, 0xC7, 0xB9, 0x4F, 0x00, 0x32, 0x40, 0x18, 0x48, 0x5F, 0xD6, 0x55, 0x72, 0x07, 0xBF, 0xD2, 0x67, 0xC1, 0xCD, 0x5B, 0xF4, 0xD7, 0xC9, 0xD0, 0x59, 0x9B, 0x5C, 0x65, 0xD1, 0x95, 0x52, 0x61, 0x7E, 0xC7, 0x41, 0x1B, 0x0C, 0xE8, 0xF3, 0xC9, 0xDF, 0x97, 0xA9, 0x02, 0x54, 0xC0, 0xF1, 0xFD, 0xC8, 0x7B, 0x6D, 0x69, 0x6C, 0xBE, 0x8F, 0x67, 0x7C, 0x9A, 0x1C, 0xB5, 0xA6, 0x56, 0xBE, 0x3F, 0xC5, 0x51, 0xC5, 0xEF, 0xA6, 0x5B, 0x25, 0x6A, 0x7B, 0x27, 0xC2, 0xD2, 0xF0, 0x58, 0x19, 0x6F, 0xCB, 0xFF, 0x36, 0xDD, 0xA2, 0xF7, 0x6D, 0x14, 0x1F, 0x1F, 0x3D, 0x46, 0x07, 0x34, 0x00, 0x9F, 0x2C, 0xC6, 0x6F, 0xDC, 0xE9, 0x3A, 0xB6, 0xEB, 0xDC, 0x09, 0x1E, 0x79, 0x98, 0xA9, 0x01, 0x4C, 0x4F, 0x88, 0x5E, 0xA5, 0x48, 0x92, 0xED, 0x6A, 0x63, 0x0A, 0x9C, 0xAE, 0x41, 0xCF, 0x18, 0xE0, 0x40, 0x1A, 0x09, 0x94, 0x9C, 0x6D, 0x2F, 0xE3, 0x0C, 0x98, 0x3F, 0x22, 0xCA, 0xF4, 0x28, 0x56, 0x2B, 0xE0, 0xDC, 0x41, 0xCB, 0xEF, 0xBE, 0x29, 0xDC, 0x83, 0x78, 0x01, 0x61, 0xF8, 0x38, 0x86, 0xC7, 0x33, 0x0B, 0x4B, 0x23, 0x03, 0x1B, 0xB1, 0x27, 0xAE, 0x06, 0x85, 0x83, 0x9A, 0xBE, 0x07, 0xB5, 0xFB, 0xF2, 0x9F, 0x7F, 0x97, 0xDA, 0x5E, 0xA8, 0xC7, 0x1A, 0xDA, 0x78, 0x24, 0x2F, 0xE2, 0x3C, 0x6F, 0x80, 0xD2, 0xDF, 0x9D, 0x29, 0xEF, 0xA0, 0x74, 0xC8, 0x5E, 0x69, 0x66, 0x63, 0xD4, 0xB3, 0xFB, 0x9D, 0xAB, 0x71, 0x00, 0x17, 0x40, 0x1B, 0x92, 0x0D, 0x6F, 0x14, 0xE0, 0x36, 0xB3, 0x93, 0x80, 0x1E, 0x80, 0x1F, 0xCF, 0xD6, 0x48, 0xC0, 0x0A, 0x08, 0xB9, 0xCF, 0x47, 0x07, 0xAD, 0xBE, 0x2E, 0xAB, 0x23, 0xD4, 0x02, 0xDD, 0x3F, 0x3F, 0x6C, 0xB4, 0xC1, 0xE3, 0x86, 0x17, 0x86, 0xFF, 0x1B, 0xF6, 0x0D, 0xFE, 0xE1, 0x1F, 0x57, 0x02, 0x7E, 0x7C, 0x1B, 0x62, 0xBD, 0x2F, 0x97, 0x1D, 0x37, 0x70, 0x80, 0x88, 0x9F, 0x84, 0x84, 0x4E, 0x40, 0x47, 0xD2, 0xFD, 0xCE, 0x96, 0x29, 0xFD, 0x02, 0x1A, 0x77, 0x3E, 0x3B, 0x7C, 0x3B, 0xF2, 0xF2, 0xAB, 0x9F, 0x5F, 0x8F, 0xD6, 0xB4, 0x00, 0x42, 0x0D, 0xDF, 0x91, 0x74, 0xDD, 0x26, 0xA8, 0x34, 0x30, 0xE0, 0xF0, 0x64, 0x18, 0x80, 0x38, 0x8D, 0xB9, 0x33, 0xCF, 0x95, 0xFD, 0xBB, 0x24, 0x7D, 0x87, 0x63, 0xFE, 0x9E, 0x4B, 0x62, 0x59, 0xCE, 0xEB, 0x81, 0x63, 0x6D, 0x98, 0x33, 0xCC, 0x9A, 0x55, 0x70, 0x1F, 0x66, 0xDD, 0xA7, 0x5B, 0x7E, 0x34, 0x39, 0x38, 0xF7, 0x79, 0x42, 0x15, 0x90, 0x37, 0x47, 0xC4, 0x1B, 0x92, 0x3B, 0x75, 0xCD, 0x32, 0xFE, 0x7D, 0x53, 0xAA, 0xFF, 0x35, 0xA3, 0xC6, 0x5F, 0x21, 0x1C, 0xDA, 0xD5, 0xBF, 0xF2, 0x6D, 0xDC, 0x58, 0x8F, 0xE9, 0xAA, 0x3F, 0xCB, 0x2F, 0x1D, 0x28, 0xDE, 0x17, 0x12, 0x4F, 0xA0, 0x02, 0xC8, 0x02, 0xBC, 0x21, 0x01, 0x90, 0x03, 0x9C, 0x40, 0x9D, 0x09, 0x1A, 0x7D, 0xCA, 0xD3, 0xC7, 0x13, 0xF6, 0x44, 0x92, 0x9F, 0x00, 0x35, 0x8B, 0xF7, 0xAC, 0xA7, 0x63, 0xB8, 0xB7, 0x90, 0x52, 0x3B, 0x6C, 0xD8, 0x2D, 0x2B, 0xB6, 0x33, 0x65, 0x4D, 0xD0, 0x26, 0x39, 0xF0, 0xFC, 0x2E, 0x39, 0xD9, 0xED, 0xE7, 0xB6, 0x52, 0x0C, 0xA4, 0xCC, 0xAA, 0xE8, 0x07, 0x64, 0xF6, 0x98, 0x29, 0x02, 0x1A, 0xED, 0x61, 0x3D, 0xE3, 0xE9, 0x96, 0x41, 0xC6, 0xF2, 0xEC, 0x67, 0xE8, 0xD8, 0xB3, 0x0F, 0x0C, 0xA2, 0x41, 0x0D, 0x69, 0x68, 0xA3, 0x00, 0x61, 0x60, 0x6A, 0x88, 0xC7, 0xF6, 0x78, 0x48, 0x14, 0xA0, 0x0D, 0x39, 0x80, 0xF2, 0x64, 0xB6, 0x26, 0x68, 0xDC, 0x2E, 0x17, 0x84, 0x51, 0xD1, 0xD4, 0xCF, 0xBC, 0xDE, 0x44, 0x31, 0x9F, 0xCD, 0x7C, 0x2F, 0x9F, 0xF0, 0x7E, 0x4B, 0xF4, 0x0D, 0xB3, 0x6F, 0x35, 0xFD, 0x7C, 0x82, 0x76, 0x1B, 0xDE, 0x15, 0xB1, 0xA3, 0x78, 0x6A, 0x97, 0xD9, 0xE0, 0x06, 0x6D, 0x4F, 0x90, 0x11, 0x9B, 0xD0, 0xEB, 0x64, 0x36, 0xBB, 0x3C, 0xAF, 0x7A, 0xDF, 0x1C, 0xAD, 0x78, 0xEE, 0xB5, 0x0C, 0x1C, 0xDA, 0x79, 0x61, 0x6A, 0x88, 0x35, 0x12, 0x50, 0x6E, 0x3C, 0x7D, 0x47, 0x61, 0xDB, 0x83, 0x57, 0x0F, 0x20, 0x06, 0xD0, 0xA3, 0xFA, 0x1F, 0xCF, 0x09, 0x40, 0x75, 0x82, 0x86, 0xB1, 0x0B, 0x74, 0xC1, 0x7F, 0x6F, 0x1C, 0x5B, 0x37, 0x02, 0x4F, 0xCC, 0x34, 0x1A, 0x3B, 0xAE, 0xBC, 0xAD, 0xD1, 0xA4, 0x92, 0x93, 0xE9, 0x7E, 0x7A, 0xE2, 0xE9, 0xD9, 0xD3, 0xF2, 0xFF, 0xBD, 0xA7, 0x45, 0x35, 0x74, 0xDF, 0xA6, 0x72, 0x9E, 0xAF, 0x6B, 0x16, 0x0C, 0xC8, 0x12, 0xB9, 0xF7, 0xDB, 0xD7, 0xCB, 0xBA, 0x7B, 0x18, 0x4C, 0x01, 0x35, 0xC0, 0x0B, 0x88, 0x7C, 0x50, 0x40, 0xD2, 0x63, 0x9F, 0x2D, 0x80, 0x24, 0xE0, 0x07, 0x30, 0x01, 0xA4, 0x00, 0x8A, 0xC7, 0xC3, 0xA6, 0xE1, 0x32, 0x41, 0x83, 0x05, 0x41, 0x29, 0x7F, 0xBE, 0x0D, 0xC7, 0xD0, 0xE5, 0x8D, 0x3A, 0x8A, 0xC2, 0x57, 0x0B, 0xE6, 0x8A, 0x85, 0x12, 0x64, 0x17, 0x0D, 0xD4, 0xE5, 0x1F, 0xD3, 0x17, 0xBB, 0xBD, 0x02, 0x57, 0xC9, 0xED, 0x75, 0x6E, 0xFB, 0xF8, 0xE4, 0x05, 0x98, 0xEC, 0xEB, 0xC9, 0x58, 0x02, 0x5C, 0x83, 0xBA, 0x65, 0xDC, 0x91, 0xF7, 0xEE, 0x10, 0x36, 0xF5, 0x81, 0x49, 0x3B, 0xEC, 0x8B, 0x53, 0xEA, 0xB6, 0x09, 0x8F, 0x00, 0x8A, 0x1A, 0xB5, 0x5F, 0xE1, 0xC4, 0x80, 0xE4, 0x4E, 0x27, 0x13, 0xEF, 0x29, 0x9A, 0x7C, 0x8D, 0x25, 0x0E, 0x60, 0x77, 0x57, 0x98, 0xA0, 0x75, 0x8F, 0xD0, 0xF5, 0xBE, 0xEB, 0x8A, 0x72, 0x31, 0xEA, 0xD2, 0xE2, 0x38, 0x5C, 0xB6, 0xCD, 0x16, 0x85, 0x75, 0x9B, 0xEC, 0x23, 0x08, 0x2C, 0x8F, 0x8A, 0xB2, 0xC7, 0x52, 0x68, 0x47, 0x48, 0xBA, 0x2A, 0x07, 0xE4, 0xA0, 0x80, 0xF2, 0x47, 0x9C, 0xD6, 0x7F, 0x92, 0xAC, 0xDA, 0xFD, 0x18, 0xDD, 0xF4, 0xCF, 0x36, 0x52, 0xA0, 0xD3, 0x95, 0xBA, 0xBD, 0xB4, 0xA6, 0x0A, 0x83, 0x89, 0x77, 0x40, 0x02, 0xB8, 0xCE, 0x68, 0xD2, 0xA0, 0xC7, 0x99, 0x92, 0x00, 0x0E, 0xC0, 0x0D, 0xA8, 0x03, 0xA4, 0x03, 0xD1, 0x70, 0x01, 0xAC, 0xE1, 0x3D, 0x8F, 0x4A, 0xD2, 0x41, 0xF3, 0x4F, 0x22, 0xA1, 0x34, 0x50, 0x1D, 0x75, 0x5C, 0xA3, 0x8C, 0xA3, 0x77, 0xB8, 0xC2, 0x55, 0xA0, 0xAB, 0x04, 0x9A, 0x8C, 0x57, 0x30, 0xDB, 0x92, 0x97, 0xB0, 0xFD, 0x22, 0x90, 0x7B, 0xDB, 0xE4, 0xD8, 0x73, 0x01, 0x35, 0x60, 0x20, 0x0F, 0x10, 0x06, 0x54, 0x2D, 0xC5, 0x03, 0xBE, 0x7E, 0x9C, 0xC7, 0x80, 0xB1, 0xFA, 0xB4, 0xF1, 0x7A, 0xA5, 0x19, 0xBB, 0x5E, 0x53, 0x6A, 0xCA, 0x67, 0xA1, 0xE6, 0xBF, 0x49, 0x00, 0xA6, 0x80, 0x07, 0x10, 0x0A, 0xA4, 0xCE, 0xBD, 0x02, 0xB0, 0x04, 0x32, 0x1A, 0x04, 0xB8, 0x01, 0x4A, 0x00, 0x0B, 0x20, 0x01, 0xD4, 0x04, 0x2D, 0x20, 0x92, 0x63, 0x7A, 0x57, 0x9A, 0x7D, 0x97, 0xE2, 0xFC, 0xAE, 0x51, 0x2A, 0xD6, 0x95, 0xDA, 0xEE, 0x51, 0x96, 0xC0, 0x45, 0x52, 0xCE, 0x92, 0x97, 0x70, 0x7F, 0xB4, 0xD3, 0xE2, 0x37, 0x0D, 0xB1, 0x4C, 0x70, 0xE5, 0x11, 0x50, 0x71, 0x06, 0x42, 0xB7, 0x76, 0xB4, 0xCF, 0xAA, 0x90, 0x9F, 0xD0, 0xEB, 0xA8, 0xB1, 0x8E, 0x7A, 0x50, 0x5E, 0xC5, 0xEC, 0xEB, 0x85, 0x7B, 0xF6, 0xBB, 0x62, 0xC2, 0x54, 0xB5, 0xC3, 0xA4, 0xDA, 0x38, 0x80, 0xE4, 0xFE, 0xA2, 0xC7, 0xB4, 0x07, 0x03, 0x6C, 0x8D, 0xB3, 0xEF, 0x9E, 0x75, 0x80, 0x48, 0x60, 0xE2, 0x2A, 0xD9, 0x41, 0x83, 0xB5, 0xBF, 0x19, 0x77, 0x51, 0x3F, 0xBF, 0xD4, 0x6D, 0x86, 0xA1, 0x8A, 0x47, 0x5F, 0x98, 0x58, 0xA5, 0x10, 0xE4, 0x4A, 0x1C, 0xE8, 0x39, 0x57, 0x96, 0xC3, 0xE5, 0xAD, 0x47, 0x4D, 0xF7, 0x6D, 0xEC, 0xBC, 0x46, 0x4A, 0x43, 0x1B, 0x06, 0xD4, 0x12, 0x95, 0x9B, 0x03, 0x3E, 0xF1, 0xF5, 0x6C, 0x3D, 0xA3, 0x21, 0xE2, 0xBF, 0x27, 0xCA, 0xAE, 0xF1, 0x70, 0x4D, 0x7C, 0xA6, 0xED, 0x6D, 0x9B, 0x18, 0x09, 0xED, 0x4F, 0x54, 0x1B, 0x7C, 0x1A, 0x0E, 0x18, 0x03, 0x65, 0xB3, 0x6C, 0x79, 0x4D, 0x7D, 0x54, 0x6E, 0x1F, 0x50, 0x6B, 0xF8, 0x84, 0x9E, 0xAC, 0x83, 0x56, 0x9F, 0x32, 0x3C, 0xA7, 0xA1, 0x6B, 0x25, 0xF2, 0x7B, 0x3C, 0x43, 0x09, 0x5D, 0x6F, 0xEA, 0x63, 0x1D, 0xD0, 0x52, 0xE5, 0x0C, 0xF7, 0x6A, 0x96, 0xD5, 0x0C, 0x69, 0xF1, 0x4C, 0xC9, 0x0A, 0xCD, 0x1B, 0x7D, 0x86, 0x23, 0x80, 0xD0, 0x46, 0x6E, 0xE4, 0x88, 0x6D, 0xC9, 0x92, 0xFF, 0xD1, 0xEB, 0xF9, 0x7A, 0x95, 0x46, 0x79, 0xDF, 0xDB, 0x79, 0xC4, 0x23, 0x72, 0xF4, 0x97, 0x47, 0xBC, 0x0A, 0xB0, 0xD1, 0x3A, 0x6F, 0x48, 0x3C, 0xA6, 0x03, 0x06, 0x84, 0x00, 0x39, 0x2D, 0x38, 0x06, 0x78, 0xA3, 0x06, 0x04, 0x84, 0x00, 0x1A, 0x00, 0x37, 0x10, 0x34, 0xBB, 0xCD, 0x90, 0x01, 0xBF, 0x53, 0xFE, 0xF5, 0x79, 0xEB, 0x27, 0x37, 0x24, 0x98, 0xD3, 0xE0, 0xDE, 0xAB, 0x7B, 0x94, 0xD4, 0x85, 0xBB, 0xD1, 0xCC, 0x56, 0x57, 0x7C, 0xCE, 0xDB, 0x53, 0x26, 0x0D, 0xE8, 0x93, 0xB0, 0xA6, 0x5F, 0xEB, 0x28, 0xDE, 0x78, 0x4B, 0x47, 0xF0, 0x08, 0x40, 0x0E, 0xDC, 0x11, 0x9D, 0x55, 0xBD, 0xCB, 0x2B, 0x70, 0x9B, 0x86, 0x4F, 0xB4, 0xB4, 0x57, 0xE7, 0x8A, 0x5E, 0x77, 0x7C, 0x58, 0xC7, 0x39, 0x7A, 0xC4, 0xBD, 0x12, 0x30, 0x07, 0xD8, 0x00, 0xCA, 0x86, 0x01, 0x2C, 0x80, 0x16, 0x50, 0x23, 0x80, 0x41, 0x8F, 0x64, 0x4A, 0x00, 0x21, 0x80, 0xCD, 0xA7, 0xFE, 0x16, 0x9E, 0xA0, 0xD1, 0xB7, 0xA7, 0x05, 0x7B, 0xEB, 0xF0, 0xF2, 0xD7, 0x74, 0x95, 0x9A, 0xB8, 0x7B, 0x4A, 0xA1, 0xF9, 0xC9, 0xB3, 0xEF, 0xF9, 0x01, 0x6F, 0xB9, 0xD4, 0x9D, 0x84, 0x9C, 0xA0, 0xDD, 0x36, 0x58, 0xDE, 0x8E, 0x6C, 0x52, 0x80, 0x0E, 0x08, 0x10, 0xD9, 0xB0, 0x75, 0x0A, 0xBF, 0x7A, 0x4A, 0x7C, 0x85, 0xF7, 0x6F, 0xC7, 0xF3, 0x8C, 0x5C, 0xF2, 0xCD, 0x92, 0xDD, 0x52, 0x0C, 0xA2, 0x3B, 0xC0, 0x43, 0xEE, 0x80, 0xE4, 0x63, 0x98, 0x1E, 0x8F, 0xEB, 0x2E, 0x5D, 0x3D, 0x96, 0xBD, 0xDF, 0x79, 0xC3, 0x12, 0xD0, 0x00, 0xE4, 0x00, 0xE4, 0x00, 0x07, 0x10, 0xA7, 0x83, 0xC6, 0xF3, 0x8F, 0x8A, 0xE3, 0xB6, 0x0B, 0x1A, 0xB9, 0x82, 0x7A, 0x84, 0x28, 0xB1, 0x1F, 0xBB, 0xA1, 0x13, 0xD3, 0x7B, 0xB0, 0x4C, 0x19, 0x1B, 0xFF, 0x6B, 0x76, 0x31, 0xB5, 0x9B, 0x3A, 0xD3, 0x95, 0xDC, 0xCB, 0x60, 0xA6, 0x2A, 0x09, 0xB0, 0x68, 0xD0, 0xE3, 0x0C, 0xC0, 0x3F, 0x45, 0x72, 0xB9, 0x9A, 0xBD, 0xE6, 0xDD, 0xD2, 0x5F, 0xF8, 0x94, 0xF5, 0xD3, 0xCC, 0xD6, 0xFE, 0x16, 0xB9, 0x2E, 0x27, 0x54, 0xC0, 0x39, 0x00, 0x27, 0xA0, 0x05, 0xF8, 0x01, 0x42, 0x80, 0x6C, 0x54, 0x6C, 0xF7, 0xDC, 0x38, 0x40, 0xD9, 0x46, 0xEA, 0xFE, 0x6F, 0x4E, 0x40, 0xE8, 0xB4, 0x87, 0x77, 0xCC, 0x04, 0x31, 0x13, 0x5C, 0xC6, 0x9D, 0xA8, 0xC5, 0x84, 0x05, 0x1D, 0xCB, 0x14, 0x38, 0x34, 0x49, 0xB6, 0xEE, 0x36, 0x21, 0x82, 0x92, 0x77, 0xCE, 0xF7, 0x0E, 0x14, 0xD0, 0xDD, 0xF8, 0xD5, 0xC6, 0xA2, 0xB8, 0x4F, 0x5B, 0xFE, 0xA8, 0xA9, 0x04, 0x01, 0xA6, 0x80, 0x08, 0xA0, 0xF6, 0x57, 0xCB, 0x58, 0xCE, 0x15, 0xE6, 0x3D, 0x0E, 0x24, 0xFF, 0xA6, 0xE9, 0xFA, 0xB5, 0x75, 0x27, 0x10, 0xFD, 0xCA, 0xE1, 0x07, 0x01, 0xA4, 0xC0, 0x91, 0x49, 0xC6, 0x01, 0xD1, 0xC8, 0xD3, 0x10, 0xA0, 0x0C, 0xDF, 0xC9, 0x0E, 0x78, 0x01, 0x65, 0x0D, 0x7A, 0x1C, 0x95, 0x05, 0x30, 0x07, 0x7C, 0xA4, 0xCF, 0xB5, 0x63, 0xA6, 0x9F, 0xBE, 0xD0, 0x21, 0x48, 0xF5, 0xA1, 0x9E, 0xF7, 0x65, 0x2E, 0xF8, 0x7B, 0x77, 0x52, 0x38, 0x32, 0xED, 0x2C, 0xC8, 0xA6, 0x67, 0xB5, 0x26, 0xA8, 0xFC, 0xAB, 0x97, 0xC3, 0xB6, 0xCD, 0xD5, 0xDC, 0xDA, 0x69, 0xA0, 0xBB, 0x0D, 0x39, 0x1B, 0x11, 0x40, 0xE5, 0x5C, 0x19, 0x26, 0x8D, 0xFF, 0xBC, 0xD2, 0x04, 0xEF, 0xC7, 0x19, 0x56, 0xB4, 0xFE, 0x96, 0x37, 0x73, 0xA1, 0x67, 0x9F, 0xEB, 0xEF, 0x00, 0xFD, 0xBC, 0x42, 0x0D, 0xB0, 0x03, 0x78, 0x23, 0xE8, 0xB9, 0x71, 0xA8, 0x00, 0x71, 0x00, 0xB7, 0x47, 0xAD, 0x80, 0x81, 0xD3, 0x20, 0x03, 0x42, 0x3A, 0x68, 0xF6, 0xC7, 0x04, 0xD3, 0x29, 0x9A, 0x48, 0xD8, 0x06, 0x52, 0xD9, 0xE8, 0x96, 0xC4, 0x04, 0x81, 0x57, 0x38, 0xEE, 0x32, 0xA6, 0xA8, 0x9D, 0xA2, 0x16, 0x15, 0x31, 0x41, 0x93, 0xB7, 0x97, 0x23, 0xB7, 0xCD, 0xA2, 0x1A, 0x60, 0x02, 0xC8, 0xD9, 0x19, 0x8F, 0xB4, 0xC6, 0x24, 0x71, 0xE2, 0xF6, 0xDE, 0xEE, 0xDC, 0xBE, 0xD9, 0x12, 0xB8, 0x3C, 0x67, 0x0E, 0x80, 0x53, 0x8E, 0x01, 0xB8, 0x11, 0xB6, 0x95, 0xC1, 0xEA, 0x6E, 0x50, 0x0C, 0x24, 0x01, 0x25, 0x73, 0xF7, 0x07, 0x84, 0x81, 0x68, 0x94, 0x35, 0x0E, 0x10, 0x05, 0x58, 0x00, 0x4A, 0x80, 0xE1, 0xB8, 0x33, 0xD3, 0x17, 0x68, 0x6B, 0xC1, 0x1B, 0x02, 0xDD, 0x1B, 0x0E, 0x83, 0x32, 0x57, 0x46, 0xCB, 0xAE, 0x38, 0x7E, 0x59, 0xFA, 0x50, 0x5E, 0x84, 0x76, 0x4E, 0xCD, 0x6B, 0x45, 0xF6, 0xF1, 0xBC, 0x65, 0x4F, 0xCD, 0x9D, 0xD6, 0x48, 0x07, 0x4A, 0x80, 0x50, 0xC0, 0x1A, 0x92, 0xC0, 0xE8, 0x23, 0x4C, 0x2C, 0x28, 0xEE, 0xDC, 0xCE, 0x9E, 0x92, 0x9D, 0x2C, 0xD7, 0x1C, 0x66, 0x6E, 0x62, 0x09, 0xD0, 0xB3, 0x2B, 0xFA, 0x4A, 0x3B, 0xB3, 0xC8, 0x01, 0xA8, 0x3E, 0xAA, 0xAB, 0x07, 0xC8, 0x69, 0xD0, 0x67, 0x40, 0xAD, 0x41, 0x00, 0x07, 0x70, 0xEE, 0x35, 0x66, 0x6B, 0x7D, 0x6A, 0xCD, 0x7B, 0x20, 0xBE, 0xD7, 0xA5, 0x8B, 0x7E, 0xC1, 0xD3, 0xF4, 0x35, 0xFF, 0x6F, 0x9A, 0x68, 0x3C, 0xC7, 0x1A, 0x93, 0x63, 0x8C, 0xE9, 0x1B, 0xBC, 0x3C, 0x45, 0xFF, 0x29, 0x07, 0x79, 0x35, 0x1B, 0x0D, 0x90, 0x6A, 0x10, 0x40, 0xE7, 0xE9, 0x8C, 0x5C, 0xED, 0x92, 0x72, 0xCB, 0x16, 0xEE, 0xFB, 0xF7, 0x94, 0xDA, 0x6A, 0x9B, 0x13, 0xEC, 0xA4, 0x5D, 0xD7, 0x0D, 0x7C, 0x5A, 0x02, 0x7E, 0x6B, 0x72, 0xEA, 0x08, 0xC0, 0xDC, 0x28, 0x40, 0x62, 0x5B, 0x06, 0x9E, 0x04, 0xC4, 0x00, 0xAE, 0xDD, 0x09, 0x9C, 0x0D, 0xD7, 0x9D, 0xB8, 0x15, 0x9D, 0xA0, 0xE5, 0x1F, 0x6F, 0xFF, 0x07, 0xFF, 0xFE, 0xFD, 0x7F, 0x3E, 0x8B, 0x48, 0x81, 0xE3, 0xA0, 0xCA, 0xF6, 0x81, 0xDC, 0xD1, 0x41, 0x92, 0xBE, 0x73, 0x90, 0xFA, 0x9C, 0x38, 0x58, 0x9F, 0xAC, 0xAC, 0x00, 0xAC, 0x5B, 0xF2, 0xBC, 0x04, 0xC8, 0xC9, 0x76, 0x4B, 0xC7, 0x60, 0x3D, 0xBB, 0x50, 0xDF, 0x05, 0xE6, 0x97, 0xC8, 0x59, 0x46, 0x3B, 0x83, 0x31, 0xFA, 0x91, 0xF3, 0x94, 0xDB, 0x2C, 0xD4, 0x69, 0x6E, 0x78, 0x1C, 0x4F, 0x45, 0x00, 0x4D, 0xC0, 0xE5, 0xB9, 0xA4, 0x9A, 0x00, 0x99, 0x0D, 0x06, 0xAC, 0x00, 0xCE, 0x67, 0x53, 0x73, 0xE0, 0xAE, 0xB4, 0x6A, 0x41, 0xFF, 0x3B, 0x8E, 0x87, 0x8B, 0xBA, 0x61, 0x66, 0xE5, 0x88, 0xB7, 0xF3, 0x9A, 0xF7, 0x70, 0x75, 0xF4, 0xD9, 0x29, 0xA1, 0xC3, 0xF1, 0x8A, 0xB5, 0xF2, 0x15, 0x8C, 0xF8, 0x4D, 0x57, 0xA3, 0x5E, 0xB9, 0x75, 0xF5, 0x0E, 0x40, 0x04, 0x1C, 0x07, 0x26, 0xD9, 0xA0, 0xF2, 0x53, 0xB8, 0x99, 0x63, 0x01, 0xD4, 0x6F, 0x70, 0x10, 0x28, 0x60, 0x2C, 0xFD, 0x75, 0x8C, 0xD8, 0x12, 0x18, 0x05, 0x97, 0x34, 0x20, 0x1A, 0xEE, 0x0D, 0x6E, 0x04, 0x10, 0x04, 0x24, 0x3F, 0xAE, 0x6E, 0x05, 0xA8, 0x35, 0xA2, 0xE1, 0x0D, 0xD9, 0x30, 0x05, 0x0A, 0x7B, 0xDA, 0x0C, 0x17, 0x50, 0x64, 0x0F, 0x8F, 0x22, 0x58, 0x51, 0x85, 0x06, 0xFB, 0xEA, 0x01, 0xEC, 0x23, 0xB8, 0x7E, 0xB8, 0x20, 0xF0, 0x67, 0xCF, 0xB0, 0x47, 0x3D, 0x4E, 0x51, 0x94, 0xF7, 0x62, 0x37, 0xE5, 0x35, 0xC0, 0x12, 0x50, 0x05, 0x48, 0x1E, 0x65, 0xD4, 0x95, 0xD0, 0x46, 0x13, 0x6D, 0x2B, 0x69, 0x00, 0x91, 0x3F, 0x7D, 0x34, 0xED, 0xFF, 0x41, 0x9E, 0x6B, 0x13, 0xDD, 0xB1, 0x48, 0x22, 0xA0, 0xA6, 0x35, 0xCB, 0xB6, 0xB3, 0x0D, 0x11, 0xC0, 0x0C, 0x48, 0xC3, 0x02, 0xA8, 0xB9, 0x32, 0x44, 0x43, 0x81, 0xD3, 0xDF, 0x92, 0x0A, 0xC4, 0x7C, 0x1A, 0x57, 0x3F, 0xEA, 0xA0, 0xD1, 0x1F, 0x13, 0x3C, 0x96, 0x4A, 0x58, 0x6F, 0xFE, 0x15, 0xB6, 0x13, 0x07, 0xA4, 0xE3, 0x7D, 0xCB, 0x97, 0x2E, 0xB3, 0x33, 0xDA, 0x1A, 0x71, 0xDD, 0x72, 0x7A, 0x9B, 0x12, 0x68, 0x3D, 0x88, 0x7E, 0x4B, 0x12, 0xE1, 0x40, 0x35, 0xF2, 0x00, 0xAE, 0x80, 0x1A, 0x30, 0x07, 0xFA, 0xBB, 0x42, 0xE7, 0x57, 0x3A, 0x0D, 0x1D, 0x45, 0x44, 0xD9, 0xBE, 0x8C, 0xF3, 0xEE, 0x3F, 0x6D, 0x54, 0x36, 0x13, 0xED, 0xF9, 0x8A, 0x9B, 0x1B, 0xE0, 0x07, 0xA8, 0xAB, 0x1B, 0x08, 0xF0, 0x01, 0x4C, 0x46, 0xB9, 0x1C, 0x10, 0x01, 0x38, 0x01, 0x9A, 0x3B, 0x6A, 0x00, 0x5E, 0x40, 0x9E, 0xB9, 0x8E, 0x76, 0xD0, 0x5A, 0xA0, 0x9B, 0xE4, 0x6A, 0x92, 0xE9, 0xF7, 0x7A, 0x77, 0x4C, 0x12, 0x70, 0xB4, 0x74, 0x4A, 0xF6, 0x03, 0xEC, 0x2D, 0x4C, 0x00, 0xFB, 0x1A, 0x7F, 0x6F, 0x9E, 0x3C, 0x89, 0x62, 0x9E, 0x9B, 0xC7, 0xC8, 0x48, 0x3C, 0xD6, 0x46, 0x26, 0x80, 0x30, 0x40, 0x04, 0x8C, 0xEF, 0xD8, 0x1C, 0x8A, 0x75, 0x2E, 0xB9, 0x33, 0x93, 0x3E, 0x9F, 0x5A, 0x66, 0x73, 0x2C, 0xBB, 0x44, 0x47, 0x7B, 0xF5, 0x31, 0x56, 0xAA, 0x49, 0x25, 0x8E, 0x6E, 0x5D, 0x5F, 0x4E, 0x03, 0xB0, 0x02, 0x42, 0x81, 0xEC, 0x64, 0x13, 0x05, 0x60, 0x8D, 0xC8, 0x46, 0x01, 0xDE, 0x30, 0x05, 0x34, 0xF6, 0x8F, 0x74, 0x26, 0x68, 0x82, 0x21, 0xC7, 0x12, 0xF4, 0x0C, 0xB9, 0xFE, 0xF1, 0xEF, 0xE4, 0x59, 0x78, 0x4A, 0x59, 0xFB, 0x14, 0x63, 0xE8, 0xA9, 0x13, 0x14, 0x3F, 0x39, 0x9F, 0xF6, 0xB4, 0xFD, 0x1E, 0x98, 0x86, 0x20, 0x1C, 0xC9, 0xD6, 0xC0, 0x79, 0x16, 0x10, 0x06, 0xB8, 0x00, 0xF6, 0xD8, 0xD7, 0xC5, 0x5D, 0x46, 0x1D, 0xD7, 0xF0, 0xED, 0x77, 0x78, 0xAC, 0x83, 0x3D, 0xCF, 0xE5, 0xF4, 0x6E, 0x24, 0xA0, 0x36, 0x9F, 0x7A, 0x6D, 0x4D, 0x05, 0x9F, 0x80, 0xF4, 0x59, 0x38, 0x00, 0x3B, 0x20, 0x09, 0x38, 0x01, 0xC5, 0xDB, 0xE1, 0x92, 0x0E, 0x70, 0x9E, 0xC4, 0x47, 0x16, 0x30, 0x77, 0xF8, 0x79, 0x79, 0xF6, 0x90, 0xBF, 0x4B, 0x22, 0xAC, 0x09, 0x13, 0x3C, 0x67, 0x87, 0xBA, 0x42, 0x6A, 0xEB, 0xF1, 0xA0, 0xB3, 0x94, 0xC4, 0xDA, 0x73, 0xCF, 0x76, 0xB2, 0x9B, 0x1E, 0x23, 0x37, 0xF2, 0x79, 0x16, 0x26, 0x8F, 0xD1, 0x97, 0xCD, 0xA3, 0x8F, 0x6D, 0x62, 0x43, 0xA2, 0xE1, 0x73, 0x11, 0x9D, 0x7F, 0xC8, 0x49, 0x75, 0xFC, 0x7C, 0xC4, 0x90, 0x0C, 0xEE, 0xF7, 0x50, 0xF7, 0xC9, 0xCF, 0x82, 0xF3, 0xED, 0x00, 0x1A, 0xBD, 0xC4, 0xC6, 0xA9, 0x4E, 0x14, 0xC8, 0x11, 0x9E, 0x4C, 0x80, 0x19, 0x90, 0x04, 0x62, 0x26, 0xB7, 0xDF, 0xAD, 0x5F, 0x01, 0x39, 0xFB, 0x1D, 0x53, 0x31, 0x9F, 0x80, 0x98, 0xA0, 0x59, 0x5F, 0x6A, 0x15, 0x2B, 0x9A, 0x0A, 0x03, 0x7E, 0x5E, 0x48, 0x41, 0x3A, 0xBE, 0x58, 0xE6, 0x58, 0xAE, 0x55, 0xBD, 0x31, 0xEA, 0xD2, 0xE5, 0x08, 0x7D, 0xC6, 0xF0, 0x24, 0x9E, 0x36, 0x96, 0x79, 0x5C, 0xDC, 0x01, 0x2D, 0xE0, 0x8C, 0x50, 0x52, 0x00, 0xC6, 0xBF, 0xA4, 0x2C, 0xE4, 0x36, 0xF0, 0xA3, 0xD1, 0x28, 0x73, 0xE1, 0x93, 0xCE, 0xEF, 0xA9, 0x1D, 0xB4, 0x04, 0x78, 0x34, 0x66, 0x3A, 0x92, 0x32, 0x4F, 0xD4, 0xE8, 0xCA, 0x59, 0xDF, 0xDE, 0xF9, 0xB9, 0xB6, 0xD7, 0x73, 0x5F, 0x6F, 0xB8, 0x02, 0x39, 0xB0, 0x06, 0x01, 0x61, 0x8D, 0xF3, 0xFB, 0x6F, 0x7A, 0x13, 0x43, 0xF9, 0xB7, 0xC3, 0x0A, 0x2F, 0xC8, 0xEC, 0x7F, 0x7E, 0xA4, 0x20, 0xC5, 0xB2, 0x55, 0xD4, 0x18, 0xD3, 0xCA, 0x52, 0xDD, 0x8C, 0x22, 0x7F, 0xF0, 0x73, 0xB5, 0x13, 0x0D, 0xE0, 0x3A, 0x4F, 0xDE, 0x52, 0x72, 0x1C, 0xA1, 0x9A, 0x6F, 0x85, 0x6E, 0xC1, 0x10, 0x75, 0xE0, 0xF0, 0x4F, 0xEB, 0xB3, 0xB7, 0x1D, 0xA1, 0x6B, 0x2B, 0xE5, 0xE3, 0xB1, 0xC3, 0x40, 0x08, 0x90, 0x07, 0x28, 0x69, 0x73, 0x9D, 0x03, 0x48, 0x01, 0xD5, 0x76, 0x41, 0x23, 0xE8, 0xA8, 0x06, 0x94, 0xB4, 0xA0, 0x63, 0x02, 0x1A, 0x80, 0x17, 0x50, 0x86, 0xD1, 0x3C, 0x4A, 0x80, 0x03, 0x90, 0x86, 0x36, 0x5C, 0x80, 0x6C, 0x54, 0x5B, 0x4E, 0xCD, 0x75, 0x7D, 0x9C, 0xC6, 0x60, 0xD1, 0x53, 0xC7, 0xA9, 0x13, 0x0F, 0x86, 0xEC, 0x10, 0x21, 0x2D, 0x14, 0x4E, 0x88, 0xD5, 0x34, 0x3D, 0x95, 0xFE, 0x26, 0x17, 0x23, 0x1F, 0xA1, 0xA1, 0xB0, 0xD9, 0x13, 0xE6, 0x39, 0x9A, 0x93, 0x94, 0x00, 0x6C, 0xC0, 0x99, 0x31, 0x73, 0x02, 0xE6, 0x5B, 0x6A, 0x59, 0xB0, 0xA1, 0xF6, 0x8D, 0xC9, 0x5E, 0xC7, 0x27, 0xAD, 0x5F, 0xAE, 0x41, 0x3B, 0x5F, 0x22, 0x57, 0x94, 0x30, 0x0E, 0xA0, 0xDE, 0xC8, 0x46, 0x34, 0x0A, 0x30, 0x07, 0x9C, 0x80, 0x59, 0x3C, 0xE7, 0x00, 0xC2, 0x80, 0x0D, 0xB4, 0x71, 0x00, 0xB5, 0x86, 0x02, 0x56, 0xFD, 0x03, 0xCE, 0x79, 0x23, 0x5B, 0x1A, 0xDC, 0x20, 0xDF, 0x23, 0x85, 0xF5, 0xA5, 0xFE, 0xC1, 0x39, 0xF0, 0xB3, 0x1F, 0x43, 0x92, 0x28, 0xAC, 0xF7, 0x0E, 0x83, 0x38, 0xEB, 0x9B, 0x16, 0x1A, 0x4F, 0x8B, 0xD3, 0x31, 0xF3, 0xD9, 0x9E, 0x0E, 0x50, 0x0A, 0xA4, 0x01, 0x7E, 0x00, 0x11, 0x40, 0xE7, 0xF9, 0xB1, 0x49, 0xC5, 0xF4, 0x1A, 0xEC, 0xF5, 0xA9, 0x07, 0x38, 0xBD, 0x14, 0xD5, 0x46, 0x2E, 0x62, 0x64, 0xAA, 0x00, 0xB7, 0xF9, 0xD4, 0xFF, 0x6D, 0xF4, 0x70, 0x1A, 0x9E, 0x40, 0x8D, 0xE6, 0x0D, 0x01, 0x9C, 0x80, 0x19, 0x90, 0xA3, 0x56, 0xA5, 0x8D, 0x6C, 0x44, 0x43, 0x1A, 0x06, 0x30, 0x01, 0x3E, 0xFB, 0x19, 0x74, 0x86, 0xD6, 0x65, 0x00, 0x05, 0x44, 0xFD, 0xAE, 0x9D, 0x9E, 0x81, 0x27, 0x26, 0x02, 0x09, 0x2E, 0x1B, 0xD9, 0x05, 0xE8, 0x8E, 0xDA, 0x9A, 0x87, 0xA2, 0x7B, 0x13, 0x96, 0xEA, 0x80, 0xDC, 0x91, 0xCA, 0xD8, 0x42, 0x48, 0x33, 0x3D, 0xE9, 0x01, 0x30, 0xED, 0x9F, 0x33, 0xFB, 0xA1, 0xAC, 0x6A, 0x5D, 0x1B, 0xED, 0x2B, 0x49, 0x7F, 0xF2, 0xD1, 0x08, 0x1D, 0x37, 0x2C, 0xC7, 0x77, 0xC6, 0x01, 0xE8, 0x11, 0x57, 0x72, 0x06, 0xD4, 0x00, 0x09, 0x40, 0x4F, 0x83, 0x00, 0x6B, 0x84, 0x3E, 0xC2, 0x4B, 0xF5, 0x80, 0x81, 0xF3, 0x7E, 0x0B, 0x03, 0x9A, 0x88, 0x59, 0x9D, 0x09, 0x16, 0x6E, 0xB7, 0x52, 0x78, 0x38, 0x14, 0x73, 0xC7, 0x3C, 0x55, 0xDA, 0x53, 0x1F, 0xAE, 0x74, 0xF1, 0x21, 0x5C, 0xA0, 0xDE, 0xA9, 0xE2, 0xF8, 0xA9, 0x44, 0x90, 0x5E, 0x6D, 0x76, 0x12, 0x20, 0x15, 0x70, 0x06, 0xE4, 0x00, 0x87, 0x1B, 0x07, 0x88, 0xE8, 0x35, 0x38, 0xD9, 0xD2, 0xDC, 0xF9, 0xC3, 0xE2, 0xFE, 0x29, 0x1E, 0xCF, 0x44, 0x26, 0xC0, 0x78, 0x6B, 0x48, 0xE7, 0xB2, 0x60, 0xFB, 0x9A, 0x79, 0x00, 0x3D, 0x80, 0x05, 0x10, 0x93, 0xC4, 0x3C, 0x00, 0x25, 0xC0, 0x0D, 0x29, 0x40, 0x03, 0xB0, 0x04, 0xC2, 0x81, 0x8C, 0x59, 0xF3, 0x1D, 0x33, 0x9A, 0x98, 0x35, 0x26, 0xEB, 0x14, 0x18, 0x3F, 0x56, 0x6E, 0x2B, 0x49, 0xC2, 0x1F, 0x19, 0xD2, 0xEF, 0x7C, 0xC7, 0x31, 0xF6, 0xD1, 0xB7, 0x75, 0x9E, 0xBC, 0xC4, 0x84, 0xE0, 0xD9, 0x97, 0x54, 0x01, 0x1E, 0x35, 0x82, 0x86, 0x06, 0xC0, 0x0D, 0x8B, 0xFE, 0xCE, 0xEA, 0xDF, 0x6F, 0xD4, 0x69, 0x08, 0xE0, 0x03, 0x08, 0x3D, 0xBF, 0x98, 0x02, 0xDE, 0x08, 0x01, 0xD2, 0xB7, 0x2C, 0x15, 0x31, 0xC0, 0x01, 0x48, 0xC3, 0x0C, 0x88, 0x46, 0xE9, 0x7E, 0x36, 0x89, 0x01, 0x3E, 0x80, 0x18, 0x60, 0x0C, 0x78, 0x23, 0xB5, 0x63, 0xC6, 0xF0, 0xA7, 0x37, 0x48, 0x33, 0x1D, 0xE1, 0xAF, 0xA9, 0x9B, 0xFB, 0x8B, 0xA6, 0x02, 0xD1, 0x97, 0x28, 0xE8, 0x83, 0x2A, 0x92, 0x30, 0x33, 0x54, 0x7C, 0x5E, 0x45, 0x8E, 0x19, 0xED, 0xF3, 0x78, 0x1C, 0x42, 0xFA, 0x53, 0x35, 0xBC, 0x21, 0x0E, 0x9C, 0x49, 0xD9, 0x0A, 0x3E, 0xF1, 0x9A, 0x31, 0xF1, 0x9B, 0xE1, 0xA9, 0x02, 0xF4, 0x3C, 0x1D, 0xB0, 0x06, 0x38, 0x37, 0xE2, 0x37, 0x50, 0x16, 0x7F, 0xFB, 0xE9, 0x65, 0x72, 0xB5, 0x4F, 0x2E, 0x92, 0x02, 0xE0, 0x02, 0xCC, 0x76, 0xE5, 0xF7, 0x64, 0x63, 0x32, 0x18, 0x01, 0x24, 0x01, 0xC1, 0x8D, 0x69, 0xF4, 0x9D, 0x85, 0x26, 0x5F, 0x13, 0x9F, 0x67, 0xB7, 0x21, 0x50, 0xCF, 0x2C, 0xBA, 0xE1, 0x9F, 0x91, 0x0D, 0xD5, 0x4A, 0xAF, 0xEF, 0x40, 0x4F, 0x52, 0xC8, 0x2B, 0xFA, 0x33, 0x54, 0xAC, 0xEF, 0x78, 0x6C, 0x4D, 0x3B, 0xCA, 0x64, 0x6E, 0x1B, 0x0C, 0x90, 0x3E, 0xDD, 0xC3, 0xD1, 0x38, 0xDB, 0xB4, 0xE2, 0x8E, 0xB6, 0x37, 0x88, 0xB6, 0x7D, 0x99, 0x09, 0x70, 0x72, 0x1B, 0xB3, 0x59, 0xFF, 0x37, 0x9F, 0x21, 0x5B, 0x9D, 0xE7, 0x84, 0xA6, 0xB5, 0x01, 0x88, 0x6B, 0xFB, 0x0C, 0x70, 0xC3, 0x6A, 0xB4, 0xC7, 0x00, 0xCD, 0x86, 0x02, 0x3C, 0x17, 0x7D, 0x07, 0xA2, 0x31, 0x37, 0x02, 0x8B, 0x0E, 0x9A, 0xFE, 0xD1, 0x40, 0xAD, 0xCE, 0xB4, 0x6D, 0xC8, 0xBE, 0xEB, 0x48, 0xF4, 0xA5, 0x6A, 0x0A, 0xF8, 0x84, 0xD1, 0x4A, 0x69, 0x27, 0x37, 0xA6, 0xAD, 0x6F, 0x6B, 0x6F, 0x8D, 0x78, 0x7A, 0xE4, 0x7C, 0xBB, 0x34, 0x89, 0x03, 0x27, 0xB6, 0xC6, 0x9E, 0x1C, 0x80, 0x12, 0x88, 0xA9, 0x7E, 0xDF, 0x0E, 0x80, 0x6A, 0xE8, 0xD2, 0x97, 0x1B, 0x75, 0xE6, 0x2B, 0xC7, 0x2A, 0x40, 0x8C, 0x5B, 0xD2, 0xE4, 0xC7, 0xAD, 0x7E, 0x66, 0x3B, 0x72, 0x11, 0xF1, 0x98, 0x88, 0x13, 0x60, 0x37, 0x93, 0x01, 0x08, 0x01, 0x5C, 0x00, 0xCD, 0xFD, 0x49, 0x80, 0x28, 0xA0, 0xFA, 0x4C, 0xA0, 0x13, 0x34, 0xFB, 0x63, 0x06, 0x31, 0x78, 0xFF, 0x22, 0x33, 0x63, 0xD9, 0x28, 0x0E, 0xF8, 0x21, 0x64, 0xFD, 0x82, 0x27, 0x0F, 0x0A, 0x53, 0x30, 0x8C, 0xF7, 0xC8, 0x93, 0x7C, 0xC4, 0x92, 0xDE, 0x23, 0xBB, 0x75, 0xB6, 0x17, 0x5B, 0x19, 0x10, 0x0C, 0x98, 0x01, 0xAA, 0x8D, 0xEA, 0xEF, 0x7C, 0x2C, 0xE0, 0xE2, 0x01, 0x4D, 0x92, 0xAE, 0xA1, 0x09, 0x50, 0x01, 0x77, 0x68, 0x2C, 0x76, 0x41, 0x9F, 0x6A, 0xDB, 0x15, 0x18, 0x3D, 0xF5, 0xCE, 0x7C, 0xAA, 0x98, 0x16, 0x40, 0x32, 0x10, 0xF9, 0xB4, 0x80, 0x24, 0x20, 0x02, 0xA8, 0x02, 0x25, 0x1D, 0x35, 0xF8, 0xF8, 0xBB, 0xE6, 0xE7, 0xDC, 0xE0, 0x22, 0xD0, 0x80, 0x61, 0x81, 0x5D, 0xAA, 0x74, 0x11, 0x03, 0x7B, 0x5B, 0x95, 0x7A, 0xAB, 0x02, 0xD7, 0xB2, 0xBB, 0xD0, 0x7A, 0x52, 0xB6, 0x36, 0xCD, 0x8E, 0x0D, 0xB3, 0x06, 0x01, 0x72, 0x80, 0x49, 0x1F, 0x95, 0xEF, 0xAE, 0xBA, 0x69, 0xF3, 0x70, 0xDA, 0x32, 0x99, 0x71, 0xB6, 0xC3, 0x9A, 0xFA, 0xEE, 0xED, 0xD4, 0x86, 0xF8, 0xCE, 0xD5, 0x06, 0x3F, 0x15, 0xE0, 0xF4, 0x3D, 0x35, 0x6A, 0x0D, 0xD7, 0x9D, 0x81, 0x13, 0x05, 0x2C, 0x1B, 0x06, 0xA8, 0x00, 0xAC, 0x00, 0x19, 0xC0, 0x02, 0xC4, 0xBC, 0x09, 0xE2, 0x8F, 0x17, 0xCC, 0xDB, 0xF2, 0x5B, 0x41, 0xB3, 0xD4, 0xFA, 0x46, 0x42, 0x8A, 0xC2, 0x5A, 0x04, 0x56, 0x01, 0x39, 0x56, 0x88, 0xED, 0xB1, 0x75, 0x7D, 0x3D, 0x3D, 0xDF, 0x41, 0x4F, 0x4E, 0x80, 0x7C, 0x4F, 0x90, 0x85, 0x00, 0x16, 0x8D, 0x69, 0x92, 0xE4, 0x27, 0xC9, 0x6F, 0x53, 0x82, 0xD9, 0x2E, 0x83, 0xC6, 0x00, 0xEB, 0x5E, 0xBD, 0xD5, 0x5F, 0xF4, 0xDA, 0xF3, 0xDF, 0x1A, 0x4F, 0x4F, 0x68, 0x00, 0xFE, 0x54, 0xAC, 0x8E, 0x00, 0x5A, 0x40, 0x44, 0x83, 0x00, 0x13, 0x80, 0x0D, 0x38, 0xFC, 0x78, 0x7A, 0x4E, 0x2B, 0x7C, 0xA1, 0xD5, 0x45, 0xE8, 0x7C, 0x20, 0x8F, 0xF5, 0x7C, 0xD2, 0xF1, 0x2E, 0x65, 0x30, 0x3A, 0x80, 0xB8, 0x2D, 0xB4, 0xF4, 0xAC, 0xE2, 0x80, 0x4F, 0xD0, 0xA8, 0x83, 0x26, 0x37, 0x4C, 0x80, 0x10, 0xC0, 0x06, 0x9C, 0x47, 0xCD, 0x20, 0x12, 0x48, 0x7F, 0x46, 0x17, 0xA7, 0x67, 0xDF, 0x1A, 0xBC, 0x07, 0x2F, 0x29, 0xB6, 0xCE, 0x2D, 0x33, 0x70, 0x0C, 0x70, 0xD9, 0x4D, 0xCF, 0x61, 0xBB, 0xB0, 0xA7, 0x09, 0x58, 0xC3, 0x6B, 0xD7, 0x46, 0xA5, 0xE1, 0x0C, 0x98, 0x01, 0x52, 0x00, 0xAD, 0xDC, 0x69, 0xDE, 0xB2, 0x85, 0x9F, 0x09, 0x5A, 0xFD, 0x89, 0x3E, 0x87, 0xC4, 0xF7, 0x8B, 0xD9, 0x9F, 0x32, 0x94, 0xCF, 0x39, 0xBF, 0xA6, 0x2A, 0xF4, 0x5E, 0xC8, 0x07, 0xCA, 0xE2, 0x2E, 0x1F, 0xE9, 0x3C, 0x9E, 0xCF, 0x9B, 0xA0, 0x23, 0xA2, 0x33, 0xE7, 0x47, 0x80, 0x27, 0x60, 0x05, 0x88, 0xED, 0x80, 0x9E, 0xD3, 0x78, 0x96, 0x0A, 0xC5, 0x0E, 0x9A, 0x74, 0xD0, 0xC4, 0x77, 0xBB, 0xE9, 0x34, 0xC0, 0xB9, 0x01, 0x5A, 0xBF, 0x4E, 0x58, 0xBB, 0xFF, 0x9F, 0xFB, 0x0E, 0x9A, 0x29, 0xE0, 0x01, 0xC4, 0x44, 0x84, 0x00, 0x6F, 0x94, 0x00, 0x19, 0x80, 0x37, 0xC4, 0x01, 0x6A, 0x70, 0xA3, 0x14, 0x41, 0xCB, 0xB9, 0x9A, 0x7A, 0xCB, 0x12, 0x11, 0x5A, 0x1F, 0x83, 0xA8, 0x7D, 0xEB, 0xA3, 0x33, 0xAF, 0xD6, 0x3A, 0x68, 0x89, 0xD7, 0x57, 0xC8, 0xD4, 0xD4, 0x9F, 0x16, 0xAB, 0x8E, 0x4F, 0xC5, 0xB5, 0x3E, 0xDD, 0x4D, 0x72, 0xD3, 0x47, 0x57, 0x0E, 0xA8, 0xCC, 0x8E, 0xBC, 0xDA, 0xBE, 0x42, 0xCE, 0x9E, 0x2E, 0x93, 0xDA, 0xFF, 0x5F, 0x36, 0xAC, 0xA1, 0x07, 0xA0, 0x04, 0xA6, 0xDC, 0x2B, 0x6B, 0x80, 0x08, 0xB1, 0x6F, 0x09, 0xE8, 0xDD, 0x9D, 0x24, 0x06, 0x58, 0x02, 0x69, 0x9D, 0x8B, 0x72, 0x40, 0xAC, 0x11, 0x0D, 0x6F, 0x9C, 0x06, 0x03, 0xDA, 0x48, 0xEA, 0xA0, 0xCD, 0x8D, 0x60, 0xBC, 0xD0, 0x19, 0x49, 0x13, 0x42, 0xA7, 0x95, 0x57, 0xB5, 0x4F, 0x0A, 0xE3, 0x2F, 0xA0, 0xE8, 0x53, 0x22, 0x32, 0x69, 0xAF, 0x74, 0xDA, 0x3D, 0x85, 0xF1, 0x3D, 0x4A, 0xAE, 0xD9, 0x38, 0xF9, 0x9B, 0xAD, 0x57, 0x60, 0x22, 0x99, 0x8D, 0x58, 0x3B, 0xF2, 0x08, 0x47, 0xDA, 0x15, 0x74, 0xD5, 0x00, 0xA4, 0x36, 0xB4, 0x61, 0x09, 0xD4, 0x87, 0x9C, 0xBC, 0xF5, 0x2D, 0x55, 0x89, 0x8F, 0x2B, 0x4D, 0x1B, 0xDF, 0x07, 0x50, 0xD2, 0xD7, 0xAF, 0x03, 0xA8, 0x00, 0x4E, 0x8D, 0x02, 0x22, 0x81, 0x0C, 0xA0, 0xBA, 0xE1, 0x86, 0x18, 0x60, 0x01, 0xEE, 0x4A, 0xE3, 0xD6, 0xAE, 0x32, 0x24, 0x35, 0x52, 0xD0, 0xCC, 0xA1, 0x8A, 0xE2, 0x94, 0x3B, 0xCE, 0x36, 0xA7, 0x3E, 0x90, 0x32, 0xCA, 0xD0, 0x86, 0x60, 0x9D, 0x57, 0x67, 0x68, 0x1E, 0xBA, 0x58, 0xDB, 0xC2, 0xEF, 0xAD, 0x1D, 0x02, 0x68, 0x83, 0x64, 0xDC, 0x31, 0x01, 0x9A, 0xEF, 0xF4, 0x8E, 0x9D, 0x4F, 0xE7, 0x1C, 0x90, 0xB1, 0x05, 0x84, 0x83, 0x00, 0x8A, 0xC7, 0x15, 0x31, 0x77, 0x8D, 0x21, 0xA7, 0xCD, 0x4C, 0xB6, 0x91, 0xAE, 0x15, 0x10, 0x8D, 0x89, 0x32, 0x0B, 0x60, 0x09, 0x84, 0x37, 0xB2, 0x41, 0x80, 0x37, 0xAC, 0xE1, 0xA3, 0x07, 0x2D, 0x1D, 0x34, 0xE9, 0xC7, 0xD3, 0x91, 0x89, 0xA3, 0xC4, 0x54, 0xAC, 0x18, 0x2E, 0x5C, 0x9D, 0xB3, 0xB5, 0xE3, 0xBD, 0x78, 0xBD, 0x57, 0xC8, 0xB7, 0x34, 0x8B, 0xDE, 0x92, 0xCA, 0x6D, 0x7E, 0x9F, 0x76, 0xD5, 0x9C, 0x6A, 0x98, 0x00, 0x2A, 0x93, 0x60, 0x07, 0x44, 0x76, 0x0C, 0x94, 0x7E, 0x15, 0x00, 0xEB, 0x27, 0x31, 0x1A, 0x79, 0x2D, 0xEB, 0xA4, 0x43, 0x11, 0x07, 0xA0, 0xDA, 0x9D, 0xE2, 0x93, 0xF9, 0xDD, 0x6E, 0x58, 0x28, 0x12, 0x20, 0xED, 0xE6, 0x7B, 0x51, 0xA5, 0x6D, 0xA5, 0x5B, 0x2D, 0xA0, 0x78, 0x7B, 0x23, 0x91, 0x37, 0xCE, 0x74, 0x24, 0x01, 0x59, 0x40, 0xCD, 0xE8, 0x69, 0x74, 0xD0, 0x14, 0xC9, 0xD3, 0xA8, 0x3F, 0xF6, 0x15, 0x43, 0xE3, 0x3B, 0xAE, 0x9D, 0x48, 0x08, 0x8C, 0x71, 0xB6, 0x57, 0x32, 0xA2, 0x55, 0x27, 0x70, 0xAB, 0x89, 0xE7, 0x45, 0xE0, 0x6B, 0x26, 0x4A, 0xFE, 0x16, 0x4A, 0xEE, 0x24, 0x58, 0x43, 0x81, 0xF3, 0xBC, 0xA3, 0xE6, 0x82, 0x90, 0xFD, 0x49, 0xD6, 0xD0, 0x3A, 0xAE, 0x78, 0x00, 0xC7, 0xDE, 0xCC, 0x68, 0x5F, 0x10, 0xCC, 0x00, 0xFF, 0x70, 0xEF, 0x8B, 0x72, 0x1B, 0x2F, 0xAB, 0x43, 0x6F, 0xCF, 0xA6, 0xE4, 0x09, 0x8C, 0xB0, 0x33, 0x37, 0xCC, 0x81, 0xA8, 0x46, 0x34, 0x0E, 0x60, 0x01, 0x68, 0x01, 0x96, 0x40, 0x59, 0x07, 0xCD, 0xA0, 0xC8, 0x9C, 0x70, 0xBE, 0xC0, 0x84, 0xD4, 0xB7, 0x8E, 0x0A, 0x17, 0x7D, 0xF2, 0xD9, 0x92, 0x66, 0x56, 0x10, 0xB7, 0x3E, 0x92, 0xDD, 0x0A, 0xEF, 0x6B, 0xFA, 0x4E, 0xEE, 0xC8, 0xD1, 0x9D, 0x83, 0xAD, 0x86, 0xEE, 0x06, 0x65, 0x3B, 0x00, 0x45, 0x83, 0x81, 0xEA, 0x80, 0xDE, 0xF3, 0x7A, 0xD6, 0x63, 0x2F, 0xE8, 0x08, 0x53, 0x9E, 0xD5, 0xFA, 0x18, 0x0E, 0xE4, 0x04, 0x4D, 0xEA, 0xD7, 0xEA, 0xED, 0x77, 0x0B, 0x27, 0xEA, 0x27, 0xAA, 0x00, 0x23, 0x20, 0x62, 0xFB, 0xB5, 0xB9, 0x02, 0x35, 0x38, 0x40, 0x36, 0xCC, 0x01, 0x25, 0xC0, 0x26, 0x87, 0x3F, 0x7B, 0xDA, 0x54, 0x07, 0x3A, 0x99, 0xE3, 0x3A, 0x49, 0x99, 0xB6, 0xB4, 0xD7, 0x4E, 0xD8, 0x50, 0xE7, 0x1E, 0x6D, 0x1E, 0x0F, 0xD4, 0xD2, 0x9F, 0x74, 0x9A, 0x7D, 0xB0, 0xB9, 0x32, 0xDB, 0xFD, 0xDB, 0x63, 0x52, 0xDD, 0x3F, 0x4F, 0x17, 0xAA, 0x6B, 0xA3, 0x55, 0x09, 0xD8, 0x08, 0xF8, 0xCD, 0x4F, 0x76, 0x37, 0x72, 0x20, 0x03, 0xB0, 0xB7, 0xAF, 0x51, 0x81, 0xE0, 0x5F, 0x27, 0xE3, 0xE4, 0xD8, 0xFA, 0x0F, 0x13, 0xBA, 0x1A, 0xA1, 0x1C, 0xA7, 0xCB, 0xB6, 0x6D, 0x61, 0x44, 0x80, 0xC5, 0x76, 0x8D, 0xA2, 0x06, 0x0B, 0x20, 0x0C, 0x68, 0xC3, 0x0C, 0x88, 0xD3, 0x48, 0xA0, 0xAA, 0x63, 0x16, 0x3D, 0x59, 0x6B, 0x2D, 0x62, 0x22, 0xED, 0xB3, 0xD6, 0xCA, 0x4C, 0x6A, 0x48, 0x05, 0x4A, 0x62, 0xD7, 0x4B, 0x6A, 0xD7, 0xB5, 0xEA, 0x7E, 0x64, 0xC4, 0x4C, 0x57, 0xCC, 0xA6, 0x39, 0x85, 0x70, 0x9E, 0x5C, 0xBD, 0x99, 0xD9, 0xA0, 0x0E, 0x01, 0x4F, 0xFB, 0x44, 0x3C, 0x8D, 0x16, 0x35, 0xBE, 0x44, 0x4F, 0x9A, 0xDF, 0x77, 0x8A, 0x5C, 0x7D, 0x9B, 0x47, 0x15, 0xFF, 0x2A, 0x6A, 0x9D, 0xA8, 0x65, 0xBB, 0x5B, 0x92, 0x4F, 0xC6, 0x8D, 0x76, 0x1E, 0x2D, 0x6C, 0xDB, 0x34, 0x48, 0x23, 0x08, 0x48, 0x07, 0x8A, 0x1A, 0x07, 0xC8, 0x02, 0x4A, 0xB6, 0xA2, 0xB2, 0x64, 0xC7, 0xAC, 0xBB, 0xA8, 0x8A, 0xB1, 0x9D, 0xCE, 0x7A, 0x8E, 0x40, 0x32, 0x4E, 0x13, 0x49, 0xF4, 0xA3, 0x1F, 0x28, 0xBC, 0x0B, 0x2C, 0xF6, 0xC5, 0xCC, 0xDE, 0x54, 0xF7, 0x3C, 0x8D, 0xB4, 0xCC, 0x29, 0xA3, 0x17, 0x58, 0x22, 0x4A, 0xD3, 0x19, 0x8A, 0x9D, 0x17, 0x98, 0x46, 0x6D, 0x67, 0xA0, 0x26, 0x4B, 0x39, 0xAA, 0xD9, 0xD6, 0x29, 0x48, 0xE9, 0x4F, 0x0D, 0x2D, 0x40, 0xF4, 0x11, 0xDD, 0x16, 0x7C, 0xE7, 0x24, 0x08, 0xCB, 0xBA, 0xE9, 0xB4, 0x73, 0xE3, 0xD6, 0x1E, 0x59, 0xAA, 0x40, 0x72, 0xAF, 0x2C, 0x01, 0x34, 0x80, 0x28, 0xA0, 0xB4, 0x8D, 0xC8, 0xB8, 0x11, 0x00, 0x39, 0xC0, 0x0A, 0x48, 0x01, 0x3E, 0x31, 0xAB, 0x1E, 0x02, 0xE2, 0x29, 0xEB, 0xE0, 0xFB, 0xAB, 0xA3, 0xEA, 0xD1, 0xE5, 0x19, 0x05, 0x2C, 0xDA, 0xE4, 0x05, 0xA9, 0x6E, 0xEE, 0x98, 0xF9, 0xB2, 0xBF, 0xB3, 0x59, 0x67, 0x7A, 0x27, 0x26, 0x44, 0x80, 0x2C, 0xC0, 0x0F, 0x70, 0xA6, 0xB8, 0x6B, 0x80, 0xD2, 0x7C, 0xE7, 0x78, 0xE2, 0xFD, 0x0A, 0x41, 0x3A, 0x2D, 0xCB, 0xB7, 0x5C, 0x59, 0x02, 0x70, 0xF6, 0x8A, 0xDC, 0x0B, 0x13, 0x58, 0x9D, 0xBD, 0xB9, 0x45, 0x20, 0xA5, 0x1E, 0x77, 0xC0, 0x49, 0x6E, 0x33, 0x60, 0x05, 0xC4, 0x20, 0x1A, 0x0C, 0xB8, 0x3E, 0xDF, 0x32, 0xE5, 0x9D, 0x40, 0xCC, 0xDA, 0xB7, 0xDF, 0x35, 0x7B, 0x81, 0xE1, 0x69, 0xA4, 0x74, 0xCC, 0x92, 0x65, 0x60, 0x7B, 0xB1, 0xAE, 0xE0, 0x05, 0x21, 0xB9, 0xE4, 0x71, 0x93, 0x67, 0x38, 0xA8, 0xEF, 0xF2, 0x80, 0x4D, 0xCC, 0xC6, 0xA2, 0x76, 0xDE, 0x3D, 0x44, 0xDB, 0xD3, 0x96, 0x68, 0xC7, 0x8C, 0x1B, 0x3E, 0x67, 0xED, 0xE9, 0xEF, 0xA6, 0xC7, 0xB5, 0x2D, 0x01, 0xA9, 0x07, 0x01, 0xF8, 0x2D, 0xB9, 0x23, 0xBA, 0x3A, 0x85, 0x84, 0x39, 0x58, 0x14, 0x90, 0xDA, 0x6B, 0x5E, 0x00, 0x29, 0xC0, 0x05, 0x48, 0x07, 0x2A, 0xBB, 0x9E, 0x60, 0x00, 0x31, 0xC0, 0xD4, 0x28, 0x40, 0x0D, 0x70, 0xE9, 0x98, 0x41, 0x40, 0x42, 0xF4, 0x60, 0x20, 0x96, 0xFE, 0x26, 0x38, 0xEC, 0x2B, 0x20, 0x28, 0x86, 0x4E, 0xA9, 0x30, 0xF2, 0x58, 0x0A, 0xA3, 0x21, 0xCF, 0xF1, 0xA8, 0x7F, 0x12, 0x1C, 0xB4, 0xA5, 0x03, 0x23, 0x80, 0x3A, 0xFB, 0x93, 0x31, 0xC0, 0x09, 0xD0, 0x79, 0x84, 0x16, 0x13, 0x88, 0x71, 0x8E, 0x22, 0x7C, 0x4A, 0x7E, 0xE4, 0xB8, 0xAC, 0x51, 0x8D, 0xD8, 0xD7, 0x5C, 0x9B, 0x8A, 0xCE, 0x1C, 0x64, 0x3A, 0xC7, 0xAD, 0xE7, 0xCD, 0x9A, 0x3D, 0x99, 0xEB, 0x9A, 0x3B, 0x9A, 0x02, 0x16, 0x0D, 0x6F, 0x1C, 0x40, 0x02, 0xE0, 0x02, 0x24, 0x81, 0x3C, 0x1D, 0x34, 0x94, 0x02, 0xBE, 0x04, 0x59, 0x1C, 0xAC, 0x29, 0x94, 0x09, 0x04, 0x5B, 0x82, 0x17, 0x3A, 0x52, 0xC4, 0xD1, 0x2D, 0xA9, 0x85, 0x5E, 0xBD, 0xF2, 0x3D, 0x6F, 0xA1, 0xCF, 0xE0, 0xDD, 0x99, 0x0C, 0xF4, 0x1C, 0x2C, 0x08, 0x50, 0x05, 0xCE, 0x9D, 0xE6, 0x04, 0x78, 0x0E, 0xC2, 0xDA, 0x9F, 0x46, 0x35, 0x41, 0x27, 0x33, 0xB6, 0xC7, 0xA8, 0x8E, 0xEE, 0xE4, 0xB6, 0x04, 0x70, 0x9E, 0xCB, 0xBD, 0xC4, 0xEA, 0xD2, 0x42, 0xD6, 0x1F, 0x57, 0xB5, 0x03, 0x94, 0xCC, 0x7D, 0x01, 0x50, 0x07, 0x72, 0x1A, 0xAB, 0x0E, 0x60, 0xD5, 0x48, 0x40, 0x9F, 0xFC, 0xEE, 0x31, 0x80, 0x12, 0x08, 0xEB, 0xA0, 0xC9, 0x1F, 0xFF, 0x8A, 0x24, 0x0E, 0x41, 0x2B, 0xB7, 0xD5, 0x67, 0x7B, 0x1C, 0x96, 0x5A, 0xAE, 0x8C, 0x79, 0x5F, 0x9F, 0x4E, 0x5A, 0x59, 0xB6, 0xEB, 0xE6, 0x4F, 0x82, 0x43, 0x7C, 0xCF, 0xFA, 0x4B, 0x00, 0xFC, 0xE4, 0x6E, 0xFD, 0x91, 0xCB, 0x13, 0x01, 0xEC, 0x6C, 0x61, 0x05, 0xEE, 0x2F, 0xCE, 0x1F, 0x9D, 0x0C, 0x58, 0x02, 0x4E, 0x80, 0x15, 0x80, 0xB8, 0xCA, 0x0D, 0xE1, 0x9D, 0x8E, 0x8C, 0x7F, 0xAD, 0x34, 0x4D, 0xC0, 0xA7, 0x7E, 0xA2, 0xCF, 0xB4, 0xE2, 0x40, 0x01, 0x0F, 0x40, 0x1A, 0x64, 0x80, 0x1C, 0x20, 0xAB, 0x83, 0xA6, 0xA8, 0x04, 0x1F, 0x74, 0x76, 0x4B, 0x40, 0xF4, 0x85, 0x8E, 0xF7, 0x3C, 0x76, 0xC2, 0x7E, 0x9A, 0x12, 0x0D, 0x51, 0xC4, 0x5D, 0x3A, 0xE2, 0xF7, 0xDA, 0xB9, 0x83, 0x16, 0xBC, 0x47, 0x84, 0xA5, 0x31, 0x33, 0xB3, 0x45, 0x80, 0x25, 0xC0, 0x0E, 0x10, 0xEF, 0x14, 0xB7, 0xD4, 0x16, 0x90, 0xE4, 0xDA, 0x9D, 0xB5, 0x26, 0x8F, 0x45, 0x5E, 0x02, 0xD3, 0xE6, 0x9D, 0x1D, 0x26, 0xB9, 0xC3, 0x58, 0xBC, 0x5B, 0xE2, 0x6A, 0xB6, 0x59, 0x05, 0x34, 0x80, 0x98, 0xFA, 0x80, 0x03, 0x6C, 0x0D, 0x6F, 0x30, 0x40, 0x0E, 0x9C, 0x02, 0x98, 0x00, 0xD3, 0x0E, 0x9A, 0xFD, 0xB1, 0xEE, 0x38, 0x4B, 0xD9, 0xF2, 0x5F, 0x38, 0x04, 0x06, 0xA4, 0x29, 0x0C, 0x0A, 0xAD, 0x9A, 0xD4, 0x69, 0x7D, 0x5B, 0x59, 0x21, 0xCF, 0x67, 0x6C, 0x5D, 0xCE, 0x23, 0x56, 0x55, 0x00, 0xE5, 0xEE, 0x4A, 0x8E, 0x86, 0x79, 0x43, 0x81, 0xF2, 0x9D, 0xFE, 0x4E, 0x01, 0x4C, 0xF6, 0xDC, 0xB9, 0xFA, 0xB3, 0x7A, 0x05, 0xC0, 0x6A, 0xD2, 0xBB, 0xC4, 0xC8, 0xEF, 0x94, 0xEC, 0x24, 0xFD, 0xE7, 0x12, 0x03, 0x64, 0x75, 0x79, 0xAA, 0xA1, 0x02, 0x14, 0xEF, 0xF2, 0x14, 0x39, 0x30, 0x6E, 0x00, 0xF1, 0x24, 0x05, 0xE2, 0xB6, 0x21, 0x76, 0xD0, 0xFC, 0x6B, 0xE5, 0x56, 0x93, 0x3F, 0xE9, 0x38, 0x8F, 0xD5, 0x57, 0x5B, 0x0F, 0xA8, 0x4F, 0x17, 0x43, 0xE0, 0x82, 0x03, 0x9B, 0x59, 0x1A, 0xCC, 0x12, 0xF4, 0xEC, 0x59, 0xFF, 0x37, 0x69, 0x7B, 0xFD, 0xD6, 0x04, 0x70, 0x03, 0xEC, 0x09, 0xE1, 0xF1, 0xDD, 0x06, 0x1F, 0x31, 0x71, 0xDD, 0x3E, 0xFF, 0xC9, 0x80, 0xF8, 0x4E, 0x71, 0x93, 0xED, 0x3A, 0x4D, 0x36, 0x8A, 0x7E, 0xC1, 0xF6, 0xBF, 0x57, 0xD9, 0xD8, 0x4E, 0xD0, 0x2A, 0x80, 0x07, 0x90, 0x72, 0x2B, 0xA0, 0xCF, 0xC3, 0x7A, 0xCB, 0xE3, 0x40, 0x28, 0xA0, 0x0D, 0x26, 0x40, 0x04, 0xA8, 0x39, 0x71, 0xA0, 0xB9, 0x05, 0x32, 0x26, 0x7D, 0xD4, 0x8B, 0xEF, 0xB6, 0x12, 0x50, 0x01, 0x1F, 0xC7, 0x98, 0x48, 0x58, 0xE9, 0x78, 0x3F, 0x4F, 0x3A, 0xE3, 0xEA, 0xEF, 0x30, 0x31, 0xCF, 0xBE, 0xD5, 0xFB, 0xB3, 0x00, 0x99, 0x80, 0x17, 0xC0, 0xB1, 0xB5, 0x8E, 0x94, 0x00, 0x32, 0x40, 0x72, 0x1B, 0x76, 0xA6, 0x00, 0xF6, 0x98, 0xB7, 0x39, 0x35, 0xAC, 0x31, 0xA9, 0xF1, 0x79, 0x3C, 0xF7, 0x70, 0x8E, 0xFE, 0xF5, 0x87, 0x9E, 0x06, 0xC2, 0x04, 0x5C, 0x81, 0xE9, 0x69, 0x13, 0x02, 0xA2, 0x51, 0xD2, 0x50, 0x20, 0x03, 0x08, 0x01, 0x3C, 0x80, 0xEE, 0x16, 0x9F, 0xB9, 0xD8, 0xA5, 0x05, 0x6C, 0x85, 0xB3, 0x3E, 0xEE, 0x01, 0xF2, 0xE5, 0x1F, 0x99, 0xAD, 0xE7, 0x27, 0xAB, 0x17, 0xA8, 0xA2, 0xF4, 0x28, 0x32, 0xB3, 0x3D, 0xBB, 0xC5, 0x6A, 0x22, 0xA2, 0xBE, 0x7E, 0x7A, 0xE8, 0xE3, 0xB5, 0x14, 0x3F, 0x30, 0x35, 0x6C, 0x9A, 0x1B, 0x38, 0xAF, 0x1C, 0x08, 0x05, 0x20, 0x02, 0x58, 0x01, 0x53, 0x2F, 0xF6, 0x86, 0x26, 0xE0, 0x04, 0x84, 0xAC, 0x71, 0xF7, 0x99, 0xBC, 0xF1, 0xB9, 0xBD, 0xDE, 0x8E, 0xA9, 0x98, 0x31, 0xB0, 0x69, 0x8F, 0x20, 0x60, 0x2C, 0xCB, 0x4E, 0x83, 0x13, 0x90, 0x86, 0x1A, 0x60, 0x0E, 0x78, 0x23, 0x02, 0x48, 0x03, 0xCA, 0x3B, 0x68, 0x85, 0x74, 0x79, 0x40, 0x07, 0x92, 0x89, 0x71, 0x6A, 0x66, 0x47, 0x87, 0x1C, 0xF7, 0xAC, 0x5D, 0x59, 0x7B, 0x38, 0x16, 0x9E, 0x78, 0x8D, 0xDD, 0xFE, 0xB8, 0x83, 0x86, 0x9D, 0x7C, 0x9A, 0xD5, 0xB7, 0x77, 0xB5, 0x8D, 0x1B, 0x7F, 0x6F, 0xB0, 0x65, 0xBB, 0x9D, 0x55, 0xB5, 0x11, 0xB3, 0x07, 0x8F, 0xC0, 0x79, 0xA3, 0xFF, 0x07, 0x6D, 0x30, 0x35, 0xB4, 0x21, 0x80, 0xE7, 0xF4, 0x52, 0xF6, 0xF5, 0x20, 0x7E, 0x1A, 0x6B, 0xB8, 0x05, 0xAD, 0xA3, 0xBC, 0x12, 0x90, 0xD3, 0x32, 0xE5, 0x80, 0x2B, 0x90, 0x02, 0x14, 0x35, 0xA2, 0xCF, 0x0E, 0x0C, 0x10, 0x01, 0x6C, 0x40, 0x57, 0xD7, 0xEF, 0x6E, 0xA9, 0x08, 0x9A, 0x96, 0xCF, 0xF0, 0x40, 0x4B, 0x4D, 0x44, 0x0B, 0x38, 0xE0, 0x9E, 0xC5, 0xC9, 0xB0, 0x54, 0x33, 0x5F, 0xBD, 0x7C, 0x71, 0x63, 0xF6, 0x78, 0x84, 0xD0, 0x34, 0x03, 0x14, 0x90, 0x0A, 0x88, 0xCC, 0x30, 0x06, 0xC0, 0x67, 0xCF, 0x76, 0x69, 0x8D, 0x1B, 0xDE, 0x98, 0x3E, 0x4D, 0x94, 0x76, 0xF7, 0xBE, 0x5A, 0xE3, 0x00, 0xD2, 0xF0, 0x49, 0x7B, 0xD3, 0xCF, 0x85, 0x5F, 0x6E, 0xDE, 0xF1, 0xDE, 0x04, 0x12, 0x88, 0xE8, 0x40, 0x2A, 0x60, 0x04, 0xA4, 0x6F, 0x13, 0x46, 0x3A, 0x8D, 0x68, 0x38, 0xC0, 0x04, 0x48, 0x00, 0x41, 0x1D, 0x33, 0xEA, 0x8C, 0x6F, 0x7D, 0xA7, 0xB5, 0x64, 0xFD, 0x5E, 0xA5, 0x15, 0xD4, 0x8D, 0x37, 0xD9, 0x57, 0xC5, 0xC2, 0x8F, 0xA9, 0xDA, 0x75, 0x19, 0x18, 0xFC, 0xD7, 0x3B, 0x70, 0x71, 0xA5, 0x58, 0xFC, 0x3E, 0x6C, 0xFB, 0x30, 0x3D, 0xCE, 0x9E, 0x3A, 0x83, 0x74, 0x4F, 0x32, 0x32, 0x81, 0x9A, 0x9D, 0x78, 0x1E, 0x60, 0xB1, 0x1D, 0x57, 0x49, 0xE0, 0x48, 0x83, 0xB6, 0xE4, 0x99, 0xF6, 0xAB, 0x0D, 0xBB, 0xD0, 0x3C, 0x42, 0x3C, 0x42, 0x1E, 0xF7, 0x5E, 0x2F, 0xB2, 0xDB, 0x8E, 0x7C, 0x9A, 0x89, 0x1C, 0x70, 0x05, 0x8A, 0x1A, 0xB2, 0x3F, 0xA5, 0x6C, 0x14, 0x4F, 0x66, 0xA4, 0x83, 0x76, 0xC7, 0xD5, 0x11, 0xAD, 0xA4, 0x4F, 0x77, 0x34, 0x28, 0xDA, 0xC4, 0xBD, 0xB0, 0xD0, 0x0E, 0x75, 0x6A, 0x39, 0x50, 0xE8, 0xE2, 0xDA, 0xD2, 0xB6, 0x6F, 0x49, 0x65, 0x7A, 0x01, 0xF2, 0x03, 0xD6, 0x16, 0x30, 0xC7, 0x43, 0x95, 0xE5, 0x8A, 0x3A, 0x07, 0x50, 0x53, 0x20, 0x76, 0xFF, 0x06, 0x06, 0x68, 0x00, 0x01, 0x24, 0x01, 0x56, 0x40, 0x0F, 0x60, 0x23, 0xAB, 0xA9, 0xBD, 0xE0, 0xC6, 0x62, 0x4F, 0xA6, 0x83, 0xB8, 0xD7, 0xD6, 0xF3, 0x74, 0x9A, 0xEE, 0xBE, 0x46, 0x09, 0xC0, 0x19, 0x88, 0x41, 0x02, 0x19, 0x40, 0xD5, 0xD3, 0x8A, 0x98, 0x80, 0x58, 0x07, 0x4D, 0x96, 0xD8, 0x4B, 0x84, 0xE2, 0xF9, 0xFD, 0x9E, 0xD5, 0xB8, 0x6E, 0x81, 0x2E, 0xD5, 0xD2, 0x00, 0xD6, 0xFF, 0xE0, 0x18, 0xF5, 0xD7, 0x77, 0x47, 0xCB, 0x7B, 0x6E, 0x9D, 0x72, 0xDB, 0xC8, 0xEF, 0x35, 0x68, 0x6E, 0x33, 0x00, 0xF9, 0x8E, 0x60, 0x0D, 0x3A, 0x58, 0x53, 0xA9, 0x52, 0xDE, 0x38, 0xD4, 0x11, 0xA4, 0xFE, 0x24, 0x00, 0x29, 0x30, 0x23, 0x00, 0xE3, 0x47, 0x98, 0xCB, 0xAB, 0x50, 0x6E, 0xFD, 0x29, 0x1F, 0xA3, 0xAC, 0xAB, 0x26, 0xE3, 0x00, 0x07, 0x20, 0x0E, 0xA8, 0x01, 0xC6, 0x80, 0x0B, 0x10, 0x0A, 0xA4, 0xF4, 0xEB, 0xE3, 0x74, 0xCC, 0xB4, 0x3B, 0x50, 0x31, 0xAC, 0x48, 0x84, 0x7E, 0x21, 0xB7, 0x16, 0xCF, 0xA9, 0xA9, 0xAB, 0x25, 0xFA, 0x85, 0x5C, 0xFA, 0x30, 0x50, 0x73, 0xE3, 0x7C, 0x04, 0xD3, 0x6C, 0x4F, 0xF6, 0xB8, 0xEF, 0xF6, 0x8B, 0x92, 0xA7, 0x0B, 0x43, 0x00, 0x3D, 0x00, 0x01, 0xFD, 0x29, 0x6E, 0x55, 0x5B, 0xCF, 0x9E, 0xBB, 0x53, 0x03, 0x4E, 0xED, 0x26, 0x8E, 0x2D, 0x0B, 0x94, 0x7F, 0x0D, 0xB6, 0x64, 0xA4, 0x62, 0xA4, 0x43, 0x38, 0x95, 0x23, 0x03, 0xAC, 0x80, 0xD1, 0x47, 0x11, 0x02, 0xC2, 0x11, 0xE5, 0x43, 0x0D, 0x9E, 0x61, 0x01, 0x20, 0x05, 0x88, 0xDC, 0x3E, 0xDA, 0xCA, 0x1D, 0xB4, 0x9F, 0xFA, 0xE3, 0xB7, 0xD7, 0x2A, 0x32, 0x24, 0x87, 0x60, 0xC1, 0x35, 0x2D, 0xDD, 0x84, 0xBE, 0xE4, 0x91, 0xE5, 0x68, 0x61, 0xD2, 0x9A, 0xA7, 0x33, 0x6D, 0x69, 0x4A, 0xD8, 0x98, 0xB9, 0xCA, 0x28, 0x47, 0xDF, 0x19, 0xBB, 0xCC, 0x2E, 0x63, 0xDE, 0xF9, 0x90, 0xAD, 0x5A, 0x6B, 0x01, 0x08, 0x01, 0x56, 0xFB, 0x44, 0xEE, 0xBA, 0x47, 0x7D, 0x23, 0x81, 0xF2, 0x7D, 0xAE, 0x8F, 0x0E, 0xD3, 0x75, 0x08, 0xF7, 0x59, 0x23, 0xBD, 0x19, 0x75, 0x57, 0xAE, 0x8C, 0xA9, 0xAB, 0x6D, 0x1F, 0x32, 0x71, 0xC0, 0x05, 0x88, 0x04, 0x32, 0x80, 0x69, 0xF8, 0x25, 0x06, 0x58, 0x01, 0x09, 0xC0, 0xE6, 0xE9, 0xF4, 0x09, 0x1A, 0x84, 0xA7, 0x33, 0xF1, 0x8D, 0x4C, 0xDD, 0x25, 0x49, 0x6D, 0xBE, 0x87, 0x73, 0x47, 0x91, 0x76, 0x77, 0x1C, 0x86, 0x15, 0xDF, 0x77, 0xA7, 0xAC, 0xD1, 0x5E, 0x92, 0x7B, 0xB6, 0xCC, 0x46, 0xE9, 0x2E, 0xBA, 0xC9, 0x07, 0x7D, 0xFB, 0xE9, 0xAE, 0x90, 0xC6, 0x48, 0x22, 0xA9, 0x02, 0x5E, 0x00, 0x25, 0x70, 0x1A, 0x5C, 0x80, 0xDA, 0xAE, 0x0E, 0x67, 0x3F, 0x42, 0xD3, 0x8D, 0xAD, 0x1D, 0x17, 0xED, 0x8C, 0x2C, 0xF6, 0xF1, 0xCE, 0x3C, 0x4A, 0x5D, 0x0F, 0xA4, 0x73, 0x00, 0x51, 0xC0, 0x08, 0xF0, 0x00, 0xA2, 0x80, 0xAA, 0xB6, 0xDF, 0x6D, 0x88, 0x00, 0x37, 0x66, 0x71, 0x63, 0x16, 0xDF, 0x5D, 0x58, 0xBF, 0x2C, 0x1A, 0x99, 0x20, 0x59, 0x54, 0x39, 0x63, 0x50, 0x3D, 0x40, 0xDF, 0x7E, 0x04, 0xB5, 0x3D, 0x03, 0x7D, 0xEB, 0xA5, 0xC9, 0x75, 0x70, 0x32, 0xDF, 0x8D, 0x7B, 0x7A, 0xB6, 0x5C, 0x1B, 0xF9, 0x16, 0xE7, 0x38, 0xF2, 0xA4, 0x87, 0x18, 0xB0, 0xC6, 0xF4, 0x9E, 0x79, 0x02, 0xF6, 0x4A, 0xA6, 0x8E, 0xA8, 0xC7, 0xFC, 0x0D, 0x33, 0x77, 0x57, 0x5D, 0x6E, 0xF7, 0x39, 0xBA, 0x8F, 0x41, 0x40, 0x02, 0xE5, 0xE3, 0xF3, 0x09, 0x24, 0xF7, 0x2C, 0x40, 0x02, 0x2C, 0x80, 0x18, 0xA0, 0x0E, 0x58, 0x01, 0x21, 0x40, 0xF6, 0x8E, 0x78, 0xB7, 0xB4, 0xC4, 0x7B, 0x46, 0xEA, 0x4F, 0x1E, 0x6C, 0xFC, 0xF6, 0x1D, 0xCB, 0x12, 0x59, 0x5E, 0x8B, 0xBE, 0xCB, 0xD2, 0x77, 0x88, 0x48, 0xED, 0xE1, 0x66, 0xD1, 0xBD, 0xA5, 0xBD, 0x41, 0xD3, 0xD9, 0x69, 0xC6, 0x7A, 0xB2, 0xC1, 0xFD, 0xC5, 0xAB, 0x34, 0xD4, 0xA0, 0xDB, 0xF8, 0xD9, 0xB0, 0xAD, 0x47, 0xA8, 0x34, 0x09, 0xC5, 0xC7, 0x0E, 0x5B, 0x1A, 0x4F, 0xD0, 0x38, 0x7E, 0x03, 0xED, 0xF7, 0xC5, 0x11, 0x3D, 0xCE, 0x74, 0xEE, 0x28, 0x4F, 0xAC, 0x19, 0x1E, 0xBD, 0x76, 0x9F, 0x1E, 0x4F, 0x6F, 0xB8, 0x36, 0xBC, 0x41, 0x80, 0x04, 0xC0, 0x0E, 0x28, 0x01, 0x95, 0x1D, 0xB4, 0x6A, 0x5B, 0xA8, 0xC9, 0xD7, 0x42, 0x59, 0xDF, 0xC5, 0xF0, 0x45, 0xCD, 0x3E, 0x3A, 0x8D, 0x12, 0x93, 0xA0, 0x51, 0x2A, 0xF4, 0x9F, 0xEF, 0x81, 0xC9, 0x58, 0x6C, 0xBB, 0x35, 0x37, 0x40, 0xCF, 0xE8, 0x47, 0x00, 0xD6, 0xA0, 0x77, 0x76, 0xFD, 0x69, 0xC6, 0x52, 0xF9, 0x97, 0x3B, 0xA5, 0x01, 0xD1, 0x98, 0xDB, 0xFA, 0xA4, 0x9C, 0x8C, 0x7F, 0x57, 0xB0, 0x2B, 0x1C, 0x14, 0xB7, 0x56, 0x28, 0xF9, 0x54, 0x38, 0x4F, 0x6F, 0xF9, 0x06, 0x58, 0x00, 0xE9, 0x0D, 0x03, 0xC2, 0x01, 0x33, 0x40, 0xD7, 0xE0, 0x24, 0xDF, 0x76, 0x84, 0x69, 0x35, 0x39, 0xF4, 0x27, 0xBB, 0xEE, 0x61, 0xDF, 0x48, 0x95, 0xB7, 0xD1, 0xE2, 0x8C, 0x07, 0x26, 0xBA, 0xDA, 0x34, 0xDA, 0x49, 0xED, 0xB1, 0xF4, 0x3C, 0x4F, 0xDA, 0x76, 0xD2, 0xAF, 0xA1, 0x7B, 0x1E, 0xD6, 0xE5, 0x59, 0x62, 0xBC, 0xA5, 0xC9, 0xA3, 0xA1, 0x05, 0x58, 0x00, 0x2E, 0x7B, 0x9A, 0x5F, 0xFC, 0xD1, 0xE7, 0x7F, 0x9A, 0xB8, 0x4A, 0x6E, 0xF6, 0xED, 0x27, 0x00, 0xE1, 0x77, 0x44, 0xD3, 0x47, 0xEB, 0x65, 0x06, 0xC3, 0xA2, 0x9F, 0x3D, 0x05, 0x6A, 0x56, 0x93, 0x01, 0x56, 0x80, 0x27, 0x10, 0xE7, 0x81, 0x02, 0xE9, 0x53, 0x74, 0xE8, 0xA0, 0x11, 0xE2, 0xE3, 0xF9, 0x05, 0xCD, 0xEA, 0xD1, 0xD2, 0xD7, 0x56, 0xE2, 0xB0, 0x82, 0x1E, 0x60, 0xA7, 0x6D, 0x2D, 0x1F, 0x25, 0x8E, 0x09, 0x1A, 0x9D, 0xC7, 0x80, 0x80, 0x9F, 0x0E, 0x48, 0xDE, 0x56, 0x51, 0xDE, 0xD0, 0x68, 0x1C, 0x20, 0x1E, 0xC1, 0x7A, 0xBE, 0x06, 0x64, 0x00, 0xF3, 0xD6, 0x95, 0x3C, 0xB4, 0x21, 0xBC, 0xFD, 0x0B, 0x6C, 0x62, 0x57, 0xF1, 0x1B, 0x0D, 0xB6, 0xBF, 0x37, 0xF9, 0x04, 0x94, 0x80, 0xEC, 0xCA, 0x2C, 0x27, 0x60, 0x6F, 0x71, 0xCC, 0x01, 0x2E, 0x80, 0x02, 0x90, 0x03, 0x4C, 0x8B, 0x95, 0xF0, 0x57, 0x55, 0xA1, 0x73, 0xA3, 0x35, 0xC0, 0xDB, 0x24, 0xAB, 0x97, 0x4D, 0xE0, 0x37, 0xC9, 0x82, 0xD7, 0x52, 0xFA, 0x7D, 0x2C, 0x3F, 0x52, 0xB3, 0xEA, 0xEC, 0xDA, 0x47, 0xC9, 0x56, 0x44, 0xC8, 0x02, 0x5C, 0x5E, 0xEB, 0x13, 0xE0, 0x30, 0x40, 0x0E, 0x58, 0x23, 0x0A, 0xE0, 0x98, 0x89, 0x0E, 0x40, 0xA5, 0x51, 0x80, 0x31, 0x90, 0x2B, 0x78, 0x7E, 0xBB, 0x45, 0xD4, 0x66, 0xE1, 0xF9, 0xB4, 0xD0, 0xCE, 0xD4, 0x29, 0x20, 0x0C, 0xC4, 0x3C, 0xC9, 0x6F, 0xCE, 0x80, 0x01, 0x51, 0x80, 0x1C, 0x38, 0xF3, 0x29, 0x00, 0x9F, 0xA5, 0x86, 0xE9, 0x7E, 0xAE, 0xEC, 0x70, 0x61, 0x82, 0x20, 0x28, 0xBB, 0xA0, 0x9C, 0x2D, 0x39, 0x08, 0xB9, 0xD1, 0x74, 0x87, 0x17, 0x82, 0xC8, 0x2C, 0xB1, 0xF7, 0x4D, 0xF0, 0x8C, 0x5D, 0xE4, 0xB3, 0x87, 0x27, 0x20, 0xA3, 0x94, 0x13, 0x80, 0x1E, 0xE0, 0x68, 0x83, 0x1F, 0x05, 0x8F, 0x8E, 0xA4, 0x3F, 0xB6, 0x62, 0x4E, 0x8D, 0x04, 0x62, 0xB9, 0xA0, 0xC9, 0xE8, 0x64, 0x4C, 0x5C, 0x27, 0xA3, 0x28, 0x7F, 0xE7, 0x86, 0x6B, 0xE7, 0x46, 0x2C, 0x80, 0x79, 0xD1, 0x1A, 0x03, 0xA9, 0x0D, 0x02, 0xBC, 0x00, 0x55, 0x80, 0x63, 0x2F, 0xD1, 0x49, 0x0C, 0x21, 0x47, 0x66, 0x6E, 0xF2, 0x37, 0x68, 0xAD, 0x68, 0xAB, 0x9F, 0x46, 0x51, 0xF6, 0xD0, 0x06, 0xF2, 0xF5, 0xFD, 0x26, 0x60, 0x2D, 0x99, 0x19, 0xFF, 0xA7, 0xAC, 0x42, 0x7B, 0xEC, 0xC2, 0xE7, 0xD0, 0xF0, 0x94, 0x06, 0x66, 0x73, 0x4A, 0xDF, 0x81, 0xA9, 0x46, 0x24, 0x90, 0xBA, 0xC1, 0xB9, 0xC3, 0x64, 0xF4, 0xBC, 0x10, 0xE6, 0x5B, 0xF8, 0xD7, 0x38, 0x5E, 0xB3, 0x0A, 0xF5, 0xF6, 0x37, 0xCE, 0xFE, 0x3E, 0x52, 0x57, 0x6C, 0x40, 0xCA, 0xEE, 0x95, 0x70, 0x01, 0xD2, 0x81, 0x51, 0x92, 0x3A, 0xDA, 0x28, 0x80, 0x02, 0xE0, 0x02, 0x26, 0x31, 0x24, 0xD6, 0xEF, 0x11, 0xFA, 0x53, 0x5F, 0x0A, 0xE0, 0x27, 0x6C, 0x5B, 0xE3, 0x98, 0x43, 0x19, 0xF6, 0x2D, 0x1B, 0x56, 0xE9, 0xBA, 0xA6, 0x4C, 0x0F, 0xFC, 0xA3, 0x9C, 0x19, 0xDB, 0x1B, 0x28, 0x03, 0xA8, 0xDA, 0x31, 0xB0, 0x02, 0xC4, 0x00, 0x92, 0xE7, 0xF1, 0x6C, 0x68, 0x00, 0x9E, 0x00, 0xDB, 0x13, 0x34, 0x06, 0x7C, 0x30, 0x26, 0x75, 0xB3, 0x7A, 0x6D, 0x66, 0xE0, 0xD7, 0x5D, 0x5E, 0xEF, 0xDA, 0x0A, 0xD9, 0x1D, 0x94, 0x11, 0xBB, 0xD3, 0x4F, 0x05, 0x70, 0x6D, 0x64, 0x23, 0x1A, 0xDE, 0x38, 0xC0, 0x4D, 0x02, 0x5B, 0x07, 0xCD, 0xD1, 0x84, 0x4E, 0x2D, 0x64, 0x18, 0xF9, 0xA9, 0x0C, 0x91, 0x39, 0x4E, 0xD1, 0x66, 0xE3, 0x3F, 0xD7, 0xED, 0x89, 0x0E, 0x8B, 0x6F, 0x96, 0xE9, 0xE2, 0x7B, 0x54, 0x25, 0x62, 0x96, 0xD1, 0xA3, 0xAD, 0xC4, 0xB1, 0xF2, 0x19, 0x3C, 0x02, 0x3D, 0xF1, 0x78, 0x9E, 0xDA, 0x86, 0x8F, 0xF1, 0x62, 0xED, 0xB7, 0x2F, 0x27, 0x40, 0x04, 0x70, 0x01, 0x2A, 0x7D, 0xBB, 0xCD, 0x95, 0x1C, 0xF1, 0x3B, 0x2F, 0x7B, 0xFC, 0x77, 0x0D, 0x9F, 0x9A, 0x3D, 0x7E, 0x0A, 0xE4, 0x82, 0x66, 0x52, 0xB2, 0x00, 0x75, 0xC0, 0x13, 0x88, 0x02, 0xB2, 0x9E, 0x24, 0x87, 0x01, 0x1C, 0x80, 0xCE, 0x9E, 0xF6, 0xF7, 0x4A, 0x90, 0x9F, 0xD9, 0x0D, 0xFA, 0xD3, 0xDC, 0x19, 0x17, 0x76, 0xF3, 0x4E, 0x76, 0x47, 0xCB, 0xF3, 0xA3, 0x25, 0xDE, 0xE2, 0x19, 0x25, 0xAB, 0x47, 0x6E, 0x54, 0x57, 0x0F, 0x0C, 0x3A, 0x7E, 0xF7, 0x2F, 0x3F, 0xBA, 0x49, 0xD7, 0x3C, 0x1D, 0xA0, 0x04, 0x4E, 0x43, 0x1A, 0x5E, 0xBB, 0xFB, 0x5D, 0x1D, 0xE0, 0x02, 0x34, 0xF7, 0x06, 0xC0, 0x39, 0x51, 0x9E, 0x51, 0xC9, 0x75, 0xE0, 0x9A, 0x66, 0x29, 0x24, 0xB1, 0xF0, 0x5B, 0x3F, 0x63, 0x9B, 0xCE, 0x40, 0x55, 0x5B, 0x36, 0x37, 0x44, 0x01, 0x0D, 0xC0, 0x1D, 0x48, 0xD9, 0xA3, 0xDF, 0xA4, 0x1D, 0xB4, 0xD7, 0x2D, 0x10, 0xAE, 0x0D, 0x99, 0xDA, 0xF6, 0x5A, 0x8E, 0x7E, 0xCF, 0xD2, 0x6F, 0x85, 0x38, 0x09, 0x46, 0x21, 0x64, 0xBB, 0x36, 0xB8, 0xBE, 0x57, 0x82, 0x47, 0x79, 0x3E, 0x0D, 0x10, 0xFB, 0x55, 0xDB, 0xED, 0x1E, 0x79, 0xC3, 0x81, 0x39, 0xE0, 0x85, 0x01, 0x4E, 0x80, 0xAE, 0x81, 0xA0, 0xEF, 0x86, 0x0E, 0x44, 0xA3, 0x74, 0x0F, 0x12, 0xC5, 0x12, 0x4D, 0xA6, 0xE9, 0x61, 0x3B, 0xB7, 0x85, 0x83, 0x67, 0x44, 0xB3, 0x7E, 0x6E, 0xF4, 0xD8, 0x01, 0x10, 0x3B, 0x06, 0xF4, 0x00, 0xDE, 0x08, 0x03, 0xB2, 0xB6, 0xD8, 0x1D, 0xF3, 0x0E, 0xA8, 0x31, 0x82, 0x36, 0x13, 0xFC, 0x3F, 0x43, 0x37, 0xFF, 0x16, 0xB6, 0x20, 0x33, 0x5C, 0x8E, 0xE7, 0xB2, 0x7A, 0xE8, 0x2B, 0x7B, 0x0C, 0x49, 0x68, 0xD7, 0xD7, 0xDF, 0xA6, 0x84, 0x6B, 0xA5, 0x7E, 0x27, 0xCA, 0x00, 0x3D, 0x7B, 0x7A, 0x62, 0xA6, 0x52, 0xF8, 0x89, 0x96, 0x35, 0xFC, 0x00, 0x36, 0x41, 0xB3, 0x0E, 0x13, 0x01, 0x5E, 0x40, 0x32, 0x70, 0x3D, 0x15, 0xE7, 0xA0, 0x76, 0xBB, 0x11, 0x7E, 0x6A, 0xC9, 0xF7, 0x14, 0x8F, 0x63, 0x45, 0x0B, 0x6F, 0x02, 0x35, 0x93, 0xA5, 0x93, 0x09, 0x27, 0x40, 0x05, 0xB0, 0xF9, 0xA4, 0x80, 0x34, 0xD8, 0x00, 0xD5, 0x5D, 0x56, 0xD1, 0xB3, 0x1E, 0xCF, 0x63, 0x8E, 0xC1, 0xE7, 0x60, 0x04, 0xD9, 0xAC, 0x7B, 0xA0, 0xB2, 0xAB, 0xD6, 0x85, 0x01, 0x19, 0xC9, 0x5D, 0x8B, 0xA2, 0x7F, 0x7A, 0xAF, 0x4F, 0x2F, 0xBC, 0x2C, 0xE1, 0xDF, 0x2B, 0x1B, 0x27, 0xBC, 0x05, 0xC9, 0x26, 0x9F, 0xE6, 0x0C, 0xE8, 0x13, 0xE5, 0x7B, 0x39, 0x07, 0xF6, 0xA7, 0xA5, 0xF3, 0xB5, 0x04, 0xE6, 0xC8, 0xAE, 0x7A, 0x53, 0xFC, 0x24, 0x19, 0x44, 0xAE, 0xF1, 0xBC, 0x4C, 0xA6, 0xC7, 0x80, 0xF4, 0x6E, 0x7E, 0x0C, 0xC0, 0x0E, 0xE0, 0x0A, 0xE4, 0x01, 0x2A, 0xA7, 0xE5, 0x0C, 0xE0, 0xC6, 0xBC, 0x3D, 0x95, 0x9E, 0xC7, 0x73, 0xBC, 0xEC, 0x1D, 0xBB, 0x81, 0x3A, 0xCA, 0x07, 0xE6, 0x2D, 0x86, 0x15, 0x70, 0xC8, 0x90, 0xEA, 0x20, 0x21, 0x66, 0xFE, 0x08, 0xE5, 0xF8, 0xC4, 0x4C, 0x47, 0x83, 0x65, 0x62, 0x36, 0x83, 0xA9, 0x3E, 0x2D, 0x2A, 0xD8, 0xE0, 0x68, 0xAE, 0xE8, 0xDB, 0x42, 0xC6, 0x03, 0xA0, 0xA7, 0x2C, 0xCF, 0x8F, 0x75, 0x1F, 0x37, 0x64, 0x59, 0x84, 0xF9, 0x3C, 0x9D, 0x7F, 0x55, 0x20, 0xA5, 0xA6, 0x0F, 0xA5, 0xC3, 0x73, 0x46, 0x48, 0xA2, 0x73, 0x42, 0x01, 0x84, 0x77, 0xDE, 0x27, 0x01, 0x25, 0xC0, 0x14, 0xF0, 0x02, 0xD2, 0xDA, 0xEA, 0x59, 0x00, 0x22, 0x80, 0xAD, 0x63, 0xC6, 0x68, 0x46, 0xD0, 0xB8, 0xA1, 0xAB, 0x6F, 0x77, 0x16, 0xFC, 0x59, 0x70, 0xBA, 0x28, 0x49, 0xEB, 0x8A, 0x74, 0x7C, 0x77, 0x9B, 0x53, 0xB1, 0x55, 0xE6, 0xE2, 0xF1, 0x1F, 0x90, 0xD7, 0x43, 0xD1, 0x81, 0xD0, 0x06, 0x01, 0x49, 0x7B, 0xEC, 0xEE, 0x3A, 0x56, 0xD6, 0xF9, 0xE5, 0xB0, 0xF3, 0x36, 0xA7, 0x51, 0xE1, 0x93, 0xDA, 0xAF, 0xA1, 0xBE, 0x73, 0x90, 0x79, 0xBB, 0x9D, 0x8B, 0x1F, 0x2B, 0xCF, 0x69, 0x43, 0x2A, 0x20, 0x0E, 0x60, 0xD5, 0xF0, 0xC6, 0x63, 0xC6, 0x43, 0x0E, 0x48, 0x35, 0x18, 0x98, 0x67, 0xA6, 0x18, 0x88, 0x00, 0xB2, 0xEE, 0x77, 0x76, 0xD0, 0xE0, 0x3F, 0x20, 0xFC, 0xFA, 0x14, 0x77, 0xD1, 0x0A, 0x4B, 0x8B, 0xA6, 0x0C, 0x57, 0x29, 0x10, 0x5D, 0xCA, 0xB3, 0xCE, 0xB6, 0xEE, 0xAF, 0x74, 0xE6, 0x63, 0x4A, 0x19, 0xA7, 0x21, 0x0D, 0x07, 0x6A, 0x0A, 0xEA, 0xF3, 0xF6, 0xF3, 0xDB, 0x0A, 0xDF, 0x81, 0xB1, 0xDE, 0x85, 0x46, 0x8C, 0x43, 0xF1, 0x49, 0xA3, 0x43, 0x38, 0x45, 0xCF, 0x19, 0x9D, 0x46, 0xEC, 0xF4, 0x15, 0xA2, 0xAB, 0xED, 0xA5, 0x61, 0xF2, 0x44, 0x44, 0x1B, 0x01, 0x38, 0xBF, 0xB9, 0x76, 0x40, 0x68, 0x27, 0xAD, 0x22, 0x01, 0x13, 0xC0, 0xA3, 0xBF, 0x85, 0x27, 0x68, 0xFA, 0x4D, 0x90, 0x85, 0x52, 0xB7, 0xBB, 0xFA, 0x7E, 0x48, 0xAB, 0xC7, 0xBA, 0x84, 0xA1, 0x79, 0x6D, 0x6D, 0x1E, 0xE7, 0x85, 0x33, 0xED, 0x3F, 0x2F, 0xEC, 0xFC, 0x0C, 0x8B, 0x89, 0x35, 0xF8, 0xB1, 0xDF, 0x3D, 0x7B, 0x31, 0x8E, 0xA1, 0x8C, 0x7D, 0x40, 0xD7, 0xEC, 0xEF, 0x9E, 0x67, 0x33, 0x1E, 0x7D, 0x9B, 0xCC, 0xB8, 0x66, 0xB7, 0x1C, 0x5F, 0x87, 0x65, 0x47, 0x61, 0x09, 0xB8, 0x35, 0x04, 0x30, 0x6F, 0xD8, 0xFE, 0xE4, 0x07, 0x48, 0x1D, 0x5F, 0x19, 0xC0, 0x08, 0x50, 0x07, 0x38, 0x1F, 0x3F, 0x9A, 0xD8, 0xE6, 0xAD, 0x76, 0x83, 0x66, 0xDF, 0x4A, 0x73, 0x1B, 0x15, 0xBE, 0xB9, 0x4C, 0x4D, 0x13, 0x65, 0xC2, 0x0B, 0x85, 0xBA, 0x08, 0x75, 0x14, 0x8F, 0x5C, 0xD1, 0xD8, 0x9F, 0x3E, 0xF6, 0x20, 0x73, 0xAB, 0xA9, 0xA7, 0xA1, 0xC7, 0x1B, 0x06, 0x48, 0xED, 0x2F, 0xCE, 0xB6, 0x2E, 0x7A, 0x3D, 0x72, 0xA6, 0xEE, 0xF4, 0x9B, 0xEF, 0xAA, 0x2B, 0xE9, 0x95, 0xAB, 0x7E, 0x4C, 0xE3, 0x1D, 0x7B, 0xCD, 0x66, 0x74, 0xA7, 0x2B, 0xCD, 0x01, 0x8E, 0x27, 0x29, 0x6C, 0x0D, 0x6E, 0xCC, 0xB7, 0xD0, 0xE3, 0x73, 0x3E, 0x60, 0xC0, 0xEB, 0x31, 0xDC, 0x6D, 0x08, 0x03, 0x65, 0x13, 0x34, 0x47, 0xFF, 0xE3, 0x7F, 0x5E, 0x07, 0x8A, 0xFF, 0x01, 0x8F, 0x27, 0x7B, 0x3B, 0xE9, 0x33, 0x7E, 0xF5, 0x92, 0x7B, 0xA6, 0xFD, 0x48, 0xCF, 0xD5, 0x93, 0x74, 0xCF, 0x23, 0x72, 0x83, 0xAA, 0x21, 0x8D, 0xDA, 0x1D, 0x52, 0x67, 0x1E, 0x09, 0x5D, 0x13, 0x27, 0x10, 0x0E, 0x5E, 0xCA, 0xE6, 0x73, 0xE1, 0x16, 0x9B, 0xEC, 0xDE, 0x14, 0x8E, 0x11, 0x3B, 0xDD, 0xD2, 0x75, 0x7C, 0x76, 0xFB, 0xA4, 0x55, 0x83, 0x1A, 0xA7, 0x21, 0x40, 0xE8, 0xA3, 0x9C, 0x49, 0x00, 0xDB, 0x6E, 0xC2, 0x2C, 0x05, 0x22, 0x80, 0xAC, 0xFE, 0xCE, 0x9C, 0xA0, 0xC5, 0x57, 0xB3, 0x3B, 0x65, 0xD8, 0xF5, 0x28, 0xBF, 0xAC, 0xB7, 0xA7, 0x75, 0x3E, 0xCD, 0xFF, 0x2A, 0x2F, 0xD8, 0x18, 0x06, 0x32, 0xF5, 0xD9, 0x36, 0x5F, 0xB9, 0x51, 0x80, 0xEF, 0x3F, 0x39, 0x9F, 0x6D, 0x0C, 0xA3, 0x09, 0x98, 0x3F, 0x86, 0x81, 0x36, 0xBF, 0xEE, 0xF2, 0xC5, 0x9B, 0x14, 0x33, 0xDD, 0xBC, 0xFC, 0x59, 0x42, 0x54, 0x5D, 0x0B, 0x21, 0xBF, 0xC9, 0x32, 0xAA, 0x0E, 0xE1, 0xF8, 0x2C, 0x24, 0x20, 0x37, 0xF4, 0x40, 0x10, 0xE0, 0xDA, 0x90, 0x46, 0x02, 0x65, 0xBB, 0x0A, 0xED, 0xDE, 0x38, 0x80, 0xF2, 0x16, 0x01, 0xAC, 0x69, 0xC5, 0x2A, 0x20, 0x26, 0x68, 0x70, 0x1C, 0x30, 0xF2, 0x77, 0xA5, 0xE1, 0x98, 0xA6, 0xD8, 0x3E, 0x42, 0x65, 0xDA, 0x5E, 0xD0, 0x42, 0x2A, 0x68, 0xB8, 0xE5, 0x9D, 0x19, 0x5A, 0xF9, 0xB4, 0x7C, 0x3C, 0x93, 0xB3, 0xE1, 0xFB, 0x93, 0x29, 0x90, 0x3E, 0xEF, 0xB8, 0x5B, 0xDB, 0xEC, 0x34, 0x17, 0x23, 0x6A, 0xB2, 0x12, 0xFA, 0x8C, 0x50, 0x52, 0xDD, 0x66, 0x18, 0xFE, 0x89, 0xF6, 0xD6, 0xBD, 0xAC, 0x3A, 0x01, 0x67, 0x44, 0x6C, 0x1D, 0xF8, 0xB5, 0xEF, 0x02, 0xA7, 0x61, 0x80, 0x1E, 0x20, 0x7D, 0x3B, 0xDF, 0xCC, 0xC2, 0x2B, 0x02, 0x9C, 0x01, 0x25, 0xC0, 0xA4, 0xBF, 0xD3, 0x26, 0x6A, 0x18, 0x21, 0x23, 0xE3, 0xFB, 0x83, 0x85, 0xE3, 0x1A, 0x05, 0x81, 0x22, 0x46, 0x81, 0xFC, 0xF4, 0x15, 0xD4, 0xB8, 0x7D, 0x5A, 0x72, 0x5B, 0x5D, 0xDC, 0x0A, 0xFB, 0x7A, 0xF8, 0x0C, 0x31, 0xC4, 0x61, 0x0C, 0xB0, 0x01, 0x37, 0x0A, 0x18, 0x57, 0x02, 0xB9, 0x33, 0x8B, 0xF3, 0x0C, 0xFA, 0x4F, 0xCF, 0x89, 0xEF, 0x40, 0x4A, 0xCC, 0x60, 0x90, 0x4F, 0xEA, 0x7F, 0x8F, 0xF4, 0xB1, 0x01, 0xE7, 0x00, 0xE2, 0x80, 0x15, 0xE0, 0x09, 0x44, 0x00, 0xC9, 0x40, 0xC9, 0x6E, 0x10, 0x8D, 0x11, 0x3F, 0x9D, 0xB3, 0xB1, 0x00, 0xE1, 0x80, 0x26, 0x20, 0x67, 0x6B, 0xA7, 0xCE, 0x10, 0x81, 0xA1, 0x2D, 0x8D, 0x51, 0x45, 0x0F, 0xA7, 0x51, 0xB6, 0x85, 0xC6, 0x50, 0x5A, 0x7E, 0xC7, 0xED, 0x30, 0xEB, 0xF1, 0xBB, 0x42, 0x9E, 0x50, 0x6B, 0xA5, 0x86, 0x54, 0x9F, 0x86, 0x78, 0x3A, 0x40, 0xCE, 0xDE, 0x56, 0x8D, 0x37, 0x53, 0xED, 0x00, 0xC7, 0xB6, 0x76, 0x4E, 0x5B, 0x92, 0xD3, 0x76, 0x2B, 0x9E, 0x49, 0xC0, 0xB1, 0x79, 0x76, 0x7F, 0x63, 0xC3, 0x7F, 0xDB, 0x0D, 0x85, 0xA6, 0x13, 0xE4, 0x83, 0x33, 0xA0, 0x0A, 0xC8, 0x01, 0x38, 0x36, 0x44, 0x01, 0x0B, 0xA0, 0xF4, 0xE9, 0x64, 0x26, 0x5E, 0x56, 0x17, 0x79, 0x9E, 0xFE, 0xC9, 0x39, 0xB6, 0xB3, 0x74, 0xD0, 0x08, 0x1D, 0x56, 0x9A, 0xAB, 0xFE, 0xC9, 0x8A, 0x99, 0xC5, 0x4A, 0x6F, 0xD9, 0x93, 0xEC, 0x21, 0x09, 0xE8, 0x73, 0x30, 0xE9, 0x76, 0x0C, 0x94, 0xE7, 0xCC, 0x71, 0x8F, 0x99, 0xF5, 0xF8, 0x83, 0x18, 0x30, 0xCB, 0xFE, 0x30, 0xC0, 0x8D, 0xF4, 0xD9, 0xD4, 0x66, 0x1D, 0xD0, 0xAF, 0xFA, 0x26, 0xD7, 0xA7, 0x21, 0xA6, 0x82, 0x24, 0x3F, 0x39, 0xBE, 0xB8, 0x8B, 0x23, 0x0D, 0x60, 0xDD, 0xCA, 0x23, 0xEE, 0x80, 0x46, 0xC3, 0x1A, 0x0E, 0x98, 0x02, 0x51, 0xDB, 0xCA, 0x41, 0x06, 0x02, 0x70, 0x63, 0x2C, 0x31, 0x6B, 0xB6, 0xF4, 0xB3, 0xDB, 0x94, 0xBF, 0x87, 0x8E, 0x70, 0x55, 0xC2, 0xFC, 0x86, 0xFD, 0xC9, 0x6F, 0x4E, 0x28, 0x71, 0xF5, 0xC8, 0xE9, 0x43, 0x9C, 0x3D, 0x34, 0x51, 0x9E, 0x0B, 0xDD, 0x1D, 0xB7, 0xF2, 0xBC, 0x3E, 0x6D, 0xCA, 0x75, 0x4F, 0x52, 0xC7, 0x64, 0x7F, 0x52, 0x05, 0x8C, 0x81, 0x9A, 0x97, 0x9B, 0xAD, 0x46, 0x58, 0xBD, 0x0F, 0x8F, 0xAE, 0xBE, 0x34, 0x9E, 0x2D, 0x19, 0x91, 0xAC, 0xFB, 0x74, 0x67, 0x23, 0xCE, 0xD6, 0x2D, 0x61, 0x07, 0xA4, 0xA1, 0xD2, 0x48, 0xC0, 0xFC, 0x31, 0x6F, 0x60, 0x02, 0xD4, 0x1B, 0x0C, 0x70, 0x00, 0x47, 0xF1, 0x9D, 0xB3, 0x26, 0xEB, 0xEA, 0xA6, 0x77, 0xD0, 0x90, 0xD0, 0x28, 0x91, 0xE5, 0xB7, 0x6B, 0x26, 0x5F, 0x2E, 0x32, 0x68, 0x14, 0x3B, 0x15, 0x7B, 0x5A, 0x70, 0xCF, 0x14, 0x38, 0xAE, 0x02, 0xAF, 0x4C, 0xC2, 0x34, 0x1F, 0x87, 0x6C, 0xBF, 0xDD, 0x01, 0x47, 0xC3, 0x00, 0x21, 0x40, 0x03, 0xA8, 0x11, 0xBA, 0x98, 0x7B, 0x54, 0xF1, 0x38, 0x36, 0x6D, 0x29, 0xD5, 0xD3, 0xC7, 0x36, 0x5A, 0xA6, 0x4E, 0x9F, 0x80, 0x04, 0x30, 0xED, 0xEA, 0x61, 0x80, 0x15, 0xA0, 0x06, 0x88, 0x36, 0xBC, 0x51, 0x80, 0x3A, 0xE0, 0xB1, 0xFD, 0x41, 0x4E, 0x3D, 0xE8, 0x6F, 0xA9, 0xC7, 0xD0, 0xEA, 0x18, 0xA0, 0xD4, 0x41, 0xD3, 0xCF, 0x28, 0xCA, 0xC5, 0xF0, 0x83, 0x95, 0x2F, 0x9B, 0xC5, 0xB2, 0x16, 0xB3, 0x55, 0xC5, 0x2E, 0x5B, 0x86, 0x33, 0x3C, 0xD7, 0x6A, 0x53, 0xB6, 0x78, 0xBC, 0x29, 0xE5, 0x3C, 0xA7, 0xDB, 0x7A, 0x60, 0x80, 0xE5, 0xBE, 0x83, 0x1A, 0xCD, 0xA3, 0xDB, 0x41, 0x93, 0x99, 0xFB, 0xA5, 0x7E, 0x89, 0x1A, 0x82, 0xC6, 0x33, 0xEC, 0xAA, 0xBF, 0x6D, 0x7A, 0x4C, 0x05, 0xF9, 0xBA, 0x47, 0xA5, 0xCC, 0xE1, 0xB8, 0x11, 0x0D, 0x6B, 0x14, 0x40, 0xA7, 0x91, 0x80, 0x36, 0x66, 0x14, 0x99, 0x07, 0x04, 0x4C, 0x33, 0x57, 0x34, 0xB4, 0x00, 0xD7, 0xFE, 0x96, 0xD9, 0xD3, 0xA0, 0x32, 0x64, 0xF1, 0x5B, 0x69, 0x8E, 0x69, 0x4E, 0xF5, 0x6B, 0x97, 0xCA, 0xDE, 0x2F, 0x51, 0x31, 0x5C, 0x8E, 0x3D, 0xEE, 0x5E, 0xF6, 0x51, 0x9F, 0x3D, 0x6D, 0xDA, 0x05, 0x68, 0xEE, 0x76, 0x04, 0xE8, 0x69, 0x28, 0x60, 0xBE, 0xCF, 0x97, 0xC2, 0xFD, 0x44, 0x6D, 0xBF, 0xDD, 0xBC, 0x93, 0xBE, 0x77, 0x04, 0x9A, 0x7F, 0x82, 0xAC, 0x76, 0x55, 0x90, 0xAF, 0x47, 0xBB, 0x8F, 0x82, 0x15, 0x60, 0xF6, 0x38, 0x2E, 0x8C, 0x4B, 0x6C, 0x83, 0x1B, 0xF1, 0x34, 0xC4, 0x1B, 0x03, 0xA1, 0x80, 0xE7, 0xE3, 0x20, 0x1B, 0x00, 0x2B, 0x20, 0x06, 0x44, 0x75, 0xD0, 0x1C, 0xD9, 0x26, 0xAA, 0x09, 0x1A, 0xB4, 0x86, 0x2C, 0xE0, 0xAE, 0x75, 0xBC, 0x77, 0x59, 0x47, 0x4D, 0x21, 0x1C, 0x5B, 0x04, 0xEE, 0x51, 0xA9, 0x6F, 0xBA, 0x7B, 0xEE, 0x02, 0x3E, 0xA9, 0xFB, 0xD9, 0xDE, 0xA5, 0x31, 0x32, 0x12, 0x87, 0x01, 0x3A, 0x00, 0x3B, 0x10, 0xA3, 0x2E, 0x9D, 0x7F, 0x3D, 0x7D, 0x98, 0xEE, 0x1B, 0xA0, 0x1A, 0xF2, 0xD3, 0x95, 0xA4, 0xBA, 0xC6, 0x6F, 0x61, 0xBB, 0xEA, 0xC6, 0x05, 0x9C, 0x71, 0x8A, 0x63, 0xC0, 0xAB, 0x91, 0x40, 0x10, 0x90, 0xE7, 0x79, 0xDA, 0x0E, 0x60, 0xD5, 0xC8, 0xC6, 0x01, 0x24, 0x1B, 0x0A, 0xA8, 0x00, 0x39, 0x47, 0x8E, 0x80, 0xCB, 0x85, 0xCB, 0x0D, 0x9A, 0x7F, 0xA5, 0x02, 0xEA, 0x8E, 0x2B, 0x6E, 0x89, 0x61, 0x3C, 0xBA, 0x9C, 0x89, 0x40, 0x04, 0xAF, 0xA0, 0x65, 0x2C, 0x3D, 0x60, 0x9C, 0x97, 0x66, 0x63, 0xDE, 0x61, 0x0A, 0x05, 0x8A, 0xF7, 0x73, 0xC2, 0x01, 0x5C, 0x19, 0x63, 0xEE, 0xED, 0x6B, 0x3A, 0x03, 0x56, 0x6B, 0xB1, 0x5F, 0x95, 0xD1, 0x92, 0x8E, 0xDD, 0x4C, 0x87, 0xF6, 0x56, 0x13, 0xBC, 0x7D, 0xF5, 0xA6, 0xD2, 0x59, 0x05, 0x04, 0x01, 0x2E, 0x0D, 0x6A, 0x24, 0x50, 0xF3, 0x3F, 0x04, 0x60, 0xD5, 0x78, 0x76, 0x3F, 0x8A, 0xE7, 0xED, 0xA9, 0x80, 0x5B, 0x07, 0x2D, 0x91, 0xB4, 0x2C, 0x5A, 0x3E, 0x6E, 0xD2, 0x82, 0x86, 0x57, 0xAA, 0x5E, 0xD0, 0xA6, 0xC6, 0x59, 0x3D, 0x55, 0x2F, 0x33, 0x09, 0x85, 0x04, 0xEE, 0x9B, 0x84, 0xCC, 0xE5, 0x84, 0xA6, 0xF7, 0x78, 0xA8, 0x07, 0x08, 0x03, 0xCA, 0xA6, 0x5B, 0x0D, 0x40, 0xCC, 0xAA, 0xE3, 0xA2, 0xB7, 0xD9, 0x95, 0xA7, 0xF8, 0xE1, 0x9D, 0xD5, 0x9F, 0x6A, 0x52, 0xFD, 0x84, 0x1F, 0xF4, 0x8E, 0xB2, 0x97, 0x00, 0xD4, 0x87, 0x12, 0x4F, 0x40, 0x0E, 0x70, 0xBC, 0x41, 0x0D, 0x01, 0xA8, 0xA1, 0x0E, 0xD4, 0x08, 0x07, 0x4B, 0x83, 0x81, 0x13, 0x4F, 0x3B, 0x0C, 0x03, 0xD9, 0x97, 0x93, 0xFB, 0xF2, 0x2C, 0xC4, 0x25, 0x26, 0x09, 0x89, 0xA4, 0x25, 0x73, 0xB5, 0xF0, 0x34, 0x63, 0x74, 0x9A, 0xF0, 0x49, 0x82, 0xBA, 0xB7, 0xAE, 0xA6, 0x39, 0x00, 0xEB, 0xED, 0x19, 0x90, 0x8D, 0xE9, 0x56, 0xB7, 0x8E, 0xC4, 0xD5, 0x63, 0x61, 0xC0, 0x4E, 0x23, 0xF7, 0xB8, 0x3A, 0x7D, 0x90, 0xBF, 0xB3, 0xDA, 0x85, 0x60, 0xCD, 0x24, 0xF5, 0xB4, 0x2E, 0x66, 0x47, 0xD0, 0x66, 0xA6, 0xFC, 0xC3, 0x94, 0x4E, 0x90, 0x3A, 0x47, 0x91, 0x4E, 0x00, 0x27, 0x40, 0x05, 0x10, 0x6A, 0xBC, 0x32, 0x9A, 0xBA, 0x1B, 0xE1, 0xB9, 0x00, 0xA3, 0x06, 0x03, 0x1A, 0x80, 0x58, 0x83, 0x01, 0x35, 0x60, 0x06, 0xFE, 0x7D, 0x54, 0x5E, 0x7F, 0x43, 0x2B, 0xD1, 0x75, 0x2D, 0x83, 0xA2, 0xC9, 0xD5, 0x47, 0x47, 0x41, 0xA5, 0x2D, 0x08, 0x65, 0xAB, 0xE5, 0xD4, 0xE3, 0x4C, 0x39, 0xE3, 0x26, 0xE9, 0x67, 0x2B, 0x8E, 0x8B, 0x02, 0x5A, 0x80, 0x1F, 0x60, 0x5A, 0x49, 0xE7, 0x72, 0xE2, 0xEB, 0xA2, 0x3E, 0x92, 0x04, 0xE7, 0x76, 0xB2, 0x7B, 0xAF, 0xB0, 0x1A, 0x5B, 0xF1, 0x8E, 0x72, 0x8D, 0x90, 0x82, 0x02, 0x2C, 0x5B, 0x45, 0xD7, 0x1B, 0xEA, 0x0D, 0xDB, 0x9F, 0xCC, 0x80, 0xA4, 0xFE, 0xFF, 0x0E, 0xA0, 0x04, 0x48, 0x35, 0x0E, 0x40, 0x06, 0x1C, 0x07, 0x28, 0x81, 0xB9, 0xAF, 0x3B, 0xC1, 0x89, 0xC6, 0xD1, 0x08, 0xCF, 0x92, 0xEB, 0xC0, 0xC1, 0xD2, 0x8D, 0x52, 0x94, 0x68, 0x05, 0x8E, 0x40, 0xB5, 0x89, 0x78, 0xBB, 0xED, 0xBE, 0x63, 0x8B, 0xAC, 0x4F, 0x57, 0x54, 0x36, 0x08, 0xA0, 0x6C, 0xE8, 0xFE, 0x64, 0x93, 0xF3, 0x9A, 0x1A, 0xB1, 0xCC, 0x1B, 0x71, 0x4E, 0x05, 0xB6, 0x1D, 0x14, 0x49, 0xE6, 0x30, 0xBB, 0x1A, 0x04, 0xE7, 0x8E, 0x41, 0xE3, 0x1D, 0xD3, 0xB8, 0x63, 0x0A, 0xF1, 0xAF, 0x83, 0x6E, 0x23, 0x3E, 0x2C, 0xBB, 0xFF, 0xC1, 0xF3, 0xF2, 0x3A, 0x3C, 0xB7, 0xA7, 0x7D, 0xDD, 0x32, 0xEB, 0xA0, 0xA1, 0x69, 0xA8, 0x22, 0x30, 0x3D, 0x90, 0xF9, 0xDD, 0x07, 0x48, 0x0B, 0x05, 0x06, 0xBC, 0x2D, 0x4D, 0xE4, 0xBB, 0x95, 0x3A, 0xB5, 0x40, 0x9F, 0xB1, 0xFE, 0xBF, 0xD3, 0x69, 0x1A, 0x3B, 0x81, 0xC1, 0xB5, 0x41, 0xB4, 0x5B, 0xFB, 0x26, 0x27, 0x48, 0x2B, 0x57, 0x0F, 0xB5, 0xAE, 0x89, 0x0F, 0x10, 0xBE, 0x14, 0x5F, 0xB4, 0xB6, 0x4C, 0x17, 0x2B, 0x70, 0x1A, 0x21, 0x13, 0x03, 0x46, 0x94, 0x75, 0xA6, 0x8A, 0x19, 0x70, 0x07, 0x52, 0xE7, 0xA0, 0x02, 0x70, 0x00, 0x6E, 0x40, 0x56, 0x23, 0x80, 0x78, 0x9E, 0x08, 0x2D, 0x60, 0x5E, 0x26, 0x53, 0x2A, 0x76, 0xF9, 0x8E, 0x18, 0xC6, 0xD2, 0x5E, 0x94, 0xB4, 0x2C, 0x8A, 0x45, 0x0C, 0x2B, 0xCD, 0x09, 0x6A, 0x62, 0xDC, 0x46, 0x34, 0x06, 0xDB, 0x75, 0xDF, 0xAA, 0x86, 0x78, 0x5C, 0x9F, 0x56, 0x8E, 0xB9, 0xA8, 0xDF, 0xCE, 0x32, 0x20, 0x15, 0x08, 0x6B, 0xE4, 0xEF, 0x2E, 0xAF, 0x53, 0x8A, 0x9F, 0xA5, 0x36, 0xD7, 0x19, 0xBA, 0x47, 0x23, 0x8F, 0x75, 0x6F, 0x0A, 0xDB, 0x36, 0x1A, 0x1C, 0x80, 0xD6, 0x0E, 0x65, 0xCE, 0x84, 0x5A, 0x43, 0x4E, 0xA3, 0x00, 0x4D, 0x20, 0xAE, 0xBD, 0x44, 0x43, 0x18, 0xE0, 0x02, 0x1E, 0x87, 0xCA, 0xA4, 0xE7, 0x78, 0x37, 0x17, 0x02, 0xD7, 0x2F, 0x6A, 0xAA, 0xFE, 0x1D, 0x3C, 0x44, 0xF7, 0xF3, 0xE9, 0x2A, 0xDF, 0x1A, 0x4B, 0xE5, 0x76, 0x08, 0xD3, 0x6E, 0xD4, 0xD3, 0x35, 0x21, 0x1B, 0x7C, 0x37, 0xB5, 0xED, 0x86, 0x2D, 0x0A, 0x58, 0x36, 0xF8, 0x79, 0x5A, 0xAD, 0x51, 0x40, 0xC8, 0xAF, 0x84, 0x87, 0x79, 0xA5, 0x7D, 0x94, 0xBF, 0x86, 0xAE, 0x39, 0x87, 0xBD, 0x99, 0xD6, 0x5C, 0x06, 0x97, 0x22, 0x40, 0xCD, 0xE3, 0xA6, 0x63, 0xB3, 0x3A, 0x45, 0xD7, 0x03, 0xB8, 0x00, 0x11, 0xDB, 0x2E, 0x84, 0x05, 0x08, 0xED, 0xC4, 0x92, 0xE3, 0x53, 0xE5, 0x5E, 0x6A, 0x1A, 0xFB, 0x3B, 0x65, 0xBE, 0x53, 0x3A, 0x68, 0xD6, 0xBA, 0xC1, 0x82, 0xF3, 0x91, 0xE4, 0x77, 0x21, 0x10, 0x8E, 0x76, 0x59, 0x74, 0xFC, 0xEC, 0x44, 0x3D, 0x1A, 0x10, 0xA8, 0x65, 0x27, 0x2E, 0x04, 0xFC, 0x06, 0x8D, 0x66, 0x19, 0x8D, 0x0E, 0xF0, 0xE3, 0xB0, 0x1C, 0xD5, 0x20, 0xC0, 0x65, 0xA3, 0xCE, 0xB3, 0xC4, 0xE6, 0x27, 0x74, 0xDF, 0x6E, 0x13, 0x2E, 0x8F, 0xE5, 0x45, 0xFE, 0xE3, 0x8E, 0x53, 0x4F, 0x56, 0x2D, 0xE7, 0xA4, 0xF3, 0x64, 0xC7, 0x8A, 0xF6, 0xA1, 0x56, 0x18, 0x70, 0x01, 0x92, 0x1B, 0x02, 0x44, 0x02, 0x5E, 0x0D, 0x03, 0x10, 0xDE, 0xF8, 0xFB, 0x7C, 0x42, 0x75, 0x34, 0x35, 0xF0, 0x7A, 0x2F, 0xFA, 0x13, 0x8A, 0x25, 0x26, 0x0A, 0xE7, 0x0B, 0x4C, 0x67, 0x56, 0x57, 0xCB, 0x15, 0x9D, 0x18, 0x5E, 0x7B, 0x80, 0x5D, 0x9F, 0xFB, 0x7A, 0x4E, 0x19, 0x62, 0x5A, 0x61, 0x0B, 0xB0, 0xC7, 0x78, 0x5F, 0xAA, 0x91, 0xDB, 0xC1, 0x8D, 0xEE, 0x2D, 0x21, 0x3B, 0x4C, 0xAB, 0xF1, 0x53, 0xFF, 0xEE, 0x2E, 0xA3, 0x55, 0x77, 0x5D, 0x53, 0x01, 0x09, 0x20, 0xCE, 0x56, 0xAE, 0x33, 0x05, 0xAA, 0x57, 0x0C, 0x27, 0xA0, 0x07, 0x30, 0x01, 0xD2, 0xB6, 0x07, 0x8D, 0x37, 0x2C, 0x01, 0x75, 0x80, 0x0F, 0x70, 0x04, 0x20, 0x05, 0x22, 0x3B, 0x68, 0x81, 0x72, 0x32, 0x77, 0x6B, 0x72, 0x15, 0x74, 0x6E, 0xA9, 0x70, 0xB6, 0xA1, 0xC7, 0x20, 0x28, 0xD1, 0x69, 0x65, 0x7C, 0x95, 0xF9, 0xDE, 0xAB, 0xE7, 0x3C, 0x97, 0x8F, 0x2A, 0x30, 0x01, 0x7A, 0x00, 0x4E, 0x80, 0x04, 0x38, 0x0C, 0xF0, 0xCF, 0x74, 0x13, 0x8B, 0x3A, 0x67, 0x1D, 0x6C, 0xBB, 0x99, 0xEB, 0x62, 0x3A, 0x0B, 0x2E, 0x7E, 0xCA, 0xC8, 0xFC, 0x4C, 0xBF, 0x4C, 0x3E, 0x6C, 0xCA, 0x08, 0xD1, 0xC8, 0x0E, 0x61, 0x5E, 0x99, 0xAF, 0x43, 0x80, 0x14, 0x30, 0x32, 0x56, 0x1C, 0x0D, 0x03, 0x4E, 0x3E, 0xF2, 0xEC, 0x05, 0xA4, 0xCD, 0xF0, 0x6D, 0x07, 0x0D, 0x87, 0xB1, 0x39, 0xF7, 0x1C, 0x2B, 0x8C, 0xE2, 0x1D, 0xE9, 0xA2, 0x7D, 0xE0, 0xA2, 0x4C, 0x40, 0x25, 0x61, 0xA4, 0x9E, 0x76, 0xB6, 0x3B, 0xDE, 0x6C, 0x77, 0xCD, 0xEC, 0xB8, 0xCC, 0xC2, 0x69, 0x58, 0x00, 0x52, 0x00, 0x25, 0x70, 0x96, 0xF9, 0xCC, 0xDC, 0xA9, 0xE6, 0x72, 0x13, 0x8D, 0xE9, 0x2E, 0xCF, 0x91, 0x86, 0x19, 0x4D, 0xC7, 0xDB, 0xC6, 0x19, 0xEB, 0xE1, 0x41, 0xAD, 0x12, 0xDF, 0x99, 0xDB, 0xA3, 0x67, 0xEE, 0x07, 0x64, 0x80, 0x34, 0x4C, 0xF6, 0x41, 0x8D, 0x14, 0x10, 0x6A, 0x68, 0xE3, 0x00, 0xEC, 0x0D, 0xD9, 0xDF, 0x12, 0xF3, 0x22, 0x28, 0x74, 0xC8, 0xF8, 0xDC, 0xD6, 0xF8, 0x4F, 0x10, 0xF6, 0x7C, 0x34, 0x2A, 0x33, 0x7E, 0xB0, 0x13, 0xE8, 0x15, 0x38, 0xDE, 0x76, 0x6E, 0xF0, 0x5D, 0xF7, 0x7F, 0x24, 0x6E, 0xE5, 0x6F, 0x1E, 0x4D, 0x77, 0x4D, 0xCC, 0xE8, 0xD1, 0x4C, 0x55, 0xC0, 0x75, 0xD6, 0xDD, 0xB2, 0xA3, 0x44, 0xBB, 0xD8, 0xA8, 0xEB, 0x2C, 0x55, 0x33, 0xE9, 0x50, 0x4C, 0xEC, 0xA6, 0x4D, 0x31, 0x14, 0x90, 0xC6, 0x18, 0x22, 0x71, 0x01, 0x69, 0x5B, 0x50, 0x4E, 0xFD, 0xF1, 0x3E, 0x92, 0x11, 0x8F, 0x02, 0xA4, 0x00, 0x8B, 0xC6, 0xEB, 0x76, 0x64, 0xCF, 0xB7, 0x08, 0x30, 0x4D, 0x43, 0x33, 0x43, 0x65, 0x0A, 0x2F, 0x11, 0xAD, 0x3F, 0x89, 0xF9, 0x1E, 0x88, 0x02, 0xF7, 0x66, 0x56, 0xD2, 0x43, 0xD8, 0xC9, 0xE8, 0xE5, 0x50, 0x5E, 0x2F, 0x02, 0x5F, 0x3E, 0x8B, 0xAB, 0x2F, 0x21, 0xA7, 0x9D, 0x2A, 0x00, 0x39, 0xAF, 0xC1, 0x67, 0xC3, 0xB7, 0xD4, 0xF9, 0xBC, 0xE0, 0xD9, 0x56, 0x2E, 0x12, 0xDF, 0x8A, 0xF7, 0xC2, 0x7C, 0xD1, 0x80, 0x99, 0xBB, 0x75, 0x5A, 0x1D, 0xDC, 0xAB, 0x21, 0x7B, 0x35, 0x8C, 0xC6, 0xF4, 0xBD, 0x3B, 0x60, 0x07, 0x08, 0x9A, 0x75, 0x0B, 0xA8, 0x03, 0x21, 0x0D, 0x06, 0xBC, 0xA1, 0x8F, 0x24, 0xA9, 0xC6, 0x3C, 0xDE, 0x1D, 0x35, 0xFA, 0xA3, 0x82, 0x5B, 0x12, 0x1F, 0x4C, 0x92, 0xC5, 0xF7, 0xD7, 0x29, 0x54, 0xBB, 0xDD, 0x5A, 0x7A, 0xD9, 0xFA, 0xC5, 0x6C, 0xFD, 0x12, 0xF4, 0x25, 0xD1, 0x17, 0xE7, 0x29, 0x7C, 0x4E, 0x05, 0x5B, 0x78, 0xA7, 0x6C, 0x95, 0x00, 0xB1, 0x0D, 0x25, 0x20, 0xCF, 0x4F, 0x71, 0xFA, 0x26, 0x0C, 0xFD, 0xFA, 0xF5, 0x7A, 0xED, 0xC2, 0x4A, 0x75, 0x60, 0x7C, 0xCE, 0x00, 0x1D, 0x2D, 0xCF, 0xC1, 0xA8, 0x6B, 0x02, 0xF6, 0xC8, 0x4D, 0xA6, 0x36, 0x0A, 0x98, 0x0C, 0x08, 0x0B, 0x60, 0x05, 0xE4, 0x01, 0x22, 0x00, 0x7F, 0xEC, 0xB0, 0x85, 0x01, 0x15, 0x20, 0xB3, 0x83, 0xC6, 0xB0, 0xCD, 0x08, 0x6F, 0x15, 0x29, 0xFE, 0x94, 0x86, 0x62, 0x6C, 0x1B, 0x9C, 0x5B, 0x3F, 0x11, 0x01, 0x75, 0x21, 0x9C, 0xA5, 0x5C, 0xA7, 0x4D, 0x08, 0x09, 0xDC, 0x35, 0x23, 0x2B, 0x57, 0x7A, 0xD7, 0x47, 0x1F, 0xA9, 0x11, 0xD6, 0x38, 0x80, 0x17, 0x10, 0xBA, 0x92, 0xF4, 0xBD, 0x81, 0xCC, 0x8C, 0x23, 0x73, 0xDF, 0x92, 0xFB, 0xDD, 0xC6, 0xF2, 0xD7, 0xC3, 0x68, 0x6A, 0x2E, 0xE7, 0x67, 0x38, 0x96, 0xD7, 0x3E, 0xEA, 0xCC, 0xA3, 0x74, 0x1D, 0x9F, 0xC6, 0x33, 0x09, 0x30, 0x01, 0x82, 0x80, 0xEA, 0x34, 0x13, 0x3B, 0x10, 0xD3, 0xCE, 0x2D, 0x0D, 0x1E, 0x9F, 0x2A, 0xC0, 0x13, 0xB0, 0x46, 0xCC, 0x8F, 0xC4, 0x1D, 0x33, 0xB9, 0x67, 0x9A, 0x9B, 0xE5, 0x80, 0x12, 0x12, 0x5A, 0xAD, 0xD2, 0x7B, 0xB7, 0x54, 0x24, 0x63, 0x8C, 0xF1, 0x82, 0x13, 0x59, 0x46, 0x6E, 0x41, 0xCF, 0x8D, 0xDD, 0xEA, 0x3D, 0x3A, 0x4C, 0xAE, 0x9E, 0x1B, 0xDE, 0xD0, 0xFD, 0x29, 0x9E, 0x19, 0xB0, 0x91, 0x96, 0x3D, 0x7D, 0x47, 0x3F, 0xD6, 0x98, 0x81, 0xF4, 0x71, 0xF2, 0x19, 0x99, 0xB4, 0x00, 0x58, 0x81, 0x43, 0x93, 0x71, 0x03, 0xD2, 0x1B, 0xD4, 0x48, 0xA0, 0xE6, 0x3B, 0xDF, 0x06, 0xF7, 0x00, 0x82, 0x1B, 0xD1, 0xF0, 0x86, 0x36, 0x02, 0xA8, 0x1E, 0xFA, 0xE1, 0x09, 0x9A, 0x76, 0x76, 0x53, 0xBF, 0xB3, 0xA9, 0x46, 0x7C, 0x05, 0x03, 0x32, 0xC1, 0xCC, 0x68, 0x3A, 0xEA, 0xDC, 0xFD, 0x43, 0x3B, 0x8F, 0xFB, 0x9D, 0xAF, 0xA0, 0xA5, 0x4C, 0xD0, 0x46, 0x98, 0x24, 0x7A, 0x35, 0xBD, 0x79, 0xC6, 0x68, 0x24, 0x37, 0x72, 0x0F, 0x90, 0x58, 0x4D, 0xEC, 0x7E, 0x3B, 0xB2, 0x23, 0x30, 0x50, 0x26, 0x04, 0xF0, 0x29, 0x3B, 0x06, 0x18, 0xDF, 0x44, 0xBE, 0xEA, 0x00, 0xD6, 0x50, 0x01, 0x9C, 0x81, 0x10, 0x20, 0x1B, 0x35, 0xA1, 0x67, 0x80, 0x1E, 0xFD, 0x8D, 0x48, 0xA0, 0xAC, 0xF1, 0x7E, 0x92, 0xC1, 0x63, 0xD4, 0x32, 0x2F, 0x02, 0x9B, 0x9E, 0xC5, 0x6E, 0xFE, 0x22, 0x1C, 0x39, 0x98, 0x21, 0x33, 0xA9, 0xDA, 0xF9, 0x17, 0x6A, 0x31, 0x48, 0xEE, 0x24, 0x39, 0x2D, 0x51, 0x8E, 0x3C, 0x8F, 0x56, 0x02, 0xCF, 0x4D, 0x6D, 0x82, 0x66, 0x05, 0x54, 0x23, 0x03, 0x88, 0x03, 0x78, 0x23, 0x73, 0xCF, 0xA0, 0x57, 0x4E, 0x22, 0x66, 0x3F, 0x2E, 0xD5, 0xB0, 0xC6, 0xB1, 0xED, 0xFD, 0xE4, 0xFD, 0x45, 0xE9, 0xC5, 0x31, 0x53, 0x5F, 0x7C, 0x3A, 0x4C, 0x01, 0x58, 0x02, 0xA9, 0xFB, 0x97, 0x17, 0x01, 0xDC, 0x80, 0xA4, 0x86, 0x35, 0xBC, 0x11, 0x8F, 0x06, 0x05, 0x03, 0xA2, 0x1D, 0x34, 0x7F, 0x0D, 0x69, 0x60, 0xCF, 0xD5, 0x3E, 0x82, 0x47, 0xE5, 0xDB, 0xEE, 0x6A, 0x6E, 0x0B, 0xEC, 0x2D, 0xF8, 0xCC, 0x10, 0x01, 0x7E, 0x54, 0x47, 0x75, 0x35, 0x6E, 0x5F, 0x9B, 0x3D, 0x88, 0x39, 0xCC, 0x81, 0x70, 0xBF, 0xC2, 0xB5, 0xC1, 0xC0, 0x75, 0xC8, 0xAA, 0x5E, 0x29, 0xAB, 0x8F, 0x1F, 0x0F, 0x0D, 0x06, 0x84, 0x05, 0x70, 0x6D, 0x14, 0x10, 0xD1, 0x13, 0xD3, 0x07, 0xE0, 0x04, 0x34, 0x00, 0x4B, 0x20, 0x14, 0x28, 0x42, 0x03, 0xED, 0x39, 0x00, 0x15, 0xA0, 0x0C, 0x38, 0x01, 0x71, 0x1A, 0x05, 0x64, 0x6E, 0x6D, 0x48, 0x72, 0x40, 0x0E, 0x30, 0x9D, 0x1C, 0x11, 0x5F, 0x2D, 0xAA, 0x44, 0xD0, 0xD4, 0xCD, 0x35, 0xF7, 0x75, 0x64, 0x26, 0xCB, 0x70, 0x74, 0x4F, 0x81, 0xAF, 0x47, 0x26, 0x2E, 0x97, 0x99, 0x6B, 0x8E, 0xCC, 0xED, 0x19, 0xF7, 0x9C, 0x8B, 0x3A, 0x33, 0xA0, 0x07, 0x10, 0x05, 0xE8, 0x4D, 0x79, 0xD4, 0xEE, 0xC9, 0xCA, 0x9C, 0x4B, 0xEA, 0x23, 0xE4, 0x6E, 0xFD, 0x7A, 0x75, 0x80, 0xFB, 0xB5, 0x9C, 0x07, 0x10, 0x06, 0xA6, 0x92, 0xCA, 0x79, 0x6F, 0x1E, 0x53, 0x3C, 0xDB, 0xE2, 0x67, 0xA5, 0x3B, 0x51, 0x24, 0x05, 0xC4, 0xD4, 0xE3, 0x1A, 0x66, 0x0D, 0x02, 0x44, 0x81, 0x13, 0xF3, 0x78, 0x6C, 0x6B, 0x16, 0x97, 0x0E, 0x5A, 0xA2, 0x7D, 0x97, 0x31, 0x51, 0x4C, 0x2C, 0xBB, 0x3D, 0x0D, 0xED, 0x1D, 0x7C, 0x2A, 0xA0, 0x30, 0x2F, 0x08, 0x9A, 0x08, 0xAD, 0x29, 0x82, 0xA0, 0x47, 0xD1, 0x8A, 0x9F, 0x44, 0xA3, 0xD0, 0xE3, 0x51, 0x7C, 0x1E, 0x8F, 0x62, 0x05, 0xAA, 0x63, 0x97, 0xD6, 0x41, 0xF3, 0x6D, 0xB0, 0x40, 0x67, 0xDB, 0x85, 0xD3, 0x84, 0xB0, 0x00, 0x3F, 0x8D, 0x09, 0x6F, 0xDC, 0x22, 0xDD, 0x76, 0xAA, 0x2C, 0x7E, 0x8E, 0x1F, 0x05, 0x54, 0xEC, 0xB6, 0x19, 0x67, 0x20, 0x07, 0x07, 0x08, 0x06, 0xCC, 0x01, 0x55, 0xC0, 0x1A, 0x35, 0xA7, 0xB4, 0xFA, 0x82, 0x96, 0xA2, 0x9F, 0x1A, 0x18, 0x9D, 0x5D, 0x2A, 0x36, 0x0A, 0xFC, 0x8B, 0x51, 0xE1, 0xDC, 0xC0, 0x84, 0x15, 0xC2, 0x73, 0x3A, 0x7B, 0x57, 0x5A, 0x3D, 0xA5, 0x62, 0x02, 0x54, 0x01, 0x11, 0x80, 0x02, 0x38, 0xDE, 0x60, 0xE0, 0x5A, 0xA4, 0x8C, 0xEA, 0xC4, 0xD8, 0x7B, 0x3E, 0x72, 0xD5, 0x7C, 0xB6, 0xEB, 0x82, 0x1E, 0xE0, 0x38, 0xC0, 0x53, 0xFB, 0xBA, 0x23, 0xEC, 0x1D, 0x8A, 0xD4, 0x7D, 0xB4, 0xF5, 0xD1, 0xFF, 0x66, 0x40, 0x0A, 0x88, 0x7C, 0x8C, 0x52, 0xB3, 0x61, 0x80, 0x1E, 0x80, 0x0A, 0x38, 0x02, 0x90, 0x02, 0xC1, 0x08, 0x5A, 0x76, 0x87, 0xF8, 0xB1, 0x2F, 0xD7, 0x51, 0x6A, 0x7F, 0xF2, 0x6B, 0x0D, 0xA7, 0x6E, 0xB4, 0xA2, 0xE5, 0x3B, 0x5A, 0x82, 0x79, 0x15, 0x4A, 0xD9, 0x3D, 0x7D, 0xF5, 0x64, 0x86, 0x92, 0x76, 0x2B, 0xB4, 0x5B, 0xC3, 0x01, 0x35, 0x80, 0x1F, 0xC5, 0x2F, 0x99, 0x32, 0xF2, 0x64, 0xA8, 0xA7, 0xAB, 0x2E, 0x27, 0xDD, 0xED, 0x4F, 0x39, 0xD8, 0x00, 0xD1, 0x49, 0x22, 0x7E, 0x70, 0x59, 0xDA, 0x72, 0x72, 0xA7, 0x62, 0x75, 0xCE, 0x7C, 0xDE, 0x41, 0x23, 0xA0, 0xAC, 0x63, 0x97, 0xC0, 0xC4, 0xE7, 0x38, 0x20, 0xD6, 0x60, 0x80, 0x6A, 0x4B, 0x3D, 0xA7, 0x03, 0x35, 0xE1, 0xAD, 0x0E, 0x1A, 0xB5, 0x59, 0x59, 0x27, 0xD0, 0x4A, 0x21, 0x6D, 0xC8, 0x02, 0x45, 0xFD, 0x92, 0x79, 0xCD, 0x8D, 0xAA, 0x12, 0x9A, 0x55, 0x4D, 0x56, 0x53, 0x42, 0xF0, 0xA3, 0xA8, 0x3F, 0x13, 0x11, 0xC6, 0xBB, 0x03, 0x52, 0x03, 0x60, 0xD9, 0x83, 0x03, 0x51, 0xCF, 0x64, 0xCB, 0xAC, 0x18, 0x79, 0x25, 0x9B, 0x6C, 0x3E, 0x01, 0xC6, 0x00, 0xD3, 0x92, 0x3B, 0x2F, 0x3B, 0xBF, 0xF2, 0xB3, 0xDC, 0x22, 0xA6, 0xD2, 0x5E, 0x69, 0xCA, 0x40, 0xC8, 0x8E, 0x1D, 0x3B, 0xE0, 0x0C, 0xE4, 0x40, 0x80, 0x08, 0xC0, 0xAD, 0xC1, 0x40, 0x4C, 0x40, 0xA5, 0x83, 0x36, 0x42, 0x43, 0x3D, 0x49, 0x55, 0x70, 0x40, 0x52, 0xD7, 0x3F, 0x5A, 0xE8, 0x53, 0x26, 0xBF, 0xD5, 0x5C, 0x45, 0x3A, 0xCD, 0x8C, 0xD0, 0x3D, 0xEA, 0xFF, 0x7C, 0x3C, 0x6B, 0xA5, 0x1B, 0x91, 0x20, 0x5A, 0xB0, 0x03, 0x88, 0x00, 0x54, 0x80, 0x8C, 0xDD, 0xE0, 0x48, 0xE9, 0x5D, 0x1D, 0x97, 0xD9, 0x91, 0xBD, 0x41, 0x1B, 0x2A, 0xC0, 0xEC, 0x38, 0xD3, 0x75, 0x3A, 0x3A, 0xF0, 0x93, 0xE1, 0x99, 0x5A, 0x68, 0x3E, 0xFE, 0xA5, 0xC2, 0x80, 0x2B, 0x90, 0xD5, 0x87, 0xE8, 0x04, 0xA8, 0xC1, 0x0E, 0x88, 0x02, 0x1A, 0x80, 0x1F, 0x20, 0x1A, 0xA9, 0x1D, 0x34, 0xE9, 0x99, 0xB4, 0xFC, 0xCE, 0x67, 0x14, 0xBF, 0x3D, 0xAD, 0x3A, 0xC9, 0x41, 0xF0, 0x8C, 0x85, 0xAA, 0x12, 0x6A, 0x04, 0x15, 0xB1, 0xFC, 0xA2, 0xEC, 0x35, 0xF1, 0x21, 0x02, 0x2A, 0x9E, 0x5D, 0xAC, 0x1E, 0x6B, 0x7F, 0x6F, 0xCC, 0xB7, 0xCC, 0xC5, 0x3E, 0xE7, 0x45, 0xF9, 0xE8, 0xE4, 0xAB, 0xAC, 0x1E, 0x0C, 0xAD, 0xED, 0xB5, 0x95, 0xFC, 0x48, 0x61, 0x5D, 0xB3, 0xF2, 0x98, 0x1B, 0xE4, 0x53, 0x8D, 0x9E, 0x19, 0x74, 0x01, 0x2C, 0x80, 0xAC, 0xED, 0x04, 0x62, 0xD2, 0x30, 0x40, 0x13, 0x10, 0x03, 0x38, 0x01, 0x25, 0x20, 0xAD, 0x83, 0xA6, 0xB8, 0x24, 0x14, 0xB7, 0x42, 0x0C, 0xA1, 0x60, 0x10, 0x89, 0x61, 0xBD, 0x16, 0xA7, 0x16, 0x8F, 0x4E, 0x02, 0x2B, 0x36, 0xE9, 0x38, 0x23, 0x9A, 0xF3, 0x88, 0x68, 0x2E, 0x4B, 0xBB, 0xFC, 0xFB, 0x5B, 0x47, 0xA3, 0x18, 0x70, 0x03, 0xC4, 0x81, 0x13, 0x00, 0xCD, 0xF3, 0x35, 0xEF, 0xFE, 0xC7, 0xD7, 0x3E, 0x1D, 0xE0, 0x18, 0x3D, 0x87, 0x47, 0x51, 0xED, 0xEC, 0x49, 0xEB, 0x8C, 0x79, 0xE8, 0xFA, 0x40, 0x28, 0xBB, 0x26, 0xEE, 0xD1, 0x67, 0x62, 0x05, 0x84, 0x00, 0xCF, 0x3D, 0x3B, 0x2C, 0xD6, 0xA8, 0x86, 0x00, 0xDC, 0x20, 0x03, 0x84, 0x80, 0xA4, 0x0E, 0xDA, 0x28, 0x0D, 0xF5, 0xF4, 0xA3, 0x40, 0x87, 0xF4, 0xA4, 0xC0, 0x7A, 0x96, 0x7B, 0x99, 0x17, 0xF5, 0x31, 0xB4, 0x60, 0x9A, 0x50, 0xBE, 0x44, 0x73, 0xE4, 0xB9, 0x79, 0x92, 0xAF, 0xA7, 0x8C, 0xEE, 0x45, 0x80, 0xCE, 0xBF, 0x1A, 0xB0, 0xB5, 0x41, 0xBF, 0x9D, 0x7F, 0x0E, 0x02, 0x7E, 0xBD, 0x17, 0x4A, 0x81, 0x30, 0xC0, 0x0B, 0x48, 0x7B, 0x93, 0xB2, 0xBF, 0xDA, 0x7D, 0x77, 0x02, 0xCE, 0xD1, 0x5F, 0x50, 0xD1, 0x1A, 0x55, 0xAF, 0xE5, 0xE6, 0x59, 0x3D, 0xB0, 0xC8, 0x06, 0xA8, 0x03, 0x66, 0x80, 0x3B, 0x10, 0x0A, 0xA4, 0xF7, 0xF8, 0xA2, 0x02, 0x74, 0x00, 0x99, 0x2D, 0xCD, 0xD7, 0x45, 0x20, 0x89, 0x20, 0xD2, 0x24, 0x8E, 0x59, 0x6C, 0xE2, 0xEE, 0x96, 0x49, 0x1C, 0x54, 0xBA, 0x4B, 0x39, 0xC2, 0x46, 0xAE, 0xFB, 0x19, 0xF2, 0x99, 0xB2, 0xD3, 0x54, 0x49, 0xA6, 0x92, 0x66, 0x8D, 0x03, 0xA8, 0x01, 0xC4, 0xE3, 0x40, 0xD4, 0xA0, 0x5F, 0x4D, 0xA9, 0xFE, 0xE6, 0x7B, 0x83, 0x11, 0x6C, 0x4E, 0xE0, 0x0C, 0x1C, 0xA0, 0x02, 0xE4, 0x00, 0x11, 0xBF, 0xF6, 0xE4, 0xB8, 0x42, 0x55, 0x34, 0x35, 0xF1, 0xF1, 0x70, 0x2E, 0x20, 0x3B, 0xAE, 0x24, 0x80, 0x1E, 0xC0, 0x09, 0x88, 0x46, 0x9E, 0xAD, 0xD8, 0x71, 0xF8, 0x1F, 0xDB, 0x9D, 0xCE, 0xD3, 0x19, 0xFD, 0xCA, 0x56, 0xDC, 0xD2, 0x2A, 0xBF, 0x77, 0xA8, 0xA7, 0xB5, 0x2E, 0xA2, 0xE1, 0x4F, 0x76, 0x6F, 0x99, 0x76, 0xC5, 0x4F, 0x1B, 0xF5, 0xD3, 0x4E, 0x4B, 0x7B, 0xB4, 0xD3, 0xF2, 0x9E, 0x18, 0x7C, 0xB7, 0xB3, 0xDA, 0x01, 0x68, 0x12, 0x57, 0x0A, 0x68, 0x02, 0xD6, 0xFB, 0xB8, 0x4F, 0x1F, 0xD0, 0x74, 0xF2, 0xF9, 0x6E, 0x12, 0x38, 0x3A, 0x0D, 0x0B, 0x80, 0x31, 0xC0, 0x09, 0x58, 0xC7, 0x65, 0x7C, 0x76, 0x46, 0xB6, 0xB0, 0x7A, 0xA1, 0x65, 0x6E, 0x71, 0x47, 0x4D, 0x20, 0xB5, 0x17, 0x5A, 0xC3, 0x1B, 0x69, 0x40, 0x49, 0x43, 0x1B, 0xB3, 0xD0, 0x18, 0x20, 0x03, 0x7C, 0x4E, 0x69, 0xD3, 0xC2, 0xD1, 0xFB, 0xE8, 0x4C, 0xFC, 0x1D, 0x6F, 0xD7, 0x7F, 0xC3, 0x04, 0xF7, 0xE8, 0x4C, 0x9A, 0xE3, 0x98, 0x53, 0x74, 0xC5, 0x59, 0xF1, 0x88, 0x21, 0x66, 0xF7, 0x84, 0xB1, 0xB6, 0x22, 0xF4, 0xDE, 0x00, 0xC9, 0x80, 0x3D, 0xB6, 0xE0, 0x21, 0x8D, 0xFE, 0x62, 0x2E, 0xC1, 0x9F, 0x76, 0xD4, 0x11, 0x74, 0x3F, 0x02, 0x05, 0x88, 0x01, 0x46, 0x80, 0x8F, 0x79, 0xA9, 0xFD, 0x5C, 0x75, 0xB5, 0x1F, 0x32, 0xEF, 0xF0, 0xCC, 0x33, 0x9A, 0xFD, 0x9D, 0xDF, 0x43, 0x03, 0x88, 0x02, 0x6E, 0x40, 0x56, 0xCF, 0x32, 0x0A, 0x40, 0x0D, 0x56, 0x40, 0x19, 0xF0, 0x03, 0x84, 0x00, 0x35, 0x87, 0xB4, 0xBA, 0x31, 0x63, 0x42, 0x0D, 0xC0, 0xBC, 0x7B, 0x12, 0x0E, 0xB4, 0x72, 0x58, 0xB0, 0xBD, 0x41, 0x9E, 0x81, 0xE0, 0x6B, 0x62, 0xE7, 0xBF, 0x1A, 0x7D, 0xD7, 0x09, 0x70, 0x3D, 0x94, 0xA8, 0x9B, 0x3C, 0x62, 0x99, 0x0E, 0x44, 0x00, 0xCE, 0x40, 0xD2, 0x8C, 0x2B, 0x4E, 0x83, 0xE3, 0x56, 0xD6, 0x57, 0x01, 0x4C, 0x01, 0x27, 0x20, 0x18, 0x48, 0x9D, 0x01, 0x8D, 0x5F, 0xEB, 0x77, 0xAF, 0x64, 0x8E, 0xDB, 0xF9, 0x43, 0x1D, 0xE4, 0x93, 0x80, 0x31, 0x90, 0xB4, 0x5D, 0x2F, 0x38, 0x01, 0x69, 0xA8, 0x03, 0x16, 0x80, 0x17, 0x90, 0x01, 0x60, 0xD5, 0xF1, 0x3D, 0xA3, 0x15, 0xBA, 0x0F, 0x0E, 0xC5, 0x97, 0xAC, 0xF5, 0xC8, 0x3F, 0xD9, 0x5E, 0xB2, 0xD0, 0xE8, 0xC3, 0xB6, 0x7F, 0x8C, 0xDA, 0x66, 0x0F, 0x13, 0x04, 0x95, 0xB2, 0xA7, 0xD7, 0xDF, 0xE3, 0x86, 0xEA, 0x53, 0x1D, 0x50, 0x80, 0x1E, 0x01, 0x1C, 0x2F, 0xC0, 0xB8, 0x71, 0xB3, 0x49, 0xFB, 0xDE, 0xC9, 0x83, 0x99, 0x0C, 0x52, 0x80, 0xE4, 0x19, 0xF8, 0x0A, 0x20, 0x57, 0xF3, 0xCB, 0xD2, 0xA0, 0xE4, 0x69, 0xCB, 0xD8, 0x2F, 0xD7, 0xE3, 0x00, 0x17, 0xE0, 0xB2, 0x9B, 0x92, 0xC5, 0x1A, 0xB2, 0xDF, 0xDB, 0x73, 0xFC, 0xAB, 0xFB, 0x09, 0x30, 0xED, 0xA0, 0xD1, 0xB7, 0x85, 0x89, 0x15, 0x44, 0x5F, 0x8E, 0xAD, 0x01, 0x3C, 0xCD, 0xD1, 0xED, 0x15, 0x0C, 0x9E, 0xE0, 0xB2, 0xEE, 0x1A, 0xBA, 0x24, 0xF5, 0xFD, 0xBC, 0xEA, 0xF0, 0xBC, 0x67, 0x2A, 0x94, 0x9F, 0x0C, 0xC7, 0x79, 0x85, 0x4B, 0x1A, 0xF5, 0xD3, 0x57, 0xD0, 0xAB, 0xAE, 0x76, 0x6E, 0x08, 0x1F, 0x81, 0x74, 0x06, 0xB4, 0xC1, 0x0A, 0xCC, 0x7D, 0x83, 0xEC, 0x67, 0x85, 0x44, 0x7C, 0x6F, 0xDB, 0xD1, 0x17, 0xAA, 0x9C, 0xC0, 0x38, 0xE0, 0xBE, 0xC5, 0xEB, 0x46, 0x5E, 0x79, 0x5C, 0xC0, 0xCB, 0x81, 0x48, 0xC0, 0x04, 0x10, 0xDE, 0xFA, 0x76, 0x27, 0x3B, 0x68, 0xDC, 0x46, 0x10, 0x0C, 0xBF, 0xC5, 0xF4, 0x09, 0xDA, 0x34, 0xC3, 0x43, 0xD0, 0x98, 0x15, 0x83, 0x4B, 0x62, 0x5F, 0x0E, 0xC3, 0xD5, 0xD7, 0x04, 0x81, 0xC6, 0xFF, 0x61, 0xDE, 0x90, 0x37, 0x30, 0x80, 0x1F, 0x40, 0x05, 0x10, 0x6D, 0x4C, 0x76, 0xE8, 0xCA, 0xC3, 0x6C, 0x71, 0x80, 0x4C, 0x40, 0x15, 0xE0, 0x81, 0x35, 0x78, 0xDF, 0xD5, 0x2A, 0x56, 0x47, 0xCB, 0xD4, 0x1A, 0xE4, 0xEF, 0xD5, 0xFD, 0x19, 0xD4, 0xB1, 0x00, 0x32, 0x7A, 0x51, 0x11, 0xA0, 0x03, 0xDD, 0x9F, 0xC4, 0x1B, 0x02, 0x68, 0x23, 0xB9, 0x83, 0x26, 0x48, 0x62, 0x66, 0xFE, 0x09, 0x45, 0x6E, 0x3B, 0xBF, 0x97, 0x08, 0xB5, 0x80, 0xA2, 0xB7, 0xE0, 0xA7, 0x62, 0x9F, 0x42, 0xEF, 0x8B, 0x86, 0xF9, 0x9A, 0x8F, 0xB5, 0xF3, 0x04, 0xED, 0x3E, 0x6D, 0x07, 0x08, 0x02, 0xFC, 0x00, 0xB3, 0xFC, 0xAA, 0xE1, 0x0D, 0x9B, 0x2E, 0xDD, 0x8E, 0xCF, 0x5B, 0xB8, 0xE2, 0xE8, 0xC0, 0x34, 0x84, 0x1A, 0x02, 0x70, 0x01, 0x93, 0xF6, 0xB8, 0xDD, 0xBD, 0x29, 0xBF, 0x8E, 0x8D, 0xBC, 0x32, 0xDB, 0x62, 0x5B, 0x2C, 0x4D, 0x1B, 0xB7, 0x78, 0xF3, 0x66, 0x80, 0xFD, 0xB1, 0x59, 0x8A, 0xC6, 0xF9, 0xBD, 0xC4, 0xE4, 0x16, 0xEF, 0x4A, 0x5B, 0x40, 0xA6, 0xBE, 0xBA, 0x80, 0x88, 0x5D, 0xE3, 0x0B, 0x21, 0xD8, 0x03, 0x92, 0xDF, 0x92, 0x67, 0xA8, 0xB5, 0x61, 0xB3, 0x6F, 0x81, 0x5B, 0x7B, 0xFC, 0xB5, 0x68, 0x9E, 0xAF, 0x91, 0x0A, 0xED, 0x4F, 0x55, 0x80, 0x2B, 0x20, 0x53, 0xE3, 0x0C, 0xE0, 0xA6, 0xC6, 0xEA, 0x7A, 0x6B, 0xEE, 0x97, 0x44, 0x1D, 0x80, 0x65, 0x5A, 0xEA, 0x00, 0x06, 0x72, 0xEA, 0x58, 0xBB, 0x29, 0x68, 0x84, 0x20, 0x3A, 0x76, 0xB7, 0x32, 0xE3, 0x37, 0xCD, 0x3F, 0x4E, 0x40, 0xCC, 0xC0, 0x58, 0x23, 0x91, 0x3E, 0xD6, 0xE4, 0xD6, 0x10, 0x40, 0xA2, 0x91, 0x80, 0x1D, 0xA0, 0xAC, 0x83, 0x76, 0x6F, 0x03, 0xE3, 0x26, 0x8E, 0xA0, 0x1D, 0x42, 0x47, 0xC2, 0xCC, 0x21, 0x29, 0x75, 0x6F, 0x39, 0xFD, 0x81, 0x30, 0x9D, 0xAD, 0xCB, 0x7A, 0xC4, 0x73, 0x85, 0x9A, 0x2B, 0x38, 0xF1, 0xDE, 0xD0, 0xC9, 0x9F, 0xB1, 0x55, 0x05, 0xB8, 0x7E, 0x21, 0x8C, 0xAB, 0x26, 0x2C, 0x73, 0x71, 0xB0, 0x7A, 0x67, 0x2A, 0x80, 0x90, 0xC7, 0x4F, 0x40, 0x80, 0x71, 0xC1, 0x9B, 0x84, 0x97, 0xD7, 0xEF, 0x5E, 0x1E, 0xD7, 0x85, 0x67, 0x5E, 0x9B, 0xD2, 0x88, 0x7E, 0x19, 0x12, 0x01, 0xC2, 0x80, 0x1A, 0x60, 0x04, 0xF8, 0x01, 0x82, 0x81, 0x34, 0xA0, 0xC6, 0x04, 0x64, 0x1E, 0xCF, 0xB9, 0x0E, 0x40, 0xDA, 0x96, 0xBD, 0xFD, 0x77, 0xD9, 0xA1, 0xA7, 0x56, 0x84, 0x4B, 0x2F, 0x77, 0xC3, 0x90, 0x29, 0x84, 0xBD, 0x88, 0x96, 0x74, 0x9A, 0xDB, 0x73, 0xE4, 0x38, 0xB3, 0x29, 0x75, 0x44, 0xC2, 0x00, 0x0B, 0x80, 0xAF, 0xC4, 0x09, 0xA0, 0x02, 0xC8, 0xFA, 0x62, 0xDC, 0x91, 0x4B, 0x23, 0xC0, 0x65, 0x27, 0x6F, 0x2B, 0xF7, 0x54, 0x26, 0xC7, 0xB2, 0x7E, 0xA3, 0x79, 0xFD, 0xCD, 0x4A, 0xEB, 0xF5, 0xA3, 0x7D, 0xB7, 0x1C, 0x45, 0xCD, 0xB8, 0x32, 0xDD, 0xE7, 0x00, 0xA2, 0x80, 0x25, 0xE0, 0x05, 0x44, 0x00, 0x69, 0x40, 0xBD, 0x82, 0xDE, 0x02, 0xF0, 0xBC, 0x3D, 0xA3, 0xB3, 0x91, 0x89, 0x66, 0x2B, 0x52, 0x4C, 0xCB, 0x56, 0xF5, 0x28, 0x99, 0x63, 0x27, 0x85, 0x4A, 0x2B, 0x36, 0xBA, 0x6F, 0xD7, 0x93, 0xD8, 0x22, 0x7D, 0xBC, 0x3A, 0x12, 0xD6, 0x54, 0xF1, 0xE4, 0x7E, 0x14, 0x38, 0x4F, 0x6A, 0xDF, 0x14, 0x10, 0x69, 0xD4, 0x93, 0xE1, 0x9F, 0xE7, 0x33, 0xB4, 0x63, 0x41, 0xF8, 0x94, 0x0A, 0x98, 0x00, 0x7A, 0x00, 0x76, 0xC0, 0x3E, 0xF0, 0xD2, 0x45, 0xC3, 0x6E, 0xB6, 0xEC, 0xEC, 0x90, 0x76, 0x59, 0x1E, 0x70, 0x65, 0x7D, 0x69, 0x3F, 0x80, 0x27, 0x90, 0x8D, 0x92, 0x06, 0x01, 0x69, 0x0D, 0x07, 0xCA, 0xE7, 0x5E, 0xDF, 0x51, 0xEB, 0x03, 0xAC, 0x39, 0xC4, 0x94, 0x45, 0x56, 0x5E, 0x28, 0x8A, 0xBA, 0x95, 0x89, 0xBA, 0xEF, 0x15, 0x65, 0xD1, 0x23, 0xBE, 0x14, 0x73, 0xFC, 0x3C, 0x69, 0x5B, 0xE6, 0xC7, 0x27, 0x24, 0x00, 0xCA, 0x47, 0x13, 0x6C, 0xB0, 0x6C, 0x6A, 0xA4, 0x3F, 0xD9, 0x1D, 0x31, 0x76, 0x07, 0xCA, 0x00, 0x71, 0x80, 0x68, 0xE3, 0x18, 0x30, 0xE9, 0x5E, 0xA5, 0xD5, 0xDB, 0xE8, 0xB7, 0x41, 0x4A, 0xCE, 0xF6, 0x94, 0x62, 0x06, 0xCC, 0x81, 0xE2, 0xDD, 0x07, 0x64, 0xD2, 0xB0, 0x06, 0x03, 0x2A, 0x80, 0x3C, 0xEF, 0x85, 0xAC, 0x0E, 0x5A, 0xE1, 0x71, 0x23, 0x2B, 0x98, 0x7A, 0x9E, 0x84, 0x3F, 0x25, 0x1B, 0x0E, 0xCE, 0xA9, 0x63, 0x87, 0x39, 0xFF, 0x3B, 0x0E, 0xBB, 0xB4, 0x47, 0x7C, 0xE2, 0x3C, 0x95, 0x62, 0x5E, 0xB6, 0x91, 0x4B, 0xB3, 0xDC, 0x01, 0x7B, 0x64, 0xDF, 0x93, 0x1B, 0x4F, 0x92, 0x43, 0x6B, 0x52, 0xAD, 0xDB, 0x03, 0xF7, 0x78, 0xE3, 0x00, 0x4C, 0xC0, 0x74, 0x97, 0xCD, 0x20, 0xC5, 0xCC, 0xB5, 0xA4, 0xCF, 0xD6, 0xD3, 0x1D, 0x3D, 0x63, 0xB3, 0x26, 0x58, 0x02, 0x64, 0x40, 0x78, 0xDF, 0x95, 0x04, 0xB0, 0x02, 0xC2, 0x80, 0x6C, 0xDD, 0x97, 0x43, 0x8F, 0x24, 0x70, 0x02, 0xC6, 0x40, 0xFB, 0x88, 0x8F, 0x2B, 0xA2, 0x16, 0x44, 0x6E, 0xD3, 0x7D, 0xD7, 0xA2, 0xA4, 0x7A, 0x28, 0x0B, 0xCE, 0x34, 0x8A, 0xE3, 0x2D, 0x15, 0x9A, 0xD3, 0x34, 0xD7, 0xD8, 0xE2, 0xB6, 0xAC, 0x77, 0x20, 0xF9, 0x59, 0x5D, 0x06, 0x38, 0x03, 0xDA, 0xE0, 0x6C, 0x18, 0xE0, 0x33, 0x57, 0x35, 0x4A, 0xA4, 0x06, 0xCC, 0x61, 0x39, 0x0F, 0xE0, 0x0A, 0x04, 0xF0, 0x5C, 0x3B, 0xFC, 0x76, 0x24, 0x17, 0xDF, 0x31, 0xF8, 0xED, 0x54, 0x9C, 0xBE, 0xF3, 0x8C, 0x63, 0x0A, 0xC2, 0x05, 0x78, 0x02, 0x59, 0x40, 0x69, 0xC3, 0x1B, 0xDC, 0x18, 0x9B, 0x03, 0x05, 0x24, 0x3B, 0x6A, 0xD4, 0x7D, 0xAC, 0x0A, 0xED, 0x1C, 0x96, 0x3F, 0x01, 0x35, 0x21, 0xFC, 0x7B, 0xB8, 0xCC, 0x4B, 0x00, 0x35, 0xA1, 0x0C, 0xB4, 0x17, 0x43, 0x20, 0x40, 0x6E, 0xD4, 0xA4, 0x59, 0xF8, 0xCC, 0xF7, 0xE8, 0x25, 0x8D, 0x7A, 0x54, 0x7D, 0xE5, 0x9A, 0xD5, 0x03, 0x16, 0x80, 0x28, 0xF0, 0xCA, 0xE3, 0x86, 0x01, 0x2A, 0xF3, 0xF4, 0x3E, 0x51, 0x2B, 0x20, 0xAB, 0xBF, 0x65, 0x4B, 0x0D, 0xD1, 0xED, 0x92, 0x0D, 0xFF, 0x65, 0xD9, 0xF8, 0x0A, 0x18, 0xDA, 0x68, 0x15, 0x2A, 0xE0, 0x07, 0xA8, 0x9A, 0x06, 0x0D, 0x40, 0x06, 0xDE, 0x08, 0x40, 0x19, 0x30, 0x03, 0x8A, 0x3B, 0x6A, 0xDC, 0xCE, 0x04, 0xF4, 0xA7, 0xBE, 0xF7, 0x3D, 0xAD, 0x62, 0xB1, 0xB0, 0xB5, 0x44, 0x03, 0x7E, 0x30, 0xE1, 0x3E, 0xCD, 0x17, 0xFF, 0xC3, 0xC9, 0xE7, 0xD8, 0x33, 0x7C, 0x01, 0xEC, 0xDA, 0xDD, 0x92, 0x20, 0xCD, 0xC7, 0x68, 0x2B, 0x00, 0x7F, 0xE4, 0x14, 0xEA, 0x00, 0x12, 0xFB, 0x36, 0x21, 0x0E, 0x68, 0xC3, 0xCE, 0x36, 0xC1, 0xE1, 0xB3, 0x86, 0x7F, 0xF5, 0x6F, 0x2E, 0xBB, 0xA6, 0xA2, 0x3F, 0xE9, 0x08, 0x20, 0xE6, 0x05, 0x51, 0x40, 0xC8, 0xCE, 0xEA, 0x4E, 0x5E, 0xA6, 0x0A, 0xC8, 0xA7, 0xD9, 0x28, 0xFB, 0x5B, 0x74, 0x1E, 0xD0, 0xBF, 0xC3, 0x77, 0x69, 0x98, 0xC1, 0xF8, 0x3D, 0xA0, 0xE5, 0xFD, 0xEA, 0x54, 0x42, 0xA2, 0x90, 0x0C, 0x61, 0x71, 0xDE, 0xDD, 0xA3, 0xEF, 0xFD, 0x93, 0x6A, 0x5B, 0x40, 0x1D, 0x7B, 0xCC, 0xA2, 0x08, 0x30, 0x06, 0xC4, 0x1A, 0xB4, 0x83, 0xA6, 0xB7, 0x0A, 0x0A, 0x9C, 0xF3, 0x54, 0x4F, 0xE7, 0x93, 0xED, 0x27, 0x79, 0x5E, 0xD1, 0x21, 0x4B, 0xDE, 0x29, 0xEE, 0x9B, 0x93, 0xA7, 0xF9, 0x67, 0xD6, 0xC8, 0x34, 0xCC, 0x10, 0x50, 0x34, 0xA6, 0x98, 0x80, 0x38, 0xA0, 0x09, 0x38, 0x03, 0xD1, 0xA8, 0x3E, 0xA7, 0x1C, 0x06, 0x48, 0x3A, 0x68, 0xDF, 0x6B, 0x51, 0x53, 0xEC, 0x3B, 0xA4, 0x71, 0x25, 0x0E, 0xB8, 0x49, 0x18, 0xE8, 0xCA, 0x6C, 0xC9, 0x82, 0xC0, 0x7B, 0x14, 0x75, 0x4F, 0xEF, 0x13, 0x71, 0xCA, 0xDB, 0x3D, 0x3A, 0xBB, 0xD9, 0xE8, 0xCF, 0xF8, 0xE3, 0x83, 0x77, 0xCF, 0x63, 0x06, 0xA8, 0x00, 0x73, 0xE3, 0x4C, 0xD9, 0x3E, 0x78, 0x93, 0xF9, 0x0D, 0x6B, 0x10, 0x70, 0x66, 0xA2, 0x87, 0xB7, 0xBA, 0x06, 0x3B, 0x50, 0xBA, 0x6C, 0x7A, 0xA3, 0xDB, 0xCC, 0x10, 0x51, 0x9C, 0xC0, 0x74, 0x0B, 0xF4, 0xD5, 0xE4, 0xB4, 0xBB, 0x4D, 0x84, 0x09, 0xB0, 0x00, 0xC2, 0x81, 0x6A, 0x49, 0xE4, 0xC3, 0x00, 0x39, 0xC0, 0x05, 0xA8, 0x02, 0x3E, 0x41, 0xB3, 0x35, 0x49, 0xE6, 0x81, 0x9A, 0xB1, 0x1F, 0x6B, 0xEF, 0x0C, 0x6A, 0x87, 0x5B, 0xC4, 0x4E, 0xCD, 0xBA, 0x66, 0x52, 0xBF, 0x1A, 0x81, 0xBF, 0xA6, 0x34, 0xB7, 0x89, 0xAF, 0xAE, 0x35, 0x36, 0xE0, 0x05, 0x9C, 0xB3, 0x24, 0x21, 0xBC, 0xBF, 0x93, 0x12, 0xF8, 0x6B, 0x97, 0x31, 0x6D, 0x17, 0x6F, 0x9B, 0x68, 0x00, 0x46, 0x40, 0xE8, 0x36, 0xC1, 0x98, 0xD4, 0x4F, 0xE4, 0x4F, 0x0E, 0x1E, 0xF9, 0x75, 0x24, 0x5D, 0xA7, 0xF1, 0xA5, 0xDB, 0x59, 0xB4, 0xF0, 0xFA, 0xE4, 0x00, 0x52, 0x9F, 0x8C, 0x63, 0xE3, 0x7D, 0x99, 0x96, 0xF4, 0x5B, 0xD4, 0x00, 0x39, 0x80, 0x9D, 0x8E, 0x99, 0x77, 0xBF, 0x77, 0x7C, 0x07, 0x5B, 0x0F, 0x5F, 0xDE, 0x81, 0xEC, 0xD9, 0x6D, 0xAC, 0xD5, 0xE7, 0x4A, 0x81, 0xE2, 0x31, 0xFB, 0x9A, 0xC5, 0xB6, 0xF3, 0x2C, 0xB4, 0x69, 0x47, 0x38, 0x01, 0x30, 0x03, 0x44, 0x8F, 0x67, 0xA5, 0x00, 0x6E, 0x40, 0xF4, 0xB7, 0x68, 0x6E, 0xFF, 0xC4, 0x74, 0xA0, 0x02, 0x90, 0x03, 0x9C, 0x00, 0x48, 0x1B, 0x09, 0xC4, 0x0A, 0x3D, 0xE9, 0x6D, 0x24, 0x60, 0x9D, 0x53, 0x55, 0xEF, 0xF5, 0xBE, 0x9F, 0x4E, 0x35, 0xA0, 0x74, 0x2B, 0x16, 0x86, 0x34, 0xAA, 0x11, 0x0D, 0x6E, 0x1C, 0x60, 0x7A, 0xB1, 0x64, 0xDE, 0x03, 0xF1, 0x3F, 0x6A, 0x39, 0x29, 0xAD, 0x5B, 0xA7, 0x2D, 0xFF, 0x82, 0x69, 0x28, 0x68, 0x61, 0x8A, 0xE1, 0x58, 0x2A, 0xB9, 0xEF, 0xEC, 0xF9, 0x4C, 0xFD, 0xDB, 0x9A, 0x19, 0xC3, 0x01, 0x7A, 0x29, 0x65, 0x7A, 0x02, 0x72, 0x76, 0x08, 0x5D, 0x1A, 0x0A, 0xD4, 0xD9, 0xDA, 0xD5, 0x7A, 0x4D, 0x15, 0x01, 0xF7, 0x47, 0x10, 0x72, 0x7D, 0xCB, 0xBC, 0x07, 0x88, 0xAE, 0x9A, 0x82, 0xC7, 0xCE, 0xE8, 0xBA, 0x4F, 0x37, 0xE5, 0x73, 0x75, 0x3F, 0x80, 0x35, 0xDC, 0x81, 0x3C, 0x40, 0xF1, 0xBE, 0x42, 0xB1, 0x00, 0xA2, 0x80, 0xCE, 0x91, 0x23, 0xBB, 0x22, 0x3A, 0x6F, 0xCD, 0xD6, 0x85, 0x54, 0x85, 0xE5, 0x4F, 0x06, 0x9A, 0x8C, 0x2A, 0x20, 0xBC, 0xA3, 0x81, 0xC9, 0xA8, 0xA8, 0x3D, 0x84, 0x07, 0x4E, 0x57, 0x02, 0xDF, 0xC3, 0x85, 0x5D, 0x71, 0xCB, 0x7F, 0x69, 0x50, 0x27, 0xA0, 0x04, 0x9C, 0x04, 0xE8, 0x00, 0xDA, 0xB0, 0x47, 0x55, 0xF9, 0xB4, 0x8A, 0x66, 0xE4, 0x8E, 0xD6, 0x11, 0xC0, 0xEA, 0xA7, 0xF3, 0x7A, 0xCF, 0xCF, 0x63, 0x64, 0x2C, 0x5D, 0x94, 0xF2, 0x7E, 0x33, 0xC6, 0xBD, 0x70, 0x1E, 0x01, 0x2C, 0x11, 0x03, 0x22, 0x40, 0x4F, 0xC3, 0x1A, 0x0E, 0x48, 0x36, 0x0C, 0xD0, 0x00, 0x8A, 0x3A, 0x68, 0x53, 0x25, 0x80, 0x0D, 0x41, 0xA4, 0xE2, 0x75, 0x10, 0x8C, 0x3F, 0xB2, 0xAF, 0xA6, 0xE2, 0xD2, 0xA9, 0x85, 0x82, 0x1A, 0xA1, 0xDA, 0x94, 0xA1, 0x9E, 0xA0, 0xD1, 0x4F, 0x6B, 0xCE, 0xAF, 0xCE, 0xD1, 0x91, 0x79, 0xB5, 0xED, 0x94, 0xB5, 0xCD, 0xF0, 0xD4, 0x23, 0x36, 0x18, 0xB2, 0x6D, 0x2D, 0xB3, 0x00, 0x79, 0x84, 0x50, 0xA4, 0x61, 0x0E, 0xC4, 0xEA, 0x19, 0xC1, 0xC5, 0x60, 0xEA, 0xA5, 0xDD, 0x3A, 0x20, 0x3F, 0x3D, 0xDB, 0xB8, 0x9B, 0xD9, 0xDD, 0xB0, 0x7A, 0xA7, 0x52, 0x07, 0x4A, 0x5B, 0xE7, 0x91, 0x01, 0x25, 0xC0, 0x12, 0x48, 0xEA, 0x5A, 0x80, 0x03, 0x54, 0x80, 0x1A, 0x82, 0x46, 0x7D, 0x36, 0xAD, 0xA8, 0x3F, 0xD5, 0x25, 0xDC, 0xFC, 0x0C, 0xE5, 0x0D, 0x57, 0x10, 0xE2, 0x9E, 0xAD, 0xC6, 0x1B, 0x20, 0x02, 0xAD, 0x56, 0x47, 0x65, 0x27, 0x22, 0xB3, 0x59, 0x37, 0x37, 0x4B, 0xFB, 0xC4, 0x4E, 0x36, 0x75, 0x77, 0xC0, 0x0A, 0xE0, 0x79, 0x16, 0x09, 0x08, 0x06, 0xB2, 0xF6, 0x02, 0xCC, 0x03, 0x88, 0x3E, 0x5A, 0xFC, 0xB9, 0x3F, 0xE5, 0x72, 0xDA, 0x98, 0x41, 0x2B, 0x34, 0x51, 0xCF, 0xD9, 0x7E, 0x0E, 0xA4, 0xF3, 0xBC, 0x75, 0xF1, 0x78, 0x0A, 0x29, 0xB2, 0xD3, 0x3D, 0xD2, 0x30, 0x06, 0x3C, 0x80, 0x28, 0xA0, 0x1C, 0xC1, 0x27, 0x05, 0xD8, 0x81, 0x79, 0x15, 0xD0, 0xFF, 0xAA, 0xCD, 0x79, 0xDE, 0x5E, 0x2B, 0xA6, 0x9C, 0x37, 0x39, 0x26, 0x25, 0x95, 0x91, 0x68, 0xE5, 0x98, 0xE9, 0xD8, 0x27, 0xD5, 0x41, 0x4F, 0x7E, 0xE8, 0x51, 0x1D, 0xE4, 0xF3, 0x38, 0x28, 0x1A, 0x40, 0xF2, 0xA8, 0x01, 0x07, 0x60, 0xB6, 0x1F, 0xD0, 0xA8, 0x47, 0x1B, 0xD8, 0x80, 0xB2, 0xAD, 0xF5, 0x3D, 0x5D, 0x47, 0xEC, 0xBF, 0xE1, 0xAF, 0xC9, 0x66, 0xC8, 0xB9, 0x2E, 0x3E, 0x59, 0xFB, 0x35, 0xCA, 0x0A, 0x54, 0xBF, 0x46, 0xB5, 0x11, 0x02, 0x54, 0xBF, 0x46, 0x89, 0x01, 0x11, 0xC0, 0x02, 0x88, 0x03, 0xD4, 0x04, 0x8D, 0xE1, 0xE6, 0x16, 0xFC, 0x5F, 0xFD, 0x34, 0x9C, 0x75, 0xE9, 0xD6, 0x66, 0x5C, 0xA5, 0x97, 0x0D, 0x82, 0x56, 0xFF, 0xBC, 0x12, 0xD0, 0x23, 0x63, 0x25, 0xDA, 0x88, 0x46, 0xEE, 0xC0, 0xE4, 0x5C, 0x99, 0xF8, 0xA7, 0x12, 0x36, 0xB9, 0x7D, 0xA6, 0x06, 0x32, 0x6E, 0xE3, 0x1E, 0x83, 0x33, 0xFD, 0xEA, 0x56, 0xD0, 0x86, 0xFC, 0x55, 0x77, 0xA1, 0xAD, 0x1A, 0x37, 0x1A, 0x55, 0xD9, 0x88, 0x68, 0x18, 0x90, 0xBC, 0x35, 0xE4, 0x2C, 0x80, 0xF4, 0xC6, 0x01, 0x9C, 0x01, 0x51, 0x80, 0x1C, 0x10, 0x02, 0x66, 0x57, 0x23, 0xC1, 0x09, 0x84, 0xA2, 0x5B, 0x48, 0x0C, 0x9B, 0x5B, 0x79, 0xB7, 0xA4, 0x1B, 0x32, 0x91, 0xFD, 0xDF, 0x3C, 0x31, 0xB0, 0x92, 0x95, 0x5B, 0x00, 0xC6, 0xDE, 0x79, 0xCF, 0xB9, 0x75, 0xDE, 0x2A, 0x1B, 0x50, 0x35, 0x85, 0x26, 0x80, 0x1A, 0x22, 0x88, 0x16, 0xBE, 0x88, 0xFC, 0xF2, 0xCC, 0x66, 0x21, 0x3E, 0x34, 0x46, 0x93, 0x93, 0x06, 0xEB, 0xA0, 0x69, 0xCF, 0xCF, 0x8D, 0x4B, 0xC5, 0x8C, 0x68, 0xD6, 0x60, 0xC4, 0xDE, 0x65, 0x7C, 0x91, 0x00, 0x6D, 0x78, 0x23, 0x0A, 0x28, 0xDD, 0x3D, 0x90, 0x71, 0xC5, 0x8C, 0x1A, 0xD6, 0x4F, 0xF7, 0x01, 0xDC, 0x00, 0x9B, 0x4F, 0x77, 0x5E, 0xAF, 0x83, 0xA6, 0xF0, 0xF1, 0xD4, 0x57, 0xB2, 0xB5, 0x37, 0xC3, 0xC9, 0xDB, 0x1E, 0xEA, 0x2A, 0x8E, 0xA3, 0x2A, 0x62, 0xCF, 0xA1, 0x83, 0x9E, 0x06, 0x35, 0x8A, 0xE7, 0xA4, 0xE6, 0x8D, 0x6A, 0xE8, 0x5E, 0x70, 0xAE, 0x53, 0x84, 0x1A, 0x7B, 0xA4, 0x55, 0xB6, 0xEC, 0x5F, 0xE9, 0x66, 0xB5, 0x68, 0x86, 0xEA, 0x7A, 0x71, 0xC4, 0x54, 0x50, 0x6E, 0x1B, 0x87, 0xF1, 0x1E, 0x3F, 0x37, 0x01, 0x98, 0xB7, 0x63, 0x57, 0xF9, 0x60, 0xBE, 0x08, 0xB0, 0x02, 0x7E, 0x80, 0x24, 0x20, 0x12, 0xF0, 0x86, 0x36, 0x24, 0x00, 0x75, 0xA0, 0xB4, 0x83, 0x66, 0x5F, 0xF1, 0xB3, 0x34, 0x51, 0xC3, 0xD6, 0x9A, 0xA0, 0xE1, 0xC1, 0xA7, 0x91, 0x9F, 0x76, 0xFC, 0x91, 0x78, 0x3C, 0xC5, 0xC4, 0xB7, 0x48, 0xFC, 0xFF, 0xDA, 0x85, 0x08, 0x50, 0xF1, 0x0F, 0x95, 0x56, 0xE2, 0x46, 0x02, 0x12, 0x40, 0xF9, 0x0C, 0x94, 0x3D, 0x82, 0x7D, 0x11, 0x1D, 0xA0, 0x04, 0x38, 0x67, 0x28, 0xB8, 0xE3, 0xE4, 0xE3, 0x2E, 0xBC, 0xDB, 0xB5, 0xE5, 0xE9, 0xC5, 0x66, 0x02, 0xA4, 0x00, 0x93, 0x1D, 0xA0, 0xA0, 0x3D, 0x84, 0xAC, 0x0C, 0x78, 0x34, 0x1C, 0x30, 0x06, 0x44, 0x00, 0x26, 0x40, 0x1A, 0xE9, 0x1D, 0x35, 0x38, 0xFB, 0x3B, 0xD9, 0xBB, 0xD4, 0xF0, 0x02, 0x09, 0xC1, 0xF3, 0x29, 0xD1, 0x11, 0x4D, 0x88, 0x1F, 0x10, 0x9A, 0xAD, 0xF8, 0x6D, 0xB6, 0xE2, 0xED, 0x27, 0x2E, 0x04, 0xF8, 0x80, 0x1B, 0xFA, 0xBC, 0x59, 0xF3, 0x67, 0xA6, 0x9E, 0xC0, 0x68, 0xC7, 0x4D, 0x3B, 0xCF, 0x34, 0x17, 0xE0, 0x54, 0x35, 0x23, 0x15, 0xD3, 0x61, 0x26, 0xD3, 0xA2, 0xF0, 0x93, 0x07, 0xCB, 0xDB, 0xB2, 0x57, 0x04, 0xD8, 0x01, 0x58, 0x00, 0xF2, 0x86, 0x02, 0xFC, 0x7C, 0x4B, 0x69, 0x3F, 0xCF, 0xD5, 0x50, 0xE0, 0xF4, 0xB7, 0x44, 0x00, 0x96, 0x40, 0xC8, 0xF4, 0xF8, 0x75, 0xCC, 0x02, 0xF9, 0xCE, 0x78, 0x1F, 0xCF, 0x56, 0xAF, 0x4E, 0x1E, 0x6D, 0xC4, 0xDE, 0x1B, 0x5A, 0xE7, 0xD6, 0x64, 0xEE, 0x02, 0xCF, 0xDB, 0x53, 0x9F, 0x56, 0x48, 0xD9, 0x6B, 0xEA, 0x85, 0xD0, 0xCE, 0x53, 0xC8, 0x74, 0xBA, 0xDB, 0x1A, 0x71, 0xA9, 0x9B, 0xA2, 0xD7, 0x02, 0x6C, 0xB2, 0x16, 0x23, 0x1D, 0xD3, 0xD1, 0x1A, 0x1B, 0xE2, 0x89, 0x41, 0x3C, 0x76, 0x3C, 0x22, 0x00, 0x9F, 0x07, 0x02, 0x48, 0xC3, 0xF2, 0x69, 0x5F, 0xF6, 0x86, 0x01, 0xA7, 0xA3, 0x55, 0x02, 0x64, 0xEC, 0xD4, 0xB1, 0xCE, 0x9E, 0x96, 0x50, 0xE4, 0xB0, 0xBF, 0x41, 0x8B, 0xBA, 0xB6, 0x07, 0x4A, 0xD6, 0x1E, 0x2E, 0x8C, 0xA4, 0x9E, 0x05, 0xAA, 0x46, 0xEE, 0xFF, 0xA8, 0xE3, 0xCD, 0xB5, 0xF3, 0xDA, 0x3B, 0x9F, 0xD9, 0xE5, 0x01, 0x61, 0x40, 0xED, 0x29, 0x02, 0xF8, 0xD3, 0xCD, 0x3E, 0x6D, 0x9D, 0x73, 0x3E, 0x2D, 0xFD, 0x9D, 0xCA, 0xF3, 0x9A, 0x3B, 0xDD, 0x04, 0x57, 0xCE, 0xA6, 0x3D, 0x6D, 0x9D, 0xBB, 0x8F, 0x60, 0x6C, 0x8E, 0x3C, 0x00, 0xA9, 0x86, 0x34, 0xA8, 0x91, 0xBB, 0x45, 0x81, 0x18, 0x90, 0x68, 0x28, 0x40, 0xFD, 0x2D, 0x45, 0x40, 0x24, 0x30, 0x3B, 0x85, 0xCE, 0x9E, 0x56, 0x9D, 0xF2, 0xDD, 0x96, 0x78, 0x29, 0x84, 0xD4, 0x80, 0xFB, 0xDF, 0x09, 0x66, 0xBD, 0x41, 0xF3, 0xD2, 0xD5, 0x0A, 0x69, 0xEF, 0x60, 0xF1, 0xBC, 0x2E, 0x6D, 0xBA, 0xFC, 0xFF, 0x31, 0x51, 0x1C, 0xBA, 0x47, 0xD8, 0x73, 0xAA, 0x9D, 0x32, 0xBF, 0xC3, 0xA8, 0xBC, 0x47, 0xDF, 0x79, 0x0A, 0x40, 0xE8, 0xA2, 0x53, 0xAF, 0x7E, 0xF3, 0xAA, 0x6C, 0x53, 0xAA, 0x03, 0xA4, 0x00, 0x4E, 0x80, 0xAC, 0x71, 0xF6, 0x27, 0x26, 0x40, 0x14, 0x70, 0x02, 0xAA, 0xB3, 0xB3, 0xE4, 0x8D, 0x6A, 0x58, 0x83, 0x80, 0x53, 0x00, 0x0B, 0xE0, 0x8E, 0x98, 0xF1, 0x24, 0xDE, 0x7E, 0x25, 0xD0, 0x40, 0x5D, 0x40, 0xBE, 0xE3, 0x84, 0x2E, 0x2B, 0xDB, 0x54, 0x41, 0x76, 0x54, 0x12, 0xC7, 0xB2, 0x77, 0x9C, 0x6C, 0xC4, 0xF7, 0xA6, 0x30, 0xE9, 0x8F, 0x69, 0x6E, 0x4E, 0x6A, 0x48, 0x01, 0x16, 0xC0, 0xE4, 0xF7, 0xB6, 0xB4, 0xD1, 0x91, 0xBA, 0x97, 0x40, 0xE1, 0x9F, 0x4C, 0x53, 0x4F, 0xE4, 0xA0, 0xCE, 0xF3, 0xBB, 0x4E, 0xFF, 0x6E, 0x4C, 0x05, 0x08, 0x01, 0x47, 0xF6, 0xC8, 0xA1, 0x55, 0x23, 0x1A, 0x09, 0xC4, 0x01, 0xE6, 0x7F, 0xD7, 0x03, 0xB8, 0x34, 0xCE, 0xE3, 0x84, 0x97, 0x00, 0x3F, 0x49, 0xEF, 0x39, 0xA5, 0x31, 0xCD, 0x5D, 0xFE, 0xC6, 0x2C, 0x09, 0x97, 0x4E, 0xA8, 0x44, 0x3A, 0x62, 0x76, 0x18, 0x49, 0x4E, 0x61, 0x3C, 0x62, 0x66, 0xEB, 0x2D, 0x10, 0xAB, 0xE5, 0x56, 0xAE, 0xCC, 0x75, 0xE9, 0xF4, 0x40, 0x01, 0xEA, 0x80, 0x05, 0x30, 0xBD, 0xA4, 0xD3, 0x9C, 0x7B, 0x62, 0x29, 0x0E, 0xDE, 0xF2, 0x7F, 0x67, 0xFF, 0xB4, 0x63, 0xD6, 0xC7, 0x5D, 0xE1, 0xDB, 0x44, 0x10, 0xFE, 0x4B, 0xAE, 0xFA, 0xCF, 0x1B, 0x16, 0xB0, 0x03, 0x50, 0xCD, 0x22, 0x6A, 0x78, 0x23, 0x76, 0x0B, 0xBC, 0x38, 0x90, 0x67, 0x7B, 0xCA, 0x1E, 0x99, 0xB8, 0x00, 0x61, 0x80, 0x2B, 0x10, 0xD9, 0xAB, 0x5C, 0x3A, 0x66, 0x8C, 0x1F, 0x8C, 0x1C, 0xAF, 0x20, 0xFE, 0xBD, 0x39, 0xA3, 0x7B, 0x1F, 0xBF, 0xC6, 0x7B, 0x34, 0x75, 0x68, 0x08, 0xF2, 0xD1, 0x71, 0x76, 0x87, 0x9A, 0xBC, 0xF2, 0x4C, 0xBC, 0x0F, 0x69, 0x72, 0x00, 0x8E, 0x06, 0x37, 0x12, 0xD0, 0xE8, 0xAC, 0xD1, 0xAA, 0xBF, 0x8F, 0x5A, 0x3E, 0x6E, 0x6D, 0xDB, 0x31, 0x7E, 0x44, 0x22, 0x81, 0xB8, 0x2D, 0xA9, 0xE5, 0x80, 0x0A, 0xE0, 0x7E, 0xFA, 0x47, 0x9C, 0x47, 0x1C, 0x30, 0x02, 0xC2, 0x9F, 0xDD, 0x9C, 0x00, 0x2E, 0xC0, 0x1D, 0x28, 0x6E, 0x1C, 0x20, 0x09, 0x70, 0x05, 0x2C, 0x01, 0x9F, 0x92, 0xA1, 0x76, 0xD0, 0x04, 0x4D, 0x0E, 0x46, 0xED, 0xF5, 0xF3, 0xD3, 0xCC, 0x11, 0x3C, 0x8E, 0xAD, 0x35, 0xFC, 0xC1, 0xCC, 0x91, 0x2D, 0xB4, 0x99, 0x5F, 0x7F, 0x95, 0x4C, 0xF8, 0x29, 0xAB, 0x18, 0xA0, 0x04, 0xC8, 0x13, 0x42, 0x31, 0xC0, 0xCE, 0xCF, 0x21, 0x10, 0xFF, 0xC6, 0xBF, 0x32, 0x3A, 0xDA, 0xAC, 0xF0, 0x0B, 0xF2, 0x1C, 0xF2, 0x77, 0x7B, 0xFC, 0xF1, 0x6D, 0x36, 0x76, 0x1A, 0xC5, 0x13, 0x98, 0xB9, 0x31, 0x4C, 0xF3, 0xE4, 0x2E, 0x13, 0x6B, 0x02, 0x3E, 0x29, 0x5E, 0x06, 0xF4, 0x29, 0x9D, 0x78, 0x3D, 0x7D, 0x43, 0x0C, 0x48, 0x43, 0x0D, 0xA8, 0xEC, 0xA0, 0x29, 0x2C, 0xDD, 0x54, 0x91, 0x1C, 0xA7, 0x7D, 0x46, 0x23, 0xD6, 0x56, 0xE9, 0xF4, 0x3E, 0x25, 0x27, 0x5A, 0xF5, 0x22, 0xB7, 0x5C, 0xEB, 0xDB, 0x0B, 0xC9, 0xF1, 0xAF, 0x71, 0xB2, 0x7C, 0x82, 0xA6, 0x80, 0x06, 0x30, 0x03, 0x2E, 0x39, 0x07, 0x5B, 0x9A, 0x50, 0x8C, 0x4E, 0xCD, 0x2C, 0xAA, 0x69, 0x70, 0x7E, 0x74, 0x13, 0x74, 0x8A, 0xCC, 0x8A, 0x4F, 0x73, 0x66, 0x0F, 0xE9, 0xEF, 0x7C, 0xFA, 0xA3, 0x6F, 0xB0, 0x05, 0xA0, 0x47, 0xF3, 0xB1, 0x0A, 0xC1, 0xE6, 0x81, 0x01, 0xD3, 0x20, 0x99, 0x06, 0x78, 0x23, 0xFA, 0x5B, 0xA4, 0x3A, 0x68, 0xD6, 0xFA, 0x73, 0x82, 0x63, 0x63, 0x9C, 0xD5, 0xD6, 0x27, 0x5D, 0x4F, 0x39, 0x91, 0x1F, 0xCA, 0x18, 0xAD, 0x8C, 0xA9, 0xAF, 0x19, 0xC1, 0xAB, 0x69, 0x45, 0x40, 0x04, 0x50, 0xD9, 0x60, 0x20, 0xAD, 0x21, 0xBB, 0x23, 0x41, 0x26, 0xBB, 0xA6, 0x8F, 0x62, 0xC2, 0x8C, 0x09, 0x72, 0x01, 0x14, 0xFB, 0x6E, 0x73, 0xAE, 0x38, 0x3C, 0x20, 0x8D, 0x98, 0x23, 0x7F, 0xFF, 0x7F, 0x92, 0xC0, 0x5C, 0xB7, 0x88, 0x01, 0x76, 0x40, 0x0F, 0xE0, 0xBA, 0x15, 0x6C, 0x49, 0x1B, 0xD6, 0x20, 0xE0, 0xF0, 0x06, 0x1D, 0x40, 0x27, 0x6A, 0x58, 0x47, 0x4A, 0xB2, 0x0E, 0x1C, 0x96, 0xFC, 0xF5, 0x5E, 0x45, 0x78, 0x1F, 0x85, 0x19, 0x57, 0x5B, 0x6D, 0xBD, 0xD6, 0x8C, 0x29, 0xA9, 0x3F, 0x4E, 0x5B, 0xD2, 0x11, 0x99, 0xF4, 0x73, 0x3D, 0x22, 0xC0, 0xFC, 0xC0, 0x01, 0x9F, 0xE6, 0x0C, 0xBB, 0x42, 0xC8, 0xBF, 0x61, 0xA8, 0xBC, 0xCA, 0x87, 0x1A, 0x40, 0x26, 0x60, 0xB9, 0xFD, 0xAB, 0x35, 0x01, 0x76, 0x80, 0x06, 0x02, 0x9C, 0x6C, 0x38, 0x40, 0xA7, 0x21, 0x00, 0x37, 0xF4, 0x3C, 0xFD, 0xCF, 0xD2, 0xD0, 0x86, 0x37, 0x6C, 0xB0, 0x7B, 0xA3, 0x4F, 0x74, 0xD0, 0x02, 0xD5, 0x40, 0xC7, 0x29, 0xF6, 0x0B, 0x61, 0x24, 0x94, 0x32, 0x91, 0x48, 0xC7, 0xF7, 0x57, 0xCA, 0x94, 0x50, 0xA1, 0x7F, 0x6C, 0xBC, 0x4E, 0x69, 0x7C, 0x63, 0xF6, 0x24, 0x6E, 0xED, 0xB1, 0x5F, 0xF3, 0x86, 0x01, 0x26, 0xCF, 0xD0, 0xC5, 0xAD, 0x42, 0x4D, 0x9B, 0xE6, 0x34, 0xF5, 0xF4, 0xAB, 0x4A, 0x03, 0x38, 0x1F, 0xF4, 0xCA, 0x3E, 0xE8, 0x0C, 0x56, 0xE8, 0x2F, 0x90, 0x7C, 0xA5, 0x12, 0xA6, 0xCE, 0x29, 0x07, 0x28, 0xD9, 0xD3, 0x61, 0x46, 0x40, 0xCC, 0xFB, 0x52, 0x00, 0x0D, 0x20, 0xB4, 0x41, 0x80, 0x33, 0xA0, 0x09, 0x88, 0x03, 0xE3, 0x27, 0x75, 0xE6, 0xED, 0x79, 0xE7, 0x08, 0xB6, 0x04, 0xB5, 0xDA, 0x77, 0x47, 0x30, 0xE1, 0x9E, 0x03, 0x20, 0xCC, 0x78, 0x88, 0xA1, 0xB9, 0x33, 0xCE, 0x3A, 0xA5, 0xD1, 0xE3, 0xB3, 0x75, 0x74, 0x7B, 0xBE, 0x84, 0x00, 0x99, 0x0D, 0x79, 0x8A, 0x97, 0x8D, 0xAB, 0xD0, 0x71, 0xE7, 0x9C, 0xCE, 0xEF, 0x5F, 0x1A, 0x0F, 0x67, 0x1F, 0x62, 0x01, 0xE3, 0x86, 0x03, 0x1E, 0xDB, 0x36, 0x8B, 0x0A, 0x90, 0x00, 0xB4, 0x1E, 0xE3, 0xF9, 0x00, 0x32, 0xC6, 0x78, 0x1E, 0xE0, 0x86, 0x38, 0xA0, 0x0A, 0x18, 0x37, 0x0A, 0x08, 0x01, 0x32, 0x80, 0xFA, 0x90, 0x7F, 0x5F, 0x9E, 0xF5, 0x8B, 0x99, 0xAB, 0x79, 0x60, 0x26, 0xBB, 0x14, 0x19, 0xC8, 0x1E, 0xBE, 0x88, 0x68, 0x0D, 0x80, 0x99, 0x73, 0xB3, 0xEF, 0x68, 0xAB, 0xB1, 0xFA, 0x5E, 0xE6, 0x23, 0x0E, 0x8E, 0xBF, 0xCE, 0x4F, 0xF4, 0x76, 0x61, 0x87, 0x79, 0xA0, 0x0A, 0xF8, 0x18, 0xF3, 0xCC, 0x5D, 0x78, 0xAE, 0x98, 0x6D, 0xF0, 0x37, 0x3E, 0xE9, 0x44, 0x3D, 0xD9, 0x6F, 0x80, 0x1E, 0x40, 0x12, 0x50, 0x03, 0x72, 0x2A, 0x9B, 0x02, 0x70, 0x43, 0x0C, 0xD0, 0x86, 0x9F, 0x86, 0x03, 0x51, 0x40, 0xC5, 0x34, 0x14, 0x35, 0x0A, 0x60, 0x05, 0x84, 0x00, 0x35, 0xC0, 0x0A, 0x70, 0x60, 0x3A, 0x95, 0xAF, 0x10, 0x7D, 0xFE, 0xAE, 0x03, 0xDF, 0x11, 0xBA, 0x10, 0x64, 0xC6, 0xAD, 0x80, 0x24, 0x30, 0x65, 0x15, 0xD2, 0x16, 0x90, 0x7A, 0xEF, 0x99, 0x48, 0x8C, 0x22, 0x66, 0xF2, 0x48, 0x72, 0x68, 0x9D, 0xDD, 0xE3, 0x69, 0x05, 0x84, 0xEF, 0xF1, 0xF9, 0x89, 0x20, 0x07, 0x62, 0x36, 0x8F, 0xD5, 0x5C, 0x00, 0xB2, 0x7F, 0x77, 0xC3, 0x0F, 0xFF, 0x68, 0x1C, 0xD8, 0x5F, 0x15, 0x85, 0x03, 0x50, 0xF4, 0xE9, 0xF7, 0x00, 0x29, 0x40, 0x10, 0xE0, 0xF6, 0x0C, 0x87, 0x1D, 0xA0, 0xA2, 0xAB, 0xEB, 0x05, 0x78, 0xA3, 0xA8, 0xA1, 0x0D, 0x06, 0x32, 0x1A, 0xDE, 0x25, 0x77, 0x05, 0x8C, 0x3A, 0x66, 0xB7, 0x65, 0xE8, 0x43, 0x89, 0x7C, 0x53, 0xC5, 0x1A, 0xDD, 0xAB, 0x36, 0x92, 0xB8, 0x27, 0xB0, 0xA1, 0x45, 0x40, 0x79, 0x91, 0x65, 0x49, 0x72, 0x44, 0x3D, 0x3D, 0xB7, 0xD3, 0xD7, 0x78, 0xA7, 0xF6, 0x0B, 0x90, 0x06, 0x37, 0x44, 0x01, 0x35, 0x00, 0x57, 0xF6, 0x95, 0x4D, 0xB7, 0x3E, 0x58, 0xBD, 0x7A, 0x2D, 0xBE, 0x9B, 0x16, 0x67, 0x54, 0xCC, 0x07, 0xB3, 0x95, 0xC9, 0x4F, 0x2C, 0xD8, 0xEE, 0x5E, 0x44, 0x0A, 0x18, 0x03, 0xEE, 0x40, 0x6A, 0x3F, 0xA4, 0x05, 0x48, 0x02, 0x46, 0x1B, 0x5A, 0x0D, 0x7D, 0x90, 0x40, 0x4E, 0xD0, 0xA6, 0x2E, 0xD0, 0x4D, 0x6D, 0xBA, 0x0F, 0x1C, 0xA4, 0x36, 0xD3, 0x1D, 0x78, 0xD4, 0x58, 0x50, 0xD3, 0x15, 0xBA, 0x65, 0xF5, 0x8F, 0xBC, 0xF3, 0x8F, 0x04, 0x42, 0x45, 0xE6, 0x51, 0x45, 0x68, 0x78, 0x36, 0x18, 0xD8, 0xC5, 0x61, 0xBD, 0xF9, 0xEF, 0x9C, 0xE9, 0xD0, 0xC9, 0xDE, 0xAB, 0x3D, 0x78, 0x9C, 0x63, 0xC2, 0x9E, 0x99, 0x01, 0x9F, 0xCB, 0xC2, 0xCF, 0x70, 0x71, 0xA4, 0xD0, 0x50, 0xA2, 0x59, 0x77, 0x77, 0x35, 0x20, 0x04, 0x98, 0x9A, 0xD5, 0x31, 0x80, 0x14, 0x60, 0x01, 0xC4, 0x01, 0xA3, 0x46, 0x01, 0xE1, 0x1D, 0x35, 0xE9, 0x11, 0xF7, 0xC0, 0x33, 0x40, 0xBB, 0x29, 0xE1, 0x74, 0x19, 0xD9, 0x98, 0x5B, 0x9F, 0x4C, 0x71, 0x34, 0xB5, 0xB3, 0x67, 0xB1, 0x5F, 0xFF, 0x86, 0xC9, 0xCF, 0x0E, 0xDE, 0x74, 0x24, 0x0F, 0x04, 0x10, 0xDB, 0x4E, 0x21, 0xAE, 0xCF, 0xFB, 0x60, 0x7A, 0xF2, 0x42, 0x00, 0x23, 0x60, 0x6C, 0x27, 0x22, 0x9F, 0xEB, 0x53, 0xEE, 0x89, 0x45, 0x9C, 0x03, 0xA5, 0x03, 0x63, 0x0D, 0x34, 0x4A, 0x63, 0x71, 0x39, 0xA0, 0x04, 0x44, 0x67, 0x4F, 0x98, 0x00, 0xB5, 0x46, 0x36, 0x02, 0x90, 0x6A, 0x04, 0x60, 0x04, 0xD4, 0x04, 0x4D, 0xFB, 0x7C, 0x5D, 0x78, 0xD3, 0x7C, 0xA5, 0xF4, 0x82, 0x48, 0x8E, 0xF6, 0xE2, 0x42, 0xA6, 0x59, 0x3F, 0x1C, 0x6A, 0x0D, 0x5F, 0xCA, 0x5D, 0xBE, 0x7B, 0x5B, 0x86, 0xDC, 0x76, 0x23, 0x90, 0x05, 0xE0, 0x0C, 0x68, 0x35, 0xB4, 0x11, 0xBB, 0xAF, 0x5B, 0x78, 0xCD, 0x21, 0xEB, 0xBD, 0x49, 0x4A, 0x00, 0x7A, 0x00, 0x66, 0xE0, 0xC4, 0xD6, 0xC4, 0x9C, 0x5B, 0x26, 0xFE, 0x5B, 0x01, 0x38, 0xC8, 0x6D, 0x7D, 0xBD, 0x9A, 0x47, 0xD8, 0x00, 0x4D, 0x20, 0x72, 0x1E, 0x7D, 0x80, 0x0D, 0x10, 0x6E, 0x68, 0xC3, 0x00, 0x3D, 0x8D, 0x00, 0xE6, 0xF9, 0x84, 0x5D, 0x31, 0xB2, 0x1A, 0xDA, 0xF5, 0x81, 0xC4, 0xFD, 0x12, 0x55, 0x51, 0xB1, 0xB6, 0xE8, 0x25, 0x04, 0xCD, 0xF5, 0xEB, 0x50, 0x21, 0xD5, 0xB9, 0x00, 0x3C, 0xCD, 0x69, 0x6B, 0xB2, 0x47, 0xFF, 0xDE, 0x8D, 0x68, 0xC3, 0x1D, 0xB0, 0x07, 0xB9, 0xF2, 0x20, 0x68, 0x2B, 0xDA, 0xB7, 0x28, 0x75, 0x60, 0xBE, 0x68, 0x02, 0x8C, 0xC9, 0x77, 0x34, 0x26, 0x76, 0x3A, 0xBD, 0xA0, 0x73, 0x4D, 0xEC, 0x88, 0x4C, 0xD6, 0x47, 0x9F, 0xE6, 0x34, 0x4A, 0xC0, 0x14, 0x28, 0xDF, 0x8A, 0x4D, 0x4C, 0x00, 0x09, 0x70, 0x26, 0x03, 0x15, 0x8F, 0x68, 0xD1, 0x04, 0x6D, 0x5E, 0x9B, 0xFD, 0x7E, 0x4D, 0xFD, 0xEE, 0x03, 0xC7, 0x10, 0xC2, 0x11, 0xA1, 0x33, 0xE1, 0xCE, 0x9E, 0x33, 0x3A, 0x05, 0x30, 0x1F, 0x5A, 0xE7, 0x9F, 0xED, 0x2F, 0xD5, 0xF1, 0x99, 0xA3, 0xBF, 0x48, 0xE3, 0x00, 0xA7, 0x1E, 0xFF, 0xB4, 0x29, 0xE6, 0x59, 0x07, 0x6D, 0xE9, 0xEE, 0x12, 0xDC, 0xC1, 0x11, 0xBB, 0x6A, 0x9C, 0x0D, 0x0A, 0x40, 0x0C, 0xA8, 0x91, 0x29, 0x39, 0x23, 0xB2, 0xDD, 0xF1, 0xB1, 0x3D, 0x35, 0x3A, 0x83, 0x89, 0x74, 0x00, 0x4B, 0xA0, 0xA4, 0xBB, 0xA2, 0x18, 0x10, 0x07, 0x34, 0x01, 0x3F, 0x40, 0x38, 0x30, 0x13, 0xB3, 0x27, 0x01, 0x39, 0x1D, 0xB4, 0x98, 0xA0, 0xA1, 0x84, 0x63, 0xB8, 0x3D, 0xA9, 0x6A, 0xCF, 0x75, 0xF8, 0x87, 0xF2, 0xF8, 0x80, 0x94, 0x87, 0x20, 0xFF, 0x8D, 0xCD, 0x79, 0xAB, 0x80, 0xC9, 0xB2, 0x55, 0x21, 0xBE, 0x56, 0x38, 0xF8, 0xE4, 0x7F, 0x45, 0xF6, 0x18, 0xC8, 0xB3, 0xD5, 0x07, 0x67, 0x2A, 0xE6, 0x8C, 0x8A, 0xA5, 0xCC, 0x21, 0xB3, 0x27, 0x35, 0x1D, 0xD0, 0x86, 0x15, 0x10, 0x02, 0x64, 0x75, 0x08, 0xA6, 0xF8, 0xF3, 0xA1, 0xCF, 0x7C, 0x12, 0x88, 0xBC, 0x64, 0x7F, 0x11, 0xCA, 0xDB, 0xBD, 0x00, 0x00, 0x13, 0x20, 0xA3, 0x3B, 0xCF, 0x18, 0xE0, 0x00, 0xC4, 0x01, 0x6D, 0xB8, 0x00, 0xA9, 0x40, 0x55, 0xB7, 0x7C, 0xCC, 0x42, 0x9B, 0xFB, 0xC0, 0xF4, 0x9F, 0x0A, 0x7A, 0xD4, 0x58, 0x71, 0x40, 0x32, 0xEF, 0x47, 0x3C, 0x5A, 0x69, 0x2B, 0xDA, 0xCD, 0xB0, 0xAE, 0x6D, 0xC3, 0xC7, 0xF3, 0x5C, 0xA2, 0x00, 0x6F, 0xA0, 0xAF, 0x1D, 0x48, 0x40, 0xA2, 0x71, 0x1A, 0x06, 0x44, 0x9E, 0xE9, 0xEF, 0xFB, 0xAD, 0xB0, 0xBC, 0x2E, 0x00, 0xDC, 0x30, 0x6A, 0x38, 0xE0, 0x05, 0x4C, 0xB1, 0x40, 0xE9, 0xF7, 0x66, 0x9C, 0x83, 0x44, 0xF5, 0x41, 0x8B, 0x6E, 0x7B, 0x7C, 0xF5, 0x12, 0x51, 0x03, 0x22, 0x3B, 0xBB, 0x69, 0x00, 0x27, 0x20, 0x0E, 0xA8, 0x02, 0x26, 0x80, 0x1B, 0x90, 0x0C, 0x14, 0xF5, 0x71, 0xAD, 0x3A, 0x68, 0x05, 0xFB, 0x0F, 0xD3, 0xD6, 0x7B, 0xF3, 0x2F, 0x6D, 0xEB, 0xC6, 0xF8, 0x5B, 0x59, 0xF1, 0x76, 0xAE, 0x02, 0x3C, 0xFB, 0x71, 0xE2, 0xBD, 0xA5, 0xC9, 0x33, 0x50, 0x36, 0xD2, 0x2E, 0xD7, 0x40, 0x57, 0x00, 0x23, 0x40, 0x9F, 0x99, 0xD7, 0xB8, 0xF5, 0x96, 0xD5, 0x06, 0xA9, 0x7F, 0xCD, 0xA1, 0xA6, 0x15, 0xC1, 0x00, 0x39, 0x00, 0x9D, 0x3D, 0x47, 0xE2, 0x04, 0xDC, 0xDB, 0x65, 0x07, 0x6D, 0x3C, 0x02, 0xA8, 0x57, 0x61, 0x44, 0x3F, 0x6C, 0x1D, 0x34, 0x3A, 0x80, 0x0A, 0x10, 0x63, 0x88, 0xAD, 0x4F, 0xD0, 0xA4, 0x61, 0x8D, 0x00, 0x4C, 0x81, 0xE8, 0xB5, 0x4C, 0xFD, 0x74, 0xDE, 0xAA, 0x7A, 0x77, 0xB1, 0x9D, 0xFA, 0x46, 0xA4, 0x24, 0x0B, 0x4F, 0xE7, 0xDC, 0x0B, 0x2C, 0x70, 0x42, 0x61, 0xFA, 0x7E, 0x3D, 0x32, 0x46, 0x90, 0x5E, 0x2B, 0x02, 0x99, 0x2C, 0x6C, 0x27, 0x2C, 0x6A, 0x2A, 0x25, 0x02, 0x68, 0x02, 0x7C, 0x80, 0x43, 0xDB, 0x71, 0x85, 0xE8, 0xA7, 0x41, 0xE7, 0xB7, 0x17, 0x3B, 0x66, 0x70, 0xA4, 0x00, 0x3F, 0x0D, 0x02, 0xA2, 0x80, 0xD2, 0x0E, 0xDD, 0xD4, 0xA8, 0x7E, 0xEE, 0x0A, 0x57, 0x0A, 0x22, 0xFA, 0xE1, 0xC6, 0x00, 0x23, 0xDA, 0xAC, 0xB8, 0x87, 0xD5, 0x0F, 0x20, 0x05, 0x78, 0x02, 0x79, 0x76, 0xB3, 0xE8, 0x51, 0x80, 0x09, 0xD0, 0x86, 0x19, 0x10, 0xD2, 0x31, 0xFB, 0x7A, 0xA7, 0xCC, 0x5A, 0x41, 0x8D, 0x4E, 0x2D, 0x81, 0xF8, 0x23, 0xD4, 0x83, 0xA4, 0x8E, 0x62, 0x36, 0x2B, 0x06, 0x82, 0x69, 0xAB, 0x41, 0x7A, 0x3E, 0x0D, 0x7D, 0x7C, 0x1E, 0xCF, 0x36, 0x06, 0x76, 0xBD, 0x1D, 0xAF, 0x57, 0xC0, 0xB7, 0x3E, 0x3C, 0xCD, 0x5A, 0x9C, 0xAA, 0x81, 0x02, 0xC9, 0x80, 0x1D, 0x40, 0x1B, 0xA6, 0x80, 0xC7, 0x1A, 0x90, 0x9A, 0x7B, 0x5A, 0xDC, 0x26, 0x99, 0x39, 0xCC, 0x06, 0xEF, 0xE4, 0x04, 0x27, 0x10, 0xDA, 0xD7, 0x6E, 0x02, 0xC4, 0x00, 0x3B, 0x8D, 0x00, 0xBC, 0x11, 0x0A, 0x64, 0x02, 0x53, 0x4F, 0x24, 0xEA, 0xA0, 0xF5, 0x85, 0x60, 0x46, 0x89, 0x0F, 0x7D, 0xA7, 0x34, 0x96, 0x96, 0xD1, 0x89, 0xC2, 0x69, 0xA7, 0x26, 0xA7, 0xEE, 0xD0, 0x66, 0x12, 0x5E, 0xB2, 0xC0, 0x91, 0x8F, 0x6B, 0xFD, 0xBC, 0x1F, 0xAF, 0x40, 0xB7, 0xED, 0x59, 0xD7, 0x2A, 0x20, 0x0F, 0xE0, 0xB6, 0x4F, 0x69, 0x87, 0x97, 0x63, 0x18, 0xDF, 0x66, 0xA0, 0x72, 0xC0, 0x19, 0xB0, 0x46, 0x08, 0x50, 0xF4, 0xEB, 0x24, 0x98, 0x8B, 0xCF, 0xCC, 0x00, 0xE4, 0xD5, 0x90, 0x20, 0x9B, 0x5E, 0xEC, 0x96, 0xEC, 0xEB, 0xCB, 0xBB, 0x14, 0x90, 0xBC, 0xAF, 0xEB, 0x1C, 0x80, 0x14, 0x60, 0x04, 0xB8, 0x03, 0xD9, 0xA8, 0x5E, 0xAF, 0x14, 0x1D, 0x34, 0x69, 0x3F, 0x03, 0x42, 0x87, 0x2D, 0xC7, 0x9F, 0xCC, 0x7B, 0x5A, 0x1E, 0xD5, 0x97, 0x54, 0xED, 0x6B, 0x41, 0x61, 0x68, 0xBC, 0x68, 0x69, 0x72, 0xD0, 0x93, 0x7F, 0x8C, 0x19, 0x2C, 0x0F, 0xA0, 0xAA, 0x91, 0x40, 0x54, 0xC3, 0x1A, 0xB1, 0x9D, 0xA5, 0xC2, 0xD6, 0x79, 0x43, 0x6F, 0x7A, 0x79, 0x8E, 0x16, 0x29, 0x80, 0x19, 0xA0, 0x02, 0x70, 0x01, 0xA1, 0x5B, 0x44, 0x52, 0xE2, 0x77, 0xC9, 0xAC, 0x3B, 0xAE, 0xA9, 0xD2, 0x79, 0xFB, 0x04, 0xDC, 0xA7, 0x30, 0x08, 0x98, 0x02, 0x11, 0x40, 0x6A, 0xC3, 0x1B, 0xD2, 0xF0, 0x7D, 0xCD, 0x97, 0x89, 0x99, 0xCE, 0x42, 0x83, 0x43, 0x14, 0xC9, 0xEA, 0x7C, 0x39, 0x69, 0x48, 0x70, 0x86, 0x76, 0x55, 0x99, 0xF0, 0xA8, 0xBD, 0x16, 0x95, 0xF1, 0x9A, 0x15, 0xD3, 0xEE, 0x71, 0x91, 0x06, 0x1B, 0x40, 0xDC, 0xA0, 0x46, 0x01, 0xA6, 0xD3, 0x98, 0xBB, 0xE6, 0x16, 0x31, 0x93, 0x81, 0xBB, 0x6E, 0x23, 0x18, 0xF0, 0xDC, 0xB9, 0xA6, 0xC3, 0xC0, 0x08, 0x7D, 0xCD, 0x55, 0x13, 0x3F, 0x84, 0x77, 0x0C, 0xF0, 0xE4, 0xCE, 0x41, 0x0C, 0x61, 0x0A, 0xC0, 0xDF, 0x54, 0x07, 0x03, 0x22, 0x80, 0x36, 0xAC, 0xE1, 0x09, 0x24, 0x3F, 0xD3, 0x05, 0x13, 0x34, 0xEB, 0x8B, 0x06, 0x43, 0x14, 0x32, 0xF2, 0x4F, 0x7D, 0xBD, 0xC2, 0xE8, 0xEC, 0xC0, 0x30, 0x99, 0xDD, 0xA7, 0x43, 0x54, 0x10, 0x08, 0xA7, 0x75, 0x87, 0x32, 0xFE, 0x97, 0x59, 0xB1, 0x1D, 0x20, 0x15, 0x88, 0x86, 0x65, 0xE3, 0x00, 0x1A, 0x40, 0xC8, 0xAF, 0xF9, 0x36, 0xC6, 0x3A, 0xE9, 0xDC, 0xA1, 0x01, 0x55, 0x7C, 0xCA, 0x00, 0xB4, 0x00, 0x11, 0x80, 0x64, 0x3B, 0xBD, 0x1B, 0x8F, 0xFC, 0xC3, 0xE8, 0x6C, 0xFF, 0xC6, 0x76, 0x10, 0x83, 0xA5, 0x7C, 0x63, 0xD9, 0x59, 0x5B, 0x02, 0xB4, 0x80, 0x68, 0x24, 0x03, 0xE1, 0x80, 0x0F, 0x04, 0x08, 0xEB, 0x8D, 0x71, 0xDE, 0x03, 0xBE, 0x0A, 0xC4, 0xA1, 0xBC, 0x6A, 0x9E, 0x56, 0xDE, 0x0A, 0x0D, 0xDA, 0x66, 0x1A, 0x84, 0xA9, 0xA8, 0xA8, 0x35, 0x15, 0xE5, 0xF2, 0x8E, 0xC8, 0xD2, 0x23, 0xF2, 0x48, 0x34, 0x9F, 0x80, 0x30, 0xC0, 0x02, 0x50, 0x6E, 0x28, 0x30, 0x2D, 0xCB, 0xC4, 0xDB, 0x80, 0xF9, 0xF4, 0x17, 0x55, 0x00, 0x7E, 0x2C, 0x1C, 0xE7, 0x36, 0x2B, 0xB4, 0xBC, 0xC8, 0xB5, 0xEF, 0x93, 0x74, 0x67, 0x01, 0x78, 0xCE, 0xC4, 0xFD, 0x7C, 0x9E, 0x46, 0xF6, 0x8A, 0x53, 0xDA, 0x07, 0x8F, 0x43, 0x00, 0x05, 0x20, 0x0C, 0x18, 0x01, 0x71, 0x80, 0x94, 0x19, 0x64, 0xE9, 0xA8, 0xC5, 0x8D, 0x9A, 0xFF, 0xFF, 0x8C, 0x58, 0x39, 0x0E, 0x25, 0xEF, 0xE7, 0x33, 0xB1, 0x9B, 0x44, 0xA1, 0xBF, 0x55, 0xE7, 0x4C, 0xFB, 0x46, 0x8D, 0x9F, 0x76, 0x3E, 0x06, 0x58, 0x9E, 0xB7, 0xA7, 0x37, 0x0E, 0x90, 0x13, 0xD7, 0x89, 0x48, 0xFD, 0xDA, 0x86, 0xEA, 0xEF, 0xF8, 0xBF, 0xB4, 0x35, 0x48, 0xAE, 0xFC, 0xC7, 0xB9, 0x27, 0x16, 0xFE, 0x40, 0xFD, 0x49, 0x6F, 0x25, 0xC3, 0x05, 0xD1, 0x92, 0xD9, 0xBF, 0xFA, 0x38, 0x1A, 0x93, 0xC2, 0x6C, 0xD4, 0x24, 0x65, 0x1D, 0x48, 0x6E, 0x41, 0x1D, 0x05, 0xF8, 0x00, 0xA2, 0x80, 0x35, 0x82, 0x81, 0x51, 0x80, 0xBC, 0xCF, 0xE7, 0xCF, 0x2B, 0xEA, 0x13, 0x8C, 0x34, 0x78, 0x5E, 0x88, 0x21, 0x68, 0x47, 0xDB, 0x6C, 0xC9, 0x71, 0x25, 0x86, 0xB5, 0x38, 0xBB, 0x9E, 0x2D, 0x0B, 0x4C, 0xFF, 0xEA, 0x49, 0x48, 0xEB, 0x18, 0xF0, 0xBF, 0x54, 0x12, 0x0A, 0xF0, 0x46, 0x9C, 0x5F, 0x33, 0x73, 0xF6, 0x17, 0xE9, 0xDC, 0x91, 0x5A, 0x29, 0x7C, 0xCA, 0x03, 0xB8, 0x01, 0xE9, 0x1D, 0x2D, 0x03, 0x72, 0xDA, 0x40, 0xF8, 0x67, 0x0B, 0x95, 0xBD, 0xE9, 0x4B, 0x27, 0x67, 0xFD, 0x66, 0xC0, 0xED, 0x79, 0x51, 0xC6, 0x13, 0x2D, 0x4A, 0x40, 0x08, 0x50, 0x01, 0xAC, 0x80, 0x10, 0x20, 0xBD, 0x83, 0x36, 0x2B, 0xAD, 0x9E, 0xA6, 0x17, 0x5A, 0x9D, 0x69, 0x24, 0x84, 0x57, 0x54, 0x79, 0x77, 0xAB, 0x24, 0xC6, 0x05, 0x8B, 0xB6, 0xE7, 0x05, 0xBD, 0x2D, 0xCA, 0x0A, 0x94, 0x3C, 0xEA, 0x7C, 0x8D, 0x3C, 0x80, 0x07, 0x60, 0x09, 0x04, 0x3D, 0x23, 0x3E, 0x35, 0x6E, 0x9F, 0x53, 0xC9, 0xDA, 0xA1, 0x8F, 0x03, 0x64, 0xED, 0x61, 0xEC, 0x38, 0xAB, 0xCB, 0xC6, 0xBA, 0x82, 0x42, 0x77, 0x48, 0xD3, 0xA6, 0x20, 0x52, 0x7D, 0x6C, 0x6F, 0x04, 0xF7, 0x9D, 0xC1, 0x00, 0x2D, 0xC0, 0x19, 0x08, 0xDB, 0xB7, 0xDA, 0x63, 0x00, 0x0B, 0x20, 0x06, 0x98, 0x21, 0x68, 0xF6, 0xEB, 0x7A, 0x29, 0xF8, 0x2C, 0x76, 0xD0, 0x70, 0x92, 0x4B, 0xED, 0xBE, 0x3F, 0xEF, 0xBE, 0x1F, 0x46, 0x97, 0xA3, 0x6E, 0x3F, 0x6C, 0xF3, 0x37, 0x68, 0xF1, 0x1C, 0x6E, 0x81, 0x9F, 0x83, 0x31, 0xE0, 0x0D, 0xF5, 0x06, 0x6F, 0x77, 0xE3, 0x71, 0xB4, 0x31, 0x05, 0x88, 0x76, 0x59, 0xFE, 0x7E, 0xE2, 0xDD, 0xD2, 0xC0, 0xD3, 0x51, 0x33, 0x39, 0x80, 0x9C, 0x7E, 0x97, 0x91, 0x98, 0x9B, 0xE7, 0xB2, 0x97, 0xD1, 0xDC, 0x01, 0x6C, 0xAE, 0xE6, 0x02, 0x64, 0x4F, 0x5C, 0xD0, 0x01, 0x84, 0x01, 0x2D, 0x20, 0x0E, 0x50, 0xD2, 0x07, 0xFD, 0x04, 0xB8, 0x3A, 0x68, 0xD4, 0x97, 0xF1, 0xFC, 0x6F, 0x33, 0x7C, 0x76, 0x62, 0x28, 0x84, 0xFB, 0xDA, 0x4E, 0x68, 0xF8, 0xF4, 0x11, 0x00, 0x7B, 0x92, 0x1C, 0xA4, 0x5B, 0x17, 0x98, 0x0D, 0xD0, 0x02, 0x8C, 0x37, 0x62, 0x3A, 0x38, 0x14, 0x98, 0x72, 0x5E, 0xDA, 0xB5, 0x02, 0x18, 0xB9, 0xEE, 0xBD, 0x38, 0x8C, 0x7E, 0x09, 0x54, 0xBF, 0xD3, 0x4E, 0x3C, 0x99, 0x41, 0x02, 0x66, 0x5C, 0x31, 0x15, 0xF0, 0x86, 0x71, 0x43, 0x1B, 0x0E, 0x78, 0x00, 0xA5, 0x8F, 0x4C, 0xFC, 0xD9, 0x50, 0x01, 0x84, 0x01, 0x76, 0x40, 0x0A, 0x48, 0xE9, 0xA0, 0x31, 0x9C, 0xA4, 0x3B, 0xE7, 0x9D, 0x11, 0xEB, 0x1A, 0xA5, 0xEE, 0x6D, 0xE8, 0x8A, 0xEA, 0xBA, 0x84, 0x22, 0x49, 0x9D, 0xB4, 0x93, 0xDD, 0xE7, 0x5D, 0x69, 0x07, 0x28, 0x7F, 0x3A, 0x46, 0xED, 0x19, 0x81, 0x12, 0x40, 0x08, 0xC8, 0x95, 0x89, 0xA4, 0x73, 0xFB, 0x2B, 0x38, 0xBB, 0x3F, 0xA7, 0x61, 0x02, 0x28, 0x01, 0xDC, 0x38, 0x0C, 0x4C, 0xB1, 0x7C, 0xEA, 0xC6, 0x11, 0x53, 0x7A, 0xD9, 0x49, 0x59, 0x2B, 0x20, 0x46, 0x6A, 0xF4, 0x00, 0x2C, 0xAF, 0xB8, 0x68, 0x43, 0x1B, 0xB1, 0x11, 0x0C, 0xCC, 0xB1, 0xE4, 0xCC, 0xE3, 0x29, 0x9D, 0x33, 0xB0, 0x3E, 0xE9, 0xD4, 0x6A, 0x19, 0xB2, 0x20, 0xF4, 0x22, 0x1C, 0xC7, 0x4E, 0x81, 0x66, 0xF8, 0x30, 0x9E, 0x17, 0xC0, 0xBB, 0xA7, 0xDD, 0xBB, 0xE7, 0x13, 0x18, 0xDB, 0xE0, 0x00, 0xF4, 0x3C, 0xCD, 0xF0, 0x4B, 0x71, 0xF4, 0xDA, 0xF2, 0xD4, 0xBD, 0x8D, 0x5B, 0x00, 0x33, 0x3C, 0x5D, 0x01, 0x8C, 0xCE, 0xDB, 0xB4, 0x1D, 0xCC, 0x21, 0xE3, 0x0A, 0x45, 0xCC, 0xDA, 0x1A, 0xF5, 0x4B, 0x07, 0xAC, 0x11, 0x06, 0x94, 0x75, 0xD0, 0x12, 0x88, 0x03, 0x94, 0x34, 0x0C, 0xC8, 0x02, 0x62, 0xA0, 0x40, 0xC6, 0x14, 0xA3, 0x3B, 0x68, 0x7A, 0x9F, 0x4B, 0x4C, 0x40, 0xD6, 0x77, 0x5E, 0x4B, 0xAB, 0x96, 0x4F, 0x97, 0x1E, 0xF8, 0xD3, 0x96, 0xA3, 0x0F, 0x08, 0xE2, 0x64, 0xCD, 0xE3, 0xF9, 0x5C, 0x09, 0x6C, 0xF6, 0xA6, 0x47, 0xCA, 0x24, 0x00, 0xAE, 0x86, 0x03, 0xD2, 0xF0, 0xF3, 0x93, 0x48, 0xAB, 0x19, 0xA5, 0xB6, 0x69, 0x38, 0x58, 0x39, 0x68, 0xBC, 0x0C, 0x0B, 0x50, 0x07, 0x4C, 0x00, 0x1F, 0x5D, 0x96, 0xDE, 0xC9, 0xF1, 0x16, 0xA4, 0x3B, 0xE4, 0x74, 0x9B, 0x28, 0x1B, 0xFA, 0x28, 0x64, 0x66, 0xF6, 0x91, 0x8C, 0x00, 0x19, 0xD4, 0x93, 0x0B, 0x6A, 0x78, 0x01, 0xE9, 0x40, 0xD5, 0x4C, 0x1A, 0x77, 0xD0, 0xAC, 0xC7, 0xE4, 0x19, 0x32, 0x49, 0x55, 0x7F, 0x6A, 0x14, 0x07, 0xF3, 0x0A, 0xFB, 0x87, 0x71, 0x4F, 0xAE, 0x7C, 0x17, 0x76, 0x3D, 0x5C, 0xE8, 0xAB, 0x7A, 0x44, 0xF5, 0x67, 0x6C, 0xDD, 0xE7, 0xD4, 0xE5, 0x40, 0x52, 0xA3, 0x80, 0xD2, 0xAD, 0x3C, 0x6D, 0xBC, 0x95, 0xA7, 0x4D, 0x97, 0x26, 0x62, 0xB7, 0x36, 0x41, 0x5B, 0x03, 0xF0, 0xFC, 0x7D, 0x3A, 0x37, 0xDB, 0x50, 0x0E, 0xF8, 0xC4, 0xCC, 0x80, 0xE2, 0x79, 0xC3, 0x01, 0x65, 0xFF, 0x9F, 0x00, 0x84, 0x9D, 0x89, 0x8D, 0x2C, 0x39, 0x8F, 0x84, 0x5D, 0x69, 0x13, 0x24, 0xDE, 0xF4, 0xDF, 0xB1, 0x45, 0x06, 0x43, 0x28, 0x09, 0xFF, 0xC3, 0x2C, 0xAE, 0x0F, 0x95, 0x93, 0x3D, 0xAF, 0x8B, 0xAD, 0x93, 0x47, 0x70, 0xAE, 0x51, 0xC7, 0x90, 0x80, 0x2F, 0xA0, 0x36, 0x2C, 0xB8, 0x13, 0x50, 0xA2, 0x06, 0x06, 0x48, 0x0C, 0x1C, 0xD0, 0x41, 0xD2, 0x66, 0x14, 0xFB, 0xDA, 0x57, 0x83, 0x67, 0xA3, 0xFD, 0x53, 0x66, 0x44, 0x16, 0x72, 0x60, 0xC3, 0x11, 0x2A, 0xF6, 0xE0, 0xB1, 0xEC, 0x8E, 0x14, 0xF7, 0xA3, 0xCE, 0x94, 0xB7, 0xBF, 0x36, 0x75, 0x50, 0x40, 0x5F, 0x09, 0xB9, 0xAF, 0x4C, 0x37, 0x95, 0x0D, 0x18, 0xC8, 0x40, 0x1D, 0xF8, 0xD8, 0x4C, 0x00, 0xA1, 0xA0, 0xD2, 0x98, 0x27, 0x16, 0xA0, 0x06, 0x88, 0xDE, 0xD8, 0x35, 0x48, 0x40, 0x06, 0xAA, 0x80, 0x25, 0x90, 0xFE, 0x1C, 0x2A, 0x64, 0xE0, 0x0F, 0x62, 0xD0, 0x80, 0x09, 0x90, 0xDC, 0x3B, 0x93, 0xC6, 0x7A, 0xF7, 0x4E, 0xCA, 0x8F, 0x22, 0x37, 0x47, 0xF7, 0x44, 0xBC, 0x1A, 0x9D, 0x38, 0xDD, 0xEF, 0x53, 0xDA, 0x7A, 0xEE, 0x03, 0x2B, 0xEE, 0xF3, 0xC3, 0xAA, 0x81, 0x0F, 0x14, 0xD8, 0x06, 0x18, 0x93, 0x18, 0xA8, 0x0B, 0x7F, 0xF4, 0xDD, 0xB9, 0xFE, 0x37, 0x43, 0x6D, 0xF4, 0x8A, 0x3D, 0xD1, 0x5C, 0xBD, 0x97, 0xA4, 0x70, 0xA0, 0x37, 0x8C, 0xBD, 0x1D, 0x90, 0x06, 0xCC, 0x00, 0x6F, 0x20, 0xD7, 0x93, 0x03, 0x33, 0x90, 0x00, 0x74, 0x60, 0x0A, 0xF8, 0x20, 0x0C, 0xA8, 0x05, 0xF4, 0xA6, 0x17, 0x6E, 0x8C, 0x56, 0xC7, 0x5A, 0x44, 0x38, 0x96, 0x32, 0x48, 0x3C, 0xF5, 0xF4, 0x8C, 0x30, 0x1C, 0x93, 0xC3, 0xA7, 0x99, 0x75, 0x5F, 0xC2, 0xA3, 0xB4, 0x19, 0xA7, 0x23, 0x5B, 0x66, 0x29, 0x4D, 0x50, 0xA7, 0x72, 0x1F, 0x50, 0x07, 0x5C, 0x81, 0xF2, 0x5B, 0xA6, 0x25, 0xD9, 0x42, 0x86, 0xBE, 0xFC, 0xDF, 0x9D, 0xC6, 0x30, 0x98, 0xE9, 0x46, 0x05, 0x14, 0xD0, 0x02, 0x8A, 0xB1, 0x0E, 0x05, 0x7C, 0x10, 0x0D, 0x1C, 0xA9, 0xCB, 0x04, 0x76, 0x03, 0x3A, 0x08, 0x07, 0x2A, 0x81, 0x6E, 0xD6, 0x9D, 0x03, 0x7B, 0xA0, 0x0A, 0xB8, 0x03, 0xD1, 0x40, 0x71, 0xA0, 0x35, 0x8D, 0xC5, 0xB5, 0xE0, 0xAA, 0x23, 0x13, 0x29, 0x24, 0xC0, 0xF5, 0x9E, 0xB3, 0x48, 0xE1, 0x9C, 0x29, 0xC6, 0x59, 0xF9, 0x34, 0x6F, 0x90, 0xC7, 0x31, 0xB4, 0x00, 0xE9, 0x41, 0x02, 0x9B, 0x68, 0x40, 0x05, 0xA0, 0x48, 0xBC, 0x73, 0x61, 0xD3, 0xC5, 0xD4, 0x22, 0x58, 0xD2, 0x07, 0xE9, 0x83, 0x04, 0x7A, 0x8D, 0x87, 0xD6, 0x00, 0x96, 0xAD, 0xB0, 0xD7, 0xD1, 0xD9, 0xE6, 0x8C, 0x8A, 0x5F, 0xDC, 0x28, 0x80, 0x9C, 0xE9, 0xBC, 0x04, 0xD0, 0x05, 0x58, 0x03, 0x5E, 0x40, 0xE4, 0x73, 0x2B, 0x10, 0xA0, 0x79, 0x39, 0x30, 0x40, 0x16, 0x8C, 0x16, 0x67, 0x84, 0xC1, 0xD9, 0x78, 0xB5, 0x09, 0x89, 0x51, 0x6B, 0xFD, 0xF6, 0xB3, 0x91, 0xF5, 0x16, 0x45, 0x79, 0x66, 0x4E, 0x0D, 0xF2, 0x3F, 0x04, 0xE7, 0x84, 0x47, 0xAF, 0x03, 0xF7, 0x81, 0x01, 0xD6, 0x40, 0xAC, 0xBB, 0xC9, 0x2C, 0x43, 0x2C, 0xAD, 0xCC, 0xA1, 0x1D, 0x1B, 0x68, 0xDE, 0x41, 0x00, 0x57, 0x20, 0x0C, 0xC8, 0x41, 0xCD, 0xCC, 0xA5, 0x26, 0x89, 0xEC, 0x5F, 0x12, 0xFD, 0x3E, 0x5E, 0xC3, 0xA4, 0x8F, 0x42, 0x6F, 0x79, 0x0D, 0x1B, 0xF0, 0x61, 0xEF, 0xC1, 0x5C, 0x51, 0x57, 0x00, 0x7B, 0x03, 0x22, 0x80, 0xFA, 0xA0, 0x00, 0xB7, 0x31, 0xDA, 0xA6, 0xD1, 0xE0, 0xF6, 0x70, 0xFF, 0xEB, 0xCF, 0xC9, 0x54, 0x18, 0x77, 0xAD, 0xD3, 0xDE, 0xDB, 0x66, 0x65, 0xB3, 0x6F, 0x68, 0x88, 0xF7, 0x25, 0x62, 0x92, 0xEF, 0x21, 0x4D, 0xD7, 0x9D, 0xC9, 0x9D, 0xF2, 0x08, 0xB4, 0x0E, 0x42, 0x81, 0x23, 0x03, 0xC0, 0x8A, 0xE0, 0xBA, 0x32, 0x12, 0xE2, 0xB4, 0x5A, 0xB3, 0x81, 0x13, 0x05, 0xE4, 0x80, 0x8B, 0x5F, 0x8E, 0x79, 0xB9, 0x26, 0x71, 0x9B, 0xE4, 0x97, 0x71, 0x5E, 0xD3, 0x93, 0xAD, 0x64, 0xE6, 0x7E, 0x9E, 0x80, 0xEF, 0x5B, 0x97, 0x63, 0x6D, 0x60, 0x1B, 0x20, 0x09, 0x98, 0x01, 0xE1, 0x40, 0x26, 0xB5, 0xAE, 0xC6, 0x68, 0x72, 0x49, 0x1B, 0xC6, 0xB9, 0xAD, 0x33, 0xCA, 0x90, 0x53, 0x34, 0x33, 0x07, 0xDC, 0xCD, 0xD9, 0xA5, 0x97, 0x5F, 0x28, 0xF7, 0xEB, 0x17, 0x8A, 0x7F, 0x4D, 0x4F, 0x07, 0xB6, 0xDE, 0x10, 0x1A, 0xF4, 0x6A, 0x7C, 0x51, 0xA7, 0x7D, 0xE0, 0xE9, 0xA1, 0x19, 0x0E, 0x68, 0x0D, 0x16, 0xE0, 0x01, 0x30, 0xFE, 0x7E, 0x4A, 0x00, 0x18, 0xC5, 0xF3, 0x31, 0xDA, 0x86, 0xB5, 0x36, 0x4D, 0xB1, 0x7E, 0xE1, 0x5F, 0xA4, 0xEB, 0x5F, 0xE5, 0xFC, 0x32, 0x30, 0x01, 0xBC, 0x81, 0x34, 0xA0, 0x6D, 0x56, 0xB8, 0x81, 0x6E, 0xC0, 0x63, 0x8C, 0xA6, 0xFF, 0xDC, 0x3C, 0x31, 0x6A, 0x63, 0xE3, 0x74, 0x36, 0xD3, 0x39, 0x77, 0x20, 0x65, 0x2F, 0xF7, 0x5D, 0xDE, 0xF3, 0xE4, 0x0B, 0xED, 0xBE, 0xED, 0x62, 0x7B, 0xB0, 0x9E, 0x22, 0xEC, 0xFC, 0xC9, 0x2E, 0x1B, 0x0B, 0xCE, 0x18, 0x4D, 0xB1, 0x23, 0x38, 0xB2, 0x66, 0x77, 0x57, 0x1E, 0x93, 0x16, 0x10, 0x31, 0x28, 0xA0, 0xF4, 0x76, 0x16, 0x46, 0x01, 0xCC, 0x9D, 0x5C, 0x05, 0x88, 0x02, 0xDA, 0x80, 0x0D, 0x22, 0x81, 0xCA, 0x99, 0x8F, 0x0E, 0x6C, 0x1D, 0xF4, 0xD3, 0x46, 0x49, 0x01, 0x4F, 0x20, 0x0A, 0x28, 0xCE, 0x4E, 0xFB, 0xEB, 0xEF, 0xCC, 0xDB, 0xB3, 0x87, 0xD1, 0x82, 0xEC, 0x9B, 0x57, 0x98, 0x32, 0xE5, 0xF8, 0x42, 0x62, 0x13, 0xAB, 0x6E, 0xAA, 0xC1, 0x5F, 0x19, 0x69, 0xCC, 0xD1, 0xEE, 0x64, 0x48, 0x37, 0xE6, 0x9F, 0xA5, 0xC7, 0x60, 0x82, 0x0F, 0xFC, 0x33, 0xD6, 0x3C, 0x94, 0x9A, 0xB1, 0x3F, 0xFE, 0x40, 0x98, 0x20, 0x28, 0x6D, 0x7F, 0xC4, 0x2F, 0x83, 0xBD, 0xD5, 0xD8, 0x67, 0x32, 0x4F, 0x5E, 0xFC, 0x39, 0x09, 0xC7, 0x11, 0x98, 0x30, 0xFE, 0x01, 0xE2, 0xD6, 0xFD, 0xE8, 0x41, 0x6D, 0x20, 0xE3, 0x5E, 0x13, 0x56, 0x03, 0x54, 0x64, 0x3E, 0x7E, 0x83, 0x00, 0xA2, 0x00, 0x89, 0x5B, 0x8E, 0x65, 0xF3, 0x15, 0xE3, 0x36, 0xE0, 0x1C, 0x59, 0xEF, 0x70, 0x83, 0x7F, 0x7E, 0xF5, 0x87, 0xEA, 0x98, 0xAC, 0xA1, 0xE0, 0x58, 0x47, 0x9B, 0x7F, 0x60, 0x05, 0x10, 0x75, 0xB4, 0x56, 0x59, 0x38, 0xF4, 0x93, 0x0A, 0x2F, 0x18, 0xC9, 0xBF, 0x4D, 0x17, 0xA8, 0x04, 0x3E, 0xEB, 0xF8, 0x74, 0xBA, 0xF1, 0x69, 0xA0, 0x6B, 0x75, 0xB6, 0x78, 0xB5, 0x5F, 0x7A, 0x2B, 0xF3, 0xB6, 0xD9, 0x35, 0x36, 0x4E, 0xCD, 0x7E, 0x04, 0x63, 0x7E, 0x94, 0x08, 0xA6, 0xE3, 0xF7, 0xDA, 0x7B, 0xCE, 0x71, 0xB1, 0x07, 0x36, 0xE0, 0xDA, 0x31, 0x48, 0x1F, 0x7B, 0x0C, 0x96, 0xF2, 0x21, 0xA0, 0x02, 0xAC, 0x02, 0x24, 0xE7, 0xCD, 0x45, 0x93, 0xC5, 0xBF, 0x4D, 0x06, 0x25, 0x7B, 0x47, 0xF4, 0x22, 0x05, 0xE9, 0x39, 0xDB, 0xC6, 0xAD, 0xFE, 0x4D, 0x4D, 0xF5, 0x19, 0x66, 0xFB, 0xD2, 0x86, 0x4F, 0x2A, 0x99, 0xC9, 0xF1, 0xB9, 0x27, 0x4F, 0x55, 0x09, 0x4B, 0x58, 0x01, 0xDE, 0x00, 0x85, 0x41, 0x56, 0xE3, 0x95, 0xBC, 0x7C, 0xCA, 0x71, 0x6E, 0x4C, 0x5A, 0xBF, 0x78, 0xC7, 0x82, 0x05, 0xD9, 0xB3, 0xA9, 0x9F, 0xE6, 0x2C, 0x76, 0xCA, 0x94, 0x4B, 0x01, 0x59, 0xB7, 0xBE, 0x75, 0x28, 0xE0, 0x09, 0xC4, 0xBA, 0xCF, 0xDD, 0xEA, 0xCF, 0x26, 0x55, 0x80, 0x06, 0x70, 0x6A, 0x47, 0x02, 0xE0, 0x98, 0x8D, 0xA0, 0xCD, 0x6E, 0x27, 0x50, 0x9C, 0xAC, 0xF8, 0x39, 0x14, 0x7B, 0xC1, 0x67, 0xDD, 0x85, 0xB4, 0x95, 0x51, 0x0F, 0x8E, 0xDC, 0x57, 0x6D, 0x4F, 0xF4, 0x95, 0x9F, 0xEC, 0xD4, 0x7F, 0xF6, 0x53, 0x1C, 0x51, 0xFE, 0x73, 0x8B, 0xD1, 0x81, 0xAF, 0xF3, 0x69, 0x9F, 0x8A, 0x89, 0x75, 0xB5, 0x7B, 0x4D, 0x3C, 0xDC, 0x71, 0x4A, 0xCA, 0x17, 0xA5, 0x22, 0xE2, 0x32, 0x53, 0x7F, 0xB0, 0xE3, 0xE9, 0xD5, 0x37, 0x5A, 0xBF, 0x1E, 0xF7, 0xA6, 0x02, 0x5A, 0x03, 0xBF, 0x3F, 0xC5, 0x33, 0x8A, 0x34, 0x01, 0x69, 0x3E, 0x7C, 0xE2, 0x3F, 0x71, 0x8B, 0x47, 0x69, 0xD1, 0x68, 0x75, 0x39, 0xB6, 0xC5, 0x36, 0x8C, 0xC6, 0x58, 0x7F, 0xF5, 0x57, 0xC1, 0x1A, 0xDE, 0x13, 0xDE, 0x48, 0x5C, 0x59, 0xCA, 0xE8, 0x6C, 0xBC, 0xCA, 0x62, 0x59, 0x46, 0x01, 0x08, 0xF3, 0x9E, 0x30, 0xE5, 0xAE, 0x33, 0x12, 0x7D, 0x0E, 0x8C, 0xDD, 0xFA, 0xAC, 0x59, 0xE7, 0xB2, 0x92, 0xBF, 0xC0, 0x9A, 0x9E, 0xCE, 0x78, 0xD2, 0xBF, 0x66, 0xDE, 0xCA, 0x85, 0x2C, 0xE4, 0x27, 0xF2, 0x62, 0xA7, 0xE2, 0x2A, 0x17, 0xE0, 0x02, 0x88, 0xDF, 0xF1, 0x9B, 0xCA, 0x81, 0x3E, 0x93, 0x33, 0x81, 0xEC, 0x5B, 0x47, 0x91, 0x16, 0xCC, 0x81, 0x3A, 0xB0, 0xFA, 0x9E, 0x9C, 0xEB, 0x0C, 0xB4, 0xBE, 0xC2, 0x4E, 0x7A, 0xF2, 0xFA, 0xD8, 0x75, 0x6A, 0x7F, 0x0B, 0x3B, 0xC3, 0x3E, 0xBE, 0x65, 0x4E, 0xB7, 0xF5, 0xD9, 0xEC, 0xDD, 0x37, 0x2D, 0x98, 0x5D, 0x7C, 0x55, 0xD1, 0xF4, 0xF1, 0x16, 0x9C, 0x8A, 0xCD, 0x4B, 0x85, 0x66, 0x9F, 0x83, 0xBA, 0xD4, 0xD8, 0xAC, 0x7E, 0x25, 0x97, 0x7A, 0x3A, 0x0D, 0xD6, 0xD5, 0x2E, 0x77, 0xAE, 0x3C, 0x6C, 0x0D, 0x15, 0x47, 0x95, 0xC8, 0xEB, 0x0E, 0xA8, 0x9A, 0xDE, 0xF1, 0xC2, 0x1A, 0xE4, 0x02, 0x22, 0x06, 0x7D, 0xD7, 0x62, 0x59, 0x01, 0xE5, 0x40, 0xEA, 0xFD, 0x70, 0xEF, 0xE7, 0xFA, 0xBC, 0x80, 0xDC, 0x63, 0xB3, 0x5C, 0x5F, 0xE6, 0x7B, 0x8C, 0x1F, 0x63, 0x6B, 0xDD, 0x7B, 0x40, 0xDB, 0xF4, 0xAB, 0xB4, 0xD1, 0xED, 0x9C, 0x82, 0xC6, 0x95, 0xBF, 0x44, 0xBE, 0xAE, 0xF5, 0x53, 0xE6, 0x2A, 0xCE, 0x07, 0x26, 0x4D, 0x4C, 0x19, 0xBD, 0x09, 0x3E, 0xD9, 0x9C, 0xE8, 0x99, 0x12, 0xA7, 0x4C, 0x1C, 0xCB, 0x39, 0x1E, 0x04, 0xA3, 0xDE, 0xC7, 0xAB, 0x11, 0xF2, 0x4B, 0x19, 0xB6, 0xD3, 0x6E, 0x39, 0xF7, 0xF8, 0x8C, 0x98, 0x71, 0x48, 0x39, 0x16, 0xBF, 0xC3, 0xC7, 0x51, 0x40, 0x12, 0x36, 0x48, 0xA0, 0xD6, 0x80, 0x69, 0x4B, 0x0E, 0x34, 0xBB, 0x08, 0x1A, 0x20, 0x36, 0x0F, 0x15, 0xB0, 0x06, 0x76, 0x02, 0x1A, 0xF3, 0x8A, 0x8C, 0xCD, 0xF6, 0x19, 0x67, 0xFE, 0x8D, 0x17, 0xA5, 0xCD, 0x70, 0x12, 0xB7, 0xC6, 0x29, 0x3D, 0x0B, 0x2D, 0xAD, 0xC7, 0xD5, 0x6D, 0x88, 0x8E, 0xE6, 0x7B, 0xA8, 0x3D, 0x6E, 0x57, 0xC5, 0xA7, 0x3C, 0x9B, 0x5D, 0xF9, 0x78, 0x10, 0x03, 0x58, 0x57, 0xFE, 0x98, 0xCE, 0xC3, 0x7D, 0xD4, 0x4A, 0x72, 0xFD, 0x24, 0x08, 0x82, 0xE7, 0x57, 0x58, 0x92, 0x95, 0xDA, 0x4D, 0x67, 0xD3, 0x51, 0x26, 0x3A, 0x4A, 0x9B, 0xC1, 0x71, 0x33, 0x48, 0xA0, 0x02, 0x08, 0x1F, 0x2C, 0xC0, 0x0B, 0x88, 0x7D, 0xCF, 0x51, 0xED, 0x7B, 0x84, 0x85, 0x00, 0x5A, 0xC0, 0x92, 0xBB, 0x17, 0x40, 0xE7, 0x59, 0x05, 0xC6, 0x68, 0xF2, 0xE5, 0xB9, 0xA8, 0xD5, 0x9F, 0x27, 0x84, 0x92, 0x11, 0x29, 0x33, 0xD4, 0x93, 0x78, 0x4F, 0x6B, 0xCA, 0x0F, 0x61, 0xB5, 0x60, 0xB4, 0xDE, 0xB7, 0x60, 0x9A, 0xD3, 0x68, 0x54, 0x60, 0x62, 0x8F, 0x0F, 0x5F, 0xF4, 0x16, 0xDF, 0x22, 0x77, 0xA7, 0x72, 0x7E, 0x52, 0x54, 0xE2, 0x1A, 0x3F, 0x30, 0xC9, 0x11, 0xBB, 0x38, 0xBD, 0xEA, 0xED, 0xA8, 0xFA, 0xE4, 0x2F, 0x41, 0x32, 0x07, 0x3E, 0x46, 0x83, 0x67, 0x15, 0x98, 0x87, 0x2B, 0x01, 0x1D, 0xD8, 0x1E, 0xF8, 0x20, 0x01, 0xD7, 0x3B, 0x1A, 0x6B, 0x05, 0x54, 0x02, 0xF9, 0x3C, 0x5C, 0xA7, 0xF1, 0x23, 0xD0, 0x32, 0xAF, 0x18, 0x8D, 0xA6, 0x67, 0xA4, 0x05, 0x26, 0xF7, 0xB5, 0xA2, 0x85, 0x6F, 0xC4, 0xFB, 0xDD, 0xF1, 0xD3, 0xA2, 0x93, 0x85, 0x7E, 0x47, 0x53, 0x1C, 0xDC, 0x47, 0xF9, 0x72, 0xAD, 0x2B, 0x80, 0xB6, 0x8F, 0xA3, 0x47, 0x36, 0x33, 0xF2, 0xC6, 0x4C, 0x32, 0x76, 0x1D, 0xFB, 0x04, 0xBB, 0xF7, 0x6F, 0xE6, 0x50, 0xFD, 0xDA, 0x1B, 0x2D, 0x58, 0xB2, 0xCE, 0x10, 0xF3, 0x18, 0xC3, 0x70, 0xC5, 0x7F, 0x16, 0x2A, 0xDF, 0x40, 0xCA, 0x60, 0x03, 0xDE, 0x03, 0x7B, 0x90, 0x40, 0x31, 0x72, 0x31, 0x88, 0x7C, 0xA5, 0x76, 0xEF, 0xEA, 0xD4, 0x8C, 0x7B, 0x0D, 0x8C, 0x63, 0x34, 0xFB, 0x3C, 0xB4, 0x12, 0x48, 0x7B, 0x5C, 0xDB, 0xAF, 0x6E, 0x3E, 0x95, 0x8E, 0x84, 0xBA, 0x5D, 0xE8, 0xEC, 0x2F, 0x32, 0x13, 0xE9, 0x29, 0xED, 0x39, 0xFB, 0x80, 0xFF, 0xAA, 0xEA, 0xD8, 0xE4, 0x51, 0x92, 0x4D, 0x88, 0xC6, 0x5A, 0xC9, 0x92, 0xB9, 0x63, 0x42, 0x3F, 0x7D, 0x64, 0xC7, 0x84, 0x74, 0xA7, 0x5D, 0x85, 0xAC, 0x93, 0xE5, 0xC9, 0x20, 0x7B, 0x9F, 0xFC, 0xDC, 0xCC, 0xBB, 0x25, 0xAA, 0x35, 0x50, 0x57, 0xCF, 0x03, 0x24, 0x3A, 0x7F, 0xB0, 0x00, 0x52, 0x80, 0x52, 0xA0, 0x8D, 0xBA, 0xFD, 0x40, 0x1F, 0x19, 0x87, 0x00, 0x24, 0xA8, 0x8E, 0xFB, 0xC1, 0x03, 0x90, 0x81, 0xF9, 0xE2, 0x2B, 0x30, 0xDA, 0x67, 0x18, 0x85, 0x18, 0x70, 0x7E, 0x4E, 0x5C, 0x1A, 0x8D, 0x7E, 0x2C, 0x43, 0x1D, 0x6C, 0x36, 0xDA, 0xBF, 0x24, 0x1E, 0x8E, 0x5D, 0xB3, 0x68, 0x34, 0xE3, 0xF4, 0x94, 0x93, 0xD4, 0xCE, 0x2F, 0xFF, 0x8B, 0x8A, 0xE8, 0xA3, 0xAE, 0x0B, 0x3F, 0x33, 0x55, 0xA8, 0xEE, 0xBA, 0xA1, 0x1C, 0x99, 0x04, 0xE7, 0x82, 0x8E, 0xEF, 0x69, 0x63, 0x8A, 0x73, 0xFE, 0xBB, 0xB7, 0x4B, 0xF3, 0xA7, 0x95, 0x6A, 0x3C, 0xA2, 0x62, 0x3A, 0xF0, 0x41, 0x0E, 0x0A, 0x68, 0xB9, 0x95, 0x73, 0x59, 0xD4, 0xB0, 0x13, 0x58, 0xCE, 0x87, 0x80, 0x36, 0xB0, 0x17, 0x20, 0x7C, 0x45, 0x39, 0xD2, 0xE2, 0x8B, 0x9F, 0xC4, 0x86, 0xD2, 0x4B, 0xAB, 0x5C, 0xB7, 0x81, 0x0A, 0x47, 0xB6, 0x9D, 0x04, 0x14, 0x9E, 0x4D, 0xA7, 0xA5, 0xB5, 0x5F, 0x0D, 0xFE, 0xDD, 0x69, 0x34, 0x67, 0x90, 0x84, 0xDE, 0xC3, 0x64, 0x28, 0x12, 0xE0, 0x84, 0x34, 0x36, 0xC8, 0xB9, 0x52, 0xCE, 0xD8, 0x87, 0x61, 0x06, 0x5C, 0x9D, 0x11, 0x13, 0x97, 0x18, 0xBF, 0x9D, 0x2B, 0x4D, 0x0B, 0x20, 0x75, 0x2F, 0xEF, 0xFC, 0xE4, 0x8F, 0x98, 0x40, 0x3E, 0x46, 0x6B, 0x19, 0xF0, 0x9A, 0x44, 0x1B, 0x14, 0x50, 0xEB, 0x8E, 0xF0, 0xAC, 0xE0, 0x43, 0xC0, 0x0C, 0x10, 0x9A, 0x90, 0xAF, 0x38, 0x8C, 0x76, 0x69, 0x26, 0xF7, 0x3E, 0x45, 0x6E, 0x6B, 0x27, 0xF2, 0x32, 0x65, 0x9C, 0x86, 0xD2, 0x38, 0x6B, 0xEF, 0x84, 0xB0, 0x59, 0xED, 0xAB, 0x6A, 0xDD, 0xF2, 0xC9, 0x4E, 0x8E, 0xFD, 0xB6, 0x5D, 0x37, 0x20, 0xFD, 0x97, 0xFB, 0x39, 0x21, 0x09, 0x66, 0xFE, 0x50, 0x90, 0x83, 0xA3, 0x29, 0x4E, 0x59, 0xED, 0x6E, 0x0E, 0x8E, 0xFB, 0x64, 0xB5, 0x75, 0xE4, 0x46, 0x0D, 0xF0, 0x0D, 0x68, 0x03, 0x7C, 0x45, 0x1C, 0xF0, 0xF5, 0x1F, 0x50, 0xA0, 0xD6, 0x7D, 0xB7, 0x8C, 0x78, 0xEE, 0x50, 0xFB, 0xDE, 0x91, 0x53, 0x81, 0xDE, 0x5C, 0xF6, 0x68, 0xB4, 0xFA, 0xEB, 0x2F, 0x67, 0x46, 0xFE, 0x12, 0x8B, 0xF4, 0x75, 0x87, 0x8A, 0x96, 0xCF, 0x10, 0x1A, 0xFB, 0x43, 0xAF, 0x9A, 0xB5, 0xFA, 0xEE, 0x15, 0xE5, 0x4D, 0xA3, 0xF5, 0xD9, 0xB8, 0xA8, 0xAB, 0xC5, 0xBE, 0xFB, 0x40, 0x17, 0xB0, 0x2F, 0xB5, 0x24, 0x3F, 0x82, 0x65, 0xC6, 0x8E, 0x1F, 0x36, 0xF3, 0x52, 0xB1, 0xE2, 0x5C, 0x42, 0x27, 0x71, 0x52, 0xD4, 0xD6, 0xE6, 0x88, 0xB9, 0xAF, 0xE0, 0xBA, 0x00, 0x49, 0xC0, 0x1D, 0x88, 0x0D, 0xF8, 0xC0, 0x7A, 0x50, 0xB7, 0xED, 0xD2, 0xEE, 0xB8, 0xBF, 0x0D, 0xB4, 0xEF, 0x8E, 0x09, 0x95, 0xFF, 0x92, 0x9C, 0x14, 0x1A, 0xAD, 0xBF, 0x74, 0x97, 0x9D, 0x8F, 0x9B, 0x83, 0xD5, 0xEA, 0x9E, 0x10, 0xF8, 0xB4, 0xF8, 0x93, 0xDF, 0xA2, 0xF9, 0xC8, 0xA5, 0xB9, 0x5E, 0x23, 0x0D, 0x03, 0x9D, 0xDE, 0x43, 0x96, 0x76, 0x01, 0xCB, 0x7E, 0x02, 0x05, 0x72, 0x26, 0xA4, 0x60, 0x6B, 0x64, 0x3B, 0x6B, 0x7A, 0x67, 0x64, 0xFD, 0x5C, 0x36, 0x72, 0x34, 0x6C, 0x6B, 0x03, 0xD6, 0x03, 0x03, 0xD4, 0x01, 0x63, 0xEC, 0xEB, 0xB2, 0x81, 0x1D, 0x45, 0x6B, 0x75, 0xC0, 0x15, 0x88, 0x35, 0xC8, 0x5B, 0x39, 0xD0, 0x37, 0x50, 0x01, 0xE4, 0xC0, 0x0D, 0xD8, 0x7C, 0xF3, 0x39, 0xCD, 0x64, 0x8C, 0xD1, 0x6A, 0x1D, 0x6B, 0x35, 0xB4, 0x37, 0xAE, 0x23, 0x47, 0x57, 0xC3, 0x59, 0x9D, 0x86, 0x11, 0x1D, 0x81, 0xBD, 0x0C, 0x05, 0x17, 0xDA, 0x34, 0x9A, 0x5D, 0x6D, 0x16, 0xB1, 0xED, 0x51, 0xFE, 0xEE, 0x56, 0xB8, 0xB0, 0x0F, 0x31, 0x0F, 0x27, 0xCA, 0xBA, 0x37, 0xB7, 0x2A, 0x61, 0xB6, 0xE8, 0xD3, 0x7A, 0x85, 0x36, 0x88, 0xBE, 0xC7, 0x0F, 0xFD, 0x4F, 0xD9, 0x80, 0x2F, 0xC0, 0x06, 0x91, 0xCC, 0x84, 0x00, 0xCC, 0x07, 0xF6, 0x2F, 0x14, 0x90, 0xC7, 0x19, 0xF2, 0x04, 0x2F, 0x1C, 0x90, 0x7D, 0x8F, 0xE5, 0xC8, 0x67, 0xA4, 0x15, 0x8D, 0xB6, 0x69, 0xB4, 0xC1, 0xED, 0x49, 0x4B, 0x49, 0x88, 0xC2, 0xED, 0x59, 0x0D, 0x44, 0xC6, 0xBD, 0x06, 0x63, 0xF9, 0x6B, 0x34, 0x61, 0x45, 0x22, 0xA7, 0xE7, 0xAE, 0xA7, 0xF7, 0x2F, 0x75, 0x1A, 0x2F, 0x77, 0x35, 0x96, 0xA3, 0xA3, 0x2E, 0xC4, 0x94, 0x04, 0xD6, 0x35, 0xDA, 0x39, 0xE7, 0xB7, 0xDC, 0x66, 0xB2, 0x7D, 0x0F, 0x31, 0x91, 0x1B, 0x9C, 0x90, 0x12, 0x80, 0xE7, 0xA0, 0x81, 0x58, 0x83, 0x3D, 0x30, 0x80, 0xBB, 0x83, 0x05, 0x50, 0x02, 0xE4, 0xF3, 0x70, 0xF5, 0x73, 0xF5, 0xE4, 0x2B, 0xC7, 0x68, 0xF2, 0xD7, 0xDF, 0xB6, 0x47, 0x4F, 0x07, 0x13, 0x4C, 0x26, 0xD8, 0x0E, 0xA3, 0xB5, 0xD5, 0xC6, 0x29, 0xCF, 0x02, 0xC7, 0xB5, 0x25, 0xAF, 0xAE, 0xED, 0x1D, 0xEF, 0xAC, 0x7C, 0x3A, 0x5D, 0x49, 0x0E, 0x58, 0xEC, 0xD4, 0xEC, 0x8A, 0x7E, 0x9C, 0xAE, 0x27, 0xDA, 0x1E, 0x67, 0x9E, 0x18, 0x37, 0x2E, 0x06, 0xF9, 0x58, 0xA0, 0xAC, 0x80, 0x1B, 0x60, 0x09, 0xA8, 0x0D, 0x0A, 0xE8, 0x75, 0x0F, 0x07, 0xD5, 0x7B, 0xE0, 0xF8, 0x1A, 0xE8, 0xA0, 0x80, 0xDE, 0xF7, 0xD4, 0x6D, 0xB9, 0xB7, 0x4D, 0xDF, 0xC0, 0xBA, 0xDC, 0x20, 0x67, 0xF3, 0xFD, 0x4D, 0x4F, 0xFD, 0xAB, 0x49, 0x81, 0xA8, 0xAF, 0x47, 0xFE, 0x7D, 0x4E, 0x8B, 0x3D, 0x79, 0x87, 0x16, 0x70, 0x03, 0x5B, 0xA3, 0x1A, 0x22, 0x8D, 0x21, 0xBB, 0x67, 0xA4, 0x5D, 0xCD, 0xAD, 0x37, 0x36, 0x84, 0xE9, 0xA6, 0x01, 0xF8, 0xFA, 0xC9, 0x7D, 0x4E, 0xD8, 0x9B, 0x9D, 0x99, 0x39, 0x70, 0xFB, 0x74, 0xC3, 0xDE, 0x4C, 0x71, 0xF4, 0x5B, 0x42, 0x79, 0xF9, 0x1D, 0x62, 0x58, 0x72, 0x5F, 0x25, 0xED, 0x71, 0xDB, 0x54, 0x73, 0x92, 0x03, 0xC5, 0x24, 0x4A, 0x03, 0xB4, 0x01, 0x17, 0xA0, 0x66, 0xEF, 0xB6, 0x02, 0x6A, 0x90, 0x03, 0xDF, 0xC0, 0xD6, 0x79, 0x33, 0x5E, 0x79, 0x37, 0x1A, 0xCD, 0xFE, 0x4A, 0x10, 0x9E, 0xBB, 0xA7, 0xE7, 0x5C, 0xFE, 0x4B, 0x20, 0xA9, 0xDA, 0x82, 0x23, 0xE3, 0x36, 0x3C, 0x44, 0x79, 0xA3, 0x5F, 0x15, 0xD8, 0xD7, 0x39, 0xAD, 0x7D, 0x8C, 0xF6, 0xAA, 0xA6, 0x98, 0xC1, 0x68, 0x62, 0x63, 0x50, 0x1D, 0x7F, 0xC1, 0x58, 0x2B, 0x7E, 0x5F, 0x22, 0x4E, 0xAE, 0x72, 0xC9, 0xAD, 0x85, 0xBE, 0x78, 0xAC, 0x20, 0x02, 0x70, 0x07, 0x4E, 0x29, 0x3C, 0x2B, 0x3D, 0xFC, 0xBE, 0x58, 0xBA, 0x3F, 0x49, 0xA6, 0x0A, 0x6C, 0x07, 0x5C, 0xD9, 0x07, 0x1F, 0x08, 0xBD, 0xAD, 0x25, 0x72, 0x37, 0x41, 0x30, 0x01, 0xBC, 0xC7, 0xCA, 0xC7, 0x68, 0xFE, 0x5A, 0x0B, 0xEE, 0x56, 0x3A, 0x1B, 0xA7, 0xC5, 0xC5, 0x2A, 0xC5, 0xEC, 0xF2, 0x9C, 0xFE, 0x48, 0xCD, 0x91, 0x76, 0xBB, 0x20, 0x6D, 0x5F, 0x9A, 0xA1, 0xCC, 0xC3, 0xB7, 0x53, 0x10, 0xD7, 0xE3, 0x5C, 0x0B, 0x07, 0x6A, 0x03, 0x39, 0x88, 0x23, 0x76, 0x7C, 0x67, 0xBA, 0x68, 0xE3, 0xE1, 0xC9, 0xBA, 0x8B, 0xDF, 0x11, 0x79, 0xAE, 0x17, 0xAC, 0x99, 0x8A, 0x73, 0x88, 0xF7, 0xB8, 0xD5, 0xAA, 0x77, 0xDE, 0xB7, 0xC6, 0xD8, 0x80, 0xC7, 0x20, 0x9F, 0x89, 0x3C, 0x08, 0x01, 0x7C, 0x20, 0x4F, 0xF3, 0xEE, 0x5C, 0x40, 0xD5, 0xBC, 0x72, 0x8C, 0x16, 0xFF, 0x6B, 0x34, 0x11, 0x98, 0x69, 0x67, 0x7D, 0x83, 0xC1, 0xD3, 0x27, 0xA5, 0x7B, 0x4F, 0x90, 0x5F, 0xE8, 0xDB, 0xBE, 0xFA, 0xED, 0x3A, 0xCF, 0xA8, 0x1F, 0x4E, 0x4B, 0xB5, 0x3A, 0x61, 0x36, 0x9B, 0x40, 0x60, 0x4D, 0xF4, 0x4B, 0x1B, 0xF0, 0x0D, 0xC4, 0x95, 0x6F, 0xFD, 0xA5, 0x23, 0x01, 0xBD, 0xE7, 0x95, 0x38, 0x3D, 0xD8, 0x4E, 0x1B, 0xEB, 0x1D, 0x83, 0x19, 0xBC, 0xC1, 0xF3, 0xC0, 0x09, 0x8A, 0x88, 0xDE, 0xDF, 0x7D, 0xBD, 0x1D, 0xCB, 0xF7, 0x40, 0xC6, 0xAC, 0x83, 0xE8, 0x5B, 0xEB, 0xBF, 0x0B, 0xC8, 0x0D, 0x48, 0x01, 0x4B, 0x81, 0x53, 0x59, 0xE8, 0xB4, 0x59, 0xFE, 0x55, 0xA2, 0xA5, 0xE7, 0xED, 0xE3, 0x96, 0x0F, 0xD9, 0x8E, 0x83, 0x7C, 0x3A, 0x3C, 0xCF, 0x5B, 0x27, 0x1E, 0x27, 0xF4, 0x6D, 0x5F, 0x92, 0x2F, 0xDE, 0xBF, 0x25, 0x89, 0x7A, 0x82, 0x3A, 0x35, 0xC1, 0x66, 0xB0, 0x84, 0x8D, 0xD7, 0xC7, 0xD0, 0xF6, 0x09, 0x9F, 0x0A, 0x90, 0x00, 0x56, 0x22, 0x39, 0xA9, 0x3F, 0x38, 0x8C, 0x6C, 0xEB, 0x94, 0x29, 0xF5, 0x2F, 0xE5, 0xE7, 0x24, 0x8E, 0x2A, 0x6C, 0xD6, 0x63, 0xB3, 0x3A, 0x53, 0x8E, 0xFD, 0x8F, 0x5C, 0xEF, 0xCB, 0x45, 0xE5, 0x60, 0x0F, 0x78, 0x3F, 0x73, 0x80, 0x13, 0x70, 0xEB, 0xA3, 0x61, 0xEF, 0x80, 0x2A, 0xB0, 0x0A, 0x90, 0x9C, 0x57, 0x8A, 0x36, 0xAB, 0xEF, 0x9E, 0xBE, 0x7C, 0xD3, 0x66, 0x98, 0xB7, 0x62, 0x33, 0x2B, 0x64, 0x6A, 0x8E, 0x6A, 0x7E, 0x5B, 0x99, 0xFC, 0xA1, 0xCD, 0xA3, 0xEC, 0x1D, 0x87, 0x5A, 0xBF, 0xB5, 0x56, 0xF6, 0x91, 0x5F, 0x17, 0x26, 0x05, 0x04, 0x2C, 0xA8, 0x09, 0x98, 0x00, 0x0C, 0xCB, 0xA6, 0xDD, 0xA3, 0x0E, 0x11, 0x04, 0x9F, 0x37, 0x79, 0xBD, 0xAF, 0x93, 0xAB, 0x21, 0x63, 0x33, 0xBF, 0xE4, 0x75, 0xE4, 0xF4, 0x1D, 0x51, 0xDE, 0x26, 0x36, 0xB0, 0xA6, 0xFD, 0xC8, 0x5B, 0xEB, 0x18, 0x83, 0x06, 0xB2, 0xCF, 0x31, 0x1D, 0x88, 0x02, 0xBC, 0x01, 0x4D, 0x60, 0x09, 0x57, 0x5C, 0x76, 0xE9, 0x9E, 0x37, 0x7D, 0x6C, 0xD6, 0xDF, 0x38, 0xCB, 0x0E, 0x5C, 0xF5, 0x76, 0x8E, 0x9A, 0x60, 0xE0, 0x0A, 0xB4, 0x15, 0xDE, 0xDE, 0xC2, 0xDC, 0x0C, 0xDD, 0x08, 0xA5, 0x49, 0x31, 0x36, 0x7C, 0x97, 0x12, 0x1B, 0xFF, 0x72, 0xF4, 0x0B, 0x31, 0xB9, 0x93, 0x35, 0x6F, 0x4C, 0x3F, 0x89, 0x05, 0xE4, 0xC0, 0x0C, 0xD8, 0x05, 0x78, 0x8C, 0x79, 0x13, 0x88, 0x31, 0x5A, 0xCB, 0x4F, 0x0B, 0x49, 0x8E, 0xC0, 0x44, 0x38, 0x9B, 0x2E, 0x62, 0xB7, 0xF3, 0xB7, 0x33, 0xEF, 0xAC, 0xAA, 0x0A, 0xF8, 0x06, 0x34, 0x06, 0x7B, 0x60, 0xC0, 0xF1, 0x07, 0x34, 0xE0, 0x0E, 0xD8, 0x40, 0xE4, 0x1E, 0x99, 0xEE, 0x40, 0xEA, 0xBC, 0x42, 0x45, 0xF8, 0xE6, 0x91, 0x96, 0xB9, 0x24, 0x93, 0x3E, 0xAA, 0x3A, 0xBA, 0xB1, 0x85, 0x92, 0x86, 0xD8, 0xE3, 0x3D, 0xB5, 0xA9, 0xA2, 0x0C, 0xAA, 0x56, 0x5D, 0xDA, 0x42, 0xA7, 0x07, 0xC0, 0x1E, 0x57, 0x77, 0x5C, 0x32, 0x96, 0x28, 0x25, 0x45, 0x12, 0xD3, 0x02, 0xD8, 0x5A, 0x42, 0xE9, 0x67, 0x13, 0x40, 0x37, 0x20, 0xD4, 0x6D, 0xC8, 0x9F, 0xA7, 0x9C, 0xC3, 0x80, 0xC2, 0x6F, 0x53, 0x7B, 0x98, 0x8F, 0x32, 0x9D, 0x5E, 0xF1, 0xCB, 0xAB, 0xAB, 0x81, 0x37, 0x60, 0x39, 0xD0, 0x81, 0x03, 0xD1, 0x8F, 0xE8, 0x62, 0x02, 0x3A, 0xD8, 0xF6, 0xD4, 0x39, 0xF8, 0xD3, 0x16, 0xD8, 0x69, 0xB3, 0xFD, 0x39, 0x20, 0x6B, 0x8A, 0x76, 0xF6, 0x88, 0xD8, 0x6E, 0x16, 0xA5, 0xC8, 0x46, 0xF4, 0x72, 0xFB, 0x94, 0xD6, 0x27, 0x32, 0xB6, 0x4C, 0xB8, 0x53, 0xBE, 0x0D, 0xC4, 0xB9, 0x8B, 0xD3, 0x3F, 0xFB, 0xCB, 0xBC, 0xC8, 0x53, 0x71, 0x14, 0x39, 0x58, 0xC0, 0xF6, 0x49, 0x42, 0xE0, 0xC3, 0x29, 0x79, 0x3E, 0x05, 0x0E, 0x93, 0xAD, 0x22, 0x1C, 0x9F, 0x34, 0x6B, 0x50, 0x17, 0x8D, 0x72, 0x94, 0x77, 0x68, 0x25, 0xF6, 0xDD, 0x4C, 0x6F, 0x63, 0xB1, 0xA3, 0x86, 0x8C, 0xE5, 0x60, 0x0D, 0x0C, 0x28, 0xBA, 0x36, 0xAD, 0x80, 0x6A, 0x20, 0x13, 0xB0, 0x71, 0x43, 0xD2, 0xC1, 0xAE, 0x40, 0x9E, 0x4C, 0xA6, 0x3D, 0x36, 0x93, 0x2F, 0x9F, 0xCA, 0x63, 0x4F, 0xEE, 0x79, 0xE2, 0xF7, 0x5B, 0x8E, 0x12, 0x62, 0x11, 0x44, 0xCB, 0x4B, 0x61, 0xC1, 0xA0, 0xE7, 0xDF, 0xEE, 0x4A, 0xE2, 0x7E, 0x4E, 0x1B, 0x41, 0x57, 0x5A, 0x6D, 0x0E, 0x11, 0xF6, 0x91, 0x07, 0xDA, 0x80, 0x08, 0x3E, 0xFC, 0x95, 0xA0, 0xEB, 0xA9, 0x7A, 0xC8, 0x19, 0xA0, 0x31, 0x3F, 0x50, 0x54, 0xDE, 0x63, 0x8D, 0xAC, 0xC0, 0x3E, 0xF5, 0xCB, 0x14, 0xF1, 0x73, 0x36, 0xF3, 0x06, 0xB6, 0xDE, 0x5B, 0x9F, 0xBE, 0xA2, 0xF4, 0x32, 0x30, 0xC0, 0xD7, 0x73, 0xAB, 0xD7, 0x7B, 0xE3, 0xED, 0x27, 0x0B, 0xCC, 0x16, 0xE0, 0x79, 0xDC, 0x90, 0x63, 0xB4, 0x91, 0xAD, 0xFA, 0x5D, 0xD2, 0x89, 0xED, 0xA7, 0x01, 0xB4, 0x27, 0x22, 0x9D, 0x5B, 0x15, 0x71, 0xE4, 0x8A, 0xB3, 0x73, 0x22, 0x6C, 0x09, 0x62, 0x0C, 0x17, 0xEF, 0xB7, 0xC5, 0x2D, 0x13, 0x0B, 0xA9, 0x8F, 0xB5, 0x1D, 0x17, 0x94, 0x0F, 0x91, 0xBF, 0x44, 0x0E, 0x99, 0x4F, 0xD3, 0x13, 0xC1, 0x26, 0xCF, 0xCC, 0xA6, 0x6C, 0xDF, 0xD8, 0xCE, 0x95, 0xE2, 0xB2, 0x3D, 0x31, 0x3C, 0x3D, 0xDD, 0x17, 0xB7, 0x4F, 0x66, 0xD1, 0x07, 0x3D, 0x7B, 0x82, 0xB1, 0xDD, 0x42, 0x01, 0xBB, 0x81, 0xA5, 0x77, 0x4D, 0xDA, 0xDA, 0x80, 0x3A, 0xD0, 0x75, 0x8B, 0xC9, 0x4B, 0x00, 0x6B, 0x3D, 0x0D, 0x21, 0x0D, 0xB0, 0x35, 0xAF, 0xF8, 0xD8, 0xCC, 0xAE, 0xE0, 0x5D, 0xF7, 0x24, 0x21, 0x5B, 0x4F, 0x9C, 0x7B, 0x4F, 0xFE, 0x4D, 0x4D, 0xA6, 0xDD, 0x5C, 0xA0, 0xB4, 0xAE, 0xE0, 0x9D, 0x9F, 0xA2, 0x3B, 0x3B, 0x05, 0xD7, 0xBF, 0xD8, 0x61, 0x1C, 0xD5, 0x6B, 0x2F, 0xC0, 0x1C, 0x0F, 0x5D, 0x79, 0xC7, 0x9A, 0x64, 0x24, 0x56, 0xA7, 0x17, 0x50, 0x02, 0xF8, 0x3A, 0xEE, 0xB5, 0x33, 0x4D, 0x92, 0x3D, 0x1F, 0x8E, 0xD3, 0x75, 0xCB, 0x9D, 0x67, 0x11, 0x39, 0x78, 0x9B, 0x6E, 0x1B, 0xA0, 0x35, 0xC8, 0x01, 0x5F, 0x91, 0x7F, 0xF4, 0x0B, 0xD2, 0x27, 0xC8, 0x9C, 0x05, 0x78, 0x3D, 0xD9, 0x08, 0x67, 0x45, 0x73, 0x1A, 0x0D, 0x07, 0x27, 0x8B, 0x69, 0x46, 0x5E, 0x80, 0x37, 0x4E, 0x29, 0xD2, 0xC8, 0x5D, 0x57, 0x1B, 0x59, 0xF5, 0xBC, 0x35, 0x6D, 0x95, 0x46, 0xF3, 0x53, 0x7F, 0x38, 0x16, 0xA1, 0xE8, 0xA5, 0x52, 0xCE, 0x11, 0x30, 0x8A, 0x24, 0x7D, 0x60, 0x9A, 0x63, 0x9F, 0xCB, 0x55, 0x14, 0xB0, 0xFB, 0x97, 0xC9, 0xE1, 0xB4, 0xDD, 0xDC, 0x56, 0x27, 0xB3, 0x3D, 0xCF, 0x56, 0xB6, 0x9F, 0x56, 0x95, 0x3B, 0xFE, 0xA1, 0xC2, 0x90, 0x0E, 0x44, 0x0C, 0xEC, 0xFE, 0xD4, 0x7A, 0xAF, 0xFF, 0x25, 0x40, 0x6E, 0x3E, 0x7C, 0xFC, 0x1B, 0xFE, 0x84, 0xD6, 0x85, 0x46, 0x8B, 0xAB, 0x62, 0x4C, 0xA6, 0x69, 0xC3, 0x96, 0x9C, 0x74, 0xBA, 0x9E, 0xBE, 0x5F, 0xF6, 0x6D, 0xED, 0x31, 0x06, 0x5D, 0x2B, 0xB9, 0xFE, 0xDF, 0xE2, 0x08, 0xCA, 0x14, 0xE3, 0x93, 0xCC, 0x46, 0xD5, 0x32, 0x9A, 0x69, 0x01, 0xD4, 0x8F, 0x6B, 0xFA, 0x36, 0x37, 0xB0, 0x1A, 0xB6, 0x4B, 0x1F, 0x34, 0x60, 0xF9, 0x6B, 0x24, 0x3F, 0xD3, 0x9A, 0x7E, 0x91, 0x3A, 0xA2, 0x0A, 0xB5, 0x6E, 0x27, 0x84, 0xD6, 0xB3, 0xEB, 0x3D, 0xAA, 0x6C, 0xAE, 0x83, 0x7D, 0x7F, 0x4A, 0x2E, 0x77, 0xFA, 0x2F, 0x4F, 0x9A, 0x3E, 0x8D, 0xBF, 0x0A, 0x28, 0xBE, 0xD2, 0x34, 0x5A, 0x1E, 0xA3, 0xC5, 0x97, 0xCF, 0x23, 0x48, 0x92, 0xDC, 0x89, 0xDF, 0xBD, 0xA6, 0xC7, 0x68, 0x3B, 0x8A, 0x61, 0x11, 0xC3, 0xCB, 0xDC, 0x88, 0x0E, 0x34, 0xA3, 0x03, 0x72, 0xA5, 0x26, 0x73, 0x29, 0xED, 0x53, 0xD9, 0x74, 0x74, 0x20, 0x5D, 0x81, 0xCD, 0xB0, 0xBF, 0xDE, 0xCD, 0x63, 0xCD, 0x00, 0x95, 0xDF, 0xF6, 0x85, 0xF4, 0xD3, 0xB3, 0xC3, 0xE5, 0x89, 0xD0, 0x9E, 0x23, 0x06, 0x87, 0x43, 0x3C, 0xE9, 0x53, 0x0E, 0xD4, 0x1A, 0xC8, 0x93, 0xBD, 0x61, 0x03, 0x19, 0xF8, 0x33, 0xD2, 0x06, 0x59, 0x40, 0x0C, 0x6C, 0x3F, 0x17, 0x30, 0x7D, 0x32, 0xAC, 0x9C, 0x46, 0xAB, 0xBB, 0x0D, 0xA5, 0xCA, 0x9F, 0xE6, 0xF9, 0x26, 0x22, 0x73, 0x07, 0xB1, 0x3D, 0x09, 0x1A, 0x89, 0x42, 0xE7, 0x48, 0x96, 0x40, 0xDD, 0xF5, 0x63, 0x8C, 0x40, 0x1E, 0xAD, 0xF2, 0x08, 0x36, 0x4A, 0xB8, 0x15, 0xAF, 0x33, 0xEE, 0x66, 0x08, 0xFB, 0x91, 0x8F, 0xA3, 0x34, 0x04, 0xFD, 0x95, 0xB1, 0xE6, 0x95, 0x0F, 0x76, 0x96, 0x62, 0xC5, 0x59, 0x56, 0x9F, 0x5D, 0x73, 0x09, 0x4D, 0x38, 0xD0, 0xA7, 0x05, 0x55, 0x0F, 0x68, 0xC9, 0x04, 0x68, 0x73, 0x19, 0x30, 0x4E, 0x27, 0x02, 0xEC, 0xC5, 0x87, 0x4F, 0xAC, 0x60, 0x3D, 0xD9, 0x42, 0x49, 0xA3, 0xF5, 0x77, 0x4A, 0xDB, 0x41, 0xB9, 0x6E, 0x36, 0x83, 0xEE, 0x51, 0x20, 0x28, 0xEC, 0x49, 0xED, 0xD8, 0x4A, 0xBB, 0x21, 0x87, 0xB4, 0x6E, 0x19, 0x0E, 0x0E, 0x34, 0xBB, 0x3A, 0xCE, 0xEF, 0x3A, 0x32, 0xB2, 0x47, 0x35, 0xB1, 0x9E, 0x63, 0x2B, 0x15, 0x63, 0x9F, 0x3A, 0xC0, 0xA3, 0x4B, 0x70, 0xE9, 0x32, 0xFA, 0x51, 0xC7, 0x11, 0x9A, 0xDC, 0x27, 0x82, 0xCC, 0x98, 0x9F, 0x61, 0x2C, 0xE6, 0xFA, 0xA0, 0x0A, 0xC4, 0x02, 0xD2, 0x80, 0x28, 0x20, 0x65, 0x70, 0x69, 0xC8, 0x60, 0x38, 0x00, 0x4C, 0x72, 0xD1, 0x04, 0x24, 0xE7, 0x61, 0x00, 0xD6, 0xC0, 0x0E, 0x40, 0xF1, 0x26, 0xA3, 0xC4, 0x9B, 0xB2, 0x08, 0x25, 0x38, 0xA6, 0x79, 0x21, 0xDB, 0x96, 0x15, 0xC4, 0x4B, 0x7A, 0xFE, 0xC4, 0x89, 0x5F, 0xD7, 0x64, 0xBA, 0xA6, 0xA2, 0x5B, 0x83, 0xBE, 0x51, 0x62, 0x1A, 0xAD, 0x38, 0xB4, 0x68, 0x98, 0xB8, 0xFD, 0x3E, 0x51, 0x80, 0xB0, 0x8D, 0xDC, 0x58, 0xB2, 0x02, 0xC8, 0xC6, 0x43, 0xD9, 0xC0, 0xCA, 0x29, 0x89, 0x9A, 0xC3, 0x9A, 0x30, 0x7A, 0x1A, 0x14, 0x50, 0x63, 0xFA, 0x0E, 0x25, 0x8C, 0xAE, 0xBE, 0xEC, 0x99, 0x80, 0x19, 0xB0, 0x1D, 0x58, 0x84, 0x0D, 0x0A, 0xB0, 0xA7, 0x91, 0xBB, 0x3A, 0x20, 0x83, 0xC5, 0x6C, 0x91, 0x0D, 0x68, 0x00, 0xBE, 0x4E, 0xAF, 0x77, 0x1A, 0x0D, 0xBA, 0x38, 0xD1, 0x31, 0x57, 0x1A, 0x47, 0x36, 0x9C, 0xF7, 0xE4, 0x69, 0xDA, 0x5C, 0x3C, 0x13, 0x2B, 0x13, 0x6B, 0x6F, 0x55, 0x7E, 0xAD, 0x07, 0x6A, 0x5F, 0x23, 0x2D, 0x59, 0x7B, 0x07, 0xC3, 0xC0, 0x22, 0xFB, 0xEE, 0x95, 0xE6, 0x4C, 0xE2, 0x63, 0xAD, 0x48, 0x8E, 0xB5, 0xFC, 0x97, 0xAB, 0x10, 0xA7, 0x68, 0x97, 0xCA, 0xEC, 0x4C, 0x25, 0x62, 0x4B, 0xBB, 0x13, 0xAC, 0xF9, 0x40, 0x1F, 0xF3, 0xF1, 0x3B, 0x84, 0x0D, 0x04, 0x70, 0xBD, 0x0D, 0xA3, 0x31, 0xA0, 0x41, 0xE5, 0xEE, 0xB3, 0xA1, 0x0B, 0x88, 0x00, 0x3C, 0x01, 0xB5, 0x31, 0x68, 0x00, 0xD1, 0x40, 0xD9, 0xBC, 0x29, 0xC7, 0x68, 0x02, 0x39, 0x04, 0x91, 0x39, 0x47, 0xC6, 0x68, 0x7D, 0x8F, 0x9C, 0xB9, 0xF8, 0xC4, 0x75, 0x6D, 0xA4, 0x56, 0xE6, 0x2E, 0xB5, 0x68, 0xB4, 0xE7, 0x3E, 0xC0, 0x8C, 0x9B, 0x3C, 0xF7, 0xD7, 0x9F, 0x5E, 0x65, 0x1D, 0xEF, 0xE3, 0xE6, 0xDD, 0xDB, 0xEE, 0xE9, 0x29, 0xC5, 0x8B, 0x00, 0xE0, 0x09, 0x8C, 0x06, 0x2B, 0xB0, 0x7B, 0x10, 0x03, 0xEE, 0x26, 0x8B, 0x0B, 0x5C, 0x50, 0xF3, 0x35, 0x01, 0xEA, 0x37, 0xED, 0x3D, 0x28, 0x40, 0x1C, 0xD0, 0x35, 0x68, 0x20, 0xED, 0x69, 0xC2, 0x91, 0x83, 0x00, 0x18, 0xEB, 0x69, 0xCE, 0xEE, 0x05, 0x54, 0x2C, 0xBE, 0x42, 0xA3, 0xE9, 0x5F, 0xF6, 0xD1, 0x04, 0x5B, 0x16, 0xF8, 0xB6, 0x65, 0xE8, 0xB0, 0x62, 0x1B, 0xFE, 0x2A, 0x1E, 0x9B, 0x35, 0xA6, 0xD9, 0x4B, 0xD3, 0x1F, 0x74, 0xD7, 0xC4, 0xBE, 0xE7, 0xB4, 0x19, 0x32, 0xFB, 0xF4, 0x48, 0xAE, 0x62, 0xC4, 0x1E, 0x9F, 0x24, 0xC7, 0xC5, 0xD9, 0x13, 0x39, 0x48, 0x20, 0x14, 0x0F, 0xCD, 0x81, 0xE6, 0x7F, 0x73, 0xB6, 0xFF, 0x3E, 0xAA, 0x11, 0xA7, 0x55, 0x5B, 0x9F, 0x71, 0x54, 0x1B, 0x50, 0x03, 0x5C, 0x07, 0x3D, 0x90, 0x07, 0x3A, 0x28, 0xA0, 0xD7, 0x13, 0x1D, 0x30, 0x20, 0x1D, 0xB0, 0x67, 0xCE, 0x97, 0x3E, 0x0D, 0x73, 0xEC, 0x0C, 0x35, 0xFB, 0x8B, 0xEF, 0x0F, 0x69, 0xF8, 0x7B, 0xB6, 0xA3, 0xFA, 0xB2, 0x04, 0x5F, 0x3A, 0x62, 0x14, 0x91, 0x64, 0x22, 0xE5, 0x3A, 0x11, 0x77, 0xD4, 0xDD, 0x8D, 0xD1, 0xCA, 0xAF, 0xA1, 0x96, 0x00, 0xA5, 0xC7, 0x31, 0x31, 0x6B, 0xDC, 0x3C, 0xCE, 0x4A, 0x22, 0x7C, 0xA2, 0x58, 0x4F, 0xC6, 0xAD, 0x85, 0xB4, 0xF2, 0x99, 0xC2, 0x18, 0x9B, 0x63, 0x5E, 0x3F, 0x6A, 0x4B, 0xBC, 0x3F, 0xE5, 0x86, 0x09, 0x29, 0x3F, 0x74, 0xAA, 0xA8, 0x1A, 0xD0, 0x81, 0x04, 0xCD, 0x0B, 0xAC, 0xBE, 0xB1, 0x03, 0xF0, 0xCD, 0x8C, 0x24, 0xC0, 0x6A, 0xB0, 0x80, 0xED, 0x78, 0x25, 0x0B, 0xB0, 0x41, 0xD8, 0xBC, 0xA2, 0x34, 0x9A, 0xCF, 0x4E, 0x80, 0xBE, 0xEA, 0xB6, 0xEE, 0xDC, 0x97, 0x90, 0x99, 0xA6, 0x55, 0xA3, 0xB3, 0xAB, 0xC8, 0xEA, 0x0C, 0x63, 0xFE, 0xDE, 0xE5, 0xE4, 0x88, 0x2B, 0x0E, 0x21, 0x7A, 0x14, 0x8E, 0x58, 0x6C, 0xB4, 0x59, 0x53, 0x83, 0x1C, 0x68, 0xF6, 0xD7, 0x07, 0xB4, 0x4F, 0xAD, 0x92, 0x28, 0xEC, 0x6A, 0x4C, 0xCB, 0xFD, 0xB0, 0x8E, 0x42, 0xBB, 0x52, 0xFC, 0x9D, 0xED, 0xD4, 0x7F, 0x0D, 0x1B, 0x9A, 0xCD, 0x59, 0xCE, 0x68, 0xEA, 0x0D, 0x68, 0x01, 0x6B, 0xBD, 0xDA, 0xEA, 0x83, 0xBC, 0x77, 0x89, 0xC8, 0x7B, 0xED, 0xEF, 0x0D, 0x44, 0x01, 0xAA, 0xC0, 0x4A, 0x40, 0xF8, 0x8A, 0x9C, 0x91, 0x16, 0x7F, 0x05, 0x9F, 0x03, 0x0E, 0x14, 0x5E, 0x1F, 0xDC, 0x7C, 0xFA, 0xAD, 0x2A, 0x3C, 0x97, 0xD5, 0x23, 0xB1, 0x8D, 0x49, 0x1B, 0x28, 0x1F, 0xD8, 0x94, 0xD1, 0xBF, 0xBD, 0x69, 0xCE, 0xAC, 0x85, 0xE0, 0xAA, 0x74, 0x7C, 0x16, 0x7B, 0x01, 0x21, 0xBF, 0x4F, 0xF0, 0x2C, 0xE0, 0x9A, 0x4B, 0x3C, 0x0A, 0xB2, 0x71, 0x5A, 0x04, 0x4E, 0x88, 0xBF, 0x7F, 0xAE, 0x47, 0xE5, 0xF4, 0x64, 0x74, 0xA9, 0x15, 0x58, 0x7D, 0x1B, 0xC6, 0x1D, 0x90, 0x1A, 0xEC, 0xA7, 0x7C, 0x7E, 0x01, 0x56, 0x40, 0xF7, 0xD8, 0x67, 0x03, 0x22, 0x7C, 0x08, 0xC4, 0x02, 0xB4, 0x01, 0x9F, 0x57, 0x76, 0x1C, 0xA3, 0xE5, 0xA5, 0xC1, 0xB4, 0x72, 0x56, 0x72, 0x9F, 0x6E, 0xCE, 0x6E, 0xE8, 0xAD, 0x3C, 0xB6, 0xAB, 0xD9, 0x1A, 0x97, 0xE8, 0x5D, 0xE2, 0x69, 0xB4, 0x9A, 0x1D, 0xCF, 0x29, 0xDB, 0x55, 0xD1, 0x16, 0xB3, 0x2B, 0x26, 0x50, 0x63, 0x43, 0xFA, 0xAE, 0xA9, 0xE1, 0xE8, 0x42, 0x03, 0x01, 0x19, 0xC0, 0x36, 0xB6, 0x24, 0xFB, 0x49, 0xD6, 0xEA, 0x69, 0x28, 0x4A, 0x5B, 0x9C, 0x0E, 0xC8, 0x77, 0x05, 0xA4, 0xD6, 0x23, 0x96, 0xA2, 0x40, 0x12, 0x6B, 0xA0, 0xBC, 0xE9, 0x03, 0x1E, 0x4F, 0x15, 0x90, 0xDE, 0x0F, 0x77, 0xDD, 0x61, 0xF8, 0x95, 0x40, 0xF9, 0xB1, 0x5A, 0xA1, 0xA3, 0x8A, 0x4E, 0x8A, 0xAA, 0xE9, 0x37, 0xDE, 0x2B, 0x63, 0x9C, 0x7A, 0x0D, 0x9F, 0x75, 0x1B, 0x8A, 0xDD, 0x43, 0xE0, 0x2F, 0xD4, 0xFC, 0x35, 0x57, 0xDE, 0x0A, 0x64, 0xFF, 0x8E, 0x92, 0xD2, 0xA3, 0x92, 0x62, 0x53, 0xEB, 0x86, 0xEF, 0x8E, 0xFC, 0xE7, 0x04, 0xB6, 0xA1, 0x9C, 0x47, 0x8D, 0x95, 0x7E, 0x80, 0x16, 0xE0, 0x83, 0xBD, 0xA7, 0xFE, 0x9B, 0x3A, 0x2C, 0x23, 0xBB, 0x7A, 0x56, 0xBF, 0x39, 0xD9, 0x9D, 0xBE, 0xD6, 0x4C, 0x7B, 0x16, 0x80, 0x3A, 0x9B, 0xD9, 0x80, 0xD7, 0x20, 0x6F, 0x04, 0x5B, 0x67, 0x3D, 0x87, 0x6A, 0x51, 0x60, 0x73, 0x0D, 0x15, 0xC0, 0x0D, 0x90, 0xB8, 0x05, 0xAC, 0xD5, 0x69, 0xB3, 0x46, 0xC9, 0xB5, 0x36, 0xDC, 0x30, 0xDB, 0x67, 0xE9, 0x37, 0x78, 0xAB, 0x74, 0xCF, 0xF6, 0x25, 0xB3, 0xC2, 0xD9, 0x9C, 0x40, 0x8D, 0xE9, 0xB5, 0x97, 0xB3, 0x9B, 0x47, 0xA5, 0xE4, 0x46, 0xE0, 0x36, 0xEB, 0x3A, 0x6B, 0xC9, 0x7C, 0xFC, 0xB7, 0x0B, 0x70, 0xC3, 0xC3, 0x0E, 0xC0, 0x1A, 0xC8, 0x9A, 0x57, 0xFC, 0x27, 0xFF, 0x1F, 0x47, 0x4C, 0x6F, 0xD5, 0x4F, 0x95, 0x5D, 0x4E, 0x06, 0xB8, 0x05, 0x7B, 0xFC, 0x50, 0xD9, 0x1B, 0xD0, 0xCD, 0x1E, 0xAA, 0x40, 0x28, 0xE0, 0x3E, 0x50, 0x20, 0x36, 0xC0, 0xC6, 0x36, 0xC1, 0xA6, 0x37, 0xD4, 0x62, 0x4E, 0x20, 0x17, 0x70, 0x84, 0xD3, 0x1D, 0x9F, 0xF6, 0x06, 0xBA, 0xC7, 0x68, 0x1B, 0x3E, 0x41, 0xB3, 0xB7, 0x78, 0x7D, 0xA2, 0xE1, 0x19, 0xA8, 0xCE, 0x31, 0x19, 0xE9, 0xC8, 0x9E, 0xCA, 0xD0, 0x60, 0x8A, 0xCE, 0x35, 0xD0, 0xE4, 0x77, 0x1A, 0x12, 0xAA, 0xEF, 0x4E, 0xDD, 0xAE, 0x8F, 0xF4, 0x81, 0x8F, 0xDC, 0xAA, 0xCF, 0x57, 0xF1, 0x59, 0xEE, 0x8E, 0x7F, 0x92, 0x95, 0xA8, 0x35, 0x03, 0x2D, 0x4E, 0x15, 0x66, 0x07, 0x2C, 0xE8, 0xCA, 0x5E, 0x02, 0x13, 0x51, 0xD0, 0x9F, 0x76, 0xCD, 0x3E, 0x07, 0x96, 0xAD, 0x2C, 0x41, 0x9E, 0xFD, 0x55, 0x01, 0x5D, 0xC0, 0xCE, 0xC1, 0x1E, 0x04, 0xE0, 0xCC, 0x26, 0x17, 0xC0, 0x0A, 0xD0, 0xBE, 0x3B, 0x36, 0x66, 0x02, 0xD6, 0x40, 0xE8, 0xBC, 0x69, 0xB4, 0xD9, 0xFE, 0xB2, 0xE0, 0xBD, 0xF7, 0x74, 0x6C, 0x8C, 0x91, 0x54, 0x15, 0x1C, 0x67, 0xAB, 0xE1, 0xAF, 0xD1, 0x98, 0xA0, 0x7A, 0x22, 0x26, 0xDE, 0x70, 0xDC, 0xDE, 0x0D, 0x7B, 0x68, 0x42, 0x8C, 0x10, 0x7E, 0x25, 0xFA, 0xF6, 0xD9, 0x44, 0x62, 0xAA, 0x78, 0x17, 0x3E, 0x89, 0xFF, 0x54, 0x92, 0x62, 0x3E, 0xF9, 0x5C, 0x1A, 0xE2, 0x14, 0x01, 0x87, 0xC1, 0x4C, 0xE7, 0xEE, 0xA0, 0x9C, 0x18, 0xCC, 0x6C, 0xFE, 0x75, 0x57, 0xCC, 0xD3, 0xC3, 0x48, 0x03, 0xF8, 0xED, 0xAF, 0x80, 0x0C, 0x1A, 0x28, 0x03, 0x30, 0x6E, 0xF2, 0x98, 0x77, 0x39, 0x60, 0x09, 0x68, 0x01, 0x14, 0x4C, 0x4F, 0x01, 0x4C, 0x81, 0x38, 0x99, 0xD4, 0x34, 0x1A, 0x92, 0x1F, 0x77, 0xE7, 0x37, 0x1A, 0x2C, 0x6D, 0x5C, 0xFB, 0x36, 0xAB, 0x72, 0xE2, 0x56, 0x3C, 0xEB, 0xDB, 0x52, 0xC3, 0x50, 0xB6, 0xE4, 0xB4, 0xBC, 0xEB, 0x7B, 0xF4, 0x0A, 0x73, 0x61, 0x5E, 0xDF, 0xAD, 0x73, 0xF8, 0x49, 0x67, 0x75, 0x67, 0x9F, 0x4C, 0x4A, 0x97, 0x0B, 0xFB, 0x39, 0x05, 0x20, 0x97, 0x66, 0xB9, 0x8E, 0xC7, 0x77, 0x8F, 0x77, 0x64, 0xE1, 0xCD, 0x3A, 0xEA, 0xA4, 0xB6, 0x7F, 0x97, 0x5D, 0xE6, 0x9D, 0x32, 0x6D, 0x1E, 0x06, 0xBD, 0xA2, 0x9D, 0x19, 0x40, 0x39, 0xD0, 0xC9, 0xBB, 0xC0, 0xA0, 0xF2, 0xAE, 0x5C, 0xD9, 0x7E, 0x47, 0x59, 0xDC, 0x00, 0x71, 0x80, 0x9E, 0xF4, 0x7D, 0x86, 0xDA, 0xAF, 0x84, 0x60, 0x23, 0xDD, 0x00, 0xFA, 0x34, 0x31, 0x67, 0x3F, 0x47, 0xD8, 0xB0, 0x03, 0x6A, 0xC8, 0xE2, 0xE3, 0x99, 0x6E, 0xFA, 0x37, 0x9E, 0x62, 0x15, 0x96, 0x3C, 0xE8, 0x9A, 0xA5, 0x63, 0x46, 0xB5, 0x8F, 0x9D, 0x62, 0x03, 0x98, 0x29, 0xC9, 0xBF, 0x3D, 0x3E, 0x41, 0x6A, 0x06, 0x90, 0xDB, 0xED, 0x4D, 0x73, 0xE1, 0x3B, 0xF5, 0xB9, 0x3B, 0x27, 0xE3, 0xE3, 0x4F, 0x0C, 0x65, 0xEF, 0x3B, 0xC1, 0x7F, 0xF7, 0xE0, 0xA9, 0x36, 0x69, 0x1F, 0xE8, 0xFD, 0xA6, 0x0C, 0xCA, 0x1F, 0xDF, 0xD0, 0xD5, 0xF9, 0xFC, 0xDA, 0x8A, 0x01, 0xBD, 0x52, 0xAF, 0x60, 0x35, 0x3B, 0x56, 0x8B, 0xAF, 0x1A, 0x4E, 0x71, 0xD7, 0xCE, 0x98, 0xCC, 0x6E, 0xC5, 0x9B, 0x22, 0x5F, 0xC8, 0xC7, 0xB7, 0xE3, 0xAF, 0x84, 0x6A, 0x15, 0xAD, 0x37, 0x75, 0x94, 0x59, 0x9B, 0x27, 0xD5, 0x3E, 0x83, 0xB6, 0x00, 0xAA, 0x00, 0x1E, 0xE3, 0x4F, 0x0D, 0x4A, 0xCF, 0x9B, 0x0B, 0x58, 0x75, 0x79, 0x72, 0x28, 0xED, 0xB8, 0xA8, 0xA5, 0xF3, 0x24, 0x6B, 0x2C, 0xDA, 0x69, 0x01, 0x12, 0x03, 0x05, 0x9C, 0x68, 0xC0, 0x08, 0x1F, 0xD8, 0x20, 0x81, 0x94, 0xFF, 0x3F, 0x0B, 0xF2, 0x9F, 0x2D, 0xDE, 0xE3, 0x58, 0xCD, 0x3F, 0x97, 0x5A, 0xD4, 0xC6, 0x42, 0xBD, 0xE3, 0x4A, 0xB8, 0xF5, 0x09, 0xEF, 0xF7, 0xDE, 0x38, 0x51, 0xCE, 0x52, 0x29, 0x56, 0x97, 0xC2, 0x79, 0xEA, 0xE3, 0x1E, 0x4A, 0x2E, 0xC0, 0xCE, 0x22, 0xC4, 0xAB, 0x30, 0x2A, 0xE6, 0x93, 0x9D, 0x3E, 0x73, 0xEE, 0x77, 0xB4, 0x60, 0xC7, 0x2F, 0x0A, 0x13, 0x67, 0xB7, 0x12, 0x5E, 0x38, 0x95, 0xE5, 0x11, 0xF4, 0x78, 0xF3, 0x10, 0x7A, 0x27, 0x5A, 0xEC, 0xDB, 0xF7, 0x13, 0x0D, 0x34, 0x3B, 0xBB, 0xEC, 0x41, 0x03, 0x32, 0x60, 0xCA, 0x82, 0x0C, 0x62, 0x03, 0xCE, 0x87, 0x71, 0x67, 0xAC, 0xC5, 0x06, 0x32, 0xE7, 0x15, 0x3D, 0x56, 0x8B, 0x2F, 0x2F, 0x61, 0x89, 0x20, 0x22, 0x35, 0x8D, 0x69, 0x56, 0x24, 0x7B, 0x3E, 0xC0, 0xCF, 0x12, 0x86, 0x85, 0xDE, 0x83, 0x5D, 0x58, 0x39, 0x43, 0x41, 0x5A, 0xCD, 0x18, 0xCC, 0xD7, 0xD3, 0x61, 0x61, 0x6A, 0xC5, 0xD6, 0xDD, 0x8F, 0x8F, 0x4D, 0x3C, 0xFA, 0x48, 0x9F, 0xDD, 0x7D, 0xC0, 0xCB, 0x81, 0x25, 0xBF, 0xCE, 0x0C, 0x7A, 0xDA, 0xA8, 0x68, 0x72, 0x99, 0x82, 0x49, 0x98, 0xD6, 0x62, 0x77, 0xEA, 0x62, 0xD0, 0x77, 0xEC, 0x80, 0xC8, 0x60, 0x0D, 0xE4, 0x41, 0x00, 0xEE, 0x63, 0xF4, 0x06, 0x6C, 0x03, 0x2A, 0x4F, 0x49, 0xD4, 0x02, 0x2C, 0x00, 0xDE, 0x11, 0x24, 0x8E, 0xD5, 0xF2, 0xAF, 0xA6, 0x6E, 0x24, 0x3E, 0xB7, 0x4B, 0x8D, 0x7C, 0xB2, 0x4F, 0x48, 0x48, 0x71, 0x67, 0xD3, 0x84, 0x3F, 0x6A, 0x9C, 0xB9, 0x9D, 0x72, 0xEA, 0xC8, 0x3E, 0xCA, 0xE3, 0xEA, 0x98, 0x4F, 0x72, 0x5A, 0xC3, 0x48, 0xDC, 0x9B, 0x52, 0x8C, 0x81, 0xB4, 0xEF, 0xB0, 0x65, 0x0D, 0x54, 0x01, 0x09, 0x60, 0xD5, 0x55, 0x4E, 0xCC, 0x32, 0x1D, 0x0E, 0x2B, 0x7F, 0xEA, 0x24, 0xC4, 0x01, 0x3D, 0x59, 0xD2, 0x80, 0x37, 0x90, 0xB4, 0xAF, 0x0F, 0x1A, 0xE8, 0x47, 0x91, 0xAC, 0x78, 0xBB, 0x74, 0x60, 0x9F, 0x24, 0x40, 0xC0, 0x69, 0x27, 0x03, 0x4C, 0xE6, 0x95, 0x3A, 0x56, 0xAB, 0xB3, 0xAE, 0x25, 0xEB, 0x96, 0x1C, 0xDA, 0x42, 0x23, 0x0A, 0x86, 0xDF, 0xAC, 0x0B, 0x15, 0x1C, 0x39, 0x19, 0x31, 0xA9, 0x77, 0xF1, 0x45, 0x3D, 0xEB, 0x5A, 0xF9, 0x62, 0x1D, 0x25, 0xD5, 0x2C, 0x7F, 0x76, 0xF2, 0x13, 0x62, 0xDA, 0x09, 0xC3, 0x9A, 0xE1, 0xCD, 0xC5, 0x04, 0x79, 0xBD, 0x72, 0x7D, 0xD8, 0xDA, 0x98, 0x5D, 0x59, 0x4E, 0xF5, 0x75, 0xFC, 0xCA, 0x51, 0xE4, 0x60, 0xE7, 0xBD, 0xAE, 0xC5, 0xFE, 0x8F, 0x08, 0x9E, 0x0E, 0x12, 0x68, 0x7B, 0x6A, 0x64, 0x03, 0x48, 0x07, 0xAC, 0x5F, 0xF9, 0xCA, 0x3B, 0x4F, 0x2D, 0xF3, 0x58, 0xAD, 0x8F, 0xD5, 0x6A, 0x23, 0x46, 0x60, 0x5F, 0xFD, 0x94, 0xE2, 0x8E, 0xD2, 0x81, 0xC8, 0x84, 0x2B, 0x0A, 0x09, 0x3C, 0x70, 0xFF, 0x35, 0x58, 0xAB, 0xDF, 0x92, 0x95, 0x75, 0x89, 0xEF, 0x25, 0xD7, 0x12, 0xEE, 0xF6, 0x4C, 0x58, 0x3D, 0x4E, 0xDE, 0xE0, 0x0A, 0xB8, 0x81, 0x53, 0xF9, 0xE4, 0x40, 0x2D, 0x20, 0x99, 0x43, 0xFB, 0xA4, 0xC6, 0x77, 0x01, 0xC6, 0xCA, 0x95, 0x02, 0xBC, 0x81, 0xBC, 0x7A, 0x71, 0xDF, 0x5B, 0x04, 0xB0, 0x07, 0x32, 0x30, 0xC0, 0xE2, 0x91, 0xD8, 0x8D, 0xBB, 0x74, 0xBD, 0x06, 0xDE, 0x80, 0xE9, 0x5D, 0x49, 0xB4, 0x95, 0x56, 0x13, 0x98, 0xAB, 0xF6, 0x9A, 0x8E, 0x77, 0x39, 0xBA, 0x3E, 0x0D, 0xEF, 0xB5, 0xF8, 0xB7, 0x10, 0xEA, 0x8E, 0x91, 0x4C, 0xB0, 0x19, 0x38, 0x71, 0xB7, 0xF8, 0x5F, 0x77, 0x54, 0x8A, 0xDF, 0x82, 0x57, 0xBC, 0x75, 0x2A, 0xCB, 0x76, 0x8D, 0x8B, 0x31, 0xD8, 0xB2, 0x90, 0x95, 0xA3, 0x2C, 0xC5, 0x05, 0xD6, 0x1E, 0xB0, 0xB5, 0x37, 0x9B, 0xC1, 0xB2, 0xB1, 0x7C, 0x50, 0x1C, 0xEB, 0x3A, 0x87, 0x58, 0x30, 0x37, 0x0A, 0x58, 0x76, 0x4F, 0xAA, 0x8C, 0x41, 0x01, 0x25, 0x03, 0x1B, 0x34, 0x1D, 0x1B, 0x4F, 0xFB, 0x5F, 0x07, 0x18, 0x4F, 0xC8, 0x06, 0xB4, 0x80, 0xBD, 0x01, 0x89, 0x79, 0x65, 0x1F, 0xAB, 0x6D, 0x5C, 0xA7, 0xBD, 0xA7, 0x6C, 0x9D, 0xA9, 0x1D, 0xE3, 0x9E, 0x18, 0x55, 0x4D, 0x09, 0xC1, 0xA5, 0xC5, 0x05, 0x0F, 0x4B, 0x8F, 0xBC, 0x1C, 0x2C, 0x00, 0xA3, 0x79, 0xD2, 0x27, 0x75, 0x25, 0x0F, 0xE1, 0xEF, 0x7B, 0xA9, 0xB0, 0x78, 0xFE, 0xEE, 0x0B, 0x7A, 0xB2, 0xF7, 0x76, 0xFC, 0x1A, 0x37, 0xF7, 0x09, 0x60, 0xB9, 0x4F, 0x90, 0x4A, 0xE9, 0x37, 0xA2, 0x5B, 0x77, 0x8C, 0x3D, 0x76, 0xDD, 0x5C, 0x02, 0x06, 0x9A, 0x40, 0x6E, 0x80, 0x36, 0x5F, 0x83, 0xDD, 0x80, 0x18, 0xA0, 0x0E, 0x44, 0xDD, 0x45, 0x35, 0xEE, 0x80, 0x15, 0xA0, 0x1B, 0x58, 0x4F, 0x0F, 0xF1, 0x2E, 0x76, 0xB2, 0xA5, 0xD1, 0xE4, 0x3B, 0xA7, 0xC9, 0x0A, 0xF8, 0x27, 0x54, 0xF1, 0xE3, 0x1B, 0xEB, 0xBE, 0xB3, 0x7D, 0xAC, 0x0B, 0x36, 0xB4, 0x9C, 0xD4, 0xB5, 0xC4, 0x21, 0xB7, 0xDE, 0x83, 0x07, 0xD3, 0xD4, 0x82, 0x07, 0x0F, 0x56, 0xB3, 0x1B, 0xFB, 0x26, 0xB0, 0x85, 0x50, 0xDF, 0x92, 0x08, 0xAD, 0x63, 0x5F, 0x9A, 0x64, 0x03, 0x51, 0x80, 0xFE, 0x0A, 0x47, 0x77, 0x1E, 0xC1, 0x89, 0x90, 0xF1, 0xCF, 0xD6, 0x9C, 0xEF, 0xE2, 0x2E, 0xE4, 0xFC, 0xD0, 0x4C, 0x29, 0x41, 0xDC, 0x07, 0x07, 0xFE, 0x81, 0x39, 0xE0, 0x0A, 0x04, 0xB3, 0x5D, 0x1C, 0x48, 0x26, 0xD2, 0x2C, 0x60, 0x0B, 0x1E, 0x56, 0x00, 0x36, 0xD8, 0x03, 0xE5, 0x9B, 0x9B, 0x56, 0xD3, 0x3F, 0xFF, 0xC6, 0xE8, 0xC6, 0xF5, 0xD1, 0xD6, 0x55, 0x4B, 0x50, 0x2B, 0x60, 0x82, 0xD8, 0x18, 0x6A, 0x55, 0xD3, 0x53, 0xA7, 0x39, 0x21, 0xAF, 0xF4, 0x21, 0xAF, 0x5F, 0xA0, 0x87, 0x3E, 0x1B, 0x8D, 0xA3, 0xD9, 0x1C, 0x1B, 0xE8, 0x11, 0x2C, 0xA1, 0xF3, 0xE3, 0x78, 0xC1, 0x99, 0x18, 0xB1, 0x7E, 0xAD, 0x87, 0x18, 0x3A, 0xC0, 0xCE, 0xFB, 0x2B, 0xE1, 0x06, 0xA0, 0xD1, 0xCA, 0x01, 0x04, 0x4B, 0x7A, 0x01, 0x92, 0x00, 0xC3, 0x0A, 0x6A, 0x80, 0x07, 0x90, 0x32, 0x68, 0xA0, 0x95, 0x85, 0xF2, 0x40, 0x3F, 0x15, 0x49, 0xC2, 0x87, 0x0D, 0x04, 0xDF, 0x34, 0xC0, 0xE7, 0x4D, 0x35, 0x1A, 0xCD, 0x3E, 0x1F, 0x91, 0x2E, 0x19, 0x11, 0x28, 0xBD, 0x12, 0xBD, 0xDB, 0x1B, 0xE6, 0x4D, 0x1F, 0xDF, 0x24, 0x7B, 0xF4, 0x19, 0x05, 0xE6, 0xEE, 0x84, 0x48, 0x2E, 0x01, 0xA7, 0xEA, 0x7A, 0xA6, 0x9B, 0x4D, 0x30, 0x2F, 0x1D, 0xF0, 0x8D, 0x87, 0x4C, 0x0D, 0x65, 0xE8, 0x8A, 0xCD, 0x66, 0xCA, 0x8E, 0xBF, 0x1C, 0xA1, 0xAF, 0xFD, 0x4B, 0xF1, 0xC8, 0x89, 0x12, 0xF8, 0x0C, 0x1C, 0x3D, 0x42, 0xE7, 0x55, 0xEC, 0x16, 0x72, 0x2B, 0xA3, 0x9B, 0xB0, 0x51, 0x17, 0x20, 0x0D, 0x58, 0x02, 0x6E, 0xCF, 0x48, 0x13, 0x20, 0x36, 0xD0, 0x09, 0x54, 0x03, 0x91, 0x80, 0x14, 0xB0, 0x0C, 0xD8, 0xCD, 0x37, 0x69, 0x34, 0xFF, 0x0B, 0xC3, 0x43, 0x68, 0x6D, 0x0A, 0xCE, 0x9D, 0x13, 0x36, 0xAE, 0x28, 0x58, 0x6B, 0xE1, 0xE8, 0x76, 0xAA, 0x29, 0x36, 0x25, 0x86, 0x9E, 0x60, 0x5E, 0x5C, 0x1E, 0xDC, 0x3A, 0x1D, 0x5F, 0x5B, 0xA9, 0xC0, 0x08, 0xF4, 0x8C, 0x42, 0x8A, 0x18, 0x53, 0xC0, 0xB7, 0x14, 0x70, 0x03, 0x32, 0x07, 0xEC, 0x60, 0xA1, 0xB0, 0x5D, 0xD1, 0x76, 0xBC, 0xD5, 0x33, 0xE2, 0xC1, 0xD8, 0xF7, 0x93, 0x93, 0xD6, 0xAF, 0x76, 0xE2, 0x02, 0xBA, 0xC6, 0xD8, 0x01, 0xEC, 0x06, 0x3C, 0xA9, 0x2A, 0x0F, 0xC4, 0xC0, 0x37, 0x70, 0x0A, 0x79, 0x13, 0xF0, 0x02, 0xD2, 0x38, 0xB2, 0x69, 0xB4, 0x40, 0x47, 0xA9, 0xCA, 0xB9, 0x34, 0x2A, 0x56, 0xAC, 0x66, 0x24, 0xAA, 0x73, 0xDC, 0xFC, 0x35, 0xAD, 0x54, 0x1B, 0x33, 0x6A, 0x7F, 0x2E, 0xDC, 0x50, 0x9E, 0x36, 0x00, 0x06, 0x0A, 0x57, 0xB3, 0x19, 0x90, 0x8F, 0x90, 0xD0, 0x64, 0x72, 0xED, 0x02, 0x70, 0x26, 0x0D, 0xAA, 0x2D, 0x8E, 0xD3, 0x76, 0x56, 0x15, 0xCA, 0x11, 0x29, 0xA5, 0x57, 0x93, 0xE1, 0xAC, 0xF9, 0x34, 0x5F, 0x5E, 0x60, 0x3B, 0x98, 0xFE, 0x6A, 0x10, 0x25, 0xC7, 0x45, 0xB9, 0x05, 0x08, 0xA5, 0x30, 0x0F, 0x20, 0x03, 0x0D, 0xC0, 0x04, 0xF0, 0x41, 0xF5, 0x6C, 0x32, 0x05, 0xD4, 0x06, 0x52, 0x00, 0xDF, 0xC0, 0x66, 0x39, 0xF9, 0x7C, 0x5A, 0x0D, 0x64, 0xD3, 0x68, 0x89, 0x60, 0x91, 0xE8, 0x98, 0xC7, 0xAF, 0x36, 0x65, 0xEE, 0x13, 0x68, 0x59, 0xF6, 0x21, 0xC5, 0xB0, 0x19, 0xA6, 0x63, 0x3E, 0x8E, 0xCD, 0x06, 0xCC, 0x50, 0xD5, 0x78, 0xDC, 0xDE, 0x32, 0x36, 0xAB, 0x81, 0x19, 0x8E, 0x35, 0xD2, 0x63, 0xAC, 0x0F, 0xD4, 0x5C, 0x1D, 0x07, 0xA2, 0xCE, 0x90, 0x54, 0x3F, 0x7D, 0x16, 0x4E, 0x91, 0xCB, 0x4C, 0x67, 0xB1, 0xFB, 0xFE, 0x2A, 0xC9, 0x16, 0xCA, 0xBF, 0x60, 0xAA, 0x9C, 0x86, 0xFE, 0x4A, 0x81, 0xD2, 0x06, 0xC2, 0x81, 0x32, 0x98, 0x7C, 0x09, 0x60, 0x49, 0x6D, 0x02, 0xC0, 0x15, 0x30, 0x07, 0x64, 0xDF, 0x6D, 0x30, 0x7C, 0x03, 0x71, 0xDC, 0xC8, 0xB4, 0xD9, 0xB9, 0x14, 0xDC, 0x99, 0x91, 0xD9, 0x70, 0xED, 0x2C, 0xC3, 0x39, 0x7A, 0x6F, 0x9C, 0x1D, 0xC5, 0xA0, 0x53, 0x16, 0xE8, 0x23, 0xCE, 0xA8, 0xB1, 0xF5, 0xA5, 0x6C, 0xA8, 0x8F, 0x6E, 0x02, 0xBC, 0x7C, 0x00, 0xE3, 0x7C, 0xCA, 0x63, 0xD4, 0xAD, 0xAD, 0x51, 0xEB, 0xD6, 0xF0, 0xEA, 0xC1, 0xA9, 0x34, 0x5C, 0x77, 0x41, 0x94, 0x1A, 0x20, 0x09, 0xEC, 0x18, 0x14, 0xC0, 0x9C, 0xAB, 0x3D, 0xB0, 0x78, 0xCB, 0x89, 0x1F, 0xF8, 0x53, 0x91, 0xBD, 0x81, 0x30, 0xC0, 0x1D, 0x50, 0xBA, 0x96, 0xEA, 0x5F, 0x15, 0xD9, 0xBE, 0x68, 0xB5, 0xFE, 0xD5, 0xB1, 0x23, 0x24, 0xEC, 0x90, 0xAE, 0x82, 0xD5, 0xD2, 0x10, 0xD0, 0xA9, 0xF8, 0x7E, 0x09, 0xF6, 0x0D, 0xB4, 0xDE, 0xA7, 0x02, 0xEF, 0xE3, 0x2D, 0xD3, 0xA7, 0xA7, 0xD8, 0x23, 0x78, 0x5E, 0x24, 0xEC, 0x3E, 0x91, 0x7A, 0xDF, 0x56, 0x6B, 0x01, 0x62, 0x01, 0x2E, 0x77, 0xB0, 0x89, 0x49, 0x9F, 0x3A, 0x76, 0xEA, 0x0D, 0xE4, 0x02, 0xCC, 0x01, 0x0D, 0x20, 0x68, 0xB5, 0x06, 0x4C, 0xFF, 0x85, 0xD7, 0x45, 0x44, 0x85, 0xD4, 0xB7, 0xE1, 0x0B, 0x1F, 0xBE, 0x5A, 0x32, 0xAF, 0x8B, 0xE8, 0x58, 0x4D, 0xD1, 0x06, 0x5B, 0xA3, 0xFE, 0xA2, 0x26, 0xF9, 0xEA, 0x3B, 0x51, 0x8E, 0x53, 0x28, 0x0C, 0xEE, 0x94, 0xFD, 0x61, 0x55, 0xEC, 0x29, 0xA1, 0xD3, 0xBB, 0xBD, 0x8A, 0x3D, 0x9D, 0x03, 0x95, 0x19, 0x7D, 0x3C, 0x5A, 0xB6, 0xCE, 0x22, 0xBE, 0x7E, 0x8E, 0x69, 0x3F, 0x57, 0xF3, 0xDC, 0xEC, 0x4E, 0x0F, 0x2C, 0x62, 0x16, 0x78, 0x26, 0x3E, 0x31, 0x2B, 0xA0, 0xC6, 0xE8, 0xF5, 0x0B, 0x49, 0xFA, 0x49, 0x1D, 0xCB, 0xFA, 0xE5, 0x62, 0x62, 0x0E, 0x23, 0x8A, 0xFC, 0x24, 0x74, 0x84, 0x00, 0xD9, 0x4F, 0x05, 0x0A, 0x13, 0xAD, 0xF6, 0x02, 0x3C, 0x00, 0x73, 0x60, 0xE7, 0x93, 0xE5, 0x21, 0x80, 0x2F, 0xBE, 0x42, 0xAB, 0xED, 0x6F, 0x90, 0x89, 0xFB, 0x17, 0x3E, 0x96, 0xD5, 0xE3, 0x01, 0x6F, 0x7C, 0x87, 0x9D, 0x90, 0xC0, 0xCA, 0x86, 0xCA, 0x45, 0x09, 0xFC, 0x03, 0x99, 0xBC, 0xB6, 0xDF, 0x63, 0xED, 0x48, 0x69, 0xE5, 0xCF, 0xA7, 0xC5, 0x0A, 0xA6, 0xBD, 0x4E, 0xF0, 0xF2, 0xB9, 0x87, 0x72, 0x2E, 0x47, 0x03, 0x96, 0x40, 0xAE, 0x41, 0xFE, 0x92, 0x44, 0xEC, 0x08, 0x1B, 0xB8, 0xDE, 0x3E, 0x59, 0x35, 0x60, 0x25, 0x60, 0x7E, 0x0B, 0x4D, 0xD0, 0x7D, 0xB4, 0xD6, 0xA0, 0x81, 0xAD, 0x83, 0x06, 0x9C, 0x92, 0x02, 0x05, 0x98, 0x01, 0xEA, 0x00, 0x7F, 0x20, 0x1F, 0xBD, 0x89, 0x90, 0x33, 0x2A, 0x68, 0x35, 0xF9, 0x2B, 0x47, 0xD2, 0x46, 0x7E, 0x3A, 0x27, 0x81, 0xF4, 0xB2, 0xE5, 0x13, 0x61, 0xF0, 0x51, 0xC9, 0x30, 0xE4, 0x58, 0xEB, 0x38, 0x3B, 0x22, 0xD8, 0xCA, 0xED, 0x91, 0x1C, 0xBA, 0x84, 0xCD, 0xCF, 0xFE, 0xEF, 0x3C, 0x23, 0xF2, 0xDE, 0x73, 0x7C, 0x43, 0xCB, 0x7F, 0xA9, 0x15, 0xFB, 0x14, 0xD7, 0x85, 0x01, 0xAA, 0xB0, 0x36, 0x7D, 0x86, 0xF9, 0x4B, 0x37, 0x73, 0xF6, 0x35, 0x1E, 0xE8, 0x81, 0x0D, 0x32, 0xE6, 0x8B, 0x8E, 0x2D, 0xB4, 0x80, 0x50, 0x20, 0x13, 0x28, 0xBB, 0x1B, 0x8A, 0x8A, 0x03, 0xB5, 0x99, 0x80, 0xF0, 0x04, 0xED, 0x0D, 0xB0, 0x27, 0x3E, 0xAF, 0x4C, 0x2C, 0xB3, 0x63, 0x35, 0x3D, 0xEB, 0x5A, 0xD9, 0x91, 0x3F, 0xB3, 0x50, 0x14, 0xB1, 0xE8, 0x86, 0x22, 0x4F, 0x7D, 0x30, 0xCB, 0x0D, 0xF7, 0x8D, 0x37, 0xC7, 0xDA, 0x93, 0xEB, 0x9D, 0x8F, 0xEB, 0x5B, 0x6D, 0xDC, 0x65, 0x0E, 0x04, 0x73, 0xB6, 0x6D, 0xEC, 0x64, 0xCC, 0x7D, 0xBA, 0x3D, 0x20, 0x57, 0x09, 0x64, 0x9C, 0x76, 0x2B, 0x47, 0xCC, 0x32, 0x01, 0x79, 0x3A, 0x45, 0x33, 0x4E, 0x51, 0xF3, 0x70, 0xC9, 0xBD, 0xE2, 0x47, 0x0F, 0xEC, 0x81, 0x0C, 0xF2, 0xA9, 0x65, 0x1F, 0xA4, 0x03, 0x61, 0xF7, 0x43, 0x0E, 0xE3, 0xE2, 0xA7, 0x0D, 0x44, 0x1C, 0xAB, 0xD9, 0x5F, 0x0A, 0xCA, 0x2D, 0xE2, 0xCB, 0xB3, 0xDD, 0x13, 0x2F, 0xF5, 0x71, 0xC5, 0xEA, 0x1F, 0x2E, 0xA7, 0x89, 0x7B, 0x52, 0xEC, 0x69, 0xA7, 0x06, 0xD7, 0xB7, 0xD1, 0x6A, 0xF5, 0x8F, 0x12, 0xE3, 0x38, 0x7D, 0x28, 0x78, 0x8B, 0xB7, 0xB8, 0xEF, 0x95, 0x3A, 0x8B, 0xDD, 0x66, 0x32, 0x90, 0xFE, 0xE4, 0xBF, 0xF4, 0x2C, 0x6F, 0x5B, 0x98, 0xD0, 0x89, 0x75, 0x6D, 0xDD, 0xEB, 0x9A, 0xC5, 0x5D, 0xF6, 0xDE, 0xFE, 0x4B, 0xC8, 0xCD, 0x93, 0xB3, 0xC7, 0x53, 0x90, 0x34, 0x10, 0x06, 0x64, 0x01, 0xD5, 0xA7, 0x4C, 0x13, 0xE8, 0x59, 0xC9, 0x54, 0x00, 0x39, 0x55, 0x1B, 0x4F, 0x70, 0x6A, 0x70, 0x32, 0x4E, 0x8F, 0xD5, 0xB0, 0xA0, 0xB5, 0xF7, 0x87, 0x72, 0x81, 0xF8, 0xA7, 0x1B, 0xAC, 0x26, 0x8E, 0xB9, 0x2C, 0x8A, 0x3A, 0x5E, 0xED, 0x6F, 0x70, 0xAC, 0xC2, 0x58, 0xA3, 0xD5, 0xFC, 0xCD, 0xF6, 0x56, 0xC6, 0xCF, 0x84, 0xA9, 0x3E, 0x0A, 0x38, 0xAB, 0xE8, 0x4E, 0x79, 0xD2, 0x25, 0x98, 0xD0, 0x0D, 0xD8, 0x02, 0x36, 0xD7, 0xB5, 0xE6, 0x14, 0xBB, 0x55, 0x58, 0x43, 0x81, 0xED, 0xB7, 0x77, 0xD1, 0x9E, 0xD6, 0x8D, 0x2C, 0x3D, 0x22, 0x6A, 0xCC, 0xBC, 0x15, 0x10, 0x03, 0x74, 0x10, 0x4D, 0x33, 0x03, 0xFC, 0xE4, 0x83, 0xA3, 0x41, 0xC9, 0x37, 0x1D, 0x28, 0xBE, 0xB9, 0x8F, 0xD5, 0xE2, 0xAF, 0x04, 0x11, 0xD0, 0xDC, 0xB3, 0xAE, 0x7D, 0xA7, 0xCC, 0x46, 0x06, 0xB1, 0x15, 0xB4, 0x9A, 0x0A, 0x5A, 0x4D, 0x7B, 0x0B, 0x8C, 0xBE, 0x9E, 0x42, 0xC6, 0x33, 0xD6, 0xD8, 0x25, 0x90, 0x5B, 0x8D, 0x5E, 0x9D, 0x00, 0xFD, 0x34, 0xAE, 0x13, 0x5E, 0xF8, 0xB8, 0x61, 0x25, 0xB7, 0xA8, 0x2B, 0xE9, 0x78, 0x73, 0xD7, 0x54, 0x3A, 0x71, 0x6F, 0x31, 0x18, 0xE1, 0x3A, 0x4E, 0x6F, 0xEA, 0x40, 0xF3, 0x56, 0x60, 0xCD, 0xB3, 0x64, 0x03, 0x91, 0x40, 0xE9, 0xA0, 0x1E, 0xD7, 0xF7, 0x53, 0x31, 0xBB, 0x72, 0xB0, 0x6E, 0x87, 0x9C, 0xD9, 0xB3, 0xAE, 0xD9, 0xBC, 0xA2, 0xC7, 0x6A, 0xF9, 0x97, 0x9F, 0xB9, 0x91, 0xEC, 0xA7, 0x15, 0x57, 0xC2, 0x9A, 0xA5, 0x23, 0x9F, 0x2B, 0x1C, 0x7F, 0x82, 0x09, 0x1F, 0x53, 0xAC, 0xA9, 0x5F, 0x09, 0x1D, 0xF1, 0x27, 0xF9, 0xCA, 0xFD, 0x77, 0xDB, 0xD1, 0xA3, 0x61, 0x2E, 0xAC, 0xD1, 0xB0, 0x89, 0x87, 0x16, 0x9B, 0x2A, 0xFE, 0xFC, 0x15, 0x08, 0xB5, 0x5D, 0x72, 0x0A, 0x3C, 0xEE, 0x51, 0x79, 0x92, 0x46, 0x90, 0x31, 0x50, 0x02, 0x12, 0x40, 0x8C, 0x9D, 0x2A, 0x6F, 0x5B, 0xEC, 0x81, 0x36, 0x60, 0x03, 0x2F, 0xA0, 0xF7, 0x7D, 0x0C, 0x2F, 0x05, 0xD2, 0x1F, 0xE5, 0x04, 0xBB, 0x35, 0x16, 0x96, 0x03, 0xB9, 0x8F, 0xD5, 0xEA, 0xDB, 0x43, 0x33, 0x01, 0xEF, 0x84, 0xCB, 0xD0, 0x30, 0xD6, 0xB6, 0x17, 0x34, 0xF1, 0x2A, 0xB0, 0x4F, 0x55, 0x21, 0xFD, 0xD1, 0x19, 0x5E, 0x79, 0x03, 0xA1, 0x0C, 0x53, 0xCA, 0xF1, 0x74, 0xDD, 0x37, 0x6A, 0xC9, 0x6B, 0x6A, 0xBE, 0x51, 0xCE, 0x6E, 0x40, 0x83, 0x46, 0x07, 0xFC, 0xA9, 0xED, 0xF7, 0x7D, 0xEB, 0x8A, 0xC6, 0x06, 0x64, 0xB0, 0x17, 0x10, 0x5C, 0xAB, 0x9D, 0x13, 0x15, 0x48, 0x03, 0x5A, 0x06, 0x63, 0xD8, 0x35, 0xD0, 0x04, 0xEA, 0xCD, 0x6A, 0xE3, 0x36, 0x3B, 0x70, 0xBE, 0xE9, 0x80, 0x2B, 0x47, 0xDE, 0xB1, 0x5A, 0x43, 0x11, 0x2C, 0x14, 0x68, 0xC1, 0x96, 0x5F, 0x1B, 0xC3, 0xC1, 0x14, 0x53, 0x3A, 0x04, 0x9A, 0x5F, 0x73, 0x88, 0xAB, 0x7D, 0xB7, 0xFC, 0xF7, 0x37, 0x0F, 0x37, 0xE8, 0x3B, 0x74, 0xE7, 0xC2, 0x0F, 0x30, 0x39, 0x42, 0xE8, 0x55, 0x9D, 0xFD, 0xF5, 0x34, 0xBC, 0xD8, 0x57, 0xD9, 0xE5, 0xF1, 0x41, 0xE7, 0xAF, 0xDD, 0x9B, 0x9F, 0x08, 0x8E, 0x3E, 0x52, 0x23, 0x3B, 0x1F, 0x39, 0x3D, 0x1D, 0x93, 0xD0, 0x08, 0x02, 0x64, 0x73, 0xAD, 0x04, 0x44, 0x00, 0x35, 0x80, 0x52, 0xD0, 0x32, 0x08, 0x03, 0x3C, 0xF8, 0xF0, 0xCE, 0x21, 0x8C, 0xBA, 0x9C, 0xE4, 0xBF, 0x40, 0xA8, 0x4D, 0xF7, 0x40, 0x8B, 0xC9, 0xE5, 0x61, 0x5E, 0xB5, 0x7C, 0x10, 0xE5, 0xEA, 0x94, 0x1F, 0xD8, 0x52, 0x30, 0xEC, 0x4E, 0xF9, 0xAE, 0xAB, 0x04, 0x14, 0x29, 0xFC, 0x30, 0x53, 0x5E, 0x2D, 0x39, 0x90, 0x98, 0x0D, 0x67, 0x1A, 0x73, 0xE1, 0xD7, 0x9D, 0xD6, 0xED, 0x7A, 0xAB, 0x06, 0xE7, 0x18, 0xBB, 0xFB, 0xB6, 0x32, 0x93, 0xA3, 0xCE, 0x06, 0x13, 0x14, 0x1A, 0xBD, 0x77, 0x44, 0x17, 0x96, 0x33, 0xDE, 0xB9, 0x55, 0x35, 0x57, 0x11, 0xDB, 0x40, 0x28, 0x50, 0x4C, 0xBA, 0x77, 0xA0, 0xD9, 0x8B, 0x76, 0x03, 0x2A, 0x00, 0xEF, 0x35, 0x21, 0x80, 0x0E, 0xAC, 0xE7, 0x15, 0xA5, 0xD1, 0x90, 0x4A, 0xB4, 0x56, 0x43, 0x54, 0x5B, 0xEE, 0x98, 0x3B, 0x6B, 0x6F, 0x76, 0x3B, 0x4C, 0xB8, 0x13, 0xB9, 0x2D, 0x0E, 0x7F, 0xE4, 0x9B, 0xDE, 0xC1, 0xFB, 0xB9, 0x30, 0x83, 0x52, 0x37, 0xCC, 0x94, 0x0A, 0xA3, 0xD1, 0x03, 0x59, 0x14, 0xB6, 0x0D, 0xF6, 0x85, 0x82, 0xB5, 0x22, 0x7F, 0xFF, 0x52, 0xB1, 0xFD, 0x30, 0x1B, 0xB9, 0x33, 0xC3, 0xF8, 0xF6, 0x0F, 0xA2, 0xA4, 0x93, 0x2B, 0xDE, 0x87, 0xDD, 0x40, 0x9F, 0x61, 0xDB, 0x4C, 0x2E, 0x61, 0xEE, 0x19, 0x15, 0xC8, 0x00, 0x6B, 0x20, 0x98, 0x5C, 0xB2, 0x80, 0x1C, 0xA3, 0x6D, 0x1F, 0xAC, 0x3B, 0x90, 0xED, 0x1B, 0x10, 0x03, 0x68, 0xD7, 0xDD, 0x34, 0x1A, 0xEB, 0xCA, 0x6A, 0x94, 0x0E, 0xFC, 0x72, 0xE2, 0x7A, 0xE8, 0xD5, 0x25, 0x4C, 0x64, 0x3A, 0x3B, 0x88, 0xFC, 0x5A, 0xFA, 0x54, 0x3F, 0x32, 0x1D, 0xE5, 0x94, 0x2E, 0x92, 0x49, 0xD1, 0x63, 0xFB, 0x5A, 0x07, 0x74, 0xFD, 0x24, 0x6D, 0x7B, 0xAC, 0x55, 0xC7, 0x6D, 0x13, 0xEC, 0x39, 0xC3, 0xD2, 0xA3, 0x19, 0x85, 0xCC, 0xA4, 0x3F, 0xA9, 0x68, 0x8C, 0x47, 0x73, 0xE0, 0x24, 0x0C, 0xD3, 0x63, 0x91, 0x53, 0x65, 0xCA, 0x5C, 0xA5, 0x98, 0x3C, 0x26, 0x07, 0x62, 0x03, 0x35, 0x0E, 0xA5, 0xD5, 0x80, 0xEF, 0x71, 0xC9, 0x29, 0x60, 0x3D, 0x08, 0x80, 0xF9, 0x70, 0x3D, 0xC8, 0xC1, 0x89, 0x6E, 0x1C, 0xA3, 0x29, 0x7A, 0x19, 0x8B, 0x21, 0x0F, 0xF7, 0x91, 0x0A, 0xD6, 0xB2, 0x09, 0x86, 0x1A, 0x26, 0x94, 0xA1, 0xD5, 0xB8, 0x56, 0x73, 0x3E, 0x5E, 0xE1, 0x02, 0x9E, 0x23, 0x65, 0x2F, 0x16, 0xF8, 0x4F, 0x0F, 0x99, 0x0F, 0x3A, 0x3E, 0x47, 0xA6, 0x4C, 0x62, 0x58, 0xE0, 0x5F, 0xA2, 0x3C, 0xFA, 0x98, 0xF7, 0x74, 0xF2, 0x0F, 0x18, 0x74, 0x3B, 0x83, 0x32, 0x4C, 0xD8, 0xBD, 0x15, 0x5F, 0x3B, 0x98, 0x63, 0x72, 0x67, 0xEC, 0xC1, 0xE6, 0x72, 0xD2, 0xA3, 0x75, 0x3C, 0x66, 0xFC, 0x5D, 0x56, 0x00, 0x56, 0x77, 0x91, 0x91, 0x32, 0x1F, 0x6E, 0x03, 0x66, 0x80, 0x16, 0xB0, 0x1D, 0xAF, 0x64, 0x02, 0x2E, 0x77, 0x93, 0x2A, 0x37, 0x1A, 0xCD, 0xBE, 0x6B, 0x94, 0x4A, 0x5D, 0xBE, 0x35, 0x9D, 0x5A, 0xD0, 0xF0, 0xA9, 0x51, 0x94, 0x46, 0x8C, 0x5A, 0xF3, 0xDB, 0x10, 0x72, 0x7C, 0x6A, 0xAF, 0x32, 0xD8, 0x11, 0x55, 0xE1, 0xDE, 0x2E, 0xCC, 0x23, 0x69, 0x20, 0xB8, 0x7F, 0xD7, 0x7D, 0x7A, 0xE0, 0xF1, 0xAA, 0x0A, 0xD0, 0x00, 0xD6, 0xA5, 0xCB, 0x2E, 0x00, 0x53, 0x2F, 0x2F, 0x65, 0xB0, 0x1E, 0x6C, 0xC0, 0xE4, 0xEE, 0x28, 0x17, 0x8C, 0xFA, 0x2B, 0xAF, 0x0E, 0x40, 0x34, 0xC0, 0x87, 0xCD, 0x7D, 0x30, 0x81, 0x8A, 0xF9, 0x75, 0x15, 0xD8, 0xF1, 0xA4, 0x29, 0xE8, 0xBF, 0xD2, 0x14, 0x72, 0xD1, 0x6A, 0xFE, 0xD7, 0xEB, 0x6E, 0x1F, 0xE8, 0x9F, 0xCF, 0x49, 0xA6, 0x58, 0xD5, 0x50, 0x23, 0xB9, 0xD9, 0x85, 0x1D, 0x17, 0x78, 0x4D, 0xFF, 0x43, 0xAA, 0xDC, 0x58, 0x4F, 0x1F, 0xDF, 0x5A, 0x0A, 0x0F, 0xDA, 0xB7, 0x7A, 0x81, 0xB2, 0x22, 0xC9, 0x9F, 0xA0, 0x2F, 0xB3, 0x41, 0x78, 0x32, 0x0E, 0xC0, 0x0C, 0x58, 0x57, 0x2E, 0x01, 0x52, 0xD7, 0x2E, 0x55, 0x48, 0x0B, 0x40, 0x1D, 0xA0, 0xE3, 0xEC, 0x6A, 0xFE, 0x7E, 0xD5, 0xF8, 0x0F, 0xEC, 0xE9, 0x81, 0x19, 0xFB, 0xBE, 0x85, 0x79, 0x02, 0x1D, 0x40, 0x0D, 0xBC, 0xEE, 0x74, 0xAF, 0xCA, 0x3B, 0xDB, 0xA6, 0x8E, 0xD5, 0x2C, 0xFE, 0xBA, 0x50, 0x8E, 0x47, 0xAB, 0xA1, 0xAC, 0xC9, 0xD9, 0x7D, 0x17, 0x65, 0xBC, 0x7B, 0x82, 0xFF, 0x9D, 0x90, 0x0A, 0xC5, 0x6E, 0xA1, 0xFA, 0x96, 0xB6, 0x53, 0x3A, 0x69, 0xDF, 0x5D, 0x74, 0xB1, 0x2E, 0x01, 0x32, 0x27, 0x37, 0xFD, 0x5F, 0x25, 0x35, 0xFA, 0x26, 0x94, 0x5F, 0x8D, 0xB6, 0x1F, 0xAB, 0x85, 0x3E, 0x7E, 0x5C, 0x07, 0xA4, 0x80, 0x3D, 0x90, 0x05, 0x78, 0x3D, 0xCA, 0x9A, 0x05, 0x84, 0x0C, 0x5E, 0xD1, 0x8D, 0x75, 0xCB, 0x4C, 0x5B, 0xFD, 0x4B, 0x85, 0xAE, 0x9E, 0x92, 0xEF, 0x75, 0x37, 0x0E, 0x4B, 0x3B, 0x56, 0xCB, 0x2F, 0x0A, 0x5A, 0xEA, 0xDF, 0x09, 0x57, 0x4B, 0x2E, 0x69, 0x4D, 0xB3, 0x8D, 0xA1, 0x82, 0x06, 0x82, 0x61, 0x3B, 0xA7, 0x84, 0x44, 0xA8, 0x73, 0xF5, 0x78, 0x89, 0xEC, 0xB8, 0x64, 0x18, 0x7D, 0x63, 0x7D, 0x00, 0xE0, 0xB3, 0x8C, 0xE7, 0xE5, 0x2C, 0x92, 0x73, 0x48, 0x6B, 0xC3, 0xA8, 0xE4, 0xB1, 0x97, 0xED, 0x0C, 0x29, 0x63, 0x41, 0xEF, 0xD6, 0xE3, 0xF6, 0xC8, 0x06, 0x5C, 0x81, 0xD0, 0x5F, 0xC7, 0xF7, 0x3C, 0x5D, 0xDD, 0x4F, 0xB5, 0x6D, 0xBE, 0xA1, 0xAA, 0x93, 0xA3, 0x04, 0x98, 0xDF, 0x0D, 0xCA, 0x35, 0x00, 0x69, 0x80, 0xAF, 0x64, 0x00, 0x56, 0x40, 0xAC, 0x79, 0xF3, 0x58, 0xAD, 0x50, 0x33, 0x95, 0xF1, 0x4D, 0xD4, 0x30, 0x1B, 0xA1, 0x8C, 0x11, 0x8C, 0xD7, 0x0D, 0x97, 0x7F, 0x16, 0x92, 0xB8, 0xCA, 0x27, 0xE5, 0x07, 0x56, 0xDB, 0xFF, 0x68, 0xEA, 0x70, 0xA5, 0x5F, 0xCD, 0x0E, 0x6E, 0x06, 0x50, 0x27, 0x82, 0x41, 0xC7, 0xA0, 0x3B, 0x41, 0x58, 0xE4, 0x75, 0xE7, 0xC9, 0x70, 0xF1, 0x39, 0x5E, 0xC0, 0xDB, 0x09, 0xDE, 0x0B, 0xC8, 0x47, 0x7B, 0x34, 0xD9, 0x26, 0xCE, 0xCE, 0x5D, 0x92, 0xC1, 0x51, 0xBA, 0x2F, 0x6E, 0x17, 0xB1, 0x16, 0x10, 0x8C, 0xA6, 0x3A, 0x2D, 0xC3, 0x83, 0xD5, 0x60, 0xDD, 0x5A, 0x0E, 0xDA, 0xF7, 0x9B, 0x42, 0xBF, 0x4C, 0xD0, 0x6A, 0xFD, 0x09, 0x79, 0xA7, 0xF4, 0x97, 0x7E, 0x95, 0xB6, 0x2F, 0xC1, 0x8E, 0x72, 0xC5, 0x70, 0x10, 0x41, 0x65, 0x92, 0x16, 0x4E, 0x2F, 0xE2, 0x97, 0x97, 0x28, 0xF5, 0x51, 0x8E, 0x8F, 0x93, 0xFF, 0x3F, 0xD1, 0xB1, 0x54, 0xA0, 0x67, 0x13, 0x6C, 0x9E, 0x23, 0xEC, 0x77, 0x48, 0xF0, 0xB1, 0x28, 0xBD, 0x70, 0xFB, 0x58, 0x54, 0x37, 0x2B, 0x34, 0xA9, 0x44, 0x75, 0x89, 0x51, 0x47, 0x03, 0x8B, 0x83, 0x6C, 0x1F, 0x9F, 0x06, 0x77, 0x1F, 0x2E, 0x05, 0x74, 0xAC, 0x53, 0xCD, 0x03, 0xF0, 0x41, 0xB1, 0x7C, 0x40, 0x81, 0x3E, 0xAE, 0x2A, 0x40, 0x6C, 0x1E, 0xBE, 0xD1, 0xFC, 0x81, 0x6D, 0xBE, 0x32, 0x56, 0x73, 0xE8, 0x2B, 0xAF, 0xF6, 0x4F, 0xF3, 0x30, 0xB6, 0xE2, 0x8C, 0xB1, 0x05, 0xC7, 0xF4, 0x80, 0xBF, 0xC3, 0x1D, 0x5E, 0xA2, 0xCA, 0x80, 0xAB, 0x4A, 0x92, 0xDE, 0xA1, 0xA7, 0xAA, 0x91, 0xDB, 0xD7, 0x51, 0x1A, 0x61, 0x15, 0xC3, 0xA0, 0xF2, 0x8E, 0x12, 0x50, 0x77, 0x64, 0x27, 0xAF, 0xC2, 0xD7, 0x58, 0xAB, 0x01, 0x5D, 0xD4, 0xFD, 0xE4, 0x92, 0xBD, 0x9A, 0xB4, 0x7E, 0xC9, 0x72, 0x30, 0x7F, 0xD6, 0xCE, 0x5A, 0xB9, 0x9E, 0xF6, 0xDC, 0x1D, 0x74, 0xD2, 0xDE, 0x2E, 0x5B, 0x67, 0xCA, 0xA9, 0x02, 0xD6, 0x83, 0x47, 0x6E, 0x2C, 0x03, 0xF0, 0x0D, 0xC4, 0xBC, 0xA9, 0xB5, 0x68, 0xB5, 0xFD, 0x97, 0x3A, 0x52, 0x7D, 0xF6, 0xDD, 0x3E, 0x21, 0x10, 0x97, 0x3D, 0x21, 0x07, 0x99, 0x52, 0x2C, 0xFB, 0x66, 0xE8, 0x86, 0x7F, 0x52, 0x65, 0x73, 0xEF, 0x7C, 0x76, 0x83, 0x9D, 0x27, 0xBF, 0x93, 0x52, 0x08, 0x5C, 0x21, 0x00, 0xC6, 0xBB, 0x19, 0x46, 0xF1, 0x62, 0xC8, 0x83, 0x25, 0xB0, 0x97, 0x8B, 0x2D, 0x14, 0xD0, 0x75, 0x8B, 0xF3, 0x51, 0xD9, 0xFD, 0x55, 0xED, 0x5E, 0x39, 0x60, 0x5C, 0x80, 0xFB, 0xB2, 0x31, 0x1E, 0xC6, 0x5C, 0x39, 0xC0, 0x03, 0xC8, 0x7C, 0x23, 0x2D, 0xD4, 0x8A, 0x19, 0xB8, 0x00, 0x36, 0xD8, 0xFA, 0xAF, 0x48, 0x0B, 0x9D, 0xF5, 0x45, 0xAB, 0xC9, 0x5F, 0x16, 0xFA, 0xDE, 0xF5, 0x57, 0x7E, 0x39, 0x83, 0xAC, 0x90, 0xB0, 0x10, 0xA5, 0x7F, 0xB8, 0x2D, 0x28, 0xB2, 0xA3, 0x3B, 0xBE, 0x85, 0x68, 0x42, 0xCC, 0x56, 0xAF, 0xD5, 0x38, 0x3C, 0x92, 0x56, 0xB3, 0x31, 0x57, 0x08, 0xC0, 0x7E, 0x13, 0x2D, 0xB4, 0x28, 0x5C, 0x22, 0x57, 0x32, 0x58, 0x9C, 0x09, 0xD7, 0x01, 0x9C, 0x9C, 0xBB, 0xA0, 0x87, 0x1B, 0xB0, 0x1E, 0xD4, 0x60, 0x03, 0x30, 0x89, 0x9C, 0x68, 0xA0, 0x2D, 0x2E, 0x8B, 0xB7, 0x13, 0x51, 0xE4, 0xF6, 0x79, 0xBA, 0x01, 0x0C, 0xD6, 0xBA, 0x02, 0xED, 0x40, 0x05, 0x10, 0x1B, 0xD8, 0x7D, 0xFB, 0x93, 0x16, 0x5F, 0x91, 0x33, 0xD6, 0xF4, 0xCF, 0xBF, 0x82, 0x8B, 0x46, 0x33, 0x91, 0xFA, 0x25, 0xC5, 0x28, 0x2E, 0x03, 0x98, 0x6E, 0x02, 0x27, 0xF8, 0xEA, 0x49, 0xB0, 0xD8, 0xD4, 0xEE, 0x7B, 0x76, 0x03, 0xF9, 0x79, 0x7B, 0x76, 0x9E, 0x12, 0x63, 0x1B, 0xB8, 0xCD, 0xA9, 0x3E, 0x7F, 0xD5, 0x35, 0x71, 0x44, 0x75, 0x8C, 0x3B, 0x5C, 0x9F, 0xA0, 0xD9, 0x29, 0x9C, 0xA8, 0x23, 0x2B, 0xEA, 0xC7, 0x08, 0x80, 0xEA, 0x93, 0x4A, 0xE9, 0xF7, 0x36, 0x50, 0x4E, 0x61, 0xD0, 0xFD, 0xCB, 0xF3, 0xB5, 0xD3, 0x09, 0x61, 0x29, 0x20, 0x0D, 0xA4, 0xDC, 0x39, 0x6C, 0xA9, 0x40, 0x34, 0x60, 0x05, 0x6C, 0xC7, 0x9B, 0x35, 0x0F, 0x97, 0x02, 0xA5, 0xB4, 0x9A, 0x7D, 0xFE, 0x0E, 0xB3, 0xC9, 0x28, 0xB2, 0x18, 0x7D, 0x07, 0xC5, 0x7E, 0x23, 0x8C, 0x90, 0xF8, 0x6C, 0x0A, 0xC8, 0x68, 0xF3, 0x6D, 0x4C, 0xF8, 0x7E, 0x62, 0x06, 0xF6, 0x0B, 0xCB, 0xED, 0x3A, 0xB7, 0xCA, 0x6D, 0x40, 0x7E, 0xB0, 0x93, 0x06, 0xBE, 0xEC, 0x4E, 0x49, 0xF3, 0x64, 0x08, 0x8B, 0x85, 0x30, 0xE3, 0xB1, 0xD8, 0xCC, 0xDF, 0xB9, 0x82, 0x56, 0x5B, 0xEE, 0x55, 0x87, 0x5B, 0x44, 0x16, 0x27, 0xF8, 0xD5, 0x90, 0x90, 0xE9, 0x46, 0x76, 0xFA, 0xDB, 0xEF, 0x0D, 0x98, 0x3C, 0x21, 0xB3, 0x0D, 0x54, 0x8C, 0x1B, 0x63, 0x01, 0x32, 0x0F, 0x5B, 0x01, 0x4B, 0x60, 0x07, 0x70, 0xE5, 0x68, 0xC1, 0x6A, 0xFE, 0x67, 0x06, 0xE5, 0xA6, 0xF8, 0x02, 0x3D, 0x8F, 0x02, 0x6E, 0xD4, 0x07, 0xB5, 0xC4, 0xC1, 0x45, 0x12, 0xFE, 0x32, 0xBB, 0x73, 0xFD, 0xCA, 0x68, 0xB5, 0xF8, 0x4D, 0x07, 0x59, 0xA7, 0x07, 0xF2, 0x36, 0xC0, 0xFB, 0x57, 0x0E, 0x8A, 0x4D, 0x89, 0xB5, 0x62, 0x2C, 0x12, 0xC3, 0x62, 0x70, 0xA5, 0xCB, 0x1B, 0xBF, 0xFD, 0x59, 0x75, 0x2C, 0xE8, 0xD0, 0xBC, 0x22, 0xC1, 0xEB, 0xEA, 0xD6, 0xB0, 0x17, 0xF7, 0xBB, 0xE3, 0xB9, 0xB0, 0x64, 0x4B, 0x8F, 0xB9, 0xB5, 0xFB, 0xC4, 0x79, 0x02, 0x38, 0xF5, 0xE4, 0x05, 0x54, 0x4E, 0x06, 0x4D, 0x0D, 0x14, 0x58, 0xC6, 0x72, 0x40, 0xC0, 0xEA, 0x4E, 0xB9, 0x31, 0xA1, 0xD5, 0xE0, 0x54, 0x13, 0xD3, 0xCF, 0x5B, 0x94, 0x71, 0xA7, 0x95, 0xAE, 0x1D, 0xB3, 0xF7, 0x32, 0x53, 0x3B, 0x27, 0x8B, 0xAC, 0xEE, 0x96, 0x9F, 0xF2, 0x8C, 0xB5, 0x90, 0x53, 0xDF, 0x07, 0x03, 0xB1, 0xA6, 0x72, 0xEF, 0x9F, 0x5C, 0x1A, 0xE3, 0xA4, 0x3D, 0x39, 0xB9, 0x75, 0x7C, 0x33, 0xA7, 0x74, 0xBD, 0x6E, 0x5F, 0x78, 0xE5, 0x6D, 0x35, 0x1F, 0x77, 0xDA, 0x1E, 0xAB, 0xD9, 0xCF, 0x6F, 0x4D, 0x8D, 0xC8, 0x2D, 0xC7, 0x78, 0x15, 0x4C, 0xE8, 0xA3, 0xAF, 0x0C, 0x30, 0x01, 0x82, 0xB5, 0x66, 0x0D, 0xC4, 0xD8, 0x77, 0xD9, 0x60, 0xB3, 0x21, 0x18, 0xE0, 0x03, 0x35, 0xC0, 0x4E, 0x61, 0x0A, 0xAD, 0x96, 0xDF, 0x29, 0x37, 0xAD, 0xFF, 0x47, 0x38, 0x98, 0xEB, 0xB6, 0x5B, 0x8F, 0xEC, 0x7D, 0x25, 0x75, 0xAB, 0xAF, 0x53, 0xAE, 0xF5, 0x15, 0x0B, 0x65, 0x2E, 0x31, 0x1D, 0x7F, 0x02, 0xEF, 0x2C, 0x0C, 0xA4, 0x33, 0x19, 0xD9, 0x94, 0xB2, 0xEF, 0x86, 0x64, 0x9B, 0x21, 0xBB, 0x3B, 0x20, 0x70, 0x67, 0x59, 0x43, 0x5F, 0xE0, 0x43, 0xC8, 0xC0, 0xEF, 0x4F, 0xBC, 0xEF, 0x30, 0xDA, 0x1B, 0x01, 0x8B, 0x7A, 0x73, 0x4B, 0xDA, 0xB7, 0x7C, 0x5A, 0xD6, 0x7D, 0x68, 0x75, 0xBB, 0x5B, 0x62, 0x66, 0x0F, 0x04, 0x38, 0x8E, 0x4D, 0x03, 0x62, 0x03, 0x59, 0xFC, 0xE5, 0x69, 0xB5, 0xFA, 0x16, 0xB4, 0x9D, 0xB4, 0x1A, 0x1B, 0x49, 0xC7, 0xA4, 0x7E, 0x19, 0x0E, 0x3C, 0x6D, 0x28, 0x7F, 0xA8, 0x8D, 0xCA, 0xAF, 0xB1, 0xDA, 0xD5, 0xF0, 0xED, 0x8E, 0x20, 0xF3, 0x6F, 0x2F, 0x67, 0x45, 0x04, 0x94, 0xF5, 0x04, 0x8E, 0xEF, 0xF4, 0x34, 0x52, 0x61, 0x21, 0x8C, 0xF1, 0x12, 0xAF, 0xCF, 0xED, 0x3D, 0xC6, 0x32, 0x09, 0x44, 0x00, 0xB9, 0x6E, 0xE3, 0x55, 0xFD, 0x04, 0x88, 0xFC, 0x48, 0x45, 0x68, 0x3E, 0x2A, 0x3A, 0x1E, 0x00, 0xF7, 0x9B, 0x35, 0xE0, 0xBE, 0xB1, 0x05, 0xF0, 0x0D, 0x98, 0x02, 0x7B, 0x5E, 0x29, 0x05, 0x5C, 0x80, 0xE8, 0x79, 0xC5, 0x69, 0xB5, 0xC9, 0x20, 0x52, 0xA1, 0xD5, 0x90, 0xA4, 0xD8, 0x0A, 0xFB, 0xB6, 0x41, 0x39, 0x44, 0x05, 0xF2, 0xF0, 0x82, 0x4F, 0xBB, 0x85, 0x69, 0xF2, 0x77, 0xBA, 0xFC, 0xBE, 0x8E, 0xEC, 0x48, 0x9F, 0x99, 0x09, 0xC7, 0x65, 0x2A, 0xD9, 0xB3, 0x8D, 0xA9, 0xC5, 0x57, 0x2C, 0x14, 0x56, 0x8B, 0xD3, 0xEC, 0xE0, 0x74, 0xEE, 0x78, 0x1A, 0x88, 0x2D, 0xDA, 0x29, 0x81, 0xD4, 0x01, 0xFF, 0x1B, 0x0B, 0xEE, 0xAE, 0xE8, 0xFD, 0xDE, 0x27, 0xF7, 0xC6, 0xE9, 0x05, 0xF7, 0xD9, 0x0D, 0x16, 0x90, 0x36, 0x8B, 0x7B, 0xB0, 0xA6, 0x14, 0xF0, 0x05, 0x98, 0x02, 0xBB, 0xD8, 0x91, 0x1A, 0xB0, 0x41, 0xF0, 0xCD, 0x3D, 0x56, 0x8B, 0x85, 0x1B, 0x95, 0x3F, 0x33, 0x94, 0xBB, 0x5D, 0x17, 0x8E, 0x9E, 0x31, 0x19, 0x52, 0x53, 0xA8, 0x67, 0xAE, 0x97, 0xF2, 0x7E, 0xC8, 0x63, 0x35, 0x2D, 0x8E, 0x6E, 0x16, 0x0B, 0x38, 0xA0, 0x41, 0x1B, 0xB2, 0x5B, 0x36, 0x87, 0x23, 0xB6, 0xC4, 0x7A, 0x82, 0x2A, 0x8F, 0xA7, 0xA8, 0xE4, 0x3E, 0xAF, 0x39, 0x11, 0xF7, 0xA7, 0xE4, 0x5C, 0x66, 0x4C, 0x91, 0xFE, 0xBC, 0xCD, 0x01, 0xAF, 0xF7, 0xE8, 0x32, 0xBF, 0xC7, 0xCC, 0x5E, 0xC0, 0xD9, 0x76, 0x6A, 0xC0, 0x5F, 0x70, 0x03, 0xE6, 0xC0, 0x6E, 0xE0, 0xBA, 0x95, 0xC2, 0x6A, 0xFB, 0x2B, 0x61, 0xC9, 0xD8, 0x5F, 0x83, 0x0C, 0xD1, 0xBA, 0x0B, 0xF5, 0x3A, 0xE6, 0x58, 0x9A, 0xF0, 0x34, 0x46, 0x4D, 0x10, 0xDD, 0xFE, 0xA5, 0xE7, 0xD7, 0x8F, 0x20, 0x7A, 0x2B, 0xAB, 0xF0, 0xEE, 0x90, 0x00, 0xEB, 0xC9, 0xA8, 0x21, 0x72, 0x14, 0x6D, 0xF2, 0x2C, 0xEE, 0xE7, 0xA2, 0x13, 0x27, 0x70, 0xCE, 0x1C, 0xA5, 0x56, 0xC0, 0x7A, 0xB0, 0x00, 0x31, 0x3E, 0x3C, 0xD1, 0xE5, 0x19, 0xBF, 0x97, 0x2D, 0xFC, 0x9C, 0x2E, 0x6C, 0x3D, 0x95, 0xC7, 0x0B, 0x38, 0x25, 0xD9, 0x1B, 0xC8, 0x1E, 0x04, 0xE0, 0x09, 0x88, 0x03, 0x4B, 0x80, 0xDD, 0x40, 0x35, 0xAD, 0x26, 0x7F, 0x3E, 0xC9, 0xDA, 0xF9, 0x2D, 0xCE, 0xB4, 0x1A, 0x95, 0x32, 0xF2, 0x43, 0xE6, 0x37, 0x35, 0x4B, 0xF7, 0x46, 0x08, 0x22, 0x85, 0xE9, 0xCB, 0x8F, 0x90, 0x93, 0xFE, 0x0A, 0x0C, 0x51, 0xE8, 0x3D, 0xB1, 0x28, 0xF9, 0x25, 0x2E, 0x2B, 0x0B, 0x1A, 0x01, 0x26, 0xB4, 0xF1, 0xAA, 0x7A, 0x72, 0x8D, 0x37, 0x7E, 0x00, 0xDB, 0xEB, 0x35, 0x0E, 0x73, 0x71, 0x20, 0x01, 0x11, 0x80, 0x18, 0xA0, 0x79, 0xF4, 0x37, 0x7E, 0x57, 0x22, 0x3F, 0xC5, 0x15, 0xE5, 0x77, 0xCF, 0xA1, 0x92, 0xF9, 0x0B, 0x26, 0x90, 0x54, 0x87, 0x36, 0xA0, 0x6A, 0xA0, 0x80, 0x17, 0xB0, 0xD9, 0xE5, 0xB0, 0xF1, 0x69, 0x09, 0xD0, 0x9B, 0x56, 0x53, 0x74, 0x84, 0x5D, 0xFB, 0x9D, 0xA1, 0xF4, 0x95, 0xD0, 0x6A, 0x50, 0x55, 0x89, 0x9C, 0x82, 0x8D, 0xFE, 0x57, 0xDC, 0xFD, 0x2A, 0x7B, 0xE5, 0x9C, 0x3C, 0x32, 0x91, 0xFB, 0xB4, 0xC1, 0x3E, 0x4D, 0x1F, 0x78, 0x89, 0x9F, 0xFD, 0xCE, 0x19, 0x71, 0xA4, 0x65, 0x98, 0xF3, 0x70, 0x0B, 0xBA, 0xEF, 0x7D, 0xB7, 0xC8, 0xE8, 0x3D, 0x70, 0x26, 0xAD, 0x5D, 0x7D, 0x4C, 0x58, 0x39, 0xC9, 0x2C, 0xF3, 0x7D, 0xF2, 0x98, 0x4F, 0x83, 0x5F, 0x9F, 0x98, 0x42, 0xDC, 0xA9, 0xB9, 0xC5, 0xE2, 0x91, 0x1E, 0x14, 0xB0, 0xE6, 0x78, 0x99, 0x0E, 0xF8, 0x02, 0x92, 0x2E, 0xC7, 0x33, 0xD6, 0xEC, 0xAF, 0x82, 0x65, 0xC5, 0x30, 0x17, 0xEA, 0x03, 0x64, 0xC2, 0x81, 0xCC, 0xB6, 0x31, 0x0C, 0xEA, 0xC0, 0xC6, 0x6A, 0x55, 0xCC, 0x89, 0xBD, 0x7B, 0x59, 0xFA, 0x6F, 0x47, 0xDC, 0x79, 0x8E, 0x6B, 0xC6, 0x20, 0xE8, 0xBA, 0xC3, 0x16, 0xD5, 0xAC, 0xFB, 0x07, 0x34, 0x47, 0xBD, 0x28, 0xA6, 0x60, 0xC8, 0x7F, 0xA2, 0xC3, 0x3E, 0x61, 0x19, 0xD6, 0x2C, 0xD0, 0x71, 0x53, 0x3C, 0x3C, 0xD2, 0x99, 0x99, 0xBC, 0x24, 0xF6, 0x23, 0x8A, 0x3E, 0x58, 0x79, 0x2B, 0x57, 0x57, 0x3E, 0xA9, 0x6B, 0x72, 0xA7, 0xAE, 0xED, 0x7A, 0x52, 0xD7, 0x36, 0x60, 0x02, 0xEC, 0x0D, 0xE8, 0x95, 0xB9, 0x03, 0xA3, 0x51, 0xA6, 0x74, 0xFE, 0x56, 0x99, 0x28, 0x3C, 0x33, 0x44, 0x3F, 0x4B, 0x1D, 0x39, 0x12, 0xBE, 0xC7, 0x4D, 0xD5, 0x30, 0x88, 0x08, 0x83, 0x2B, 0x77, 0xC7, 0x02, 0x56, 0x56, 0x9F, 0xDC, 0x52, 0x9E, 0x24, 0x83, 0xFE, 0xB4, 0x39, 0x9B, 0x17, 0xE0, 0x3A, 0x70, 0xA0, 0xB9, 0x67, 0x07, 0xCC, 0x5B, 0x06, 0x13, 0xBA, 0xFC, 0x64, 0xF7, 0xB9, 0x0C, 0x36, 0x5E, 0x61, 0xBB, 0xAB, 0x3A, 0xA6, 0xE8, 0x78, 0x3A, 0x16, 0xBC, 0xAD, 0xA1, 0x06, 0x19, 0x03, 0x19, 0xD8, 0x23, 0x14, 0xE3, 0x40, 0x2F, 0xA0, 0x06, 0xEE, 0x4F, 0x5C, 0x5F, 0xE7, 0x93, 0x01, 0x95, 0xC7, 0x68, 0x6F, 0xCB, 0x82, 0xF9, 0x1B, 0x27, 0xA5, 0x92, 0x05, 0x9B, 0xC0, 0x4C, 0xCC, 0x62, 0xDD, 0xC6, 0x6A, 0x56, 0xB2, 0x3C, 0x02, 0x01, 0xB4, 0x9A, 0x72, 0x3D, 0xE4, 0x52, 0x3B, 0x96, 0x39, 0x62, 0x61, 0x0A, 0xF8, 0x06, 0xC2, 0xE7, 0xF2, 0xB2, 0x78, 0x87, 0x80, 0xD5, 0x72, 0x06, 0x97, 0x25, 0xA5, 0xC1, 0x7F, 0x63, 0xAC, 0x4F, 0x72, 0x9B, 0x8D, 0xBF, 0x72, 0xDD, 0xED, 0xE0, 0x94, 0x46, 0x48, 0x60, 0x3D, 0xDD, 0x6A, 0xAC, 0x06, 0xF6, 0x2F, 0x89, 0xEF, 0xA7, 0xC6, 0x5D, 0xE3, 0x5F, 0x12, 0xDF, 0x0B, 0xA0, 0x45, 0x4D, 0x69, 0xB5, 0xAB, 0xA9, 0xB1, 0xA0, 0x9F, 0x6C, 0x7C, 0xD9, 0x2E, 0x1B, 0xF2, 0x60, 0x92, 0x70, 0x2E, 0x23, 0x34, 0xE5, 0xAB, 0xF7, 0x1F, 0x8C, 0xA6, 0x57, 0xE6, 0xDA, 0x70, 0x9F, 0x63, 0x93, 0x39, 0xC3, 0x5F, 0x13, 0x15, 0x37, 0x20, 0x65, 0x10, 0x80, 0x6F, 0x60, 0xF7, 0xE0, 0x08, 0x04, 0xB0, 0xBC, 0x8B, 0x5E, 0xE6, 0xB1, 0xFD, 0xC9, 0x1D, 0x8E, 0x09, 0xB4, 0x32, 0xF3, 0xF3, 0x1F, 0x3D, 0x40, 0xAB, 0x07, 0xEB, 0xC9, 0x6A, 0x1B, 0x68, 0x0C, 0x7C, 0x90, 0x80, 0xF7, 0xDD, 0xC7, 0x47, 0x07, 0xA2, 0xB7, 0x40, 0x69, 0x0E, 0x5C, 0x6F, 0x33, 0xEB, 0x99, 0xA0, 0x4F, 0x57, 0x63, 0x57, 0x81, 0x48, 0x90, 0xCF, 0x3C, 0x43, 0xB8, 0xC0, 0xD4, 0x1B, 0xD7, 0xAA, 0xF1, 0x1A, 0x95, 0xE4, 0x7B, 0xC6, 0xBD, 0x7B, 0xBF, 0x39, 0x8D, 0x60, 0x7D, 0x3B, 0xE5, 0x2B, 0xC7, 0x53, 0xC3, 0xFB, 0x54, 0x02, 0xBB, 0x80, 0x75, 0x6D, 0xA4, 0x4C, 0x1B, 0xE8, 0x73, 0x47, 0x5C, 0x74, 0x59, 0x24, 0x4B, 0xEB, 0xE8, 0xDF, 0xE2, 0x2A, 0x75, 0xE9, 0x47, 0x58, 0xBC, 0x6D, 0xC2, 0x1F, 0x91, 0x57, 0x1D, 0xEC, 0x81, 0x3C, 0x33, 0xF4, 0x71, 0x77, 0x96, 0x03, 0x5E, 0xC0, 0xAE, 0x67, 0x86, 0xAE, 0x77, 0x86, 0x5E, 0x7D, 0x8D, 0xF3, 0x28, 0xB9, 0x2B, 0xF5, 0x35, 0xDB, 0x71, 0xDA, 0x9F, 0x80, 0x5E, 0x34, 0xAC, 0xD6, 0xD5, 0x57, 0xA3, 0xA4, 0xA8, 0xC7, 0x27, 0x69, 0x72, 0x25, 0xAA, 0xD8, 0xF9, 0xDA, 0xEA, 0x80, 0x6F, 0x60, 0x8D, 0xD5, 0x7C, 0x01, 0x3B, 0x00, 0xBA, 0x6F, 0xD6, 0xA5, 0xEB, 0xCA, 0x4F, 0x7A, 0xC4, 0x66, 0xA3, 0x11, 0x89, 0x3E, 0x41, 0x9D, 0x3B, 0x89, 0x76, 0xBD, 0x0A, 0xC2, 0xF9, 0x48, 0x56, 0xE7, 0xC0, 0x06, 0xFE, 0xAF, 0xB1, 0xB6, 0x9F, 0xB1, 0x76, 0xEC, 0xFB, 0x28, 0x0F, 0xAF, 0x79, 0xD3, 0x68, 0xB5, 0x5C, 0x57, 0xF0, 0xB8, 0x5A, 0xBE, 0x9B, 0x7C, 0x88, 0x4E, 0xF6, 0x5D, 0xA1, 0x3D, 0x61, 0x40, 0xF8, 0xC4, 0x15, 0xDE, 0xF0, 0x8A, 0x7D, 0xB5, 0xCC, 0x8B, 0xDB, 0x93, 0xAB, 0x27, 0xD7, 0x63, 0x25, 0x5D, 0xA3, 0x77, 0x6A, 0xEC, 0xE6, 0xC3, 0x81, 0xF5, 0xC0, 0x4E, 0x07, 0x0B, 0x96, 0x18, 0x33, 0x1F, 0x08, 0xA0, 0x93, 0x7A, 0x6F, 0xFC, 0x1C, 0xA3, 0x39, 0x1C, 0xD4, 0x4F, 0x5F, 0x20, 0x0E, 0x96, 0xE5, 0xFC, 0x04, 0x24, 0xB1, 0x80, 0xA8, 0xDB, 0x16, 0xDD, 0xB7, 0x76, 0x47, 0x2F, 0x20, 0x0B, 0xF0, 0x27, 0x89, 0xB5, 0x1F, 0x49, 0xF0, 0x5E, 0xC7, 0x6A, 0xFB, 0x8B, 0x86, 0xF6, 0xEE, 0xCB, 0x41, 0x94, 0x22, 0x38, 0xB6, 0x58, 0xE3, 0xF8, 0x61, 0x82, 0xF3, 0xA0, 0x14, 0x60, 0xF1, 0xCD, 0xC8, 0xFD, 0x38, 0xD7, 0x8E, 0x9C, 0xC3, 0x71, 0xCD, 0x8C, 0xB7, 0x8A, 0xDD, 0x52, 0x9B, 0x5A, 0x6B, 0x06, 0xB4, 0x0E, 0xEC, 0x6E, 0xAF, 0x8A, 0xDF, 0x1E, 0xF6, 0x81, 0x24, 0x51, 0x01, 0x7B, 0x8E, 0x26, 0x72, 0xE9, 0x74, 0xCA, 0x91, 0x0F, 0xCA, 0xE3, 0x37, 0xBC, 0xB5, 0x79, 0x42, 0xEF, 0xF0, 0x5C, 0x3A, 0x10, 0x36, 0x90, 0x41, 0xDF, 0xEB, 0x82, 0x3B, 0x50, 0x3D, 0x50, 0x20, 0xF6, 0x13, 0x1A, 0x0D, 0x40, 0x04, 0xE8, 0x63, 0x34, 0x41, 0x5D, 0x46, 0xE6, 0xA4, 0x33, 0x0A, 0x0A, 0xE7, 0x04, 0x9F, 0x34, 0xFC, 0x03, 0xBD, 0x6A, 0xEA, 0x3D, 0x3B, 0x59, 0x5F, 0x8D, 0xC7, 0x6F, 0xD9, 0x93, 0x13, 0x41, 0xB6, 0x39, 0x5F, 0x8D, 0xEA, 0xA7, 0xC8, 0xE9, 0x56, 0x10, 0x02, 0x64, 0x0C, 0x28, 0x4B, 0x3A, 0x16, 0xD9, 0x0B, 0xF6, 0xB1, 0xFD, 0x6B, 0x3A, 0xC2, 0x1F, 0x68, 0xD8, 0x4E, 0xF4, 0xDC, 0x75, 0xF6, 0x35, 0x0A, 0x17, 0xF6, 0xE8, 0x3E, 0x9D, 0x66, 0x2D, 0xEF, 0x3C, 0x3D, 0xDF, 0x80, 0xF6, 0xC0, 0x06, 0xFD, 0x08, 0xBC, 0x36, 0x50, 0x1B, 0xC8, 0x05, 0xD8, 0x7E, 0x04, 0x5E, 0x0D, 0x38, 0xF1, 0x84, 0x3A, 0x46, 0xD3, 0x2F, 0x63, 0xBE, 0x2A, 0xA7, 0x02, 0x42, 0xE6, 0x6F, 0x3C, 0xAA, 0xB8, 0x7A, 0x8A, 0xB5, 0xF1, 0xC7, 0x65, 0x59, 0xDC, 0x52, 0xE6, 0x74, 0x5C, 0x27, 0x5C, 0x67, 0x44, 0x89, 0xC9, 0x74, 0x3E, 0x86, 0x61, 0xB1, 0x5C, 0x06, 0x87, 0x2F, 0x10, 0xF5, 0x94, 0xC0, 0x6D, 0x96, 0xD5, 0xCE, 0x48, 0x73, 0x36, 0x20, 0x07, 0x16, 0x8D, 0x46, 0xC1, 0x39, 0xD6, 0x71, 0xD7, 0x8C, 0x2D, 0x86, 0x3B, 0xE9, 0x42, 0x19, 0x13, 0x86, 0x02, 0x7B, 0x5F, 0xD2, 0xAC, 0x9E, 0x03, 0x19, 0x04, 0x50, 0xC5, 0x2D, 0x2B, 0x80, 0x12, 0x20, 0xF7, 0xFD, 0x70, 0xF9, 0x95, 0x68, 0xDF, 0x5C, 0xAD, 0xF3, 0x18, 0xCD, 0x90, 0xA5, 0x20, 0x09, 0xD5, 0xF9, 0x5D, 0xC8, 0x5B, 0x52, 0x14, 0x3B, 0xBA, 0x2A, 0x7E, 0xBC, 0x1C, 0xFB, 0x58, 0x23, 0x74, 0x25, 0x2B, 0x78, 0xCC, 0x60, 0xCE, 0xC2, 0x75, 0xC2, 0x2D, 0xBD, 0xBA, 0xBF, 0xED, 0xB1, 0x88, 0x9D, 0xAA, 0x77, 0x57, 0x20, 0x65, 0xA0, 0xC0, 0xA9, 0xF4, 0xB4, 0xB1, 0x4F, 0x62, 0xC0, 0xB1, 0x0A, 0x54, 0x13, 0xAF, 0xD8, 0xC4, 0x9D, 0x59, 0x73, 0x5D, 0x8C, 0xBF, 0xC5, 0x5D, 0x59, 0xC5, 0x4C, 0xD2, 0xC1, 0xD6, 0x5B, 0xF4, 0x24, 0x36, 0xE0, 0x09, 0xC4, 0xBA, 0xD3, 0x70, 0x6D, 0x01, 0xF9, 0xA4, 0xC6, 0xDB, 0x06, 0xD6, 0x71, 0x91, 0xCE, 0x27, 0xBE, 0xA9, 0xC7, 0x68, 0xFE, 0x45, 0x42, 0x2B, 0x62, 0x32, 0xC0, 0x02, 0xAA, 0x67, 0xB1, 0xE9, 0xD8, 0x18, 0xC1, 0xD3, 0x3D, 0x82, 0x63, 0x32, 0x42, 0x6E, 0x71, 0x37, 0x84, 0x7E, 0x9A, 0xD8, 0xD0, 0xDF, 0x40, 0x5B, 0xEC, 0xA3, 0xA9, 0x59, 0xD4, 0x46, 0x70, 0x40, 0x78, 0x7C, 0xD6, 0xC1, 0x86, 0x65, 0x84, 0x4D, 0x57, 0xAE, 0xB5, 0x6D, 0xCD, 0xC3, 0x38, 0x69, 0x69, 0x76, 0x69, 0xCD, 0x31, 0xCD, 0x74, 0x9F, 0x41, 0xD2, 0x0B, 0x48, 0x03, 0x7C, 0x01, 0x92, 0x03, 0x79, 0xD0, 0x40, 0xE4, 0xAD, 0xF1, 0x5D, 0x0B, 0xC8, 0x01, 0xA3, 0x10, 0x6D, 0x40, 0x2C, 0x20, 0xA9, 0x5E, 0x53, 0xB4, 0x5A, 0xFC, 0x15, 0xAC, 0x30, 0xDE, 0x9C, 0xC4, 0x74, 0x91, 0xC6, 0xE6, 0x1F, 0x58, 0xDB, 0x7C, 0x37, 0xE2, 0x3A, 0xEE, 0xBF, 0xF9, 0xB9, 0xF2, 0x09, 0x18, 0x9C, 0xFB, 0xDA, 0x51, 0x83, 0x77, 0xAE, 0x58, 0x4F, 0x19, 0xEA, 0xC2, 0xA7, 0x4E, 0x40, 0xFA, 0xA7, 0xC1, 0x19, 0x63, 0x50, 0xC8, 0xEE, 0x51, 0x06, 0x7C, 0x7E, 0x8B, 0x9F, 0x95, 0xD7, 0x9C, 0xED, 0xFC, 0x78, 0x47, 0x56, 0x5C, 0x37, 0xD0, 0x14, 0xC0, 0x14, 0xD8, 0x8F, 0xCC, 0x70, 0x0A, 0x10, 0x05, 0xF0, 0xCD, 0x95, 0x00, 0x1E, 0xF6, 0x89, 0x72, 0xB6, 0x01, 0xE1, 0x80, 0x18, 0x57, 0x48, 0xDE, 0x71, 0x81, 0x3E, 0xE9, 0xF2, 0x27, 0x63, 0x8D, 0x93, 0x00, 0x65, 0xD9, 0x56, 0x8E, 0x31, 0x56, 0x02, 0x67, 0xFE, 0xA6, 0x42, 0xEF, 0x1E, 0x91, 0x12, 0xA7, 0xA2, 0xDF, 0x53, 0xE9, 0xEE, 0xBF, 0xD9, 0xB0, 0x8D, 0x49, 0xB6, 0x14, 0xE3, 0x3B, 0x8B, 0x7F, 0xEC, 0xBB, 0xE4, 0xA0, 0xE5, 0xFE, 0x6F, 0xAC, 0xF6, 0x55, 0x8E, 0x38, 0x1D, 0x6B, 0xDB, 0x6F, 0xC7, 0x84, 0x1C, 0xF8, 0xC4, 0x19, 0xF1, 0x9D, 0x1E, 0x41, 0x7E, 0x7B, 0x0E, 0xAA, 0xF6, 0xF8, 0x80, 0x3B, 0xFF, 0xA5, 0xB6, 0x66, 0x00, 0x03, 0x14, 0xB2, 0x80, 0x15, 0xFF, 0x52, 0xE2, 0xE7, 0x27, 0x9D, 0x57, 0xFA, 0x58, 0xAD, 0xAE, 0x8C, 0xB5, 0x0C, 0xFF, 0xAA, 0xD1, 0xD5, 0x7C, 0x6E, 0xDA, 0x1B, 0x85, 0x21, 0xBB, 0x20, 0xA7, 0x55, 0xE3, 0x22, 0x6A, 0x1E, 0xD5, 0xDE, 0x74, 0x79, 0xA6, 0x4B, 0xF9, 0x73, 0xC0, 0xDD, 0x74, 0x40, 0x06, 0x50, 0x83, 0xDC, 0x80, 0xC9, 0x40, 0x8F, 0x83, 0xF9, 0x84, 0x96, 0x85, 0x13, 0xAD, 0x8F, 0xDE, 0x48, 0x72, 0xCB, 0x4C, 0x8C, 0xAE, 0xAB, 0x8C, 0xCE, 0x8E, 0x8F, 0x32, 0xEC, 0x1F, 0xA5, 0xC3, 0xD1, 0x80, 0xD7, 0xC0, 0xAF, 0x4F, 0xBF, 0xB6, 0x54, 0x40, 0x14, 0xE0, 0xF5, 0xF4, 0xAA, 0xEA, 0x7F, 0xB5, 0xB9, 0xD7, 0x63, 0x35, 0xA8, 0x95, 0x7A, 0xD4, 0xD5, 0xA2, 0xD7, 0x5B, 0x31, 0x27, 0x76, 0x8E, 0x7F, 0x63, 0x23, 0x68, 0x28, 0x8E, 0xC3, 0x95, 0xD8, 0x71, 0xDA, 0x22, 0x3B, 0x96, 0x19, 0x8C, 0x4C, 0x29, 0xA5, 0xF7, 0x97, 0x59, 0xAF, 0x31, 0x6D, 0xC9, 0x72, 0xCE, 0x12, 0x0A, 0x84, 0x00, 0x5E, 0x40, 0xB0, 0x81, 0x99, 0x8C, 0x8C, 0xEB, 0x87, 0x91, 0x5E, 0xD3, 0x9C, 0x57, 0x58, 0xD2, 0xCF, 0x88, 0xB4, 0x1E, 0xF3, 0xF6, 0x9B, 0xDC, 0x55, 0x8C, 0x3A, 0x03, 0xE2, 0xB7, 0x07, 0x3B, 0x72, 0x60, 0x83, 0x27, 0xAF, 0x2A, 0xF2, 0xAE, 0x77, 0xEB, 0x41, 0x2A, 0xA0, 0x1B, 0x58, 0x06, 0x88, 0xCC, 0x9B, 0x8C, 0x83, 0x8E, 0x96, 0x68, 0xAE, 0x7D, 0x37, 0xB8, 0xDF, 0x7B, 0x52, 0x40, 0x6A, 0xD6, 0xF0, 0xFE, 0x56, 0xE6, 0xDE, 0x89, 0xEA, 0xFD, 0xB8, 0xD2, 0x2C, 0x96, 0x02, 0x51, 0xBF, 0x74, 0x09, 0xEE, 0x8A, 0x3A, 0x21, 0x4E, 0x9B, 0x64, 0x18, 0x43, 0x55, 0x3B, 0x50, 0x40, 0x2C, 0xC0, 0x85, 0x5A, 0x48, 0xD3, 0x87, 0x70, 0x8F, 0x8E, 0x2E, 0x75, 0x05, 0x9C, 0x8D, 0xBA, 0x60, 0x41, 0xEA, 0xF0, 0x08, 0x27, 0x32, 0xE5, 0xB1, 0x65, 0xB6, 0x1C, 0xBB, 0xDB, 0xBC, 0xC8, 0xA6, 0x4B, 0x09, 0x08, 0x01, 0xBC, 0xEE, 0x80, 0xF2, 0x32, 0x20, 0xE7, 0xC7, 0xB7, 0x01, 0x8B, 0xC1, 0xE6, 0x0D, 0x68, 0x01, 0x6B, 0x20, 0x31, 0x6F, 0x26, 0x6D, 0x46, 0xD7, 0x2D, 0x84, 0x57, 0xA5, 0xE5, 0xFB, 0x3D, 0x6B, 0x15, 0xD6, 0xE7, 0x52, 0x24, 0x7B, 0x56, 0x42, 0xF7, 0x0A, 0x31, 0x16, 0x0A, 0x30, 0xD7, 0x7A, 0xF7, 0x4F, 0xF5, 0xBB, 0x27, 0x4B, 0xD8, 0xE2, 0x41, 0x6A, 0xFE, 0x4A, 0x0D, 0xEC, 0x9C, 0x87, 0xCC, 0x5F, 0x0C, 0x40, 0x12, 0x60, 0x28, 0x4D, 0xEA, 0x2E, 0x49, 0x6B, 0xB6, 0x4C, 0xE2, 0xEA, 0x7D, 0x77, 0x58, 0x95, 0xFA, 0x47, 0x52, 0x56, 0x0B, 0x50, 0x0A, 0x44, 0x00, 0xDE, 0x83, 0x7C, 0x1C, 0x3E, 0x7A, 0x97, 0x2B, 0x87, 0x00, 0xBE, 0x01, 0xE9, 0x7F, 0xDC, 0xC7, 0xFA, 0x2A, 0x81, 0x86, 0xD5, 0x84, 0x56, 0x43, 0xBD, 0xD9, 0x67, 0x20, 0xF6, 0xAC, 0xFB, 0x86, 0xB4, 0x63, 0x15, 0x54, 0x85, 0xEF, 0x4A, 0x26, 0x25, 0x4C, 0xF2, 0xEE, 0x09, 0xAD, 0xCF, 0xFD, 0xF3, 0xA4, 0xC6, 0xB0, 0x70, 0x86, 0x9B, 0x8F, 0xCF, 0xA7, 0x75, 0x97, 0x0E, 0x66, 0x03, 0x56, 0x40, 0xE5, 0xAD, 0x5F, 0x58, 0x1B, 0x58, 0x4E, 0x8F, 0xEC, 0x9D, 0xED, 0xFC, 0x2E, 0xF0, 0xAA, 0x80, 0x14, 0xE0, 0x7E, 0x5B, 0xC6, 0x7A, 0x10, 0x37, 0xDE, 0x46, 0xDA, 0xBB, 0x01, 0x1B, 0xE8, 0x40, 0x68, 0xD8, 0xF8, 0x57, 0xFB, 0x9F, 0x3A, 0x56, 0xD3, 0x63, 0x35, 0xFF, 0x7C, 0xE2, 0xFD, 0xE7, 0x0A, 0xFD, 0x60, 0xD4, 0xDA, 0xED, 0x3F, 0x78, 0x23, 0x36, 0xF2, 0xA2, 0x2D, 0x26, 0x0B, 0xB1, 0x19, 0x69, 0x7F, 0xF2, 0xAF, 0x18, 0x8E, 0xBC, 0x5A, 0x04, 0x23, 0xA6, 0x05, 0xC4, 0x02, 0x4C, 0xE7, 0x0C, 0x1E, 0xC0, 0x6E, 0x0A, 0xC3, 0xDF, 0xB1, 0x37, 0xAF, 0x13, 0x5A, 0x3A, 0xC3, 0xB1, 0x4F, 0x1D, 0xED, 0x51, 0xE9, 0xE3, 0xF5, 0x39, 0x6E, 0x3F, 0x6D, 0x18, 0x90, 0x3E, 0x58, 0x80, 0xDB, 0x3F, 0x8C, 0xE7, 0x0B, 0x38, 0xF1, 0x88, 0x00, 0xBC, 0x6E, 0xE3, 0x89, 0x3E, 0xED, 0xC7, 0x07, 0xC5, 0x37, 0xFB, 0x58, 0x0D, 0xD1, 0x02, 0x53, 0x24, 0x79, 0xE4, 0x16, 0x78, 0x88, 0x76, 0x4D, 0x88, 0x3C, 0xA7, 0xBA, 0xCF, 0xA7, 0xEE, 0x66, 0x02, 0xCA, 0x86, 0x0D, 0x54, 0x5F, 0x55, 0x05, 0xE9, 0x2B, 0xD8, 0x21, 0x47, 0x4F, 0x68, 0xE5, 0x1D, 0x0B, 0x5B, 0x7A, 0xE7, 0xEB, 0x30, 0xBC, 0xEC, 0x0E, 0xD4, 0xBE, 0x7F, 0x60, 0x35, 0xF3, 0x7C, 0x98, 0x4C, 0x70, 0xB5, 0xAF, 0x51, 0x7A, 0x53, 0xE4, 0xAE, 0xFA, 0xB4, 0x41, 0x3F, 0xFA, 0x6B, 0xA2, 0x83, 0x18, 0x34, 0xA0, 0x0E, 0xE4, 0xD3, 0x7E, 0x24, 0x13, 0x08, 0xE7, 0x43, 0x26, 0x52, 0x03, 0xDE, 0x40, 0xC6, 0xBC, 0xB2, 0x8E, 0xD5, 0xFC, 0x13, 0xDE, 0xAC, 0x52, 0x94, 0xA0, 0xB8, 0x43, 0x0B, 0x47, 0x9C, 0xCD, 0x8C, 0xE1, 0xBC, 0x35, 0xC3, 0xC5, 0xA5, 0x7C, 0x4E, 0xD4, 0x7A, 0x67, 0x7E, 0x2F, 0x5A, 0x6D, 0x3D, 0xEB, 0x5A, 0xD3, 0x78, 0xFB, 0x1F, 0x52, 0xDB, 0xBC, 0x3C, 0xA6, 0x00, 0xAE, 0xF7, 0x06, 0xD5, 0xC9, 0xBD, 0x88, 0xA6, 0x9C, 0x9F, 0x8B, 0xD3, 0xF2, 0xEE, 0x04, 0x0A, 0xE2, 0x84, 0xF5, 0x94, 0x85, 0x8B, 0x63, 0xC3, 0xC5, 0x4F, 0x05, 0x54, 0x0C, 0xF4, 0xC1, 0xD8, 0x77, 0x07, 0x8D, 0x7E, 0x6B, 0x0B, 0xB6, 0x00, 0xB9, 0x00, 0x55, 0x60, 0x2F, 0x40, 0x12, 0x68, 0x3B, 0x56, 0x8B, 0xBF, 0x48, 0xC4, 0xD1, 0xE1, 0x0C, 0xAA, 0xD1, 0xC4, 0x75, 0xEC, 0x53, 0x7B, 0x8F, 0x04, 0x19, 0xE6, 0xAB, 0x56, 0x8D, 0x42, 0xDC, 0xA6, 0xD0, 0xF7, 0xDD, 0x02, 0x28, 0xDE, 0x42, 0x77, 0x06, 0x08, 0x26, 0xA6, 0x64, 0xD4, 0x7D, 0x5F, 0xB7, 0xF8, 0x8F, 0xF0, 0x32, 0x95, 0xF7, 0x2B, 0x71, 0xA9, 0xC1, 0xFA, 0xF1, 0x09, 0x55, 0x4E, 0x14, 0xB3, 0xEE, 0x56, 0x06, 0xB4, 0x64, 0x19, 0xC0, 0x10, 0x7B, 0xFB, 0xD3, 0x67, 0x65, 0x01, 0x5E, 0x37, 0xC2, 0xEE, 0x16, 0x84, 0xBE, 0x81, 0x4A, 0x20, 0x1B, 0xF0, 0x02, 0x64, 0xDF, 0x6F, 0xEE, 0x33, 0xDE, 0x69, 0x34, 0x24, 0x12, 0xB5, 0x25, 0x8E, 0x16, 0xA2, 0xC8, 0x32, 0xCB, 0x9C, 0x43, 0x68, 0xE2, 0x9C, 0xAA, 0x36, 0xE9, 0x0D, 0x32, 0x59, 0x41, 0x41, 0xD5, 0xB0, 0x3B, 0x72, 0x1C, 0x8F, 0x5B, 0x8D, 0x49, 0x60, 0xE5, 0x63, 0x8A, 0x06, 0xEA, 0xD8, 0x6E, 0xAC, 0x55, 0x80, 0x2A, 0x10, 0x31, 0xFF, 0x6D, 0x8C, 0x26, 0xF5, 0xFB, 0x24, 0x27, 0xF4, 0x2B, 0x33, 0x0A, 0x85, 0x27, 0x29, 0xCA, 0x5A, 0x0B, 0x60, 0x47, 0x34, 0x05, 0xE0, 0x27, 0x4F, 0x20, 0x0A, 0x48, 0x03, 0x8A, 0xC3, 0x7D, 0x50, 0x7D, 0xA7, 0x13, 0xD1, 0xF9, 0xD4, 0x02, 0x98, 0x02, 0x7B, 0x20, 0x31, 0xAF, 0x04, 0x8D, 0x56, 0x7F, 0x1E, 0xA7, 0xCB, 0x54, 0xA7, 0xC0, 0x5A, 0x3B, 0xA7, 0x88, 0x2D, 0x27, 0x85, 0xD1, 0x70, 0x6A, 0xD5, 0x9A, 0x41, 0x01, 0x5F, 0x64, 0x3C, 0x46, 0x3B, 0xBD, 0x8A, 0x8C, 0x07, 0x5C, 0x66, 0xF8, 0xD1, 0xEF, 0xA3, 0x40, 0x04, 0x40, 0x0F, 0x9A, 0x6E, 0x16, 0x72, 0x01, 0xB9, 0xE7, 0xA1, 0x01, 0xF4, 0xA7, 0xF1, 0xDA, 0xEE, 0xEC, 0x10, 0x41, 0xD5, 0xF0, 0xD3, 0xF6, 0xF1, 0xBE, 0x62, 0x6C, 0x03, 0xA4, 0x00, 0xD5, 0x81, 0x0C, 0x12, 0x30, 0x01, 0x5C, 0xEF, 0x54, 0x51, 0x1B, 0x94, 0x03, 0x59, 0x80, 0x0F, 0xE4, 0xD1, 0x55, 0xDC, 0x06, 0xF4, 0x19, 0x69, 0x48, 0x23, 0x6A, 0x2E, 0xDA, 0x9E, 0xD3, 0x81, 0xCC, 0x10, 0xB4, 0x0F, 0x9D, 0x9F, 0xC3, 0xBC, 0xDC, 0x5B, 0x3F, 0xD4, 0x0A, 0x5E, 0x07, 0x6E, 0x17, 0x11, 0x97, 0xD8, 0x15, 0x4C, 0xAC, 0xE4, 0x2D, 0xD3, 0x29, 0xB9, 0x76, 0xF7, 0x48, 0xAA, 0x04, 0x54, 0x80, 0x15, 0x40, 0x26, 0x25, 0x23, 0xC7, 0xDA, 0x76, 0x57, 0x90, 0xAA, 0xF2, 0x22, 0xFA, 0xCB, 0x39, 0x08, 0x3C, 0xBC, 0x7D, 0xB6, 0x80, 0x14, 0xA0, 0x7D, 0xC3, 0x12, 0xF0, 0x0D, 0xC4, 0xA0, 0xFD, 0xB6, 0x61, 0x2F, 0xA0, 0x14, 0x88, 0x05, 0x88, 0xCF, 0x9B, 0x7D, 0xA7, 0xA6, 0x9E, 0x24, 0x85, 0x5E, 0xDF, 0xA2, 0xE6, 0x19, 0xF0, 0x42, 0x76, 0x4E, 0x80, 0xDC, 0x59, 0x25, 0x3C, 0x2D, 0xBA, 0xF6, 0xB4, 0x03, 0x85, 0x0D, 0xBD, 0xFC, 0x4E, 0x8F, 0x8C, 0xC7, 0x85, 0x6B, 0x4C, 0xD8, 0x60, 0x07, 0xC6, 0xC5, 0x23, 0xB6, 0x00, 0x32, 0x0F, 0x43, 0xEE, 0x2E, 0x01, 0xB2, 0x00, 0xB6, 0xE3, 0xDA, 0x0D, 0xF4, 0xBC, 0xD2, 0x7D, 0xFE, 0xBE, 0xF4, 0x4A, 0xB3, 0x1E, 0xE5, 0x84, 0xBE, 0x30, 0x69, 0x6F, 0x35, 0xF9, 0xD7, 0x73, 0xB8, 0x04, 0xD8, 0x3A, 0x28, 0x40, 0x02, 0xF0, 0xA6, 0x54, 0x3C, 0x60, 0x35, 0xD8, 0x00, 0xDF, 0x2C, 0xE3, 0x9B, 0x40, 0x2A, 0xDF, 0xA4, 0xD5, 0xF6, 0x5F, 0x4E, 0x3D, 0xAA, 0x3A, 0xCA, 0x3D, 0xD1, 0x3A, 0x5D, 0x31, 0x70, 0xCB, 0xA6, 0xB8, 0xC4, 0x26, 0x33, 0x3B, 0xB0, 0x12, 0x98, 0x5C, 0x7D, 0x07, 0xBD, 0xDE, 0x5E, 0xAA, 0x4C, 0x59, 0x03, 0xE0, 0xEE, 0x1B, 0x3F, 0x05, 0x10, 0x1B, 0xD8, 0xAC, 0xED, 0x1D, 0x50, 0x02, 0x85, 0xE6, 0xB2, 0xFA, 0xB9, 0x31, 0xE9, 0xDA, 0xAA, 0x33, 0xB7, 0x98, 0x23, 0x54, 0x75, 0xE5, 0x6E, 0xF1, 0x16, 0xA7, 0x01, 0x24, 0x6D, 0x28, 0x03, 0x03, 0xF6, 0x1E, 0x28, 0x20, 0x0B, 0x70, 0x3A, 0xCF, 0x76, 0x02, 0x1E, 0x80, 0x39, 0xB0, 0xFB, 0xAA, 0x49, 0x30, 0x03, 0x42, 0xE9, 0xF4, 0x3D, 0x63, 0x4D, 0xB0, 0xAC, 0xD9, 0x9E, 0x7E, 0x1B, 0x3A, 0x8D, 0x07, 0x1A, 0x06, 0x8A, 0x1E, 0xB1, 0xF4, 0xC0, 0x7A, 0x66, 0x3E, 0xDD, 0xAF, 0x93, 0x8B, 0xFF, 0x0C, 0x39, 0xD6, 0xC9, 0x5D, 0x9D, 0x93, 0xD8, 0xEB, 0x02, 0xC9, 0x69, 0x70, 0x6E, 0x26, 0x10, 0x7D, 0x37, 0x78, 0x58, 0x73, 0x7D, 0xD7, 0x00, 0xD2, 0x7E, 0xBD, 0xDB, 0x27, 0xEF, 0x4E, 0x27, 0x83, 0x4B, 0x65, 0x1C, 0x4D, 0x35, 0xA1, 0x07, 0xBB, 0x7B, 0x7B, 0xED, 0x3A, 0x8B, 0x5C, 0x18, 0x50, 0x7B, 0x50, 0x03, 0x1D, 0xF8, 0x20, 0x00, 0xFE, 0x21, 0x4E, 0x4B, 0x05, 0x01, 0x6C, 0x03, 0xD2, 0x1C, 0xE1, 0x80, 0x07, 0x20, 0x0E, 0x68, 0xCC, 0x2B, 0x49, 0xA3, 0xE9, 0x84, 0x8C, 0x7F, 0xE9, 0xDE, 0xC9, 0x46, 0x6C, 0xD3, 0x8C, 0x25, 0x10, 0x77, 0x51, 0xB8, 0x36, 0xB1, 0xC7, 0xBA, 0x5D, 0x5A, 0x88, 0xFB, 0xBA, 0xB7, 0x33, 0x3F, 0xCF, 0x4E, 0x33, 0xEC, 0x9A, 0x56, 0x52, 0xA6, 0xA3, 0x51, 0xBA, 0x80, 0x3D, 0x0F, 0xB3, 0x81, 0xF0, 0x75, 0x9A, 0x4E, 0xD9, 0xC8, 0x5D, 0x9B, 0x1D, 0x29, 0x45, 0x1D, 0xA5, 0x53, 0x81, 0xE5, 0x61, 0x1E, 0x65, 0x5F, 0xD6, 0x3A, 0xA9, 0x3D, 0x62, 0xB3, 0xD3, 0xD2, 0xC1, 0x4E, 0x51, 0xCA, 0x05, 0x98, 0x02, 0x2A, 0x80, 0x34, 0xC0, 0x57, 0xF2, 0x78, 0xE4, 0x81, 0x10, 0xC0, 0x07, 0xFC, 0x81, 0x6E, 0x20, 0xF3, 0x16, 0x4F, 0x4C, 0xA1, 0xCD, 0xEC, 0x4F, 0xEF, 0x14, 0x79, 0x02, 0x46, 0xAE, 0x9E, 0x8E, 0x59, 0x86, 0x26, 0x33, 0xAA, 0xF0, 0x52, 0x58, 0xFE, 0xD2, 0x3C, 0x75, 0x03, 0xA9, 0x1C, 0xED, 0xB2, 0x4E, 0x7B, 0x10, 0x9F, 0x1A, 0x39, 0x9F, 0x84, 0x22, 0x9F, 0xE5, 0xDD, 0x13, 0xC3, 0xCD, 0x67, 0x53, 0xF4, 0x09, 0xC2, 0x9D, 0xAE, 0x2D, 0x73, 0xE4, 0x75, 0x54, 0x81, 0xE3, 0x86, 0x42, 0x3F, 0xC8, 0xF4, 0x69, 0x39, 0x3D, 0x4A, 0x66, 0x60, 0xF6, 0x9E, 0x91, 0x3C, 0x19, 0x48, 0xB9, 0x81, 0xC5, 0xA2, 0xEA, 0x81, 0x18, 0xB0, 0x75, 0xB0, 0x06, 0x05, 0xB8, 0x52, 0xC0, 0x18, 0x50, 0x05, 0x24, 0x81, 0x95, 0xCC, 0x5C, 0x02, 0xC2, 0x80, 0x1C, 0x7F, 0xBC, 0x35, 0x6D, 0xE6, 0x68, 0x6A, 0xA4, 0x76, 0x55, 0xB7, 0xC7, 0xDE, 0x53, 0x88, 0x52, 0x1F, 0x64, 0x6F, 0x78, 0xD3, 0x32, 0x31, 0x57, 0xB2, 0xD8, 0xAC, 0x1D, 0x71, 0x16, 0x20, 0x98, 0x94, 0xB7, 0x79, 0x80, 0x9D, 0x69, 0x28, 0xA3, 0x11, 0xE9, 0x1B, 0x83, 0xA8, 0x16, 0xE0, 0x06, 0xAC, 0x3D, 0xFF, 0x2D, 0x81, 0x9C, 0x87, 0x9E, 0x40, 0x29, 0x1E, 0xAE, 0x75, 0x0F, 0xB0, 0x3D, 0xBE, 0xD2, 0x98, 0x41, 0x74, 0xD2, 0xF0, 0xE4, 0x76, 0x05, 0x2D, 0x7F, 0x64, 0xB0, 0x39, 0x61, 0x7B, 0xA0, 0x03, 0x26, 0x6F, 0x09, 0x90, 0xDC, 0xAE, 0x88, 0xC5, 0x87, 0x80, 0x3D, 0xED, 0x6F, 0x84, 0xAF, 0x9C, 0x71, 0x16, 0xA8, 0xD3, 0x37, 0xC3, 0xD5, 0x23, 0x1C, 0x5E, 0x08, 0x2B, 0x04, 0x7B, 0x03, 0x58, 0x8E, 0x95, 0x6C, 0x8B, 0xE3, 0x6F, 0x54, 0xB0, 0xD2, 0xBE, 0xE7, 0x26, 0x5B, 0x43, 0x0A, 0x6D, 0x16, 0xFE, 0xF3, 0x2E, 0x62, 0x81, 0x98, 0x16, 0x55, 0xC0, 0x0A, 0x3C, 0xD4, 0xC9, 0x87, 0x88, 0x0D, 0xA8, 0xDC, 0x58, 0xB3, 0x25, 0xE5, 0x0C, 0x5A, 0xFB, 0x30, 0x5B, 0xD9, 0x29, 0xF3, 0xF7, 0x73, 0x76, 0xEB, 0x7E, 0xE6, 0x9F, 0x01, 0x5B, 0x80, 0xA5, 0x83, 0x00, 0xF6, 0x02, 0x64, 0x03, 0x6C, 0x40, 0xB1, 0x0C, 0x50, 0x05, 0xA4, 0x81, 0x7D, 0x9A, 0xC9, 0x02, 0xD9, 0x40, 0x73, 0xFA, 0x16, 0x6D, 0x96, 0x70, 0x16, 0x76, 0xCE, 0xA1, 0x1F, 0xC7, 0x58, 0x13, 0x99, 0x70, 0xB9, 0xE0, 0x57, 0xB2, 0x3D, 0x89, 0x84, 0x0D, 0xB8, 0x70, 0x52, 0x32, 0x34, 0x75, 0x39, 0x6F, 0x31, 0xFA, 0x64, 0x9F, 0x81, 0xCD, 0x6F, 0x2D, 0x01, 0x38, 0x77, 0x86, 0x06, 0xD6, 0x9E, 0xD1, 0x1E, 0x40, 0x39, 0x5E, 0x39, 0x5B, 0xC2, 0xC2, 0xA7, 0x9A, 0x57, 0xA8, 0x98, 0x62, 0xB4, 0x56, 0x9C, 0xAB, 0x15, 0x9C, 0xF2, 0x0E, 0xEC, 0x41, 0xD9, 0x5D, 0xA7, 0x95, 0x0A, 0xB4, 0x8F, 0xED, 0x12, 0x10, 0x05, 0x82, 0x66, 0x1A, 0xC4, 0x02, 0x5C, 0x01, 0x35, 0x60, 0xE9, 0x63, 0x34, 0xA6, 0x56, 0x6E, 0x1A, 0x6D, 0xE2, 0x9D, 0x32, 0x1E, 0x6F, 0xA6, 0x4D, 0x74, 0x51, 0x7A, 0x0F, 0xA3, 0x41, 0x1A, 0xCD, 0xC5, 0xDC, 0x66, 0x65, 0xB1, 0xBF, 0x4D, 0xA7, 0xCE, 0xC9, 0xA5, 0x5B, 0x27, 0xF6, 0x35, 0xE6, 0xA1, 0x12, 0x6E, 0xDB, 0x2C, 0x53, 0xC9, 0x6C, 0x11, 0xC0, 0x1D, 0x0F, 0x3B, 0x00, 0x6B, 0x20, 0x14, 0xFF, 0x4D, 0x0B, 0xC8, 0x3D, 0xFF, 0x4D, 0xA7, 0xD1, 0x59, 0x4F, 0xFF, 0xA9, 0x71, 0xE5, 0xC2, 0x9E, 0x38, 0x97, 0x60, 0x8B, 0x9D, 0x55, 0xE0, 0xEC, 0xB4, 0x0D, 0xB8, 0x00, 0xE2, 0x03, 0x1D, 0x18, 0x60, 0x0B, 0x28, 0xC1, 0xCF, 0x99, 0x02, 0x19, 0x37, 0x62, 0x03, 0x6A, 0xC0, 0x2E, 0xC0, 0x66, 0x5E, 0x88, 0xD0, 0x66, 0xFD, 0xD7, 0x0B, 0x8D, 0xF2, 0xF2, 0x8B, 0x34, 0x2B, 0x5A, 0xB0, 0xCD, 0x0D, 0xA0, 0x55, 0x30, 0x63, 0xDD, 0xBE, 0xDB, 0x7E, 0x6A, 0xA0, 0xC2, 0x14, 0xB1, 0x95, 0x38, 0x65, 0xA0, 0x41, 0x87, 0x1A, 0x4B, 0x11, 0x7F, 0xA7, 0xA4, 0x4B, 0x2B, 0x3A, 0x1B, 0x60, 0x41, 0xA5, 0x21, 0x46, 0x62, 0xA7, 0xC7, 0x26, 0x10, 0x0B, 0x68, 0x67, 0x82, 0x1B, 0xE3, 0x71, 0x77, 0xF2, 0xBC, 0xF9, 0x5D, 0xEC, 0x6E, 0xFE, 0x24, 0x44, 0xBD, 0xED, 0x7C, 0x12, 0xD0, 0x00, 0x4C, 0x07, 0x01, 0xB8, 0x00, 0x25, 0xB7, 0x46, 0x45, 0x06, 0x10, 0x05, 0xD8, 0xBE, 0x8B, 0x9A, 0x33, 0x80, 0xD6, 0x79, 0x85, 0x0E, 0x35, 0xCC, 0x2B, 0x47, 0x9C, 0x29, 0xBE, 0x01, 0xE4, 0x7F, 0xB6, 0x4F, 0xD3, 0x80, 0xEA, 0xA9, 0xD4, 0xD7, 0x0F, 0xC2, 0xF2, 0xF6, 0x6E, 0x6A, 0x10, 0xBD, 0x1D, 0xB5, 0xF3, 0x27, 0x35, 0xB5, 0xF1, 0xF1, 0xAA, 0x25, 0xDC, 0xFE, 0xCB, 0x50, 0x53, 0xE0, 0xF2, 0x7C, 0x2B, 0x10, 0xCE, 0x16, 0xE5, 0xB7, 0x66, 0x58, 0xD8, 0x95, 0xF8, 0xAD, 0x75, 0x0B, 0x49, 0xE6, 0xE3, 0xB8, 0x71, 0xBD, 0x0B, 0x3F, 0x33, 0xB8, 0xC0, 0x02, 0xF6, 0x34, 0xE4, 0x0D, 0xFE, 0x59, 0x15, 0x88, 0x93, 0x5C, 0x98, 0xF4, 0xAD, 0xD3, 0xED, 0x79, 0xC9, 0x73, 0x35, 0x33, 0x9F, 0x02, 0x68, 0x3B, 0x56, 0xDB, 0x7F, 0x39, 0x65, 0x13, 0xAE, 0xA7, 0xE4, 0xD8, 0x96, 0x9F, 0xF3, 0x0A, 0x3A, 0x9E, 0xAD, 0x19, 0x64, 0x74, 0xC8, 0xD6, 0x29, 0xC2, 0x20, 0xAF, 0x92, 0x63, 0xA7, 0x93, 0x26, 0xC7, 0x6A, 0x34, 0x57, 0x09, 0x40, 0xDF, 0x59, 0x8E, 0xD5, 0x7A, 0x01, 0x92, 0x80, 0x6E, 0x80, 0x25, 0x4A, 0xC7, 0x4F, 0x41, 0x55, 0xFD, 0x5F, 0xE2, 0x56, 0x1E, 0x57, 0xB9, 0xD2, 0x5C, 0x83, 0xD0, 0x79, 0x98, 0x40, 0xD1, 0xBE, 0x03, 0x59, 0x83, 0x04, 0xF4, 0xE9, 0x06, 0x2A, 0x0A, 0x78, 0x0D, 0x16, 0x20, 0xC1, 0xFA, 0x5A, 0xBE, 0x09, 0xD4, 0x55, 0x6D, 0x0B, 0xAB, 0xC9, 0x5F, 0x17, 0xBE, 0x5F, 0x2A, 0xCE, 0x13, 0x61, 0xE7, 0xAA, 0xBE, 0x7B, 0xA2, 0x0E, 0x11, 0xF0, 0x30, 0x62, 0x6B, 0xDD, 0x1E, 0x08, 0x14, 0xD8, 0xEB, 0x86, 0x3C, 0xA9, 0xAC, 0xC1, 0x2C, 0x89, 0xBB, 0x4B, 0xB5, 0x6D, 0x80, 0xDF, 0xC2, 0x5E, 0x31, 0x50, 0x05, 0xF2, 0x28, 0x73, 0xDD, 0x7A, 0xCD, 0xEE, 0x77, 0x39, 0x72, 0xF5, 0x6F, 0x16, 0xCA, 0x81, 0xAE, 0x41, 0x02, 0x59, 0x40, 0x2B, 0x50, 0x31, 0xB0, 0x81, 0x0E, 0xF2, 0x9E, 0xD2, 0xB9, 0xEF, 0x60, 0x71, 0x3B, 0x10, 0x0D, 0xA8, 0x02, 0x2B, 0x00, 0x31, 0xA0, 0xE3, 0x58, 0x4D, 0xFF, 0xAA, 0xA1, 0xD0, 0x91, 0x8E, 0x3A, 0xA9, 0xC0, 0xDF, 0x67, 0x32, 0x02, 0x0C, 0x65, 0xD3, 0x95, 0x9F, 0xD5, 0xAC, 0x13, 0x3E, 0xCD, 0xD0, 0x7B, 0x5D, 0x93, 0x27, 0x50, 0x20, 0x4A, 0x77, 0xC7, 0xAD, 0xCC, 0x68, 0x03, 0x6E, 0x34, 0xE6, 0xB7, 0x1E, 0x8B, 0x15, 0x90, 0xFC, 0x6F, 0x54, 0x45, 0xDB, 0xB7, 0x5A, 0x1D, 0x3E, 0xD9, 0x71, 0xEA, 0xFB, 0x63, 0x0B, 0x5F, 0xB7, 0x96, 0x68, 0xCC, 0x9B, 0x5B, 0x00, 0x29, 0x40, 0x13, 0x30, 0x19, 0x14, 0x40, 0xC5, 0x57, 0xDD, 0x40, 0x38, 0xE0, 0x7C, 0xF8, 0x14, 0x8D, 0x27, 0x3F, 0xAD, 0xF3, 0x0A, 0xAD, 0x06, 0x39, 0xA2, 0xA5, 0xFE, 0xE7, 0x0D, 0x11, 0x44, 0xFB, 0x92, 0x05, 0x63, 0x24, 0x5A, 0x1D, 0x05, 0xB1, 0x2E, 0xB8, 0x23, 0x55, 0x4E, 0xAC, 0xC4, 0xE9, 0xB5, 0x7D, 0xBA, 0x26, 0xD1, 0xBF, 0x4C, 0x27, 0x27, 0xB5, 0xB9, 0x56, 0x01, 0xB5, 0x01, 0xE3, 0x44, 0x5D, 0x27, 0x70, 0x7E, 0x95, 0x35, 0xD3, 0x27, 0x6B, 0x9C, 0xD9, 0x72, 0xEB, 0xA1, 0x64, 0x63, 0x81, 0x61, 0x87, 0xA3, 0x4B, 0xFD, 0x86, 0xEA, 0x87, 0x76, 0x49, 0x1C, 0x5D, 0xA2, 0x9A, 0x1E, 0x40, 0xAE, 0x41, 0x00, 0x65, 0xF7, 0xB4, 0x2D, 0xBB, 0x27, 0xEA, 0x3E, 0x59, 0x69, 0x80, 0xE9, 0x23, 0xA5, 0x78, 0x55, 0xD5, 0xC0, 0x6A, 0xFE, 0x85, 0x57, 0xBA, 0x58, 0x6B, 0xB6, 0xBF, 0xB8, 0x7B, 0x6D, 0x9B, 0x66, 0xE0, 0xF4, 0xC2, 0x2B, 0x9C, 0xEA, 0x52, 0x10, 0x87, 0xC8, 0x7D, 0xCB, 0xF9, 0xF5, 0x95, 0xB6, 0xAC, 0xD7, 0x2F, 0x7C, 0x75, 0x95, 0xDF, 0x75, 0x2F, 0x14, 0x96, 0xB7, 0xFA, 0x61, 0xC6, 0x23, 0x37, 0x1D, 0xF7, 0x7A, 0xBC, 0x9A, 0x21, 0x8D, 0x7B, 0xE4, 0xC9, 0xA9, 0x79, 0x64, 0x68, 0xED, 0x56, 0x3F, 0x54, 0xB9, 0x87, 0x47, 0x39, 0xD0, 0x3A, 0x48, 0xEE, 0x8C, 0x80, 0x0E, 0x6A, 0xCC, 0xBC, 0x6B, 0xB0, 0xEE, 0xBA, 0x0D, 0x17, 0x40, 0x1A, 0x30, 0x9D, 0x57, 0xE2, 0x58, 0x2D, 0x3E, 0x73, 0x7D, 0x96, 0xB1, 0xAF, 0xDA, 0x36, 0x90, 0x3C, 0xE0, 0x0D, 0x0F, 0xA2, 0xED, 0x29, 0xA7, 0xA9, 0xE9, 0x3C, 0xE1, 0xB3, 0x44, 0xEB, 0x3D, 0xD6, 0xFA, 0x91, 0xED, 0x68, 0x96, 0xBC, 0xB1, 0x26, 0x70, 0x3D, 0x35, 0xF7, 0x2C, 0x37, 0x0F, 0xA6, 0xCB, 0xF8, 0xAD, 0xBD, 0xB7, 0x0C, 0xC8, 0xAB, 0xF8, 0xD0, 0x4E, 0x3F, 0xD4, 0xC5, 0xA2, 0x3A, 0xE6, 0x4D, 0xD9, 0x95, 0xC6, 0xBB, 0x07, 0xDE, 0x47, 0x24, 0xFB, 0x09, 0x03, 0x28, 0x50, 0x01, 0x74, 0x33, 0x09, 0x1F, 0xF0, 0x53, 0x36, 0x02, 0x58, 0x00, 0xFA, 0x84, 0xB7, 0x6B, 0x01, 0x1E, 0x77, 0xA4, 0xC8, 0x9C, 0x56, 0x4B, 0xCC, 0x49, 0x4D, 0x04, 0x54, 0x5A, 0xB1, 0x67, 0xE7, 0x46, 0x00, 0x3F, 0xF5, 0x43, 0xED, 0xC0, 0x69, 0x7F, 0xEB, 0xDC, 0xB0, 0x8C, 0x85, 0xD9, 0xB7, 0xD3, 0xDB, 0x7E, 0x3D, 0x15, 0x05, 0x91, 0x3C, 0x7A, 0x25, 0xF0, 0x37, 0x30, 0x40, 0x7D, 0x0E, 0xC0, 0x75, 0xD7, 0xA9, 0x08, 0x13, 0xAD, 0xE6, 0xAA, 0xD4, 0x1B, 0x60, 0x16, 0xC2, 0xDD, 0x85, 0x81, 0xC7, 0xFD, 0x75, 0x5C, 0x38, 0x92, 0x77, 0x03, 0x1F, 0xA6, 0x7A, 0xB0, 0xC2, 0xAD, 0x0D, 0x6F, 0x06, 0x6B, 0xB5, 0x0C, 0x90, 0x0D, 0x68, 0x03, 0xA7, 0x19, 0x87, 0x01, 0xD1, 0x03, 0x01, 0x2C, 0x9E, 0x56, 0x4F, 0x39, 0x9F, 0x36, 0x50, 0x41, 0xA3, 0x15, 0xCE, 0xEB, 0x7B, 0xE3, 0xCA, 0xF2, 0x19, 0x46, 0x4E, 0x5A, 0xA3, 0x09, 0x5D, 0x86, 0x3A, 0x8E, 0xD6, 0xC0, 0x15, 0x59, 0xA8, 0x49, 0x37, 0x56, 0xAB, 0x27, 0x6D, 0xD9, 0x82, 0xAE, 0x47, 0xFF, 0x5D, 0xDC, 0xB0, 0x06, 0x01, 0x01, 0x23, 0x14, 0xA3, 0x51, 0x03, 0x29, 0xC0, 0xF4, 0x77, 0x19, 0xF4, 0xD3, 0x9F, 0x64, 0xB3, 0x37, 0x4C, 0xDD, 0x3D, 0x5A, 0xE8, 0xA7, 0x56, 0xC6, 0x3B, 0x88, 0x62, 0xF2, 0x3D, 0x70, 0xDA, 0x68, 0x3A, 0x60, 0x0B, 0x70, 0x01, 0x82, 0x45, 0xB3, 0x0E, 0xC4, 0x87, 0x3A, 0x9F, 0xBA, 0x80, 0x7C, 0xCA, 0xE1, 0x77, 0x01, 0xCA, 0x62, 0xFC, 0xA4, 0xD5, 0xFA, 0x3B, 0x6A, 0x78, 0xC8, 0x38, 0x63, 0x04, 0x21, 0x0D, 0xAD, 0xF9, 0xF1, 0xC2, 0x98, 0x8E, 0xFE, 0x50, 0xDE, 0xA3, 0xA5, 0x28, 0x54, 0xED, 0xB8, 0xEB, 0xA5, 0xE4, 0xDA, 0x0A, 0xA7, 0x05, 0x0F, 0x06, 0xE9, 0xD3, 0x12, 0xC9, 0xE7, 0xA1, 0xE9, 0xDD, 0x21, 0x77, 0x37, 0x7F, 0xE1, 0xA7, 0x2A, 0xD3, 0x7F, 0x6E, 0x5F, 0x3F, 0xDA, 0x53, 0xCE, 0x7B, 0xC6, 0xE6, 0x5C, 0xC4, 0x0E, 0x41, 0x21, 0x41, 0xBB, 0xB2, 0xBD, 0xF6, 0xD1, 0xBA, 0x5A, 0x09, 0x68, 0x00, 0xBE, 0x80, 0x33, 0xE9, 0x37, 0x10, 0x47, 0x00, 0xEB, 0xA9, 0x67, 0xEF, 0x27, 0x83, 0x08, 0xB8, 0x8A, 0x47, 0x60, 0xB5, 0x8D, 0xAB, 0x41, 0xEF, 0x0D, 0x4F, 0x56, 0x28, 0xB2, 0x76, 0x4A, 0x26, 0x4C, 0xF3, 0x4D, 0xD7, 0x5E, 0xBB, 0xB0, 0x9E, 0xAC, 0xC2, 0xF2, 0x80, 0xF2, 0xDA, 0x3E, 0xB5, 0xB3, 0xF1, 0x6E, 0xA1, 0xEB, 0x2A, 0xC7, 0xB4, 0x13, 0xB8, 0x88, 0x02, 0xAC, 0xEE, 0x23, 0xEF, 0xD2, 0xB1, 0x85, 0x01, 0x6D, 0xBF, 0xA0, 0x46, 0xD0, 0xCD, 0x7D, 0xFE, 0x1B, 0xA3, 0x94, 0xDE, 0x3C, 0xCD, 0x5F, 0x67, 0xDD, 0xB4, 0xBB, 0xC4, 0xEE, 0x38, 0xAA, 0x1A, 0xB0, 0x0D, 0xB8, 0x03, 0x21, 0x40, 0xD2, 0x05, 0xBE, 0x80, 0xA4, 0xB5, 0xB7, 0x03, 0x4F, 0xAA, 0xB2, 0xC6, 0xED, 0x3A, 0x97, 0x13, 0x7E, 0x30, 0x5A, 0x6D, 0xE3, 0xBE, 0x5B, 0x70, 0x07, 0xD1, 0xF6, 0xD5, 0x98, 0x8C, 0xBA, 0x73, 0x74, 0x23, 0x64, 0xAA, 0x13, 0x8D, 0x4E, 0xB3, 0x73, 0xA8, 0x45, 0xEE, 0xEB, 0x2D, 0x53, 0xEA, 0x5C, 0xD6, 0xD6, 0xFE, 0xF9, 0xF3, 0xE4, 0x34, 0xA5, 0xD1, 0x59, 0xCF, 0xC4, 0xD8, 0xBB, 0x65, 0x16, 0x32, 0x07, 0xA2, 0xF0, 0x70, 0x1B, 0x70, 0x42, 0x81, 0x3A, 0xB1, 0xBC, 0xA2, 0xAB, 0xE1, 0x76, 0x74, 0xAC, 0x66, 0x3E, 0xD4, 0x6F, 0x4C, 0xCB, 0xD3, 0x42, 0xDA, 0x4F, 0xBE, 0x6A, 0x4F, 0x5A, 0xF9, 0x76, 0x40, 0x0B, 0xA8, 0xF1, 0xD2, 0x69, 0x01, 0xB9, 0x81, 0x68, 0xC0, 0x15, 0x90, 0x00, 0x56, 0x03, 0xE2, 0x40, 0x3B, 0x8D, 0x26, 0x10, 0x3E, 0x54, 0x99, 0x6C, 0xD9, 0x1A, 0x21, 0xCB, 0xC6, 0xCC, 0xDC, 0x85, 0x19, 0x65, 0x86, 0x35, 0x72, 0xC1, 0x49, 0x34, 0xFD, 0xC8, 0x35, 0xD9, 0x8F, 0x05, 0xF0, 0x7E, 0xB6, 0x82, 0x58, 0x30, 0x4F, 0xD5, 0xEC, 0x01, 0x0D, 0xD8, 0x78, 0x7E, 0xC4, 0xE6, 0xBF, 0xD1, 0x31, 0x9A, 0x00, 0x7F, 0x40, 0x02, 0x48, 0xFA, 0x5C, 0xD9, 0x5C, 0x86, 0x96, 0xC8, 0x9F, 0x30, 0x7D, 0x9D, 0x35, 0xAA, 0x9B, 0x60, 0x20, 0xF2, 0x6E, 0x98, 0x1D, 0x83, 0xB6, 0x27, 0xE9, 0xCC, 0x80, 0xE0, 0xFF, 0x6C, 0x90, 0x3D, 0x58, 0x80, 0x39, 0xB0, 0xE4, 0x2E, 0x34, 0xE7, 0x12, 0x93, 0x67, 0xA0, 0x29, 0xD6, 0x1D, 0x88, 0x6A, 0xEA, 0xAE, 0x42, 0x93, 0xD1, 0xD8, 0x93, 0x76, 0xB5, 0x27, 0x8F, 0xB1, 0xE1, 0x2A, 0xF2, 0x80, 0xF3, 0x64, 0xEB, 0xAF, 0x57, 0xE2, 0x76, 0x80, 0x35, 0x77, 0x2A, 0xEB, 0x24, 0xBA, 0x23, 0xE5, 0x4D, 0xE0, 0xDD, 0x71, 0x03, 0x7A, 0x03, 0xDB, 0xA7, 0x0F, 0xD0, 0xC4, 0x04, 0xCC, 0x81, 0xDD, 0x80, 0x05, 0xE0, 0x8A, 0x40, 0x41, 0xD4, 0xB8, 0x73, 0xC7, 0x97, 0x59, 0x39, 0xFE, 0x2A, 0x36, 0x54, 0x5A, 0x77, 0xD1, 0x46, 0x2F, 0xA0, 0x0C, 0x48, 0x07, 0xA2, 0xEF, 0x4F, 0x59, 0x40, 0x4F, 0x08, 0x43, 0x1C, 0x88, 0x06, 0xDA, 0x06, 0x02, 0x94, 0x01, 0x11, 0x83, 0x05, 0xA4, 0x8D, 0xA7, 0x29, 0x69, 0x33, 0x9B, 0x61, 0xDA, 0xD3, 0x46, 0x5A, 0x2E, 0xF9, 0x26, 0x91, 0xC2, 0x3C, 0x8A, 0xC4, 0x9F, 0x3F, 0x61, 0x41, 0x53, 0x9D, 0x96, 0x3B, 0xB0, 0xD9, 0x15, 0x28, 0x60, 0x9D, 0x22, 0x95, 0x96, 0x6D, 0x0A, 0x65, 0xCD, 0xC6, 0x74, 0x3E, 0x6E, 0x6E, 0xAC, 0xA4, 0xF0, 0x8F, 0x05, 0x5E, 0xF1, 0x1A, 0xDF, 0x37, 0x63, 0x2C, 0x13, 0x0C, 0xD0, 0x89, 0x60, 0x71, 0x98, 0x32, 0x2E, 0xD5, 0x8E, 0xC1, 0xC7, 0x53, 0x49, 0xCF, 0x04, 0xAA, 0x04, 0xF2, 0xC4, 0xAC, 0x80, 0xDE, 0x0C, 0xD3, 0x03, 0x96, 0x40, 0x2C, 0x20, 0x93, 0x43, 0x18, 0x88, 0x04, 0x3A, 0x6E, 0x94, 0x02, 0x31, 0x70, 0x07, 0x52, 0x26, 0xA4, 0x10, 0xB4, 0x99, 0xE3, 0xD6, 0x7E, 0x72, 0x23, 0x71, 0x79, 0x37, 0x65, 0xB4, 0x73, 0x4F, 0xD3, 0x24, 0x43, 0x37, 0x4D, 0xD5, 0xB9, 0x8D, 0x22, 0x51, 0x4D, 0xDE, 0x96, 0x2C, 0x47, 0xEE, 0x6C, 0x33, 0xA7, 0xE7, 0x3E, 0x6B, 0xB3, 0xA8, 0xC1, 0x8F, 0xD4, 0xDC, 0x9D, 0xD5, 0x98, 0x83, 0x48, 0xA0, 0x6C, 0x00, 0xDB, 0x1F, 0xC5, 0x89, 0x5A, 0x80, 0x19, 0xA0, 0x05, 0x48, 0x0C, 0x1A, 0xC8, 0xFD, 0x74, 0xFA, 0xF4, 0x41, 0x01, 0xBD, 0x07, 0x72, 0xAB, 0x6C, 0xCA, 0xA0, 0xEC, 0x5F, 0x7D, 0xB5, 0x9F, 0x5A, 0xDA, 0x5D, 0x80, 0xEA, 0xB9, 0xDA, 0xD2, 0x6A, 0x71, 0xCC, 0x55, 0x09, 0xDB, 0xE7, 0x77, 0xC8, 0xD8, 0xA3, 0xCE, 0xC3, 0xA6, 0x49, 0x8D, 0xEF, 0xE0, 0x85, 0xDB, 0x4A, 0x40, 0xD8, 0xD5, 0xDE, 0x5B, 0xFB, 0xC9, 0x55, 0x64, 0x02, 0xA3, 0x8D, 0xD5, 0xF2, 0x29, 0x28, 0x91, 0xFB, 0x2A, 0x14, 0xF6, 0x78, 0x0E, 0x69, 0xD1, 0xE7, 0xDE, 0xEC, 0xEB, 0x2E, 0x8D, 0x4D, 0x05, 0x74, 0xDD, 0x1A, 0x1E, 0x31, 0xA8, 0xBC, 0x2B, 0x64, 0x9D, 0xB0, 0x07, 0x3A, 0x78, 0x5A, 0x86, 0xA8, 0x02, 0x11, 0x80, 0x0F, 0x74, 0xFF, 0x2B, 0xD3, 0xDB, 0x9E, 0x4C, 0xEF, 0xBD, 0xF3, 0x58, 0xAD, 0xBF, 0x2C, 0xE7, 0xFC, 0xEB, 0x6F, 0xAD, 0xD0, 0x49, 0xE3, 0xCD, 0xEF, 0x77, 0x11, 0x2D, 0xA4, 0x6B, 0xE6, 0xD8, 0x30, 0x37, 0x5B, 0xB2, 0xBC, 0xC5, 0xC6, 0x77, 0x1F, 0x1E, 0x4F, 0xA0, 0x1C, 0x48, 0x03, 0xCC, 0xFE, 0x55, 0x01, 0xDD, 0x77, 0x2D, 0x62, 0x1C, 0x51, 0xBA, 0x3B, 0xDD, 0x9D, 0xC1, 0xC2, 0x0A, 0x20, 0x0A, 0x30, 0x05, 0xB4, 0x81, 0x63, 0xD1, 0x0D, 0x78, 0xDF, 0x78, 0x11, 0x0A, 0x54, 0x3D, 0x7D, 0x70, 0x06, 0xA1, 0x80, 0x16, 0xB0, 0xF8, 0xE6, 0x65, 0x43, 0x5E, 0x74, 0x61, 0xB5, 0x82, 0xB9, 0x6C, 0xDF, 0x43, 0xCE, 0x7A, 0x3A, 0x3B, 0x0B, 0xFE, 0x2E, 0x7B, 0xE3, 0x0F, 0x29, 0xF2, 0xFD, 0xCF, 0xDA, 0x61, 0xAD, 0xF5, 0x8A, 0x37, 0x51, 0xCD, 0xE5, 0xF8, 0x68, 0x14, 0xF0, 0x7C, 0xA4, 0x81, 0x9F, 0xC9, 0x28, 0x71, 0x9B, 0x6B, 0x0D, 0xAC, 0x80, 0x93, 0x19, 0x3A, 0x26, 0x29, 0x01, 0xAC, 0x1F, 0x73, 0xC9, 0x20, 0xEF, 0xB1, 0x96, 0x75, 0x8F, 0x20, 0x5F, 0x83, 0x02, 0x62, 0x0F, 0x12, 0xE8, 0xD7, 0x0F, 0x5E, 0x40, 0x0E, 0x5C, 0xEE, 0xDE, 0xFA, 0xFC, 0x6F, 0xCB, 0x80, 0xD4, 0x63, 0xB5, 0xFE, 0xCB, 0xC9, 0x8A, 0x4D, 0x45, 0xD8, 0xC0, 0xBF, 0xF9, 0xD6, 0xD0, 0xE4, 0x0A, 0xC7, 0xC1, 0xB0, 0x04, 0x59, 0xC7, 0xBA, 0xE1, 0x02, 0x56, 0xB9, 0x44, 0xE9, 0x72, 0x3D, 0xC9, 0xDE, 0xBE, 0x4E, 0xF4, 0xF8, 0x4E, 0x0F, 0xEB, 0x0D, 0x88, 0xDD, 0xED, 0x1F, 0xF6, 0xC9, 0x0C, 0x05, 0xFC, 0x49, 0x5E, 0xF1, 0x40, 0x48, 0xE1, 0x4A, 0x7E, 0x8E, 0xD3, 0x0E, 0xB9, 0xF7, 0x9D, 0xFF, 0x48, 0x17, 0x7F, 0xC4, 0xBC, 0xB9, 0x8F, 0x04, 0x08, 0x93, 0x65, 0x80, 0x7E, 0xDA, 0x39, 0xAA, 0x03, 0x59, 0x77, 0x7B, 0xB0, 0x2E, 0xA0, 0x02, 0x70, 0x07, 0x56, 0xDC, 0x15, 0x54, 0x45, 0xE1, 0x2C, 0xEE, 0xA0, 0xB2, 0xBE, 0x62, 0x29, 0x89, 0xFA, 0x1C, 0xE0, 0xE5, 0xF9, 0xC5, 0xC3, 0x4D, 0xF6, 0x1C, 0x6F, 0xC7, 0x35, 0x54, 0x8E, 0xA2, 0xE8, 0x98, 0x5F, 0x3E, 0x9D, 0xBE, 0xDB, 0xA7, 0xAF, 0xF6, 0x35, 0xC5, 0xF2, 0xEC, 0xA8, 0xEE, 0x40, 0x6C, 0x80, 0x15, 0x4A, 0x74, 0x41, 0x9F, 0x9A, 0xB8, 0x1C, 0xF8, 0xAD, 0xB7, 0xED, 0xFD, 0xA4, 0x8B, 0x3E, 0xE5, 0xC5, 0xAD, 0x80, 0xF4, 0x3D, 0x46, 0x73, 0x8D, 0x29, 0xA9, 0x70, 0x6A, 0x40, 0x08, 0x50, 0x01, 0x74, 0xDD, 0xDD, 0x57, 0x8C, 0x45, 0x53, 0x1B, 0xB0, 0x05, 0x48, 0x01, 0xCB, 0x1E, 0xE1, 0xCF, 0x04, 0xAC, 0x4F, 0xAF, 0x58, 0x5A, 0x6D, 0xFF, 0x45, 0xE2, 0x68, 0x12, 0x9F, 0x99, 0xD1, 0x57, 0x3B, 0x36, 0x2E, 0xA0, 0x9A, 0x09, 0xF7, 0x96, 0x2B, 0xF4, 0xDF, 0x76, 0x8D, 0x0E, 0x61, 0x32, 0xBA, 0x72, 0xC7, 0xA6, 0x28, 0x56, 0x05, 0x20, 0xFD, 0xE9, 0x6E, 0x79, 0x4B, 0xE9, 0xCF, 0x76, 0xE0, 0xC8, 0x1A, 0xEE, 0xAB, 0x09, 0x41, 0x1F, 0x69, 0xD3, 0x41, 0x0B, 0xB0, 0x93, 0x46, 0xE7, 0x57, 0xBB, 0x92, 0x8A, 0x79, 0xE1, 0x2D, 0x1A, 0x68, 0xF1, 0x95, 0x4B, 0x3D, 0x72, 0xCD, 0x0D, 0x07, 0x8B, 0xC7, 0x5D, 0xC1, 0x20, 0x00, 0x53, 0xB8, 0xAC, 0x81, 0xAA, 0xC1, 0xBE, 0x07, 0xE0, 0xE6, 0x9B, 0x72, 0x77, 0x5F, 0x2D, 0xA1, 0xD5, 0x64, 0x2A, 0x0A, 0xF4, 0x73, 0xAF, 0x95, 0x6F, 0xC4, 0x75, 0xDB, 0x70, 0x94, 0xEE, 0x80, 0x09, 0xD2, 0x50, 0x94, 0x26, 0x36, 0x72, 0x63, 0xFB, 0x6E, 0x35, 0xB5, 0x69, 0x35, 0x79, 0xB2, 0xAE, 0xF6, 0x95, 0x77, 0x1C, 0xE3, 0xA8, 0xF2, 0x53, 0x42, 0xA5, 0x45, 0x99, 0xA9, 0x79, 0x73, 0xDD, 0x21, 0xAA, 0x5A, 0x03, 0xB9, 0x7A, 0x61, 0x30, 0xC6, 0xB4, 0x85, 0xDE, 0xD7, 0x5B, 0x59, 0xAC, 0xEC, 0x6E, 0x74, 0x78, 0xD6, 0x07, 0xA2, 0xF4, 0x31, 0xD7, 0x20, 0x6C, 0x8C, 0xE0, 0x77, 0x19, 0xD0, 0x5E, 0x00, 0x2D, 0x93, 0x01, 0x68, 0x02, 0x6B, 0x20, 0x47, 0x57, 0x82, 0x56, 0xD3, 0xBF, 0xFC, 0x6E, 0x64, 0xF9, 0x35, 0x25, 0x8F, 0xA5, 0xC8, 0xDD, 0x51, 0x1F, 0x65, 0x47, 0x47, 0x0E, 0xB4, 0x25, 0x3A, 0xC1, 0xEC, 0x44, 0x7E, 0xFF, 0x3E, 0xB5, 0x65, 0xAF, 0x0F, 0x97, 0x4B, 0xE8, 0xF1, 0xBE, 0xDE, 0x35, 0x96, 0x47, 0x05, 0x21, 0x66, 0x1C, 0x32, 0xBD, 0x8C, 0xE9, 0xA7, 0xC0, 0xAD, 0xEF, 0x4D, 0x09, 0x4D, 0x07, 0x7E, 0xC2, 0x7E, 0xBD, 0x01, 0xE3, 0x29, 0xEC, 0xC9, 0xF7, 0x8F, 0xF5, 0x4B, 0xD0, 0x8F, 0xAB, 0x57, 0xD4, 0x15, 0x94, 0xB2, 0x0D, 0xB8, 0xDE, 0x4D, 0x7D, 0xCC, 0x80, 0xEC, 0xC1, 0x06, 0xAC, 0x80, 0xBD, 0xE7, 0xCD, 0xC6, 0xA7, 0x75, 0x85, 0x6D, 0x61, 0x35, 0x9B, 0xA2, 0x24, 0xFD, 0x33, 0x3F, 0xA1, 0x7D, 0x49, 0x8E, 0xD8, 0xE9, 0x10, 0xDA, 0x81, 0x5B, 0xDF, 0x52, 0x7C, 0x1A, 0x2B, 0xBD, 0x9D, 0xA6, 0x34, 0xCE, 0xF2, 0xC4, 0xB4, 0x91, 0x5F, 0x23, 0x91, 0x38, 0x35, 0xC5, 0xCB, 0x7F, 0xD9, 0x4D, 0x72, 0xE4, 0xA5, 0x3C, 0x80, 0xBD, 0x01, 0x0D, 0x20, 0x74, 0x7C, 0x49, 0xE3, 0x36, 0x62, 0x17, 0x8C, 0x65, 0x3F, 0xC7, 0xC9, 0x78, 0xE0, 0xA8, 0xC8, 0x7D, 0x52, 0x3D, 0xEB, 0x78, 0x1C, 0x17, 0xBB, 0xAB, 0xD2, 0x81, 0xC7, 0x8C, 0x73, 0x05, 0x58, 0xED, 0x2C, 0xEB, 0xAE, 0x76, 0x16, 0xC2, 0x00, 0xB6, 0xB9, 0x8E, 0x04, 0x4C, 0x80, 0x10, 0x16, 0xAB, 0xD2, 0x68, 0xFE, 0xB9, 0x86, 0x74, 0xED, 0x2F, 0xC8, 0xB2, 0xC3, 0x31, 0x41, 0xD3, 0xA7, 0x43, 0x06, 0x04, 0x28, 0x58, 0x71, 0xB6, 0x18, 0x64, 0xD1, 0x7D, 0xD5, 0x15, 0x7C, 0xB8, 0xB4, 0xD1, 0x97, 0x31, 0x2D, 0xB2, 0x6E, 0x09, 0x59, 0xE1, 0x04, 0x5D, 0xB7, 0x28, 0xE3, 0xE6, 0xC0, 0xA7, 0x5B, 0x9A, 0x9F, 0x16, 0x70, 0xF4, 0xE3, 0xF6, 0xD5, 0xC2, 0xCB, 0xF4, 0x8E, 0xD1, 0x2F, 0x0E, 0x04, 0x0E, 0x6D, 0xAA, 0xC8, 0x9C, 0x42, 0xBB, 0xC5, 0x2A, 0xCA, 0xBB, 0xA9, 0x8A, 0x17, 0x50, 0x72, 0xFB, 0x7E, 0x93, 0x17, 0x7E, 0x7B, 0xDA, 0xEE, 0x2F, 0x20, 0x0C, 0xB0, 0x0D, 0x9C, 0x7C, 0xBF, 0xA0, 0xD5, 0xE2, 0xCF, 0x15, 0xAD, 0x7D, 0xFC, 0x8B, 0x5D, 0xC7, 0xA4, 0xD9, 0xF6, 0x08, 0xBA, 0xEE, 0xF9, 0x43, 0x36, 0x5C, 0x5F, 0x2B, 0xE6, 0xE7, 0x9C, 0x3D, 0x2D, 0x2F, 0x3D, 0x00, 0xED, 0x5F, 0xC1, 0x07, 0x46, 0x25, 0x73, 0xDC, 0x81, 0xBA, 0x72, 0x93, 0xE5, 0x78, 0x1F, 0x7A, 0x7C, 0x11, 0x2A, 0x77, 0x7A, 0x63, 0x09, 0xA0, 0x4C, 0xC9, 0xA6, 0xCB, 0x8D, 0xC7, 0x81, 0xBA, 0x4B, 0xA8, 0xB9, 0x4F, 0xDC, 0x4D, 0xDB, 0xF5, 0x48, 0x1C, 0xC6, 0x98, 0xA9, 0x99, 0xC2, 0x3A, 0x68, 0xBB, 0x33, 0xA9, 0x82, 0xFF, 0xFA, 0x02, 0x72, 0x70, 0x1E, 0x3A, 0x5E, 0x69, 0x05, 0x62, 0x03, 0xEC, 0xF5, 0xED, 0x49, 0xA3, 0xE5, 0xB4, 0x59, 0xC7, 0x31, 0x2D, 0x5B, 0x27, 0xAA, 0xEE, 0xA3, 0xA8, 0x84, 0x8D, 0x74, 0x1B, 0x2C, 0xA9, 0xEA, 0x73, 0xF0, 0x35, 0xAC, 0xFD, 0xB7, 0x5B, 0xED, 0x6E, 0xF3, 0x09, 0xA3, 0xF9, 0x18, 0x6D, 0x03, 0xCE, 0x86, 0xCC, 0x63, 0xB4, 0x14, 0x18, 0x8D, 0xBF, 0x85, 0x7E, 0xA8, 0xC1, 0x24, 0xA3, 0x9D, 0x46, 0xFD, 0x4E, 0x4D, 0xD0, 0xB1, 0xAB, 0x9E, 0x98, 0xFC, 0x19, 0x54, 0x76, 0x57, 0xF4, 0x31, 0x34, 0x13, 0x33, 0x70, 0x94, 0x55, 0xDD, 0xFB, 0x8E, 0x16, 0x98, 0x03, 0xF9, 0x74, 0xB0, 0xC9, 0xF5, 0x64, 0x69, 0x2D, 0x3C, 0x2C, 0x03, 0xDC, 0x01, 0x4D, 0x80, 0xBD, 0xA5, 0xF7, 0x31, 0x5A, 0xE1, 0x50, 0x1B, 0x1B, 0x7B, 0xC0, 0x31, 0x76, 0x5C, 0x42, 0xF9, 0xA5, 0xF2, 0x21, 0xB5, 0xF0, 0x17, 0x90, 0xB8, 0xFD, 0xDE, 0x7D, 0xA9, 0xF0, 0x5F, 0xED, 0xC8, 0xB9, 0x80, 0x51, 0x37, 0xA1, 0x81, 0x7D, 0x95, 0x68, 0xB0, 0xB7, 0x0F, 0x97, 0x33, 0x6C, 0x2D, 0x40, 0x0D, 0xFC, 0x57, 0x7F, 0x91, 0x03, 0x9F, 0x87, 0xD8, 0x12, 0xAE, 0x0E, 0x4A, 0x2E, 0xF3, 0xE9, 0x12, 0xE7, 0xF1, 0x53, 0x27, 0x50, 0xF9, 0x8A, 0xE0, 0x02, 0x95, 0x63, 0xD8, 0x05, 0xB4, 0x71, 0xBC, 0x03, 0x92, 0xC0, 0xE2, 0x18, 0x4B, 0xC0, 0xAE, 0x11, 0xD7, 0x30, 0x09, 0xAC, 0xD6, 0x53, 0x1C, 0xB1, 0xA1, 0x78, 0x95, 0x53, 0x8F, 0xA5, 0x3A, 0x29, 0x83, 0x06, 0xFB, 0x6A, 0x60, 0x70, 0xC4, 0x86, 0xE7, 0xC8, 0x95, 0x9E, 0x86, 0xBB, 0x67, 0x92, 0xFC, 0x4E, 0xE6, 0x22, 0x27, 0xD7, 0xCC, 0xC6, 0xBF, 0xE3, 0x74, 0x35, 0xD2, 0x79, 0xA3, 0xE3, 0x19, 0xCD, 0x5F, 0xD1, 0x80, 0x1D, 0x8D, 0xE1, 0x2D, 0x63, 0xD0, 0xB1, 0x5D, 0xAF, 0x7B, 0x0A, 0x0B, 0xE7, 0x2E, 0x3D, 0xE3, 0x8F, 0xCC, 0x28, 0xD5, 0x0B, 0xCD, 0x7E, 0x5D, 0xF4, 0x29, 0x4A, 0x80, 0x6F, 0x8D, 0x0E, 0xE9, 0x1B, 0xD0, 0x04, 0x6A, 0xDC, 0x43, 0xD6, 0x40, 0xD9, 0x8D, 0xDC, 0x80, 0x25, 0xA0, 0xCA, 0x37, 0xF9, 0x1D, 0xC6, 0x68, 0x8A, 0xEC, 0x32, 0xF5, 0xF8, 0xF2, 0x64, 0x2D, 0x62, 0x72, 0x37, 0x31, 0x23, 0xD7, 0xCA, 0x0F, 0x9E, 0x31, 0x12, 0xBA, 0xFB, 0x43, 0x57, 0x5C, 0x62, 0xD5, 0xE1, 0x4F, 0xBB, 0xE3, 0x90, 0xF5, 0x4B, 0x7E, 0xA9, 0x13, 0x52, 0x52, 0x6A, 0x1C, 0xAF, 0x5B, 0xAC, 0xB4, 0x3F, 0xD8, 0x41, 0x30, 0x40, 0x6F, 0xB7, 0xFA, 0xB2, 0xFE, 0x6E, 0x30, 0x5C, 0xE7, 0xB9, 0x80, 0xB1, 0x99, 0xD9, 0x59, 0xD5, 0xF6, 0x58, 0x74, 0xE2, 0x86, 0x3B, 0x01, 0x0E, 0x0B, 0xA4, 0xAA, 0x03, 0x9D, 0x6C, 0x5D, 0x7E, 0x37, 0x2C, 0x75, 0x01, 0x3A, 0x80, 0x6A, 0x20, 0x9E, 0x50, 0xDF, 0x0A, 0x80, 0x3D, 0xB0, 0xF6, 0xB1, 0xDA, 0x1E, 0x75, 0xBD, 0x9C, 0xAC, 0xDD, 0x44, 0x8F, 0x1C, 0xB3, 0x09, 0xA8, 0x16, 0x86, 0x4A, 0x8C, 0xB5, 0x7D, 0xAC, 0xDD, 0xF2, 0x53, 0xA4, 0x95, 0x05, 0xA4, 0x5F, 0x3E, 0xDC, 0xC2, 0xEA, 0x6B, 0xF8, 0xD3, 0xC1, 0x95, 0xAB, 0xE3, 0x7A, 0x1C, 0x5F, 0xAC, 0xF5, 0xD4, 0x5C, 0x33, 0x0B, 0xAF, 0x1E, 0x2D, 0x98, 0x35, 0xF9, 0xB6, 0x41, 0x1F, 0xE0, 0xB8, 0x17, 0x67, 0xE0, 0x44, 0x4E, 0xE4, 0x60, 0xE6, 0xBA, 0x0D, 0x64, 0x1E, 0x36, 0x47, 0x4C, 0xFF, 0x3C, 0xB3, 0x33, 0x26, 0x15, 0xF2, 0x51, 0x70, 0x75, 0x0A, 0xD0, 0xF3, 0x9B, 0xF9, 0x74, 0xC2, 0xDA, 0x05, 0xB8, 0x0F, 0x02, 0xB0, 0x81, 0x24, 0xB0, 0x1D, 0xD0, 0x98, 0xEC, 0xE9, 0xA6, 0xCD, 0x04, 0xEB, 0xCE, 0xA6, 0xC9, 0x91, 0xD2, 0xC1, 0x28, 0x5E, 0x36, 0xC6, 0x9D, 0x86, 0x7C, 0xD8, 0xE5, 0x70, 0x75, 0x2E, 0x47, 0xA0, 0x18, 0xC6, 0x5A, 0xC0, 0x6B, 0xB3, 0x59, 0x0C, 0x15, 0xFB, 0x01, 0x4C, 0x17, 0x80, 0xCE, 0xC3, 0x8E, 0xF9, 0x46, 0x31, 0xA9, 0x87, 0x1B, 0xA6, 0x0B, 0x07, 0xCA, 0xF0, 0x70, 0xE9, 0x38, 0x6F, 0x7D, 0x0C, 0xC9, 0xC9, 0x4D, 0x5F, 0xEC, 0xCC, 0xB9, 0x35, 0x86, 0xB4, 0x31, 0xAB, 0xE5, 0xBC, 0x32, 0x3F, 0x40, 0xB9, 0x49, 0xF7, 0xC9, 0x9B, 0x4C, 0xA0, 0x8F, 0x21, 0x81, 0x4A, 0xFE, 0x82, 0x40, 0xEB, 0x80, 0x46, 0x5E, 0xF7, 0x7F, 0xD3, 0x06, 0xCE, 0x1F, 0x7C, 0xD1, 0x66, 0x8A, 0xF0, 0x76, 0xD9, 0x08, 0x6A, 0xC8, 0x55, 0x5B, 0xD0, 0x96, 0x13, 0x31, 0x92, 0x0F, 0x98, 0xB9, 0xD3, 0xD9, 0x00, 0xA3, 0xE6, 0xF2, 0x7B, 0x87, 0xFF, 0x6A, 0x44, 0x84, 0x22, 0x99, 0x7D, 0xC6, 0x19, 0x93, 0xBD, 0xBB, 0x60, 0x3A, 0x18, 0xAB, 0x66, 0xD0, 0x06, 0xBF, 0xDF, 0x18, 0x79, 0xC2, 0xC4, 0x8A, 0x81, 0x09, 0x13, 0x28, 0xAC, 0xA4, 0xB3, 0x04, 0xE6, 0xFA, 0xC5, 0x96, 0xEC, 0x08, 0x7F, 0xF4, 0x7C, 0x4A, 0xCA, 0x68, 0x71, 0x60, 0x52, 0x55, 0x66, 0xD0, 0x67, 0x76, 0x00, 0x3E, 0x61, 0xB2, 0xE5, 0x40, 0xD8, 0x3D, 0xBC, 0xBB, 0x80, 0x0A, 0x20, 0x0C, 0x70, 0x01, 0x98, 0x16, 0xCC, 0x9A, 0x1F, 0x1C, 0x20, 0x7A, 0x6C, 0x86, 0x4D, 0xEF, 0x8A, 0x15, 0x58, 0xF8, 0x28, 0x8A, 0xC2, 0x74, 0x6B, 0x07, 0xDC, 0xED, 0x76, 0xC5, 0x0A, 0x56, 0x03, 0x71, 0xC9, 0xB3, 0x08, 0xF2, 0xAD, 0x4E, 0x96, 0xB7, 0xCD, 0x12, 0xA4, 0x3D, 0x91, 0x8A, 0x9C, 0x89, 0xEE, 0x27, 0x59, 0xC1, 0x3F, 0xC8, 0x29, 0x07, 0xC8, 0xBC, 0xBB, 0xEA, 0xA9, 0x8F, 0x25, 0x78, 0x78, 0x0F, 0x60, 0x09, 0xAC, 0xB4, 0x65, 0x6C, 0x76, 0x75, 0xDC, 0xAB, 0x13, 0xEE, 0x5A, 0x9B, 0xDF, 0x7D, 0x46, 0x5D, 0x4E, 0x44, 0xA5, 0x00, 0x1F, 0x50, 0x07, 0xD5, 0x04, 0x88, 0x18, 0x38, 0xE0, 0x0A, 0x68, 0x01, 0xD2, 0x80, 0x2D, 0xA0, 0x85, 0x36, 0xF3, 0xBF, 0xFA, 0xEC, 0xA2, 0xC7, 0x13, 0x19, 0x9F, 0xC8, 0x6E, 0x20, 0x13, 0xC6, 0x37, 0xEA, 0xE5, 0x35, 0xA0, 0xBD, 0xB8, 0xF3, 0x0F, 0xB1, 0xDD, 0xBC, 0xDB, 0x1C, 0x2B, 0x3D, 0x91, 0xF2, 0xF3, 0x8B, 0xFA, 0xF1, 0xCF, 0x2C, 0xB9, 0xDD, 0x60, 0x26, 0x8C, 0x2A, 0x03, 0x5B, 0x6E, 0x07, 0xA1, 0xD9, 0x20, 0x6F, 0x3F, 0xB7, 0x3F, 0xC2, 0xF1, 0x1A, 0x03, 0x05, 0xC4, 0x00, 0xDD, 0x40, 0xF5, 0xE3, 0x9A, 0x6E, 0x80, 0x7A, 0xBA, 0xDB, 0x00, 0x91, 0x41, 0x03, 0xDE, 0x77, 0x32, 0xEA, 0xDB, 0xBE, 0x7D, 0xCF, 0x9B, 0xC9, 0x37, 0xFD, 0x6E, 0x6E, 0x6B, 0xC7, 0x3B, 0x34, 0x6D, 0x8E, 0xF3, 0xB4, 0xCE, 0x83, 0x93, 0xA8, 0xF7, 0x86, 0x2B, 0x4F, 0x36, 0xF2, 0xCF, 0xB2, 0xF0, 0x55, 0xB4, 0xBF, 0x9F, 0x0B, 0xC8, 0x2D, 0xDB, 0x2B, 0xBE, 0xFF, 0xB6, 0xCE, 0x3B, 0x92, 0x3E, 0x2E, 0x80, 0x5E, 0x35, 0xE3, 0xC1, 0x90, 0xC1, 0x71, 0x70, 0xD7, 0xC0, 0x1A, 0xD0, 0xBC, 0x2D, 0xBA, 0xE4, 0x96, 0x0A, 0xF6, 0x18, 0x18, 0x60, 0x7E, 0xF7, 0x31, 0xF3, 0xAB, 0x8D, 0x34, 0x12, 0x91, 0x6F, 0x6D, 0x86, 0xA0, 0x4F, 0x00, 0xD8, 0x0E, 0xF8, 0x93, 0xA4, 0x16, 0xF9, 0x34, 0x51, 0x7D, 0xF4, 0x1E, 0xAC, 0x80, 0xF3, 0x8A, 0x1D, 0xAB, 0xA1, 0x9D, 0x59, 0xBA, 0x7F, 0x59, 0x0A, 0xA5, 0x39, 0x77, 0xE5, 0x1A, 0xFF, 0x93, 0x7C, 0xC8, 0x84, 0x33, 0xAD, 0x22, 0x47, 0x2D, 0x34, 0xFE, 0x21, 0xB7, 0xCC, 0x5F, 0xB8, 0x8F, 0x7E, 0xFC, 0x69, 0xF3, 0x09, 0xC8, 0x55, 0x1A, 0x82, 0x12, 0xD5, 0xBB, 0x05, 0xC6, 0xBA, 0x53, 0xA3, 0xD6, 0xA6, 0x22, 0x15, 0x55, 0x13, 0x2F, 0x2F, 0x9A, 0xB3, 0xF2, 0x3C, 0x01, 0xAD, 0x81, 0x8E, 0x65, 0x8E, 0xFB, 0x97, 0x9A, 0x2F, 0x3C, 0xCC, 0x08, 0x65, 0xC6, 0xD9, 0xFA, 0x05, 0x88, 0xBC, 0x13, 0x5C, 0xFA, 0xA9, 0x79, 0xD1, 0x00, 0x56, 0xCF, 0x69, 0x58, 0x01, 0x69, 0xC0, 0x7A, 0xDE, 0x74, 0x5A, 0xAD, 0x3E, 0x01, 0xD7, 0x2C, 0x4C, 0xCD, 0x6D, 0x93, 0x90, 0xD0, 0x82, 0x98, 0x35, 0xF7, 0x52, 0xE9, 0xCF, 0x6A, 0xE8, 0x47, 0x8B, 0x75, 0xFA, 0x5F, 0x02, 0x0A, 0x4C, 0xC8, 0x34, 0x9E, 0xCD, 0xD7, 0x7D, 0x9C, 0x4E, 0x1E, 0xCA, 0xF7, 0xEF, 0x1E, 0x6F, 0xA7, 0xAB, 0x41, 0x39, 0xB0, 0x98, 0xB8, 0x31, 0xD8, 0xBF, 0x9E, 0x03, 0x75, 0x8B, 0xEF, 0x5D, 0x42, 0xDF, 0x7E, 0x67, 0x42, 0x16, 0xF3, 0x30, 0x72, 0xDD, 0xF7, 0x84, 0xEC, 0x3B, 0x11, 0x2D, 0x07, 0x1D, 0x77, 0x9B, 0x96, 0xB5, 0x01, 0x53, 0x40, 0x1D, 0x60, 0x09, 0x6E, 0x6E, 0xC0, 0x0C, 0xF0, 0x9C, 0x37, 0xCF, 0x58, 0x6B, 0x74, 0x20, 0xDF, 0x8E, 0x1E, 0x97, 0x36, 0x9A, 0x1D, 0x35, 0x05, 0xDA, 0xCB, 0x3E, 0x17, 0x55, 0xA7, 0xA2, 0xB6, 0x40, 0x12, 0x2A, 0x0E, 0x1E, 0x3C, 0xD5, 0x3E, 0x9E, 0xC8, 0xC7, 0xEB, 0xED, 0x76, 0xA7, 0x96, 0x6F, 0xBF, 0x65, 0x09, 0xA3, 0x38, 0x51, 0x1F, 0x29, 0xE9, 0xF5, 0xB4, 0x5A, 0xF7, 0xBB, 0x0B, 0xA1, 0xD8, 0x1D, 0x1B, 0xD1, 0xC1, 0x5A, 0x77, 0xB8, 0xA8, 0x39, 0xD2, 0xD7, 0xE3, 0xA1, 0x2E, 0xE0, 0xF8, 0x42, 0x04, 0xD8, 0x09, 0xB8, 0xAE, 0xBB, 0xA2, 0xD6, 0x7A, 0x20, 0xC0, 0xF6, 0xAB, 0xE7, 0x8B, 0xEF, 0x7F, 0xD5, 0x7F, 0x6E, 0x5B, 0xF0, 0x0B, 0x69, 0x7D, 0x81, 0x16, 0x35, 0x43, 0x56, 0x80, 0x8F, 0x17, 0x4D, 0x6D, 0xE4, 0x47, 0x0C, 0x62, 0x8A, 0xE2, 0x68, 0xB4, 0x1E, 0xF4, 0x76, 0xBF, 0xE2, 0xFB, 0x1F, 0xEC, 0x54, 0xA3, 0x9E, 0x32, 0x02, 0x6F, 0x20, 0xAF, 0x7E, 0x7A, 0xFB, 0xD4, 0xF0, 0x86, 0x3D, 0x7A, 0xC2, 0x40, 0x9D, 0x2F, 0x43, 0x6B, 0xDF, 0x0D, 0x1D, 0x5B, 0x81, 0x73, 0xF9, 0xC8, 0xDF, 0xD8, 0x8E, 0xF3, 0x0D, 0x8D, 0x85, 0x20, 0x6F, 0x23, 0x82, 0xD2, 0x3B, 0xAD, 0x4D, 0x1B, 0x38, 0x69, 0xC1, 0x09, 0x54, 0x0D, 0x36, 0xE0, 0x05, 0xF0, 0x7A, 0xD3, 0x7A, 0xE7, 0xC1, 0x55, 0xD1, 0x6A, 0xFB, 0xCF, 0xE7, 0x3C, 0x9D, 0x02, 0x7D, 0x52, 0x78, 0x4F, 0x6C, 0xFC, 0xB7, 0x09, 0xC7, 0x34, 0xCC, 0xE5, 0xAB, 0x7B, 0xD4, 0x35, 0xFA, 0x6A, 0xCC, 0x15, 0xFB, 0x99, 0xA1, 0xC9, 0xD1, 0x6D, 0x49, 0x27, 0x22, 0x10, 0x9B, 0x2B, 0x04, 0x7F, 0xA9, 0xDB, 0x94, 0x6C, 0x7C, 0x29, 0x7A, 0xB5, 0xF6, 0xA1, 0xBC, 0x4C, 0x14, 0x3D, 0xAF, 0x77, 0x86, 0x95, 0x72, 0x70, 0xCA, 0x60, 0x5E, 0xE1, 0xD0, 0x39, 0xB3, 0x90, 0xFD, 0x20, 0x83, 0x49, 0x7D, 0xEC, 0x62, 0xBC, 0x01, 0x5B, 0x40, 0x05, 0xBB, 0xD7, 0x02, 0x3D, 0xA8, 0x02, 0x62, 0xA0, 0x0A, 0xEC, 0x05, 0x08, 0x8B, 0xFF, 0x8C, 0x56, 0x93, 0x2F, 0x12, 0xA5, 0x5E, 0x7F, 0xF9, 0x99, 0x2B, 0x70, 0x78, 0x5E, 0x1B, 0x7F, 0x9E, 0xDC, 0xA3, 0x73, 0x81, 0x7C, 0xEF, 0xEA, 0xFE, 0x06, 0x87, 0xB2, 0x22, 0xE3, 0x9F, 0x5E, 0xEF, 0x52, 0xAE, 0x2C, 0x5C, 0x13, 0xFA, 0x76, 0x3E, 0x6A, 0x50, 0x75, 0xFF, 0x2A, 0x4C, 0x57, 0x7B, 0x1B, 0xD5, 0x02, 0xDC, 0x89, 0xF5, 0x6A, 0x8A, 0xE3, 0x27, 0x73, 0x79, 0x71, 0x50, 0x07, 0x10, 0x63, 0xD1, 0x53, 0x77, 0xFD, 0x01, 0x3E, 0x24, 0x0E, 0xAB, 0xBB, 0x9B, 0x48, 0x51, 0x55, 0x4C, 0x81, 0xF0, 0xC7, 0x86, 0x35, 0xD8, 0x80, 0x3B, 0xC0, 0x37, 0x6B, 0x03, 0xCD, 0x54, 0xC4, 0x4D, 0xAB, 0xA1, 0x9A, 0xC0, 0x2B, 0x3E, 0xB1, 0x4D, 0x5B, 0x81, 0x02, 0xDF, 0xD3, 0x17, 0xBA, 0x91, 0x4D, 0xD7, 0x02, 0x15, 0x7B, 0x33, 0x1C, 0x23, 0xAC, 0x6E, 0xE9, 0xE0, 0xF5, 0xD4, 0xB5, 0x5B, 0x71, 0x8A, 0x1D, 0x1D, 0x33, 0xC0, 0xEB, 0x4E, 0x3D, 0x56, 0x45, 0x4A, 0x23, 0x9D, 0x23, 0x03, 0x31, 0x86, 0xDC, 0x80, 0xD4, 0x47, 0xA2, 0xEF, 0x68, 0xB8, 0x03, 0x5E, 0x80, 0xD8, 0x20, 0xE7, 0x95, 0x4B, 0x01, 0x87, 0x4B, 0x18, 0x72, 0x9C, 0x81, 0x62, 0x0C, 0xD4, 0x01, 0x55, 0x20, 0x9F, 0x8E, 0x97, 0x49, 0x2C, 0xC0, 0x14, 0x58, 0x72, 0xC7, 0x7E, 0x58, 0x76, 0x13, 0x45, 0xAB, 0xD9, 0xA7, 0x06, 0x80, 0xE9, 0xC7, 0xF3, 0x9A, 0x41, 0x81, 0x0E, 0xDD, 0x09, 0x50, 0x69, 0x26, 0x81, 0xF3, 0xDA, 0xEA, 0xC4, 0x2F, 0x58, 0xEB, 0x3A, 0xAF, 0xC5, 0x7A, 0x9A, 0xF6, 0xEE, 0xE2, 0xFC, 0x61, 0x87, 0x44, 0x20, 0x0B, 0xD8, 0x7D, 0x57, 0x8C, 0x85, 0x00, 0x6B, 0xDF, 0x89, 0x0C, 0x51, 0x80, 0xB3, 0x71, 0x2C, 0xD3, 0xBA, 0xF2, 0x5F, 0xAD, 0xF3, 0x14, 0xF0, 0xBE, 0xCF, 0x6B, 0x47, 0x56, 0x74, 0xD0, 0x8F, 0xD0, 0x90, 0x0F, 0x28, 0x75, 0xBB, 0xFC, 0x2D, 0x70, 0x03, 0xAA, 0x80, 0x70, 0x40, 0x37, 0xB0, 0x12, 0x10, 0x7D, 0x14, 0x23, 0xB7, 0xF9, 0x17, 0x97, 0xF2, 0x76, 0x5A, 0xED, 0xB3, 0x61, 0x84, 0xCE, 0x48, 0x6F, 0x1C, 0x8D, 0xC4, 0x51, 0x29, 0x93, 0x1B, 0x27, 0xD0, 0x46, 0xF5, 0xCF, 0x7D, 0xCA, 0xA5, 0xD5, 0xAE, 0x3C, 0xA2, 0xE6, 0x5E, 0x08, 0x6C, 0xC1, 0xC3, 0xD3, 0x65, 0xB8, 0x01, 0x95, 0xA7, 0x5F, 0xAE, 0x03, 0x4D, 0x04, 0xC0, 0xCA, 0xDC, 0x0E, 0x20, 0xF6, 0x40, 0x00, 0x77, 0x20, 0xE5, 0x17, 0x9E, 0x72, 0xEA, 0xAF, 0x1D, 0x23, 0xAC, 0x27, 0x9D, 0x34, 0x1B, 0x68, 0xC6, 0xF7, 0x39, 0x27, 0x56, 0x01, 0xAE, 0x80, 0xD9, 0xBD, 0x87, 0x6E, 0xBE, 0xF9, 0xC6, 0xF0, 0x8F, 0xD5, 0x62, 0x72, 0xB8, 0x0A, 0x91, 0xE3, 0xD0, 0xAB, 0xB4, 0x3D, 0x96, 0x51, 0xB1, 0x14, 0x8B, 0x6B, 0x4C, 0x10, 0xBE, 0xF2, 0x12, 0x21, 0xEA, 0xA7, 0x13, 0x8B, 0x9D, 0xEC, 0xC2, 0xC9, 0x15, 0xAD, 0x0B, 0x71, 0x1A, 0xE8, 0x6D, 0xC5, 0x2B, 0x14, 0x25, 0xD8, 0x74, 0xB3, 0xD2, 0xD7, 0xC6, 0x9A, 0x82, 0xB8, 0x9B, 0x2B, 0x65, 0x00, 0x2B, 0x66, 0xC1, 0x17, 0x40, 0x37, 0xE0, 0xFE, 0xDB, 0x9D, 0xF3, 0x38, 0x87, 0xD9, 0x0D, 0x44, 0x9E, 0x46, 0x74, 0xDD, 0x93, 0xA9, 0x3A, 0xF7, 0xF9, 0x15, 0x40, 0xDA, 0xAD, 0x5D, 0xB3, 0x05, 0x0F, 0xBB, 0x9F, 0xA4, 0x4D, 0x01, 0x92, 0x37, 0x7F, 0xA3, 0xD1, 0x72, 0x74, 0x91, 0xEA, 0xF3, 0x49, 0xEE, 0xBD, 0xAF, 0xAE, 0xF7, 0x5B, 0x13, 0x5E, 0xD6, 0x12, 0x58, 0xC2, 0x6A, 0x4A, 0x9D, 0x83, 0x7E, 0xEE, 0x5B, 0x30, 0x32, 0x7F, 0xB5, 0x64, 0x94, 0x31, 0x50, 0xCC, 0x30, 0x64, 0x90, 0xFE, 0x72, 0xE4, 0xA4, 0x4F, 0x0F, 0x14, 0xD7, 0x5F, 0x87, 0x07, 0x39, 0x9E, 0x42, 0xCF, 0xBB, 0x09, 0xDA, 0x56, 0xC6, 0x8E, 0x6E, 0x6D, 0xF9, 0x54, 0x40, 0x1A, 0xE0, 0x16, 0x48, 0x85, 0x53, 0xDF, 0xF7, 0x15, 0x3E, 0x84, 0xDE, 0x81, 0x49, 0x6A, 0x2D, 0xA0, 0xE7, 0x0E, 0x6E, 0x74, 0x46, 0x6D, 0x40, 0x6D, 0x90, 0x03, 0x01, 0x76, 0x0F, 0x0C, 0x90, 0x06, 0xFA, 0x8C, 0xB4, 0xFA, 0x56, 0xFF, 0xCE, 0xFA, 0xF3, 0x46, 0xB6, 0x15, 0x6E, 0x22, 0x7B, 0xB6, 0x0B, 0x60, 0x57, 0x63, 0x1F, 0xAC, 0x98, 0xD3, 0x83, 0x53, 0xB6, 0xEF, 0x8A, 0xB0, 0x9C, 0x53, 0xD3, 0xB9, 0x11, 0x14, 0x2C, 0x12, 0x06, 0xB0, 0x54, 0xDA, 0xE5, 0x6E, 0x33, 0x48, 0x17, 0x7E, 0xFA, 0x98, 0x62, 0x01, 0x27, 0x0A, 0x67, 0xBF, 0xEB, 0x85, 0x9C, 0xDB, 0x82, 0xFB, 0xAC, 0xEC, 0x09, 0x6C, 0x05, 0x98, 0xB3, 0x52, 0xFE, 0x6B, 0xC0, 0xD8, 0xA7, 0x22, 0x81, 0x2D, 0x74, 0xBC, 0x27, 0x7C, 0x52, 0x80, 0x36, 0xD0, 0x2C, 0xCD, 0x76, 0xA0, 0x15, 0xA8, 0x04, 0xE2, 0xD5, 0xFB, 0x69, 0x40, 0x0C, 0xE8, 0xA4, 0xD1, 0x90, 0x61, 0x2B, 0xDB, 0xBE, 0x40, 0xA8, 0x71, 0xA4, 0xD1, 0x79, 0xDD, 0x3E, 0xC5, 0x1D, 0xF0, 0x23, 0xB5, 0x43, 0x63, 0x67, 0xC2, 0x52, 0x2A, 0xB7, 0x33, 0xF2, 0xA4, 0x08, 0xF8, 0xA5, 0xB2, 0x19, 0xE3, 0xC8, 0x4B, 0x16, 0x4E, 0xCF, 0x54, 0xA0, 0x87, 0xB9, 0xC7, 0x90, 0x79, 0xE2, 0x57, 0xFC, 0x62, 0xF9, 0x41, 0x8E, 0x58, 0xB0, 0xF1, 0x0F, 0xC0, 0x43, 0x80, 0x8C, 0x59, 0xEB, 0x71, 0x96, 0xD7, 0xE9, 0xEA, 0x89, 0x65, 0xE4, 0x83, 0x1E, 0x0D, 0xF1, 0x15, 0xE3, 0xB0, 0x12, 0xA0, 0x62, 0x06, 0xE1, 0x02, 0xA2, 0xEE, 0xC0, 0x41, 0x06, 0x10, 0x0D, 0x58, 0x02, 0x9B, 0x5E, 0xBA, 0x35, 0xE0, 0x9B, 0x74, 0xE0, 0x3A, 0x75, 0x8F, 0x03, 0x36, 0x33, 0xC5, 0x71, 0x5E, 0xF6, 0x34, 0x9A, 0x4B, 0xB8, 0xB6, 0x76, 0xE0, 0x4F, 0x25, 0x3D, 0x13, 0x29, 0x98, 0xDE, 0x79, 0x2B, 0x02, 0x5C, 0x41, 0x7D, 0xD1, 0x71, 0xA5, 0xEE, 0xA3, 0x01, 0x20, 0xC9, 0x35, 0xE2, 0xF7, 0xFB, 0x06, 0x2C, 0x22, 0x76, 0xBA, 0xB1, 0xC4, 0x02, 0x96, 0xFD, 0x2A, 0x70, 0x78, 0x3E, 0xE8, 0x73, 0xDE, 0x8C, 0xBC, 0xEB, 0x4C, 0xC4, 0x01, 0xCA, 0xBB, 0xA4, 0x51, 0x7D, 0x6C, 0xDC, 0x90, 0xE3, 0x4B, 0x5B, 0x35, 0xF3, 0x6A, 0x3C, 0xC6, 0xE2, 0x40, 0x8D, 0x1B, 0xD9, 0x0A, 0xCE, 0x3E, 0x31, 0x20, 0xD7, 0x40, 0x00, 0x6F, 0x40, 0x1D, 0xD8, 0x03, 0x1D, 0x89, 0x8C, 0x9D, 0x34, 0xDA, 0xDC, 0x0A, 0x74, 0x7D, 0x02, 0xFC, 0xE9, 0x8A, 0xEC, 0x64, 0x06, 0x0B, 0x03, 0xB6, 0x8B, 0x0A, 0xB8, 0x78, 0x6C, 0x9A, 0x1C, 0xA7, 0x31, 0x5A, 0xFC, 0xB4, 0x50, 0xD5, 0x5F, 0x9A, 0xDC, 0xC9, 0xE3, 0xB0, 0x83, 0xCD, 0xD5, 0x9A, 0x31, 0xCB, 0xB8, 0xAA, 0xAF, 0x83, 0x07, 0xB6, 0x06, 0x6C, 0xB0, 0x8F, 0x74, 0xD6, 0x9D, 0x81, 0xA7, 0x03, 0x51, 0x60, 0x2D, 0x40, 0x78, 0x8B, 0xCF, 0xA7, 0xD3, 0x7E, 0xE7, 0xDD, 0xC8, 0x4C, 0x0C, 0xA0, 0xF3, 0x60, 0x0D, 0x8E, 0x4E, 0xB8, 0x00, 0xBE, 0x01, 0x33, 0x40, 0xF6, 0xAD, 0xBE, 0xE3, 0x05, 0xE4, 0x7A, 0xBC, 0x1D, 0x2E, 0x70, 0x86, 0xAF, 0xFC, 0x6B, 0xA8, 0xFD, 0x60, 0xF2, 0x58, 0x4D, 0x1B, 0x2A, 0x99, 0x90, 0x4F, 0x7F, 0x3B, 0xB9, 0x78, 0x40, 0xC7, 0x5F, 0x9D, 0xBA, 0x4D, 0xCF, 0x5D, 0xCA, 0xDE, 0x1B, 0xE8, 0x44, 0xC9, 0x99, 0x77, 0x45, 0x69, 0x29, 0x79, 0x1A, 0x42, 0xC5, 0x9D, 0xF6, 0xD2, 0x0A, 0xC8, 0x55, 0xAF, 0xAA, 0x27, 0x23, 0x39, 0x13, 0xB0, 0x81, 0xEB, 0xE0, 0xEA, 0x82, 0xE1, 0x27, 0x05, 0x27, 0x95, 0xD7, 0x01, 0x65, 0x61, 0x15, 0x03, 0xD3, 0x77, 0x65, 0x81, 0xDB, 0x1D, 0x4B, 0x8E, 0x41, 0xD7, 0xA0, 0x81, 0x4A, 0x20, 0x14, 0xB0, 0x06, 0x82, 0x51, 0x46, 0x8E, 0xB5, 0x69, 0x72, 0xDC, 0x4E, 0x2F, 0x2E, 0x14, 0x1F, 0xD6, 0x72, 0x18, 0x3D, 0xF4, 0x3B, 0xE8, 0x69, 0x0B, 0x9C, 0x9B, 0xBB, 0x70, 0x6D, 0xD9, 0x7A, 0x54, 0xAE, 0x3E, 0xDA, 0x93, 0xE3, 0x57, 0x63, 0x12, 0x95, 0xBB, 0xD6, 0x9E, 0x99, 0x18, 0x40, 0xCE, 0x5C, 0x8E, 0x53, 0x5D, 0xA9, 0x6B, 0xEC, 0x24, 0x00, 0x5D, 0x19, 0x4D, 0xA7, 0xAC, 0xCF, 0x49, 0x4D, 0x81, 0x20, 0x7A, 0x50, 0x6C, 0xDE, 0x38, 0xF6, 0xBD, 0xE4, 0x31, 0x51, 0x6C, 0x7B, 0x77, 0xED, 0x95, 0x05, 0xA4, 0xDC, 0xBD, 0x8E, 0x9D, 0xBB, 0xB0, 0x00, 0x61, 0x80, 0xF7, 0x5D, 0x77, 0xD9, 0x83, 0xDC, 0x40, 0x05, 0xB7, 0x2C, 0x5A, 0x0D, 0x7B, 0x40, 0x5B, 0x7D, 0xE9, 0xF2, 0x31, 0xA1, 0x61, 0x5F, 0x83, 0x12, 0x88, 0x65, 0x6D, 0x41, 0x16, 0x94, 0x39, 0xB4, 0x5A, 0x3D, 0xFF, 0xA5, 0x11, 0xE6, 0x6F, 0xF3, 0xF6, 0x0F, 0x76, 0x9C, 0x5A, 0x47, 0x52, 0x9D, 0xFA, 0x13, 0xBF, 0x94, 0xA7, 0x38, 0xF5, 0xCF, 0xF5, 0xA4, 0xC3, 0x6E, 0xBB, 0xFD, 0x40, 0x74, 0xE6, 0x26, 0xD1, 0x00, 0x53, 0x8A, 0x29, 0x45, 0xC0, 0x26, 0xEC, 0xC2, 0x19, 0x7A, 0x5A, 0xD7, 0x33, 0xC2, 0xBC, 0xEF, 0x0E, 0x96, 0x5A, 0x40, 0xD5, 0x3D, 0x35, 0xAB, 0x07, 0x0E, 0x44, 0x02, 0xEA, 0xF7, 0x24, 0x16, 0x03, 0x5A, 0x69, 0x35, 0xFF, 0x8B, 0x91, 0xB4, 0x6A, 0x74, 0x81, 0x83, 0xB2, 0x9A, 0xC7, 0xB8, 0x47, 0x1C, 0x09, 0x65, 0x29, 0xF8, 0x46, 0x6A, 0x7F, 0x90, 0x82, 0x8C, 0xBB, 0x51, 0xD2, 0x7E, 0x6A, 0x67, 0xA9, 0x0F, 0x67, 0xC7, 0x78, 0x0D, 0x68, 0x5C, 0xBE, 0x59, 0x26, 0x91, 0x1D, 0x85, 0x49, 0xDE, 0x18, 0x14, 0xD8, 0x75, 0x37, 0xCD, 0xF3, 0xBC, 0xDB, 0x44, 0x2D, 0xBF, 0x6D, 0xD8, 0xFA, 0xB3, 0x1A, 0x73, 0xB5, 0xE3, 0x94, 0xD0, 0xEE, 0xE6, 0x90, 0x93, 0x47, 0x49, 0xD3, 0xEE, 0x94, 0x3D, 0xA7, 0x6E, 0xA4, 0x01, 0x51, 0x80, 0x0F, 0x74, 0x6C, 0x5F, 0x0A, 0xB8, 0x00, 0xC7, 0xEB, 0x65, 0xB4, 0x5A, 0xA0, 0x24, 0x47, 0x78, 0x97, 0xE2, 0xA1, 0xB0, 0x26, 0xE5, 0x24, 0xE0, 0x23, 0x32, 0x81, 0x9C, 0xC3, 0xDC, 0xB7, 0xF3, 0x6D, 0xA8, 0x1D, 0x97, 0xD5, 0x98, 0x52, 0x7C, 0x3A, 0x68, 0xFA, 0xF1, 0x66, 0xF9, 0xF5, 0x6B, 0x8C, 0xCA, 0x1C, 0xF6, 0xF3, 0xAB, 0xBB, 0xBD, 0xC4, 0x4F, 0x66, 0xC4, 0x4E, 0xDE, 0xBA, 0xCD, 0x58, 0x93, 0xB1, 0x53, 0x15, 0xD0, 0x67, 0x6A, 0x02, 0xBC, 0xCE, 0xB6, 0x5D, 0x12, 0xC4, 0x7E, 0x8E, 0x83, 0x52, 0xF7, 0x99, 0x4D, 0x0C, 0xC8, 0x0F, 0x7A, 0x94, 0x73, 0xF6, 0x20, 0x04, 0xF0, 0x7C, 0x64, 0xC2, 0x0C, 0x88, 0x41, 0xC9, 0xAD, 0xAA, 0xB3, 0x3D, 0xCF, 0x86, 0x9C, 0x85, 0x3E, 0xBD, 0x9F, 0xE9, 0x98, 0xE6, 0x56, 0x3D, 0xFD, 0x67, 0x37, 0x4A, 0xCE, 0x3D, 0xE0, 0x4A, 0x2E, 0x67, 0xA9, 0xF1, 0xED, 0xFB, 0x56, 0x5E, 0x99, 0x9B, 0xF2, 0x7D, 0x31, 0x2B, 0x29, 0x6B, 0xB4, 0xE8, 0xBF, 0xA2, 0xCF, 0x9E, 0x1B, 0x6B, 0xFD, 0xF2, 0x34, 0x17, 0xD5, 0x95, 0x6D, 0xDD, 0x59, 0x93, 0xF4, 0xE9, 0xAE, 0xB7, 0x39, 0xC8, 0x02, 0xD4, 0x7F, 0x63, 0x34, 0x01, 0x8C, 0xA7, 0xAB, 0x2D, 0x77, 0x4D, 0x54, 0x74, 0x9D, 0x36, 0x7D, 0x62, 0x40, 0xF8, 0x93, 0x44, 0xF4, 0x68, 0x3C, 0x2D, 0x7F, 0xBA, 0x29, 0x2C, 0xC0, 0x13, 0xC8, 0x3D, 0xD6, 0x2E, 0x5A, 0xAD, 0xA6, 0x0A, 0x1A, 0x5D, 0x6C, 0xE4, 0xBA, 0x4C, 0xC5, 0x08, 0xF6, 0xD5, 0x49, 0xC7, 0x6B, 0x11, 0x4C, 0x5B, 0x43, 0x9E, 0xBC, 0xBC, 0xC5, 0xB3, 0xB6, 0x8F, 0x4C, 0x37, 0x73, 0x57, 0xF8, 0x6F, 0xFC, 0xAE, 0x84, 0xEB, 0x24, 0x46, 0x9D, 0xC5, 0x96, 0xBD, 0xDE, 0x98, 0x50, 0xA5, 0x97, 0x58, 0x23, 0x70, 0xB4, 0x13, 0xCE, 0xA8, 0x74, 0x1D, 0xC4, 0x80, 0x29, 0xDB, 0x74, 0xD3, 0x85, 0x8C, 0xB9, 0xFC, 0x77, 0x27, 0x83, 0x8F, 0x89, 0x5D, 0x36, 0xAE, 0x53, 0xAA, 0xB3, 0x6A, 0x4A, 0x80, 0x68, 0x36, 0x75, 0x06, 0xB6, 0xDC, 0xF2, 0x6A, 0x5D, 0x03, 0x9D, 0x87, 0x01, 0xC4, 0xA2, 0xD5, 0x7A, 0x3A, 0x58, 0xC6, 0x17, 0x67, 0x51, 0xBF, 0xEF, 0xED, 0x15, 0xD3, 0x21, 0x3A, 0x0C, 0xE3, 0x47, 0x63, 0x62, 0x37, 0x46, 0xFF, 0xE3, 0xA3, 0x83, 0x4B, 0x75, 0x92, 0xAB, 0x33, 0x69, 0x9D, 0x43, 0x79, 0x50, 0x00, 0xD7, 0x6F, 0x59, 0x5B, 0xD5, 0x3B, 0x4B, 0x94, 0x3D, 0x0A, 0xD3, 0x7E, 0x65, 0xF8, 0x9B, 0x5E, 0x07, 0xBA, 0xCB, 0xAC, 0x00, 0x17, 0xC0, 0xFA, 0xE7, 0x24, 0xDF, 0x7A, 0x6E, 0x06, 0xAC, 0xD5, 0x8C, 0x4B, 0x6D, 0x2B, 0x26, 0x60, 0x5C, 0x63, 0x0A, 0x86, 0xE3, 0xFB, 0x54, 0xB8, 0x49, 0x00, 0x21, 0x83, 0x1E, 0xE4, 0x60, 0x0F, 0xD6, 0x2D, 0x00, 0xA7, 0x5C, 0xD6, 0x62, 0x4E, 0xC5, 0xD5, 0xDF, 0x04, 0xF5, 0x2C, 0xF8, 0x9C, 0x25, 0x67, 0x34, 0x50, 0x15, 0xD7, 0x66, 0x3B, 0xAF, 0x49, 0xD4, 0xE9, 0xBB, 0xE2, 0xD8, 0x9E, 0x2C, 0x5C, 0xA3, 0xDB, 0xC1, 0xEB, 0x4E, 0xCE, 0x61, 0x1A, 0x0F, 0x6F, 0x9D, 0x7D, 0x75, 0x3C, 0x86, 0x43, 0xF1, 0x78, 0x34, 0xE8, 0xA4, 0xE9, 0x93, 0x66, 0xDC, 0xAC, 0x31, 0x18, 0xEC, 0xD3, 0xC9, 0x12, 0x38, 0x51, 0x1A, 0xFD, 0xC5, 0xAF, 0xB6, 0x9E, 0x7D, 0x6E, 0x31, 0x11, 0x8B, 0xB7, 0xCE, 0x98, 0x15, 0xAC, 0x81, 0x60, 0x61, 0xAD, 0x00, 0xCD, 0x8A, 0xDA, 0x18, 0x18, 0xB0, 0xE7, 0x95, 0x1A, 0xC4, 0xA0, 0xD8, 0x4B, 0x47, 0x68, 0xB5, 0x3D, 0xBD, 0x9C, 0xF4, 0xAF, 0x70, 0x88, 0xBA, 0xBA, 0x64, 0x68, 0x34, 0xD6, 0xD6, 0x36, 0x08, 0x1C, 0x45, 0xB0, 0x43, 0xE8, 0xD5, 0xD7, 0x32, 0xF2, 0xB1, 0x9A, 0x3B, 0x9D, 0x35, 0x7B, 0xD6, 0x09, 0x26, 0x22, 0xF2, 0x62, 0x34, 0xCB, 0x5A, 0xB3, 0x4E, 0xDB, 0xEF, 0x8C, 0xF8, 0xBD, 0x79, 0x89, 0xBD, 0xA2, 0x77, 0x6B, 0xF3, 0x30, 0x03, 0x18, 0xE1, 0x80, 0x16, 0x50, 0x74, 0x4D, 0x71, 0xD7, 0x63, 0x15, 0x6D, 0x32, 0x3B, 0xBA, 0xC6, 0x40, 0xEC, 0x1C, 0x9C, 0x00, 0xEB, 0x20, 0x2D, 0xC6, 0x7F, 0xA4, 0x80, 0x3F, 0xB0, 0x0D, 0xEC, 0x04, 0x16, 0x3F, 0x05, 0x50, 0x49, 0xAB, 0x09, 0x42, 0x04, 0x3B, 0xBF, 0xD8, 0x7B, 0xAB, 0x61, 0x2E, 0xF1, 0x66, 0xB1, 0x14, 0x87, 0x2E, 0xC5, 0x66, 0x50, 0xBD, 0x31, 0xE4, 0xFC, 0xE9, 0xDD, 0x0E, 0xEE, 0xD3, 0x73, 0xD8, 0xE2, 0x74, 0xA4, 0x1C, 0x03, 0x29, 0x60, 0x0C, 0xE7, 0xF2, 0xBE, 0xC0, 0x8B, 0x42, 0x5D, 0xC1, 0xCE, 0x2A, 0x40, 0xE4, 0x8E, 0xFA, 0xF9, 0x8C, 0x2E, 0x1A, 0xA8, 0x6D, 0xB0, 0x80, 0x64, 0xAE, 0x01, 0x43, 0xE2, 0x77, 0x7B, 0x6C, 0xFE, 0xCD, 0xF6, 0x51, 0xDA, 0xB4, 0x19, 0x6B, 0xEA, 0x40, 0x31, 0x8F, 0x7B, 0x6C, 0xB8, 0x1B, 0x08, 0x19, 0x6C, 0xC0, 0x1C, 0x60, 0x52, 0x78, 0x37, 0x3F, 0x01, 0x6D, 0xB4, 0x9A, 0x42, 0x47, 0xCF, 0xEB, 0x69, 0xA5, 0x4A, 0xA5, 0x88, 0x91, 0x50, 0xC8, 0xA9, 0x85, 0xA8, 0x1E, 0x87, 0xE7, 0x13, 0x30, 0x78, 0xAD, 0x96, 0x3C, 0x87, 0xD7, 0xBE, 0x33, 0xDC, 0x29, 0x0C, 0xCF, 0x16, 0x29, 0x79, 0x2F, 0xF8, 0xAC, 0x7C, 0x0C, 0xB9, 0x7B, 0xB7, 0xEF, 0x7C, 0xAE, 0x06, 0x06, 0x44, 0x01, 0xB5, 0x80, 0xBB, 0x90, 0xD1, 0x8E, 0x60, 0xF0, 0x91, 0x9A, 0x38, 0xA5, 0xEF, 0x33, 0xE4, 0x3C, 0xE8, 0x1E, 0x98, 0x89, 0xFA, 0x74, 0x3C, 0x36, 0x05, 0x4A, 0x06, 0x06, 0xE4, 0x06, 0x5C, 0x01, 0x5B, 0x80, 0x1B, 0x8D, 0x47, 0xAB, 0x19, 0xAC, 0x56, 0x49, 0xAB, 0xE1, 0x0E, 0xB2, 0x1D, 0x28, 0xA3, 0xA4, 0x10, 0x84, 0x09, 0x12, 0x56, 0x6B, 0xA9, 0x3B, 0xE8, 0x2E, 0x4F, 0x48, 0xAF, 0x7A, 0x8D, 0x81, 0xEC, 0xE7, 0xA2, 0x65, 0x54, 0xCC, 0xC7, 0x5C, 0xCA, 0xE8, 0x07, 0x2C, 0x5A, 0x67, 0x63, 0x5C, 0x3A, 0x46, 0x5F, 0xCC, 0x41, 0xB9, 0xCB, 0x1A, 0x77, 0x8C, 0x9D, 0x0C, 0xE8, 0xBE, 0x8F, 0xBC, 0x61, 0x57, 0x4E, 0xA6, 0x9C, 0x02, 0xF7, 0x55, 0x3F, 0x6D, 0x00, 0x84, 0x70, 0xE0, 0x69, 0x61, 0x4A, 0xA9, 0xDC, 0x2D, 0x96, 0xD9, 0x1F, 0x58, 0xD7, 0x60, 0x03, 0x3B, 0x98, 0x35, 0x08, 0xA4, 0x00, 0x94, 0x42, 0x0D, 0xA7, 0xD5, 0x7C, 0x42, 0x9F, 0xFA, 0x05, 0xA7, 0x32, 0x6E, 0x2F, 0x6E, 0x77, 0xF2, 0x9E, 0x31, 0x79, 0x1E, 0x93, 0xE0, 0xE1, 0x7D, 0x77, 0x63, 0x59, 0x8F, 0xC0, 0x77, 0x9C, 0xD6, 0xE8, 0xF5, 0x3B, 0xE3, 0x30, 0x2A, 0xD5, 0x47, 0x59, 0xFC, 0xF4, 0x57, 0xFD, 0x89, 0xE5, 0xF4, 0xD8, 0xA2, 0x4E, 0x3A, 0xEF, 0x51, 0xFE, 0x71, 0x86, 0x01, 0x66, 0x4E, 0x0E, 0x7A, 0x0F, 0xFA, 0x17, 0xBF, 0x62, 0x23, 0x12, 0xE6, 0x7C, 0x8B, 0x9E, 0xD5, 0x8A, 0x1A, 0x95, 0xBA, 0xEF, 0x4C, 0x2C, 0x18, 0xC1, 0x4F, 0xD2, 0xDC, 0x6A, 0xC0, 0x06, 0x5E, 0x03, 0x07, 0x2C, 0x2F, 0x50, 0x17, 0xF4, 0x37, 0xD6, 0x98, 0x73, 0xEB, 0xEF, 0x0C, 0x85, 0x0F, 0x72, 0xEB, 0x58, 0xAD, 0x27, 0xA1, 0x7F, 0x8F, 0x6A, 0x87, 0xDE, 0xBB, 0x01, 0xB8, 0x4F, 0x03, 0x0A, 0xA3, 0xD5, 0xD4, 0x7F, 0xE9, 0xAE, 0x2C, 0x72, 0xCC, 0x73, 0x8B, 0xE6, 0xAE, 0x29, 0xCE, 0xB8, 0xD0, 0x4C, 0xFF, 0x3B, 0xC3, 0xC8, 0xAF, 0x5E, 0x29, 0xC2, 0xAE, 0x1B, 0x47, 0x25, 0x6D, 0x19, 0xB0, 0x13, 0xA8, 0xB8, 0xFA, 0x78, 0xDB, 0x91, 0x2E, 0x8D, 0xFE, 0x75, 0x92, 0xF3, 0x29, 0x64, 0x67, 0x03, 0x65, 0x98, 0x92, 0x0E, 0x35, 0x34, 0x5F, 0xDF, 0x40, 0x2D, 0xA0, 0xF7, 0x8D, 0x6A, 0x7E, 0x1A, 0x21, 0xDA, 0x04, 0x62, 0xD3, 0x6A, 0xF9, 0xDD, 0xDA, 0xED, 0xA7, 0x08, 0xE0, 0x09, 0x51, 0x4D, 0xE8, 0x7B, 0x29, 0x2E, 0x9E, 0x5B, 0x27, 0x93, 0x84, 0xB3, 0xB7, 0xFF, 0x51, 0xC9, 0x22, 0xFA, 0x34, 0xE6, 0x3A, 0xB2, 0x5F, 0x7E, 0x47, 0x6E, 0x93, 0x1E, 0xD9, 0x81, 0x33, 0x81, 0xA7, 0x7F, 0x59, 0xC5, 0x79, 0xB4, 0x0B, 0x56, 0x1D, 0x9C, 0x7D, 0x8B, 0x99, 0xE0, 0x4C, 0x98, 0xEF, 0xB1, 0x76, 0x5C, 0x01, 0xAF, 0xAB, 0xEA, 0xD5, 0xE2, 0xEE, 0x20, 0x5B, 0x0E, 0x64, 0x03, 0xB5, 0xEF, 0x96, 0xA8, 0x41, 0x5F, 0xDD, 0x7C, 0xAA, 0xE6, 0x43, 0x40, 0xEC, 0x4E, 0x21, 0xD9, 0x00, 0x5E, 0x19, 0xAB, 0x71, 0x1B, 0xA0, 0x4B, 0xD4, 0xBF, 0x18, 0xD5, 0xEE, 0xC2, 0x3A, 0x6A, 0x85, 0x84, 0x9D, 0x0E, 0x58, 0x42, 0xF2, 0x83, 0xAF, 0xCD, 0x14, 0xAC, 0x67, 0x5D, 0x93, 0x5F, 0x3D, 0x58, 0x71, 0x4F, 0xDB, 0xA7, 0xB9, 0xFD, 0x2E, 0xC0, 0x03, 0x08, 0x01, 0xE8, 0x81, 0x5B, 0x63, 0x0B, 0x8E, 0x6E, 0x59, 0xB7, 0xC0, 0xED, 0x2E, 0x3C, 0xE4, 0x5A, 0x79, 0xF9, 0x3B, 0x13, 0x17, 0xFB, 0x6B, 0xFB, 0xB0, 0xBB, 0x58, 0x5D, 0x68, 0xAE, 0x04, 0x52, 0x81, 0x68, 0x20, 0x37, 0xD0, 0x8F, 0xDA, 0x18, 0x4D, 0x99, 0xFB, 0x31, 0x7A, 0xD1, 0xE8, 0x77, 0x67, 0xDF, 0x5C, 0xC7, 0x6A, 0xFD, 0x57, 0xD3, 0x06, 0x9A, 0x63, 0xCD, 0xE0, 0x1A, 0x1D, 0xB9, 0x7A, 0xEC, 0xA1, 0x5C, 0xDA, 0x2B, 0x27, 0xA9, 0xCD, 0x9D, 0x49, 0x91, 0x77, 0xDF, 0x82, 0xFD, 0x74, 0xCE, 0xE3, 0x05, 0x90, 0xD7, 0x5F, 0x5E, 0x8D, 0x7B, 0xDF, 0xC2, 0x2D, 0xDE, 0xBF, 0x83, 0xE5, 0x04, 0xA2, 0x98, 0x03, 0x6E, 0x53, 0x76, 0x62, 0xCC, 0xA3, 0x45, 0xD2, 0xE2, 0x69, 0x19, 0x2A, 0xB3, 0x7E, 0xF3, 0x5F, 0xA0, 0x09, 0xFB, 0xC4, 0x84, 0xB3, 0xEE, 0xF6, 0x4C, 0x3E, 0xD0, 0x1A, 0xF8, 0x20, 0xEF, 0x20, 0xB2, 0x6E, 0x80, 0x9F, 0xBC, 0x00, 0x7D, 0x9C, 0xCB, 0xA1, 0xB7, 0x76, 0x64, 0x04, 0x8D, 0x96, 0xEB, 0xEA, 0x9C, 0x27, 0xBD, 0xBF, 0xA2, 0x6D, 0x11, 0x9D, 0x55, 0x62, 0xCA, 0x19, 0x43, 0x50, 0xEA, 0xD5, 0x82, 0x7F, 0x2F, 0x58, 0x6F, 0xFC, 0xD6, 0x1D, 0xFB, 0xA5, 0x4C, 0xF7, 0x2B, 0x0C, 0x04, 0x42, 0x81, 0x92, 0x81, 0x01, 0x2D, 0x4F, 0x77, 0xE3, 0x10, 0x7A, 0xC2, 0x6E, 0x75, 0xE0, 0xA0, 0x5B, 0xDA, 0xCF, 0x9A, 0x75, 0xD2, 0xA4, 0xE2, 0xE4, 0xA7, 0x06, 0xB5, 0x07, 0x02, 0xB0, 0xF5, 0x8F, 0x3E, 0xE2, 0x31, 0xF0, 0x06, 0x62, 0x3F, 0xCA, 0x00, 0x6F, 0xC4, 0x7F, 0x60, 0xEB, 0x5F, 0xCA, 0x00, 0xF5, 0x0E, 0xB5, 0xDC, 0x5F, 0xC2, 0xDA, 0xEE, 0x3D, 0xA3, 0x11, 0xE2, 0x61, 0xCD, 0xFC, 0x0E, 0x43, 0x1E, 0x0C, 0xFB, 0x97, 0xB6, 0xC1, 0x94, 0xCB, 0xF6, 0xA5, 0x4C, 0x97, 0xFE, 0xF8, 0x24, 0xE3, 0x14, 0xAF, 0xCA, 0x9D, 0x97, 0xD2, 0x1B, 0x26, 0x09, 0x05, 0xDA, 0xD9, 0xB1, 0x05, 0x26, 0x59, 0x57, 0x01, 0x50, 0x8C, 0x56, 0xF5, 0x14, 0x60, 0x30, 0x3D, 0x5B, 0xEA, 0x54, 0x29, 0xD6, 0x15, 0x5D, 0x99, 0x9C, 0x11, 0x56, 0x65, 0xC0, 0x61, 0x78, 0x8B, 0x79, 0x06, 0x60, 0x06, 0x48, 0x0D, 0x7C, 0xD0, 0x80, 0xD7, 0x93, 0x67, 0xBA, 0x01, 0x13, 0x60, 0xE7, 0xDD, 0x3B, 0xCC, 0x05, 0x38, 0x79, 0x4D, 0x71, 0xAC, 0xC6, 0x86, 0x66, 0x93, 0x95, 0x92, 0xA8, 0xDD, 0x56, 0x96, 0x51, 0x46, 0xCD, 0xE6, 0x1E, 0xB8, 0x4A, 0x4B, 0xC2, 0x95, 0xA3, 0x7D, 0x67, 0x96, 0xFA, 0x33, 0xD6, 0x4E, 0x16, 0xD0, 0x3E, 0x39, 0x8B, 0x77, 0x80, 0x3C, 0x15, 0x68, 0x3A, 0x2A, 0xD7, 0xAF, 0x00, 0xD8, 0x58, 0x28, 0x75, 0x4E, 0x9B, 0x52, 0x40, 0x1A, 0xCC, 0x25, 0xEB, 0x97, 0xDB, 0x89, 0xE8, 0xC1, 0x19, 0xC6, 0x7E, 0x9A, 0x35, 0xEE, 0xA7, 0x3F, 0x36, 0x77, 0x81, 0x70, 0xC0, 0x37, 0x60, 0x39, 0x68, 0x80, 0xA3, 0x4B, 0xE4, 0xFE, 0x39, 0xB3, 0x7F, 0xB5, 0xE6, 0xCA, 0xA7, 0x35, 0x97, 0x1C, 0xAB, 0xE9, 0x7D, 0xE2, 0x98, 0xA8, 0x81, 0xC9, 0x9E, 0x5F, 0x37, 0x31, 0x19, 0x7C, 0x51, 0x35, 0x66, 0xB2, 0xAA, 0x94, 0x97, 0xF6, 0xBB, 0x02, 0x48, 0xF6, 0xB3, 0x85, 0xE6, 0xD8, 0xE2, 0x78, 0xE3, 0x19, 0x15, 0x52, 0xA0, 0x9E, 0x02, 0xC3, 0xA2, 0x54, 0xF7, 0xEF, 0x8C, 0xAE, 0xEB, 0x54, 0x58, 0xC5, 0x18, 0x8F, 0x6A, 0xEE, 0xD4, 0x21, 0x9C, 0xD1, 0x75, 0xB2, 0x22, 0x9F, 0x16, 0x97, 0xB9, 0x81, 0xBD, 0x9E, 0xDE, 0x96, 0x3E, 0x58, 0x03, 0x01, 0xF2, 0x91, 0x8B, 0x89, 0x05, 0xF8, 0x40, 0x9E, 0x16, 0xA2, 0xB9, 0x80, 0xBA, 0x9C, 0xCB, 0xB0, 0x9A, 0x4D, 0x06, 0x96, 0x1F, 0xAB, 0xF9, 0x97, 0x81, 0x30, 0xC1, 0xD0, 0x70, 0x66, 0x07, 0xD0, 0xCF, 0x89, 0x55, 0x66, 0x39, 0x03, 0xC8, 0x57, 0x1B, 0x72, 0xC0, 0xE9, 0xF1, 0xD0, 0x53, 0x79, 0xD9, 0xFD, 0xC8, 0x46, 0x51, 0x5D, 0x50, 0x00, 0x4B, 0xFA, 0xDF, 0x28, 0x78, 0xC8, 0x5A, 0x80, 0x5F, 0xCD, 0x90, 0xC1, 0x5A, 0xDA, 0x73, 0xE6, 0x64, 0x21, 0x1A, 0xBD, 0x9D, 0xF0, 0x24, 0xDF, 0x1D, 0x80, 0x18, 0x4E, 0x61, 0xCA, 0x6D, 0x01, 0x66, 0x80, 0x38, 0xB0, 0xEB, 0x71, 0x78, 0xEF, 0x59, 0x41, 0x06, 0xA9, 0x40, 0x2C, 0x3E, 0x64, 0x6A, 0x25, 0x60, 0x7D, 0x77, 0xC1, 0xF4, 0xA4, 0xD1, 0xCE, 0xE1, 0xF6, 0x88, 0x97, 0x57, 0x7F, 0x2B, 0x3E, 0x6A, 0xDC, 0xAA, 0xBF, 0xBF, 0x5C, 0x88, 0x7D, 0x07, 0xF4, 0xB0, 0xEF, 0x53, 0x76, 0xEC, 0xAB, 0x77, 0xDE, 0x23, 0x24, 0x2C, 0x27, 0xA9, 0xEC, 0x8C, 0x80, 0x3D, 0x48, 0x40, 0x17, 0xB0, 0x7B, 0x20, 0x80, 0xCA, 0xB1, 0x36, 0xF5, 0x1F, 0xEE, 0x46, 0xC5, 0xA6, 0x67, 0xF7, 0x38, 0x4B, 0x90, 0x9F, 0xF5, 0xFB, 0x1C, 0xBE, 0x1E, 0xC9, 0x9C, 0xE0, 0xA7, 0x00, 0x4C, 0x00, 0x8D, 0x81, 0x0F, 0x0A, 0xF0, 0xE6, 0x82, 0x0F, 0x48, 0x0F, 0x04, 0x58, 0x1C, 0x8D, 0x0E, 0x78, 0x00, 0x79, 0x35, 0x6A, 0x85, 0xD5, 0xE2, 0x8B, 0xB1, 0x64, 0x20, 0x4E, 0x95, 0xB5, 0xE1, 0x64, 0x1B, 0x5D, 0x7E, 0xDD, 0x3D, 0xD9, 0x88, 0xFE, 0xFD, 0xD6, 0xE6, 0xF6, 0x07, 0x5F, 0x29, 0x03, 0x54, 0x6F, 0x3A, 0xAE, 0xDD, 0x69, 0x6B, 0xC5, 0xC4, 0xB1, 0x59, 0xE4, 0x44, 0xEE, 0xC0, 0x70, 0xFB, 0x2D, 0xC1, 0x77, 0xC4, 0x33, 0xEC, 0xDA, 0x49, 0x8D, 0x43, 0x87, 0x6A, 0x86, 0x94, 0xAB, 0xE8, 0x4B, 0xEA, 0xD5, 0x4F, 0xFE, 0x56, 0x37, 0x10, 0xAF, 0x48, 0xCE, 0xBE, 0xB7, 0x42, 0xD5, 0xC1, 0x1A, 0xD8, 0x7D, 0xB8, 0x95, 0xF5, 0xC8, 0xD9, 0x38, 0xB0, 0xB9, 0x5B, 0x26, 0x60, 0x7D, 0xCB, 0xFE, 0x98, 0x1D, 0xAB, 0xF1, 0xD2, 0x8E, 0x4B, 0x47, 0xE7, 0xFE, 0xC2, 0x55, 0xB6, 0xF6, 0x34, 0x18, 0x6D, 0x04, 0x9D, 0x22, 0xFE, 0x90, 0x0E, 0x83, 0xB6, 0xC7, 0xAE, 0xB4, 0xD6, 0xBF, 0x8A, 0x33, 0xB8, 0x43, 0x45, 0x8E, 0x2D, 0xF4, 0x3E, 0x63, 0xAC, 0x85, 0x4F, 0xE5, 0x40, 0x6E, 0xA0, 0xE8, 0x91, 0x95, 0x98, 0xF9, 0x53, 0xB7, 0x6A, 0x05, 0xA7, 0xBB, 0xFD, 0x5A, 0x16, 0xE5, 0x11, 0x84, 0x17, 0x1A, 0xC8, 0x00, 0xDE, 0xE4, 0xFB, 0x59, 0xCF, 0xCC, 0x01, 0xED, 0xC1, 0xF3, 0x89, 0x86, 0x5D, 0x05, 0xE8, 0x40, 0x12, 0x58, 0x7D, 0x47, 0xAE, 0x7D, 0x90, 0xB4, 0x7D, 0x1F, 0xAB, 0xD5, 0x17, 0x71, 0x8F, 0x90, 0x69, 0xB2, 0x9B, 0x88, 0x1D, 0xAC, 0x44, 0x25, 0xA4, 0xA1, 0xAD, 0xA5, 0x6E, 0x47, 0x2E, 0x80, 0x35, 0x52, 0x8A, 0x53, 0x98, 0x86, 0x4B, 0xEB, 0xDD, 0x37, 0x03, 0x5E, 0xE1, 0xED, 0x49, 0xB7, 0xE3, 0x27, 0xCF, 0x07, 0x3D, 0xA6, 0x3C, 0x6D, 0xEF, 0x16, 0x13, 0xAC, 0xE9, 0x0C, 0x05, 0x92, 0x1D, 0x96, 0xB8, 0x5A, 0x8D, 0xF1, 0xE8, 0x68, 0xE7, 0xB5, 0x55, 0x6E, 0xCD, 0xE0, 0xB0, 0xA7, 0x30, 0x66, 0xDD, 0x49, 0x98, 0x5D, 0xFC, 0x04, 0x48, 0x01, 0xB5, 0xEF, 0xFE, 0x83, 0xCB, 0xF9, 0x10, 0x30, 0xBD, 0x17, 0x14, 0xF5, 0x79, 0xC5, 0x8E, 0xD5, 0xFA, 0xAF, 0x36, 0xC4, 0x35, 0x65, 0x2A, 0xCF, 0xAC, 0x21, 0xBF, 0x8C, 0xEA, 0xFD, 0x8D, 0xE1, 0x30, 0xCD, 0xB9, 0x78, 0x4F, 0xB0, 0xBD, 0x6F, 0x8F, 0xC7, 0xE5, 0xC9, 0xBD, 0x8E, 0x6B, 0x69, 0xB7, 0xE8, 0xAA, 0x24, 0x60, 0x0A, 0xC8, 0x51, 0xE3, 0x1C, 0xD8, 0x2F, 0x13, 0x83, 0x9A, 0x72, 0x6C, 0xC0, 0xC2, 0x4C, 0xD8, 0x1E, 0x53, 0xC6, 0x2D, 0x47, 0xD2, 0xA7, 0xDD, 0x7D, 0x0F, 0xD4, 0x07, 0x06, 0xC8, 0x06, 0x16, 0x57, 0x84, 0x22, 0xE6, 0xA1, 0x02, 0x3A, 0xA8, 0x73, 0xDA, 0x03, 0xB6, 0xF3, 0x21, 0xE0, 0x0B, 0x90, 0x0D, 0x68, 0xCD, 0x2B, 0xC7, 0x6A, 0x85, 0x78, 0x5E, 0x2C, 0xC3, 0x75, 0x23, 0x13, 0x0D, 0x2A, 0x96, 0xC1, 0x49, 0xFC, 0xAD, 0x79, 0x8C, 0x21, 0xD8, 0x37, 0x0E, 0xE1, 0x63, 0xF6, 0xBE, 0x5B, 0x91, 0xEB, 0x13, 0x42, 0x36, 0x1D, 0xAB, 0x51, 0xC8, 0xB8, 0x38, 0x82, 0x1A, 0x08, 0x07, 0xF8, 0x90, 0xE6, 0x32, 0xAA, 0x6E, 0xF0, 0x7E, 0x4E, 0x79, 0x4C, 0xE0, 0xD6, 0xCB, 0xDD, 0x3D, 0xA7, 0x18, 0xBF, 0x45, 0x95, 0xFB, 0xE4, 0xD3, 0x1A, 0x6D, 0x68, 0x80, 0x25, 0xB0, 0x8D, 0x76, 0x1A, 0xAC, 0xC7, 0x6A, 0x02, 0x94, 0xD0, 0x16, 0xC0, 0xCA, 0x79, 0xE8, 0x80, 0x0B, 0x20, 0x0D, 0x18, 0x0D, 0x2B, 0xC7, 0x6A, 0xE8, 0xF8, 0xB0, 0x9A, 0xFD, 0x7F, 0x98, 0x73, 0xA4, 0x08, 0x33, 0x4C, 0xDD, 0xB6, 0x4B, 0x4D, 0x37, 0xE5, 0x18, 0xE7, 0x72, 0xB0, 0xBC, 0xFD, 0x6E, 0x6F, 0xC9, 0x11, 0x7C, 0x1C, 0x36, 0x9C, 0x69, 0x9B, 0xA2, 0xA2, 0x1B, 0xC8, 0x00, 0xBA, 0x67, 0x3C, 0x19, 0x10, 0x71, 0xBA, 0xC4, 0x9C, 0xA2, 0x65, 0x15, 0x8A, 0x3D, 0xC2, 0x78, 0xBA, 0x8E, 0xBF, 0x9F, 0xDD, 0xE0, 0x97, 0x8F, 0x99, 0xC7, 0x86, 0x55, 0x3C, 0x17, 0x3E, 0x47, 0x0E, 0x05, 0x56, 0x30, 0x8F, 0x69, 0xB0, 0x06, 0x75, 0x0B, 0xDE, 0x56, 0xD0, 0x8B, 0x03, 0xB0, 0x29, 0x63, 0x0F, 0x9C, 0x6F, 0x3A, 0xE0, 0x74, 0x72, 0x19, 0xAD, 0x26, 0x7F, 0xF1, 0x99, 0x7B, 0xE3, 0x70, 0x50, 0xE8, 0x10, 0x2D, 0xA3, 0xDD, 0xE1, 0x6A, 0x93, 0x1C, 0x12, 0xF8, 0xB6, 0x5A, 0xD3, 0x55, 0xBD, 0x28, 0xAD, 0x76, 0xCB, 0x50, 0xAC, 0x9F, 0xC2, 0xFE, 0x76, 0x46, 0x90, 0x8F, 0xE3, 0xC2, 0x8C, 0x8E, 0x55, 0x40, 0x0B, 0x30, 0x01, 0xAA, 0xA6, 0x8E, 0x3F, 0x61, 0x2D, 0x61, 0x86, 0x60, 0x01, 0x99, 0xB0, 0x5D, 0xF6, 0x18, 0x94, 0xED, 0x68, 0x58, 0xF6, 0x31, 0xB3, 0x9D, 0xA7, 0x28, 0xE1, 0xF7, 0xB4, 0xDB, 0x4C, 0xBE, 0x00, 0x75, 0x40, 0x1A, 0x50, 0x05, 0x72, 0xDD, 0x16, 0x49, 0x05, 0x82, 0x0F, 0x59, 0xD7, 0x95, 0x80, 0x3B, 0x90, 0x94, 0xE7, 0x0D, 0x1A, 0x4D, 0x71, 0x0B, 0xD5, 0x89, 0x53, 0x75, 0xA3, 0x6E, 0x4F, 0x75, 0xD4, 0x98, 0x14, 0x51, 0xA3, 0xC2, 0x27, 0xF6, 0xE7, 0x73, 0xB8, 0xBF, 0xCB, 0xFF, 0xE1, 0x92, 0xFC, 0x4D, 0xD0, 0x75, 0x94, 0xCD, 0x29, 0xDB, 0x02, 0x6C, 0xEA, 0x48, 0x0C, 0xA2, 0x81, 0x32, 0x2E, 0x79, 0x74, 0x5C, 0xDF, 0xD5, 0xF9, 0xB6, 0xF0, 0x90, 0x72, 0x2F, 0x0C, 0xA7, 0xC4, 0x3A, 0x11, 0xFA, 0x33, 0x8B, 0xE2, 0x94, 0x2C, 0xAC, 0x3D, 0x58, 0xF7, 0x65, 0xB4, 0x74, 0x20, 0x83, 0xBA, 0xCF, 0x42, 0xC5, 0x8A, 0xC6, 0xC1, 0xD6, 0x7B, 0x82, 0xDA, 0x06, 0xF6, 0x35, 0x4F, 0x79, 0x8D, 0x83, 0xD5, 0xEC, 0xDB, 0x34, 0xC3, 0x05, 0xBF, 0x60, 0xC7, 0x57, 0x73, 0x16, 0x59, 0x4C, 0xE9, 0x9A, 0x0C, 0x13, 0x9D, 0xF0, 0x89, 0x4F, 0x86, 0x49, 0x5C, 0x07, 0x8F, 0xBC, 0x43, 0x2D, 0x76, 0xAE, 0x9F, 0xAD, 0xEB, 0x16, 0x7C, 0x6E, 0x3A, 0x33, 0x63, 0xE0, 0x83, 0x05, 0x50, 0xF3, 0xC6, 0x2E, 0x4D, 0x73, 0x9B, 0x20, 0x2A, 0xA5, 0xAF, 0x29, 0xE8, 0xDE, 0x47, 0x89, 0x21, 0x9D, 0x97, 0x51, 0x1E, 0x87, 0xB1, 0x35, 0x08, 0xE0, 0x01, 0xA8, 0x03, 0xDB, 0x80, 0xD5, 0x83, 0x02, 0xB6, 0x02, 0x76, 0x0A, 0x22, 0x37, 0xA0, 0x09, 0x48, 0x00, 0x4B, 0xD9, 0x50, 0x9D, 0x37, 0xE9, 0xBB, 0x49, 0xA1, 0x9C, 0xB1, 0xE6, 0x7F, 0xF5, 0x79, 0xA4, 0x0A, 0xBF, 0xB5, 0xFB, 0xD7, 0xB4, 0x68, 0xA9, 0x8D, 0x6C, 0x4B, 0x21, 0xD6, 0x66, 0x14, 0x63, 0xF1, 0x69, 0xC8, 0x6A, 0xB7, 0x16, 0xBF, 0x5F, 0x55, 0xA1, 0xAC, 0xEC, 0x3D, 0x7D, 0x73, 0xED, 0x7C, 0xD1, 0x48, 0x0E, 0x16, 0x60, 0xE5, 0xDD, 0xA3, 0x54, 0x18, 0x57, 0xB6, 0xF1, 0x97, 0x6F, 0x98, 0x2B, 0x16, 0xC0, 0x66, 0xF3, 0x27, 0x1B, 0x9E, 0xB3, 0xD0, 0x61, 0x27, 0xBF, 0xB3, 0x92, 0x2C, 0x01, 0x5E, 0xE8, 0xD3, 0x01, 0x0B, 0x40, 0x09, 0xBB, 0x3F, 0xC5, 0xD3, 0x4A, 0xDA, 0x13, 0xB0, 0x81, 0x6C, 0x76, 0x37, 0x00, 0x7C, 0x90, 0x7A, 0xBC, 0x28, 0xB4, 0x5A, 0xA0, 0xD3, 0x43, 0x27, 0x42, 0x24, 0x1B, 0x5B, 0xA8, 0xC4, 0x9E, 0x32, 0x1E, 0x0C, 0xB2, 0xF4, 0x64, 0xEF, 0x49, 0x98, 0xE0, 0x5E, 0xD6, 0xAE, 0x14, 0x0F, 0x9E, 0x7B, 0x28, 0x7E, 0x78, 0xBB, 0x82, 0xE2, 0xED, 0xB9, 0x16, 0x78, 0xD8, 0x41, 0x3D, 0x93, 0x5F, 0xDC, 0x32, 0x4E, 0xAA, 0xBB, 0x3A, 0x00, 0x13, 0xD6, 0x91, 0xA2, 0x0E, 0x76, 0x18, 0xF5, 0x9F, 0x3B, 0xC0, 0xCE, 0x15, 0xD3, 0x64, 0xA0, 0x80, 0x3A, 0x20, 0xFB, 0x81, 0x00, 0xBA, 0x81, 0x53, 0xF1, 0x29, 0x40, 0x39, 0x90, 0x0A, 0x18, 0xB7, 0x84, 0x06, 0x22, 0x81, 0xF3, 0xCA, 0x19, 0x6A, 0xF9, 0xE5, 0x76, 0x78, 0xFC, 0x62, 0x06, 0x5F, 0x60, 0x76, 0xFA, 0x43, 0x2F, 0xA3, 0x32, 0x15, 0x9C, 0xFC, 0x2B, 0x61, 0x90, 0x08, 0x8A, 0x93, 0x5E, 0x92, 0x61, 0x92, 0xCF, 0xAA, 0x26, 0x8C, 0x23, 0xEB, 0x9D, 0xA0, 0x28, 0x09, 0x58, 0x03, 0x19, 0x3F, 0xBD, 0x17, 0x86, 0x05, 0x98, 0x51, 0xD0, 0x30, 0xA8, 0x32, 0x01, 0x94, 0x4A, 0x3D, 0x7A, 0xDA, 0xE4, 0x1D, 0x6F, 0xB9, 0x5C, 0xFD, 0x97, 0x7E, 0xFD, 0x51, 0x81, 0x25, 0xD7, 0x04, 0xF3, 0x0D, 0x58, 0xDE, 0x9F, 0x6A, 0x3D, 0xFE, 0xAB, 0x30, 0xC0, 0x1D, 0x50, 0x03, 0xA8, 0xA0, 0x5E, 0xC0, 0xB9, 0xC0, 0x84, 0xD3, 0x68, 0x53, 0x5E, 0xC0, 0x1F, 0x4F, 0xC7, 0xDF, 0xB8, 0x6D, 0xAA, 0x4C, 0x74, 0x32, 0x61, 0x74, 0x72, 0x92, 0x1A, 0xB3, 0xC5, 0xFC, 0x57, 0xCF, 0x52, 0x79, 0xB5, 0x3A, 0x66, 0x71, 0xF0, 0x11, 0xBB, 0xB1, 0x13, 0x74, 0xAD, 0xF1, 0x5E, 0xFB, 0x06, 0xCC, 0x00, 0xD9, 0x80, 0x7E, 0xA8, 0xD3, 0x0A, 0xB1, 0x27, 0xCE, 0xD2, 0x05, 0xB8, 0xE3, 0xA1, 0xF6, 0xFC, 0xDC, 0x07, 0x3D, 0x77, 0x86, 0x53, 0x67, 0xB7, 0x19, 0xD7, 0x07, 0x78, 0x14, 0xE9, 0x06, 0x92, 0x88, 0x1B, 0xE5, 0xF3, 0xA6, 0x02, 0xD5, 0x9C, 0x11, 0x83, 0x27, 0x57, 0xC0, 0x0D, 0x10, 0xBF, 0x7B, 0xC2, 0x4A, 0xD3, 0x68, 0xFD, 0xA5, 0xFB, 0x95, 0xE5, 0x95, 0x7B, 0xD5, 0xDB, 0xB0, 0x7E, 0x6D, 0x9D, 0x06, 0xCD, 0x75, 0x92, 0x40, 0xA4, 0x39, 0x3D, 0x2D, 0x1F, 0x29, 0x0A, 0x96, 0xBC, 0xDA, 0xD3, 0x29, 0x23, 0x18, 0x6D, 0x9C, 0x94, 0xF5, 0xFD, 0x60, 0xE5, 0xAF, 0xD3, 0x60, 0x8F, 0x73, 0x48, 0x61, 0x5D, 0x43, 0x9D, 0x32, 0xE0, 0x14, 0xFE, 0xC6, 0x2B, 0xBE, 0x61, 0xC8, 0xE3, 0x74, 0xB3, 0x5B, 0xA6, 0xC2, 0x38, 0x81, 0xE3, 0x6E, 0x46, 0xE8, 0x0E, 0xD8, 0xA6, 0xAD, 0x01, 0x33, 0xA0, 0x6C, 0xFE, 0xA8, 0x0B, 0xE8, 0x41, 0x0D, 0xDC, 0x81, 0x1D, 0xF3, 0x66, 0xDC, 0x1D, 0x0A, 0x4F, 0x69, 0xE3, 0x74, 0xB6, 0x0B, 0x8D, 0xEB, 0x7C, 0xBB, 0x2A, 0x27, 0x3B, 0xCA, 0x26, 0x69, 0x3A, 0x66, 0xAE, 0x32, 0x74, 0xD2, 0xD7, 0x40, 0x93, 0x27, 0x6B, 0x6D, 0x71, 0xAD, 0x57, 0x61, 0x0E, 0xD1, 0x64, 0x05, 0x9C, 0x58, 0x3F, 0x90, 0x83, 0xAA, 0x9F, 0x9F, 0xAC, 0x8E, 0xAC, 0xB7, 0x4E, 0x26, 0x94, 0xFC, 0x42, 0x8F, 0xA7, 0x9F, 0x23, 0x75, 0xBC, 0x18, 0x97, 0x56, 0xA6, 0x11, 0xE2, 0xD3, 0xA9, 0x8D, 0xA9, 0x93, 0xD4, 0xBE, 0xA9, 0x2D, 0x57, 0x80, 0xFB, 0xC0, 0x06, 0x7D, 0xCB, 0x02, 0x78, 0x00, 0x2D, 0x40, 0x19, 0x10, 0xEB, 0x6E, 0x60, 0x72, 0xE4, 0xEA, 0x07, 0x6D, 0x34, 0xDA, 0x4F, 0xE4, 0x5B, 0xA0, 0xA2, 0x50, 0xE8, 0xA1, 0x87, 0x11, 0xE6, 0xF6, 0x39, 0x06, 0x64, 0x1B, 0x3C, 0x02, 0x25, 0x9F, 0xCB, 0x44, 0xDC, 0x2F, 0x25, 0x61, 0xE7, 0xF4, 0x5C, 0xC7, 0x61, 0x7A, 0xD7, 0x00, 0x58, 0x0F, 0x1C, 0x10, 0xDE, 0x9F, 0x0D, 0x88, 0x1A, 0xD8, 0x5D, 0x2D, 0x70, 0x9C, 0xF3, 0x06, 0xEC, 0xBC, 0xFB, 0xFE, 0x2F, 0xBF, 0xFD, 0xD2, 0xC6, 0xA4, 0xDC, 0xC4, 0xA7, 0xB5, 0x01, 0x1D, 0x98, 0x00, 0x6A, 0x83, 0x3D, 0x90, 0x81, 0x03, 0x1E, 0x77, 0x8C, 0x53, 0x02, 0xD8, 0x8F, 0x2C, 0x65, 0xEE, 0xC7, 0xE9, 0xBB, 0x8E, 0x33, 0x87, 0x56, 0x83, 0x9D, 0xD2, 0xE4, 0xCF, 0x67, 0x5D, 0x8E, 0xEF, 0x88, 0xE6, 0x58, 0xC1, 0x3B, 0xA0, 0x73, 0x5E, 0x93, 0xAE, 0x23, 0x8A, 0x13, 0x5E, 0x1A, 0xDD, 0x90, 0xB7, 0xD6, 0x37, 0xE3, 0xB6, 0xEC, 0x4F, 0xD6, 0x1F, 0xE0, 0x0B, 0xBB, 0x2B, 0x06, 0xA5, 0xB1, 0xA6, 0x3E, 0x27, 0xA0, 0x5D, 0x40, 0xD3, 0xB1, 0x76, 0x94, 0xF9, 0x8E, 0x76, 0x25, 0xCB, 0x60, 0xAF, 0x1E, 0x4A, 0x2A, 0x4F, 0xAF, 0x29, 0x19, 0xF8, 0xDD, 0xE1, 0x88, 0x9F, 0xD2, 0x06, 0x0D, 0x94, 0x01, 0xCD, 0x62, 0x65, 0x03, 0x8A, 0xFD, 0xAB, 0x0A, 0xD8, 0x31, 0x0F, 0x1B, 0xB0, 0x02, 0xB6, 0x03, 0x77, 0xAA, 0x2B, 0xAC, 0xA6, 0x67, 0xAC, 0xE5, 0x82, 0x27, 0x83, 0x9F, 0x76, 0x22, 0xF3, 0xFB, 0xEB, 0x1E, 0x54, 0x10, 0x89, 0x59, 0x0B, 0x9F, 0x02, 0xBA, 0xF2, 0xEA, 0x74, 0xAC, 0x05, 0xAD, 0xC6, 0x9C, 0x62, 0xFA, 0x3A, 0x1D, 0xF0, 0x00, 0xAC, 0x9E, 0xBF, 0xE8, 0x7A, 0x42, 0xD9, 0xEC, 0xC7, 0x26, 0x9C, 0xE0, 0xD4, 0x03, 0x00, 0x4C, 0xFF, 0xD5, 0x0D, 0xCE, 0xEE, 0x40, 0x9B, 0xD8, 0x20, 0x81, 0x90, 0x7B, 0x94, 0x84, 0xFE, 0x87, 0xD6, 0x37, 0xD3, 0x6E, 0x06, 0xA9, 0x40, 0xC8, 0xFD, 0x70, 0xF1, 0x4D, 0x9D, 0x4F, 0xEB, 0x8D, 0xE8, 0xB5, 0x7D, 0x55, 0xB4, 0xE6, 0x38, 0xA2, 0x85, 0xA3, 0x7E, 0x7B, 0x45, 0x61, 0x59, 0x5B, 0x01, 0xD1, 0x94, 0xA9, 0x48, 0x17, 0x6D, 0x38, 0x57, 0x50, 0xB1, 0x6D, 0xF9, 0x8E, 0xB5, 0x1D, 0xBF, 0x40, 0x45, 0x8E, 0x65, 0x8A, 0x82, 0x09, 0xE7, 0x53, 0x27, 0x10, 0x8F, 0x4E, 0x84, 0x51, 0xA9, 0x39, 0x4F, 0x8F, 0x2A, 0xAA, 0xAE, 0x01, 0xFE, 0xAB, 0x92, 0x66, 0x7D, 0x5E, 0x33, 0x34, 0x7C, 0xFC, 0x9E, 0x2A, 0x80, 0xCD, 0x43, 0xDD, 0x40, 0x2F, 0x5E, 0x8D, 0x00, 0x49, 0x40, 0x0D, 0xB0, 0x41, 0x31, 0x0A, 0xEB, 0x40, 0x05, 0x90, 0x09, 0x58, 0xDF, 0x72, 0xD1, 0x39, 0xE0, 0xEC, 0x49, 0x3F, 0x56, 0x73, 0xE4, 0x10, 0x8D, 0x1E, 0xA2, 0x35, 0x66, 0xE8, 0x5A, 0x8E, 0x75, 0x5B, 0x03, 0x27, 0x68, 0x85, 0x25, 0x24, 0x02, 0xBE, 0x92, 0x5A, 0xB4, 0xDA, 0x33, 0xD6, 0x6A, 0xAC, 0xC6, 0x5F, 0xDF, 0xC7, 0x5C, 0x03, 0x37, 0x40, 0x0B, 0xA0, 0x8F, 0x32, 0x06, 0x96, 0x47, 0x56, 0x83, 0x93, 0x91, 0x17, 0x25, 0xE0, 0x1C, 0xA8, 0x7C, 0x1D, 0x6B, 0x27, 0xF3, 0xC0, 0x8F, 0xB3, 0xD0, 0x1F, 0xD7, 0x21, 0x67, 0xE1, 0xF2, 0x41, 0x0C, 0x1A, 0xD8, 0x32, 0x28, 0xC0, 0x0C, 0xE8, 0x78, 0x42, 0xA5, 0x6B, 0x1E, 0x16, 0x10, 0x06, 0x98, 0x00, 0x9E, 0xF3, 0x8A, 0x1C, 0xAB, 0xC5, 0xA7, 0x24, 0x5F, 0xD9, 0xDF, 0x25, 0xCA, 0x7D, 0x7F, 0xCE, 0xC9, 0x52, 0x9D, 0x16, 0x28, 0x82, 0x5F, 0x62, 0xF7, 0xDC, 0x7F, 0x37, 0x52, 0x14, 0x63, 0x53, 0xBF, 0xE3, 0xE9, 0xFC, 0x70, 0x35, 0x04, 0x84, 0x0B, 0xE3, 0x5A, 0x59, 0xEA, 0x69, 0xE7, 0xE9, 0x0D, 0x58, 0xDC, 0xFD, 0x29, 0xF9, 0xD7, 0x76, 0xE7, 0x90, 0xCB, 0x01, 0x0B, 0xA9, 0x03, 0x7F, 0xF4, 0x79, 0x93, 0xE9, 0xB8, 0xA7, 0xAD, 0xE0, 0x06, 0x44, 0x80, 0xD8, 0x40, 0xC9, 0x60, 0x3D, 0x9F, 0x0C, 0xE8, 0x75, 0x1B, 0x2F, 0xF5, 0x91, 0x5E, 0xA9, 0xE7, 0x2A, 0xC6, 0x37, 0x1D, 0xD0, 0x41, 0xF7, 0xB1, 0x5A, 0x7E, 0x63, 0x2D, 0x5C, 0xD1, 0x6E, 0xB7, 0xE5, 0x9B, 0xA1, 0xD9, 0xAC, 0x15, 0x73, 0x24, 0x11, 0xD7, 0x9E, 0xEE, 0x49, 0x93, 0x19, 0xA1, 0xEB, 0xB6, 0x9A, 0x3D, 0x5D, 0x2E, 0xE3, 0xF8, 0x06, 0xEE, 0xBE, 0xA5, 0x96, 0x80, 0x0E, 0x36, 0x13, 0x16, 0x02, 0x78, 0xAA, 0x2A, 0xF4, 0xE4, 0x1E, 0x75, 0x00, 0x8C, 0x7C, 0x9E, 0xB3, 0x3F, 0x93, 0xE8, 0xEF, 0x5A, 0x35, 0xDF, 0x80, 0xC6, 0xD3, 0x12, 0x4F, 0x1E, 0xE4, 0xA0, 0x01, 0x49, 0xE0, 0xFC, 0x9E, 0x09, 0x44, 0x01, 0x9E, 0xF7, 0xE4, 0x2F, 0x07, 0x7C, 0x03, 0xA7, 0xF4, 0x4B, 0x8F, 0xD5, 0xEA, 0x6A, 0x2F, 0xA2, 0x89, 0x32, 0xC7, 0xEA, 0x9A, 0x6E, 0x77, 0x1B, 0x7B, 0x7D, 0x07, 0xB2, 0x3D, 0x05, 0xFD, 0x32, 0x22, 0xFD, 0x56, 0x3D, 0xB9, 0x13, 0xB0, 0x84, 0xA9, 0x78, 0x03, 0xDC, 0xD7, 0x81, 0x78, 0xFE, 0x78, 0xEB, 0xEE, 0x8A, 0xCB, 0x57, 0x34, 0x7E, 0x42, 0xD3, 0x75, 0x1C, 0xA7, 0x61, 0xBF, 0x6F, 0x6F, 0x47, 0x32, 0xA0, 0xED, 0x6E, 0x1A, 0xA2, 0x01, 0x98, 0x01, 0xE5, 0x40, 0x27, 0x50, 0x3D, 0xF0, 0x1B, 0x4C, 0xEC, 0xD8, 0xF1, 0x1F, 0xBD, 0x41, 0xEB, 0x51, 0xAE, 0x77, 0x40, 0x14, 0x68, 0x3B, 0x56, 0xEB, 0xAF, 0xF3, 0x83, 0x35, 0x54, 0x71, 0xAB, 0x36, 0xB6, 0x52, 0x4B, 0xDC, 0xA6, 0x77, 0xC1, 0x83, 0x51, 0x85, 0x94, 0x62, 0xD1, 0x69, 0x00, 0x6B, 0x9F, 0xD5, 0xFC, 0xD5, 0x95, 0x17, 0xB9, 0x7B, 0x83, 0xEE, 0x78, 0x84, 0xB5, 0x37, 0x90, 0x02, 0x58, 0x00, 0xFB, 0x72, 0x71, 0x41, 0xAD, 0xEB, 0xAE, 0xF6, 0xCF, 0x05, 0xE8, 0x4F, 0xF1, 0xA0, 0x8E, 0x0D, 0xF9, 0x45, 0xF9, 0xED, 0x6B, 0x01, 0x9E, 0x40, 0xBE, 0xF9, 0x54, 0x0B, 0x88, 0x20, 0xEE, 0x87, 0x1D, 0x77, 0xA7, 0xD0, 0x12, 0x20, 0xF7, 0xFD, 0x70, 0x0B, 0x13, 0xD5, 0x68, 0x58, 0xE0, 0xEC, 0x06, 0xF8, 0x2A, 0x58, 0x33, 0xD1, 0xDE, 0x28, 0x1D, 0x2E, 0xDD, 0x36, 0x44, 0xC2, 0x53, 0xF1, 0xFD, 0x74, 0x8F, 0xDE, 0x4D, 0xCC, 0x7C, 0xD5, 0x7F, 0xF4, 0xA1, 0x15, 0xBD, 0x83, 0x53, 0xCE, 0xE0, 0x94, 0x02, 0xD2, 0x77, 0x14, 0xA3, 0x37, 0x10, 0x7E, 0xA7, 0x42, 0x25, 0x0B, 0x79, 0xE8, 0xB2, 0xF4, 0x0D, 0xD8, 0x89, 0x0D, 0x5C, 0x8D, 0x1A, 0xBD, 0xEE, 0xE0, 0xC9, 0x5E, 0x03, 0x05, 0xF2, 0xE9, 0xD7, 0xAB, 0x0E, 0x98, 0x0D, 0x0A, 0x70, 0xBB, 0x9B, 0x82, 0xAA, 0x3F, 0x7A, 0x6B, 0x03, 0x7D, 0x5A, 0x19, 0xD4, 0xA0, 0x95, 0x7B, 0xD8, 0xB1, 0x1A, 0xBA, 0x81, 0xB6, 0xC6, 0xD4, 0x79, 0xA3, 0xF3, 0xC3, 0xAE, 0x98, 0x64, 0xC6, 0xC6, 0xCE, 0x3F, 0xBD, 0x7C, 0xF3, 0x64, 0xE5, 0xF6, 0x9D, 0xFA, 0xFD, 0xD6, 0xD2, 0x9A, 0x5C, 0x7E, 0x04, 0x3D, 0x15, 0xC8, 0x22, 0x80, 0x02, 0x97, 0x5B, 0x1E, 0x9F, 0xE8, 0xF8, 0x67, 0xEB, 0x7F, 0xF9, 0xD5, 0xBC, 0xDB, 0x89, 0x37, 0x94, 0xDF, 0x31, 0x2A, 0xFE, 0xB8, 0xC6, 0x2D, 0x53, 0x61, 0x83, 0xEE, 0xBB, 0x81, 0xB2, 0x09, 0xE0, 0x7B, 0x60, 0x4F, 0x13, 0xBD, 0x75, 0x27, 0x20, 0x2C, 0x06, 0x0D, 0x07, 0xB9, 0x00, 0x66, 0xAA, 0x37, 0x7F, 0xA0, 0x81, 0x6A, 0x5A, 0x4D, 0xD0, 0x7A, 0xD0, 0x7A, 0x7E, 0xDD, 0xFD, 0x5D, 0x97, 0x5B, 0x0A, 0x2E, 0xFE, 0xCA, 0x69, 0x8F, 0x00, 0xAB, 0xA9, 0xDA, 0xA4, 0x46, 0xC4, 0xBF, 0x8A, 0x33, 0xD6, 0x53, 0x15, 0x5A, 0xAC, 0x43, 0xA5, 0x7C, 0x44, 0x03, 0xED, 0x40, 0x1A, 0x60, 0x3A, 0x48, 0xEA, 0x91, 0xD3, 0x6F, 0xF6, 0x14, 0x7F, 0x31, 0x97, 0xA3, 0xEE, 0xAA, 0xAB, 0x28, 0xEE, 0x1B, 0xB7, 0x7E, 0xB5, 0x28, 0xE0, 0x0B, 0x08, 0x7D, 0xD0, 0x40, 0x0A, 0xF0, 0xF6, 0xA4, 0x48, 0x7B, 0x7A, 0x18, 0xE8, 0xDD, 0x14, 0xD4, 0x0C, 0xD8, 0x05, 0xE8, 0x31, 0x1E, 0xAD, 0xA6, 0xC8, 0x51, 0x68, 0xC1, 0x6F, 0x6D, 0x02, 0xB1, 0xD5, 0x08, 0xE6, 0xFE, 0xC1, 0xED, 0xBA, 0xF7, 0x68, 0x42, 0xE5, 0xB8, 0xC6, 0x9C, 0xF1, 0x95, 0x5B, 0x23, 0x9D, 0xF5, 0x8D, 0x42, 0xA7, 0xB7, 0xF3, 0xCA, 0x4B, 0xA7, 0x63, 0x01, 0x16, 0xC0, 0xA6, 0x74, 0x9D, 0x01, 0xE1, 0x78, 0xC8, 0xB2, 0x68, 0x4A, 0x6B, 0x5A, 0xDD, 0xC2, 0xFD, 0x59, 0x30, 0x5E, 0x38, 0x8D, 0x77, 0x7B, 0x84, 0x96, 0xFE, 0x3C, 0x8A, 0x7E, 0x0C, 0x5B, 0x74, 0x17, 0x6F, 0x60, 0x27, 0x20, 0xF1, 0x48, 0xFC, 0x35, 0x1D, 0x43, 0x80, 0x6F, 0xC0, 0x04, 0x90, 0x06, 0x96, 0x3C, 0x6A, 0x4E, 0x45, 0xA5, 0x3D, 0x5A, 0xCD, 0xBE, 0x19, 0xAA, 0x5D, 0x10, 0xF9, 0x90, 0x44, 0x47, 0x83, 0xB6, 0x69, 0x2A, 0xAA, 0x33, 0x0B, 0x1A, 0x96, 0x28, 0x40, 0x70, 0x37, 0xE8, 0x13, 0xD2, 0xDB, 0x4F, 0x48, 0x6F, 0xAD, 0xB7, 0x0F, 0x6D, 0x00, 0x5D, 0x40, 0x25, 0xA0, 0x36, 0xE3, 0x50, 0x00, 0xA3, 0x34, 0x55, 0x8C, 0x99, 0x8F, 0x92, 0x22, 0x43, 0x9F, 0xFC, 0x4D, 0xE7, 0xCD, 0x66, 0x36, 0xC3, 0xD5, 0x81, 0xA4, 0x7B, 0x01, 0x27, 0xF1, 0x8B, 0x23, 0xAF, 0x01, 0x37, 0x20, 0xD7, 0x20, 0x80, 0x8A, 0x5B, 0xF7, 0xBF, 0x16, 0x07, 0xEE, 0x1D, 0x03, 0x2C, 0x05, 0xCC, 0xEF, 0x51, 0xA9, 0x32, 0xAF, 0x38, 0xAD, 0xE6, 0xB8, 0x14, 0xB8, 0xE3, 0x8B, 0x45, 0x7C, 0x2E, 0x9A, 0xA4, 0xB4, 0xCE, 0x04, 0x0E, 0xB2, 0x1C, 0xD9, 0xD9, 0x2B, 0xF1, 0x8A, 0xF7, 0x4F, 0x8E, 0x3F, 0xF5, 0x11, 0xAE, 0xB6, 0x66, 0xB8, 0x90, 0x5D, 0x00, 0x39, 0x48, 0x36, 0x50, 0x0D, 0x44, 0x01, 0xE6, 0x80, 0xF7, 0x2F, 0x2D, 0x6B, 0x2C, 0x09, 0x19, 0x1C, 0x80, 0xE1, 0x3E, 0xBC, 0x62, 0x4F, 0xC9, 0x42, 0x1D, 0x05, 0x99, 0xCD, 0x1A, 0x74, 0x96, 0xFD, 0x15, 0xA0, 0x7A, 0x8F, 0x1C, 0xD7, 0x41, 0xDF, 0x02, 0x09, 0xAB, 0x81, 0xA8, 0x5B, 0x15, 0xBD, 0x0B, 0xC8, 0x00, 0x6C, 0x03, 0x3B, 0x00, 0x3D, 0x4E, 0x64, 0x1A, 0x2D, 0x3E, 0xF9, 0x26, 0xEB, 0x46, 0x2A, 0xA7, 0x22, 0xF3, 0x5B, 0xAD, 0x10, 0x9D, 0x8C, 0x3D, 0x9B, 0x56, 0xCF, 0xF6, 0xE6, 0xDF, 0xE1, 0x74, 0x55, 0x20, 0x94, 0xF7, 0xCF, 0x56, 0xEE, 0xDC, 0x18, 0xE9, 0xD6, 0xE8, 0x5A, 0xB7, 0x4F, 0x3A, 0x1C, 0x70, 0x03, 0x6C, 0x03, 0x21, 0xBF, 0x65, 0xDC, 0x4E, 0xDF, 0x81, 0xE6, 0x57, 0x5B, 0xBF, 0x19, 0xC6, 0x10, 0xD7, 0xE4, 0xE8, 0xF6, 0xB5, 0xCF, 0x5D, 0xA7, 0xD4, 0x6A, 0xA0, 0x7D, 0xB0, 0x07, 0x32, 0xB0, 0x3B, 0xE5, 0x44, 0x07, 0xE5, 0xF4, 0xBB, 0x3C, 0xC7, 0xEF, 0x06, 0xDC, 0x01, 0x69, 0xC0, 0xF8, 0x26, 0x93, 0xFD, 0x90, 0x06, 0xF9, 0x85, 0xB1, 0x64, 0x8A, 0x8A, 0xF4, 0x2B, 0x60, 0x48, 0xB7, 0xAB, 0x40, 0xB5, 0xC3, 0x51, 0x8C, 0xB4, 0x85, 0x7E, 0x3C, 0x5A, 0xE9, 0x8A, 0x18, 0x98, 0x9D, 0xB6, 0x45, 0x2C, 0x93, 0xBD, 0x0B, 0x0C, 0xD7, 0x40, 0xB9, 0xC2, 0x37, 0x60, 0x05, 0xD0, 0xCD, 0x9A, 0x1F, 0x10, 0xA6, 0x44, 0x91, 0x0E, 0xB5, 0x59, 0x64, 0x1E, 0xDA, 0xCF, 0x2F, 0x4B, 0x6D, 0x9D, 0x38, 0x0E, 0x6E, 0x5E, 0xF6, 0x8B, 0x8A, 0xFD, 0xC1, 0xE8, 0x17, 0xA0, 0x0B, 0xB0, 0x06, 0x7C, 0x90, 0x4F, 0x4B, 0xDE, 0x7A, 0x44, 0xFC, 0xA8, 0xA6, 0xD2, 0x03, 0x17, 0x40, 0x36, 0x60, 0x6B, 0xDE, 0x74, 0x1A, 0xAD, 0x50, 0xB5, 0xCD, 0x5A, 0xBA, 0x71, 0x9A, 0xB6, 0x39, 0x8C, 0xD6, 0x89, 0x7A, 0x09, 0xED, 0x29, 0x1F, 0x72, 0x2A, 0x58, 0x21, 0x44, 0x70, 0x4B, 0xEC, 0x38, 0x8F, 0x49, 0xF4, 0xF5, 0x52, 0x71, 0xBF, 0x66, 0xB6, 0xF5, 0x82, 0x25, 0x76, 0xE1, 0x53, 0x0D, 0xCC, 0x06, 0x0C, 0xA8, 0xE8, 0xAF, 0xC5, 0x64, 0x0D, 0xFA, 0xA8, 0x29, 0xE5, 0xD4, 0xC5, 0x1E, 0x41, 0xAA, 0x98, 0xFF, 0xF5, 0x82, 0x3D, 0xC5, 0x07, 0x9B, 0x69, 0xEB, 0x53, 0x88, 0x58, 0x40, 0xCE, 0x24, 0x5F, 0x09, 0x88, 0x01, 0x16, 0x40, 0xDB, 0xFC, 0xCF, 0xEA, 0x29, 0x3B, 0x7E, 0xB4, 0xF9, 0x2D, 0x01, 0xE1, 0x27, 0x14, 0x21, 0xFF, 0x6C, 0xD6, 0x88, 0xE0, 0xA5, 0x63, 0xA1, 0x9B, 0x5F, 0x57, 0x37, 0xB7, 0x6D, 0x6C, 0x08, 0xEA, 0x98, 0xAC, 0xCB, 0xF6, 0x84, 0xDE, 0xF2, 0xD2, 0x72, 0x3A, 0xF1, 0x3C, 0xC6, 0x11, 0x19, 0x65, 0x71, 0xD6, 0xAE, 0xB2, 0x3D, 0x4C, 0x03, 0xAE, 0x80, 0x06, 0xB0, 0x0A, 0x60, 0x94, 0x45, 0x95, 0x99, 0xA3, 0x30, 0x9A, 0x04, 0x80, 0x14, 0x0F, 0x67, 0x49, 0x0F, 0x3E, 0x49, 0x9E, 0x6C, 0x85, 0xAE, 0x5B, 0xA2, 0x44, 0x16, 0x60, 0x06, 0xC4, 0x1A, 0xC8, 0xA0, 0x81, 0xDC, 0x40, 0x29, 0xB5, 0xF5, 0x81, 0x96, 0xBB, 0x0E, 0x44, 0x64, 0x1E, 0x3A, 0xE0, 0x7C, 0x73, 0xA0, 0x3D, 0xAF, 0xE4, 0x18, 0x6D, 0x8F, 0x5B, 0xDE, 0x02, 0x3A, 0x1A, 0x51, 0x2C, 0x7E, 0x60, 0x6C, 0x1D, 0x56, 0xAE, 0x8D, 0xFA, 0x08, 0x95, 0xC9, 0x60, 0xEF, 0x9F, 0x8E, 0xC6, 0x36, 0xE0, 0xA8, 0xBF, 0x9D, 0xCE, 0x3A, 0x7B, 0xEA, 0xB6, 0x26, 0xFC, 0x50, 0x7A, 0xD7, 0x45, 0xAB, 0xCD, 0xC3, 0x06, 0xD2, 0xF0, 0xB0, 0xD7, 0x44, 0x59, 0x1C, 0x77, 0x93, 0x28, 0x40, 0x04, 0x0F, 0x37, 0x93, 0x74, 0x02, 0x16, 0xE4, 0x5F, 0xBC, 0xE5, 0x1E, 0xB5, 0x5B, 0x07, 0x39, 0x88, 0xFB, 0xA1, 0xAC, 0x81, 0x03, 0xB6, 0x81, 0x9A, 0x3A, 0x3C, 0x1F, 0x74, 0x0D, 0x04, 0x88, 0x06, 0xD4, 0x80, 0xBD, 0x01, 0x96, 0xF1, 0x89, 0xD1, 0x66, 0x1B, 0x53, 0xC0, 0xEB, 0xD2, 0x52, 0xE8, 0xE9, 0x97, 0x54, 0x1D, 0x08, 0xB9, 0x45, 0x7E, 0xC6, 0xB2, 0x09, 0xB6, 0xB4, 0xD4, 0x4F, 0xB8, 0x65, 0x15, 0x10, 0x7A, 0xAE, 0x2B, 0x6C, 0x81, 0x32, 0x03, 0xBB, 0x39, 0xD3, 0x31, 0x88, 0x22, 0x00, 0x4F, 0x40, 0x0B, 0xF0, 0x86, 0x25, 0x84, 0xC1, 0x9D, 0x8D, 0xEC, 0xE5, 0x4E, 0x18, 0xCB, 0x84, 0xF6, 0xC4, 0x1F, 0xD5, 0xAE, 0xFF, 0xCB, 0x7C, 0x87, 0xD3, 0xED, 0x3D, 0x4F, 0xC6, 0x56, 0x28, 0x70, 0xF2, 0xC7, 0x17, 0x90, 0x3A, 0x58, 0x83, 0xE6, 0x2B, 0x40, 0x38, 0xD0, 0x35, 0x50, 0x20, 0x07, 0x56, 0x80, 0x0C, 0xEC, 0xB4, 0xDF, 0xA0, 0xCD, 0x64, 0x94, 0xA7, 0x6E, 0x15, 0x7E, 0xF5, 0x18, 0x91, 0x4F, 0x99, 0xDA, 0x36, 0x7C, 0x95, 0x28, 0xC7, 0xAA, 0xE3, 0xFB, 0x44, 0x37, 0xB0, 0x16, 0xDC, 0xE3, 0x6C, 0x53, 0x58, 0x9E, 0xB2, 0x52, 0x1B, 0xDF, 0x5D, 0x7A, 0xBA, 0xCF, 0xCE, 0xA7, 0x34, 0x40, 0x7D, 0x30, 0xC9, 0xDD, 0xF1, 0x61, 0xA4, 0x0F, 0x7C, 0xD4, 0x36, 0x7C, 0x26, 0x9E, 0xF5, 0xFC, 0xEB, 0x13, 0xAD, 0x34, 0x3D, 0x95, 0x75, 0xA5, 0xB3, 0xE6, 0xD5, 0x4C, 0x66, 0x65, 0x0D, 0x1E, 0xA0, 0x0E, 0xEC, 0x05, 0xAC, 0xBE, 0xC1, 0x37, 0x63, 0x16, 0x81, 0xED, 0x80, 0x11, 0x0B, 0x90, 0x04, 0x18, 0x16, 0xEB, 0x98, 0x37, 0x15, 0xA8, 0x4D, 0x9B, 0xE9, 0x5F, 0x1B, 0x94, 0xC0, 0xCA, 0x60, 0xEB, 0x71, 0x16, 0x31, 0x3F, 0x0D, 0x8E, 0x15, 0x2B, 0xB8, 0xF5, 0xCD, 0xFF, 0x90, 0x78, 0x9A, 0x5F, 0xB0, 0xE0, 0x88, 0x47, 0x1E, 0x61, 0x79, 0x98, 0xEB, 0xE4, 0x0B, 0x13, 0x5E, 0x80, 0x39, 0x20, 0x8C, 0x12, 0x14, 0x90, 0x44, 0xFE, 0x5A, 0x98, 0xDA, 0xC9, 0xA1, 0xA0, 0x82, 0x66, 0x3F, 0xC2, 0x92, 0xCC, 0xB4, 0xF5, 0x02, 0xD6, 0x55, 0x56, 0x8B, 0xE3, 0xE7, 0x55, 0x37, 0x21, 0x6B, 0xE0, 0x83, 0xFA, 0x57, 0xEE, 0xB2, 0xB0, 0xC0, 0x19, 0x70, 0x01, 0x6C, 0x01, 0xDB, 0xEF, 0xDC, 0x65, 0x37, 0x20, 0xD7, 0x49, 0x55, 0xA5, 0xD5, 0xEC, 0xD8, 0xA9, 0x04, 0xED, 0x19, 0xCB, 0xD1, 0xDA, 0x01, 0x19, 0x70, 0x0E, 0xAB, 0x69, 0x23, 0xB3, 0xD7, 0x6B, 0xC2, 0x11, 0x68, 0x42, 0x9B, 0x6F, 0x21, 0xCB, 0xA2, 0x11, 0xFC, 0xE7, 0x61, 0xC1, 0x1D, 0x07, 0xD8, 0xB7, 0xF7, 0x45, 0xFD, 0x4E, 0x8E, 0xAD, 0x2B, 0xF5, 0xC8, 0x4F, 0xEF, 0x25, 0x65, 0x70, 0xCF, 0x6F, 0xD9, 0xEA, 0xE3, 0x38, 0x13, 0x60, 0xE7, 0x58, 0x2D, 0xC6, 0x86, 0x0D, 0x84, 0x00, 0xE5, 0x83, 0x05, 0x64, 0x0D, 0xFA, 0x8E, 0x98, 0x6C, 0x7D, 0x9C, 0x6A, 0xCD, 0x44, 0x5D, 0x20, 0xE5, 0x36, 0xF3, 0xBA, 0xFE, 0xE4, 0x0C, 0x05, 0xC1, 0x6A, 0xFE, 0xD7, 0x1B, 0x37, 0xCB, 0x0A, 0x54, 0x7F, 0xC2, 0x86, 0x6C, 0xAB, 0x98, 0xC8, 0xA8, 0x97, 0xF5, 0x21, 0x45, 0x90, 0x66, 0xDF, 0x75, 0xB9, 0x87, 0x4C, 0x68, 0xB5, 0xF9, 0x4E, 0xAC, 0x08, 0x7C, 0x0B, 0x4B, 0xFC, 0x8C, 0xA7, 0xA7, 0x5A, 0xF0, 0x29, 0xAB, 0x31, 0xFA, 0xAD, 0xFB, 0x2E, 0xA4, 0x6D, 0xBA, 0xCA, 0xF4, 0x1E, 0x6B, 0xB1, 0x80, 0xBD, 0x6F, 0x65, 0x22, 0x3D, 0xE5, 0xDD, 0x40, 0x73, 0x20, 0xAD, 0x41, 0x03, 0x77, 0x66, 0x98, 0x1D, 0x09, 0x24, 0x19, 0xC4, 0x02, 0x7C, 0x20, 0x7A, 0xFB, 0xC9, 0xDD, 0x81, 0x8C, 0x79, 0x45, 0x8E, 0xD5, 0xE2, 0x2F, 0xA7, 0xDF, 0x9B, 0x7F, 0x61, 0x09, 0xFD, 0xF3, 0x9C, 0x14, 0xA2, 0xA4, 0xF2, 0x72, 0x79, 0x29, 0xAA, 0xBA, 0xF2, 0x83, 0xB4, 0x6E, 0x66, 0x74, 0x3C, 0xDA, 0x1D, 0xD7, 0xE8, 0xC6, 0x5E, 0x45, 0x19, 0x5E, 0xDE, 0xDF, 0x6E, 0xC9, 0x7D, 0x66, 0xCC, 0x44, 0x00, 0x8A, 0x87, 0x77, 0x07, 0xC9, 0x13, 0x91, 0xC2, 0xD7, 0xC7, 0x8F, 0x9F, 0xAA, 0x5C, 0xAE, 0x9C, 0xB7, 0x46, 0xFF, 0x80, 0x2E, 0xAF, 0xCD, 0x06, 0xFF, 0x4F, 0x80, 0x29, 0x37, 0x50, 0x0B, 0x68, 0x86, 0x6D, 0xA4, 0x81, 0xDE, 0xF3, 0x2B, 0x0D, 0x64, 0xCF, 0x43, 0x01, 0x7C, 0x03, 0xBB, 0x00, 0x65, 0x7F, 0x4E, 0xA1, 0xD5, 0xF2, 0xCB, 0x5D, 0xEE, 0x55, 0x5F, 0x2A, 0x51, 0xE6, 0x84, 0xA9, 0x3A, 0xA6, 0x44, 0x27, 0xFF, 0xD0, 0x0A, 0xEE, 0x83, 0xEA, 0x12, 0x8C, 0x5F, 0x47, 0x10, 0x54, 0x38, 0xD6, 0x4E, 0xC0, 0x9D, 0xCA, 0x4A, 0x61, 0x6F, 0x1E, 0x3A, 0x90, 0x01, 0xF8, 0x02, 0x24, 0x80, 0xB5, 0xEE, 0xA2, 0x97, 0x28, 0x86, 0xE7, 0x6E, 0x97, 0xAF, 0xD5, 0xA3, 0x33, 0xCF, 0x3F, 0x7E, 0x3C, 0x25, 0x13, 0x0A, 0xF4, 0xBE, 0x43, 0x52, 0x95, 0x77, 0xBC, 0xC9, 0x1A, 0xF0, 0x02, 0x62, 0xD0, 0x7D, 0x97, 0xE6, 0x95, 0x03, 0x19, 0x80, 0x1B, 0x20, 0x72, 0xA7, 0x8A, 0x6F, 0x01, 0x60, 0x7C, 0x98, 0xAD, 0xBE, 0x7D, 0x20, 0x02, 0xD5, 0x18, 0xDD, 0x48, 0x9B, 0x8F, 0x30, 0xF6, 0xEA, 0x83, 0x10, 0xFF, 0xF6, 0xEF, 0x77, 0x59, 0xDB, 0xBF, 0xDF, 0xBA, 0x5C, 0xAE, 0xED, 0xC0, 0xF7, 0x1B, 0x99, 0xAA, 0xBB, 0x4B, 0x76, 0xAD, 0x81, 0x01, 0x5E, 0x80, 0xEE, 0x67, 0xD1, 0x5B, 0x00, 0xED, 0x14, 0x57, 0x34, 0xE6, 0xD6, 0x17, 0x83, 0x11, 0xDE, 0x52, 0x63, 0x7A, 0xF6, 0xF7, 0x6D, 0xFB, 0xF6, 0x3B, 0xF6, 0x55, 0x72, 0xC7, 0xEC, 0x96, 0x02, 0x5B, 0x00, 0x66, 0x85, 0xAF, 0x00, 0xEC, 0xC9, 0xB3, 0x5F, 0xB4, 0x6F, 0x03, 0xB6, 0x01, 0xEF, 0x79, 0xC5, 0x8F, 0xD5, 0xFA, 0x2F, 0x0A, 0x5A, 0x6B, 0x0E, 0xAF, 0xF6, 0x87, 0x35, 0xF9, 0x43, 0x4C, 0x4F, 0xAD, 0x16, 0x08, 0x97, 0xA3, 0x28, 0x23, 0x7A, 0xCB, 0x3F, 0x6A, 0x68, 0xD7, 0xA9, 0x31, 0xBD, 0x2F, 0xED, 0x00, 0xE5, 0x58, 0x9B, 0xF1, 0xDA, 0xE3, 0x6B, 0xAE, 0x05, 0xF8, 0x06, 0x4E, 0x46, 0x83, 0x32, 0xD7, 0xB7, 0x80, 0xED, 0xFC, 0xB9, 0x4B, 0x67, 0x3E, 0x98, 0xCE, 0x68, 0xB7, 0x2D, 0x38, 0x66, 0x18, 0xE7, 0x65, 0xE7, 0x60, 0x19, 0xB8, 0x00, 0x61, 0x40, 0x26, 0x7F, 0xA5, 0xB7, 0x51, 0x2D, 0xE7, 0xA6, 0x03, 0xA9, 0x80, 0x16, 0xB0, 0x0D, 0xD0, 0xC5, 0x37, 0xC7, 0x6A, 0xB2, 0xBE, 0x41, 0x56, 0x3E, 0xF9, 0xF2, 0xD5, 0x9F, 0x3F, 0xB7, 0x26, 0xE2, 0xDE, 0xD4, 0x78, 0xD0, 0xFC, 0xB0, 0x24, 0xFE, 0xE0, 0xA1, 0xAB, 0xAB, 0x94, 0xC5, 0xF7, 0x93, 0xDD, 0xE1, 0xC1, 0x14, 0x0C, 0xDA, 0x82, 0x9E, 0x84, 0x3B, 0x82, 0x77, 0x14, 0x87, 0x06, 0x39, 0x56, 0x3B, 0x3A, 0x86, 0xEB, 0xF5, 0xCB, 0x6E, 0x36, 0x3A, 0x80, 0x7D, 0x39, 0xA9, 0x9E, 0x1C, 0xD2, 0x25, 0xC0, 0x79, 0xE5, 0xCE, 0x02, 0x5E, 0xC7, 0x9D, 0xB6, 0x37, 0xA0, 0x0B, 0xB0, 0x04, 0x2A, 0x9F, 0x3E, 0xD1, 0x0A, 0x94, 0x03, 0xB1, 0x80, 0xDD, 0xF3, 0x66, 0xB3, 0x6B, 0x34, 0x50, 0x45, 0xAB, 0xED, 0xBF, 0xFE, 0x5C, 0x5E, 0x82, 0x4C, 0xA2, 0x64, 0x76, 0x07, 0x35, 0x52, 0x0A, 0xBB, 0xE7, 0xB4, 0x00, 0x2A, 0x14, 0x27, 0x47, 0x4E, 0x3C, 0x4F, 0xDF, 0x88, 0xFB, 0xE2, 0x6E, 0x16, 0x77, 0xF4, 0xCB, 0x36, 0xA0, 0x0A, 0xAC, 0xBC, 0x6B, 0x9B, 0xB2, 0xEF, 0x2A, 0xCB, 0xD0, 0x33, 0x7B, 0xA7, 0x18, 0x1B, 0xF0, 0x7D, 0xF7, 0x89, 0x36, 0xBE, 0xF9, 0x04, 0xEB, 0xAC, 0x80, 0x5C, 0xF7, 0x26, 0x1A, 0x05, 0xA4, 0x03, 0xB5, 0x07, 0x06, 0xF4, 0xBA, 0x4F, 0x6A, 0xD1, 0x77, 0xAB, 0xEE, 0x56, 0x3E, 0x04, 0xD4, 0x9F, 0x46, 0x42, 0x57, 0x56, 0x13, 0xAC, 0x26, 0xDF, 0x20, 0x93, 0x65, 0xB8, 0xC2, 0x34, 0xDC, 0x45, 0x5B, 0x7C, 0x9C, 0x1C, 0x39, 0x83, 0x73, 0x4F, 0xE7, 0x60, 0x43, 0x7F, 0xE9, 0x5E, 0xB7, 0x5B, 0x4D, 0x9F, 0xEC, 0x8E, 0xD4, 0xA7, 0x40, 0x71, 0x15, 0x60, 0x0A, 0x48, 0xB1, 0x25, 0xF4, 0x87, 0x10, 0xE0, 0xA4, 0x3B, 0xF3, 0x8F, 0x9E, 0x74, 0xB9, 0x10, 0x8C, 0x53, 0x25, 0xBD, 0xC2, 0x97, 0x96, 0x9D, 0xE6, 0xDD, 0xF6, 0xE0, 0xF8, 0xEF, 0xF6, 0xBE, 0xBB, 0x90, 0x9B, 0x3E, 0x4D, 0xC5, 0x15, 0xE8, 0xE3, 0x90, 0x05, 0x8A, 0x5E, 0x61, 0xBD, 0x7B, 0xBC, 0xF6, 0x20, 0x04, 0xD0, 0x02, 0xDC, 0xF9, 0x26, 0xAD, 0x06, 0xBD, 0x52, 0x97, 0x0D, 0x07, 0x43, 0xC0, 0xEF, 0x9D, 0xCB, 0xF0, 0x73, 0x53, 0x94, 0x51, 0xAD, 0xD3, 0x0B, 0x61, 0x8F, 0x27, 0x4B, 0xFE, 0xB0, 0x3D, 0xBF, 0x7E, 0x6F, 0xB9, 0xA5, 0x9C, 0xE6, 0x1F, 0xAE, 0x23, 0x25, 0xED, 0x01, 0x68, 0xCC, 0xC3, 0xD3, 0x45, 0x01, 0x60, 0x97, 0x42, 0xAA, 0xA5, 0x31, 0x32, 0xB5, 0x4E, 0x13, 0xC0, 0xBB, 0x87, 0xAF, 0xD0, 0x97, 0x5E, 0xAC, 0x52, 0x60, 0xE9, 0x04, 0x93, 0x92, 0xD9, 0xA2, 0xE6, 0xD6, 0xDA, 0x94, 0x41, 0x24, 0x40, 0x59, 0xCD, 0xA5, 0x80, 0x15, 0x7D, 0xCC, 0x40, 0x6C, 0xC0, 0x15, 0x90, 0xBC, 0x33, 0xFF, 0x7C, 0xDF, 0xCE, 0x5E, 0x3F, 0x56, 0x33, 0x74, 0x6C, 0xF3, 0x0D, 0x47, 0x4C, 0x1B, 0x6A, 0x49, 0xD4, 0xA6, 0x78, 0xC5, 0x27, 0x0C, 0xE2, 0x13, 0x22, 0x81, 0xD5, 0x24, 0x84, 0xC7, 0xDA, 0xBB, 0x0D, 0x6D, 0x72, 0xF7, 0x62, 0xFD, 0x05, 0xFF, 0x25, 0x56, 0x55, 0x14, 0x20, 0x74, 0x2B, 0x27, 0xB0, 0x9D, 0xB6, 0x9B, 0x87, 0x74, 0x8D, 0x3B, 0x8D, 0x36, 0x18, 0x3F, 0x10, 0x0B, 0xE0, 0x99, 0xA9, 0x68, 0x63, 0x98, 0x52, 0x60, 0x2F, 0x20, 0x2F, 0x95, 0xEB, 0x3E, 0x8D, 0x6E, 0x59, 0x09, 0xAE, 0x0D, 0x84, 0x02, 0xA7, 0x33, 0x69, 0x01, 0xC5, 0xF2, 0x18, 0x1F, 0x6C, 0x60, 0x31, 0xB2, 0xE3, 0x80, 0x0F, 0xF8, 0xE7, 0xB4, 0xA6, 0xD1, 0x1C, 0x43, 0xAD, 0xC7, 0xFF, 0x20, 0xF9, 0x95, 0x6B, 0xEF, 0x4A, 0x18, 0x5B, 0x0B, 0xFE, 0x51, 0xA5, 0xF2, 0x9F, 0xCD, 0xB8, 0x45, 0xAD, 0x59, 0xBD, 0x43, 0x4D, 0xF3, 0x14, 0x18, 0x52, 0xD1, 0x9C, 0x99, 0xD9, 0x40, 0x16, 0x10, 0x0D, 0xB0, 0x46, 0xBA, 0x6A, 0x30, 0x21, 0x16, 0x66, 0xD1, 0xEF, 0x7D, 0xFB, 0xBD, 0x6C, 0x4C, 0x69, 0xFD, 0x44, 0xA4, 0xCE, 0xDF, 0xE5, 0x2E, 0xFB, 0x60, 0xD9, 0x13, 0x6B, 0x00, 0xED, 0xA9, 0x66, 0x93, 0x81, 0x16, 0xE0, 0x0A, 0xB4, 0xDE, 0xB9, 0xA6, 0xBD, 0x81, 0x7A, 0x32, 0x4F, 0x85, 0x6F, 0xCE, 0xC3, 0x2D, 0x40, 0x05, 0xAD, 0x16, 0xA8, 0x93, 0xB2, 0xF1, 0xCF, 0x7A, 0xC2, 0x49, 0x98, 0x39, 0x81, 0xA9, 0x9F, 0xD4, 0xC9, 0x67, 0x98, 0x9A, 0xC0, 0x5B, 0xFE, 0x14, 0x4F, 0xEA, 0xF8, 0xBD, 0xE5, 0x71, 0x47, 0xD2, 0xE1, 0x9D, 0xD4, 0xD0, 0x4B, 0x60, 0xB3, 0x5C, 0x6A, 0xC6, 0x51, 0x0C, 0x64, 0xF3, 0xD3, 0xBC, 0xD9, 0x4C, 0x4B, 0x06, 0x8E, 0x40, 0xBD, 0xB2, 0x28, 0x8D, 0xF1, 0x1A, 0xCE, 0x97, 0x67, 0xF2, 0xB1, 0x81, 0xEC, 0xBC, 0xB2, 0x12, 0x08, 0x16, 0xBA, 0x39, 0x20, 0x1B, 0xD0, 0x02, 0x38, 0x8E, 0x54, 0x80, 0x70, 0xC0, 0x1B, 0x30, 0x01, 0x36, 0x15, 0x9A, 0x63, 0x3E, 0x6D, 0xA0, 0x8C, 0x46, 0xCB, 0x3F, 0xB7, 0x69, 0x28, 0x62, 0xE3, 0xC3, 0x35, 0xA4, 0x13, 0x41, 0x13, 0x2B, 0xA6, 0x78, 0x7A, 0x8F, 0x76, 0x58, 0xB3, 0x75, 0xD9, 0xD5, 0x26, 0xDA, 0xAF, 0x36, 0xD1, 0x23, 0xFA, 0x85, 0x9F, 0x60, 0x60, 0x33, 0x38, 0x54, 0x80, 0x65, 0x2C, 0xCD, 0x78, 0xE4, 0xCE, 0x07, 0xC6, 0x55, 0xF0, 0x43, 0x1F, 0xA1, 0xB6, 0x66, 0x2C, 0x92, 0xE2, 0x89, 0xC6, 0x08, 0xF9, 0xDD, 0x38, 0x45, 0xAE, 0x3C, 0x06, 0x1D, 0x4B, 0xFA, 0x09, 0x25, 0x2E, 0x01, 0x2C, 0x80, 0x48, 0xA0, 0x94, 0xC3, 0xE8, 0x0E, 0x16, 0x88, 0x01, 0x9B, 0xF1, 0x1D, 0x05, 0x7C, 0x20, 0x06, 0x68, 0xF2, 0x15, 0x1A, 0xAD, 0x26, 0x4A, 0x14, 0x1F, 0xA2, 0x1B, 0xC5, 0x47, 0x51, 0xE3, 0xE7, 0x73, 0xB4, 0x3B, 0x2D, 0x99, 0x86, 0x87, 0x3A, 0x85, 0x87, 0x49, 0x2B, 0x5D, 0x7A, 0xFC, 0xFD, 0xD3, 0x3C, 0x17, 0x3F, 0x4A, 0x39, 0x8B, 0x49, 0xF1, 0x3E, 0x4E, 0x7F, 0xC7, 0xC3, 0x36, 0x00, 0x0F, 0xE1, 0x9A, 0xF9, 0xA0, 0x01, 0xF4, 0xBC, 0xE2, 0x0D, 0x18, 0x45, 0xBE, 0x14, 0x58, 0xE3, 0xC0, 0x34, 0x9B, 0xB2, 0xC7, 0x7C, 0x5A, 0x4B, 0x38, 0x5E, 0x89, 0xF9, 0x5F, 0xD7, 0xFC, 0x7B, 0xC1, 0xCC, 0xFC, 0x02, 0xCC, 0x80, 0xA0, 0xE3, 0x4C, 0x00, 0x53, 0x20, 0x64, 0x90, 0x83, 0x06, 0x72, 0x0D, 0x0C, 0xA8, 0xA2, 0xDE, 0x3C, 0x6D, 0x86, 0x20, 0x9E, 0xBA, 0x4D, 0x89, 0xCC, 0xC6, 0xD2, 0x32, 0x9F, 0x76, 0x16, 0x42, 0x0E, 0x1A, 0xE3, 0x7D, 0xA5, 0x7B, 0xB8, 0x3F, 0x2B, 0xE5, 0xED, 0xF7, 0x3E, 0xF9, 0x24, 0x74, 0x01, 0xDF, 0x42, 0x65, 0xC8, 0xDB, 0xFC, 0x90, 0xCA, 0xEE, 0x97, 0xC0, 0xD2, 0xFB, 0xAB, 0xB4, 0xCE, 0x2B, 0x3D, 0xAA, 0x5C, 0xD4, 0xEF, 0x4A, 0x4A, 0xE7, 0x3F, 0x2D, 0x10, 0xA8, 0xEC, 0x51, 0x54, 0x52, 0x1B, 0xF8, 0xED, 0xCD, 0x8E, 0xD3, 0x9A, 0x18, 0xF0, 0x00, 0x72, 0x03, 0x2D, 0x23, 0xBD, 0x76, 0xBA, 0x82, 0x02, 0xEA, 0x03, 0x05, 0xB6, 0xE1, 0x95, 0x72, 0x20, 0xE2, 0xEE, 0x9A, 0x79, 0x3C, 0x6B, 0xCA, 0x06, 0x25, 0x70, 0x71, 0xBB, 0xD8, 0x38, 0xCA, 0x73, 0x04, 0xBE, 0x36, 0xBC, 0xC4, 0x12, 0x1F, 0x2C, 0x63, 0x4A, 0x61, 0xE3, 0xB3, 0x52, 0x4C, 0x80, 0xC5, 0x9E, 0x66, 0x19, 0xC5, 0x6E, 0xE8, 0x3B, 0xEE, 0xD6, 0x0B, 0x5C, 0xA7, 0x28, 0x81, 0xD9, 0xC9, 0xFA, 0x3B, 0xC0, 0x28, 0xFD, 0xDA, 0xF3, 0x26, 0xBB, 0x83, 0xC6, 0x60, 0xE3, 0xE1, 0x51, 0x13, 0x5D, 0xBF, 0xD8, 0xB1, 0x1E, 0x29, 0x60, 0x2E, 0x9D, 0x46, 0x59, 0x1E, 0x7A, 0xC3, 0xE7, 0xC7, 0xD9, 0xEB, 0xD9, 0xF7, 0xAD, 0xDD, 0xB7, 0x17, 0xE0, 0x63, 0x98, 0x1D, 0x80, 0xD5, 0x40, 0x00, 0x99, 0x37, 0xDB, 0x81, 0x4C, 0xA0, 0x38, 0xB0, 0x85, 0x46, 0xDB, 0xD3, 0x2C, 0x43, 0x61, 0x1F, 0x0D, 0xF8, 0xD4, 0x53, 0x79, 0x89, 0xC0, 0xD7, 0x5C, 0x36, 0x3E, 0xF5, 0x4D, 0x15, 0x67, 0x6E, 0x96, 0x57, 0x54, 0x8A, 0x99, 0x86, 0xA9, 0x8B, 0x6B, 0xEE, 0x0C, 0x80, 0xE7, 0xD7, 0xD6, 0xF5, 0x6B, 0x46, 0xC1, 0x7E, 0xD7, 0x6C, 0x3F, 0x43, 0xA7, 0x33, 0x02, 0xC9, 0xF8, 0xED, 0x03, 0x58, 0x8C, 0xA2, 0x24, 0xDE, 0x8C, 0xF8, 0x95, 0xAC, 0xE8, 0x59, 0xC0, 0x75, 0x03, 0x6D, 0x63, 0xFA, 0xC2, 0x9B, 0xC7, 0x76, 0x0A, 0xF4, 0x8C, 0x42, 0x49, 0xC0, 0x6D, 0x02, 0xAC, 0x0E, 0xD0, 0x22, 0x22, 0xC0, 0xE6, 0x4C, 0x32, 0x20, 0x36, 0xA0, 0x05, 0x70, 0xBC, 0x5A, 0xD0, 0x68, 0x02, 0xC3, 0xEC, 0xC4, 0xC2, 0xBD, 0x14, 0x43, 0xAC, 0x14, 0xC3, 0x60, 0x61, 0x88, 0xB9, 0xB0, 0xB6, 0x29, 0x60, 0xB4, 0x65, 0x0C, 0x7F, 0xDE, 0xDD, 0x32, 0xAE, 0xC6, 0x0D, 0x67, 0xBF, 0xAA, 0x37, 0x92, 0x78, 0x02, 0x43, 0xAE, 0xAC, 0xC8, 0x06, 0xF6, 0x06, 0xF4, 0x43, 0x1F, 0xDB, 0xF9, 0x60, 0x73, 0x0A, 0x8E, 0x79, 0x7D, 0x31, 0x38, 0x32, 0x03, 0xAE, 0x80, 0xDD, 0x00, 0xA3, 0x22, 0x14, 0x2E, 0xCE, 0x7D, 0x8B, 0x45, 0xEE, 0x04, 0x4C, 0x81, 0xC8, 0xBB, 0x01, 0x50, 0x2C, 0xA0, 0x89, 0x0D, 0xD4, 0x20, 0x0C, 0xF0, 0xBC, 0x5B, 0x05, 0x69, 0xD1, 0x68, 0x08, 0xAD, 0xFB, 0x36, 0xEC, 0x53, 0xAE, 0xF8, 0x9A, 0xB1, 0x79, 0xFC, 0xC5, 0xB9, 0x41, 0x65, 0x8A, 0x0D, 0x75, 0xCE, 0x8A, 0x2C, 0x98, 0x82, 0xD1, 0x4E, 0xD7, 0xA4, 0x7A, 0x7B, 0xD9, 0xCC, 0x5F, 0x5E, 0xE7, 0x7B, 0xB2, 0x05, 0xCB, 0xE9, 0xFC, 0xB3, 0x67, 0xF8, 0x0A, 0xC0, 0x08, 0x7B, 0xD6, 0x7C, 0x25, 0xE5, 0xEA, 0x0E, 0xD4, 0x4F, 0x14, 0x53, 0xEA, 0x18, 0x6D, 0xF1, 0x84, 0x92, 0xF7, 0xE1, 0xE0, 0x54, 0x45, 0xE5, 0x58, 0x52, 0x01, 0x4F, 0xA0, 0xFC, 0x2E, 0xC7, 0xDD, 0x02, 0xF8, 0xBE, 0x23, 0xB3, 0x26, 0x80, 0xC6, 0xBF, 0x74, 0x84, 0x0D, 0x60, 0x90, 0xDA, 0x95, 0x46, 0x43, 0xCE, 0x8B, 0x0B, 0x2E, 0x98, 0x9E, 0x06, 0x31, 0xB6, 0x70, 0xEC, 0xEA, 0xE6, 0xD3, 0xAF, 0xA4, 0x21, 0xD7, 0xDC, 0x7B, 0x1A, 0x95, 0x04, 0xDC, 0xF4, 0xCC, 0x86, 0x04, 0xFA, 0xAA, 0x98, 0x65, 0x4B, 0x65, 0x9B, 0xBC, 0x14, 0x87, 0xBF, 0x01, 0x08, 0x84, 0x99, 0x42, 0x51, 0x42, 0x26, 0x8E, 0x57, 0xF6, 0x64, 0x63, 0x66, 0xCF, 0x0F, 0x24, 0x20, 0x81, 0x87, 0x3B, 0x27, 0x9E, 0xF5, 0x41, 0x60, 0x2C, 0x6D, 0xD8, 0x1A, 0x1B, 0x07, 0xB0, 0x16, 0xA0, 0x35, 0x5B, 0x8C, 0x4D, 0x84, 0x75, 0xDF, 0x9D, 0xC6, 0xD3, 0x81, 0x9E, 0xD8, 0x9A, 0x0C, 0xD2, 0x27, 0x5A, 0xB8, 0x80, 0x8C, 0x41, 0x02, 0xE1, 0x80, 0x0D, 0xB4, 0x00, 0x17, 0xFC, 0x2E, 0x2A, 0xB4, 0x99, 0xC3, 0xF3, 0x42, 0xF9, 0x26, 0x7A, 0xC4, 0x28, 0x8D, 0xBA, 0x0A, 0xBD, 0xCC, 0x3D, 0xE7, 0x7F, 0xAD, 0xB3, 0x23, 0xEE, 0x13, 0xD3, 0xD8, 0x27, 0xD0, 0x51, 0xFB, 0x68, 0xCC, 0xCD, 0x22, 0x34, 0xBF, 0x8B, 0xFB, 0x18, 0x24, 0x07, 0x32, 0x32, 0x81, 0x0A, 0xAC, 0x09, 0xF0, 0x59, 0x01, 0xEE, 0x78, 0xA8, 0x0C, 0x16, 0x37, 0x60, 0x1B, 0x0F, 0x33, 0xF0, 0x4A, 0x37, 0xB0, 0xE6, 0xAB, 0xEC, 0x89, 0x94, 0x86, 0x01, 0x2A, 0x80, 0x0C, 0xF6, 0x02, 0x56, 0x03, 0xDB, 0x01, 0xD9, 0x80, 0xC6, 0xFD, 0x73, 0x3D, 0x06, 0xD9, 0x32, 0xC8, 0x81, 0x0D, 0x74, 0xD0, 0x80, 0x2A, 0x10, 0x41, 0x9B, 0x21, 0xD4, 0x29, 0x25, 0xB0, 0x19, 0x95, 0xDB, 0x36, 0xC6, 0x99, 0x45, 0x7E, 0x7F, 0x77, 0x4D, 0xF9, 0xF3, 0xC9, 0x37, 0x34, 0x9F, 0xED, 0x6A, 0x52, 0x6A, 0xF6, 0x11, 0xA8, 0x59, 0x74, 0x24, 0xA8, 0xAD, 0xD3, 0x9B, 0xDA, 0xE7, 0x37, 0xF3, 0x9C, 0x4F, 0x5F, 0xA5, 0x37, 0x3E, 0x45, 0xA3, 0x5D, 0x6B, 0x0F, 0x2C, 0x81, 0x1C, 0x89, 0xCF, 0x34, 0xBC, 0x19, 0x0A, 0x6C, 0xBE, 0xF2, 0x3D, 0x34, 0x4C, 0x74, 0xC7, 0x81, 0x01, 0xA3, 0xB5, 0xA7, 0xE0, 0x71, 0xE2, 0xA6, 0xB9, 0x00, 0x4D, 0xE0, 0x64, 0x12, 0xDB, 0x80, 0x43, 0x38, 0x00, 0x19, 0x44, 0xCD, 0x60, 0x37, 0xC0, 0x89, 0x1C, 0x2C, 0x40, 0x6D, 0xE0, 0x80, 0x2B, 0xFE, 0x59, 0x71, 0xDA, 0x2C, 0x31, 0x29, 0x35, 0x27, 0xAD, 0x3E, 0xC6, 0x4B, 0x6B, 0x23, 0xCC, 0x88, 0x7F, 0xD6, 0x5B, 0xF0, 0x2F, 0x54, 0x8F, 0xAE, 0x69, 0xA2, 0x3C, 0x89, 0x37, 0x27, 0xA0, 0x4F, 0x00, 0x64, 0x8E, 0x32, 0x88, 0xFD, 0xCE, 0x24, 0xF1, 0x69, 0x6F, 0xE5, 0xC8, 0xC9, 0x46, 0xB1, 0xC7, 0xC6, 0x77, 0x5F, 0x33, 0x53, 0xBB, 0x81, 0xF2, 0x99, 0xBE, 0x63, 0x97, 0x50, 0x40, 0xD7, 0xBC, 0xB2, 0xF9, 0x8D, 0xE6, 0x4B, 0xCF, 0x1F, 0xAE, 0x14, 0xD0, 0x05, 0xA4, 0xCD, 0x44, 0xE7, 0xD7, 0x1C, 0xB3, 0x2E, 0x07, 0x7C, 0x03, 0x11, 0x40, 0xCD, 0x72, 0x21, 0x06, 0x44, 0x03, 0xBD, 0x80, 0xAA, 0x81, 0x00, 0x39, 0x88, 0x04, 0xD2, 0xF0, 0x2B, 0x49, 0xD3, 0x66, 0x35, 0x8E, 0xA7, 0x44, 0x1D, 0x47, 0x52, 0x82, 0x7F, 0x6E, 0xF5, 0x19, 0x28, 0x58, 0x5D, 0xFB, 0x5B, 0x27, 0xBC, 0x6C, 0x52, 0x53, 0xFC, 0x27, 0x4F, 0x2B, 0x0E, 0x94, 0xFF, 0xC2, 0x3D, 0x2A, 0xE7, 0x8F, 0x7A, 0xCC, 0xA3, 0xF3, 0xAF, 0xDB, 0xFC, 0xA9, 0x6C, 0x86, 0x86, 0xE2, 0xCF, 0xA1, 0xF9, 0xFB, 0xEE, 0x76, 0x16, 0x0F, 0xE7, 0x04, 0xFA, 0x30, 0x75, 0x48, 0xB6, 0x00, 0x85, 0xB3, 0x04, 0x87, 0x5D, 0x03, 0x96, 0x02, 0xAA, 0x4C, 0xDD, 0xC1, 0x9B, 0x5B, 0x00, 0xFE, 0xF8, 0xDA, 0xC0, 0x36, 0x40, 0x15, 0x08, 0x9F, 0xE9, 0xAB, 0x80, 0xEC, 0x1B, 0xBB, 0x07, 0x3E, 0x28, 0x40, 0x37, 0x90, 0x46, 0x9B, 0xF5, 0x17, 0xF4, 0xDC, 0x56, 0x9F, 0xF7, 0x36, 0x96, 0x7C, 0x90, 0x74, 0xDC, 0x52, 0xB3, 0x11, 0xBC, 0x48, 0x83, 0x08, 0x54, 0x08, 0x5A, 0x14, 0xF5, 0xBA, 0x22, 0xC6, 0x66, 0x6F, 0x9C, 0x9D, 0x95, 0x73, 0xC2, 0x92, 0xCF, 0x27, 0x35, 0x7F, 0x01, 0x16, 0xC0, 0x66, 0x39, 0xC5, 0x7C, 0x92, 0x27, 0x7B, 0x9F, 0x51, 0xD2, 0x90, 0x5B, 0xC2, 0x50, 0x16, 0xC0, 0xCE, 0x8D, 0x99, 0x83, 0xA0, 0x5E, 0x1A, 0x83, 0xAC, 0x4F, 0xD9, 0x94, 0xDE, 0x11, 0x9C, 0x2D, 0x80, 0xEC, 0xBB, 0xD2, 0x74, 0x25, 0x60, 0x02, 0xA8, 0x01, 0x7B, 0x3D, 0x95, 0x3F, 0x75, 0xEB, 0x2D, 0x68, 0xF0, 0x36, 0x60, 0x28, 0x28, 0xF0, 0xB0, 0xBF, 0x9C, 0x14, 0xD2, 0x42, 0x84, 0x6F, 0x26, 0x9B, 0xE2, 0x4D, 0x99, 0xDE, 0xCB, 0x69, 0x28, 0xCA, 0x30, 0x65, 0x40, 0xE5, 0xB1, 0x9A, 0xDD, 0xAD, 0x2D, 0x25, 0xEE, 0x3C, 0x7F, 0x00, 0xBE, 0xA1, 0xAB, 0xE9, 0x73, 0x07, 0x50, 0x8B, 0x0F, 0x29, 0xB7, 0x76, 0x6B, 0xB2, 0xF2, 0xCB, 0xDC, 0x5F, 0xDB, 0x8E, 0xD1, 0xD3, 0x01, 0x06, 0x06, 0xF5, 0xAA, 0xB3, 0xCD, 0xE3, 0xCB, 0xB5, 0x7D, 0x47, 0x70, 0x9A, 0x19, 0x8F, 0xFB, 0xE9, 0x54, 0x29, 0x0A, 0x44, 0x00, 0x3E, 0x90, 0x60, 0xD3, 0xE5, 0x4B, 0x3B, 0x20, 0xF7, 0x71, 0x2F, 0xD3, 0x6A, 0x68, 0x69, 0xE6, 0x1E, 0xD3, 0x3F, 0xB5, 0xB0, 0x66, 0x87, 0xE1, 0x24, 0xB4, 0x7B, 0xF2, 0xDC, 0x37, 0x6C, 0xB8, 0x0D, 0xFB, 0x6A, 0xC6, 0xD1, 0x5A, 0x86, 0xDC, 0xE6, 0x95, 0x79, 0xAB, 0x47, 0xA7, 0xDB, 0xF3, 0x44, 0x7B, 0x06, 0x0A, 0x6C, 0x99, 0x0D, 0x16, 0xAF, 0xA4, 0x00, 0xBA, 0x01, 0x46, 0xEF, 0x7A, 0x33, 0xE8, 0xF3, 0x93, 0x03, 0x83, 0xB7, 0xF7, 0xEA, 0x69, 0xD0, 0x0D, 0x68, 0x0E, 0xDE, 0x2A, 0x8E, 0xA4, 0x78, 0x21, 0x7D, 0x69, 0xEB, 0x91, 0x7A, 0xDE, 0x80, 0x2A, 0x90, 0x71, 0x37, 0x45, 0xCA, 0x05, 0x84, 0x01, 0xB6, 0x01, 0xA6, 0xF1, 0x96, 0x00, 0x6D, 0x7C, 0x85, 0x56, 0x93, 0x6F, 0x74, 0xAD, 0xF2, 0x0F, 0x92, 0xFE, 0xD5, 0x4B, 0xD9, 0x38, 0x1B, 0xDB, 0x04, 0xA3, 0xD9, 0x12, 0x23, 0xBD, 0xF6, 0x87, 0xF1, 0x40, 0x5A, 0xBF, 0x6D, 0xA6, 0x36, 0xF3, 0x03, 0x58, 0x0D, 0x68, 0x8F, 0x4A, 0x57, 0x02, 0xDE, 0xC0, 0xB2, 0x7B, 0xE4, 0x6F, 0x05, 0x98, 0x83, 0x7A, 0x04, 0x6C, 0xE6, 0x93, 0xDA, 0xDD, 0xDA, 0x98, 0xC1, 0x9A, 0x68, 0x60, 0x53, 0x9F, 0xF6, 0x8A, 0xB6, 0xF8, 0x29, 0x21, 0x36, 0xB9, 0xF5, 0xAD, 0xF4, 0xD1, 0x6B, 0xF5, 0x41, 0x8F, 0xB5, 0xDD, 0x80, 0x0E, 0xA0, 0x14, 0xF0, 0x00, 0x58, 0xB6, 0xC4, 0x87, 0x6B, 0x50, 0x72, 0x66, 0xA8, 0x7E, 0xA1, 0x4F, 0x15, 0x45, 0x1F, 0x77, 0x41, 0xF6, 0x32, 0x2A, 0xF6, 0x3F, 0xD4, 0x94, 0x2C, 0x0B, 0xBC, 0x8B, 0x12, 0x13, 0x10, 0xCF, 0x5B, 0x8F, 0xEE, 0x0D, 0xE2, 0x2D, 0xBB, 0x7B, 0xF8, 0x0B, 0x21, 0x78, 0x58, 0x05, 0xF8, 0x53, 0x65, 0xD6, 0x8F, 0xD5, 0xD2, 0xEE, 0x84, 0x63, 0x77, 0x1A, 0xE1, 0x2E, 0xC8, 0x5C, 0x71, 0xAF, 0x5D, 0x22, 0xF3, 0xF0, 0xEA, 0x48, 0x5E, 0x27, 0xE6, 0xB9, 0x36, 0x60, 0x0A, 0xC4, 0x06, 0x32, 0x4E, 0x34, 0xF6, 0xEE, 0x44, 0xB5, 0x72, 0x70, 0x4E, 0xE8, 0x80, 0x6D, 0x60, 0x3B, 0xA0, 0x7C, 0x53, 0x68, 0x35, 0x43, 0x5F, 0xE8, 0xDE, 0x5F, 0x95, 0xD9, 0xCA, 0x60, 0x10, 0x6F, 0x6A, 0x7D, 0xFC, 0x5B, 0xA2, 0x4F, 0x06, 0x8D, 0x06, 0x32, 0x51, 0x3A, 0x11, 0xC4, 0xFB, 0x67, 0x01, 0xA8, 0xF9, 0x2D, 0x29, 0x1B, 0x01, 0xB8, 0x00, 0xE2, 0x4F, 0xD6, 0x95, 0x02, 0x41, 0x6B, 0x6F, 0xA0, 0x68, 0x92, 0xF9, 0xC4, 0xA4, 0x17, 0x37, 0x60, 0xD5, 0xDD, 0x16, 0x2E, 0xF7, 0xC0, 0xE6, 0x15, 0x66, 0x3A, 0x28, 0x97, 0xCC, 0xBB, 0xE0, 0x35, 0x1C, 0xC8, 0x41, 0x3D, 0x2A, 0x3A, 0x15, 0x4F, 0x61, 0x7B, 0xCE, 0xC3, 0x81, 0x3D, 0x6B, 0xB3, 0xFA, 0x79, 0x85, 0x56, 0xF3, 0xBF, 0x5A, 0xD0, 0x4B, 0x4B, 0xC3, 0xF2, 0x96, 0xDF, 0x22, 0x1B, 0x93, 0xBE, 0x2A, 0xE8, 0xEC, 0xA1, 0xF9, 0xC1, 0xDD, 0xF1, 0x2B, 0x6D, 0xA5, 0xF4, 0xD0, 0x9D, 0x75, 0xC5, 0x4D, 0x90, 0xFB, 0x0F, 0x0B, 0xE8, 0x0E, 0xF2, 0x6E, 0x58, 0x5F, 0x0D, 0x98, 0x02, 0xBB, 0x9F, 0xEA, 0x59, 0xA6, 0xD6, 0x07, 0x20, 0x47, 0xEC, 0x16, 0x58, 0xCD, 0x84, 0x32, 0xCE, 0x49, 0x40, 0x03, 0x38, 0xC5, 0xB0, 0x7A, 0xC7, 0xDE, 0x6D, 0x10, 0x0E, 0xA4, 0x01, 0xA5, 0xAC, 0xFC, 0x07, 0xB8, 0xB8, 0xAE, 0xB1, 0x5A, 0x27, 0x90, 0x06, 0x68, 0x02, 0xAB, 0x01, 0x09, 0xA0, 0xEB, 0x58, 0x2D, 0xBE, 0x24, 0xB5, 0x95, 0xF2, 0x55, 0x7E, 0xC6, 0x51, 0x78, 0x65, 0xB8, 0xED, 0x12, 0x90, 0xD8, 0xB6, 0x30, 0xD6, 0x64, 0xC6, 0x9A, 0x9D, 0x80, 0xF1, 0xB0, 0x19, 0x07, 0xD6, 0x75, 0xA7, 0xD5, 0x59, 0x02, 0x5A, 0xC0, 0x96, 0xBB, 0x76, 0x33, 0x83, 0x98, 0x57, 0x9E, 0x7A, 0xD0, 0xDC, 0xC0, 0x8E, 0x5B, 0x74, 0xC2, 0xE4, 0x96, 0x54, 0xF6, 0xB8, 0xF5, 0x07, 0xB6, 0xE3, 0x4D, 0xAF, 0xFB, 0x8F, 0xB6, 0xFD, 0x49, 0xCA, 0xA0, 0x11, 0xED, 0x5E, 0xF4, 0x82, 0x66, 0xE3, 0x6A, 0x37, 0x88, 0xA0, 0xA1, 0x9E, 0x4C, 0x98, 0x0D, 0xB4, 0x1E, 0xB3, 0xE5, 0x5F, 0x28, 0x14, 0x4D, 0xE2, 0xDB, 0x70, 0xA0, 0xAD, 0x66, 0x9D, 0xD3, 0x2D, 0x50, 0x10, 0xEC, 0xF7, 0xFA, 0x43, 0x9F, 0xFC, 0x42, 0x3F, 0x2C, 0xDD, 0x97, 0xEA, 0xB2, 0xEB, 0xB5, 0x1D, 0x30, 0x2B, 0x08, 0x7B, 0xE2, 0x9D, 0x1D, 0x51, 0x09, 0x68, 0x53, 0xD1, 0x6B, 0x0A, 0xEC, 0x01, 0x2B, 0xA0, 0x6E, 0x4D, 0xB6, 0x7D, 0x32, 0x2E, 0xB4, 0xF0, 0xDF, 0xEA, 0x4E, 0xF2, 0x59, 0x57, 0x8D, 0x29, 0x47, 0x2E, 0x1F, 0xE2, 0x04, 0xFC, 0x2B, 0xF6, 0x91, 0xA3, 0x33, 0xA7, 0x05, 0x84, 0x03, 0x95, 0xB3, 0xCF, 0xB2, 0xD0, 0xAA, 0x00, 0x57, 0xC0, 0x0C, 0xD8, 0xF5, 0x08, 0x39, 0x2D, 0xC0, 0x7B, 0x5E, 0x49, 0x5A, 0xAD, 0x3E, 0x73, 0xC5, 0x8A, 0x6F, 0x3B, 0xF0, 0x44, 0xB2, 0x5A, 0x89, 0x4D, 0xCB, 0x39, 0x45, 0xC5, 0x87, 0xC9, 0x14, 0xBA, 0xE6, 0x87, 0xF6, 0x38, 0xD5, 0x78, 0xE4, 0x25, 0x85, 0x7B, 0xB6, 0x9C, 0x7C, 0xCA, 0x57, 0x96, 0xDD, 0x67, 0x8E, 0xE4, 0x5F, 0x0D, 0xB0, 0x05, 0x38, 0x6B, 0x45, 0x0B, 0x68, 0x03, 0x58, 0x56, 0xDD, 0x1B, 0x58, 0x33, 0x90, 0xDE, 0x52, 0xD7, 0xD0, 0x5F, 0xB5, 0x7E, 0x1E, 0xC9, 0x53, 0x91, 0x27, 0xEA, 0xEE, 0x09, 0x64, 0xDC, 0xE9, 0x69, 0xD2, 0x40, 0xEF, 0x5B, 0xE3, 0x6F, 0xF3, 0xA1, 0x03, 0x6E, 0x80, 0x38, 0xA0, 0x31, 0xAF, 0x04, 0xAD, 0xD6, 0xD3, 0xAC, 0x05, 0x45, 0x8C, 0x5B, 0x0D, 0x95, 0x0A, 0x12, 0xA8, 0xC7, 0x6C, 0x9F, 0xF8, 0x1D, 0xDC, 0x94, 0xEE, 0x81, 0x58, 0x62, 0x0A, 0x3D, 0x43, 0x77, 0x44, 0xEA, 0x27, 0x0A, 0x82, 0x77, 0x8E, 0xF6, 0x17, 0xD0, 0x01, 0xC8, 0x62, 0x57, 0xD3, 0xBB, 0x9B, 0xE4, 0xB2, 0xC1, 0x29, 0x59, 0x9A, 0x57, 0x1A, 0x9F, 0x3C, 0x7F, 0xF1, 0xA2, 0x3C, 0x22, 0x4A, 0x54, 0xA7, 0x0E, 0x01, 0x58, 0x4E, 0xC7, 0x92, 0xAC, 0x5A, 0xBF, 0x6E, 0xCE, 0xC8, 0x19, 0x83, 0x87, 0x78, 0x1C, 0x9A, 0xE6, 0x00, 0xAB, 0x43, 0x74, 0x01, 0xBF, 0xB0, 0x03, 0x90, 0x00, 0x13, 0xEC, 0x7B, 0x03, 0xD9, 0x40, 0xFB, 0xF8, 0x27, 0x69, 0xB4, 0xB9, 0xCE, 0x57, 0xA1, 0xB3, 0xA5, 0xEC, 0x84, 0x73, 0x26, 0xE1, 0xBF, 0xD5, 0x0E, 0x04, 0x67, 0xA5, 0x01, 0x33, 0xDC, 0x57, 0x1B, 0xD6, 0x8A, 0xF7, 0x94, 0x7B, 0xCB, 0x18, 0xA0, 0x74, 0xFF, 0x1E, 0xD5, 0x2B, 0xF0, 0x29, 0x12, 0xA0, 0x30, 0x22, 0xB5, 0x1B, 0xFB, 0x2A, 0x2F, 0xF6, 0xA3, 0x39, 0xD5, 0x83, 0x50, 0x3E, 0xBC, 0xB3, 0x24, 0x73, 0xB3, 0xD6, 0xF3, 0x56, 0xA6, 0xAF, 0x79, 0xA5, 0xF6, 0x98, 0x72, 0x02, 0x78, 0x1E, 0xCF, 0xF1, 0x36, 0x00, 0xD7, 0x3B, 0xBC, 0x6F, 0x05, 0xD4, 0x06, 0xF2, 0x51, 0x27, 0x92, 0xC1, 0x12, 0x60, 0x2B, 0x50, 0xC7, 0x6A, 0x1B, 0xBE, 0xAC, 0x85, 0xC2, 0xF6, 0x6D, 0x81, 0xC0, 0x41, 0xD4, 0x04, 0x21, 0x75, 0xC2, 0x8E, 0x3A, 0xF3, 0xBB, 0x47, 0x6C, 0xAE, 0x98, 0x2E, 0x74, 0x19, 0x8D, 0x59, 0x7B, 0xCA, 0x2F, 0xB8, 0xF2, 0x0E, 0x66, 0x6B, 0xFF, 0x2A, 0x29, 0xFD, 0xB4, 0x34, 0x23, 0x24, 0x00, 0x9B, 0xFF, 0x06, 0xC4, 0x89, 0x93, 0x1F, 0x2D, 0xC0, 0x75, 0x67, 0xA9, 0xEC, 0x93, 0xC5, 0x06, 0xA3, 0x9D, 0x5E, 0x9F, 0x94, 0xB8, 0x96, 0x9F, 0x99, 0xEA, 0xE4, 0x69, 0x98, 0x03, 0x25, 0xFF, 0x68, 0xDF, 0xBB, 0x1B, 0x70, 0x22, 0x00, 0x4D, 0x60, 0x19, 0xDE, 0xCC, 0x06, 0x28, 0x33, 0x98, 0x49, 0xA3, 0x09, 0xFA, 0x3B, 0x64, 0x7C, 0xEE, 0x88, 0x5D, 0x35, 0xD8, 0x53, 0xA3, 0xDC, 0x1F, 0x2A, 0x12, 0x68, 0x9F, 0xA1, 0x96, 0x8C, 0xAF, 0xDF, 0x4D, 0x6C, 0xEE, 0xFE, 0xBB, 0x7B, 0x9F, 0x62, 0x6C, 0x8F, 0x19, 0x6A, 0xC6, 0xD6, 0xE1, 0xC0, 0x92, 0xBB, 0x00, 0xBA, 0x0A, 0x9F, 0xF8, 0xA6, 0xDB, 0x5D, 0xC5, 0xBA, 0xF7, 0xDD, 0x68, 0x8F, 0xF9, 0xBC, 0xEC, 0x52, 0x95, 0x83, 0xD5, 0xBF, 0xE3, 0x29, 0x6A, 0x18, 0x28, 0x7D, 0x07, 0xDB, 0x73, 0xA8, 0x2D, 0x40, 0x13, 0x88, 0x75, 0xAF, 0x0B, 0x19, 0x77, 0x3A, 0xCC, 0x96, 0x7B, 0xE9, 0x30, 0x7B, 0x4A, 0x19, 0x8D, 0xFD, 0x62, 0x68, 0x35, 0x45, 0xE6, 0x4B, 0xE8, 0xE7, 0x48, 0xD4, 0xBD, 0x27, 0xD9, 0x6A, 0x63, 0xA4, 0x4A, 0xC0, 0xE8, 0xDA, 0x53, 0x0B, 0x94, 0x78, 0xD8, 0x42, 0x8D, 0x2B, 0xB4, 0x54, 0xBD, 0xE2, 0xEC, 0x01, 0xB0, 0x84, 0x8D, 0x9D, 0xEE, 0x2F, 0xA7, 0x3D, 0xB3, 0x5B, 0xB6, 0xDC, 0x6D, 0x99, 0x65, 0x60, 0x41, 0x45, 0xCD, 0x79, 0xF3, 0x97, 0x74, 0x22, 0xFB, 0x0C, 0x12, 0x61, 0x6F, 0xDD, 0x47, 0x8A, 0xAE, 0xC6, 0xCA, 0x7C, 0x45, 0x27, 0xBE, 0xE7, 0x75, 0x0B, 0xA2, 0xD1, 0xE7, 0x2F, 0x1B, 0xB0, 0xBE, 0x9B, 0x0D, 0x7A, 0x02, 0xED, 0x83, 0xF5, 0xD4, 0xB0, 0x38, 0x20, 0x01, 0xD8, 0xC4, 0x6E, 0x76, 0xD1, 0x68, 0x86, 0x28, 0xAA, 0xCA, 0xB7, 0xAA, 0x85, 0x37, 0x96, 0x64, 0x8F, 0xE9, 0x54, 0x81, 0x1C, 0x05, 0x8A, 0xFA, 0x2D, 0xAD, 0xE9, 0x84, 0xAA, 0xBF, 0x8C, 0x8E, 0x88, 0xA7, 0x93, 0xEA, 0xAE, 0xC5, 0xA9, 0x38, 0x71, 0x0F, 0x03, 0x3A, 0x81, 0x33, 0xE0, 0x65, 0xFE, 0x66, 0x7E, 0x27, 0x04, 0xC4, 0x83, 0xCC, 0x5F, 0x06, 0x8A, 0x1F, 0x4D, 0xA2, 0x7A, 0x14, 0x7E, 0x6D, 0x01, 0xBA, 0x7F, 0xFD, 0x0A, 0x92, 0x65, 0xF0, 0x03, 0x39, 0x81, 0xD6, 0x35, 0xF0, 0x00, 0x18, 0x9D, 0xD4, 0x0D, 0x14, 0x5B, 0x33, 0xFA, 0x8D, 0xA5, 0x2C, 0xF8, 0x02, 0x72, 0x50, 0xB4, 0x64, 0xD0, 0x68, 0x0E, 0xC7, 0xB0, 0x26, 0xDA, 0x6B, 0xB7, 0xC0, 0x31, 0x3C, 0xAD, 0x19, 0x2D, 0x1A, 0x66, 0x72, 0xAC, 0x6D, 0xAC, 0xD6, 0xEE, 0xDA, 0x77, 0x27, 0xD5, 0xF5, 0xE4, 0xA9, 0xED, 0x66, 0x1D, 0xFD, 0xBA, 0xB5, 0x00, 0x16, 0x8F, 0x42, 0xA7, 0xA5, 0xC2, 0x7D, 0x76, 0xDA, 0x0B, 0xF0, 0xA2, 0xF4, 0xF7, 0x18, 0xDD, 0x01, 0x19, 0x73, 0xC5, 0xBE, 0x45, 0x7D, 0x25, 0xEF, 0x9E, 0xAB, 0xD5, 0x3F, 0x95, 0x84, 0x38, 0x4A, 0xCF, 0x6A, 0xAC, 0xD9, 0x82, 0xF1, 0x82, 0x61, 0xE6, 0x81, 0xF9, 0x98, 0x52, 0x81, 0x1A, 0x03, 0xA9, 0x00, 0xC2, 0x78, 0x76, 0xDF, 0x13, 0x44, 0x06, 0x0C, 0xB4, 0xD9, 0x99, 0x9F, 0x01, 0x15, 0x8A, 0xF2, 0x19, 0x23, 0x77, 0xA5, 0xD9, 0x32, 0x99, 0xD4, 0x0C, 0x45, 0x52, 0x85, 0x07, 0x02, 0xA7, 0x29, 0xBF, 0x2E, 0xD7, 0x2B, 0x80, 0xF4, 0x9F, 0x80, 0x14, 0x3B, 0xA8, 0x32, 0x84, 0x64, 0xFB, 0x60, 0x6F, 0x3C, 0x64, 0xE2, 0xC4, 0x96, 0xC9, 0xF3, 0x98, 0xEC, 0x8D, 0x8C, 0xA9, 0xFF, 0x1C, 0xEC, 0xC9, 0xDE, 0xD0, 0x9E, 0x10, 0x72, 0xDE, 0x91, 0x6F, 0x4F, 0x60, 0x0B, 0x20, 0x1F, 0x04, 0x96, 0x50, 0x3B, 0x21, 0x2B, 0x11, 0x96, 0x36, 0xDD, 0x85, 0x7F, 0x3B, 0x01, 0x5F, 0x00, 0x7F, 0x25, 0xDD, 0x80, 0x3B, 0x10, 0x3A, 0x88, 0x41, 0x02, 0x19, 0x40, 0x33, 0x42, 0x93, 0xB4, 0x59, 0x4E, 0xCE, 0x91, 0x22, 0xB4, 0xDA, 0x82, 0x34, 0xA8, 0x95, 0xF8, 0x73, 0xEC, 0x42, 0xB0, 0x30, 0x6A, 0x02, 0x89, 0xCD, 0x3D, 0xF5, 0xAA, 0xFF, 0x3C, 0xE2, 0x87, 0xCE, 0x8B, 0x30, 0x6F, 0x61, 0x4F, 0xCC, 0xB1, 0xE5, 0x96, 0x75, 0x74, 0xFF, 0x75, 0x4D, 0x94, 0xA3, 0xEE, 0x28, 0x76, 0x27, 0x2B, 0xE4, 0xC0, 0xAF, 0x87, 0x4C, 0x41, 0x90, 0x93, 0xA3, 0x97, 0x01, 0x78, 0x33, 0x0F, 0xEA, 0x27, 0x9E, 0x5B, 0x30, 0xA8, 0x4C, 0x0C, 0x02, 0x09, 0x29, 0x63, 0xDE, 0x00, 0xBC, 0x61, 0xE5, 0x65, 0x00, 0x3F, 0x55, 0x01, 0xBD, 0x81, 0x32, 0x20, 0x37, 0x10, 0x06, 0xE0, 0x2F, 0xA0, 0xBF, 0xE9, 0x59, 0x70, 0x6C, 0xB8, 0x4C, 0xE9, 0x6D, 0x4E, 0xFA, 0xE7, 0xEC, 0x00, 0xAE, 0xF8, 0x1B, 0xDB, 0xC6, 0x41, 0xCF, 0xE1, 0xA4, 0x6C, 0x51, 0xC8, 0x25, 0x8C, 0xD1, 0xEC, 0x32, 0x5A, 0xD2, 0x4D, 0xCD, 0xEC, 0x91, 0x39, 0x18, 0xA8, 0x9C, 0x3C, 0x8A, 0xC5, 0xC0, 0x70, 0xFD, 0xBA, 0x94, 0xE6, 0xA9, 0x2A, 0xEC, 0xC6, 0xA7, 0x64, 0x8D, 0x70, 0x02, 0x2C, 0x20, 0x54, 0xBF, 0x0B, 0x0F, 0x77, 0x8F, 0x7D, 0x1C, 0xA0, 0xEA, 0x69, 0x5D, 0xCA, 0xA6, 0x7E, 0xEA, 0x95, 0xE3, 0x09, 0x1F, 0x64, 0xCE, 0x70, 0x0F, 0x20, 0x18, 0xEF, 0x4B, 0x40, 0x88, 0x1A, 0x08, 0xB0, 0x6D, 0xB0, 0x01, 0x59, 0x40, 0x1C, 0xA3, 0x35, 0xE2, 0xEE, 0x51, 0x98, 0x34, 0xA9, 0x93, 0x31, 0x91, 0x73, 0xCF, 0xD0, 0xE9, 0x8C, 0xD9, 0x53, 0x37, 0x7C, 0x84, 0xC3, 0xB0, 0x5D, 0x8E, 0xD1, 0xB8, 0x11, 0x1C, 0xA5, 0x7A, 0x67, 0x79, 0x36, 0xBF, 0xAE, 0xFD, 0x9A, 0xB9, 0xE6, 0xD9, 0x95, 0xFC, 0x83, 0x9F, 0x1E, 0xE0, 0x72, 0xB5, 0xE9, 0xF4, 0x63, 0xC2, 0xBD, 0xF1, 0x49, 0x39, 0x26, 0xE5, 0xA7, 0xCB, 0xBF, 0x8E, 0xE2, 0x70, 0x2E, 0x40, 0x8D, 0x0F, 0x7F, 0x49, 0x80, 0x9C, 0xF9, 0x0C, 0xCB, 0x20, 0x53, 0x19, 0x33, 0xD8, 0x80, 0xF2, 0x19, 0x31, 0x9B, 0xEB, 0x00, 0xE0, 0x3D, 0x48, 0xC0, 0x04, 0xD8, 0x82, 0x37, 0x9B, 0x6F, 0x32, 0x87, 0x8C, 0x4B, 0x5A, 0x50, 0x28, 0xAF, 0x30, 0x44, 0x5A, 0xB1, 0x6F, 0x71, 0xE9, 0xDD, 0x85, 0x68, 0x10, 0xAB, 0xDE, 0xAD, 0x30, 0xE0, 0xD6, 0x5D, 0x01, 0x3A, 0x48, 0x4A, 0xE3, 0xE5, 0x6C, 0xDA, 0xB5, 0x7E, 0x62, 0xF0, 0x3D, 0xD7, 0x94, 0xC2, 0x72, 0xA0, 0x71, 0x32, 0xD1, 0x4E, 0x7A, 0x5A, 0x02, 0x16, 0x1C, 0x22, 0xF3, 0x73, 0x1B, 0xC0, 0x92, 0x16, 0xE7, 0xD7, 0xDD, 0xF3, 0xA6, 0x32, 0xDB, 0xD5, 0x81, 0x98, 0xA1, 0xE5, 0xB3, 0x84, 0x06, 0x83, 0xD5, 0x0C, 0x3A, 0x4F, 0x58, 0xB4, 0x27, 0xD8, 0xC9, 0x68, 0xDE, 0x16, 0x20, 0x6C, 0x82, 0x7A, 0x1B, 0xB0, 0x06, 0x5C, 0x01, 0x2B, 0x40, 0x73, 0xE0, 0x80, 0xC5, 0x04, 0xD9, 0x8A, 0x36, 0xDB, 0xF0, 0x24, 0xB5, 0x8E, 0x30, 0x2A, 0x83, 0xC7, 0x4C, 0x4D, 0xDF, 0x88, 0x6E, 0x4B, 0x61, 0x29, 0x4C, 0xE4, 0x81, 0xF7, 0x4A, 0xC4, 0x89, 0x79, 0x7D, 0xBA, 0xBA, 0xF7, 0x4F, 0xB0, 0x4C, 0x6D, 0xE6, 0xC5, 0x88, 0xFB, 0xFA, 0xA4, 0xD1, 0xF2, 0xDF, 0xB3, 0x9E, 0x38, 0xF8, 0x98, 0xCE, 0xFC, 0xC4, 0xB3, 0x73, 0xA6, 0x80, 0xF5, 0x2C, 0xCB, 0x3A, 0xF1, 0x3B, 0x1B, 0x93, 0x3B, 0x4C, 0xEE, 0x0D, 0x6C, 0x67, 0xD9, 0x2B, 0x50, 0xF3, 0x4A, 0xF4, 0x18, 0x6B, 0xAC, 0x24, 0xF3, 0xAF, 0x17, 0x4B, 0x70, 0x0D, 0xBF, 0xC4, 0x1A, 0xF8, 0x07, 0xDC, 0x58, 0x3E, 0x78, 0x03, 0x55, 0x40, 0xC7, 0xA0, 0x26, 0x6E, 0x2B, 0x83, 0x02, 0x64, 0x50, 0x46, 0x9B, 0x8D, 0x95, 0xA8, 0x4C, 0x98, 0x7E, 0x35, 0x21, 0xCF, 0x6C, 0xDC, 0x4B, 0x29, 0x53, 0xA7, 0x93, 0xD8, 0xB1, 0xFA, 0x88, 0xA4, 0x9E, 0xA4, 0xC8, 0x5F, 0xB1, 0xC8, 0x1E, 0x9B, 0x25, 0x7E, 0x5D, 0x9B, 0xA8, 0x71, 0xE6, 0xFC, 0x66, 0x1F, 0xC6, 0x95, 0xE0, 0x6C, 0xC2, 0xC9, 0x24, 0x0C, 0x48, 0xDF, 0xC1, 0x90, 0x0A, 0xA8, 0xC0, 0x9E, 0xB5, 0x00, 0x31, 0x60, 0x07, 0xA0, 0x7B, 0x90, 0x00, 0x76, 0xB4, 0x3C, 0xF1, 0xE5, 0xF2, 0xF9, 0x17, 0x68, 0x09, 0xFE, 0xEB, 0x45, 0xCD, 0x6D, 0xC0, 0x0D, 0xE8, 0x85, 0x20, 0xFE, 0x4E, 0x40, 0x0A, 0xD0, 0x81, 0x35, 0x90, 0x0B, 0xE8, 0xC9, 0x0F, 0x58, 0x09, 0xA8, 0xD3, 0x66, 0xFA, 0xF9, 0x21, 0x53, 0xE2, 0x38, 0x20, 0x7B, 0x43, 0x39, 0x1E, 0x3D, 0x50, 0x1A, 0x15, 0x2B, 0x5B, 0xE1, 0xFF, 0x33, 0x45, 0xD1, 0xA9, 0x05, 0x1D, 0x69, 0x4F, 0x7C, 0xA5, 0x58, 0xB5, 0x7A, 0x47, 0x40, 0xB7, 0x3D, 0xAD, 0x8C, 0x12, 0x50, 0x7D, 0x84, 0x66, 0x03, 0xE8, 0x47, 0x11, 0xF4, 0x74, 0x03, 0x64, 0x77, 0x5E, 0x01, 0x62, 0x01, 0x5E, 0xC0, 0x9D, 0x1C, 0x27, 0xA7, 0x2E, 0xAF, 0x19, 0xB3, 0x49, 0x20, 0x59, 0x53, 0x36, 0xD8, 0x4F, 0x95, 0x5E, 0xE8, 0x2D, 0x23, 0xE6, 0x09, 0xD8, 0x40, 0xE8, 0x49, 0x36, 0xC0, 0x0B, 0x48, 0x39, 0x45, 0x68, 0xB4, 0x9A, 0x61, 0x4C, 0xDA, 0xFA, 0xC2, 0x2C, 0x6E, 0xF2, 0xFD, 0xB1, 0xB2, 0x64, 0x2E, 0xEA, 0x36, 0xB5, 0x1E, 0x3D, 0xD5, 0x58, 0x09, 0xA9, 0x51, 0x37, 0xAA, 0xE7, 0x3C, 0x0E, 0xB5, 0x60, 0xFD, 0x22, 0xD5, 0x3B, 0x1F, 0x31, 0x29, 0xA1, 0x63, 0x82, 0xE1, 0x46, 0xBF, 0x8A, 0x32, 0x97, 0x01, 0xBB, 0x9F, 0x8A, 0xAF, 0x56, 0x60, 0x8F, 0x46, 0x24, 0x1D, 0xE1, 0x05, 0x9C, 0xAF, 0x6D, 0x80, 0xE7, 0x4F, 0x81, 0x74, 0xCF, 0xD8, 0xDE, 0x76, 0x44, 0xE6, 0x37, 0x85, 0x76, 0x12, 0xF0, 0x02, 0xCA, 0xEF, 0x9B, 0xE4, 0x1A, 0x98, 0x03, 0x5A, 0xC0, 0xB6, 0xDB, 0xE7, 0x61, 0xF6, 0xDC, 0xFE, 0x8F, 0xD5, 0xFC, 0x0B, 0x11, 0x84, 0xEC, 0xBF, 0x1A, 0x77, 0x4A, 0x34, 0x44, 0xF8, 0x51, 0x0C, 0xE3, 0xA8, 0x96, 0xDE, 0x89, 0x30, 0x92, 0xEA, 0x87, 0xE8, 0xBC, 0xEB, 0xB3, 0xD7, 0xDB, 0xD4, 0x92, 0x4D, 0x10, 0x19, 0x3F, 0x1B, 0xF0, 0x61, 0x25, 0x20, 0x7A, 0x37, 0x01, 0x58, 0x0D, 0xC8, 0xBA, 0x3B, 0x79, 0x89, 0xDC, 0x11, 0xE6, 0xA3, 0x13, 0xEB, 0x00, 0x57, 0xD1, 0xD2, 0x01, 0xC7, 0x36, 0xE5, 0x2F, 0xC7, 0xBE, 0x27, 0x77, 0xFA, 0xD2, 0x46, 0xBD, 0x5A, 0x35, 0x00, 0x1D, 0x4F, 0x41, 0xDE, 0x5E, 0x77, 0x5D, 0x5E, 0x0E, 0x24, 0xEE, 0x3A, 0xB5, 0x6D, 0x40, 0x07, 0xAD, 0x16, 0xDF, 0xE4, 0xDF, 0x5E, 0x7F, 0xA5, 0x27, 0x2D, 0x64, 0x4D, 0x9E, 0x5A, 0x4F, 0xC0, 0xD8, 0x55, 0xE0, 0x54, 0xDF, 0x33, 0x9A, 0x43, 0x6F, 0xB9, 0xE5, 0x7C, 0x7A, 0xF5, 0x6E, 0xBA, 0x4F, 0x8D, 0x3B, 0x83, 0x03, 0xBB, 0xC7, 0x83, 0xAD, 0xAC, 0x42, 0xBE, 0x54, 0x83, 0x36, 0x4B, 0x58, 0xC7, 0xBE, 0x2B, 0xAF, 0x87, 0xC0, 0xAF, 0xE2, 0xEB, 0xD8, 0xD0, 0xC7, 0x4E, 0xF3, 0x69, 0xD1, 0xF3, 0x3D, 0x43, 0x3C, 0x82, 0x6E, 0xA4, 0xE3, 0x9E, 0x66, 0x55, 0xCB, 0x9D, 0x0B, 0xEF, 0x41, 0xBF, 0x27, 0x50, 0x74, 0x5E, 0xF4, 0xE0, 0x74, 0xFA, 0x03, 0x3C, 0x01, 0x29, 0xC0, 0x58, 0xB2, 0xB4, 0x69, 0xB5, 0xFC, 0x72, 0x14, 0x7A, 0xF9, 0x27, 0xA4, 0xB0, 0x65, 0x5F, 0xF1, 0x15, 0xB3, 0xFA, 0x7C, 0x8B, 0x81, 0x82, 0x3C, 0xD7, 0xED, 0xE8, 0x11, 0x59, 0x49, 0xA9, 0xC8, 0x27, 0x50, 0xB0, 0x9F, 0x58, 0xDE, 0x02, 0xBC, 0x9F, 0x5C, 0x0E, 0x96, 0xE8, 0xBF, 0xFD, 0xED, 0x04, 0xA8, 0x7D, 0x47, 0xFD, 0xBA, 0xEE, 0x3E, 0x89, 0xDC, 0x76, 0xDA, 0x81, 0x4A, 0x20, 0x0D, 0xB8, 0xDB, 0x17, 0xDB, 0xDD, 0xEE, 0xE2, 0xAA, 0x87, 0x6D, 0x20, 0xF2, 0xE9, 0x8B, 0x54, 0x40, 0x8E, 0xB5, 0x77, 0x00, 0xAB, 0xEE, 0x0E, 0xAF, 0x36, 0xD8, 0x0D, 0xA8, 0x9D, 0xD2, 0x6F, 0x5A, 0xAD, 0x3E, 0x49, 0xB5, 0xAB, 0x23, 0x68, 0x7D, 0xFE, 0x61, 0x9B, 0x58, 0x9E, 0xFE, 0x21, 0xDB, 0x32, 0x11, 0x1B, 0x0A, 0x43, 0xAF, 0xC7, 0xD2, 0x3B, 0xBC, 0xF2, 0x76, 0x1A, 0x3C, 0x85, 0xBF, 0x3E, 0xC3, 0xA3, 0xEF, 0x29, 0x56, 0xF2, 0xD8, 0x70, 0x71, 0xC5, 0x07, 0xDA, 0xEE, 0xD0, 0x9C, 0x2B, 0x77, 0x0A, 0x5A, 0x06, 0xF0, 0x18, 0xF4, 0xFD, 0x89, 0xD6, 0x3E, 0xC1, 0x96, 0x3C, 0xDD, 0x76, 0xA7, 0xD4, 0x96, 0xB3, 0x70, 0xD0, 0x1C, 0xF7, 0x09, 0x04, 0x23, 0x04, 0x0E, 0x44, 0x0E, 0x36, 0xA0, 0x05, 0xAC, 0x8D, 0x37, 0xD3, 0xEE, 0x90, 0x42, 0x04, 0xAD, 0xD6, 0x5F, 0x50, 0x2A, 0x74, 0xCC, 0x55, 0x23, 0x88, 0x6E, 0x73, 0x93, 0x0A, 0x41, 0x4C, 0x6B, 0x22, 0xA0, 0x15, 0x1F, 0xAC, 0x32, 0x19, 0x01, 0x7D, 0xCA, 0x18, 0xAF, 0x22, 0xF3, 0x38, 0x7F, 0xAE, 0x9D, 0xC0, 0xB2, 0x3B, 0xBD, 0x25, 0xFC, 0x2E, 0x9E, 0x96, 0x7D, 0x2F, 0x6F, 0x1A, 0x80, 0xCB, 0xDD, 0xF6, 0x3E, 0x14, 0xD8, 0xF5, 0x74, 0x4F, 0x2C, 0xE0, 0xAE, 0xE5, 0x64, 0xB4, 0x1D, 0xC5, 0x31, 0xB0, 0x93, 0x15, 0x0B, 0x6F, 0x01, 0x17, 0x20, 0xA9, 0x2F, 0x60, 0x40, 0x16, 0x3D, 0xC3, 0x83, 0xF5, 0xF4, 0x47, 0x5A, 0xB7, 0x61, 0xD9, 0x64, 0xE4, 0xF8, 0xD4, 0x72, 0x7D, 0x56, 0x13, 0xB1, 0xBF, 0x6C, 0xB4, 0x91, 0x8A, 0x82, 0x8A, 0x2B, 0x7A, 0x43, 0x19, 0x32, 0x50, 0x6A, 0xA3, 0x20, 0x3A, 0x1D, 0x5D, 0x25, 0x03, 0x7B, 0xA8, 0xBC, 0xDD, 0xB4, 0xB7, 0xFC, 0xB4, 0x25, 0xE2, 0xC4, 0x5C, 0x43, 0x00, 0x97, 0xBB, 0x58, 0xDC, 0x17, 0xC7, 0xC5, 0x93, 0xDA, 0x54, 0x77, 0x99, 0xF5, 0xEE, 0xFB, 0x4D, 0x6A, 0x00, 0xA4, 0x02, 0x8C, 0xA6, 0x76, 0x10, 0xC7, 0xF6, 0x8C, 0xF8, 0x72, 0x01, 0x1F, 0x73, 0xC9, 0x5D, 0x29, 0xBC, 0x13, 0xD0, 0x41, 0x3E, 0xBD, 0xBB, 0x6A, 0x01, 0xF9, 0x74, 0xFF, 0xDC, 0x7B, 0x6C, 0x38, 0x38, 0xE2, 0x9B, 0x4E, 0xAB, 0x6D, 0xE4, 0x65, 0x56, 0x7D, 0xB9, 0x57, 0x6B, 0x5A, 0x1C, 0x87, 0x20, 0x95, 0xD9, 0xF6, 0x9E, 0x1D, 0xC6, 0x90, 0xC5, 0x63, 0x8D, 0x28, 0x7D, 0xAD, 0xBB, 0x3C, 0x3B, 0x1E, 0xAB, 0xD5, 0x25, 0x73, 0x7E, 0xB5, 0x1F, 0x2A, 0x6C, 0x5F, 0xA7, 0x31, 0xE3, 0xAD, 0x56, 0xB0, 0x69, 0xD1, 0x06, 0x82, 0xFA, 0x11, 0x8F, 0xB6, 0x84, 0xE8, 0x2D, 0x3F, 0xAC, 0x09, 0x2C, 0x05, 0x4E, 0x5A, 0x41, 0xFD, 0x32, 0x33, 0xB7, 0x9E, 0x1A, 0xC7, 0x65, 0xF7, 0x36, 0x90, 0x7E, 0x6F, 0x03, 0x1E, 0xF4, 0x61, 0x03, 0x5E, 0x03, 0x07, 0x34, 0x6E, 0x51, 0xBF, 0x6C, 0xA0, 0x8D, 0x17, 0x5F, 0x5A, 0x4D, 0x50, 0xA6, 0xE1, 0xF1, 0xE7, 0x3D, 0x09, 0x7E, 0x05, 0x9D, 0x65, 0x09, 0xDC, 0x9F, 0x76, 0x60, 0x00, 0x22, 0x54, 0xB0, 0xA7, 0xE4, 0xDB, 0xB8, 0x77, 0x3E, 0xCD, 0xA5, 0x78, 0x58, 0x38, 0x7F, 0xB5, 0xE3, 0x88, 0x1D, 0xD4, 0x6C, 0x66, 0x8C, 0xD1, 0x3E, 0x0D, 0xBA, 0x8E, 0x3E, 0xE8, 0xA0, 0xB9, 0x09, 0x2A, 0x17, 0x18, 0x86, 0xB8, 0xD8, 0x22, 0x06, 0x50, 0xBB, 0xC5, 0x21, 0xB7, 0xFC, 0xD6, 0x20, 0x76, 0xA0, 0xEE, 0x53, 0xC3, 0xB7, 0xD9, 0x5A, 0x84, 0x05, 0x08, 0x01, 0xB8, 0x02, 0x3D, 0x7E, 0x02, 0x5F, 0x40, 0xE9, 0x8D, 0x5C, 0x80, 0x0F, 0xB4, 0x9E, 0x94, 0xFA, 0xA2, 0xD5, 0x14, 0xB2, 0x78, 0xBD, 0xA7, 0xB7, 0x71, 0x8C, 0x61, 0x27, 0x6D, 0xDE, 0x0B, 0xBD, 0x48, 0x76, 0xE0, 0x15, 0xB7, 0xF1, 0x53, 0x6F, 0x66, 0xA8, 0x5D, 0xCD, 0x6B, 0xEC, 0x3A, 0x92, 0x6D, 0x16, 0x8D, 0xF8, 0x49, 0xD0, 0x67, 0xF7, 0x37, 0x96, 0x02, 0xB2, 0x40, 0x2F, 0x8D, 0xA7, 0xC6, 0xFB, 0x44, 0x19, 0x3A, 0x48, 0x06, 0x00, 0x60, 0xEC, 0xA0, 0x45, 0x12, 0x08, 0x05, 0x64, 0xE0, 0x6B, 0xDE, 0xDC, 0xBF, 0x7A, 0xC4, 0x3C, 0xB5, 0x1F, 0x2D, 0x3F, 0x9F, 0x99, 0x1E, 0x6F, 0xA7, 0x14, 0x50, 0x73, 0xE1, 0xD7, 0x06, 0x52, 0x07, 0x09, 0x44, 0x01, 0xEE, 0x83, 0xFD, 0x7B, 0x88, 0xAB, 0xDE, 0x18, 0xCD, 0xE0, 0xB1, 0x5B, 0x3A, 0x17, 0x54, 0x1D, 0x6F, 0xA7, 0x50, 0x73, 0x0B, 0x4E, 0xDD, 0x29, 0x67, 0x0C, 0xE3, 0xB1, 0x7D, 0x5F, 0xDD, 0xDF, 0x72, 0x3F, 0x7D, 0x92, 0x92, 0x39, 0x02, 0x71, 0xEA, 0x19, 0x81, 0x0A, 0x60, 0xF7, 0xED, 0xBD, 0xE6, 0x38, 0xCA, 0xBE, 0x4A, 0xCD, 0x81, 0x5F, 0xE0, 0x2A, 0x1A, 0x0F, 0xC3, 0x81, 0xB5, 0x1E, 0x45, 0x8A, 0x05, 0x08, 0x17, 0x9D, 0xAB, 0x01, 0x35, 0x0B, 0x8D, 0x65, 0x42, 0x23, 0x7A, 0x06, 0xD7, 0x6A, 0xC0, 0x0C, 0x60, 0xDD, 0x96, 0x6D, 0x20, 0xD7, 0x60, 0x03, 0xDE, 0xF7, 0x7F, 0x53, 0x05, 0x8C, 0x71, 0x84, 0xA4, 0xD5, 0x1C, 0x5E, 0x48, 0x95, 0xCF, 0x6A, 0xBD, 0x03, 0x1E, 0xE3, 0xA9, 0xFE, 0x11, 0x6B, 0xAC, 0x6E, 0xD6, 0xD3, 0x0C, 0x3B, 0x30, 0x79, 0xA4, 0xE9, 0xC1, 0xBD, 0x8C, 0xC6, 0x8C, 0x3C, 0x73, 0xCE, 0xCF, 0xE6, 0xC4, 0x04, 0x3A, 0x81, 0x4D, 0x7F, 0xBE, 0x3E, 0x96, 0x5C, 0x80, 0x50, 0xC1, 0xF6, 0x7C, 0x79, 0x60, 0x19, 0x4D, 0x7F, 0x37, 0x4D, 0xD4, 0xBE, 0xB5, 0x7D, 0xF1, 0xD0, 0x4F, 0x70, 0x3E, 0xC7, 0x22, 0xAC, 0xFE, 0xF1, 0x11, 0x3A, 0x3C, 0xAA, 0x72, 0x0A, 0xC4, 0x1E, 0x37, 0x69, 0xDC, 0x3E, 0x37, 0xD9, 0x37, 0x16, 0xFF, 0xDB, 0x06, 0x22, 0x01, 0xBA, 0x75, 0xDD, 0x69, 0x34, 0x88, 0xB7, 0xD6, 0x9E, 0x6E, 0x66, 0xC1, 0x62, 0x25, 0x04, 0x0E, 0xB6, 0xEB, 0x64, 0x66, 0xE6, 0x6C, 0x25, 0xFB, 0x43, 0x86, 0xDD, 0x01, 0x96, 0xB8, 0x02, 0xA0, 0xCE, 0x2C, 0x18, 0x3B, 0x2D, 0x72, 0x64, 0x0F, 0x68, 0xB5, 0xFC, 0xB5, 0x79, 0xB2, 0x13, 0x41, 0x3F, 0xAD, 0xB5, 0x5E, 0xE4, 0x7D, 0x6D, 0xDD, 0x7A, 0x09, 0xA3, 0xF4, 0x06, 0x6C, 0x01, 0xCE, 0x13, 0x99, 0xE7, 0xD8, 0x37, 0x39, 0xDB, 0x27, 0xC0, 0xC2, 0xEA, 0xB3, 0xC5, 0x11, 0x07, 0xB4, 0x52, 0x98, 0xF8, 0x0E, 0xF0, 0x85, 0x0E, 0x36, 0x60, 0x83, 0xD5, 0x77, 0x28, 0x70, 0x19, 0x50, 0xC7, 0x6A, 0x89, 0x2F, 0x36, 0x13, 0x3B, 0xA6, 0xF7, 0xF8, 0x4A, 0xC5, 0x56, 0x32, 0x49, 0x1E, 0xBE, 0x1D, 0x81, 0x41, 0x0B, 0x24, 0x4C, 0xF6, 0x95, 0x73, 0xBD, 0xD6, 0x55, 0x61, 0x56, 0xCC, 0xAD, 0xD2, 0xE3, 0x7D, 0x6F, 0x1F, 0x2F, 0xE8, 0x7C, 0x4A, 0x78, 0x56, 0xF1, 0x49, 0xFA, 0x94, 0xD0, 0x05, 0x95, 0x47, 0xF7, 0x2B, 0x9C, 0x37, 0x53, 0x83, 0x9D, 0x9D, 0x66, 0x9E, 0x09, 0x63, 0xA4, 0x0A, 0x6C, 0x01, 0x64, 0x6C, 0x20, 0xCE, 0x7A, 0xAA, 0xF1, 0xEF, 0x53, 0x64, 0xD2, 0xC6, 0xA9, 0x69, 0xE3, 0x92, 0x5B, 0x80, 0xC7, 0xA8, 0x05, 0x26, 0x10, 0x06, 0xC0, 0xCD, 0x07, 0xE7, 0x18, 0x3E, 0x19, 0x50, 0x0E, 0x64, 0x02, 0xDD, 0x78, 0xC5, 0x8B, 0x46, 0x63, 0x1C, 0x8A, 0x61, 0x42, 0xBF, 0x8A, 0x0B, 0x3A, 0x7A, 0xCA, 0x56, 0x7B, 0x82, 0x3E, 0x8E, 0x2F, 0x9D, 0x5F, 0xB0, 0xA0, 0x58, 0xF8, 0x33, 0xA0, 0xF7, 0x42, 0x6A, 0x31, 0xE1, 0x64, 0x62, 0x3F, 0x3A, 0x4E, 0xC6, 0x4B, 0x77, 0x0F, 0xFF, 0x0D, 0xE1, 0xA8, 0x3D, 0x7E, 0x64, 0x4A, 0x8E, 0xB2, 0xB2, 0x8C, 0x33, 0xA3, 0x6E, 0x95, 0x50, 0x15, 0x60, 0x27, 0xA0, 0x0A, 0xD8, 0x55, 0xCE, 0x89, 0x44, 0x36, 0x94, 0x1A, 0xD0, 0xA1, 0x3F, 0xD5, 0x2B, 0x6B, 0x7C, 0xB7, 0xCB, 0x01, 0x16, 0xBF, 0x58, 0x01, 0xAC, 0x18, 0x91, 0x81, 0x26, 0x60, 0x05, 0xC4, 0x06, 0x8A, 0x95, 0x11, 0x0B, 0xD8, 0x0E, 0x68, 0xD3, 0x66, 0xFD, 0x1D, 0xA8, 0x5D, 0x1D, 0x5F, 0x45, 0x1D, 0x5E, 0x16, 0xC6, 0xB8, 0xD7, 0x46, 0xEC, 0x6E, 0x3B, 0x76, 0xA5, 0xAD, 0xF0, 0xB7, 0x4D, 0x1B, 0xB3, 0x7E, 0x4A, 0x19, 0x63, 0x9F, 0x8C, 0x46, 0x76, 0x53, 0xBC, 0xC5, 0x2D, 0x73, 0x2C, 0x69, 0x31, 0xB1, 0x94, 0x67, 0x14, 0x51, 0x06, 0x20, 0x1D, 0xE8, 0x35, 0x0F, 0x83, 0x0F, 0x27, 0xE4, 0x14, 0x80, 0xCB, 0x60, 0x01, 0xDA, 0x00, 0xF7, 0x69, 0xF7, 0x5F, 0x11, 0x62, 0x4C, 0x11, 0xC5, 0x1A, 0x4C, 0x68, 0xD4, 0x30, 0x3B, 0x91, 0x20, 0x55, 0x40, 0xEA, 0xED, 0xEA, 0x74, 0x01, 0x82, 0x28, 0x80, 0xAF, 0x50, 0xF4, 0x73, 0x09, 0x70, 0x52, 0xD5, 0x0A, 0x1E, 0x05, 0xDB, 0x10, 0xF5, 0x76, 0xCD, 0x4B, 0x34, 0xB2, 0x46, 0x7D, 0xB3, 0xC3, 0x66, 0x49, 0x74, 0x2C, 0xAC, 0x75, 0xDD, 0x9B, 0x57, 0x3F, 0x95, 0x3F, 0x6A, 0x2C, 0xB2, 0x9C, 0xF2, 0xB8, 0x9A, 0x3A, 0x92, 0x9A, 0x09, 0x11, 0x53, 0x68, 0xBE, 0x59, 0xA0, 0xCE, 0x90, 0xDA, 0x8C, 0x9B, 0x4B, 0x5D, 0xB4, 0x00, 0xD4, 0xBE, 0xC2, 0x20, 0x3D, 0x70, 0x19, 0xC4, 0x80, 0xC5, 0xA0, 0x36, 0x3F, 0x37, 0x27, 0x08, 0x11, 0x96, 0xA8, 0x4C, 0xBD, 0x12, 0x87, 0x16, 0x6B, 0x02, 0x67, 0xDC, 0x58, 0x8F, 0x9B, 0x57, 0x81, 0x30, 0xA0, 0xE3, 0x76, 0x86, 0xEF, 0x81, 0x04, 0x60, 0x1B, 0xF0, 0x1E, 0x2F, 0xB8, 0xD3, 0x66, 0x7B, 0xBA, 0xEE, 0x35, 0x86, 0x79, 0x25, 0x4E, 0x17, 0x1A, 0xD3, 0xE2, 0xB0, 0x31, 0xFA, 0xA2, 0x27, 0x84, 0x3B, 0x36, 0x73, 0xF9, 0x46, 0x56, 0x3D, 0x93, 0x53, 0x7F, 0xC5, 0x0E, 0x92, 0xA7, 0xAC, 0xFE, 0x44, 0x6B, 0xE7, 0x53, 0x18, 0x6C, 0xC6, 0x00, 0x90, 0x2D, 0x36, 0x31, 0x06, 0xB6, 0x02, 0x5A, 0x40, 0x32, 0x9A, 0xC4, 0x52, 0x5B, 0x19, 0xBB, 0x18, 0xEC, 0xA9, 0x94, 0xF9, 0x76, 0x20, 0xB8, 0x31, 0xB2, 0xB0, 0x8D, 0x7F, 0xA3, 0x19, 0x52, 0x2C, 0x2D, 0x63, 0x4E, 0x99, 0x2C, 0x80, 0xE5, 0x94, 0xDA, 0x30, 0xE4, 0x32, 0x80, 0x66, 0xD5, 0x1E, 0x6C, 0x60, 0xD5, 0x40, 0x80, 0xBD, 0x80, 0x12, 0xDA, 0x4C, 0xEE, 0x05, 0xCD, 0x0D, 0x8D, 0xB6, 0xCB, 0x46, 0xCF, 0x3E, 0x30, 0x76, 0xBD, 0x11, 0x38, 0x5C, 0x82, 0xA5, 0x1D, 0x36, 0xEB, 0xA7, 0xFA, 0x33, 0xE3, 0x57, 0xE8, 0xC1, 0x2C, 0x39, 0xD3, 0x53, 0xAD, 0x18, 0x57, 0xF1, 0xE1, 0x1E, 0xF3, 0xF4, 0x51, 0x01, 0xB0, 0x9A, 0xC1, 0x37, 0x70, 0x07, 0x72, 0x03, 0xBB, 0x61, 0x09, 0x4D, 0x80, 0x9F, 0x6C, 0x03, 0x3E, 0x83, 0x56, 0xA7, 0x84, 0x4A, 0x39, 0xD5, 0xF6, 0x59, 0x75, 0x20, 0x70, 0xF6, 0x61, 0xD2, 0x66, 0x02, 0xE6, 0xF9, 0x90, 0xE3, 0x93, 0x50, 0x05, 0x52, 0x00, 0xDC, 0x75, 0x31, 0xE6, 0x3F, 0xEC, 0x02, 0x6C, 0x01, 0x11, 0x40, 0x36, 0xEE, 0xE8, 0x2B, 0x69, 0x33, 0xC5, 0x6F, 0x7D, 0x7A, 0xD7, 0xE0, 0xBF, 0xED, 0xE8, 0xF9, 0x6B, 0xF6, 0x6C, 0xE6, 0x05, 0x37, 0xAE, 0xC9, 0x08, 0xF2, 0xD5, 0x75, 0x8B, 0x72, 0x7F, 0xE4, 0x9A, 0x94, 0xF2, 0x54, 0x7E, 0x8B, 0x93, 0x6B, 0xD2, 0x3F, 0x4F, 0x6D, 0xBA, 0xDB, 0xBF, 0x28, 0x7E, 0x5F, 0xC0, 0xEB, 0x52, 0xB8, 0x94, 0xE3, 0x3E, 0xEB, 0x41, 0x2E, 0xA0, 0xF6, 0x20, 0x7E, 0x29, 0xD2, 0x94, 0x73, 0x84, 0x1E, 0x30, 0x33, 0x6B, 0xB9, 0xB4, 0xFC, 0x8E, 0x6E, 0xD8, 0xF4, 0x2E, 0x99, 0x13, 0x7F, 0x36, 0x60, 0xCB, 0x81, 0x03, 0xEA, 0x8F, 0xB0, 0x49, 0xCE, 0xA7, 0x00, 0x72, 0xD1, 0x6A, 0xF6, 0xD9, 0x29, 0xB3, 0x69, 0x35, 0xF8, 0xC0, 0x4D, 0xD8, 0xE4, 0x03, 0x71, 0x60, 0xFD, 0xCC, 0x95, 0xB6, 0x15, 0x75, 0x63, 0x65, 0x27, 0xB2, 0xF2, 0xF1, 0x64, 0x44, 0xD2, 0xB9, 0xC5, 0x4C, 0x7E, 0xB9, 0x13, 0xF3, 0xC5, 0xE7, 0x61, 0xDF, 0xC5, 0x14, 0x0C, 0xA6, 0x14, 0x31, 0x36, 0x5C, 0x7D, 0x47, 0x66, 0x76, 0x52, 0x72, 0x94, 0xA3, 0x79, 0xD0, 0x03, 0xFF, 0x85, 0x10, 0xF5, 0xFC, 0x7B, 0xA5, 0x57, 0xA4, 0x02, 0x96, 0xB9, 0x3A, 0x7B, 0xD5, 0x9B, 0x76, 0xD3, 0x63, 0x5F, 0x05, 0xB2, 0x81, 0x18, 0xD8, 0x7E, 0xDA, 0x56, 0x0B, 0x90, 0x31, 0xAF, 0x14, 0xAD, 0xE6, 0x88, 0xC5, 0xAE, 0x84, 0xF2, 0xA1, 0xA3, 0x70, 0x31, 0x96, 0x61, 0x9F, 0xEC, 0x91, 0x74, 0x15, 0xFF, 0x79, 0xAB, 0xF7, 0x6A, 0xB9, 0xAB, 0xA5, 0x84, 0x56, 0xBB, 0x9A, 0x31, 0xC2, 0xCF, 0x7E, 0xAB, 0x6B, 0x89, 0x51, 0x0F, 0x0E, 0x0E, 0xC2, 0xA3, 0xE8, 0x41, 0xEF, 0xEA, 0x5D, 0x1A, 0x54, 0x1B, 0xA0, 0x4B, 0x23, 0xED, 0xD1, 0x80, 0x8D, 0x41, 0x0F, 0x1C, 0xA8, 0x7D, 0x3A, 0x41, 0x8D, 0x81, 0xA8, 0xAC, 0x33, 0x7B, 0xBF, 0xC9, 0x7D, 0x8D, 0x32, 0x07, 0xBA, 0x67, 0x23, 0xA9, 0x5B, 0x47, 0x3D, 0x62, 0x90, 0x80, 0x1B, 0xA0, 0x0B, 0xD8, 0x09, 0x68, 0xB0, 0x2E, 0x9F, 0x56, 0x0B, 0x6C, 0x24, 0x69, 0x7F, 0x3D, 0xB7, 0x13, 0xFF, 0x0A, 0x6F, 0x6C, 0x1A, 0x79, 0x08, 0x84, 0xF5, 0xA2, 0xA7, 0x34, 0x67, 0xC3, 0x7D, 0xA5, 0x18, 0x6B, 0xFB, 0x9D, 0xA1, 0xF8, 0xA8, 0x27, 0x75, 0xB9, 0x8E, 0x58, 0x22, 0x4B, 0x93, 0x80, 0x7D, 0x49, 0x68, 0xFA, 0xF9, 0xF6, 0x31, 0x50, 0x22, 0x01, 0xA1, 0xB7, 0x9C, 0x8E, 0xF1, 0x0D, 0xC8, 0x1A, 0x6C, 0x60, 0x27, 0x60, 0x97, 0x56, 0x5C, 0x32, 0xF7, 0x77, 0x9D, 0x51, 0xB2, 0x67, 0x20, 0xE9, 0x06, 0x98, 0xC6, 0xBA, 0x15, 0xF0, 0xBC, 0x9B, 0x8C, 0xB8, 0x0F, 0x36, 0xA0, 0x0A, 0xD0, 0x77, 0x92, 0x7D, 0x77, 0xAF, 0x8E, 0x63, 0xB5, 0x44, 0xFC, 0x3E, 0x27, 0x56, 0xE0, 0xFD, 0x69, 0xF8, 0xF5, 0xB4, 0xD4, 0xD6, 0x5D, 0x48, 0xD5, 0x17, 0x9B, 0x02, 0x98, 0x84, 0xAB, 0xD4, 0x9C, 0x7E, 0xDB, 0xA7, 0xEE, 0x87, 0x92, 0xC8, 0x74, 0xC0, 0xAE, 0x31, 0xD0, 0x06, 0xF6, 0xBA, 0x7B, 0x50, 0x76, 0x02, 0xCA, 0x05, 0x6D, 0x0F, 0x94, 0xE6, 0x02, 0xAC, 0x7F, 0x65, 0x43, 0x72, 0xA0, 0x7B, 0x10, 0x03, 0x01, 0x68, 0xF4, 0x64, 0xE9, 0x62, 0x5C, 0x0E, 0x58, 0x3F, 0x5D, 0x53, 0xD7, 0x02, 0x82, 0xA1, 0x15, 0x07, 0x3C, 0xC7, 0xA7, 0x36, 0x88, 0x1A, 0x38, 0x60, 0x09, 0x9C, 0x2C, 0xE5, 0xA6, 0x87, 0x0D, 0x28, 0xA7, 0xD5, 0x6A, 0x2A, 0xB6, 0x29, 0x18, 0x8C, 0x3D, 0x65, 0x77, 0x4D, 0xB3, 0x7C, 0x87, 0x3B, 0x54, 0x1D, 0xCD, 0xE4, 0x04, 0x5E, 0xEF, 0x89, 0x4B, 0x65, 0xBD, 0x91, 0x63, 0x59, 0x77, 0x4F, 0x0C, 0x6D, 0xD6, 0xB1, 0x01, 0x27, 0xB9, 0x88, 0xD3, 0x4F, 0x6F, 0x1B, 0x66, 0xDE, 0x63, 0x4D, 0x12, 0x58, 0x71, 0xB7, 0x94, 0xE4, 0xDF, 0x25, 0x1A, 0xC8, 0x1C, 0x4C, 0xE0, 0x99, 0xA1, 0x2B, 0x96, 0x35, 0x16, 0x17, 0x2D, 0x29, 0x8E, 0x99, 0xB1, 0xD3, 0x02, 0x52, 0xC7, 0x16, 0x0E, 0x50, 0xC1, 0xCD, 0x12, 0x68, 0x79, 0x5A, 0x9D, 0x38, 0x20, 0x01, 0xAC, 0x05, 0x6C, 0x65, 0x26, 0x33, 0xAD, 0xD6, 0x93, 0x19, 0x65, 0x9F, 0xBB, 0x3B, 0xA7, 0x5B, 0xCD, 0xAA, 0x46, 0x1E, 0xD1, 0x1A, 0x45, 0xD7, 0xB5, 0xA7, 0x79, 0x1E, 0x90, 0x41, 0x99, 0xAB, 0x27, 0x27, 0x92, 0x2B, 0x51, 0xD1, 0x2D, 0xC4, 0xEC, 0xDF, 0x41, 0xF4, 0xAF, 0xFE, 0xD2, 0x4F, 0x4F, 0xA2, 0xA6, 0xEB, 0x27, 0x1F, 0x49, 0xE1, 0x02, 0x16, 0x13, 0x92, 0x37, 0x4C, 0xE1, 0x77, 0x43, 0xCA, 0xCD, 0x66, 0x21, 0x31, 0x0F, 0x59, 0x4B, 0x77, 0x52, 0x2A, 0xD7, 0xCF, 0x22, 0x72, 0x34, 0x3A, 0x82, 0x0E, 0xC5, 0x06, 0x6A, 0x56, 0x30, 0x36, 0x99, 0x5E, 0x1B, 0xB0, 0x35, 0xD8, 0x80, 0x34, 0xB0, 0xE6, 0xCD, 0xD6, 0xF9, 0xD4, 0x40, 0xD1, 0x68, 0xCD, 0x66, 0xE1, 0x1B, 0x69, 0x10, 0x92, 0x57, 0x4E, 0x64, 0x32, 0x0B, 0x57, 0x04, 0x9E, 0xAA, 0xDA, 0x1F, 0x52, 0xBF, 0xDB, 0xA7, 0xBD, 0xF2, 0x43, 0x5C, 0xDA, 0xEB, 0xC3, 0x11, 0xCA, 0x2B, 0xE2, 0x78, 0x3E, 0xD9, 0xF7, 0x9F, 0xE9, 0xC9, 0xEC, 0xE9, 0x43, 0xCD, 0x2D, 0x36, 0xEF, 0xC8, 0x59, 0x57, 0x92, 0x3E, 0x47, 0x67, 0x22, 0x29, 0x20, 0x09, 0xA8, 0x00, 0xD2, 0x40, 0xF5, 0x6F, 0xF5, 0x67, 0xC7, 0x63, 0x66, 0x2C, 0xE9, 0xE9, 0x47, 0xBD, 0xEB, 0xBE, 0xB9, 0xAF, 0x05, 0xF8, 0x9C, 0xF2, 0xF6, 0x02, 0x6C, 0xE0, 0x7B, 0xE0, 0x83, 0x02, 0x22, 0x01, 0x5E, 0xA8, 0x25, 0x69, 0xB4, 0x3D, 0xC3, 0xC0, 0xBE, 0x2E, 0x79, 0x51, 0x93, 0xC3, 0xD7, 0x39, 0xEB, 0x26, 0xBC, 0xB7, 0x29, 0x9B, 0xA9, 0x58, 0xF8, 0x3D, 0x97, 0xB3, 0xDD, 0xCA, 0xA5, 0x42, 0xE7, 0xF9, 0x8B, 0x38, 0xED, 0x3C, 0x77, 0x44, 0xD7, 0x5F, 0x4E, 0xF7, 0x3A, 0xAB, 0xC4, 0xE2, 0xDA, 0x6A, 0xB4, 0xC1, 0xED, 0x28, 0x6B, 0x01, 0xD8, 0x43, 0xCB, 0xE6, 0xEF, 0xB9, 0xA7, 0xC2, 0x4A, 0x17, 0x90, 0x83, 0xD3, 0x28, 0x8D, 0xA1, 0x01, 0x2A, 0xCD, 0xB1, 0xC1, 0xC3, 0xF8, 0x5D, 0x29, 0xCA, 0x9F, 0x9B, 0x5F, 0x97, 0xE9, 0xAC, 0x40, 0x09, 0xAF, 0xA6, 0x40, 0x15, 0xD0, 0x06, 0x94, 0x03, 0xA9, 0x40, 0x0C, 0x4E, 0xBB, 0x80, 0x63, 0x34, 0xC1, 0xF4, 0x6C, 0xC5, 0x1E, 0xA0, 0x8A, 0xEE, 0x14, 0xA3, 0x3B, 0xB4, 0xAC, 0xA6, 0x02, 0x43, 0x26, 0x8B, 0xDF, 0xA6, 0x42, 0xD7, 0x2F, 0xEF, 0x6D, 0xC8, 0xD3, 0xF5, 0x4D, 0xFB, 0x48, 0x91, 0xD2, 0x35, 0x06, 0x30, 0xE6, 0x6E, 0xC2, 0xAA, 0xB1, 0x2B, 0xE6, 0x6E, 0x0A, 0xC8, 0x02, 0x2C, 0x80, 0x1C, 0xAC, 0x23, 0x0D, 0x4D, 0x95, 0x1E, 0x20, 0x14, 0xB0, 0xBA, 0x8F, 0x67, 0x8B, 0x35, 0x05, 0x3E, 0xEB, 0x17, 0xC7, 0xFB, 0xE6, 0x9D, 0x9F, 0x5A, 0x81, 0x8F, 0xCC, 0x0E, 0x9D, 0x68, 0x3B, 0x01, 0xD7, 0x81, 0x03, 0xA6, 0x80, 0x38, 0xB0, 0xE5, 0xFE, 0xD4, 0x8B, 0x56, 0xD3, 0x09, 0x66, 0x21, 0x86, 0xB7, 0x36, 0xDC, 0xDB, 0x5E, 0x93, 0x07, 0x49, 0x89, 0xCD, 0x44, 0x72, 0x4C, 0x69, 0xE3, 0xBF, 0xA5, 0xDF, 0x9D, 0xB8, 0xE4, 0x9A, 0xA0, 0x47, 0x80, 0x28, 0x61, 0x19, 0x9E, 0xA6, 0x99, 0x25, 0xBB, 0x9B, 0xBA, 0x79, 0xDC, 0xDE, 0xCE, 0xB1, 0x52, 0xDE, 0x80, 0x4A, 0x50, 0x73, 0x95, 0x75, 0xBF, 0x1C, 0x56, 0x57, 0x66, 0x86, 0x15, 0xE0, 0x5C, 0xCE, 0x18, 0xA4, 0xE1, 0x46, 0xC8, 0xAE, 0x17, 0xEC, 0x45, 0x73, 0x14, 0xEF, 0x74, 0x04, 0xDE, 0x94, 0x19, 0xCD, 0x40, 0x51, 0xC2, 0x62, 0x50, 0x1B, 0xE8, 0x17, 0x6B, 0x30, 0xB3, 0x76, 0x35, 0x70, 0x4A, 0xDB, 0xA1, 0x41, 0x8A, 0x04, 0xDC, 0xFC, 0xFC, 0xC4, 0x8A, 0x5B, 0x9C, 0xC2, 0x4E, 0x6E, 0x3A, 0x09, 0xED, 0xBC, 0x55, 0xC9, 0x14, 0xE4, 0xA3, 0x57, 0xDE, 0x09, 0xB6, 0xBF, 0x47, 0x5C, 0xB9, 0xFA, 0xF2, 0xFE, 0x02, 0xD5, 0xAC, 0x8B, 0x0B, 0x18, 0x21, 0x26, 0xDA, 0xE7, 0xF5, 0x74, 0xBA, 0x5C, 0x77, 0x9C, 0x39, 0xD6, 0x3C, 0xEC, 0x7B, 0x74, 0x6D, 0x79, 0x9A, 0xC2, 0x16, 0x1F, 0x5E, 0x5E, 0x5C, 0x3D, 0xB9, 0x18, 0xB1, 0x7E, 0xF7, 0x21, 0x3B, 0x83, 0x65, 0xAD, 0x3B, 0xB8, 0xB4, 0x17, 0xC0, 0x04, 0x5E, 0xF1, 0x81, 0xDE, 0x9B, 0x40, 0x26, 0xE0, 0x83, 0x34, 0x0A, 0x6E, 0xD1, 0x6A, 0x0E, 0x27, 0xD0, 0xF2, 0xBF, 0xFC, 0x4C, 0x99, 0x13, 0x82, 0x51, 0x6E, 0x10, 0x53, 0x24, 0x52, 0xD3, 0xA9, 0x2F, 0x3E, 0x4C, 0x97, 0xDE, 0xDA, 0xEF, 0x58, 0xBB, 0x0F, 0xAE, 0x5B, 0x4F, 0xDF, 0xC0, 0x65, 0x3C, 0x17, 0xDE, 0x85, 0x62, 0xCE, 0x46, 0x42, 0xCC, 0x91, 0x71, 0x9A, 0xF2, 0x1A, 0x48, 0xEA, 0xBF, 0x13, 0x72, 0x1C, 0xE3, 0x89, 0xDC, 0x27, 0xBF, 0xAA, 0x79, 0xD8, 0xC7, 0xCB, 0x32, 0x11, 0x83, 0x9C, 0xA9, 0x79, 0x05, 0xE1, 0x12, 0x96, 0xA1, 0x5A, 0x19, 0x85, 0xC2, 0x74, 0x1D, 0x37, 0x67, 0x0B, 0x75, 0xBF, 0x06, 0x06, 0x30, 0x83, 0x37, 0x0D, 0xB0, 0xBC, 0x43, 0x0C, 0x56, 0xB4, 0x5A, 0xC0, 0x94, 0x4B, 0x70, 0xAD, 0x77, 0x99, 0xF6, 0xFE, 0xF0, 0x14, 0x31, 0x53, 0xB9, 0x23, 0xC6, 0x04, 0x09, 0x1B, 0xC6, 0x49, 0xB5, 0xA2, 0xF1, 0xA8, 0x10, 0xC6, 0xFA, 0xD5, 0xD9, 0x10, 0x8F, 0xF3, 0x04, 0xE0, 0xC5, 0xB8, 0xA6, 0x50, 0xF1, 0x34, 0xE1, 0xAF, 0xDB, 0xAE, 0xC0, 0x29, 0x5C, 0x3D, 0x85, 0x7B, 0x35, 0x5B, 0x83, 0x3D, 0x09, 0x16, 0xD6, 0xC0, 0x76, 0xC0, 0xE5, 0xD4, 0xA0, 0x9D, 0x1A, 0x48, 0xF1, 0x23, 0x8F, 0xC6, 0x54, 0x73, 0xE7, 0x7E, 0x3A, 0x31, 0x3C, 0xDD, 0x40, 0xC7, 0x04, 0xEF, 0x64, 0x36, 0xD9, 0x18, 0x34, 0xB0, 0x98, 0x0F, 0xAC, 0x40, 0x24, 0x50, 0xF3, 0x4A, 0x1C, 0xA3, 0x25, 0xA6, 0x84, 0xD1, 0xD1, 0x41, 0x8F, 0x11, 0x7B, 0xF2, 0xC1, 0xBC, 0xBD, 0x1B, 0x5F, 0x7A, 0xE5, 0x74, 0x56, 0xBA, 0x65, 0xD5, 0xEC, 0x89, 0x14, 0x34, 0xC7, 0x7D, 0x30, 0xE5, 0x58, 0xC6, 0x47, 0x48, 0xBF, 0xE3, 0xE4, 0xBD, 0x33, 0x50, 0xB6, 0x2E, 0x25, 0xD5, 0x75, 0xEA, 0x06, 0xED, 0xB4, 0xBC, 0x1B, 0x13, 0x3E, 0xB5, 0x8F, 0xEE, 0x40, 0xE4, 0x0F, 0x76, 0x84, 0x71, 0x83, 0x61, 0xA8, 0x9E, 0x04, 0xDD, 0x9F, 0x36, 0x91, 0xAF, 0x81, 0x8E, 0xF7, 0x1A, 0xAB, 0x28, 0x7A, 0x59, 0x34, 0x90, 0xE3, 0x4E, 0xDA, 0x03, 0x19, 0xA8, 0x0C, 0xF6, 0xC0, 0x00, 0xCB, 0xC9, 0x2B, 0x55, 0x1A, 0x8D, 0x91, 0x02, 0xFC, 0xAF, 0xF3, 0x72, 0xE0, 0xF6, 0x67, 0x4A, 0xFC, 0xAD, 0xC2, 0x11, 0x57, 0x59, 0x09, 0x4F, 0x4A, 0xC0, 0x4A, 0xFE, 0x64, 0xC8, 0xC7, 0xFE, 0xD5, 0x5B, 0xF3, 0x50, 0xA9, 0x08, 0x38, 0x5D, 0x71, 0x15, 0x9D, 0x75, 0x21, 0x6D, 0x8C, 0x16, 0xBF, 0x26, 0x9F, 0xFB, 0xE4, 0x04, 0x34, 0xF3, 0xC5, 0x36, 0x7B, 0x01, 0x32, 0x68, 0x0C, 0xA8, 0x03, 0x21, 0x40, 0xAD, 0x79, 0x45, 0x66, 0xB3, 0x91, 0x5F, 0x37, 0xB4, 0x1A, 0x89, 0x31, 0x9F, 0x16, 0x4B, 0x13, 0x1F, 0xF1, 0x7D, 0x94, 0xA3, 0x7A, 0x4C, 0x18, 0x0D, 0x13, 0xEE, 0x81, 0x19, 0x10, 0x0E, 0x94, 0xC3, 0xA0, 0x5B, 0x00, 0x5B, 0x80, 0x37, 0x50, 0x49, 0xA3, 0x35, 0xCD, 0x34, 0xBD, 0xDF, 0x74, 0x12, 0x14, 0x47, 0x0D, 0x26, 0x0D, 0x7E, 0xF5, 0x71, 0xE4, 0x56, 0xD4, 0xF4, 0x3F, 0x73, 0xF8, 0xB9, 0xE9, 0x50, 0x03, 0xFA, 0xF4, 0x24, 0xA8, 0x31, 0xCF, 0x9C, 0x8B, 0xDA, 0xE7, 0x40, 0x94, 0xBF, 0x26, 0x5C, 0x79, 0x62, 0xDC, 0xDB, 0xC7, 0xAC, 0x6C, 0x4E, 0x16, 0xB7, 0xEC, 0x20, 0xCF, 0xA9, 0x1A, 0x3F, 0xC5, 0x47, 0x64, 0xBA, 0xE3, 0x53, 0x03, 0xD6, 0x47, 0x41, 0xF1, 0x74, 0xA7, 0x32, 0x19, 0xA7, 0xEB, 0x6C, 0x3C, 0x3E, 0xDE, 0xF9, 0xB0, 0x71, 0x2E, 0x8E, 0x48, 0x5B, 0x8C, 0x38, 0x58, 0x14, 0x8C, 0x1C, 0x88, 0x4C, 0x7D, 0xD0, 0x02, 0xBC, 0x81, 0x92, 0xF5, 0x9D, 0x5A, 0x57, 0x02, 0x66, 0x40, 0x0C, 0xDA, 0x60, 0x33, 0xE5, 0x89, 0xC9, 0x05, 0x09, 0xD3, 0x21, 0x18, 0x61, 0x73, 0x11, 0xD3, 0x3D, 0x6A, 0xB7, 0x13, 0xFB, 0xD8, 0xB1, 0x4F, 0xB5, 0x34, 0x33, 0x95, 0xCF, 0x2E, 0xBA, 0x8F, 0x07, 0xAD, 0x8B, 0x15, 0x12, 0x79, 0x0B, 0x06, 0x86, 0x3C, 0xD9, 0x09, 0x3E, 0x97, 0x3C, 0x9D, 0x37, 0xED, 0x56, 0xF9, 0xA6, 0xFF, 0x70, 0x1D, 0xED, 0x6E, 0x1E, 0x60, 0x80, 0xB5, 0xEE, 0x56, 0xA6, 0x0C, 0x43, 0xC7, 0x4C, 0xEE, 0x4C, 0xEE, 0x82, 0x13, 0x85, 0xF8, 0xD0, 0x30, 0xB6, 0xC9, 0x71, 0x27, 0x87, 0x8D, 0xF8, 0xDD, 0x84, 0x50, 0x96, 0x03, 0xB1, 0x00, 0x6A, 0xA1, 0x2D, 0xC2, 0x81, 0xBD, 0x06, 0x0E, 0xA8, 0x02, 0xD9, 0x34, 0xDA, 0x46, 0x97, 0x04, 0xDF, 0x48, 0x0C, 0xD7, 0x9A, 0x54, 0x1B, 0xC5, 0x62, 0xE2, 0x09, 0x0F, 0xFE, 0x2E, 0xAC, 0xEA, 0x86, 0x88, 0x68, 0x56, 0x7E, 0xB3, 0x73, 0x3F, 0x95, 0x52, 0x1E, 0xBF, 0x52, 0x7C, 0xD9, 0xA7, 0x78, 0xA7, 0x37, 0x10, 0x54, 0x59, 0xDC, 0xBF, 0x80, 0x13, 0xB2, 0xEA, 0x27, 0x95, 0x04, 0x66, 0xE2, 0x92, 0xD6, 0x02, 0x54, 0xF0, 0x48, 0x77, 0xCF, 0x47, 0x59, 0x80, 0xEA, 0xC0, 0x7F, 0xC5, 0xEC, 0xFB, 0x48, 0x68, 0xC6, 0x9C, 0xAD, 0x4A, 0xE7, 0xEB, 0xF6, 0x2F, 0x2E, 0x27, 0x03, 0x2C, 0x85, 0x9C, 0x8F, 0x58, 0xD9, 0x12, 0xD0, 0x02, 0xAC, 0x01, 0xD7, 0x81, 0x03, 0x21, 0x40, 0xEA, 0x2C, 0x7E, 0x41, 0xA3, 0x8D, 0xB3, 0x76, 0x37, 0x82, 0x7C, 0x5B, 0x27, 0xF8, 0xAD, 0x93, 0x01, 0x50, 0x93, 0xB8, 0x90, 0x23, 0xFC, 0x69, 0x27, 0x27, 0x07, 0x35, 0xFE, 0xFF, 0x58, 0xD2, 0x34, 0x18, 0xD3, 0x5E, 0xB3, 0x85, 0x07, 0xE0, 0xBF, 0x48, 0x95, 0xE4, 0x89, 0x70, 0x6F, 0x76, 0xF6, 0x63, 0xF6, 0xC5, 0x9C, 0x15, 0x62, 0x70, 0x36, 0x87, 0x45, 0x13, 0x02, 0x32, 0xE0, 0xF9, 0x99, 0x5B, 0xB0, 0xC2, 0x68, 0xB0, 0x08, 0xC5, 0x61, 0xD5, 0x4F, 0x51, 0x9D, 0xEC, 0x19, 0x5B, 0x3D, 0xA3, 0x69, 0x46, 0x4C, 0x4D, 0xBD, 0x86, 0x33, 0xEA, 0x92, 0x40, 0x34, 0x90, 0x35, 0x08, 0x20, 0xEA, 0x06, 0xDB, 0xA9, 0xB9, 0xD3, 0x68, 0x3A, 0x7A, 0xB7, 0x0C, 0x16, 0x30, 0x46, 0x11, 0x93, 0xE0, 0xB3, 0xA7, 0xB5, 0x66, 0xE2, 0x0A, 0x65, 0x89, 0x96, 0x44, 0xDD, 0x77, 0x1E, 0x0C, 0x88, 0x04, 0xE5, 0x2B, 0x6D, 0x79, 0xF3, 0xC4, 0xDE, 0xFB, 0xCA, 0x57, 0xDE, 0xFE, 0x53, 0x11, 0x89, 0xA3, 0x45, 0xE2, 0x71, 0xF7, 0xA4, 0xC8, 0xC1, 0xE9, 0x12, 0x45, 0x1F, 0x24, 0xEB, 0x0B, 0x02, 0x9F, 0xB6, 0x00, 0xB2, 0x81, 0xFA, 0xE0, 0x6C, 0x7B, 0x24, 0x73, 0xF6, 0xEB, 0x23, 0x86, 0xAB, 0xDC, 0xAD, 0xA9, 0x5F, 0x59, 0xF7, 0x79, 0x4B, 0x0C, 0xE8, 0x89, 0x8D, 0x49, 0x0D, 0x1A, 0xD8, 0xCE, 0x2B, 0x05, 0x90, 0x0D, 0x54, 0xCC, 0xF9, 0xC5, 0x68, 0xB5, 0x49, 0x40, 0x28, 0x19, 0xAB, 0x51, 0x4A, 0x15, 0xE3, 0xCF, 0x32, 0x70, 0x85, 0xF2, 0x82, 0x36, 0xD9, 0xCE, 0xEF, 0xBB, 0x6B, 0x25, 0x9D, 0x6A, 0x8F, 0xD5, 0x3E, 0x20, 0x02, 0xF9, 0x6B, 0x51, 0xEF, 0xE3, 0xFE, 0xB3, 0x73, 0xE0, 0x6A, 0xD6, 0x9F, 0x07, 0xA5, 0xCE, 0x98, 0x45, 0x7F, 0x09, 0xED, 0xF8, 0x1A, 0xE3, 0x8D, 0xD5, 0x9C, 0xCE, 0x47, 0x05, 0xD6, 0xE3, 0xB9, 0x95, 0x00, 0x98, 0x76, 0xBF, 0x4E, 0x82, 0x9B, 0x70, 0xC1, 0xA4, 0xDF, 0x9A, 0xB3, 0x76, 0xC2, 0xF6, 0x09, 0x14, 0x4F, 0x6F, 0x31, 0x15, 0xA6, 0x06, 0xD4, 0xBE, 0x11, 0x01, 0xD8, 0x02, 0x64, 0xA0, 0xC6, 0xAA, 0x33, 0x5A, 0x0D, 0xC1, 0x02, 0x11, 0x86, 0x58, 0x58, 0x3E, 0x1A, 0x38, 0x45, 0xE5, 0x78, 0xD3, 0x98, 0xDF, 0xD9, 0x8E, 0xDC, 0x5A, 0xCF, 0x3B, 0x6D, 0x19, 0x64, 0xDA, 0xB2, 0x8D, 0xD5, 0xB0, 0xF9, 0xC3, 0x40, 0x76, 0xCA, 0x81, 0x71, 0xEE, 0xBF, 0x1C, 0x61, 0xBC, 0x6F, 0xFB, 0xF1, 0xC0, 0x76, 0x01, 0x96, 0x00, 0x0D, 0xD4, 0x0C, 0x4C, 0x35, 0x90, 0x02, 0xDC, 0x95, 0x2D, 0x42, 0x71, 0x26, 0xFC, 0xC0, 0xD5, 0x19, 0xD7, 0x8A, 0x1B, 0x04, 0xDB, 0x7A, 0x4E, 0x4E, 0xD1, 0x06, 0x38, 0x0E, 0x7D, 0x0C, 0x2B, 0x83, 0xB0, 0x81, 0x3F, 0x8D, 0x4A, 0x37, 0xB0, 0x1D, 0x90, 0xA2, 0x1B, 0x8E, 0x56, 0x0B, 0x48, 0xB4, 0xAF, 0xFE, 0x6B, 0xF4, 0xA7, 0xC1, 0x79, 0x26, 0x47, 0x45, 0x72, 0x35, 0x86, 0x8A, 0x61, 0x70, 0x38, 0xBC, 0xDF, 0xAD, 0xD1, 0x94, 0x00, 0x78, 0xD2, 0x96, 0xFD, 0x27, 0x77, 0xD8, 0x8C, 0x8C, 0x52, 0x0E, 0x10, 0x26, 0x46, 0xA3, 0x95, 0xBB, 0xD3, 0xCF, 0x5E, 0xF7, 0xAD, 0x32, 0x12, 0x70, 0x03, 0x34, 0xEE, 0x50, 0xDF, 0x7A, 0xF4, 0xB1, 0x8A, 0xC8, 0x9F, 0xAE, 0x56, 0x0C, 0x8E, 0x83, 0xA9, 0x8F, 0x5B, 0x23, 0x18, 0x62, 0x9E, 0x89, 0x5A, 0xD7, 0x7E, 0xB1, 0xCE, 0xA5, 0x49, 0x36, 0x90, 0x3A, 0x10, 0xC0, 0xF3, 0xFE, 0x6F, 0x4B, 0x80, 0xCD, 0xD9, 0xAB, 0xB4, 0xDA, 0x39, 0xD1, 0x7E, 0x56, 0xAB, 0xE9, 0x5D, 0xB6, 0x35, 0xB1, 0xC6, 0xCE, 0xA7, 0xD2, 0xF1, 0xDC, 0xDA, 0x44, 0xE0, 0x57, 0x5D, 0xAA, 0x13, 0x11, 0x4F, 0xD7, 0xF1, 0x30, 0x26, 0x5D, 0x51, 0xA4, 0x23, 0x7E, 0x2D, 0xC5, 0x11, 0xAC, 0x3B, 0x69, 0x9F, 0xF0, 0xBA, 0x5F, 0x0E, 0xD9, 0x75, 0x24, 0x1C, 0xEF, 0x44, 0x65, 0xA6, 0x77, 0xEF, 0xC7, 0x4E, 0x5B, 0x80, 0xBB, 0xD1, 0x1C, 0x35, 0x78, 0x76, 0xCE, 0x60, 0x61, 0xB6, 0x4D, 0xCD, 0x8A, 0x3F, 0xFE, 0x4A, 0x63, 0x9E, 0x0C, 0xAB, 0x05, 0x17, 0x00, 0xAD, 0x51, 0x80, 0x9F, 0x7A, 0xDD, 0xE9, 0x0B, 0x26, 0x40, 0x0E, 0x2A, 0x26, 0x7D, 0xC1, 0x68, 0xB5, 0xA2, 0xDE, 0x08, 0xAA, 0xCD, 0xD6, 0xC6, 0x3E, 0xBE, 0x37, 0x86, 0xF8, 0xD4, 0x64, 0x77, 0x14, 0x73, 0xD4, 0x26, 0x2B, 0xB1, 0x28, 0x11, 0x79, 0x67, 0xAA, 0xF5, 0xE3, 0xF6, 0x66, 0xD7, 0x84, 0x93, 0xDF, 0xE7, 0xBF, 0x66, 0x33, 0x36, 0x40, 0x44, 0xF6, 0xE7, 0x64, 0xD3, 0xAB, 0x31, 0x17, 0x7B, 0x5D, 0xC7, 0x59, 0xE9, 0x53, 0x01, 0x13, 0xC0, 0x0B, 0xA0, 0xF2, 0x17, 0x8B, 0x24, 0xD2, 0x78, 0x90, 0xE3, 0xEE, 0x7C, 0x6D, 0xE0, 0xFC, 0x14, 0x63, 0xC9, 0x3C, 0x8D, 0x07, 0xAC, 0xC6, 0x83, 0x6B, 0x80, 0x35, 0x10, 0x6B, 0xA0, 0x80, 0xC7, 0xA0, 0x80, 0x54, 0x0A, 0x39, 0xD3, 0x68, 0x0D, 0x69, 0xBF, 0xDA, 0x9F, 0xD1, 0x6C, 0xFF, 0xEA, 0x19, 0x03, 0x35, 0xA0, 0xC8, 0x85, 0x6B, 0xF8, 0x73, 0x73, 0x7F, 0xB0, 0x8C, 0xE3, 0x10, 0x3A, 0x92, 0x3A, 0xFB, 0x28, 0x0B, 0x2A, 0x45, 0x86, 0x00, 0x9F, 0x25, 0xC4, 0x4E, 0xA4, 0x3B, 0xF7, 0x58, 0x92, 0x5E, 0xB5, 0x4B, 0x3D, 0x82, 0x0D, 0xD8, 0x27, 0x93, 0x00, 0x53, 0xE9, 0x0A, 0x8F, 0x1E, 0x39, 0xC5, 0xF9, 0x24, 0x1B, 0xD0, 0x38, 0xA9, 0xF4, 0x3F, 0x35, 0x85, 0x9E, 0x7B, 0x19, 0x80, 0x1B, 0xD5, 0x25, 0x43, 0xED, 0x30, 0x9A, 0xA1, 0x22, 0x1C, 0xE3, 0x2E, 0x81, 0x9A, 0xE1, 0x27, 0x0A, 0xD8, 0x06, 0x5C, 0x07, 0xF5, 0xC8, 0xE7, 0x26, 0x73, 0x3F, 0xC6, 0x68, 0x47, 0x6D, 0x7D, 0xFF, 0x95, 0x43, 0xC8, 0x1B, 0xED, 0x4B, 0x84, 0xCA, 0x43, 0x93, 0xDA, 0x48, 0x0D, 0x4B, 0xC5, 0x80, 0x13, 0xE5, 0x48, 0xBB, 0x03, 0x2C, 0xF4, 0x7C, 0xED, 0xB1, 0xB6, 0x50, 0x95, 0x83, 0xB7, 0x4A, 0xF9, 0x15, 0xC5, 0xCD, 0x2A, 0x4C, 0xB5, 0x1D, 0x7E, 0xDD, 0xA6, 0x7E, 0xE3, 0xC1, 0x66, 0x45, 0xC7, 0x58, 0xCB, 0x05, 0xD8, 0x6B, 0xE0, 0xF7, 0xA7, 0xF0, 0xE3, 0xF1, 0xA5, 0x86, 0xD3, 0x4F, 0x2E, 0x80, 0xD2, 0xDF, 0x53, 0x39, 0xA6, 0x32, 0xE3, 0x4E, 0x4F, 0x6E, 0x5B, 0x4E, 0xE9, 0xB2, 0x3B, 0xD0, 0x79, 0xA3, 0xE4, 0xA9, 0xD7, 0xDE, 0x80, 0x4F, 0xCA, 0xE0, 0x19, 0x69, 0x7B, 0xC3, 0x59, 0xEF, 0xFE, 0xD5, 0x98, 0x95, 0xFA, 0x64, 0xA0, 0x26, 0x46, 0xC3, 0x76, 0x2C, 0x71, 0xCB, 0xE1, 0xAD, 0xA9, 0x9C, 0xBA, 0xB5, 0xA0, 0x8B, 0x03, 0x56, 0xEB, 0x2B, 0x69, 0x19, 0x16, 0xA1, 0xF3, 0x1E, 0x76, 0x92, 0xE0, 0x86, 0x36, 0xB1, 0xAA, 0x2B, 0x31, 0x79, 0x4E, 0x1F, 0x7D, 0xD4, 0x57, 0x6B, 0x03, 0x6A, 0x00, 0x97, 0xB8, 0xB6, 0xBB, 0xD6, 0xC5, 0x37, 0x10, 0x0D, 0xD4, 0xBC, 0xE2, 0x7D, 0x95, 0x2F, 0xD4, 0xD1, 0x19, 0x58, 0xC2, 0xA4, 0xC8, 0x99, 0x52, 0x8C, 0x0B, 0x7C, 0xC0, 0x75, 0xFD, 0x56, 0x12, 0x17, 0x20, 0x1D, 0xA8, 0x06, 0x7A, 0x01, 0x95, 0x83, 0x9A, 0x1B, 0x56, 0x00, 0xE1, 0xB4, 0xDA, 0x4F, 0xD2, 0xFB, 0x0B, 0x8C, 0x17, 0xA2, 0xAA, 0x4B, 0x3F, 0x28, 0xEF, 0x44, 0x31, 0xF1, 0x28, 0xB7, 0x69, 0x29, 0xA5, 0xDC, 0x30, 0x6F, 0xD9, 0x89, 0xAB, 0x65, 0xDD, 0x66, 0xEB, 0x01, 0xF8, 0x53, 0x91, 0x43, 0xC2, 0xBE, 0x3B, 0x2C, 0x78, 0x63, 0x78, 0x32, 0x98, 0x4C, 0xC1, 0x66, 0x33, 0xC0, 0x8A, 0x5B, 0xCE, 0x2A, 0xEA, 0x96, 0x45, 0xD3, 0x05, 0x78, 0x00, 0x19, 0x3F, 0x7F, 0xA6, 0x1F, 0xAD, 0x97, 0xB5, 0x99, 0xD2, 0x0E, 0xC3, 0xE8, 0x1C, 0xE5, 0xBB, 0xE6, 0x32, 0xC5, 0x9A, 0x6B, 0x05, 0x5A, 0xEF, 0xEB, 0x53, 0xD6, 0x64, 0x1D, 0x6D, 0x60, 0x37, 0x60, 0x02, 0xE4, 0x02, 0x2A, 0xE0, 0x1F, 0xDA, 0x42, 0xA3, 0x29, 0x8D, 0x86, 0x02, 0x16, 0x89, 0xE9, 0x08, 0x95, 0x93, 0x47, 0x2D, 0xD8, 0x85, 0xF7, 0xC4, 0xF2, 0x7C, 0xA2, 0x53, 0xF5, 0x19, 0x2D, 0xDE, 0xB0, 0x94, 0xDB, 0x71, 0x5E, 0xFF, 0x52, 0x2A, 0xE8, 0x0A, 0x1A, 0xFB, 0xF0, 0x86, 0x25, 0xB0, 0xC1, 0xF4, 0x6D, 0xFA, 0x87, 0x22, 0x93, 0x5D, 0x2A, 0x70, 0xC8, 0x41, 0xBB, 0x64, 0x56, 0x17, 0x70, 0xEA, 0xA1, 0x16, 0xD0, 0xCD, 0x80, 0xEB, 0x18, 0xCD, 0x7F, 0xAA, 0xD5, 0x36, 0x0B, 0x3B, 0x85, 0xD7, 0x63, 0xC1, 0x92, 0x21, 0x93, 0x72, 0x85, 0x95, 0x0E, 0x7E, 0x90, 0x0D, 0xF0, 0x53, 0x04, 0x50, 0xBE, 0x50, 0x74, 0x27, 0x80, 0x36, 0x60, 0x09, 0xE4, 0xA2, 0xD1, 0xEC, 0x1E, 0x69, 0x7B, 0xDD, 0x4E, 0x35, 0x8C, 0xB4, 0x3B, 0xF2, 0x89, 0x0E, 0x61, 0x7E, 0x44, 0xBD, 0x21, 0x25, 0x3E, 0x46, 0x63, 0x20, 0xC9, 0xAE, 0x44, 0x4F, 0xE6, 0x25, 0xD7, 0x80, 0xD9, 0xF9, 0xC2, 0xD2, 0x9A, 0x23, 0x35, 0x64, 0xF2, 0xDB, 0x17, 0x46, 0x44, 0xEE, 0x44, 0x5B, 0x90, 0x64, 0x75, 0xB7, 0xA5, 0x2D, 0x20, 0x0C, 0xA8, 0x79, 0x05, 0xA9, 0xF3, 0x8C, 0x05, 0xDB, 0x29, 0xAC, 0x2F, 0xF6, 0xEE, 0xA6, 0x26, 0x7C, 0x51, 0x8C, 0x60, 0x4E, 0x12, 0x8E, 0xB3, 0x83, 0x0A, 0xD0, 0x74, 0x4F, 0x0E, 0xCC, 0x81, 0x08, 0xA0, 0x37, 0x46, 0xA1, 0x08, 0xA0, 0x09, 0x44, 0xD2, 0x68, 0x3E, 0xFD, 0xBE, 0xEC, 0x6A, 0xC6, 0xD8, 0x56, 0x1F, 0xAC, 0x6D, 0x54, 0x7D, 0x02, 0xDD, 0xEB, 0xAD, 0xB0, 0x4C, 0x57, 0xDE, 0x2D, 0x7A, 0x69, 0x35, 0xF1, 0x39, 0xDD, 0xBF, 0xCA, 0xC7, 0x7B, 0x8C, 0x70, 0x0A, 0xE3, 0xA6, 0x3A, 0xFB, 0x0A, 0x96, 0xE3, 0x04, 0x8E, 0x15, 0xEB, 0xC9, 0x16, 0x5A, 0x7E, 0x57, 0xBF, 0x2F, 0xBD, 0x33, 0xAE, 0xFA, 0x69, 0x00, 0xCD, 0x03, 0x49, 0x5F, 0xB9, 0xF6, 0x32, 0x17, 0x5F, 0xC9, 0x53, 0x46, 0x50, 0x8F, 0xEF, 0xDB, 0x17, 0x0C, 0x2B, 0x02, 0x94, 0x33, 0x09, 0x15, 0x50, 0x1B, 0xC4, 0x40, 0x07, 0x0E, 0x30, 0xFD, 0x70, 0x29, 0xAD, 0x16, 0x08, 0x64, 0x8A, 0xC7, 0x27, 0x86, 0xBE, 0x4F, 0xDB, 0x76, 0xFE, 0xBB, 0x05, 0xE7, 0xFE, 0x76, 0x1C, 0xAE, 0x0C, 0xC8, 0x36, 0x2A, 0x0F, 0xDD, 0x5A, 0x74, 0x71, 0x75, 0x2F, 0x8B, 0xF1, 0x3E, 0xAC, 0x93, 0x5D, 0x22, 0x32, 0x0F, 0x7B, 0x4C, 0x19, 0xEB, 0x84, 0xAA, 0x9A, 0xB5, 0xE9, 0x63, 0xA7, 0x38, 0xEB, 0x3C, 0x8D, 0xC7, 0xAE, 0xDF, 0x1E, 0x80, 0x0A, 0xC0, 0x87, 0x7C, 0xC5, 0xF2, 0x17, 0xCD, 0xDA, 0x71, 0x62, 0x97, 0x3D, 0x06, 0xE2, 0xE1, 0xA3, 0xE1, 0x18, 0xBD, 0xBA, 0x3B, 0xE0, 0x28, 0xA2, 0x40, 0x4F, 0xFF, 0x08, 0x19, 0x58, 0x03, 0x11, 0x00, 0x37, 0x86, 0x9D, 0x80, 0x3A, 0xE0, 0x46, 0xAB, 0x25, 0xCD, 0x74, 0xD5, 0x19, 0xC3, 0x30, 0x86, 0x5C, 0x6F, 0x0C, 0xB9, 0x98, 0xA0, 0x6C, 0x52, 0x33, 0x8F, 0x46, 0xBB, 0xF7, 0xCF, 0x3E, 0xA7, 0xFA, 0x99, 0x30, 0xF5, 0xAB, 0x76, 0xAB, 0x93, 0xC1, 0x64, 0xF1, 0x2B, 0x39, 0x99, 0x6D, 0xAD, 0xCE, 0x69, 0xA5, 0xD7, 0x6D, 0x2D, 0x5E, 0xDB, 0xCD, 0x99, 0xFD, 0x08, 0x2C, 0x05, 0xA4, 0x00, 0xAB, 0x5F, 0x9E, 0x57, 0x72, 0x84, 0xD7, 0xF1, 0x64, 0xE4, 0xA6, 0xFB, 0x11, 0x33, 0x33, 0xF5, 0xB7, 0xDC, 0xE7, 0x4C, 0x49, 0xF4, 0xB2, 0xF9, 0xD0, 0x93, 0x64, 0xAA, 0x05, 0x44, 0x02, 0xED, 0x48, 0x08, 0x92, 0x02, 0x62, 0x01, 0x19, 0x93, 0x72, 0x9A, 0x34, 0x5A, 0xDD, 0x46, 0x83, 0x29, 0x76, 0x97, 0x26, 0x9C, 0x83, 0x35, 0x85, 0x15, 0x5D, 0x93, 0x38, 0xE0, 0x1F, 0x54, 0xEF, 0xB3, 0xDA, 0x7E, 0x64, 0xD5, 0x92, 0xF5, 0x62, 0xE2, 0x4F, 0x1C, 0x2A, 0x7E, 0xAE, 0x7F, 0x3B, 0x7D, 0x64, 0x7D, 0xFC, 0x46, 0x3C, 0xCB, 0x32, 0x40, 0xA7, 0x63, 0xB5, 0xAB, 0x23, 0xBD, 0x9C, 0x3C, 0xDF, 0xAE, 0xF9, 0xF4, 0xB4, 0xD3, 0x17, 0xFB, 0x35, 0x75, 0xDE, 0x39, 0x29, 0x23, 0x3D, 0x07, 0x8C, 0xC5, 0x2E, 0x2F, 0xAC, 0x19, 0x38, 0x6A, 0x1E, 0x91, 0x13, 0x13, 0x61, 0x90, 0xA0, 0x80, 0xD2, 0x3B, 0x3A, 0xA0, 0x0E, 0x84, 0x01, 0x2D, 0xB3, 0xB9, 0x16, 0xA0, 0x4A, 0xAB, 0xF5, 0x31, 0x17, 0x8D, 0x97, 0xDF, 0x4D, 0x79, 0x5C, 0xDC, 0x1B, 0x69, 0x6A, 0x95, 0x32, 0x47, 0x52, 0x47, 0xF9, 0x77, 0x36, 0xC7, 0x18, 0x97, 0xB5, 0xA7, 0xDA, 0x58, 0xC6, 0x78, 0xCE, 0x1E, 0x70, 0xD4, 0x4E, 0x01, 0xEA, 0x28, 0xDE, 0x6F, 0x20, 0xEA, 0x5E, 0x00, 0x99, 0xEB, 0xCA, 0xD8, 0xE3, 0x9A, 0x80, 0x24, 0xAC, 0x96, 0x0C, 0x6B, 0x02, 0xCC, 0xD5, 0xEB, 0xA3, 0x03, 0x4C, 0x7F, 0x5E, 0xE6, 0x9D, 0xCB, 0xCB, 0xC1, 0x59, 0x01, 0xE4, 0x02, 0xC2, 0x07, 0x79, 0x2B, 0xA9, 0x5B, 0x02, 0xA5, 0x40, 0x0A, 0x60, 0xF5, 0x14, 0x91, 0xD3, 0x77, 0x20, 0x40, 0x9E, 0x1D, 0x54, 0xD6, 0x6D, 0xB5, 0xA9, 0x6C, 0xCF, 0xED, 0x53, 0x5C, 0xBA, 0xB1, 0x50, 0xCF, 0x50, 0x33, 0x75, 0x28, 0xF6, 0x76, 0x5F, 0x3D, 0x0B, 0x5C, 0x9F, 0x2E, 0xF7, 0x91, 0xEC, 0x0E, 0x7E, 0x2B, 0x51, 0xA7, 0x01, 0x7D, 0x72, 0x72, 0x6F, 0xF1, 0xF3, 0xBA, 0x85, 0x4C, 0xE1, 0xC7, 0x9C, 0x38, 0x0A, 0x8C, 0xE7, 0x74, 0xD9, 0xAC, 0x5F, 0x37, 0xC6, 0xF1, 0x59, 0xD3, 0x9D, 0x12, 0xA7, 0x91, 0x41, 0xAC, 0xBB, 0x97, 0x04, 0x7D, 0x6F, 0x69, 0x80, 0xF7, 0xC0, 0x07, 0x71, 0x6B, 0x56, 0xA8, 0x02, 0x91, 0xCF, 0xFA, 0x79, 0x1C, 0x54, 0x8F, 0x10, 0xCB, 0x9E, 0x37, 0xF5, 0x58, 0x6D, 0xFF, 0xF5, 0x88, 0x7A, 0x2B, 0x7E, 0x02, 0x36, 0xE4, 0xEA, 0xB4, 0x0B, 0xD2, 0xCF, 0x22, 0x08, 0xC3, 0x88, 0xB1, 0x5F, 0xFB, 0xE5, 0x58, 0x53, 0xA1, 0xD5, 0xE4, 0x6E, 0x54, 0xF1, 0x0A, 0x70, 0x87, 0x01, 0xEE, 0x83, 0x06, 0xD8, 0xC3, 0xFD, 0x64, 0x83, 0xD3, 0x13, 0x57, 0x9C, 0x69, 0x2C, 0x09, 0xA6, 0x5E, 0xC9, 0xCF, 0xFF, 0xD3, 0xA7, 0x19, 0xF4, 0xD9, 0x73, 0x07, 0x2B, 0xEE, 0x34, 0xCB, 0x28, 0xC0, 0x0C, 0x50, 0x1F, 0xD8, 0x20, 0x81, 0xA0, 0x54, 0x46, 0x00, 0xBE, 0x01, 0xDB, 0x8F, 0xBA, 0xC5, 0xBA, 0x4D, 0x99, 0x3E, 0xAF, 0xF8, 0xB1, 0x9A, 0xD0, 0x4E, 0xB8, 0xF2, 0x2E, 0xFD, 0xEB, 0x40, 0x21, 0x06, 0x2A, 0x45, 0x14, 0x4A, 0x10, 0x28, 0xCE, 0x4E, 0x31, 0x43, 0xE6, 0xE7, 0x96, 0x2B, 0x4F, 0xDE, 0x9A, 0x56, 0xF3, 0x5B, 0xDC, 0xC6, 0x03, 0xE8, 0x35, 0x88, 0xC1, 0x1E, 0x04, 0x5B, 0x8D, 0x00, 0xC9, 0xF5, 0xB0, 0xE9, 0xBF, 0xBC, 0xD2, 0x61, 0x93, 0xB1, 0x77, 0xD6, 0xA4, 0x53, 0x2B, 0xA6, 0x9A, 0x03, 0xF7, 0xF6, 0x22, 0x99, 0x02, 0x3B, 0x1E, 0x75, 0x8B, 0x05, 0xF8, 0xC0, 0x72, 0xD0, 0x40, 0xF2, 0x07, 0x1A, 0x30, 0x62, 0x01, 0xBB, 0xEE, 0x09, 0x1E, 0x0D, 0x8C, 0x0D, 0x2F, 0xAB, 0xE9, 0x37, 0xD6, 0xDA, 0xE5, 0x54, 0xAC, 0xF6, 0x17, 0xD6, 0x9B, 0x02, 0x29, 0x6D, 0x4C, 0xB7, 0x10, 0xC8, 0xDE, 0xF8, 0x86, 0xD1, 0x45, 0x2F, 0x45, 0x74, 0x5F, 0x4F, 0x2F, 0x16, 0xF1, 0xBB, 0xB5, 0x8A, 0x11, 0x71, 0x7F, 0xF2, 0x7D, 0x8F, 0x35, 0xBB, 0x1C, 0x6B, 0x5B, 0x4E, 0x0D, 0xB2, 0x4E, 0x3C, 0x98, 0x99, 0xA0, 0xCE, 0x44, 0x39, 0x2A, 0x44, 0xE5, 0xA5, 0x31, 0xBF, 0x39, 0x3C, 0x9E, 0x99, 0x26, 0x79, 0xCB, 0xFC, 0x57, 0x0E, 0x6C, 0x10, 0x74, 0x71, 0x02, 0xBE, 0x80, 0x6C, 0x20, 0x1E, 0x1B, 0xCA, 0x02, 0x96, 0xDF, 0xF6, 0xCD, 0x3E, 0x56, 0xB3, 0xBF, 0xFA, 0xE2, 0x9E, 0x02, 0x9D, 0xFC, 0x82, 0xEA, 0xC9, 0xDE, 0x39, 0x01, 0xF6, 0x71, 0xDB, 0xBA, 0xCE, 0xBA, 0x66, 0x10, 0xAC, 0x89, 0xBE, 0xB5, 0x27, 0xFA, 0xC9, 0xC2, 0x3D, 0xCB, 0x4D, 0xDD, 0x2A, 0xED, 0x3B, 0x00, 0x6D, 0xC0, 0x13, 0x28, 0x76, 0xD2, 0xD6, 0x31, 0x97, 0xB2, 0x5A, 0xF4, 0x4A, 0x60, 0x88, 0xD3, 0x96, 0xF6, 0xA4, 0x4F, 0xEE, 0xD3, 0x9A, 0xF7, 0x28, 0x25, 0xE4, 0x2D, 0x8E, 0x0D, 0xBF, 0xC1, 0xDD, 0x50, 0x23, 0x04, 0xF0, 0x05, 0x58, 0x0C, 0x0A, 0xC8, 0x79, 0x53, 0x04, 0x70, 0x07, 0x6C, 0x40, 0xA1, 0x9B, 0x6A, 0x20, 0xF4, 0xEE, 0x19, 0x63, 0x71, 0xAC, 0xE6, 0x7F, 0xF9, 0xE5, 0x5B, 0xFC, 0xAE, 0x55, 0x5F, 0xAA, 0xA2, 0x8E, 0x94, 0x73, 0xC3, 0x33, 0x31, 0xCD, 0xF4, 0x52, 0x37, 0x8C, 0x67, 0x72, 0xEF, 0xA1, 0x7E, 0x17, 0x69, 0x8F, 0xF1, 0x1A, 0xD3, 0x01, 0xEF, 0xB2, 0x09, 0xAC, 0xCD, 0x6D, 0x49, 0x00, 0x4F, 0xA0, 0x8B, 0x97, 0xEE, 0x31, 0xC9, 0x98, 0x2B, 0xEB, 0x17, 0xE1, 0xA0, 0xBB, 0x66, 0x0E, 0x2E, 0xC2, 0xFB, 0x6A, 0x1F, 0x39, 0x01, 0xB7, 0xFB, 0xBE, 0xBA, 0x46, 0xAE, 0xC7, 0xD8, 0x0E, 0x1F, 0xD8, 0x0E, 0x50, 0x67, 0xBF, 0x7D, 0xD0, 0x8C, 0x5A, 0x00, 0x95, 0xF4, 0xD4, 0x03, 0xDB, 0xE6, 0x61, 0x03, 0xAE, 0x80, 0x0C, 0x6C, 0xCD, 0x2B, 0x7D, 0xAC, 0x16, 0x9F, 0x7B, 0x48, 0x7F, 0x8E, 0xC8, 0xFC, 0x52, 0xBD, 0xC6, 0x5C, 0x52, 0x53, 0x60, 0x01, 0x0F, 0xDB, 0xDE, 0xC1, 0x66, 0x1B, 0xF7, 0x85, 0xCA, 0x9F, 0x4A, 0x96, 0x7C, 0xA4, 0x33, 0xEA, 0x68, 0xF0, 0xFB, 0xEC, 0x93, 0x0B, 0x70, 0x7A, 0xC0, 0xFB, 0x77, 0xD9, 0x8A, 0xA3, 0xC8, 0xC9, 0x46, 0xB3, 0x4D, 0x57, 0x6B, 0xC2, 0x86, 0x8C, 0xA7, 0xEF, 0x3D, 0xBE, 0x4E, 0x1D, 0xAB, 0xED, 0xAB, 0xCE, 0xC3, 0xC6, 0x08, 0x9C, 0xEE, 0x99, 0x4F, 0xD7, 0x8B, 0x05, 0x2C, 0x1F, 0x34, 0x60, 0x32, 0x16, 0x35, 0xC0, 0x1C, 0x50, 0x05, 0xA8, 0xC5, 0x13, 0x0A, 0xA8, 0x01, 0xBE, 0xE7, 0x95, 0x3C, 0x56, 0xCB, 0xAF, 0x3F, 0x46, 0x76, 0x1E, 0xAB, 0x65, 0xC3, 0x8D, 0x26, 0x02, 0xDD, 0x65, 0x68, 0x38, 0xCB, 0xE4, 0x45, 0x39, 0x66, 0x9D, 0xD6, 0xB7, 0xAE, 0xBD, 0x55, 0x53, 0x5C, 0x59, 0x06, 0x7E, 0xDA, 0x0B, 0xEC, 0x04, 0x22, 0x80, 0x9E, 0xDF, 0x54, 0x0C, 0x08, 0xCE, 0x50, 0x06, 0x48, 0x8A, 0xA5, 0xFC, 0x79, 0x77, 0x05, 0x2D, 0x6A, 0x4D, 0x2E, 0x66, 0x70, 0xFF, 0x3C, 0x25, 0x7A, 0xB2, 0xC2, 0x25, 0x39, 0x66, 0x3E, 0x6C, 0xBD, 0x75, 0x55, 0x36, 0x3D, 0x74, 0x31, 0xD0, 0x41, 0x8C, 0x45, 0x13, 0xA8, 0x7D, 0x2F, 0x21, 0x34, 0x57, 0xC9, 0xA3, 0xB7, 0xB6, 0x81, 0x93, 0x43, 0x67, 0xC7, 0x6A, 0x75, 0x77, 0xC4, 0x70, 0x45, 0x67, 0xAE, 0x15, 0x70, 0xBC, 0xB6, 0x7E, 0x53, 0xDA, 0x02, 0x45, 0x06, 0x9E, 0x01, 0xD1, 0xF3, 0xAA, 0x5B, 0xBF, 0xC9, 0x9E, 0x3D, 0x34, 0x4E, 0x29, 0xCA, 0x2D, 0x46, 0x22, 0x0E, 0xA8, 0x02, 0xBE, 0x81, 0x92, 0x5F, 0xE6, 0x63, 0x33, 0x3D, 0xD0, 0x59, 0x8E, 0x7E, 0x74, 0xAA, 0x25, 0x7E, 0xC9, 0x0C, 0x7E, 0xE2, 0xA8, 0xD6, 0xB4, 0x0C, 0xBD, 0xBA, 0xD7, 0xC9, 0xC3, 0xEB, 0x6E, 0xFA, 0x95, 0x0D, 0x44, 0x0C, 0x74, 0xF0, 0xE8, 0xE0, 0x99, 0x3E, 0xBB, 0x41, 0x01, 0xF6, 0xC4, 0xC4, 0xCA, 0xE6, 0xD3, 0x20, 0xED, 0x58, 0xAD, 0x3F, 0x07, 0x91, 0xF5, 0xE6, 0x58, 0x83, 0x47, 0xC9, 0x15, 0x07, 0x25, 0xD9, 0x93, 0x16, 0xB6, 0x47, 0xC1, 0x58, 0x46, 0x64, 0x4E, 0xEF, 0xE0, 0x94, 0x3E, 0xE9, 0xCB, 0x5B, 0xC6, 0x08, 0x3C, 0x62, 0xAD, 0xA2, 0xDF, 0x07, 0x08, 0xC6, 0xA8, 0x1C, 0x70, 0x36, 0x1D, 0x60, 0x62, 0xC7, 0x2F, 0x7F, 0x53, 0x8F, 0x97, 0xEC, 0x34, 0x8D, 0x0E, 0xF9, 0xE5, 0x15, 0xE9, 0xE9, 0x07, 0x55, 0xC6, 0x65, 0x91, 0x4A, 0x74, 0xCC, 0x6A, 0x9B, 0x81, 0x1B, 0x80, 0x2D, 0x40, 0x0C, 0xD8, 0x7D, 0x7F, 0x62, 0x05, 0x99, 0x04, 0x10, 0x05, 0xF8, 0x40, 0x39, 0xFC, 0x1B, 0xF0, 0x04, 0xD2, 0xE6, 0x15, 0x86, 0x0C, 0x94, 0xE7, 0x5A, 0x56, 0xE1, 0x26, 0x3F, 0xE1, 0xA4, 0xDE, 0x1B, 0x07, 0x87, 0xC0, 0xE0, 0x08, 0x31, 0x78, 0x1E, 0xAC, 0xFE, 0x16, 0xEC, 0xB2, 0xAE, 0x31, 0xD7, 0xC6, 0x5E, 0x2C, 0x7E, 0x77, 0x5F, 0x09, 0x1F, 0x08, 0x60, 0x35, 0x58, 0x03, 0x07, 0xAE, 0x86, 0x66, 0xF0, 0x82, 0xF3, 0x9B, 0x16, 0x60, 0x3A, 0xBE, 0x5B, 0xE1, 0xAA, 0x45, 0xAF, 0xCA, 0xD5, 0x1B, 0x48, 0xFC, 0x56, 0xCD, 0x5A, 0xCA, 0x4F, 0x40, 0xFA, 0x33, 0xD8, 0x9E, 0x4F, 0xE7, 0x4A, 0xD5, 0xCF, 0x95, 0x6A, 0x03, 0x96, 0xC0, 0xF2, 0x3B, 0xF2, 0xDA, 0x7D, 0xBE, 0x11, 0xCD, 0xB6, 0xAF, 0x70, 0xBB, 0x5A, 0xCC, 0x95, 0xAA, 0xB1, 0x78, 0xA8, 0xE1, 0xB0, 0xDC, 0x7B, 0x44, 0xF2, 0xBE, 0x4F, 0xED, 0x69, 0x9F, 0xB9, 0xF6, 0x7B, 0xA5, 0x3A, 0xD3, 0x42, 0xEF, 0x2B, 0x95, 0x18, 0xA0, 0x3D, 0x90, 0x81, 0x01, 0xB6, 0x80, 0xE6, 0x16, 0x47, 0x73, 0x31, 0x53, 0x88, 0xB1, 0x19, 0xA5, 0x9F, 0x96, 0x0E, 0x48, 0x76, 0xD3, 0xA2, 0x30, 0xD1, 0x2D, 0xC6, 0xA6, 0xCF, 0x39, 0x71, 0xAD, 0xC7, 0x6A, 0x36, 0xD0, 0xDB, 0x78, 0x2D, 0xEF, 0x9F, 0xEE, 0x39, 0xB0, 0x29, 0xB0, 0xF2, 0x5F, 0x53, 0x74, 0x1F, 0xAB, 0xC9, 0x5F, 0x7D, 0x99, 0xCE, 0x81, 0xEC, 0xBC, 0x0E, 0x1C, 0xDF, 0x42, 0x4F, 0x03, 0x1A, 0x88, 0x77, 0x3A, 0x2E, 0xCC, 0xBB, 0xB1, 0x58, 0xA9, 0x5E, 0xC5, 0x66, 0xE6, 0x4F, 0x93, 0xA9, 0x5A, 0x77, 0x03, 0x1E, 0x19, 0xD8, 0x06, 0x34, 0x06, 0x57, 0x4F, 0x95, 0x38, 0x2D, 0x6F, 0x36, 0xAD, 0x16, 0x7D, 0x5F, 0xA9, 0x98, 0x5C, 0x9A, 0xFE, 0x6C, 0x00, 0x6C, 0xDB, 0xC5, 0x50, 0x1F, 0x10, 0x06, 0xF4, 0x1E, 0xF4, 0xF3, 0x69, 0x3D, 0x9F, 0xF2, 0xEE, 0x2E, 0xD8, 0x67, 0x4B, 0x05, 0x74, 0x03, 0xEB, 0x14, 0x02, 0x03, 0xA2, 0x80, 0xD9, 0xA9, 0xA0, 0xA4, 0xD5, 0xF4, 0xB3, 0x5A, 0x54, 0x4C, 0x5B, 0xF8, 0xFE, 0x6B, 0x83, 0x1B, 0x12, 0x6E, 0x86, 0xFA, 0xBE, 0x5F, 0x77, 0x8D, 0x70, 0x7A, 0xE0, 0x46, 0x04, 0x87, 0x9C, 0xD2, 0x6A, 0x5A, 0x6F, 0xBB, 0xA4, 0x73, 0xD1, 0xE3, 0x32, 0x4D, 0xE4, 0x60, 0xDD, 0x0F, 0x77, 0xFC, 0xDC, 0x42, 0x31, 0x38, 0xD9, 0x0D, 0x74, 0xD0, 0xC5, 0x94, 0x5F, 0xE1, 0x9D, 0xD3, 0x1B, 0xA3, 0xCF, 0xF9, 0x62, 0xAD, 0x7B, 0x73, 0x59, 0x01, 0x6C, 0xBD, 0xEB, 0x74, 0x5B, 0x80, 0xCA, 0x1B, 0xB4, 0x9E, 0x2C, 0x20, 0x8D, 0x79, 0x35, 0xB7, 0xB9, 0xD3, 0x01, 0x7D, 0x1A, 0xD5, 0x49, 0x02, 0x1D, 0xC7, 0x6C, 0xF6, 0x85, 0x8E, 0xBB, 0x0C, 0x85, 0xE9, 0xBA, 0xBE, 0x4A, 0x83, 0xC5, 0x4E, 0x22, 0xA9, 0x10, 0x36, 0xF5, 0x09, 0x8D, 0x6F, 0x43, 0x40, 0xB7, 0xF3, 0x6A, 0xFC, 0xE3, 0xF9, 0x54, 0x6C, 0xEF, 0xFD, 0x74, 0x31, 0x1A, 0x28, 0x21, 0xC0, 0xEE, 0xC1, 0x02, 0x78, 0x7E, 0x5C, 0x5C, 0x83, 0x8F, 0x53, 0x36, 0x00, 0xF6, 0xD4, 0x70, 0x1D, 0xAB, 0x29, 0x0F, 0x2B, 0x1C, 0x18, 0x57, 0xDF, 0xAE, 0xD4, 0xA7, 0xFB, 0x98, 0x3C, 0x88, 0x41, 0x01, 0x16, 0x40, 0x9E, 0x5A, 0x72, 0x20, 0x1D, 0x08, 0xBB, 0x7F, 0xDD, 0xB5, 0xE7, 0x4D, 0x01, 0xF8, 0x8D, 0xA2, 0x8E, 0xD5, 0x1C, 0x27, 0xB6, 0x49, 0xFB, 0x6B, 0x33, 0x74, 0xCF, 0xEB, 0xC0, 0xA9, 0x33, 0x7D, 0x8E, 0x58, 0x36, 0xC9, 0x0A, 0x8D, 0x5B, 0x4C, 0xFA, 0xBD, 0xB0, 0xDD, 0x7D, 0xE0, 0xE8, 0x96, 0x8A, 0x53, 0xBE, 0xE3, 0x3C, 0x4D, 0x3E, 0xE7, 0x22, 0xDD, 0x80, 0x8F, 0xB9, 0xF6, 0x5D, 0x5D, 0x1D, 0x13, 0x6B, 0xC2, 0x1E, 0x87, 0x02, 0xAE, 0x0F, 0xFB, 0x4C, 0xD8, 0x75, 0x45, 0x64, 0x16, 0xB3, 0x75, 0xF2, 0x3D, 0x64, 0xD9, 0x2D, 0x81, 0x97, 0x83, 0x20, 0x62, 0xD0, 0xF7, 0xC1, 0xCD, 0xEA, 0xFE, 0xF1, 0x1C, 0xB8, 0x02, 0x5B, 0x1F, 0x2D, 0x50, 0x01, 0x7E, 0x0B, 0x1B, 0xC4, 0xD5, 0x18, 0xD1, 0xD3, 0xAC, 0xBF, 0x10, 0xD4, 0xEA, 0x49, 0x9C, 0xB2, 0xD0, 0x4E, 0x04, 0xA7, 0xF6, 0x69, 0xD6, 0x94, 0xFF, 0x68, 0xF7, 0x20, 0x57, 0xA1, 0x7A, 0x31, 0x7D, 0x6A, 0x9F, 0x12, 0x73, 0x11, 0xC0, 0x02, 0x08, 0x07, 0xA8, 0xC6, 0xC6, 0x20, 0x55, 0x4C, 0xDE, 0x14, 0x80, 0x9C, 0x84, 0xAB, 0xC3, 0xFD, 0xA9, 0x54, 0xA4, 0x8A, 0x9C, 0xFD, 0xDA, 0xFA, 0xD8, 0x49, 0x7A, 0xE8, 0x02, 0x6A, 0x01, 0x9E, 0x80, 0xD6, 0xC0, 0x07, 0x01, 0xD8, 0x80, 0xB9, 0x28, 0xEA, 0x40, 0x2E, 0x20, 0x0C, 0xB0, 0x0D, 0xAC, 0x9A, 0x37, 0x0D, 0xE8, 0x9E, 0x37, 0x8D, 0x56, 0x4B, 0x74, 0x6A, 0xF4, 0x9A, 0xBE, 0x4E, 0x0E, 0xF5, 0x05, 0x9D, 0x6E, 0xA2, 0x8D, 0x01, 0xA8, 0x11, 0x28, 0xC9, 0xE5, 0xF1, 0x6B, 0xEF, 0xCB, 0x05, 0x5E, 0x57, 0xBA, 0x02, 0xFE, 0xD9, 0xB1, 0x2C, 0xAB, 0x03, 0x12, 0x16, 0xD9, 0x1B, 0x30, 0x19, 0x14, 0xC0, 0x2F, 0x7F, 0x54, 0x7B, 0xA9, 0x97, 0x34, 0xA9, 0x51, 0xD0, 0x3A, 0x67, 0xDA, 0x41, 0x1F, 0xBD, 0xAE, 0x45, 0xBB, 0xAE, 0x31, 0x5A, 0xCD, 0xC0, 0xDB, 0xB7, 0x7D, 0xCC, 0x00, 0x6D, 0x40, 0x62, 0x60, 0x37, 0x54, 0x80, 0xA4, 0x7D, 0x06, 0x45, 0x8B, 0x24, 0x60, 0x3E, 0x66, 0x0A, 0x20, 0x14, 0xC8, 0x9A, 0x57, 0x84, 0x46, 0x83, 0xFA, 0x61, 0x65, 0x4F, 0x9E, 0x6B, 0x7C, 0xD3, 0x55, 0x0C, 0xF1, 0x77, 0x15, 0x83, 0x5F, 0x62, 0x72, 0x9A, 0xBD, 0xF3, 0x2F, 0x8F, 0x74, 0x64, 0xD2, 0x55, 0x54, 0xFE, 0x34, 0x05, 0x15, 0x3A, 0x21, 0xF6, 0xDD, 0xAC, 0xAC, 0xFC, 0x2E, 0x7C, 0xDD, 0x02, 0x68, 0x9D, 0x2B, 0xF3, 0x4F, 0x05, 0xB4, 0x58, 0xBD, 0x73, 0x72, 0xEC, 0xCA, 0x7E, 0x85, 0x75, 0x6C, 0x30, 0x19, 0xC7, 0xDD, 0x66, 0xCE, 0x0E, 0xB2, 0x3C, 0x56, 0x7F, 0x58, 0xC2, 0xC6, 0xAA, 0x80, 0x05, 0xA0, 0x39, 0xF0, 0x41, 0x9F, 0x57, 0x66, 0xA9, 0x06, 0xA2, 0x00, 0x0F, 0xE0, 0x5C, 0xED, 0x0B, 0x88, 0x0D, 0x24, 0x5F, 0xC9, 0x33, 0x41, 0x7B, 0x94, 0x36, 0x7D, 0x0A, 0xE9, 0x36, 0x06, 0x5E, 0x08, 0x72, 0x34, 0x64, 0x44, 0x31, 0xDA, 0xC7, 0x47, 0xB3, 0xBF, 0x4F, 0x96, 0xCD, 0x9A, 0xC6, 0x47, 0x88, 0xE2, 0xBA, 0x9C, 0x60, 0x9D, 0xC0, 0x58, 0xED, 0x53, 0x19, 0x0C, 0x94, 0x03, 0x6D, 0x6C, 0x32, 0x0B, 0x24, 0x1D, 0x40, 0x42, 0xD9, 0xE8, 0x9F, 0x52, 0xD7, 0xA4, 0xAE, 0x33, 0xCD, 0x71, 0xF7, 0x71, 0x52, 0x6A, 0x32, 0x7C, 0xCC, 0x2F, 0xCA, 0x08, 0xC5, 0x65, 0xA0, 0x95, 0x4F, 0x29, 0x9B, 0x3C, 0x88, 0x79, 0xA5, 0x01, 0x9A, 0x8B, 0x9F, 0xBA, 0x6F, 0xA3, 0xEB, 0x06, 0x96, 0x01, 0xFB, 0x44, 0xFC, 0x69, 0x35, 0x43, 0x80, 0x65, 0x4F, 0x01, 0xD5, 0x56, 0xFB, 0x9C, 0x1E, 0x19, 0x88, 0x83, 0xBA, 0x2A, 0x2E, 0x89, 0xE5, 0xA3, 0x99, 0x97, 0xB8, 0xFD, 0xC7, 0x66, 0xCA, 0xDA, 0x7D, 0xCA, 0x7D, 0x45, 0xAB, 0xAD, 0x99, 0xE2, 0x02, 0xD8, 0xC0, 0xF7, 0xC0, 0x81, 0xA0, 0xC6, 0x77, 0x30, 0x70, 0x10, 0x30, 0x49, 0xE5, 0xAF, 0xDE, 0x7C, 0x9F, 0x00, 0x61, 0xFA, 0xE9, 0x04, 0x34, 0x0A, 0x96, 0x63, 0xF4, 0x39, 0x86, 0xC8, 0x3D, 0x2E, 0x3A, 0x07, 0x0E, 0x94, 0x3D, 0x48, 0xA0, 0x85, 0xFA, 0xD0, 0x8F, 0x6A, 0xEE, 0xAE, 0xC1, 0xC6, 0xC3, 0x31, 0xA5, 0x35, 0x20, 0x0A, 0x68, 0xF2, 0xCD, 0x63, 0xB5, 0x3D, 0x72, 0x00, 0x32, 0xEA, 0x85, 0xF6, 0x17, 0x8E, 0x4C, 0x48, 0x2C, 0x8E, 0x3D, 0xB5, 0x9B, 0x3A, 0xDD, 0xBF, 0xF6, 0xB4, 0x3E, 0x46, 0x10, 0x59, 0xDF, 0xBD, 0x60, 0x3D, 0x09, 0xB9, 0xE7, 0x0A, 0xB8, 0xEE, 0x7B, 0xA8, 0x6F, 0x20, 0x9B, 0xDE, 0x45, 0x80, 0x45, 0x16, 0x4C, 0x72, 0x63, 0x6B, 0x8B, 0xD6, 0x49, 0x2B, 0xFE, 0x75, 0xAC, 0x91, 0x64, 0x55, 0xEC, 0x29, 0x9D, 0xEF, 0xA7, 0xFE, 0x2F, 0x12, 0xB0, 0x06, 0xC4, 0x81, 0x25, 0x03, 0x46, 0xC1, 0x1A, 0x9F, 0xF6, 0x02, 0x7C, 0x51, 0x42, 0x1D, 0x88, 0x0D, 0xF8, 0x80, 0xAA, 0x94, 0x35, 0xF0, 0x0D, 0xA4, 0xCC, 0x9B, 0xC7, 0x68, 0x82, 0xFC, 0x7B, 0xD1, 0xAB, 0x82, 0x6A, 0xFB, 0x9E, 0xA8, 0x90, 0x02, 0x56, 0xD8, 0xD6, 0xA6, 0x8C, 0x5B, 0x3B, 0x78, 0x81, 0xBA, 0x2A, 0x5A, 0x94, 0x4E, 0x8E, 0x1A, 0x6B, 0xB1, 0xCC, 0x49, 0xE8, 0xDB, 0x91, 0x5B, 0xD9, 0x40, 0x0A, 0xF0, 0xA2, 0xDE, 0xE6, 0x4F, 0x61, 0xAE, 0xE6, 0xD6, 0xEE, 0xA7, 0xC6, 0x55, 0x98, 0x23, 0xF0, 0x81, 0x99, 0x23, 0xF3, 0xE3, 0x62, 0x30, 0x13, 0xE5, 0xC3, 0x58, 0x79, 0x85, 0xA4, 0x4E, 0x40, 0xC6, 0x8D, 0x5E, 0x3D, 0xD8, 0x40, 0xF2, 0x53, 0xDF, 0x6A, 0x09, 0x25, 0xAC, 0xED, 0x18, 0x9C, 0x74, 0x07, 0x20, 0x16, 0xA0, 0x05, 0x38, 0x6B, 0xC2, 0x9B, 0x46, 0x53, 0xA4, 0xDB, 0xB4, 0x8C, 0xD1, 0x18, 0x5B, 0xF5, 0xD9, 0xE1, 0x91, 0x16, 0xC9, 0x22, 0xBD, 0x6D, 0x81, 0x3D, 0x04, 0x59, 0x1E, 0xFD, 0x6F, 0x29, 0xFE, 0xE0, 0x79, 0xC3, 0x1F, 0x25, 0xC8, 0x1C, 0xE3, 0xA9, 0x01, 0xB1, 0xEF, 0x96, 0x7F, 0xAC, 0x18, 0xA3, 0x9A, 0x15, 0xCC, 0x35, 0x5B, 0xAE, 0xC6, 0x69, 0x9F, 0x92, 0x13, 0x08, 0x5A, 0x54, 0xF7, 0x1B, 0x23, 0x04, 0x95, 0x39, 0xF6, 0x2D, 0x23, 0xD0, 0x02, 0x9C, 0xFC, 0xB9, 0x02, 0xD2, 0x07, 0x6B, 0xF0, 0x28, 0x56, 0x46, 0xDF, 0x6D, 0xEA, 0x3A, 0x80, 0x54, 0x40, 0x9F, 0x37, 0xC5, 0xE6, 0xCD, 0xA0, 0xD5, 0xA6, 0xD5, 0xF1, 0x6A, 0x34, 0xE5, 0xD2, 0x75, 0xA5, 0xC8, 0x24, 0x6F, 0x27, 0x5E, 0x38, 0x28, 0x97, 0xE0, 0x7E, 0xEC, 0x77, 0x38, 0x34, 0xEC, 0x91, 0x47, 0xD7, 0x7A, 0x32, 0x32, 0x9E, 0x50, 0xAD, 0xFA, 0x60, 0x0D, 0x0C, 0x60, 0x5E, 0xC7, 0x66, 0x5E, 0x38, 0x8D, 0x5E, 0x35, 0x23, 0xD6, 0xB8, 0x87, 0x5C, 0xC5, 0x1D, 0x27, 0xF3, 0x77, 0xDD, 0x81, 0xBD, 0x10, 0xA0, 0xEB, 0xC9, 0xA4, 0xD4, 0x41, 0x0C, 0x1A, 0x10, 0x03, 0x9C, 0x5D, 0x46, 0x07, 0x2A, 0x80, 0xE8, 0xDD, 0xF7, 0x3B, 0xF7, 0xA3, 0x0E, 0xCD, 0x57, 0xF2, 0x4C, 0x50, 0xFF, 0x2B, 0x41, 0xDD, 0xAC, 0x2B, 0x7A, 0xB7, 0xF7, 0xC6, 0x81, 0x17, 0xC5, 0xB4, 0xEC, 0x36, 0x31, 0x7D, 0x5B, 0x02, 0x97, 0xC7, 0x15, 0x76, 0x2E, 0x04, 0x1F, 0xE5, 0x75, 0x4A, 0x32, 0x25, 0x7B, 0x10, 0x32, 0x08, 0xC0, 0x05, 0x30, 0x1B, 0x28, 0x90, 0x7A, 0xF2, 0x6C, 0xB9, 0xB4, 0xDF, 0x72, 0xE5, 0xFD, 0xD3, 0x6F, 0xED, 0x73, 0x88, 0x3F, 0x2D, 0x30, 0x1E, 0x03, 0x89, 0x02, 0x6D, 0x74, 0x25, 0xBD, 0x5D, 0x7A, 0x07, 0x05, 0x64, 0xDC, 0x97, 0xB9, 0x5C, 0xDC, 0x4F, 0x07, 0x7C, 0x68, 0x80, 0x2A, 0xB0, 0x0C, 0x10, 0xBE, 0xB9, 0x8F, 0xD5, 0xE2, 0xBB, 0xBB, 0xEB, 0xDA, 0x93, 0x1E, 0x12, 0x1C, 0x6B, 0xB8, 0xCE, 0x58, 0xA1, 0xBA, 0x27, 0x04, 0x0E, 0x30, 0x6F, 0xF8, 0xA5, 0xCA, 0x99, 0x29, 0x7F, 0x5B, 0x6D, 0xEB, 0x7D, 0x75, 0xD7, 0x05, 0xF8, 0xC0, 0x36, 0x20, 0x06, 0x6C, 0x05, 0x56, 0x02, 0x52, 0xAC, 0xFD, 0x39, 0xE9, 0xDE, 0xCC, 0xFD, 0x00, 0xFC, 0x2E, 0x77, 0x77, 0xBA, 0x99, 0x36, 0xFF, 0x2E, 0xF7, 0x30, 0xF6, 0x9C, 0x87, 0x0A, 0x98, 0x03, 0xBE, 0x07, 0x39, 0x68, 0x20, 0xF2, 0xE9, 0x81, 0x3E, 0x48, 0x07, 0x22, 0x00, 0x73, 0x60, 0xCB, 0x7D, 0xD7, 0x5F, 0x09, 0xE4, 0xB1, 0x9A, 0xE1, 0x62, 0xB0, 0x3B, 0xA1, 0xB1, 0x18, 0xE8, 0x13, 0xBD, 0xBD, 0x60, 0xB5, 0x50, 0x84, 0x6C, 0x12, 0xA9, 0x44, 0xC7, 0x63, 0x66, 0xC7, 0x85, 0x4B, 0xDE, 0xDE, 0xB5, 0xE2, 0xA6, 0xB0, 0xEF, 0x62, 0xF4, 0xC5, 0xBA, 0xFE, 0x41, 0xE9, 0x53, 0xDE, 0xBF, 0x18, 0x59, 0xB8, 0xB2, 0xB8, 0xF1, 0xAB, 0x1E, 0x55, 0xA1, 0x73, 0xBF, 0xC0, 0x6E, 0x80, 0x5F, 0x43, 0x59, 0xE6, 0x7C, 0x45, 0x9C, 0xB6, 0xDD, 0xFD, 0x4A, 0xA2, 0x81, 0x3E, 0x6D, 0x4B, 0x02, 0x10, 0x03, 0x74, 0x10, 0x3D, 0xC3, 0x38, 0x81, 0x10, 0xC0, 0x15, 0xD0, 0xA7, 0xCF, 0x49, 0x24, 0x90, 0x3D, 0xAF, 0x04, 0xAD, 0x56, 0x48, 0x53, 0xB2, 0x18, 0x09, 0x1D, 0x45, 0xB5, 0x42, 0x29, 0x82, 0x08, 0xB1, 0xE7, 0x3E, 0x5D, 0xD8, 0x3E, 0xA6, 0x0B, 0x6D, 0xC8, 0x66, 0xD0, 0x18, 0x77, 0xD1, 0x4B, 0x47, 0x98, 0x7F, 0xC2, 0x13, 0x7E, 0xC2, 0xB2, 0x81, 0xA3, 0xF2, 0xC0, 0x75, 0x50, 0x4F, 0x6F, 0x4E, 0x0A, 0xC6, 0x60, 0x21, 0x05, 0x74, 0x7E, 0x43, 0x3D, 0xCA, 0x9D, 0x14, 0xC6, 0x39, 0xE9, 0x33, 0xA7, 0x12, 0xF2, 0x44, 0xB6, 0x00, 0x21, 0x72, 0x20, 0xC0, 0xB6, 0x81, 0x0F, 0xEA, 0x7E, 0x25, 0x64, 0x7E, 0xB3, 0x81, 0x17, 0x60, 0x0D, 0xF0, 0x95, 0x16, 0x20, 0x02, 0xC8, 0x66, 0x11, 0x2A, 0x8D, 0xD6, 0xA7, 0x3F, 0x90, 0x6E, 0xD4, 0xCE, 0xC6, 0x97, 0xCD, 0x0A, 0xA3, 0x55, 0xD8, 0xF8, 0xD4, 0x13, 0x26, 0x48, 0x24, 0x7B, 0x6C, 0x2F, 0xE6, 0x5F, 0xDD, 0x17, 0x83, 0x6D, 0x8C, 0x76, 0xD0, 0xF1, 0x70, 0xDF, 0x56, 0x52, 0x06, 0xD7, 0x40, 0x20, 0x70, 0xAC, 0xBC, 0xCD, 0x6C, 0x2C, 0x70, 0x5C, 0x30, 0x90, 0x29, 0x2C, 0x9A, 0x0A, 0x3B, 0x39, 0x2D, 0xC3, 0xF1, 0x17, 0x94, 0xBA, 0xBA, 0x3B, 0xFF, 0x02, 0xB8, 0x29, 0x5E, 0x07, 0x33, 0x0D, 0xC0, 0x0A, 0x88, 0x31, 0xE5, 0x52, 0xE0, 0x48, 0x14, 0xC4, 0xD8, 0xA9, 0x80, 0x0C, 0x40, 0x07, 0x7B, 0x01, 0x12, 0x78, 0xF3, 0x14, 0x02, 0x31, 0xA9, 0x6B, 0xD5, 0xF4, 0x23, 0x13, 0x34, 0xF8, 0xAA, 0x8D, 0xC3, 0xB7, 0x27, 0x6F, 0x86, 0x38, 0xDA, 0xCC, 0x5D, 0x34, 0x76, 0xFF, 0x6E, 0xEE, 0xBD, 0x1E, 0xC9, 0x6A, 0x2A, 0xC5, 0xDD, 0x22, 0xF2, 0xC8, 0x5A, 0x03, 0xCA, 0x80, 0x3B, 0x19, 0x37, 0x4F, 0x19, 0xB2, 0x4D, 0x1C, 0x25, 0x6C, 0xA4, 0x4A, 0x07, 0x31, 0x97, 0x2A, 0x4D, 0x76, 0x29, 0x1C, 0x13, 0xEE, 0x5F, 0x1A, 0x61, 0x1C, 0x4B, 0x06, 0xCB, 0xDE, 0x67, 0x18, 0xB2, 0x4D, 0x9C, 0x6C, 0xC0, 0x0D, 0x88, 0x06, 0x8A, 0x43, 0x9B, 0x6A, 0x56, 0x01, 0x58, 0x0F, 0x0C, 0xD8, 0xF3, 0x4A, 0x1A, 0x60, 0x0A, 0x50, 0xB7, 0xD6, 0x8D, 0x46, 0xC3, 0xAD, 0x33, 0x4A, 0x51, 0xB3, 0x2B, 0xF6, 0xDD, 0xAD, 0xB2, 0x7B, 0x26, 0x56, 0xA2, 0xEC, 0x6E, 0x0B, 0x66, 0xB9, 0x24, 0xAA, 0x39, 0x3B, 0x4E, 0x10, 0x94, 0xBC, 0x6E, 0x53, 0x62, 0x4F, 0xD3, 0x87, 0x00, 0x7A, 0x03, 0xC9, 0x87, 0x0B, 0x30, 0x01, 0x98, 0xDF, 0xB6, 0x4E, 0x5F, 0x8A, 0x33, 0x1E, 0x80, 0xD6, 0x9F, 0x4F, 0x43, 0x8E, 0x3C, 0x4F, 0xFC, 0xF4, 0xC8, 0xF2, 0x5C, 0xA3, 0x76, 0x1E, 0xD5, 0x8F, 0x7B, 0x01, 0x8B, 0x00, 0x5A, 0xA8, 0xA9, 0x05, 0xEC, 0x04, 0xDC, 0x6F, 0xF7, 0x55, 0x0C, 0x5C, 0x01, 0x29, 0xBC, 0x52, 0x0E, 0xB8, 0x02, 0xB9, 0xF8, 0x0A, 0xAD, 0x26, 0x7F, 0xD1, 0x68, 0x93, 0xAA, 0x8A, 0xBE, 0xD0, 0xF9, 0xFD, 0x82, 0x86, 0x45, 0x06, 0x56, 0xF3, 0x1A, 0xA1, 0xEF, 0xBD, 0x14, 0xB2, 0x85, 0xA9, 0x94, 0xF1, 0xBB, 0x9D, 0x44, 0xCE, 0xBD, 0x92, 0x1B, 0xFF, 0x1D, 0xA0, 0x5D, 0x3D, 0xA0, 0x09, 0x73, 0x70, 0x35, 0x6C, 0x3F, 0x8D, 0xDE, 0xF5, 0x64, 0x61, 0x35, 0x23, 0xB3, 0x0C, 0xBB, 0x5C, 0xC2, 0xF4, 0x6C, 0x9D, 0x32, 0x4A, 0x24, 0x7D, 0x6E, 0x6F, 0x6B, 0x03, 0x96, 0x40, 0xFA, 0xA0, 0x81, 0x8A, 0x41, 0x03, 0x9D, 0xB4, 0x6B, 0x03, 0x15, 0x77, 0x46, 0xC0, 0xE2, 0xC3, 0x04, 0x9C, 0x6F, 0x2A, 0xA0, 0x3D, 0x36, 0x3F, 0x46, 0x53, 0x14, 0x21, 0x78, 0x20, 0x0B, 0xAB, 0x14, 0x89, 0xAB, 0x91, 0xA3, 0x3A, 0x1F, 0xD3, 0x91, 0x30, 0x46, 0x72, 0xD2, 0x70, 0xAD, 0x75, 0x1C, 0x3B, 0xAE, 0x42, 0xBD, 0x6B, 0xA8, 0x71, 0x43, 0x3B, 0x59, 0xE0, 0xB6, 0x81, 0xCE, 0x1B, 0xB5, 0x81, 0x70, 0xA0, 0x14, 0xE6, 0x92, 0x31, 0x10, 0x05, 0x29, 0x82, 0x75, 0xF0, 0x63, 0x3C, 0x8F, 0x27, 0x7E, 0x60, 0x30, 0x5E, 0xF1, 0xC7, 0xD7, 0x60, 0x46, 0xA3, 0xD3, 0xF9, 0xE7, 0x80, 0x19, 0x10, 0x83, 0x1C, 0x54, 0x70, 0xF8, 0x02, 0x19, 0xF7, 0xFA, 0xC7, 0xFB, 0x41, 0x39, 0xE0, 0x0A, 0x48, 0x03, 0x96, 0xF3, 0x66, 0xD0, 0x6A, 0xF6, 0x45, 0x90, 0x77, 0x24, 0x52, 0xCA, 0xAB, 0xFE, 0xF2, 0x2B, 0x36, 0xD7, 0xE9, 0xB2, 0xBB, 0xE7, 0x36, 0xDF, 0xE3, 0xA7, 0x73, 0x78, 0xC6, 0x9C, 0x3E, 0xEF, 0xF7, 0xD8, 0x11, 0x8C, 0x2D, 0x32, 0x19, 0x80, 0x5E, 0x17, 0xBA, 0x0A, 0x06, 0x35, 0x58, 0x80, 0x24, 0x10, 0xFC, 0xDA, 0xC9, 0x15, 0xB7, 0xD9, 0x34, 0xFA, 0x96, 0x63, 0x5B, 0xF5, 0xBB, 0xCA, 0x1A, 0x9B, 0x8F, 0x9F, 0xB3, 0x41, 0x29, 0x70, 0xD4, 0x8F, 0xD8, 0x37, 0x43, 0x01, 0x19, 0xE8, 0xC0, 0x68, 0xD8, 0x05, 0xF4, 0x1E, 0x8B, 0x2E, 0xA0, 0x7B, 0xB0, 0x80, 0x63, 0x7B, 0x7B, 0x24, 0xFF, 0xCF, 0x64, 0xA0, 0xD5, 0x7C, 0x7A, 0xFF, 0x15, 0xEC, 0x54, 0x1B, 0xDA, 0x1E, 0x0B, 0x63, 0x4D, 0xCD, 0xA7, 0xA6, 0x53, 0xA7, 0xA3, 0xB3, 0x4C, 0x7D, 0x6D, 0x5D, 0x39, 0xF3, 0xF6, 0x34, 0xBD, 0xA7, 0x29, 0xCA, 0x4F, 0xD4, 0xE4, 0x6E, 0x18, 0xE3, 0x36, 0x90, 0xC1, 0x06, 0x9A, 0xE1, 0x28, 0x0E, 0x2E, 0xFF, 0xA9, 0x2E, 0xCD, 0xBD, 0x44, 0x66, 0x3C, 0xB0, 0xC3, 0xC6, 0x6E, 0xFA, 0x47, 0xCE, 0x46, 0xA8, 0x1B, 0x58, 0x03, 0x5B, 0x40, 0x14, 0x50, 0x0B, 0x68, 0x1D, 0xB0, 0x39, 0x9C, 0x00, 0x66, 0x40, 0xFB, 0x38, 0x13, 0x6C, 0xB0, 0x80, 0xA5, 0xDC, 0x58, 0x00, 0x4F, 0x80, 0x3A, 0x85, 0xB6, 0x69, 0xB4, 0x80, 0xBB, 0xC3, 0x61, 0xB4, 0x2E, 0x41, 0x25, 0x47, 0xEF, 0x99, 0x2E, 0x85, 0xDD, 0xAD, 0x15, 0x02, 0x1E, 0x59, 0x18, 0xE8, 0xBB, 0xAF, 0x9B, 0x7B, 0xAD, 0x27, 0x09, 0xAB, 0x38, 0x33, 0x43, 0x39, 0x9C, 0xE7, 0x3B, 0x35, 0xA0, 0x67, 0x38, 0xDD, 0xA0, 0x1B, 0x62, 0x15, 0x0C, 0xA4, 0x4E, 0xE5, 0xF8, 0xFB, 0xB0, 0x46, 0xF9, 0x42, 0x36, 0xF8, 0xAD, 0x29, 0x96, 0x7C, 0xDB, 0xDF, 0xED, 0xB8, 0x95, 0x83, 0x77, 0x01, 0xB6, 0x00, 0x6F, 0x20, 0xEA, 0xF6, 0x70, 0x88, 0x01, 0xE5, 0xF4, 0xB6, 0x00, 0xDB, 0x29, 0x93, 0x01, 0x78, 0x03, 0xEA, 0x80, 0x07, 0x5E, 0xD1, 0xA4, 0xD5, 0x12, 0x42, 0x3E, 0xC1, 0x14, 0x8F, 0x11, 0xF2, 0xB7, 0x66, 0x70, 0x6A, 0xFA, 0x11, 0x3B, 0xB2, 0x7A, 0x9C, 0xDA, 0x10, 0xC5, 0xA4, 0xAB, 0xAB, 0x7E, 0x8A, 0x75, 0xAE, 0x79, 0xF2, 0x5B, 0x82, 0xEE, 0x96, 0x5B, 0x08, 0xBE, 0x75, 0x30, 0xA7, 0x88, 0xB5, 0x01, 0xF6, 0x53, 0x67, 0x2D, 0x35, 0x45, 0xAA, 0x93, 0x8D, 0x07, 0x14, 0x9F, 0xFE, 0x11, 0x3E, 0x88, 0x23, 0x4A, 0xEF, 0xC5, 0x26, 0xB5, 0x00, 0x25, 0x95, 0xC3, 0x01, 0x4D, 0x40, 0x7A, 0x10, 0x80, 0x3A, 0x10, 0x49, 0x25, 0x17, 0xC0, 0x6C, 0xB0, 0x00, 0x11, 0x76, 0x61, 0x06, 0x6A, 0x03, 0x3D, 0xAF, 0xC4, 0x99, 0x9F, 0x05, 0xA9, 0x90, 0x0A, 0x8C, 0x69, 0xB7, 0x51, 0x05, 0x0C, 0xFC, 0x91, 0x46, 0x86, 0x28, 0xF5, 0xF4, 0x89, 0x9E, 0xF3, 0x7C, 0x5F, 0x0D, 0xA2, 0x6F, 0xF9, 0x2B, 0x67, 0xAA, 0x1A, 0x1B, 0x50, 0xC0, 0x06, 0xD4, 0xD7, 0x00, 0x1A, 0x30, 0x05, 0xB6, 0x03, 0x4A, 0x83, 0x16, 0x47, 0xD3, 0x9C, 0xB3, 0x3F, 0xC8, 0x69, 0x5C, 0xE0, 0x36, 0x2E, 0xB5, 0xAB, 0x79, 0xB4, 0x1E, 0x29, 0xFE, 0xAD, 0x83, 0x05, 0x74, 0xDE, 0x02, 0x7E, 0x67, 0xF4, 0x0A, 0x60, 0x0A, 0x78, 0x3E, 0x32, 0x01, 0x1B, 0x28, 0x1F, 0x2C, 0x20, 0x06, 0xD2, 0xC0, 0xDE, 0x80, 0x28, 0xD0, 0x46, 0xA3, 0x35, 0xEA, 0x89, 0x76, 0x4F, 0xFD, 0xAF, 0xA2, 0x16, 0x46, 0x7D, 0x22, 0x4C, 0x81, 0xB4, 0xFF, 0xA9, 0x35, 0xB2, 0xB4, 0x39, 0xFF, 0x4D, 0xFB, 0x1F, 0x66, 0xCA, 0x03, 0x74, 0xB9, 0x38, 0x3E, 0xB1, 0x1B, 0x8A, 0x9E, 0xFA, 0x39, 0x4D, 0x20, 0x1C, 0xF0, 0x00, 0xCC, 0x80, 0xA6, 0x1B, 0x72, 0x84, 0x1E, 0x92, 0xAD, 0xCB, 0x73, 0x5A, 0x0D, 0xD8, 0x7C, 0xF2, 0xD1, 0x81, 0xFC, 0xC0, 0xDB, 0x96, 0x1C, 0xF5, 0x23, 0x5F, 0x80, 0x6C, 0xA0, 0x17, 0x4D, 0x0E, 0x44, 0x00, 0xD5, 0x40, 0xE7, 0xAD, 0x5F, 0xEF, 0x93, 0x47, 0x28, 0x0E, 0x84, 0x00, 0x1E, 0x80, 0xCE, 0x2B, 0xDD, 0x40, 0x0A, 0xD0, 0xA7, 0x00, 0x77, 0x6C, 0x16, 0xD3, 0x23, 0x77, 0x3D, 0xB3, 0x73, 0xE5, 0x38, 0xBC, 0x37, 0x34, 0xD8, 0x54, 0xF0, 0xE3, 0x56, 0x98, 0xF1, 0x2D, 0x67, 0x3A, 0xC2, 0xAD, 0xFF, 0x18, 0xCD, 0x69, 0xB4, 0x99, 0x7A, 0x35, 0xD6, 0xAA, 0x7A, 0xC4, 0xF1, 0x0A, 0xE8, 0x60, 0x9C, 0xF3, 0xB7, 0x88, 0x05, 0xCC, 0x6B, 0xCA, 0xF2, 0xD6, 0x53, 0xEF, 0xC4, 0x1E, 0xD9, 0x2D, 0xBF, 0x5E, 0xCE, 0x58, 0x4B, 0x8F, 0xB1, 0x25, 0xCF, 0x94, 0xCD, 0x7D, 0xF7, 0xDD, 0x2E, 0x03, 0x32, 0x07, 0x0E, 0x54, 0xE2, 0x15, 0x09, 0x80, 0xC5, 0x69, 0x52, 0x83, 0x0D, 0x70, 0x1B, 0x8A, 0x02, 0x2C, 0x80, 0xD3, 0x8D, 0xA9, 0x68, 0xB4, 0x3D, 0xA3, 0xAF, 0x8F, 0xD1, 0x04, 0x19, 0x09, 0xE3, 0xE2, 0x66, 0xCB, 0x7B, 0x43, 0x15, 0x6F, 0x6C, 0x78, 0x59, 0x23, 0xD8, 0x4E, 0x04, 0xA7, 0x5C, 0x20, 0xE2, 0xAA, 0x08, 0xE5, 0xB4, 0xC2, 0x12, 0x0A, 0x9F, 0xBF, 0xDD, 0xAD, 0xA0, 0xD5, 0x00, 0x51, 0x20, 0xC6, 0x58, 0xB5, 0x61, 0x9E, 0x65, 0x53, 0x84, 0xCE, 0xD6, 0x01, 0x8A, 0x4F, 0xF2, 0x61, 0x26, 0x8B, 0x71, 0xC0, 0x20, 0x40, 0x84, 0x45, 0xEF, 0x43, 0x9C, 0x5A, 0xBA, 0x6A, 0xC0, 0x12, 0x90, 0x0D, 0xEC, 0xBC, 0xA1, 0xEB, 0x16, 0xA5, 0x93, 0x02, 0x62, 0x03, 0x1E, 0x80, 0xC9, 0xAB, 0x54, 0x07, 0xE0, 0xD7, 0x85, 0x3D, 0xC7, 0x66, 0xF2, 0x97, 0x1B, 0x35, 0xDA, 0x61, 0x08, 0xB0, 0x54, 0x20, 0xE8, 0xBE, 0x91, 0x23, 0x84, 0x4C, 0x83, 0x32, 0x44, 0xC3, 0xC2, 0xE0, 0x49, 0x2C, 0xBF, 0x95, 0xBE, 0xEB, 0x71, 0xAA, 0x55, 0xCD, 0x1E, 0x2A, 0xB7, 0xF3, 0xD3, 0x12, 0xA0, 0x67, 0xBC, 0x1B, 0xA8, 0x35, 0x60, 0x2A, 0x4A, 0x9E, 0xB8, 0xE8, 0xDD, 0xCD, 0xD4, 0xF2, 0xF2, 0x04, 0x45, 0xB2, 0x46, 0xFB, 0xFE, 0x5F, 0x2F, 0x01, 0x78, 0x47, 0x73, 0xE3, 0xD9, 0xFA, 0x4A, 0x58, 0x85, 0xED, 0x3F, 0xC8, 0x02, 0xD4, 0x81, 0x9C, 0x93, 0xB6, 0x05, 0xD0, 0x0B, 0xC8, 0x06, 0x7C, 0x03, 0x2B, 0xE6, 0x4D, 0x05, 0x5A, 0xE7, 0x95, 0x33, 0xD2, 0xF4, 0x73, 0xA3, 0xC5, 0xF6, 0x2F, 0x7E, 0x1C, 0xF1, 0xCB, 0x31, 0x45, 0xC9, 0x0C, 0x5C, 0xCB, 0xB1, 0xFF, 0x70, 0x52, 0xDE, 0xB0, 0x8B, 0x04, 0xB3, 0x49, 0xEF, 0xEE, 0x79, 0x4C, 0xF0, 0x3A, 0x55, 0x05, 0x6F, 0x75, 0x4D, 0x01, 0xAA, 0xC0, 0x36, 0x60, 0x6D, 0xE0, 0xAE, 0x44, 0xA1, 0xA7, 0x2F, 0x4F, 0xF9, 0x5A, 0x51, 0x36, 0xFC, 0x44, 0xF2, 0xE7, 0xCD, 0x81, 0xEC, 0x3B, 0xF5, 0xCC, 0xF9, 0x27, 0xD8, 0x77, 0x6E, 0xD0, 0x76, 0x40, 0x13, 0xB0, 0x00, 0x3C, 0x81, 0xD6, 0xBB, 0xCD, 0x71, 0x0F, 0xAA, 0x00, 0xEF, 0xBB, 0xF1, 0x61, 0xF1, 0xD3, 0x3A, 0xAF, 0xD0, 0x6A, 0xF6, 0x55, 0x15, 0x2C, 0xF7, 0x3F, 0x47, 0x8B, 0x46, 0xD8, 0xD0, 0x36, 0xB6, 0xA8, 0xCA, 0xF9, 0xF7, 0x7A, 0x5A, 0x27, 0x2B, 0x72, 0xF5, 0xE1, 0x8A, 0xB4, 0xD7, 0x3F, 0x74, 0x32, 0x57, 0x73, 0xC6, 0x5A, 0xD4, 0x93, 0x9D, 0x16, 0x80, 0x38, 0xB0, 0xE6, 0x95, 0x5E, 0xF3, 0x89, 0x5E, 0x7B, 0x3B, 0xC1, 0xDA, 0x19, 0x64, 0x3D, 0x40, 0xE0, 0xFA, 0xFC, 0xC2, 0xF3, 0x2D, 0x8E, 0xB3, 0x75, 0x01, 0x4B, 0x01, 0xED, 0x3B, 0xAF, 0x6C, 0x17, 0xE0, 0x1B, 0xC8, 0x35, 0xE8, 0xFB, 0x96, 0x2F, 0x0A, 0x14, 0x93, 0x72, 0x9E, 0xF8, 0x71, 0x19, 0x60, 0x0D, 0x88, 0x00, 0x9A, 0xF3, 0xA6, 0x1C, 0xAB, 0xF9, 0x5F, 0xD9, 0x14, 0x40, 0xE2, 0x8E, 0x77, 0x8D, 0xB5, 0xB4, 0xC0, 0x6F, 0x96, 0x89, 0xF3, 0x44, 0x16, 0x84, 0x5A, 0xFA, 0x37, 0x33, 0xF1, 0xC5, 0x4E, 0xC3, 0xA9, 0xBB, 0x56, 0xD3, 0x12, 0x48, 0x01, 0xC2, 0x01, 0x1B, 0xA8, 0x00, 0x12, 0xBF, 0x87, 0x76, 0x72, 0xD3, 0x77, 0x3C, 0xE9, 0x02, 0x57, 0x92, 0x0F, 0x37, 0x67, 0x9F, 0x87, 0xC6, 0xF8, 0xFE, 0x09, 0x44, 0xD0, 0x7A, 0xCB, 0xEF, 0x54, 0xAC, 0xB5, 0xEE, 0x31, 0x27, 0x4F, 0x62, 0x56, 0xF8, 0x9D, 0xFF, 0x1D, 0x06, 0xF8, 0x40, 0x38, 0xCA, 0x0A, 0xF0, 0x06, 0x92, 0x6F, 0x1E, 0xB3, 0x45, 0x7C, 0x29, 0x30, 0x1D, 0x0E, 0x01, 0x37, 0xF3, 0xBF, 0xFA, 0x2E, 0xA0, 0x7B, 0xBA, 0x26, 0xC9, 0x77, 0x55, 0x6C, 0x69, 0xA4, 0xC7, 0x58, 0x4F, 0x9C, 0x6A, 0x7F, 0xE6, 0x3A, 0xD1, 0x82, 0xFD, 0x44, 0xA6, 0x8A, 0x9E, 0x76, 0x63, 0xE0, 0x67, 0xF0, 0xE4, 0x2B, 0xA6, 0x02, 0x5E, 0xF7, 0x37, 0x6C, 0xBA, 0x29, 0x36, 0xD7, 0x86, 0x0D, 0xB0, 0x38, 0xE1, 0x49, 0xE3, 0x58, 0x3E, 0xA6, 0x0C, 0x40, 0x05, 0x68, 0x1B, 0x6B, 0xEF, 0xF5, 0x8F, 0x55, 0xAB, 0x74, 0x6E, 0xA5, 0x02, 0xEC, 0x04, 0xDC, 0xEF, 0x2E, 0xAA, 0x1E, 0x80, 0x35, 0x20, 0x7E, 0xA7, 0x30, 0x87, 0x00, 0xA9, 0x7C, 0x93, 0x56, 0xCB, 0xBF, 0x18, 0x1D, 0x5C, 0xC4, 0x8C, 0x1D, 0xEA, 0xF2, 0xCB, 0xE7, 0xE4, 0x16, 0x1F, 0x4A, 0x6D, 0x1C, 0xE5, 0x8A, 0x11, 0x6F, 0x2C, 0xC9, 0x78, 0x13, 0xFD, 0x58, 0x5C, 0xA4, 0xD4, 0xDD, 0x9F, 0xC1, 0xA2, 0x80, 0x17, 0xA0, 0x83, 0x45, 0x6D, 0x6A, 0x19, 0xC4, 0xE5, 0xD9, 0xE7, 0x6F, 0xEA, 0x63, 0x2E, 0x86, 0xD1, 0xF5, 0x5C, 0xD4, 0xF7, 0x18, 0xCF, 0xF5, 0x16, 0x48, 0x11, 0xA0, 0xD6, 0xE9, 0x94, 0x3D, 0x6F, 0x6E, 0xA0, 0xC6, 0x08, 0x6A, 0x80, 0x2B, 0x70, 0x72, 0x49, 0x1A, 0x68, 0x06, 0xEA, 0x1D, 0x50, 0x03, 0x4E, 0x66, 0xBA, 0x01, 0xB2, 0x00, 0xCD, 0x79, 0xE5, 0x58, 0xAD, 0xA6, 0xE7, 0xBE, 0x4E, 0xAB, 0xFF, 0xC4, 0xB5, 0xBD, 0x7B, 0x8A, 0xD3, 0xE3, 0x43, 0x5B, 0xC0, 0x93, 0xAB, 0x3E, 0x69, 0x68, 0x75, 0xAB, 0x7D, 0xE7, 0xAD, 0x10, 0xF0, 0x6B, 0x68, 0xC7, 0xBF, 0xCC, 0x13, 0x7E, 0x5D, 0xFB, 0x8E, 0xE5, 0xDA, 0x06, 0x9C, 0xBF, 0xE9, 0x78, 0x66, 0x4D, 0xA6, 0xC8, 0xC0, 0x00, 0xAF, 0xB9, 0x92, 0xF1, 0x96, 0x69, 0xBF, 0xB4, 0x66, 0x3F, 0xAE, 0x8F, 0xA0, 0x0C, 0x7F, 0xFE, 0x94, 0x61, 0xEB, 0xF8, 0x85, 0x3D, 0xA8, 0x95, 0x0B, 0xA8, 0x01, 0x7C, 0xD8, 0x73, 0x47, 0xE1, 0xB5, 0x6B, 0xC5, 0xE0, 0x68, 0x39, 0x3E, 0xF7, 0x97, 0x06, 0x34, 0x79, 0x49, 0xA5, 0xD5, 0x1A, 0xAA, 0x7F, 0x56, 0x10, 0x0F, 0x5D, 0xFA, 0x15, 0x4F, 0xD5, 0x2E, 0x5C, 0x24, 0xBA, 0x60, 0x66, 0x89, 0x11, 0x8C, 0x88, 0x49, 0x3E, 0xB9, 0x14, 0x98, 0xDF, 0xD6, 0xDA, 0x7A, 0x46, 0xD0, 0xBE, 0x3B, 0xB4, 0xE0, 0xCA, 0x0C, 0x6C, 0xC0, 0x0C, 0x90, 0x04, 0xAC, 0xEF, 0x6E, 0xA8, 0x16, 0x94, 0x14, 0x98, 0xEF, 0x2B, 0x77, 0x97, 0xD0, 0xC5, 0xBF, 0x76, 0xFD, 0xFC, 0x64, 0x72, 0xD2, 0x64, 0x94, 0x36, 0x8C, 0x19, 0xAA, 0x39, 0xBE, 0x0F, 0x01, 0x6A, 0x03, 0x5D, 0xE3, 0xED, 0x78, 0x52, 0x27, 0xF6, 0x02, 0xCC, 0x00, 0x6D, 0x40, 0x36, 0x7D, 0xA2, 0x40, 0x0E, 0x2A, 0xC7, 0xC9, 0x47, 0xAB, 0xE5, 0x3A, 0x3D, 0xA9, 0x6C, 0x2E, 0xB2, 0x5E, 0x10, 0xE0, 0x17, 0x94, 0x17, 0x60, 0x9E, 0x2F, 0xFD, 0x10, 0xA2, 0x50, 0xF6, 0x33, 0x58, 0x6D, 0xBD, 0x8E, 0x35, 0xB9, 0x96, 0x65, 0x56, 0x6D, 0x21, 0x3C, 0x07, 0xB8, 0x01, 0x52, 0x77, 0x9C, 0xCC, 0x05, 0x30, 0xAE, 0x41, 0x63, 0x0B, 0x86, 0x83, 0xCC, 0x01, 0x67, 0x86, 0x8B, 0xFC, 0x64, 0x7B, 0xE4, 0xFC, 0xCF, 0x4E, 0xF1, 0x37, 0x43, 0x70, 0xCA, 0x65, 0xEA, 0x76, 0x32, 0x1E, 0x67, 0x9D, 0x02, 0xE6, 0x40, 0x18, 0x55, 0x4F, 0x81, 0x58, 0x40, 0xFB, 0x63, 0xA7, 0x0D, 0x68, 0x03, 0x3B, 0x00, 0x65, 0x86, 0x4A, 0xD0, 0x6A, 0x1B, 0xC2, 0xB1, 0xDA, 0x68, 0xE1, 0x55, 0x81, 0x6E, 0x40, 0x3D, 0xB9, 0x7D, 0x47, 0xBD, 0xDD, 0xF9, 0x9B, 0xA1, 0xAF, 0x8D, 0xCA, 0x6D, 0x35, 0x7B, 0x8A, 0xDD, 0xF1, 0xD4, 0x4F, 0x32, 0xBA, 0x0C, 0xD4, 0x81, 0x1D, 0x00, 0xF7, 0xBB, 0xF6, 0xBB, 0xE5, 0x7A, 0x1D, 0x29, 0xC0, 0xBE, 0x17, 0x98, 0x5A, 0x9C, 0xE0, 0xF4, 0x27, 0x72, 0xA9, 0xA7, 0xBE, 0xF7, 0x78, 0xCE, 0x81, 0x32, 0x1E, 0x59, 0xC6, 0x86, 0xF1, 0xB8, 0x23, 0xDD, 0x81, 0x28, 0xA0, 0x36, 0x57, 0x7C, 0x80, 0xF9, 0x1C, 0x5A, 0x80, 0xC4, 0x3C, 0xF4, 0xB7, 0x57, 0x34, 0x40, 0x5F, 0xEE, 0x3E, 0x56, 0x13, 0x48, 0xF8, 0x6E, 0x9F, 0x4C, 0x9E, 0x69, 0xDB, 0x15, 0x88, 0x17, 0x44, 0xED, 0x89, 0x49, 0x25, 0x26, 0x78, 0xF4, 0x38, 0x86, 0x9B, 0x51, 0xD0, 0x3B, 0x5E, 0x70, 0x29, 0xF3, 0x6D, 0x3D, 0x35, 0x8B, 0xBB, 0x80, 0xDE, 0x40, 0x38, 0xB0, 0xF3, 0xCE, 0x8C, 0xE1, 0xDC, 0x90, 0x9C, 0x45, 0xC7, 0xE8, 0x4D, 0xBA, 0x9B, 0x5A, 0xEE, 0xBC, 0x5D, 0x69, 0x27, 0x95, 0xA6, 0x00, 0xBA, 0xCA, 0xB9, 0xF6, 0xEC, 0xA2, 0xEF, 0xE4, 0xEE, 0x57, 0x40, 0xFF, 0xC1, 0x1A, 0xA8, 0x01, 0x69, 0x14, 0x39, 0x04, 0xBC, 0x6F, 0x58, 0x00, 0x32, 0xD8, 0x0E, 0xE8, 0xA0, 0x8F, 0xD1, 0x14, 0x82, 0xB5, 0xDA, 0xB0, 0xA4, 0x60, 0x3D, 0x53, 0x1F, 0xE7, 0x97, 0xEF, 0x11, 0x3C, 0x8E, 0x69, 0xE2, 0x9A, 0x78, 0xB8, 0xEA, 0x52, 0x79, 0xE5, 0xFC, 0x3C, 0x8D, 0xC4, 0x59, 0xCC, 0x7F, 0x37, 0xFD, 0xC4, 0x22, 0x75, 0x29, 0xEE, 0x18, 0x7B, 0x9C, 0xF8, 0xAD, 0x55, 0x68, 0x7E, 0x1C, 0x16, 0xE3, 0x7F, 0x07, 0xBA, 0x7F, 0x6D, 0x3E, 0xF7, 0x91, 0xBF, 0x75, 0x1F, 0xDD, 0x9E, 0xE7, 0xD2, 0xCD, 0x6E, 0x26, 0xD4, 0x70, 0x5E, 0x0A, 0xA4, 0xF2, 0xE7, 0x00, 0x1D, 0x78, 0x00, 0x3D, 0x3E, 0x0D, 0x5B, 0x40, 0xE4, 0x0D, 0x37, 0x40, 0x13, 0x90, 0x06, 0x8C, 0x52, 0xDC, 0x9B, 0x46, 0x33, 0xE8, 0x70, 0x52, 0xA2, 0xB6, 0x1C, 0xDD, 0x02, 0x27, 0x8B, 0x54, 0x26, 0x40, 0xB5, 0xAC, 0xA7, 0x89, 0x95, 0x4D, 0x85, 0x70, 0x31, 0x14, 0x75, 0xB7, 0x88, 0xBE, 0x9A, 0x24, 0xED, 0x38, 0x32, 0xBF, 0xA7, 0x2A, 0x31, 0x80, 0x1C, 0xE8, 0xB8, 0xD9, 0x6A, 0x70, 0xD4, 0x31, 0xF9, 0x87, 0xB4, 0x11, 0x48, 0x53, 0x20, 0xC7, 0x11, 0x44, 0xFB, 0xB4, 0xD2, 0xFB, 0x35, 0xFE, 0xA7, 0x4B, 0xAB, 0x5E, 0x4F, 0xD3, 0x58, 0x15, 0xAA, 0x63, 0x8E, 0x5D, 0x0B, 0xC8, 0x0D, 0x74, 0xDE, 0x7F, 0xC0, 0x60, 0x97, 0xD1, 0x0D, 0x44, 0x0C, 0x04, 0x30, 0x07, 0xB6, 0x53, 0xEF, 0x6E, 0x3E, 0x19, 0x50, 0x4D, 0xA3, 0x39, 0xFE, 0x02, 0x1E, 0x98, 0x89, 0x9A, 0x9F, 0x4F, 0x6B, 0x45, 0xC1, 0x9F, 0x37, 0xDE, 0x48, 0x2D, 0x87, 0xCB, 0x27, 0x26, 0xF0, 0x32, 0xDE, 0x48, 0x4E, 0x4F, 0x7D, 0x34, 0x5E, 0x95, 0x31, 0x8B, 0xB4, 0x99, 0x89, 0xC7, 0xA9, 0x3D, 0xA0, 0x10, 0xCD, 0x06, 0x34, 0x7E, 0x5B, 0x57, 0x8F, 0x09, 0x75, 0xFE, 0x74, 0x71, 0x46, 0xE1, 0xE9, 0xBC, 0xC0, 0x10, 0xC2, 0xBC, 0xA2, 0x41, 0x63, 0x03, 0x4B, 0x01, 0x7B, 0xE6, 0xE5, 0xEB, 0x47, 0x8C, 0x05, 0x94, 0x4C, 0x6E, 0xEF, 0xC0, 0x06, 0x1D, 0x1C, 0xAF, 0x37, 0xF6, 0x9E, 0xFF, 0xB6, 0x80, 0x54, 0xA0, 0x85, 0x13, 0x83, 0x46, 0x8B, 0xF1, 0xE4, 0xDB, 0x64, 0xB3, 0x6D, 0x78, 0xCF, 0xB6, 0x8C, 0x1C, 0x17, 0x55, 0x17, 0x37, 0xFC, 0x81, 0x33, 0x59, 0x1B, 0xB2, 0x44, 0x59, 0x4C, 0xB9, 0x02, 0x22, 0x7E, 0x75, 0xCD, 0x72, 0xFA, 0x03, 0x4C, 0x56, 0x63, 0xC2, 0x12, 0x48, 0xDA, 0x03, 0x28, 0x1F, 0xB7, 0x9A, 0x4E, 0x22, 0x7C, 0x32, 0x36, 0xE8, 0xD1, 0x5F, 0xE7, 0x5A, 0x44, 0xBF, 0x31, 0xEA, 0x63, 0xBC, 0x91, 0x1F, 0xF2, 0xF8, 0x83, 0x3A, 0x00, 0x2B, 0x3A, 0xE4, 0xF0, 0x0A, 0xB5, 0xD8, 0x81, 0x71, 0x62, 0xD8, 0x84, 0x79, 0x50, 0xA3, 0x03, 0x68, 0x00, 0xB5, 0x46, 0x8E, 0x2D, 0x80, 0xF0, 0x41, 0x0D, 0x36, 0x60, 0x31, 0x30, 0x80, 0xBA, 0xE0, 0xE2, 0xB4, 0x19, 0x2E, 0xE7, 0x19, 0x85, 0x7B, 0x96, 0xF5, 0xAC, 0x96, 0x06, 0x4C, 0x1F, 0x0D, 0x73, 0x81, 0x20, 0xBC, 0xF8, 0xFC, 0x19, 0xFD, 0xB3, 0x52, 0x8E, 0xCD, 0x02, 0xF0, 0xAB, 0xCE, 0x47, 0x30, 0x0A, 0xC7, 0xBA, 0xB7, 0x9B, 0x55, 0x95, 0xE1, 0x12, 0xC0, 0x04, 0xD0, 0x9C, 0x57, 0x92, 0xAE, 0xD4, 0x31, 0x72, 0xC3, 0x04, 0x51, 0x80, 0x25, 0xB0, 0x26, 0x7E, 0xE0, 0x0A, 0xAC, 0x75, 0xC3, 0x69, 0x56, 0x68, 0x68, 0xC2, 0x4A, 0xF0, 0x03, 0x02, 0xB5, 0x60, 0xC1, 0x35, 0x10, 0x07, 0x8E, 0x59, 0x0D, 0x66, 0xDD, 0x32, 0x28, 0x40, 0xD6, 0x20, 0x00, 0x55, 0xC0, 0x02, 0xA8, 0xA0, 0xCD, 0x30, 0x0F, 0x77, 0x15, 0x12, 0xC4, 0x1D, 0xEE, 0xC7, 0x1A, 0xA5, 0x52, 0x33, 0xC7, 0xB7, 0x0D, 0x87, 0x3B, 0x58, 0x0C, 0xF3, 0x61, 0x17, 0x97, 0xB0, 0x4B, 0xEC, 0x9B, 0x1E, 0xDC, 0x68, 0x9E, 0x7B, 0x28, 0x24, 0x4F, 0x87, 0x7C, 0x01, 0x19, 0x40, 0x08, 0x60, 0x09, 0xE4, 0x4C, 0x08, 0xAE, 0xC0, 0x4B, 0x68, 0x8A, 0x31, 0x5A, 0x8C, 0x45, 0x8C, 0x2D, 0xE9, 0xD9, 0xBC, 0xFE, 0xEE, 0xB4, 0xDA, 0x4E, 0xE0, 0x61, 0x52, 0x85, 0x3A, 0x81, 0x30, 0xA0, 0x65, 0x16, 0xF0, 0x04, 0x24, 0xEF, 0xBE, 0x19, 0x62, 0x80, 0xCB, 0xC0, 0x01, 0x33, 0x40, 0x02, 0xD8, 0x0A, 0x28, 0xA7, 0xC7, 0xA6, 0xD1, 0x7A, 0xEE, 0xE7, 0x3D, 0x2A, 0xF8, 0x02, 0xB7, 0xB7, 0xEC, 0x39, 0xF3, 0x35, 0xD6, 0xC5, 0x08, 0xF8, 0xDE, 0xF9, 0x8A, 0x3B, 0x97, 0xB0, 0x2B, 0x28, 0xA5, 0x4D, 0x7F, 0x02, 0x63, 0x8E, 0xB3, 0xFE, 0xC7, 0xFF, 0x09, 0x20, 0x80, 0x00, 0x7C, 0x9D, 0x89, 0x8D, 0xEC, 0x48, 0x8F, 0x84, 0x5D, 0x79, 0x26, 0x24, 0x6F, 0xD2, 0x7F, 0xC7, 0x16, 0x15, 0x0C, 0xB5, 0x52, 0xF8, 0x07, 0x8B, 0xEB, 0x43, 0xA9, 0xD5, 0x33, 0x5D, 0x7C, 0x79, 0xF2, 0x08, 0xEE, 0x22, 0x9D, 0x03, 0x84, 0x01, 0xC2, 0x9F, 0x25, 0x50, 0x6B, 0x5E, 0x63, 0x7F, 0xD9, 0x59, 0x65, 0x4C, 0x0A, 0x5D, 0x16, 0x3E, 0x85, 0xAC, 0x97, 0x9F, 0x4B, 0xB6, 0xEF, 0x72, 0x2E, 0x5C, 0xE3, 0xF1, 0x29, 0x66, 0x2D, 0xC9, 0x34, 0xF1, 0xFD, 0x82, 0x62, 0x40, 0xD7, 0xFA, 0x60, 0x0F, 0xE0, 0x05, 0xCC, 0x8E, 0x50, 0x0F, 0xA0, 0x6A, 0x11, 0x40, 0x1A, 0xE0, 0x0E, 0xD8, 0xC2, 0x77, 0xF0, 0x3F, 0x4A, 0x88, 0xBD, 0xDF, 0xE1, 0xF8, 0x3A, 0x38, 0x05, 0x7F, 0xD9, 0x9E, 0xDD, 0x5D, 0x0A, 0xBF, 0x37, 0x70, 0x7B, 0xBB, 0x24, 0x76, 0x26, 0xCB, 0xB7, 0xAB, 0xDD, 0x49, 0x20, 0x2F, 0xA7, 0x9E, 0xEA, 0xA3, 0xAE, 0x2D, 0x7D, 0x76, 0x84, 0x02, 0xB1, 0xD0, 0x80, 0x09, 0x46, 0xF0, 0xE9, 0xF4, 0xDB, 0x5A, 0x7B, 0x60, 0x5D, 0x8F, 0x5D, 0x7D, 0x92, 0x1D, 0x9D, 0xB9, 0x32, 0x3D, 0xED, 0x93, 0xB5, 0xB9, 0xF6, 0xED, 0x77, 0xDF, 0x6F, 0xAB, 0xC1, 0x91, 0x79, 0x37, 0x20, 0x8B, 0xDC, 0x69, 0x19, 0x80, 0x0E, 0x10, 0x3B, 0xCB, 0xCE, 0xA2, 0x8A, 0xD7, 0xA0, 0x45, 0x00, 0xE7, 0xF0, 0x67, 0x40, 0x0A, 0xD0, 0x8E, 0x9F, 0xD5, 0xA1, 0xCD, 0x9E, 0xC0, 0xCA, 0x03, 0xD1, 0x67, 0xEB, 0xB4, 0x11, 0xC4, 0x39, 0xCA, 0xD1, 0x34, 0x58, 0x76, 0x92, 0xE6, 0x2F, 0x26, 0xD5, 0xCA, 0x7A, 0x02, 0xA0, 0xAF, 0x54, 0x14, 0xC5, 0x55, 0x03, 0x26, 0xA8, 0x5D, 0x29, 0x16, 0x27, 0xEF, 0xC5, 0xE4, 0xCC, 0x2E, 0xF8, 0x54, 0x16, 0xDF, 0xA5, 0x3A, 0xE2, 0x95, 0x0D, 0x45, 0xF0, 0x03, 0x22, 0xB6, 0x0A, 0x68, 0x01, 0xB6, 0x70, 0x07, 0x2A, 0x81, 0x51, 0x04, 0x15, 0x64, 0xA1, 0x05, 0x78, 0x02, 0x39, 0x40, 0x6F, 0xAB, 0x91, 0x93, 0x80, 0x39, 0x10, 0x0D, 0xD4, 0x01, 0x9A, 0x60, 0x1B, 0xE4, 0x85, 0x19, 0x10, 0x07, 0x28, 0xA3, 0xCD, 0xDE, 0xC6, 0x35, 0xBF, 0x73, 0x6D, 0x6D, 0x4D, 0x9A, 0x6E, 0x51, 0x18, 0xA2, 0xEE, 0x63, 0xB8, 0x8E, 0xCA, 0x0C, 0xF6, 0x27, 0xDF, 0x32, 0xF6, 0x37, 0x52, 0xAC, 0x7F, 0x35, 0x4F, 0x87, 0xE7, 0x45, 0x59, 0xF5, 0x3B, 0xFE, 0xF1, 0x07, 0xB0, 0x6D, 0x1C, 0xD0, 0x02, 0xD8, 0x42, 0xF7, 0x6B, 0x86, 0xAC, 0x8C, 0x5C, 0xFF, 0x29, 0x34, 0x46, 0x2D, 0xFA, 0x69, 0x59, 0x6C, 0x0A, 0xB8, 0x03, 0x91, 0x07, 0xE5, 0x84, 0x06, 0x58, 0x01, 0xEC, 0x6A, 0xAC, 0x07, 0x08, 0x03, 0xDA, 0xA1, 0x2D, 0x77, 0x0E, 0x60, 0x02, 0x64, 0x00, 0x13, 0x2B, 0x38, 0xB7, 0xD0, 0x03, 0x98, 0x02, 0x11, 0x40, 0x1B, 0x30, 0xB3, 0x22, 0x30, 0x4A, 0x9B, 0xD9, 0x66, 0x26, 0xE6, 0x9A, 0x8E, 0xD9, 0x21, 0x6B, 0xB3, 0xD3, 0xF8, 0xF7, 0x4B, 0x47, 0x1F, 0x18, 0xDF, 0x3D, 0x5D, 0xFB, 0xA7, 0x3A, 0xA4, 0xBC, 0x39, 0x01, 0x63, 0xAF, 0x57, 0x8C, 0xC7, 0x70, 0xF7, 0xA7, 0x5B, 0x82, 0x06, 0x90, 0x87, 0x9F, 0xD6, 0x74, 0x07, 0x28, 0xE5, 0x28, 0x80, 0xCD, 0x28, 0x75, 0x59, 0x03, 0xD3, 0x8D, 0x01, 0xBA, 0x0F, 0x85, 0x9A, 0x05, 0x45, 0x75, 0xEE, 0xBB, 0x37, 0xBD, 0x14, 0x70, 0x8C, 0x03, 0x65, 0xE1, 0xC0, 0x04, 0x7F, 0x06, 0x68, 0x02, 0x94, 0xFA, 0x13, 0x01, 0x2C, 0x16, 0xB3, 0xA8, 0x85, 0xDD, 0x0F, 0xA1, 0xDA, 0xF9, 0xFA, 0x85, 0xDA, 0xB7, 0xA2, 0xC1, 0xD6, 0x66, 0xCC, 0x74, 0xEA, 0x4D, 0x73, 0xA8, 0x0D, 0x65, 0xF5, 0xCA, 0x5C, 0xCF, 0x6A, 0xE5, 0xC9, 0xDB, 0xB3, 0x59, 0x03, 0x28, 0x79, 0x5C, 0xEA, 0xBB, 0x63, 0xD6, 0x6E, 0x3A, 0x7B, 0x7E, 0x2A, 0x1E, 0x10, 0x9C, 0x9F, 0x00, 0x27, 0x76, 0x89, 0xCD, 0x9D, 0xA9, 0x95, 0xB0, 0xB5, 0xFC, 0x10, 0x4F, 0x9B, 0x0B, 0x75, 0x36, 0xFE, 0xDB, 0x57, 0x6C, 0x03, 0xA1, 0x86, 0xDF, 0x1B, 0x07, 0x2C, 0x81, 0xA7, 0x7E, 0x23, 0x81, 0xF2, 0x45, 0x01, 0xAD, 0xF7, 0x02, 0x68, 0x02, 0x54, 0xB0, 0x73, 0x23, 0x81, 0x87, 0x63, 0x40, 0xC7, 0x42, 0x00, 0x8A, 0x50, 0xC6, 0xD0, 0x66, 0x88, 0x44, 0x95, 0xF5, 0x2F, 0x7E, 0x97, 0xF2, 0xF4, 0x52, 0xC5, 0xE0, 0x53, 0x08, 0x9B, 0x1C, 0x17, 0xA4, 0x9A, 0x47, 0x43, 0x25, 0x61, 0xC5, 0x61, 0xE6, 0x52, 0x03, 0xB8, 0x83, 0x04, 0xFE, 0x09, 0x12, 0x1C, 0x20, 0x0A, 0xD0, 0x01, 0x8E, 0x7F, 0xC4, 0xF4, 0xF7, 0x15, 0x1B, 0x56, 0xB9, 0xDF, 0x42, 0x76, 0xB2, 0x3F, 0x9B, 0x85, 0xF6, 0xAD, 0x2B, 0x11, 0xB1, 0xD8, 0x9F, 0xF9, 0x25, 0xDE, 0x9F, 0x14, 0x66, 0x78, 0xFE, 0x25, 0xC5, 0x01, 0x53, 0xC0, 0x0B, 0xE8, 0x4F, 0xF1, 0xE2, 0x34, 0xD0, 0x8B, 0x18, 0x80, 0x42, 0x46, 0x4F, 0x4B, 0xC3, 0x45, 0xE7, 0xA1, 0xD9, 0x12, 0x92, 0xB0, 0x65, 0xA8, 0x61, 0x3C, 0xA8, 0x72, 0xD7, 0x98, 0x75, 0xE5, 0xC9, 0x26, 0x03, 0x0E, 0x7E, 0xAF, 0x07, 0xC2, 0x79, 0xED, 0xFF, 0x55, 0xD7, 0xEE, 0x14, 0xBD, 0x63, 0x90, 0x00, 0xE0, 0xA7, 0x1E, 0x20, 0x1A, 0x50, 0x26, 0xF5, 0xF7, 0x82, 0xD1, 0x10, 0x56, 0x59, 0x7C, 0xFD, 0xE3, 0xF6, 0x26, 0x54, 0xD6, 0xA3, 0x02, 0x98, 0x75, 0xD7, 0x98, 0x30, 0x02, 0xE7, 0x76, 0x1E, 0xCF, 0xDC, 0x7A, 0xFF, 0xEE, 0x14, 0xFB, 0xFE, 0x94, 0x92, 0x79, 0x02, 0x63, 0xEB, 0x66, 0xA1, 0x8B, 0x8C, 0xCE, 0xB4, 0x06, 0x2A, 0x00, 0x5B, 0xC8, 0x01, 0xE0, 0x47, 0xBA, 0x0E, 0x1C, 0xB5, 0x99, 0xDD, 0x28, 0x6F, 0x17, 0xA5, 0x7C, 0x07, 0x93, 0xC6, 0x04, 0xFE, 0xAE, 0x74, 0xC4, 0xCA, 0x3A, 0xA1, 0xD3, 0xA6, 0x7A, 0x77, 0x22, 0x97, 0x8F, 0x06, 0xA2, 0xD5, 0xA7, 0xE8, 0xC7, 0x00, 0x1B, 0x40, 0x62, 0x0D, 0x9B, 0x40, 0xEB, 0x62, 0x5F, 0xF1, 0x59, 0x1B, 0xAE, 0x49, 0x34, 0xD7, 0xDA, 0x94, 0x85, 0x6C, 0x40, 0xF2, 0xD6, 0xBF, 0xB1, 0x5C, 0xB0, 0x87, 0x0B, 0xA3, 0x4D, 0x43, 0x33, 0xDF, 0x05, 0x06, 0x61, 0x40, 0x05, 0x30, 0x8C, 0xBE, 0x98, 0xDC, 0xC5, 0xA8, 0xB6, 0xD0, 0x04, 0x9E, 0x88, 0x83, 0xDE, 0x6F, 0x86, 0xEE, 0x2B, 0x45, 0xAB, 0x35, 0x02, 0x78, 0xA5, 0x3F, 0x9C, 0x41, 0xF4, 0x53, 0x2B, 0x59, 0x79, 0x89, 0x8C, 0xE3, 0x95, 0x56, 0xB3, 0x6E, 0xA8, 0xB2, 0x84, 0xDE, 0xE5, 0x2B, 0xF5, 0x15, 0xEC, 0xF8, 0x04, 0x6F, 0xA3, 0x16, 0x01, 0x98, 0xDC, 0xBA, 0x10, 0x7D, 0xEE, 0x98, 0x7C, 0x36, 0xE3, 0x69, 0x9F, 0xDA, 0xCB, 0xBC, 0x6B, 0x71, 0x4E, 0xAE, 0x45, 0x3F, 0x91, 0x76, 0x3D, 0x74, 0xAD, 0xEC, 0x9B, 0xD7, 0x50, 0x45, 0xF0, 0x14, 0xE8, 0x5E, 0x5B, 0x2C, 0xD4, 0x81, 0xCC, 0xCD, 0x96, 0x54, 0xA0, 0x1C, 0xC8, 0x00, 0x9E, 0xFA, 0xE7, 0x01, 0xEA, 0x00, 0x5D, 0xFB, 0x4A, 0xD3, 0x6A, 0x83, 0xCD, 0x5C, 0xA1, 0x58, 0x2D, 0xB6, 0xFD, 0x54, 0x2B, 0x30, 0x62, 0xA7, 0x11, 0x1C, 0x53, 0x94, 0xBB, 0xE6, 0xD9, 0xDA, 0x1F, 0xB7, 0xAF, 0xD5, 0x3E, 0xAA, 0x57, 0x6B, 0xA7, 0xD1, 0x8F, 0x3E, 0x17, 0x03, 0x8E, 0x9F, 0x5E, 0x04, 0xDD, 0x77, 0x54, 0xDC, 0xE5, 0x51, 0x3B, 0xB9, 0x3A, 0xCD, 0x3E, 0x0F, 0x19, 0xA8, 0x5C, 0xAB, 0xE5, 0xB9, 0x67, 0x7D, 0x51, 0xD9, 0x8A, 0x07, 0x45, 0x0A, 0x32, 0x30, 0x90, 0x75, 0xCE, 0x1D, 0x82, 0x3A, 0x0A, 0xA8, 0xDF, 0xE1, 0x04, 0x53, 0x20, 0x7B, 0x21, 0x80, 0xD5, 0x9D, 0x8B, 0x5B, 0x05, 0x0C, 0xBB, 0x34, 0x73, 0x86, 0x3E, 0x87, 0x10, 0x4C, 0x54, 0xB1, 0x5B, 0x89, 0xC8, 0x8E, 0x22, 0xD5, 0x42, 0x0D, 0x8B, 0x6B, 0x39, 0x56, 0x63, 0xB3, 0x2B, 0x3D, 0xDE, 0xF5, 0x13, 0xFC, 0xD4, 0xB9, 0x53, 0x11, 0x22, 0x01, 0x5F, 0x68, 0x7C, 0x4A, 0xA5, 0xF8, 0x90, 0x0D, 0x70, 0xF2, 0x2E, 0x52, 0x4E, 0x5F, 0xAC, 0xED, 0xBD, 0x3F, 0x0B, 0x5A, 0xDD, 0x5D, 0x33, 0x74, 0x1F, 0xDE, 0xE5, 0xEA, 0x4F, 0x22, 0x06, 0xB2, 0xAD, 0xEE, 0x48, 0xEA, 0xDC, 0xA6, 0x74, 0xBF, 0x8B, 0x77, 0x63, 0xE1, 0x71, 0xF7, 0x76, 0x6D, 0x01, 0xE2, 0x00, 0x39, 0xFB, 0xCA, 0xD0, 0x6A, 0x82, 0x16, 0x67, 0x35, 0xFF, 0x42, 0x81, 0x82, 0x3B, 0x06, 0x0E, 0xAD, 0x14, 0xC4, 0x12, 0x35, 0x58, 0x4F, 0x84, 0x7A, 0x38, 0xD5, 0xBB, 0x2C, 0xAF, 0x3F, 0x01, 0x29, 0xBD, 0x16, 0x26, 0x5C, 0xB6, 0x81, 0x01, 0xCC, 0x6E, 0x35, 0x8D, 0x3E, 0x8B, 0x7D, 0xD8, 0xE7, 0xD3, 0xEC, 0xD7, 0x15, 0xC8, 0xA0, 0xCF, 0x9F, 0xD1, 0x01, 0xE0, 0xF8, 0x95, 0xF2, 0x7C, 0xFA, 0xAA, 0xB1, 0xD6, 0x27, 0xB6, 0x17, 0x71, 0x6F, 0x03, 0x3E, 0x77, 0xD9, 0xCE, 0x11, 0xC0, 0x0D, 0x18, 0x7A, 0xCD, 0x05, 0xD0, 0x01, 0x18, 0x2F, 0xEC, 0x02, 0x72, 0xD1, 0xFB, 0x4A, 0x1C, 0x5A, 0x4D, 0x37, 0x0B, 0x2A, 0x70, 0x76, 0x2F, 0x83, 0x94, 0xB3, 0x30, 0xF3, 0xD4, 0x59, 0x42, 0xB4, 0x55, 0x3F, 0x82, 0xAD, 0xB4, 0xD0, 0xF3, 0xE1, 0xD1, 0xEB, 0xF8, 0x26, 0x2D, 0x8B, 0x7E, 0xCA, 0xD5, 0x5D, 0x80, 0x68, 0x40, 0x86, 0x59, 0xD9, 0x80, 0x26, 0x20, 0xFE, 0xAE, 0x3A, 0xF6, 0x94, 0xFC, 0xCF, 0x55, 0xDE, 0x14, 0x8F, 0x80, 0xB0, 0xF0, 0x15, 0x46, 0x4A, 0x66, 0xC1, 0x24, 0x76, 0xEE, 0x7E, 0x97, 0x6F, 0x12, 0xF9, 0x32, 0x7B, 0x21, 0x04, 0x86, 0x2D, 0x8B, 0xEB, 0x8E, 0x12, 0x58, 0x02, 0x39, 0x37, 0xE2, 0x13, 0x41, 0x10, 0x03, 0x9E, 0xFE, 0xE4, 0x4A, 0xAB, 0x21, 0xC2, 0x1E, 0x53, 0xBF, 0x0B, 0x4C, 0x9C, 0x82, 0x38, 0x40, 0xC7, 0xF6, 0xD7, 0x0A, 0x8C, 0x74, 0x9D, 0x1F, 0x4C, 0x07, 0xB9, 0x06, 0xA9, 0x6C, 0x3B, 0xFB, 0xAD, 0x2A, 0xF8, 0x8C, 0xB5, 0xD8, 0x41, 0xB6, 0x48, 0x01, 0xCC, 0xEF, 0x55, 0xBD, 0x08, 0xA6, 0xA8, 0xDC, 0x0B, 0xB8, 0x3E, 0xF9, 0xEA, 0x27, 0x3E, 0xBD, 0x1F, 0x56, 0x76, 0x99, 0xE7, 0xAE, 0x06, 0x24, 0x9F, 0x33, 0x0A, 0xEB, 0x16, 0x5E, 0x1B, 0xC6, 0x93, 0xF1, 0xED, 0x0E, 0xD4, 0xA7, 0x79, 0xA1, 0x27, 0x87, 0x15, 0x10, 0x09, 0x78, 0x03, 0xCA, 0xB1, 0xD6, 0x40, 0x0A, 0x50, 0xB5, 0x6F, 0x36, 0xAD, 0xE6, 0x28, 0x4F, 0xAA, 0x86, 0x1B, 0x44, 0xD7, 0x5B, 0xB0, 0xFE, 0x6F, 0x69, 0x87, 0xE7, 0xA2, 0x15, 0x41, 0xE9, 0xCC, 0x5D, 0x47, 0x83, 0xAB, 0xFF, 0xDD, 0xD5, 0x8C, 0x5D, 0x3F, 0xF0, 0xC9, 0x9F, 0x48, 0xA1, 0x17, 0x30, 0x0D, 0xB0, 0x2C, 0xAF, 0x13, 0x10, 0xBD, 0xBF, 0x0B, 0x0B, 0x9A, 0xE8, 0x2A, 0x39, 0x01, 0x68, 0xD2, 0xAD, 0xC9, 0xEB, 0x0A, 0x5E, 0xD1, 0xF3, 0x99, 0x4C, 0xEC, 0x2D, 0xC5, 0x40, 0x96, 0x50, 0x53, 0x9E, 0x5D, 0x46, 0xB6, 0x33, 0x79, 0x03, 0xF5, 0xA8, 0x61, 0x03, 0x51, 0x77, 0xDC, 0x25, 0x6C, 0x11, 0x80, 0x1B, 0xA0, 0x9F, 0x6E, 0x68, 0x1A, 0xC0, 0x38, 0x8D, 0x16, 0xEB, 0x9A, 0x4D, 0xE4, 0x2E, 0xAB, 0xA0, 0x8B, 0x86, 0xE9, 0x26, 0x2D, 0x6F, 0x34, 0x45, 0xE7, 0x07, 0xC9, 0x59, 0xA7, 0xD1, 0x5C, 0x13, 0x34, 0xE3, 0x12, 0x95, 0x47, 0x10, 0x91, 0x97, 0xD1, 0x5B, 0x32, 0x8F, 0xA5, 0x11, 0x15, 0x80, 0x35, 0x70, 0x74, 0xC1, 0x02, 0x16, 0xA6, 0xD0, 0xC7, 0xDB, 0x60, 0x8B, 0x73, 0x78, 0x9E, 0x95, 0xA8, 0x18, 0x46, 0xB6, 0x37, 0x3C, 0xEA, 0x8F, 0x96, 0xC2, 0xC9, 0xB7, 0x29, 0x8B, 0xFC, 0x25, 0x37, 0xD4, 0x9D, 0xC0, 0x5D, 0x2C, 0x8C, 0x77, 0xC0, 0x29, 0x0C, 0xB2, 0x70, 0x03, 0x6C, 0x00, 0x4E, 0xEC, 0x31, 0xA0, 0xEA, 0x9E, 0xDF, 0x99, 0xB4, 0xDA, 0x9A, 0x6B, 0x14, 0x97, 0x66, 0x6D, 0x94, 0x6A, 0x97, 0xE0, 0xEF, 0xE4, 0x32, 0xCA, 0x93, 0xB6, 0xD5, 0xDE, 0x3A, 0xFA, 0x6E, 0x65, 0xF3, 0x8D, 0xB3, 0xDB, 0xB3, 0x38, 0xCF, 0x5B, 0x6A, 0x68, 0x4F, 0xE1, 0x6B, 0x7C, 0xB2, 0x10, 0xB9, 0xC8, 0xB5, 0x53, 0xB0, 0xE8, 0x35, 0x5E, 0x6C, 0x0A, 0x81, 0x3F, 0xA1, 0x5B, 0x1E, 0xAD, 0xCA, 0xEE, 0x53, 0x94, 0x2A, 0x20, 0x57, 0x4D, 0x63, 0x3E, 0x6D, 0x38, 0xA6, 0x77, 0xA8, 0x06, 0x5D, 0xA0, 0x6B, 0xAE, 0x02, 0x5C, 0x81, 0x91, 0xDB, 0xB5, 0x3C, 0x44, 0x00, 0x95, 0x80, 0x0F, 0xA0, 0x05, 0x78, 0x30, 0xBB, 0x97, 0x56, 0x43, 0x10, 0xAA, 0x5C, 0xA1, 0xF9, 0x5F, 0x8A, 0xFE, 0x1B, 0xA6, 0x9B, 0x66, 0xA2, 0x57, 0xDD, 0xA1, 0xC6, 0x6C, 0x2E, 0x93, 0x51, 0x73, 0xE2, 0x23, 0xC5, 0xAF, 0x3C, 0xB3, 0xD2, 0x24, 0x4F, 0x54, 0x1A, 0xC8, 0x03, 0x28, 0xB3, 0x31, 0x06, 0xD0, 0x00, 0x64, 0x7F, 0xC6, 0xEA, 0xD6, 0x36, 0x4A, 0x24, 0x00, 0xC5, 0x65, 0x86, 0x72, 0x58, 0xCC, 0xF5, 0xE1, 0xE9, 0xEB, 0xCA, 0x0A, 0xF2, 0xA7, 0x94, 0xD3, 0x65, 0x03, 0x5C, 0x4C, 0xBE, 0xA7, 0xF1, 0x1C, 0x48, 0x03, 0x46, 0x77, 0x00, 0xAE, 0x29, 0x25, 0x80, 0xC8, 0x85, 0x00, 0x3A, 0x78, 0x65, 0x0C, 0xC8, 0x02, 0x56, 0xDD, 0xE7, 0x3D, 0xAE, 0x35, 0xBC, 0x9F, 0xE1, 0xDB, 0x14, 0x73, 0x7E, 0x38, 0xE3, 0xD8, 0x52, 0xB2, 0xF6, 0x3A, 0xE7, 0x08, 0xDA, 0x5B, 0x22, 0x65, 0xAD, 0xEE, 0x6B, 0x68, 0xEA, 0x95, 0x9D, 0x80, 0xF5, 0x6C, 0x4F, 0x07, 0x1C, 0x1E, 0x0A, 0x4C, 0xDE, 0xD9, 0x18, 0x23, 0x00, 0x4B, 0x0E, 0x39, 0xF2, 0x7C, 0x8D, 0xC0, 0x93, 0x68, 0xCE, 0x82, 0xC5, 0x4B, 0x9C, 0xEE, 0x72, 0x17, 0x19, 0x9E, 0x7A, 0xBB, 0x68, 0x2A, 0x07, 0xE7, 0xFE, 0xAC, 0x9E, 0x73, 0xC4, 0x1C, 0xDA, 0x7E, 0x97, 0xC5, 0x04, 0xDC, 0xEE, 0x42, 0x16, 0x73, 0x20, 0x63, 0x61, 0x40, 0x1C, 0x40, 0x07, 0x10, 0x03, 0x34, 0x81, 0x7E, 0xC6, 0xDA, 0x6C, 0xCB, 0x54, 0x63, 0xE8, 0x18, 0x4E, 0xD1, 0x2E, 0x24, 0x45, 0x4C, 0x6D, 0xD8, 0x3D, 0x30, 0xA8, 0x77, 0x00, 0xB2, 0x17, 0xF9, 0x37, 0x3B, 0xC1, 0x98, 0x2F, 0x9B, 0xCF, 0xF9, 0xF0, 0x16, 0x36, 0xC9, 0x01, 0xAC, 0xA9, 0xD4, 0x01, 0x58, 0x2F, 0xEC, 0xD5, 0xED, 0x40, 0x60, 0x08, 0x31, 0x4A, 0x07, 0x58, 0x1C, 0xE1, 0xB2, 0xFF, 0xF4, 0xB9, 0x43, 0x46, 0xDE, 0xAF, 0x44, 0xE9, 0x9D, 0xBD, 0x02, 0x3D, 0x45, 0x15, 0xB3, 0x51, 0x02, 0x58, 0x04, 0x71, 0x73, 0x06, 0x20, 0x1C, 0x60, 0x05, 0x83, 0x08, 0xC0, 0x7E, 0xE3, 0xEA, 0x0B, 0x01, 0xCE, 0xBE, 0x52, 0x03, 0xC4, 0xA2, 0x06, 0x3F, 0x4B, 0x83, 0xD1, 0xFC, 0xDC, 0x3D, 0x7F, 0x64, 0x6C, 0x93, 0x30, 0x14, 0x7F, 0x8B, 0x06, 0xDC, 0xEE, 0xAA, 0x88, 0xA9, 0x4D, 0x6E, 0x9C, 0x55, 0xFF, 0x21, 0x98, 0x01, 0xDB, 0x35, 0x90, 0x4C, 0xD7, 0x36, 0x76, 0xD5, 0xE6, 0x5F, 0xC6, 0x9C, 0x75, 0xC6, 0x4B, 0xF4, 0xAE, 0x75, 0x60, 0x6B, 0x68, 0x0B, 0x20, 0xF7, 0x67, 0xC2, 0xD0, 0x41, 0x01, 0x91, 0x80, 0x08, 0x70, 0x0E, 0x20, 0x0A, 0xE8, 0xA2, 0x67, 0x5D, 0x5F, 0x4F, 0xFE, 0xFC, 0xFA, 0xCD, 0xD9, 0xF9, 0x47, 0xD7, 0x13, 0x59, 0x40, 0xC9, 0xBA, 0x20, 0x03, 0x08, 0x01, 0x2A, 0x80, 0x2E, 0x60, 0xB6, 0xDB, 0xE0, 0x71, 0x40, 0x0A, 0xB0, 0x85, 0x07, 0xF0, 0x67, 0x33, 0xD9, 0xAE, 0xF3, 0xBD, 0x87, 0xC2, 0xD8, 0xE2, 0x86, 0xD9, 0xC8, 0xB8, 0x22, 0x1E, 0xE4, 0xBB, 0x1B, 0x47, 0xAC, 0x9E, 0x92, 0x5D, 0xFD, 0xDB, 0xF5, 0x7C, 0xE2, 0x9F, 0x79, 0xDE, 0xEA, 0x3A, 0x1C, 0xCB, 0xF6, 0x44, 0x83, 0x4F, 0x3C, 0x3F, 0x4E, 0x00, 0xF2, 0xE8, 0xA8, 0xE0, 0x93, 0x07, 0x83, 0x4C, 0xF7, 0x16, 0x5F, 0x74, 0x09, 0xFB, 0xC6, 0x4D, 0x03, 0x60, 0x17, 0x78, 0xF5, 0xC5, 0xC1, 0xC3, 0x92, 0x37, 0x6A, 0xB7, 0xDE, 0x5F, 0x04, 0x61, 0xD8, 0x28, 0x1A, 0xA8, 0x62, 0x00, 0x1A, 0x78, 0x5A, 0xFB, 0x2A, 0x10, 0x0E, 0xE4, 0x01, 0x22, 0x00, 0x27, 0x0E, 0xC0, 0x40, 0x8B, 0x26, 0x8D, 0xA6, 0xDB, 0x07, 0x4A, 0x37, 0xE0, 0xE5, 0xDB, 0x39, 0xC7, 0xB6, 0x07, 0xAA, 0xE2, 0xCC, 0x13, 0x8D, 0x2F, 0x56, 0xB6, 0xF7, 0xD2, 0xE1, 0xD9, 0x8C, 0xCD, 0x41, 0xAF, 0xB6, 0xDA, 0xC5, 0x83, 0x94, 0xB1, 0x2E, 0x89, 0x9B, 0x79, 0xE3, 0x53, 0xED, 0xCA, 0x4A, 0x51, 0x3E, 0xD6, 0xBC, 0x4D, 0xF1, 0xD3, 0xBE, 0x92, 0x30, 0xAF, 0x10, 0xFB, 0xEB, 0xAC, 0x6E, 0x52, 0x67, 0x24, 0x70, 0x7F, 0xCF, 0x01, 0x16, 0x4E, 0xE5, 0x26, 0x7D, 0xB4, 0xBE, 0xCD, 0x78, 0xFD, 0xF1, 0x17, 0x33, 0x16, 0x77, 0x3E, 0x21, 0xB9, 0x53, 0x40, 0x9F, 0xB5, 0xEB, 0x07, 0xC7, 0xF1, 0xB3, 0x2A, 0x20, 0x05, 0x80, 0xDB, 0x7F, 0xDE, 0x91, 0x66, 0x7F, 0xB3, 0xB3, 0xFE, 0x3C, 0x03, 0xB3, 0x5D, 0x58, 0xC6, 0x11, 0x93, 0x31, 0x59, 0xD7, 0x3E, 0x0B, 0x52, 0xFC, 0x9F, 0x3E, 0x8D, 0xDB, 0xCD, 0x80, 0x66, 0x09, 0x2C, 0xFF, 0xE1, 0x7B, 0xBD, 0xD5, 0x8C, 0xC5, 0xB1, 0x71, 0x9D, 0xB3, 0xC9, 0x3A, 0x33, 0x08, 0xB6, 0x5F, 0x78, 0x14, 0x50, 0xC6, 0x78, 0x1B, 0x1B, 0x6B, 0x01, 0xA5, 0x80, 0x1E, 0xE0, 0x0C, 0x60, 0x07, 0x60, 0xCE, 0x80, 0xA2, 0xB7, 0x1D, 0xCE, 0xEF, 0xB1, 0x3B, 0x4C, 0xAC, 0x7B, 0x3B, 0x77, 0x3E, 0xA6, 0xE2, 0x67, 0x89, 0xDD, 0x0F, 0xED, 0xCB, 0x12, 0x98, 0x5C, 0x79, 0x69, 0x05, 0xBC, 0x81, 0x3C, 0x40, 0x39, 0x30, 0x8A, 0xE4, 0x77, 0x35, 0xC0, 0x02, 0xC8, 0xA0, 0xCD, 0x9C, 0x36, 0x83, 0x6E, 0x8E, 0x05, 0x6A, 0x21, 0x78, 0xD8, 0xDC, 0x1E, 0xA2, 0x7A, 0x12, 0xB0, 0x8D, 0x1A, 0xC8, 0xFC, 0xDC, 0x8E, 0x72, 0x87, 0xA5, 0xCE, 0x53, 0xF7, 0xBB, 0x6B, 0xAD, 0xFB, 0x06, 0xA2, 0x18, 0xC1, 0xF0, 0xED, 0xBE, 0x53, 0x0C, 0x98, 0xE1, 0x67, 0xC9, 0x48, 0x4B, 0x2D, 0x18, 0x6F, 0xDB, 0x37, 0x8F, 0x02, 0xD6, 0x80, 0xD8, 0x22, 0x00, 0x73, 0xC0, 0x13, 0xFF, 0x69, 0xAE, 0x3E, 0xB6, 0x2D, 0xF1, 0xE2, 0xBC, 0x6D, 0xEF, 0x6A, 0x63, 0x5C, 0xBF, 0xC8, 0x0E, 0x30, 0xB9, 0x01, 0xAC, 0x00, 0x4A, 0x61, 0xD6, 0x23, 0x80, 0x24, 0xA0, 0x03, 0xD8, 0x22, 0x1A, 0xE8, 0xDA, 0xA8, 0x96, 0x02, 0x36, 0xB4, 0x59, 0xD0, 0x66, 0x3C, 0x94, 0x42, 0x5A, 0xA3, 0x0D, 0x59, 0x3A, 0x11, 0x88, 0x97, 0x9A, 0xFF, 0x60, 0x91, 0x18, 0xFA, 0x6D, 0x6F, 0xF7, 0x61, 0x49, 0xA0, 0xF2, 0xF1, 0x3B, 0xEC, 0x24, 0x61, 0x23, 0x52, 0x79, 0x17, 0x83, 0x4D, 0x11, 0xB6, 0x79, 0x2A, 0xEC, 0xDA, 0x81, 0x33, 0x80, 0xEC, 0x2F, 0x9C, 0xC0, 0x9B, 0x32, 0x40, 0x1C, 0x40, 0x65, 0x71, 0x00, 0x33, 0xC0, 0x1D, 0x98, 0xDA, 0x75, 0xE6, 0x4A, 0x5F, 0x41, 0x91, 0xD9, 0x06, 0xD3, 0x36, 0xE0, 0x69, 0x80, 0x2B, 0x50, 0x6B, 0x79, 0x11, 0xC0, 0x1A, 0x08, 0x01, 0x72, 0x51, 0x0A, 0x8C, 0xEE, 0xB6, 0xE1, 0x80, 0x06, 0x10, 0x4A, 0x9B, 0xE5, 0x65, 0x33, 0xF7, 0xE4, 0x01, 0x61, 0xD3, 0x10, 0x1C, 0x7F, 0xC4, 0x99, 0x1F, 0x2C, 0x7C, 0x93, 0x27, 0x8A, 0x0D, 0xAE, 0x91, 0xA2, 0x00, 0xB4, 0x3C, 0xEA, 0x78, 0xBB, 0xD0, 0x33, 0x16, 0x2E, 0xB0, 0x44, 0x3B, 0xA0, 0x8A, 0x87, 0xCA, 0xC0, 0x90, 0xB2, 0xAC, 0x0C, 0x9F, 0x62, 0xAD, 0x24, 0xBE, 0xF1, 0xEE, 0x81, 0x09, 0xFC, 0x00, 0x1A, 0x0B, 0x05, 0xEC, 0xDB, 0xEE, 0xDF, 0x61, 0xA5, 0x84, 0x41, 0x18, 0x76, 0xDB, 0x6F, 0x6B, 0x4F, 0x5C, 0x30, 0x3F, 0xCD, 0xED, 0xDD, 0x80, 0xCA, 0xED, 0x1C, 0x75, 0x16, 0x05, 0x48, 0x02, 0x1A, 0x80, 0x2B, 0x90, 0x06, 0x94, 0x03, 0x13, 0xB4, 0x59, 0x61, 0x78, 0xBB, 0xFD, 0xAB, 0xB3, 0xEE, 0x48, 0x47, 0xA3, 0x54, 0x48, 0x94, 0xC4, 0x0F, 0xE2, 0x86, 0xC3, 0xEA, 0xFC, 0xE6, 0xED, 0xB1, 0x71, 0x5E, 0x9E, 0x3E, 0x8A, 0x30, 0xF5, 0x76, 0x58, 0xA9, 0xBF, 0xF8, 0x8E, 0x2D, 0x1C, 0x38, 0x01, 0xC3, 0xBA, 0xDD, 0x5A, 0xBD, 0xD6, 0x40, 0xDF, 0x3E, 0xA5, 0x2D, 0xB4, 0xC5, 0x89, 0xF4, 0xEA, 0x25, 0x9D, 0xE7, 0x76, 0xC8, 0xF9, 0x00, 0x71, 0xDE, 0x02, 0x1E, 0x91, 0x47, 0x72, 0xEF, 0x30, 0xCD, 0xF8, 0xE3, 0x2E, 0x63, 0x57, 0x04, 0x31, 0x20, 0x59, 0xBD, 0x1D, 0xC0, 0x18, 0xD0, 0x05, 0xA4, 0x00, 0xCC, 0xAF, 0xEB, 0x7D, 0xF3, 0x14, 0xF0, 0x67, 0xB5, 0xFE, 0xCD, 0xFF, 0x16, 0xB4, 0xB6, 0x74, 0xB9, 0x85, 0xAE, 0x50, 0x13, 0x07, 0x3B, 0x61, 0x5B, 0x14, 0xFF, 0x07, 0x97, 0x87, 0x31, 0x88, 0xF7, 0x91, 0x07, 0x1B, 0x36, 0x5A, 0xBF, 0xBB, 0xBF, 0xB8, 0x00, 0xA6, 0x77, 0x13, 0x80, 0x11, 0xA0, 0xCF, 0xE2, 0xEA, 0x5E, 0x14, 0x7F, 0xFD, 0xA7, 0xF4, 0x35, 0x49, 0x3C, 0xB2, 0x62, 0x93, 0x40, 0x06, 0xA0, 0x0D, 0x98, 0xBD, 0xD2, 0xDE, 0x70, 0x7D, 0x30, 0x03, 0xFF, 0x76, 0x09, 0x54, 0xDD, 0x49, 0xC7, 0x16, 0xB7, 0x36, 0xAB, 0x0D, 0x50, 0xBD, 0x30, 0x20, 0x14, 0x60, 0x59, 0xCB, 0xEC, 0xA7, 0x53, 0x40, 0x3B, 0xAD, 0xB6, 0xEA, 0x43, 0xD9, 0x3F, 0xFD, 0xF8, 0xD4, 0xBC, 0xA3, 0x52, 0x0A, 0xAB, 0x45, 0xDA, 0x06, 0xE6, 0x12, 0xA1, 0x47, 0x24, 0xC6, 0x5B, 0xD2, 0xE7, 0x9D, 0xDF, 0x10, 0xA8, 0xCE, 0xA7, 0x08, 0x6A, 0x61, 0x02, 0x3C, 0x31, 0x98, 0x45, 0xD6, 0x82, 0x9E, 0x70, 0x5E, 0xF8, 0x65, 0xAD, 0x27, 0xAF, 0x96, 0x97, 0x3D, 0x50, 0x07, 0x9E, 0xA8, 0x61, 0xEE, 0xA7, 0x7E, 0xA3, 0x35, 0x38, 0x47, 0x50, 0xFE, 0xE5, 0x92, 0x95, 0x00, 0x5E, 0x41, 0xBE, 0x8C, 0xF5, 0x09, 0x18, 0xC0, 0x5A, 0x03, 0x75, 0x40, 0x8A, 0x6E, 0x50, 0x20, 0x0A, 0xB0, 0x03, 0xB8, 0xED, 0x9B, 0xB5, 0x66, 0x93, 0x6D, 0x8E, 0x69, 0xFD, 0xAF, 0xB6, 0xE4, 0xA0, 0x15, 0xAD, 0x06, 0x91, 0xBC, 0x2C, 0x70, 0xB4, 0xF6, 0xFC, 0x7C, 0x7E, 0x47, 0x02, 0xBD, 0x2F, 0x1C, 0x83, 0x6D, 0xFE, 0xB3, 0xC9, 0xD4, 0xF8, 0x47, 0x83, 0x6C, 0x80, 0xEC, 0xBB, 0xBB, 0xF8, 0x14, 0x90, 0x02, 0x78, 0xEE, 0x2F, 0x30, 0xCE, 0x12, 0x77, 0x1D, 0x9D, 0xCA, 0x1D, 0xED, 0x74, 0xBB, 0xC5, 0xCE, 0xCA, 0x81, 0xBE, 0xA2, 0x2E, 0x72, 0x9E, 0xF1, 0xE1, 0xB9, 0x5F, 0x9B, 0x22, 0x48, 0xB6, 0x0E, 0x87, 0x45, 0xD4, 0x5E, 0xF0, 0x06, 0xA0, 0x87, 0x40, 0x7B, 0x41, 0xF5, 0xCE, 0x02, 0x62, 0x00, 0x3B, 0x00, 0x15, 0x2F, 0x4C, 0x69, 0x35, 0xF9, 0x6D, 0xC3, 0x5A, 0xFD, 0xAF, 0x06, 0xAA, 0x56, 0x2D, 0xB8, 0x19, 0xE0, 0x7A, 0xAA, 0xC8, 0x0D, 0x55, 0xCC, 0x1B, 0x19, 0x74, 0x30, 0xA8, 0x63, 0xF4, 0xA5, 0x7D, 0xEA, 0x09, 0xF2, 0x0E, 0x1C, 0x9F, 0xF3, 0xD1, 0x78, 0x5B, 0x68, 0xDF, 0x7A, 0xEE, 0x9E, 0x80, 0x2E, 0x68, 0xD8, 0x3E, 0xB7, 0x6B, 0x57, 0xED, 0x6E, 0x1D, 0x92, 0x07, 0xE0, 0x22, 0xC0, 0xE2, 0xDB, 0x27, 0xDC, 0x72, 0xA9, 0x03, 0xE3, 0x54, 0xCE, 0x02, 0x84, 0x5B, 0x68, 0x39, 0x0A, 0xA8, 0xB9, 0xA3, 0x53, 0xAC, 0xCB, 0xD2, 0x5E, 0x08, 0x25, 0x4C, 0x81, 0x68, 0xC0, 0x14, 0x70, 0xBE, 0x12, 0xB4, 0x9A, 0xEE, 0x06, 0x2E, 0xBF, 0x9A, 0x63, 0x1D, 0xE8, 0x0F, 0x65, 0xE2, 0x8E, 0x1E, 0x2A, 0x74, 0x3A, 0x43, 0xEB, 0x67, 0x1A, 0x93, 0x21, 0xF2, 0x1F, 0x54, 0x30, 0xBE, 0xCD, 0xF3, 0xFA, 0xAE, 0xC2, 0x48, 0x2A, 0x0F, 0x3A, 0xE0, 0x8B, 0x43, 0x1B, 0x0A, 0x20, 0x75, 0x0B, 0x3C, 0xDE, 0xEA, 0xEE, 0xFD, 0x68, 0x0D, 0x56, 0xE1, 0x61, 0x2B, 0x60, 0x06, 0x08, 0x83, 0x79, 0xD7, 0x7F, 0x13, 0x69, 0x18, 0x6F, 0x4F, 0xA1, 0xF8, 0xD3, 0x30, 0xD9, 0xC1, 0x52, 0x1C, 0x25, 0x01, 0xD4, 0x73, 0xD5, 0x03, 0x8A, 0xEA, 0x56, 0x07, 0x38, 0x75, 0x6F, 0x0E, 0x59, 0x80, 0x0F, 0xB0, 0xAE, 0x90, 0x77, 0xAC, 0xD9, 0x2F, 0xF6, 0x99, 0xA6, 0xFF, 0xE6, 0x77, 0x4D, 0x0E, 0x2E, 0x6C, 0x70, 0x01, 0x96, 0x40, 0xD2, 0x5E, 0x06, 0x8E, 0x9F, 0x44, 0x32, 0x85, 0x4D, 0x5D, 0xCD, 0xF3, 0xDC, 0xBF, 0x0B, 0x9B, 0xF5, 0xBD, 0x11, 0xA4, 0x02, 0x9E, 0x77, 0x2B, 0xC0, 0x1E, 0x20, 0x03, 0x08, 0x03, 0xBA, 0xEE, 0x7A, 0x4E, 0xD9, 0x4F, 0x7E, 0x09, 0x77, 0xE2, 0x7C, 0x08, 0x04, 0xD0, 0xFB, 0xEB, 0xC7, 0x19, 0xD1, 0x5F, 0x23, 0x72, 0xDB, 0x0D, 0xE6, 0x61, 0x7C, 0xE4, 0x9E, 0x1F, 0x0F, 0xE8, 0x22, 0xE2, 0xAE, 0x6F, 0xC9, 0x04, 0xA2, 0x01, 0xA3, 0x1F, 0x6A, 0x80, 0x3C, 0x40, 0x3D, 0xAA, 0x51, 0x34, 0x9B, 0xE3, 0x62, 0x7F, 0xE6, 0x5F, 0x3B, 0x74, 0x5D, 0x6B, 0xBB, 0x71, 0xA3, 0x12, 0x26, 0x57, 0x64, 0x18, 0x97, 0x85, 0x44, 0x6E, 0x47, 0x54, 0xE6, 0x55, 0x6D, 0xEC, 0xF3, 0x1D, 0x6C, 0x74, 0x13, 0xF1, 0x80, 0x50, 0x80, 0xF5, 0x9D, 0xE9, 0xE1, 0x9F, 0x06, 0x0C, 0xB1, 0x60, 0xE1, 0x28, 0x87, 0xD7, 0xD3, 0x1C, 0x48, 0x6E, 0x8D, 0x4E, 0xF1, 0xBB, 0x91, 0x48, 0xF1, 0x53, 0xBE, 0x43, 0x0F, 0x57, 0xB2, 0xDD, 0x29, 0xAF, 0xC6, 0x1A, 0xB8, 0x7A, 0xDE, 0x35, 0x51, 0x7E, 0xAF, 0x53, 0x6A, 0x40, 0x1D, 0x20, 0x1D, 0x60, 0x95, 0xD9, 0x2C, 0x72, 0xF1, 0x88, 0x3F, 0x1B, 0xAD, 0x16, 0xDB, 0x35, 0x5F, 0x1E, 0x9D, 0xC8, 0xFA, 0x49, 0xE2, 0x17, 0x62, 0xA0, 0x90, 0x08, 0xD3, 0x3E, 0xFA, 0x8B, 0x69, 0xAB, 0x2A, 0xF4, 0x00, 0xD4, 0x69, 0xAD, 0x4F, 0xBC, 0x3D, 0xD6, 0x6A, 0x7E, 0xCF, 0x38, 0x53, 0x40, 0x3F, 0xCB, 0x9C, 0x32, 0x63, 0x23, 0x01, 0x37, 0x20, 0xAF, 0x86, 0x98, 0xF9, 0xD8, 0xDE, 0x69, 0x58, 0x01, 0xE4, 0x00, 0xE7, 0x07, 0x5B, 0x3B, 0xF9, 0xF3, 0x66, 0xAD, 0xD5, 0xD8, 0x9C, 0xE4, 0x59, 0xA0, 0xB8, 0x27, 0xEA, 0x01, 0xD2, 0x80, 0x39, 0xB7, 0xB0, 0xCF, 0x9C, 0x5B, 0x00, 0x51, 0x6A, 0x1F, 0x0E, 0x90, 0xF9, 0x29, 0x75, 0xE3, 0xA6, 0xF2, 0x8C, 0xB5, 0x5C, 0x07, 0x79, 0x6E, 0xB2, 0xA0, 0x6E, 0xAA, 0xA9, 0xC1, 0xA3, 0x90, 0xBA, 0x1B, 0x87, 0x6F, 0x97, 0x7F, 0x5B, 0xC7, 0xEB, 0x7F, 0xA8, 0xEF, 0x3F, 0x7B, 0x21, 0x43, 0x2B, 0xCE, 0x90, 0xFE, 0x00, 0xD9, 0x77, 0x7B, 0x81, 0xF4, 0x7D, 0xA5, 0xA8, 0x88, 0xBE, 0x88, 0x5B, 0xE3, 0xCB, 0x29, 0x67, 0xC8, 0x9F, 0x25, 0x20, 0x9C, 0x68, 0x09, 0xE4, 0xFE, 0xFA, 0xD1, 0xB7, 0x8A, 0x94, 0x59, 0xCC, 0x7F, 0x1D, 0xD0, 0x8C, 0x15, 0x47, 0xB9, 0x01, 0xA9, 0x02, 0x18, 0x7B, 0x3A, 0x8B, 0x74, 0x60, 0x62, 0x61, 0x40, 0x1F, 0x20, 0x06, 0x70, 0xBD, 0x1B, 0x02, 0x88, 0xD1, 0x68, 0xB5, 0xA2, 0x7F, 0x85, 0xEB, 0x47, 0xD4, 0xEF, 0xA2, 0x92, 0x11, 0xB0, 0xEB, 0x96, 0x46, 0xE9, 0x24, 0x6C, 0xB7, 0x13, 0x5B, 0x73, 0xD8, 0x7B, 0xE5, 0x8E, 0xE6, 0x31, 0x4F, 0x45, 0x1E, 0x05, 0x2E, 0x46, 0x3C, 0x1A, 0x48, 0xBB, 0x4B, 0xEC, 0xDA, 0xEF, 0x1C, 0x00, 0x55, 0x80, 0xEB, 0xF8, 0x61, 0x4C, 0x47, 0x81, 0x60, 0xAA, 0x45, 0x7F, 0x3A, 0x0A, 0x0C, 0x20, 0x57, 0xAB, 0xAA, 0x7A, 0x54, 0x83, 0xDA, 0x59, 0x8B, 0xB5, 0x9E, 0xDB, 0x5C, 0x27, 0x6D, 0xD3, 0x6D, 0xB9, 0x99, 0x85, 0xBD, 0x0E, 0xA3, 0x45, 0xC9, 0x5E, 0xFD, 0x72, 0x31, 0x77, 0xC2, 0x5F, 0x2B, 0x50, 0xFC, 0xF4, 0xD4, 0x38, 0xD0, 0x6A, 0xBD, 0x42, 0x26, 0x09, 0xAF, 0xC0, 0x6F, 0x2E, 0x06, 0x12, 0xD8, 0xA4, 0xD6, 0x53, 0x54, 0xAC, 0x9B, 0x42, 0x19, 0x0B, 0xBC, 0x08, 0x72, 0xB7, 0xE6, 0x92, 0xAB, 0xD6, 0xD8, 0x1E, 0x01, 0x02, 0xE5, 0x3A, 0x7C, 0x1C, 0x10, 0x85, 0x03, 0x69, 0xD7, 0x68, 0xAA, 0xF0, 0x66, 0x00, 0xCC, 0x18, 0xB2, 0xBC, 0xD6, 0x68, 0xDC, 0xCC, 0x80, 0x4B, 0x0B, 0x4D, 0xF0, 0xE9, 0x2E, 0xFC, 0x04, 0xEA, 0xAA, 0x41, 0xDF, 0x3A, 0xE4, 0x47, 0xFE, 0xD1, 0xF7, 0x53, 0x3C, 0x62, 0x59, 0xA1, 0x77, 0xF5, 0x8E, 0xAF, 0x7D, 0x45, 0x00, 0xEF, 0x45, 0x00, 0xBA, 0x43, 0x75, 0x16, 0x15, 0xC0, 0xE0, 0x17, 0xDE, 0xCD, 0x60, 0x70, 0xEA, 0x73, 0x85, 0xEB, 0xA0, 0xA0, 0x48, 0x34, 0x0E, 0x87, 0x47, 0x8B, 0xFC, 0x90, 0x5E, 0xBB, 0x3D, 0xE7, 0xB6, 0x94, 0x30, 0xF6, 0x28, 0xB8, 0x24, 0xD1, 0x5D, 0xDE, 0x45, 0x59, 0xFC, 0xAF, 0xE9, 0x58, 0xDE, 0xB1, 0x5E, 0xEF, 0x5B, 0x12, 0xAD, 0x0E, 0x20, 0x09, 0x50, 0x4A, 0x95, 0xBF, 0x60, 0xB5, 0xE0, 0xBA, 0xFD, 0x89, 0x7E, 0x47, 0x00, 0x52, 0x77, 0x20, 0xCA, 0xE7, 0xAD, 0x60, 0xA8, 0xF5, 0xEB, 0x9F, 0xA7, 0xC2, 0xC3, 0x6C, 0xB3, 0xF1, 0x03, 0x88, 0xF5, 0xC1, 0x9F, 0x45, 0x24, 0xD0, 0x8B, 0x91, 0xFB, 0x53, 0xF5, 0x8D, 0xA1, 0xF2, 0x16, 0x8D, 0xA6, 0x7F, 0xB1, 0x02, 0x8B, 0x57, 0x5B, 0x56, 0x98, 0xCB, 0x01, 0x47, 0x44, 0xB3, 0x98, 0x63, 0x10, 0x6B, 0x35, 0xFD, 0x87, 0xF5, 0xE0, 0xD6, 0xD3, 0xE1, 0x21, 0xD3, 0x37, 0x56, 0xC0, 0xAA, 0x08, 0xCA, 0x06, 0x59, 0xBC, 0x12, 0x48, 0x67, 0xDD, 0xD7, 0xFD, 0x57, 0xAF, 0x15, 0x80, 0x38, 0xC0, 0x1C, 0xFB, 0x88, 0xDB, 0x5D, 0xAE, 0x9F, 0x52, 0x30, 0x69, 0xC0, 0x84, 0x0A, 0x58, 0x6F, 0x15, 0xC6, 0xE0, 0x13, 0xB3, 0xEA, 0xC3, 0x36, 0x4F, 0x79, 0x2B, 0xB4, 0x02, 0x3E, 0x03, 0x9C, 0xE5, 0x07, 0x68, 0x5F, 0x5F, 0x9A, 0x00, 0x96, 0x80, 0x2F, 0xA2, 0x81, 0x32, 0x60, 0xCE, 0x82, 0x69, 0xE3, 0x45, 0x9B, 0xC9, 0xDA, 0x8C, 0x5E, 0xFA, 0x5A, 0xB5, 0x46, 0x45, 0x70, 0xC8, 0x02, 0x2E, 0x78, 0xDB, 0x25, 0x75, 0x58, 0x4B, 0x6F, 0xA8, 0xF3, 0xB9, 0x5A, 0xBF, 0xC9, 0x5F, 0x4B, 0x43, 0xEA, 0xBF, 0x31, 0x83, 0xA4, 0xF7, 0x5B, 0xB3, 0x00, 0x8E, 0x85, 0x3E, 0x16, 0xB0, 0x2B, 0x15, 0xCD, 0xAC, 0x17, 0xB5, 0x0F, 0x9F, 0x68, 0x37, 0x20, 0x83, 0x87, 0x69, 0x40, 0x28, 0x50, 0x0E, 0xCC, 0x61, 0xEC, 0x7B, 0x6D, 0xB7, 0xA5, 0x1D, 0xAC, 0xB1, 0x52, 0x56, 0x32, 0xD0, 0xBD, 0xE4, 0x9B, 0x0A, 0x6D, 0x40, 0x27, 0xFC, 0x4A, 0x66, 0x40, 0x16, 0xD0, 0x01, 0x63, 0x9F, 0x03, 0x48, 0x02, 0xE6, 0x40, 0x0C, 0x50, 0xB1, 0xF2, 0x48, 0x46, 0xA3, 0x21, 0x25, 0x4D, 0x7B, 0xD6, 0xB9, 0x55, 0x88, 0xF9, 0x94, 0xC0, 0xA5, 0x52, 0xEB, 0x4C, 0xEB, 0x5E, 0x87, 0x59, 0x61, 0xBB, 0xC6, 0xF6, 0x69, 0x5F, 0xB5, 0x2B, 0xAF, 0x57, 0xD6, 0x1C, 0xEF, 0xEC, 0x21, 0x5A, 0x80, 0x58, 0x6B, 0xD7, 0xE3, 0x76, 0xD9, 0x99, 0x3B, 0x80, 0x25, 0xD0, 0x7C, 0xC5, 0xD8, 0xC4, 0x12, 0x96, 0x64, 0xD9, 0xB0, 0x2B, 0x70, 0x72, 0xB1, 0x81, 0xCB, 0x47, 0xE6, 0x6E, 0xCD, 0x4B, 0xC5, 0x3F, 0xAA, 0x2C, 0x31, 0x46, 0xE5, 0x6B, 0xB4, 0x53, 0x6B, 0xB4, 0x00, 0xE6, 0x07, 0x6C, 0x51, 0xB0, 0x8F, 0x00, 0xBE, 0x08, 0x5D, 0xE4, 0x62, 0x80, 0x0C, 0xA0, 0xD7, 0x68, 0x56, 0x34, 0x9A, 0x6D, 0xE5, 0x3E, 0xEA, 0x7D, 0x34, 0x06, 0xC1, 0x8C, 0xEE, 0x8D, 0xDD, 0x2A, 0xBC, 0x85, 0x47, 0x30, 0xCB, 0xA4, 0xB1, 0x6E, 0x58, 0xFE, 0x46, 0x5A, 0xBD, 0xC7, 0x5A, 0x7E, 0x2A, 0xF6, 0x12, 0xD6, 0xA7, 0xD4, 0xCE, 0x39, 0x7A, 0xF7, 0x93, 0xC9, 0x46, 0x95, 0xB8, 0xEC, 0x50, 0xA3, 0x8B, 0x93, 0x8D, 0x71, 0x4B, 0xE7, 0x2F, 0x00, 0x2C, 0xE6, 0x8B, 0x01, 0x8E, 0xE3, 0x95, 0x0A, 0xC0, 0x05, 0xE8, 0x9D, 0xF8, 0xBE, 0x99, 0xED, 0x4F, 0x15, 0xCF, 0x1A, 0x04, 0x98, 0xC7, 0x41, 0x1B, 0xB1, 0x2E, 0xD9, 0x01, 0xAA, 0xEF, 0x30, 0x5D, 0x2E, 0x2A, 0x17, 0xB1, 0x18, 0xA0, 0x0D, 0x98, 0xC6, 0x8C, 0x0F, 0xA3, 0xCD, 0x1C, 0xFF, 0xE0, 0xAC, 0xC6, 0x71, 0x44, 0xF2, 0x52, 0x64, 0x93, 0x98, 0x12, 0xDF, 0xDD, 0xB6, 0x46, 0x6A, 0xBB, 0xDB, 0x0C, 0xF2, 0x87, 0xFC, 0x7C, 0xB4, 0x96, 0xE3, 0x3C, 0x4D, 0x53, 0x99, 0xCA, 0x02, 0x8B, 0xC8, 0x82, 0x25, 0xE5, 0xBD, 0xB3, 0x2C, 0x29, 0x2D, 0x28, 0x6B, 0x5E, 0x05, 0xA8, 0xB5, 0xCC, 0x74, 0x0A, 0xE5, 0x0C, 0xA4, 0xD0, 0xE0, 0xD3, 0x47, 0x04, 0x50, 0x6A, 0x02, 0x2E, 0x7A, 0x5E, 0x71, 0xBE, 0x79, 0x0A, 0xCB, 0x14, 0x1E, 0x76, 0xC0, 0x65, 0x1D, 0xBC, 0x30, 0xCC, 0x15, 0x9F, 0x99, 0xF5, 0x94, 0xB3, 0x36, 0x4B, 0xCE, 0x22, 0x00, 0xCE, 0xEA, 0x39, 0x40, 0xF3, 0xA1, 0x02, 0x2D, 0x34, 0x1A, 0x83, 0x05, 0x3B, 0xFF, 0xD3, 0x10, 0xDA, 0xEE, 0x5D, 0x30, 0xBC, 0x51, 0x81, 0x71, 0x76, 0xF4, 0xF9, 0x6C, 0xD4, 0x25, 0xAE, 0x76, 0x22, 0xFD, 0xA9, 0xCD, 0x56, 0x1E, 0xB1, 0xC5, 0xD6, 0x14, 0x02, 0x18, 0xF5, 0x59, 0x15, 0x06, 0xA5, 0x10, 0x28, 0xD5, 0xC8, 0x6B, 0x91, 0x8C, 0x00, 0x7E, 0xA4, 0xA5, 0x8F, 0xEF, 0x43, 0x05, 0x24, 0x01, 0x1B, 0x20, 0xE2, 0x6F, 0x7B, 0x55, 0x7D, 0xCE, 0x0F, 0xC5, 0x3A, 0xDA, 0x8D, 0x39, 0xA4, 0xC1, 0x3E, 0xD9, 0xFB, 0xAD, 0xF3, 0x5E, 0xD2, 0x5C, 0x80, 0x96, 0xCF, 0x5A, 0x16, 0x80, 0x19, 0x10, 0x8B, 0x2A, 0x60, 0x36, 0x2E, 0x24, 0x8F, 0xD1, 0x12, 0xF7, 0x36, 0xDD, 0x93, 0x86, 0x0A, 0x22, 0x4F, 0x19, 0xD8, 0x07, 0xC6, 0x7F, 0xE8, 0x94, 0xCD, 0x2E, 0xF4, 0x75, 0x66, 0xEA, 0xDB, 0xB8, 0xA6, 0xED, 0xA3, 0xEA, 0xED, 0xD4, 0x6E, 0x65, 0x6A, 0x45, 0x1B, 0x15, 0x14, 0xD6, 0x30, 0x01, 0x50, 0x85, 0xDC, 0x1A, 0x10, 0x03, 0x86, 0x66, 0x62, 0xA9, 0xB5, 0x02, 0x93, 0x80, 0x2D, 0x8E, 0xAF, 0x1F, 0x42, 0x81, 0xDA, 0x87, 0xCA, 0x82, 0xED, 0x61, 0x54, 0xFA, 0xD5, 0x39, 0x74, 0x00, 0x4A, 0x73, 0x1B, 0x9E, 0x28, 0x60, 0xB6, 0x60, 0xC5, 0x1A, 0xE0, 0xA6, 0x7B, 0x1A, 0x90, 0x01, 0x54, 0x17, 0xB6, 0x68, 0xC0, 0x1D, 0x18, 0xA7, 0xD1, 0x0A, 0x36, 0xF7, 0xF8, 0x37, 0xBF, 0x9B, 0xBB, 0xFF, 0x9B, 0x03, 0xB9, 0x43, 0xD9, 0xDB, 0x14, 0x5C, 0x04, 0x8E, 0x06, 0x72, 0x3E, 0x28, 0x0F, 0xB0, 0xBA, 0xD2, 0x96, 0x53, 0x3F, 0x02, 0x61, 0xD1, 0x77, 0x3B, 0x46, 0x5F, 0xD0, 0x83, 0x3B, 0x05, 0xA4, 0x03, 0xA6, 0x80, 0x24, 0x10, 0xBA, 0x6F, 0x0E, 0x30, 0x0B, 0xF5, 0xBB, 0x8D, 0x7D, 0xF5, 0xED, 0x30, 0xAF, 0xDA, 0x9F, 0xB1, 0xD2, 0x83, 0x2A, 0x1D, 0x40, 0x3C, 0xA9, 0x8E, 0x36, 0xB7, 0xAE, 0xEB, 0xEC, 0x84, 0xF6, 0x8F, 0x72, 0x4E, 0x73, 0x0B, 0x8F, 0x85, 0x7E, 0x0A, 0x54, 0x07, 0x70, 0x03, 0x76, 0x55, 0x79, 0x8F, 0x69, 0xFD, 0xCF, 0x05, 0xFD, 0xB8, 0x7A, 0x70, 0xA8, 0x6D, 0x47, 0x9B, 0x68, 0xDD, 0x42, 0x4C, 0x4A, 0x37, 0x41, 0x3A, 0xA1, 0x36, 0x8F, 0xDB, 0xE9, 0x4D, 0xFB, 0x84, 0x0B, 0xD8, 0xA5, 0x94, 0xDF, 0x3E, 0x81, 0xFE, 0x74, 0x13, 0xD1, 0xDE, 0x4B, 0xC3, 0x00, 0x71, 0x3E, 0x1E, 0xF2, 0xB5, 0xB6, 0x04, 0x90, 0x0A, 0x9C, 0xB5, 0xF6, 0xA3, 0x0E, 0x48, 0xF4, 0xE2, 0xD2, 0x5E, 0x8F, 0x47, 0xBE, 0xF9, 0x49, 0xC3, 0xA9, 0x78, 0xAF, 0x6F, 0xFD, 0xE7, 0x97, 0xA5, 0x17, 0xC3, 0x80, 0x0E, 0x98, 0xD2, 0x13, 0xE8, 0xB8, 0x51, 0x72, 0xFF, 0x4C, 0x17, 0x2E, 0x6C, 0x09, 0x44, 0xAB, 0xCD, 0x3F, 0xDB, 0xD1, 0xD5, 0x05, 0x79, 0xA6, 0xAC, 0x47, 0x84, 0x37, 0xA3, 0xD7, 0xCF, 0xEE, 0xBF, 0xAC, 0x7D, 0x13, 0x45, 0x01, 0x04, 0xDC, 0x43, 0x39, 0xDF, 0xC6, 0xD0, 0xB2, 0x46, 0x30, 0xFA, 0x77, 0x28, 0x1E, 0xB9, 0x08, 0xB9, 0x65, 0xCA, 0xF4, 0x7C, 0x94, 0x0B, 0x05, 0xB8, 0xFD, 0x94, 0xF9, 0x7C, 0xB2, 0xB5, 0xA1, 0x15, 0x70, 0x0C, 0x10, 0x59, 0x28, 0x40, 0x75, 0x34, 0x97, 0xC3, 0xAB, 0x2C, 0xAF, 0x20, 0x6F, 0xD6, 0x42, 0x3E, 0x27, 0x67, 0x2D, 0x60, 0x94, 0x07, 0xE8, 0x3D, 0x7C, 0x2E, 0xB2, 0x81, 0x12, 0x20, 0x0A, 0xB0, 0x85, 0x2A, 0x60, 0x54, 0x9E, 0xE0, 0x58, 0xDB, 0x83, 0x5E, 0x55, 0xFD, 0x9B, 0xC0, 0xEE, 0x58, 0xB9, 0x05, 0xDA, 0xE7, 0xF1, 0xC9, 0x79, 0x2B, 0x84, 0x00, 0x2B, 0x7F, 0xDF, 0x21, 0x0C, 0x56, 0xB3, 0xAF, 0xD5, 0x0E, 0x75, 0x74, 0x18, 0x2A, 0xCA, 0xBB, 0x71, 0xAB, 0x3D, 0x45, 0x51, 0x00, 0x5B, 0x77, 0x85, 0x03, 0x72, 0x16, 0x05, 0xA4, 0x03, 0xDD, 0x54, 0x43, 0xE4, 0x64, 0x04, 0x6C, 0x00, 0xF7, 0x85, 0x02, 0x5D, 0x97, 0xD4, 0xC5, 0x79, 0xC2, 0x22, 0xC5, 0x61, 0xC5, 0x94, 0xF5, 0xDD, 0x91, 0x64, 0x80, 0x5A, 0x8B, 0xF2, 0x90, 0xAD, 0x0A, 0x94, 0x01, 0xD9, 0x80, 0x07, 0xC0, 0x94, 0xF1, 0x72, 0x60, 0x78, 0xDB, 0x69, 0x5A, 0x4D, 0x36, 0xA9, 0x0C, 0x15, 0x05, 0x93, 0xB5, 0x6A, 0xAE, 0x8A, 0xD5, 0x38, 0x6A, 0x05, 0xB6, 0x0A, 0x4E, 0x85, 0xD5, 0x58, 0x53, 0x74, 0xA1, 0x9A, 0xFA, 0x7A, 0x3A, 0x4C, 0x9F, 0x31, 0xF3, 0xE6, 0xDB, 0x51, 0x6D, 0xC9, 0x99, 0x52, 0xFA, 0x64, 0xFB, 0x39, 0x13, 0xE6, 0xED, 0x0A, 0xF0, 0x8F, 0x7E, 0xFB, 0x0C, 0x04, 0x1E, 0x52, 0x33, 0xF3, 0x00, 0xA1, 0x8B, 0x5A, 0xC4, 0xD5, 0x47, 0x54, 0x9F, 0x59, 0x98, 0x4C, 0xBE, 0xF1, 0x57, 0xB9, 0x19, 0x27, 0x0D, 0xDC, 0x34, 0xFB, 0x96, 0x26, 0x9D, 0xAD, 0x72, 0x0F, 0x03, 0x3A, 0x80, 0xD1, 0x4F, 0x49, 0x64, 0x2F, 0xEC, 0x7D, 0x88, 0x51, 0xBD, 0x56, 0x53, 0xF8, 0x60, 0xE2, 0xFC, 0xC2, 0x04, 0x11, 0xBA, 0x7B, 0x8A, 0xC1, 0x4E, 0xDB, 0x8A, 0x6B, 0x22, 0xE8, 0xC4, 0xC3, 0xDE, 0x80, 0xB1, 0x36, 0x41, 0xAB, 0xE5, 0x7F, 0xEA, 0x9B, 0x48, 0xDD, 0x95, 0x70, 0x4F, 0xAE, 0x23, 0x7B, 0x4C, 0x52, 0xE4, 0xF3, 0xE3, 0xB1, 0xD0, 0x00, 0xBC, 0x80, 0x5A, 0x53, 0xAE, 0x81, 0x5A, 0x01, 0x77, 0x20, 0x08, 0xBA, 0x4D, 0x68, 0xB5, 0x8E, 0x57, 0xC2, 0x7B, 0xF6, 0x46, 0x1E, 0x4F, 0x9D, 0x7B, 0xCA, 0x2B, 0xFC, 0xA1, 0x0B, 0xFC, 0x11, 0xB8, 0x32, 0x1C, 0xC0, 0x15, 0x08, 0x01, 0x7C, 0x00, 0x23, 0x12, 0x60, 0xFD, 0xB8, 0x2A, 0xAD, 0x66, 0x9B, 0xF1, 0xD4, 0x48, 0xA3, 0x09, 0x26, 0xF8, 0x14, 0xDB, 0xCC, 0x6E, 0xAA, 0x7A, 0x6C, 0x15, 0xE0, 0xEC, 0x50, 0x51, 0xA6, 0x41, 0x5E, 0x2D, 0x2D, 0xFD, 0xBC, 0xEB, 0x92, 0xF8, 0x13, 0xE4, 0x98, 0xFA, 0xA4, 0x69, 0x33, 0xFE, 0x58, 0x6F, 0x5B, 0x31, 0x7D, 0x10, 0x7A, 0xF7, 0x19, 0x68, 0x07, 0xD8, 0xCB, 0x22, 0xEB, 0xD6, 0x57, 0xED, 0x01, 0xD2, 0x5F, 0xD7, 0xBF, 0x3F, 0x92, 0x4F, 0x4D, 0x11, 0x8B, 0xBD, 0x2C, 0xA4, 0xF2, 0xEC, 0xB6, 0xE7, 0x8F, 0x60, 0x7A, 0x04, 0x30, 0xB5, 0xB9, 0x55, 0xCC, 0xB4, 0x1A, 0x82, 0x95, 0xB9, 0x40, 0x26, 0xE0, 0x05, 0xA4, 0xE2, 0x15, 0x0B, 0x1A, 0xCD, 0x9F, 0xB4, 0x9F, 0x32, 0x54, 0xFE, 0xE7, 0x6F, 0x30, 0xEB, 0xEA, 0x4E, 0xD0, 0x5F, 0x6C, 0x18, 0x1B, 0xEE, 0xD8, 0x49, 0xED, 0x9D, 0x98, 0xDC, 0x14, 0x50, 0xC3, 0x72, 0xE7, 0x29, 0x54, 0xDD, 0xB2, 0x87, 0xD2, 0x3B, 0x3A, 0x86, 0xC2, 0x8E, 0x80, 0xFA, 0x5D, 0xF9, 0x23, 0xF3, 0xC6, 0xE3, 0x86, 0x2D, 0x3C, 0x9F, 0x37, 0x5B, 0x01, 0x3B, 0x80, 0x50, 0x90, 0x35, 0x5E, 0xE5, 0xD7, 0x61, 0x8E, 0xE6, 0xD3, 0x61, 0x75, 0x6D, 0x68, 0xCF, 0xCD, 0x7E, 0x9E, 0xC4, 0x54, 0x58, 0xD4, 0x16, 0x9D, 0xBB, 0x27, 0x14, 0x30, 0xB1, 0x70, 0xA0, 0x02, 0xF0, 0x85, 0x26, 0xC0, 0xAD, 0x41, 0x94, 0x56, 0xA3, 0xAF, 0xD6, 0x51, 0x29, 0x2F, 0x70, 0xE0, 0xC6, 0xF4, 0xAA, 0xEA, 0xD9, 0x5E, 0x8A, 0x6D, 0x1B, 0x71, 0xCE, 0xA6, 0xA8, 0xEB, 0xE5, 0x54, 0x93, 0xCF, 0x19, 0x37, 0x58, 0xC3, 0x65, 0x72, 0x3B, 0xCE, 0xA2, 0xDF, 0x00, 0x36, 0x66, 0x01, 0x5E, 0xB1, 0x3B, 0x14, 0x44, 0xDF, 0x63, 0x5F, 0x6E, 0x5C, 0x7F, 0xCA, 0x12, 0x9E, 0xBA, 0x16, 0x01, 0xDA, 0x81, 0x9C, 0xF7, 0xBF, 0x82, 0x15, 0x08, 0x66, 0xEA, 0xD7, 0x5F, 0x5D, 0x9B, 0x51, 0x73, 0x60, 0x1F, 0xC7, 0xEE, 0x41, 0xFD, 0x6B, 0xD4, 0x82, 0x1F, 0xA0, 0xF7, 0xD2, 0x60, 0x0A, 0xF8, 0xC2, 0x12, 0x50, 0x07, 0xA4, 0x00, 0x1B, 0xEC, 0x99, 0x12, 0x34, 0x5A, 0xAE, 0xE8, 0x1C, 0x5A, 0xD6, 0xA4, 0x3B, 0xCA, 0x0B, 0x8E, 0x6D, 0xD1, 0x6D, 0x62, 0x4B, 0x50, 0x5B, 0x3D, 0xC6, 0xF9, 0xB9, 0x66, 0x43, 0x8A, 0x4E, 0x8E, 0x3B, 0x43, 0x5E, 0x86, 0xC7, 0xD9, 0xAB, 0xBF, 0x26, 0x1C, 0x13, 0x18, 0xA4, 0xAC, 0xC7, 0x64, 0x9B, 0xCD, 0xBB, 0x2F, 0xA7, 0x2A, 0xC0, 0xDF, 0x93, 0xA0, 0xDF, 0x17, 0x9F, 0x7C, 0x5F, 0xF1, 0x00, 0xC4, 0x00, 0x4D, 0xC0, 0xF4, 0x29, 0x90, 0x5D, 0xDB, 0xC7, 0x2B, 0x4B, 0xC6, 0x54, 0x25, 0x7F, 0x5C, 0xDA, 0x91, 0x6F, 0xD2, 0x16, 0x96, 0xDF, 0x5B, 0xAF, 0x83, 0x42, 0x1D, 0x05, 0x68, 0x2E, 0x62, 0x71, 0x6E, 0x58, 0x00, 0x93, 0xB4, 0x5A, 0x6D, 0x23, 0x2E, 0x45, 0xE4, 0x38, 0x02, 0x37, 0x7D, 0x17, 0x8C, 0x69, 0x6B, 0x9C, 0x0E, 0xD5, 0xB7, 0x00, 0x2C, 0x50, 0x43, 0x2B, 0xF1, 0xB3, 0xD6, 0x7C, 0x6F, 0x06, 0xD2, 0x3C, 0x46, 0x5C, 0xF1, 0x21, 0xDC, 0x17, 0xAE, 0x9E, 0x1F, 0x47, 0xF0, 0x33, 0x3A, 0xC6, 0xED, 0x96, 0x9F, 0x7D, 0x7C, 0x99, 0x79, 0x6B, 0xF8, 0xA6, 0xDE, 0x1D, 0xEC, 0x3C, 0x81, 0x68, 0x20, 0xED, 0x4A, 0x82, 0x61, 0xCD, 0x70, 0x3D, 0xE7, 0x07, 0xCF, 0x3D, 0x75, 0x31, 0xD9, 0xFB, 0xDC, 0x0A, 0xE3, 0xB9, 0x3B, 0xA8, 0x2E, 0x28, 0x1C, 0x70, 0x16, 0x62, 0xFF, 0x85, 0x06, 0xCC, 0x80, 0x0A, 0x5A, 0xAD, 0x7F, 0xFF, 0xE9, 0x6E, 0xF9, 0x37, 0x02, 0xB1, 0xE0, 0xFA, 0xFD, 0x85, 0xBD, 0x65, 0x5D, 0xBD, 0x11, 0x8E, 0x42, 0x0D, 0xAD, 0x09, 0xDA, 0xD1, 0xE9, 0xFC, 0x57, 0x5D, 0xC1, 0xB9, 0xDB, 0xB6, 0x33, 0xCD, 0x20, 0xF5, 0x3E, 0xAD, 0xB5, 0x03, 0x5A, 0xDF, 0xEB, 0x02, 0xE0, 0xCE, 0xB0, 0xD6, 0x9D, 0x3A, 0x94, 0xC6, 0x5B, 0x03, 0x20, 0x07, 0x50, 0x59, 0x38, 0xD0, 0x2C, 0xCF, 0x7D, 0x74, 0x03, 0xAF, 0xD2, 0xBC, 0x7C, 0x56, 0x22, 0xEF, 0xF5, 0x1C, 0xFF, 0x20, 0x8F, 0x2F, 0xDC, 0x03, 0xA6, 0x34, 0x07, 0x3A, 0x80, 0x39, 0x40, 0x2D, 0x7C, 0xA1, 0x0B, 0xDB, 0x9B, 0xED, 0x93, 0x11, 0xF3, 0xEA, 0xC7, 0xFB, 0xC0, 0xE3, 0x88, 0x74, 0xEF, 0xC4, 0x11, 0x4E, 0x07, 0xBF, 0x3E, 0xB6, 0x05, 0x7E, 0xBD, 0x8A, 0x93, 0xB7, 0x37, 0x32, 0xCF, 0xED, 0x59, 0x3B, 0xCD, 0x16, 0x3D, 0xCA, 0xD5, 0x18, 0xA8, 0x60, 0xF2, 0x3F, 0x73, 0x00, 0xD8, 0xC9, 0x18, 0x6F, 0x9A, 0x03, 0xB2, 0x68, 0xD6, 0x4F, 0xE8, 0x1D, 0xC0, 0x0D, 0x01, 0xEC, 0x00, 0x51, 0x40, 0xF5, 0xDB, 0x40, 0xC4, 0xF0, 0x90, 0x99, 0xF6, 0x94, 0x08, 0xA3, 0x03, 0x31, 0x74, 0x3D, 0xDD, 0x9B, 0x36, 0x18, 0x9B, 0x77, 0x1F, 0x70, 0x97, 0xFE, 0xD0, 0x3F, 0xC0, 0x51, 0xFE, 0x83, 0x19, 0x10, 0x7E, 0x27, 0xA4, 0x9E, 0x02, 0x34, 0x80, 0x27, 0x3B, 0xD2, 0x19, 0x2B, 0x40, 0x82, 0xEF, 0x68, 0x22, 0xEB, 0x5F, 0x7A, 0xD5, 0x50, 0xD7, 0xB3, 0x96, 0xB3, 0x82, 0x6F, 0xBE, 0xA5, 0xB7, 0xCD, 0x56, 0x18, 0xB7, 0x93, 0x68, 0xF7, 0x35, 0x61, 0x8C, 0x76, 0xEC, 0xD9, 0xC9, 0x9E, 0x6F, 0x26, 0xFD, 0xE9, 0x8A, 0xCB, 0x4E, 0xA7, 0xF6, 0x84, 0x45, 0x4D, 0x80, 0x98, 0xBB, 0xA8, 0xC7, 0x98, 0x47, 0x30, 0xC0, 0x51, 0xC0, 0xE4, 0x3E, 0xA7, 0x00, 0x7F, 0x12, 0x8A, 0x92, 0x14, 0xDA, 0xE0, 0x5D, 0x07, 0x46, 0x73, 0x87, 0xB5, 0xE4, 0xC0, 0x4C, 0xB1, 0x86, 0xF1, 0x58, 0x8B, 0x38, 0x60, 0x01, 0x44, 0x03, 0xE5, 0x2B, 0x3C, 0xB3, 0x30, 0x05, 0xBC, 0x81, 0x3E, 0x34, 0x9A, 0xE0, 0x1F, 0x29, 0x1E, 0x05, 0x05, 0xA8, 0x50, 0x3C, 0xE1, 0xDB, 0x61, 0x29, 0x12, 0xCE, 0xE5, 0xD2, 0xC8, 0x92, 0xF2, 0xB8, 0xFA, 0x8F, 0xE7, 0xF9, 0x34, 0x49, 0x0A, 0x96, 0x11, 0xB3, 0x98, 0x5F, 0xB9, 0x02, 0xF1, 0xE1, 0x7D, 0xC1, 0x94, 0xBC, 0x23, 0xE9, 0xA6, 0x80, 0xC7, 0x82, 0x13, 0x93, 0x59, 0x70, 0x54, 0xA0, 0x49, 0x7C, 0x12, 0x5D, 0xCC, 0xEB, 0xFD, 0x88, 0xBF, 0xEE, 0x86, 0x45, 0xA5, 0xE0, 0xBD, 0x1E, 0x30, 0x42, 0x97, 0xB1, 0x3E, 0xE0, 0x45, 0x9F, 0x3B, 0x0C, 0x6C, 0x02, 0xD4, 0xDC, 0x48, 0x07, 0xCC, 0x00, 0x49, 0x40, 0x87, 0xC1, 0x2D, 0x5A, 0x4D, 0xB7, 0xC8, 0xB6, 0x1E, 0xAB, 0x55, 0xA3, 0xB1, 0x83, 0x0C, 0x1E, 0x42, 0x25, 0xB9, 0x20, 0x07, 0x2D, 0x58, 0x47, 0x8E, 0xC6, 0x95, 0x1E, 0xF9, 0xA9, 0x96, 0xD2, 0xA7, 0x6B, 0xA5, 0x7C, 0x52, 0x39, 0x52, 0x6F, 0xFD, 0x78, 0x1F, 0x5E, 0x30, 0x3F, 0xAD, 0x42, 0x1B, 0xA8, 0xFB, 0x67, 0x14, 0xF4, 0xC7, 0x52, 0xF7, 0x16, 0xCD, 0x4C, 0xEF, 0xC3, 0x45, 0x16, 0xEF, 0xBC, 0xBC, 0x54, 0xD1, 0x4B, 0xC9, 0x2B, 0x25, 0xA5, 0x3C, 0x19, 0x74, 0xB7, 0x35, 0xDE, 0x01, 0xF2, 0x13, 0x4A, 0x6F, 0x5F, 0x0C, 0x50, 0x8B, 0x58, 0x78, 0x03, 0x8F, 0x29, 0x9F, 0xB1, 0x66, 0xCF, 0x04, 0xED, 0x5F, 0x48, 0xDA, 0x71, 0xF2, 0x93, 0xDA, 0x43, 0x3B, 0xBC, 0xB8, 0xF4, 0x24, 0xA6, 0x37, 0xC5, 0x19, 0xFE, 0xE3, 0xB0, 0x46, 0x91, 0xDB, 0x27, 0x6D, 0x22, 0xD9, 0x49, 0xF9, 0x0D, 0x68, 0x6E, 0xC4, 0x0E, 0x65, 0x91, 0x77, 0x0F, 0xB7, 0x4E, 0x9C, 0x45, 0xAE, 0x8D, 0xB7, 0x9F, 0x5D, 0xD5, 0x3E, 0x1A, 0x00, 0x15, 0xFB, 0xE9, 0xD2, 0xD6, 0x2D, 0x0E, 0xC3, 0xB7, 0x72, 0x91, 0x72, 0x76, 0xAB, 0x41, 0x24, 0xB2, 0x4B, 0x16, 0xC3, 0x71, 0x89, 0x4A, 0x03, 0x00, 0x5E, 0x93, 0x1F, 0xFA, 0x07, 0xF8, 0xBC, 0x7F, 0xB0, 0x06, 0xA2, 0x80, 0x1A, 0x54, 0x13, 0x9C, 0x02, 0xC4, 0x01, 0x35, 0x1A, 0xCD, 0xD1, 0x4C, 0xCC, 0x9C, 0x43, 0x6D, 0x3B, 0xC1, 0xE9, 0x7A, 0xEA, 0x83, 0xD5, 0xF3, 0x88, 0x95, 0x4B, 0x42, 0xF0, 0x44, 0xE5, 0x5B, 0xA5, 0x7D, 0xBB, 0x3B, 0x52, 0xEF, 0x06, 0xB8, 0x33, 0x80, 0x5F, 0xE7, 0x86, 0x7C, 0x92, 0x1C, 0xE9, 0xFA, 0x89, 0x04, 0xA4, 0x6E, 0x67, 0x5A, 0x2B, 0xC7, 0xED, 0x9D, 0x72, 0x55, 0x0E, 0x8C, 0x73, 0xFC, 0x01, 0x75, 0x29, 0x10, 0x88, 0x3F, 0xDE, 0x21, 0xED, 0x77, 0x38, 0x41, 0xFF, 0x69, 0x05, 0xE2, 0xF6, 0xE8, 0xB6, 0xF7, 0x27, 0x5B, 0x8C, 0x6D, 0x12, 0x7E, 0x01, 0xAE, 0x8B, 0x06, 0x42, 0x16, 0x09, 0xD4, 0x16, 0x02, 0x49, 0xD1, 0x6A, 0x81, 0x86, 0xCD, 0xBE, 0xFA, 0x30, 0xB1, 0x6F, 0x36, 0xB3, 0x94, 0x0C, 0x7E, 0xC9, 0x82, 0xC6, 0x0E, 0x4F, 0xA8, 0xAE, 0xD4, 0xE8, 0xB8, 0xC5, 0x5C, 0x2D, 0x1E, 0x07, 0x10, 0x05, 0x10, 0xEE, 0x96, 0xB1, 0xAD, 0xAF, 0xF8, 0xB6, 0x3C, 0x27, 0x37, 0x8D, 0xEB, 0x58, 0x16, 0x44, 0x00, 0x29, 0xAF, 0xE9, 0x13, 0x9F, 0xDE, 0x2C, 0xBF, 0xF8, 0x74, 0x29, 0x4E, 0x67, 0xB6, 0x37, 0xB3, 0xF5, 0x28, 0x6F, 0x9B, 0xFB, 0x05, 0x0F, 0x4B, 0x5C, 0x28, 0xA4, 0xB6, 0x35, 0x1C, 0x0A, 0x8C, 0xB2, 0x8F, 0x27, 0x30, 0xB6, 0x5D, 0xD7, 0x15, 0x50, 0x03, 0x2C, 0x81, 0x08, 0x20, 0x0B, 0xDB, 0xF0, 0x71, 0x1A, 0x2D, 0xF7, 0x70, 0xA5, 0xBF, 0x43, 0x9A, 0x86, 0x63, 0x35, 0x3C, 0x0E, 0xBF, 0x93, 0xF8, 0x8A, 0xA9, 0xC7, 0x4A, 0xAE, 0xC5, 0xE6, 0xBA, 0xC6, 0xD5, 0xFA, 0xAD, 0xAF, 0x72, 0xE3, 0x60, 0xCA, 0xBA, 0x3E, 0x29, 0xEB, 0x93, 0x00, 0x1E, 0xDA, 0x3E, 0xD4, 0x47, 0xDD, 0xBB, 0xD8, 0x61, 0xE0, 0xEE, 0xEF, 0x9F, 0x01, 0x04, 0x4F, 0xBD, 0x73, 0x67, 0x80, 0x7B, 0x03, 0xB9, 0xE8, 0xB5, 0x6B, 0xD4, 0xD5, 0x55, 0x91, 0x7D, 0x43, 0xA9, 0xD1, 0xE9, 0x8F, 0x98, 0x15, 0xC7, 0xC1, 0x31, 0x58, 0xF2, 0x24, 0x50, 0x5B, 0x87, 0x64, 0x09, 0x64, 0x00, 0x2D, 0x8B, 0x02, 0x66, 0x2F, 0x09, 0xA7, 0x01, 0x75, 0x20, 0x9A, 0x46, 0x2B, 0x9C, 0x80, 0x9C, 0x39, 0x91, 0x98, 0xBB, 0xAD, 0xBA, 0x15, 0x1A, 0xBD, 0x4D, 0xE2, 0x0D, 0x8E, 0x05, 0x09, 0x74, 0x45, 0x31, 0xBB, 0xEA, 0x0B, 0xC0, 0xEB, 0xDE, 0x1E, 0xD4, 0xE8, 0x58, 0x5B, 0x2C, 0x3C, 0x2E, 0x5F, 0x2E, 0x37, 0x06, 0x00, 0x9E, 0x47, 0x20, 0x13, 0xA8, 0x59, 0x70, 0xB2, 0xB3, 0xB7, 0xCB, 0x42, 0x02, 0xB0, 0x02, 0x1E, 0xCF, 0x79, 0x5F, 0x8B, 0x1B, 0x3B, 0xEC, 0xE5, 0x53, 0xB6, 0x39, 0xF9, 0x56, 0x7A, 0xE8, 0x4E, 0x37, 0x7B, 0xE4, 0xC8, 0x6A, 0x6F, 0x9B, 0xB9, 0xA3, 0xF1, 0x14, 0x20, 0x09, 0x30, 0xD4, 0xDC, 0x0D, 0x54, 0x02, 0xBD, 0xAF, 0xA4, 0xD3, 0x6A, 0xBD, 0x9E, 0x30, 0x5A, 0x0D, 0x3F, 0x8B, 0x3D, 0xAB, 0x59, 0x0B, 0x3C, 0xC9, 0x09, 0x1B, 0xA6, 0xD9, 0xCF, 0xDB, 0x20, 0x11, 0x6C, 0x5F, 0x76, 0x7B, 0x3B, 0xA4, 0x3E, 0xA5, 0xED, 0x4C, 0x55, 0x3F, 0xEB, 0x05, 0xA6, 0x64, 0x5D, 0xBE, 0x93, 0xB0, 0x9E, 0x15, 0x7E, 0xEC, 0xEE, 0x07, 0xD4, 0x02, 0x38, 0xFD, 0xE8, 0x3C, 0x76, 0x08, 0x85, 0xEF, 0xD6, 0x78, 0x0E, 0x28, 0x33, 0x31, 0x63, 0x47, 0x1E, 0xAC, 0xF6, 0x17, 0x88, 0x34, 0x79, 0x0A, 0xB7, 0xB6, 0x76, 0x15, 0xC6, 0xEB, 0xA6, 0x14, 0xE3, 0x5D, 0xB4, 0xD6, 0x74, 0x9E, 0x15, 0x10, 0xB2, 0xF0, 0x85, 0x2E, 0x12, 0x28, 0xDE, 0xDF, 0x9B, 0x56, 0x9B, 0xBF, 0x0D, 0xF4, 0xA0, 0x88, 0x05, 0x92, 0x8A, 0xBD, 0x0D, 0xA8, 0x6C, 0x73, 0x7A, 0x73, 0xBB, 0x32, 0x04, 0xBA, 0x97, 0x9B, 0xDF, 0xA5, 0xED, 0xDF, 0x2B, 0x28, 0x7B, 0xBF, 0x2A, 0xAF, 0xA0, 0x42, 0x97, 0xE3, 0x26, 0x5E, 0xD9, 0xBD, 0x66, 0x45, 0xDC, 0x22, 0x31, 0xB9, 0xE8, 0xBC, 0xFD, 0x40, 0xE1, 0xFF, 0xD1, 0x15, 0x3C, 0x1B, 0x78, 0x32, 0xE4, 0x9F, 0xE2, 0x17, 0x7B, 0x2E, 0x19, 0xF8, 0xBB, 0xCF, 0x9B, 0x0B, 0x04, 0x8F, 0x13, 0x6B, 0x3C, 0x2F, 0x69, 0xCD, 0x38, 0xC0, 0xD4, 0x5D, 0x5C, 0xE4, 0x06, 0xE4, 0x01, 0xDA, 0x60, 0xA7, 0xD3, 0x80, 0x2A, 0xE0, 0xB4, 0x5A, 0xBC, 0xF5, 0xC6, 0xDC, 0x41, 0xD1, 0xF5, 0x0D, 0xF7, 0x82, 0x1E, 0x78, 0xCE, 0xD7, 0x0F, 0x39, 0xD6, 0xF8, 0x3B, 0xDB, 0x9F, 0x72, 0x02, 0x2C, 0x4E, 0x77, 0x67, 0x0C, 0x65, 0xE5, 0x8F, 0xF2, 0x3A, 0xDD, 0x8F, 0x1B, 0xFF, 0xF1, 0xB7, 0xD6, 0x23, 0xB8, 0x1F, 0x7D, 0x77, 0x41, 0x9A, 0x01, 0xB2, 0x3F, 0x43, 0xCD, 0x76, 0x54, 0x25, 0xF7, 0xD1, 0xFD, 0x14, 0xB7, 0xFE, 0x9D, 0xC9, 0x2B, 0xCC, 0x26, 0x2C, 0x58, 0xC3, 0x3C, 0x80, 0x57, 0x48, 0xDE, 0xB2, 0x3E, 0xF8, 0x8F, 0xA0, 0xAA, 0x38, 0x7B, 0x16, 0x29, 0x60, 0x64, 0x6F, 0x4A, 0x05, 0x44, 0x02, 0xBD, 0x37, 0x01, 0x39, 0x80, 0x35, 0x10, 0x03, 0x3C, 0x11, 0xF7, 0xF7, 0x42, 0x70, 0xDB, 0x8E, 0x8A, 0xBE, 0xF5, 0xFB, 0x0E, 0x1D, 0x1B, 0x28, 0xD0, 0x40, 0x88, 0xA8, 0x7E, 0x3E, 0x22, 0x7B, 0x6A, 0x32, 0xE4, 0x39, 0x76, 0xDC, 0xF3, 0x46, 0x06, 0xF0, 0xFA, 0x9C, 0x62, 0x07, 0xC8, 0xE7, 0x84, 0x01, 0xCC, 0xD5, 0xB6, 0x89, 0x69, 0x6E, 0x4F, 0x4A, 0x42, 0x3C, 0xBD, 0x16, 0x0F, 0xB3, 0x1F, 0xD9, 0x8C, 0xE5, 0x75, 0x81, 0xC4, 0xA3, 0x05, 0xD5, 0x79, 0xF7, 0x9C, 0xCA, 0x01, 0x2C, 0x00, 0xF5, 0xC5, 0x59, 0x28, 0xE0, 0x02, 0xB4, 0xDE, 0x2E, 0x81, 0xA3, 0x7C, 0x08, 0x44, 0x00, 0x36, 0x40, 0xE4, 0x13, 0x5D, 0xA4, 0xD5, 0xF4, 0x17, 0x8D, 0xB2, 0xA4, 0xC0, 0x77, 0x5E, 0x1A, 0x88, 0x47, 0xE3, 0x07, 0x8B, 0xC0, 0xC0, 0x13, 0x54, 0x17, 0x78, 0xE7, 0x7F, 0xF4, 0x78, 0xE0, 0x1F, 0x1C, 0xC6, 0x3D, 0x61, 0x2D, 0x93, 0x80, 0xD8, 0xA2, 0x00, 0x6B, 0xA0, 0xF5, 0x4E, 0xD5, 0xC6, 0x43, 0x86, 0xE5, 0xB5, 0x9E, 0x66, 0xE8, 0xDA, 0x6F, 0x49, 0x36, 0xEF, 0xA7, 0xBD, 0xA0, 0x32, 0x95, 0xE0, 0x13, 0xFC, 0x32, 0x80, 0xEE, 0xC9, 0xA8, 0x6E, 0x7D, 0x43, 0xAF, 0x85, 0x2F, 0xFA, 0x9B, 0x42, 0x1F, 0xC0, 0x14, 0xD0, 0x01, 0x84, 0x03, 0x27, 0x99, 0x44, 0x7E, 0xCB, 0xD9, 0xF5, 0x63, 0x35, 0xFB, 0x37, 0x1B, 0x96, 0x81, 0x2A, 0x87, 0xD1, 0x6A, 0x58, 0x95, 0x1C, 0x0B, 0x89, 0x4D, 0x32, 0x85, 0x18, 0x67, 0xD2, 0x66, 0x55, 0xC1, 0x37, 0xA2, 0xC7, 0x78, 0xDB, 0xDC, 0x71, 0xF5, 0x31, 0xE6, 0x68, 0x2F, 0x04, 0xD0, 0x03, 0x44, 0xBE, 0xD1, 0xF2, 0xE6, 0x55, 0x29, 0x9F, 0xA6, 0x8D, 0x1E, 0x6F, 0xD2, 0x9F, 0xEF, 0xA9, 0x62, 0x9E, 0x34, 0xE5, 0x1C, 0x9C, 0xF2, 0xEA, 0x56, 0x6B, 0x3B, 0xF1, 0xB9, 0xA8, 0x15, 0x10, 0x0B, 0x37, 0xC0, 0x1A, 0xF0, 0x03, 0x14, 0xCB, 0x62, 0x16, 0xD9, 0x40, 0x24, 0xA0, 0x73, 0x8F, 0xDF, 0x18, 0xA0, 0x72, 0x5F, 0xF1, 0xC7, 0x6A, 0xBE, 0x4D, 0xB9, 0x12, 0xC7, 0xD8, 0x96, 0x3F, 0xAB, 0x35, 0xE2, 0x7B, 0x38, 0xC1, 0xE5, 0x6A, 0xE1, 0x14, 0xD2, 0x07, 0x92, 0x37, 0xF6, 0xEF, 0x1D, 0xD4, 0x3F, 0x25, 0x19, 0x8B, 0xAA, 0x45, 0x2C, 0xEA, 0x36, 0xA5, 0xE6, 0x3B, 0xC5, 0x9A, 0xCE, 0x25, 0x7F, 0xB2, 0x85, 0xA8, 0x3A, 0xF1, 0xA4, 0xD6, 0xF4, 0x5B, 0x0F, 0xE0, 0x4F, 0xE2, 0xB7, 0xF5, 0xD3, 0x27, 0x09, 0x59, 0x14, 0x77, 0xDD, 0x90, 0x0D, 0x70, 0x08, 0xA1, 0xC4, 0x24, 0x3F, 0x01, 0xB6, 0xA0, 0x63, 0x4E, 0xE6, 0x23, 0x62, 0xE6, 0x80, 0x0F, 0xA0, 0x01, 0xB8, 0xED, 0x9B, 0x7F, 0x56, 0xDB, 0x1B, 0x41, 0xFA, 0x67, 0x5D, 0x63, 0x7A, 0xBD, 0xFE, 0x66, 0x8F, 0xCC, 0x6E, 0x0D, 0xA9, 0xA8, 0xEE, 0xD2, 0x3B, 0x7A, 0x5C, 0xFE, 0x91, 0xA5, 0x0B, 0xDE, 0xC7, 0x3F, 0x49, 0x09, 0xC3, 0x95, 0x4C, 0x01, 0x2D, 0x80, 0x0B, 0x13, 0x5E, 0xE1, 0xF6, 0x4A, 0x2F, 0x9A, 0xCE, 0x93, 0x8A, 0x4A, 0x17, 0x45, 0x71, 0x95, 0x43, 0xE2, 0xCC, 0x62, 0x63, 0xBB, 0xCC, 0x93, 0x9F, 0x3F, 0x39, 0xBB, 0xC5, 0xF1, 0x4F, 0x7B, 0x78, 0x03, 0xAC, 0x01, 0x57, 0xA0, 0xEC, 0x6E, 0xE2, 0x92, 0x0E, 0xC4, 0x42, 0xE7, 0xEE, 0x35, 0x9F, 0x71, 0xF7, 0x52, 0x8F, 0x78, 0xAC, 0x96, 0xFF, 0x1A, 0x8B, 0xC0, 0x63, 0xB5, 0xF9, 0x05, 0xF6, 0x72, 0xB3, 0x23, 0x65, 0xCB, 0x66, 0x65, 0xEB, 0x03, 0x0B, 0x7A, 0xAB, 0x22, 0x4F, 0xA6, 0xF7, 0x8F, 0xF5, 0x99, 0xA1, 0x11, 0x1C, 0xDD, 0xF7, 0x04, 0x70, 0x07, 0xE2, 0x00, 0x45, 0x2F, 0xD1, 0xBC, 0x57, 0xF0, 0xD9, 0x87, 0x52, 0x4F, 0x94, 0x48, 0xE8, 0x6A, 0xC8, 0x75, 0x58, 0xD4, 0x9F, 0x36, 0x8E, 0xE4, 0x42, 0xF0, 0x4A, 0x3F, 0xFD, 0x70, 0x32, 0x6F, 0x59, 0x45, 0xF5, 0x6F, 0x76, 0xC9, 0x42, 0x17, 0x06, 0x8C, 0xDC, 0x55, 0x7F, 0x95, 0x40, 0x16, 0xE0, 0x01, 0x9C, 0xA7, 0x63, 0xF3, 0x9D, 0x51, 0x51, 0xFA, 0x58, 0xAD, 0x7E, 0x95, 0x8C, 0x27, 0x14, 0x17, 0xC5, 0xD3, 0xFF, 0x5A, 0x9E, 0x2E, 0x8E, 0x12, 0x0D, 0x81, 0x58, 0xB3, 0x6D, 0x3B, 0xA4, 0x68, 0xDA, 0x37, 0x4A, 0xAB, 0x7D, 0xC4, 0xFC, 0x76, 0x74, 0xA9, 0xBE, 0x5D, 0x7D, 0xEA, 0xE9, 0x79, 0xCF, 0x1B, 0x82, 0x04, 0xE0, 0x0A, 0xB4, 0xAC, 0xB9, 0x86, 0xE1, 0xE6, 0x75, 0xF1, 0x3A, 0x43, 0x6C, 0x09, 0xAB, 0x1D, 0x66, 0x38, 0x37, 0xAC, 0x06, 0xBF, 0xE6, 0x7E, 0x12, 0x7B, 0x34, 0x75, 0x2C, 0xAF, 0x28, 0x44, 0x06, 0x20, 0x45, 0x81, 0x40, 0x20, 0x7B, 0x11, 0xB7, 0x53, 0xE1, 0x14, 0xC0, 0xA5, 0x5E, 0x16, 0xC7, 0xF6, 0xE1, 0x77, 0xC8, 0x15, 0xFF, 0xF8, 0x7D, 0xC5, 0x1F, 0xAB, 0xA1, 0x26, 0xCF, 0xC2, 0xBE, 0x33, 0xF4, 0xD1, 0xD5, 0x62, 0x7C, 0x44, 0x12, 0xED, 0x92, 0x10, 0x9E, 0xC6, 0x58, 0xBB, 0x1B, 0x5B, 0xDE, 0xB5, 0x66, 0xCE, 0x8B, 0x0E, 0x90, 0xB2, 0xB0, 0x45, 0x01, 0x73, 0x39, 0x21, 0x19, 0xA5, 0x6F, 0xEA, 0x7D, 0xBC, 0xCD, 0x77, 0x98, 0x6B, 0x30, 0x30, 0xE2, 0x61, 0xA6, 0xE4, 0xE5, 0xF6, 0x66, 0x2F, 0x7A, 0x38, 0x40, 0x70, 0x8E, 0xDE, 0xAD, 0x71, 0x00, 0x4E, 0xBC, 0x5E, 0x54, 0x2E, 0xCE, 0x82, 0xA1, 0x9C, 0x02, 0xD2, 0x80, 0xE9, 0x85, 0x00, 0xE9, 0x80, 0x09, 0x0D, 0x05, 0xE8, 0x01, 0xE6, 0x3C, 0x66, 0x1B, 0x68, 0xBB, 0x76, 0xD2, 0x6C, 0x1B, 0x68, 0xD9, 0x20, 0x81, 0xCC, 0x96, 0xAA, 0x15, 0xFE, 0x95, 0xC7, 0x11, 0xCD, 0xCD, 0x62, 0xE1, 0xCF, 0xA7, 0x28, 0x83, 0x81, 0x96, 0xCB, 0x21, 0x56, 0x4F, 0x4E, 0xC6, 0x11, 0x40, 0x13, 0xE0, 0xC3, 0x39, 0x57, 0xE4, 0x57, 0x9F, 0xC2, 0x82, 0xE4, 0xA4, 0xA4, 0xDF, 0xD0, 0x60, 0x35, 0xA3, 0x1A, 0x15, 0x13, 0xA0, 0xD9, 0xE9, 0x7D, 0xD8, 0x03, 0x8A, 0xDE, 0xB5, 0x5B, 0x6C, 0xF1, 0xD0, 0x94, 0x09, 0x84, 0x2F, 0x64, 0x91, 0x40, 0x27, 0xCF, 0xE1, 0x40, 0xCE, 0xC2, 0x01, 0xFF, 0xC6, 0xD6, 0x72, 0x3F, 0x09, 0xF0, 0xD4, 0x9A, 0xE5, 0x6A, 0x59, 0x14, 0x1D, 0xF3, 0xF1, 0xB3, 0xDA, 0xD1, 0x5A, 0xC9, 0xA6, 0x5E, 0x4F, 0x7E, 0x6E, 0xAA, 0xA3, 0x63, 0x8A, 0xCA, 0xA7, 0x6D, 0xDE, 0x37, 0x3C, 0xA5, 0x97, 0x07, 0xED, 0x6D, 0xBE, 0xB9, 0xB0, 0x01, 0xC2, 0xEE, 0x29, 0x1A, 0x8F, 0x0B, 0x96, 0xA7, 0xB1, 0x5D, 0xF9, 0x87, 0x15, 0x26, 0x67, 0x47, 0xDE, 0x0F, 0x6C, 0x9A, 0x3F, 0xEB, 0x47, 0xC9, 0xA7, 0x1C, 0xA8, 0x13, 0x38, 0xC5, 0xDA, 0x6C, 0xA0, 0x0E, 0xE0, 0xB3, 0xF0, 0x85, 0x2D, 0x1A, 0xE8, 0x73, 0x57, 0x71, 0x97, 0x00, 0xF9, 0x79, 0x78, 0xE4, 0x8E, 0x6A, 0x34, 0x0B, 0x8E, 0x8A, 0x56, 0x13, 0x84, 0x09, 0x36, 0x0F, 0x37, 0x14, 0x5B, 0x6A, 0xE8, 0x46, 0x5A, 0x0E, 0x52, 0x99, 0xD5, 0x7A, 0x3B, 0x17, 0xCE, 0x6F, 0x73, 0x38, 0x23, 0x57, 0xD0, 0x20, 0xEA, 0x1B, 0xD4, 0xB3, 0x5B, 0x11, 0x57, 0x06, 0x88, 0xCF, 0xA6, 0x56, 0x72, 0x5B, 0x34, 0x82, 0xFF, 0xB0, 0xC1, 0x19, 0xCA, 0x6C, 0x79, 0x86, 0x34, 0xF1, 0xC9, 0x18, 0xAD, 0xDA, 0x57, 0xE4, 0xEA, 0xF5, 0x26, 0x8F, 0x56, 0xF0, 0xE4, 0xAD, 0x56, 0x67, 0xB6, 0x90, 0x45, 0x2C, 0x06, 0xF0, 0x06, 0x3A, 0x6F, 0xDD, 0xD7, 0x31, 0xA0, 0x17, 0x11, 0x80, 0xD8, 0xBE, 0x49, 0x47, 0xC4, 0xE1, 0x2B, 0xB4, 0x9A, 0x22, 0x8B, 0xC8, 0x14, 0x61, 0x02, 0xB5, 0xEB, 0xC0, 0xD6, 0x9E, 0x2B, 0xB8, 0xDA, 0x14, 0xD7, 0x43, 0x13, 0xC6, 0xF5, 0x14, 0xD5, 0x77, 0x3B, 0xE0, 0x81, 0x2D, 0xB8, 0xA0, 0xCD, 0xA7, 0xAA, 0xDA, 0x6E, 0xE8, 0x22, 0x9A, 0x3B, 0x16, 0xA7, 0xED, 0xD5, 0x27, 0xDF, 0x1E, 0x0D, 0x51, 0x3F, 0x6F, 0x57, 0x17, 0x76, 0xAD, 0xCC, 0xA7, 0x48, 0xCD, 0x3E, 0xA2, 0x80, 0xB6, 0xD0, 0x00, 0x8E, 0x5D, 0x3E, 0xF5, 0xD2, 0x85, 0x2C, 0x9E, 0xC0, 0x7E, 0x03, 0xAF, 0x7B, 0x0E, 0xB6, 0x6F, 0x20, 0x0B, 0xD0, 0xA2, 0xA7, 0x86, 0xA5, 0x5F, 0x40, 0x07, 0xAD, 0x66, 0x50, 0x05, 0x90, 0xDA, 0xEE, 0x53, 0x7A, 0x6D, 0x07, 0x76, 0x0C, 0xC5, 0xB3, 0xE1, 0x9B, 0x4D, 0xD6, 0xE8, 0x23, 0x9B, 0x77, 0x9F, 0x63, 0x7F, 0x8E, 0x1E, 0xB6, 0xBB, 0x01, 0x27, 0x6A, 0x01, 0x61, 0x0B, 0x05, 0x3C, 0xF8, 0xE9, 0x73, 0x3C, 0xE7, 0x65, 0xFE, 0x6E, 0x9B, 0x07, 0x37, 0x12, 0xF3, 0xD0, 0xB6, 0xB1, 0x26, 0x6B, 0xF3, 0xF0, 0x0A, 0xB5, 0xD3, 0xB9, 0x3F, 0x0B, 0x60, 0x9F, 0x4D, 0xDB, 0x1A, 0xD0, 0x5A, 0xC4, 0x22, 0x01, 0x13, 0x20, 0xF5, 0xDE, 0xD7, 0x43, 0x00, 0xE7, 0x43, 0x4A, 0x8A, 0x18, 0x10, 0x03, 0x54, 0x3C, 0xAE, 0x42, 0x5A, 0xCD, 0xE1, 0x12, 0x78, 0x36, 0x51, 0x48, 0x57, 0xCF, 0xE4, 0x16, 0xE4, 0x1A, 0x4E, 0xE5, 0xA7, 0xD9, 0x38, 0x6A, 0x87, 0x78, 0x31, 0x71, 0xED, 0xE3, 0xF4, 0x30, 0x9E, 0x68, 0x3F, 0x2D, 0x1A, 0x9D, 0x05, 0xD0, 0x07, 0xC8, 0x00, 0x28, 0x08, 0x69, 0xF9, 0x2A, 0x68, 0x30, 0x8A, 0xC4, 0xE4, 0x81, 0x78, 0xC4, 0x9D, 0x54, 0xDE, 0xBC, 0x3B, 0x96, 0xB5, 0x6C, 0xB5, 0xC9, 0x93, 0x72, 0xCC, 0x12, 0x3D, 0x54, 0x6A, 0xC0, 0xCC, 0x0D, 0x9C, 0xB8, 0x6B, 0x8D, 0x3D, 0x16, 0x67, 0x91, 0x40, 0x53, 0x47, 0x75, 0x51, 0x05, 0xE4, 0x00, 0xFE, 0x91, 0x9A, 0xAF, 0xC5, 0xEC, 0xC3, 0x6C, 0x5A, 0x2D, 0xFE, 0xA5, 0x62, 0xA9, 0xA7, 0xD5, 0xFA, 0x37, 0x19, 0x1B, 0x6F, 0x86, 0xE1, 0x1F, 0xD9, 0x14, 0x3E, 0xF9, 0x5A, 0xFF, 0xDA, 0xC4, 0x6F, 0x37, 0xD0, 0xAF, 0x56, 0x0C, 0x73, 0x8D, 0xE9, 0x64, 0xA4, 0x1C, 0x40, 0x2C, 0xBA, 0x6E, 0xDD, 0x6F, 0x4B, 0xA0, 0xCF, 0x65, 0x5F, 0x7D, 0x84, 0x07, 0x0F, 0x75, 0xEB, 0x0A, 0xE6, 0x72, 0x04, 0x20, 0x61, 0x66, 0x7D, 0xD2, 0x6C, 0x9F, 0x74, 0x64, 0x16, 0x04, 0xD7, 0x47, 0xB4, 0x94, 0xF9, 0x47, 0x33, 0x9F, 0x36, 0xBC, 0x0A, 0x58, 0x03, 0xEE, 0x1F, 0xD5, 0x93, 0x02, 0xCA, 0x81, 0x0C, 0xC0, 0x0F, 0x70, 0xEC, 0x2E, 0xB2, 0x9C, 0xD8, 0x37, 0x95, 0x56, 0x4B, 0xFC, 0xB3, 0x7A, 0xA0, 0xA5, 0x8F, 0xD7, 0x76, 0x71, 0x89, 0x55, 0xC5, 0x4E, 0x9C, 0x03, 0xA4, 0x51, 0x05, 0x74, 0x6A, 0x6B, 0x01, 0x94, 0xB2, 0x57, 0x77, 0x9B, 0xA9, 0x4B, 0xF4, 0x5C, 0xE2, 0x91, 0x69, 0x34, 0x96, 0x9D, 0x70, 0x51, 0x2F, 0x20, 0x06, 0x68, 0xDF, 0x15, 0x8C, 0xBD, 0xEE, 0x82, 0x52, 0x83, 0xAF, 0x10, 0x58, 0x3D, 0x65, 0x15, 0xCA, 0xD0, 0x89, 0xC2, 0x92, 0x11, 0xB0, 0x2B, 0x6B, 0x83, 0xEC, 0xC0, 0xA0, 0xB2, 0x77, 0x8A, 0x34, 0x40, 0x9C, 0xC7, 0x17, 0xA0, 0x14, 0xC8, 0x01, 0xAA, 0x79, 0xFB, 0x00, 0xDA, 0x6E, 0xD1, 0xDC, 0xC3, 0x87, 0x05, 0x84, 0x02, 0xDA, 0x80, 0xB3, 0x51, 0x53, 0xD3, 0x68, 0x05, 0x1F, 0xAE, 0x14, 0xE4, 0xCB, 0xCE, 0x2E, 0x6B, 0x5C, 0x9A, 0xA1, 0xAC, 0x33, 0x25, 0xF6, 0x3B, 0x22, 0x6C, 0x4B, 0xED, 0x8A, 0x0E, 0x1E, 0x38, 0x3E, 0x9B, 0xC1, 0x0F, 0xFA, 0xB7, 0x74, 0x25, 0xD0, 0xBE, 0x50, 0xA0, 0x88, 0xCF, 0xA5, 0xCB, 0xE5, 0x15, 0x3B, 0x79, 0x1A, 0x0A, 0xC4, 0x23, 0x2A, 0x9B, 0x1C, 0x01, 0xF3, 0xD6, 0x80, 0xEF, 0x32, 0x5E, 0xCF, 0x15, 0x3B, 0xF2, 0xEE, 0x40, 0x7E, 0x0E, 0x60, 0x84, 0x2D, 0x06, 0xF0, 0xB3, 0x48, 0xA0, 0xF5, 0x4E, 0xEF, 0x6A, 0x07, 0xEA, 0x93, 0xC2, 0x7A, 0xE4, 0xBE, 0x5A, 0xF4, 0xBE, 0x99, 0x79, 0x68, 0xB5, 0x86, 0xB4, 0xB7, 0x15, 0x72, 0x92, 0xBA, 0x2F, 0xAF, 0xA4, 0xBA, 0xAE, 0xB4, 0x92, 0xAC, 0xD8, 0xBF, 0xFE, 0x0C, 0xE2, 0x72, 0x6F, 0xA1, 0xF9, 0x58, 0xCD, 0x6E, 0x9F, 0x87, 0x1D, 0x20, 0x72, 0x21, 0x80, 0xDB, 0x22, 0x80, 0xB8, 0x92, 0xB6, 0x28, 0x20, 0xF1, 0x1C, 0x48, 0xE3, 0x91, 0x6A, 0xD5, 0x4B, 0x24, 0xD8, 0xD7, 0x6A, 0xFA, 0x6C, 0x70, 0xB3, 0x38, 0x09, 0x3C, 0xFA, 0xB8, 0x75, 0x9F, 0x15, 0xA4, 0x00, 0x6B, 0xC0, 0x0B, 0x88, 0x01, 0xE6, 0x7B, 0x78, 0x53, 0xA0, 0x02, 0x88, 0x85, 0xF0, 0xCD, 0xC4, 0xA7, 0x33, 0x40, 0x35, 0xAD, 0x36, 0x88, 0x3A, 0xA8, 0xA1, 0xD7, 0xE7, 0xE8, 0xEF, 0xF0, 0x26, 0x9B, 0xE8, 0x67, 0x5B, 0x8E, 0xA6, 0x6E, 0xAB, 0x0F, 0xF2, 0x1B, 0x72, 0x16, 0xAD, 0xCC, 0x5E, 0xFE, 0x08, 0x7D, 0xD3, 0x6F, 0xF5, 0x5E, 0x39, 0xF1, 0x65, 0x16, 0x59, 0x8B, 0x06, 0xEA, 0x2C, 0x78, 0xC2, 0xE2, 0x12, 0xC4, 0xDB, 0x92, 0xB1, 0xEA, 0x93, 0x72, 0xE5, 0x8C, 0x9D, 0x6C, 0x60, 0xF8, 0xEA, 0xA5, 0xCA, 0x62, 0x0B, 0xD6, 0x2A, 0x73, 0xE1, 0x46, 0x46, 0xC2, 0x8A, 0x57, 0x01, 0x65, 0xFB, 0x0B, 0x09, 0xE8, 0x01, 0xAC, 0x80, 0xAA, 0x7B, 0xD1, 0x28, 0x01, 0x32, 0x00, 0x5F, 0x88, 0xE3, 0xCD, 0xF9, 0xB4, 0xAB, 0x6E, 0x2E, 0x6B, 0xC5, 0x46, 0x4B, 0x89, 0xEE, 0x60, 0x12, 0xBF, 0x04, 0x36, 0xD5, 0xDC, 0xE5, 0x30, 0x71, 0xD5, 0x0B, 0xC5, 0xC2, 0x79, 0x12, 0x2E, 0x6B, 0x9F, 0x3B, 0xF0, 0xEE, 0x9F, 0xB1, 0x56, 0xF4, 0x72, 0x2C, 0xA6, 0xE8, 0x3D, 0x58, 0xC8, 0x22, 0x01, 0x3D, 0x00, 0xCD, 0x7C, 0x9A, 0xE5, 0x15, 0x73, 0xF7, 0x86, 0x6E, 0x79, 0x5B, 0x63, 0xE6, 0x73, 0x0B, 0x78, 0x72, 0xE4, 0x79, 0x77, 0x2A, 0xC0, 0xF6, 0x61, 0xF8, 0x7D, 0x27, 0x98, 0xBA, 0xA5, 0x74, 0xEC, 0xF9, 0x75, 0x60, 0x38, 0xA8, 0x39, 0x9A, 0xE3, 0x8E, 0xDE, 0x66, 0x01, 0x6A, 0xFB, 0xA6, 0xE2, 0x93, 0x1C, 0x60, 0x9A, 0x56, 0x83, 0xB6, 0xB7, 0x8A, 0xA3, 0x74, 0x48, 0xFA, 0x5F, 0x25, 0x46, 0x17, 0x2E, 0x85, 0x94, 0x74, 0x1A, 0x6C, 0xD9, 0xDD, 0x48, 0x0E, 0x9A, 0xA6, 0x07, 0xFC, 0x1B, 0x6D, 0xB9, 0x6B, 0x5A, 0x92, 0x9E, 0x85, 0x00, 0xAC, 0x00, 0x3F, 0x8B, 0x04, 0xF0, 0x0A, 0xEC, 0xB3, 0x37, 0x40, 0xCE, 0x49, 0x2A, 0x1E, 0xB3, 0x59, 0xE1, 0x7E, 0x7A, 0x44, 0x70, 0x58, 0x79, 0x1B, 0xEC, 0x5A, 0xB1, 0x26, 0x31, 0xE0, 0x08, 0x90, 0xCA, 0x36, 0x17, 0x80, 0x2A, 0x60, 0x01, 0xF8, 0x01, 0x42, 0x80, 0x6E, 0x6A, 0x36, 0x00, 0x73, 0x80, 0xE2, 0x43, 0x07, 0xC4, 0xF7, 0xCD, 0x58, 0xC3, 0x0A, 0xD0, 0x87, 0x56, 0x53, 0xE4, 0x81, 0xD4, 0x6C, 0xBD, 0x8B, 0x5D, 0xCD, 0x32, 0x02, 0x9E, 0xDD, 0xCD, 0xC8, 0x45, 0x4F, 0x5F, 0x2C, 0x44, 0x26, 0xD7, 0x0C, 0x8D, 0xFC, 0xE4, 0x13, 0x7D, 0x0F, 0xB2, 0x7D, 0x16, 0x0A, 0x54, 0xDF, 0x2E, 0x0F, 0xC9, 0x3B, 0xDA, 0xE2, 0xD7, 0x58, 0x7B, 0x32, 0x6B, 0xF5, 0x99, 0x69, 0x3E, 0xAF, 0x2A, 0x71, 0x3C, 0x7D, 0xFC, 0x4B, 0xEE, 0x3E, 0x2B, 0x47, 0x80, 0x70, 0xA0, 0x0B, 0xA0, 0xE8, 0xF3, 0x59, 0xC8, 0x59, 0x0C, 0x70, 0xAF, 0x5D, 0xF6, 0x7C, 0xF2, 0x04, 0x74, 0xDF, 0x2C, 0xBE, 0x79, 0x80, 0xE4, 0x42, 0x18, 0xB4, 0x9A, 0x41, 0xBC, 0xB3, 0x0B, 0xE5, 0xC0, 0x65, 0x3F, 0x21, 0x2C, 0x55, 0xC3, 0x71, 0x60, 0x60, 0x35, 0x2D, 0x59, 0x6D, 0x78, 0x87, 0x5F, 0x39, 0x9E, 0xBD, 0x13, 0xFC, 0xFA, 0x72, 0xA7, 0x3F, 0xC7, 0xB5, 0x03, 0x94, 0x2D, 0x74, 0x11, 0x40, 0xFB, 0xDB, 0xD5, 0x00, 0x65, 0xAF, 0xAF, 0x1E, 0x4A, 0xF3, 0x9E, 0xFE, 0x1C, 0x3A, 0xE9, 0x44, 0x92, 0x7D, 0xA5, 0xE8, 0xA5, 0x60, 0x1C, 0x34, 0x00, 0x39, 0x80, 0xE7, 0x67, 0x01, 0x35, 0xA0, 0x65, 0x11, 0x77, 0xDB, 0x1F, 0x2D, 0xA0, 0x75, 0x4D, 0xE9, 0xC0, 0x99, 0x5B, 0x15, 0x3B, 0x3E, 0x97, 0x59, 0xA7, 0xED, 0x95, 0x56, 0x73, 0x94, 0x00, 0x8D, 0x6D, 0xAA, 0x73, 0xDC, 0x22, 0x75, 0x99, 0x48, 0x2E, 0x76, 0xDB, 0xF2, 0x41, 0x5C, 0xA8, 0x6C, 0x1D, 0x45, 0xF2, 0x71, 0x79, 0x5C, 0x11, 0xB3, 0x2B, 0x96, 0x57, 0xBD, 0x30, 0x20, 0xF5, 0x46, 0xF1, 0x52, 0xBA, 0xA6, 0x14, 0xA3, 0x11, 0xD8, 0x49, 0xC6, 0xEE, 0x5A, 0x18, 0xFE, 0xC1, 0xF9, 0x6E, 0x2D, 0xFD, 0xD7, 0xA1, 0x2A, 0x80, 0xCE, 0xDB, 0xC9, 0x68, 0x02, 0x84, 0x03, 0x39, 0x40, 0x05, 0xD0, 0xF6, 0x28, 0x8C, 0x02, 0x6D, 0x6B, 0xC3, 0x4F, 0xCC, 0xBB, 0x0D, 0x70, 0x05, 0xF8, 0x50, 0x1F, 0x81, 0x71, 0x5A, 0x2D, 0xB6, 0x37, 0x6D, 0xAE, 0xF7, 0x36, 0xFF, 0x95, 0x43, 0x80, 0x19, 0x35, 0xC7, 0x86, 0xA9, 0xD1, 0x81, 0xCD, 0x64, 0xEA, 0xE7, 0xF5, 0x29, 0x61, 0x25, 0xD0, 0x37, 0x67, 0x7E, 0x6D, 0x61, 0xCC, 0xF7, 0xA9, 0x7B, 0x41, 0xAB, 0xC5, 0x50, 0x2A, 0xF2, 0x00, 0x7E, 0xAE, 0x6D, 0xD6, 0xD6, 0x4E, 0x14, 0x6E, 0xC8, 0x27, 0x49, 0xAF, 0x78, 0xDC, 0x6C, 0x3C, 0xBC, 0xA5, 0xF5, 0xE5, 0xF9, 0x85, 0x14, 0x40, 0x0F, 0x60, 0x03, 0x38, 0xD1, 0x40, 0x2C, 0xF8, 0x66, 0xF9, 0x0E, 0x08, 0x01, 0x9E, 0x96, 0x07, 0xFB, 0x69, 0x0A, 0xA8, 0x01, 0xE2, 0x00, 0x3A, 0x80, 0xB3, 0x07, 0x85, 0xD3, 0x6A, 0xB9, 0x15, 0x8E, 0x6C, 0xDB, 0xB8, 0x89, 0xAB, 0x32, 0x7B, 0x42, 0x8A, 0xED, 0x5F, 0x5A, 0x7B, 0x1B, 0xAC, 0xF5, 0xE5, 0x28, 0x2B, 0x0B, 0xEE, 0x8C, 0xBF, 0x7A, 0x65, 0x9A, 0x9E, 0x95, 0x81, 0x37, 0xBF, 0x7E, 0xFE, 0xDE, 0xB3, 0xD0, 0x01, 0x12, 0x7F, 0xFD, 0x62, 0x03, 0x4F, 0xCC, 0xC9, 0x7E, 0xB2, 0x78, 0xF6, 0x54, 0xF1, 0xF4, 0x07, 0x65, 0x46, 0xDA, 0x3C, 0x85, 0x3D, 0xA2, 0x6F, 0x9B, 0x58, 0x5B, 0xA0, 0xB6, 0xFF, 0x07, 0xBC, 0x89, 0x60, 0x3D, 0x10, 0x0B, 0xDF, 0xAB, 0x5A, 0x03, 0xDE, 0x9B, 0x2B, 0x3A, 0x80, 0xC7, 0x42, 0x01, 0x35, 0xBC, 0x32, 0x01, 0x54, 0xBE, 0x9F, 0xEC, 0xEF, 0x3E, 0x55, 0x05, 0x01, 0xD9, 0x83, 0xA5, 0x4B, 0x7C, 0x7E, 0x0D, 0x94, 0x3C, 0x03, 0x9B, 0x4F, 0xDA, 0x8A, 0x7C, 0x6E, 0x4F, 0xED, 0x33, 0x5B, 0x17, 0x66, 0x4C, 0xC1, 0xBD, 0x9B, 0xD9, 0xE4, 0x2E, 0xF4, 0x6F, 0xCD, 0x0F, 0x46, 0xBA, 0x52, 0x66, 0x1F, 0xC8, 0x00, 0x9A, 0xC2, 0x98, 0x01, 0x74, 0x73, 0x47, 0xDB, 0xC3, 0xD0, 0xA5, 0xF5, 0xBD, 0xB9, 0x17, 0xA6, 0xC0, 0x53, 0xA6, 0x13, 0x8F, 0xA4, 0xC0, 0xE1, 0x88, 0xE9, 0x5B, 0xEE, 0x6B, 0x8C, 0x5B, 0x09, 0x20, 0x0E, 0xA8, 0x2D, 0x1A, 0xF0, 0x73, 0x2B, 0xF1, 0x7B, 0x03, 0x5D, 0x40, 0x0D, 0x10, 0x05, 0x70, 0x27, 0x1A, 0xD9, 0x4F, 0x0A, 0x4C, 0xD0, 0x68, 0xBD, 0xDD, 0x94, 0x07, 0xBF, 0x2E, 0x5B, 0x0F, 0x54, 0xCA, 0x42, 0xA0, 0x6D, 0x72, 0xAF, 0xAB, 0x90, 0x35, 0x5B, 0x09, 0xD6, 0x8C, 0xAD, 0xDC, 0x23, 0xED, 0x8A, 0x3E, 0xC9, 0x7E, 0x6B, 0xF1, 0x67, 0x8F, 0x57, 0x07, 0xEC, 0x00, 0x9A, 0xF7, 0x43, 0xBA, 0x1A, 0x74, 0x18, 0x2D, 0x7E, 0x73, 0x8D, 0xF9, 0x8F, 0x7C, 0xD6, 0x5A, 0xFD, 0x74, 0x01, 0xA9, 0x64, 0x26, 0x24, 0x6D, 0x07, 0xD8, 0x5B, 0x08, 0xF4, 0xD8, 0x35, 0x9F, 0x86, 0xE2, 0xD1, 0x40, 0x2D, 0x28, 0x34, 0xE4, 0x76, 0x4B, 0x12, 0xC5, 0xC2, 0x15, 0xA0, 0x16, 0x4D, 0x7F, 0xA4, 0x6C, 0x2A, 0xF6, 0xCD, 0xA2, 0xD1, 0x66, 0xFB, 0xEE, 0x17, 0xA7, 0x27, 0x52, 0x95, 0xE6, 0x4F, 0x76, 0xC2, 0x0E, 0x2A, 0xE0, 0xED, 0x2D, 0xE8, 0x8A, 0xFA, 0x0D, 0xAD, 0x35, 0xDA, 0xD0, 0x68, 0xC1, 0x36, 0x76, 0xCC, 0x21, 0xE3, 0x41, 0xDB, 0xEC, 0xEE, 0x32, 0xA1, 0x09, 0xF8, 0x01, 0xE2, 0x92, 0x9D, 0xD8, 0x99, 0x68, 0xC6, 0x8E, 0xBB, 0xCC, 0xB5, 0x63, 0xE7, 0x5C, 0x66, 0x83, 0x6E, 0x6D, 0x5D, 0x2E, 0xFC, 0x69, 0xDF, 0x5F, 0x9C, 0x7B, 0x0A, 0x84, 0x01, 0x6F, 0x82, 0x0C, 0x70, 0x16, 0x7A, 0xB7, 0xA6, 0xF1, 0xD8, 0xC9, 0x7A, 0x00, 0xD3, 0xC5, 0x01, 0xA4, 0xEE, 0x69, 0xDD, 0x7C, 0x53, 0x80, 0xE2, 0x9A, 0xB6, 0x7A, 0x43, 0x1E, 0x89, 0xF6, 0x73, 0x15, 0xAB, 0x7B, 0x2D, 0x70, 0xE3, 0x96, 0xAF, 0x12, 0x8E, 0xEC, 0xBF, 0x00, 0x66, 0xB0, 0x96, 0x5C, 0x5A, 0x14, 0xCE, 0x91, 0x26, 0x0C, 0xFB, 0x5F, 0x22, 0xAB, 0xFE, 0x8C, 0x2D, 0x51, 0xC0, 0x04, 0x70, 0x07, 0xF2, 0x4D, 0xD1, 0x93, 0x79, 0x84, 0xF9, 0xBD, 0x5E, 0x99, 0x9C, 0xAD, 0xEF, 0xA2, 0x92, 0x12, 0x57, 0x2A, 0x9D, 0xA7, 0x3B, 0x4A, 0x27, 0x7F, 0x01, 0x90, 0x06, 0xD2, 0x80, 0xA1, 0x7C, 0x88, 0x02, 0x3A, 0x80, 0x15, 0xE0, 0x03, 0xF4, 0xEC, 0x80, 0x2B, 0xA0, 0x66, 0x11, 0x40, 0x14, 0xA0, 0x03, 0x9C, 0x85, 0x32, 0x52, 0x26, 0x34, 0x9A, 0xAC, 0x8A, 0x54, 0x5F, 0x75, 0x2D, 0x39, 0x7B, 0x05, 0xF5, 0xC4, 0x5F, 0x7D, 0x04, 0x89, 0xBF, 0x99, 0x4F, 0xEF, 0x25, 0xA4, 0xE9, 0xFF, 0x20, 0x02, 0xB8, 0xBF, 0x11, 0x58, 0xF1, 0xBF, 0x3D, 0x6D, 0xE8, 0x29, 0x02, 0xC2, 0x81, 0xBC, 0x4A, 0xF2, 0x65, 0x3F, 0xB1, 0x38, 0x6C, 0xD7, 0x16, 0x97, 0x47, 0x61, 0x24, 0x1C, 0x60, 0x81, 0x5D, 0x07, 0x7E, 0x56, 0xB6, 0x6A, 0xD8, 0xE7, 0x96, 0xCB, 0x57, 0xBF, 0x5B, 0xA1, 0x66, 0x00, 0xFE, 0x85, 0x03, 0x91, 0x40, 0x6F, 0x46, 0xB3, 0x39, 0x10, 0xB9, 0x08, 0xC0, 0x1D, 0xD0, 0x06, 0x64, 0xEE, 0x4F, 0xDD, 0xB4, 0x99, 0x62, 0x27, 0x4E, 0x85, 0x1F, 0x5A, 0x7C, 0x65, 0x8E, 0x7C, 0xB5, 0xAA, 0x61, 0xAC, 0xE9, 0x44, 0x96, 0xE0, 0x0C, 0x4E, 0xEA, 0x18, 0x68, 0xD9, 0x3C, 0x9F, 0x01, 0xC9, 0x73, 0x2C, 0x77, 0x4B, 0x29, 0x76, 0x2F, 0x60, 0x77, 0x07, 0xC0, 0x0C, 0xF0, 0xB3, 0x78, 0x85, 0xAD, 0x6C, 0x05, 0xCF, 0xF9, 0x07, 0x3A, 0xDB, 0x1B, 0x2B, 0xB3, 0x8E, 0x61, 0x02, 0x9F, 0x4D, 0xCE, 0x4E, 0xD6, 0x0E, 0x3F, 0xCD, 0xEA, 0xB3, 0x01, 0x1F, 0x3C, 0x3C, 0x01, 0xB8, 0x00, 0x79, 0x80, 0x36, 0x60, 0x62, 0x6B, 0x1A, 0x1D, 0x88, 0xB9, 0x33, 0xF8, 0x22, 0x16, 0x0A, 0x58, 0x03, 0x92, 0xC0, 0x31, 0x40, 0x99, 0x81, 0x6A, 0xB4, 0xD9, 0xF6, 0x7E, 0xF3, 0xFA, 0x41, 0x86, 0x87, 0x5B, 0xF6, 0x55, 0x10, 0xA8, 0x74, 0x6B, 0xFD, 0x20, 0xD9, 0xC8, 0xE4, 0x9C, 0xDF, 0xA5, 0xDD, 0x1F, 0x71, 0x80, 0xA7, 0x09, 0x2D, 0x2C, 0xF3, 0xEC, 0xA1, 0x6A, 0x80, 0xCF, 0xE2, 0xDC, 0x0F, 0xA5, 0x6E, 0xB8, 0xBF, 0xFB, 0x47, 0xBD, 0xBD, 0x29, 0x03, 0xE8, 0x3D, 0x9D, 0x5E, 0xC1, 0x5F, 0xF8, 0xB7, 0x50, 0x45, 0x9B, 0x40, 0xF2, 0xF7, 0xF8, 0xA6, 0x70, 0x17, 0x4A, 0x4A, 0x48, 0x02, 0xA5, 0xB7, 0xBB, 0x5D, 0x0C, 0x08, 0xA7, 0xBC, 0x24, 0x10, 0x01, 0xF8, 0x00, 0x4A, 0x9F, 0xED, 0x01, 0xD2, 0xEE, 0x00, 0x60, 0x38, 0xAD, 0xE6, 0xBF, 0xD8, 0xB1, 0x37, 0x1B, 0x4D, 0xC7, 0x95, 0x80, 0x95, 0x16, 0x28, 0x01, 0x9E, 0xC4, 0xF5, 0xDA, 0x0C, 0x92, 0xAB, 0x9D, 0xBC, 0x76, 0x7E, 0xFA, 0x82, 0x7E, 0x52, 0x8B, 0x89, 0x4E, 0xA0, 0x02, 0x48, 0x03, 0xC2, 0x17, 0x05, 0x30, 0x23, 0xC3, 0x86, 0x37, 0xF9, 0x4F, 0x13, 0xCE, 0x13, 0x57, 0x0B, 0x38, 0x15, 0xBC, 0x72, 0xE7, 0xDF, 0xE6, 0x5F, 0x38, 0x85, 0x81, 0x97, 0x27, 0xD0, 0x64, 0x00, 0xA3, 0x74, 0x2E, 0x40, 0x2E, 0xAA, 0x61, 0x04, 0x95, 0xDB, 0x9B, 0x6D, 0x05, 0x68, 0x7D, 0xDC, 0xE6, 0x02, 0x48, 0x03, 0xA6, 0xB4, 0x28, 0xAD, 0x16, 0x28, 0x89, 0x2C, 0x43, 0x25, 0x48, 0xFA, 0xBF, 0xC2, 0x52, 0x85, 0xC5, 0x5A, 0x03, 0x8B, 0xD2, 0xC9, 0x1F, 0x42, 0x0D, 0x9E, 0x8A, 0x29, 0x56, 0xE7, 0xDD, 0xE2, 0x00, 0x5A, 0xEF, 0xF5, 0xA8, 0x9E, 0x14, 0xBE, 0x6C, 0x60, 0x14, 0xA8, 0x04, 0xD2, 0x81, 0x58, 0xE0, 0x67, 0x4F, 0x1F, 0x25, 0x4E, 0xDB, 0xAD, 0xB6, 0x53, 0x7B, 0xE4, 0x76, 0x8A, 0x5E, 0xF4, 0xA4, 0xA8, 0xF4, 0xDD, 0xD6, 0x4E, 0x78, 0x5F, 0xCD, 0xF7, 0xDC, 0xB5, 0x23, 0x48, 0x79, 0xF8, 0x43, 0x51, 0x38, 0x96, 0x02, 0x01, 0xBC, 0x81, 0xA9, 0xD7, 0x53, 0x8E, 0x8C, 0xB8, 0xAB, 0x70, 0xBB, 0x16, 0x36, 0x80, 0x18, 0xB0, 0xFB, 0xD0, 0x3B, 0x43, 0x73, 0x53, 0xC5, 0x1B, 0x73, 0x59, 0x6D, 0x13, 0x8B, 0x64, 0xFB, 0xA7, 0xF4, 0xC6, 0xAA, 0xF3, 0x87, 0x14, 0x47, 0x5E, 0x90, 0x3C, 0x97, 0x75, 0xF2, 0x76, 0x7C, 0x33, 0x53, 0xC7, 0x16, 0x3D, 0xC0, 0x28, 0x50, 0xBD, 0xB0, 0x05, 0x33, 0x43, 0x79, 0x93, 0xBF, 0xA7, 0xA6, 0x3F, 0xED, 0xDE, 0x52, 0xEE, 0xC8, 0x09, 0x43, 0xBA, 0xA1, 0xEF, 0x25, 0x9A, 0xF1, 0x4B, 0x5D, 0x70, 0xCC, 0xE4, 0xD3, 0xA9, 0x38, 0xD6, 0xCC, 0xEA, 0x40, 0x2C, 0x6A, 0x6E, 0xB5, 0xA8, 0x16, 0x1E, 0x92, 0x17, 0x3C, 0x24, 0x27, 0x90, 0x0B, 0x37, 0x20, 0xB8, 0xAD, 0x09, 0xAD, 0x06, 0x85, 0xD2, 0xD0, 0x81, 0xEA, 0x93, 0xAC, 0xE8, 0x09, 0x63, 0xCE, 0xC2, 0x10, 0xFD, 0x5E, 0xAB, 0xD2, 0x50, 0xCE, 0x6F, 0x73, 0x47, 0xA6, 0xF2, 0xD3, 0x83, 0xD6, 0xD6, 0x08, 0x8C, 0xB1, 0xCF, 0x93, 0xC9, 0xC7, 0x4F, 0x40, 0x05, 0x90, 0x07, 0xE8, 0xDC, 0x91, 0xC7, 0x1B, 0x98, 0xEB, 0xAD, 0x63, 0xFE, 0x24, 0xCA, 0xD8, 0x2D, 0x02, 0xC2, 0xDB, 0x33, 0x53, 0x37, 0x66, 0x3F, 0xCD, 0xD5, 0x36, 0x2D, 0x77, 0xA6, 0x31, 0x90, 0xD7, 0x4F, 0x48, 0xD5, 0x1C, 0x88, 0x64, 0xBE, 0x25, 0x50, 0xEC, 0xD4, 0xA7, 0x80, 0xD8, 0x9A, 0xD2, 0x01, 0x1B, 0xE0, 0x24, 0xF0, 0x18, 0x56, 0x69, 0xB5, 0xDE, 0xD6, 0x26, 0x85, 0x6D, 0x35, 0xF3, 0x17, 0xCF, 0xEB, 0xF0, 0x8D, 0xFC, 0xCD, 0x2E, 0x84, 0x86, 0x13, 0xD7, 0x24, 0xF4, 0xCE, 0x43, 0xAF, 0xDA, 0x8C, 0x8C, 0xCF, 0x58, 0x1B, 0xBF, 0xDB, 0x10, 0x9F, 0x01, 0x54, 0x01, 0xF1, 0x85, 0x2D, 0x06, 0x60, 0xAD, 0x76, 0x3E, 0x79, 0x58, 0x6C, 0x3C, 0xC9, 0xEB, 0xB6, 0xDE, 0xA5, 0xA4, 0xE1, 0x77, 0x4D, 0x91, 0xB0, 0x87, 0x61, 0x02, 0xB3, 0x86, 0x4D, 0xFB, 0x3A, 0x0E, 0x99, 0x2C, 0x0B, 0x78, 0x03, 0xB9, 0x36, 0x14, 0xB9, 0x47, 0x9E, 0xF4, 0x82, 0x3E, 0x75, 0x01, 0x62, 0xA1, 0x79, 0xFB, 0xAC, 0xEC, 0xB1, 0xDA, 0x40, 0x33, 0x2B, 0x64, 0xA5, 0xF7, 0x12, 0x07, 0xDC, 0x75, 0x62, 0x36, 0x6F, 0x77, 0x66, 0x7B, 0x13, 0x53, 0x78, 0x43, 0xD0, 0xFB, 0x61, 0xE8, 0x56, 0x6B, 0xFD, 0x34, 0xD0, 0x7B, 0x42, 0x4C, 0x6C, 0x34, 0xD8, 0x0C, 0x13, 0x17, 0xA0, 0x03, 0x70, 0x52, 0x3D, 0x76, 0xA2, 0x8C, 0x02, 0x8F, 0x77, 0xD4, 0xB6, 0x61, 0x62, 0xE9, 0xB0, 0x78, 0x79, 0x77, 0xF4, 0x67, 0x1A, 0xDD, 0x2D, 0xD2, 0x82, 0x9E, 0x37, 0xCE, 0x1F, 0x76, 0xC8, 0xDC, 0xDF, 0x93, 0x05, 0x2F, 0x25, 0x72, 0x00, 0x0B, 0x80, 0xAA, 0x79, 0x2E, 0x40, 0xF5, 0xC2, 0x81, 0x58, 0xA8, 0x01, 0xF7, 0xDF, 0x12, 0x7F, 0xF2, 0x00, 0xB3, 0x35, 0xCC, 0x61, 0x68, 0xF0, 0x65, 0xF9, 0x4B, 0x69, 0xF6, 0xEC, 0xEB, 0xBB, 0xAB, 0xCB, 0x0F, 0x69, 0xB3, 0xBD, 0xE8, 0xE5, 0x0E, 0xE8, 0xC9, 0x57, 0x38, 0x8C, 0xFE, 0x34, 0xFF, 0x08, 0x4D, 0x0F, 0xAF, 0xF4, 0x5F, 0x21, 0x7D, 0xE0, 0xD1, 0x9E, 0xA7, 0xB7, 0x2B, 0xAE, 0x2E, 0x8D, 0xBC, 0x9D, 0xFA, 0x53, 0x7E, 0xDC, 0xF4, 0x0A, 0xCA, 0xA5, 0x35, 0xE0, 0x8F, 0x62, 0x58, 0x71, 0xC8, 0xDD, 0x5E, 0x39, 0x8D, 0xBB, 0x65, 0xBB, 0x2E, 0xBC, 0x81, 0x61, 0x50, 0xC7, 0xEF, 0x55, 0x4E, 0x0C, 0x0F, 0x3B, 0x3E, 0x81, 0xF7, 0x01, 0xB4, 0xF9, 0x26, 0xAD, 0x26, 0xA8, 0x91, 0xAC, 0x81, 0xD5, 0x6A, 0x2E, 0x67, 0xA4, 0x9B, 0xA1, 0x96, 0xCE, 0x36, 0x39, 0x44, 0x0B, 0x69, 0x7C, 0x59, 0xF7, 0xC9, 0xC3, 0x3E, 0xAD, 0x1F, 0xEC, 0x7C, 0xFA, 0xB8, 0x2F, 0x3C, 0x01, 0x8B, 0x85, 0x2E, 0x1A, 0x28, 0xFA, 0x7C, 0x59, 0x0E, 0x79, 0x65, 0x34, 0xBC, 0x1A, 0x1F, 0x4C, 0x42, 0x2B, 0x85, 0x9D, 0xEC, 0x5C, 0xD9, 0xCB, 0xF1, 0xE9, 0xC9, 0x9D, 0x1C, 0xE9, 0xF4, 0xC1, 0xFA, 0x7C, 0x52, 0x81, 0x04, 0x90, 0x00, 0xA2, 0xEE, 0x03, 0x48, 0x2E, 0xC2, 0x00, 0xE5, 0x44, 0x99, 0xCF, 0x89, 0xA5, 0xF6, 0x95, 0xA6, 0xD5, 0x74, 0x53, 0xD4, 0xE7, 0x87, 0x74, 0x41, 0x2D, 0xBD, 0x24, 0xF4, 0x9E, 0x46, 0x30, 0xD2, 0xCB, 0x7F, 0xA8, 0xB4, 0x3D, 0x44, 0xE5, 0xE5, 0x56, 0x9B, 0x4B, 0xEB, 0x9B, 0xC5, 0x62, 0x22, 0x8F, 0xA6, 0xB4, 0x0A, 0x90, 0x03, 0x84, 0x00, 0x9A, 0xC0, 0x31, 0x40, 0xA9, 0x68, 0xCD, 0x9A, 0xF8, 0xDC, 0x1B, 0x7E, 0xBD, 0xF3, 0x66, 0x07, 0x9E, 0xDA, 0xE3, 0x44, 0x2A, 0x9E, 0x4D, 0x1A, 0xA0, 0x1C, 0x22, 0xB3, 0x01, 0x23, 0x98, 0x5F, 0xC9, 0x0E, 0x4E, 0xEB, 0x9F, 0x48, 0xA0, 0x9B, 0x2D, 0x09, 0x81, 0xD8, 0x3B, 0xFD, 0x51, 0xC0, 0x6C, 0x21, 0x80, 0x1E, 0xE0, 0x30, 0x9F, 0xDA, 0x6E, 0xA9, 0xF0, 0x34, 0x1A, 0xCD, 0x30, 0x6B, 0x5D, 0x31, 0x36, 0x05, 0x46, 0x8B, 0xD6, 0x5D, 0x7E, 0x63, 0x05, 0x7B, 0x05, 0xBF, 0x7E, 0x1C, 0x9B, 0xBB, 0x38, 0x9D, 0x1D, 0xF7, 0xAA, 0xC6, 0x63, 0x84, 0x3F, 0x22, 0x43, 0x6C, 0xF2, 0x0C, 0x8C, 0x2E, 0x1C, 0xE8, 0x5A, 0xB0, 0x19, 0xE5, 0xDB, 0x08, 0x54, 0xFD, 0xD1, 0x7A, 0x51, 0xF6, 0x55, 0xA4, 0xBA, 0x90, 0xE0, 0xA1, 0xEC, 0x97, 0x78, 0xF2, 0x9A, 0x3F, 0xD7, 0x69, 0x7A, 0x96, 0x84, 0xDD, 0xE0, 0x64, 0x1D, 0x8D, 0x05, 0x14, 0x85, 0x90, 0x0F, 0x60, 0x03, 0x34, 0xD5, 0x26, 0x0B, 0x68, 0xBD, 0x91, 0x0D, 0xF8, 0xC2, 0x02, 0x40, 0xA2, 0xEB, 0xDB, 0x9A, 0x65, 0x1C, 0x2B, 0x40, 0x37, 0x22, 0x1D, 0x95, 0x5B, 0xB7, 0xE6, 0xB8, 0x36, 0xB6, 0x50, 0x96, 0x0D, 0xDE, 0x86, 0xAA, 0xED, 0x4C, 0x69, 0x6F, 0x1D, 0xED, 0xF4, 0xC7, 0x81, 0x5B, 0x74, 0x6F, 0xD0, 0x0D, 0x08, 0x60, 0xC5, 0x03, 0xA8, 0x9E, 0x97, 0x40, 0xE9, 0xDD, 0x63, 0x77, 0xD6, 0x06, 0x79, 0x7D, 0x5D, 0x8A, 0xDD, 0xFA, 0xA3, 0xAD, 0xD1, 0xFB, 0x57, 0x3C, 0xE5, 0xE7, 0xF4, 0xFB, 0x04, 0x3E, 0xD1, 0x5F, 0x64, 0x6B, 0x6C, 0x69, 0xA0, 0xA8, 0x4F, 0xED, 0x80, 0x14, 0x60, 0x0E, 0xE4, 0xE6, 0x2B, 0x9D, 0x04, 0xD4, 0x6E, 0x48, 0x02, 0x27, 0x16, 0x67, 0x31, 0xC0, 0x33, 0x3D, 0x99, 0xFB, 0xF2, 0xD1, 0x61, 0x3E, 0xD3, 0xF0, 0x84, 0x9E, 0x41, 0x09, 0xF3, 0x41, 0x38, 0x21, 0x4D, 0xB7, 0x21, 0xF7, 0xCF, 0x68, 0xA9, 0x14, 0x41, 0x04, 0x52, 0x9E, 0xF4, 0x2E, 0xE6, 0x33, 0xEE, 0xD8, 0x38, 0xB7, 0x6B, 0x59, 0xD9, 0x50, 0x71, 0x80, 0xDE, 0x9F, 0x89, 0xAE, 0x79, 0xD6, 0x9D, 0x96, 0x67, 0xC5, 0x43, 0x75, 0x95, 0x44, 0x04, 0x88, 0x1F, 0xF6, 0x7C, 0xEE, 0xF9, 0xB4, 0xE9, 0xA2, 0x60, 0x6B, 0x0D, 0xA0, 0x09, 0xD0, 0x27, 0x58, 0x0A, 0x44, 0x2F, 0x72, 0x61, 0x40, 0x7E, 0x6A, 0x64, 0x6D, 0x11, 0x84, 0x01, 0xBE, 0xB0, 0x03, 0x68, 0x00, 0x66, 0x40, 0x3B, 0x6D, 0x96, 0x30, 0x16, 0x2F, 0xC0, 0x9E, 0x2B, 0x48, 0xEB, 0xDB, 0x74, 0x77, 0x7E, 0x73, 0x55, 0xA4, 0x7F, 0x68, 0xCB, 0xD5, 0x65, 0xE8, 0xB7, 0xED, 0xA0, 0x1A, 0x50, 0xF1, 0xE4, 0x51, 0xED, 0x9C, 0xA1, 0xE3, 0x85, 0x75, 0xE2, 0x0D, 0x88, 0xAF, 0xA7, 0x7F, 0x7F, 0x56, 0x06, 0xE4, 0x1A, 0x8B, 0x96, 0x98, 0xED, 0x96, 0x97, 0xFE, 0xA9, 0x98, 0xF6, 0x45, 0x01, 0x69, 0x0B, 0xC8, 0x98, 0xEC, 0x2B, 0xF1, 0x27, 0xE6, 0xBD, 0xBA, 0xDD, 0x79, 0x90, 0x3F, 0x70, 0x1A, 0x18, 0x83, 0x2A, 0x89, 0x2E, 0x22, 0x80, 0x5E, 0x85, 0x80, 0x53, 0x80, 0xC8, 0x22, 0x01, 0x55, 0xC0, 0x16, 0x11, 0x8B, 0x04, 0xAA, 0x69, 0xB3, 0xFA, 0x87, 0x7F, 0xE8, 0xA0, 0xE9, 0x56, 0x69, 0x67, 0x8B, 0x68, 0x0D, 0x37, 0x85, 0x72, 0xFD, 0x17, 0xF2, 0x5C, 0xDD, 0xCC, 0xF3, 0xED, 0x8D, 0x22, 0x03, 0x24, 0xDB, 0xB0, 0xB3, 0xC4, 0x2E, 0x77, 0x9C, 0x99, 0xDC, 0x73, 0x45, 0x13, 0x10, 0xBB, 0x97, 0x9B, 0x48, 0xC6, 0x4A, 0xB6, 0x15, 0x9E, 0xED, 0x00, 0x0B, 0x18, 0xE4, 0x08, 0x10, 0x0A, 0x9C, 0xB5, 0xA0, 0x7C, 0x84, 0x93, 0x65, 0x71, 0x74, 0x11, 0x5B, 0xC0, 0x3E, 0xFB, 0xC9, 0x00, 0x49, 0x40, 0x0D, 0xF0, 0x06, 0x7A, 0x2D, 0xAF, 0x0E, 0xF8, 0x59, 0xD8, 0xA2, 0x81, 0x10, 0x20, 0x0F, 0x50, 0xA8, 0x71, 0x7F, 0x0F, 0x1C, 0xBD, 0x9B, 0x73, 0xFF, 0x8E, 0xF2, 0x53, 0xB3, 0xAE, 0xCE, 0x60, 0x42, 0xCE, 0xCE, 0x07, 0x87, 0x5B, 0x2B, 0xE8, 0x34, 0x9E, 0x57, 0x4E, 0xC3, 0xFC, 0x6E, 0xA1, 0x97, 0xAC, 0x76, 0x2A, 0x81, 0x25, 0x38, 0xDC, 0x52, 0x16, 0x06, 0xE8, 0x6A, 0xD4, 0x96, 0x03, 0xED, 0x8F, 0x5F, 0x71, 0xDD, 0x76, 0x5B, 0x8A, 0xBA, 0x7F, 0x35, 0x0D, 0xE2, 0x07, 0x0F, 0x67, 0xD8, 0x26, 0x6F, 0x83, 0x55, 0x0E, 0x68, 0x01, 0xB9, 0x3F, 0x3B, 0xFB, 0xE6, 0x49, 0xA0, 0xD6, 0x82, 0x6A, 0x80, 0x2F, 0x72, 0xED, 0x29, 0x0E, 0xD4, 0x01, 0xA6, 0x17, 0xB3, 0x30, 0xA0, 0x63, 0xB1, 0x66, 0x3D, 0x02, 0xD4, 0x63, 0x33, 0x9C, 0xCE, 0xFC, 0x38, 0x86, 0xF0, 0xA7, 0xAD, 0x59, 0x9D, 0x42, 0x18, 0xD7, 0xE3, 0x77, 0x3A, 0x52, 0x0D, 0xB4, 0x5C, 0xE9, 0x60, 0x43, 0x96, 0x4F, 0x92, 0x3C, 0x0F, 0x69, 0x3C, 0x8F, 0x2D, 0xA2, 0x00, 0xFF, 0xA4, 0x62, 0x49, 0x2F, 0x1C, 0xB8, 0x95, 0x28, 0x6A, 0x1F, 0xB2, 0x77, 0x1E, 0x13, 0x90, 0xFB, 0xB9, 0xC2, 0x0A, 0xF3, 0x18, 0xEA, 0x2E, 0x57, 0xBE, 0xAB, 0xA4, 0xE4, 0xFC, 0x5D, 0x40, 0x78, 0x5B, 0xCD, 0x37, 0x85, 0x2B, 0xFF, 0xCE, 0xBB, 0x05, 0x14, 0x7B, 0x2D, 0x3B, 0x50, 0x06, 0x64, 0x01, 0x1E, 0x80, 0xE8, 0xBD, 0xC5, 0x1F, 0x03, 0x38, 0x3B, 0xE3, 0xA0, 0x00, 0x37, 0x8F, 0xFE, 0xAC, 0xE6, 0x19, 0x57, 0x2D, 0xA8, 0x8C, 0xFC, 0xE0, 0x11, 0x28, 0x9F, 0x94, 0xFB, 0x68, 0xAB, 0x5F, 0x47, 0x07, 0x2F, 0x04, 0x34, 0x10, 0x51, 0x09, 0x24, 0x1F, 0x12, 0xB2, 0x38, 0x40, 0xD6, 0xAB, 0x1F, 0x83, 0xA5, 0xFE, 0xCE, 0xD4, 0xF0, 0xA7, 0x8E, 0x06, 0xCB, 0x25, 0x2F, 0xFE, 0x09, 0xB0, 0xCE, 0xAE, 0xEC, 0x63, 0xB5, 0x79, 0x9A, 0xFF, 0xAC, 0xD5, 0x9C, 0x4E, 0x2E, 0x80, 0x25, 0x09, 0x32, 0x40, 0xCE, 0x6D, 0xA0, 0x51, 0xA0, 0xFD, 0xD3, 0x52, 0xE2, 0x93, 0x1E, 0x33, 0x7C, 0xF3, 0xD0, 0x6A, 0x42, 0x45, 0x32, 0xB6, 0xDB, 0x84, 0x53, 0xED, 0x38, 0x8E, 0x6E, 0xA1, 0xDB, 0xEE, 0x1A, 0x90, 0x83, 0xBA, 0xB3, 0x56, 0x63, 0x00, 0xEF, 0x73, 0x65, 0xA7, 0x49, 0x98, 0x74, 0xBB, 0x46, 0xD0, 0x00, 0xAC, 0x81, 0xDB, 0x97, 0x88, 0x3F, 0x94, 0x0F, 0xEF, 0xD2, 0x29, 0xCB, 0x1D, 0x02, 0xB1, 0x97, 0xE6, 0xE7, 0xDF, 0xF7, 0xEE, 0xC9, 0xC3, 0xB6, 0xF8, 0x11, 0x80, 0xF7, 0x7B, 0x55, 0x1A, 0xE0, 0x51, 0x4E, 0x76, 0x8A, 0xF4, 0x3F, 0xBE, 0xF7, 0x73, 0x00, 0x53, 0xE0, 0xAF, 0xD5, 0x0D, 0x90, 0xB1, 0x28, 0x20, 0x1C, 0xB0, 0x06, 0xD4, 0x01, 0x3F, 0x7B, 0x1E, 0x54, 0x5A, 0x4D, 0xB1, 0xF6, 0x4B, 0xAF, 0x3E, 0x7A, 0xFC, 0x32, 0x3C, 0xE2, 0xC4, 0x66, 0x29, 0xF6, 0x86, 0x4B, 0x63, 0x25, 0x8B, 0x65, 0x27, 0x8A, 0x52, 0xE7, 0xE4, 0xCE, 0x8B, 0xB4, 0x2B, 0xC3, 0xAF, 0xDE, 0x1A, 0x15, 0xA0, 0x14, 0xF0, 0x01, 0x34, 0x80, 0xB3, 0xD0, 0x3E, 0x6F, 0x02, 0x50, 0x3C, 0x5E, 0x9B, 0xD8, 0x30, 0x6F, 0xB0, 0xC7, 0xC8, 0x79, 0x6F, 0x81, 0xB5, 0xAF, 0xC4, 0xE7, 0x7E, 0x5A, 0x6B, 0x27, 0xD9, 0x53, 0x7F, 0x2C, 0xE0, 0x0E, 0xC6, 0x29, 0xD3, 0x80, 0xE2, 0xB9, 0x59, 0x00, 0x0A, 0x36, 0x85, 0x03, 0x93, 0x0B, 0x03, 0x6A, 0xE1, 0x02, 0xC8, 0x00, 0x8F, 0xE6, 0xDA, 0x63, 0x35, 0xC3, 0x09, 0xF2, 0xE0, 0x2A, 0x20, 0xC7, 0x7F, 0x2A, 0x4E, 0x69, 0x2B, 0xB9, 0x69, 0xB6, 0x43, 0x55, 0x36, 0xE6, 0xDB, 0xE8, 0xA0, 0xD5, 0x7D, 0x8F, 0x35, 0x50, 0x9E, 0x65, 0x4A, 0xF5, 0x95, 0x96, 0x40, 0xA8, 0xF2, 0x42, 0x19, 0x10, 0x0A, 0xD8, 0xC2, 0x9F, 0xD6, 0xA0, 0x5C, 0x98, 0x76, 0x6E, 0xC9, 0x82, 0x2E, 0xEA, 0xE2, 0x7D, 0xBC, 0x01, 0x5F, 0x33, 0x57, 0x01, 0xED, 0xEF, 0x2B, 0xF5, 0x17, 0x2A, 0xB7, 0x75, 0x97, 0x14, 0x6C, 0xE8, 0x73, 0x07, 0xF6, 0x42, 0x98, 0x29, 0x0D, 0xD4, 0x27, 0x76, 0x2C, 0xCA, 0x96, 0x35, 0x40, 0x0E, 0x10, 0x02, 0xE4, 0x93, 0xC0, 0x4C, 0xAB, 0x39, 0xC4, 0x61, 0x6D, 0xD0, 0xCA, 0x56, 0xF3, 0x5F, 0x31, 0x7D, 0xA3, 0x9E, 0xAE, 0x98, 0x1D, 0xF9, 0x83, 0x6A, 0xFC, 0x0C, 0x32, 0xA2, 0x57, 0xFE, 0x50, 0xCC, 0xA7, 0x3D, 0x17, 0x5D, 0x65, 0x3C, 0xF8, 0x9D, 0x02, 0x24, 0x3F, 0xC6, 0x6B, 0x20, 0x15, 0x68, 0x4E, 0x54, 0xDA, 0xC2, 0xB9, 0x8E, 0xEF, 0x78, 0x72, 0x5E, 0x57, 0x83, 0xD7, 0x6B, 0x16, 0x57, 0x51, 0xF9, 0x10, 0x90, 0xAB, 0x41, 0x50, 0x3C, 0x15, 0xCA, 0x52, 0x77, 0x2B, 0x54, 0xA6, 0x22, 0x68, 0x00, 0xE1, 0x54, 0x1B, 0xB8, 0xD5, 0x98, 0x4F, 0x2F, 0xD8, 0x2A, 0x61, 0xC1, 0x37, 0xED, 0x00, 0xB1, 0x6F, 0xEA, 0xD0, 0x6A, 0x3C, 0xA4, 0xF1, 0x9A, 0xAB, 0xD0, 0xA0, 0x7C, 0x12, 0x28, 0x98, 0x28, 0xB2, 0xC9, 0x32, 0x8C, 0xFA, 0xAA, 0xE0, 0x8E, 0x7E, 0xDF, 0x09, 0x58, 0x89, 0xDA, 0xC2, 0x54, 0x4D, 0xD6, 0x38, 0x2D, 0x72, 0x71, 0xFA, 0xEE, 0x01, 0x34, 0x07, 0x28, 0x76, 0x5D, 0x0B, 0x66, 0x1B, 0xEC, 0xB1, 0x85, 0xC3, 0x81, 0xBE, 0xFE, 0x5C, 0x08, 0xC0, 0x1B, 0x97, 0x18, 0xD0, 0xFD, 0xF6, 0xE4, 0x88, 0xA7, 0x97, 0xF8, 0xF4, 0x9E, 0xED, 0x37, 0x28, 0xE7, 0xCF, 0xD9, 0x09, 0xE8, 0xCD, 0xB1, 0xB1, 0x03, 0x44, 0x02, 0xA5, 0x40, 0x2F, 0x46, 0xD9, 0xAB, 0x00, 0xD0, 0x01, 0xAC, 0x80, 0x0C, 0xDA, 0x2C, 0x7F, 0x93, 0xC6, 0x5C, 0xB7, 0x65, 0x56, 0x6F, 0x88, 0xB5, 0xB0, 0x48, 0x1C, 0x47, 0xD4, 0xA5, 0x04, 0x0F, 0xA7, 0x56, 0x65, 0x3D, 0x71, 0xA2, 0xBD, 0x83, 0xC6, 0xD4, 0x2E, 0x79, 0x2A, 0xAE, 0x45, 0xD7, 0x5B, 0x61, 0x77, 0x3F, 0x9A, 0x6E, 0xC0, 0x0B, 0x38, 0x09, 0x48, 0xE2, 0x95, 0xE6, 0x8D, 0x3B, 0x6E, 0xAD, 0x2A, 0x37, 0x40, 0xA9, 0x19, 0x7D, 0x00, 0x73, 0xBC, 0xD2, 0x85, 0x4F, 0x67, 0x5F, 0xB1, 0x1F, 0xFE, 0x3A, 0xA0, 0x0B, 0x03, 0xA0, 0x94, 0x52, 0xAE, 0x5B, 0xBB, 0x44, 0x14, 0xF0, 0x02, 0x7A, 0x0D, 0x79, 0x64, 0x11, 0x1F, 0x38, 0x20, 0xB2, 0x68, 0x20, 0x85, 0x36, 0xAB, 0xCD, 0xE2, 0xF5, 0x2D, 0x52, 0x48, 0xC8, 0x85, 0xA9, 0xC3, 0xFF, 0xB2, 0x0F, 0x71, 0x13, 0xDD, 0x14, 0x5D, 0x11, 0xC4, 0x8E, 0x71, 0x2E, 0xF8, 0x24, 0x0F, 0x51, 0x44, 0xF3, 0x51, 0xB5, 0xDE, 0xC5, 0x68, 0x58, 0xDB, 0x63, 0xC0, 0x09, 0x4A, 0x39, 0x01, 0x31, 0x40, 0x53, 0xA9, 0x38, 0x76, 0x3E, 0xE5, 0x9A, 0xF7, 0x49, 0xF5, 0x06, 0xF4, 0xB0, 0xF5, 0x3D, 0x70, 0xCE, 0x9A, 0xDE, 0x00, 0x3C, 0xCC, 0xA7, 0xA5, 0xCB, 0x14, 0x33, 0xA7, 0xD6, 0xAE, 0xB1, 0x36, 0x77, 0xA0, 0x95, 0x31, 0xF9, 0x5B, 0x74, 0x59, 0x06, 0xF0, 0x04, 0xE2, 0x00, 0x1E, 0x80, 0x0D, 0xE0, 0x02, 0x04, 0x95, 0xA0, 0x82, 0x46, 0x6B, 0x6C, 0x4A, 0x29, 0xB8, 0xE6, 0x78, 0xFC, 0x0C, 0x3A, 0x96, 0xEB, 0xCC, 0x31, 0xF8, 0xA0, 0x72, 0xB7, 0x5D, 0xB1, 0x6D, 0x81, 0xD7, 0x97, 0x30, 0xDD, 0xA3, 0x8D, 0xDE, 0x6F, 0xD3, 0x54, 0xF1, 0xC7, 0xDF, 0x29, 0x06, 0xA4, 0x7E, 0x1A, 0x66, 0x0C, 0x20, 0x09, 0xF0, 0x4D, 0x76, 0x20, 0xC9, 0x79, 0xF5, 0x27, 0x72, 0x81, 0xE4, 0x0F, 0x58, 0xD2, 0x00, 0x65, 0xF9, 0xF1, 0xB9, 0x9B, 0xB8, 0x60, 0xDC, 0x6D, 0x90, 0xC4, 0x7C, 0x8D, 0x86, 0x43, 0x03, 0x0C, 0x23, 0x40, 0x53, 0x16, 0xB7, 0x80, 0x59, 0x19, 0xAC, 0x48, 0x60, 0x74, 0x11, 0x8B, 0x03, 0x54, 0x2D, 0x14, 0x18, 0x7A, 0x01, 0x9C, 0x46, 0x63, 0xF2, 0xD9, 0x1E, 0x2F, 0x0A, 0xB6, 0x0B, 0x33, 0xFC, 0x49, 0x54, 0x95, 0xF4, 0x86, 0x1B, 0xA6, 0x62, 0x03, 0x11, 0xBF, 0xD9, 0xE9, 0xB1, 0xAE, 0xA1, 0x6F, 0xC7, 0xA4, 0x48, 0x2E, 0x54, 0xC2, 0x6F, 0xF6, 0x99, 0x90, 0x8A, 0x87, 0xCE, 0x15, 0xF8, 0x5A, 0x6C, 0xED, 0x71, 0x1F, 0x3E, 0xB9, 0x2E, 0xB9, 0x0B, 0x55, 0xE1, 0xD3, 0x1C, 0xC0, 0xFC, 0x2E, 0xCA, 0xB1, 0x04, 0x42, 0xF1, 0x26, 0x66, 0xA9, 0x3D, 0x9E, 0x1E, 0xA6, 0x76, 0x8C, 0xB2, 0x2B, 0x3C, 0x10, 0x8B, 0xF1, 0xB5, 0x5D, 0x03, 0xBD, 0xB6, 0x3B, 0xB1, 0x98, 0x1B, 0x72, 0x16, 0x06, 0xD8, 0x63, 0xC9, 0x35, 0x1A, 0xFB, 0xFE, 0xED, 0xDF, 0x59, 0x55, 0x68, 0x66, 0xDE, 0xBE, 0x31, 0x91, 0x5A, 0xFF, 0x8D, 0xC3, 0xD3, 0xA3, 0x8D, 0x37, 0xB5, 0xAF, 0x8C, 0x2B, 0xFB, 0x74, 0x69, 0x54, 0xD6, 0x8B, 0xB1, 0xD7, 0x70, 0x31, 0x40, 0x34, 0x6C, 0xC6, 0x0C, 0xC4, 0x01, 0xD4, 0x01, 0xEE, 0x0A, 0x7E, 0x65, 0xEC, 0x15, 0x4C, 0x81, 0x06, 0x3A, 0xB7, 0x99, 0x54, 0xEE, 0x83, 0x80, 0x38, 0xE0, 0xB9, 0x76, 0x45, 0x9A, 0xD1, 0x02, 0x25, 0xEE, 0xD8, 0x07, 0x72, 0x53, 0x35, 0x76, 0x51, 0x72, 0x5B, 0xB7, 0x53, 0x00, 0xC9, 0xD5, 0xDD, 0x80, 0x6C, 0xA0, 0x62, 0xC1, 0x87, 0xB5, 0x08, 0xA0, 0x63, 0xFD, 0x54, 0x46, 0xA3, 0xC9, 0x86, 0xFF, 0x72, 0xEB, 0xA1, 0x0D, 0x3F, 0xDB, 0x3A, 0xE3, 0xCE, 0x82, 0xC3, 0xCF, 0xF5, 0x87, 0xA3, 0x8D, 0x2F, 0xED, 0xFE, 0x9B, 0x8F, 0x74, 0x42, 0x2A, 0x8D, 0x46, 0x4D, 0x2A, 0x06, 0x21, 0x85, 0xFB, 0xE4, 0x61, 0xA0, 0x91, 0x52, 0xB7, 0x40, 0x2C, 0x64, 0x00, 0xDF, 0x98, 0x2D, 0x86, 0x11, 0xBF, 0xF5, 0x79, 0x7C, 0x8A, 0x87, 0x99, 0x65, 0xEC, 0x87, 0xB4, 0x63, 0xAB, 0x8C, 0xEE, 0x4A, 0xE0, 0xA9, 0xFB, 0xA2, 0xE7, 0xEE, 0x87, 0x5D, 0xAD, 0x39, 0x2F, 0xFD, 0x3C, 0x53, 0x50, 0x15, 0x60, 0xEA, 0x8C, 0x26, 0x30, 0x4E, 0xBF, 0xDA, 0xA2, 0x00, 0x5D, 0x1C, 0xBE, 0xD2, 0xF8, 0x24, 0x1F, 0xB9, 0xEA, 0x10, 0xE6, 0xDC, 0xF2, 0x5F, 0xBC, 0xF7, 0xC0, 0x6C, 0xEB, 0xEE, 0x16, 0x6C, 0x3C, 0xC7, 0xF1, 0xEB, 0x96, 0x9B, 0x30, 0xFC, 0x33, 0xDA, 0xD0, 0x09, 0x39, 0xB7, 0x82, 0xB0, 0xCF, 0xD9, 0x13, 0xD1, 0x8E, 0x8D, 0x9A, 0xFD, 0xB6, 0x0E, 0xD0, 0x33, 0xCD, 0x6F, 0x3B, 0x8B, 0x62, 0x53, 0xAE, 0x7A, 0x4F, 0xE6, 0xC8, 0x6B, 0xC1, 0x84, 0xF2, 0xCF, 0xF2, 0xDC, 0x40, 0x16, 0xD0, 0x06, 0x83, 0x24, 0x53, 0x75, 0xD7, 0xDF, 0x11, 0x74, 0x0E, 0xFD, 0x10, 0xEB, 0x27, 0xC9, 0x47, 0xE6, 0xAA, 0x75, 0x75, 0x6F, 0x0B, 0x68, 0x5B, 0x61, 0xAB, 0x04, 0x74, 0x00, 0x17, 0x20, 0x1C, 0xA8, 0x6D, 0xAE, 0x77, 0x0E, 0x20, 0x0E, 0x58, 0xD1, 0x66, 0x06, 0xDF, 0x52, 0xF4, 0xEF, 0xFE, 0x54, 0x31, 0xD7, 0x95, 0x3D, 0x74, 0x7D, 0x44, 0x01, 0x47, 0x47, 0x68, 0xA2, 0x77, 0x7D, 0x07, 0xF3, 0x5F, 0x3E, 0xD1, 0x28, 0xFB, 0x0F, 0x49, 0x9D, 0x5C, 0xC4, 0xC2, 0x06, 0xD0, 0x5E, 0x1C, 0x3E, 0xBC, 0x1D, 0x1D, 0x67, 0xAF, 0x5F, 0x36, 0x0B, 0xBD, 0x6F, 0xAB, 0xCA, 0xB2, 0x84, 0x4F, 0x28, 0x5A, 0xE4, 0xD3, 0x1C, 0xDA, 0x59, 0xCE, 0xC9, 0x5A, 0xEE, 0xBD, 0xBB, 0x0E, 0x03, 0xBE, 0x71, 0xEB, 0x35, 0x9B, 0x7D, 0x72, 0xBD, 0x17, 0xF1, 0x11, 0x3E, 0xEE, 0x00, 0xC2, 0x80, 0x52, 0xBE, 0x49, 0xAB, 0x39, 0xDC, 0x5F, 0x9B, 0x00, 0x63, 0x57, 0x41, 0x41, 0xED, 0x2C, 0x53, 0xA4, 0x40, 0xFE, 0x0A, 0x8F, 0xF5, 0xE7, 0xB3, 0xAD, 0xD4, 0xB9, 0x1D, 0x1D, 0xE4, 0xF4, 0x8F, 0xFA, 0x2A, 0x50, 0x00, 0x46, 0x1C, 0x80, 0x02, 0x32, 0x13, 0x40, 0xE7, 0x3E, 0x3C, 0x40, 0xCF, 0x1E, 0x8E, 0xD7, 0x42, 0x55, 0x40, 0xF3, 0x36, 0xD6, 0x40, 0x14, 0xE0, 0x0E, 0x68, 0x00, 0x11, 0x6F, 0xC3, 0x11, 0xD1, 0xA7, 0xF0, 0xC9, 0x87, 0x69, 0x96, 0x6B, 0x0C, 0x65, 0x56, 0x3B, 0xE0, 0x0D, 0x0C, 0x37, 0x22, 0x01, 0x5A, 0x17, 0x02, 0x64, 0x02, 0x1E, 0x80, 0x0E, 0xE0, 0xBC, 0x3B, 0x28, 0xCD, 0x16, 0x7B, 0x00, 0x6E, 0x5C, 0x3B, 0xC7, 0x2F, 0x39, 0x00, 0x5F, 0xAF, 0x9A, 0x77, 0xC0, 0x07, 0xA3, 0x06, 0xB3, 0x6D, 0x27, 0x72, 0x9A, 0xCB, 0x93, 0x83, 0xCD, 0x3F, 0xB5, 0x8C, 0x0E, 0x44, 0x00, 0x6E, 0x80, 0xF4, 0x47, 0xC7, 0xAC, 0x80, 0xD9, 0x9F, 0xE5, 0x5A, 0xCD, 0xE2, 0xEE, 0x13, 0x94, 0x07, 0x0F, 0x23, 0x6F, 0x65, 0xAB, 0x2E, 0x20, 0x0F, 0x40, 0xC3, 0x96, 0x5E, 0xDD, 0xB3, 0xFD, 0x2F, 0x15, 0xA4, 0xEF, 0xC2, 0x3D, 0xFF, 0xC8, 0x88, 0xB3, 0xC2, 0xFB, 0x2C, 0x3C, 0x16, 0x02, 0x3C, 0x49, 0x32, 0x09, 0xA4, 0x02, 0x4F, 0x99, 0x41, 0xD0, 0x6A, 0xB9, 0x0D, 0x5D, 0xEC, 0x57, 0x80, 0xA1, 0xD2, 0x97, 0x7E, 0x53, 0xF9, 0x36, 0x66, 0x49, 0x59, 0xBD, 0x02, 0x85, 0x0F, 0xD1, 0x13, 0x49, 0x57, 0xFF, 0xA9, 0xBC, 0x1C, 0xF6, 0x1F, 0x75, 0xB3, 0xC5, 0x87, 0x02, 0x58, 0x02, 0x3A, 0x77, 0x82, 0x9F, 0x27, 0xE7, 0xDF, 0xA7, 0x8E, 0xB5, 0xA9, 0x55, 0x0A, 0x48, 0x02, 0xE7, 0xC9, 0xBF, 0xDC, 0x4F, 0x3B, 0x99, 0xE3, 0x91, 0xB5, 0xF3, 0x77, 0x3A, 0xD9, 0x73, 0xE1, 0x38, 0x0E, 0xF0, 0x22, 0xA6, 0x05, 0x3C, 0x59, 0xDC, 0x8B, 0x39, 0x40, 0x27, 0x90, 0x0E, 0x98, 0x00, 0xC7, 0x01, 0x19, 0xE0, 0x6F, 0x33, 0xA8, 0xBD, 0xCF, 0xF7, 0x2F, 0x16, 0x11, 0x59, 0x50, 0x24, 0x9E, 0xC0, 0xE9, 0x61, 0x7C, 0xBB, 0xAF, 0x15, 0x6C, 0x28, 0x0E, 0x81, 0x1E, 0xAD, 0xDB, 0x3F, 0xF4, 0x5C, 0x0B, 0xFC, 0xCD, 0x3C, 0x40, 0xFA, 0x3F, 0x35, 0xA9, 0xEE, 0x86, 0xCE, 0x2E, 0xB7, 0xCA, 0x72, 0xBE, 0xBA, 0x37, 0xF3, 0x97, 0xEC, 0x5C, 0x9F, 0x8C, 0xC4, 0x8A, 0xBB, 0x63, 0x6F, 0x0B, 0x10, 0x9F, 0x12, 0xD9, 0x27, 0xA1, 0x71, 0xAF, 0xE7, 0x4F, 0x26, 0xBC, 0xDC, 0x11, 0xB1, 0x3C, 0x77, 0xE4, 0x4E, 0xEB, 0xEE, 0xFE, 0x83, 0x87, 0x6B, 0x99, 0x07, 0xF9, 0x5C, 0xD3, 0xF2, 0x00, 0xD6, 0x40, 0xF0, 0xD4, 0x7C, 0x68, 0xB5, 0xED, 0x64, 0xE9, 0xF5, 0x2F, 0x64, 0xC1, 0x58, 0xF6, 0x6F, 0xB5, 0xE9, 0x9D, 0xE0, 0xB1, 0x0D, 0xAB, 0x1B, 0xF9, 0x79, 0x53, 0xF4, 0xD8, 0xDE, 0x0D, 0xF4, 0x8C, 0xC2, 0x70, 0x57, 0xEB, 0x23, 0xB8, 0xA7, 0x00, 0xB9, 0x65, 0x43, 0xE2, 0xDC, 0xE5, 0x48, 0xC1, 0x72, 0x2F, 0x6A, 0x97, 0x38, 0x6B, 0x2F, 0x01, 0x2E, 0xEE, 0xB9, 0xD0, 0x59, 0x1C, 0xE0, 0x24, 0xF0, 0x38, 0x5B, 0x93, 0xDE, 0x88, 0x1D, 0x0F, 0x6B, 0xB4, 0x66, 0xA8, 0x98, 0x21, 0x4D, 0x07, 0x4A, 0x61, 0x03, 0x4D, 0xA0, 0x66, 0xAD, 0x15, 0x80, 0xC8, 0x8D, 0x13, 0x8B, 0x02, 0xF4, 0x00, 0xC5, 0x65, 0x6D, 0xDB, 0x1C, 0x43, 0x80, 0x62, 0x33, 0xEA, 0xF2, 0xAF, 0xCB, 0x69, 0x5A, 0x33, 0x4F, 0x79, 0xF3, 0xE4, 0xE2, 0xB7, 0x34, 0x4F, 0x24, 0x8F, 0xB6, 0x9F, 0xF2, 0xB2, 0x4B, 0x59, 0xAD, 0x1E, 0x4D, 0xA6, 0x26, 0xE4, 0x53, 0x30, 0x5E, 0x54, 0x9F, 0x7A, 0xC0, 0x57, 0xD6, 0xA2, 0xC2, 0x6A, 0x6C, 0x60, 0x12, 0x90, 0x73, 0xA7, 0x5D, 0xB8, 0x03, 0xBA, 0xE0, 0x21, 0x3A, 0xEA, 0xED, 0x0D, 0xC9, 0x0C, 0x6E, 0x44, 0x3A, 0x61, 0xAE, 0x5E, 0x3B, 0x2D, 0x78, 0x67, 0x60, 0x76, 0xB7, 0x34, 0x10, 0xBA, 0xE8, 0x85, 0x01, 0x7E, 0x00, 0x33, 0x80, 0xA7, 0xA0, 0x43, 0xF7, 0x10, 0x07, 0x5E, 0x0D, 0x62, 0x7F, 0xA7, 0xEF, 0x3C, 0x18, 0xB5, 0xCD, 0xC8, 0xC8, 0x4D, 0x0A, 0x33, 0xF4, 0xA7, 0x58, 0x59, 0xBA, 0xFE, 0x6F, 0x31, 0x3F, 0xF6, 0xC3, 0x53, 0xA0, 0x1C, 0x48, 0x05, 0x3C, 0x17, 0x07, 0xE0, 0x9B, 0x6C, 0x63, 0x36, 0xBE, 0x36, 0xE4, 0x50, 0xAD, 0x8F, 0x7E, 0xD2, 0x09, 0xD6, 0xA3, 0xFD, 0x70, 0xF2, 0x56, 0x92, 0xEB, 0xE0, 0x9B, 0xE7, 0x6D, 0x59, 0x3E, 0x7B, 0x0B, 0xD3, 0xBF, 0x8E, 0x70, 0x4D, 0xF1, 0x27, 0x20, 0x59, 0x86, 0x90, 0x40, 0x1F, 0xB6, 0x2F, 0x5D, 0x50, 0x05, 0xC9, 0x80, 0x5C, 0xD8, 0xDC, 0xCE, 0x73, 0x75, 0x5A, 0x4D, 0x30, 0x2A, 0x99, 0x44, 0x74, 0xE2, 0x5F, 0xE7, 0x53, 0x33, 0x19, 0x33, 0xDB, 0x1D, 0xDF, 0xD7, 0x23, 0xA8, 0x48, 0x0C, 0x2D, 0xBF, 0x37, 0x03, 0xA3, 0xD5, 0x7A, 0x77, 0x44, 0xDE, 0xAA, 0x14, 0x98, 0x5E, 0x38, 0x90, 0x0D, 0xF8, 0x00, 0x76, 0x00, 0xDE, 0x5D, 0xAB, 0x9E, 0xD5, 0x8D, 0x35, 0xAA, 0x40, 0xE5, 0x9D, 0x65, 0x15, 0x0D, 0x88, 0x73, 0xF9, 0xFF, 0xA1, 0xF8, 0x0B, 0xF6, 0xEA, 0x9A, 0xA8, 0x2E, 0xE0, 0x19, 0x67, 0xA1, 0x05, 0xF3, 0x61, 0x90, 0x42, 0x7B, 0x80, 0x94, 0xBD, 0xE5, 0x2E, 0x3A, 0x81, 0x6A, 0x20, 0x14, 0x10, 0xC5, 0x9B, 0x2D, 0xC0, 0xF8, 0xBE, 0x29, 0xB4, 0x9A, 0x6E, 0xA1, 0xC5, 0x20, 0x06, 0x7D, 0xF4, 0x27, 0x44, 0x61, 0xE9, 0xEC, 0xCB, 0xB5, 0x6E, 0x1C, 0xD9, 0x2A, 0x6A, 0xC3, 0xC6, 0x6F, 0x14, 0xF1, 0xFB, 0xAA, 0x37, 0xE9, 0x5A, 0xAD, 0xD6, 0x24, 0x9F, 0xCC, 0x47, 0xA1, 0xA3, 0x72, 0x11, 0x0E, 0x68, 0xBF, 0xC8, 0x27, 0xFC, 0x62, 0x1C, 0x6B, 0x29, 0x8B, 0x82, 0x29, 0xF7, 0x67, 0x93, 0x40, 0x1E, 0x40, 0x0A, 0xB0, 0xA7, 0x85, 0x5C, 0x32, 0x5D, 0x89, 0x6D, 0x33, 0xDE, 0x92, 0x32, 0x79, 0x66, 0xAF, 0x04, 0xE0, 0x03, 0x4C, 0x52, 0xF8, 0x14, 0x98, 0x58, 0x08, 0x50, 0x06, 0x78, 0x02, 0xEA, 0x77, 0xC7, 0xBD, 0x53, 0xB4, 0x9A, 0x6D, 0x03, 0xDC, 0x81, 0x9F, 0xB3, 0x1B, 0x97, 0x10, 0xAF, 0x15, 0x5A, 0xED, 0x6D, 0x86, 0x59, 0x9B, 0xBB, 0xA2, 0xAB, 0x73, 0x39, 0x1C, 0x5B, 0x57, 0xFD, 0xA7, 0xCE, 0x6E, 0x06, 0x77, 0xFA, 0xB1, 0x3D, 0x0B, 0x92, 0x26, 0xF3, 0xF3, 0x00, 0xFA, 0xAB, 0xDB, 0x00, 0xA6, 0xFD, 0xD3, 0xCF, 0xCD, 0x0B, 0xAA, 0x15, 0xD0, 0x8F, 0x0D, 0x00, 0x69, 0x26, 0x88, 0x02, 0xE6, 0x40, 0xDA, 0x5E, 0x73, 0xF9, 0xAD, 0x29, 0x53, 0xC2, 0x6A, 0xBE, 0x7C, 0x6A, 0xFB, 0xB6, 0xD2, 0x0B, 0x48, 0x6E, 0x06, 0x02, 0x74, 0xEF, 0x4A, 0x9F, 0x80, 0x09, 0xA0, 0x8B, 0x13, 0xF7, 0x3A, 0x28, 0x09, 0x34, 0xCF, 0x1D, 0x74, 0x3C, 0x0A, 0x3C, 0x6A, 0x19, 0x86, 0xD5, 0x4D, 0x0C, 0x43, 0xDB, 0x57, 0xE6, 0xDB, 0x65, 0x03, 0x2D, 0xF9, 0x3B, 0x3B, 0xA5, 0x33, 0x43, 0xED, 0xA3, 0x06, 0x20, 0x73, 0x8B, 0xA3, 0x37, 0xE7, 0x9B, 0x2C, 0x14, 0x30, 0x0E, 0x19, 0x07, 0x52, 0x16, 0x7C, 0x25, 0x9F, 0xAA, 0xF3, 0x5B, 0xE1, 0xE0, 0x49, 0xB9, 0x5D, 0x58, 0xDC, 0x4A, 0x6A, 0x65, 0xFB, 0xE9, 0x91, 0x36, 0x80, 0xF1, 0x86, 0x3B, 0xBF, 0xB0, 0x4C, 0xE6, 0xDB, 0xE3, 0x9F, 0x39, 0xEE, 0x80, 0x17, 0x30, 0xF4, 0xC8, 0x05, 0x60, 0x07, 0x50, 0x03, 0x84, 0xE0, 0x43, 0x05, 0x2A, 0x68, 0xB5, 0x37, 0x56, 0xF0, 0x33, 0xAC, 0xE3, 0xD7, 0xD7, 0x4E, 0xAD, 0xBD, 0xC9, 0x2C, 0xB1, 0x4D, 0x0B, 0x03, 0xF6, 0x45, 0x8B, 0xE8, 0x4A, 0xCE, 0x4B, 0x20, 0xF3, 0x2D, 0x52, 0x7F, 0x0A, 0xA2, 0xB0, 0x49, 0x53, 0x89, 0xEF, 0x6E, 0xE3, 0x7E, 0x18, 0x86, 0xB8, 0xF3, 0x60, 0xA3, 0xF1, 0xE6, 0xD3, 0x56, 0x9B, 0xCD, 0x50, 0x02, 0x9F, 0x32, 0x81, 0x30, 0xA0, 0x14, 0xE8, 0xC6, 0x2B, 0xC5, 0xC3, 0x04, 0xC5, 0xF5, 0x0F, 0x7D, 0xFE, 0x9B, 0xDB, 0x60, 0xB8, 0xC1, 0x9F, 0x6D, 0xF7, 0xA3, 0x0A, 0x74, 0x6F, 0x9F, 0x9F, 0x01, 0xCA, 0x80, 0x4E, 0x60, 0x72, 0x9B, 0xDB, 0x34, 0xA0, 0x06, 0x78, 0x00, 0xE1, 0x40, 0x29, 0x6D, 0x96, 0x6B, 0x33, 0x36, 0x91, 0xA8, 0xCD, 0x2D, 0x6A, 0x78, 0x6E, 0x58, 0x60, 0x98, 0x48, 0xF2, 0x63, 0x3A, 0xB5, 0xC3, 0xB1, 0xE6, 0xFE, 0xF5, 0x46, 0xE6, 0x93, 0xA8, 0xC6, 0x23, 0x14, 0x8F, 0x2D, 0x40, 0x7D, 0x64, 0xA8, 0x94, 0x89, 0xDB, 0x0A, 0xE8, 0x0F, 0xC5, 0xD4, 0x74, 0x96, 0x40, 0x02, 0x70, 0x51, 0x02, 0x6C, 0xB1, 0xCB, 0x26, 0xDB, 0xF2, 0xE9, 0x92, 0xAF, 0x8C, 0xF4, 0xB2, 0x09, 0x54, 0xC0, 0x76, 0xEC, 0x68, 0x0F, 0x9F, 0xC6, 0x59, 0x1B, 0xE0, 0x28, 0x0C, 0x4B, 0xCA, 0xE6, 0x69, 0x1C, 0xC0, 0x17, 0x29, 0x40, 0x35, 0x30, 0x9B, 0x7C, 0x23, 0x03, 0xB8, 0x02, 0x31, 0x40, 0x3F, 0x46, 0x7B, 0x0B, 0x3F, 0x1B, 0x79, 0xA4, 0xA9, 0x2C, 0x14, 0x7C, 0x62, 0xD0, 0x67, 0xDD, 0xBB, 0xE3, 0x05, 0xED, 0xB8, 0x19, 0x5E, 0x39, 0xEF, 0xD6, 0x05, 0xF6, 0x24, 0x22, 0x53, 0x0F, 0x92, 0x79, 0x16, 0x0B, 0x07, 0x6C, 0x15, 0xDE, 0x9E, 0xEB, 0xCF, 0xC2, 0xAE, 0x1E, 0xA8, 0xF6, 0xE7, 0xB7, 0xCC, 0x5B, 0x34, 0xE3, 0xB0, 0x7B, 0xC4, 0x5A, 0x59, 0x0A, 0xA0, 0xB8, 0x18, 0x3B, 0x34, 0xE6, 0x9E, 0x6C, 0xB9, 0x8A, 0x31, 0xDE, 0x52, 0xBD, 0x0E, 0xA4, 0x0D, 0xB4, 0x7C, 0xEB, 0xC7, 0xA6, 0x61, 0x57, 0x3F, 0x40, 0x0A, 0xD0, 0x07, 0x98, 0x62, 0xFF, 0xF7, 0x4F, 0x43, 0xFC, 0x02, 0xDA, 0x68, 0xB4, 0xC6, 0xDF, 0xE9, 0x70, 0x9E, 0x79, 0xE8, 0xEF, 0xF7, 0x54, 0x12, 0x5D, 0x44, 0x26, 0x31, 0x23, 0x52, 0x30, 0xD9, 0x4A, 0x57, 0x2B, 0xC3, 0xDE, 0x06, 0xEE, 0xAD, 0xE7, 0x0E, 0x4B, 0x59, 0x33, 0x0E, 0xB9, 0x37, 0xC1, 0x48, 0xA0, 0x3F, 0x69, 0xD4, 0xA6, 0x77, 0xC2, 0xB5, 0x60, 0x4C, 0x02, 0x0A, 0xA7, 0x09, 0x62, 0x55, 0x0B, 0x6E, 0x63, 0xC9, 0x91, 0x66, 0x40, 0x1C, 0xE0, 0x18, 0xE0, 0x2C, 0x03, 0xED, 0x9D, 0xB3, 0x3C, 0x92, 0xCA, 0xDB, 0xF6, 0x2E, 0xD7, 0x8D, 0x8D, 0x33, 0x37, 0xFC, 0x13, 0x0E, 0xB0, 0xDF, 0x48, 0xFA, 0x0E, 0xC6, 0x02, 0x24, 0x17, 0x02, 0x1C, 0x61, 0x0A, 0xD8, 0x3E, 0x6C, 0xA0, 0x9B, 0x46, 0x1B, 0x44, 0xEA, 0xD3, 0x7E, 0x8A, 0xB8, 0xAA, 0xF4, 0x11, 0x51, 0xF4, 0x27, 0xB8, 0xED, 0x21, 0x93, 0x47, 0xB7, 0xAE, 0x27, 0x3F, 0xDA, 0x87, 0xF6, 0xA9, 0xC4, 0xF8, 0xAA, 0xF8, 0xB9, 0x03, 0x66, 0xC0, 0xA3, 0xE6, 0x71, 0x80, 0xB2, 0x45, 0xEE, 0x2B, 0xAC, 0x08, 0xCA, 0x5B, 0x5F, 0xBA, 0xE4, 0xD3, 0x04, 0xA2, 0x81, 0xE0, 0xA7, 0x02, 0x28, 0x4D, 0x69, 0x97, 0x3E, 0x9B, 0xF0, 0xDE, 0x8D, 0x2D, 0x9D, 0xCA, 0x75, 0x9F, 0xFE, 0xBC, 0x30, 0xB3, 0x36, 0x30, 0xBB, 0xCE, 0xDA, 0xB9, 0xF0, 0x96, 0x0F, 0x00, 0x7D, 0x80, 0x69, 0xFC, 0x2C, 0x39, 0x3F, 0x59, 0x6A, 0x2A, 0x68, 0x10, 0x2D, 0x42, 0xAB, 0xD1, 0x4F, 0xB5, 0x97, 0x18, 0xB5, 0x7F, 0x28, 0x74, 0x9C, 0x75, 0x11, 0xD9, 0x2D, 0x70, 0xF2, 0x6D, 0xAB, 0xED, 0x7A, 0x9B, 0x2B, 0x03, 0x08, 0x03, 0x34, 0x80, 0x93, 0x77, 0x7B, 0xEC, 0x39, 0xAF, 0x33, 0xC9, 0x9F, 0x1A, 0x45, 0xA1, 0x0C, 0x72, 0xAE, 0x9D, 0x0A, 0x90, 0x58, 0x24, 0x70, 0xFA, 0xF6, 0x63, 0x6A, 0x53, 0xBA, 0xE2, 0x51, 0xBA, 0xA4, 0x13, 0x6C, 0xC7, 0xE1, 0x67, 0x33, 0x3D, 0xF5, 0x29, 0x52, 0x67, 0xDD, 0x58, 0x2E, 0x0A, 0x0F, 0x3B, 0x81, 0x90, 0xFF, 0x90, 0x56, 0xB3, 0xA0, 0xD5, 0x04, 0xB7, 0xB5, 0xB1, 0x7F, 0x73, 0x90, 0x0F, 0xD9, 0xB9, 0xE1, 0x82, 0x5F, 0xD0, 0x7A, 0x45, 0x15, 0x44, 0xA1, 0xCC, 0xAA, 0xDB, 0x8C, 0xDC, 0x9D, 0x89, 0x09, 0x1F, 0x01, 0x61, 0xB9, 0x5B, 0xB8, 0x9B, 0x00, 0x35, 0x40, 0x0A, 0xA0, 0xF1, 0x1F, 0x5D, 0xB9, 0x74, 0x00, 0x5A, 0xC6, 0x14, 0xE8, 0x02, 0x84, 0x6E, 0x5F, 0xBB, 0x5D, 0x70, 0xC7, 0x17, 0x05, 0xDC, 0x8D, 0x81, 0x1E, 0xCF, 0x00, 0xC3, 0xD6, 0x9C, 0xBD, 0xCC, 0xAE, 0xCF, 0xB5, 0x4C, 0x3E, 0x71, 0x7C, 0x33, 0xD8, 0xE2, 0x2C, 0xBC, 0x80, 0x38, 0x80, 0x15, 0xC0, 0x70, 0xFE, 0xF4, 0x7E, 0x0A, 0x60, 0x0E, 0xAD, 0xF6, 0x17, 0x2F, 0x48, 0xC1, 0x7D, 0x29, 0xFF, 0xC4, 0x54, 0xE7, 0x08, 0x46, 0x6C, 0xDB, 0xE3, 0x2E, 0x46, 0x37, 0x42, 0xE1, 0x69, 0xE3, 0xDE, 0x0B, 0xCE, 0xAB, 0x39, 0x84, 0xB5, 0xE3, 0x72, 0x06, 0xA5, 0xDF, 0x9D, 0xB7, 0x62, 0x6E, 0x87, 0x76, 0xD7, 0x55, 0xFB, 0x79, 0x1E, 0xB9, 0x1F, 0x1F, 0x20, 0x59, 0x3D, 0xA6, 0x40, 0xD9, 0xDD, 0x44, 0x8F, 0xD7, 0x76, 0xC6, 0x55, 0xCF, 0x5B, 0xA0, 0x63, 0xF8, 0x2B, 0xB6, 0x05, 0xCB, 0x5B, 0x28, 0x8C, 0xF8, 0x31, 0x62, 0x51, 0xB1, 0x39, 0x94, 0x0D, 0xE4, 0x01, 0x3A, 0x77, 0x21, 0x0B, 0x40, 0x1D, 0xF0, 0x02, 0x2A, 0x81, 0xD9, 0x4E, 0x4B, 0xD2, 0x34, 0x9A, 0x61, 0xF7, 0x97, 0x5A, 0x29, 0x7E, 0xFD, 0xAD, 0x6E, 0x99, 0xB6, 0x1B, 0xD2, 0x6C, 0xDF, 0xD8, 0xD8, 0x8C, 0xBF, 0x5F, 0xC0, 0x20, 0xD3, 0xEB, 0xBE, 0x4A, 0x7D, 0x25, 0x5D, 0xD9, 0x03, 0x80, 0x0D, 0x7E, 0x54, 0x80, 0xA3, 0xB7, 0xDB, 0x55, 0xFD, 0x2E, 0xAA, 0xCD, 0x8F, 0xD2, 0xFC, 0xB0, 0x6B, 0x79, 0x01, 0x46, 0x3D, 0x75, 0xFB, 0x88, 0xAC, 0x17, 0x10, 0xFD, 0xDE, 0x74, 0x11, 0xE6, 0x62, 0xBD, 0x30, 0xDB, 0x4D, 0xED, 0x15, 0xFB, 0x15, 0x36, 0xB4, 0xF3, 0x1C, 0xF5, 0x74, 0x80, 0x66, 0x36, 0x55, 0x01, 0xAD, 0x8B, 0xF9, 0xA0, 0x88, 0x8D, 0x7A, 0x09, 0x10, 0x41, 0xAB, 0x39, 0x5C, 0xC0, 0x1E, 0xFF, 0x72, 0x23, 0x8D, 0xF5, 0x93, 0x40, 0x8F, 0xDD, 0xF0, 0x75, 0x43, 0x0B, 0x0E, 0x4F, 0x82, 0xC5, 0xB6, 0x50, 0xE9, 0xDB, 0x45, 0x14, 0xDF, 0xBC, 0xAB, 0x9D, 0x30, 0x6A, 0xB7, 0x7E, 0xAA, 0xC4, 0x2D, 0xD8, 0x64, 0xBB, 0x66, 0xCD, 0xA2, 0x3F, 0xCE, 0xDB, 0x7A, 0xF2, 0x42, 0x85, 0x60, 0xFE, 0xDF, 0x0F, 0xD6, 0x8B, 0x02, 0x74, 0x80, 0x79, 0x6E, 0x6B, 0x67, 0x1D, 0xD9, 0x57, 0xC3, 0xC6, 0x0D, 0x06, 0x58, 0xBC, 0x1E, 0x47, 0xA0, 0xD7, 0xE3, 0xC3, 0x40, 0xB2, 0x26, 0x90, 0x05, 0x94, 0x01, 0x19, 0x9F, 0x98, 0x98, 0x02, 0xB9, 0xD1, 0x41, 0x4D, 0x5A, 0x2D, 0x36, 0x7D, 0xC2, 0xFE, 0xD5, 0xC6, 0xD4, 0x6B, 0x8F, 0x1F, 0xAA, 0x7F, 0x29, 0x98, 0x47, 0xB6, 0xDA, 0x67, 0xB6, 0x81, 0x9B, 0x5F, 0x3E, 0xDC, 0xFA, 0x3A, 0xD6, 0x18, 0xFC, 0xD0, 0xFA, 0xF4, 0x74, 0xFE, 0xB4, 0xD9, 0x52, 0x56, 0x6D, 0x0C, 0xC0, 0xD8, 0x89, 0x38, 0xCB, 0x12, 0x6E, 0x59, 0xF7, 0x7E, 0x8A, 0xD9, 0x01, 0xF7, 0xFF, 0x50, 0xB9, 0x2D, 0xBD, 0x44, 0xAF, 0x82, 0xBA, 0x7D, 0x2C, 0x37, 0x7E, 0xD6, 0x7D, 0x65, 0xA3, 0x67, 0x05, 0x2A, 0x77, 0x51, 0x3F, 0xB7, 0x0B, 0x43, 0x7B, 0x31, 0x80, 0xF4, 0xFE, 0x6C, 0x80, 0x9E, 0xBB, 0x3E, 0x28, 0x83, 0x56, 0x4B, 0xDC, 0x9E, 0xDA, 0x7E, 0x69, 0x6A, 0xD9, 0x90, 0x60, 0x56, 0x69, 0xAC, 0x24, 0x67, 0xB6, 0x8C, 0x75, 0x1B, 0xFB, 0x9A, 0xFC, 0xBE, 0xED, 0xE9, 0xBC, 0x55, 0xFC, 0xF4, 0x73, 0x03, 0x75, 0x46, 0x3D, 0x8C, 0x8D, 0x7E, 0x80, 0xCA, 0xBB, 0x91, 0x76, 0x0E, 0x20, 0xEC, 0xC8, 0x72, 0x65, 0xFC, 0xE1, 0x72, 0x73, 0x39, 0xCF, 0x9E, 0xE0, 0xEA, 0xC1, 0x2B, 0xB3, 0x68, 0x03, 0xB2, 0xDF, 0xE6, 0x4A, 0x6C, 0xC5, 0x42, 0x61, 0x4E, 0xB5, 0x67, 0xD7, 0x13, 0xEA, 0xCA, 0xB0, 0x41, 0xE5, 0x01, 0xBA, 0x77, 0xA6, 0xF5, 0xB7, 0x08, 0x68, 0xE1, 0x40, 0x36, 0x60, 0x8B, 0xBB, 0xF2, 0x25, 0xF0, 0x09, 0x56, 0x2B, 0x5C, 0x9C, 0x06, 0xC7, 0x35, 0x77, 0x6A, 0xF0, 0x33, 0xA5, 0x57, 0x7E, 0xB0, 0xCA, 0x75, 0xD4, 0x23, 0xA4, 0xA7, 0x62, 0xB4, 0xD6, 0x9D, 0xBB, 0xCC, 0xE3, 0x84, 0xD9, 0x67, 0x63, 0x3C, 0x80, 0x35, 0xC0, 0xA5, 0x6F, 0x0A, 0x68, 0x5F, 0xCC, 0xBB, 0x15, 0xC6, 0x53, 0x5B, 0x1B, 0x01, 0x28, 0x5D, 0x70, 0x05, 0x9C, 0x85, 0xCA, 0x62, 0x80, 0xE1, 0x7C, 0x85, 0xF1, 0x18, 0x42, 0xB1, 0x27, 0x6A, 0x1D, 0x6B, 0xA0, 0xA3, 0x77, 0x93, 0x63, 0xAF, 0xDB, 0xDB, 0x31, 0x3B, 0x6D, 0x2D, 0x00, 0xE7, 0xA7, 0x06, 0xD4, 0x00, 0xE9, 0xBB, 0x67, 0xE1, 0x71, 0x5A, 0x8D, 0xEA, 0x26, 0xDB, 0x44, 0x35, 0xE4, 0x77, 0xBD, 0xCD, 0x10, 0xF6, 0xE9, 0xC5, 0x29, 0x71, 0x57, 0x39, 0xB3, 0x42, 0x5B, 0xAD, 0xF2, 0xBB, 0xA9, 0x59, 0x5F, 0x33, 0x14, 0xCE, 0x07, 0xFA, 0xBC, 0xA9, 0xA5, 0x09, 0xF8, 0xF6, 0xD1, 0xA1, 0xB7, 0xA3, 0x01, 0xE5, 0xE8, 0xBA, 0xBA, 0xAE, 0xC2, 0xD5, 0x43, 0x35, 0x33, 0x6C, 0xC1, 0x9F, 0x5F, 0xA8, 0xE2, 0xEC, 0x05, 0x54, 0xF9, 0xE6, 0x0F, 0xF6, 0xA7, 0x99, 0x42, 0x47, 0x62, 0xFD, 0x39, 0x79, 0x5C, 0x9E, 0xC6, 0xD8, 0xC2, 0x4E, 0x5C, 0x06, 0xCC, 0xE6, 0xAF, 0xF9, 0x22, 0xEB, 0x6E, 0xF7, 0x76, 0x12, 0xD0, 0x01, 0xC2, 0x80, 0xDC, 0xDB, 0xD5, 0x39, 0xB4, 0xDA, 0xD0, 0x6A, 0xE8, 0xF3, 0x1B, 0x81, 0x5A, 0x03, 0x46, 0x49, 0x9A, 0xBD, 0x8E, 0x0B, 0x4E, 0x63, 0x1B, 0x76, 0xED, 0x67, 0xAE, 0xF2, 0xDD, 0xAA, 0xB1, 0x9F, 0x0E, 0xCF, 0xAF, 0x58, 0x46, 0x3C, 0x0A, 0x97, 0xD3, 0xC0, 0xA9, 0xBB, 0xBA, 0x9A, 0xF2, 0x09, 0x57, 0x5B, 0x4F, 0x84, 0x06, 0xEE, 0x8B, 0xA6, 0xDA, 0xAD, 0xF8, 0x74, 0x12, 0xB0, 0x06, 0xF2, 0x6D, 0x12, 0xCF, 0xCC, 0x08, 0x93, 0xBD, 0x02, 0xE9, 0xDE, 0x7D, 0x04, 0xA6, 0x88, 0xCD, 0x7E, 0x49, 0x4C, 0x0A, 0xD4, 0x03, 0x15, 0x4A, 0x7F, 0x8E, 0x03, 0xC9, 0x0A, 0xA0, 0x03, 0xA8, 0x03, 0xBE, 0xA8, 0xED, 0x18, 0x7A, 0x02, 0x50, 0x01, 0x9C, 0x13, 0xD4, 0xB7, 0x7B, 0xCE, 0x38, 0x0E, 0x33, 0xDD, 0xF8, 0x67, 0xB1, 0xDE, 0x98, 0xC7, 0x60, 0x62, 0xAF, 0x9B, 0x2D, 0x2D, 0x50, 0x73, 0xD7, 0xCA, 0xA2, 0xB2, 0x2B, 0x8F, 0x28, 0xFC, 0xED, 0xF2, 0x80, 0x2B, 0xED, 0xD9, 0x59, 0xBF, 0xA8, 0xBB, 0xDF, 0xB3, 0x0E, 0x6F, 0x9F, 0xAF, 0xCE, 0x65, 0xAD, 0xB5, 0xE6, 0x91, 0x5D, 0x8D, 0x06, 0x6A, 0x6F, 0xA6, 0x39, 0x80, 0xE6, 0x62, 0x16, 0x14, 0xA5, 0x63, 0x2A, 0xCD, 0x5B, 0x56, 0xF4, 0x64, 0x9E, 0x6D, 0x81, 0x7A, 0xAC, 0x37, 0x20, 0xF6, 0x95, 0xC0, 0xB5, 0x08, 0x79, 0x8C, 0x09, 0x83, 0xBA, 0x02, 0xFC, 0xD4, 0x44, 0x2D, 0x06, 0x98, 0xB8, 0xFB, 0x44, 0xE7, 0xA1, 0xD1, 0xE4, 0x6F, 0xA4, 0x29, 0xE2, 0x29, 0x6C, 0xBB, 0xA7, 0xF2, 0xD4, 0x91, 0xCA, 0xD8, 0xB6, 0xAE, 0xCE, 0xD5, 0xA7, 0x74, 0x26, 0x0E, 0x5D, 0xF1, 0x3C, 0xDF, 0x95, 0xDD, 0xF3, 0x11, 0x54, 0xA1, 0xFA, 0x2F, 0x70, 0xD6, 0x3E, 0xA7, 0x38, 0x62, 0xEE, 0x4C, 0x49, 0x77, 0xA0, 0x39, 0xA8, 0x72, 0x4D, 0x28, 0x8B, 0xDD, 0xC0, 0x6D, 0x21, 0x05, 0xF8, 0x01, 0x62, 0x4D, 0x1F, 0xE7, 0xCD, 0x4A, 0x9E, 0xE7, 0x68, 0xC1, 0x36, 0x81, 0x36, 0xB0, 0x9D, 0x6F, 0x41, 0x91, 0x6D, 0xBE, 0x8C, 0xD5, 0x5D, 0x4C, 0xE5, 0x09, 0x64, 0x00, 0x7D, 0x80, 0x79, 0x2A, 0xB3, 0x00, 0x1B, 0x20, 0x14, 0xA8, 0xC7, 0x68, 0x8A, 0x18, 0x87, 0xF8, 0xBF, 0x10, 0xB8, 0x34, 0x62, 0xB6, 0xF0, 0x3F, 0x9E, 0x1B, 0x5A, 0x88, 0xAE, 0xCA, 0xAA, 0xA1, 0x9A, 0x45, 0x95, 0x15, 0xA0, 0xB7, 0xC8, 0x09, 0x3B, 0x6E, 0x3D, 0xA7, 0x80, 0xBC, 0x7B, 0x27, 0x54, 0x00, 0x0C, 0xF6, 0xE6, 0x01, 0x6E, 0x37, 0x92, 0x3C, 0xC9, 0xF1, 0x41, 0x57, 0x08, 0x15, 0x81, 0x1F, 0xD3, 0xDF, 0xE5, 0xE9, 0x87, 0x08, 0xA0, 0xFB, 0xCD, 0x8A, 0xDF, 0x60, 0x9B, 0xF1, 0x0A, 0xB0, 0xFF, 0x72, 0x5E, 0x30, 0x9A, 0xCF, 0x73, 0xDA, 0x57, 0x03, 0x86, 0x33, 0xF8, 0x00, 0x13, 0x6B, 0xC9, 0x06, 0xC4, 0x16, 0x03, 0xE8, 0xC2, 0x03, 0x98, 0xA2, 0xD1, 0x6C, 0x7B, 0x81, 0x3F, 0xFD, 0xA1, 0x17, 0x14, 0xD4, 0x82, 0xED, 0x8E, 0x08, 0x7A, 0x30, 0xD9, 0x0A, 0x0D, 0x8D, 0x7D, 0x6B, 0x7F, 0xC0, 0x09, 0xA6, 0xC4, 0x3C, 0xAE, 0x0D, 0x40, 0x0B, 0x10, 0xBB, 0xB7, 0xCC, 0x3C, 0xFF, 0xD1, 0xDC, 0xCE, 0xF7, 0xCD, 0x13, 0x00, 0x9B, 0xDB, 0x15, 0xFB, 0x69, 0x0B, 0x90, 0x03, 0x74, 0xDF, 0x2D, 0x08, 0xF3, 0xCE, 0x33, 0xD7, 0xBD, 0x6E, 0x9E, 0x27, 0xB5, 0x4B, 0xCF, 0x7D, 0xEC, 0xC8, 0xD9, 0xF0, 0xBB, 0xED, 0x29, 0x42, 0x80, 0xD9, 0x53, 0xB0, 0x2A, 0x60, 0xBE, 0xE8, 0x45, 0x2E, 0x06, 0x08, 0x07, 0x26, 0x68, 0x36, 0xDF, 0xF4, 0xCD, 0xF9, 0x37, 0xBF, 0x7B, 0xA6, 0x5C, 0xF9, 0x57, 0x35, 0x0E, 0x77, 0xFD, 0x51, 0x5C, 0x1E, 0xC3, 0x91, 0xBE, 0x11, 0x7D, 0x35, 0x4C, 0xF2, 0xFE, 0x1E, 0x3B, 0xF4, 0x4E, 0x82, 0x49, 0xB9, 0x3F, 0x89, 0xDF, 0x5E, 0xA2, 0x4C, 0x20, 0x02, 0xE8, 0x66, 0x4C, 0xF4, 0x16, 0x5D, 0xA0, 0x45, 0xA5, 0xD6, 0x5C, 0xFB, 0x0B, 0x47, 0x01, 0x11, 0xA0, 0x8C, 0xA7, 0x0F, 0xFA, 0x3B, 0xF2, 0x55, 0xA8, 0xCE, 0xA7, 0x8C, 0xE5, 0xE4, 0xDD, 0x17, 0x3B, 0xD8, 0xFB, 0x9F, 0x72, 0x93, 0x02, 0x94, 0x2D, 0x12, 0x48, 0x01, 0xEC, 0x00, 0xB2, 0xD0, 0x35, 0x9E, 0x3C, 0x56, 0x8B, 0xBF, 0x63, 0xC7, 0x40, 0x19, 0x2C, 0x04, 0xDD, 0x53, 0xE1, 0xA3, 0xF2, 0x6D, 0x01, 0x18, 0x14, 0xDE, 0xC7, 0xC9, 0xC0, 0x9D, 0xF9, 0xF1, 0x74, 0xB1, 0x5D, 0xA7, 0x8E, 0xF0, 0x2B, 0xF6, 0x6B, 0x8F, 0x2A, 0x79, 0xF9, 0xEE, 0x95, 0x7D, 0xDF, 0x91, 0x72, 0xAF, 0xF3, 0x0A, 0x68, 0x5E, 0x61, 0x39, 0xEC, 0xCE, 0x78, 0xB3, 0xEF, 0x2E, 0x46, 0x05, 0xCC, 0x73, 0x30, 0xD9, 0x99, 0x2D, 0x4F, 0xE5, 0xC6, 0xFA, 0xCD, 0xDE, 0xE8, 0x93, 0xFB, 0xE3, 0xFA, 0xCE, 0x7E, 0xAB, 0x3B, 0x11, 0xBE, 0x41, 0xB1, 0xED, 0x06, 0x11, 0x3C, 0x80, 0x5A, 0xCC, 0xEE, 0x05, 0xD2, 0x80, 0x0B, 0x90, 0x03, 0xF4, 0x46, 0x0F, 0x44, 0x69, 0xB4, 0xFC, 0xB6, 0x97, 0x42, 0x10, 0xB4, 0x72, 0xC5, 0x42, 0x12, 0x65, 0x20, 0xC3, 0xA4, 0x8C, 0x82, 0x70, 0x15, 0x5A, 0x3D, 0xD4, 0x7C, 0xCF, 0x6A, 0xCF, 0x38, 0xE2, 0x5D, 0xBD, 0x81, 0x2C, 0xE0, 0x11, 0x25, 0x3A, 0x80, 0x7E, 0xA4, 0x71, 0xCD, 0x17, 0x7C, 0x18, 0xC0, 0x2C, 0x24, 0xD9, 0xE2, 0xFE, 0xEE, 0x7B, 0xAF, 0x02, 0xF0, 0x17, 0x54, 0x2E, 0xD7, 0x5A, 0xC2, 0x40, 0x6C, 0x81, 0x06, 0x77, 0xE1, 0xAB, 0xAB, 0x56, 0x7B, 0x24, 0xE9, 0x7D, 0x08, 0x47, 0x07, 0x56, 0x39, 0x01, 0xC2, 0x81, 0x9A, 0x6D, 0x22, 0x2D, 0x80, 0x3A, 0x10, 0x0A, 0x64, 0x02, 0xF3, 0x58, 0xAD, 0x56, 0xDC, 0x47, 0x2E, 0xAB, 0x55, 0xC7, 0x8A, 0x89, 0xCE, 0x6E, 0xF8, 0xB5, 0x22, 0xC5, 0xF8, 0x46, 0x3E, 0x97, 0x76, 0xF0, 0xB7, 0x53, 0x23, 0x44, 0xAA, 0x60, 0xA7, 0x66, 0xFA, 0xE2, 0x7D, 0xDD, 0x54, 0xBB, 0xFB, 0xB2, 0x71, 0x05, 0xCB, 0x45, 0xAD, 0x45, 0x45, 0x00, 0x13, 0x9A, 0x72, 0xED, 0xF4, 0x59, 0xC8, 0x54, 0x01, 0xE3, 0x8A, 0xC9, 0x1B, 0x69, 0x3E, 0x82, 0x45, 0x54, 0x56, 0xD8, 0x0C, 0xA0, 0x78, 0x2B, 0x34, 0x50, 0x11, 0x82, 0x30, 0x2F, 0xB7, 0x88, 0x73, 0xE7, 0x2F, 0x77, 0x00, 0xC3, 0x2A, 0x5C, 0xDF, 0x4F, 0xB5, 0x9F, 0x0E, 0x20, 0x0D, 0x74, 0xD3, 0x6A, 0x7F, 0xF7, 0x82, 0xFE, 0xE5, 0x65, 0xC6, 0xF6, 0xE3, 0x0E, 0xB6, 0x9C, 0x85, 0x13, 0x6E, 0x8F, 0x01, 0x55, 0x81, 0x3E, 0x2F, 0x85, 0x2D, 0x34, 0xBF, 0x79, 0x44, 0xFA, 0xA9, 0xC9, 0xA8, 0xA0, 0x57, 0xF5, 0xD5, 0x37, 0xC3, 0x24, 0x7E, 0x52, 0x35, 0x10, 0xDE, 0xBD, 0x6E, 0xA9, 0x7D, 0xEE, 0xE6, 0x5D, 0xB5, 0x0F, 0x47, 0x98, 0x9D, 0x06, 0xF8, 0xA2, 0x16, 0x93, 0xFB, 0x0A, 0x0C, 0xFA, 0x76, 0xDB, 0x18, 0x46, 0x7B, 0x39, 0xAA, 0x56, 0xF4, 0xA6, 0xDE, 0x64, 0x5A, 0x68, 0x7C, 0xA3, 0x4E, 0xB8, 0x80, 0xE9, 0xAD, 0x63, 0x4F, 0x20, 0x15, 0x68, 0xDB, 0x66, 0xF8, 0x02, 0xD8, 0x00, 0x61, 0x40, 0x09, 0x8D, 0x36, 0x2B, 0xB4, 0x65, 0xFF, 0x7A, 0x73, 0xB0, 0xDB, 0x11, 0xC2, 0x43, 0x43, 0xC9, 0x62, 0x82, 0x09, 0x5E, 0xB1, 0xC6, 0xC4, 0x52, 0xB9, 0x9C, 0x44, 0xF5, 0x6D, 0x0A, 0xDA, 0x14, 0x01, 0xBB, 0xB2, 0x1D, 0x83, 0x03, 0xE8, 0x6A, 0xC4, 0x79, 0x35, 0x71, 0xCC, 0x47, 0x5D, 0xE7, 0x96, 0xE6, 0x1F, 0x05, 0x18, 0x46, 0x70, 0x01, 0xC4, 0x01, 0x5B, 0x78, 0xBF, 0x5A, 0xC5, 0x18, 0x15, 0x8C, 0xC9, 0xAF, 0xE7, 0x9F, 0x3A, 0xBF, 0xF5, 0x46, 0x5D, 0xCE, 0x0E, 0xAE, 0x0D, 0xEC, 0xB9, 0x3E, 0x09, 0xDE, 0x22, 0x40, 0x28, 0x90, 0xBE, 0x88, 0xCF, 0xA7, 0x04, 0x7A, 0x97, 0xCA, 0xC7, 0xF7, 0x1D, 0xF8, 0x37, 0x9B, 0xF1, 0x9F, 0xEF, 0x3B, 0x14, 0x89, 0x7E, 0x93, 0x30, 0x57, 0x15, 0x26, 0x68, 0x89, 0xB3, 0x2A, 0x0E, 0x4B, 0xD5, 0x47, 0xF1, 0xAA, 0xE2, 0x23, 0x1E, 0xCC, 0x54, 0xC6, 0xC8, 0x3B, 0xCD, 0xD1, 0xCF, 0x3E, 0x64, 0xF2, 0x0B, 0x7D, 0x6A, 0x0B, 0x75, 0x40, 0x12, 0xF0, 0x01, 0xEA, 0xE9, 0x54, 0xBE, 0xF6, 0x15, 0x20, 0x1C, 0xA8, 0x02, 0x1E, 0xC5, 0x36, 0x26, 0x52, 0xCA, 0x5A, 0x2D, 0xEA, 0x95, 0xFD, 0x60, 0x45, 0xD4, 0xF9, 0xCB, 0x87, 0xBF, 0x9A, 0x66, 0x07, 0xAC, 0x06, 0x11, 0x48, 0xC0, 0x06, 0x08, 0x5D, 0xE4, 0x8D, 0x2C, 0xA0, 0x76, 0x62, 0xCB, 0xD0, 0x6A, 0x7F, 0x17, 0x83, 0x12, 0xA4, 0xAE, 0xE5, 0x6F, 0xDB, 0x28, 0x1C, 0xC9, 0x45, 0xD6, 0x37, 0x65, 0x5B, 0x12, 0x30, 0x3F, 0x77, 0x8E, 0x9B, 0x32, 0x6A, 0x7C, 0x6F, 0xA1, 0xC2, 0xD5, 0x9C, 0x2E, 0xB2, 0x58, 0xAB, 0x2D, 0x92, 0x93, 0xB1, 0x00, 0xE7, 0xBC, 0x1B, 0x20, 0x58, 0xFC, 0x78, 0xB5, 0xE5, 0x94, 0xF5, 0x63, 0xCD, 0x33, 0x6D, 0xBB, 0x80, 0x0C, 0x60, 0xE8, 0x49, 0xCF, 0x6B, 0x27, 0xA5, 0xAA, 0xAE, 0x3F, 0x95, 0x6A, 0x8F, 0x96, 0xC5, 0xAE, 0xDF, 0x62, 0x1B, 0x0C, 0x56, 0xEC, 0x9D, 0xF5, 0x43, 0x2E, 0x7E, 0xAB, 0x1B, 0x50, 0xBC, 0x32, 0xE9, 0xA7, 0x61, 0x74, 0x00, 0x5D, 0xC8, 0x9D, 0x3F, 0x01, 0xFC, 0x8D, 0x35, 0xC5, 0x0E, 0xEC, 0xF5, 0x18, 0xAF, 0x1B, 0x52, 0x0A, 0x1A, 0xD0, 0x6E, 0x12, 0x7F, 0x2E, 0x88, 0x65, 0x18, 0x23, 0x25, 0x72, 0x75, 0x23, 0x4F, 0xFD, 0xA8, 0x46, 0x26, 0xFB, 0xE7, 0x72, 0x20, 0x7D, 0x46, 0x50, 0x2C, 0x58, 0xD0, 0xAF, 0xE7, 0xF6, 0x8D, 0xED, 0x05, 0xF5, 0xAD, 0x5C, 0xDD, 0x0C, 0x05, 0x6A, 0x2E, 0x9F, 0x7E, 0xC3, 0x4B, 0xFA, 0x94, 0x20, 0x67, 0xBD, 0x19, 0xDE, 0xF1, 0x24, 0x7E, 0x54, 0x02, 0x1A, 0x77, 0x6A, 0x6A, 0x2F, 0x2A, 0x81, 0x36, 0xBC, 0x22, 0x0E, 0x64, 0x02, 0xD3, 0x0B, 0x01, 0x6A, 0xE1, 0x07, 0x90, 0x06, 0x2C, 0x29, 0xA6, 0x45, 0xAB, 0x19, 0x44, 0x36, 0xA5, 0x37, 0x67, 0xA7, 0xEF, 0xC6, 0x3F, 0xEC, 0x8A, 0x9F, 0x89, 0x9F, 0x65, 0xA3, 0xBD, 0x65, 0xD9, 0x75, 0xF0, 0x88, 0xF9, 0x34, 0x2D, 0xF0, 0xF3, 0x91, 0x05, 0x18, 0xA0, 0x75, 0x21, 0xC0, 0x30, 0x80, 0x65, 0x6B, 0x58, 0x36, 0xCF, 0x30, 0x5E, 0xF9, 0xE3, 0xCD, 0xC3, 0x5B, 0xCB, 0x28, 0x0E, 0x53, 0xC8, 0x86, 0xA2, 0x12, 0x3C, 0x13, 0x89, 0x8C, 0x8A, 0x87, 0x6B, 0x92, 0xBE, 0xA5, 0x33, 0x8F, 0xF0, 0xD3, 0xA2, 0xF7, 0xA1, 0x02, 0xB2, 0xA0, 0x86, 0xB6, 0x34, 0x90, 0x07, 0xF0, 0xB9, 0xFB, 0x89, 0xD4, 0x00, 0x71, 0x80, 0xDC, 0x9F, 0xC5, 0x63, 0x35, 0xFF, 0x6D, 0x2D, 0x79, 0x1C, 0xA9, 0x63, 0xD1, 0xF7, 0xCD, 0x20, 0xD6, 0xBE, 0x55, 0x9B, 0x95, 0x9F, 0x38, 0x89, 0x49, 0x70, 0x3D, 0xFB, 0x64, 0xFA, 0xE5, 0xDD, 0x5B, 0x3D, 0x05, 0x18, 0xF6, 0xD7, 0xF6, 0x45, 0x03, 0x56, 0x00, 0xBD, 0xB2, 0x72, 0x2E, 0x17, 0xD9, 0xAC, 0x07, 0x55, 0xF7, 0x0E, 0xB3, 0xE7, 0xCB, 0x27, 0x71, 0x8A, 0x3E, 0x69, 0xF6, 0x43, 0x3E, 0x4F, 0x7A, 0x9A, 0x5F, 0x8A, 0x87, 0x18, 0xC7, 0x57, 0x23, 0x91, 0xC3, 0x62, 0xDE, 0x45, 0xF7, 0x2D, 0xDC, 0x66, 0x4F, 0x5B, 0x04, 0xC0, 0x1D, 0x30, 0x05, 0x8E, 0xAF, 0x81, 0x06, 0xD0, 0x06, 0xB6, 0x13, 0xD8, 0x3B, 0x43, 0x03, 0xA5, 0x52, 0xBA, 0x92, 0x72, 0xBE, 0xCD, 0x58, 0x52, 0xF6, 0x82, 0x3C, 0xDB, 0x3A, 0xCC, 0x57, 0xE0, 0x6E, 0x70, 0x96, 0x8F, 0xFF, 0x6A, 0xC6, 0x22, 0xFE, 0x2E, 0xD9, 0xF5, 0x74, 0x61, 0x61, 0x97, 0x3F, 0x35, 0xC0, 0x07, 0xE8, 0x27, 0x39, 0xAF, 0xDE, 0xAE, 0x9C, 0xFE, 0x24, 0x4E, 0x29, 0x77, 0xBF, 0x79, 0x85, 0x51, 0xF2, 0x49, 0xAD, 0x65, 0xAB, 0x2C, 0x1A, 0xCF, 0xD8, 0x79, 0x84, 0x22, 0x50, 0x7A, 0x2B, 0x3B, 0x9F, 0xA6, 0xEA, 0x18, 0x90, 0x7D, 0xA3, 0xA8, 0x07, 0x58, 0x40, 0x1F, 0xC6, 0x18, 0x16, 0xB2, 0x0F, 0xE7, 0x53, 0xDD, 0x92, 0x80, 0xEF, 0x2B, 0x5A, 0xB4, 0x5A, 0x22, 0x5E, 0xD8, 0xFA, 0xB7, 0xAE, 0xFD, 0x06, 0x89, 0x6F, 0xC2, 0xB5, 0xE2, 0x2F, 0x7B, 0x62, 0xD2, 0x89, 0x56, 0x0F, 0x1A, 0xFF, 0xF0, 0x67, 0xC2, 0x68, 0x43, 0xA3, 0x15, 0x4B, 0x7B, 0xEE, 0xDA, 0x1C, 0x5F, 0x34, 0x8B, 0x79, 0x0C, 0x70, 0x05, 0xA6, 0x69, 0x3B, 0x4E, 0x34, 0x81, 0xD1, 0x86, 0x25, 0xC6, 0xEB, 0x58, 0x64, 0x59, 0xA6, 0xCE, 0xEB, 0x84, 0x66, 0x59, 0x49, 0x3F, 0x02, 0x6C, 0x6C, 0x83, 0x19, 0x6B, 0xF3, 0x39, 0x80, 0xB1, 0x46, 0x65, 0x16, 0x07, 0x28, 0x7C, 0x7A, 0x5F, 0x01, 0x66, 0xF6, 0x5F, 0x80, 0x50, 0x40, 0xF6, 0x95, 0x12, 0xC0, 0x03, 0xC8, 0xFD, 0x59, 0x1C, 0x1A, 0xAD, 0x10, 0x2C, 0x9D, 0xFE, 0x5C, 0xAB, 0xD8, 0xA8, 0x4D, 0xE0, 0x2A, 0x55, 0x64, 0x7F, 0x47, 0xD5, 0xEF, 0x18, 0x5B, 0xE2, 0xF7, 0xC1, 0x43, 0xBE, 0x9D, 0xB9, 0x76, 0xC4, 0x11, 0xD9, 0x40, 0xC9, 0xA2, 0xEF, 0xE9, 0x1A, 0xBA, 0x57, 0xAE, 0xDB, 0x95, 0xFD, 0x28, 0x16, 0xAC, 0xF1, 0x9C, 0x03, 0x6F, 0xBD, 0x8E, 0xEC, 0x0D, 0x11, 0x4F, 0x13, 0x39, 0xF6, 0xC7, 0x18, 0x26, 0x27, 0x2C, 0xD4, 0x58, 0x8C, 0x0A, 0x58, 0x02, 0x4A, 0xC4, 0x47, 0x15, 0x86, 0xBF, 0x90, 0x40, 0x0A, 0x10, 0x01, 0xD8, 0xE2, 0x50, 0x02, 0xE5, 0xDC, 0x05, 0x58, 0xA5, 0xB4, 0x5A, 0x6F, 0x49, 0x1B, 0xAA, 0x17, 0x5D, 0xFB, 0xEA, 0xFB, 0xC3, 0x02, 0x50, 0xA9, 0x64, 0xEB, 0xA5, 0xCD, 0x34, 0x68, 0xD6, 0xFE, 0x7C, 0xEE, 0x53, 0x71, 0xC7, 0x59, 0x88, 0xF4, 0x1B, 0xD1, 0x40, 0x7E, 0xDA, 0xFF, 0xF0, 0x50, 0x22, 0xF4, 0xF3, 0xB0, 0x1C, 0xC5, 0xE5, 0xF6, 0xE3, 0xFA, 0x25, 0xE2, 0x98, 0x4F, 0x0A, 0x25, 0x25, 0x67, 0x8F, 0x02, 0x7C, 0xC8, 0x25, 0x48, 0x04, 0x88, 0x04, 0x3A, 0x80, 0xA9, 0xFD, 0x75, 0x05, 0xE2, 0xC9, 0x96, 0x03, 0xC2, 0x01, 0x0F, 0x40, 0x8D, 0x42, 0xA3, 0x40, 0x2A, 0x40, 0xE3, 0x45, 0xD2, 0x6A, 0xB3, 0xD2, 0x51, 0xB2, 0xBB, 0x87, 0xFE, 0xBC, 0x45, 0xAE, 0xB6, 0x25, 0xC3, 0x8C, 0x65, 0x27, 0xC5, 0x26, 0xE1, 0xC2, 0xD1, 0xF9, 0x36, 0x52, 0xBD, 0xAD, 0xF6, 0xD4, 0xE0, 0x29, 0x10, 0xB2, 0xF8, 0x7C, 0x2A, 0xE5, 0x2D, 0x14, 0x18, 0x4E, 0x62, 0x61, 0xD8, 0xDC, 0xDF, 0xC6, 0x62, 0xF0, 0xFC, 0x52, 0xDF, 0x0F, 0x0F, 0xD7, 0xA2, 0xC3, 0x6F, 0x28, 0x6B, 0x8B, 0x06, 0x92, 0x9F, 0x0E, 0x13, 0xDD, 0x16, 0x05, 0x88, 0x2F, 0x06, 0xB0, 0x03, 0x64, 0xDF, 0x9E, 0xE6, 0x54, 0x20, 0x0A, 0xB0, 0x00, 0x8E, 0xFD, 0x87, 0xB2, 0x4E, 0x71, 0x0B, 0x4D, 0xBA, 0x05, 0x6A, 0x7B, 0x7F, 0xE9, 0x5D, 0x6F, 0xC6, 0xF6, 0x05, 0xEA, 0x9B, 0x9B, 0x33, 0x68, 0x82, 0x6E, 0x73, 0xC7, 0x8F, 0xFD, 0x93, 0x2C, 0xEF, 0xFA, 0x5F, 0x1D, 0x07, 0x07, 0x18, 0xDE, 0xCF, 0xEF, 0x19, 0xBA, 0xE0, 0x25, 0x42, 0x1E, 0x31, 0x80, 0xA7, 0x1E, 0xC5, 0x29, 0x30, 0x61, 0x6F, 0x2B, 0x77, 0x7F, 0x54, 0x35, 0x84, 0xC5, 0x86, 0x0B, 0x2B, 0x60, 0x28, 0xD1, 0xD1, 0x80, 0x1B, 0x10, 0x0D, 0xA4, 0x03, 0xC5, 0x5F, 0x77, 0x80, 0xFD, 0x36, 0x44, 0x80, 0xE3, 0xF7, 0x42, 0xE8, 0x09, 0xE8, 0x01, 0x2C, 0xF6, 0x4D, 0xA7, 0xD5, 0x04, 0x57, 0x7F, 0xD9, 0xEC, 0x04, 0x09, 0x6C, 0x06, 0x07, 0x57, 0xA8, 0x60, 0x33, 0x96, 0x81, 0xD5, 0x52, 0xB6, 0x52, 0x25, 0xE4, 0x1A, 0x6B, 0x15, 0x5F, 0xB5, 0x13, 0xDE, 0x23, 0x85, 0xD5, 0x60, 0x80, 0x2D, 0x3C, 0x01, 0x8A, 0x06, 0x9F, 0xAF, 0x24, 0xA9, 0x2A, 0x97, 0xA9, 0x75, 0xB8, 0xB3, 0xB3, 0x8C, 0xC1, 0x78, 0x39, 0x6F, 0xBA, 0x14, 0x22, 0x60, 0x38, 0x06, 0x25, 0x03, 0x2E, 0x1C, 0x80, 0x4C, 0x95, 0xBC, 0x15, 0x17, 0x4D, 0x80, 0x58, 0xF0, 0x67, 0xE5, 0x6B, 0xB5, 0x04, 0x7A, 0x6D, 0xA1, 0x0B, 0x29, 0x3C, 0x1C, 0x05, 0xC2, 0x00, 0x4D, 0xC0, 0x0D, 0xAF, 0x98, 0xD1, 0x6A, 0x8A, 0x04, 0x86, 0xF3, 0xB7, 0x85, 0xD6, 0x6F, 0x55, 0xAD, 0x4D, 0xF7, 0x6B, 0xFC, 0xD3, 0x49, 0xC0, 0x2F, 0x9A, 0x86, 0x8E, 0x53, 0xFD, 0xE9, 0x96, 0x94, 0x9F, 0xA8, 0xBB, 0xF9, 0x5D, 0xA8, 0x79, 0x04, 0xB0, 0x06, 0xA2, 0xEE, 0x0A, 0x33, 0xBB, 0xB3, 0x0C, 0xFE, 0x3A, 0xBD, 0x65, 0xBE, 0x8D, 0x42, 0x72, 0xFD, 0xAB, 0xB1, 0x97, 0x70, 0xA5, 0xC4, 0xE8, 0xEE, 0x77, 0xB9, 0x26, 0x61, 0x26, 0x0C, 0x06, 0xF7, 0x95, 0xB8, 0x9B, 0x02, 0x98, 0x02, 0x5A, 0x37, 0x6C, 0x51, 0xC6, 0xF8, 0x3C, 0x90, 0x0A, 0x44, 0x01, 0x2E, 0x80, 0xC8, 0xDA, 0xB0, 0xF6, 0x93, 0x03, 0x5D, 0xB4, 0x9A, 0x21, 0x8F, 0xE1, 0xC4, 0xDD, 0xC2, 0x5D, 0x1A, 0x2B, 0x19, 0xCB, 0xF2, 0x5D, 0xA1, 0x5A, 0xD9, 0x83, 0x3C, 0x5A, 0x17, 0x5E, 0xD6, 0xEF, 0x14, 0xAC, 0x7C, 0x67, 0x66, 0x3D, 0xE5, 0xC3, 0xE2, 0x40, 0x1E, 0xA0, 0xFA, 0xEE, 0xB4, 0xCC, 0x88, 0xCB, 0x9E, 0xA3, 0xB9, 0x31, 0xD2, 0xFF, 0x5C, 0x4F, 0xC4, 0xB7, 0x16, 0x76, 0x58, 0x9E, 0xBD, 0x3F, 0x9B, 0xF5, 0x4D, 0xAF, 0x25, 0xCB, 0x99, 0x06, 0x0E, 0xB8, 0x6F, 0x94, 0x60, 0x80, 0x12, 0x20, 0x73, 0xE1, 0x00, 0x7F, 0x41, 0x04, 0x48, 0x07, 0xA6, 0x16, 0x06, 0x54, 0x02, 0x71, 0x00, 0x73, 0x80, 0x69, 0x47, 0x32, 0x34, 0x9A, 0xE3, 0x2C, 0xDE, 0xEB, 0x39, 0x13, 0xFF, 0x57, 0x6C, 0x81, 0x8E, 0xF6, 0x18, 0x3C, 0xCC, 0x6C, 0x11, 0x4D, 0xFF, 0x2C, 0x11, 0x5D, 0x6F, 0x7C, 0xAA, 0xF5, 0x53, 0xD9, 0x98, 0x46, 0x01, 0xB9, 0x35, 0x5A, 0x7F, 0x8C, 0xA6, 0xC0, 0xE8, 0xC7, 0xD1, 0xCD, 0x3B, 0x1E, 0xF7, 0x4C, 0xFE, 0xD9, 0xB1, 0x4E, 0xB2, 0xA3, 0x6F, 0x31, 0xE2, 0xAE, 0x39, 0x86, 0xA1, 0x09, 0x8F, 0x3C, 0x73, 0xF7, 0x0E, 0xE0, 0x06, 0xF4, 0xFE, 0x4C, 0x14, 0xD0, 0x04, 0x5C, 0x16, 0x0D, 0xA4, 0x03, 0xC3, 0xAF, 0xE4, 0x40, 0x13, 0x02, 0x64, 0x00, 0x2E, 0x80, 0x1A, 0x60, 0x9B, 0xFD, 0x20, 0x87, 0x46, 0x0B, 0x8A, 0xD9, 0x41, 0x35, 0xBF, 0x06, 0xED, 0x1F, 0xDC, 0x37, 0x28, 0xD7, 0xC8, 0x69, 0xB0, 0xD8, 0x06, 0x3C, 0xB2, 0x42, 0x68, 0x73, 0x29, 0x94, 0xC6, 0xAD, 0x1F, 0x9C, 0x1C, 0x4C, 0x6D, 0x77, 0x33, 0x61, 0x57, 0x20, 0xCF, 0x2D, 0x18, 0xA7, 0xC2, 0xFD, 0x8C, 0x3A, 0xEE, 0x94, 0xE7, 0xC0, 0x99, 0xB6, 0x57, 0x00, 0x22, 0x2E, 0x39, 0x08, 0xBA, 0x19, 0x71, 0xD7, 0x86, 0xD2, 0xA8, 0xE2, 0xCD, 0x0A, 0xA0, 0xF9, 0x90, 0x8A, 0x08, 0x1F, 0x87, 0x59, 0x15, 0xD0, 0x9B, 0xA7, 0x70, 0x16, 0x54, 0x2A, 0x3A, 0x0E, 0x98, 0x2E, 0x0E, 0x20, 0xF4, 0x96, 0x14, 0xD0, 0xB1, 0x6F, 0x1E, 0x20, 0x8B, 0x36, 0xCB, 0x55, 0x0C, 0xED, 0x2D, 0xF0, 0xF6, 0xAB, 0xB5, 0x48, 0xA6, 0x6C, 0x07, 0xB8, 0xDE, 0x3D, 0x4A, 0xE1, 0x3A, 0xEC, 0x66, 0xB6, 0xDA, 0x9D, 0x7F, 0x75, 0xCE, 0xB9, 0xA3, 0x53, 0x66, 0x40, 0xCA, 0xC2, 0x81, 0xA8, 0xCF, 0xB1, 0xE3, 0x00, 0x7D, 0x5E, 0x67, 0x9C, 0x18, 0x77, 0xC0, 0xE7, 0x02, 0xAF, 0x3F, 0xB0, 0x42, 0x56, 0x9F, 0xCB, 0xE7, 0x30, 0x8D, 0x9C, 0x67, 0xD4, 0x01, 0x4A, 0xD6, 0xF8, 0x7E, 0x6B, 0x31, 0x9F, 0x02, 0xBC, 0x81, 0x5C, 0x74, 0xDD, 0x8B, 0x3F, 0xA5, 0x67, 0x24, 0x17, 0xE7, 0x2E, 0x9F, 0xCA, 0x04, 0x7C, 0x91, 0x94, 0x55, 0x17, 0x9A, 0x0D, 0xE2, 0xFB, 0xE9, 0x05, 0x25, 0x08, 0xD7, 0x7F, 0x8D, 0xCE, 0xBD, 0x5B, 0xA0, 0xC5, 0x1A, 0xBD, 0x5E, 0xA5, 0x9C, 0x44, 0xFF, 0xC5, 0xA9, 0xCB, 0x6C, 0xF9, 0xD5, 0x45, 0xAF, 0x1D, 0x73, 0xAC, 0xCA, 0xAB, 0x03, 0xF4, 0xA2, 0x62, 0x51, 0xC0, 0x3C, 0x1D, 0x8E, 0xAF, 0xC4, 0x52, 0x76, 0x2E, 0x80, 0x9B, 0x1E, 0x06, 0x0A, 0x80, 0x06, 0x62, 0xFD, 0x54, 0xC4, 0x7D, 0x57, 0xE7, 0x51, 0x2A, 0x83, 0xC7, 0xF6, 0x5B, 0x0E, 0x20, 0x1F, 0xB7, 0x12, 0x90, 0x72, 0x77, 0xA5, 0xD6, 0x02, 0x78, 0x1B, 0x53, 0x01, 0x64, 0x80, 0x63, 0x14, 0xB1, 0xFF, 0xA8, 0xF8, 0x70, 0xEB, 0x31, 0x5A, 0xAD, 0x31, 0x37, 0x6A, 0xB0, 0x9E, 0x04, 0x07, 0x1B, 0x1D, 0x7C, 0xB5, 0x8D, 0x70, 0xF5, 0x87, 0x8C, 0x81, 0x1F, 0xD5, 0xEB, 0xEA, 0xF7, 0x90, 0xF2, 0xF1, 0xAD, 0xE9, 0x47, 0x6D, 0x22, 0x6C, 0x21, 0xC0, 0xB7, 0x75, 0x74, 0xD1, 0x0B, 0x77, 0xC5, 0x05, 0x9E, 0xE6, 0x9D, 0xA8, 0x6A, 0xBD, 0xDA, 0xB0, 0xF1, 0xB6, 0xD0, 0xBA, 0xC6, 0x73, 0xC6, 0xDB, 0x81, 0x6C, 0x5A, 0x74, 0x8F, 0x67, 0xF2, 0x56, 0x80, 0xC6, 0xE3, 0x0B, 0x3F, 0x0A, 0xD8, 0x00, 0x2C, 0x4F, 0x92, 0x03, 0xA4, 0x02, 0xE3, 0x37, 0x5A, 0xEE, 0x9F, 0xF9, 0x00, 0xC9, 0x16, 0x23, 0x49, 0xAB, 0x0D, 0xE6, 0xAD, 0x60, 0x93, 0xEC, 0xE6, 0x25, 0x94, 0x2B, 0x91, 0x53, 0xFA, 0x64, 0x65, 0xEB, 0x0B, 0x7D, 0xED, 0x37, 0x6D, 0xED, 0xF2, 0xAD, 0xDD, 0x92, 0x0A, 0xFE, 0xA9, 0xA2, 0x3D, 0x37, 0xD2, 0x81, 0xD2, 0xDB, 0x83, 0x94, 0xFE, 0x56, 0xFE, 0x23, 0xB4, 0xB3, 0x06, 0xE2, 0x28, 0xA1, 0xF1, 0x9E, 0x3B, 0x16, 0x7B, 0x15, 0xDC, 0x97, 0x24, 0x39, 0xC0, 0xC8, 0xDB, 0x10, 0x63, 0xF0, 0x09, 0x29, 0x33, 0x40, 0x0E, 0x30, 0x3C, 0x7D, 0x28, 0x90, 0x3B, 0xD6, 0x6C, 0x51, 0x84, 0x02, 0xDE, 0x80, 0xD8, 0x0E, 0x4E, 0x9E, 0x68, 0xBE, 0xC7, 0x8E, 0xE2, 0x8A, 0x10, 0xF8, 0x59, 0x23, 0x2B, 0x37, 0x6B, 0x90, 0x54, 0x1E, 0x78, 0xE8, 0x5D, 0x3F, 0x4C, 0x35, 0xE6, 0x92, 0xE1, 0xB0, 0x76, 0x79, 0x89, 0x2E, 0x87, 0x47, 0x26, 0x93, 0xD1, 0xEE, 0x5E, 0x35, 0x7D, 0x80, 0x8A, 0xC5, 0xF5, 0x50, 0xCE, 0xD3, 0xA2, 0x98, 0x7E, 0xDC, 0x33, 0xFB, 0x9D, 0x98, 0xE9, 0x5E, 0x40, 0xB2, 0x6E, 0x71, 0x21, 0x8D, 0x57, 0x5C, 0xEF, 0x46, 0x73, 0xF8, 0x84, 0x25, 0xE1, 0xD6, 0x9F, 0x51, 0x60, 0x74, 0xB3, 0x46, 0x0B, 0x88, 0x05, 0xC5, 0xC1, 0xDD, 0x80, 0x3A, 0x0B, 0xFB, 0x14, 0xB8, 0xC5, 0xC2, 0xDF, 0x57, 0x10, 0x89, 0x5D, 0xAB, 0x09, 0x6A, 0xD0, 0x65, 0x56, 0x84, 0x31, 0xFE, 0x65, 0x3D, 0x97, 0x50, 0x4B, 0x3A, 0x66, 0x02, 0x6A, 0x93, 0x47, 0xD7, 0x77, 0x58, 0xBC, 0x08, 0xC0, 0xC5, 0x76, 0x9D, 0x3B, 0xFC, 0xCF, 0xA7, 0xF6, 0x6C, 0xA5, 0x3C, 0x5B, 0xCC, 0x0D, 0x5D, 0x78, 0xBD, 0x09, 0x6E, 0xCE, 0x5D, 0xE0, 0xD9, 0x4A, 0x8F, 0xF0, 0xA4, 0x01, 0xF8, 0x00, 0xBA, 0x1E, 0xB6, 0x36, 0xC0, 0x03, 0xA8, 0x7D, 0x73, 0xDE, 0xD8, 0xA7, 0xF5, 0xA3, 0x94, 0xD6, 0x2B, 0x71, 0x55, 0x9B, 0x96, 0x25, 0x02, 0x78, 0x01, 0x5D, 0xAB, 0x4D, 0xD4, 0x40, 0xC8, 0x62, 0x6E, 0xA4, 0x00, 0x75, 0x80, 0x4E, 0x1E, 0x1C, 0x69, 0x34, 0x45, 0x42, 0x74, 0xCD, 0xCA, 0xA2, 0x20, 0x29, 0x97, 0x6E, 0x00, 0x77, 0xC5, 0xB2, 0x42, 0x65, 0x45, 0xEB, 0xAD, 0x0E, 0xB0, 0x3B, 0xD0, 0xF2, 0xED, 0x6D, 0xE9, 0xC3, 0xCC, 0x59, 0x56, 0x12, 0x03, 0x25, 0x0B, 0x07, 0x9A, 0x3A, 0xA5, 0x0E, 0x54, 0x5E, 0xD1, 0x52, 0x56, 0x45, 0x50, 0x24, 0x93, 0xAD, 0xD1, 0x38, 0xFE, 0xE2, 0xD9, 0xF5, 0x54, 0x58, 0xE3, 0x73, 0x67, 0xC6, 0x35, 0xC7, 0x5F, 0xDF, 0x1B, 0x63, 0xD2, 0x93, 0xBE, 0xB0, 0x06, 0x62, 0x76, 0xAD, 0x73, 0x80, 0x63, 0xF3, 0xE4, 0x42, 0x6F, 0xDD, 0xC5, 0x70, 0xC0, 0x02, 0x08, 0x9E, 0x00, 0x87, 0x56, 0x5B, 0x01, 0x80, 0x88, 0x6D, 0x0D, 0x9C, 0x9B, 0x28, 0xD9, 0xBB, 0xAC, 0xC8, 0xBA, 0xA2, 0xEB, 0xB7, 0xE4, 0x05, 0x5D, 0xEF, 0x16, 0x0C, 0x18, 0x5F, 0x6D, 0x1A, 0x8D, 0xC7, 0x88, 0xE1, 0x9A, 0x6E, 0x77, 0x1A, 0xA3, 0xE6, 0xA2, 0x6E, 0x87, 0x83, 0xFF, 0x50, 0xEB, 0x68, 0x9E, 0x47, 0x97, 0x8E, 0x7A, 0xFB, 0xE1, 0x77, 0xB9, 0xEF, 0xD9, 0xFC, 0x59, 0xA9, 0xF5, 0x84, 0xEB, 0x0E, 0x2E, 0x07, 0xD2, 0xDF, 0x66, 0xAA, 0xB1, 0x93, 0x88, 0xF7, 0x7E, 0xB8, 0xCE, 0x2F, 0xD5, 0x04, 0x2B, 0x20, 0x0F, 0x30, 0x14, 0x6A, 0x3F, 0x40, 0xDA, 0x22, 0x17, 0x07, 0x88, 0x0F, 0x72, 0x03, 0x84, 0x12, 0x34, 0x9A, 0x63, 0x47, 0x91, 0x75, 0x0B, 0x05, 0x9A, 0x43, 0x9B, 0xE4, 0x36, 0xC2, 0xCA, 0x75, 0x33, 0xEB, 0xFE, 0xFB, 0xE7, 0xEF, 0xCC, 0x1F, 0x70, 0x48, 0x4E, 0xFE, 0x47, 0x32, 0xAE, 0xAD, 0xF1, 0x10, 0x48, 0xBA, 0x32, 0xBE, 0xE7, 0xC1, 0xED, 0xCD, 0x55, 0x05, 0x86, 0x82, 0xCB, 0x91, 0x74, 0xD3, 0xBC, 0xCB, 0x59, 0x3F, 0x2D, 0x12, 0x83, 0x5B, 0xA0, 0xEE, 0xCF, 0x78, 0x7A, 0x5A, 0xB0, 0x61, 0xA6, 0xE5, 0xDD, 0xE8, 0xF7, 0x9C, 0xB7, 0x27, 0xDF, 0x5F, 0xCE, 0x69, 0x06, 0xC0, 0x8E, 0xB2, 0x6E, 0x9F, 0x25, 0xE0, 0x00, 0xD6, 0x80, 0x06, 0x70, 0xF6, 0xCD, 0x51, 0x7C, 0x92, 0x03, 0xF4, 0x33, 0x41, 0x79, 0xF7, 0x44, 0x12, 0xBA, 0xAC, 0x54, 0x8A, 0x97, 0xAD, 0x10, 0x89, 0xC0, 0x59, 0x69, 0xFD, 0x43, 0x97, 0xEC, 0x7A, 0xDB, 0x6F, 0xD6, 0x85, 0x06, 0x50, 0xF6, 0x96, 0x03, 0xA8, 0xEC, 0x08, 0x9F, 0x67, 0x4D, 0x3D, 0xB3, 0xF8, 0x8A, 0x17, 0x18, 0x1E, 0xB2, 0x86, 0xF3, 0xC8, 0xDB, 0xBA, 0x60, 0x1E, 0xF5, 0xF8, 0x3C, 0x5B, 0xC7, 0x1A, 0x40, 0x09, 0x30, 0x7A, 0x4B, 0x82, 0x9D, 0x37, 0x05, 0x34, 0x37, 0x4B, 0x29, 0x0D, 0x16, 0xCC, 0x3D, 0x75, 0xE4, 0x6F, 0x80, 0x03, 0xF5, 0xC3, 0xCF, 0xD7, 0x08, 0x64, 0x22, 0x61, 0xFB, 0x1C, 0x40, 0x02, 0xB0, 0x03, 0x78, 0x00, 0x39, 0xC0, 0xFC, 0xF0, 0xBB, 0x18, 0x02, 0xF1, 0xD8, 0x2C, 0x7F, 0x87, 0xD0, 0x36, 0xA7, 0xE9, 0xD0, 0x12, 0xE0, 0x08, 0x36, 0xD5, 0x09, 0xAC, 0x9E, 0xA3, 0x08, 0x29, 0x94, 0x3E, 0xC5, 0xF8, 0x18, 0x19, 0x3F, 0x9C, 0x45, 0xC8, 0x7A, 0xC9, 0x8C, 0x91, 0x47, 0xCA, 0x45, 0x2E, 0xC6, 0x59, 0xBD, 0x0F, 0xA8, 0x00, 0x1E, 0xAF, 0x2C, 0xDD, 0x9A, 0x87, 0xBA, 0xFD, 0xBE, 0xFB, 0x97, 0x23, 0x72, 0x0E, 0x89, 0xBD, 0x04, 0xDC, 0xF7, 0xE1, 0x56, 0x79, 0x76, 0x00, 0x25, 0x40, 0x26, 0x50, 0x0E, 0xE4, 0x00, 0x65, 0x40, 0x3B, 0x30, 0x67, 0x43, 0xE6, 0x0B, 0x5F, 0x54, 0x02, 0x63, 0x8B, 0xDE, 0x2E, 0x91, 0xE7, 0x86, 0x2C, 0xD4, 0x81, 0x2C, 0xDA, 0xAC, 0xD6, 0x15, 0x1A, 0xAB, 0x73, 0xB5, 0x62, 0x31, 0x6E, 0xDB, 0xA7, 0xDC, 0x56, 0xD3, 0xB3, 0x60, 0xBA, 0x68, 0xD8, 0x2C, 0x9D, 0x09, 0xCB, 0x08, 0xB5, 0xDC, 0xFD, 0x40, 0xA3, 0x78, 0x23, 0xA2, 0x8C, 0xA6, 0xAF, 0x95, 0x0C, 0x30, 0x59, 0x24, 0xE0, 0x57, 0x52, 0xB2, 0xFD, 0xF9, 0x28, 0x62, 0x87, 0x1B, 0xFB, 0x49, 0x36, 0x70, 0xEC, 0x4D, 0xB9, 0x10, 0xBE, 0xF2, 0xAC, 0x45, 0x43, 0x2F, 0x88, 0x73, 0x13, 0xDC, 0x4B, 0x26, 0x9B, 0x53, 0x1A, 0x50, 0xF1, 0x49, 0x48, 0x70, 0xA0, 0xD7, 0x66, 0x56, 0x40, 0x12, 0x0D, 0xC4, 0x00, 0x1E, 0x0B, 0x01, 0x22, 0xD6, 0x74, 0x49, 0x9B, 0xF5, 0x6F, 0x72, 0x79, 0x32, 0x73, 0x6D, 0xAF, 0xC6, 0xA3, 0xEB, 0xBB, 0xD1, 0x7F, 0x31, 0xB8, 0x80, 0xE6, 0x36, 0x75, 0x57, 0x47, 0xD1, 0x36, 0x16, 0xFA, 0xCD, 0xC0, 0x05, 0xEA, 0xCA, 0x1C, 0xD3, 0xF3, 0x27, 0x0B, 0xC4, 0xAB, 0xB8, 0x2E, 0x72, 0x11, 0x00, 0xAD, 0x64, 0xF2, 0xCE, 0x4D, 0x66, 0x0C, 0x6F, 0xF1, 0x6A, 0xAE, 0x9F, 0x2D, 0x77, 0x6D, 0x4F, 0x9C, 0xEC, 0xF1, 0x69, 0x80, 0x4C, 0x3C, 0x14, 0x03, 0x5C, 0x81, 0x6C, 0xA0, 0x12, 0xE8, 0xC5, 0x34, 0x66, 0xE3, 0x11, 0x40, 0x06, 0xF0, 0x06, 0xEA, 0x2C, 0x62, 0xD1, 0x40, 0x0B, 0x30, 0x3B, 0x53, 0x4F, 0x03, 0x72, 0x00, 0x33, 0xDA, 0x6C, 0x68, 0x2C, 0x54, 0x46, 0x04, 0x6C, 0x76, 0x7C, 0x10, 0xD9, 0xE8, 0x6D, 0xE9, 0xAE, 0xB6, 0xFE, 0x80, 0xD8, 0x0E, 0xF8, 0x3F, 0x23, 0xF7, 0x13, 0x8D, 0x02, 0x82, 0x69, 0x1A, 0xDC, 0x0F, 0xE9, 0x16, 0x64, 0xC6, 0xA2, 0x39, 0x20, 0x94, 0x15, 0x59, 0x34, 0x57, 0x6F, 0xD9, 0x7D, 0xFF, 0x6D, 0xEF, 0xE3, 0xE7, 0x19, 0x59, 0x74, 0x6D, 0xC4, 0x00, 0x15, 0x40, 0xBF, 0x49, 0x1B, 0xCE, 0x2C, 0xC8, 0x7C, 0x12, 0xCD, 0x54, 0x36, 0x93, 0x83, 0x52, 0x0A, 0xCA, 0xA6, 0x11, 0x40, 0x08, 0xD0, 0xBB, 0xF6, 0x88, 0x00, 0xE6, 0x80, 0x1B, 0x10, 0xBA, 0x18, 0xA0, 0xF2, 0x4E, 0xAF, 0x17, 0x01, 0x9E, 0x1B, 0x7B, 0x1F, 0xDA, 0x0C, 0xEA, 0xEF, 0x8D, 0x55, 0xBF, 0x72, 0x70, 0x16, 0x90, 0x42, 0x09, 0xBD, 0xF9, 0xAA, 0xA0, 0x0C, 0xC3, 0xD3, 0xA8, 0x2D, 0xE0, 0x45, 0x1D, 0x08, 0x7B, 0xEF, 0xE4, 0x62, 0x4F, 0x72, 0x76, 0x53, 0x74, 0x93, 0x90, 0xC5, 0x00, 0xC9, 0x09, 0x7B, 0x69, 0xE5, 0x51, 0x2B, 0x12, 0xFA, 0x51, 0x74, 0xE4, 0x60, 0x8E, 0x05, 0xE0, 0x09, 0xA4, 0xDF, 0x05, 0x27, 0x35, 0xBB, 0xCC, 0x18, 0x8C, 0xC5, 0x6F, 0xAB, 0x7A, 0xEF, 0x0F, 0xD2, 0x40, 0xD6, 0xE6, 0x83, 0x0A, 0x10, 0x06, 0x74, 0x6E, 0xA2, 0xCB, 0x47, 0x47, 0xD2, 0x0E, 0x10, 0x02, 0xD4, 0x00, 0xA3, 0xD8, 0x65, 0xF4, 0xB1, 0x99, 0xC0, 0x2E, 0xE2, 0xB0, 0xBC, 0xE9, 0x9D, 0xD5, 0x91, 0x82, 0x25, 0xBD, 0xE7, 0x07, 0x55, 0xFD, 0x1D, 0x5D, 0xEB, 0xE4, 0x55, 0x08, 0x9A, 0xF9, 0x09, 0x49, 0x3D, 0x9D, 0x1C, 0x0A, 0xC8, 0x59, 0xD4, 0xA7, 0xAB, 0xD9, 0x00, 0x91, 0xC0, 0x5C, 0x45, 0xD9, 0xB8, 0x5C, 0xC2, 0xE8, 0xDE, 0x77, 0xCA, 0x86, 0x6E, 0xB2, 0xFD, 0x73, 0x9B, 0xC8, 0xBD, 0x7B, 0x29, 0x20, 0x54, 0x5D, 0xEB, 0x37, 0x17, 0xA6, 0x9E, 0x7F, 0x10, 0x6F, 0xC6, 0xC8, 0x81, 0xDE, 0x0B, 0xA8, 0x1E, 0x20, 0x87, 0x7D, 0xCB, 0x81, 0xAA, 0x85, 0x00, 0xB1, 0x10, 0x8A, 0x25, 0x52, 0x85, 0xA0, 0x81, 0x39, 0xB4, 0x9A, 0x6E, 0x32, 0x61, 0xE1, 0x8E, 0x10, 0x79, 0x79, 0x39, 0xB2, 0x07, 0xC6, 0x9B, 0xFC, 0x61, 0xCB, 0x67, 0xAD, 0xC3, 0x2F, 0xAB, 0x45, 0x7C, 0xBC, 0x1C, 0xF6, 0x29, 0x65, 0x77, 0x5F, 0x28, 0x60, 0xE7, 0x83, 0x01, 0xBA, 0x60, 0x35, 0x66, 0x32, 0xF4, 0x23, 0xFA, 0xD1, 0x6F, 0x08, 0x2E, 0x1E, 0x3F, 0x66, 0x24, 0x33, 0x81, 0x98, 0x10, 0x0F, 0xF4, 0x79, 0x13, 0x82, 0xF2, 0x51, 0x63, 0x77, 0x26, 0x2D, 0x2C, 0xE6, 0x69, 0x86, 0x0E, 0xE4, 0xB9, 0xAF, 0xDF, 0x29, 0xC0, 0xD4, 0x22, 0x81, 0x16, 0x20, 0x1A, 0x70, 0x03, 0xE2, 0x69, 0xA2, 0x4E, 0xAB, 0x19, 0xF4, 0xD6, 0x26, 0x57, 0x26, 0xD6, 0x2E, 0x2F, 0x87, 0xE5, 0xC0, 0x77, 0x20, 0xBE, 0x19, 0x44, 0x86, 0xE0, 0x5C, 0xF9, 0x1D, 0xFE, 0xAC, 0x8F, 0xD5, 0xFC, 0xDC, 0x63, 0xAD, 0x7A, 0xE1, 0xDF, 0x7C, 0x5B, 0xA0, 0xF3, 0xAD, 0x21, 0xCE, 0x7D, 0xC8, 0x66, 0x04, 0x74, 0x25, 0x3F, 0x6D, 0xFF, 0x7B, 0x81, 0x6D, 0x8C, 0xE2, 0x28, 0x57, 0x35, 0x4C, 0xE5, 0x3E, 0xA4, 0xE2, 0xC5, 0x15, 0x4C, 0x62, 0xE0, 0x05, 0x3B, 0xFA, 0x75, 0x6D, 0xB2, 0x02, 0x7A, 0x1D, 0xE0, 0xB1, 0x18, 0xC2, 0x81, 0x5A, 0xF8, 0x01, 0x64, 0x00, 0x7B, 0xEE, 0x75, 0xB4, 0x9A, 0x6F, 0xB1, 0x51, 0x6F, 0x67, 0x9B, 0xBE, 0x14, 0x28, 0xA4, 0x64, 0x2F, 0x41, 0x83, 0x3F, 0x50, 0x07, 0xE3, 0x67, 0xF4, 0xF2, 0x0D, 0xD5, 0xB7, 0xEF, 0x2C, 0xCD, 0xE5, 0x76, 0x1B, 0x28, 0x6F, 0x1D, 0x80, 0xFF, 0x9E, 0xA1, 0xC1, 0xD2, 0x44, 0xBA, 0x23, 0x85, 0x29, 0x65, 0xC5, 0xF6, 0xC2, 0x54, 0x76, 0x00, 0xC4, 0x77, 0x4E, 0x0E, 0x90, 0x3F, 0xD8, 0x7E, 0xAA, 0x27, 0x61, 0xE5, 0x11, 0xC6, 0x3E, 0xB7, 0xA6, 0x9A, 0x2A, 0x10, 0xBE, 0x36, 0x14, 0x20, 0x06, 0x98, 0x03, 0x74, 0x01, 0x65, 0x80, 0x17, 0x60, 0x0A, 0x38, 0x3D, 0x71, 0x42, 0xAB, 0x05, 0x4E, 0xF9, 0x3A, 0x58, 0x7F, 0xE3, 0x4E, 0x50, 0xE8, 0xA3, 0xAB, 0x10, 0x9B, 0x2B, 0x42, 0x95, 0x18, 0x31, 0x3A, 0xCC, 0x59, 0xBE, 0xD7, 0x35, 0xB1, 0xFF, 0x68, 0xFD, 0x93, 0x01, 0xC4, 0x2C, 0x64, 0x61, 0x77, 0x65, 0xFB, 0x53, 0xDB, 0xFD, 0x08, 0x23, 0xB2, 0x2C, 0x8F, 0x12, 0x28, 0x79, 0xFB, 0x6B, 0xDB, 0x00, 0xA5, 0x00, 0xBD, 0x03, 0x45, 0x21, 0x52, 0x46, 0x67, 0xA8, 0xAC, 0x49, 0xC1, 0x62, 0x2A, 0x30, 0x05, 0xD0, 0x9F, 0x3B, 0x55, 0x3D, 0xED, 0x42, 0x80, 0xF2, 0x45, 0x00, 0xE9, 0x80, 0x07, 0x60, 0x06, 0x38, 0x6E, 0x58, 0xEF, 0x58, 0xCB, 0xED, 0xF2, 0x1B, 0xFF, 0x4C, 0x11, 0x2D, 0xAE, 0xC1, 0x9C, 0xC4, 0xC6, 0x16, 0x5B, 0x2C, 0xC5, 0x85, 0xD0, 0x50, 0x4F, 0x9C, 0xF9, 0x1F, 0xED, 0x58, 0xA4, 0xEF, 0x16, 0x19, 0xC2, 0x80, 0x5E, 0x00, 0x3E, 0x80, 0xD5, 0x62, 0x00, 0x77, 0x60, 0x68, 0xAE, 0xE3, 0xCC, 0xAB, 0xA3, 0x8C, 0xE0, 0xAD, 0x4C, 0xFB, 0x34, 0xB7, 0xD8, 0x9F, 0x4D, 0x01, 0x16, 0x00, 0x55, 0x6B, 0x29, 0x50, 0x92, 0x94, 0xE1, 0xE0, 0x05, 0x63, 0x4D, 0x12, 0xC3, 0xEF, 0x0B, 0x44, 0xDF, 0xBD, 0xF4, 0xA2, 0x80, 0x91, 0x1B, 0x1D, 0x40, 0x2D, 0xB2, 0xDF, 0x87, 0xF1, 0xD7, 0x58, 0xA4, 0x0B, 0xCE, 0x19, 0x2D, 0x04, 0xCF, 0x42, 0x7F, 0x77, 0x2C, 0x3F, 0x1B, 0x52, 0xE9, 0xC2, 0xA8, 0x5C, 0x77, 0x7A, 0xA7, 0x23, 0xEF, 0x4A, 0x84, 0xEB, 0xD8, 0xED, 0x51, 0x2B, 0x26, 0x3F, 0xAE, 0x29, 0xF4, 0x96, 0x9E, 0xA8, 0x02, 0xC2, 0x00, 0x4B, 0x40, 0x15, 0x08, 0x3F, 0x6F, 0xCE, 0x1A, 0xBF, 0x35, 0xB2, 0xB9, 0xAE, 0x2D, 0x4D, 0x13, 0x46, 0xEB, 0x03, 0xC4, 0x42, 0x0A, 0x60, 0xD4, 0x83, 0xF2, 0x1B, 0xBD, 0xF6, 0xC9, 0x1F, 0xEA, 0xE9, 0x39, 0x27, 0x07, 0x98, 0x5C, 0xD1, 0xEF, 0x8D, 0x66, 0x1D, 0x07, 0xA2, 0x81, 0x0E, 0x60, 0x14, 0xE8, 0x59, 0xD8, 0x22, 0x81, 0x59, 0x17, 0x5C, 0x04, 0x8D, 0xF6, 0x26, 0x5C, 0x41, 0x07, 0x06, 0xD5, 0x8F, 0xC7, 0x30, 0xB8, 0x02, 0xDB, 0x6B, 0xB8, 0x21, 0x0C, 0x19, 0x1B, 0xDE, 0xD3, 0x79, 0x62, 0x77, 0x8F, 0xB7, 0x43, 0x76, 0x50, 0xF9, 0x9F, 0x8E, 0x63, 0x50, 0x5D, 0x74, 0x4D, 0x71, 0x98, 0xC5, 0xE7, 0x40, 0xCF, 0x8B, 0x78, 0x7A, 0xEE, 0x26, 0xFB, 0xA0, 0xD8, 0xAD, 0xFA, 0xAD, 0x0A, 0xC4, 0x00, 0x75, 0x00, 0xB6, 0xAC, 0x14, 0x05, 0xC6, 0xE9, 0x37, 0x82, 0x45, 0x84, 0x27, 0x63, 0x5E, 0x49, 0x79, 0xF9, 0xD1, 0xBB, 0xBE, 0xC2, 0x17, 0xDD, 0x1F, 0x85, 0x8E, 0x03, 0x84, 0x02, 0x99, 0x40, 0xBF, 0x89, 0xCF, 0x57, 0x51, 0x8B, 0xD3, 0x68, 0xB3, 0x07, 0xA3, 0x46, 0x42, 0x62, 0xC8, 0x6F, 0x7E, 0xC6, 0xE8, 0xE6, 0x26, 0x6D, 0x41, 0x86, 0xE7, 0xF6, 0x41, 0xF1, 0x9F, 0x47, 0x5F, 0x23, 0x79, 0x55, 0xBF, 0xB7, 0x82, 0xAB, 0x3D, 0x19, 0x7B, 0xFB, 0xD4, 0x9F, 0xEF, 0x63, 0x51, 0x1F, 0x34, 0x1D, 0x95, 0x7D, 0x95, 0x58, 0x71, 0x97, 0xD3, 0x67, 0xEB, 0x13, 0xA3, 0x08, 0x1B, 0xF0, 0x44, 0x91, 0x12, 0x70, 0x03, 0x9A, 0xDB, 0x22, 0x7D, 0x26, 0xBD, 0x26, 0x5C, 0xFF, 0x58, 0x60, 0xC4, 0x2C, 0xB0, 0x2A, 0xAD, 0x4C, 0x3C, 0x90, 0xAC, 0xDA, 0x4E, 0x20, 0x65, 0x31, 0x8B, 0x00, 0xA2, 0x16, 0x09, 0xD4, 0x1E, 0xB7, 0x9F, 0x64, 0xD2, 0xE1, 0xB5, 0x80, 0x5A, 0x92, 0xF3, 0xAF, 0xFC, 0x89, 0xC6, 0x68, 0xC7, 0xCA, 0xDF, 0xF5, 0x3A, 0x31, 0xF3, 0xE7, 0x96, 0x55, 0xEB, 0xAB, 0xCC, 0x2C, 0xBF, 0x69, 0x91, 0x0D, 0xA3, 0x71, 0x15, 0x2B, 0x59, 0x34, 0x90, 0xBE, 0x90, 0x45, 0xB0, 0xE3, 0xEE, 0x95, 0xB2, 0x80, 0xBF, 0x97, 0x91, 0x3B, 0x9C, 0x1E, 0x02, 0xC8, 0xCF, 0x64, 0x1D, 0x65, 0xE4, 0x03, 0x18, 0x3A, 0x56, 0x77, 0x7D, 0x67, 0xBD, 0xBF, 0xF3, 0x46, 0xB6, 0x33, 0x4A, 0x06, 0x66, 0x92, 0x04, 0x2A, 0xD7, 0x5A, 0xFA, 0xB1, 0x88, 0x01, 0x4D, 0x1F, 0x81, 0x00, 0x7A, 0x00, 0x5F, 0x84, 0x03, 0x55, 0x34, 0x9A, 0x60, 0x2F, 0xCF, 0xDE, 0x9B, 0x8E, 0xA1, 0xB8, 0xD4, 0x72, 0x67, 0xD9, 0xAC, 0xE4, 0x7D, 0xEF, 0xB5, 0xD0, 0xB1, 0xB3, 0xAF, 0x58, 0x58, 0x50, 0x82, 0xE8, 0xD6, 0x0A, 0x3B, 0xE7, 0xC9, 0x12, 0x67, 0x6A, 0x0F, 0x30, 0x0D, 0xD4, 0x00, 0x11, 0x80, 0x2D, 0x8A, 0x81, 0xA1, 0xAB, 0x7F, 0xEE, 0xA6, 0x15, 0xC0, 0xDD, 0x01, 0xB0, 0x99, 0x8F, 0x3D, 0x42, 0x60, 0x94, 0xA1, 0x05, 0xE8, 0xEE, 0x50, 0x7D, 0x5B, 0x81, 0x62, 0x9C, 0x63, 0x3E, 0x26, 0x4B, 0x8D, 0x81, 0xD9, 0x59, 0x66, 0x01, 0x74, 0xEE, 0x15, 0xD5, 0x81, 0xD2, 0x85, 0x01, 0x19, 0x40, 0x2C, 0x3C, 0x01, 0x0A, 0xD7, 0x69, 0xD3, 0x66, 0xCC, 0x1A, 0x62, 0xDE, 0x2E, 0x92, 0xFD, 0xAC, 0x6B, 0x5B, 0xD0, 0xA0, 0xF9, 0x94, 0x4C, 0x62, 0x98, 0x2B, 0x2E, 0x07, 0xAD, 0xB0, 0x99, 0x3F, 0xF1, 0x75, 0x30, 0xE4, 0xD3, 0x8D, 0x85, 0x7D, 0xE5, 0xD9, 0x8C, 0x8C, 0xCD, 0xE6, 0x2B, 0x81, 0x50, 0xC0, 0x0C, 0x60, 0xEB, 0x59, 0x8A, 0x2B, 0x25, 0xBB, 0xC5, 0x52, 0xF6, 0x41, 0x69, 0x98, 0x45, 0x02, 0xD9, 0xC0, 0x18, 0x4C, 0x38, 0xAC, 0x66, 0x7F, 0x3D, 0x38, 0x61, 0xB0, 0x6B, 0xEC, 0x32, 0x99, 0x6B, 0xF3, 0x84, 0xBE, 0x1F, 0x04, 0x01, 0x12, 0x48, 0x5D, 0x5D, 0x00, 0x01, 0x64, 0x00, 0x4B, 0xC0, 0x0B, 0x28, 0xBD, 0xC5, 0x02, 0x24, 0x01, 0x4F, 0x1A, 0xCD, 0xF0, 0x1D, 0x8E, 0xC3, 0x67, 0x1A, 0xFE, 0x8B, 0xAC, 0x4C, 0xF6, 0x46, 0x28, 0x66, 0xB3, 0xBF, 0x58, 0x56, 0x20, 0x88, 0x99, 0x5B, 0x50, 0x74, 0xFF, 0x53, 0x2E, 0xC5, 0x4A, 0xB9, 0x6F, 0x2F, 0x33, 0x59, 0x18, 0x90, 0x03, 0x84, 0x00, 0x96, 0x40, 0xE4, 0x75, 0xF2, 0x90, 0xB5, 0x2F, 0xC4, 0x87, 0xF6, 0x02, 0x7C, 0x2B, 0x6D, 0xBA, 0x01, 0xEA, 0xC0, 0xD1, 0xF7, 0x61, 0x3E, 0x9D, 0xB7, 0x22, 0x6E, 0x09, 0x22, 0x46, 0xE1, 0x78, 0xE0, 0xD2, 0xBE, 0x9B, 0xDD, 0x9A, 0x02, 0x4D, 0xE1, 0xC4, 0xB3, 0xC8, 0x45, 0x00, 0xE2, 0x0B, 0xFE, 0xAC, 0x80, 0x76, 0x5A, 0xCD, 0xF1, 0x8F, 0x5C, 0x02, 0x1F, 0xC0, 0x9C, 0x3B, 0x27, 0xD2, 0xEB, 0x87, 0x9A, 0xDE, 0x16, 0x75, 0x85, 0x12, 0x6A, 0x99, 0xFB, 0x02, 0xFA, 0xD5, 0xE0, 0xFF, 0x16, 0x1C, 0x97, 0x02, 0xB9, 0x88, 0xCF, 0x35, 0x2B, 0x14, 0xE8, 0x7E, 0x75, 0x84, 0x9B, 0xC6, 0xA3, 0x34, 0x38, 0x2E, 0x0E, 0x97, 0x9C, 0xF0, 0x61, 0x05, 0x6E, 0x02, 0xAE, 0x40, 0xAD, 0x99, 0x9D, 0x55, 0x36, 0xFA, 0x36, 0xB3, 0xEA, 0xBF, 0x56, 0x38, 0xF6, 0x39, 0xD7, 0x26, 0x8C, 0x67, 0x07, 0x18, 0x83, 0xF1, 0xF4, 0xDB, 0xE4, 0x55, 0xD6, 0xBE, 0x0D, 0xE4, 0x00, 0xF5, 0x83, 0xBD, 0x63, 0x2D, 0x70, 0x8A, 0x5A, 0xCF, 0x90, 0x47, 0xFE, 0x04, 0xD6, 0x32, 0x1B, 0xE7, 0x1F, 0x99, 0x8D, 0x22, 0xEF, 0xCC, 0x1A, 0x87, 0x76, 0x55, 0xC4, 0x25, 0xBB, 0x5C, 0xF6, 0xD1, 0xE0, 0xAF, 0x62, 0xED, 0xD7, 0xDA, 0x42, 0x3E, 0x15, 0x7A, 0x86, 0x9F, 0x4D, 0x2F, 0x74, 0x1F, 0x5E, 0x2D, 0x83, 0xF0, 0xAD, 0xDF, 0x66, 0x6F, 0x98, 0x15, 0x30, 0x5E, 0x03, 0xA6, 0x80, 0x9F, 0x85, 0xBF, 0xF7, 0xF5, 0xFA, 0xCB, 0xD2, 0xA3, 0xB0, 0x90, 0xBC, 0xDD, 0x9D, 0x91, 0x63, 0xC8, 0x55, 0x11, 0x4B, 0xB3, 0x00, 0xF1, 0x69, 0xEF, 0x63, 0x05, 0x78, 0x2E, 0x06, 0x08, 0x59, 0xF8, 0xDD, 0xC8, 0x45, 0x0E, 0xAD, 0x96, 0x2B, 0x5D, 0xDD, 0x28, 0xC4, 0x1D, 0x47, 0xED, 0x6C, 0xF8, 0xD6, 0x18, 0xDB, 0xE6, 0xE0, 0xE7, 0x0A, 0xDC, 0xDB, 0x6F, 0x9E, 0x95, 0x1B, 0x5C, 0x42, 0xFF, 0x25, 0xB0, 0x66, 0xF1, 0x39, 0x74, 0x0C, 0xD0, 0x06, 0x44, 0x03, 0xFE, 0x11, 0xC4, 0x4A, 0xF9, 0xBA, 0x86, 0xA8, 0x65, 0xCA, 0x0C, 0x21, 0xE1, 0xA7, 0x8F, 0xC6, 0xC7, 0x5E, 0xA1, 0x7A, 0xF0, 0xE9, 0x30, 0x7B, 0xE8, 0x52, 0x39, 0x9C, 0xD5, 0x88, 0xA1, 0x1F, 0x3D, 0x9E, 0x86, 0xC0, 0x4E, 0xC5, 0x18, 0x01, 0xD8, 0x06, 0xD7, 0x1A, 0xA8, 0x58, 0x18, 0x10, 0x05, 0x68, 0x00, 0xC7, 0x01, 0x3D, 0xC0, 0x04, 0x8D, 0xC6, 0xE2, 0x32, 0x0A, 0xF9, 0x2B, 0x34, 0x50, 0x1C, 0x01, 0x75, 0x64, 0x7B, 0x08, 0x94, 0xAB, 0x2D, 0xD8, 0x0A, 0x62, 0x55, 0x85, 0x71, 0x1F, 0x7A, 0xE3, 0x04, 0x96, 0x9F, 0xD2, 0x76, 0x65, 0x4D, 0x7B, 0x02, 0x1D, 0x80, 0x0F, 0xA0, 0x0E, 0x1C, 0x05, 0x58, 0x1B, 0xE6, 0x49, 0x57, 0x05, 0xDB, 0xE6, 0xDD, 0x2A, 0x55, 0x47, 0x6E, 0x19, 0x60, 0x35, 0xC0, 0xE7, 0x8D, 0x78, 0xD9, 0xD3, 0xFB, 0xCD, 0xF6, 0x40, 0x4A, 0xF7, 0xA1, 0xB3, 0xE7, 0x73, 0xC0, 0xF5, 0x6D, 0xEB, 0xC9, 0x0E, 0xA3, 0xEF, 0x1A, 0xE8, 0xDA, 0x60, 0x93, 0x00, 0x76, 0x00, 0x1F, 0xE0, 0x67, 0xC1, 0xFA, 0xDD, 0xF0, 0x00, 0x09, 0xC0, 0x9D, 0x36, 0xE3, 0x95, 0x80, 0xED, 0x99, 0x7C, 0xEF, 0x51, 0xB5, 0x1A, 0xBF, 0x8E, 0xBC, 0xC1, 0x40, 0x00, 0x34, 0x32, 0x7E, 0x43, 0xE3, 0x48, 0xBE, 0x2D, 0xE0, 0xE6, 0x56, 0xAA, 0xC6, 0x25, 0x1D, 0x63, 0x8A, 0x71, 0xF4, 0x06, 0xE4, 0xD3, 0xF7, 0x22, 0x05, 0x70, 0x03, 0x32, 0x69, 0x65, 0x16, 0x83, 0xED, 0xDE, 0xAA, 0xC1, 0xFC, 0x65, 0x20, 0x7B, 0xE1, 0x00, 0x5B, 0xBE, 0x9F, 0x02, 0x46, 0x5F, 0x77, 0xD8, 0x3C, 0x39, 0xBB, 0xB2, 0x13, 0xB1, 0xFA, 0x4D, 0xF2, 0xA3, 0xCF, 0x3C, 0xF6, 0x90, 0x9B, 0xCF, 0xF1, 0xC4, 0x12, 0x08, 0x07, 0xB2, 0x81, 0x56, 0x0A, 0x0E, 0x01, 0x6A, 0x80, 0x39, 0x10, 0x45, 0xA3, 0xCD, 0x2F, 0x6B, 0xE0, 0x4C, 0xEF, 0xCC, 0x0D, 0x6C, 0xC6, 0xE9, 0x98, 0x10, 0x93, 0x48, 0x5B, 0x15, 0x59, 0x6D, 0x4E, 0x83, 0xE7, 0x74, 0x73, 0x6F, 0x15, 0x46, 0xEB, 0xA7, 0x81, 0xAA, 0x7C, 0x47, 0x5A, 0xEC, 0x48, 0x53, 0xA0, 0x05, 0xF0, 0x03, 0x9C, 0x5D, 0xC2, 0xB3, 0x80, 0xA2, 0x07, 0x68, 0x67, 0x20, 0x8F, 0x3E, 0x76, 0xEE, 0x1B, 0xFB, 0x29, 0x3C, 0x2C, 0x01, 0xD2, 0x80, 0xDB, 0xC9, 0x1A, 0x8F, 0x3C, 0x5F, 0x30, 0xAA, 0x7E, 0x78, 0x6E, 0x63, 0x43, 0xC1, 0x3B, 0x7C, 0xD7, 0x7B, 0x8A, 0xF3, 0xC5, 0x13, 0x61, 0x08, 0xC0, 0x88, 0xBE, 0x3F, 0xF9, 0x01, 0x22, 0xA8, 0x90, 0x08, 0xA3, 0xE5, 0xE1, 0x95, 0x60, 0xA3, 0x63, 0x86, 0x43, 0x47, 0xD4, 0x6A, 0x4D, 0xB8, 0xAF, 0xD3, 0x64, 0xC5, 0xBE, 0xFB, 0x77, 0x8F, 0x3A, 0xD6, 0xC6, 0x85, 0xFF, 0xCE, 0x8D, 0xCF, 0xFB, 0x1E, 0x55, 0xCE, 0x58, 0xCD, 0xC2, 0x77, 0x65, 0x5B, 0x54, 0x2E, 0xF6, 0x67, 0xE2, 0x57, 0x51, 0x1E, 0x53, 0x4D, 0x31, 0x62, 0x60, 0xAD, 0xB5, 0x4F, 0xC7, 0x42, 0x68, 0xC2, 0x3B, 0x63, 0x08, 0x48, 0x16, 0x09, 0xB1, 0x79, 0x1B, 0xCC, 0xEB, 0x05, 0x84, 0xAC, 0xE7, 0x1F, 0xFE, 0x5E, 0x28, 0x2A, 0xB3, 0xAB, 0x79, 0xAD, 0x8A, 0xB5, 0x02, 0x5A, 0x80, 0x27, 0x90, 0x0E, 0x74, 0x6C, 0xC0, 0x61, 0x00, 0x2D, 0x20, 0x9C, 0x46, 0x13, 0x88, 0x9A, 0x65, 0xFD, 0xA4, 0xE8, 0xC6, 0x51, 0xDF, 0x9E, 0x29, 0xEB, 0xB2, 0xAC, 0x9D, 0x1F, 0x0A, 0x6F, 0xB3, 0x18, 0x4E, 0x0E, 0x36, 0x57, 0xAB, 0x87, 0xC8, 0x4F, 0x42, 0x64, 0xB0, 0x08, 0xFD, 0x00, 0x61, 0x80, 0x2B, 0x1F, 0xC2, 0xB0, 0xB3, 0xC8, 0xBE, 0x93, 0x4A, 0x9D, 0x2A, 0xFC, 0x2C, 0x4B, 0xFE, 0x88, 0x71, 0x9A, 0x01, 0xB2, 0xB0, 0x85, 0xEF, 0x2B, 0xCA, 0x64, 0xF1, 0x64, 0x1D, 0xD3, 0xD3, 0xA5, 0xF0, 0xF5, 0x82, 0xE5, 0x23, 0xB3, 0xC3, 0x55, 0x3E, 0x83, 0x7B, 0x29, 0xD0, 0xBC, 0x72, 0x35, 0xA0, 0xB2, 0x18, 0xC0, 0x16, 0xA1, 0x40, 0xE6, 0xFA, 0x47, 0x94, 0x56, 0x53, 0x9C, 0x28, 0xCB, 0x7E, 0xA5, 0x04, 0x26, 0x7E, 0x15, 0x80, 0xE6, 0x08, 0x3D, 0x6B, 0xDB, 0x9B, 0x51, 0xD1, 0x22, 0x2A, 0xFA, 0x6E, 0xF5, 0xF0, 0x24, 0xA9, 0x7D, 0x04, 0x21, 0xE2, 0x73, 0x52, 0x8B, 0xFA, 0xE8, 0x08, 0x17, 0x70, 0x12, 0x90, 0x4B, 0x87, 0x22, 0x01, 0x58, 0xED, 0xEE, 0x31, 0xD5, 0x0A, 0x78, 0x03, 0xE9, 0xB7, 0x52, 0x60, 0xFC, 0x20, 0x9C, 0xAE, 0x8C, 0xA5, 0xC2, 0x7D, 0xC1, 0x86, 0x20, 0x1B, 0xFE, 0xD8, 0x8B, 0xE3, 0x79, 0x33, 0x9F, 0xEB, 0xC9, 0x8A, 0x2E, 0x67, 0x08, 0x10, 0x30, 0x5D, 0x08, 0x20, 0xB3, 0x28, 0xC0, 0x38, 0x41, 0x93, 0x56, 0x33, 0x84, 0xD9, 0x7D, 0x43, 0xAA, 0xE7, 0xDC, 0x61, 0x29, 0x51, 0xAC, 0x27, 0xB5, 0x31, 0x3C, 0x1B, 0x9C, 0xFB, 0xFB, 0x96, 0x03, 0x48, 0xFF, 0x06, 0x58, 0xE2, 0x8E, 0x9E, 0xE4, 0x01, 0x42, 0x01, 0x13, 0x40, 0x7D, 0xA1, 0x80, 0xAF, 0xD5, 0x1E, 0x23, 0xC8, 0x53, 0xB0, 0x0D, 0xD4, 0x6A, 0xC3, 0x9C, 0x3B, 0x4F, 0x30, 0x6D, 0xE1, 0x7C, 0x73, 0x3D, 0x4F, 0x5C, 0x0E, 0xFD, 0x15, 0x84, 0xB4, 0x78, 0xDA, 0xA8, 0x0C, 0xCF, 0x66, 0xFE, 0x66, 0xA9, 0xED, 0x2E, 0x8E, 0x95, 0x0F, 0x70, 0x07, 0xC2, 0x00, 0x1F, 0xC0, 0x08, 0x07, 0x22, 0xF6, 0xB2, 0x1F, 0xB4, 0x9A, 0xFF, 0x43, 0x4C, 0xCC, 0x0D, 0x39, 0x23, 0xF0, 0x0F, 0xED, 0x66, 0x00, 0xD1, 0xE0, 0x9D, 0xA9, 0xBA, 0x3D, 0x2D, 0x1B, 0x2D, 0x2D, 0xAC, 0xFF, 0x3A, 0x0D, 0xE2, 0x9B, 0xDD, 0x45, 0x3F, 0x00, 0x62, 0xE5, 0xD7, 0x65, 0xAA, 0x0C, 0xB0, 0xC5, 0x39, 0x78, 0x25, 0x7D, 0xB1, 0xAF, 0x3C, 0xB2, 0x0B, 0x14, 0xAA, 0x23, 0x68, 0xBD, 0x10, 0x40, 0xF9, 0xA9, 0x80, 0x1A, 0xBC, 0xD2, 0x14, 0xB1, 0x7B, 0x5B, 0xA6, 0xC0, 0x9F, 0x4A, 0x9F, 0xCE, 0x7A, 0xCE, 0x76, 0x61, 0xAB, 0x0D, 0x11, 0x9F, 0x04, 0x7A, 0x76, 0x29, 0x13, 0x20, 0xF3, 0xB3, 0x94, 0x09, 0xA0, 0x0E, 0x78, 0x01, 0xB1, 0xA8, 0xA4, 0xD9, 0xDE, 0xDC, 0xA1, 0x42, 0xAF, 0x9F, 0x3B, 0x67, 0xD9, 0x36, 0xE4, 0xB5, 0x49, 0xB8, 0xDD, 0xD0, 0x3D, 0x8E, 0xBA, 0x15, 0x3B, 0xE4, 0xDB, 0xC3, 0x46, 0xB8, 0x2B, 0x7C, 0x06, 0xDB, 0x42, 0x07, 0x10, 0x22, 0x00, 0xCB, 0xBB, 0x35, 0x17, 0xC7, 0x95, 0x3B, 0xD0, 0x02, 0x1C, 0x5F, 0x8B, 0xDA, 0x7D, 0x98, 0xD1, 0xB9, 0x34, 0x36, 0xD9, 0x19, 0x58, 0x9F, 0x72, 0x94, 0xFE, 0x61, 0x9E, 0x2A, 0x98, 0xDC, 0x29, 0xFA, 0xD5, 0x90, 0x70, 0x01, 0xDA, 0x37, 0xE9, 0x65, 0x21, 0x05, 0x98, 0x02, 0x5E, 0x40, 0x0E, 0x50, 0x0E, 0x4C, 0xD0, 0x6A, 0x89, 0xCB, 0x39, 0xC4, 0x70, 0x61, 0xD1, 0x29, 0xEC, 0xA1, 0xD8, 0xAF, 0x7C, 0x3B, 0x0E, 0x24, 0xEE, 0x34, 0x15, 0x10, 0xB1, 0xD9, 0x8B, 0x7B, 0xFE, 0x67, 0xE7, 0x1F, 0xB7, 0x4F, 0x36, 0x77, 0x2D, 0x0E, 0xE0, 0xBD, 0x38, 0x80, 0xF1, 0x4D, 0x7D, 0x05, 0xAD, 0xF3, 0x11, 0xE8, 0xB7, 0x05, 0x0F, 0x76, 0x65, 0x80, 0x25, 0xE0, 0x07, 0xB0, 0x00, 0x78, 0xE1, 0xFF, 0x91, 0xCD, 0x6E, 0xAF, 0x82, 0x1B, 0x66, 0xD8, 0x46, 0xDC, 0x4A, 0x61, 0xDF, 0x1B, 0x7B, 0x08, 0xD0, 0xB6, 0x48, 0xA0, 0x0A, 0x48, 0x03, 0x62, 0x91, 0x6C, 0xC0, 0xFC, 0x58, 0xAD, 0x2E, 0x29, 0x3F, 0x11, 0xFF, 0x57, 0xB1, 0xEE, 0xA0, 0x42, 0x47, 0x63, 0x24, 0x9A, 0x35, 0xFE, 0x16, 0x2B, 0xCC, 0x25, 0xEB, 0xD7, 0x83, 0xDB, 0xFA, 0xBD, 0x4C, 0xF5, 0xF7, 0xE4, 0xB1, 0x8B, 0xBB, 0x01, 0x31, 0x80, 0x05, 0x20, 0x0A, 0xD8, 0xB9, 0xD2, 0x75, 0xD7, 0x25, 0xF1, 0xE4, 0x50, 0xD6, 0x53, 0x29, 0xDB, 0x01, 0xE4, 0xA7, 0x14, 0x53, 0x0A, 0x66, 0x52, 0x46, 0x85, 0xD9, 0x96, 0x67, 0x93, 0x8B, 0x78, 0x2C, 0x45, 0xF7, 0x06, 0xDE, 0x16, 0x9C, 0xC7, 0x8A, 0x67, 0xA2, 0xE9, 0x00, 0xF5, 0xE9, 0x80, 0x29, 0x0E, 0xE8, 0x00, 0xBE, 0xA8, 0x00, 0xDA, 0xA9, 0xE9, 0x41, 0xA3, 0xF5, 0x63, 0xB4, 0xD9, 0x8E, 0x3F, 0x0D, 0xBD, 0x04, 0x94, 0xE6, 0xE4, 0x20, 0xD8, 0x23, 0xC3, 0x76, 0xEA, 0x90, 0xAC, 0x8A, 0x8F, 0x3E, 0x69, 0x5E, 0xD2, 0x13, 0xB6, 0x76, 0x8A, 0x27, 0x39, 0xC6, 0x02, 0x38, 0x8E, 0x87, 0x3C, 0x95, 0xCC, 0x00, 0x9E, 0x80, 0x38, 0xE0, 0x72, 0x2B, 0x7C, 0x8C, 0x01, 0xCF, 0xFE, 0xFA, 0x74, 0xAC, 0xE2, 0x27, 0x40, 0xFD, 0xD5, 0x78, 0x95, 0xBD, 0x8D, 0xB3, 0xB8, 0xC5, 0x0C, 0xF0, 0x58, 0x73, 0x29, 0x3E, 0x45, 0x3E, 0xAA, 0x25, 0x6C, 0xFC, 0xE9, 0x9B, 0x0F, 0x28, 0x0D, 0xC4, 0x01, 0x4A, 0x80, 0x11, 0xB8, 0xE2, 0x44, 0x01, 0xB3, 0x45, 0x03, 0x51, 0xB4, 0xDA, 0x9B, 0x42, 0xA4, 0xC8, 0x83, 0x79, 0x43, 0xA0, 0x1E, 0x8A, 0x93, 0xE4, 0xF4, 0xAA, 0x13, 0xC6, 0x4F, 0xC8, 0x64, 0xA4, 0xE8, 0x13, 0xBA, 0x25, 0xBE, 0xE5, 0x5E, 0xD5, 0x74, 0x00, 0x0F, 0xC0, 0xE4, 0xD3, 0xDC, 0xD2, 0x80, 0x3E, 0x8B, 0x64, 0xF9, 0xF6, 0x9A, 0x89, 0xD7, 0xFE, 0x06, 0x4C, 0x6E, 0x97, 0x89, 0x0C, 0xE0, 0x05, 0xE4, 0xBE, 0x92, 0x34, 0x5A, 0x33, 0x81, 0x19, 0x33, 0x12, 0xF0, 0xB3, 0xFF, 0xCA, 0xB9, 0x26, 0x9C, 0x1D, 0x2B, 0x9B, 0x0F, 0x1F, 0xFA, 0x68, 0x41, 0x9E, 0x00, 0x5C, 0x80, 0x0C, 0xA0, 0x93, 0x62, 0x32, 0x80, 0xFB, 0xA7, 0xB3, 0x48, 0xAF, 0xD1, 0xD8, 0x70, 0xBA, 0xE4, 0x96, 0x03, 0xE0, 0x21, 0xC8, 0x37, 0xA6, 0x9C, 0x8A, 0xF5, 0x20, 0x1B, 0xF5, 0xFB, 0x72, 0xEE, 0x02, 0xD0, 0x5B, 0x76, 0x59, 0xAF, 0x12, 0x8C, 0xAB, 0x0C, 0x5B, 0x0A, 0xD0, 0x45, 0x06, 0xE5, 0x4D, 0xAE, 0x6E, 0xEF, 0x2C, 0x55, 0x59, 0x4F, 0xB4, 0x51, 0xB8, 0xAB, 0x36, 0x45, 0x28, 0x9F, 0x54, 0xF6, 0xBC, 0xFA, 0xB7, 0xD9, 0x53, 0x22, 0x50, 0x8F, 0xB0, 0xE5, 0x06, 0xF3, 0xEC, 0x4E, 0x10, 0x2F, 0x01, 0xA2, 0x16, 0x02, 0xA4, 0xDC, 0xE2, 0xFB, 0xC5, 0x6E, 0x40, 0xBD, 0x38, 0xFB, 0xD0, 0x00, 0x73, 0xE0, 0x08, 0x20, 0xB3, 0xAF, 0x38, 0xAD, 0x26, 0x0C, 0x0A, 0x7F, 0xAD, 0x06, 0x8F, 0x5A, 0xE9, 0x96, 0xBF, 0xD4, 0xA6, 0xF9, 0x06, 0x4A, 0xC2, 0x4A, 0xB8, 0x17, 0x7C, 0x62, 0x2C, 0xFA, 0x91, 0x03, 0xE8, 0x6F, 0x2E, 0xC7, 0x82, 0xF3, 0xED, 0xEA, 0x4D, 0x18, 0x2C, 0x74, 0x64, 0x32, 0x2F, 0x83, 0x01, 0xB2, 0x9E, 0xB1, 0x86, 0xD5, 0x8C, 0xF2, 0xC9, 0xFD, 0x94, 0x36, 0x3E, 0xEA, 0x8F, 0x5C, 0xE1, 0x17, 0xC2, 0x72, 0x5B, 0x07, 0xB2, 0x81, 0x38, 0x0B, 0x5F, 0xE4, 0x5D, 0x51, 0x71, 0x1C, 0x08, 0x03, 0xFA, 0x00, 0x35, 0x40, 0x36, 0x10, 0x02, 0xB8, 0x02, 0x69, 0xEB, 0xAA, 0x4C, 0x5A, 0x4D, 0xF7, 0x4D, 0xFB, 0x6D, 0x5D, 0xC7, 0xDE, 0x7C, 0x18, 0x7B, 0x3A, 0x1C, 0xE5, 0x6E, 0x09, 0xDE, 0x98, 0x28, 0xC7, 0xE4, 0x76, 0x7D, 0xF7, 0x77, 0x07, 0x7D, 0x26, 0x1C, 0x30, 0xBA, 0xC8, 0x7B, 0x41, 0x32, 0x07, 0xFA, 0x3A, 0xBB, 0x0D, 0xBB, 0x61, 0xCE, 0xF3, 0x97, 0xF6, 0x9A, 0x6B, 0x1C, 0x88, 0x78, 0x7D, 0x62, 0xDC, 0xFB, 0xFE, 0x8A, 0x36, 0xEA, 0xF2, 0xA5, 0x9D, 0x6B, 0x4F, 0xC0, 0x2B, 0x07, 0x30, 0xA2, 0x6F, 0x1B, 0x4E, 0xD3, 0x16, 0xC0, 0xCC, 0xC2, 0x80, 0x52, 0xC0, 0x1A, 0x90, 0x02, 0xEC, 0xD0, 0xC1, 0x4B, 0xAB, 0xD9, 0xEA, 0x59, 0xCF, 0x77, 0xAC, 0xE1, 0x4E, 0x60, 0xB6, 0xF1, 0x34, 0x3A, 0x8B, 0xF4, 0xA7, 0xA8, 0x73, 0xE2, 0xFC, 0x47, 0xC0, 0x40, 0xE2, 0x53, 0x2B, 0xD5, 0x40, 0x2D, 0x7A, 0x6E, 0xE3, 0xE9, 0xA2, 0xA8, 0xD1, 0xDD, 0x57, 0xD2, 0x15, 0x5A, 0xDD, 0xE0, 0x3B, 0xCD, 0x4E, 0xD4, 0xF3, 0xD6, 0x03, 0xC4, 0x33, 0x74, 0x86, 0x91, 0x75, 0x16, 0x51, 0x1C, 0xCA, 0x2D, 0x30, 0x61, 0x08, 0x90, 0x47, 0x44, 0x72, 0x21, 0x40, 0xF2, 0x53, 0xF2, 0x15, 0x20, 0x0D, 0x18, 0x07, 0xBA, 0x80, 0x6C, 0xC0, 0x05, 0x50, 0x05, 0x8C, 0xE5, 0x6A, 0x41, 0xAB, 0xF9, 0x8E, 0x58, 0x5F, 0xB9, 0x3D, 0xBB, 0x66, 0xA8, 0x7B, 0xAC, 0xE7, 0x01, 0x89, 0xF1, 0x59, 0x81, 0x4E, 0x0B, 0xF2, 0xF8, 0x87, 0xC0, 0xC7, 0x6A, 0xF5, 0xC9, 0xF3, 0x8B, 0x8F, 0x7A, 0xD3, 0x59, 0xDC, 0x9A, 0x13, 0xFB, 0x4A, 0xB0, 0xE5, 0x25, 0x73, 0xAF, 0x98, 0xAB, 0x93, 0x4F, 0xED, 0x52, 0x2F, 0x42, 0xDE, 0x61, 0x55, 0x0C, 0x2B, 0x3F, 0x8D, 0x43, 0x5C, 0x00, 0xA3, 0x54, 0x80, 0x01, 0x5E, 0x40, 0x19, 0x30, 0xB2, 0xDF, 0xF7, 0x00, 0xA2, 0x80, 0x0F, 0x8D, 0x0E, 0xD8, 0x42, 0x03, 0x38, 0x4C, 0xCF, 0x0A, 0x20, 0x17, 0xCD, 0x84, 0x2C, 0xA7, 0xD5, 0xD8, 0xDB, 0xE1, 0x95, 0x03, 0xF8, 0x4D, 0x9F, 0x5A, 0x45, 0xF4, 0xDA, 0xCE, 0x40, 0xBD, 0x3D, 0xE5, 0x1C, 0x3D, 0xDD, 0x92, 0x2E, 0x48, 0x18, 0x6D, 0xAE, 0x24, 0x05, 0xFB, 0x8B, 0x12, 0xD7, 0xE7, 0x80, 0x6F, 0xC0, 0x70, 0xBB, 0x93, 0x01, 0x92, 0x3E, 0x36, 0xE6, 0x2A, 0x1C, 0x7A, 0x16, 0x57, 0x4E, 0x4E, 0x99, 0x46, 0xF1, 0x16, 0xB6, 0xEB, 0x3A, 0x81, 0xF6, 0xD7, 0xD9, 0xA2, 0x13, 0x7E, 0x0C, 0xC0, 0x04, 0x90, 0xF5, 0x48, 0x76, 0x00, 0xD9, 0x1F, 0x04, 0x50, 0xBD, 0xB3, 0x7D, 0x11, 0x02, 0x94, 0x02, 0xC9, 0x87, 0xF5, 0xD1, 0x96, 0x4F, 0xC0, 0x0B, 0x98, 0xC7, 0x68, 0xB9, 0x4E, 0xA0, 0xF9, 0x33, 0xDA, 0xCF, 0xBB, 0x20, 0x70, 0xCA, 0xB7, 0xE1, 0xF2, 0x9B, 0xB1, 0x69, 0xB1, 0x82, 0x0B, 0x4C, 0x9F, 0xAB, 0xA3, 0x99, 0x5D, 0x1E, 0x49, 0xFB, 0xD3, 0x82, 0xBC, 0xAC, 0x05, 0xA9, 0x21, 0xC0, 0x0F, 0x50, 0xF6, 0xF6, 0x9B, 0xD5, 0x75, 0x7A, 0xFF, 0xD5, 0x25, 0x39, 0x83, 0xC6, 0xEB, 0x6B, 0xB0, 0xA4, 0x2E, 0x2B, 0xBB, 0xF4, 0xBF, 0xC9, 0xEA, 0xB4, 0x6B, 0x3C, 0x3A, 0x9A, 0x35, 0x8B, 0x03, 0xC4, 0xC2, 0x06, 0xF0, 0x02, 0x42, 0x81, 0x62, 0x21, 0xF6, 0x22, 0x17, 0x5D, 0x8B, 0x5E, 0x18, 0x90, 0xB3, 0xE8, 0x3B, 0xEF, 0xD7, 0x9B, 0x46, 0x2B, 0x84, 0xF9, 0x25, 0xFF, 0x8C, 0xF6, 0x73, 0xA7, 0x15, 0xBE, 0xAD, 0x1A, 0x2E, 0x12, 0x69, 0x1B, 0x3B, 0xC6, 0x43, 0xC9, 0x62, 0xD2, 0xD0, 0x35, 0x3D, 0x19, 0xC8, 0xCB, 0x4F, 0xAF, 0x0B, 0x5B, 0x74, 0xF1, 0x18, 0x5A, 0x00, 0xCC, 0x24, 0x1B, 0x3A, 0xD1, 0x47, 0x9A, 0x8B, 0x73, 0x8F, 0x42, 0xAC, 0x0C, 0x72, 0x87, 0x2F, 0x12, 0x46, 0x63, 0xF2, 0x72, 0xEC, 0x28, 0x14, 0x83, 0x79, 0x8D, 0x25, 0x4F, 0x74, 0x6D, 0x34, 0xE0, 0x03, 0x48, 0x2F, 0xE2, 0x86, 0x09, 0x50, 0xC9, 0xDF, 0x03, 0x6A, 0x16, 0x0D, 0x44, 0x02, 0x3A, 0x80, 0x1C, 0x7E, 0xBA, 0x4B, 0xA5, 0x52, 0x90, 0xF2, 0x92, 0x33, 0x8F, 0x1C, 0x4F, 0xFF, 0xA2, 0x6C, 0xBD, 0xE1, 0x1F, 0xDD, 0x34, 0xC2, 0xDA, 0x33, 0x4C, 0x40, 0x40, 0xB5, 0xE3, 0xED, 0x73, 0x3C, 0x41, 0xA3, 0xB1, 0x6F, 0xFB, 0xB5, 0xBE, 0xD7, 0x73, 0x99, 0xD2, 0x04, 0x4C, 0x01, 0xEF, 0x5B, 0x05, 0xAB, 0x94, 0x0E, 0x71, 0xC6, 0x06, 0x36, 0xF1, 0xDB, 0x59, 0x96, 0x54, 0x80, 0x32, 0x04, 0xDC, 0xFC, 0x19, 0xCC, 0xCB, 0xBC, 0xC5, 0x27, 0x05, 0xE5, 0x87, 0x7E, 0x04, 0x27, 0xBC, 0xEF, 0x1D, 0x93, 0x3D, 0x69, 0x44, 0x00, 0x53, 0xA0, 0x6A, 0xEF, 0xA3, 0x8B, 0x12, 0x20, 0x0D, 0xF0, 0x02, 0x84, 0x95, 0x52, 0xFB, 0xE9, 0x0C, 0xD0, 0x43, 0xA3, 0xCD, 0xDF, 0xDA, 0xE2, 0x08, 0xD9, 0x95, 0x3F, 0x9A, 0x3E, 0xD5, 0xC8, 0xB8, 0x1A, 0x33, 0xAC, 0x18, 0x58, 0xD3, 0x2C, 0x4C, 0xD9, 0x2C, 0xEF, 0xCE, 0x56, 0xE3, 0x45, 0x9D, 0x71, 0x3C, 0x36, 0xC6, 0x5B, 0xB4, 0x2C, 0x9A, 0x03, 0xCE, 0x00, 0xA3, 0x37, 0x88, 0x71, 0xF3, 0x79, 0x12, 0xD3, 0x76, 0x11, 0xDD, 0x05, 0xA4, 0x76, 0xE0, 0x28, 0x3E, 0x55, 0xEE, 0x82, 0xB5, 0x38, 0x06, 0xC8, 0xFE, 0x2C, 0x82, 0x9E, 0xFB, 0xF5, 0x97, 0x31, 0xBB, 0x85, 0x73, 0x6F, 0x43, 0x28, 0xDA, 0x40, 0xC6, 0x1D, 0x3E, 0x48, 0x01, 0xE6, 0x2C, 0x14, 0xE8, 0x59, 0xF8, 0x82, 0xAF, 0xAC, 0xCF, 0xE3, 0xB9, 0x4B, 0xED, 0xFC, 0xA0, 0xCF, 0xA3, 0x3C, 0xBF, 0xBA, 0xE8, 0xAB, 0x27, 0xD6, 0x5B, 0x25, 0xDE, 0x90, 0x3E, 0x88, 0xBA, 0xEB, 0x3F, 0x41, 0x44, 0x0C, 0xEE, 0x36, 0x70, 0x09, 0x84, 0x2F, 0x3E, 0x6D, 0x8E, 0xF3, 0x00, 0xCD, 0xCE, 0x4A, 0xD7, 0x30, 0x44, 0x03, 0xE8, 0x3D, 0xED, 0xF4, 0x9B, 0x16, 0x9A, 0x3C, 0x20, 0x3C, 0x29, 0xD7, 0xBD, 0x90, 0x5A, 0x70, 0x33, 0x8D, 0xB7, 0x97, 0xF6, 0x79, 0x0A, 0xDA, 0xC2, 0xEF, 0x23, 0x57, 0xB1, 0xD4, 0x2E, 0x01, 0x5F, 0x0C, 0x45, 0xBC, 0x63, 0xD1, 0x0B, 0x05, 0x4E, 0x2E, 0x1C, 0x90, 0x02, 0x72, 0x68, 0x35, 0xD9, 0x8E, 0xF0, 0xBA, 0x92, 0x91, 0xF6, 0x6F, 0x12, 0x79, 0x31, 0x68, 0x12, 0x2E, 0x98, 0x98, 0xE3, 0x5B, 0xFE, 0x25, 0xBF, 0x53, 0x42, 0x8F, 0xBF, 0xAD, 0x67, 0xDB, 0x3E, 0x37, 0xD0, 0xD4, 0x3B, 0x60, 0x90, 0x0E, 0xD4, 0x59, 0x50, 0xED, 0x56, 0x01, 0xE7, 0x65, 0xD3, 0x2E, 0x95, 0x51, 0x86, 0x70, 0xE9, 0xC2, 0xDE, 0xF3, 0x97, 0xC5, 0x66, 0xC8, 0x72, 0x6B, 0x95, 0x27, 0x0D, 0x70, 0xE4, 0xEE, 0x20, 0x25, 0xE7, 0x4D, 0x9B, 0xF5, 0xA7, 0x4F, 0x52, 0xDB, 0xDD, 0x84, 0x9D, 0x7D, 0x57, 0x54, 0x01, 0xC6, 0x8A, 0x7D, 0xD1, 0x06, 0xD4, 0x00, 0x29, 0x80, 0x29, 0x20, 0x09, 0xB0, 0xF5, 0xA3, 0x04, 0x8D, 0xA6, 0xF0, 0xB1, 0xAC, 0xBB, 0xB6, 0x23, 0x7E, 0x61, 0x96, 0x96, 0x5A, 0x21, 0xC5, 0x46, 0x28, 0x7E, 0xE2, 0x07, 0x57, 0x85, 0xEE, 0x74, 0x9E, 0xAB, 0xAA, 0x3D, 0xEB, 0x63, 0xB5, 0x62, 0x82, 0x24, 0x2F, 0xD7, 0x8B, 0xCA, 0x85, 0x03, 0x4D, 0x19, 0x6B, 0x03, 0x46, 0xAE, 0xA6, 0xD0, 0xF9, 0x64, 0x6A, 0x8F, 0xDC, 0x79, 0xEA, 0xE7, 0xD3, 0xEF, 0x9A, 0x87, 0x57, 0x71, 0xE0, 0xB0, 0x0B, 0xE7, 0xDE, 0x0F, 0x69, 0x3C, 0x26, 0xAF, 0x30, 0xDE, 0x9E, 0x9F, 0xA6, 0x35, 0xB9, 0x56, 0x13, 0x07, 0xAA, 0xD6, 0x32, 0xB2, 0x50, 0xE0, 0x18, 0x7B, 0xF3, 0x02, 0x65, 0xC0, 0xEC, 0xCF, 0xD2, 0x68, 0xB5, 0xE7, 0xEA, 0xB9, 0x2D, 0x91, 0xA0, 0x18, 0x79, 0x54, 0x70, 0xCC, 0xAC, 0x59, 0xF1, 0x79, 0xFE, 0x11, 0x01, 0x67, 0xD9, 0x96, 0x1A, 0x9F, 0xEF, 0xAA, 0x76, 0x75, 0x1A, 0xCC, 0x67, 0x9D, 0xD7, 0x85, 0x2F, 0x6C, 0x80, 0x4B, 0x5A, 0xF8, 0x6A, 0xD4, 0x1B, 0xBA, 0x97, 0x02, 0x6E, 0xA3, 0xCD, 0x99, 0x75, 0xAF, 0xD7, 0x69, 0x40, 0x35, 0x30, 0xF3, 0x3A, 0x0E, 0x19, 0x8D, 0xA2, 0x08, 0xB7, 0xEC, 0x51, 0x02, 0x59, 0x2E, 0x70, 0xF1, 0x17, 0x50, 0x76, 0x9F, 0x36, 0xDC, 0x81, 0x5A, 0x74, 0x01, 0xB3, 0x6E, 0x02, 0xD1, 0xFF, 0xEA, 0x60, 0x13, 0xC0, 0x1C, 0x1A, 0xCD, 0x69, 0xB4, 0x4B, 0xB7, 0xC9, 0x7C, 0x30, 0x69, 0x19, 0xE3, 0x69, 0x45, 0x30, 0x6B, 0x66, 0xB5, 0x80, 0xB1, 0x15, 0x70, 0x7E, 0xE6, 0xB7, 0xA8, 0x3D, 0x98, 0x6C, 0x75, 0xBB, 0x59, 0xF3, 0x2C, 0x1A, 0x98, 0x7C, 0xBB, 0x93, 0xC9, 0xAE, 0xDE, 0x62, 0x14, 0x77, 0x64, 0xE5, 0xEF, 0x27, 0x96, 0xA6, 0xCF, 0x49, 0x44, 0x12, 0x50, 0x03, 0x3C, 0x61, 0x8A, 0x33, 0x40, 0x18, 0xD0, 0x7B, 0xB8, 0x3A, 0x0D, 0xD8, 0x01, 0xC2, 0x80, 0x0C, 0xA0, 0x69, 0x98, 0x02, 0x5C, 0x80, 0x50, 0x20, 0x05, 0x28, 0x07, 0x98, 0x04, 0x27, 0x06, 0xA8, 0x02, 0xF1, 0x18, 0x2D, 0xBE, 0x46, 0x83, 0xCB, 0x6D, 0xD3, 0x89, 0xA7, 0x1B, 0x9B, 0x46, 0x0F, 0x32, 0x26, 0xA2, 0x57, 0xE1, 0xB4, 0xAF, 0x2A, 0x33, 0x07, 0x78, 0x2D, 0x32, 0x8E, 0x9B, 0xFA, 0xB4, 0x89, 0x6D, 0xBB, 0x5D, 0xAF, 0x2A, 0x00, 0x25, 0x1A, 0x1F, 0xE9, 0x96, 0x5D, 0xB0, 0x84, 0x97, 0x00, 0xEA, 0xE0, 0x37, 0x73, 0xF6, 0xEE, 0xA0, 0xEF, 0x39, 0x80, 0x06, 0x30, 0x0C, 0xFA, 0x36, 0x30, 0x07, 0x5E, 0x47, 0x49, 0xC0, 0x05, 0xC8, 0x02, 0x5A, 0xD7, 0x49, 0x7B, 0x00, 0x77, 0xA0, 0x04, 0xE8, 0x00, 0xC6, 0xD6, 0x49, 0x9B, 0x80, 0x09, 0x10, 0x0E, 0x64, 0x01, 0xD3, 0xB4, 0x19, 0x8F, 0xB5, 0x2C, 0xF9, 0x65, 0x77, 0x91, 0xBD, 0xBE, 0x4D, 0xC0, 0xA5, 0x52, 0xB9, 0x6D, 0x9B, 0x1C, 0xED, 0x26, 0x1D, 0xA7, 0x5B, 0xF9, 0x5E, 0x3E, 0xE3, 0x53, 0x8C, 0xE1, 0x40, 0x12, 0xB1, 0x50, 0xA0, 0x3F, 0xC1, 0xE5, 0x61, 0x26, 0xD1, 0x53, 0xF6, 0x64, 0x6F, 0x99, 0x57, 0x3E, 0x2B, 0x5B, 0x34, 0x50, 0x02, 0x34, 0xCB, 0xDD, 0x17, 0x14, 0xC7, 0x72, 0x2E, 0xFD, 0x57, 0x04, 0x18, 0xC6, 0xC6, 0xB0, 0x1B, 0xA0, 0x73, 0x73, 0x39, 0x02, 0xA8, 0x4F, 0xF6, 0x86, 0x28, 0xA0, 0x0B, 0x73, 0xC0, 0x07, 0xC8, 0x45, 0x0B, 0xEB, 0x8F, 0x69, 0xB4, 0xC2, 0x9C, 0x1B, 0xFE, 0x81, 0xF9, 0x13, 0x92, 0x1F, 0xB5, 0x95, 0x32, 0xDD, 0xDD, 0xD3, 0x36, 0xA6, 0x57, 0x03, 0xAD, 0xDF, 0x6C, 0x9E, 0x39, 0x3E, 0xDB, 0xE7, 0xA7, 0x67, 0xC1, 0x37, 0xFB, 0xD1, 0x0F, 0x60, 0xB2, 0x18, 0x20, 0x18, 0x45, 0xEF, 0x37, 0x96, 0x22, 0xF1, 0x68, 0x97, 0x08, 0x5B, 0x6E, 0x3B, 0xE0, 0x03, 0x68, 0xBE, 0x0A, 0x7E, 0x30, 0x37, 0x7E, 0xC6, 0x45, 0x50, 0x61, 0x3C, 0xF6, 0xC7, 0x00, 0xFA, 0x51, 0x3C, 0xD0, 0x62, 0xA4, 0x1C, 0xA0, 0x28, 0xC7, 0x39, 0x80, 0x37, 0x50, 0x06, 0xB4, 0x2F, 0x72, 0xD1, 0xC0, 0xE8, 0x2E, 0x0E, 0x07, 0x88, 0xA4, 0xD5, 0x1A, 0xD2, 0x06, 0x89, 0xA3, 0x47, 0x28, 0x5A, 0x17, 0xD4, 0xE6, 0xCD, 0x0F, 0x5B, 0x7C, 0xEF, 0x7D, 0x4A, 0xCF, 0x20, 0xC2, 0x8D, 0xC2, 0x59, 0xE3, 0x50, 0x8B, 0xAB, 0x35, 0xB4, 0x3D, 0x66, 0x0A, 0xA6, 0x79, 0x07, 0xD0, 0xB9, 0x50, 0x60, 0x36, 0xD6, 0x24, 0x8B, 0x9E, 0xF3, 0x46, 0x32, 0xFB, 0x19, 0x4E, 0xAC, 0xBC, 0x39, 0x02, 0xA8, 0xDD, 0x7A, 0x73, 0x11, 0x00, 0x1F, 0x56, 0xBD, 0x2D, 0xEE, 0xF6, 0x5E, 0xE4, 0xFB, 0xC9, 0xEB, 0xC9, 0x5C, 0x3E, 0x02, 0x60, 0xEE, 0xCA, 0x73, 0x47, 0x3B, 0x02, 0x84, 0x02, 0x35, 0x40, 0xE7, 0x07, 0xB2, 0x98, 0xAB, 0x01, 0xF7, 0xBB, 0xA6, 0xBD, 0xCE, 0x34, 0xEC, 0x00, 0x9B, 0x44, 0x64, 0x88, 0x90, 0x79, 0xAE, 0x90, 0xA4, 0xED, 0x72, 0xE9, 0x3B, 0x87, 0xF2, 0xAD, 0x36, 0x3E, 0x0E, 0x58, 0xB2, 0xB3, 0xDD, 0x15, 0x5C, 0x8A, 0xA7, 0x58, 0x40, 0x12, 0x38, 0x1F, 0x88, 0x03, 0xF4, 0xF1, 0xD3, 0x49, 0xE3, 0x74, 0x57, 0xCC, 0xA7, 0xAD, 0xC0, 0x00, 0xFC, 0x14, 0x01, 0xF4, 0xDE, 0xCA, 0xE7, 0x07, 0x2E, 0x4A, 0x9B, 0x0D, 0x1A, 0xBD, 0xD5, 0xDB, 0xEB, 0xD9, 0x4D, 0x87, 0xE9, 0x72, 0x77, 0xC6, 0xCC, 0xFD, 0xD9, 0x6F, 0x80, 0x03, 0x11, 0x40, 0x1D, 0xA0, 0x03, 0x98, 0xD9, 0x9A, 0xEC, 0x06, 0xE2, 0x00, 0xA9, 0x40, 0xD3, 0xCD, 0x61, 0x87, 0x36, 0x83, 0x41, 0x14, 0xB5, 0x52, 0x63, 0xB1, 0x52, 0xA7, 0x72, 0x49, 0xC9, 0x68, 0x60, 0xF3, 0x8C, 0x36, 0x4A, 0xD1, 0xD1, 0x1D, 0x09, 0xA3, 0x5D, 0xC2, 0x69, 0xF8, 0xD2, 0xD8, 0x2E, 0x1D, 0xE8, 0x5C, 0xB0, 0x2F, 0x9E, 0x00, 0x16, 0x97, 0xF8, 0x90, 0x3D, 0x6D, 0xDC, 0xDA, 0x5E, 0x2F, 0x2A, 0x1A, 0x08, 0x62, 0x0F, 0x35, 0xA0, 0x06, 0x18, 0xD9, 0x2C, 0x50, 0x5E, 0xDC, 0xE9, 0xD8, 0x60, 0x93, 0x95, 0x78, 0x7B, 0x41, 0x6D, 0x99, 0x72, 0xE4, 0xD3, 0x7E, 0xC6, 0x04, 0xA8, 0x86, 0x5D, 0x25, 0x01, 0x5F, 0x44, 0x00, 0x69, 0x40, 0x39, 0x30, 0x1B, 0xBD, 0x12, 0x03, 0x74, 0xE1, 0x46, 0xA3, 0xC9, 0x46, 0x84, 0x15, 0x7B, 0x76, 0x31, 0xD4, 0xCE, 0x3C, 0xBA, 0xC2, 0x39, 0xD2, 0x1C, 0x69, 0xEC, 0xD2, 0x88, 0x07, 0xBB, 0x5D, 0x6E, 0xC8, 0xFC, 0x16, 0x33, 0xEA, 0x7C, 0x22, 0xC2, 0xDF, 0x3A, 0xE3, 0xB3, 0xD0, 0xBB, 0x15, 0xF4, 0xE9, 0xAB, 0x6F, 0xDC, 0x79, 0x54, 0xAC, 0x26, 0x77, 0xF3, 0x2E, 0x20, 0x1A, 0x90, 0xB9, 0x85, 0x69, 0xA9, 0x12, 0x66, 0x97, 0x4E, 0x77, 0x3C, 0x22, 0x8F, 0xF4, 0xF6, 0x32, 0xA9, 0xBE, 0xF7, 0xE4, 0xDA, 0xF4, 0x6C, 0x24, 0x4B, 0xE7, 0x81, 0x18, 0x60, 0x74, 0xE1, 0x0B, 0x03, 0x3A, 0x17, 0xBE, 0x4B, 0x62, 0x00, 0xCF, 0xED, 0xF3, 0xF1, 0x3F, 0x6E, 0xB0, 0x79, 0xF2, 0xDF, 0xFC, 0x8C, 0xA7, 0xB0, 0x1A, 0xFB, 0x66, 0x8A, 0x20, 0xF0, 0x93, 0x8D, 0xEB, 0x90, 0xC4, 0xB5, 0x7D, 0xF6, 0x95, 0x18, 0x89, 0x41, 0x79, 0x05, 0x35, 0x53, 0x17, 0x02, 0x04, 0x1F, 0x06, 0xD0, 0x57, 0x74, 0x85, 0x85, 0x2C, 0xAC, 0x88, 0x57, 0x79, 0x6E, 0x96, 0x21, 0x40, 0xC6, 0xC2, 0x81, 0x8E, 0xB7, 0x3B, 0x6A, 0xB2, 0x0F, 0xF6, 0xBA, 0x83, 0x92, 0x47, 0x96, 0xDD, 0x30, 0x1B, 0xB6, 0x0B, 0x79, 0x9A, 0x90, 0x55, 0xEF, 0xA2, 0xC4, 0xE4, 0x8E, 0x06, 0xFC, 0x00, 0xD1, 0x40, 0x0E, 0xD0, 0x07, 0x98, 0xA6, 0x8C, 0x0A, 0xA0, 0x0E, 0xFC, 0x0D, 0x35, 0xA3, 0xD1, 0xB0, 0xDF, 0x9A, 0x5D, 0xAD, 0x40, 0xFB, 0xE0, 0xCC, 0x61, 0x5A, 0xEB, 0x30, 0xDF, 0x16, 0xC7, 0xDD, 0x8C, 0xA6, 0xDC, 0xAD, 0x31, 0xE4, 0xBE, 0xB1, 0x9B, 0x7D, 0x92, 0x3A, 0xEC, 0x93, 0x1A, 0xFF, 0xE9, 0xF1, 0xA3, 0xC9, 0xE8, 0xF2, 0xD5, 0x14, 0x0E, 0xE9, 0x27, 0xC8, 0x2E, 0x77, 0x40, 0x0B, 0x90, 0x01, 0x7C, 0x51, 0xF9, 0xE6, 0x96, 0xDA, 0xD3, 0xAC, 0x4C, 0x38, 0x2A, 0x0C, 0x46, 0x13, 0xCE, 0xD6, 0x5A, 0xC3, 0x9C, 0xCD, 0x7A, 0xB1, 0xFB, 0x10, 0x37, 0x8C, 0xAD, 0x1F, 0xC0, 0x06, 0xC8, 0xF3, 0xE9, 0x27, 0xB5, 0xD0, 0x06, 0xA2, 0x69, 0xB4, 0x5D, 0xDE, 0xCB, 0x61, 0x49, 0x8D, 0x1D, 0x69, 0xBE, 0x99, 0xFC, 0x05, 0x0F, 0xF9, 0x6C, 0xFA, 0x95, 0x0A, 0x82, 0x98, 0x98, 0x9F, 0xE3, 0xDF, 0x0C, 0xF9, 0x6F, 0x5F, 0x68, 0xC9, 0xCF, 0x18, 0x4B, 0xC0, 0x15, 0xB0, 0x06, 0x3C, 0x00, 0x5E, 0x45, 0x1F, 0x39, 0xB1, 0xD9, 0xF9, 0x59, 0x6C, 0x51, 0xA8, 0x77, 0x7D, 0x7B, 0x2E, 0xA2, 0x00, 0xE7, 0xCF, 0xEC, 0x4D, 0xA5, 0xDC, 0xEF, 0x6B, 0xBC, 0x04, 0xC0, 0x07, 0xC7, 0xA6, 0x9F, 0x38, 0xFD, 0xF3, 0x34, 0x16, 0xC0, 0x30, 0xCF, 0xC5, 0xEF, 0x5E, 0x48, 0x6C, 0x40, 0x35, 0x8B, 0x32, 0x20, 0x89, 0x66, 0x26, 0x1B, 0xAD, 0x76, 0x27, 0x10, 0xF9, 0xE4, 0x95, 0xAD, 0x16, 0x47, 0x56, 0xE4, 0x38, 0xF1, 0xCF, 0x6A, 0x8E, 0x2C, 0x33, 0xC9, 0x3B, 0xFC, 0x19, 0xDF, 0x62, 0x63, 0xC6, 0xD8, 0x05, 0xC8, 0x06, 0x22, 0xBF, 0x39, 0x30, 0x0B, 0x05, 0xA2, 0xBF, 0xF2, 0xDE, 0x34, 0xDE, 0x8E, 0x3C, 0x77, 0x4A, 0xE5, 0x02, 0x56, 0x40, 0x2E, 0xD8, 0x98, 0x7C, 0x86, 0x4D, 0x7A, 0x59, 0x71, 0xBD, 0xD7, 0xEB, 0xB5, 0x4C, 0xB2, 0xA7, 0xA2, 0xEF, 0x96, 0xE0, 0xDC, 0x04, 0x76, 0x85, 0x3F, 0x00, 0xDB, 0x84, 0x9E, 0x03, 0xE8, 0xC2, 0x17, 0x69, 0xC0, 0x6C, 0x7E, 0xC2, 0x71, 0x40, 0x8B, 0x56, 0xCB, 0xAB, 0x7F, 0x6A, 0x59, 0x5C, 0x7B, 0x41, 0x3D, 0x7A, 0x53, 0xCC, 0x27, 0x1E, 0x4C, 0xB7, 0xEC, 0x4B, 0x35, 0x78, 0xAE, 0x93, 0x9A, 0xBE, 0x93, 0x10, 0xA8, 0x59, 0x18, 0x10, 0xB3, 0xA8, 0x4F, 0x7B, 0x3C, 0xA5, 0x47, 0xE4, 0xCA, 0xA5, 0x62, 0x1E, 0x33, 0x86, 0x23, 0x6E, 0xA6, 0x0E, 0xE4, 0x95, 0x11, 0xEE, 0xCF, 0xF8, 0x93, 0x4D, 0x0C, 0x37, 0x76, 0xA6, 0x67, 0xA8, 0x65, 0x77, 0xD5, 0x66, 0xBA, 0xA3, 0xDD, 0xED, 0x2C, 0x9D, 0x2D, 0x2B, 0x0D, 0x88, 0x00, 0xCA, 0x80, 0x0E, 0x60, 0xA8, 0xFA, 0x71, 0x00, 0xCB, 0x7B, 0xFD, 0xCB, 0x43, 0xA3, 0x15, 0x8D, 0xB6, 0xDD, 0xEA, 0x68, 0x34, 0xC6, 0xB5, 0x7A, 0x6B, 0x9B, 0xED, 0x87, 0x92, 0xFE, 0xCD, 0xAF, 0xF0, 0xBC, 0xD4, 0xFB, 0xBE, 0xA2, 0xA4, 0x74, 0x77, 0xA8, 0x01, 0xDE, 0x40, 0xD8, 0x8D, 0xAA, 0x77, 0x0A, 0xC7, 0xEE, 0x01, 0x58, 0x33, 0x9E, 0x89, 0xF9, 0xE7, 0x2A, 0x90, 0xC7, 0x2F, 0xAD, 0x07, 0x88, 0x00, 0x72, 0x80, 0x59, 0x67, 0x61, 0xFD, 0x90, 0x7F, 0xDE, 0xFF, 0x75, 0xE2, 0x32, 0x9F, 0xC1, 0xF4, 0x3E, 0xE9, 0xDD, 0xBD, 0xE0, 0xE0, 0xBA, 0xB9, 0x8B, 0x19, 0xCF, 0x62, 0x80, 0xD1, 0xFB, 0x06, 0x66, 0x07, 0x70, 0x05, 0xB2, 0x69, 0x34, 0x5C, 0xC4, 0xCD, 0x07, 0xF7, 0x1A, 0xB9, 0x33, 0x61, 0xC2, 0x1B, 0x41, 0xDA, 0x84, 0xE7, 0xFB, 0x4C, 0xAE, 0xB7, 0xCC, 0xAF, 0xB2, 0xD9, 0xA6, 0xD1, 0xE6, 0x3F, 0xF2, 0xFB, 0x4A, 0x16, 0x09, 0x34, 0xF7, 0xD6, 0x6B, 0x53, 0x8D, 0xA7, 0x78, 0x7B, 0x27, 0x79, 0xFF, 0x89, 0x37, 0x5D, 0x2E, 0xC0, 0xF9, 0x13, 0x92, 0x4B, 0xD8, 0x67, 0xE8, 0x9C, 0x4C, 0xC0, 0x17, 0xB3, 0xF3, 0xF2, 0x29, 0xF4, 0x29, 0x20, 0x37, 0xF0, 0x72, 0x16, 0x1A, 0x40, 0x7C, 0xD4, 0x9E, 0x5C, 0x80, 0x1C, 0xA0, 0x0E, 0x90, 0x06, 0x44, 0x2E, 0x14, 0xC8, 0xF5, 0x3B, 0x19, 0x47, 0xDA, 0x1B, 0x60, 0x5F, 0x5C, 0x59, 0x91, 0x6A, 0x8E, 0xB0, 0x8F, 0xEA, 0xFA, 0x63, 0x06, 0x63, 0xA3, 0x85, 0x61, 0xBC, 0xDB, 0x39, 0xE4, 0xB7, 0xD1, 0x62, 0x51, 0x01, 0xB4, 0x01, 0x73, 0x3E, 0x61, 0xF6, 0xFC, 0x84, 0xD9, 0x8B, 0xF9, 0x4A, 0x3C, 0xE5, 0xE4, 0x5E, 0xFC, 0xEC, 0xCE, 0x38, 0x36, 0x07, 0x74, 0x00, 0xEF, 0xBD, 0x6D, 0x17, 0x90, 0x14, 0xF6, 0x2A, 0x40, 0x0D, 0xF0, 0x03, 0x44, 0x00, 0x69, 0x40, 0x3D, 0x5D, 0xF1, 0x00, 0xB5, 0xC5, 0x7F, 0x96, 0x12, 0x0C, 0x50, 0x0E, 0x74, 0x7E, 0xF2, 0x96, 0xFD, 0x20, 0x03, 0x37, 0x34, 0xAF, 0xE0, 0xA7, 0xE8, 0xE0, 0x9C, 0xA9, 0x78, 0x55, 0xD5, 0x30, 0xF5, 0xB7, 0x1C, 0x23, 0xCC, 0x50, 0xF4, 0x79, 0x0B, 0x54, 0xDB, 0xD5, 0x95, 0x00, 0x97, 0x90, 0x8D, 0xA3, 0x24, 0xE0, 0x07, 0x08, 0x03, 0x9A, 0x0D, 0x6B, 0x8A, 0x35, 0x77, 0x74, 0x20, 0xB1, 0xB5, 0x3F, 0xAC, 0xE5, 0xC3, 0x4B, 0xE1, 0xED, 0xF3, 0xC9, 0xBE, 0xC1, 0xF6, 0x93, 0x7D, 0xF6, 0x70, 0x5F, 0xC0, 0xEC, 0x2A, 0xAF, 0x02, 0x78, 0x00, 0xA5, 0x40, 0xFB, 0xA6, 0xA6, 0x09, 0xE0, 0x0A, 0xD4, 0x01, 0x9A, 0x68, 0x60, 0x66, 0x13, 0xD5, 0x1A, 0x70, 0x05, 0x62, 0x80, 0x36, 0x1A, 0x4D, 0xFE, 0x21, 0x52, 0x3B, 0x1B, 0x20, 0xCA, 0x5F, 0x26, 0x69, 0xB7, 0x6F, 0xBF, 0x7D, 0xC1, 0xC8, 0x4E, 0xC5, 0xE8, 0xF5, 0xFC, 0x8D, 0xB4, 0x4E, 0x5A, 0xE9, 0xF6, 0xDD, 0x8A, 0xDD, 0xA9, 0x09, 0x51, 0xC0, 0x7C, 0x5A, 0x49, 0x9D, 0x85, 0x2B, 0x30, 0xFE, 0xCA, 0x53, 0xB0, 0xF7, 0xA0, 0x30, 0x7E, 0xA7, 0xCF, 0xDD, 0xC9, 0xD7, 0x35, 0x31, 0x03, 0x74, 0x02, 0x26, 0xEF, 0xBA, 0xC5, 0x4F, 0xFA, 0x2C, 0x43, 0x2C, 0xFE, 0x3F, 0x3B, 0x7E, 0x92, 0x7D, 0x40, 0xF7, 0xAE, 0x7E, 0x02, 0xF0, 0xC5, 0xC8, 0x6E, 0x0B, 0x8B, 0x4C, 0xA0, 0x6C, 0x91, 0x8B, 0x00, 0xB8, 0x3B, 0x9C, 0x04, 0x22, 0x68, 0x34, 0xBD, 0x5C, 0x6A, 0x96, 0xDC, 0x08, 0xD8, 0xAD, 0xC4, 0x36, 0x79, 0x67, 0x55, 0x8A, 0x3A, 0x70, 0xEC, 0xF2, 0x64, 0xE6, 0xE8, 0xE5, 0xE7, 0x90, 0xFC, 0x68, 0xE9, 0xE4, 0x3D, 0x2F, 0xAB, 0x16, 0xB4, 0xDD, 0x01, 0x78, 0xC9, 0xD7, 0x1D, 0x9A, 0xDE, 0x6F, 0xDB, 0x71, 0xCD, 0x27, 0xA5, 0xE7, 0x11, 0x6F, 0x0C, 0x20, 0x0C, 0x28, 0x01, 0x66, 0xB3, 0x61, 0xB9, 0x7C, 0x71, 0xBF, 0xD4, 0x9D, 0x43, 0xF4, 0x51, 0xB2, 0xBB, 0x9B, 0x71, 0x30, 0xEE, 0xB8, 0x13, 0x07, 0x32, 0xEF, 0xB3, 0x86, 0x04, 0xA0, 0x09, 0xD8, 0x00, 0xD1, 0x40, 0x1B, 0x30, 0xB9, 0x47, 0x8E, 0x43, 0xA3, 0xD9, 0x7F, 0xAF, 0x69, 0x90, 0x33, 0xC8, 0x9D, 0xDD, 0x0E, 0x37, 0x82, 0x6F, 0x77, 0x1E, 0xFB, 0x6D, 0x04, 0x59, 0x5F, 0x41, 0x52, 0xB9, 0x13, 0xAE, 0xF2, 0xBF, 0x32, 0xAD, 0x4E, 0xDF, 0x4D, 0x15, 0xCF, 0xE5, 0x6D, 0x93, 0x3F, 0x6D, 0x0E, 0xD6, 0xB9, 0x85, 0xB1, 0xDB, 0xF5, 0x4E, 0x4F, 0x7A, 0x5F, 0x73, 0x21, 0x30, 0x05, 0x3D, 0xAC, 0x47, 0x80, 0x6A, 0x98, 0xC2, 0x04, 0x88, 0x00, 0xCA, 0x80, 0x89, 0xB5, 0x8F, 0x03, 0xBA, 0x08, 0x03, 0x2A, 0x3E, 0xD3, 0x73, 0x80, 0xA9, 0x9D, 0x9E, 0x06, 0x58, 0x00, 0xEE, 0x40, 0x26, 0x8D, 0xE6, 0x34, 0xD3, 0xAB, 0x48, 0x37, 0xAE, 0x7A, 0x7B, 0x3F, 0x62, 0xBD, 0xD2, 0xAC, 0x1D, 0x1F, 0x38, 0x3A, 0xCE, 0xBD, 0xA4, 0x3D, 0x4D, 0x77, 0xD9, 0x08, 0xE4, 0x71, 0x8D, 0xEE, 0xBA, 0x13, 0xB6, 0xB5, 0xE3, 0x09, 0x74, 0x00, 0xBE, 0x55, 0xE6, 0xBE, 0x7F, 0x52, 0x1A, 0xBF, 0xCA, 0x1A, 0x64, 0x38, 0xBD, 0x60, 0xC1, 0x3A, 0x4F, 0xD5, 0xE2, 0x53, 0xA3, 0x22, 0x1B, 0x25, 0xEF, 0x27, 0xBB, 0x57, 0xF8, 0xEF, 0xE0, 0xBB, 0x3D, 0xC7, 0x7D, 0x56, 0x34, 0x03, 0xB4, 0x6E, 0xA4, 0xDD, 0x09, 0x73, 0x35, 0x40, 0xFA, 0xA7, 0xDF, 0xA6, 0x00, 0xEE, 0x40, 0xD6, 0xB3, 0xE5, 0xD3, 0x66, 0xF7, 0x7C, 0xAC, 0xA6, 0xE9, 0x08, 0xFE, 0x81, 0xBA, 0x5D, 0x96, 0xE4, 0x9F, 0x3B, 0x8E, 0xB8, 0x08, 0x23, 0xDC, 0xCE, 0xA1, 0x8C, 0x35, 0xDA, 0x0F, 0xAC, 0x29, 0xA4, 0x23, 0x99, 0x67, 0x71, 0xFE, 0xAB, 0x06, 0x76, 0x23, 0x58, 0xF2, 0xBC, 0xF2, 0xA2, 0xFA, 0x6C, 0x7B, 0xCE, 0x06, 0x3A, 0xBA, 0x0E, 0x8A, 0x3D, 0x7F, 0x24, 0x6B, 0xC9, 0xF6, 0xEC, 0xCF, 0x7B, 0x01, 0x6C, 0xFE, 0xD7, 0x2D, 0x94, 0xA5, 0x59, 0x9F, 0x16, 0x39, 0x7E, 0x00, 0x55, 0x40, 0x72, 0xD1, 0x77, 0x4A, 0xBE, 0x2E, 0x32, 0x81, 0x30, 0x40, 0xE5, 0x96, 0x84, 0xB3, 0x04, 0x82, 0xAF, 0xFC, 0x19, 0x2D, 0xEF, 0xBC, 0x51, 0xDD, 0x0A, 0xE3, 0x52, 0x54, 0xFD, 0x7B, 0xFE, 0x9C, 0xD1, 0xA3, 0xB5, 0xED, 0x19, 0x1D, 0x11, 0xEC, 0x4A, 0xDE, 0x00, 0xAE, 0x28, 0x41, 0x5C, 0x2A, 0x1C, 0xFA, 0x64, 0xEF, 0x2F, 0xD6, 0x21, 0xCB, 0xBC, 0x01, 0x7B, 0x44, 0xFA, 0x76, 0x22, 0xF2, 0xE2, 0x13, 0x8F, 0xEC, 0xEF, 0x93, 0xC0, 0x31, 0x30, 0x3D, 0x5B, 0x54, 0x52, 0x69, 0x61, 0x58, 0x9D, 0x8D, 0x21, 0xC6, 0x28, 0xEA, 0x9C, 0xDB, 0x75, 0x22, 0x9F, 0x1A, 0x7A, 0x15, 0xE0, 0xD4, 0x42, 0x17, 0x09, 0x58, 0xDD, 0xCB, 0xAB, 0x2B, 0x40, 0xC7, 0xD6, 0x2C, 0xC2, 0xBE, 0xC7, 0xF4, 0x1D, 0x85, 0x7F, 0x46, 0xAB, 0xEF, 0xEC, 0xFC, 0x80, 0x3D, 0xF9, 0x64, 0xB3, 0xF6, 0x73, 0x93, 0xA0, 0x21, 0xAE, 0x79, 0xDD, 0x9E, 0x84, 0x41, 0x5F, 0xAE, 0xF8, 0xBA, 0xEB, 0xB1, 0xEE, 0xF2, 0xBA, 0x47, 0xEA, 0x5A, 0x43, 0xD6, 0x16, 0xA8, 0xD7, 0x3A, 0xE4, 0x8B, 0xBB, 0x7B, 0x6F, 0x03, 0x5D, 0xDB, 0xD3, 0x04, 0x2F, 0xD5, 0xBD, 0xD9, 0x7D, 0xFD, 0xB4, 0x34, 0xAB, 0xDD, 0x5E, 0xE3, 0x2D, 0x57, 0xAE, 0x47, 0x5B, 0xAC, 0xD7, 0x04, 0xC5, 0x2F, 0xED, 0x80, 0x0D, 0x20, 0x84, 0x2D, 0x02, 0xF0, 0xE1, 0x3C, 0x06, 0x62, 0x00, 0x0F, 0x40, 0x3E, 0xAD, 0xD7, 0xCC, 0x81, 0xC7, 0xF5, 0xA0, 0x8F, 0xCD, 0xFA, 0xE7, 0xAC, 0x75, 0xF9, 0xEE, 0x06, 0xEC, 0xCC, 0x50, 0x2B, 0xAD, 0x91, 0x88, 0x6D, 0xF3, 0x8C, 0x78, 0xE0, 0xEE, 0x4E, 0x66, 0x29, 0xDF, 0x2B, 0x5A, 0xE8, 0x66, 0x2F, 0xCA, 0x93, 0x1E, 0xC5, 0xE9, 0xB8, 0x7E, 0x67, 0x85, 0x05, 0xB5, 0xF1, 0x29, 0xE6, 0x5D, 0xE6, 0x64, 0x6B, 0x2C, 0xE9, 0xD5, 0x37, 0xFA, 0xF8, 0x77, 0x5F, 0x9C, 0x4D, 0x8B, 0xA1, 0x58, 0xE1, 0x8E, 0x33, 0x29, 0x18, 0x59, 0xF0, 0x26, 0xE6, 0x05, 0x8F, 0x81, 0x8A, 0x7F, 0x38, 0x76, 0x91, 0x13, 0x80, 0x82, 0xCE, 0x13, 0xFB, 0xE9, 0x7C, 0xFC, 0xC6, 0x67, 0xE1, 0x06, 0xD8, 0x01, 0xF6, 0x95, 0x28, 0x40, 0x03, 0x70, 0xFE, 0x82, 0x39, 0x6D, 0xC6, 0x5B, 0xD3, 0x26, 0x45, 0x30, 0xB9, 0x6F, 0x87, 0x62, 0xB4, 0xA0, 0xF8, 0xCD, 0x7C, 0x9B, 0xAB, 0x19, 0xE2, 0x1B, 0x2A, 0x8C, 0x3E, 0x5D, 0xC1, 0x28, 0x7A, 0xB6, 0x9D, 0xA2, 0x53, 0x14, 0xD5, 0xB6, 0x7A, 0x8F, 0x57, 0xF6, 0x34, 0x14, 0x56, 0x6A, 0x18, 0x14, 0xDD, 0x11, 0xEC, 0xA5, 0xFB, 0x1E, 0x2D, 0xCE, 0x93, 0x24, 0xED, 0x6F, 0xB7, 0x24, 0xD6, 0xAF, 0xB0, 0xF5, 0x03, 0x7C, 0x5D, 0xD7, 0x52, 0xA6, 0x5C, 0xCA, 0x02, 0x70, 0xFF, 0x54, 0x2F, 0xD4, 0xC2, 0x16, 0xDC, 0x0D, 0x3E, 0x5D, 0xE7, 0x4C, 0x01, 0x3D, 0x7C, 0x08, 0x78, 0x01, 0xB2, 0xF0, 0xB7, 0x67, 0x3A, 0x8C, 0x16, 0x7B, 0xC2, 0x60, 0x34, 0x7A, 0x75, 0x4C, 0x52, 0x85, 0xB6, 0x83, 0xB7, 0x26, 0x14, 0x56, 0xD6, 0xD9, 0xD6, 0x25, 0xC1, 0x5C, 0x8E, 0x7B, 0x49, 0x73, 0xB6, 0xDD, 0xBA, 0xBA, 0xD2, 0x2A, 0xDC, 0x80, 0x28, 0x17, 0x5A, 0x28, 0xC5, 0xAA, 0xE5, 0xCD, 0xEE, 0x8F, 0x27, 0xA1, 0xB8, 0x0F, 0xA0, 0x2B, 0xDF, 0x48, 0x8D, 0x9D, 0x94, 0xD7, 0x5C, 0xD8, 0xF7, 0x9E, 0x71, 0x94, 0xCF, 0x12, 0x13, 0x71, 0x97, 0xE1, 0xF6, 0xC7, 0xF7, 0x69, 0xF7, 0xCA, 0x76, 0xF5, 0x8C, 0xBC, 0x96, 0x75, 0x75, 0x20, 0x07, 0x88, 0xB8, 0xF7, 0x81, 0x72, 0xC0, 0xEA, 0x3F, 0xA7, 0x67, 0xC8, 0xAF, 0x59, 0x59, 0x95, 0xAD, 0xC8, 0x9A, 0x21, 0x9F, 0x7D, 0xFC, 0xD7, 0x5B, 0x3E, 0x44, 0xB0, 0x79, 0xB2, 0x2B, 0x6B, 0x36, 0xF6, 0x32, 0xD5, 0xFF, 0xCD, 0xE5, 0x48, 0x61, 0x06, 0x02, 0x23, 0x96, 0x6C, 0xA2, 0xE5, 0xB7, 0x16, 0x06, 0x43, 0x23, 0xB8, 0x3E, 0x17, 0x2B, 0xB5, 0x9E, 0xBB, 0x66, 0xBE, 0xCA, 0x23, 0xBA, 0xA7, 0x34, 0xCD, 0xE7, 0xA0, 0xC3, 0x40, 0xD9, 0x34, 0xF5, 0x9B, 0x77, 0xA2, 0x24, 0xB3, 0x45, 0x2E, 0x11, 0xA8, 0x6E, 0x60, 0x66, 0xA1, 0x8B, 0x58, 0x14, 0x6B, 0x97, 0x01, 0x8F, 0x7B, 0x0A, 0x67, 0x03, 0xC1, 0x87, 0x7A, 0x77, 0x08, 0xB0, 0x04, 0xF6, 0x67, 0x97, 0xD1, 0x14, 0xAB, 0x4A, 0x3E, 0x83, 0xEB, 0x03, 0x7C, 0x07, 0x3D, 0xB8, 0x0F, 0xA4, 0x18, 0x8E, 0x91, 0x63, 0xFF, 0xF4, 0xD9, 0x00, 0x6C, 0x47, 0xBF, 0xD0, 0xAF, 0xC4, 0x6C, 0x25, 0xEF, 0x3F, 0xEF, 0x5D, 0x6D, 0x2E, 0x46, 0xE1, 0x4B, 0x6C, 0x25, 0x33, 0x3E, 0xC5, 0x9C, 0xA7, 0x15, 0x42, 0xAD, 0xC8, 0x72, 0x6D, 0x7D, 0x4E, 0xE6, 0x3A, 0xF0, 0xB1, 0xAC, 0xC0, 0x0D, 0xF6, 0xDE, 0xDD, 0xCD, 0x81, 0xA7, 0xA8, 0xC4, 0x1F, 0x89, 0x3F, 0xA7, 0x7C, 0x80, 0x3D, 0xBA, 0x7F, 0xEB, 0x32, 0x05, 0xD2, 0x81, 0x68, 0x80, 0x67, 0x3D, 0x31, 0x60, 0x12, 0xBF, 0xE7, 0x0D, 0x58, 0xDE, 0xDD, 0x57, 0x3D, 0x80, 0x53, 0x80, 0xE6, 0xBE, 0x32, 0xB4, 0x19, 0x8A, 0xB2, 0xA5, 0x62, 0x13, 0xC4, 0xF2, 0x6B, 0x33, 0x38, 0xE7, 0xD9, 0x69, 0xAF, 0x0A, 0x6A, 0x63, 0x1E, 0xBF, 0x91, 0xD5, 0xF4, 0x07, 0x01, 0xF5, 0xB6, 0x68, 0xC0, 0xB2, 0x47, 0xEF, 0xC0, 0xDE, 0x5E, 0x44, 0xD7, 0x82, 0xBC, 0x43, 0xEF, 0xDD, 0xBB, 0xD7, 0x71, 0xFF, 0x48, 0xBB, 0xAD, 0xC8, 0x39, 0xFB, 0x82, 0x7B, 0xBC, 0x59, 0xAF, 0xB6, 0xFE, 0xCF, 0x7C, 0xBA, 0xE0, 0xCD, 0x7A, 0xDD, 0x72, 0xEF, 0xFA, 0xC1, 0x9B, 0xBF, 0x03, 0xA7, 0x79, 0xB5, 0x00, 0x42, 0x01, 0x8F, 0x85, 0x2E, 0x1A, 0x18, 0xC1, 0x2F, 0x30, 0x4A, 0x2B, 0x03, 0x9C, 0xE4, 0x43, 0x40, 0xF6, 0xF7, 0x6A, 0x31, 0xB6, 0xAF, 0x3C, 0xE3, 0xCC, 0x21, 0x4B, 0x5F, 0x42, 0x51, 0x98, 0xAF, 0xCD, 0x10, 0x1A, 0x6A, 0xD9, 0xB6, 0x39, 0xB8, 0xB3, 0xA7, 0xE6, 0x9B, 0xFE, 0x22, 0xE7, 0xB6, 0x59, 0xFB, 0xDA, 0x2C, 0x99, 0xF7, 0xE0, 0xB0, 0x8B, 0xC9, 0x5B, 0xCD, 0xBB, 0x0B, 0x53, 0xD0, 0x8B, 0x55, 0x4F, 0xB2, 0xB5, 0xEE, 0x9D, 0xDB, 0xB1, 0x5B, 0x2E, 0x90, 0xDA, 0xB0, 0x02, 0x6F, 0xB0, 0x99, 0x16, 0x05, 0x14, 0x18, 0xF0, 0xB9, 0xFB, 0x36, 0x1F, 0x01, 0xAA, 0xEE, 0xB6, 0xC4, 0xD1, 0x40, 0x2D, 0x3A, 0x37, 0xE6, 0x20, 0x40, 0xC8, 0xDD, 0x18, 0xB5, 0x1B, 0xA8, 0x00, 0xD8, 0xFE, 0xA5, 0x03, 0xF0, 0x45, 0x7E, 0xBA, 0xA5, 0x66, 0xF0, 0x36, 0xB0, 0x97, 0x17, 0xA1, 0xCD, 0x28, 0x80, 0x29, 0x10, 0x98, 0xD0, 0x6D, 0x9E, 0xD8, 0xB3, 0x17, 0x29, 0x61, 0x5C, 0xE0, 0x2E, 0x8F, 0xF2, 0xD8, 0x6D, 0xA0, 0x2E, 0x09, 0xF4, 0x79, 0x52, 0x8C, 0xE7, 0x00, 0xCE, 0x0A, 0x2E, 0x79, 0x33, 0xF4, 0xD6, 0x81, 0xAD, 0x54, 0x64, 0xDD, 0x23, 0x0A, 0xFF, 0x52, 0x56, 0x4C, 0xCA, 0x8A, 0x33, 0xD2, 0x47, 0x59, 0xCF, 0xED, 0x95, 0x2B, 0xBE, 0x7F, 0xAA, 0x95, 0xB5, 0x01, 0x59, 0xB0, 0x27, 0xD8, 0x28, 0xD0, 0x03, 0x8C, 0xDD, 0x25, 0xF5, 0xCD, 0x85, 0xFF, 0x73, 0x30, 0x6E, 0x07, 0x5C, 0x00, 0x39, 0x80, 0xC9, 0xBE, 0x22, 0xCF, 0x48, 0x4B, 0x5A, 0x0D, 0x8B, 0x49, 0xC4, 0x5E, 0x97, 0xE6, 0x3D, 0xAC, 0x75, 0x75, 0x43, 0xDF, 0xFC, 0x09, 0xD2, 0xDA, 0x7F, 0xB4, 0xCE, 0xA6, 0x3C, 0x87, 0x5E, 0xFD, 0x3B, 0xA1, 0xF8, 0x78, 0xEB, 0x14, 0xC6, 0xC7, 0x40, 0xCA, 0xD6, 0xA4, 0x3B, 0x3C, 0x0E, 0xC5, 0x24, 0xFD, 0x5D, 0xEB, 0xB7, 0x9D, 0xCC, 0xEC, 0x6E, 0x5F, 0x77, 0xE5, 0x22, 0x1C, 0x01, 0xF7, 0x79, 0xA2, 0x3F, 0x3B, 0xA3, 0xC6, 0xFD, 0x7D, 0x4F, 0x2C, 0x6C, 0x51, 0x80, 0xD3, 0x81, 0x30, 0x40, 0x28, 0xE0, 0x02, 0x9C, 0xBE, 0xE5, 0x7A, 0x75, 0x80, 0xE0, 0xCD, 0xE1, 0x3C, 0x56, 0xAB, 0x7F, 0xF3, 0xFB, 0x73, 0x7B, 0x7B, 0x42, 0x24, 0x4A, 0x5D, 0x73, 0x3D, 0xDF, 0x6E, 0x3F, 0x73, 0x55, 0x0F, 0x4A, 0x0D, 0x63, 0x75, 0x01, 0x02, 0x55, 0x9F, 0xF6, 0x39, 0xA7, 0x39, 0x25, 0xD3, 0x92, 0x3E, 0xEB, 0xDD, 0x43, 0xD9, 0xF7, 0x63, 0x0A, 0x9F, 0x86, 0xA7, 0x53, 0xB6, 0x16, 0xEB, 0xB7, 0xA1, 0x70, 0x3E, 0x5A, 0x69, 0x14, 0xFF, 0x65, 0xBB, 0xC6, 0x89, 0xBF, 0x5D, 0xAC, 0xFE, 0x0A, 0x6E, 0xF5, 0xAE, 0x9F, 0x95, 0xB9, 0x47, 0x4E, 0x15, 0x30, 0xB3, 0x88, 0x85, 0x7F, 0x3E, 0xCD, 0x7D, 0x32, 0x1B, 0xCA, 0x92, 0x1D, 0x40, 0x9B, 0x0F, 0x81, 0x10, 0x40, 0x1A, 0x78, 0x5E, 0x91, 0xC7, 0x68, 0xFD, 0xAF, 0x50, 0x3A, 0x80, 0x48, 0xA1, 0x7F, 0x3D, 0xDF, 0x8C, 0xE3, 0xE9, 0xAE, 0x0B, 0xB6, 0xB9, 0xA4, 0xF3, 0xD6, 0xF9, 0xCC, 0xE0, 0x1D, 0x9E, 0x9F, 0xA9, 0x85, 0xDE, 0xEB, 0x1F, 0xB4, 0x27, 0xF3, 0xBC, 0x16, 0x69, 0x6F, 0x1A, 0xE7, 0x96, 0x79, 0x3E, 0xD9, 0xAE, 0xF1, 0x88, 0x91, 0x30, 0x75, 0x76, 0xE2, 0x15, 0x91, 0xD6, 0x47, 0x06, 0x30, 0xD9, 0x7A, 0x9D, 0xCB, 0xF5, 0x1E, 0xFE, 0x87, 0xC9, 0xF7, 0x3C, 0xD9, 0x17, 0x37, 0x04, 0x40, 0x0B, 0x70, 0x5D, 0x34, 0x10, 0xC5, 0x4E, 0x3A, 0x00, 0x4F, 0x80, 0x56, 0x80, 0xEA, 0x3E, 0x34, 0x40, 0x83, 0xE9, 0x4C, 0xC0, 0x0C, 0x5E, 0x39, 0x41, 0xA3, 0x0D, 0x5A, 0xE2, 0x1D, 0x85, 0xEF, 0xB8, 0xF5, 0x6B, 0x34, 0xFC, 0x65, 0xA9, 0x5B, 0xF9, 0x1C, 0x2B, 0x92, 0xED, 0xF7, 0xE1, 0x36, 0x38, 0xD4, 0xF4, 0x15, 0xCF, 0x54, 0x7D, 0x4A, 0x1E, 0xBA, 0xDE, 0xB3, 0x98, 0xEF, 0xD5, 0x9C, 0x7D, 0xEB, 0xB0, 0x55, 0x62, 0x34, 0x52, 0x03, 0x9B, 0xBD, 0x8D, 0xA8, 0x8C, 0xE8, 0x6F, 0xE3, 0x79, 0x83, 0x61, 0x29, 0x58, 0xDA, 0x4F, 0x6F, 0x38, 0x0D, 0xFA, 0xE4, 0x00, 0x39, 0xC0, 0x50, 0x9A, 0x2D, 0x80, 0x5A, 0x74, 0x03, 0x63, 0x77, 0x45, 0x88, 0x33, 0xDF, 0x2B, 0x80, 0x54, 0xC0, 0xEB, 0x7D, 0x58, 0x7F, 0xD9, 0xFA, 0x07, 0x08, 0x79, 0x5E, 0x59, 0xAB, 0xE5, 0x7B, 0x25, 0x18, 0xE4, 0xD5, 0xDE, 0x56, 0xDB, 0x13, 0x64, 0xEA, 0xAF, 0x24, 0x2C, 0x1C, 0x5B, 0x2C, 0x3B, 0xCC, 0xEA, 0xB7, 0xC0, 0xD8, 0xE7, 0x4D, 0x42, 0xD3, 0xBF, 0x4A, 0x0F, 0x93, 0x3B, 0x97, 0xDA, 0x6C, 0x7D, 0xAD, 0x2C, 0x56, 0xAD, 0x4D, 0xC3, 0xF8, 0xA1, 0xF6, 0x6A, 0xE9, 0x8F, 0x2B, 0xD2, 0xF6, 0x72, 0x2E, 0x6C, 0xA4, 0x1A, 0xCF, 0x1D, 0xFD, 0xB9, 0x45, 0x06, 0xC0, 0xE9, 0x73, 0x25, 0x40, 0x7C, 0x7C, 0x42, 0xE2, 0xC0, 0x21, 0x6C, 0x91, 0x80, 0xCD, 0x4E, 0xF3, 0xBA, 0xE6, 0xE2, 0xF5, 0xF0, 0xFA, 0x8F, 0x69, 0x7F, 0xBC, 0x1C, 0xF3, 0x58, 0x4D, 0x68, 0x35, 0x28, 0xDE, 0x7A, 0x6C, 0x3F, 0x2A, 0x1E, 0xD8, 0xD8, 0xCD, 0xF3, 0x17, 0xBA, 0x8B, 0xCA, 0x40, 0x24, 0xE4, 0x60, 0x07, 0xF5, 0x6F, 0x5B, 0x41, 0x56, 0xE4, 0x7B, 0x30, 0x79, 0x8A, 0xFA, 0x99, 0x07, 0x78, 0x5A, 0x3D, 0x14, 0x93, 0x82, 0x6E, 0xE1, 0xFC, 0xC3, 0x15, 0xEC, 0x00, 0x67, 0x70, 0xA3, 0x96, 0xB7, 0xCA, 0x2A, 0x9E, 0x44, 0xFB, 0x27, 0xC8, 0xBC, 0x1B, 0x62, 0x06, 0x20, 0x09, 0x98, 0x02, 0x1D, 0x5C, 0xEF, 0x3F, 0x3B, 0x68, 0x2E, 0xF8, 0x50, 0x00, 0xF3, 0x7B, 0x91, 0x73, 0x01, 0xB4, 0xF6, 0x61, 0x03, 0xF1, 0x91, 0xAF, 0x71, 0xFF, 0x5E, 0x3F, 0x53, 0xD7, 0x6A, 0x38, 0xA3, 0xEB, 0xD4, 0xFF, 0xB8, 0x3B, 0xB2, 0xE6, 0x07, 0xF5, 0xB3, 0x7D, 0x40, 0x4D, 0xD9, 0x18, 0xEF, 0xCE, 0xB6, 0x32, 0xCE, 0x8A, 0xC7, 0x4E, 0xC3, 0x5B, 0x37, 0x33, 0x66, 0xF1, 0x49, 0xD8, 0xA0, 0x6F, 0x77, 0xD0, 0xB4, 0xF7, 0x10, 0xE5, 0x7F, 0x07, 0xD6, 0xFC, 0x93, 0xCF, 0xE9, 0x75, 0xB0, 0xE6, 0x63, 0x3C, 0x7D, 0x6A, 0x46, 0xD7, 0x08, 0x02, 0xD8, 0x59, 0x34, 0xD0, 0xFE, 0x31, 0xD7, 0xA2, 0xFB, 0xC6, 0xD0, 0x16, 0x06, 0x74, 0xD2, 0x16, 0x80, 0x7C, 0xAF, 0xFE, 0x07, 0x10, 0xBD, 0x05, 0x58, 0xA4, 0x1E, 0xAB, 0x19, 0xAD, 0x86, 0x5B, 0x68, 0x34, 0x32, 0x11, 0x5C, 0xB0, 0x77, 0x6D, 0x75, 0x4F, 0x65, 0x61, 0x7F, 0x82, 0x7D, 0x51, 0x43, 0x75, 0x30, 0x23, 0x21, 0x9C, 0x70, 0x4B, 0x00, 0x50, 0x4A, 0xE2, 0x6A, 0x5B, 0xD6, 0x0C, 0x36, 0xE0, 0x13, 0x97, 0x29, 0xA3, 0x38, 0xA6, 0xB1, 0x14, 0x14, 0xF3, 0xEE, 0x00, 0x22, 0x3C, 0x26, 0xEE, 0x2C, 0xE4, 0x71, 0x80, 0xD3, 0x4F, 0x78, 0xC4, 0x00, 0xE4, 0x07, 0x59, 0x3B, 0xFD, 0x0E, 0xF4, 0x40, 0xF2, 0x95, 0x5C, 0xE8, 0xE2, 0x2C, 0xE4, 0x36, 0xAC, 0x14, 0x50, 0x8F, 0x2D, 0x00, 0xCE, 0xDE, 0x5A, 0x98, 0xDD, 0x13, 0x5C, 0x63, 0x5F, 0xF9, 0xB3, 0x9A, 0xFF, 0xCC, 0xE5, 0x99, 0xA8, 0x27, 0x3B, 0xF6, 0x6E, 0x03, 0x29, 0x2E, 0xEB, 0xEA, 0xB0, 0x4D, 0xEE, 0x19, 0xA4, 0xB7, 0x97, 0x50, 0x06, 0xE6, 0x73, 0x5A, 0xBB, 0x5A, 0xE3, 0x49, 0xEF, 0x1A, 0xCF, 0x6E, 0x81, 0x2C, 0x2A, 0x61, 0x2B, 0x57, 0x76, 0x28, 0x6B, 0x76, 0xDA, 0xDF, 0xEA, 0x4F, 0x7A, 0x68, 0xF5, 0xF1, 0x8E, 0x4D, 0xFE, 0xE9, 0xE5, 0xD4, 0xCE, 0x91, 0x7C, 0x12, 0xA1, 0x9F, 0x40, 0x0D, 0x4D, 0x79, 0x0D, 0xC0, 0x78, 0x74, 0x55, 0xAC, 0x80, 0xE6, 0xA1, 0xD8, 0x01, 0x09, 0x40, 0x13, 0xC8, 0xBC, 0xAF, 0xE4, 0xFD, 0xB9, 0xA7, 0xBB, 0xFC, 0x87, 0x1E, 0x4B, 0xED, 0x9B, 0x99, 0x8F, 0xD5, 0x78, 0x33, 0x40, 0x9A, 0xF2, 0x71, 0xBB, 0x9A, 0xFE, 0xAC, 0xDE, 0xAD, 0xAA, 0x2B, 0xEA, 0xB1, 0x35, 0x50, 0xD6, 0x68, 0x73, 0xCF, 0xD0, 0xFA, 0x9C, 0x71, 0x4D, 0x98, 0xC0, 0x1B, 0x6F, 0x43, 0x4D, 0x7F, 0xFA, 0x78, 0xB3, 0x75, 0xAC, 0xF4, 0x7B, 0xB1, 0xF1, 0xB5, 0x93, 0xF2, 0x6A, 0x88, 0x37, 0xFB, 0x71, 0x56, 0x9C, 0x59, 0x5B, 0xD8, 0xBD, 0xEA, 0xF8, 0x8E, 0xA0, 0x28, 0x40, 0x14, 0x30, 0xF9, 0xAC, 0x6B, 0x9C, 0xC4, 0xB3, 0xC8, 0x0F, 0xE6, 0xD6, 0x0D, 0x19, 0xFB, 0xB8, 0xD5, 0xF8, 0x50, 0x01, 0xFF, 0x9C, 0x9B, 0xAD, 0x1E, 0xCF, 0x1B, 0xAD, 0x96, 0xBF, 0x7B, 0xFB, 0x54, 0x43, 0x55, 0xD3, 0xBE, 0x6E, 0xDC, 0xCD, 0x70, 0x4A, 0x83, 0xC6, 0x6A, 0xE9, 0x2A, 0x6B, 0xDF, 0x7A, 0x30, 0xF5, 0x1C, 0x72, 0xFD, 0xAD, 0x0B, 0xD0, 0xBF, 0x36, 0x09, 0x4A, 0xAD, 0x83, 0x57, 0x71, 0x96, 0x3A, 0x17, 0x4A, 0x05, 0xEB, 0x4D, 0xB3, 0x66, 0x1A, 0xA8, 0xD4, 0x73, 0x2D, 0x1F, 0x7F, 0x05, 0x4A, 0x85, 0x1E, 0x55, 0x29, 0xB6, 0x3E, 0xE6, 0x21, 0x03, 0x10, 0x80, 0xE2, 0x62, 0x57, 0xA1, 0x0C, 0x3C, 0x3D, 0x8B, 0x30, 0x20, 0x13, 0xA8, 0xB9, 0xAA, 0x9E, 0xE5, 0x11, 0x60, 0x8C, 0x85, 0x0B, 0x70, 0x78, 0xD5, 0x1F, 0x40, 0x0C, 0x60, 0xE7, 0x4D, 0x53, 0x5A, 0xAD, 0x20, 0xD9, 0x79, 0x04, 0x0E, 0x8A, 0xF2, 0x8F, 0xD5, 0x98, 0x9F, 0x98, 0xBB, 0x3A, 0xF5, 0x3A, 0x79, 0xFD, 0x72, 0xAB, 0xE5, 0x75, 0xC8, 0x6D, 0x5E, 0xF5, 0xEA, 0xC9, 0x27, 0xD1, 0x7A, 0xEB, 0x74, 0xE4, 0xA9, 0xE3, 0x2C, 0xC6, 0x7A, 0x29, 0x91, 0xC0, 0xAE, 0x5C, 0xAF, 0x78, 0xA1, 0xFA, 0x73, 0x33, 0x2D, 0xDB, 0xD9, 0xDE, 0x6B, 0xC9, 0x82, 0x25, 0x63, 0xBF, 0x99, 0x60, 0x55, 0xEC, 0xB9, 0xFC, 0xD6, 0xFA, 0x74, 0xB7, 0x39, 0x09, 0x8C, 0x53, 0x18, 0x0E, 0x48, 0x05, 0x6A, 0x78, 0xBB, 0xBF, 0xD3, 0x79, 0x4B, 0x80, 0x68, 0x40, 0x79, 0x25, 0x34, 0x40, 0x0A, 0xB0, 0xE2, 0xF5, 0x98, 0x46, 0x7B, 0x52, 0x94, 0x17, 0x3C, 0x3C, 0x09, 0x8D, 0xB6, 0x1D, 0x8C, 0x05, 0x5B, 0x7D, 0x1B, 0x56, 0x6F, 0x74, 0xD3, 0xF3, 0x5A, 0xAB, 0x79, 0x5C, 0x82, 0x4D, 0x2B, 0x0B, 0xCC, 0x3E, 0x9E, 0xB0, 0xF3, 0x79, 0x81, 0x40, 0x1B, 0x7E, 0xF6, 0x66, 0x7B, 0x30, 0xF7, 0x23, 0x77, 0xFD, 0x8E, 0x47, 0x02, 0xB1, 0x1E, 0xAD, 0xBA, 0x8D, 0xDD, 0x2C, 0xBC, 0x17, 0x07, 0x50, 0x5B, 0x04, 0x50, 0xBE, 0xB3, 0x36, 0x80, 0x21, 0x7A, 0x31, 0xDC, 0x57, 0x17, 0x71, 0xBB, 0xB1, 0x4F, 0xFF, 0xD7, 0x25, 0x34, 0x3F, 0x97, 0xD0, 0x7C, 0xA7, 0x2B, 0x56, 0x5F, 0x5A, 0x6D, 0xBE, 0x56, 0xBB, 0x87, 0x1A, 0xB7, 0xB0, 0xF8, 0x59, 0xAD, 0x4D, 0x0B, 0x3B, 0x20, 0x14, 0x9E, 0xA2, 0xBF, 0xFD, 0x8C, 0x8D, 0xE5, 0x29, 0xBD, 0x76, 0xCA, 0x62, 0x09, 0x0A, 0xC0, 0xA3, 0x46, 0xE7, 0xFE, 0xAC, 0x29, 0xA6, 0xCC, 0xE2, 0xF6, 0x2B, 0xF8, 0xCB, 0xBF, 0x9B, 0x17, 0x47, 0x9A, 0x64, 0xEC, 0xFF, 0xB1, 0x5A, 0x02, 0x15, 0xF7, 0x5A, 0x37, 0xFD, 0xB1, 0x93, 0x2E, 0x7C, 0x51, 0xF7, 0xE9, 0x4B, 0x14, 0x88, 0x06, 0x3C, 0x3F, 0x61, 0x29, 0x03, 0xEC, 0x00, 0x71, 0xBE, 0x87, 0xDC, 0x3A, 0xB8, 0x50, 0x69, 0xFD, 0x14, 0x96, 0x33, 0x06, 0x9D, 0xB1, 0x86, 0xAB, 0x1B, 0xB5, 0x23, 0x64, 0xAF, 0x30, 0x45, 0x55, 0xAE, 0xBB, 0xC8, 0xF8, 0x7C, 0xB6, 0xD0, 0xEA, 0x47, 0xA1, 0x84, 0x82, 0x23, 0x40, 0x51, 0x69, 0x84, 0x9A, 0xAC, 0x97, 0x80, 0x7C, 0xEC, 0x3C, 0xD8, 0x8E, 0x8C, 0x8F, 0x2F, 0x70, 0xFB, 0xAD, 0xF3, 0x18, 0x92, 0xBB, 0x46, 0xC7, 0xE3, 0x9C, 0x78, 0x8E, 0xEA, 0x72, 0xDB, 0xA2, 0x94, 0x27, 0xBA, 0xFD, 0xA7, 0x5B, 0x54, 0x33, 0x80, 0x01, 0x88, 0x01, 0xAA, 0x40, 0xC6, 0x5D, 0x5E, 0xD9, 0x03, 0x54, 0xDE, 0x5B, 0x68, 0x0F, 0x10, 0x8F, 0x11, 0xF0, 0x33, 0x00, 0x56, 0x93, 0xBF, 0x2D, 0x74, 0xB0, 0xAE, 0xBC, 0x07, 0x0F, 0xF7, 0xC1, 0xC0, 0x1D, 0xDB, 0xBD, 0x0B, 0x63, 0x4D, 0xA6, 0x78, 0x25, 0xF8, 0xCC, 0x50, 0x9E, 0xB0, 0x92, 0xD7, 0xFD, 0xA7, 0x57, 0xF8, 0xFA, 0x92, 0xD9, 0xE2, 0xCD, 0xEF, 0xB1, 0x46, 0xD9, 0x09, 0x8B, 0xCB, 0x73, 0x56, 0xF1, 0x8E, 0x58, 0x7F, 0xF2, 0xDC, 0xCC, 0xEF, 0xCB, 0x80, 0xFA, 0x8E, 0xAE, 0x06, 0x62, 0x00, 0x9E, 0x67, 0x43, 0x81, 0x16, 0xA0, 0xE6, 0x8B, 0xCF, 0x71, 0x2D, 0xEE, 0xB6, 0xE7, 0xB2, 0x38, 0xCE, 0x87, 0x80, 0x7D, 0x6E, 0x60, 0xCF, 0x11, 0x5B, 0x1E, 0xAB, 0xE9, 0x9F, 0xD5, 0x9A, 0xA7, 0x8A, 0xEF, 0xD5, 0xE0, 0x8C, 0xE4, 0x9E, 0xEF, 0x0C, 0x06, 0x29, 0x5C, 0xA8, 0x68, 0xB5, 0x38, 0x57, 0xF9, 0x4A, 0xB2, 0x59, 0x41, 0x3D, 0xED, 0x03, 0x25, 0x80, 0x52, 0xBA, 0xDA, 0x60, 0xBC, 0x8A, 0x5D, 0x5E, 0x85, 0x3A, 0xE7, 0xD7, 0x91, 0xD7, 0x95, 0x97, 0xD9, 0xFB, 0x90, 0xAB, 0xFC, 0x16, 0x49, 0xB1, 0x75, 0x40, 0xD6, 0x8D, 0xDC, 0xBA, 0x9F, 0x16, 0x7D, 0x3E, 0x5E, 0xB5, 0x5C, 0x04, 0x71, 0xFF, 0xCC, 0x69, 0x2E, 0xFB, 0xAF, 0xC0, 0xB1, 0xDD, 0xF5, 0x84, 0xA6, 0x1F, 0xE7, 0xDA, 0x9F, 0xD5, 0x0C, 0xEA, 0xD5, 0x1D, 0xBF, 0x5A, 0xBC, 0xA3, 0xDF, 0x0B, 0x15, 0xCF, 0x50, 0x18, 0xA3, 0xF4, 0x0A, 0x8F, 0x25, 0xE5, 0xBC, 0x79, 0x1B, 0xBD, 0xCE, 0x1D, 0xD6, 0x6C, 0xE6, 0x4F, 0xDD, 0xFB, 0x45, 0xF8, 0x3A, 0xD7, 0x92, 0x11, 0x11, 0xB6, 0x18, 0xA4, 0xE7, 0x9F, 0x9E, 0x1A, 0xD8, 0x4E, 0x1B, 0x63, 0xFC, 0x71, 0x9F, 0xDC, 0xA1, 0xF4, 0x69, 0xC0, 0xE3, 0x76, 0xB6, 0x96, 0xBD, 0x93, 0xB7, 0x78, 0x2F, 0x39, 0xCF, 0x79, 0x65, 0xD8, 0xC2, 0xAB, 0x81, 0xE1, 0x6A, 0x7A, 0x80, 0xA2, 0x33, 0x8F, 0x85, 0x80, 0x06, 0x70, 0xD3, 0x4A, 0x07, 0x4E, 0xE1, 0xCD, 0x74, 0xA0, 0xF7, 0xE1, 0x28, 0x8D, 0xE6, 0xBF, 0x2B, 0x81, 0x37, 0xD4, 0x48, 0x9F, 0x04, 0xE6, 0xDD, 0xD7, 0x66, 0x12, 0x3D, 0x87, 0xE7, 0xE7, 0x91, 0x9C, 0xA8, 0x86, 0x27, 0xFE, 0xD4, 0x5D, 0xF3, 0x13, 0x1C, 0x6A, 0xF9, 0xB9, 0x85, 0x16, 0xC5, 0x8E, 0x1A, 0x48, 0x9E, 0x78, 0x65, 0x67, 0xED, 0x1A, 0x3F, 0xCF, 0xEB, 0x2C, 0xB3, 0xC5, 0xBA, 0xDC, 0x18, 0x5F, 0x63, 0xA7, 0xDF, 0xFC, 0xCB, 0x6E, 0x9E, 0x3B, 0xEC, 0xD9, 0x72, 0x27, 0xD7, 0x07, 0x07, 0x3A, 0xAB, 0x9B, 0x19, 0x6F, 0x2F, 0xA0, 0x12, 0x98, 0x78, 0x3A, 0xBD, 0x00, 0x4F, 0x7C, 0xE6, 0x00, 0x55, 0x40, 0x2E, 0x2C, 0x98, 0xBC, 0x09, 0x84, 0xDE, 0x32, 0x36, 0xE9, 0xB4, 0x5A, 0xFC, 0xEB, 0x42, 0xDB, 0xB7, 0xF9, 0x0D, 0xF8, 0x7C, 0x67, 0xA6, 0x47, 0x3A, 0x4E, 0xFB, 0xE2, 0x88, 0xBE, 0x1F, 0xDB, 0xA3, 0x7C, 0xDE, 0x32, 0x00, 0x4A, 0xAB, 0xB1, 0xB4, 0x33, 0x3E, 0x2D, 0x40, 0x63, 0x00, 0xEA, 0x48, 0x30, 0xAC, 0x21, 0xB5, 0x5D, 0xB7, 0x18, 0xEE, 0x11, 0x7C, 0x27, 0x46, 0x2C, 0xD9, 0xF5, 0x86, 0x89, 0x1A, 0xD7, 0x3D, 0x5B, 0x1F, 0x57, 0x87, 0x39, 0xC0, 0x75, 0x61, 0xE2, 0x56, 0x1F, 0xD0, 0xA1, 0x5F, 0xF6, 0xA3, 0x37, 0xA0, 0x80, 0x2E, 0x6C, 0x51, 0x74, 0xB2, 0x05, 0x30, 0x07, 0xA8, 0x00, 0x58, 0x95, 0x3F, 0x8B, 0x98, 0x7B, 0x67, 0xC9, 0xBF, 0x2D, 0x34, 0x7F, 0x17, 0xA9, 0x08, 0xF9, 0xEF, 0x83, 0x07, 0x76, 0x1D, 0xFB, 0x59, 0xAD, 0x44, 0x37, 0x9B, 0x3F, 0xA8, 0xB2, 0xFC, 0x19, 0x6B, 0x7D, 0x2D, 0x6B, 0xBD, 0x7A, 0x78, 0xBE, 0x60, 0xA3, 0x6B, 0xEE, 0x09, 0x9B, 0xBB, 0xC6, 0xBE, 0xC7, 0xBC, 0x70, 0x36, 0x77, 0x01, 0xA6, 0x32, 0x3F, 0x57, 0xA7, 0x58, 0x73, 0xC9, 0x13, 0x35, 0x5C, 0x08, 0x90, 0x8B, 0xE2, 0x2D, 0xC9, 0xF6, 0xF7, 0x78, 0xEF, 0xDC, 0x21, 0x77, 0x0E, 0x10, 0x02, 0xD4, 0x01, 0x9A, 0x05, 0xF5, 0xF6, 0xEC, 0xD5, 0x40, 0x2A, 0x10, 0xAF, 0xFC, 0xC5, 0x3C, 0x5A, 0x40, 0xB2, 0x70, 0xFE, 0x82, 0x15, 0xAD, 0x56, 0x1F, 0x73, 0xD1, 0xB1, 0x33, 0x57, 0xA5, 0xC1, 0xB1, 0x59, 0x91, 0x9B, 0x46, 0x94, 0xE9, 0xF8, 0x95, 0x80, 0x4B, 0xA3, 0x25, 0xB5, 0xCE, 0x19, 0x05, 0x0C, 0x56, 0x4D, 0xFB, 0xA6, 0xB4, 0xB3, 0x45, 0xBF, 0x7F, 0x2A, 0x13, 0x9B, 0x5E, 0xF0, 0xBD, 0x3C, 0xF8, 0x53, 0x19, 0xFD, 0x24, 0x54, 0x7B, 0xEC, 0x55, 0xA2, 0x36, 0x4E, 0xC3, 0xAB, 0xD6, 0x3C, 0x53, 0x79, 0xEC, 0x4F, 0x7B, 0x26, 0x1E, 0xE9, 0xCD, 0x7C, 0x3A, 0x64, 0x02, 0xA6, 0x80, 0x18, 0x70, 0x72, 0x31, 0xFF, 0x15, 0x68, 0xB1, 0xCF, 0x19, 0x77, 0xFE, 0x9F, 0x40, 0x4B, 0x3C, 0x43, 0xAD, 0xAF, 0xA6, 0x2B, 0xED, 0xB2, 0x0A, 0x0E, 0xBF, 0xD3, 0x9A, 0xF8, 0x68, 0xE2, 0x1F, 0x4B, 0x64, 0x17, 0x49, 0x44, 0xF5, 0x54, 0x94, 0xBD, 0x91, 0xAE, 0xA0, 0x9E, 0x0D, 0x67, 0xC3, 0x15, 0x9E, 0x32, 0x00, 0x5D, 0xBC, 0x6E, 0xE9, 0x45, 0x4D, 0x18, 0xA1, 0x09, 0xF6, 0x3C, 0xDE, 0x5B, 0x2B, 0xC5, 0xC1, 0xD8, 0xE4, 0xDE, 0xE7, 0x95, 0x7A, 0x94, 0x47, 0x67, 0xBE, 0x76, 0xAC, 0xE8, 0xBB, 0xE4, 0xF9, 0x63, 0x35, 0x91, 0x5B, 0x89, 0x46, 0xE4, 0x73, 0x67, 0x97, 0x85, 0xDF, 0x11, 0xAC, 0x1E, 0xA6, 0x42, 0x02, 0x52, 0x1F, 0xE7, 0x9A, 0x01, 0x12, 0xB7, 0xE7, 0x57, 0xF5, 0xB1, 0xDA, 0xDC, 0x43, 0x8D, 0x5E, 0x1E, 0x89, 0x2B, 0x31, 0xD2, 0x43, 0x77, 0x11, 0x6F, 0x88, 0x49, 0x55, 0xBC, 0xD3, 0x45, 0x04, 0xA0, 0x83, 0x05, 0x13, 0x4B, 0x63, 0xF3, 0x8D, 0x37, 0x2C, 0xEB, 0xF9, 0xB4, 0x51, 0x2B, 0x67, 0xF1, 0x0D, 0xA0, 0x03, 0x9C, 0x04, 0x5A, 0x6F, 0x55, 0x50, 0xB7, 0xBF, 0x46, 0xD6, 0xF6, 0xD7, 0x09, 0x23, 0x98, 0x0D, 0xCE, 0x74, 0xB5, 0x37, 0x61, 0x23, 0x9E, 0xEF, 0xDE, 0x72, 0xFB, 0x61, 0x5D, 0xBF, 0x79, 0x91, 0x37, 0xBE, 0xA1, 0xA7, 0x54, 0xC0, 0xFB, 0x36, 0x5D, 0x36, 0x60, 0x8B, 0xE8, 0x6F, 0x3E, 0x4C, 0x9F, 0xDF, 0x1E, 0x30, 0xE5, 0x9B, 0x0C, 0x90, 0x4F, 0xCA, 0x04, 0xFA, 0x66, 0x27, 0x36, 0xA2, 0xC9, 0x2D, 0x5F, 0x72, 0xF8, 0x27, 0x36, 0x7C, 0xDC, 0xDF, 0x84, 0x98, 0xA7, 0xE6, 0xDF, 0x98, 0xBC, 0x32, 0xAF, 0xA0, 0x60, 0x3F, 0x41, 0xA7, 0xA0, 0x00, 0x72, 0x03, 0x47, 0x6F, 0xBD, 0x3C, 0xDB, 0x87, 0x96, 0x40, 0xF5, 0xEB, 0x05, 0x66, 0xFB, 0x91, 0x5A, 0x6F, 0x39, 0x7C, 0x89, 0x4F, 0xB3, 0x8D, 0xDC, 0xAF, 0x16, 0x0F, 0x6C, 0x80, 0x13, 0xF7, 0xF0, 0x4B, 0x5B, 0xC8, 0x22, 0x80, 0xD9, 0x37, 0x53, 0x6F, 0x7D, 0xDE, 0x51, 0x20, 0x0D, 0xA0, 0x97, 0x92, 0xB7, 0x63, 0xBE, 0xD2, 0xFD, 0x58, 0x4D, 0xFE, 0x35, 0x6A, 0x61, 0x71, 0x40, 0x11, 0x5D, 0xBF, 0x60, 0x5D, 0x31, 0xBD, 0x4C, 0xC5, 0x4A, 0xA5, 0xBE, 0xB2, 0x65, 0xFA, 0x1E, 0xC8, 0x4F, 0x01, 0x94, 0x90, 0x6E, 0x8A, 0x37, 0x3E, 0xA5, 0x4A, 0xB5, 0xD5, 0x21, 0x3B, 0xB6, 0x26, 0x01, 0xD6, 0x8A, 0x50, 0x4E, 0x9B, 0x83, 0xAA, 0x04, 0xF0, 0xF3, 0x0A, 0x90, 0x08, 0x05, 0x94, 0x36, 0xB2, 0x57, 0x6B, 0x4F, 0x1E, 0x02, 0xB0, 0xB7, 0x3E, 0x5D, 0x8E, 0xE7, 0x49, 0x93, 0x90, 0xBE, 0xAB, 0xC2, 0x55, 0x81, 0xD3, 0x0B, 0x5B, 0x14, 0xE0, 0x75, 0x77, 0x86, 0xCC, 0x01, 0xC2, 0x01, 0x95, 0xCF, 0x7F, 0xA5, 0x81, 0xA0, 0xDA, 0x78, 0x3C, 0x36, 0xE3, 0xAD, 0x60, 0xA7, 0x42, 0xE5, 0xCA, 0x2C, 0x5E, 0x5E, 0x49, 0x95, 0x9A, 0x8D, 0x08, 0x0E, 0x46, 0x1A, 0x6C, 0x76, 0xCE, 0x37, 0x5F, 0x2D, 0x78, 0x54, 0xE3, 0xF4, 0xAE, 0xAB, 0x6B, 0xEB, 0xFC, 0xF5, 0x2D, 0xA2, 0x63, 0x6D, 0x17, 0x33, 0x46, 0x96, 0x2D, 0x01, 0xF1, 0x5B, 0x8B, 0xF1, 0x5C, 0xDA, 0xDC, 0x74, 0x6D, 0xC5, 0x93, 0xB6, 0x10, 0x82, 0xDD, 0xFF, 0x93, 0xE5, 0xE7, 0x9F, 0x34, 0xBD, 0x76, 0x20, 0x04, 0xB0, 0x5A, 0xD8, 0x22, 0x80, 0x92, 0xFB, 0xF7, 0xBA, 0xEE, 0xA1, 0x69, 0x7D, 0xEF, 0x27, 0xA1, 0xF7, 0x2F, 0x64, 0x3D, 0x56, 0xB3, 0xAB, 0x74, 0xD1, 0xAA, 0x91, 0x73, 0x67, 0x8A, 0x1B, 0x4A, 0xEC, 0xFC, 0x3C, 0x18, 0x85, 0x15, 0xB2, 0x9A, 0x9C, 0xC5, 0xA3, 0xD9, 0x65, 0x34, 0xA7, 0x04, 0xC0, 0x93, 0xE4, 0x17, 0x7B, 0x2B, 0xA0, 0xFA, 0x14, 0xAB, 0x27, 0x1A, 0x48, 0x6A, 0xA6, 0x06, 0xE0, 0xF6, 0x7E, 0xDA, 0x3A, 0x69, 0x63, 0x47, 0x15, 0x7D, 0x0A, 0x33, 0xE2, 0x87, 0xB3, 0x1E, 0x73, 0x07, 0xE6, 0xA3, 0xFD, 0xE1, 0x7F, 0xBE, 0xD8, 0x4F, 0x81, 0x16, 0x3F, 0x49, 0x2C, 0x64, 0xF1, 0x49, 0x43, 0x96, 0xFC, 0xAF, 0x45, 0x8D, 0x2E, 0xA2, 0x85, 0x05, 0x10, 0xF9, 0x5D, 0xD4, 0xDA, 0xFF, 0x25, 0x1A, 0x30, 0x5E, 0x97, 0xA7, 0xD7, 0xB1, 0x06, 0x13, 0x86, 0x50, 0xF7, 0x15, 0xC9, 0xFE, 0x07, 0x06, 0x65, 0x85, 0x94, 0x02, 0x3D, 0xEF, 0x19, 0xC7, 0x0C, 0x88, 0x3D, 0x64, 0xE7, 0x56, 0xD4, 0x27, 0xCA, 0x62, 0x37, 0x61, 0x09, 0x9F, 0xF2, 0x6C, 0x8D, 0x41, 0x2E, 0x1C, 0x0F, 0xD9, 0xA6, 0xCE, 0x74, 0xAB, 0xA0, 0x98, 0xC9, 0xCB, 0x12, 0xB9, 0x35, 0x32, 0x75, 0x4F, 0x64, 0x0B, 0x52, 0xD9, 0x54, 0x8A, 0x8A, 0x01, 0xCD, 0x68, 0xD7, 0x00, 0x1A, 0xC0, 0xD1, 0xF5, 0x65, 0xC6, 0x62, 0x7F, 0xE6, 0xEC, 0xE0, 0x55, 0x40, 0x0D, 0x90, 0x01, 0x28, 0xF3, 0x8F, 0x0E, 0xA0, 0x09, 0x84, 0xEC, 0x2B, 0x8F, 0xCD, 0x02, 0x05, 0xC6, 0x19, 0xEB, 0x30, 0x19, 0x6C, 0x9E, 0x11, 0xD8, 0x39, 0x7A, 0x30, 0xFA, 0x76, 0x84, 0xD5, 0x71, 0x24, 0xB1, 0xBF, 0xC9, 0x1C, 0x2C, 0xD2, 0xC6, 0x5E, 0x7A, 0x79, 0x70, 0xD7, 0xFB, 0x68, 0xF5, 0x28, 0xAC, 0x0C, 0x2B, 0x58, 0x03, 0xA8, 0x02, 0xB4, 0xDE, 0xFE, 0xA6, 0xFE, 0xF4, 0x26, 0x7A, 0xC4, 0x6A, 0x28, 0x9B, 0xB9, 0x15, 0x88, 0xC6, 0xB1, 0x68, 0xEF, 0xB0, 0x93, 0x8D, 0xC2, 0xD7, 0xE3, 0xA9, 0xB3, 0xDC, 0x09, 0x2C, 0x80, 0x1D, 0x5E, 0x15, 0x81, 0x16, 0xA0, 0x1A, 0xE8, 0xDC, 0x57, 0x64, 0xDD, 0xB3, 0x8B, 0x18, 0xC0, 0xEB, 0x53, 0x0C, 0xAE, 0x80, 0x1A, 0xE0, 0xBE, 0xAF, 0x0C, 0x8D, 0x96, 0x68, 0x58, 0xF6, 0x9C, 0x31, 0xE8, 0x07, 0x2E, 0xF8, 0x37, 0xD3, 0x10, 0x2F, 0xB1, 0x46, 0x8A, 0x68, 0x0E, 0xD4, 0x53, 0x47, 0xAE, 0x24, 0x3F, 0x03, 0xEA, 0x3A, 0x7D, 0xEB, 0xDB, 0x7F, 0xF3, 0xC0, 0x12, 0xB5, 0x2B, 0xFF, 0xD8, 0x56, 0x31, 0x25, 0x70, 0x76, 0xD4, 0xD6, 0xE0, 0x53, 0xC9, 0xAD, 0xBA, 0xD2, 0x8A, 0x9F, 0xC5, 0x26, 0xA1, 0xE6, 0xCE, 0x6D, 0x5E, 0x32, 0x98, 0xC7, 0x20, 0xB0, 0xC4, 0x42, 0x9F, 0x64, 0x8E, 0x23, 0x3C, 0xE6, 0x5F, 0xCB, 0xBA, 0x19, 0xA0, 0xB1, 0x18, 0x20, 0x8B, 0x97, 0xFB, 0x45, 0x07, 0xC0, 0x87, 0x56, 0xAC, 0xAC, 0xFC, 0xC1, 0x07, 0x48, 0x4E, 0xA4, 0x0C, 0xDA, 0xAC, 0xFE, 0xCD, 0xCF, 0xCB, 0xB9, 0x2D, 0xDF, 0x76, 0xC7, 0x4F, 0x2D, 0x2C, 0x65, 0xA6, 0x7B, 0x0D, 0xB7, 0x9F, 0x41, 0x60, 0xC1, 0xC4, 0x9B, 0x14, 0xBC, 0x45, 0xEF, 0xF1, 0xEB, 0xF2, 0x19, 0x3B, 0xF3, 0x05, 0x8B, 0x04, 0x15, 0x2B, 0x90, 0xAE, 0x5D, 0x40, 0x24, 0x1E, 0xBA, 0xEF, 0xC9, 0x7E, 0xBD, 0xF5, 0x93, 0x40, 0x1A, 0x30, 0x87, 0xD8, 0x7F, 0xF2, 0x2B, 0x66, 0xBA, 0xC7, 0xBC, 0x7E, 0xDA, 0x3E, 0xE6, 0xC7, 0x2F, 0xC9, 0x25, 0x4D, 0x74, 0x11, 0xC0, 0x21, 0xCE, 0x07, 0x09, 0xD8, 0x62, 0x7C, 0x77, 0x13, 0xBD, 0x43, 0xD3, 0x13, 0x40, 0x24, 0xA0, 0x05, 0x78, 0xED, 0x2B, 0x7F, 0xD3, 0x93, 0x37, 0x82, 0x55, 0x54, 0xD0, 0x59, 0xE5, 0xE2, 0x78, 0xFD, 0x1D, 0xA7, 0x2D, 0x7F, 0x8E, 0x4C, 0x1D, 0x81, 0xFF, 0x56, 0xE8, 0xB7, 0xFD, 0x24, 0x29, 0xB8, 0xEC, 0xBB, 0xC2, 0xE8, 0x40, 0xBE, 0x9D, 0xB2, 0x30, 0x07, 0xAF, 0x84, 0xB5, 0xA1, 0xDE, 0xC1, 0x5E, 0xE0, 0x9D, 0x77, 0xFC, 0x02, 0x54, 0x1E, 0xA7, 0xF9, 0xB3, 0xE6, 0x8B, 0xC0, 0x5C, 0xF4, 0x5B, 0xE4, 0x9F, 0xB8, 0x64, 0xDC, 0x67, 0xCF, 0x53, 0x80, 0x3A, 0x20, 0xF3, 0x89, 0xBA, 0xDB, 0xE2, 0x2C, 0xE2, 0xBF, 0x6E, 0x04, 0x72, 0xE7, 0x89, 0xF4, 0xC2, 0x03, 0x10, 0x07, 0x8C, 0x4E, 0x01, 0x7B, 0xAC, 0xC6, 0x1B, 0xC1, 0x16, 0xC4, 0x07, 0xF2, 0xAB, 0xEA, 0xE4, 0x6B, 0x35, 0x39, 0x5D, 0xFF, 0x90, 0xA8, 0x56, 0x2B, 0x52, 0x0A, 0xFF, 0x6D, 0xFF, 0x67, 0x6A, 0x47, 0x72, 0x41, 0xB1, 0x62, 0xB9, 0x09, 0xEC, 0xA4, 0x06, 0x08, 0xE5, 0x5B, 0x84, 0xC9, 0x99, 0xB0, 0x13, 0x11, 0x9C, 0x77, 0x09, 0x50, 0x4F, 0x82, 0x97, 0x7B, 0x46, 0xD5, 0xB2, 0x98, 0xD2, 0xCD, 0xC3, 0xC6, 0xA5, 0x34, 0x60, 0x09, 0xF8, 0xC2, 0x1C, 0x10, 0x01, 0x8E, 0x2D, 0xCE, 0xC2, 0x3E, 0x65, 0x3F, 0x0E, 0x78, 0xDD, 0x03, 0x90, 0xAF, 0x44, 0x02, 0xEA, 0xC0, 0xF3, 0x4A, 0xD0, 0x6A, 0x73, 0xAE, 0xE4, 0x48, 0x93, 0xC0, 0x22, 0x9C, 0x57, 0x55, 0xC6, 0x58, 0xC5, 0xCF, 0x78, 0xB2, 0x75, 0x54, 0x09, 0x8B, 0x06, 0x67, 0xA8, 0xF7, 0x65, 0x35, 0xDE, 0x65, 0x44, 0x9E, 0x75, 0x94, 0x7E, 0x6E, 0x89, 0x37, 0x65, 0xC1, 0x9F, 0xCE, 0x94, 0xCA, 0xC4, 0xB0, 0x06, 0x24, 0x80, 0xF2, 0x37, 0xCF, 0x6F, 0x85, 0x0B, 0x39, 0xC8, 0x8A, 0x05, 0xA3, 0xBC, 0x4A, 0xBF, 0x97, 0x49, 0xA0, 0xE3, 0x3F, 0xB2, 0xFE, 0xCE, 0x2C, 0x6C, 0xA1, 0x8B, 0x00, 0x5C, 0xFE, 0x2B, 0x8D, 0xA8, 0x00, 0xBE, 0x12, 0xFD, 0x89, 0x4B, 0x25, 0x5F, 0x79, 0xAC, 0x86, 0x3B, 0x41, 0x88, 0xA3, 0xF3, 0x5E, 0xFA, 0x36, 0xA6, 0xF3, 0xFB, 0x08, 0x32, 0xC6, 0x15, 0x17, 0x8B, 0x54, 0xDB, 0x25, 0xA4, 0xA3, 0xD7, 0x49, 0x0D, 0x21, 0x4C, 0x46, 0x05, 0xB6, 0xDA, 0x5A, 0x99, 0x5F, 0x05, 0x18, 0x2F, 0xE9, 0x87, 0x3A, 0xED, 0x7B, 0x84, 0xE5, 0xE4, 0x2D, 0x00, 0x07, 0x5A, 0xD8, 0x82, 0xE5, 0x18, 0x98, 0xB5, 0x49, 0x8D, 0x3A, 0xB6, 0xA3, 0xE5, 0x89, 0xFF, 0xF2, 0x78, 0x59, 0x7F, 0xD2, 0xD1, 0x16, 0x21, 0x8B, 0x4F, 0x23, 0x6A, 0x5E, 0x93, 0xC5, 0x00, 0x2E, 0xF8, 0xE6, 0x80, 0xEA, 0x9D, 0x65, 0x62, 0x0D, 0x1C, 0x05, 0x94, 0xAF, 0xC8, 0x63, 0x34, 0xFD, 0x85, 0xA5, 0xB4, 0x0C, 0x95, 0x9B, 0xA7, 0xE1, 0xB8, 0x8F, 0xDA, 0xDE, 0x6A, 0xB1, 0x4D, 0xD5, 0xB8, 0x8B, 0xC7, 0xF6, 0xCC, 0x4B, 0x6A, 0xC0, 0x5C, 0xB5, 0x8C, 0x54, 0x95, 0x4B, 0x26, 0xAC, 0x69, 0xBC, 0xDA, 0x98, 0xB9, 0xA0, 0x9C, 0x78, 0x3E, 0xF7, 0xA3, 0xB8, 0xA4, 0x68, 0xF7, 0x1F, 0xC4, 0xF6, 0x22, 0x6F, 0xE7, 0x51, 0x79, 0x9F, 0xDA, 0xC8, 0x3D, 0x9B, 0xB6, 0xEE, 0xD4, 0xD7, 0x77, 0x9B, 0xEB, 0xC7, 0xDB, 0xAD, 0x09, 0xC8, 0x00, 0xAC, 0xC7, 0xED, 0x58, 0xC8, 0xE2, 0x2C, 0xF6, 0x4D, 0x15, 0xA0, 0xD7, 0x30, 0x3A, 0x80, 0x14, 0x1F, 0x02, 0x6E, 0x80, 0x08, 0x60, 0xB2, 0x6F, 0xC6, 0x63, 0x34, 0xFB, 0x57, 0x3F, 0x33, 0xC5, 0x96, 0xA6, 0xE2, 0x7A, 0x3E, 0x52, 0xD7, 0x19, 0x44, 0xB2, 0x71, 0x62, 0x53, 0x5D, 0x89, 0xD4, 0xBE, 0xFA, 0x7F, 0x9E, 0x03, 0xD2, 0xDD, 0x1C, 0xF1, 0x8A, 0xDA, 0xDB, 0xFA, 0x81, 0x5C, 0x3F, 0xFA, 0xA0, 0xB2, 0xC1, 0xF6, 0x79, 0x1A, 0xF7, 0x4F, 0x03, 0x67, 0x0D, 0x5A, 0x4A, 0xE5, 0x42, 0x58, 0xF2, 0x29, 0x1F, 0x4A, 0xFA, 0x80, 0x29, 0x59, 0xBA, 0xBE, 0xF2, 0x62, 0x27, 0x5F, 0x40, 0xF8, 0xE9, 0x49, 0xA6, 0x04, 0xF4, 0x00, 0xA6, 0x8B, 0x04, 0x3C, 0x80, 0x11, 0xBA, 0x90, 0xF7, 0x38, 0xE6, 0xC0, 0x99, 0x7D, 0xE8, 0x80, 0x14, 0xDE, 0xAC, 0x00, 0xA6, 0xF6, 0x15, 0xA5, 0xD1, 0xD0, 0x0E, 0xA9, 0x54, 0x31, 0x23, 0xA2, 0xE0, 0x7C, 0x9D, 0xD8, 0xB4, 0x10, 0xC6, 0xE5, 0x1C, 0x67, 0x08, 0x2B, 0x88, 0xF9, 0xE6, 0x3D, 0xD2, 0x9E, 0xDB, 0xA7, 0xBE, 0xCE, 0x63, 0x7E, 0xC1, 0x67, 0x34, 0x31, 0x29, 0xF7, 0xFC, 0xD5, 0xD9, 0xE9, 0x5A, 0x8B, 0xD2, 0xF8, 0x0D, 0x50, 0x5F, 0xD6, 0x03, 0x08, 0xFD, 0xEB, 0xE2, 0xA4, 0xF3, 0x14, 0x54, 0x65, 0xB2, 0x65, 0xC6, 0x0E, 0xFB, 0xDC, 0x25, 0xB1, 0x78, 0x75, 0x07, 0xA4, 0xEF, 0xBC, 0x8C, 0xAE, 0x85, 0x7E, 0xC0, 0xF4, 0x0C, 0x26, 0x88, 0x05, 0x10, 0x06, 0xF8, 0xF3, 0x90, 0x9D, 0x67, 0x00, 0x49, 0xC0, 0x1C, 0x3F, 0xB3, 0xA2, 0xD1, 0xE2, 0x57, 0x27, 0xAD, 0xD2, 0x1B, 0x60, 0x98, 0xF7, 0xB2, 0xEE, 0x5D, 0x89, 0xF9, 0xB1, 0x7E, 0x1C, 0xC4, 0x0B, 0x74, 0x0B, 0x6B, 0xD9, 0x71, 0x80, 0xEA, 0x07, 0x94, 0xEC, 0xE6, 0x82, 0x4C, 0xF9, 0x31, 0x36, 0x6A, 0x42, 0x1E, 0x11, 0x4A, 0xD3, 0x03, 0x90, 0xDA, 0x87, 0x2C, 0x31, 0xEE, 0xA7, 0x9D, 0xFA, 0xA3, 0x4C, 0xE5, 0xBB, 0x7F, 0xB8, 0xAC, 0x05, 0x13, 0x56, 0xA2, 0xA4, 0xB9, 0xE6, 0x73, 0x83, 0xA2, 0x9C, 0x29, 0x75, 0xD5, 0x72, 0x00, 0xB7, 0xBB, 0x8F, 0x6F, 0xCF, 0x22, 0x6E, 0x4C, 0xEE, 0x9B, 0xC2, 0x90, 0x05, 0x90, 0x0E, 0x44, 0x00, 0x6A, 0x78, 0xA5, 0x1C, 0xB0, 0x02, 0x9E, 0x64, 0x31, 0xA1, 0xCD, 0x12, 0xA2, 0x02, 0x23, 0x1B, 0xD1, 0x12, 0xB8, 0x93, 0x65, 0x3D, 0x8D, 0x11, 0x08, 0x25, 0x59, 0xC1, 0xE7, 0x2A, 0xF0, 0x0D, 0xB9, 0xD8, 0xEF, 0x67, 0x73, 0x17, 0xB1, 0x50, 0x97, 0xAF, 0x58, 0x87, 0x11, 0xF5, 0x0A, 0xD7, 0xEC, 0x41, 0x36, 0xE8, 0xE8, 0x66, 0xB9, 0x3B, 0xC2, 0x46, 0x2C, 0xF2, 0x84, 0xA3, 0xD2, 0x81, 0x56, 0x80, 0x25, 0x2D, 0x23, 0xAF, 0xF6, 0xB9, 0xC2, 0x20, 0x5A, 0x7B, 0x8B, 0xD7, 0xC7, 0x27, 0xD9, 0xC9, 0x34, 0x4C, 0x7C, 0xD2, 0x04, 0xDC, 0x17, 0x01, 0x84, 0x2F, 0x06, 0xC0, 0x84, 0x3F, 0xCF, 0x21, 0xE8, 0x14, 0x10, 0x03, 0x78, 0x02, 0xF2, 0xD4, 0x04, 0xF2, 0x4D, 0xC0, 0x63, 0xDF, 0x0C, 0xDA, 0xAC, 0xF0, 0xC7, 0xCF, 0x60, 0x19, 0xBF, 0x6A, 0x67, 0x01, 0x48, 0xD4, 0x24, 0xF2, 0xE7, 0x35, 0x03, 0x5A, 0x04, 0x5A, 0xFF, 0x94, 0x87, 0xFF, 0x27, 0x71, 0xEC, 0x30, 0x93, 0x1C, 0x97, 0xC7, 0xCD, 0x4C, 0xCA, 0x0D, 0xA8, 0xD7, 0xFE, 0xA3, 0xF6, 0x26, 0xB0, 0xD7, 0x96, 0xB0, 0xD4, 0xB6, 0xC4, 0xAA, 0x5D, 0x59, 0x6A, 0x43, 0x05, 0x09, 0x4F, 0xEC, 0x36, 0x94, 0x7F, 0x75, 0x07, 0x75, 0x97, 0xC5, 0x78, 0x16, 0x42, 0x66, 0x8E, 0x9F, 0xDD, 0x2F, 0x98, 0x7C, 0x94, 0x0D, 0x84, 0x01, 0x16, 0x80, 0xE4, 0xC2, 0x17, 0x0A, 0xE8, 0x01, 0x4A, 0xF0, 0xEB, 0x6C, 0xFB, 0x73, 0xF6, 0xD3, 0x1C, 0x80, 0xFF, 0x95, 0x71, 0x20, 0x0A, 0x28, 0x63, 0x11, 0x12, 0x6D, 0xD6, 0x90, 0x50, 0xD1, 0x7E, 0x4F, 0xB3, 0x2E, 0x63, 0x28, 0x1B, 0xEF, 0x59, 0xBD, 0xF6, 0x81, 0x7F, 0xA1, 0x75, 0x05, 0x64, 0x51, 0x68, 0x5C, 0xB0, 0x99, 0x0A, 0xC0, 0xFC, 0xFE, 0x11, 0xB6, 0x93, 0xB9, 0x9C, 0x8F, 0x85, 0x99, 0x9A, 0xEB, 0x15, 0xA3, 0xEE, 0x43, 0x50, 0x78, 0xAA, 0x1F, 0xD1, 0xDE, 0x4E, 0xC0, 0xD8, 0xE8, 0x95, 0x0D, 0x62, 0x1B, 0xC6, 0xE2, 0x8E, 0x62, 0x6C, 0x79, 0xF4, 0x89, 0x3D, 0xF3, 0x66, 0x56, 0xB5, 0xA3, 0x4E, 0x80, 0x63, 0xB7, 0x58, 0x9D, 0x19, 0xA0, 0x01, 0xD8, 0x01, 0x4A, 0xEF, 0x11, 0xD9, 0x05, 0xD4, 0xC2, 0x1B, 0x38, 0xE7, 0x9A, 0xB7, 0x4C, 0x10, 0x78, 0x6D, 0x36, 0x70, 0xBF, 0xF4, 0x15, 0xB4, 0x9B, 0x30, 0xE1, 0x27, 0x48, 0x8A, 0xB8, 0x63, 0x7D, 0x39, 0x5B, 0xD0, 0x8E, 0x4C, 0x22, 0x1A, 0xCB, 0x02, 0x60, 0x74, 0xFB, 0x69, 0x1E, 0xA0, 0xB3, 0xC6, 0x5A, 0xFD, 0xCF, 0x18, 0x54, 0x29, 0x9A, 0x02, 0xAE, 0xDB, 0x98, 0x7A, 0xA5, 0x3E, 0x27, 0x80, 0xDE, 0x87, 0x5A, 0xF8, 0xA4, 0xAB, 0x4F, 0x11, 0xB6, 0x1D, 0x25, 0xFB, 0x5D, 0xEB, 0xE8, 0x1F, 0xF2, 0xED, 0x51, 0xB4, 0xF7, 0x67, 0x85, 0x09, 0xAE, 0xDC, 0xE8, 0x2E, 0xC0, 0x3E, 0x9D, 0x69, 0x4E, 0x02, 0x12, 0x77, 0x2F, 0x08, 0x17, 0xA0, 0x0B, 0xA8, 0x04, 0x7C, 0x5F, 0x99, 0x04, 0x52, 0x80, 0xE6, 0x9B, 0x03, 0x9B, 0x15, 0x9D, 0xA9, 0xAF, 0x77, 0xFB, 0xC6, 0xAE, 0xD0, 0x3D, 0xAB, 0xF4, 0x93, 0x68, 0x0D, 0x9A, 0xC8, 0xBE, 0xAA, 0x3B, 0x3D, 0x0C, 0xA6, 0xE3, 0x06, 0x4F, 0x25, 0xED, 0xDA, 0xFD, 0xA8, 0xB7, 0x1A, 0xB6, 0x7F, 0xBF, 0x0E, 0xC4, 0x66, 0x2A, 0xF9, 0xFE, 0x6C, 0x7E, 0xD8, 0x2B, 0x41, 0xB3, 0xA7, 0xF7, 0xEA, 0x1C, 0xD7, 0x26, 0x64, 0xE5, 0x9E, 0x83, 0x53, 0x77, 0xC2, 0xE6, 0x53, 0xF9, 0xA8, 0x6B, 0x48, 0x5B, 0x7F, 0x52, 0x51, 0xBD, 0xBC, 0x01, 0xAA, 0x9E, 0xB7, 0x03, 0x95, 0x0B, 0x03, 0xD8, 0x3A, 0xCF, 0xA9, 0xFB, 0x54, 0x40, 0x19, 0x90, 0x09, 0xF8, 0x01, 0xCE, 0xBE, 0x59, 0xFB, 0x90, 0x52, 0x90, 0xA7, 0x69, 0x33, 0x81, 0x3C, 0xC1, 0xDB, 0x25, 0xEF, 0x2A, 0xCA, 0x13, 0x47, 0xD4, 0xB1, 0x07, 0x5A, 0x95, 0xE2, 0x2B, 0xC4, 0x06, 0x07, 0x64, 0xBE, 0x87, 0x0C, 0x64, 0x75, 0x33, 0xA0, 0xBF, 0x07, 0x89, 0x59, 0x75, 0xA4, 0xD9, 0x41, 0x94, 0x58, 0xB3, 0x72, 0x01, 0xBB, 0x50, 0xBA, 0xA6, 0x31, 0xB9, 0x72, 0xD3, 0x70, 0x73, 0x75, 0x2C, 0x53, 0x61, 0xF9, 0xA0, 0x28, 0x26, 0x0F, 0x76, 0xF5, 0xF4, 0xFB, 0xE1, 0xFF, 0x21, 0x73, 0xD5, 0x29, 0xA8, 0x29, 0xCF, 0xF6, 0x19, 0x7D, 0x37, 0x2E, 0x8B, 0x03, 0xF8, 0xC2, 0x0A, 0xF0, 0x01, 0xE6, 0xD3, 0x87, 0xEC, 0x30, 0x76, 0xD8, 0x40, 0x09, 0x60, 0x06, 0x9C, 0x02, 0x58, 0x88, 0xAA, 0x4A, 0x9B, 0xE9, 0xBF, 0x09, 0xC4, 0xEB, 0xA0, 0x8E, 0x5B, 0xEB, 0xA2, 0x16, 0x74, 0xE0, 0x8C, 0x46, 0x6E, 0x42, 0xE4, 0xA6, 0xBA, 0x3A, 0xC6, 0x52, 0x08, 0xEF, 0xE8, 0x77, 0x78, 0x5D, 0x29, 0x30, 0xE2, 0x3B, 0xE0, 0x28, 0x87, 0x29, 0x9F, 0x15, 0xC6, 0xB8, 0xED, 0xEB, 0x5B, 0xB1, 0xC9, 0xC3, 0xAA, 0xEE, 0x43, 0x66, 0x51, 0xEE, 0xD7, 0xA6, 0x94, 0x41, 0xAF, 0x57, 0x21, 0xFF, 0x02, 0x44, 0x4D, 0x77, 0xF6, 0xA7, 0xB8, 0xE2, 0x00, 0x3E, 0x40, 0x12, 0xB1, 0xB0, 0x85, 0x2F, 0x9A, 0x39, 0x53, 0x40, 0xFA, 0x1D, 0xBA, 0x1A, 0xE3, 0x43, 0x80, 0x57, 0xD8, 0xF9, 0xE4, 0x4D, 0xF6, 0x1C, 0x5A, 0xCD, 0x90, 0x2E, 0x34, 0xBD, 0x4A, 0x36, 0x06, 0x6B, 0xB7, 0xFC, 0x7E, 0xFD, 0xC0, 0x8D, 0x76, 0x44, 0x66, 0xBD, 0x69, 0x8D, 0x1B, 0x8C, 0x32, 0x30, 0xF0, 0xC9, 0x86, 0x64, 0x16, 0x45, 0xD8, 0x79, 0x53, 0x6E, 0xFA, 0x59, 0x58, 0x2B, 0x01, 0x8D, 0xD7, 0x7F, 0x96, 0x4F, 0x42, 0xAC, 0x3A, 0x2B, 0x3D, 0x81, 0xC9, 0x45, 0xC3, 0xA2, 0x7E, 0x27, 0xD9, 0x6A, 0xBC, 0x1D, 0xB3, 0xE3, 0x29, 0x05, 0x68, 0x7E, 0xED, 0x82, 0x61, 0x45, 0x80, 0xFE, 0xA1, 0xEE, 0xCC, 0xFA, 0xAB, 0xE1, 0xF6, 0x82, 0x4D, 0xF6, 0xE9, 0xA6, 0x3C, 0x72, 0xA7, 0xF7, 0x45, 0x02, 0xFC, 0xF5, 0x32, 0x60, 0x74, 0x5F, 0x89, 0xC7, 0x6A, 0x94, 0x1D, 0xC2, 0x72, 0xD2, 0xC7, 0x76, 0xD7, 0x8B, 0xD7, 0xC3, 0x71, 0x5C, 0x0B, 0x31, 0x7B, 0x73, 0xFC, 0x1F, 0x5A, 0x2F, 0x0F, 0x47, 0xD8, 0x5A, 0x8D, 0x51, 0x57, 0xBA, 0x49, 0x9B, 0x09, 0xEF, 0xC9, 0x9C, 0xA0, 0xFD, 0x64, 0x38, 0x88, 0xC3, 0x78, 0xF3, 0xFC, 0x19, 0x93, 0x40, 0x0E, 0x30, 0x4C, 0x9F, 0x38, 0xFC, 0x83, 0xEF, 0x44, 0xB5, 0x3A, 0x6F, 0x50, 0x48, 0x1F, 0xC8, 0x00, 0x66, 0x9F, 0xD4, 0x78, 0xFB, 0x04, 0xD6, 0x6D, 0xA1, 0xF7, 0xE0, 0xB4, 0xF3, 0x49, 0x8D, 0x0F, 0x40, 0x95, 0xA3, 0xEB, 0xA3, 0x38, 0xD1, 0x1F, 0xC5, 0x09, 0x7F, 0xAC, 0x16, 0xBF, 0x65, 0xD7, 0x4B, 0xA0, 0xEC, 0x1F, 0x81, 0xA1, 0xD2, 0x8E, 0xF6, 0x88, 0xE2, 0x70, 0x99, 0x56, 0xFD, 0xD0, 0x6C, 0x04, 0xED, 0xFA, 0x1F, 0x39, 0xA4, 0x0C, 0x0E, 0xE5, 0x30, 0x40, 0xCF, 0x8A, 0xBB, 0xDD, 0x90, 0x58, 0x5C, 0xAC, 0xD4, 0xC4, 0x61, 0x27, 0x9F, 0xB7, 0xDC, 0xFE, 0x39, 0x95, 0xF6, 0x5F, 0x2E, 0xF5, 0x3A, 0xF2, 0xE9, 0x4D, 0x13, 0xFF, 0xBB, 0x20, 0xCD, 0x33, 0x66, 0x28, 0x4B, 0x1F, 0x05, 0xB0, 0x04, 0xE6, 0xF1, 0x69, 0x27, 0x50, 0x8F, 0x80, 0x89, 0x03, 0x52, 0x80, 0x0E, 0x50, 0x72, 0x97, 0x39, 0x76, 0x00, 0x55, 0x80, 0x2F, 0xCE, 0xE3, 0xE1, 0x06, 0x3A, 0xF7, 0x4D, 0xA5, 0xD5, 0x10, 0x23, 0x48, 0x4D, 0x38, 0xF2, 0x1B, 0xEA, 0x42, 0x25, 0x89, 0x94, 0xD7, 0x98, 0x9F, 0x9F, 0x5C, 0x0E, 0xDA, 0xD6, 0x54, 0x6E, 0x23, 0x96, 0x18, 0xE6, 0x70, 0x7C, 0x8A, 0x57, 0xEC, 0x2D, 0x05, 0x63, 0xE0, 0x82, 0x95, 0x89, 0xAA, 0x8F, 0xF4, 0xC0, 0xCC, 0x3E, 0x64, 0x46, 0xE9, 0xDC, 0x85, 0xE5, 0xE2, 0x40, 0x31, 0xCB, 0xC5, 0xDF, 0x4B, 0x91, 0xEF, 0x04, 0xDF, 0xF5, 0x78, 0x1E, 0x27, 0xC5, 0xD3, 0x4E, 0xF5, 0x2C, 0x98, 0x5D, 0x9B, 0x40, 0xF9, 0x2D, 0x32, 0x21, 0xBA, 0x68, 0x40, 0x0B, 0xC8, 0xB8, 0x3D, 0x42, 0xD5, 0x40, 0x26, 0x60, 0x79, 0xFB, 0x87, 0xA2, 0x80, 0xE7, 0x95, 0xBF, 0x19, 0x5A, 0xBF, 0x63, 0xD1, 0xB8, 0xE0, 0xA4, 0x7D, 0x02, 0x51, 0x1E, 0xC5, 0xFA, 0x7F, 0x72, 0xAF, 0x72, 0x32, 0xEB, 0xD6, 0xEF, 0xED, 0x54, 0xA4, 0x97, 0x16, 0x69, 0x7D, 0xAA, 0xDA, 0x53, 0xCE, 0xDD, 0xD9, 0xA2, 0x9A, 0xCD, 0x5A, 0x16, 0xDC, 0xAF, 0x9C, 0x5D, 0x25, 0xEF, 0x83, 0xB7, 0x1B, 0x90, 0x5F, 0xFD, 0x93, 0xCD, 0x40, 0xD5, 0x1F, 0xE4, 0xA9, 0xE2, 0xAF, 0x79, 0xA3, 0x4B, 0xF0, 0x33, 0x02, 0x74, 0x4B, 0x04, 0xAB, 0xBC, 0x01, 0x6F, 0xA0, 0x1C, 0xE8, 0xFC, 0xC4, 0xF0, 0x18, 0xAE, 0xB3, 0x4F, 0x41, 0xC1, 0x00, 0x5A, 0xB7, 0x86, 0x80, 0x15, 0x10, 0xBE, 0xAF, 0x24, 0x8D, 0xD6, 0xBF, 0x03, 0xD8, 0x18, 0x86, 0x9A, 0xC7, 0xAC, 0xD7, 0xD9, 0xAF, 0xB4, 0x04, 0x89, 0xFC, 0xC1, 0x8F, 0x6D, 0x7D, 0xF5, 0xE0, 0x9E, 0xFE, 0x1F, 0x29, 0xA4, 0x74, 0x0C, 0xB1, 0x97, 0xC0, 0x79, 0x76, 0xF0, 0xD8, 0x2D, 0xBF, 0x2F, 0x97, 0x05, 0xB3, 0x37, 0x30, 0x07, 0xB7, 0x14, 0x17, 0x60, 0x77, 0x1F, 0x0A, 0xE8, 0x50, 0x8F, 0xDA, 0x58, 0x3F, 0x91, 0x77, 0x6D, 0xDA, 0x11, 0x8E, 0x91, 0xDD, 0x6B, 0xE9, 0x04, 0xDE, 0x57, 0x3A, 0xD7, 0xAE, 0x0C, 0xC2, 0x1D, 0xC0, 0x06, 0x08, 0xD6, 0xBB, 0xCD, 0x7D, 0x7B, 0x0F, 0x01, 0xAC, 0x81, 0xA7, 0xF6, 0xC4, 0xD6, 0xCA, 0x6C, 0x0D, 0x40, 0x2B, 0x3F, 0x46, 0x9B, 0x5F, 0x9A, 0xF2, 0xB0, 0x11, 0x02, 0x37, 0xC0, 0x51, 0xD4, 0xA7, 0xC6, 0x0F, 0x9D, 0xBB, 0xB8, 0x85, 0xD8, 0xA6, 0x34, 0xCA, 0xDD, 0x00, 0x7A, 0x3E, 0x91, 0x95, 0x62, 0x88, 0x9D, 0xC1, 0x3C, 0xB6, 0x7B, 0xD2, 0x01, 0x64, 0xCD, 0x15, 0x6C, 0x31, 0xD9, 0x30, 0x50, 0x3F, 0x5A, 0x62, 0x6B, 0xED, 0x5D, 0xEA, 0xE8, 0x75, 0xE4, 0xDF, 0x6D, 0xCD, 0x0E, 0x40, 0x57, 0x7A, 0x29, 0xCB, 0xC9, 0x42, 0x00, 0xA9, 0xFB, 0x53, 0x3A, 0x10, 0xB1, 0xA8, 0x1B, 0xA9, 0x77, 0x51, 0x72, 0x3E, 0x05, 0xF3, 0x77, 0x1B, 0xFE, 0x54, 0x40, 0xE2, 0x4D, 0xFB, 0x65, 0xC8, 0x28, 0xDF, 0x1D, 0x54, 0x70, 0x2E, 0x17, 0x11, 0x5C, 0x93, 0x76, 0x2F, 0xC8, 0x14, 0x94, 0x3F, 0xB8, 0xC0, 0x5C, 0x31, 0x38, 0xBE, 0x26, 0xFC, 0x44, 0xB2, 0x5A, 0xC1, 0xF2, 0x11, 0x58, 0xF6, 0x79, 0xF7, 0x78, 0xFD, 0xBB, 0xE1, 0xCC, 0x1E, 0x39, 0x85, 0x57, 0x61, 0xC5, 0x43, 0x9B, 0xB7, 0x21, 0x99, 0x71, 0xDD, 0x5B, 0x4B, 0xB2, 0xBB, 0x27, 0xB5, 0x48, 0x36, 0x6A, 0xCC, 0xE9, 0xC6, 0x96, 0x8D, 0xF3, 0x74, 0xDE, 0x4B, 0xFD, 0xF4, 0x24, 0xC9, 0xFB, 0x68, 0x31, 0xC3, 0x43, 0x1E, 0x60, 0x05, 0xB8, 0x01, 0xA1, 0xC0, 0x70, 0x35, 0xD3, 0x4F, 0x43, 0xCD, 0x93, 0x78, 0x78, 0xEE, 0x7C, 0x1A, 0xDE, 0xAB, 0x1F, 0xC7, 0xFF, 0x51, 0x1A, 0x4D, 0xE0, 0x61, 0xF0, 0xDC, 0xEE, 0x5D, 0x57, 0x1D, 0x63, 0x85, 0xEC, 0xEA, 0x50, 0xB3, 0x69, 0xCA, 0x81, 0xE3, 0xEF, 0xB6, 0xC7, 0xAB, 0xDB, 0x07, 0xC9, 0xBA, 0x70, 0xE6, 0x7C, 0x52, 0xEE, 0x32, 0x9E, 0xCE, 0x60, 0x63, 0x40, 0xB1, 0xE9, 0x66, 0xEE, 0x05, 0x72, 0xE7, 0xAE, 0x30, 0x3B, 0x86, 0x19, 0x7F, 0xB8, 0x39, 0x2E, 0x6C, 0x4D, 0x4F, 0x29, 0xEF, 0xDA, 0xDD, 0x6D, 0x3B, 0xFA, 0x3C, 0x0D, 0x1C, 0xD7, 0xEF, 0x20, 0x1C, 0x9A, 0xB2, 0xD0, 0xA7, 0xB0, 0x68, 0x84, 0xDB, 0x2F, 0xA0, 0x01, 0x58, 0x03, 0x6D, 0x6F, 0x94, 0x30, 0x9E, 0xE2, 0xC0, 0x31, 0x20, 0x15, 0x10, 0xC3, 0x9B, 0xD5, 0xC0, 0xD4, 0xBE, 0xE2, 0x34, 0x9A, 0x62, 0x35, 0xAB, 0xC1, 0x37, 0xA2, 0x41, 0xE5, 0x56, 0x28, 0xF5, 0x8E, 0x1F, 0xE2, 0x34, 0x06, 0x4C, 0xF9, 0xA5, 0x7A, 0xAB, 0x40, 0xFA, 0x25, 0x9F, 0x50, 0x8F, 0x36, 0x02, 0x95, 0x12, 0x22, 0x00, 0xB4, 0x6F, 0x9E, 0xC5, 0xDE, 0x85, 0x9F, 0x0E, 0xFB, 0xF6, 0xE9, 0xB1, 0x2C, 0x4F, 0x42, 0x9B, 0xD9, 0x5D, 0x9E, 0x6C, 0xB5, 0x33, 0x57, 0x5E, 0xE1, 0xFD, 0x7C, 0xEA, 0xBE, 0xE9, 0x25, 0xB3, 0x66, 0x31, 0x20, 0x85, 0x8E, 0xF9, 0xEF, 0x07, 0xB8, 0x03, 0xF8, 0x59, 0x3E, 0x71, 0x1F, 0x4D, 0xA0, 0x05, 0x28, 0x05, 0x7C, 0x97, 0x96, 0x6E, 0x20, 0x04, 0xE0, 0xCF, 0xBA, 0x68, 0xB3, 0x6D, 0xA8, 0x32, 0xBD, 0xFF, 0x2A, 0xF2, 0x0E, 0xB4, 0x88, 0xB2, 0xD5, 0xCC, 0xCB, 0x6D, 0xDA, 0x9B, 0xC8, 0xBB, 0xB0, 0xFC, 0xA7, 0x8F, 0x9E, 0xA6, 0x34, 0xD0, 0xB4, 0x35, 0xAF, 0x69, 0x03, 0x4F, 0x18, 0xCC, 0x13, 0xEB, 0xA4, 0x89, 0x57, 0x8A, 0xC8, 0x5F, 0x81, 0x51, 0xB6, 0x42, 0xC7, 0x1E, 0x81, 0x08, 0x3F, 0xE5, 0x38, 0x7D, 0x5D, 0x98, 0xFA, 0xE6, 0x72, 0xC4, 0xE3, 0xF4, 0x2A, 0x7E, 0x23, 0x87, 0x5D, 0x82, 0xD1, 0xE8, 0xB3, 0x56, 0x2A, 0x20, 0x02, 0xC8, 0x04, 0xAA, 0x80, 0x16, 0x60, 0xD6, 0x90, 0x56, 0xB7, 0xF3, 0xC3, 0x1B, 0xE0, 0x43, 0x39, 0x77, 0x33, 0x63, 0x0B, 0x80, 0xA6, 0xF3, 0xA4, 0xCD, 0x7C, 0xBB, 0x4A, 0x39, 0xA6, 0x8C, 0xCF, 0xFF, 0x8A, 0x0F, 0x4D, 0x16, 0x8A, 0x4E, 0x1A, 0xF3, 0x57, 0xEC, 0x16, 0x6C, 0xF2, 0x5B, 0xB8, 0xAF, 0xFB, 0xF0, 0xA4, 0xC1, 0x16, 0x4C, 0x30, 0x5D, 0x08, 0xC0, 0x0C, 0x3F, 0x9F, 0x75, 0x1C, 0x24, 0xEC, 0x72, 0x56, 0x26, 0xDB, 0xCF, 0xDB, 0x17, 0x37, 0xF0, 0x33, 0x93, 0xBF, 0xAE, 0xEA, 0xB3, 0x76, 0xC9, 0xF7, 0x30, 0x8C, 0x91, 0xBC, 0xFB, 0x39, 0xC0, 0xE3, 0x00, 0x5D, 0xD7, 0xF4, 0xE9, 0x9A, 0x02, 0x95, 0xC0, 0x38, 0xE3, 0xD4, 0x40, 0xFA, 0xBB, 0x80, 0xE2, 0xDF, 0x16, 0x7B, 0xD0, 0x00, 0xB1, 0x6F, 0x4E, 0x03, 0x11, 0x77, 0xD1, 0x52, 0x1B, 0x6D, 0x16, 0x68, 0x99, 0x9A, 0x83, 0x3F, 0x29, 0xEB, 0xBD, 0x40, 0x89, 0x74, 0xE0, 0x92, 0xBF, 0x6E, 0xB5, 0xF2, 0x80, 0xF7, 0x7E, 0xE8, 0x41, 0xFB, 0xC1, 0x0C, 0x18, 0x2E, 0x92, 0xB0, 0x19, 0x07, 0x11, 0xAE, 0xC2, 0x97, 0xBA, 0xBF, 0xCC, 0x7A, 0x63, 0xF7, 0x67, 0xCC, 0xB1, 0xC5, 0xA8, 0x63, 0x0F, 0x9A, 0xF5, 0x33, 0x7A, 0xEC, 0xA7, 0xB5, 0xB5, 0xF5, 0x7A, 0x2F, 0x7C, 0x3D, 0xDF, 0x02, 0x4B, 0xA0, 0xDE, 0x9E, 0x2B, 0x1F, 0xE0, 0xF2, 0x3E, 0xC4, 0xBF, 0x0A, 0x82, 0x3F, 0x06, 0x50, 0x7D, 0xFE, 0x2C, 0xB4, 0x81, 0x62, 0xF7, 0x75, 0x36, 0x40, 0x55, 0x7C, 0x9A, 0x45, 0xCA, 0xDD, 0xED, 0xBD, 0x9F, 0x56, 0xEE, 0xFB, 0x66, 0xD2, 0x66, 0x89, 0xB9, 0xD2, 0xB6, 0x1D, 0xB8, 0x13, 0x3D, 0xEC, 0x3E, 0x4D, 0xCC, 0x3A, 0x7A, 0xFF, 0x32, 0xDB, 0x06, 0xE9, 0x7A, 0x67, 0x29, 0x03, 0x3C, 0x2D, 0x0F, 0x5D, 0x83, 0xB2, 0xAE, 0x2C, 0xF6, 0xF0, 0x28, 0x65, 0x43, 0xE2, 0xF5, 0xF1, 0x9C, 0xB5, 0xCB, 0x8A, 0xDE, 0xB3, 0xBD, 0x55, 0xD6, 0xAD, 0x51, 0xC7, 0x1E, 0xCB, 0xC6, 0xBF, 0x33, 0xDE, 0x06, 0xFF, 0x8E, 0x37, 0xA9, 0x0F, 0x06, 0x8F, 0x00, 0xC0, 0x18, 0x40, 0x9D, 0x7B, 0x10, 0x49, 0x00, 0x3E, 0x40, 0x06, 0xD0, 0xB6, 0x27, 0xEF, 0x9D, 0xD3, 0x5A, 0x40, 0x2B, 0x50, 0x02, 0x58, 0xE2, 0x95, 0x16, 0xC0, 0x17, 0xC9, 0x57, 0x8A, 0x36, 0xAB, 0xDD, 0x0E, 0x13, 0x03, 0xA5, 0xBF, 0x73, 0x93, 0xDF, 0x2F, 0x57, 0x8F, 0x76, 0xB6, 0x1D, 0x49, 0xFF, 0xE2, 0x03, 0xF3, 0xAA, 0xB6, 0x62, 0x24, 0x3E, 0xD7, 0x9C, 0xC7, 0xE9, 0x95, 0x9B, 0xCA, 0x52, 0x7B, 0x22, 0xAD, 0x75, 0x09, 0xA1, 0x0D, 0x37, 0xFC, 0x93, 0xB2, 0x9E, 0xDA, 0x88, 0xB7, 0xA7, 0x13, 0x8E, 0xA2, 0x70, 0x37, 0xFA, 0xDB, 0xA5, 0x88, 0x7A, 0x6B, 0xE7, 0xE9, 0x8B, 0x28, 0xC6, 0x31, 0x78, 0x77, 0xE6, 0x61, 0x46, 0xD6, 0x9C, 0xBB, 0xB1, 0x58, 0xAF, 0xF3, 0xD1, 0x16, 0xD1, 0x00, 0x5B, 0x3A, 0xDB, 0x2E, 0x10, 0x6A, 0x40, 0x9D, 0x8F, 0x0F, 0x52, 0x80, 0xA3, 0x77, 0x8F, 0xC6, 0xC9, 0x5D, 0x69, 0x85, 0x36, 0xFB, 0xCB, 0x18, 0x9A, 0x5F, 0xFA, 0x62, 0xAD, 0xEF, 0xB9, 0xDF, 0xEA, 0x62, 0xB1, 0x38, 0x5B, 0x27, 0xEB, 0x3F, 0xEF, 0x9A, 0xE0, 0x67, 0x4E, 0xCF, 0x90, 0xDF, 0x6D, 0x65, 0x99, 0x92, 0x99, 0x8F, 0xCB, 0xE2, 0xF0, 0xC8, 0xD4, 0x80, 0xCB, 0xED, 0x17, 0xAB, 0x05, 0xF3, 0x28, 0x98, 0xD7, 0xAE, 0xBE, 0xB8, 0xB4, 0xD2, 0x15, 0x6F, 0xBE, 0x69, 0x97, 0x23, 0x40, 0xCC, 0xE2, 0x5B, 0xEB, 0xA3, 0x4C, 0xDF, 0xB8, 0x21, 0x67, 0xA1, 0x8B, 0x02, 0xFE, 0x24, 0x81, 0x81, 0x2C, 0x20, 0x3E, 0x2A, 0x00, 0xB5, 0xF0, 0xF3, 0xD1, 0x87, 0xB4, 0x43, 0xAB, 0xCD, 0x65, 0xB5, 0x69, 0x41, 0x1B, 0x1C, 0x0B, 0x04, 0x0A, 0x54, 0x61, 0xB5, 0x34, 0x54, 0x5C, 0x7A, 0xA2, 0xAF, 0xDD, 0x28, 0x3D, 0x42, 0x77, 0xEE, 0x8B, 0xD8, 0xA7, 0xC3, 0xF8, 0x3A, 0x88, 0xCA, 0x17, 0x57, 0xCF, 0xAD, 0x7A, 0x4A, 0x8E, 0x8A, 0xC6, 0x6B, 0xC0, 0x14, 0x10, 0x66, 0xD0, 0x5C, 0xDD, 0x08, 0x11, 0xB7, 0xBB, 0x4A, 0xB3, 0xCB, 0x00, 0x0F, 0xC0, 0x1A, 0x60, 0x39, 0x67, 0x1C, 0xA0, 0x7D, 0x91, 0x8B, 0x5A, 0x34, 0x30, 0xFA, 0xC9, 0xB3, 0xAA, 0x8F, 0xAC, 0x49, 0xF1, 0xE1, 0xA7, 0xF2, 0x62, 0x61, 0xF6, 0x91, 0x35, 0x29, 0x3D, 0xBF, 0x82, 0x32, 0x75, 0xFF, 0x5D, 0x0A, 0x4C, 0x6B, 0x1B, 0xB1, 0x5F, 0x91, 0x29, 0x49, 0x74, 0xE1, 0xB5, 0x9C, 0x5C, 0x4F, 0x49, 0xDD, 0x35, 0xD9, 0x77, 0xB7, 0xCF, 0x58, 0xCB, 0x88, 0x3E, 0xE9, 0xD8, 0x15, 0xC0, 0x6C, 0xAA, 0x10, 0x4F, 0x9A, 0xF4, 0x8D, 0x53, 0x5C, 0xE2, 0xAC, 0xBF, 0x27, 0xD6, 0xB0, 0xFA, 0xCA, 0x60, 0xD0, 0x65, 0x11, 0x4F, 0xB2, 0x8E, 0xD7, 0x9D, 0x59, 0x75, 0x38, 0xBA, 0x3E, 0x09, 0x40, 0x9D, 0xAC, 0xC4, 0xB8, 0x6B, 0xC7, 0xEE, 0x12, 0xBD, 0x7C, 0xFC, 0x1F, 0xB2, 0x98, 0x73, 0xDF, 0x18, 0x94, 0x0F, 0x05, 0xB0, 0x4F, 0x71, 0xB2, 0xEE, 0x9B, 0xD2, 0x8F, 0xD5, 0x04, 0x8B, 0xCD, 0x60, 0x6A, 0xBA, 0x33, 0x1F, 0x6C, 0x90, 0x19, 0x58, 0x02, 0x75, 0x06, 0xF5, 0xDF, 0x05, 0xF4, 0x58, 0xE1, 0x36, 0x1B, 0xF6, 0x1F, 0x99, 0x90, 0x9E, 0xFC, 0xA3, 0x58, 0x50, 0xC6, 0x73, 0x93, 0xEE, 0xE9, 0xD2, 0x76, 0xC5, 0x95, 0x5D, 0x94, 0xE9, 0x06, 0x67, 0xFF, 0xB1, 0x7C, 0x13, 0x5C, 0x7D, 0xB7, 0x66, 0x44, 0x06, 0x60, 0xD8, 0x43, 0x8B, 0xE2, 0xCB, 0x5C, 0x5F, 0x9B, 0x97, 0x4C, 0x7F, 0x04, 0x96, 0x4B, 0x5E, 0x6F, 0x41, 0x3F, 0xAD, 0x35, 0xCA, 0x3E, 0xE5, 0x8A, 0x3A, 0x80, 0xFB, 0x2D, 0x12, 0x99, 0xB3, 0xFF, 0xC8, 0x0D, 0x9C, 0x62, 0x0E, 0x21, 0xA0, 0x7A, 0x3B, 0xD2, 0x4E, 0xF2, 0x15, 0x5A, 0x4D, 0x7F, 0x83, 0x2C, 0x33, 0xD1, 0x76, 0x4F, 0x64, 0x85, 0xD9, 0xF5, 0x4D, 0x4D, 0x28, 0x11, 0x45, 0xC1, 0x42, 0xCD, 0x86, 0xFC, 0x87, 0xB9, 0x42, 0x9F, 0x4A, 0xF6, 0xF8, 0x54, 0xAC, 0x38, 0x77, 0xA6, 0x35, 0x5E, 0xEF, 0xA7, 0x59, 0xAB, 0xD5, 0xC0, 0x6A, 0xD6, 0x7C, 0xF3, 0x4D, 0xC5, 0x8E, 0xF5, 0xAE, 0x39, 0x6B, 0x79, 0x00, 0xA6, 0x8C, 0x33, 0xF1, 0x29, 0x1F, 0x1F, 0xB7, 0x3D, 0xEB, 0x0C, 0x30, 0x75, 0xBB, 0xD5, 0xB4, 0x81, 0x3A, 0xC0, 0xB0, 0xEC, 0xC2, 0x01, 0x09, 0x20, 0xEA, 0xCE, 0xC8, 0x6D, 0x01, 0x92, 0x0F, 0xF7, 0x95, 0x76, 0xC0, 0x0B, 0xA8, 0xEB, 0x15, 0x58, 0xCD, 0x7E, 0x9D, 0x2F, 0xBC, 0xF3, 0x67, 0xBC, 0x39, 0x8A, 0xEE, 0x26, 0x9D, 0xF8, 0xF7, 0xB4, 0x41, 0x8F, 0x94, 0xF0, 0x1F, 0x0E, 0x46, 0x9E, 0x6A, 0x37, 0x5B, 0x95, 0x61, 0xAC, 0xDD, 0x4D, 0x8C, 0x9D, 0xAB, 0x33, 0x94, 0x33, 0x2F, 0x79, 0xB7, 0xA4, 0xE6, 0x9B, 0x53, 0x43, 0x84, 0x2E, 0xD5, 0xCB, 0x37, 0x6F, 0x0D, 0xE8, 0xE2, 0xCC, 0x5D, 0xC4, 0x73, 0xF4, 0xAE, 0x33, 0xA7, 0xEE, 0x4B, 0x38, 0x20, 0x09, 0x7C, 0x73, 0x3D, 0x9D, 0xB0, 0xC5, 0x59, 0xE8, 0xA2, 0xEE, 0x9E, 0x39, 0x9E, 0x40, 0x0F, 0x50, 0x0E, 0xF0, 0xF7, 0xA6, 0x80, 0x14, 0xA0, 0xF5, 0x11, 0xFC, 0xA2, 0xD5, 0x18, 0x27, 0xD8, 0x22, 0xA9, 0x94, 0x15, 0x0D, 0xBE, 0xF6, 0xD0, 0x36, 0xF9, 0x41, 0x44, 0x36, 0xE3, 0x59, 0xE3, 0xF2, 0xDD, 0xC6, 0x7C, 0x32, 0x21, 0xAB, 0xB9, 0x68, 0xD1, 0xA7, 0xB5, 0xA0, 0x44, 0x1E, 0xAB, 0x77, 0xE7, 0xBD, 0x3F, 0xF4, 0x67, 0x78, 0xE4, 0xEE, 0x62, 0xF1, 0x7C, 0x27, 0xD3, 0xBB, 0x82, 0x4E, 0xE7, 0xAE, 0x90, 0xCD, 0x00, 0xC2, 0x01, 0xC6, 0x02, 0x32, 0x3F, 0xA9, 0xA2, 0xF2, 0x5F, 0x9F, 0x12, 0xF0, 0x4F, 0xE6, 0xB2, 0x0F, 0x60, 0xF1, 0xC9, 0x84, 0x1C, 0x40, 0xEB, 0x2E, 0x42, 0xB3, 0x7C, 0xAC, 0x86, 0x38, 0x41, 0x8D, 0xFC, 0x0E, 0x4A, 0x53, 0xBA, 0x8E, 0xD5, 0x3B, 0x13, 0xD2, 0x0B, 0x50, 0xB3, 0xD5, 0x3F, 0xAC, 0xAB, 0xA6, 0x2C, 0xEB, 0x53, 0xFF, 0x2F, 0xF4, 0x5C, 0xD6, 0xDE, 0x7B, 0x86, 0xE7, 0x4A, 0x01, 0x0E, 0x73, 0x52, 0xF4, 0x4D, 0xF5, 0xC9, 0x47, 0x72, 0xA2, 0x12, 0xE8, 0x03, 0xD0, 0xDA, 0x42, 0x2F, 0xFE, 0x56, 0x20, 0xCF, 0xB9, 0x26, 0x6A, 0x2D, 0xCE, 0x01, 0xB2, 0x19, 0x4D, 0xFA, 0x44, 0x06, 0x9A, 0x25, 0x54, 0x0E, 0xB8, 0x02, 0xC1, 0x25, 0x6C, 0xC1, 0x0D, 0xCA, 0x1D, 0x30, 0xD9, 0x87, 0xF1, 0xC9, 0xBC, 0x12, 0x40, 0xB8, 0xE2, 0x26, 0xAD, 0x96, 0x3F, 0x73, 0x75, 0x37, 0xEE, 0x3D, 0x9E, 0xC8, 0x96, 0xE1, 0x1A, 0xDB, 0xBE, 0xEA, 0x12, 0x83, 0x5F, 0x77, 0xC1, 0xB7, 0xDD, 0xBC, 0x78, 0xFF, 0xEE, 0x06, 0xCF, 0x86, 0xA5, 0x9F, 0xDD, 0x80, 0xDE, 0x33, 0x65, 0xE7, 0x7E, 0x63, 0xDA, 0xF7, 0xDE, 0x08, 0xE7, 0x75, 0xCD, 0xD6, 0x53, 0x11, 0x51, 0x01, 0xA8, 0xD3, 0x77, 0x43, 0x5F, 0xDA, 0x1A, 0xA1, 0xFF, 0xC4, 0xA1, 0x9B, 0x9B, 0x20, 0xBD, 0xF8, 0x3C, 0xBD, 0xC9, 0x5F, 0x22, 0x3D, 0xBD, 0x3C, 0x74, 0x63, 0x7E, 0x34, 0x74, 0xDA, 0x3E, 0x1A, 0x3A, 0x02, 0xE4, 0x01, 0x62, 0xC1, 0xBA, 0xD5, 0x12, 0xC0, 0x12, 0x08, 0xE3, 0x32, 0x4C, 0xAB, 0x15, 0xDC, 0xB6, 0xED, 0x28, 0xB7, 0x1C, 0xBF, 0xAA, 0xB1, 0x5D, 0x1A, 0x83, 0xA3, 0x7A, 0xBF, 0x58, 0xC0, 0xCF, 0x82, 0x5B, 0xBB, 0xF6, 0xC7, 0x0F, 0x19, 0xF3, 0xAE, 0x99, 0x4A, 0xB1, 0xCC, 0x2D, 0xF9, 0x78, 0x3C, 0x41, 0xF1, 0xD7, 0x61, 0x97, 0xA9, 0x3C, 0xCC, 0x98, 0x30, 0x18, 0x34, 0x06, 0x06, 0xCD, 0xE0, 0x8D, 0x19, 0x06, 0xED, 0x62, 0xEB, 0xBB, 0x5B, 0x29, 0xA0, 0x14, 0x96, 0x34, 0x67, 0x30, 0xE9, 0x3D, 0xCC, 0xE4, 0x13, 0x9B, 0x69, 0x5E, 0xB1, 0xF7, 0x5A, 0x34, 0x43, 0x17, 0x17, 0xD0, 0xBA, 0xFF, 0x9C, 0xEB, 0x33, 0xD2, 0x03, 0xD4, 0x22, 0x0D, 0xB0, 0xA4, 0xAC, 0x19, 0x90, 0x07, 0x68, 0xC1, 0xCF, 0xFE, 0x96, 0xB5, 0xDE, 0x4B, 0x8B, 0xA1, 0x3F, 0xD8, 0xC9, 0xD7, 0x68, 0x66, 0xD5, 0xF0, 0xD7, 0x87, 0xFD, 0x20, 0xBE, 0xE1, 0x7B, 0x38, 0x6F, 0x5D, 0x3F, 0x2E, 0xB5, 0x7E, 0x92, 0x7D, 0xD7, 0x20, 0xB2, 0x77, 0x9E, 0x7E, 0x6F, 0x9B, 0xFE, 0x14, 0xFE, 0x9C, 0x7C, 0xFB, 0x96, 0xE6, 0xFE, 0x37, 0x8D, 0x3D, 0x8A, 0xF7, 0xAF, 0x1E, 0xFA, 0x62, 0x76, 0xFF, 0xB5, 0xC7, 0xCB, 0x20, 0x7E, 0xAB, 0xB0, 0xC9, 0xBC, 0xE5, 0x3C, 0xF1, 0x0C, 0x91, 0x5C, 0x9B, 0x59, 0xD1, 0xC1, 0x06, 0xCC, 0xE7, 0x42, 0x6A, 0x0A, 0xF0, 0x7E, 0xC9, 0xDE, 0x24, 0xA7, 0xD6, 0xBA, 0x01, 0xA4, 0x03, 0xC2, 0x53, 0xD2, 0x00, 0x4D, 0x35, 0xDF, 0xA0, 0xCD, 0x06, 0x2D, 0x95, 0x54, 0xD0, 0xDF, 0x4B, 0x0B, 0xCA, 0x35, 0xF9, 0x5E, 0xDB, 0xD7, 0x29, 0x89, 0x1C, 0xA5, 0x41, 0x50, 0xC4, 0xFB, 0x92, 0x71, 0x8D, 0xAB, 0x81, 0x08, 0x4B, 0x23, 0xD9, 0xE5, 0xF5, 0x19, 0x61, 0x38, 0xB1, 0x22, 0x39, 0x74, 0xFB, 0x34, 0x3F, 0x2E, 0x24, 0xFA, 0x1A, 0x37, 0x74, 0x90, 0x3B, 0xEC, 0x74, 0x87, 0x1D, 0x87, 0x48, 0xAC, 0x0D, 0x58, 0x6C, 0xC0, 0xF8, 0x92, 0xB3, 0xBC, 0x20, 0x5F, 0x41, 0x6F, 0x7B, 0x0A, 0xC0, 0x8A, 0x42, 0xE7, 0x6B, 0x18, 0x67, 0x70, 0x6C, 0x80, 0x16, 0xD8, 0x47, 0x16, 0x54, 0xC5, 0x0B, 0x36, 0x5D, 0xE5, 0xD0, 0x5A, 0x64, 0x00, 0x42, 0x79, 0x8C, 0x7D, 0x93, 0x5F, 0xEC, 0xC9, 0x83, 0x59, 0xEF, 0x8D, 0x07, 0xDB, 0x13, 0x5E, 0xC5, 0x9E, 0x16, 0x2E, 0xDB, 0x5D, 0x73, 0x76, 0x85, 0xB1, 0xAD, 0x81, 0xBB, 0xCB, 0xD8, 0xE7, 0x52, 0x71, 0xE5, 0x81, 0x48, 0xD7, 0xCB, 0x61, 0xB8, 0x44, 0x62, 0x34, 0x1D, 0x7C, 0xA2, 0xFF, 0x45, 0xED, 0x0D, 0xB4, 0xE4, 0x5A, 0x8B, 0x73, 0x60, 0x6D, 0x40, 0x0F, 0x96, 0xF4, 0x93, 0xBF, 0xC0, 0xDE, 0x8C, 0x3D, 0x6F, 0x4A, 0xEC, 0x7A, 0xC8, 0x31, 0xA6, 0xF0, 0x89, 0xB7, 0x11, 0x0D, 0xA6, 0x46, 0xDC, 0x4A, 0x25, 0xA5, 0x9F, 0xC0, 0xD2, 0x22, 0xED, 0x0E, 0x41, 0xB5, 0x03, 0x95, 0x80, 0x33, 0xD5, 0x74, 0x80, 0xB7, 0xA7, 0x1A, 0x5E, 0x19, 0x1A, 0x4D, 0x36, 0x2F, 0x30, 0x76, 0x8E, 0x7F, 0xB5, 0xD4, 0x36, 0x17, 0xC8, 0xE3, 0x07, 0x2D, 0x43, 0xEF, 0x87, 0xBE, 0x93, 0xD4, 0x0C, 0x98, 0x38, 0xCC, 0x3B, 0xD8, 0x31, 0xD5, 0x4C, 0x52, 0x63, 0x2E, 0xD0, 0x76, 0x4A, 0x63, 0x31, 0xD1, 0x36, 0x6F, 0xD3, 0xF3, 0x66, 0x3A, 0xCE, 0x7A, 0x86, 0x6A, 0x7D, 0x10, 0x01, 0x13, 0x38, 0x36, 0x8C, 0x6B, 0x1E, 0x1F, 0xD9, 0x3C, 0xA1, 0x5A, 0x57, 0x19, 0x73, 0x14, 0x13, 0x9F, 0xC6, 0xDE, 0xCC, 0xB5, 0xDA, 0x5E, 0x38, 0xF3, 0xF4, 0x47, 0x38, 0x07, 0x08, 0x03, 0xE6, 0x07, 0x7D, 0x32, 0x5C, 0xDD, 0x81, 0x89, 0x85, 0x00, 0x99, 0x80, 0xB2, 0x8A, 0xB0, 0xF7, 0x53, 0xAC, 0xE7, 0xC4, 0x68, 0x33, 0xFD, 0x75, 0x93, 0xAD, 0xA9, 0xAB, 0x4A, 0xCA, 0x43, 0xDF, 0x83, 0x5A, 0xA6, 0x15, 0x7C, 0x0E, 0x8D, 0x6B, 0xBB, 0x41, 0x95, 0x28, 0x62, 0xED, 0x6A, 0x79, 0xB5, 0x61, 0xB4, 0x27, 0x03, 0x65, 0x8A, 0x4A, 0xF2, 0x0B, 0x76, 0xA7, 0xCA, 0x5B, 0xDD, 0xE5, 0x89, 0xAD, 0xF5, 0xED, 0xF3, 0x68, 0x05, 0xDC, 0x79, 0x63, 0x66, 0x39, 0x29, 0xE0, 0xBD, 0x10, 0x40, 0xEB, 0xF3, 0x6F, 0x56, 0x77, 0x69, 0x4F, 0x7F, 0xCB, 0xC8, 0x06, 0x10, 0x07, 0x54, 0xEE, 0x26, 0x90, 0xE6, 0x40, 0x2B, 0x90, 0x03, 0x18, 0x7D, 0x07, 0x06, 0x78, 0x03, 0x19, 0x4F, 0xC1, 0x0C, 0xAD, 0x66, 0xE8, 0x3D, 0x2E, 0xF2, 0xAF, 0xE3, 0x5D, 0x62, 0xAE, 0xB0, 0xD4, 0x98, 0x24, 0x0A, 0x10, 0xAA, 0x71, 0x8C, 0xD1, 0xFA, 0x8F, 0x8E, 0xBC, 0x2E, 0x4F, 0x5B, 0x45, 0x4A, 0xE5, 0xED, 0x6A, 0x98, 0x9F, 0xD3, 0x05, 0x0B, 0xCE, 0xEA, 0x56, 0x68, 0xCA, 0xFA, 0x6B, 0x25, 0x30, 0xCF, 0xD2, 0x58, 0x2C, 0x55, 0xDE, 0x2F, 0xE3, 0x9F, 0x22, 0x7E, 0xE9, 0x6F, 0x3E, 0x15, 0x55, 0x96, 0xDF, 0x7B, 0xB7, 0x9C, 0x27, 0x66, 0x15, 0x1F, 0xE1, 0xE9, 0x3A, 0x00, 0x83, 0x4E, 0x5C, 0x21, 0x2D, 0x81, 0x1E, 0xA0, 0x12, 0xB0, 0xC1, 0x2B, 0x7D, 0x00, 0x4B, 0x20, 0x76, 0x96, 0xA7, 0xD0, 0x6A, 0x0E, 0xC9, 0xDB, 0x82, 0xE6, 0x50, 0x74, 0xAF, 0x07, 0x1D, 0x75, 0xB3, 0x39, 0x85, 0x5A, 0x17, 0x2B, 0x38, 0x0D, 0xAA, 0x50, 0xE3, 0x10, 0x72, 0x17, 0x95, 0xF9, 0x27, 0xE5, 0x2A, 0x9D, 0x0A, 0x7D, 0xC6, 0xEC, 0x55, 0x40, 0x77, 0x2D, 0xBF, 0x2B, 0x7C, 0xED, 0xD1, 0xCD, 0x3E, 0x6F, 0xAF, 0x85, 0xD9, 0xE1, 0x38, 0xCF, 0x29, 0x2C, 0xCF, 0x1B, 0xAB, 0x8D, 0xAB, 0x25, 0xE1, 0xED, 0xF6, 0xBA, 0x44, 0xCA, 0x13, 0x78, 0x05, 0x60, 0x38, 0xD2, 0xB5, 0x01, 0x2F, 0x20, 0xED, 0x11, 0x26, 0x06, 0x9A, 0xCA, 0x64, 0x02, 0x28, 0x5D, 0xF7, 0x03, 0x38, 0xDF, 0x34, 0x80, 0xFA, 0xDE, 0x12, 0xB4, 0x5A, 0x20, 0x60, 0xDC, 0x9C, 0xA1, 0x5B, 0xFC, 0xDB, 0x8D, 0x1B, 0x4D, 0x06, 0x94, 0x51, 0xB3, 0x56, 0xDE, 0xB8, 0x20, 0xC8, 0x66, 0x7D, 0xA7, 0x5C, 0x29, 0xAD, 0x76, 0xD5, 0x92, 0x0F, 0x8D, 0x47, 0x01, 0x5C, 0x1C, 0x99, 0x36, 0x09, 0x89, 0xDF, 0x02, 0x26, 0xB9, 0x54, 0xD3, 0xDE, 0x89, 0x7A, 0x3E, 0x33, 0xB4, 0x3E, 0x97, 0x27, 0x5D, 0x1C, 0x20, 0x16, 0xF4, 0xBD, 0xA5, 0xDD, 0x82, 0x4D, 0xA7, 0x80, 0x5E, 0xDB, 0x6B, 0x7C, 0x8A, 0xA6, 0x02, 0x18, 0x2A, 0x70, 0xF2, 0x5F, 0x49, 0x00, 0x5A, 0xBB, 0x16, 0x6A, 0x74, 0x18, 0x3D, 0x62, 0x0B, 0x74, 0x0E, 0xD2, 0x6A, 0xF0, 0x72, 0xF8, 0xC9, 0xDF, 0x0C, 0xED, 0xC9, 0x77, 0x6A, 0xBA, 0x4A, 0x21, 0x75, 0x3B, 0x36, 0x74, 0x6F, 0x0C, 0xAF, 0x2A, 0x95, 0xBC, 0x3F, 0x57, 0xA9, 0x79, 0x57, 0x2B, 0xE9, 0x3D, 0xFF, 0xFB, 0xB3, 0xC7, 0x8F, 0xF1, 0xD4, 0x83, 0x9F, 0x65, 0xBF, 0xDD, 0x2C, 0xF4, 0x69, 0x49, 0x70, 0x98, 0xC2, 0x77, 0x2F, 0x7D, 0x5C, 0x83, 0xAA, 0x01, 0x91, 0x8F, 0x9A, 0xEF, 0xA7, 0x63, 0x51, 0xD1, 0xBD, 0x71, 0x15, 0x4F, 0x89, 0x3C, 0x13, 0xB5, 0x59, 0x00, 0x54, 0x80, 0xEB, 0x5D, 0xEB, 0xC3, 0xA3, 0xB3, 0x08, 0x70, 0x94, 0x05, 0x40, 0x80, 0xE6, 0xA7, 0x71, 0x32, 0xBF, 0x7D, 0xD2, 0x6A, 0xF5, 0x6F, 0x04, 0x5D, 0x8A, 0xE7, 0xE7, 0x09, 0x93, 0x7F, 0x56, 0x08, 0x71, 0x22, 0x5F, 0xDA, 0xE0, 0xEC, 0x18, 0x87, 0xCC, 0x54, 0x07, 0x4A, 0xB0, 0x90, 0xDE, 0xE7, 0xF1, 0x15, 0xA0, 0x13, 0x4E, 0x15, 0x61, 0x1C, 0xF4, 0xBA, 0xCA, 0x01, 0x18, 0x72, 0x77, 0x7F, 0x9E, 0xA4, 0xF8, 0x60, 0x31, 0x19, 0x9F, 0x19, 0x5B, 0xC0, 0xD3, 0x9C, 0x42, 0x6E, 0xE1, 0xC7, 0xC3, 0x0A, 0x99, 0x45, 0x0A, 0x10, 0xC3, 0x70, 0xC5, 0xDD, 0xB8, 0xE2, 0x04, 0xC0, 0x4F, 0x6E, 0x8B, 0x01, 0xA2, 0xEF, 0xDA, 0x62, 0x96, 0xF2, 0x1D, 0xE6, 0x79, 0x1C, 0x20, 0xE5, 0x23, 0x6A, 0x72, 0xC9, 0x14, 0xC7, 0x9B, 0x4A, 0x6A, 0xFD, 0x4B, 0x25, 0xED, 0x47, 0x0E, 0x7D, 0xF3, 0xF5, 0x5D, 0xB1, 0xA7, 0xD4, 0x20, 0x85, 0x24, 0x15, 0x33, 0x14, 0x39, 0x7F, 0xEE, 0x6A, 0xBF, 0x31, 0x96, 0xDF, 0xA4, 0x48, 0x3D, 0x4F, 0x51, 0x33, 0xBD, 0x76, 0xB7, 0x7E, 0xAA, 0xEA, 0x5B, 0xA1, 0x25, 0xC0, 0x3C, 0x53, 0xA5, 0xE5, 0xDE, 0x51, 0x9F, 0xAF, 0xF6, 0x74, 0x6A, 0xE3, 0x06, 0x09, 0x04, 0x11, 0x80, 0x3B, 0x00, 0x23, 0xE8, 0xA7, 0x03, 0x7C, 0xFC, 0xED, 0xD2, 0x0B, 0xFA, 0x64, 0x4F, 0x01, 0x32, 0x40, 0x2A, 0x8F, 0xA3, 0xFF, 0xA1, 0xB2, 0x6C, 0x7D, 0x4B, 0x85, 0x85, 0x03, 0xB5, 0xAF, 0xA4, 0x3F, 0x56, 0x9B, 0xDF, 0x1E, 0x7A, 0x8E, 0xFF, 0x22, 0x46, 0x55, 0xBE, 0x27, 0x64, 0xB9, 0x3B, 0x69, 0x6F, 0x43, 0x8F, 0xCE, 0x5E, 0x71, 0xBB, 0xA6, 0x8B, 0xE8, 0x53, 0x98, 0x7D, 0x5F, 0xDB, 0x79, 0x72, 0x15, 0xE6, 0x06, 0x6D, 0x5A, 0xFF, 0xC1, 0x27, 0x69, 0x80, 0x12, 0x04, 0xCF, 0x74, 0xB0, 0x6F, 0xD2, 0xE9, 0x5A, 0xFB, 0xE0, 0x67, 0x78, 0xFF, 0xEF, 0x86, 0x9E, 0x4F, 0x6E, 0x10, 0x61, 0x57, 0xF9, 0x27, 0x56, 0xFC, 0x9D, 0x9A, 0xB1, 0x93, 0x91, 0x33, 0x4D, 0x80, 0x70, 0xA0, 0x86, 0x7E, 0xCF, 0x5B, 0x90, 0xA2, 0x06, 0xC8, 0xFE, 0x0F, 0xFF, 0x8B, 0x29, 0x10, 0xBA, 0xAF, 0xD0, 0x6A, 0xCE, 0x62, 0xAE, 0xFA, 0x05, 0xD8, 0xFC, 0x24, 0x76, 0x2D, 0x43, 0xAF, 0xE7, 0xC8, 0xDA, 0x1A, 0xAB, 0x59, 0xC5, 0x50, 0xD9, 0x5E, 0xE8, 0x50, 0x59, 0xAE, 0xFF, 0xEC, 0x54, 0x50, 0x7A, 0x60, 0x2E, 0xEA, 0x0D, 0xCD, 0x5E, 0x02, 0x4E, 0xBD, 0x75, 0x9C, 0xBE, 0x25, 0x38, 0x6C, 0x5D, 0xD1, 0xF4, 0x14, 0x3D, 0x7B, 0xBF, 0x0E, 0xFB, 0xAF, 0xD0, 0x2D, 0x43, 0xDF, 0xE6, 0xAE, 0xB2, 0xF7, 0xB8, 0x10, 0x5F, 0xCC, 0xE5, 0xFE, 0x8C, 0xC7, 0x8F, 0x52, 0xC1, 0x26, 0x13, 0x7B, 0xE9, 0xD0, 0xBD, 0x8D, 0x37, 0xD0, 0x1B, 0x72, 0xA6, 0x76, 0x96, 0x15, 0xD0, 0x84, 0x01, 0x11, 0x80, 0xFC, 0x90, 0x7C, 0xB8, 0x11, 0xF9, 0x06, 0x60, 0x35, 0xF9, 0x17, 0x01, 0x09, 0xA6, 0xC2, 0x91, 0xF0, 0x7F, 0x5B, 0x89, 0x58, 0x29, 0x5C, 0x52, 0x23, 0x9B, 0x24, 0x50, 0x97, 0xEB, 0xBB, 0xCF, 0x65, 0xB5, 0xDE, 0x89, 0xAA, 0xF6, 0x04, 0xAB, 0x55, 0x01, 0xF7, 0xB5, 0x61, 0xD1, 0xA7, 0x00, 0xAB, 0x0D, 0x4B, 0x6B, 0x68, 0x35, 0x8E, 0x84, 0xD8, 0x21, 0x57, 0x7F, 0xCA, 0xD1, 0x78, 0x83, 0xE7, 0x89, 0xCB, 0x71, 0xE9, 0x8B, 0x27, 0x40, 0x92, 0x1C, 0xA3, 0x4A, 0xFF, 0xCF, 0x0E, 0xEA, 0xB8, 0xAB, 0xC3, 0xE8, 0x02, 0x51, 0x05, 0x98, 0xEC, 0x55, 0xEB, 0x09, 0x31, 0x07, 0x94, 0xEE, 0x11, 0x07, 0x5C, 0x81, 0xE3, 0xC0, 0xD3, 0x8C, 0xEE, 0xB1, 0x9A, 0xFE, 0x4B, 0x47, 0x96, 0x77, 0xA2, 0x43, 0xD9, 0xFF, 0x76, 0xB1, 0x94, 0x31, 0x2C, 0xE6, 0xBC, 0xCA, 0x66, 0xD1, 0xCD, 0x71, 0x75, 0xAD, 0x89, 0xCB, 0x75, 0x4D, 0xF7, 0x8A, 0xF9, 0xD3, 0x3A, 0x70, 0x86, 0x49, 0x0E, 0x5B, 0x40, 0x7C, 0xE5, 0x9C, 0xF0, 0x2F, 0x64, 0xBE, 0x46, 0xD3, 0x84, 0x4F, 0xA2, 0x14, 0x53, 0x8B, 0xCD, 0x99, 0x00, 0x49, 0x8F, 0x23, 0x6C, 0x77, 0xB5, 0x0B, 0x61, 0x23, 0x37, 0x5A, 0xF9, 0x91, 0xAF, 0xF6, 0xE7, 0x78, 0x98, 0x03, 0x0C, 0x03, 0x13, 0x0A, 0x54, 0x50, 0x00, 0x86, 0xE9, 0x48, 0xC0, 0xF1, 0x7D, 0x98, 0xC0, 0xE9, 0xBB, 0x39, 0x55, 0x53, 0x66, 0xB5, 0x69, 0x34, 0xFB, 0x25, 0x79, 0x57, 0x0B, 0x56, 0xB7, 0x8A, 0xCB, 0xAF, 0x56, 0xA1, 0x2B, 0x83, 0xD0, 0x5B, 0x91, 0x1F, 0x70, 0xBD, 0xFC, 0xF7, 0x04, 0xD5, 0x47, 0x5D, 0x97, 0x2E, 0x95, 0x35, 0x50, 0x00, 0xD4, 0xFE, 0xA0, 0xDF, 0x0A, 0xD0, 0xBF, 0x6C, 0x15, 0xFA, 0x03, 0xED, 0x96, 0x09, 0xA0, 0x87, 0x95, 0xFB, 0xB1, 0xAC, 0xA2, 0x7C, 0x31, 0x96, 0xF0, 0xCA, 0xFF, 0xE6, 0x1D, 0x6E, 0xC0, 0x3E, 0xB3, 0xE6, 0xAA, 0xC3, 0xEF, 0x4B, 0xCF, 0xD1, 0x9A, 0x44, 0x01, 0x93, 0xBB, 0x5C, 0x8C, 0xB5, 0x8A, 0x72, 0x80, 0xC3, 0x3F, 0xC9, 0x00, 0x6D, 0xBC, 0x39, 0xF1, 0x2A, 0x20, 0x9F, 0x77, 0x82, 0x3A, 0xDC, 0x5E, 0x9D, 0x5B, 0x2A, 0xF7, 0xBD, 0xBA, 0xB3, 0x83, 0xDC, 0x3A, 0x6F, 0x4F, 0x30, 0x4B, 0xE9, 0x52, 0x6B, 0x9A, 0x4F, 0x65, 0xF6, 0x3C, 0xC9, 0x6A, 0x9B, 0xD9, 0xA7, 0xB2, 0x99, 0x53, 0xB2, 0x9A, 0x87, 0xEC, 0x83, 0xCD, 0xA2, 0x43, 0xE6, 0x82, 0xC5, 0xBD, 0xD4, 0xCD, 0x75, 0x0F, 0xAB, 0x27, 0x8A, 0xFA, 0x14, 0x53, 0x3B, 0x2C, 0x59, 0x4F, 0xCF, 0x1E, 0x40, 0x29, 0x01, 0xFB, 0xDE, 0x3D, 0x9E, 0x7C, 0x8C, 0xF8, 0xAB, 0x16, 0x15, 0xA0, 0x77, 0xA1, 0xD5, 0x01, 0x58, 0x00, 0xC9, 0x44, 0x61, 0x37, 0xC0, 0x1A, 0x60, 0x67, 0x98, 0x58, 0xA8, 0x02, 0x7C, 0x25, 0x8A, 0x46, 0x0B, 0xB8, 0x28, 0xAC, 0x90, 0xEE, 0xD0, 0x79, 0x1B, 0x6D, 0x4D, 0x40, 0x57, 0x93, 0x76, 0x23, 0x9F, 0x66, 0xF4, 0x8D, 0x7C, 0x9F, 0xFE, 0xA8, 0x35, 0xD9, 0xBC, 0x1D, 0x53, 0x37, 0x07, 0xF9, 0xD1, 0x46, 0xB3, 0x75, 0x35, 0x9C, 0xC7, 0xCD, 0x76, 0xFC, 0x75, 0x23, 0xC9, 0xD3, 0xE7, 0xD9, 0xFB, 0x15, 0x37, 0x0C, 0x76, 0x64, 0x7C, 0x46, 0xC3, 0x13, 0x06, 0x7C, 0x52, 0x24, 0x01, 0x0E, 0x57, 0xAB, 0xB7, 0x7B, 0xC4, 0x56, 0xF8, 0x19, 0xDD, 0x9E, 0xB6, 0x83, 0x1E, 0xB9, 0x08, 0x70, 0x2A, 0x1F, 0x60, 0xF6, 0x9F, 0xB1, 0x6B, 0xDD, 0x33, 0xBE, 0x10, 0x40, 0xE8, 0x77, 0x4E, 0xC0, 0x02, 0x88, 0xC1, 0xCF, 0xEA, 0xD0, 0x66, 0x89, 0x5E, 0xCC, 0x52, 0xFF, 0xDB, 0x3E, 0xBB, 0x3B, 0xB7, 0x3A, 0xDC, 0x91, 0xBF, 0x1F, 0x89, 0x63, 0xF6, 0xF4, 0x15, 0x62, 0x89, 0x8F, 0x82, 0x2B, 0x1D, 0xBB, 0xF5, 0xE4, 0x27, 0xC6, 0x70, 0x37, 0x65, 0xEB, 0x9A, 0xB7, 0xA1, 0x9D, 0xE2, 0x2F, 0x9D, 0x47, 0x34, 0x7B, 0x3E, 0x7A, 0x8F, 0x1D, 0xAF, 0x2E, 0xA6, 0xFE, 0x75, 0xE3, 0x0B, 0xA0, 0xBF, 0xDA, 0xCA, 0x97, 0x96, 0x0E, 0xF6, 0xE2, 0xF7, 0xAE, 0xC1, 0x8C, 0xF8, 0x7A, 0x92, 0x79, 0xE5, 0x00, 0xC1, 0xC0, 0x75, 0x01, 0x4D, 0x6F, 0x6F, 0x00, 0xDA, 0xC0, 0xB1, 0xBB, 0x89, 0xA3, 0x26, 0xE0, 0x41, 0xBF, 0x30, 0xAD, 0xB6, 0x43, 0xCC, 0x1C, 0xF2, 0xB7, 0xC1, 0xC0, 0xEA, 0xC0, 0x7D, 0x60, 0xB9, 0x57, 0x7D, 0x81, 0x66, 0xDD, 0x38, 0x3E, 0xC5, 0x5C, 0x49, 0xCB, 0xF2, 0xE9, 0x5F, 0x56, 0x5C, 0x40, 0x8C, 0x39, 0x5B, 0x0E, 0xE8, 0x79, 0x8F, 0x6A, 0xF5, 0x27, 0x3D, 0x45, 0x9F, 0x04, 0x4F, 0x65, 0x79, 0x49, 0xE6, 0x3D, 0x85, 0xBB, 0xFA, 0xB9, 0x97, 0x06, 0x60, 0x06, 0xC8, 0x82, 0x61, 0xFE, 0xAE, 0xEB, 0xCA, 0x5B, 0xCF, 0xFA, 0x93, 0x79, 0x3B, 0xB7, 0xBD, 0x00, 0x9E, 0x7C, 0x92, 0x41, 0x8D, 0x02, 0x86, 0x30, 0x20, 0x0B, 0xD0, 0x7D, 0x73, 0x1C, 0x9F, 0x18, 0xDB, 0x10, 0xA5, 0xD1, 0xD0, 0x09, 0x23, 0xEC, 0x3B, 0xD4, 0x08, 0x06, 0xC7, 0xE2, 0x77, 0xD1, 0x19, 0x83, 0xD1, 0xF4, 0xCC, 0x7D, 0x05, 0x3D, 0xB7, 0xDE, 0x3E, 0x07, 0x42, 0x3F, 0x62, 0x07, 0xC5, 0x2B, 0x28, 0x03, 0x27, 0x2C, 0xE9, 0xB9, 0x36, 0xC7, 0x3D, 0x0B, 0xF0, 0x06, 0x9D, 0x74, 0x6E, 0x3D, 0x45, 0x4B, 0xA1, 0x77, 0x77, 0x9A, 0x4A, 0xA0, 0xE5, 0x56, 0xD8, 0x67, 0x48, 0x73, 0x94, 0x07, 0x45, 0x7A, 0x45, 0xE9, 0x1C, 0xFF, 0x8A, 0x4F, 0x2F, 0x5C, 0xEF, 0xFE, 0x09, 0x73, 0xEE, 0xD6, 0x8B, 0x66, 0x9F, 0xAA, 0x82, 0x00, 0x8E, 0x01, 0x6A, 0xFB, 0xCA, 0x33, 0x41, 0x07, 0x8D, 0x26, 0xCB, 0x7F, 0x35, 0xAD, 0x95, 0x79, 0x79, 0x22, 0xCB, 0x66, 0xFB, 0x09, 0x08, 0x4E, 0xE7, 0x62, 0x38, 0x07, 0x75, 0xD0, 0xB5, 0xF6, 0xC9, 0xED, 0x60, 0xD9, 0x1B, 0x77, 0x22, 0xFD, 0xD4, 0xE9, 0xCA, 0xBC, 0x7A, 0x4D, 0x4C, 0xB2, 0xC8, 0x47, 0xE6, 0xEC, 0xD0, 0xA1, 0xCD, 0x7F, 0x20, 0x0E, 0xF5, 0x1D, 0xB8, 0xB4, 0xA1, 0xDF, 0xAA, 0x53, 0x4F, 0x6D, 0xD8, 0xD5, 0xE8, 0x3A, 0xE9, 0x52, 0xA6, 0x7E, 0x8C, 0x3F, 0x9A, 0x72, 0x11, 0xF7, 0x5C, 0x2C, 0xF6, 0x2B, 0x59, 0x54, 0x70, 0xE9, 0x60, 0x80, 0x71, 0xC1, 0xCD, 0xDF, 0x00, 0xB3, 0x3B, 0x8E, 0x2B, 0x3C, 0xB1, 0xD1, 0x6A, 0x71, 0x70, 0x8B, 0xD2, 0xB7, 0x59, 0xBB, 0xE3, 0x92, 0xF0, 0x76, 0x29, 0x30, 0xD4, 0xE5, 0x95, 0x68, 0xE3, 0x2F, 0xDB, 0x78, 0xFB, 0xD0, 0x6A, 0xFD, 0xD1, 0x06, 0xF3, 0xC7, 0xB9, 0xFF, 0x15, 0x6D, 0x58, 0x07, 0x47, 0xC8, 0xDD, 0x3E, 0x30, 0x12, 0x06, 0x8A, 0x57, 0x75, 0x25, 0x9E, 0xCE, 0xCC, 0xA3, 0x77, 0x77, 0x1A, 0x61, 0x9E, 0x2F, 0x91, 0x40, 0x16, 0x30, 0x6B, 0x43, 0x9E, 0x7A, 0x45, 0xAE, 0x88, 0x28, 0xFE, 0x09, 0xAE, 0xEC, 0x79, 0x51, 0xC0, 0x16, 0x74, 0xEC, 0x25, 0x95, 0x8E, 0x12, 0x38, 0xFB, 0xB0, 0x0E, 0x20, 0xCC, 0x8F, 0x99, 0x3B, 0x80, 0x3C, 0x49, 0xAB, 0x09, 0xAA, 0xB0, 0xC7, 0xFE, 0x73, 0x86, 0xE2, 0x16, 0x35, 0x8A, 0x8E, 0x42, 0xCE, 0x01, 0x6F, 0xD4, 0x56, 0xFE, 0x54, 0x98, 0xE9, 0x47, 0x24, 0xB2, 0xF5, 0x2D, 0xB8, 0xF0, 0xCD, 0x9C, 0x96, 0x67, 0x1E, 0x54, 0xBD, 0xA7, 0x88, 0x3D, 0x94, 0xF6, 0x73, 0x7F, 0xA7, 0x17, 0xFA, 0xE9, 0xBE, 0x9C, 0x4C, 0x4F, 0x58, 0x03, 0x09, 0x1D, 0x6D, 0x0B, 0x01, 0xBC, 0x5F, 0x67, 0x25, 0x85, 0xE4, 0x78, 0x2D, 0xD0, 0xB3, 0x0B, 0x93, 0x3E, 0x0B, 0x9A, 0x3B, 0x30, 0x5C, 0x3B, 0xAE, 0x9C, 0xEE, 0xDF, 0x4D, 0x14, 0x10, 0x96, 0x89, 0x34, 0x60, 0x5C, 0xD7, 0xF6, 0x93, 0x9E, 0x7D, 0xD3, 0x69, 0x35, 0xBD, 0xCD, 0xC5, 0x8E, 0xE0, 0xE3, 0xAF, 0x87, 0xAD, 0xC3, 0x99, 0xF4, 0x3A, 0x9B, 0xAA, 0x7B, 0xB7, 0xAC, 0xD1, 0xCB, 0x3F, 0x98, 0xBC, 0xD4, 0xD4, 0x8E, 0x78, 0x7F, 0x9A, 0x09, 0x06, 0xCF, 0xB9, 0xEC, 0xE2, 0x1E, 0x40, 0x30, 0x52, 0x95, 0x7F, 0x31, 0x66, 0x17, 0x18, 0xD4, 0x37, 0x48, 0xE4, 0xF1, 0x1C, 0x07, 0x60, 0x1F, 0x9E, 0xDC, 0x90, 0x42, 0xF3, 0xD4, 0x5D, 0xD4, 0x9F, 0x23, 0x9F, 0xEE, 0x71, 0xB9, 0xB3, 0xDA, 0x34, 0x81, 0x53, 0xFF, 0x25, 0x0D, 0x96, 0x77, 0xD5, 0xB1, 0xEB, 0x67, 0xEE, 0x37, 0x10, 0xFE, 0x5F, 0xCD, 0x57, 0xE6, 0x99, 0xA0, 0xDF, 0x31, 0xB6, 0x79, 0xA7, 0xBE, 0x52, 0x50, 0xA5, 0x3F, 0x1F, 0x67, 0x84, 0xEE, 0x34, 0x53, 0xCC, 0x76, 0x81, 0xD1, 0x62, 0xA3, 0xA0, 0xCF, 0x05, 0x94, 0x95, 0x45, 0xC6, 0x3B, 0x2B, 0xAB, 0x78, 0x98, 0xE9, 0xEF, 0x77, 0x1A, 0x3F, 0x3F, 0x75, 0x30, 0x05, 0x1E, 0x06, 0xF5, 0xA2, 0x98, 0xCE, 0xE6, 0x32, 0xEB, 0xDB, 0xEF, 0x92, 0x55, 0x15, 0x0C, 0x34, 0xF0, 0xC2, 0xB3, 0xC3, 0x16, 0xA7, 0xBA, 0xCB, 0x68, 0x80, 0xBD, 0xA7, 0x16, 0x40, 0xFC, 0x63, 0xBB, 0x04, 0xAC, 0xEF, 0x48, 0x8C, 0x2F, 0x68, 0x9F, 0x29, 0x20, 0x0C, 0xD0, 0x00, 0xFC, 0x2A, 0xAD, 0x85, 0xD1, 0xB0, 0x09, 0xB8, 0xC1, 0x79, 0x36, 0x62, 0x48, 0x18, 0x1F, 0xF8, 0x3C, 0xBA, 0x6A, 0x8F, 0x55, 0x89, 0xC5, 0x74, 0x74, 0xBB, 0x9F, 0x5E, 0xA1, 0xE3, 0xBE, 0xAF, 0x52, 0x49, 0xF7, 0x34, 0x6F, 0x4D, 0xBC, 0x07, 0xE0, 0xA5, 0xAD, 0x4F, 0x01, 0xC6, 0x17, 0x7B, 0xFE, 0x7C, 0x46, 0xDA, 0x06, 0xE1, 0x60, 0xAD, 0x4D, 0x39, 0x70, 0xC6, 0xF7, 0x39, 0x95, 0x8A, 0x07, 0xAA, 0xB5, 0x9D, 0xDF, 0x6D, 0x9F, 0xFA, 0xD1, 0xC9, 0xEF, 0x01, 0x84, 0xD9, 0xC0, 0x8B, 0x10, 0xC0, 0x13, 0x88, 0x03, 0x34, 0x77, 0xAE, 0xBA, 0x7F, 0xAF, 0x02, 0xF0, 0x04, 0x0E, 0x0F, 0x52, 0x0B, 0x7A, 0xE7, 0xDA, 0x1F, 0xA3, 0xC5, 0x47, 0x02, 0x7D, 0x3B, 0x35, 0xC7, 0x95, 0xAA, 0x50, 0x26, 0xB9, 0x97, 0x77, 0xD9, 0x2C, 0x91, 0xEF, 0x06, 0xFA, 0x89, 0xB2, 0x08, 0x97, 0xD1, 0xCA, 0x37, 0x46, 0x3E, 0x7F, 0x75, 0x63, 0x06, 0xA4, 0x7C, 0xB3, 0xD9, 0xA9, 0xA7, 0xB6, 0x27, 0x7A, 0x1E, 0xE5, 0x0B, 0x86, 0xED, 0x35, 0x97, 0x3F, 0x2D, 0xA9, 0x9F, 0xBC, 0x84, 0xA7, 0x53, 0x6A, 0x3E, 0x83, 0x64, 0x12, 0xE0, 0xE0, 0xAA, 0x85, 0xF6, 0x47, 0xC1, 0x2F, 0x3F, 0x4D, 0x44, 0x8C, 0xDE, 0x74, 0x20, 0xE2, 0x9E, 0xA6, 0x7C, 0x25, 0xF5, 0x23, 0x1C, 0x2F, 0x9F, 0x26, 0x22, 0xF5, 0xF4, 0x35, 0xDE, 0xE1, 0xA0, 0x5B, 0xD2, 0x12, 0x8A, 0xBE, 0x07, 0x31, 0xF7, 0x9E, 0xEE, 0x18, 0x78, 0x22, 0xCD, 0xAD, 0xE0, 0x2E, 0x01, 0x7D, 0xDC, 0xCC, 0xDC, 0xBB, 0x28, 0xCB, 0xE5, 0x3B, 0x2E, 0x52, 0x80, 0x39, 0x40, 0x19, 0xE0, 0x03, 0xD0, 0x03, 0xC8, 0x63, 0xB7, 0xCB, 0xDE, 0x8A, 0xB8, 0x7A, 0xE7, 0x5B, 0x87, 0x12, 0x4F, 0x27, 0x20, 0x1D, 0x0C, 0x08, 0xFA, 0xC8, 0x39, 0x6F, 0xD8, 0x9A, 0xF2, 0x2B, 0x55, 0xA8, 0xFF, 0xD5, 0xDE, 0xB8, 0x3F, 0x1D, 0x40, 0xF5, 0xDB, 0xCB, 0xF2, 0xD3, 0x84, 0xCF, 0x3F, 0x13, 0x34, 0x9F, 0x39, 0x4C, 0xAB, 0x7D, 0xCE, 0xB6, 0x30, 0x1E, 0x7A, 0x8A, 0xA0, 0x29, 0x81, 0x21, 0xB1, 0x8F, 0x71, 0xFB, 0x36, 0xA4, 0x37, 0xF8, 0xA5, 0x0D, 0xD6, 0xF1, 0xC9, 0xC3, 0x75, 0x66, 0xA6, 0xF0, 0x68, 0x6D, 0xCC, 0xDF, 0xA0, 0x54, 0x46, 0x00, 0xD3, 0xDC, 0x03, 0x00, 0x56, 0xE9, 0x95, 0xB2, 0x74, 0xEF, 0xD6, 0x5C, 0x3B, 0x83, 0x57, 0xB8, 0x91, 0x95, 0xBE, 0xF5, 0x3D, 0x67, 0xBB, 0xE5, 0x3F, 0xED, 0xBF, 0x2C, 0xEF, 0xF6, 0x8D, 0x19, 0x80, 0xF8, 0x47, 0x14, 0xE0, 0x2C, 0xF4, 0xD3, 0xCA, 0x92, 0x36, 0x4F, 0x40, 0xAE, 0x87, 0xB0, 0xEB, 0x35, 0x52, 0xAF, 0x5E, 0x7A, 0x30, 0x1A, 0xFB, 0x1A, 0x87, 0xDE, 0x95, 0x2B, 0x7D, 0x6B, 0xEF, 0xB7, 0x1B, 0x6E, 0xEF, 0x6D, 0x58, 0xAE, 0xFB, 0xCA, 0xEF, 0x3F, 0x06, 0x24, 0x1D, 0x35, 0xCA, 0x3B, 0x8A, 0xFC, 0x49, 0x9D, 0x38, 0x06, 0x3C, 0x44, 0xAC, 0x7A, 0x53, 0x11, 0x0C, 0xD0, 0x00, 0xDC, 0xB7, 0xC6, 0xA5, 0xB7, 0xE2, 0x4C, 0x36, 0xBD, 0xA1, 0xF0, 0x29, 0x8C, 0x8D, 0xDC, 0x99, 0x20, 0xB2, 0x93, 0x95, 0x6E, 0x38, 0xE6, 0x92, 0x51, 0xCE, 0xEF, 0x3A, 0x04, 0xEA, 0xD3, 0x03, 0x2F, 0x15, 0xB0, 0x59, 0xE8, 0xA2, 0x80, 0xAA, 0xB7, 0xEA, 0xD1, 0x9E, 0x63, 0x58, 0x07, 0x10, 0xC6, 0x46, 0xC6, 0x40, 0x0A, 0xD0, 0x7C, 0xC5, 0x68, 0xB3, 0xF9, 0x89, 0xDA, 0x9C, 0x09, 0x5A, 0x09, 0x42, 0x71, 0xD9, 0x97, 0x2B, 0x12, 0xA7, 0xE4, 0x2D, 0x7C, 0xD7, 0x64, 0x2F, 0x68, 0xE1, 0x4E, 0xD0, 0x97, 0x2B, 0x92, 0x4D, 0x14, 0x85, 0x82, 0xFA, 0xF9, 0x64, 0x5E, 0xF8, 0x67, 0x68, 0xB5, 0xEE, 0x16, 0x20, 0xEB, 0xEB, 0xE0, 0xB9, 0xA2, 0xD6, 0xBC, 0x2B, 0x23, 0x36, 0xF3, 0xCA, 0x88, 0x51, 0x9A, 0xC5, 0xFE, 0xCE, 0x31, 0xF4, 0xC2, 0xED, 0xD7, 0x0D, 0xBB, 0x72, 0xEE, 0x61, 0x9F, 0x79, 0x7A, 0x86, 0xCC, 0x27, 0x6E, 0x92, 0xBE, 0x60, 0x11, 0x6C, 0x02, 0x1D, 0xF4, 0xD0, 0x28, 0xA0, 0xFB, 0xD0, 0x00, 0xBB, 0x72, 0x2B, 0xD0, 0x2A, 0x98, 0xAF, 0xAC, 0xD1, 0xAE, 0xAE, 0xC6, 0xBF, 0xFA, 0x6E, 0x45, 0xDE, 0xC7, 0xF8, 0x2D, 0xE2, 0x3A, 0x9B, 0xF8, 0x1F, 0x83, 0x45, 0x28, 0x60, 0xAD, 0x27, 0xC2, 0x02, 0x32, 0xE5, 0x2F, 0x78, 0x52, 0xB3, 0x3F, 0x57, 0x28, 0xDD, 0x78, 0xB2, 0xB8, 0xCA, 0xAE, 0xEB, 0xB9, 0x09, 0xF6, 0xBE, 0x69, 0x7C, 0x93, 0x7B, 0xC6, 0x9B, 0xE3, 0x77, 0x75, 0x35, 0x0E, 0x7C, 0x0B, 0xB6, 0x13, 0xF8, 0xE4, 0x2C, 0x04, 0x91, 0x80, 0xE5, 0x67, 0x31, 0x93, 0xFF, 0x90, 0x90, 0x31, 0x07, 0xA6, 0x3F, 0x6B, 0x5A, 0x7F, 0x0E, 0x1D, 0x0A, 0xE8, 0x67, 0xEB, 0xB0, 0x3F, 0xAB, 0xC9, 0xBF, 0x41, 0xAD, 0xE2, 0x6A, 0x44, 0xAF, 0x42, 0x93, 0x9F, 0xD7, 0x6A, 0x35, 0x12, 0x88, 0x4B, 0x99, 0xEC, 0x55, 0x91, 0x62, 0x1D, 0xDF, 0x9D, 0x80, 0x21, 0xDC, 0xBF, 0x56, 0x2D, 0x8C, 0x05, 0x31, 0xC7, 0x0C, 0x30, 0x06, 0x66, 0x03, 0x38, 0x7A, 0x37, 0x76, 0x2A, 0xBF, 0xDD, 0x64, 0x31, 0x9F, 0xB2, 0x76, 0x4C, 0x26, 0x60, 0x18, 0xA2, 0x7E, 0x02, 0x95, 0x8F, 0x2C, 0x4E, 0x02, 0x33, 0x1F, 0x75, 0x1C, 0x01, 0xBA, 0x17, 0x7C, 0xE5, 0xEA, 0xCB, 0x8E, 0x04, 0x88, 0x3B, 0xF0, 0x60, 0x77, 0x8B, 0x4C, 0x0F, 0x40, 0x0E, 0xA0, 0x83, 0x57, 0xD4, 0x1E, 0xAB, 0xE9, 0xCF, 0x35, 0x94, 0x65, 0xDB, 0x5D, 0xAC, 0x57, 0x76, 0xCF, 0x2E, 0x67, 0x47, 0x6D, 0x1F, 0x4B, 0x1D, 0x5B, 0xA7, 0x70, 0x32, 0xE6, 0x79, 0x27, 0xAC, 0x71, 0x04, 0xB0, 0x7B, 0xE7, 0x53, 0x33, 0xA9, 0xDC, 0x0D, 0x81, 0x39, 0x40, 0x3A, 0x20, 0x57, 0xF7, 0xD9, 0xA0, 0x27, 0xF5, 0xF1, 0x1F, 0x4E, 0xED, 0x66, 0xDE, 0xBC, 0x0D, 0x50, 0x12, 0xE5, 0x55, 0x60, 0xDE, 0x55, 0x86, 0x0E, 0xE3, 0xFA, 0x8B, 0xF7, 0xC9, 0x7D, 0x54, 0xEB, 0x04, 0x8A, 0xF8, 0xB4, 0xCE, 0x93, 0xBA, 0xEB, 0x0E, 0xFC, 0x00, 0xCA, 0x87, 0xFA, 0x5F, 0x75, 0x2C, 0x78, 0xF3, 0xDD, 0x09, 0xD2, 0x7E, 0xB7, 0x76, 0x0D, 0xDB, 0x2A, 0xEC, 0x80, 0xDB, 0xB2, 0xE4, 0x0E, 0x4B, 0x99, 0x6C, 0x83, 0x05, 0x45, 0xF2, 0x65, 0x9E, 0xAB, 0xB3, 0xC3, 0xD8, 0x15, 0x96, 0xE2, 0xDF, 0x26, 0xFD, 0xA4, 0x3A, 0x0A, 0x0F, 0x60, 0xF4, 0xCF, 0x3A, 0x3D, 0xCE, 0x80, 0x3A, 0x4C, 0x32, 0xB9, 0x5B, 0xEC, 0xEE, 0xDB, 0x1D, 0xBB, 0xEC, 0x6F, 0x06, 0x1A, 0x43, 0x32, 0xD2, 0xAF, 0x43, 0xF7, 0x3C, 0x9E, 0x9E, 0x94, 0x3B, 0x66, 0x2A, 0x09, 0x58, 0x00, 0xAE, 0xFC, 0xB4, 0x18, 0xC0, 0x65, 0x31, 0x00, 0xA3, 0xA4, 0xAC, 0x95, 0xD7, 0xFA, 0x54, 0xB2, 0x0F, 0xC0, 0x94, 0x01, 0x7E, 0xE2, 0x0A, 0x7F, 0x9C, 0x56, 0x63, 0x6D, 0x01, 0x77, 0xA9, 0x80, 0x6B, 0xD2, 0x15, 0x55, 0x08, 0xA9, 0x48, 0x20, 0x50, 0xC7, 0x8A, 0x29, 0xB1, 0x29, 0x87, 0x68, 0x5D, 0x26, 0x1C, 0x6B, 0xF9, 0x3D, 0xE0, 0x2A, 0x0F, 0xB8, 0x9C, 0x6F, 0x94, 0x3C, 0x17, 0xC0, 0xB9, 0x51, 0x14, 0x60, 0x0E, 0x9C, 0x37, 0xA6, 0xA7, 0xF2, 0xE7, 0x88, 0x13, 0xDE, 0xB7, 0x29, 0x16, 0xC3, 0xF4, 0xED, 0xF5, 0x91, 0xBC, 0xE7, 0x7A, 0x56, 0x48, 0x18, 0x3E, 0xDD, 0xFD, 0xD5, 0xB9, 0x90, 0x01, 0x4D, 0xF8, 0xA2, 0xFE, 0xAB, 0x15, 0x74, 0xFE, 0x57, 0x6F, 0x41, 0x07, 0x4E, 0x00, 0x7A, 0xE5, 0x97, 0xC0, 0x6A, 0x68, 0x8F, 0x37, 0x7B, 0x51, 0xB2, 0x63, 0xEB, 0xED, 0x47, 0xCF, 0x0B, 0xCC, 0xCC, 0xD5, 0x5C, 0x86, 0xE6, 0x47, 0x20, 0xFC, 0x86, 0x9F, 0xC9, 0x37, 0x02, 0xCA, 0x85, 0xA1, 0xF0, 0x05, 0x5F, 0x6D, 0x89, 0x0D, 0xB6, 0x96, 0x50, 0xED, 0x05, 0xD0, 0x7D, 0x18, 0x07, 0x10, 0x01, 0x66, 0x4F, 0x73, 0xC6, 0xD6, 0x10, 0xFB, 0x49, 0xF4, 0x2D, 0x3C, 0x67, 0x91, 0x47, 0x3E, 0xA7, 0x88, 0xC6, 0x06, 0xA5, 0x7E, 0x4B, 0x4C, 0x1C, 0x5E, 0x8D, 0x02, 0x48, 0x01, 0xC2, 0x17, 0xB6, 0x98, 0x3B, 0x3D, 0xAB, 0xA8, 0x59, 0xE4, 0xC0, 0xF9, 0x74, 0xB3, 0xD4, 0xBC, 0x35, 0x85, 0x45, 0x1E, 0x49, 0x29, 0x1A, 0x2D, 0xB1, 0xAA, 0x69, 0x6D, 0x69, 0x7B, 0xA0, 0x90, 0xDF, 0xF2, 0xB7, 0xA6, 0x9A, 0x25, 0x7E, 0x5D, 0x1D, 0x9B, 0xC0, 0xF8, 0x4A, 0xEE, 0x06, 0x83, 0x79, 0x9F, 0x8C, 0x35, 0x76, 0x9E, 0xCC, 0xAB, 0xF6, 0x2E, 0xFE, 0xBA, 0x49, 0x14, 0xD0, 0x07, 0x08, 0x07, 0xC4, 0x6E, 0xC1, 0x15, 0xE6, 0x1B, 0x0B, 0xDD, 0x7A, 0x57, 0xBB, 0xB8, 0xC3, 0x37, 0xD7, 0x89, 0xA9, 0x4C, 0xA7, 0xE9, 0xE0, 0x3E, 0x05, 0x88, 0x2C, 0x12, 0xE0, 0xF2, 0x3D, 0xBE, 0x38, 0x1F, 0xC4, 0x2D, 0x5D, 0x34, 0x6B, 0x51, 0x5B, 0xA8, 0xF0, 0x21, 0xE0, 0x03, 0xA8, 0xDC, 0xEA, 0xD7, 0xF6, 0x67, 0xB5, 0x42, 0xF2, 0xB2, 0x39, 0x24, 0x35, 0x33, 0x11, 0x90, 0xEF, 0xC1, 0x79, 0xA5, 0x02, 0xEE, 0xCE, 0x8D, 0xE2, 0x45, 0x2A, 0x06, 0x0E, 0xF6, 0x02, 0xFF, 0x1E, 0x70, 0xF5, 0x55, 0x53, 0x52, 0x7D, 0x82, 0xEC, 0xED, 0xB8, 0x92, 0xFB, 0xCE, 0xFD, 0x30, 0x80, 0x9A, 0x08, 0x3D, 0x8B, 0xB3, 0x67, 0xB5, 0xD9, 0x98, 0xD5, 0xA6, 0xC7, 0xB2, 0xB8, 0xDD, 0x9B, 0x6D, 0x35, 0xF6, 0xA2, 0xC2, 0x3C, 0x07, 0x6A, 0x65, 0xED, 0x94, 0xB7, 0x64, 0xF8, 0xE4, 0x56, 0x12, 0xB2, 0xC5, 0xE3, 0xDA, 0x56, 0xA0, 0xFB, 0x96, 0xCF, 0x31, 0xFA, 0x4D, 0x06, 0x08, 0x05, 0xFC, 0xF0, 0x21, 0xFF, 0x19, 0x01, 0x6D, 0xC0, 0x7D, 0xA7, 0x50, 0xD2, 0x66, 0x8D, 0xCC, 0xDB, 0xA7, 0xCC, 0x78, 0x97, 0x1F, 0x48, 0x53, 0x6B, 0xB4, 0xE5, 0x26, 0x64, 0xD4, 0xEF, 0x0B, 0x86, 0x06, 0x04, 0x5D, 0xF5, 0x37, 0x3F, 0xA7, 0x6F, 0x55, 0xD2, 0x66, 0x15, 0xE1, 0xB3, 0xE8, 0xC7, 0x9F, 0x74, 0x84, 0xE3, 0xC8, 0xB8, 0x89, 0xF8, 0x40, 0xFB, 0x42, 0x00, 0x68, 0x07, 0xEC, 0xA2, 0x1F, 0x9B, 0xE4, 0x91, 0x5B, 0x89, 0x1E, 0xBB, 0x83, 0x84, 0x3C, 0xCA, 0xD6, 0xB1, 0xC6, 0xCE, 0x7C, 0xAB, 0x39, 0x82, 0xA1, 0x9C, 0x05, 0xB3, 0x08, 0xE4, 0x71, 0x8A, 0xD4, 0x22, 0x72, 0x21, 0x40, 0x1E, 0xB6, 0x6C, 0x01, 0x9E, 0x88, 0x69, 0x01, 0xA6, 0xFB, 0x70, 0x00, 0x77, 0xE0, 0x2C, 0x34, 0xF6, 0x95, 0xA6, 0xD1, 0x70, 0x38, 0xF3, 0x1E, 0xDC, 0xEA, 0xCC, 0x98, 0xE2, 0xBF, 0x26, 0xA4, 0x3A, 0xDA, 0x46, 0x3E, 0x63, 0x7E, 0x33, 0x58, 0x60, 0x33, 0xAF, 0xBB, 0x9B, 0x54, 0xF6, 0x47, 0xCE, 0xFB, 0x6C, 0x49, 0xC1, 0xD9, 0xC4, 0x6D, 0xD3, 0xFD, 0xD2, 0x0D, 0x50, 0x0E, 0xD8, 0x0B, 0x50, 0x79, 0x87, 0x16, 0x55, 0x26, 0xE1, 0xA9, 0x85, 0x4B, 0x99, 0x5D, 0x59, 0x56, 0x2E, 0xC5, 0x7E, 0xD0, 0x67, 0x9D, 0x2B, 0xDD, 0xF9, 0xCB, 0xAF, 0x62, 0x80, 0x3A, 0x70, 0x9A, 0xE1, 0xFE, 0x45, 0x2E, 0x02, 0xB8, 0x33, 0x36, 0x7E, 0x17, 0x72, 0xA0, 0x16, 0x31, 0x80, 0x1A, 0xCB, 0x69, 0x00, 0xD5, 0x5B, 0x42, 0xC0, 0x67, 0x6D, 0x56, 0xE8, 0xBC, 0x73, 0xF2, 0xB5, 0xD2, 0xC0, 0x4A, 0xEF, 0x5D, 0xF4, 0x98, 0xE0, 0xCF, 0x1D, 0xAC, 0x7A, 0x3A, 0xF9, 0xA6, 0x8E, 0x49, 0x02, 0x99, 0x6F, 0xD7, 0x2B, 0x0A, 0x8F, 0x58, 0xAE, 0x52, 0x09, 0x3C, 0x49, 0x10, 0xE6, 0x38, 0x80, 0xC9, 0xC2, 0x5F, 0x63, 0xED, 0x52, 0x1F, 0xFA, 0x0C, 0xB7, 0xDA, 0x1C, 0x7B, 0xDD, 0x61, 0x5A, 0xFD, 0xF6, 0xE3, 0xD2, 0xBD, 0xD5, 0xC5, 0x33, 0x18, 0x86, 0x61, 0xCC, 0x9D, 0x64, 0x0C, 0xAB, 0x74, 0x00, 0xAA, 0x74, 0x34, 0x2C, 0xCE, 0x7F, 0x28, 0x53, 0xAB, 0x03, 0xB5, 0xC8, 0x03, 0x28, 0xEF, 0x33, 0x0D, 0xA8, 0xDF, 0x93, 0x33, 0x0E, 0x6D, 0x26, 0x3F, 0x95, 0x50, 0x6D, 0xB9, 0x42, 0xEB, 0xC7, 0x0C, 0xBB, 0x48, 0x25, 0x16, 0x8A, 0x33, 0x6C, 0x45, 0x04, 0x7B, 0xB6, 0x30, 0xBD, 0x9B, 0x37, 0x83, 0x4B, 0x6C, 0xDF, 0xE6, 0xD3, 0x8A, 0x51, 0xD6, 0xC9, 0x48, 0x61, 0x73, 0x13, 0x20, 0x06, 0xC8, 0x4B, 0x09, 0x7D, 0xE3, 0x0A, 0xEE, 0x2B, 0x9F, 0x8A, 0x6D, 0xEF, 0x51, 0xED, 0xB0, 0x59, 0xA0, 0x21, 0x2F, 0xAA, 0x63, 0x2E, 0x95, 0xDF, 0x84, 0xE9, 0x9F, 0x5C, 0x6C, 0x7B, 0x2A, 0xD2, 0xAA, 0x00, 0x75, 0xE0, 0xE4, 0x42, 0xEE, 0x4F, 0x1E, 0x77, 0x54, 0x25, 0x06, 0xF0, 0x85, 0xD4, 0x1D, 0x63, 0xB1, 0xB8, 0x53, 0xC7, 0x23, 0x69, 0x34, 0xFD, 0x8D, 0x86, 0x8E, 0x8F, 0xBC, 0x7E, 0xD9, 0x55, 0x8D, 0x11, 0x2D, 0xC8, 0x32, 0x90, 0xFC, 0xE1, 0x48, 0xFF, 0x43, 0x6F, 0xFF, 0x5B, 0x32, 0x98, 0xA5, 0x24, 0x1C, 0x0D, 0xBE, 0xED, 0x8D, 0x3A, 0x57, 0xF4, 0x9C, 0xE3, 0x26, 0x16, 0x7D, 0x70, 0x53, 0xBB, 0xB0, 0x69, 0x29, 0xB9, 0xD9, 0xEC, 0xB9, 0x66, 0xCD, 0xDD, 0x55, 0x13, 0x29, 0x53, 0x50, 0x74, 0xDD, 0x21, 0x69, 0xB5, 0xFB, 0xC5, 0xDE, 0xF4, 0x75, 0xF7, 0x12, 0x5F, 0xD7, 0x78, 0xEC, 0x7D, 0xA2, 0x0A, 0x50, 0x07, 0xCE, 0x2C, 0x02, 0x90, 0x04, 0x92, 0x5D, 0x12, 0x0E, 0x30, 0xB3, 0x38, 0x40, 0x34, 0x20, 0x8A, 0x37, 0xE9, 0xBB, 0xA2, 0x48, 0xB7, 0x08, 0x6D, 0xC6, 0x28, 0xC1, 0xEA, 0x47, 0x0B, 0x70, 0xAA, 0x7F, 0x37, 0x33, 0xF3, 0x41, 0x3C, 0x01, 0x29, 0x7F, 0xD2, 0x56, 0xC8, 0xAE, 0xF3, 0xFC, 0x2F, 0x79, 0xCD, 0xE0, 0x15, 0x98, 0x8A, 0x82, 0xBC, 0x82, 0x36, 0x90, 0x0A, 0x3C, 0x5D, 0x88, 0x0C, 0x10, 0xFF, 0x28, 0xC9, 0x31, 0x58, 0xC6, 0xD4, 0xE2, 0x66, 0x02, 0xC3, 0xBE, 0x99, 0x38, 0x58, 0xF1, 0xBA, 0x18, 0x77, 0x1F, 0xF5, 0x93, 0x77, 0x33, 0xEC, 0x63, 0x0B, 0xD9, 0x87, 0x06, 0x54, 0x2D, 0x72, 0xF1, 0x91, 0xA5, 0xC8, 0xBE, 0x0B, 0x65, 0xC7, 0x81, 0x4C, 0x40, 0x17, 0x47, 0x00, 0x5D, 0x4C, 0x3F, 0xD3, 0x13, 0x69, 0x09, 0x51, 0x02, 0x73, 0x75, 0xFF, 0x8B, 0xC2, 0xDF, 0x89, 0x31, 0xA5, 0xC8, 0xDD, 0x34, 0x45, 0xAA, 0x78, 0xD4, 0xCF, 0xF5, 0xB2, 0xF9, 0x45, 0xD1, 0xDF, 0x53, 0x9A, 0xF8, 0x73, 0xB4, 0xE6, 0xB5, 0x7A, 0x8D, 0xB0, 0x88, 0x04, 0x74, 0xEE, 0x36, 0xEC, 0xD3, 0xC0, 0xE3, 0x91, 0xA5, 0xC7, 0x6A, 0xBD, 0xDA, 0x76, 0xDE, 0x42, 0xCE, 0x3D, 0xE2, 0xCE, 0x93, 0x39, 0x6B, 0xCC, 0x37, 0xF6, 0xDB, 0x57, 0x9D, 0x8F, 0x10, 0xDD, 0x7D, 0x0F, 0x17, 0x07, 0xD4, 0x16, 0x0D, 0x58, 0x02, 0xB5, 0x07, 0x57, 0x6F, 0x60, 0x02, 0x68, 0x05, 0x7C, 0x80, 0xA7, 0x22, 0xD7, 0xEE, 0x74, 0xFB, 0xCA, 0xC7, 0x6A, 0xF1, 0xAF, 0x07, 0xB5, 0x3E, 0xEC, 0x1C, 0xE0, 0xCE, 0x56, 0xA9, 0x8C, 0x13, 0xC4, 0xEA, 0x5A, 0x7A, 0x14, 0xCE, 0xB6, 0x1D, 0x79, 0x87, 0x8C, 0xEF, 0x0C, 0x79, 0x0A, 0xE0, 0xA2, 0xD2, 0x96, 0xC1, 0x7C, 0xDE, 0x0F, 0x00, 0xE9, 0xD7, 0x97, 0x91, 0x4F, 0x07, 0x8A, 0x30, 0xA0, 0xEB, 0x3D, 0x61, 0xF5, 0x8E, 0xB5, 0x7A, 0xF4, 0x1F, 0x75, 0x0D, 0x1B, 0xB1, 0x97, 0xF4, 0x37, 0x4A, 0x12, 0x8F, 0xA3, 0x7F, 0x3E, 0x62, 0x7E, 0x35, 0x40, 0x9F, 0x85, 0x2E, 0x02, 0x18, 0xA7, 0x4B, 0x63, 0x2D, 0x93, 0x40, 0x38, 0xE0, 0xC2, 0x87, 0xB7, 0xDE, 0xA9, 0x1E, 0x80, 0x3F, 0xB3, 0x7E, 0xAC, 0x96, 0x57, 0x8B, 0x9F, 0x58, 0x99, 0x13, 0xEB, 0x82, 0x7E, 0x40, 0xAE, 0x13, 0x7E, 0x66, 0x7B, 0x6A, 0x2A, 0xF4, 0xEC, 0xCA, 0xFF, 0x63, 0x86, 0xEA, 0x25, 0x03, 0x82, 0x8C, 0x80, 0xFD, 0xA2, 0x8B, 0x69, 0x20, 0xA9, 0xFA, 0x70, 0x80, 0xF3, 0x66, 0xD5, 0x22, 0x16, 0x75, 0x8F, 0x3C, 0xD3, 0x2B, 0xAF, 0x4F, 0xFA, 0x4D, 0xDD, 0x8E, 0x67, 0x16, 0x06, 0xE7, 0xDD, 0x7F, 0x56, 0xB4, 0xD7, 0xA7, 0xFD, 0xCF, 0x2C, 0xEA, 0xFF, 0x71, 0x79, 0x2F, 0xE4, 0x13, 0x07, 0x74, 0x01, 0x44, 0x01, 0x93, 0xEF, 0xE5, 0xB3, 0xEA, 0x57, 0xF9, 0xE3, 0xA7, 0xE0, 0x62, 0xD5, 0xC2, 0x05, 0xD1, 0xEB, 0x0A, 0xB4, 0xAB, 0xDB, 0x16, 0xF6, 0x35, 0x52, 0x6B, 0xD1, 0xEE, 0x4D, 0xF4, 0x73, 0x63, 0xF7, 0x7A, 0xAF, 0x20, 0x32, 0x8F, 0x2E, 0xFB, 0xD3, 0x7C, 0x46, 0x00, 0x17, 0x56, 0xC5, 0xDE, 0xCD, 0x79, 0xF9, 0x26, 0x53, 0xD5, 0x0C, 0x6F, 0xF2, 0x95, 0x85, 0x3F, 0x5E, 0xEE, 0xA7, 0x4F, 0x20, 0xDD, 0x92, 0xBD, 0x76, 0xA5, 0xFE, 0x1B, 0x30, 0x5C, 0x23, 0x35, 0x16, 0x0D, 0x58, 0x2C, 0x06, 0xF0, 0xC5, 0xEC, 0xDC, 0x2F, 0x65, 0x76, 0xF4, 0x7F, 0xE9, 0x75, 0x70, 0x15, 0x56, 0x7C, 0xA2, 0xF2, 0xE2, 0x9F, 0xD1, 0x7A, 0x45, 0x0F, 0x67, 0x65, 0xB6, 0x12, 0xF1, 0x0C, 0xFD, 0xC5, 0xA2, 0xA2, 0x63, 0xB6, 0xB2, 0x43, 0x56, 0xA9, 0xB6, 0x71, 0x3F, 0xFC, 0xF8, 0xBC, 0xCF, 0x33, 0x3F, 0xEF, 0x4C, 0x35, 0x4A, 0xC5, 0x2D, 0x7E, 0x0B, 0x04, 0x60, 0x1B, 0x2B, 0xCE, 0xBD, 0xCD, 0xD7, 0xC2, 0x04, 0x0F, 0x8F, 0xC1, 0x4C, 0xD4, 0xCB, 0x32, 0x96, 0x89, 0x9E, 0x3B, 0xC9, 0xB9, 0x9B, 0x21, 0x63, 0xBA, 0x38, 0xEF, 0x96, 0x29, 0xB4, 0x64, 0x0C, 0x30, 0x75, 0xAB, 0xBC, 0xAA, 0x2C, 0x12, 0xB0, 0x02, 0xFA, 0xDC, 0x8E, 0xD2, 0xB3, 0x9F, 0x66, 0x11, 0x0D, 0x9C, 0x6F, 0xB7, 0x1A, 0xB9, 0xFB, 0xDA, 0x57, 0xCD, 0xBF, 0x82, 0x8B, 0x00, 0x91, 0x8C, 0x81, 0x13, 0x57, 0xCF, 0xDD, 0xCF, 0xD2, 0xA4, 0xF1, 0x27, 0x75, 0x53, 0xBD, 0xFC, 0x12, 0x25, 0xAD, 0xC7, 0x6A, 0x4A, 0xA9, 0x72, 0xA6, 0x5C, 0x33, 0xE1, 0x77, 0x6D, 0x18, 0x06, 0x38, 0x6B, 0x82, 0xED, 0xEE, 0x29, 0xC9, 0x4E, 0x88, 0x4F, 0x32, 0x1D, 0x8F, 0xF3, 0x14, 0x84, 0xD3, 0x3B, 0xB7, 0x6D, 0xFA, 0xEF, 0xB0, 0x35, 0x8F, 0x60, 0x45, 0x35, 0x40, 0xD7, 0x04, 0xF5, 0x8E, 0xAC, 0x80, 0x14, 0xA0, 0x0A, 0x68, 0x03, 0xC6, 0xAF, 0x1D, 0x5B, 0x9E, 0x64, 0x97, 0x6C, 0x20, 0x94, 0x0F, 0x19, 0xB7, 0x04, 0x74, 0xE1, 0xFB, 0xA6, 0xF1, 0x52, 0xD0, 0x50, 0xEF, 0x32, 0x17, 0x1C, 0xBD, 0x15, 0x97, 0xA5, 0x1C, 0x24, 0x0C, 0x85, 0xCD, 0xBA, 0xE8, 0x65, 0x1B, 0xDA, 0xFB, 0x06, 0xD1, 0x87, 0xDA, 0x7D, 0x4C, 0x8E, 0xA4, 0xF7, 0x96, 0xCD, 0xE3, 0xD7, 0x06, 0xB9, 0xD9, 0xE7, 0xB9, 0x13, 0x2C, 0x16, 0x14, 0xB7, 0x8D, 0x5B, 0x7E, 0xD9, 0x1B, 0x78, 0xF2, 0xD4, 0xAF, 0x02, 0x7C, 0x7B, 0x3C, 0x8F, 0xC7, 0x79, 0xF5, 0xE6, 0x20, 0xB9, 0x2A, 0xF9, 0xF4, 0x53, 0x23, 0x36, 0x71, 0x3E, 0xFD, 0xFB, 0x9D, 0x6F, 0x2E, 0x98, 0x72, 0xBF, 0xF0, 0xB9, 0xCF, 0xC0, 0x39, 0x40, 0x04, 0xA0, 0x79, 0x4F, 0x53, 0x3F, 0xB7, 0x5E, 0x45, 0x18, 0x8D, 0x86, 0xEA, 0xCF, 0xE8, 0x6D, 0x89, 0xED, 0x86, 0xE6, 0x29, 0xA6, 0x90, 0xF9, 0xC2, 0xF1, 0x6C, 0xCA, 0x14, 0x0B, 0xBA, 0xB2, 0x44, 0x32, 0x2F, 0x3F, 0xE4, 0x37, 0xBC, 0xC2, 0xE8, 0xA7, 0xD1, 0x73, 0xF0, 0x94, 0x46, 0xA4, 0x03, 0xAD, 0x80, 0x3E, 0x22, 0x72, 0x80, 0x04, 0xD0, 0xCD, 0xB4, 0xB0, 0xB5, 0x36, 0x2F, 0x17, 0xE7, 0xAE, 0xD5, 0x16, 0x96, 0x5C, 0x29, 0x46, 0x15, 0x57, 0xD1, 0x06, 0x7C, 0x80, 0x72, 0xA0, 0x15, 0xA8, 0x5C, 0xC4, 0xFD, 0xA9, 0xED, 0xAA, 0xFE, 0x79, 0x85, 0x56, 0x00, 0x3D, 0x77, 0xB2, 0x82, 0x07, 0x70, 0xAE, 0xD3, 0x0E, 0x2A, 0x40, 0x68, 0x35, 0xFD, 0x9D, 0xD2, 0x2C, 0x1A, 0xD7, 0xF3, 0xB2, 0xD5, 0xBC, 0x9B, 0x4B, 0x0E, 0xA0, 0x77, 0xC4, 0x48, 0x1B, 0x54, 0x57, 0x87, 0x12, 0x0A, 0xB7, 0xCB, 0x3B, 0xAF, 0xFF, 0x3D, 0x55, 0x1A, 0x0C, 0x85, 0x33, 0xC8, 0xF4, 0x56, 0xA0, 0xB6, 0xE8, 0x3A, 0x6D, 0xFD, 0x41, 0xF2, 0x16, 0x1C, 0x6C, 0x96, 0xCB, 0x93, 0x37, 0xDC, 0x6C, 0x78, 0x46, 0x77, 0xE4, 0x1A, 0xB4, 0x76, 0x50, 0x72, 0xAD, 0x82, 0xA3, 0xE3, 0x72, 0xFD, 0x04, 0xAF, 0x95, 0xC3, 0xDE, 0x46, 0xF7, 0x7D, 0xB2, 0x03, 0xE0, 0x55, 0x55, 0xE4, 0xCE, 0x8B, 0xF7, 0x02, 0x26, 0x81, 0x76, 0xC0, 0x87, 0xFD, 0x22, 0x81, 0x30, 0xA0, 0x82, 0xAF, 0xD0, 0x68, 0x28, 0x2A, 0x10, 0xCD, 0x0D, 0x0B, 0x3B, 0x16, 0xE1, 0x8A, 0xDF, 0x06, 0x3F, 0x39, 0xAB, 0x4B, 0x29, 0xFB, 0xEF, 0x3F, 0x1B, 0x4E, 0x46, 0x22, 0x4C, 0xAC, 0xD1, 0xF2, 0x73, 0x01, 0x55, 0x5B, 0x33, 0xC7, 0x86, 0x04, 0x72, 0x57, 0xF6, 0x6A, 0xA0, 0xF7, 0x02, 0xCB, 0x1E, 0xF7, 0x5D, 0x80, 0x34, 0xD0, 0x0A, 0xFB, 0x50, 0x95, 0xF1, 0xEA, 0x7C, 0xA3, 0xFD, 0x08, 0x84, 0x6A, 0x70, 0x26, 0xAF, 0x45, 0x04, 0xD6, 0xEA, 0x5C, 0xD8, 0xED, 0x3E, 0x97, 0x03, 0xE4, 0x9A, 0xE2, 0x1C, 0x40, 0x12, 0xB0, 0x03, 0x14, 0x9B, 0x22, 0xED, 0xC8, 0xFE, 0xAB, 0x84, 0x00, 0x52, 0x80, 0x27, 0x7B, 0x32, 0x81, 0x31, 0x7A, 0x09, 0x68, 0x34, 0x47, 0x92, 0xD5, 0xF4, 0xCE, 0xC1, 0xC0, 0xBF, 0x4E, 0x0E, 0xB2, 0x4C, 0x2C, 0x60, 0x49, 0xF3, 0xD5, 0xF7, 0xAD, 0xAD, 0x09, 0xA8, 0x37, 0x43, 0xF1, 0x0C, 0x50, 0x73, 0xF5, 0x1A, 0x5F, 0xC7, 0xC5, 0x13, 0x67, 0xA7, 0x50, 0xAB, 0x3E, 0xCD, 0x40, 0x9C, 0x9D, 0x63, 0x0B, 0xD0, 0xFD, 0x19, 0xBC, 0x20, 0x0E, 0x0B, 0x7A, 0x3E, 0x9F, 0x22, 0xE8, 0x9B, 0x5C, 0xF7, 0xA5, 0xDE, 0xC3, 0x6E, 0x14, 0x86, 0x4C, 0x2A, 0xB4, 0xCA, 0x9A, 0xD5, 0x00, 0x77, 0x20, 0x0C, 0xC8, 0x00, 0xCA, 0x00, 0xD8, 0x65, 0xDD, 0xE6, 0x28, 0x7D, 0x00, 0x52, 0x81, 0x70, 0x40, 0x9F, 0x0A, 0x29, 0x20, 0x14, 0xA8, 0x7D, 0xB3, 0x1E, 0x9B, 0x05, 0xFC, 0x80, 0xD6, 0x2B, 0x23, 0x06, 0x1D, 0xB0, 0xB7, 0x7A, 0x16, 0xBF, 0x9E, 0xB6, 0x19, 0x53, 0x03, 0x4B, 0x18, 0xAC, 0xD4, 0x14, 0xEF, 0x03, 0xFA, 0xD5, 0x72, 0xC5, 0x38, 0x5D, 0x4B, 0x98, 0xBC, 0xC2, 0x08, 0xBF, 0xE5, 0x12, 0x08, 0xA3, 0xCE, 0x2B, 0x20, 0x0A, 0x74, 0xAC, 0x26, 0x64, 0xAF, 0x1A, 0x6E, 0xBF, 0x9D, 0x9F, 0xD9, 0x6C, 0xBB, 0x9F, 0x46, 0x28, 0xB2, 0x36, 0x93, 0x4F, 0xBA, 0xCC, 0xC9, 0x0F, 0xD6, 0x09, 0x36, 0x44, 0x2E, 0xFA, 0xD6, 0xEA, 0xA0, 0x16, 0x0D, 0xF3, 0xBC, 0x29, 0xFC, 0x33, 0x8B, 0x48, 0xE0, 0x1C, 0xBE, 0x79, 0x8B, 0xC9, 0x8C, 0xD2, 0x66, 0xF9, 0x24, 0xFF, 0xFF, 0x14, 0xCC, 0x54, 0xE5, 0xAD, 0x29, 0x90, 0xF2, 0x41, 0xF0, 0xBD, 0x03, 0xBE, 0xD7, 0x82, 0x73, 0x22, 0x20, 0x1A, 0x9C, 0x7D, 0xD5, 0x5F, 0xD2, 0x76, 0x30, 0xDE, 0xD3, 0xC1, 0x28, 0x1D, 0x16, 0xA9, 0x75, 0xE1, 0xD5, 0x0A, 0x78, 0xD4, 0xCA, 0xB7, 0xD6, 0xC6, 0x2E, 0xEB, 0xC0, 0x30, 0x89, 0x64, 0x01, 0xB8, 0x38, 0xD6, 0xBD, 0x57, 0x02, 0xBF, 0x87, 0xD6, 0xB6, 0xBE, 0x79, 0x7B, 0x24, 0x85, 0xAE, 0x67, 0x7C, 0xBD, 0x60, 0x0E, 0x6F, 0x24, 0xA4, 0x30, 0x0A, 0x78, 0x06, 0xA8, 0x02, 0x6A, 0x80, 0xCC, 0xA2, 0x01, 0x0B, 0xA0, 0x9F, 0x7E, 0x3F, 0x40, 0xCD, 0x22, 0x81, 0x14, 0xC0, 0x02, 0xD0, 0x03, 0xB0, 0xFB, 0x8F, 0x0E, 0x8D, 0x56, 0x2B, 0xD9, 0x72, 0x2B, 0x9B, 0xE4, 0x55, 0x76, 0xDF, 0x88, 0x18, 0xA0, 0xBF, 0x90, 0xFF, 0x8B, 0x83, 0xA9, 0x8A, 0x44, 0x81, 0x3D, 0x69, 0x5C, 0x8D, 0x7E, 0x28, 0x9A, 0x11, 0x40, 0x6C, 0x43, 0x8C, 0x84, 0x33, 0x1A, 0x96, 0x50, 0x20, 0x0E, 0xEC, 0x59, 0x06, 0x1C, 0x59, 0xF0, 0x61, 0x00, 0xF8, 0xBD, 0xDD, 0xE4, 0x23, 0xD7, 0x74, 0x7B, 0x9F, 0x70, 0x7F, 0x84, 0x38, 0xE8, 0xE8, 0xCC, 0x58, 0x61, 0xA3, 0xDA, 0xC4, 0xC9, 0xF5, 0x00, 0x45, 0x02, 0x62, 0x00, 0x45, 0x8F, 0xA6, 0x6F, 0x5F, 0x51, 0xE4, 0xFE, 0xC2, 0x00, 0x65, 0x40, 0x26, 0xE0, 0x07, 0xAF, 0xCC, 0x00, 0x65, 0xC0, 0xAC, 0x73, 0xF0, 0x1C, 0xDA, 0xAC, 0xD9, 0x04, 0xEF, 0xB2, 0x99, 0xB4, 0x21, 0x43, 0x29, 0xF4, 0x37, 0x59, 0xA4, 0xFC, 0xE7, 0xFC, 0x28, 0x45, 0x12, 0x7D, 0xA9, 0xBC, 0x62, 0xAE, 0x29, 0xAF, 0x22, 0x9C, 0x30, 0x92, 0x32, 0x18, 0xE6, 0xB9, 0xC7, 0x9D, 0x42, 0xE0, 0x1C, 0x23, 0x6B, 0x00, 0x37, 0x3C, 0x0C, 0xC1, 0x00, 0xEB, 0xC0, 0x27, 0xE4, 0x9D, 0xED, 0x35, 0xA6, 0xD6, 0xBB, 0x5B, 0xEB, 0x0F, 0xC9, 0x82, 0x5D, 0x72, 0xE7, 0x5A, 0x34, 0x46, 0x6B, 0xD8, 0x13, 0x3E, 0xB0, 0x9D, 0xD4, 0x18, 0x60, 0xD8, 0xA2, 0x31, 0x06, 0x17, 0x96, 0x0B, 0x59, 0x1C, 0xC0, 0x03, 0x98, 0x58, 0xAF, 0xF0, 0xA1, 0x4E, 0x2C, 0x70, 0x0A, 0x0F, 0x3B, 0x80, 0x30, 0xC0, 0x16, 0x51, 0x78, 0x25, 0x92, 0x36, 0x1B, 0xB4, 0xF9, 0x09, 0xC7, 0xF7, 0x33, 0x34, 0x8D, 0x6A, 0x33, 0x64, 0xA7, 0xC6, 0x0A, 0xF3, 0xAB, 0x42, 0xC9, 0x7F, 0x0C, 0xBD, 0xBA, 0xDD, 0xA8, 0xD0, 0xF1, 0x11, 0x07, 0xF3, 0x37, 0x9B, 0x77, 0xFE, 0x4A, 0x49, 0xA2, 0x80, 0x5E, 0xB0, 0x29, 0x03, 0xFD, 0x64, 0xD6, 0x97, 0xD0, 0x60, 0xE7, 0xB9, 0x75, 0x19, 0x73, 0xF0, 0x29, 0x28, 0x47, 0xFF, 0x9E, 0x96, 0xE2, 0xC9, 0xCA, 0x48, 0x01, 0xCE, 0x22, 0xEC, 0x6E, 0x28, 0xD0, 0x72, 0x1F, 0xC4, 0xAC, 0x01, 0x5F, 0x44, 0xFF, 0x57, 0xDC, 0x53, 0x80, 0xD3, 0xFB, 0xD0, 0x6E, 0xB9, 0xCD, 0x4E, 0xEA, 0xD2, 0x7E, 0xD5, 0x13, 0xDE, 0x46, 0xC6, 0xB5, 0x01, 0xE1, 0xC4, 0xF5, 0xF0, 0x6A, 0xF3, 0xA3, 0x13, 0xBF, 0xDB, 0xC1, 0xCC, 0x0A, 0x7A, 0xBA, 0xFF, 0xAC, 0x45, 0xAB, 0xC5, 0xE3, 0x51, 0xEB, 0x5B, 0x15, 0xA6, 0x92, 0xBE, 0x0B, 0xA0, 0x03, 0x30, 0x06, 0x63, 0xCF, 0xA7, 0x89, 0xEB, 0xF5, 0x0B, 0x74, 0xFC, 0xF0, 0xC6, 0xD3, 0x8F, 0x2C, 0x45, 0x09, 0xB3, 0xE5, 0xE9, 0x91, 0xA0, 0xF3, 0xE1, 0x96, 0x6F, 0xCD, 0xBA, 0x7D, 0x17, 0xBE, 0x30, 0x05, 0xB4, 0x17, 0x09, 0xD8, 0x01, 0xF2, 0xD3, 0x71, 0xBC, 0x05, 0xC8, 0x4F, 0x26, 0x6A, 0x2F, 0xBC, 0x6F, 0x8F, 0x65, 0xE4, 0x63, 0x35, 0x79, 0xAC, 0xD6, 0x0E, 0x7D, 0xA6, 0xDE, 0x64, 0x07, 0x5A, 0x0D, 0x41, 0x9B, 0x86, 0x20, 0x6D, 0x0E, 0x3C, 0x7F, 0xB8, 0x97, 0x1A, 0xFD, 0x90, 0x2E, 0x1F, 0xEF, 0xED, 0xA9, 0xFD, 0x86, 0x76, 0x47, 0x5A, 0x85, 0xA3, 0xC4, 0x01, 0xA6, 0x6F, 0xCE, 0xA7, 0x15, 0x96, 0x30, 0xB1, 0x9E, 0x09, 0xC7, 0xF5, 0xFE, 0x9E, 0x3F, 0x29, 0xB0, 0x75, 0x80, 0xE3, 0x77, 0x3B, 0xA4, 0x73, 0x00, 0x6D, 0x60, 0xE2, 0x93, 0x3C, 0xDA, 0x8B, 0x5C, 0xC4, 0x62, 0x00, 0xBA, 0x31, 0x55, 0x3F, 0xC2, 0xC1, 0x9F, 0x1E, 0x49, 0xE5, 0x80, 0x0B, 0x10, 0xF3, 0x28, 0xEB, 0xD0, 0x6A, 0xFA, 0x4B, 0xF2, 0x36, 0xA9, 0xDF, 0x16, 0x97, 0x27, 0xD1, 0xE3, 0xCF, 0x15, 0xA2, 0x9D, 0xAB, 0x9E, 0x60, 0x56, 0x3F, 0xEF, 0x9E, 0xE6, 0x20, 0x3A, 0xAD, 0x72, 0x7B, 0xD4, 0xCE, 0xA5, 0x9E, 0x80, 0x25, 0x96, 0xB7, 0x9B, 0x4B, 0xD2, 0x33, 0x02, 0x90, 0x4F, 0x83, 0x9E, 0x31, 0x20, 0xAE, 0xCE, 0xCD, 0xCC, 0xA7, 0x9C, 0xBF, 0x26, 0x16, 0x73, 0x57, 0x66, 0xF0, 0x5F, 0x9B, 0x5F, 0xA6, 0xFA, 0x1E, 0x4F, 0x8F, 0x30, 0x44, 0x00, 0xDD, 0x6B, 0xF4, 0x02, 0x4C, 0x16, 0x03, 0x78, 0x01, 0x1D, 0xB7, 0xFA, 0x2B, 0x1D, 0xAE, 0xCF, 0x43, 0x05, 0xCE, 0xBE, 0x99, 0xFD, 0xF1, 0xDE, 0x16, 0xAD, 0xF6, 0xD6, 0xAC, 0xB4, 0xE2, 0xE4, 0x9A, 0x89, 0xCB, 0xF9, 0xEF, 0xD0, 0xA7, 0x89, 0x01, 0x8F, 0xB1, 0x56, 0x66, 0x06, 0xAD, 0x0A, 0x7B, 0x67, 0xE6, 0xA3, 0xD8, 0x21, 0x4F, 0x86, 0xAA, 0xFB, 0x5D, 0x33, 0xAD, 0x0A, 0x18, 0xFF, 0xA8, 0xBC, 0x07, 0x92, 0x5F, 0xEA, 0x18, 0xF9, 0x78, 0x4C, 0x7B, 0xDF, 0xE4, 0x17, 0xA5, 0x7B, 0xB0, 0x68, 0x99, 0x03, 0x88, 0xEC, 0x58, 0x6B, 0xE0, 0x08, 0xA0, 0x09, 0x74, 0xFE, 0x57, 0x86, 0xB2, 0x7D, 0x50, 0x9F, 0x82, 0x82, 0x8F, 0x98, 0x87, 0x9D, 0xFF, 0xCA, 0x57, 0x2E, 0xC0, 0xE3, 0x79, 0x85, 0x56, 0x73, 0x88, 0x95, 0x1B, 0xAE, 0x53, 0x66, 0x0A, 0x77, 0xC7, 0x89, 0xAB, 0x9D, 0xC8, 0x29, 0x59, 0x6F, 0x09, 0xC5, 0x52, 0x9C, 0x19, 0x91, 0x9F, 0x82, 0x9F, 0x6B, 0xFA, 0xC9, 0x06, 0x7D, 0x9E, 0xF4, 0xA0, 0xA1, 0x27, 0xFB, 0x69, 0x60, 0xD1, 0xBC, 0x30, 0x52, 0x08, 0x29, 0x81, 0x6A, 0x5E, 0x26, 0xF7, 0x95, 0xFD, 0xE4, 0xEC, 0xE1, 0xF1, 0x36, 0x7D, 0x9F, 0xA7, 0xA3, 0x90, 0xD5, 0xED, 0xFF, 0x8F, 0xBE, 0x3A, 0xB3, 0x01, 0x58, 0x47, 0x81, 0x6C, 0xA0, 0x16, 0xF3, 0x78, 0xBC, 0xD8, 0xDC, 0xEB, 0x00, 0x51, 0x80, 0x5F, 0x0F, 0x11, 0x0C, 0xB9, 0xBC, 0x9A, 0xDE, 0x1F, 0xEF, 0xD0, 0xC4, 0xEF, 0xCA, 0xDE, 0x15, 0x10, 0x1C, 0x63, 0x26, 0x77, 0xF5, 0x15, 0xD7, 0xD3, 0xB4, 0x75, 0x01, 0x0E, 0xDC, 0x3A, 0x77, 0x6E, 0x5F, 0xCB, 0xE7, 0xF6, 0xE9, 0xBC, 0xDC, 0xF9, 0xDC, 0xDD, 0x03, 0x7A, 0xC1, 0x2C, 0x35, 0x96, 0xB0, 0x58, 0x6E, 0xEE, 0x99, 0xDF, 0xCD, 0x2A, 0xB2, 0x6F, 0x21, 0xBF, 0xD8, 0x5C, 0x01, 0x36, 0x12, 0x6E, 0x81, 0x25, 0x19, 0xB1, 0x4C, 0x66, 0xA2, 0x1D, 0x80, 0xCD, 0x54, 0x18, 0x17, 0x4E, 0x26, 0xD6, 0xEC, 0xEF, 0xA9, 0x02, 0xDE, 0x77, 0xA7, 0x2F, 0xCD, 0xBD, 0x92, 0x16, 0x50, 0x06, 0xA4, 0x02, 0xCA, 0x8C, 0x7C, 0x01, 0xB4, 0x80, 0xD0, 0x7D, 0x45, 0x68, 0xB4, 0x44, 0xAC, 0xB1, 0x14, 0x29, 0x18, 0x95, 0x38, 0x07, 0x76, 0xFE, 0x96, 0x15, 0xCD, 0x59, 0x49, 0xCB, 0xBE, 0x9C, 0xB8, 0x02, 0xD9, 0x43, 0x29, 0x18, 0xAD, 0xE2, 0xD3, 0x1C, 0x49, 0x1F, 0x5F, 0xA3, 0x53, 0x6A, 0x90, 0x0E, 0x92, 0xBB, 0xA5, 0x0F, 0x6F, 0xCB, 0x74, 0x64, 0x87, 0x01, 0xE9, 0xB7, 0x84, 0x63, 0x1B, 0x23, 0xCF, 0x74, 0x1C, 0xBD, 0xEA, 0xA0, 0xF6, 0x54, 0x49, 0xB1, 0xD4, 0x56, 0x15, 0xF0, 0xA4, 0xDA, 0xE6, 0x47, 0xA0, 0x35, 0x80, 0x4A, 0xA0, 0xE9, 0x93, 0x35, 0xC0, 0xF3, 0x6E, 0x32, 0x9E, 0x0D, 0x44, 0x01, 0x1A, 0x77, 0xCB, 0x71, 0xAB, 0xBB, 0xB9, 0x4D, 0x18, 0x8D, 0x56, 0x48, 0xA2, 0x08, 0x41, 0x8E, 0x89, 0x06, 0xE5, 0x48, 0x70, 0xC4, 0x88, 0x80, 0xC3, 0x60, 0x7A, 0x1D, 0x23, 0x03, 0x37, 0x40, 0xDF, 0x2E, 0xEF, 0xFA, 0x94, 0x96, 0x4D, 0xD0, 0xC5, 0xC0, 0x8E, 0x52, 0xF4, 0xF7, 0x37, 0xA0, 0xF9, 0xDE, 0x93, 0xE3, 0x31, 0xE8, 0xEC, 0x27, 0xDD, 0x9B, 0x31, 0xB3, 0xDA, 0x4C, 0xF1, 0xA6, 0xEE, 0x2B, 0x4E, 0x8F, 0x6E, 0xF2, 0x5F, 0x9E, 0xA5, 0xA3, 0x6F, 0x13, 0x91, 0xAB, 0x82, 0xEA, 0xEE, 0xF3, 0x4C, 0xBF, 0x9C, 0x16, 0xE0, 0x8B, 0x64, 0x99, 0x67, 0x02, 0xE3, 0xEB, 0x1A, 0x3D, 0x80, 0xD6, 0x3E, 0x6C, 0x20, 0x0C, 0x90, 0x02, 0x9E, 0x74, 0x1B, 0xA7, 0xD1, 0x1A, 0x9D, 0x3E, 0x02, 0xBE, 0xEE, 0xF1, 0xDE, 0x4E, 0x3B, 0x03, 0x9F, 0x9D, 0xC7, 0x06, 0xD2, 0xFA, 0x07, 0x99, 0xC4, 0xE0, 0xD7, 0xE0, 0xA2, 0x76, 0x57, 0x67, 0x9B, 0x7E, 0x86, 0x1A, 0x95, 0x61, 0x60, 0x2E, 0xBD, 0x7C, 0x30, 0x30, 0xFE, 0x1A, 0xD6, 0xB8, 0xEE, 0x15, 0xA0, 0x01, 0x3C, 0x6E, 0xAC, 0xFD, 0xA4, 0xB9, 0x26, 0xD1, 0xBB, 0xB6, 0xD6, 0xB8, 0xE4, 0x08, 0x5B, 0xDB, 0xE1, 0x93, 0xEF, 0x18, 0x63, 0x8D, 0x8C, 0x53, 0x74, 0xA1, 0x69, 0x51, 0xC0, 0xEC, 0x6E, 0xDD, 0x76, 0x02, 0xA0, 0xBB, 0xCD, 0x16, 0x4F, 0xAB, 0xCD, 0x85, 0x2F, 0xCE, 0x00, 0xCA, 0x3F, 0xF7, 0xD0, 0x6A, 0xF3, 0xAF, 0x1C, 0xC2, 0x7C, 0x01, 0x15, 0x30, 0xF4, 0x4E, 0xB1, 0xBC, 0x25, 0xFC, 0x26, 0x70, 0x68, 0x0F, 0x59, 0x6F, 0x7A, 0xDD, 0xF2, 0x43, 0xF9, 0x09, 0xE4, 0x15, 0x6F, 0xEF, 0x1C, 0xE3, 0xA9, 0xCC, 0xF0, 0xC3, 0xA7, 0x9E, 0x3B, 0xC3, 0x55, 0x8D, 0xF9, 0xA6, 0xAF, 0x6E, 0x57, 0x3C, 0x7F, 0xA9, 0x72, 0x4A, 0xEE, 0x44, 0xA3, 0x1E, 0x38, 0xDD, 0xFF, 0xB5, 0xFB, 0x3F, 0x5B, 0x46, 0x5C, 0xA7, 0xBB, 0x7E, 0x62, 0x02, 0x33, 0x34, 0x6C, 0x01, 0xF3, 0x64, 0x9E, 0x03, 0x12, 0x00, 0x17, 0x45, 0x77, 0x60, 0x02, 0xE8, 0x03, 0x70, 0x47, 0x18, 0x05, 0xE2, 0xDC, 0x6A, 0xF3, 0xB5, 0x13, 0x94, 0x3D, 0x51, 0x92, 0x5E, 0x54, 0xED, 0x1D, 0x4F, 0x03, 0x95, 0x51, 0xCB, 0xD5, 0x5C, 0xEA, 0x1F, 0xF4, 0xCC, 0x56, 0xC6, 0xC7, 0x9B, 0x09, 0xD3, 0xF9, 0x51, 0x0D, 0xC6, 0xC0, 0x53, 0x7D, 0x04, 0x6D, 0x63, 0xAF, 0xBE, 0x1E, 0x6F, 0x0D, 0x1E, 0x43, 0x03, 0xA8, 0x7D, 0x42, 0x1F, 0x13, 0xE6, 0x2D, 0xC7, 0xED, 0x96, 0x64, 0x0B, 0x67, 0xEA, 0xA8, 0xE2, 0x13, 0xE3, 0x4E, 0xB3, 0xA6, 0xAF, 0x67, 0x63, 0x68, 0x7D, 0x0B, 0x8C, 0xCE, 0x23, 0x52, 0xC1, 0x74, 0xCA, 0xE2, 0x86, 0x72, 0x80, 0xE6, 0xD6, 0x63, 0x40, 0xB2, 0xE1, 0xCD, 0x62, 0x88, 0x03, 0xA4, 0x00, 0xAC, 0xC3, 0xE1, 0x43, 0xA1, 0x08, 0xD1, 0xD0, 0x68, 0xB2, 0x3A, 0x1D, 0xAB, 0x4C, 0xED, 0x89, 0x60, 0xC0, 0x29, 0xDC, 0x66, 0x9A, 0x7D, 0xCE, 0xD9, 0xCB, 0x1C, 0x68, 0x9D, 0x57, 0x8C, 0xFC, 0x08, 0x90, 0x57, 0xA1, 0x88, 0xFE, 0x29, 0xDF, 0xDA, 0x56, 0xC1, 0xFA, 0x22, 0xB6, 0x16, 0xD7, 0x0C, 0x3F, 0x6B, 0x26, 0x3B, 0x2A, 0x50, 0xFE, 0xF6, 0x37, 0xDB, 0x35, 0xD1, 0xFA, 0xA9, 0x70, 0x64, 0xC7, 0x62, 0x57, 0x4A, 0x79, 0xAC, 0x3D, 0xD7, 0x04, 0x66, 0x40, 0x3E, 0xC1, 0x56, 0x98, 0xBC, 0xE6, 0x6E, 0xC4, 0xAE, 0x03, 0x84, 0x01, 0xB5, 0x95, 0x5A, 0xFA, 0x29, 0xD8, 0x32, 0x42, 0x00, 0xBA, 0x8E, 0xCB, 0x00, 0x6F, 0x20, 0x93, 0xDD, 0x81, 0x68, 0x33, 0xC5, 0xDA, 0x3F, 0x3C, 0x45, 0x19, 0x52, 0xA0, 0x5D, 0x7F, 0xE7, 0xD2, 0xA9, 0x1D, 0x7D, 0x27, 0x21, 0x47, 0x52, 0x05, 0x71, 0x54, 0xC9, 0x9F, 0x77, 0x43, 0x78, 0x19, 0xF8, 0x68, 0x9B, 0x54, 0x33, 0x7F, 0x67, 0x5D, 0x09, 0x8E, 0x5C, 0x47, 0x21, 0x62, 0x5B, 0x4C, 0xAD, 0x63, 0xC1, 0xFB, 0xF5, 0x4B, 0xD4, 0x5F, 0x23, 0x99, 0xF5, 0x86, 0x8D, 0xBF, 0xDE, 0xDE, 0x75, 0x64, 0xD8, 0xBE, 0x62, 0x28, 0x3E, 0x82, 0x05, 0xE5, 0x56, 0x84, 0xAA, 0x75, 0xE9, 0x50, 0xBF, 0xC4, 0x29, 0x59, 0xAC, 0x77, 0xA2, 0xD7, 0x9D, 0xE1, 0x85, 0x03, 0x08, 0xEA, 0x9A, 0x0E, 0x90, 0xBA, 0x38, 0x80, 0x2F, 0x4E, 0xE3, 0x4D, 0xE4, 0xBA, 0xFE, 0x9F, 0x00, 0x7C, 0xBD, 0x6D, 0x72, 0xF3, 0x3C, 0xCF, 0xB4, 0xB9, 0x95, 0x6B, 0x05, 0x53, 0x24, 0xBE, 0xB1, 0xFF, 0x8D, 0x4D, 0xB9, 0x1B, 0x0C, 0xA9, 0xE7, 0x3E, 0xEB, 0xFD, 0x75, 0x94, 0x1C, 0x39, 0x89, 0x61, 0x4A, 0x22, 0x9B, 0x40, 0x03, 0x26, 0x3A, 0xF8, 0x5F, 0x64, 0x62, 0xA6, 0xC8, 0x44, 0x34, 0x81, 0xF6, 0xBB, 0xC7, 0x68, 0x97, 0xF3, 0x6E, 0x33, 0x2A, 0xC8, 0x7C, 0xEC, 0x45, 0x62, 0xB8, 0xA5, 0x4C, 0x32, 0x1F, 0xAB, 0x0A, 0xC0, 0xCC, 0xDB, 0x0C, 0x64, 0x9A, 0x7C, 0xE9, 0xA4, 0x9B, 0xE1, 0x31, 0x06, 0xF0, 0x1F, 0x75, 0xC6, 0xA0, 0x9A, 0x9F, 0xCC, 0x00, 0x75, 0xA0, 0x27, 0xA1, 0x8D, 0xF9, 0x4D, 0x53, 0xC5, 0x37, 0x17, 0x6E, 0xEC, 0xBB, 0xC3, 0x0C, 0x4D, 0x0F, 0x53, 0x15, 0x7D, 0xF7, 0xB1, 0x46, 0x62, 0x1D, 0xC5, 0xDB, 0xA6, 0x36, 0x79, 0x01, 0x92, 0x80, 0x0B, 0x2F, 0xB2, 0x7A, 0xEF, 0x09, 0x56, 0xC4, 0x02, 0x56, 0x4C, 0xF5, 0x33, 0x20, 0x06, 0xCC, 0xCC, 0xD3, 0x6B, 0x82, 0x66, 0xEC, 0x0A, 0x5F, 0xB0, 0x66, 0x57, 0x43, 0xDE, 0x8C, 0x19, 0x53, 0xBC, 0x37, 0x7D, 0x77, 0x0B, 0x6A, 0xA8, 0x23, 0x5B, 0x0D, 0x25, 0x2E, 0x53, 0x36, 0x30, 0x56, 0xC7, 0x67, 0xD3, 0x91, 0x69, 0x78, 0x9C, 0xE9, 0x38, 0xFB, 0x33, 0x39, 0xA5, 0x6E, 0x6F, 0x84, 0xC7, 0xEB, 0x48, 0xC0, 0xD5, 0xD4, 0x2A, 0x0B, 0xD8, 0x0B, 0xD0, 0x24, 0xF8, 0x76, 0xDB, 0x18, 0xAE, 0x3D, 0x29, 0x93, 0x3F, 0x70, 0x07, 0x9D, 0xB9, 0x80, 0xEC, 0xA4, 0xC6, 0xE1, 0x13, 0x38, 0x3A, 0x3F, 0x9B, 0xBB, 0x80, 0xBD, 0xDF, 0x58, 0x4D, 0xAB, 0xBE, 0x06, 0x62, 0xB2, 0x5B, 0x89, 0xDC, 0x40, 0x24, 0x60, 0x01, 0x6C, 0x7B, 0x5D, 0x86, 0x37, 0xD5, 0xF7, 0x95, 0x13, 0x33, 0x67, 0xB7, 0x0E, 0x56, 0x58, 0xD5, 0x54, 0x94, 0xB1, 0x74, 0xC7, 0xFC, 0xF7, 0x69, 0xA5, 0x12, 0x62, 0xAA, 0x42, 0x8F, 0xB4, 0xCA, 0x9F, 0xA6, 0x50, 0xAF, 0x25, 0xA8, 0xFE, 0xB0, 0xA7, 0x81, 0x9B, 0x52, 0xB8, 0x66, 0x21, 0x7F, 0x1A, 0x82, 0x95, 0x14, 0x3E, 0x93, 0x3F, 0x4B, 0x4E, 0xBA, 0x92, 0x6B, 0x94, 0xE0, 0x02, 0x2B, 0x92, 0xFA, 0x6E, 0x30, 0xB5, 0x8F, 0x91, 0x0F, 0x56, 0xCC, 0xC6, 0x66, 0xF6, 0x1F, 0xFF, 0x4F, 0x76, 0xDE, 0x83, 0x36, 0x5A, 0x57, 0x9D, 0xC4, 0xB5, 0x86, 0x53, 0x0C, 0xC8, 0xC2, 0xFB, 0x24, 0x01, 0x6B, 0xA0, 0xD8, 0xB7, 0x4A, 0x0D, 0x68, 0xA5, 0xB2, 0x7E, 0x44, 0x66, 0x40, 0x0C, 0xD8, 0x09, 0xC8, 0x06, 0xCC, 0x28, 0xE1, 0xFB, 0xC4, 0x2C, 0x98, 0x83, 0xE2, 0x58, 0x6A, 0xF4, 0xE6, 0x14, 0x48, 0x18, 0x3A, 0x7E, 0x2B, 0xBB, 0xF0, 0x15, 0x6F, 0xC3, 0x4E, 0xC7, 0x52, 0x2E, 0x91, 0x5F, 0xA3, 0xE3, 0xD9, 0xF8, 0x9E, 0x54, 0xF7, 0xD8, 0x1C, 0x67, 0x2C, 0xE2, 0xEC, 0x02, 0x4E, 0xAB, 0x37, 0x0E, 0x22, 0x77, 0xA8, 0xAF, 0x99, 0xC0, 0x56, 0xC0, 0x13, 0xA8, 0x7E, 0x07, 0xD8, 0xE4, 0x38, 0x2B, 0x6F, 0x29, 0x9B, 0x19, 0xA8, 0x52, 0xCC, 0xA9, 0xAF, 0x6B, 0xAC, 0xD4, 0x1C, 0x98, 0xFB, 0xE4, 0xF9, 0x86, 0xBE, 0x2D, 0xB8, 0x3A, 0x28, 0xFD, 0x2F, 0xA0, 0x37, 0xF7, 0x18, 0xE2, 0xAD, 0x40, 0xDD, 0x3E, 0xD5, 0xA9, 0x80, 0x25, 0x30, 0x2F, 0xDA, 0x9A, 0x22, 0xD5, 0x89, 0x59, 0xD2, 0x02, 0x33, 0x26, 0x4A, 0x5F, 0xC0, 0xE0, 0x75, 0xF7, 0x6F, 0x68, 0x48, 0xE6, 0x6F, 0xA0, 0x74, 0x16, 0xAA, 0x6F, 0x19, 0xAC, 0xBC, 0x6A, 0xE0, 0x54, 0x16, 0x39, 0x3B, 0x1E, 0x95, 0xE2, 0xD6, 0xD5, 0x9C, 0x77, 0x35, 0xEF, 0xE2, 0x4D, 0x3F, 0x86, 0x56, 0xA6, 0x15, 0x50, 0x21, 0xAF, 0xC6, 0x8B, 0xC5, 0xF1, 0x52, 0x5C, 0x29, 0x14, 0x2F, 0x84, 0x6C, 0x8A, 0xE1, 0xDC, 0x9E, 0x4B, 0xDC, 0x41, 0xD1, 0x18, 0x8D, 0xBB, 0x0A, 0x5D, 0x18, 0x05, 0xE1, 0xC0, 0xA2, 0xCE, 0x6E, 0x02, 0x2C, 0x0E, 0xB0, 0x6E, 0x82, 0x23, 0x6B, 0x6F, 0xC0, 0xEB, 0x1D, 0x59, 0xA1, 0x80, 0x07, 0xA0, 0xC4, 0xE2, 0x1B, 0xAA, 0xE7, 0x08, 0xE8, 0x9A, 0x98, 0x9D, 0xEE, 0x65, 0x04, 0x3E, 0x83, 0x4F, 0xCC, 0x18, 0x90, 0x9D, 0xF1, 0x1B, 0x59, 0x12, 0x50, 0xC1, 0x99, 0x09, 0x2E, 0xFB, 0x2B, 0x42, 0x2E, 0xB9, 0xFD, 0xC3, 0xEC, 0xC8, 0xAC, 0x45, 0xA4, 0x01, 0x53, 0x8B, 0xD9, 0x1B, 0x30, 0x07, 0x36, 0xA1, 0x02, 0x54, 0x5C, 0x0F, 0x6E, 0x3D, 0xAD, 0x1E, 0x8B, 0x30, 0x05, 0x34, 0x00, 0xD9, 0x84, 0x02, 0xB9, 0xC6, 0xE1, 0x04, 0x28, 0x27, 0xF2, 0x83, 0x06, 0x5A, 0x5F, 0x21, 0xB7, 0x4F, 0x8B, 0x17, 0xE0, 0xC8, 0xCF, 0x84, 0x29, 0xB0, 0xFD, 0xED, 0xC3, 0x25, 0x6B, 0x4D, 0xD4, 0xDE, 0xEE, 0x65, 0x2B, 0x1C, 0xA6, 0xE8, 0x10, 0x21, 0x5D, 0xD7, 0xC6, 0x30, 0xF2, 0x5F, 0xD4, 0xAC, 0x85, 0x15, 0xE1, 0xE8, 0x3B, 0xA8, 0x3E, 0x51, 0x93, 0x89, 0xDA, 0x0C, 0x39, 0xFE, 0x8D, 0x64, 0xB8, 0x56, 0xBC, 0x2E, 0x21, 0x91, 0x80, 0xC6, 0x9B, 0x32, 0x3B, 0x31, 0x94, 0x09, 0x57, 0x01, 0xCE, 0x37, 0xE4, 0x88, 0xDA, 0x01, 0x9C, 0x18, 0x6E, 0xC0, 0x15, 0x30, 0x7F, 0x4D, 0xC2, 0xAC, 0x81, 0xDA, 0xC4, 0xFA, 0x60, 0x13, 0xFE, 0xC6, 0x22, 0xFD, 0xB5, 0xCB, 0x5A, 0xFB, 0xD5, 0x6C, 0x75, 0x03, 0xCB, 0x00, 0x99, 0x53, 0x6C, 0xA2, 0xB6, 0x79, 0x69, 0x2C, 0x5E, 0x52, 0xE9, 0xB8, 0x21, 0xF7, 0xA6, 0xA9, 0xC9, 0xC6, 0xBA, 0x28, 0x1C, 0xFB, 0x26, 0x1E, 0x50, 0x70, 0x2D, 0x9F, 0x9E, 0x6F, 0x3E, 0x51, 0xDB, 0xB7, 0x2A, 0xF7, 0x31, 0x6E, 0x2C, 0x60, 0xCB, 0xDB, 0x7F, 0xB8, 0xFD, 0x55, 0xC1, 0x23, 0x81, 0x5A, 0xAF, 0xB0, 0x7A, 0x0A, 0x9B, 0xF2, 0x13, 0xC3, 0x04, 0x64, 0xD2, 0x1F, 0x09, 0x1B, 0xBD, 0x71, 0x5D, 0xD7, 0x03, 0x88, 0x4D, 0x6F, 0x42, 0xE9, 0x22, 0xFA, 0x95, 0x75, 0x25, 0x3F, 0xE5, 0x51, 0xF5, 0x3A, 0x76, 0x76, 0x00, 0xBE, 0x81, 0x5D, 0x80, 0x26, 0x4F, 0xD1, 0x89, 0x1A, 0x5D, 0xE3, 0xB7, 0xA3, 0xCE, 0x78, 0xB9, 0xFF, 0x9E, 0x66, 0xD2, 0x8E, 0xF2, 0xB3, 0x0C, 0xD4, 0x08, 0xDA, 0xA6, 0xE3, 0x89, 0xC0, 0x1C, 0xDF, 0x11, 0xB5, 0x35, 0x63, 0x2D, 0xEF, 0x58, 0x9B, 0x81, 0x7C, 0x5B, 0x32, 0x7B, 0x02, 0x47, 0xB8, 0x26, 0x76, 0xBE, 0x7B, 0x25, 0xE9, 0xAF, 0x50, 0xDF, 0x63, 0x22, 0xD4, 0xF7, 0x8B, 0x95, 0x33, 0x90, 0x74, 0x03, 0x33, 0xD5, 0xA9, 0x04, 0x7A, 0x7D, 0x6E, 0x0C, 0xCA, 0x70, 0xE9, 0xD4, 0x96, 0x01, 0x9A, 0x80, 0xAF, 0x4F, 0xA7, 0x6C, 0x22, 0xD7, 0xEB, 0x07, 0xBB, 0x84, 0x2F, 0x2A, 0x20, 0xA3, 0xDD, 0xF3, 0x68, 0xFB, 0x3D, 0x05, 0x51, 0x93, 0xDF, 0xAE, 0x8A, 0x64, 0xFC, 0x57, 0x54, 0x0B, 0x3C, 0xEF, 0xE6, 0x0A, 0xAD, 0x84, 0x12, 0x83, 0x6C, 0x85, 0xA2, 0xC5, 0xE2, 0xDE, 0x67, 0x8C, 0xFD, 0xE8, 0x5F, 0x1B, 0x74, 0x9B, 0xA6, 0xD3, 0x93, 0x40, 0x4B, 0xD8, 0xEB, 0x33, 0x57, 0xFB, 0xDD, 0x99, 0x6A, 0x05, 0x6A, 0x36, 0x06, 0x0C, 0xA8, 0xCD, 0xA0, 0xF7, 0x6B, 0x7B, 0x55, 0x0D, 0xEC, 0xF8, 0x5E, 0xE7, 0x40, 0x8D, 0xBF, 0xD6, 0x55, 0xF6, 0xAF, 0xFF, 0xB9, 0x13, 0xD1, 0xC0, 0xFC, 0xF5, 0xC9, 0x6D, 0x5B, 0x0E, 0x78, 0x00, 0xA6, 0xC0, 0x9A, 0xCD, 0x0D, 0x03, 0x76, 0x00, 0xCA, 0x53, 0xF4, 0x2F, 0x6A, 0xFA, 0x0B, 0x57, 0x34, 0x77, 0x41, 0x3B, 0x91, 0x5F, 0x61, 0xB8, 0x0A, 0xBA, 0x36, 0x25, 0x22, 0x65, 0x37, 0xBA, 0xFD, 0x0B, 0x08, 0xED, 0x01, 0x42, 0xBE, 0xBD, 0x2C, 0x67, 0xFB, 0xC8, 0xFD, 0x49, 0x3B, 0xC6, 0x1D, 0xF5, 0xA9, 0x28, 0x09, 0x65, 0x28, 0xE5, 0xD9, 0xAC, 0x4B, 0x42, 0x8A, 0x68, 0x62, 0xD2, 0xD1, 0xE3, 0x75, 0x53, 0x53, 0x7F, 0x9D, 0x98, 0xF6, 0xDC, 0x16, 0xEB, 0xDE, 0xD5, 0xFD, 0xEC, 0x80, 0xA8, 0x8F, 0x78, 0x00, 0x58, 0x03, 0x61, 0xC0, 0xE8, 0xDE, 0x32, 0x69, 0xB5, 0xDF, 0x9E, 0x59, 0xAA, 0xC0, 0x62, 0x0C, 0x0B, 0x58, 0x0D, 0x48, 0xF2, 0x4C, 0xD1, 0x89, 0x9A, 0xA1, 0x7A, 0x6B, 0x61, 0x22, 0x66, 0x93, 0x64, 0x92, 0x86, 0xCA, 0x85, 0xED, 0x50, 0x5B, 0xC5, 0x98, 0xD9, 0xB9, 0x47, 0xEC, 0xE0, 0xD8, 0x7A, 0xDD, 0x26, 0xEC, 0xD9, 0xCC, 0x14, 0xEA, 0x30, 0x27, 0x89, 0x6A, 0x6C, 0xDF, 0xFA, 0x88, 0x8B, 0xE9, 0x54, 0x0F, 0x4E, 0xE7, 0x58, 0xC0, 0x9F, 0x6C, 0x9F, 0x69, 0x57, 0x4D, 0x49, 0xE9, 0x88, 0xBD, 0x0B, 0x67, 0x6E, 0x84, 0x19, 0xF2, 0x86, 0x03, 0xEB, 0xB4, 0xDB, 0xE3, 0x9F, 0xA5, 0x6E, 0x29, 0x7D, 0x7B, 0xF6, 0xE6, 0x11, 0x41, 0x57, 0x00, 0xE3, 0x85, 0xBA, 0x16, 0x50, 0x39, 0x36, 0xA4, 0x04, 0x5F, 0xEC, 0x04, 0xAC, 0x81, 0x1D, 0x80, 0x06, 0x4F, 0x89, 0x09, 0x1A, 0x52, 0x5C, 0x6A, 0x39, 0xA6, 0x98, 0x8B, 0x89, 0x7D, 0xA9, 0xD8, 0xCD, 0x2E, 0x45, 0x91, 0x54, 0x41, 0x2F, 0x3A, 0xD9, 0x5A, 0x12, 0x53, 0x51, 0xF6, 0x75, 0xB8, 0x7A, 0x1B, 0xDB, 0x5B, 0xF2, 0x1F, 0x3D, 0xDD, 0x69, 0x70, 0xB4, 0x27, 0xD5, 0x89, 0xD1, 0x1A, 0x4D, 0xD4, 0xA9, 0x74, 0x67, 0x01, 0x91, 0xC0, 0x24, 0xD3, 0x55, 0xBE, 0x0D, 0x7E, 0x66, 0xF4, 0xB6, 0xDC, 0xEE, 0x34, 0xFB, 0x64, 0x2D, 0xE7, 0xD3, 0x9D, 0x66, 0x44, 0xC5, 0x49, 0x86, 0x5B, 0xA7, 0x1A, 0x4F, 0x0C, 0xB0, 0x9E, 0xCE, 0xCF, 0xC0, 0x18, 0x20, 0xEB, 0x06, 0x64, 0xE3, 0xC5, 0x5E, 0x80, 0x29, 0xB0, 0x0A, 0x10, 0xE5, 0x29, 0x27, 0x68, 0x81, 0xD5, 0x4B, 0x2A, 0x26, 0x7B, 0xE9, 0x58, 0x56, 0x47, 0x60, 0x33, 0x7B, 0x37, 0x04, 0x38, 0x4D, 0xAA, 0x79, 0x9B, 0xD7, 0x9C, 0x4C, 0xB4, 0xA6, 0x91, 0xC8, 0x9B, 0xAE, 0x7C, 0xA6, 0xBA, 0x3D, 0x62, 0x68, 0x03, 0xB5, 0x81, 0x35, 0xC6, 0x07, 0x0C, 0xC2, 0xCE, 0xAB, 0xC8, 0xEA, 0x5F, 0x7E, 0xF5, 0xF4, 0x0B, 0xD8, 0x6F, 0x63, 0x3D, 0xAA, 0x89, 0x78, 0xB1, 0xCE, 0xDD, 0x49, 0xCF, 0xA3, 0x1A, 0x47, 0x35, 0xD7, 0x99, 0x3C, 0x5D, 0xEF, 0x71, 0xD9, 0x40, 0xF5, 0xFC, 0x36, 0x04, 0x71, 0xFE, 0x85, 0x04, 0x66, 0x33, 0x46, 0x1B, 0x90, 0xE0, 0x8B, 0xFA, 0xF6, 0x13, 0x69, 0xBE, 0xB8, 0x93, 0xA7, 0xEC, 0x89, 0x5A, 0xFE, 0x67, 0x6C, 0x82, 0x67, 0xE8, 0x24, 0x8B, 0xF7, 0xDD, 0xBC, 0x2B, 0x78, 0xDC, 0x19, 0x62, 0x9F, 0x9B, 0x3A, 0x5E, 0x72, 0x11, 0xF5, 0xDA, 0x0E, 0xCD, 0x3D, 0xC3, 0x8D, 0xEF, 0x30, 0xA5, 0xFC, 0x38, 0x82, 0x4E, 0xE0, 0x28, 0xD7, 0x48, 0x93, 0x2C, 0x69, 0xE7, 0xD5, 0xA3, 0xFD, 0xCA, 0x81, 0x22, 0xB7, 0x42, 0xD1, 0x26, 0xA3, 0x79, 0xEC, 0x90, 0xF9, 0xDF, 0xD7, 0x11, 0xAE, 0xA3, 0x81, 0xCD, 0xD1, 0xD8, 0x75, 0xB5, 0xFC, 0x98, 0x2B, 0xEB, 0xB4, 0xCF, 0x6E, 0xA7, 0x24, 0x66, 0x94, 0xCB, 0x36, 0x50, 0xD3, 0x10, 0x5C, 0x98, 0x44, 0x94, 0xC4, 0x24, 0x0A, 0x39, 0x60, 0x01, 0x6C, 0x42, 0x27, 0xB3, 0xE8, 0x0C, 0xB5, 0x42, 0x9D, 0x84, 0xED, 0x23, 0x2E, 0xED, 0x40, 0x98, 0x7E, 0x42, 0x73, 0x34, 0x2A, 0xF7, 0xCD, 0xF0, 0xF9, 0xA6, 0x57, 0x56, 0xC5, 0xD3, 0xA6, 0x7D, 0xAD, 0xB7, 0xF2, 0xD3, 0x27, 0xCC, 0x35, 0xFF, 0x8C, 0x71, 0x3D, 0x8A, 0xD8, 0x11, 0x5C, 0x29, 0xEB, 0x02, 0xA6, 0x16, 0x59, 0xEA, 0x1C, 0x09, 0x31, 0x26, 0x61, 0x73, 0x73, 0xDA, 0xCE, 0xFB, 0xDE, 0x6D, 0xA4, 0x85, 0x3D, 0x12, 0x40, 0xF9, 0xA2, 0xEA, 0x88, 0x3D, 0x94, 0xDB, 0xF8, 0x67, 0x9D, 0x42, 0xA7, 0x26, 0x35, 0x91, 0x02, 0x82, 0x0A, 0xD9, 0x94, 0xF5, 0x49, 0x01, 0xD9, 0x40, 0x2D, 0xC0, 0x0B, 0x18, 0xB9, 0xAD, 0x03, 0x47, 0xFB, 0x96, 0x9F, 0x22, 0x68, 0x0D, 0x07, 0x26, 0x6B, 0xC8, 0x97, 0x61, 0x6C, 0x4D, 0x38, 0x09, 0x58, 0x54, 0x3F, 0xC7, 0xF5, 0x40, 0x94, 0x79, 0x5F, 0x72, 0xED, 0x2D, 0xB7, 0x00, 0x71, 0x5B, 0x90, 0x22, 0x04, 0xFC, 0x0B, 0xA5, 0x53, 0x22, 0x7C, 0x1B, 0x37, 0x6D, 0xDE, 0x7C, 0xFB, 0xF8, 0x18, 0xBA, 0x8F, 0x64, 0x08, 0x58, 0x01, 0xE7, 0x8B, 0xA7, 0x6A, 0x2A, 0x31, 0x8A, 0x1A, 0x23, 0x68, 0xB7, 0x69, 0xAD, 0x1C, 0x45, 0x7C, 0x31, 0x66, 0xCE, 0x07, 0xCF, 0xF8, 0x5F, 0xEF, 0xE4, 0xD8, 0x30, 0xA0, 0x7B, 0x54, 0x3A, 0xA0, 0xF9, 0x87, 0x6A, 0x14, 0x3C, 0x42, 0x02, 0x58, 0x1B, 0x3F, 0xF3, 0x04, 0xC4, 0x81, 0xD1, 0x08, 0x7D, 0x9E, 0x9E, 0x32, 0x5F, 0x15, 0x62, 0xB6, 0xFF, 0xB7, 0xE7, 0x38, 0x34, 0x70, 0x84, 0xB5, 0x9B, 0xA9, 0xB2, 0xFB, 0x3F, 0x99, 0xB9, 0x18, 0x71, 0xD6, 0x39, 0xA3, 0xA1, 0x26, 0xD5, 0x1A, 0xDE, 0xEB, 0x9D, 0xA2, 0xE2, 0x11, 0xCF, 0x26, 0xEF, 0xB6, 0xA8, 0x70, 0xE1, 0xF6, 0x01, 0x39, 0x89, 0xF1, 0x54, 0x67, 0x3C, 0xFD, 0xE6, 0x80, 0x1B, 0xC3, 0x2A, 0xE7, 0xDA, 0xDE, 0xC5, 0xEF, 0xCF, 0x01, 0xE5, 0x8B, 0xF1, 0x43, 0x70, 0x4C, 0x60, 0x9C, 0xE1, 0x46, 0x43, 0x71, 0x38, 0x8A, 0x32, 0xF2, 0x54, 0x7A, 0x07, 0x95, 0x15, 0xD6, 0xD1, 0x2F, 0x07, 0x3C, 0x89, 0x06, 0x34, 0x81, 0x35, 0xAA, 0x4B, 0xF1, 0xA8, 0xD9, 0xDA, 0xAD, 0x26, 0x66, 0x1B, 0xB7, 0x86, 0x95, 0x34, 0x74, 0xAE, 0x37, 0x66, 0xFC, 0xB4, 0xB6, 0xE4, 0x87, 0x70, 0x96, 0x37, 0x2A, 0x9B, 0x51, 0xDF, 0xB6, 0xA5, 0x32, 0xB3, 0x18, 0x39, 0x2E, 0x60, 0xAB, 0xA1, 0x93, 0x95, 0x42, 0xA3, 0xA8, 0x05, 0xE4, 0x86, 0xA2, 0x66, 0x8B, 0xA9, 0x7D, 0x89, 0x53, 0xD6, 0x0F, 0x2C, 0x61, 0x09, 0x25, 0xF0, 0x64, 0x83, 0x6C, 0x59, 0xD4, 0x2B, 0x37, 0xBE, 0x00, 0x9D, 0x7F, 0x7E, 0x94, 0xA3, 0x05, 0xAC, 0xE9, 0xE1, 0x9E, 0x57, 0xF5, 0x44, 0xB0, 0x20, 0xBA, 0x05, 0x7F, 0x4B, 0x4F, 0xC9, 0x2D, 0x10, 0x94, 0xD9, 0x74, 0x74, 0x0F, 0x07, 0xBC, 0x88, 0x06, 0x4C, 0x01, 0x11, 0x60, 0x15, 0xA0, 0x53, 0xCD, 0x6B, 0x13, 0x33, 0xE1, 0xC6, 0x56, 0xB1, 0xA8, 0x3B, 0xFE, 0x6F, 0xCC, 0x18, 0x4F, 0x57, 0x3C, 0x05, 0xFC, 0x27, 0x70, 0xDA, 0x74, 0x90, 0xB9, 0x69, 0xB7, 0xBA, 0x6F, 0xDD, 0xA2, 0x51, 0x16, 0x0A, 0xDE, 0xA2, 0x93, 0x17, 0x57, 0x34, 0x65, 0x1A, 0xBA, 0x8A, 0x06, 0x77, 0xE5, 0x62, 0xF3, 0xDB, 0xC4, 0xA8, 0x43, 0x78, 0x28, 0xBA, 0x31, 0x04, 0x04, 0xEB, 0x7D, 0xAC, 0x4F, 0x76, 0xE3, 0xEA, 0xD1, 0xC2, 0x80, 0x10, 0xBC, 0xD8, 0xC2, 0x71, 0xBD, 0x11, 0x25, 0x75, 0xCA, 0x88, 0xD4, 0x32, 0x11, 0x02, 0x64, 0xDC, 0xF0, 0xAF, 0x03, 0x90, 0x34, 0x99, 0xA3, 0x10, 0xD0, 0xFF, 0x81, 0x24, 0x16, 0x85, 0x51, 0x27, 0xE6, 0x67, 0x4C, 0xDB, 0xDC, 0x6B, 0x62, 0xA6, 0x2C, 0x1D, 0x49, 0x24, 0x09, 0xCC, 0xB5, 0x39, 0xE9, 0x46, 0x9D, 0x6C, 0x28, 0x27, 0xBC, 0x01, 0x3A, 0xB4, 0xE1, 0xEE, 0x6B, 0x43, 0xAB, 0xEB, 0x73, 0x6D, 0x9E, 0xDB, 0x13, 0x3F, 0x74, 0x8F, 0xBC, 0x3A, 0x01, 0x59, 0xF8, 0x60, 0x36, 0x63, 0x9E, 0x91, 0x70, 0xEA, 0x80, 0x29, 0x6F, 0x32, 0xFC, 0xB8, 0x29, 0x04, 0xEF, 0x0C, 0x46, 0x29, 0x3B, 0x29, 0x3F, 0x1E, 0x67, 0x0F, 0xC2, 0xE6, 0xA2, 0x9C, 0xEC, 0xF9, 0xC0, 0xDB, 0xC5, 0x18, 0x56, 0x45, 0x3C, 0x77, 0x02, 0xA5, 0x8C, 0xFC, 0x02, 0x9A, 0xE3, 0x33, 0xF8, 0xBF, 0x2C, 0x07, 0xF6, 0x1A, 0x13, 0x37, 0x20, 0x8B, 0xD8, 0x40, 0x2B, 0x4E, 0xC9, 0x98, 0x98, 0x19, 0xB2, 0x84, 0x57, 0xFF, 0xC4, 0x8E, 0x5E, 0x98, 0xA3, 0x65, 0x08, 0x3C, 0xD1, 0x76, 0x20, 0x4D, 0x27, 0xEC, 0x3F, 0x3C, 0x4C, 0xE1, 0x71, 0x62, 0xDB, 0xB8, 0xAF, 0xCE, 0x95, 0x67, 0x3E, 0x3D, 0xDA, 0xF1, 0xC4, 0xBC, 0xE9, 0x37, 0x3F, 0xF5, 0x1C, 0x10, 0x1B, 0x6F, 0x35, 0x06, 0xD6, 0x9E, 0x35, 0x94, 0xEB, 0x6B, 0x4E, 0x65, 0x72, 0x1D, 0x40, 0xFD, 0x5D, 0x85, 0xBF, 0x8D, 0xCA, 0x80, 0xFD, 0xB1, 0x01, 0xEA, 0x9B, 0xD3, 0xC5, 0x05, 0x2F, 0x47, 0xBD, 0x72, 0x8E, 0xF6, 0x36, 0xAA, 0x39, 0xD9, 0x0C, 0x3A, 0x53, 0x2E, 0x05, 0x32, 0x80, 0x20, 0xD4, 0x70, 0x4A, 0x09, 0x60, 0x0A, 0x84, 0xF0, 0x14, 0x9B, 0xA8, 0x39, 0xF4, 0x52, 0xB3, 0x3F, 0x1D, 0x72, 0xFF, 0x22, 0x74, 0x53, 0x48, 0x43, 0x77, 0xC2, 0x52, 0x32, 0x85, 0x9A, 0x9D, 0x31, 0x5A, 0xDF, 0x42, 0xD9, 0x7D, 0x73, 0x0D, 0xFD, 0xA4, 0xEE, 0x99, 0x00, 0xFA, 0xA9, 0xFA, 0x3D, 0x1D, 0xB6, 0xED, 0xD5, 0xD0, 0xF6, 0x02, 0x5C, 0x81, 0xB0, 0x1B, 0x20, 0x39, 0xBD, 0x91, 0x32, 0x88, 0x0D, 0x78, 0x01, 0xF9, 0xA4, 0x90, 0xDA, 0x71, 0x5A, 0xAE, 0xFD, 0xFE, 0xF5, 0x24, 0xCA, 0x81, 0x9E, 0x6A, 0xEC, 0x93, 0xF6, 0x0F, 0x84, 0x02, 0x3E, 0x2F, 0xCE, 0x02, 0xDF, 0x00, 0x09, 0x60, 0x7E, 0x66, 0x79, 0xAE, 0xCF, 0xF8, 0xC5, 0xA9, 0xAF, 0x87, 0x6B, 0x40, 0x96, 0xB8, 0x1B, 0x2C, 0x2E, 0xDE, 0x58, 0x28, 0x7B, 0xD0, 0xDB, 0xA7, 0x5E, 0x45, 0x6D, 0x7D, 0x14, 0xB5, 0xAC, 0x3B, 0x74, 0x20, 0x02, 0x3F, 0x19, 0xB7, 0xA3, 0x14, 0x8D, 0x72, 0x33, 0x19, 0x6D, 0xC6, 0x38, 0x75, 0x03, 0x15, 0x80, 0xE7, 0xDB, 0x9E, 0x60, 0xCD, 0x23, 0x27, 0x08, 0x07, 0x9C, 0xC8, 0x7D, 0x45, 0x46, 0x3B, 0x15, 0xD7, 0x31, 0x7F, 0x28, 0xDE, 0xE6, 0xEC, 0xA2, 0x80, 0x36, 0x50, 0x93, 0x19, 0x3C, 0xF2, 0xC2, 0x36, 0x60, 0xE9, 0x93, 0xD1, 0x36, 0x6A, 0x50, 0x16, 0xD0, 0x7D, 0x6B, 0xFD, 0x10, 0xB5, 0xFC, 0xDD, 0xE3, 0x4A, 0x8F, 0xCA, 0x81, 0x9B, 0x70, 0x07, 0x32, 0x50, 0xDB, 0xE0, 0x9F, 0x1B, 0x82, 0x70, 0xC1, 0xCE, 0xBB, 0x34, 0xFD, 0x4D, 0x57, 0xF6, 0x27, 0x6A, 0x46, 0x50, 0x13, 0xE0, 0xFA, 0x87, 0xE0, 0x3F, 0x95, 0xC2, 0xD6, 0x7E, 0x6F, 0x9B, 0x2B, 0x6B, 0x40, 0x04, 0x30, 0x03, 0xDC, 0x18, 0xD8, 0x7E, 0xFD, 0x6C, 0x65, 0x7D, 0xE4, 0xC8, 0xC1, 0x7E, 0x1B, 0x0B, 0xB6, 0xDC, 0x64, 0x6D, 0x14, 0xAB, 0x02, 0xED, 0x63, 0x31, 0x00, 0x18, 0x31, 0x0E, 0x05, 0x91, 0xBC, 0x96, 0xED, 0x1F, 0xEE, 0xE7, 0x22, 0x53, 0x54, 0x32, 0xC5, 0xB8, 0x3C, 0xC5, 0x26, 0x6A, 0xD3, 0x9F, 0x40, 0x60, 0x1D, 0xAF, 0x41, 0xDB, 0xB7, 0x46, 0x1E, 0xF6, 0x16, 0x7C, 0xDA, 0xBD, 0x7F, 0xFF, 0x8B, 0xA9, 0x21, 0x3F, 0x24, 0x6B, 0x0C, 0x0E, 0xDF, 0x0C, 0x18, 0x04, 0x11, 0x37, 0xE7, 0x5B, 0x95, 0x9B, 0x7F, 0x4B, 0xD0, 0x85, 0xA3, 0x7D, 0x5A, 0x59, 0xF1, 0x14, 0x9B, 0x9E, 0xDE, 0x6F, 0x89, 0xA5, 0x17, 0x60, 0x32, 0xDF, 0x3D, 0xE2, 0x2B, 0x57, 0x0C, 0x88, 0x63, 0x0E, 0xE8, 0x01, 0xE8, 0xBE, 0x65, 0xEE, 0xCD, 0xA3, 0xC9, 0x56, 0xB9, 0x05, 0xC6, 0x35, 0xB7, 0x37, 0x42, 0x03, 0xA8, 0xC9, 0x4D, 0x9B, 0x64, 0xAD, 0xC6, 0x51, 0x13, 0x41, 0xEC, 0xE6, 0x99, 0x0A, 0xF4, 0x9C, 0x92, 0x13, 0xB5, 0xFE, 0x3D, 0x87, 0x97, 0xCA, 0x6F, 0xA7, 0x20, 0x45, 0x68, 0xD1, 0x91, 0xFF, 0x61, 0x72, 0x04, 0xE9, 0x5B, 0xC4, 0x20, 0x21, 0x87, 0xC3, 0x4A, 0x51, 0xA6, 0x9B, 0xC3, 0xF7, 0x0A, 0xE5, 0x7D, 0x6D, 0xF4, 0xC4, 0x3D, 0xF9, 0x9A, 0x01, 0x64, 0xBD, 0x0D, 0x53, 0x5B, 0xDF, 0xE6, 0x03, 0xBD, 0x81, 0x58, 0xC4, 0x06, 0xAC, 0x46, 0xC2, 0x7E, 0x5D, 0xE4, 0xAC, 0x89, 0x0D, 0x88, 0x01, 0x16, 0xF7, 0xB6, 0x48, 0x69, 0x8A, 0xCA, 0xD8, 0xD4, 0x9D, 0xCF, 0x08, 0x02, 0x4C, 0x80, 0x60, 0x2C, 0xC4, 0xDF, 0x8E, 0x82, 0x11, 0x80, 0x3B, 0x20, 0x82, 0x53, 0x22, 0x01, 0x21, 0x2C, 0x79, 0xCA, 0xAC, 0xD8, 0x95, 0xAA, 0xD7, 0x6A, 0x4C, 0x77, 0x56, 0xDD, 0x34, 0xAB, 0x15, 0xDB, 0x99, 0x64, 0x23, 0x53, 0xC4, 0x3E, 0x85, 0xA1, 0x47, 0x0D, 0xC2, 0x44, 0xEA, 0x5D, 0xB1, 0xD7, 0x64, 0xF4, 0x29, 0xD7, 0x45, 0x9A, 0x5C, 0x22, 0xE4, 0x5D, 0xCA, 0x70, 0x86, 0xCA, 0xB5, 0x16, 0xCB, 0xF6, 0x6E, 0x72, 0x8F, 0x9C, 0x25, 0xA5, 0x3C, 0x59, 0x6C, 0x58, 0x6B, 0xB1, 0x39, 0x1C, 0x05, 0x20, 0x62, 0x09, 0x91, 0x73, 0xCA, 0x2D, 0x25, 0x83, 0xA8, 0x79, 0xFE, 0x90, 0xDA, 0x75, 0xA5, 0x07, 0x8A, 0xAB, 0x24, 0x9B, 0x59, 0x8C, 0x00, 0xD9, 0x2F, 0x42, 0x00, 0x25, 0xF6, 0x06, 0xD4, 0x26, 0x2D, 0x67, 0x82, 0xB6, 0xB1, 0x26, 0xB4, 0x42, 0x6E, 0x5A, 0x72, 0xCE, 0x66, 0x94, 0xD1, 0x8B, 0x55, 0x9F, 0x92, 0xF8, 0xCF, 0xC2, 0x90, 0x8E, 0xE8, 0xFA, 0xC8, 0x1C, 0xF6, 0x91, 0x21, 0x65, 0x1A, 0x7E, 0x9F, 0x42, 0xC6, 0x31, 0x31, 0x1A, 0xDF, 0x4C, 0xE7, 0x4A, 0xD1, 0x46, 0xD3, 0x1A, 0xED, 0x0D, 0x6F, 0x88, 0x02, 0xCC, 0x01, 0x69, 0x84, 0x62, 0x94, 0x9B, 0x35, 0xFD, 0x2D, 0xF6, 0x0C, 0x15, 0xDE, 0x8F, 0x16, 0xA0, 0x79, 0x67, 0x36, 0x85, 0x23, 0x11, 0x04, 0x4D, 0xEC, 0xAF, 0x58, 0xD1, 0x80, 0x4E, 0xCA, 0x2A, 0x23, 0x4A, 0x2E, 0x60, 0x32, 0x82, 0xD5, 0x89, 0x0D, 0x8C, 0x60, 0x19, 0x0E, 0x28, 0xE1, 0x35, 0x5A, 0xC2, 0x04, 0x4D, 0x58, 0xFE, 0x53, 0x33, 0x95, 0x66, 0x6E, 0x75, 0xA1, 0x66, 0x64, 0x74, 0x18, 0x83, 0x94, 0x36, 0x0D, 0x76, 0x27, 0xFB, 0xA5, 0xBE, 0xA5, 0xEC, 0xC9, 0x69, 0xD6, 0xE9, 0x10, 0xCE, 0x61, 0x34, 0xE5, 0x94, 0xE3, 0x7E, 0xE0, 0x4F, 0x3F, 0xB5, 0x75, 0x9A, 0x0D, 0x9C, 0x14, 0x33, 0xC6, 0xA7, 0x88, 0x6D, 0x37, 0x39, 0x56, 0x4E, 0x72, 0xB5, 0x4C, 0xA6, 0x6D, 0x3C, 0x06, 0x87, 0x27, 0x83, 0x2F, 0xF5, 0xFA, 0x1D, 0xD4, 0x29, 0x72, 0x55, 0x4A, 0x4B, 0xCE, 0x48, 0xAE, 0x00, 0xB4, 0x81, 0x9E, 0x24, 0xB6, 0x1C, 0x11, 0xEA, 0x6D, 0x30, 0x5E, 0x09, 0x68, 0x03, 0x2B, 0x00, 0xD9, 0x3C, 0x65, 0x82, 0xC6, 0x84, 0xF8, 0x88, 0x8D, 0x52, 0x42, 0x6F, 0xC8, 0x23, 0x69, 0x78, 0x1E, 0x65, 0xD0, 0xBA, 0xC1, 0xF0, 0x20, 0x0A, 0xE1, 0xAD, 0x42, 0x7F, 0x41, 0xF3, 0xD7, 0x34, 0x61, 0x36, 0x83, 0x88, 0x93, 0xE8, 0xF8, 0x8B, 0x16, 0x20, 0xF1, 0xFA, 0x47, 0x9F, 0x46, 0x89, 0x9B, 0x43, 0x85, 0x58, 0x02, 0x68, 0x03, 0xA9, 0xEF, 0x5C, 0x78, 0xAD, 0x47, 0x7E, 0xAC, 0x7C, 0xED, 0x6D, 0x6A, 0x7D, 0x7A, 0x96, 0x01, 0x76, 0xCC, 0xAF, 0x32, 0xA7, 0x43, 0xF8, 0x9B, 0xE8, 0x3D, 0xDF, 0xEA, 0x32, 0xA0, 0x94, 0xE1, 0x15, 0x40, 0x46, 0xB9, 0x13, 0xC0, 0x02, 0xD8, 0x1B, 0x90, 0xE2, 0x29, 0x3E, 0x41, 0x33, 0xAC, 0x43, 0x56, 0xFE, 0x96, 0x07, 0x5A, 0x0E, 0x19, 0x5A, 0x92, 0xBD, 0x22, 0x85, 0x45, 0xE0, 0x45, 0xF5, 0x32, 0xD8, 0xEC, 0x71, 0xBF, 0xDA, 0xED, 0xD7, 0x35, 0xA1, 0x63, 0x4A, 0xF6, 0x65, 0xBE, 0x3B, 0x40, 0x27, 0x71, 0x5B, 0x46, 0x81, 0xE6, 0x88, 0xE5, 0x67, 0x5A, 0x7B, 0xE4, 0xFE, 0xF1, 0x64, 0x05, 0x66, 0x21, 0x51, 0x0C, 0x25, 0x9E, 0x6E, 0x9B, 0xE0, 0xDA, 0xAA, 0x4F, 0x51, 0x58, 0xED, 0x71, 0x6F, 0xB5, 0x79, 0x42, 0x53, 0xB7, 0x7C, 0x1A, 0x7E, 0xE4, 0x51, 0x8E, 0xCA, 0x78, 0xB9, 0x29, 0xD0, 0xFD, 0x6E, 0x13, 0xD8, 0x02, 0x34, 0x81, 0xCD, 0xDD, 0x82, 0x24, 0x4C, 0x81, 0x18, 0xBF, 0x95, 0x9E, 0xA8, 0x39, 0x76, 0xEE, 0x5A, 0x7F, 0x51, 0x93, 0x48, 0xB6, 0x3E, 0xD3, 0xC7, 0xF3, 0x76, 0xAD, 0xC6, 0x73, 0x28, 0x68, 0x47, 0x1A, 0xF9, 0x74, 0xB6, 0xFF, 0xBA, 0x9A, 0x18, 0x8E, 0xF2, 0x98, 0xE1, 0x2D, 0x03, 0xE2, 0xE9, 0xCB, 0xBF, 0x4E, 0xB6, 0xBB, 0xF9, 0xEB, 0x0B, 0x27, 0x4A, 0xF8, 0x85, 0xB1, 0x28, 0x00, 0xCF, 0x48, 0x8C, 0x74, 0x63, 0xB4, 0xDE, 0x6D, 0xA6, 0x55, 0x33, 0x51, 0x9D, 0x11, 0x3E, 0xFA, 0x75, 0x7E, 0xEA, 0x3F, 0x12, 0x98, 0xAF, 0x6C, 0x35, 0x10, 0xF5, 0x66, 0x53, 0xEF, 0xF5, 0x3A, 0x1C, 0x86, 0x02, 0x7B, 0xCF, 0x99, 0x40, 0x25, 0x4F, 0x99, 0xA1, 0x36, 0x06, 0x90, 0x35, 0xA9, 0x87, 0x4F, 0xD1, 0xAC, 0x6D, 0x57, 0x64, 0x51, 0xEE, 0xC6, 0x53, 0x69, 0xE4, 0xBD, 0xDA, 0x8F, 0x65, 0xBC, 0x01, 0xF3, 0xC5, 0xE7, 0xE9, 0xAA, 0x42, 0xFD, 0xB1, 0xB9, 0x18, 0xAF, 0xE6, 0x51, 0x32, 0xB5, 0xC7, 0xA9, 0xA1, 0xC6, 0x24, 0x5A, 0xDE, 0x76, 0x6C, 0xFB, 0xC8, 0xBA, 0x32, 0xD2, 0xAD, 0x33, 0x33, 0xAF, 0x5F, 0xCF, 0x8E, 0xB9, 0x29, 0x6D, 0xBF, 0x15, 0xFB, 0x7A, 0x1E, 0x9B, 0xB1, 0x69, 0xA2, 0xF6, 0x68, 0x9A, 0x75, 0x1C, 0x1B, 0x56, 0x03, 0x1E, 0xA3, 0xCB, 0x02, 0x1D, 0x54, 0xF2, 0xFA, 0xC5, 0x66, 0x24, 0x2A, 0x80, 0xDC, 0x40, 0xF1, 0x9F, 0xCF, 0x3D, 0x31, 0x4B, 0xDC, 0x19, 0xBD, 0x21, 0x13, 0xC8, 0x37, 0x79, 0x88, 0xC2, 0x71, 0xFF, 0xCD, 0x4A, 0x94, 0xB5, 0x3E, 0xC8, 0x7E, 0xE6, 0x8E, 0x27, 0x50, 0x33, 0x0D, 0x1F, 0x7D, 0xDD, 0xE9, 0xA8, 0xEF, 0x4E, 0xDD, 0xEB, 0x87, 0x60, 0x6A, 0x24, 0xBD, 0xF0, 0xB5, 0xC7, 0x4B, 0x82, 0xDA, 0xFB, 0x94, 0xAB, 0xF3, 0x9E, 0x04, 0xED, 0x9D, 0xD7, 0x93, 0xBF, 0x25, 0xFE, 0x62, 0x1F, 0xEF, 0xCC, 0x02, 0x54, 0x27, 0x43, 0x92, 0x21, 0xA7, 0x28, 0x52, 0xA3, 0xEB, 0xB1, 0xE5, 0xCD, 0xA2, 0x1A, 0x39, 0x7E, 0xFE, 0x32, 0x1A, 0x9C, 0x8C, 0xB8, 0x01, 0x44, 0x12, 0x0D, 0xF8, 0x02, 0x64, 0x03, 0x6B, 0x8E, 0x92, 0x12, 0xA5, 0x4E, 0xCC, 0x0A, 0x33, 0xE5, 0x6A, 0x5A, 0xE1, 0xE7, 0xD3, 0x34, 0xA4, 0x36, 0x74, 0xA1, 0x25, 0x05, 0xD1, 0xA7, 0x9A, 0xBA, 0x2C, 0xE4, 0xA1, 0x49, 0xDE, 0x31, 0x80, 0x11, 0xE4, 0x5F, 0x40, 0x58, 0xA9, 0xC5, 0xF0, 0xCF, 0x1A, 0x43, 0xE7, 0x0C, 0x5D, 0x32, 0x74, 0xA1, 0xB7, 0xA7, 0x0A, 0x77, 0x17, 0x15, 0xD3, 0x01, 0x88, 0xD1, 0x4F, 0xCD, 0x34, 0x76, 0xF9, 0xB0, 0x1F, 0xC3, 0x5B, 0x4A, 0x29, 0xB0, 0x12, 0x18, 0xE7, 0xFE, 0x5E, 0x1C, 0xBB, 0x49, 0x79, 0x9D, 0xE1, 0x99, 0x80, 0x24, 0x55, 0xDA, 0xA2, 0xF6, 0x1A, 0xD4, 0xA8, 0x54, 0xA0, 0xDD, 0xAD, 0x02, 0xAC, 0x01, 0x37, 0xC0, 0x0A, 0xD0, 0x41, 0x02, 0x3E, 0x0A, 0x67, 0x4E, 0xCC, 0x1A, 0x2A, 0x74, 0x4D, 0xF1, 0xE7, 0x34, 0x7F, 0x74, 0x64, 0xDD, 0xEE, 0xA0, 0xEF, 0xB5, 0x23, 0xFF, 0x23, 0x36, 0x95, 0x9F, 0xFD, 0xFA, 0xA8, 0xF5, 0xE7, 0xE1, 0xD9, 0xBA, 0xEE, 0xF6, 0x57, 0x9F, 0x56, 0x82, 0xA5, 0xD7, 0x2A, 0x58, 0x4F, 0xA3, 0x04, 0xB9, 0x4D, 0x02, 0xF2, 0xD4, 0x3D, 0xCA, 0xB3, 0xA9, 0x3E, 0xF5, 0xA9, 0x93, 0x69, 0x89, 0x8B, 0x9A, 0xEA, 0x1D, 0xA1, 0x80, 0xD5, 0x59, 0x9F, 0x5E, 0x77, 0x20, 0x3F, 0x53, 0xBF, 0x15, 0xDC, 0x42, 0xBE, 0xD7, 0xF1, 0xCD, 0x97, 0x5F, 0x9F, 0x96, 0x52, 0x6E, 0x80, 0xF9, 0xDB, 0x1F, 0x3D, 0x04, 0x10, 0x05, 0x4C, 0xE6, 0x14, 0x46, 0xCD, 0x10, 0xFB, 0x76, 0x41, 0x12, 0x4C, 0x19, 0xF6, 0x03, 0x32, 0xB0, 0x7B, 0xDF, 0xB3, 0xD4, 0x9E, 0xE2, 0xCB, 0xFC, 0x7D, 0x4C, 0x55, 0x7B, 0x17, 0x9F, 0xF3, 0x1C, 0x18, 0xD1, 0x87, 0x31, 0xDC, 0x67, 0x09, 0x12, 0x0E, 0xBC, 0x26, 0xE2, 0x14, 0x6C, 0xFB, 0x2C, 0xD2, 0x73, 0x8A, 0x2A, 0x09, 0xF1, 0x9B, 0xED, 0x03, 0x49, 0xEE, 0xC9, 0x41, 0x48, 0x01, 0x26, 0x94, 0x1E, 0x40, 0x4D, 0xD4, 0x94, 0x4A, 0xC1, 0xF1, 0xFA, 0x2B, 0xCE, 0xF6, 0x66, 0x0A, 0x28, 0x53, 0x01, 0x03, 0x8C, 0x91, 0x8F, 0x4C, 0x6B, 0x51, 0x01, 0xAC, 0x09, 0x05, 0xF6, 0xE9, 0x0B, 0x07, 0xD8, 0x02, 0x3C, 0x79, 0x4A, 0x4E, 0xD4, 0x36, 0x24, 0x76, 0x47, 0x2E, 0xE2, 0x4A, 0x56, 0xDB, 0x99, 0x3C, 0x6D, 0x30, 0x44, 0x7E, 0xE1, 0x4A, 0xCD, 0x46, 0x24, 0x76, 0xCF, 0x52, 0xE0, 0xF5, 0xEC, 0x9B, 0x44, 0x1B, 0xCB, 0x31, 0x39, 0x7E, 0x1C, 0x65, 0xE5, 0x34, 0x14, 0x4E, 0xFE, 0xDF, 0xEB, 0x07, 0x3F, 0x1E, 0xEF, 0x5D, 0xD7, 0x38, 0x89, 0xCB, 0xC6, 0x3E, 0x22, 0x48, 0x4C, 0xDE, 0x95, 0x7C, 0xFA, 0xA5, 0x13, 0x46, 0x44, 0xDC, 0x4C, 0x20, 0x4C, 0xF7, 0xAE, 0xB2, 0xC8, 0x26, 0xA8, 0x77, 0x76, 0x2B, 0x0E, 0x44, 0xCC, 0x56, 0xD2, 0x3B, 0xAD, 0xAD, 0x0D, 0x44, 0x03, 0xAA, 0xAF, 0x0F, 0xAE, 0x6E, 0xC0, 0x7A, 0x46, 0xE5, 0x44, 0x4D, 0xA0, 0xD8, 0x9F, 0x1C, 0x3F, 0x5A, 0x55, 0xE8, 0x44, 0x6D, 0x5A, 0xD4, 0x37, 0x9C, 0xAB, 0x64, 0xC3, 0x55, 0xB3, 0xFA, 0x1D, 0x6B, 0xFB, 0x33, 0xD6, 0x2A, 0x66, 0xAC, 0x31, 0xDE, 0xAE, 0xC0, 0xAA, 0x5B, 0xBE, 0xB4, 0xC6, 0x69, 0xA9, 0xF2, 0xAD, 0xDE, 0xB4, 0xC9, 0x56, 0xFB, 0x5C, 0xA1, 0x19, 0x9F, 0x2B, 0x74, 0x13, 0x49, 0xCC, 0xCA, 0x7D, 0x62, 0x28, 0x63, 0x44, 0x33, 0x8B, 0xF4, 0x59, 0x88, 0xF3, 0xC6, 0xD0, 0x67, 0x0D, 0x0B, 0x54, 0xBD, 0xB3, 0x5C, 0x33, 0xA0, 0x1B, 0xA8, 0x00, 0xC6, 0xB9, 0x68, 0xCE, 0xB4, 0x0D, 0xCC, 0x0A, 0x31, 0x7A, 0xA2, 0xA6, 0xB4, 0x41, 0xA2, 0xB6, 0x56, 0x05, 0x03, 0xCD, 0x56, 0x14, 0x21, 0x97, 0x61, 0x8B, 0x76, 0x35, 0x6E, 0x4B, 0x6E, 0xBC, 0x49, 0xE9, 0x94, 0x5E, 0xBC, 0xA5, 0x3E, 0x53, 0x44, 0x7C, 0xDC, 0x7B, 0x66, 0x17, 0x78, 0x03, 0x56, 0x33, 0x79, 0x78, 0x17, 0x52, 0x67, 0x85, 0x39, 0xF2, 0xF3, 0x88, 0x36, 0x4F, 0xA5, 0x2D, 0x77, 0xD2, 0xC6, 0xE2, 0xAB, 0xFF, 0xC4, 0xC3, 0x04, 0x6C, 0x3D, 0x0E, 0x0D, 0x3A, 0x93, 0x2A, 0xDE, 0xC1, 0xF2, 0x2C, 0xD9, 0x73, 0xEC, 0x42, 0xD6, 0xBB, 0xE6, 0xDE, 0x02, 0xBC, 0x5E, 0xBB, 0xBF, 0x25, 0x17, 0x60, 0x0B, 0x10, 0x9F, 0x8D, 0x62, 0x20, 0x67, 0x32, 0xB6, 0x81, 0xF6, 0x09, 0x9A, 0x61, 0x01, 0xBF, 0xEA, 0x97, 0x11, 0xA9, 0x15, 0x74, 0x19, 0xAA, 0xA7, 0xB7, 0xCF, 0xAE, 0x0D, 0xF1, 0xCE, 0xD8, 0xCB, 0xD2, 0x7D, 0x52, 0x86, 0x98, 0xCF, 0xF1, 0x5E, 0xA0, 0xC4, 0x0E, 0xDE, 0x3A, 0xF7, 0x69, 0x59, 0x3A, 0xC5, 0xAE, 0x23, 0x58, 0xCC, 0x84, 0x3F, 0xC7, 0xE2, 0x8B, 0x91, 0x89, 0x9E, 0x66, 0xB3, 0x3F, 0x4C, 0x7E, 0xD9, 0xB8, 0x79, 0xC9, 0xA4, 0x8A, 0x34, 0x60, 0x0E, 0xCC, 0x8B, 0x31, 0x22, 0xAB, 0x4C, 0x43, 0xCF, 0xF3, 0x2C, 0x7B, 0x5B, 0xC8, 0xF9, 0x98, 0x64, 0xF1, 0x79, 0x0C, 0x15, 0x43, 0x67, 0x1B, 0x99, 0x80, 0xE7, 0x24, 0x94, 0x98, 0x02, 0xD2, 0x00, 0xA9, 0x49, 0x54, 0xC0, 0xD1, 0x2E, 0x9C, 0x29, 0x35, 0x51, 0x73, 0x18, 0x7F, 0xB4, 0xC3, 0x6E, 0x62, 0x17, 0x2F, 0x7A, 0x83, 0xBF, 0x89, 0xB3, 0x82, 0xB1, 0xF8, 0x95, 0x5B, 0x21, 0xE5, 0x6C, 0x5D, 0x9B, 0xFD, 0x5B, 0x2C, 0xAB, 0x71, 0x8B, 0xD2, 0xA7, 0xCA, 0xFA, 0x56, 0xC2, 0xCE, 0x18, 0xCF, 0x59, 0x16, 0x3E, 0x65, 0x86, 0x72, 0x82, 0x17, 0x33, 0xF1, 0x57, 0x80, 0x56, 0xFA, 0x3D, 0x12, 0xEF, 0xE9, 0xA2, 0x0A, 0xC8, 0x5C, 0xCA, 0xFB, 0xDE, 0xF2, 0x92, 0x67, 0x1E, 0x59, 0x33, 0x8E, 0x6C, 0xE2, 0xC9, 0xAF, 0x2E, 0x80, 0xB2, 0xB9, 0xBB, 0xBD, 0x49, 0x43, 0x31, 0x0F, 0x4D, 0x05, 0x56, 0xCE, 0x16, 0x3E, 0x60, 0x0B, 0x78, 0xAF, 0x10, 0x3B, 0xED, 0x7D, 0x0A, 0xAD, 0x8C, 0xD1, 0x43, 0xB6, 0xD0, 0x80, 0x00, 0xA3, 0x72, 0xC7, 0x63, 0xAA, 0xA9, 0xEA, 0x3F, 0xE1, 0xDF, 0x42, 0x38, 0x61, 0x98, 0x66, 0xD9, 0x60, 0xD8, 0xA7, 0x0F, 0x86, 0xD6, 0xBC, 0x85, 0x97, 0xDF, 0xE6, 0xE2, 0xB2, 0xBF, 0xC2, 0x6D, 0x8E, 0x75, 0xCC, 0xD3, 0xE7, 0x3F, 0x27, 0x9F, 0x2E, 0xDE, 0xB1, 0x56, 0xF9, 0xCE, 0x46, 0x7C, 0xBF, 0x4D, 0xCA, 0x52, 0x80, 0x7A, 0x15, 0x96, 0x31, 0xC9, 0x8C, 0xA3, 0xC9, 0xED, 0x9C, 0x3A, 0xD3, 0xD7, 0x1E, 0xB0, 0xFA, 0x26, 0x7A, 0xE9, 0x91, 0xF4, 0x16, 0x63, 0xD8, 0x44, 0x08, 0xB0, 0x6A, 0x9E, 0x1E, 0x40, 0x25, 0x4F, 0xD9, 0x13, 0xB5, 0xC4, 0xFC, 0xDC, 0x14, 0xE5, 0x9F, 0xBE, 0x27, 0x5C, 0x04, 0xA5, 0x15, 0xC5, 0xAA, 0x5D, 0x03, 0xAE, 0x9A, 0x6F, 0xA3, 0x9A, 0x57, 0x1F, 0xBA, 0x69, 0x30, 0x68, 0xE4, 0x83, 0xC4, 0x82, 0x0D, 0x8C, 0x15, 0x69, 0x4E, 0x07, 0xC6, 0xA9, 0xD9, 0xFE, 0xB4, 0x67, 0x57, 0x3B, 0x42, 0x33, 0x86, 0xF3, 0x2B, 0x75, 0x4C, 0xCE, 0x64, 0x25, 0xE0, 0x02, 0xAC, 0x00, 0xF4, 0x74, 0x90, 0x50, 0xCE, 0x2D, 0x26, 0x27, 0xD0, 0x6F, 0x03, 0x2B, 0x34, 0x9B, 0xC3, 0x65, 0xC7, 0x2B, 0xCC, 0x47, 0x23, 0xD5, 0xB7, 0xEA, 0xAC, 0x8A, 0x50, 0xC0, 0xE3, 0x6D, 0x9E, 0x5D, 0x02, 0x1C, 0x9F, 0xAD, 0xB9, 0xAD, 0xB1, 0xA8, 0x38, 0x1B, 0x0E, 0xCB, 0x7E, 0xEF, 0x67, 0x03, 0x49, 0xCC, 0x6A, 0x65, 0xA3, 0x19, 0xB9, 0x4C, 0xA6, 0x1F, 0xC5, 0x79, 0xAC, 0xA4, 0xEF, 0xDE, 0x1A, 0x24, 0xBD, 0xC9, 0x01, 0x9A, 0x59, 0x3F, 0x30, 0x05, 0x8D, 0xB1, 0xF8, 0xDF, 0x33, 0x84, 0xE1, 0xFC, 0xDD, 0x71, 0xBB, 0x91, 0x0A, 0xE3, 0xCA, 0xF5, 0xF9, 0xAE, 0xD9, 0x98, 0x3C, 0xFD, 0xEE, 0x6D, 0xA4, 0xE8, 0xA2, 0x0A, 0x12, 0x40, 0xF3, 0x94, 0xA9, 0xAF, 0xF6, 0x60, 0xB4, 0x04, 0xF1, 0xB1, 0xBC, 0x0E, 0x80, 0x98, 0x6E, 0xF3, 0xB6, 0xCF, 0xFF, 0x6C, 0x6A, 0x9F, 0x16, 0x10, 0x46, 0x6C, 0x40, 0x1D, 0xA7, 0x74, 0x01, 0xD1, 0x40, 0x25, 0x7E, 0xD6, 0xE7, 0xFA, 0x6C, 0x7A, 0xE8, 0x41, 0xF0, 0x50, 0xDB, 0x4C, 0x80, 0xAB, 0x27, 0x68, 0xBE, 0x8D, 0xA9, 0x81, 0xFC, 0xCF, 0x6C, 0xEA, 0x22, 0xAE, 0x23, 0xE9, 0xC4, 0x70, 0x9A, 0x0B, 0x4D, 0x6E, 0xA8, 0x2A, 0xC1, 0xE4, 0x3A, 0x1D, 0xC1, 0xB6, 0x4F, 0x2A, 0x99, 0xC6, 0xBD, 0x9F, 0xC8, 0x69, 0x2C, 0xDC, 0x0B, 0x90, 0x7B, 0x57, 0x82, 0x6C, 0x7C, 0x1D, 0x00, 0xFC, 0x94, 0x5E, 0x67, 0x02, 0x55, 0x38, 0x05, 0x17, 0x8F, 0x51, 0xC9, 0xDE, 0xB7, 0xEF, 0xC6, 0x94, 0xFF, 0xDD, 0x6C, 0xAA, 0x8D, 0x17, 0x4D, 0x8E, 0xD1, 0xBF, 0x34, 0x50, 0x4A, 0x6C, 0x20, 0x16, 0x20, 0x3C, 0xB3, 0x93, 0x47, 0x6B, 0xF6, 0xF1, 0x19, 0x34, 0x9F, 0xB9, 0x21, 0x32, 0x95, 0xF5, 0xEE, 0x17, 0x03, 0x8C, 0x79, 0x36, 0xB2, 0xDB, 0x44, 0x7F, 0x70, 0xF4, 0xB4, 0x6F, 0xE3, 0xBD, 0xCC, 0x81, 0xCA, 0x4F, 0xDD, 0x67, 0x29, 0x13, 0x30, 0x16, 0x70, 0x3C, 0xCA, 0x46, 0xE9, 0xE0, 0xD3, 0x9F, 0x8F, 0x2C, 0x1E, 0xC9, 0xDF, 0x10, 0x99, 0xA6, 0xF4, 0x7E, 0xEB, 0x7D, 0x9D, 0xEB, 0x1E, 0xEA, 0x09, 0xE8, 0x14, 0x0E, 0x78, 0xF1, 0x45, 0x4E, 0x6B, 0x66, 0x43, 0xC2, 0x9C, 0x62, 0xC1, 0xD4, 0x63, 0x09, 0x52, 0x5F, 0x7A, 0x0A, 0xC6, 0x1E, 0xCB, 0x31, 0x3C, 0x77, 0x61, 0xB0, 0x94, 0xAC, 0x1F, 0x32, 0x40, 0x93, 0x10, 0x60, 0x37, 0x20, 0x0B, 0x40, 0x7D, 0x1B, 0x46, 0x2D, 0x63, 0xC6, 0xA1, 0x15, 0x63, 0xFA, 0x55, 0x77, 0xD5, 0x5E, 0xED, 0x8A, 0xDC, 0xC1, 0x62, 0xDB, 0x9F, 0xEC, 0x69, 0x0A, 0x3B, 0x23, 0xEB, 0xCD, 0xEC, 0xDB, 0xBC, 0x3A, 0x63, 0x5D, 0x5B, 0x48, 0x48, 0x5D, 0x00, 0x4B, 0x3C, 0x93, 0x32, 0xC8, 0xA8, 0xF1, 0x99, 0x57, 0x25, 0x34, 0xC6, 0x47, 0x79, 0xB4, 0xCF, 0x5C, 0xB2, 0x37, 0xA5, 0xB1, 0xFD, 0x36, 0x40, 0x31, 0x03, 0xB6, 0x03, 0xB9, 0xAF, 0x33, 0x42, 0x1F, 0x63, 0xCE, 0x29, 0x2A, 0x1B, 0xB3, 0x40, 0xA3, 0x77, 0x98, 0xC4, 0x2B, 0x59, 0x6C, 0x01, 0x5A, 0x98, 0x75, 0x64, 0x80, 0x7D, 0x8E, 0x24, 0x80, 0xDD, 0x80, 0xF6, 0xD4, 0xFD, 0x4E, 0xD0, 0x04, 0xE9, 0x62, 0xB7, 0x2F, 0x2F, 0x72, 0x15, 0xFB, 0x59, 0x4A, 0xC5, 0x76, 0xE4, 0xFA, 0x3B, 0xCD, 0x10, 0x91, 0x19, 0xDF, 0xFE, 0x6D, 0x88, 0xA4, 0x93, 0x1A, 0x60, 0xF3, 0x96, 0x1E, 0x87, 0xD6, 0x69, 0x9C, 0xFD, 0xB6, 0xCB, 0x3A, 0xCB, 0x5A, 0xC3, 0x1C, 0xAB, 0x67, 0xEB, 0xF8, 0xDD, 0xDA, 0x9C, 0x9D, 0xF6, 0xEE, 0x77, 0xAD, 0xB9, 0x15, 0x90, 0x20, 0x12, 0x98, 0xA9, 0x47, 0x9D, 0x16, 0x5C, 0x3D, 0xC2, 0xF0, 0x5D, 0xC8, 0xF9, 0xF1, 0x79, 0xEC, 0xF1, 0x80, 0xD4, 0x49, 0xB5, 0x7C, 0xF7, 0x53, 0xAA, 0x89, 0x05, 0x4C, 0xB2, 0x75, 0x0B, 0xE0, 0x1B, 0x88, 0xE0, 0x29, 0x7B, 0xA2, 0x76, 0xFC, 0x5A, 0x61, 0xFB, 0x66, 0x27, 0x5C, 0x07, 0xF2, 0xA7, 0xAA, 0x67, 0x26, 0xAD, 0x4A, 0xFA, 0xDC, 0xF9, 0xE1, 0x97, 0x7F, 0xF7, 0xF1, 0xB0, 0xC3, 0xCE, 0x01, 0xC4, 0x47, 0x8E, 0x4C, 0xA9, 0xB0, 0x73, 0x82, 0x39, 0x99, 0xDF, 0x3F, 0xD8, 0xE9, 0x8B, 0xB2, 0x74, 0x3E, 0xE7, 0x95, 0x43, 0xEC, 0xCF, 0x54, 0x9A, 0x93, 0xB8, 0xD9, 0x30, 0x0F, 0x05, 0x9C, 0x50, 0x01, 0x70, 0xA6, 0xF3, 0x97, 0xD9, 0xD9, 0xB9, 0xDB, 0xB8, 0xA1, 0xF3, 0x36, 0xC4, 0xB6, 0x01, 0xC6, 0x50, 0x38, 0xF7, 0x61, 0x7C, 0xFF, 0x35, 0xC9, 0xD9, 0x53, 0x52, 0x09, 0x84, 0x02, 0xBE, 0x01, 0x21, 0xF6, 0x02, 0xD4, 0x27, 0x5B, 0x6E, 0x82, 0x66, 0x58, 0x51, 0xCB, 0x46, 0x99, 0x94, 0xDB, 0x55, 0x6F, 0x57, 0xB4, 0x32, 0x55, 0x33, 0xB1, 0x53, 0xCD, 0x05, 0x55, 0xAB, 0xDD, 0x2D, 0xA9, 0x92, 0x77, 0x1F, 0x6F, 0x32, 0x53, 0x4E, 0x7C, 0x4E, 0x5D, 0xBE, 0xAE, 0xD9, 0xC0, 0xBB, 0x2B, 0x84, 0x3C, 0xAE, 0x1B, 0x2A, 0xD7, 0xD1, 0x78, 0xE1, 0xE2, 0x9B, 0xBA, 0x87, 0x3C, 0xED, 0xBC, 0xF6, 0x31, 0xB8, 0x02, 0xD2, 0x2F, 0xE2, 0x6F, 0x8F, 0x78, 0x5D, 0xF7, 0x0C, 0x3C, 0xB8, 0x6E, 0x67, 0x8B, 0x1E, 0x51, 0x76, 0x32, 0xB9, 0x4E, 0x21, 0xA9, 0x35, 0x2F, 0xE1, 0x04, 0x8A, 0x68, 0x07, 0xCA, 0x80, 0xD8, 0x80, 0xAF, 0x9B, 0x09, 0x7B, 0x77, 0x8C, 0xDD, 0xE9, 0xEC, 0x43, 0xBF, 0x7D, 0x96, 0x04, 0x89, 0x27, 0x24, 0xAF, 0x54, 0x04, 0x54, 0x47, 0x07, 0x33, 0xBA, 0xD3, 0x60, 0x25, 0xA5, 0x5F, 0x57, 0x13, 0x7B, 0xFC, 0xFE, 0xE7, 0xC2, 0x14, 0xAA, 0xCF, 0x32, 0x0E, 0xFB, 0x75, 0xDC, 0x3A, 0x7C, 0x36, 0xA3, 0xB8, 0x80, 0xE4, 0xFB, 0xFA, 0x69, 0xB9, 0xE0, 0x27, 0xA5, 0x2A, 0xA6, 0x3C, 0xCA, 0x5F, 0x21, 0x4D, 0x04, 0x38, 0x0D, 0x2A, 0xE7, 0xCF, 0x8E, 0x9A, 0x57, 0xC6, 0x1C, 0x71, 0x46, 0x6D, 0x37, 0xA3, 0x66, 0x94, 0xAB, 0x03, 0xE1, 0x5A, 0x8C, 0xCC, 0x2A, 0x04, 0x61, 0x19, 0x10, 0x0B, 0x48, 0x01, 0xC2, 0x01, 0x2B, 0x40, 0x1F, 0xAF, 0xCD, 0x2B, 0x46, 0x7A, 0x60, 0x95, 0xB5, 0xEA, 0xED, 0xCB, 0x3B, 0x75, 0x49, 0xA6, 0x78, 0xE8, 0xAF, 0x46, 0xBB, 0x65, 0xEE, 0x49, 0xEE, 0xC2, 0x50, 0xFB, 0x7A, 0xC6, 0x9B, 0xDD, 0x82, 0xB5, 0xDD, 0x47, 0xAF, 0x76, 0x8A, 0x31, 0x3D, 0x3B, 0x1A, 0x71, 0x77, 0xF7, 0xF4, 0xA4, 0x6D, 0x84, 0x63, 0xCE, 0xFA, 0x24, 0xFE, 0xF8, 0xB1, 0xDA, 0x8B, 0xF8, 0x04, 0x6D, 0x01, 0xDB, 0x01, 0x51, 0xA0, 0xE2, 0x56, 0xF7, 0x6D, 0x9D, 0xA5, 0x13, 0xFF, 0x6C, 0xF2, 0x09, 0xB4, 0x39, 0xD3, 0x96, 0xA3, 0xC7, 0x97, 0xDD, 0x84, 0x73, 0xC4, 0x07, 0xF7, 0x91, 0x4D, 0x08, 0xB0, 0x94, 0x3F, 0x4B, 0xC0, 0x04, 0x60, 0x7A, 0x2F, 0x80, 0xA0, 0x25, 0x66, 0x12, 0x4B, 0xD1, 0x6D, 0xFC, 0xAA, 0xDE, 0x00, 0x9F, 0x4E, 0x1A, 0x6C, 0x7B, 0xD3, 0x5C, 0x7A, 0x63, 0x4B, 0x6A, 0xBA, 0x13, 0xE4, 0x04, 0x2D, 0xCE, 0x16, 0x11, 0x97, 0x22, 0x94, 0xEE, 0x4D, 0x6F, 0x1B, 0xC5, 0x18, 0x75, 0x6B, 0xA4, 0xC1, 0xE3, 0x7D, 0x64, 0x71, 0x73, 0xF1, 0xE8, 0xAE, 0xDC, 0xE7, 0x62, 0x8F, 0xE9, 0x06, 0x22, 0x93, 0x9D, 0x05, 0x68, 0xBF, 0x6B, 0xF6, 0x8C, 0x47, 0x83, 0x8C, 0x63, 0x1F, 0x2C, 0x7E, 0x3D, 0x35, 0x6E, 0x5B, 0x7C, 0x99, 0xB9, 0x0E, 0xD0, 0xFB, 0x4D, 0x7B, 0x77, 0x27, 0x0C, 0x90, 0x71, 0x12, 0x28, 0xC0, 0x89, 0x11, 0x3C, 0x4A, 0x27, 0x68, 0xC5, 0x9E, 0x78, 0x32, 0x23, 0x8D, 0xCD, 0xE3, 0xF7, 0xA3, 0x74, 0x98, 0x6E, 0xEE, 0x70, 0x2B, 0x4D, 0xE9, 0xFB, 0x69, 0x33, 0x9E, 0xF1, 0x35, 0xB8, 0xDA, 0x77, 0xA7, 0x9C, 0x8A, 0x28, 0x2D, 0xB8, 0xEE, 0x2E, 0xBA, 0x9D, 0x00, 0x29, 0x02, 0x24, 0xA7, 0x95, 0xF9, 0xDB, 0x14, 0xC4, 0x9F, 0xD6, 0x31, 0xF0, 0x4C, 0x7A, 0xC6, 0x98, 0x0A, 0xD1, 0xB7, 0x1E, 0x2F, 0x66, 0x23, 0xCF, 0x4E, 0x13, 0x47, 0xDF, 0xA7, 0xE6, 0x89, 0x1F, 0x6D, 0xFA, 0x61, 0x4E, 0x7A, 0x09, 0xD0, 0x8C, 0xC5, 0x52, 0x20, 0xE4, 0x0D, 0xD0, 0xF1, 0x5D, 0x31, 0xC0, 0x17, 0x70, 0x27, 0x50, 0x8C, 0x1A, 0x93, 0xE2, 0x3B, 0x7E, 0x8F, 0x02, 0x79, 0xED, 0x86, 0xC4, 0xB6, 0x51, 0x74, 0xDF, 0xBC, 0x5D, 0xCF, 0x67, 0xDF, 0x9C, 0xA3, 0x7D, 0x95, 0x8E, 0xFA, 0xB4, 0x92, 0xDA, 0xCF, 0xBE, 0x12, 0x44, 0x6D, 0xAE, 0x77, 0xF9, 0x2C, 0xC8, 0xEB, 0x81, 0x44, 0x85, 0xE6, 0xF4, 0xE3, 0xC4, 0xCF, 0x6E, 0x28, 0x7D, 0xAE, 0x3E, 0xDE, 0xFD, 0x43, 0x00, 0x4F, 0xC0, 0x1E, 0x71, 0xB7, 0x46, 0x9F, 0xC4, 0x39, 0x18, 0xCD, 0x39, 0xCD, 0x44, 0xAF, 0x85, 0x8D, 0x9C, 0xFD, 0xAF, 0xBD, 0x3E, 0xD7, 0x29, 0xD7, 0xA4, 0xFB, 0x83, 0xB5, 0xE6, 0x1A, 0x06, 0xAC, 0x80, 0xF0, 0x59, 0xBD, 0x32, 0x6A, 0x54, 0x4F, 0x34, 0xED, 0x7B, 0x57, 0x23, 0xF8, 0xD5, 0xB1, 0x0D, 0xE3, 0xC9, 0x48, 0x52, 0x44, 0x69, 0x7F, 0x9B, 0xCB, 0xCE, 0x2D, 0xFD, 0x3C, 0x40, 0x37, 0x83, 0xF6, 0x64, 0xC0, 0x4C, 0xEB, 0xAB, 0xE2, 0xFB, 0xED, 0x94, 0x85, 0xEA, 0xFB, 0xC8, 0x04, 0x20, 0xBC, 0xB2, 0x34, 0xF1, 0x75, 0x1C, 0xDD, 0x0A, 0x68, 0xCC, 0x8B, 0xB7, 0x40, 0x77, 0xF4, 0xF1, 0x9D, 0x67, 0x51, 0x31, 0xBB, 0x54, 0xCE, 0xC7, 0x62, 0xFA, 0xB5, 0xC1, 0xEE, 0x63, 0x3D, 0xEC, 0xFB, 0xEE, 0xDE, 0xC9, 0xC9, 0xBC, 0xF7, 0x0D, 0xD8, 0x02, 0xB6, 0x03, 0x6B, 0x03, 0x22, 0x9C, 0x8A, 0xE4, 0x04, 0x6D, 0x7F, 0xA2, 0x85, 0x95, 0xC6, 0x8E, 0x46, 0xCE, 0xAA, 0xED, 0xFF, 0xA0, 0xFB, 0x2B, 0x2E, 0xBA, 0x32, 0xA8, 0x3B, 0x15, 0x8F, 0x14, 0x19, 0xFD, 0xE9, 0x5D, 0xA9, 0xF5, 0x74, 0x3F, 0x41, 0x56, 0xF1, 0x9B, 0x4B, 0x97, 0xBC, 0x78, 0x0B, 0x88, 0xF1, 0xEC, 0xD1, 0xEB, 0xDE, 0xDE, 0xE7, 0x6E, 0xB3, 0x05, 0x28, 0x1D, 0xA9, 0x02, 0xB1, 0x37, 0xBE, 0x61, 0x32, 0x00, 0xF7, 0x9E, 0x5E, 0x92, 0x33, 0xF0, 0xB8, 0x81, 0xF0, 0xFA, 0x96, 0x0A, 0x31, 0x16, 0x05, 0x6D, 0xC4, 0x9B, 0x53, 0x79, 0x36, 0x68, 0x84, 0xD8, 0xC6, 0x17, 0x13, 0x30, 0xF9, 0x18, 0x01, 0xFC, 0x60, 0x38, 0x62, 0xD4, 0xE4, 0x1B, 0x35, 0xE6, 0xAB, 0xED, 0x7B, 0x9D, 0x9A, 0x75, 0x43, 0xA3, 0xD2, 0xFA, 0xC1, 0x7B, 0x2A, 0x7D, 0x5E, 0x07, 0xBA, 0x91, 0x55, 0x6D, 0xA2, 0xD5, 0xEB, 0xD3, 0x0D, 0xE4, 0x64, 0xE0, 0x00, 0xE9, 0x77, 0x3D, 0x49, 0x21, 0x69, 0x0A, 0xCD, 0xB4, 0xCE, 0x4E, 0xAF, 0x11, 0x63, 0xFD, 0x33, 0x15, 0x54, 0x2A, 0xB7, 0x23, 0x2F, 0x53, 0xDA, 0x90, 0xA1, 0xF1, 0x94, 0xC7, 0x9F, 0x14, 0xE8, 0xE9, 0xAE, 0xB5, 0x00, 0x4D, 0x62, 0x8E, 0x04, 0x98, 0x34, 0x67, 0xF5, 0xFF, 0x87, 0xF1, 0xAD, 0x02, 0xD6, 0x40, 0x2E, 0x9E, 0xF2, 0x17, 0xB4, 0xBB, 0x88, 0x72, 0x14, 0x64, 0x24, 0x64, 0xD4, 0x9B, 0xB5, 0x9C, 0x29, 0x4A, 0xFD, 0x16, 0x9D, 0xB3, 0xF7, 0x6E, 0xDE, 0xCD, 0x38, 0xD4, 0xEA, 0x93, 0xEB, 0x7D, 0xA6, 0x5E, 0x71, 0x26, 0x9E, 0x40, 0xCD, 0xE3, 0x71, 0xF2, 0x61, 0x8B, 0xF0, 0x9B, 0x34, 0xAA, 0x67, 0xCB, 0xAA, 0xFD, 0x6D, 0x17, 0xBD, 0x94, 0x71, 0x6A, 0x4E, 0xC4, 0x6E, 0x53, 0xFA, 0x3C, 0xCF, 0xD3, 0xFD, 0xB4, 0xE7, 0xD7, 0x63, 0x28, 0xE1, 0x05, 0x88, 0x03, 0x7B, 0x03, 0xAB, 0xDE, 0xA3, 0x19, 0x9B, 0xAB, 0x01, 0x7F, 0x9D, 0x32, 0xCE, 0x99, 0xB1, 0x01, 0x69, 0xE0, 0x9C, 0x52, 0x27, 0x6A, 0xF6, 0xDB, 0xC5, 0xD3, 0xDE, 0x4C, 0x4D, 0xDA, 0x74, 0xCB, 0xB6, 0x67, 0x5B, 0xCA, 0x7B, 0x1E, 0xEA, 0xC6, 0x87, 0xA3, 0xBE, 0xFA, 0x6D, 0x7C, 0x6A, 0x3F, 0x57, 0xAF, 0x5B, 0x86, 0x9D, 0xE7, 0x46, 0x56, 0xC7, 0x9A, 0x12, 0x88, 0x45, 0x6C, 0x86, 0x64, 0x5F, 0x39, 0x8D, 0xB2, 0xC8, 0xD5, 0xEE, 0x4B, 0xEF, 0x0A, 0x5F, 0x81, 0x59, 0xCE, 0x4E, 0x2F, 0x9F, 0x3E, 0x4E, 0xD3, 0xBA, 0xDF, 0x6E, 0xD7, 0xFE, 0xE9, 0x11, 0xB2, 0x06, 0x0E, 0xEC, 0x05, 0x18, 0xDF, 0xB7, 0x3F, 0x75, 0xDB, 0xBE, 0x81, 0x7D, 0x96, 0x38, 0x80, 0xC6, 0xDB, 0xCA, 0xD7, 0xF5, 0x44, 0xCD, 0xFF, 0xAB, 0x82, 0x83, 0x55, 0xFC, 0x56, 0x07, 0x30, 0xF4, 0x76, 0x87, 0x1B, 0x47, 0x87, 0xB3, 0x13, 0xA8, 0x28, 0x9E, 0xA4, 0x29, 0xD8, 0x49, 0xB2, 0x98, 0x46, 0xC6, 0x6F, 0x7B, 0x76, 0xFB, 0x34, 0xB5, 0xDF, 0xF9, 0xC9, 0xB4, 0xDB, 0xD3, 0xC0, 0x14, 0xC8, 0xC9, 0x8A, 0x24, 0xDA, 0x4E, 0xF1, 0xF1, 0xE4, 0x77, 0x9C, 0xE6, 0xFF, 0xA3, 0x06, 0x4E, 0xD7, 0x40, 0x19, 0x61, 0x83, 0xE3, 0xF7, 0xB6, 0xAC, 0xD9, 0x06, 0x35, 0x6F, 0xC2, 0xC5, 0xD5, 0x7F, 0x7F, 0xEA, 0x0A, 0xC4, 0x81, 0xDD, 0x80, 0x18, 0xE0, 0x0C, 0xA5, 0x4C, 0x80, 0x36, 0x70, 0x5E, 0x3C, 0x26, 0xBC, 0x80, 0xC5, 0xEB, 0x2D, 0x10, 0xEB, 0x44, 0x2D, 0xD8, 0xAB, 0x86, 0x89, 0x68, 0x1A, 0x28, 0x30, 0xB2, 0x77, 0xAC, 0xA9, 0x37, 0x06, 0x0E, 0xD3, 0xFD, 0x22, 0x9C, 0xE9, 0x56, 0xDF, 0x8D, 0x63, 0xBF, 0x83, 0xBC, 0x67, 0x2F, 0x52, 0x4E, 0x43, 0xA3, 0x55, 0x80, 0x13, 0x35, 0xB5, 0xC4, 0xC4, 0xD4, 0xC3, 0xAE, 0x09, 0x9E, 0xDD, 0x67, 0xBD, 0x9F, 0x4A, 0xF3, 0x93, 0x42, 0xD0, 0x53, 0x7A, 0xCD, 0xEF, 0x65, 0xD2, 0xC1, 0xE3, 0xE9, 0xD8, 0xAC, 0x73, 0x7F, 0x98, 0x20, 0x38, 0x60, 0x46, 0x6C, 0x22, 0xAE, 0x9F, 0x72, 0x31, 0x4E, 0x7D, 0x34, 0xF4, 0x36, 0x20, 0x36, 0xB0, 0xE2, 0x8D, 0xE8, 0xFC, 0xAC, 0xF2, 0x44, 0x2D, 0xD1, 0x33, 0xFB, 0xB6, 0xB0, 0xF4, 0x5F, 0x35, 0x51, 0x62, 0x5F, 0xA8, 0xB1, 0x8D, 0x37, 0x5F, 0xB2, 0x6C, 0x99, 0x4A, 0xE6, 0x27, 0x57, 0x4D, 0xEE, 0x50, 0x9B, 0x64, 0x81, 0x49, 0xC2, 0xC7, 0xA9, 0xD3, 0xE7, 0xC7, 0x18, 0x98, 0x00, 0x7C, 0x01, 0xCD, 0x95, 0xCF, 0x08, 0x6B, 0x39, 0x4B, 0x1E, 0xE5, 0x50, 0xDB, 0x40, 0xF7, 0xE4, 0x0D, 0x33, 0xF7, 0x55, 0x47, 0xE4, 0xBD, 0x3E, 0xA4, 0xF4, 0x7C, 0xEA, 0x63, 0xF0, 0x5E, 0x06, 0x2C, 0x79, 0xE3, 0x23, 0x0E, 0xEC, 0x24, 0xFA, 0xB5, 0xA4, 0x16, 0xFD, 0xC7, 0x05, 0x2A, 0xEB, 0x8D, 0x96, 0xC6, 0xFB, 0x06, 0xF3, 0x13, 0xB4, 0x59, 0x7B, 0xF2, 0x99, 0x67, 0x8A, 0x3A, 0x3E, 0x4B, 0x0C, 0x5F, 0x53, 0x18, 0x18, 0xEB, 0xB4, 0x8A, 0xAF, 0x1F, 0xA4, 0xEB, 0x31, 0xD6, 0xF4, 0x98, 0xA1, 0x36, 0xB6, 0x2C, 0x6F, 0x69, 0x88, 0x1C, 0xF3, 0xD8, 0x25, 0x80, 0x07, 0x90, 0x0A, 0x54, 0xF3, 0xD3, 0x4F, 0xCF, 0xE5, 0xBB, 0x4D, 0x74, 0x35, 0xAD, 0xDC, 0xE3, 0x11, 0x79, 0xAD, 0x4A, 0x39, 0x0B, 0xA9, 0x63, 0x28, 0x5F, 0xC7, 0x37, 0x06, 0x58, 0x9F, 0x8A, 0xAA, 0x55, 0x9F, 0x09, 0xC7, 0xFA, 0x57, 0x87, 0xBC, 0xA9, 0xF3, 0x20, 0xF6, 0xBC, 0xF8, 0xDA, 0x9F, 0xF3, 0xC5, 0xDB, 0x21, 0xAF, 0x4F, 0xD4, 0x50, 0xBB, 0x22, 0xBA, 0x91, 0xCF, 0xB8, 0x90, 0x1D, 0x59, 0x2A, 0x48, 0xB0, 0x70, 0x85, 0x37, 0x9D, 0x25, 0x6D, 0x74, 0x85, 0xF5, 0x12, 0x36, 0xB3, 0xB5, 0x77, 0x8E, 0x3B, 0xBF, 0x55, 0x26, 0x31, 0xA5, 0x6F, 0x43, 0x41, 0x24, 0x54, 0x02, 0xA6, 0x40, 0x6C, 0x20, 0x79, 0xB9, 0x4E, 0xE3, 0xC5, 0xDD, 0x57, 0x41, 0xEC, 0xD3, 0x13, 0xC8, 0xD7, 0xCD, 0x7E, 0xDE, 0x7F, 0xE2, 0x9B, 0x8C, 0x50, 0x3F, 0xA5, 0xCD, 0x2C, 0x7B, 0x7A, 0xBB, 0x98, 0x29, 0xB1, 0x4E, 0x81, 0x14, 0xA1, 0xC4, 0x9C, 0xA2, 0x40, 0xD7, 0x5B, 0x0D, 0x24, 0xF5, 0x7A, 0xA2, 0x7B, 0x00, 0x42, 0xD8, 0x9C, 0x69, 0x13, 0xB5, 0x5C, 0x7F, 0x63, 0x2D, 0x61, 0x0D, 0x9C, 0xBF, 0x1B, 0x28, 0x04, 0x0E, 0xDD, 0xA8, 0xF8, 0xC9, 0x52, 0x8C, 0x35, 0xA5, 0x61, 0x4B, 0xDF, 0x2B, 0xF3, 0xDD, 0x6E, 0xE7, 0xF3, 0xF9, 0xFE, 0x6F, 0xB7, 0x79, 0x82, 0x2D, 0x20, 0x89, 0xE3, 0xA8, 0xBD, 0xEB, 0x7A, 0xAB, 0x8E, 0x3A, 0x89, 0x2D, 0x9B, 0xC7, 0x4E, 0x43, 0x85, 0xFB, 0x05, 0x7E, 0x1F, 0xBD, 0x8A, 0x8B, 0xB8, 0x4F, 0x48, 0x66, 0xE2, 0x91, 0xFD, 0x99, 0xA7, 0xD9, 0x3B, 0x9E, 0x56, 0x12, 0x9B, 0xF8, 0xF4, 0xF9, 0xEF, 0xB9, 0x19, 0xDB, 0xBF, 0xA6, 0x2F, 0x0B, 0x10, 0x42, 0x9B, 0xA7, 0x9C, 0xA8, 0xB1, 0x9D, 0xB1, 0x1B, 0x27, 0x68, 0x53, 0x86, 0xB9, 0xF5, 0x59, 0xBA, 0xB7, 0x0A, 0xD4, 0xE2, 0xDC, 0xB8, 0x03, 0xA9, 0xB3, 0xD0, 0xE7, 0x15, 0x71, 0x5D, 0x9E, 0x25, 0x34, 0x77, 0x0A, 0xD1, 0x09, 0x9C, 0x31, 0x08, 0x0E, 0xA0, 0xE6, 0x82, 0xDA, 0x01, 0x1C, 0xED, 0xBF, 0x6A, 0x4E, 0xCA, 0x84, 0x31, 0xEB, 0x9A, 0x00, 0x3A, 0xE9, 0xB8, 0x39, 0x6D, 0x96, 0xE6, 0xB7, 0xCC, 0x93, 0x37, 0xF9, 0xAF, 0x19, 0x17, 0xC6, 0xD4, 0x72, 0x73, 0xF2, 0x43, 0x1C, 0x10, 0x01, 0xD6, 0x9E, 0x60, 0xF3, 0x68, 0xBD, 0xD6, 0xD4, 0xBA, 0x81, 0x72, 0x20, 0x37, 0xA0, 0x7C, 0x7B, 0x06, 0xA0, 0x0B, 0x38, 0x9E, 0xED, 0x35, 0x41, 0x9B, 0x85, 0xC1, 0xE4, 0x52, 0x06, 0x3B, 0x42, 0xD7, 0x15, 0xD8, 0x3A, 0x3B, 0x31, 0x6F, 0xC5, 0xB6, 0x81, 0x58, 0xED, 0xB7, 0xEE, 0x27, 0x3E, 0x2D, 0x31, 0x72, 0xDD, 0xC7, 0x33, 0x6E, 0xDF, 0x7C, 0xCC, 0xF9, 0x00, 0x37, 0xEE, 0xE7, 0x67, 0x3D, 0xCB, 0xC7, 0x7D, 0x6A, 0x99, 0x6C, 0x76, 0x52, 0x92, 0xB1, 0x88, 0xEB, 0xC1, 0xCD, 0xDC, 0xD8, 0x3A, 0xDB, 0xFA, 0x71, 0xDA, 0x75, 0x4C, 0x1B, 0x50, 0x20, 0x1C, 0xF0, 0x0D, 0x48, 0x00, 0x7B, 0x60, 0x44, 0x02, 0xAE, 0x33, 0x72, 0x80, 0x68, 0xC0, 0x03, 0x10, 0xF9, 0x54, 0x9D, 0x2E, 0xC0, 0x8B, 0xA7, 0x9C, 0xA1, 0x76, 0x1B, 0x1A, 0x7B, 0xA3, 0x87, 0x65, 0xFE, 0x1E, 0x6F, 0x89, 0x6A, 0x59, 0x55, 0xB4, 0xFB, 0xCD, 0x0D, 0xAB, 0xAC, 0x82, 0x0D, 0x91, 0x79, 0xDE, 0x96, 0x18, 0xD7, 0xEB, 0xAA, 0xEF, 0xAD, 0x13, 0x5F, 0xDA, 0xD3, 0x11, 0x61, 0x05, 0x8F, 0x1A, 0x08, 0x07, 0x6C, 0x01, 0x3E, 0xCF, 0x2B, 0x63, 0x7C, 0xDD, 0xDF, 0xE6, 0xD5, 0x31, 0x59, 0xF1, 0x08, 0xD7, 0xE8, 0x50, 0x1A, 0x6F, 0x0A, 0xA0, 0x24, 0xB0, 0xE2, 0xDB, 0x33, 0xE4, 0xD3, 0x35, 0xB5, 0x89, 0x7A, 0xAF, 0x53, 0x95, 0xCF, 0x05, 0x1A, 0x13, 0xC3, 0xF7, 0x02, 0xB5, 0x04, 0x76, 0x7D, 0x16, 0xA1, 0x27, 0x6A, 0x47, 0xE8, 0x60, 0xB6, 0xAA, 0xD3, 0xF9, 0x4A, 0xF4, 0x8E, 0x35, 0xDB, 0xDA, 0xF0, 0x61, 0xF1, 0x8D, 0x6D, 0x20, 0x49, 0xBA, 0x35, 0x7D, 0xDB, 0x40, 0xEB, 0xFC, 0xFB, 0x6F, 0x67, 0x61, 0x17, 0x20, 0x0D, 0x88, 0x04, 0xDC, 0x00, 0x73, 0xE0, 0xE6, 0xBC, 0x23, 0x4E, 0xA3, 0x61, 0x77, 0x00, 0x29, 0x8C, 0xE1, 0x66, 0xF0, 0x0C, 0xF1, 0x9D, 0x9C, 0xB6, 0xD7, 0xC3, 0xE9, 0xC4, 0xD0, 0xF5, 0xB3, 0xE8, 0xEE, 0x7F, 0xAD, 0xA7, 0x04, 0x38, 0xB5, 0x69, 0x0E, 0x78, 0x03, 0xF6, 0x59, 0xC1, 0x47, 0x00, 0xAA, 0xEF, 0xE0, 0x34, 0x3D, 0x51, 0xF3, 0x5F, 0x1B, 0xE8, 0xDD, 0xC2, 0xDD, 0x57, 0xFB, 0x2F, 0x15, 0xF8, 0xA5, 0xA6, 0x71, 0xFE, 0xE1, 0x12, 0xD8, 0x82, 0xCB, 0xC2, 0x2C, 0x46, 0xF5, 0xAD, 0x38, 0x8E, 0xB7, 0xFD, 0xCA, 0x19, 0x41, 0xD9, 0x8C, 0x85, 0x02, 0xE5, 0xEF, 0x14, 0xB2, 0x8A, 0xB0, 0xB7, 0x5E, 0xF4, 0xC7, 0x29, 0x25, 0x64, 0xA7, 0x00, 0xC0, 0xEF, 0x6E, 0xFA, 0xC8, 0x8D, 0x53, 0xC6, 0x39, 0x75, 0x2B, 0x31, 0x52, 0xEF, 0xED, 0xDE, 0x02, 0xE8, 0xBC, 0xD8, 0x44, 0x11, 0xF9, 0xAE, 0x0C, 0x62, 0xBD, 0xCF, 0xC7, 0x68, 0xC0, 0xF3, 0x35, 0xA5, 0x2B, 0x01, 0x7C, 0xDF, 0xBA, 0xE5, 0x7C, 0xAE, 0x50, 0x48, 0x91, 0x21, 0xD8, 0x27, 0xF6, 0xBD, 0x7F, 0x2B, 0x03, 0xDD, 0x7D, 0x05, 0x0F, 0x6F, 0x0B, 0xDC, 0x5E, 0x22, 0xB9, 0x76, 0xB6, 0xD9, 0x95, 0x7A, 0x15, 0x49, 0x79, 0xC6, 0x3A, 0x9E, 0x76, 0xB7, 0x94, 0x42, 0xCF, 0x64, 0xDE, 0x0D, 0x30, 0x7F, 0x5F, 0xCC, 0x1F, 0xE2, 0xA4, 0x1A, 0x1F, 0x2F, 0xEF, 0x00, 0x46, 0x29, 0xD9, 0x79, 0xA7, 0x6B, 0x76, 0x76, 0xF6, 0x32, 0xDF, 0xE2, 0xF8, 0x1C, 0x4F, 0x30, 0x42, 0x81, 0x25, 0xC4, 0x22, 0x36, 0x91, 0x80, 0xD5, 0xA4, 0x2B, 0x01, 0x29, 0x80, 0x27, 0x20, 0xB3, 0x40, 0x68, 0x40, 0x15, 0x70, 0xBB, 0xB6, 0x61, 0x88, 0x5A, 0x62, 0x73, 0xBE, 0x13, 0xC5, 0x74, 0x1E, 0xD8, 0x98, 0xD6, 0x7C, 0xAA, 0x58, 0x3C, 0x82, 0xD5, 0x45, 0x5C, 0x19, 0xA4, 0x5D, 0xB3, 0xAB, 0xC8, 0x47, 0xFC, 0xF6, 0xB9, 0xB7, 0xEB, 0xB5, 0xB2, 0x7F, 0x3B, 0x40, 0xAE, 0xC4, 0x51, 0x35, 0x10, 0x1B, 0xA8, 0xBC, 0x05, 0x24, 0x71, 0xB2, 0x16, 0xB6, 0x00, 0xF2, 0xF4, 0x39, 0x30, 0xAE, 0x61, 0xD7, 0xC9, 0xB5, 0xDD, 0x63, 0x2C, 0x5F, 0x80, 0xD9, 0xEB, 0xD0, 0xE4, 0x01, 0xA4, 0x01, 0xBD, 0x89, 0x29, 0x88, 0x95, 0xB7, 0xC2, 0xDF, 0x46, 0x52, 0x5E, 0xF3, 0x20, 0x06, 0x5C, 0xDE, 0xBB, 0xC4, 0x1C, 0xE5, 0xED, 0xFC, 0x88, 0xA0, 0xD5, 0xAF, 0xD2, 0x38, 0xDA, 0x20, 0x6A, 0xC4, 0x46, 0xDE, 0x47, 0x1A, 0xB6, 0x36, 0xC4, 0xF1, 0xE8, 0xDD, 0xCE, 0x7A, 0x3B, 0x40, 0x32, 0x67, 0xC2, 0xF1, 0xA6, 0x94, 0x6A, 0xDE, 0xDE, 0xF3, 0x74, 0x1F, 0x60, 0x92, 0xFA, 0xDB, 0xD2, 0xAF, 0x9C, 0x30, 0x20, 0x17, 0x30, 0xE1, 0x5A, 0xC6, 0xDC, 0xA2, 0x9B, 0x82, 0x48, 0xC1, 0x03, 0x2F, 0x4E, 0xF7, 0xC5, 0x71, 0x1F, 0xE3, 0x87, 0x99, 0xA6, 0xB3, 0xD3, 0x27, 0x76, 0x8C, 0xF4, 0x3B, 0x80, 0xDC, 0x80, 0x15, 0x21, 0x1F, 0xF4, 0xA7, 0x4C, 0xDB, 0xE7, 0xC6, 0x09, 0xAC, 0x79, 0xB1, 0x81, 0xE9, 0xDB, 0x7B, 0xAA, 0xB6, 0xE6, 0x14, 0x99, 0xA8, 0xB1, 0x83, 0xE0, 0xF5, 0x37, 0x81, 0x05, 0x1A, 0x04, 0x8F, 0xED, 0x31, 0x66, 0xEB, 0x8E, 0x5C, 0xD4, 0x54, 0xA8, 0xE6, 0x68, 0x95, 0xB7, 0xE4, 0xB5, 0x42, 0xCF, 0x19, 0xC6, 0xF8, 0x64, 0x3E, 0xCB, 0x47, 0xC0, 0xA0, 0xE8, 0xF0, 0xAB, 0x00, 0x7C, 0x0F, 0xB8, 0x13, 0x39, 0x3D, 0x19, 0x99, 0x3C, 0x91, 0xE3, 0xC7, 0xE2, 0xC0, 0x16, 0xF6, 0x15, 0x64, 0x96, 0x46, 0x30, 0x3D, 0x47, 0x36, 0x55, 0x40, 0xEE, 0x7F, 0xF9, 0x4C, 0xE1, 0xF8, 0x6F, 0xE7, 0x14, 0x94, 0x35, 0xA0, 0x06, 0xEC, 0x24, 0x16, 0x20, 0x02, 0xCC, 0x1B, 0xAC, 0x81, 0x2E, 0xA0, 0x02, 0x70, 0x05, 0xA6, 0x3A, 0x2D, 0x0A, 0xA8, 0xE2, 0x99, 0xCD, 0xA0, 0xD1, 0x0B, 0x79, 0xEA, 0xEF, 0x64, 0x6F, 0xDA, 0xDC, 0xF3, 0x39, 0x68, 0x8E, 0x3B, 0xF3, 0x4A, 0xCC, 0xCF, 0x25, 0xB1, 0x4E, 0xCC, 0x9A, 0x85, 0xC0, 0x2B, 0xE3, 0xDE, 0x4E, 0xFB, 0xD3, 0xD2, 0x07, 0x57, 0xFB, 0x18, 0xF9, 0x4D, 0xD9, 0xE9, 0x06, 0xC4, 0xF9, 0xE2, 0x26, 0x38, 0xC4, 0x5C, 0x66, 0x33, 0x83, 0xFB, 0x42, 0x0B, 0x50, 0xC7, 0x8B, 0x96, 0xD4, 0xC5, 0xF5, 0xDA, 0xFA, 0xCD, 0xEC, 0x0E, 0x61, 0xA2, 0x43, 0x18, 0x8E, 0xC4, 0x00, 0xDB, 0x84, 0x00, 0xBE, 0x09, 0x07, 0x62, 0x9A, 0xCD, 0x0A, 0xD0, 0x1C, 0xBD, 0xEA, 0x80, 0x18, 0x5F, 0x24, 0x2C, 0x81, 0xD5, 0x80, 0xCE, 0x99, 0x3A, 0x41, 0xDB, 0x6C, 0x24, 0xA2, 0x58, 0xFE, 0xB4, 0x62, 0x6C, 0xA8, 0x3D, 0xFB, 0xA0, 0xDB, 0x0B, 0x5F, 0x4B, 0x38, 0xBB, 0x62, 0x1A, 0xF5, 0x8D, 0xB7, 0x35, 0xAF, 0x25, 0x83, 0x36, 0x8B, 0xEC, 0x69, 0xE2, 0x93, 0xEB, 0xB3, 0x36, 0x6A, 0xC0, 0x05, 0xB0, 0xE9, 0xE0, 0x3E, 0xBD, 0x12, 0xA7, 0x31, 0xA1, 0x52, 0xFB, 0x26, 0x8A, 0xAA, 0x87, 0x9D, 0x9A, 0xA0, 0x5B, 0x5F, 0xA8, 0xE7, 0xE3, 0xC6, 0x7C, 0x24, 0xC6, 0xA7, 0x13, 0x88, 0x05, 0x48, 0x13, 0xF2, 0x42, 0x37, 0x90, 0xD3, 0x69, 0xF9, 0xD6, 0xEB, 0x41, 0x81, 0x01, 0xC2, 0x81, 0xC5, 0xB7, 0x07, 0xD1, 0xC6, 0x33, 0xF7, 0x04, 0x0D, 0xC5, 0x05, 0x76, 0x35, 0x22, 0x18, 0xB0, 0x39, 0x3C, 0x3C, 0xB7, 0xB2, 0xEA, 0x4F, 0xF0, 0xEF, 0xCE, 0x8D, 0xD9, 0xF2, 0xE9, 0x67, 0xDC, 0x4F, 0x47, 0x8C, 0x29, 0x15, 0x90, 0x7D, 0x6C, 0xE0, 0x2C, 0x98, 0x4F, 0x9A, 0x23, 0x2B, 0x02, 0x29, 0xC4, 0x38, 0x70, 0x4D, 0x5B, 0x07, 0xE1, 0x22, 0x6E, 0xBA, 0x24, 0xD2, 0xFE, 0x66, 0x1C, 0x72, 0xC6, 0xCA, 0xDB, 0x84, 0x63, 0x32, 0x28, 0x2A, 0x8D, 0xAD, 0x9A, 0x5C, 0xDD, 0xA9, 0x4E, 0x63, 0xF3, 0xDC, 0xC0, 0x69, 0x79, 0xEC, 0x40, 0xD5, 0x3D, 0xCA, 0xD3, 0x6E, 0x65, 0x02, 0xE3, 0xFE, 0x8E, 0xD0, 0xCD, 0xB7, 0xC7, 0x02, 0xC4, 0x00, 0x53, 0xC6, 0x3C, 0x27, 0x68, 0xB3, 0x2C, 0x98, 0x4C, 0x37, 0xFB, 0xD9, 0x2D, 0xAB, 0xD8, 0xED, 0x94, 0x67, 0x5A, 0xF6, 0xD3, 0xE6, 0xB5, 0x14, 0x5B, 0x02, 0x7D, 0x96, 0x03, 0x60, 0x7D, 0xEC, 0x96, 0x63, 0xE6, 0x88, 0x02, 0x78, 0x10, 0x06, 0x28, 0xB1, 0x1B, 0x58, 0x05, 0x48, 0xDD, 0xB5, 0x11, 0x53, 0x2B, 0xB9, 0xA7, 0xF0, 0xAE, 0x07, 0xEC, 0x4E, 0x96, 0xFC, 0xCC, 0xA4, 0x9D, 0x93, 0xFD, 0x34, 0x62, 0xBD, 0x4B, 0xF4, 0x39, 0x65, 0xAD, 0x8F, 0x46, 0xA4, 0xC4, 0x67, 0xD3, 0xA5, 0xED, 0xB3, 0x2C, 0xD0, 0xCF, 0xB2, 0xA0, 0xDF, 0x65, 0x81, 0xED, 0x4F, 0xF7, 0xB2, 0x2A, 0x3B, 0x51, 0xCB, 0x42, 0x9E, 0x42, 0xFF, 0x44, 0x58, 0xB9, 0x51, 0xDB, 0x9A, 0x8A, 0x04, 0xB2, 0xDC, 0x58, 0xCA, 0x65, 0xBF, 0x8B, 0xA9, 0x98, 0xA8, 0xDD, 0x52, 0x26, 0xF4, 0x87, 0x03, 0xBA, 0x80, 0x8A, 0x77, 0x81, 0x68, 0x84, 0x3E, 0x2B, 0x3C, 0x3B, 0x9B, 0x4C, 0x47, 0xF8, 0x2F, 0x40, 0x19, 0xA7, 0xC8, 0x89, 0xFD, 0x48, 0x19, 0x13, 0x27, 0x40, 0x14, 0x30, 0x7B, 0xA5, 0x0C, 0x49, 0x62, 0x01, 0xBB, 0x88, 0xCF, 0x8B, 0x1E, 0xFF, 0x5A, 0x82, 0xDA, 0x1B, 0xBC, 0x94, 0x77, 0x09, 0x3A, 0x4B, 0x5E, 0xDF, 0x27, 0x6A, 0x0E, 0x37, 0xF7, 0x8D, 0xBE, 0x04, 0xB6, 0x17, 0xED, 0x96, 0x03, 0x9F, 0x4F, 0xE9, 0xE2, 0xA4, 0xFB, 0xA7, 0xFB, 0xB4, 0x18, 0x36, 0xD5, 0x45, 0xC6, 0x1C, 0xE6, 0x1D, 0x6B, 0x7B, 0x22, 0x93, 0xF3, 0x79, 0xDF, 0x9E, 0xF3, 0xE6, 0xEF, 0xC4, 0xB1, 0x08, 0x4D, 0x00, 0x2F, 0x36, 0x80, 0x2C, 0x88, 0xD9, 0xAA, 0x7A, 0xFC, 0x9E, 0x16, 0x4D, 0xE5, 0xCF, 0x92, 0x2C, 0x19, 0xC3, 0xE2, 0x48, 0x28, 0x07, 0xB2, 0x27, 0xF6, 0x80, 0x17, 0x11, 0xEF, 0x51, 0x2C, 0x82, 0x6B, 0xB1, 0xB5, 0x80, 0x59, 0x0E, 0xAF, 0xC4, 0x51, 0x07, 0x10, 0x06, 0xC8, 0xC8, 0x16, 0x3C, 0x73, 0x35, 0xCF, 0xFC, 0x8B, 0x5A, 0xFC, 0x8C, 0xE3, 0xD7, 0x4A, 0xB4, 0x32, 0x58, 0x0D, 0xBB, 0x7B, 0xE8, 0x91, 0x5B, 0x1D, 0x8D, 0xC7, 0x25, 0x0A, 0xCB, 0x10, 0xA7, 0xFD, 0xCB, 0x56, 0xD6, 0x4A, 0x7D, 0x3B, 0x80, 0xCE, 0xB2, 0xEF, 0xFE, 0x61, 0xAC, 0xFC, 0x3F, 0xCB, 0x92, 0x02, 0xA4, 0xE7, 0x5F, 0x24, 0x46, 0x34, 0x9C, 0xE0, 0xDD, 0x8D, 0x78, 0x84, 0x8B, 0xFB, 0xF1, 0xB3, 0x4B, 0xC4, 0xF7, 0xD5, 0x2C, 0x17, 0xE5, 0x1D, 0xBF, 0xF5, 0x71, 0x7F, 0xEA, 0x9C, 0x6D, 0x51, 0x60, 0x3B, 0xD1, 0x80, 0x04, 0xE0, 0x0C, 0x82, 0x08, 0x10, 0x84, 0x2F, 0x40, 0xF4, 0x2D, 0xFA, 0xB0, 0x06, 0xE6, 0xA3, 0xDC, 0xB1, 0x96, 0xBF, 0x6D, 0x16, 0x5B, 0xCE, 0x06, 0x1E, 0x98, 0xEF, 0xFA, 0x7E, 0x12, 0x72, 0xF7, 0x36, 0x2E, 0x16, 0xBB, 0xB9, 0x5D, 0xF1, 0x2E, 0x41, 0xAD, 0x3E, 0x4B, 0xD0, 0xD3, 0x07, 0x72, 0x5F, 0x25, 0xBE, 0xCF, 0x51, 0x13, 0x91, 0x80, 0x2D, 0xC0, 0xFD, 0xD1, 0x91, 0xF4, 0x94, 0xBC, 0x27, 0x61, 0x1C, 0x72, 0x53, 0xC2, 0xE7, 0xF2, 0x37, 0x7E, 0xE3, 0x7C, 0x26, 0xB7, 0x01, 0x5E, 0x54, 0xA2, 0x3E, 0x82, 0xED, 0x4A, 0x60, 0x1B, 0x20, 0x02, 0xC4, 0x0C, 0xF8, 0x02, 0x2A, 0x81, 0x54, 0xC0, 0x3E, 0x8D, 0x5D, 0x5D, 0x80, 0xDC, 0xF7, 0x14, 0x44, 0xAD, 0xA6, 0x95, 0x03, 0xD2, 0x8C, 0x16, 0xBC, 0x28, 0x98, 0xA6, 0xA6, 0xE2, 0xC9, 0x32, 0xA9, 0x8D, 0xB9, 0xBE, 0x25, 0x1D, 0x66, 0x83, 0xAE, 0x30, 0xDF, 0x54, 0xDC, 0x7D, 0xFD, 0xCD, 0xF7, 0x3E, 0x5A, 0xE0, 0x34, 0x9F, 0x53, 0xFB, 0x74, 0xE4, 0x2A, 0xC0, 0x8C, 0xE0, 0x62, 0x65, 0x96, 0x58, 0x3A, 0x55, 0x23, 0x4D, 0xEC, 0x99, 0x21, 0xDD, 0x27, 0xA3, 0x1F, 0xA3, 0x0A, 0xEB, 0xB7, 0xAD, 0xA2, 0x28, 0x5F, 0xAC, 0xD7, 0x3D, 0xE7, 0xB4, 0xFE, 0x72, 0x40, 0x0A, 0xB0, 0x05, 0x8C, 0x04, 0x19, 0x63, 0xA5, 0xC2, 0xA3, 0x16, 0x20, 0x14, 0xD8, 0xFA, 0xEA, 0x92, 0x1D, 0x73, 0xCA, 0x44, 0xAD, 0x7F, 0x77, 0x32, 0x17, 0x41, 0x7E, 0x51, 0x35, 0x26, 0xBC, 0xD3, 0x50, 0x64, 0x36, 0xE6, 0x34, 0xB0, 0x18, 0x6B, 0xF9, 0x1D, 0x95, 0xD7, 0xA7, 0xEE, 0xF8, 0xDB, 0xC0, 0xAC, 0xAF, 0x2D, 0xDD, 0xFD, 0x53, 0x95, 0x44, 0x01, 0xAE, 0xC0, 0x6A, 0x60, 0xCF, 0xE8, 0xAA, 0xDB, 0xDF, 0x8E, 0x19, 0x3E, 0xB7, 0x4B, 0x9E, 0x9F, 0x87, 0x3E, 0xDF, 0x50, 0xCC, 0x43, 0xDD, 0x6F, 0xC3, 0xC9, 0x90, 0x5B, 0x52, 0x24, 0xA7, 0xA7, 0xA0, 0x6C, 0x60, 0x42, 0x19, 0x0B, 0x98, 0x85, 0xA9, 0xD8, 0xE4, 0xF0, 0x4E, 0xF0, 0x00, 0x0B, 0x60, 0xF5, 0xAC, 0x64, 0xDF, 0xA0, 0xCF, 0x5F, 0x3F, 0x2D, 0x45, 0x1A, 0x8D, 0x3B, 0x56, 0x1B, 0x92, 0xB3, 0x2A, 0x59, 0xFD, 0x6E, 0xBF, 0xCB, 0x5D, 0x29, 0xF1, 0xEF, 0x54, 0x86, 0x2B, 0xB8, 0x69, 0x22, 0x7F, 0x4D, 0x2C, 0xF1, 0x5F, 0xBF, 0xB5, 0xA0, 0x59, 0x8C, 0xDA, 0x2C, 0x77, 0x4F, 0xFB, 0x36, 0x01, 0x6C, 0x03, 0xEB, 0x64, 0x97, 0x02, 0x26, 0x6F, 0x75, 0x58, 0xEA, 0x64, 0x50, 0x01, 0x33, 0xF7, 0xDC, 0xC5, 0xF7, 0x31, 0x24, 0x65, 0xCF, 0x2E, 0xDE, 0x1E, 0xB9, 0x43, 0x5E, 0x69, 0x22, 0x1C, 0xC8, 0x45, 0x24, 0x30, 0xA7, 0x4C, 0x09, 0xA0, 0xAE, 0xB9, 0x31, 0x18, 0x60, 0x0D, 0x68, 0xCD, 0x8B, 0x8F, 0xB7, 0xBC, 0x6C, 0xE0, 0x64, 0xFD, 0xEA, 0x9E, 0xA8, 0xC1, 0x18, 0xA6, 0x6A, 0xA3, 0x45, 0x8C, 0x6C, 0x64, 0x2B, 0xA1, 0xD1, 0x43, 0xAF, 0x4C, 0x84, 0x60, 0x39, 0x93, 0xDC, 0x95, 0xAB, 0xDC, 0x78, 0x56, 0xEE, 0xB9, 0x9F, 0x2B, 0x14, 0x03, 0x81, 0x23, 0x41, 0x39, 0x9E, 0xF7, 0x0C, 0x24, 0x20, 0x12, 0x18, 0xC5, 0xC1, 0x5E, 0xFB, 0xE7, 0x93, 0xD4, 0x60, 0xD3, 0x68, 0xD3, 0x81, 0xC5, 0xE9, 0xA6, 0x9F, 0x51, 0xC9, 0x81, 0x74, 0xF6, 0xB4, 0x1F, 0xF7, 0xFC, 0x5D, 0x7C, 0x51, 0xE6, 0xB2, 0xFD, 0xB4, 0xB9, 0x4B, 0x05, 0xCA, 0x81, 0xE6, 0xB2, 0x7C, 0x6E, 0x99, 0xBB, 0x80, 0x70, 0xC0, 0xE3, 0x55, 0x03, 0x32, 0x00, 0x5B, 0x80, 0x37, 0x4F, 0x39, 0x63, 0x4D, 0x7E, 0xFB, 0x51, 0xFB, 0x98, 0xCF, 0xD6, 0x6F, 0xCD, 0x1C, 0x19, 0x74, 0x05, 0x73, 0x74, 0xEC, 0x0B, 0xC1, 0x20, 0xCB, 0x82, 0xA6, 0x35, 0x9D, 0x8D, 0xBF, 0x51, 0x93, 0x9B, 0x9D, 0xC3, 0xBC, 0x0B, 0x06, 0x4F, 0x80, 0xD6, 0x57, 0x4E, 0x28, 0x01, 0xBC, 0x80, 0x9C, 0xCB, 0x61, 0x7D, 0x1D, 0x98, 0x08, 0x9D, 0x3A, 0xE0, 0x3B, 0x54, 0x15, 0x2F, 0xF2, 0x4B, 0xBF, 0xE6, 0x85, 0xEA, 0x6F, 0x9B, 0x59, 0x29, 0x40, 0x1D, 0x30, 0xC2, 0x37, 0x10, 0x27, 0x53, 0x7C, 0x03, 0x69, 0x93, 0x9D, 0x0D, 0xAC, 0xE2, 0x8B, 0x09, 0x48, 0xE3, 0x4A, 0x1B, 0x59, 0xFE, 0x64, 0xBE, 0xE6, 0x44, 0x4D, 0xB1, 0x78, 0xD9, 0xCE, 0xD4, 0x32, 0x67, 0xD2, 0xD3, 0x3C, 0x43, 0xA7, 0xCB, 0x9E, 0xC1, 0xFE, 0x41, 0x0A, 0x37, 0x1B, 0x41, 0x89, 0xC1, 0xE6, 0x82, 0x2A, 0x3E, 0xDD, 0x66, 0xB7, 0x1D, 0xD7, 0x2B, 0x2A, 0x0E, 0xE3, 0x48, 0xC3, 0xFA, 0x1E, 0x71, 0x60, 0xF5, 0x54, 0x38, 0xF0, 0x88, 0x35, 0xC2, 0x36, 0x95, 0x72, 0x4C, 0xCE, 0xCE, 0x7D, 0x93, 0xB3, 0xE7, 0x7D, 0x7E, 0x7E, 0x4B, 0xDB, 0x95, 0x2C, 0xED, 0x6F, 0x4D, 0xFA, 0xAC, 0xB2, 0x7E, 0x17, 0x3D, 0x90, 0xE3, 0x95, 0xB2, 0x81, 0xAD, 0x80, 0x12, 0x23, 0x89, 0x24, 0xF5, 0x0E, 0xDD, 0x80, 0xC8, 0x48, 0x1B, 0x80, 0xE6, 0xEB, 0x96, 0xB5, 0xE7, 0x4C, 0x9F, 0xA0, 0x19, 0x24, 0x18, 0xE6, 0x12, 0x45, 0x39, 0xB3, 0x02, 0x46, 0xC5, 0x1D, 0xB7, 0xB4, 0xC2, 0x5E, 0x9C, 0x15, 0x04, 0x24, 0xD7, 0x11, 0x38, 0x26, 0x93, 0xF9, 0x7A, 0x7B, 0x6F, 0x5F, 0x23, 0xBB, 0x22, 0x12, 0x3A, 0x3D, 0xCD, 0x04, 0x48, 0x9D, 0xA3, 0x37, 0x5B, 0x53, 0xF8, 0x62, 0xE8, 0x38, 0xA0, 0x20, 0x66, 0x53, 0x36, 0x67, 0xEB, 0x66, 0xC3, 0xB2, 0xF8, 0xE6, 0xEC, 0xE8, 0xF9, 0x29, 0x72, 0x0D, 0x03, 0xB4, 0xC7, 0xA4, 0xED, 0x8D, 0xD9, 0x68, 0x2E, 0xD2, 0x80, 0x19, 0x10, 0xFE, 0x86, 0x60, 0x2F, 0x20, 0x14, 0x70, 0x62, 0x33, 0x9E, 0x41, 0xA8, 0x00, 0x6E, 0x3C, 0x33, 0x26, 0x66, 0x8E, 0x96, 0x53, 0x25, 0xFC, 0xE2, 0x1C, 0x4E, 0xD1, 0xA2, 0xCF, 0x40, 0x5B, 0xA5, 0x7F, 0x4D, 0x8A, 0x85, 0xF7, 0x01, 0xDC, 0x28, 0xDF, 0xA2, 0x46, 0xBD, 0xFB, 0xDA, 0xBB, 0x4E, 0xA6, 0x7F, 0x4E, 0xCD, 0xB4, 0x02, 0x69, 0x80, 0x6E, 0x8E, 0x14, 0x23, 0xA6, 0xCC, 0x66, 0x21, 0xCA, 0x15, 0x5C, 0xA4, 0x1B, 0x30, 0xD1, 0x1A, 0x19, 0x20, 0xFB, 0x7E, 0x5C, 0x88, 0xB7, 0xF8, 0x67, 0x14, 0x50, 0x3E, 0x70, 0x77, 0xBF, 0x23, 0x6C, 0x3E, 0xB5, 0x38, 0xE0, 0x1B, 0xC8, 0x9C, 0xE2, 0x34, 0xEA, 0x55, 0x05, 0x94, 0x00, 0xA9, 0x80, 0x8D, 0x7A, 0x95, 0x80, 0x0B, 0x90, 0xCE, 0x33, 0x7B, 0x82, 0x16, 0x4C, 0x8A, 0xE6, 0x1C, 0x5A, 0x1C, 0x19, 0x52, 0x1E, 0x48, 0xB4, 0xE6, 0x43, 0x55, 0xA5, 0x90, 0xD3, 0xBA, 0x15, 0x3A, 0x4E, 0xCB, 0xD3, 0xC6, 0x6C, 0x03, 0xD3, 0xFB, 0x9F, 0xBB, 0x39, 0xEB, 0x28, 0x8D, 0x9B, 0x26, 0xC1, 0x19, 0xD0, 0x30, 0x4A, 0x00, 0x0D, 0xBC, 0x18, 0x06, 0xD8, 0xD8, 0xDB, 0xD8, 0x5B, 0x52, 0x17, 0x0E, 0xA8, 0xF0, 0xC5, 0x8D, 0xF7, 0x19, 0x8B, 0x49, 0x78, 0xC5, 0x22, 0x4A, 0x9A, 0x1C, 0xBC, 0x88, 0x3C, 0x60, 0x40, 0x34, 0xE0, 0x49, 0x14, 0xD1, 0xF7, 0x14, 0x6A, 0x92, 0x28, 0x86, 0x05, 0xAC, 0x01, 0x25, 0x16, 0x7F, 0xB5, 0x37, 0x20, 0xCF, 0xD7, 0x08, 0x91, 0x8E, 0x31, 0x4B, 0x2A, 0x61, 0xFE, 0x14, 0x97, 0xB9, 0xEF, 0xC7, 0xA8, 0xBA, 0x2A, 0x60, 0xBD, 0xAD, 0x46, 0x53, 0xE2, 0x9C, 0x0E, 0x57, 0xD7, 0xA8, 0x5A, 0xCE, 0x6E, 0xDC, 0xE6, 0x3F, 0x41, 0x81, 0x73, 0xDA, 0xD0, 0x6D, 0x45, 0x39, 0xA1, 0x6D, 0x60, 0x37, 0x5E, 0xCC, 0x02, 0x10, 0x25, 0x3A, 0x1A, 0x26, 0x55, 0xB2, 0xE4, 0x33, 0x37, 0xE9, 0x8E, 0x96, 0x0A, 0x04, 0x6F, 0x8B, 0xC1, 0xE4, 0xE9, 0x71, 0xE7, 0xF6, 0xE6, 0x37, 0x8D, 0x7B, 0xD0, 0x0F, 0x4A, 0xC5, 0x37, 0x0B, 0xB0, 0x24, 0x82, 0x68, 0x20, 0xF7, 0xFC, 0x67, 0x6C, 0xB3, 0x27, 0x80, 0x05, 0xA1, 0x80, 0x08, 0x4E, 0xE9, 0x06, 0x4A, 0x78, 0x26, 0x9C, 0xC2, 0x01, 0xC4, 0x0C, 0x15, 0xC7, 0x9A, 0x78, 0x50, 0xE4, 0x76, 0x56, 0xB4, 0xC9, 0xC4, 0x0C, 0x0B, 0x85, 0x74, 0xE8, 0xD4, 0xD1, 0xD0, 0x9B, 0x63, 0xFF, 0x46, 0x56, 0xBC, 0x4E, 0x44, 0xA5, 0x7C, 0xF0, 0x37, 0xEF, 0xFE, 0xE3, 0xFE, 0xBF, 0xF7, 0x7B, 0x4F, 0x57, 0x79, 0x0B, 0x55, 0x77, 0x02, 0xEB, 0x07, 0xFF, 0x33, 0x36, 0x0F, 0x8E, 0x2C, 0xE5, 0xC7, 0xFC, 0x41, 0x10, 0x41, 0xFB, 0xB3, 0x19, 0xD2, 0x29, 0x9F, 0x98, 0xEF, 0x5D, 0x00, 0xDD, 0x8B, 0xB7, 0x94, 0xB7, 0x1F, 0x63, 0x35, 0x55, 0xF2, 0x02, 0xCC, 0x80, 0xA0, 0x0E, 0x2F, 0x3E, 0x77, 0x4E, 0xC0, 0x8B, 0x10, 0x40, 0x1C, 0xA7, 0x54, 0x00, 0x4E, 0x24, 0x4F, 0xE9, 0x33, 0xCE, 0xFA, 0xB7, 0x01, 0x2A, 0x5D, 0x3F, 0x55, 0x2D, 0x54, 0x7E, 0x35, 0x7A, 0xAA, 0x01, 0xDF, 0xDC, 0xEE, 0xDF, 0xAA, 0x55, 0x3A, 0x51, 0x6D, 0xC1, 0xA5, 0xFB, 0x52, 0x7D, 0x9A, 0x98, 0x79, 0xBC, 0x6B, 0xF6, 0xB3, 0xFE, 0x73, 0xBF, 0xD9, 0xB8, 0x75, 0x16, 0x7E, 0x25, 0xC0, 0xB1, 0xAC, 0x25, 0x72, 0xF1, 0xC5, 0x6B, 0x8A, 0x43, 0x2B, 0x14, 0x60, 0x8F, 0xFD, 0xF4, 0xDB, 0xFA, 0xC7, 0x47, 0x8D, 0x9B, 0xC4, 0x97, 0x47, 0x08, 0x43, 0xBD, 0x18, 0x33, 0xA8, 0x81, 0x20, 0x6A, 0x11, 0x0E, 0xB4, 0xBC, 0x5B, 0xA5, 0xED, 0xA3, 0xA0, 0x02, 0xE2, 0xF3, 0xE2, 0xBB, 0x82, 0xDF, 0x09, 0xA8, 0x9F, 0x53, 0x10, 0x35, 0x6C, 0xF3, 0xFD, 0x9E, 0xCA, 0x30, 0x04, 0xF8, 0xE5, 0x61, 0xE5, 0xEF, 0x49, 0xF1, 0xF4, 0xB4, 0x0C, 0x53, 0x43, 0xFB, 0x2F, 0xC1, 0xBF, 0x14, 0x78, 0x44, 0x18, 0xA3, 0x46, 0xDE, 0x35, 0xFB, 0xFC, 0xE1, 0xC5, 0x38, 0x6D, 0x07, 0x44, 0x5F, 0xB7, 0x21, 0x9B, 0x7F, 0xBF, 0x80, 0x9C, 0x17, 0xEB, 0x35, 0x82, 0x0D, 0x79, 0xFB, 0x4B, 0xCD, 0x06, 0x7E, 0x4D, 0x64, 0x26, 0x99, 0x7D, 0x03, 0x6A, 0xC0, 0xD8, 0xC2, 0xCA, 0x77, 0x6B, 0x58, 0x3E, 0x2B, 0xF8, 0x29, 0x49, 0xB3, 0x37, 0x91, 0x4A, 0x0C, 0x48, 0x22, 0x04, 0x38, 0x59, 0xA6, 0xF6, 0x46, 0xD4, 0xFD, 0x6E, 0x20, 0x21, 0x6A, 0xFB, 0xBF, 0xFE, 0x9D, 0x6A, 0xBF, 0xDD, 0xE3, 0x5A, 0x79, 0x94, 0x49, 0x44, 0xB2, 0x70, 0xFB, 0x12, 0x34, 0x63, 0x0C, 0x76, 0x2A, 0xC8, 0xEE, 0x19, 0x63, 0x6F, 0xD4, 0xA6, 0xFF, 0x9D, 0x7F, 0x72, 0x05, 0x32, 0x81, 0x20, 0x4C, 0x00, 0xD9, 0xC0, 0x1A, 0x18, 0x90, 0x3E, 0xEA, 0xCD, 0x1B, 0xD8, 0x94, 0x37, 0x71, 0xDD, 0x3E, 0x5D, 0x03, 0x65, 0xBF, 0x4D, 0xCC, 0x84, 0x18, 0xD1, 0x73, 0x3B, 0xA1, 0x84, 0x7C, 0x8E, 0x12, 0x70, 0x79, 0xD5, 0xE4, 0xD8, 0x9F, 0x14, 0x85, 0x7C, 0xD3, 0x61, 0xB4, 0x01, 0x4F, 0x9E, 0xD2, 0x27, 0x6A, 0xF2, 0x5F, 0x09, 0x46, 0x57, 0x28, 0x9E, 0x90, 0x99, 0xB0, 0xD8, 0x5F, 0xD7, 0xCC, 0x52, 0x11, 0x7B, 0xA9, 0x80, 0x95, 0xC9, 0xAE, 0x47, 0x1F, 0x0A, 0x99, 0xB1, 0xF6, 0x83, 0xDE, 0x8E, 0xED, 0xAF, 0x0B, 0x75, 0x38, 0xA0, 0xFD, 0x26, 0xC7, 0xE4, 0xBA, 0xC8, 0x59, 0xEB, 0xAF, 0x3F, 0xA3, 0x4D, 0x42, 0x66, 0x6A, 0x3E, 0xFB, 0xE3, 0x33, 0x66, 0x10, 0x51, 0x7D, 0x14, 0x46, 0x3F, 0xD9, 0x6B, 0x7A, 0x94, 0x5F, 0x20, 0x89, 0x9E, 0x34, 0x53, 0x05, 0xB6, 0x03, 0xC7, 0xF7, 0x41, 0x81, 0x12, 0x20, 0x12, 0xD0, 0x8F, 0x66, 0x6A, 0x01, 0x44, 0xF3, 0x14, 0x3F, 0x51, 0x53, 0x24, 0x25, 0xB4, 0xFC, 0x1E, 0xFE, 0xBD, 0x37, 0xDB, 0x95, 0x42, 0x1F, 0x72, 0x6D, 0x3E, 0x15, 0xEB, 0x87, 0xD2, 0xD1, 0x0F, 0xF4, 0x55, 0x3A, 0xF6, 0xC7, 0xA8, 0x7A, 0xCF, 0x5A, 0xED, 0xF4, 0x04, 0xCF, 0x29, 0x3E, 0x01, 0xF6, 0xB3, 0x82, 0xF7, 0x93, 0x08, 0x16, 0x5F, 0xC1, 0x43, 0xEF, 0x26, 0xD2, 0x35, 0xF2, 0x48, 0xFE, 0x61, 0x1F, 0x11, 0x05, 0xFF, 0xFE, 0x73, 0x6D, 0x41, 0x56, 0x9A, 0xF5, 0x10, 0x83, 0x3E, 0x35, 0x8E, 0x02, 0x4C, 0x6A, 0xC3, 0x36, 0x40, 0x17, 0x90, 0x3E, 0xF9, 0xAC, 0x40, 0x3B, 0x50, 0x06, 0x78, 0x02, 0x2B, 0xDF, 0x3D, 0xFB, 0xCA, 0x39, 0x65, 0xA2, 0x66, 0xBF, 0xC7, 0xAA, 0xAF, 0x40, 0x7D, 0xE8, 0x6E, 0xA6, 0x0D, 0xDF, 0x02, 0x3D, 0x18, 0xE2, 0xE2, 0x33, 0xAC, 0xCD, 0xBA, 0x9D, 0xCD, 0x79, 0xED, 0x57, 0x55, 0x9B, 0xBB, 0xD5, 0xE4, 0x16, 0xE7, 0xB3, 0xDB, 0xCE, 0xBC, 0x77, 0xD9, 0x67, 0xBB, 0x7C, 0x92, 0x13, 0x66, 0x87, 0x32, 0x9D, 0x47, 0x8B, 0xA7, 0xD8, 0xDD, 0x90, 0xE7, 0xAA, 0xF5, 0x6C, 0x4D, 0x26, 0xD7, 0xD0, 0x7E, 0x16, 0xA1, 0x5B, 0xDE, 0x25, 0xF8, 0x88, 0x64, 0x3A, 0xDF, 0xD2, 0xFC, 0xEA, 0x7C, 0xCD, 0x59, 0x53, 0x81, 0xA6, 0x1C, 0xE0, 0xCC, 0xDD, 0xB7, 0x05, 0xB4, 0x00, 0xD9, 0x80, 0x6D, 0x9C, 0x52, 0x05, 0xD8, 0x02, 0x4E, 0x5A, 0x6B, 0x4F, 0xD4, 0x1C, 0x5D, 0x7E, 0xBD, 0x10, 0xB5, 0x66, 0xB3, 0x95, 0xD6, 0x67, 0xE6, 0xB6, 0x46, 0xCE, 0xCA, 0xE6, 0xFF, 0x79, 0xA3, 0x85, 0xB9, 0xE8, 0xBB, 0x66, 0xAF, 0x51, 0xD5, 0x4E, 0x46, 0xE1, 0x0C, 0x96, 0x91, 0xF3, 0x12, 0xB0, 0x9C, 0x1A, 0x21, 0x20, 0xE7, 0x8B, 0xF5, 0xA9, 0x43, 0x7B, 0x3F, 0xCC, 0xC8, 0x1F, 0x3E, 0x36, 0x73, 0x7D, 0x3D, 0x4E, 0x36, 0x63, 0x3F, 0xCA, 0xCE, 0x3E, 0xC3, 0x51, 0x47, 0xAE, 0xEC, 0x31, 0x8A, 0x05, 0x22, 0x80, 0x3A, 0x3E, 0x3F, 0x40, 0xCC, 0xAF, 0x76, 0x2A, 0x50, 0xB3, 0xDF, 0xDD, 0x40, 0x08, 0xB0, 0x8A, 0x67, 0x3A, 0x50, 0xC1, 0x53, 0x6A, 0xA2, 0x16, 0xF0, 0x90, 0xEF, 0xB1, 0x11, 0x16, 0x78, 0xBB, 0x4A, 0x21, 0x81, 0x2A, 0xF6, 0x6F, 0x3A, 0x30, 0xFF, 0xE0, 0xD6, 0x4D, 0x2D, 0xDB, 0x8F, 0x05, 0xD1, 0x8F, 0x3A, 0x51, 0xEB, 0xBB, 0x91, 0x87, 0xBF, 0x4B, 0x89, 0x70, 0x3E, 0x13, 0x8F, 0xEA, 0xBA, 0x33, 0xF5, 0xDF, 0x42, 0xA2, 0xE7, 0x4C, 0x9F, 0xFE, 0x37, 0xD7, 0x0A, 0xD7, 0x4E, 0xD5, 0x4A, 0xF2, 0x7D, 0x4D, 0xDD, 0xFB, 0x53, 0xFE, 0x1E, 0x3A, 0xD2, 0xFC, 0xFD, 0xB3, 0x7D, 0x6F, 0x92, 0x05, 0x24, 0x8F, 0xCA, 0x81, 0xEE, 0x2B, 0x96, 0xCA, 0xB9, 0xA4, 0xA3, 0x00, 0x0F, 0x40, 0x26, 0x3F, 0x84, 0xD0, 0x02, 0x62, 0xCD, 0x29, 0x13, 0xB5, 0x84, 0x81, 0x53, 0x2A, 0x4C, 0x3E, 0xC5, 0xB0, 0x5E, 0x5A, 0x82, 0x14, 0x47, 0x73, 0xEE, 0xE8, 0x3B, 0x6D, 0x5B, 0xF8, 0x4D, 0x44, 0x8D, 0x35, 0xE9, 0x5B, 0x41, 0x3B, 0x93, 0x1B, 0x1F, 0xAF, 0x30, 0x5E, 0x99, 0xEA, 0xCC, 0x7C, 0x19, 0x3C, 0xDE, 0x1C, 0x72, 0x92, 0x0D, 0x5A, 0xAF, 0x21, 0x74, 0x9C, 0x36, 0x48, 0x26, 0xC0, 0x1A, 0x83, 0x6E, 0x9E, 0xA2, 0xF7, 0x82, 0xB9, 0xDE, 0xD6, 0x5B, 0x80, 0xB9, 0x32, 0x7B, 0xC4, 0x73, 0x9B, 0xAA, 0x34, 0xC0, 0x1D, 0x48, 0x05, 0x7A, 0xAE, 0xCC, 0xE9, 0xFA, 0x4E, 0x44, 0x01, 0x9E, 0x80, 0xE4, 0xDB, 0xC4, 0xCF, 0x14, 0x88, 0x39, 0x73, 0x4F, 0xD0, 0xEA, 0xB7, 0x56, 0x49, 0x51, 0xA8, 0x69, 0x5C, 0x37, 0x2D, 0x7B, 0x0A, 0xF4, 0x32, 0xAD, 0x80, 0xD5, 0xDC, 0x21, 0x99, 0xC9, 0x2D, 0xD9, 0x6F, 0x79, 0xC1, 0x74, 0x99, 0x9D, 0xD5, 0x3B, 0x42, 0xFB, 0x68, 0x82, 0x2B, 0x5F, 0xDB, 0x64, 0xBD, 0xDD, 0x33, 0xF6, 0xE2, 0xA7, 0x17, 0x62, 0x1C, 0x39, 0x75, 0xBA, 0x2D, 0x20, 0x94, 0xFD, 0xD7, 0x97, 0x73, 0x4F, 0x3D, 0x0E, 0xB0, 0x1C, 0xE8, 0x59, 0x98, 0x9C, 0x31, 0xDD, 0x6F, 0x97, 0x06, 0x25, 0xBC, 0x81, 0x9C, 0x27, 0xCB, 0xE9, 0xD7, 0x07, 0xC4, 0x06, 0x7C, 0x01, 0xDB, 0x5E, 0x9D, 0x5C, 0x08, 0x93, 0xC9, 0x7A, 0x9E, 0xA8, 0xC1, 0xAE, 0x35, 0xB2, 0xF0, 0xF5, 0x54, 0x32, 0x49, 0x6A, 0x16, 0xA4, 0x34, 0x11, 0x32, 0x14, 0x74, 0xFB, 0x4A, 0x76, 0xC5, 0xDA, 0x5C, 0x40, 0x71, 0x6E, 0x0B, 0xA4, 0xDF, 0x1D, 0x28, 0x09, 0xEA, 0x43, 0x71, 0x1C, 0xF3, 0x32, 0x81, 0x26, 0xF6, 0x9A, 0xFC, 0xA2, 0xB7, 0x33, 0x9B, 0xB0, 0x4A, 0x6A, 0x07, 0xC5, 0x34, 0x2E, 0x76, 0x74, 0xF1, 0x7D, 0xD3, 0x49, 0x6C, 0x6A, 0x5D, 0x1E, 0x99, 0x08, 0x21, 0xFC, 0x61, 0xAA, 0xB3, 0x43, 0x71, 0x8A, 0xD3, 0x79, 0x2E, 0x75, 0xB2, 0x69, 0x80, 0x4C, 0x16, 0xB1, 0xC5, 0xEB, 0x07, 0xE0, 0xD3, 0x1F, 0xA0, 0x88, 0xFD, 0x6A, 0x00, 0xD2, 0x38, 0xB3, 0x79, 0xB4, 0x79, 0x8A, 0x0A, 0x63, 0xB6, 0xB9, 0xA6, 0x4B, 0x81, 0x20, 0x28, 0x93, 0xFC, 0xA3, 0x8F, 0x7F, 0x93, 0x8A, 0xFD, 0x00, 0xED, 0x6F, 0x7C, 0x10, 0x71, 0xFF, 0x40, 0x6E, 0x02, 0x10, 0x79, 0x0B, 0x67, 0x44, 0x8F, 0x7D, 0xD3, 0xA2, 0x82, 0xB8, 0x29, 0xF3, 0x78, 0xE3, 0x45, 0x99, 0x8C, 0xA9, 0x1A, 0x51, 0x04, 0x28, 0x7E, 0x39, 0xB9, 0x71, 0xE6, 0xD8, 0xED, 0xB9, 0x33, 0x12, 0xFC, 0x27, 0x8A, 0x2E, 0x60, 0x3B, 0x78, 0x99, 0xCC, 0x23, 0x23, 0x71, 0x04, 0x01, 0xCA, 0x79, 0x95, 0xD5, 0x79, 0x9F, 0xAD, 0x6B, 0x4D, 0x80, 0x51, 0xC7, 0x92, 0x74, 0x60, 0x2C, 0x93, 0x62, 0x84, 0xBD, 0x05, 0xEC, 0xC5, 0x58, 0x3B, 0x70, 0x7C, 0x76, 0x05, 0x47, 0x2B, 0x79, 0x4A, 0x4F, 0xCC, 0xB0, 0x35, 0xE0, 0x62, 0x88, 0xA7, 0x28, 0xD7, 0xB3, 0xFD, 0xB8, 0xAB, 0x89, 0x6E, 0xA8, 0x8B, 0xE5, 0xCC, 0x19, 0xC9, 0x5B, 0x5A, 0x50, 0xFE, 0x49, 0x21, 0xD2, 0x3A, 0xD3, 0x14, 0xBE, 0x91, 0xFA, 0x97, 0x29, 0x20, 0x63, 0xA5, 0x70, 0x8A, 0xB9, 0x81, 0x69, 0xF0, 0x30, 0x0A, 0xDB, 0x92, 0x37, 0xD9, 0x68, 0x3B, 0x5E, 0x1C, 0x71, 0xF3, 0x34, 0xF3, 0xEC, 0x8F, 0x6B, 0x7F, 0xE0, 0x28, 0x9E, 0x1B, 0x95, 0x1E, 0xDF, 0x27, 0xE3, 0x77, 0xAC, 0x09, 0x64, 0x20, 0xF4, 0x8B, 0x88, 0x1E, 0x2F, 0x16, 0xFE, 0xA1, 0x04, 0x16, 0x5F, 0xCC, 0x04, 0x46, 0x8B, 0x2B, 0xBE, 0x38, 0x92, 0xB3, 0xD4, 0x04, 0x0D, 0x0A, 0x64, 0x45, 0xF3, 0x26, 0x2F, 0x3F, 0x20, 0x84, 0xBF, 0x4B, 0x54, 0x69, 0x34, 0xC0, 0xB1, 0xD8, 0x79, 0x7A, 0x5C, 0x08, 0x03, 0x7A, 0xB5, 0x8E, 0xBC, 0x39, 0xAC, 0xD2, 0x14, 0x16, 0x20, 0x0F, 0xC2, 0x32, 0xC4, 0x81, 0x3D, 0x72, 0x81, 0xE0, 0x67, 0xA3, 0x3D, 0x58, 0x03, 0x35, 0x3F, 0x53, 0xB6, 0xE3, 0xFF, 0xC1, 0x8F, 0x04, 0xB1, 0x79, 0x25, 0xC4, 0x5C, 0xC6, 0x94, 0xC8, 0xD6, 0xBE, 0xD7, 0x5A, 0x1C, 0x53, 0x89, 0x69, 0x63, 0x18, 0xBC, 0xB6, 0x6D, 0x12, 0x0A, 0x8D, 0x6A, 0xCA, 0x06, 0x34, 0x81, 0xA9, 0xF4, 0x98, 0xCA, 0x77, 0x59, 0xC0, 0x2E, 0xBC, 0x38, 0x3F, 0x8B, 0x00, 0xAC, 0x80, 0x94, 0xA9, 0x91, 0x9F, 0x98, 0x29, 0xDD, 0xEB, 0x0D, 0xE9, 0xEB, 0xBF, 0xCC, 0x98, 0xFD, 0xE4, 0x48, 0x22, 0x8F, 0xCD, 0x36, 0xF4, 0x2F, 0x77, 0x54, 0xCC, 0xEF, 0xBC, 0x0D, 0xF3, 0x18, 0xA5, 0xBF, 0xF6, 0xCF, 0xCD, 0xE8, 0x2E, 0x0A, 0x5F, 0x11, 0xC8, 0x4A, 0xF2, 0x0D, 0x04, 0xBB, 0xB0, 0x49, 0x42, 0x5A, 0x8B, 0xCD, 0x76, 0xFC, 0x8A, 0xA3, 0x65, 0xF8, 0x19, 0x5E, 0xC4, 0xA3, 0x13, 0x60, 0x52, 0xD3, 0x76, 0x9C, 0x92, 0x71, 0x3B, 0xD7, 0xAD, 0xD3, 0x53, 0x6F, 0x15, 0x90, 0x76, 0xDB, 0xFF, 0x63, 0x44, 0xA2, 0x42, 0x7F, 0x03, 0xD5, 0xFC, 0xB3, 0x0B, 0x70, 0xE3, 0xEF, 0xDC, 0x40, 0xB1, 0xCF, 0xDB, 0x4E, 0xC2, 0xF1, 0x62, 0x17, 0x90, 0x41, 0x08, 0xD0, 0x82, 0x53, 0xF2, 0x8C, 0x33, 0x83, 0x56, 0xBC, 0x62, 0x9A, 0xFA, 0xE0, 0xD1, 0xB5, 0x9D, 0x31, 0xE3, 0xF7, 0xE0, 0x58, 0x63, 0x8D, 0x0B, 0x8D, 0x40, 0xD7, 0x55, 0xE7, 0x45, 0xF9, 0xF6, 0x7F, 0xC2, 0x25, 0x3B, 0x6E, 0x4D, 0xDC, 0x41, 0xA5, 0x3C, 0xB8, 0x29, 0xE5, 0x19, 0x8E, 0x84, 0x82, 0xA0, 0xC8, 0xC7, 0x35, 0xDB, 0x70, 0x4A, 0x0B, 0x5B, 0x5B, 0x31, 0x2E, 0xF1, 0xBC, 0x5D, 0xE9, 0x78, 0x80, 0xAF, 0x03, 0xDF, 0x3B, 0xEB, 0x93, 0xBA, 0x6F, 0x3A, 0x6A, 0x70, 0xEC, 0xE2, 0x82, 0x85, 0x3F, 0x98, 0x00, 0xED, 0xF4, 0xFA, 0x2E, 0xC0, 0x8A, 0xE2, 0xDD, 0x02, 0x3A, 0x68, 0x3F, 0x3E, 0x10, 0x60, 0xF3, 0x0F, 0x95, 0x03, 0xA1, 0x40, 0xB3, 0xC2, 0xA7, 0x7D, 0x62, 0xE6, 0x98, 0x2B, 0x45, 0x41, 0xD3, 0x2A, 0xB6, 0x75, 0x58, 0x85, 0x92, 0x91, 0x4A, 0x5C, 0x63, 0x7B, 0xE3, 0x5A, 0xD1, 0xA4, 0x56, 0xBC, 0xA9, 0x2C, 0x70, 0x19, 0xF0, 0xEA, 0x90, 0xB1, 0xC7, 0x06, 0x3E, 0xAF, 0x29, 0x5E, 0x22, 0x74, 0x46, 0xC9, 0xDF, 0xE2, 0x78, 0xFC, 0x84, 0x01, 0x9B, 0x9F, 0x76, 0x6F, 0xFA, 0x42, 0x6C, 0xC4, 0x3A, 0x16, 0x50, 0xEB, 0x0A, 0xDD, 0x89, 0x23, 0x46, 0x89, 0x9B, 0x2E, 0x7C, 0xD2, 0x0A, 0x20, 0xC2, 0x17, 0xE3, 0xF5, 0x65, 0xDA, 0x0A, 0xB8, 0x03, 0xA9, 0x40, 0xC7, 0xDC, 0x2E, 0xF8, 0x67, 0x17, 0x60, 0x41, 0x18, 0x20, 0xD3, 0x66, 0xB3, 0x81, 0x12, 0xA0, 0x79, 0x89, 0x96, 0x4C, 0xCC, 0x82, 0xC5, 0x71, 0xF9, 0x34, 0x7B, 0x4B, 0xDB, 0x3C, 0xC2, 0x45, 0x22, 0xDD, 0xB0, 0xDF, 0x5C, 0x89, 0xC1, 0xBE, 0xF5, 0xD4, 0xD3, 0x63, 0xAD, 0x76, 0x3A, 0x15, 0x9D, 0x7D, 0x56, 0xE3, 0x8A, 0x3C, 0x69, 0x7F, 0x58, 0x5C, 0x46, 0x16, 0x57, 0xE4, 0x65, 0x88, 0x4B, 0x71, 0x51, 0x59, 0xB0, 0x4D, 0x06, 0x16, 0xCE, 0xDC, 0x3F, 0x18, 0x22, 0x58, 0xCC, 0x78, 0xAF, 0x8D, 0x17, 0x93, 0xA9, 0xA9, 0xE9, 0xFC, 0xD5, 0xD0, 0xA0, 0x60, 0x5B, 0x90, 0xC0, 0x32, 0x4A, 0xE2, 0x0E, 0x48, 0x01, 0x7B, 0x11, 0x09, 0x88, 0x00, 0xE6, 0xC0, 0xBC, 0x2F, 0x0C, 0x9D, 0x23, 0xD7, 0x1A, 0xE0, 0xC5, 0x4A, 0x20, 0xD7, 0x8B, 0x6A, 0x9C, 0x92, 0x39, 0x31, 0xCB, 0xFF, 0x9A, 0xDB, 0x87, 0x23, 0xA4, 0x75, 0x63, 0x1F, 0xEF, 0x27, 0xD2, 0xAB, 0xA3, 0xC4, 0x28, 0x7F, 0xF0, 0x8C, 0xDF, 0x00, 0x4B, 0x5F, 0xBF, 0x7B, 0x9D, 0x7F, 0xF3, 0x12, 0xC6, 0xB4, 0xFC, 0x98, 0x3D, 0x24, 0xD1, 0x02, 0x64, 0x7D, 0x2B, 0x8F, 0xDE, 0x2A, 0xD6, 0xF4, 0x8F, 0xAC, 0x76, 0x8B, 0x6E, 0xEE, 0x99, 0x4B, 0xC7, 0x26, 0x10, 0x70, 0x07, 0x6C, 0x13, 0xC1, 0x53, 0xE6, 0xB7, 0xF4, 0xFB, 0xD7, 0x2B, 0x80, 0x36, 0x62, 0xFC, 0x11, 0x14, 0xD0, 0x1A, 0x45, 0x09, 0xB0, 0x06, 0xD4, 0x81, 0x65, 0xD3, 0x7D, 0x0E, 0x10, 0x03, 0x8E, 0x05, 0xD2, 0x5A, 0x13, 0xB5, 0xFA, 0xB5, 0xB7, 0xDF, 0xEA, 0xBF, 0xA4, 0x0E, 0x2B, 0xA8, 0x6B, 0x96, 0x71, 0xF5, 0x34, 0xD3, 0x15, 0xC8, 0x27, 0x8B, 0xFE, 0xA5, 0x80, 0x6D, 0xDF, 0x6F, 0x59, 0xBB, 0x7E, 0xDA, 0xE5, 0x89, 0xBE, 0x59, 0x6A, 0x5E, 0x2F, 0xF6, 0xA8, 0xB5, 0x01, 0xE8, 0x02, 0x56, 0x03, 0x47, 0x28, 0x5D, 0xB7, 0xDA, 0x3C, 0x8F, 0xE4, 0xB6, 0x94, 0x67, 0x7E, 0xBA, 0xDC, 0x7B, 0x03, 0x6A, 0x37, 0x1B, 0x35, 0x88, 0x3C, 0xF9, 0x1B, 0xBE, 0x80, 0x9A, 0x29, 0xF7, 0x02, 0xB6, 0x7D, 0x36, 0xDA, 0xCD, 0x80, 0x26, 0x6A, 0x5E, 0x94, 0xF1, 0xBF, 0xFE, 0xC1, 0x88, 0x38, 0x7D, 0xFB, 0x6B, 0xA2, 0xD6, 0xBF, 0xAB, 0x40, 0x7F, 0xC6, 0xC1, 0x86, 0xEC, 0xA0, 0xFC, 0x89, 0x89, 0x7E, 0xA3, 0xB6, 0x37, 0x56, 0xA1, 0xD2, 0x7B, 0xFF, 0xBE, 0x97, 0x6D, 0x9F, 0x25, 0xD4, 0xFA, 0xEE, 0x13, 0xF0, 0x2D, 0xAA, 0x23, 0x13, 0xBF, 0x98, 0xA4, 0x42, 0xFF, 0xE8, 0xF6, 0x66, 0xC0, 0x49, 0x77, 0xDC, 0xEF, 0x56, 0xC2, 0x54, 0xAA, 0x56, 0x01, 0x2B, 0x18, 0xAE, 0x78, 0xFB, 0x9A, 0xD5, 0x88, 0xC4, 0x13, 0xFB, 0x51, 0x21, 0xBF, 0xD5, 0x3D, 0x44, 0x28, 0x90, 0x53, 0xEB, 0x33, 0x41, 0x58, 0x09, 0x38, 0x61, 0x0E, 0x6C, 0x9C, 0xE2, 0x0E, 0xEC, 0x04, 0xF4, 0x44, 0x94, 0x63, 0x0D, 0xCA, 0xC1, 0x6F, 0xFA, 0xE2, 0xFF, 0x35, 0x1F, 0x78, 0xAF, 0x4F, 0xCC, 0xD8, 0x7C, 0x6C, 0xE8, 0xC8, 0x96, 0xA8, 0x0C, 0x44, 0xF6, 0xAD, 0xD9, 0x44, 0x4D, 0x26, 0x6A, 0x9B, 0x57, 0xE8, 0xA7, 0x5E, 0x7C, 0x2F, 0x60, 0xAD, 0x7F, 0x08, 0xDF, 0x3B, 0x80, 0x55, 0x6F, 0x72, 0x6B, 0x32, 0x86, 0xCE, 0x23, 0xEB, 0xB7, 0x3E, 0xDD, 0xE2, 0x6D, 0x6F, 0x59, 0x0A, 0x4C, 0xCE, 0xF2, 0x88, 0xE2, 0x5A, 0xEF, 0xC5, 0xB8, 0x17, 0x61, 0x44, 0x02, 0xA2, 0x40, 0xC8, 0x7B, 0x4D, 0xD6, 0x06, 0x22, 0x80, 0x49, 0xB8, 0xAB, 0x05, 0x98, 0xBC, 0x22, 0xB1, 0xFB, 0x89, 0xDA, 0xC6, 0xE6, 0xAC, 0x37, 0x26, 0x37, 0xCB, 0x58, 0x29, 0x92, 0x8F, 0x49, 0xF5, 0x92, 0xA2, 0xFB, 0xF6, 0x9E, 0x3E, 0x80, 0x4F, 0x79, 0x59, 0xEC, 0xAF, 0xC9, 0xC9, 0xEB, 0x77, 0xC9, 0x5D, 0xF6, 0x9B, 0x61, 0xA5, 0xEB, 0xED, 0xFA, 0xD0, 0x0D, 0xEC, 0x00, 0x74, 0x4A, 0xCF, 0x26, 0x23, 0x46, 0x78, 0x14, 0x54, 0x71, 0xFC, 0x69, 0x70, 0x5F, 0xF1, 0xAA, 0xE8, 0xE2, 0x57, 0x8F, 0xDE, 0xFB, 0x28, 0x76, 0x35, 0x96, 0xC3, 0xFE, 0xE6, 0xB9, 0x8F, 0x58, 0x26, 0x09, 0xD4, 0x98, 0x60, 0x9E, 0x9E, 0x52, 0xC0, 0xD6, 0xC9, 0x45, 0x01, 0x46, 0xD3, 0x69, 0x1E, 0xAD, 0xE6, 0x29, 0x39, 0x51, 0x13, 0xCC, 0x9C, 0x3C, 0x7E, 0x33, 0x27, 0x69, 0x87, 0xC1, 0xAE, 0x1B, 0x12, 0xD3, 0x4D, 0xD9, 0x77, 0xA0, 0x21, 0xFF, 0xA5, 0xFF, 0x60, 0xE5, 0xAF, 0x35, 0x4C, 0x7F, 0x4C, 0x4E, 0x7C, 0x24, 0x81, 0xF9, 0x4F, 0x23, 0xC7, 0x3C, 0x9A, 0x47, 0xB7, 0x6B, 0xEB, 0x11, 0x9B, 0xED, 0xA8, 0x90, 0x23, 0x13, 0xCF, 0x99, 0x1A, 0x38, 0xB2, 0x1C, 0x2D, 0x93, 0x61, 0xCE, 0x2B, 0x6C, 0xAD, 0x51, 0x3E, 0x42, 0x79, 0x54, 0xA3, 0x71, 0x4F, 0x66, 0x23, 0xC3, 0xA5, 0x8C, 0xD3, 0x26, 0xDC, 0x80, 0x5A, 0x1F, 0xF5, 0x88, 0x08, 0xC2, 0x03, 0x90, 0x7C, 0x83, 0x67, 0x0A, 0xCC, 0x29, 0x47, 0x1A, 0xA2, 0x26, 0x94, 0xDB, 0x7E, 0x63, 0x6D, 0x85, 0x9F, 0x21, 0xF7, 0x9B, 0x52, 0x0A, 0x56, 0x08, 0x7F, 0xED, 0x7C, 0x02, 0x8E, 0x15, 0xD0, 0x75, 0x5B, 0xBF, 0xDE, 0xDE, 0xAA, 0x77, 0x93, 0x87, 0x45, 0x9E, 0x4C, 0x60, 0x02, 0x44, 0xDE, 0x3C, 0xA6, 0xAD, 0x74, 0x84, 0x7A, 0x93, 0xC1, 0xCB, 0xF8, 0x86, 0xD2, 0xB7, 0x65, 0x41, 0xD7, 0x88, 0x98, 0x8F, 0xC5, 0xF7, 0xE8, 0x8E, 0x96, 0xC0, 0x8A, 0x5B, 0x69, 0xBA, 0xF7, 0x8F, 0xDC, 0x19, 0x78, 0xD3, 0x06, 0x77, 0x03, 0x46, 0x24, 0x57, 0xAD, 0x33, 0xE4, 0xB6, 0x01, 0x11, 0x80, 0x0B, 0xB0, 0xF3, 0x1D, 0xA3, 0x73, 0xA4, 0x3C, 0x65, 0x52, 0x87, 0x7E, 0x91, 0x71, 0x47, 0x29, 0xA3, 0xF3, 0x51, 0xEA, 0x06, 0xA1, 0xE8, 0xF7, 0x24, 0xED, 0x62, 0x66, 0x6C, 0x02, 0x16, 0x6C, 0x2A, 0x16, 0xCF, 0x58, 0xCB, 0xB3, 0x0C, 0xAD, 0x8F, 0xE2, 0x9D, 0x6B, 0x74, 0x6C, 0xC0, 0xEB, 0x55, 0x64, 0x27, 0x91, 0xAE, 0x03, 0x48, 0xB9, 0x32, 0x6D, 0x9E, 0xDC, 0xBE, 0x25, 0x53, 0xEE, 0xC8, 0x17, 0xED, 0xE3, 0x42, 0xEF, 0x73, 0x31, 0x02, 0x73, 0xB9, 0xDB, 0xB4, 0xCD, 0x91, 0xAB, 0x4E, 0xF7, 0xD1, 0xFB, 0x25, 0xDF, 0xF1, 0xD4, 0x46, 0xA9, 0x80, 0xA2, 0x82, 0x09, 0xD0, 0x09, 0x54, 0x01, 0x6E, 0xC0, 0xDA, 0x3C, 0xB3, 0x81, 0x9A, 0x33, 0x75, 0xA2, 0xE6, 0xEC, 0xFD, 0xA4, 0xDC, 0x93, 0x12, 0x5C, 0xA1, 0x3D, 0xF7, 0xB5, 0xE9, 0xD7, 0x17, 0x18, 0xDB, 0xAD, 0xB8, 0xC0, 0xF6, 0xE4, 0x8D, 0xBE, 0xA5, 0x8C, 0x76, 0x7B, 0x32, 0xF0, 0x7B, 0xBD, 0x62, 0xC6, 0x2F, 0xFA, 0x38, 0x8A, 0x11, 0x5F, 0x19, 0x91, 0x35, 0xDF, 0x2B, 0xE1, 0xF3, 0x97, 0xD6, 0xDB, 0x56, 0x4C, 0xD6, 0xBD, 0xB1, 0xE4, 0xF9, 0x06, 0x2C, 0x5F, 0x47, 0x74, 0x65, 0xB4, 0x26, 0xE1, 0xF4, 0x74, 0x4F, 0x1B, 0x9B, 0xCF, 0x3D, 0xB6, 0xF5, 0x93, 0x74, 0x06, 0xA4, 0x4E, 0xB6, 0xD9, 0xBF, 0x92, 0x87, 0x16, 0x30, 0x39, 0x6B, 0xD9, 0x73, 0x26, 0xE0, 0xF2, 0xF6, 0x66, 0x6C, 0x09, 0xFC, 0xCC, 0x36, 0xB2, 0xF0, 0xCA, 0xA0, 0x9A, 0x48, 0x63, 0xC6, 0x61, 0x82, 0x6C, 0xBA, 0xC8, 0x1F, 0x62, 0x5C, 0xD1, 0x8A, 0x4D, 0x86, 0xBF, 0xB5, 0x52, 0x79, 0xBC, 0x31, 0x19, 0x2D, 0x8A, 0x5A, 0x5B, 0xE8, 0x78, 0x99, 0xC0, 0x8E, 0x49, 0xED, 0x1B, 0x07, 0x6F, 0x60, 0x07, 0x50, 0x3C, 0x53, 0xF6, 0x58, 0x13, 0x02, 0xD1, 0x7C, 0xFB, 0x94, 0x2B, 0x8E, 0x37, 0xE0, 0xED, 0x4F, 0x72, 0x15, 0xA0, 0xAA, 0x5B, 0x9B, 0xA5, 0x3C, 0x1A, 0xB3, 0xD1, 0x3C, 0xF9, 0x1F, 0x7B, 0x01, 0xD6, 0xF4, 0x8A, 0x2C, 0xA0, 0xC6, 0x5A, 0xB3, 0x08, 0x05, 0xC6, 0x47, 0x32, 0x05, 0xF0, 0x0D, 0xE4, 0xC8, 0x2D, 0x67, 0xA4, 0x25, 0x65, 0xBA, 0xF1, 0xC7, 0xDF, 0x6C, 0x3E, 0x9A, 0x8F, 0xE5, 0x72, 0xAB, 0xF1, 0xF3, 0x35, 0xAB, 0xF2, 0x72, 0xB6, 0x05, 0xDE, 0xD6, 0xA9, 0x72, 0x12, 0x37, 0x38, 0xB6, 0xE2, 0x3A, 0x72, 0xC8, 0xD4, 0x6A, 0x1E, 0x0B, 0xEE, 0xF9, 0x06, 0xB7, 0x52, 0xE2, 0x32, 0x60, 0x7C, 0xA3, 0xA7, 0x76, 0xB6, 0x37, 0x70, 0x7C, 0x27, 0x05, 0xF1, 0x29, 0x63, 0x2A, 0xDA, 0x73, 0x61, 0x6D, 0x86, 0x50, 0x4F, 0x4A, 0xD9, 0x51, 0x3A, 0x15, 0x41, 0x3B, 0x89, 0x54, 0xD3, 0xF6, 0xCB, 0x81, 0xF0, 0xD7, 0x82, 0x5F, 0x1C, 0xC8, 0x81, 0x00, 0x16, 0xC0, 0xF2, 0xD7, 0x7E, 0x7E, 0xC9, 0x38, 0x71, 0x4D, 0xD0, 0x0A, 0x92, 0x5A, 0x1A, 0x33, 0xEE, 0x9A, 0x72, 0x79, 0xFE, 0x87, 0xD6, 0x95, 0x9B, 0xA6, 0xC5, 0x9B, 0x6A, 0x96, 0xA2, 0x41, 0x02, 0x53, 0xD8, 0x6C, 0x72, 0xE2, 0x81, 0x3A, 0x33, 0x46, 0xE5, 0xD8, 0xA0, 0x7E, 0xD5, 0x74, 0x93, 0xCF, 0xE2, 0xBA, 0xDB, 0xF0, 0x62, 0x26, 0xD7, 0xD6, 0xF1, 0xFE, 0xBB, 0xB2, 0x81, 0x52, 0xA6, 0xEC, 0xD8, 0xE9, 0x5C, 0x77, 0x8C, 0x1F, 0xF5, 0xCF, 0x09, 0x4B, 0xC7, 0x34, 0xD3, 0xEF, 0x18, 0xD6, 0x49, 0x5A, 0xE3, 0x68, 0xE0, 0x7A, 0xD6, 0x8C, 0xA2, 0x41, 0x1C, 0x6F, 0xF9, 0xAD, 0x40, 0xD0, 0xD9, 0x5E, 0x46, 0xFF, 0x58, 0x40, 0x10, 0x6E, 0x80, 0xF2, 0x94, 0x0E, 0x20, 0xD7, 0xDB, 0x26, 0xBF, 0x7A, 0x62, 0xD6, 0x6C, 0x9F, 0x67, 0xEC, 0xC2, 0x26, 0xA8, 0x25, 0xB6, 0xC4, 0xEE, 0x45, 0xEA, 0x73, 0xB7, 0xDC, 0x52, 0x6C, 0x78, 0xB8, 0x67, 0x6A, 0x46, 0xE3, 0xE5, 0xB7, 0x66, 0x36, 0x70, 0x94, 0xA7, 0x21, 0xD3, 0x5A, 0x40, 0x07, 0xE0, 0xF6, 0x4A, 0xD5, 0xDE, 0xBC, 0x2F, 0x17, 0x8E, 0x82, 0x6F, 0xC8, 0x19, 0x53, 0x4F, 0x02, 0xAD, 0x4E, 0x07, 0xD4, 0xDB, 0x98, 0x96, 0x13, 0x2F, 0x01, 0xE6, 0xAE, 0x67, 0x3C, 0x25, 0x38, 0x16, 0x9D, 0x97, 0xAC, 0xC5, 0x9B, 0xFE, 0xB9, 0x36, 0xA0, 0x06, 0xF4, 0xDC, 0xC4, 0x78, 0x17, 0x11, 0x23, 0xE6, 0xBA, 0x32, 0xC0, 0x15, 0x90, 0x00, 0xE6, 0xD2, 0x31, 0x63, 0xD0, 0x74, 0xAA, 0x4C, 0x36, 0x5D, 0x65, 0x36, 0xBB, 0x40, 0xCD, 0x0A, 0x94, 0xEE, 0x9C, 0xC8, 0x5B, 0x40, 0xEF, 0x7B, 0x63, 0x3D, 0x81, 0x9C, 0xC4, 0x5B, 0x1F, 0x4D, 0x2D, 0x47, 0x53, 0xE3, 0xB6, 0x40, 0xC6, 0xF5, 0xF8, 0x8C, 0x93, 0x7D, 0x96, 0xB4, 0xA2, 0x1C, 0x0D, 0xC8, 0x8C, 0x56, 0xF8, 0x8B, 0x70, 0xBC, 0x58, 0x82, 0x53, 0xC6, 0x91, 0x7C, 0x74, 0xAC, 0xE4, 0xF7, 0x7F, 0x7A, 0x20, 0x38, 0xD5, 0x14, 0x0E, 0xE5, 0x1A, 0x15, 0x6D, 0x5C, 0xCE, 0xF9, 0x87, 0xDA, 0x21, 0xD0, 0x15, 0xB3, 0x2A, 0xDD, 0xA1, 0xD3, 0x49, 0x02, 0x78, 0x11, 0xF9, 0xE5, 0xA8, 0x0A, 0xDB, 0x40, 0x2F, 0x42, 0x80, 0x6C, 0xC0, 0x07, 0xF3, 0x62, 0x40, 0x0C, 0xAD, 0x35, 0x31, 0xDB, 0x5C, 0xFB, 0x0B, 0x6D, 0x7D, 0x85, 0x6D, 0x66, 0x13, 0xED, 0xE1, 0x53, 0x51, 0x67, 0xBE, 0xE4, 0xF7, 0x19, 0x96, 0x24, 0xF6, 0x88, 0xB2, 0xB0, 0x76, 0xB9, 0x1D, 0xA5, 0x4E, 0x79, 0x3B, 0x43, 0x30, 0x4D, 0xA0, 0x9D, 0x99, 0x70, 0x9E, 0x27, 0x74, 0xB6, 0x19, 0x90, 0x6B, 0x31, 0x34, 0xDA, 0xA6, 0xE3, 0x83, 0xE1, 0x68, 0x03, 0xD1, 0x80, 0x6E, 0xFC, 0x6C, 0x14, 0x44, 0x57, 0x60, 0xF3, 0x62, 0xF1, 0x06, 0x26, 0xAC, 0xEB, 0x07, 0xA7, 0xC4, 0xC9, 0xFA, 0xD9, 0x10, 0x7E, 0x5A, 0x24, 0xB4, 0x61, 0x02, 0x5A, 0xC0, 0x11, 0x90, 0x37, 0x90, 0x0E, 0x8C, 0x5A, 0xBB, 0x06, 0x0D, 0x6C, 0x05, 0xA4, 0x00, 0x73, 0x68, 0xB7, 0xEB, 0xC4, 0x4C, 0x7E, 0xE1, 0x69, 0x31, 0x2C, 0xE4, 0xD3, 0xEF, 0x7E, 0xE7, 0xD6, 0x48, 0x08, 0xAC, 0x5C, 0x2D, 0xD8, 0x76, 0x7C, 0x5A, 0x17, 0xD4, 0x5E, 0x32, 0x66, 0xC6, 0x25, 0x61, 0x8E, 0x05, 0x5D, 0x8C, 0xF2, 0xCF, 0x26, 0x14, 0xCC, 0x0C, 0xDD, 0x7B, 0x94, 0x39, 0xFE, 0x83, 0xD4, 0xBB, 0xB5, 0xF0, 0xC1, 0x20, 0x43, 0x73, 0xCC, 0x7B, 0x71, 0x84, 0x24, 0x63, 0x46, 0x65, 0xCE, 0x8D, 0x47, 0xBC, 0xB4, 0x5D, 0x8E, 0x77, 0xAD, 0x29, 0x20, 0x3F, 0x08, 0x8F, 0x9C, 0x83, 0x96, 0x53, 0x0A, 0x1F, 0xF9, 0x6C, 0x1D, 0x21, 0xB8, 0x82, 0xC3, 0x4D, 0x80, 0xDC, 0xFC, 0xEB, 0x06, 0x58, 0x03, 0xAE, 0x73, 0x44, 0xD8, 0x8B, 0x98, 0xEE, 0x1A, 0x7B, 0x62, 0xA6, 0x4C, 0xD8, 0x11, 0xF6, 0x41, 0x08, 0xEE, 0x49, 0x1B, 0x43, 0xC7, 0xED, 0x0E, 0xDB, 0x88, 0x84, 0x16, 0xFB, 0x7E, 0x38, 0x15, 0x6E, 0x2C, 0xD4, 0x89, 0xEC, 0x5B, 0xE3, 0x00, 0x7F, 0x81, 0xBB, 0x87, 0x39, 0xE2, 0xA4, 0x9C, 0x87, 0xB9, 0xEB, 0x38, 0x3E, 0x33, 0x07, 0x58, 0x81, 0xB0, 0xB1, 0x88, 0x9E, 0x67, 0xC1, 0x44, 0x9E, 0x2F, 0x0A, 0x4E, 0x69, 0x0E, 0x61, 0x1C, 0x51, 0xD4, 0x54, 0x4A, 0xB1, 0xF3, 0x5B, 0x4C, 0xA7, 0xD9, 0xE7, 0x74, 0x20, 0x60, 0x3C, 0xF9, 0xD0, 0xF1, 0x38, 0xA9, 0xB9, 0xCE, 0x14, 0x5B, 0x75, 0x84, 0x55, 0x16, 0x10, 0x45, 0x24, 0xE0, 0x0A, 0x48, 0x01, 0x3B, 0x00, 0x35, 0x44, 0x5E, 0xE6, 0x21, 0x80, 0x54, 0xC7, 0x15, 0x26, 0xB0, 0xF3, 0x8C, 0xA7, 0xC1, 0x43, 0x2D, 0x35, 0xFF, 0x49, 0x96, 0x16, 0xFD, 0x83, 0x4F, 0x9A, 0x07, 0x16, 0x58, 0x26, 0xB7, 0xF7, 0xE7, 0x6F, 0xF0, 0x5D, 0x47, 0x13, 0xE3, 0x06, 0x6E, 0x06, 0x62, 0x50, 0x2C, 0xC8, 0x2A, 0xEE, 0x2D, 0x16, 0xED, 0x34, 0x92, 0x49, 0x3C, 0x99, 0x38, 0x25, 0x1D, 0x61, 0x4A, 0x3A, 0x70, 0xA7, 0xF2, 0xED, 0x7B, 0x32, 0x98, 0x99, 0xDD, 0xDC, 0xBC, 0x66, 0xEA, 0x34, 0x44, 0xD9, 0x41, 0x18, 0x5E, 0x8C, 0xC4, 0x1B, 0x3A, 0xF1, 0x5B, 0x9A, 0xBF, 0x7A, 0x51, 0xF4, 0x95, 0x04, 0x6A, 0xE3, 0xCF, 0xAA, 0xFE, 0x80, 0x33, 0xEB, 0x37, 0xE3, 0x02, 0x3A, 0xA0, 0x12, 0x2F, 0x27, 0x94, 0x10, 0x60, 0x1B, 0xA0, 0x89, 0x7F, 0x7E, 0x9D, 0xA0, 0xCD, 0xE5, 0x38, 0xB5, 0x6C, 0x31, 0x47, 0x07, 0x59, 0x68, 0xA6, 0x9D, 0xBF, 0x7B, 0x42, 0xFD, 0xAE, 0x2E, 0x33, 0xB9, 0x96, 0xF8, 0x8B, 0xF0, 0x63, 0x11, 0xC7, 0x7B, 0x50, 0xF2, 0x2F, 0xF8, 0x0F, 0xEC, 0xDE, 0x57, 0x9C, 0xC1, 0x96, 0xCD, 0xFF, 0xC9, 0x28, 0x71, 0x05, 0x9F, 0xCE, 0x40, 0x32, 0x07, 0xE1, 0x06, 0x6B, 0xC4, 0xE9, 0x3D, 0xFB, 0x40, 0x0D, 0xB4, 0x11, 0x8A, 0x9F, 0x95, 0x43, 0xFE, 0xEE, 0x40, 0x24, 0x16, 0xF5, 0xF2, 0xFE, 0xA1, 0xB9, 0x9E, 0xA7, 0x89, 0x47, 0x0B, 0xEE, 0x72, 0x0D, 0x79, 0xF7, 0x07, 0x0F, 0xA0, 0x8C, 0xA8, 0x0F, 0x7A, 0xFD, 0xD4, 0xEC, 0x25, 0x80, 0x18, 0xB0, 0x13, 0x50, 0x9F, 0x98, 0x05, 0x84, 0xA1, 0xD5, 0xF0, 0x84, 0x59, 0x06, 0x2D, 0xBD, 0xF4, 0x09, 0x64, 0x6C, 0x87, 0xCB, 0xE8, 0x6E, 0xB4, 0x52, 0x10, 0x7F, 0xCA, 0xB2, 0xBD, 0x5F, 0x8F, 0xAB, 0x93, 0x29, 0x9B, 0xFB, 0x53, 0x9E, 0x34, 0x76, 0xE5, 0xF1, 0x56, 0xA2, 0xA6, 0x01, 0x36, 0x1E, 0x41, 0x3C, 0x33, 0x67, 0xCD, 0x2E, 0xB7, 0x3E, 0x0E, 0xD1, 0x7A, 0x84, 0xDC, 0x56, 0x60, 0xD5, 0xDB, 0xF3, 0xCD, 0xFB, 0xC9, 0x1B, 0xB1, 0xD3, 0xFA, 0x4D, 0xEB, 0x6D, 0x73, 0xD3, 0x6B, 0xE4, 0x16, 0x60, 0x8C, 0x50, 0x33, 0xB9, 0x70, 0x23, 0xC4, 0xC7, 0xB7, 0x03, 0x50, 0xC5, 0x99, 0xBD, 0x71, 0xB4, 0x37, 0x4F, 0x89, 0x89, 0x5A, 0xF2, 0x71, 0xEC, 0xBF, 0x01, 0x60, 0xB5, 0x91, 0x9E, 0x96, 0xF2, 0x44, 0x6D, 0x75, 0xA3, 0x14, 0x38, 0x37, 0x6A, 0x72, 0x29, 0xA7, 0xED, 0xAF, 0xE0, 0x3D, 0xFE, 0x94, 0xDA, 0xD7, 0xFE, 0x08, 0x0B, 0x7B, 0xC2, 0xDE, 0x58, 0x08, 0x4B, 0xE8, 0x7A, 0xDC, 0x7E, 0x01, 0x31, 0x60, 0x1C, 0xEA, 0x64, 0xDF, 0x50, 0x62, 0xAE, 0x45, 0x7F, 0xF4, 0xB7, 0xE7, 0x9B, 0x17, 0xD1, 0x38, 0xE5, 0xE4, 0xD0, 0x1C, 0x59, 0x6A, 0xD2, 0x16, 0x65, 0x5C, 0x85, 0x00, 0x27, 0x8A, 0xB1, 0xB0, 0x78, 0x7B, 0xA2, 0x76, 0x01, 0x45, 0x8C, 0xD2, 0xD1, 0x0E, 0xF8, 0x02, 0x52, 0x78, 0x8A, 0x4E, 0xD4, 0xEA, 0x37, 0xA8, 0x2B, 0xA1, 0xE0, 0xD6, 0xF2, 0xFF, 0x69, 0x8E, 0x11, 0xAA, 0x0A, 0x33, 0x84, 0xED, 0x90, 0x98, 0x43, 0x69, 0x98, 0xF0, 0x4D, 0x56, 0xF6, 0xB9, 0xB9, 0xBD, 0x2A, 0x6D, 0x1B, 0x50, 0x0B, 0xB0, 0x06, 0xC4, 0x5E, 0x73, 0xB8, 0xAA, 0x57, 0xEE, 0xD7, 0x7A, 0x77, 0x04, 0x46, 0xB3, 0x4D, 0x07, 0x44, 0x80, 0x75, 0xB6, 0x0D, 0x89, 0xBE, 0x19, 0xCC, 0x76, 0x64, 0xF3, 0xAD, 0x40, 0xD6, 0xEB, 0xAD, 0x2C, 0x06, 0x68, 0x00, 0x35, 0xF9, 0x6C, 0x6B, 0x3D, 0xDF, 0x60, 0xC7, 0xBC, 0xF8, 0xBA, 0xDF, 0x46, 0x01, 0x65, 0xB7, 0x74, 0x14, 0x51, 0x6B, 0x78, 0x1C, 0xEE, 0xFC, 0xDD, 0x0A, 0x3C, 0x03, 0xC5, 0x05, 0xD7, 0x26, 0x32, 0xE1, 0x3F, 0x04, 0xAD, 0xB7, 0x11, 0x82, 0xF2, 0x18, 0x17, 0xBA, 0x37, 0x6A, 0x5B, 0xAE, 0x4F, 0xAA, 0xF1, 0x33, 0xF9, 0x19, 0x25, 0x13, 0x92, 0x26, 0x9C, 0xD8, 0xEB, 0xB5, 0x70, 0xD7, 0xC5, 0x33, 0xF3, 0xED, 0x4E, 0x20, 0x1F, 0x43, 0x77, 0x21, 0xD6, 0x28, 0xEB, 0x0D, 0x24, 0xC3, 0x35, 0x8E, 0xB5, 0x67, 0xE7, 0xE4, 0x5C, 0xAF, 0x01, 0xF4, 0xE4, 0xEF, 0xC5, 0x5B, 0xB9, 0xBD, 0x16, 0x50, 0x53, 0x3D, 0x1C, 0x80, 0xF8, 0xDC, 0x9B, 0x01, 0xCD, 0xAB, 0xE9, 0xE9, 0x49, 0xE7, 0x3C, 0xD2, 0xAD, 0xE1, 0x76, 0x5A, 0x22, 0xBF, 0x9B, 0x5D, 0x3A, 0xDC, 0xD5, 0xB2, 0x1D, 0x36, 0x79, 0xC9, 0xC4, 0xFF, 0x16, 0x78, 0x39, 0x84, 0x63, 0x1F, 0xA3, 0xFB, 0xB1, 0x36, 0x71, 0x7D, 0x1C, 0x0F, 0xE5, 0x44, 0xA6, 0x8F, 0xA8, 0x0E, 0x98, 0xF3, 0xC5, 0x06, 0x7C, 0x7F, 0xF6, 0x0E, 0x1C, 0x28, 0x99, 0x0B, 0x1C, 0x48, 0x99, 0x2D, 0x13, 0x06, 0x48, 0x80, 0x5D, 0x04, 0xFF, 0x5E, 0x1B, 0x8E, 0x66, 0xEB, 0x4E, 0xF5, 0xD6, 0x5B, 0xE4, 0x29, 0x22, 0x5E, 0x09, 0x04, 0xD1, 0x32, 0x92, 0xEF, 0x06, 0x9C, 0x11, 0x95, 0x06, 0xD2, 0x81, 0xD0, 0x8F, 0x6D, 0x43, 0x00, 0xAE, 0x6F, 0x56, 0x67, 0xEC, 0x89, 0x1A, 0x7C, 0xE7, 0x3A, 0x0D, 0xB3, 0x80, 0x54, 0xCE, 0x87, 0x59, 0x25, 0xE2, 0xCA, 0x4D, 0x99, 0x0D, 0xD5, 0x07, 0xB6, 0xAE, 0x66, 0x12, 0x34, 0x52, 0xFB, 0x3E, 0x0D, 0x1E, 0x13, 0xCA, 0x3C, 0xA5, 0xAB, 0xD5, 0x44, 0x7D, 0x1E, 0x03, 0x01, 0x2C, 0x7B, 0xCD, 0xF7, 0xFA, 0xE3, 0x18, 0x57, 0x75, 0x8F, 0xE2, 0x34, 0xB1, 0x0C, 0x07, 0x16, 0x03, 0x6B, 0x01, 0x68, 0xE2, 0xC5, 0xD9, 0xBA, 0x3B, 0x0F, 0x13, 0xBD, 0x79, 0xE6, 0x37, 0x3B, 0xAF, 0x6D, 0x36, 0x29, 0x80, 0xB4, 0xD7, 0x02, 0x60, 0x7F, 0xB6, 0x33, 0xA2, 0x80, 0x9D, 0x3C, 0x93, 0xE8, 0x1F, 0x1C, 0x40, 0xD4, 0xE4, 0x54, 0x0F, 0xF9, 0x4F, 0x75, 0x82, 0x82, 0x26, 0xFB, 0xD3, 0xB8, 0x26, 0xA7, 0x8D, 0x73, 0x02, 0xEE, 0x73, 0x45, 0xBE, 0x22, 0xE4, 0x54, 0xA7, 0x24, 0x6F, 0x9D, 0x53, 0xC2, 0x7F, 0xD2, 0x9E, 0x04, 0x47, 0x47, 0x36, 0x5A, 0x6F, 0x2F, 0xD5, 0x0E, 0xE0, 0xF6, 0x12, 0x7E, 0xFC, 0x97, 0xD6, 0x63, 0x07, 0x67, 0x7F, 0xCE, 0x7F, 0x39, 0x9B, 0x31, 0xC0, 0xC9, 0x76, 0xEF, 0x9B, 0x27, 0x4E, 0x25, 0x64, 0x32, 0xAA, 0xA8, 0x1B, 0xA2, 0x66, 0xB5, 0x81, 0x5E, 0xA3, 0xC3, 0x30, 0x01, 0x90, 0xD9, 0x68, 0x5B, 0x80, 0x15, 0x78, 0x31, 0x0D, 0x90, 0xC2, 0x99, 0xCD, 0x17, 0x77, 0xE0, 0x14, 0x39, 0x41, 0x53, 0x1A, 0x4B, 0x25, 0xB6, 0xED, 0x7B, 0x63, 0xA5, 0x28, 0xAF, 0x75, 0x5F, 0xB6, 0x70, 0x19, 0xBF, 0xE1, 0xBB, 0x8C, 0x80, 0x76, 0x7C, 0x0D, 0xE4, 0x25, 0xEF, 0x23, 0x8D, 0xA3, 0x9A, 0x15, 0xD4, 0x17, 0x54, 0x70, 0xC7, 0x1D, 0xE0, 0xE6, 0x91, 0xCE, 0x1B, 0x16, 0xC7, 0xFF, 0xD4, 0x60, 0x38, 0xCF, 0xCC, 0xFD, 0x6C, 0x45, 0xF5, 0x3C, 0x73, 0x65, 0xAC, 0x62, 0x09, 0x66, 0x27, 0x53, 0x66, 0xB7, 0xB3, 0x1D, 0xE2, 0xE3, 0x59, 0xC1, 0x18, 0x3A, 0x45, 0x13, 0x0D, 0xA0, 0xE4, 0xE6, 0xBD, 0xE5, 0x69, 0xE6, 0xDB, 0x01, 0x54, 0x03, 0x1E, 0xC0, 0xAA, 0x29, 0x4C, 0x05, 0xDA, 0xA9, 0x96, 0xD8, 0x44, 0xCD, 0xD8, 0xE2, 0x46, 0xC6, 0xFF, 0x8D, 0x2D, 0xFA, 0x7F, 0x73, 0x0C, 0x09, 0x75, 0xEE, 0xDE, 0x08, 0x86, 0xEF, 0xDA, 0xB4, 0xE2, 0xB5, 0x91, 0x1F, 0x5F, 0xA7, 0x65, 0x7D, 0x5C, 0xB6, 0xC7, 0x8E, 0x63, 0x9A, 0x52, 0x0B, 0xC2, 0x8F, 0x61, 0x35, 0xA2, 0x7F, 0xE3, 0x94, 0xF9, 0xA0, 0xD9, 0x40, 0x6C, 0xBE, 0x6F, 0x7E, 0x56, 0x6F, 0x03, 0x38, 0xC9, 0xEB, 0x2A, 0xB0, 0xCF, 0x6D, 0x26, 0x83, 0x68, 0x9C, 0xC2, 0x3D, 0x12, 0xE0, 0x5A, 0xF9, 0x8F, 0x61, 0xE2, 0x12, 0x20, 0xA7, 0x3E, 0x56, 0x81, 0x11, 0x97, 0x8F, 0xAA, 0xAC, 0xC0, 0xE2, 0xA8, 0x2C, 0x01, 0x6C, 0x03, 0xDB, 0x00, 0x5D, 0x23, 0x2E, 0x4F, 0xD4, 0x1C, 0x6F, 0x30, 0x2A, 0x2B, 0x2A, 0x18, 0xB1, 0xFE, 0x96, 0x65, 0x6F, 0xCA, 0x5E, 0x73, 0xF1, 0x6D, 0xCF, 0x69, 0xEF, 0x43, 0x73, 0xEF, 0x57, 0x52, 0x6B, 0xE1, 0x39, 0xD3, 0xFF, 0xBC, 0x73, 0x0C, 0x97, 0x71, 0xB4, 0xE4, 0x36, 0xE7, 0x9F, 0xD1, 0xD8, 0x27, 0xBC, 0xCB, 0x80, 0x9E, 0xEA, 0x07, 0x67, 0xCC, 0xC7, 0x63, 0x6E, 0x8A, 0x5A, 0x8C, 0x01, 0xDD, 0xC0, 0x32, 0xE2, 0x76, 0xE2, 0xE6, 0x95, 0xC9, 0x4F, 0x7D, 0x3B, 0x68, 0x31, 0x85, 0x46, 0x39, 0xFE, 0x6C, 0x9D, 0x04, 0xDF, 0x35, 0x4D, 0x11, 0x1C, 0x88, 0xF5, 0x62, 0x74, 0xDD, 0x4E, 0x20, 0x0A, 0x40, 0xA6, 0xAD, 0xDC, 0xBB, 0x5A, 0xB0, 0x6B, 0xA7, 0x41, 0xAA, 0x74, 0x41, 0x5C, 0xA1, 0x43, 0xAA, 0x68, 0xD2, 0xC0, 0x3D, 0xA0, 0xF2, 0x89, 0x62, 0xCE, 0xD7, 0x31, 0x4F, 0xCC, 0x57, 0x87, 0x2C, 0x06, 0xAD, 0xEF, 0x84, 0x50, 0x8C, 0xE0, 0xF8, 0x11, 0x3B, 0x56, 0x2F, 0x3D, 0xD5, 0x21, 0x8C, 0x9D, 0x36, 0x61, 0x78, 0x51, 0x9F, 0x32, 0x6B, 0x2E, 0x84, 0xC6, 0x9A, 0x73, 0xD7, 0x4C, 0xF0, 0x8F, 0xCF, 0x87, 0x2A, 0xB0, 0xA7, 0x4F, 0xDE, 0xD8, 0x51, 0xCA, 0xD4, 0x5E, 0x73, 0xE0, 0x30, 0xBB, 0xB9, 0x78, 0xE7, 0x8A, 0x69, 0x85, 0x9D, 0x40, 0xD9, 0xED, 0x53, 0x06, 0xD1, 0x0F, 0xE0, 0x8B, 0x4D, 0x78, 0x01, 0x4A, 0xB8, 0x8F, 0x88, 0x3E, 0x41, 0x4B, 0x5A, 0x23, 0xC5, 0x94, 0xB8, 0xDE, 0x59, 0x9A, 0x67, 0x0B, 0x8B, 0xA0, 0x05, 0x7F, 0x4F, 0xEC, 0x87, 0x25, 0xF6, 0x7B, 0xFA, 0xCB, 0x27, 0x87, 0x14, 0x47, 0x0C, 0x01, 0xFE, 0xCF, 0x2B, 0x32, 0x17, 0x5E, 0x34, 0x3F, 0x3D, 0x6E, 0xA7, 0xD6, 0x7F, 0x9A, 0xAC, 0xF9, 0x64, 0x61, 0xDB, 0x6D, 0x0A, 0xBE, 0x8F, 0x88, 0xEA, 0xC6, 0x3B, 0x8E, 0x00, 0x7B, 0x36, 0x51, 0x08, 0x73, 0xA0, 0x47, 0x7C, 0xED, 0xDB, 0x37, 0x95, 0xA3, 0xEF, 0x08, 0x6D, 0xDC, 0xB2, 0xF7, 0xE0, 0x8B, 0xBF, 0x24, 0x6E, 0x20, 0xF9, 0xE0, 0x73, 0x05, 0xDA, 0x98, 0x5C, 0xA9, 0x84, 0xF0, 0xC5, 0x24, 0x1A, 0x2F, 0x6E, 0xA2, 0x6A, 0x62, 0x56, 0xEC, 0x0F, 0x3D, 0xC9, 0xAA, 0xA3, 0x23, 0xCF, 0x5A, 0x9E, 0x09, 0xE5, 0x81, 0xD1, 0xB7, 0xD4, 0xB0, 0x19, 0xD6, 0xCD, 0x34, 0x78, 0xCC, 0xD0, 0x0C, 0x08, 0xBF, 0x93, 0x66, 0x09, 0x5E, 0x17, 0x79, 0xD2, 0x61, 0x37, 0x95, 0x1D, 0x63, 0x78, 0xE6, 0xF6, 0x11, 0xD3, 0x5B, 0xE5, 0x1A, 0x56, 0x22, 0x3B, 0x19, 0xB0, 0xB8, 0x3B, 0x55, 0xC1, 0xB5, 0xDF, 0xE9, 0x4E, 0x06, 0xB0, 0xAB, 0x35, 0xC0, 0x9B, 0x7C, 0xC8, 0x7D, 0xE0, 0xE1, 0xE1, 0x8B, 0x4E, 0x8A, 0x4C, 0xE6, 0x4C, 0xEA, 0x97, 0xAB, 0x80, 0x0A, 0x66, 0x39, 0x26, 0xC2, 0xEA, 0x3D, 0xDA, 0xF4, 0x00, 0x2F, 0xB6, 0x02, 0xB1, 0x00, 0x9B, 0x23, 0x19, 0xF5, 0x74, 0x62, 0xD6, 0xF4, 0x0D, 0x09, 0x14, 0x41, 0xB7, 0x70, 0xFF, 0xC9, 0x51, 0x38, 0xE3, 0x86, 0x2F, 0xBC, 0xE7, 0x1A, 0x75, 0x5C, 0x78, 0xAB, 0x51, 0xD9, 0xC3, 0x98, 0x05, 0x10, 0xCF, 0xA4, 0xFC, 0x3C, 0xBD, 0xFC, 0x8C, 0x89, 0xC5, 0xAD, 0xBF, 0x98, 0xED, 0xD6, 0x31, 0xC6, 0x8C, 0xB9, 0x85, 0x01, 0xE3, 0xAD, 0x6C, 0x53, 0x26, 0x22, 0x38, 0xCA, 0xDB, 0x3A, 0x1C, 0xC5, 0xF6, 0xBC, 0x77, 0x11, 0xF6, 0x34, 0x33, 0xDE, 0xBC, 0x28, 0xA7, 0x0F, 0x9E, 0x1F, 0xF1, 0x2E, 0x8C, 0x55, 0xE1, 0x39, 0x89, 0x97, 0x40, 0x35, 0x93, 0x32, 0x37, 0xE2, 0x69, 0x0B, 0x28, 0x21, 0x36, 0x90, 0x0B, 0xB0, 0x00, 0x54, 0x01, 0xA3, 0x5C, 0x37, 0x9A, 0xDA, 0xDC, 0x63, 0x67, 0x2C, 0xA9, 0x3A, 0xF3, 0x5C, 0xFA, 0x71, 0xDF, 0xCF, 0x82, 0x0E, 0x29, 0x5A, 0x70, 0x1D, 0x59, 0xD0, 0xBB, 0xF3, 0xF5, 0x4C, 0xE0, 0x0C, 0x77, 0xEA, 0x02, 0xF4, 0xC8, 0xFA, 0x9B, 0xFB, 0x00, 0x93, 0xBA, 0x3A, 0x5E, 0xAD, 0x93, 0x76, 0x1D, 0x3F, 0xC8, 0x51, 0x1E, 0x43, 0x80, 0x5C, 0x40, 0x17, 0x3F, 0xF4, 0xBE, 0x96, 0xA4, 0xCC, 0xB3, 0x3F, 0x3D, 0x12, 0xA7, 0x3D, 0xAA, 0x4E, 0x61, 0x06, 0xC3, 0xC3, 0x5A, 0x51, 0xEB, 0xD3, 0xE6, 0x34, 0xEB, 0x16, 0xFE, 0xCF, 0x36, 0x02, 0x34, 0x02, 0xD6, 0xF1, 0x03, 0x4D, 0x5D, 0x57, 0x9B, 0x28, 0x60, 0x17, 0x2F, 0xC3, 0x06, 0x52, 0x80, 0x4A, 0x2A, 0xC0, 0x7B, 0x62, 0x06, 0xF9, 0x62, 0xCD, 0x3E, 0xA5, 0xF9, 0x04, 0x8B, 0xE0, 0x76, 0x87, 0x35, 0xB2, 0x54, 0x27, 0x71, 0x7D, 0xE5, 0xAC, 0x6D, 0x98, 0x96, 0x78, 0x73, 0x95, 0xE5, 0x58, 0x8A, 0x1A, 0xEF, 0x05, 0x66, 0xA3, 0x31, 0xE3, 0x08, 0x9F, 0x81, 0x37, 0x55, 0xC7, 0x0E, 0x23, 0x1F, 0x3A, 0x77, 0x97, 0xCD, 0x26, 0x97, 0x7E, 0x2A, 0xF7, 0xCF, 0x76, 0xAE, 0xE4, 0xC7, 0x05, 0x62, 0xF3, 0xD6, 0x55, 0x3C, 0x82, 0xCA, 0x8B, 0x78, 0xDA, 0x7C, 0x3E, 0x9E, 0x19, 0x4E, 0x7D, 0x9D, 0x09, 0x2C, 0xB9, 0x11, 0xAC, 0x14, 0x1E, 0x29, 0x81, 0xFD, 0x83, 0x1F, 0xB2, 0x80, 0x5E, 0x2F, 0x6A, 0x5E, 0x34, 0x68, 0x7E, 0xB2, 0x20, 0xAC, 0xAE, 0x13, 0x33, 0xC1, 0x5A, 0xA6, 0x58, 0x33, 0x86, 0x65, 0x93, 0x6A, 0x8C, 0x1A, 0xC9, 0x5D, 0x9D, 0x0E, 0x6E, 0xAF, 0x24, 0x6F, 0xB1, 0x79, 0x1C, 0x19, 0xF7, 0xC9, 0xB2, 0xDB, 0x63, 0x67, 0xE6, 0xF9, 0xFA, 0x4C, 0xB8, 0xF0, 0xCB, 0x79, 0xC4, 0x65, 0xDE, 0xEB, 0x9C, 0x0A, 0xA0, 0xEF, 0xE3, 0xDB, 0xD1, 0x89, 0x23, 0xE3, 0x96, 0x94, 0x18, 0x8F, 0x38, 0x6C, 0xCA, 0x10, 0xDD, 0x0A, 0x40, 0x92, 0x89, 0xCF, 0x01, 0x4C, 0x82, 0xF6, 0x8E, 0xC9, 0x20, 0x67, 0xB0, 0x82, 0x19, 0xB3, 0x94, 0x36, 0x5B, 0x99, 0xAF, 0xFB, 0x43, 0xE0, 0xCC, 0x64, 0xF9, 0x51, 0x52, 0x66, 0x4F, 0x44, 0x1E, 0x68, 0x82, 0x3F, 0xEB, 0x7C, 0x7F, 0x26, 0x0B, 0x28, 0x9F, 0x98, 0x29, 0x44, 0x7E, 0xAD, 0x99, 0x14, 0xBD, 0xCF, 0xCD, 0x1D, 0x4C, 0x63, 0xEF, 0xDF, 0x47, 0x49, 0x37, 0xA4, 0xA3, 0x63, 0x2F, 0x2A, 0xE2, 0xB3, 0x17, 0xF5, 0xA4, 0xFC, 0x68, 0x53, 0x66, 0x5D, 0xC7, 0x9B, 0xA3, 0x26, 0xCB, 0x7F, 0x1E, 0x4B, 0xCD, 0xE7, 0x58, 0x22, 0x74, 0x3E, 0xA3, 0x6E, 0xB6, 0x9D, 0x1C, 0x51, 0x3A, 0x8E, 0xCB, 0xA7, 0x40, 0x02, 0x30, 0x05, 0xDC, 0x09, 0xC3, 0x29, 0x6A, 0x78, 0x9F, 0x3A, 0x2F, 0x43, 0xEE, 0xD5, 0x94, 0xB3, 0x6E, 0xA1, 0x10, 0x3A, 0x1F, 0x39, 0x38, 0x98, 0xE3, 0xCC, 0x71, 0xB6, 0x0B, 0x88, 0x00, 0x8A, 0x32, 0xF9, 0x5A, 0xC0, 0xDE, 0x80, 0x14, 0xE0, 0x06, 0x04, 0x87, 0xDB, 0xB2, 0x89, 0x99, 0x3D, 0x56, 0xD4, 0xBA, 0x14, 0x06, 0xDE, 0x2D, 0xF3, 0x22, 0x77, 0x08, 0x0B, 0x37, 0x88, 0xCD, 0x47, 0xEB, 0x56, 0xF6, 0xE3, 0x9C, 0xE2, 0x9E, 0x77, 0x9C, 0x25, 0x6F, 0x41, 0x25, 0xBC, 0x87, 0xF0, 0x26, 0xB0, 0x14, 0x47, 0x6E, 0x6C, 0xA3, 0xFC, 0xC3, 0x9E, 0xFE, 0xED, 0x27, 0x1D, 0xBD, 0x05, 0x10, 0xE5, 0xA6, 0xBC, 0x31, 0x7F, 0x7D, 0x9C, 0x33, 0x1A, 0x50, 0x1E, 0xC5, 0x06, 0x8A, 0x67, 0x2E, 0x1B, 0x6F, 0x5C, 0xEE, 0x88, 0x70, 0x80, 0x51, 0xFF, 0x47, 0x74, 0x8B, 0xD1, 0x2D, 0xEE, 0x84, 0x35, 0x27, 0xBC, 0xBD, 0x09, 0xF9, 0xFF, 0xCC, 0x81, 0x14, 0xA0, 0x37, 0x15, 0xF1, 0x04, 0x94, 0x48, 0x01, 0xA0, 0x36, 0xDE, 0xC2, 0x28, 0x77, 0x64, 0x3E, 0xC6, 0xA6, 0x12, 0xC9, 0xBC, 0xF7, 0xAA, 0x27, 0x0F, 0xB2, 0xA5, 0x21, 0x51, 0x19, 0x3D, 0x35, 0xE2, 0xF7, 0xB3, 0x5E, 0x5F, 0x3F, 0xCD, 0x9D, 0xD7, 0xAD, 0xB5, 0x6E, 0x31, 0xA2, 0x41, 0x91, 0xF1, 0xEB, 0x76, 0x32, 0xFD, 0x3F, 0xF2, 0xB8, 0xB5, 0x46, 0x03, 0x59, 0xAF, 0x97, 0xC3, 0xF6, 0xB7, 0xA3, 0xA5, 0xF7, 0xAB, 0xC5, 0x25, 0x61, 0xCF, 0xD1, 0xFC, 0xB2, 0x2D, 0xA7, 0xF8, 0x57, 0xFA, 0xBA, 0xD0, 0xDB, 0x79, 0x6E, 0xB7, 0x5E, 0xDD, 0x20, 0xCE, 0xFC, 0x77, 0x6F, 0x20, 0x1A, 0xF0, 0x02, 0xE4, 0x98, 0x15, 0x01, 0x52, 0x9F, 0xAD, 0x7A, 0x9D, 0xA8, 0x61, 0x9A, 0x61, 0x35, 0x8A, 0x2D, 0xBE, 0x2C, 0x95, 0xFD, 0xC8, 0xDD, 0x16, 0x63, 0x4F, 0x29, 0x68, 0x8D, 0xEB, 0x32, 0xAD, 0xF1, 0xDE, 0x55, 0xE7, 0x96, 0xEB, 0x47, 0x9B, 0xA7, 0xE6, 0xD3, 0x36, 0xB0, 0x65, 0x5C, 0x2E, 0x5E, 0x95, 0x67, 0xF4, 0xEA, 0x0A, 0x20, 0x05, 0xE8, 0x07, 0x8A, 0x88, 0xDE, 0x87, 0x74, 0xE7, 0x6C, 0xE5, 0x10, 0x0E, 0x18, 0x03, 0xBB, 0x8E, 0x97, 0xDE, 0xE3, 0xF7, 0x88, 0xDD, 0x37, 0xB6, 0x6E, 0x05, 0xDA, 0xA9, 0xAF, 0xD8, 0xAC, 0x1A, 0x18, 0xD1, 0x02, 0xC2, 0x00, 0x27, 0x44, 0x70, 0x4A, 0x04, 0x20, 0x84, 0x29, 0x4F, 0xD9, 0x13, 0xB5, 0xFC, 0xED, 0xEF, 0x98, 0xEB, 0x44, 0x0D, 0x7B, 0x05, 0xDB, 0xEF, 0xAD, 0x2D, 0x54, 0x1B, 0xB6, 0xC6, 0xE2, 0xF0, 0x91, 0xB5, 0x1E, 0xB9, 0xFB, 0xCD, 0xB9, 0x95, 0xC9, 0x6A, 0xAE, 0xD7, 0x6D, 0xA5, 0x36, 0x10, 0x06, 0x6C, 0x86, 0xCB, 0xEA, 0x6D, 0x64, 0xA4, 0x8B, 0x70, 0xA0, 0x8C, 0x41, 0xB8, 0xFB, 0x34, 0x78, 0xE4, 0x00, 0x6B, 0x11, 0xFB, 0xDD, 0x3B, 0xDC, 0x3D, 0x45, 0x0B, 0xA3, 0x65, 0x4F, 0xF0, 0xC6, 0x1A, 0x9F, 0xA8, 0xA9, 0xB7, 0x35, 0xC0, 0xA6, 0xFD, 0xCD, 0xC7, 0xBA, 0xD2, 0x17, 0xA0, 0xC1, 0x17, 0x1D, 0x50, 0xBE, 0xA1, 0x88, 0xEE, 0xB1, 0x92, 0x9C, 0xA8, 0x15, 0xF6, 0xB1, 0xCD, 0x71, 0x11, 0x2F, 0x61, 0x6D, 0xB6, 0x41, 0xB2, 0x4F, 0x63, 0x6F, 0xF9, 0x46, 0x52, 0x70, 0xFF, 0x10, 0xA1, 0x31, 0x5E, 0xF1, 0x6F, 0x05, 0x86, 0xCE, 0x85, 0xF3, 0x6D, 0x91, 0xB7, 0xF5, 0xB4, 0x64, 0x3B, 0x75, 0xEA, 0xCD, 0x00, 0xE5, 0x71, 0xCF, 0x29, 0x42, 0x89, 0x31, 0xCC, 0x9D, 0x8B, 0xF1, 0xF4, 0x84, 0x9A, 0x04, 0xF8, 0x05, 0x64, 0x01, 0x31, 0x9D, 0x67, 0x74, 0x52, 0xB2, 0x9F, 0xF2, 0x64, 0x1B, 0x23, 0x79, 0xE0, 0xA6, 0xD7, 0xAE, 0x0D, 0x1C, 0x53, 0x01, 0x01, 0x7A, 0xBD, 0xE9, 0x90, 0xE7, 0xCA, 0x0E, 0xC0, 0x1C, 0x58, 0x06, 0xEC, 0xE2, 0x29, 0x32, 0x51, 0x6B, 0x96, 0x34, 0xC1, 0x36, 0x67, 0x67, 0xB0, 0xD2, 0x2F, 0x50, 0xD0, 0x90, 0xC1, 0xD6, 0x15, 0xD3, 0x68, 0x4C, 0x28, 0x94, 0xD9, 0x8C, 0xAD, 0x57, 0x4C, 0x8B, 0xEB, 0x48, 0xBC, 0xE5, 0xB8, 0x9F, 0xA6, 0x03, 0x36, 0xE6, 0x18, 0x54, 0xCA, 0x4E, 0x07, 0xCF, 0xD9, 0x42, 0x62, 0x94, 0xBF, 0xFD, 0x93, 0xE4, 0x6D, 0x6B, 0x5C, 0x1B, 0x90, 0x00, 0x76, 0x8E, 0x2A, 0x80, 0x23, 0x9F, 0xF7, 0x95, 0xDE, 0xE5, 0x01, 0x17, 0x04, 0xBA, 0x28, 0x25, 0x72, 0x90, 0xA8, 0x73, 0x09, 0x17, 0xC7, 0xDF, 0x6B, 0xF5, 0xDB, 0x49, 0xDB, 0x0B, 0x88, 0x0D, 0x98, 0x00, 0x5B, 0x70, 0x66, 0x15, 0x8F, 0x98, 0xD9, 0x77, 0xB2, 0xD3, 0x82, 0xCB, 0x42, 0x17, 0x6C, 0xC0, 0xAE, 0x71, 0xE4, 0xDB, 0x48, 0x0C, 0xDA, 0xCA, 0xD5, 0x4C, 0xD1, 0xFF, 0xD2, 0x7F, 0x70, 0x7B, 0x1A, 0x8E, 0xD7, 0xFE, 0x14, 0xFE, 0x7B, 0xDF, 0xB2, 0x7C, 0x64, 0x5A, 0x5D, 0xFB, 0xDA, 0x7D, 0x6C, 0x1E, 0x8F, 0x95, 0xFB, 0xD8, 0x94, 0xE6, 0x6B, 0x43, 0xBB, 0xFA, 0xFA, 0x4F, 0x08, 0xB5, 0xCA, 0x79, 0xE8, 0x1D, 0xFB, 0xE5, 0xA9, 0x45, 0xE9, 0xC2, 0x91, 0xD8, 0x33, 0xA4, 0xEB, 0xB8, 0xF6, 0xD5, 0x94, 0x9D, 0xD2, 0x33, 0x70, 0x44, 0x59, 0xDD, 0x40, 0xD7, 0xAC, 0xA5, 0x11, 0xC9, 0x5C, 0x8C, 0x64, 0x12, 0x0E, 0xAC, 0xF5, 0x51, 0x38, 0x04, 0xF0, 0x4D, 0x71, 0xC1, 0x27, 0x68, 0x9B, 0x16, 0x01, 0x8E, 0xB4, 0x98, 0x4C, 0xE4, 0xF4, 0x2E, 0xC1, 0xDD, 0xD7, 0x12, 0x21, 0xDC, 0x6F, 0xCB, 0x94, 0xBD, 0x6A, 0xBA, 0x85, 0xBC, 0xBE, 0x90, 0x1C, 0x0E, 0x91, 0xEB, 0x0E, 0x7B, 0x7E, 0x2F, 0x48, 0x4F, 0xE4, 0xA3, 0x88, 0x91, 0xB4, 0xBC, 0xAD, 0x7B, 0xA6, 0xEF, 0x42, 0x8E, 0x46, 0x7F, 0xEE, 0xE5, 0xA5, 0xE3, 0xEB, 0xCB, 0xD8, 0xCD, 0x45, 0x5E, 0x40, 0x2C, 0x40, 0x1A, 0x78, 0xBC, 0x59, 0xC6, 0x1F, 0x57, 0x15, 0x2F, 0xDA, 0x3E, 0x73, 0x98, 0x98, 0x6C, 0xAC, 0x31, 0x16, 0xE3, 0xE2, 0xDD, 0xA7, 0x17, 0xF4, 0x4C, 0x81, 0x7A, 0x80, 0x17, 0x7B, 0x03, 0xEE, 0x80, 0x2A, 0x70, 0x2A, 0x1C, 0x75, 0x82, 0x06, 0xC9, 0x31, 0x4C, 0x19, 0xB4, 0xCD, 0x15, 0xCC, 0x7E, 0x76, 0x08, 0x52, 0x98, 0xE4, 0x5F, 0x8E, 0xDD, 0xAF, 0x4A, 0xEE, 0xAA, 0xBF, 0x19, 0xF1, 0xF6, 0x03, 0x94, 0xE4, 0xB9, 0xAB, 0x8C, 0xE0, 0x0F, 0xE4, 0x0F, 0x79, 0xFC, 0x6D, 0xBB, 0x71, 0x8A, 0x8E, 0x97, 0x8B, 0xBF, 0xB7, 0x6B, 0xAB, 0xEB, 0x9F, 0x22, 0x3C, 0x73, 0xE2, 0x43, 0x15, 0x15, 0x69, 0x0E, 0x3F, 0x58, 0x01, 0x75, 0x6C, 0x8C, 0xAF, 0xEA, 0x26, 0x71, 0xBA, 0xC8, 0x75, 0xDE, 0x34, 0x99, 0x38, 0xD2, 0xD1, 0x12, 0xA0, 0xA6, 0xE1, 0xC6, 0x2C, 0xFB, 0x04, 0xD0, 0x06, 0x36, 0xAF, 0xD9, 0x24, 0x4C, 0x80, 0xD0, 0xB7, 0x49, 0x7B, 0x87, 0x62, 0x11, 0xC8, 0xAA, 0xB2, 0xDD, 0xFD, 0x9B, 0xCA, 0x6E, 0xC1, 0x34, 0x37, 0x45, 0xB9, 0x3B, 0x98, 0xBC, 0xFD, 0x08, 0x5B, 0x65, 0xD8, 0xD3, 0x55, 0x30, 0xF6, 0xC7, 0x8F, 0xBA, 0xEE, 0xC2, 0x1D, 0xB1, 0x30, 0x20, 0xA6, 0x47, 0xE7, 0x0F, 0x0B, 0x47, 0x7D, 0x72, 0x12, 0x3C, 0x81, 0x39, 0x6A, 0x6E, 0xDF, 0x9E, 0x9D, 0xF7, 0xE9, 0xE8, 0x64, 0xC0, 0xB6, 0xF9, 0x5E, 0x00, 0x33, 0x60, 0x66, 0x39, 0x3D, 0x97, 0x69, 0xC6, 0x9B, 0x57, 0xEF, 0x45, 0x39, 0x53, 0x78, 0xAF, 0x68, 0xC0, 0x3F, 0x2D, 0xA8, 0x37, 0x11, 0x4E, 0x2C, 0x40, 0x85, 0x57, 0x79, 0x02, 0x2E, 0x40, 0x8E, 0xD7, 0xE5, 0x19, 0x6A, 0x86, 0x0C, 0x83, 0xB6, 0xE4, 0xFC, 0xBC, 0x6E, 0x3D, 0x99, 0x96, 0x19, 0x6B, 0x48, 0x13, 0x22, 0x67, 0x29, 0x74, 0xC2, 0x28, 0xCE, 0x99, 0x30, 0x47, 0x23, 0x0A, 0x58, 0xD7, 0xDE, 0x81, 0x22, 0x4B, 0xDF, 0x64, 0x5B, 0xE3, 0xBC, 0x9E, 0xD9, 0x68, 0x73, 0x7B, 0x50, 0xE5, 0x1B, 0xF6, 0xD1, 0xED, 0x85, 0x33, 0xCD, 0x4A, 0x5E, 0xD0, 0xC6, 0xFF, 0xB7, 0x01, 0xDB, 0x40, 0x12, 0xB3, 0xCF, 0xD5, 0x75, 0xEC, 0x16, 0x4E, 0xDA, 0xB1, 0x2B, 0xD3, 0xFA, 0xEC, 0x54, 0x71, 0xC6, 0x98, 0x25, 0xB2, 0x6A, 0xD4, 0x04, 0xCB, 0x4F, 0x9B, 0xE4, 0x22, 0x07, 0x54, 0x01, 0x27, 0x72, 0x01, 0x2D, 0x5C, 0x77, 0x3A, 0xA0, 0x09, 0x78, 0x4C, 0xD0, 0x28, 0x06, 0x2D, 0xC5, 0x85, 0xB9, 0x1A, 0xB7, 0x93, 0xDC, 0x8F, 0x34, 0xE4, 0x9D, 0x48, 0x2D, 0x17, 0x6C, 0x25, 0x64, 0xD9, 0x4D, 0x10, 0x10, 0x7D, 0x7D, 0x39, 0xEA, 0x07, 0x5D, 0x7F, 0xB9, 0xC8, 0x45, 0xF1, 0x82, 0x2A, 0x90, 0x1C, 0x09, 0x84, 0x31, 0x0B, 0xEA, 0xB5, 0xBC, 0x3F, 0xDB, 0x02, 0x34, 0x80, 0xF1, 0xD7, 0x98, 0x6D, 0x0D, 0x4F, 0xC4, 0x33, 0x36, 0xB0, 0xFD, 0xF6, 0x96, 0xEA, 0x51, 0x88, 0x46, 0xED, 0x38, 0xC2, 0xE2, 0x66, 0xFA, 0x68, 0x30, 0xFF, 0x53, 0x94, 0xEB, 0x78, 0x66, 0x3D, 0xAA, 0x4F, 0x82, 0xE3, 0x5B, 0xBF, 0x1E, 0x4A, 0x24, 0xE0, 0x01, 0x28, 0x21, 0xC4, 0x54, 0xD6, 0xCB, 0x9E, 0x98, 0x05, 0xDD, 0xED, 0x0B, 0xD9, 0x84, 0x53, 0x92, 0x2D, 0x98, 0x5E, 0x76, 0x34, 0xC4, 0x74, 0x7E, 0xFD, 0x6B, 0x07, 0xA4, 0x52, 0xDF, 0x3F, 0xD1, 0xD1, 0x3E, 0x5E, 0xB7, 0x72, 0x57, 0x49, 0x82, 0xDA, 0x37, 0xEE, 0x29, 0x12, 0x9C, 0x01, 0x4C, 0xED, 0x43, 0x6F, 0x5E, 0x02, 0xFB, 0x7A, 0xE1, 0xC8, 0xC1, 0x5E, 0xC0, 0x0A, 0x6E, 0xAD, 0xF4, 0x9B, 0xC0, 0x13, 0x9F, 0xED, 0x51, 0x51, 0xE0, 0xD8, 0xCA, 0x53, 0x0A, 0x76, 0x8A, 0x72, 0xBB, 0xB9, 0xF0, 0x57, 0xEA, 0x29, 0x94, 0xBA, 0x47, 0xE3, 0xDE, 0xB3, 0xB9, 0xEB, 0xD3, 0x41, 0x11, 0x70, 0x01, 0x62, 0x03, 0x1E, 0x80, 0x29, 0xA0, 0xFD, 0xF7, 0xB3, 0xB8, 0xC5, 0x8B, 0x71, 0xDB, 0xD3, 0xE4, 0xEB, 0x02, 0x36, 0xF0, 0x3A, 0x05, 0xE8, 0xBD, 0x1D, 0xC5, 0xE2, 0xEE, 0xBF, 0xC9, 0x65, 0xDE, 0xEE, 0x34, 0x78, 0xAA, 0x4F, 0xDA, 0x04, 0xAF, 0x3F, 0xFE, 0xF5, 0x1E, 0xBB, 0xD0, 0x27, 0xF3, 0x76, 0xFA, 0x78, 0x52, 0x6A, 0x33, 0x3B, 0xFB, 0x3B, 0xC2, 0x1B, 0x71, 0xD7, 0xDD, 0x3A, 0x9A, 0xCB, 0x17, 0xA7, 0xFC, 0xE0, 0x0B, 0xA8, 0x0D, 0xF4, 0xCC, 0x11, 0x78, 0x51, 0x8E, 0xF1, 0x66, 0x15, 0xC7, 0x52, 0xFD, 0x29, 0x3D, 0xE5, 0x08, 0x41, 0x51, 0x4C, 0x6F, 0xEC, 0xF6, 0x61, 0xC9, 0x5E, 0x4C, 0x5B, 0x73, 0xA0, 0x14, 0x68, 0x66, 0xA8, 0x6D, 0x05, 0xB4, 0x80, 0xDC, 0x84, 0x33, 0x6D, 0xED, 0x8C, 0xB3, 0x42, 0xCA, 0xE6, 0xCF, 0x4D, 0xE8, 0x37, 0x63, 0x48, 0xA8, 0x08, 0x78, 0x0C, 0xA8, 0x85, 0xB0, 0xE3, 0x66, 0xC3, 0xB4, 0xB1, 0xD9, 0x00, 0x59, 0xB0, 0x20, 0xD0, 0x5B, 0x84, 0xF7, 0x16, 0x46, 0x4D, 0xF0, 0xBE, 0xB3, 0x2E, 0xAB, 0xDB, 0x4C, 0x8C, 0xB5, 0x21, 0x08, 0xDA, 0xD3, 0x37, 0x57, 0xD6, 0xDB, 0xB3, 0x63, 0x12, 0x1C, 0x32, 0xDE, 0x4A, 0xCF, 0xD5, 0x80, 0x2C, 0xC2, 0x80, 0x4C, 0xBE, 0xEF, 0x58, 0x5C, 0xCC, 0x96, 0xD5, 0x4C, 0x12, 0xE7, 0x1E, 0x6F, 0xAF, 0x99, 0x89, 0x72, 0x12, 0xB4, 0x67, 0x4A, 0xB4, 0x01, 0x37, 0xC0, 0x0A, 0xD8, 0x1F, 0x4F, 0x13, 0x33, 0x20, 0x16, 0xCF, 0xD4, 0x89, 0x5A, 0x23, 0x45, 0x66, 0xEE, 0x99, 0x3B, 0xB9, 0xC6, 0xDF, 0x98, 0x7C, 0xD3, 0x4E, 0xD9, 0x37, 0xC4, 0xB6, 0xC9, 0xFB, 0x12, 0x93, 0x71, 0x80, 0x79, 0x73, 0x12, 0xEC, 0x76, 0xA9, 0xDC, 0x75, 0xCA, 0x07, 0x4E, 0x69, 0x49, 0x4D, 0x3D, 0x17, 0x2F, 0x33, 0xBD, 0xED, 0x2D, 0xEC, 0x54, 0xDD, 0xF5, 0xD7, 0xB2, 0xFD, 0x5A, 0xE7, 0xDE, 0x7A, 0x69, 0x2B, 0x20, 0xD6, 0x05, 0xC7, 0xD8, 0x34, 0x6F, 0x9C, 0xC7, 0x9D, 0xFA, 0x98, 0xC2, 0x4E, 0x95, 0xC5, 0xC8, 0x9D, 0x4C, 0x7B, 0x16, 0xEA, 0x48, 0x7A, 0xB2, 0xF3, 0xC3, 0x21, 0x26, 0xEF, 0x02, 0x74, 0x11, 0x02, 0x48, 0xBC, 0xB0, 0x49, 0x9E, 0x9E, 0xA1, 0x36, 0x9E, 0xDE, 0xD6, 0x5C, 0xB1, 0x4F, 0xC9, 0x86, 0xF2, 0x39, 0x5E, 0xD8, 0xC9, 0xD0, 0x60, 0x85, 0x65, 0x20, 0x89, 0x51, 0x50, 0xB9, 0xE8, 0xB3, 0x8C, 0xCA, 0x8F, 0x7F, 0x9A, 0xD7, 0x7C, 0xA6, 0xA9, 0x84, 0x15, 0x60, 0xF7, 0xAC, 0x75, 0x9E, 0xB5, 0x67, 0x8E, 0x3F, 0xEA, 0xCC, 0x23, 0x12, 0xF0, 0x0D, 0xEC, 0xC9, 0xB1, 0x52, 0x26, 0xBD, 0x11, 0x3B, 0x01, 0x0D, 0xC0, 0x9E, 0xCE, 0xB1, 0x31, 0x8F, 0x6E, 0x9F, 0x2F, 0x8B, 0xC1, 0x5B, 0xC7, 0xB9, 0x28, 0x9F, 0xAB, 0x3D, 0xFF, 0x2A, 0x7F, 0x66, 0x13, 0xD1, 0x81, 0x34, 0x22, 0x00, 0x27, 0x64, 0x8F, 0xAF, 0x0C, 0x8E, 0xF6, 0x02, 0xDA, 0x27, 0x6A, 0x1B, 0xC6, 0x55, 0xB2, 0x26, 0x6A, 0xDC, 0x60, 0xCE, 0xA7, 0x8F, 0xB1, 0x78, 0x23, 0x6A, 0xED, 0xF0, 0xB0, 0x87, 0x11, 0x51, 0xD9, 0x37, 0x69, 0x48, 0xEC, 0xE3, 0x0B, 0xA9, 0xEB, 0xCD, 0xBB, 0xD1, 0x99, 0xAE, 0xDD, 0x34, 0x02, 0xE6, 0x3D, 0xDE, 0xEE, 0x9A, 0x1A, 0xD3, 0x09, 0x06, 0xD8, 0x7B, 0x5C, 0x40, 0x19, 0xA7, 0x06, 0xD6, 0x04, 0xAF, 0x01, 0x21, 0x9A, 0x6F, 0x0F, 0xB9, 0x25, 0xB7, 0xA2, 0xA7, 0x63, 0x72, 0xCF, 0xDE, 0x14, 0xC3, 0x25, 0xDC, 0x6C, 0x97, 0x09, 0x09, 0x6F, 0xBF, 0xAA, 0x40, 0x3B, 0x51, 0x40, 0x06, 0xA0, 0x09, 0xAC, 0x06, 0x74, 0x92, 0xCE, 0xCF, 0x58, 0x13, 0x44, 0xC6, 0xE4, 0x77, 0xAB, 0x6C, 0x73, 0x16, 0x37, 0x1A, 0xB2, 0x45, 0x5B, 0xF0, 0xC0, 0x14, 0x83, 0xBC, 0xF2, 0xC3, 0xD8, 0xDB, 0xF1, 0x33, 0xBC, 0x65, 0x3E, 0x57, 0x2F, 0xDB, 0x9C, 0x50, 0x9C, 0x4B, 0xB2, 0x6F, 0x33, 0x71, 0x7E, 0xB2, 0xE9, 0xFB, 0x31, 0x2B, 0x76, 0x47, 0x08, 0x27, 0xB7, 0x76, 0xBC, 0x7B, 0xA7, 0x4E, 0x59, 0xDF, 0xA6, 0x4E, 0x95, 0x38, 0x5A, 0x01, 0xEC, 0xBE, 0x32, 0x12, 0xE6, 0x21, 0xA7, 0x35, 0xDE, 0xF1, 0x7C, 0xD7, 0x60, 0x0C, 0x04, 0x61, 0x32, 0x06, 0xD4, 0xE2, 0x94, 0x48, 0x6D, 0xEE, 0xC8, 0xED, 0x06, 0x32, 0x80, 0xDE, 0x40, 0x39, 0x90, 0x1B, 0x08, 0x03, 0xAA, 0xC6, 0x8D, 0x7C, 0x82, 0xC6, 0x19, 0x6B, 0xC1, 0x32, 0x61, 0xED, 0xFC, 0x05, 0x54, 0xF5, 0xE6, 0xDD, 0xC2, 0xE8, 0x1C, 0x0B, 0xA8, 0xBD, 0x71, 0x99, 0x25, 0x82, 0xB6, 0xBF, 0x95, 0xC5, 0xD7, 0xF7, 0x18, 0xB7, 0x25, 0xE5, 0xAA, 0xDC, 0x00, 0x9B, 0x8E, 0x9B, 0xFB, 0x4A, 0x5B, 0xF3, 0xB4, 0x58, 0x98, 0x5F, 0xF4, 0x49, 0xD7, 0x15, 0x05, 0x56, 0xBD, 0x21, 0x9C, 0x34, 0xC9, 0x54, 0x20, 0x1A, 0xF0, 0xE9, 0x33, 0xFE, 0xF6, 0x67, 0x48, 0x4E, 0x91, 0xFD, 0xD8, 0x7F, 0xC5, 0xE8, 0x1B, 0xB3, 0x6F, 0x3D, 0x1B, 0x58, 0x02, 0xCC, 0xD8, 0x5A, 0x0A, 0x44, 0x12, 0x05, 0x58, 0x00, 0x8B, 0x63, 0x32, 0xE7, 0xCC, 0x3D, 0xBE, 0x33, 0x13, 0x34, 0xC3, 0xC4, 0x89, 0x1D, 0x66, 0x65, 0x33, 0x05, 0x2D, 0x8D, 0x41, 0xA3, 0x8C, 0xB9, 0x8D, 0x77, 0x6D, 0xA5, 0x66, 0x27, 0x74, 0x48, 0x78, 0x0D, 0x48, 0x2D, 0x3F, 0x9B, 0xC5, 0x39, 0x79, 0x69, 0x7E, 0xDB, 0x2D, 0xCC, 0x92, 0x7B, 0x56, 0xA4, 0x7E, 0x9E, 0x01, 0xEE, 0xB7, 0xF9, 0x3D, 0xE5, 0x9C, 0x59, 0x52, 0x62, 0x0F, 0xE8, 0x31, 0xE5, 0xDB, 0xFE, 0x62, 0x05, 0x10, 0x7D, 0x16, 0x22, 0x14, 0x13, 0x66, 0xB7, 0x7E, 0xDC, 0xE3, 0x26, 0x7D, 0x65, 0x7D, 0x76, 0x16, 0x38, 0x81, 0x5A, 0x33, 0xE0, 0x16, 0x90, 0x03, 0x07, 0xBC, 0x00, 0x71, 0x60, 0xCE, 0x94, 0xD9, 0x2C, 0xF6, 0x09, 0x9A, 0xB3, 0x7F, 0x61, 0x60, 0xED, 0xE0, 0x08, 0xDA, 0x4E, 0x81, 0x29, 0x6F, 0x26, 0x04, 0x61, 0x4D, 0x24, 0x5A, 0xA5, 0xB3, 0x45, 0xEB, 0xE6, 0x8A, 0xFD, 0xD5, 0x86, 0x7C, 0x5D, 0xA9, 0x7B, 0x4F, 0x51, 0xAE, 0xFE, 0x39, 0x3E, 0x52, 0xD8, 0x98, 0xA0, 0x4D, 0xBF, 0xE2, 0x79, 0x54, 0xC6, 0xF8, 0x25, 0x40, 0x65, 0x23, 0xB8, 0x6A, 0xC4, 0xAD, 0x98, 0xBD, 0x76, 0x01, 0x53, 0xC0, 0x85, 0x50, 0xC6, 0x35, 0x47, 0x1B, 0x9A, 0xA6, 0x40, 0x53, 0x4D, 0x77, 0xF7, 0x48, 0xCF, 0x16, 0xB2, 0xF3, 0x28, 0xFE, 0x8C, 0xBF, 0x72, 0x0A, 0x45, 0x80, 0x08, 0x20, 0x9D, 0xD8, 0x80, 0x1B, 0x60, 0x01, 0xC4, 0x35, 0x79, 0x42, 0xD0, 0x02, 0x4F, 0x1E, 0x45, 0xAA, 0xF2, 0x5E, 0xB8, 0x7D, 0xD9, 0xD6, 0x67, 0x9B, 0x4A, 0x56, 0xE3, 0x46, 0xB5, 0x59, 0xCA, 0x8E, 0x44, 0x48, 0xFD, 0x5E, 0x9E, 0xFE, 0xD6, 0xC8, 0x62, 0x45, 0xCA, 0x02, 0x58, 0x96, 0x45, 0x4F, 0x82, 0x55, 0x5F, 0x41, 0xCD, 0x4F, 0x6E, 0xA7, 0x5C, 0x23, 0x89, 0xE6, 0x82, 0x1D, 0xB7, 0x98, 0x67, 0x73, 0x25, 0x16, 0xB0, 0x13, 0xD0, 0x00, 0x78, 0x0F, 0xE5, 0xD1, 0xFE, 0xD3, 0x57, 0x8F, 0xA3, 0x21, 0x07, 0xD5, 0xD4, 0x53, 0xD5, 0x6C, 0xF1, 0x71, 0xAA, 0x2E, 0x33, 0xC5, 0x0F, 0x6E, 0xCA, 0x36, 0x6D, 0xCB, 0x16, 0x90, 0x49, 0x38, 0xE0, 0x4D, 0x08, 0x90, 0xD8, 0x21, 0xBC, 0xF7, 0xB4, 0x64, 0x9E, 0xFF, 0x46, 0xDD, 0x48, 0x3F, 0xED, 0xC5, 0x3D, 0xC7, 0x1B, 0xB0, 0x21, 0x46, 0x76, 0x37, 0x9D, 0xFB, 0xFC, 0xF8, 0x80, 0x61, 0x37, 0x0E, 0xF4, 0xF8, 0x98, 0x42, 0xB6, 0xDF, 0x7A, 0x68, 0x63, 0xD1, 0xF2, 0x3E, 0x36, 0x79, 0x7B, 0x5D, 0xD5, 0x61, 0x7A, 0x11, 0x8D, 0x36, 0x3D, 0xD9, 0xAE, 0x76, 0x5A, 0xB3, 0x6B, 0xF2, 0x9A, 0x2D, 0x40, 0x1A, 0x30, 0x21, 0x7C, 0x86, 0x26, 0xF5, 0xA6, 0xBB, 0xCF, 0x34, 0xC2, 0xCF, 0xC8, 0x05, 0x4E, 0xA1, 0xC9, 0x79, 0x99, 0x79, 0x9D, 0x55, 0xD2, 0xEC, 0x30, 0x06, 0x23, 0xB2, 0x1D, 0x90, 0xC1, 0xBC, 0x98, 0x84, 0x01, 0xD2, 0x08, 0xDA, 0x92, 0x09, 0x5A, 0xFD, 0x66, 0xFC, 0xE9, 0xC1, 0xAA, 0xB5, 0x8D, 0x9A, 0x05, 0x8D, 0x89, 0x1D, 0xB7, 0x32, 0x37, 0x97, 0x8D, 0x8E, 0xA0, 0x6D, 0x3B, 0xD9, 0x68, 0xD3, 0x10, 0x69, 0xD6, 0xA2, 0x67, 0xA6, 0x2F, 0x76, 0x92, 0x78, 0x3A, 0x01, 0x9F, 0xDA, 0xF5, 0x8D, 0xA0, 0x49, 0xBC, 0xA9, 0x6A, 0x42, 0x19, 0xA7, 0x1B, 0x30, 0x03, 0x26, 0xE5, 0xA5, 0xFC, 0xDA, 0x41, 0xC4, 0x91, 0xF5, 0x8A, 0xC8, 0x3E, 0xC1, 0x3E, 0xA6, 0x89, 0xAA, 0xB3, 0xA7, 0xCC, 0x15, 0x26, 0xB5, 0x8B, 0x60, 0xF2, 0x68, 0xD4, 0xF1, 0xBF, 0x6A, 0x96, 0x5E, 0x09, 0x6B, 0x84, 0xD4, 0x80, 0x16, 0xEE, 0x22, 0x2B, 0x61, 0xEF, 0x91, 0x10, 0x66, 0xDC, 0x45, 0xCE, 0x09, 0x5A, 0xE3, 0x36, 0xB2, 0x9C, 0x69, 0x1F, 0x35, 0xD1, 0x7A, 0x82, 0x96, 0x56, 0xCC, 0xC9, 0x69, 0xC4, 0xAE, 0x94, 0x29, 0x2F, 0x93, 0xD4, 0xFD, 0x26, 0xA7, 0xC9, 0xE4, 0x21, 0xE6, 0x27, 0x9F, 0x30, 0x28, 0xE7, 0xCD, 0x2A, 0x92, 0x11, 0x9C, 0x7D, 0x46, 0xCB, 0xAB, 0x6B, 0xCD, 0xD2, 0x67, 0x9F, 0x8A, 0x92, 0xD3, 0x97, 0x3D, 0x00, 0x51, 0xC2, 0x80, 0xAD, 0x40, 0x73, 0xC5, 0x9E, 0x8C, 0xD9, 0xDA, 0x5C, 0xD1, 0x72, 0xA2, 0xBF, 0xE6, 0xF2, 0x72, 0x84, 0x2E, 0x8C, 0x2B, 0xD3, 0x31, 0x0E, 0x5C, 0xD4, 0x35, 0x1A, 0x81, 0x54, 0x01, 0xFC, 0x03, 0xB3, 0xF7, 0x28, 0x8D, 0x4B, 0x26, 0x67, 0xCC, 0x8A, 0xDE, 0x45, 0xBE, 0x7F, 0x21, 0xDF, 0x7B, 0xE4, 0xE3, 0xFE, 0x8B, 0x19, 0xC4, 0x48, 0xAC, 0x8A, 0xBA, 0xA1, 0x3A, 0x24, 0xED, 0xB9, 0x38, 0xD0, 0x4E, 0xE1, 0xA7, 0x7F, 0xEC, 0x47, 0x95, 0x81, 0x89, 0x47, 0xD4, 0x09, 0x1E, 0x29, 0xA3, 0x35, 0x26, 0xBF, 0xBC, 0x59, 0x8F, 0x9B, 0xF0, 0xDD, 0x45, 0x8B, 0x69, 0x4C, 0x3D, 0x2D, 0x04, 0x1D, 0x58, 0x09, 0x88, 0xBD, 0x49, 0xEF, 0x72, 0x03, 0x2A, 0x75, 0x72, 0x3F, 0x8D, 0x95, 0xA2, 0x55, 0x57, 0x1A, 0x82, 0x6B, 0x16, 0x42, 0xB1, 0xAF, 0x53, 0xDA, 0x6F, 0x63, 0x10, 0x08, 0x01, 0x6A, 0x10, 0x2F, 0x7A, 0x46, 0x1F, 0xD1, 0x32, 0x41, 0xDB, 0x1F, 0x03, 0x48, 0x18, 0xA6, 0xB5, 0xFD, 0xD6, 0x51, 0x59, 0x6E, 0xC8, 0x51, 0xDD, 0xF5, 0xD7, 0x1F, 0xC8, 0x21, 0xAE, 0xE1, 0xBE, 0xF8, 0x48, 0x90, 0x53, 0x44, 0x66, 0x76, 0x16, 0xC2, 0xD4, 0x86, 0x9F, 0xE2, 0xCE, 0x71, 0xBD, 0xDC, 0xA3, 0x10, 0x31, 0x90, 0x46, 0x81, 0x5A, 0x4E, 0x5F, 0xB2, 0xFA, 0x8C, 0xB0, 0x9E, 0x55, 0x6A, 0x02, 0x8B, 0xD0, 0x02, 0x7C, 0x4C, 0x5A, 0x92, 0x03, 0x4D, 0xB9, 0x69, 0x62, 0x33, 0x39, 0xA0, 0xEE, 0x93, 0x53, 0x3D, 0x8C, 0x28, 0x19, 0x03, 0x22, 0xCD, 0x6B, 0x4D, 0x98, 0xB8, 0xB1, 0x00, 0x2D, 0x20, 0x14, 0xA8, 0xC5, 0xC4, 0x8D, 0x00, 0x94, 0x30, 0x05, 0xCE, 0x40, 0xBB, 0x0D, 0x64, 0xB9, 0x8A, 0xE2, 0xFE, 0xC6, 0x46, 0x43, 0x85, 0x6E, 0xDC, 0xBF, 0x97, 0x61, 0x8B, 0x20, 0x69, 0xB2, 0xEF, 0x32, 0x29, 0x56, 0x6F, 0xAB, 0xEC, 0x99, 0xC9, 0xE3, 0xA8, 0x4E, 0xCA, 0xA2, 0xC9, 0x2D, 0xD8, 0xAF, 0xF1, 0xCA, 0x3F, 0x43, 0x64, 0x3B, 0xD3, 0xE1, 0xEF, 0x2E, 0xFC, 0x4C, 0xC8, 0xFC, 0x34, 0x56, 0x58, 0x54, 0x32, 0x22, 0x01, 0x9D, 0x23, 0xA2, 0xE2, 0x16, 0x09, 0xE1, 0x71, 0xCC, 0x67, 0x27, 0xD3, 0xB0, 0x62, 0x94, 0xA2, 0xE9, 0x83, 0xA3, 0x54, 0x0F, 0x39, 0xB4, 0x66, 0xC0, 0x64, 0x22, 0x3E, 0xE9, 0x08, 0x85, 0x08, 0xE0, 0x05, 0x94, 0xBC, 0x09, 0x46, 0xBE, 0x80, 0x20, 0xCA, 0x26, 0x68, 0x4A, 0x0B, 0x1B, 0x61, 0xD0, 0xA8, 0x80, 0x44, 0xA0, 0x01, 0x6B, 0x16, 0x3E, 0x7B, 0x20, 0x5A, 0xE1, 0xC5, 0x9E, 0x6A, 0x3E, 0x5A, 0x10, 0xB3, 0xE2, 0xDF, 0xF5, 0x40, 0xC5, 0x2C, 0x01, 0xE3, 0x5A, 0x23, 0xC5, 0xD9, 0xB2, 0x1E, 0xFF, 0xA0, 0x69, 0x84, 0xF3, 0xF1, 0x94, 0xAE, 0x78, 0x97, 0xED, 0xAB, 0xDF, 0xBC, 0x04, 0x53, 0x60, 0x0B, 0xA0, 0x6F, 0x9B, 0x0D, 0x1E, 0xE5, 0xE4, 0x30, 0x25, 0x82, 0x36, 0x3D, 0xA0, 0x8C, 0xB9, 0x24, 0xC6, 0x45, 0x89, 0xF3, 0x66, 0xEB, 0xFB, 0xD4, 0x1D, 0x6F, 0x1B, 0x0F, 0x02, 0x20, 0x1B, 0xE8, 0x20, 0x36, 0x50, 0x06, 0x64, 0x01, 0xFD, 0x83, 0xE3, 0x08, 0x41, 0xB3, 0xEF, 0x48, 0xE3, 0xD1, 0x60, 0xE6, 0x0D, 0xC2, 0x8C, 0x6E, 0x61, 0xE7, 0x52, 0xC3, 0x52, 0x93, 0x41, 0xD3, 0x67, 0xC2, 0x51, 0x04, 0x33, 0xBA, 0xB9, 0x8C, 0xB9, 0xCA, 0x94, 0x4D, 0x23, 0xF4, 0x33, 0xB7, 0x50, 0x86, 0x70, 0x0B, 0x8B, 0x1D, 0xAF, 0x7B, 0x4C, 0x30, 0x68, 0x76, 0x76, 0xD6, 0xB3, 0xDE, 0xD8, 0xA5, 0x03, 0xFD, 0x78, 0xD1, 0xF5, 0x28, 0x6F, 0x3A, 0x59, 0x95, 0x27, 0x69, 0xD1, 0x95, 0xA3, 0x89, 0x25, 0xCD, 0x90, 0xF1, 0xB8, 0xEB, 0x50, 0xD4, 0x7F, 0xAB, 0xB9, 0xA3, 0xFA, 0xDB, 0x05, 0x02, 0x9A, 0x0A, 0xA5, 0x2A, 0x90, 0x94, 0x26, 0x65, 0x03, 0xDA, 0x40, 0xAC, 0x09, 0x9A, 0x63, 0x2A, 0xA4, 0xFE, 0xEF, 0xA0, 0xC1, 0xD0, 0x46, 0x30, 0xFB, 0x8D, 0xFE, 0x21, 0x3F, 0x7A, 0x5A, 0xDE, 0xA9, 0x2D, 0xEB, 0xFD, 0x6E, 0x56, 0xED, 0x24, 0x04, 0x04, 0x97, 0x05, 0x72, 0x86, 0x5F, 0xE4, 0xED, 0x9B, 0xBA, 0xF9, 0xFF, 0x9E, 0x46, 0xAF, 0xBB, 0xEF, 0x22, 0x53, 0x4F, 0x75, 0xA3, 0x17, 0x20, 0x0A, 0xF8, 0x02, 0x62, 0x06, 0xA3, 0x3E, 0xDF, 0x15, 0x77, 0xEB, 0xA7, 0x1F, 0xBE, 0x51, 0xD4, 0x73, 0x3E, 0x6D, 0x63, 0x22, 0x69, 0x7C, 0x1C, 0x20, 0xF1, 0x01, 0x3B, 0x05, 0x0E, 0xF4, 0xEC, 0x06, 0x08, 0xF1, 0xAF, 0xA3, 0x79, 0x86, 0x6A, 0x4F, 0xD0, 0x02, 0xAB, 0x9F, 0xAA, 0x6F, 0xD0, 0xB0, 0x8A, 0x69, 0xE1, 0x64, 0xB4, 0xA1, 0xEF, 0x94, 0x43, 0xED, 0xB1, 0x42, 0xAB, 0x2D, 0x4E, 0x6D, 0x89, 0xC8, 0xE9, 0x70, 0x3D, 0x1A, 0x3F, 0x57, 0x80, 0xCB, 0x6F, 0x83, 0xB7, 0xCD, 0x05, 0x40, 0x9E, 0x5D, 0xCF, 0x3D, 0x95, 0xB3, 0xCA, 0xAE, 0x93, 0x8C, 0x99, 0x5E, 0xE3, 0x48, 0x3B, 0x52, 0x6D, 0x6E, 0x40, 0x0B, 0x08, 0x07, 0x6A, 0xAA, 0xF4, 0x8C, 0x31, 0x93, 0xBB, 0xDE, 0x1D, 0x73, 0x70, 0x73, 0xC0, 0x95, 0x02, 0x63, 0x9E, 0xDD, 0x80, 0x35, 0x39, 0xB6, 0x7C, 0xEA, 0x89, 0x02, 0xB9, 0x81, 0x16, 0x22, 0x06, 0x33, 0x97, 0x05, 0xF6, 0x06, 0x62, 0x4F, 0xCC, 0xF2, 0xAD, 0x57, 0x8F, 0x3D, 0x47, 0x04, 0xEF, 0x0D, 0xBD, 0x91, 0x97, 0xC4, 0xEA, 0x0B, 0x45, 0xD9, 0x45, 0x4F, 0xCC, 0xEC, 0xDD, 0x8A, 0x92, 0x98, 0x6A, 0x23, 0x19, 0x73, 0x8E, 0xB7, 0x9D, 0xDD, 0xDA, 0x8C, 0xE0, 0x94, 0x54, 0xF8, 0xE4, 0x6B, 0x4F, 0x61, 0xDB, 0x9B, 0x8C, 0xA0, 0x3D, 0x3A, 0x26, 0xEE, 0xF1, 0x4F, 0xD3, 0x60, 0x3C, 0x10, 0xDF, 0xC6, 0xA6, 0x16, 0x7C, 0xAE, 0x8E, 0x3F, 0xD5, 0xE4, 0x4C, 0x1A, 0x6D, 0x4A, 0xF8, 0xD4, 0x6B, 0xC5, 0xC5, 0x69, 0x3F, 0x38, 0x26, 0xCB, 0x85, 0xC5, 0x2C, 0x56, 0x8C, 0x0A, 0x64, 0xE2, 0xE2, 0x94, 0x0D, 0x78, 0x00, 0x9D, 0xB8, 0x46, 0x6D, 0x03, 0xC1, 0xCD, 0x84, 0xE5, 0x13, 0xB3, 0xEF, 0x00, 0xE3, 0x96, 0xE0, 0xEE, 0x27, 0x89, 0xD4, 0xAB, 0xB1, 0x44, 0x88, 0xCD, 0x8F, 0x22, 0x27, 0xED, 0x85, 0x7D, 0x7D, 0xEE, 0x16, 0xC1, 0xD4, 0x67, 0xE6, 0x29, 0xD8, 0x0D, 0xBB, 0x95, 0x65, 0xD7, 0x7F, 0xCE, 0xE3, 0x8A, 0xB9, 0xCA, 0x23, 0xE4, 0xA1, 0x40, 0x8F, 0xD7, 0x5B, 0x7E, 0xC3, 0x9F, 0xE9, 0x5F, 0xAF, 0xC4, 0x18, 0xB7, 0xC1, 0x69, 0xB7, 0x5B, 0xB4, 0x1A, 0x7D, 0x87, 0xE6, 0x14, 0x89, 0x56, 0x03, 0x6A, 0xC0, 0xFE, 0x38, 0xBA, 0xEE, 0x0D, 0x98, 0xBD, 0xB6, 0x91, 0xEE, 0x80, 0xED, 0xB7, 0x78, 0x37, 0x04, 0x50, 0x05, 0x5C, 0xBE, 0x5D, 0x90, 0x6A, 0x64, 0x6E, 0x3C, 0xD2, 0x42, 0x0C, 0x46, 0x07, 0x3B, 0x61, 0x70, 0x92, 0x01, 0xC5, 0x2A, 0x37, 0x4B, 0x6B, 0x0B, 0x12, 0x57, 0xDB, 0xC9, 0xB0, 0xFA, 0xF1, 0x14, 0x16, 0x33, 0x6A, 0xBB, 0xDF, 0x8A, 0x7C, 0x69, 0xA0, 0xA6, 0x01, 0xD1, 0x02, 0x34, 0x81, 0x19, 0x9C, 0x39, 0xF2, 0x9B, 0x38, 0x97, 0xF9, 0x7D, 0x6B, 0x0C, 0x19, 0xD8, 0x63, 0x15, 0x34, 0x95, 0xAB, 0x9C, 0xED, 0x4F, 0x87, 0x5C, 0x0C, 0x66, 0xEC, 0xE7, 0x10, 0x7B, 0x3E, 0xE1, 0x02, 0xD6, 0xC7, 0x54, 0xB7, 0x82, 0x98, 0xFF, 0x93, 0xC8, 0x79, 0x1F, 0x71, 0x0C, 0x77, 0x03, 0x50, 0x62, 0xA2, 0x2D, 0x73, 0x4A, 0x4D, 0xD4, 0xB8, 0xD3, 0xD5, 0x1E, 0xCF, 0x58, 0x8B, 0x78, 0x4B, 0xFF, 0x25, 0x03, 0x9F, 0x68, 0x17, 0x47, 0x8C, 0xBF, 0x5D, 0x90, 0xBE, 0x51, 0x4B, 0xBD, 0x62, 0x0E, 0xFD, 0x4F, 0xF1, 0x16, 0x01, 0x5C, 0xDF, 0x64, 0xBB, 0x69, 0x36, 0xB1, 0xF6, 0x35, 0xC7, 0xEF, 0xE3, 0xF0, 0x9E, 0x93, 0xC3, 0x2D, 0x37, 0x35, 0x7E, 0x16, 0xA9, 0xB3, 0xB7, 0x15, 0xDC, 0x52, 0x91, 0xBF, 0x84, 0x2D, 0x1B, 0xFD, 0x96, 0x72, 0xD1, 0x4C, 0x44, 0x00, 0x73, 0x40, 0x0B, 0xB0, 0x05, 0x8C, 0x60, 0xE7, 0x02, 0x74, 0x01, 0xE5, 0x80, 0xF3, 0x94, 0x4E, 0x20, 0xE4, 0xFD, 0xE6, 0x6B, 0x9D, 0xA8, 0xED, 0xFF, 0x8A, 0x77, 0x4A, 0xC6, 0x89, 0xED, 0x42, 0x92, 0x47, 0xD3, 0x49, 0x77, 0x63, 0x2B, 0xB7, 0x93, 0xFD, 0xA0, 0xF6, 0x93, 0xD5, 0x97, 0xF6, 0xC9, 0xE5, 0xE8, 0x33, 0x77, 0x5D, 0xF7, 0xA3, 0xA1, 0x42, 0xF3, 0xA9, 0xB6, 0x9B, 0x86, 0xD8, 0xEA, 0xB7, 0x35, 0x92, 0x9F, 0x34, 0x95, 0xB1, 0x12, 0x5A, 0x3F, 0x70, 0xFD, 0x35, 0x7A, 0xB5, 0xCE, 0x33, 0x59, 0xCF, 0x42, 0x21, 0x64, 0x74, 0xB8, 0xC7, 0x57, 0x73, 0xF9, 0xDB, 0x04, 0xDA, 0xFA, 0x9B, 0xD8, 0x06, 0xC8, 0x02, 0x62, 0xC6, 0xBD, 0x03, 0x25, 0x40, 0x14, 0xA0, 0x63, 0x95, 0x91, 0x6F, 0x98, 0xBD, 0x18, 0x51, 0x3D, 0x51, 0x9B, 0x79, 0x2D, 0x93, 0x30, 0xD6, 0xFE, 0xED, 0x8E, 0x4A, 0x25, 0x3C, 0x06, 0xAC, 0x7E, 0x77, 0x8B, 0x2C, 0xFF, 0x2D, 0x92, 0x16, 0xBC, 0x9C, 0xAA, 0x30, 0x0E, 0xDD, 0xFE, 0x59, 0xC4, 0x1E, 0x36, 0xA5, 0xF8, 0x40, 0x06, 0x50, 0x4D, 0x24, 0xD0, 0xF1, 0xEA, 0x63, 0xFD, 0x7C, 0xE9, 0xDB, 0x4E, 0x45, 0xDE, 0x34, 0x71, 0xCA, 0xD9, 0xF6, 0x9B, 0x39, 0xF3, 0x9E, 0x8C, 0x4A, 0x88, 0x6D, 0xF2, 0xFE, 0xCE, 0x25, 0xEF, 0xB5, 0x65, 0x02, 0x9C, 0xBA, 0xFA, 0x24, 0x94, 0x98, 0xDE, 0x7D, 0x01, 0xCC, 0x7F, 0x26, 0x9F, 0xB6, 0x6E, 0xF5, 0xF9, 0x2D, 0x9B, 0x38, 0xFD, 0x8A, 0xFE, 0xA2, 0xA6, 0x8C, 0x1A, 0xF7, 0xF6, 0xAD, 0x31, 0x19, 0x94, 0x7C, 0x3A, 0x09, 0x06, 0x93, 0x20, 0x3B, 0x0C, 0xC6, 0x9F, 0xF8, 0x99, 0xFB, 0xF7, 0x69, 0x30, 0x79, 0xB7, 0xCA, 0x19, 0xAA, 0x8C, 0xCE, 0xDA, 0x33, 0x81, 0x03, 0x76, 0x01, 0xF2, 0x38, 0x9B, 0x60, 0x73, 0xEC, 0xA6, 0x9A, 0xCD, 0x3E, 0x2E, 0x37, 0x44, 0xC5, 0xC7, 0x4C, 0x92, 0x51, 0xE3, 0x8C, 0x6F, 0xCC, 0x71, 0x73, 0x62, 0x3F, 0xB5, 0xEC, 0xC0, 0xBD, 0xAF, 0xA5, 0x00, 0x3A, 0x01, 0xDA, 0xC0, 0x0E, 0xA2, 0x01, 0xD7, 0xF7, 0xDB, 0x0D, 0x07, 0x5C, 0x80, 0x73, 0xB3, 0x59, 0x80, 0x26, 0xE0, 0x8C, 0x9A, 0xE5, 0x89, 0x9A, 0xDD, 0x35, 0x14, 0x5A, 0xD3, 0xF4, 0x4F, 0x8B, 0xAF, 0x1B, 0x35, 0x77, 0x2B, 0xD6, 0x51, 0x27, 0x7A, 0x58, 0xD2, 0x08, 0xC6, 0xBE, 0x5D, 0x2B, 0xE7, 0xD6, 0x7B, 0x72, 0x90, 0x13, 0xE8, 0xB1, 0x0D, 0x2E, 0x60, 0x2B, 0xA0, 0x76, 0xF7, 0x48, 0xF0, 0x7C, 0x9C, 0xCC, 0xB3, 0x49, 0x63, 0x9B, 0x1E, 0xCD, 0x23, 0x1D, 0xCD, 0x32, 0xF6, 0xCE, 0x51, 0x28, 0x39, 0xD4, 0xF1, 0x62, 0xA8, 0x49, 0x90, 0x5F, 0x6F, 0x2B, 0xCB, 0x12, 0xC0, 0x08, 0x49, 0x62, 0x13, 0x06, 0x9C, 0xDE, 0x97, 0x09, 0xE4, 0xFE, 0x78, 0x9D, 0x9F, 0x89, 0x20, 0xA0, 0x0D, 0xC4, 0xFA, 0x3E, 0x43, 0xDB, 0x7F, 0x33, 0x16, 0x4D, 0xE6, 0xC2, 0xAC, 0x64, 0x65, 0x8C, 0xDE, 0x89, 0xAE, 0x86, 0x18, 0x64, 0x2C, 0x09, 0x7A, 0xDA, 0xF4, 0x33, 0xF3, 0x08, 0x70, 0x7F, 0xFE, 0xE1, 0x9C, 0x20, 0xAC, 0xD3, 0x82, 0x6D, 0x2D, 0x40, 0x03, 0x88, 0xE4, 0x43, 0x21, 0x19, 0x04, 0x6A, 0x64, 0xD3, 0x27, 0xB9, 0x9C, 0xB7, 0xB7, 0x11, 0xFA, 0x6D, 0x7A, 0xD6, 0xCC, 0xCF, 0xAE, 0x1D, 0xA9, 0xCE, 0x4E, 0xD6, 0xB1, 0x1F, 0x99, 0x3B, 0xFE, 0x29, 0x4E, 0x00, 0x54, 0x80, 0x1D, 0xC4, 0x22, 0x0C, 0x18, 0x85, 0x5E, 0x1C, 0xC8, 0x05, 0xB8, 0x03, 0x32, 0x12, 0x42, 0x02, 0xAA, 0xEF, 0x1B, 0x7C, 0x9F, 0xA8, 0x05, 0xB2, 0x8B, 0xAA, 0x20, 0xC2, 0x06, 0xF7, 0xE7, 0xDD, 0x9E, 0x1D, 0x63, 0x57, 0x65, 0xE6, 0x58, 0x50, 0xE7, 0xB7, 0xE9, 0xB8, 0xF5, 0xA6, 0x43, 0xEE, 0x93, 0x92, 0x71, 0x67, 0xFD, 0x93, 0x1B, 0xB5, 0x4F, 0x5F, 0x2B, 0x59, 0xC0, 0xF4, 0xDF, 0x9A, 0x22, 0x6D, 0x1F, 0x39, 0xCC, 0x11, 0xA6, 0x1D, 0xCC, 0xF0, 0x64, 0xB5, 0x65, 0x4D, 0x5B, 0x14, 0x2A, 0x18, 0x74, 0x1E, 0x24, 0x70, 0xE1, 0xB0, 0xE8, 0x92, 0x43, 0x74, 0xA4, 0xB9, 0xA2, 0x70, 0xBE, 0x81, 0xC5, 0x87, 0x74, 0x09, 0x90, 0x01, 0x94, 0x4E, 0xB5, 0xFC, 0xDB, 0xB0, 0x2B, 0x14, 0xF0, 0x05, 0x6C, 0x7D, 0xFB, 0x09, 0x6E, 0x07, 0x34, 0xE7, 0x2F, 0x4C, 0xD0, 0x12, 0x12, 0xDB, 0x9D, 0xD6, 0x46, 0xDC, 0xA1, 0xC6, 0xB7, 0x57, 0xE2, 0x26, 0xB3, 0x0B, 0xD3, 0x25, 0x95, 0xA7, 0x1E, 0xFB, 0x68, 0x1D, 0xCE, 0x91, 0x3E, 0xF3, 0x80, 0xE6, 0xFF, 0x6B, 0x7C, 0x7F, 0xCD, 0x2E, 0xF2, 0x58, 0x00, 0xE9, 0x35, 0x2D, 0xAE, 0x13, 0x03, 0xBB, 0xD5, 0xD2, 0x96, 0xA7, 0x44, 0x75, 0x31, 0xBF, 0xA8, 0x26, 0x39, 0x9B, 0x7A, 0x6F, 0xAD, 0x9B, 0x8C, 0x15, 0x7F, 0x11, 0xE1, 0xB0, 0x9D, 0x41, 0x9C, 0xFE, 0x66, 0xE5, 0xF7, 0x02, 0x4A, 0x88, 0xE9, 0xDF, 0xD6, 0xA3, 0x75, 0x02, 0x4E, 0x98, 0x02, 0x8B, 0xA7, 0xB8, 0x00, 0x9B, 0xD0, 0xEB, 0x0D, 0x83, 0xA0, 0xD5, 0xAF, 0x83, 0x83, 0x49, 0x42, 0x89, 0xDC, 0x7E, 0x67, 0xBC, 0x6A, 0x1E, 0xBF, 0xBB, 0x83, 0x6F, 0x43, 0xE1, 0xD4, 0xDC, 0xED, 0xD1, 0x1F, 0x43, 0x67, 0xDE, 0x61, 0xE7, 0xAE, 0x96, 0x54, 0x24, 0x66, 0xE2, 0x5D, 0x40, 0x2A, 0x10, 0x0D, 0xB8, 0x01, 0x16, 0x2F, 0xC6, 0x1D, 0x7F, 0xFC, 0xCB, 0xD5, 0xDE, 0x5C, 0xE4, 0x29, 0x17, 0x9A, 0x07, 0x8B, 0xDD, 0xBB, 0x21, 0x0A, 0x8B, 0x80, 0xB5, 0x3F, 0x8D, 0x51, 0xED, 0xE2, 0x3E, 0x3A, 0x37, 0xB1, 0x08, 0x7D, 0x6F, 0x6E, 0x53, 0x37, 0x23, 0x0E, 0x6C, 0xE7, 0x8B, 0x0A, 0xD8, 0x7E, 0x9F, 0xA0, 0x2A, 0xF7, 0x21, 0x8B, 0xA8, 0xF5, 0x2F, 0x6A, 0x5A, 0x86, 0xAD, 0xBE, 0x89, 0x1A, 0x43, 0x50, 0x4D, 0xCB, 0x7A, 0x17, 0x96, 0x85, 0xE8, 0xEF, 0x77, 0x5A, 0xE6, 0x2F, 0x5A, 0xFB, 0x6B, 0x39, 0x34, 0xFF, 0xBE, 0x4F, 0x9C, 0x0C, 0xE8, 0x0F, 0x4A, 0x89, 0x79, 0x71, 0x9E, 0x5A, 0xB3, 0x2D, 0x3C, 0xE1, 0x1A, 0x79, 0x56, 0x17, 0x10, 0x93, 0xBD, 0x3C, 0xF7, 0xC6, 0x9E, 0xF5, 0x05, 0xF7, 0xF3, 0x5E, 0x0F, 0x28, 0x1D, 0x6C, 0x60, 0xFB, 0x1B, 0xA7, 0x12, 0x20, 0x1B, 0x28, 0x7D, 0xE3, 0x9B, 0x13, 0x2E, 0x05, 0xD6, 0x7E, 0xBF, 0x6B, 0x5D, 0xC0, 0x3A, 0x61, 0xE6, 0x29, 0x7C, 0x16, 0xC8, 0x5A, 0x58, 0x9A, 0x8A, 0x28, 0xDA, 0x54, 0x57, 0xFF, 0x66, 0x6B, 0xBD, 0x9F, 0x0E, 0xC6, 0x22, 0xEA, 0x70, 0xB5, 0xDF, 0x8D, 0x99, 0x8D, 0xE2, 0x09, 0x2A, 0x13, 0x35, 0xFD, 0xF4, 0xE2, 0x8D, 0x78, 0xFF, 0x8D, 0x30, 0xA2, 0x00, 0x1F, 0xF8, 0x7B, 0xD4, 0x7D, 0x73, 0x92, 0xF7, 0xFA, 0xBB, 0xE0, 0x0A, 0x98, 0x74, 0x67, 0xBF, 0xF3, 0xD8, 0x3C, 0xBA, 0x65, 0xC4, 0xDB, 0x37, 0x40, 0xD7, 0xA7, 0x5C, 0x28, 0x09, 0x23, 0x9C, 0x28, 0x60, 0x1B, 0xE0, 0xD3, 0xFD, 0xD6, 0x81, 0xDC, 0x80, 0x27, 0x20, 0x7C, 0x43, 0x12, 0xDA, 0x80, 0x37, 0x4F, 0xD9, 0x27, 0x6A, 0x1B, 0x05, 0x92, 0xD9, 0x74, 0x99, 0xC7, 0x46, 0x57, 0x41, 0x71, 0xAC, 0xB5, 0x92, 0xCD, 0x38, 0x85, 0x36, 0xE2, 0xC9, 0x5D, 0xF0, 0x18, 0x17, 0xEA, 0xAF, 0xEF, 0xF9, 0x5B, 0x91, 0x67, 0xC5, 0x20, 0x64, 0x4C, 0x11, 0x2D, 0x50, 0x0B, 0xE8, 0x49, 0x84, 0x99, 0x5D, 0x94, 0x9C, 0xBC, 0xFB, 0xA9, 0xE7, 0x9A, 0xA5, 0xD3, 0x75, 0x0A, 0x58, 0xF4, 0x6C, 0xF1, 0x53, 0xEE, 0x9E, 0xEB, 0x0E, 0x47, 0x0C, 0x0C, 0x26, 0x77, 0xCD, 0x2F, 0x03, 0xF6, 0x1C, 0x19, 0x11, 0x9F, 0x9F, 0x15, 0x10, 0x5C, 0xD2, 0x1A, 0xD1, 0x0A, 0xD4, 0x06, 0x8C, 0xEF, 0x6B, 0x05, 0xDC, 0x1E, 0x7F, 0x76, 0x00, 0x51, 0x93, 0xFF, 0xA2, 0x90, 0x14, 0xB9, 0x9B, 0xA6, 0xF1, 0xEC, 0xC4, 0x7E, 0x1F, 0x06, 0x16, 0xC5, 0xFA, 0x63, 0xC3, 0x5F, 0x58, 0xCD, 0xFD, 0xA8, 0x6F, 0x26, 0x8C, 0x5C, 0xCD, 0x7A, 0x22, 0x73, 0x2D, 0xE0, 0xF6, 0x06, 0x3C, 0x80, 0x28, 0xA0, 0xC6, 0xF1, 0xFC, 0x69, 0xF4, 0x86, 0xA4, 0xDA, 0xDB, 0xE8, 0x0F, 0x67, 0x2A, 0xD7, 0xAB, 0x92, 0x3C, 0x45, 0xCE, 0x66, 0x5E, 0x08, 0x3F, 0x2F, 0xB1, 0x0C, 0xD8, 0x49, 0x14, 0xB0, 0x1A, 0xD8, 0x9B, 0x70, 0x40, 0x88, 0x51, 0x92, 0xA7, 0xF5, 0xEA, 0x3A, 0xF6, 0x33, 0x40, 0x2C, 0x60, 0xCD, 0x1E, 0x99, 0x03, 0x55, 0x3C, 0xA5, 0x27, 0x6A, 0x0A, 0xD1, 0x49, 0x02, 0x56, 0x31, 0xAB, 0x7E, 0xB9, 0x1D, 0x85, 0x2D, 0x81, 0x88, 0x2E, 0xB4, 0xA9, 0x0C, 0x41, 0xB4, 0x61, 0xA5, 0x60, 0x8D, 0xCA, 0xD0, 0x9C, 0x95, 0x41, 0xC4, 0x8C, 0xB5, 0x7D, 0xFB, 0xA1, 0xE4, 0x59, 0x0E, 0xE6, 0x28, 0x61, 0x1B, 0x30, 0x03, 0x5C, 0x3E, 0x8D, 0x5F, 0xD4, 0x39, 0x04, 0x38, 0x8F, 0xF0, 0xE9, 0x84, 0x97, 0x8C, 0xD3, 0x74, 0xE6, 0xE5, 0xCF, 0x94, 0x41, 0x38, 0x85, 0x6A, 0xCD, 0xAE, 0xED, 0xEF, 0x82, 0xD3, 0x05, 0xB0, 0x0D, 0x08, 0xB1, 0x93, 0x08, 0x40, 0x1E, 0x8D, 0xFD, 0xAE, 0x42, 0x37, 0x10, 0x39, 0x2F, 0xBE, 0xD5, 0x59, 0x96, 0x40, 0xD4, 0xED, 0x8B, 0x80, 0xA8, 0x19, 0x7A, 0x37, 0x55, 0x62, 0xE3, 0xAE, 0xF7, 0x4F, 0x8E, 0x53, 0xE7, 0x3C, 0x36, 0xF6, 0x46, 0x21, 0x63, 0x05, 0x52, 0x2F, 0x76, 0xA0, 0x81, 0x90, 0x7D, 0x16, 0x54, 0xF2, 0x59, 0x86, 0x56, 0xBE, 0x0E, 0x74, 0x5E, 0x40, 0x0A, 0xB1, 0x89, 0x78, 0x6B, 0x1D, 0x4F, 0x6A, 0xC3, 0xF5, 0x5A, 0x42, 0x19, 0xDC, 0x06, 0x7A, 0x5F, 0x3F, 0xFE, 0x19, 0x03, 0x32, 0x4F, 0x85, 0x66, 0xBC, 0x56, 0xBE, 0x4D, 0xB7, 0xB7, 0x00, 0x6A, 0x84, 0x12, 0x41, 0x14, 0x60, 0x01, 0x94, 0x7F, 0x7C, 0xFB, 0x18, 0xAF, 0x16, 0x60, 0x42, 0xBA, 0xFA, 0xF5, 0xB2, 0x6C, 0xE3, 0x29, 0x7E, 0xC2, 0xE6, 0xA8, 0x37, 0xA0, 0xEB, 0xCB, 0xCA, 0xF8, 0x2D, 0x0D, 0xB2, 0x1C, 0xCB, 0xB9, 0x8A, 0xDF, 0xE8, 0xD0, 0x4C, 0xEC, 0xE4, 0x15, 0x34, 0xB7, 0x85, 0x09, 0x70, 0xD4, 0xB7, 0xC9, 0xF8, 0xDC, 0xD8, 0x62, 0xA4, 0xFF, 0x27, 0xAB, 0x05, 0xD9, 0x50, 0x2F, 0x36, 0xB0, 0x0A, 0xF0, 0x5B, 0xD8, 0x8D, 0x3D, 0x9C, 0x51, 0xCF, 0x37, 0xE0, 0xD3, 0x17, 0x65, 0xE6, 0xA0, 0x7A, 0x73, 0xDD, 0x28, 0xBB, 0xD6, 0xDB, 0x98, 0xFE, 0xA9, 0x7E, 0x11, 0xC0, 0x08, 0x1F, 0xC4, 0x47, 0x27, 0x5D, 0x01, 0xD4, 0xE6, 0x54, 0xA7, 0x80, 0xED, 0xF3, 0x22, 0xA0, 0xA3, 0x38, 0xCE, 0x2A, 0x47, 0x79, 0xCA, 0x9E, 0xA8, 0x05, 0xB6, 0xAA, 0xBA, 0x7E, 0xBF, 0xB3, 0x98, 0x75, 0x1F, 0x5B, 0xDF, 0x64, 0xB5, 0x69, 0x8D, 0xEA, 0x45, 0x9B, 0x2A, 0xE3, 0x6E, 0x14, 0x2B, 0x8C, 0x01, 0x8B, 0x3B, 0x9A, 0xB6, 0xFD, 0xB9, 0x50, 0x8E, 0xD2, 0xAD, 0x08, 0xC1, 0xDE, 0x80, 0x0A, 0xE0, 0xB8, 0xFD, 0xF3, 0x67, 0x18, 0x08, 0x47, 0x2F, 0xB7, 0x9C, 0x05, 0xC2, 0xA4, 0x97, 0x9D, 0x64, 0xD9, 0x3D, 0xDE, 0x3C, 0xC1, 0x05, 0xEA, 0x64, 0x87, 0x8C, 0xDB, 0x10, 0x31, 0x6D, 0x7E, 0x8B, 0x88, 0x89, 0x7C, 0x10, 0x02, 0x84, 0xF0, 0x0D, 0x1B, 0x68, 0xFE, 0x16, 0x73, 0x40, 0x8A, 0x2F, 0x2E, 0x00, 0xBF, 0x5A, 0xCE, 0xD1, 0x92, 0xD9, 0x5F, 0x9B, 0x98, 0x61, 0x76, 0x1B, 0x7B, 0x63, 0x83, 0x4C, 0x1A, 0x75, 0x0B, 0xDE, 0xBF, 0xBB, 0xC4, 0xDA, 0x1B, 0x51, 0x72, 0x38, 0xF0, 0x6B, 0x6C, 0xA6, 0x3A, 0xD6, 0x2C, 0xD5, 0xDF, 0x95, 0x41, 0xDE, 0xB9, 0xEA, 0x56, 0xAE, 0x64, 0x72, 0x3A, 0xBC, 0xF0, 0xA8, 0x4F, 0x0B, 0xE1, 0xF5, 0x35, 0x7E, 0xE1, 0x66, 0x5F, 0xC7, 0x75, 0x2B, 0x12, 0xAA, 0xDF, 0x76, 0xB2, 0x63, 0x85, 0xAB, 0x06, 0x9B, 0xF6, 0x15, 0x71, 0xC3, 0xB4, 0x4E, 0x8F, 0x6D, 0xF7, 0xB1, 0x69, 0x05, 0x64, 0x56, 0x0D, 0x06, 0xA4, 0x02, 0xD1, 0x40, 0xC6, 0xA4, 0xB5, 0x02, 0x4D, 0x1D, 0xCA, 0x36, 0xA0, 0x67, 0x23, 0x08, 0xF0, 0x0D, 0xEC, 0x00, 0x34, 0x79, 0x8A, 0x4F, 0xD0, 0x0A, 0x1D, 0x13, 0x45, 0x91, 0x43, 0xDC, 0x1B, 0x56, 0x05, 0x05, 0x57, 0xC3, 0xF4, 0x42, 0xB0, 0xAB, 0xD8, 0x8B, 0x59, 0x31, 0x60, 0x90, 0x0C, 0x23, 0xC6, 0xA0, 0xF5, 0x3F, 0x5A, 0xA4, 0xE6, 0xA9, 0xC2, 0x1C, 0x4F, 0x31, 0xF1, 0x29, 0x7F, 0x01, 0xF6, 0x22, 0x14, 0x08, 0xCA, 0xDD, 0xC6, 0x47, 0x66, 0x21, 0x5A, 0x0C, 0x1A, 0x76, 0xE6, 0x99, 0xD7, 0xCA, 0x9A, 0xCC, 0xBE, 0xC9, 0x22, 0x7E, 0xE4, 0x49, 0x99, 0xC6, 0xEF, 0xD3, 0xA9, 0x44, 0x01, 0x77, 0x40, 0x9A, 0xF0, 0x17, 0x4A, 0x64, 0xBF, 0xC3, 0xAF, 0x1D, 0x28, 0xC2, 0x89, 0xBD, 0xDF, 0x33, 0xD7, 0x9C, 0xD9, 0x13, 0xB4, 0x66, 0x0F, 0x85, 0x91, 0xBB, 0xF9, 0x7F, 0xEE, 0xC2, 0x92, 0xA9, 0x3A, 0xB0, 0x45, 0xE6, 0x41, 0x39, 0xD5, 0xB1, 0x0A, 0xD4, 0x75, 0x33, 0x3B, 0x96, 0x02, 0x61, 0x73, 0x9F, 0x7D, 0xEE, 0xE4, 0xB8, 0x9D, 0xB0, 0xC1, 0xEF, 0x24, 0x45, 0x01, 0xC9, 0x81, 0xB3, 0x04, 0x60, 0xC9, 0x0A, 0xA3, 0xC5, 0x59, 0x87, 0xF7, 0xB8, 0x93, 0x73, 0xE3, 0x7B, 0x5E, 0x9C, 0xDE, 0x14, 0x76, 0xAC, 0xC0, 0xB3, 0x26, 0x51, 0x87, 0xBF, 0xF3, 0x0C, 0x54, 0x60, 0xE5, 0xC8, 0x84, 0x80, 0x16, 0x61, 0x80, 0x05, 0xD0, 0xF1, 0xF6, 0xE4, 0x95, 0x04, 0xCE, 0x0D, 0x80, 0xB0, 0x0D, 0x2C, 0x07, 0xE6, 0x14, 0x2D, 0x06, 0x6D, 0x63, 0xC7, 0x40, 0x1C, 0xEB, 0x82, 0x28, 0x6A, 0xBA, 0x7C, 0x28, 0x45, 0xFB, 0x6F, 0xFB, 0x7B, 0xD3, 0x56, 0x5E, 0xA5, 0xE0, 0x1D, 0xEA, 0xFA, 0x0B, 0x68, 0x7F, 0x2B, 0xDA, 0xF7, 0x1A, 0x37, 0x83, 0xD7, 0x60, 0xB4, 0x3F, 0xBB, 0x45, 0x99, 0x84, 0x11, 0x75, 0xF3, 0xB8, 0x21, 0xA5, 0x4D, 0xEA, 0xC2, 0x9D, 0x5C, 0xDA, 0xE9, 0x99, 0x3E, 0xF7, 0xE7, 0xDB, 0xBD, 0xED, 0x9A, 0x0A, 0xAC, 0x00, 0xB6, 0x00, 0x63, 0xBF, 0x6C, 0x0B, 0x70, 0x03, 0x42, 0x89, 0x04, 0xD2, 0xDF, 0x07, 0x6D, 0xBD, 0x56, 0xC5, 0xE7, 0xC5, 0x6C, 0x40, 0x1D, 0x58, 0x1B, 0x90, 0x11, 0xA3, 0x6A, 0x4D, 0xD4, 0x36, 0x76, 0xE1, 0x45, 0x90, 0x71, 0x53, 0x7D, 0xA3, 0x56, 0x5D, 0xEC, 0x4F, 0xBF, 0x69, 0x36, 0x11, 0x01, 0x5D, 0x0F, 0x9E, 0x13, 0x26, 0xEB, 0xBB, 0x72, 0x37, 0x46, 0x6D, 0xE4, 0xBE, 0xFD, 0x89, 0xD3, 0x06, 0xFC, 0xB3, 0x22, 0xD6, 0x04, 0x5E, 0xEB, 0x09, 0x4C, 0xCE, 0xF8, 0x70, 0x7B, 0x73, 0x17, 0xBA, 0x18, 0x04, 0x46, 0x46, 0x3E, 0x6D, 0x16, 0x37, 0xA1, 0x32, 0x8B, 0x48, 0x40, 0x9D, 0x28, 0xC0, 0x36, 0xE1, 0x80, 0x6F, 0x60, 0xD6, 0x64, 0x6E, 0x40, 0x07, 0x50, 0xFE, 0xBE, 0xB8, 0xEA, 0xD5, 0xEF, 0xDB, 0xEF, 0x29, 0x88, 0x9A, 0xC0, 0x9B, 0xC3, 0x03, 0xB9, 0xF7, 0x46, 0x17, 0x71, 0xC3, 0xD4, 0x56, 0xCC, 0xF1, 0xF4, 0x4D, 0xC7, 0x52, 0xD0, 0x1D, 0xFD, 0x14, 0x43, 0xEF, 0x3E, 0xCB, 0x35, 0xA6, 0x1E, 0xC9, 0xF4, 0xD3, 0x22, 0xB0, 0x14, 0xE8, 0x06, 0x6A, 0x20, 0x17, 0x79, 0x72, 0xE2, 0x25, 0x66, 0x71, 0x34, 0xFD, 0xF2, 0xF9, 0xFC, 0xD5, 0xE9, 0x7E, 0x65, 0x77, 0xAD, 0x23, 0x7F, 0x8D, 0xFF, 0x72, 0xA6, 0x4E, 0x33, 0x9F, 0xC1, 0x8B, 0x36, 0xB9, 0x6C, 0x0A, 0xA4, 0x00, 0x1D, 0x9C, 0xE2, 0x39, 0xB0, 0x13, 0x70, 0xAA, 0x44, 0x1A, 0x40, 0x29, 0x90, 0x0B, 0x50, 0xBE, 0xA1, 0x14, 0xB0, 0x00, 0xE6, 0x1F, 0xF4, 0x98, 0xA8, 0x29, 0x1C, 0xFC, 0x5D, 0x68, 0x98, 0x67, 0xEC, 0x29, 0xF1, 0xEA, 0x91, 0xB6, 0x13, 0xB7, 0xD1, 0x59, 0xBF, 0x28, 0x5C, 0x35, 0x47, 0xC5, 0xCD, 0x6F, 0x9F, 0x37, 0x1B, 0x43, 0xED, 0x59, 0x3F, 0x2D, 0x06, 0x61, 0x35, 0x30, 0xCF, 0xA2, 0x56, 0x20, 0x1C, 0x98, 0x49, 0xFF, 0x38, 0x3C, 0x16, 0xB3, 0x03, 0xB7, 0x02, 0xDE, 0x6F, 0x6E, 0x9B, 0x18, 0x45, 0x35, 0xB9, 0x6F, 0x9F, 0xDD, 0xFA, 0x38, 0x6D, 0xC5, 0x72, 0x52, 0xA3, 0x15, 0xA8, 0x71, 0x38, 0x57, 0xC0, 0x89, 0x9C, 0x6D, 0xD5, 0xF5, 0xD1, 0x48, 0x15, 0x08, 0x62, 0x1E, 0x22, 0xA9, 0x80, 0x12, 0x6E, 0x3C, 0xE5, 0x44, 0xCD, 0xE0, 0x66, 0x3F, 0x15, 0xF2, 0x02, 0x9B, 0xEA, 0xCC, 0xD7, 0x15, 0x26, 0x8B, 0x15, 0x2C, 0x18, 0x80, 0x56, 0xA2, 0x73, 0x3F, 0x7B, 0x57, 0x53, 0xA3, 0x38, 0xAC, 0xB9, 0x43, 0x1C, 0x0F, 0x09, 0x42, 0xFA, 0x71, 0xD6, 0x99, 0x2C, 0xB3, 0x58, 0x40, 0xFA, 0x5B, 0x2B, 0x76, 0xB6, 0xFD, 0x44, 0x01, 0x8D, 0x2B, 0x61, 0xB2, 0x29, 0xC6, 0xE4, 0x31, 0xDC, 0x5D, 0x3C, 0xBD, 0x8D, 0xBA, 0xB1, 0x72, 0xE1, 0x28, 0x99, 0xD5, 0xF9, 0xA4, 0x41, 0x2B, 0xA0, 0x84, 0xCB, 0xEB, 0xCA, 0xD9, 0x94, 0x71, 0x2D, 0x00, 0x9D, 0x17, 0x13, 0xB0, 0x19, 0x25, 0x85, 0xA3, 0x49, 0x24, 0x93, 0x13, 0x35, 0xC7, 0x0D, 0x2D, 0x1B, 0x63, 0xCD, 0xFD, 0x27, 0xEA, 0xFA, 0xDA, 0x70, 0xCF, 0xE1, 0xC0, 0x55, 0x33, 0xFC, 0xF3, 0x26, 0x58, 0x78, 0x28, 0x56, 0x5A, 0x47, 0x5B, 0xCB, 0xCF, 0xFE, 0x71, 0x9C, 0x02, 0x1E, 0x86, 0xC4, 0x26, 0x6A, 0x06, 0xE8, 0x22, 0x36, 0x21, 0xC0, 0x28, 0x15, 0x96, 0x0C, 0x17, 0x67, 0x15, 0xE9, 0x37, 0xC7, 0xDE, 0x98, 0x4E, 0xB9, 0x39, 0x93, 0xCF, 0xD9, 0x77, 0xBE, 0x0E, 0xB9, 0xC0, 0xAC, 0x64, 0x65, 0x03, 0xE9, 0x40, 0xDB, 0x67, 0x01, 0x9F, 0x80, 0x04, 0x90, 0x0C, 0x9E, 0x6F, 0xA0, 0x03, 0x28, 0x7D, 0xBB, 0x1D, 0xB6, 0x01, 0x4E, 0xCC, 0x1B, 0xC2, 0x26, 0x6A, 0x01, 0x13, 0x2F, 0x6D, 0xF4, 0xF0, 0x4A, 0x65, 0x5A, 0x73, 0xBC, 0xBE, 0x4D, 0xD1, 0x14, 0xD4, 0x0D, 0x45, 0xA0, 0x76, 0x77, 0xDB, 0xEF, 0x33, 0x54, 0xF6, 0xBB, 0xEB, 0x6E, 0xC1, 0xBB, 0x55, 0x02, 0x11, 0x84, 0x01, 0x5E, 0x44, 0xCC, 0x70, 0x34, 0x7E, 0xEC, 0xBA, 0x29, 0xA2, 0x3A, 0xF5, 0xF7, 0x67, 0xDE, 0x74, 0xEC, 0x2E, 0x46, 0x4F, 0xD2, 0x1B, 0x66, 0x7A, 0x33, 0x5D, 0x31, 0xFB, 0xF8, 0x7F, 0x28, 0x30, 0x3B, 0xCD, 0xEA, 0x80, 0xCB, 0xA7, 0xA7, 0xA0, 0xBF, 0x6D, 0xE6, 0x22, 0x01, 0x27, 0x66, 0xFE, 0x1B, 0x0A, 0x88, 0x00, 0x66, 0x3C, 0x45, 0x27, 0x6A, 0x89, 0xCC, 0x1B, 0x67, 0xB3, 0x32, 0x37, 0xB6, 0x12, 0x9A, 0xA8, 0x31, 0xBE, 0x39, 0xE9, 0x4D, 0x8A, 0x7F, 0x57, 0xE4, 0x2E, 0x0C, 0xD2, 0xFF, 0x59, 0x39, 0xAB, 0x71, 0x15, 0xC5, 0x29, 0xBD, 0x60, 0xB5, 0xCD, 0x5C, 0x14, 0xF7, 0x45, 0xB1, 0xD7, 0xC9, 0x5A, 0xE7, 0x7E, 0xF6, 0xC3, 0x3E, 0x9B, 0x04, 0xCD, 0xA5, 0xD2, 0xB4, 0x12, 0xE8, 0x79, 0x9F, 0xCF, 0xDC, 0xE4, 0x1D, 0x55, 0x35, 0x2D, 0x0C, 0x89, 0x9A, 0x44, 0xA3, 0x02, 0x76, 0x03, 0x2A, 0x40, 0x6D, 0x06, 0x66, 0x62, 0x97, 0xC0, 0x29, 0x73, 0x58, 0xC0, 0x2E, 0x46, 0xD9, 0x81, 0xBE, 0xA7, 0x20, 0x68, 0x85, 0x4E, 0x28, 0xE2, 0xA8, 0x02, 0xEF, 0x86, 0x73, 0xFC, 0xDD, 0x75, 0x41, 0xFB, 0x9F, 0xC2, 0xA0, 0x80, 0xD9, 0x55, 0x77, 0x43, 0xC6, 0x3D, 0x17, 0xE8, 0xD7, 0x03, 0x7D, 0xCF, 0x52, 0xD4, 0xDE, 0xC7, 0xE4, 0x12, 0x1E, 0x25, 0x90, 0x9F, 0x59, 0x54, 0xEB, 0xD5, 0x67, 0xF0, 0x98, 0x7E, 0x13, 0x96, 0xE7, 0xDA, 0x98, 0x24, 0xEF, 0x36, 0x1A, 0xC1, 0xDF, 0xBD, 0x35, 0x0C, 0x23, 0x6A, 0x26, 0xB7, 0xB0, 0x14, 0x46, 0x01, 0xEF, 0xE3, 0x95, 0x10, 0x03, 0x34, 0x80, 0xDA, 0x9F, 0x02, 0xDC, 0xBD, 0x71, 0xD4, 0x0D, 0x84, 0x01, 0xAB, 0xC7, 0xBC, 0xFF, 0x87, 0x93, 0xB2, 0x52, 0x3D, 0x51, 0x6B, 0xD8, 0x2A, 0xEC, 0x42, 0xB9, 0x9E, 0x31, 0x11, 0x13, 0xC9, 0x44, 0x52, 0xB5, 0x21, 0x8F, 0x64, 0xE0, 0x0F, 0x45, 0x40, 0x28, 0xF6, 0xFC, 0x45, 0x6D, 0x4D, 0xD4, 0xE6, 0x02, 0x9D, 0x4D, 0x8A, 0x99, 0x5F, 0x8E, 0xB8, 0x95, 0xFD, 0x6E, 0x53, 0xB6, 0x02, 0x99, 0x80, 0x17, 0x90, 0x73, 0x29, 0x17, 0xA3, 0x16, 0xF1, 0x5A, 0xB8, 0x37, 0x2F, 0xBB, 0xA2, 0x16, 0x91, 0x8C, 0xDA, 0xB3, 0x69, 0x89, 0x0C, 0x92, 0x27, 0x6A, 0x3E, 0x96, 0x64, 0x01, 0xD8, 0x06, 0x3C, 0x81, 0xF0, 0x8F, 0x00, 0x93, 0x9F, 0x58, 0x28, 0xB1, 0x11, 0xA7, 0xD1, 0x4C, 0x6C, 0x82, 0xCE, 0x23, 0xE9, 0x53, 0x3D, 0xC1, 0xA8, 0x4D, 0xDF, 0xF6, 0x15, 0xDC, 0x04, 0x74, 0xD4, 0x62, 0xF5, 0x6B, 0x4C, 0x5D, 0xED, 0x28, 0x01, 0xCA, 0xA0, 0xC3, 0xC1, 0x4D, 0xFA, 0xBE, 0x9D, 0x18, 0xFD, 0xD9, 0x2F, 0x99, 0xD4, 0x48, 0x3B, 0xFE, 0xE1, 0xDE, 0x40, 0x27, 0x90, 0x01, 0xF8, 0x02, 0xCA, 0xA7, 0xB8, 0xFC, 0x66, 0xC5, 0x70, 0x6F, 0xCE, 0x9C, 0xB6, 0xD1, 0xFB, 0xA4, 0x0E, 0xD6, 0xB5, 0x70, 0x97, 0x3A, 0xB5, 0x58, 0x99, 0x80, 0xD9, 0x6B, 0x19, 0x27, 0x0D, 0x04, 0xD1, 0x3D, 0xC5, 0xEC, 0x80, 0x04, 0x30, 0x26, 0x45, 0x31, 0xF3, 0x1C, 0x62, 0x19, 0x5F, 0xEC, 0x7F, 0x54, 0xB8, 0x77, 0xF1, 0x14, 0x9F, 0xA0, 0xED, 0xDF, 0x95, 0x39, 0xCF, 0xA5, 0xDC, 0x85, 0x5A, 0x6F, 0x49, 0xE8, 0x79, 0x7B, 0xD3, 0x19, 0x3F, 0x50, 0x56, 0x90, 0x85, 0x61, 0x10, 0x79, 0x5C, 0x3A, 0xE0, 0x9D, 0x39, 0x1B, 0xA1, 0xD3, 0xC2, 0x62, 0xE4, 0x8E, 0x69, 0x8B, 0x3B, 0xB7, 0xAC, 0xA4, 0xEA, 0xE1, 0xC0, 0x26, 0x64, 0x03, 0x47, 0xCF, 0x49, 0xFE, 0xA3, 0x89, 0xF8, 0x4C, 0x59, 0xC2, 0x38, 0x26, 0x89, 0x8C, 0xCF, 0xF4, 0x78, 0x11, 0xF3, 0x0D, 0x53, 0xD8, 0xE1, 0x6F, 0x7A, 0xD2, 0x6A, 0x40, 0x17, 0x61, 0x73, 0x0A, 0xD1, 0x40, 0x08, 0x9F, 0xC6, 0x05, 0xCC, 0x5F, 0x97, 0x04, 0x76, 0xF2, 0xC5, 0x06, 0x4C, 0x81, 0xBD, 0x3E, 0xB3, 0xBB, 0x98, 0xA0, 0x09, 0xD6, 0xEA, 0xED, 0x2C, 0x8A, 0x80, 0x0F, 0x4C, 0x61, 0xDA, 0x61, 0xF8, 0xD5, 0x0E, 0xCB, 0x65, 0x29, 0x44, 0x12, 0x21, 0xD0, 0xF1, 0x69, 0x9A, 0x99, 0xEE, 0x75, 0xF3, 0x46, 0x28, 0x19, 0x58, 0xFE, 0xA5, 0xE2, 0x07, 0x6C, 0xA0, 0x0C, 0x08, 0x42, 0x03, 0xF0, 0xE6, 0x98, 0x7C, 0xBE, 0x79, 0x9F, 0xD8, 0x31, 0x5A, 0x3A, 0x3E, 0xEE, 0x47, 0x51, 0xCB, 0x11, 0x95, 0x26, 0x87, 0xCD, 0x80, 0xE8, 0xEB, 0xB5, 0x3E, 0x05, 0x33, 0xD0, 0xC3, 0x9F, 0x76, 0x82, 0x62, 0x80, 0xD5, 0xEB, 0x9E, 0x50, 0x74, 0x64, 0x91, 0xFC, 0x74, 0x15, 0x74, 0xC0, 0x05, 0x10, 0x07, 0x6C, 0x64, 0x99, 0x13, 0x34, 0x65, 0x23, 0x40, 0x45, 0x17, 0x99, 0x62, 0xBF, 0xD4, 0x95, 0xC8, 0xD8, 0xCB, 0x40, 0xBA, 0x58, 0x17, 0x8A, 0xC1, 0x75, 0xE3, 0xE1, 0x26, 0xBF, 0x91, 0x56, 0xC6, 0x7B, 0x19, 0x11, 0x75, 0x73, 0x20, 0x45, 0xF9, 0xBF, 0xE8, 0x49, 0x30, 0x58, 0x09, 0xB4, 0x13, 0x0B, 0x18, 0x2F, 0xCE, 0xF5, 0x14, 0x91, 0x73, 0x9A, 0xE0, 0x54, 0x67, 0x5C, 0x8F, 0x26, 0x99, 0x8E, 0x9F, 0xC9, 0xE2, 0x99, 0xCD, 0x78, 0x52, 0x3A, 0x19, 0x7D, 0x23, 0x09, 0x23, 0xA6, 0x3D, 0x6B, 0x25, 0x61, 0x84, 0x03, 0x1D, 0xAF, 0x00, 0xB3, 0x1A, 0x70, 0x01, 0x8C, 0x90, 0x8D, 0x53, 0xCA, 0x80, 0x98, 0x23, 0xFE, 0xBD, 0xA8, 0x89, 0x99, 0xB1, 0xCD, 0xDB, 0xDC, 0xC4, 0xC6, 0x51, 0x21, 0x78, 0x44, 0x41, 0x95, 0x3B, 0xA4, 0x96, 0x9B, 0x7E, 0x03, 0xBF, 0xE8, 0x8E, 0xBD, 0xB2, 0x36, 0xD0, 0x76, 0x67, 0xFA, 0xC2, 0x85, 0x91, 0xE9, 0xA9, 0x13, 0x17, 0xC1, 0x67, 0x97, 0x22, 0x36, 0xB0, 0x0C, 0x70, 0x46, 0x29, 0xE5, 0x56, 0x17, 0xD2, 0xE9, 0x64, 0x5C, 0x57, 0x83, 0xF7, 0x94, 0xC0, 0x56, 0x2E, 0x1D, 0x75, 0xF1, 0x86, 0xE0, 0xEF, 0xAC, 0x1F, 0xA8, 0x22, 0x1A, 0x56, 0xFD, 0xB8, 0x4A, 0x04, 0xD0, 0x00, 0xC4, 0x80, 0xDD, 0x80, 0x10, 0xC5, 0x0F, 0x36, 0xBD, 0x09, 0x97, 0xE0, 0xA8, 0x89, 0x08, 0x60, 0xDE, 0xD7, 0xCD, 0x10, 0x5C, 0xEF, 0x5D, 0xC4, 0xCC, 0xD9, 0x6D, 0x37, 0x91, 0x0A, 0xE8, 0x01, 0xF5, 0x68, 0x09, 0x55, 0x02, 0x85, 0x55, 0x83, 0x8C, 0xF2, 0x46, 0x49, 0x52, 0xDF, 0x71, 0x96, 0x40, 0x2E, 0x8E, 0xB3, 0xBC, 0x95, 0x11, 0x0A, 0xA5, 0x18, 0x43, 0xF8, 0xA4, 0x66, 0x10, 0x06, 0x2C, 0x07, 0xAC, 0x68, 0x8A, 0xA7, 0x73, 0xDF, 0x67, 0x1E, 0xCC, 0xF4, 0x11, 0xA4, 0x9B, 0x70, 0xF9, 0xFD, 0xAF, 0xF5, 0x18, 0xC8, 0x24, 0x47, 0x6B, 0x6D, 0xC0, 0x66, 0xD0, 0x1A, 0x60, 0x0D, 0xA4, 0x01, 0x3D, 0x9E, 0x5F, 0x1B, 0x50, 0x05, 0xAA, 0x6E, 0x1D, 0x3B, 0x1E, 0xFC, 0x00, 0x47, 0x72, 0x25, 0x60, 0x05, 0x88, 0x00, 0x36, 0xED, 0x12, 0x4F, 0xCC, 0x02, 0x6B, 0x00, 0x41, 0x8F, 0x1A, 0x5F, 0xF9, 0xCD, 0x00, 0xE7, 0xB6, 0x0C, 0xE6, 0x1D, 0xAD, 0x3F, 0x55, 0xCD, 0x73, 0xDB, 0xB3, 0x8E, 0xF2, 0xFC, 0xA8, 0x6A, 0x3E, 0x09, 0x58, 0x9F, 0x16, 0xFC, 0xAB, 0x3E, 0xE2, 0xDA, 0xC0, 0xAE, 0xA4, 0xE3, 0x67, 0x72, 0x60, 0x35, 0xAB, 0x48, 0x01, 0x58, 0x53, 0x25, 0xD3, 0xCE, 0xE9, 0x14, 0xB2, 0xF3, 0x0D, 0x5F, 0xD9, 0x26, 0x6E, 0xEA, 0xEC, 0x5D, 0x6C, 0xA8, 0x03, 0x19, 0x40, 0x4F, 0xA6, 0x43, 0xBC, 0x89, 0xE7, 0xB6, 0x81, 0x56, 0x20, 0x13, 0xB0, 0x4F, 0x02, 0x8D, 0x7E, 0xDE, 0x10, 0x32, 0x51, 0x4B, 0x94, 0xAC, 0x65, 0xA3, 0x24, 0x2B, 0x13, 0xA6, 0xCD, 0xBA, 0xEF, 0xE4, 0x36, 0xA4, 0x02, 0x73, 0xC5, 0xDE, 0x10, 0x01, 0x63, 0xDD, 0xA8, 0xDD, 0x4D, 0xA9, 0xC9, 0x89, 0xF3, 0x49, 0xC5, 0x7E, 0x5B, 0xA3, 0xE4, 0x06, 0xCC, 0x80, 0xD5, 0xEF, 0x1C, 0xF7, 0xA4, 0x3B, 0xFB, 0xE3, 0xC5, 0x36, 0x5B, 0x0D, 0xD8, 0x83, 0xB9, 0x65, 0x06, 0x8B, 0x67, 0x86, 0xDD, 0x07, 0xCE, 0x94, 0x6F, 0xC7, 0x69, 0x28, 0xA7, 0xFD, 0x28, 0x9A, 0x10, 0x35, 0x10, 0xFB, 0xFC, 0x7C, 0xFA, 0xF1, 0x2B, 0xDD, 0xC0, 0x59, 0x5F, 0x13, 0x32, 0x2F, 0x26, 0x30, 0x2A, 0xD3, 0x71, 0x69, 0x99, 0x1C, 0xC3, 0x9E, 0xA8, 0x15, 0x74, 0xB4, 0x72, 0x54, 0x94, 0xFA, 0xB7, 0xDA, 0x80, 0x49, 0x68, 0xCD, 0x09, 0xA4, 0x2A, 0xE2, 0x62, 0x3F, 0x49, 0x5C, 0x4E, 0x0B, 0x2E, 0xFB, 0x64, 0x76, 0xF8, 0xFE, 0x34, 0x2E, 0xD3, 0x57, 0x37, 0x0C, 0x07, 0x5C, 0x00, 0x4B, 0x60, 0x36, 0x47, 0x67, 0x0B, 0x72, 0x1D, 0xB7, 0x4C, 0x07, 0xE2, 0xE6, 0xD4, 0xE7, 0x49, 0xB8, 0x68, 0x99, 0xC4, 0x90, 0xFB, 0x17, 0x8C, 0xE1, 0xF2, 0xA3, 0xD2, 0xBA, 0x02, 0x75, 0xF6, 0xB0, 0x81, 0x6D, 0x80, 0x10, 0xB3, 0x45, 0x6C, 0x06, 0xB4, 0x02, 0xB5, 0x00, 0x9B, 0x81, 0xBB, 0x81, 0xEF, 0x6A, 0x23, 0x73, 0x4D, 0xD4, 0xFA, 0x57, 0x78, 0x15, 0x12, 0xBF, 0x95, 0x41, 0x5F, 0xDD, 0xFB, 0xD6, 0xB7, 0xC7, 0x16, 0xA4, 0x2D, 0xA3, 0x05, 0x97, 0x2C, 0x36, 0x2E, 0xD3, 0xAF, 0x7F, 0xDF, 0xD6, 0xC9, 0x87, 0x79, 0xAF, 0xD0, 0x25, 0x6F, 0xF0, 0x52, 0x5E, 0x75, 0x57, 0x0B, 0xB0, 0xA7, 0x20, 0x22, 0x88, 0x29, 0xD9, 0x4B, 0x06, 0xD6, 0x4F, 0x6F, 0xB3, 0x32, 0x60, 0xB2, 0x7A, 0xA6, 0x21, 0x57, 0xCD, 0x2F, 0x1B, 0x79, 0x96, 0x6F, 0x50, 0x22, 0x02, 0x28, 0x01, 0x7A, 0x13, 0xFD, 0xAE, 0x59, 0xB6, 0x03, 0xA1, 0x80, 0x2F, 0x60, 0xC7, 0xBF, 0x72, 0x23, 0xAF, 0x18, 0x81, 0xA8, 0x51, 0x4E, 0xD3, 0xD8, 0x98, 0x49, 0x6E, 0xE7, 0xEC, 0xB6, 0x90, 0x7B, 0x65, 0x36, 0xBD, 0x53, 0xB1, 0x16, 0x50, 0xA3, 0xCE, 0x22, 0xE3, 0x03, 0xF0, 0x2E, 0xDA, 0x4F, 0xBF, 0x36, 0x79, 0xBA, 0x5F, 0xC5, 0xA9, 0x82, 0xB5, 0x05, 0xCC, 0x2C, 0xAE, 0x0B, 0x08, 0x1E, 0xA5, 0x8C, 0xC8, 0x70, 0x7B, 0xB2, 0x24, 0x97, 0x0D, 0x9C, 0xDE, 0x8A, 0x1F, 0xFF, 0x0A, 0xBD, 0x62, 0x22, 0xFD, 0x2B, 0x20, 0x5A, 0x35, 0x50, 0xB7, 0x8A, 0x19, 0xB3, 0x3F, 0xAE, 0xF2, 0xF3, 0xF5, 0x2B, 0x5C, 0x9F, 0xF6, 0x48, 0xED, 0x5C, 0x91, 0xCC, 0x06, 0x6C, 0x12, 0xEB, 0x5D, 0xBB, 0x58, 0x00, 0xAB, 0x01, 0x9D, 0x33, 0x6B, 0xA2, 0xB6, 0xD1, 0xD1, 0xC0, 0x0B, 0x9E, 0x7B, 0xDE, 0x28, 0x66, 0x8E, 0x8D, 0xC0, 0x6E, 0x68, 0x1B, 0xD3, 0x10, 0xC9, 0x22, 0xE0, 0xEA, 0x88, 0x19, 0x49, 0xC9, 0xBD, 0xAF, 0xBD, 0xFA, 0x90, 0xDD, 0x46, 0x7C, 0x28, 0x47, 0xE2, 0xB2, 0x8E, 0x58, 0x7C, 0xB1, 0x5F, 0x2D, 0xB2, 0x74, 0xDD, 0x44, 0x23, 0x3F, 0x7D, 0x7F, 0x72, 0x23, 0x08, 0xA3, 0xDE, 0xAC, 0xD1, 0xBC, 0x92, 0x92, 0xD9, 0xBE, 0xAD, 0xD9, 0xD6, 0x49, 0x50, 0xDA, 0x8F, 0x53, 0x14, 0x46, 0x2E, 0x64, 0xA2, 0x4F, 0x1F, 0xB2, 0xAA, 0xB7, 0x72, 0xD9, 0x67, 0xD5, 0xB2, 0x81, 0x5A, 0x40, 0x34, 0xA0, 0x53, 0xBF, 0x2A, 0x80, 0x27, 0x90, 0xD7, 0xED, 0x01, 0x51, 0x13, 0x36, 0x67, 0x31, 0xF8, 0x98, 0x46, 0x21, 0xF7, 0xEA, 0xC9, 0x22, 0x32, 0x34, 0xF5, 0x41, 0x0F, 0xA2, 0x9F, 0xAA, 0xE6, 0xB6, 0xD7, 0x33, 0xD6, 0x0A, 0x9C, 0xA5, 0x94, 0x9E, 0xFC, 0x07, 0xF1, 0x59, 0xE2, 0x12, 0x66, 0x80, 0xEC, 0x67, 0x4D, 0xEC, 0x09, 0xE4, 0x66, 0xD4, 0x26, 0xFB, 0x54, 0xC7, 0xB5, 0x28, 0x80, 0xD1, 0xB5, 0x8C, 0x9F, 0x7E, 0xF4, 0xC6, 0x79, 0xBE, 0xCE, 0x5F, 0x38, 0xE6, 0x9D, 0x53, 0xA1, 0xBB, 0x6E, 0xE3, 0xCA, 0x3A, 0xB9, 0xBA, 0x7B, 0x03, 0x46, 0x04, 0x47, 0xEC, 0x31, 0x16, 0x51, 0x20, 0x0A, 0x70, 0x01, 0xB6, 0xE1, 0x14, 0x27, 0x56, 0x03, 0x32, 0xEB, 0x9C, 0x9E, 0xA8, 0x29, 0x4D, 0x35, 0x9C, 0xCB, 0x1D, 0xB6, 0xF3, 0x59, 0x81, 0x9C, 0xB8, 0x36, 0xAC, 0x26, 0x76, 0x70, 0x2D, 0x23, 0xD8, 0xAC, 0xAD, 0x7C, 0x96, 0x52, 0xFA, 0x2C, 0xDA, 0xB1, 0x5C, 0xBE, 0xFF, 0x53, 0x9E, 0xB2, 0x1E, 0x75, 0x62, 0x7A, 0x61, 0x39, 0xB0, 0x64, 0xDA, 0xFC, 0x4F, 0x86, 0xFE, 0x4C, 0xEF, 0xEF, 0xFA, 0x93, 0x5F, 0xB6, 0x32, 0x14, 0x2A, 0x67, 0x49, 0x6D, 0x36, 0xDB, 0xD0, 0x6F, 0x7B, 0x17, 0x1F, 0x23, 0x1D, 0x2E, 0x04, 0x8E, 0xEF, 0xA2, 0xBD, 0x0E, 0x94, 0x39, 0x0D, 0x48, 0x14, 0x88, 0x4D, 0x4F, 0xE0, 0x06, 0x2A, 0x09, 0x03, 0xBC, 0x01, 0xE1, 0x1B, 0x9A, 0x3F, 0xDB, 0xFC, 0x97, 0x76, 0x4E, 0xD0, 0x0C, 0x73, 0x46, 0x4E, 0x47, 0x6D, 0x63, 0xFD, 0xB9, 0x56, 0xA3, 0x3E, 0xD4, 0x02, 0x61, 0x92, 0xA2, 0xAA, 0xDA, 0xBC, 0x1D, 0xE9, 0x35, 0xA8, 0x2E, 0x70, 0x4C, 0x4F, 0xD0, 0x0F, 0x66, 0x32, 0xAA, 0x19, 0xBB, 0x1A, 0xA3, 0x18, 0x1C, 0x55, 0x02, 0x22, 0xE3, 0x81, 0x05, 0x88, 0xE2, 0x45, 0xE3, 0xEE, 0xF9, 0xC8, 0xDD, 0xF2, 0x2C, 0x20, 0x9D, 0x9A, 0x88, 0xF2, 0x14, 0x0C, 0x31, 0x8C, 0x98, 0x4F, 0xBB, 0xD8, 0x6E, 0x9C, 0x32, 0x91, 0xCC, 0xA9, 0x51, 0xE3, 0xFA, 0x33, 0x64, 0x2C, 0x8C, 0x01, 0x6D, 0xA0, 0xFD, 0x7A, 0x58, 0xE3, 0xC3, 0x30, 0xD8, 0x78, 0xB1, 0x05, 0xB0, 0x06, 0x44, 0x01, 0xC3, 0xFA, 0xEC, 0xDE, 0xD5, 0x1C, 0xB3, 0xE1, 0xDE, 0x68, 0xF3, 0x46, 0x6B, 0xC7, 0x72, 0x64, 0xCD, 0xAB, 0x24, 0xEE, 0xA9, 0xA2, 0xD8, 0x17, 0x1A, 0x23, 0x44, 0xAC, 0x3F, 0x77, 0x7C, 0x73, 0x14, 0xF8, 0x7C, 0x3A, 0xDA, 0x58, 0xF5, 0xAB, 0x30, 0xAB, 0x03, 0x8B, 0x2F, 0x06, 0x21, 0x0A, 0xE8, 0x9E, 0x96, 0xB9, 0xB7, 0xAB, 0x1D, 0xD7, 0xA8, 0x52, 0xA7, 0x5D, 0x80, 0xF5, 0xF5, 0xAC, 0x95, 0xA3, 0x97, 0x34, 0xB1, 0xF7, 0xDD, 0x73, 0xB2, 0x63, 0xE3, 0x63, 0x8C, 0x8F, 0x17, 0x03, 0x93, 0x0C, 0x0C, 0x71, 0x9A, 0x28, 0x71, 0x14, 0x6E, 0x22, 0x1C, 0xF0, 0x02, 0x64, 0x6A, 0x1A, 0x04, 0xD0, 0x7A, 0x5B, 0x10, 0x86, 0x4C, 0xD0, 0x02, 0x8F, 0x09, 0x0B, 0x5A, 0x93, 0x19, 0x96, 0xAA, 0xB7, 0xFC, 0x07, 0x2B, 0x97, 0x64, 0xDB, 0x33, 0xC1, 0x57, 0x26, 0xCD, 0x64, 0xD3, 0x77, 0xD1, 0x9E, 0xB7, 0x32, 0x4E, 0x8C, 0x7F, 0xC8, 0x78, 0xCD, 0x41, 0x8C, 0x05, 0xC6, 0x48, 0x3B, 0x38, 0xEA, 0x1D, 0x48, 0x9E, 0x12, 0x6B, 0xD6, 0x2A, 0x74, 0x98, 0xE2, 0xBA, 0x70, 0x33, 0xBD, 0x23, 0xFD, 0xF6, 0xB1, 0x59, 0xC7, 0x2B, 0x59, 0xFB, 0x35, 0x36, 0x97, 0x31, 0x01, 0x08, 0x9C, 0xD9, 0x7B, 0x71, 0x37, 0x17, 0x6F, 0x2F, 0x79, 0x57, 0x9E, 0x41, 0x2B, 0x2B, 0xDD, 0xFC, 0x0B, 0x09, 0x84, 0x13, 0x02, 0xE8, 0x67, 0x55, 0x5A, 0xEB, 0x1E, 0x71, 0xD1, 0x87, 0x98, 0x25, 0xBE, 0xF7, 0x45, 0x57, 0xCD, 0x4E, 0x1A, 0x3D, 0x17, 0x1C, 0xDF, 0x74, 0x63, 0x09, 0x18, 0x68, 0x59, 0xE3, 0x5D, 0x58, 0x92, 0xFD, 0x42, 0x37, 0xB7, 0xFA, 0xE9, 0x5C, 0x73, 0x5B, 0x91, 0x26, 0xE5, 0x04, 0x2E, 0x78, 0x93, 0x0E, 0x06, 0xE1, 0x40, 0x6F, 0x40, 0xD7, 0xD8, 0x46, 0x01, 0x72, 0x17, 0x99, 0xCE, 0xBB, 0x48, 0x4C, 0x7F, 0x71, 0x5C, 0xF1, 0xEC, 0xEC, 0x7F, 0x3D, 0x84, 0xF8, 0x64, 0xF4, 0x8D, 0x90, 0x9F, 0xF7, 0x6D, 0xFE, 0x8C, 0x55, 0xFF, 0x3E, 0xCB, 0x7B, 0x4C, 0x39, 0xF0, 0x06, 0x03, 0x42, 0x81, 0xA6, 0x13, 0xA4, 0xD1, 0xCC, 0x69, 0x0B, 0xE0, 0xEB, 0x85, 0x3A, 0xB0, 0x13, 0x58, 0x05, 0xC0, 0xDA, 0x3B, 0xEF, 0x1D, 0xAD, 0xB8, 0xF7, 0x95, 0x74, 0xB3, 0x14, 0xA8, 0x3B, 0x3A, 0xB2, 0xC7, 0xD8, 0x2F, 0x70, 0x5F, 0xB9, 0x04, 0xBE, 0x81, 0x6A, 0xE3, 0x45, 0x88, 0xDE, 0x82, 0x40, 0xE5, 0xCD, 0x85, 0x53, 0x7E, 0x06, 0xB3, 0x63, 0xDB, 0x2A, 0x06, 0xEC, 0xF9, 0x8A, 0x19, 0x4F, 0x2D, 0x60, 0x7C, 0xCD, 0x3A, 0xA7, 0x13, 0x3D, 0xA3, 0x14, 0x8C, 0x59, 0xE3, 0x28, 0x59, 0x9D, 0x1E, 0x63, 0x7F, 0x69, 0xF7, 0x4C, 0x26, 0x00, 0x4D, 0x63, 0x18, 0x0F, 0x9E, 0xD9, 0x7F, 0x2E, 0x55, 0x8B, 0xF5, 0xE8, 0xCA, 0x22, 0xCD, 0x02, 0x5C, 0xE0, 0x0B, 0xB0, 0x0D, 0xE8, 0x35, 0x4D, 0x94, 0x88, 0x02, 0xB6, 0xF2, 0x67, 0x44, 0x09, 0x5E, 0x5C, 0x0B, 0x68, 0x9B, 0x98, 0x35, 0xFA, 0x15, 0x47, 0x31, 0x4A, 0x93, 0xEB, 0xC5, 0x0C, 0xD0, 0x10, 0xE4, 0xF1, 0xD8, 0xA6, 0xAD, 0x40, 0x60, 0x94, 0xA7, 0x9D, 0x02, 0x08, 0x7C, 0xAE, 0xDB, 0x96, 0x79, 0xFA, 0x90, 0x52, 0xDA, 0x70, 0xE5, 0x87, 0x9E, 0x80, 0xFC, 0xDE, 0x8E, 0x23, 0xE7, 0xD7, 0x58, 0x06, 0x4C, 0x9F, 0xBA, 0x2A, 0xFC, 0x83, 0xC6, 0x96, 0x3C, 0xAB, 0xE9, 0x5C, 0x13, 0x80, 0x26, 0x5E, 0xC4, 0x29, 0x7D, 0x0C, 0x0F, 0x36, 0x9D, 0x84, 0x44, 0x51, 0x72, 0x13, 0x84, 0x16, 0xB0, 0x82, 0x9F, 0x6F, 0x13, 0x02, 0xD4, 0xFC, 0xCC, 0x00, 0x5B, 0x40, 0xB1, 0x37, 0xFE, 0xBC, 0xD8, 0x05, 0x54, 0x02, 0x59, 0x40, 0x34, 0x90, 0xC7, 0x92, 0x87, 0x31, 0x33, 0x7A, 0x7C, 0xD6, 0xBA, 0x8B, 0x74, 0xDB, 0x52, 0x7F, 0x47, 0x86, 0xFD, 0x83, 0xFA, 0x5D, 0x4E, 0x81, 0x3F, 0x5B, 0xF1, 0x5B, 0x49, 0x6E, 0x06, 0x4B, 0x00, 0x0A, 0x14, 0xFC, 0x7C, 0x63, 0x80, 0x97, 0xB4, 0x15, 0x2A, 0x43, 0xE8, 0x8A, 0xD5, 0x4A, 0xA5, 0x3C, 0xA2, 0x97, 0x72, 0xD1, 0xC6, 0xA0, 0x04, 0xF1, 0x2C, 0xDA, 0x2D, 0x14, 0x46, 0x16, 0x8A, 0xF0, 0x37, 0x60, 0x8B, 0x05, 0xFA, 0x06, 0x48, 0xE2, 0x14, 0x6F, 0x62, 0x03, 0xBA, 0x08, 0x01, 0x64, 0xE0, 0x80, 0x06, 0x21, 0xEF, 0x1B, 0x8A, 0x45, 0xFF, 0x9B, 0x10, 0x01, 0x76, 0x7F, 0x5E, 0x5C, 0x80, 0x2A, 0x11, 0x40, 0xD6, 0xC4, 0x6C, 0x73, 0xA5, 0xAE, 0xB4, 0x31, 0xA2, 0x38, 0x34, 0x99, 0xD2, 0xEE, 0x98, 0xA5, 0x96, 0x43, 0x5F, 0xD0, 0x85, 0xA5, 0x67, 0xF4, 0x2D, 0xFB, 0xB9, 0x19, 0xCB, 0xF9, 0x2E, 0xD8, 0x3D, 0x80, 0xB2, 0x57, 0x0E, 0xF2, 0x02, 0x4C, 0x01, 0x0D, 0xC0, 0x9F, 0x7E, 0x21, 0x79, 0x9A, 0xDB, 0xEB, 0x02, 0x4E, 0xAF, 0xEF, 0xA9, 0x71, 0xD9, 0x6F, 0x86, 0xCF, 0xE2, 0xFB, 0x8A, 0x2F, 0x9E, 0x86, 0xF9, 0xC7, 0x01, 0x11, 0x55, 0x43, 0x57, 0xEB, 0x01, 0x22, 0xDE, 0xB4, 0x05, 0x8D, 0x77, 0xE7, 0x3D, 0x0C, 0x70, 0x07, 0x66, 0x43, 0x3A, 0x6D, 0xCE, 0x04, 0x7C, 0x4E, 0xB1, 0x89, 0x9A, 0xFC, 0x46, 0xAF, 0x4E, 0x3F, 0x2A, 0xDD, 0xBF, 0x7D, 0xD0, 0x5A, 0x81, 0x8D, 0x95, 0xD6, 0xDF, 0x3F, 0x2F, 0x25, 0xD0, 0xAB, 0x22, 0x90, 0x1A, 0x96, 0xC6, 0x68, 0x7D, 0x0D, 0x01, 0x6E, 0x69, 0xD1, 0xD5, 0x1B, 0xC2, 0x88, 0x05, 0xE8, 0x7A, 0x57, 0xCE, 0x4E, 0xE8, 0xD8, 0x40, 0xCA, 0x95, 0xCD, 0x66, 0xFB, 0xAC, 0x8E, 0xAD, 0x80, 0xF1, 0x14, 0xB7, 0x37, 0x6A, 0x63, 0x80, 0xD0, 0x9B, 0x6F, 0xCF, 0xDB, 0x6D, 0x9A, 0x7E, 0x58, 0x94, 0xBF, 0x26, 0xB3, 0x02, 0x88, 0x04, 0xA6, 0xF8, 0xED, 0x24, 0x90, 0x10, 0x69, 0x40, 0x38, 0x30, 0xF9, 0x3E, 0xA5, 0x80, 0x05, 0x10, 0x31, 0xC5, 0x7A, 0x13, 0x35, 0xFD, 0xC5, 0x29, 0x1C, 0x1B, 0xA0, 0x5E, 0x33, 0xD6, 0x58, 0x25, 0xA5, 0x8A, 0xF6, 0x31, 0xEE, 0xF0, 0x80, 0xD6, 0xF8, 0xC5, 0x45, 0x77, 0xFC, 0xA2, 0xB5, 0x27, 0x6A, 0xF1, 0x1D, 0x6B, 0xF5, 0xA6, 0xA6, 0x75, 0x00, 0xE5, 0x40, 0xEC, 0x4F, 0x3D, 0x6B, 0xDD, 0x21, 0x67, 0x3C, 0x8A, 0x29, 0x45, 0x3E, 0x0A, 0xA8, 0x8D, 0x1C, 0x64, 0xC0, 0x88, 0x2E, 0x53, 0xC3, 0xE4, 0xF9, 0xA9, 0xFC, 0xA2, 0x78, 0xB1, 0x7C, 0xC2, 0xFC, 0x96, 0x37, 0xBB, 0x03, 0xD1, 0x40, 0x4D, 0x8A, 0x97, 0x9F, 0x8C, 0x38, 0xC0, 0x0A, 0xD0, 0x98, 0x17, 0x9F, 0xFC, 0xF0, 0xED, 0x80, 0x1E, 0xE7, 0x81, 0x98, 0xA8, 0x19, 0x2E, 0x4D, 0xDB, 0xBF, 0xDB, 0x8B, 0xC6, 0x57, 0xBE, 0xA5, 0x34, 0x25, 0x0D, 0x8D, 0xA6, 0x7F, 0xF2, 0xED, 0x0A, 0x11, 0xA6, 0xBF, 0x7C, 0xAF, 0x50, 0x61, 0xD4, 0x16, 0x03, 0x54, 0x40, 0x13, 0xE5, 0x9F, 0x0F, 0x4A, 0xC8, 0xFA, 0x94, 0x6E, 0xE5, 0x0C, 0xA4, 0xC9, 0x47, 0x7C, 0xDD, 0xAF, 0x84, 0x91, 0x31, 0xBE, 0xA1, 0x09, 0x55, 0x40, 0x46, 0x5B, 0xB2, 0xBB, 0x65, 0xDF, 0xFC, 0xBF, 0x27, 0x59, 0xE9, 0xEA, 0x91, 0x6B, 0x01, 0xBB, 0xDF, 0xEA, 0x5D, 0x2B, 0xA0, 0xFB, 0x55, 0x20, 0xDD, 0x80, 0x75, 0x94, 0x01, 0xA0, 0x9C, 0xA7, 0x9C, 0xA8, 0x39, 0x24, 0x77, 0x6D, 0xCC, 0xEF, 0xB6, 0xD1, 0x04, 0x2F, 0xF8, 0x70, 0x74, 0x16, 0x49, 0x17, 0x77, 0xFF, 0xFC, 0xA8, 0x06, 0x93, 0x2C, 0x04, 0x41, 0xF9, 0xDD, 0xFA, 0x6C, 0x1C, 0xF9, 0xD9, 0x6E, 0xD4, 0x0D, 0x94, 0x01, 0xAC, 0xA6, 0x25, 0x30, 0x9E, 0x9E, 0x0C, 0xEA, 0xC5, 0x53, 0x54, 0xC7, 0x91, 0x0F, 0x90, 0xE2, 0x8B, 0xD7, 0x78, 0xEC, 0xBC, 0x21, 0xF8, 0xF6, 0xF9, 0x67, 0x66, 0x6B, 0x4F, 0x6E, 0xFB, 0xB1, 0xBB, 0x0C, 0x92, 0xD3, 0xAA, 0x66, 0xAF, 0x3B, 0xE9, 0xC7, 0xD8, 0xC6, 0xF2, 0x72, 0x01, 0x29, 0x40, 0x38, 0xA0, 0xFD, 0xCE, 0xBE, 0xA3, 0x80, 0xE2, 0xCC, 0xBC, 0xF7, 0x04, 0x2D, 0xB0, 0x49, 0x16, 0x1B, 0x73, 0xF1, 0x74, 0x34, 0x4D, 0xDC, 0xF1, 0x98, 0x06, 0x57, 0xCA, 0x0F, 0xDB, 0x03, 0xDF, 0x8E, 0xC4, 0x64, 0x8E, 0x4E, 0x3D, 0xC6, 0x94, 0x68, 0xCF, 0x45, 0x34, 0xDF, 0xD2, 0xC4, 0x0E, 0xA8, 0x02, 0xAC, 0x79, 0xB7, 0x20, 0x44, 0x81, 0xC5, 0x53, 0xCE, 0xCE, 0x32, 0x83, 0xB6, 0x92, 0x98, 0x7E, 0xAA, 0x71, 0x53, 0x04, 0xE3, 0xDC, 0xC5, 0x23, 0xDF, 0xB7, 0x1F, 0x4B, 0xE7, 0xBE, 0xD6, 0xB1, 0x7E, 0xFA, 0xF6, 0xE6, 0xA8, 0x65, 0x0A, 0x24, 0x37, 0x42, 0x47, 0x42, 0x10, 0x03, 0xB2, 0x80, 0x68, 0x40, 0x67, 0xF1, 0xBF, 0x00, 0x57, 0x20, 0x79, 0x66, 0xF9, 0x04, 0x2D, 0x31, 0x0B, 0x8F, 0xC2, 0x94, 0xC9, 0x21, 0x0D, 0xCD, 0x6D, 0x77, 0x2F, 0x63, 0x98, 0x9C, 0x52, 0x79, 0xA2, 0x1C, 0x29, 0x7D, 0xDC, 0xF6, 0x67, 0xC3, 0xE0, 0x4D, 0x24, 0xCD, 0x5B, 0x58, 0x04, 0xD7, 0x73, 0xC0, 0x37, 0x20, 0xEB, 0x23, 0x2C, 0x6F, 0x40, 0x93, 0xA7, 0xCC, 0x9A, 0xF5, 0xDC, 0xA2, 0x27, 0x51, 0xCC, 0x3F, 0xFE, 0x87, 0x31, 0x39, 0x6F, 0xF8, 0x2D, 0xC9, 0xB7, 0xDB, 0xE7, 0xED, 0xA7, 0x9A, 0xCA, 0xA7, 0xBF, 0xFF, 0x9B, 0x26, 0xB4, 0x09, 0x55, 0xA0, 0xE6, 0x5B, 0x8A, 0x77, 0xF4, 0x77, 0x03, 0x51, 0xC0, 0xE6, 0x99, 0x49, 0x4C, 0x5F, 0xEB, 0xEA, 0x89, 0x5A, 0xC1, 0x09, 0xCA, 0x37, 0xE6, 0x78, 0x4E, 0x1F, 0xBB, 0x9D, 0x4F, 0x4A, 0xE4, 0xD4, 0xC0, 0xB8, 0xD6, 0xEF, 0x61, 0xD5, 0x79, 0xED, 0x82, 0x99, 0x0D, 0xF3, 0x5A, 0x4F, 0xF4, 0xBD, 0x1F, 0xC1, 0x1F, 0x02, 0xA8, 0x57, 0x58, 0x16, 0x79, 0x6B, 0xF6, 0x83, 0xA7, 0x9C, 0x72, 0xB3, 0x19, 0xAA, 0xE2, 0xFC, 0xC3, 0xF3, 0xA2, 0x23, 0x4E, 0x7C, 0xFB, 0x24, 0xF1, 0x0E, 0x62, 0xDC, 0x83, 0x27, 0xD1, 0x2B, 0x66, 0x1C, 0xF6, 0x4D, 0x3D, 0xCA, 0xC1, 0x49, 0x99, 0x12, 0xA2, 0x26, 0xA7, 0xE1, 0x93, 0x6B, 0x2A, 0xA7, 0xEA, 0x06, 0x50, 0x61, 0x28, 0x37, 0x03, 0x3B, 0xA7, 0xD8, 0x44, 0xAD, 0xB1, 0x2A, 0xD7, 0xA2, 0x0D, 0x78, 0xFC, 0x2E, 0xD0, 0x16, 0x63, 0x26, 0xB1, 0xE0, 0xB7, 0xAC, 0x60, 0x97, 0xAB, 0xC6, 0xCD, 0x14, 0x36, 0x27, 0x1D, 0x33, 0xD6, 0x64, 0xA2, 0xA6, 0x4F, 0xA3, 0x9F, 0x7D, 0x92, 0x37, 0x17, 0xA1, 0x6B, 0x1E, 0xF9, 0x6F, 0x4E, 0x70, 0x12, 0x3E, 0x45, 0xE9, 0x1C, 0x1E, 0x63, 0x70, 0x2D, 0x0D, 0xE8, 0xE8, 0xD9, 0x72, 0xB3, 0xF3, 0xFC, 0x34, 0x8F, 0x90, 0x7C, 0xFB, 0xD7, 0xD5, 0xBA, 0x41, 0xD0, 0xFF, 0x6B, 0x60, 0xB1, 0xDE, 0x1C, 0x05, 0x53, 0x4A, 0x45, 0x02, 0xD4, 0x74, 0xAC, 0x17, 0x40, 0xEA, 0x93, 0x0D, 0xE3, 0xAF, 0x9A, 0xE4, 0x93, 0x41, 0x37, 0xB7, 0x35, 0xA7, 0x1E, 0x53, 0x86, 0xBD, 0xDC, 0x6C, 0x58, 0x2E, 0x5E, 0x5B, 0x6F, 0xB8, 0x28, 0x05, 0x7E, 0x75, 0x14, 0x2B, 0xF1, 0x6B, 0x16, 0xEB, 0xEC, 0x59, 0x40, 0x19, 0xF2, 0xB1, 0xAF, 0xD9, 0x4C, 0x05, 0xBA, 0xFD, 0x22, 0x47, 0x6A, 0x77, 0xBB, 0x3D, 0x88, 0xEC, 0xE8, 0x64, 0xDD, 0x78, 0x71, 0x3E, 0xD2, 0x18, 0x71, 0x9A, 0x01, 0xCE, 0xFF, 0x37, 0x46, 0xB0, 0x74, 0x0A, 0xF6, 0x7C, 0x7B, 0x06, 0x80, 0x88, 0x8C, 0x6E, 0xB9, 0x29, 0x90, 0x05, 0xCE, 0x34, 0x3E, 0x0B, 0x6C, 0xF6, 0xE4, 0x39, 0x47, 0xB5, 0x5F, 0x21, 0x28, 0x50, 0xD3, 0xFE, 0x7C, 0xCF, 0x9E, 0xFC, 0x8B, 0xED, 0xFC, 0xD9, 0x02, 0xDC, 0x80, 0x9C, 0x1D, 0x7A, 0x9D, 0xA0, 0x6D, 0x7A, 0x30, 0x6C, 0xA4, 0x3A, 0xAC, 0x40, 0xDA, 0x05, 0x26, 0xB5, 0x5B, 0xB7, 0x43, 0xB0, 0xDC, 0xC5, 0x6E, 0x3C, 0x6C, 0x45, 0x1B, 0xD0, 0x6E, 0xE3, 0x9B, 0x70, 0xF5, 0x4C, 0xEC, 0xA7, 0xF5, 0x96, 0x18, 0x85, 0x59, 0x3F, 0x6D, 0x9C, 0x5A, 0x81, 0xFD, 0x03, 0x75, 0x2B, 0xA1, 0x92, 0x23, 0x76, 0x4A, 0x81, 0xB4, 0x47, 0x0F, 0x04, 0x7A, 0x53, 0x12, 0x5B, 0x63, 0x03, 0x39, 0x6D, 0xC9, 0x81, 0x9D, 0x80, 0xC6, 0xED, 0x5F, 0xCF, 0xD8, 0x19, 0x1F, 0xBC, 0xE3, 0xB2, 0x36, 0x6D, 0x31, 0xAC, 0x99, 0x2D, 0xC2, 0x04, 0x08, 0x47, 0x62, 0x3A, 0x72, 0x47, 0x14, 0xF0, 0x04, 0xC2, 0xDF, 0x23, 0x6D, 0xC2, 0x00, 0xA7, 0x7A, 0xA2, 0x3E, 0x41, 0x13, 0xFA, 0x15, 0x18, 0x1D, 0xA4, 0x8A, 0x7B, 0x48, 0xD8, 0x1F, 0xAE, 0x95, 0x6C, 0x9D, 0x1B, 0xF8, 0x9D, 0xBB, 0xB0, 0xD1, 0x1F, 0x4D, 0xB7, 0xCB, 0x57, 0x1D, 0x3A, 0x99, 0x6F, 0x23, 0x35, 0xF7, 0xF4, 0xC8, 0x7E, 0x7B, 0xA7, 0xAD, 0xE0, 0x67, 0xD8, 0xFC, 0x99, 0x52, 0xE1, 0x0A, 0x1C, 0xB9, 0xCC, 0x27, 0xA2, 0xF7, 0x25, 0xD1, 0x14, 0x35, 0xAC, 0xD8, 0x3E, 0x9D, 0xA7, 0x78, 0x20, 0x04, 0x9B, 0xEA, 0xD7, 0xE8, 0x4F, 0xAB, 0x70, 0xE6, 0xA6, 0xC6, 0xD4, 0x4E, 0x29, 0x55, 0x46, 0x10, 0x60, 0x3B, 0xE5, 0x00, 0x62, 0xF4, 0x27, 0x05, 0x72, 0x03, 0xDD, 0x84, 0x03, 0x25, 0x40, 0x38, 0xB1, 0x08, 0xDA, 0x55, 0x6B, 0x4E, 0xCC, 0x14, 0xA5, 0xB7, 0x2D, 0x34, 0x7F, 0x49, 0x8C, 0x10, 0xEF, 0xDF, 0x53, 0xC9, 0x2D, 0xF0, 0x31, 0x25, 0x20, 0xC8, 0x05, 0x33, 0xC1, 0xD1, 0x9C, 0xF7, 0x3C, 0x00, 0x12, 0xE0, 0x33, 0x91, 0xA1, 0x1B, 0xBD, 0x5A, 0x8B, 0x6B, 0xF8, 0x31, 0x60, 0x9E, 0xB2, 0xA9, 0xE2, 0x95, 0x97, 0xA7, 0x9D, 0x5F, 0xF2, 0xA8, 0x8A, 0x2A, 0x64, 0x5C, 0xDD, 0x91, 0x0F, 0xBC, 0xDB, 0xB1, 0xD7, 0xA8, 0x38, 0xA5, 0x03, 0x4B, 0x00, 0xD1, 0xB9, 0xAC, 0x10, 0xBA, 0x1C, 0xD5, 0x2C, 0x28, 0xB0, 0x8C, 0x20, 0xC7, 0x80, 0x08, 0x91, 0x35, 0xCD, 0x87, 0x80, 0x8A, 0xF1, 0x35, 0x24, 0x1C, 0x58, 0x4D, 0x18, 0xA1, 0xC0, 0x4E, 0x20, 0x65, 0x62, 0x66, 0x78, 0xB6, 0xF8, 0x86, 0x48, 0x5F, 0x82, 0xBB, 0x5D, 0xC8, 0xD3, 0x85, 0xCB, 0x44, 0x50, 0xA7, 0xD7, 0x9B, 0xF7, 0xC5, 0x9F, 0x3A, 0x34, 0x7E, 0xC1, 0x8B, 0x38, 0x29, 0xAF, 0x3D, 0x96, 0x38, 0x93, 0xF1, 0x32, 0x7E, 0x2E, 0x0D, 0xE8, 0xC6, 0x8B, 0x5B, 0x39, 0x5B, 0x34, 0x60, 0x8A, 0xD8, 0xDD, 0x18, 0xD6, 0x66, 0xFD, 0x22, 0x6F, 0x29, 0xD3, 0xDC, 0x5C, 0x74, 0x0A, 0xF3, 0x78, 0x4A, 0x30, 0xC8, 0x84, 0x39, 0x5E, 0x0C, 0xBE, 0x6F, 0xDA, 0x56, 0x34, 0x47, 0xDD, 0xF4, 0xA3, 0xC9, 0x91, 0x18, 0x8D, 0x5A, 0x66, 0x02, 0xE9, 0x53, 0xE2, 0x3A, 0x1E, 0x92, 0x38, 0xEA, 0x06, 0x52, 0x00, 0xDB, 0x80, 0x2C, 0x40, 0x6D, 0x46, 0xEB, 0xC4, 0xCC, 0x9F, 0x1C, 0x78, 0x33, 0x3C, 0x1F, 0x2D, 0x1B, 0x7A, 0xC5, 0x36, 0xA8, 0x51, 0xDD, 0x68, 0x48, 0x6D, 0x58, 0x2D, 0x38, 0x54, 0xC8, 0xB4, 0xDB, 0x86, 0x51, 0x28, 0x7A, 0x4F, 0x89, 0xCD, 0x0C, 0x22, 0xB7, 0xF3, 0xD7, 0xF7, 0x0F, 0x50, 0xBF, 0x58, 0xBE, 0x76, 0x75, 0x55, 0x2E, 0x4B, 0x9C, 0xD3, 0x75, 0xF7, 0xE3, 0x24, 0xAA, 0x09, 0xB4, 0x02, 0xEA, 0x80, 0x34, 0x10, 0x0B, 0xA8, 0x3D, 0x17, 0xDE, 0x1D, 0x13, 0xFC, 0x72, 0x92, 0x8F, 0xE8, 0xE4, 0xFC, 0xB5, 0xA8, 0x2A, 0x41, 0x8D, 0x02, 0x2A, 0x21, 0x51, 0xF9, 0x06, 0xBA, 0xA0, 0x5B, 0xED, 0x04, 0x54, 0x01, 0x5F, 0x40, 0x06, 0x04, 0xAB, 0x2D, 0x80, 0x2E, 0x80, 0x56, 0xCB, 0x93, 0x67, 0x20, 0xBA, 0x1A, 0x39, 0xA3, 0x92, 0x8D, 0x96, 0xAD, 0xB5, 0xE1, 0xA3, 0xD9, 0x0D, 0x57, 0xE6, 0x4C, 0xF8, 0x37, 0xBB, 0x41, 0x40, 0x6C, 0xFA, 0x8C, 0xF1, 0xAA, 0xF4, 0x6B, 0x4F, 0xBB, 0x67, 0x50, 0xF0, 0xCF, 0xC7, 0xB4, 0x35, 0xD7, 0xF3, 0x59, 0xAC, 0x28, 0x27, 0x36, 0xFC, 0xA2, 0x57, 0xE0, 0x94, 0x5C, 0x80, 0xD5, 0xB8, 0x8E, 0xE3, 0x67, 0xBD, 0x70, 0xE6, 0xE6, 0x91, 0x2B, 0xB1, 0x80, 0x6C, 0xA0, 0x13, 0xA7, 0x34, 0x73, 0xAB, 0xF5, 0x87, 0xA2, 0xCE, 0x26, 0x8C, 0x88, 0xE3, 0xC5, 0x0A, 0x06, 0x26, 0xF1, 0x05, 0x56, 0x31, 0x30, 0x98, 0xA2, 0x42, 0x67, 0xDB, 0x80, 0x25, 0x10, 0x1B, 0x48, 0x8A, 0x68, 0xCB, 0x01, 0x25, 0x3C, 0x20, 0xEF, 0xAD, 0x35, 0x41, 0x4B, 0x7E, 0x9D, 0x05, 0x3D, 0xF0, 0x78, 0x27, 0x6C, 0x88, 0x07, 0x55, 0x4C, 0x05, 0x17, 0xD8, 0x14, 0xA0, 0xA9, 0xB1, 0xF4, 0xDE, 0xEC, 0x89, 0xF4, 0x4D, 0xF0, 0xFE, 0x61, 0x42, 0x19, 0xC7, 0x79, 0x50, 0x09, 0x89, 0x5B, 0x40, 0x78, 0x73, 0x7E, 0x12, 0x50, 0x62, 0xE6, 0xAD, 0x7B, 0x66, 0xAA, 0x9B, 0x6F, 0x2F, 0xFE, 0xAC, 0x81, 0x1D, 0x33, 0x0D, 0x04, 0x34, 0x00, 0x0A, 0x47, 0xC4, 0xD1, 0xD2, 0xEC, 0x14, 0x0C, 0x9C, 0x2A, 0xAC, 0x7E, 0x2B, 0x89, 0xF3, 0x87, 0x3E, 0xCB, 0xDA, 0xED, 0x40, 0x14, 0xE0, 0xC4, 0xCC, 0x70, 0xE3, 0x93, 0x1E, 0x6C, 0x6B, 0x7A, 0x02, 0x4C, 0xD4, 0x8A, 0x6D, 0x20, 0xE2, 0xBF, 0xE2, 0x2E, 0x54, 0xFF, 0x56, 0x9B, 0x71, 0xFD, 0xC1, 0x56, 0x77, 0xA1, 0x5C, 0xB2, 0x16, 0x64, 0x8E, 0xC0, 0x42, 0x20, 0xBF, 0x0B, 0x82, 0xC9, 0x81, 0xF1, 0x78, 0x7D, 0xDC, 0x3A, 0xFF, 0x25, 0x73, 0x14, 0x20, 0xFB, 0x23, 0x73, 0xC4, 0x1B, 0x3C, 0x55, 0x86, 0x79, 0x54, 0x37, 0x79, 0x4D, 0x64, 0x64, 0xBD, 0x66, 0x7D, 0x93, 0xE0, 0xE2, 0x8F, 0xB1, 0xC0, 0xB1, 0x90, 0xB4, 0xD3, 0xB0, 0x44, 0x15, 0xC8, 0x59, 0xE9, 0x07, 0x10, 0xCF, 0x62, 0x81, 0xD9, 0xDF, 0xB7, 0x28, 0x3B, 0xF4, 0xB3, 0xE3, 0x98, 0x40, 0x25, 0x4F, 0x89, 0x89, 0x5A, 0x43, 0x70, 0x17, 0xFB, 0x8D, 0x66, 0xEB, 0x7E, 0xE4, 0x5B, 0xF5, 0x9F, 0x1E, 0xE9, 0xBF, 0xD4, 0x35, 0xB8, 0x70, 0x62, 0x7F, 0xA0, 0xAA, 0x27, 0xA7, 0xEF, 0x95, 0xD4, 0xF6, 0x47, 0x1C, 0x72, 0x05, 0x8A, 0x88, 0xFA, 0x68, 0x69, 0xC4, 0x32, 0xC2, 0xDF, 0xB4, 0xAB, 0x3D, 0xC3, 0xB1, 0x71, 0x14, 0x8C, 0xA8, 0x36, 0x4F, 0x29, 0xC0, 0x5F, 0x43, 0xBE, 0xB3, 0x0E, 0x89, 0xFE, 0x2C, 0xC6, 0x64, 0x8F, 0x1D, 0xC3, 0xEB, 0x59, 0x55, 0x3E, 0x95, 0x82, 0x40, 0xE8, 0xC7, 0x13, 0xC6, 0x81, 0x22, 0xDC, 0x80, 0x25, 0x6F, 0x43, 0xB5, 0xE2, 0x8B, 0x35, 0x51, 0x0B, 0xDE, 0x5B, 0x35, 0xD0, 0x83, 0xCF, 0xE2, 0xA9, 0x98, 0x4D, 0x15, 0x74, 0x36, 0xAD, 0xFC, 0x1D, 0x2D, 0xEC, 0xDE, 0xD5, 0x56, 0x3B, 0xD1, 0xFA, 0xB1, 0xBE, 0x15, 0xB3, 0xF9, 0x0E, 0xAB, 0x24, 0x62, 0xBF, 0x32, 0xF7, 0xC4, 0xB7, 0x8D, 0x90, 0xFB, 0x06, 0x3B, 0x85, 0xC2, 0x6B, 0x06, 0x19, 0x43, 0xB2, 0x7A, 0x4E, 0x79, 0x63, 0xBF, 0x1B, 0x30, 0xBD, 0xD7, 0x39, 0x24, 0x02, 0xAE, 0xF1, 0xF5, 0x36, 0x3E, 0x88, 0x33, 0x74, 0x76, 0x02, 0xAE, 0x6F, 0x71, 0xD4, 0x94, 0x10, 0xB9, 0x00, 0xE6, 0xEF, 0x02, 0x3E, 0xFC, 0x5D, 0xAD, 0xCE, 0xCF, 0xEC, 0x44, 0x6D, 0xFF, 0x66, 0x53, 0x6E, 0x89, 0x27, 0x2E, 0xA7, 0x90, 0x3B, 0x03, 0x42, 0x87, 0x07, 0x57, 0xAB, 0xC1, 0xCE, 0x50, 0x06, 0xBD, 0xA1, 0xE3, 0x36, 0x81, 0x0E, 0xFB, 0x18, 0xE9, 0x88, 0xCF, 0x92, 0x3B, 0x5F, 0x75, 0xC8, 0xFB, 0x35, 0xF9, 0x59, 0xFE, 0x31, 0x2F, 0x5B, 0x3C, 0x7A, 0x9C, 0x2A, 0x62, 0xDE, 0x77, 0x46, 0x80, 0x0A, 0x4E, 0x91, 0xAB, 0x65, 0xC0, 0x10, 0x1C, 0xB0, 0xBC, 0xA5, 0xAE, 0x85, 0xA3, 0xA3, 0x0E, 0x71, 0xCE, 0x23, 0x5C, 0xAA, 0x5F, 0x79, 0x47, 0x14, 0xA8, 0xE6, 0x62, 0x23, 0x66, 0xFF, 0x9D, 0x98, 0xC4, 0x84, 0x02, 0x3C, 0x01, 0x5D, 0x00, 0x92, 0x84, 0x37, 0x80, 0xA0, 0x09, 0x12, 0x45, 0xC4, 0xF0, 0x6C, 0x4F, 0xAC, 0x01, 0x64, 0xCB, 0xE3, 0xD2, 0xE1, 0xBD, 0xB1, 0x1C, 0x16, 0x9B, 0x32, 0xA6, 0xD7, 0xB4, 0x29, 0x3F, 0x42, 0xA4, 0xEA, 0x04, 0xA1, 0xDE, 0x24, 0x84, 0x7A, 0x7A, 0x34, 0xF8, 0x59, 0xCD, 0x1F, 0x1F, 0x38, 0x1E, 0xC9, 0x1A, 0xC1, 0x6C, 0xAC, 0x48, 0x81, 0x79, 0xD1, 0xEA, 0x76, 0x39, 0x30, 0x1E, 0x61, 0xFC, 0x02, 0xCD, 0x53, 0x28, 0xC2, 0xC5, 0xB1, 0x6F, 0x5F, 0xFC, 0x4C, 0xD4, 0x0E, 0xD7, 0xDB, 0xC9, 0x38, 0x9A, 0x93, 0xEC, 0x60, 0xF7, 0xD6, 0x05, 0x74, 0x10, 0x0A, 0x44, 0x03, 0x12, 0x38, 0x93, 0x3F, 0x63, 0x96, 0xF8, 0xD5, 0xBC, 0x43, 0x61, 0x56, 0xBF, 0x0D, 0x73, 0x83, 0x51, 0x87, 0xA4, 0x70, 0xB3, 0xD0, 0xC6, 0xC7, 0x94, 0x84, 0xF4, 0x82, 0x47, 0x68, 0x48, 0xF5, 0xD3, 0x5E, 0x30, 0xF4, 0xAB, 0x0E, 0xF9, 0x9B, 0x6F, 0xE8, 0x1F, 0xF3, 0xDE, 0x25, 0x6F, 0x7D, 0xFE, 0xB9, 0xFD, 0x8F, 0x48, 0x74, 0x85, 0xB6, 0x5B, 0x5A, 0x9B, 0x23, 0xBB, 0x8D, 0x80, 0xB4, 0x01, 0x99, 0x07, 0x45, 0x02, 0xA7, 0x29, 0xF4, 0x66, 0x44, 0x63, 0x1C, 0x41, 0xE2, 0xDA, 0x93, 0x38, 0x80, 0x91, 0x07, 0xA4, 0xCE, 0x32, 0x17, 0xF1, 0x95, 0x04, 0x72, 0xA0, 0x80, 0x39, 0xB0, 0x78, 0x66, 0x0A, 0x80, 0xA5, 0xF3, 0xD5, 0xD4, 0xC2, 0x90, 0x10, 0x59, 0x86, 0xE9, 0x52, 0xEC, 0x1F, 0xCA, 0xF6, 0x93, 0xA4, 0x16, 0xAB, 0xA0, 0x70, 0xC1, 0x19, 0x77, 0xD7, 0xAA, 0x9F, 0xA6, 0x56, 0xDF, 0xA8, 0x89, 0xBE, 0xE6, 0xDE, 0xAD, 0x6F, 0xFA, 0x9E, 0x37, 0xB0, 0x9A, 0x91, 0xE1, 0x29, 0x15, 0x37, 0xB0, 0xF8, 0xEF, 0x19, 0xAE, 0x29, 0xE8, 0x54, 0x40, 0xE5, 0xAF, 0x22, 0xAE, 0x8E, 0xFA, 0xD6, 0x0D, 0x88, 0x11, 0xCA, 0xA8, 0x8D, 0x74, 0x89, 0xE0, 0x8D, 0xE4, 0xBA, 0x8F, 0x9A, 0xBB, 0x37, 0x50, 0x14, 0x48, 0x44, 0x81, 0x96, 0x37, 0x5D, 0xCB, 0x0C, 0x50, 0x62, 0x12, 0x90, 0xAC, 0x81, 0xBD, 0x01, 0xB5, 0x39, 0x73, 0xA2, 0xE6, 0xC8, 0x39, 0xD8, 0x82, 0x4D, 0x67, 0x2E, 0x2B, 0xC2, 0xF5, 0xF7, 0x69, 0xAD, 0x92, 0xA9, 0x75, 0x85, 0x87, 0xC8, 0xDA, 0x90, 0x5F, 0x11, 0xD1, 0xEA, 0x7F, 0xA4, 0x91, 0xDA, 0x29, 0x62, 0xCB, 0xE3, 0xAF, 0x94, 0x84, 0x30, 0x08, 0x36, 0x73, 0x2A, 0x9C, 0x22, 0x6F, 0x73, 0xBC, 0x98, 0xBC, 0xC8, 0x35, 0xE6, 0xD3, 0x81, 0xA3, 0x9C, 0x46, 0x52, 0x73, 0xCA, 0x7D, 0x43, 0x1D, 0xD7, 0xFD, 0x3E, 0x55, 0xD9, 0x93, 0xAB, 0x64, 0xE3, 0xF5, 0x74, 0x5B, 0x80, 0xE1, 0x8B, 0xC1, 0x08, 0x22, 0x7A, 0x04, 0x6E, 0x7F, 0x93, 0xAA, 0x7A, 0x90, 0x40, 0x3A, 0x60, 0x0B, 0xD8, 0x01, 0x8C, 0xA4, 0x22, 0x35, 0x51, 0xE3, 0x92, 0xDC, 0x36, 0xEA, 0x66, 0x97, 0xC3, 0xA6, 0x14, 0xE6, 0x1C, 0x7B, 0xF4, 0xF8, 0xD4, 0x64, 0xCA, 0xBD, 0xC2, 0x8B, 0xCB, 0x7D, 0x12, 0x21, 0x5F, 0x73, 0xEF, 0xE3, 0x60, 0xAC, 0x33, 0x20, 0x26, 0x78, 0x40, 0x2D, 0xE0, 0xB8, 0x71, 0x11, 0xD2, 0xC0, 0x22, 0x7A, 0x8A, 0x30, 0x27, 0x09, 0x5D, 0x4F, 0xFB, 0x75, 0x46, 0xBB, 0x1E, 0x0F, 0x25, 0x67, 0xD4, 0xA2, 0x88, 0xF5, 0x58, 0xD5, 0x1B, 0xF7, 0x3C, 0x67, 0x23, 0x00, 0xB7, 0x7A, 0xEC, 0x38, 0x10, 0xB1, 0x81, 0x8E, 0x11, 0x2B, 0xA7, 0x42, 0x17, 0x28, 0x22, 0x1D, 0x30, 0xE2, 0x78, 0x2F, 0x25, 0x70, 0x4E, 0x89, 0x89, 0x5A, 0xB2, 0x55, 0x85, 0xD2, 0x3A, 0xB5, 0x98, 0x1A, 0xA8, 0xEC, 0x95, 0x68, 0xC7, 0x11, 0x45, 0x12, 0x25, 0x66, 0x3B, 0xA7, 0xC1, 0xA0, 0xC9, 0x27, 0x21, 0xF2, 0xEC, 0xED, 0xD6, 0x1A, 0xC5, 0x95, 0x37, 0x96, 0x06, 0x5E, 0xF7, 0x24, 0xEA, 0x0C, 0xF0, 0x4B, 0x00, 0x36, 0xE1, 0x3A, 0x3F, 0xE3, 0xFB, 0x02, 0x90, 0xE2, 0xA7, 0x36, 0xFE, 0x8C, 0xC0, 0x11, 0xE5, 0x1B, 0x66, 0x7C, 0x52, 0x90, 0xBC, 0xCE, 0x2F, 0x2C, 0x00, 0x3C, 0x2D, 0xCE, 0xF3, 0x54, 0x07, 0xED, 0x0D, 0x34, 0x35, 0xAB, 0xA4, 0xB6, 0x66, 0x05, 0x54, 0x02, 0x6D, 0x40, 0x15, 0x90, 0x4E, 0x08, 0xD0, 0x42, 0x6D, 0xAD, 0x27, 0x68, 0xB8, 0xFA, 0xA6, 0xBE, 0x32, 0xC5, 0xB1, 0x7F, 0xA5, 0x23, 0xDF, 0x4E, 0xDE, 0x57, 0xA2, 0x1C, 0x2C, 0x1B, 0x31, 0xDF, 0xF1, 0xA4, 0xA9, 0x6D, 0x20, 0xF6, 0x75, 0x67, 0x1F, 0xEF, 0x06, 0x5D, 0xA7, 0xAC, 0x2B, 0x16, 0x8E, 0x4E, 0x29, 0x5C, 0xDD, 0xAB, 0x06, 0x57, 0x14, 0x8E, 0x74, 0x4E, 0xB9, 0x35, 0x69, 0xC6, 0x1D, 0xB9, 0xE9, 0xB4, 0xB5, 0xCF, 0xEF, 0x6C, 0x07, 0x76, 0x03, 0x9E, 0xD7, 0x05, 0x56, 0xA8, 0x64, 0xF0, 0x45, 0x67, 0x6D, 0x75, 0xEC, 0xA3, 0xFE, 0xD4, 0x0F, 0x98, 0x3F, 0xA2, 0x35, 0x17, 0xF3, 0x63, 0x9C, 0xE8, 0x20, 0x12, 0x28, 0x07, 0x42, 0x01, 0x7F, 0x8E, 0x90, 0x95, 0xC5, 0x98, 0x35, 0xFB, 0xC8, 0x0B, 0xED, 0x66, 0x0D, 0xC9, 0xDE, 0x5B, 0xB0, 0x46, 0x71, 0xC7, 0x08, 0xD3, 0xCD, 0x84, 0xC4, 0x8D, 0x5D, 0x33, 0x89, 0x9B, 0x44, 0x9A, 0x33, 0xD0, 0xA6, 0x10, 0xA2, 0x72, 0xB6, 0x3F, 0xEF, 0x62, 0xEE, 0xB6, 0x4E, 0x6D, 0x2E, 0x02, 0x3B, 0x5F, 0xB7, 0x0E, 0x1D, 0x0B, 0x0F, 0x9F, 0x45, 0x20, 0x47, 0x58, 0x10, 0xE3, 0x97, 0x71, 0x7F, 0xB6, 0xFB, 0xEC, 0x18, 0xA5, 0x0F, 0x70, 0x8A, 0xE4, 0x6C, 0xDA, 0x21, 0xCA, 0xBA, 0x6E, 0x61, 0x56, 0x31, 0xAE, 0x70, 0x06, 0x64, 0xFA, 0x1F, 0x50, 0x3F, 0x6C, 0x2A, 0x4B, 0x90, 0xD3, 0x00, 0xC5, 0x8B, 0xED, 0x40, 0x04, 0x60, 0x09, 0x44, 0xE2, 0x94, 0x93, 0xD5, 0x91, 0x33, 0x23, 0x6E, 0xAA, 0xE2, 0xC1, 0x2F, 0x77, 0xE6, 0x6A, 0x4C, 0x5A, 0x5C, 0xC9, 0xAC, 0xE3, 0x98, 0x86, 0x94, 0x8F, 0xE4, 0xFD, 0xDD, 0x27, 0xC8, 0xA9, 0x54, 0x6D, 0x8E, 0x9F, 0x18, 0x79, 0x7A, 0x1A, 0xD8, 0xC4, 0x7D, 0x2C, 0xE9, 0x71, 0x95, 0x2A, 0xB9, 0x66, 0x68, 0xC6, 0x6B, 0x6E, 0x66, 0x5E, 0x71, 0x6C, 0xCC, 0xD4, 0x6E, 0x24, 0xA7, 0x58, 0x60, 0x9F, 0xB7, 0x6F, 0xFE, 0x4E, 0x9F, 0x1E, 0xF7, 0xFC, 0x9C, 0x93, 0xCA, 0xB8, 0x27, 0xFF, 0x8F, 0xBD, 0xCE, 0x8D, 0x5A, 0xD4, 0x74, 0x37, 0x53, 0x9F, 0xAC, 0x37, 0xA0, 0x1A, 0x68, 0x05, 0x4A, 0x00, 0x0F, 0xC0, 0x04, 0x88, 0x1F, 0xA0, 0x36, 0x33, 0x68, 0x9B, 0x82, 0xAD, 0x42, 0x95, 0x13, 0xC3, 0xDB, 0x45, 0xE1, 0x8E, 0x90, 0xAC, 0x70, 0x2C, 0xA7, 0xB1, 0xD6, 0x66, 0x0E, 0xBB, 0x60, 0x9D, 0xFE, 0xAF, 0x8D, 0x76, 0xC9, 0xCF, 0xAA, 0xE0, 0x60, 0xDF, 0x9C, 0x12, 0x3D, 0x8D, 0x06, 0xA2, 0x01, 0xD1, 0x29, 0x8C, 0xE2, 0x99, 0x3E, 0x46, 0x1C, 0x80, 0xF1, 0xC5, 0x6A, 0x60, 0x9D, 0x7B, 0x3D, 0xB0, 0x37, 0x70, 0x1C, 0x22, 0xA6, 0x4C, 0x7B, 0xD2, 0xB9, 0xFB, 0x6F, 0xBA, 0x6A, 0xD3, 0x38, 0xC9, 0x8F, 0xD2, 0xBB, 0xE3, 0xCD, 0x53, 0x5D, 0x05, 0x04, 0x91, 0x02, 0xB8, 0x01, 0xA2, 0xC0, 0x22, 0xC4, 0x99, 0xC0, 0x99, 0x13, 0x34, 0x41, 0xA5, 0xBB, 0x6D, 0xEC, 0xE9, 0x2C, 0xAA, 0xB9, 0x9D, 0x27, 0x8B, 0xD4, 0xE2, 0x94, 0xF9, 0x2D, 0x15, 0xAC, 0x26, 0xB4, 0x7F, 0x92, 0x5B, 0xCE, 0x04, 0x0D, 0x38, 0x79, 0x3F, 0xCD, 0x7D, 0x10, 0xDB, 0x94, 0x5C, 0x85, 0x5B, 0x42, 0xF3, 0x76, 0xE7, 0x24, 0xBB, 0xA6, 0x0B, 0xEC, 0x34, 0x69, 0x06, 0xA6, 0x83, 0xD5, 0x14, 0xD6, 0x5A, 0x01, 0x6B, 0xB4, 0xDD, 0xC9, 0xD1, 0x15, 0x40, 0x65, 0xE2, 0x82, 0x23, 0x69, 0x9C, 0x99, 0x53, 0x05, 0x59, 0xD4, 0x37, 0x95, 0x3A, 0x2C, 0x65, 0x6A, 0x31, 0xDE, 0xCB, 0x98, 0x3F, 0x38, 0x37, 0x2A, 0xDB, 0xB8, 0x43, 0xED, 0x05, 0x58, 0x03, 0x2E, 0x80, 0x05, 0xA0, 0x03, 0x05, 0x2C, 0x99, 0x07, 0xD8, 0x13, 0xB3, 0x6B, 0x6D, 0xB8, 0xE1, 0x11, 0x36, 0x69, 0x4A, 0xF3, 0x62, 0x38, 0x36, 0xA4, 0xBC, 0x4E, 0xA1, 0xA4, 0x40, 0xF1, 0xE0, 0x02, 0x8A, 0xAE, 0x90, 0xA3, 0x80, 0xCF, 0x56, 0xF8, 0x34, 0xEA, 0x77, 0x66, 0x47, 0xBB, 0xF1, 0xF2, 0x50, 0x1E, 0x6D, 0xC6, 0x73, 0x8A, 0x67, 0xF3, 0xEC, 0xB4, 0xE4, 0x3C, 0xDF, 0x12, 0xA7, 0xAC, 0x02, 0x76, 0xB3, 0xF5, 0x58, 0x00, 0x5B, 0x00, 0x6B, 0x20, 0xED, 0x6E, 0xB8, 0x30, 0x59, 0x36, 0x1C, 0x21, 0x4F, 0x7A, 0xAE, 0xD5, 0x78, 0x70, 0xF2, 0x7A, 0x2A, 0xF8, 0x25, 0x40, 0x60, 0xDC, 0x40, 0x33, 0x71, 0xD0, 0x15, 0x28, 0x9D, 0x5E, 0x3E, 0x80, 0x10, 0x18, 0x05, 0xBF, 0xDB, 0x06, 0x20, 0xC0, 0xBD, 0x38, 0xED, 0xA9, 0x2D, 0xAE, 0x68, 0xDC, 0xAA, 0xC3, 0xD0, 0x99, 0x24, 0x1B, 0xFF, 0xBC, 0x16, 0x9D, 0xF4, 0x30, 0x14, 0xDD, 0xFD, 0xA8, 0xDC, 0xBF, 0x18, 0x03, 0xB5, 0xAF, 0x89, 0xA5, 0x34, 0x37, 0x55, 0x36, 0xE3, 0x82, 0x6A, 0x69, 0x26, 0xDE, 0xDF, 0x71, 0x96, 0x1C, 0x59, 0x28, 0xFE, 0x02, 0x14, 0x2F, 0x6E, 0x99, 0xE2, 0x59, 0x82, 0x6F, 0xD8, 0x8E, 0x9F, 0xD5, 0x1C, 0x2D, 0x40, 0x6E, 0x97, 0x75, 0x1B, 0xC9, 0x7C, 0x71, 0x53, 0x85, 0x25, 0xB1, 0xE7, 0x11, 0xC8, 0x49, 0x6C, 0x22, 0xE3, 0x04, 0xB5, 0x9A, 0x0B, 0xA8, 0xCD, 0x46, 0x8B, 0x05, 0x48, 0x03, 0x5A, 0x80, 0x05, 0x10, 0x0A, 0x94, 0x5C, 0x60, 0xFF, 0x9B, 0x31, 0x73, 0x0C, 0x5A, 0x9F, 0x2A, 0x3C, 0x7C, 0x0F, 0x21, 0x0E, 0x97, 0x66, 0x83, 0x55, 0x64, 0x87, 0x40, 0xB8, 0xC9, 0x64, 0x31, 0x9E, 0x3E, 0xB9, 0x7D, 0x66, 0x6F, 0xB9, 0xEC, 0xF1, 0xA1, 0xDE, 0x44, 0x10, 0x6E, 0x6F, 0xA7, 0x8E, 0xAC, 0x8F, 0x54, 0xB4, 0x01, 0x15, 0xA0, 0xD7, 0x7B, 0xA6, 0x4C, 0xA6, 0xAA, 0x4D, 0x19, 0x33, 0xA1, 0x40, 0x34, 0x7F, 0xB6, 0xAE, 0x35, 0x77, 0x4E, 0x51, 0xDB, 0x9A, 0xD2, 0x56, 0x42, 0xCF, 0x2D, 0x70, 0x15, 0xA0, 0x44, 0x7F, 0x5C, 0x6A, 0x54, 0x01, 0xB1, 0xD7, 0xAC, 0x46, 0x0B, 0x58, 0xF2, 0x31, 0x6B, 0x3A, 0x51, 0xC3, 0x7A, 0x60, 0x6B, 0x4F, 0xD4, 0xE0, 0x05, 0x13, 0xFE, 0xB4, 0xAD, 0xF1, 0xAD, 0x28, 0xF0, 0xB3, 0x42, 0x2F, 0x36, 0x79, 0x45, 0x6F, 0xDF, 0x8F, 0xF3, 0xAD, 0x1E, 0xFF, 0x6C, 0x69, 0xA0, 0x89, 0x2C, 0xE0, 0x74, 0xA0, 0x90, 0x4F, 0x0C, 0x89, 0xEA, 0xD7, 0xA1, 0xFB, 0x94, 0x88, 0x3A, 0x22, 0x23, 0xC5, 0xDD, 0xD5, 0x89, 0xA1, 0x12, 0x7E, 0xE5, 0x62, 0x2C, 0xCA, 0x6F, 0xAB, 0x5E, 0xA8, 0xE5, 0x28, 0x7B, 0xCA, 0xD9, 0x8A, 0xE6, 0x1A, 0x32, 0x81, 0xEC, 0xD7, 0x92, 0x38, 0x64, 0xDC, 0x9D, 0x81, 0xCD, 0x17, 0xCB, 0x01, 0xF5, 0xFB, 0xC8, 0x4F, 0x44, 0x4D, 0xAE, 0xB5, 0x66, 0xD2, 0x6D, 0x3F, 0x73, 0xA2, 0x36, 0xB8, 0xA2, 0xF7, 0xDE, 0x0D, 0xF9, 0x76, 0xA5, 0x40, 0xBE, 0xDD, 0x71, 0xA3, 0x76, 0x8B, 0xF1, 0xF2, 0x53, 0xF8, 0xA9, 0x6F, 0xA7, 0xA6, 0xFA, 0x64, 0xDF, 0xAA, 0x4C, 0x7C, 0x5F, 0x21, 0x52, 0x4F, 0x28, 0x81, 0xE0, 0x99, 0xA7, 0x89, 0xE5, 0x19, 0x56, 0x84, 0x13, 0x02, 0x1C, 0x7B, 0xBE, 0x49, 0x77, 0xB4, 0xA7, 0x6A, 0xC6, 0x8F, 0xDD, 0x57, 0xD9, 0x3C, 0x8A, 0x81, 0x1C, 0x5D, 0x51, 0x26, 0x63, 0x04, 0x68, 0xA2, 0x88, 0xD1, 0x2A, 0xDB, 0x01, 0xAB, 0xD7, 0x65, 0xA4, 0x64, 0xA2, 0x56, 0x7C, 0xEA, 0xE6, 0x7F, 0x65, 0xD4, 0xBE, 0x7F, 0xB6, 0xC1, 0xFB, 0xD9, 0xDE, 0xDB, 0x52, 0x48, 0x98, 0xF2, 0x0D, 0xAB, 0x40, 0xAD, 0x99, 0xD5, 0xBE, 0x3A, 0xC7, 0xCE, 0x4F, 0x3B, 0xAE, 0xC9, 0xA5, 0x74, 0x20, 0x79, 0x24, 0x93, 0x99, 0xFB, 0xDD, 0x2F, 0x99, 0x7D, 0x96, 0xFD, 0x16, 0xA5, 0x7A, 0xF0, 0x7D, 0xFA, 0xAA, 0xB8, 0xB9, 0x01, 0x17, 0x40, 0x14, 0xF0, 0x11, 0x9E, 0x6C, 0x7D, 0x8C, 0xB2, 0x74, 0x1E, 0x6B, 0x9C, 0xE0, 0xCD, 0x90, 0x13, 0x20, 0x94, 0xB2, 0x85, 0x4E, 0x76, 0x08, 0x50, 0x49, 0xF0, 0x68, 0x04, 0x8E, 0x4E, 0x20, 0x16, 0x50, 0xC2, 0x53, 0x7A, 0xA2, 0xD6, 0x63, 0xCE, 0xFA, 0xBB, 0x65, 0x2A, 0x8B, 0x54, 0x76, 0x2B, 0xBA, 0x27, 0x6C, 0x43, 0x8A, 0x4A, 0x42, 0xEE, 0xA8, 0x9D, 0x68, 0x30, 0xE3, 0xF5, 0x4C, 0xD4, 0xEA, 0xA9, 0x67, 0x87, 0x90, 0x3E, 0xAA, 0xEA, 0x9B, 0x32, 0xDD, 0x05, 0x50, 0xC3, 0x20, 0x7E, 0xF2, 0x12, 0xB0, 0x1B, 0x30, 0xAA, 0xB1, 0x5E, 0x38, 0x25, 0xE5, 0xED, 0x78, 0xEF, 0x39, 0x8D, 0x6D, 0x00, 0x7D, 0x84, 0x94, 0xC5, 0xBC, 0x36, 0x1B, 0x73, 0x5F, 0xCE, 0x44, 0xE4, 0x74, 0xBA, 0x55, 0xDA, 0xF1, 0xE4, 0xBE, 0x9B, 0xF7, 0x8C, 0x8F, 0x25, 0x01, 0x85, 0x0C, 0x65, 0x34, 0x84, 0x07, 0x60, 0x0A, 0xEC, 0x02, 0xD6, 0x02, 0x64, 0xFA, 0x88, 0xCE, 0x50, 0x3B, 0xFE, 0xC6, 0x46, 0x7B, 0x8C, 0x8D, 0xCD, 0x58, 0xAB, 0x33, 0xD4, 0xE4, 0x47, 0x2C, 0xA0, 0x76, 0xF6, 0x6F, 0x32, 0x96, 0xB2, 0x5E, 0x49, 0x2D, 0x26, 0x6A, 0x4F, 0xE7, 0xB9, 0xBD, 0x7E, 0x64, 0xCD, 0x3C, 0xB1, 0xEF, 0x66, 0xD1, 0x3E, 0xD6, 0x7B, 0x1A, 0xE3, 0xDC, 0xF7, 0x3A, 0x3F, 0xC7, 0xA8, 0xBF, 0x72, 0x3D, 0xD2, 0x68, 0x79, 0xDE, 0xE7, 0x21, 0xAD, 0xB7, 0xDF, 0x18, 0x13, 0x8A, 0x6F, 0xF3, 0x3D, 0xCC, 0x4F, 0x31, 0x8E, 0x6A, 0xEA, 0xE8, 0xAE, 0xED, 0x85, 0xF1, 0x68, 0xB2, 0x43, 0x19, 0x43, 0x0D, 0x00, 0x49, 0x00, 0xC4, 0x02, 0x96, 0xE1, 0x67, 0xB1, 0x01, 0x09, 0xC0, 0x79, 0x8A, 0xD7, 0x44, 0x6D, 0xD3, 0x45, 0xB6, 0xF0, 0x14, 0x68, 0x47, 0xB1, 0x85, 0x26, 0x3A, 0x23, 0x34, 0x84, 0x8D, 0x93, 0x39, 0xB7, 0x0C, 0x59, 0x75, 0xB6, 0xB9, 0x18, 0xF8, 0xA6, 0x44, 0xC6, 0xED, 0x75, 0x81, 0x9B, 0xC6, 0xEB, 0x70, 0x98, 0xB3, 0xD3, 0xF6, 0xF6, 0x65, 0x53, 0x79, 0x2F, 0xDE, 0xF2, 0xD7, 0xA3, 0x5D, 0x79, 0xA4, 0x73, 0xB5, 0x17, 0x60, 0x0A, 0x68, 0x01, 0x22, 0xC0, 0x47, 0x59, 0xF3, 0xE3, 0xD2, 0x33, 0x6E, 0x3B, 0x4D, 0xE5, 0xFF, 0x0C, 0x40, 0x01, 0x22, 0x11, 0x4A, 0x63, 0x28, 0x95, 0x28, 0x07, 0xB2, 0x01, 0x57, 0x60, 0xD2, 0x75, 0x33, 0x80, 0x9E, 0x33, 0xB9, 0xFC, 0xE4, 0x5E, 0x53, 0x66, 0x6F, 0xE4, 0x3E, 0xEC, 0x84, 0x68, 0x27, 0xFB, 0x49, 0xEA, 0x70, 0x69, 0x68, 0x44, 0x95, 0xAC, 0x84, 0xF5, 0xDF, 0xF3, 0x5F, 0xDE, 0x5E, 0xD0, 0x21, 0x4C, 0x48, 0x9F, 0x7A, 0xF2, 0xED, 0xD4, 0xFC, 0x04, 0xF0, 0x9A, 0x54, 0xB2, 0x7B, 0x5B, 0xC1, 0xF6, 0x15, 0xD6, 0xA9, 0x01, 0x78, 0x4E, 0x8F, 0xC1, 0xAB, 0x81, 0xED, 0x93, 0xE1, 0xD7, 0x06, 0x78, 0x00, 0xC5, 0x37, 0x2C, 0xE7, 0x29, 0x35, 0x42, 0xF6, 0x74, 0x94, 0xFF, 0xAB, 0x34, 0x0A, 0x3E, 0x03, 0x72, 0x3A, 0x58, 0x32, 0x7B, 0xBA, 0x04, 0x67, 0x16, 0xF6, 0x46, 0xB1, 0x1D, 0x1F, 0x40, 0x2B, 0x1B, 0xD1, 0x16, 0x60, 0x44, 0x26, 0xF6, 0xE8, 0x97, 0x03, 0xBA, 0x80, 0xF2, 0x89, 0x99, 0x72, 0x17, 0x20, 0x90, 0x3D, 0xD2, 0x4C, 0x8F, 0x6C, 0x79, 0x1A, 0xB5, 0x2F, 0x11, 0xA6, 0x04, 0x6E, 0x2E, 0x0D, 0x37, 0x7A, 0x18, 0xAC, 0x29, 0xCF, 0x06, 0xE7, 0xE6, 0xDD, 0x42, 0xCD, 0x39, 0x66, 0xB1, 0xBD, 0x00, 0x99, 0xEF, 0x7F, 0x04, 0xB5, 0x53, 0xB0, 0xCE, 0x2B, 0x6A, 0x01, 0xD3, 0xDD, 0x3E, 0x9D, 0x67, 0xEE, 0x4F, 0x5C, 0x1B, 0xD0, 0x0D, 0xEC, 0x62, 0x24, 0x1F, 0xA5, 0xD1, 0xCF, 0x46, 0xCA, 0x69, 0x02, 0xCA, 0xC5, 0xF6, 0xB4, 0x43, 0xB5, 0xBC, 0xD5, 0x64, 0x4C, 0xB9, 0x09, 0x6E, 0x1A, 0x07, 0x9E, 0x19, 0x28, 0xBA, 0x6A, 0x40, 0xF2, 0x3D, 0xBA, 0x99, 0x22, 0x78, 0x31, 0x31, 0x5D, 0x5E, 0x32, 0x41, 0x9B, 0x55, 0x01, 0x73, 0x97, 0x3A, 0xB1, 0x69, 0xD6, 0xCE, 0x17, 0x67, 0x49, 0xC3, 0x59, 0x7A, 0x0A, 0x25, 0x63, 0xFD, 0x4D, 0xA0, 0x8C, 0x4B, 0x75, 0x05, 0x7A, 0xDD, 0x36, 0x64, 0x93, 0x0C, 0x6D, 0x54, 0x3B, 0x6C, 0x9F, 0xD9, 0xBD, 0xE3, 0x83, 0x5D, 0x1B, 0xE9, 0x37, 0x6D, 0xCF, 0x0D, 0xD8, 0xC4, 0x68, 0x6E, 0x9D, 0x53, 0x72, 0x0D, 0x48, 0x00, 0xA1, 0x00, 0x34, 0x6D, 0x7E, 0xBE, 0x29, 0x61, 0x35, 0x67, 0xFA, 0xDD, 0x74, 0xFD, 0x9F, 0xA4, 0x97, 0x3D, 0x29, 0x1E, 0x4C, 0xEA, 0x40, 0x08, 0x90, 0xC6, 0xC1, 0x05, 0x95, 0x0A, 0x50, 0xEC, 0x40, 0xB3, 0x0D, 0xB0, 0x0D, 0xD4, 0xE2, 0xBA, 0xAA, 0x00, 0x37, 0xA0, 0xF7, 0xC4, 0xCC, 0x99, 0x17, 0xA0, 0x78, 0xD4, 0xC8, 0x86, 0xCC, 0xBE, 0x8C, 0x3B, 0xB7, 0xD8, 0xAD, 0xDA, 0x52, 0xFC, 0xCF, 0x20, 0x88, 0x6C, 0x68, 0x43, 0x19, 0x93, 0x95, 0x00, 0x84, 0x1D, 0x9F, 0x10, 0x0A, 0xA9, 0xBC, 0x0B, 0x6C, 0x01, 0xCC, 0x99, 0xE0, 0x29, 0x08, 0xC8, 0x14, 0x5E, 0x8F, 0x0A, 0x34, 0xCD, 0xDF, 0x6B, 0xE3, 0x88, 0xB2, 0x3E, 0x00, 0x75, 0x85, 0x13, 0x52, 0x03, 0x64, 0xE0, 0xC0, 0x0E, 0xE0, 0x71, 0x85, 0x53, 0xAE, 0xD1, 0x8D, 0x3B, 0x2B, 0x3E, 0x8B, 0x6C, 0x8A, 0xE5, 0xC1, 0x85, 0xD1, 0xAD, 0x5A, 0xAC, 0x19, 0x6E, 0x3A, 0xF5, 0x78, 0x80, 0x6C, 0x22, 0x00, 0x15, 0xC0, 0x14, 0x80, 0x6A, 0x59, 0xF7, 0xE1, 0x19, 0xD0, 0xD3, 0x14, 0xD2, 0x90, 0x51, 0x36, 0x30, 0x9D, 0x1C, 0xEF, 0x29, 0x64, 0x4E, 0x04, 0xAB, 0x37, 0x5B, 0x2F, 0xE4, 0xA9, 0x1F, 0x80, 0x36, 0x7B, 0x45, 0x48, 0xEC, 0x75, 0x4E, 0x8A, 0xC4, 0xC8, 0xDC, 0x80, 0xAF, 0xAB, 0x5A, 0xAF, 0xB3, 0xBD, 0xE9, 0xF6, 0x26, 0xAA, 0x8B, 0xE2, 0x45, 0x99, 0xBD, 0x6C, 0x99, 0x4B, 0x9C, 0x96, 0x0F, 0x0D, 0x08, 0xEF, 0xF4, 0xBD, 0x01, 0xE7, 0xCF, 0xF6, 0x1A, 0x4F, 0x0A, 0xDE, 0x41, 0x95, 0x23, 0xBA, 0x79, 0xCD, 0x08, 0xD7, 0xFF, 0xF2, 0xE9, 0x32, 0x4E, 0xE9, 0x4C, 0x92, 0x4B, 0xFD, 0x05, 0x54, 0x00, 0xBD, 0x81, 0x74, 0xC0, 0x08, 0x69, 0xC0, 0xA8, 0x06, 0x9B, 0x4E, 0xD0, 0x26, 0x3E, 0xCC, 0x1E, 0xDB, 0x1B, 0x5A, 0xBB, 0x3B, 0x1E, 0x76, 0xB5, 0x71, 0x55, 0x2E, 0xC7, 0x42, 0x3C, 0x02, 0x5B, 0x04, 0xAE, 0xBF, 0x81, 0xC6, 0xA0, 0x75, 0x7E, 0x93, 0x95, 0xA7, 0x38, 0x7F, 0x31, 0xEF, 0xD6, 0x1B, 0xD0, 0xF8, 0xC7, 0x1D, 0x2D, 0xFA, 0xDD, 0x1A, 0x76, 0xBE, 0x68, 0x73, 0x63, 0xDB, 0x80, 0xEE, 0xB7, 0x6D, 0xE8, 0x5A, 0x80, 0x2A, 0xE0, 0xC9, 0x33, 0x85, 0xC2, 0xE6, 0xAC, 0xFC, 0xA9, 0x3E, 0x5A, 0x31, 0x7F, 0x6F, 0x61, 0x6C, 0x49, 0x71, 0xC4, 0x70, 0x05, 0xBF, 0x99, 0xB1, 0x25, 0xCD, 0x12, 0xD3, 0x0D, 0x68, 0x03, 0x41, 0xCC, 0xC5, 0x2D, 0x0E, 0x84, 0x01, 0xE5, 0x5C, 0xDD, 0xAF, 0x09, 0x5A, 0x4D, 0xD0, 0x70, 0x05, 0xB2, 0x19, 0xBB, 0x6B, 0xF0, 0x45, 0x86, 0x37, 0x84, 0xF3, 0xC1, 0x64, 0x95, 0x7B, 0xDD, 0xAA, 0x6C, 0xD5, 0x59, 0xE3, 0xDC, 0xFC, 0x93, 0xD1, 0xF1, 0x4D, 0x39, 0xB9, 0x34, 0x96, 0x86, 0xCB, 0xD1, 0x9B, 0x95, 0x57, 0xD2, 0xA4, 0x17, 0xDB, 0x06, 0x16, 0x07, 0xF8, 0xDE, 0x1C, 0x29, 0x06, 0xCC, 0xA4, 0x49, 0xA8, 0xB5, 0xB5, 0xBD, 0x13, 0x2A, 0x2F, 0x9C, 0xD2, 0x9C, 0xBE, 0x16, 0x73, 0x09, 0x1D, 0xF2, 0x18, 0x53, 0xD8, 0x92, 0xC9, 0x79, 0xAC, 0x70, 0x29, 0x9A, 0xDF, 0x55, 0x1F, 0x89, 0xA8, 0x79, 0xF3, 0x8A, 0x78, 0x45, 0x21, 0x5D, 0xEF, 0xCD, 0xAB, 0x1A, 0x6A, 0x90, 0x2E, 0xC0, 0x0A, 0xE8, 0x13, 0xB3, 0xC6, 0xA3, 0xDA, 0x67, 0xD1, 0xC9, 0x6B, 0xDC, 0xFD, 0xB5, 0xBC, 0xDD, 0xCE, 0x3A, 0xCC, 0x44, 0xAB, 0x19, 0xB8, 0x6D, 0x96, 0x7E, 0x53, 0x87, 0x64, 0xBF, 0xBB, 0xC5, 0x29, 0x6F, 0xA5, 0x4A, 0xE6, 0xF5, 0x3E, 0x42, 0x91, 0xC7, 0x9B, 0x7C, 0xB6, 0xDF, 0xC5, 0xD4, 0x12, 0x1C, 0x4D, 0x3D, 0x5A, 0x4E, 0xDE, 0x20, 0xB1, 0x12, 0x10, 0x25, 0x1A, 0x98, 0x42, 0x8C, 0xDD, 0x27, 0x9D, 0x93, 0xD3, 0x16, 0x3E, 0x3F, 0xE6, 0x7E, 0xA7, 0x3E, 0xA6, 0x7D, 0xEF, 0x24, 0x0D, 0x33, 0x55, 0x63, 0xEC, 0x21, 0x62, 0x00, 0x36, 0xD5, 0x50, 0x80, 0xF2, 0xCC, 0x1E, 0xB9, 0x73, 0xE3, 0x94, 0xA3, 0xDC, 0x8E, 0x43, 0x6A, 0x28, 0x2A, 0x80, 0x43, 0x7E, 0xEA, 0x5E, 0x2F, 0x7D, 0xBA, 0xDB, 0xAF, 0x74, 0xDE, 0x77, 0x7E, 0xC1, 0xDB, 0xAA, 0x39, 0xFD, 0x1C, 0xDE, 0x74, 0x8E, 0xF9, 0xB8, 0x7E, 0xD5, 0xC8, 0xD3, 0xD6, 0x49, 0x8F, 0x71, 0xB4, 0x70, 0x51, 0xD4, 0xF6, 0x6C, 0x5F, 0xFA, 0x06, 0x24, 0x81, 0xE8, 0x77, 0x0E, 0xBC, 0xE4, 0x2D, 0x1F, 0x15, 0x01, 0xB4, 0x01, 0xCB, 0x3B, 0xF9, 0x9D, 0x26, 0x06, 0xB3, 0xA7, 0xA9, 0x53, 0x05, 0x30, 0xBD, 0xD9, 0x8D, 0x22, 0xFF, 0xF4, 0xBA, 0xE7, 0xA2, 0x3C, 0x36, 0xE7, 0x16, 0xC2, 0x6B, 0xF6, 0xF7, 0xC0, 0x02, 0x24, 0x89, 0x79, 0x51, 0x81, 0x15, 0x80, 0x1A, 0xAF, 0xF5, 0x35, 0x41, 0xDB, 0xB4, 0xEC, 0x18, 0x71, 0x88, 0x49, 0x9A, 0xED, 0x8F, 0x6B, 0xFC, 0xD2, 0x8D, 0x6B, 0x4F, 0xED, 0x37, 0x11, 0xDF, 0x7E, 0x9F, 0x00, 0xB7, 0xB0, 0x6C, 0x7F, 0x1A, 0xFC, 0xAC, 0x60, 0x2C, 0x14, 0x47, 0x45, 0xAC, 0x78, 0xDB, 0xA9, 0xA9, 0x4D, 0x7E, 0x19, 0xE0, 0x09, 0xD4, 0x22, 0xEC, 0x66, 0xB7, 0x5D, 0x99, 0xC3, 0xDE, 0xA1, 0xA6, 0x3F, 0xE8, 0xFC, 0xCE, 0xF1, 0xFD, 0x9D, 0x67, 0xAA, 0x9D, 0x92, 0x84, 0xE4, 0x85, 0xBD, 0xE3, 0x55, 0x2E, 0x75, 0xEE, 0x12, 0x8D, 0xC9, 0x90, 0x4F, 0xF5, 0xC1, 0x26, 0x0C, 0x58, 0x82, 0x9F, 0xC5, 0x02, 0x34, 0x80, 0xE0, 0x29, 0xA9, 0x13, 0x35, 0xC1, 0x3E, 0x5B, 0xCB, 0xEF, 0x16, 0xB0, 0x2C, 0xB9, 0x51, 0x2A, 0x28, 0x66, 0xEA, 0x80, 0x34, 0xE5, 0xCD, 0xEE, 0x01, 0x85, 0xEE, 0xD2, 0x4C, 0x82, 0xA9, 0xEF, 0x26, 0x9E, 0x4C, 0x10, 0x66, 0x21, 0x9D, 0x3A, 0x3D, 0x61, 0x6F, 0xB5, 0xEF, 0x3E, 0x45, 0xA9, 0x12, 0x4F, 0x37, 0xA8, 0x4E, 0xE0, 0xAD, 0xA9, 0xAA, 0xC9, 0xD5, 0x00, 0xEE, 0x2A, 0xCA, 0x89, 0x20, 0xF2, 0xB1, 0x9E, 0xDB, 0xEB, 0x18, 0x73, 0xCF, 0xFE, 0xD7, 0xE2, 0xF5, 0x16, 0xFB, 0xDA, 0x15, 0xB2, 0x94, 0xC2, 0x78, 0x7B, 0x32, 0x24, 0xF5, 0x41, 0x90, 0x2E, 0xA0, 0x65, 0xD1, 0xFF, 0x86, 0x47, 0x44, 0x34, 0xE0, 0xF9, 0x2E, 0xF8, 0x43, 0x26, 0x6A, 0xCA, 0xC4, 0x30, 0xB6, 0x12, 0x89, 0xC0, 0xAD, 0x59, 0xF6, 0x4F, 0xC8, 0x96, 0x16, 0xCC, 0xA6, 0x82, 0x66, 0xB7, 0x6D, 0x58, 0x3B, 0x98, 0x8C, 0x9B, 0xC9, 0x6B, 0x9F, 0xC3, 0x0F, 0x71, 0xD2, 0x66, 0x4E, 0x5D, 0xDB, 0x94, 0xBE, 0xE9, 0x35, 0x4B, 0x9E, 0x44, 0x15, 0xDC, 0x7F, 0xB1, 0xB4, 0x67, 0xDF, 0x8B, 0x4F, 0x17, 0xA8, 0xC5, 0xA0, 0x4D, 0xB6, 0xAE, 0xDA, 0xAB, 0x37, 0xAD, 0x00, 0xF6, 0x0C, 0xDF, 0xA9, 0xC8, 0x9A, 0x7E, 0x41, 0x33, 0x41, 0x5C, 0x1C, 0x16, 0x45, 0x81, 0x02, 0xC9, 0x8B, 0x42, 0x60, 0xFC, 0xA2, 0xE4, 0x80, 0x93, 0xB9, 0x95, 0x40, 0x1A, 0xD0, 0x0B, 0xA8, 0x0D, 0x44, 0x03, 0x4E, 0x14, 0x27, 0x1D, 0x47, 0x1B, 0x9A, 0x0E, 0x0E, 0xBC, 0x32, 0x2B, 0x05, 0x77, 0xCA, 0x4E, 0x48, 0x09, 0x99, 0x50, 0x06, 0x5A, 0xB1, 0x3B, 0xE9, 0xC2, 0xBD, 0xB8, 0x1C, 0x9B, 0x89, 0x37, 0x2F, 0x21, 0x6F, 0x2E, 0xD5, 0x18, 0x52, 0xC9, 0x34, 0x57, 0xDF, 0x47, 0xEC, 0xB3, 0xD1, 0x03, 0xA7, 0x0C, 0x74, 0x8F, 0x71, 0x39, 0xA0, 0x8B, 0x48, 0x60, 0x24, 0xA2, 0x31, 0xFC, 0x12, 0x86, 0xB7, 0x37, 0x8F, 0x14, 0x30, 0xBD, 0xCE, 0xDF, 0x53, 0xCE, 0xC9, 0xE9, 0x89, 0x29, 0xB7, 0x68, 0x98, 0xC8, 0x1E, 0xCA, 0x0D, 0xF4, 0x04, 0x12, 0x55, 0xD7, 0xD8, 0x36, 0x50, 0xA0, 0x13, 0x33, 0x0A, 0x5D, 0x80, 0x3B, 0x90, 0x9C, 0x5F, 0x2C, 0x01, 0x74, 0x10, 0x80, 0xC7, 0x04, 0xCD, 0x9F, 0xC6, 0xF6, 0xBB, 0x9B, 0x2D, 0x7A, 0xFC, 0x3F, 0xEC, 0xA6, 0x34, 0x1E, 0x1A, 0x9A, 0x58, 0x27, 0x54, 0xB2, 0x60, 0xDE, 0x27, 0x7B, 0x83, 0x12, 0xD1, 0xEB, 0x6E, 0xE5, 0xFB, 0xD4, 0xD7, 0xDE, 0x69, 0xBC, 0x9D, 0xC5, 0xB5, 0x8F, 0xC9, 0x72, 0xDC, 0x9C, 0x47, 0x3B, 0x09, 0x8D, 0x53, 0xB6, 0x6F, 0x4F, 0x67, 0x58, 0xEE, 0xAA, 0xF7, 0x29, 0x71, 0x6F, 0x7B, 0xCD, 0xFB, 0x7D, 0xF1, 0x94, 0x98, 0xCD, 0x51, 0x39, 0xF9, 0x64, 0x67, 0x23, 0xDC, 0xAF, 0x63, 0xC7, 0x19, 0x0E, 0x37, 0x43, 0x9F, 0xAE, 0xA7, 0xF9, 0xBB, 0xA2, 0x00, 0x4F, 0xA0, 0x1D, 0xB3, 0x15, 0x5D, 0x40, 0x14, 0x12, 0xEE, 0xB7, 0x00, 0x1A, 0x40, 0xAE, 0x09, 0x5A, 0x3C, 0x1B, 0x76, 0x52, 0x86, 0x89, 0x65, 0xBD, 0x22, 0xC7, 0x8A, 0xC2, 0xF4, 0x76, 0x37, 0xD6, 0xCF, 0x4B, 0x70, 0xE9, 0xDE, 0xCA, 0x95, 0xBB, 0x8E, 0x1A, 0xCF, 0xA1, 0x69, 0x29, 0x24, 0x3A, 0xB9, 0x99, 0x54, 0xD8, 0x7F, 0x70, 0xC4, 0x45, 0xE4, 0x74, 0x64, 0xDF, 0x53, 0x85, 0x59, 0x80, 0x4C, 0x87, 0x91, 0xE9, 0x27, 0x30, 0xDB, 0xC4, 0xFE, 0x3A, 0x17, 0xAC, 0x0D, 0xE0, 0xCC, 0x31, 0x03, 0x9F, 0x4C, 0x04, 0xE7, 0x02, 0x8A, 0x7F, 0x36, 0xD8, 0xAE, 0x24, 0x99, 0xF1, 0x58, 0xDC, 0x6C, 0xBE, 0x13, 0xB6, 0x48, 0x6E, 0x22, 0x19, 0x17, 0x9D, 0x05, 0xB8, 0x01, 0xC9, 0xD5, 0xE6, 0x4E, 0xC0, 0x1D, 0x88, 0xE2, 0x9E, 0xDE, 0x89, 0x19, 0x97, 0x04, 0xAC, 0x9E, 0x5A, 0xE5, 0x94, 0x5F, 0x02, 0x3D, 0x80, 0x76, 0x62, 0x49, 0xB0, 0x37, 0xB6, 0x1C, 0xC6, 0xD4, 0xDB, 0xFC, 0x89, 0x99, 0x01, 0x11, 0xD7, 0x1A, 0x5E, 0xC6, 0xB4, 0x78, 0x7A, 0xA6, 0xCC, 0xA8, 0xE3, 0x55, 0x29, 0xDC, 0x0A, 0x12, 0x39, 0xD5, 0xA9, 0x5F, 0xB1, 0x7E, 0x05, 0xC1, 0x4B, 0xFC, 0x6B, 0x99, 0x27, 0x0A, 0xB8, 0x01, 0x39, 0xB5, 0x02, 0x63, 0x8F, 0x38, 0x66, 0xCE, 0xDC, 0x45, 0xEF, 0x62, 0xB9, 0x8E, 0xDC, 0x65, 0x66, 0x73, 0xA0, 0x20, 0x3C, 0x98, 0xEE, 0x13, 0x6D, 0x9C, 0xE7, 0xFB, 0x67, 0xFB, 0x2E, 0x81, 0xDE, 0xD8, 0xB7, 0x93, 0x41, 0x03, 0xEE, 0x13, 0xB3, 0xA2, 0x54, 0x2A, 0x48, 0x82, 0x2C, 0x4E, 0xCD, 0xBD, 0x9F, 0x9A, 0xCF, 0x70, 0xE3, 0xB7, 0x29, 0xEC, 0xD2, 0x50, 0x93, 0x87, 0xF0, 0x5A, 0xCF, 0x4D, 0xF7, 0xA6, 0x98, 0xAA, 0xFE, 0x09, 0xCC, 0x9E, 0x0C, 0x96, 0x37, 0x01, 0x66, 0xA6, 0xCC, 0x4D, 0x41, 0xDC, 0x37, 0xB0, 0x08, 0x35, 0x60, 0x9C, 0x65, 0x72, 0x8C, 0x53, 0x8B, 0x0A, 0xA8, 0x00, 0xB9, 0x81, 0x38, 0x1B, 0x75, 0xFC, 0x7B, 0xC7, 0x44, 0x9E, 0xC5, 0x9E, 0xCF, 0xA2, 0x93, 0x0F, 0xA1, 0xD8, 0xA7, 0x3C, 0x2C, 0x37, 0x6F, 0x73, 0x94, 0x89, 0x96, 0x02, 0x21, 0x40, 0x1A, 0x10, 0x0D, 0xB8, 0x02, 0x56, 0x40, 0xFC, 0x10, 0x38, 0x42, 0xD0, 0x9A, 0xFF, 0xEE, 0x34, 0xB8, 0x1F, 0x3D, 0xAA, 0x1E, 0x93, 0xFD, 0x10, 0x67, 0xE6, 0x3D, 0x8D, 0x5A, 0x2A, 0x9E, 0x54, 0xC8, 0x00, 0x71, 0xAF, 0x7E, 0x6D, 0xD4, 0x3A, 0x19, 0x19, 0x9D, 0x7D, 0xC6, 0xB7, 0x24, 0x9D, 0x1D, 0x66, 0xF6, 0x4D, 0xA6, 0xBD, 0x0E, 0xB8, 0xB2, 0x6F, 0x6B, 0x42, 0x3B, 0x5B, 0x9F, 0xA9, 0x80, 0x3A, 0x10, 0x0A, 0xCC, 0x06, 0xEA, 0x35, 0x55, 0xE5, 0x6A, 0xF5, 0xE9, 0xBF, 0x3D, 0x15, 0x7A, 0xF6, 0x57, 0x20, 0x16, 0xAC, 0xC9, 0x63, 0x0C, 0x43, 0x18, 0xC3, 0x46, 0x0C, 0x4D, 0x01, 0xF7, 0xF7, 0x48, 0x16, 0xB0, 0x0C, 0xD8, 0x01, 0x34, 0x97, 0x04, 0xFB, 0xEE, 0xD7, 0x31, 0x6A, 0x14, 0xD2, 0x37, 0x92, 0x67, 0x8F, 0x89, 0x1B, 0xD7, 0x53, 0x11, 0x68, 0xCE, 0xD3, 0xCD, 0x82, 0xFF, 0xF7, 0x39, 0x60, 0x8F, 0xF8, 0xBC, 0xED, 0x18, 0x55, 0xDA, 0x14, 0xE2, 0x3F, 0x7D, 0x6E, 0x47, 0xA7, 0x3A, 0xA5, 0xB5, 0xC5, 0x68, 0xE5, 0xC7, 0xC0, 0x44, 0xCE, 0x76, 0x28, 0xE2, 0xE3, 0x84, 0x10, 0x5E, 0x00, 0x5D, 0x79, 0x88, 0xF1, 0xAC, 0x9D, 0x14, 0x3F, 0xE5, 0x05, 0xED, 0xBC, 0x95, 0xC6, 0x3E, 0x66, 0x4B, 0xFD, 0x03, 0x56, 0x9F, 0x58, 0xA3, 0xCF, 0x53, 0xF3, 0xB3, 0x1C, 0xDF, 0x05, 0x58, 0x02, 0xA5, 0xB8, 0x22, 0x77, 0x02, 0xAA, 0x40, 0xEC, 0x09, 0xDA, 0xFE, 0x06, 0x0D, 0xE9, 0xE2, 0x6D, 0x4F, 0xAE, 0x95, 0x9F, 0x94, 0xB2, 0x62, 0xB6, 0xAC, 0x9D, 0x9D, 0x4E, 0x4C, 0x03, 0xB8, 0x8E, 0x9A, 0x31, 0x82, 0x23, 0x3B, 0x7D, 0x78, 0x36, 0x07, 0x5C, 0xF9, 0xED, 0x50, 0xB4, 0x27, 0xE9, 0x76, 0xD2, 0xB6, 0x67, 0x8E, 0x1A, 0xF9, 0x06, 0x4D, 0x6D, 0x1A, 0xC5, 0x31, 0x4C, 0x06, 0x88, 0xBE, 0x47, 0x39, 0x71, 0xF5, 0x9B, 0xE0, 0x2D, 0x7A, 0x1A, 0x40, 0x08, 0x0B, 0x13, 0x4F, 0x36, 0x81, 0x43, 0x8B, 0x4C, 0xEA, 0xDB, 0xC5, 0xE4, 0x0E, 0xD9, 0x7C, 0x1E, 0x8C, 0x16, 0x99, 0x40, 0x35, 0xBB, 0x61, 0x17, 0x90, 0x46, 0x11, 0x52, 0x00, 0x73, 0xA0, 0x4E, 0xD0, 0x46, 0xD8, 0xE6, 0xAF, 0x8E, 0xC6, 0xA2, 0x75, 0xED, 0x47, 0xED, 0xDE, 0x2D, 0xEC, 0x50, 0x28, 0x98, 0xE5, 0xC7, 0x9E, 0x26, 0x9F, 0xEF, 0x4D, 0x4D, 0xEE, 0xC6, 0xE5, 0x68, 0x60, 0xC2, 0x25, 0x88, 0xAC, 0xA3, 0x96, 0x4D, 0x35, 0xC9, 0xD8, 0x40, 0xCF, 0x32, 0xB5, 0xA6, 0x2F, 0x12, 0xE1, 0x09, 0x40, 0x3B, 0x3D, 0xF3, 0xD7, 0x24, 0xF4, 0xDB, 0xED, 0xB5, 0x6E, 0x07, 0x90, 0x69, 0x34, 0x3C, 0xCF, 0xE7, 0x29, 0x41, 0x9F, 0xD5, 0x63, 0x3A, 0x05, 0x5C, 0x1A, 0x9E, 0x54, 0xE0, 0xC5, 0x1B, 0x34, 0x63, 0xB4, 0xB6, 0x01, 0x13, 0xC2, 0x0E, 0x0A, 0xB8, 0x02, 0x34, 0xC5, 0x8F, 0x1D, 0x80, 0xAF, 0x09, 0xDA, 0x2C, 0xCE, 0xF1, 0x5B, 0xDA, 0x0C, 0xD3, 0xB4, 0x9E, 0x48, 0x4E, 0x4E, 0xE9, 0x7C, 0x76, 0x9D, 0x65, 0xF8, 0x13, 0x34, 0x5F, 0x8B, 0x87, 0xDF, 0xEA, 0x7F, 0x3E, 0x29, 0xA3, 0x67, 0x21, 0x7D, 0xF7, 0x47, 0x82, 0x47, 0x94, 0x59, 0xAE, 0x6F, 0xED, 0x4A, 0x9A, 0x6E, 0xDC, 0xA5, 0x55, 0x9C, 0xDD, 0xA7, 0xB5, 0x67, 0x95, 0xCA, 0xA3, 0x05, 0x08, 0x2F, 0x6B, 0x9D, 0x7D, 0xD6, 0x93, 0x30, 0xC8, 0x94, 0xB4, 0xB9, 0x6F, 0x09, 0x47, 0x5A, 0x16, 0x82, 0x36, 0xCD, 0x13, 0xCB, 0x11, 0xB4, 0x95, 0xAF, 0xEA, 0xBD, 0xF5, 0x9D, 0x80, 0x2C, 0x05, 0xAC, 0x80, 0x36, 0x06, 0xAD, 0x01, 0x3F, 0x23, 0xCD, 0xFE, 0xEB, 0xDF, 0xA3, 0x7C, 0xB3, 0xA7, 0x74, 0xFF, 0x8F, 0xE9, 0x90, 0x7B, 0x05, 0xA2, 0xE5, 0x89, 0xA6, 0x87, 0xB9, 0x59, 0xE4, 0x83, 0x73, 0x7C, 0x86, 0xDA, 0xF2, 0x7B, 0xF5, 0xE8, 0x5F, 0xCA, 0xC6, 0x26, 0x0A, 0x10, 0x62, 0xD6, 0x90, 0x63, 0x82, 0xAE, 0x53, 0x72, 0xA1, 0x0C, 0x6C, 0xCE, 0xCC, 0x6E, 0xB6, 0x2A, 0xEF, 0x3D, 0x55, 0x74, 0x26, 0xC5, 0x27, 0xD9, 0x3B, 0xED, 0xD9, 0xE4, 0xAB, 0x78, 0xB7, 0xED, 0x5D, 0x3E, 0x69, 0x11, 0x45, 0x08, 0xE1, 0x53, 0xD3, 0x07, 0xF4, 0x9A, 0xFB, 0xC1, 0xEB, 0x6E, 0x54, 0x05, 0x68, 0x03, 0x4B, 0x00, 0xB1, 0x5B, 0xF8, 0x86, 0xA8, 0xF9, 0x37, 0x4E, 0xEF, 0xD1, 0xD8, 0x8F, 0x24, 0x97, 0xA7, 0x2D, 0xBF, 0x15, 0xB3, 0x76, 0xF0, 0xB9, 0xF9, 0x35, 0xB8, 0xDA, 0x94, 0xBF, 0xAE, 0xD1, 0xF9, 0x8D, 0x9A, 0x28, 0x60, 0x1B, 0x78, 0xCB, 0x0E, 0xEF, 0xEA, 0xB1, 0x0C, 0x91, 0x51, 0xC8, 0x8B, 0x80, 0x4D, 0xEF, 0x89, 0x38, 0xBD, 0xC6, 0x6B, 0x9A, 0x41, 0xF7, 0xEC, 0xD4, 0xE3, 0x49, 0xF2, 0x44, 0xCD, 0xCE, 0xF3, 0xA1, 0x0D, 0xD0, 0x02, 0x76, 0x12, 0x9B, 0x50, 0xC0, 0x92, 0xFF, 0xA0, 0x03, 0xDE, 0x80, 0x05, 0xB0, 0x47, 0x65, 0x09, 0x40, 0x05, 0xF0, 0xF9, 0x0C, 0x75, 0xA2, 0x16, 0x18, 0xA3, 0x22, 0x6F, 0xD4, 0xC6, 0x84, 0x5C, 0x37, 0x10, 0xC6, 0xAA, 0xB6, 0x7D, 0xEB, 0x65, 0x63, 0x7F, 0xCD, 0xD4, 0x56, 0xBE, 0xFD, 0x2B, 0x63, 0x01, 0xFD, 0x0D, 0x9E, 0x00, 0x31, 0x97, 0xD8, 0x3B, 0xB9, 0x5B, 0xAC, 0xA5, 0x19, 0xEB, 0x59, 0xFB, 0xCB, 0x6E, 0x17, 0x4E, 0x5B, 0x8D, 0xBB, 0x9B, 0xE3, 0xD0, 0xF2, 0x03, 0x57, 0x5E, 0xFD, 0x69, 0xAB, 0x14, 0x88, 0xDA, 0x2D, 0xE6, 0xB3, 0x02, 0xA4, 0x09, 0x25, 0xE2, 0x75, 0xE8, 0x97, 0x02, 0x92, 0x47, 0x5E, 0x80, 0x4C, 0x09, 0xAF, 0x01, 0xD6, 0xC0, 0x3D, 0x65, 0xA2, 0x96, 0x13, 0xA7, 0xE7, 0xEE, 0xE6, 0x11, 0x18, 0x07, 0x59, 0x54, 0x60, 0x0A, 0x33, 0xAE, 0xC0, 0xE0, 0x50, 0x99, 0x6E, 0x9F, 0xDF, 0x2B, 0x34, 0x28, 0xA7, 0xBE, 0xCD, 0x16, 0x4E, 0x49, 0xA2, 0x12, 0x21, 0xC0, 0x54, 0xEB, 0x9C, 0x0E, 0x59, 0x6B, 0x72, 0x11, 0xA6, 0x95, 0x4D, 0x72, 0xD6, 0x33, 0xAD, 0x2D, 0x46, 0x71, 0xE5, 0xF2, 0xAC, 0xA7, 0x49, 0xFE, 0x74, 0xB6, 0x16, 0xFC, 0x37, 0x13, 0x19, 0xFF, 0x18, 0xAD, 0xF9, 0x9B, 0x9C, 0x54, 0x49, 0x2C, 0x42, 0xDE, 0x91, 0x97, 0xEB, 0xFD, 0x5A, 0x27, 0xE7, 0x2D, 0x1A, 0x50, 0x1E, 0x2D, 0x42, 0x14, 0xE8, 0x3E, 0x51, 0xAB, 0xDF, 0xBA, 0x4C, 0xA4, 0x50, 0xF0, 0x11, 0x1C, 0x6B, 0xF3, 0xF5, 0x18, 0x56, 0x54, 0xE9, 0x86, 0x19, 0xAE, 0x0B, 0x7A, 0x87, 0xEE, 0x7E, 0x5B, 0x96, 0x15, 0xD9, 0xE0, 0xDF, 0x25, 0xEA, 0x05, 0x74, 0xCE, 0xBD, 0x81, 0x08, 0x40, 0x37, 0x70, 0xFA, 0xB5, 0x3F, 0xBE, 0x4E, 0xA7, 0x3D, 0x5E, 0xFE, 0xED, 0x8C, 0x06, 0x8E, 0xF6, 0x0F, 0x93, 0x14, 0x13, 0xA7, 0x7C, 0x31, 0x0B, 0x51, 0xCF, 0x19, 0x6C, 0x80, 0x4E, 0xB9, 0x99, 0xBD, 0x63, 0xC7, 0x82, 0x10, 0xC2, 0x81, 0xD2, 0xB7, 0x13, 0x7E, 0x3B, 0x50, 0x06, 0xF8, 0x06, 0xD6, 0x7C, 0xD9, 0x0D, 0xD4, 0x8C, 0x6A, 0x3B, 0x61, 0xEB, 0xDF, 0x32, 0x3F, 0x02, 0x37, 0xAF, 0x9F, 0xFB, 0x44, 0x51, 0xAD, 0xBC, 0xD9, 0x7D, 0xB2, 0x84, 0x9B, 0x43, 0xD8, 0x32, 0xD0, 0x2D, 0x4F, 0x15, 0x63, 0xE9, 0x33, 0x5D, 0xD3, 0x77, 0x40, 0x4D, 0x9F, 0xB0, 0xDB, 0x20, 0xCC, 0x04, 0x88, 0x7E, 0x7A, 0xA4, 0xEF, 0xD3, 0x09, 0x75, 0x8A, 0x70, 0xAA, 0x6E, 0x72, 0xF2, 0x54, 0x66, 0xE8, 0xD4, 0x70, 0x9E, 0xB5, 0x99, 0x4C, 0xF7, 0x44, 0x9B, 0xE2, 0xE1, 0x99, 0x02, 0x02, 0x3A, 0x1D, 0xDB, 0x12, 0x08, 0x01, 0x5C, 0x01, 0x6B, 0xC0, 0xFD, 0x75, 0xA4, 0xAB, 0xF9, 0x84, 0x0D, 0xEC, 0xF1, 0x52, 0x0F, 0x60, 0x54, 0xCE, 0x22, 0x7A, 0xEE, 0xA7, 0xC5, 0xA8, 0x6D, 0xAE, 0xF7, 0x31, 0x4F, 0x63, 0x46, 0xCF, 0xEF, 0xD9, 0xFF, 0x8B, 0xCC, 0xEE, 0x90, 0x86, 0x07, 0x63, 0x39, 0xDE, 0xEF, 0x0D, 0x07, 0x3D, 0xB3, 0xB7, 0xD5, 0x5B, 0x7E, 0x9F, 0xA2, 0x33, 0xF6, 0x7D, 0x2A, 0x84, 0x81, 0xED, 0xC4, 0x7A, 0x6F, 0x70, 0x16, 0x77, 0x0E, 0x51, 0x53, 0x8D, 0x6E, 0x27, 0xB5, 0x63, 0x82, 0x78, 0x14, 0x91, 0xD9, 0x01, 0x95, 0xF3, 0x8F, 0x9F, 0x76, 0x21, 0x71, 0x1E, 0x6E, 0xBE, 0x89, 0xCF, 0x43, 0x71, 0x0B, 0xB0, 0x8C, 0x10, 0x22, 0x81, 0xF1, 0xFA, 0xDB, 0x84, 0x37, 0x60, 0x09, 0x6C, 0xC7, 0x29, 0x41, 0xE8, 0x02, 0x7C, 0xDD, 0xE9, 0x10, 0xC2, 0xB6, 0x21, 0x26, 0x15, 0xBD, 0x23, 0xAA, 0xE1, 0x7B, 0xE8, 0xEB, 0x49, 0xEF, 0x73, 0x0F, 0x7C, 0x06, 0xD1, 0x5F, 0x0A, 0x42, 0x6E, 0x63, 0x43, 0xBC, 0xB7, 0xA2, 0x40, 0x9E, 0x0A, 0xEA, 0x3C, 0x1D, 0xEA, 0x5A, 0x5E, 0x57, 0xFD, 0xF6, 0xF5, 0xE6, 0xA4, 0x4D, 0xEB, 0x93, 0x51, 0x28, 0x65, 0xDC, 0xBB, 0x8B, 0xB9, 0x65, 0xC1, 0x3D, 0xF3, 0x31, 0xA4, 0xE6, 0x44, 0x64, 0x36, 0xE0, 0xA7, 0xAA, 0x4A, 0xD7, 0x95, 0x8A, 0x14, 0xB8, 0x8E, 0x62, 0x9A, 0xB7, 0x4F, 0xCD, 0x1D, 0x6B, 0x41, 0x14, 0xD0, 0x9F, 0xAA, 0x77, 0x59, 0xC0, 0xD2, 0x51, 0x05, 0x80, 0xD3, 0x78, 0xB0, 0x81, 0x9A, 0xFA, 0x4A, 0x99, 0xA0, 0x09, 0x36, 0xEE, 0xFD, 0xCD, 0x87, 0xEF, 0x42, 0xCF, 0x6C, 0x9B, 0x22, 0x87, 0x29, 0xA7, 0xF1, 0x1A, 0xD9, 0x7A, 0x12, 0xD3, 0xDE, 0x7D, 0xA9, 0x79, 0x32, 0xCF, 0xD5, 0xF7, 0xD6, 0x4C, 0xDB, 0x49, 0xEC, 0x74, 0x7F, 0xFB, 0x2A, 0x44, 0x8D, 0x63, 0xC1, 0x68, 0xBD, 0xDC, 0x71, 0x0B, 0x06, 0xCD, 0x68, 0xC7, 0xCC, 0x10, 0xCE, 0x66, 0xA9, 0xB2, 0xC8, 0xCA, 0x9C, 0xDB, 0xF8, 0xB3, 0xC9, 0x3E, 0x05, 0xC9, 0xD3, 0x8F, 0x41, 0x46, 0x6D, 0x7B, 0x93, 0x8F, 0xD3, 0x80, 0x68, 0x20, 0x83, 0xC3, 0x76, 0x1A, 0x07, 0x0B, 0x60, 0x0D, 0x68, 0x00, 0x2B, 0xDE, 0x36, 0xA1, 0xDB, 0x01, 0x2D, 0x9E, 0x79, 0x82, 0xA6, 0x74, 0x14, 0x19, 0x7D, 0x0D, 0xF9, 0x49, 0xAE, 0x0D, 0xDB, 0xB7, 0x6D, 0xB4, 0x11, 0x80, 0x48, 0x64, 0xDA, 0x58, 0x72, 0x67, 0xBF, 0x45, 0x8C, 0xF6, 0x29, 0x33, 0xB6, 0xBE, 0xB3, 0xB0, 0xA9, 0xCF, 0x84, 0x1E, 0xF8, 0x49, 0xE4, 0x73, 0x20, 0xFA, 0xCC, 0xEA, 0xE9, 0xB1, 0x75, 0xB3, 0x34, 0x28, 0x94, 0x9A, 0x9E, 0x6D, 0xE4, 0x1E, 0xA7, 0xF7, 0xC0, 0x29, 0x32, 0x22, 0xBA, 0xBE, 0x55, 0xEF, 0x3B, 0xDF, 0x26, 0x3D, 0x33, 0x98, 0x2B, 0x80, 0x18, 0x6C, 0x22, 0xDE, 0xA2, 0xD4, 0x6C, 0xBE, 0xCF, 0xDF, 0x0D, 0xA1, 0xDA, 0x80, 0xF2, 0x0D, 0x9D, 0x9F, 0x1E, 0x3F, 0xE7, 0xFA, 0x34, 0x78, 0x17, 0xD9, 0x0C, 0x35, 0x4A, 0xBF, 0x26, 0x8F, 0x4B, 0x64, 0xD3, 0x2F, 0x3E, 0x0D, 0x3B, 0x2C, 0x57, 0xBB, 0x7D, 0x45, 0xA2, 0x59, 0x4A, 0xCF, 0x66, 0xD3, 0xF1, 0xDC, 0x2B, 0xA0, 0xEA, 0xED, 0x67, 0x5D, 0xBC, 0x8B, 0x1F, 0x63, 0x87, 0x1F, 0x26, 0x30, 0x8B, 0xD1, 0x82, 0x45, 0x07, 0x32, 0x31, 0xC6, 0xCE, 0x5D, 0xA7, 0x76, 0x66, 0xEC, 0xF1, 0x6F, 0x13, 0x3C, 0x6E, 0x89, 0xB3, 0x2C, 0x8B, 0xE2, 0x1D, 0xB0, 0x98, 0x15, 0x62, 0x0B, 0x10, 0x01, 0xB6, 0xBF, 0x47, 0xC9, 0x33, 0x4F, 0xBB, 0x8B, 0xFA, 0x64, 0xC4, 0x35, 0xB0, 0x14, 0x67, 0x06, 0x51, 0xD7, 0xE2, 0x1F, 0x41, 0xF3, 0x5F, 0x98, 0x36, 0xD7, 0x2E, 0xAB, 0xF5, 0x3B, 0x79, 0xE3, 0xEE, 0x5B, 0x63, 0x4F, 0x44, 0x13, 0xD3, 0xEF, 0xB0, 0xA7, 0x05, 0xB4, 0xF7, 0xBA, 0x59, 0x7E, 0x72, 0x66, 0xB7, 0xF5, 0x49, 0xDC, 0x96, 0x20, 0x0C, 0x30, 0x22, 0x67, 0xF2, 0xF8, 0xF4, 0xD6, 0xDC, 0xC1, 0x35, 0x78, 0x4C, 0xA1, 0x39, 0x8F, 0x1C, 0xA1, 0x3C, 0x1B, 0x35, 0x71, 0xAC, 0x56, 0xCB, 0x66, 0x5B, 0xEB, 0xED, 0xDE, 0xB9, 0x03, 0x50, 0x1E, 0x89, 0x12, 0x46, 0xC4, 0xA7, 0x33, 0x57, 0xBD, 0xE9, 0xBE, 0x8B, 0x47, 0x6D, 0xEF, 0xE3, 0x78, 0xE9, 0xDB, 0x39, 0x75, 0x5A, 0x72, 0x95, 0x4E, 0xD4, 0xE2, 0xA7, 0xAD, 0xF7, 0x46, 0x64, 0x76, 0xC2, 0x67, 0x39, 0x2A, 0x70, 0x61, 0x95, 0x71, 0xE7, 0x5F, 0x70, 0xF7, 0xDD, 0x81, 0xC2, 0xF2, 0xF8, 0x34, 0xAB, 0xE9, 0xF7, 0x02, 0x3D, 0xC2, 0x47, 0x3F, 0x9D, 0xC8, 0xFA, 0x74, 0xFB, 0xDF, 0x0D, 0x98, 0x7C, 0xDA, 0x43, 0x1F, 0x67, 0x51, 0x9D, 0x16, 0xDF, 0xD7, 0x54, 0x8E, 0x77, 0xC5, 0xA3, 0xA0, 0xC7, 0x9C, 0xC2, 0xC8, 0xC4, 0xB1, 0x22, 0x99, 0x2E, 0xC6, 0xBA, 0x81, 0xCD, 0x20, 0x74, 0x00, 0x29, 0x40, 0x24, 0xE1, 0xF3, 0x22, 0xCF, 0x24, 0xE6, 0xB7, 0xE8, 0x7E, 0x2F, 0xF3, 0x8A, 0xD7, 0x97, 0xB1, 0xEB, 0xFE, 0x6A, 0xCC, 0x09, 0x18, 0xB5, 0xA4, 0x21, 0x14, 0xF3, 0xD1, 0xAA, 0xEF, 0x82, 0xAA, 0x75, 0xA3, 0x44, 0xBB, 0x7D, 0xE3, 0x31, 0xB3, 0x05, 0x4B, 0x70, 0x4E, 0x3B, 0xEA, 0x6B, 0xA5, 0xB3, 0xD7, 0xBB, 0x78, 0x8F, 0x59, 0xF8, 0xEE, 0xC1, 0x3B, 0xE3, 0xDD, 0x0B, 0x50, 0x9F, 0xB9, 0xC1, 0x9D, 0x5E, 0x6E, 0x9C, 0x0A, 0xC5, 0x65, 0x9A, 0x81, 0x4E, 0xD6, 0xE8, 0x94, 0xAB, 0xCF, 0x4A, 0x6A, 0x52, 0xC4, 0xDF, 0x2D, 0xE6, 0x4C, 0x1C, 0xAD, 0x00, 0x76, 0x11, 0x8B, 0x10, 0x42, 0x01, 0x59, 0x80, 0xD7, 0x74, 0xD4, 0x07, 0xA2, 0x00, 0x37, 0x40, 0x46, 0x1A, 0x2E, 0xC0, 0xEC, 0x9D, 0x78, 0xBA, 0xAC, 0x89, 0x5A, 0x41, 0xDE, 0x34, 0xC1, 0xBE, 0xFE, 0xCF, 0xFB, 0x5C, 0xEE, 0xA3, 0x61, 0x72, 0xF5, 0x67, 0x6F, 0xB9, 0x91, 0xF1, 0x6F, 0x75, 0x0D, 0x88, 0x6E, 0x9B, 0x3C, 0xBD, 0x4B, 0xDD, 0x20, 0xF2, 0xF8, 0x1E, 0x2C, 0x7F, 0xFF, 0x7D, 0x09, 0xC0, 0xF4, 0x0E, 0x40, 0xDC, 0x9C, 0x6F, 0x57, 0x29, 0x3F, 0x55, 0x23, 0x1E, 0x37, 0x63, 0x77, 0x71, 0x04, 0xE5, 0x11, 0x85, 0xC3, 0xC7, 0x2F, 0x19, 0xB0, 0x99, 0xAB, 0x12, 0x19, 0x57, 0x81, 0xD7, 0xF3, 0x06, 0x51, 0x40, 0x0B, 0xA8, 0x29, 0xD6, 0x9F, 0x8D, 0x2E, 0x03, 0xF6, 0xE2, 0x8B, 0xFE, 0xE6, 0xA5, 0x64, 0x00, 0x3D, 0x3B, 0x63, 0x3E, 0x51, 0x6B, 0x54, 0xFE, 0xE7, 0xC6, 0x3A, 0x39, 0x1E, 0x01, 0xC4, 0x4D, 0x52, 0xE8, 0x62, 0x20, 0xEC, 0xF5, 0xE4, 0x30, 0x48, 0x40, 0x5A, 0x56, 0xFA, 0x6B, 0x04, 0xF0, 0xCE, 0x71, 0xDF, 0xD6, 0x81, 0x9F, 0xC9, 0xED, 0x12, 0x60, 0x1B, 0x60, 0xF2, 0xCE, 0x71, 0x45, 0x9F, 0xE4, 0x0C, 0x74, 0x45, 0xC6, 0x1D, 0x4D, 0x70, 0xB4, 0x47, 0x45, 0xAA, 0x5B, 0xD3, 0xA4, 0x67, 0x6E, 0x2F, 0x1B, 0xD8, 0xB3, 0x27, 0xE3, 0x40, 0x2B, 0x03, 0x15, 0x80, 0x35, 0xE0, 0x9F, 0xC9, 0x90, 0x2C, 0x46, 0x41, 0x01, 0x17, 0xC0, 0xF6, 0xBB, 0x85, 0xE8, 0x0B, 0xD8, 0x1B, 0xD0, 0x31, 0x37, 0x9E, 0xB0, 0x8D, 0x63, 0x5C, 0xCF, 0xDE, 0x0A, 0x37, 0xB9, 0xB6, 0xC0, 0x39, 0x7E, 0x07, 0xCB, 0xF4, 0x1C, 0xCE, 0xA2, 0x81, 0x18, 0x2E, 0xC9, 0x77, 0x41, 0xB5, 0xEE, 0x4E, 0x0B, 0x75, 0xFE, 0xB7, 0x9F, 0x94, 0xD9, 0x2C, 0x4D, 0x00, 0xAF, 0xF7, 0x51, 0xEE, 0xD3, 0x87, 0x7E, 0xB4, 0xF5, 0x49, 0xBB, 0x95, 0xBF, 0x22, 0x3E, 0xA3, 0xE8, 0x6B, 0xDC, 0xFE, 0xD3, 0x31, 0xD2, 0x68, 0x9E, 0x69, 0xBC, 0x7C, 0xF7, 0xF1, 0x0E, 0x6A, 0x05, 0x66, 0xC8, 0xEA, 0x6C, 0xF8, 0x05, 0x90, 0x0B, 0x88, 0x39, 0x9A, 0x47, 0xAA, 0x01, 0xC5, 0xC7, 0xA6, 0x38, 0x70, 0x5E, 0x0C, 0xC0, 0x04, 0x58, 0x0D, 0x48, 0xF3, 0x4C, 0x9B, 0xA8, 0x6D, 0x56, 0x1E, 0x27, 0x33, 0x41, 0x05, 0x26, 0x71, 0x21, 0xE8, 0xE6, 0xBD, 0x95, 0x7F, 0xA1, 0xF1, 0x95, 0xAB, 0x72, 0xA9, 0xD7, 0x47, 0x4F, 0xC3, 0x54, 0xE1, 0x9D, 0xE4, 0x4A, 0x3E, 0x8D, 0xB0, 0xF7, 0xB9, 0x54, 0x8C, 0x88, 0x06, 0xAA, 0x5E, 0xD7, 0xA9, 0xC6, 0x07, 0xC4, 0x91, 0x4C, 0x19, 0x2C, 0xF4, 0x09, 0xA6, 0x87, 0xE1, 0xC8, 0x27, 0xD1, 0x7E, 0x12, 0x2D, 0x99, 0x14, 0x39, 0x39, 0x95, 0xF6, 0x31, 0x4F, 0x53, 0x07, 0x82, 0xC8, 0x00, 0xAA, 0x80, 0xF6, 0x51, 0xE7, 0x00, 0xE7, 0x2D, 0x53, 0x13, 0x28, 0x07, 0x32, 0x00, 0x63, 0x24, 0x3B, 0x00, 0x6F, 0xA0, 0x84, 0x67, 0xEE, 0x09, 0x9A, 0xA0, 0x57, 0x49, 0xC5, 0x54, 0xED, 0x61, 0x25, 0x0F, 0x0F, 0xEA, 0x5E, 0x62, 0x9C, 0x2B, 0xD7, 0xE6, 0x65, 0x93, 0x70, 0xB8, 0x91, 0x59, 0xB4, 0x7F, 0xAD, 0x3A, 0x46, 0xC4, 0x9D, 0xBD, 0x3A, 0x3E, 0x28, 0x2D, 0xCF, 0x3A, 0x1D, 0x90, 0x02, 0x7C, 0x03, 0xE5, 0x37, 0x27, 0xC1, 0x4F, 0xD5, 0x81, 0x3F, 0xB5, 0xA1, 0xFC, 0x62, 0x8F, 0x53, 0xF9, 0x3A, 0x37, 0xBD, 0xB1, 0x0D, 0xB0, 0x64, 0xBC, 0x66, 0x9B, 0x42, 0xE7, 0xA6, 0x07, 0xC8, 0x1C, 0x35, 0x20, 0x46, 0x24, 0xA0, 0xC4, 0x8C, 0xA7, 0xA8, 0xD7, 0xFA, 0x62, 0xF1, 0xC5, 0xDC, 0xC0, 0x1E, 0x9B, 0xF5, 0x06, 0xBA, 0x66, 0x34, 0x4F, 0xD8, 0x14, 0x39, 0x46, 0xAE, 0xE8, 0xC2, 0xE0, 0xC8, 0x1F, 0xD9, 0xBA, 0x7F, 0x8B, 0xC9, 0x6E, 0xC1, 0x47, 0xC9, 0x60, 0x2B, 0x9A, 0xE4, 0x0D, 0x45, 0x69, 0x03, 0x73, 0x05, 0xA2, 0x7D, 0x32, 0xD0, 0x8E, 0x9B, 0xDE, 0xDC, 0x7B, 0xF6, 0xB1, 0x28, 0x03, 0x54, 0x81, 0x90, 0x9B, 0x71, 0x10, 0x67, 0x82, 0x59, 0xD7, 0x7F, 0xDC, 0x38, 0x0B, 0x33, 0xC7, 0xDB, 0xC7, 0xF5, 0x57, 0xB1, 0xAC, 0x63, 0x13, 0xDC, 0x99, 0x59, 0x72, 0x91, 0x37, 0x15, 0x60, 0x44, 0x26, 0x10, 0x0E, 0xF8, 0x26, 0x9C, 0x30, 0x20, 0x17, 0xD7, 0xB2, 0x01, 0x54, 0x4F, 0xE9, 0x22, 0x20, 0x27, 0xAB, 0x12, 0xF0, 0x00, 0x84, 0xB0, 0x69, 0x56, 0x65, 0x13, 0x34, 0x43, 0x05, 0xB5, 0xCD, 0x53, 0x93, 0x35, 0xE1, 0x6D, 0x70, 0x0E, 0xAA, 0xC0, 0xCE, 0xD4, 0x62, 0x2E, 0x60, 0x34, 0x57, 0x6E, 0x42, 0xE9, 0xF6, 0xDD, 0x0A, 0xD5, 0x29, 0xB0, 0x3B, 0x12, 0xE3, 0xF4, 0xB7, 0x9B, 0x69, 0x35, 0x03, 0xE3, 0x1B, 0xE8, 0x7D, 0xDB, 0x81, 0xD3, 0x54, 0x79, 0xBA, 0x5E, 0xAB, 0x21, 0xD8, 0xC6, 0x2B, 0xD3, 0x78, 0x85, 0x99, 0xB3, 0x7A, 0xA9, 0x4F, 0x15, 0xC1, 0x9A, 0xEC, 0x97, 0xBE, 0x37, 0x37, 0xC5, 0x29, 0x28, 0x94, 0xE3, 0xEF, 0x9C, 0x67, 0x2E, 0x91, 0x41, 0x6C, 0xA2, 0x71, 0xCA, 0x26, 0x7A, 0x52, 0x4D, 0x1C, 0x10, 0xE5, 0x8B, 0x06, 0x58, 0x01, 0x5B, 0x01, 0x4D, 0x9E, 0xB9, 0x26, 0x68, 0x8E, 0xF6, 0x56, 0xBE, 0x19, 0x34, 0xBA, 0xF7, 0xB6, 0x3D, 0x19, 0xCD, 0x69, 0x0D, 0x9B, 0x13, 0x6D, 0x2C, 0x61, 0x54, 0x66, 0x47, 0xEA, 0xAD, 0x61, 0xD1, 0xAB, 0xFB, 0xCD, 0x45, 0x20, 0xAC, 0x89, 0xE3, 0x00, 0xC0, 0x57, 0xE7, 0x40, 0xFF, 0x30, 0x02, 0x0B, 0xEF, 0x55, 0xCA, 0x0E, 0x0B, 0xC6, 0x02, 0x00, 0x4F, 0x20, 0xF8, 0xA2, 0x37, 0x46, 0x85, 0xCB, 0xE9, 0xA1, 0xDD, 0xC9, 0xEC, 0x46, 0x96, 0x75, 0x4F, 0x46, 0x9F, 0xED, 0x91, 0x44, 0xE6, 0xFF, 0x05, 0x4E, 0x94, 0x9D, 0x58, 0xC0, 0x16, 0x20, 0x1C, 0x6F, 0xB0, 0x04, 0x9A, 0x28, 0xC2, 0x03, 0x58, 0x39, 0xDD, 0xF5, 0x80, 0xE6, 0xAD, 0x62, 0x9D, 0x91, 0x16, 0xD8, 0x65, 0x2D, 0x67, 0x8A, 0xDB, 0xDB, 0x32, 0x75, 0xE6, 0x83, 0xCC, 0x51, 0x68, 0x55, 0xEE, 0x3D, 0xB5, 0x1E, 0xD9, 0xFB, 0xC7, 0x89, 0xDA, 0xAA, 0x4F, 0x57, 0x0C, 0x07, 0xBA, 0x88, 0x00, 0xB2, 0x88, 0x78, 0x97, 0x5C, 0x92, 0x4F, 0xFA, 0x31, 0xEE, 0xCD, 0x50, 0x48, 0x1E, 0x17, 0x8A, 0x99, 0x67, 0xED, 0xD9, 0x26, 0x98, 0xF2, 0x33, 0xA3, 0x1A, 0x76, 0x54, 0xA9, 0x91, 0x0A, 0xFC, 0x96, 0xD2, 0xB0, 0x4F, 0xED, 0xDB, 0xCD, 0x38, 0xDF, 0x79, 0x4A, 0xAE, 0x59, 0x0A, 0xBF, 0xCE, 0x78, 0x2D, 0x80, 0x7F, 0xBC, 0xA6, 0xBC, 0x81, 0x9C, 0x07, 0x99, 0x4E, 0xD4, 0x12, 0xF5, 0x8F, 0xE5, 0x18, 0x0E, 0x2B, 0xD0, 0xB7, 0x06, 0x06, 0xCC, 0x2D, 0x1D, 0x4C, 0xE4, 0xE7, 0x18, 0x33, 0x47, 0xCD, 0xDD, 0x56, 0xEE, 0x1C, 0xFF, 0x6B, 0xED, 0x3E, 0xA5, 0xAF, 0x7B, 0xF3, 0x53, 0x4C, 0xB2, 0xE3, 0x22, 0x02, 0xD8, 0x84, 0xBE, 0x75, 0x8C, 0xB3, 0x22, 0x9F, 0x9E, 0x91, 0xE3, 0x15, 0xB7, 0x79, 0xBD, 0x35, 0x11, 0xC7, 0x9C, 0x48, 0xE6, 0xD9, 0xD7, 0x1F, 0x4F, 0xFC, 0x7C, 0xCB, 0xAD, 0x96, 0x00, 0x39, 0x7B, 0xF1, 0x05, 0x88, 0x01, 0xB6, 0x81, 0x5E, 0xBC, 0xBE, 0xB9, 0xCE, 0xDD, 0x0A, 0xAC, 0xCD, 0x17, 0x13, 0x10, 0xBE, 0xBD, 0x04, 0xE8, 0x9E, 0x9D, 0x8B, 0x89, 0x5A, 0x21, 0x83, 0x4D, 0x95, 0x75, 0x33, 0xFA, 0x3F, 0x63, 0x6D, 0x65, 0x27, 0xF7, 0xC4, 0x15, 0x8B, 0x23, 0xBB, 0xD5, 0xD9, 0xDC, 0x72, 0x99, 0xDA, 0xF6, 0xD7, 0x9A, 0x54, 0x67, 0x97, 0x80, 0xD0, 0xD9, 0x6D, 0x23, 0xC6, 0x34, 0x40, 0x80, 0x9C, 0xF4, 0xF9, 0x99, 0xA8, 0xF4, 0xA8, 0x5C, 0x3E, 0xE5, 0x30, 0x57, 0x0F, 0x1B, 0x0D, 0x88, 0x7E, 0x4D, 0x75, 0x4C, 0xE9, 0x7A, 0xF4, 0x7D, 0x19, 0x31, 0xF8, 0xED, 0x4D, 0xB3, 0x05, 0xD0, 0x4D, 0x34, 0xE0, 0x1B, 0xE8, 0x19, 0x87, 0x47, 0xE8, 0x4E, 0x60, 0x1B, 0x5F, 0x4C, 0x40, 0x1C, 0xB2, 0xC0, 0xE9, 0xA2, 0x30, 0xA7, 0xEC, 0x89, 0x5A, 0x23, 0xE5, 0xD2, 0x1D, 0x19, 0xF6, 0xA2, 0xBF, 0x6D, 0x69, 0x2B, 0xFD, 0xFD, 0x13, 0x7B, 0x6F, 0x0A, 0x01, 0x7C, 0xE4, 0x95, 0xFC, 0x87, 0x7B, 0x54, 0xBC, 0xEB, 0xA9, 0xAF, 0xE2, 0x51, 0x63, 0x96, 0x39, 0x06, 0x7D, 0x1B, 0xE8, 0xBA, 0x88, 0x9B, 0xFB, 0x0D, 0xB4, 0xDD, 0xD5, 0xDD, 0xF6, 0xD3, 0x98, 0x34, 0x39, 0x3C, 0x2C, 0x71, 0x34, 0x9D, 0x46, 0x3C, 0xA6, 0xDA, 0xE1, 0xDD, 0x2C, 0x50, 0x01, 0xA4, 0xF0, 0xA2, 0x18, 0xD0, 0xFE, 0x59, 0x18, 0x24, 0xE0, 0xF1, 0x2E, 0x0C, 0x76, 0x00, 0xFD, 0x59, 0x11, 0xA8, 0xF0, 0xC5, 0x06, 0xEC, 0xAC, 0xD6, 0x01, 0xA9, 0xB9, 0x69, 0x30, 0x6A, 0x3A, 0x1D, 0xF7, 0x94, 0x16, 0x80, 0xF4, 0x55, 0xB3, 0xCD, 0x75, 0xEE, 0xA6, 0x5F, 0x63, 0x73, 0xB2, 0x57, 0x9C, 0x52, 0xD8, 0xD3, 0xE1, 0x21, 0xE2, 0x75, 0xA3, 0x3B, 0xAB, 0xE7, 0x8A, 0x4F, 0x6B, 0x9D, 0x0C, 0xA0, 0x04, 0xC8, 0x06, 0x8E, 0xF0, 0xE7, 0x5C, 0xF9, 0x4D, 0x8F, 0x9A, 0xA9, 0xC0, 0x63, 0x1E, 0xDA, 0xD6, 0x5B, 0x56, 0x2E, 0xF3, 0x20, 0x1E, 0x3B, 0xDB, 0x6B, 0x11, 0xF1, 0x16, 0xFF, 0xCF, 0xE4, 0x7F, 0x04, 0xB1, 0x1D, 0x9F, 0x92, 0x7E, 0x03, 0x66, 0x23, 0x5A, 0xA7, 0x96, 0x3A, 0x00, 0xE7, 0x91, 0x09, 0xB0, 0x4F, 0x81, 0x12, 0xA0, 0x06, 0xB8, 0xCF, 0x99, 0x13, 0xB5, 0x8D, 0x22, 0x36, 0x0F, 0x14, 0xDB, 0xB0, 0x68, 0xA6, 0xAD, 0x1E, 0xE7, 0xC3, 0x64, 0x55, 0x86, 0x7B, 0x42, 0xA3, 0x65, 0x8B, 0xFB, 0x57, 0xC8, 0xBD, 0x3D, 0x58, 0x74, 0xBF, 0xED, 0xB5, 0x74, 0x01, 0xEE, 0xC4, 0x1C, 0x3D, 0xFD, 0x43, 0xEA, 0xA4, 0x2B, 0x70, 0x06, 0x99, 0xC7, 0x27, 0x4D, 0x66, 0x09, 0xFF, 0xB4, 0xB9, 0x18, 0xED, 0x3F, 0x4F, 0xDD, 0x7C, 0xEC, 0xD9, 0x44, 0x05, 0x6C, 0x16, 0xDF, 0x9F, 0x8E, 0xC5, 0xD2, 0x40, 0xAE, 0x77, 0xF1, 0xB0, 0x12, 0x88, 0xF5, 0x56, 0x69, 0x2D, 0xC6, 0xA9, 0x17, 0xE0, 0xF2, 0xFA, 0x28, 0xCC, 0xD1, 0xC4, 0x30, 0x73, 0xA2, 0x26, 0x68, 0x0C, 0x24, 0x8D, 0x3F, 0xB4, 0x1B, 0xBE, 0x43, 0xBA, 0x9E, 0x1C, 0x49, 0x33, 0x41, 0x79, 0xC3, 0x62, 0xBD, 0xA3, 0xCF, 0x4C, 0xE3, 0x87, 0x25, 0x80, 0xCB, 0xA7, 0x3C, 0x4F, 0xA6, 0xC3, 0x43, 0xBF, 0x8D, 0xA8, 0x53, 0x00, 0x5F, 0x80, 0xEC, 0x5B, 0xE4, 0xD9, 0xA7, 0x65, 0x51, 0xCD, 0x3E, 0x0B, 0x13, 0xFC, 0x93, 0x47, 0xCB, 0x99, 0x16, 0xC6, 0x53, 0xA6, 0xE6, 0xDA, 0x92, 0xD6, 0x6D, 0xC2, 0xA7, 0xC6, 0xD4, 0x50, 0x72, 0xFA, 0x51, 0x9B, 0xBF, 0xCC, 0x99, 0xC5, 0xA6, 0x40, 0x6D, 0x26, 0x7F, 0x2E, 0x20, 0xEA, 0x96, 0x67, 0xE1, 0x31, 0x05, 0x95, 0x3D, 0x81, 0x5C, 0x80, 0x24, 0xCE, 0xEC, 0xB8, 0xF3, 0x6B, 0xD8, 0x2E, 0x32, 0x66, 0xCA, 0x7F, 0x90, 0x8D, 0x78, 0xD7, 0x86, 0xEF, 0x50, 0x39, 0x2C, 0x12, 0x7C, 0x36, 0x35, 0x76, 0xD0, 0xC2, 0x2F, 0x29, 0xAC, 0xCB, 0x4C, 0x34, 0xDE, 0xA2, 0xC6, 0xD9, 0x6F, 0x97, 0x4F, 0x07, 0x96, 0x5D, 0x40, 0xFB, 0xDC, 0x16, 0x81, 0x6D, 0x80, 0x10, 0xA3, 0x38, 0x2F, 0x46, 0x74, 0x7C, 0xF9, 0x9D, 0x59, 0x7B, 0x1D, 0x38, 0xD2, 0x60, 0x80, 0xB8, 0xB6, 0x9F, 0x27, 0x61, 0xDB, 0xCC, 0x4A, 0x01, 0x9F, 0x0A, 0xE7, 0x71, 0xCE, 0xFC, 0x36, 0x47, 0x12, 0xC0, 0x13, 0x28, 0x2E, 0x68, 0x8D, 0x55, 0xA9, 0xAA, 0x40, 0x15, 0x90, 0x0D, 0xD8, 0xD4, 0x98, 0x1B, 0xE0, 0x09, 0xCC, 0xCF, 0xAA, 0x27, 0x6A, 0x58, 0x17, 0x78, 0x24, 0xE6, 0xD2, 0x69, 0x48, 0x1A, 0x5F, 0xFB, 0xD9, 0x32, 0xC8, 0xA5, 0xC8, 0xE5, 0xCE, 0x82, 0xFD, 0xB2, 0xF6, 0xD3, 0x3E, 0x3B, 0xEA, 0xE3, 0xD8, 0x11, 0x4F, 0xC7, 0xF8, 0x59, 0x82, 0xF6, 0xDD, 0x41, 0xE8, 0x57, 0x8D, 0xF6, 0x75, 0x0B, 0x05, 0x66, 0x54, 0xEA, 0x99, 0x57, 0xCA, 0x34, 0xA0, 0x2D, 0x1C, 0x55, 0xF2, 0x33, 0xE5, 0x4D, 0x1B, 0xDF, 0x67, 0x41, 0xED, 0x02, 0xA8, 0x9C, 0xDB, 0x12, 0xFB, 0x86, 0x01, 0x5F, 0xB7, 0x48, 0xD9, 0x80, 0x06, 0x50, 0x7C, 0xDA, 0xA4, 0xBE, 0x76, 0xA5, 0x7B, 0xF3, 0xC5, 0x04, 0x24, 0x79, 0x26, 0x8F, 0x56, 0xF3, 0x94, 0x98, 0xA8, 0x39, 0x9C, 0xEB, 0x64, 0x73, 0x06, 0xE8, 0xBF, 0x9C, 0xCC, 0xB8, 0x96, 0xE8, 0xA8, 0xA2, 0x6E, 0xAC, 0xA6, 0x97, 0x9E, 0x5D, 0x09, 0x54, 0x0B, 0x7C, 0x9A, 0x1A, 0xC7, 0x7D, 0x3A, 0xEE, 0x38, 0x06, 0x8F, 0x71, 0xCD, 0xF8, 0xEE, 0x3F, 0x53, 0x0E, 0xB4, 0xD3, 0xB3, 0x52, 0x6F, 0xC1, 0x35, 0x53, 0x84, 0x0D, 0x83, 0x04, 0xCE, 0x8E, 0x81, 0xA3, 0x60, 0xB9, 0x77, 0xD9, 0x5C, 0x68, 0x73, 0xCF, 0x98, 0x6A, 0x63, 0x8E, 0x8E, 0xC6, 0xD1, 0x16, 0xC0, 0x03, 0xC8, 0xA6, 0x92, 0xBE, 0x81, 0x4D, 0x48, 0xBF, 0xE5, 0x7A, 0xB9, 0xF9, 0x25, 0x2D, 0x60, 0x35, 0x5F, 0x2C, 0x40, 0xF9, 0x86, 0x0E, 0x1C, 0xED, 0xE6, 0x99, 0x67, 0xA8, 0x05, 0x6B, 0x55, 0xE3, 0x97, 0xAE, 0x57, 0xB1, 0xB1, 0x7D, 0x76, 0x86, 0x1A, 0xCD, 0x40, 0xE8, 0x16, 0x60, 0x1A, 0xAC, 0xAE, 0x79, 0x5A, 0x63, 0x88, 0x01, 0x33, 0x79, 0xB0, 0x58, 0xB7, 0x9E, 0x30, 0x4F, 0xF1, 0xA7, 0x28, 0xE0, 0x05, 0xA8, 0x03, 0x2B, 0x01, 0xFB, 0x1D, 0x51, 0x9D, 0x77, 0xAE, 0xD7, 0x9D, 0x0F, 0xB7, 0xE0, 0xCE, 0x5C, 0x2C, 0xFE, 0x8C, 0xD2, 0x85, 0x63, 0x75, 0x01, 0x9B, 0xB0, 0x31, 0x1F, 0x49, 0x60, 0x9C, 0x32, 0xD7, 0x66, 0x81, 0x41, 0xE2, 0xCC, 0xD5, 0x40, 0x18, 0x50, 0xAC, 0xFB, 0xD9, 0x44, 0xED, 0xD7, 0x99, 0x6F, 0x6F, 0x60, 0x15, 0x5E, 0x2C, 0xC2, 0x1D, 0xD0, 0x7C, 0xCF, 0x0C, 0x9F, 0x98, 0x25, 0x1E, 0x51, 0x39, 0xCB, 0x76, 0xFA, 0x3A, 0x6B, 0x3C, 0x31, 0xF3, 0x32, 0x54, 0x16, 0xA9, 0xC2, 0xF7, 0x42, 0x61, 0x08, 0xB0, 0xA7, 0x98, 0x11, 0xA8, 0xF5, 0xB4, 0x13, 0xA1, 0x76, 0xAC, 0x83, 0x3C, 0x5A, 0x85, 0x39, 0x90, 0x73, 0xF3, 0x35, 0x86, 0xAE, 0xD9, 0xB6, 0x28, 0xF8, 0xC1, 0x68, 0x01, 0x27, 0x53, 0x09, 0x3C, 0x55, 0xC2, 0x2C, 0x27, 0x0C, 0x2E, 0x47, 0xC3, 0xF8, 0x51, 0x14, 0xE1, 0xE9, 0x40, 0xB0, 0xC2, 0x81, 0x65, 0x88, 0xA7, 0x39, 0xB0, 0x92, 0xB0, 0x17, 0xE2, 0x40, 0x29, 0xDF, 0x47, 0xFF, 0xBA, 0xED, 0xC4, 0xC2, 0x8B, 0xD5, 0x80, 0x2B, 0xA0, 0xEB, 0x1E, 0x71, 0x07, 0x03, 0x31, 0x2B, 0x96, 0xA7, 0xE8, 0xB3, 0x4E, 0xB7, 0x14, 0x98, 0xB0, 0x98, 0x71, 0xC7, 0xDB, 0xD9, 0xB4, 0x59, 0xA1, 0xA0, 0xAE, 0x7C, 0x5C, 0x49, 0x13, 0xC8, 0xFD, 0x29, 0xCA, 0x08, 0x99, 0x91, 0xCC, 0x2F, 0x60, 0x72, 0xB1, 0x17, 0x60, 0x35, 0x98, 0x87, 0xD9, 0x0D, 0x5D, 0xB2, 0xC7, 0xCF, 0xF4, 0x67, 0xEE, 0x69, 0xDE, 0xCB, 0x8F, 0xE9, 0x7C, 0x91, 0xFE, 0xC0, 0x56, 0xA7, 0x17, 0xB6, 0x2B, 0x0B, 0xE8, 0x02, 0x58, 0x2C, 0xBC, 0x0B, 0x05, 0x34, 0x08, 0x7D, 0xE1, 0x0B, 0xE8, 0xCD, 0xF7, 0x39, 0x50, 0x45, 0x04, 0x10, 0x0D, 0x58, 0x00, 0x2A, 0x80, 0xCB, 0xD4, 0xCB, 0x4F, 0xCC, 0x1A, 0x22, 0x69, 0x0A, 0x16, 0xCD, 0xBB, 0x60, 0xBE, 0xA7, 0xF2, 0x8C, 0x3A, 0x49, 0x81, 0x14, 0x9D, 0x46, 0x81, 0x39, 0x1F, 0xB7, 0x0E, 0x03, 0x7C, 0xD2, 0x4B, 0xCE, 0xFD, 0x8C, 0xE2, 0x8B, 0xF3, 0xF9, 0x36, 0x93, 0x2D, 0x15, 0xC0, 0x08, 0xF7, 0xBF, 0x32, 0x21, 0xA9, 0x99, 0x07, 0x5C, 0xEB, 0x46, 0x6E, 0x1C, 0xF3, 0x32, 0x8C, 0x09, 0x0F, 0x05, 0xB6, 0x63, 0x47, 0xE7, 0xAF, 0xD3, 0xCD, 0x0A, 0x7E, 0x01, 0x0A, 0xF4, 0xD8, 0x9D, 0x13, 0xE5, 0x1C, 0xD7, 0x0B, 0x10, 0x01, 0x92, 0x77, 0x86, 0x10, 0xEE, 0x49, 0x27, 0xB1, 0xF1, 0x62, 0x0A, 0x20, 0x0D, 0xCC, 0x8B, 0xB2, 0x71, 0xCA, 0x51, 0x87, 0x6C, 0xC6, 0x60, 0x62, 0x4C, 0x8C, 0xA3, 0x4A, 0xE5, 0x53, 0x3B, 0xEB, 0xC5, 0xAA, 0x9F, 0x32, 0xEE, 0x59, 0xDA, 0x59, 0x6C, 0x22, 0x1F, 0xF6, 0x66, 0xC3, 0xD8, 0x59, 0xE8, 0xF9, 0x3E, 0xE9, 0x25, 0x80, 0x0B, 0xB1, 0x01, 0x0D, 0x40, 0x36, 0x10, 0xB3, 0x72, 0x89, 0x77, 0x3D, 0x60, 0x8B, 0x53, 0x84, 0x59, 0x48, 0x37, 0x9F, 0x79, 0x72, 0xFD, 0xBB, 0x46, 0xAE, 0x75, 0xAE, 0x00, 0xE2, 0xAC, 0xDF, 0x73, 0x24, 0x6C, 0xE3, 0x23, 0xB3, 0x80, 0x9C, 0x87, 0x32, 0xA1, 0x0E, 0xB4, 0xF0, 0x26, 0xD2, 0x63, 0x90, 0x02, 0xC8, 0xC6, 0x8B, 0xBD, 0x00, 0xED, 0x77, 0xA9, 0x2E, 0xCA, 0x33, 0xF7, 0x04, 0x6D, 0xB3, 0x05, 0x9A, 0xFF, 0xE0, 0x5B, 0x7E, 0xFB, 0xA1, 0x3B, 0x36, 0x94, 0x59, 0xD5, 0xC4, 0x3F, 0xCA, 0x84, 0x35, 0x5B, 0x78, 0x50, 0x88, 0x73, 0x0A, 0xF7, 0x35, 0x56, 0x9B, 0x05, 0xC1, 0x24, 0x2F, 0x9D, 0x5D, 0x3C, 0x05, 0x76, 0xF1, 0x28, 0x88, 0x9B, 0xC7, 0xC0, 0x3D, 0xBD, 0xBB, 0x7F, 0x4C, 0x79, 0xFB, 0xCA, 0x7E, 0xB1, 0x19, 0x85, 0x31, 0x3A, 0xAB, 0x2B, 0x68, 0xFB, 0xA9, 0x1B, 0x6A, 0x8E, 0x6D, 0xE7, 0x99, 0xC2, 0x98, 0x04, 0x83, 0xD1, 0x9C, 0x9F, 0xED, 0x7C, 0x7B, 0x58, 0xAE, 0x06, 0x92, 0xCF, 0xDC, 0xE0, 0x53, 0x56, 0x0C, 0x18, 0x61, 0xA5, 0x02, 0xD0, 0xB8, 0xED, 0xD2, 0x9A, 0x8F, 0xD7, 0x75, 0xC7, 0x1A, 0xB6, 0x0A, 0xB2, 0x9B, 0x9E, 0x15, 0xCD, 0x84, 0x7B, 0x41, 0x24, 0x9C, 0x43, 0x66, 0x36, 0x8E, 0xAD, 0xE1, 0x02, 0x26, 0xF1, 0xE4, 0xAB, 0xF9, 0x57, 0xE8, 0x38, 0x89, 0xC4, 0xC7, 0x6A, 0x89, 0x88, 0x4F, 0x6E, 0xB5, 0x13, 0x0A, 0x8C, 0x69, 0x85, 0x8E, 0xD0, 0x21, 0xCD, 0x25, 0xE5, 0x93, 0xF8, 0xA3, 0x8C, 0x9A, 0x70, 0x8D, 0x34, 0x09, 0xED, 0x47, 0x46, 0x9B, 0x89, 0x60, 0xE8, 0xB7, 0x95, 0xA5, 0xCE, 0x6D, 0x02, 0xA8, 0xD9, 0x37, 0x70, 0xC0, 0x16, 0xD0, 0x35, 0x9D, 0x29, 0xDF, 0x86, 0x18, 0xAA, 0x6F, 0x47, 0x4B, 0x53, 0x60, 0x2D, 0x40, 0x84, 0xA7, 0xF8, 0x44, 0x4D, 0xD9, 0xFD, 0x69, 0xEE, 0x78, 0xF5, 0xCB, 0xA3, 0x4F, 0xCB, 0x67, 0xF1, 0xB9, 0x42, 0xB9, 0xF9, 0x17, 0xA8, 0x3C, 0xD7, 0xFD, 0x46, 0xAD, 0xDF, 0xFC, 0xE5, 0xB3, 0xF5, 0xA9, 0x05, 0x74, 0xBE, 0x0D, 0x89, 0x5B, 0x08, 0xE5, 0x8B, 0x01, 0x84, 0xDD, 0xF2, 0xFF, 0xAD, 0xA7, 0x29, 0xA3, 0xD5, 0x5C, 0x6A, 0x37, 0x17, 0x25, 0xCE, 0xC5, 0x7C, 0xF6, 0x88, 0xEB, 0x86, 0x79, 0x22, 0x6A, 0x7F, 0x5D, 0x66, 0xD6, 0xBB, 0xCE, 0xCC, 0xB3, 0x33, 0x02, 0xE8, 0x06, 0x6A, 0x54, 0xB8, 0x49, 0x9B, 0x0E, 0x60, 0x94, 0xBD, 0x5A, 0x80, 0x14, 0xCF, 0xEC, 0xD7, 0x29, 0x6A, 0xE7, 0x44, 0xCD, 0xD0, 0x9C, 0xAB, 0x94, 0xAE, 0xB5, 0x6F, 0xD6, 0x77, 0xE9, 0xA6, 0x80, 0x9A, 0x6C, 0x68, 0x51, 0x50, 0xC8, 0xBC, 0x9F, 0x24, 0x05, 0xD7, 0xCF, 0x58, 0x33, 0x7B, 0x33, 0x88, 0xCB, 0x08, 0xFF, 0x28, 0xB7, 0x93, 0x9D, 0x0B, 0x70, 0x54, 0xE6, 0xA9, 0x51, 0x3B, 0xC9, 0x3A, 0x7B, 0x92, 0x83, 0x78, 0x24, 0xB3, 0xDF, 0x27, 0xA3, 0xE8, 0xF0, 0xCC, 0xFD, 0x6E, 0x17, 0x9E, 0xDC, 0x0C, 0xB9, 0xED, 0x4B, 0xE8, 0x07, 0x72, 0x3B, 0xF5, 0xAC, 0x06, 0x84, 0x48, 0x8E, 0x27, 0xEF, 0x77, 0xE7, 0xB4, 0x0B, 0x88, 0x06, 0x76, 0xBF, 0x0D, 0x56, 0xB9, 0xAA, 0x07, 0x10, 0x35, 0x87, 0xBF, 0x6E, 0x18, 0xD6, 0xEA, 0x86, 0x92, 0x0F, 0x2B, 0xFD, 0x4D, 0xF0, 0xAB, 0x1A, 0x5F, 0x6B, 0x24, 0x1B, 0x78, 0x38, 0xCA, 0xC9, 0x22, 0x47, 0x16, 0xFA, 0xF6, 0xFB, 0x19, 0x67, 0x83, 0x37, 0x61, 0x53, 0x17, 0x70, 0x8E, 0x14, 0x90, 0x7C, 0x11, 0x7D, 0x5D, 0xF4, 0xB7, 0x9E, 0xCD, 0xB8, 0x36, 0x8E, 0x12, 0x7E, 0xFA, 0x9E, 0x70, 0xED, 0xD1, 0xA6, 0xDF, 0x64, 0xDB, 0x25, 0x40, 0xD4, 0x7D, 0xB6, 0xDC, 0xAD, 0xF4, 0x04, 0x3C, 0x80, 0x2C, 0xA0, 0x93, 0x11, 0x2D, 0x6A, 0x9E, 0x0B, 0x28, 0xE2, 0xDB, 0x39, 0xB9, 0x0A, 0xF0, 0x0D, 0xA4, 0x8C, 0x6A, 0x32, 0x51, 0x0B, 0x68, 0x2F, 0xAE, 0xAC, 0x26, 0x71, 0x98, 0xB0, 0x84, 0xC2, 0x94, 0xA4, 0x36, 0x1E, 0xF2, 0x65, 0x70, 0x6E, 0xC8, 0x4D, 0x35, 0xB8, 0x68, 0xB0, 0xFC, 0x9A, 0x37, 0x41, 0xF2, 0x61, 0x78, 0x64, 0x9F, 0x3B, 0x6E, 0x7D, 0x7A, 0xBF, 0x2C, 0x7F, 0x57, 0xC4, 0x59, 0x84, 0xE3, 0x67, 0x91, 0xDC, 0xF8, 0xB4, 0xDB, 0x69, 0x50, 0x8F, 0x39, 0xB9, 0x4F, 0x4B, 0x3C, 0xDA, 0xC3, 0xE4, 0x51, 0x31, 0x00, 0x79, 0xE6, 0x7F, 0x8D, 0xD0, 0x99, 0x9C, 0xB9, 0x5A, 0x8C, 0x5C, 0xC2, 0x59, 0xD6, 0x4E, 0xC0, 0x37, 0xFD, 0x3C, 0x1C, 0x48, 0xBA, 0x51, 0xEF, 0x0D, 0xAC, 0x18, 0x57, 0x44, 0xC0, 0x1B, 0xB0, 0x0D, 0x38, 0x4E, 0xB9, 0x77, 0xB5, 0xA4, 0xEF, 0x0D, 0xD2, 0x61, 0x74, 0xD7, 0xAF, 0x3E, 0x2B, 0x6B, 0x0A, 0x68, 0xF9, 0xE4, 0x36, 0xC1, 0xF3, 0xB8, 0x1C, 0x6B, 0x25, 0x29, 0xCA, 0xB5, 0x6F, 0x42, 0xA9, 0xCC, 0x95, 0x38, 0xC9, 0x3C, 0x67, 0x8D, 0x6E, 0x80, 0x29, 0xB1, 0x89, 0x7E, 0x9B, 0xF7, 0xEB, 0x2D, 0x83, 0x94, 0x7D, 0x4A, 0x7E, 0x62, 0x73, 0xC1, 0x97, 0x0C, 0xF6, 0xBE, 0x8E, 0xAA, 0x76, 0x96, 0xE3, 0x21, 0x53, 0xFC, 0xC9, 0xF7, 0x8D, 0x9C, 0xBF, 0xAF, 0x73, 0x66, 0x72, 0xC5, 0x5E, 0xA7, 0x99, 0x4D, 0x53, 0xD2, 0xD8, 0x0D, 0x64, 0xF0, 0xBB, 0xB2, 0xB7, 0xDF, 0xE8, 0x9A, 0x54, 0xC3, 0x0D, 0xC8, 0x7E, 0x9B, 0xD1, 0xAE, 0x39, 0x25, 0x27, 0x68, 0x85, 0xCD, 0x30, 0x41, 0x35, 0xF6, 0xD8, 0x51, 0xAF, 0x14, 0x76, 0xCD, 0xE3, 0x8B, 0x51, 0xF8, 0xEB, 0xBB, 0xD8, 0xAC, 0x4A, 0x6E, 0xD7, 0xF1, 0x8F, 0xF9, 0x84, 0x03, 0xB8, 0x84, 0x38, 0xA4, 0x6F, 0x0D, 0x32, 0x20, 0xC0, 0xB6, 0xA9, 0xE1, 0xE3, 0x8B, 0x23, 0xC9, 0xFA, 0x6C, 0x83, 0x72, 0x3D, 0x3D, 0x5B, 0x88, 0xB3, 0x66, 0x9E, 0xCF, 0x39, 0x05, 0xDF, 0x3C, 0x73, 0x44, 0x3B, 0x35, 0xBE, 0x2F, 0x67, 0xDD, 0xFF, 0x3A, 0x1D, 0x3A, 0x7F, 0xCB, 0xA0, 0xA7, 0x12, 0x2B, 0x80, 0x32, 0x8E, 0xEC, 0xA4, 0x15, 0x8A, 0x13, 0xEB, 0x1D, 0xC4, 0x56, 0x80, 0x08, 0x60, 0x93, 0x5A, 0x12, 0x13, 0xB4, 0x66, 0x2D, 0x1D, 0x1D, 0xBD, 0xA5, 0xE0, 0x86, 0xD4, 0x8D, 0xED, 0xA3, 0x6C, 0x4C, 0xBA, 0x5D, 0xB1, 0x6B, 0x9B, 0xC6, 0xCA, 0x08, 0x78, 0xF8, 0xD5, 0x6B, 0x09, 0xE0, 0x76, 0x4D, 0x5A, 0x46, 0xD2, 0x17, 0x3F, 0x52, 0x63, 0x28, 0x51, 0x80, 0x19, 0xB0, 0x1F, 0x07, 0x5F, 0x14, 0x30, 0xF2, 0x9B, 0xA3, 0xF0, 0xF8, 0xF4, 0xCE, 0x35, 0xDA, 0x94, 0x6C, 0x1C, 0x69, 0x1F, 0x3D, 0x24, 0x7D, 0x2E, 0x67, 0x1C, 0xCD, 0xA2, 0xA2, 0x79, 0xCA, 0x98, 0x62, 0xDB, 0x02, 0x7A, 0x0C, 0xB3, 0x17, 0x60, 0x06, 0xF4, 0xEC, 0xE1, 0x6F, 0xA0, 0x8B, 0x10, 0x20, 0x37, 0x60, 0xC4, 0x2E, 0x40, 0x93, 0x37, 0x8C, 0x89, 0x19, 0xAD, 0x8D, 0x3C, 0x0B, 0xC3, 0x35, 0xF6, 0x6F, 0x79, 0x6C, 0xDB, 0x5F, 0x69, 0x68, 0x15, 0xAF, 0x92, 0x60, 0x0A, 0x58, 0x23, 0xF5, 0x85, 0x03, 0xED, 0x75, 0xDD, 0xC7, 0xB6, 0xC4, 0xF4, 0x90, 0x79, 0x13, 0x11, 0x76, 0x10, 0x02, 0xAC, 0xFD, 0x4A, 0x93, 0x46, 0x29, 0x7F, 0x84, 0x6E, 0xAD, 0xDB, 0x9A, 0x58, 0x29, 0x96, 0xC8, 0x99, 0x7C, 0x1E, 0x63, 0x3F, 0x0E, 0xAD, 0xDE, 0xC0, 0xEC, 0xF1, 0xD5, 0xD3, 0x84, 0x03, 0x5A, 0x38, 0x16, 0x56, 0x94, 0x62, 0x43, 0xC7, 0xDA, 0x15, 0xC8, 0x60, 0x40, 0x93, 0x21, 0x5C, 0x40, 0x3B, 0xB1, 0x81, 0x30, 0x40, 0x84, 0x31, 0x57, 0x1C, 0x4D, 0x0B, 0x08, 0x39, 0x41, 0xDB, 0xFC, 0x77, 0x85, 0x5D, 0xA8, 0x15, 0x76, 0xED, 0x7B, 0xA4, 0x21, 0xAE, 0xD2, 0x36, 0xFC, 0xFD, 0x3C, 0x93, 0xBE, 0x97, 0x4D, 0xB7, 0x09, 0xCE, 0x34, 0x00, 0xCF, 0x29, 0x6B, 0x78, 0x9A, 0xAF, 0xD8, 0xE9, 0x33, 0xA4, 0x4A, 0x24, 0x20, 0x06, 0xAC, 0x02, 0x82, 0x97, 0x55, 0xFB, 0x9F, 0x13, 0x98, 0xC5, 0x74, 0x48, 0xE1, 0xCE, 0xFA, 0xA4, 0x79, 0x60, 0x89, 0x89, 0x41, 0x48, 0x9D, 0x49, 0x92, 0xC3, 0x6E, 0x5D, 0x9D, 0x49, 0x8F, 0x1F, 0xCE, 0x18, 0xAC, 0x29, 0xDF, 0xAE, 0x0A, 0xE4, 0xA6, 0x4F, 0x8C, 0x01, 0x31, 0x82, 0x48, 0x00, 0xBD, 0x80, 0xDA, 0x80, 0x2B, 0xB0, 0x1D, 0x67, 0xD6, 0xA8, 0x24, 0x7B, 0xC4, 0xA7, 0x89, 0x19, 0x83, 0x15, 0x81, 0xC9, 0x48, 0x28, 0x97, 0xB4, 0xAF, 0x34, 0xB4, 0x55, 0x7E, 0xC8, 0x6E, 0xDC, 0x64, 0x5B, 0xD1, 0x1C, 0x74, 0x96, 0x9D, 0x40, 0x4E, 0xF3, 0x95, 0x9C, 0xE6, 0x2B, 0x1C, 0xBC, 0xFB, 0x08, 0x7D, 0x80, 0xE9, 0xA8, 0x7F, 0x80, 0x08, 0xA0, 0x1C, 0x52, 0x45, 0xA9, 0xCD, 0xF9, 0xF7, 0x72, 0xFA, 0xC8, 0x28, 0x3F, 0xD8, 0xC6, 0x8B, 0xC6, 0x67, 0x9F, 0x51, 0x4B, 0x0A, 0x01, 0xB6, 0x32, 0x9E, 0x7E, 0xD5, 0x38, 0xC3, 0xAD, 0xCF, 0xF9, 0x5C, 0xF4, 0x3E, 0xA2, 0xDC, 0x6A, 0xC0, 0x9D, 0x85, 0xB5, 0x0B, 0x68, 0x36, 0xE2, 0xD5, 0x81, 0x03, 0x5B, 0xF1, 0xB3, 0xDA, 0x40, 0x10, 0xA9, 0xF8, 0x59, 0xE4, 0xC4, 0x4C, 0x27, 0x3C, 0x03, 0x3A, 0xE6, 0xC4, 0x39, 0x2A, 0x63, 0x3D, 0x78, 0xB3, 0x78, 0xF6, 0xA7, 0xC9, 0xDA, 0xE9, 0xEB, 0x37, 0xB3, 0x0E, 0xF9, 0x9B, 0x99, 0x2A, 0x87, 0x77, 0xB1, 0x95, 0x42, 0x4E, 0xD7, 0x53, 0x07, 0x22, 0x58, 0x91, 0x4F, 0x93, 0xCF, 0x16, 0x20, 0x93, 0x56, 0x7A, 0xC1, 0xBC, 0x7C, 0x65, 0x77, 0x57, 0x1A, 0x91, 0xA8, 0xBC, 0xE5, 0xC0, 0xEA, 0x84, 0xBD, 0x47, 0x2D, 0x2C, 0x5A, 0x4A, 0xC0, 0x17, 0x10, 0x0E, 0x54, 0xB3, 0x54, 0xD8, 0x00, 0xD9, 0x80, 0x35, 0x50, 0x46, 0xCB, 0x92, 0x06, 0x76, 0x12, 0x0D, 0x48, 0x02, 0xD6, 0x40, 0x2D, 0xA0, 0x7F, 0xC0, 0xC2, 0x9D, 0x31, 0x33, 0x94, 0xDB, 0xB9, 0xA1, 0x3B, 0xBF, 0x16, 0x06, 0x0A, 0xE7, 0xEF, 0x5B, 0x15, 0x56, 0x0C, 0xE5, 0xBF, 0xCD, 0x16, 0xD5, 0x8D, 0x31, 0xE8, 0x7A, 0xCC, 0x0C, 0xF6, 0x29, 0xCF, 0x5F, 0xA7, 0x83, 0xE4, 0xC8, 0xC4, 0xEF, 0x35, 0x76, 0xAE, 0x87, 0x73, 0xA9, 0x19, 0x30, 0x02, 0x5A, 0xEB, 0x6D, 0x7D, 0x3D, 0x6D, 0x76, 0xB0, 0x0D, 0x88, 0x0E, 0x15, 0xC4, 0x1E, 0xC7, 0x9A, 0xA0, 0xB1, 0x59, 0xF3, 0x14, 0x25, 0x12, 0x2F, 0xE2, 0x7B, 0x18, 0xFB, 0x1B, 0x9A, 0x5B, 0xE5, 0x46, 0x3C, 0x53, 0x08, 0x64, 0x69, 0xFD, 0x10, 0x45, 0x67, 0x84, 0x00, 0xC2, 0x81, 0xCA, 0x0F, 0x36, 0x90, 0x05, 0x94, 0x00, 0xCD, 0x4E, 0x78, 0xBE, 0x27, 0x66, 0x8E, 0x12, 0xD7, 0xD0, 0xE7, 0xB6, 0xBF, 0x22, 0xB1, 0x69, 0xD9, 0x8A, 0x81, 0x69, 0x4A, 0x35, 0x75, 0xD3, 0xE4, 0xD9, 0xB8, 0x56, 0xA2, 0xAF, 0x26, 0xD0, 0x3F, 0x34, 0x03, 0x39, 0x85, 0xC1, 0x5A, 0xE7, 0xA6, 0xAA, 0x05, 0x84, 0x00, 0x6E, 0xC4, 0xF3, 0x5C, 0x72, 0xCA, 0xD9, 0xF0, 0xA8, 0x42, 0xC2, 0x90, 0xB1, 0x63, 0xEF, 0x38, 0xBA, 0x34, 0xB0, 0x39, 0x30, 0xC7, 0x2A, 0xD4, 0x93, 0x10, 0xC0, 0x26, 0x66, 0x4A, 0x38, 0x90, 0x01, 0xF4, 0x38, 0xDA, 0x2E, 0xC0, 0x36, 0x30, 0x9D, 0x1F, 0x54, 0x01, 0x4F, 0x20, 0x94, 0x70, 0x20, 0x05, 0x68, 0x5E, 0x2B, 0x5B, 0x81, 0xA8, 0x89, 0x59, 0x20, 0x7F, 0xA1, 0xFD, 0x35, 0x35, 0xD1, 0x3A, 0x47, 0x81, 0xDD, 0x34, 0xB8, 0x43, 0x55, 0x40, 0xDF, 0xCF, 0xFA, 0x15, 0x5C, 0xF8, 0x35, 0x0A, 0xC6, 0x66, 0xCF, 0xED, 0xD0, 0x3E, 0x4F, 0x76, 0xE7, 0x00, 0x63, 0xBF, 0x3E, 0xC3, 0x3E, 0x35, 0x90, 0x80, 0x6D, 0xDE, 0x69, 0xFB, 0x6A, 0xDC, 0x82, 0x33, 0x93, 0x69, 0x80, 0x39, 0xED, 0x8D, 0xB9, 0x24, 0x4C, 0x2C, 0x67, 0xF0, 0x33, 0x36, 0x3B, 0xB6, 0xCD, 0x8F, 0xC2, 0xCF, 0x67, 0x01, 0x08, 0x03, 0xD2, 0x0B, 0xC8, 0x00, 0xAA, 0x80, 0x4E, 0x9E, 0xE2, 0x40, 0x31, 0x04, 0x6E, 0x40, 0x6F, 0x42, 0x81, 0x12, 0x20, 0x92, 0x08, 0xA0, 0x39, 0x76, 0x4B, 0x26, 0x66, 0x89, 0xBB, 0xDB, 0x42, 0xCA, 0x95, 0xE8, 0xB7, 0xAC, 0x7D, 0x2A, 0x42, 0x1C, 0x45, 0xC1, 0xDD, 0xBF, 0xFD, 0x73, 0xC3, 0x1E, 0xB2, 0xC9, 0x3F, 0x97, 0xEA, 0xC7, 0x0C, 0x60, 0xBD, 0xB5, 0xBB, 0xD5, 0xF3, 0x22, 0xE0, 0x49, 0xF0, 0x28, 0x1F, 0xF1, 0x23, 0xF9, 0xF6, 0x59, 0x4A, 0x62, 0x1E, 0xFB, 0xB4, 0x37, 0x9E, 0x06, 0xB4, 0x33, 0x7F, 0xF6, 0x06, 0x8C, 0xEF, 0x3B, 0xFF, 0xA9, 0x8E, 0xD7, 0x98, 0x4C, 0xA2, 0xFB, 0x5B, 0xCC, 0x66, 0x0D, 0x4C, 0x72, 0xF4, 0x64, 0x87, 0x48, 0x00, 0x25, 0x40, 0x12, 0x27, 0xC7, 0x74, 0x03, 0x46, 0x38, 0x96, 0xF1, 0x77, 0xA4, 0x15, 0x3B, 0x62, 0x04, 0x3C, 0xE3, 0xBB, 0xB1, 0xE7, 0xB9, 0x03, 0x09, 0x5F, 0xD5, 0x4C, 0x4A, 0xD9, 0xB4, 0xEF, 0x0B, 0x54, 0x82, 0x47, 0xBC, 0xFE, 0x9A, 0xF5, 0x44, 0x4D, 0x4F, 0x9D, 0xF8, 0x38, 0x6B, 0x44, 0x11, 0x0D, 0x58, 0x00, 0x32, 0x79, 0x42, 0xF1, 0xDA, 0x23, 0x1E, 0x31, 0x4D, 0x75, 0x92, 0x4D, 0x00, 0xED, 0x9B, 0xE7, 0x7E, 0x7D, 0x3D, 0xEC, 0xB1, 0xDF, 0x2F, 0xE5, 0xFB, 0x62, 0x1A, 0xB3, 0x8E, 0x0A, 0x51, 0x1F, 0x21, 0x53, 0x99, 0x5E, 0x5F, 0xAF, 0xCA, 0xBE, 0x03, 0x68, 0x8A, 0x95, 0xBE, 0x00, 0x33, 0x60, 0x7E, 0x96, 0x0A, 0x98, 0x00, 0xB1, 0x27, 0x39, 0x75, 0xA2, 0xD6, 0x94, 0xC9, 0xB9, 0xD9, 0xA9, 0x81, 0xC4, 0xF8, 0xEA, 0xC7, 0x70, 0xDF, 0x42, 0x28, 0x26, 0x07, 0x7C, 0x09, 0x65, 0xBD, 0x25, 0x79, 0x67, 0xDD, 0x39, 0xF6, 0x0E, 0x7B, 0x9C, 0xF7, 0xDE, 0x9D, 0x62, 0x6F, 0x40, 0x1D, 0xD8, 0x72, 0x53, 0x64, 0x70, 0xF5, 0xDD, 0x7A, 0x5E, 0x23, 0xD8, 0xCE, 0xEE, 0xA4, 0xBA, 0xD4, 0x48, 0x89, 0x63, 0xA0, 0x76, 0x12, 0x66, 0xD6, 0x54, 0xE7, 0x4C, 0xCD, 0xA2, 0xDD, 0x34, 0x51, 0x8A, 0xD2, 0x32, 0x9B, 0x5F, 0xEB, 0xD8, 0x94, 0xAD, 0x05, 0x58, 0xBF, 0x7B, 0x98, 0x3B, 0x81, 0x34, 0x20, 0x0A, 0xD0, 0xC2, 0x29, 0xD5, 0x80, 0x17, 0x90, 0x3C, 0xF3, 0x94, 0xB5, 0xC7, 0x18, 0x0A, 0xFB, 0x6F, 0x16, 0xD3, 0xF2, 0xCD, 0x50, 0x9B, 0xD4, 0xA5, 0x51, 0x87, 0xEA, 0xB7, 0x83, 0x6E, 0x25, 0x4F, 0x39, 0xBB, 0xAF, 0x4F, 0x11, 0x86, 0xD5, 0x27, 0x1B, 0x32, 0x3E, 0x57, 0xA8, 0x12, 0x42, 0x8C, 0xCB, 0x03, 0x75, 0xA4, 0xF6, 0x33, 0x74, 0x18, 0x0B, 0x8E, 0x35, 0x1C, 0xC9, 0x59, 0xD7, 0x6F, 0xF6, 0x78, 0xC8, 0x49, 0x19, 0x04, 0x54, 0x17, 0x5E, 0x3C, 0x0A, 0xE6, 0xF8, 0xB1, 0xD5, 0xEB, 0x44, 0xEC, 0x35, 0x39, 0x2E, 0x80, 0x3A, 0x30, 0x96, 0x0D, 0x63, 0x31, 0x66, 0x02, 0xE8, 0x06, 0xA6, 0x4F, 0x94, 0x19, 0xB0, 0x14, 0x10, 0xFB, 0x24, 0xDE, 0x06, 0xDA, 0x39, 0x44, 0x06, 0x1E, 0x95, 0x3B, 0x7F, 0x55, 0xED, 0x25, 0xFB, 0x89, 0x5A, 0x54, 0xFD, 0xB0, 0x96, 0xFC, 0x3E, 0xDF, 0xCE, 0x5B, 0x47, 0x70, 0xAF, 0xD0, 0xCD, 0x38, 0x89, 0xDF, 0x7D, 0xF6, 0x3C, 0xC9, 0x43, 0x32, 0x25, 0x67, 0x0E, 0xA4, 0x02, 0xBE, 0x80, 0x90, 0xB3, 0x9D, 0xC0, 0xC8, 0xD4, 0x7B, 0x85, 0xEE, 0x9E, 0xCD, 0x18, 0x5E, 0x9A, 0x6F, 0xF7, 0x54, 0x53, 0x60, 0xAD, 0xDB, 0xFE, 0x6B, 0xCB, 0x11, 0xCC, 0xE2, 0x51, 0xB6, 0x7F, 0x91, 0x05, 0x72, 0x92, 0x46, 0x1C, 0x08, 0x06, 0x2F, 0x18, 0xA0, 0x1D, 0xC0, 0x1A, 0x35, 0x77, 0x01, 0x9B, 0x67, 0xA6, 0x00, 0x3D, 0xA7, 0xD4, 0x44, 0x4D, 0xB0, 0x84, 0x68, 0x83, 0xB9, 0x98, 0xD4, 0x6F, 0xD6, 0x98, 0xFA, 0x76, 0x99, 0xD5, 0x74, 0xD4, 0x52, 0x2C, 0x87, 0xDB, 0x86, 0xC7, 0xD9, 0x89, 0x1A, 0xD9, 0xFB, 0xCD, 0xEB, 0xA3, 0xCE, 0x3D, 0x09, 0x7D, 0xAE, 0x1F, 0xDF, 0x8C, 0xAB, 0x73, 0x5F, 0x57, 0x96, 0xCD, 0xE0, 0xF9, 0xF8, 0x04, 0xE4, 0xE8, 0xB7, 0xC4, 0xF4, 0x13, 0x61, 0x64, 0xCA, 0x80, 0x93, 0xA2, 0xD9, 0xC4, 0x7A, 0x32, 0x51, 0xED, 0xAF, 0xFC, 0x62, 0xF2, 0x01, 0x3F, 0x3B, 0x52, 0x9A, 0x6F, 0xF6, 0x86, 0xD6, 0xBB, 0xC2, 0xEB, 0x37, 0xB1, 0xFE, 0xDC, 0xC9, 0xCA, 0x01, 0x53, 0x20, 0x78, 0x4A, 0xF4, 0x44, 0x4D, 0x91, 0xD2, 0xAC, 0x49, 0xF5, 0xCF, 0xB0, 0x14, 0x11, 0x79, 0x66, 0x21, 0xF3, 0x17, 0x56, 0xED, 0xE9, 0xCE, 0x74, 0xFD, 0xAE, 0x3E, 0x69, 0x43, 0xC8, 0xD9, 0x9F, 0x22, 0xC0, 0xB7, 0x26, 0x22, 0x08, 0x9D, 0x12, 0xCF, 0x0D, 0x48, 0x10, 0x72, 0xCD, 0xF8, 0xF6, 0xC9, 0xCE, 0x92, 0x02, 0xF0, 0xA2, 0x4F, 0xDF, 0xD2, 0x93, 0xB7, 0x1E, 0x93, 0xA2, 0x9B, 0x77, 0xC8, 0xEC, 0x93, 0xC7, 0x35, 0x4E, 0xF5, 0xAB, 0xA6, 0x1D, 0x1C, 0x15, 0x10, 0x01, 0x9A, 0xFB, 0xA2, 0x66, 0xCC, 0x9D, 0x9A, 0xE6, 0xCE, 0x02, 0x44, 0x11, 0x0A, 0xD8, 0x9A, 0xFE, 0xCF, 0x40, 0x28, 0x50, 0x3C, 0xA5, 0x7D, 0x82, 0x46, 0xB3, 0x26, 0xD9, 0x54, 0x14, 0x8A, 0xCB, 0x38, 0x87, 0x6D, 0x66, 0x70, 0x43, 0x74, 0x1B, 0x5C, 0xDE, 0x76, 0x41, 0x07, 0xB3, 0xE4, 0x6A, 0xE0, 0xF6, 0xD0, 0xDE, 0xC7, 0x03, 0x63, 0x4D, 0x89, 0x98, 0x4F, 0x43, 0x06, 0xE1, 0xA0, 0xDE, 0x38, 0x0A, 0x07, 0x76, 0xF3, 0xE3, 0x06, 0x30, 0xCD, 0x74, 0xF3, 0x51, 0x2B, 0x30, 0xD2, 0x90, 0xB7, 0xFE, 0xA4, 0xB6, 0x43, 0xBF, 0xE5, 0x4E, 0x1B, 0x35, 0x61, 0x07, 0x92, 0x6B, 0x58, 0x61, 0x60, 0x8A, 0xDA, 0x8E, 0x4D, 0xE2, 0xCC, 0xAC, 0xD1, 0xB9, 0x1C, 0x5F, 0x0A, 0x24, 0x57, 0xDE, 0xC6, 0x6C, 0x7B, 0x25, 0xCA, 0x5F, 0x44, 0x02, 0xB6, 0x00, 0xD9, 0x80, 0xD9, 0xF4, 0x73, 0x9C, 0xA0, 0x39, 0xD4, 0x98, 0x76, 0x4A, 0xBC, 0x8D, 0x14, 0x94, 0x30, 0xB4, 0xB3, 0x57, 0xC5, 0xBE, 0x78, 0x21, 0xAE, 0x12, 0x9B, 0xB7, 0x64, 0xEC, 0x8B, 0xDA, 0x37, 0xC7, 0x5B, 0x26, 0xF9, 0x38, 0xA7, 0x2F, 0xF1, 0x94, 0xA4, 0x8E, 0xE7, 0xAD, 0xE1, 0x28, 0x09, 0xC9, 0x4F, 0x45, 0xAB, 0xE3, 0xC5, 0x69, 0x08, 0x2A, 0x13, 0xDF, 0x9C, 0x5B, 0x08, 0xE3, 0x2B, 0x77, 0x53, 0x6D, 0xBC, 0x60, 0xE3, 0x0F, 0xB7, 0xDC, 0x5A, 0x94, 0xDF, 0x4B, 0x9D, 0x11, 0x57, 0x53, 0x5D, 0x30, 0x59, 0x6F, 0xE3, 0xDD, 0xBD, 0x80, 0xA4, 0xFA, 0x18, 0x42, 0x15, 0x69, 0xA0, 0x1C, 0x94, 0x1B, 0xF0, 0x02, 0x74, 0x8E, 0x7C, 0xFA, 0x1E, 0x4E, 0xD4, 0x02, 0xF6, 0xE5, 0xB2, 0x79, 0x5B, 0x68, 0x3C, 0x51, 0xEE, 0x42, 0xDE, 0x51, 0x98, 0x87, 0x7D, 0xBE, 0x85, 0x5E, 0xB3, 0xEC, 0x94, 0xE7, 0xFA, 0x59, 0x4B, 0xC9, 0xAD, 0x86, 0xD2, 0xFD, 0x71, 0x32, 0x9E, 0xFD, 0xC1, 0x3C, 0x1D, 0x04, 0x6C, 0x4A, 0x79, 0x9C, 0xE9, 0x15, 0x85, 0x17, 0xD7, 0xD3, 0x3A, 0xD0, 0x99, 0xD8, 0x92, 0xA7, 0x67, 0x40, 0x38, 0x5E, 0x34, 0x26, 0xFC, 0x98, 0x4F, 0xAB, 0x42, 0xC0, 0x17, 0xDF, 0x20, 0xB4, 0x84, 0x2C, 0x66, 0xD0, 0x2C, 0xAE, 0x82, 0x68, 0xD0, 0xB7, 0xB9, 0xFE, 0x5C, 0x0E, 0x24, 0x17, 0x97, 0xB6, 0xB1, 0x9C, 0xDC, 0x02, 0x58, 0x02, 0xFE, 0x39, 0xD2, 0x22, 0x1A, 0xF0, 0xC2, 0xE2, 0x44, 0x75, 0x62, 0x96, 0xF8, 0xB4, 0x8B, 0x96, 0x73, 0x59, 0xCC, 0x93, 0x34, 0xC6, 0x8C, 0x79, 0x62, 0xD5, 0xD8, 0x61, 0x60, 0x72, 0xDF, 0x2F, 0xAB, 0x4F, 0xCE, 0x7E, 0xCA, 0x6E, 0x20, 0xEC, 0x3A, 0xF2, 0xC9, 0x3E, 0xDD, 0x41, 0x4C, 0xDF, 0x74, 0xB1, 0x55, 0xEF, 0xD6, 0xB5, 0x27, 0x01, 0x55, 0x9E, 0x1A, 0x41, 0x30, 0xBA, 0x42, 0x4D, 0x90, 0x51, 0xE2, 0xF6, 0x08, 0xD5, 0x3C, 0xCA, 0xAA, 0x23, 0xE3, 0xDA, 0xBB, 0x7C, 0x15, 0xA6, 0xF8, 0x24, 0x0D, 0x49, 0x9D, 0xFE, 0x8E, 0xC1, 0x08, 0x26, 0xD7, 0xAD, 0xCB, 0x81, 0x4A, 0x2E, 0x2E, 0xB9, 0x7A, 0x72, 0x05, 0xBA, 0x28, 0xB6, 0xF8, 0x1C, 0x01, 0x75, 0x81, 0x9F, 0x01, 0xBD, 0x27, 0x66, 0xF5, 0x18, 0xEC, 0xBB, 0x25, 0xF6, 0x76, 0xE8, 0xBF, 0xB5, 0xAB, 0xF0, 0x35, 0xF6, 0xA6, 0xB3, 0x73, 0xE0, 0x49, 0xD3, 0xFA, 0x8B, 0x59, 0x5E, 0xB3, 0xFD, 0xAB, 0xA7, 0xF5, 0xBA, 0xE6, 0x4B, 0xDC, 0x82, 0xBD, 0x42, 0x5A, 0x3B, 0x30, 0x1B, 0x53, 0xB9, 0x09, 0x9E, 0xD2, 0xA3, 0xB1, 0x26, 0x42, 0xD0, 0xB3, 0x52, 0x75, 0xC0, 0x85, 0x30, 0x20, 0x89, 0xD1, 0x47, 0x9A, 0x83, 0x6F, 0x25, 0x8D, 0x0E, 0x73, 0x7C, 0x45, 0xE9, 0xA9, 0x3C, 0xF6, 0xC9, 0x9B, 0x16, 0xC9, 0x34, 0x63, 0x95, 0x02, 0x6A, 0xC6, 0x59, 0x01, 0x2A, 0x80, 0x11, 0x1E, 0x40, 0xD1, 0x45, 0x79, 0x15, 0x20, 0x06, 0x98, 0x4D, 0xCC, 0x9A, 0x9D, 0xD5, 0x95, 0x2D, 0xDD, 0x1D, 0x2A, 0x44, 0x04, 0x66, 0xEF, 0x7D, 0x5A, 0x69, 0xE3, 0xEE, 0xBA, 0x36, 0x53, 0x2B, 0xF2, 0xF6, 0x5E, 0x59, 0xF6, 0xE6, 0x29, 0xB7, 0xAE, 0x5B, 0x43, 0xE2, 0xB3, 0x33, 0x70, 0x76, 0x3E, 0x52, 0x80, 0xD3, 0x6C, 0x77, 0x03, 0xB2, 0x26, 0x8D, 0xFB, 0xF6, 0x73, 0xC6, 0xF3, 0x14, 0xDE, 0x6A, 0x93, 0x29, 0xBC, 0x00, 0x57, 0xC0, 0x36, 0x20, 0x0A, 0x74, 0x5D, 0x5D, 0x3A, 0x39, 0xCE, 0x30, 0x30, 0x11, 0x41, 0x26, 0x06, 0x96, 0xB2, 0xC7, 0x8F, 0x03, 0xE3, 0xE1, 0xEA, 0x4D, 0xD9, 0x29, 0x00, 0x2B, 0xC0, 0x95, 0x48, 0x20, 0x0C, 0xC8, 0x06, 0x7A, 0x04, 0x15, 0x67, 0xCC, 0xF2, 0x9D, 0xFC, 0x87, 0x24, 0x75, 0xF7, 0x7C, 0x6C, 0xBE, 0x25, 0x85, 0x7A, 0x0C, 0x92, 0xE6, 0xA7, 0xC1, 0x60, 0xDC, 0x0E, 0xE3, 0xB8, 0x69, 0xCC, 0x9A, 0x99, 0x63, 0x69, 0x52, 0xC2, 0x78, 0xB3, 0x2A, 0x01, 0x84, 0xD7, 0x91, 0x19, 0x7E, 0x66, 0x0D, 0xE8, 0xC6, 0xCF, 0x74, 0x5A, 0x7D, 0x3B, 0xEF, 0x9F, 0xFC, 0xB4, 0xE2, 0x80, 0x1A, 0x60, 0x02, 0x24, 0x2F, 0xBC, 0xC5, 0x48, 0x8C, 0x52, 0x54, 0x94, 0xC7, 0x8C, 0x5D, 0x7D, 0xF6, 0xA2, 0x29, 0xA4, 0x50, 0x39, 0x5D, 0x14, 0x2D, 0xE9, 0x9D, 0xA9, 0x0B, 0xE8, 0x7E, 0x15, 0xC9, 0x5C, 0x40, 0x05, 0xD0, 0xD3, 0x0A, 0xC3, 0x80, 0x28, 0xA0, 0x9C, 0x1A, 0xE4, 0x9E, 0x98, 0x6D, 0x88, 0x81, 0xED, 0xBF, 0x74, 0xA1, 0xF4, 0xE0, 0x2A, 0x8A, 0xED, 0x05, 0x44, 0xB1, 0x10, 0x30, 0xB6, 0x9D, 0xCF, 0x9F, 0x90, 0xD6, 0xD9, 0x9B, 0x05, 0xB2, 0x5F, 0xBB, 0x26, 0x06, 0xCF, 0xA6, 0xFB, 0xA4, 0x01, 0xD9, 0x40, 0x24, 0x60, 0x02, 0x48, 0x00, 0x7B, 0x13, 0x93, 0xA0, 0xA0, 0xD3, 0x26, 0xE3, 0x2D, 0x3B, 0xD8, 0xE7, 0x45, 0x40, 0x88, 0x99, 0x18, 0xA7, 0xF1, 0x68, 0xDD, 0x15, 0xC7, 0xDE, 0x67, 0xD7, 0xD0, 0xA6, 0x91, 0x4B, 0xBE, 0xF5, 0x87, 0x35, 0xC9, 0xCA, 0x05, 0x34, 0x27, 0x7E, 0x39, 0xC3, 0x9D, 0xD8, 0x82, 0x17, 0x2B, 0x00, 0x53, 0x60, 0x1B, 0x20, 0xCD, 0x33, 0x63, 0xA2, 0x26, 0xCC, 0x68, 0x6B, 0x88, 0x44, 0x9B, 0xB6, 0xB0, 0x51, 0x68, 0xB5, 0xC0, 0x86, 0x82, 0x22, 0x4E, 0x53, 0xE4, 0xFD, 0x5B, 0x04, 0xA5, 0xFB, 0xDB, 0x22, 0x6F, 0x7F, 0x72, 0xBB, 0x7D, 0xBD, 0x95, 0x71, 0x5E, 0x44, 0x03, 0x22, 0x73, 0xDB, 0x03, 0x2C, 0x09, 0xE3, 0x29, 0xA7, 0xC4, 0x65, 0xAA, 0xF4, 0x1D, 0x88, 0xB8, 0xFD, 0xEF, 0xF6, 0xA9, 0x8E, 0x72, 0x9F, 0x86, 0x79, 0xC0, 0xAC, 0x1C, 0x4E, 0xAE, 0xC7, 0x94, 0x72, 0xCA, 0xAD, 0x14, 0x8B, 0xD3, 0xC2, 0x3B, 0x3F, 0x4D, 0x3E, 0x7B, 0x4D, 0x0E, 0x3C, 0xF7, 0xFF, 0x15, 0x90, 0x02, 0x96, 0x8C, 0x43, 0x25, 0x20, 0x0D, 0xF8, 0xF8, 0x85, 0xE8, 0x44, 0x4D, 0x99, 0x7C, 0x1E, 0xB8, 0x26, 0xC4, 0x7F, 0xDA, 0x5F, 0x47, 0x3E, 0x19, 0xF1, 0xB1, 0x7A, 0xDA, 0x14, 0xA0, 0xD2, 0x90, 0xEA, 0x50, 0x7E, 0x33, 0xE2, 0x77, 0xDC, 0xDE, 0xB1, 0x71, 0xAC, 0xDC, 0xA2, 0x89, 0x04, 0xD4, 0x5E, 0x7F, 0xB7, 0x94, 0xBB, 0x4F, 0x0A, 0x8B, 0x1B, 0x46, 0xC6, 0xB8, 0x47, 0x41, 0xF8, 0x14, 0x3B, 0x1D, 0x93, 0x22, 0x40, 0x72, 0x82, 0x07, 0x4C, 0x36, 0x96, 0x05, 0x47, 0x17, 0xC3, 0xA5, 0xCE, 0x0F, 0x1A, 0xF7, 0x01, 0xC4, 0xDF, 0x82, 0x66, 0x02, 0xAC, 0x4D, 0xE0, 0xAE, 0xA9, 0x6E, 0xA0, 0x92, 0x10, 0xC0, 0x15, 0x58, 0x3C, 0x33, 0x03, 0xE8, 0xC9, 0xBA, 0xF4, 0x89, 0x9A, 0x61, 0xC2, 0x5B, 0x89, 0x6C, 0x84, 0x7B, 0x85, 0x3E, 0xB7, 0x3A, 0x4B, 0x0A, 0x92, 0x36, 0x71, 0x79, 0x93, 0x86, 0xE2, 0x6B, 0x36, 0x31, 0xF9, 0x41, 0x73, 0xDD, 0xF1, 0xA8, 0x89, 0xFC, 0xD8, 0x48, 0xBA, 0xBC, 0x1E, 0x28, 0x35, 0x23, 0x4F, 0x38, 0x82, 0x88, 0x19, 0xB8, 0xED, 0x6F, 0x1F, 0x92, 0x59, 0xCF, 0xF6, 0x26, 0x92, 0x41, 0x1F, 0x45, 0x24, 0x95, 0xF9, 0x41, 0x23, 0x2E, 0x71, 0xE4, 0x09, 0xD1, 0xA3, 0x65, 0x10, 0x93, 0xD5, 0xDA, 0xA3, 0x9B, 0x25, 0xA0, 0x0E, 0xAC, 0x49, 0x75, 0x0D, 0x60, 0x6D, 0x40, 0x16, 0x4F, 0x59, 0x13, 0x35, 0x24, 0xBC, 0x54, 0x34, 0xBB, 0x4E, 0x27, 0xA3, 0x06, 0x2B, 0x4C, 0x55, 0x2C, 0x9C, 0x54, 0x92, 0xB6, 0x21, 0x1B, 0x1D, 0x51, 0x45, 0xE6, 0xCA, 0x7C, 0x93, 0x21, 0xF7, 0xFE, 0xD4, 0xCA, 0x12, 0x35, 0xE1, 0xD2, 0x37, 0x4E, 0xB6, 0x01, 0x9D, 0xA3, 0x9E, 0x3F, 0xC5, 0xC8, 0x1C, 0xEF, 0x64, 0x40, 0x4F, 0x55, 0x22, 0x23, 0xAA, 0xC0, 0x4E, 0x8E, 0xD1, 0x23, 0x6B, 0x3E, 0x49, 0x23, 0x71, 0xCA, 0x3D, 0x57, 0xDE, 0xBD, 0xFC, 0x3F, 0x33, 0xA8, 0x45, 0x04, 0x07, 0xE0, 0xB4, 0x05, 0xD0, 0x04, 0x3A, 0x08, 0x05, 0x72, 0x01, 0xBA, 0x81, 0xE5, 0x80, 0xFC, 0xA0, 0xF7, 0xBE, 0x06, 0x3B, 0x48, 0x6B, 0x08, 0x92, 0x5E, 0x8D, 0x19, 0x50, 0x0A, 0xEE, 0xFF, 0x62, 0x6C, 0x85, 0x59, 0x68, 0x62, 0x66, 0x5C, 0xB1, 0x77, 0x3E, 0xD5, 0x51, 0x6B, 0x81, 0x66, 0xB7, 0x60, 0xF1, 0xC8, 0x84, 0x79, 0xBE, 0xFA, 0x5E, 0xEF, 0x8A, 0x3D, 0x37, 0xB0, 0x47, 0x42, 0xEC, 0x71, 0x2A, 0xBB, 0xF2, 0x8C, 0x9F, 0xA2, 0xFB, 0xB9, 0xDE, 0x42, 0x81, 0xDD, 0x84, 0x02, 0xEB, 0xA9, 0xFC, 0xEF, 0x59, 0xE4, 0xCC, 0x43, 0x1A, 0x47, 0xCE, 0x87, 0x98, 0x73, 0xDE, 0xE7, 0xDC, 0x6C, 0xF1, 0xC2, 0x1B, 0x26, 0xB7, 0x3E, 0xD6, 0xD9, 0x16, 0x2D, 0x03, 0xBA, 0xB8, 0xB0, 0x58, 0x84, 0x00, 0xDB, 0x80, 0x79, 0x8E, 0x2F, 0x9D, 0xA0, 0x25, 0x6A, 0xE7, 0xDB, 0x99, 0x2A, 0xAF, 0x98, 0x39, 0x2B, 0x4D, 0x2B, 0x43, 0x39, 0xD7, 0xDA, 0x3C, 0xA5, 0x7E, 0x0A, 0x60, 0x58, 0xDE, 0xEE, 0x2B, 0xA9, 0x9F, 0xEA, 0xC5, 0xCD, 0xEB, 0xE5, 0xB8, 0x4E, 0xF5, 0x26, 0x14, 0xF0, 0x0D, 0x6C, 0x1B, 0x7B, 0x35, 0xA0, 0x3E, 0xB7, 0xB3, 0xD4, 0x49, 0x8F, 0x66, 0x36, 0x5F, 0x8D, 0x7A, 0xFB, 0xC6, 0xBC, 0x0C, 0x50, 0x05, 0x72, 0xDD, 0xCE, 0x96, 0x31, 0x4B, 0x7C, 0x9C, 0xA9, 0xB3, 0xB9, 0xBE, 0x4F, 0xFB, 0x1E, 0xE7, 0xCA, 0x42, 0x04, 0x68, 0xAE, 0xE2, 0xC6, 0x62, 0x40, 0xE4, 0xC5, 0x24, 0xD7, 0x97, 0x02, 0x61, 0xC0, 0x49, 0x99, 0xB7, 0x09, 0x5A, 0xD1, 0x0B, 0x6F, 0x23, 0x23, 0x3D, 0x85, 0xCD, 0x5B, 0x66, 0xED, 0x39, 0x2B, 0xA0, 0x11, 0x93, 0x9C, 0xEE, 0x24, 0x3A, 0xE6, 0x2F, 0xAF, 0xB9, 0xA6, 0x50, 0x1F, 0xAB, 0x73, 0x1F, 0xE4, 0x68, 0xDA, 0x80, 0xEA, 0x94, 0x09, 0x03, 0xA7, 0xF3, 0x77, 0x00, 0x53, 0x60, 0x66, 0x93, 0x2A, 0x9A, 0x6F, 0x39, 0xB5, 0x3C, 0xAB, 0xB2, 0x75, 0xB2, 0x16, 0xCB, 0x81, 0x65, 0x80, 0xE4, 0x2D, 0x29, 0xEB, 0x93, 0xC5, 0xB1, 0x16, 0xC3, 0xD4, 0xB7, 0x50, 0x00, 0x4F, 0x22, 0xD4, 0x20, 0x3C, 0x7D, 0x6C, 0xD6, 0x41, 0x2C, 0x62, 0x03, 0x46, 0x6C, 0x9E, 0x59, 0x7D, 0x1B, 0xEB, 0xDF, 0xFC, 0xD1, 0xEC, 0xC7, 0x2B, 0xBE, 0xCC, 0xB1, 0xA8, 0xDB, 0xC2, 0x17, 0xD9, 0x90, 0x2F, 0xB9, 0xC6, 0xEE, 0x60, 0x0D, 0xF9, 0x66, 0x93, 0xB7, 0x77, 0xF1, 0x39, 0x8F, 0xC8, 0x3D, 0x4F, 0xDC, 0x40, 0x94, 0x47, 0xF0, 0x99, 0x89, 0xBF, 0xCA, 0xDC, 0x75, 0xA7, 0x8C, 0x13, 0x98, 0x59, 0x52, 0xFA, 0xCC, 0x05, 0x5E, 0x87, 0x82, 0x98, 0x0E, 0x00, 0x05, 0x94, 0xBC, 0x8D, 0xC6, 0xEC, 0x87, 0xA0, 0xD3, 0x0E, 0xEF, 0x3B, 0xCE, 0x45, 0xEB, 0xF4, 0x69, 0xC8, 0x60, 0x6A, 0x00, 0x33, 0x4A, 0x8A, 0xD7, 0x7F, 0x35, 0x27, 0xB8, 0xEB, 0x58, 0x76, 0x4B, 0x02, 0x61, 0x40, 0xCB, 0xBB, 0x1D, 0xEF, 0x06, 0xB4, 0xBF, 0xFB, 0xF0, 0x3E, 0xD2, 0x50, 0xAD, 0xA7, 0xF7, 0xA2, 0x95, 0x62, 0x7C, 0x77, 0xFF, 0x44, 0xE5, 0xB5, 0x27, 0x33, 0xB0, 0xB8, 0xC7, 0x6B, 0x34, 0xCB, 0x73, 0x2E, 0x03, 0xDE, 0xC5, 0xE7, 0x3A, 0xFE, 0x5C, 0xF7, 0x49, 0xD5, 0x7F, 0x45, 0x5F, 0x7A, 0xB3, 0xCB, 0xF3, 0x34, 0xA0, 0x8E, 0x05, 0x2C, 0xE2, 0x34, 0x0C, 0x0D, 0xC4, 0xCC, 0xEA, 0xB6, 0xC7, 0xD5, 0x09, 0xE4, 0x79, 0xF6, 0x2F, 0x07, 0xA4, 0x18, 0x3A, 0x88, 0x88, 0x38, 0xD3, 0x12, 0x67, 0x7A, 0xFE, 0x15, 0x06, 0x6D, 0x6E, 0x34, 0x73, 0xA9, 0x2D, 0x94, 0x3C, 0x6C, 0x5C, 0x95, 0x88, 0x74, 0xA0, 0xB9, 0x30, 0xDD, 0x05, 0x28, 0x11, 0x5C, 0x83, 0x2E, 0x01, 0x64, 0x03, 0xBE, 0x26, 0x66, 0xFB, 0xD9, 0x5D, 0x0F, 0x69, 0x96, 0x3C, 0xE4, 0x23, 0x0C, 0x85, 0x15, 0x37, 0xAB, 0x12, 0x13, 0x3C, 0xF9, 0x2D, 0xA4, 0xCE, 0x45, 0x99, 0xDC, 0x30, 0x3E, 0xCF, 0xB0, 0x3D, 0xA6, 0xA2, 0x93, 0x49, 0x76, 0x13, 0x7C, 0xEA, 0x28, 0xA7, 0xDA, 0xB7, 0x03, 0xB3, 0x51, 0x74, 0xF4, 0x69, 0x26, 0x78, 0x32, 0xC2, 0x16, 0xD1, 0x0A, 0xEC, 0x02, 0xD6, 0x02, 0x34, 0x80, 0x70, 0xDE, 0x98, 0x7E, 0x47, 0x45, 0x09, 0xA9, 0x38, 0xC0, 0x16, 0x3F, 0x7B, 0x63, 0x51, 0x5E, 0x4E, 0x50, 0x7F, 0x6D, 0x6E, 0x4E, 0xF5, 0x3E, 0x2D, 0x50, 0xD7, 0x02, 0xD4, 0x00, 0x6F, 0x20, 0x27, 0xB5, 0x43, 0x00, 0x5F, 0x40, 0x72, 0x21, 0xB5, 0x4F, 0xCC, 0x04, 0xF9, 0x8B, 0xB1, 0x71, 0xF3, 0xC8, 0xC2, 0xB5, 0x92, 0x48, 0x72, 0x59, 0x3B, 0xA1, 0x5C, 0xAD, 0xC6, 0xA5, 0xAD, 0x82, 0xB9, 0xE2, 0xCE, 0x5F, 0xCA, 0x4B, 0x7E, 0x92, 0x86, 0x7E, 0x68, 0x1E, 0x49, 0x51, 0x2E, 0x6E, 0xDA, 0x94, 0xB0, 0x7C, 0xD1, 0x16, 0xA0, 0x7D, 0x0A, 0x76, 0x4B, 0x80, 0x45, 0x74, 0x4E, 0x19, 0x0D, 0x45, 0xB8, 0x69, 0xAE, 0xAB, 0xAF, 0x3E, 0x94, 0x0D, 0xD8, 0x7E, 0xEF, 0xE2, 0xCE, 0x76, 0x78, 0x91, 0xD3, 0xD4, 0x93, 0x0F, 0xBB, 0xE9, 0x93, 0x32, 0x59, 0x07, 0xD4, 0x80, 0x8A, 0xC3, 0x2D, 0x9C, 0x4B, 0x9E, 0xFA, 0x74, 0x8C, 0x52, 0xC0, 0x36, 0xA0, 0x3D, 0x47, 0x44, 0x01, 0x11, 0xD4, 0x48, 0x64, 0x62, 0x36, 0xF7, 0xFB, 0x29, 0xCF, 0xAC, 0x91, 0x97, 0x9F, 0xC4, 0x04, 0xDD, 0xCD, 0xAE, 0x39, 0xC5, 0x6E, 0x7A, 0xC9, 0xDD, 0x74, 0xAA, 0x1B, 0x40, 0xDB, 0xB5, 0x79, 0x44, 0xAE, 0x29, 0x22, 0x91, 0xCD, 0xE1, 0xE6, 0xD4, 0xE4, 0x29, 0x7F, 0xF6, 0xF4, 0xE6, 0x5D, 0x80, 0xF0, 0xCC, 0xC5, 0xD1, 0x23, 0x3E, 0x96, 0x39, 0xEC, 0x02, 0x12, 0x54, 0xA7, 0xEB, 0xBD, 0x51, 0x97, 0x00, 0x5D, 0xB7, 0x44, 0x91, 0x4F, 0xD3, 0x49, 0x95, 0x49, 0x4A, 0x17, 0x65, 0x04, 0xEE, 0x91, 0x48, 0x2F, 0x72, 0x8E, 0xAC, 0x02, 0x4A, 0x3E, 0xF9, 0x41, 0x8B, 0x08, 0xC0, 0x37, 0x90, 0x02, 0xB4, 0x11, 0x1C, 0x67, 0x2B, 0x27, 0x66, 0x86, 0xBC, 0xB7, 0xD8, 0xFF, 0x35, 0xEE, 0xF3, 0x77, 0x62, 0xBB, 0x33, 0x8C, 0xEE, 0x06, 0x58, 0x0A, 0x2D, 0xFF, 0x5D, 0x94, 0x2D, 0xD8, 0xA6, 0xCA, 0xFE, 0x6E, 0x45, 0x4D, 0xD7, 0x3F, 0xFF, 0x18, 0xBD, 0x74, 0x03, 0x15, 0x80, 0x27, 0xA0, 0x0A, 0xAC, 0x22, 0x04, 0xF0, 0x71, 0x95, 0xE7, 0x24, 0x5F, 0x13, 0x47, 0x36, 0x4B, 0x7B, 0xAE, 0x34, 0x72, 0x13, 0x01, 0x44, 0x5F, 0xFB, 0x7C, 0xE7, 0x8B, 0x7B, 0x9F, 0x9D, 0x9A, 0x98, 0x1D, 0x4E, 0x4A, 0x7B, 0x53, 0x9F, 0xBB, 0x05, 0x88, 0xFD, 0x1A, 0x0B, 0x6C, 0x22, 0x17, 0x10, 0x84, 0x4C, 0xED, 0x6E, 0x01, 0x4A, 0x4C, 0xA1, 0x96, 0xD7, 0x44, 0xCD, 0x59, 0x55, 0xAF, 0x3F, 0x59, 0x45, 0xD3, 0xD0, 0x5D, 0x3B, 0xE6, 0x36, 0x37, 0x2D, 0xC6, 0x10, 0x3C, 0xED, 0x86, 0xD7, 0x8D, 0xE9, 0xE3, 0xD8, 0xF7, 0xAD, 0xF2, 0x39, 0x6B, 0x9B, 0xE5, 0x40, 0x0A, 0xE0, 0x05, 0x88, 0xCD, 0xCE, 0x1D, 0xE0, 0xFE, 0x9A, 0x53, 0x9F, 0x49, 0xFE, 0x78, 0x38, 0x3E, 0x09, 0x0D, 0x71, 0xA6, 0x32, 0xA9, 0x80, 0x27, 0xA0, 0x0E, 0x4C, 0xC3, 0x9A, 0x32, 0x4E, 0x93, 0x6D, 0xDD, 0x26, 0x73, 0x09, 0x9C, 0x62, 0x63, 0x74, 0x05, 0xC1, 0xDE, 0x7A, 0x00, 0xF3, 0x3C, 0x5E, 0x0B, 0x88, 0x4D, 0xF0, 0x48, 0x37, 0xF3, 0x0C, 0x03, 0xF0, 0xF5, 0x6E, 0x33, 0x64, 0x4F, 0xD4, 0x02, 0xDB, 0x2A, 0xAA, 0xE8, 0x2B, 0xD8, 0x3E, 0x63, 0x0D, 0x06, 0xCB, 0xBD, 0xB9, 0x0F, 0x27, 0x88, 0x5A, 0xEA, 0x6F, 0x70, 0x6C, 0xA9, 0x5F, 0xD4, 0xB0, 0x78, 0x1A, 0x72, 0xA6, 0xFB, 0x9A, 0x6A, 0x3A, 0xD0, 0x1B, 0x48, 0x07, 0x7C, 0x03, 0x4A, 0x6C, 0x07, 0x64, 0x01, 0xCD, 0xE0, 0x45, 0xBC, 0xF9, 0x2E, 0x61, 0x0C, 0x50, 0x33, 0xDA, 0x4A, 0x38, 0x50, 0x53, 0x7D, 0x15, 0x8C, 0xDA, 0xC9, 0x77, 0x09, 0x8E, 0xA7, 0x29, 0x09, 0x33, 0x04, 0x28, 0x94, 0x01, 0x4A, 0x60, 0x12, 0xB7, 0x63, 0xAC, 0x14, 0x72, 0xCC, 0x9E, 0x88, 0xC0, 0x8B, 0x65, 0x80, 0x25, 0xB0, 0x09, 0x35, 0x9C, 0x22, 0x31, 0x51, 0x4B, 0x96, 0xC2, 0xF8, 0xEF, 0x06, 0x56, 0x56, 0xC8, 0xB9, 0xAC, 0x84, 0x67, 0xCE, 0xE9, 0x66, 0xDD, 0xB4, 0xF7, 0x30, 0xEC, 0xE7, 0x56, 0x8F, 0x18, 0xC4, 0x0B, 0xF5, 0x75, 0xEC, 0x4B, 0x9D, 0xE4, 0x0C, 0xA3, 0xF8, 0x40, 0xEC, 0xE4, 0x4E, 0x39, 0xCD, 0x67, 0x9C, 0xA7, 0x78, 0x03, 0x2B, 0x81, 0xB8, 0x3D, 0xF2, 0xAE, 0x2B, 0x6B, 0x17, 0x5E, 0xCC, 0x0D, 0xEC, 0x24, 0x1C, 0x58, 0xFB, 0xFE, 0x2C, 0x4E, 0x3F, 0xF8, 0xF6, 0xDB, 0xC2, 0x6C, 0x9D, 0x9D, 0x86, 0x1D, 0x53, 0x6C, 0x31, 0xE5, 0x15, 0x40, 0x73, 0xDE, 0x9A, 0x4C, 0x3C, 0x14, 0x21, 0x02, 0xD8, 0xC4, 0xDA, 0x38, 0xA5, 0x17, 0x8F, 0x70, 0xCA, 0x1D, 0x6A, 0x85, 0x49, 0x86, 0x29, 0xDA, 0xE8, 0x2D, 0xC3, 0x6C, 0xE6, 0x6A, 0xB7, 0xC8, 0xB9, 0xD9, 0x98, 0xCF, 0x2F, 0x47, 0x07, 0x0B, 0xD3, 0x6B, 0xB0, 0x5C, 0xFE, 0x35, 0x58, 0x96, 0x3B, 0x5D, 0x43, 0x4D, 0x2A, 0x04, 0xCC, 0x02, 0xF4, 0xD9, 0x7B, 0xC9, 0x79, 0xCC, 0x9C, 0x75, 0xFA, 0xB8, 0xAA, 0xD6, 0xC4, 0x5C, 0x15, 0xDB, 0xED, 0xF1, 0xA6, 0x5B, 0xCD, 0x99, 0xDE, 0x80, 0x8D, 0xB9, 0xE9, 0x5E, 0x8C, 0xE4, 0xF8, 0xA6, 0x4D, 0xF1, 0x0B, 0xF5, 0x72, 0xE1, 0xF3, 0xA5, 0x92, 0xD5, 0xC4, 0xD3, 0xD4, 0xB3, 0x26, 0x4D, 0x93, 0x21, 0x54, 0x20, 0x16, 0xE0, 0x05, 0x68, 0x72, 0xD2, 0x47, 0x44, 0x03, 0xC5, 0x60, 0x57, 0x4D, 0xD0, 0xE8, 0x11, 0xEC, 0x1B, 0xE9, 0x96, 0x11, 0x78, 0x04, 0x2D, 0xC7, 0xE3, 0x50, 0x9C, 0xF7, 0xCD, 0xC0, 0x60, 0x14, 0xDE, 0xA2, 0x72, 0x8F, 0x14, 0xC4, 0x02, 0xA9, 0x57, 0x85, 0xD4, 0x7A, 0xDB, 0xE6, 0xBA, 0x02, 0x53, 0x11, 0x55, 0x09, 0xD8, 0xA7, 0x05, 0x6A, 0xD9, 0x9B, 0xD2, 0xE1, 0x13, 0x34, 0xDB, 0x80, 0xC8, 0x93, 0x68, 0x94, 0x06, 0x54, 0x10, 0xFD, 0xB4, 0x3B, 0x40, 0xAA, 0x1B, 0x2D, 0xE4, 0xAE, 0xBF, 0xC1, 0xEC, 0xC1, 0xD8, 0x29, 0xA5, 0xCE, 0x09, 0x45, 0x73, 0xA4, 0xD5, 0xBB, 0x42, 0x32, 0x01, 0x5C, 0x01, 0x2B, 0x40, 0x83, 0x50, 0xC0, 0xB9, 0x88, 0xD2, 0x59, 0x79, 0xF6, 0xD4, 0x71, 0x15, 0x33, 0x9C, 0xE9, 0x66, 0x12, 0xEB, 0xD3, 0x4C, 0x7B, 0x72, 0x1B, 0x12, 0x6A, 0xA9, 0xEA, 0x5D, 0xAE, 0xB7, 0x3F, 0x93, 0x5C, 0x54, 0xE7, 0xBF, 0xDA, 0xE0, 0x4E, 0x60, 0xED, 0xDB, 0x3C, 0x61, 0x9F, 0xEB, 0xB2, 0x1C, 0xF0, 0xBC, 0x2D, 0xF0, 0xEC, 0x64, 0xD1, 0xE9, 0x05, 0x12, 0xCF, 0x01, 0x51, 0x42, 0x80, 0x95, 0x40, 0xFB, 0xB8, 0xF0, 0x21, 0x5A, 0x32, 0x9E, 0x31, 0x75, 0xF7, 0xCB, 0x8B, 0x9B, 0x29, 0x5C, 0xBF, 0x86, 0x9E, 0x1D, 0x16, 0x09, 0xA6, 0xF2, 0x26, 0x90, 0x05, 0x94, 0x00, 0xB9, 0x01, 0x73, 0x40, 0x37, 0xE1, 0xE3, 0x49, 0x30, 0x41, 0x7B, 0x2B, 0x06, 0x4A, 0x9A, 0x39, 0xA0, 0x85, 0x56, 0x43, 0x16, 0xB8, 0x1D, 0xB4, 0xC1, 0x64, 0x66, 0x25, 0x53, 0x91, 0xEC, 0xAE, 0x3C, 0x25, 0x80, 0xD1, 0x68, 0xF3, 0x07, 0xD9, 0xA7, 0x0A, 0x49, 0x05, 0x98, 0xD2, 0x24, 0x99, 0xAE, 0x33, 0xA3, 0xFD, 0x7C, 0x76, 0xA5, 0xD2, 0xDF, 0xC5, 0x94, 0x1B, 0xD0, 0x02, 0xCC, 0x22, 0xAC, 0x36, 0x8E, 0xB6, 0x02, 0x9A, 0x77, 0x47, 0x95, 0xF1, 0x1C, 0x27, 0x49, 0x0F, 0xBC, 0x1D, 0x3B, 0xC6, 0xB7, 0x11, 0xAA, 0x73, 0x31, 0x45, 0x55, 0x2A, 0x71, 0x8F, 0x78, 0x9A, 0x79, 0x46, 0x02, 0xBD, 0xB0, 0x92, 0xD8, 0x84, 0x09, 0x90, 0x0E, 0x74, 0xC2, 0x4D, 0x5F, 0x74, 0x62, 0x76, 0x17, 0xE6, 0x0E, 0xF3, 0x47, 0xD4, 0x71, 0xF8, 0x6F, 0x9E, 0x6F, 0xBE, 0xA1, 0x97, 0xAC, 0xC4, 0x94, 0x57, 0x83, 0xD9, 0x00, 0x75, 0xC5, 0xB4, 0xFD, 0x69, 0x5C, 0x96, 0x7B, 0xEA, 0xFF, 0xA6, 0xE4, 0x7F, 0x03, 0x11, 0x53, 0x87, 0x3A, 0x12, 0xCE, 0x6B, 0x49, 0x6B, 0x0A, 0xE4, 0x64, 0x77, 0x18, 0xCE, 0xAC, 0x0D, 0xA4, 0x52, 0xDA, 0x08, 0x40, 0x0A, 0x08, 0x05, 0x7A, 0x26, 0x17, 0xB7, 0x6E, 0xCC, 0x16, 0x17, 0xED, 0x3E, 0x59, 0xC9, 0x4C, 0xA6, 0x2D, 0xBC, 0xAF, 0x98, 0xA3, 0x57, 0x2C, 0x59, 0x2E, 0xDE, 0x68, 0x0A, 0x62, 0x1F, 0xDB, 0x98, 0x01, 0x9E, 0x40, 0x15, 0xD7, 0xF5, 0x0A, 0x14, 0xDB, 0x74, 0x2D, 0x05, 0xEC, 0xC4, 0x4C, 0x79, 0x23, 0x35, 0x0C, 0x29, 0x11, 0x24, 0x12, 0xBB, 0xBE, 0xDD, 0xDE, 0x24, 0x51, 0x49, 0x71, 0xCD, 0x88, 0x6F, 0xE3, 0xB2, 0x53, 0x4C, 0x36, 0x2D, 0x85, 0x94, 0xE7, 0x28, 0xE3, 0xE3, 0x8B, 0xE8, 0x31, 0xE1, 0x9A, 0x46, 0xA8, 0xC0, 0x12, 0x3E, 0xF5, 0x78, 0x54, 0x53, 0xEE, 0x48, 0x45, 0xD9, 0x47, 0x6B, 0xF4, 0xF1, 0xD5, 0x03, 0x76, 0x8F, 0x4A, 0x0D, 0x84, 0xDD, 0xEC, 0xA9, 0xE4, 0xA4, 0x22, 0x68, 0xE8, 0x14, 0x88, 0x96, 0xF3, 0xED, 0xB1, 0xA6, 0xAB, 0x38, 0x4E, 0x09, 0x3D, 0x2A, 0xC8, 0xE2, 0x58, 0x5C, 0x05, 0x84, 0x03, 0xD9, 0x84, 0x03, 0xB1, 0x00, 0x0F, 0xA0, 0x8C, 0x39, 0xE3, 0x27, 0x68, 0x37, 0xFD, 0xE0, 0xF7, 0xF6, 0xC6, 0xAE, 0xEB, 0xD6, 0xDF, 0xF4, 0x41, 0xDC, 0xE1, 0x31, 0xA5, 0x8E, 0x94, 0xA1, 0x79, 0x60, 0x44, 0x30, 0xB1, 0xFB, 0xDD, 0x2B, 0xE6, 0x93, 0x70, 0x4F, 0x5C, 0x63, 0xBC, 0x46, 0x93, 0x70, 0x60, 0x4D, 0xDB, 0xCF, 0xBA, 0x35, 0xC2, 0x23, 0x20, 0xE6, 0xE9, 0x27, 0x17, 0x9C, 0x7D, 0xEF, 0x05, 0x64, 0x31, 0x66, 0x02, 0x24, 0x5F, 0x5C, 0x0A, 0xE8, 0x1A, 0x2F, 0xD6, 0xB9, 0x46, 0x29, 0x35, 0x4E, 0xB2, 0x78, 0xE3, 0xA6, 0x55, 0xC1, 0x34, 0x82, 0x1F, 0x9C, 0xCB, 0x4B, 0x2C, 0xF0, 0x70, 0x55, 0xF2, 0x02, 0x5C, 0x06, 0xD8, 0x06, 0xA2, 0x80, 0xDE, 0xBC, 0x0E, 0x05, 0xF0, 0x06, 0xD0, 0x4D, 0xE8, 0x3A, 0xF5, 0xB5, 0x73, 0x42, 0x34, 0xEB, 0x27, 0x9E, 0x72, 0xF7, 0xA2, 0x60, 0x9D, 0xD8, 0xB0, 0xBA, 0x93, 0x42, 0x6B, 0x01, 0x38, 0xAB, 0xD5, 0xFE, 0x66, 0x0C, 0x6D, 0x7B, 0x33, 0x95, 0xD7, 0xE7, 0x69, 0xE9, 0xFB, 0xED, 0xC8, 0x26, 0xFE, 0x36, 0x64, 0xDF, 0x42, 0x34, 0x10, 0x05, 0x34, 0x57, 0x5A, 0xA5, 0x9F, 0x66, 0x8C, 0x0B, 0xB0, 0x00, 0x42, 0x6E, 0xCD, 0x77, 0x8D, 0x78, 0x30, 0x8E, 0xC2, 0x72, 0x56, 0xF8, 0x12, 0xD7, 0xDD, 0x65, 0x0A, 0x81, 0xB8, 0x02, 0xF6, 0xE6, 0x30, 0xC2, 0x46, 0x24, 0x9B, 0x80, 0x02, 0xA5, 0x84, 0x01, 0x51, 0xC4, 0xBC, 0x88, 0xF1, 0x0A, 0x20, 0x6A, 0xCC, 0xCF, 0x48, 0x43, 0x33, 0xBD, 0xAC, 0x09, 0xDE, 0x93, 0xA9, 0xBC, 0xA7, 0xDF, 0x06, 0x4A, 0x55, 0xCA, 0x71, 0x0F, 0xAC, 0xB3, 0x8C, 0xCA, 0x7F, 0x2E, 0x08, 0x14, 0x28, 0x03, 0x72, 0x03, 0x26, 0xC0, 0x6E, 0x60, 0x31, 0x08, 0x3D, 0x0B, 0xD3, 0x1F, 0x6C, 0x02, 0x7B, 0xB0, 0x92, 0x6F, 0x27, 0xB4, 0x81, 0xF3, 0x17, 0xC6, 0xAB, 0xFF, 0x5A, 0xE1, 0xB3, 0x75, 0x0A, 0xAF, 0x56, 0x8A, 0x02, 0x65, 0xB7, 0x88, 0x0E, 0x0B, 0x91, 0xB7, 0xD6, 0x98, 0x57, 0x56, 0xC5, 0xD4, 0x0C, 0x13, 0x09, 0xD8, 0x06, 0x56, 0xF2, 0x14, 0xC3, 0xD1, 0x3E, 0x55, 0x62, 0x13, 0x35, 0x6C, 0x34, 0xF9, 0x2A, 0x08, 0x6F, 0xC5, 0x07, 0xB2, 0xBD, 0x5A, 0xB7, 0x05, 0xF4, 0x5A, 0xD9, 0x0E, 0x53, 0x07, 0x7B, 0xFA, 0x7E, 0x66, 0x7E, 0x0A, 0x17, 0xFD, 0xC8, 0x6A, 0x33, 0xE5, 0x1C, 0x5F, 0x43, 0xBE, 0x58, 0xF9, 0xD4, 0x09, 0xAC, 0xE4, 0xC4, 0x4C, 0x80, 0x9E, 0x53, 0x9C, 0xEF, 0x5B, 0x93, 0x22, 0x5F, 0x4C, 0x4D, 0x9E, 0xED, 0x3C, 0x20, 0x8C, 0x88, 0x67, 0x59, 0xE1, 0xD4, 0x82, 0x99, 0xDE, 0x30, 0xD9, 0x8D, 0xBE, 0x38, 0xAA, 0xE8, 0xB7, 0x16, 0x14, 0xB2, 0x03, 0xAB, 0x12, 0x24, 0x14, 0x51, 0xA6, 0xCC, 0xE4, 0x74, 0xA2, 0x01, 0xDF, 0x80, 0x29, 0x20, 0x0D, 0x6C, 0xC2, 0x70, 0x8B, 0xBB, 0x4F, 0xCF, 0xC2, 0x3C, 0x62, 0x27, 0xAA, 0xB0, 0x6A, 0xA3, 0x94, 0x00, 0x5B, 0xEC, 0xAB, 0x7C, 0x8C, 0x1E, 0x0C, 0xAB, 0x20, 0x15, 0x64, 0xD3, 0x4A, 0x7F, 0x6D, 0x5B, 0x3F, 0xAD, 0x09, 0xA6, 0xA4, 0x7F, 0x7F, 0x32, 0x94, 0x09, 0xE9, 0xB7, 0x95, 0xFF, 0x92, 0xB7, 0xA5, 0x5F, 0xC6, 0x9B, 0x9C, 0xDB, 0x09, 0xAC, 0xC7, 0xB0, 0xFF, 0x0E, 0xB5, 0x04, 0x62, 0xA4, 0x90, 0x89, 0xFD, 0x71, 0x84, 0x6F, 0x3A, 0x96, 0x4C, 0x59, 0x3B, 0x8B, 0x38, 0x71, 0x26, 0x76, 0x7C, 0x1E, 0xD7, 0xA0, 0xE0, 0x70, 0x8A, 0x59, 0x03, 0x6C, 0xC0, 0x16, 0x20, 0x0D, 0x2C, 0x8E, 0xB1, 0xE2, 0xD1, 0xFE, 0x1D, 0x5D, 0x07, 0xEF, 0x6E, 0xA4, 0xEA, 0xB8, 0x23, 0xC7, 0xA3, 0x1A, 0x85, 0x77, 0x29, 0x8F, 0xCE, 0xB1, 0x7D, 0x23, 0x15, 0xC0, 0x60, 0xDB, 0xDA, 0xB6, 0xDE, 0x44, 0x65, 0x10, 0xA9, 0xE3, 0xB8, 0xDE, 0x3E, 0x39, 0xC9, 0x9D, 0x40, 0x1A, 0x30, 0xFB, 0x55, 0x45, 0x28, 0xB1, 0x88, 0x89, 0xE8, 0x5E, 0x40, 0x28, 0x5E, 0x9C, 0x5B, 0x97, 0xAE, 0xC9, 0x81, 0x06, 0xBA, 0xDE, 0xC6, 0x75, 0xA1, 0x77, 0xDB, 0x9E, 0x93, 0x63, 0xEA, 0x1C, 0xD7, 0xC3, 0x08, 0x4F, 0xAD, 0xC7, 0x51, 0xB9, 0xB9, 0x71, 0xDE, 0x63, 0xDF, 0x35, 0xEE, 0x76, 0xFB, 0x85, 0x06, 0x7F, 0xB6, 0x01, 0x4F, 0xA0, 0xF8, 0x4D, 0x4C, 0xCE, 0xAD, 0x3C, 0xED, 0x2A, 0x7F, 0x6B, 0xC2, 0xE2, 0xBA, 0xCD, 0xF8, 0x22, 0x2B, 0x6E, 0xB3, 0x71, 0xB3, 0x88, 0x40, 0x8D, 0x84, 0xD4, 0x99, 0xCF, 0x42, 0x0F, 0x7C, 0x67, 0x1D, 0x3E, 0xB7, 0x97, 0xC9, 0xC9, 0xDF, 0xDC, 0xCC, 0xB4, 0x49, 0x2A, 0x9E, 0x1A, 0x9A, 0x71, 0x7A, 0xA8, 0xF1, 0x1F, 0x01, 0x74, 0x36, 0xAA, 0x16, 0x50, 0x7A, 0x8E, 0xE8, 0x6C, 0x01, 0x48, 0x02, 0xA1, 0x37, 0x31, 0x75, 0x2A, 0x8B, 0xF7, 0x88, 0x3C, 0xCC, 0x8F, 0xE5, 0x9D, 0x20, 0xA6, 0xA4, 0xAA, 0xF8, 0x24, 0x34, 0x9C, 0x52, 0x88, 0x2F, 0xA6, 0x63, 0xAC, 0x8F, 0xEC, 0xC2, 0x04, 0xCC, 0x13, 0x68, 0xFB, 0xEC, 0xB6, 0x8C, 0x72, 0x99, 0x80, 0x6E, 0x20, 0x4E, 0xD0, 0xF6, 0xD3, 0x41, 0xAA, 0xAC, 0xB1, 0xAD, 0x53, 0x7E, 0x5E, 0xD4, 0x31, 0xEA, 0x11, 0x78, 0x2E, 0x23, 0x01, 0xF6, 0x4D, 0x54, 0xD6, 0xE7, 0xAE, 0xE6, 0x53, 0x68, 0x8C, 0x68, 0x21, 0xBE, 0xF9, 0x16, 0x04, 0xA0, 0x56, 0x67, 0x42, 0x38, 0x13, 0x46, 0xCE, 0x5A, 0x30, 0x1B, 0xBF, 0xE6, 0x4E, 0x53, 0xE4, 0x79, 0x73, 0x66, 0x00, 0x4F, 0x60, 0x3A, 0xE0, 0x1C, 0x73, 0xE6, 0x98, 0xE9, 0xE3, 0xE4, 0xDA, 0x36, 0x57, 0xE5, 0xC1, 0xD2, 0x46, 0xA1, 0x96, 0xBB, 0x38, 0xBF, 0x15, 0x4C, 0x6C, 0xD5, 0x11, 0x34, 0x9B, 0x6E, 0xC6, 0xF5, 0xD6, 0x8F, 0x66, 0x21, 0x5A, 0x5B, 0x00, 0x2F, 0x06, 0x4D, 0x00, 0x31, 0xC0, 0x7B, 0x82, 0x26, 0x4F, 0xF3, 0x8B, 0x12, 0xC7, 0xC6, 0xB3, 0x6D, 0x28, 0x12, 0x5C, 0x0C, 0x4C, 0xC1, 0xBF, 0xC7, 0xCF, 0x35, 0x38, 0x56, 0xE8, 0x93, 0x12, 0xEF, 0xAF, 0xB3, 0xD5, 0x08, 0xE0, 0xEB, 0x34, 0xB2, 0xD3, 0x7A, 0xBD, 0xB0, 0x8F, 0x27, 0xE4, 0x46, 0x44, 0x78, 0x3B, 0x8A, 0x9E, 0xF6, 0x3F, 0xF3, 0xBE, 0x91, 0x8F, 0xE6, 0x0D, 0x2C, 0x85, 0xDA, 0xEF, 0x33, 0xA0, 0xF3, 0xF9, 0x0B, 0xFB, 0x6C, 0x19, 0x9B, 0x72, 0xA7, 0xAB, 0x98, 0x5B, 0xEA, 0x4C, 0xEF, 0x93, 0x5B, 0x40, 0x9A, 0xBC, 0xF9, 0xE3, 0xFD, 0x70, 0xB4, 0x6B, 0xB6, 0xB7, 0x4F, 0x20, 0x93, 0x7D, 0xB3, 0x15, 0x30, 0x22, 0x67, 0x8F, 0x8A, 0xB0, 0x00, 0xF2, 0x8C, 0x34, 0xFD, 0xC5, 0x67, 0x17, 0x7E, 0xB5, 0x44, 0xE1, 0x2E, 0x28, 0xF5, 0x13, 0x1F, 0x6A, 0x61, 0x03, 0xAA, 0x76, 0x63, 0x25, 0x54, 0xC6, 0xFF, 0xB3, 0x68, 0x29, 0xF1, 0xA6, 0xC4, 0x6B, 0x5F, 0xAD, 0x7A, 0x63, 0x1B, 0xFB, 0x6D, 0x95, 0xB6, 0xEF, 0xB8, 0xC3, 0x7C, 0x81, 0x75, 0x43, 0xFC, 0xD4, 0x0D, 0x98, 0xE1, 0x45, 0x40, 0x8F, 0x71, 0xD8, 0x74, 0xB0, 0x8B, 0x02, 0x64, 0xCE, 0x2C, 0xC0, 0x93, 0x6F, 0xE8, 0x69, 0xCD, 0x86, 0xA0, 0x4D, 0x8B, 0xB3, 0xAC, 0xBB, 0xDB, 0x30, 0x4B, 0x52, 0x8C, 0x4D, 0x7A, 0xD9, 0x31, 0x01, 0x61, 0xCA, 0xAC, 0x8B, 0x19, 0x84, 0x84, 0x39, 0xE0, 0x9B, 0x50, 0x20, 0x36, 0x30, 0x6D, 0xA5, 0x4D, 0x27, 0x68, 0xF6, 0x6C, 0xA3, 0xAC, 0xC6, 0x97, 0xE4, 0xB7, 0xB5, 0x0F, 0x32, 0x47, 0x85, 0x5E, 0x2D, 0x85, 0x7F, 0x37, 0x36, 0x56, 0xA6, 0x6F, 0xD0, 0x8E, 0x70, 0x6D, 0x7A, 0x3A, 0x9F, 0xDE, 0x02, 0x0B, 0x3F, 0x89, 0xF1, 0xB5, 0xDF, 0x16, 0xFF, 0xA7, 0xF5, 0x8A, 0xE2, 0xC8, 0x78, 0x8A, 0x29, 0x83, 0x4D, 0xE8, 0xDC, 0xDA, 0xE6, 0xED, 0x0B, 0x47, 0x3B, 0x01, 0x84, 0x77, 0xD6, 0xFF, 0x72, 0xE6, 0x66, 0x39, 0x3B, 0x2E, 0xAC, 0x9B, 0xED, 0xE6, 0xCC, 0x9F, 0xF7, 0xB4, 0xE0, 0x3D, 0xCD, 0x8D, 0x6B, 0x4B, 0x2E, 0x2A, 0x6D, 0xBD, 0x9D, 0xB2, 0xD5, 0x80, 0x50, 0x5E, 0x97, 0x0E, 0xF8, 0x02, 0x72, 0xB3, 0x84, 0x5B, 0x26, 0x68, 0xFE, 0xED, 0xC7, 0x8B, 0xCC, 0xEF, 0x8D, 0xCB, 0xD3, 0xAD, 0xF0, 0x18, 0xDA, 0xC5, 0x74, 0x02, 0x43, 0xD3, 0x40, 0xE8, 0x22, 0x9D, 0x6F, 0x4B, 0xC1, 0xEB, 0xA9, 0x3C, 0x4D, 0xFD, 0xE7, 0xA9, 0xC6, 0xA3, 0x69, 0x79, 0xDD, 0x01, 0xE8, 0x9E, 0xEE, 0xBC, 0xC0, 0x1E, 0x6C, 0xC0, 0x0A, 0x88, 0x99, 0x58, 0xC4, 0xD4, 0xA9, 0x01, 0xBB, 0xDF, 0x23, 0x96, 0x90, 0x12, 0x35, 0xBB, 0xD4, 0xEB, 0xB5, 0xD4, 0xF1, 0x59, 0x78, 0x4E, 0xB5, 0xBF, 0x73, 0x70, 0x15, 0x75, 0x0B, 0x2C, 0xBE, 0x51, 0x71, 0xCB, 0xCB, 0x74, 0x25, 0x60, 0x05, 0x94, 0x4C, 0x9F, 0x1E, 0x20, 0x1C, 0xA8, 0x49, 0x75, 0xDE, 0x13, 0xB5, 0xF8, 0x46, 0x0D, 0x97, 0xA9, 0xC4, 0xAB, 0xA8, 0xE9, 0xC6, 0x3C, 0x08, 0x9B, 0xA4, 0xD5, 0x1B, 0x8A, 0xDA, 0x66, 0xD0, 0xEA, 0xD5, 0x6E, 0x8F, 0x4C, 0x2B, 0xCA, 0xFB, 0x10, 0xB1, 0x64, 0x9C, 0xE6, 0x80, 0xB5, 0x18, 0x42, 0x01, 0xF6, 0x68, 0xFF, 0x7B, 0x1E, 0x24, 0xC0, 0x96, 0xB7, 0xAF, 0x7D, 0x10, 0xBA, 0xDE, 0xA3, 0xC9, 0xE2, 0x7A, 0x3D, 0xD3, 0x45, 0x39, 0x73, 0xDF, 0x27, 0xDD, 0x5B, 0x9D, 0x1F, 0x9E, 0x2B, 0xC8, 0x92, 0xEB, 0x63, 0x00, 0xB1, 0x18, 0x9B, 0xC8, 0x36, 0x4D, 0xC7, 0x81, 0xFE, 0xB8, 0x0C, 0x94, 0x72, 0xFC, 0x09, 0xE0, 0x0D, 0x74, 0x4E, 0xD0, 0x12, 0x65, 0xBB, 0xA9, 0xFF, 0xF5, 0x6F, 0xA2, 0x27, 0x34, 0x68, 0xF0, 0xDF, 0x1A, 0xBC, 0x02, 0x62, 0x78, 0x65, 0xB2, 0xA9, 0x7A, 0x41, 0xA2, 0x16, 0xEE, 0x40, 0x7D, 0x2B, 0x56, 0xEA, 0xF5, 0x38, 0xD4, 0x78, 0xAC, 0x95, 0x27, 0x51, 0x98, 0x4F, 0xBC, 0x3C, 0xFD, 0x8D, 0xBD, 0xDE, 0x3A, 0xE1, 0x59, 0x86, 0x76, 0x02, 0x39, 0x35, 0x90, 0x9B, 0xD1, 0x6A, 0x60, 0x2F, 0x40, 0xE3, 0x4D, 0x1F, 0x9C, 0xE9, 0xED, 0x9E, 0xF5, 0xA7, 0xCA, 0xCC, 0xC9, 0xB8, 0x5A, 0xE2, 0x03, 0x41, 0x73, 0xB1, 0xD2, 0x90, 0x77, 0xB3, 0x49, 0x7D, 0x9E, 0x7B, 0x54, 0xF0, 0xAE, 0xE4, 0x80, 0x2A, 0x60, 0x0E, 0xF8, 0x06, 0xA2, 0x81, 0x9A, 0xB5, 0x81, 0x4F, 0xD0, 0xEA, 0xF7, 0x45, 0xC4, 0xAE, 0x7F, 0x37, 0x1B, 0x47, 0x4F, 0x30, 0xE3, 0x7C, 0x0B, 0x6B, 0x43, 0x11, 0x79, 0x2D, 0x0E, 0xFF, 0xDD, 0x95, 0xA0, 0xDF, 0x2E, 0xE3, 0x1A, 0x80, 0xEF, 0xB7, 0x00, 0xCF, 0xE3, 0x99, 0x98, 0x6E, 0xCA, 0x6F, 0xB3, 0x79, 0x3E, 0xD2, 0x05, 0x95, 0xAF, 0x31, 0xB9, 0xD2, 0x69, 0xA8, 0x62, 0xBC, 0x1B, 0xE6, 0x69, 0x55, 0x90, 0xFD, 0xD6, 0x1E, 0x67, 0x4D, 0x05, 0xE8, 0x5B, 0x99, 0x6B, 0xC0, 0x2A, 0x60, 0x6F, 0xC0, 0x4F, 0xB3, 0x44, 0x07, 0x92, 0x47, 0x9E, 0x80, 0x30, 0x19, 0x4C, 0x3F, 0xDD, 0x0C, 0x6E, 0x57, 0x0D, 0x46, 0xAD, 0xB1, 0x91, 0x1F, 0xEB, 0x9F, 0x51, 0xC3, 0xFD, 0xD6, 0x93, 0x6E, 0x41, 0x1B, 0xF7, 0xA6, 0x1A, 0x6B, 0xA6, 0x6F, 0xDE, 0xAD, 0x7E, 0xFA, 0x30, 0xCE, 0x54, 0x7F, 0x7F, 0xA2, 0xB6, 0x5E, 0xB3, 0x3E, 0x9C, 0x99, 0x27, 0xF7, 0xF3, 0x38, 0xE7, 0xC4, 0xAD, 0x4C, 0x71, 0x06, 0xC1, 0x82, 0x51, 0x2B, 0x4E, 0xD9, 0xA9, 0xE2, 0x8B, 0x1E, 0xB7, 0xBD, 0x69, 0x54, 0xB9, 0xE2, 0x55, 0xEA, 0xC6, 0xA2, 0xC7, 0x1A, 0x90, 0x81, 0x00, 0xBA, 0x80, 0x34, 0x9C, 0xE9, 0xC9, 0xF7, 0x25, 0x8E, 0x5A, 0xE7, 0x45, 0x60, 0x6D, 0x9C, 0x19, 0x02, 0xD4, 0xE6, 0x29, 0xF3, 0x2C, 0xD8, 0x53, 0x44, 0xF4, 0x8D, 0x1A, 0x37, 0x96, 0x12, 0x2B, 0xCF, 0x34, 0xCC, 0x3A, 0x74, 0x33, 0xF5, 0x03, 0xBB, 0x55, 0xBD, 0xE6, 0x59, 0x00, 0xDE, 0x8E, 0x82, 0xEB, 0xD3, 0x01, 0x83, 0xD8, 0x84, 0x04, 0x10, 0xFB, 0xDD, 0x24, 0x76, 0x79, 0x5B, 0xB4, 0xCF, 0x9E, 0x24, 0x7D, 0x52, 0x19, 0x4A, 0xAD, 0x53, 0xA3, 0x10, 0xC1, 0xC0, 0xAE, 0x5B, 0xAD, 0x3F, 0xB1, 0xD0, 0xBF, 0x59, 0x4B, 0x4F, 0x2B, 0x15, 0x60, 0x3A, 0xB2, 0x36, 0x51, 0x05, 0xB4, 0xCD, 0x1C, 0xEF, 0xB5, 0x49, 0xB5, 0x06, 0x34, 0x80, 0xF5, 0xE9, 0x29, 0x2D, 0x02, 0xD8, 0xE6, 0x29, 0x3A, 0x51, 0x43, 0xC1, 0x98, 0xCE, 0xB7, 0xA4, 0xF1, 0xBB, 0x47, 0x6E, 0x16, 0xC5, 0xAA, 0x29, 0x74, 0x17, 0x77, 0xA4, 0x93, 0x09, 0x33, 0x5D, 0x6B, 0xBD, 0x51, 0xD3, 0x8F, 0x87, 0xDA, 0x9E, 0xCB, 0x6F, 0x56, 0x56, 0x09, 0x94, 0xCF, 0x53, 0x00, 0x90, 0x06, 0xC6, 0x55, 0xB8, 0x64, 0x32, 0x01, 0x29, 0x74, 0xDB, 0x14, 0x8E, 0x1B, 0x82, 0x87, 0xED, 0xDD, 0xA9, 0xD6, 0xA7, 0xFE, 0x2C, 0x7E, 0xDC, 0x1B, 0x8F, 0x1D, 0xA1, 0x8C, 0x2A, 0x8C, 0x23, 0x5D, 0x80, 0x35, 0x51, 0x80, 0x3B, 0x51, 0x40, 0xEE, 0xB7, 0xD5, 0x56, 0x73, 0xC4, 0xDA, 0x06, 0x74, 0xF3, 0xC5, 0x8F, 0xC7, 0xE6, 0x0A, 0x40, 0x78, 0xA6, 0xF8, 0x44, 0x0D, 0x6D, 0xDD, 0x5C, 0xE8, 0x8D, 0xF0, 0x5B, 0x2F, 0xFD, 0xD2, 0x04, 0xEC, 0xF5, 0xD2, 0xF1, 0xC2, 0xB2, 0xA0, 0x0A, 0x7D, 0xF1, 0x55, 0xEF, 0x46, 0xFB, 0xED, 0x1B, 0xE2, 0x73, 0x85, 0xBE, 0x83, 0xCC, 0x79, 0x14, 0x09, 0x14, 0x23, 0xBA, 0xE3, 0xED, 0xAF, 0xDF, 0x67, 0x5C, 0x4C, 0xC7, 0x26, 0x61, 0x9C, 0xC6, 0x16, 0xA5, 0xB8, 0x70, 0x66, 0xD4, 0xBA, 0x47, 0xDF, 0xBD, 0xDD, 0x5F, 0xE3, 0x34, 0xFF, 0xAB, 0x06, 0x52, 0x01, 0x6B, 0x40, 0x9C, 0x58, 0x1F, 0xCC, 0x99, 0xC9, 0xCB, 0x6F, 0x84, 0x09, 0x01, 0x96, 0xF0, 0xC5, 0xCF, 0x24, 0x31, 0x0C, 0xA8, 0xDB, 0x10, 0x00, 0x51, 0x53, 0xB4, 0x68, 0x32, 0x7B, 0x16, 0xA2, 0xBD, 0x0B, 0xE9, 0xEA, 0xD3, 0xC3, 0x78, 0x1B, 0xCB, 0x76, 0x9B, 0x9A, 0x99, 0x3F, 0x6D, 0x09, 0xF6, 0x67, 0xB2, 0x16, 0x33, 0x9C, 0xE2, 0xED, 0x90, 0x1A, 0x0B, 0xE8, 0xB3, 0x21, 0x1C, 0x40, 0xE7, 0xBD, 0x28, 0x02, 0xF1, 0x19, 0xEB, 0x38, 0xD3, 0xBF, 0x64, 0x4E, 0x67, 0xF6, 0x27, 0x9F, 0x09, 0xBB, 0xA7, 0x78, 0xF3, 0x6E, 0x4E, 0xF9, 0xD8, 0xFD, 0x9E, 0x6C, 0x17, 0x9B, 0x56, 0xA1, 0x05, 0x6C, 0xE7, 0x0E, 0x59, 0x13, 0xE3, 0x1D, 0xAC, 0x80, 0x4F, 0x96, 0x6A, 0x02, 0xE9, 0x40, 0x18, 0x30, 0x7D, 0xB8, 0x2A, 0x00, 0x37, 0x20, 0x8D, 0x67, 0xEA, 0x04, 0x8D, 0xED, 0xCA, 0x14, 0x9B, 0xE9, 0x9E, 0x71, 0x73, 0x3A, 0x4A, 0x2B, 0x30, 0xFA, 0x83, 0x8D, 0x1E, 0x8A, 0x39, 0x15, 0x8E, 0xB6, 0xF6, 0xE7, 0x61, 0xA0, 0xDF, 0xC4, 0x78, 0x67, 0xF0, 0x0A, 0xE8, 0xFE, 0xF4, 0xF7, 0x49, 0x40, 0x1D, 0xC8, 0xA4, 0x5A, 0x5B, 0x0C, 0xEC, 0xF1, 0xAC, 0x4B, 0xDE, 0xF0, 0x39, 0x55, 0x35, 0x4E, 0x16, 0x35, 0x11, 0x27, 0x97, 0x31, 0xEA, 0x7B, 0xDB, 0x2F, 0x4E, 0xC6, 0x6E, 0x1B, 0x8F, 0x88, 0x2C, 0xA0, 0xA7, 0xA1, 0x8A, 0x01, 0x7B, 0x03, 0x12, 0x40, 0xCE, 0x0D, 0x21, 0x80, 0x16, 0xA0, 0x36, 0xE0, 0x0A, 0xAC, 0xE2, 0x99, 0xF6, 0xF1, 0x59, 0x98, 0x75, 0xFB, 0x14, 0xE0, 0xD5, 0x2C, 0xDF, 0x47, 0xB0, 0x7C, 0x53, 0x4B, 0x23, 0x0D, 0x33, 0xC7, 0x25, 0x2C, 0x2E, 0x70, 0xEE, 0xDE, 0xBD, 0x6D, 0x09, 0xF4, 0x99, 0x75, 0x6D, 0x39, 0x4B, 0x9E, 0x1E, 0x5B, 0x43, 0x05, 0x72, 0xBF, 0xB7, 0x9E, 0xB9, 0xA1, 0x1C, 0x4B, 0x11, 0x66, 0xAC, 0x9D, 0x0A, 0xD8, 0xC2, 0xCC, 0x6A, 0xBC, 0xBD, 0x62, 0x7C, 0xDB, 0xA7, 0x0A, 0x74, 0xDC, 0xE6, 0x47, 0xED, 0x0A, 0x4A, 0x43, 0xC2, 0xF0, 0x32, 0xF3, 0xDF, 0x03, 0x18, 0x33, 0xC7, 0xDE, 0x40, 0x15, 0x5F, 0x5C, 0x80, 0x3B, 0xDE, 0x60, 0x0A, 0x34, 0x51, 0x06, 0xF8, 0x06, 0x96, 0xE0, 0xCC, 0x68, 0x60, 0x7A, 0x99, 0x2D, 0x9B, 0xA0, 0xC5, 0x6F, 0x22, 0xD8, 0xA6, 0x48, 0xA7, 0xB1, 0xFC, 0xDF, 0x79, 0x87, 0x6E, 0xA7, 0x7D, 0xCC, 0x86, 0x9E, 0xA1, 0xFB, 0xCE, 0xD6, 0xAE, 0xD7, 0x84, 0xBC, 0xB5, 0x65, 0x91, 0x9F, 0x9E, 0xBC, 0x49, 0x04, 0x20, 0x0A, 0xF8, 0xD3, 0x93, 0xBF, 0xA6, 0x0F, 0xA1, 0x1F, 0x6B, 0x03, 0xAB, 0x31, 0x33, 0xC0, 0x51, 0x8D, 0x3F, 0xEF, 0xDC, 0xE1, 0x6D, 0xA4, 0x37, 0x96, 0x04, 0x39, 0x8E, 0x64, 0x76, 0x0B, 0x38, 0xFE, 0xE4, 0x34, 0x09, 0x02, 0xBA, 0xC6, 0xAA, 0x13, 0xF0, 0xC5, 0xEB, 0x74, 0xCC, 0xBD, 0x17, 0xE0, 0x01, 0x98, 0x03, 0x7B, 0x14, 0xB1, 0x00, 0x36, 0xA1, 0xB7, 0x41, 0x13, 0xA2, 0x96, 0xA8, 0x4D, 0x28, 0xC5, 0x16, 0xB6, 0x3B, 0xA3, 0x46, 0x85, 0x91, 0x8B, 0xCF, 0x70, 0xE7, 0x4E, 0x66, 0xA0, 0x14, 0xCE, 0xFC, 0x89, 0x5A, 0xAE, 0x4F, 0xD4, 0x5C, 0x27, 0xCD, 0x8A, 0x71, 0x6A, 0x60, 0x1B, 0xB1, 0x00, 0x15, 0x60, 0xF4, 0xEF, 0xF0, 0x47, 0x23, 0xE2, 0x33, 0xF3, 0x3A, 0x46, 0xD6, 0xB4, 0xE6, 0xDD, 0xDC, 0xC8, 0x0B, 0xC6, 0x62, 0x04, 0x8E, 0x66, 0x98, 0x85, 0x88, 0x77, 0x43, 0x35, 0xF2, 0xF6, 0x9E, 0xBC, 0x8D, 0x79, 0xFC, 0x6D, 0x8C, 0xAA, 0xC7, 0x8D, 0x00, 0x08, 0xC2, 0x0B, 0x90, 0x78, 0xAD, 0x39, 0x54, 0xDF, 0xAE, 0xE4, 0x21, 0x13, 0x35, 0xE4, 0x23, 0xD7, 0xDE, 0x74, 0x36, 0x55, 0x46, 0x8D, 0x73, 0xE3, 0x3D, 0xBD, 0xF5, 0x19, 0xB5, 0x52, 0xB4, 0xD2, 0x6D, 0x7B, 0x3B, 0x6F, 0xD5, 0x27, 0x2D, 0xD2, 0xA6, 0x04, 0x2A, 0x80, 0x4A, 0xA0, 0x05, 0xA8, 0xF7, 0x26, 0x77, 0xFA, 0x36, 0xCA, 0xDB, 0x14, 0xC9, 0x27, 0x07, 0x91, 0x23, 0x21, 0x4F, 0x23, 0xFB, 0xD8, 0xB7, 0x5C, 0x69, 0x31, 0x16, 0x79, 0x26, 0xA2, 0x22, 0x80, 0x05, 0x5E, 0xEC, 0xFD, 0xF6, 0x42, 0x4D, 0xE5, 0x1B, 0x04, 0xD0, 0x05, 0x58, 0x03, 0xD3, 0x6A, 0xF1, 0x3C, 0x36, 0x36, 0xB0, 0x66, 0x97, 0xDF, 0x00, 0x55, 0x60, 0x09, 0xB0, 0x6B, 0xC6, 0xE8, 0x44, 0xAD, 0x91, 0xF7, 0x56, 0x06, 0xA3, 0xCB, 0xE2, 0x06, 0xAB, 0xA3, 0x77, 0x65, 0xAA, 0xB2, 0xF5, 0x25, 0x04, 0x36, 0x4D, 0x43, 0xA3, 0xE9, 0xAC, 0xD9, 0xBF, 0x7B, 0x3B, 0xF2, 0xEE, 0x5B, 0x29, 0x96, 0x7F, 0xBD, 0x9D, 0x13, 0x70, 0x07, 0xF2, 0xFB, 0x20, 0x05, 0xC6, 0x01, 0x9B, 0x0B, 0xEA, 0x69, 0x63, 0xA7, 0xCA, 0x35, 0x00, 0xC7, 0x8A, 0xC6, 0x11, 0xF8, 0xC7, 0x6E, 0xD3, 0x98, 0xE5, 0x91, 0xD3, 0x80, 0x93, 0x88, 0xE9, 0x2F, 0x9F, 0x63, 0x55, 0x0B, 0x34, 0x6F, 0xCA, 0x1A, 0x80, 0x13, 0x75, 0x2B, 0xA0, 0xB0, 0x44, 0x03, 0xAC, 0x08, 0x05, 0xF6, 0xB9, 0x91, 0x01, 0x61, 0xC0, 0x78, 0x30, 0xD4, 0x2C, 0xA7, 0x78, 0xB4, 0x8F, 0xFE, 0x4D, 0xD7, 0x31, 0xAD, 0xDF, 0xA7, 0x55, 0xDF, 0xBC, 0x8D, 0x0A, 0x76, 0xC9, 0x6C, 0xD3, 0x77, 0x6B, 0x8F, 0x8F, 0xC9, 0xDB, 0xF0, 0xB3, 0x66, 0xA3, 0x68, 0xD6, 0x76, 0x23, 0xB0, 0x6D, 0x60, 0xEE, 0x40, 0xB2, 0x81, 0x98, 0x7C, 0xA0, 0xB9, 0xA4, 0x38, 0x00, 0xBA, 0xC7, 0x2D, 0xF2, 0x3A, 0xD2, 0x09, 0x02, 0xEA, 0x9B, 0x22, 0x06, 0xAB, 0xB1, 0x27, 0x2F, 0x5E, 0xC7, 0x9A, 0x23, 0x4E, 0x2F, 0x5A, 0x9D, 0x44, 0x4F, 0x03, 0x36, 0x63, 0x50, 0x02, 0xA4, 0xBF, 0xE8, 0x8D, 0x53, 0x34, 0x5F, 0xE7, 0x09, 0xD7, 0x8F, 0xC5, 0xAD, 0xCF, 0x2E, 0x0C, 0x10, 0xF6, 0x3A, 0xE4, 0x96, 0x4C, 0xD0, 0x90, 0xF0, 0x52, 0x9E, 0x78, 0xBA, 0x55, 0x30, 0x01, 0xBF, 0x9E, 0xFC, 0xBE, 0x14, 0x43, 0x0A, 0x8F, 0x3A, 0x9A, 0x46, 0x5A, 0x3E, 0xD3, 0x8E, 0xCC, 0x8F, 0x48, 0xB4, 0xE7, 0x5E, 0xC5, 0x05, 0x41, 0xF6, 0xBB, 0x20, 0xD8, 0x0A, 0x18, 0x31, 0xF3, 0x8D, 0xE5, 0x8C, 0xEF, 0x1E, 0x17, 0x67, 0x7E, 0x98, 0x69, 0x67, 0x53, 0xB3, 0xF8, 0x7C, 0xB2, 0x64, 0xD7, 0x31, 0x8A, 0x31, 0x7B, 0xFD, 0x6D, 0x74, 0x2A, 0xE8, 0xF9, 0xB3, 0x54, 0x5E, 0xDE, 0x05, 0x84, 0x02, 0x59, 0x40, 0x73, 0x63, 0xC1, 0x99, 0x8F, 0xA4, 0x05, 0x54, 0x03, 0x99, 0xC0, 0xF4, 0xE6, 0xA8, 0x06, 0xAC, 0x80, 0xC8, 0x39, 0x65, 0xA2, 0x26, 0xCC, 0x86, 0x4B, 0xE6, 0x5D, 0xE8, 0x6F, 0x45, 0x1A, 0x69, 0x8C, 0x1A, 0x2F, 0x82, 0xD5, 0x18, 0x71, 0x46, 0x11, 0xDF, 0x71, 0x7D, 0x7E, 0x1D, 0x74, 0xC4, 0x6F, 0x2F, 0x71, 0xFC, 0xBD, 0xB7, 0x55, 0x76, 0x06, 0x30, 0x4E, 0xEF, 0x7B, 0x01, 0xDA, 0xD7, 0x57, 0x3F, 0x4F, 0x49, 0xF0, 0x66, 0x99, 0x53, 0x8D, 0x78, 0xEC, 0xB7, 0x90, 0x23, 0x4E, 0x43, 0xD5, 0x30, 0xCE, 0x70, 0xE7, 0xFA, 0x14, 0x20, 0xEC, 0x66, 0xDC, 0x2E, 0x86, 0x7E, 0x9F, 0x2B, 0x6B, 0x17, 0xA0, 0x0D, 0x84, 0x4E, 0xFF, 0x23, 0xCE, 0x22, 0x02, 0x70, 0x07, 0x2C, 0x80, 0x1D, 0xE3, 0xEC, 0x0C, 0x68, 0x02, 0x2E, 0x33, 0xF0, 0x26, 0x68, 0x8A, 0x67, 0xC7, 0x7E, 0xEB, 0x55, 0xC4, 0xE7, 0x68, 0xD2, 0x04, 0xF1, 0xA2, 0x56, 0x72, 0xE2, 0x27, 0x8F, 0xDD, 0x44, 0x03, 0xA1, 0xB7, 0xB1, 0xE2, 0x8E, 0xE3, 0xAD, 0x7D, 0x9A, 0xAB, 0x13, 0xD6, 0x40, 0xC5, 0x6B, 0x96, 0x34, 0xC5, 0xD1, 0x4D, 0x3F, 0xDB, 0xB1, 0xD5, 0x9C, 0x02, 0x89, 0x5C, 0xC0, 0x38, 0x14, 0x4E, 0x66, 0xDE, 0xE2, 0xFF, 0x52, 0xDC, 0x4A, 0x77, 0x66, 0x6D, 0x28, 0x37, 0x06, 0xD2, 0x80, 0x51, 0xEF, 0xC3, 0x00, 0x17, 0xC0, 0x14, 0xF0, 0xE4, 0x29, 0x01, 0xD4, 0xC6, 0xDB, 0x65, 0x01, 0x2B, 0xE7, 0x45, 0xC0, 0x16, 0xB0, 0x15, 0x90, 0xE4, 0x99, 0x31, 0x31, 0x33, 0x76, 0x77, 0x7E, 0xA3, 0x24, 0xE5, 0x58, 0x18, 0x45, 0xB3, 0x54, 0x64, 0xC3, 0xD8, 0x20, 0xA7, 0x18, 0x4C, 0xC6, 0xF2, 0xF6, 0xB5, 0x35, 0xE1, 0xE5, 0x38, 0x46, 0x5C, 0xDB, 0x47, 0xEF, 0x99, 0xFE, 0x29, 0xC0, 0xCC, 0x20, 0xB6, 0x01, 0xC6, 0xB1, 0x1F, 0xA3, 0x99, 0x31, 0x66, 0xD5, 0xAC, 0xDC, 0x11, 0x2A, 0xD5, 0x45, 0x55, 0x50, 0xD9, 0x48, 0x6A, 0x1A, 0x3B, 0x4D, 0x83, 0x1F, 0xFA, 0x76, 0x6C, 0x2E, 0xB6, 0x3A, 0x80, 0xA9, 0x7A, 0x49, 0x42, 0x03, 0x10, 0x27, 0x14, 0xD0, 0x7C, 0xF3, 0x39, 0x26, 0xDF, 0x76, 0x2D, 0x1C, 0xB5, 0x02, 0xD1, 0x80, 0x2A, 0xB0, 0x05, 0x90, 0xC0, 0x99, 0x52, 0x13, 0x33, 0xC7, 0x12, 0x13, 0x39, 0x1B, 0x62, 0xA1, 0xE8, 0x40, 0x54, 0xC8, 0x7B, 0xD9, 0x2E, 0x6C, 0x63, 0x16, 0x48, 0x01, 0x5B, 0x86, 0x80, 0xB4, 0xFF, 0xA2, 0xB4, 0xDE, 0x56, 0x82, 0x27, 0x49, 0x68, 0x56, 0xF9, 0xA7, 0xE1, 0xE3, 0x74, 0x3A, 0x27, 0xA2, 0x81, 0x5E, 0xEF, 0x13, 0x5C, 0x04, 0xF1, 0x9C, 0x86, 0x6E, 0x7B, 0x0C, 0x38, 0x9B, 0xC3, 0x26, 0xE8, 0xFA, 0x6B, 0x88, 0x52, 0x4D, 0x12, 0x81, 0xBD, 0x65, 0x40, 0xFB, 0xF1, 0xB5, 0x70, 0x9E, 0x12, 0x27, 0x82, 0x91, 0x78, 0xC3, 0x0E, 0x40, 0x89, 0x50, 0xC6, 0xBA, 0x80, 0xE6, 0xA6, 0x82, 0x26, 0x21, 0x9F, 0xD2, 0x45, 0x01, 0x62, 0x8E, 0xF4, 0x4D, 0xF3, 0x16, 0x09, 0xF6, 0x95, 0xD0, 0x67, 0x1F, 0x6A, 0x75, 0xF0, 0x88, 0xC9, 0x24, 0x19, 0x48, 0x0A, 0x49, 0xC1, 0x8D, 0x50, 0xE3, 0x97, 0x04, 0x25, 0xA3, 0x76, 0x03, 0x93, 0x47, 0xCC, 0xB9, 0x9A, 0x9E, 0x82, 0x66, 0xE3, 0x4D, 0x20, 0x95, 0xCF, 0x29, 0x42, 0x0C, 0xB0, 0xC9, 0xDA, 0xEF, 0x31, 0x27, 0xE7, 0x76, 0x52, 0xD0, 0x6A, 0x95, 0xBB, 0xBD, 0xB1, 0x00, 0xA8, 0x7E, 0x63, 0xCA, 0xC1, 0x84, 0xB7, 0xF0, 0xB1, 0xC8, 0x39, 0x5B, 0x71, 0xA5, 0x80, 0x31, 0x79, 0xAA, 0x89, 0x58, 0x80, 0x17, 0x91, 0xC0, 0xEF, 0x7B, 0xF8, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x84, 0x9D, 0x89, 0xAD, 0xEC, 0x4C, 0x8E, 0xAC, 0x5D, 0x69, 0x13, 0x92, 0x3B, 0xE9, 0xBF, 0x63, 0x0F, 0x15, 0x41, 0x1D, 0xA5, 0xF0, 0x5F, 0xBC, 0xC1, 0xF6, 0xA1, 0x4E, 0xD5, 0x4C, 0xF7, 0x65, 0x4B, 0x99, 0x5C, 0x83, 0xA9, 0x4F, 0xCF, 0xDF, 0xF4, 0xAD, 0x9F, 0xAB, 0x03, 0x9C, 0xC1, 0x77, 0xAD, 0x40, 0x09, 0x30, 0x8A, 0xEF, 0x5A, 0xD6, 0x66, 0x85, 0xDB, 0xD5, 0x1C, 0x05, 0x83, 0x4C, 0xC8, 0x9B, 0xD6, 0xBD, 0x2B, 0x3B, 0x6C, 0x77, 0xA5, 0x0F, 0xCA, 0x97, 0xA3, 0x2B, 0x01, 0xC6, 0xA1, 0xEC, 0x7B, 0x2B, 0x7B, 0xAE, 0x07, 0x16, 0x4C, 0x0F, 0xC6, 0xB3, 0x72, 0x00, 0x48, 0xBB, 0x3B, 0x10, 0xF6, 0xE8, 0xDB, 0x66, 0xC8, 0x8D, 0x1A, 0xBD, 0xD8, 0x7C, 0xC2, 0xC3, 0x67, 0x06, 0x96, 0xDC, 0x56, 0x14, 0x65, 0xEF, 0xD4, 0x53, 0xE2, 0x2C, 0xDA, 0x7C, 0x43, 0xD0, 0xC1, 0x27, 0x2B, 0x20, 0x13, 0xA8, 0xBA, 0xF5, 0xD3, 0xCE, 0x01, 0xA4, 0x81, 0x92, 0xCF, 0xCE, 0x4A, 0x7E, 0x1A, 0x22, 0x0D, 0xD8, 0x51, 0xAF, 0xBD, 0xBE, 0xCF, 0xEA, 0xAE, 0xF5, 0x1A, 0xAD, 0xD1, 0x06, 0x71, 0x02, 0x59, 0x99, 0xF6, 0x27, 0x1E, 0x88, 0x3D, 0xE1, 0x63, 0xB7, 0xE4, 0xE0, 0xCC, 0xF3, 0x67, 0x3B, 0x6A, 0x9E, 0x6F, 0x3C, 0x70, 0xF2, 0x5F, 0xAB, 0x56, 0x16, 0x0E, 0x54, 0xEE, 0xA7, 0x3B, 0xE9, 0xB6, 0xBE, 0xF0, 0x13, 0xE9, 0x6F, 0x6A, 0x76, 0x13, 0x14, 0xFB, 0x92, 0x8B, 0xDD, 0x4D, 0xDF, 0xDE, 0x2C, 0x11, 0x6C, 0x5D, 0xB9, 0x76, 0x5D, 0xEE, 0x6E, 0x55, 0x61, 0xEC, 0xF9, 0xD9, 0x3E, 0x13, 0x05, 0xCC, 0xB6, 0x99, 0x0C, 0x50, 0xC9, 0xA0, 0x73, 0xEE, 0x2E, 0xCC, 0x63, 0x2B, 0x76, 0x02, 0xA8, 0xDF, 0x7B, 0x1A, 0x45, 0xF7, 0x97, 0x6B, 0x35, 0x36, 0x29, 0x33, 0x95, 0x91, 0xF2, 0xED, 0xEF, 0x63, 0xAC, 0x7B, 0xE6, 0x87, 0x70, 0x45, 0x89, 0xB2, 0xE5, 0x5A, 0xB5, 0x92, 0xFD, 0xED, 0xEF, 0xCB, 0xBB, 0x52, 0x20, 0x46, 0x28, 0x71, 0x00, 0x55, 0x20, 0xCE, 0xDB, 0x53, 0xB4, 0x3D, 0x1A, 0x7B, 0x18, 0xAA, 0x3E, 0x4B, 0xFB, 0xB7, 0x40, 0xB7, 0x3D, 0xCF, 0x5B, 0x79, 0xAA, 0x6D, 0xD8, 0x1D, 0x40, 0xED, 0x33, 0xCE, 0xFD, 0x74, 0xAC, 0x31, 0x66, 0xB0, 0x5B, 0x2E, 0x21, 0x1A, 0x58, 0xC1, 0xA8, 0xDC, 0x74, 0x87, 0xF1, 0x1A, 0xEA, 0x15, 0xF1, 0x00, 0x32, 0x00, 0xE1, 0x2F, 0xAB, 0x80, 0x89, 0xBD, 0xB0, 0x68, 0xB5, 0x4D, 0xE8, 0xE5, 0x70, 0xC7, 0x42, 0xFF, 0xA2, 0xA8, 0xF0, 0xC1, 0xC8, 0x96, 0xF2, 0x86, 0x9B, 0x81, 0xCB, 0x57, 0x01, 0x69, 0x17, 0x4F, 0x36, 0x59, 0xDD, 0x8B, 0x09, 0x74, 0xAB, 0x6F, 0xBB, 0x81, 0x77, 0xEE, 0xCD, 0xE2, 0x1A, 0x37, 0xEC, 0x00, 0x7F, 0xA1, 0x03, 0x63, 0x06, 0x59, 0xB5, 0xD0, 0xDE, 0x10, 0xE9, 0x15, 0x82, 0x90, 0x1D, 0x54, 0x7F, 0xD6, 0x95, 0x6A, 0xEC, 0x86, 0x63, 0xE0, 0xE9, 0xF4, 0x5E, 0xE5, 0x3E, 0x7A, 0xFB, 0x1E, 0x7C, 0x4F, 0xF9, 0x66, 0x76, 0x71, 0x14, 0x57, 0x81, 0xDD, 0x09, 0xB1, 0x9B, 0x1E, 0x24, 0x80, 0x28, 0x22, 0x01, 0x1B, 0xE0, 0x14, 0x7E, 0xD9, 0xFD, 0x7C, 0x62, 0x82, 0x6C, 0x8D, 0x26, 0x2C, 0x68, 0x08, 0xBB, 0xB9, 0x0D, 0xFA, 0x58, 0x01, 0xA9, 0x09, 0xCD, 0x64, 0xEA, 0xA4, 0xD0, 0x44, 0x7C, 0x94, 0x5D, 0x9B, 0x7B, 0x6D, 0xDE, 0x59, 0x8E, 0x35, 0x5A, 0xAD, 0x96, 0x46, 0xD2, 0x68, 0x06, 0x98, 0x02, 0x5A, 0xC4, 0x00, 0xBE, 0xB5, 0xB4, 0xAD, 0x6F, 0xD4, 0xD9, 0x66, 0x70, 0x7A, 0xB8, 0xF1, 0x09, 0x2F, 0x57, 0x7F, 0x60, 0xDF, 0x9E, 0xB3, 0x32, 0x42, 0xC0, 0x93, 0xB9, 0xD1, 0x77, 0xE9, 0x01, 0xCD, 0x04, 0x09, 0x9C, 0x77, 0xEA, 0xE0, 0x8A, 0xD3, 0x80, 0xE1, 0x93, 0xB6, 0x2A, 0xB7, 0x62, 0xF7, 0xA2, 0xCF, 0x6E, 0x20, 0x0E, 0xA0, 0x01, 0xF8, 0xA6, 0xE0, 0x1E, 0xA3, 0x29, 0xD2, 0x73, 0x52, 0x70, 0x01, 0xAA, 0x7F, 0x65, 0xFB, 0x88, 0xFE, 0xB9, 0x1C, 0xEA, 0xC5, 0xC8, 0xA1, 0xF0, 0x93, 0x71, 0xD4, 0x76, 0x54, 0xAE, 0x8C, 0xB7, 0x7E, 0xAE, 0x02, 0x51, 0x5A, 0x2B, 0x5F, 0xB5, 0xE4, 0x6B, 0x35, 0xB6, 0x03, 0x93, 0x6F, 0xA6, 0xD2, 0x9E, 0xDA, 0x9B, 0xE5, 0x6A, 0x21, 0xBD, 0xA3, 0xEA, 0xFD, 0x48, 0x62, 0xF6, 0x0E, 0x17, 0xFE, 0xB0, 0x9B, 0x69, 0x56, 0x78, 0xAC, 0x69, 0xB4, 0xE1, 0x23, 0xA6, 0x7F, 0x9A, 0x37, 0x87, 0x17, 0xC3, 0x30, 0xB5, 0x59, 0x40, 0xCB, 0x1E, 0xF0, 0x40, 0xAD, 0x86, 0xA6, 0xF2, 0x81, 0x3B, 0xC0, 0xEE, 0x49, 0xAE, 0x01, 0xAC, 0x01, 0x39, 0x80, 0x09, 0x9F, 0x42, 0x5F, 0xA3, 0x19, 0x13, 0x27, 0xC1, 0x02, 0x8A, 0x42, 0xBA, 0xAD, 0xFB, 0x9A, 0x29, 0x18, 0x19, 0xCC, 0xD9, 0x7B, 0x72, 0x12, 0xCE, 0xB7, 0x33, 0x0D, 0x11, 0xE8, 0xBF, 0xDB, 0x6F, 0xF3, 0x16, 0x7E, 0x14, 0x21, 0x0A, 0x30, 0x05, 0x22, 0x76, 0x09, 0x02, 0xCB, 0x97, 0xB2, 0x6E, 0xF0, 0x2B, 0x4E, 0xA2, 0xCF, 0x96, 0x15, 0xE7, 0x7B, 0x52, 0xBA, 0x23, 0xDD, 0xBB, 0x74, 0xF1, 0xDD, 0x30, 0xB3, 0xFE, 0x28, 0xBA, 0xC1, 0xB1, 0xEE, 0x28, 0xDF, 0x3D, 0x17, 0xB8, 0xE9, 0xE1, 0xCF, 0x28, 0xD0, 0x87, 0xD9, 0x61, 0x61, 0x94, 0x70, 0x80, 0x1E, 0x60, 0x14, 0xC8, 0x01, 0xDC, 0x01, 0x4D, 0xC0, 0x19, 0x41, 0xC4, 0x63, 0x34, 0xC7, 0x73, 0x37, 0xC9, 0x35, 0x57, 0xAC, 0xBB, 0x47, 0xDE, 0x5A, 0x0A, 0xA7, 0x18, 0xFC, 0x0F, 0x12, 0x3C, 0xA6, 0x57, 0xE4, 0x99, 0xDF, 0xD7, 0x73, 0xE7, 0xF1, 0x3E, 0xCB, 0x8B, 0x3B, 0x80, 0x09, 0x1A, 0x54, 0x06, 0x80, 0xD1, 0x64, 0x3D, 0x11, 0x40, 0xE3, 0x23, 0x47, 0x82, 0xEC, 0x25, 0x75, 0x36, 0x5E, 0x49, 0xD5, 0xD8, 0x17, 0xEB, 0x39, 0x9F, 0xED, 0x00, 0x3B, 0xFE, 0x6A, 0xEB, 0x89, 0x04, 0x1D, 0x0B, 0xE3, 0x61, 0xD6, 0x40, 0x25, 0xFD, 0x0B, 0xBB, 0x1F, 0x31, 0x6F, 0x60, 0x0A, 0xE8, 0x00, 0xC2, 0xEF, 0x33, 0xAD, 0x04, 0xE8, 0xE4, 0x2F, 0x73, 0x8D, 0x16, 0x28, 0x6D, 0x87, 0xF2, 0x56, 0xD1, 0xCB, 0xE9, 0xD0, 0x54, 0xA4, 0x32, 0x9D, 0x62, 0x31, 0xA5, 0x78, 0x98, 0xEA, 0xD3, 0xB3, 0xEC, 0x9F, 0x92, 0xF1, 0x8E, 0x53, 0xA7, 0xDF, 0xA2, 0xF1, 0x33, 0xC4, 0x8E, 0x11, 0x04, 0xE0, 0xC1, 0xEB, 0xD3, 0x98, 0xF0, 0x7E, 0xFC, 0xB7, 0x62, 0xEA, 0xA2, 0xDF, 0xC3, 0x89, 0x46, 0x78, 0x04, 0xFE, 0xB6, 0x13, 0x61, 0xD6, 0x3D, 0x79, 0x66, 0x3E, 0xC2, 0x36, 0x45, 0xB8, 0x92, 0x4B, 0xB7, 0x3E, 0x48, 0x10, 0x63, 0xBB, 0x86, 0x0A, 0xA8, 0xDD, 0x82, 0x6D, 0xC0, 0x0C, 0x21, 0x40, 0x1A, 0xB0, 0x97, 0xCC, 0x5C, 0x9B, 0x1B, 0xD1, 0xE5, 0x40, 0xAB, 0xED, 0x53, 0xB5, 0xCD, 0xF9, 0x4D, 0xD9, 0x9E, 0xE2, 0x88, 0xA1, 0x43, 0x69, 0xA7, 0x80, 0xB4, 0x41, 0x94, 0x4A, 0x85, 0x8E, 0xE0, 0x23, 0x66, 0x40, 0xD9, 0x73, 0x6D, 0xBE, 0x9A, 0xCE, 0xF4, 0x09, 0xDF, 0x15, 0xDE, 0x32, 0xC0, 0x0A, 0x52, 0x8C, 0xBC, 0xCA, 0x5D, 0xFA, 0x28, 0x27, 0xC0, 0x90, 0xEC, 0x76, 0x8A, 0x79, 0x06, 0x23, 0x44, 0x01, 0x17, 0x20, 0x1C, 0xA8, 0xA0, 0xE3, 0xFE, 0xFB, 0xC4, 0x6A, 0x7B, 0xD2, 0xA5, 0x2B, 0x65, 0x2C, 0xC1, 0xE6, 0xD2, 0xA2, 0xC9, 0xAB, 0xF0, 0x09, 0x7E, 0x01, 0x30, 0xC3, 0x29, 0x16, 0x03, 0x5C, 0x81, 0x10, 0x20, 0x1D, 0x68, 0xE7, 0xA4, 0x99, 0x01, 0xEA, 0x80, 0xE7, 0xDA, 0xAC, 0x90, 0xA0, 0x31, 0x65, 0x5B, 0x9E, 0x50, 0x71, 0xF4, 0x67, 0x48, 0x9B, 0x51, 0x44, 0xEA, 0x92, 0x83, 0x2D, 0x15, 0xAE, 0x88, 0x92, 0xBA, 0xAF, 0x1D, 0x35, 0x44, 0xAE, 0xD0, 0x5E, 0xAE, 0x14, 0xCC, 0x1E, 0x51, 0xC9, 0x07, 0xC6, 0x08, 0x01, 0x32, 0x80, 0x70, 0x9E, 0xE4, 0xFD, 0xE7, 0x37, 0xF9, 0xAE, 0x10, 0xA1, 0x04, 0x49, 0x24, 0x07, 0x32, 0x83, 0xC7, 0x10, 0x4B, 0x41, 0xA1, 0x8F, 0xE2, 0x8D, 0xEE, 0xD6, 0x1D, 0x79, 0xCF, 0x2D, 0xD8, 0x0E, 0xF1, 0xFE, 0x1A, 0x9B, 0x31, 0x53, 0x0C, 0xA3, 0x24, 0x01, 0x32, 0x57, 0x23, 0x11, 0xC6, 0x3E, 0x0D, 0xF8, 0x07, 0x66, 0x80, 0x38, 0x70, 0x02, 0x50, 0x76, 0x41, 0x8B, 0xAF, 0xD1, 0xFA, 0x97, 0x11, 0x4C, 0xD5, 0x5F, 0x0A, 0x31, 0x8F, 0xA0, 0x7D, 0xB5, 0x14, 0x1B, 0x8E, 0xD4, 0xA1, 0x47, 0x29, 0x8D, 0x6D, 0x13, 0x7C, 0x36, 0xB2, 0xEA, 0xD7, 0xFA, 0x24, 0xB7, 0xDC, 0x44, 0xD7, 0x0E, 0xEF, 0x6F, 0xD2, 0x72, 0xDE, 0x32, 0x98, 0x3F, 0x6A, 0x38, 0xB2, 0xB0, 0x7B, 0x99, 0xDD, 0x3A, 0x4A, 0x6E, 0x4C, 0xD1, 0xCE, 0x3B, 0x7E, 0xC8, 0x24, 0x4E, 0x71, 0x42, 0xB1, 0x18, 0xF7, 0x15, 0xF3, 0xF7, 0x88, 0xF4, 0x00, 0x0B, 0xA0, 0x0F, 0xBE, 0x3B, 0x02, 0xF4, 0xCA, 0x70, 0x0C, 0x50, 0x0D, 0x0C, 0xB3, 0x4C, 0x12, 0x40, 0xDA, 0xA7, 0xB1, 0xD6, 0x09, 0x01, 0xEC, 0x00, 0x92, 0x84, 0x03, 0x5A, 0xC0, 0xF4, 0xDA, 0x6C, 0xF6, 0xE5, 0xBC, 0x55, 0xBB, 0xDF, 0xED, 0x2B, 0xFD, 0x7B, 0xC0, 0xE6, 0x7F, 0x5D, 0x58, 0xF3, 0xE0, 0x86, 0x2A, 0x8B, 0xFD, 0xE9, 0xE6, 0xBC, 0x33, 0x4C, 0x3B, 0x25, 0xCB, 0xB5, 0xF3, 0x94, 0x5B, 0xE5, 0xAC, 0x97, 0x24, 0xF0, 0xDC, 0x5E, 0x05, 0x44, 0xBE, 0xDF, 0x25, 0xB3, 0x68, 0x9C, 0x34, 0x6B, 0x5E, 0xBD, 0xCD, 0x0C, 0x6B, 0x23, 0xA7, 0x7A, 0x2F, 0xF4, 0x39, 0x44, 0x7E, 0x1A, 0xB2, 0xEB, 0x56, 0xCA, 0x94, 0x06, 0x5C, 0x80, 0x74, 0xA0, 0x0E, 0x30, 0x49, 0x6D, 0x8E, 0x01, 0xC2, 0x89, 0x20, 0x1A, 0x48, 0x07, 0x3A, 0x29, 0xFE, 0xE2, 0x80, 0x1A, 0x10, 0xEB, 0xA5, 0x39, 0xEF, 0x29, 0x15, 0x3E, 0xFA, 0x1B, 0x45, 0xED, 0x42, 0x0F, 0x41, 0xD0, 0x17, 0xC5, 0x7A, 0x8F, 0xFC, 0x02, 0xA4, 0x16, 0xE6, 0xB8, 0xFF, 0xB9, 0x1C, 0x35, 0xCE, 0x47, 0x36, 0xC1, 0x09, 0x05, 0x6A, 0x80, 0xD6, 0xF7, 0xBB, 0x2D, 0x29, 0xE4, 0xE6, 0x99, 0xE4, 0xD9, 0x15, 0x59, 0xBB, 0xB7, 0x72, 0xF0, 0x29, 0xE4, 0x5D, 0x74, 0x66, 0x4F, 0xF2, 0x37, 0x07, 0xF0, 0x2B, 0x27, 0xD0, 0x3C, 0x0D, 0x36, 0xDD, 0xE4, 0xCF, 0x85, 0x3C, 0xC6, 0x93, 0xA2, 0x80, 0xDE, 0x64, 0x1E, 0xCF, 0x06, 0x13, 0xA0, 0x0F, 0x50, 0x02, 0x38, 0x4F, 0x91, 0x51, 0x20, 0xEC, 0x16, 0x97, 0xAC, 0xC7, 0x6A, 0x82, 0xC2, 0xC4, 0x34, 0xDE, 0x0F, 0xFD, 0xEA, 0x1C, 0x32, 0xA2, 0x0B, 0x41, 0xFC, 0xEC, 0x85, 0x91, 0x93, 0xB8, 0xBA, 0x39, 0xCA, 0xFE, 0xD3, 0x02, 0xF3, 0xD6, 0xEA, 0xB4, 0x08, 0x05, 0x84, 0x50, 0xC2, 0xFA, 0x9D, 0xE9, 0x81, 0xCF, 0x4F, 0x4F, 0x77, 0x07, 0xEB, 0x76, 0xD0, 0xA8, 0xB7, 0x44, 0x49, 0x13, 0x26, 0x83, 0xF2, 0x4F, 0xEF, 0x58, 0xD0, 0x5A, 0xB2, 0xAA, 0x85, 0xF2, 0x0A, 0x44, 0x19, 0x5D, 0xF9, 0x78, 0xDC, 0x10, 0x35, 0xA0, 0x56, 0x38, 0x37, 0x56, 0xE5, 0x08, 0x18, 0x05, 0x5A, 0x00, 0x5F, 0xA5, 0x5D, 0x07, 0x22, 0x80, 0x2C, 0x7C, 0x57, 0xB2, 0x46, 0x53, 0x6A, 0x69, 0x27, 0xC6, 0xFA, 0xEA, 0x92, 0x6F, 0x95, 0xF6, 0x60, 0xFD, 0xDA, 0xD9, 0x08, 0x56, 0xBF, 0xC6, 0xCD, 0x80, 0x42, 0x47, 0xF8, 0x3E, 0x6A, 0xF1, 0xDD, 0x28, 0x2B, 0xF7, 0xD4, 0x5C, 0x9F, 0x8F, 0xCC, 0xA1, 0x13, 0x42, 0xD8, 0x6B, 0xDF, 0xE0, 0x1F, 0xE7, 0x2F, 0xDB, 0x31, 0xF9, 0xFA, 0xBF, 0xFA, 0xB4, 0x89, 0x49, 0x5D, 0x3D, 0xA9, 0x91, 0xD7, 0xD8, 0x86, 0xF0, 0x97, 0xB1, 0x1A, 0x6B, 0x80, 0xEA, 0x93, 0x5D, 0x9F, 0x6D, 0xA4, 0x4C, 0x60, 0x58, 0x4A, 0x8D, 0x75, 0x66, 0x04, 0x98, 0x03, 0xB4, 0x03, 0xD1, 0x6F, 0x2C, 0x17, 0x4F, 0xFD, 0xFA, 0x10, 0x93, 0x6B, 0x35, 0xA3, 0x60, 0x2A, 0x2B, 0x3D, 0x15, 0xBF, 0x86, 0x65, 0xF3, 0xDF, 0xED, 0xA0, 0x16, 0x0D, 0x6B, 0xBB, 0xA1, 0x42, 0x24, 0xCD, 0xBE, 0xB9, 0x5F, 0x18, 0xE5, 0xF5, 0x91, 0x00, 0x70, 0xFB, 0x64, 0xD4, 0x92, 0xEF, 0x92, 0x0A, 0x10, 0x06, 0x58, 0x00, 0x5A, 0x84, 0x00, 0x68, 0x7B, 0xDA, 0xB7, 0x47, 0x9F, 0xA5, 0x9A, 0x2B, 0x7E, 0x75, 0x94, 0xF1, 0xDE, 0xD6, 0x1F, 0x77, 0x41, 0x5C, 0x02, 0xB7, 0xC4, 0x0B, 0x8B, 0x83, 0xBE, 0x2B, 0xBE, 0xE2, 0x4F, 0x2F, 0xAE, 0x5F, 0xC9, 0x7C, 0x7B, 0x3A, 0x71, 0x5D, 0x58, 0x22, 0x88, 0x37, 0x39, 0x0C, 0xFB, 0x00, 0x73, 0x57, 0x0A, 0xC6, 0x81, 0x76, 0xFE, 0xD1, 0x80, 0xAA, 0x35, 0x9A, 0xB3, 0xFD, 0xCD, 0xF0, 0x96, 0x9B, 0xA1, 0xAC, 0xF2, 0x16, 0x41, 0x0D, 0x6A, 0xF1, 0x78, 0x44, 0x3D, 0xD9, 0x02, 0x10, 0xEF, 0xB5, 0x79, 0xE2, 0x5E, 0xF3, 0xC9, 0x3F, 0xDA, 0xB3, 0xBE, 0x61, 0xFD, 0x4F, 0xFD, 0x8C, 0x17, 0x8F, 0x03, 0xD5, 0xFC, 0xAE, 0xDE, 0x91, 0xEC, 0xDA, 0x7E, 0xA1, 0x27, 0x55, 0x38, 0x1B, 0x7A, 0xE6, 0xBB, 0x68, 0xD3, 0x9F, 0x2C, 0x4E, 0x25, 0x90, 0x83, 0xEF, 0x36, 0x30, 0x9C, 0x5D, 0x48, 0xB0, 0xA9, 0xE9, 0xE0, 0x5D, 0x33, 0x77, 0x34, 0x34, 0x34, 0x48, 0x15, 0x4C, 0x90, 0xC3, 0xD4, 0xB4, 0x10, 0x05, 0x1C, 0x7E, 0xD7, 0x07, 0xC8, 0x04, 0x86, 0x3F, 0x99, 0x58, 0x9B, 0x05, 0x3C, 0x4E, 0x65, 0x53, 0x4E, 0x07, 0xAE, 0x69, 0xB7, 0xAB, 0x7E, 0x77, 0x0E, 0x7D, 0x5A, 0x1D, 0x08, 0x65, 0xB4, 0xB3, 0x77, 0xE3, 0x8E, 0xA2, 0x56, 0x15, 0x67, 0x76, 0xBB, 0xD1, 0x13, 0x30, 0x35, 0x60, 0x01, 0x9C, 0x5E, 0x65, 0xDF, 0x1F, 0xB2, 0x5F, 0xE9, 0x35, 0xD1, 0x27, 0xD1, 0x78, 0x36, 0x2D, 0xD6, 0x1B, 0xBD, 0xE3, 0x53, 0x6F, 0x5F, 0x14, 0x9B, 0x29, 0x5E, 0xA1, 0x70, 0x60, 0xBB, 0xA4, 0xF6, 0xB4, 0x66, 0xB2, 0x22, 0x37, 0x48, 0xDD, 0xF2, 0xDF, 0x0A, 0x8E, 0xE5, 0xAD, 0xC7, 0x56, 0xAC, 0xE3, 0xAC, 0x86, 0x87, 0x36, 0x91, 0xC0, 0x11, 0x7C, 0x97, 0x84, 0x25, 0x10, 0xFC, 0x2E, 0x1F, 0xA3, 0x25, 0x2E, 0x09, 0x55, 0x26, 0x8E, 0xFB, 0x37, 0xB6, 0x1D, 0x9A, 0x88, 0x94, 0xE4, 0x08, 0xC5, 0x1F, 0x92, 0x7A, 0xF8, 0x8D, 0xB1, 0x00, 0xF7, 0xFF, 0x0E, 0x49, 0xD9, 0x9E, 0x5B, 0x5B, 0x1C, 0xD6, 0xDD, 0x97, 0x0E, 0x64, 0xFC, 0x43, 0x6A, 0x79, 0x7B, 0x14, 0xEC, 0x51, 0x47, 0xBE, 0xB4, 0x21, 0x8B, 0x41, 0x03, 0xFB, 0xFB, 0x9F, 0x2A, 0x6D, 0xB1, 0xD3, 0x2C, 0x9E, 0x76, 0xE5, 0x19, 0xA0, 0xB6, 0x5A, 0xBA, 0x0D, 0x08, 0x5B, 0x79, 0x58, 0x1D, 0x05, 0x46, 0xF1, 0x52, 0x2B, 0xDB, 0x01, 0x64, 0x50, 0x91, 0xED, 0x11, 0x6D, 0x03, 0x7A, 0x61, 0x40, 0x0A, 0xA0, 0x7C, 0x8E, 0xE6, 0xD1, 0x78, 0x64, 0x4D, 0x2B, 0xD7, 0x6A, 0x85, 0x88, 0xA7, 0x71, 0x6E, 0x55, 0x52, 0xA0, 0x3E, 0x31, 0x3A, 0x10, 0x12, 0x38, 0xFD, 0xC6, 0x7F, 0xF8, 0x35, 0xC7, 0x40, 0x61, 0xA5, 0xB6, 0xFB, 0xF1, 0x1E, 0x32, 0x16, 0x5E, 0x91, 0xB4, 0xC8, 0x6C, 0x6A, 0xE8, 0x08, 0x60, 0x0A, 0x88, 0x03, 0x67, 0x9B, 0x21, 0x77, 0xE6, 0xE9, 0xEA, 0x70, 0x1F, 0xFC, 0x44, 0xB7, 0x0D, 0x86, 0xF2, 0x7E, 0x9A, 0x8F, 0x7E, 0x64, 0xFB, 0xBB, 0x3A, 0x4B, 0xF7, 0x31, 0x7C, 0xDA, 0xE5, 0xCF, 0xB5, 0xFA, 0x42, 0xFF, 0xB6, 0x47, 0x6F, 0xCA, 0x64, 0xD3, 0xFC, 0x0A, 0x84, 0x6E, 0xB6, 0x9F, 0x76, 0x15, 0x20, 0x0E, 0xE0, 0x0D, 0xD8, 0xAA, 0xE7, 0x15, 0x50, 0x0E, 0x0C, 0xA2, 0x78, 0x00, 0x46, 0xEB, 0xDF, 0xBD, 0x65, 0x19, 0x38, 0xD3, 0x22, 0x91, 0x39, 0x41, 0xA4, 0x74, 0x24, 0x13, 0x41, 0x95, 0xF1, 0x11, 0x65, 0x6B, 0xA4, 0x63, 0x77, 0x71, 0xD5, 0xC6, 0xE9, 0xF7, 0xDC, 0xE7, 0xF1, 0x2D, 0x2B, 0xCC, 0x1B, 0x81, 0xCA, 0xD3, 0x7E, 0xD8, 0x03, 0x38, 0x21, 0x07, 0xB0, 0x7A, 0xBB, 0x35, 0x37, 0x05, 0x91, 0x4F, 0xB2, 0x6B, 0x04, 0x30, 0xFF, 0x14, 0x3C, 0x68, 0x89, 0x08, 0x7E, 0xF2, 0x77, 0x8C, 0x98, 0xF1, 0x61, 0xD4, 0x96, 0x95, 0x60, 0xB3, 0x64, 0x3A, 0x2D, 0x57, 0x24, 0xE1, 0x3C, 0x18, 0xC6, 0x0E, 0xC9, 0xA0, 0x41, 0x84, 0x68, 0xC2, 0x80, 0x13, 0x44, 0x03, 0xB6, 0x7B, 0x34, 0xD6, 0x4F, 0x43, 0x62, 0x5B, 0x5C, 0x0B, 0xFD, 0x4B, 0x26, 0xB8, 0x69, 0x66, 0x7E, 0xC5, 0x29, 0x29, 0xD6, 0x3B, 0x03, 0x08, 0x87, 0xCD, 0x2A, 0xFD, 0xDA, 0x4C, 0x10, 0x77, 0xD9, 0x73, 0x82, 0x36, 0x73, 0x83, 0x41, 0xF4, 0x00, 0x93, 0x40, 0xDB, 0x1A, 0x12, 0x48, 0x7D, 0xB7, 0x5B, 0xFB, 0x6E, 0x21, 0x7C, 0x54, 0x23, 0x64, 0xC7, 0xF4, 0x85, 0xF0, 0x5B, 0x84, 0xD6, 0x28, 0x57, 0x1B, 0x03, 0xCC, 0x0A, 0xF8, 0xFB, 0xAB, 0xE4, 0xC7, 0x36, 0x90, 0xD8, 0x5D, 0xA2, 0x38, 0x3F, 0xB8, 0x1A, 0xEB, 0x9E, 0xBB, 0x9B, 0x03, 0xB3, 0x86, 0x01, 0xED, 0x44, 0x13, 0x49, 0x18, 0xD1, 0xAC, 0xEA, 0x1B, 0x90, 0x1B, 0x45, 0xC5, 0xDD, 0xF4, 0x38, 0x41, 0xA7, 0x2D, 0xF7, 0x8F, 0xAB, 0xB7, 0x93, 0xDC, 0xAA, 0xDA, 0xD4, 0x9E, 0x80, 0x38, 0xE4, 0xF0, 0x01, 0x13, 0xA0, 0x5E, 0xBD, 0x38, 0x1C, 0xD9, 0xBA, 0xED, 0x23, 0x2B, 0x42, 0xCA, 0x88, 0x35, 0x01, 0xAD, 0xFD, 0x8E, 0x9F, 0x90, 0x5F, 0xA6, 0x25, 0xFE, 0x16, 0xEF, 0x18, 0x9D, 0x82, 0xE0, 0x25, 0x26, 0x02, 0x28, 0xE1, 0x03, 0x54, 0xC1, 0x2E, 0x52, 0xB4, 0x04, 0x76, 0x5E, 0xB0, 0x5C, 0xCA, 0x76, 0xE7, 0xC6, 0x3E, 0x3B, 0x34, 0xF8, 0x53, 0xD2, 0xA5, 0x76, 0x1C, 0x36, 0x19, 0x76, 0x29, 0xE7, 0xED, 0x04, 0x50, 0x03, 0x6C, 0x80, 0xFD, 0xAE, 0x76, 0x73, 0xAA, 0x03, 0x26, 0x40, 0x9D, 0xB5, 0x99, 0xA0, 0x79, 0x8F, 0xC7, 0xC5, 0x51, 0x45, 0xD1, 0xB5, 0xEC, 0xDA, 0xC2, 0xAB, 0x1A, 0xDC, 0x1D, 0x9C, 0x5C, 0xD7, 0x8C, 0x05, 0xF6, 0xB2, 0xC1, 0x13, 0xE0, 0xF3, 0x99, 0x5F, 0x14, 0xDF, 0xA6, 0xC6, 0xDD, 0xA2, 0x0F, 0xC8, 0x10, 0x02, 0x9C, 0x01, 0xEA, 0xF2, 0x37, 0x9E, 0x15, 0x4D, 0x7B, 0xFE, 0xEE, 0xB9, 0xFD, 0x2C, 0x55, 0x99, 0x00, 0xCE, 0x50, 0xC0, 0x24, 0x81, 0x5C, 0xB5, 0x2F, 0x26, 0x3A, 0xF2, 0xC0, 0x90, 0xCE, 0xE7, 0x25, 0xEB, 0xB3, 0x69, 0xA5, 0x80, 0x91, 0x7F, 0x6D, 0x5A, 0x09, 0x06, 0xFB, 0xCA, 0x4F, 0x0E, 0xB4, 0x00, 0x35, 0xC0, 0xFC, 0x20, 0xF8, 0x04, 0x9B, 0xE9, 0x9A, 0x07, 0x6B, 0x02, 0xA5, 0x28, 0xDF, 0x17, 0xFB, 0x47, 0x08, 0xC8, 0x97, 0x63, 0xE9, 0x88, 0x35, 0x0A, 0x3C, 0x9C, 0x1F, 0xDC, 0xFE, 0x8D, 0x06, 0x70, 0xEA, 0xCF, 0xEA, 0x37, 0xCE, 0xF3, 0xEF, 0xEB, 0xBD, 0x82, 0x7C, 0x65, 0xCC, 0x00, 0xE5, 0x45, 0x96, 0xF9, 0xBE, 0x5C, 0xB4, 0x60, 0x70, 0x34, 0x27, 0x69, 0xEB, 0x77, 0x17, 0x6C, 0x19, 0xD0, 0x09, 0xE0, 0xDF, 0xC7, 0x2A, 0x67, 0x05, 0x13, 0x0F, 0xFD, 0x8C, 0x5D, 0x0F, 0xA3, 0x7C, 0x93, 0x0D, 0xE8, 0x6F, 0x09, 0xCD, 0x3A, 0x0C, 0xD3, 0x89, 0x74, 0x60, 0x94, 0x28, 0xAA, 0x65, 0x0A, 0xF1, 0x89, 0xCF, 0x7D, 0x6E, 0x64, 0xAE, 0xCD, 0x0C, 0x81, 0xC2, 0x18, 0xDE, 0xFE, 0x71, 0x64, 0x0E, 0xC4, 0x7E, 0xD5, 0xBB, 0x50, 0x16, 0x5A, 0xAC, 0xD8, 0x96, 0x29, 0x18, 0xA4, 0x48, 0xB9, 0x0A, 0x51, 0x79, 0xF5, 0x40, 0xEA, 0x53, 0x05, 0xAE, 0xDE, 0x6D, 0xF6, 0x80, 0x25, 0x20, 0x0E, 0x1C, 0x7F, 0x17, 0x90, 0xE3, 0x1F, 0xBD, 0x92, 0x31, 0x1B, 0x1E, 0x71, 0xF0, 0x5D, 0x81, 0x55, 0x15, 0x0B, 0x86, 0xE7, 0x6D, 0x40, 0x08, 0x20, 0x07, 0x08, 0x5F, 0x91, 0x6B, 0xC6, 0x4C, 0xF5, 0xBE, 0xF0, 0x5B, 0x84, 0xA9, 0x47, 0x03, 0x75, 0x4B, 0x24, 0x27, 0x81, 0xE2, 0x1D, 0x99, 0x3B, 0xEE, 0x68, 0x04, 0xAF, 0xD1, 0x76, 0x20, 0x14, 0xB0, 0x03, 0xB8, 0xF2, 0xF9, 0xAE, 0x35, 0x9A, 0xA3, 0xE8, 0xA3, 0x89, 0xF4, 0xAC, 0xC8, 0x37, 0x58, 0x47, 0x6F, 0xFE, 0x38, 0x67, 0x85, 0x13, 0x5A, 0x19, 0xB5, 0x0B, 0x30, 0xBE, 0x3A, 0x13, 0xFD, 0x69, 0x52, 0xB6, 0xCF, 0x52, 0x82, 0x06, 0xDA, 0x08, 0x21, 0xE2, 0x9D, 0x98, 0xCA, 0x67, 0x73, 0xE5, 0x8F, 0x57, 0x17, 0xC3, 0x30, 0xF4, 0xF2, 0x6B, 0x2A, 0x9E, 0x2F, 0xA4, 0xE0, 0x1E, 0xBE, 0x37, 0x7B, 0xE5, 0x3B, 0x37, 0x10, 0xAB, 0x1D, 0xF6, 0x88, 0xE6, 0xEB, 0x30, 0x76, 0x2F, 0x60, 0x47, 0x87, 0x72, 0x45, 0x24, 0x76, 0xFD, 0x5B, 0x02, 0xA7, 0xF1, 0xC7, 0xFE, 0x34, 0x56, 0x8E, 0x6E, 0x26, 0x90, 0xBF, 0xEC, 0xB5, 0x5A, 0x70, 0x37, 0x66, 0x30, 0xA9, 0xE9, 0x5F, 0xAB, 0xC1, 0x03, 0x3A, 0x8A, 0x06, 0xC9, 0x6C, 0xF8, 0xAE, 0x16, 0xF7, 0x9A, 0xB2, 0x5C, 0xAB, 0xD5, 0x67, 0x65, 0x65, 0x02, 0x63, 0x40, 0x27, 0x50, 0x02, 0xA4, 0x11, 0xFD, 0x1A, 0x16, 0xF7, 0xE3, 0x96, 0x61, 0xDE, 0x09, 0x31, 0xBE, 0x29, 0x58, 0xD0, 0x70, 0xCB, 0xC3, 0xE4, 0x00, 0x26, 0x40, 0xC7, 0x8E, 0xEB, 0x6C, 0x8F, 0x01, 0xEC, 0xB4, 0xFE, 0x98, 0x73, 0xAA, 0xCF, 0x78, 0x2E, 0x1C, 0x07, 0x66, 0x65, 0x15, 0x76, 0x27, 0x75, 0xB3, 0xDD, 0x2A, 0x88, 0x01, 0xAC, 0x80, 0xD5, 0xAE, 0xAA, 0xF8, 0xCA, 0x22, 0xAE, 0xD5, 0x92, 0xE5, 0xD8, 0x46, 0x3A, 0x3B, 0xE4, 0x6D, 0xED, 0x76, 0x2F, 0xA1, 0x74, 0x70, 0xB2, 0x95, 0x3C, 0xF0, 0x18, 0xB5, 0xF1, 0xCD, 0xA4, 0xD5, 0xFE, 0xBF, 0x39, 0x0E, 0x01, 0xAA, 0x81, 0x0C, 0xA2, 0x81, 0x5B, 0xDA, 0x24, 0x37, 0x0B, 0xCC, 0x73, 0xF7, 0xD1, 0xE8, 0xAB, 0xBF, 0x55, 0x83, 0xB6, 0x6D, 0xDF, 0x3B, 0xD1, 0x0E, 0x48, 0x02, 0xD6, 0x7B, 0xAF, 0x30, 0xFA, 0xDA, 0x85, 0x2A, 0xFB, 0x90, 0xED, 0x62, 0x3D, 0xE3, 0xA3, 0x33, 0xC0, 0x86, 0xB3, 0xB9, 0xBB, 0xDA, 0x0A, 0x18, 0x25, 0x0E, 0x50, 0x0A, 0x78, 0x00, 0x6A, 0xC0, 0xE6, 0x90, 0x4C, 0xD7, 0x6A, 0x85, 0xFF, 0x05, 0x85, 0x37, 0x97, 0xC9, 0x2F, 0x75, 0x6A, 0xC9, 0x93, 0x3D, 0x8B, 0x2A, 0xE8, 0x05, 0x9F, 0x21, 0xEA, 0x7F, 0xE8, 0xE9, 0x4F, 0x0E, 0xDE, 0xDD, 0x02, 0xFB, 0x9A, 0xAF, 0xB5, 0xF2, 0x2F, 0x02, 0x55, 0x62, 0x00, 0x3D, 0x80, 0xC4, 0x8D, 0xEC, 0xF3, 0xAA, 0x50, 0xE4, 0xD3, 0x7A, 0x12, 0x5B, 0x66, 0xB7, 0x5B, 0xBD, 0x77, 0xE5, 0xC0, 0x4A, 0x01, 0xAB, 0x37, 0xCF, 0xC3, 0x7F, 0x8B, 0xC5, 0x33, 0xF5, 0xA8, 0x7C, 0x80, 0x56, 0x8D, 0xB9, 0x7E, 0xD0, 0x8F, 0xF6, 0x21, 0x22, 0x49, 0x04, 0xF1, 0x01, 0xA4, 0x10, 0x09, 0xC4, 0x10, 0x07, 0xF0, 0x02, 0x92, 0x4D, 0x91, 0x76, 0xD6, 0x68, 0x8D, 0xE1, 0x24, 0x1F, 0x54, 0x9A, 0x65, 0x70, 0xFD, 0xD6, 0xB9, 0x84, 0x60, 0x7A, 0x84, 0x6D, 0xCD, 0x45, 0xA5, 0x25, 0x87, 0x76, 0x1A, 0x8D, 0xF6, 0x55, 0x6A, 0x52, 0xBE, 0x67, 0xB6, 0xA6, 0x08, 0x03, 0xB2, 0x00, 0x6B, 0x40, 0x15, 0x38, 0xFD, 0xFE, 0xC4, 0x77, 0x3B, 0x0A, 0x6D, 0x50, 0x7F, 0xFB, 0x75, 0xBE, 0x4D, 0xC3, 0x06, 0x44, 0x01, 0xDA, 0xF8, 0x4E, 0x84, 0xB9, 0x23, 0x5E, 0xD8, 0x41, 0xC3, 0xEC, 0x72, 0x0B, 0x2A, 0x3E, 0x12, 0xEB, 0x74, 0x0C, 0x8C, 0x5D, 0x50, 0x4B, 0x80, 0x4A, 0x47, 0x02, 0x1D, 0xC0, 0x34, 0x61, 0x40, 0xE7, 0x5D, 0x6F, 0x90, 0x03, 0x8C, 0xAC, 0xD1, 0x86, 0x73, 0x70, 0x45, 0xCF, 0xA0, 0x21, 0xFB, 0x64, 0x79, 0xAD, 0x2A, 0xF0, 0x42, 0xD4, 0x6E, 0x13, 0xF8, 0x47, 0x6F, 0xA8, 0xF9, 0x35, 0xDA, 0x2E, 0x76, 0xD2, 0xF3, 0x1E, 0xD4, 0xF6, 0xD4, 0xD7, 0x6B, 0x80, 0x55, 0x38, 0x99, 0x01, 0xA2, 0x80, 0xE2, 0xDB, 0xB6, 0x1B, 0x2F, 0xE4, 0x52, 0x8C, 0x8C, 0x47, 0xC5, 0x76, 0x1B, 0x05, 0x37, 0xE1, 0x36, 0x0A, 0xD8, 0xB9, 0xBB, 0x84, 0xBC, 0xB7, 0xEF, 0x85, 0x91, 0x39, 0x63, 0xAA, 0xE4, 0x43, 0x95, 0x46, 0x87, 0x86, 0xCE, 0x31, 0x50, 0xB0, 0x16, 0x06, 0x5D, 0x81, 0x4E, 0x60, 0x04, 0xA8, 0x01, 0xC2, 0x01, 0x17, 0x20, 0x9D, 0x0A, 0x6C, 0x6B, 0x34, 0x46, 0xCF, 0x3A, 0x7B, 0xA1, 0x34, 0x87, 0xE4, 0xF3, 0x97, 0xA3, 0xC8, 0x52, 0xE4, 0xB3, 0x4A, 0x50, 0x99, 0x54, 0xE1, 0xED, 0x6F, 0x1B, 0x37, 0xDD, 0xEA, 0x39, 0xF5, 0x0A, 0x51, 0x8B, 0xFE, 0x8D, 0xE0, 0x08, 0x90, 0x07, 0xD0, 0x02, 0xB6, 0xC1, 0xB4, 0x14, 0x18, 0xA4, 0x20, 0x81, 0x67, 0x7C, 0xA4, 0x9E, 0xFA, 0xA8, 0x9C, 0x0D, 0xC2, 0xB7, 0x64, 0x0B, 0x64, 0x02, 0x16, 0xC0, 0x24, 0x93, 0x1B, 0x1B, 0x96, 0x16, 0x5D, 0xC3, 0xE2, 0x7B, 0xE9, 0x30, 0xDA, 0x14, 0x8D, 0xE6, 0x30, 0x9A, 0xD1, 0x68, 0x72, 0x80, 0x36, 0x58, 0x44, 0x13, 0xB0, 0x22, 0x92, 0x30, 0xA2, 0x81, 0x18, 0x18, 0xCD, 0x1E, 0xA3, 0x09, 0x7A, 0xD6, 0x6C, 0xB8, 0x67, 0x11, 0xE5, 0x27, 0x7B, 0x44, 0xFB, 0x98, 0x99, 0x61, 0xCF, 0x90, 0x41, 0x33, 0x21, 0x22, 0xED, 0x75, 0xD5, 0x5A, 0x3F, 0x9A, 0x7D, 0x76, 0x6E, 0x49, 0x30, 0x0B, 0x62, 0x00, 0x35, 0x40, 0x82, 0x30, 0x20, 0xF2, 0x1D, 0x65, 0x79, 0x36, 0x46, 0xCD, 0x63, 0x42, 0xFB, 0x61, 0x57, 0xEC, 0xCE, 0xDF, 0xA0, 0x53, 0xBD, 0xDD, 0x69, 0xFC, 0xE7, 0x72, 0x2C, 0x87, 0x56, 0x66, 0xB8, 0x9F, 0x7C, 0x59, 0x7F, 0x88, 0x15, 0xFB, 0xA5, 0xE7, 0xB5, 0xAB, 0x0F, 0xE6, 0xE9, 0xAE, 0x35, 0x07, 0x66, 0x11, 0x40, 0x25, 0xE0, 0x06, 0xA8, 0x02, 0xCE, 0x15, 0x74, 0x91, 0x6B, 0x34, 0xBD, 0x85, 0xE6, 0x04, 0xB5, 0x61, 0x9F, 0x7E, 0xFE, 0x18, 0x89, 0x7E, 0x22, 0xEF, 0x27, 0x10, 0x2A, 0xFD, 0x95, 0xD7, 0xCF, 0x67, 0xFB, 0x62, 0x06, 0x2F, 0xC1, 0x62, 0x04, 0x1B, 0xB9, 0x03, 0x6F, 0x40, 0x37, 0x60, 0xCA, 0xB0, 0xFD, 0x00, 0xDA, 0x80, 0xC7, 0xBE, 0x65, 0x9B, 0x37, 0xDB, 0x6E, 0x65, 0x5E, 0x4A, 0x03, 0x9C, 0x22, 0x0E, 0x60, 0xFA, 0x76, 0x62, 0x30, 0xC9, 0xE4, 0xC9, 0x90, 0x62, 0x77, 0x00, 0xF2, 0xA1, 0x28, 0x36, 0x98, 0x76, 0x30, 0x12, 0x6D, 0x82, 0xC5, 0x83, 0x57, 0xC6, 0x2A, 0x0D, 0x98, 0xBC, 0x2B, 0x7F, 0x96, 0x40, 0x32, 0xF6, 0x3C, 0x05, 0x68, 0x02, 0x69, 0x6B, 0x33, 0xBB, 0x7C, 0xB2, 0x31, 0xC1, 0x1B, 0x0F, 0xE1, 0xE9, 0x6E, 0x69, 0xD4, 0xB0, 0x7B, 0xF0, 0xD0, 0xF7, 0xCE, 0xD1, 0xCE, 0x2F, 0xF6, 0x8C, 0x5D, 0x50, 0x06, 0x84, 0xAD, 0x3C, 0xFC, 0xBA, 0x03, 0xC5, 0xA7, 0xC0, 0x80, 0x6C, 0xC0, 0x0C, 0x38, 0xFB, 0xA0, 0xF8, 0xFB, 0xA0, 0xE0, 0x79, 0xC5, 0x5B, 0xB9, 0x77, 0xA0, 0xD2, 0x4A, 0x84, 0x2E, 0x02, 0x08, 0x03, 0x5A, 0x68, 0xB3, 0xCD, 0x7F, 0x70, 0x51, 0x6E, 0xB1, 0x15, 0xF9, 0xFC, 0x50, 0x30, 0x6B, 0xB1, 0xE0, 0x52, 0x2B, 0x74, 0xC5, 0x3B, 0xF7, 0x5D, 0x89, 0x9A, 0x06, 0x34, 0x9B, 0x17, 0x0E, 0xA1, 0x02, 0x78, 0x03, 0xAD, 0xC0, 0xCE, 0x8B, 0xE9, 0x63, 0x33, 0xE7, 0x86, 0x7B, 0x83, 0xEC, 0xB0, 0x28, 0x24, 0x38, 0x33, 0x50, 0x29, 0x29, 0x65, 0x1F, 0x8F, 0x23, 0x32, 0xC0, 0x4E, 0x3C, 0x89, 0xAE, 0xED, 0x82, 0xBC, 0x97, 0xD8, 0xDB, 0xCA, 0x3F, 0x7E, 0x96, 0xBB, 0x25, 0x10, 0x0D, 0xE8, 0xE3, 0x8C, 0x00, 0x49, 0xD4, 0xAD, 0xC4, 0x2D, 0xCF, 0x46, 0xF1, 0x18, 0xA0, 0x79, 0x8B, 0xAC, 0x98, 0x41, 0x25, 0x10, 0x07, 0x10, 0x03, 0xEA, 0x95, 0x83, 0xD2, 0x9D, 0x39, 0xB1, 0x8D, 0x95, 0x9E, 0x64, 0x75, 0xEC, 0x8E, 0x23, 0xA6, 0x5D, 0x6D, 0x67, 0xAC, 0xE2, 0x96, 0xE6, 0x9B, 0x43, 0x38, 0x50, 0x09, 0xB8, 0x02, 0x32, 0xEF, 0xA7, 0xF9, 0x2B, 0x15, 0x27, 0x32, 0xB3, 0x95, 0x82, 0xFE, 0x0F, 0x93, 0xFF, 0x36, 0xDC, 0x3A, 0x87, 0xF3, 0x52, 0x1A, 0x87, 0x56, 0x39, 0x8F, 0xB2, 0xAF, 0xC2, 0xBE, 0x7D, 0xB7, 0x39, 0xEC, 0x88, 0xEC, 0x5D, 0x2A, 0xCE, 0x8F, 0x4C, 0xA1, 0x27, 0x90, 0xBB, 0xF0, 0x98, 0x66, 0x3E, 0xFD, 0xB6, 0x97, 0xF6, 0x23, 0xB6, 0x93, 0xFB, 0x5D, 0x10, 0xE7, 0x5E, 0x53, 0x16, 0x6B, 0xED, 0x9D, 0x8D, 0x1D, 0xEE, 0xC2, 0xDB, 0xC9, 0x3D, 0x67, 0xF8, 0x58, 0xF4, 0x46, 0x72, 0x60, 0xC3, 0x92, 0xAD, 0x84, 0x6C, 0xA6, 0x6E, 0x4D, 0x49, 0x08, 0x70, 0xE6, 0x4E, 0xE6, 0xB9, 0x01, 0x69, 0xF8, 0x2E, 0x73, 0xAD, 0x96, 0x97, 0xB2, 0x72, 0x2B, 0x4A, 0x51, 0xFE, 0xBE, 0xB3, 0x1E, 0x4F, 0xF8, 0x76, 0x3A, 0x11, 0xB9, 0x08, 0x0E, 0xB1, 0x4D, 0x41, 0x1A, 0xE0, 0xC2, 0x00, 0x7C, 0xC5, 0xBE, 0x7C, 0xEB, 0xB8, 0x84, 0xE5, 0xA1, 0xD1, 0x77, 0xAB, 0x3F, 0x20, 0x8C, 0xBC, 0xBB, 0xEF, 0xB5, 0x66, 0xCA, 0xCA, 0xC9, 0xAE, 0xB2, 0xF3, 0xB8, 0xF3, 0xBC, 0x6A, 0x40, 0x2A, 0x30, 0x46, 0xBF, 0x63, 0x7B, 0xA0, 0x68, 0x9E, 0x78, 0x4B, 0x6D, 0x75, 0x70, 0x5B, 0xAE, 0x9B, 0xDE, 0xB1, 0x92, 0x73, 0xF8, 0xAE, 0x87, 0x69, 0x0E, 0x84, 0x33, 0x10, 0xE8, 0x3B, 0x40, 0x14, 0xD0, 0x3C, 0xD9, 0x74, 0x80, 0xB2, 0xBB, 0x99, 0xE1, 0x89, 0x07, 0xB8, 0xB8, 0xD8, 0x04, 0x69, 0xC6, 0x38, 0xC8, 0x02, 0xD9, 0x0C, 0xCA, 0xB0, 0xC1, 0x59, 0xE3, 0x46, 0x6B, 0xF7, 0x40, 0x99, 0x28, 0xBA, 0xFD, 0x1A, 0xF5, 0xF4, 0x6F, 0x93, 0xF2, 0x67, 0x63, 0xA5, 0x0D, 0xA0, 0x7C, 0x44, 0x5A, 0x01, 0x2F, 0x40, 0x8C, 0x60, 0xE4, 0xE0, 0x7A, 0x3D, 0x30, 0xAB, 0xEA, 0x10, 0x4F, 0xF8, 0x7E, 0x18, 0xB7, 0xA7, 0x02, 0xB5, 0x30, 0xFE, 0xD2, 0xDE, 0x71, 0xF8, 0x6D, 0x3F, 0xEA, 0xE7, 0x4D, 0xF4, 0x7A, 0x57, 0x88, 0xDB, 0x33, 0xFB, 0x32, 0x3B, 0x0F, 0xB5, 0xF5, 0xBB, 0x64, 0xC5, 0xAE, 0x01, 0x29, 0x22, 0x80, 0x53, 0x37, 0x34, 0x80, 0x8E, 0x35, 0xDA, 0x5E, 0x93, 0xAC, 0xD0, 0x38, 0xF6, 0x8A, 0xEF, 0x32, 0xBF, 0xB4, 0x46, 0x42, 0x44, 0x14, 0xB1, 0x94, 0xCA, 0x6A, 0xBC, 0x6E, 0x3C, 0x80, 0x12, 0xC2, 0xAD, 0xA1, 0xA6, 0xBE, 0x19, 0x9B, 0xDA, 0x00, 0x92, 0x70, 0x60, 0xEF, 0x88, 0x4C, 0xE0, 0x2C, 0xB6, 0x8F, 0x2F, 0x98, 0x4F, 0x59, 0xFD, 0xE9, 0xBC, 0x77, 0x9E, 0x44, 0x02, 0xE6, 0x40, 0x2A, 0xD0, 0xC6, 0x9A, 0xF7, 0xEE, 0x3F, 0x3E, 0x9B, 0xCD, 0xA1, 0x53, 0x30, 0x4C, 0x72, 0x53, 0x6B, 0xD5, 0x87, 0xF5, 0x81, 0x8D, 0x03, 0x92, 0x71, 0xC0, 0x01, 0x5A, 0x58, 0x03, 0x50, 0x40, 0x12, 0x30, 0x01, 0x42, 0x81, 0x32, 0xA0, 0x0F, 0x30, 0x8F, 0xCD, 0xE6, 0xD6, 0xCD, 0x1C, 0xD8, 0x33, 0x6C, 0x0D, 0xC9, 0x89, 0x24, 0x8E, 0x19, 0xC4, 0x38, 0xC7, 0x7F, 0x31, 0x7E, 0xF7, 0x59, 0x52, 0x16, 0xB4, 0x59, 0xFB, 0xDA, 0x25, 0x78, 0x69, 0x1A, 0x50, 0x07, 0x38, 0xCA, 0x2C, 0x6E, 0x6F, 0x7F, 0x0B, 0xC1, 0xEF, 0xF2, 0x9A, 0xD0, 0x9B, 0x67, 0xB7, 0x80, 0x06, 0x5D, 0xA0, 0x02, 0xF4, 0xB3, 0x6E, 0xBB, 0x95, 0x01, 0xF9, 0x56, 0x37, 0x67, 0x17, 0x56, 0xEC, 0x0E, 0x22, 0xDE, 0x7A, 0x2B, 0xFF, 0xD5, 0xF7, 0xF2, 0xA8, 0x15, 0xF5, 0xAA, 0x6D, 0x2A, 0xF2, 0xCF, 0x0B, 0x78, 0xE8, 0x61, 0x24, 0xA0, 0x05, 0x44, 0x10, 0x05, 0x3C, 0x79, 0x5B, 0x86, 0x32, 0xD9, 0x8A, 0x67, 0xF7, 0xF8, 0x2E, 0xE3, 0xBA, 0x42, 0xA8, 0x74, 0x85, 0x37, 0x10, 0x01, 0xB5, 0x1B, 0x1D, 0xEE, 0x0C, 0xBC, 0x43, 0x28, 0xDD, 0xA6, 0xA0, 0x78, 0x15, 0x71, 0x86, 0x17, 0xEA, 0x02, 0x01, 0x0A, 0xC3, 0x73, 0xC0, 0x03, 0xA8, 0x6D, 0xCF, 0xDA, 0x86, 0xE5, 0xDA, 0x81, 0xFC, 0x2D, 0x59, 0xD5, 0x7E, 0x82, 0x5D, 0xDB, 0x80, 0x22, 0xC2, 0xDE, 0x5F, 0x32, 0x01, 0x6B, 0x7F, 0xC5, 0x5C, 0xDB, 0xB6, 0xAE, 0x62, 0x7C, 0xB4, 0x2D, 0x94, 0xFA, 0x36, 0x4D, 0x32, 0xCE, 0x7D, 0xDB, 0xF9, 0x72, 0x80, 0x16, 0xA0, 0x0A, 0xC8, 0x20, 0x04, 0xE8, 0x58, 0xF5, 0xF3, 0x35, 0x1A, 0x5E, 0x39, 0x68, 0x89, 0x15, 0x7A, 0x0F, 0xFA, 0xF7, 0x29, 0x2E, 0x6F, 0xB7, 0xC7, 0x11, 0xDF, 0xF8, 0xFC, 0x1E, 0xA6, 0x50, 0x83, 0x95, 0xFE, 0x1B, 0xAC, 0x1B, 0x2B, 0x04, 0x49, 0x8B, 0xD4, 0x03, 0x8B, 0xDD, 0x9F, 0x0D, 0xC4, 0x00, 0x9A, 0x04, 0xAF, 0xC7, 0x58, 0xDB, 0x6D, 0xA3, 0x87, 0x19, 0xE0, 0xBD, 0x25, 0xE4, 0x7B, 0xC4, 0xB6, 0x9D, 0x58, 0x87, 0x83, 0xD7, 0x47, 0xE4, 0x5F, 0xA3, 0xAA, 0xB3, 0x00, 0x16, 0xBC, 0x14, 0xF6, 0x9C, 0xCA, 0xF3, 0x6E, 0x9B, 0x7C, 0xE7, 0xC6, 0x10, 0xD2, 0xC2, 0x76, 0x02, 0x48, 0x11, 0x7C, 0x5E, 0xA7, 0x89, 0xE4, 0x1F, 0x7F, 0xC8, 0xBF, 0xEA, 0xDD, 0xAB, 0x05, 0x8C, 0xE5, 0x10, 0x8D, 0x9D, 0x06, 0x21, 0x5C, 0xE3, 0xAA, 0x48, 0x5D, 0x06, 0x83, 0x66, 0x0F, 0xA4, 0x58, 0xAB, 0x7E, 0x56, 0xA2, 0xD1, 0xE6, 0xBB, 0xB8, 0xD8, 0xE9, 0x0D, 0xAC, 0x8B, 0x50, 0x44, 0xD4, 0xBD, 0xA7, 0xA7, 0x0D, 0x08, 0x7D, 0x4D, 0x58, 0xFB, 0x5A, 0x9F, 0x27, 0x51, 0x76, 0x88, 0x9D, 0x80, 0x0A, 0x07, 0x74, 0x80, 0x34, 0x80, 0x23, 0x5B, 0xB7, 0x06, 0x82, 0xF1, 0xF2, 0xDB, 0x2C, 0x63, 0xEC, 0x2E, 0x70, 0x1E, 0x7E, 0xB9, 0xDB, 0x1A, 0xE0, 0x20, 0x6D, 0x32, 0xE3, 0x56, 0x1E, 0x4D, 0xC0, 0x15, 0xC8, 0x04, 0xC6, 0xD8, 0xFD, 0x98, 0x80, 0xDB, 0x47, 0x80, 0xB4, 0xEC, 0x52, 0x18, 0x4A, 0xD7, 0x37, 0x03, 0x29, 0x2E, 0x89, 0xF5, 0x4B, 0xA3, 0x94, 0xB6, 0xF8, 0x8D, 0x7F, 0xCE, 0x84, 0xB3, 0x51, 0x88, 0x5E, 0x5A, 0x7C, 0xF3, 0xB6, 0xEB, 0xE2, 0xCE, 0x67, 0xE9, 0xAE, 0x02, 0x16, 0x80, 0x1A, 0x20, 0x02, 0x3C, 0x7D, 0x6B, 0x34, 0xE5, 0x66, 0xD8, 0x4E, 0xD2, 0x94, 0x49, 0x33, 0x0B, 0x10, 0xFB, 0xA9, 0xEE, 0xEB, 0x59, 0x7F, 0xA0, 0x45, 0x11, 0xCD, 0xF8, 0xC6, 0x59, 0xDB, 0x68, 0xC9, 0xF1, 0x45, 0x3E, 0x24, 0xEA, 0x34, 0x9E, 0x6D, 0xF7, 0x00, 0x30, 0xBE, 0x22, 0xAE, 0xC0, 0x63, 0xD1, 0xE1, 0x7D, 0x10, 0x40, 0x0E, 0xD0, 0xBB, 0x0E, 0x6E, 0xD6, 0x6A, 0x8E, 0x97, 0xA0, 0x1D, 0xA7, 0xA0, 0xC7, 0xD7, 0xB7, 0x45, 0x4B, 0x40, 0x06, 0x33, 0xF6, 0x14, 0x8B, 0x4F, 0x58, 0x4D, 0xBF, 0x0A, 0xDE, 0xB2, 0x56, 0x2B, 0xDA, 0x49, 0x80, 0x36, 0x20, 0xFB, 0xB3, 0x5A, 0x5C, 0x80, 0x23, 0xB7, 0xB4, 0x74, 0xC4, 0x5D, 0x91, 0x29, 0x9A, 0x72, 0xF4, 0x4E, 0x9D, 0x9B, 0x00, 0xD1, 0xB7, 0x54, 0x4A, 0x5D, 0x02, 0x94, 0xEB, 0xBC, 0xD9, 0x3A, 0xAE, 0xEB, 0x2C, 0x04, 0xEB, 0xA4, 0xF3, 0x28, 0xE6, 0x6F, 0x8D, 0xD8, 0x8B, 0xBA, 0xE7, 0x7A, 0x77, 0x27, 0x27, 0x51, 0x02, 0x64, 0xDC, 0x18, 0xE1, 0xA9, 0x26, 0x6B, 0x35, 0x2C, 0x26, 0xC0, 0x54, 0xF1, 0x70, 0xBF, 0x2E, 0xAC, 0x06, 0xF9, 0xDE, 0x54, 0x6A, 0x54, 0x2A, 0x02, 0x4A, 0xC1, 0x3F, 0xD3, 0x4E, 0x7D, 0x56, 0x8B, 0x7F, 0x17, 0xB2, 0xEB, 0xED, 0xF5, 0x77, 0x00, 0x39, 0x1F, 0xAB, 0x39, 0x70, 0x12, 0x90, 0x03, 0xF4, 0xBB, 0xD8, 0x0D, 0x9A, 0xA5, 0xC0, 0xAA, 0xC7, 0x74, 0x03, 0xA1, 0x40, 0xDD, 0x3B, 0xB7, 0x68, 0x66, 0xD9, 0xE8, 0x7F, 0xEF, 0x58, 0x79, 0xE6, 0x6E, 0x7B, 0x87, 0x57, 0x86, 0x0D, 0x0B, 0xBB, 0x5B, 0xEF, 0x07, 0x56, 0x1A, 0x02, 0x7D, 0x9B, 0x48, 0xF2, 0x37, 0x20, 0x09, 0x1C, 0x7E, 0x37, 0x0E, 0xB4, 0x01, 0x53, 0xF8, 0xEE, 0xE9, 0x19, 0xE2, 0xE2, 0xE2, 0xE3, 0x06, 0xF7, 0xC4, 0x87, 0x81, 0xE9, 0x40, 0x8C, 0xD0, 0x0B, 0x6F, 0x28, 0x9B, 0x47, 0x65, 0xF2, 0xF7, 0x4F, 0x51, 0x4F, 0xCA, 0xDC, 0xFE, 0x4B, 0x0B, 0x2C, 0xFA, 0xD5, 0x87, 0xEF, 0x27, 0x0B, 0x34, 0x0A, 0xD8, 0x7E, 0x67, 0x80, 0x13, 0xBA, 0x2F, 0x9C, 0xEF, 0x5D, 0xBB, 0x9D, 0xB7, 0x71, 0xAF, 0x60, 0x3F, 0xB5, 0x55, 0xD5, 0x5B, 0x08, 0xE5, 0xC4, 0x9B, 0xFF, 0x8D, 0xA7, 0x91, 0x31, 0x3E, 0x1A, 0xFB, 0x67, 0x2F, 0x83, 0xBE, 0x35, 0xF6, 0x7D, 0xFB, 0xE2, 0x83, 0x5D, 0x06, 0xDB, 0xFB, 0x1E, 0x80, 0x19, 0x31, 0x44, 0x02, 0xEE, 0x40, 0xEE, 0xD6, 0x9B, 0x5E, 0xAB, 0xD5, 0xA5, 0x7B, 0xDE, 0x55, 0x3F, 0xAB, 0xD9, 0xD8, 0xD5, 0xD2, 0x37, 0xA1, 0xEC, 0x19, 0xD2, 0x5F, 0xFA, 0xC7, 0x3D, 0x30, 0x3F, 0xF6, 0xCF, 0x98, 0x40, 0xD6, 0x06, 0x8C, 0x09, 0x12, 0x90, 0x0D, 0xE0, 0x09, 0xE5, 0x7D, 0x51, 0x49, 0xC8, 0x1B, 0x2F, 0xC8, 0x79, 0xCE, 0x7D, 0x57, 0x20, 0xB6, 0x17, 0x39, 0x00, 0x49, 0x20, 0x0C, 0x68, 0x46, 0x0F, 0xF2, 0xAE, 0x28, 0x31, 0x9E, 0x6E, 0x71, 0xF6, 0xB6, 0xE3, 0x61, 0xC5, 0xA1, 0xAB, 0xE6, 0xD9, 0xDE, 0x2C, 0xC1, 0x74, 0x3F, 0x1A, 0xAD, 0xA7, 0x81, 0x64, 0xB3, 0xC2, 0x09, 0xC0, 0x88, 0x2A, 0x26, 0x8C, 0xE6, 0xE3, 0xD5, 0xE9, 0x1A, 0x6D, 0x5D, 0x59, 0xAA, 0x83, 0x0B, 0x9E, 0x38, 0xBD, 0xB6, 0xCC, 0x26, 0xC5, 0xE2, 0xE5, 0x77, 0xA0, 0xFD, 0x8C, 0x16, 0x53, 0xBB, 0x14, 0xFB, 0x96, 0x02, 0xDB, 0x96, 0xED, 0xE7, 0xD9, 0xE2, 0x83, 0xB3, 0x7B, 0xFE, 0x1A, 0x10, 0xDF, 0x65, 0xFF, 0x77, 0x9E, 0x43, 0xF7, 0x53, 0xBD, 0x82, 0xB8, 0x98, 0xA8, 0x83, 0x3B, 0xB7, 0x43, 0xC7, 0xBE, 0x57, 0x02, 0x3F, 0x15, 0xE0, 0xC6, 0x23, 0x64, 0x1D, 0xEA, 0x38, 0x5B, 0x38, 0x60, 0xC8, 0xAD, 0x7F, 0xDD, 0x2D, 0x95, 0x8C, 0x3E, 0x0D, 0x16, 0xE9, 0xC4, 0x1F, 0xBB, 0x1F, 0x7D, 0xE5, 0x4A, 0x18, 0xCD, 0x88, 0xA2, 0xB5, 0xE4, 0x00, 0x41, 0x8C, 0x7D, 0x34, 0xE3, 0x6D, 0x8D, 0x36, 0x5F, 0x15, 0xCD, 0xC5, 0xFE, 0x91, 0x5B, 0xCA, 0x07, 0x1D, 0x56, 0x92, 0x50, 0x34, 0x9E, 0xB8, 0xD6, 0xBB, 0xC9, 0x57, 0xB7, 0x55, 0x36, 0x08, 0xFD, 0xD4, 0xEE, 0x04, 0xB0, 0x03, 0xEC, 0xF1, 0xD7, 0x0E, 0x54, 0xAC, 0x6A, 0xCC, 0x3D, 0x88, 0xFC, 0xCC, 0x6D, 0x3F, 0x42, 0x76, 0x80, 0xFA, 0xFD, 0xE9, 0x69, 0xAF, 0x9F, 0xB7, 0x5B, 0x59, 0x69, 0x18, 0xDF, 0x0C, 0x2C, 0xDF, 0xD2, 0xD2, 0x67, 0xF5, 0x53, 0x30, 0x46, 0x88, 0x81, 0xED, 0x66, 0x35, 0xE3, 0x19, 0xC0, 0xAB, 0x03, 0x7D, 0x60, 0x3B, 0x0D, 0xA0, 0x94, 0xE1, 0xFC, 0x00, 0x61, 0xC0, 0xEC, 0x05, 0xDA, 0xE7, 0x9F, 0x46, 0x83, 0xAF, 0xE6, 0x03, 0xBF, 0xD1, 0xD8, 0xFA, 0x32, 0xFE, 0x6B, 0x7A, 0xDF, 0x15, 0x18, 0xFD, 0x2D, 0x7C, 0xCA, 0xB9, 0x0B, 0x9F, 0xFE, 0xA9, 0x71, 0x86, 0x00, 0xCA, 0x9F, 0x4C, 0x01, 0x65, 0x40, 0xEE, 0xC5, 0x60, 0xC0, 0x2E, 0xB4, 0xF4, 0xB5, 0xB6, 0xDD, 0x5B, 0x69, 0xA4, 0xEF, 0x4F, 0xB9, 0x3F, 0xD9, 0x87, 0xF9, 0xEC, 0x05, 0xAA, 0xDB, 0xFD, 0xCE, 0xF5, 0x04, 0x72, 0xAF, 0x98, 0x0D, 0x67, 0x39, 0xAA, 0xD9, 0xEE, 0x92, 0x0C, 0x3C, 0x07, 0x58, 0xC5, 0xE9, 0x93, 0x80, 0x15, 0x50, 0x6C, 0x1C, 0x11, 0xC2, 0x88, 0x92, 0xB5, 0x9A, 0x70, 0x3E, 0x34, 0xD7, 0x78, 0xC8, 0xAC, 0xD5, 0xF5, 0xA8, 0x41, 0x4F, 0xC7, 0xFF, 0x6A, 0xDD, 0x2A, 0x88, 0xD2, 0xF5, 0xA3, 0x69, 0x65, 0xF3, 0x4A, 0x71, 0xA3, 0xA0, 0xB3, 0xE5, 0x4C, 0x60, 0xFF, 0x0F, 0x85, 0xC8, 0x75, 0xFD, 0x59, 0x47, 0x9F, 0x78, 0x5D, 0x54, 0x18, 0xE1, 0x89, 0x82, 0x76, 0xB1, 0x40, 0x9E, 0x47, 0x3C, 0xC1, 0xB6, 0x02, 0x2E, 0xEF, 0x0C, 0x68, 0x3F, 0x3D, 0x05, 0xCE, 0xA4, 0x6F, 0x7C, 0x14, 0x95, 0x56, 0xEC, 0xA1, 0x89, 0x5A, 0x14, 0xBE, 0xD3, 0xAF, 0x3C, 0x53, 0x00, 0x7E, 0x80, 0xC3, 0x9F, 0x84, 0x02, 0x42, 0x3C, 0x43, 0x09, 0xB6, 0x46, 0x53, 0xF4, 0x32, 0xFF, 0x5B, 0x22, 0x98, 0x75, 0x8B, 0x12, 0x38, 0xDD, 0xA6, 0xBF, 0xFB, 0x33, 0x5C, 0xF6, 0x0A, 0xB8, 0x3D, 0x5C, 0xD1, 0x8F, 0xB0, 0x72, 0xD1, 0x86, 0x0D, 0xD8, 0x01, 0x3C, 0x81, 0xD1, 0x77, 0x37, 0x48, 0x6D, 0x95, 0x41, 0x61, 0x43, 0xDD, 0xCE, 0x56, 0x1E, 0xF0, 0xF1, 0x4A, 0x6A, 0xB2, 0xEB, 0x6A, 0x2D, 0xD3, 0xCC, 0x35, 0xE6, 0xA6, 0x3A, 0x7E, 0xF0, 0x47, 0x22, 0x40, 0xB7, 0xC0, 0xB7, 0xF5, 0x16, 0x22, 0x86, 0x50, 0x20, 0xF9, 0x13, 0xB1, 0x8F, 0x54, 0x9F, 0x00, 0x36, 0xC0, 0x9F, 0xDC, 0x26, 0x20, 0x9F, 0xDD, 0xB4, 0xAE, 0x6B, 0x35, 0xDB, 0x9E, 0xD2, 0x7F, 0x5B, 0xCD, 0xE4, 0x67, 0x28, 0x64, 0x41, 0xCF, 0xC0, 0x5B, 0x30, 0xDD, 0x9A, 0xCA, 0x5D, 0x8F, 0xDA, 0x53, 0x6D, 0x7D, 0xB4, 0xB5, 0x96, 0x01, 0x5E, 0x40, 0x6E, 0x07, 0x51, 0x00, 0x83, 0x87, 0x7A, 0x9B, 0xE8, 0x57, 0xC9, 0x61, 0x67, 0x82, 0x8B, 0x2E, 0x26, 0x53, 0x17, 0xC1, 0x3C, 0x48, 0x28, 0xE0, 0x41, 0x07, 0xEC, 0x3C, 0x49, 0x0E, 0xD9, 0x66, 0x16, 0x5D, 0xCF, 0x96, 0x0F, 0x17, 0x61, 0x0A, 0x48, 0x02, 0x67, 0x00, 0x21, 0x72, 0xD5, 0x4C, 0x9D, 0x0F, 0xD7, 0x2E, 0xA3, 0x4F, 0x20, 0x0C, 0x38, 0xC1, 0x5F, 0x36, 0xB0, 0xAA, 0x90, 0x93, 0x6B, 0x34, 0x47, 0x73, 0x47, 0x35, 0x77, 0x25, 0xD4, 0xD7, 0x68, 0x34, 0x2F, 0x3C, 0x36, 0x1D, 0x87, 0xC8, 0x97, 0xFA, 0x5A, 0xE9, 0x5E, 0x5A, 0x19, 0xF7, 0x0A, 0xA9, 0xCA, 0xFB, 0x49, 0x53, 0xC2, 0x06, 0xA8, 0x79, 0x7B, 0xB1, 0x92, 0x9F, 0xB6, 0xFE, 0xBE, 0x1B, 0xFC, 0xAD, 0x79, 0xA4, 0x07, 0xDF, 0x48, 0x63, 0x73, 0x69, 0x3F, 0xA3, 0xF7, 0x12, 0x6F, 0xA9, 0x7D, 0x9F, 0xB4, 0xF8, 0xAB, 0x2F, 0x0F, 0xD0, 0x05, 0x8C, 0xF2, 0x27, 0x8B, 0x01, 0x34, 0x80, 0x1D, 0xA3, 0xAC, 0xBD, 0x77, 0x03, 0x10, 0xBF, 0x25, 0xC3, 0x34, 0xF9, 0xCB, 0xED, 0x2D, 0x1F, 0xFE, 0xF2, 0xAC, 0xD1, 0x82, 0xC5, 0x9C, 0xEF, 0x35, 0xBA, 0xDD, 0x18, 0x42, 0xB1, 0x20, 0xA7, 0xD2, 0x84, 0x61, 0x61, 0xD1, 0x28, 0x27, 0x08, 0xBE, 0x93, 0xC5, 0xF2, 0x99, 0x2C, 0x56, 0x60, 0x3E, 0x72, 0xAD, 0x42, 0xC4, 0x8A, 0xEB, 0x33, 0xAE, 0xF4, 0x7E, 0x1B, 0xC1, 0x55, 0xFF, 0x0C, 0x74, 0x36, 0xFF, 0xBA, 0xBD, 0x80, 0xF8, 0x63, 0xAD, 0xBA, 0xE8, 0x70, 0x50, 0x63, 0x73, 0x09, 0x9F, 0xB5, 0x85, 0x67, 0xEE, 0x92, 0x69, 0x03, 0xEF, 0xFE, 0x38, 0xA0, 0x6A, 0xBB, 0x7D, 0x6F, 0x01, 0x5C, 0x2B, 0x40, 0xFB, 0x16, 0xC7, 0x0D, 0x07, 0xF4, 0x00, 0x7E, 0xF6, 0x97, 0x6B, 0xB5, 0x84, 0x38, 0x59, 0x37, 0x72, 0x08, 0xE9, 0x4C, 0xCE, 0xE1, 0x71, 0x6A, 0x6B, 0xE6, 0xBC, 0x83, 0x75, 0x7F, 0x45, 0xB2, 0x82, 0xF5, 0xE2, 0x43, 0xAB, 0xCD, 0xF9, 0xBC, 0xA0, 0x93, 0x77, 0xA4, 0x93, 0x44, 0x3B, 0x30, 0x0C, 0x94, 0x8C, 0xE8, 0x4D, 0x88, 0xF3, 0x05, 0xA5, 0x2D, 0xEC, 0x79, 0xED, 0x9E, 0x25, 0xBA, 0x3F, 0x30, 0x01, 0xE8, 0x1B, 0x28, 0xE5, 0xB3, 0xC8, 0xAD, 0xE4, 0x96, 0x8E, 0x10, 0xFE, 0x71, 0xCF, 0xFB, 0xE1, 0xCB, 0x54, 0x3B, 0x01, 0x33, 0x80, 0x25, 0x10, 0x2B, 0x06, 0xE5, 0xC0, 0x24, 0xDB, 0x82, 0x0C, 0x30, 0xE2, 0xF0, 0xBB, 0x08, 0x40, 0xED, 0x16, 0x5F, 0x88, 0xE7, 0x59, 0x2B, 0x1C, 0xB4, 0x19, 0x18, 0x0A, 0x36, 0x7F, 0xDD, 0x8E, 0xE8, 0x31, 0x1C, 0x9F, 0xE6, 0x78, 0xFC, 0xD3, 0x7F, 0x06, 0x31, 0x3D, 0xB7, 0xC8, 0xFE, 0x57, 0x3A, 0xC7, 0xFA, 0x96, 0xD2, 0x9C, 0x43, 0xD4, 0xE2, 0x9E, 0xC4, 0x4B, 0x9A, 0x32, 0xE7, 0x55, 0xEF, 0x78, 0x74, 0x13, 0xE6, 0x39, 0xA5, 0x1E, 0x85, 0xB8, 0xB8, 0x35, 0xFA, 0x66, 0x87, 0xEE, 0xF8, 0x4A, 0x7B, 0x02, 0x79, 0xF8, 0xC7, 0x60, 0x93, 0x91, 0x02, 0xF9, 0x79, 0x43, 0x55, 0x00, 0x57, 0x60, 0x67, 0x13, 0x73, 0xE5, 0x9C, 0x0D, 0x38, 0x71, 0xBF, 0xA1, 0x16, 0xC0, 0x49, 0x40, 0xF3, 0xFB, 0x86, 0x36, 0x1E, 0x78, 0xBB, 0xB7, 0x22, 0x55, 0xDC, 0x6B, 0x53, 0xB3, 0x9C, 0xAA, 0x0D, 0xC9, 0x12, 0x25, 0x4A, 0x05, 0xF1, 0x5D, 0x52, 0x43, 0xC3, 0xEC, 0x03, 0x24, 0x4F, 0x94, 0x98, 0x40, 0x0C, 0xD0, 0xCD, 0x13, 0xCC, 0xDF, 0x4E, 0x3D, 0xD8, 0x17, 0x89, 0x59, 0xCE, 0x8D, 0x89, 0x6E, 0xED, 0xF7, 0x5E, 0xB3, 0x76, 0x18, 0x41, 0x3A, 0x9B, 0xA2, 0x4A, 0x18, 0x5D, 0x6E, 0x37, 0x5E, 0x6E, 0x25, 0x8E, 0xD5, 0xB6, 0x02, 0xB6, 0xEC, 0x11, 0x09, 0x78, 0x10, 0x02, 0x44, 0xF3, 0x29, 0x3E, 0xC0, 0x6C, 0x05, 0xCF, 0x01, 0x7D, 0x9A, 0x19, 0x80, 0x18, 0xC0, 0x04, 0x08, 0xFE, 0x24, 0x1F, 0xA3, 0x0D, 0x97, 0x4D, 0xBF, 0x6D, 0xCB, 0x82, 0xCD, 0x78, 0x3B, 0xFA, 0xEF, 0x81, 0xEF, 0x02, 0x79, 0x5D, 0x94, 0xE0, 0x70, 0x81, 0xC6, 0x7C, 0x8C, 0xE6, 0xB2, 0x22, 0x42, 0x9F, 0xCD, 0x78, 0xE9, 0x77, 0x46, 0x36, 0x02, 0x18, 0xDF, 0xF0, 0xE7, 0x8D, 0xB7, 0x19, 0x53, 0x1B, 0x1F, 0x9C, 0x60, 0x0E, 0x36, 0x85, 0x58, 0x95, 0xAF, 0x9D, 0xAB, 0xE3, 0xD9, 0x1C, 0x6C, 0x58, 0x86, 0x79, 0x01, 0x59, 0x99, 0xB5, 0x06, 0x42, 0x01, 0x6D, 0xC0, 0x94, 0x70, 0x20, 0x82, 0x2D, 0x6B, 0x0E, 0x94, 0x30, 0xBB, 0x11, 0x84, 0xAD, 0x94, 0x16, 0x90, 0x0D, 0x44, 0x02, 0x55, 0xEB, 0x08, 0xD1, 0x68, 0x7C, 0x0C, 0xEC, 0x71, 0x69, 0xF1, 0x5D, 0x4B, 0xEC, 0x27, 0x6E, 0x74, 0x34, 0x34, 0x95, 0xE7, 0x4E, 0x18, 0xC6, 0x2F, 0xB4, 0xF9, 0xE8, 0x1B, 0x56, 0xBC, 0x41, 0xA2, 0xD4, 0xA3, 0x06, 0xD5, 0xBC, 0xCF, 0x94, 0xC8, 0xE1, 0xDB, 0x72, 0x49, 0x3F, 0xF4, 0x0E, 0x28, 0x6E, 0x93, 0x01, 0x07, 0x22, 0x76, 0xBA, 0x1C, 0x97, 0x23, 0xB4, 0x0D, 0x36, 0x8E, 0xA4, 0x94, 0x5A, 0x30, 0x61, 0x28, 0x5C, 0x35, 0xA3, 0xDB, 0xE7, 0xDE, 0x40, 0x0E, 0xE0, 0x0A, 0x98, 0xEC, 0x27, 0x62, 0x80, 0x6A, 0xFC, 0xDF, 0x99, 0x31, 0x36, 0x20, 0x5C, 0x08, 0x07, 0xEC, 0x00, 0xE2, 0x84, 0x02, 0xCE, 0xA2, 0x94, 0xFA, 0xDA, 0x4C, 0x30, 0xB8, 0xAE, 0x49, 0x81, 0xFB, 0xAF, 0xB0, 0xD5, 0xAE, 0xA8, 0x51, 0x4E, 0x7C, 0x16, 0x34, 0xC2, 0xEA, 0xBC, 0x83, 0x78, 0xE5, 0xDF, 0x48, 0x6A, 0x3E, 0xED, 0xCA, 0x09, 0xC8, 0xE7, 0x2C, 0x8B, 0x7C, 0x1B, 0xB3, 0x72, 0x6D, 0xCE, 0x7F, 0x84, 0xF2, 0x75, 0x36, 0xFB, 0x13, 0x50, 0x62, 0x87, 0x66, 0x5E, 0x53, 0xBE, 0xB8, 0x1D, 0x60, 0xE5, 0x15, 0xAC, 0x5D, 0xC7, 0xBF, 0xF8, 0x93, 0x7E, 0x7B, 0xB6, 0x19, 0x11, 0x39, 0xD3, 0x8D, 0xEF, 0xF4, 0x58, 0x0D, 0x33, 0x6D, 0xEC, 0x51, 0x70, 0x62, 0x88, 0x4E, 0x20, 0x15, 0x50, 0x7B, 0x3B, 0x6E, 0xEB, 0xE9, 0x51, 0x30, 0x59, 0xA3, 0x29, 0x0A, 0x88, 0xAA, 0x68, 0x39, 0xAC, 0x46, 0xB0, 0x8F, 0x87, 0xA9, 0xC5, 0xD7, 0x2B, 0x32, 0x2E, 0x6F, 0x2E, 0x64, 0xC1, 0x72, 0xD6, 0x4A, 0xF7, 0x2A, 0x87, 0x4D, 0xC7, 0x0A, 0x2D, 0x92, 0x40, 0x37, 0x30, 0x43, 0x34, 0x33, 0xDB, 0x44, 0x9C, 0xCD, 0x58, 0x5C, 0x45, 0x82, 0x15, 0x65, 0x9A, 0x47, 0x24, 0x38, 0x6C, 0xB5, 0x92, 0x58, 0xC3, 0xDB, 0xB1, 0xB1, 0x9D, 0x4A, 0x5F, 0xA7, 0x2C, 0x56, 0x24, 0x78, 0x37, 0x65, 0xD3, 0x4D, 0xE5, 0x1D, 0xAC, 0x14, 0x94, 0x89, 0x55, 0x0D, 0x4A, 0x20, 0x7A, 0xAF, 0x62, 0x98, 0x57, 0x14, 0x48, 0x01, 0x22, 0x81, 0x1D, 0xA1, 0x19, 0x22, 0x1D, 0x78, 0xF6, 0xA0, 0x6D, 0xD0, 0x0E, 0xFF, 0x4B, 0xC5, 0x15, 0x29, 0x56, 0x11, 0xAC, 0xF4, 0x52, 0x6C, 0x30, 0xD3, 0x76, 0x74, 0xA0, 0xB2, 0xC5, 0x4D, 0x38, 0x41, 0x35, 0x96, 0xFF, 0x6D, 0x1D, 0xD2, 0xB5, 0xCB, 0xA7, 0xFC, 0x39, 0x6C, 0xB3, 0x68, 0x62, 0xE6, 0xD6, 0x83, 0x2E, 0x79, 0xD5, 0xE0, 0x1E, 0x0F, 0xE0, 0x59, 0x83, 0x5E, 0x4C, 0x53, 0x07, 0x63, 0x6E, 0xA5, 0x92, 0xE6, 0x24, 0x70, 0x12, 0xDF, 0x99, 0x02, 0xC1, 0xEF, 0xBC, 0x58, 0x71, 0x92, 0x2D, 0x12, 0x01, 0xB3, 0x5B, 0x7A, 0x06, 0xA8, 0x60, 0xCA, 0xF1, 0x00, 0xA9, 0xD4, 0xD9, 0x08, 0xC0, 0x89, 0xD0, 0x0F, 0x1C, 0xC8, 0x04, 0x3A, 0x90, 0x72, 0xF4, 0x5C, 0x9B, 0x39, 0x3C, 0xC1, 0x0C, 0x44, 0xD7, 0xE1, 0xD0, 0x44, 0x71, 0xC7, 0x66, 0x2C, 0x19, 0x6E, 0x86, 0x31, 0xF4, 0x97, 0x6B, 0x72, 0xDA, 0x35, 0xAE, 0x32, 0xFB, 0x21, 0xED, 0x9A, 0x14, 0xC0, 0xD3, 0xFE, 0xE4, 0x5B, 0xF9, 0x7F, 0x01, 0xA8, 0x00, 0x3E, 0xEF, 0xCA, 0x13, 0x65, 0x22, 0x71, 0x3D, 0x75, 0x1A, 0xCD, 0xCF, 0xA3, 0x0A, 0xAA, 0x46, 0xAC, 0x7E, 0x28, 0x87, 0xC9, 0x92, 0x53, 0xAF, 0xFB, 0x02, 0x3F, 0xCF, 0x86, 0x33, 0x3E, 0x8D, 0x77, 0x54, 0x33, 0x9F, 0x57, 0xEF, 0x34, 0x60, 0x44, 0xE9, 0xCA, 0x88, 0x72, 0x73, 0xA7, 0x00, 0xBE, 0x38, 0x80, 0xEA, 0xA7, 0x91, 0xA8, 0xEF, 0xC5, 0xF7, 0xA3, 0x6B, 0xB4, 0x40, 0x33, 0x6C, 0x2B, 0xB7, 0xB0, 0x14, 0x9B, 0x60, 0x30, 0xC1, 0xA3, 0x86, 0xC5, 0xD9, 0x95, 0xCE, 0xBB, 0xD3, 0x79, 0xC6, 0x27, 0x0F, 0xFE, 0x7B, 0xBD, 0xB8, 0x7F, 0xEA, 0xEC, 0xBB, 0xCD, 0x44, 0x77, 0x4C, 0xB1, 0x3F, 0x8A, 0xE3, 0x44, 0xCA, 0x1B, 0x4E, 0x3F, 0x89, 0x86, 0x47, 0x23, 0x74, 0x78, 0x4B, 0x4A, 0x01, 0x4F, 0x13, 0x76, 0xF2, 0x46, 0x0B, 0x26, 0x7E, 0x00, 0xDE, 0xB5, 0xF2, 0xEC, 0xC6, 0xDE, 0xB6, 0xD0, 0x91, 0x7F, 0xEC, 0xBF, 0x73, 0x05, 0xF0, 0xC0, 0xE8, 0x33, 0x42, 0xA5, 0x09, 0x64, 0xDD, 0x08, 0x05, 0x2C, 0x01, 0x2D, 0x60, 0x1F, 0x57, 0x8B, 0xB5, 0xD9, 0x93, 0x14, 0x22, 0x98, 0x87, 0xF1, 0xE6, 0x27, 0xEE, 0x8E, 0x3E, 0x83, 0xDE, 0x9B, 0x53, 0xB8, 0x10, 0x99, 0x46, 0xB4, 0xD5, 0xB7, 0x05, 0xE6, 0x4D, 0x74, 0xA3, 0x24, 0x9E, 0xCC, 0x59, 0xAC, 0x34, 0xCA, 0x00, 0x61, 0x77, 0xD4, 0xB7, 0xE1, 0x5E, 0xD6, 0xEE, 0x2C, 0xE5, 0x53, 0x30, 0xBC, 0xF4, 0x1C, 0x19, 0x43, 0x4B, 0xEE, 0xE4, 0xDC, 0x41, 0xBA, 0x06, 0x52, 0x3F, 0x3D, 0x8D, 0xCC, 0x11, 0x76, 0x32, 0x29, 0xDD, 0x40, 0x0E, 0x30, 0xC2, 0x41, 0x3A, 0x25, 0x02, 0xB0, 0x01, 0x4A, 0x80, 0x89, 0x7F, 0xA1, 0x6E, 0x19, 0x13, 0x17, 0xA2, 0x80, 0xAC, 0xB5, 0x59, 0x7D, 0x6D, 0x86, 0xD7, 0xB1, 0xF4, 0xB2, 0x99, 0xDB, 0x60, 0xBD, 0x28, 0x75, 0xAF, 0xA6, 0xFC, 0x67, 0xB3, 0xA4, 0xCD, 0x0A, 0x16, 0x7C, 0xD6, 0x75, 0xE2, 0xD3, 0x9F, 0x6E, 0xB8, 0xCC, 0x8A, 0xA1, 0x01, 0x91, 0x40, 0xF9, 0x86, 0xE4, 0xEC, 0x70, 0xDC, 0xD1, 0xB2, 0x5D, 0xA2, 0xCF, 0x86, 0x13, 0x74, 0x44, 0x31, 0x21, 0xDF, 0x8C, 0xBE, 0x1B, 0x91, 0xFD, 0x0F, 0x3B, 0x37, 0xB6, 0xF6, 0x8C, 0xB3, 0x6B, 0x01, 0xEF, 0x55, 0xA7, 0x56, 0x40, 0x33, 0x5F, 0x2D, 0x03, 0xB8, 0x00, 0x2D, 0xB0, 0xA7, 0x1D, 0x20, 0x0B, 0x68, 0x03, 0xA6, 0x68, 0x5D, 0x01, 0xAC, 0x81, 0xBA, 0xEC, 0xC9, 0x46, 0x1C, 0xD8, 0xAC, 0x91, 0xCB, 0x3E, 0x82, 0xE8, 0x77, 0xE2, 0x2A, 0xE2, 0x99, 0x18, 0x22, 0xCE, 0x61, 0x40, 0x73, 0xEA, 0x77, 0x2B, 0x76, 0x5D, 0x39, 0x8E, 0xF6, 0x4F, 0xE5, 0x33, 0xF4, 0x23, 0xA3, 0x39, 0x80, 0x0A, 0xF1, 0xD9, 0xF1, 0x33, 0xC1, 0x3A, 0xDD, 0x79, 0x97, 0xD7, 0xC8, 0x6A, 0x6F, 0xA1, 0x6F, 0x19, 0x39, 0xC1, 0x24, 0xE2, 0x95, 0x46, 0x33, 0xDE, 0x17, 0x08, 0xA9, 0x81, 0x95, 0xDA, 0x66, 0x40, 0xBF, 0xFB, 0xBA, 0xC6, 0x56, 0x67, 0x82, 0xF1, 0x82, 0xDD, 0x3D, 0x8D, 0x99, 0x3C, 0xB4, 0x04, 0x98, 0x55, 0x8F, 0x76, 0x42, 0x80, 0xF3, 0x28, 0x3F, 0x01, 0x99, 0x40, 0x19, 0xBE, 0xF3, 0x59, 0xA3, 0x0D, 0xDC, 0xCD, 0x13, 0x30, 0x4C, 0x7C, 0x7B, 0x21, 0x39, 0x04, 0xD1, 0x43, 0x7D, 0xF1, 0x42, 0xD7, 0xA2, 0x38, 0xDA, 0xF9, 0xFE, 0x69, 0xB4, 0xEF, 0x48, 0xD9, 0xA2, 0x08, 0x07, 0xB4, 0x80, 0xD4, 0x77, 0xC5, 0x5B, 0xEF, 0xAB, 0xFE, 0x27, 0x6D, 0x23, 0xCD, 0x40, 0x73, 0x75, 0xC4, 0x98, 0xD4, 0xE8, 0x59, 0xF5, 0x11, 0xD6, 0xD3, 0x0B, 0xE8, 0xF3, 0x4E, 0x6B, 0xE8, 0x7A, 0x73, 0xB4, 0x96, 0x3C, 0xC3, 0xC7, 0xC5, 0x08, 0xAA, 0x76, 0xD0, 0xFF, 0x87, 0x7C, 0xAE, 0x86, 0x13, 0x40, 0x0A, 0x10, 0x73, 0x4B, 0x59, 0x4F, 0x03, 0x75, 0x80, 0xBD, 0x13, 0x0E, 0x4E, 0x34, 0x96, 0x1A, 0x77, 0xF6, 0xA7, 0x30, 0x73, 0xD7, 0x02, 0x83, 0xD2, 0x68, 0x98, 0x9F, 0xD7, 0xA4, 0x82, 0xA9, 0x62, 0x29, 0xAE, 0xE4, 0xD6, 0xEC, 0xEE, 0x31, 0x1F, 0x3C, 0x1C, 0xEF, 0x9A, 0x3B, 0x98, 0xC2, 0x89, 0xF0, 0xFD, 0x44, 0x34, 0x10, 0x2B, 0xAA, 0xF9, 0x0C, 0x1E, 0xE4, 0xF6, 0xBB, 0xBF, 0x91, 0xC2, 0xEC, 0xA8, 0xD3, 0x33, 0xC6, 0x32, 0x01, 0xC8, 0x5E, 0xB2, 0x44, 0x3D, 0xFF, 0xB3, 0xF2, 0x1C, 0x58, 0xFB, 0xF0, 0x8A, 0x08, 0xE5, 0x1C, 0x81, 0xBD, 0xA5, 0x76, 0x1E, 0xAF, 0x98, 0x72, 0xBF, 0x07, 0x08, 0xFA, 0x10, 0x09, 0xE4, 0x00, 0x5E, 0x80, 0x39, 0x80, 0x31, 0xE7, 0x01, 0x60, 0x34, 0xE1, 0x26, 0x85, 0x5C, 0xA9, 0x97, 0x77, 0x07, 0xD2, 0xD1, 0x76, 0xEE, 0xD2, 0x57, 0x2A, 0x80, 0x61, 0x31, 0xCD, 0xF0, 0xF5, 0xCC, 0xAF, 0xB8, 0xA1, 0xED, 0xEB, 0xF9, 0x49, 0x76, 0x1F, 0xC2, 0x80, 0x33, 0x80, 0xC6, 0x1D, 0x14, 0x6C, 0xBB, 0xA4, 0x3D, 0xF3, 0x19, 0xCE, 0xD0, 0xAB, 0x61, 0x9F, 0xD8, 0x64, 0xC4, 0x00, 0xD2, 0xBC, 0x65, 0xB7, 0xAF, 0x4F, 0x37, 0x3B, 0x0E, 0xBB, 0xDA, 0x66, 0x55, 0xE3, 0xF5, 0x53, 0xE9, 0x6C, 0xF9, 0x3C, 0xB3, 0x02, 0xE1, 0x8C, 0x45, 0x03, 0x58, 0xD9, 0xEB, 0x47, 0xEE, 0xE4, 0xC6, 0xDB, 0x2C, 0x0E, 0x64, 0x00, 0xB5, 0x7B, 0x86, 0xCE, 0x1A, 0x8D, 0xD1, 0x80, 0x38, 0xFA, 0xFA, 0xFC, 0x3E, 0xD3, 0x8E, 0x27, 0xDB, 0xED, 0x8A, 0xCA, 0x3D, 0x89, 0x7C, 0xFF, 0x9C, 0x6B, 0x78, 0xB1, 0xE5, 0xFB, 0x7E, 0xC6, 0x67, 0x2F, 0x4D, 0x12, 0xF1, 0x59, 0x23, 0x45, 0x3C, 0x1B, 0xA2, 0x59, 0x29, 0xC8, 0x78, 0x94, 0x63, 0x98, 0x3C, 0xDC, 0x94, 0x3D, 0x13, 0x84, 0x8F, 0x48, 0xCC, 0xFA, 0xC9, 0xB5, 0x1B, 0xDA, 0x80, 0xD8, 0xC4, 0x62, 0xF0, 0x02, 0x62, 0xF9, 0xA0, 0x77, 0xBF, 0xC7, 0x4E, 0x29, 0x6D, 0x0D, 0x45, 0x81, 0xC8, 0x95, 0x6D, 0x03, 0x26, 0x76, 0xF5, 0x12, 0x21, 0xC0, 0xD9, 0x49, 0x3D, 0xC2, 0x13, 0x08, 0xDF, 0xB4, 0xDB, 0x5A, 0xCD, 0xAE, 0x99, 0xD8, 0x28, 0x85, 0x90, 0xB8, 0x1A, 0xCE, 0x26, 0x1B, 0x24, 0x15, 0xBA, 0x50, 0x23, 0xDA, 0xD5, 0xE2, 0x28, 0xB1, 0x4F, 0xD1, 0x58, 0x84, 0xEF, 0x1E, 0xF6, 0xDE, 0x84, 0xFF, 0xAE, 0xD1, 0x6D, 0xA0, 0x0B, 0x28, 0xBB, 0xD1, 0x1C, 0x66, 0x5F, 0x67, 0x6D, 0x65, 0x10, 0x57, 0x84, 0x64, 0x64, 0x35, 0xED, 0x77, 0x9B, 0x3C, 0xA0, 0x06, 0xF8, 0x00, 0xCD, 0x23, 0x1C, 0x8E, 0x9C, 0xB3, 0xA6, 0x2E, 0xEB, 0xB0, 0x00, 0x95, 0x14, 0x93, 0xA0, 0xAC, 0x46, 0xD3, 0x15, 0x6E, 0x25, 0x7E, 0x59, 0x1A, 0x20, 0x15, 0xE8, 0x03, 0x4C, 0xC2, 0xD1, 0x11, 0x03, 0xAC, 0x80, 0x52, 0xA0, 0x77, 0x94, 0xE3, 0x79, 0xD2, 0x9C, 0xB9, 0x1E, 0x81, 0xCD, 0x66, 0x30, 0x8F, 0x60, 0xC3, 0x9A, 0x09, 0x0F, 0x43, 0x39, 0x02, 0x38, 0xE2, 0x01, 0x8E, 0x12, 0x44, 0xDF, 0xCA, 0xFA, 0x76, 0x3D, 0x5A, 0xFD, 0xAA, 0x34, 0x19, 0x30, 0xCD, 0x7C, 0xF6, 0x01, 0x94, 0x88, 0xAB, 0x41, 0x37, 0xF1, 0xE9, 0x09, 0xA5, 0xE6, 0x49, 0x90, 0x65, 0x03, 0xB3, 0x4A, 0x13, 0x71, 0x4B, 0x4C, 0x1C, 0x42, 0xF8, 0x5D, 0x36, 0x4C, 0xB8, 0xCD, 0x69, 0xC2, 0xE1, 0xAF, 0xF5, 0x62, 0x8F, 0x02, 0x53, 0xAF, 0x56, 0x87, 0x3F, 0x8D, 0x1A, 0x2A, 0x40, 0x3A, 0x51, 0x40, 0x18, 0x60, 0x7A, 0xFF, 0xC4, 0x19, 0x51, 0x59, 0xAE, 0xD1, 0xE2, 0xDA, 0x82, 0xAA, 0xE6, 0x68, 0x8A, 0xAC, 0x44, 0x03, 0x4B, 0x17, 0xF4, 0x1C, 0x46, 0x7F, 0x68, 0x19, 0xB4, 0xDB, 0x69, 0x72, 0xB0, 0xE7, 0x8E, 0xA1, 0x9E, 0xEA, 0xDC, 0x56, 0x49, 0x7A, 0xB6, 0x3B, 0x19, 0x28, 0x25, 0x04, 0xC0, 0x77, 0xF9, 0x0C, 0x0D, 0xED, 0xAB, 0x67, 0xC2, 0x68, 0xDB, 0x19, 0x04, 0xD9, 0x4A, 0xD1, 0xAE, 0xCE, 0x23, 0x10, 0x44, 0x0A, 0xD0, 0x0A, 0xFB, 0x4C, 0xD3, 0xF5, 0x6F, 0xC6, 0x98, 0x3F, 0x30, 0x99, 0x59, 0x42, 0x20, 0xB0, 0x42, 0xCD, 0xF7, 0x00, 0x49, 0xCC, 0x4A, 0x07, 0x24, 0x31, 0x80, 0x05, 0xE0, 0x0A, 0x04, 0x51, 0x49, 0x0C, 0x30, 0xB2, 0x46, 0x63, 0x3C, 0x40, 0x41, 0xDA, 0x89, 0x46, 0x7A, 0x4E, 0xED, 0x5A, 0xEC, 0xE3, 0xBB, 0x29, 0x39, 0x03, 0x65, 0xC0, 0x1F, 0xB6, 0x8D, 0xFD, 0x41, 0xE9, 0x9B, 0xF4, 0x7F, 0x04, 0xF3, 0xFC, 0x51, 0x2D, 0x4F, 0x01, 0x22, 0x89, 0xBE, 0xF7, 0xC7, 0x24, 0xB5, 0xC8, 0x73, 0xB7, 0x12, 0xAC, 0x8B, 0x4B, 0x13, 0x6C, 0x2F, 0xCF, 0xCC, 0xB6, 0xB3, 0x00, 0x79, 0x80, 0xA1, 0x72, 0x84, 0x25, 0xCD, 0x93, 0xAB, 0x2B, 0xFA, 0xCA, 0x26, 0xF0, 0x27, 0x8D, 0x4E, 0x24, 0xF4, 0x1A, 0xE8, 0x3D, 0x14, 0x15, 0xF9, 0x91, 0x43, 0x4C, 0xC0, 0x0E, 0x51, 0x40, 0xEA, 0xC7, 0xE1, 0x0D, 0xC0, 0x73, 0x6D, 0x56, 0x28, 0xD5, 0x86, 0x70, 0xCA, 0xE8, 0xBA, 0x07, 0x46, 0x6A, 0xD0, 0x6A, 0x75, 0x94, 0x2A, 0x6D, 0x0D, 0xE1, 0x5A, 0xAD, 0x77, 0x90, 0xA0, 0xBE, 0xD3, 0xD8, 0x36, 0x9F, 0x69, 0x6C, 0x25, 0x04, 0xA8, 0x03, 0xB4, 0xAE, 0xFE, 0x2D, 0x90, 0xF1, 0xBA, 0x28, 0x4F, 0x7F, 0x50, 0x3F, 0xCB, 0xFA, 0xCC, 0xB7, 0x78, 0x04, 0x28, 0x71, 0x76, 0x47, 0x20, 0x3F, 0xED, 0x3E, 0x9F, 0xDD, 0x7A, 0xE7, 0x7C, 0xB9, 0xA5, 0x5E, 0xC5, 0x98, 0x7E, 0xE6, 0x8B, 0x85, 0x19, 0xDC, 0x53, 0x40, 0xEF, 0x34, 0xAD, 0xF1, 0xBA, 0x4C, 0x40, 0xEC, 0xD3, 0x9F, 0x96, 0x84, 0xF2, 0x3B, 0x01, 0xDA, 0xD6, 0x68, 0x0D, 0xC9, 0xE3, 0x0E, 0x0C, 0x71, 0xF9, 0xFC, 0x82, 0x85, 0xF1, 0xBB, 0x53, 0x5E, 0x06, 0xF9, 0xC7, 0x1A, 0xF9, 0xD5, 0xEF, 0x22, 0xE3, 0xD5, 0xA0, 0x6E, 0xF9, 0x78, 0x1C, 0x95, 0xB7, 0x68, 0xFE, 0x49, 0x40, 0xF6, 0x53, 0x00, 0x6A, 0x00, 0xDB, 0x6E, 0x69, 0xE5, 0xC1, 0x27, 0x5C, 0x0E, 0x49, 0x1F, 0x6C, 0x27, 0x02, 0x07, 0x58, 0x71, 0xEE, 0x18, 0x60, 0x23, 0xD6, 0x5E, 0x4F, 0x4E, 0x76, 0xAD, 0x1F, 0xCF, 0x39, 0x7A, 0x07, 0xAD, 0x6F, 0x43, 0xDA, 0x1E, 0x4D, 0xAC, 0xF7, 0x6D, 0x03, 0x69, 0x32, 0x7E, 0x2D, 0xBA, 0x21, 0x85, 0x33, 0x06, 0x58, 0xE1, 0x92, 0x02, 0x3A, 0x89, 0xF3, 0x51, 0x33, 0xE9, 0x35, 0xDA, 0x5C, 0x21, 0xA7, 0xCA, 0xAC, 0xAE, 0x3E, 0x45, 0x70, 0x9A, 0x63, 0x45, 0x89, 0x91, 0xF9, 0xE0, 0x00, 0x8A, 0xA3, 0xA4, 0x62, 0x9F, 0x5E, 0xE5, 0xED, 0x08, 0x2A, 0x7F, 0xFD, 0x07, 0xE4, 0x57, 0x00, 0x03, 0xF6, 0x8E, 0x98, 0x8F, 0xE6, 0x7E, 0xF8, 0xFA, 0xB6, 0xAB, 0xFA, 0xB8, 0xCE, 0x57, 0xD3, 0xF9, 0x3A, 0x80, 0x34, 0x61, 0x80, 0x2B, 0x50, 0xAF, 0x6E, 0xCA, 0xC6, 0x79, 0xFE, 0x27, 0xC5, 0x27, 0xBB, 0xE7, 0xE3, 0xC0, 0x4C, 0x87, 0xFF, 0x6A, 0xEF, 0x7B, 0xB8, 0xBA, 0x6C, 0x67, 0xF3, 0x80, 0x18, 0xA0, 0x1A, 0x98, 0x66, 0x93, 0x72, 0x00, 0xD1, 0x40, 0x9D, 0x5B, 0xB0, 0x75, 0x45, 0x30, 0x22, 0x0B, 0xA7, 0xEC, 0xA9, 0xFF, 0xF6, 0x24, 0x4C, 0x24, 0xFE, 0x29, 0x12, 0x70, 0x58, 0x4B, 0x5E, 0xE1, 0xEE, 0xB9, 0x96, 0xB1, 0xBF, 0x2D, 0x40, 0xFD, 0x51, 0x9B, 0x96, 0xF3, 0xF1, 0xD2, 0x02, 0x90, 0x06, 0x6A, 0x67, 0xF3, 0x7C, 0xEF, 0x8F, 0xDE, 0x26, 0x77, 0x4E, 0xC5, 0xF2, 0x65, 0x5D, 0x85, 0x1D, 0x77, 0x40, 0x13, 0x38, 0x07, 0xA8, 0xA1, 0x23, 0xB7, 0x7B, 0x19, 0x7A, 0x65, 0xE5, 0x76, 0x1D, 0x11, 0x47, 0xF5, 0x39, 0xA1, 0x93, 0x42, 0xA7, 0x3F, 0x78, 0xB1, 0xEE, 0x58, 0x4B, 0x33, 0x67, 0x64, 0x40, 0x1C, 0xC0, 0x12, 0xD0, 0x03, 0x9C, 0x01, 0x2C, 0x76, 0x35, 0xCB, 0x1A, 0x4D, 0xAE, 0x28, 0xD3, 0x6A, 0x1B, 0x72, 0xEF, 0x29, 0x33, 0x91, 0x41, 0xF6, 0x5C, 0x0B, 0xFA, 0xA0, 0x86, 0x99, 0x15, 0xFB, 0xCC, 0xAC, 0xD4, 0xFB, 0x22, 0x8A, 0x3C, 0x5D, 0x8A, 0x6D, 0xEC, 0x5C, 0x17, 0x7C, 0xAA, 0x01, 0x32, 0x80, 0x18, 0x7E, 0x97, 0x6F, 0x9C, 0xCE, 0x0A, 0x19, 0xBA, 0x25, 0xEE, 0x19, 0x59, 0x3B, 0x80, 0x0A, 0xE0, 0x03, 0xD4, 0x6E, 0x97, 0xDD, 0xDA, 0x1D, 0x6F, 0xD2, 0xDE, 0xBB, 0x33, 0x29, 0x25, 0x1D, 0x74, 0xB3, 0xD8, 0x00, 0x19, 0xBC, 0x15, 0x8E, 0x00, 0xC3, 0x81, 0xB2, 0x08, 0xA0, 0x88, 0x1E, 0xB6, 0x43, 0x2A, 0xA0, 0x06, 0xE4, 0x21, 0x02, 0x68, 0x5B, 0x9B, 0xE9, 0x3D, 0x77, 0x7D, 0xEA, 0xE7, 0x07, 0x4A, 0x26, 0x04, 0x14, 0x42, 0xE1, 0x03, 0x45, 0xA3, 0x52, 0xA1, 0x88, 0x77, 0x1C, 0x91, 0xA7, 0x7F, 0x9D, 0x34, 0x7B, 0xDB, 0xC9, 0xEA, 0x19, 0x52, 0xA9, 0x03, 0xB4, 0x7C, 0x3E, 0x11, 0xDB, 0xF1, 0x58, 0x73, 0xF5, 0xBE, 0x20, 0xD7, 0xC0, 0xFD, 0x6A, 0xEF, 0x52, 0x3B, 0xBC, 0xAA, 0xF7, 0x0A, 0xA0, 0x02, 0xCA, 0xB6, 0x43, 0xF3, 0x1D, 0x2F, 0x9E, 0xA7, 0xC5, 0x36, 0xA8, 0x32, 0xAD, 0xB4, 0xA0, 0xF1, 0xE5, 0x3C, 0xB5, 0xA7, 0x16, 0xD0, 0x5B, 0x55, 0x0A, 0xC0, 0x1D, 0xC8, 0x03, 0x94, 0x01, 0x43, 0x77, 0x45, 0x3F, 0x0D, 0x6B, 0x79, 0xD6, 0x66, 0xC6, 0x1E, 0xD7, 0x40, 0x17, 0xAE, 0xD5, 0x1B, 0x78, 0xA6, 0x6A, 0x51, 0x68, 0x70, 0xD6, 0xEB, 0x65, 0x8B, 0xB6, 0xFE, 0x77, 0x46, 0xF6, 0xC4, 0xBD, 0xA4, 0xD2, 0x07, 0xA8, 0x00, 0xB2, 0xFF, 0x4F, 0xB5, 0xD6, 0x9D, 0xFA, 0x79, 0x4C, 0xA8, 0x0D, 0xB4, 0xB0, 0xB5, 0xAD, 0x01, 0x1B, 0xC0, 0x9B, 0x18, 0xFC, 0xE4, 0x9D, 0xB4, 0xDA, 0x0D, 0xAA, 0x38, 0x7A, 0xB7, 0x57, 0x6B, 0x9B, 0xBA, 0xFD, 0x15, 0xBC, 0x52, 0xFC, 0xE4, 0x09, 0xE1, 0xD1, 0x38, 0x41, 0x19, 0x05, 0x20, 0x8C, 0x50, 0xC0, 0x0F, 0x61, 0x40, 0x9E, 0x55, 0x5A, 0x58, 0xA3, 0xF9, 0xAF, 0x16, 0xA2, 0x6D, 0x08, 0xE1, 0x9B, 0xA1, 0x82, 0xAD, 0x93, 0xC6, 0x40, 0xCC, 0x04, 0xE9, 0xD6, 0xE9, 0x5F, 0x32, 0xBB, 0xAA, 0x2E, 0x7D, 0x09, 0xFF, 0x5C, 0x03, 0xEA, 0x9B, 0x22, 0x03, 0x66, 0x08, 0x01, 0x62, 0x00, 0x77, 0x40, 0x1B, 0xD8, 0xF4, 0xC7, 0x33, 0x26, 0x2A, 0xB4, 0x41, 0x28, 0xCF, 0xB0, 0x55, 0x72, 0x4D, 0xE0, 0x34, 0xA0, 0x01, 0x58, 0xFC, 0xFD, 0x44, 0xB7, 0x7B, 0x83, 0xDE, 0xAB, 0xEF, 0xE1, 0x85, 0x2B, 0x06, 0x97, 0xA6, 0x6E, 0xDD, 0x9B, 0x0F, 0xCE, 0x75, 0xAA, 0xA3, 0xA1, 0x1E, 0xB5, 0x54, 0x22, 0x85, 0x48, 0xA0, 0x0C, 0x68, 0x56, 0x5D, 0x4F, 0x02, 0x35, 0x6B, 0xB4, 0xB8, 0x26, 0x17, 0x6D, 0x0A, 0x13, 0xF3, 0x9D, 0x97, 0x7A, 0x9A, 0x99, 0xB0, 0x1F, 0x05, 0xFB, 0xCB, 0x26, 0x7F, 0x4F, 0x5A, 0xCA, 0xF6, 0x6E, 0xDC, 0xB3, 0x51, 0xBD, 0x53, 0x3B, 0x2B, 0xDA, 0x7B, 0x00, 0x0F, 0x40, 0xFA, 0x73, 0x83, 0xF2, 0x93, 0xAF, 0x6E, 0xE4, 0xFC, 0xB0, 0x0B, 0x3A, 0xFD, 0x51, 0x99, 0x30, 0xBF, 0xD5, 0x7A, 0xF3, 0x91, 0xD7, 0x04, 0x76, 0x36, 0xB6, 0x36, 0x39, 0xB9, 0x55, 0xCC, 0x78, 0x54, 0xF8, 0x9F, 0x9E, 0xCF, 0xE6, 0xCB, 0xD6, 0x8C, 0x73, 0x9B, 0x39, 0xA6, 0xC1, 0x0D, 0x81, 0xC3, 0xCB, 0x00, 0xEB, 0xCF, 0xA9, 0x15, 0x74, 0x77, 0x89, 0x30, 0x20, 0x1B, 0x18, 0x5D, 0x9B, 0xAD, 0x79, 0x56, 0xC7, 0x7E, 0x2E, 0xA1, 0xA1, 0x7C, 0x94, 0x68, 0x58, 0x12, 0x4F, 0xC3, 0x66, 0x86, 0xF1, 0x77, 0x36, 0xAA, 0xBE, 0xCB, 0x8F, 0xFC, 0xDC, 0x6F, 0x60, 0x39, 0x90, 0x09, 0xC4, 0xA2, 0x80, 0x9C, 0xB7, 0x80, 0x9C, 0x4F, 0xCF, 0x07, 0x3D, 0xDB, 0x78, 0xD4, 0xBB, 0x7B, 0x00, 0x2D, 0x40, 0x0E, 0xE0, 0xF9, 0x4E, 0x3E, 0xF6, 0x36, 0x31, 0x6E, 0x71, 0x79, 0x93, 0x85, 0xB0, 0x6B, 0x24, 0xA3, 0x49, 0x06, 0x62, 0x49, 0xD3, 0x27, 0xEF, 0x06, 0xC6, 0xF3, 0x74, 0xD2, 0xEE, 0x61, 0x1F, 0x25, 0xBC, 0x81, 0x3E, 0x9F, 0x19, 0x50, 0x22, 0x63, 0x8D, 0x76, 0xAF, 0x0C, 0x4C, 0x51, 0x3C, 0x99, 0xA7, 0xD0, 0xFF, 0x34, 0x89, 0x5B, 0x8B, 0x51, 0x81, 0x65, 0x43, 0x45, 0xC3, 0x9A, 0xB3, 0x50, 0xF7, 0x76, 0x15, 0xDD, 0xD3, 0x2B, 0x6E, 0xA5, 0x0D, 0x11, 0xE0, 0xC8, 0x46, 0xF0, 0x9F, 0x61, 0x63, 0x01, 0xBC, 0xAF, 0xF1, 0xBB, 0x5D, 0x28, 0xBF, 0x7B, 0x36, 0xE5, 0x51, 0x95, 0x2C, 0x01, 0xBC, 0x81, 0x3E, 0x6F, 0x4A, 0x64, 0x45, 0x60, 0x36, 0xAD, 0xD3, 0x8C, 0xD2, 0x19, 0x23, 0x40, 0x4D, 0x9B, 0x6F, 0x67, 0xD1, 0x3E, 0xB4, 0xC1, 0xD9, 0x11, 0x27, 0x03, 0x62, 0x80, 0x36, 0xEA, 0xD8, 0xC9, 0xA7, 0x2B, 0x59, 0x81, 0x14, 0xC2, 0x81, 0x7A, 0x8C, 0x76, 0x97, 0x9C, 0xA4, 0xBF, 0x4E, 0xDA, 0xEA, 0x80, 0x0A, 0x53, 0x5A, 0xF5, 0x3B, 0xB5, 0x52, 0x67, 0xA3, 0xF3, 0x7B, 0xDE, 0x33, 0x3F, 0xED, 0x08, 0xFE, 0x0F, 0xD9, 0xB4, 0x54, 0xC0, 0x1B, 0x30, 0x22, 0xFC, 0xED, 0xB7, 0x5A, 0x65, 0xDC, 0xE1, 0x4D, 0xBC, 0xEF, 0x73, 0x3F, 0x72, 0xE8, 0x65, 0xFC, 0xD4, 0xAF, 0xF2, 0x30, 0x92, 0xA8, 0x3B, 0x23, 0xCF, 0x18, 0x61, 0xF5, 0x10, 0x36, 0x99, 0x41, 0x69, 0x08, 0x1D, 0x46, 0xA3, 0x8A, 0xB7, 0xD4, 0x7D, 0x8B, 0x31, 0xF7, 0x0C, 0x81, 0x2B, 0xD0, 0x45, 0x4F, 0xC3, 0x81, 0xD5, 0xE1, 0x17, 0x07, 0xFC, 0x00, 0x65, 0x6B, 0xB4, 0xB9, 0xF4, 0x32, 0x53, 0xFB, 0x6B, 0x34, 0x8A, 0x61, 0x33, 0xAD, 0xDC, 0x74, 0x2A, 0x4A, 0xF7, 0xF5, 0xBC, 0x97, 0x15, 0x9F, 0xBB, 0x71, 0x34, 0x1B, 0x98, 0x00, 0x3A, 0x81, 0x9C, 0x1B, 0xA5, 0x6F, 0x27, 0x78, 0xD0, 0xAE, 0xB8, 0x85, 0xDE, 0x31, 0x15, 0x7F, 0xA7, 0x3F, 0x81, 0xD3, 0x80, 0x17, 0x80, 0x1B, 0x35, 0x76, 0xA5, 0x3F, 0xB0, 0xDB, 0x4C, 0x63, 0x9D, 0x51, 0x26, 0x17, 0x8B, 0x3A, 0x3A, 0x8D, 0x5A, 0x17, 0x42, 0xF8, 0xB9, 0x2B, 0x82, 0x53, 0x3B, 0x6E, 0xFC, 0x39, 0xE1, 0x12, 0x28, 0x46, 0xF2, 0xDA, 0x80, 0xCF, 0xE7, 0x4C, 0xD3, 0xED, 0x89, 0xB0, 0x35, 0xD3, 0x7B, 0xA6, 0x65, 0x54, 0xB1, 0xAD, 0x04, 0x0D, 0xF3, 0x5D, 0x85, 0x01, 0xB9, 0x94, 0xAB, 0x45, 0xB9, 0x3E, 0xDD, 0xB6, 0xBE, 0xF6, 0x31, 0x60, 0xE6, 0xB3, 0xC9, 0x4D, 0xEE, 0x6A, 0x8A, 0x32, 0xF0, 0xCC, 0x78, 0xE5, 0x38, 0x74, 0x33, 0x64, 0xDB, 0x8F, 0x80, 0xC4, 0x05, 0xAA, 0xD3, 0xC6, 0xC2, 0xB7, 0xBE, 0x2D, 0xB8, 0xFA, 0xFC, 0x52, 0x8D, 0xDE, 0x6F, 0x52, 0x1D, 0xDF, 0x01, 0x4F, 0x40, 0x16, 0x42, 0x1C, 0x40, 0x13, 0x28, 0xD9, 0xFF, 0x3B, 0xA0, 0x0C, 0xC8, 0x06, 0x9C, 0x50, 0x01, 0xCE, 0x01, 0xD4, 0x76, 0xB9, 0xCF, 0x1A, 0x4D, 0x28, 0x1B, 0x12, 0xD7, 0x5B, 0x5A, 0x3A, 0xFB, 0x89, 0x7D, 0x5A, 0x82, 0x22, 0x75, 0x39, 0xBC, 0xA6, 0x32, 0x16, 0x86, 0x61, 0xAC, 0x06, 0x5C, 0xEF, 0xFC, 0xA3, 0xE7, 0x1E, 0xEB, 0x0D, 0xCC, 0x7C, 0x76, 0xF0, 0x9E, 0xD7, 0xBF, 0x62, 0x90, 0xB7, 0x53, 0xD5, 0xC6, 0x67, 0x2A, 0x98, 0x74, 0x7B, 0x02, 0x64, 0xFE, 0x91, 0xD3, 0xAD, 0x48, 0x0B, 0xED, 0x62, 0xC9, 0x62, 0xA5, 0x9C, 0x90, 0xAD, 0xA2, 0x1F, 0xC0, 0x1D, 0x90, 0x85, 0xDD, 0x9F, 0x8C, 0xD8, 0xFF, 0xBB, 0xB4, 0xED, 0xFD, 0xC0, 0xA7, 0x49, 0xA0, 0x0C, 0xF0, 0x02, 0xCC, 0x81, 0x70, 0xFC, 0x32, 0xD6, 0x4B, 0x63, 0x97, 0xD0, 0x6A, 0x68, 0x67, 0xF6, 0x7F, 0x8F, 0xB4, 0xE3, 0x5C, 0x2B, 0x88, 0x07, 0xAD, 0x6B, 0xF0, 0xA0, 0x7D, 0xAB, 0x77, 0xFA, 0xD9, 0x5A, 0xDF, 0xF2, 0x29, 0x79, 0x12, 0x56, 0x77, 0x5B, 0xF7, 0x8E, 0xE3, 0xF5, 0xB5, 0x49, 0x60, 0x3B, 0xF9, 0x5D, 0x1E, 0x65, 0x88, 0x4E, 0xA0, 0xFC, 0xDD, 0x83, 0x8A, 0x09, 0x5F, 0x44, 0x00, 0x1B, 0x51, 0x19, 0x90, 0xC1, 0x88, 0x6A, 0xF5, 0xE6, 0x88, 0x2E, 0x36, 0x5A, 0x09, 0x10, 0x44, 0xED, 0x94, 0xFB, 0x76, 0x7B, 0x1C, 0x20, 0xF3, 0xD3, 0xF1, 0x78, 0x56, 0x03, 0x16, 0xC8, 0x00, 0xF0, 0xFF, 0xEC, 0xCD, 0x3F, 0xA2, 0x2F, 0x48, 0xA3, 0x07, 0x85, 0xB6, 0x29, 0x28, 0xEC, 0xDA, 0xB9, 0xD6, 0xA1, 0x96, 0x24, 0xFA, 0x74, 0x1A, 0x71, 0x67, 0xE3, 0x41, 0xDB, 0xDA, 0xBA, 0x10, 0x5E, 0x6F, 0xF1, 0x17, 0x39, 0xED, 0x77, 0xC9, 0x00, 0x8C, 0xF6, 0x83, 0x17, 0xD0, 0x76, 0x2F, 0xE7, 0xDF, 0x45, 0x92, 0x4F, 0x9F, 0x3B, 0x13, 0xD6, 0xD6, 0x7C, 0x6E, 0x18, 0x1F, 0x97, 0x01, 0xA7, 0xF0, 0xC7, 0x62, 0xB0, 0x9D, 0x06, 0xF4, 0xF0, 0x11, 0xB9, 0x66, 0x5A, 0xFB, 0xCF, 0x7F, 0xE0, 0x6D, 0x19, 0x3B, 0x70, 0xDD, 0x40, 0xF1, 0x46, 0x74, 0x7A, 0xB6, 0x62, 0x80, 0x0F, 0x10, 0x49, 0x1C, 0xC0, 0x8D, 0x48, 0xA0, 0xE8, 0xF5, 0x86, 0xAE, 0xCD, 0x1E, 0xD5, 0x08, 0x2E, 0xDC, 0xB0, 0xEF, 0x83, 0x86, 0x1E, 0x1C, 0x5A, 0xFE, 0xE7, 0x7E, 0x20, 0xE2, 0x8B, 0x7F, 0x34, 0xDA, 0xD2, 0x4B, 0xDB, 0x33, 0x7E, 0x6C, 0x47, 0x54, 0x88, 0x01, 0xBC, 0x80, 0xFE, 0x21, 0x1E, 0x45, 0xA2, 0xB2, 0xB5, 0x72, 0xC1, 0x76, 0x5B, 0xFA, 0xD9, 0xE2, 0x78, 0xE6, 0xDB, 0xF4, 0x13, 0x8F, 0xCA, 0x7B, 0xD8, 0xEA, 0x03, 0x13, 0xFB, 0xDC, 0x38, 0x03, 0xCF, 0x62, 0x82, 0x7C, 0x17, 0x2D, 0x30, 0xA5, 0x11, 0x09, 0xF3, 0xFA, 0x01, 0x66, 0x68, 0xFA, 0x4D, 0x69, 0xF4, 0x6A, 0x01, 0x10, 0x75, 0xAF, 0xA0, 0xAD, 0xCF, 0x0A, 0xDA, 0xE6, 0x4F, 0x6A, 0xD6, 0x68, 0x3F, 0x1B, 0xB4, 0xCF, 0xFC, 0x6E, 0xF5, 0xAA, 0xF9, 0xDD, 0xCE, 0x27, 0xD0, 0x28, 0x35, 0x66, 0xE8, 0x4A, 0x6B, 0x64, 0x8C, 0x86, 0x12, 0x91, 0xD9, 0xBF, 0xB7, 0xF3, 0x09, 0x38, 0x0D, 0x58, 0xF7, 0x61, 0xFD, 0x86, 0x0D, 0x00, 0x4E, 0x01, 0xE6, 0x80, 0x37, 0xD0, 0xDB, 0x8A, 0xBB, 0xC2, 0xA1, 0x9B, 0xE7, 0xD8, 0xA2, 0x66, 0x37, 0xEC, 0x22, 0x0C, 0x0E, 0x53, 0x77, 0x0F, 0x35, 0x90, 0x44, 0x28, 0xC1, 0x54, 0xCF, 0x1A, 0xA4, 0x85, 0xC7, 0x1C, 0x9D, 0x58, 0xE3, 0x9C, 0xBF, 0x9F, 0x3B, 0xD3, 0x28, 0x09, 0xA4, 0xDC, 0x9D, 0xA0, 0xE1, 0x40, 0x19, 0xD0, 0x4A, 0x14, 0xDD, 0xB9, 0x03, 0xC8, 0x00, 0xD6, 0xC0, 0x9F, 0xCD, 0x92, 0x7B, 0x28, 0x14, 0xFF, 0xBE, 0x9E, 0xAB, 0xE0, 0xE9, 0x62, 0xE8, 0x55, 0xE9, 0xE6, 0x39, 0x83, 0x64, 0xAB, 0xF5, 0x5C, 0x39, 0xDB, 0xF8, 0x86, 0x03, 0xF2, 0x19, 0xB9, 0xD8, 0x46, 0x84, 0x06, 0x64, 0x3E, 0x57, 0xE7, 0x06, 0xA3, 0x45, 0x13, 0x4E, 0xF3, 0x41, 0xAB, 0x0D, 0x74, 0xE9, 0xD6, 0x5F, 0x3A, 0xA9, 0xF1, 0x1C, 0x49, 0x7E, 0xB5, 0x2A, 0xE2, 0x41, 0x47, 0x57, 0x22, 0xBF, 0xCB, 0xE1, 0x23, 0xB9, 0xC5, 0xB3, 0x00, 0x6A, 0x5B, 0x0F, 0x12, 0xB0, 0x06, 0x46, 0x98, 0x04, 0x17, 0x3E, 0xA0, 0x0B, 0xFE, 0xB1, 0x1B, 0xC8, 0x00, 0x82, 0xA8, 0x1F, 0x18, 0x97, 0xC3, 0x68, 0x85, 0x3E, 0xBB, 0xA7, 0xA3, 0x1B, 0x79, 0xA7, 0xD4, 0x84, 0x8A, 0x17, 0x7F, 0x59, 0x91, 0x88, 0xFC, 0xE7, 0x17, 0x23, 0xC4, 0x69, 0xBD, 0xDA, 0x1F, 0xE5, 0x7E, 0xD0, 0x74, 0xC7, 0x9D, 0x94, 0x7E, 0x6A, 0x01, 0x3A, 0x80, 0x27, 0xB0, 0x8D, 0xF2, 0x41, 0x1F, 0x16, 0x66, 0xDD, 0x63, 0x4E, 0x8B, 0xA7, 0xF2, 0x56, 0x4D, 0xCE, 0xA3, 0x9F, 0xB1, 0x19, 0x58, 0x0B, 0xDE, 0x7D, 0x72, 0xF7, 0x0C, 0x68, 0x12, 0x87, 0x28, 0x40, 0x04, 0x38, 0x09, 0x48, 0x03, 0xAA, 0x80, 0x37, 0x30, 0xDB, 0x3D, 0x79, 0x80, 0x6A, 0xA0, 0xF7, 0x53, 0x02, 0x19, 0x44, 0xBE, 0x75, 0xC0, 0xF3, 0x5E, 0x9D, 0x0D, 0x7D, 0x20, 0x7F, 0xDD, 0x0D, 0x45, 0x79, 0xEE, 0x9D, 0xCD, 0x76, 0x57, 0x04, 0x1A, 0x2E, 0xBB, 0x52, 0xF2, 0x5D, 0x8A, 0x2D, 0x05, 0x3C, 0x3A, 0x07, 0x2B, 0xAD, 0x51, 0xB5, 0x65, 0x72, 0xDE, 0x02, 0x0A, 0xF8, 0x00, 0xB3, 0x3A, 0xBE, 0xAC, 0x11, 0xEF, 0xB4, 0xDC, 0x4A, 0xF3, 0x35, 0xFF, 0x29, 0x48, 0xCB, 0xD3, 0x74, 0xCD, 0xFB, 0xB0, 0xF9, 0x28, 0xD6, 0xC0, 0x2E, 0xEF, 0x06, 0x3B, 0x11, 0xC0, 0x06, 0x28, 0x01, 0x72, 0x3F, 0x29, 0x30, 0x87, 0x18, 0xFE, 0x9F, 0x37, 0xD0, 0xFC, 0xFF, 0x69, 0x03, 0x64, 0x11, 0x43, 0x18, 0x21, 0x40, 0x1D, 0x00, 0xBA, 0x3B, 0xC8, 0xEE, 0xD3, 0x66, 0x03, 0x35, 0xD5, 0x23, 0xDC, 0x30, 0x71, 0xED, 0xD8, 0x3A, 0xCD, 0x09, 0x50, 0x97, 0x46, 0xFF, 0x52, 0x3B, 0xAC, 0x8B, 0xB0, 0xD3, 0xEA, 0x2B, 0xFE, 0x72, 0xFE, 0x31, 0x7A, 0xA7, 0x84, 0x09, 0xE1, 0xF7, 0xCB, 0x79, 0x36, 0x48, 0xDF, 0xDD, 0x95, 0xF2, 0xB6, 0x00, 0xDA, 0xF9, 0xDB, 0x63, 0x4D, 0x48, 0x6F, 0x0F, 0xEE, 0x3D, 0x65, 0xB7, 0x4D, 0x58, 0xEB, 0xB4, 0xEE, 0x6A, 0x94, 0x92, 0x0D, 0x06, 0xE8, 0xE9, 0x05, 0x1B, 0x57, 0xB6, 0x69, 0x77, 0xE7, 0x0F, 0x12, 0xE8, 0xF5, 0xBC, 0x12, 0xE8, 0x21, 0x1A, 0x28, 0xF9, 0x47, 0xD2, 0xDB, 0x39, 0xC5, 0x20, 0x7B, 0x75, 0xBE, 0x9E, 0x05, 0x96, 0x6B, 0xF6, 0x1B, 0x0C, 0xA8, 0x6B, 0x72, 0xB1, 0x7B, 0xA3, 0x1D, 0x80, 0x5D, 0xF0, 0x9D, 0xF3, 0x8E, 0xC6, 0x4E, 0x7C, 0x22, 0x28, 0xB7, 0x7B, 0xEE, 0x7A, 0xEC, 0x73, 0xB0, 0x05, 0xE0, 0x02, 0xE0, 0xBB, 0xDC, 0x34, 0xF9, 0x26, 0x6B, 0xB7, 0xEF, 0xDD, 0x1F, 0xB7, 0x4A, 0x6C, 0xEF, 0x4C, 0x20, 0x1D, 0xE8, 0x7A, 0x97, 0xF7, 0x17, 0x5F, 0xA1, 0x2D, 0xC8, 0x31, 0x3C, 0x4A, 0xE5, 0xA5, 0x50, 0xF4, 0x68, 0xE7, 0x51, 0x7D, 0x69, 0x1E, 0xF5, 0xB9, 0xC9, 0x5A, 0x22, 0x1D, 0x68, 0x05, 0xA6, 0xE9, 0x99, 0x08, 0xE0, 0x0A, 0x94, 0x03, 0xB3, 0x8B, 0xF0, 0x1E, 0xA3, 0x09, 0x5A, 0x78, 0x4C, 0x29, 0x31, 0x2D, 0x10, 0x0F, 0xB0, 0xBC, 0x3A, 0x48, 0xDB, 0x1D, 0x31, 0x81, 0xFC, 0x6E, 0xD7, 0xB6, 0x8A, 0x6B, 0xDF, 0xC5, 0x00, 0xBE, 0xD9, 0xC7, 0x79, 0x07, 0x38, 0xF3, 0xEF, 0x60, 0x4B, 0x40, 0x0C, 0xF0, 0x00, 0x66, 0xA5, 0x24, 0x9E, 0xF1, 0x1E, 0x96, 0x2D, 0x37, 0x1E, 0x5A, 0x61, 0xC1, 0x67, 0x09, 0xFF, 0x00, 0x42, 0x97, 0x22, 0x0B, 0xD0, 0x7E, 0x9B, 0xF0, 0x9C, 0x0D, 0x07, 0xC2, 0x9E, 0x58, 0x3A, 0x18, 0xC5, 0x3F, 0x16, 0xDF, 0xFF, 0x5A, 0x51, 0x4D, 0xAA, 0x8C, 0x35, 0xB7, 0xB1, 0xBE, 0xEF, 0x9C, 0x10, 0x6A, 0xC4, 0x01, 0x64, 0x00, 0xCD, 0xBB, 0x01, 0xE4, 0xC4, 0xDA, 0x6C, 0x8F, 0x7F, 0xBA, 0xA2, 0x69, 0xFF, 0x4B, 0x28, 0xE5, 0xBD, 0xF1, 0x3B, 0x9A, 0xAF, 0xD2, 0xA0, 0xDA, 0x27, 0x01, 0xF5, 0x26, 0xBD, 0xD3, 0x8E, 0xEF, 0x8E, 0x10, 0x9A, 0x40, 0x99, 0x92, 0xC6, 0xEB, 0xC1, 0x24, 0x2B, 0xD1, 0x80, 0x17, 0xB0, 0x9A, 0x4A, 0xB3, 0x23, 0xBB, 0xBB, 0x56, 0x99, 0xC6, 0x32, 0xBA, 0xD3, 0xB9, 0x47, 0x75, 0x02, 0x13, 0x3B, 0xDD, 0x03, 0xC4, 0x7A, 0x55, 0x18, 0x4A, 0x07, 0x90, 0xC7, 0x7F, 0xCF, 0x29, 0x28, 0x16, 0x22, 0xDF, 0xB8, 0x5B, 0x09, 0x3E, 0x1D, 0xA4, 0xDD, 0x77, 0x09, 0x3D, 0x1C, 0xC8, 0x02, 0xAA, 0x29, 0x05, 0xF6, 0x69, 0xCC, 0x8D, 0x06, 0x5A, 0xD7, 0x66, 0xF6, 0xAE, 0x41, 0xED, 0xEC, 0xC0, 0x09, 0x9A, 0xFB, 0x9C, 0xED, 0xEE, 0x0D, 0xFB, 0x41, 0x23, 0xB8, 0x58, 0xCD, 0xFF, 0xA7, 0x8F, 0xB1, 0xDC, 0x80, 0x94, 0xD7, 0x83, 0x1D, 0x7C, 0xC7, 0xA8, 0x08, 0xD8, 0x35, 0x7F, 0xC7, 0x00, 0x3F, 0xC0, 0x34, 0xAF, 0x86, 0x60, 0x83, 0xD2, 0x6E, 0x9D, 0x66, 0xB5, 0x7B, 0x5B, 0x52, 0xE2, 0x07, 0x94, 0xDA, 0xD0, 0x10, 0xB1, 0x28, 0xA0, 0x82, 0x23, 0x38, 0xBD, 0x35, 0x48, 0x3E, 0x36, 0x94, 0x8E, 0x90, 0xDD, 0xD0, 0xD8, 0xB7, 0x08, 0x6B, 0x3D, 0xAA, 0x84, 0x40, 0xF5, 0xAE, 0x69, 0x20, 0x9A, 0x98, 0xFB, 0x93, 0x0A, 0xE0, 0x0A, 0x98, 0x03, 0x61, 0x6B, 0x33, 0xA7, 0x79, 0xE0, 0x5B, 0x7B, 0xF8, 0xEB, 0xA2, 0xD5, 0xE9, 0xC4, 0x78, 0x0D, 0x57, 0x66, 0xB7, 0x26, 0xA6, 0x73, 0xFC, 0x16, 0x35, 0xCC, 0xCF, 0xD4, 0xBA, 0xDB, 0x47, 0x2B, 0x27, 0x89, 0x00, 0xAA, 0x81, 0xD1, 0x7B, 0xD6, 0x67, 0x2E, 0xC1, 0xAB, 0x5D, 0xDD, 0xAF, 0x78, 0x7A, 0xB9, 0xB5, 0x1C, 0x48, 0x03, 0x62, 0x80, 0xDD, 0x34, 0xB0, 0x59, 0xE4, 0x38, 0x6F, 0xB3, 0xCC, 0xEA, 0x49, 0x50, 0x3E, 0x23, 0xE5, 0x79, 0x08, 0x3B, 0x61, 0xE5, 0xB0, 0xBB, 0x82, 0x3E, 0xC9, 0xE0, 0xAA, 0x81, 0xE1, 0x11, 0x26, 0x0A, 0x98, 0x00, 0x31, 0xC0, 0xE4, 0xDD, 0x33, 0xE3, 0x67, 0x8D, 0x16, 0x57, 0xCA, 0x2C, 0xCE, 0x37, 0x52, 0x5F, 0x15, 0x95, 0x60, 0x4B, 0x8A, 0x41, 0x3A, 0xA9, 0x82, 0x61, 0x26, 0x0E, 0x34, 0xBF, 0x73, 0x8F, 0xA9, 0x9F, 0x40, 0xBD, 0x3F, 0x70, 0xC0, 0xF4, 0x1E, 0x61, 0x8F, 0x2D, 0x3E, 0x39, 0x53, 0xD8, 0x3B, 0xF3, 0x2C, 0x2B, 0x55, 0xE8, 0x40, 0x1B, 0xB0, 0xBB, 0x9C, 0xCF, 0x00, 0xFE, 0xA8, 0x84, 0x70, 0x72, 0x87, 0x67, 0x9E, 0xC7, 0x5F, 0xEB, 0x54, 0x71, 0xA9, 0x65, 0xFB, 0x25, 0x9B, 0x89, 0x93, 0x7A, 0xDF, 0xD1, 0x06, 0x46, 0x99, 0x2A, 0x0B, 0xC0, 0x13, 0x48, 0x03, 0xB6, 0x25, 0x5E, 0x1B, 0xF0, 0x03, 0xA4, 0xAD, 0xCD, 0xF6, 0x3D, 0xDC, 0x56, 0x6A, 0x7B, 0x67, 0x62, 0x6D, 0x47, 0x3D, 0x94, 0x8D, 0x91, 0xA7, 0xF2, 0xF7, 0x68, 0xA4, 0xE6, 0x9B, 0xB0, 0x9D, 0x3C, 0x6B, 0xB4, 0xCF, 0xD0, 0xFA, 0xC7, 0x4C, 0x12, 0x44, 0x01, 0xD6, 0x77, 0x92, 0xA3, 0x2E, 0x99, 0x17, 0xA9, 0xA7, 0xCF, 0xC0, 0x77, 0xFF, 0xBA, 0x03, 0x9D, 0xC0, 0xEC, 0x5C, 0x70, 0x00, 0xAE, 0x7F, 0xBB, 0x26, 0x9D, 0xD3, 0xD4, 0xCE, 0x54, 0x62, 0xB0, 0xA4, 0x9C, 0x49, 0x57, 0x4D, 0xFE, 0xF2, 0xDA, 0xCA, 0xAB, 0xA1, 0x81, 0x3E, 0xBB, 0x96, 0x16, 0xB0, 0x01, 0x9C, 0x08, 0x62, 0xEB, 0x53, 0x47, 0x08, 0x03, 0xA4, 0xD7, 0x68, 0x75, 0x69, 0x7D, 0x89, 0xD6, 0xF7, 0x41, 0x63, 0xB4, 0x59, 0x08, 0x09, 0x50, 0xE2, 0xB3, 0x38, 0x75, 0xB5, 0xA4, 0x35, 0x60, 0x1F, 0x69, 0xDB, 0x8E, 0x4F, 0xF7, 0xBB, 0x12, 0x05, 0x6C, 0xFD, 0xFD, 0xE8, 0x3B, 0x4C, 0x26, 0xE7, 0x51, 0x09, 0x2A, 0xDD, 0x6C, 0xDA, 0x3B, 0xDC, 0xF5, 0x8B, 0xF7, 0x80, 0x18, 0x00, 0x17, 0x85, 0x6D, 0x17, 0x32, 0x63, 0x9D, 0x79, 0xC7, 0xA4, 0x60, 0x25, 0xE5, 0xF9, 0x16, 0x3F, 0xAC, 0x50, 0x0E, 0xFD, 0xDA, 0x39, 0x7C, 0x98, 0x84, 0xF8, 0x85, 0xFB, 0x80, 0x05, 0x10, 0x7E, 0xEF, 0xAD, 0x39, 0x0A, 0x58, 0x02, 0xA1, 0xDF, 0x5B, 0xA0, 0xFF, 0x6C, 0xC6, 0x24, 0x47, 0x0D, 0x76, 0x37, 0xBF, 0x19, 0xA1, 0x16, 0xC3, 0x41, 0x91, 0xF5, 0x73, 0x41, 0x35, 0x9B, 0x1B, 0xC9, 0x6E, 0x9B, 0xED, 0xB0, 0xF5, 0x96, 0x2E, 0x67, 0x2D, 0x61, 0x80, 0x39, 0xA0, 0x09, 0xB8, 0x02, 0xB9, 0x5B, 0x52, 0xE2, 0xCD, 0xEC, 0x3B, 0xBB, 0xA3, 0x76, 0x37, 0x07, 0x9A, 0x40, 0x60, 0x17, 0xBD, 0x57, 0x7B, 0x68, 0x02, 0xDB, 0xAF, 0x2E, 0xBB, 0xEC, 0x79, 0x37, 0x64, 0x27, 0x03, 0x19, 0x3A, 0x0F, 0x26, 0xB0, 0x59, 0xB1, 0xF7, 0x40, 0x68, 0xB3, 0xA8, 0x7B, 0x53, 0x94, 0xF8, 0x67, 0x45, 0x54, 0x00, 0xA5, 0xB4, 0x99, 0x01, 0x46, 0x84, 0x00, 0xED, 0x6B, 0xB3, 0xB9, 0xC4, 0x45, 0x65, 0xBE, 0x19, 0xA1, 0x1D, 0x50, 0x1E, 0xA4, 0xDD, 0x25, 0xE1, 0xD2, 0xAB, 0x5E, 0x2F, 0xE7, 0x5D, 0x18, 0x78, 0x37, 0xC7, 0xDA, 0x86, 0xE6, 0x84, 0x03, 0x47, 0xF6, 0xD3, 0xA7, 0x31, 0x59, 0xDE, 0x9A, 0xD5, 0xEA, 0x57, 0xE9, 0x79, 0xA6, 0xD0, 0x67, 0x00, 0x0B, 0x40, 0x1C, 0x88, 0x03, 0x14, 0xEF, 0x04, 0x65, 0xF0, 0x60, 0xB4, 0xB2, 0x31, 0x4E, 0xE4, 0xEB, 0xC8, 0x27, 0x4C, 0x61, 0xFA, 0x46, 0xCC, 0x8B, 0xFB, 0x54, 0x56, 0x01, 0xF8, 0x5E, 0xAF, 0x65, 0x09, 0x44, 0x03, 0x95, 0x9F, 0x07, 0xCD, 0x89, 0x02, 0x9E, 0x34, 0x9A, 0xF3, 0xFA, 0x37, 0xFB, 0x16, 0x06, 0x6E, 0xB7, 0xD6, 0x02, 0x33, 0x57, 0x39, 0xBF, 0x54, 0x3E, 0x63, 0x81, 0xD2, 0x4F, 0xBF, 0xA8, 0xCE, 0x2D, 0xF8, 0xD2, 0xC9, 0xF7, 0x91, 0xB0, 0xFE, 0xBC, 0x96, 0x09, 0x3C, 0xEA, 0xC0, 0xFD, 0x78, 0x1F, 0x1C, 0xD2, 0x1C, 0xDE, 0x7D, 0xB1, 0x6E, 0xCE, 0xBB, 0x16, 0x4A, 0x1F, 0xA7, 0x75, 0xF5, 0xF4, 0x86, 0xCD, 0xB2, 0x23, 0x40, 0x12, 0x41, 0xC8, 0x70, 0x50, 0xB1, 0x57, 0x5D, 0x94, 0x08, 0x40, 0x0B, 0x68, 0xA5, 0x47, 0x43, 0xCC, 0x01, 0xBA, 0x81, 0x3A, 0x80, 0x27, 0x60, 0x44, 0xB0, 0x42, 0xE3, 0x67, 0x8D, 0x26, 0x1C, 0x1F, 0x64, 0x5D, 0x72, 0xBE, 0x46, 0xDB, 0x6E, 0x79, 0x45, 0x22, 0xAB, 0x1B, 0x5A, 0xA1, 0xDA, 0xBB, 0x58, 0x6B, 0x5B, 0xE1, 0xEF, 0x23, 0x2D, 0xEE, 0x23, 0xED, 0x9B, 0xDD, 0x0E, 0x03, 0xA6, 0x6F, 0x95, 0x1C, 0x59, 0x97, 0x6D, 0x57, 0xDB, 0xEE, 0xA3, 0xBD, 0x29, 0x8C, 0x91, 0x37, 0x45, 0x7F, 0x00, 0xA4, 0x12, 0xDF, 0xEE, 0x5A, 0xBC, 0xC8, 0xD4, 0x62, 0x65, 0xEB, 0xD3, 0x25, 0x1A, 0x57, 0xF4, 0x37, 0xD0, 0x06, 0xFE, 0x43, 0xEE, 0xDE, 0xC0, 0x01, 0x92, 0x15, 0x62, 0x17, 0xA0, 0x8A, 0x08, 0x20, 0x0F, 0xE0, 0x01, 0x58, 0x01, 0x3B, 0xF2, 0x6D, 0xB6, 0x46, 0xD3, 0xB5, 0xCF, 0x55, 0x4D, 0x89, 0xD6, 0x6B, 0x29, 0xD9, 0xD4, 0x50, 0x59, 0xD3, 0xE8, 0x99, 0x62, 0xED, 0xFA, 0x1A, 0x4B, 0x80, 0xB4, 0x37, 0x1A, 0xC7, 0x91, 0x7B, 0x2F, 0xA6, 0x74, 0x07, 0xB2, 0x68, 0x9E, 0x06, 0x46, 0x57, 0xC2, 0x9B, 0xD1, 0x26, 0x5B, 0x83, 0x36, 0xD1, 0x53, 0x54, 0xAE, 0x37, 0x16, 0xDC, 0xCA, 0x29, 0xB7, 0x4D, 0x38, 0x6B, 0x96, 0x87, 0x2D, 0x53, 0xA5, 0x3C, 0xAF, 0x28, 0xDA, 0x25, 0x02, 0xE4, 0xB9, 0xAB, 0x70, 0x4E, 0xAC, 0x17, 0x71, 0x1C, 0x88, 0x03, 0x74, 0xF1, 0x45, 0xFC, 0x8C, 0xE7, 0xA9, 0x01, 0xDE, 0xF7, 0x26, 0xF1, 0x13, 0x80, 0xEB, 0xDA, 0xCC, 0xBE, 0x36, 0xFB, 0x3E, 0x68, 0xB8, 0x87, 0xDB, 0x10, 0xA9, 0xB9, 0xFC, 0x42, 0xC9, 0xF8, 0xAD, 0x91, 0x7D, 0x12, 0xB5, 0x4A, 0xB8, 0xDC, 0x4D, 0x7C, 0xA3, 0xF7, 0x03, 0xE6, 0x09, 0xC0, 0xAC, 0xC8, 0xC5, 0xDF, 0xC2, 0x42, 0x5B, 0xDC, 0x7C, 0xBA, 0x1B, 0x77, 0x8B, 0xF0, 0xE1, 0x15, 0x3F, 0xB0, 0x59, 0x6F, 0x3C, 0x24, 0x40, 0xFE, 0x90, 0x8C, 0x0C, 0x9B, 0x3F, 0xE1, 0x63, 0x33, 0xA8, 0xF6, 0xE1, 0xB8, 0x0A, 0x20, 0x9D, 0x56, 0x3A, 0x9F, 0x6E, 0x0C, 0x01, 0xC6, 0x69, 0x9E, 0x4F, 0x84, 0xE0, 0x87, 0x68, 0xA0, 0xE4, 0x33, 0xB6, 0x08, 0xBC, 0x2F, 0xA7, 0xFF, 0xD3, 0x66, 0x10, 0x4B, 0x15, 0x2C, 0x58, 0x51, 0x33, 0x1C, 0x14, 0xAE, 0xDC, 0xFC, 0x61, 0x57, 0xEA, 0xF1, 0x9B, 0x11, 0xDA, 0xA5, 0xEB, 0x9F, 0x81, 0x31, 0x21, 0x4C, 0x80, 0xDE, 0x55, 0xC6, 0xE7, 0xCD, 0x4E, 0xCA, 0xEA, 0x44, 0xFD, 0x5D, 0x8F, 0x7D, 0xE5, 0x64, 0x76, 0xE8, 0xF9, 0x37, 0x34, 0x07, 0x68, 0x03, 0xDB, 0x7E, 0x21, 0xC5, 0x57, 0x66, 0xD5, 0xB6, 0x0B, 0x88, 0x01, 0x26, 0x3F, 0xAE, 0xBD, 0x02, 0x5D, 0xF7, 0xB6, 0xFE, 0x54, 0xA0, 0x1C, 0x68, 0x36, 0xC0, 0x1F, 0x05, 0xD4, 0x81, 0x88, 0xBB, 0x98, 0xF2, 0x04, 0xEA, 0x9B, 0x73, 0xDC, 0x35, 0x0B, 0xFA, 0xDD, 0x48, 0xC6, 0xB0, 0xCF, 0xF6, 0x2C, 0x10, 0x28, 0x58, 0xF9, 0xB5, 0x1C, 0x44, 0xF4, 0xAE, 0xA5, 0xC4, 0xD6, 0x52, 0xE4, 0x73, 0x9E, 0x11, 0x21, 0x9F, 0xF3, 0x2C, 0x99, 0xCA, 0xD5, 0xB7, 0xEE, 0xA9, 0x41, 0x2F, 0xB5, 0x9E, 0x11, 0x5F, 0xA3, 0x95, 0x0E, 0x85, 0x22, 0x44, 0x00, 0x35, 0x60, 0x35, 0x68, 0xF3, 0x71, 0x4F, 0x99, 0x26, 0xB4, 0xF7, 0x51, 0xC4, 0x05, 0x8A, 0x57, 0xB4, 0x80, 0x91, 0x75, 0x29, 0xEE, 0x01, 0x4E, 0x6F, 0x20, 0x06, 0xC8, 0xFA, 0x04, 0xA4, 0x02, 0x98, 0x02, 0x21, 0x40, 0xD5, 0xDA, 0x2C, 0xAF, 0x2C, 0x9A, 0x4B, 0x7E, 0x6D, 0xC6, 0x5C, 0xDC, 0x20, 0x3D, 0x8C, 0x7E, 0xB4, 0x71, 0xF4, 0x72, 0x8F, 0xAE, 0x9B, 0x01, 0xD8, 0xBE, 0x9B, 0xE7, 0x73, 0x71, 0x7E, 0x22, 0x26, 0xF7, 0x4F, 0xFD, 0x69, 0xDE, 0x9C, 0x11, 0x42, 0xFA, 0x5B, 0x8B, 0x50, 0xAF, 0x41, 0x2F, 0xFC, 0x7F, 0xC3, 0x0B, 0x6B, 0x40, 0xB1, 0xC3, 0x4E, 0xE9, 0x3C, 0x6E, 0x26, 0x28, 0xFA, 0x5D, 0x37, 0xC9, 0x55, 0xDB, 0xED, 0xF4, 0x6E, 0x39, 0x59, 0xD8, 0x43, 0x4B, 0x20, 0xE5, 0xC8, 0x2E, 0xAA, 0x7B, 0x8B, 0xA7, 0x17, 0x90, 0x09, 0xB4, 0xDE, 0x5B, 0x3C, 0x7D, 0x80, 0xB2, 0xFF, 0x57, 0xA8, 0x9D, 0x23, 0xBD, 0xAE, 0x33, 0x67, 0x1C, 0xFF, 0x52, 0x4F, 0x7B, 0xD0, 0x12, 0xD8, 0x33, 0x3A, 0xF3, 0x98, 0x3A, 0x72, 0xEE, 0xFD, 0xEF, 0xC2, 0xF8, 0x3F, 0x2C, 0x95, 0x8E, 0xE7, 0xBA, 0xE2, 0xAF, 0x70, 0x40, 0xA8, 0x81, 0x26, 0xF9, 0x16, 0xD9, 0xD4, 0xFD, 0x1E, 0xC8, 0xF7, 0x98, 0xCD, 0xE7, 0x79, 0xBE, 0x9F, 0x52, 0x6D, 0xCA, 0x65, 0x98, 0x9F, 0x8E, 0x0B, 0x1B, 0xA5, 0x2F, 0x47, 0x44, 0x6F, 0xB8, 0xAB, 0xF5, 0xD3, 0x82, 0x71, 0x7E, 0xD3, 0x79, 0x06, 0xB2, 0xC1, 0xC7, 0x75, 0x9F, 0x18, 0xBD, 0x48, 0x5E, 0xDE, 0x90, 0x3C, 0x43, 0x06, 0x16, 0x44, 0xAB, 0x42, 0x0F, 0xB4, 0xC5, 0xC7, 0xD1, 0x0C, 0x3D, 0x65, 0x61, 0x3B, 0x4E, 0xE0, 0xB6, 0x22, 0x18, 0xFA, 0x62, 0x1E, 0xAC, 0xC6, 0xC3, 0x24, 0x66, 0x18, 0x8D, 0x59, 0x72, 0xB1, 0x1A, 0x27, 0x90, 0x30, 0xCB, 0xBA, 0x6C, 0x95, 0xF0, 0xF9, 0x25, 0x6C, 0xEF, 0x9D, 0x96, 0xFB, 0x6C, 0x70, 0x2E, 0xCE, 0x4D, 0xF8, 0x21, 0xE3, 0xE1, 0x8F, 0xA9, 0xF4, 0x82, 0xCF, 0x3F, 0x99, 0x24, 0x43, 0x49, 0x76, 0xF4, 0xD3, 0x54, 0x70, 0x8D, 0x1F, 0xDD, 0x64, 0x39, 0x57, 0x71, 0xE5, 0x47, 0x09, 0xA2, 0xE4, 0x32, 0x6E, 0x0F, 0x8E, 0x61, 0x2F, 0x56, 0x62, 0x07, 0x4E, 0xCA, 0x7E, 0xEF, 0xEE, 0x68, 0x83, 0x21, 0xCB, 0xB0, 0x1B, 0x8F, 0x5C, 0x27, 0xBE, 0x25, 0xA6, 0x6C, 0x39, 0x8D, 0x47, 0x1C, 0x16, 0xF2, 0x14, 0xFA, 0xC1, 0x68, 0xCC, 0xA3, 0x8C, 0xF7, 0x8F, 0x8C, 0x8B, 0x8B, 0xCD, 0x78, 0x94, 0x55, 0x19, 0x65, 0xE4, 0xE9, 0xDC, 0xC7, 0xFD, 0xB6, 0xB8, 0xCB, 0x33, 0x47, 0x2C, 0x73, 0xD4, 0xD1, 0xDC, 0xC1, 0x29, 0x6B, 0x9E, 0x48, 0xB9, 0x40, 0x8F, 0xBD, 0x3F, 0x38, 0x13, 0xE1, 0x80, 0x31, 0xAE, 0x13, 0xF3, 0xD5, 0x30, 0x42, 0x0E, 0xE6, 0x91, 0x83, 0xD3, 0x78, 0x42, 0x2B, 0x30, 0xB4, 0xC4, 0x80, 0x1C, 0x2C, 0xC7, 0x09, 0xDC, 0xC3, 0x74, 0xEE, 0x18, 0xA2, 0x31, 0x65, 0x1D, 0x3C, 0x26, 0x59, 0xDC, 0x63, 0xE4, 0x5B, 0xCF, 0x2F, 0x5F, 0x7F, 0xDF, 0xB6, 0xF2, 0x47, 0x78, 0x78, 0x8C, 0x27, 0xCB, 0x34, 0xEE, 0xC1, 0xB4, 0xEC, 0xE8, 0x29, 0xA5, 0x28, 0xC9, 0x59, 0x92, 0x33, 0x13, 0xAF, 0xFA, 0x07, 0xF3, 0xF6, 0x24, 0x7B, 0x8B, 0xD7, 0xA1, 0xEC, 0xED, 0xC2, 0x27, 0x08, 0xD7, 0x89, 0x59, 0x32, 0x30, 0x5E, 0x17, 0xF3, 0x0F, 0x67, 0xF0, 0x8D, 0xFF, 0x18, 0x9A, 0xA3, 0x0F, 0xC6, 0x62, 0x0E, 0x76, 0xE3, 0x19, 0x66, 0x7C, 0x0E, 0xDA, 0xA0, 0x17, 0x86, 0x63, 0x06, 0xF6, 0x91, 0x89, 0x27, 0x94, 0xB5, 0xFD, 0x91, 0x75, 0x91, 0xEB, 0xAA, 0x10, 0xA4, 0x52, 0xA4, 0x7A, 0xDF, 0xBD, 0xF8, 0xF9, 0x68, 0xFD, 0xF6, 0x70, 0x52, 0xE2, 0xB6, 0x9B, 0x41, 0x6B, 0xFA, 0xAB, 0x4E, 0xBC, 0xDC, 0xAB, 0x30, 0x3E, 0xD9, 0xA4, 0xCB, 0xCE, 0xC0, 0x58, 0x7C, 0x4A, 0xA5, 0xE6, 0xA2, 0x38, 0x26, 0x07, 0xB7, 0xE4, 0x30, 0xD0, 0xA4, 0x17, 0xC6, 0x62, 0x1E, 0x6C, 0x98, 0xC4, 0xE3, 0xB8, 0x87, 0x99, 0xDC, 0x30, 0x16, 0x73, 0xB0, 0x02, 0xDB, 0x70, 0xE0, 0x2C, 0x6E, 0xA8, 0x9E, 0x75, 0x65, 0xEC, 0xBF, 0x8C, 0xDF, 0xB7, 0x4F, 0xEF, 0x95, 0xCB, 0xFB, 0x04, 0x23, 0xE3, 0xBE, 0x18, 0x69, 0x9F, 0xFD, 0x2C, 0x7F, 0x7D, 0x7E, 0x38, 0x70, 0x49, 0x75, 0xCD, 0x8B, 0x85, 0x49, 0x0C, 0xFD, 0x54, 0xDC, 0x74, 0x9F, 0x44, 0x37, 0xC2, 0x4C, 0x62, 0x06, 0x0A, 0x5F, 0x19, 0xF8, 0x72, 0x64, 0x63, 0x0D, 0x76, 0xE0, 0x14, 0x9E, 0xC0, 0x2D, 0x22, 0x3E, 0x8D, 0x96, 0xE8, 0x8B, 0x29, 0xBB, 0x71, 0xE4, 0x31, 0xE4, 0x48, 0x1A, 0xEB, 0xB1, 0x90, 0x83, 0xD1, 0x4A, 0x37, 0xFE, 0x48, 0xB7, 0x48, 0x72, 0xB9, 0x6E, 0xF5, 0xE2, 0x8B, 0xE7, 0xA5, 0x06, 0x23, 0xE7, 0x99, 0xCF, 0x21, 0x17, 0x2F, 0x62, 0x73, 0x6D, 0xEB, 0x22, 0x70, 0xE4, 0x9B, 0xCD, 0xC4, 0xC1, 0xD3, 0x3D, 0xA6, 0x5E, 0x4F, 0x1D, 0x9C, 0xC0, 0x16, 0x86, 0x95, 0x72, 0xB1, 0x5B, 0x0E, 0x9E, 0x94, 0x07, 0xF7, 0x5D, 0xC6, 0x41, 0x93, 0x21, 0x1A, 0x73, 0xB1, 0x07, 0x8F, 0xE3, 0x8A, 0x66, 0x15, 0x8F, 0xA1, 0x05, 0xFA, 0x62, 0x38, 0x96, 0xD2, 0xCD, 0x5F, 0xBA, 0xA9, 0x24, 0x9B, 0x72, 0xBC, 0xC8, 0x8A, 0x24, 0xF5, 0x50, 0xB9, 0x87, 0x74, 0xED, 0x73, 0x98, 0xDF, 0x9D, 0xCB, 0x23, 0x4C, 0x97, 0x76, 0x28, 0xFA, 0x3D, 0xC7, 0xF0, 0xA4, 0xBA, 0x93, 0x00, 0x5B, 0x58, 0x83, 0x51, 0xE8, 0x2D, 0x13, 0x6D, 0x7F, 0xED, 0x10, 0x86, 0x39, 0x58, 0x86, 0xFD, 0x7A, 0x70, 0x16, 0x0F, 0x2A, 0x30, 0x0F, 0x36, 0xE8, 0x81, 0x71, 0x30, 0x0B, 0x5F, 0x0E, 0x76, 0xE3, 0x31, 0x99, 0x5A, 0x9F, 0x29, 0xE3, 0xFA, 0x65, 0x5C, 0x0F, 0xE9, 0x84, 0x1E, 0x25, 0x78, 0x4D, 0x16, 0xEF, 0xB9, 0x7D, 0xB8, 0xB8, 0x08, 0xD6, 0xC4, 0xB2, 0xD1, 0x59, 0xA6, 0x54, 0xD5, 0x4B, 0xA9, 0x83, 0xB5, 0xF8, 0x0C, 0xFD, 0x6D, 0xE8, 0x4E, 0xAC, 0x6D, 0x9C, 0x23, 0xED, 0x67, 0x0F, 0x8E, 0xCB, 0x91, 0x8B, 0x47, 0xEE, 0xBB, 0x04, 0x97, 0x07, 0x6D, 0xD0, 0x0B, 0xC3, 0x30, 0x1D, 0xAB, 0xB0, 0x07, 0x27, 0xE5, 0xE2, 0x49, 0xDC, 0xD0, 0xAA, 0x12, 0x4D, 0xAC, 0x52, 0xEE, 0x5F, 0xCA, 0xAD, 0xC7, 0xB6, 0xFD, 0x58, 0x93, 0xED, 0xFD, 0xE2, 0xCD, 0xF6, 0xC4, 0xA5, 0x39, 0xC9, 0xA1, 0x1F, 0x8B, 0x87, 0x1D, 0x38, 0x9C, 0x35, 0xF2, 0x3F, 0xD8, 0x60, 0xFA, 0xEA, 0x71, 0xAC, 0xC4, 0x70, 0x14, 0x56, 0xB2, 0x65, 0xCA, 0x83, 0x6E, 0x32, 0x30, 0x5C, 0x16, 0x66, 0xCA, 0xC5, 0x6A, 0xEC, 0x90, 0x07, 0x67, 0x50, 0x73, 0x33, 0xF3, 0x53, 0x72, 0xD1, 0x0A, 0xDD, 0xE5, 0xC1, 0x68, 0xCC, 0x51, 0xBE, 0xF3, 0xCB, 0x77, 0xDE, 0xF7, 0x7C, 0xD0, 0x9F, 0x0F, 0xF7, 0x63, 0x1A, 0x8F, 0xD6, 0xCE, 0x15, 0xC8, 0x0B, 0x13, 0xBA, 0x47, 0xF7, 0x28, 0xC7, 0x5E, 0x4C, 0x69, 0xFA, 0xE6, 0x39, 0xD8, 0x85, 0x22, 0x1D, 0x63, 0xE4, 0x91, 0x83, 0x29, 0x5E, 0x0B, 0xCB, 0x65, 0x61, 0x8B, 0xC2, 0x31, 0x39, 0x78, 0x42, 0x2E, 0xAE, 0x26, 0x7D, 0x06, 0x2D, 0xE4, 0xA0, 0x9B, 0x6C, 0x8C, 0xC0, 0x34, 0x2C, 0x57, 0xBE, 0xE7, 0x8F, 0x7C, 0xEB, 0xC3, 0xFF, 0xAB, 0x0C, 0xF9, 0xE1, 0xFD, 0x3C, 0xB9, 0x0A, 0xFB, 0x28, 0x9D, 0x60, 0x4D, 0x03, 0x4B, 0xC0, 0x65, 0x87, 0x5A, 0xFC, 0xA2, 0x7A, 0x99, 0xBB, 0x15, 0x21, 0xC0, 0x0F, 0xD4, 0x0F, 0x18, 0xF6, 0x1A, 0x38, 0x2C, 0x53, 0xB1, 0x35, 0xEC, 0xA5, 0x12, 0x68, 0x35, 0xAD, 0x61, 0x83, 0x03, 0xCB, 0x56, 0xA0, 0xE3, 0x5E, 0x17, 0x33, 0xE8, 0x8B, 0xAF, 0xF2, 0xD9, 0x5F, 0x3E, 0xE7, 0xF9, 0xF0, 0x3F, 0x38, 0xC2, 0xC2, 0x43, 0x2A, 0x07, 0x82, 0x7C, 0xEC, 0x13, 0x7C, 0xB3, 0x39, 0x0B, 0x73, 0x67, 0xB9, 0x9C, 0xBD, 0x34, 0xA4, 0x5D, 0x6C, 0xF8, 0x6A, 0x13, 0xA4, 0x2E, 0x33, 0x50, 0xFF, 0x9D, 0xC3, 0x66, 0x50, 0x70, 0x2E, 0x1B, 0xD0, 0xD4, 0xB7, 0x0E, 0xB4, 0xDE, 0x90, 0x17, 0xCF, 0x4B, 0xB0, 0x15, 0x68, 0xBE, 0x84, 0x73, 0xA9, 0x04, 0x5A, 0xDD, 0x64, 0xD4, 0xCF, 0x2F, 0xA3, 0x7D, 0x3E, 0xD4, 0x3C, 0x02, 0x28, 0x41, 0xF3, 0xC0, 0x7C, 0x74, 0xEE, 0xB9, 0x59, 0x52, 0x6F, 0xFB, 0x65, 0x44, 0x5E, 0xCA, 0x2E, 0x3E, 0x97, 0x67, 0x54, 0x67, 0xEA, 0xFB, 0xC1, 0x88, 0x20, 0xDD, 0xCB, 0x01, 0x5A, 0xC3, 0x16, 0x90, 0x30, 0x0C, 0x65, 0x0B, 0x68, 0x60, 0xD4, 0x26, 0x1C, 0x22, 0x3A, 0x2C, 0x93, 0x16, 0xB3, 0x18, 0x24, 0xB0, 0x37, 0x0C, 0x98, 0x39, 0x03, 0x56, 0x19, 0xD9, 0x2F, 0x23, 0x8A, 0x39, 0xEE, 0xFF, 0x30, 0xA0, 0x6C, 0xF2, 0x12, 0x7B, 0x59, 0x7A, 0xF4, 0xA8, 0x1F, 0x97, 0x4E, 0x5A, 0x4D, 0x96, 0xF4, 0x19, 0xA7, 0x71, 0xF3, 0x32, 0xE7, 0xD2, 0xC2, 0x2F, 0xB5, 0x30, 0x20, 0xB4, 0xE3, 0xBB, 0x05, 0x14, 0xB0, 0x6F, 0x0C, 0x02, 0xD8, 0x7B, 0xD8, 0x12, 0x08, 0xB1, 0x05, 0x7A, 0x22, 0x33, 0x68, 0x18, 0xCD, 0x0C, 0x7B, 0xF1, 0x50, 0x46, 0x4E, 0x69, 0xF6, 0x84, 0x3E, 0x7A, 0xC9, 0x70, 0x29, 0xAA, 0x8F, 0xF7, 0x80, 0xA6, 0x56, 0xDA, 0xA4, 0xB0, 0x14, 0x69, 0xC3, 0x73, 0xDC, 0x59, 0xC6, 0x54, 0x50, 0x9D, 0x65, 0x63, 0x7D, 0x8E, 0x31, 0xC1, 0x2C, 0x1D, 0x54, 0x4F, 0x47, 0x85, 0x54, 0xD2, 0xAE, 0xA2, 0x3F, 0x96, 0xF6, 0xAA, 0xBF, 0x4C, 0x25, 0x5A, 0xE9, 0xC5, 0x05, 0x93, 0x46, 0x52, 0xFE, 0xAC, 0xD3, 0x2E, 0x82, 0xBF, 0xA5, 0x5C, 0x05, 0xA3, 0xD3, 0x70, 0x4B, 0x71, 0x07, 0xB3, 0x71, 0x15, 0xB7, 0x1C, 0x67, 0xE4, 0x91, 0x86, 0x2D, 0x8E, 0x5C, 0x2A, 0xC8, 0x70, 0x25, 0x1C, 0xFF, 0x4F, 0x8D, 0xF6, 0x1E, 0x4C, 0xE7, 0xEA, 0x54, 0x8D, 0xA6, 0xC7, 0x5D, 0x2A, 0x2D, 0x7A, 0xA8, 0xCE, 0x02, 0x8B, 0x22, 0x4D, 0x75, 0xD5, 0x72, 0x4C, 0x9B, 0x12, 0x9A, 0x38, 0xDE, 0x8C, 0x9C, 0xC2, 0x5C, 0xD9, 0x18, 0x8E, 0x29, 0xEB, 0x35, 0xF0, 0x14, 0xAE, 0xAB, 0x56, 0x0B, 0xF4, 0xC1, 0x0C, 0x6C, 0x31, 0x78, 0x0E, 0x93, 0x98, 0x8C, 0xC5, 0x2C, 0xAC, 0xC4, 0x76, 0x9C, 0xB7, 0x56, 0x8B, 0x9F, 0xDE, 0xCA, 0x39, 0x29, 0xCE, 0x4C, 0x09, 0xBF, 0x6F, 0xAC, 0x8B, 0x74, 0xF5, 0xBC, 0xCB, 0x85, 0xF9, 0xBD, 0xD6, 0x9C, 0x65, 0xDA, 0x35, 0x3F, 0xA1, 0x12, 0xB7, 0x6E, 0x2A, 0x4B, 0xF5, 0x63, 0x07, 0x9F, 0x56, 0xF5, 0xA4, 0x22, 0xEC, 0xAD, 0xF6, 0x9E, 0xC1, 0x70, 0xFA, 0xDD, 0x19, 0xE3, 0x49, 0xC9, 0xD4, 0x8C, 0x51, 0x9D, 0x51, 0x24, 0x5A, 0xBA, 0xCF, 0xD7, 0xFB, 0x54, 0xCA, 0xF9, 0x50, 0xDB, 0xE9, 0x4F, 0x63, 0xCC, 0x2A, 0x5A, 0xAB, 0xB0, 0xAB, 0xC1, 0x1D, 0x62, 0x46, 0xE0, 0x2A, 0xE4, 0x68, 0x09, 0xAF, 0x45, 0xCF, 0x91, 0x25, 0x63, 0x31, 0xB5, 0xD8, 0x48, 0x25, 0x5D, 0x54, 0x68, 0x96, 0x7C, 0xDE, 0xB7, 0xE6, 0x4B, 0xBE, 0xCE, 0xA3, 0x30, 0x49, 0xBB, 0x7E, 0xE0, 0xFE, 0xFE, 0x35, 0x1A, 0xCB, 0x8F, 0x64, 0x99, 0x5C, 0xE0, 0xA6, 0x22, 0x2A, 0xF0, 0x49, 0x16, 0x3B, 0x5A, 0xB8, 0x0F, 0x7B, 0xC3, 0x70, 0x54, 0x80, 0x3D, 0xA5, 0x24, 0x96, 0x91, 0x6B, 0x8C, 0x74, 0x63, 0x9A, 0xA4, 0x84, 0x61, 0x85, 0xA9, 0xC3, 0x99, 0xD4, 0x47, 0x6A, 0x9B, 0xCA, 0x96, 0x26, 0x82, 0x1D, 0xC6, 0x3F, 0x8A, 0x63, 0x07, 0xDB, 0x70, 0x15, 0xAD, 0x15, 0xD8, 0xF0, 0x94, 0x74, 0xAC, 0x46, 0x4F, 0x7C, 0xA4, 0xDD, 0x31, 0x2C, 0x5C, 0x49, 0xF7, 0x87, 0xBC, 0x86, 0x0F, 0x49, 0x93, 0x6A, 0x72, 0x3D, 0x47, 0xAB, 0x52, 0x3B, 0x7B, 0x71, 0x92, 0x7E, 0xFA, 0xBD, 0x6B, 0xEB, 0x91, 0x52, 0x95, 0x96, 0xEB, 0xF8, 0x44, 0xA1, 0xD5, 0xB7, 0x80, 0x4A, 0xCE, 0x47, 0xF2, 0xF4, 0x45, 0x9B, 0x7E, 0x5D, 0xD2, 0x1C, 0xA4, 0x83, 0x76, 0x94, 0x90, 0x72, 0x53, 0xA1, 0x52, 0xCC, 0x75, 0x42, 0xCF, 0xE6, 0x41, 0xBB, 0x92, 0xEE, 0x6C, 0x86, 0x98, 0x62, 0xAD, 0x62, 0xED, 0x5B, 0xBB, 0x39, 0xCE, 0x10, 0x37, 0x0E, 0x73, 0x3B, 0xF4, 0x48, 0xC7, 0xD0, 0xCE, 0x2D, 0xEC, 0xC5, 0xA3, 0xFE, 0xA3, 0x8C, 0x87, 0x02, 0xCD, 0x8D, 0xCF, 0xF3, 0x30, 0xAB, 0x31, 0xA9, 0x93, 0xD7, 0x21, 0x63, 0xB0, 0xA5, 0x95, 0x9F, 0x65, 0x31, 0x3E, 0x44, 0x89, 0xA3, 0x8B, 0xD1, 0x94, 0xD2, 0xC3, 0x30, 0xCA, 0xAB, 0xA6, 0x3F, 0x55, 0xCD, 0xA8, 0xE9, 0xC6, 0xCE, 0xD6, 0xAA, 0x7D, 0xC8, 0xA0, 0x56, 0x03, 0x35, 0xC9, 0x8C, 0x4A, 0x25, 0xCD, 0xF5, 0x3E, 0xD7, 0x3F, 0x8E, 0x54, 0x3C, 0x81, 0x8C, 0x39, 0x9A, 0xCA, 0x55, 0xC3, 0x69, 0x2A, 0x33, 0xCC, 0x64, 0xF2, 0x47, 0x2E, 0x81, 0x13, 0x22, 0xF0, 0x29, 0x7A, 0x1B, 0x7C, 0x51, 0xFB, 0x52, 0xE9, 0x1E, 0x0A, 0x34, 0xD7, 0x47, 0xB5, 0x29, 0xEB, 0x64, 0xAC, 0x8F, 0xD2, 0xED, 0x21, 0x5D, 0xDD, 0x58, 0xF4, 0x10, 0xE2, 0xC9, 0x59, 0xF8, 0xAE, 0x86, 0xC8, 0x6F, 0xCD, 0xA6, 0x9B, 0x6C, 0x04, 0xA7, 0x25, 0xFC, 0xDB, 0xBE, 0x52, 0x3F, 0x7D, 0x17, 0x3C, 0x9C, 0x28, 0xEA, 0xAF, 0x65, 0x8C, 0xAB, 0x18, 0x5C, 0x7E, 0xD6, 0x1F, 0xA6, 0xD7, 0x8D, 0x4D, 0x25, 0xB5, 0x2F, 0x32, 0x24, 0x08, 0xFC, 0x28, 0xCC, 0x93, 0x98, 0x07, 0xE7, 0x2D, 0xC0, 0x0E, 0x21, 0xBD, 0x71, 0x64, 0x2F, 0xC6, 0xB0, 0x77, 0x0D, 0x6B, 0x70, 0xFC, 0x1D, 0x43, 0xC2, 0x9C, 0x70, 0xF2, 0xE4, 0xF3, 0x3C, 0xCC, 0xE8, 0xE4, 0x7A, 0x5B, 0xA1, 0x84, 0x03, 0xEE, 0x64, 0xAA, 0x7D, 0xDE, 0xA2, 0x85, 0xC7, 0x58, 0x16, 0x65, 0xAD, 0x0A, 0xCA, 0xF1, 0xED, 0x29, 0xD5, 0xE9, 0x11, 0x44, 0xE8, 0x43, 0x9B, 0x22, 0x9C, 0xEF, 0x93, 0xFF, 0x0C, 0x5A, 0x32, 0x3E, 0x92, 0x31, 0x8C, 0x4F, 0x22, 0xF8, 0x4D, 0xAE, 0x89, 0xFC, 0x0C, 0xED, 0x47, 0xFD, 0xDB, 0x8A, 0x53, 0x44, 0x8E, 0xF3, 0x2B, 0xFA, 0xE6, 0x8D, 0x59, 0xD8, 0x2A, 0xC2, 0xCA, 0x88, 0xFC, 0x04, 0xED, 0x95, 0x6D, 0x68, 0xCE, 0x98, 0x29, 0x5C, 0xF5, 0xAC, 0x92, 0x1E, 0x55, 0x69, 0xA9, 0xCF, 0xA3, 0x22, 0x2D, 0xF9, 0x41, 0xEB, 0x51, 0x41, 0xA2, 0xEB, 0x99, 0x72, 0x8D, 0x56, 0xF2, 0xC8, 0x16, 0xAA, 0x25, 0xF2, 0xB0, 0xC0, 0xD3, 0xAA, 0xB0, 0x02, 0x8B, 0x8E, 0xD6, 0x57, 0x5F, 0xCD, 0x70, 0x6F, 0x5B, 0x77, 0x36, 0x57, 0x85, 0xEC, 0x94, 0xD2, 0xDF, 0xB2, 0xEC, 0xD1, 0x33, 0xF6, 0xA1, 0x5C, 0x7A, 0x6F, 0xF8, 0xED, 0xB4, 0xA9, 0x53, 0x78, 0xF4, 0x65, 0xC0, 0x61, 0x6C, 0xC4, 0xAF, 0x60, 0x2B, 0xC7, 0xD1, 0xC5, 0x16, 0x45, 0x3C, 0x97, 0xD3, 0xD8, 0x85, 0xC1, 0xCE, 0x39, 0x18, 0x8B, 0xA5, 0xEE, 0x3A, 0x4A, 0xD7, 0x3E, 0xAD, 0x8C, 0x8B, 0x74, 0x99, 0x15, 0x28, 0xD5, 0x28, 0xB2, 0x8D, 0x5C, 0x8D, 0x53, 0xDD, 0x1F, 0x42, 0xD3, 0x9B, 0x87, 0x8C, 0x9F, 0xC0, 0x2E, 0xF4, 0xD0, 0x3A, 0x4D, 0x6B, 0x6E, 0x7C, 0x7B, 0x9E, 0xB7, 0x44, 0xE2, 0x18, 0xF6, 0x92, 0xC4, 0xEA, 0xAB, 0xED, 0x0C, 0x21, 0xD6, 0xAF, 0x5A, 0x59, 0x8E, 0x12, 0x4D, 0xA7, 0x7B, 0xE7, 0xFD, 0xBA, 0x82, 0x0F, 0x6E, 0x10, 0xCA, 0x0D, 0x33, 0x71, 0x9B, 0x88, 0x27, 0x88, 0x1E, 0x83, 0x1E, 0xEA, 0x69, 0x0C, 0xD7, 0x18, 0x9A, 0x8F, 0x16, 0x60, 0xA9, 0x6C, 0x9D, 0xFA, 0xAC, 0xF9, 0x90, 0xED, 0x9D, 0x36, 0x61, 0x40, 0xB9, 0xE6, 0x85, 0x27, 0x3F, 0x72, 0x4D, 0x8E, 0xF4, 0x72, 0x39, 0x52, 0xA3, 0x1D, 0xDC, 0xC6, 0xD6, 0xAA, 0xB7, 0xD1, 0x59, 0xFB, 0xD2, 0x6A, 0x2D, 0xBD, 0x83, 0xE4, 0xF2, 0xEE, 0x0B, 0xA5, 0x64, 0xA4, 0xB4, 0xDC, 0xD5, 0x0E, 0x0B, 0xE4, 0x56, 0x50, 0xE4, 0x77, 0x1B, 0x74, 0xF5, 0x28, 0x88, 0x06, 0x3E, 0x32, 0x07, 0xBB, 0xF0, 0x18, 0x21, 0xFD, 0x10, 0xCC, 0x0C, 0x5B, 0xE6, 0xA0, 0x05, 0x7B, 0xAB, 0xD1, 0x06, 0x23, 0xE8, 0x0F, 0x53, 0xAA, 0x41, 0x69, 0xD6, 0xFA, 0x90, 0x2A, 0x47, 0xE3, 0x4E, 0xA8, 0xD6, 0x50, 0x93, 0x36, 0x0C, 0xE7, 0xD6, 0x78, 0x2C, 0xA7, 0x54, 0xB2, 0x20, 0x19, 0x65, 0xE3, 0xC6, 0x71, 0x39, 0x17, 0xF7, 0x6F, 0x85, 0x45, 0xEB, 0x5B, 0x9A, 0x6A, 0xD6, 0x77, 0xDD, 0xD1, 0x1C, 0x47, 0x63, 0x06, 0xFF, 0xA8, 0xA2, 0x2E, 0x62, 0x26, 0x19, 0xEA, 0x26, 0x43, 0x11, 0x4F, 0x8C, 0x56, 0xB4, 0x4B, 0x0D, 0xC1, 0xE3, 0x72, 0x8A, 0x68, 0xE1, 0xC4, 0x31, 0x68, 0x48, 0xF9, 0x68, 0x21, 0x75, 0xD0, 0x1A, 0x83, 0xF9, 0xBE, 0xF9, 0x25, 0xA5, 0xDA, 0x38, 0x9F, 0x47, 0x35, 0x9B, 0xBF, 0x70, 0x7C, 0x29, 0x07, 0xE2, 0x5B, 0x74, 0x53, 0xAF, 0xE8, 0x6F, 0xB5, 0x28, 0x9C, 0x0E, 0x1B, 0x8D, 0xAC, 0x6F, 0xC5, 0x15, 0x7D, 0x79, 0xE6, 0xD2, 0xC5, 0x51, 0x58, 0xF2, 0x39, 0x9C, 0x1D, 0x63, 0x08, 0x59, 0x0C, 0x97, 0xC3, 0xF1, 0x6F, 0x39, 0x93, 0xFC, 0xD3, 0x42, 0x3B, 0xBE, 0x25, 0x5B, 0x39, 0x91, 0x61, 0x9B, 0x03, 0x3D, 0xA4, 0x4C, 0xC6, 0x4A, 0x36, 0x2F, 0xCA, 0x9F, 0x7D, 0x93, 0x97, 0x38, 0x0C, 0x60, 0xAE, 0x52, 0x3E, 0x45, 0xA1, 0x76, 0x9C, 0x0F, 0xF9, 0xDC, 0xAB, 0x0F, 0x12, 0x9A, 0x54, 0xBE, 0x15, 0x9B, 0xF2, 0xB1, 0xE2, 0x20, 0x73, 0xB8, 0x8D, 0xB5, 0xB3, 0x92, 0xDE, 0x8B, 0xAB, 0x7C, 0x9B, 0x4B, 0xF9, 0xFD, 0xE7, 0xC3, 0x08, 0x67, 0x75, 0x6E, 0xB4, 0x96, 0xBD, 0x87, 0xD3, 0xFD, 0x09, 0xFA, 0x9D, 0xB0, 0x4E, 0xBF, 0xBF, 0xD9, 0x6D, 0x30, 0x5D, 0x92, 0xEC, 0xF9, 0x14, 0x11, 0xFA, 0x62, 0x79, 0x29, 0x02, 0x10, 0xAF, 0xF7, 0x52, 0xEF, 0x3F, 0xBF, 0xF3, 0x46, 0x33, 0x82, 0x83, 0x9C, 0xA1, 0x6C, 0x5A, 0x45, 0xDA, 0x06, 0x9F, 0xDB, 0xA0, 0x88, 0x81, 0xFA, 0xB0, 0x78, 0x0A, 0x35, 0xA5, 0xB3, 0x1F, 0x23, 0xB8, 0x73, 0xA9, 0x24, 0x69, 0x90, 0x70, 0xB2, 0x1E, 0xEE, 0xED, 0x97, 0x9A, 0x8B, 0xC7, 0xE5, 0xA9, 0x8B, 0x76, 0xD6, 0xE5, 0xAD, 0x33, 0xEB, 0xAD, 0x15, 0xBE, 0xF5, 0x5C, 0x5C, 0xB2, 0xE1, 0x6E, 0x27, 0xBE, 0xD9, 0x6D, 0x42, 0xC1, 0xAF, 0xC5, 0x41, 0x08, 0x65, 0xBC, 0x4C, 0xEA, 0x04, 0x3E, 0xDF, 0x1A, 0x35, 0x99, 0xD5, 0x82, 0x21, 0xC5, 0x8E, 0x7B, 0xC1, 0xFD, 0xCB, 0xBF, 0xFE, 0xF3, 0xBF, 0xFF, 0xF3, 0x3F, 0xFC, 0xDB, 0x3F, 0xFC, 0xDD, 0x5F, 0x7F, 0xFF, 0xFB, 0xCB, 0x5F, 0xFE, 0x03, 0xBB, 0x17, 0x80, 0x14, } }; static VipsProfileFallback vips__profile_fallback_p3 = { "p3", 480, { 0x78, 0xDA, 0x7D, 0x90, 0x33, 0xC0, 0x55, 0x01, 0x14, 0xC7, 0x7F, 0xCF, 0xF6, 0xDB, 0xB2, 0x6D, 0xDB, 0xB6, 0xB5, 0x3C, 0x9B, 0xF7, 0xDE, 0xB0, 0x86, 0x25, 0x9B, 0x5B, 0x4B, 0xB6, 0x9B, 0x7A, 0x63, 0x5B, 0x6E, 0x8B, 0x7B, 0x36, 0x2F, 0x3E, 0xFB, 0x4C, 0xC7, 0x7F, 0x80, 0xEE, 0x75, 0x2E, 0x9A, 0x17, 0x8D, 0x9D, 0x21, 0x5F, 0x90, 0x84, 0xA5, 0xB3, 0xA6, 0x76, 0x5E, 0xBD, 0x66, 0x6D, 0x67, 0xCB, 0x5B, 0x0C, 0x04, 0xB1, 0xE1, 0xA6, 0x43, 0x38, 0x2A, 0x96, 0x16, 0x2C, 0x9B, 0xB9, 0x1C, 0x40, 0x0C, 0x6F, 0x14, 0xA3, 0x92, 0x90, 0xA3, 0x61, 0xF0, 0xFD, 0x39, 0x3A, 0x80, 0x27, 0x03, 0x52, 0xE1, 0x42, 0x6C, 0xCB, 0xDB, 0x33, 0xC2, 0xCE, 0x1D, 0x93, 0x7E, 0xF4, 0x98, 0x78, 0xF7, 0xC0, 0xFB, 0xEE, 0xCF, 0x2F, 0xD1, 0x76, 0xD8, 0x63, 0x71, 0x31, 0x0A, 0xFC, 0x05, 0xBA, 0x47, 0x4B, 0x82, 0x04, 0xBA, 0xCE, 0x40, 0xD7, 0x8D, 0x52, 0x49, 0xCB, 0xA7, 0x03, 0xC1, 0x68, 0x2A, 0x1C, 0x53, 0xF3, 0xD5, 0x40, 0x7F, 0x41, 0x25, 0xA8, 0xE6, 0xDB, 0x80, 0x60, 0xB2, 0x3A, 0x3F, 0xA6, 0xE5, 0x91, 0xEA, 0xFC, 0x82, 0x96, 0x0B, 0xCB, 0x97, 0x4E, 0x53, 0xF3, 0x0A, 0xD0, 0x39, 0xD9, 0x20, 0x8F, 0x34, 0xC8, 0xF3, 0xB9, 0xF5, 0x51, 0x00, 0x40, 0x07, 0x38, 0xE3, 0x85, 0x15, 0xCB, 0x00, 0x2B, 0xD0, 0x1E, 0x91, 0xC5, 0x0C, 0x63, 0x5A, 0x2B, 0x3B, 0x66, 0x6D, 0x87, 0x69, 0x4C, 0x63, 0x30, 0x68, 0x7E, 0x35, 0xF5, 0x41, 0x4C, 0x0C, 0x1B, 0x0A, 0x80, 0xCE, 0x39, 0x15, 0x4C, 0x2F, 0x65, 0xF9, 0x4B, 0x0F, 0xB0, 0x1C, 0x84, 0x7F, 0xFB, 0x64, 0xF9, 0xCF, 0x49, 0x59, 0xFE, 0xBF, 0x10, 0x0C, 0x27, 0xA0, 0x12, 0xAC, 0xBF, 0xDF, 0xFA, 0x0A, 0x26, 0xDC, 0x03, 0xA8, 0xEF, 0xCD, 0x55, 0xEB, 0xAB, 0xA3, 0xC0, 0x7E, 0xB3, 0xBE, 0xD7, 0x7B, 0x34, 0xF8, 0xEC, 0x70, 0x7F, 0x53, 0x29, 0x2C, 0x84, 0x01, 0x30, 0x00, 0xFA, 0x44, 0x1A, 0x3E, 0x9F, 0x06, 0xD7, 0x1A, 0x08, 0x3C, 0x04, 0xFB, 0x3A, 0x05, 0x79, 0x5F, 0x5E, 0x41, } }; static VipsProfileFallback vips__profile_fallback_sGrey = { "sGrey", 360, { 0x78, 0xDA, 0x7D, 0x8F, 0x23, 0x60, 0x25, 0x00, 0x18, 0x80, 0xBF, 0x67, 0xFB, 0xB5, 0x33, 0xCB, 0xF9, 0xAE, 0x9F, 0x6D, 0xB3, 0x3C, 0xDB, 0x7E, 0xAF, 0xF7, 0x43, 0x0F, 0xE7, 0xD5, 0xA5, 0x99, 0x71, 0x69, 0x5E, 0x99, 0x11, 0x67, 0xFB, 0xA1, 0xCD, 0xBF, 0x0D, 0x10, 0x78, 0x02, 0xF6, 0x60, 0x5C, 0x7C, 0x1C, 0x82, 0xA1, 0x44, 0xEC, 0xC1, 0xEB, 0x5B, 0x9F, 0x3E, 0x7E, 0xFA, 0x7C, 0x5C, 0x36, 0x82, 0x08, 0x33, 0x0A, 0xB4, 0x1C, 0xB1, 0xDA, 0xE3, 0x91, 0x67, 0x6F, 0xEE, 0xBF, 0x05, 0x88, 0x5B, 0xD3, 0x71, 0x7B, 0x22, 0x16, 0x60, 0x1B, 0x2C, 0xF6, 0x20, 0x00, 0xE8, 0xBC, 0xE0, 0xB1, 0x86, 0x1C, 0xB5, 0x35, 0x36, 0x79, 0xED, 0xFF, 0x72, 0x5D, 0x4B, 0xCE, 0x5B, 0xE9, 0xFE, 0x3F, 0xD1, 0xCC, 0xC1, 0x20, 0x71, 0x38, 0xE3, 0x76, 0xA0, 0x09, 0x38, 0x6D, 0x8F, 0xC4, 0x12, 0xC0, 0x18, 0x70, 0x32, 0x9D, 0x88, 0x14, 0x6D, 0x81, 0x1C, 0x30, 0xDB, 0x3D, 0x56, 0x07, 0x08, 0x0E, 0x03, 0xE7, 0xFD, 0x6F, 0x5F, 0xDF, 0x01, 0xC1, 0x43, 0xE0, 0x78, 0x30, 0x90, 0xB4, 0x03, 0x00, 0x02, 0x40, 0xED, 0x0C, 0xBD, 0x7B, 0x03, 0xC8, 0x81, 0xC3, 0xC4, 0x79, 0x40, 0x8C, 0xEC, 0x3E, 0x35, 0x52, 0xE0, 0x30, 0x77, 0x8A, 0x78, 0x19, 0x4A, 0x3F, 0xEF, 0xFC, 0x25, 0xEE, 0xBA, 0x76, 0x15, 0x00, 0x81, 0xFA, 0x06, 0x48, 0xFA, 0xF3, 0xF9, 0xB9, 0xB3, 0x20, 0xFB, 0x06, 0x1B, 0x3F, 0xF2, 0xF9, 0xB5, 0x5F, 0xF9, 0xFC, 0xC6, 0x6F, 0x10, 0xF5, 0x41, 0x53, 0x34, 0x62, 0x8D, 0x59, 0x01, 0x10, 0x01, 0x42, 0x97, 0x17, 0x66, 0xCB, 0x40, 0xF3, 0x09, 0x4C, 0x6D, 0xA0, 0xFC, 0x52, 0x00, 0xD8, 0x1E, 0x49, 0xEC, } }; static VipsProfileFallback vips__profile_fallback_sRGB = { "sRGB", 480, { 0x78, 0xDA, 0x7D, 0x90, 0x33, 0x60, 0x1D, 0x01, 0x1C, 0x87, 0xBF, 0x67, 0xD4, 0xB6, 0xB1, 0xD4, 0xEE, 0x52, 0x6B, 0xA9, 0x8D, 0xE5, 0xD9, 0xBC, 0xBB, 0x6A, 0xAD, 0xBB, 0xD4, 0xDA, 0x6A, 0x77, 0x7E, 0xDD, 0xCA, 0xEC, 0xB1, 0x9D, 0x2D, 0x63, 0xEC, 0x1C, 0x62, 0x7F, 0xD3, 0xDF, 0xF8, 0x81, 0xAE, 0x22, 0xE2, 0x8E, 0x8A, 0xC6, 0xC5, 0x10, 0x8D, 0x49, 0xC2, 0xC9, 0x43, 0x7B, 0x17, 0x9F, 0xBF, 0x70, 0x71, 0xB1, 0xA5, 0x0A, 0x03, 0xD3, 0xB1, 0x31, 0x91, 0x05, 0x4E, 0xB7, 0x98, 0x38, 0x72, 0xEA, 0xE0, 0x69, 0x00, 0xD1, 0x79, 0x55, 0x74, 0x4B, 0x42, 0x84, 0x81, 0xD0, 0x98, 0x87, 0x0E, 0x20, 0x7B, 0x4D, 0xC0, 0x19, 0xF3, 0x5C, 0xAF, 0xFE, 0x7D, 0xF6, 0xE2, 0x4E, 0x5D, 0xEA, 0xE6, 0xB2, 0xDB, 0x67, 0x0E, 0x36, 0x1D, 0xFB, 0xC6, 0xD8, 0xD8, 0x3D, 0x5E, 0xD1, 0x0D, 0xB4, 0x03, 0xCB, 0xDD, 0x09, 0x41, 0x02, 0xDD, 0x62, 0x60, 0xE9, 0x55, 0x29, 0xA1, 0xD9, 0xFB, 0x81, 0xE9, 0xEE, 0x80, 0xD3, 0x03, 0xBA, 0xF3, 0xC0, 0x6A, 0x41, 0x3D, 0x10, 0x74, 0xB7, 0xB4, 0xB8, 0xBF, 0xDB, 0x7E, 0xA5, 0xD9, 0xAE, 0x6E, 0xFB, 0x87, 0x66, 0x0B, 0xA7, 0x4F, 0xEE, 0x03, 0xDD, 0x1F, 0x60, 0xB1, 0x7F, 0x80, 0xED, 0x1A, 0x60, 0x47, 0x23, 0x97, 0xDD, 0x00, 0x80, 0x0E, 0x18, 0xEF, 0x8D, 0x9D, 0x39, 0x05, 0x58, 0x81, 0xF9, 0x88, 0x9C, 0xE4, 0x10, 0x7B, 0x47, 0xA9, 0x31, 0x6B, 0x35, 0xEC, 0x63, 0x1F, 0xEB, 0x41, 0xD3, 0x6B, 0xA8, 0x0E, 0xA2, 0x6F, 0xD3, 0x46, 0x00, 0x74, 0xE3, 0x77, 0x81, 0xA9, 0x54, 0x96, 0xEB, 0x56, 0x82, 0xE5, 0x11, 0x74, 0x3C, 0x91, 0xE5, 0xB6, 0xB7, 0xB2, 0xDC, 0xF1, 0x0E, 0x0C, 0x25, 0xF0, 0x27, 0xD9, 0xDF, 0x1F, 0x7F, 0x03, 0xDB, 0x6B, 0xC1, 0xF0, 0xB0, 0x3F, 0xE6, 0x7A, 0x01, 0x3F, 0xEF, 0xC3, 0xEC, 0xA2, 0xFE, 0xD8, 0xF2, 0x37, 0x30, 0xE9, 0x36, 0xA4, 0xD2, 0x12, 0x4E, 0xC1, 0x09, 0x80, 0x01, 0xD0, 0xFB, 0x82, 0x50, 0xFB, 0x19, 0x26, 0x5C, 0x80, 0x69, 0x19, 0x60, 0xBF, 0xA4, 0x00, 0xE3, 0xE2, 0x5F, 0xB1, } }; VipsProfileFallback *vips__profile_fallback_table[] = { &vips__profile_fallback_cmyk, &vips__profile_fallback_p3, &vips__profile_fallback_sGrey, &vips__profile_fallback_sRGB, NULL }; libvips-8.18.2/libvips/colour/profiles.h000066400000000000000000000004431516303661500202400ustar00rootroot00000000000000/* The fallback profiles, coded as a set of uchar arrays, see wrap-profiles.sh */ #include typedef struct _VipsProfileFallback { const char *name; size_t length; const unsigned char data[]; } VipsProfileFallback; extern VipsProfileFallback *vips__profile_fallback_table[]; libvips-8.18.2/libvips/colour/profiles/000077500000000000000000000000001516303661500200665ustar00rootroot00000000000000libvips-8.18.2/libvips/colour/profiles/cmyk.icm000066400000000000000000035261541516303661500215430ustar00rootroot00000000000000largl prtrCMYKLab  (5acspMSFT-argldesc8icprtgwtpt bkpt clrt4A2B1A2B0A2B2B2A1ѼB2A0ѼB2A2xLѼgamtJ.targx 3DevDx 3CIEDx 3descChemical prooftextCreated by Graeme W. Gill. Released into the public domain. No Warranty, Use at your own risk.XYZ QXYZ $:clrtCyanx[7KMagenta#͒|Yellow|&Black%o{mft2 Z gt(5BN[h  t ' 3 ? K W cn z,7BMX cmx*4?IS] L !!T!!""[""# #b##$'$h$$%-%o%%&4&v&&':'|''(A(())G))* *M**++R++,,W,,--]--. .a../%/f//0)0j001-1n11212r22343u33484x445:5{556=6}667?7788A8899B99::D::;;E;;<>E>>??D??@@=@w@@A%A_AAB BFBBBC,CfCCDDLDDDE2EkEEFFPFFFG5GnGGHHRHHHI6IoIIJJRJJJK5KnKKLLPLLLM2MjMMNNLNNNO-OeOOP PEP}PPQ%Q]QQRR=RuRRSSTSSST2TjTTUUHUUUV&V]VVWW:WrWWXXNXXXY+YbYYZZ>ZuZZ[[Q[[[\-\d\\] ]@]w]]^^S^^^_._e__` `H```a9avaab+bgbbccYccddJddde;exeef,fiffggZgghhJhhhi;iwiij+jgjjkkXkkl lHlllm9mummn)nfnnooVoop pGpppq7qtqqr(rdrrssUsst tEtttu6uruuv&vcvvwwSwwxxDxxxy4ypyyz$z`zz{{Q{{||A|}||}2}n}}~"~^~~Nƀ?|3p'dރXӄMDžB7t,j"`ۉVъMȋD;y3q+i#aސZבTВMʓ GĔB<{8v3r/n,k)h&f$d"b!a `XΡ D0kXϤ E3n \ӧJ8s&b٪Qɫ@|0l[ӮKî;w*fޱVβ E5q%`صPȶ?{/jZѹ I8s&bڼQȽ?{.iX Bz#\=u®VÏ7oĨPň1iơIǁǹ*bȚ Bzɲ"Zʒ:r˪R̊2jͣK΃λ+cϛ C|д$\є>O>>??R??@@W@@AAaAAB'BjBBC0CrCCD9D{DDEAEEFFJFFGGRGGHHYHHIIaIIJ&JhJJK.KoKKL4LvLLM;M}MNNBNNOOHOOP PNPPQQTQQRRZRRSS_SST#TdTTU(UiUUV-VnVVW1WrWWX5XvXXY9YzYYZ=Z~Z[[@[[\\D\\]]G]]^ ^I^^_ _L__``S``aacaab0btbbcAccddSdde!eeeef3fxfggFgghhZhhi)iniij=jjk kRkkl"lgllm7m|mnnMnnoocoop3pypqqJqqrrarrs2sxsttJttuubuuv4vzvwwMwwxxfxxy9yyz zRzz{%{l{{|@||}}Z}}~.~u~J׀\܁]ނ_ a#c%f)j,m1r5v:{?ŒEȍ KώR֏Yݐa'j0r:|Dɕ NԖYߗ"e.q;~šHϛVݜ!e0t@ȟ PؠP3lޢO3lߤQä6oTǧ9sY̩?y%_ӫ F-gۭN­6pX̰@z(bײK4nW̵@{)dطL5oW˺?y&`ԼG.h۾N¾5nJ|FxBt§ >pâ9kĝ4fŘ.`ƒ)[Ǎǿ#UȆȸNɀɲGyʫ@rˤ9k̜1c͔)[Όξ!RσϵI{Ь@qѣ6hҙ-^ӏ"TԅԶIzի >o֠3dו(Y؊ػM~ٯBrڣ6fۗ)Z܋ܻM~ݮ@pޡ2cߓ6| O#i<U'm?W(n?V'l< R!f6{J],q? Qc0uBRc/s> M\'j5xDR`*n8{FS`*n 8 {  E  Q  ^ ( k 4wA MY"e.q:}FQ]&i1t<HS^&h1s 5 p !"!]!!""J"""#7#r##$#$^$$%%K%%%&7&r&&'#'^''((J((()6)q))*"*]**++H+++,4,o,,--Z--. .E.../1/l//00W0011B1}112.2i2233T3344@4{445+5f5566R6677=7x778(8c8899N999:::t::;%;_;;<>Z>>? ?D???@0@m@@A#A`AABBSBBCCECCCD7DtDDE)EfEEFFWFFG GIGGGH:HvHHI*IgIIJJWJJK KGKKKL7LsLLM'McMMNNRNNOOAO}OOP0PlPPQQZQQR RHRRRS6SrSST$T`TTUUMUUUV:VuVVW(WcWWXXQXXYY?YzYYZ-ZiZZ[[X[[\ \G\\\]6]r]]^&^b^^__R__``F``aaBaaab?b~bbc;c{ccd9dxdde6eueef4fsffg2gqggh0hphhi/ioiij.jnjjk.knkkl.lnllm/mommn0nqnno2oroop4puppq7qxqqr:r{rrs>ssttBttuuGuuv vLvvwwRwwxxXxxyy^yyz#zezz{*{l{{|2|t||}:}|}~~B~~ KπNˁ GÂ@~9x3r.l)h%d!`߉]܊[ڋZٌYٍYَYڏZې\ޑ_"c&g+l0r7y>˜Fʙ OԚXݛ c+m6yBȟ NՠTѡMʢGģA;z6u1p-l*i'f$c!`߬]ۭY׮TүO̰ JDZD={6t/m'e\طSθ IĹ?}5r)g[սOȾB5q+o9}GŠSÖ_Ģ(kŮ3vƸ>ǀHȊQɓZʜ!c˥)k̭1s͵9{ν@ςGЉ NяTҖZӛ`ԡ$eէ)j֬.oױ3tص8yٺ<}ھ@ہD܅G݈ Kދ NߎZ3| T-uN&nFe<[2z P&nDa6~ S(oD_3zN"h<V)oBZ-sE\.tGa4zN!g: R%k=  U ' m ?  V ( m >U&k< R"h8}Mb1wFZ)n= Q e3xF  H !&!^!!""<"t""##Q###$/$f$$% %D%{%%&!&X&&&'5'm''((I((()&)]))**:*q**++M+++,),`,,--<-s--..O.../*/a//00<0s0011N1112)2`2233:3q3344K4445%5\556676m6677H7778$8[888969m99::I:::;&;];;<<:,>c>>? ?A?x??@@V@@@A4AkAABBIBBBC&C]CCDD:DqDDEENEEEF+FbFFGG?GvGGHHRHHHI.IeIIJ JAJxJJKKTKKKL/LfLLM MAMxMMNNSNNNO.OdOOPP?PuPPQQOQQQR)R`RRSS9SpSSTTITTTU#UZUUUV5VlVVWWHWWWX%X]XXYY;YrYYZZRZZZ[2[j[[\\K\\\],]e]]^^H^^^_+_d__``C`w``aaHa}aabbObbbc"cWcccd+d`ddde3eheeff=frffggFg{gghhPhhhi%i[iiij0jfjjkkj€Frʁ"Nz҂+W܄5a?lŅJwІ*V݈ 6cCpʉ$Q~؋3`Cp̌'Uߎ ;iŎ"P~ې 8gŐ"Qޒ rۢDyKQ"V&Z¦*^ŧ-`Ȩ/bɩ0cʪ0cʫ0cɬ.aǭ,^î(Z"TM~Duس :k̳.^ QBrѷ1aN~ܹ :iǹ%T߻|'{}ю~}YVm5jgB.ih~"%}I|h}}~͍/gCF-%~|6J||}ΕE~gZMCAx.2Q%1u{@b{ϭ | 6[|0}蕃g~ȎtDE.ʁ%Y{^3x{߷TH{||+(}V{K\0- h|,'|;$f | І:؂ uҀYxc @z ؄fЖ]Nw5~'|R v{tȜ݌zH|f<N 5SC&}} 0L{ѪkڜĚǘ?GxFdGtyMʇg5,&;}L{۪Rѥ*査w Lqb/KG4)&1} 8p{Ĩ R[>sv-abi`LӐ?4ڄr&~P ʆ{hNtș墈a.Lq=5څ']~!{Lԟ/s䙺a+J5'K"P|2R||{T~!Bzp y_kDyI˗z&2nz'|jy"+yϝûʂ2մ ~o}^|ItE|u2 {&"z zd<۲}rcnCf\qbG%2(@}%~{rtz|rl٣[Ʌ.H7V1~$y1|59{"g1C̱|Mɑk.lZG3;1荙)$S |{0؜={/1ojZ FG<1q_l$~} {(ȪZSzꞺj#2)ZBGj2/v%. }p+{ױͱ!zTEi{X~G쎊2&@} ]{=3ycYhW ֚aDQx3 &~W!{wI}jsZ{p,zdb)y=T|xCIqy4/Cy^$uyH+y7ƾrM}c|[T{VC{=..z#.ycyƚ:څpq!bS7HB}-ۑ{"Oz zh{O4p0aI)QUxA6-}J!{'fhz94jpbZ`ͫQfGA_-Ð~!{s)zHXo`#]P4 A|N$.$#"5h{zFðoٚR_9.Q͏AO.ď#3`|W>zP ·I|n.J^PǢzhAO/?^>$n|ˈQz\8"~7Ql`TO\>q/k;%ċZ}l!wz釆B|yziLy\}x:LRxr<x,ǔx"xɊ3xqx_h̽]}6\3{lMyz<šzJ*y IJy؊xՅ@x6?hؼ| \H]Lܪj~ vv޵wdz ~yV38zHe|oB"~5.?f%́ =u*І̱v4|w#x豮zUHc|3XA~\.& c]u=˵vvz>w0Bx0zKa|? 1.,&r*Cxz5xzG{'V|cÂ}@ۂp}-|:$΃.{ٿʂfOցǂxc끧)@V%~,}>$Y|YVǁ!İǀUŁꆳc'@z,e,~`$[}xc9ᘊ/e4a퀐?^,sq$%~דh)|~O~ma@6,Z$U~uԺc~ڬ~k~~}~З`P?І,!$~=U~~M20~|~^_6%>倨 ,$Á~w~ɀ~Wf}巗}̮e{+~^f~>h%,% - p~$ʪ}!}a1z}֪ ]|~ϝ>,Ł׃\%rf7w*ynzX{5z{^%|>?|,|$/{˸'\ w:ڈˀu!~z$̀$^lp> }+|#ȃ|YҌ̼W ԈyFy؅9g^&K=+>a}#mE|=ژ[ᥗx \؃=;Y+ -~#O}Yǿ좻وLcˆ@uwŐ\N<*q#R }ɊwȇԧУɡoIvmJ[IW(n;+[V$p&~dHxI x֟z zr֋5{VZ{<5N{+{#τ{r1bÈPr%XՈQ~;J}C*k|Q#Ec{0 ٯUZ3*bquXׁ:~)ᄨ}""„.|YԕJCĆao0 VJ:X)}"y|Vޚbъo>V=]9DžT)\t~"b|˹?̐b9םɄhOn 1uUT80Z)r"e$|ظwIJ𪁏ߖw0 Km,oT^=8C)j"-|QU֏ܵǖ[ncl5T&8)WQi"߄}&aȩ9T:{jև_Ru헰8)8#p}s9w ux)%yPzkzT[z9di{!* [{#zz0Va~‘~A~lj~>Sa}83|)4{"7{hܑ+L~mi҂RƋ8*~2(|!{Я/iiv`f}Ց3h@SE[8(S}:!|z4&>|ڐhy"Q7j|'}!q|#w0ڍ퓨S{4@fӍ!AP^^_6nY1'~=!v|t{څ4Qрu&B} E{i%vݛ{tq; 5_KsvP3&}n Q{~3ہup _ZYݳ ݭ/yaNFjqOY gFĔ~1|@${>z $@wҥajޅfX'hFq1}$?X{†zʑlȫ퐕vХNhXpE֓0U$-|$jzْԱQ 4=vfȟ(WAEG0Ox$ |ц]zґ;&хkՠu=/tewgVE֊Z0$q |=`zŏp%u@~eWUD 0ڌ$}ItzЏd,tre8ŠpTeC20&%>} zXwz̹wlw_vPwM?x'-Yx#yLy8 }@{,Q|/lgz_zzMPԢz@\z-y"8yy~΃zIgkk^$~O֢}?ښ|,{!zTz(yʊy[Ljf]y{N\?7aA,@|c! zAyベ+xֶ j]PN,>Ԙȁ, J}!{HoyܼxfpjՐt\vNq >cd,/~!Y{^GyѼ(x5iw[N5]?#|,̎"x{=yQwŵhխtZצFMv >Ή-OЁ2#|$_zͻޮEwhYK[ dLΟjH=ė-$ |z.|x%s~vvcںKvWduIv:v*w G^xUVx{|q3{scxz!V{yIWx:Zx(uxIx׉=xzyooc*!Vl}4H6| 9{2(0yy0ȉx{oԿdb&VkuGc9 @}'{(yWx{Ҏnᾣ0bz(UІGʦ׃)90'Q|8݋yxy애n/Bap UrvHu 9J(}};z-YPxy2n̼әaε;:UHD؊9.)0Y~`z.xxWn@ԟQaU.HEQ:DH)Sl!'{ oTy1wJĚlm6TaT&pr擡uJzw\7^{zm>}- ݂% LmΌp er=Ptxw60\yy=}^-Q&bpFM!s.iu&w}yn_€3{0>?{, {R$1g{0;||M}|*u}}I@~B}|c~}_}>b}+|V# {sz{R|`꒠}z4~^a*=΀+Y}p#ǁ|y<rzYc{)8|Ox}j]S~='+~v#߁~}OXxyYz&F{jw|}]}>̃?+ǀU$d}wxh}y~ zv{d\d}=G+΀Հ$5^}svow=xzRu{m2[}<e+Ѐ$ek~ vw>x7~y©tO{Z-|<{C+ׁ$~U1vfwRxWyd+szǦ.Y|o<$+{+w$ց~IpJWsuMwuyYg#z;{I*.z#҃HzϾy {;|G[|uI}%[#}kgt*UZ0";ՂW~*}#-|R#ܯނQGމŕXȁ;/*VQ}#2r|»ӂ#5ڗځ(q\ڍX.:ǂY*?4~#Gc}kAQq*֚;A^o׀FuW2:v8*8!E#X^})B"u58֟1nFU݀W:aP*-#i\}RnD)9g6mymUR9ځ2N*%#zZ}5Zg߼S*m'EiTØj9 @*5x#X}ӑq|rΗ،-tlBvpo[YxU[xzm9z)̈́Rz##z3zxҧz({J݈{mt|bUˆ|9|2){"ǃ{I Ѥ/܀lfā!U 9k[})^||"|{ٯ/+F΋ْ"5$kBT9))M}="`|+./j:`M:~LjCduSp8k)9}"Z|PJq{}&%h QԄG7)u~g"S|hWLYS^|х2gLLP7t(T"o@| ۯCn |Qf.P7%N(6"Y.|9lFʈnތ ze݄ O݃^7"X(E"X|Цqrt{4NvgkxfQry~7z@(jzp"Jzfx皥yinzx{,e͌{Pjr{7 {(K!{("vzŖ|N~jwd㋁O6c}.({!΄>{bjsǒj:v㆞dK̄P_7~(5|!%{(=֎ˎvCc(NЈ56h(0}!ۄ!{4PrC*,tɌtb Mmu5с'τ}!{8ې&$=sԋka M *5$'Nq~+!n{͞Дms`Li?V4]9' V~!J{ޞÒÒ 0r._K] 4ȉݘᦀy&iÑYfGL1󇔃%y|} 5{si.Rz/0jCGX2mF&;12%\v} V{j3qbrs:t9d{uPTʘvwBw/x$y1yҊr_wavxsHxod뜸xU6yCݒQy/y$JzOz k}׀$}r蠘}od}fT;]}=C|z/H{>$mzz>9~.r3]dś+TC )/|#:{ ޅz`>A}4R2p6^6cŇSBE.}#{vЅzm@s}MBnО܏yaҚT?S>A.r9#{Ņpzf &{XGmpY`aޒzRoB%.֊'#|8ƅ_zS {0m`2_YQqΒ Aҏ.#|TzFy /md_P!ᕢ?.R#ㆹ|jLzBz_q*oճrf@ys[sL*t~cy,Oz$bzmsʺ puԥsxvWyxxz\{${B=}{v+{~$*y{jjmCno^q΀ʏtFviw Yz~~<}x}K+ik|$B|5)iOsm5p`g^s}tvgYy<}r+Y0}#|gי$kd#osrspu#Zx=3|Ɂ+ ~$ }&;gjˠnXq rtWgxd=~|+~`$>}ge_i誽Lmepr t6Vw=,|Ld+~A$~}?ezISi(nl1UpHCrsX3w\<|+%I}eàqhHalPJ|oŬqsDW wz;{l,p%Ҁ~RbygykUzo9{sVu|uY}xO<y+z$zFLv=sjvwu y w:z,xt{zZ}F{<d{_*{>#M{*tbud)wP։xrzX|~;@~}G*i|\#w{xrPtLOu$Qw݆py҄W|u:~E*u0}Q#m|zpprytŏvFoy:W{bp:~OD*z~ #w|ȷ1oؠl2qLs˜vsnx?@V*z׊:~L*~#|nڬ Aqs,uamwUMzQ:\}؅*#€}*nv=pXŖr=tڣlw'Uy⓭9}*w$ }gnt o㹄*qɱځtVlqv¡Ty79}g*8$m} hQHl"Np ڀrmruT xY:ny*cZy#yrat”~wjxpngyV z:;{:)z# 6zҬ}~,}~i}~~-m~d~oT p~$9})|"ׁ{|ڡ|a|nU}Sk}̓Rk~8j~)Z|"|zJ"{#xs{mr~D|3xj}S~Z8')g@}"|Ryޠqzz\|p{`h|WNQ}^8.y)O-~C"|vxmyz2n|?zךg_{PX}j8 )R~"|w92p&"} {NoU(yAϦPjE|Yu(Gm2L% ~! E{OZj~]mVw6HohrXR#t\E v2{xR%vYys܄`yǘuq2#rwth~vX?uwF|x1y%Nz :z3A;xzu>zfW\{\W{F2{1z%sz LzyWMہÁCśeV?E;~q2|K%ф{% zqO@^r\eqЅUDu^2t}%儨{ z6~ȒBqf_dq6U4D ˄1I%w| pzX}$\pǕHcɑTDFC0J$ȄP|u⃸zߡ}Kpib2T /Ca/{$56|pz`|Rr#Ϣc˜jSB.G‚#0|-z{xjuJDliۜos^瘓qPɔksV?ŏu.$w#yC y}tptr%jsm^tPkv\@2w-쉓x#Pyyny{wD|-{D#jz`݄yy=q;fb0c[SMׁ=ʍ-|#Sz焔zy1qelPZ3@M=zr,{}"{{yvGGo[Qc x,$-"}{oU`yvp!dLYSLwr=,T3"[a{ Dyv""p`5eY8˗K;},?)"PU{'yoְjfk]nSdoGq9)s)4v׈xb߅yn'oflpy]'qSsTG,!t9u)Yw xyk߮UueѪIvM[-vQ}DwtF3wx9xy)n"x $y8yl*|dѩi|}Z;|QP-d{E{8ܓAz) y y_Nylc `ZYPEE2#7r}A(o{ SyTylBdl>ZWE^PV;D_6'( Q|҇#yN`y jo bȧ_Y#'OΝ2HDƆ7(N}Rنz9K4xifjb"WF&|2{[#oIyMxjxcx\"R4H4=6`1&}# zxhxaGڎZׯWR8H>1 ̀G$ { gyw_ܲYmBfQdH󣖋0>O2q$i|͈y8ʅw_XUYb?OQFǣ]8z*~S9$Ӏ} Ks_ytdWv2jewnmqyPrBUp{^u9;~w+ y#ڀyJplrotpqvTtl#x5~C'߀T}8"6{~p5'~'?}!4{ҝojq}w2}^oS~.K]~b~IsC~4(|'@{!{| |RB|=| m}![}ÃI~4:q~8'G|(!{EhzÐz?z{jDly|\|I:~<3-' o|!{Tysfyz`z4k{KZ|5jH}3e灮&P};!4{UyynVy8znizZ{HP}>3B&n/}! {Wxxyyjoj"z9Y{V3HI|܏l46e& ~- {^ԋXd7gykjVnYqGEt27vwZ%u#x y~Tk݄Lmxtpcj\yrY^u FŃv1(x%y QzWs?tu,vhrx4Xփy(E(y1nzU%zn zv|U%}+u}~gc~+W}D}51{&{!zsVejV;d{^|aQ9|bA{/{$ăz 3zN|ujH]ɁO@"~0){|l$z )'zZ{Ssi]^i]GÆO'Ä@/`+}$l{]zLy݋ד1r/f\χ6iOԅ?A.'1#L{@z,xgpЉØfC [ϒN셬W>,烺="4{zxfn쟊ețO[$L|=l+ŃÁD"D&|-ys3el g|b_4jXmwL9p#=s<,v!>xv%yNrjkQulb=1nX&pKtr=#u++ۇw!xyzq0pi#rasWOuK'v<ۋ_w+;x"Pyd9yp5owhy_yU~:zYIaWz;݊z,Jz"Äyyn"kgȖ*^_WNV'~Hw~; y}D,3{S"ׄz4Ƀym#@gg 6]i~6T H; +|"ozyj:B5c K[SI L:*9}!fz胣yujdϓ[(SFTGڊ9X=#)~!Lz_yDksc"#.ZYՖcQ9RGݍ7_z)_ ˄:zqye$eO^ fnUiL kBn5q'muΆwxdi]YjTm/KkoMA'qY6LZs'uvOx6„xc7nk[죸pIT*qK"Ns?A|^t6ev'֊wʆexqxauvZHv;SI{vJ} w@ޕTxQ5̏x'x @xxau|Yq|nP|>I<| @x{5X{'qkyy0Kxa\XY7pPԜځH\逯?{*y4}',$zyqx^{XbkQH +>ԓq4#-&ψ|ayAWx^X|8PmPH (>Ԓ3jU'&Lj|By +xg^٠8XBPtH<>Pb1ێJ($}R[yx:Z d1SeKhCj:2l0Vo"tY=w8xqZ@h{SZiJvkBuCm9 o/r#Jsu[wixJ[^mSɬenJtoBA)q49ԝr/tQ"vSwͅxYHs!RmsJ9tBuO:ƛu/cv!Čw<wfwXCxPy'HyAy:Ty60x"V(x|xwX Png,H?~@}9tY|/^n{H"yvMxZmwWcaQEIA-ς8/z.7}#z`xwVqPV)H8`@3{7s*%-6r#IJ{(Ux˄wW`P(ĐsH1@uƊ'6S-3E#Њ{mxw_hAZsj^mgdxhp9ij*s=nLRVvrz8{Hv*~8x)$@xy#ceUCgSi %k l~nohVqryPuu7zx)~yV#_y_r@cshv*{GlvofypdwxO+ty7z^z ) }zt"Pz]-}a9}fx~,yj}fo}3Pht|7^z{(}{O"<O{[q_d8z3iPf|mȃNs`k7Zy}(}{!Y{(oYΜ[^%bygdlLVr5yr'}||!q{EWBJ\;ĉ0awf]gd kLqq4y,'}}m!{zVƗz[8`jFv^ezc/jʕLq 5Nx߄'}~.",{nVZb`uebGjKq6x_(g}~"{Ǫn\oa6{qeyQsj)evnNxr7h|v)n0x#<9y kuf&VmIiom1xrodtrNxu^6|Iw(~y@"yΦmg/pjXr܈mu[vp`vxc6s^wN>wx6b{y(!~zS" z~pd| 3g|~kX|uPn}bcr |Mv2|q6&{s{'~{-! zbuؕeÅ6itm%yapLuo/5c{3}'k~{!s{ 7`ԏŔCdBÄh,tkފ`oK]t;4@z^&~|u!F*{:H_LWb߄ffsynxomr'at'Ru@܀Bw3.ˁ@x$Cy.z~TvAx~&w'm;~zx`~yQ7z<@z`/Mzv$za 'zT{}0~vO|~k;}!~^}P{~o~uA6}0| $ׁz (zr|W{Xt!{[iE{][|>Py}{Ba~/o}${[Â.zj|dz5Oszlh?zݍ[{vO|A}/ .~#{Q2zJy yA}"-uQ#Aa|A݂zx,w^pbfgPZ{9jwLem?"&q,u"-wyvɋCe=oÉge^Ik-Z4n7Lp=s,^v"qx8yguw/m mndpZ[rMt<v[,T6xS"yXقyt"3tplkuc w|XԄx;LVy|al}GV}vI惇|=ق|r.{G#₣zkXz pj_$RTyhIo=W-{|#rzypchmŒ^;T(̈I큤`<䂂,)D}"zvynĂf;^LҐTсnIY8;j'*~!{ӂylԜfS ]ajTV[H2ۍ9|)!h{Ogygi0^cbD[~Pf"PiEl: q*(uH e2wL`xhVdbؓpfYiNlE:o8r)vT ȄxOUy&h`kamHXxo(NepEvs08c[uO)Åxw!XxFyegHr`1FssWd]u'Nr`vCD}w7x**['x!y_K6ydݐoyD_yVǍ>z*N)=zCf{{#7Iz*z6"2y+ydl^^?oUhBLNcC 8}*!{Y!ԃyE'yjaR\3ꇚT7gKLB`G7]M(|\ 郒z,y(a%OUZDSҌ7K؊AۇP5օ~'g},ꃍz'-xa!<[iҔR}K&B35}&L~drzHAxZӢ7_=T͟aPO^dk1o%ڈt {wg x[#cDTڞeM;5hNDk K6vBU8l03}%ÆzZy4x~S%,O88JKqBS9`/${y5x9Q˘^rOۏHIBE0u7z-3$R|f~y6ăyxPn^OKX`Dc>*fZ4j#,nN"VwsvxVO~bpJdCf<_is4lp,Dvo"#ktswDxCO6gdIixD"k <)m5oT+ϒr'!#uaņwQx,O|lIdn Co<'q4җr+Oqt vLgwtBxO>vrit:u!4u,w""_wvRwJx MxGơy.@Rye:; yc3ܕy4,.yD#-Ux8x2/xN3(HYA'j:u~1ߔ|*{+"͉@ymxU؄2wMG{ A=i79Șq1=)O|">MyxRwM:Ez@Z9F91)~c"EzpkxAwUcSSeYh_HtkdaoGjULsoQ5;ytb(T}nwH" x9^^`abYegDuij`mnKs!rY5y[v?'}GxQ"U~y/_Yj]l$bos=gIq_ol-sfK2qu5 xxC'}y_!~yϟVvCZv`8xpeGx^jxJpy4x]z5'&}z8!Az28SNX3GD]ocA3^i ~JJo}4w|&}z ZxW__ivdl:Xj Epe0wy{$~{π>zTYv^hdcJWi$Dp/02xځ2$~|WzT xWu\ٞVgbUWhECo90px%~ } RizpoVp[xzra}k{sfYujDxo0|t%[kw^ }|xl_/mcwogim.5zN$ |%z\[|>^ncb`Fg{R'l@mrÊ/zQ$| ,zdLwNW{+wY]InCwbbxlfXSyk+B${o.~t#rwO 3x}tB_xtcmugaw jRxnxB$zr.~Qu#€[x! :y qhxrkmsn `?uMpQwHrBzt.}w#Dy@Dynqwo~slqot_svAQuw^Ay,xD.}yO#7yZTy|Kkzeumbzkzo{\^q{P^t{@x{.\}]z#̀4ziJiz)ziskin/w]BpOs@Qw4.}(|#6zz,{Zgr'ri͌gblr5[SoY,Nr?xwD-[|~#,1{Hށzxfyrh唿g&kYYnuLr*H~oa,e_t?"([w2ԁxuy{_o{1cfR{fZ|jL|n$=m~q,9u"_Gx1xuy&gn^y j emylYzcoK{r<}Ntf,@wI"0xytkupmvqcwsXyuKvzv@<|w,kx"yځyrt@x9kty bJvyWwzAJfyz={z,.zs#z!߁ypr5isd`GtEUev6IWx1={b},~{"ځzyq+pcgqT^s_YaQ .dHh5?TlD4"pO'".t/wUx]5eWgP jG?l?o3Qr'kvR : xI+y\؉l3V$mNioFچqx>8su3ᄲuu(~w xւyXZrVgsNGu Ev7=w63x(U5x!@yD.ycT'yjUzKMŅJzDz;фZz3Iz( z ! yy@TtlSsLV Aj7m.qqb$Exu|:wHxNiIQOkmCc!lMl?Ŝm9ՙ'o,4p0xr})ȌNt"vwxiCќr?fs86s3t.Ju*Yw(#wȄx@xZD@x?lz69y3yG,x(Bx#LxdxXɃSx0Bo=ܗ#:4S~3}{,]f{&za"!yexB=wAхp;570>g3<.~D(S{!Iy]\xx>w^yMv`S~cZmg`\XkfFHpl;2Ox;r%|vK ~wњ-Y*XH~[\|`0amdf"ZiyjGoo[24wtY%|w& ~xTSdcWlgy\~jtjalXgoFSnr1w!vN%|_x a~x֒OoSpdw)Yrg"_GsVetEm0v1hvxR%S|ax ~y3KCyBPy uVzhf\z/UczODkz0vBz7$|y.ymG̓RMrtTRdZЀTbA.Cj~0v|$0|zV!yEkՀ+K#KsRdYRTt`ņCj-.u~ #M|{_yCq~I q]P)dWvT_ˌ)Bil.]u"|{yΉBA}GRrNVcUnR^@ hӉ-u8"||yݓcOZeWTxrg[ghj;aXImfzCrl/yr$}vBcw_DXr9aH]cudb[gchHfVljDroZ0dy1tY$}w]xIZd&]ftaLiecelU|joDpr0Hxv.$}fxlxۉUn8YpZq^}qcc[s?T8htCo}v`/x8x$G}hx^yAiQx}4Vjxpc[yba/yS0g6yBnjz$/=wy#}yyyN2{So&Y'ax_RXe@Am}.w{#j}z8(y"Kqz-Qp} ,y{9"~z 4y{ S߉qXF f] ZbLhӃ=p",Kyi|"%~zׁyyjRHSpVe[Ya)Llg=o>+yA~`!~z?yxwPnsTaYXh_ӑ>Lf=oR+y !~{IJXyqzNpSqqPX fr1\[6saMug=^yl+}=r"vwxwmPZon]eobWZVqf.Ltijh=(xo+|t/!wx4uiac2mjedim4hXokJrnaY7>d)\ZM`ÑQeRFk9:r*Zz~!zy$owTOhwwXd^w]jSxb%G@z(g$9h|6lt)~r vowntZKgtv]7^puaySyveFxj<8{Hn)r~s vyx.iqqacqd#]zp4}3s'v QWxz4y.^syosXGtpOvUrnGws=yt3|v'x% XxwyMZpwQV`rwNdtx3Fgvxo@Sp\?LrCYt~<w}2{|&.z tyu'ixXlSo"zKqmHD's;uvށ2#zt&{~{}yxWkRmJzp7Cs :uӅ,2yځ &~|orzyWxV6~SQdWK [Dх`:e/k#rmuNwTχYP\%I\` Bd69Ѓh/,m$jsa^vv@x0RńD_M߃bHRve(A%hW8ւKk/Yo$Et8wW3xRfKLIgFBj}?7l7(oc/kr%ev?x?0yRVlL;~mE`Co>qr6Qs2.u?%w~ xijF9ωl4ވn.;ap(ys#Uvςx_FXyC1p%=pq9gq4 }r-Wt:)6v #݃>w 9x^xAzv> w98ww3jw|-x(x~#x !xwx?ƅ|Z/Qv;T_4*Y^.](ScZ"ti6quCw=V9HX4o\}/`*Ze#kvHrnhvsx(<\9Y^4]u`R0s d*׏h~#$mv~ swmx9{aB6kb3d-d/k?h(k!o]tw6x9fm6h2wj5-l9(ьn$UrV" {v \x9wx9єl6#m1>n,pC(r9(St%w[!:xgax9r/5֐s1f't,vt'܊nu~&v$7w!_x{ !_x8x95x2iy?-3x&x0!ɇw" x@ /xc Hzxm93~G4 }1S|-|)uz$ym!+x lxI xZI&\Qw_WVg6b\WgrbEni0,wp#|^u(@~w/T^SIWYYth[^g`bTVegLDdll0urS#{u~Mwc~NH`RUcUt W[ed@\hfSc=lB2kpb.u?tO#{v~=wˆHk,MkoSnT`YogQaLq@kjstE.7tv#m{w~x Cu}Igtwn Pzv_b1WvP_kw>hiw.tux#T|xi{ xG@g~yF~ kM~}_T}XP#]|?g@{-tzo"|{y7xZ=x,CilJvW^R\gE[gMNW捀>d@+r{z<x_IJo~"`xPnbW`e]Rjjc@pj-xjq"}t %vYT{w\Xm_X]`'cbQWhgk@o&l.pwr\"|uwNS_y.WHbfl[eC^`hlOf~l?mo-Evt@"|v wNvj0wDS3k jXl]E]nN^dEq>qlDs},vv<"n|wgxG~JQsuYOqsIiUZto\W[fu{Mbzv>=kw7,vEx"K|xkx|F|sK|whR-|QZ9X{L,`{=[jQ{2,$v)y!}ByiHx{GCErtHeOgY2V:L,_=\ip+kv { }sygxy@$oFs?cMCXTK]n=hq*u}O}z"xw>phnWC`J+UfRC}J'\e<{g{*:u~}qzۀxReMeteR+gh X>ZUj^Mngczq!~(tvD|f`Urbb7YRfd]Yh!bxKlgTt"6Oru*zDw2 0xGHxiVx#aZxnV^UxLcGxuBJiux7px*myx Txxg1S_V́nVg[VMa-~BPg}5o|u(yzgy yje4xdfMMC\nQTWqqI]?eh5o'2zH|>yyix@ggqQaqTVsYLt^XAvcw3yi(}hp'tGvJfnV`2o YVpZ]Lar/b@5tf37xl&}Wr>Bu Aw>e jR^]fk`/TmkcKHof?s8j2wn&:|sv Pxbf e[gh"Sjj)I.mlR>qfn30vsq&|u_w7{x`blZd o QgpSGkkqx=or3uyt'W|Avx3fx`^uRXa1vHOe=vxGiLv>?n0w 3t{w'!| x*6x}x][~X-^[~,Ob?}Gf|=Ll{0=sz%{yH`xXCx[Y3Vw[N`9\Fe^;kZ0s}%{zyxPYUύvU_YzM$^C;d@:jÃ2Zr€8%2{{ɀy)‚x\yP0WRyeT"MynY|Fy^;;{'cT1}ei%pt݁v}ZvV:UvY MBw:]VDx4a:yf60$|Zk$|=qu3w\Xjr]Tns_+LtbCmv!f: x-i/{>n$|~s;vx,WndRp~eLrYh$Bt(j97vmY/zNp$~xu-wxVPk|j}Oml_I1onArMo9?uiqg0Eys$~Kv|x_xTh r5NjsZG?met@pst9su.xv$j~*wxnxT'e{FNgzFljz>mzx8r;z0,xay#}xڀxSxQb삚MeuEh>li5Rqn~"-*w'|J$}yzxbxQO`;LcnFhTr>#lJ5>ptq0uvq~e%}NzpxxMOK SD́W>]75b*'i1 Ap\tȁvMYUEI#EXB\*<|`5 Fe[+j!BquwK}a[dH-}1]A}aS:}d4"~h+m5"ysKuqv`xNJzCalGxzcBC{e:t|7h2}*l+U~p"yt/Xw8xIYwHhAEhx$i?VySk9zfm1|o+\~@r"8vVxxJt&o4D>uo=lwCp7y r50zis)}uL"w`x\pxIq5vDrw*z|$ yށwxłx1AOgwx<(:d*7܄eo2;h?.j(omS$q!0u~x2y,<>k7pl@3hmy/Oo )p%hsr!ā~vx_-y$;q7^s3fs.s($t$ƀiu"w xx7~w6 ~xD2D~x=-a w'w$>w"xa!$x lx86}|58{|1j|{- }z)z$y$-8y::; ;M;;<<]<<=*=n==><>>? ?O??@@b@@A0AtAABBBBCCSCCDDcDDE/EsEEF>FFG GMGGHHZHHI$IgIIJ0JsJJK;K~KLLELLM MOMMNNXNNOO`OOP%PgPPQ,QmQQR1RsRRS6SwSST:T{TTU>U~UVV@VVWWCWWXXDXXYYFYYZZFZZ[[G[[\\G\\]]F]]^^E^^__D__``B``aa@aaab=b|bbc:cyccd7dvdde3eqeef.fmffg)ghggh#hbhhii[iijjTjjkkLkkllClllm9mwmmn/nmnno$obooppVppq qJqqrr=rzrrs/slsst!t^ttuuOuuvv?v{vvw/wjwwxxYxxy yGyyyz5zpzz{"{]{{||I|||}5}o}}~~Z~~ D~.h݁RȂ=x)dڄPƅ=x*f݇TˈC2n"_׋PȌA~3p&cݏWѐKƑ@~6s,j#aݕYՖQΗ KǘD?}:y6u3r1q0p0p0q2s5u8y=~BƦIͧQըYީ c*m5xAȭ Nծ\(k7{HѲZ(m;ŵ P۶ e6|¸Nڹ g:ǻU*qGվe<[2yO—%lôBĉ^ť2yMǔ!gȮ;ɁTʚ'm˳?̅V͜'mβ=ς RЗ!eѪ4xҽFӊWԛ$hլ3wֻBׅ Oؒ[ٞ$gک/q۳8zܼ@݂Gމ NߏRVY[[[YWSN HA9w0n&cXL>{0l!]L:v(cO:u$_H0jQ7pUBIQX`%g,n4v;} B  I  Q  X  _ $f+m2t9z@F MTZ`%g+m1s7y=CI O  T !!Z!!""_""###d##$($i$$%-%n%%&2&s&&'7'x''(<(}())A))**G**+ +L++,,R,,--X--..]../!/c//0'0h001,1m11212r22363w334:4{445>5~566A6677C7788D8899E99::E::;;D;;<>?>>>?D LT\#f-p8zC O[%i3wB Qa-q> Pc1vEZ*o?V(n@X,rDRa,o:~HV!d.r <   I  V c - p 9|FR^'j3v>JU`(j2u<F PY b(k 1 s !9!{!!"A""##I##$$Q$$%%Y%%&&a&&'''i''(.(p(()6)x))*>**++E++, ,L,,--S--..Y..//`//0$0e001)1j112.2o22323s33464w445:5{556=6~677@7788C8899E99::G::; ;I;;< >M>>??N??@@O@@AAOAABBOBBCCNCCD DMDDE EKEEF FHFFGGEGGHHAHHHI=I|IIJ8JwJJK2KqKKL,LjLLM%McMMNN[NNOOSOOP PIPPQQ@Q}QQR5RrRRS*SgSSTT[TTUUNUUVVAV}VVW4WpWWX'XcXXYYWYYZ ZJZZ[[>[{[[\1\n\\]%]b]]^^V^^__K__``?`}``a4aqaab)bgbbcc]ccddSdde eIeeff@f}ffg7guggh.hlhhi&iciijj[jjkkSkkl lLllmmDmmmnBijFȴ J̵ OѶSַX۸^"c(i.o4v;|BſIPX_¡%gé,nİ3uŷ;|ƾBǃIȊOɑVʘ]˟"d̥(jͬ/pβ5wϸ;|оAтF҈ LӍQԓV՘[֜`ס#dؤ&g٨)jڪ,lۭ.nܮ/oݯ/oޯ/o߯/n-m,k*i'f$c!`\XTO JD>}8v1p*h#aYP H?|5s+i!^T I=z2o&bV Imft2@BCDEGH I J L M  N  O  Q RSTVWXY[\]^_ a"b#c$d%f'g ( h !)!i!!"*"k""#,#l##$-$m$$%.%n%%&/&p&&'1'q''(2(r(()3)s))*4*u**+6+v++,7,w,,-8-x--.9.z../;/{//0<0|001=1}112>2223@3344A4455B5566C6677E7788F8899G99::H::; ;J;;< >M>>??O??@@P@@AAQAABBRBBCCTCCDDUDDEEVEEFFWFFGGYGGHHZHHII[IIJJ\JJKK^KKLL_LLM M`MMN!NaNNO"OcOOP#PdPPQ%QeQQR&RfRRS'ShSST(TiTTU*UjUUV+VkVVW,WmWWX-XnXXY/YoYYZ0ZpZZ[1[r[[\2\s\\]4]t]]^5^u^^_6_v__`7`x``a9ayaab:bzbbc;c{ccde~eef?ffgg@gghhAhhiiCiijjDjjkkEkkllFllmmHmmn nInno oJoop pKppq qMqqrrNrrssOssttPttuuRuuvvSvvwwTwwxxUxxyyWyyzzXzz{{Y{{||Z||}}\}}~~]~~^߀_ a"b#c$d%f'g(h)i*k,l-m.n/p0q2r3s4u5v7w8x9z:{<|=}>?ABÝCĞDşFƠGȡHɢ Iʣ Kˤ Lͥ MΦNϧPШQҩRӪSԫUլV׭WخXٯZڰ[ܱ\ݲ]޳_ߴ `!a"b#d%e&f'g(i*j+k,l-n/o0p1q²2só4tĴ5uŵ6vƷ7xǸ9yȹ:zɺ;{ʼ<}˽>~̾?Ϳ@΀AςCЃDфE҅FӇGԈIՉ J֊ K׌ L؍ NَOڏPۑQܒSݓTޔUߖVXYZ[]^_ `!b#c$d%e&g(h)i*j+l-m.n/o0q2r3s4t5v7w8x9y:{<|=}??@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~????@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~??`@2 OdJ@``LI- 1S60G4X;*```f:@4 SEi@``Y<#i'VFX`eMfdnnnwgFXFX `st``^F_2V @\xelmSusvJJ1+`YRibKbK@ [+(i u uğ}\Be*YDYD@~llS?9@nn̄~\s)]` $_s_s_hbCCnOgZܞ<ˀɀmTHp'p'@0`v9^^TQb;K2hK ō &Kx`xy=(']H]D "::nm utlk~˕ @Xd@A`@ P  z[&) V£HRY7l z}sz@ { A d&3v 8PS@-Z q(8 9d\Tb<[oCoY@_+o+I0gE@@%bqqW5@(A t ֣((]Rw(W ݲv*wlHe%e7Xqhzj|jQ5O7`Rdl˔o]p?3qk2e["p5EsV2\O؋abjVc`.=?`#e#^Q7 3DV6^8``Zl@ ="fWo<Saqo=9! E%EV_cFcDmds&7E<^vjAgXT`;b/B\dżkwjPu|rvlIxPNoFq`(_w09<A=P['gsÞrǝ}zuCTsMAH\\%[$emmg\8Jma~٘A~}H&@/7Rc_PD"8͐bz~RVdWG:$vdj W0`sҬs^vQ0bdb0 +)Kljb,oā؋iďs =43:Ŭ͒ /3W >5/t$݌$®܊-xW`$ &X(& ҂RUN)#@u;d~W2r>d8!:(qx@l\<)Z]hys,.=?K; Ź:KHwt"X{v ;,UCezֲy}O)u});Oi 83GX6S=gbUtzr8{yK}w4]Tg \~q4.V dWܗi2҈k1m2`mMJ݁:,+KlRZf8N(`9Ue= 2=EogHK WT@( F`;[`D2 RR H.@MY\'^aN7[n#:-=aF"]^`E!N4A\Pnb`$c_cQmewCfA#_krbQ`X@bAq8U `h:gGrџorTmz{on%{~ST:]#C7 -0@gjgf Kap1=%`۰-灃#2tZUGMbCXqw y {"{h!k&L?[;bu*Mc\`l gdhiEހ7`'\|="RP GRGIiMPium'vQ.,<@CA%u~< -p9qGW0]\a5|N]%_A(2XAQF WXƶZmAN_UA/!"PUuY_dprTe'BJ>@rVD2^``֬`CQi`t|}ZV{p>tnvwV)]PTbb.4cn(jFTWjyS.FT8o <_Q_ k9jĝu{pyIUs/KWwwˏoDFCet2uP}Y}{t}}Lna ;m\&UUFǕ7߼Hz@Ҁ9~LyYQSw*se`].:,Pviʈ+ (Fm_ YqS!ON=^ܛ6_؛&{ 7u|:oq .۹.%KkqԗY\ۋ_:V4K "M i nY-z )@ @|S8di=Iw!%r5xC(h`~< =euy0y<|E6\(>Cx %_OGLM6E@S_fSmʭefha]QA6'-@JXO IkY XX(n-D9@<@vJ`=!~aj''z4h-#R.+S %>+>K>\FAF4*!I_)`~0>Q&2&9:)c'=4I[P^BEU&n:=8$QQ04A޿C(5H,&o&B0cH#b b2d.0\$+B> GRku18FwIԹK+90H@ I)eH__k"emXaV\-:ҒK2BP?QHS.<KiuOjEh!jDok s*[b?8fxQW2X;[3]z2hC8Oh>9G"_(~fc|]݂s*[2`Ҽ_&!_etd$7|G\Tu5YZRX>͆ÈhѢ v frz~}zOx.x.=Ks|Im{$-$0Lky){2NFt,ZMeH>(2;?'8 NW٩S|QKg@N< 23 8_;9rAj^nY*W{~gDˠ6"k'!f&W_}u i&](egg\h j9M²tuvVT UBJ5D B/0?HIHPXWYRg-"ǻQsXUS?4' j Z*4>A<?v&SuM">u>)''}Qg>۾aY T 6%6UTp4p1l1k <)< k6w 3)=Z38;<-'8FO H*'4{ ?-W2;bv?E|D 10DAز- !-E"%0 $#A=FOGtBN,7=$Y 43 !P–3ݿ4 m2'$86\7\_^\d-DM6#*,,A<ڼA#@ $};W'n:c6c&fh<nr7(aS!BWF Jت?MoP= -F]mI5Eh-X= ofjy¬e\2``] ^`D&:WO`t/-eh CF&:W{x7wuYy|tG~0zEGx)~Nz* x+E|{GôN[+=7f9ꆆz,T b?4 P59V xJc QS0۵ki7սIUڵ9~rm|y}w"{unMub/@m`/|KQ0slg#TGhVlX8]Hs]@!Ͼp#F:5FL2@K9=&<l;Vi1mp+iv_iBɞJH"DPBYHg&tANNkVJY۴v$}tlnnmq|i^teidg 5Lw#v*8Vh{C+="r"98u+@GVݴg:yzc}$՝mM~1|~+MQN( <* ⬒A]ɹdS"Ne9L|Er›n df],_S^i}keFt|enbĴ-CZ>5K?c7VN[X Dw<>kC`G8LFv]MTNcHy/BM.@4$L&r*ַ. 1Vhp}[=.!gH syrvUZ31 v\~.'}3`0(:XY}j:XznrܿL~<:SV8x RK k "U-TOwr{۽ Фb/)zAz& v)'(!o#2"iʧMfi234_9hU:E<V@\A}2¨ s (?S'A,>SۚNS)XAZ@[ߨNx6@۠d136ĕ[7%81K=nn7GGGLExXdNwIyzya{ uHph"gx^au_`,[`_Q_e 6FWvsMXQ#_Zi".l-w8ڢV Q.j| 14?o|]qmUQ&nm}zMyU}Bw#t]rglV{~>}{ vh*<$惛ҌH %ï_#<4~*i~`_\7YWQL&NN{Qw<kw9fd)m\S#XW1M DpAn.;;2r-S05v8Bì}UKjTM4*}6 (S+(fիp'#:}ZkPV1 5 /8=oMT%fLs^N|jwIOJy0S~xX.Q}VIx.,Ny>վɸ*K u|(? I5*GIqCp"&T)6ݥT%2Ah" '#%*7V":M8G'=;|A#DʧDW=P70q ̐P#Ћ&' Y4 PV7S6OeLX`cuRWgm&ggjc\B]VOR)R~NSOOp/SLerYznsNWP y!fԌD2@srqnkN)]A}`p`[@0`s(pIshpcBdpb\b~\"AS}`lk g` :mq:RAsVctUxKLMHJFfAH~<1{@y,?fst@;Ox߀?j([(TQϖŎ%5:iw2;ֻ-- $$yl -!w&w5-.6dY<;=0_J#!r쎺ے%L¿ WEc g}ȸT 8%  jZ2EQ4dϡVt4oOjpZ1Gw{w0]k`1Wh P&M*sx׬Ѣv"JZ\S7gћ8 G}?"Ϩ8Cx m͘xX";sew)ٻ M@9`~Ȳ .+ c!I# y$O"D(ӭrm-ߥ/lК.nv/#̊y !s9D). $jQOvNOjRaR\SVS.ONiEI@PEBE@&g?Wbif#AER{tV Hoqwgbc_WI.cnqr|m}<XI|,jU3`bGbUcPrcwNZKBGWW U 2quNYfJ7pyV`KSp/|Bgh9&z5h3o1u*|w)iz+f3 *PkkqxÆ_vHj99kb) g t$}d2| y zɱyanmcqy`Q7FL)Uac$__䤖r!e7:n,q |Ոha0,Љ"dcPp]ra0!j5d`i2Զoo{?>`72` F%Ix2 ͏+4Ϧhΐ&`!3hf<$ #1}>Ҏ#]2z0ӅRgǗ"Ç&/+t oP+*cNwon!Gbwе!7;@i-N̏O||y~ѓ$y=jDX}AS߿BLm@dE9fU"S$@-?(D:O]SZ`94RoqGmi;a \Z]R"R&Nˎ52O|WiYeRoBLe MWXBY=Y/ʚ:Wq9E9BA\A @=J5RM3z8YfeP{eAzJJ2^Xi'7ʚ$K"{KmkfXv#:,3PxZdfMO2W eɔ/d2u:{N{Px[eGfCPIjhúOUs^%ƮDptQpz*ZgeQO>_ũ̅`xXWrӏː{N[Nk'cT 96%`0fDEYOzLbC 1=%NEO2N{,)O޷*PB(B(%1z0 .4b&C5*e4FgWTJCOd-yq yKx|=y y! sU hWT y)&wB~c5HYFU>lnzlIpz|x7vA)vBc`I]V01rMLlnIQ vB)dJ`Vi nLzэڜ=ѬbgJc|WV5cm}A^\vBre #*_YYԭZ;mrpX$ŭ TItŃW^ncb _>SU:qgWX3Jf8(SMu Vtj\RLRa ]0Kc|pyKqտmMaVLL̫O{&vVGqokwiIȒe./ZOP7DEmm|KevHX9Po];H.DBCJD%D@ΕQ| x#_(wJ.( H8yCSo> 8y6?69*,F,(,и~ur\V2J>!"aS1_]b>J^B/Y}o4.{s ;xѣymWXC _4_@NC;gc!:%Z*wcvNc)6a@<QDl`h g :6ȣlU `@SFv4;Qj7O:M7SRcc3` у ˜8PܴٙPhshsYT9zX7E8i}gA~s<kJ\rSjN9)5Ifhmd4WMH5FtE/Cs:Pfrq offYQ[GBD9E& 'rv@$n}LiWc]\SJ=:ao!Hj ?4d)PVBZ=VLC95v|~ wd^E:XS/PP: KE<830'˙7~ }g\R4)fKOSb3C{$ *?{ F<̑=T<1.*ΝXj~qY ]R@$I90d3 (_v.*F'%]!'#;^5~WT|N* e:+*(847]<}3: Sk6 z[tK{*81DKVjV Re5uNgM`fJN ;01:-$Ky$^tN-;4[dBf=f_#Y5RhŔ`SiS88(x _#P%1O98jqwlz={3x2Xfzd}oqWSC`'RF3:H:ku|iM+ AT" Sw>S51<\:|]44ǪZgZy;@_NU`ZOPT/j@ZsguZQG9GTd+@ji"HihG<\_TL,;#4R xsf nE;dEf`@V~N+E60_~Nnf$g9a;MGJVJQGv9"2X*U|~ e3[5U\?8I{OMJ:4;- %~|rQ-Q0 P9D~DCi:'5.'> | cyRwK7 Gl(=|E;}80Cɽ16)6!{~ZRL-D=#J8C89k4,*9%l{RLE1'A)0$ =Tj:ݰp+ ,p Q0J gA ,+63F~V2f12[+j1+)SԦ$!IDNwB:b,#"E:?>\>78(W7hW$1tG2h/Ȥ,"1\MoQ:-z&1GJQL LQK CTuH\c;OJ5x4,%#>VU ;|,<6NsQU\VWWTAPoPZJ`ATu2/ U<"uOS{Xns@v=wpwmq{!t'lOZD&SV8p{#WPR\ bjyOPmy'#iQm~j`502k3\bU@TZ:IPEF7*/(M~m#b2`^AMRuKw71*#ObY}NW-$[5,AJ:}3Y,% %| xJSOb)qT);|;5.0'M ~) KFF`BLH'V5t4x*~(!*~AL0F@;4$.yl+"¢# z~FLH?<40|)0l%eb; ~bH @8A1' 1)ZG?( ϡ H@@5%Xz() LqMqp y I7@H@8!"v$Hgxh G;?@6 `!)6*6*!&4 ""G%aPzCSiF / #/1221+Bq*]%'ī UI! !Iz1u 04t79:::5XH3U`-/?v&&zG@2t#4S8hHKN9P PPMCnpNh]u2g.W-(/( 7?FNMRmSprt tipF[|bopwq\Oh9KQGpy{M{W&_p!9MX:w\=`m~NOUS738/(FEDt\75PJE@@15 =TfHF@@3 Qe [ N7VH@@5dn  4kSdـl%S :h!O}6dKy2aHvA;y4s.m(g"a[UO J !!E!!""@"""#;#z##$7$v$$%3%r%%&/&n&&'+'j''(((g(()$)d))*"*a**++^++,,\,,--[--..Y..//X//00W0011V1122V2233V3344W4455X5566Y667)7p778E8899a99:7:~:; ;T;;<* >h>>????@@_@@A8AABBYBBC2CzCD DTDDE.EwEFFQFFG,GuGHHPHHI,IuIJJQJJK-KwKL LTLLM1M{MNNXNNO6OOPP_PPQ>QQRRgRRSGSST&TqTUUQUUV1V{VWW[WWX;XXYYfYYZFZZ[$[g[[\3\w\\]C]]^^S^^__c__`/`s``a?aab bPbbccaccd-dqdde>eef fOffgg`ggh-hqhhi>iij jOjjkk`kkl-lqllm>mmn nOnnoo_oop,ppppq=qqr rNrrss_sst,tpttu=uuv vNvvww_wwx,xpxxy=yyz zNzz{{`{{|-|q||}=}}~~K~~Xހ"e.r;~G̈́R؅^&h0s:}DɊ MҋVڌ_%g-n4v;}BŒH˓ MДSՕXږ\ޗ`"c&f(i*k,m.n2xIӠ^.tDΣX(m<Ʀ Pڧc2vDΪW$i6{HѮZ(l:~ñLղ^,p>ǵ Pٶb0uB̹Uߺ#h6{Iӽ]+p? S,uO˜*süNė)rŻMƖ(qǺMȖ(qɺMʖ(r˻M̗)rͼNΗ*sϼOИ*tѽOҘ+tӽOԘ+tսO֘*s׼Oؘ*sټNژ*sۼNܗ*sݼNޗ)r߻N)rM)rMN%[3i AwN&\5k CyQ*`8oG} V/e>tM&]6lF|V/f ?vO)`:pJ%[4h9m >rCxI}N T&Z,` 2 f  8 l > s  E z  L S%Z,a4i;pCxKS&[.c7k ?tI@~7u.l%c[  R ! !J!!""C"""#;#y##$4$r$$%-%k%%&&&d&&''^''((W(())Q))* *K**++F++,,@,,,-;-y--.6.t../1/o//0,0k001'1f112#2b2233^3344Z4455V5566S6677P7788M889 9J99::C:::;:;x;;<2">a>>??Y??@@R@@A AKAABBDBBBC=C{CCD6DuDDE0EoEEF*FiFFG$GcGGHH]HHIIXIIJJRJJKKMKKL LHLLMMDMMNN?N~NNO;OzOOP8PwPPQ4QsQQR1RpRRS-SmSST*TjTTU(UgUUV%VeVVW#WcWWX!XaXXYYWYYZ ZHZZZ[8[t[[\(\d\\]]T]]^^C^^^_2_n__` `\``aaJaaab8bsbbc%c`ccddMddde:eueef&fbffggNgggh9hthhi%i`iijjKjjjk6kqkkl!l\llm mFmmmn0njnnooToopp>pxppq'qaqqrrJrrrs3smssttUttuu=uwuuv%vavvw!wawwx x_xxyy^yyzz\zz{{Z{{||W||}}T}}~~P~~ Lʀ HƁC>}9w3q,j%c\؈Tω KƊB8v.k#`ێUϏ IÐ˲Y.uJصf;ʷX.v ]QF:ݽ/Ҿ$vǿkaVMŸCÕ9Č0Ń'zqiȻaɳYʬQˤJ̝C͖<ΐ6ω0Ѓ*}$xrmhռcַ _׳ZخV٪RڦNۣKܟHݜEޙBߖ?=;y(bK5oY C~.iS?y*eQ=x*eR@{.iW F5q$`P@|1m"^OA~3p&bU H=z0m#`S G:w.k"^R F ; x / l # `  U  I>{3p(eZOD:w/l%bXMC9v/l%bY"g 7 | !!L!!""a""#2#w#$$G$$%%]%%&.&s&&'D''((Z(()+)q))*B**++X++,*,o,,-A--..X../)/o//0@0011W112(2n223?3344U445&5l556=6677T778%8k889=99::T::;%;k;;<=<<==T==>&>l>>?>??@@V@@A)AnAAB9B|BCCGCCDDVDDE!EeEEF0FtFFG@GGH HPHHII`IIJ,JpJJK=KKL LNLLMM_MMN,NqNNO>OOP PPPPQQcQQR1RvRRSDSSTTXTTU'UlUUV;VVW WOWWXXdXXY3YxYZZHZZ[[\[[\+\p\\]>]]^ ^Q^^__d__`2`v``aDaabbUbbc"cfccd,dmdde0eqeef4fuffg8gxggh;h|hhi>iijjAjjkkCkkllEllmmFmmnnGnnooHooppHppqqGqqrrFrrssEssttCttuuAuuuv>v}vvw:wywwx6xuxxy2yqyyz-zlzz{({g{{|#|a||}}[}}~~U~~Nˀ Gā@~8v0p6x>†Fɇ MЈS։Yۊ]!b%e(h*k,l-m.n.m-l+j)h%d!`ޘ[ٙVӚP̛ IŜA8v/m&cޠYԡNɢC:|BƥIͦPӧV٨\ީ a$f)j,m0p3t7x;}@òFɳ LϴRֵYݶa'i/q8zBǻ LѼWܽb+n7zDQ_£*nò4qĮ'dšXƕMNJBȼ7tɲ-kʨ#a˟X̖P͎ HΆ@~ϼ8vе1oѮ*iҧ$bӡ\ԛVՕQ֐ L׊G؆Bف=|ڻ9x۷5tܳ1pݯ.mެ*iߩ'f$d"aYw#\Az'` F,eL3lS;u"\ D~,gO8r!\ E/iT>y)cN:t#] F/jS=x'aL6q ! [ F 1 l  W  C ~ .iUB}.iVC~0kX E3n!\J8t'bQ@[8  ` !>!!""f""#E##$#$m$%%L%%&+&u&' 'U''(4(~())^))*=**++h++,G,,-'-r-..R../3/~/00^001?112 2k233L334-4y455Z556<6677h778I889*9u9: :U::;5;;<<_<<=>==>>h>>?G??@%@o@AAMAAB+BuBC CSCCD2D|DEEZEEF9FFGGbGGH@HHIIjIIJIJJK(KsKLLRLLM2M}MNN]NNO=OOPPhPPQHQQR)RtRS SUSST6TTUUcUUVDVVW&WrWXXTXXY6YYZZdZZ[F[[\'\r\]]R]]^1^{^__Y__`7``aa]aab9bbcc]ccd8ddeeZeef3f{fg gSggh3hhiimij jWjjkAkkl*lwlmm`mmnHnno1o~oppfpqqMqqr4rrsshsttOttu5uuvvgvwwMwwx2x~xyycyyzGzz{+{w{||[||}>}}~!~m~P2}Ɂ_A׃"mO0{Ɔ\=ӈhH݊(rQ0zōYTlɐ'>Ukǔ$ݕ9Nbuљ-@RduО*ߟ:HT`jät̥$|Ӧ+ڧ16:=?@ACDFHJLNQSVY] [E/~̽hS>)xdQ >Í,{jź ZƩIǚ:Ȋ+{mʾ`˱S̥H͚>Α6ψ.Ё'{"vrpnopr v$|+ۂ2܊;ݔFޟR߫_n#~5?_@`!Bb%Ef )Jk0Qq7XzAb *Km6Xy"De1SuAd1Tv"Eg7Z}+Ic}2I`w.D[r*AXo(?Vm'>Um'?Vm)AXp,D\s1Iax7Og&>Womft2@BCDEGH I J L M  N  O  Q RSTVWXY[\]^_ a"b#c$d%f'g ( h !)!i!!"*"k""#,#l##$-$m$$%.%n%%&/&p&&'1'q''(2(r(()3)s))*4*u**+6+v++,7,w,,-8-x--.9.z../;/{//0<0|001=1}112>2223@3344A4455B5566C6677E7788F8899G99::H::; ;J;;< >M>>??O??@@P@@AAQAABBRBBCCTCCDDUDDEEVEEFFWFFGGYGGHHZHHII[IIJJ\JJKK^KKLL_LLM M`MMN!NaNNO"OcOOP#PdPPQ%QeQQR&RfRRS'ShSST(TiTTU*UjUUV+VkVVW,WmWWX-XnXXY/YoYYZ0ZpZZ[1[r[[\2\s\\]4]t]]^5^u^^_6_v__`7`x``a9ayaab:bzbbc;c{ccde~eef?ffgg@gghhAhhiiCiijjDjjkkEkkllFllmmHmmn nInno oJoop pKppq qMqqrrNrrssOssttPttuuRuuvvSvvwwTwwxxUxxyyWyyzzXzz{{Y{{||Z||}}\}}~~]~~^߀_ a"b#c$d%f'g(h)i*k,l-m.n/p0q2r3s4u5v7w8x9z:{<|=}>?ABÝCĞDşFƠGȡHɢ Iʣ Kˤ Lͥ MΦNϧPШQҩRӪSԫUլV׭WخXٯZڰ[ܱ\ݲ]޳_ߴ `!a"b#d%e&f'g(i*j+k,l-n/o0p1q²2só4tĴ5uŵ6vƷ7xǸ9yȹ:zɺ;{ʼ<}˽>~̾?Ϳ@΀AςCЃDфE҅FӇGԈIՉ J֊ K׌ L؍ NَOڏPۑQܒSݓTޔUߖVXYZ[]^_ `!b#c$d%e&g(h)i*j+l-m.n/o0q2r3s4t5v7w8x9y:{<|=}??@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~????@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~??QE|2#[t9hdX]j3YqQQWOJ>09Hdq|*j8JFTx*@sTScdZCSnSQ+LF:`#Ar~ x1wTgTg q~Dr7aaBPBVV^SP@=rL_୯2o]i8/=YVL[ydyЅ9x~D`mt]`CX,V&}Rm:!|A_ u+,wI`HaH 2oS on4YX eA/hl8{7%_7s]tL300($\pL[`Rs,TU q ``_0 :`*>(&I:4Rq_JK2ꮕx2Vdj` KA]<%6@1T#y9 R!lsBRQ_S ;.PXyX1wadUj^9iVURtS7Xq-|ם{ȏ#3Eg~4?YYbzLN)w e c{SCfUy?Penuu3:^]] d)7BmLoj[>/+t!9/2zmf?/;[Lkg8#k)`}~*?s @w$@lm]?`,Z%C;beK<>ˢsӫ׹6;݀ }ks ]Yz`=aM$_T)R+>;O`}0`5 X e0vc4yI<872c0}^ O)?D\_|uav;UP0S8c̎-XF(4 .LdY6iU'> FnODIԲrɪ&:z qlub9 f$e-:zFcwWŹYYm=3(thB @0;#Zm z  1<} Juty{TU`o]z] ik `W OS@@\q$\%*5X^x_jNQ~O0mx}j`Y d17T\{|jUkC$Lr<GR*=^>h[yyMOFw/0 mͰ:F OXL8\g"*E2{A=.92h]zTD,}j.1t)a}_h p8 :܃8JUPZ A/<>4: ,,}G]W bkjhqZh ?l8Kt@NAC >O.9\@3wo)*j4KBt JIW'Neh/AMnn5dYkVlXRRQQ3;~>Ay_lĸw3~`v(OK#f'1prS^x`d\QP}RV/$>1@a[VnAmz@>p$/KS4d}Dlhzic[GW5ەnW|6oD{uT#_MR];}h_z-{y}kY?eʪvp |FzNr["7a[0<>}bV~7&!|Ƹ~E*[~q hEa7bbphHfB0z P79"xmlF\u` t#&j37cVBunA'=9n {ܢ@Φ5lu" /[I^`)^7#0PFJqz`j^3&-Y;?V^|^}f je,6<44g1<$lWɅ 5l.B?r~ѣ-Z& `,- jq *d=Airx{4xNǎ`Ⱦ>ǻ=(L."bx#Y#8 "C4L':Y>#S&{9Wy`;al ro \ VS?N@AY72w!u/'& 0E@:^ۑE9 =I<G" 4 E E:+C?E @ 7X+b1;-@'e$eS$Sh#);)(2y4pAlAl %`(^M``YTO9O#P;8z8޿Q/ʗ`jszf~4{! qBG\ jDkahcE" SOoaW[`#0.oIacl>wC~`*[U@3GXv@sK_lvt&s2l5<`"n9z^BT:u%-)QM\i4}^Kxzs~X`oFH|cX)ՏFx (RR?1}My&TztSJ^n=x3 )XU3/2z =~s𺝂ZyXImF~p{bge,hi$F@hK nf,F,f7Q䀧#\̗h s(h,~]\q1W= vm\r1̡>"7? emebYEzyys3pp>d=Y #QU+KëL0g g-:\JqSo`Q&)dڄ|u1k(t~E[,yGm|\Cͩ2Mpo X ZYX{+?18 WwBrfbpz ߜG gـ0jd8B 9H FbB@+"v *Ͱ'B0pO\X8`"h+ 4ַ Lr l2IdBOo"A9<68 c)Z*)Bs9,:@ͣF tM -r'un "'):B,F!C:d.x1>]+d!2$p#" 3U(Z.sɰ=!NA9@:K0J,)9$@ ttF!gig@0s G**nXHZZ<`V MXTPv887$<17)rI6U6_ӮngJmmC5!JfC``^ nQaSW_l=D,+GqVaEip%r5rN2#cO! 'n,@eajbuzml i8,F?zόV/a*GkFWsYwvwu ~8J)nvsP6Ihx~;W+a,K]PY)<H"" KJl _3[ġBqGOM ^ Fά]KΦlr2)? !Q?@+B4a<'>72~'p&8!&ԿV'yABM0l)~(Sv ˙45Ta~pr 8xhv$~g $LX=g$?TLV4z+v;zNRX(3AJ";غLBWin`\inlއX}q =i~~*BB7ELB~`*d7?;UBnM-iZA H<Cg,>A5 $p%n~1O!]#/ v+ܜ. IY eSi$E=A58,9)lH(W B]0\x&Al2 >6,-$@=F =p =Exy}e?QQ6U!L=+uKuIp;'J4bWE^ji&~k"'j4w揣la[ThO@Gh+S9Sbaէw,. %̰. > PSF{n)eª**0=W)?oW6d ܙLtYO\JKF,}@z+le L^X1[G$lRU np{Ly/^!c>.9k-N6$%D!?uf\{`X}!@grdA+k4/f%].L@ Z  q (oKuWA8 "[9-8GMo3a888941fe'mH["HN$ßu%D;i(5 JC$'=K8^=>vI>z< &#@5#/H?,f$N!DfEC`F@jNADDH.S(ɍ%2rc*b+Mdpwjop l!eUa` afl\qqlrw$N:Y0bTWu7wl=\y[X}j%y~<Ewb}oEzqR:ۂz$wfAJLd8߷|#ʏ3u;EMw6caQ[%W#QbYGߐKvt`(h;`Irpx,Рٱ^^q ꨸ a \. ﷔/K\v-0#ydcRJ#GC|??zRnW9+T6ɶ͚ gwK{?{+rtB;z{7{~ tcpvkl*4>Ďˆ2IX<,U;Gd4\KX7W_RaDY.^ d6h*d#˹]jpgi%#+vJ8M24F?7у&ȓ0p6M>EdIfLrQGX-A;,8{ Qim%No!̽$ޕ` Gۣ|Qy :;,09!`te 7~Ҏ q> Dq:5?ٓb]-A3$ 1>S A tW p G }W)O4بkUlF?b3Q5Q'_9:@5E\ENvN M< Z = Ŧ .L.C$'m5(M*PeS-+)%ٝI 1=2/)t+(O0V(I(_.-,'ݭ,e߯ ь [3cX82I 1)M03G-m_3p5j4cL3$Au qǍDd?9$$6= 7>!:Z9x?=Al7,ȼ ŴKtu `.CGNR >wX@]`d|FI5zYp0=_/ ,ё(ן&`a: RqM쏔ᨕD9p~,hÛ"qSMr~iۛwzyg-QYR.GCA߮ JT(~I `6}3h*^;_rfz(lyourvqCtlv:ˮʝIKIY|R%R/OF׽EXjEEDHNR%Vȼ'ǼoB)hz``d1:S}'q+8$\{10BG*`m!(;.)Z4ƣŢc(e0ϦjBOE 5>3~ Lr ~ 7 *joe!2Ƈ<]Sbsz|jS j6$%!Fp "Z, 5J l , Z&r?L'=L}UZ36H+ ;Mqqbr DX̓מYD iy F_$.<< p p 0u@[y O%,vG)![VV [#8 @LYnLL! /DӇ - 6 'L"2!2Wlw #aszcV- p'G?W&&P'6K+ A&^P)'#U!$J K(DX.- I)!$E)S= ++Z ,|,C+oq+&\ 3 `;,$8 7[0F_-/6i3TR1xs65J9Cg45X/4!'i&0.+6BWBJY&&@'c=3HAGIfZ@EيE5̕iDq BIC=ÑFRN܆TMdNK^QKpe%N7h S0PMRewVglPn4PejksOg6oWknlgtpj\g\a8eq V ,B9w|v_!lψ{Yh|yh^gsilYO_KF0B7Wr1t.tx"va iu.,m%EtiQWO=VyaAC!NЅ_ lǒΈ ߋډ`I$Bmr|qh{8etxgdh#k]xP`QOKϓ֦Vf.mxܪU+'UvqJI8OWu_sNb{peWm2gڕ[ѡ?$x+)eH$;t~1ο&0-1_K47w=A*Ey+P-۪/M~{bh:TC9+sg#qWxkCPLF# %wҰjѴzsL^;C-'b mc*Vw Sʟd c!SYXѼ~EƞhًOG6*M 8 z, 6vTI$LUti; ȟs#YN6 `#S  +/KK n$rH }b?6F/*bb 1*E`Xc'*S[@ XVTk6 6Oy̋M'ޱkhʹvC3 = C#\ ?_)OS g3~,=ITp/4 8 Lmb{,gIC !) %O>"a{jR?p&Ӣ"95Y)*,Y$# 4&!$'\cJs*#'&#7 å#[ e'4!4z8L , .'**A+zޱ`t)/,I)"RF. 59';:"@}GcAA"NBB !(=.fը 9rԲ5*HIh_Mj!aca^udYh=OQ2PkPfQzձI 3:=H^WyN[SnJQaŪTUg@G}6uY-( e4fZeOdv`Ʃ]DŎ7Z eBEezôs}{s'R ِw԰z0z4vmrxy U[u 5Z_jvpRhöNaHS@^^WUmVrqOtLRti(s M@(|u{hlI;B|rF6Z47]?HvHSptNk~RiTʖ4$1+#$ylg6 TbDA).j,0!';,4{/33B/Cp[A'L ڙ`Ƴ  BOƛ4;*|~gP.2J~r[ae'^ةɄNr'\fDh* U.X%M-a'-|gQN5f F-QoL=149] ss֠YPW@6m'-L0` 4 Wi 1TASS e9}+ Hhexw -"SF  D J,2AtA7L5D5&E7Հ~A'$`$>$b ' $+9)zLxbYP^uN_L`6ߌEaD؄DNA\>,627m"ueBjA@Zbwf%4z( ~T`7XJhVKSM(AJWz)I;Ym:43CoTi>3_]&of$ssy^zy vj ʴmgjie`VZ:uZe`Ka&M:jM[Na?\Σ9[;YVkESTTa(SsaPD`r{\F$G- *! g2}Yo`~ i O5~A`<4SdLhw!2w.<.L]-sP1ۃz7%i1j@)6HYrtHФjdKib!8L"0B4Vq݈3?3Vkdg)2:OoFcV}pɎH@L  +y40,תDMXn:SۊvO,anmAmK   4Lc<MR$ր'q5nK9i;*]j(h'w%Hū Ty* n\7] 7Sz VzsE3^L+ITFuUAeV<<+ 81,M#b:h+I\N8. Vj.P^3/QJ9δ2?SD;tf&ttoHdH#H2@:~o:hG9JO13"Z/9GSRK!"GI & Vf&YbOfY czZ^."XdO}mJNbYFZSKs@zQAm<OrS/O(=R( PA,cM!7MEKRKKIIm!qd[jtTURF$\6r:oN zbIy؈ zҽ 7x5 dqf#3[,"[,Ž}\}pwf^`bMe3nwdNKT~>!x w Ķx7"{ltGX*w @"b \#Rzz&mcA4gtzΆdIwN2կ8Ɛ0M[׾ܼؠ N7p癉[EB-)kѩVE`Gkն}gQ0:w"DR!qD]'pvTGi-ɬ>t|^qYE*UF9<'DDX)gj{{ U'^O4AԚPҿb6qw{Ƭyw}j~6aޓ!]/>#QN(Ұ^ϫw}ESYN<(Rݼ(ڪ9~pJ9]R4x65/>8T t7 b1sBQvT/h.bƯfN!oӠN(d579I[Gq |wAui e ic+F2+R=a7Mhu~E3r &x Fm&c~/_!1ْ מ54'A5Z++s#C\n al,jQg$J[9BBChCi? E@Ҥ-0*& Uit 7\Yw P/bJ4WM!D#*B? >A% RGay`O\&Ș?S$@W:1/on,Y.D(E:[@vK;-m6J3l#61(.A!OHx HNMRI#IBpY2=U2_ NbW{NR^GyJ[B8I`#Za- mk>h-pTiuh,l_QQ mn&bmYUWSZBnU'q*dpEz*DEQq0}bǠt]kij'zpyV|@lbigRNjj`4xR)IjtΩW@v|`uRpzY,{A|?& Zkj4;\\KJDʫǁM E~VfOE,6Gx7J'JO@^W/W׎EGs=\4F0HEm.K=^vMZh0E9jTó: {2547IE`u ђ  J++r6BQTcz"+bjx NihӨ̴ jBJ=',2j?OcCr{,O?w~;Cj}l<͇Wˣ d.W=BwNT@d~G9ۆuwիѓ?Mº'W6yEX!mDR[QtxxJ)Ɵ o C+P;I7}]C}.~ubljJ'PYf}/p? kQThxw5ipCp:Էkcb_bY"W#8ЧO' |'i!]T6mZPYIv X(WPi#W@-DZ,@.?^"bi e!&[zicrnO U ]E(>?#Gl;q)I:xh6ɖ/ *QBF @ z?a3r5}0(+|&`!M!z:J3 e//na_)?&D$"E %l-/BE{(;%8e1N.%9+*4+6k@@B@$:~/1$m.PVvMqCCDV/G X g+i~6LB.TgYDܬz 1'3@SiiwM֝Zxzr=ǁ^h'T#@"0q?`T lM^ +Txo^n!O/ k)&7-E}Z~{yRwmlmkCx(Anyo-m;hMQi]k3i"o.Omo#iRd8`=`Z5) wuf.$jZR2V)C'U+`RTZ]6G[Y TUOjmĥ~nRyd$T;`nIi()Eh=BsZXD=CD BF\@;s+|GPalhA R?8v4:r1r\/*r"##){,&&n. VZA.b! )N<.WwG:^% 5L Q8Q:4x/\(ME#k0!F7%1W 1O12`.qX1,(v'% 6DJDg~:YO39.$1;w<&.@wKQ O$P<MEfNftPKƹMHpLU6T37a{bIjX8QR;T"]ggjkX#voEp;ox wyu=dLpyk^$i\, Z"Q: Xqul@HE1{׉-a5I4E ăMRǽ.ˤEV[nΉs޳C}ao2WIB1V om $Dn5KIη[j-jAy രte[[o>>  l)^4@s}Sl>>0Wj6}oЈw2߰r91 '}J&2}>;|TrcPx~,wۢr:kqkb> #1;}?F{X[~yق<A$xzqj*d0#[v*k7gAK{iWhi@mjޗh`\-ŁC q5c"X.wT>}UsZU?X8ZT \[WS(3t`cR hG#$4B~4@NC|B"INN&JG[1,l~,XfQhA 5j2-1Fe2w/3cم98o4 ;"J[ _r @VD.'U&+$Mi!| pڸxG 6a" l #Q!}!G`L 6 ! 8 ) h[TJ= 0 ֭9/f2=.n'T J=3'n +@-X bo5ҳ5j;. B}:S_d28H-+h1&X(2lR+'5(k]#wX&i$p!KPEnET=<6%8PApA :Ni9VA*8Lb2s63C3)! Y5~Y^`OII:2KUK[XXG'WOAPQ5j`TKmeT1P,iO3}gqbV\?\%iU@rzd$"5!V]pԣap[?u%dnL p1| KXKr)=|rSidնjkq@vsMWā@=,v8&D9/N8`;okg'H9RB]f5N9 s}9.~l=Q `lk~ߧS8@ xMrk'f2 jdBM hjXGlRt6opq;nBlc -y sj%e 2I cJC g\k|npQnulkug}{ s>1ja#c1 aF e|api.m9gnk~e O[[#x|m*_~UM*FR.;]UXV ~,X$$\Ϧ`Vo`OP1nz]s ObkEz B2AmMCuE+E&M,F @GxaP? 5/42+/E1Iq 03 0~96~20zten'UB01(%"$Bzqse} e} aJS-6!::" IO |<t d6qU#@ +e" $;IK|*? }(;+)f M6M7H^r)SkJ9Zx 馄ʂll7:v4Zc,A% * "#tX3XQx GJ^h+@VOS8r73 3:p5z .*@(_K$,q$Ъ $% UyU]%L"EE-GQORjOM?)yJDCG"g"Hqp D3PEO:7v'5dm`7S'Zs;[!d^l7 q r" uJ2vYRxx))!nxO| sa#nHo/zM*ewCwOS/wit(zB#pVM=Ɏ'. ['J:`Q\yƘr**&AgF2d}BLg7xA(D0sBS[şo:DΕ8uEEF.[@n%R 7eJx/]Bp(V ;i ! O }  5 c  I w  / ]  C q )X>l%S :h!O}6dKy2aHvA;y4s.m(g"a[UO J !!E!!""@"""#;#z##$7$v$$%3%r%%&/&n&&'+'j''(((g(()$)d))*"*a**++^++,,\,,--[--..Y..//X//00W0011V1122V2233V3344W4455X5566Y667)7p778E8899a99:7:~:; ;T;;<* >h>>????@@_@@A8AABBYBBC2CzCD DTDDE.EwEFFQFFG,GuGHHPHHI,IuIJJQJJK-KwKL LTLLM1M{MNNXNNO6OOPP_PPQ>QQRRgRRSGSST&TqTUUQUUV1V{VWW[WWX;XXYYfYYZFZZ[$[g[[\3\w\\]C]]^^S^^__c__`/`s``a?aab bPbbccaccd-dqdde>eef fOffgg`ggh-hqhhi>iij jOjjkk`kkl-lqllm>mmn nOnnoo_oop,ppppq=qqr rNrrss_sst,tpttu=uuv vNvvww_wwx,xpxxy=yyz zNzz{{`{{|-|q||}=}}~~K~~Xހ"e.r;~G̈́R؅^&h0s:}DɊ MҋVڌ_%g-n4v;}BŒH˓ MДSՕXږ\ޗ`"c&f(i*k,m.n2xIӠ^.tDΣX(m<Ʀ Pڧc2vDΪW$i6{HѮZ(l:~ñLղ^,p>ǵ Pٶb0uB̹Uߺ#h6{Iӽ]+p? S,uO˜*süNė)rŻMƖ(qǺMȖ(qɺMʖ(r˻M̗)rͼNΗ*sϼOИ*tѽOҘ+tӽOԘ+tսO֘*s׼Oؘ*sټNژ*sۼNܗ*sݼNޗ)r߻N)rM)rMN%[3i AwN&\5k CyQ*`8oG} V/e>tM&]6lF|V/f ?vO)`:pJ%[4h9m >rCxI}N T&Z,` 2 f  8 l > s  E z  L S%Z,a4i;pCxKS&[.c7k ?tI@~7u.l%c[  R ! !J!!""C"""#;#y##$4$r$$%-%k%%&&&d&&''^''((W(())Q))* *K**++F++,,@,,,-;-y--.6.t../1/o//0,0k001'1f112#2b2233^3344Z4455V5566S6677P7788M889 9J99::C:::;:;x;;<2">a>>??Y??@@R@@A AKAABBDBBBC=C{CCD6DuDDE0EoEEF*FiFFG$GcGGHH]HHIIXIIJJRJJKKMKKL LHLLMMDMMNN?N~NNO;OzOOP8PwPPQ4QsQQR1RpRRS-SmSST*TjTTU(UgUUV%VeVVW#WcWWX!XaXXYYWYYZ ZHZZZ[8[t[[\(\d\\]]T]]^^C^^^_2_n__` `\``aaJaaab8bsbbc%c`ccddMddde:eueef&fbffggNgggh9hthhi%i`iijjKjjjk6kqkkl!l\llm mFmmmn0njnnooToopp>pxppq'qaqqrrJrrrs3smssttUttuu=uwuuv%vavvw!wawwx x_xxyy^yyzz\zz{{Z{{||W||}}T}}~~P~~ Lʀ HƁC>}9w3q,j%c\؈Tω KƊB8v.k#`ێUϏ IÐ˲Y.uJصf;ʷX.v ]QF:ݽ/Ҿ$vǿkaVMŸCÕ9Č0Ń'zqiȻaɳYʬQˤJ̝C͖<ΐ6ω0Ѓ*}$xrmhռcַ _׳ZخV٪RڦNۣKܟHݜEޙBߖ?=;y(bK5oY C~.iS?y*eQ=x*eR@{.iW F5q$`P@|1m"^OA~3p&bU H=z0m#`S G:w.k"^R F ; x / l # `  U  I>{3p(eZOD:w/l%bXMC9v/l%bY"g 7 | !!L!!""a""#2#w#$$G$$%%]%%&.&s&&'D''((Z(()+)q))*B**++X++,*,o,,-A--..X../)/o//0@0011W112(2n223?3344U445&5l556=6677T778%8k889=99::T::;%;k;;<=<<==T==>&>l>>?>??@@V@@A)AnAAB9B|BCCGCCDDVDDE!EeEEF0FtFFG@GGH HPHHII`IIJ,JpJJK=KKL LNLLMM_MMN,NqNNO>OOP PPPPQQcQQR1RvRRSDSSTTXTTU'UlUUV;VVW WOWWXXdXXY3YxYZZHZZ[[\[[\+\p\\]>]]^ ^Q^^__d__`2`v``aDaabbUbbc"cfccd,dmdde0eqeef4fuffg8gxggh;h|hhi>iijjAjjkkCkkllEllmmFmmnnGnnooHooppHppqqGqqrrFrrssEssttCttuuAuuuv>v}vvw:wywwx6xuxxy2yqyyz-zlzz{({g{{|#|a||}}[}}~~U~~Nˀ Gā@~8v0p6x>†Fɇ MЈS։Yۊ]!b%e(h*k,l-m.n.m-l+j)h%d!`ޘ[ٙVӚP̛ IŜA8v/m&cޠYԡNɢC:|BƥIͦPӧV٨\ީ a$f)j,m0p3t7x;}@òFɳ LϴRֵYݶa'i/q8zBǻ LѼWܽb+n7zDQ_£*nò4qĮ'dšXƕMNJBȼ7tɲ-kʨ#a˟X̖P͎ HΆ@~ϼ8vе1oѮ*iҧ$bӡ\ԛVՕQ֐ L׊G؆Bف=|ڻ9x۷5tܳ1pݯ.mެ*iߩ'f$d"aYw#\Az'` F,eL3lS;u"\ D~,gO8r!\ E/iT>y)cN:t#] F/jS=x'aL6q ! [ F 1 l  W  C ~ .iUB}.iVC~0kX E3n!\J8t'bQ@[8  ` !>!!""f""#E##$#$m$%%L%%&+&u&' 'U''(4(~())^))*=**++h++,G,,-'-r-..R../3/~/00^001?112 2k233L334-4y455Z556<6677h778I889*9u9: :U::;5;;<<_<<=>==>>h>>?G??@%@o@AAMAAB+BuBC CSCCD2D|DEEZEEF9FFGGbGGH@HHIIjIIJIJJK(KsKLLRLLM2M}MNN]NNO=OOPPhPPQHQQR)RtRS SUSST6TTUUcUUVDVVW&WrWXXTXXY6YYZZdZZ[F[[\'\r\]]R]]^1^{^__Y__`7``aa]aab9bbcc]ccd8ddeeZeef3f{fg gSggh3hhiimij jWjjkAkkl*lwlmm`mmnHnno1o~oppfpqqMqqr4rrsshsttOttu5uuvvgvwwMwwx2x~xyycyyzGzz{+{w{||[||}>}}~!~m~P2}Ɂ_A׃"mO0{Ɔ\=ӈhH݊(rQ0zōYTlɐ'>Ukǔ$ݕ9Nbuљ-@RduО*ߟ:HT`jät̥$|Ӧ+ڧ16:=?@ACDFHJLNQSVY] [E/~̽hS>)xdQ >Í,{jź ZƩIǚ:Ȋ+{mʾ`˱S̥H͚>Α6ψ.Ё'{"vrpnopr v$|+ۂ2܊;ݔFޟR߫_n#~5?_@`!Bb%Ef )Jk0Qq7XzAb *Km6Xy"De1SuAd1Tv"Eg7Z}+Ic}2I`w.D[r*AXo(?Vm'>Um'?Vm)AXp,D\s1Iax7Og&>Womft2@BCDEGH I J L M  N  O  Q RSTVWXY[\]^_ a"b#c$d%f'g ( h !)!i!!"*"k""#,#l##$-$m$$%.%n%%&/&p&&'1'q''(2(r(()3)s))*4*u**+6+v++,7,w,,-8-x--.9.z../;/{//0<0|001=1}112>2223@3344A4455B5566C6677E7788F8899G99::H::; ;J;;< >M>>??O??@@P@@AAQAABBRBBCCTCCDDUDDEEVEEFFWFFGGYGGHHZHHII[IIJJ\JJKK^KKLL_LLM M`MMN!NaNNO"OcOOP#PdPPQ%QeQQR&RfRRS'ShSST(TiTTU*UjUUV+VkVVW,WmWWX-XnXXY/YoYYZ0ZpZZ[1[r[[\2\s\\]4]t]]^5^u^^_6_v__`7`x``a9ayaab:bzbbc;c{ccde~eef?ffgg@gghhAhhiiCiijjDjjkkEkkllFllmmHmmn nInno oJoop pKppq qMqqrrNrrssOssttPttuuRuuvvSvvwwTwwxxUxxyyWyyzzXzz{{Y{{||Z||}}\}}~~]~~^߀_ a"b#c$d%f'g(h)i*k,l-m.n/p0q2r3s4u5v7w8x9z:{<|=}>?ABÝCĞDşFƠGȡHɢ Iʣ Kˤ Lͥ MΦNϧPШQҩRӪSԫUլV׭WخXٯZڰ[ܱ\ݲ]޳_ߴ `!a"b#d%e&f'g(i*j+k,l-n/o0p1q²2só4tĴ5uŵ6vƷ7xǸ9yȹ:zɺ;{ʼ<}˽>~̾?Ϳ@΀AςCЃDфE҅FӇGԈIՉ J֊ K׌ L؍ NَOڏPۑQܒSݓTޔUߖVXYZ[]^_ `!b#c$d%e&g(h)i*j+l-m.n/o0q2r3s4t5v7w8x9y:{<|=}??@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~????@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~??F={rP`ii&8֒@?JjrLL}Qf `pp5oup'83Zll`s@Ilٍ,xs[vo.>P`uQF*tetpul6OZzNi}b}O@XHqkoz {Э5yxyioUzw::{ >7$Hrivy'2[Z9:EKkً c|jz"dJVr{:^5If|t|tW_ y y-NyAX3laa~t񁇦ٻ"I9vÆ /ɀ<KEt4#@p`}`53Ο@mXwBI$ u0ix]D/@<^vT`Z@Tm΍ћh[/󥕼uAcN9WNfBEeOs,O@b JCs|@=a>rW G|Gꅝ<~딛533쩙+1$w*7;#NHNh#G{ȡ;.)qM󚴺!J]^鍥]^6a9蝚  }S*:+YDX͹ZSinr sؒ:%4_(y2çP? [5C0(,쳖(푓|&p퍑0(KF4@'LNTm`%PfYXuNZF=.?;# 8(9?0?g9xk@XLvǖ k~1E "zGT&yt[kSgs]qV PIЂ ().>ϻt_^EZ f "vRʗ;w(uMFk{dK"_*.y@b{@*;m^Xl4sHwxxzzxFV^/BaY{)aF{ ,Yq ,n|T >WVdF>`h ej0lzn O%0.~%GT\!@+]<+nZcyfcA-46 CIR{T1X<\tS_,"*/kOMG 2F3OE3^l8u8Rh-dq|/VX]Ӎhu0bג{W O'J#EFR0 1>ia~z5ee; ԹQ^r.<3W褠GaTM4`Twإk:X?쏫YkrM*jla̙ W虗& K/? He՚h{ÖĀwDOQ$@C7EdJ1S뗘r-6-*}(*  K+ 6$? Os >IUdž] zsD`0W>gP+HqCɢ) Ν*ش-4G OHQ~v\aZT*c`j*stE$xyхJmzeL,^hsiXA4ļ[]>~)>h(#z4%F,mdźnegtx`yd$xy9w $.@fcw?)p]=n8NUIj_c6"hEkbMlY MԻ/"A[R"-7D Y9M_l_x=~wH Ec]OTqX[  1 0*H0.UBYNZzk!t}<c1Xj:M9W?DY~Il$W,@=%9FKTY[g[pz][5ӣ(%m$:(6n17M60Oebeb[ oln))@Ymddr鋄|3a`^&m%ϛlO*l{g-~&TodntjY :>r䉨xB&Uv$]*p][Ttpּpױ%qf.t =E^dnt"S?vt{*e9rBZZ{u׽utvEwIh06✚|Ltց`|ټ{Rg5|ך}_|C.I>azw>\|3'!;'%'ލ,~,G!D,/xoF)>TwC^S;#<ǵֱ,<Ss1\vƊ4xVpClɇcs((=WprDTUu9>;˼jg & 6z=9{jz[XDR hKH';E#?Ttx|s2A 8zHc짜S칚AEki31B^) q ɪi~Iz< GNĖ eړfČ1ʉ?k\fb=iӦ"-|Xᯉm[[MQ~B>gx$Mp@}*p9gpq]eW5`ҜK%t=QeJCN * ^`oAb nux:xBwv wA 1aKmoX/l^&q*l$ 8P9Sϫ\[l`refhj<(5S{Mb E("cm+2C? uIRZP,aSQW.-Z8CG`D +rT j8v~H<*yF1ie9> tC'# 'Sq"+4@Dm+TdnGx E,0, ] ]~>>{%g#g%90&@LSv]tjr #|"o<__^0b0@o}zDŽ`` SZene5e|P8`cfcnbDw|f}͍w`a?mRmii"Bi3>@7_h9dl1h`CҞQBzClZZ_'j\.MoY mCm5_o21~XpWn=0G >?ʟb<x`1[Au>rAj4rsϞ8LtdZ-1Zjssc1<٫ jܜ\?p}%]w͹4w٧>yAVy=y C3>~hs^F;à8*Diӂ:JJ~/dh (xS8d41GHDWJs-_3 !{O񩆌 ڇ(wWgkE`DIu%|+/R;zm%@/n # WoΛ{󖑘h bZ^ߐ_Q0 F&m<X|Z&R>e|3@q g>Ah ؿM iL뇫g(〢(ߞ ;0% I_P]:Ĉ'ǧ;K}L9.vDr?pBl8ju]T|`M#FW^@7Ă Dؖ-5!k$X\FHdnrG $"#x6Ly:|{5y,zocIzug yΑMخI2o.R)e)LgJoExmNq-Ypee8TSօZ_HNdoh80jtkkyl ` P2wv(9ZJFU+9!#69޷BKdO7T 5WC s[ !+!}H,P<(bc;]-)Op2Mg7:C<~@O R# ꄣ-gA60#NfyBZ7=ն}~">)ޛ-Y ""_#/GPBOK?[mz+ѻ+%>  99kE? >/$Z :@MXdnx]g݂.-UU\6`?9o摛|H` @ A?T&W)X#-N_QlU^* GH5}|1eWU$Ao&BV\ /]β]dvPJ'Pecie' C?}z)A?N$Ha^ma Ha<`K%|``ki'F;Ġ|u 'GcnedTnc׵eU#ZINlnoWmtdBNF6)Nig#g}filKj>"{VtnDa3?6CbēnC%msmopДqK5v=lK|M'+rIu5~Ӓygta+yztz4OzuBztA?`{'vɨˢe^G=s zfYb[[ SGRI>ۅ3EC@? .DgjqmvС/%%LH_` 㩜 Ț u ?ݒŽ4T46p hGhmᘆpOڃfk\`yV 삚PVZJWƀOʧ;GUHXY+lzQ+x$fT2lqo!o|Bnt0nno dCS*Y]|Rwm`ode_kCɥaM4QVYZT s  S!p,6^C?D6,w"*}V$y3)l62;\?=gDK #e ! 8r%}Dn0X(Rn\#3~h R&|*v/ # Z b y"?>\)^@Zwsq*; 1 ; ; j هOH  \!g8=G;Y-nxzڪg v^n$ k9MI0V]d'pŝyY&PPL]` ;U>|Xy`<3r4?8B `MW0^K[ ^D?y;~WZe3n4@IC}H ~OY`]w$ÒCczJ|-vȗe6F9E@KRLY1pO_a_G@R{]|c Ud<9KjNPepQ*7Oeaba2Q{Hw_@QaT'VVPZX$|)Kitcdv 8}[=^uNt`-as|a5 &<"k7coK\zj@ cVY D;2?DH@J ɻt /h# DX7@-s- ^*kB #z',Ɋ0w3 ++< Pgh!8'& UPyUs1?ܟ lK sp <IeX(@)Tq;W ׿ 籫{E^ [z-5ATjP3Z~ Rm 90bBR9`sZñZzrpII)(`| /`zxRc`nm>1(''~ s } NK-`Zz 7<]}{*Q=x`k82d a,$'m(+w NN5aMOQ*@#irht~-tH}tfS9,%,L-0Qw NSQ[! :?x|GO͒f &11|N6߃;F'L![\ZM5zO%T,ʂc4:MAC:Dnb{A_d_RgX [d,*yƘRG𜅚jݵEJûK޹XNsWQ={ix8edjFlP:l]zYd|Qr̳"|W\^Va)b3C(.8^?cs&2mOzX##{<nćvq1nj`)rarz[jrS*sZW`'", /F&Ը XK' Hxb9| ꮈ ˅'<~Piq qབྷ*8#Нj` XAu|Weg`Qi\ iXoiTD|i\ Ӌ7p~-'{@6i-Jwẑz8Kmjz]1JEMOTQ R25 חk(ڞ֊ߨq2KP EbP\'eO >a,1 5 8y\;%f aJޛU h2 4.G> ; l@,ɠw,ў*Y%<<!>A$wU&e ml/c?8AE\% A p[7 h%:h2/hv -49 5Nj g"  U U"pc >Hz) $7M]<LOonYj{jj{G  &8UK`r 6Vqigi@6}AA `x j```|'`dKts0t )"mpe;=c(e%VN0M|)wr^d-"yrFJG'aq$ki:Vo~{/̕b 6*FoM 0{sx DP,UP;s7qZAz)C6d &+]e0bF- O-uVV(dV\B+7ioI{d]LE̫58%f|`w dwrce2]6fWggOHh0 aܜ|$E9v| D*\~U#w pvu-aq4{o=v$Q%)x gH|y1u pf)bv^YK\ wZ^Y9O[?Uyp[_/ƥM(.'n #q*d_aoFSNE<>`&@+ fAh 2ɊaKk*?^'V 9 MbFR<4G+%Z%x(}+-bs +/=mb@D_ . 2YB)%%(̊"jThM'nǐL6 ؽGG ` H8w>bX7ܓ{>d_u V(JJLxa3=N+G7^B948|::%ez5M.,F[a0y-78zn>:o[.EXnH=֥ިZ`@3R M Zv%```vqvq]ĮL /,/&j"Xba:68= NW(]```ktvzV7i%I!r =][7 7$9< ZU.(Z!@zso"0XzH+D.&jtgs?<XC%D^w4R~~}rV c(Ssq|,9H/MF2]2_~‚'\o$;8. |֝?}UJRNQX +փdVzhJgO;5%Q+"/~jquT8T \n[aNrt [&DtEXQ.9>BHFM G$1-u9%pcYqx`fojsWnTkZXsT[O\,H_]:N/So6 G "e L}$ofxcg6f?dh٦EŖЕ+wems^*apX LbX(Jo&F:*-~/{G2(Є M\9I\й\PuҕY>ڙ N05։".$N)ɞ/'#!PF#e /eiyfT9jv%ZJ KU 6 Gf! 7 HJ[ ζx{~L S._c^r&H7T/;&iIL_v ) UCX'j<:8bdtU ULqqZ( ;XhuT B~Rya(.9'<Ul#s8V^@"4747 F0 R b#$<```ppWMGX(!FGT`!A):&@: N(\J```d$rgOP;'"z2RY;)-}:6J_(FLDosoeGQ^ (o]XZWgC<,2l?#)YvH}zs"v$_PՉI$Nݳfe@ik; 7@Q>d5^wcpVpcZ1"7")5sqhqs;<%GJPGe#g9{ckRicQbcH6ԛ;.,)/"L!zz EQ9`)/_^ֱgTXkJB71V-':SAF=846~98 8"oe`:DMZ6zz[Rh~UUZD^VITHODNP<Rd/wwr g{Y*< 2}9 w q?q 'D:^+U;'lR( gR%CtRըn_[Pz1,d& KZz(as"Ths}QljQ];DdX88UQ5T6R8'`ţ@}yaS᪙1 9?v4J<%2U3xk-(!nywMBt![bҭUǵreH5*( Ruu<hgFR#!; A :p(jD-ۡ&( =9|拵P)XGt{z7 ^Y0ocE?4;@N~''yplCЉ autG<gH4Xzȡ67aW}MK47gVsV8x?U$(T'%]X./bHbUOD !w#*2>]yuEsrq?,=@9H]*Nda4ٳ%N ۆ!ۊ`5242z 1u5?o6{uYN bJvE=k;`ل>SE< J6iN5HI2WK,,Kdm+ PkPfF^qhjyfcgTE_l$EN}-u?:,(=*,=n(? 4]95taj mxXsN4L`kj>kc9lb;"Z3M5bRG+sN#NJ$L&dȾsѪ&r&SxR>x,`VV/#V9|e<op no lOԮɂKݼBz=UL3EtY6 +0bw _ iגܛg.?Ϡ[ ѥ3|\1lL;iЉp%7R@@m8#_f5o./]yeiMS,{0gϵړз:eΗSg?:ED6ZWiZpAIE;Yt<N:zI@s-lE7XmbGUH4. - 6 @]jy@}``OfCg1 % F5%}-^"@3 >f&SDlfE@w'bZ'O^Dh'i6EzK,i"j[/2 9%@c8cf:Jb GxHD<"3# |M.JFP:;K.U+T=(Cdx[M>G:~@""3 iqx峘BY.TWZ?_"l+1&>K*Jk0T],Ә̐)-cpkha]="E*2jw2D^tKȴ|W vO-"e0`24]22}t)ehިNj2 t#%eA!d^C%We(gPN.<#2$A8DpDBs0󹊢ltIYsCA W:*]VSLzKt٘E!5;0%.',$/V#/`!ϠVxjeZ]G^E:hSX2*V%Zk۸%U#L"rC"@>@~ $1#.~:deD)}fxBMʛ^f~9v f_]FԘ ה4kUF) F&XfρDz,V8~|z/S4BrM>Ki$k §<e8h٧e| Rbֲ)Bp'DZM7suɝB'1%ۗgfcY7/Y %<cbfbc6hV.IbvƳm->2^ "6YL`pGtGrV1 K d $D , 7 @^cB}``Y}D87h# ;=*)!(l 2$>X^c>zah]'[>_5)lNdjWX;z'% l5 0 Iz.qxs0se@@Q*&UM-'lJ'h0| thRW=s"p^KY< .TmAaMHq>>*:8 V4CM{}gMf6-J".J[ G?':7/1s') 7u 6F2FSu:lZb|LOw5L>i'I JJSP˜O CP .95;4WFHw兮Uj2j/ph")n?djrfmo$Bl!SCDE ОDFҦ[5ܨF šh6-QsB&,{yg\ffݣĄ'OcC=N1v*4lC?\wl|rμb-oEijҢԾ_5׆Pֿoiafˉ[{@MN"%7ސh)yKgaE#!&VGH- XPo7P^w6 "a5XJ/E'T`sBûz*Z nEE ! +(696R _6;V`G76% ` w2^!sm a&!2TPd6ZXIa3`~6- Wp3N-u !E!N-Pc7]-eCU+6) 6ك43+z /!%5C >=R/~#MaD@#=:><?/pD3GJ9*& W ->g]Qky=En!nEdG[,Z7^TcVcU Ty;3.-]! uLLf&ÖP .)3Hw\lyrCjuSjNOHd$Wz/\[ |{+FqXYdlvEm{r[b\U8ƭȏ,~=6f{Vhn ʍ)տ`KiAp\C tVF0R_~dcq~YKR%D19HdX\yһV[~-y , 8sM ``vL/!-QQ.: @M/8d28(m9ʒ %UYb.`) + , <Y?P6e9#2` Z> *Q& LL l=>!P8{0"o O q(‹m-*(&q]] 3.NC'GUDи@Q%k4,-.*<| Z[+Z5{ʜk;+FXzD>>.:3 *GF B֢(hH]gj}RcuUNOWST:OI>,dد[qL2}cqNZuSYRDP.I+( dq+oXN=L&vUD<%86B7p/a)1C!OB oP|zWgO>;W(g/9%5 o2QeK ܸ3Bwуzl^iWI3754*//2 _.㒳1;'c 7o42_k9^c]U(IKX;D7OAc:*=8i- S|jiAdX._v3 k#.gCXfY/VZUS68n0GЦK xM;#D>T,@;Vd"ɤX,UpCT׉!W.Wz6ș(:Xƅi_Qxߎe b8ӑ v;Xb-†Э_cw sjARg)z9&OQbzkB|5TͪnVkLx^&w=yy/DSv`jzL+&bE  Ac%I%<-+J*rf%y 2ȓ޽?z T v<  }$#&Y-H/x6& ";7 jh  !  m d "!-vH_1n~'3{q %e%! l ) )*H%Q OYx= 1ėؿ!Mţ-& $." p F =T3DRlul/vbq&_>07:1( ۫xW$"E.g`#zbd-NsAs;xNzJuB48 .ʼn go-\B3Rd|Kf=d23"ii2Q\ݛE92c |7Uc2*F/&U_4av Q~TP='Fq\DttP3M(Y O/ [qe YXF*ȋ=m\vUNp>f*.-" o+[trx /Qm۾_xyV`p06SacQWDm^5[.;-Ma&**2% Hj ]ڹk`}5z w>n)aU$O?kGkDs7AXB7- rźf;nt.CX̛"[-31Txx{vɨAtt]B:`<}">No%r *CDYjep왹Fuox~[Ѓ/T X`Ԋ"(*EJBWdֆTp$ggʀgiP+8[_aQ'BVT`o{:۳@C /#6dIX`oP} ɞ4GkAQ)yyJJ 2 e?0 eXxuBCdVW ܛ gx Wjjqq ~=HXwopy  _Mm_[~ yr:rY={i O߻ ; ՜ ࣅ 7mm_ ) {6U}]p,OAc}2x$*J"H2-ԍJ"shX XvJ]N9.2) ޖ,M 08IPiv8ngp\SMo>3,HD9*u 3<f"P8?Z5/)7!W}$ZXME?H,'!o|N91C*Yn/h}}}uh;RJ<gS+EQ.#$ _)Sϖ5clsLsF6#R':!d k-0O#D'XxjpOYX(K9E4\%'8VR0!= {̸'cZ30Xs(l^S#F.+;iGP5`.x/r6."_-$s #hu<)G䔍|Y n&ox>/rqOYkl%S :h!O}6dKy2aHvA;y4s.m(g"a[UO J !!E!!""@"""#;#z##$7$v$$%3%r%%&/&n&&'+'j''(((g(()$)d))*"*a**++^++,,\,,--[--..Y..//X//00W0011V1122V2233V3344W4455X5566Y667)7p778E8899a99:7:~:; ;T;;<* >h>>????@@_@@A8AABBYBBC2CzCD DTDDE.EwEFFQFFG,GuGHHPHHI,IuIJJQJJK-KwKL LTLLM1M{MNNXNNO6OOPP_PPQ>QQRRgRRSGSST&TqTUUQUUV1V{VWW[WWX;XXYYfYYZFZZ[$[g[[\3\w\\]C]]^^S^^__c__`/`s``a?aab bPbbccaccd-dqdde>eef fOffgg`ggh-hqhhi>iij jOjjkk`kkl-lqllm>mmn nOnnoo_oop,ppppq=qqr rNrrss_sst,tpttu=uuv vNvvww_wwx,xpxxy=yyz zNzz{{`{{|-|q||}=}}~~K~~Xހ"e.r;~G̈́R؅^&h0s:}DɊ MҋVڌ_%g-n4v;}BŒH˓ MДSՕXږ\ޗ`"c&f(i*k,m.n2xIӠ^.tDΣX(m<Ʀ Pڧc2vDΪW$i6{HѮZ(l:~ñLղ^,p>ǵ Pٶb0uB̹Uߺ#h6{Iӽ]+p? S,uO˜*süNė)rŻMƖ(qǺMȖ(qɺMʖ(r˻M̗)rͼNΗ*sϼOИ*tѽOҘ+tӽOԘ+tսO֘*s׼Oؘ*sټNژ*sۼNܗ*sݼNޗ)r߻N)rM)rMN%[3i AwN&\5k CyQ*`8oG} V/e>tM&]6lF|V/f ?vO)`:pJ%[4h9m >rCxI}N T&Z,` 2 f  8 l > s  E z  L S%Z,a4i;pCxKS&[.c7k ?tI@~7u.l%c[  R ! !J!!""C"""#;#y##$4$r$$%-%k%%&&&d&&''^''((W(())Q))* *K**++F++,,@,,,-;-y--.6.t../1/o//0,0k001'1f112#2b2233^3344Z4455V5566S6677P7788M889 9J99::C:::;:;x;;<2">a>>??Y??@@R@@A AKAABBDBBBC=C{CCD6DuDDE0EoEEF*FiFFG$GcGGHH]HHIIXIIJJRJJKKMKKL LHLLMMDMMNN?N~NNO;OzOOP8PwPPQ4QsQQR1RpRRS-SmSST*TjTTU(UgUUV%VeVVW#WcWWX!XaXXYYWYYZ ZHZZZ[8[t[[\(\d\\]]T]]^^C^^^_2_n__` `\``aaJaaab8bsbbc%c`ccddMddde:eueef&fbffggNgggh9hthhi%i`iijjKjjjk6kqkkl!l\llm mFmmmn0njnnooToopp>pxppq'qaqqrrJrrrs3smssttUttuu=uwuuv%vavvw!wawwx x_xxyy^yyzz\zz{{Z{{||W||}}T}}~~P~~ Lʀ HƁC>}9w3q,j%c\؈Tω KƊB8v.k#`ێUϏ IÐ˲Y.uJصf;ʷX.v ]QF:ݽ/Ҿ$vǿkaVMŸCÕ9Č0Ń'zqiȻaɳYʬQˤJ̝C͖<ΐ6ω0Ѓ*}$xrmhռcַ _׳ZخV٪RڦNۣKܟHݜEޙBߖ?=;y(bK5oY C~.iS?y*eQ=x*eR@{.iW F5q$`P@|1m"^OA~3p&bU H=z0m#`S G:w.k"^R F ; x / l # `  U  I>{3p(eZOD:w/l%bXMC9v/l%bY"g 7 | !!L!!""a""#2#w#$$G$$%%]%%&.&s&&'D''((Z(()+)q))*B**++X++,*,o,,-A--..X../)/o//0@0011W112(2n223?3344U445&5l556=6677T778%8k889=99::T::;%;k;;<=<<==T==>&>l>>?>??@@V@@A)AnAAB9B|BCCGCCDDVDDE!EeEEF0FtFFG@GGH HPHHII`IIJ,JpJJK=KKL LNLLMM_MMN,NqNNO>OOP PPPPQQcQQR1RvRRSDSSTTXTTU'UlUUV;VVW WOWWXXdXXY3YxYZZHZZ[[\[[\+\p\\]>]]^ ^Q^^__d__`2`v``aDaabbUbbc"cfccd,dmdde0eqeef4fuffg8gxggh;h|hhi>iijjAjjkkCkkllEllmmFmmnnGnnooHooppHppqqGqqrrFrrssEssttCttuuAuuuv>v}vvw:wywwx6xuxxy2yqyyz-zlzz{({g{{|#|a||}}[}}~~U~~Nˀ Gā@~8v0p6x>†Fɇ MЈS։Yۊ]!b%e(h*k,l-m.n.m-l+j)h%d!`ޘ[ٙVӚP̛ IŜA8v/m&cޠYԡNɢC:|BƥIͦPӧV٨\ީ a$f)j,m0p3t7x;}@òFɳ LϴRֵYݶa'i/q8zBǻ LѼWܽb+n7zDQ_£*nò4qĮ'dšXƕMNJBȼ7tɲ-kʨ#a˟X̖P͎ HΆ@~ϼ8vе1oѮ*iҧ$bӡ\ԛVՕQ֐ L׊G؆Bف=|ڻ9x۷5tܳ1pݯ.mެ*iߩ'f$d"aYw#\Az'` F,eL3lS;u"\ D~,gO8r!\ E/iT>y)cN:t#] F/jS=x'aL6q ! [ F 1 l  W  C ~ .iUB}.iVC~0kX E3n!\J8t'bQ@[8  ` !>!!""f""#E##$#$m$%%L%%&+&u&' 'U''(4(~())^))*=**++h++,G,,-'-r-..R../3/~/00^001?112 2k233L334-4y455Z556<6677h778I889*9u9: :U::;5;;<<_<<=>==>>h>>?G??@%@o@AAMAAB+BuBC CSCCD2D|DEEZEEF9FFGGbGGH@HHIIjIIJIJJK(KsKLLRLLM2M}MNN]NNO=OOPPhPPQHQQR)RtRS SUSST6TTUUcUUVDVVW&WrWXXTXXY6YYZZdZZ[F[[\'\r\]]R]]^1^{^__Y__`7``aa]aab9bbcc]ccd8ddeeZeef3f{fg gSggh3hhiimij jWjjkAkkl*lwlmm`mmnHnno1o~oppfpqqMqqr4rrsshsttOttu5uuvvgvwwMwwx2x~xyycyyzGzz{+{w{||[||}>}}~!~m~P2}Ɂ_A׃"mO0{Ɔ\=ӈhH݊(rQ0zōYTlɐ'>Ukǔ$ݕ9Nbuљ-@RduО*ߟ:HT`jät̥$|Ӧ+ڧ16:=?@ACDFHJLNQSVY] [E/~̽hS>)xdQ >Í,{jź ZƩIǚ:Ȋ+{mʾ`˱S̥H͚>Α6ψ.Ё'{"vrpnopr v$|+ۂ2܊;ݔFޟR߫_n#~5?_@`!Bb%Ef )Jk0Qq7XzAb *Km6Xy"De1SuAd1Tv"Eg7Z}+Ic}2I`w.D[r*AXo(?Vm'>Um'?Vm)AXp,D\s1Iax7Og&>Womft29Up   ,@Tgy ) 2!:"A#H$N%T&X'\(_)b*c+d,d-c.b/`0]1Z2V3Q4L5F6@78809':;<<=>?@ABCDEyFlG`HUIJJ@K6L.M&NOPQR STUVWXYZ[\] ^ _`abc d&e,f2g9hAiIjRk\lgmrnopqrstuvxy$z9{N|e}|~ǁ0Iawˍގ#2@NZfr|vk^QC4%޻ʼqY@& ƬǕ~hS>)ѺҪӚԌ~qeZPG?81,(%#""#%(-39AJT`lz,Fa~ }xsojea\XS O!K"G#D$@%=&9'5(1)-*)+%, -./01 2 3456789:;< = >?@A!B&C+D0E5F:G?HDIIJOKTLZM`NfOlPrQxRSTUVWXYZ[\]^_`abcefgh i)j1k:lBmInQoXp_qfrlsrtwu{vwxyz{|}~}zvrnid_YTNHB<60*$  &/9DO\jx²ҳ&8J[m (6DQ]iuЉђҚӡԧի֯ײشٶڶ۶ܵݳް߮~vmdZOD8,}iU@+ z o d YND9/% !"#$%&'|(v)p*j+e,`-[.V/S0O1L2I3G4E5C6B7A8@9?:?;???@@BADBGCJDNERFWG]HcIkJrK{LMNOPQRSTUW XY&Z4[C\Q]^^l_y`abcdefghijkmnopq'r0s8t?uGvNwUx[yazg{l|q}v~z}}xsmhb[UOJD>83-("  &-5>GPZdoz9$x=RNNK ԠV'$תyga)bØAH4:"y+ y<^%^";c\eL 7Ѳݍ[Ҁݠgi;PtYdz =?7܈3O3AHϋoko݌fdN0A޻_GQltL0ރV!8Nr TblD SQ ,d9QECLZjy7Ӂ5?-u@۟tSMPa24dMYg$Gۃ՘M]8'/ _d htrN}ܥ2l2;uI 6UvOMT[̳z#dQ gS&)t+9|EO͍gl7ܵș {d. ilvpES#>=k ȗ7YU,v#>CPGEvǻ6]k伔.zpqr~Cz<85F .2΂GbnH;)J8ZKI2}?3$.11twׄ(хQ,҆|C0~png_TJ=jH(+(x J@6\tr("C*!8)VTapf]mmr޻̋ݏ֢JDߦo,%}؎Ѡ+$֮ desc$cprt "wtptDchadX,rXYZgXYZbXYZrTRC gTRC bTRC mluc enUSsP3Cmluc enUSCC0XYZ -sf32 B%NXYZ =XYZ J7 XYZ (8 xparafi Y [libvips-8.18.2/libvips/colour/profiles/sGrey.icm000066400000000000000000000005501516303661500216510ustar00rootroot00000000000000hlcms mntrGRAYXYZ  acspMSFTsawsctrl-handbzigdesc$cprt"wtptchad,kTRCH mluc enUSsGrymluc enUSCC0XYZ -sf32 ?&qparafi Y [libvips-8.18.2/libvips/colour/profiles/sRGB.icm000066400000000000000000000007401516303661500213560ustar00rootroot00000000000000lcms mntrRGB XYZ  acspMSFTsawsctrl-handyVZ>#UFO desc$cprt "wtptDchadX,rXYZgXYZbXYZrTRC gTRC bTRC mluc enUSsRGBmluc enUSCC0XYZ -sf32 ?&qXYZ o8XYZ bXYZ $parafi Y [libvips-8.18.2/libvips/colour/rad2float.c000066400000000000000000000154361516303661500202760ustar00rootroot00000000000000/* Convert Radiance 32bit packed format to float. * * 3/3/09 * - from LabQ2Lab and Radiance sources * 2/11/09 * - gtkdoc * 20/9/12 * - redo as a class * 13/12/12 * - tag output as scRGB, since it'll be 0-1 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Sections of this file from Greg Ward and Radiance with kind permission. The Radience copyright notice appears below. */ /* ==================================================================== * The Radiance Software License, Version 1.0 * * Copyright (c) 1990 - 2009 The Regents of the University of California, * through Lawrence Berkeley National Laboratory. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes Radiance software * (http://radsite.lbl.gov/) * developed by the Lawrence Berkeley National Laboratory * (http://www.lbl.gov/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Radiance," "Lawrence Berkeley National Laboratory" * and "The Regents of the University of California" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact radiance@radsite.lbl.gov. * * 5. Products derived from this software may not be called "Radiance", * nor may "Radiance" appear in their name, without prior written * permission of Lawrence Berkeley National Laboratory. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of Lawrence Berkeley National Laboratory. For more * information on Lawrence Berkeley National Laboratory, please see * . */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" /* Begin copy-paste from Radiance sources. */ #define RED 0 #define GRN 1 #define BLU 2 #define CIEX 0 /* or, if input is XYZ... */ #define CIEY 1 #define CIEZ 2 #define EXP 3 /* exponent same for either format */ #define COLXS 128 /* excess used for exponent */ #define WHT 3 /* used for RGBPRIMS type */ #undef BYTE #define BYTE unsigned char /* 8-bit unsigned integer */ typedef BYTE COLR[4]; /* red, green, blue (or X,Y,Z), exponent */ typedef float COLORV; typedef COLORV COLOR[3]; /* red, green, blue (or X,Y,Z) */ #define copycolor(c1, c2) ( \ (c1)[0] = (c2)[0], \ (c1)[1] = (c2)[1], \ (c1)[2] = (c2)[2]) static void colr_color(COLOR col, COLR clr) /* convert short to float color */ { if (clr[EXP] == 0) col[RED] = col[GRN] = col[BLU] = 0.0; else { double f = ldexp(1.0, (int) clr[EXP] - (COLXS + 8)); col[RED] = (clr[RED] + 0.5) * f; col[GRN] = (clr[GRN] + 0.5) * f; col[BLU] = (clr[BLU] + 0.5) * f; } } /* End copy-paste from Radiance sources. */ typedef VipsColourCode VipsRad2float; typedef VipsColourCodeClass VipsRad2floatClass; G_DEFINE_TYPE(VipsRad2float, vips_rad2float, VIPS_TYPE_COLOUR_CODE); static void vips_rad2float_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { COLR *inp = (COLR *) in[0]; COLOR *outbuf = (COLOR *) out; int i; for (i = 0; i < width; i++) colr_color(outbuf[i], inp[i]); } static void vips_rad2float_class_init(VipsRad2floatClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "rad2float"; object_class->description = _("unpack Radiance coding to float RGB"); colour_class->process_line = vips_rad2float_line; } static void vips_rad2float_init(VipsRad2float *rad2float) { VipsColour *colour = VIPS_COLOUR(rad2float); VipsColourCode *code = VIPS_COLOUR_CODE(rad2float); colour->coding = VIPS_CODING_NONE; colour->interpretation = VIPS_INTERPRETATION_scRGB; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 3; colour->input_bands = 4; code->input_coding = VIPS_CODING_RAD; } /** * vips_rad2float: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Unpack a RAD ([enum@Vips.Coding.RAD]) image to a three-band float image. * * ::: seealso * [method@Image.float2rad], [method@Image.LabQ2LabS]. * * Returns: 0 on success, -1 on error. */ int vips_rad2float(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("rad2float", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/sRGB2HSV.c000066400000000000000000000076371516303661500176640ustar00rootroot00000000000000/* to HSV ... useful for compatibility with other packages * * 9/6/15 * - from LabS2Lab.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pcolour.h" typedef VipsColourCode VipssRGB2HSV; typedef VipsColourCodeClass VipssRGB2HSVClass; G_DEFINE_TYPE(VipssRGB2HSV, vips_sRGB2HSV, VIPS_TYPE_COLOUR_CODE); static void vips_sRGB2HSV_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { unsigned char *p = (unsigned char *) in[0]; unsigned char *q = (unsigned char *) out; int i; for (i = 0; i < width; i++) { unsigned char c_max; unsigned char c_min; float secondary_diff; float wrap_around_hue; if (p[1] < p[2]) { if (p[2] < p[0]) { /* Center red (at top). */ c_max = p[0]; c_min = p[1]; secondary_diff = p[1] - p[2]; wrap_around_hue = 255.0F; } else { /* Center blue. */ c_max = p[2]; c_min = VIPS_MIN(p[1], p[0]); secondary_diff = p[0] - p[1]; wrap_around_hue = 170.0F; } } else { if (p[1] < p[0]) { /* Center red (at bottom) */ c_max = p[0]; c_min = p[2]; secondary_diff = p[1] - p[2]; wrap_around_hue = 0.0F; } else { /* Center green */ c_max = p[1]; c_min = VIPS_MIN(p[2], p[0]); secondary_diff = p[2] - p[0]; wrap_around_hue = 85.0F; } } if (c_max == 0) { q[0] = 0; q[1] = 0; q[2] = 0; } else { unsigned char delta; q[2] = c_max; delta = c_max - c_min; if (delta == 0) q[0] = 0; else q[0] = 42.5 * (secondary_diff / (float) delta) + wrap_around_hue; q[1] = delta * 255.0 / (float) c_max; } p += 3; q += 3; } } static void vips_sRGB2HSV_class_init(VipssRGB2HSVClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "sRGB2HSV"; object_class->description = _("transform sRGB to HSV"); colour_class->process_line = vips_sRGB2HSV_line; } static void vips_sRGB2HSV_init(VipssRGB2HSV *sRGB2HSV) { VipsColour *colour = VIPS_COLOUR(sRGB2HSV); VipsColourCode *code = VIPS_COLOUR_CODE(sRGB2HSV); colour->interpretation = VIPS_INTERPRETATION_HSV; colour->format = VIPS_FORMAT_UCHAR; colour->bands = 3; colour->input_bands = 3; code->input_coding = VIPS_CODING_NONE; code->input_format = VIPS_FORMAT_UCHAR; code->input_interpretation = VIPS_INTERPRETATION_sRGB; } /** * vips_sRGB2HSV: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert to HSV. * * HSV is a crude polar coordinate system for RGB images. It is provided for * compatibility with other image processing systems. See [method@Image.Lab2LCh] for a * much better colour space. * * ::: seealso * [method@Image.HSV2sRGB], [method@Image.Lab2LCh]. * * Returns: 0 on success, -1 on error. */ int vips_sRGB2HSV(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("sRGB2HSV", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/sRGB2scRGB.c000066400000000000000000000101241516303661500201450ustar00rootroot00000000000000/* Turn displayable rgb files to scRGB. * * Modified: * 15/11/94 JC * - memory leak fixed * - error message added * 16/11/94 JC * - partialed * 21/9/12 * - redone as a class * - sRGB only, support for other RGBs is now via lcms * 6/11/12 * - add 16-bit sRGB import * 11/12/12 * - cut about to make sRGB2scRGB.c * 12/2/15 * - add 16-bit alpha handling * 26/2/16 * - look for RGB16 tag, not just ushort, for the 16-bit path * 24/11/17 lovell * - special path for 3 and 4 band images * 16/4/25 * - move on top of ColourCode */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcolour.h" typedef VipsColourCode VipssRGB2scRGB; typedef VipsColourCodeClass VipssRGB2scRGBClass; G_DEFINE_TYPE(VipssRGB2scRGB, vips_sRGB2scRGB, VIPS_TYPE_COLOUR_CODE); static void vips_sRGB2scRGB_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { if (colour->in[0]->BandFmt == VIPS_FORMAT_UCHAR) { float *restrict q; VipsPel *restrict p; q = (float *) out; p = in[0]; for (int i = 0; i < width; i++) { q[0] = vips_v2Y_8[p[0]]; q[1] = vips_v2Y_8[p[1]]; q[2] = vips_v2Y_8[p[2]]; p += 3; q += 3; } } else if (colour->in[0]->BandFmt == VIPS_FORMAT_USHORT) { float *restrict q; unsigned short *restrict p; q = (float *) out; p = (unsigned short *) in[0]; for (int i = 0; i < width; i++) { q[0] = vips_v2Y_16[p[0]]; q[1] = vips_v2Y_16[p[1]]; q[2] = vips_v2Y_16[p[2]]; p += 3; q += 3; } } else g_assert_not_reached(); } static int vips_sRGB2scRGB_build(VipsObject *object) { VipsColour *colour = (VipsColour *) object; VipsColourCode *code = (VipsColourCode *) object; // input image we want if (vips_object_argument_isset(object, "in") && code->in->Type == VIPS_INTERPRETATION_RGB16) { vips_col_make_tables_RGB_16(); code->input_format = VIPS_FORMAT_USHORT; } else { vips_col_make_tables_RGB_8(); code->input_format = VIPS_FORMAT_UCHAR; } colour->input_bands = 3; // output image we make colour->interpretation = VIPS_INTERPRETATION_scRGB; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 3; return VIPS_OBJECT_CLASS(vips_sRGB2scRGB_parent_class)->build(object); } static void vips_sRGB2scRGB_class_init(VipssRGB2scRGBClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "sRGB2scRGB"; object_class->description = _("convert an sRGB image to scRGB"); object_class->build = vips_sRGB2scRGB_build; colour_class->process_line = vips_sRGB2scRGB_line; } static void vips_sRGB2scRGB_init(VipssRGB2scRGB *sRGB2scRGB) { } /** * vips_sRGB2scRGB: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert an sRGB image to scRGB. * * RGB16 images are also handled. * * ::: seealso * [method@Image.scRGB2XYZ], [method@Image.scRGB2sRGB], * [method@Image.rad2float]. * * Returns: 0 on success, -1 on error. */ int vips_sRGB2scRGB(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("sRGB2scRGB", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/scRGB2BW.c000066400000000000000000000105401516303661500176620ustar00rootroot00000000000000/* Turn scRGB into greyscale. * * 17/4/15 * - from scRGB2BW.c * 16/4/25 * - move on top of ColourCode */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef struct _VipsscRGB2BW { VipsColourCode parent_instance; int depth; } VipsscRGB2BW; typedef VipsColourCodeClass VipsscRGB2BWClass; G_DEFINE_TYPE(VipsscRGB2BW, vips_scRGB2BW, VIPS_TYPE_COLOUR_CODE); static void vips_scRGB2BW_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsscRGB2BW *scRGB2BW = (VipsscRGB2BW *) colour; if (scRGB2BW->depth == 16) { unsigned short *restrict q; float *restrict p; q = (unsigned short *) out; p = (float *) in[0]; for (int i = 0; i < width; i++) { const float R = p[0]; const float G = p[1]; const float B = p[2]; int g; int og; vips_col_scRGB2BW_16(R, G, B, &g, &og); q[0] = g; p += 3; q += 1; } } else { unsigned char *restrict q; float *restrict p; q = (unsigned char *) out; p = (float *) in[0]; for (int i = 0; i < width; i++) { const float R = p[0]; const float G = p[1]; const float B = p[2]; int g; int og; vips_col_scRGB2BW_8(R, G, B, &g, &og); q[0] = g; p += 3; q += 1; } } } static int vips_scRGB2BW_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsscRGB2BW *scRGB2BW = (VipsscRGB2BW *) object; VipsColour *colour = (VipsColour *) object; VipsColourCode *code = (VipsColourCode *) object; // input image we want code->input_format = VIPS_FORMAT_FLOAT; colour->input_bands = 3; // output image we make switch (scRGB2BW->depth) { case 16: colour->interpretation = VIPS_INTERPRETATION_GREY16; colour->format = VIPS_FORMAT_USHORT; break; case 8: colour->interpretation = VIPS_INTERPRETATION_B_W; colour->format = VIPS_FORMAT_UCHAR; break; default: vips_error(class->nickname, "%s", _("depth must be 8 or 16")); return -1; } colour->bands = 1; return VIPS_OBJECT_CLASS(vips_scRGB2BW_parent_class)->build(object); } static void vips_scRGB2BW_class_init(VipsscRGB2BWClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "scRGB2BW"; object_class->description = _("convert scRGB to BW"); object_class->build = vips_scRGB2BW_build; colour_class->process_line = vips_scRGB2BW_line; VIPS_ARG_INT(class, "depth", 130, _("Depth"), _("Output device space depth in bits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsscRGB2BW, depth), 8, 16, 8); } static void vips_scRGB2BW_init(VipsscRGB2BW *scRGB2BW) { scRGB2BW->depth = 8; } /** * vips_scRGB2BW: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert an scRGB image to greyscale. Set @depth to 16 to get 16-bit output. * * ::: tip "Optional arguments" * * @depth: `gint`, depth of output image in bits * * ::: seealso * [method@Image.LabS2LabQ], [method@Image.sRGB2scRGB], * [method@Image.rad2float]. * * Returns: 0 on success, -1 on error. */ int vips_scRGB2BW(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("scRGB2BW", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/scRGB2XYZ.c000066400000000000000000000055471516303661500200570ustar00rootroot00000000000000/* Turn scRGB to XYZ colourspace. * * Modified: * 29/5/02 JC * - from lab2xyz * 2/11/09 * - gtkdoc * - cleanups * 20/9/12 * redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef VipsColourTransform VipsscRGB2XYZ; typedef VipsColourTransformClass VipsscRGB2XYZClass; G_DEFINE_TYPE(VipsscRGB2XYZ, vips_scRGB2XYZ, VIPS_TYPE_COLOUR_TRANSFORM); static void vips_scRGB2XYZ_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { float *restrict p = (float *) in[0]; float *restrict q = (float *) out; for (int i = 0; i < width; i++) { const float R = p[0] * VIPS_D65_Y0; const float G = p[1] * VIPS_D65_Y0; const float B = p[2] * VIPS_D65_Y0; /* Manually inlined logic from the vips_col_scRGB2XYZ function * as the original is defined in a separate file and is part of * the public API so a compiler will not inline. */ q[0] = 0.4124F * R + 0.3576F * G + 0.1805F * B; q[1] = 0.2126F * R + 0.7152F * G + 0.0722F * B; q[2] = 0.0193F * R + 0.1192F * G + 0.9505F * B; p += 3; q += 3; } } static void vips_scRGB2XYZ_class_init(VipsscRGB2XYZClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); object_class->nickname = "scRGB2XYZ"; object_class->description = _("transform scRGB to XYZ"); colour_class->process_line = vips_scRGB2XYZ_line; } static void vips_scRGB2XYZ_init(VipsscRGB2XYZ *scRGB2XYZ) { VipsColour *colour = VIPS_COLOUR(scRGB2XYZ); colour->interpretation = VIPS_INTERPRETATION_XYZ; } /** * vips_scRGB2XYZ: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn XYZ to scRGB. * * Returns: 0 on success, -1 on error */ int vips_scRGB2XYZ(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("scRGB2XYZ", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/scRGB2sRGB.c000066400000000000000000000122121516303661500201450ustar00rootroot00000000000000/* Turn scRGB files into displayable rgb. * * Author: J-P. Laurent * Modified: * 15/11/94 JC * - error message added * - out->Type set to IM_TYPE_RGB * - memory leak fixed * 16/11/94 JC * - uses im_wrapone() * 15/2/95 JC * - oops! now uses PEL, not float for output pointer * 2/1/96 JC * - sometimes produced incorrect result at extrema * - reformatted * - now uses IM_RINT() and clip() * 18/9/96 JC * - some speed-ups ... 3x faster * - slightly less accurate, but who cares * - added out-of-mem check for table build * 21/9/12 * - redone as a class * - sRGB only, support for other RGBs is now via lcms * 6/11/12 * - added 16-bit option * 11/12/12 * - cut about to make scRGB2sRGB.c * 12/2/15 * - add 16-bit alpha handling * 16/4/25 * - move on top of ColourCode */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef struct _VipsscRGB2sRGB { VipsColourCode parent_instance; int depth; } VipsscRGB2sRGB; typedef VipsColourCodeClass VipsscRGB2sRGBClass; G_DEFINE_TYPE(VipsscRGB2sRGB, vips_scRGB2sRGB, VIPS_TYPE_COLOUR_CODE); static void vips_scRGB2sRGB_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) colour; if (scRGB2sRGB->depth == 16) { unsigned short *restrict q; float *restrict p; q = (unsigned short *) out; p = (float *) in[0]; for (int i = 0; i < width; i++) { const float R = p[0]; const float G = p[1]; const float B = p[2]; int r, g, b; vips_col_scRGB2sRGB_16(R, G, B, &r, &g, &b, NULL); q[0] = r; q[1] = g; q[2] = b; p += 3; q += 3; } } else { unsigned char *restrict q; float *restrict p; q = (unsigned char *) out; p = (float *) in[0]; for (int i = 0; i < width; i++) { const float R = p[0]; const float G = p[1]; const float B = p[2]; int r, g, b; vips_col_scRGB2sRGB_8(R, G, B, &r, &g, &b, NULL); q[0] = r; q[1] = g; q[2] = b; p += 3; q += 3; } } } static int vips_scRGB2sRGB_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) object; VipsColour *colour = (VipsColour *) object; VipsColourCode *code = (VipsColourCode *) object; // input image we want code->input_format = VIPS_FORMAT_FLOAT; colour->input_bands = 3; // output image we make switch (scRGB2sRGB->depth) { case 16: colour->interpretation = VIPS_INTERPRETATION_RGB16; colour->format = VIPS_FORMAT_USHORT; break; case 8: colour->interpretation = VIPS_INTERPRETATION_sRGB; colour->format = VIPS_FORMAT_UCHAR; break; default: vips_error(class->nickname, "%s", _("depth must be 8 or 16")); return -1; } colour->bands = 3; return VIPS_OBJECT_CLASS(vips_scRGB2sRGB_parent_class)->build(object); } static void vips_scRGB2sRGB_class_init(VipsscRGB2sRGBClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "scRGB2sRGB"; object_class->description = _("convert scRGB to sRGB"); object_class->build = vips_scRGB2sRGB_build; colour_class->process_line = vips_scRGB2sRGB_line; VIPS_ARG_INT(class, "depth", 130, _("Depth"), _("Output device space depth in bits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsscRGB2sRGB, depth), 8, 16, 8); } static void vips_scRGB2sRGB_init(VipsscRGB2sRGB *scRGB2sRGB) { scRGB2sRGB->depth = 8; } /** * vips_scRGB2sRGB: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert an scRGB image to sRGB. Set @depth to 16 to get 16-bit output. * * ::: tip "Optional arguments" * * @depth: `gint`, depth of output image in bits * * ::: seealso * [method@Image.LabS2LabQ], [method@Image.sRGB2scRGB], * [method@Image.rad2float]. * * Returns: 0 on success, -1 on error. */ int vips_scRGB2sRGB(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("scRGB2sRGB", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/uhdr2scRGB.c000066400000000000000000000174011516303661500203170ustar00rootroot00000000000000/* Turn uhdr (RGB plus a gainmap) to scRGB colourspace. * * 26/11/25 * - from XYZ2scRGB.c.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcolour.h" typedef struct _VipsUhdr2scRGB { VipsColour parent; VipsImage *in; /* Gainmap metadata. */ float gamma[3]; float min_content_boost[3]; float max_content_boost[3]; float offset_hdr[3]; float offset_sdr[3]; /* And the actual map. */ VipsImage *gainmap; } VipsUhdr2scRGB; typedef VipsColourClass VipsUhdr2scRGBClass; G_DEFINE_TYPE(VipsUhdr2scRGB, vips_uhdr2scRGB, VIPS_TYPE_COLOUR); /* Derived from the apache-licensed applyGain() method of libuhdr. */ /* Monochrome gainmap, colour image. Probably the most common case. */ static void vips_uhdr2scRGB_mono(VipsUhdr2scRGB *uhdr, VipsPel *out, VipsPel **in, int width) { VipsPel *restrict p1 = in[0]; VipsPel *restrict p2 = in[1]; float *restrict q = (float *) out; for (int i = 0; i < width; i++) { float r = vips_v2Y_8[p1[0]]; float g = vips_v2Y_8[p1[1]]; float b = vips_v2Y_8[p1[2]]; p1 += 3; // the gainmap is not gamma corrected in libultrahdr, confusingly float gg = p2[0] / 255.0; p2 += 1; if (uhdr->gamma[1] != 1.0f) gg = pow(gg, 1.0f / uhdr->gamma[1]); float boostg = log2(uhdr->min_content_boost[1]) * (1.0f - gg) + log2(uhdr->max_content_boost[1]) * gg; float gaing = exp2(boostg); q[0] = ((r + uhdr->offset_sdr[1]) * gaing) - uhdr->offset_hdr[1]; q[1] = ((g + uhdr->offset_sdr[1]) * gaing) - uhdr->offset_hdr[1]; q[2] = ((b + uhdr->offset_sdr[1]) * gaing) - uhdr->offset_hdr[1]; q += 3; } } /* Colour image, colour gainmap. Allowed, but not common. */ static void vips_uhdr2scRGB_rgb(VipsUhdr2scRGB *uhdr, VipsPel *out, VipsPel **in, int width) { VipsPel *restrict p1 = in[0]; VipsPel *restrict p2 = in[1]; float *restrict q = (float *) out; for (int i = 0; i < width; i++) { float r = vips_v2Y_8[p1[0]]; float g = vips_v2Y_8[p1[1]]; float b = vips_v2Y_8[p1[2]]; p1 += 3; float gr = vips_v2Y_8[p2[0]]; float gg = vips_v2Y_8[p2[1]]; float gb = vips_v2Y_8[p2[2]]; p2 += 3; if (uhdr->gamma[0] != 1.0f) gr = pow(gr, 1.0f / uhdr->gamma[0]); if (uhdr->gamma[1] != 1.0f) gg = pow(gg, 1.0f / uhdr->gamma[1]); if (uhdr->gamma[2] != 1.0f) gb = pow(gb, 1.0f / uhdr->gamma[2]); float boostr = log2(uhdr->min_content_boost[0]) * (1.0f - gr) + log2(uhdr->max_content_boost[0]) * gr; float boostg = log2(uhdr->min_content_boost[1]) * (1.0f - gg) + log2(uhdr->max_content_boost[1]) * gg; float boostb = log2(uhdr->min_content_boost[2]) * (1.0f - gb) + log2(uhdr->max_content_boost[2]) * gb; float gainr = exp2(boostr); float gaing = exp2(boostg); float gainb = exp2(boostb); q[0] = ((r + uhdr->offset_sdr[0]) * gainr) - uhdr->offset_hdr[0]; q[1] = ((g + uhdr->offset_sdr[1]) * gaing) - uhdr->offset_hdr[1]; q[2] = ((b + uhdr->offset_sdr[2]) * gainb) - uhdr->offset_hdr[2]; q += 3; } } static void vips_uhdr2scRGB_line(VipsColour *colour, VipsPel *out, VipsPel **in, int width) { VipsUhdr2scRGB *uhdr = (VipsUhdr2scRGB *) colour; g_assert(colour->in[0]->Xsize == colour->in[1]->Xsize); g_assert(colour->in[0]->Ysize == colour->in[1]->Ysize); if (uhdr->gainmap->Bands == 1) vips_uhdr2scRGB_mono(uhdr, out, in, width); else vips_uhdr2scRGB_rgb(uhdr, out, in, width); } // pass in the array to fill, size must match static int image_get_array_float(VipsImage *image, const char *name, float *out, int n_out) { double *d; int n; if (vips_image_get_array_double(image, name, &d, &n)) return -1; if (n != n_out) { vips_error("image_get_array_float", _("bad size")); return -1; } for (int i = 0; i < n; i++) out[i] = d[i]; return 0; } static int vips_uhdr2scRGB_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsColour *colour = VIPS_COLOUR(object); VipsUhdr2scRGB *uhdr = (VipsUhdr2scRGB *) object; /* We allow one-band gainmap plus 3 band main image, so we have to turn * off the automatic detach-attach alpha processing. */ colour->input_bands = 0; colour->n = 2; colour->in = (VipsImage **) vips_object_local_array(object, 2); /* Get the gainmap image metadata. */ if (uhdr->in) { if (vips_check_bands(class->nickname, uhdr->in, 3)) return -1; if (uhdr->in->BandFmt != VIPS_FORMAT_UCHAR) { vips_error(class->nickname, "%s", _("image must be uchar")); return -1; } /* Need this for fast srgb -> scRGB. */ vips_col_make_tables_RGB_8(); if (image_get_array_float(uhdr->in, "gainmap-max-content-boost", &uhdr->max_content_boost[0], 3) || image_get_array_float(uhdr->in, "gainmap-min-content-boost", &uhdr->min_content_boost[0], 3) || image_get_array_float(uhdr->in, "gainmap-gamma", &uhdr->gamma[0], 3) || image_get_array_float(uhdr->in, "gainmap-offset-sdr", &uhdr->offset_sdr[0], 3) || image_get_array_float(uhdr->in, "gainmap-offset-hdr", &uhdr->offset_hdr[0], 3)) return -1; VipsImage *gainmap; if (!(gainmap = vips_image_get_gainmap(uhdr->in))) return -1; if (vips_check_bands_1or3(class->nickname, gainmap)) return -1; /* Scale the gainmap image to match the main image 1:1. */ if (vips_resize(gainmap, &uhdr->gainmap, (double) uhdr->in->Xsize / gainmap->Xsize, "vscale", (double) uhdr->in->Ysize / gainmap->Ysize, "kernel", VIPS_KERNEL_LINEAR, NULL)) return -1; g_object_unref(gainmap); colour->in[0] = uhdr->in; g_object_ref(uhdr->in); colour->in[1] = uhdr->gainmap; } if (VIPS_OBJECT_CLASS(vips_uhdr2scRGB_parent_class)->build(object)) return -1; return 0; } static void vips_uhdr2scRGB_class_init(VipsUhdr2scRGBClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdr2scRGB"; object_class->description = _("transform uhdr to scRGB"); object_class->build = vips_uhdr2scRGB_build; colour_class->process_line = vips_uhdr2scRGB_line; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsColourTransform, in)); } static void vips_uhdr2scRGB_init(VipsUhdr2scRGB *uhdr) { VipsColour *colour = VIPS_COLOUR(uhdr); colour->interpretation = VIPS_INTERPRETATION_scRGB; colour->format = VIPS_FORMAT_FLOAT; colour->bands = 3; } /** * vips_uhdr2scRGB: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Transform a uhdr image (three band sRGB with an attached gainmap) to * scRGB. * * Returns: 0 on success, -1 on error */ int vips_uhdr2scRGB(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("uhdr2scRGB", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/colour/wrap-profiles.sh000077500000000000000000000021271516303661500213760ustar00rootroot00000000000000#!/bin/bash # code up the binary files in $1 as a set of name / string pairs in $2 # For example: # $ ./wrap-profiles.sh profiles profiles.c # we have to use arrays for the strings, since MSVC won't allow string # literals larger than 64kb in=$1 out=$2 echo "/* this file is generated automatically, do not edit! */" > $out echo "/* clang-format off */" > $out echo "" >> $out echo "#include \"profiles.h\"" >> $out echo "" >> $out profile_names= for file in $in/*.icm; do root=${file%.icm} base=${root##*/} profile_name=vips__profile_fallback_$base profile_names="$profile_names $profile_name" echo "static VipsProfileFallback $profile_name = {" >> $out echo -e "\t\"$base\"," >> $out echo -e "\t$(stat --format=%s $file)," >> $out echo -e "\t{" >> $out pigz -c -z -11 $file | hexdump -v -e '" 0x" 1/1 "%02X,"' | fmt >> $out echo -e "\t}" >> $out echo "};" >> $out echo >> $out done echo "VipsProfileFallback *vips__profile_fallback_table[] = {" >> $out for profile_name in $profile_names; do echo -e "\t&$profile_name," >> $out done echo -e "\tNULL" >> $out echo "};" >> $out libvips-8.18.2/libvips/conversion/000077500000000000000000000000001516303661500171255ustar00rootroot00000000000000libvips-8.18.2/libvips/conversion/addalpha.c000066400000000000000000000057211516303661500210340ustar00rootroot00000000000000/* Add an appropriate alpha band. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconversion.h" typedef struct _VipsAddAlpha { VipsConversion parent_instance; VipsImage *in; } VipsAddAlpha; typedef VipsConversionClass VipsAddAlphaClass; G_DEFINE_TYPE(VipsAddAlpha, vips_addalpha, VIPS_TYPE_CONVERSION); static int vips_addalpha_build(VipsObject *object) { VipsAddAlpha *addalpha = (VipsAddAlpha *) object; VipsConversion *conversion = VIPS_CONVERSION(object); VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); double max_alpha = vips_interpretation_max_alpha(addalpha->in->Type); if (VIPS_OBJECT_CLASS(vips_addalpha_parent_class)->build(object)) return -1; if (vips_bandjoin_const1(addalpha->in, &t[0], max_alpha, NULL) || vips_image_write(t[0], conversion->out)) return -1; return 0; } static void vips_addalpha_class_init(VipsAddAlphaClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "addalpha"; vobject_class->description = _("append an alpha channel"); vobject_class->build = vips_addalpha_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsAddAlpha, in)); } static void vips_addalpha_init(VipsAddAlpha *addalpha) { } /** * vips_addalpha: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Append an alpha channel. * * ::: seealso * [method@Image.hasalpha]. * * Returns: 0 on success, -1 on error */ int vips_addalpha(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("addalpha", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/arrayjoin.c000066400000000000000000000326131516303661500212740ustar00rootroot00000000000000/* join an array of images together * * 11/12/15 * - from join.c * 6/9/21 * - minmise inputs once we've used them * 29/12/22 * - much faster with large arrays * 29/1/24 * - render and don't forward pixels for complete subregions */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsArrayjoin { VipsConversion parent_instance; /* Params. */ VipsArrayImage *in; int across; int shim; VipsArrayDouble *background; VipsAlign halign; VipsAlign valign; int hspacing; int vspacing; int down; VipsRect *rects; gboolean *minimised; } VipsArrayjoin; typedef VipsConversionClass VipsArrayjoinClass; G_DEFINE_TYPE(VipsArrayjoin, vips_arrayjoin, VIPS_TYPE_CONVERSION); static int vips_arrayjoin_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsImage **in = (VipsImage **) a; VipsArrayjoin *join = (VipsArrayjoin *) b; VipsConversion *conversion = VIPS_CONVERSION(join); VipsRect *r = &out_region->valid; int n; /* Find the left/top/width/height of the cells this region touches. */ int cell_width = join->hspacing + join->shim; int cell_height = join->vspacing + join->shim; int left = r->left / cell_width; int top = r->top / cell_height; int width = (VIPS_ROUND_UP(VIPS_RECT_RIGHT(r), cell_width) - VIPS_ROUND_DOWN(r->left, cell_width)) / cell_width; int height = (VIPS_ROUND_UP(VIPS_RECT_BOTTOM(r), cell_height) - VIPS_ROUND_DOWN(r->top, cell_height)) / cell_height; int i; VipsRegion *reg; /* Size of image array. */ vips_array_image_get(join->in, &n); /* Does this rect fit completely within one of our inputs? We can just * forward the request. */ if (width == 1 && height == 1) { VipsRect need; i = VIPS_MIN(n - 1, left + top * join->across); /* The part of in[i] we need. */ need = out_region->valid; need.left -= join->rects[i].left; need.top -= join->rects[i].top; /* And render into out_region. We can't just forward a pointer since * we are about to unref reg. */ reg = vips_region_new(in[i]); if (vips_region_prepare_to(reg, out_region, &need, r->left, r->top)) { g_object_unref(reg); return -1; } g_object_unref(reg); } else { /* Output requires more than one input. Paste all touching * inputs into the output. */ int x, y; for (y = 0; y < height; y++) for (x = 0; x < width; x++) { i = VIPS_MIN(n - 1, x + left + (y + top) * join->across); reg = vips_region_new(in[i]); if (vips__insert_paste_region(out_region, reg, &join->rects[i])) { g_object_unref(reg); return -1; } g_object_unref(reg); } } /* In sequential mode, we can minimise an input once our generate point * is well past the end of it. This can save a lot of memory and file * descriptors on large image arrays. * * minimise_all is quite expensive, so only trigger once for each input. * * We don't lock for minimised[], but it's harmless. */ if (vips_image_is_sequential(conversion->out)) for (i = 0; i < n; i++) { int bottom_edge = VIPS_RECT_BOTTOM(&join->rects[i]); if (!join->minimised[i] && r->top > bottom_edge + 1024) { join->minimised[i] = TRUE; vips_image_minimise_all(in[i]); } } return 0; } static int vips_arrayjoin_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsArrayjoin *join = (VipsArrayjoin *) object; VipsImage **in; int n; VipsImage **format; VipsImage **band; VipsImage **size; int hspacing; int vspacing; int output_width; int output_height; int i; if (VIPS_OBJECT_CLASS(vips_arrayjoin_parent_class)->build(object)) return -1; in = vips_array_image_get(join->in, &n); /* Array length zero means error. */ if (n == 0) return -1; for (i = 0; i < n; i++) if (vips_image_pio_input(in[i]) || vips_check_coding_known(class->nickname, in[i])) return -1; /* Move all input images to a common format and number of bands. */ format = (VipsImage **) vips_object_local_array(object, n); if (vips__formatalike_vec(in, format, n)) return -1; in = format; /* We have to include the number of bands in @background in our * calculation. */ band = (VipsImage **) vips_object_local_array(object, n); if (vips__bandalike_vec(class->nickname, in, band, n, VIPS_AREA(join->background)->n)) return -1; in = band; /* Now sizealike: search for the largest image. */ hspacing = in[0]->Xsize; vspacing = in[0]->Ysize; for (i = 1; i < n; i++) { if (in[i]->Xsize > hspacing) hspacing = in[i]->Xsize; if (in[i]->Ysize > vspacing) vspacing = in[i]->Ysize; } if (!vips_object_argument_isset(object, "hspacing")) join->hspacing = hspacing; // FIXME: Invalidates operation cache if (!vips_object_argument_isset(object, "vspacing")) join->vspacing = vspacing; // FIXME: Invalidates operation cache hspacing = join->hspacing; vspacing = join->vspacing; if (!vips_object_argument_isset(object, "across")) join->across = n; // FIXME: Invalidates operation cache /* How many images down the grid? */ join->down = VIPS_ROUND_UP(n, join->across) / join->across; /* The output size. */ output_width = hspacing * join->across + join->shim * (join->across - 1); output_height = vspacing * join->down + join->shim * (join->down - 1); /* Make a rect for the position of each input. */ join->rects = VIPS_ARRAY(join, n, VipsRect); for (i = 0; i < n; i++) { int x = i % join->across; int y = i / join->across; join->rects[i].left = x * (hspacing + join->shim); join->rects[i].top = y * (vspacing + join->shim); join->rects[i].width = hspacing; join->rects[i].height = vspacing; /* In the centre of the array, we make width / height larger * by shim. */ if (x != join->across - 1) join->rects[i].width += join->shim; if (y != join->down - 1) join->rects[i].height += join->shim; /* The right edge of the final image is stretched to the right * to fill the whole row. */ if (i == n - 1) join->rects[i].width = output_width - join->rects[i].left; } /* A thing to track which inputs we've signalled minimise on. */ join->minimised = VIPS_ARRAY(join, n, gboolean); for (i = 0; i < n; i++) join->minimised[i] = FALSE; /* Each image must be cropped and aligned within an @hspacing by * @vspacing box. */ size = (VipsImage **) vips_object_local_array(object, n); for (i = 0; i < n; i++) { int left, top; int width, height; /* Compiler warnings. */ left = 0; top = 0; switch (join->halign) { case VIPS_ALIGN_LOW: left = 0; break; case VIPS_ALIGN_CENTRE: left = (hspacing - in[i]->Xsize) / 2; break; case VIPS_ALIGN_HIGH: left = hspacing - in[i]->Xsize; break; default: g_assert_not_reached(); break; } switch (join->valign) { case VIPS_ALIGN_LOW: top = 0; break; case VIPS_ALIGN_CENTRE: top = (vspacing - in[i]->Ysize) / 2; break; case VIPS_ALIGN_HIGH: top = vspacing - in[i]->Ysize; break; default: g_assert_not_reached(); break; } width = join->rects[i].width; height = join->rects[i].height; if (vips_embed(in[i], &size[i], left, top, width, height, "extend", VIPS_EXTEND_BACKGROUND, "background", join->background, NULL)) return -1; } if (vips_image_pipeline_array(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, size)) return -1; conversion->out->Xsize = output_width; conversion->out->Ysize = output_height; /* Don't use start_many -- the set of input images can be huge (many * 10s of 1000s) and we don't want to have 20,000 regions active. It's * much quicker to make them on demand. */ if (vips_image_generate(conversion->out, NULL, vips_arrayjoin_gen, NULL, size, join)) return -1; return 0; } static void vips_arrayjoin_class_init(VipsArrayjoinClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_arrayjoin_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "arrayjoin"; vobject_class->description = _("join an array of images"); vobject_class->build = vips_arrayjoin_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_BOXED(class, "in", -1, _("Input"), _("Array of input images"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, in), VIPS_TYPE_ARRAY_IMAGE); VIPS_ARG_INT(class, "across", 4, _("Across"), _("Number of images across grid"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, across), 1, 1000000, 1); VIPS_ARG_INT(class, "shim", 5, _("Shim"), _("Pixels between images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, shim), 0, 1000000, 0); VIPS_ARG_BOXED(class, "background", 6, _("Background"), _("Colour for new pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_ENUM(class, "halign", 7, _("Horizontal align"), _("Align on the left, centre or right"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, halign), VIPS_TYPE_ALIGN, VIPS_ALIGN_LOW); VIPS_ARG_ENUM(class, "valign", 8, _("Vertical align"), _("Align on the top, centre or bottom"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, valign), VIPS_TYPE_ALIGN, VIPS_ALIGN_LOW); VIPS_ARG_INT(class, "hspacing", 9, _("Horizontal spacing"), _("Horizontal spacing between images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, hspacing), 1, 1000000, 1); VIPS_ARG_INT(class, "vspacing", 10, _("Vertical spacing"), _("Vertical spacing between images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsArrayjoin, vspacing), 1, 1000000, 1); } static void vips_arrayjoin_init(VipsArrayjoin *join) { /* Init our instance fields. */ join->background = vips_array_double_newv(1, 0.0); } static int vips_arrayjoinv(VipsImage **in, VipsImage **out, int n, va_list ap) { VipsArrayImage *array; int result; array = vips_array_image_new(in, n); result = vips_call_split("arrayjoin", ap, array, out); vips_area_unref(VIPS_AREA(array)); return result; } /** * vips_arrayjoin: * @in: (array length=n) (transfer none): array of input images * @out: (out): output image * @n: number of input images * @...: `NULL`-terminated list of optional named arguments * * Lay out the images in @in in a grid. The grid is @across images across and * however high is necessary to use up all of @in. Images are set down * left-to-right and top-to-bottom. @across defaults to @n. * * Each input image is placed with a box of size @hspacing by @vspacing * pixels and cropped. These default to the largest width and largest height * of the input images. * * Space between images is filled with @background. This defaults to 0 * (black). * * Images are positioned within their @hspacing by @vspacing box at low, * centre or high coordinate values, controlled by @halign and @valign. These * default to left-top. * * Boxes are joined and separated by @shim pixels. This defaults to 0. * * If the number of bands in the input images differs, all but one of the * images must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the n-band images are operated upon. * * The input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * [method@Image.colourspace] can be useful for moving the images to a common * colourspace for compositing. * * ::: tip "Optional arguments" * * @across: `gint`, number of images per row * * @shim: `gint`, space between images, in pixels * * @background: [struct@ArrayDouble], background ink colour * * @halign: [enum@Align], low, centre or high alignment * * @valign: [enum@Align], low, centre or high alignment * * @hspacing: `gint`, horizontal distance between images * * @vspacing: `gint`, vertical distance between images * * ::: seealso * [method@Image.join], [method@Image.insert], [method@Image.colourspace]. * * Returns: 0 on success, -1 on error */ int vips_arrayjoin(VipsImage **in, VipsImage **out, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_arrayjoinv(in, out, n, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/autorot.c000066400000000000000000000131021516303661500207630ustar00rootroot00000000000000/* autorot * * 19/10/14 * - from jpegload * 12/4/16 * - test and remove orientation from every ifd * 6/10/18 * - don't remove orientation if it's one of the cases we don't handle * 10/5/20 * - handle mirrored images * - deprecate vips_autorot_get_angle() * 24/10/20 * - only remove main image orientation, since we don't rotate the * embedded thumbnail */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pconversion.h" typedef struct _VipsAutorot { VipsConversion parent_instance; VipsImage *in; VipsAngle angle; gboolean flip; } VipsAutorot; typedef VipsConversionClass VipsAutorotClass; G_DEFINE_TYPE(VipsAutorot, vips_autorot, VIPS_TYPE_CONVERSION); static void * vips_autorot_remove_angle_sub(VipsImage *image, const char *field, GValue *value, void *my_data) { if (strcmp(field, "exif-ifd0-Orientation") == 0) { #ifdef DEBUG printf("vips_autorot_remove_angle: %s\n", field); #endif /*DEBUG*/ (void) vips_image_remove(image, field); } return NULL; } /** * vips_autorot_remove_angle: (method) * @image: image to remove orientation from * * Remove the orientation tag on @image. Also remove any exif orientation tags. * You must [method@Image.copy] the image before calling this function since it * modifies metadata. */ void vips_autorot_remove_angle(VipsImage *image) { (void) vips_image_remove(image, VIPS_META_ORIENTATION); (void) vips_image_map(image, vips_autorot_remove_angle_sub, NULL); } static int vips_autorot_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsAutorot *autorot = (VipsAutorot *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); if (VIPS_OBJECT_CLASS(vips_autorot_parent_class)->build(object)) return -1; VipsAngle angle; gboolean flip; VipsImage *in; in = autorot->in; switch (vips_image_get_orientation(in)) { case 2: angle = VIPS_ANGLE_D0; flip = TRUE; break; case 3: angle = VIPS_ANGLE_D180; flip = FALSE; break; case 4: angle = VIPS_ANGLE_D180; flip = TRUE; break; case 5: angle = VIPS_ANGLE_D90; flip = TRUE; break; case 6: angle = VIPS_ANGLE_D90; flip = FALSE; break; case 7: angle = VIPS_ANGLE_D270; flip = TRUE; break; case 8: angle = VIPS_ANGLE_D270; flip = FALSE; break; case 1: default: angle = VIPS_ANGLE_D0; flip = FALSE; break; } g_object_set(object, "angle", angle, "flip", flip, NULL); if (angle != VIPS_ANGLE_D0) { if (vips_rot(in, &t[0], angle, NULL)) return -1; in = t[0]; } if (flip) { if (vips_flip(in, &t[1], VIPS_DIRECTION_HORIZONTAL, NULL)) return -1; in = t[1]; } /* We must copy before modifying metadata. */ if (vips_copy(in, &t[2], NULL)) return -1; in = t[2]; vips_autorot_remove_angle(in); if (vips_image_write(in, conversion->out)) return -1; return 0; } static void vips_autorot_class_init(VipsAutorotClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "autorot"; vobject_class->description = _("autorotate image by exif tag"); vobject_class->build = vips_autorot_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsAutorot, in)); VIPS_ARG_ENUM(class, "angle", 6, _("Angle"), _("Angle image was rotated by"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsAutorot, angle), VIPS_TYPE_ANGLE, VIPS_ANGLE_D0); VIPS_ARG_BOOL(class, "flip", 7, _("Flip"), _("Whether the image was flipped or not"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsAutorot, flip), FALSE); } static void vips_autorot_init(VipsAutorot *autorot) { autorot->angle = VIPS_ANGLE_D0; autorot->flip = FALSE; } /** * vips_autorot: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Look at the image metadata and rotate and flip the image to make it * upright. The [const@META_ORIENTATION] tag is removed from @out to prevent * accidental double rotation. * * Read @angle to find the amount the image was rotated by. Read @flip to * see if the image was also flipped. * * ::: tip "Optional arguments" * * @angle: [enum@Angle], output, the image was rotated by * * @flip: `gboolean`, output, whether the image was flipped * * Returns: 0 on success, -1 on error */ int vips_autorot(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("autorot", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/bandary.c000066400000000000000000000153731516303661500207220ustar00rootroot00000000000000/* base class for various operations on bands * * Copyright: 1991, N. Dessipris, modification of im_bandary() * * Author: N. Dessipris * Written on: 17/04/1991 * Modified on : * 16/3/94 JC * - rewritten for partials * - now in ANSI C * - now works for any number of input images, except zero * 7/10/94 JC * - new IM_NEW() * 16/4/07 * - fall back to im_copy() for 1 input image * 17/1/09 * - cleanups * - gtk-doc * - im_bandary() just calls this * - works for RAD coding too * 27/1/10 * - formatalike inputs * 17/5/11 * - sizealike inputs * 27/10/11 * - rewrite as a class * 20/11/11 * - from bandjoin * 15/12/17 * - remove max images restriction */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "bandary.h" G_DEFINE_ABSTRACT_TYPE(VipsBandary, vips_bandary, VIPS_TYPE_CONVERSION); static int vips_bandary_stop(void *vseq, void *a, void *b) { VipsBandarySequence *seq = (VipsBandarySequence *) vseq; if (seq->ir) { int i; for (i = 0; seq->ir[i]; i++) VIPS_UNREF(seq->ir[i]); VIPS_FREE(seq->ir); } VIPS_FREE(seq->p); VIPS_FREE(seq->pixels); VIPS_FREE(seq); return 0; } static void * vips_bandary_start(VipsImage *out, void *a, void *b) { VipsImage **in = (VipsImage **) a; VipsBandary *bandary = (VipsBandary *) b; VipsBandarySequence *seq; int i, n; if (!(seq = VIPS_NEW(NULL, VipsBandarySequence))) return NULL; seq->bandary = bandary; seq->ir = NULL; seq->p = NULL; seq->pixels = NULL; /* How many images? */ for (n = 0; in[n]; n++) ; /* Allocate space for region array. */ if (!(seq->ir = VIPS_ARRAY(NULL, n + 1, VipsRegion *))) { vips_bandary_stop(seq, NULL, NULL); return NULL; } /* Create a set of regions. */ for (i = 0; i < n; i++) if (!(seq->ir[i] = vips_region_new(in[i]))) { vips_bandary_stop(seq, NULL, NULL); return NULL; } seq->ir[n] = NULL; /* Input pointers. */ if (!(seq->p = VIPS_ARRAY(NULL, n + 1, VipsPel *))) { vips_bandary_stop(seq, NULL, NULL); return NULL; } /* Pixel buffer. This is used as working space by some subclasses. */ if (!(seq->pixels = VIPS_ARRAY(NULL, n * VIPS_IMAGE_SIZEOF_PEL(bandary->ready[0]), VipsPel))) { vips_bandary_stop(seq, NULL, NULL); return NULL; } return seq; } static int vips_bandary_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsBandarySequence *seq = (VipsBandarySequence *) vseq; VipsBandary *bandary = (VipsBandary *) b; VipsBandaryClass *class = VIPS_BANDARY_GET_CLASS(bandary); VipsRect *r = &out_region->valid; VipsPel *q; int y, i; if (vips_reorder_prepare_many(out_region->im, seq->ir, r)) return -1; for (i = 0; i < bandary->n; i++) seq->p[i] = VIPS_REGION_ADDR(seq->ir[i], r->left, r->top); seq->p[i] = NULL; q = VIPS_REGION_ADDR(out_region, r->left, r->top); VIPS_GATE_START("vips_bandary_gen: work"); for (y = 0; y < r->height; y++) { class->process_line(seq, q, seq->p, r->width); for (i = 0; i < bandary->n; i++) seq->p[i] += VIPS_REGION_LSKIP(seq->ir[i]); q += VIPS_REGION_LSKIP(out_region); } VIPS_GATE_STOP("vips_bandary_gen: work"); return 0; } static int vips_bandary_build(VipsObject *object) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); VipsBandaryClass *class = VIPS_BANDARY_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsBandary *bandary = VIPS_BANDARY(object); int i; VipsImage **decode; VipsImage **format; VipsImage **size; if (VIPS_OBJECT_CLASS(vips_bandary_parent_class)->build(object)) return -1; if (bandary->n <= 0) { vips_error(object_class->nickname, "%s", _("no input images")); return -1; } decode = (VipsImage **) vips_object_local_array(object, bandary->n); format = (VipsImage **) vips_object_local_array(object, bandary->n); size = (VipsImage **) vips_object_local_array(object, bandary->n); for (i = 0; i < bandary->n; i++) if (vips_image_decode(bandary->in[i], &decode[i])) return -1; if (vips__formatalike_vec(decode, format, bandary->n) || vips__sizealike_vec(format, size, bandary->n)) return -1; bandary->ready = size; if (vips_image_pipeline_array(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, bandary->ready)) return -1; conversion->out->Bands = bandary->out_bands; if (class->format_table) conversion->out->BandFmt = class->format_table[bandary->ready[0]->BandFmt]; if (vips_image_generate(conversion->out, vips_bandary_start, vips_bandary_gen, vips_bandary_stop, bandary->ready, bandary)) return -1; return 0; } static void vips_bandary_class_init(VipsBandaryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_bandary_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "bandary"; vobject_class->description = _("operations on image bands"); vobject_class->build = vips_bandary_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; } static void vips_bandary_init(VipsBandary *bandary) { bandary->out_bands = -1; } /* Call this before chaining up in _build() to make the operation fall back to * copy. */ int vips_bandary_copy(VipsBandary *bandary) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(bandary); VipsConversion *conversion = VIPS_CONVERSION(bandary); if (!bandary->in) { vips_error(object_class->nickname, "%s", _("no input images")); return -1; } /* This isn't set by arith until build(), so we have to set * again here. * * Should arith set out in _init()? */ g_object_set(bandary, "out", vips_image_new(), NULL); return vips_image_write(bandary->in[0], conversion->out); } libvips-8.18.2/libvips/conversion/bandary.h000066400000000000000000000054151516303661500207230ustar00rootroot00000000000000/* base class for various operations on bands */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS__BANDARY_H #define VIPS__BANDARY_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include "pconversion.h" #define VIPS_TYPE_BANDARY (vips_bandary_get_type()) #define VIPS_BANDARY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_BANDARY, VipsBandary)) #define VIPS_BANDARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_BANDARY, VipsBandaryClass)) #define VIPS_IS_BANDARY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_BANDARY)) #define VIPS_IS_BANDARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_BANDARY)) #define VIPS_BANDARY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_BANDARY, VipsBandaryClass)) struct _VipsBandary; /* Our sequence value. */ typedef struct { struct _VipsBandary *bandary; /* Set of input regions. */ VipsRegion **ir; /* For each input, an input pointer. */ VipsPel **p; /* A memory area large enough to hold one pixel from each input image. */ VipsPel *pixels; } VipsBandarySequence; typedef void (*VipsBandaryProcessFn)(VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width); typedef struct _VipsBandary { VipsConversion parent_instance; /* Array of input arguments, set these from a subclass. */ VipsImage **in; int n; /* The number of output bands. For example, VipsBandjoin sets the sum * of the bands in the input images. */ int out_bands; /* The input images, ready for the operation. */ VipsImage **ready; } VipsBandary; typedef struct _VipsBandaryClass { VipsConversionClass parent_class; /* The buffer processor. */ VipsBandaryProcessFn process_line; /* For each input format, what output format. Leave NULL for output * format == input format. */ const VipsBandFormat *format_table; } VipsBandaryClass; GType vips_bandary_get_type(void); int vips_bandary_copy(VipsBandary *bandary); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS__BANDARY_H*/ libvips-8.18.2/libvips/conversion/bandbool.c000066400000000000000000000204131516303661500210510ustar00rootroot00000000000000/* bandbool.c -- bool op across image bands * * 7/12/12 * - from boolean.c */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "bandary.h" typedef struct _VipsBandbool { VipsBandary parent_instance; VipsImage *in; VipsOperationBoolean operation; } VipsBandbool; typedef VipsBandaryClass VipsBandboolClass; G_DEFINE_TYPE(VipsBandbool, vips_bandbool, VIPS_TYPE_BANDARY); static int vips_bandbool_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBandary *bandary = (VipsBandary *) object; VipsBandbool *bandbool = (VipsBandbool *) object; /* << and >> don't work over bands. */ if (bandbool->operation == VIPS_OPERATION_BOOLEAN_LSHIFT || bandbool->operation == VIPS_OPERATION_BOOLEAN_RSHIFT) { vips_error(class->nickname, _("operator %s not supported across image bands"), vips_enum_nick(VIPS_TYPE_OPERATION_BOOLEAN, bandbool->operation)); return -1; } if (bandbool->in) { if (vips_check_noncomplex(class->nickname, bandbool->in)) return -1; bandary->n = 1; bandary->in = &bandbool->in; if (bandbool->in->Bands == 1) return vips_bandary_copy(bandary); } bandary->out_bands = 1; if (VIPS_OBJECT_CLASS(vips_bandbool_parent_class)->build(object)) return -1; return 0; } #define SWITCH(I, F, OP) \ switch (vips_image_get_format(im)) { \ case VIPS_FORMAT_UCHAR: \ I(unsigned char, OP); \ break; \ case VIPS_FORMAT_CHAR: \ I(signed char, OP); \ break; \ case VIPS_FORMAT_USHORT: \ I(unsigned short, OP); \ break; \ case VIPS_FORMAT_SHORT: \ I(signed short, OP); \ break; \ case VIPS_FORMAT_UINT: \ I(unsigned int, OP); \ break; \ case VIPS_FORMAT_INT: \ I(signed int, OP); \ break; \ case VIPS_FORMAT_FLOAT: \ F(float, OP); \ break; \ case VIPS_FORMAT_DOUBLE: \ F(double, OP); \ break; \ \ default: \ g_assert_not_reached(); \ } #define LOOPB(TYPE, OP) \ { \ TYPE *p = (TYPE *) in[0]; \ TYPE *q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ TYPE acc; \ \ acc = p[0]; \ for (b = 1; b < bands; b++) \ acc = acc OP p[b]; \ \ q[x] = acc; \ p += bands; \ } \ } #define FLOOPB(TYPE, OP) \ { \ TYPE *p = (TYPE *) in[0]; \ int *q = (int *) out; \ \ for (x = 0; x < width; x++) { \ int acc; \ \ acc = (int) p[0]; \ for (b = 1; b < bands; b++) \ acc = acc OP((int) p[b]); \ \ q[x] = acc; \ p += bands; \ } \ } static void vips_bandbool_buffer(VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width) { VipsBandary *bandary = seq->bandary; VipsBandbool *bandbool = (VipsBandbool *) bandary; VipsImage *im = bandary->ready[0]; int bands = im->Bands; int x, b; switch (bandbool->operation) { case VIPS_OPERATION_BOOLEAN_AND: SWITCH(LOOPB, FLOOPB, &); break; case VIPS_OPERATION_BOOLEAN_OR: SWITCH(LOOPB, FLOOPB, |); break; case VIPS_OPERATION_BOOLEAN_EOR: SWITCH(LOOPB, FLOOPB, ^); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Format conversions for boolean. */ static const VipsBandFormat vips_bandbool_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, I, I, I, I }; static void vips_bandbool_class_init(VipsBandboolClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "bandbool"; object_class->description = _("boolean operation across image bands"); object_class->build = vips_bandbool_build; bandary_class->process_line = vips_bandbool_buffer; bandary_class->format_table = vips_bandbool_format_table; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandbool, in)); VIPS_ARG_ENUM(class, "boolean", 200, _("Operation"), _("Boolean to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandbool, operation), VIPS_TYPE_OPERATION_BOOLEAN, VIPS_OPERATION_BOOLEAN_AND); } static void vips_bandbool_init(VipsBandbool *bandbool) { bandbool->operation = VIPS_OPERATION_BOOLEAN_AND; } static int vips_bandboolv(VipsImage *in, VipsImage **out, VipsOperationBoolean operation, va_list ap) { return vips_call_split("bandbool", ap, in, out, operation); } /** * vips_bandbool: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @boolean: boolean operation to perform * @...: `NULL`-terminated list of optional named arguments * * Perform various boolean operations across the bands of an image. For * example, a three-band uchar image operated on with * [enum@Vips.OperationBoolean.AND] will produce a one-band uchar image where each * pixel is the bitwise and of the band elements of the corresponding pixel in * the input image. * * The output image is the same format as the input image for integer * types. Float types are cast to int before processing. Complex types are not * supported. * * The output image always has one band. * * This operation is useful in conjunction with [method@Image.relational]. You can use * it to see if all image bands match exactly. * * ::: seealso * [method@Image.boolean_const]. * * Returns: 0 on success, -1 on error */ int vips_bandbool(VipsImage *in, VipsImage **out, VipsOperationBoolean boolean, ...) { va_list ap; int result; va_start(ap, boolean); result = vips_bandboolv(in, out, boolean, ap); va_end(ap); return result; } /** * vips_bandand: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.AND] on an image. See * [method@Image.bandbool]. * * Returns: 0 on success, -1 on error */ int vips_bandand(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_bandboolv(in, out, VIPS_OPERATION_BOOLEAN_AND, ap); va_end(ap); return result; } /** * vips_bandor: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.OR] on an image. See * [method@Image.bandbool]. * * Returns: 0 on success, -1 on error */ int vips_bandor(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_bandboolv(in, out, VIPS_OPERATION_BOOLEAN_OR, ap); va_end(ap); return result; } /** * vips_bandeor: (method) * @in: left-hand input [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * Perform [enum@Vips.OperationBoolean.EOR] on an image. See * [method@Image.bandbool]. * * Returns: 0 on success, -1 on error */ int vips_bandeor(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_bandboolv(in, out, VIPS_OPERATION_BOOLEAN_EOR, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/bandfold.c000066400000000000000000000120361516303661500210440ustar00rootroot00000000000000/* Fold up x into bands. * * 5/6/15 * - from copy.c * 10/6/15 * - add @factor option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsBandfold { VipsConversion parent_instance; /* The input image. */ VipsImage *in; int factor; } VipsBandfold; typedef VipsConversionClass VipsBandfoldClass; G_DEFINE_TYPE(VipsBandfold, vips_bandfold, VIPS_TYPE_CONVERSION); static int vips_bandfold_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsBandfold *bandfold = (VipsBandfold *) b; VipsRegion *ir = (VipsRegion *) seq; VipsImage *out = out_region->im; VipsRect *r = &out_region->valid; int psize = VIPS_IMAGE_SIZEOF_PEL(out); VipsRect need; int y; need.left = r->left * bandfold->factor; need.top = r->top; need.width = r->width * bandfold->factor; need.height = r->height; if (vips_region_prepare(ir, &need)) return -1; for (y = 0; y < r->height; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, r->left * bandfold->factor, r->top + y); VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); /* We can't use vips_region_region() since we change pixel * coordinates. */ memcpy(q, p, (size_t) psize * r->width); } return 0; } static int vips_bandfold_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsBandfold *bandfold = (VipsBandfold *) object; if (VIPS_OBJECT_CLASS(vips_bandfold_parent_class)->build(object)) return -1; if (vips_image_pio_input(bandfold->in)) return -1; if (bandfold->factor == 0) bandfold->factor = bandfold->in->Xsize; // FIXME: Invalidates operation cache if (bandfold->in->Xsize % bandfold->factor != 0) { vips_error(class->nickname, "%s", _("@factor must be a factor of image width")); return -1; } if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, bandfold->in, NULL)) return -1; conversion->out->Xsize /= bandfold->factor; conversion->out->Bands *= bandfold->factor; if (vips_image_generate(conversion->out, vips_start_one, vips_bandfold_gen, vips_stop_one, bandfold->in, bandfold)) return -1; return 0; } static void vips_bandfold_class_init(VipsBandfoldClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_bandfold_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "bandfold"; vobject_class->description = _("fold up x axis into bands"); vobject_class->build = vips_bandfold_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandfold, in)); VIPS_ARG_INT(class, "factor", 11, _("Factor"), _("Fold by this factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBandfold, factor), 0, 10000000, 0); } static void vips_bandfold_init(VipsBandfold *bandfold) { /* 0 means fold by width, see above. */ bandfold->factor = 0; } /** * vips_bandfold: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Fold up an image horizontally: width is collapsed into bands. * Use @factor to set how much to fold by: @factor 3, for example, will make * the output image three times narrower than the input, and with three times * as many bands. By default the whole of the input width is folded up. * * ::: tip "Optional arguments" * * @factor: `gint`, fold by this factor * * ::: seealso * [ctor@Image.csvload], [method@Image.bandunfold]. * * Returns: 0 on success, -1 on error. */ int vips_bandfold(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("bandfold", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/bandjoin.c000066400000000000000000000256511516303661500210660ustar00rootroot00000000000000/* VipsBandjoin -- bandwise join of a set of images * * Copyright: 1991, N. Dessipris, modification of im_bandjoin() * * Author: N. Dessipris * Written on: 17/04/1991 * Modified on : * 16/3/94 JC * - rewritten for partials * - now in ANSI C * - now works for any number of input images, except zero * 7/10/94 JC * - new IM_NEW() * 16/4/07 * - fall back to im_copy() for 1 input image * 17/1/09 * - cleanups * - gtk-doc * - im_bandjoin() just calls this * - works for RAD coding too * 27/1/10 * - formatalike inputs * 17/5/11 * - sizealike inputs * 27/10/11 * - rewrite as a class * 7/11/15 * - added bandjoin_const */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "bandary.h" typedef struct _VipsBandjoin { VipsBandary parent_instance; /* The input images. */ VipsArrayImage *in; } VipsBandjoin; typedef VipsBandaryClass VipsBandjoinClass; G_DEFINE_TYPE(VipsBandjoin, vips_bandjoin, VIPS_TYPE_BANDARY); static void vips_bandjoin_buffer(VipsBandarySequence *seq, VipsPel *q, VipsPel **p, int width) { VipsBandary *bandary = seq->bandary; VipsConversion *conversion = (VipsConversion *) bandary; VipsImage **in = bandary->ready; /* Output pel size. */ const int ops = VIPS_IMAGE_SIZEOF_PEL(conversion->out); int i; /* Loop for each input image. Scattered write is faster than * scattered read. */ for (i = 0; i < bandary->n; i++) { /* Input pel size. */ int ips = VIPS_IMAGE_SIZEOF_PEL(in[i]); VipsPel *restrict p1; VipsPel *restrict q1; int x, z; q1 = q; p1 = p[i]; if (ips == 1) { for (x = 0; x < width; x++) { q1[0] = p1[x]; q1 += ops; } q += ips; } else if (ips == 3) { for (x = 0; x < width; x++) { q1[0] = p1[0]; q1[1] = p1[1]; q1[2] = p1[2]; p1 += ips; q1 += ops; } q += ips; } else { for (x = 0; x < width; x++) { for (z = 0; z < ips; z++) q1[z] = p1[z]; p1 += ips; q1 += ops; } q += ips; } } } static int vips_bandjoin_build(VipsObject *object) { VipsBandary *bandary = (VipsBandary *) object; VipsBandjoin *bandjoin = (VipsBandjoin *) object; if (bandjoin->in) { bandary->in = vips_array_image_get(bandjoin->in, &bandary->n); if (bandary->n == 1) return vips_bandary_copy(bandary); else { int i; bandary->out_bands = 0; for (i = 0; i < bandary->n; i++) if (bandary->in[i]) bandary->out_bands += bandary->in[i]->Bands; } } if (VIPS_OBJECT_CLASS(vips_bandjoin_parent_class)->build(object)) return -1; return 0; } static void vips_bandjoin_class_init(VipsBandjoinClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); VIPS_DEBUG_MSG("vips_bandjoin_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "bandjoin"; vobject_class->description = _("bandwise join a set of images"); vobject_class->build = vips_bandjoin_build; bandary_class->process_line = vips_bandjoin_buffer; VIPS_ARG_BOXED(class, "in", 0, _("Input"), _("Array of input images"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandjoin, in), VIPS_TYPE_ARRAY_IMAGE); } static void vips_bandjoin_init(VipsBandjoin *bandjoin) { /* Init our instance fields. */ } static int vips_bandjoinv(VipsImage **in, VipsImage **out, int n, va_list ap) { VipsArrayImage *array; int result; array = vips_array_image_new(in, n); result = vips_call_split("bandjoin", ap, array, out); vips_area_unref(VIPS_AREA(array)); return result; } /** * vips_bandjoin: * @in: (array length=n) (transfer none): array of input images * @out: (out): output image * @n: number of input images * @...: `NULL`-terminated list of optional named arguments * * Join a set of images together, bandwise. * * If the images * have n and m bands, then the output image will have n + m * bands, with the first n coming from the first image and the last m * from the second. * * If the images differ in size, the smaller images are enlarged to match the * larger by adding zero pixels along the bottom and right. * * The input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * ::: seealso * [method@Image.insert]. * * Returns: 0 on success, -1 on error */ int vips_bandjoin(VipsImage **in, VipsImage **out, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_bandjoinv(in, out, n, ap); va_end(ap); return result; } /** * vips_bandjoin2: (method) * @in1: first input image * @in2: second input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Join a pair of images together, bandwise. See [func@Image.bandjoin]. * * Returns: 0 on success, -1 on error */ int vips_bandjoin2(VipsImage *in1, VipsImage *in2, VipsImage **out, ...) { va_list ap; int result; VipsImage *in[2]; in[0] = in1; in[1] = in2; va_start(ap, out); result = vips_bandjoinv(in, out, 2, ap); va_end(ap); return result; } typedef struct _VipsBandjoinConst { VipsBandary parent_instance; VipsImage *in; VipsArrayDouble *c; /* The constant expanded to in's format, ready to be appended to each * pixel. */ int n; VipsPel *c_ready; } VipsBandjoinConst; typedef VipsBandaryClass VipsBandjoinConstClass; G_DEFINE_TYPE(VipsBandjoinConst, vips_bandjoin_const, VIPS_TYPE_BANDARY); static void vips_bandjoin_const_finalize(GObject *object) { VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) object; VIPS_FREE(bandjoin->c_ready); G_OBJECT_CLASS(vips_bandjoin_const_parent_class)->finalize(object); } static void vips_bandjoin_const_buffer(VipsBandarySequence *seq, VipsPel *q, VipsPel **p, int width) { VipsBandary *bandary = seq->bandary; VipsConversion *conversion = (VipsConversion *) bandary; VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) bandary; VipsImage *in = bandary->ready[0]; /* Output pel size. */ const int ops = VIPS_IMAGE_SIZEOF_PEL(conversion->out); /* Input pel size. */ const int ips = VIPS_IMAGE_SIZEOF_PEL(in); /* Extra bands size. */ const int ebs = ops - ips; VipsPel *restrict p1; VipsPel *restrict q1; int x, z; q1 = q; p1 = p[0]; /* Special path for 8-bit RGB -> RGBA ... it's a common case. */ if (ips == 3 && ebs == 1) { int c = bandjoin->c_ready[0]; for (x = 0; x < width; x++) { q1[0] = p1[0]; q1[1] = p1[1]; q1[2] = p1[2]; q1[3] = c; p1 += 3; q1 += 4; } } else { for (x = 0; x < width; x++) { for (z = 0; z < ips; z++) q1[z] = p1[z]; p1 += ips; q1 += ips; for (z = 0; z < ebs; z++) q1[z] = bandjoin->c_ready[z]; q1 += ebs; } } } static int vips_bandjoin_const_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBandary *bandary = (VipsBandary *) object; VipsBandjoinConst *bandjoin = (VipsBandjoinConst *) object; if (bandjoin->c && bandjoin->in) { double *c; int n; c = vips_array_double_get(bandjoin->c, &n); if (n == 0) return vips_bandary_copy(bandary); else bandary->out_bands = bandjoin->in->Bands + n; bandary->n = 1; bandary->in = &bandjoin->in; if (!(bandjoin->c_ready = vips__vector_to_pels(class->nickname, n, bandjoin->in->BandFmt, bandjoin->in->Coding, c, NULL, n))) return -1; } if (VIPS_OBJECT_CLASS(vips_bandjoin_const_parent_class)->build(object)) return -1; return 0; } static void vips_bandjoin_const_class_init(VipsBandjoinConstClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); VIPS_DEBUG_MSG("vips_bandjoin_const_class_init\n"); gobject_class->finalize = vips_bandjoin_const_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "bandjoin_const"; vobject_class->description = _("append a constant band to an image"); vobject_class->build = vips_bandjoin_const_build; bandary_class->process_line = vips_bandjoin_const_buffer; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandjoinConst, in)); VIPS_ARG_BOXED(class, "c", 12, _("Constants"), _("Array of constants to add"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandjoinConst, c), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_bandjoin_const_init(VipsBandjoinConst *bandjoin) { /* Init our instance fields. */ } static int vips_bandjoin_constv(VipsImage *in, VipsImage **out, double *c, int n, va_list ap) { VipsArrayDouble *array; int result; array = vips_array_double_new(c, n); result = vips_call_split("bandjoin_const", ap, in, out, array); vips_area_unref(VIPS_AREA(array)); return result; } /** * vips_bandjoin_const: (method) * @in: input image * @out: (out): output image * @c: (array length=n): array of constants to append * @n: number of constants * @...: `NULL`-terminated list of optional named arguments * * Append a set of constant bands to an image. * * ::: seealso * [func@Image.bandjoin]. * * Returns: 0 on success, -1 on error */ int vips_bandjoin_const(VipsImage *in, VipsImage **out, double *c, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_bandjoin_constv(in, out, c, n, ap); va_end(ap); return result; } /** * vips_bandjoin_const1: (method) * @in: input image * @out: (out): output image * @c: constant to append * @...: `NULL`-terminated list of optional named arguments * * Append a single constant band to an image. * * Returns: 0 on success, -1 on error */ int vips_bandjoin_const1(VipsImage *in, VipsImage **out, double c, ...) { va_list ap; int result; va_start(ap, c); result = vips_bandjoin_constv(in, out, &c, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/bandmean.c000066400000000000000000000124601516303661500210410ustar00rootroot00000000000000/* average image bands * * Author: Simon Goodall * Written on: 17/7/07 * 17/7/07 JC * - hacked about a bit * 18/8/09 * - gtkdoc * - get rid of the complex case, just double the width * 19/11/11 * - redo as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "bandary.h" typedef struct _VipsBandmean { VipsBandary parent_instance; VipsImage *in; } VipsBandmean; typedef VipsBandaryClass VipsBandmeanClass; G_DEFINE_TYPE(VipsBandmean, vips_bandmean, VIPS_TYPE_BANDARY); /* Unsigned int types. Round, keep sum in a larger variable. */ #define UILOOP(TYPE, STYPE) \ { \ TYPE *p = (TYPE *) in[0]; \ TYPE *q = (TYPE *) out; \ \ for (i = 0; i < sz; i++) { \ STYPE sum; \ \ sum = 0; \ for (j = 0; j < bands; j++) \ sum += p[j]; \ q[i] = (sum + bands / 2) / bands; \ p += bands; \ } \ } /* Signed int types. Round, keep sum in a larger variable. */ #define SILOOP(TYPE, STYPE) \ { \ TYPE *p = (TYPE *) in[0]; \ TYPE *q = (TYPE *) out; \ \ for (i = 0; i < sz; i++) { \ STYPE sum; \ \ sum = 0; \ for (j = 0; j < bands; j++) \ sum += p[j]; \ q[i] = sum > 0 \ ? (sum + bands / 2) / bands \ : (sum - bands / 2) / bands; \ p += bands; \ } \ } /* Float loop. No rounding, sum in same container. */ #define FLOOP(TYPE) \ { \ TYPE *p = (TYPE *) in[0]; \ TYPE *q = (TYPE *) out; \ \ for (i = 0; i < sz; i++) { \ TYPE sum; \ \ sum = 0; \ for (j = 0; j < bands; j++) \ sum += p[j]; \ q[i] = sum / bands; \ p += bands; \ } \ } static void vips_bandmean_buffer(VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width) { VipsBandary *bandary = seq->bandary; VipsImage *im = bandary->ready[0]; const int bands = im->Bands; const int sz = width * (vips_band_format_iscomplex(im->BandFmt) ? 2 : 1); int i, j; switch (vips_image_get_format(im)) { case VIPS_FORMAT_CHAR: SILOOP(signed char, int); break; case VIPS_FORMAT_UCHAR: UILOOP(unsigned char, unsigned int); break; case VIPS_FORMAT_SHORT: SILOOP(signed short, int); break; case VIPS_FORMAT_USHORT: UILOOP(unsigned short, unsigned int); break; case VIPS_FORMAT_INT: SILOOP(signed int, int64_t); break; case VIPS_FORMAT_UINT: UILOOP(unsigned int, uint64_t); break; case VIPS_FORMAT_FLOAT: FLOOP(float); break; case VIPS_FORMAT_DOUBLE: FLOOP(double); break; case VIPS_FORMAT_COMPLEX: FLOOP(float); break; case VIPS_FORMAT_DPCOMPLEX: FLOOP(double); break; default: g_assert_not_reached(); } } static int vips_bandmean_build(VipsObject *object) { VipsBandary *bandary = (VipsBandary *) object; VipsBandmean *bandmean = (VipsBandmean *) object; bandary->n = 1; bandary->in = &bandmean->in; if (bandmean->in && bandmean->in->Bands == 1) return vips_bandary_copy(bandary); bandary->out_bands = 1; if (VIPS_OBJECT_CLASS(vips_bandmean_parent_class)->build(object)) return -1; return 0; } static void vips_bandmean_class_init(VipsBandmeanClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "bandmean"; object_class->description = _("band-wise average"); object_class->build = vips_bandmean_build; bandary_class->process_line = vips_bandmean_buffer; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandmean, in)); } static void vips_bandmean_init(VipsBandmean *bandmean) { } /** * vips_bandmean: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation writes a one-band image where each pixel is the average of * the bands for that pixel in the input image. The output band format is * the same as the input band format. Integer types use round-to-nearest * averaging. * * ::: seealso * [method@Image.add], [method@Image.avg], [method@Image.recomb] * * Returns: 0 on success, -1 on error */ int vips_bandmean(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("bandmean", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/bandrank.c000066400000000000000000000167641516303661500210670ustar00rootroot00000000000000/* Sort a set of images, pixelwise, and pick out the index at each point. * * 19/8/03 * - from im_maxvalue(), via im_gbandrank() * 10/11/10 * - gtkdoc * - cleanups * - any mix of formats and bands * 23/10/13 * - redo as a class, from bandjoin.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "bandary.h" typedef struct _VipsBandrank { VipsBandary parent_instance; /* The input images. */ VipsArrayImage *in; int index; /* Pick out this one */ } VipsBandrank; typedef VipsBandaryClass VipsBandrankClass; G_DEFINE_TYPE(VipsBandrank, vips_bandrank, VIPS_TYPE_BANDARY); /* Special-case max and min (rather common). */ #define FIND_MAX(TYPE) \ { \ for (x = 0; x < sz; x++) { \ TYPE top = ((TYPE *) p[0])[x]; \ \ for (i = 1; i < bandary->n; i++) { \ TYPE v = ((TYPE *) p[i])[x]; \ \ if (v > top) \ top = v; \ } \ \ ((TYPE *) q)[x] = top; \ } \ } #define FIND_MIN(TYPE) \ { \ for (x = 0; x < sz; x++) { \ TYPE bot = ((TYPE *) p[0])[x]; \ \ for (i = 1; i < bandary->n; i++) { \ TYPE v = ((TYPE *) p[i])[x]; \ \ if (v < bot) \ bot = v; \ } \ \ ((TYPE *) q)[x] = bot; \ } \ } #define FIND_RANK(TYPE) \ { \ TYPE *sort = (TYPE *) sort_buffer; \ \ for (x = 0; x < sz; x++) { \ for (i = 0; i < bandary->n; i++) { \ TYPE v = ((TYPE *) p[i])[x]; \ \ /* Search for element >v. \ */ \ for (j = 0; j < i; j++) \ if (sort[j] > v) \ break; \ \ /* Move remaining elements down. \ */ \ for (k = i; k > j; k--) \ sort[k] = sort[k - 1]; \ \ /* Insert this element. \ */ \ sort[j] = v; \ } \ \ ((TYPE *) q)[x] = sort[bandrank->index]; \ } \ } #define SWITCH(OPERATION) \ switch (in[0]->BandFmt) { \ case VIPS_FORMAT_UCHAR: \ OPERATION(unsigned char); \ break; \ case VIPS_FORMAT_CHAR: \ OPERATION(signed char); \ break; \ case VIPS_FORMAT_USHORT: \ OPERATION(unsigned short); \ break; \ case VIPS_FORMAT_SHORT: \ OPERATION(signed short); \ break; \ case VIPS_FORMAT_UINT: \ OPERATION(unsigned int); \ break; \ case VIPS_FORMAT_INT: \ OPERATION(signed int); \ break; \ case VIPS_FORMAT_FLOAT: \ OPERATION(float); \ break; \ case VIPS_FORMAT_DOUBLE: \ OPERATION(double); \ break; \ \ default: \ g_assert_not_reached(); \ } /* Sort input band elements in the stack. Needs to be big enough for * sizeof(band-element) * number-of-images. */ static void vips_bandrank_buffer(VipsBandarySequence *seq, VipsPel *q, VipsPel **p, int width) { VipsBandary *bandary = seq->bandary; VipsBandrank *bandrank = (VipsBandrank *) bandary; VipsImage **in = bandary->ready; int sz = width * in[0]->Bands; VipsPel *sort_buffer = seq->pixels; int i, j, k; int x; /* Special-case max and min. */ if (bandrank->index == 0) SWITCH(FIND_MIN) else if (bandrank->index == bandary->n - 1) SWITCH(FIND_MAX) else SWITCH(FIND_RANK) } static int vips_bandrank_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBandary *bandary = (VipsBandary *) object; VipsBandrank *bandrank = (VipsBandrank *) object; if (bandrank->in) { int n; VipsImage **in = vips_array_image_get(bandrank->in, &n); VipsImage **band = (VipsImage **) vips_object_local_array(object, n); int i; for (i = 0; i < n; i++) if (vips_check_noncomplex(class->nickname, in[i])) return -1; if (n == 1) { bandary->in = in; bandary->n = 1; return vips_bandary_copy(bandary); } if (vips__bandalike_vec(class->nickname, in, band, n, 0)) return -1; bandary->in = band; bandary->n = n; bandary->out_bands = band[0]->Bands; if (bandrank->index == -1) bandrank->index = bandary->n / 2; // FIXME: Invalidates operation cache else if (bandrank->index >= bandary->n) { vips_error(class->nickname, _("index out of range")); return -1; } } if (VIPS_OBJECT_CLASS(vips_bandrank_parent_class)->build(object)) return -1; return 0; } static void vips_bandrank_class_init(VipsBandrankClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); VIPS_DEBUG_MSG("vips_bandrank_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "bandrank"; vobject_class->description = _("band-wise rank of a set of images"); vobject_class->build = vips_bandrank_build; bandary_class->process_line = vips_bandrank_buffer; VIPS_ARG_BOXED(class, "in", 0, _("Input"), _("Array of input images"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandrank, in), VIPS_TYPE_ARRAY_IMAGE); VIPS_ARG_INT(class, "index", 0, _("Index"), _("Select this band element from sorted list"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBandrank, index), -1, 1000000, -1); } static void vips_bandrank_init(VipsBandrank *bandrank) { /* -1 means median. */ bandrank->index = -1; } static int vips_bandrankv(VipsImage **in, VipsImage **out, int n, va_list ap) { VipsArrayImage *array; int result; array = vips_array_image_new(in, n); result = vips_call_split("bandrank", ap, array, out); vips_area_unref(VIPS_AREA(array)); return result; } /** * vips_bandrank: * @in: (array length=n): array of input images * @out: (out): output image * @n: number of input images * @...: `NULL`-terminated list of optional named arguments * * Sorts the images @in band-element-wise, then outputs an * image in which each band element is selected from the sorted list by the * @index parameter. For example, if @index * is zero, then each output band element will be the minimum of all the * corresponding input band elements. * * By default, @index is -1, meaning pick the median value. * * It works for any uncoded, non-complex image type. Images are cast up to the * smallest common-format. * * Any image can have either 1 band or n bands, where n is the same for all * the non-1-band images. Single band images are then effectively copied to * make n-band images. * * Smaller input images are expanded by adding black pixels. * * ::: tip "Optional arguments" * * @index: `gint`, pick this index from list of sorted values * * ::: seealso * [method@Image.rank]. * * Returns: 0 on success, -1 on error */ int vips_bandrank(VipsImage **in, VipsImage **out, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_bandrankv(in, out, n, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/bandunfold.c000066400000000000000000000123311516303661500214050ustar00rootroot00000000000000/* Fold up x into bands. * * 5/6/15 * - from copy.c * 10/6/15 * - add @factor option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsBandunfold { VipsConversion parent_instance; /* The input image. */ VipsImage *in; int factor; } VipsBandunfold; typedef VipsConversionClass VipsBandunfoldClass; G_DEFINE_TYPE(VipsBandunfold, vips_bandunfold, VIPS_TYPE_CONVERSION); static int vips_bandunfold_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsBandunfold *bandunfold = (VipsBandunfold *) b; VipsRegion *ir = (VipsRegion *) seq; VipsImage *in = ir->im; VipsImage *out = out_region->im; VipsRect *r = &out_region->valid; int esize = VIPS_IMAGE_SIZEOF_ELEMENT(in); int psize = VIPS_IMAGE_SIZEOF_PEL(out); VipsRect need; int y; need.left = r->left / bandunfold->factor; need.top = r->top; need.width = 1 + VIPS_RECT_RIGHT(r) / bandunfold->factor - need.left; need.height = r->height; if (vips_region_prepare(ir, &need)) return -1; for (y = 0; y < r->height; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, r->left / bandunfold->factor, r->top + y) + (r->left % bandunfold->factor) * esize; VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); /* We can't use vips_region_region() since we change pixel * coordinates. */ memcpy(q, p, (size_t) r->width * psize); } return 0; } static int vips_bandunfold_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsBandunfold *bandunfold = (VipsBandunfold *) object; if (VIPS_OBJECT_CLASS(vips_bandunfold_parent_class)->build(object)) return -1; if (vips_image_pio_input(bandunfold->in)) return -1; if (bandunfold->factor == 0) bandunfold->factor = bandunfold->in->Bands; // FIXME: Invalidates operation cache if (bandunfold->in->Bands % bandunfold->factor != 0) { vips_error(class->nickname, "%s", _("@factor must be a factor of image bands")); return -1; } if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, bandunfold->in, NULL)) return -1; conversion->out->Xsize *= bandunfold->factor; conversion->out->Bands /= bandunfold->factor; if (vips_image_generate(conversion->out, vips_start_one, vips_bandunfold_gen, vips_stop_one, bandunfold->in, bandunfold)) return -1; return 0; } static void vips_bandunfold_class_init(VipsBandunfoldClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_bandunfold_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "bandunfold"; vobject_class->description = _("unfold image bands into x axis"); vobject_class->build = vips_bandunfold_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBandunfold, in)); VIPS_ARG_INT(class, "factor", 11, _("Factor"), _("Unfold by this factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBandunfold, factor), 0, 10000000, 0); } static void vips_bandunfold_init(VipsBandunfold *bandunfold) { /* 0 means unfold by width, see above. */ bandunfold->factor = 0; } /** * vips_bandunfold: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Unfold image bands into x axis. * Use @factor to set how much to unfold by: @factor 3, for example, will make * the output image three times wider than the input, and with one third * as many bands. By default, all bands are unfolded. * * ::: tip "Optional arguments" * * @factor: `gint`, unfold by this factor * * ::: seealso * [ctor@Image.csvload], [method@Image.bandfold]. * * Returns: 0 on success, -1 on error. */ int vips_bandunfold(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("bandunfold", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/byteswap.c000066400000000000000000000151451516303661500211350ustar00rootroot00000000000000/* Swap image byte order. * * 5/6/15 * - from copy.c * 27/1/16 * - don't swap coded images * 11/3/24 * - support unaligned images */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsByteswap { VipsConversion parent_instance; /* The input image. */ VipsImage *in; } VipsByteswap; typedef VipsConversionClass VipsByteswapClass; G_DEFINE_TYPE(VipsByteswap, vips_byteswap, VIPS_TYPE_CONVERSION); /* Swap pairs of bytes. */ static void vips_byteswap_swap2(VipsPel *in, VipsPel *out, int width, VipsImage *im) { guint16 *p = (guint16 *) in; guint16 *q = (guint16 *) out; int sz = (VIPS_IMAGE_SIZEOF_PEL(im) * width) / 2; int x; // must be 2-byte aligned, or behaviour is undefined g_assert(VIPS_ALIGNED(p, 2) && VIPS_ALIGNED(q, 2)); for (x = 0; x < sz; x++) q[x] = GUINT16_SWAP_LE_BE(p[x]); } /* Swap 4- of bytes. */ static void vips_byteswap_swap4(VipsPel *in, VipsPel *out, int width, VipsImage *im) { guint32 *p = (guint32 *) in; guint32 *q = (guint32 *) out; int sz = (VIPS_IMAGE_SIZEOF_PEL(im) * width) / 4; int x; // must be 4-byte aligned, or behaviour is undefined g_assert(VIPS_ALIGNED(p, 4) && VIPS_ALIGNED(q, 4)); for (x = 0; x < sz; x++) q[x] = GUINT32_SWAP_LE_BE(p[x]); } /* Swap 8- of bytes. */ static void vips_byteswap_swap8(VipsPel *in, VipsPel *out, int width, VipsImage *im) { guint64 *p = (guint64 *) in; guint64 *q = (guint64 *) out; int sz = (VIPS_IMAGE_SIZEOF_PEL(im) * width) / 8; int x; // must be 8-byte aligned, or behaviour is undefined g_assert(VIPS_ALIGNED(p, 8) && VIPS_ALIGNED(q, 8)); for (x = 0; x < sz; x++) q[x] = GUINT64_SWAP_LE_BE(p[x]); } typedef void (*SwapFn)(VipsPel *in, VipsPel *out, int width, VipsImage *im); static SwapFn vips_byteswap_swap_fn[] = { NULL, /* VIPS_FORMAT_UCHAR = 0, */ NULL, /* VIPS_FORMAT_CHAR = 1, */ vips_byteswap_swap2, /* VIPS_FORMAT_USHORT = 2, */ vips_byteswap_swap2, /* VIPS_FORMAT_SHORT = 3, */ vips_byteswap_swap4, /* VIPS_FORMAT_UINT = 4, */ vips_byteswap_swap4, /* VIPS_FORMAT_INT = 5, */ vips_byteswap_swap4, /* VIPS_FORMAT_FLOAT = 6, */ vips_byteswap_swap4, /* VIPS_FORMAT_COMPLEX = 7, */ vips_byteswap_swap8, /* VIPS_FORMAT_DOUBLE = 8, */ vips_byteswap_swap8 /* VIPS_FORMAT_DPCOMPLEX = 9, */ }; static void vips_byteswap_swap_unaligned(VipsPel *in, VipsPel *out, int n, int size) { for (int x = 0; x < n; x++) { for (int i = 0; i < size; i++) out[i] = in[size - i - 1]; in += size; out += size; } } /* Byteswap, turning bands into the x axis. */ static int vips_byteswap_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsImage *im = ir->im; VipsRect *r = &out_region->valid; SwapFn swap_aligned = vips_byteswap_swap_fn[im->BandFmt]; int size = vips_format_sizeof(im->BandFmt); int y; g_assert(swap_aligned); if (vips_region_prepare(ir, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); if (VIPS_ALIGNED(p, size) && VIPS_ALIGNED(q, size)) swap_aligned(p, q, r->width, im); else /* Ouch!! horribly slow. * * This can be necessary for formats like PFM, where the data * offset in the file can have any alignment. */ vips_byteswap_swap_unaligned(p, q, r->width * im->Bands, size); } return 0; } static int vips_byteswap_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsByteswap *byteswap = (VipsByteswap *) object; if (VIPS_OBJECT_CLASS(vips_byteswap_parent_class)->build(object)) return -1; /* Lots of images don't need swapping. */ if (byteswap->in->Coding != VIPS_CODING_NONE || !vips_byteswap_swap_fn[byteswap->in->BandFmt]) return vips_image_write(byteswap->in, conversion->out); if (vips_image_pio_input(byteswap->in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, byteswap->in, NULL)) return -1; if (vips_image_generate(conversion->out, vips_start_one, vips_byteswap_gen, vips_stop_one, byteswap->in, byteswap)) return -1; return 0; } static void vips_byteswap_class_init(VipsByteswapClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_byteswap_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "byteswap"; vobject_class->description = _("byteswap an image"); vobject_class->build = vips_byteswap_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsByteswap, in)); } static void vips_byteswap_init(VipsByteswap *byteswap) { } /** * vips_byteswap: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Swap the byte order in an image. * * ::: seealso * [ctor@Image.rawload]. * * Returns: 0 on success, -1 on error. */ int vips_byteswap(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("byteswap", ap, in, out); va_end(ap); return result; } /* Convenience function: swap if @swap is `TRUE`, otherwise copy. */ int vips__byteswap_bool(VipsImage *in, VipsImage **out, gboolean swap) { if (swap) return vips_byteswap(in, out, NULL); else return vips_copy(in, out, NULL); } libvips-8.18.2/libvips/conversion/cache.c000066400000000000000000000115511516303661500203370ustar00rootroot00000000000000/* vips_sink_screen() as an operation. * * 13/1/12 * - from tilecache.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a cache of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsCache { VipsConversion parent_instance; VipsImage *in; int tile_width; int tile_height; int max_tiles; } VipsCache; typedef VipsConversionClass VipsCacheClass; G_DEFINE_TYPE(VipsCache, vips_cache, VIPS_TYPE_CONVERSION); static int vips_cache_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsCache *cache = (VipsCache *) object; VIPS_DEBUG_MSG("vips_cache_build\n"); if (VIPS_OBJECT_CLASS(vips_cache_parent_class)->build(object)) return -1; if (vips_sink_screen(cache->in, conversion->out, NULL, cache->tile_width, cache->tile_height, cache->max_tiles, 0, NULL, NULL)) return -1; return 0; } static void vips_cache_class_init(VipsCacheClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_cache_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "cache"; vobject_class->description = _("cache an image"); vobject_class->build = vips_cache_build; /* sinkscreen swallows errors (you don't want to see them when you display * images), making this operation worse than useless for batch processing. * Just use tilecache() instead. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCache, in)); VIPS_ARG_INT(class, "tile_width", 3, _("Tile width"), _("Tile width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCache, tile_width), 1, 1000000, 128); VIPS_ARG_INT(class, "tile_height", 3, _("Tile height"), _("Tile height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCache, tile_height), 1, 1000000, 128); VIPS_ARG_INT(class, "max_tiles", 3, _("Max tiles"), _("Maximum number of tiles to cache"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCache, max_tiles), -1, 1000000, 250); } static void vips_cache_init(VipsCache *cache) { /* By default, enough pixels for two 1920 x 1080 displays. */ cache->tile_width = 128; cache->tile_height = 128; cache->max_tiles = 250; } /** * vips_cache: * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation behaves rather like [method@Image.copy] between images * @in and @out, except that it keeps a cache of computed pixels. * This cache is made of up to @max_tiles tiles (a value of -1 * means any number of tiles), and each tile is of size @tile_width * by @tile_height pixels. By default it will cache 250 128 x 128 pixel tiles, * enough for two 1920 x 1080 images. * * This operation is a thin wrapper over [method@Image.sink_screen], see the * documentation for that operation for details. * * It uses a set of background threads to calculate pixels and the various * active cache operations coordinate so as not to overwhelm your system. When * a request is made for an area of pixels, the operation will block until all * of those pixels have been calculated. Pixels are calculated with a set of * threads. * * ::: tip "Optional arguments" * * @tile_width: width of tiles in cache * * @tile_height: height of tiles in cache * * @max_tiles: maximum number of tiles to cache * * ::: seealso * [method@Image.tilecache]. * * Returns: 0 on success, -1 on error. */ int vips_cache(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("cache", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/cast.c000066400000000000000000000457201516303661500202330ustar00rootroot00000000000000/* cast an image to a numerical format * * Author: Nicos Dessipris * Written on: 07/03/1991 * Modified on: * 04/05/1992 JC * - works for char, uchar too * - floating point code removed from integer clip operations * - uses nint() instead of own rounding code * - calculated the number of >255 clips for float/double input * incorrectly * - rejects complex input correctly now * 27/4/93 JC * - adapted to work with partial images * - nint() removed, now just +0.5 * - im_warning code removed * 30/6/93 JC * - adapted for partial v2 * 31/8/93 JC * - now detects and prints over/underflows * 27/10/93 JC * - unsigned integer clips now faster! * - falls back to im_copy() correctly * 5/5/94 JC * - switched to rint() * 18/8/94 JC * - now uses evalend callback * 9/5/95 JC * - now does complex too * 11/7/95 JC * - now uses IM_RINT() macro * 10/3/01 JC * - slightly faster and simpler * - generalised to im_clip2fmt(), all other clippers now just call * this * 21/4/04 JC * - now does floor(), not rint() ... you'll need to round yourself * before calling this if you want round-to-nearest * 7/11/07 * - use new evalstart/evalend system * 26/8/08 * - oops, complex->complex conversion was broken * 27/1/10 * - modernised * - gtk-doc * 27/10/11 * - redone as a class * 10/4/12 * - cast to uint now removes <0 values * 11/2/15 * - add @shift option * 1/3/16 * - better behaviour for shift of non-int types (thanks apacheark) * 14/11/18 * - revise for better uint/int clipping [erdmann] * - remove old overflow/underflow detect * 8/12/20 * - fix range clip in int32 -> unsigned casts [ewelot] */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsCast { VipsConversion parent_instance; VipsImage *in; VipsBandFormat format; gboolean shift; } VipsCast; typedef VipsConversionClass VipsCastClass; G_DEFINE_TYPE(VipsCast, vips_cast, VIPS_TYPE_CONVERSION); /* Cast down from an int. */ #define CAST_UCHAR(X) VIPS_CLIP(0, (X), UCHAR_MAX) #define CAST_CHAR(X) VIPS_CLIP(SCHAR_MIN, (X), SCHAR_MAX) #define CAST_USHORT(X) VIPS_CLIP(0, (X), USHRT_MAX) #define CAST_SHORT(X) VIPS_CLIP(SHRT_MIN, (X), SHRT_MAX) /* These cast down from gint64 to uint32 or int32. */ #define CAST_UINT(X) VIPS_CLIP(0, (X), UINT_MAX) #define CAST_INT(X) VIPS_CLIP(INT_MIN, (X), INT_MAX) /* Rightshift an integer type, ie. sizeof(ITYPE) >= sizeof(OTYPE). * * If we're casting between two formats of the same size (eg. ushort to * short), sizes can be equal. */ #define SHIFT_RIGHT(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ int n = ((int) sizeof(ITYPE) << 3) - ((int) sizeof(OTYPE) << 3); \ \ g_assert(sizeof(ITYPE) >= sizeof(OTYPE)); \ \ for (x = 0; x < sz; x++) \ q[x] = p[x] >> n; \ } /* Leftshift an integer type, ie. sizeof(ITYPE) <= sizeof(OTYPE). We need to * copy the bottom bit up into the fresh new bits. */ #define SHIFT_LEFT(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ int n = ((int) sizeof(OTYPE) << 3) - ((int) sizeof(ITYPE) << 3); \ \ g_assert(sizeof(ITYPE) <= sizeof(OTYPE)); \ \ for (x = 0; x < sz; x++) \ q[x] = (p[x] << n) | (((p[x] & 1) << n) - (p[x] & 1)); \ } #define SHIFT_LEFT_SIGNED(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ int n = ((int) sizeof(OTYPE) << 3) - ((int) sizeof(ITYPE) << 3); \ \ g_assert(sizeof(ITYPE) <= sizeof(OTYPE)); \ \ for (x = 0; x < sz; x++) \ q[x] = VIPS_LSHIFT_INT(p[x], n) | \ (((p[x] & 1) << n) - (p[x] & 1)); \ } /* Cast int types to an int type. We need to pass in the type of the * intermediate value, either int or int64, or we'll have problems with uint * sources turning -ve. */ #define CAST_INT_INT(ITYPE, OTYPE, TEMP, CAST) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) { \ TEMP t = (TEMP) p[x]; \ \ q[x] = CAST(t); \ } \ } /* Int to int handling. */ #define INT_INT(ITYPE, OTYPE, TEMP, CAST) \ { \ if (cast->shift && \ sizeof(ITYPE) > sizeof(OTYPE)) { \ SHIFT_RIGHT(ITYPE, OTYPE); \ } \ else if (cast->shift) { \ SHIFT_LEFT(ITYPE, OTYPE); \ } \ else { \ CAST_INT_INT(ITYPE, OTYPE, TEMP, CAST); \ } \ } /* Int to int handling for signed int types. */ #define INT_INT_SIGNED(ITYPE, OTYPE, TEMP, CAST) \ { \ if (cast->shift && \ sizeof(ITYPE) > sizeof(OTYPE)) { \ SHIFT_RIGHT(ITYPE, OTYPE); \ } \ else if (cast->shift) { \ SHIFT_LEFT_SIGNED(ITYPE, OTYPE); \ } \ else { \ CAST_INT_INT(ITYPE, OTYPE, TEMP, CAST); \ } \ } /* Cast float types to an int type. * * We need to do the range clip as double or we'll get errors for int max, * since that can't be represented as a 32-bit float. */ #define CAST_FLOAT_INT(ITYPE, OTYPE, TEMP, CAST) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = CAST((double) p[x]); \ } /* Cast complex types to an int type. Just take the real part. * * We need to do the range clip as double or we'll get errors for int max, * since that can't be represented as a 32-bit float. */ #define CAST_COMPLEX_INT(ITYPE, OTYPE, TEMP, CAST) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) { \ q[x] = CAST((double) p[0]); \ p += 2; \ } \ } /* Cast non-complex types to a float type. */ #define CAST_REAL_FLOAT(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = p[x]; \ } /* Cast complex types to a float type ... just take real. */ #define CAST_COMPLEX_FLOAT(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) { \ q[x] = p[0]; \ p += 2; \ } \ } /* Cast any non-complex to a complex type ... set imaginary to zero. */ #define CAST_REAL_COMPLEX(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) { \ q[0] = p[x]; \ q[1] = 0.0; \ q += 2; \ } \ } /* Cast any complex to a complex type. */ #define CAST_COMPLEX_COMPLEX(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) in; \ OTYPE *restrict q = (OTYPE *) out; \ \ for (x = 0; x < sz; x++) { \ q[0] = p[0]; \ q[1] = p[1]; \ p += 2; \ q += 2; \ } \ } #define BAND_SWITCH_INNER(ITYPE, INT, FLOAT, COMPLEX) \ { \ switch (conversion->out->BandFmt) { \ case VIPS_FORMAT_UCHAR: \ INT(ITYPE, unsigned char, int, CAST_UCHAR); \ break; \ \ case VIPS_FORMAT_CHAR: \ INT(ITYPE, signed char, int, CAST_CHAR); \ break; \ \ case VIPS_FORMAT_USHORT: \ INT(ITYPE, unsigned short, int, CAST_USHORT); \ break; \ \ case VIPS_FORMAT_SHORT: \ INT(ITYPE, signed short, int, CAST_SHORT); \ break; \ \ case VIPS_FORMAT_UINT: \ INT(ITYPE, unsigned int, gint64, CAST_UINT); \ break; \ \ case VIPS_FORMAT_INT: \ INT(ITYPE, signed int, gint64, CAST_INT); \ break; \ \ case VIPS_FORMAT_FLOAT: \ FLOAT(ITYPE, float); \ break; \ \ case VIPS_FORMAT_DOUBLE: \ FLOAT(ITYPE, double); \ break; \ \ case VIPS_FORMAT_COMPLEX: \ COMPLEX(ITYPE, float); \ break; \ \ case VIPS_FORMAT_DPCOMPLEX: \ COMPLEX(ITYPE, double); \ break; \ \ default: \ g_assert_not_reached(); \ } \ } static int vips_cast_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) vseq; VipsCast *cast = (VipsCast *) b; VipsConversion *conversion = (VipsConversion *) b; VipsRect *r = &out_region->valid; int sz = VIPS_REGION_N_ELEMENTS(out_region); int x, y; if (vips_region_prepare(ir, r)) return -1; VIPS_GATE_START("vips_cast_gen: work"); for (y = 0; y < r->height; y++) { VipsPel *in = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *out = VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (ir->im->BandFmt) { case VIPS_FORMAT_UCHAR: BAND_SWITCH_INNER(unsigned char, INT_INT, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_CHAR: BAND_SWITCH_INNER(signed char, INT_INT_SIGNED, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_USHORT: BAND_SWITCH_INNER(unsigned short, INT_INT, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_SHORT: BAND_SWITCH_INNER(signed short, INT_INT_SIGNED, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_UINT: BAND_SWITCH_INNER(unsigned int, INT_INT, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_INT: BAND_SWITCH_INNER(signed int, INT_INT_SIGNED, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_FLOAT: BAND_SWITCH_INNER(float, CAST_FLOAT_INT, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_DOUBLE: BAND_SWITCH_INNER(double, CAST_FLOAT_INT, CAST_REAL_FLOAT, CAST_REAL_COMPLEX); break; case VIPS_FORMAT_COMPLEX: BAND_SWITCH_INNER(float, CAST_COMPLEX_INT, CAST_COMPLEX_FLOAT, CAST_COMPLEX_COMPLEX); break; case VIPS_FORMAT_DPCOMPLEX: BAND_SWITCH_INNER(double, CAST_COMPLEX_INT, CAST_COMPLEX_FLOAT, CAST_COMPLEX_COMPLEX); break; default: g_assert_not_reached(); } } VIPS_GATE_STOP("vips_cast_gen: work"); return 0; } static int vips_cast_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsCast *cast = (VipsCast *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_cast_parent_class)->build(object)) return -1; in = cast->in; /* Trivial case: fall back to copy(). */ if (in->BandFmt == cast->format) return vips_image_write(in, conversion->out); if (vips_image_decode(in, &t[0])) return -1; in = t[0]; /* If @shift is on but we're not in an int format and we're going to * an int format, we need to cast to int first. For example, what * about a float image tagged as rgb16 being cast to uint8? We need * to cast to ushort before we do the final cast to uint8. */ if (cast->shift && !vips_band_format_isint(in->BandFmt) && vips_band_format_isint(cast->format)) { if (vips_cast(in, &t[1], vips_image_guess_format(in), NULL)) return -1; in = t[1]; } if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; conversion->out->BandFmt = cast->format; if (vips_image_generate(conversion->out, vips_start_one, vips_cast_gen, vips_stop_one, in, cast)) return -1; return 0; } static void vips_cast_class_init(VipsCastClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_cast_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "cast"; vobject_class->description = _("cast an image"); vobject_class->build = vips_cast_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCast, in)); VIPS_ARG_ENUM(class, "format", 6, _("Format"), _("Format to cast to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCast, format), VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR); VIPS_ARG_BOOL(class, "shift", 7, _("Shift"), _("Shift integer values up and down"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCast, shift), FALSE); } static void vips_cast_init(VipsCast *cast) { } static int vips_castv(VipsImage *in, VipsImage **out, VipsBandFormat format, va_list ap) { return vips_call_split("cast", ap, in, out, format); } /** * vips_cast: (method) * @in: input image * @out: (out): output image * @format: format to convert to * @...: `NULL`-terminated list of optional named arguments * * Convert @in to @format. You can convert between any pair of formats. * Floats are truncated (not rounded). Out of range values are clipped. * * Casting from complex to real returns the real part. * * If @shift is `TRUE`, integer values are shifted up and down. For example, * casting from unsigned 8 bit to unsigned 16 bit would * shift every value left by 8 bits. The bottom bit is copied into the new * bits, so 255 would become 65535. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * ::: seealso * [method@Image.scale], [method@Image.complexform], [method@Image.real], * [method@Image.imag], [method@Image.cast_uchar], [method@Image.msb]. * * Returns: 0 on success, -1 on error */ int vips_cast(VipsImage *in, VipsImage **out, VipsBandFormat format, ...) { va_list ap; int result; va_start(ap, format); result = vips_castv(in, out, format, ap); va_end(ap); return result; } /** * vips_cast_uchar: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.UCHAR]. See [method@Image.cast]. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * Returns: 0 on success, -1 on error */ int vips_cast_uchar(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_UCHAR, ap); va_end(ap); return result; } /** * vips_cast_char: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.CHAR]. See [method@Image.cast]. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * Returns: 0 on success, -1 on error */ int vips_cast_char(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_CHAR, ap); va_end(ap); return result; } /** * vips_cast_ushort: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.USHORT]. See [method@Image.cast]. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * Returns: 0 on success, -1 on error */ int vips_cast_ushort(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_USHORT, ap); va_end(ap); return result; } /** * vips_cast_short: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.SHORT]. See [method@Image.cast]. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * Returns: 0 on success, -1 on error */ int vips_cast_short(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_SHORT, ap); va_end(ap); return result; } /** * vips_cast_uint: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.UINT]. See [method@Image.cast]. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * Returns: 0 on success, -1 on error */ int vips_cast_uint(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_UINT, ap); va_end(ap); return result; } /** * vips_cast_int: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.INT]. See [method@Image.cast]. * * ::: tip "Optional arguments" * * @shift: `gboolean`, integer values are shifted * * Returns: 0 on success, -1 on error */ int vips_cast_int(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_INT, ap); va_end(ap); return result; } /** * vips_cast_float: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.FLOAT]. See [method@Image.cast]. * * Returns: 0 on success, -1 on error */ int vips_cast_float(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_FLOAT, ap); va_end(ap); return result; } /** * vips_cast_double: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.DOUBLE]. See [method@Image.cast]. * * Returns: 0 on success, -1 on error */ int vips_cast_double(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_DOUBLE, ap); va_end(ap); return result; } /** * vips_cast_complex: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.COMPLEX]. See [method@Image.cast]. * * Returns: 0 on success, -1 on error */ int vips_cast_complex(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_COMPLEX, ap); va_end(ap); return result; } /** * vips_cast_dpcomplex: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert @in to [enum@Vips.BandFormat.DPCOMPLEX]. See [method@Image.cast]. * * Returns: 0 on success, -1 on error */ int vips_cast_dpcomplex(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_castv(in, out, VIPS_FORMAT_DPCOMPLEX, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/composite.cpp000066400000000000000000001164211516303661500216400ustar00rootroot00000000000000/* composite an array of images with PDF operators * * 25/9/17 * - from bandjoin.c * 30/11/17 * - add composite2 class, to make a nice CLI interface * 30/1/18 * - remove number of images limit * - allow one mode ... reused for all joins * 11/8/18 [medakk] * - x/y params let you position images * 27/11/18 * - don't stop on first non-transparent image [felixbuenemann, GDmac] * 6/12/18 * - do our own subimage positioning * 8/5/19 * - revise in/out/dest-in/dest-out to make smoother alpha */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #if defined(HAVE__ALIGNED_MALLOC) || defined(HAVE_MEMALIGN) #include #endif #include #include #include #include "pconversion.h" /* Maximum number of image bands. */ #define MAX_BANDS (64) /* Uncomment to disable the vector path ... handy for debugging. #undef HAVE_VECTOR_ARITH */ /* We have a vector path with gcc's vector attr. */ #ifdef HAVE_VECTOR_ARITH /* A vector of four floats. */ typedef float v4f __attribute__((vector_size(4 * sizeof(float)), aligned(16))); #endif /*HAVE_VECTOR_ARITH*/ typedef struct _VipsCompositeBase { VipsConversion parent_instance; /* The input images. */ VipsArrayImage *in; /* For N input images, 1 blend mode or N - 1 blend modes. */ VipsArrayInt *mode; /* Compositing space. This defaults to RGB, or B_W if we only have * G and GA inputs. */ VipsInterpretation compositing_space; /* Set if the input images have already been premultiplied. */ gboolean premultiplied; /* The x and y positions for each image in the stack. There are n - 1 * of these, since image 0 is always positioned at (0, 0). Set by * subclasses. Can be NULL. */ int *x_offset; int *y_offset; /* A rect for the position of each input image. For each output region, * we composite the set of input images which intersect that area. */ VipsRect *subimages; /* The number of non-alpha bands we are blending. */ int bands; /* The maximum value for each band, set from the image interpretation. * This is used to scale each band to 0 - 1. */ double max_band[MAX_BANDS + 1]; /* TRUE if all our modes are skippable, ie. we can avoid compositing * the whole stack for every pixel request. */ gboolean skippable; } VipsCompositeBase; typedef VipsConversionClass VipsCompositeBaseClass; /* We need C linkage for this. */ extern "C" { G_DEFINE_ABSTRACT_TYPE(VipsCompositeBase, vips_composite_base, VIPS_TYPE_CONVERSION); } static void vips_composite_base_dispose(GObject *gobject) { VipsCompositeBase *composite = (VipsCompositeBase *) gobject; if (composite->in) { vips_area_unref((VipsArea *) composite->in); composite->in = nullptr; } if (composite->mode) { vips_area_unref((VipsArea *) composite->mode); composite->mode = nullptr; } VIPS_FREE(composite->subimages); G_OBJECT_CLASS(vips_composite_base_parent_class)->dispose(gobject); } /* Our sequence value. */ typedef struct { #ifdef HAVE_VECTOR_ARITH /* max_band as a vector, for the RGBA case. This must be * defined first to ensure that the member is aligned * on a 16-byte boundary. */ v4f max_band_vec; #endif /*HAVE_VECTOR_ARITH*/ VipsCompositeBase *composite; /* Full set of input regions, each made on the corresponding input * image. */ VipsRegion **input_regions; /* We then vips_region_prepare_to() to one of this set of regions, * each defined on the base image. */ VipsRegion **composite_regions; /* Number of input regions which intersect this request rect. */ int n; /* For each of @n above (inputs which intersect this request), the * index of the input image we need. We can use this index to get the * position, input region and composite region. */ int *enabled; /* For each enabled image, an input pointer. */ VipsPel **p; } VipsCompositeSequence; #ifdef HAVE_VECTOR_ARITH /* Allocate aligned memory. The return value can be released * by calling the vips_free_aligned() function, for example: * VIPS_FREEF(vips_free_aligned, ptr); */ static inline void * vips_alloc_aligned(size_t sz, size_t align) { g_assert(!(align & (align - 1))); #ifdef HAVE__ALIGNED_MALLOC return _aligned_malloc(sz, align); #elif defined(HAVE_POSIX_MEMALIGN) void *ptr; if (posix_memalign(&ptr, align, sz)) return nullptr; return ptr; #elif defined(HAVE_MEMALIGN) return memalign(align, sz); #else #error Missing aligned alloc implementation #endif } static inline void vips_free_aligned(void *ptr) { #ifdef HAVE__ALIGNED_MALLOC _aligned_free(ptr); #else /*defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN)*/ free(ptr); #endif } #endif /*HAVE_VECTOR_ARITH*/ static int vips_composite_stop(void *vseq, void *a, void *b) { VipsCompositeSequence *seq = (VipsCompositeSequence *) vseq; if (seq->input_regions) { for (int i = 0; seq->input_regions[i]; i++) VIPS_UNREF(seq->input_regions[i]); VIPS_FREE(seq->input_regions); } if (seq->composite_regions) { for (int i = 0; seq->composite_regions[i]; i++) VIPS_UNREF(seq->composite_regions[i]); VIPS_FREE(seq->composite_regions); } VIPS_FREE(seq->enabled); VIPS_FREE(seq->p); #ifdef HAVE_VECTOR_ARITH VIPS_FREEF(vips_free_aligned, seq); #else /*!defined(HAVE_VECTOR_ARITH)*/ VIPS_FREE(seq); #endif /*HAVE_VECTOR_ARITH*/ return 0; } static void * vips_composite_start(VipsImage *out, void *a, void *b) { VipsImage **in = (VipsImage **) a; VipsCompositeBase *composite = (VipsCompositeBase *) b; VipsCompositeSequence *seq; int i, n; #ifdef HAVE_VECTOR_ARITH /* Ensure that the memory is aligned on a 16-byte boundary. */ if (!(seq = ((VipsCompositeSequence *) vips_alloc_aligned( sizeof(VipsCompositeSequence), 16)))) #else /*!defined(HAVE_VECTOR_ARITH)*/ if (!(seq = VIPS_NEW(NULL, VipsCompositeSequence))) #endif /*HAVE_VECTOR_ARITH*/ return nullptr; seq->composite = composite; seq->input_regions = nullptr; seq->enabled = nullptr; seq->p = nullptr; /* How many images? */ for (n = 0; in[n]; n++) ; /* Allocate space for region array. */ if (!(seq->input_regions = VIPS_ARRAY(NULL, n + 1, VipsRegion *))) { vips_composite_stop(seq, nullptr, nullptr); return nullptr; } for (i = 0; i < n + 1; i++) seq->input_regions[i] = nullptr; if (!(seq->composite_regions = VIPS_ARRAY(NULL, n + 1, VipsRegion *))) { vips_composite_stop(seq, nullptr, nullptr); return nullptr; } for (i = 0; i < n + 1; i++) seq->composite_regions[i] = nullptr; seq->enabled = VIPS_ARRAY(NULL, n, int); seq->p = VIPS_ARRAY(NULL, n, VipsPel *); if (!seq->enabled || !seq->p) { vips_composite_stop(seq, nullptr, nullptr); return nullptr; } /* Create a set of regions. */ for (i = 0; i < n; i++) { seq->input_regions[i] = vips_region_new(in[i]); seq->composite_regions[i] = vips_region_new(in[0]); if (!seq->input_regions[i] || !seq->composite_regions[i]) { vips_composite_stop(seq, nullptr, nullptr); return nullptr; } } #ifdef HAVE_VECTOR_ARITH /* We need a float version for the vector path. */ if (composite->bands == 3) seq->max_band_vec = (v4f){ (float) composite->max_band[0], (float) composite->max_band[1], (float) composite->max_band[2], (float) composite->max_band[3] }; #endif return seq; } /* For each of the supported interpretations, the maximum value of each band. */ static int vips_composite_base_max_band(VipsCompositeBase *composite, double *max_band) { double max_alpha; int b; max_alpha = vips_interpretation_max_alpha(composite->compositing_space); for (b = 0; b <= composite->bands; b++) max_band[b] = max_alpha; switch (composite->compositing_space) { case VIPS_INTERPRETATION_XYZ: max_band[0] = VIPS_D65_X0; max_band[1] = VIPS_D65_Y0; max_band[2] = VIPS_D65_Z0; break; case VIPS_INTERPRETATION_LAB: max_band[0] = 100; max_band[1] = 128; max_band[2] = 128; break; case VIPS_INTERPRETATION_LCH: max_band[0] = 100; max_band[1] = 128; max_band[2] = 360; break; case VIPS_INTERPRETATION_CMC: max_band[0] = 100; max_band[1] = 128; max_band[2] = 360; break; case VIPS_INTERPRETATION_scRGB: max_band[0] = 1; max_band[1] = 1; max_band[2] = 1; break; case VIPS_INTERPRETATION_sRGB: max_band[0] = 255; max_band[1] = 255; max_band[2] = 255; break; case VIPS_INTERPRETATION_HSV: max_band[0] = 255; max_band[1] = 255; max_band[2] = 255; break; case VIPS_INTERPRETATION_CMYK: max_band[0] = 255; max_band[1] = 255; max_band[2] = 255; max_band[3] = 255; break; case VIPS_INTERPRETATION_RGB16: max_band[0] = 65535; max_band[1] = 65535; max_band[2] = 65535; break; case VIPS_INTERPRETATION_GREY16: max_band[0] = 65535; break; case VIPS_INTERPRETATION_YXY: max_band[0] = 100; max_band[1] = 1; max_band[2] = 1; break; case VIPS_INTERPRETATION_B_W: max_band[0] = 255; break; default: return -1; } return 0; } /* Find the subset of our input images which intersect this region. If we are * not in skippable mode, we must enable all layers. */ static void vips_composite_base_select(VipsCompositeSequence *seq, VipsRect *r) { VipsCompositeBase *composite = seq->composite; int n = composite->in->area.n; seq->n = 0; for (int i = 0; i < n; i++) if (!composite->skippable || vips_rect_overlapsrect(r, &composite->subimages[i])) { seq->enabled[seq->n] = i; seq->n += 1; } } /* Cairo naming conventions: * * aR alpha of result * aA alpha of source A (the new pixel) * aB alpha of source B (the thing we accumulate) * xR colour band of result * xA colour band of source A * xB colour band of source B */ /* A is the new pixel coming in, of any non-complex type T. * * We must scale incoming pixels to 0 - 1 by dividing by the scale[] vector. * * If premultipled is not set, we premultiply incoming pixels before blending. * * B is the double pixel we are accumulating. */ template static void vips_composite_base_blend(VipsCompositeBase *composite, VipsBlendMode mode, double *restrict B, T *restrict p) { const int bands = composite->bands; double A[MAX_BANDS + 1]; double aA; double aB; double aR; double t1; double t2; double t3; double f[MAX_BANDS + 1]; /* Load and scale the pixel to 0 - 1. */ for (int b = 0; b <= bands; b++) A[b] = p[b] / composite->max_band[b]; /* Not necessary, but it stops a compiler warning. */ for (int b = bands + 1; b < MAX_BANDS + 1; b++) A[b] = 0.0; aA = A[bands]; aB = B[bands]; /* We may need to premultiply A. */ if (!composite->premultiplied) for (int b = 0; b < bands; b++) A[b] *= aA; switch (mode) { case VIPS_BLEND_MODE_CLEAR: aR = 0; for (int b = 0; b < bands; b++) B[b] = 0; break; case VIPS_BLEND_MODE_SOURCE: aR = aA; for (int b = 0; b < bands; b++) B[b] = A[b]; break; case VIPS_BLEND_MODE_OVER: aR = aA + aB * (1 - aA); t1 = 1 - aA; for (int b = 0; b < bands; b++) B[b] = A[b] + t1 * B[b]; break; case VIPS_BLEND_MODE_IN: aR = aA * aB; // if aA == 0, then aR == 0 and so B will already be 0 if (aA != 0) for (int b = 0; b < bands; b++) B[b] = A[b] * aR / aA; break; case VIPS_BLEND_MODE_OUT: aR = aA * (1 - aB); // if aA == 0, then aR == 0 and so B will already be 0 if (aA != 0) for (int b = 0; b < bands; b++) B[b] = A[b] * aR / aA; break; case VIPS_BLEND_MODE_ATOP: aR = aB; t1 = 1 - aA; for (int b = 0; b < bands; b++) B[b] = A[b] + t1 * B[b]; break; case VIPS_BLEND_MODE_DEST: aR = aB; // B = B break; case VIPS_BLEND_MODE_DEST_OVER: aR = aB + aA * (1 - aB); t1 = 1 - aB; for (int b = 0; b < bands; b++) B[b] = B[b] + t1 * A[b]; break; case VIPS_BLEND_MODE_DEST_IN: aR = aA * aB; // B = B if (aB != 0) for (int b = 0; b < bands; b++) B[b] *= aR / aB; break; case VIPS_BLEND_MODE_DEST_OUT: aR = (1 - aA) * aB; // B = B // if aB is 0, then B is already 0 if (aB != 0) for (int b = 0; b < bands; b++) B[b] *= aR / aB; break; case VIPS_BLEND_MODE_DEST_ATOP: aR = aA; t1 = 1 - aB; for (int b = 0; b < bands; b++) B[b] = t1 * A[b] + B[b]; break; case VIPS_BLEND_MODE_XOR: aR = aA + aB - 2 * aA * aB; t1 = 1 - aB; t2 = 1 - aA; for (int b = 0; b < bands; b++) B[b] = t1 * A[b] + t2 * B[b]; break; case VIPS_BLEND_MODE_ADD: aR = VIPS_MIN(1, aA + aB); for (int b = 0; b < bands; b++) B[b] = A[b] + B[b]; break; case VIPS_BLEND_MODE_SATURATE: aR = VIPS_MIN(1, aA + aB); t1 = VIPS_MIN(aA, 1 - aB); for (int b = 0; b < bands; b++) B[b] = t1 * A[b] + B[b]; break; default: /* The PDF modes are a bit different. */ aR = aA + aB * (1 - aA); switch (mode) { case VIPS_BLEND_MODE_MULTIPLY: for (int b = 0; b < bands; b++) f[b] = A[b] * B[b]; break; case VIPS_BLEND_MODE_SCREEN: for (int b = 0; b < bands; b++) f[b] = A[b] + B[b] - A[b] * B[b]; break; case VIPS_BLEND_MODE_OVERLAY: for (int b = 0; b < bands; b++) if (B[b] <= 0.5) f[b] = 2 * A[b] * B[b]; else f[b] = 1 - 2 * (1 - A[b]) * (1 - B[b]); break; case VIPS_BLEND_MODE_DARKEN: for (int b = 0; b < bands; b++) f[b] = VIPS_MIN(A[b], B[b]); break; case VIPS_BLEND_MODE_LIGHTEN: for (int b = 0; b < bands; b++) f[b] = VIPS_MAX(A[b], B[b]); break; case VIPS_BLEND_MODE_COLOUR_DODGE: for (int b = 0; b < bands; b++) if (A[b] < 1) f[b] = VIPS_MIN(1, B[b] / (1 - A[b])); else f[b] = 1; break; case VIPS_BLEND_MODE_COLOUR_BURN: for (int b = 0; b < bands; b++) if (A[b] > 0) f[b] = 1 - VIPS_MIN(1, (1 - B[b]) / A[b]); else f[b] = 0; break; case VIPS_BLEND_MODE_HARD_LIGHT: for (int b = 0; b < bands; b++) if (A[b] <= 0.5) f[b] = 2 * A[b] * B[b]; else f[b] = 1 - 2 * (1 - A[b]) * (1 - B[b]); break; case VIPS_BLEND_MODE_SOFT_LIGHT: for (int b = 0; b < bands; b++) { double g; if (B[b] <= 0.25) g = ((16 * B[b] - 12) * B[b] + 4) * B[b]; else g = sqrt(B[b]); if (A[b] <= 0.5) f[b] = B[b] - (1 - 2 * A[b]) * B[b] * (1 - B[b]); else f[b] = B[b] + (2 * A[b] - 1) * (g - B[b]); } break; case VIPS_BLEND_MODE_DIFFERENCE: for (int b = 0; b < bands; b++) f[b] = fabs(B[b] - A[b]); break; case VIPS_BLEND_MODE_EXCLUSION: for (int b = 0; b < bands; b++) f[b] = A[b] + B[b] - 2 * A[b] * B[b]; break; default: g_assert_not_reached(); for (int b = 0; b < bands; b++) B[b] = 0; } t1 = 1 - aB; t2 = 1 - aA; t3 = aA * aB; for (int b = 0; b < bands; b++) B[b] = t1 * A[b] + t2 * B[b] + t3 * f[b]; break; } B[bands] = aR; } /* We have a vector path with gcc's vector attr. */ #ifdef HAVE_VECTOR_ARITH /* Special path for RGBA with non-double output. This is overwhelmingly the * most common case, and vectorises easily. * * B is the float pixel we are accumulating, A is the new pixel coming * in from memory. */ template static void vips_composite_base_blend3(VipsCompositeSequence *seq, VipsBlendMode mode, v4f &B, T *restrict p) { VipsCompositeBase *composite = seq->composite; v4f A; float aA; float aB; float aR; float t1; float t2; float t3; v4f f; v4f g; /* Load and scale the pixel to 0 - 1. */ A[0] = p[0]; A[1] = p[1]; A[2] = p[2]; A[3] = p[3]; A /= seq->max_band_vec; aA = A[3]; aB = B[3]; /* We may need to premultiply A. */ if (!composite->premultiplied) A *= aA; /* See https://www.cairographics.org/operators for a nice summary of * the operators and their meaning. * * Some operators need the unpremultiplied values (eg. dest-in), so * we have to do an extra unpremultiply/premultiply. */ switch (mode) { case VIPS_BLEND_MODE_CLEAR: aR = 0; B[0] = 0; B[1] = 0; B[2] = 0; break; case VIPS_BLEND_MODE_SOURCE: aR = aA; B = A; break; case VIPS_BLEND_MODE_OVER: aR = aA + aB * (1 - aA); t1 = 1 - aA; B = A + t1 * B; break; case VIPS_BLEND_MODE_IN: aR = aA * aB; // if aA == 0, then aR == 0 and so B will already be 0 if (aA != 0) B = A * aR / aA; break; case VIPS_BLEND_MODE_OUT: aR = aA * (1 - aB); // if aA == 0, then aR == 0 and so B will already be 0 if (aA != 0) B = A * aR / aA; break; case VIPS_BLEND_MODE_ATOP: aR = aB; t1 = 1 - aA; B = A + t1 * B; break; case VIPS_BLEND_MODE_DEST: aR = aB; // B = B break; case VIPS_BLEND_MODE_DEST_OVER: aR = aB + aA * (1 - aB); t1 = 1 - aB; B = B + t1 * A; break; case VIPS_BLEND_MODE_DEST_IN: aR = aA * aB; // if aB is 0, then B is already 0 if (aB != 0) B *= aR / aB; break; case VIPS_BLEND_MODE_DEST_OUT: aR = (1 - aA) * aB; // B = B // if aB is 0, then B is already 0 if (aB != 0) B *= aR / aB; break; case VIPS_BLEND_MODE_DEST_ATOP: aR = aA; t1 = 1 - aB; B = t1 * A + B; break; case VIPS_BLEND_MODE_XOR: aR = aA + aB - 2 * aA * aB; t1 = 1 - aB; t2 = 1 - aA; B = t1 * A + t2 * B; break; case VIPS_BLEND_MODE_ADD: aR = VIPS_MIN(1, aA + aB); B = A + B; break; case VIPS_BLEND_MODE_SATURATE: aR = VIPS_MIN(1, aA + aB); t1 = VIPS_MIN(aA, 1 - aB); B = t1 * A + B; break; default: /* The PDF modes are a bit different. */ aR = aA + aB * (1 - aA); switch (mode) { case VIPS_BLEND_MODE_MULTIPLY: f = A * B; break; case VIPS_BLEND_MODE_SCREEN: f = A + B - A * B; break; case VIPS_BLEND_MODE_OVERLAY: f = B <= 0.5f ? 2 * A * B : 1 - 2 * (1 - A) * (1 - B); break; case VIPS_BLEND_MODE_DARKEN: f = VIPS_MIN(A, B); break; case VIPS_BLEND_MODE_LIGHTEN: f = VIPS_MAX(A, B); break; case VIPS_BLEND_MODE_COLOUR_DODGE: f = A < 1 ? VIPS_MIN(1, B / (1 - A)) : 1; break; case VIPS_BLEND_MODE_COLOUR_BURN: f = A > 0 ? 1 - VIPS_MIN(1, (1 - B) / A) : 0; break; case VIPS_BLEND_MODE_HARD_LIGHT: f = A <= 0.5f ? 2 * A * B : 1 - 2 * (1 - A) * (1 - B); break; case VIPS_BLEND_MODE_SOFT_LIGHT: /* You can't sqrt a vector, so we must loop. */ for (int b = 0; b < 3; b++) { float g; if (B[b] <= 0.25) g = ((16 * B[b] - 12) * B[b] + 4) * B[b]; else g = sqrt(B[b]); if (A[b] <= 0.5) f[b] = B[b] - (1 - 2 * A[b]) * B[b] * (1 - B[b]); else f[b] = B[b] + (2 * A[b] - 1) * (g - B[b]); } break; case VIPS_BLEND_MODE_DIFFERENCE: g = B - A; f = g > 0 ? g : -1 * g; break; case VIPS_BLEND_MODE_EXCLUSION: f = A + B - 2 * A * B; break; default: g_assert_not_reached(); /* Stop compiler warnings. */ for (int b = 0; b < 3; b++) B[b] = 0; f = A; } t1 = 1 - aB; t2 = 1 - aA; t3 = aA * aB; B = t1 * A + t2 * B + t3 * f; break; } B[3] = aR; } #endif /*HAVE_VECTOR_ARITH*/ /* min_T and max_T are the numeric range for this type. 0, 0 means no limit, * for example float. */ template static void vips_combine_pixels(VipsCompositeSequence *seq, VipsPel *q) { VipsCompositeBase *composite = seq->composite; VipsBlendMode *mode = (VipsBlendMode *) composite->mode->area.data; int n_mode = composite->mode->area.n; int n = seq->n; int bands = composite->bands; T *restrict tq = (T *restrict) q; T **restrict tp = (T * *restrict) seq->p; double B[MAX_BANDS + 1] = { 0.0 }; double aB; /* Load and scale the base pixel to 0 - 1. */ for (int b = 0; b <= bands; b++) B[b] = tp[0][b] / composite->max_band[b]; aB = B[bands]; if (!composite->premultiplied) for (int b = 0; b < bands; b++) B[b] *= aB; for (int i = 1; i < n; i++) { int j = seq->enabled[i]; VipsBlendMode m = n_mode == 1 ? mode[0] : mode[j - 1]; vips_composite_base_blend(composite, m, B, tp[i]); } /* Unpremultiply, if necessary. */ if (!composite->premultiplied) { double aR = B[bands]; if (aR == 0) for (int b = 0; b < bands; b++) B[b] = 0; else for (int b = 0; b < bands; b++) B[b] = B[b] / aR; } /* Write back as a full range pixel, clipping to range. */ for (int b = 0; b <= bands; b++) { double v; v = B[b] * composite->max_band[b]; if (min_T != 0 || max_T != 0) { v = VIPS_CLIP(min_T, v, max_T); } tq[b] = v; } } #ifdef HAVE_VECTOR_ARITH /* Three band (four with alpha) vector case. Non-double output. min_T and * max_T are the numeric range for this type. 0, 0 means no limit, * for example float. */ template static void vips_combine_pixels3(VipsCompositeSequence *seq, VipsPel *q) { VipsCompositeBase *composite = seq->composite; VipsBlendMode *mode = (VipsBlendMode *) composite->mode->area.data; int n_mode = composite->mode->area.n; int n = seq->n; T *restrict tq = (T *restrict) q; T **restrict tp = (T * *restrict) seq->p; v4f B; float aB; B[0] = tp[0][0]; B[1] = tp[0][1]; B[2] = tp[0][2]; B[3] = tp[0][3]; /* Scale the base pixel to 0 - 1. */ B /= seq->max_band_vec; aB = B[3]; if (!composite->premultiplied) { B *= aB; B[3] = aB; } for (int i = 1; i < n; i++) { int j = seq->enabled[i]; VipsBlendMode m = n_mode == 1 ? mode[0] : mode[j - 1]; vips_composite_base_blend3(seq, m, B, tp[i]); } /* Unpremultiply, if necessary. */ if (!composite->premultiplied) { float aR = B[3]; if (aR == 0) for (int b = 0; b < 3; b++) B[b] = 0; else { B /= aR; B[3] = aR; } } /* Write back as a full range pixel, clipping to range. */ B *= seq->max_band_vec; if (min_T != 0 || max_T != 0) { float low = min_T; float high = max_T; B = VIPS_CLIP(low, B, high); } tq[0] = B[0]; tq[1] = B[1]; tq[2] = B[2]; tq[3] = B[3]; } #endif /*HAVE_VECTOR_ARITH*/ static int vips_composite_base_gen(VipsRegion *output_region, void *vseq, void *a, void *b, gboolean *stop) { VipsCompositeSequence *seq = (VipsCompositeSequence *) vseq; VipsCompositeBase *composite = (VipsCompositeBase *) b; VipsRect *r = &output_region->valid; int ps = VIPS_IMAGE_SIZEOF_PEL(output_region->im); VIPS_DEBUG_MSG("vips_composite_base_gen: at %d x %d, size %d x %d\n", r->left, r->top, r->width, r->height); /* Find the subset of our input images which intersect this region. */ vips_composite_base_select(seq, r); VIPS_DEBUG_MSG(" selected %d images\n", seq->n); /* Is there just one? We can prepare directly to output and return. */ if (seq->n == 1) { /* This can only be the background image, since it's the only * image which exactly fills the whole output. */ g_assert(seq->enabled[0] == 0); if (vips_region_prepare(seq->input_regions[0], r)) return -1; if (vips_region_region(output_region, seq->input_regions[0], r, r->left, r->top)) return -1; return 0; } /* Prepare the appropriate parts into our set of composite * regions. */ for (int i = 0; i < seq->n; i++) { int j = seq->enabled[i]; VipsRect hit; VipsRect request; /* Set the composite region up to be a bit of memory at the * right position. */ if (vips_region_buffer(seq->composite_regions[j], r)) return -1; /* Clip against this subimage position and size. */ hit = *r; vips_rect_intersectrect(&hit, &composite->subimages[j], &hit); /* Translate request to subimage coordinates. */ request = hit; request.left -= composite->subimages[j].left; request.top -= composite->subimages[j].top; /* If the request is smaller than the target region, there * will be some gaps. We must make sure these are zero. */ if (request.width < r->width || request.height < r->height) vips_region_black(seq->composite_regions[j]); /* And render the right part of the input image to the * composite region. * * If we are not in skippable mode, we can be completely * outside the subimage area. */ if (!vips_rect_isempty(&request)) { VIPS_DEBUG_MSG(" fetching pixels for input %d\n", j); if (vips_region_prepare_to(seq->input_regions[j], seq->composite_regions[j], &request, hit.left, hit.top)) return -1; } } VIPS_GATE_START("vips_composite_base_gen: work"); for (int y = 0; y < r->height; y++) { VipsPel *q; for (int i = 0; i < seq->n; i++) { int j = seq->enabled[i]; seq->p[i] = VIPS_REGION_ADDR(seq->composite_regions[j], r->left, r->top + y); } q = VIPS_REGION_ADDR(output_region, r->left, r->top + y); for (int x = 0; x < r->width; x++) { switch (seq->input_regions[0]->im->BandFmt) { case VIPS_FORMAT_UCHAR: #ifdef HAVE_VECTOR_ARITH if (composite->bands == 3) vips_combine_pixels3(seq, q); else #endif vips_combine_pixels(seq, q); break; case VIPS_FORMAT_CHAR: vips_combine_pixels(seq, q); break; case VIPS_FORMAT_USHORT: #ifdef HAVE_VECTOR_ARITH if (composite->bands == 3) vips_combine_pixels3(seq, q); else #endif vips_combine_pixels(seq, q); break; case VIPS_FORMAT_SHORT: vips_combine_pixels(seq, q); break; case VIPS_FORMAT_UINT: vips_combine_pixels(seq, q); break; case VIPS_FORMAT_INT: vips_combine_pixels(seq, q); break; case VIPS_FORMAT_FLOAT: #ifdef HAVE_VECTOR_ARITH if (composite->bands == 3) vips_combine_pixels3(seq, q); else #endif vips_combine_pixels(seq, q); break; case VIPS_FORMAT_DOUBLE: vips_combine_pixels(seq, q); break; default: g_assert_not_reached(); return -1; } for (int i = 0; i < seq->n; i++) seq->p[i] += ps; q += ps; } } VIPS_GATE_STOP("vips_composite_base_gen: work"); return 0; } /* Is a mode "skippable"? * * Skippable modes are ones where a black (0, 0, 0, 0) layer placed over the * base image and composited has no effect. * * If all the modes in our stack are skippable, we can avoid compositing the * whole stack for every request. */ static gboolean vips_composite_mode_skippable(VipsBlendMode mode) { switch (mode) { case VIPS_BLEND_MODE_CLEAR: case VIPS_BLEND_MODE_SOURCE: case VIPS_BLEND_MODE_IN: case VIPS_BLEND_MODE_OUT: case VIPS_BLEND_MODE_DEST_IN: case VIPS_BLEND_MODE_DEST_ATOP: return FALSE; default: return TRUE; } } static int vips_composite_base_build(VipsObject *object) { VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsCompositeBase *composite = (VipsCompositeBase *) object; int n; int *mode; VipsImage **in; VipsImage **decode; VipsImage **compositing; VipsImage **format; if (VIPS_OBJECT_CLASS(vips_composite_base_parent_class)->build(object)) return -1; n = composite->in->area.n; if (n <= 0) { vips_error(klass->nickname, "%s", _("no input images")); return -1; } if (composite->mode->area.n != n - 1 && composite->mode->area.n != 1) { vips_error(klass->nickname, _("must be 1 or %d blend modes"), n - 1); return -1; } mode = (int *) composite->mode->area.data; composite->skippable = TRUE; for (int i = 0; i < composite->mode->area.n; i++) { if (mode[i] < 0 || mode[i] >= VIPS_BLEND_MODE_LAST) { vips_error(klass->nickname, _("blend mode index %d (%d) invalid"), i, mode[i]); return -1; } if (!vips_composite_mode_skippable((VipsBlendMode) mode[i])) composite->skippable = FALSE; } in = (VipsImage **) composite->in->area.data; /* Make a set of rects for the positions of the input images. Image 0 * (the background) is always at (0, 0). */ if (!(composite->subimages = VIPS_ARRAY(NULL, n, VipsRect))) return -1; for (int i = 0; i < n; i++) { composite->subimages[i].left = 0; composite->subimages[i].top = 0; composite->subimages[i].width = in[i]->Xsize; composite->subimages[i].height = in[i]->Ysize; } /* Position all images, if x/y is set. Image 0 * (the background) is always at (0, 0). */ if (composite->x_offset && composite->y_offset) for (int i = 1; i < n; i++) { composite->subimages[i].left = composite->x_offset[i - 1]; composite->subimages[i].top = composite->y_offset[i - 1]; } decode = (VipsImage **) vips_object_local_array(object, n); for (int i = 0; i < n; i++) if (vips_image_decode(in[i], &decode[i])) return -1; in = decode; /* Add a solid alpha to any images missing one. */ for (int i = n - 1; i >= 0; i--) if (!vips_image_hasalpha(in[i])) { VipsImage *x; if (vips_addalpha(in[i], &x, nullptr)) return -1; g_object_unref(in[i]); in[i] = x; } /* Transform to compositing space. It defaults to sRGB or B_W, usually * 8 bit, but 16 bit if any inputs are 16 bit. */ if (!vips_object_argument_isset(object, "compositing_space")) { gboolean all_grey; gboolean any_16; all_grey = TRUE; for (int i = 0; i < n; i++) if (in[i]->Bands > 2) { all_grey = FALSE; break; } any_16 = FALSE; for (int i = 0; i < n; i++) if (in[i]->Type == VIPS_INTERPRETATION_GREY16 || in[i]->Type == VIPS_INTERPRETATION_RGB16) { any_16 = TRUE; break; } composite->compositing_space = any_16 // FIXME: Invalidates operation cache ? (all_grey ? VIPS_INTERPRETATION_GREY16 : VIPS_INTERPRETATION_RGB16) : (all_grey ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB); } compositing = (VipsImage **) vips_object_local_array(object, n); for (int i = 0; i < n; i++) if (in[i]->Type == composite->compositing_space) { /* Already the right type ... just copy the image pointer * and add a ref. */ compositing[i] = in[i]; g_object_ref(in[i]); } else { if (vips_colourspace(in[i], &compositing[i], composite->compositing_space, nullptr)) return -1; } in = compositing; /* Check that they all now match in bands. This can fail for some * input combinations. */ for (int i = 1; i < n; i++) if (in[i]->Bands != in[0]->Bands) { vips_error(klass->nickname, "%s", _("images do not have same " "numbers of bands")); return -1; } if (in[0]->Bands > MAX_BANDS) { vips_error(klass->nickname, "%s", _("too many input bands")); return -1; } composite->bands = in[0]->Bands - 1; /* Set the max for each band now we know bands and compositing space. */ if (vips_composite_base_max_band(composite, composite->max_band)) { vips_error(klass->nickname, "%s", _("unsupported compositing space")); return -1; } /* Transform the input images to match in format. We may have * mixed float and double, for example. */ format = (VipsImage **) vips_object_local_array(object, n); if (vips__formatalike_vec(in, format, n)) return -1; in = format; /* We want locality, so that we only prepare a few subimages each * time. */ if (vips_image_pipeline_array(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, in)) return -1; /* The output image is always the size of the base image. */ conversion->out->Xsize = in[0]->Xsize; conversion->out->Ysize = in[0]->Ysize; if (vips_image_generate(conversion->out, vips_composite_start, vips_composite_base_gen, vips_composite_stop, in, composite)) return -1; return 0; } static void vips_composite_base_class_init(VipsCompositeBaseClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(klass); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(klass); VIPS_DEBUG_MSG("vips_composite_base_class_init\n"); gobject_class->dispose = vips_composite_base_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "composite_base"; vobject_class->description = _("blend images together"); vobject_class->build = vips_composite_base_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_ENUM(klass, "compositing_space", 10, _("Compositing space"), _("Composite images in this colour space"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompositeBase, compositing_space), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB); VIPS_ARG_BOOL(klass, "premultiplied", 11, _("Premultiplied"), _("Images have premultiplied alpha"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompositeBase, premultiplied), FALSE); } static void vips_composite_base_init(VipsCompositeBase *composite) { composite->compositing_space = VIPS_INTERPRETATION_sRGB; } typedef struct _VipsComposite { VipsCompositeBase parent_instance; /* For N input images, N - 1 x coordinates. */ VipsArrayInt *x; /* For N input images, N - 1 y coordinates. */ VipsArrayInt *y; } VipsComposite; typedef VipsCompositeBaseClass VipsCompositeClass; /* We need C linkage for this. */ extern "C" { G_DEFINE_TYPE(VipsComposite, vips_composite, vips_composite_base_get_type()); } static int vips_composite_build(VipsObject *object) { VipsObjectClass *klass = VIPS_OBJECT_GET_CLASS(object); VipsCompositeBase *base = (VipsCompositeBase *) object; VipsComposite *composite = (VipsComposite *) object; int n; n = 0; if (vips_object_argument_isset(object, "in")) n = base->in->area.n; if (vips_object_argument_isset(object, "x")) { if (composite->x->area.n != n - 1) { vips_error(klass->nickname, _("must be %d x coordinates"), n - 1); return -1; } base->x_offset = (int *) composite->x->area.data; } if (vips_object_argument_isset(object, "y")) { if (composite->y->area.n != n - 1) { vips_error(klass->nickname, _("must be %d y coordinates"), n - 1); return -1; } base->y_offset = (int *) composite->y->area.data; } if (VIPS_OBJECT_CLASS(vips_composite_parent_class)->build(object)) return -1; return 0; } static void vips_composite_class_init(VipsCompositeClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(klass); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(klass); VIPS_DEBUG_MSG("vips_composite_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "composite"; vobject_class->description = _("blend an array of images with an array of blend modes"); vobject_class->build = vips_composite_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_BOXED(klass, "in", 0, _("Inputs"), _("Array of input images"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCompositeBase, in), VIPS_TYPE_ARRAY_IMAGE); VIPS_ARG_BOXED(klass, "mode", 3, _("Blend modes"), _("Array of VipsBlendMode to join with"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCompositeBase, mode), VIPS_TYPE_ARRAY_INT); VIPS_ARG_BOXED(klass, "x", 4, _("x coordinates"), _("Array of x coordinates to join at"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsComposite, x), VIPS_TYPE_ARRAY_INT); VIPS_ARG_BOXED(klass, "y", 5, _("y coordinates"), _("Array of y coordinates to join at"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsComposite, y), VIPS_TYPE_ARRAY_INT); } static void vips_composite_init(VipsComposite *composite) { } static int vips_compositev(VipsImage **in, VipsImage **out, int n, int *mode, va_list ap) { VipsArrayImage *image_array; VipsArrayInt *mode_array; int result; image_array = vips_array_image_new(in, n); mode_array = vips_array_int_new(mode, n - 1); result = vips_call_split("composite", ap, image_array, out, mode_array); vips_area_unref(VIPS_AREA(image_array)); vips_area_unref(VIPS_AREA(mode_array)); return result; } /* See conversion.c for the doc comment. */ int vips_composite(VipsImage **in, VipsImage **out, int n, int *mode, ...) { va_list ap; int result; va_start(ap, mode); result = vips_compositev(in, out, n, mode, ap); va_end(ap); return result; } typedef struct _VipsComposite2 { VipsCompositeBase parent_instance; VipsImage *base; VipsImage *overlay; VipsBlendMode mode; int x; int y; } VipsComposite2; typedef VipsCompositeBaseClass VipsComposite2Class; /* We need C linkage for this. */ extern "C" { G_DEFINE_TYPE(VipsComposite2, vips_composite2, vips_composite_base_get_type()); } static int vips_composite2_build(VipsObject *object) { VipsCompositeBase *base = (VipsCompositeBase *) object; VipsComposite2 *composite2 = (VipsComposite2 *) object; if (composite2->overlay && composite2->base) { VipsImage *in[3]; int mode[1]; in[0] = composite2->base; in[1] = composite2->overlay; in[2] = nullptr; base->in = vips_array_image_new(in, 2); mode[0] = (int) composite2->mode; base->mode = vips_array_int_new(mode, 1); } base->x_offset = &composite2->x; base->y_offset = &composite2->y; if (VIPS_OBJECT_CLASS(vips_composite2_parent_class)->build(object)) return -1; return 0; } static void vips_composite2_class_init(VipsCompositeClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(klass); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(klass); VIPS_DEBUG_MSG("vips_composite_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "composite2"; vobject_class->description = _("blend a pair of images with a blend mode"); vobject_class->build = vips_composite2_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(klass, "base", 0, _("Base"), _("Base image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsComposite2, base)); VIPS_ARG_IMAGE(klass, "overlay", 1, _("Overlay"), _("Overlay image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsComposite2, overlay)); VIPS_ARG_ENUM(klass, "mode", 3, _("Blend mode"), _("VipsBlendMode to join with"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsComposite2, mode), VIPS_TYPE_BLEND_MODE, VIPS_BLEND_MODE_OVER); VIPS_ARG_INT(klass, "x", 4, _("x"), _("x position of overlay"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsComposite2, x), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(klass, "y", 5, _("y"), _("y position of overlay"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsComposite2, y), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); } static void vips_composite2_init(VipsComposite2 *composite2) { } /* See conversion.c for the doc comment. */ int vips_composite2(VipsImage *base, VipsImage *overlay, VipsImage **out, VipsBlendMode mode, ...) { va_list ap; int result; /* Works for gcc and clang. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wvarargs" /* Triggers a clang compiler warning because mode might not be an int. * I think the warning is harmless for all platforms we care about. */ va_start(ap, mode); g_assert(sizeof(mode) == sizeof(int)); #pragma GCC diagnostic pop result = vips_call_split("composite2", ap, base, overlay, out, mode); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/conversion.c000066400000000000000000000350411516303661500214610ustar00rootroot00000000000000/* base class for all conversion operations * * properties: * - single output image */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pconversion.h" /** * vips_composite: * @in: (array length=n) (transfer none): array of input images * @out: (out): output image * @n: number of input images * @mode: array of (@n - 1) [enum@BlendMode] * @...: `NULL`-terminated list of optional named arguments * * Composite an array of images together. * * Images are placed in a stack, with @in[0] at the bottom and @in[@n - 1] at * the top. Pixels are blended together working from the bottom upwards, with * the blend mode at each step being set by the corresponding [enum@BlendMode] * in @mode. * * Images are transformed to a compositing space before processing. This is * [enum@Vips.Interpretation.sRGB], [enum@Vips.Interpretation.B_W], * [enum@Vips.Interpretation.RGB16], or [enum@Vips.Interpretation.GREY16] * by default, depending on * how many bands and bits the input images have. You can select any other * space, such as [enum@Vips.Interpretation.LAB] or * [enum@Vips.Interpretation.scRGB]. * * The output image is in the compositing space. It will always be * [enum@Vips.BandFormat.FLOAT] unless one of the inputs is * [enum@Vips.BandFormat.DOUBLE], in which case the output will be double * as well. * * Complex images are not supported. * * The output image will always have an alpha band. A solid alpha is * added to any input missing an alpha. * * The images do not need to match in size or format. The output image is * always the size of @in[0], with other images being * positioned with the @x and @y parameters and clipped * against that rectangle. * * Image are normally treated as unpremultiplied, so this operation can be used * directly on PNG images. If your images have been through * [method@Image.premultiply], set @premultiplied. * * ::: tip "Optional arguments" * * @compositing_space: [enum@Interpretation] to composite in * * @premultiplied: `gboolean`, images are already premultiplied * * @x: [struct@ArrayInt], array of (@n - 1) x coordinates * * @y: [struct@ArrayInt], array of (@n - 1) y coordinates * * ::: seealso * [method@Image.insert]. * * Returns: 0 on success, -1 on error */ /** * vips_composite2: (method) * @base: first input image * @overlay: second input image * @out: (out): output image * @mode: composite with this blend mode * @...: `NULL`-terminated list of optional named arguments * * Composite @overlay on top of @base with @mode. See [func@Image.composite]. * * ::: tip "Optional arguments" * * @compositing_space: [enum@Interpretation] to composite in * * @premultiplied: `gboolean`, images are already premultiplied * * @x: `gint`, position of overlay * * @y: `gint`, position of overlay * * Returns: 0 on success, -1 on error */ /** * VipsBlendMode: * @VIPS_BLEND_MODE_CLEAR: where the second object is drawn, the first is removed * @VIPS_BLEND_MODE_SOURCE: the second object is drawn as if nothing were below * @VIPS_BLEND_MODE_OVER: the image shows what you would expect if you held two semi-transparent slides on top of each other * @VIPS_BLEND_MODE_IN: the first object is removed completely, the second is only drawn where the first was * @VIPS_BLEND_MODE_OUT: the second is drawn only where the first isn't * @VIPS_BLEND_MODE_ATOP: this leaves the first object mostly intact, but mixes both objects in the overlapping area * @VIPS_BLEND_MODE_DEST: leaves the first object untouched, the second is discarded completely * @VIPS_BLEND_MODE_DEST_OVER: like OVER, but swaps the arguments * @VIPS_BLEND_MODE_DEST_IN: like IN, but swaps the arguments * @VIPS_BLEND_MODE_DEST_OUT: like OUT, but swaps the arguments * @VIPS_BLEND_MODE_DEST_ATOP: like ATOP, but swaps the arguments * @VIPS_BLEND_MODE_XOR: something like a difference operator * @VIPS_BLEND_MODE_ADD: a bit like adding the two images * @VIPS_BLEND_MODE_SATURATE: a bit like the darker of the two * @VIPS_BLEND_MODE_MULTIPLY: at least as dark as the darker of the two inputs * @VIPS_BLEND_MODE_SCREEN: at least as light as the lighter of the inputs * @VIPS_BLEND_MODE_OVERLAY: multiplies or screens colors, depending on the lightness * @VIPS_BLEND_MODE_DARKEN: the darker of each component * @VIPS_BLEND_MODE_LIGHTEN: the lighter of each component * @VIPS_BLEND_MODE_COLOUR_DODGE: brighten first by a factor second * @VIPS_BLEND_MODE_COLOUR_BURN: darken first by a factor of second * @VIPS_BLEND_MODE_HARD_LIGHT: multiply or screen, depending on lightness * @VIPS_BLEND_MODE_SOFT_LIGHT: darken or lighten, depending on lightness * @VIPS_BLEND_MODE_DIFFERENCE: difference of the two * @VIPS_BLEND_MODE_EXCLUSION: somewhat like DIFFERENCE, but lower-contrast * * The various Porter-Duff and PDF blend modes. See [func@Image.composite], * for example. * * The Cairo docs have [a nice explanation of all the blend * modes](https://www.cairographics.org/operators). * * The non-separable modes are not implemented. */ /** * VipsAlign: * @VIPS_ALIGN_LOW: align low coordinate edge * @VIPS_ALIGN_CENTRE: align centre * @VIPS_ALIGN_HIGH: align high coordinate edge * * See [method@Image.join] and so on. * * Operations like [method@Image.join] need to be told whether to align images on the * low or high coordinate edge, or centre. * * ::: seealso * [method@Image.join]. */ /** * VipsAngle: * @VIPS_ANGLE_D0: no rotate * @VIPS_ANGLE_D90: 90 degrees clockwise * @VIPS_ANGLE_D180: 180 degree rotate * @VIPS_ANGLE_D270: 90 degrees anti-clockwise * * See [method@Image.rot] and so on. * * Fixed rotate angles. * * ::: seealso * [method@Image.rot]. */ /** * VipsInteresting: * @VIPS_INTERESTING_NONE: do nothing * @VIPS_INTERESTING_CENTRE: just take the centre * @VIPS_INTERESTING_ENTROPY: use an entropy measure * @VIPS_INTERESTING_ATTENTION: look for features likely to draw human attention * @VIPS_INTERESTING_LOW: position the crop towards the low coordinate * @VIPS_INTERESTING_HIGH: position the crop towards the high coordinate * @VIPS_INTERESTING_ALL: everything is interesting * * Pick the algorithm vips uses to decide image "interestingness". This is used * by [method@Image.smartcrop], for example, to decide what parts of the image to * keep. * * [enum@Vips.Interesting.NONE] and [enum@Vips.Interesting.LOW] mean the same -- the * crop is positioned at the top or left. [enum@Vips.Interesting.HIGH] positions at * the bottom or right. * * ::: seealso * [method@Image.smartcrop]. */ /** * VipsCompassDirection: * @VIPS_COMPASS_DIRECTION_CENTRE: centre * @VIPS_COMPASS_DIRECTION_NORTH: north * @VIPS_COMPASS_DIRECTION_EAST: east * @VIPS_COMPASS_DIRECTION_SOUTH: south * @VIPS_COMPASS_DIRECTION_WEST: west * @VIPS_COMPASS_DIRECTION_NORTH_EAST: north-east * @VIPS_COMPASS_DIRECTION_SOUTH_EAST: south-east * @VIPS_COMPASS_DIRECTION_SOUTH_WEST: south-west * @VIPS_COMPASS_DIRECTION_NORTH_WEST: north-west * * A direction on a compass. Used for [method@Image.gravity], for example. */ /** * VipsAngle45: * @VIPS_ANGLE45_D0: no rotate * @VIPS_ANGLE45_D45: 45 degrees clockwise * @VIPS_ANGLE45_D90: 90 degrees clockwise * @VIPS_ANGLE45_D135: 135 degrees clockwise * @VIPS_ANGLE45_D180: 180 degrees * @VIPS_ANGLE45_D225: 135 degrees anti-clockwise * @VIPS_ANGLE45_D270: 90 degrees anti-clockwise * @VIPS_ANGLE45_D315: 45 degrees anti-clockwise * * See [method@Image.rot45] and so on. * * Fixed rotate angles. * * ::: seealso * [method@Image.rot45]. */ /** * VipsExtend: * @VIPS_EXTEND_BLACK: extend with black (all 0) pixels * @VIPS_EXTEND_COPY: copy the image edges * @VIPS_EXTEND_REPEAT: repeat the whole image * @VIPS_EXTEND_MIRROR: mirror the whole image * @VIPS_EXTEND_WHITE: extend with white (all bits set) pixels * @VIPS_EXTEND_BACKGROUND: extend with colour from the @background property * * See [method@Image.embed], [method@Image.conv], [method@Image.affine] and so on. * * When the edges of an image are extended, you can specify * how you want the extension done. * * [enum@Vips.Extend.BLACK] -- new pixels are black, ie. all bits are zero. * * [enum@Vips.Extend.COPY] -- each new pixel takes the value of the nearest edge * pixel * * [enum@Vips.Extend.REPEAT] -- the image is tiled to fill the new area * * [enum@Vips.Extend.MIRROR] -- the image is reflected and tiled to reduce hash * edges * * [enum@Vips.Extend.WHITE] -- new pixels are white, ie. all bits are set * * [enum@Vips.Extend.BACKGROUND] -- colour set from the @background property * * We have to specify the exact value of each enum member since we have to * keep these frozen for back compat with vips7. * * ::: seealso * [method@Image.embed]. */ /** * VipsDirection: * @VIPS_DIRECTION_HORIZONTAL: left-right * @VIPS_DIRECTION_VERTICAL: top-bottom * * See [method@Image.flip], [method@Image.join] and so on. * * Operations like [method@Image.flip] need to be told whether to flip left-right or * top-bottom. * * ::: seealso * [method@Image.flip], [method@Image.join]. */ G_DEFINE_ABSTRACT_TYPE(VipsConversion, vips_conversion, VIPS_TYPE_OPERATION); static int vips_conversion_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); #ifdef DEBUG printf("vips_conversion_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_object_set(conversion, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_conversion_parent_class)->build(object)) return -1; return 0; } static void vips_conversion_class_init(VipsConversionClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "conversion"; vobject_class->description = _("conversion operations"); vobject_class->build = vips_conversion_build; VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsConversion, out)); } static void vips_conversion_init(VipsConversion *conversion) { } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_conversion_operation_init(void) { extern GType vips_copy_get_type(void); extern GType vips_tile_cache_get_type(void); extern GType vips_line_cache_get_type(void); extern GType vips_sequential_get_type(void); extern GType vips_cache_get_type(void); extern GType vips_embed_get_type(void); extern GType vips_gravity_get_type(void); extern GType vips_flip_get_type(void); extern GType vips_insert_get_type(void); extern GType vips_join_get_type(void); extern GType vips_arrayjoin_get_type(void); extern GType vips_extract_area_get_type(void); extern GType vips_crop_get_type(void); extern GType vips_smartcrop_get_type(void); extern GType vips_extract_band_get_type(void); extern GType vips_replicate_get_type(void); extern GType vips_cast_get_type(void); extern GType vips_bandjoin_get_type(void); extern GType vips_bandjoin_const_get_type(void); extern GType vips_bandrank_get_type(void); extern GType vips_black_get_type(void); extern GType vips_rot_get_type(void); extern GType vips_rot45_get_type(void); extern GType vips_autorot_get_type(void); extern GType vips_ifthenelse_get_type(void); extern GType vips_switch_get_type(void); extern GType vips_recomb_get_type(void); extern GType vips_bandmean_get_type(void); extern GType vips_bandfold_get_type(void); extern GType vips_bandunfold_get_type(void); extern GType vips_flatten_get_type(void); extern GType vips_premultiply_get_type(void); extern GType vips_unpremultiply_get_type(void); extern GType vips_bandbool_get_type(void); extern GType vips_gaussnoise_get_type(void); extern GType vips_grid_get_type(void); extern GType vips_transpose3d_get_type(void); extern GType vips_scale_get_type(void); extern GType vips_wrap_get_type(void); extern GType vips_zoom_get_type(void); extern GType vips_subsample_get_type(void); extern GType vips_msb_get_type(void); extern GType vips_byteswap_get_type(void); extern GType vips_xyz_get_type(void); extern GType vips_falsecolour_get_type(void); extern GType vips_gamma_get_type(void); extern GType vips_composite_get_type(void); extern GType vips_composite2_get_type(void); extern GType vips_addalpha_get_type(void); vips_copy_get_type(); vips_tile_cache_get_type(); vips_line_cache_get_type(); vips_sequential_get_type(); vips_cache_get_type(); vips_embed_get_type(); vips_gravity_get_type(); vips_flip_get_type(); vips_insert_get_type(); vips_join_get_type(); vips_arrayjoin_get_type(); vips_extract_area_get_type(); vips_crop_get_type(); vips_smartcrop_get_type(); vips_extract_band_get_type(); vips_replicate_get_type(); vips_cast_get_type(); vips_bandjoin_get_type(); vips_bandjoin_const_get_type(); vips_bandrank_get_type(); vips_black_get_type(); vips_rot_get_type(); vips_rot45_get_type(); vips_autorot_get_type(); vips_ifthenelse_get_type(); vips_switch_get_type(); vips_recomb_get_type(); vips_bandmean_get_type(); vips_bandfold_get_type(); vips_bandunfold_get_type(); vips_flatten_get_type(); vips_premultiply_get_type(); vips_unpremultiply_get_type(); vips_bandbool_get_type(); vips_gaussnoise_get_type(); vips_grid_get_type(); vips_transpose3d_get_type(); vips_scale_get_type(); vips_wrap_get_type(); vips_zoom_get_type(); vips_subsample_get_type(); vips_msb_get_type(); vips_byteswap_get_type(); vips_xyz_get_type(); vips_falsecolour_get_type(); vips_gamma_get_type(); vips_composite_get_type(); vips_composite2_get_type(); vips_addalpha_get_type(); } libvips-8.18.2/libvips/conversion/copy.c000066400000000000000000000253411516303661500202500ustar00rootroot00000000000000/* Copy an image. * * Copyright: 1990, N. Dessipris, based on im_powtra() * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 23/4/93 J.Cupitt * - adapted to work with partial images * 30/6/93 JC * - adapted for partial v2 * - and ANSI C * 7/7/93 JC * - now does IM_CODING_LABQ too * 22/2/95 JC * - new use of im_region_region() * 25/6/02 JC * - added im_copy_set() * - hint is IM_ANY * 5/9/02 JC * - added xoff/yoff to copy_set * 14/4/04 JC * - im_copy() now zeros Xoffset/Yoffset (since origin is the same as * input) * 26/5/04 JC * - added im_copy_swap() * 1/6/05 * - added im_copy_morph() * 13/6/05 * - oop, im_copy_set() was messed up * 29/9/06 * - added im_copy_set_meta(), handy wrapper for nip2 to set meta fields * 2/11/06 * - moved im__convert_saveable() here so it's always defined (was part * of JPEG write code) * 15/2/08 * - added im__saveable_t ... so we can have CMYK JPEG write * 24/3/09 * - added IM_CODING_RAD support * 28/1/10 * - gtk-doc * - cleanups * - removed im_copy_from() and associated stuff * - added im_copy_native() * 28/11/10 * - im_copy_set() now sets xoff / yoff again hmmm * 29/9/11 * - rewrite as a class * 1/12/11 * - use glib byteswap macros * 15/5/15 * - support bands -> width conversion * 4/6/15 * - support width -> bands conversion * 5/6/15 * - move byteswap out to vips_byteswap() * - move band folding out to vips_bandfold()/vips_unfold() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsCopy { VipsConversion parent_instance; /* The input image. */ VipsImage *in; /* Fields we can optionally set on the way through. */ gboolean swap; VipsInterpretation interpretation; double xres; double yres; int xoffset; int yoffset; int bands; VipsBandFormat format; VipsCoding coding; int width; int height; } VipsCopy; typedef VipsConversionClass VipsCopyClass; G_DEFINE_TYPE(VipsCopy, vips_copy, VIPS_TYPE_CONVERSION); static int vips_copy_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; if (vips_region_prepare(ir, r) || vips_region_region(out_region, ir, r, r->left, r->top)) return -1; return 0; } /* The props we copy, if set, from the operation to the image. */ static const char *vips_copy_names[] = { "interpretation", "xres", "yres", "xoffset", "yoffset", "bands", "format", "coding", "width", "height" }; static int vips_copy_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsCopy *copy = (VipsCopy *) object; guint64 pel_size_before; guint64 pel_size_after; VipsImage copy_of_fields; int i; if (VIPS_OBJECT_CLASS(vips_copy_parent_class)->build(object)) return -1; if (vips_image_pio_input(copy->in)) return -1; if (copy->swap) g_warning("copy swap is deprecated, use byteswap instead"); if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, copy->in, NULL)) return -1; /* Take a copy of all the basic header fields. We use this for * sanity-checking the changes our caller has made. */ copy_of_fields = *conversion->out; /* Use props to adjust header fields. */ for (i = 0; i < VIPS_NUMBER(vips_copy_names); i++) { const char *name = vips_copy_names[i]; GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return -1; if (argument_instance->assigned) { GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); GValue value = G_VALUE_INIT; g_value_init(&value, type); g_object_get_property(G_OBJECT(object), name, &value); #ifdef VIPS_DEBUG { char *str; str = g_strdup_value_contents(&value); printf("vips_copy_build: %s = %s\n", name, str); g_free(str); } #endif /* VIPS_DEBUG */ g_object_set_property(G_OBJECT(conversion->out), name, &value); g_value_unset(&value); } } /* Disallow changes which alter sizeof(pel). */ pel_size_before = VIPS_IMAGE_SIZEOF_PEL(©_of_fields); pel_size_after = VIPS_IMAGE_SIZEOF_PEL(conversion->out); if (pel_size_after != pel_size_before) { vips_error(class->nickname, "%s", _("must not change pel size")); return -1; } if (vips_image_generate(conversion->out, vips_start_one, vips_copy_gen, vips_stop_one, copy->in, copy)) return -1; return 0; } static void vips_copy_class_init(VipsCopyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_copy_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "copy"; vobject_class->description = _("copy an image"); vobject_class->build = vips_copy_build; /* We use copy to make fresh vipsimages to stop sharing, so don't * cache it. Plus copy is cheap. */ operation_class->flags = VIPS_OPERATION_SEQUENTIAL | VIPS_OPERATION_NOCACHE; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCopy, in)); VIPS_ARG_BOOL(class, "swap", 2, _("Swap"), _("Swap bytes in image between little and big-endian"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsCopy, swap), FALSE); VIPS_ARG_INT(class, "width", 3, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, width), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "height", 4, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, height), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "bands", 5, _("Bands"), _("Number of bands in image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, bands), 0, VIPS_MAX_COORD, 0); VIPS_ARG_ENUM(class, "format", 6, _("Format"), _("Pixel format in image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, format), VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR); VIPS_ARG_ENUM(class, "coding", 7, _("Coding"), _("Pixel coding"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, coding), VIPS_TYPE_CODING, VIPS_CODING_NONE); VIPS_ARG_ENUM(class, "interpretation", 8, _("Interpretation"), _("Pixel interpretation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, interpretation), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND); VIPS_ARG_DOUBLE(class, "xres", 9, _("Xres"), _("Horizontal resolution in pixels/mm"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, xres), -0.0, 1000000, 0); VIPS_ARG_DOUBLE(class, "yres", 10, _("Yres"), _("Vertical resolution in pixels/mm"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, yres), -0.0, 1000000, 0); VIPS_ARG_INT(class, "xoffset", 11, _("Xoffset"), _("Horizontal offset of origin"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, xoffset), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "yoffset", 12, _("Yoffset"), _("Vertical offset of origin"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCopy, yoffset), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); } static void vips_copy_init(VipsCopy *copy) { /* Init our instance fields. */ } /** * vips_copy: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Copy an image, optionally modifying the header. VIPS copies images by * copying pointers, so this operation is instant, even for very large images. * * You can optionally change any or all header fields during the copy. You can * make any change which does not change the size of a pel, so for example * you can turn a 4-band uchar image into a 2-band ushort image, but you * cannot change a 100 x 100 RGB image into a 300 x 100 mono image. * * ::: tip "Optional arguments" * * @width: `gint`, set image width * * @height: `gint`, set image height * * @bands: `gint`, set image bands * * @format: [enum@BandFormat], set image format * * @coding: [enum@Coding], set image coding * * @interpretation: [enum@Interpretation], set image interpretation * * @xres: `gdouble`, set image xres * * @yres: `gdouble`, set image yres * * @xoffset: `gint`, set image xoffset * * @yoffset: `gint`, set image yoffset * * ::: seealso * [method@Image.byteswap], [method@Image.bandfold], * [method@Image.bandunfold]. * * Returns: 0 on success, -1 on error. */ int vips_copy(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("copy", ap, in, out); va_end(ap); return result; } /** * vips_copy_file: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * A simple convenience function to copy an image to a file, then copy * again to output. If the image is already a file, just copy straight * through. * * The file is allocated with [ctor@Image.new_temp_file]. * The file is automatically deleted when @out is closed. * * ::: seealso * [method@Image.copy], [ctor@Image.new_temp_file]. * * Returns: 0 on success, -1 on error */ int vips_copy_file(VipsImage *in, VipsImage **out, ...) { VipsImage *file; if (vips_image_isfile(in)) return vips_copy(in, out, NULL); if (!(file = vips_image_new_temp_file("%s.v"))) return -1; if (vips_image_write(in, file) || vips_image_pio_input(file)) { g_object_unref(file); return -1; } *out = file; return 0; } libvips-8.18.2/libvips/conversion/embed.c000066400000000000000000000523261516303661500203550ustar00rootroot00000000000000/* VipsEmbed * * Author: J. Cupitt * Written on: 21/2/95 * Modified on: * 6/4/04 * - added extend pixels from edge mode * - sets Xoffset / Yoffset to x / y * 15/4/04 * - added replicate and mirror modes * 4/3/05 * - added solid white mode * 4/1/07 * - degenerate to im_copy() for 0/0/w/h * 1/8/07 * - more general ... x and y can be negative * 24/3/09 * - added IM_CODING_RAD support * 5/11/09 * - gtkdoc * 27/1/10 * - use im_region_paint() * - cleanups * 15/10/11 * - rewrite as a class * 10/10/12 * - add @background * 19/9/17 * - break into embed and gravity */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsEmbedBase { VipsConversion parent_instance; /* The input image. */ VipsImage *in; VipsExtend extend; VipsArrayDouble *background; int width; int height; /* Pixel we paint calculated from background. */ VipsPel *ink; /* Geometry calculations. */ VipsRect rout; /* Whole output area */ VipsRect rsub; /* Rect occupied by image */ /* The 8 border pieces. The 4 borders strictly up/down/left/right of * the main image, and the 4 corner pieces. */ VipsRect border[8]; /* Passed to us by subclasses. */ int x; int y; } VipsEmbedBase; typedef VipsConversionClass VipsEmbedBaseClass; G_DEFINE_ABSTRACT_TYPE(VipsEmbedBase, vips_embed_base, VIPS_TYPE_CONVERSION); /* r is the bit we are trying to paint, guaranteed to be entirely within * border area i. Set out to be the edge of the image we need to paint the * pixels in r. */ static void vips_embed_base_find_edge(VipsEmbedBase *base, VipsRect *r, int i, VipsRect *out) { /* Expand the border by 1 pixel, intersect with the image area, and we * get the edge. Usually too much though: eg. we could make the entire * right edge. */ *out = base->border[i]; vips_rect_marginadjust(out, 1); vips_rect_intersectrect(out, &base->rsub, out); /* Usually too much though: eg. we could make the entire * right edge. If we're strictly up/down/left/right of the image, we * can trim. */ if (i == 0 || i == 2) { VipsRect extend; /* Above or below. */ extend = *r; extend.top = 0; extend.height = base->height; vips_rect_intersectrect(out, &extend, out); } if (i == 1 || i == 3) { VipsRect extend; /* Left or right. */ extend = *r; extend.left = 0; extend.width = base->width; vips_rect_intersectrect(out, &extend, out); } } /* Copy a single pixel sideways into a line of pixels. */ static void vips_embed_base_copy_pixel(VipsEmbedBase *base, VipsPel *q, VipsPel *p, int n) { const int bs = VIPS_IMAGE_SIZEOF_PEL(base->in); int x, b; for (x = 0; x < n; x++) for (b = 0; b < bs; b++) *q++ = p[b]; } /* Paint r of region or. It's a border area, lying entirely within * base->border[i]. p points to the top-left source pixel to fill with. * plsk is the line stride. */ static void vips_embed_base_paint_edge(VipsEmbedBase *base, VipsRegion *out_region, int i, VipsRect *r, VipsPel *p, int plsk) { const int bs = VIPS_IMAGE_SIZEOF_PEL(base->in); VipsRect todo; VipsPel *q; int y; VIPS_GATE_START("vips_embed_base_paint_edge: work"); /* Pixels left to paint. */ todo = *r; /* Corner pieces ... copy the single pixel to paint the top line of * todo, then use the line copier below to paint the rest of it. */ if (i > 3) { q = VIPS_REGION_ADDR(out_region, todo.left, todo.top); vips_embed_base_copy_pixel(base, q, p, todo.width); p = q; todo.top += 1; todo.height -= 1; } if (i == 1 || i == 3) { /* Vertical line of pixels to copy. */ for (y = 0; y < todo.height; y++) { q = VIPS_REGION_ADDR(out_region, todo.left, todo.top + y); vips_embed_base_copy_pixel(base, q, p, todo.width); p += plsk; } } else { /* Horizontal line of pixels to copy. */ for (y = 0; y < todo.height; y++) { q = VIPS_REGION_ADDR(out_region, todo.left, todo.top + y); memcpy(q, p, (size_t) bs * todo.width); } } VIPS_GATE_STOP("vips_embed_base_paint_edge: work"); } static int vips_embed_base_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsEmbedBase *base = (VipsEmbedBase *) b; VipsRect *r = &out_region->valid; VipsRect ovl; int i; VipsPel *p; int plsk; int ink; /* Entirely within the input image? Generate the subimage and copy * pointers. */ if (vips_rect_includesrect(&base->rsub, r)) { VipsRect need; need = *r; need.left -= base->x; need.top -= base->y; if (vips_region_prepare(ir, &need) || vips_region_region(out_region, ir, r, need.left, need.top)) return -1; return 0; } /* Does any of the input image appear in the area we have been asked * to make? Paste it in. */ vips_rect_intersectrect(r, &base->rsub, &ovl); if (!vips_rect_isempty(&ovl)) { /* Paint the bits coming from the input image. */ ovl.left -= base->x; ovl.top -= base->y; if (vips_region_prepare_to(ir, out_region, &ovl, ovl.left + base->x, ovl.top + base->y)) return -1; ovl.left += base->x; ovl.top += base->y; } switch (base->extend) { case VIPS_EXTEND_BLACK: case VIPS_EXTEND_WHITE: VIPS_GATE_START("vips_embed_base_gen: work1"); ink = base->extend == VIPS_EXTEND_BLACK ? 0 : (int) vips_interpretation_max_alpha(base->in->Type); /* Paint the borders a solid value. */ for (i = 0; i < 8; i++) vips_region_paint(out_region, &base->border[i], ink); VIPS_GATE_STOP("vips_embed_base_gen: work1"); break; case VIPS_EXTEND_BACKGROUND: VIPS_GATE_START("vips_embed_base_gen: work2"); /* Paint the borders a solid value. */ for (i = 0; i < 8; i++) vips_region_paint_pel(out_region, &base->border[i], base->ink); VIPS_GATE_STOP("vips_embed_base_gen: work2"); break; case VIPS_EXTEND_COPY: /* Extend the borders. */ for (i = 0; i < 8; i++) { VipsRect todo; VipsRect edge; vips_rect_intersectrect(r, &base->border[i], &todo); if (!vips_rect_isempty(&todo)) { vips_embed_base_find_edge(base, &todo, i, &edge); /* Did we paint any of the input image? If we * did, we can fetch the edge pixels from * that. */ if (!vips_rect_isempty(&ovl)) { p = VIPS_REGION_ADDR(out_region, edge.left, edge.top); plsk = VIPS_REGION_LSKIP(out_region); } else { /* No pixels painted ... fetch * directly from the input image. */ edge.left -= base->x; edge.top -= base->y; if (vips_region_prepare(ir, &edge)) return -1; p = VIPS_REGION_ADDR(ir, edge.left, edge.top); plsk = VIPS_REGION_LSKIP(ir); } vips_embed_base_paint_edge(base, out_region, i, &todo, p, plsk); } } break; default: g_assert_not_reached(); } return 0; } static int vips_embed_base_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsEmbedBase *base = (VipsEmbedBase *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); VipsRect want; if (VIPS_OBJECT_CLASS(vips_embed_base_parent_class)->build(object)) return -1; /* nip2 can generate this quite often ... just copy. */ if (base->x == 0 && base->y == 0 && base->width == base->in->Xsize && base->height == base->in->Ysize) return vips_image_write(base->in, conversion->out); if (!vips_object_argument_isset(object, "extend") && vips_object_argument_isset(object, "background")) base->extend = VIPS_EXTEND_BACKGROUND; // FIXME: Invalidates operation cache if (base->extend == VIPS_EXTEND_BACKGROUND) if (!(base->ink = vips__vector_to_ink( class->nickname, base->in, VIPS_AREA(base->background)->data, NULL, VIPS_AREA(base->background)->n))) return -1; switch (base->extend) { case VIPS_EXTEND_REPEAT: { /* Clock arithmetic: we want negative x/y to wrap around * nicely. */ const int nx = base->x < 0 ? -base->x % base->in->Xsize : base->in->Xsize - base->x % base->in->Xsize; const int ny = base->y < 0 ? -base->y % base->in->Ysize : base->in->Ysize - base->y % base->in->Ysize; if (vips_replicate(base->in, &t[0], base->width / base->in->Xsize + 2, base->height / base->in->Ysize + 2, NULL) || vips_extract_area(t[0], &t[1], nx, ny, base->width, base->height, NULL) || vips_image_write(t[1], conversion->out)) return -1; } break; case VIPS_EXTEND_MIRROR: { /* As repeat, but the tiles are twice the size because of * mirroring. */ const int w2 = base->in->Xsize * 2; const int h2 = base->in->Ysize * 2; const int nx = base->x < 0 ? -base->x % w2 : w2 - base->x % w2; const int ny = base->y < 0 ? -base->y % h2 : h2 - base->y % h2; if ( /* Make a 2x2 mirror tile. */ vips_flip(base->in, &t[0], VIPS_DIRECTION_HORIZONTAL, NULL) || vips_join(base->in, t[0], &t[1], VIPS_DIRECTION_HORIZONTAL, NULL) || vips_flip(t[1], &t[2], VIPS_DIRECTION_VERTICAL, NULL) || vips_join(t[1], t[2], &t[3], VIPS_DIRECTION_VERTICAL, NULL) || /* Repeat, then cut out the centre. */ vips_replicate(t[3], &t[4], base->width / t[3]->Xsize + 2, base->height / t[3]->Ysize + 2, NULL) || vips_extract_area(t[4], &t[5], nx, ny, base->width, base->height, NULL) || /* Overwrite the centre with the in, much faster * for centre pixels. */ vips_insert(t[5], base->in, &t[6], base->x, base->y, NULL) || vips_image_write(t[6], conversion->out)) return -1; } break; case VIPS_EXTEND_BLACK: case VIPS_EXTEND_WHITE: case VIPS_EXTEND_BACKGROUND: case VIPS_EXTEND_COPY: /* embed is used in many places. We don't really care about * geometry, so use ANY to avoid disturbing all pipelines. */ if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_ANY, base->in, NULL)) return -1; conversion->out->Xsize = base->width; conversion->out->Ysize = base->height; /* Whole output area. */ base->rout.left = 0; base->rout.top = 0; base->rout.width = conversion->out->Xsize; base->rout.height = conversion->out->Ysize; /* Rect occupied by image (can be clipped to nothing). */ want.left = base->x; want.top = base->y; want.width = base->in->Xsize; want.height = base->in->Ysize; vips_rect_intersectrect(&want, &base->rout, &base->rsub); /* FIXME ... actually, it can't. base_find_edge() will fail * if rsub is empty. Make this more general at some point * and remove this test. */ if (vips_rect_isempty(&base->rsub)) { vips_error(class->nickname, "%s", _("bad dimensions")); return -1; } /* Edge rects of new pixels ... top, right, bottom, left. Order * important. Can be empty. */ base->border[0].left = base->rsub.left; base->border[0].top = 0; base->border[0].width = base->rsub.width; base->border[0].height = base->rsub.top; base->border[1].left = VIPS_RECT_RIGHT(&base->rsub); base->border[1].top = base->rsub.top; base->border[1].width = conversion->out->Xsize - VIPS_RECT_RIGHT(&base->rsub); base->border[1].height = base->rsub.height; base->border[2].left = base->rsub.left; base->border[2].top = VIPS_RECT_BOTTOM(&base->rsub); base->border[2].width = base->rsub.width; base->border[2].height = conversion->out->Ysize - VIPS_RECT_BOTTOM(&base->rsub); base->border[3].left = 0; base->border[3].top = base->rsub.top; base->border[3].width = base->rsub.left; base->border[3].height = base->rsub.height; /* Corner rects. Top-left, top-right, bottom-right, * bottom-left. Order important. */ base->border[4].left = 0; base->border[4].top = 0; base->border[4].width = base->rsub.left; base->border[4].height = base->rsub.top; base->border[5].left = VIPS_RECT_RIGHT(&base->rsub); base->border[5].top = 0; base->border[5].width = conversion->out->Xsize - VIPS_RECT_RIGHT(&base->rsub); base->border[5].height = base->rsub.top; base->border[6].left = VIPS_RECT_RIGHT(&base->rsub); base->border[6].top = VIPS_RECT_BOTTOM(&base->rsub); base->border[6].width = conversion->out->Xsize - VIPS_RECT_RIGHT(&base->rsub); base->border[6].height = conversion->out->Ysize - VIPS_RECT_BOTTOM(&base->rsub); base->border[7].left = 0; base->border[7].top = VIPS_RECT_BOTTOM(&base->rsub); base->border[7].width = base->rsub.left; base->border[7].height = conversion->out->Ysize - VIPS_RECT_BOTTOM(&base->rsub); if (vips_image_generate(conversion->out, vips_start_one, vips_embed_base_gen, vips_stop_one, base->in, base)) return -1; break; default: g_assert_not_reached(); } return 0; } static void vips_embed_base_class_init(VipsEmbedBaseClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_embed_base_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "embed_base"; vobject_class->description = _("embed an image in a larger image"); vobject_class->build = vips_embed_base_build; /* Not seq with mirror. */ VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsEmbedBase, in)); VIPS_ARG_INT(class, "width", 5, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsEmbedBase, width), 1, 1000000000, 1); VIPS_ARG_INT(class, "height", 6, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsEmbedBase, height), 1, 1000000000, 1); VIPS_ARG_ENUM(class, "extend", 7, _("Extend"), _("How to generate the extra pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsEmbedBase, extend), VIPS_TYPE_EXTEND, VIPS_EXTEND_BLACK); VIPS_ARG_BOXED(class, "background", 12, _("Background"), _("Color for background pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsEmbedBase, background), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_embed_base_init(VipsEmbedBase *base) { base->extend = VIPS_EXTEND_BLACK; base->background = vips_array_double_newv(1, 0.0); } /* Embed with specified x, y */ typedef struct _VipsEmbed { VipsEmbedBase parent_instance; int x; int y; } VipsEmbed; typedef VipsConversionClass VipsEmbedClass; G_DEFINE_TYPE(VipsEmbed, vips_embed, vips_embed_base_get_type()); static int vips_embed_build(VipsObject *object) { VipsEmbedBase *base = (VipsEmbedBase *) object; VipsEmbed *embed = (VipsEmbed *) object; /* Just pass the specified x, y down. */ base->x = embed->x; base->y = embed->y; if (VIPS_OBJECT_CLASS(vips_embed_parent_class)->build(object)) return -1; return 0; } static void vips_embed_class_init(VipsEmbedClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_embed_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "embed"; vobject_class->description = _("embed an image in a larger image"); vobject_class->build = vips_embed_build; VIPS_ARG_INT(class, "x", 3, _("x"), _("Left edge of input in output"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsEmbed, x), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "y", 4, _("y"), _("Top edge of input in output"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsEmbed, y), -1000000000, 1000000000, 0); } static void vips_embed_init(VipsEmbed *embed) { } /** * vips_embed: (method) * @in: input image * @out: (out): output image * @x: place @in at this x position in @out * @y: place @in at this y position in @out * @width: @out should be this many pixels across * @height: @out should be this many pixels down * @...: `NULL`-terminated list of optional named arguments * * The opposite of [method@Image.extract_area]: embed @in within an image of * size @width by @height at position @x, @y. * * @extend controls what appears in the new pels, see [enum@Extend]. * * ::: tip "Optional arguments" * * @extend: [enum@Extend] to generate the edge pixels * (default: [enum@Vips.Extend.BLACK]) * * @background: [struct@ArrayDouble] colour for edge pixels * * ::: seealso * [method@Image.extract_area], [method@Image.insert]. * * Returns: 0 on success, -1 on error. */ int vips_embed(VipsImage *in, VipsImage **out, int x, int y, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("embed", ap, in, out, x, y, width, height); va_end(ap); return result; } /* Embed with a general direction. */ typedef struct _VipsGravity { VipsEmbedBase parent_instance; VipsCompassDirection direction; } VipsGravity; typedef VipsConversionClass VipsGravityClass; G_DEFINE_TYPE(VipsGravity, vips_gravity, vips_embed_base_get_type()); static int vips_gravity_build(VipsObject *object) { VipsEmbedBase *base = (VipsEmbedBase *) object; VipsGravity *gravity = (VipsGravity *) object; if (vips_object_argument_isset(object, "in") && vips_object_argument_isset(object, "width") && vips_object_argument_isset(object, "height") && vips_object_argument_isset(object, "direction")) { switch (gravity->direction) { case VIPS_COMPASS_DIRECTION_CENTRE: base->x = (base->width - base->in->Xsize) / 2; base->y = (base->height - base->in->Ysize) / 2; break; case VIPS_COMPASS_DIRECTION_NORTH: base->x = (base->width - base->in->Xsize) / 2; base->y = 0; break; case VIPS_COMPASS_DIRECTION_EAST: base->x = base->width - base->in->Xsize; base->y = (base->height - base->in->Ysize) / 2; break; case VIPS_COMPASS_DIRECTION_SOUTH: base->x = (base->width - base->in->Xsize) / 2; base->y = base->height - base->in->Ysize; break; case VIPS_COMPASS_DIRECTION_WEST: base->x = 0; base->y = (base->height - base->in->Ysize) / 2; break; case VIPS_COMPASS_DIRECTION_NORTH_EAST: base->x = base->width - base->in->Xsize; base->y = 0; break; case VIPS_COMPASS_DIRECTION_SOUTH_EAST: base->x = base->width - base->in->Xsize; base->y = base->height - base->in->Ysize; break; case VIPS_COMPASS_DIRECTION_SOUTH_WEST: base->x = 0; base->y = base->height - base->in->Ysize; break; case VIPS_COMPASS_DIRECTION_NORTH_WEST: base->x = 0; base->y = 0; break; default: g_assert_not_reached(); } } if (VIPS_OBJECT_CLASS(vips_gravity_parent_class)->build(object)) return -1; return 0; } static void vips_gravity_class_init(VipsGravityClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_gravity_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "gravity"; vobject_class->description = _("place an image within a larger " "image with a certain gravity"); vobject_class->build = vips_gravity_build; VIPS_ARG_ENUM(class, "direction", 3, _("Direction"), _("Direction to place image within width/height"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGravity, direction), VIPS_TYPE_COMPASS_DIRECTION, VIPS_COMPASS_DIRECTION_CENTRE); } static void vips_gravity_init(VipsGravity *gravity) { gravity->direction = VIPS_COMPASS_DIRECTION_CENTRE; } /** * vips_gravity: (method) * @in: input image * @out: output image * @direction: place @in at this direction in @out * @width: @out should be this many pixels across * @height: @out should be this many pixels down * @...: `NULL`-terminated list of optional named arguments * * The opposite of [method@Image.extract_area]: place @in within an image of * size @width by @height at a certain gravity. * * @extend controls what appears in the new pels, see [enum@Extend]. * * ::: tip "Optional arguments" * * @extend: [enum@Extend] to generate the edge pixels * (default: [enum@Vips.Extend.BLACK]) * * @background: [struct@ArrayDouble] colour for edge pixels * * ::: seealso * [method@Image.extract_area], [method@Image.insert]. * * Returns: 0 on success, -1 on error. */ int vips_gravity(VipsImage *in, VipsImage **out, VipsCompassDirection direction, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("gravity", ap, in, out, direction, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/extract.c000066400000000000000000000266271516303661500207600ustar00rootroot00000000000000/* extract an area and/or a set of bands * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 12/02/1990 * Modified on: 4/6/92, J.Cupitt * - speed up! why wasn't this done before? Why am I stupid? * - layout, messages fixed * now extracts IM_CODING_LABQ to IM_CODING_LABQ file: K.Martinez 1/7/93 * 2/7/93 JC * - adapted for partial v2 * - ANSIfied * 7/7/93 JC * - behaviour for IM_CODING_LABQ fixed * - better messages * 7/10/94 JC * - new IM_NEW() * 22/2/95 JC * - new use of im_region_region() * 6/7/98 JC * - im_extract_area() and im_extract_band() added * 11/7/01 JC * - im_extract_band() now numbers from zero * 7/11/01 JC * - oh what pain, im_extract now numbers bands from zero as well * 6/9/02 JC * - zero xoff/yoff for extracted area * 14/4/04 JC * - nope, -ve the origin * 17/7/04 * - added im_extract_bands(), remove many bands from image * 24/3/09 * - added IM_CODING_RAD support * 29/1/10 * - cleanups * - gtkdoc * 26/10/11 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" #include "bandary.h" typedef struct _VipsExtractArea { VipsConversion parent_instance; /* The input image. */ VipsImage *in; int left; int top; int width; int height; } VipsExtractArea; typedef VipsConversionClass VipsExtractAreaClass; G_DEFINE_TYPE(VipsExtractArea, vips_extract_area, VIPS_TYPE_CONVERSION); /* Extract an area. Can just use pointers. */ static int vips_extract_area_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsExtractArea *extract = (VipsExtractArea *) b; VipsRect iarea; /* Ask for input we need. Translate from demand in or's space to * demand in ir's space. */ iarea = out_region->valid; iarea.left += extract->left; iarea.top += extract->top; if (vips_region_prepare(ir, &iarea)) return -1; /* Attach or to ir. */ if (vips_region_region(out_region, ir, &out_region->valid, iarea.left, iarea.top)) return -1; return 0; } static int vips_extract_area_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsExtractArea *extract = (VipsExtractArea *) object; VipsImage *in; if (VIPS_OBJECT_CLASS(vips_extract_area_parent_class)->build(object)) return -1; in = extract->in; if ((guint64) extract->left + extract->width > in->Xsize || (guint64) extract->top + extract->height > in->Ysize || extract->left < 0 || extract->top < 0 || extract->width <= 0 || extract->height <= 0) { vips_error(class->nickname, "%s", _("bad extract area")); return -1; } if (vips_image_pio_input(in) || vips_check_coding_known(class->nickname, in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; conversion->out->Xsize = extract->width; conversion->out->Ysize = extract->height; conversion->out->Xoffset = -extract->left; conversion->out->Yoffset = -extract->top; if (vips_image_generate(conversion->out, vips_start_one, vips_extract_area_gen, vips_stop_one, in, extract)) return -1; return 0; } static void vips_extract_area_class_init(VipsExtractAreaClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_extract_area_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "extract_area"; vobject_class->description = _("extract an area from an image"); vobject_class->build = vips_extract_area_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "input", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractArea, in)); VIPS_ARG_INT(class, "left", 3, _("Left"), _("Left edge of extract area"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractArea, left), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "top", 4, _("Top"), _("Top edge of extract area"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractArea, top), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "width", 5, _("Width"), _("Width of extract area"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractArea, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 6, _("Height"), _("Height of extract area"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractArea, height), 1, VIPS_MAX_COORD, 1); } #ifdef __EMSCRIPTEN__ static void vips_crop_init_adapter(VipsExtractArea *extract, void *dummy) { vips_extract_area_init(extract); } #endif static void vips_extract_area_init(VipsExtractArea *extract) { } /** * vips_extract_area: (method) * @in: input image * @out: (out): output image * @left: left edge of area to extract * @top: top edge of area to extract * @width: width of area to extract * @height: height of area to extract * @...: `NULL`-terminated list of optional named arguments * * Extract an area from an image. The area must fit within @in. * * ::: seealso * [method@Image.extract_band], [method@Image.smartcrop]. * * Returns: 0 on success, -1 on error. */ int vips_extract_area(VipsImage *in, VipsImage **out, int left, int top, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("extract_area", ap, in, out, left, top, width, height); va_end(ap); return result; } /* A synonym for extract_area. */ GType vips_crop_get_type(void) { static gsize gtype_id = 0; if (g_once_init_enter(>ype_id)) { GType new_type = g_type_register_static_simple(VIPS_TYPE_CONVERSION, g_intern_static_string("crop"), sizeof(VipsExtractAreaClass), (GClassInitFunc) (void (*)(void)) vips_extract_area_class_intern_init, sizeof(VipsExtractArea), #ifdef __EMSCRIPTEN__ (GInstanceInitFunc) vips_crop_init_adapter, #else (GInstanceInitFunc) (void (*)(void)) vips_extract_area_init, #endif (GTypeFlags) 0); g_once_init_leave(>ype_id, new_type); } return (GType) gtype_id; } /** * vips_crop: (method) * @in: input image * @out: (out): output image * @left: left edge of area to extract * @top: top edge of area to extract * @width: width of area to extract * @height: height of area to extract * @...: `NULL`-terminated list of optional named arguments * * A synonym for [method@Image.extract_area]. * * ::: seealso * [method@Image.extract_band], [method@Image.smartcrop]. * * Returns: 0 on success, -1 on error. */ int vips_crop(VipsImage *in, VipsImage **out, int left, int top, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("crop", ap, in, out, left, top, width, height); va_end(ap); return result; } typedef struct _VipsExtractBand { VipsBandary parent_instance; /* The input image. */ VipsImage *in; int band; int n; } VipsExtractBand; typedef VipsBandaryClass VipsExtractBandClass; G_DEFINE_TYPE(VipsExtractBand, vips_extract_band, VIPS_TYPE_BANDARY); static void vips_extract_band_buffer(VipsBandarySequence *seq, VipsPel *out, VipsPel **in, int width) { VipsBandary *bandary = seq->bandary; VipsConversion *conversion = (VipsConversion *) bandary; VipsExtractBand *extract = (VipsExtractBand *) bandary; VipsImage *im = bandary->ready[0]; int es = VIPS_IMAGE_SIZEOF_ELEMENT(im); int ips = VIPS_IMAGE_SIZEOF_PEL(im); const int ops = VIPS_IMAGE_SIZEOF_PEL(conversion->out); VipsPel *restrict p; VipsPel *restrict q; int x, z; p = in[0] + extract->band * es; q = out; if (ops == 1) { for (x = 0; x < width; x++) { q[x] = p[0]; p += ips; } } else { for (x = 0; x < width; x++) { for (z = 0; z < ops; z++) q[z] = p[z]; p += ips; q += ops; } } } static int vips_extract_band_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsBandary *bandary = (VipsBandary *) object; VipsExtractBand *extract = (VipsExtractBand *) object; if (extract->in) { int bands; vips_image_decode_predict(extract->in, &bands, NULL); bandary->n = 1; bandary->in = &extract->in; bandary->out_bands = extract->n; if ((guint64) extract->band + extract->n > bands) { vips_error(class->nickname, "%s", _("bad extract band")); return -1; } if (extract->band == 0 && extract->n == bands) return vips_bandary_copy(bandary); } if (VIPS_OBJECT_CLASS(vips_extract_band_parent_class)->build(object)) return -1; return 0; } static void vips_extract_band_class_init(VipsExtractBandClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class); VIPS_DEBUG_MSG("vips_extract_band_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "extract_band"; vobject_class->description = _("extract band from an image"); vobject_class->build = vips_extract_band_build; bandary_class->process_line = vips_extract_band_buffer; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractBand, in)); VIPS_ARG_INT(class, "band", 3, _("Band"), _("Band to extract"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsExtractBand, band), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "n", 4, _("n"), _("Number of bands to extract"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsExtractBand, n), 1, VIPS_MAX_COORD, 1); } static void vips_extract_band_init(VipsExtractBand *extract) { extract->n = 1; } /** * vips_extract_band: (method) * @in: input image * @out: (out): output image * @band: index of first band to extract * @...: `NULL`-terminated list of optional named arguments * * Extract a band or bands from an image. Extracting out of range is an error. * * @n defaults to 1. * * ::: tip "Optional arguments" * * @n: `gint`, number of bands to extract * * ::: seealso * [method@Image.extract_area]. * * Returns: 0 on success, -1 on error. */ int vips_extract_band(VipsImage *in, VipsImage **out, int band, ...) { va_list ap; int result; va_start(ap, band); result = vips_call_split("extract_band", ap, in, out, band); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/falsecolour.c000066400000000000000000000204401516303661500216070ustar00rootroot00000000000000/* im_falsecolour * * 23/6/95 JC * - rewritten for PIO * - now walks edges of colour cube to get more saturated appearance * 21/8/05 * - uses falsecolour scale from PET scanner * 7/4/06 * - hmm, reversed scale * 29/1/10 * - cleanups * - gtkdoc * 12/7/11 * - force input to mono 8-bit for the user * 1/8/13 * - redone as a class * 23/1/14 * - oops, was not auto-getting and casting the first band */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconversion.h" typedef struct _VipsFalsecolour { VipsConversion parent_instance; VipsImage *in; } VipsFalsecolour; typedef VipsConversionClass VipsFalsecolourClass; G_DEFINE_TYPE(VipsFalsecolour, vips_falsecolour, VIPS_TYPE_CONVERSION); /* Falsecolour scale nicked from a PET scan. */ static unsigned char vips_falsecolour_pet[][3] = { { 12, 0, 25 }, { 17, 0, 34 }, { 20, 0, 41 }, { 22, 0, 45 }, { 23, 0, 47 }, { 27, 0, 55 }, { 12, 0, 25 }, { 5, 0, 11 }, { 5, 0, 11 }, { 5, 0, 11 }, { 1, 0, 4 }, { 1, 0, 4 }, { 6, 0, 13 }, { 15, 0, 30 }, { 19, 0, 40 }, { 23, 0, 48 }, { 28, 0, 57 }, { 36, 0, 74 }, { 42, 0, 84 }, { 46, 0, 93 }, { 51, 0, 102 }, { 59, 0, 118 }, { 65, 0, 130 }, { 69, 0, 138 }, { 72, 0, 146 }, { 81, 0, 163 }, { 47, 0, 95 }, { 12, 0, 28 }, { 64, 0, 144 }, { 61, 0, 146 }, { 55, 0, 140 }, { 52, 0, 137 }, { 47, 0, 132 }, { 43, 0, 128 }, { 38, 0, 123 }, { 30, 0, 115 }, { 26, 0, 111 }, { 23, 0, 108 }, { 17, 0, 102 }, { 9, 0, 94 }, { 6, 0, 91 }, { 2, 0, 87 }, { 0, 0, 88 }, { 0, 0, 100 }, { 0, 0, 104 }, { 0, 0, 108 }, { 0, 0, 113 }, { 0, 0, 121 }, { 0, 0, 125 }, { 0, 0, 129 }, { 0, 0, 133 }, { 0, 0, 141 }, { 0, 0, 146 }, { 0, 0, 150 }, { 0, 0, 155 }, { 0, 0, 162 }, { 0, 0, 167 }, { 0, 0, 173 }, { 0, 0, 180 }, { 0, 0, 188 }, { 0, 0, 193 }, { 0, 0, 197 }, { 0, 0, 201 }, { 0, 0, 209 }, { 0, 0, 214 }, { 0, 0, 218 }, { 0, 0, 222 }, { 0, 0, 230 }, { 0, 0, 235 }, { 0, 0, 239 }, { 0, 0, 243 }, { 0, 0, 247 }, { 0, 4, 251 }, { 0, 10, 255 }, { 0, 14, 255 }, { 0, 18, 255 }, { 0, 24, 255 }, { 0, 31, 255 }, { 0, 36, 255 }, { 0, 39, 255 }, { 0, 45, 255 }, { 0, 53, 255 }, { 0, 56, 255 }, { 0, 60, 255 }, { 0, 66, 255 }, { 0, 74, 255 }, { 0, 77, 255 }, { 0, 81, 255 }, { 0, 88, 251 }, { 0, 99, 239 }, { 0, 104, 234 }, { 0, 108, 230 }, { 0, 113, 225 }, { 0, 120, 218 }, { 0, 125, 213 }, { 0, 128, 210 }, { 0, 133, 205 }, { 0, 141, 197 }, { 0, 145, 193 }, { 0, 150, 188 }, { 0, 154, 184 }, { 0, 162, 176 }, { 0, 167, 172 }, { 0, 172, 170 }, { 0, 180, 170 }, { 0, 188, 170 }, { 0, 193, 170 }, { 0, 197, 170 }, { 0, 201, 170 }, { 0, 205, 170 }, { 0, 211, 170 }, { 0, 218, 170 }, { 0, 222, 170 }, { 0, 226, 170 }, { 0, 232, 170 }, { 0, 239, 170 }, { 0, 243, 170 }, { 0, 247, 170 }, { 0, 251, 161 }, { 0, 255, 147 }, { 0, 255, 139 }, { 0, 255, 131 }, { 0, 255, 120 }, { 0, 255, 105 }, { 0, 255, 97 }, { 0, 255, 89 }, { 0, 255, 78 }, { 0, 255, 63 }, { 0, 255, 55 }, { 0, 255, 47 }, { 0, 255, 37 }, { 0, 255, 21 }, { 0, 255, 13 }, { 0, 255, 5 }, { 2, 255, 2 }, { 13, 255, 13 }, { 18, 255, 18 }, { 23, 255, 23 }, { 27, 255, 27 }, { 35, 255, 35 }, { 40, 255, 40 }, { 43, 255, 43 }, { 48, 255, 48 }, { 55, 255, 55 }, { 60, 255, 60 }, { 64, 255, 64 }, { 69, 255, 69 }, { 72, 255, 72 }, { 79, 255, 79 }, { 90, 255, 82 }, { 106, 255, 74 }, { 113, 255, 70 }, { 126, 255, 63 }, { 140, 255, 56 }, { 147, 255, 53 }, { 155, 255, 48 }, { 168, 255, 42 }, { 181, 255, 36 }, { 189, 255, 31 }, { 197, 255, 27 }, { 209, 255, 21 }, { 224, 255, 14 }, { 231, 255, 10 }, { 239, 255, 7 }, { 247, 251, 3 }, { 255, 243, 0 }, { 255, 239, 0 }, { 255, 235, 0 }, { 255, 230, 0 }, { 255, 222, 0 }, { 255, 218, 0 }, { 255, 214, 0 }, { 255, 209, 0 }, { 255, 201, 0 }, { 255, 197, 0 }, { 255, 193, 0 }, { 255, 188, 0 }, { 255, 180, 0 }, { 255, 176, 0 }, { 255, 172, 0 }, { 255, 167, 0 }, { 255, 156, 0 }, { 255, 150, 0 }, { 255, 146, 0 }, { 255, 142, 0 }, { 255, 138, 0 }, { 255, 131, 0 }, { 255, 125, 0 }, { 255, 121, 0 }, { 255, 117, 0 }, { 255, 110, 0 }, { 255, 104, 0 }, { 255, 100, 0 }, { 255, 96, 0 }, { 255, 90, 0 }, { 255, 83, 0 }, { 255, 78, 0 }, { 255, 75, 0 }, { 255, 71, 0 }, { 255, 67, 0 }, { 255, 65, 0 }, { 255, 63, 0 }, { 255, 59, 0 }, { 255, 54, 0 }, { 255, 52, 0 }, { 255, 50, 0 }, { 255, 46, 0 }, { 255, 41, 0 }, { 255, 39, 0 }, { 255, 36, 0 }, { 255, 32, 0 }, { 255, 25, 0 }, { 255, 22, 0 }, { 255, 20, 0 }, { 255, 17, 0 }, { 255, 13, 0 }, { 255, 10, 0 }, { 255, 7, 0 }, { 255, 4, 0 }, { 255, 0, 0 }, { 252, 0, 0 }, { 251, 0, 0 }, { 249, 0, 0 }, { 248, 0, 0 }, { 244, 0, 0 }, { 242, 0, 0 }, { 240, 0, 0 }, { 237, 0, 0 }, { 234, 0, 0 }, { 231, 0, 0 }, { 229, 0, 0 }, { 228, 0, 0 }, { 225, 0, 0 }, { 222, 0, 0 }, { 221, 0, 0 }, { 219, 0, 0 }, { 216, 0, 0 }, { 213, 0, 0 }, { 212, 0, 0 }, { 210, 0, 0 }, { 207, 0, 0 }, { 204, 0, 0 }, { 201, 0, 0 }, { 199, 0, 0 }, { 196, 0, 0 }, { 193, 0, 0 }, { 192, 0, 0 }, { 190, 0, 0 }, { 188, 0, 0 }, { 184, 0, 0 }, { 183, 0, 0 }, { 181, 0, 0 }, { 179, 0, 0 }, { 175, 0, 0 }, { 174, 0, 0 }, { 174, 0, 0 } }; static int vips_falsecolour_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsFalsecolour *falsecolour = (VipsFalsecolour *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); if (VIPS_OBJECT_CLASS(vips_falsecolour_parent_class)->build(object)) return -1; if (!(t[0] = vips_image_new_from_memory( (void *) vips_falsecolour_pet, sizeof(vips_falsecolour_pet), 1, VIPS_NUMBER(vips_falsecolour_pet), 3, VIPS_FORMAT_UCHAR))) return -1; /* Force to mono 8-bit. Don't use vips_colourspace() to go to B_W, we * want to work for images which aren't in a recognised space, like * MULTIBAND. */ if (vips_image_decode(falsecolour->in, &t[1]) || vips_extract_band(t[1], &t[2], 0, NULL) || vips_cast(t[2], &t[3], VIPS_FORMAT_UCHAR, NULL) || vips_maplut(t[3], &t[4], t[0], NULL) || vips_image_write(t[4], conversion->out)) return -1; return 0; } static void vips_falsecolour_class_init(VipsFalsecolourClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "falsecolour"; vobject_class->description = _("false-color an image"); vobject_class->build = vips_falsecolour_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFalsecolour, in)); } static void vips_falsecolour_init(VipsFalsecolour *falsecolour) { } /** * vips_falsecolour: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Force @in to 1 band, 8-bit, then transform to * a 3-band 8-bit image with a false colour * map. The map is supposed to make small differences in brightness more * obvious. * * ::: seealso * [method@Image.maplut]. * * Returns: 0 on success, -1 on error */ int vips_falsecolour(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("falsecolour", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/flatten.c000066400000000000000000000256111516303661500207330ustar00rootroot00000000000000/* flatten the alpha out of an image, replacing it with a constant background * * Author: John Cupitt * Written on: 18/6/12 * * 4/1/14 * - better rounding * 9/5/15 * - add max_alpha to match vips_premultiply() etc. * 25/5/16 * - max_alpha defaults to 65535 for RGB16/GREY16 * 12/9/21 * - out of range alpha and max_alpha correctly */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsFlatten { VipsConversion parent_instance; VipsImage *in; /* Background colour. */ VipsArrayDouble *background; /* The [double] background converted to the input image format. */ VipsPel *ink; /* Use this to scale alpha to 0 - 1. */ double max_alpha; } VipsFlatten; typedef VipsConversionClass VipsFlattenClass; G_DEFINE_TYPE(VipsFlatten, vips_flatten, VIPS_TYPE_CONVERSION); /* Flatten with black background. */ #define VIPS_FLATTEN_BLACK_INT(TYPE) \ { \ TYPE *restrict p = (TYPE *) in; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ TYPE alpha = p[bands - 1]; \ int b; \ \ for (b = 0; b < bands - 1; b++) \ q[b] = (p[b] * alpha) / max_alpha; \ \ p += bands; \ q += bands - 1; \ } \ } /* Same, but with float arithmetic. Necessary for short/int to prevent * overflow. */ #define VIPS_FLATTEN_BLACK_FLOAT(TYPE) \ { \ TYPE *restrict p = (TYPE *) in; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ TYPE alpha = p[bands - 1]; \ int b; \ \ for (b = 0; b < bands - 1; b++) \ q[b] = ((double) p[b] * alpha) / max_alpha; \ \ p += bands; \ q += bands - 1; \ } \ } /* Flatten with any background. */ #define VIPS_FLATTEN_INT(TYPE) \ { \ TYPE *restrict p = (TYPE *) in; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ TYPE alpha = p[bands - 1]; \ TYPE nalpha = max_alpha - alpha; \ TYPE *restrict bg = (TYPE *) flatten->ink; \ int b; \ \ for (b = 0; b < bands - 1; b++) \ q[b] = (p[b] * alpha + bg[b] * nalpha) / max_alpha; \ \ p += bands; \ q += bands - 1; \ } \ } #define VIPS_FLATTEN_FLOAT(TYPE) \ { \ TYPE *restrict p = (TYPE *) in; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ TYPE alpha = p[bands - 1]; \ TYPE nalpha = max_alpha - alpha; \ TYPE *restrict bg = (TYPE *) flatten->ink; \ int b; \ \ for (b = 0; b < bands - 1; b++) \ q[b] = ((double) p[b] * alpha + \ (double) bg[b] * nalpha) / \ max_alpha; \ \ p += bands; \ q += bands - 1; \ } \ } static int vips_flatten_black_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) vseq; VipsFlatten *flatten = (VipsFlatten *) b; VipsRect *r = &out_region->valid; int width = r->width; int bands = ir->im->Bands; double max_alpha = flatten->max_alpha; int x, y; if (vips_region_prepare(ir, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *in = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *out = VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (ir->im->BandFmt) { case VIPS_FORMAT_UCHAR: VIPS_FLATTEN_BLACK_INT(unsigned char); break; case VIPS_FORMAT_CHAR: VIPS_FLATTEN_BLACK_INT(signed char); break; case VIPS_FORMAT_USHORT: VIPS_FLATTEN_BLACK_FLOAT(unsigned short); break; case VIPS_FORMAT_SHORT: VIPS_FLATTEN_BLACK_FLOAT(signed short); break; case VIPS_FORMAT_UINT: VIPS_FLATTEN_BLACK_FLOAT(unsigned int); break; case VIPS_FORMAT_INT: VIPS_FLATTEN_BLACK_FLOAT(signed int); break; case VIPS_FORMAT_FLOAT: VIPS_FLATTEN_BLACK_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: VIPS_FLATTEN_BLACK_FLOAT(double); break; case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: default: g_assert_not_reached(); } } return 0; } /* Any background. */ static int vips_flatten_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) vseq; VipsFlatten *flatten = (VipsFlatten *) b; VipsRect *r = &out_region->valid; int width = r->width; int bands = ir->im->Bands; double max_alpha = flatten->max_alpha; int x, y; if (vips_region_prepare(ir, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *in = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *out = VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (ir->im->BandFmt) { case VIPS_FORMAT_UCHAR: VIPS_FLATTEN_INT(unsigned char); break; case VIPS_FORMAT_CHAR: VIPS_FLATTEN_INT(signed char); break; case VIPS_FORMAT_USHORT: VIPS_FLATTEN_FLOAT(unsigned short); break; case VIPS_FORMAT_SHORT: VIPS_FLATTEN_FLOAT(signed short); break; case VIPS_FORMAT_UINT: VIPS_FLATTEN_FLOAT(unsigned int); break; case VIPS_FORMAT_INT: VIPS_FLATTEN_FLOAT(signed int); break; case VIPS_FORMAT_FLOAT: VIPS_FLATTEN_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: VIPS_FLATTEN_FLOAT(double); break; case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: default: g_assert_not_reached(); } } return 0; } static int vips_flatten_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsFlatten *flatten = (VipsFlatten *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; int i; gboolean black; VipsBandFormat original_format; if (VIPS_OBJECT_CLASS(vips_flatten_parent_class)->build(object)) return -1; in = flatten->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; /* Trivial case: fall back to copy(). */ if (in->Bands == 1) return vips_image_write(in, conversion->out); if (vips_check_noncomplex(class->nickname, in)) return -1; /* Is max-alpha unset? Default to the correct value for this * interpretation. */ if (!vips_object_argument_isset(object, "max_alpha")) flatten->max_alpha = vips_interpretation_max_alpha(in->Type); // FIXME: Invalidates operation cache /* Is max_alpha less than the numeric range of this image? If it is, * we can get int overflow. * * This is not a common case, so efficiency is not so important. * Cast to double, then cast back to the input type right at the end. */ original_format = VIPS_FORMAT_NOTSET; if (vips_band_format_isint(in->BandFmt) && flatten->max_alpha < vips_image_get_format_max(in->BandFmt)) { original_format = in->BandFmt; if (vips_cast(in, &t[1], VIPS_FORMAT_DOUBLE, NULL)) return -1; in = t[1]; } t[2] = vips_image_new(); if (vips_image_pipelinev(t[2], VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; t[2]->Bands -= 1; /* Is the background black? We have a special path for this. */ black = TRUE; for (i = 0; i < VIPS_AREA(flatten->background)->n; i++) { const double *background = vips_array_double_get(flatten->background, NULL); if (background[i] != 0.0) { black = FALSE; break; } } if (black) { if (vips_image_generate(t[2], vips_start_one, vips_flatten_black_gen, vips_stop_one, in, flatten)) return -1; in = t[2]; } else { /* Convert the background to the image's format. */ if (!(flatten->ink = vips__vector_to_ink(class->nickname, t[2], VIPS_AREA(flatten->background)->data, NULL, VIPS_AREA(flatten->background)->n))) return -1; if (vips_image_generate(t[2], vips_start_one, vips_flatten_gen, vips_stop_one, in, flatten)) return -1; in = t[2]; } if (original_format != VIPS_FORMAT_NOTSET) { if (vips_cast(in, &t[3], original_format, NULL)) return -1; in = t[3]; } if (vips_image_write(in, conversion->out)) return -1; return 0; } static void vips_flatten_class_init(VipsFlattenClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_flatten_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "flatten"; vobject_class->description = _("flatten alpha out of an image"); vobject_class->build = vips_flatten_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFlatten, in)); VIPS_ARG_BOXED(class, "background", 2, _("Background"), _("Background value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsFlatten, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_DOUBLE(class, "max_alpha", 115, _("Maximum alpha"), _("Maximum value of alpha channel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsFlatten, max_alpha), 0, 100000000, 255); } static void vips_flatten_init(VipsFlatten *flatten) { flatten->background = vips_array_double_newv(1, 0.0); flatten->max_alpha = 255.0; } /** * vips_flatten: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Take the last band of @in as an alpha and use it to blend the * remaining channels with @background. * * The alpha channel is 0 - @max_alpha, where @max_alpha means 100% image * and 0 means 100% background. @background defaults to zero (black). * * @max_alpha has the default value 255, or 65535 for images tagged as * [enum@Vips.Interpretation.RGB16] or [enum@Vips.Interpretation.GREY16]. * * Useful for flattening PNG images to RGB. * * Non-complex images only. * * ::: tip "Optional arguments" * * @background: [struct@ArrayDouble] colour for new pixels * * @max_alpha: `gdouble`, maximum value for alpha * * ::: seealso * [method@Image.premultiply], [ctor@Image.pngload]. * * Returns: 0 on success, -1 on error */ int vips_flatten(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("flatten", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/flip.c000066400000000000000000000133441516303661500202300ustar00rootroot00000000000000/* flip left/right and up/down * * Copyright: 1990, N. Dessipris * Written on: 28/10/91 * Updated on: * 19/7/93 JC * - now allows IM_CODING_LABQ too * - yuk! needs rewriting * 21/12/94 JC * - rewritten * 14/4/04 * - sets Xoffset / Yoffset * 24/3/09 * - added IM_CODING_RAD support * 29/1/10 * - cleanups * - gtkdoc * 17/10/11 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsFlip { VipsConversion parent_instance; /* The input image. */ VipsImage *in; /* Left-right or up-down. */ VipsDirection direction; } VipsFlip; typedef VipsConversionClass VipsFlipClass; G_DEFINE_TYPE(VipsFlip, vips_flip, VIPS_TYPE_CONVERSION); static int vips_flip_vertical_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; VipsRect in; VipsPel *p, *q; int y; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int ls; int psk, qsk; /* Transform to input coordinates. */ in = *r; in.top = ir->im->Ysize - bo; /* Ask for input we need. */ if (vips_region_prepare(ir, &in)) return -1; /* Loop, copying and reversing lines. */ p = VIPS_REGION_ADDR(ir, le, in.top + in.height - 1); q = VIPS_REGION_ADDR(out_region, le, to); psk = VIPS_REGION_LSKIP(ir); qsk = VIPS_REGION_LSKIP(out_region); ls = VIPS_REGION_SIZEOF_LINE(out_region); for (y = to; y < bo; y++) { memcpy(q, p, ls); p -= psk; q += qsk; } return 0; } static int vips_flip_horizontal_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; VipsRect in; VipsPel *p, *q; int x, y, z; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int ps = VIPS_IMAGE_SIZEOF_PEL(ir->im); /* sizeof pel */ int hgt = ir->im->Xsize - r->width; int lastx; /* Transform to input coordinates. */ in = *r; in.left = hgt - r->left; /* Find x of final pixel in input area. */ lastx = VIPS_RECT_RIGHT(&in) - 1; /* Ask for input we need. */ if (vips_region_prepare(ir, &in)) return -1; /* Loop, copying and reversing lines. */ for (y = to; y < bo; y++) { p = VIPS_REGION_ADDR(ir, lastx, y); q = VIPS_REGION_ADDR(out_region, le, y); for (x = le; x < ri; x++) { /* Copy the pel. */ for (z = 0; z < ps; z++) q[z] = p[z]; /* Skip forwards in out, back in in. */ q += ps; p -= ps; } } return 0; } static int vips_flip_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsFlip *flip = (VipsFlip *) object; VipsImage *in; VipsGenerateFn generate_fn; if (VIPS_OBJECT_CLASS(vips_flip_parent_class)->build(object)) return -1; in = flip->in; if (vips_image_pio_input(in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; if (flip->direction == VIPS_DIRECTION_HORIZONTAL) { generate_fn = vips_flip_horizontal_gen; conversion->out->Xoffset = in->Xsize; conversion->out->Yoffset = 0; } else { generate_fn = vips_flip_vertical_gen; conversion->out->Xoffset = 0; conversion->out->Yoffset = in->Ysize; } if (vips_image_generate(conversion->out, vips_start_one, generate_fn, vips_stop_one, in, flip)) return -1; return 0; } static void vips_flip_class_init(VipsFlipClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_flip_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "flip"; vobject_class->description = _("flip an image"); vobject_class->build = vips_flip_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFlip, in)); VIPS_ARG_ENUM(class, "direction", 6, _("Direction"), _("Direction to flip image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFlip, direction), VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL); } static void vips_flip_init(VipsFlip *flip) { } /** * vips_flip: (method) * @in: input image * @out: (out): output image * @direction: flip horizontally or vertically * @...: `NULL`-terminated list of optional named arguments * * Flips an image left-right or up-down. * * ::: seealso * [method@Image.rot]. * * Returns: 0 on success, -1 on error */ int vips_flip(VipsImage *in, VipsImage **out, VipsDirection direction, ...) { va_list ap; int result; va_start(ap, direction); result = vips_call_split("flip", ap, in, out, direction); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/gamma.c000066400000000000000000000110321516303661500203500ustar00rootroot00000000000000/* Raise an image to a gamma factor * * Copyright: 1990, N. Dessipris. * * Written on: 19/07/1990 * Modified on: * 19/6/95 JC * - redone as library function * 23/3/10 * - gtkdoc * - 16 bit as well * 1/8/13 * - redone as a class * 11/11/13 * - any format * - calculate pow(1/exp) rather than pow(exp) to be consistent with * other packages */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pconversion.h" typedef struct _VipsGamma { VipsConversion parent_instance; VipsImage *in; double exponent; } VipsGamma; typedef VipsConversionClass VipsGammaClass; G_DEFINE_TYPE(VipsGamma, vips_gamma, VIPS_TYPE_CONVERSION); /* For each input format, what we normalise the pow() about. */ static double vips_gamma_maxval[10] = { /* UC */ UCHAR_MAX, /* C */ SCHAR_MAX, /* US */ USHRT_MAX, /* S */ SHRT_MAX, /* UI */ UINT_MAX, /* I */ INT_MAX, /* F */ 1.0, /* X */ 1.0, /* D */ 1.0, /* DX */ 1.0 }; static int vips_gamma_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsGamma *gamma = (VipsGamma *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); VipsImage *in = gamma->in; double scale; if (VIPS_OBJECT_CLASS(vips_gamma_parent_class)->build(object)) return -1; scale = pow(vips_gamma_maxval[in->BandFmt], 1.0 / gamma->exponent) / vips_gamma_maxval[in->BandFmt]; if (in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT) { if (vips_identity(&t[0], "ushort", in->BandFmt == VIPS_FORMAT_USHORT, NULL) || vips_pow_const1(t[0], &t[1], 1.0 / gamma->exponent, NULL) || vips_linear1(t[1], &t[2], 1.0 / scale, 0, NULL) || vips_cast(t[2], &t[3], in->BandFmt, NULL) || vips_maplut(in, &t[4], t[3], NULL) || vips_image_write(t[4], conversion->out)) return -1; } else { if (vips_pow_const1(in, &t[1], 1.0 / gamma->exponent, NULL) || vips_linear1(t[1], &t[2], 1.0 / scale, 0, NULL) || vips_cast(t[2], &t[3], in->BandFmt, NULL) || vips_image_write(t[3], conversion->out)) return -1; } return 0; } static void vips_gamma_class_init(VipsGammaClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "gamma"; vobject_class->description = _("gamma an image"); vobject_class->build = vips_gamma_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGamma, in)); VIPS_ARG_DOUBLE(class, "exponent", 2, _("Exponent"), _("Gamma factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGamma, exponent), 0.000001, 1000.0, 1.0 / 2.4); } static void vips_gamma_init(VipsGamma *gamma) { gamma->exponent = 1.0 / 2.4; } /** * vips_gamma: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Calculate @in ** (1 / @exponent), normalising to the maximum range of the * input type. For float types use 1.0 as the maximum. * * ::: tip "Optional arguments" * * @exponent: `gdouble`, gamma, default 1.0 / 2.4 * * ::: seealso * [ctor@Image.identity], [method@Image.pow_const1], [method@Image.maplut] * * Returns: 0 on success, -1 on error */ int vips_gamma(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("gamma", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/grid.c000066400000000000000000000147201516303661500202220ustar00rootroot00000000000000/* vips_grid * * 4/8/05 * 7/9/05 * - oops, clipping was wrong * 30/1/10 * - gtkdoc * - small cleanups * 30/5/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconversion.h" typedef struct _VipsGrid { VipsConversion parent_instance; VipsImage *in; int tile_height; int across; int down; } VipsGrid; typedef VipsConversionClass VipsGridClass; G_DEFINE_TYPE(VipsGrid, vips_grid, VIPS_TYPE_CONVERSION); static int vips_grid_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) vseq; VipsGrid *grid = (VipsGrid *) b; VipsRect *r = &out_region->valid; int twidth = grid->in->Xsize; int theight = grid->tile_height; int x, y; VipsRect tile; /* Find top left of tiles we need. */ int xs = (r->left / twidth) * twidth; int ys = (r->top / theight) * theight; /* The tile enclosing the top-left corner of the requested area. */ tile.left = xs; tile.top = ys; tile.width = twidth; tile.height = theight; /* If the request fits inside a single tile, we can just pointer-copy. */ if (vips_rect_includesrect(&tile, r)) { VipsRect irect; /* Translate request to input space. */ irect = *r; irect.left -= xs; irect.top -= ys; irect.top += grid->across * ys + theight * (xs / twidth); if (vips_region_prepare(ir, &irect) || vips_region_region(out_region, ir, r, irect.left, irect.top)) return -1; return 0; } for (y = ys; y < VIPS_RECT_BOTTOM(r); y += theight) for (x = xs; x < VIPS_RECT_RIGHT(r); x += twidth) { VipsRect paint; VipsRect input; /* Whole tile at x, y */ tile.left = x; tile.top = y; tile.width = twidth; tile.height = theight; /* Which parts touch the area of the output we are * building. */ vips_rect_intersectrect(&tile, r, &paint); g_assert(!vips_rect_isempty(&paint)); /* Translate back to ir coordinates. */ input = paint; input.left -= x; input.top -= y; input.top += grid->across * y + theight * (x / twidth); /* Render into out_region. */ if (vips_region_prepare_to(ir, out_region, &input, paint.left, paint.top)) return -1; } return 0; } static int vips_grid_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsGrid *grid = (VipsGrid *) object; if (VIPS_OBJECT_CLASS(vips_grid_parent_class)->build(object)) return -1; if (vips_check_coding_known(class->nickname, grid->in) || vips_image_pio_input(grid->in)) return -1; if (grid->in->Ysize % grid->tile_height != 0 || grid->in->Ysize / grid->tile_height != grid->across * grid->down) { vips_error(class->nickname, "%s", _("bad grid geometry")); return -1; } /* We can render small tiles with pointer copies. */ if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, grid->in, NULL)) return -1; conversion->out->Xsize = grid->in->Xsize * grid->across; conversion->out->Ysize = grid->tile_height * grid->down; if (vips_image_generate(conversion->out, vips_start_one, vips_grid_gen, vips_stop_one, grid->in, grid)) return -1; return 0; } static void vips_grid_class_init(VipsGridClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "grid"; vobject_class->description = _("grid an image"); vobject_class->build = vips_grid_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGrid, in)); VIPS_ARG_INT(class, "tile_height", 3, _("Tile height"), _("Chop into tiles this high"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGrid, tile_height), 1, 10000000, 128); VIPS_ARG_INT(class, "across", 4, _("Across"), _("Number of tiles across"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGrid, across), 1, 10000000, 1); VIPS_ARG_INT(class, "down", 5, _("Down"), _("Number of tiles down"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGrid, down), 1, 10000000, 1); } static void vips_grid_init(VipsGrid *grid) { grid->tile_height = 128; grid->across = 1; grid->down = 1; } /** * vips_grid: (method) * @in: input image * @out: (out): output image * @tile_height: chop into tiles this high * @across: tiles across * @down: tiles down * @...: `NULL`-terminated list of optional named arguments * * Chop a tall thin image up into a set of tiles, lay the tiles out in a grid. * * The input image should be a very tall, thin image containing a list of * smaller images. Volumetric or time-sequence images are often laid out like * this. This image is chopped into a series of tiles, each @tile_height * pixels high and the width of @in. The tiles are then rearranged into a grid * @across tiles across and @down tiles down in row-major order. * * Supplying @tile_height, @across and @down is not strictly necessary, we * only really need two of these. Requiring three is a double-check that the * image has the expected geometry. * * ::: seealso * [method@Image.embed], [method@Image.insert], [method@Image.join]. * * Returns: 0 on success, -1 on error */ int vips_grid(VipsImage *in, VipsImage **out, int tile_height, int across, int down, ...) { va_list ap; int result; va_start(ap, down); result = vips_call_split("grid", ap, in, out, tile_height, across, down); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/ifthenelse.c000066400000000000000000000331551516303661500214260ustar00rootroot00000000000000/* ifthenelse.c -- use a condition image to join two images together * * Modified: * 9/2/95 JC * - partialed and ANSIfied * 11/9/95 JC * - return( 0 ) missing! oops * 15/4/05 * - now just evals left/right if all zero/all one * 7/10/06 * - set THINSTRIP * 23/9/09 * - gtkdoc comment * 23/9/09 * - use im_check*() * - allow many-band conditional and single-band a/b * - allow a/b to differ in format and bands * 25/6/10 * - let the conditional image be any format by adding a (!=0) if * necessary * 17/5/11 * - added sizealike * 14/11/11 * - redone as a class * 19/4/12 * - fix blend * - small blend speedup */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsIfthenelse { VipsConversion parent_instance; /* Params. */ VipsImage *cond; VipsImage *in1; VipsImage *in2; gboolean blend; } VipsIfthenelse; typedef VipsConversionClass VipsIfthenelseClass; G_DEFINE_TYPE(VipsIfthenelse, vips_ifthenelse, VIPS_TYPE_CONVERSION); #define IBLEND1(TYPE) \ { \ TYPE *a = (TYPE *) ap; \ TYPE *b = (TYPE *) bp; \ TYPE *q = (TYPE *) qp; \ \ for (i = 0, x = 0; x < n; i++, x += bands) { \ const int v = c[i]; \ \ for (z = x; z < x + bands; z++) \ q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \ } \ } #define IBLENDN(TYPE) \ { \ TYPE *a = (TYPE *) ap; \ TYPE *b = (TYPE *) bp; \ TYPE *q = (TYPE *) qp; \ \ for (x = 0; x < n; x += bands) { \ for (z = x; z < x + bands; z++) { \ const int v = c[z]; \ \ q[z] = (v * a[z] + (255 - v) * b[z] + 128) / 255; \ } \ } \ } #define FBLEND1(TYPE) \ { \ TYPE *a = (TYPE *) ap; \ TYPE *b = (TYPE *) bp; \ TYPE *q = (TYPE *) qp; \ \ for (i = 0, x = 0; x < n; i++, x += bands) { \ const double v = c[i] / 255.0; \ \ for (z = x; z < x + bands; z++) \ q[z] = v * a[z] + (1.0 - v) * b[z]; \ } \ } #define FBLENDN(TYPE) \ { \ TYPE *a = (TYPE *) ap; \ TYPE *b = (TYPE *) bp; \ TYPE *q = (TYPE *) qp; \ \ for (x = 0; x < n; x += bands) { \ for (z = x; z < x + bands; z++) { \ const double v = c[z] / 255.0; \ \ q[z] = v * a[z] + (1.0 - v) * b[z]; \ } \ } \ } #define CBLEND1(TYPE) \ { \ TYPE *a = (TYPE *) ap; \ TYPE *b = (TYPE *) bp; \ TYPE *q = (TYPE *) qp; \ \ for (i = 0, x = 0; x < n; i++, x += bands) { \ const double v = c[i] / 255.0; \ \ for (z = x; z < x + 2 * bands; z++) \ q[z] = v * a[z] + (1.0 - v) * b[z]; \ } \ } #define CBLENDN(TYPE) \ { \ TYPE *a = (TYPE *) ap; \ TYPE *b = (TYPE *) bp; \ TYPE *q = (TYPE *) qp; \ \ for (x = 0; x < n; x += bands) { \ for (z = x; z < x + bands; z++) { \ const double v = c[z] / 255.0; \ \ q[2 * z] = v * a[2 * z] + (1.0 - v) * b[2 * z]; \ q[2 * z + 1] = v * a[2 * z + 1] + \ (1.0 - v) * b[2 * z + 1]; \ } \ } \ } /* Blend with a 1-band conditional image. */ static void vips_blend1_buffer(VipsPel *qp, VipsPel *c, VipsPel *ap, VipsPel *bp, int width, VipsImage *im) { int i, x, z; const int bands = im->Bands; const int n = width * bands; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: IBLEND1(unsigned char); break; case VIPS_FORMAT_CHAR: IBLEND1(signed char); break; case VIPS_FORMAT_USHORT: IBLEND1(unsigned short); break; case VIPS_FORMAT_SHORT: IBLEND1(signed short); break; case VIPS_FORMAT_UINT: IBLEND1(unsigned int); break; case VIPS_FORMAT_INT: IBLEND1(signed int); break; case VIPS_FORMAT_FLOAT: FBLEND1(float); break; case VIPS_FORMAT_DOUBLE: FBLEND1(double); break; case VIPS_FORMAT_COMPLEX: CBLEND1(float); break; case VIPS_FORMAT_DPCOMPLEX: CBLEND1(double); break; default: g_assert_not_reached(); } } /* Blend with a many band conditional image. */ static void vips_blendn_buffer(VipsPel *qp, VipsPel *c, VipsPel *ap, VipsPel *bp, int width, VipsImage *im) { int x, z; const int bands = im->Bands; const int n = width * bands; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: IBLENDN(unsigned char); break; case VIPS_FORMAT_CHAR: IBLENDN(signed char); break; case VIPS_FORMAT_USHORT: IBLENDN(unsigned short); break; case VIPS_FORMAT_SHORT: IBLENDN(signed short); break; case VIPS_FORMAT_UINT: IBLENDN(unsigned int); break; case VIPS_FORMAT_INT: IBLENDN(signed int); break; case VIPS_FORMAT_FLOAT: FBLENDN(float); break; case VIPS_FORMAT_DOUBLE: FBLENDN(double); break; case VIPS_FORMAT_COMPLEX: CBLENDN(float); break; case VIPS_FORMAT_DPCOMPLEX: CBLENDN(double); break; default: g_assert_not_reached(); } } static int vips_blend_gen(VipsRegion *out_region, void *seq, void *client1, void *client2, gboolean *stop) { VipsRegion **ir = (VipsRegion **) seq; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); VipsImage *c = ir[2]->im; VipsImage *a = ir[0]->im; int x, y; int all0, all255; if (vips_region_prepare(ir[2], r)) return -1; /* Is the conditional all zero or all 255? We can avoid asking * for one of the inputs to be calculated. */ all0 = *VIPS_REGION_ADDR(ir[2], le, to) == 0; all255 = *VIPS_REGION_ADDR(ir[2], le, to) == 255; for (y = to; y < bo; y++) { VipsPel *p = VIPS_REGION_ADDR(ir[2], le, y); int width = r->width * c->Bands; for (x = 0; x < width; x++) { all0 &= p[x] == 0; all255 &= p[x] == 255; } if (!all0 && !all255) break; } if (all255) { /* All 255. Point or at the then image. */ if (vips_region_prepare(ir[0], r) || vips_region_region(out_region, ir[0], r, r->left, r->top)) return -1; } else if (all0) { /* All zero. Point or at the else image. */ if (vips_region_prepare(ir[1], r) || vips_region_region(out_region, ir[1], r, r->left, r->top)) return -1; } else { /* Mix of set and clear ... ask for both then and else parts * and interleave. * * We can't use vips_reorder_prepare_many() since we always * want the c image first. */ if (vips_region_prepare(ir[0], r) || vips_region_prepare(ir[1], r)) return -1; for (y = to; y < bo; y++) { VipsPel *ap = VIPS_REGION_ADDR(ir[0], le, y); VipsPel *bp = VIPS_REGION_ADDR(ir[1], le, y); VipsPel *cp = VIPS_REGION_ADDR(ir[2], le, y); VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); if (c->Bands == 1) vips_blend1_buffer(q, cp, ap, bp, r->width, a); else vips_blendn_buffer(q, cp, ap, bp, r->width, a); } } return 0; } static int vips_ifthenelse_gen(VipsRegion *out_region, void *seq, void *client1, void *client2, gboolean *stop) { VipsRegion **ir = (VipsRegion **) seq; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); VipsImage *c = ir[2]->im; VipsImage *a = ir[0]->im; int size, width; int i, x, y, z; int all0, alln0; if (c->Bands == 1) { /* Copying PEL-sized units with a one-band conditional. */ size = VIPS_IMAGE_SIZEOF_PEL(a); width = r->width; } else { /* Copying ELEMENT sized-units with an n-band conditional. */ size = VIPS_IMAGE_SIZEOF_ELEMENT(a); width = r->width * a->Bands; } if (vips_region_prepare(ir[2], r)) return -1; /* Is the conditional all zero or all non-zero? We can avoid asking * for one of the inputs to be calculated. */ all0 = *VIPS_REGION_ADDR(ir[2], le, to) == 0; alln0 = *VIPS_REGION_ADDR(ir[2], le, to) != 0; for (y = to; y < bo; y++) { VipsPel *p = VIPS_REGION_ADDR(ir[2], le, y); for (x = 0; x < width; x++) { all0 &= p[x] == 0; alln0 &= p[x] != 0; } if (!all0 && !alln0) break; } if (alln0) { /* All non-zero. Point or at the then image. */ if (vips_region_prepare(ir[0], r) || vips_region_region(out_region, ir[0], r, r->left, r->top)) return -1; } else if (all0) { /* All zero. Point or at the else image. */ if (vips_region_prepare(ir[1], r) || vips_region_region(out_region, ir[1], r, r->left, r->top)) return -1; } else { /* Mix of set and clear ... ask for both then and else parts * and interleave. */ if (vips_region_prepare(ir[0], r) || vips_region_prepare(ir[1], r)) return -1; for (y = to; y < bo; y++) { VipsPel *ap = VIPS_REGION_ADDR(ir[0], le, y); VipsPel *bp = VIPS_REGION_ADDR(ir[1], le, y); VipsPel *cp = VIPS_REGION_ADDR(ir[2], le, y); VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); for (x = 0, i = 0; i < width; i++, x += size) if (cp[i]) for (z = x; z < x + size; z++) q[z] = ap[z]; else for (z = x; z < x + size; z++) q[z] = bp[z]; } } return 0; } static int vips_ifthenelse_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsIfthenelse *ifthenelse = (VipsIfthenelse *) object; VipsGenerateFn generate_fn = ifthenelse->blend ? vips_blend_gen : vips_ifthenelse_gen; VipsImage **band = (VipsImage **) vips_object_local_array(object, 3); VipsImage **size = (VipsImage **) vips_object_local_array(object, 3); VipsImage **format = (VipsImage **) vips_object_local_array(object, 3); VipsImage *all[3]; if (VIPS_OBJECT_CLASS(vips_ifthenelse_parent_class)->build(object)) return -1; /* We have to have the condition image last since we want the output * image to inherit its properties from the then/else parts. */ all[0] = ifthenelse->in1; all[1] = ifthenelse->in2; all[2] = ifthenelse->cond; /* No need to check input images, sizealike and friends will do this * for us. */ /* Cast our input images up to a common bands and size. */ if (vips__bandalike_vec(class->nickname, all, band, 3, 0) || vips__sizealike_vec(band, size, 3)) return -1; /* Condition is cast to uchar, then/else to a common type. */ if (size[2]->BandFmt != VIPS_FORMAT_UCHAR) { if (vips_cast(size[2], &format[2], VIPS_FORMAT_UCHAR, NULL)) return -1; } else { format[2] = size[2]; g_object_ref(format[2]); } if (vips__formatalike_vec(size, format, 2)) return -1; if (vips_image_pipeline_array(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, format)) return -1; if (vips_image_generate(conversion->out, vips_start_many, generate_fn, vips_stop_many, format, ifthenelse)) return -1; return 0; } static void vips_ifthenelse_class_init(VipsIfthenelseClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_ifthenelse_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "ifthenelse"; vobject_class->description = _("ifthenelse an image"); vobject_class->build = vips_ifthenelse_build; VIPS_ARG_IMAGE(class, "cond", -2, _("Condition"), _("Condition input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsIfthenelse, cond)); VIPS_ARG_IMAGE(class, "in1", -1, _("Then image"), _("Source for TRUE pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsIfthenelse, in1)); VIPS_ARG_IMAGE(class, "in2", 0, _("Else image"), _("Source for FALSE pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsIfthenelse, in2)); VIPS_ARG_BOOL(class, "blend", 4, _("Blend"), _("Blend smoothly between then and else parts"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIfthenelse, blend), FALSE); } static void vips_ifthenelse_init(VipsIfthenelse *ifthenelse) { } /** * vips_ifthenelse: (method) * @cond: condition [class@Image] * @in1: then [class@Image] * @in2: else [class@Image] * @out: (out): output [class@Image] * @...: `NULL`-terminated list of optional named arguments * * This operation scans the condition image @cond * and uses it to select pixels from either the then image @in1 or the else * image @in2. Non-zero means @in1, 0 means @in2. * * Any image can have either 1 band or n bands, where n is the same for all * the non-1-band images. Single band images are then effectively copied to * make n-band images. * * Images @in1 and @in2 are cast up to the smallest common format. @cond is * cast to uchar. * * If the images differ in size, the smaller images are enlarged to match the * largest by adding zero pixels along the bottom and right. * * If @blend is `TRUE`, then values in @out are smoothly blended between @in1 * and @in2 using the formula: * * ``` * out = (cond / 255) * in1 + (1 - cond / 255) * in2 * ``` * * ::: tip "Optional arguments" * * @blend: `gboolean`, blend smoothly between @in1 and @in2 * * ::: seealso * [method@Image.equal]. * * Returns: 0 on success, -1 on error */ int vips_ifthenelse(VipsImage *cond, VipsImage *in1, VipsImage *in2, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("ifthenelse", ap, cond, in1, in2, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/insert.c000066400000000000000000000333401516303661500206000ustar00rootroot00000000000000/* VipsInsert * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 02/08/1990 * Modified on : * 31/8/93 JC * - ANSIfied * - Nicos' reformatting undone. Grr! * 22/12/94 * - modernised * - now does IM_CODING_LABQ too * 22/6/95 JC * - partialized * 10/2/02 JC * - adapted for im_prepare_to() stuff * 14/4/04 * - sets Xoffset / Yoffset * 3/7/06 * - add sanity range checks * 24/3/09 * - added IM_CODING_RAD support * 30/1/10 * - cleanups * - formatalike/bandalike * - gtkdoc * 29/9/11 * - rewrite as a class * - add expand, bg options * 5/11/21 * - add minimise for seq pipelines */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsInsert { VipsConversion parent_instance; /* Params. */ VipsImage *main; VipsImage *sub; int x; int y; gboolean expand; VipsArrayDouble *background; /* Pixel we paint calculated from background. */ VipsPel *ink; /* Inputs cast and banded up, plus a NULL at the end. main is 0, sub * is 1. */ VipsImage *processed[3]; /* Geometry. */ VipsRect rout; /* Output space */ VipsRect rimage[2]; /* Position of input in output */ /* TRUE if we've minimised an input. */ gboolean minimised[2]; } VipsInsert; typedef VipsConversionClass VipsInsertClass; G_DEFINE_TYPE(VipsInsert, vips_insert, VIPS_TYPE_CONVERSION); /* Trivial case: we just need pels from one of the inputs. */ static int vips__insert_just_one(VipsRegion *out_region, VipsRegion *ir, int x, int y) { VipsRect need; /* Find the part of pos we need. */ need = out_region->valid; need.left -= x; need.top -= y; if (vips_region_prepare(ir, &need)) return -1; /* Attach our output to it. */ if (vips_region_region(out_region, ir, &out_region->valid, need.left, need.top)) return -1; return 0; } /* Paste in parts of ir that fall within out_region -- ir is an input REGION * for an image positioned at pos within out_region. * * Also used by vips_arrayjoin. */ int vips__insert_paste_region(VipsRegion *out_region, VipsRegion *ir, VipsRect *pos) { VipsRect ovl; /* Does any of the sub-image appear in the area we have been asked * to make? */ vips_rect_intersectrect(&out_region->valid, pos, &ovl); if (!vips_rect_isempty(&ovl)) { /* Find the part of in we need. */ ovl.left -= pos->left; ovl.top -= pos->top; /* Paint this area of pixels into out_region. */ if (vips_region_prepare_to(ir, out_region, &ovl, ovl.left + pos->left, ovl.top + pos->top)) return -1; } return 0; } static int vips_insert_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion **ir = (VipsRegion **) seq; VipsRect *r = &out_region->valid; VipsInsert *insert = (VipsInsert *) b; VipsConversion *conversion = VIPS_CONVERSION(insert); int i; /* Three cases: * * 1. If r is entirely within sub, we can just paint from sub. * 2. If r is entirely within main and does not touch sub, we can * paint from main. * 3. We must paint from both, and the background. */ if (vips_rect_includesrect(&insert->rimage[1], r)) { /* Just the subimage. */ if (vips__insert_just_one(out_region, ir[1], insert->rimage[1].left, insert->rimage[1].top)) return -1; } else if (vips_rect_includesrect(&insert->rimage[0], r) && !vips_rect_overlapsrect(&insert->rimage[1], r)) { /* Just the main image. */ if (vips__insert_just_one(out_region, ir[0], insert->rimage[0].left, insert->rimage[0].top)) return -1; } else { /* Output requires both (or neither) input. If it is not * entirely inside both the main and the sub, then there is * going to be some background. */ vips_region_paint_pel(out_region, r, insert->ink); /* Paste the background first. */ for (i = 0; i < 2; i++) if (vips__insert_paste_region(out_region, ir[i], &insert->rimage[i])) return -1; } /* See arrayjoin for almost this code again. Move into conversion.c? */ if (vips_image_is_sequential(conversion->out)) for (i = 0; i < 2; i++) { int bottom_edge = VIPS_RECT_BOTTOM(&insert->rimage[i]); /* 1024 is a generous margin. 256 is too small. */ if (!insert->minimised[i] && r->top > bottom_edge + 1024) { insert->minimised[i] = TRUE; vips_image_minimise_all(insert->processed[i]); } } return 0; } /* Make a pair of vector constants into a set of formatted pixels. bands can * be 3 while n is 1, meaning expand the constant to the number of bands. * imag can be NULL, meaning all zero for the imaginary component. */ VipsPel * vips__vector_to_pels(const char *domain, int bands, VipsBandFormat format, VipsCoding coding, double *real, double *imag, int n) { /* Run our pipeline relative to this. */ VipsImage *context = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(context), 8); VipsImage *in; double *ones; VipsPel *result; int i; #ifdef VIPS_DEBUG printf("vips__vector_to_pels: starting\n"); #endif /*VIPS_DEBUG*/ ones = VIPS_ARRAY(context, n, double); for (i = 0; i < n; i++) ones[i] = 1.0; /* Make the real and imaginary parts. */ if (vips_black(&t[0], 1, 1, "bands", bands, NULL) || vips_linear(t[0], &t[1], ones, real, n, NULL)) { g_object_unref(context); return NULL; } in = t[1]; if (imag) { if (vips_black(&t[2], 1, 1, "bands", bands, NULL) || vips_linear(t[2], &t[3], ones, imag, n, NULL) || vips_complexform(in, t[3], &t[4], NULL)) { g_object_unref(context); return NULL; } in = t[4]; } /* Cast to the output type and coding. */ if (vips_cast(in, &t[5], format, NULL) || vips_image_encode(t[5], &t[6], coding)) { g_object_unref(context); return NULL; } in = t[6]; /* Write to memory, copy to output buffer. */ vips_image_set_int(in, "hide-progress", 1); if (!(t[7] = vips_image_new_memory()) || vips_image_write(in, t[7])) { g_object_unref(context); return NULL; } in = t[7]; if (!(result = VIPS_ARRAY(NULL, VIPS_IMAGE_SIZEOF_PEL(in), VipsPel))) { g_object_unref(context); return NULL; } memcpy(result, in->data, VIPS_IMAGE_SIZEOF_PEL(in)); #ifdef VIPS_DEBUG { int i; printf("vips__vector_to_ink:\n"); printf("\t(real, imag) = "); for (i = 0; i < n; i++) printf("(%g, %g) ", real[i], imag ? imag[i] : 0); printf("\n"); printf("\tink = "); for (i = 0; i < VIPS_IMAGE_SIZEOF_PEL(in); i++) printf("%d ", result[i]); printf("\n"); } #endif /*VIPS_DEBUG*/ g_object_unref(context); return result; } static void vips__vector_to_ink_cb(VipsObject *object, char *buf) { g_free(buf); } /* Calculate a pixel for an image from a vec of double. Valid while im is * valid. */ VipsPel * vips__vector_to_ink(const char *domain, VipsImage *im, double *real, double *imag, int n) { int bands; VipsBandFormat format; VipsPel *result; vips_image_decode_predict(im, &bands, &format); if (!(result = vips__vector_to_pels(domain, bands, format, im->Coding, real, imag, n))) return NULL; g_signal_connect(im, "postclose", G_CALLBACK(vips__vector_to_ink_cb), result); return result; } static int vips_insert_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsInsert *insert = (VipsInsert *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); if (VIPS_OBJECT_CLASS(vips_insert_parent_class)->build(object)) return -1; if (vips_image_pio_input(insert->main) || vips_image_pio_input(insert->sub) || vips_check_bands_1orn(class->nickname, insert->main, insert->sub) || vips_check_coding_known(class->nickname, insert->main) || vips_check_coding_same(class->nickname, insert->main, insert->sub)) return -1; /* Cast our input images up to a common format and bands. */ if (vips__formatalike(insert->main, insert->sub, &t[0], &t[1]) || vips__bandalike(class->nickname, t[0], t[1], &t[2], &t[3])) return -1; insert->processed[0] = t[2]; insert->processed[1] = t[3]; /* Joins can get very wide (eg. consider joining a set of tiles * horizontally to make a large image), we don't want mem use to shoot * up. SMALLTILE will guarantee we keep small and local. */ if (vips_image_pipeline_array(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, insert->processed)) return -1; /* Calculate geometry. */ insert->rimage[0].left = 0; insert->rimage[0].top = 0; insert->rimage[0].width = insert->processed[0]->Xsize; insert->rimage[0].height = insert->processed[0]->Ysize; insert->rimage[1].left = insert->x; insert->rimage[1].top = insert->y; insert->rimage[1].width = insert->processed[1]->Xsize; insert->rimage[1].height = insert->processed[1]->Ysize; if (insert->expand) { /* Expand output to bounding box of these two. */ vips_rect_unionrect(&insert->rimage[0], &insert->rimage[1], &insert->rout); /* Translate origin to top LH corner of rout. */ insert->rimage[0].left -= insert->rout.left; insert->rimage[0].top -= insert->rout.top; insert->rimage[1].left -= insert->rout.left; insert->rimage[1].top -= insert->rout.top; insert->rout.left = 0; insert->rout.top = 0; } else insert->rout = insert->rimage[0]; conversion->out->Xsize = insert->rout.width; conversion->out->Ysize = insert->rout.height; if (!(insert->ink = vips__vector_to_ink( class->nickname, conversion->out, (double *) VIPS_ARRAY_ADDR(insert->background, 0), NULL, VIPS_AREA(insert->background)->n))) return -1; if (vips_image_generate(conversion->out, vips_start_many, vips_insert_gen, vips_stop_many, insert->processed, insert)) return -1; return 0; } static void vips_insert_class_init(VipsInsertClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_insert_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "insert"; vobject_class->description = _("insert image @sub into @main at @x, @y"); vobject_class->build = vips_insert_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "main", 0, _("Main"), _("Main input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsInsert, main)); VIPS_ARG_IMAGE(class, "sub", 1, _("Sub-image"), _("Sub-image to insert into main image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsInsert, sub)); VIPS_ARG_INT(class, "x", 3, _("X"), _("Left edge of sub in main"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsInsert, x), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "y", 4, _("Y"), _("Top edge of sub in main"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsInsert, y), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_BOOL(class, "expand", 5, _("Expand"), _("Expand output to hold all of both inputs"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsInsert, expand), FALSE); VIPS_ARG_BOXED(class, "background", 6, _("Background"), _("Color for new pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsInsert, background), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_insert_init(VipsInsert *insert) { /* Init our instance fields. */ insert->background = vips_array_double_newv(1, 0.0); } /** * vips_insert: (method) * @main: big image * @sub: small image * @out: (out): output image * @x: left position of @sub * @y: top position of @sub * @...: `NULL`-terminated list of optional named arguments * * Insert @sub into @main at position @x, @y. * * Normally @out shows the whole of @main. If @expand is `TRUE` then @out is * made large enough to hold all of @main and @sub. * Any areas of @out not coming from * either @main or @sub are set to @background (default 0). * * If @sub overlaps @main, * @sub will appear on top of @main. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * ::: tip "Optional arguments" * * @expand: `gdouble`, expand output to hold whole of both images * * @background: [struct@ArrayDouble], colour for new pixels * * ::: seealso * [method@Image.join], [method@Image.embed], [method@Image.extract_area]. * * Returns: 0 on success, -1 on error */ int vips_insert(VipsImage *main, VipsImage *sub, VipsImage **out, int x, int y, ...) { va_list ap; int result; va_start(ap, y); result = vips_call_split("insert", ap, main, sub, out, x, y); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/join.c000066400000000000000000000177651516303661500202500ustar00rootroot00000000000000/* join left-right and up-down * * Copyright 1990, 1991: Kirk Martinez, N. Dessipris * Author: Kirk Martinez, N. Dessipris * Written on: 9/6/90 * Modified on: 17/04/1991 * 31/8/93 JC * - args to memcpy() were reversed * 14/11/94 JC * - tided up and ANSIfied * - now accepts IM_CODING_LABQ * - memory leaks removed * - bug in calculation of output Xsize removed (thanks Thomson!) * - bug in checking of image compatibility fixed * 23/10/95 JC * - rewritten in terms of im_insert() * 14/4/04 * - sets Xoffset / Yoffset * 1/2/10 * - gtkdoc * - cleanups * 19/10/11 * - redone as a class * 25/8/17 * - tag as sequential */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsJoin { VipsConversion parent_instance; /* Params. */ VipsImage *in1; VipsImage *in2; VipsDirection direction; gboolean expand; int shim; VipsArrayDouble *background; VipsAlign align; } VipsJoin; typedef VipsConversionClass VipsJoinClass; G_DEFINE_TYPE(VipsJoin, vips_join, VIPS_TYPE_CONVERSION); static int vips_join_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsJoin *join = (VipsJoin *) object; int x, y; VipsImage *t; if (VIPS_OBJECT_CLASS(vips_join_parent_class)->build(object)) return -1; /* Stop compiler warnings. */ x = 0; y = 0; switch (join->direction) { case VIPS_DIRECTION_HORIZONTAL: x = join->in1->Xsize + join->shim; switch (join->align) { case VIPS_ALIGN_LOW: y = 0; break; case VIPS_ALIGN_CENTRE: y = join->in1->Ysize / 2 - join->in2->Ysize / 2; break; case VIPS_ALIGN_HIGH: y = join->in1->Ysize - join->in2->Ysize; break; default: g_assert_not_reached(); } break; case VIPS_DIRECTION_VERTICAL: y = join->in1->Ysize + join->shim; switch (join->align) { case VIPS_ALIGN_LOW: x = 0; break; case VIPS_ALIGN_CENTRE: x = join->in1->Xsize / 2 - join->in2->Xsize / 2; break; case VIPS_ALIGN_HIGH: x = join->in1->Xsize - join->in2->Xsize; break; default: g_assert_not_reached(); } break; default: g_assert_not_reached(); } if (vips_insert(join->in1, join->in2, &t, x, y, "expand", TRUE, "background", join->background, NULL)) return -1; if (!join->expand) { VipsImage *t2; int left, top, width, height; switch (join->direction) { case VIPS_DIRECTION_HORIZONTAL: left = 0; top = VIPS_MAX(0, y) - y; width = t->Xsize; height = VIPS_MIN(join->in1->Ysize, join->in2->Ysize); break; case VIPS_DIRECTION_VERTICAL: left = VIPS_MAX(0, x) - x; top = 0; width = VIPS_MIN(join->in1->Xsize, join->in2->Xsize); height = t->Ysize; break; default: g_assert_not_reached(); /* Stop compiler warnings. */ left = 0; top = 0; width = 0; height = 0; } if (left != 0 || top != 0 || width != t->Xsize || height != t->Ysize) { if (vips_extract_area(t, &t2, left, top, width, height, NULL)) { g_object_unref(t); return -1; } g_object_unref(t); t = t2; } } if (vips_image_write(t, conversion->out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static void vips_join_class_init(VipsJoinClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_join_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "join"; vobject_class->description = _("join a pair of images"); vobject_class->build = vips_join_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in1", 0, _("in1"), _("First input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsJoin, in1)); VIPS_ARG_IMAGE(class, "in2", 1, _("in2"), _("Second input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsJoin, in2)); VIPS_ARG_ENUM(class, "direction", 3, _("Direction"), _("Join left-right or up-down"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsJoin, direction), VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL); VIPS_ARG_BOOL(class, "expand", 4, _("Expand"), _("Expand output to hold all of both inputs"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsJoin, expand), FALSE); VIPS_ARG_INT(class, "shim", 5, _("Shim"), _("Pixels between images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsJoin, shim), 0, 1000000, 0); VIPS_ARG_BOXED(class, "background", 6, _("Background"), _("Colour for new pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsJoin, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_ENUM(class, "align", 7, _("Align"), _("Align on the low, centre or high coordinate edge"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsJoin, align), VIPS_TYPE_ALIGN, VIPS_ALIGN_LOW); } static void vips_join_init(VipsJoin *join) { join->background = vips_array_double_newv(1, 0.0); } /** * vips_join: (method) * @in1: first input image * @in2: second input image * @out: (out): output image * @direction: join horizontally or vertically * @...: `NULL`-terminated list of optional named arguments * * Join @in1 and @in2 together, left-right or up-down depending on the value * of @direction. * * If one is taller or wider than the * other, @out will be has high as the smaller. If @expand is `TRUE`, then * the output will be expanded to contain all of the input pixels. * * Use @align to set the edge that the images align on. By default, they align * on the edge with the lower value coordinate. * * Use @background to set the colour of any pixels in @out which are not * present in either @in1 or @in2. * * Use @shim to set the spacing between the images. By default this is 0. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * If you are going to be joining many thousands of images in a regular * grid, [func@Image.arrayjoin] is a better choice. * * ::: tip "Optional arguments" * * @expand: `gboolean`, `TRUE` to expand the output image to hold all of * the input pixels * * @shim: `gint`, space between images, in pixels * * @background: [struct@ArrayDouble], background ink colour * * @align: [enumAlign], low, centre or high alignment * * ::: seealso * [func@Image.arrayjoin], [method@Image.insert]. * * Returns: 0 on success, -1 on error */ int vips_join(VipsImage *in1, VipsImage *in2, VipsImage **out, VipsDirection direction, ...) { va_list ap; int result; va_start(ap, direction); result = vips_call_split("join", ap, in1, in2, out, direction); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/meson.build000066400000000000000000000020511516303661500212650ustar00rootroot00000000000000conversion_sources = files( 'switch.c', 'transpose3d.c', 'composite.cpp', 'smartcrop.c', 'conversion.c', 'tilecache.c', 'gamma.c', 'sequential.c', 'flatten.c', 'premultiply.c', 'unpremultiply.c', 'byteswap.c', 'cache.c', 'copy.c', 'embed.c', 'flip.c', 'insert.c', 'join.c', 'arrayjoin.c', 'extract.c', 'replicate.c', 'cast.c', 'bandjoin.c', 'bandrank.c', 'recomb.c', 'bandmean.c', 'bandfold.c', 'bandunfold.c', 'bandbool.c', 'bandary.c', 'rot.c', 'rot45.c', 'autorot.c', 'ifthenelse.c', 'falsecolour.c', 'msb.c', 'grid.c', 'scale.c', 'wrap.c', 'subsample.c', 'zoom.c', 'addalpha.c', ) conversion_headers = files( 'pconversion.h', 'bandary.h', ) libvips_sources += conversion_sources conversion_lib = static_library('conversion', conversion_sources, conversion_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += conversion_lib libvips-8.18.2/libvips/conversion/msb.c000066400000000000000000000151251516303661500200560ustar00rootroot00000000000000/* vips_msb() * * Copyright: 2006, The Nottingham Trent University * * Author: Tom Vajzovic * * Written on: 2006-03-13 * 27/9/06 * - removed extra im_free() in im_copy() fallback * 4/10/06 * - removed warning on uchar fallback: it happens a lot with nip2 and * isn't very serious * 1/2/10 * - revised, cleanups * - gtkdoc * 30/5/13 * - rewrite as a class * - add --band option, remove im_msb_band() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H */ #include #include #include "pconversion.h" #include "bandary.h" typedef struct _VipsMsb { VipsConversion parent_instance; /* Params. */ VipsImage *in; int band; /* Initial input offset. */ int offset; /* Input step. */ int instep; /* Need to convert signed to unsgned. */ gboolean sign; } VipsMsb; typedef VipsConversionClass VipsMsbClass; G_DEFINE_TYPE(VipsMsb, vips_msb, VIPS_TYPE_CONVERSION); static int vips_msb_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsMsb *msb = (VipsMsb *) b; VipsConversion *conversion = (VipsConversion *) msb; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int sz = r->width * conversion->out->Bands; int x, y, i; if (vips_region_prepare(ir, r)) return -1; for (y = to; y < bo; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, le, y); VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); if (msb->in->Coding == VIPS_CODING_LABQ && msb->band == -1) { /* LABQ, no sub-band select. */ for (x = 0; x < r->width; x++) { q[0] = p[0]; q[1] = 0x80 ^ p[1]; q[2] = 0x80 ^ p[2]; q += 4; p += 3; } } else if (msb->sign) { /* Copy, converting signed to unsigned. */ p += msb->offset; for (i = 0; i < sz; i++) { q[i] = 0x80 ^ *p; p += msb->instep; } } else { /* Just pick out bytes. */ p += msb->offset; for (i = 0; i < sz; i++) { q[i] = *p; p += msb->instep; } } } return 0; } static int vips_msb_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = (VipsConversion *) object; VipsMsb *msb = (VipsMsb *) object; int vbands; if (VIPS_OBJECT_CLASS(vips_msb_parent_class)->build(object)) return -1; if (vips_check_coding_noneorlabq(class->nickname, msb->in) || vips_check_int(class->nickname, msb->in)) return -1; /* Effective number of bands this image has. */ vbands = msb->in->Coding == VIPS_CODING_LABQ ? 3 : msb->in->Bands; if (msb->band > vbands - 1) { vips_error(class->nickname, "%s", _("bad band")); return -1; } /* Step to next input element. */ msb->instep = VIPS_IMAGE_SIZEOF_ELEMENT(msb->in); /* Offset into first band element of high order byte. */ msb->offset = vips_amiMSBfirst() ? 0 : VIPS_IMAGE_SIZEOF_ELEMENT(msb->in) - 1; /* If we're picking out a band, they need scaling up. */ if (msb->band != -1) { msb->offset += VIPS_IMAGE_SIZEOF_ELEMENT(msb->in) * msb->band; msb->instep *= msb->in->Bands; } /* May need to flip sign if we're picking out a band from labq. */ if (msb->in->Coding == VIPS_CODING_LABQ && msb->band > 0) msb->sign = TRUE; if (msb->in->Coding == VIPS_CODING_NONE && !vips_band_format_isuint(msb->in->BandFmt)) msb->sign = TRUE; if (msb->band == -1 && msb->in->BandFmt == VIPS_FORMAT_UCHAR) return vips_image_write(msb->in, conversion->out); if (msb->band == 0 && msb->in->Bands == 1 && msb->in->BandFmt == VIPS_FORMAT_UCHAR) return vips_image_write(msb->in, conversion->out); if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, msb->in, NULL)) return -1; if (msb->band != -1) conversion->out->Bands = 1; else conversion->out->Bands = vbands; conversion->out->BandFmt = VIPS_FORMAT_UCHAR; conversion->out->Coding = VIPS_CODING_NONE; if (conversion->out->Bands == 1) conversion->out->Type = VIPS_INTERPRETATION_B_W; else conversion->out->Type = VIPS_INTERPRETATION_MULTIBAND; if (vips_image_generate(conversion->out, vips_start_one, vips_msb_gen, vips_stop_one, msb->in, msb)) return -1; return 0; } static void vips_msb_class_init(VipsMsbClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "msb"; vobject_class->description = _("pick most-significant byte from an image"); vobject_class->build = vips_msb_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMsb, in)); VIPS_ARG_INT(class, "band", 3, _("Band"), _("Band to msb"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMsb, band), -1, 100000000, -1); } static void vips_msb_init(VipsMsb *msb) { msb->band = -1; } /** * vips_msb: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Turn any integer image to 8-bit unsigned char by discarding all but the most * significant byte. Signed values are converted to unsigned by adding 128. * * Use @band to make a one-band 8-bit image. * * This operator also works for LABQ coding. * * ::: tip "Optional arguments" * * @band: `gint`, msb just this band * * ::: seealso * [method@Image.scale], [method@Image.cast]. * * Returns: 0 on success, -1 on error. */ int vips_msb(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("msb", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/pconversion.h000066400000000000000000000036641516303661500216540ustar00rootroot00000000000000/* base class for all conversion operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PCONVERSION_H #define VIPS_PCONVERSION_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_CONVERSION (vips_conversion_get_type()) #define VIPS_CONVERSION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_CONVERSION, VipsConversion)) #define VIPS_CONVERSION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_CONVERSION, VipsConversionClass)) #define VIPS_IS_CONVERSION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_CONVERSION)) #define VIPS_IS_CONVERSION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_CONVERSION)) #define VIPS_CONVERSION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_CONVERSION, VipsConversionClass)) typedef struct _VipsConversion { VipsOperation parent_instance; /* All have an output image. */ VipsImage *out; } VipsConversion; typedef struct _VipsConversionClass { VipsOperationClass parent_class; } VipsConversionClass; GType vips_conversion_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PCONVERSION_H*/ libvips-8.18.2/libvips/conversion/premultiply.c000066400000000000000000000170341516303661500216640ustar00rootroot00000000000000/* premultiply alpha * * Author: John Cupitt * Written on: 7/5/15 * * 11/4/16 Lovell * - fix RGBA path * 25/5/16 * - max_alpha defaults to 65535 for RGB16/GREY16 * 24/11/17 lovell * - match normalised alpha to output type */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsPremultiply { VipsConversion parent_instance; VipsImage *in; double max_alpha; } VipsPremultiply; typedef VipsConversionClass VipsPremultiplyClass; G_DEFINE_TYPE(VipsPremultiply, vips_premultiply, VIPS_TYPE_CONVERSION); /* Premultiply an n-band image. */ #define PRE_MANY(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) { \ IN alpha = p[bands - 1]; \ IN clip_alpha = VIPS_CLIP(0, alpha, max_alpha); \ OUT nalpha = (OUT) clip_alpha / max_alpha; \ \ for (i = 0; i < bands - 1; i++) \ q[i] = p[i] * nalpha; \ q[i] = alpha; \ \ p += bands; \ q += bands; \ } \ } /* Special case for RGBA, it's very common. */ #define PRE_RGBA(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) { \ IN alpha = p[3]; \ IN clip_alpha = VIPS_CLIP(0, alpha, max_alpha); \ OUT nalpha = (OUT) clip_alpha / max_alpha; \ \ q[0] = p[0] * nalpha; \ q[1] = p[1] * nalpha; \ q[2] = p[2] * nalpha; \ q[3] = alpha; \ \ p += 4; \ q += 4; \ } \ } #define PRE(IN, OUT) \ { \ if (bands == 4) { \ PRE_RGBA(IN, OUT); \ } \ else { \ PRE_MANY(IN, OUT); \ } \ } VIPS_TARGET_CLONES("default,avx") static int vips_premultiply_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsPremultiply *premultiply = (VipsPremultiply *) b; VipsRegion *ir = (VipsRegion *) vseq; VipsImage *im = ir->im; VipsRect *r = &out_region->valid; int width = r->width; int bands = im->Bands; double max_alpha = premultiply->max_alpha; int x, y, i; if (vips_region_prepare(ir, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *in = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *out = VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: PRE(unsigned char, float); break; case VIPS_FORMAT_CHAR: PRE(signed char, float); break; case VIPS_FORMAT_USHORT: PRE(unsigned short, float); break; case VIPS_FORMAT_SHORT: PRE(signed short, float); break; case VIPS_FORMAT_UINT: PRE(unsigned int, float); break; case VIPS_FORMAT_INT: PRE(signed int, float); break; case VIPS_FORMAT_FLOAT: PRE(float, float); break; case VIPS_FORMAT_DOUBLE: PRE(double, double); break; case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: default: g_assert_not_reached(); } } return 0; } static int vips_premultiply_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsPremultiply *premultiply = (VipsPremultiply *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 1); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_premultiply_parent_class)->build(object)) return -1; in = premultiply->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; /* Trivial case: fall back to copy(). */ if (in->Bands == 1) return vips_image_write(in, conversion->out); if (vips_check_noncomplex(class->nickname, in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; /* Is max-alpha unset? Default to the correct value for this * interpretation. */ if (!vips_object_argument_isset(object, "max_alpha")) premultiply->max_alpha = vips_interpretation_max_alpha(in->Type); // FIXME: Invalidates operation cache if (in->BandFmt == VIPS_FORMAT_DOUBLE) conversion->out->BandFmt = VIPS_FORMAT_DOUBLE; else conversion->out->BandFmt = VIPS_FORMAT_FLOAT; if (vips_image_generate(conversion->out, vips_start_one, vips_premultiply_gen, vips_stop_one, in, premultiply)) return -1; return 0; } static void vips_premultiply_class_init(VipsPremultiplyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_premultiply_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "premultiply"; vobject_class->description = _("premultiply image alpha"); vobject_class->build = vips_premultiply_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPremultiply, in)); VIPS_ARG_DOUBLE(class, "max_alpha", 115, _("Maximum alpha"), _("Maximum value of alpha channel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsPremultiply, max_alpha), 0, 100000000, 255); } static void vips_premultiply_init(VipsPremultiply *premultiply) { premultiply->max_alpha = 255.0; } /** * vips_premultiply: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Premultiplies any alpha channel. * * The final band is taken to be the alpha and the bands are transformed as: * * ``` * alpha = clip(0, in[in.bands - 1], max_alpha) * norm = alpha / max_alpha * out = [in[0] * norm, ..., in[in.bands - 1] * norm, alpha] * ``` * * So for an N-band image, the first N - 1 bands are multiplied by the clipped * and normalised final band, the final band is clipped. * If there is only a single band, * the image is passed through unaltered. * * The result is * [enum@Vips.BandFormat.FLOAT] unless the input format is * [enum@Vips.BandFormat.DOUBLE], in which case the output is double as well. * * @max_alpha has the default value 255, or 65535 for images tagged as * [enum@Vips.Interpretation.RGB16] or [enum@Vips.Interpretation.GREY16], and * 1.0 for images tagged as [enum@Vips.Interpretation.scRGB]. * * Non-complex images only. * * ::: tip "Optional arguments" * * @max_alpha: `gdouble`, maximum value for alpha * * ::: seealso * [method@Image.unpremultiply], [method@Image.flatten]. * * Returns: 0 on success, -1 on error */ int vips_premultiply(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("premultiply", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/recomb.c000066400000000000000000000143161516303661500205450ustar00rootroot00000000000000/* recomb.c ... pass an image though a matrix * * 21/6/95 JC * - mildly modernised * 14/3/96 JC * - better error checks, partial * 4/11/09 * - gtkdoc * 9/11/11 * - redo as a class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsRecomb { VipsConversion parent_instance; VipsImage *in; VipsImage *m; /* Our input matrix as a one-band double. */ VipsImage *coeff; } VipsRecomb; typedef VipsConversionClass VipsRecombClass; G_DEFINE_TYPE(VipsRecomb, vips_recomb, VIPS_TYPE_CONVERSION); /* Inner loop. */ #define LOOP(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < out_region->valid.width; x++) { \ double *restrict m = VIPS_MATRIX(recomb->coeff, 0, 0); \ \ for (v = 0; v < mheight; v++) { \ double t; \ \ t = 0.0; \ \ for (u = 0; u < mwidth; u++) \ t += m[u] * p[u]; \ \ q[v] = (OUT) t; \ m += mwidth; \ } \ \ p += mwidth; \ q += mheight; \ } \ } static int vips_recomb_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRecomb *recomb = (VipsRecomb *) b; VipsImage *im = recomb->in; int mwidth = recomb->m->Xsize; int mheight = recomb->m->Ysize; int y, x, u, v; if (vips_region_prepare(ir, &out_region->valid)) return -1; for (y = 0; y < out_region->valid.height; y++) { VipsPel *in = VIPS_REGION_ADDR(ir, out_region->valid.left, out_region->valid.top + y); VipsPel *out = VIPS_REGION_ADDR(out_region, out_region->valid.left, out_region->valid.top + y); switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, float); break; case VIPS_FORMAT_CHAR: LOOP(signed char, float); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, float); break; case VIPS_FORMAT_SHORT: LOOP(signed short, float); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, float); break; case VIPS_FORMAT_INT: LOOP(signed int, float); break; case VIPS_FORMAT_FLOAT: LOOP(float, float); break; case VIPS_FORMAT_DOUBLE: LOOP(double, double); break; default: g_assert_not_reached(); } } return 0; } static int vips_recomb_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = (VipsConversion *) object; VipsRecomb *recomb = (VipsRecomb *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_recomb_parent_class)->build(object)) return -1; in = recomb->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (vips_check_noncomplex(class->nickname, in)) return -1; if (vips_image_pio_input(recomb->m) || vips_check_uncoded(class->nickname, recomb->m) || vips_check_noncomplex(class->nickname, recomb->m) || vips_check_mono(class->nickname, recomb->m)) return -1; if (in->Bands != recomb->m->Xsize) { vips_error(class->nickname, "%s", _("bands in must equal matrix width")); return -1; } if (vips_check_matrix(class->nickname, recomb->m, &t[1])) return -1; recomb->coeff = t[1]; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; conversion->out->Bands = recomb->m->Ysize; if (vips_band_format_isint(in->BandFmt)) conversion->out->BandFmt = VIPS_FORMAT_FLOAT; if (vips_image_generate(conversion->out, vips_start_one, vips_recomb_gen, vips_stop_one, in, recomb)) return -1; return 0; } static void vips_recomb_class_init(VipsRecombClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "recomb"; object_class->description = _("linear recombination with matrix"); object_class->build = vips_recomb_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRecomb, in)); VIPS_ARG_IMAGE(class, "m", 102, _("M"), _("Matrix of coefficients"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRecomb, m)); } static void vips_recomb_init(VipsRecomb *recomb) { } /** * vips_recomb: (method) * @in: input image * @out: (out): output image * @m: recombination matrix * @...: `NULL`-terminated list of optional named arguments * * This operation recombines an image's bands. Each pixel in @in is treated as * an n-element vector, where n is the number of bands in @in, and multiplied by * the n x m matrix @m to produce the m-band image @out. * * @out is always float, unless @in is double, in which case @out is double * too. No complex images allowed. * * It's useful for various sorts of colour space conversions. * * ::: seealso * [method@Image.bandmean]. * * Returns: 0 on success, -1 on error */ int vips_recomb(VipsImage *in, VipsImage **out, VipsImage *m, ...) { va_list ap; int result; va_start(ap, m); result = vips_call_split("recomb", ap, in, out, m); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/replicate.c000066400000000000000000000125701516303661500212460ustar00rootroot00000000000000/* replicate an image x times horizontally and vertically * * JC, 30 sep 03 * * 15/4/04 * - some optimisations for some cases * 1/2/10 * - gtkdoc * 26/10/11 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsReplicate { VipsConversion parent_instance; /* The input image. */ VipsImage *in; int across; int down; } VipsReplicate; typedef VipsConversionClass VipsReplicateClass; G_DEFINE_TYPE(VipsReplicate, vips_replicate, VIPS_TYPE_CONVERSION); static int vips_replicate_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsImage *in = (VipsImage *) a; VipsRect *r = &out_region->valid; int twidth = in->Xsize; int theight = in->Ysize; int x, y; VipsRect tile; /* Find top left of tiles we need. */ int xs = (r->left / twidth) * twidth; int ys = (r->top / theight) * theight; /* The tile enclosing the top-left corner of the requested area. */ tile.left = xs; tile.top = ys; tile.width = twidth; tile.height = theight; /* If the request fits inside a single tile, we can just pointer-copy. */ if (vips_rect_includesrect(&tile, r)) { VipsRect irect; /* Translate request to input space. */ irect = *r; irect.left -= xs; irect.top -= ys; if (vips_region_prepare(ir, &irect)) return -1; if (vips_region_region(out_region, ir, r, irect.left, irect.top)) return -1; return 0; } for (y = ys; y < VIPS_RECT_BOTTOM(r); y += theight) for (x = xs; x < VIPS_RECT_RIGHT(r); x += twidth) { VipsRect paint; /* Whole tile at x, y */ tile.left = x; tile.top = y; tile.width = twidth; tile.height = theight; /* Which parts touch the area of the output we are * building. */ vips_rect_intersectrect(&tile, r, &paint); /* Translate back to ir coordinates. */ paint.left -= x; paint.top -= y; g_assert(!vips_rect_isempty(&paint)); /* Render into out_region. */ if (vips_region_prepare_to(ir, out_region, &paint, paint.left + x, paint.top + y)) return -1; } return 0; } static int vips_replicate_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsReplicate *replicate = (VipsReplicate *) object; if (VIPS_OBJECT_CLASS(vips_replicate_parent_class)->build(object)) return -1; if (vips_image_pio_input(replicate->in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, replicate->in, NULL)) return -1; conversion->out->Xsize *= replicate->across; conversion->out->Ysize *= replicate->down; if (vips_image_generate(conversion->out, vips_start_one, vips_replicate_gen, vips_stop_one, replicate->in, replicate)) return -1; return 0; } static void vips_replicate_class_init(VipsReplicateClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_replicate_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "replicate"; vobject_class->description = _("replicate an image"); vobject_class->build = vips_replicate_build; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReplicate, in)); VIPS_ARG_INT(class, "across", 4, _("Across"), _("Repeat this many times horizontally"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReplicate, across), 1, 1000000, 1); VIPS_ARG_INT(class, "down", 5, _("Down"), _("Repeat this many times vertically"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReplicate, down), 1, 1000000, 1); } static void vips_replicate_init(VipsReplicate *replicate) { } /** * vips_replicate: (method) * @in: input image * @out: (out): output image * @across: repeat input this many times across * @down: repeat input this many times down * @...: `NULL`-terminated list of optional named arguments * * Repeats an image many times. * * ::: seealso * [method@Image.extract_area]. * * Returns: 0 on success, -1 on error */ int vips_replicate(VipsImage *in, VipsImage **out, int across, int down, ...) { va_list ap; int result; va_start(ap, down); result = vips_call_split("replicate", ap, in, out, across, down); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/rot.c000066400000000000000000000235441516303661500201050ustar00rootroot00000000000000/* rotate by 0/90/180/270 degrees * * Copyright: 1991, N. Dessipris * Written on: 28/10/91 * Updated on: 2/4/92, J.Cupitt * bugs in im_la90rot fixed, now works for any type. * 19/7/93 JC * - IM_CODING_LABQ allowed now * 15/11/94 JC * - name changed * - memory leaks fixed * 8/2/95 JC * - oops! memory allocation problem fixed * 18/5/95 JC * - IM_MAXLINES increased * 13/8/96 JC * - rewritten for partials * 6/11/02 JC * - speed-up ... replace memcpy() with a loop for small pixels * 14/4/04 * - sets Xoffset / Yoffset * 24/3/09 * - added IM_CODING_RAD support * 1/2/10 * - cleanups * - gtkdoc * 4/11/11 * - rewrite as a class * 7/3/17 * - added 90/180/270 convenience functions * 10/11/22 alantudyk * - swapped memcpy() in d180 for a loop */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsRot { VipsConversion parent_instance; /* The input image. */ VipsImage *in; /* Rotate by ... */ VipsAngle angle; } VipsRot; typedef VipsConversionClass VipsRotClass; G_DEFINE_TYPE(VipsRot, vips_rot, VIPS_TYPE_CONVERSION); static int vips_rot90_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsImage *in = (VipsImage *) a; /* Output area. */ VipsRect *r = &out_region->valid; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int x, y, i; /* Pixel geometry. */ int ps, ls; /* Find the area of the input image we need. */ VipsRect need; need.left = to; need.top = in->Ysize - ri; need.width = r->height; need.height = r->width; if (vips_region_prepare(ir, &need)) return -1; /* Find PEL size and line skip for ir. */ ps = VIPS_IMAGE_SIZEOF_PEL(in); ls = VIPS_REGION_LSKIP(ir); /* Rotate the bit we now have. */ for (y = to; y < bo; y++) { /* Start of this output line. */ VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); /* Corresponding position in ir. */ VipsPel *p = VIPS_REGION_ADDR(ir, need.left + y - to, need.top + need.height - 1); for (x = le; x < ri; x++) { for (i = 0; i < ps; i++) q[i] = p[i]; q += ps; p -= ls; } } return 0; } static int vips_rot180_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsImage *in = (VipsImage *) a; /* Output area. */ VipsRect *r = &out_region->valid; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int x, y, i; /* Pixel geometry. */ int ps; /* Find the area of the input image we need. */ VipsRect need; need.left = in->Xsize - ri; need.top = in->Ysize - bo; need.width = r->width; need.height = r->height; if (vips_region_prepare(ir, &need)) return -1; /* Find PEL size and line skip for ir. */ ps = VIPS_IMAGE_SIZEOF_PEL(in); /* Rotate the bit we now have. */ for (y = to; y < bo; y++) { /* Start of this output line. */ VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); /* Corresponding position in ir. */ VipsPel *p = VIPS_REGION_ADDR(ir, need.left + need.width - 1, need.top + need.height - (y - to) - 1); /* Blap across! */ for (x = le; x < ri; x++) { for (i = 0; i < ps; i++) q[i] = p[i]; q += ps; p -= ps; } } return 0; } static int vips_rot270_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsImage *in = (VipsImage *) a; /* Output area. */ VipsRect *r = &out_region->valid; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int x, y, i; /* Pixel geometry. */ int ps, ls; /* Find the area of the input image we need. */ VipsRect need; need.left = in->Xsize - bo; need.top = le; need.width = r->height; need.height = r->width; if (vips_region_prepare(ir, &need)) return -1; /* Find PEL size and line skip for ir. */ ps = VIPS_IMAGE_SIZEOF_PEL(in); ls = VIPS_REGION_LSKIP(ir); /* Rotate the bit we now have. */ for (y = to; y < bo; y++) { /* Start of this output line. */ VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); /* Corresponding position in ir. */ VipsPel *p = VIPS_REGION_ADDR(ir, need.left + need.width - (y - to) - 1, need.top); for (x = le; x < ri; x++) { for (i = 0; i < ps; i++) q[i] = p[i]; q += ps; p += ls; } } return 0; } static int vips_rot_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsRot *rot = (VipsRot *) object; VipsImage *in; VipsGenerateFn generate_fn; VipsDemandStyle hint; if (VIPS_OBJECT_CLASS(vips_rot_parent_class)->build(object)) return -1; in = rot->in; if (rot->angle == VIPS_ANGLE_D0) return vips_image_write(in, conversion->out); if (vips_image_pio_input(in)) return -1; hint = rot->angle == VIPS_ANGLE_D180 ? VIPS_DEMAND_STYLE_THINSTRIP : VIPS_DEMAND_STYLE_SMALLTILE; if (vips_image_pipelinev(conversion->out, hint, in, NULL)) return -1; switch (rot->angle) { case VIPS_ANGLE_D90: generate_fn = vips_rot90_gen; conversion->out->Xsize = in->Ysize; conversion->out->Ysize = in->Xsize; conversion->out->Xoffset = in->Ysize; conversion->out->Yoffset = 0; break; case VIPS_ANGLE_D180: generate_fn = vips_rot180_gen; conversion->out->Xoffset = in->Xsize; conversion->out->Yoffset = in->Ysize; break; case VIPS_ANGLE_D270: generate_fn = vips_rot270_gen; conversion->out->Xsize = in->Ysize; conversion->out->Ysize = in->Xsize; conversion->out->Xoffset = 0; conversion->out->Yoffset = in->Xsize; break; default: g_assert_not_reached(); /* Stop compiler warnings. */ generate_fn = NULL; } if (vips_image_generate(conversion->out, vips_start_one, generate_fn, vips_stop_one, in, rot)) return -1; return 0; } static void vips_rot_class_init(VipsRotClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_rot_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "rot"; vobject_class->description = _("rotate an image"); vobject_class->build = vips_rot_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRot, in)); VIPS_ARG_ENUM(class, "angle", 6, _("Angle"), _("Angle to rotate image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRot, angle), VIPS_TYPE_ANGLE, VIPS_ANGLE_D90); } static void vips_rot_init(VipsRot *rot) { } static int vips_rotv(VipsImage *in, VipsImage **out, VipsAngle angle, va_list ap) { return vips_call_split("rot", ap, in, out, angle); } /** * vips_rot: (method) * @in: input image * @out: (out): output image * @angle: rotation angle * @...: `NULL`-terminated list of optional named arguments * * Rotate @in by a multiple of 90 degrees. * * Use [method@Image.similarity] to rotate by an arbitrary angle. * [method@Image.rot45] is useful for rotating convolution masks by 45 degrees. * * ::: seealso * [method@Image.flip], [method@Image.similarity], [method@Image.rot45]. * * Returns: 0 on success, -1 on error */ int vips_rot(VipsImage *in, VipsImage **out, VipsAngle angle, ...) { va_list ap; int result; va_start(ap, angle); result = vips_rotv(in, out, angle, ap); va_end(ap); return result; } /** * vips_rot90: (method) * @in: input image * @out: output image * @...: `NULL`-terminated list of optional named arguments * * Rotate @in by 90 degrees clockwise. A convenience function over [method@Image.rot]. * * ::: seealso * [method@Image.rot]. * * Returns: 0 on success, -1 on error */ int vips_rot90(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_rotv(in, out, VIPS_ANGLE_D90, ap); va_end(ap); return result; } /** * vips_rot180: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Rotate @in by 180 degrees. A convenience function over [method@Image.rot]. * * ::: seealso * [method@Image.rot]. * * Returns: 0 on success, -1 on error */ int vips_rot180(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_rotv(in, out, VIPS_ANGLE_D180, ap); va_end(ap); return result; } /** * vips_rot270: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Rotate @in by 270 degrees clockwise. A convenience function over [method@Image.rot]. * * ::: seealso * [method@Image.rot]. * * Returns: 0 on success, -1 on error */ int vips_rot270(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_rotv(in, out, VIPS_ANGLE_D270, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/rot45.c000066400000000000000000000153141516303661500202520ustar00rootroot00000000000000/* 'lossless' 45 degree rotate ... odd-sized square images only * * Author: N. Dessipris (Copyright, N. Dessipris 1991) * Written on: 08/05/1991 * Modified on: 28/05/1991 * 12/10/95 JC * - small revisions, needs rewriting really * 7/8/96 JC * - absolutely foul desp code revised * - many bugs and mem leaks fixed * 1/3/99 JC * - oops, fns were not preserving scale and offset * 1/12/10 * - allow any size mask for the 90 degree rot45ates by using im_rot4590(). * 12/10/13 * - rewritten as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsRot45 { VipsConversion parent_instance; /* The input image. */ VipsImage *in; /* Rotate by ... */ VipsAngle45 angle; } VipsRot45; typedef VipsConversionClass VipsRot45Class; G_DEFINE_TYPE(VipsRot45, vips_rot45, VIPS_TYPE_CONVERSION); #define COPY(Q, P) \ { \ VipsPel *q = (Q); \ VipsPel *p = (P); \ int b; \ \ for (b = 0; b < ps; b++) \ q[b] = p[b]; \ } #define ASSIGN(Xout, Yout, Xin, Yin) \ COPY(VIPS_IMAGE_ADDR(out, Xout, Yout), \ VIPS_IMAGE_ADDR(in, Xin, Yin)) #define POINT_TO_TEMP(q, Xin, Yin) \ COPY(q, VIPS_IMAGE_ADDR(in, Xin, Yin)) #define TEMP_TO_POINT(Xout, Yout, p) \ COPY(VIPS_IMAGE_ADDR(out, Xout, Yout), p) /* This can work inplace, ie. in == out is allowed. */ static void vips_rot45_rot45(VipsImage *out, VipsImage *in) { size_t ps = VIPS_IMAGE_SIZEOF_PEL(in); VipsPel *temp = VIPS_ARRAY(in, ps, VipsPel); int size = in->Xsize; int size_2 = size / 2; int x, y; g_assert(in->Xsize == in->Ysize); g_assert(out->Xsize == out->Ysize); g_assert(in->Xsize == out->Xsize); g_assert(in->Xsize % 2 == 1); /* Split the square into 8 triangles. Loop over the top-left one, * reflect to index the others. * * 1 1 2 2 3 * 8 1 2 3 3 * 8 8 x 4 4 * 7 7 6 5 4 * 7 6 6 5 5 * * do the centre separately. */ for (y = 0; y < size_2; y++) for (x = y; x < size_2; x++) { /* Save 1, it goes into 2 at the end. */ POINT_TO_TEMP(temp, x, y); /* Fill 1 from 8. */ ASSIGN(x, y, y, size_2 - (x - y)); /* 8 from 7. */ ASSIGN(y, size_2 - (x - y), y, (size - 1) - x); /* 7 from 6. */ ASSIGN(y, (size - 1) - x, size_2 - (x - y), (size - 1) - y); /* 6 from 5. */ ASSIGN(size_2 - (x - y), (size - 1) - y, (size - 1) - x, (size - 1) - y); /* 5 from 4. */ ASSIGN((size - 1) - x, (size - 1) - y, (size - 1) - y, (x - y) + size_2); /* 4 from 3. */ ASSIGN((size - 1) - y, (x - y) + size_2, (size - 1) - y, x); /* 3 from 2. */ ASSIGN((size - 1) - y, x, (x - y) + size_2, y); /* 2 from saved 1. */ TEMP_TO_POINT((x - y) + size_2, y, temp); } /* Centre. */ ASSIGN(size_2, size_2, size_2, size_2); } static int vips_rot45_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsRot45 *rot45 = (VipsRot45 *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_rot45_parent_class)->build(object)) return -1; if (vips_check_oddsquare(class->nickname, rot45->in)) return -1; if (rot45->angle == VIPS_ANGLE45_D0) return vips_image_write(rot45->in, conversion->out); if (!(t[1] = vips_image_copy_memory(rot45->in))) return -1; in = t[1]; t[0] = vips_image_new_memory(); if (vips_image_pipelinev(t[0], VIPS_DEMAND_STYLE_ANY, rot45->in, NULL)) return -1; if (vips_image_write_prepare(t[0])) return -1; switch (rot45->angle) { case VIPS_ANGLE45_D315: vips_rot45_rot45(t[0], in); in = t[0]; case VIPS_ANGLE45_D270: vips_rot45_rot45(t[0], in); in = t[0]; case VIPS_ANGLE45_D225: vips_rot45_rot45(t[0], in); in = t[0]; case VIPS_ANGLE45_D180: vips_rot45_rot45(t[0], in); in = t[0]; case VIPS_ANGLE45_D135: vips_rot45_rot45(t[0], in); in = t[0]; case VIPS_ANGLE45_D90: vips_rot45_rot45(t[0], in); in = t[0]; case VIPS_ANGLE45_D45: vips_rot45_rot45(t[0], in); in = t[0]; break; default: g_assert_not_reached(); } if (vips_image_write(in, conversion->out)) return -1; return 0; } static void vips_rot45_class_init(VipsRot45Class *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_rot45_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "rot45"; vobject_class->description = _("rotate an image"); vobject_class->build = vips_rot45_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRot45, in)); VIPS_ARG_ENUM(class, "angle", 6, _("Angle"), _("Angle to rotate image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsRot45, angle), VIPS_TYPE_ANGLE45, VIPS_ANGLE45_D45); } static void vips_rot45_init(VipsRot45 *rot45) { rot45->angle = VIPS_ANGLE45_D45; } /** * vips_rot45: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Rotate @in by a multiple of 45 degrees. Odd-length sides and square images * only. * * This operation is useful for rotating convolution masks. Use * [method@Image.similarity] to rotate images by arbitrary angles. * * ::: tip "Optional arguments" * * @angle: [enum@Angle45], rotation angle * * ::: seealso * [method@Image.rot], [method@Image.similarity]. * * Returns: 0 on success, -1 on error */ int vips_rot45(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("rot45", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/scale.c000066400000000000000000000115471516303661500203700ustar00rootroot00000000000000/* im_scale * * Author: John Cupitt * Written on: 22/4/93 * Modified on: * 30/6/93 JC * - adapted for partial v2 * - ANSI * 31/8/93 JC * - calculation of offset now includes scale * 8/5/06 * - set Type on output too * 16/10/06 * - what? no, don't set Type, useful to be able to scale histograms, for * example * 1/2/10 * - gtkdoc * 30/5/13 * - redo as a class * - add log scale and exponent as an option * 14/1/14 * - use linear uchar mode * 14/7/14 * - round to nearest on uchar output * 29/12/18 kleisauke * - ... and round to nearest in log mode too */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconversion.h" typedef struct _VipsScale { VipsConversion parent_instance; VipsImage *in; gboolean log; double exp; } VipsScale; typedef VipsConversionClass VipsScaleClass; G_DEFINE_TYPE(VipsScale, vips_scale, VIPS_TYPE_CONVERSION); static int vips_scale_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsScale *scale = (VipsScale *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); double mx; double mn; if (VIPS_OBJECT_CLASS(vips_scale_parent_class)->build(object)) return -1; if (vips_stats(scale->in, &t[0], NULL)) return -1; mn = *VIPS_MATRIX(t[0], 0, 0); mx = *VIPS_MATRIX(t[0], 1, 0); if (mn == mx) { /* Range of zero: just return black. */ if (vips_black(&t[1], scale->in->Xsize, scale->in->Ysize, "bands", scale->in->Bands, NULL) || vips_image_write(t[1], conversion->out)) return -1; } else if (scale->log) { double f = 255.0 / log10(1.0 + pow(mx, scale->exp)); if (vips_pow_const1(scale->in, &t[2], scale->exp, NULL) || vips_linear1(t[2], &t[3], 1.0, 1.0, NULL) || vips_log10(t[3], &t[4], NULL) || /* Add 0.5 to get round to nearest. */ vips_linear1(t[4], &t[5], f, 0.5, "uchar", TRUE, NULL) || vips_image_write(t[5], conversion->out)) return -1; } else { double f = 255.0 / (mx - mn); /* Add .5 to get round-to-nearest. */ double a = -(mn * f) + 0.5; if (vips_linear1(scale->in, &t[2], f, a, "uchar", TRUE, NULL) || vips_image_write(t[2], conversion->out)) return -1; } return 0; } static void vips_scale_class_init(VipsScaleClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "scale"; vobject_class->description = _("scale an image to uchar"); vobject_class->build = vips_scale_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsScale, in)); VIPS_ARG_BOOL(class, "log", 3, _("Log"), _("Log scale"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsScale, log), FALSE); VIPS_ARG_DOUBLE(class, "exp", 3, _("Exponent"), _("Exponent for log scale"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsScale, exp), 0.00001, 10000, 0.25); } static void vips_scale_init(VipsScale *scale) { scale->exp = 0.25; } /** * vips_scale: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Search the image for the maximum and minimum value, then return the image * as unsigned 8-bit, scaled so that the maximum value is 255 and the * minimum is zero. * * If @log is set, transform with log10(1.0 + pow(x, @exp)) + .5, * then scale so max == 255. By default, @exp is 0.25. * * ::: tip "Optional arguments" * * @log: `gboolean`, log scale pixels * * @exp: `gdouble`, exponent for log scale * * ::: seealso * [method@Image.cast]. * * Returns: 0 on success, -1 on error */ int vips_scale(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("scale", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/sequential.c000066400000000000000000000177521516303661500214570ustar00rootroot00000000000000/* Like copy, but ensure sequential access. * * Handy with sequential for loading files formats which are strictly * top-to-bottom, like PNG. * * 15/2/12 * - from VipsForeignLoad * 14/7/12 * - support skip forwards as well, so we can do extract/insert * 10/8/12 * - add @trace option * 21/8/12 * - remove skip forward, instead do thread stalling and have an * integrated cache * - use linecache * 4/9/12 * - stop all threads on error * - don't stall forever, just delay ahead threads * 25/2/14 * - we were allowing skipahead if the first request was for y>0, but * this broke on some busy, many-core systems, see comment below * 10/6/14 * - re-enable skipahead now we have the single-thread-first-tile idea * 6/3/17 * - deprecate @trace, @access now seq is much simpler * 6/9/21 * - don't set "persistent", it can cause huge memory use */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a cache of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG_GREEN #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsSequential { VipsConversion parent_instance; VipsImage *in; int tile_height; VipsAccess access; gboolean trace; /* Lock access to y_pos with this. */ GMutex lock; /* The next read from our source will fetch this scanline, ie. it's 0 * when we start. */ int y_pos; /* If one thread gets an error, we must stop all threads, otherwise we * can stall and never wake. */ int error; } VipsSequential; typedef VipsConversionClass VipsSequentialClass; G_DEFINE_TYPE(VipsSequential, vips_sequential, VIPS_TYPE_CONVERSION); static void vips_sequential_finalize(GObject *gobject) { VipsSequential *sequential = (VipsSequential *) gobject; g_mutex_clear(&sequential->lock); G_OBJECT_CLASS(vips_sequential_parent_class)->finalize(gobject); } static int vips_sequential_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsSequential *sequential = (VipsSequential *) b; VipsRect *r = &out_region->valid; VipsRegion *ir = (VipsRegion *) seq; /* printf("vips_sequential_generate %p: request for line %d, height %d\n", sequential, r->top, r->height); */ VIPS_GATE_START("vips_sequential_generate: wait"); vips__worker_lock(&sequential->lock); VIPS_GATE_STOP("vips_sequential_generate: wait"); /* If we've seen an error, everything must stop. */ if (sequential->error) { g_mutex_unlock(&sequential->lock); return -1; } if (r->top > sequential->y_pos) { /* This is a request for something some way down the image. * Probably the operation is something like extract_area and * we should skip the initial part of the image. In fact, * we read to cache, since it may be useful. * * Read in chunks, since we may be skipping *many* lines of image from * a file source. */ int y; for (y = sequential->y_pos; y < r->top; y += sequential->tile_height) { VipsRect area; area.left = 0; area.top = y; area.width = 1; area.height = VIPS_MIN(sequential->tile_height, r->top - area.top); if (vips_region_prepare(ir, &area)) { sequential->error = -1; g_mutex_unlock(&sequential->lock); return -1; } sequential->y_pos += area.height; } } /* This is a request for old pixels, or for pixels exactly at the read * point. This might trigger a generate from the thing feeding the cache, * eg. a loader. */ if (vips_region_prepare(ir, r) || vips_region_region(out_region, ir, r, r->left, r->top)) { sequential->error = -1; g_mutex_unlock(&sequential->lock); return -1; } sequential->y_pos = VIPS_MAX(sequential->y_pos, VIPS_RECT_BOTTOM(r)); g_mutex_unlock(&sequential->lock); return 0; } static int vips_sequential_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsSequential *sequential = (VipsSequential *) object; VipsImage *t; VIPS_DEBUG_MSG("vips_sequential_build\n"); if (VIPS_OBJECT_CLASS(vips_sequential_parent_class)->build(object)) return -1; /* We've gone forwards and backwards on sequential caches being * persistent. Persistent caches can be useful if you want to eg. * make several crop() operations on a seq image source, but they use * a lot of memory with eg. arrayjoin. * * On balance, if you want to make many crops from one source, use a * RANDOM image. */ if (vips_linecache(sequential->in, &t, "tile_height", sequential->tile_height, "access", VIPS_ACCESS_SEQUENTIAL, NULL)) return -1; vips_object_local(object, t); if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, t, NULL)) return -1; if (vips_image_generate(conversion->out, vips_start_one, vips_sequential_generate, vips_stop_one, t, sequential)) return -1; return 0; } static void vips_sequential_class_init(VipsSequentialClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_sequential_class_init\n"); gobject_class->finalize = vips_sequential_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "sequential"; vobject_class->description = _("check sequential access"); vobject_class->build = vips_sequential_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSequential, in)); VIPS_ARG_INT(class, "tile_height", 3, _("Tile height"), _("Tile height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSequential, tile_height), 1, 1000000, 1); VIPS_ARG_ENUM(class, "access", 6, _("Strategy"), _("Expected access pattern"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsSequential, access), VIPS_TYPE_ACCESS, VIPS_ACCESS_SEQUENTIAL); VIPS_ARG_BOOL(class, "trace", 2, _("Trace"), _("Trace pixel requests"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsSequential, trace), TRUE); } static void vips_sequential_init(VipsSequential *sequential) { g_mutex_init(&sequential->lock); sequential->tile_height = 1; sequential->error = 0; sequential->trace = FALSE; } /** * vips_sequential: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation behaves rather like [method@Image.copy] between images * @in and @out, except that it checks that pixels on @in are only requested * top-to-bottom. This operation is useful for loading file formats which are * strictly top-to-bottom, like PNG. * * @tile_height can be used to set the size of the tiles that * [method@Image.sequential] uses. The default value is 1. * * ::: tip "Optional arguments" * * @tile_height: `gint`, height of cache strips * * ::: seealso * [method@Image.linecache], [method@Image.tilecache]. * * Returns: 0 on success, -1 on error. */ int vips_sequential(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("sequential", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/smartcrop.c000066400000000000000000000315151516303661500213100ustar00rootroot00000000000000/* crop an image down to a specified size by removing boring parts * * Adapted from sharp's smartcrop feature, with kind permission. * * 1/3/17 * - first version, from sharp * 14/3/17 * - revised attention smartcrop * 8/6/17 * - revised again * 15/9/18 lovell * - move shrink to start of processing * 22/9/18 jcupitt * - add low and high * 19/3/20 jcupitt * - add all * 26/11/22 ejoebstl * - expose location of interest when using attention based cropping */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pconversion.h" #include "bandary.h" typedef struct _VipsSmartcrop { VipsConversion parent_instance; VipsImage *in; int width; int height; VipsInteresting interesting; gboolean premultiplied; int attention_x; int attention_y; } VipsSmartcrop; typedef VipsConversionClass VipsSmartcropClass; G_DEFINE_TYPE(VipsSmartcrop, vips_smartcrop, VIPS_TYPE_CONVERSION); static int vips_smartcrop_score(VipsSmartcrop *smartcrop, VipsImage *in, int left, int top, int width, int height, double *score) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(smartcrop), 2); if (vips_extract_area(in, &t[0], left, top, width, height, NULL) || vips_hist_find(t[0], &t[1], NULL) || vips_hist_entropy(t[1], score, NULL)) return -1; return 0; } /* Entropy-style smartcrop. Repeatedly discard low interest areas. This should * be faster for very large images. */ static int vips_smartcrop_entropy(VipsSmartcrop *smartcrop, VipsImage *in, int *left, int *top) { int max_slice_size; int width; int height; *left = 0; *top = 0; width = in->Xsize; height = in->Ysize; /* How much do we trim by each iteration? Aim for 8 steps in the axis * that needs trimming most. */ max_slice_size = VIPS_MAX( ceil((width - smartcrop->width) / 8.0), ceil((height - smartcrop->height) / 8.0)); /* Repeatedly take a slice off width and height until we * reach the target. */ while (width > smartcrop->width || height > smartcrop->height) { const int slice_width = VIPS_MIN(width - smartcrop->width, max_slice_size); const int slice_height = VIPS_MIN(height - smartcrop->height, max_slice_size); if (slice_width > 0) { double left_score; double right_score; if (vips_smartcrop_score(smartcrop, in, *left, *top, slice_width, height, &left_score)) return -1; if (vips_smartcrop_score(smartcrop, in, *left + width - slice_width, *top, slice_width, height, &right_score)) return -1; width -= slice_width; if (left_score < right_score) *left += slice_width; } if (slice_height > 0) { double top_score; double bottom_score; if (vips_smartcrop_score(smartcrop, in, *left, *top, width, slice_height, &top_score)) return -1; if (vips_smartcrop_score(smartcrop, in, *left, *top + height - slice_height, width, slice_height, &bottom_score)) return -1; height -= slice_height; if (top_score < bottom_score) *top += slice_height; } } return 0; } /* Calculate sqrt(b1^2 + b2^2 ...) */ static int pythagoras(VipsSmartcrop *smartcrop, VipsImage *in, VipsImage **out) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(smartcrop), 2 * in->Bands + 1); int i; for (i = 0; i < in->Bands; i++) if (vips_extract_band(in, &t[i], i, NULL)) return -1; for (i = 0; i < in->Bands; i++) if (vips_multiply(t[i], t[i], &t[i + in->Bands], NULL)) return -1; if (vips_sum(&t[in->Bands], &t[2 * in->Bands], in->Bands, NULL) || vips_pow_const1(t[2 * in->Bands], out, 0.5, NULL)) return -1; return 0; } static int vips_smartcrop_attention(VipsSmartcrop *smartcrop, VipsImage *in, int *left, int *top, int *attention_x, int *attention_y) { /* From smartcrop.js. */ static double skin_vector[] = { -0.78, -0.57, -0.44 }; static double ones[] = { 1.0, 1.0, 1.0 }; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(smartcrop), 24); double hscale; double vscale; double sigma; double max; int x_pos; int y_pos; /* The size we shrink to gives the precision with which we can place * the crop */ hscale = 32.0 / in->Xsize; vscale = 32.0 / in->Ysize; sigma = sqrt(pow(smartcrop->width * hscale, 2) + pow(smartcrop->height * vscale, 2)); sigma = VIPS_MAX(sigma / 10, 1.0); if (vips_resize(in, &t[17], hscale, "vscale", vscale, NULL)) return -1; /* Simple edge detect. */ if (!(t[21] = vips_image_new_matrixv(3, 3, 0.0, -1.0, 0.0, -1.0, 4.0, -1.0, 0.0, -1.0, 0.0))) return -1; /* Convert to XYZ and just use the first three bands. */ if (vips_colourspace(t[17], &t[0], VIPS_INTERPRETATION_XYZ, NULL) || vips_extract_band(t[0], &t[1], 0, "n", 3, NULL)) return -1; /* Edge detect on Y. */ if (vips_extract_band(t[1], &t[2], 1, NULL) || vips_conv(t[2], &t[3], t[21], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_linear1(t[3], &t[4], 5.0, 0.0, NULL) || vips_abs(t[4], &t[14], NULL)) return -1; /* Look for skin colours. Taken from smartcrop.js. */ if ( /* Normalise to magnitude of colour in XYZ. */ pythagoras(smartcrop, t[1], &t[5]) || vips_divide(t[1], t[5], &t[6], NULL) || /* Distance from skin point. */ vips_linear(t[6], &t[7], ones, skin_vector, 3, NULL) || pythagoras(smartcrop, t[7], &t[8]) || /* Rescale to 100 - 0 score. */ vips_linear1(t[8], &t[9], -100.0, 100.0, NULL) || /* Ignore dark areas. */ vips_more_const1(t[2], &t[10], 5.0, NULL) || !(t[11] = vips_image_new_from_image1(t[10], 0.0)) || vips_ifthenelse(t[10], t[9], t[11], &t[15], NULL)) return -1; /* Look for saturated areas. */ if (vips_colourspace(t[1], &t[12], VIPS_INTERPRETATION_LAB, NULL) || vips_extract_band(t[12], &t[13], 1, NULL) || vips_ifthenelse(t[10], t[13], t[11], &t[16], NULL)) return -1; /* Sum, blur and find maxpos. * * The amount of blur is related to the size of the crop * area: how large an area we want to consider for the scoring * function. */ if (vips_sum(&t[14], &t[18], 3, NULL) || vips_gaussblur(t[18], &t[19], sigma, NULL) || vips_max(t[19], &max, "x", &x_pos, "y", &y_pos, NULL)) return -1; /* Transform back into image coordinates. */ *attention_x = x_pos / hscale; *attention_y = y_pos / vscale; /* Centre the crop over the max. */ *left = VIPS_CLIP(0, *attention_x - smartcrop->width / 2, in->Xsize - smartcrop->width); *top = VIPS_CLIP(0, *attention_y - smartcrop->height / 2, in->Ysize - smartcrop->height); return 0; } static int vips_smartcrop_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsSmartcrop *smartcrop = (VipsSmartcrop *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; int left; int top; int attention_x = 0; int attention_y = 0; if (VIPS_OBJECT_CLASS(vips_smartcrop_parent_class)->build(object)) return -1; if (smartcrop->width > smartcrop->in->Xsize || smartcrop->height > smartcrop->in->Ysize || smartcrop->width <= 0 || smartcrop->height <= 0) { vips_error(class->nickname, "%s", _("bad extract area")); return -1; } in = smartcrop->in; /* If there's an alpha, we have to premultiply before searching for * content. There could be stuff in transparent areas which we don't * want to consider. */ if (vips_image_hasalpha(in) && !smartcrop->premultiplied) { if (vips_premultiply(in, &t[0], NULL)) return -1; in = t[0]; } switch (smartcrop->interesting) { case VIPS_INTERESTING_NONE: case VIPS_INTERESTING_LOW: left = 0; top = 0; break; case VIPS_INTERESTING_CENTRE: left = (in->Xsize - smartcrop->width) / 2; top = (in->Ysize - smartcrop->height) / 2; break; case VIPS_INTERESTING_ENTROPY: if (vips_smartcrop_entropy(smartcrop, in, &left, &top)) return -1; break; case VIPS_INTERESTING_ATTENTION: if (vips_smartcrop_attention(smartcrop, in, &left, &top, &attention_x, &attention_y)) return -1; break; case VIPS_INTERESTING_HIGH: left = in->Xsize - smartcrop->width; top = in->Ysize - smartcrop->height; break; case VIPS_INTERESTING_ALL: left = 0; top = 0; smartcrop->width = in->Xsize; // FIXME: Invalidates operation cache smartcrop->height = in->Ysize; // FIXME: Invalidates operation cache break; default: g_assert_not_reached(); /* Stop a compiler warning. */ left = 0; top = 0; break; } g_object_set(smartcrop, "attention_x", attention_x, "attention_y", attention_y, NULL); if (vips_extract_area(smartcrop->in, &t[1], left, top, smartcrop->width, smartcrop->height, NULL) || vips_image_write(t[1], conversion->out)) return -1; return 0; } static void vips_smartcrop_class_init(VipsSmartcropClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_smartcrop_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "smartcrop"; vobject_class->description = _("extract an area from an image"); vobject_class->build = vips_smartcrop_build; VIPS_ARG_IMAGE(class, "input", 0, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSmartcrop, in)); VIPS_ARG_INT(class, "width", 4, _("Width"), _("Width of extract area"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSmartcrop, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Height of extract area"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSmartcrop, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_ENUM(class, "interesting", 6, _("Interesting"), _("How to measure interestingness"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSmartcrop, interesting), VIPS_TYPE_INTERESTING, VIPS_INTERESTING_ATTENTION); VIPS_ARG_INT(class, "attention_x", 2, _("Attention x"), _("Horizontal position of attention centre"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsSmartcrop, attention_x), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "attention_y", 3, _("Attention y"), _("Vertical position of attention centre"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsSmartcrop, attention_y), 0, VIPS_MAX_COORD, 0); VIPS_ARG_BOOL(class, "premultiplied", 7, _("Premultiplied"), _("Input image already has premultiplied alpha"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSmartcrop, premultiplied), FALSE); } static void vips_smartcrop_init(VipsSmartcrop *smartcrop) { smartcrop->interesting = VIPS_INTERESTING_ATTENTION; smartcrop->premultiplied = FALSE; } /** * vips_smartcrop: (method) * @in: input image * @out: (out): output image * @width: width of area to extract * @height: height of area to extract * @...: `NULL`-terminated list of optional named arguments * * Crop an image down to a specified width and height by removing boring parts. * * Use @interesting to pick the method vips uses to decide which bits of the * image should be kept. * * You can test xoffset / yoffset on @out to find the location of the crop * within the input image. * * ::: tip "Optional arguments" * * @interesting: [enum@Interesting] to use to find interesting areas * (default: [enum@Vips.Interesting.ATTENTION]) * * @premultiplied: `gboolean`, input image already has premultiplied alpha * * @attention_x: `gint`, output, horizontal position of attention centre when * using attention based cropping * * @attention_y: `gint`, output, vertical position of attention centre when * using attention based cropping * * ::: seealso * [method@Image.extract_area]. * * Returns: 0 on success, -1 on error. */ int vips_smartcrop(VipsImage *in, VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("smartcrop", ap, in, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/subsample.c000066400000000000000000000200551516303661500212660ustar00rootroot00000000000000/* subsample * * 3/7/95 JC * - adapted from im_shrink() * 3/8/02 JC * - fall back to im_copy() for x/y factors == 1 * 21/4/08 * - don't fall back to pixel-wise shrinks for smalltile, it kills * performance, just bring VIPS_MAX_WIDTH down instead * 1/2/10 * - gtkdoc * 1/6/13 * - redo as a class * 2/11/13 * - add @point to force point sample mode * 22/1/16 * - remove SEQUENTIAL hint, it confuses vips_sequential() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconversion.h" typedef struct _VipsSubsample { VipsConversion parent_instance; VipsImage *in; int xfac; int yfac; gboolean point; } VipsSubsample; typedef VipsConversionClass VipsSubsampleClass; G_DEFINE_TYPE(VipsSubsample, vips_subsample, VIPS_TYPE_CONVERSION); /* Maximum width of input we ask for. */ #define VIPS_MAX_WIDTH (100) /* Subsample a VipsRegion. We fetch in VIPS_MAX_WIDTH pixel-wide strips, * left-to-right across the input. */ static int vips_subsample_line_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsSubsample *subsample = (VipsSubsample *) b; VipsImage *in = (VipsImage *) a; VipsRect *r = &out_region->valid; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int ps = VIPS_IMAGE_SIZEOF_PEL(in); int owidth = VIPS_MAX_WIDTH / subsample->xfac; VipsRect s; int x, y; int z, k; /* Loop down the region. */ for (y = to; y < bo; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); VipsPel *p; if (vips__worker_exit()) return 0; /* Loop across the region, in owidth-sized pieces. */ for (x = le; x < ri; x += owidth) { /* How many pixels do we make this time? */ int ow = VIPS_MIN(owidth, ri - x); /* Ask for this many from input ... can save a * little here! */ int iw = ow * subsample->xfac - (subsample->xfac - 1); /* Ask for input. */ s.left = x * subsample->xfac; s.top = y * subsample->yfac; s.width = iw; s.height = 1; if (vips_region_prepare(ir, &s)) return -1; /* Append new pels to output. */ p = VIPS_REGION_ADDR(ir, s.left, s.top); for (z = 0; z < ow; z++) { for (k = 0; k < ps; k++) q[k] = p[k]; q += ps; p += ps * subsample->xfac; } } } return 0; } /* Fetch one pixel at a time ... good for very large shrinks. */ static int vips_subsample_point_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsSubsample *subsample = (VipsSubsample *) b; VipsImage *in = (VipsImage *) a; VipsRect *r = &out_region->valid; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int ps = VIPS_IMAGE_SIZEOF_PEL(in); VipsRect s; int x, y; int k; /* Loop down the region. */ for (y = to; y < bo; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); VipsPel *p; if (vips__worker_exit()) return 0; for (x = le; x < ri; x++) { s.left = x * subsample->xfac; s.top = y * subsample->yfac; s.width = 1; s.height = 1; if (vips_region_prepare(ir, &s)) return -1; p = VIPS_REGION_ADDR(ir, s.left, s.top); for (k = 0; k < ps; k++) q[k] = p[k]; q += ps; } } return 0; } static int vips_subsample_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsSubsample *subsample = (VipsSubsample *) object; VipsGenerateFn subsample_fn; if (VIPS_OBJECT_CLASS(vips_subsample_parent_class)->build(object)) return -1; g_assert(subsample->xfac > 0); g_assert(subsample->yfac > 0); if (subsample->xfac == 1 && subsample->yfac == 1) return vips_image_write(subsample->in, conversion->out); if (vips_image_pio_input(subsample->in) || vips_check_coding_known(class->nickname, subsample->in)) return -1; /* Set demand hints. We want THINSTRIP, as we will be demanding a * large area of input for each output line. */ if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, subsample->in, NULL)) return -1; /* Prepare output. Note: we round the output width down! */ conversion->out->Xsize = subsample->in->Xsize / subsample->xfac; conversion->out->Ysize = subsample->in->Ysize / subsample->yfac; if (conversion->out->Xsize <= 0 || conversion->out->Ysize <= 0) { vips_error(class->nickname, "%s", _("image has shrunk to nothing")); return -1; } /* Generate! If this is a very large shrink, then it's probably faster * to do it a pixel at a time. */ if (subsample->point || subsample->xfac > 10) subsample_fn = vips_subsample_point_gen; else subsample_fn = vips_subsample_line_gen; if (vips_image_generate(conversion->out, vips_start_one, subsample_fn, vips_stop_one, subsample->in, subsample)) return -1; return 0; } static void vips_subsample_class_init(VipsSubsampleClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "subsample"; vobject_class->description = _("subsample an image"); vobject_class->build = vips_subsample_build; /* We don't work well as sequential: we can easily skip the first few * scanlines, and that confuses vips_sequential(). */ VIPS_ARG_IMAGE(class, "input", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSubsample, in)); VIPS_ARG_INT(class, "xfac", 3, _("Xfac"), _("Horizontal subsample factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSubsample, xfac), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "yfac", 4, _("Yfac"), _("Vertical subsample factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSubsample, yfac), 1, VIPS_MAX_COORD, 1); VIPS_ARG_BOOL(class, "point", 5, _("Point"), _("Point sample"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSubsample, point), FALSE); } static void vips_subsample_init(VipsSubsample *subsample) { } /** * vips_subsample: (method) * @in: input image * @out: (out): output image * @xfac: horizontal shrink factor * @yfac: vertical shrink factor * @...: `NULL`-terminated list of optional named arguments * * Subsample an image by an integer fraction. This is fast, nearest-neighbour * shrink. * * For small horizontal shrinks, this operation will fetch lines of pixels * from @in and then subsample that line. For large shrinks it will fetch * single pixels. * * If @point is set, @in will always be sampled in points. This can be faster * if the previous operations in the pipeline are very slow. * * ::: tip "Optional arguments" * * @point: `gboolean`, turn on point sample mode * * ::: seealso * [method@Image.affine], [method@Image.shrink], [method@Image.zoom]. * * Returns: 0 on success, -1 on error. */ int vips_subsample(VipsImage *in, VipsImage **out, int xfac, int yfac, ...) { va_list ap; int result; va_start(ap, yfac); result = vips_call_split("subsample", ap, in, out, xfac, yfac); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/switch.c000066400000000000000000000141361516303661500205770ustar00rootroot00000000000000/* switch between an array of images * * 28/7/19 * - from maplut.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include typedef struct _VipsSwitch { VipsOperation parent_instance; VipsArrayImage *tests; VipsImage *out; int n; } VipsSwitch; typedef VipsOperationClass VipsSwitchClass; G_DEFINE_TYPE(VipsSwitch, vips_switch, VIPS_TYPE_OPERATION); static int vips_switch_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion **ar = (VipsRegion **) seq; VipsSwitch *swit = (VipsSwitch *) b; VipsRect *r = &out_region->valid; int x, y, i; VipsPel *restrict q; size_t qls; VipsPel *restrict p[256]; size_t ls[256]; if (vips_reorder_prepare_many(out_region->im, ar, r)) return -1; g_assert(ar[0]->im->BandFmt == VIPS_FORMAT_UCHAR); g_assert(ar[0]->im->Bands == 1); for (i = 0; i < swit->n; i++) { p[i] = VIPS_REGION_ADDR(ar[i], r->left, r->top); ls[i] = VIPS_REGION_LSKIP(ar[i]); } q = VIPS_REGION_ADDR(out_region, r->left, r->top); qls = VIPS_REGION_LSKIP(out_region); for (y = 0; y < r->height; y++) { for (x = 0; x < r->width; x++) { for (i = 0; i < swit->n; i++) if (p[i][x]) break; q[x] = i; } q += qls; for (i = 0; i < swit->n; i++) p[i] += ls[i]; } return 0; } static int vips_switch_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsSwitch *swit = (VipsSwitch *) object; VipsImage **tests; VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; int i; g_object_set(object, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_switch_parent_class)->build(object)) return -1; /* 255 rather than 256, since we want to reserve +1 as the no * match value. */ tests = vips_area_get_data(&swit->tests->area, NULL, &swit->n, NULL, NULL); if (swit->n > 255 || swit->n < 1) { vips_error(class->nickname, "%s", _("bad number of tests")); return -1; } decode = (VipsImage **) vips_object_local_array(object, swit->n); format = (VipsImage **) vips_object_local_array(object, swit->n); band = (VipsImage **) vips_object_local_array(object, swit->n + 1); size = (VipsImage **) vips_object_local_array(object, swit->n + 1); /* Decode RAD/LABQ etc. */ for (i = 0; i < swit->n; i++) if (vips_image_decode(tests[i], &decode[i])) return -1; tests = decode; /* Must be uchar. */ for (i = 0; i < swit->n; i++) if (vips_cast_uchar(tests[i], &format[i], NULL)) return -1; tests = format; /* Images must match in size and bands. */ if (vips__bandalike_vec(class->nickname, tests, band, swit->n, 1) || vips__sizealike_vec(band, size, swit->n)) return -1; tests = size; if (tests[0]->Bands > 1) { vips_error(class->nickname, "%s", _("test images not 1-band")); return -1; } if (vips_image_pipeline_array(swit->out, VIPS_DEMAND_STYLE_THINSTRIP, tests)) return -1; if (vips_image_generate(swit->out, vips_start_many, vips_switch_gen, vips_stop_many, tests, swit)) return -1; return 0; } static void vips_switch_class_init(VipsSwitchClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "switch"; object_class->description = _("find the index of the first non-zero pixel in tests"); object_class->build = vips_switch_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_BOXED(class, "tests", 1, _("Tests"), _("Table of images to test"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSwitch, tests), VIPS_TYPE_ARRAY_IMAGE); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsSwitch, out)); } static void vips_switch_init(VipsSwitch *swit) { } static int vips_switchv(VipsImage **tests, VipsImage **out, int n, va_list ap) { VipsArrayImage *tests_array; int result; tests_array = vips_array_image_new(tests, n); result = vips_call_split("switch", ap, tests_array, out); vips_area_unref(VIPS_AREA(tests_array)); return result; } /** * vips_switch: * @tests: (array length=n): test these images * @out: (out): output index image * @n: number of input images * @...: `NULL`-terminated list of optional named arguments * * The @tests images are evaluated and at each point the index of the first * non-zero value is written to @out. If all @tests are false, the value * (@n + 1) is written. * * Images in @tests must have one band. They are expanded to the * bounding box of the set of images in @tests, and that size is used for * @out. @tests can have up to 255 elements. * * Combine with [method@Image.case] to make an efficient multi-way [method@Image.ifthenelse]. * * ::: seealso * [method@Image.maplut], [method@Image.case], [method@Image.ifthenelse]. * * Returns: 0 on success, -1 on error */ int vips_switch(VipsImage **tests, VipsImage **out, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_switchv(tests, out, n, ap); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/tilecache.c000066400000000000000000000637161516303661500212270ustar00rootroot00000000000000/* Simple tile or line cache. * * This isn't the same as the sinkscreen cache: we don't sub-divide, and we * single-thread our callee. * * 23/8/06 * - take ownership of reused tiles in case the cache is being shared * 13/2/07 * - release ownership after fillng with pixels in case we read across * threads * 4/2/10 * - gtkdoc * 12/12/10 * - use im_prepare_to() and avoid making a sequence for every cache tile * 5/12/11 * - rework as a class * 23/6/12 * - listen for "minimise" signal * 23/8/12 * - split to line and tile cache * - use a hash table instead of a list * 13/9/12 * - oops, linecache was oversized * 12/11/12 * - make linecache 50% larger to give some slop room * 8/10/12 * - make it optionally threaded * 21/2/13 * - could deadlock if downstream raised an error (thanks Todd) * 25/4/13 * - cache minimisation is optional, see "persistent" flag * 26/8/14 Lovell * - free the hash table in _dispose() * 11/7/16 * - terminate on tile calc error * 7/3/17 * - remove "access" on linecache, use the base class instead */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a cache of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG_RED #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pconversion.h" /* A tile in cache can be in one of three states: * * DATA - the tile holds valid pixels * CALC - some thread somewhere is calculating it * PEND - some thread somewhere wants it */ typedef enum VipsTileState { VIPS_TILE_STATE_DATA, VIPS_TILE_STATE_CALC, VIPS_TILE_STATE_PEND } VipsTileState; /* A tile in our cache. */ typedef struct _VipsTile { struct _VipsBlockCache *cache; VipsTileState state; VipsRegion *region; /* Region with private mem for data */ /* We count how many threads are relying on this tile. This tile can't * be flushed if ref_count > 0. */ int ref_count; /* Tile position. Just use left/top to calculate a hash. This is the * key for the hash table. Don't use region->valid in case the region * pointer is NULL. */ VipsRect pos; } VipsTile; typedef struct _VipsBlockCache { VipsConversion parent_instance; VipsImage *in; int tile_width; int tile_height; int max_tiles; VipsAccess access; gboolean threaded; gboolean persistent; GMutex lock; /* Lock everything here */ GCond new_tile; /* A new tile is ready */ GHashTable *tiles; /* Tiles, hashed by coordinates */ GQueue *recycle; /* Queue of unreffed tiles to reuse */ } VipsBlockCache; typedef VipsConversionClass VipsBlockCacheClass; G_DEFINE_ABSTRACT_TYPE(VipsBlockCache, vips_block_cache, VIPS_TYPE_CONVERSION); #define VIPS_TYPE_BLOCK_CACHE (vips_block_cache_get_type()) static void vips_block_cache_drop_all(VipsBlockCache *cache) { /* FIXME this is a disaster if active threads are working on tiles. We * should have something to block new requests, and only dispose once * all tiles are unreffed. */ g_hash_table_remove_all(cache->tiles); } static void vips_block_cache_finalize(GObject *gobject) { VipsBlockCache *cache = (VipsBlockCache *) gobject; g_mutex_clear(&cache->lock); g_cond_clear(&cache->new_tile); G_OBJECT_CLASS(vips_block_cache_parent_class)->finalize(gobject); } static void vips_block_cache_dispose(GObject *gobject) { VipsBlockCache *cache = (VipsBlockCache *) gobject; vips_block_cache_drop_all(cache); if (cache->tiles) g_assert(g_hash_table_size(cache->tiles) == 0); VIPS_FREEF(g_hash_table_destroy, cache->tiles); VIPS_FREEF(g_queue_free, cache->recycle); G_OBJECT_CLASS(vips_block_cache_parent_class)->dispose(gobject); } static int vips_tile_move(VipsTile *tile, int x, int y) { /* We are changing x/y and therefore the hash value. We must unlink * from the old hash position and relink at the new place. */ g_hash_table_steal(tile->cache->tiles, &tile->pos); tile->pos.left = x; tile->pos.top = y; tile->pos.width = tile->cache->tile_width; tile->pos.height = tile->cache->tile_height; g_hash_table_insert(tile->cache->tiles, &tile->pos, tile); if (vips_region_buffer(tile->region, &tile->pos)) return -1; /* No data yet, but someone must want it. */ tile->state = VIPS_TILE_STATE_PEND; return 0; } static VipsTile * vips_tile_new(VipsBlockCache *cache, int x, int y) { VipsTile *tile; if (!(tile = VIPS_NEW(NULL, VipsTile))) return NULL; tile->cache = cache; tile->state = VIPS_TILE_STATE_PEND; tile->ref_count = 0; tile->region = NULL; tile->pos.left = x; tile->pos.top = y; tile->pos.width = cache->tile_width; tile->pos.height = cache->tile_height; g_hash_table_insert(cache->tiles, &tile->pos, tile); g_queue_push_tail(tile->cache->recycle, tile); if (!(tile->region = vips_region_new(cache->in))) { g_hash_table_remove(cache->tiles, &tile->pos); return NULL; } vips__region_no_ownership(tile->region); if (vips_region_buffer(tile->region, &tile->pos)) { g_hash_table_remove(cache->tiles, &tile->pos); return NULL; } return tile; } /* Do we have a tile in the cache? */ static VipsTile * vips_tile_search(VipsBlockCache *cache, int x, int y) { VipsRect pos; VipsTile *tile; pos.left = x; pos.top = y; pos.width = cache->tile_width; pos.height = cache->tile_height; tile = (VipsTile *) g_hash_table_lookup(cache->tiles, &pos); return tile; } static void vips_tile_find_is_topper(gpointer element, gpointer user_data) { VipsTile *this = (VipsTile *) element; VipsTile **best = (VipsTile **) user_data; if (!*best || this->pos.top < (*best)->pos.top) *best = this; } /* Search the recycle list for the topmost tile. */ static VipsTile * vips_tile_find_topmost(GQueue *recycle) { VipsTile *tile; tile = NULL; g_queue_foreach(recycle, vips_tile_find_is_topper, &tile); return tile; } /* Find existing tile, make a new tile, or if we have a full set of tiles, * reuse one. */ static VipsTile * vips_tile_find(VipsBlockCache *cache, int x, int y) { VipsTile *tile; /* In cache already? */ if ((tile = vips_tile_search(cache, x, y))) { VIPS_DEBUG_MSG_RED( "vips_tile_find: tile %d x %d in cache\n", x, y); return tile; } /* VipsBlockCache not full? */ if (cache->max_tiles == -1 || g_hash_table_size(cache->tiles) < cache->max_tiles) { VIPS_DEBUG_MSG_RED( "vips_tile_find: making new tile at %d x %d\n", x, y); if (!(tile = vips_tile_new(cache, x, y))) return NULL; return tile; } /* Reuse an old one, if there are any. We just peek the tile pointer, * it is removed from the recycle list later on _ref. */ if (cache->recycle) { if (cache->access == VIPS_ACCESS_RANDOM) tile = g_queue_peek_head(cache->recycle); else /* This is slower :( We have to search the recycle * queue. */ tile = vips_tile_find_topmost(cache->recycle); } if (!tile) { /* There are no tiles we can reuse -- we have to make another * for now. They will get culled down again next time around. */ if (!(tile = vips_tile_new(cache, x, y))) return NULL; return tile; } VIPS_DEBUG_MSG_RED("vips_tile_find: reusing tile %d x %d\n", tile->pos.left, tile->pos.top); if (vips_tile_move(tile, x, y)) return NULL; return tile; } static gboolean vips_tile_unlocked(gpointer key, gpointer value, gpointer user_data) { VipsTile *tile = (VipsTile *) value; return !tile->ref_count; } static void vips_block_cache_minimise(VipsImage *image, VipsBlockCache *cache) { VIPS_DEBUG_MSG("vips_block_cache_minimise:\n"); g_mutex_lock(&cache->lock); /* We can't drop tiles that are in use. */ g_hash_table_foreach_remove(cache->tiles, vips_tile_unlocked, NULL); g_mutex_unlock(&cache->lock); } static int vips_block_cache_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsBlockCache *cache = (VipsBlockCache *) object; VIPS_DEBUG_MSG("vips_block_cache_build:\n"); if (VIPS_OBJECT_CLASS(vips_block_cache_parent_class)->build(object)) return -1; VIPS_DEBUG_MSG("vips_block_cache_build: max size = %g MB\n", (cache->max_tiles * cache->tile_width * cache->tile_height * VIPS_IMAGE_SIZEOF_PEL(cache->in)) / (1024 * 1024.0)); if (!cache->persistent) g_signal_connect(conversion->out, "minimise", G_CALLBACK(vips_block_cache_minimise), cache); return 0; } static void vips_block_cache_class_init(VipsBlockCacheClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_block_cache_class_init\n"); gobject_class->finalize = vips_block_cache_finalize; gobject_class->dispose = vips_block_cache_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "blockcache"; vobject_class->description = _("cache an image"); vobject_class->build = vips_block_cache_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBlockCache, in)); VIPS_ARG_INT(class, "tile_height", 4, _("Tile height"), _("Tile height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlockCache, tile_height), 1, 1000000, 128); VIPS_ARG_ENUM(class, "access", 6, _("Access"), _("Expected access pattern"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlockCache, access), VIPS_TYPE_ACCESS, VIPS_ACCESS_RANDOM); VIPS_ARG_BOOL(class, "threaded", 7, _("Threaded"), _("Allow threaded access"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlockCache, threaded), FALSE); VIPS_ARG_BOOL(class, "persistent", 8, _("Persistent"), _("Keep cache between evaluations"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlockCache, persistent), FALSE); } static unsigned int vips_rect_hash(VipsRect *pos) { guint hash; /* We could shift down by the tile size? * * X discrimination is more important than Y, since * most tiles will have a similar Y. */ hash = (guint) pos->left ^ ((guint) pos->top << 16); return hash; } static gboolean vips_rect_equal(VipsRect *a, VipsRect *b) { return a->left == b->left && a->top == b->top; } static void vips_tile_destroy(VipsTile *tile) { VipsBlockCache *cache = tile->cache; VIPS_DEBUG_MSG_RED("vips_tile_destroy: tile %d, %d (%p)\n", tile->pos.left, tile->pos.top, tile); /* 0 ref tiles should be on the recycle list. */ g_assert(tile->ref_count == 0); g_assert(g_queue_find(tile->cache->recycle, tile)); g_queue_remove(cache->recycle, tile); tile->cache = NULL; VIPS_UNREF(tile->region); g_free(tile); } static void vips_block_cache_init(VipsBlockCache *cache) { cache->tile_width = 128; cache->tile_height = 128; cache->max_tiles = 1000; cache->access = VIPS_ACCESS_RANDOM; cache->threaded = FALSE; cache->persistent = FALSE; g_mutex_init(&cache->lock); g_cond_init(&cache->new_tile); cache->tiles = g_hash_table_new_full( (GHashFunc) vips_rect_hash, (GEqualFunc) vips_rect_equal, NULL, (GDestroyNotify) vips_tile_destroy); cache->recycle = g_queue_new(); } typedef struct _VipsTileCache { VipsBlockCache parent_instance; } VipsTileCache; typedef VipsBlockCacheClass VipsTileCacheClass; G_DEFINE_TYPE(VipsTileCache, vips_tile_cache, VIPS_TYPE_BLOCK_CACHE); static void vips_tile_unref(VipsTile *tile) { g_assert(tile->ref_count > 0); tile->ref_count -= 1; if (tile->ref_count == 0) { /* Place at the end of the recycle queue. We pop from the * front when selecting an unused tile for reuse. */ g_assert(!g_queue_find(tile->cache->recycle, tile)); g_queue_push_tail(tile->cache->recycle, tile); } } static void vips_tile_ref(VipsTile *tile) { tile->ref_count += 1; g_assert(tile->ref_count > 0); if (tile->ref_count == 1) { g_assert(g_queue_find(tile->cache->recycle, tile)); g_queue_remove(tile->cache->recycle, tile); } } static void vips_tile_cache_unref(GSList *work) { GSList *p; for (p = work; p; p = p->next) vips_tile_unref((VipsTile *) p->data); g_slist_free(work); } /* Make a set of work tiles. */ static GSList * vips_tile_cache_ref(VipsBlockCache *cache, VipsRect *r) { const int tw = cache->tile_width; const int th = cache->tile_height; /* Find top left of tiles we need. */ const int xs = (r->left / tw) * tw; const int ys = (r->top / th) * th; GSList *work; VipsTile *tile; int x, y; /* Ref all the tiles we will need. */ work = NULL; for (y = ys; y < VIPS_RECT_BOTTOM(r); y += th) for (x = xs; x < VIPS_RECT_RIGHT(r); x += tw) { if (!(tile = vips_tile_find(cache, x, y))) { vips_tile_cache_unref(work); return NULL; } vips_tile_ref(tile); /* We must append, since we want to keep tile ordering * for sequential sources. */ work = g_slist_append(work, tile); VIPS_DEBUG_MSG_RED( "vips_tile_cache_ref: tile %d, %d (%p)\n", x, y, tile); } return work; } static void vips_tile_paste(VipsTile *tile, VipsRegion *out_region) { VipsRect hit; /* The part of the tile that we need. */ vips_rect_intersectrect(&out_region->valid, &tile->pos, &hit); if (!vips_rect_isempty(&hit)) vips_region_copy(tile->region, out_region, &hit, hit.left, hit.top); } /* Also called from vips_line_cache_gen(), beware. */ static int vips_tile_cache_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *in = (VipsRegion *) seq; VipsBlockCache *cache = (VipsBlockCache *) b; VipsRect *r = &out_region->valid; VipsTile *tile; GSList *work; GSList *p; int result; result = 0; VIPS_GATE_START("vips_tile_cache_gen: wait1"); vips__worker_lock(&cache->lock); VIPS_GATE_STOP("vips_tile_cache_gen: wait1"); VIPS_DEBUG_MSG_RED( "vips_tile_cache_gen: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); /* Ref all the tiles we will need. */ work = vips_tile_cache_ref(cache, r); while (work) { /* Search for data tiles: easy, we can just paste those in. */ for (;;) { for (p = work; p; p = p->next) { tile = (VipsTile *) p->data; if (tile->state == VIPS_TILE_STATE_DATA) break; } if (!p) break; VIPS_DEBUG_MSG_RED( "vips_tile_cache_gen: pasting %p\n", tile); vips_tile_paste(tile, out_region); /* We're done with this tile. */ work = g_slist_remove(work, tile); vips_tile_unref(tile); } /* Calculate the first PEND tile we find on the work list. We * don't calculate all PEND tiles since after the first, more * DATA tiles might heve been made available by other threads * and we want to get them out of the way as soon as we can. */ for (p = work; p; p = p->next) { tile = (VipsTile *) p->data; if (tile->state == VIPS_TILE_STATE_PEND) { tile->state = VIPS_TILE_STATE_CALC; VIPS_DEBUG_MSG_RED( "vips_tile_cache_gen: calc of %p\n", tile); /* In threaded mode, we let other threads run * while we calc this tile. In non-threaded * mode, we keep the lock and make 'em wait. */ if (cache->threaded) g_mutex_unlock(&cache->lock); /* Don't compute if we've seen an error * previously. */ if (!result) result = vips_region_prepare_to(in, tile->region, &tile->pos, tile->pos.left, tile->pos.top); if (cache->threaded) { VIPS_GATE_START("vips_tile_cache_gen: wait2"); g_mutex_lock(&cache->lock); VIPS_GATE_STOP("vips_tile_cache_gen: wait2"); } /* If there was an error calculating this * tile, black it out and terminate * calculation. We have to stop so we can * support things like --fail on jpegload. * * Don't return early, we'd deadlock. */ if (result) { VIPS_DEBUG_MSG_RED( "vips_tile_cache_gen: error on tile %p\n", tile); g_warning("error in tile %d x %d", tile->pos.left, tile->pos.top); vips_region_black(tile->region); *stop = TRUE; } tile->state = VIPS_TILE_STATE_DATA; /* Let everyone know there's a new DATA tile. * They need to all check their work lists. */ g_cond_broadcast(&cache->new_tile); break; } } /* There are no PEND or DATA tiles, we must need a tile some * other thread is currently calculating. * * We must block until the CALC tiles we need are done. */ if (!p && work) { for (p = work; p; p = p->next) { tile = (VipsTile *) p->data; g_assert(tile->state == VIPS_TILE_STATE_CALC); } VIPS_DEBUG_MSG_RED("vips_tile_cache_gen: waiting\n"); VIPS_GATE_START("vips_tile_cache_gen: wait3"); vips__worker_cond_wait(&cache->new_tile, &cache->lock); VIPS_GATE_STOP("vips_tile_cache_gen: wait3"); VIPS_DEBUG_MSG("vips_tile_cache_gen: awake!\n"); } } g_mutex_unlock(&cache->lock); return result; } static int vips_tile_cache_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsBlockCache *block_cache = (VipsBlockCache *) object; VipsTileCache *cache = (VipsTileCache *) object; VIPS_DEBUG_MSG("vips_tile_cache_build\n"); if (VIPS_OBJECT_CLASS(vips_tile_cache_parent_class)->build(object)) return -1; if (vips_image_pio_input(block_cache->in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, block_cache->in, NULL)) return -1; vips_image_set_int(conversion->out, VIPS_META_TILE_WIDTH, block_cache->tile_width); vips_image_set_int(conversion->out, VIPS_META_TILE_HEIGHT, block_cache->tile_height); if (vips_image_generate(conversion->out, vips_start_one, vips_tile_cache_gen, vips_stop_one, block_cache->in, cache)) return -1; return 0; } static void vips_tile_cache_class_init(VipsTileCacheClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_tile_cache_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "tilecache"; vobject_class->description = _("cache an image as a set of tiles"); vobject_class->build = vips_tile_cache_build; VIPS_ARG_INT(class, "tile_width", 3, _("Tile width"), _("Tile width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlockCache, tile_width), 1, 1000000, 128); VIPS_ARG_INT(class, "max_tiles", 5, _("Max tiles"), _("Maximum number of tiles to cache"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlockCache, max_tiles), -1, 1000000, 1000); } static void vips_tile_cache_init(VipsTileCache *cache) { } /** * vips_tilecache: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * * This operation behaves rather like [method@Image.copy] between images * @in and @out, except that it keeps a cache of computed pixels. * This cache is made of up to @max_tiles tiles (a value of -1 * means any number of tiles), and each tile is of size @tile_width * by @tile_height pixels. * * Each cache tile is made with a single call to * [method@Region.prepare]. * * When the cache fills, a tile is chosen for reuse. If @access is * [enum@Vips.Access.RANDOM], then the least-recently-used tile is reused. If * @access is [enum@Vips.Access.SEQUENTIAL] * the top-most tile is reused. * * By default, @tile_width and @tile_height are 128 pixels, and the operation * will cache up to 1,000 tiles. @access defaults to [enum@Vips.Access.RANDOM]. * * Normally, only a single thread at once is allowed to calculate tiles. If * you set @threaded to `TRUE`, [method@Image.tilecache] will allow many * threads to calculate tiles at once, and share the cache between them. * * Normally the cache is dropped when computation finishes. Set @persistent to * `TRUE` to keep the cache between computations. * * ::: tip "Optional arguments" * * @tile_width: `gint`, width of tiles in cache * * @tile_height: `gint`, height of tiles in cache * * @max_tiles: `gint`, maximum number of tiles to cache * * @access: [enum@Access], hint expected access pattern * * @threaded: `gboolean`, allow many threads * * @persistent: `gboolean`, don't drop cache at end of computation * * ::: seealso * [method@Image.linecache]. * * Returns: 0 on success, -1 on error. */ int vips_tilecache(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("tilecache", ap, in, out); va_end(ap); return result; } typedef struct _VipsLineCache { VipsBlockCache parent_instance; } VipsLineCache; typedef VipsBlockCacheClass VipsLineCacheClass; G_DEFINE_TYPE(VipsLineCache, vips_line_cache, VIPS_TYPE_BLOCK_CACHE); static int vips_line_cache_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsBlockCache *block_cache = (VipsBlockCache *) b; VIPS_GATE_START("vips_line_cache_gen: wait"); vips__worker_lock(&block_cache->lock); VIPS_GATE_STOP("vips_line_cache_gen: wait"); /* We size up the cache to the largest request. */ if (out_region->valid.height > block_cache->max_tiles * block_cache->tile_height) { block_cache->max_tiles = // FIXME: Invalidates operation cache 1 + (out_region->valid.height / block_cache->tile_height); VIPS_DEBUG_MSG("vips_line_cache_gen: bumped max_tiles to %d\n", block_cache->max_tiles); } g_mutex_unlock(&block_cache->lock); return vips_tile_cache_gen(out_region, seq, a, b, stop); } static int vips_line_cache_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsBlockCache *block_cache = (VipsBlockCache *) object; VipsLineCache *cache = (VipsLineCache *) object; int tile_width; int tile_height; int n_lines; VIPS_DEBUG_MSG("vips_line_cache_build\n"); if (!vips_object_argument_isset(object, "access")) block_cache->access = VIPS_ACCESS_SEQUENTIAL; // FIXME: Invalidates operation cache if (VIPS_OBJECT_CLASS(vips_line_cache_parent_class)->build(object)) return -1; /* This can go up with request size, see vips_line_cache_gen(). */ vips_get_tile_size(block_cache->in, &tile_width, &tile_height, &n_lines); block_cache->tile_width = block_cache->in->Xsize; // FIXME: Invalidates operation cache /* Output has two buffers n_lines height, so 2 * n_lines is the maximum * non-locality from threading. Double again for conv, rounding, etc. * * tile_height can be huge for things like tiff read, where we can * have a whole strip in a single tile ... we still need to have a * minimum of two strips, so we can handle requests that straddle a * tile boundary. */ block_cache->max_tiles = VIPS_MAX(2, // FIXME: Invalidates operation cache 4 * n_lines / block_cache->tile_height); VIPS_DEBUG_MSG("vips_line_cache_build: n_lines = %d\n", n_lines); VIPS_DEBUG_MSG("vips_line_cache_build: max_tiles = %d\n", block_cache->max_tiles); VIPS_DEBUG_MSG("vips_line_cache_build: tile_height = %d\n", block_cache->tile_height); VIPS_DEBUG_MSG("vips_line_cache_build: max size = %g MB\n", (block_cache->max_tiles * block_cache->tile_width * block_cache->tile_height * VIPS_IMAGE_SIZEOF_PEL(block_cache->in)) / (1024 * 1024.0)); if (vips_image_pio_input(block_cache->in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, block_cache->in, NULL)) return -1; if (vips_image_generate(conversion->out, vips_start_one, vips_line_cache_gen, vips_stop_one, block_cache->in, cache)) return -1; return 0; } static void vips_line_cache_class_init(VipsLineCacheClass *class) { VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_line_cache_class_init\n"); vobject_class->nickname = "linecache"; vobject_class->description = _("cache an image as a set of lines"); vobject_class->build = vips_line_cache_build; } static void vips_line_cache_init(VipsLineCache *cache) { } /** * vips_linecache: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation behaves rather like [method@Image.copy] between images * @in and @out, except that it keeps a cache of computed scanlines. * * The number of lines cached is enough for a small amount of non-local * access. * * Each cache tile is made with a single call to [method@Region.prepare]. * * When the cache fills, a tile is chosen for reuse. If @access is * [enum@Vips.Access.RANDOM], then the least-recently-used tile is reused. If * @access is [enum@Vips.Access.SEQUENTIAL], then * the top-most tile is reused. @access defaults to [enum@Vips.Access.RANDOM]. * * @tile_height can be used to set the size of the strips that * [method@Image.linecache] uses. The default is 1 (a single scanline). * * Normally, only a single thread at once is allowed to calculate tiles. If * you set @threaded to `TRUE`, [method@Image.linecache] will allow many * threads to calculate tiles at once and share the cache between them. * * ::: tip "Optional arguments" * * @access: [enum@Access], hint expected access pattern * * @tile_height: `gint`, height of tiles in cache * * @threaded: `gboolean`, allow many threads * * ::: seealso * [method@Image.tilecache]. * * Returns: 0 on success, -1 on error. */ int vips_linecache(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("linecache", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/transpose3d.c000066400000000000000000000122371516303661500215430ustar00rootroot00000000000000/* vips_transpose3d * * 30/4/18 * - from grid.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconversion.h" typedef struct _VipsTranspose3d { VipsConversion parent_instance; VipsImage *in; int page_height; } VipsTranspose3d; typedef VipsConversionClass VipsTranspose3dClass; G_DEFINE_TYPE(VipsTranspose3d, vips_transpose3d, VIPS_TYPE_CONVERSION); static int vips_transpose3d_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) vseq; VipsImage *in = (VipsImage *) a; VipsTranspose3d *transpose3d = (VipsTranspose3d *) b; VipsRect *r = &out_region->valid; int output_page_height = in->Ysize / transpose3d->page_height; int y; VipsRect tile; tile = *r; tile.height = 1; for (y = 0; y < r->height; y++) { /* y in output. */ int yo = r->top + y; /* On output page. */ int yop = yo / output_page_height; /* Line on output page. */ int yol = yo % output_page_height; /* y of input page. */ int yip = yol * transpose3d->page_height; /* y of input line. */ int yi = yip + yop; tile.top = yi; /* Render into out_region. */ if (vips_region_prepare_to(ir, out_region, &tile, tile.left, yo)) return -1; } return 0; } static int vips_transpose3d_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsTranspose3d *transpose3d = (VipsTranspose3d *) object; VipsImage *in; if (VIPS_OBJECT_CLASS(vips_transpose3d_parent_class)->build(object)) return -1; in = transpose3d->in; if (vips_check_coding_known(class->nickname, in) || vips_image_pio_input(in)) return -1; if (!vips_object_argument_isset(object, "page_height")) { if (vips_image_get_int(in, VIPS_META_PAGE_HEIGHT, &transpose3d->page_height)) // FIXME: Invalidates operation cache return -1; } if (transpose3d->page_height <= 0 || in->Ysize % transpose3d->page_height != 0) { vips_error(class->nickname, "%s", _("bad page_height")); return -1; } if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; vips_image_set_int(conversion->out, VIPS_META_PAGE_HEIGHT, in->Ysize / transpose3d->page_height); if (vips_image_generate(conversion->out, vips_start_one, vips_transpose3d_gen, vips_stop_one, in, transpose3d)) return -1; return 0; } static void vips_transpose3d_class_init(VipsTranspose3dClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "transpose3d"; vobject_class->description = _("transpose3d an image"); vobject_class->build = vips_transpose3d_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsTranspose3d, in)); VIPS_ARG_INT(class, "page_height", 3, _("Page height"), _("Height of each input page"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTranspose3d, page_height), 0, 10000000, 0); } static void vips_transpose3d_init(VipsTranspose3d *transpose3d) { } /** * vips_transpose3d: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Transpose a volumetric image. * * Volumetric images are very tall, thin images, with the metadata item * [const@META_PAGE_HEIGHT] set to the height of each sub-image. * * This operation swaps the two major dimensions, so that page N in the * output contains the Nth scanline, in order, from each input page. * * You can override the [const@META_PAGE_HEIGHT] metadata item with the optional * @page_height parameter. * * [const@META_PAGE_HEIGHT] in the output image is the number of pages in the * input image. * * ::: tip "Optional arguments" * * @page_height: `gint`, size of each input page * * ::: seealso * [method@Image.grid]. * * Returns: 0 on success, -1 on error */ int vips_transpose3d(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("transpose3d", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/unpremultiply.c000066400000000000000000000232431516303661500222260ustar00rootroot00000000000000/* unpremultiply alpha * * Author: John Cupitt * Written on: 7/5/15 * * 25/5/16 * - max_alpha defaults to 65535 for RGB16/GREY16 * 24/11/17 lovell * - match normalised alpha to output type * 27/2/21 jjonesrs * - revise range clipping and 1/x, again * 8/8/22 * - look for alpha near 0, not just exactly 0 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsUnpremultiply { VipsConversion parent_instance; VipsImage *in; double max_alpha; int alpha_band; } VipsUnpremultiply; typedef VipsConversionClass VipsUnpremultiplyClass; G_DEFINE_TYPE(VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION); /* Unpremultiply an N-band image. Don't use clip_alpha to calculate factor: we * want over and undershoots on alpha and RGB to cancel. */ #define UNPRE_MANY(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) { \ IN alpha = p[alpha_band]; \ OUT factor = alpha == 0 ? 0 : max_alpha / alpha; \ \ for (i = 0; i < alpha_band; i++) \ q[i] = factor * p[i]; \ q[alpha_band] = VIPS_CLIP(0, alpha, max_alpha); \ for (i = alpha_band + 1; i < bands; i++) \ q[i] = p[i]; \ \ p += bands; \ q += bands; \ } \ } /* Unpremultiply an RGB (four band) image. */ #define UNPRE_RGBA(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) { \ IN alpha = p[3]; \ OUT factor = alpha == 0 ? 0 : max_alpha / alpha; \ \ q[0] = factor * p[0]; \ q[1] = factor * p[1]; \ q[2] = factor * p[2]; \ q[3] = VIPS_CLIP(0, alpha, max_alpha); \ \ p += 4; \ q += 4; \ } \ } #define UNPRE(IN, OUT) \ { \ if (bands == 4) { \ UNPRE_RGBA(IN, OUT); \ } \ else { \ UNPRE_MANY(IN, OUT); \ } \ } /* For float-style images, we need to check for alpha near zero, or we'll get * +/- Inf in the output. */ #define FUNPRE_MANY(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) { \ IN alpha = p[alpha_band]; \ OUT factor = fabs(alpha) < 0.01 ? 0 : max_alpha / alpha; \ \ for (i = 0; i < alpha_band; i++) \ q[i] = factor * p[i]; \ q[alpha_band] = VIPS_CLIP(0, alpha, max_alpha); \ for (i = alpha_band + 1; i < bands; i++) \ q[i] = p[i]; \ \ p += bands; \ q += bands; \ } \ } #define FUNPRE_RGBA(IN, OUT) \ { \ IN *restrict p = (IN *) in; \ OUT *restrict q = (OUT *) out; \ \ for (x = 0; x < width; x++) { \ IN alpha = p[3]; \ OUT factor = fabs(alpha) < 0.01 ? 0 : max_alpha / alpha; \ \ q[0] = factor * p[0]; \ q[1] = factor * p[1]; \ q[2] = factor * p[2]; \ q[3] = VIPS_CLIP(0, alpha, max_alpha); \ \ p += 4; \ q += 4; \ } \ } #define FUNPRE(IN, OUT) \ { \ if (bands == 4) { \ FUNPRE_RGBA(IN, OUT); \ } \ else { \ FUNPRE_MANY(IN, OUT); \ } \ } VIPS_TARGET_CLONES("default,avx") static int vips_unpremultiply_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsUnpremultiply *unpremultiply = (VipsUnpremultiply *) b; VipsRegion *ir = (VipsRegion *) vseq; VipsImage *im = ir->im; VipsRect *r = &out_region->valid; int width = r->width; int bands = im->Bands; double max_alpha = unpremultiply->max_alpha; int alpha_band = unpremultiply->alpha_band; int x, y, i; if (vips_region_prepare(ir, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *in = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *out = VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: UNPRE(unsigned char, float); break; case VIPS_FORMAT_CHAR: UNPRE(signed char, float); break; case VIPS_FORMAT_USHORT: UNPRE(unsigned short, float); break; case VIPS_FORMAT_SHORT: UNPRE(signed short, float); break; case VIPS_FORMAT_UINT: UNPRE(unsigned int, float); break; case VIPS_FORMAT_INT: UNPRE(signed int, float); break; case VIPS_FORMAT_FLOAT: FUNPRE(float, float); break; case VIPS_FORMAT_DOUBLE: FUNPRE(double, double); break; case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: default: g_assert_not_reached(); } } return 0; } static int vips_unpremultiply_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsUnpremultiply *unpremultiply = (VipsUnpremultiply *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 1); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_unpremultiply_parent_class)->build(object)) return -1; in = unpremultiply->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; /* Trivial case: fall back to copy(). */ if (in->Bands == 1) return vips_image_write(in, conversion->out); if (vips_check_noncomplex(class->nickname, in)) return -1; if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; /* Is max-alpha unset? Default to the correct value for this * interpretation. */ if (!vips_object_argument_isset(object, "max_alpha")) unpremultiply->max_alpha = vips_interpretation_max_alpha(in->Type); // FIXME: Invalidates operation cache /* Is alpha-band unset? Default to the final band for this image. */ if (!vips_object_argument_isset(object, "alpha_band")) unpremultiply->alpha_band = in->Bands - 1; // FIXME: Invalidates operation cache else if (unpremultiply->alpha_band >= in->Bands) { vips_error(class->nickname, "%s", _("alpha_band out of range")); return -1; } if (in->BandFmt == VIPS_FORMAT_DOUBLE) conversion->out->BandFmt = VIPS_FORMAT_DOUBLE; else conversion->out->BandFmt = VIPS_FORMAT_FLOAT; if (vips_image_generate(conversion->out, vips_start_one, vips_unpremultiply_gen, vips_stop_one, in, unpremultiply)) return -1; return 0; } static void vips_unpremultiply_class_init(VipsUnpremultiplyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_unpremultiply_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "unpremultiply"; vobject_class->description = _("unpremultiply image alpha"); vobject_class->build = vips_unpremultiply_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsUnpremultiply, in)); VIPS_ARG_DOUBLE(class, "max_alpha", 115, _("Maximum alpha"), _("Maximum value of alpha channel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsUnpremultiply, max_alpha), 0, 100000000, 255); VIPS_ARG_INT(class, "alpha_band", 116, _("Alpha band"), _("Unpremultiply with this alpha"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsUnpremultiply, alpha_band), 0, 100000000, 3); } static void vips_unpremultiply_init(VipsUnpremultiply *unpremultiply) { unpremultiply->max_alpha = 255.0; } /** * vips_unpremultiply: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Unpremultiplies any alpha channel. * * Band @alpha_band (by default the final band) contains the alpha and all * other bands are transformed as: * * ``` * alpha = (int) clip(0, in[in.bands - 1], max_alpha); * norm = (double) alpha / max_alpha * if (alpha == 0) * out = [0, ..., 0, alpha] * else * out = [in[0] / norm, ..., in[in.bands - 1] / norm, alpha] * ``` * * So for an N-band image, the first N - 1 bands are divided by the clipped * and normalised final band, the final band is clipped. * If there is only a single band, the image is passed through unaltered. * * The result is [enum@Vips.BandFormat.FLOAT] unless the input format is * [enum@Vips.BandFormat.DOUBLE], in which case the output is double as well. * * @max_alpha has the default value 255, or 65535 for images tagged as * [enum@Vips.Interpretation.RGB16] or [enum@Vips.Interpretation.GREY16], and * 1.0 for images tagged as [enum@Vips.Interpretation.scRGB. * * Non-complex images only. * * ::: tip "Optional arguments" * * @max_alpha: `gdouble`, maximum value for alpha * * @alpha_band: `gint`, band containing alpha data * * ::: seealso * [method@Image.premultiply], [method@Image.flatten]. * * Returns: 0 on success, -1 on error */ int vips_unpremultiply(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("unpremultiply", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/wrap.c000066400000000000000000000102531516303661500202430ustar00rootroot00000000000000/* im_wrap * * Copyright: 2008, Nottingham Trent University * Author: Tom Vajzovic * Written on: 2008-01-15 * 2/2/10 * - rewritten in terms of im_replicate()/im_extract_area() * - gtkdoc * - allows any x/y * 31/5/13 * - redone as a class * - added rotquad behaviour if x/y not set */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include "pconversion.h" typedef struct _VipsWrap { VipsConversion parent_instance; VipsImage *in; int x; int y; } VipsWrap; typedef VipsConversionClass VipsWrapClass; G_DEFINE_TYPE(VipsWrap, vips_wrap, VIPS_TYPE_CONVERSION); static int vips_wrap_build(VipsObject *object) { VipsConversion *conversion = VIPS_CONVERSION(object); VipsWrap *wrap = (VipsWrap *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); int x; int y; if (VIPS_OBJECT_CLASS(vips_wrap_parent_class)->build(object)) return -1; if (!vips_object_argument_isset(object, "x")) wrap->x = wrap->in->Xsize / 2; // FIXME: Invalidates operation cache if (!vips_object_argument_isset(object, "y")) wrap->y = wrap->in->Ysize / 2; // FIXME: Invalidates operation cache /* Clock arithmetic: we want negative x/y to wrap around * nicely. */ x = wrap->x < 0 ? -wrap->x % wrap->in->Xsize : wrap->in->Xsize - wrap->x % wrap->in->Xsize; y = wrap->y < 0 ? -wrap->y % wrap->in->Ysize : wrap->in->Ysize - wrap->y % wrap->in->Ysize; if (vips_replicate(wrap->in, &t[0], 2, 2, NULL) || vips_extract_area(t[0], &t[1], x, y, wrap->in->Xsize, wrap->in->Ysize, NULL) || vips_image_write(t[1], conversion->out)) return -1; conversion->out->Xoffset = x; conversion->out->Yoffset = y; return 0; } static void vips_wrap_class_init(VipsWrapClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "wrap"; vobject_class->description = _("wrap image origin"); vobject_class->build = vips_wrap_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsWrap, in)); VIPS_ARG_INT(class, "x", 3, _("x"), _("Left edge of input in output"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsWrap, x), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "y", 4, _("y"), _("Top edge of input in output"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsWrap, y), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); } static void vips_wrap_init(VipsWrap *wrap) { } /** * vips_wrap: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Slice an image up and move the segments about so that the pixel that was * at 0, 0 is now at @x, @y. * * If @x and @y are not set, they default to the centre of the image. * * ::: tip "Optional arguments" * * @x: `gint`, horizontal displacement * * @y: `gint`, vertical displacement * * ::: seealso * [method@Image.embed], [method@Image.replicate]. * * Returns: 0 on success, -1 on error */ int vips_wrap(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("wrap", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/conversion/zoom.c000066400000000000000000000237661516303661500202730ustar00rootroot00000000000000/* im_zoom * * Author: N. Martinez 1991 * 6/6/94 JC * - rewritten to ANSI-C * - now works for any type, including IM_CODING_LABQ * 7/10/94 JC * - new IM_ARRAY() macro * 26/1/96 JC * - separate x and y zoom factors * 21/8/96 JC * - partial, yuk! this is so complicated ... * 30/8/96 JC * - sets demand_hint * 10/2/00 JC * - check for integer overflow in zoom facs ... was happening with ip's * zoom on large images * 3/8/02 JC * - fall back to im_copy() for x & y factors == 1 * 24/3/09 * - added IM_CODING_RAD support * 1/2/10 * - gtkdoc * 1/6/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define DEBUG_VERBOSE */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pconversion.h" typedef struct _VipsZoom { VipsConversion parent_instance; /* The input image. */ VipsImage *in; int xfac; /* Scale factors */ int yfac; } VipsZoom; typedef VipsConversionClass VipsZoomClass; G_DEFINE_TYPE(VipsZoom, vips_zoom, VIPS_TYPE_CONVERSION); /* Paint the part of the region containing only whole pels. */ static void vips_zoom_paint_whole(VipsRegion *out_region, VipsRegion *ir, VipsZoom *zoom, const int left, const int right, const int top, const int bottom) { const int ps = VIPS_IMAGE_SIZEOF_PEL(ir->im); const int ls = VIPS_REGION_LSKIP(out_region); const int rs = ps * (right - left); /* Transform to ir coordinates. */ const int ileft = left / zoom->xfac; const int iright = right / zoom->xfac; const int itop = top / zoom->yfac; const int ibottom = bottom / zoom->yfac; int x, y, z, i; /* We know this! */ g_assert(right > left && bottom > top && right % zoom->xfac == 0 && left % zoom->xfac == 0 && top % zoom->yfac == 0 && bottom % zoom->yfac == 0); /* Loop over input, as we know we are all whole. */ for (y = itop; y < ibottom; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, ileft, y); VipsPel *q = VIPS_REGION_ADDR(out_region, left, y * zoom->yfac); VipsPel *r; /* Expand the first line of pels. */ r = q; for (x = ileft; x < iright; x++) { /* Copy each pel xfac times. */ for (z = 0; z < zoom->xfac; z++) { for (i = 0; i < ps; i++) r[i] = p[i]; r += ps; } p += ps; } /* Copy the expanded line yfac-1 times. */ r = q + ls; for (z = 1; z < zoom->yfac; z++) { memcpy(r, q, rs); r += ls; } } } /* Paint the part of the region containing only part-pels. */ static void vips_zoom_paint_part(VipsRegion *out_region, VipsRegion *ir, VipsZoom *zoom, const int left, const int right, const int top, const int bottom) { const int ps = VIPS_IMAGE_SIZEOF_PEL(ir->im); const int ls = VIPS_REGION_LSKIP(out_region); const int rs = ps * (right - left); /* Start position in input. */ const int ix = left / zoom->xfac; const int iy = top / zoom->yfac; /* Pels down to yfac boundary, pels down to bottom. Do the smallest of * these for first y loop. */ const int ptbound = (iy + 1) * zoom->yfac - top; const int ptbot = bottom - top; int yt = VIPS_MIN(ptbound, ptbot); int x, y, z, i; /* Only know this. */ g_assert(right - left >= 0 && bottom - top >= 0); /* Have to loop over output. */ for (y = top; y < bottom;) { VipsPel *p = VIPS_REGION_ADDR(ir, ix, y / zoom->yfac); VipsPel *q = VIPS_REGION_ADDR(out_region, left, y); VipsPel *r; /* Output pels until we jump the input pointer. */ int xt = (ix + 1) * zoom->xfac - left; /* Loop for this output line. */ r = q; for (x = left; x < right; x++) { /* Copy 1 pel. */ for (i = 0; i < ps; i++) r[i] = p[i]; r += ps; /* Move input if on boundary. */ --xt; if (xt == 0) { xt = zoom->xfac; p += ps; } } /* Repeat that output line until the bottom of this pixel * boundary, or we hit bottom. */ r = q + ls; for (z = 1; z < yt; z++) { memcpy(r, q, rs); r += ls; } /* Move y on by the number of lines we wrote. */ y += yt; /* Reset yt for next iteration. */ yt = zoom->yfac; } } /* Zoom a VipsRegion. */ static int vips_zoom_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsZoom *zoom = (VipsZoom *) b; /* Output area we are building. */ const VipsRect *r = &out_region->valid; const int ri = VIPS_RECT_RIGHT(r); const int bo = VIPS_RECT_BOTTOM(r); VipsRect s; int left, right, top, bottom; int width, height; #ifdef DEBUG_VERBOSE printf("vips_zoom_gen: left=%d, top=%d, width=%d, height=%d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG_VERBOSE*/ /* Area of input we need. We have to round out, as we may have * part-pixels all around the edges. */ left = VIPS_ROUND_DOWN(r->left, zoom->xfac); right = VIPS_ROUND_UP(ri, zoom->xfac); top = VIPS_ROUND_DOWN(r->top, zoom->yfac); bottom = VIPS_ROUND_UP(bo, zoom->yfac); width = right - left; height = bottom - top; s.left = left / zoom->xfac; s.top = top / zoom->yfac; s.width = width / zoom->xfac; s.height = height / zoom->yfac; if (vips_region_prepare(ir, &s)) return -1; /* Find the part of the output (if any) which uses only whole pels. */ left = VIPS_ROUND_UP(r->left, zoom->xfac); right = VIPS_ROUND_DOWN(ri, zoom->xfac); top = VIPS_ROUND_UP(r->top, zoom->yfac); bottom = VIPS_ROUND_DOWN(bo, zoom->yfac); width = right - left; height = bottom - top; /* Stage 1: we just paint the whole pels in the centre of the region. * As we know they are not clipped, we can do it quickly. */ if (width > 0 && height > 0) vips_zoom_paint_whole(out_region, ir, zoom, left, right, top, bottom); /* Just fractional pixels left. Paint in the top, left, right and * bottom parts. */ if (top - r->top > 0) /* Some top pixels. */ vips_zoom_paint_part(out_region, ir, zoom, r->left, ri, r->top, VIPS_MIN(top, bo)); if (left - r->left > 0 && height > 0) /* Left pixels. */ vips_zoom_paint_part(out_region, ir, zoom, r->left, VIPS_MIN(left, ri), top, bottom); if (ri - right > 0 && height > 0) /* Right pixels. */ vips_zoom_paint_part(out_region, ir, zoom, VIPS_MAX(right, r->left), ri, top, bottom); if (bo - bottom > 0 && height >= 0) /* Bottom pixels. */ vips_zoom_paint_part(out_region, ir, zoom, r->left, ri, VIPS_MAX(bottom, r->top), bo); return 0; } static int vips_zoom_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConversion *conversion = VIPS_CONVERSION(object); VipsZoom *zoom = (VipsZoom *) object; if (VIPS_OBJECT_CLASS(vips_zoom_parent_class)->build(object)) return -1; g_assert(zoom->xfac > 0); g_assert(zoom->yfac > 0); /* Make sure we won't get integer overflow. */ if ((double) zoom->in->Xsize * zoom->xfac > (double) INT_MAX / 2 || (double) zoom->in->Ysize * zoom->yfac > (double) INT_MAX / 2) { vips_error(class->nickname, "%s", _("zoom factors too large")); return -1; } if (zoom->xfac == 1 && zoom->yfac == 1) return vips_image_write(zoom->in, conversion->out); if (vips_image_pio_input(zoom->in) || vips_check_coding_known(class->nickname, zoom->in)) return -1; /* Set demand hints. THINSTRIP will prevent us from using * vips_zoom_paint_whole() much ... so go for FATSTRIP. */ if (vips_image_pipelinev(conversion->out, VIPS_DEMAND_STYLE_FATSTRIP, zoom->in, NULL)) return -1; conversion->out->Xsize = zoom->in->Xsize * zoom->xfac; conversion->out->Ysize = zoom->in->Ysize * zoom->yfac; if (vips_image_generate(conversion->out, vips_start_one, vips_zoom_gen, vips_stop_one, zoom->in, zoom)) return -1; return 0; } static void vips_zoom_class_init(VipsZoomClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "zoom"; vobject_class->description = _("zoom an image"); vobject_class->build = vips_zoom_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "input", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsZoom, in)); VIPS_ARG_INT(class, "xfac", 3, _("Xfac"), _("Horizontal zoom factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsZoom, xfac), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "yfac", 4, _("Yfac"), _("Vertical zoom factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsZoom, yfac), 1, VIPS_MAX_COORD, 1); } static void vips_zoom_init(VipsZoom *zoom) { } /** * vips_zoom: (method) * @in: input image * @out: (out): output image * @xfac: horizontal scale factor * @yfac: vertical scale factor * @...: `NULL`-terminated list of optional named arguments * * Zoom an image by repeating pixels. This is fast nearest-neighbour * zoom. * * ::: seealso * [method@Image.affine], [method@Image.subsample]. * * Returns: 0 on success, -1 on error. */ int vips_zoom(VipsImage *in, VipsImage **out, int xfac, int yfac, ...) { va_list ap; int result; va_start(ap, yfac); result = vips_call_split("zoom", ap, in, out, xfac, yfac); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/000077500000000000000000000000001516303661500173175ustar00rootroot00000000000000libvips-8.18.2/libvips/convolution/canny.c000066400000000000000000000272551516303661500206060ustar00rootroot00000000000000/* Canny edge detector */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsCanny { VipsOperation parent_instance; VipsImage *in; VipsImage *out; double sigma; VipsPrecision precision; /* Need an image vector for start_many. */ VipsImage *args[3]; } VipsCanny; typedef VipsOperationClass VipsCannyClass; G_DEFINE_TYPE(VipsCanny, vips_canny, VIPS_TYPE_OPERATION); /* Simple 2x2 -1/+1 difference. For uchar, we try to hit the vector path and * use an offset rather than -ves. Otherwise it's float or double output. */ static int vips_canny_gradient(VipsImage *in, VipsImage **Gx, VipsImage **Gy) { VipsImage *scope; VipsImage **t; VipsPrecision precision; scope = vips_image_new(); t = (VipsImage **) vips_object_local_array((VipsObject *) scope, 2); t[0] = vips_image_new_matrixv(2, 2, -1.0, 1.0, -1.0, 1.0); if (in->BandFmt == VIPS_FORMAT_UCHAR) { precision = VIPS_PRECISION_INTEGER; vips_image_set_double(t[0], "offset", 128.0); } else precision = VIPS_PRECISION_FLOAT; if (vips_conv(in, Gx, t[0], "precision", precision, NULL) || vips_rot90(t[0], &t[1], NULL) || vips_conv(in, Gy, t[1], "precision", precision, NULL)) { g_object_unref(scope); return -1; } g_object_unref(scope); return 0; } /* LUT for calculating atan2() with +/- 4 bits of precision in each axis. */ static VipsPel vips_canny_polar_atan2[256]; /* For the uchar path, gx/gy are -128 to +127, and we need -8 to +7 for the * atan2 LUT. * * For G, we should calculate sqrt(gx * gx + gy * gy), however we are only * interested in relative magnitude (max of sqrt), so we can skip the sqrt * itself. We need a result that will fit in 0 - 255, so shift down. */ #define POLAR_UCHAR \ { \ for (x = 0; x < r->width; x++) { \ for (band = 0; band < Gx->Bands; band++) { \ int gx = p1[band] - 128; \ int gy = p2[band] - 128; \ \ int i = ((gx >> 4) & 0xf) | (gy & 0xf0); \ \ q[0] = (gx * gx + gy * gy + 256) >> 9; \ q[1] = vips_canny_polar_atan2[i]; \ \ q += 2; \ } \ \ p1 += Gx->Bands; \ p2 += Gx->Bands; \ } \ } /* Float/double path. We keep the same ranges as the uchar path to reduce * confusion. */ #define POLAR(TYPE) \ { \ TYPE *tp1 = (TYPE *) p1; \ TYPE *tp2 = (TYPE *) p2; \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < r->width; x++) { \ for (band = 0; band < Gx->Bands; band++) { \ double gx = tp1[band]; \ double gy = tp2[band]; \ double theta = VIPS_DEG(atan2(gx, gy)); \ \ tq[0] = (gx * gx + gy * gy + 256.0) / 512.0; \ tq[1] = 256.0 * fmod(theta + 360.0, 360.0) / 360.0; \ \ tq += 2; \ } \ \ tp1 += Gx->Bands; \ tp2 += Gx->Bands; \ } \ } static int vips_canny_polar_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion **in = (VipsRegion **) vseq; VipsRect *r = &out_region->valid; VipsImage *Gx = in[0]->im; int x, y, band; if (vips_reorder_prepare_many(out_region->im, in, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *p1 = (VipsPel *restrict) VIPS_REGION_ADDR(in[0], r->left, r->top + y); VipsPel *p2 = (VipsPel *restrict) VIPS_REGION_ADDR(in[1], r->left, r->top + y); VipsPel *q = (VipsPel *restrict) VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (Gx->BandFmt) { case VIPS_FORMAT_UCHAR: POLAR_UCHAR; break; case VIPS_FORMAT_FLOAT: POLAR(float); break; case VIPS_FORMAT_DOUBLE: POLAR(double); break; default: g_assert(FALSE); } } return 0; } static void * vips_atan2_init(void *null) { int i; for (i = 0; i < 256; i++) { /* Use the bottom 4 bits for x, the top 4 for y. Interpret the * 4-bit values as signed 2s complement and sign-extend to int. */ int x = i & 0xF; if (x & 0x8) x -= 0x10; int y = (i >> 4) & 0xF; if (y & 0x8) y -= 0x10; double theta = VIPS_DEG(atan2(x, y)) + 360; /* Map angle to 0–255 with wraparound. */ int value = 256 * theta / 360; vips_canny_polar_atan2[i] = value & 0xFF; } return NULL; } /* Calculate G/theta from Gx/Gy. We code theta as 0-256 for 0-360 * and skip the sqrt on G. * * For a white disc on a black background, theta is 0 at the top, 64 on the * left, 128 on the right and 192 on the right edge. */ static int vips_canny_polar(VipsImage **args, VipsImage **out) { static GOnce once = G_ONCE_INIT; g_once(&once, vips_atan2_init, NULL); *out = vips_image_new(); if (vips_image_pipeline_array(*out, VIPS_DEMAND_STYLE_THINSTRIP, args)) return -1; (*out)->Bands *= 2; if (vips_image_generate(*out, vips_start_many, vips_canny_polar_generate, vips_stop_many, args, NULL)) return -1; return 0; } #define THIN(TYPE) \ { \ TYPE *tp = (TYPE *) p; \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < r->width; x++) { \ for (band = 0; band < out_bands; band++) { \ TYPE G = tp[lsk + psk]; \ TYPE theta = tp[lsk + psk + 1]; \ int low_theta = ((int) (theta / 32)) & 0x7; \ int high_theta = (low_theta + 1) & 0x7; \ TYPE residual = theta - low_theta * 32; \ TYPE lowa = tp[offset[low_theta]]; \ TYPE lowb = tp[offset[high_theta]]; \ TYPE low = \ (lowa * (32 - residual) + lowb * residual) / 32; \ TYPE higha = tp[offset[(low_theta + 4) & 0x7]]; \ TYPE highb = tp[offset[(high_theta + 4) & 0x7]]; \ TYPE high = \ (higha * (32 - residual) + highb * residual) / 32; \ \ if (G <= low || \ G < high) \ G = 0; \ \ tq[band] = G; \ \ tp += 2; \ } \ \ tq += out_bands; \ } \ } static int vips_canny_thin_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *in = (VipsRegion *) vseq; VipsRect *r = &out_region->valid; VipsImage *im = in->im; int out_bands = out_region->im->Bands; VipsRect rect; int x, y, band; int lsk; int psk; int offset[8]; rect = *r; rect.width += 2; rect.height += 2; if (vips_region_prepare(in, &rect)) return -1; /* These are in typed units. */ lsk = VIPS_REGION_LSKIP(in) / VIPS_IMAGE_SIZEOF_ELEMENT(im); psk = VIPS_IMAGE_SIZEOF_PEL(im) / VIPS_IMAGE_SIZEOF_ELEMENT(im); /* For each of the 8 directions, the offset to get to that pixel from * the top-left of the 3x3. * * 1 | 0 | 7 * --+---+-- * 2 | X | 6 * --+---+-- * 3 | 4 | 5 */ offset[0] = psk; offset[1] = 0; offset[2] = lsk; offset[3] = 2 * lsk; offset[4] = 2 * lsk + psk; offset[5] = 2 * lsk + 2 * psk; offset[6] = lsk + 2 * psk; offset[7] = 2 * psk; for (y = 0; y < r->height; y++) { VipsPel *p = (VipsPel *restrict) VIPS_REGION_ADDR(in, r->left, r->top + y); VipsPel *q = (VipsPel *restrict) VIPS_REGION_ADDR(out_region, r->left, r->top + y); switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: THIN(unsigned char); break; case VIPS_FORMAT_FLOAT: THIN(float); break; case VIPS_FORMAT_DOUBLE: THIN(double); break; default: g_assert(FALSE); } } return 0; } /* Remove non-maximal edges. At each point, compare the G to the G in either * direction and 0 it if it's not the largest. */ static int vips_canny_thin(VipsImage *in, VipsImage **out) { *out = vips_image_new(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; (*out)->Bands /= 2; (*out)->Xsize -= 2; (*out)->Ysize -= 2; if (vips_image_generate(*out, vips_start_one, vips_canny_thin_generate, vips_stop_one, in, NULL)) return -1; return 0; } static int vips_canny_build(VipsObject *object) { VipsCanny *canny = (VipsCanny *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_canny_parent_class)->build(object)) return -1; in = canny->in; if (vips_gaussblur(in, &t[0], canny->sigma, "precision", canny->precision, NULL)) return -1; in = t[0]; if (vips_canny_gradient(in, &t[1], &t[2])) return -1; /* Form (G, theta). */ canny->args[0] = t[1]; canny->args[1] = t[2]; canny->args[2] = NULL; if (vips_canny_polar(canny->args, &t[3])) return -1; in = t[3]; /* Expand by two pixels all around, then thin in the direction of the * gradient. */ if (vips_embed(in, &t[4], 1, 1, in->Xsize + 2, in->Ysize + 2, "extend", VIPS_EXTEND_COPY, NULL)) return -1; if (vips_canny_thin(t[4], &t[5])) return -1; in = t[5]; g_object_set(object, "out", vips_image_new(), NULL); if (vips_image_write(in, canny->out)) return -1; return 0; } static void vips_canny_class_init(VipsCannyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "canny"; object_class->description = _("Canny edge detector"); object_class->build = vips_canny_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCanny, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsCanny, out)); VIPS_ARG_DOUBLE(class, "sigma", 10, _("Sigma"), _("Sigma of Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCanny, sigma), 0.01, 1000, 1.4); VIPS_ARG_ENUM(class, "precision", 103, _("Precision"), _("Convolve with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCanny, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_FLOAT); } static void vips_canny_init(VipsCanny *canny) { canny->sigma = 1.4; canny->precision = VIPS_PRECISION_FLOAT; } /** * vips_canny: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Find edges by Canny's method: The maximum of the derivative of the gradient * in the direction of the gradient. Output is float, except for uchar input, * where output is uchar, and double input, where output is double. Non-complex * images only. * * Use @sigma to control the scale over which gradient is measured. 1.4 is * usually a good value. * * Use @precision to set the precision of edge detection. For uchar images, * setting this to [enum@Vips.Precision.INTEGER] will make edge detection much * faster, but sacrifice some sensitivity. * * You will probably need to process the output further to eliminate weak * edges. * * ::: tip "Optional arguments" * * @sigma: `gdouble`, sigma for gaussian blur * * @precision: [enum@Precision], calculation accuracy * * ::: seealso * [method@Image.sobel]. * * Returns: 0 on success, -1 on error. */ int vips_canny(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("canny", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/compass.c000066400000000000000000000142071516303661500211340ustar00rootroot00000000000000/* repeatedly convolve with a rotating mask * * 23/10/13 * - from vips_conv() * 8/5/17 * - default to float ... int will often lose precision and should not be * the default * 2/11/17 * - add MIN mode */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pconvolution.h" typedef struct { VipsConvolution parent_instance; int times; VipsAngle45 angle; VipsCombine combine; VipsPrecision precision; int layers; int cluster; } VipsCompass; typedef VipsConvolutionClass VipsCompassClass; G_DEFINE_TYPE(VipsCompass, vips_compass, VIPS_TYPE_CONVOLUTION); static int vips_compass_build(VipsObject *object) { VipsConvolution *convolution = (VipsConvolution *) object; VipsCompass *compass = (VipsCompass *) object; VipsImage **masks; VipsImage *mask; VipsImage **images; int i; VipsImage **abs; VipsImage **combine; VipsImage *x; g_object_set(compass, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_compass_parent_class)->build(object)) return -1; masks = (VipsImage **) vips_object_local_array(object, compass->times); images = (VipsImage **) vips_object_local_array(object, compass->times); abs = (VipsImage **) vips_object_local_array(object, compass->times); combine = (VipsImage **) vips_object_local_array(object, compass->times); mask = convolution->M; for (i = 0; i < compass->times; i++) { if (vips_conv(convolution->in, &images[i], mask, "precision", compass->precision, "layers", compass->layers, "cluster", compass->cluster, NULL)) return -1; if (vips_rot45(mask, &masks[i], "angle", compass->angle, NULL)) return -1; mask = masks[i]; } for (i = 0; i < compass->times; i++) if (vips_abs(images[i], &abs[i], NULL)) return -1; switch (compass->combine) { case VIPS_COMBINE_MAX: if (vips_bandrank(abs, &combine[0], compass->times, "index", compass->times - 1, NULL)) return -1; x = combine[0]; break; case VIPS_COMBINE_MIN: if (vips_bandrank(abs, &combine[0], compass->times, "index", 0, NULL)) return -1; x = combine[0]; break; case VIPS_COMBINE_SUM: if (vips_sum(abs, &combine[0], compass->times, NULL)) return -1; x = combine[0]; break; default: g_assert_not_reached(); /* Stop compiler warnings. */ x = NULL; } if (vips_image_write(x, convolution->out)) return -1; return 0; } static void vips_compass_class_init(VipsCompassClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "compass"; object_class->description = _("convolve with rotating mask"); object_class->build = vips_compass_build; VIPS_ARG_INT(class, "times", 101, _("Times"), _("Rotate and convolve this many times"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompass, times), 1, 1000, 2); VIPS_ARG_ENUM(class, "angle", 103, _("Angle"), _("Rotate mask by this much between convolutions"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompass, angle), VIPS_TYPE_ANGLE45, VIPS_ANGLE45_D90); VIPS_ARG_ENUM(class, "combine", 104, _("Combine"), _("Combine convolution results like this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompass, combine), VIPS_TYPE_COMBINE, VIPS_COMBINE_MAX); VIPS_ARG_ENUM(class, "precision", 203, _("Precision"), _("Convolve with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompass, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_FLOAT); VIPS_ARG_INT(class, "layers", 204, _("Layers"), _("Use this many layers in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompass, layers), 1, 1000, 5); VIPS_ARG_INT(class, "cluster", 205, _("Cluster"), _("Cluster lines closer than this in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsCompass, cluster), 1, 100, 1); } static void vips_compass_init(VipsCompass *compass) { compass->times = 2; compass->angle = VIPS_ANGLE45_D90; compass->combine = VIPS_COMBINE_MAX; compass->precision = VIPS_PRECISION_FLOAT; compass->layers = 5; compass->cluster = 1; } /** * vips_compass: (method) * @in: input image * @out: (out): output image * @mask: convolve with this mask * @...: `NULL`-terminated list of optional named arguments * * This convolves @in with @mask @times times, rotating @mask by @angle * each time. By default, it comvolves twice, rotating by 90 degrees, taking * the maximum result. * * ::: tip "Optional arguments" * * @times: `gint`, how many times to rotate and convolve * * @angle: [enum@Angle45], rotate mask by this much between colvolutions * * @combine: [enum@Combine], combine results like this * * @precision: [enum@Precision], precision for blur, default float * * @layers: `gint`, number of layers for approximation * * @cluster: `gint`, cluster lines closer than this distance * * ::: seealso * [method@Image.conv]. * * Returns: 0 on success, -1 on error. */ int vips_compass(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("compass", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/conv.c000066400000000000000000000141011516303661500204250ustar00rootroot00000000000000/* convolution * * 12/8/13 * - from vips_hist_cum() * 8/5/17 * - default to float ... int will often lose precision and should not be * the default */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pconvolution.h" typedef struct { VipsConvolution parent_instance; VipsPrecision precision; int layers; int cluster; } VipsConv; typedef VipsConvolutionClass VipsConvClass; G_DEFINE_TYPE(VipsConv, vips_conv, VIPS_TYPE_CONVOLUTION); static int vips_conv_build(VipsObject *object) { VipsConvolution *convolution = (VipsConvolution *) object; VipsConv *conv = (VipsConv *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_conv_parent_class)->build(object)) return -1; g_object_set(conv, "out", vips_image_new(), NULL); in = convolution->in; /* printf("vips_conv_build: convolving with:\n"); vips_matrixprint(convolution->M, NULL); */ /* Unpack for processing. */ if (vips_image_decode(in, &t[0])) return -1; in = t[0]; switch (conv->precision) { case VIPS_PRECISION_FLOAT: if (vips_convf(in, &t[1], convolution->M, NULL) || vips_image_write(t[1], convolution->out)) return -1; break; case VIPS_PRECISION_INTEGER: if (vips_convi(in, &t[1], convolution->M, NULL) || vips_image_write(t[1], convolution->out)) return -1; break; case VIPS_PRECISION_APPROXIMATE: if (vips_conva(in, &t[1], convolution->M, "layers", conv->layers, "cluster", conv->cluster, NULL) || vips_image_write(t[1], convolution->out)) return -1; break; default: g_assert_not_reached(); } vips_reorder_margin_hint(convolution->out, convolution->M->Xsize * convolution->M->Ysize); return 0; } static void vips_conv_class_init(VipsConvClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "conv"; object_class->description = _("convolution operation"); object_class->build = vips_conv_build; VIPS_ARG_ENUM(class, "precision", 103, _("Precision"), _("Convolve with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConv, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_FLOAT); VIPS_ARG_INT(class, "layers", 104, _("Layers"), _("Use this many layers in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConv, layers), 1, 1000, 5); VIPS_ARG_INT(class, "cluster", 105, _("Cluster"), _("Cluster lines closer than this in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConv, cluster), 1, 100, 1); } static void vips_conv_init(VipsConv *conv) { conv->precision = VIPS_PRECISION_FLOAT; conv->layers = 5; conv->cluster = 1; } /** * vips_conv: (method) * @in: input image * @out: (out): output image * @mask: convolve with this mask * @...: `NULL`-terminated list of optional named arguments * * Perform a convolution of @in with @mask. * * Each output pixel is calculated as: * * ``` * sigma[i]{pixel[i] * mask[i]} / scale + offset * ``` * * where scale and offset are part of @mask. * * By default, @precision is * [enum@Vips.Precision.FLOAT]. The output image * is always [enum@Vips.BandFormat.FLOAT] unless @in is * [enum@Vips.BandFormat.DOUBLE], in which case @out is also * [enum@Vips.BandFormat.DOUBLE]. * * If @precision is [enum@Vips.Precision.INTEGER], then elements of @mask * are converted to integers before convolution, using `rint()`, * and the output image always has the same [enum@BandFormat] as the input * image. * * For [enum@Vips.BandFormat.UCHAR] images and [enum@Vips.Precision.INTEGER] * @precision, [method@Image.conv] uses a fast vector path based on * half-float arithmetic. This can produce slightly different results. * Disable the vector path with `--vips-novector` or `VIPS_NOVECTOR` or * [func@vector_set_enabled]. * * If @precision is [enum@Vips.Precision.APPROXIMATE] then, like * [enum@Vips.Precision.INTEGER], @mask is converted to int before * convolution, and the output image * always has the same [enum@BandFormat] as the input image. * * Larger values for @layers give more accurate * results, but are slower. As @layers approaches the mask radius, the * accuracy will become close to exact convolution and the speed will drop to * match. For many large masks, such as Gaussian, @n_layers need be only 10% of * this value and accuracy will still be good. * * Smaller values of @cluster will give more accurate results, but be slower * and use more memory. 10% of the mask radius is a good rule of thumb. * * ::: tip "Optional arguments" * * @precision: [enum@Precision], calculation accuracy * * @layers: `gint`, number of layers for approximation * * @cluster: `gint`, cluster lines closer than this distance * * ::: seealso * [method@Image.convsep]. * * Returns: 0 on success, -1 on error */ int vips_conv(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("conv", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/conva.c000066400000000000000000000756041516303661500206050ustar00rootroot00000000000000/* conva ... approximate convolution * * This operation does an approximate convolution. * * Author: John Cupitt & Nicolas Robidoux * Written on: 31/5/11 * Modified on: * 31/5/11 * - from im_aconvsep() * 10/7/16 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* See: http://incubator.quasimondo.com/processing/stackblur.pde This thing is a little like stackblur, but generalised to any 2D convolution. */ /* TODO timing: $ time vips im_conv_f img_0075.jpg x2.v g2d201.con real 5m3.359s user 9m34.700s sys 0m1.500s $ time vips im_aconv img_0075.jpg x.v g2d201.con 10 10 real 0m3.151s user 0m5.640s sys 0m0.100s $ vips im_subtract x.v x2.v diff.v $ vips im_abs diff.v abs.v $ vips im_max abs.v 2.70833 - are we handling mask offset correctly? - could we do better with an h and a v cumulativization image? we might not need the huge intermediate we have now, since any line sum an be found with simple indexing */ /* #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include #include "pconvolution.h" /* Maximum number of boxes we can break the mask into. Don't have this too * high, it'll make the instance huge, and gobject has a 64kb limit. */ #define MAX_LINES (1000) /* The number of edges we consider at once in clustering. Higher values are * faster, but risk pushing up average error in the result. */ #define MAX_EDGES (1000) /* A horizontal line in the mask. */ typedef struct _HLine { /* Start is the left-most pixel in the line, end is one beyond the * right-most pixel. */ int start; int end; /* The hlines have weights. weight 0 means this line is unused. */ int weight; } HLine; /* For clustering. A pair of hlines and their distance. An edge in a graph. */ typedef struct _Edge { /* The index into boxes->hline[]. */ int a; int b; /* The distance between them, see boxes_distance(). */ int d; } Edge; /* An element of a vline. */ typedef struct _VElement { /* band is the index into hline[] we add, row is the row we take * it from. */ int band; int row; /* Negative lobes are made with factor -1, we also common-up repeated * additions of the same line. */ int factor; } VElement; /* A vline. */ typedef struct _VLine { int band; int factor; int start; int end; } VLine; /* A set of boxes. */ typedef struct { VipsConvolution parent_instance; VipsImage *iM; int layers; int cluster; int divisor; int rounding; int offset; /* The horizontal lines we gather. hline[3] writes to band 3 in the * intermediate image. max_line is the length of the longest hline: * over 256 and we need to use an int intermediate for integer images. */ int n_hline; HLine hline[MAX_LINES]; int max_line; /* During clustering, the top few edges we are considering. */ Edge edge[MAX_EDGES]; /* Scale and sum a set of hlines to make the final value. */ int n_velement; VElement velement[MAX_LINES]; /* And group those velements as vlines. */ int n_vline; VLine vline[MAX_LINES]; } VipsConva; typedef VipsConvolutionClass VipsConvaClass; G_DEFINE_TYPE(VipsConva, vips_conva, VIPS_TYPE_CONVOLUTION); /* Euclid's algorithm. Use this to common up mults. */ static int gcd(int a, int b) { if (b == 0) return abs(a); else return gcd(b, a % b); } static void vips_conva_hline_start(VipsConva *conva, int x) { conva->hline[conva->n_hline].start = x; conva->hline[conva->n_hline].weight = 1; } static int vips_conva_hline_end(VipsConva *conva, int x, int y, int factor) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(conva); conva->hline[conva->n_hline].end = x; conva->velement[conva->n_velement].row = y; conva->velement[conva->n_velement].band = conva->n_hline; conva->velement[conva->n_velement].factor = factor; if (conva->n_hline >= MAX_LINES - 1) { vips_error(class->nickname, "%s", _("mask too complex")); return -1; } conva->n_hline += 1; if (conva->n_velement >= MAX_LINES - 1) { vips_error(class->nickname, "%s", _("mask too complex")); return -1; } conva->n_velement += 1; return 0; } #ifdef DEBUG static void vips_conva_hprint(VipsConva *conva) { int x, y; printf("hlines:\n"); printf(" n b r f w\n"); for (y = 0; y < conva->n_velement; y++) { int b = conva->velement[y].band; printf("%4d %3d %3d %2d %3d ", y, b, conva->velement[y].row, conva->velement[y].factor, conva->hline[b].weight); for (x = 0; x < 45; x++) { int rx = x * (conva->iM->Xsize + 1) / 45; if (rx >= conva->hline[b].start && rx < conva->hline[b].end) printf("#"); else printf(" "); } printf(" %3d .. %3d\n", conva->hline[b].start, conva->hline[b].end); } } static void vips_conva_vprint(VipsConva *conva) { int y; printf("%d vlines:\n", conva->n_vline); printf(" n b f s e\n"); for (y = 0; y < conva->n_vline; y++) printf("%4d %2d %2d == %3d .. %3d\n", y, conva->vline[y].band, conva->vline[y].factor, conva->vline[y].start, conva->vline[y].end); printf("divisor = %d\n", conva->divisor); printf("rounding = %d\n", conva->rounding); printf("offset = %d\n", conva->offset); printf("max_line = %d\n", conva->max_line); } #endif /*DEBUG*/ /* Break the mask into a set of hlines. */ static int vips_conva_decompose_hlines(VipsConva *conva) { VipsImage *iM = conva->iM; const int size = iM->Xsize * iM->Ysize; double *coeff = VIPS_MATRIX(iM, 0, 0); double max; double min; double depth; int layers; int layers_above; int layers_below; int z, n, x, y; /* Find mask range. We must always include the zero axis in the mask. */ max = 0; min = 0; for (n = 0; n < size; n++) { max = VIPS_MAX(max, coeff[n]); min = VIPS_MIN(min, coeff[n]); } VIPS_DEBUG_MSG("vips_conva_decompose_hlines: min = %g, max = %g\n", min, max); /* The zero axis must fall on a layer boundary. Estimate the * depth, find n-lines-above-zero, get exact depth, then calculate a * fixed n-lines which includes any negative parts. */ depth = (max - min) / conva->layers; layers_above = ceil(max / depth); depth = max / layers_above; layers_below = floor(min / depth); layers = VIPS_CLIP(1, (int64_t) layers_above - layers_below, 1000); VIPS_DEBUG_MSG("vips_conva_decompose_hlines: depth = %g, layers = %d\n", depth, conva->layers); /* For each layer, generate a set of lines which are inside the * perimeter. Work down from the top. */ for (z = 0; z < layers; z++) { /* How deep we are into the mask, as a double we can test * against. Add half the layer depth so we can easily find >50% * mask elements. */ double z_ph = max - (1 + z) * depth + depth / 2; /* Odd, but we must avoid rounding errors that make us miss 0 * in the line above. */ int z_positive = z < layers_above; for (y = 0; y < iM->Ysize; y++) { int inside; /* Start outside the perimeter. */ inside = 0; for (x = 0; x < iM->Xsize; x++) { double c = coeff[x + y * iM->Xsize]; /* The vertical line from mask[x, y] to 0 is * inside. Is our current square (x, y) part * of that line? */ if ((z_positive && c >= z_ph) || (!z_positive && c <= z_ph)) { if (!inside) { vips_conva_hline_start(conva, x); inside = 1; } } else { if (inside) { if (vips_conva_hline_end(conva, x, y, z_positive ? 1 : -1)) return -1; inside = 0; } } } if (inside && vips_conva_hline_end(conva, iM->Xsize, y, z_positive ? 1 : -1)) return -1; } } #ifdef DEBUG VIPS_DEBUG_MSG("vips_conva_decompose_hlines: generated %d hlines\n", conva->n_hline); vips_conva_hprint(conva); #endif /*DEBUG*/ return 0; } /* The 'distance' between a pair of hlines. */ static int vips_conva_distance(VipsConva *conva, int a, int b) { g_assert(conva->hline[a].weight > 0 && conva->hline[b].weight > 0); return abs(conva->hline[a].start - conva->hline[b].start) + abs(conva->hline[a].end - conva->hline[b].end); } /* Merge two hlines. Line b is deleted, and any refs to b in vlines updated to * point at a. */ static void vips_conva_merge(VipsConva *conva, int a, int b) { int i; /* Scale weights. */ int fa = conva->hline[a].weight; int fb = conva->hline[b].weight; double w = (double) fb / (fa + fb); /* New endpoints. */ conva->hline[a].start += w * (conva->hline[b].start - conva->hline[a].start); conva->hline[a].end += w * (conva->hline[b].end - conva->hline[a].end); conva->hline[a].weight += conva->hline[b].weight; /* Update velement refs to b to refer to a instead. */ for (i = 0; i < conva->n_velement; i++) if (conva->velement[i].band == b) conva->velement[i].band = a; /* Mark b to be deleted. */ conva->hline[b].weight = 0; } static int edge_sortfn(const void *p1, const void *p2) { Edge *a = (Edge *) p1; Edge *b = (Edge *) p2; return a->d - b->d; } /* Cluster in batches. Return non-zero if we merged some lines. * * This is not as accurate as rescanning the whole space on every merge, but * it's far faster. */ static int vips_conva_cluster2(VipsConva *conva) { int i, j, k; int worst; int worst_i; int merged; for (i = 0; i < MAX_EDGES; i++) { conva->edge[i].a = -1; conva->edge[i].b = -1; conva->edge[i].d = 99999; } worst_i = 0; worst = conva->edge[worst_i].d; for (i = 0; i < conva->n_hline; i++) { if (conva->hline[i].weight == 0) continue; for (j = i + 1; j < conva->n_hline; j++) { int distance; if (conva->hline[j].weight == 0) continue; distance = vips_conva_distance(conva, i, j); if (distance < worst) { conva->edge[worst_i].a = i; conva->edge[worst_i].b = j; conva->edge[worst_i].d = distance; worst_i = 0; worst = conva->edge[worst_i].d; for (k = 0; k < MAX_EDGES; k++) if (conva->edge[k].d > worst) { worst = conva->edge[k].d; worst_i = k; } } } } /* Sort to get closest first. */ qsort(conva->edge, MAX_EDGES, sizeof(Edge), edge_sortfn); /* printf("edges:\n"); printf(" n a b d:\n"); for (i = 0; i < MAX_EDGES; i++) printf("%2i) %3d %3d %3d\n", i, conva->edge[i].a, conva->edge[i].b, conva->edge[i].d); */ /* Merge from the top down. */ merged = 0; for (k = 0; k < MAX_EDGES; k++) { Edge *edge = &conva->edge[k]; if (edge->d > conva->cluster) break; /* Has been removed, see loop below. */ if (edge->a == -1) continue; vips_conva_merge(conva, edge->a, edge->b); merged = 1; /* Nodes a and b have vanished or been moved. Remove any edges * which refer to them from the edge list, */ for (i = k; i < MAX_EDGES; i++) { Edge *edgei = &conva->edge[i]; if (edgei->a == edge->a || edgei->b == edge->a || edgei->a == edge->b || edgei->b == edge->b) edgei->a = -1; } } return merged; } /* Renumber after clustering. We will have removed a lot of hlines ... shuffle * the rest down, adjust all the vline references. */ static void vips_conva_renumber(VipsConva *conva) { int i, j; VIPS_DEBUG_MSG("vips_conva_renumber: renumbering ...\n"); /* Loop for all zero-weight hlines. */ for (i = 0; i < conva->n_hline;) { if (conva->hline[i].weight > 0) { i++; continue; } /* We move hlines i + 1 down, so we need to adjust all * band[] refs to match. */ for (j = 0; j < conva->n_velement; j++) if (conva->velement[j].band > i) conva->velement[j].band -= 1; memmove(conva->hline + i, conva->hline + i + 1, sizeof(HLine) * (conva->n_hline - i - 1)); conva->n_hline -= 1; } VIPS_DEBUG_MSG("vips_conva_renumber: ... %d hlines remain\n", conva->n_hline); } /* Sort by band, then factor, then row. */ static int velement_sortfn(const void *p1, const void *p2) { VElement *a = (VElement *) p1; VElement *b = (VElement *) p2; if (a->band != b->band) return a->band - b->band; if (a->factor != b->factor) return a->factor - b->factor; return a->row - b->row; } static void vips_conva_vline(VipsConva *conva) { int y, z; VIPS_DEBUG_MSG("vips_conva_vline: forming vlines ...\n"); /* Sort to get elements which could form a vline together. */ qsort(conva->velement, conva->n_velement, sizeof(VElement), velement_sortfn); #ifdef DEBUG vips_conva_hprint(conva); #endif /*DEBUG*/ /* If two lines have the same row and band, we can join them and knock * up the factor instead. */ for (y = 0; y < conva->n_velement; y++) { for (z = y + 1; z < conva->n_velement; z++) if (conva->velement[z].band != conva->velement[y].band || conva->velement[z].row != conva->velement[y].row) break; /* We need to keep the sign of the old factor. */ if (conva->velement[y].factor > 0) conva->velement[y].factor = z - y; else conva->velement[y].factor = y - z; memmove(conva->velement + y + 1, conva->velement + z, sizeof(VElement) * (conva->n_velement - z)); conva->n_velement -= z - y - 1; } #ifdef DEBUG printf("after commoning up, %d velement remain\n", conva->n_velement); vips_conva_hprint(conva); #endif /*DEBUG*/ conva->n_vline = 0; for (y = 0; y < conva->n_velement;) { int n = conva->n_vline; /* Start of a line. */ conva->vline[n].band = conva->velement[y].band; conva->vline[n].factor = conva->velement[y].factor; conva->vline[n].start = conva->velement[y].row; /* Search for the end of this line. */ for (z = y + 1; z < conva->n_velement; z++) if (conva->velement[z].band != conva->vline[n].band || conva->velement[z].factor != conva->vline[n].factor || conva->velement[z].row != conva->vline[n].start + z - y) break; /* So the line ends at the previously examined element. We * want 'end' to be one beyond that (non-inclusive). */ conva->vline[n].end = conva->velement[z - 1].row + 1; conva->n_vline += 1; y = z; } VIPS_DEBUG_MSG("vips_conva_vline: found %d vlines\n", conva->n_vline); } /* Break a mask into boxes. */ static int vips_conva_decompose_boxes(VipsConva *conva) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(conva); VipsImage *iM = conva->iM; double *coeff = VIPS_MATRIX(iM, 0, 0); const int size = iM->Xsize * iM->Ysize; double scale = vips_image_get_scale(iM); double offset = vips_image_get_offset(iM); double sum; double area; int x, y, z; if (vips_conva_decompose_hlines(conva)) return -1; /* Cluster to find groups of lines. */ VIPS_DEBUG_MSG( "vips_conva_decompose_boxes: " "clustering hlines with thresh %d ...\n", conva->cluster); while (vips_conva_cluster2(conva)) ; /* Renumber to remove holes created by clustering. */ vips_conva_renumber(conva); /* Find a set of vlines for the remaining hlines. */ vips_conva_vline(conva); /* Find the area of the lines and the length of the longest hline. We * find the absolute area, we don't want -ves to cancel. */ area = 0; conva->max_line = 0; for (y = 0; y < conva->n_velement; y++) { x = conva->velement[y].band; z = conva->hline[x].end - conva->hline[x].start; area += abs(conva->velement[y].factor * z); if (z > conva->max_line) conva->max_line = z; } /* Strength reduction: if all lines are divisible by n, we can move * that n out into the area factor. The aim is to produce as many * factor 1 lines as we can and to reduce the chance of overflow. */ x = conva->velement[0].factor; for (y = 1; y < conva->n_velement; y++) x = gcd(x, conva->velement[y].factor); for (y = 0; y < conva->n_velement; y++) conva->velement[y].factor /= x; area *= x; /* Find the area of the original mask. Again, don't let -ves cancel. */ sum = 0; for (z = 0; z < size; z++) sum += fabs(coeff[z]); conva->divisor = VIPS_MAX(1, rint(area * scale / sum)); conva->rounding = (conva->divisor + 1) / 2; conva->offset = offset; #ifdef DEBUG vips_conva_hprint(conva); vips_conva_vprint(conva); #endif /*DEBUG*/ /* With 512x512 tiles, each hline requires 3mb of intermediate per * thread ... 300 lines is about a gb per thread, ouch. */ if (conva->n_hline > 150) { vips_error(class->nickname, "%s", _("mask too complex")); return -1; } return 0; } /* Our sequence value. */ typedef struct { VipsConva *conva; VipsRegion *ir; /* Input region */ /* Offsets for start and stop. */ int *start; int *end; int last_stride; /* Avoid recalcing offsets, if we can */ /* The rolling sums. int for integer types, double for floating point * types. */ void *sum; } VipsConvaSeq; /* Free a sequence value. */ static int vips_conva_stop(void *vseq, void *a, void *b) { VipsConvaSeq *seq = (VipsConvaSeq *) vseq; VIPS_UNREF(seq->ir); return 0; } /* Convolution start function. */ static void * vips_conva_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsConva *conva = (VipsConva *) b; VipsConvaSeq *seq; seq = VIPS_NEW(out, VipsConvaSeq); seq->conva = conva; seq->ir = vips_region_new(in); /* n_velement should be the largest possible dimension. */ g_assert(conva->n_velement >= conva->n_hline); g_assert(conva->n_velement >= conva->n_vline); seq->start = VIPS_ARRAY(out, conva->n_velement, int); seq->end = VIPS_ARRAY(out, conva->n_velement, int); if (vips_band_format_isint(out->BandFmt)) seq->sum = VIPS_ARRAY(out, conva->n_velement, int); else seq->sum = VIPS_ARRAY(out, conva->n_velement, double); seq->last_stride = -1; return seq; } /* The h and v loops are very similar, but also annoyingly different. Keep * them separate for easy debugging. */ #define HCONV(IN, OUT) \ G_STMT_START \ { \ for (i = 0; i < bands; i++) { \ OUT *seq_sum = (OUT *) seq->sum; \ \ IN *p; \ OUT *q; \ \ p = i + (IN *) VIPS_REGION_ADDR(ir, r->left, r->top + y); \ q = i * n_hline + \ (OUT *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); \ \ for (z = 0; z < n_hline; z++) { \ seq_sum[z] = 0; \ for (x = conva->hline[z].start; \ x < conva->hline[z].end; x++) \ seq_sum[z] += p[x * istride]; \ q[z] = seq_sum[z]; \ } \ q += ostride; \ \ for (x = 1; x < r->width; x++) { \ for (z = 0; z < n_hline; z++) { \ seq_sum[z] += p[seq->end[z]]; \ seq_sum[z] -= p[seq->start[z]]; \ q[z] = seq_sum[z]; \ } \ p += istride; \ q += ostride; \ } \ } \ } \ G_STMT_END /* Do horizontal masks ... we scan the mask along scanlines. */ static int vips_conva_hgenerate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConvaSeq *seq = (VipsConvaSeq *) vseq; VipsImage *in = (VipsImage *) a; VipsConva *conva = (VipsConva *) b; VipsRegion *ir = seq->ir; const int n_hline = conva->n_hline; VipsImage *iM = conva->iM; VipsRect *r = &out_region->valid; /* Double the bands (notionally) for complex. */ int bands = vips_band_format_iscomplex(in->BandFmt) ? 2 * in->Bands : in->Bands; VipsRect s; int x, y, z, i; int istride; int ostride; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += iM->Xsize - 1; if (vips_region_prepare(ir, &s)) return -1; istride = VIPS_IMAGE_SIZEOF_PEL(in) / VIPS_IMAGE_SIZEOF_ELEMENT(in); ostride = VIPS_IMAGE_SIZEOF_PEL(out_region->im) / VIPS_IMAGE_SIZEOF_ELEMENT(out_region->im); /* Init offset array. */ if (seq->last_stride != istride) { seq->last_stride = istride; for (z = 0; z < n_hline; z++) { seq->start[z] = conva->hline[z].start * istride; seq->end[z] = conva->hline[z].end * istride; } } for (y = 0; y < r->height; y++) { switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: if (conva->max_line < 256) HCONV(unsigned char, unsigned short); else HCONV(unsigned char, unsigned int); break; case VIPS_FORMAT_CHAR: if (conva->max_line < 256) HCONV(signed char, signed short); else HCONV(signed char, signed int); break; case VIPS_FORMAT_USHORT: if (conva->max_line < 256) HCONV(unsigned short, unsigned short); else HCONV(unsigned short, unsigned int); break; case VIPS_FORMAT_SHORT: if (conva->max_line < 256) HCONV(signed short, signed short); else HCONV(signed short, signed int); break; case VIPS_FORMAT_UINT: if (conva->max_line < 256) HCONV(unsigned int, unsigned short); else HCONV(unsigned int, unsigned int); break; case VIPS_FORMAT_INT: if (conva->max_line < 256) HCONV(signed int, signed short); else HCONV(signed int, signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: HCONV(float, float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: HCONV(double, double); break; default: g_assert_not_reached(); } } return 0; } static int vips_conva_horizontal(VipsConva *conva, VipsImage *in, VipsImage **out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(conva); /* Prepare output. Consider a 7x7 mask and a 7x7 image -- the output * would be 1x1. */ *out = vips_image_new(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; (*out)->Xsize -= conva->iM->Xsize - 1; if ((*out)->Xsize <= 0) { vips_error(class->nickname, "%s", _("image too small for mask")); return -1; } (*out)->Bands *= conva->n_hline; /* Short {u,}{char,short,int} lines can use {u,}short as intermediate. */ if (vips_band_format_isuint(in->BandFmt)) (*out)->BandFmt = conva->max_line < 256 ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UINT; else if (vips_band_format_isint(in->BandFmt)) (*out)->BandFmt = conva->max_line < 256 ? VIPS_FORMAT_SHORT : VIPS_FORMAT_INT; if (vips_image_generate(*out, vips_conva_start, vips_conva_hgenerate, vips_conva_stop, in, conva)) return -1; return 0; } #define CLIP_UCHAR(V) \ G_STMT_START \ { \ if ((V) < 0) \ (V) = 0; \ else if ((V) > UCHAR_MAX) \ (V) = UCHAR_MAX; \ } \ G_STMT_END #define CLIP_CHAR(V) \ G_STMT_START \ { \ if ((V) < SCHAR_MIN) \ (V) = SCHAR_MIN; \ else if ((V) > SCHAR_MAX) \ (V) = SCHAR_MAX; \ } \ G_STMT_END #define CLIP_USHORT(V) \ G_STMT_START \ { \ if ((V) < 0) \ (V) = 0; \ else if ((V) > USHRT_MAX) \ (V) = USHRT_MAX; \ } \ G_STMT_END #define CLIP_SHORT(V) \ G_STMT_START \ { \ if ((V) < SHRT_MIN) \ (V) = SHRT_MIN; \ else if ((V) > SHRT_MAX) \ (V) = SHRT_MAX; \ } \ G_STMT_END #define CLIP_NONE(V) \ { \ } #define VCONV(ACC, IN, OUT, CLIP) \ G_STMT_START \ { \ for (x = 0; x < sz; x++) { \ ACC *seq_sum = (ACC *) seq->sum; \ \ IN *p; \ OUT *q; \ ACC sum; \ \ p = x * conva->n_hline + \ (IN *) VIPS_REGION_ADDR(ir, r->left, r->top); \ q = x + (OUT *) VIPS_REGION_ADDR(out_region, r->left, r->top); \ \ sum = 0; \ for (z = 0; z < n_vline; z++) { \ seq_sum[z] = 0; \ for (k = conva->vline[z].start; \ k < conva->vline[z].end; k++) \ seq_sum[z] += p[k * istride + conva->vline[z].band]; \ sum += conva->vline[z].factor * seq_sum[z]; \ } \ sum = (sum + conva->rounding) / conva->divisor + conva->offset; \ CLIP(sum); \ *q = sum; \ q += ostride; \ \ for (y = 1; y < r->height; y++) { \ sum = 0; \ for (z = 0; z < n_vline; z++) { \ seq_sum[z] += p[seq->end[z]]; \ seq_sum[z] -= p[seq->start[z]]; \ sum += conva->vline[z].factor * seq_sum[z]; \ } \ p += istride; \ sum = (sum + conva->rounding) / conva->divisor + \ conva->offset; \ CLIP(sum); \ *q = sum; \ q += ostride; \ } \ } \ } \ G_STMT_END /* Do vertical masks ... we scan the mask down columns of pixels. */ static int vips_conva_vgenerate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConvaSeq *seq = (VipsConvaSeq *) vseq; VipsImage *in = (VipsImage *) a; VipsConva *conva = (VipsConva *) b; VipsConvolution *convolution = (VipsConvolution *) conva; VipsRegion *ir = seq->ir; const int n_vline = conva->n_vline; VipsImage *iM = conva->iM; VipsRect *r = &out_region->valid; /* Double the width (notionally) for complex. */ int sz = vips_band_format_iscomplex(in->BandFmt) ? 2 * VIPS_REGION_N_ELEMENTS(out_region) : VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int x, y, z, k; int istride; int ostride; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.height += iM->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; istride = VIPS_REGION_LSKIP(ir) / VIPS_IMAGE_SIZEOF_ELEMENT(in); ostride = VIPS_REGION_LSKIP(out_region) / VIPS_IMAGE_SIZEOF_ELEMENT(convolution->out); /* Init offset array. */ if (seq->last_stride != istride) { seq->last_stride = istride; for (z = 0; z < n_vline; z++) { seq->start[z] = conva->vline[z].band + conva->vline[z].start * istride; seq->end[z] = conva->vline[z].band + conva->vline[z].end * istride; } } switch (convolution->in->BandFmt) { case VIPS_FORMAT_UCHAR: if (conva->max_line < 256) VCONV(unsigned int, unsigned short, unsigned char, CLIP_UCHAR); else VCONV(unsigned int, unsigned int, unsigned char, CLIP_UCHAR); break; case VIPS_FORMAT_CHAR: if (conva->max_line < 256) VCONV(signed int, signed short, signed char, CLIP_CHAR); else VCONV(signed int, signed int, signed char, CLIP_CHAR); break; case VIPS_FORMAT_USHORT: if (conva->max_line < 256) VCONV(unsigned int, unsigned short, unsigned short, CLIP_USHORT); else VCONV(unsigned int, unsigned int, unsigned short, CLIP_USHORT); break; case VIPS_FORMAT_SHORT: if (conva->max_line < 256) VCONV(signed int, signed short, signed short, CLIP_SHORT); else VCONV(signed int, signed int, signed short, CLIP_SHORT); break; case VIPS_FORMAT_UINT: if (conva->max_line < 256) VCONV(unsigned int, unsigned short, unsigned int, CLIP_SHORT); else VCONV(unsigned int, unsigned int, unsigned int, CLIP_NONE); break; case VIPS_FORMAT_INT: if (conva->max_line < 256) VCONV(signed int, signed short, signed int, CLIP_NONE); else VCONV(signed int, signed int, signed int, CLIP_NONE); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: VCONV(float, float, float, CLIP_NONE); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: VCONV(double, double, double, CLIP_NONE); break; default: g_assert_not_reached(); } return 0; } static int vips_conva_vertical(VipsConva *conva, VipsImage *in, VipsImage **out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(conva); VipsConvolution *convolution = (VipsConvolution *) conva; /* Prepare output. Consider a 7x7 mask and a 7x7 image -- the output * would be 1x1. */ *out = vips_image_new(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; (*out)->Ysize -= conva->iM->Ysize - 1; if ((*out)->Ysize <= 0) { vips_error(class->nickname, "%s", _("image too small for mask")); return -1; } (*out)->Bands = convolution->in->Bands; (*out)->BandFmt = convolution->in->BandFmt; if (vips_image_generate(*out, vips_conva_start, vips_conva_vgenerate, vips_conva_stop, in, conva)) return -1; return 0; } static int vips_conva_build(VipsObject *object) { VipsConvolution *convolution = (VipsConvolution *) object; VipsConva *conva = (VipsConva *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_conva_parent_class)->build(object)) return -1; /* An int version of our mask. */ if (vips__image_intize(convolution->M, &t[0])) return -1; conva->iM = t[0]; #ifdef DEBUG printf("vips_conva_build: iM =\n"); vips_matrixprint(conva->iM, NULL); #endif /*DEBUG*/ in = convolution->in; if (vips_conva_decompose_boxes(conva)) return -1; g_object_set(conva, "out", vips_image_new(), NULL); if ( vips_embed(in, &t[1], t[0]->Xsize / 2, t[0]->Ysize / 2, in->Xsize + t[0]->Xsize - 1, in->Ysize + t[0]->Ysize - 1, "extend", VIPS_EXTEND_COPY, NULL) || vips_conva_horizontal(conva, t[1], &t[2]) || vips_conva_vertical(conva, t[2], &t[3]) || vips_image_write(t[3], convolution->out)) return -1; convolution->out->Xoffset = 0; convolution->out->Yoffset = 0; return 0; } static void vips_conva_class_init(VipsConvaClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "conva"; object_class->description = _("approximate integer convolution"); object_class->build = vips_conva_build; VIPS_ARG_INT(class, "layers", 104, _("Layers"), _("Use this many layers in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConva, layers), 1, 1000, 5); VIPS_ARG_INT(class, "cluster", 105, _("Cluster"), _("Cluster lines closer than this in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConva, cluster), 1, 100, 1); } static void vips_conva_init(VipsConva *conva) { conva->layers = 5; conva->cluster = 1; } /** * vips_conva: (method) * @in: input image * @out: (out): output image * @mask: convolution mask * @...: `NULL`-terminated list of optional named arguments * * Perform an approximate integer convolution of @in with @mask. * This is a low-level operation, see [method@Image.conv] for something more * convenient. * * The output image * always has the same [enum@BandFormat] as the input image. * Elements of @mask are converted to * integers before convolution. * * Larger values for @layers give more accurate * results, but are slower. As @layers approaches the mask radius, the * accuracy will become close to exact convolution and the speed will drop to * match. For many large masks, such as Gaussian, @layers need be only 10% of * this value and accuracy will still be good. * * Smaller values of @cluster will give more accurate results, but be slower * and use more memory. 10% of the mask radius is a good rule of thumb. * * ::: tip "Optional arguments" * * @layers: `gint`, number of layers for approximation * * @cluster: `gint`, cluster lines closer than this distance * * ::: seealso * [method@Image.conv]. * * Returns: 0 on success, -1 on error */ int vips_conva(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("conva", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/convasep.c000066400000000000000000000542111516303661500213040ustar00rootroot00000000000000/* convasep ... separable approximate convolution * * This operation does an approximate, separable convolution. * * Author: John Cupitt & Nicolas Robidoux * Written on: 31/5/11 * Modified on: * 31/5/11 * - from im_conv() * 5/7/16 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* See: http://incubator.quasimondo.com/processing/stackblur.pde This thing is a little like stackblur, but generalised to any separable mask. */ /* TODO - how about making a cumulative image and then subtracting points in that, rather than keeping a set of running totals faster? we could then use orc to write a bit of code to implement this set of lines stackoverflow has an algorithm for cumulativization using SIMD and threads, see that font rasterization with rust piece on medium by ralph levien */ /* #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "pconvolution.h" /* Maximum number of lines we can break the mask into. */ #define MAX_LINES (1000) /* Euclid's algorithm. Use this to common up mults. */ static int gcd(int a, int b) { if (b == 0) return abs(a); else return gcd(b, a % b); } typedef struct { VipsConvolution parent_instance; int layers; int divisor; int rounding; int offset; /* The "width" of the mask, ie. n for our 1xn or nx1 argument, plus * an int version of our mask. */ int width; VipsImage *iM; /* The mask broken into a set of lines. * * Start is the left-most pixel in the line, end is one beyond the * right-most pixel. */ int n_lines; int start[MAX_LINES]; int end[MAX_LINES]; int factor[MAX_LINES]; } VipsConvasep; typedef VipsConvolutionClass VipsConvasepClass; G_DEFINE_TYPE(VipsConvasep, vips_convasep, VIPS_TYPE_CONVOLUTION); static void vips_convasep_line_start(VipsConvasep *convasep, int x, int factor) { convasep->start[convasep->n_lines] = x; convasep->factor[convasep->n_lines] = factor; } static int vips_convasep_line_end(VipsConvasep *convasep, int x) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(convasep); convasep->end[convasep->n_lines] = x; if (convasep->n_lines >= MAX_LINES - 1) { vips_error(class->nickname, "%s", _("mask too complex")); return -1; } convasep->n_lines += 1; return 0; } /* Break a mask into lines. */ static int vips_convasep_decompose(VipsConvasep *convasep) { VipsImage *iM = convasep->iM; double *coeff = (double *) VIPS_IMAGE_ADDR(iM, 0, 0); double scale = vips_image_get_scale(iM); double offset = vips_image_get_offset(iM); double max; double min; double depth; double sum; double area; int layers; int layers_above; int layers_below; int z, n, x; VIPS_DEBUG_MSG( "vips_convasep_decompose: " "breaking into %d layers ...\n", convasep->layers); /* Find mask range. We must always include the zero axis in the mask. */ max = 0; min = 0; for (x = 0; x < convasep->width; x++) { max = VIPS_MAX(max, coeff[x]); min = VIPS_MIN(min, coeff[x]); } /* The zero axis must fall on a layer boundary. Estimate the * depth, find n-lines-above-zero, get exact depth, then calculate a * fixed n-lines which includes any negative parts. */ depth = (max - min) / convasep->layers; layers_above = ceil(max / depth); depth = max / layers_above; layers_below = floor(min / depth); layers = VIPS_CLIP(1, (int64_t) layers_above - layers_below, 1000); VIPS_DEBUG_MSG("depth = %g, layers = %d\n", depth, layers); /* For each layer, generate a set of lines which are inside the * perimeter. Work down from the top. */ for (z = 0; z < layers; z++) { double y = max - (1 + z) * depth; /* y plus half depth ... ie. the layer midpoint. */ double y_ph = y + depth / 2; /* Odd, but we must avoid rounding errors that make us miss 0 * in the line above. */ int y_positive = z < layers_above; int inside; /* Start outside the perimeter. */ inside = 0; for (x = 0; x < convasep->width; x++) { /* The vertical line from mask[z] to 0 is inside. Is * our current square (x, y) part of that line? */ if ((y_positive && coeff[x] >= y_ph) || (!y_positive && coeff[x] <= y_ph)) { if (!inside) { vips_convasep_line_start(convasep, x, y_positive ? 1 : -1); inside = 1; } } else if (inside) { if (vips_convasep_line_end(convasep, x)) return -1; inside = 0; } } if (inside && vips_convasep_line_end(convasep, convasep->width)) return -1; } /* Can we common up any lines? Search for lines with identical * start/end. */ for (z = 0; z < convasep->n_lines; z++) { for (n = z + 1; n < convasep->n_lines; n++) { if (convasep->start[z] == convasep->start[n] && convasep->end[z] == convasep->end[n]) { convasep->factor[z] += convasep->factor[n]; /* n can be deleted. Do this in a separate * pass below. */ convasep->factor[n] = 0; } } } /* Now we can remove all factor 0 lines. */ for (z = 0; z < convasep->n_lines; z++) { if (convasep->factor[z] == 0) { for (x = z; x < convasep->n_lines; x++) { convasep->start[x] = convasep->start[x + 1]; convasep->end[x] = convasep->end[x + 1]; convasep->factor[x] = convasep->factor[x + 1]; } convasep->n_lines -= 1; } } /* Find the area of the lines. */ area = 0; for (z = 0; z < convasep->n_lines; z++) area += convasep->factor[z] * (convasep->end[z] - convasep->start[z]); /* Strength reduction: if all lines are divisible by n, we can move * that n out into the ->area factor. The aim is to produce as many * factor 1 lines as we can and to reduce the chance of overflow. */ x = convasep->factor[0]; for (z = 1; z < convasep->n_lines; z++) x = gcd(x, convasep->factor[z]); for (z = 0; z < convasep->n_lines; z++) convasep->factor[z] /= x; area *= x; /* Find the area of the original mask. */ sum = 0; for (z = 0; z < convasep->width; z++) sum += coeff[z]; convasep->divisor = VIPS_MAX(1, rint(sum * area / scale)); convasep->rounding = (convasep->divisor + 1) / 2; convasep->offset = offset; #ifdef DEBUG /* ASCII-art layer drawing. */ printf("lines:\n"); for (z = 0; z < convasep->n_lines; z++) { printf("%3d - %2d x ", z, convasep->factor[z]); for (x = 0; x < 55; x++) { int rx = x * (convasep->width + 1) / 55; if (rx >= convasep->start[z] && rx < convasep->end[z]) printf("#"); else printf(" "); } printf(" %3d .. %3d\n", convasep->start[z], convasep->end[z]); } printf("divisor = %d\n", convasep->divisor); printf("rounding = %d\n", convasep->rounding); printf("offset = %d\n", convasep->offset); #endif /*DEBUG*/ return 0; } /* Our sequence value. */ typedef struct { VipsConvasep *convasep; VipsRegion *ir; /* Input region */ int *start; /* Offsets for start and stop */ int *end; /* The sums for each line. int for integer types, double for floating * point types. */ void *sum; int last_stride; /* Avoid recalcing offsets, if we can */ } VipsConvasepSeq; /* Free a sequence value. */ static int vips_convasep_stop(void *vseq, void *a, void *b) { VipsConvasepSeq *seq = (VipsConvasepSeq *) vseq; VIPS_UNREF(seq->ir); VIPS_FREE(seq->start); VIPS_FREE(seq->end); VIPS_FREE(seq->sum); return 0; } /* Convolution start function. */ static void * vips_convasep_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsConvasep *convasep = (VipsConvasep *) b; VipsConvasepSeq *seq; if (!(seq = VIPS_NEW(out, VipsConvasepSeq))) return NULL; /* Init! */ seq->convasep = convasep; seq->ir = vips_region_new(in); seq->start = VIPS_ARRAY(NULL, convasep->n_lines, int); seq->end = VIPS_ARRAY(NULL, convasep->n_lines, int); if (vips_band_format_isint(out->BandFmt)) seq->sum = VIPS_ARRAY(NULL, convasep->n_lines, int); else seq->sum = VIPS_ARRAY(NULL, convasep->n_lines, double); seq->last_stride = -1; if (!seq->ir || !seq->start || !seq->end || !seq->sum) { vips_convasep_stop(seq, in, convasep); return NULL; } return seq; } #define CLIP_UCHAR(V) \ G_STMT_START \ { \ if ((V) < 0) \ (V) = 0; \ else if ((V) > UCHAR_MAX) \ (V) = UCHAR_MAX; \ } \ G_STMT_END #define CLIP_CHAR(V) \ G_STMT_START \ { \ if ((V) < SCHAR_MIN) \ (V) = SCHAR_MIN; \ else if ((V) > SCHAR_MAX) \ (V) = SCHAR_MAX; \ } \ G_STMT_END #define CLIP_USHORT(V) \ G_STMT_START \ { \ if ((V) < 0) \ (V) = 0; \ else if ((V) > USHRT_MAX) \ (V) = USHRT_MAX; \ } \ G_STMT_END #define CLIP_SHORT(V) \ G_STMT_START \ { \ if ((V) < SHRT_MIN) \ (V) = SHRT_MIN; \ else if ((V) > SHRT_MAX) \ (V) = SHRT_MAX; \ } \ G_STMT_END #define CLIP_NONE(V) \ { \ } /* The h and v loops are very similar, but also annoyingly different. Keep * them separate for easy debugging. */ #define HCONV_INT(ACC, TYPE, CLIP) \ { \ for (i = 0; i < bands; i++) { \ ACC *isum = (ACC *) seq->sum; \ \ TYPE *q; \ TYPE *p; \ int64_t sum; \ \ p = i + (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top + y); \ q = i + (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); \ \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ isum[z] = 0; \ for (x = seq->start[z]; x < seq->end[z]; x += istride) \ isum[z] += p[x]; \ sum += (int64_t) convasep->factor[z] * isum[z]; \ } \ \ /* Don't add offset ... we only want to do that once, do it on \ * the vertical pass. \ */ \ sum = (sum + convasep->rounding) / convasep->divisor; \ CLIP(sum); \ *q = sum; \ q += ostride; \ \ for (x = 1; x < r->width; x++) { \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ isum[z] += p[seq->end[z]]; \ isum[z] -= p[seq->start[z]]; \ sum += (int64_t) convasep->factor[z] * isum[z]; \ } \ p += istride; \ sum = (sum + convasep->rounding) / convasep->divisor; \ CLIP(sum); \ *q = sum; \ q += ostride; \ } \ } \ } #define HCONV_FLOAT(TYPE) \ { \ for (i = 0; i < bands; i++) { \ double *dsum = (double *) seq->sum; \ \ TYPE *q; \ TYPE *p; \ double sum; \ \ p = i + (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top + y); \ q = i + (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); \ \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ dsum[z] = 0; \ for (x = seq->start[z]; x < seq->end[z]; x += istride) \ dsum[z] += p[x]; \ sum += convasep->factor[z] * dsum[z]; \ } \ \ /* Don't add offset ... we only want to do that once, do it on \ * the vertical pass. \ */ \ sum = sum / convasep->divisor; \ *q = sum; \ q += ostride; \ \ for (x = 1; x < r->width; x++) { \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ dsum[z] += p[seq->end[z]]; \ dsum[z] -= p[seq->start[z]]; \ sum += convasep->factor[z] * dsum[z]; \ } \ p += istride; \ sum = sum / convasep->divisor; \ *q = sum; \ q += ostride; \ } \ } \ } /* Do horizontal masks ... we scan the mask along scanlines. */ static int vips_convasep_generate_horizontal(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConvasepSeq *seq = (VipsConvasepSeq *) vseq; VipsImage *in = (VipsImage *) a; VipsConvasep *convasep = (VipsConvasep *) b; VipsConvolution *convolution = (VipsConvolution *) convasep; VipsRegion *ir = seq->ir; const int n_lines = convasep->n_lines; VipsRect *r = &out_region->valid; /* Double the bands (notionally) for complex. */ int bands = vips_band_format_iscomplex(in->BandFmt) ? 2 * in->Bands : in->Bands; VipsRect s; int x, y, z, i; int istride; int ostride; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += convasep->width - 1; if (vips_region_prepare(ir, &s)) return -1; /* Stride can be different for the vertical case, keep this here for * ease of direction change. */ istride = VIPS_IMAGE_SIZEOF_PEL(in) / VIPS_IMAGE_SIZEOF_ELEMENT(in); ostride = VIPS_IMAGE_SIZEOF_PEL(convolution->out) / VIPS_IMAGE_SIZEOF_ELEMENT(convolution->out); /* Init offset array. */ if (seq->last_stride != istride) { seq->last_stride = istride; for (z = 0; z < n_lines; z++) { seq->start[z] = convasep->start[z] * istride; seq->end[z] = convasep->end[z] * istride; } } for (y = 0; y < r->height; y++) { switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: HCONV_INT(unsigned int, unsigned char, CLIP_UCHAR); break; case VIPS_FORMAT_CHAR: HCONV_INT(signed int, signed char, CLIP_CHAR); break; case VIPS_FORMAT_USHORT: HCONV_INT(unsigned int, unsigned short, CLIP_USHORT); break; case VIPS_FORMAT_SHORT: HCONV_INT(signed int, signed short, CLIP_SHORT); break; case VIPS_FORMAT_UINT: HCONV_INT(unsigned int, unsigned int, CLIP_NONE); break; case VIPS_FORMAT_INT: HCONV_INT(signed int, signed int, CLIP_NONE); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: HCONV_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: HCONV_FLOAT(double); break; default: g_assert_not_reached(); } } return 0; } #define VCONV_INT(ACC, TYPE, CLIP) \ { \ for (x = 0; x < sz; x++) { \ ACC *isum = (ACC *) seq->sum; \ \ TYPE *q; \ TYPE *p; \ int64_t sum; \ \ p = x + (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top); \ q = x + (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top); \ \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ isum[z] = 0; \ for (y = seq->start[z]; y < seq->end[z]; y += istride) \ isum[z] += p[y]; \ sum += (int64_t) convasep->factor[z] * isum[z]; \ } \ sum = (sum + convasep->rounding) / convasep->divisor + \ convasep->offset; \ CLIP(sum); \ *q = sum; \ q += ostride; \ \ for (y = 1; y < r->height; y++) { \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ isum[z] += p[seq->end[z]]; \ isum[z] -= p[seq->start[z]]; \ sum += (int64_t) convasep->factor[z] * isum[z]; \ } \ p += istride; \ sum = (sum + convasep->rounding) / convasep->divisor + \ convasep->offset; \ CLIP(sum); \ *q = sum; \ q += ostride; \ } \ } \ } #define VCONV_FLOAT(TYPE) \ { \ for (x = 0; x < sz; x++) { \ double *dsum = (double *) seq->sum; \ \ TYPE *q; \ TYPE *p; \ double sum; \ \ p = x + (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top); \ q = x + (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top); \ \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ dsum[z] = 0; \ for (y = seq->start[z]; y < seq->end[z]; y += istride) \ dsum[z] += p[y]; \ sum += convasep->factor[z] * dsum[z]; \ } \ sum = sum / convasep->divisor + convasep->offset; \ *q = sum; \ q += ostride; \ \ for (y = 1; y < r->height; y++) { \ sum = 0; \ for (z = 0; z < n_lines; z++) { \ dsum[z] += p[seq->end[z]]; \ dsum[z] -= p[seq->start[z]]; \ sum += convasep->factor[z] * dsum[z]; \ } \ p += istride; \ sum = sum / convasep->divisor + convasep->offset; \ *q = sum; \ q += ostride; \ } \ } \ } /* Do vertical masks ... we scan the mask down columns of pixels. Copy-paste * from above with small changes. */ static int vips_convasep_generate_vertical(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConvasepSeq *seq = (VipsConvasepSeq *) vseq; VipsImage *in = (VipsImage *) a; VipsConvasep *convasep = (VipsConvasep *) b; VipsConvolution *convolution = (VipsConvolution *) convasep; VipsRegion *ir = seq->ir; const int n_lines = convasep->n_lines; VipsRect *r = &out_region->valid; /* Double the width (notionally) for complex. */ int sz = vips_band_format_iscomplex(in->BandFmt) ? 2 * VIPS_REGION_N_ELEMENTS(out_region) : VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int x, y, z; int istride; int ostride; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.height += convasep->width - 1; if (vips_region_prepare(ir, &s)) return -1; /* Stride can be different for the vertical case, keep this here for * ease of direction change. */ istride = VIPS_REGION_LSKIP(ir) / VIPS_IMAGE_SIZEOF_ELEMENT(in); ostride = VIPS_REGION_LSKIP(out_region) / VIPS_IMAGE_SIZEOF_ELEMENT(convolution->out); /* Init offset array. */ if (seq->last_stride != istride) { seq->last_stride = istride; for (z = 0; z < n_lines; z++) { seq->start[z] = convasep->start[z] * istride; seq->end[z] = convasep->end[z] * istride; } } switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: VCONV_INT(unsigned int, unsigned char, CLIP_UCHAR); break; case VIPS_FORMAT_CHAR: VCONV_INT(signed int, signed char, CLIP_CHAR); break; case VIPS_FORMAT_USHORT: VCONV_INT(unsigned int, unsigned short, CLIP_USHORT); break; case VIPS_FORMAT_SHORT: VCONV_INT(signed int, signed short, CLIP_SHORT); break; case VIPS_FORMAT_UINT: VCONV_INT(unsigned int, unsigned int, CLIP_NONE); break; case VIPS_FORMAT_INT: VCONV_INT(signed int, signed int, CLIP_NONE); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: VCONV_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: VCONV_FLOAT(double); break; default: g_assert_not_reached(); } return 0; } static int vips_convasep_pass(VipsConvasep *convasep, VipsImage *in, VipsImage **out, VipsDirection direction) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(convasep); VipsGenerateFn gen; *out = vips_image_new(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; if (direction == VIPS_DIRECTION_HORIZONTAL) { (*out)->Xsize -= convasep->width - 1; gen = vips_convasep_generate_horizontal; } else { (*out)->Ysize -= convasep->width - 1; gen = vips_convasep_generate_vertical; } if ((*out)->Xsize <= 0 || (*out)->Ysize <= 0) { vips_error(class->nickname, "%s", _("image too small for mask")); return -1; } if (vips_image_generate(*out, vips_convasep_start, gen, vips_convasep_stop, in, convasep)) return -1; return 0; } static int vips_convasep_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConvolution *convolution = (VipsConvolution *) object; VipsConvasep *convasep = (VipsConvasep *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_convasep_parent_class)->build(object)) return -1; if (vips_check_separable(class->nickname, convolution->M)) return -1; /* An int version of our mask. */ if (vips__image_intize(convolution->M, &t[3])) return -1; convasep->iM = t[3]; convasep->width = convasep->iM->Xsize * convasep->iM->Ysize; in = convolution->in; if (vips_convasep_decompose(convasep)) return -1; g_object_set(convasep, "out", vips_image_new(), NULL); if ( vips_embed(in, &t[0], convasep->width / 2, convasep->width / 2, in->Xsize + convasep->width - 1, in->Ysize + convasep->width - 1, "extend", VIPS_EXTEND_COPY, NULL) || vips_convasep_pass(convasep, t[0], &t[1], VIPS_DIRECTION_HORIZONTAL) || vips_convasep_pass(convasep, t[1], &t[2], VIPS_DIRECTION_VERTICAL) || vips_image_write(t[2], convolution->out)) return -1; convolution->out->Xoffset = 0; convolution->out->Yoffset = 0; vips_reorder_margin_hint(convolution->out, convolution->M->Xsize * convolution->M->Ysize); return 0; } static void vips_convasep_class_init(VipsConvasepClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "convasep"; object_class->description = _("approximate separable integer convolution"); object_class->build = vips_convasep_build; VIPS_ARG_INT(class, "layers", 104, _("Layers"), _("Use this many layers in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConvasep, layers), 1, 1000, 5); } static void vips_convasep_init(VipsConvasep *convasep) { convasep->layers = 5; convasep->n_lines = 0; } /** * vips_convasep: (method) * @in: input image * @out: (out): output image * @mask: convolve with this mask * @...: `NULL`-terminated list of optional named arguments * * Approximate separable integer convolution. This is a low-level operation, see * [method@Image.convsep] for something more convenient. * * The image is convolved twice: once with @mask and then again with @mask * rotated by 90 degrees. * @mask must be 1xn or nx1 elements. * Elements of @mask are converted to * integers before convolution. * * Larger values for @layers give more accurate * results, but are slower. As @layers approaches the mask radius, the * accuracy will become close to exact convolution and the speed will drop to * match. For many large masks, such as Gaussian, @layers need be only 10% of * this value and accuracy will still be good. * * The output image * always has the same [enum@BandFormat] as the input image. * * ::: tip "Optional arguments" * * @layers: `gint`, number of layers for approximation * * ::: seealso * [method@Image.convsep]. * * Returns: 0 on success, -1 on error */ int vips_convasep(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("convasep", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/convf.c000066400000000000000000000232051516303661500206000ustar00rootroot00000000000000/* convf * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris & Kirk Martinez * Written on: 29/04/1991 * Modified on: 19/05/1991 * 8/7/93 JC * - adapted for partial v2 * - memory leaks fixed * - ANSIfied * 12/7/93 JC * - adapted im_convbi() to im_convbf() * 7/10/94 JC * - new IM_ARRAY() macro * - evalend callbacks * - more typedef * 9/3/01 JC * - redone from im_conv() * 27/7/01 JC * - rejects masks with scale == 0 * 7/4/04 * - now uses im_embed() with edge stretching on the input, not * the output * - sets Xoffset / Yoffset * 11/11/05 * - simpler inner loop avoids gcc4 bug * 12/11/09 * - only rebuild the buffer offsets if bpl changes * - tiny speedups and cleanups * - add restrict, though it doesn't seem to help gcc * - add mask-all-zero check * 13/11/09 * - rename as im_conv_f() to make it easier for vips.c to make the * overloaded version * 3/2/10 * - gtkdoc * - more cleanups * 1/10/10 * - support complex (just double the bands) * 29/10/10 * - get rid of im_convsep_f(), just call this twice, no longer worth * keeping two versions * 15/10/11 Nicolas * - handle offset correctly in separable convolutions * 26/1/16 Lovell Fuller * - remove Duff for a 25% speedup * 23/6/16 * - redone as a class * 2/7/17 * - remove pts for a small speedup * 2/8/22 kleisauke * - bake the scale into the mask */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconvolution.h" typedef struct { VipsConvolution parent_instance; /* We make a smaller version of the mask with the zeros squeezed out. */ int nnz; /* Number of non-zero mask elements */ double *coeff; /* Array of non-zero mask coefficients */ int *coeff_pos; /* Index of each nnz element in mask->coeff */ } VipsConvf; typedef VipsConvolutionClass VipsConvfClass; G_DEFINE_TYPE(VipsConvf, vips_convf, VIPS_TYPE_CONVOLUTION); /* Our sequence value. */ typedef struct { VipsConvf *convf; VipsRegion *ir; /* Input region */ int *offsets; /* Offsets for each non-zero matrix element */ int last_bpl; /* Avoid recalcing offsets, if we can */ } VipsConvfSequence; /* Free a sequence value. */ static int vips_convf_stop(void *vseq, void *a, void *b) { VipsConvfSequence *seq = (VipsConvfSequence *) vseq; VIPS_UNREF(seq->ir); return 0; } /* Convolution start function. */ static void * vips_convf_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsConvf *convf = (VipsConvf *) b; VipsConvfSequence *seq; if (!(seq = VIPS_NEW(out, VipsConvfSequence))) return NULL; seq->convf = convf; seq->ir = NULL; seq->last_bpl = -1; seq->ir = vips_region_new(in); if (!(seq->offsets = VIPS_ARRAY(out, convf->nnz, int))) { vips_convf_stop(seq, in, convf); return NULL; } return (void *) seq; } #define CONV_FLOAT(ITYPE, OTYPE) \ { \ ITYPE *restrict p = (ITYPE *) VIPS_REGION_ADDR(ir, le, y); \ OTYPE *restrict q = (OTYPE *) VIPS_REGION_ADDR(out_region, le, y); \ int *restrict offsets = seq->offsets; \ \ for (x = 0; x < sz; x++) { \ double sum; \ int i; \ \ sum = offset; \ for (i = 0; i < nnz; i++) \ sum += t[i] * p[offsets[i]]; \ \ q[x] = sum; \ p += 1; \ } \ } /* Convolve! */ static int vips_convf_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConvfSequence *seq = (VipsConvfSequence *) vseq; VipsConvf *convf = (VipsConvf *) b; VipsConvolution *convolution = (VipsConvolution *) convf; VipsImage *M = convolution->M; double offset = vips_image_get_offset(M); VipsImage *in = (VipsImage *) a; VipsRegion *ir = seq->ir; double *restrict t = convf->coeff; const int nnz = convf->nnz; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int sz = VIPS_REGION_N_ELEMENTS(out_region) * (vips_band_format_iscomplex(in->BandFmt) ? 2 : 1); VipsRect s; int x, y, z, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; /* Fill offset array. Only do this if the bpl has changed since the * previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); for (i = 0; i < nnz; i++) { z = convf->coeff_pos[i]; x = z % M->Xsize; y = z / M->Xsize; seq->offsets[i] = (VIPS_REGION_ADDR(ir, x + le, y + to) - VIPS_REGION_ADDR(ir, le, to)) / VIPS_IMAGE_SIZEOF_ELEMENT(ir->im); } } VIPS_GATE_START("vips_convf_gen: work"); for (y = to; y < bo; y++) { switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: CONV_FLOAT(unsigned char, float); break; case VIPS_FORMAT_CHAR: CONV_FLOAT(signed char, float); break; case VIPS_FORMAT_USHORT: CONV_FLOAT(unsigned short, float); break; case VIPS_FORMAT_SHORT: CONV_FLOAT(signed short, float); break; case VIPS_FORMAT_UINT: CONV_FLOAT(unsigned int, float); break; case VIPS_FORMAT_INT: CONV_FLOAT(signed int, float); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: CONV_FLOAT(float, float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: CONV_FLOAT(double, double); break; default: g_assert_not_reached(); } } VIPS_GATE_STOP("vips_convf_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_convf_gen"); return 0; } static int vips_convf_build(VipsObject *object) { VipsConvolution *convolution = (VipsConvolution *) object; VipsConvf *convf = (VipsConvf *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; VipsImage *M; double *coeff; int ne; int i; double scale; if (VIPS_OBJECT_CLASS(vips_convf_parent_class)->build(object)) return -1; M = convolution->M; coeff = (double *) VIPS_IMAGE_ADDR(M, 0, 0); ne = M->Xsize * M->Ysize; /* Bake the scale into the mask. */ scale = vips_image_get_scale(M); for (i = 0; i < ne; i++) coeff[i] /= scale; if (!(convf->coeff = VIPS_ARRAY(object, ne, double)) || !(convf->coeff_pos = VIPS_ARRAY(object, ne, int))) return -1; /* Find non-zero mask elements. */ for (i = 0; i < ne; i++) if (coeff[i]) { convf->coeff[convf->nnz] = coeff[i]; convf->coeff_pos[convf->nnz] = i; convf->nnz += 1; } /* Was the whole mask zero? We must have at least 1 element * in there: set it to zero. */ if (convf->nnz == 0) { convf->coeff[0] = 0; convf->coeff_pos[0] = 0; convf->nnz = 1; } in = convolution->in; if (vips_embed(in, &t[0], M->Xsize / 2, M->Ysize / 2, in->Xsize + M->Xsize - 1, in->Ysize + M->Ysize - 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[0]; g_object_set(convf, "out", vips_image_new(), NULL); if (vips_image_pipelinev(convolution->out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; convolution->out->Xoffset = 0; convolution->out->Yoffset = 0; /* Prepare output. Consider a 7x7 mask and a 7x7 image -- the output * would be 1x1. */ if (vips_band_format_isint(in->BandFmt)) convolution->out->BandFmt = VIPS_FORMAT_FLOAT; convolution->out->Xsize -= M->Xsize - 1; convolution->out->Ysize -= M->Ysize - 1; if (vips_image_generate(convolution->out, vips_convf_start, vips_convf_gen, vips_convf_stop, in, convf)) return -1; convolution->out->Xoffset = -M->Xsize / 2; convolution->out->Yoffset = -M->Ysize / 2; return 0; } static void vips_convf_class_init(VipsConvfClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "convf"; object_class->description = _("float convolution operation"); object_class->build = vips_convf_build; } static void vips_convf_init(VipsConvf *convf) { convf->nnz = 0; convf->coeff = NULL; convf->coeff_pos = NULL; } /** * vips_convf: (method) * @in: input image * @out: (out): output image * @mask: convolve with this mask * @...: `NULL`-terminated list of optional named arguments * * Convolution. This is a low-level operation, see [method@Image.conv] for something * more convenient. * * Perform a convolution of @in with @mask. * Each output pixel is * calculated as sigma[i]{pixel[i] * mask[i]} / scale + offset, where scale * and offset are part of @mask. * * The convolution is performed with floating-point arithmetic. The output image * is always [enum@Vips.BandFormat.FLOAT] unless @in is [enum@Vips.BandFormat.DOUBLE], in which case * @out is also [enum@Vips.BandFormat.DOUBLE]. * * ::: seealso * [method@Image.conv]. * * Returns: 0 on success, -1 on error */ int vips_convf(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("convf", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/convi.c000066400000000000000000000745721516303661500206200ustar00rootroot00000000000000/* convi * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris & Kirk Martinez * Written on: 29/04/1991 * Modified on: 19/05/1991 * 8/7/93 JC * - adapted for partial v2 * - memory leaks fixed * - ANSIfied * 23/7/93 JC * - inner loop unrolled with a switch - 25% speed-up! * 13/12/93 JC * - tiny rounding error removed * 7/10/94 JC * - new IM_ARRAY() macro * - various simplifications * - evalend callback added * 1/2/95 JC * - use of IM_REGION_ADDR() updated * - output size was incorrect! see comment below * - bug with large non-square matrices fixed too * - uses new im_embed() function * 13/7/98 JC * - weird bug ... im_free_imask is no longer directly called for close * callback, caused SIGKILL on solaris 2.6 ... linker bug? * 9/3/01 JC * - reworked and simplified, about 10% faster * - slightly better range clipping * 27/7/01 JC * - reject masks with scale == 0 * 7/4/04 * - im_conv() now uses im_embed() with edge stretching on the input, not * the output * - sets Xoffset / Yoffset * 11/11/05 * - simpler inner loop avoids gcc4 bug * 7/11/07 * - new evalstart/end callbacks * 12/5/08 * - int rounding was +1 too much, argh * - only rebuild the buffer offsets if bpl changes * 5/4/09 * - tiny speedups and cleanups * - add restrict, though it doesn't seem to help gcc * 12/11/09 * - only check for non-zero elements once * - add mask-all-zero check * - cleanups * 3/2/10 * - gtkdoc * - more cleanups * 23/08/10 * - add a special case for 3x3 masks, about 20% faster * 1/10/10 * - support complex (just double the bands) * 18/10/10 * - add experimental Orc path * 29/10/10 * - use VipsVector * - get rid of im_convsep(), just call this twice, no longer worth * keeping two versions * 8/11/10 * - add array tiling * 9/5/11 * - argh typo in overflow estimation could cause errors * 15/10/11 Nicolas * - handle offset correctly in separable convolutions * 26/1/16 Lovell Fuller * - remove Duff for a 25% speedup * 23/6/16 * - rewritten as a class * - new fixed-point vector path, up to 2x faster * 2/7/17 * - remove pts for a small speedup * 12/10/17 * - fix leak of vectors, thanks MHeimbuc * 14/10/17 * - switch to half-float for vector path */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define DEBUG_PIXELS #define DEBUG_COMPILE */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pconvolution.h" #ifdef HAVE_ORC #include /* Larger than this and we fall back to C. */ #define MAX_PASS (20) #define MAX_SOURCES (8 /*ORC_MAX_SRC_VARS*/) /* A pass with a vector. */ typedef struct { int first; /* The index of the first mask coff we use */ int last; /* The index of the last mask coff we use */ int r; /* Set previous result in this var */ int d1; /* The destination var */ int n_const; int n_scanline; /* The associated line corresponding to the scanline. */ int line[MAX_SOURCES]; /* The code we generate for this section of the mask. */ OrcProgram *program; } Pass; #endif /*HAVE_ORC*/ typedef struct { VipsConvolution parent_instance; int n_point; /* w * h for our matrix */ /* We make a smaller version of the mask with the zeros squeezed out. */ int nnz; /* Number of non-zero mask elements */ int *coeff; /* Array of non-zero mask coefficients */ int *coeff_pos; /* Index of each nnz element in mask->coeff */ #if defined(HAVE_HWY) || defined(HAVE_ORC) /* And a half float version for the vector paths. mant has the signed * 8-bit mantissas in [-1, +1), exp has the final exponent shift before * write-back. */ short *mant; int exp; #endif /*HAVE_HWY || HAVE_ORC*/ #ifdef HAVE_ORC /* sexp has the exponent shift after the mul and before the add. */ int sexp; /* The set of passes we need for this mask. */ int n_pass; Pass pass[MAX_PASS]; /* Code for the final clip back to 8 bits. */ int r; int d1; OrcProgram *program; #endif /*HAVE_ORC*/ } VipsConvi; typedef VipsConvolutionClass VipsConviClass; G_DEFINE_TYPE(VipsConvi, vips_convi, VIPS_TYPE_CONVOLUTION); /* Our sequence value. */ typedef struct { VipsConvi *convi; VipsRegion *ir; /* Input region */ int *offsets; /* Offsets for each non-zero matrix element */ int last_bpl; /* Avoid recalcing offsets, if we can */ #ifdef HAVE_ORC /* We need a pair of intermediate buffers to keep the results of each * vector conv pass. */ short *t1; short *t2; #endif /*HAVE_ORC*/ } VipsConviSequence; #ifdef HAVE_ORC static void vips_convi_finalize(GObject *gobject) { VipsConvi *convi = (VipsConvi *) gobject; for (int i = 0; i < convi->n_pass; i++) VIPS_FREEF(orc_program_free, convi->pass[i].program); convi->n_pass = 0; VIPS_FREEF(orc_program_free, convi->program); G_OBJECT_CLASS(vips_convi_parent_class)->finalize(gobject); } #endif /*HAVE_ORC*/ /* Free a sequence value. */ static int vips_convi_stop(void *vseq, void *a, void *b) { VipsConviSequence *seq = (VipsConviSequence *) vseq; VIPS_UNREF(seq->ir); VIPS_FREE(seq->offsets); #ifdef HAVE_ORC VIPS_FREE(seq->t1); VIPS_FREE(seq->t2); #endif /*HAVE_ORC*/ return 0; } /* Convolution start function. */ static void * vips_convi_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsConvi *convi = (VipsConvi *) b; VipsConviSequence *seq; if (!(seq = VIPS_NEW(out, VipsConviSequence))) return NULL; seq->convi = convi; seq->ir = NULL; seq->last_bpl = -1; #ifdef HAVE_ORC seq->offsets = NULL; seq->t1 = NULL; seq->t2 = NULL; #endif /*HAVE_ORC*/ seq->ir = vips_region_new(in); if (convi->nnz) { if (!(seq->offsets = VIPS_ARRAY(NULL, convi->nnz, int))) { vips_convi_stop(seq, in, convi); return NULL; } } #ifdef HAVE_ORC /* Vector mode. */ if (convi->n_pass) { seq->t1 = VIPS_ARRAY(NULL, VIPS_IMAGE_N_ELEMENTS(in), short); seq->t2 = VIPS_ARRAY(NULL, VIPS_IMAGE_N_ELEMENTS(in), short); if (!seq->t1 || !seq->t2) { vips_convi_stop(seq, in, convi); return NULL; } } #endif /*HAVE_ORC*/ return (void *) seq; } #ifdef HAVE_HWY static int vips_convi_uchar_vector_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConviSequence *seq = (VipsConviSequence *) vseq; VipsConvi *convi = (VipsConvi *) b; VipsConvolution *convolution = (VipsConvolution *) convi; VipsImage *M = convolution->M; int offset = rint(vips_image_get_offset(M)); VipsImage *in = (VipsImage *) a; VipsRegion *ir = seq->ir; const int nnz = convi->nnz; VipsRect *r = &out_region->valid; int ne = r->width * in->Bands; VipsRect s; int x, y, z, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; /* Fill offset array. Only do this if the bpl has changed since the * previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); for (i = 0; i < nnz; i++) { z = convi->coeff_pos[i]; x = z % M->Xsize; y = z / M->Xsize; seq->offsets[i] = (VIPS_REGION_ADDR(ir, x + r->left, y + r->top) - VIPS_REGION_ADDR(ir, r->left, r->top)) / VIPS_IMAGE_SIZEOF_ELEMENT(ir->im); } } VIPS_GATE_START("vips_convi_uchar_vector_gen: work"); vips_convi_uchar_hwy(out_region, ir, r, ne, nnz, offset, seq->offsets, convi->mant, convi->exp); VIPS_GATE_STOP("vips_convi_uchar_vector_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_convi_uchar_vector_gen"); return 0; } #elif defined(HAVE_ORC) #define TEMP(N, S) orc_program_add_temporary(p, S, N) #define SCANLINE(N, S) orc_program_add_source(p, S, N) #define CONST(N, V, S) orc_program_add_constant(p, S, V, N) #define ASM2(OP, A, B) orc_program_append_ds_str(p, OP, A, B) #define ASM3(OP, A, B, C) orc_program_append_str(p, OP, A, B, C) /* Generate code for a section of the mask. first is the index we start * at, we set last to the index of the last one we use before we run * out of intermediates / constants / parameters / sources or mask * coefficients. * * 0 for success, -1 on error. */ static int vips_convi_compile_section(VipsConvi *convi, VipsImage *in, Pass *pass) { VipsConvolution *convolution = (VipsConvolution *) convi; VipsImage *M = convolution->M; OrcProgram *p; OrcCompileResult result; int i; #ifdef DEBUG_COMPILE printf("starting pass %d\n", pass->first); #endif /*DEBUG_COMPILE*/ pass->program = p = orc_program_new(); pass->d1 = orc_program_add_destination(p, 2, "d1"); /* "r" is the array of sums from the previous pass (if any). */ if (!(pass->r = orc_program_add_source(p, 2, "r"))) return -1; /* The value we fetch from the image, the accumulated sum. */ TEMP("value", 2); TEMP("valueb", 1); TEMP("sum", 2); CONST("sexp", convi->sexp, 2); CONST("rnd", 1 << (convi->sexp - 1), 2); pass->n_const += 2; /* Init the sum. If this is the first pass, it's a constant. If this * is a later pass, we have to init the sum from the result * of the previous pass. */ if (pass->first == 0) { CONST("rnd2", 1 << (convi->exp - 1), 2); ASM2("loadpw", "sum", "rnd2"); pass->n_const++; } else ASM2("loadw", "sum", "r"); for (i = pass->first; i < convi->n_point; i++) { int x = i % M->Xsize; int y = i / M->Xsize; char source[256]; char off[256]; char coeff[256]; /* Exclude zero elements. */ if (!convi->mant[i]) continue; /* The source. sl0 is the first scanline in the mask. */ g_snprintf(source, 256, "sl%d", y); if (orc_program_find_var_by_name(p, source) == -1) { SCANLINE(source, 1); pass->line[pass->n_scanline] = y; pass->n_scanline++; } /* Load with an offset. Only for non-first-columns though. */ if (x == 0) ASM2("convubw", "value", source); else { g_snprintf(off, 256, "c%db", x); if (orc_program_find_var_by_name(p, off) == -1) { CONST(off, in->Bands * x, 1); pass->n_const++; } ASM3("loadoffb", "valueb", source, off); ASM2("convubw", "value", "valueb"); } /* We need a signed multiply, so the image pixel needs to * become a signed 16-bit value. We know only the bottom 8 bits * of the image and coefficient are interesting, so we can take * the bottom half of a 16x16->32 multiply. */ g_snprintf(coeff, 256, "c%dw", convi->mant[i]); if (orc_program_find_var_by_name(p, coeff) == -1) { CONST(coeff, convi->mant[i], 2); pass->n_const++; } ASM3("mullw", "value", "value", coeff); /* Shift right before add to prevent overflow on large masks. */ ASM3("addw", "value", "value", "rnd"); ASM3("shrsw", "value", "value", "sexp"); /* We accumulate the signed 16-bit result in sum. Saturated * add. */ ASM3("addssw", "sum", "sum", "value"); /* orc allows up to 8 constants, so break early once we * approach this limit. */ if (pass->n_const >= 7 /*ORC_MAX_CONST_VARS - 1*/) break; /* You can have 8 sources, and pass->r counts as one of them, * so +1 there. */ if (pass->n_scanline + 1 >= 7 /*ORC_MAX_SRC_VARS - 1*/) break; } pass->last = i; /* And write to our intermediate buffer. */ ASM2("copyw", "d1", "sum"); /* Some orcs seem to be unstable with many compilers active at once. */ g_mutex_lock(&vips__global_lock); result = orc_program_compile(p); g_mutex_unlock(&vips__global_lock); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) return -1; #ifdef DEBUG_COMPILE printf("done coeffs %d to %d\n", pass->first, pass->last); #endif /*DEBUG_COMPILE*/ return 0; } /* Generate code for the final 16->8 conversion. * * 0 for success, -1 on error. */ static int vips_convi_compile_clip(VipsConvi *convi) { VipsConvolution *convolution = (VipsConvolution *) convi; VipsImage *M = convolution->M; int offset = rint(vips_image_get_offset(M)); OrcProgram *p; OrcCompileResult result; convi->program = p = orc_program_new(); convi->d1 = orc_program_add_destination(p, 1, "d1"); /* "r" is the array of sums we clip down. */ if (!(convi->r = orc_program_add_source(p, 2, "r"))) return -1; /* The value we fetch from the image. */ TEMP("value", 2); CONST("exp", convi->exp, 2); ASM3("shrsw", "value", "r", "exp"); CONST("off", offset, 2); ASM3("addw", "value", "value", "off"); ASM2("convsuswb", "d1", "value"); /* Some orcs seem to be unstable with many compilers active at once. */ g_mutex_lock(&vips__global_lock); result = orc_program_compile(p); g_mutex_unlock(&vips__global_lock); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) return -1; return 0; } static int vips_convi_compile(VipsConvi *convi, VipsImage *in) { int i; Pass *pass; /* Generate passes until we've used up the whole mask. */ for (i = 0;;) { /* Allocate space for another pass. */ if (convi->n_pass == MAX_PASS) return -1; pass = &convi->pass[convi->n_pass]; convi->n_pass += 1; pass->first = i; pass->r = -1; pass->n_const = 0; pass->n_scanline = 0; if (vips_convi_compile_section(convi, in, pass)) return -1; i = pass->last + 1; if (i >= convi->n_point) break; } if (vips_convi_compile_clip(convi)) return -1; return 0; } static int vips_convi_gen_vector(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConviSequence *seq = (VipsConviSequence *) vseq; VipsConvi *convi = (VipsConvi *) b; VipsConvolution *convolution = (VipsConvolution *) convi; VipsImage *M = convolution->M; VipsImage *in = (VipsImage *) a; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; int ne = r->width * in->Bands; VipsRect s; int i, j, y; OrcExecutor executor[MAX_PASS]; OrcExecutor clip; #ifdef DEBUG_PIXELS printf("vips_convi_gen_vector: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG_PIXELS*/ /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; for (i = 0; i < convi->n_pass; i++) { orc_executor_set_program(&executor[i], convi->pass[i].program); orc_executor_set_n(&executor[i], ne); } orc_executor_set_program(&clip, convi->program); orc_executor_set_n(&clip, ne); VIPS_GATE_START("vips_convi_gen_vector: work"); for (y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); #ifdef DEBUG_PIXELS { int h, v; printf("before convolve: x = %d, y = %d\n", r->left, r->top + y); for (v = 0; v < M->Ysize; v++) { for (h = 0; h < M->Xsize; h++) printf("%3d ", *VIPS_REGION_ADDR(ir, r->left + h, r->top + y + v)); printf("\n"); } } #endif /*DEBUG_PIXELS*/ /* We run our n passes to generate this scanline. */ for (i = 0; i < convi->n_pass; i++) { Pass *pass = &convi->pass[i]; for (j = 0; j < pass->n_scanline; j++) orc_executor_set_array(&executor[i], pass->r + 1 + j, VIPS_REGION_ADDR(ir, r->left, r->top + y + pass->line[j])); orc_executor_set_array(&executor[i], pass->r, seq->t1); orc_executor_set_array(&executor[i], pass->d1, seq->t2); orc_executor_run(&executor[i]); VIPS_SWAP(signed short *, seq->t1, seq->t2); } #ifdef DEBUG_PIXELS printf("before clip: %d\n", ((signed short *) seq->t1)[0]); #endif /*DEBUG_PIXELS*/ orc_executor_set_array(&clip, convi->r, seq->t1); orc_executor_set_array(&clip, convi->d1, q); orc_executor_run(&clip); #ifdef DEBUG_PIXELS printf("after clip: %d\n", *VIPS_REGION_ADDR(out_region, r->left, r->top + y)); #endif /*DEBUG_PIXELS*/ } VIPS_GATE_STOP("vips_convi_gen_vector: work"); VIPS_COUNT_PIXELS(out_region, "vips_convi_gen_vector"); return 0; } #endif /*HAVE_HWY*/ /* INT inner loops. */ #define CONV_INT(TYPE, CLIP) \ { \ TYPE *restrict p = (TYPE *) VIPS_REGION_ADDR(ir, le, y); \ TYPE *restrict q = (TYPE *) VIPS_REGION_ADDR(out_region, le, y); \ int *restrict offsets = seq->offsets; \ \ for (x = 0; x < sz; x++) { \ int64_t sum; \ int i; \ \ sum = 0; \ for (i = 0; i < nnz; i++) \ sum += (int64_t) t[i] * p[offsets[i]]; \ \ sum = CLIP(((sum + rounding) / scale) + offset); \ \ q[x] = sum; \ p += 1; \ } \ } /* FLOAT inner loops. */ #define CONV_FLOAT(TYPE) \ { \ TYPE *restrict p = (TYPE *) VIPS_REGION_ADDR(ir, le, y); \ TYPE *restrict q = (TYPE *) VIPS_REGION_ADDR(out_region, le, y); \ int *restrict offsets = seq->offsets; \ \ for (x = 0; x < sz; x++) { \ double sum; \ int i; \ \ sum = 0; \ for (i = 0; i < nnz; i++) \ sum += (double) t[i] * p[offsets[i]]; \ \ sum = (sum / scale) + offset; \ \ q[x] = sum; \ p += 1; \ } \ } /* Various integer range clips. */ #define CLIP_UCHAR(X) VIPS_CLIP(0, (X), UCHAR_MAX) #define CLIP_CHAR(X) VIPS_CLIP(SCHAR_MIN, (X), SCHAR_MAX) #define CLIP_USHORT(X) VIPS_CLIP(0, (X), USHRT_MAX) #define CLIP_SHORT(X) VIPS_CLIP(SHRT_MIN, (X), SHRT_MAX) #define CLIP_NONE(X) (X) /* Convolve! */ static int vips_convi_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsConviSequence *seq = (VipsConviSequence *) vseq; VipsConvi *convi = (VipsConvi *) b; VipsConvolution *convolution = (VipsConvolution *) convi; VipsImage *M = convolution->M; int scale = rint(vips_image_get_scale(M)); int rounding = scale / 2; int offset = rint(vips_image_get_offset(M)); VipsImage *in = (VipsImage *) a; VipsRegion *ir = seq->ir; int *restrict t = convi->coeff; const int nnz = convi->nnz; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int sz = VIPS_REGION_N_ELEMENTS(out_region) * (vips_band_format_iscomplex(in->BandFmt) ? 2 : 1); VipsRect s; int x, y, z, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; /* Fill offset array. Only do this if the bpl has changed since the * previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); for (i = 0; i < nnz; i++) { z = convi->coeff_pos[i]; x = z % M->Xsize; y = z / M->Xsize; seq->offsets[i] = (VIPS_REGION_ADDR(ir, x + le, y + to) - VIPS_REGION_ADDR(ir, le, to)) / VIPS_IMAGE_SIZEOF_ELEMENT(ir->im); } } VIPS_GATE_START("vips_convi_gen: work"); for (y = to; y < bo; y++) { switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: CONV_INT(unsigned char, CLIP_UCHAR); break; case VIPS_FORMAT_CHAR: CONV_INT(signed char, CLIP_CHAR); break; case VIPS_FORMAT_USHORT: CONV_INT(unsigned short, CLIP_USHORT); break; case VIPS_FORMAT_SHORT: CONV_INT(signed short, CLIP_SHORT); break; case VIPS_FORMAT_UINT: CONV_INT(unsigned int, CLIP_NONE); break; case VIPS_FORMAT_INT: CONV_INT(signed int, CLIP_NONE); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: CONV_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: CONV_FLOAT(double); break; default: g_assert_not_reached(); } } VIPS_GATE_STOP("vips_convi_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_convi_gen"); return 0; } /* Make an int version of a mask. * * We rint() everything, then adjust the scale try to match the overall * effect. */ int vips__image_intize(VipsImage *in, VipsImage **out) { VipsImage *t; int x, y; double double_result; double out_scale; double out_offset; int int_result; if (vips_check_matrix("vips2imask", in, &t)) return -1; if (!(*out = vips_image_new_matrix(t->Xsize, t->Ysize))) { g_object_unref(t); return -1; } /* We want to make an intmask which has the same input to output ratio * as the double image. * * Imagine convolving with the double image, what's the ratio of * brightness between input and output? We want the same ratio for the * int version, if we can. * * Imagine an input image where every pixel is 1, what will the output * be? */ double_result = 0; for (y = 0; y < t->Ysize; y++) for (x = 0; x < t->Xsize; x++) double_result += *VIPS_MATRIX(t, x, y); double_result /= vips_image_get_scale(t); for (y = 0; y < t->Ysize; y++) for (x = 0; x < t->Xsize; x++) *VIPS_MATRIX(*out, x, y) = rint(*VIPS_MATRIX(t, x, y)); out_scale = rint(vips_image_get_scale(t)); if (out_scale == 0) out_scale = 1; out_offset = rint(vips_image_get_offset(t)); /* Now convolve a 1 everywhere image with the int version we've made, * what do we get? */ int_result = 0; for (y = 0; y < t->Ysize; y++) for (x = 0; x < t->Xsize; x++) int_result += *VIPS_MATRIX(*out, x, y); int_result /= out_scale; /* And adjust the scale to get as close to a match as we can. */ out_scale = rint(out_scale + (int_result - double_result)); if (out_scale == 0) out_scale = 1; vips_image_set_double(*out, "scale", out_scale); vips_image_set_double(*out, "offset", out_offset); g_object_unref(t); return 0; } #if defined(HAVE_HWY) || defined(HAVE_ORC) /* Make an int version of a mask. Each element is 8.8 float, with the same * exponent for each element (so just 8 bits in @out). * * @out is a w x h int array. */ static int vips_convi_intize(VipsConvi *convi, VipsImage *M) { VipsImage *t; double scale; double *scaled; double mx; double mn; int shift; int i; if (vips_check_matrix("vips2imask", M, &t)) return -1; /* Bake the scale into the mask to make a double version. */ scale = vips_image_get_scale(t); if (!(scaled = VIPS_ARRAY(convi, convi->n_point, double))) { g_object_unref(t); return -1; } for (i = 0; i < convi->n_point; i++) scaled[i] = VIPS_MATRIX(t, 0, 0)[i] / scale; g_object_unref(t); #ifdef DEBUG_COMPILE { int x, y; printf("vips_convi_intize: double version\n"); for (y = 0; y < t->Ysize; y++) { printf("\t"); for (x = 0; x < t->Xsize; x++) printf("%g ", scaled[y * t->Xsize + x]); printf("\n"); } } #endif /*DEBUG_COMPILE*/ mx = scaled[0]; mn = scaled[0]; for (i = 1; i < convi->n_point; i++) { if (scaled[i] > mx) mx = scaled[i]; if (scaled[i] < mn) mn = scaled[i]; } /* The mask max rounded up to the next power of two gives the exponent * all elements share. Values are eg. -3 for 1/8, 3 for 8. * * Add one so we round up stuff exactly on x.0. We multiply by 128 * later, so 1.0 (for example) would become 128, which is outside * signed 8 bit. */ shift = ceil(log2(mx) + 1); if (shift > 6 || shift < -24) { g_info("vips_convi_intize: invalid shift"); return -1; } #ifdef HAVE_HWY /* Make sure we have enough range. */ if (ceil(log2(convi->n_point)) > 10) { g_info("vips_convi_intize: mask too large"); return -1; } /* Calculate the final shift. */ convi->exp = 7 - shift; #elif defined(HAVE_ORC) /* We need to sum n_points, so we have to shift right before adding a * new value to make sure we have enough range. */ convi->sexp = ceil(log2(convi->n_point)); if (convi->sexp > 10) { g_info("vips_convi_intize: mask too large"); return -1; } /* With that already done, the final shift must be ... */ convi->exp = 7 - shift - convi->sexp; #endif /*HAVE_HWY*/ if (!(convi->mant = VIPS_ARRAY(convi, convi->n_point, short)) #ifdef HAVE_HWY || !(convi->coeff_pos = VIPS_ARRAY(convi, convi->n_point, int)) #endif /*HAVE_HWY*/ ) return -1; #ifdef HAVE_HWY convi->nnz = 0; #endif /*HAVE_HWY*/ for (i = 0; i < convi->n_point; i++) { /* 128 since this is signed. */ convi->mant[i] = rint(128 * scaled[i] * pow(2, -shift)); if (convi->mant[i] < -128 || convi->mant[i] > 127) { g_info("vips_convi_intize: mask range too large"); return -1; } #ifdef HAVE_HWY /* Squeeze out zero mask elements. */ if (convi->mant[i]) { convi->mant[convi->nnz] = convi->mant[i]; convi->coeff_pos[convi->nnz] = i; convi->nnz += 1; } #endif /*HAVE_HWY*/ } #ifdef HAVE_HWY /* Was the whole mask zero? We must have at least 1 element * in there: set it to zero. */ if (convi->nnz == 0) { convi->mant[0] = 0; convi->coeff_pos[0] = 0; convi->nnz = 1; } #endif /*HAVE_HWY*/ #ifdef DEBUG_COMPILE { int x, y; printf("vips_convi_intize:\n"); #ifdef HAVE_ORC printf("sexp = %d\n", convi->sexp); #endif /*HAVE_ORC*/ printf("exp = %d\n", convi->exp); for (y = 0; y < t->Ysize; y++) { printf("\t"); for (x = 0; x < t->Xsize; x++) printf("%4d ", convi->mant[y * t->Xsize + x]); printf("\n"); } } #endif /*DEBUG_COMPILE*/ /* Verify accuracy. */ { double true_sum; int int_sum; int true_value; int int_value; true_sum = 0.0; int_sum = 0; #ifdef HAVE_HWY for (i = 0; i < convi->nnz; i++) { true_sum += 128 * scaled[convi->coeff_pos[i]]; int_sum += 128 * convi->mant[i]; } #elif defined(HAVE_ORC) for (i = 0; i < convi->n_point; i++) { int value; true_sum += 128 * scaled[i]; value = 128 * convi->mant[i]; value = (value + (1 << (convi->sexp - 1))) >> convi->sexp; int_sum += value; int_sum = VIPS_CLIP(SHRT_MIN, int_sum, SHRT_MAX); } #endif /*HAVE_HWY*/ true_value = VIPS_CLIP(0, true_sum, 255); int_value = (int_sum + (1 << (convi->exp - 1))) >> convi->exp; int_value = VIPS_CLIP(0, int_value, 255); if (abs(true_value - int_value) > 2) { g_info("vips_convi_intize: too inaccurate"); return -1; } } return 0; } #endif /*HAVE_HWY || HAVE_ORC*/ static int vips_convi_build(VipsObject *object) { VipsConvolution *convolution = (VipsConvolution *) object; VipsConvi *convi = (VipsConvi *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; VipsImage *M; VipsGenerateFn generate; double *coeff; int i; if (VIPS_OBJECT_CLASS(vips_convi_parent_class)->build(object)) return -1; in = convolution->in; M = convolution->M; convi->n_point = M->Xsize * M->Ysize; if (vips_embed(in, &t[0], M->Xsize / 2, M->Ysize / 2, in->Xsize + M->Xsize - 1, in->Ysize + M->Ysize - 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[0]; /* For uchar input, try to make a vector path. */ #ifdef HAVE_HWY if (in->BandFmt == VIPS_FORMAT_UCHAR && vips_vector_isenabled() && !vips_convi_intize(convi, M)) { generate = vips_convi_uchar_vector_gen; g_info("convi: using vector path"); } else #elif defined(HAVE_ORC) if (in->BandFmt == VIPS_FORMAT_UCHAR && vips_vector_isenabled() && !vips_convi_intize(convi, M) && !vips_convi_compile(convi, in)) { generate = vips_convi_gen_vector; g_info("convi: using vector path"); } else #endif /*HAVE_HWY*/ /* Default to the C path. */ generate = vips_convi_gen; /* Make the data for the C path. */ if (generate == vips_convi_gen) { g_info("convi: using C path"); /* Make an int version of our mask. */ if (vips__image_intize(M, &t[1])) return -1; M = t[1]; coeff = VIPS_MATRIX(M, 0, 0); if (!(convi->coeff = VIPS_ARRAY(object, convi->n_point, int)) || !(convi->coeff_pos = VIPS_ARRAY(object, convi->n_point, int))) return -1; /* Squeeze out zero mask elements. */ convi->nnz = 0; for (i = 0; i < convi->n_point; i++) if (coeff[i]) { convi->coeff[convi->nnz] = coeff[i]; convi->coeff_pos[convi->nnz] = i; convi->nnz += 1; } /* Was the whole mask zero? We must have at least 1 element * in there: set it to zero. */ if (convi->nnz == 0) { convi->coeff[0] = 0; convi->coeff_pos[0] = 0; convi->nnz = 1; } } g_object_set(convi, "out", vips_image_new(), NULL); if (vips_image_pipelinev(convolution->out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; convolution->out->Xoffset = 0; convolution->out->Yoffset = 0; /* Prepare output. Consider a 7x7 mask and a 7x7 image -- the output * would be 1x1. */ convolution->out->Xsize -= M->Xsize - 1; convolution->out->Ysize -= M->Ysize - 1; if (vips_image_generate(convolution->out, vips_convi_start, generate, vips_convi_stop, in, convi)) return -1; convolution->out->Xoffset = -M->Xsize / 2; convolution->out->Yoffset = -M->Ysize / 2; return 0; } static void vips_convi_class_init(VipsConviClass *class) { #ifdef HAVE_ORC GObjectClass *gobject_class = G_OBJECT_CLASS(class); #endif /*HAVE_ORC*/ VipsObjectClass *object_class = (VipsObjectClass *) class; #ifdef HAVE_ORC gobject_class->finalize = vips_convi_finalize; #endif /*HAVE_ORC*/ object_class->nickname = "convi"; object_class->description = _("int convolution operation"); object_class->build = vips_convi_build; } static void vips_convi_init(VipsConvi *convi) { convi->nnz = 0; convi->coeff = NULL; convi->coeff_pos = NULL; #if defined(HAVE_HWY) || defined(HAVE_ORC) convi->mant = NULL; #endif /*HAVE_HWY || HAVE_ORC*/ } /** * vips_convi: (method) * @in: input image * @out: (out): output image * @mask: convolve with this mask * @...: `NULL`-terminated list of optional named arguments * * Integer convolution. This is a low-level operation, see [method@Image.conv] for * something more convenient. * * @mask is converted to an integer mask with `rint()` of each element, rint of * scale and rint of offset. Each output pixel is then calculated as * * ``` * sigma[i]{pixel[i] * mask[i]} / scale + offset * ``` * * The output image always has the same [enum@BandFormat] as the input image. * * For [enum@Vips.BandFormat.UCHAR] images, [method@Image.convi] uses a fast vector path based on * half-float arithmetic. This can produce slightly different results. * Disable the vector path with `--vips-novector` or `VIPS_NOVECTOR` or * [func@vector_set_enabled]. * * ::: seealso * [method@Image.conv]. * * Returns: 0 on success, -1 on error */ int vips_convi(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("convi", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/convi_hwy.cpp000066400000000000000000000200731516303661500220320ustar00rootroot00000000000000/* 20/08/22 kleisauke * - initial implementation * 07/09/22 kleisauke * - implement using ReorderWidenMulAccumulate * 29/11/22 kleisauke * - prefer use of RearrangeToOddPlusEven * 02/10/23 kleisauke * - prefer use of InterleaveWhole{Lower,Upper} on RVV/SVE */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "pconvolution.h" #ifdef HAVE_HWY #undef HWY_TARGET_INCLUDE #define HWY_TARGET_INCLUDE "libvips/convolution/convi_hwy.cpp" #include #include namespace HWY_NAMESPACE { using namespace hwy::HWY_NAMESPACE; using DI32 = ScalableTag; using DI16 = ScalableTag; using DU8 = ScalableTag; constexpr DU8 du8; #if HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE) constexpr Rebind du8x32; #endif constexpr DI16 di16; constexpr DI32 di32; #if defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) #define InterleaveLower InterleaveWholeLower #define InterleaveUpper InterleaveWholeUpper #endif // Compat for Highway versions < 1.3.0 #ifndef HWY_LANES_CONSTEXPR #define HWY_LANES_CONSTEXPR #endif #if HWY_IS_BIG_ENDIAN #define HWY_ENDIAN_LOHI(lo, hi) hi, lo #else #define HWY_ENDIAN_LOHI(lo, hi) lo, hi #endif HWY_ATTR void vips_convi_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int32_t ne, int32_t nnz, int32_t offset, const int32_t *HWY_RESTRICT offsets, const int16_t *HWY_RESTRICT mant, int32_t exp) { #if HWY_TARGET != HWY_SCALAR int32_t bo = VIPS_RECT_BOTTOM(r); #if !defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) /* Ensure we do not cross 128-bit block boundaries on RVV/SVE. */ const int32_t N = 16; #else HWY_LANES_CONSTEXPR int32_t N = Lanes(du8); #endif const auto zero = Zero(du8); const auto v_exp = Set(di32, 1 << (exp - 1)); const auto v_offset = Set(di32, offset); for (int32_t y = r->top; y < bo; ++y) { VipsPel *HWY_RESTRICT p = VIPS_REGION_ADDR(ir, r->left, y); VipsPel *HWY_RESTRICT q = VIPS_REGION_ADDR(out_region, r->left, y); /* Main loop: unrolled. */ int32_t x = 0; for (; x + N <= ne; x += N) { #if HWY_ARCH_X86 || HWY_ARCH_WASM || HWY_TARGET == HWY_EMU128 /* Initialize the sum with the addition on x86 and Wasm, * avoids an extra add instruction. Should be safe given * that only one accumulator is used. */ auto sum0 = v_exp; auto sum2 = v_exp; auto sum4 = v_exp; auto sum6 = v_exp; #else auto sum0 = Zero(di32); auto sum2 = Zero(di32); auto sum4 = Zero(di32); auto sum6 = Zero(di32); #endif auto sum1 = Zero(di32); /* unused on x86 and Wasm */ auto sum3 = Zero(di32); /* unused on x86 and Wasm */ auto sum5 = Zero(di32); /* unused on x86 and Wasm */ auto sum7 = Zero(di32); /* unused on x86 and Wasm */ int32_t i = 0; for (; i + 2 <= nnz; i += 2) { /* Load two coefficients at once. */ auto mmk = BitCast(di16, Set(di32, *(int32_t *) &mant[i])); /* Load with an offset. */ auto top = LoadU(du8, /* top line */ p + offsets[i]); auto bottom = LoadU(du8, /* bottom line */ p + offsets[i + 1]); auto source = InterleaveLower(HWY_ENDIAN_LOHI(top, bottom)); auto pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk, sum0, /* byref */ sum1); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum2 = ReorderWidenMulAccumulate(di32, pix, mmk, sum2, /* byref */ sum3); source = InterleaveUpper(du8, HWY_ENDIAN_LOHI(top, bottom)); pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum4 = ReorderWidenMulAccumulate(di32, pix, mmk, sum4, /* byref */ sum5); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum6 = ReorderWidenMulAccumulate(di32, pix, mmk, sum6, /* byref */ sum7); } for (; i < nnz; ++i) { auto mmk = Set(di16, mant[i]); /* Load with an offset. */ auto top = LoadU(du8, p + offsets[i]); auto source = InterleaveLower(HWY_ENDIAN_LOHI(top, zero)); auto pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk, sum0, /* byref */ sum1); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum2 = ReorderWidenMulAccumulate(di32, pix, mmk, sum2, /* byref */ sum3); source = InterleaveUpper(du8, HWY_ENDIAN_LOHI(top, zero)); pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum4 = ReorderWidenMulAccumulate(di32, pix, mmk, sum4, /* byref */ sum5); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum6 = ReorderWidenMulAccumulate(di32, pix, mmk, sum6, /* byref */ sum7); } sum0 = RearrangeToOddPlusEven(sum0, sum1); sum2 = RearrangeToOddPlusEven(sum2, sum3); sum4 = RearrangeToOddPlusEven(sum4, sum5); sum6 = RearrangeToOddPlusEven(sum6, sum7); #if !(HWY_ARCH_X86 || HWY_ARCH_WASM || HWY_TARGET == HWY_EMU128) sum0 = Add(sum0, v_exp); sum2 = Add(sum2, v_exp); sum4 = Add(sum4, v_exp); sum6 = Add(sum6, v_exp); #endif /* The final 32->8 conversion. */ sum0 = ShiftRightSame(sum0, exp); sum2 = ShiftRightSame(sum2, exp); sum4 = ShiftRightSame(sum4, exp); sum6 = ShiftRightSame(sum6, exp); sum0 = Add(sum0, v_offset); sum2 = Add(sum2, v_offset); sum4 = Add(sum4, v_offset); sum6 = Add(sum6, v_offset); #if HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE) /* RVV/SVE defines demotion as writing to the upper or lower half * of each lane, rather than compacting them within a vector. */ auto demoted0 = DemoteTo(du8x32, sum0); auto demoted1 = DemoteTo(du8x32, sum2); auto demoted2 = DemoteTo(du8x32, sum4); auto demoted3 = DemoteTo(du8x32, sum6); StoreU(demoted0, du8x32, q + x + 0 * N / 4); StoreU(demoted1, du8x32, q + x + 1 * N / 4); StoreU(demoted2, du8x32, q + x + 2 * N / 4); StoreU(demoted3, du8x32, q + x + 3 * N / 4); #else auto demoted0 = ReorderDemote2To(di16, sum0, sum2); auto demoted2 = ReorderDemote2To(di16, sum4, sum6); auto demoted = ReorderDemote2To(du8, demoted0, demoted2); StoreU(demoted, du8, q + x); #endif p += N; } /* `ne` was not a multiple of the vector length `N`; * proceed one by one. */ for (; x < ne; ++x) { int32_t sum = 1 << (exp - 1); for (int32_t i = 0; i < nnz; ++i) sum += p[offsets[i]] * mant[i]; q[x] = VIPS_CLIP(0, (sum >> exp) + offset, UCHAR_MAX); p += 1; } } #endif } #undef InterleaveLower #undef InterleaveUpper } /*namespace HWY_NAMESPACE*/ #if HWY_ONCE HWY_EXPORT(vips_convi_uchar_hwy); void vips_convi_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int ne, int nnz, int offset, const int *restrict offsets, const short *restrict mant, int exp) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_convi_uchar_hwy)(out_region, ir, r, ne, nnz, offset, offsets, mant, exp); /* clang-format on */ } #endif /*HWY_ONCE*/ #endif /*HAVE_HWY*/ libvips-8.18.2/libvips/convolution/convolution.c000066400000000000000000000110141516303661500220370ustar00rootroot00000000000000/* base class for all convolution operations * * properties: * - one input image * - one output image * - one input mask */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pconvolution.h" /** * VipsPrecision: * @VIPS_PRECISION_INTEGER: int everywhere * @VIPS_PRECISION_FLOAT: float everywhere * @VIPS_PRECISION_APPROXIMATE: approximate integer output * * How accurate an operation should be. */ /** * VipsCombine: * @VIPS_COMBINE_MAX: take the maximum of the possible values * @VIPS_COMBINE_SUM: sum all the values * @VIPS_COMBINE_MIN: take the minimum value * * How to combine values. See [method@Image.compass], for example. */ G_DEFINE_ABSTRACT_TYPE(VipsConvolution, vips_convolution, VIPS_TYPE_OPERATION); static int vips_convolution_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConvolution *convolution = VIPS_CONVOLUTION(object); VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); #ifdef DEBUG printf("vips_convolution_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_convolution_parent_class)->build(object)) return -1; if (vips_check_matrix(class->nickname, convolution->mask, &t[0])) return -1; convolution->M = t[0]; return 0; } static void vips_convolution_class_init(VipsConvolutionClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "convolution"; vobject_class->description = _("convolution operations"); vobject_class->build = vips_convolution_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; /* Inputs set by subclassess. */ VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsConvolution, in)); VIPS_ARG_IMAGE(class, "out", 10, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsConvolution, out)); VIPS_ARG_IMAGE(class, "mask", 20, _("Mask"), _("Input matrix image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsConvolution, mask)); } static void vips_convolution_init(VipsConvolution *convolution) { } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_convolution_operation_init(void) { extern GType vips_conv_get_type(void); extern GType vips_conva_get_type(void); extern GType vips_convf_get_type(void); extern GType vips_convi_get_type(void); extern GType vips_convsep_get_type(void); extern GType vips_convasep_get_type(void); extern GType vips_compass_get_type(void); extern GType vips_fastcor_get_type(void); extern GType vips_spcor_get_type(void); extern GType vips_sharpen_get_type(void); extern GType vips_gaussblur_get_type(void); extern GType vips_sobel_get_type(void); extern GType vips_scharr_get_type(void); extern GType vips_prewitt_get_type(void); extern GType vips_canny_get_type(void); vips_conv_get_type(); vips_conva_get_type(); vips_convf_get_type(); vips_convi_get_type(); vips_compass_get_type(); vips_convsep_get_type(); vips_convasep_get_type(); vips_fastcor_get_type(); vips_spcor_get_type(); vips_sharpen_get_type(); vips_gaussblur_get_type(); vips_sobel_get_type(); vips_scharr_get_type(); vips_prewitt_get_type(); vips_canny_get_type(); } libvips-8.18.2/libvips/convolution/convsep.c000066400000000000000000000116501516303661500211430ustar00rootroot00000000000000/* convolve twice, rotating the mask * * 23/10/13 * - from vips_convsep() * 8/5/17 * - default to float ... int will often lose precision and should not be * the default */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pconvolution.h" typedef struct { VipsConvolution parent_instance; VipsPrecision precision; int layers; int cluster; } VipsConvsep; typedef VipsConvolutionClass VipsConvsepClass; G_DEFINE_TYPE(VipsConvsep, vips_convsep, VIPS_TYPE_CONVOLUTION); static int vips_convsep_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsConvolution *convolution = (VipsConvolution *) object; VipsConvsep *convsep = (VipsConvsep *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; g_object_set(convsep, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_convsep_parent_class)->build(object)) return -1; if (vips_check_separable(class->nickname, convolution->M)) return -1; in = convolution->in; if (convsep->precision == VIPS_PRECISION_APPROXIMATE) { if (vips_convasep(in, &t[0], convolution->M, "layers", convsep->layers, NULL)) return -1; in = t[0]; } else { /* Take a copy, since we must set the offset. */ if (vips_rot(convolution->M, &t[0], VIPS_ANGLE_D90, NULL) || vips_copy(t[0], &t[3], NULL)) return -1; vips_image_set_double(t[3], "offset", 0); if (vips_conv(in, &t[1], convolution->M, "precision", convsep->precision, "layers", convsep->layers, "cluster", convsep->cluster, NULL) || vips_conv(t[1], &t[2], t[3], "precision", convsep->precision, "layers", convsep->layers, "cluster", convsep->cluster, NULL)) return -1; in = t[2]; } if (vips_image_write(in, convolution->out)) return -1; return 0; } static void vips_convsep_class_init(VipsConvsepClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "convsep"; object_class->description = _("separable convolution operation"); object_class->build = vips_convsep_build; VIPS_ARG_ENUM(class, "precision", 203, _("Precision"), _("Convolve with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConvsep, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_FLOAT); VIPS_ARG_INT(class, "layers", 204, _("Layers"), _("Use this many layers in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConvsep, layers), 1, 1000, 5); VIPS_ARG_INT(class, "cluster", 205, _("Cluster"), _("Cluster lines closer than this in approximation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConvsep, cluster), 1, 100, 1); } static void vips_convsep_init(VipsConvsep *convsep) { convsep->precision = VIPS_PRECISION_FLOAT; convsep->layers = 5; convsep->cluster = 1; } /** * vips_convsep: (method) * @in: input image * @out: (out): output image * @mask: convolution mask * @...: `NULL`-terminated list of optional named arguments * * Perform a separable convolution of @in with @mask. * See [method@Image.conv] for a detailed description. * * The mask must be 1xn or nx1 elements. * * The image is convolved twice: once with @mask and then again with @mask * rotated by 90 degrees. This is much faster for certain types of mask * (gaussian blur, for example) than doing a full 2D convolution. * * ::: tip "Optional arguments" * * @precision: [enum@Precision], calculation accuracy * * @layers: `gint`, number of layers for approximation * * @cluster: `gint`, cluster lines closer than this distance * * ::: seealso * [method@Image.conv], [ctor@Image.gaussmat]. * * Returns: 0 on success, -1 on error */ int vips_convsep(VipsImage *in, VipsImage **out, VipsImage *mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("convsep", ap, in, out, mask); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/correlation.c000066400000000000000000000111571516303661500220110ustar00rootroot00000000000000/* base class for correlation * * 7/11/13 * - from convolution.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pconvolution.h" #include "correlation.h" G_DEFINE_ABSTRACT_TYPE(VipsCorrelation, vips_correlation, VIPS_TYPE_OPERATION); static int vips_correlation_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsCorrelation *correlation = (VipsCorrelation *) b; VipsCorrelationClass *cclass = VIPS_CORRELATION_GET_CLASS(correlation); VipsRect *r = &out_region->valid; VipsRect irect; /* What part of ir do we need? */ irect.left = r->left; irect.top = r->top; irect.width = r->width + correlation->ref_ready->Xsize - 1; irect.height = r->height + correlation->ref_ready->Ysize - 1; if (vips_region_prepare(ir, &irect)) return -1; cclass->correlation(correlation, ir, out_region); return 0; } static int vips_correlation_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCorrelationClass *cclass = VIPS_CORRELATION_CLASS(class); VipsCorrelation *correlation = (VipsCorrelation *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); if (VIPS_OBJECT_CLASS(vips_correlation_parent_class)->build(object)) return -1; /* Stretch input out. */ if (vips_embed(correlation->in, &t[0], correlation->ref->Xsize / 2, correlation->ref->Ysize / 2, correlation->in->Xsize + correlation->ref->Xsize - 1, correlation->in->Ysize + correlation->ref->Ysize - 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; if (vips__formatalike(t[0], correlation->ref, &t[1], &t[2]) || vips__bandalike(class->nickname, t[1], t[2], &t[3], &t[4]) || !(t[5] = vips_image_copy_memory(t[4]))) return -1; correlation->in_ready = t[3]; correlation->ref_ready = t[5]; g_object_set(object, "out", vips_image_new(), NULL); /* FATSTRIP is good for us as THINSTRIP will cause * too many recalculations on overlaps. */ if (vips_image_pipelinev(correlation->out, VIPS_DEMAND_STYLE_FATSTRIP, correlation->in_ready, correlation->ref_ready, NULL)) return -1; correlation->out->Xsize = correlation->in->Xsize; correlation->out->Ysize = correlation->in->Ysize; correlation->out->BandFmt = cclass->format_table[correlation->in_ready->BandFmt]; if (cclass->pre_generate && cclass->pre_generate(correlation)) return -1; if (vips_image_generate(correlation->out, vips_start_one, vips_correlation_gen, vips_stop_one, correlation->in_ready, correlation)) return -1; vips_reorder_margin_hint(correlation->out, correlation->ref->Xsize * correlation->ref->Ysize); return 0; } static void vips_correlation_class_init(VipsCorrelationClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "correlation"; object_class->description = _("correlation operation"); object_class->build = vips_correlation_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCorrelation, in)); VIPS_ARG_IMAGE(class, "ref", 10, _("Mask"), _("Input reference image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCorrelation, ref)); VIPS_ARG_IMAGE(class, "out", 20, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsCorrelation, out)); } static void vips_correlation_init(VipsCorrelation *correlation) { } libvips-8.18.2/libvips/convolution/correlation.h000066400000000000000000000045431516303661500220170ustar00rootroot00000000000000/* base class for all correlation operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PCORRELATION_H #define VIPS_PCORRELATION_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_CORRELATION (vips_correlation_get_type()) #define VIPS_CORRELATION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_CORRELATION, VipsCorrelation)) #define VIPS_CORRELATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_CORRELATION, VipsCorrelationClass)) #define VIPS_IS_CORRELATION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_CORRELATION)) #define VIPS_IS_CORRELATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_CORRELATION)) #define VIPS_CORRELATION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_CORRELATION, VipsCorrelationClass)) typedef struct { VipsOperation parent_instance; /* Params. */ VipsImage *in; VipsImage *ref; VipsImage *out; /* The two input images, upcast to the smallest common format. ref is * a memory buffer. */ VipsImage *in_ready; VipsImage *ref_ready; } VipsCorrelation; typedef struct { VipsOperationClass parent_class; /* For each upcast input format, what output format. */ const VipsBandFormat *format_table; /* Run just before generate. The subclass can fill in some stuff. */ int (*pre_generate)(VipsCorrelation *); void (*correlation)(VipsCorrelation *, VipsRegion *in, VipsRegion *out); } VipsCorrelationClass; GType vips_correlation_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PCORRELATION_H*/ libvips-8.18.2/libvips/convolution/edge.c000066400000000000000000000217401516303661500203730ustar00rootroot00000000000000/* Edge detector * * 12/4/23 * - from vips_sobel() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsEdge { VipsOperation parent_instance; VipsImage *in; VipsImage *out; VipsImage *mask; /* Need an image vector for start_many. */ VipsImage *args[3]; } VipsEdge; typedef VipsOperationClass VipsEdgeClass; G_DEFINE_ABSTRACT_TYPE(VipsEdge, vips_edge, VIPS_TYPE_OPERATION); static void vips_edge_dispose(GObject *gobject) { VipsEdge *edge = (VipsEdge *) gobject; VIPS_UNREF(edge->mask); G_OBJECT_CLASS(vips_edge_parent_class)->dispose(gobject); } static int vips_edge_uchar_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion **in = (VipsRegion **) vseq; VipsRect *r = &out_region->valid; int sz = r->width * in[0]->im->Bands; int x, y; if (vips_reorder_prepare_many(out_region->im, in, r)) return -1; for (y = 0; y < r->height; y++) { VipsPel *p1 = (VipsPel *restrict) VIPS_REGION_ADDR(in[0], r->left, r->top + y); VipsPel *p2 = (VipsPel *restrict) VIPS_REGION_ADDR(in[1], r->left, r->top + y); VipsPel *q = (VipsPel *restrict) VIPS_REGION_ADDR(out_region, r->left, r->top + y); for (x = 0; x < sz; x++) { int v1 = 2 * (p1[x] - 128); int v2 = 2 * (p2[x] - 128); /* Avoid the sqrt() for uchar. */ int v = abs(v1) + abs(v2); q[x] = v > 255 ? 255 : v; } } return 0; } /* Fast uchar path. */ static int vips_edge_build_uchar(VipsEdge *edge) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(edge), 20); g_info("vips_edge: uchar path"); /* For uchar, use 128 as the zero and divide the result by 2 to * prevent overflow. */ if (vips_copy(edge->mask, &t[1], NULL)) return -1; vips_image_set_double(t[1], "offset", 128.0); vips_image_set_double(t[1], "scale", 2.0); if (vips_conv(edge->in, &t[3], t[1], "precision", VIPS_PRECISION_INTEGER, NULL)) return -1; if (vips_rot90(t[1], &t[5], NULL) || vips_conv(edge->in, &t[7], t[5], "precision", VIPS_PRECISION_INTEGER, NULL)) return -1; g_object_set(edge, "out", vips_image_new(), NULL); edge->args[0] = t[3]; edge->args[1] = t[7]; edge->args[2] = NULL; if (vips_image_pipeline_array(edge->out, VIPS_DEMAND_STYLE_FATSTRIP, edge->args)) return -1; if (vips_image_generate(edge->out, vips_start_many, vips_edge_uchar_gen, vips_stop_many, edge->args, NULL)) return -1; return 0; } /* Accurate but slow path. */ static int vips_edge_build_float(VipsEdge *edge) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(edge), 20); g_info("vips_edge: float path"); if (vips_rot90(edge->mask, &t[0], NULL) || vips_conv(edge->in, &t[1], edge->mask, NULL) || vips_conv(edge->in, &t[2], t[0], NULL)) return -1; if (vips_multiply(t[1], t[1], &t[3], NULL) || vips_multiply(t[2], t[2], &t[4], NULL) || vips_add(t[3], t[4], &t[5], NULL) || vips_pow_const1(t[5], &t[6], 0.5, NULL) || vips_cast_uchar(t[6], &t[7], NULL)) return -1; g_object_set(edge, "out", vips_image_new(), NULL); if (vips_image_write(t[7], edge->out)) return -1; return 0; } static int vips_edge_build(VipsObject *object) { VipsEdge *edge = (VipsEdge *) object; if (edge->in->BandFmt == VIPS_FORMAT_UCHAR) { if (vips_edge_build_uchar(edge)) return -1; } else { if (vips_edge_build_float(edge)) return -1; } return 0; } static void vips_edge_class_init(VipsEdgeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->dispose = vips_edge_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "edge"; object_class->description = _("Edge detector"); object_class->build = vips_edge_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsEdge, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsEdge, out)); } static void vips_edge_init(VipsEdge *edge) { } typedef VipsEdge VipsSobel; typedef VipsEdgeClass VipsSobelClass; G_DEFINE_TYPE(VipsSobel, vips_sobel, vips_edge_get_type()); static int vips_sobel_build(VipsObject *object) { VipsEdge *edge = (VipsEdge *) object; edge->mask = vips_image_new_matrixv(3, 3, 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0); return VIPS_OBJECT_CLASS(vips_sobel_parent_class)->build(object); } static void vips_sobel_class_init(VipsSobelClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "sobel"; object_class->description = _("Sobel edge detector"); object_class->build = vips_sobel_build; } static void vips_sobel_init(VipsEdge *sobel) { } typedef VipsEdge VipsScharr; typedef VipsEdgeClass VipsScharrClass; G_DEFINE_TYPE(VipsScharr, vips_scharr, vips_edge_get_type()); static int vips_scharr_build(VipsObject *object) { VipsEdge *edge = (VipsEdge *) object; edge->mask = vips_image_new_matrixv(3, 3, -3.0, 0.0, 3.0, -10.0, 0.0, 10.0, -3.0, 0.0, 3.0); return VIPS_OBJECT_CLASS(vips_scharr_parent_class)->build(object); } static void vips_scharr_class_init(VipsSobelClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "scharr"; object_class->description = _("Scharr edge detector"); object_class->build = vips_scharr_build; } static void vips_scharr_init(VipsScharr *scharr) { } typedef VipsEdge VipsPrewitt; typedef VipsEdgeClass VipsPrewittClass; G_DEFINE_TYPE(VipsPrewitt, vips_prewitt, vips_edge_get_type()); static int vips_prewitt_build(VipsObject *object) { VipsEdge *edge = (VipsEdge *) object; edge->mask = vips_image_new_matrixv(3, 3, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0); return VIPS_OBJECT_CLASS(vips_prewitt_parent_class)->build(object); } static void vips_prewitt_class_init(VipsSobelClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "prewitt"; object_class->description = _("Prewitt edge detector"); object_class->build = vips_prewitt_build; } static void vips_prewitt_init(VipsPrewitt *prewitt) { } /** * vips_sobel: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Sobel edge detector. * * uchar images are computed using a fast, low-precision path. Cast to float * for a high-precision implementation. * * ::: seealso * [method@Image.canny], [method@Image.sobel], [method@Image.prewitt], * [method@Image.scharr]. * * Returns: 0 on success, -1 on error. */ int vips_sobel(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("sobel", ap, in, out); va_end(ap); return result; } /** * vips_scharr: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Scharr edge detector. * * uchar images are computed using a fast, low-precision path. Cast to float * for a high-precision implementation. * * ::: seealso * [method@Image.canny], [method@Image.sobel], [method@Image.prewitt], * [method@Image.scharr]. * * Returns: 0 on success, -1 on error. */ int vips_scharr(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("scharr", ap, in, out); va_end(ap); return result; } /** * vips_prewitt: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Prewitt edge detector. * * uchar images are computed using a fast, low-precision path. Cast to float * for a high-precision implementation. * * ::: seealso * [method@Image.canny], [method@Image.sobel], [method@Image.prewitt], * [method@Image.scharr]. * * Returns: 0 on success, -1 on error. */ int vips_prewitt(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("prewitt", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/fastcor.c000066400000000000000000000144131516303661500211270ustar00rootroot00000000000000/* fastcor * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on : 15/03/1991 * 20/2/95 JC * - ANSIfied * - in1 and in2 swapped, to match order for im_spcor * - memory leaks fixed * 21/2/95 JC * - partialed * - speed-ups * 7/4/04 * - now uses im_embed() with edge stretching on the output * - sets Xoffset / Yoffset * 8/3/06 JC * - use im_embed() with edge stretching on the input, not the output * - calculate sum of squares of differences, rather than abs of * difference * 3/2/10 * - gtkdoc * - cleanups * 7/11/13 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pconvolution.h" #include "correlation.h" typedef VipsCorrelationClass VipsFastcor; typedef VipsCorrelationClass VipsFastcorClass; G_DEFINE_TYPE(VipsFastcor, vips_fastcor, VIPS_TYPE_CORRELATION); #define CORR_INT(TYPE) \ { \ for (y = 0; y < r->height; y++) { \ unsigned int *q = (unsigned int *) \ VIPS_REGION_ADDR(out, r->left, r->top + y); \ \ for (x = 0; x < r->width; x++) \ for (b = 0; b < bands; b++) { \ TYPE *p1 = (TYPE *) ref->data; \ TYPE *p2 = (TYPE *) VIPS_REGION_ADDR(in, \ r->left + x, r->top + y); \ \ unsigned int sum; \ \ sum = 0; \ for (j = 0; j < ref->Ysize; j++) { \ for (i = b; i < sz; i += bands) { \ int t = p1[i] - p2[i]; \ \ sum += (unsigned int) t * t; \ } \ \ p1 += sz; \ p2 += lsk; \ } \ \ *q++ = sum; \ } \ } \ } #define CORR_FLOAT(TYPE) \ { \ for (y = 0; y < r->height; y++) { \ TYPE *q = (TYPE *) \ VIPS_REGION_ADDR(out, r->left, r->top + y); \ \ for (x = 0; x < r->width; x++) \ for (b = 0; b < bands; b++) { \ TYPE *p_ref = (TYPE *) ref->data; \ TYPE *p_in = (TYPE *) VIPS_REGION_ADDR(in, \ r->left + x, r->top + y); \ \ TYPE sum; \ \ sum = 0; \ for (j = 0; j < ref->Ysize; j++) { \ for (i = b; i < sz; i += bands) { \ TYPE dif = p_ref[i] - p_in[i]; \ \ sum += dif * dif; \ } \ \ p_ref += sz; \ p_in += lsk; \ } \ \ *q++ = sum; \ } \ } \ } static void vips_fastcor_correlation(VipsCorrelation *correlation, VipsRegion *in, VipsRegion *out) { VipsRect *r = &out->valid; VipsImage *ref = correlation->ref_ready; int bands = vips_band_format_iscomplex(ref->BandFmt) ? ref->Bands * 2 : ref->Bands; int sz = ref->Xsize * bands; int lsk = VIPS_REGION_LSKIP(in) / VIPS_IMAGE_SIZEOF_ELEMENT(in->im); int x, y, i, j, b; switch (vips_image_get_format(ref)) { case VIPS_FORMAT_CHAR: CORR_INT(signed char); break; case VIPS_FORMAT_UCHAR: CORR_INT(unsigned char); break; case VIPS_FORMAT_SHORT: CORR_INT(signed short); break; case VIPS_FORMAT_USHORT: CORR_INT(unsigned short); break; case VIPS_FORMAT_INT: CORR_INT(signed int); break; case VIPS_FORMAT_UINT: CORR_INT(unsigned int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: CORR_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: CORR_FLOAT(double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Type promotion for multiplication. Sign and value preserving. Make sure * these match the case statement in multiply_buffer() above. */ static const VipsBandFormat vips_fastcor_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UI, UI, UI, UI, UI, UI, F, X, D, DX }; static void vips_fastcor_class_init(VipsFastcorClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsCorrelationClass *cclass = VIPS_CORRELATION_CLASS(class); object_class->nickname = "fastcor"; object_class->description = _("fast correlation"); cclass->format_table = vips_fastcor_format_table; cclass->correlation = vips_fastcor_correlation; } static void vips_fastcor_init(VipsFastcor *fastcor) { } /** * vips_fastcor: (method) * @in: input image * @ref: reference image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Calculate a fast correlation surface. * * @ref is placed at every position in @in and the sum of squares of * differences calculated. * * The output * image is the same size as the input. Extra input edge pixels are made by * copying the existing edges outwards. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The output type is uint if both inputs are integer, float if both are float * or complex, and double if either is double or double complex. * In other words, the output type is just large enough to hold the whole * range of possible values. * * ::: seealso * [method@Image.spcor]. * * Returns: 0 on success, -1 on error */ int vips_fastcor(VipsImage *in, VipsImage *ref, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("fastcor", ap, in, ref, out); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/gaussblur.c000066400000000000000000000116311516303661500214740ustar00rootroot00000000000000/* Gaussian blur. * * 15/11/13 * - from vips_sharpen() * 19/11/14 * - change parameters to be more imagemagick-like * 21/9/20 * - allow sigma zero, meaning no blur * - sigma < 0.2 is just copy */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsGaussblur { VipsOperation parent_instance; VipsImage *in; VipsImage *out; gdouble sigma; gdouble min_ampl; VipsPrecision precision; } VipsGaussblur; typedef VipsOperationClass VipsGaussblurClass; G_DEFINE_TYPE(VipsGaussblur, vips_gaussblur, VIPS_TYPE_OPERATION); static int vips_gaussblur_build(VipsObject *object) { VipsGaussblur *gaussblur = (VipsGaussblur *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); if (VIPS_OBJECT_CLASS(vips_gaussblur_parent_class)->build(object)) return -1; /* vips_gaussmat() will make a 1x1 pixel mask for anything smaller than * this. */ if (gaussblur->sigma < 0.2) { if (vips_copy(gaussblur->in, &t[1], NULL)) return -1; } else { if (vips_gaussmat(&t[0], gaussblur->sigma, gaussblur->min_ampl, "separable", TRUE, "precision", gaussblur->precision, NULL)) return -1; #ifdef DEBUG printf("gaussblur: blurring with:\n"); vips_matrixprint(t[0], NULL); #endif /*DEBUG*/ g_info("gaussblur mask width %d", t[0]->Xsize); if (vips_convsep(gaussblur->in, &t[1], t[0], "precision", gaussblur->precision, NULL)) return -1; } g_object_set(object, "out", vips_image_new(), NULL); if (vips_image_write(t[1], gaussblur->out)) return -1; return 0; } static void vips_gaussblur_class_init(VipsGaussblurClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gaussblur"; object_class->description = _("gaussian blur"); object_class->build = vips_gaussblur_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGaussblur, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsGaussblur, out)); VIPS_ARG_DOUBLE(class, "sigma", 3, _("Sigma"), _("Sigma of Gaussian"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGaussblur, sigma), 0.0, 1000, 1.5); VIPS_ARG_DOUBLE(class, "min_ampl", 3, _("Minimum amplitude"), _("Minimum amplitude of Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussblur, min_ampl), 0.001, 1.0, 0.2); VIPS_ARG_ENUM(class, "precision", 4, _("Precision"), _("Convolve with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussblur, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER); } static void vips_gaussblur_init(VipsGaussblur *gaussblur) { gaussblur->sigma = 1.5; gaussblur->min_ampl = 0.2; gaussblur->precision = VIPS_PRECISION_INTEGER; } /** * vips_gaussblur: (method) * @in: input image * @out: (out): output image * @sigma: how large a mask to use * @...: `NULL`-terminated list of optional named arguments * * This operator runs [ctor@Image.gaussmat] and [method@Image.convsep] for * you on an image. * * Set @min_ampl smaller to generate a larger, more accurate mask. Set @sigma * larger to make the blur more blurry. * * ::: tip "Optional arguments" * * @precision: [enum@Precision], precision for blur, default int * * @min_ampl: `gdouble`, minimum amplitude, default 0.2 * * ::: seealso * [ctor@Image.gaussmat], [method@Image.convsep]. * * Returns: 0 on success, -1 on error. */ int vips_gaussblur(VipsImage *in, VipsImage **out, double sigma, ...) { va_list ap; int result; va_start(ap, sigma); result = vips_call_split("gaussblur", ap, in, out, sigma); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/meson.build000066400000000000000000000011621516303661500214610ustar00rootroot00000000000000convolution_sources = files( 'canny.c', 'edge.c', 'convolution.c', 'correlation.c', 'conv.c', 'conva.c', 'convf.c', 'convi.c', 'convi_hwy.cpp', 'convasep.c', 'convsep.c', 'compass.c', 'fastcor.c', 'spcor.c', 'sharpen.c', 'gaussblur.c', ) convolution_headers = files( 'pconvolution.h', 'correlation.h', ) libvips_sources += convolution_sources convolution_lib = static_library('convolution', convolution_sources, convolution_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += convolution_lib libvips-8.18.2/libvips/convolution/pconvolution.h000066400000000000000000000043201516303661500222260ustar00rootroot00000000000000/* base class for all convolution operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PCONVOLUTION_H #define VIPS_PCONVOLUTION_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_CONVOLUTION (vips_convolution_get_type()) #define VIPS_CONVOLUTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_CONVOLUTION, VipsConvolution)) #define VIPS_CONVOLUTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_CONVOLUTION, VipsConvolutionClass)) #define VIPS_IS_CONVOLUTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_CONVOLUTION)) #define VIPS_IS_CONVOLUTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_CONVOLUTION)) #define VIPS_CONVOLUTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_CONVOLUTION, VipsConvolutionClass)) typedef struct _VipsConvolution VipsConvolution; struct _VipsConvolution { VipsOperation parent_instance; VipsImage *in; VipsImage *out; VipsImage *mask; /* @mask cast ready for processing. */ VipsImage *M; }; typedef struct _VipsConvolutionClass { VipsOperationClass parent_class; } VipsConvolutionClass; GType vips_convolution_get_type(void); void vips_convi_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int ne, int nnz, int offset, const int *restrict offsets, const short *restrict mant, int exp); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PCONVOLUTION_H*/ libvips-8.18.2/libvips/convolution/sharpen.c000066400000000000000000000267201516303661500211320ustar00rootroot00000000000000/* Cored sharpen of LABQ image. * * Returns 0 on success and -1 on error * * Copyright: 1995 A. Abbood * Author: A. Abbood * Written on: 30/01/1995 * 15/5/95 JC * - updated for latest 7.3 mods * - m3 parameter removed * - bug fixes and speed-ups * 4/7/95 JC * - x3 parameter added * - xs are now double * 6/7/95 JC * - xs are now ys * - better LUT generation * 12/3/01 JC * - uses separable convolution for umask * - tiny clean ups * 23/7/01 JC * - fix for band extract index changed * 21/4/04 * - switched to gaussian mask and radius * 20/11/04 * - uses extract_bands() to remove and reattach ab for slight speedup * - accepts LabS as well as LabQ for slight speedup * - small code tidies * - ~15% speed up in total * 29/11/06 * - convolve first to help region sharing * 3/2/10 * - gtkdoc * - cleanups * 13/11/13 * - redo as a class * - does any type, any number of bands * 24/2/16 * - swap "radius" for "sigma", allows finer control * - allow a much greater range of parameters * - move to defaults suitable for screen output * 28/8/19 * - fix sigma 0.5 case (thanks 2h4dl) */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsSharpen { VipsOperation parent_instance; VipsImage *in; VipsImage *out; double sigma; double x1; double y2; double y3; double m1; double m2; /* The lut we build. */ int *lut; /* We used to have a radius control. */ int radius; } VipsSharpen; typedef VipsOperationClass VipsSharpenClass; G_DEFINE_TYPE(VipsSharpen, vips_sharpen, VIPS_TYPE_OPERATION); static int vips_sharpen_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion **in = (VipsRegion **) vseq; VipsSharpen *sharpen = (VipsSharpen *) b; VipsRect *r = &out_region->valid; int *lut = sharpen->lut; int x, y; if (vips_reorder_prepare_many(out_region->im, in, r)) return -1; VIPS_GATE_START("vips_sharpen_generate: work"); for (y = 0; y < r->height; y++) { short *p1 = (short *restrict) VIPS_REGION_ADDR(in[0], r->left, r->top + y); short *p2 = (short *restrict) VIPS_REGION_ADDR(in[1], r->left, r->top + y); short *q = (short *restrict) VIPS_REGION_ADDR(out_region, r->left, r->top + y); for (x = 0; x < r->width; x++) { int v1 = p1[x]; int v2 = p2[x]; /* Our LUT is -32768 - 32767. For the v1, v2 * difference to be in this range, both must be 0 - * 32767. */ int diff = ((v1 & 0x7fff) - (v2 & 0x7fff)); int out; g_assert(diff + 32768 >= 0); g_assert(diff + 32768 < 65536); out = v1 + lut[diff + 32768]; if (out < 0) out = 0; if (out > 32767) out = 32767; q[x] = out; } } VIPS_GATE_STOP("vips_sharpen_generate: work"); return 0; } static int vips_sharpen_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsSharpen *sharpen = (VipsSharpen *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 8); VipsImage **args = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; VipsInterpretation old_interpretation; int i; VIPS_GATE_START("vips_sharpen_build: build"); if (VIPS_OBJECT_CLASS(vips_sharpen_parent_class)->build(object)) return -1; /* We used to have a radius control. If that's set but sigma isn't, * use it to set a reasonable value for sigma. */ if (!vips_object_argument_isset(object, "sigma") && vips_object_argument_isset(object, "radius")) sharpen->sigma = 1 + sharpen->radius / 2; // FIXME: Invalidates operation cache in = sharpen->in; old_interpretation = in->Type; if (vips_colourspace(in, &t[0], VIPS_INTERPRETATION_LABS, NULL)) return -1; in = t[0]; if (vips_check_uncoded(class->nickname, in) || vips_check_bands_atleast(class->nickname, in, 3)) return -1; /* Stop at 10% of max ... a bit mean. We always sharpen a short, * so there's no point using a float mask. */ if (vips_gaussmat(&t[1], sharpen->sigma, 0.1, "separable", TRUE, "precision", VIPS_PRECISION_INTEGER, NULL)) return -1; #ifdef DEBUG printf("sharpen: blurring with:\n"); vips_matrixprint(t[1], NULL); #endif /*DEBUG*/ /* Make sure we're short (need this for the LUT) and not eg. float LABS. */ if (vips_cast_short(in, &t[2], NULL)) return -1; in = t[2]; /* Index with the signed difference between two 0 - 32767 images. */ if (!(sharpen->lut = VIPS_ARRAY(object, 65536, int))) return -1; for (i = 0; i < 65536; i++) { /* Rescale to +/- 100. */ double v = (i - 32767) / 327.67; double y; if (v < -sharpen->x1) /* Left of -x1. */ y = (v + sharpen->x1) * sharpen->m2 + -sharpen->x1 * sharpen->m1; else if (v < sharpen->x1) /* Centre section. */ y = v * sharpen->m1; else /* Right of x1. */ y = (v - sharpen->x1) * sharpen->m2 + sharpen->x1 * sharpen->m1; if (y < -sharpen->y3) y = -sharpen->y3; if (y > sharpen->y2) y = sharpen->y2; sharpen->lut[i] = rint(y * 327.67); } #ifdef DEBUG { VipsImage *mat; mat = vips_image_new_matrix(65536, 1); for (i = 0; i < 65536; i++) *VIPS_MATRIX(mat, i, 0) = sharpen->lut[i]; vips_image_write_to_file(mat, "x.v", NULL); printf("lut written to x.v\n"); g_object_unref(mat); } #endif /*DEBUG*/ /* Extract L and the rest, convolve L. */ if (vips_extract_band(in, &args[0], 0, NULL) || vips_extract_band(in, &t[3], 1, "n", in->Bands - 1, NULL) || vips_convsep(args[0], &args[1], t[1], "precision", VIPS_PRECISION_INTEGER, NULL)) return -1; t[5] = vips_image_new(); if (vips_image_pipeline_array(t[5], VIPS_DEMAND_STYLE_FATSTRIP, args)) return -1; if (vips_image_generate(t[5], vips_start_many, vips_sharpen_generate, vips_stop_many, args, sharpen)) return -1; g_object_set(object, "out", vips_image_new(), NULL); /* Reattach the rest. */ if (vips_bandjoin2(t[5], t[3], &t[6], NULL) || vips_colourspace(t[6], &t[7], old_interpretation, NULL) || vips_image_write(t[7], sharpen->out)) return -1; VIPS_GATE_STOP("vips_sharpen_build: build"); return 0; } static void vips_sharpen_class_init(VipsSharpenClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "sharpen"; object_class->description = _("unsharp masking for print"); object_class->build = vips_sharpen_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSharpen, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsSharpen, out)); VIPS_ARG_DOUBLE(class, "sigma", 3, _("Sigma"), _("Sigma of Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSharpen, sigma), 0.000001, 10.0, 0.5); VIPS_ARG_DOUBLE(class, "x1", 5, _("x1"), _("Flat/jaggy threshold"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSharpen, x1), 0, 1000000, 2.0); VIPS_ARG_DOUBLE(class, "y2", 6, _("y2"), _("Maximum brightening"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSharpen, y2), 0, 1000000, 10); VIPS_ARG_DOUBLE(class, "y3", 7, _("y3"), _("Maximum darkening"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSharpen, y3), 0, 1000000, 20); VIPS_ARG_DOUBLE(class, "m1", 8, _("m1"), _("Slope for flat areas"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSharpen, m1), 0, 1000000, 0.0); VIPS_ARG_DOUBLE(class, "m2", 9, _("m2"), _("Slope for jaggy areas"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSharpen, m2), 0, 1000000, 3.0); /* We used to have a radius control. */ VIPS_ARG_INT(class, "radius", 3, _("Radius"), _("Radius of Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsSharpen, radius), 1, 100, 1); } static void vips_sharpen_init(VipsSharpen *sharpen) { sharpen->sigma = 0.5; sharpen->x1 = 2.0; sharpen->y2 = 10.0; sharpen->y3 = 20.0; sharpen->m1 = 0.0; sharpen->m2 = 3.0; } /** * vips_sharpen: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Selectively sharpen the L channel of a LAB image. The input image is * transformed to [enum@Vips.Interpretation.LABS]. * * The operation performs a gaussian blur and subtracts from @in to generate a * high-frequency signal. This signal is passed through a lookup table formed * from the five parameters and added back to @in. * * The lookup table is formed like this: * * ``` * ^ * y2 |- - - - - ----------- * | / * | / slope m2 * | .../ * -x1 | ... | * -------------------...----------------------> * | ... | x1 * |... slope m1 * / | * / m2 | * / | * / | * / | * / | * ______/ _ _ _ _ _ _ | -y3 * | * ``` * * For screen output, we suggest the following settings (the defaults): * * ``` * sigma == 0.5 * x1 == 2 * y2 == 10 (don't brighten by more than 10 L*) * y3 == 20 (can darken by up to 20 L*) * m1 == 0 (no sharpening in flat areas) * m2 == 3 (some sharpening in jaggy areas) * ``` * * If you want more or less sharpening, we suggest you just change the * m2 parameter. * * The @sigma parameter changes the width of the fringe and can be * adjusted according to the output printing resolution. As an approximate * guideline, use 0.5 for 4 pixels/mm (display resolution), * 1.0 for 12 pixels/mm and 1.5 for 16 pixels/mm (300 dpi == 12 * pixels/mm). These figures refer to the image raster, not the half-tone * resolution. * * ::: tip "Optional arguments" * * @sigma: `gdouble`, sigma of gaussian * * @x1: `gdouble`, flat/jaggy threshold * * @y2: `gdouble`, maximum amount of brightening * * @y3: `gdouble`, maximum amount of darkening * * @m1: `gdouble`, slope for flat areas * * @m2: `gdouble`, slope for jaggy areas * * ::: seealso * [method@Image.conv]. * * Returns: 0 on success, -1 on error. */ int vips_sharpen(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("sharpen", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/convolution/spcor.c000066400000000000000000000216661516303661500206240ustar00rootroot00000000000000/* spcor * * Copyright: 1990, N. Dessipris; 2006, 2007 Nottingham Trent University. * * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on : * 20/2/95 JC * - updated * - ANSIfied, a little * 21/2/95 JC * - rewritten * - partialed * - speed-ups * - new correlation coefficient (see above), from Niblack "An * Introduction to Digital Image Processing", Prentice/Hall, pp 138. * 4/9/97 JC * - now does short/ushort as well * 13/2/03 JC * - oops, could segv for short images * 14/4/04 JC * - sets Xoffset / Yoffset * 8/3/06 JC * - use im_embed() with edge stretching on the input, not the output * * 2006-10-24 tcv * - add im_spcor2 * * 2007-11-12 tcv * - make im_spcor a wrapper selecting either im__spcor or im__spcor2 * 2008-09-09 JC * - roll back the windowed version for now, it has some tile edge effects * 3/2/10 * - gtkdoc * - cleanups * 7/11/13 * - redone as a class * 8/4/15 * - avoid /0 for constant reference or zero image */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pconvolution.h" #include "correlation.h" typedef struct _VipsSpcor { VipsCorrelation parent_instance; /* Per-band mean of ref images. */ double *rmean; /* Per band sqrt(sumij (ref(i,j)-mean(ref))^2) */ double *c1; } VipsSpcor; typedef VipsCorrelationClass VipsSpcorClass; G_DEFINE_TYPE(VipsSpcor, vips_spcor, VIPS_TYPE_CORRELATION); static int vips_spcor_pre_generate(VipsCorrelation *correlation) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(correlation); VipsSpcor *spcor = (VipsSpcor *) correlation; VipsImage *ref = correlation->ref_ready; int bands = ref->Bands; VipsImage **b = (VipsImage **) vips_object_local_array(VIPS_OBJECT(spcor), bands); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(spcor), 2); VipsImage **b2 = (VipsImage **) vips_object_local_array(VIPS_OBJECT(spcor), bands); int i; double *offset; double *scale; if (vips_check_noncomplex(class->nickname, ref)) return -1; /* Per-band mean. */ if (!(spcor->rmean = VIPS_ARRAY(spcor, bands, double)) || !(spcor->c1 = VIPS_ARRAY(spcor, bands, double))) return -1; for (i = 0; i < bands; i++) if (vips_extract_band(ref, &b[i], i, NULL) || vips_avg(b[i], &spcor->rmean[i], NULL)) return -1; /* Per band sqrt(sumij (ref(i,j)-mean(ref))^2) */ if (!(offset = VIPS_ARRAY(spcor, bands, double)) || !(scale = VIPS_ARRAY(spcor, bands, double))) return -1; for (i = 0; i < bands; i++) { offset[i] = -spcor->rmean[i]; scale[i] = 1.0; } if (vips_linear(ref, &t[0], scale, offset, bands, NULL) || vips_multiply(t[0], t[0], &t[1], NULL)) return -1; for (i = 0; i < bands; i++) if (vips_extract_band(t[1], &b2[i], i, NULL) || vips_avg(b2[i], &spcor->c1[i], NULL)) return -1; for (i = 0; i < bands; i++) { spcor->c1[i] *= ref->Xsize * ref->Ysize; spcor->c1[i] = sqrt(spcor->c1[i]); } return 0; } #define LOOP(IN) \ { \ IN *r1 = ((IN *) ref->data) + b; \ IN *p1 = ((IN *) p) + b; \ int in_lsk = lsk / sizeof(IN); \ IN *r1a; \ IN *p1a; \ \ /* Mean of area of in corresponding to ref. \ */ \ p1a = p1; \ sum1 = 0.0; \ for (j = 0; j < ref->Ysize; j++) { \ for (i = 0; i < sz; i += bands) \ sum1 += p1a[i]; \ p1a += in_lsk; \ } \ imean = sum1 / VIPS_IMAGE_N_PELS(ref); \ \ /* Calculate sum-of-squares-of-differences for this window on \ * in, and also sum-of-products-of-differences from mean. \ */ \ p1a = p1; \ r1a = r1; \ sum2 = 0.0; \ sum3 = 0.0; \ for (j = 0; j < ref->Ysize; j++) { \ for (i = 0; i < sz; i += bands) { \ /* Reference pel and input pel. \ */ \ IN ip = p1a[i]; \ IN rp = r1a[i]; \ \ /* Accumulate sum-of-squares-of-differences for \ * input image. \ */ \ double t = ip - imean; \ sum2 += t * t; \ \ /* Accumulate product-of-difference from mean. \ */ \ sum3 += (rp - spcor->rmean[b]) * t; \ } \ \ p1a += in_lsk; \ r1a += sz; \ } \ } static void vips_spcor_correlation(VipsCorrelation *correlation, VipsRegion *in, VipsRegion *out) { VipsSpcor *spcor = (VipsSpcor *) correlation; VipsRect *r = &out->valid; VipsImage *ref = correlation->ref_ready; int bands = vips_band_format_iscomplex(ref->BandFmt) ? ref->Bands * 2 : ref->Bands; int sz = ref->Xsize * bands; int lsk = VIPS_REGION_LSKIP(in); int x, y, b, j, i; double imean; double sum1; double sum2, sum3; double c2, cc; for (y = 0; y < r->height; y++) { float *q = (float *) VIPS_REGION_ADDR(out, r->left, r->top + y); for (x = 0; x < r->width; x++) { VipsPel *p = VIPS_REGION_ADDR(in, r->left + x, r->top + y); for (b = 0; b < bands; b++) { switch (vips_image_get_format(ref)) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOP(signed char); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOP(signed short); break; case VIPS_FORMAT_UINT: LOOP(unsigned int); break; case VIPS_FORMAT_INT: LOOP(signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: LOOP(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: LOOP(double); break; default: g_assert_not_reached(); /* Stop compiler warnings. */ sum2 = 0; sum3 = 0; } c2 = spcor->c1[b] * sqrt(sum2); if (c2 == 0.0) /* Something like constant ref. * We regard this as uncorrelated. */ cc = 0.0; else cc = sum3 / c2; *q++ = cc; } } } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_spcor_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ F, F, F, F, F, F, F, F, F, F }; static void vips_spcor_class_init(VipsSpcorClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsCorrelationClass *cclass = VIPS_CORRELATION_CLASS(class); object_class->nickname = "spcor"; object_class->description = _("spatial correlation"); cclass->format_table = vips_spcor_format_table; cclass->pre_generate = vips_spcor_pre_generate; cclass->correlation = vips_spcor_correlation; } static void vips_spcor_init(VipsSpcor *spcor) { } /** * vips_spcor: (method) * @in: input image * @ref: reference image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Calculate a correlation surface. * * @ref is placed at every position in @in and the correlation coefficient * calculated. The output * image is always float. * * The output * image is the same size as the input. Extra input edge pixels are made by * copying the existing edges outwards. * * The correlation coefficient is calculated as: * * ``` * sumij (ref(i,j)-mean(ref))(inkl(i,j)-mean(inkl)) * c(k,l) = ------------------------------------------------ * sqrt(sumij (ref(i,j)-mean(ref))^2) * * sqrt(sumij (inkl(i,j)-mean(inkl))^2) * ``` * * where inkl is the area of @in centred at position (k,l). * * from Niblack "An Introduction to Digital Image Processing", * Prentice/Hall, pp 138. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The output image is always float, unless either of the two inputs is * double, in which case the output is also double. * * ::: seealso * [method@Image.fastcor]. * * Returns: 0 on success, -1 on error */ int vips_spcor(VipsImage *in, VipsImage *ref, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("spcor", ap, in, ref, out); va_end(ap); return result; } libvips-8.18.2/libvips/create/000077500000000000000000000000001516303661500162035ustar00rootroot00000000000000libvips-8.18.2/libvips/create/black.c000066400000000000000000000104051516303661500174230ustar00rootroot00000000000000/* black.c * * Copyright: 1990, J. Cupitt * * Author: J. Cupitt * Written on: 02/08/1990 * Modified on : 16/04/1991 by N. Dessipris to work on a line by line basis * 15/8/94 JC * - adapted for partials * - ANSIfied * - memory leaks fixed! * 2/3/98 JC * - IM_ANY added * 18/1/09 * - gtkdoc * 31/10/11 * - redo as a class * 3/4/18 * - always write MULTIBAND, otherwise when we join up these things it'll * look like we have an alpha */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsBlack { VipsCreate parent_instance; int width; int height; int bands; } VipsBlack; typedef VipsCreateClass VipsBlackClass; G_DEFINE_TYPE(VipsBlack, vips_black, VIPS_TYPE_CREATE); static int vips_black_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { /* VipsRect *r = &out_region->valid; printf("vips_black_gen: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); */ vips_region_black(out_region); return 0; } static int vips_black_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsBlack *black = (VipsBlack *) object; if (VIPS_OBJECT_CLASS(vips_black_parent_class)->build(object)) return -1; vips_image_init_fields(create->out, black->width, black->height, black->bands, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL)) return -1; if (vips_image_generate(create->out, NULL, vips_black_gen, NULL, NULL, NULL)) return -1; return 0; } static void vips_black_class_init(VipsBlackClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_black_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "black"; vobject_class->description = _("make a black image"); vobject_class->build = vips_black_build; VIPS_ARG_INT(class, "width", 4, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBlack, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBlack, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "bands", 6, _("Bands"), _("Number of bands in image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsBlack, bands), 1, VIPS_MAX_COORD, 1); } static void vips_black_init(VipsBlack *black) { black->bands = 1; } /** * vips_black: * @out: (out): output image * @width: output width * @height: output height * @...: `NULL`-terminated list of optional named arguments * * Make a black unsigned char image of a specified size. * * ::: tip "Optional arguments" * * @bands: `gint`, output bands * * ::: seealso * [ctor@Image.xyz], [ctor@Image.text], [ctor@Image.gaussnoise]. * * Returns: 0 on success, -1 on error */ int vips_black(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("black", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/buildlut.c000066400000000000000000000165401516303661500202010ustar00rootroot00000000000000/* Build a LUT from a set of x/y points. * * Written on: 26/9/06 * - from im_invertlut() * 9/10/06 * - don't output x values * 18/3/09 * - saner limit and rounding behaviour * 30/3/09 * - argh, fixed again * 22/6/09 * - more fixes for tables that don't start at zero (thanks Jack) * 23/3/10 * - gtkdoc * 2/7/13 * - convert to a class * 10/12/13 * - be more forgiving about x vales not quite integers */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcreate.h" typedef struct _VipsBuildlut { VipsCreate parent_instance; /* Input image. */ VipsImage *in; /* .. and cast to a matrix. */ VipsImage *mat; int xlow; /* Index 0 in output is this x */ int lut_size; /* Number of output elements to generate */ double **data; /* Matrix row pointers */ double *buf; /* Output buffer */ } VipsBuildlut; typedef VipsCreateClass VipsBuildlutClass; G_DEFINE_TYPE(VipsBuildlut, vips_buildlut, VIPS_TYPE_CREATE); static void vips_buildlut_dispose(GObject *gobject) { VipsBuildlut *lut = (VipsBuildlut *) gobject; VIPS_FREE(lut->data); VIPS_FREE(lut->buf); VIPS_UNREF(lut->mat); G_OBJECT_CLASS(vips_buildlut_parent_class)->dispose(gobject); } /* Use this to sort our input rows by the first column. */ static int vips_buildlut_compare(const void *a, const void *b) { double **r1 = (double **) a; double **r2 = (double **) b; double diff = r1[0][0] - r2[0][0]; if (diff > 0) return 1; else if (diff == 0) return 0; else return -1; } static int vips_buildlut_build_init(VipsBuildlut *lut) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(lut); int y; int xlow, xhigh; /* Need xlow and xhigh to get the size of the LUT we build. */ xlow = xhigh = *VIPS_MATRIX(lut->mat, 0, 0); for (y = 0; y < lut->mat->Ysize; y++) { double v = *VIPS_MATRIX(lut->mat, 0, y); /* Allow for being a bit off. */ if (fabs(v - rint(v)) > 0.001) { vips_error(class->nickname, _("x value row %d not an int"), y); return -1; } v = rint(v); if (v < xlow) xlow = v; if (v > xhigh) xhigh = v; } lut->xlow = xlow; lut->lut_size = xhigh - xlow + 1; if (lut->lut_size < 1) { vips_error(class->nickname, "%s", _("x range too small")); return -1; } if (!(lut->data = VIPS_ARRAY(NULL, lut->mat->Ysize, double *))) return -1; for (y = 0; y < lut->mat->Ysize; y++) lut->data[y] = VIPS_MATRIX(lut->mat, 0, y); if (!(lut->buf = VIPS_ARRAY(NULL, lut->lut_size * (lut->mat->Xsize - 1), double))) return -1; /* Sort by 1st column in input. */ qsort(lut->data, lut->mat->Ysize, sizeof(double *), vips_buildlut_compare); #ifdef DEBUG printf("Input table, sorted by 1st column\n"); for (y = 0; y < lut->mat->Ysize; y++) { int x; printf("%.4d ", y); for (x = 0; x < lut->mat->Xsize; x++) printf("%.9f ", lut->data[y][x]); printf("\n"); } #endif /*DEBUG*/ return 0; } static int vips_buildlut_build_create(VipsBuildlut *lut) { const int xlow = lut->xlow; const VipsImage *mat = lut->mat; const int xsize = mat->Xsize; const int ysize = mat->Ysize; const int bands = xsize - 1; const int xlast = lut->data[ysize - 1][0]; int b, i, x; /* Do each output channel separately. */ for (b = 0; b < bands; b++) { for (i = 0; i < ysize - 1; i++) { const int x1 = rint(lut->data[i][0]); const int x2 = rint(lut->data[i + 1][0]); const int dx = x2 - x1; const double y1 = lut->data[i][b + 1]; const double y2 = lut->data[i + 1][b + 1]; const double dy = y2 - y1; for (x = 0; x < dx; x++) lut->buf[b + (x + x1 - xlow) * bands] = y1 + x * dy / dx; } /* We are inclusive: pop the final value in by hand. */ lut->buf[b + (xlast - xlow) * bands] = lut->data[ysize - 1][b + 1]; } return 0; } static int vips_buildlut_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsBuildlut *lut = (VipsBuildlut *) object; if (VIPS_OBJECT_CLASS(vips_buildlut_parent_class)->build(object)) return -1; if (vips_check_matrix(class->nickname, lut->in, &lut->mat)) return -1; if (vips_buildlut_build_init(lut) || vips_buildlut_build_create(lut)) return -1; vips_image_init_fields(create->out, lut->lut_size, 1, lut->mat->Xsize - 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (vips_image_write_line(create->out, 0, (VipsPel *) lut->buf)) return -1; return 0; } static void vips_buildlut_class_init(VipsBuildlutClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = vips_buildlut_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "buildlut"; vobject_class->description = _("build a look-up table"); vobject_class->build = vips_buildlut_build; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Matrix of XY coordinates"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsBuildlut, in)); } static void vips_buildlut_init(VipsBuildlut *lut) { } /** * vips_buildlut: (method) * @in: input matrix * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operation builds a lookup table from a set of points. Intermediate * values are generated by piecewise linear interpolation. The lookup table is * always of type [enum@Vips.BandFormat.DOUBLE], use [method@Image.cast] to * change it to the type you need. * * For example, consider this 2 x 2 matrix of (x, y) coordinates: * * ``` * 2 2 * 0 0 * 255 100 * ``` * * We then generate a 1 x 256 element LUT like this: * * | Index | Value | * |-------|-------| * | 0 | 0 | * | 1 | 0.4 | * | etc. | 0.4 | * | 255 | 100 | * This is then written as the output image, with the left column giving the * index in the image to place the value. * * The (x, y) points don't need to be sorted: we do that. You can have * several Ys, each becomes a band in the output LUT. You don't need to * start at zero, any integer will do, including negatives. * * ::: seealso * [ctor@Image.identity], [method@Image.invertlut], [method@Image.cast], * [method@Image.maplut]. * * Returns: 0 on success, -1 on error */ int vips_buildlut(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("buildlut", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/create/create.c000066400000000000000000000122121516303661500176100ustar00rootroot00000000000000/* base class for all create operations * * properties: * - single output image we build */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" /** * VipsTextWrap: * @VIPS_TEXT_WRAP_WORD: wrap at word boundaries * @VIPS_TEXT_WRAP_CHAR: wrap at character boundaries * @VIPS_TEXT_WRAP_WORD_CHAR: wrap at word boundaries, but fall back to character boundaries if there is not enough space for a full word * @VIPS_TEXT_WRAP_NONE: no wrapping * * Sets the word wrapping style for [ctor@Image.text] when used with a maximum * width. * * ::: seealso * [ctor@Image.text]. */ /** * VipsSdfShape: * @VIPS_SDF_SHAPE_CIRCLE: a circle at @a, radius @r * @VIPS_SDF_SHAPE_BOX: a box from @a to @b * @VIPS_SDF_SHAPE_ROUNDED_BOX: a box with rounded @corners from @a to @b * @VIPS_SDF_SHAPE_LINE: a line from @a to @b * * The SDF to generate, * * ::: seealso * [ctor@Image.sdf]. */ G_DEFINE_ABSTRACT_TYPE(VipsCreate, vips_create, VIPS_TYPE_OPERATION); static int vips_create_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); #ifdef DEBUG printf("vips_create_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_object_set(create, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_create_parent_class)->build(object)) return -1; return 0; } static void vips_create_class_init(VipsCreateClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "create"; vobject_class->description = _("create operations"); vobject_class->build = vips_create_build; VIPS_ARG_IMAGE(class, "out", 1, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsCreate, out)); } static void vips_create_init(VipsCreate *create) { } void vips_create_operation_init(void) { extern GType vips_black_get_type(void); extern GType vips_gaussmat_get_type(void); extern GType vips_logmat_get_type(void); extern GType vips_gaussnoise_get_type(void); #ifdef HAVE_PANGOCAIRO extern GType vips_text_get_type(void); #endif /*HAVE_PANGOCAIRO*/ extern GType vips_xyz_get_type(void); extern GType vips_sdf_get_type(void); extern GType vips_eye_get_type(void); extern GType vips_grey_get_type(void); extern GType vips_zone_get_type(void); extern GType vips_sines_get_type(void); extern GType vips_buildlut_get_type(void); extern GType vips_invertlut_get_type(void); extern GType vips_tonelut_get_type(void); extern GType vips_identity_get_type(void); extern GType vips_mask_butterworth_get_type(void); extern GType vips_mask_butterworth_ring_get_type(void); extern GType vips_mask_butterworth_band_get_type(void); extern GType vips_mask_gaussian_get_type(void); extern GType vips_mask_gaussian_ring_get_type(void); extern GType vips_mask_gaussian_band_get_type(void); extern GType vips_mask_ideal_get_type(void); extern GType vips_mask_ideal_ring_get_type(void); extern GType vips_mask_ideal_band_get_type(void); extern GType vips_mask_fractal_get_type(void); extern GType vips_fractsurf_get_type(void); extern GType vips_worley_get_type(void); extern GType vips_perlin_get_type(void); vips_black_get_type(); vips_gaussmat_get_type(); vips_logmat_get_type(); vips_gaussnoise_get_type(); #ifdef HAVE_PANGOCAIRO vips_text_get_type(); #endif /*HAVE_PANGOCAIRO*/ vips_xyz_get_type(); vips_sdf_get_type(); vips_eye_get_type(); vips_grey_get_type(); vips_zone_get_type(); vips_sines_get_type(); vips_buildlut_get_type(); vips_invertlut_get_type(); vips_tonelut_get_type(); vips_identity_get_type(); vips_mask_ideal_get_type(); vips_mask_ideal_ring_get_type(); vips_mask_ideal_band_get_type(); vips_mask_butterworth_get_type(); vips_mask_butterworth_ring_get_type(); vips_mask_butterworth_band_get_type(); vips_mask_gaussian_get_type(); vips_mask_gaussian_ring_get_type(); vips_mask_gaussian_band_get_type(); vips_mask_fractal_get_type(); vips_fractsurf_get_type(); vips_worley_get_type(); vips_perlin_get_type(); } libvips-8.18.2/libvips/create/eye.c000066400000000000000000000066141516303661500171400ustar00rootroot00000000000000/* make a test pattern to show the eye's frequency response * * Copyright: 1990, 1991, N.Dessipris. * * Author N. Dessipris * Written on 30/05/1990 * Updated on: 27/01/1991, 07/03/1991, * 22/7/93 JC * - im_outcheck() added * 30/8/95 JC * - modernized * 1/2/11 * - gtk-doc * 13/6/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" typedef struct _VipsEye { VipsPoint parent_instance; double factor; } VipsEye; typedef VipsPointClass VipsEyeClass; G_DEFINE_TYPE(VipsEye, vips_eye, VIPS_TYPE_POINT); static float vips_eye_point(VipsPoint *point, int x, int y) { VipsEye *eye = (VipsEye *) point; /* VIPS_MAX to prevent /0. */ int max_x = VIPS_MAX(point->width - 1, 1); int max_y = VIPS_MAX(point->height - 1, 1); float c = eye->factor * VIPS_PI / (2 * max_x); float h = max_y * max_y; return y * y * cosf(c * x * x) / h; } static void vips_eye_class_init(VipsEyeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsPointClass *point_class = VIPS_POINT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "eye"; vobject_class->description = _("make an image showing the eye's spatial response"); point_class->point = vips_eye_point; VIPS_ARG_DOUBLE(class, "factor", 6, _("Factor"), _("Maximum spatial frequency"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsEye, factor), 0.0, 1.0, 0.5); } static void vips_eye_init(VipsEye *eye) { eye->factor = 0.5; } /** * vips_eye: * @out: (out): output image * @width: image size * @height: image size * @...: `NULL`-terminated list of optional named arguments * * Create a test pattern with increasing spatial frequency in X and * amplitude in Y. * * @factor should be between 0 and 1 and determines the * maximum spatial frequency. * * Set @uchar to output a uchar image. * * ::: tip "Optional arguments" * * @factor: `gdouble`, maximum spatial frequency * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.zone]. * * Returns: 0 on success, -1 on error */ int vips_eye(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("eye", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/fractsurf.c000066400000000000000000000076041516303661500203550ustar00rootroot00000000000000/* fractal surface * * Author: N. Dessipris * Written on: 10/09/1991 * Modified on: * 20/9/95 JC * - modernised, a little * 7/2/10 * - cleanups * - gtkdoc * 4/1/14 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pcreate.h" typedef struct _VipsFractsurf { VipsCreate parent_instance; int width; int height; double fractal_dimension; } VipsFractsurf; typedef VipsCreateClass VipsFractsurfClass; G_DEFINE_TYPE(VipsFractsurf, vips_fractsurf, VIPS_TYPE_CREATE); static int vips_fractsurf_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsFractsurf *fractsurf = (VipsFractsurf *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); if (VIPS_OBJECT_CLASS(vips_fractsurf_parent_class)->build(object)) return -1; if (vips_gaussnoise(&t[0], fractsurf->width, fractsurf->height, "mean", 0.0, "sigma", 1.0, NULL) || vips_mask_fractal(&t[1], fractsurf->width, fractsurf->height, fractsurf->fractal_dimension, NULL) || vips_freqmult(t[0], t[1], &t[2], NULL) || vips_image_write(t[2], create->out)) return -1; return 0; } static void vips_fractsurf_class_init(VipsFractsurfClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "fractsurf"; vobject_class->description = _("make a fractal surface"); vobject_class->build = vips_fractsurf_build; VIPS_ARG_INT(class, "width", 4, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFractsurf, width), 1, VIPS_MAX_COORD, 64); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFractsurf, height), 1, VIPS_MAX_COORD, 64); VIPS_ARG_DOUBLE(class, "fractal_dimension", 8, _("Fractal dimension"), _("Fractal dimension"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFractsurf, fractal_dimension), 2.0, 3.0, 2.5); } static void vips_fractsurf_init(VipsFractsurf *fractsurf) { fractsurf->width = 64; fractsurf->height = 64; fractsurf->fractal_dimension = 2.5; } /** * vips_fractsurf: * @out: (out): output image * @width: output width * @height: output height * @fractal_dimension: fractal dimension * @...: `NULL`-terminated list of optional named arguments * * Generate an image of size @width by @height and fractal dimension * @fractal_dimension. The dimension should be between 2 and 3. * * ::: seealso * [ctor@Image.gaussnoise], [ctor@Image.mask_fractal]. * * Returns: 0 on success, -1 on error */ int vips_fractsurf(VipsImage **out, int width, int height, double fractal_dimension, ...) { va_list ap; int result; va_start(ap, fractal_dimension); result = vips_call_split("fractsurf", ap, out, width, height, fractal_dimension); va_end(ap); return result; } libvips-8.18.2/libvips/create/gaussmat.c000066400000000000000000000160271516303661500202010ustar00rootroot00000000000000/* generate gaussian images * * Written on: 30/11/1989 by Nicos * Updated on: 6/12/1991 * 7/8/96 JC * - ansified, mem leaks plugged * 20/11/98 JC * - mask too large check added * 18/3/09 * - bumped max mask size *40 * - added _sep variant * 30/3/09 * - set scale in _sep variant, why not * 21/10/10 * - gtkdoc * 20/10/13 * - redone as a class * 16/12/14 * - default to int output to match vips_conv() * - use @precision, not @integer * 10/3/16 * - allow 1x1 masks * - better size calc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsGaussmat { VipsCreate parent_instance; double sigma; double min_ampl; gboolean separable; gboolean integer; /* Deprecated */ VipsPrecision precision; } VipsGaussmat; typedef struct _VipsGaussmatClass { VipsCreateClass parent_class; } VipsGaussmatClass; G_DEFINE_TYPE(VipsGaussmat, vips_gaussmat, VIPS_TYPE_CREATE); /* Don't allow mask radius to go over this. */ #define MASK_SANITY (5000) static int vips_gaussmat_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsGaussmat *gaussmat = (VipsGaussmat *) object; double sig2 = 2. * gaussmat->sigma * gaussmat->sigma; int max_x = VIPS_CLIP(0, 8 * gaussmat->sigma, MASK_SANITY); int x, y; int width, height; double sum; if (VIPS_OBJECT_CLASS(vips_gaussmat_parent_class)->build(object)) return -1; /* The old, deprecated @integer property has been deliberately set to * FALSE and they've not used the new @precision property ... switch * to float to help them out. */ if (vips_object_argument_isset(object, "integer") && !vips_object_argument_isset(object, "precision") && !gaussmat->integer) gaussmat->precision = VIPS_PRECISION_FLOAT; // FIXME: Invalidates operation cache /* Find the size of the mask. Limit the mask size to 10k x 10k for * sanity. We allow x == 0, meaning a 1x1 mask. */ for (x = 0; x < max_x; x++) { double v = exp(-((double) (x * x)) / sig2); if (v < gaussmat->min_ampl) break; } if (x >= MASK_SANITY) { vips_error(class->nickname, "%s", _("mask too large")); return -1; } width = 2 * VIPS_MAX(x - 1, 0) + 1; height = gaussmat->separable ? 1 : width; vips_image_init_fields(create->out, width, height, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_write_prepare(create->out)) return -1; sum = 0.0; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { int xo = x - width / 2; int yo = y - height / 2; double distance = xo * xo + yo * yo; double v = exp(-distance / sig2); if (gaussmat->precision != VIPS_PRECISION_FLOAT) v = rint(20 * v); *VIPS_MATRIX(create->out, x, y) = v; sum += v; } } /* Make sure we can't make sum == 0: it'd certainly cause /0 later. */ if (sum == 0) sum = 1; vips_image_set_double(create->out, "scale", sum); vips_image_set_double(create->out, "offset", 0.0); return 0; } static void vips_gaussmat_class_init(VipsGaussmatClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "gaussmat"; vobject_class->description = _("make a gaussian image"); vobject_class->build = vips_gaussmat_build; VIPS_ARG_DOUBLE(class, "sigma", 2, _("Sigma"), _("Sigma of Gaussian"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGaussmat, sigma), 0.000001, 10000.0, 1.0); VIPS_ARG_DOUBLE(class, "min_ampl", 3, _("Minimum amplitude"), _("Minimum amplitude of Gaussian"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGaussmat, min_ampl), 0.000001, 10000.0, 0.1); VIPS_ARG_BOOL(class, "separable", 4, _("Separable"), _("Generate separable Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussmat, separable), FALSE); VIPS_ARG_BOOL(class, "integer", 5, _("Integer"), _("Generate integer Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsGaussmat, integer), FALSE); VIPS_ARG_ENUM(class, "precision", 6, _("Precision"), _("Generate with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussmat, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER); } static void vips_gaussmat_init(VipsGaussmat *gaussmat) { gaussmat->sigma = 1; gaussmat->min_ampl = 0.1; gaussmat->precision = VIPS_PRECISION_INTEGER; } /** * vips_gaussmat: * @out: (out): output image * @sigma: standard deviation of mask * @min_ampl: minimum amplitude * @...: `NULL`-terminated list of optional named arguments * * Creates a circularly symmetric Gaussian image of radius * @sigma. * * The size of the mask is determined by the variable @min_ampl; * if for instance the value .1 is entered this means that the produced mask * is clipped at values less than 10 percent of the maximum amplitude. * * The program uses the following equation: * * ``` * H(r) = exp(-(r * r) / (2 * @sigma * @sigma)) * ``` * * The generated image has odd size and its maximum value is normalised to * 1.0, unless @precision is [enum@Vips.Precision.INTEGER]. * * If @separable is set, only the centre horizontal is generated. This is * useful for separable convolutions. * * If @precision is [enum@Vips.Precision.INTEGER], an integer gaussian is * generated. This is useful for integer convolutions. * * "scale" is set to the sum of all the mask elements. * * ::: tip "Optional arguments" * * @separable: `gboolean`, generate a separable gaussian * * @precision: [enum@Precision] for @out * * ::: seealso * [ctor@Image.logmat], [method@Image.conv]. * * Returns: 0 on success, -1 on error */ int vips_gaussmat(VipsImage **out, double sigma, double min_ampl, ...) { va_list ap; int result; va_start(ap, min_ampl); result = vips_call_split("gaussmat", ap, out, sigma, min_ampl); va_end(ap); return result; } libvips-8.18.2/libvips/create/gaussnoise.c000066400000000000000000000137321516303661500205350ustar00rootroot00000000000000/* im_gaussnoise * * Copyright 1990, N. Dessipris. * * File written on 2/12/1986 * Author : N. Dessipris * Updated : 6/6/1991 * 21/7/93 JC * - im_outcheck() call added * 1/2/95 JC * - declaration for drand48() added * - partialised, adapting im_gaussnoise() * 23/10/98 JC * - drand48() changed to random() for portability * 21/10/02 JC * - tries rand() if random() is not available * - uses RAND_MAX, d'oh * 29/1/10 * - cleanups * - gtkdoc * 29/5/13 * - redo as a class * 8/11/14 * - use g_random_double() * 24/1/17 * - use g_random_double() once per image, use vips__random() for pixel * values from (x, y) position ... makes pixels reproducible on * recalculation */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcreate.h" typedef struct _VipsGaussnoise { VipsCreate parent_instance; int width; int height; double mean; double sigma; /* Per-image seed. Each pixel is seeded by this plus the (x, * y) coordinate. */ guint32 seed; } VipsGaussnoise; typedef VipsCreateClass VipsGaussnoiseClass; G_DEFINE_TYPE(VipsGaussnoise, vips_gaussnoise, VIPS_TYPE_CREATE); static int vips_gaussnoise_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsGaussnoise *gaussnoise = (VipsGaussnoise *) a; int sz = VIPS_REGION_N_ELEMENTS(out_region); int y; for (y = 0; y < out_region->valid.height; y++) { float *q = (float *) VIPS_REGION_ADDR(out_region, out_region->valid.left, y + out_region->valid.top); int x; for (x = 0; x < sz; x++) { guint32 seed; double sum; int i; seed = gaussnoise->seed; seed = vips__random_add(seed, out_region->valid.left + x); seed = vips__random_add(seed, out_region->valid.top + y); sum = 0.0; for (i = 0; i < 12; i++) { seed = vips__random(seed); sum += (double) seed / UINT_MAX; } q[x] = (sum - 6.0) * gaussnoise->sigma + gaussnoise->mean; } } return 0; } static int vips_gaussnoise_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsGaussnoise *gaussnoise = (VipsGaussnoise *) object; if (VIPS_OBJECT_CLASS(vips_gaussnoise_parent_class)->build(object)) return -1; vips_image_init_fields(create->out, gaussnoise->width, gaussnoise->height, 1, VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(create->out, NULL, vips_gaussnoise_gen, NULL, gaussnoise, NULL)) return -1; return 0; } static void vips_gaussnoise_class_init(VipsGaussnoiseClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = (VipsOperationClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "gaussnoise"; vobject_class->description = _("make a gaussnoise image"); vobject_class->build = vips_gaussnoise_build; /* We want a new set of numbers each time. */ operation_class->flags |= VIPS_OPERATION_NOCACHE; VIPS_ARG_INT(class, "width", 4, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGaussnoise, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGaussnoise, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_DOUBLE(class, "mean", 6, _("Mean"), _("Mean of pixels in generated image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussnoise, mean), -10000000, 1000000, 128); VIPS_ARG_DOUBLE(class, "sigma", 6, _("Sigma"), _("Standard deviation of pixels in generated image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussnoise, sigma), 0, 100000, 30); VIPS_ARG_INT(class, "seed", 7, _("Seed"), _("Random number seed"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGaussnoise, seed), INT_MIN, INT_MAX, 0); } static void vips_gaussnoise_init(VipsGaussnoise *gaussnoise) { gaussnoise->mean = 128.0; gaussnoise->sigma = 30.0; gaussnoise->seed = UINT_MAX * g_random_double(); } /** * vips_gaussnoise: * @out: (out): output image * @width: output width * @height: output height * @...: `NULL`-terminated list of optional named arguments * * Make a one band float image of gaussian noise with the specified * distribution. * * The gaussian distribution is created by averaging 12 random numbers from a * linear generator, then weighting appropriately with @mean and @sigma. * * ::: tip "Optional arguments" * * @mean: `gdouble`, mean of generated pixels * * @sigma: `gdouble`, standard deviation of generated pixels * * ::: seealso * [ctor@Image.black], [ctor@Image.xyz], [ctor@Image.text]. * * Returns: 0 on success, -1 on error */ int vips_gaussnoise(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("gaussnoise", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/grey.c000066400000000000000000000056111516303661500173200ustar00rootroot00000000000000/* grey ramps * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/02/1990 * Modified on: * 22/7/93 JC * - im_outcheck() added * - externs removed * 8/2/95 JC * - ANSIfied * - im_fgrey() made from im_grey() * 31/8/95 JC * - now makes [0,1], rather than [0,256) * - im_grey() now defined in terms of im_fgrey() * 2/3/98 JC * - partialed * 1/2/11 * - gtk-doc * 13/6/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" typedef VipsPoint VipsGrey; typedef VipsPointClass VipsGreyClass; G_DEFINE_TYPE(VipsGrey, vips_grey, VIPS_TYPE_POINT); static float vips_grey_point(VipsPoint *point, int x, int y) { return (double) x / (point->width - 1); } static void vips_grey_class_init(VipsGreyClass *class) { VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsPointClass *point_class = VIPS_POINT_CLASS(class); vobject_class->nickname = "grey"; vobject_class->description = _("make a grey ramp image"); point_class->point = vips_grey_point; point_class->min = 0.0F; point_class->max = 1.0F; } static void vips_grey_init(VipsGrey *grey) { } /** * vips_grey: * @out: (out): output image * @width: image size * @height: image size * @...: `NULL`-terminated list of optional named arguments * * Create a one-band float image with the left-most column zero and the * right-most 1. * * Intermediate pixels are a linear ramp. * * Set @uchar to output a uchar image with the leftmost pixel 0 and the * rightmost 255. * * ::: tip "Optional arguments" * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.xyz], [ctor@Image.identity]. * * Returns: 0 on success, -1 on error */ int vips_grey(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("grey", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/identity.c000066400000000000000000000114541516303661500202050ustar00rootroot00000000000000/* identity LUTs * * Copyright 1991, N. Dessipris. * * Author N. Dessipris * Written on 11/03/1991 * Updated on: * 18/6/93 JC * - im_outcheck() call added * - ANSIfied * 24/8/94 JC * - im_identity_ushort() added * 24/3/10 * - gtkdoc * 3/7/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcreate.h" typedef struct _VipsIdentity { VipsCreate parent_instance; int bands; gboolean ushort; int size; } VipsIdentity; typedef VipsCreateClass VipsIdentityClass; G_DEFINE_TYPE(VipsIdentity, vips_identity, VIPS_TYPE_CREATE); #define IDENTITY(TYPE) \ { \ TYPE *q = (TYPE *) VIPS_REGION_ADDR(out_region, le, 0); \ \ for (x = le; x < ri; x++) { \ for (i = 0; i < identity->bands; i++) \ q[i] = x; \ \ q += identity->bands; \ } \ } static int vips_identity_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsIdentity *identity = (VipsIdentity *) a; VipsRect *r = &out_region->valid; int le = r->left; int ri = VIPS_RECT_RIGHT(r); int x, i; if (identity->ushort) { IDENTITY(unsigned short); } else { IDENTITY(unsigned char); } return 0; } static int vips_identity_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsIdentity *identity = (VipsIdentity *) object; if (VIPS_OBJECT_CLASS(vips_identity_parent_class)->build(object)) return -1; vips_image_init_fields(create->out, identity->ushort ? identity->size : 256, 1, identity->bands, identity->ushort ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(create->out, NULL, vips_identity_gen, NULL, identity, NULL)) return -1; return 0; } static void vips_identity_class_init(VipsIdentityClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "identity"; vobject_class->description = _("make a 1D image where pixel values are indexes"); vobject_class->build = vips_identity_build; VIPS_ARG_INT(class, "bands", 3, _("Bands"), _("Number of bands in LUT"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIdentity, bands), 1, 100000, 1); VIPS_ARG_BOOL(class, "ushort", 4, _("Ushort"), _("Create a 16-bit LUT"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIdentity, ushort), FALSE); VIPS_ARG_INT(class, "size", 5, _("Size"), _("Size of 16-bit LUT"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsIdentity, size), 1, 65536, 65536); } static void vips_identity_init(VipsIdentity *identity) { identity->bands = 1; identity->ushort = FALSE; identity->size = 65536; } /** * vips_identity: * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Creates an identity lookup table, ie. one which will leave an image * unchanged when applied with [method@Image.maplut]. Each entry in the table * has a value equal to its position. * * Use the arithmetic operations on these tables to make LUTs representing * arbitrary functions. * * Normally LUTs are 8-bit. Set @ushort to create a 16-bit table. * * Normally 16-bit tables have 65536 entries. You can set this smaller with * @size. * * ::: tip "Optional arguments" * * @bands: `gint`, number of bands to create * * @ushort: `gboolean`, `TRUE` for an unsigned short identity * * @size: `gint`, number of LUT elements for a ushort image * * ::: seealso * [ctor@Image.xyz], [method@Image.maplut]. * * Returns: 0 on success, -1 on error */ int vips_identity(VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("identity", ap, out); va_end(ap); return result; } libvips-8.18.2/libvips/create/invertlut.c000066400000000000000000000201231516303661500204010ustar00rootroot00000000000000/* invert a lut * * Written on: 5/6/01 * Modified on : * * 7/7/03 JC * - generate image rather than doublemask (arrg) * 23/3/10 * - gtkdoc * 23/5/13 * - fix 1 high input matrices * - fix file output * 4/9/13 * - convert to a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcreate.h" /* #define DEBUG */ /* Our state. */ typedef struct _VipsInvertlut { VipsCreate parent_instance; /* Input image. */ VipsImage *in; /* .. and cast to a matrix. */ VipsImage *mat; int size; /* Number of output elements to generate */ double **data; /* Rows of unpacked matrix */ double *buf; /* Output buffer */ } VipsInvertlut; typedef VipsCreateClass VipsInvertlutClass; G_DEFINE_TYPE(VipsInvertlut, vips_invertlut, VIPS_TYPE_CREATE); static void vips_invertlut_dispose(GObject *gobject) { VipsInvertlut *lut = (VipsInvertlut *) gobject; VIPS_FREE(lut->data); VIPS_FREE(lut->buf); VIPS_UNREF(lut->mat); G_OBJECT_CLASS(vips_invertlut_parent_class)->dispose(gobject); } /* Use this to sort our input rows by the first column. */ static int compare(const void *a, const void *b) { double **r1 = (double **) a; double **r2 = (double **) b; double diff = r1[0][0] - r2[0][0]; if (diff > 0) return 1; else if (diff == 0) return 0; else return -1; } static int vips_invertlut_build_init(VipsInvertlut *lut) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(lut); int x, y; if (!lut->mat || lut->mat->Xsize < 2 || lut->mat->Ysize < 1) { vips_error(class->nickname, "%s", _("bad input matrix")); return -1; } if (lut->size < 1 || lut->size > 65536) { vips_error(class->nickname, "%s", _("bad size")); return -1; } if (!(lut->buf = VIPS_ARRAY(NULL, lut->size * (lut->mat->Xsize - 1), double))) return -1; if (!(lut->data = VIPS_ARRAY(NULL, lut->mat->Ysize, double *))) return -1; for (y = 0; y < lut->mat->Ysize; y++) lut->data[y] = VIPS_MATRIX(lut->mat, 0, y); /* Sanity check for data range. */ for (y = 0; y < lut->mat->Ysize; y++) for (x = 0; x < lut->mat->Xsize; x++) if (lut->data[y][x] > 1.0 || lut->data[y][x] < 0.0) { vips_error(class->nickname, _("element (%d, %d) is %g, outside range [0,1]"), x, y, lut->data[y][x]); return -1; } /* Sort by 1st column in input. */ qsort(lut->data, lut->mat->Ysize, sizeof(double *), compare); #ifdef DEBUG printf("Input table, sorted by 1st column\n"); for (y = 0; y < lut->mat->Ysize; y++) { printf("%.4d ", y); for (x = 0; x < lut->mat->Xsize; x++) printf("%.9f ", lut->data[y][x]); printf("\n"); } #endif /*DEBUG*/ return 0; } static int vips_invertlut_build_create(VipsInvertlut *lut) { int bands = lut->mat->Xsize - 1; int height = lut->mat->Ysize; int b; /* Do each output channel separately. */ for (b = 0; b < bands; b++) { /* The first and last lut positions we know real values for. */ int first = lut->data[0][b + 1] * (lut->size - 1); int last = lut->data[height - 1][b + 1] * (lut->size - 1); int k; /* Extrapolate bottom and top segments to (0,0) and (1,1). */ for (k = 0; k < first; k++) { /* Have this inside the loop to avoid /0 errors if * first == 0. */ double fac = lut->data[0][0] / first; lut->buf[b + k * bands] = k * fac; } for (k = last; k < lut->size; k++) { /* Inside the loop to avoid /0 errors for last == * (size - 1). */ double fac = (1 - lut->data[height - 1][0]) / ((lut->size - 1) - last); lut->buf[b + k * bands] = lut->data[height - 1][0] + (k - last) * fac; } /* Interpolate the data sections. */ for (k = first; k <= last; k++) { /* Where we're at in the [0,1] range. */ double ki = (double) k / (lut->size - 1); double irange, orange; int j; /* Search for the lowest real value < ki. There may * not be one: if not, just use 0. Tiny error. */ for (j = height - 1; j >= 0; j--) if (lut->data[j][b + 1] < ki) break; if (j == -1) j = 0; if (height > 1) { /* Interpolate k as being between row data[j] and row * data[j + 1]. */ irange = lut->data[j + 1][b + 1] - lut->data[j][b + 1]; orange = lut->data[j + 1][0] - lut->data[j][0]; lut->buf[b + k * bands] = lut->data[j][0] + orange * ((ki - lut->data[j][b + 1]) / irange); } else { lut->buf[b + k * bands] = lut->data[j][0]; } } } return 0; } static int vips_invertlut_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsInvertlut *lut = (VipsInvertlut *) object; if (VIPS_OBJECT_CLASS(vips_invertlut_parent_class)->build(object)) return -1; if (vips_check_matrix(class->nickname, lut->in, &lut->mat)) return -1; if (vips_invertlut_build_init(lut) || vips_invertlut_build_create(lut)) return -1; vips_image_init_fields(create->out, lut->size, 1, lut->mat->Xsize - 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (vips_image_write_line(create->out, 0, (VipsPel *) lut->buf)) return -1; return 0; } static void vips_invertlut_class_init(VipsInvertlutClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = vips_invertlut_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "invertlut"; vobject_class->description = _("build an inverted look-up table"); vobject_class->build = vips_invertlut_build; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Matrix of XY coordinates"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsInvertlut, in)); VIPS_ARG_INT(class, "size", 5, _("Size"), _("LUT size to generate"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsInvertlut, size), 1, 1000000, 256); } static void vips_invertlut_init(VipsInvertlut *lut) { lut->size = 256; } /** * vips_invertlut: (method) * @in: input mask * @out: (out): output LUT * @...: `NULL`-terminated list of optional named arguments * * Given a mask of target values and real values, generate a LUT which * will map reals to targets. * * Handy for linearising images from measurements of a colour chart. All * values in [0,1]. Piecewise linear interpolation, extrapolate head and tail * to 0 and 1. * * Eg. input like this: * * ``` * 4 3 * 0.1 0.2 0.3 0.1 * 0.2 0.4 0.4 0.2 * 0.7 0.5 0.6 0.3 * ``` * * Means a patch with 10% reflectance produces an image with 20% in * channel 1, 30% in channel 2, and 10% in channel 3, and so on. * * Inputs don't need to be sorted (we do that). Generate any precision * LUT, default to 256 elements. * * It won't work too well for non-monotonic camera responses * (we should fix this). Interpolation is simple piecewise linear; we ought to * do something better really. * * ::: tip "Optional arguments" * * @size: `gint`, generate this much * * ::: seealso * [method@Image.buildlut]. * * Returns: 0 on success, -1 on error */ int vips_invertlut(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("invertlut", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/create/logmat.c000066400000000000000000000172351516303661500176420ustar00rootroot00000000000000/* laplacian of logmatian * * Written on: 30/11/1989 * Updated on: 6/12/1991 * 7/8/96 JC * - ansified, mem leaks plugged * 20/11/98 JC * - mask too large check added * 26/3/02 JC * - ahem, was broken since '96, thanks matt * 16/7/03 JC * - makes mask out to zero, not out to minimum, thanks again matt * 22/10/10 * - gtkdoc * 20/10/13 * - redone as a class from logmat.c * 16/12/14 * - default to int output to match vips_conv() * - use @precision, not @integer */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsLogmat { VipsCreate parent_instance; double sigma; double min_ampl; gboolean separable; gboolean integer; /* Deprecated */ VipsPrecision precision; } VipsLogmat; typedef struct _VipsLogmatClass { VipsCreateClass parent_class; } VipsLogmatClass; G_DEFINE_TYPE(VipsLogmat, vips_logmat, VIPS_TYPE_CREATE); static int vips_logmat_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsLogmat *logmat = (VipsLogmat *) object; double sig2 = logmat->sigma * logmat->sigma; double last; int x, y; int width, height; double sum; if (VIPS_OBJECT_CLASS(vips_logmat_parent_class)->build(object)) return -1; /* The old, deprecated @integer property has been deliberately set to * FALSE and they've not used the new @precision property ... switch * to float to help them out. */ if (vips_object_argument_isset(object, "integer") && !vips_object_argument_isset(object, "precision") && !logmat->integer) logmat->precision = VIPS_PRECISION_FLOAT; // FIXME: Invalidates operation cache if (vips_check_precision_intfloat(class->nickname, logmat->precision)) return -1; /* Find the size of the mask. We want to eval the mask out to the * flat zero part, ie. beyond the minimum and to the point where it * comes back up towards zero. */ last = 0.0; for (x = 0; x < 5000; x++) { const double distance = x * x; double val; /* Handbook of Pattern Recognition and image processing * by Young and Fu AP 1986 pp 220-221 * temp = (1.0 / (2.0 * IM_PI * sig4)) * (2.0 - (distance / sig2)) * exp((-1.0) * distance / (2.0 * sig2)) .. use 0.5 to normalise */ val = 0.5 * (2.0 - (distance / sig2)) * exp(-distance / (2.0 * sig2)); /* Stop when change in value (ie. difference from the last * point) is positive (ie. we are going up) and absolute value * is less than the min. */ if (val - last >= 0 && fabs(val) < logmat->min_ampl) break; last = val; } if (x == 5000) { vips_error(class->nickname, "%s", _("mask too large")); return -1; } width = x * 2 + 1; height = logmat->separable ? 1 : width; vips_image_init_fields(create->out, width, height, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_write_prepare(create->out)) return -1; sum = 0.0; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { int xo = x - width / 2; int yo = y - height / 2; double distance = xo * xo + yo * yo; double v = 0.5 * (2.0 - (distance / sig2)) * exp(-distance / (2.0 * sig2)); if (logmat->precision == VIPS_PRECISION_INTEGER) v = rint(20 * v); *VIPS_MATRIX(create->out, x, y) = v; sum += v; } } vips_image_set_double(create->out, "scale", sum); vips_image_set_double(create->out, "offset", 0.0); return 0; } static void vips_logmat_class_init(VipsLogmatClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "logmat"; vobject_class->description = _("make a Laplacian of Gaussian image"); vobject_class->build = vips_logmat_build; VIPS_ARG_DOUBLE(class, "sigma", 2, _("Radius"), _("Radius of Gaussian"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsLogmat, sigma), 0.000001, 10000.0, 1.0); VIPS_ARG_DOUBLE(class, "min_ampl", 3, _("Width"), _("Minimum amplitude of Gaussian"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsLogmat, min_ampl), 0.000001, 10000.0, 0.1); VIPS_ARG_BOOL(class, "separable", 4, _("Separable"), _("Generate separable Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsLogmat, separable), FALSE); VIPS_ARG_BOOL(class, "integer", 5, _("Integer"), _("Generate integer Gaussian"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsLogmat, integer), FALSE); VIPS_ARG_ENUM(class, "precision", 6, _("Precision"), _("Generate with this precision"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsLogmat, precision), VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER); } static void vips_logmat_init(VipsLogmat *logmat) { logmat->sigma = 1; logmat->min_ampl = 0.1; logmat->precision = VIPS_PRECISION_INTEGER; } /** * vips_logmat: * @out: (out): output image * @sigma: standard deviation of mask * @min_ampl: minimum amplitude * @...: `NULL`-terminated list of optional named arguments * * Create a circularly symmetric Laplacian of Gaussian mask of radius * @sigma. * * The size of the mask is determined by the variable @min_ampl; * if for instance the value .1 is entered this means that the produced mask * is clipped at values within 10 percent of zero, and where the change * between mask elements is less than 10%. * * The program uses the following equation: (from Handbook of Pattern * Recognition and image processing by Young and Fu, AP 1986 pages 220-221): * * ``` * H(r) = (1 / (2 * M_PI * s4)) * (2 - (r2 / s2)) * exp(-r2 / (2 * s2)) * ``` * * where: * * ``` * 2 = @sigma * @sigma, * s4 = s2 * s2 * r2 = r * r. * ``` * * The generated mask has odd size and its maximum value is normalised to * 1.0, unless @precision is [enum@Vips.Precision.INTEGER]. * * If @separable is set, only the centre horizontal is generated. This is * useful for separable convolutions. * * If @precision is [enum@Vips.Precision.INTEGER], an integer mask is generated. * This is useful for integer convolutions. * * "scale" is set to the sum of all the mask elements. * * ::: tip "Optional arguments" * * @separable: `gboolean`, generate a separable mask * * @precision: [enum@Precision] for @out * * ::: seealso * [ctor@Image.gaussmat], [method@Image.conv]. * * Returns: 0 on success, -1 on error */ int vips_logmat(VipsImage **out, double sigma, double min_ampl, ...) { va_list ap; int result; va_start(ap, min_ampl); result = vips_call_split("logmat", ap, out, sigma, min_ampl); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask.c000066400000000000000000000063561516303661500173140ustar00rootroot00000000000000/* base class for frequency filter create operations * * 02/01/14 * - from sines.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" G_DEFINE_ABSTRACT_TYPE(VipsMask, vips_mask, VIPS_TYPE_POINT); static float vips_mask_point(VipsPoint *point, int x, int y) { VipsMask *mask = VIPS_MASK(point); VipsMaskClass *class = VIPS_MASK_GET_CLASS(point); /* VIPS_MAX to prevent /0. */ int half_width = VIPS_MAX(point->width / 2, 1); int half_height = VIPS_MAX(point->height / 2, 1); double result; /* Move centre for an optical transform mask. */ if (!mask->optical) { x = (x + half_width) % point->width; y = (y + half_height) % point->height; } x = x - half_width; y = y - half_height; if (!mask->nodc && x == 0 && y == 0) /* DC component is always 1. */ result = 1.0; else { double dx, dy; dx = (double) x / half_width; dy = (double) y / half_height; result = class->point(mask, dx, dy); /* Invert filter sense for a highpass filter, or to swap * band-pass for band-reject. */ if (mask->reject) result = 1.0 - result; } return result; } static void vips_mask_class_init(VipsMaskClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsPointClass *point_class = VIPS_POINT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask"; vobject_class->description = _("base class for frequency filters"); point_class->point = vips_mask_point; point_class->min = 0.0F; point_class->max = 1.0F; point_class->interpretation = VIPS_INTERPRETATION_FOURIER; VIPS_ARG_BOOL(class, "optical", 5, _("Optical"), _("Rotate quadrants to optical space"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMask, optical), FALSE); VIPS_ARG_BOOL(class, "reject", 5, _("Reject"), _("Invert the sense of the filter"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMask, reject), FALSE); VIPS_ARG_BOOL(class, "nodc", 5, _("Nodc"), _("Remove DC component"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMask, nodc), FALSE); } static void vips_mask_init(VipsMask *mask) { } libvips-8.18.2/libvips/create/mask_butterworth.c000066400000000000000000000103421516303661500217530ustar00rootroot00000000000000/* creates an butterworth filter. * * 02/01/14 * - from butterworth.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" G_DEFINE_TYPE(VipsMaskButterworth, vips_mask_butterworth, VIPS_TYPE_MASK); static double vips_mask_butterworth_point(VipsMask *mask, double dx, double dy) { VipsMaskButterworth *butterworth = (VipsMaskButterworth *) mask; double order = butterworth->order; double fc = butterworth->frequency_cutoff; double ac = butterworth->amplitude_cutoff; double cnst = (1.0 / ac) - 1.0; double fc2 = fc * fc; double d = dx * dx + dy * dy; if (d == 0) return 0; else return 1.0 / (1.0 + cnst * pow(fc2 / d, order)); } static void vips_mask_butterworth_class_init(VipsMaskButterworthClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_butterworth"; vobject_class->description = _("make a butterworth filter"); mask_class->point = vips_mask_butterworth_point; VIPS_ARG_DOUBLE(class, "order", 6, _("Order"), _("Filter order"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworth, order), 1.0, 1000000.0, 1.0); VIPS_ARG_DOUBLE(class, "frequency_cutoff", 7, _("Frequency cutoff"), _("Frequency cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworth, frequency_cutoff), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "amplitude_cutoff", 8, _("Amplitude cutoff"), _("Amplitude cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworth, amplitude_cutoff), 0.0, 1.0, 0.5); } static void vips_mask_butterworth_init(VipsMaskButterworth *butterworth) { butterworth->order = 1.0; butterworth->frequency_cutoff = 0.5; butterworth->amplitude_cutoff = 0.5; } /** * vips_mask_butterworth: * @out: (out): output image * @width: image size * @height: image size * @order: filter order * @frequency_cutoff: frequency threshold * @amplitude_cutoff: amplitude threshold * @...: `NULL`-terminated list of optional named arguments * * Make an butterworth high- or low-pass filter, that is, one with a variable, * smooth transition * positioned at @frequency_cutoff, where @frequency_cutoff is in * range 0 - 1. * * The shape of the curve is controlled by * @order -- higher values give a sharper transition. See Gonzalez and Wintz, * Digital Image Processing, 1987. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_butterworth(VipsImage **out, int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, ...) { va_list ap; int result; va_start(ap, amplitude_cutoff); result = vips_call_split("mask_butterworth", ap, out, width, height, order, frequency_cutoff, amplitude_cutoff); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_butterworth_band.c000066400000000000000000000132351516303661500227430ustar00rootroot00000000000000/* creates an butterworth_band filter. * * 02/01/14 * - from butterworth_band.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskButterworthBand { VipsMask parent_instance; double order; double frequency_cutoff_x; double frequency_cutoff_y; double radius; double amplitude_cutoff; } VipsMaskButterworthBand; typedef VipsMaskClass VipsMaskButterworthBandClass; G_DEFINE_TYPE(VipsMaskButterworthBand, vips_mask_butterworth_band, VIPS_TYPE_MASK); static double vips_mask_butterworth_band_point(VipsMask *mask, double dx, double dy) { VipsMaskButterworthBand *butterworth_band = (VipsMaskButterworthBand *) mask; double order = butterworth_band->order; double fcx = butterworth_band->frequency_cutoff_x; double fcy = butterworth_band->frequency_cutoff_y; double r2 = butterworth_band->radius * butterworth_band->radius; double ac = butterworth_band->amplitude_cutoff; double cnst = (1.0 / ac) - 1.0; /* Normalise the amplitude at (fcx, fcy) to 1.0. */ /* clang-format off */ double cnsta = 1.0 / (1.0 + 1.0 / (1.0 + cnst * pow(4.0 * (fcx * fcx + fcy * fcy) / r2, order))); double d1 = (dx - fcx) * (dx - fcx) + (dy - fcy) * (dy - fcy); double d2 = (dx + fcx) * (dx + fcx) + (dy + fcy) * (dy + fcy); return cnsta * (1.0 / (1.0 + cnst * pow(d1 / r2, order)) + 1.0 / (1.0 + cnst * pow(d2 / r2, order))); /* clang-format on */ } static void vips_mask_butterworth_band_class_init( VipsMaskButterworthBandClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_butterworth_band"; vobject_class->description = _("make a butterworth_band filter"); mask_class->point = vips_mask_butterworth_band_point; VIPS_ARG_DOUBLE(class, "order", 6, _("Order"), _("Filter order"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworthBand, order), 1.0, 1000000.0, 1.0); VIPS_ARG_DOUBLE(class, "frequency_cutoff_x", 7, _("Frequency cutoff x"), _("Frequency cutoff x"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworthBand, frequency_cutoff_x), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "frequency_cutoff_y", 8, _("Frequency cutoff y"), _("Frequency cutoff y"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworthBand, frequency_cutoff_y), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "radius", 9, _("Radius"), _("Radius of circle"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworthBand, radius), 0.0, 1000000.0, 0.1); VIPS_ARG_DOUBLE(class, "amplitude_cutoff", 10, _("Amplitude cutoff"), _("Amplitude cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworthBand, amplitude_cutoff), 0.0, 1.0, 0.5); } static void vips_mask_butterworth_band_init( VipsMaskButterworthBand *butterworth_band) { butterworth_band->order = 1.0; butterworth_band->frequency_cutoff_x = 0.5; butterworth_band->frequency_cutoff_y = 0.5; butterworth_band->radius = 0.1; butterworth_band->amplitude_cutoff = 0.5; } /** * vips_mask_butterworth_band: * @out: (out): output image * @width: image size * @height: image size * @order: filter order * @frequency_cutoff_x: band position * @frequency_cutoff_y: band position * @radius: band radius * @amplitude_cutoff: amplitude threshold * @...: `NULL`-terminated list of optional named arguments * * Make an butterworth band-pass or band-reject filter, that is, one with a * variable, smooth transition positioned at @frequency_cutoff_x, * @frequency_cutoff_y, of radius @radius. * * The shape of the curve is controlled by * @order -- higher values give a sharper transition. See Gonzalez and Wintz, * Digital Image Processing, 1987. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_butterworth_band(VipsImage **out, int width, int height, double order, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, ...) { va_list ap; int result; va_start(ap, amplitude_cutoff); result = vips_call_split("mask_butterworth_band", ap, out, width, height, order, frequency_cutoff_x, frequency_cutoff_y, radius, amplitude_cutoff); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_butterworth_ring.c000066400000000000000000000104231516303661500227720ustar00rootroot00000000000000/* creates an butterworth filter. * * 02/01/14 * - from butterworth.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskButterworthRing { VipsMaskButterworth parent_instance; double ringwidth; } VipsMaskButterworthRing; typedef VipsMaskButterworthClass VipsMaskButterworthRingClass; G_DEFINE_TYPE(VipsMaskButterworthRing, vips_mask_butterworth_ring, VIPS_TYPE_MASK_BUTTERWORTH); static double vips_mask_butterworth_ring_point(VipsMask *mask, double dx, double dy) { VipsMaskButterworth *butterworth = (VipsMaskButterworth *) mask; VipsMaskButterworthRing *butterworth_ring = (VipsMaskButterworthRing *) mask; double order = butterworth->order; double fc = butterworth->frequency_cutoff; double ac = butterworth->amplitude_cutoff; double ringwidth = butterworth_ring->ringwidth; double df = ringwidth / 2.0; double cnst = (1.0 / ac) - 1.0; double df2 = df * df; double dist = sqrt(dx * dx + dy * dy); return 1.0 / (1.0 + cnst * pow((dist - fc) * (dist - fc) / df2, order)); } static void vips_mask_butterworth_ring_class_init( VipsMaskButterworthRingClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_butterworth_ring"; vobject_class->description = _("make a butterworth ring filter"); mask_class->point = vips_mask_butterworth_ring_point; VIPS_ARG_DOUBLE(class, "ringwidth", 20, _("Ringwidth"), _("Ringwidth"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskButterworthRing, ringwidth), 0.0, 1000000.0, 0.1); } static void vips_mask_butterworth_ring_init( VipsMaskButterworthRing *butterworth_ring) { butterworth_ring->ringwidth = 0.1; } /** * vips_mask_butterworth_ring: * @out: (out): output image * @width: image size * @height: image size * @order: filter order * @frequency_cutoff: frequency threshold * @amplitude_cutoff: amplitude threshold * @ringwidth: ringwidth * @...: `NULL`-terminated list of optional named arguments * * Make a butterworth ring-pass or ring-reject filter, that is, one with a * variable, * smooth transition * positioned at @frequency_cutoff of width @width, where @frequency_cutoff is * in the range 0 - 1. * * The shape of the curve is controlled by * @order -- higher values give a sharper transition. See Gonzalez and Wintz, * Digital Image Processing, 1987. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_butterworth_ring(VipsImage **out, int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, double ringwidth, ...) { va_list ap; int result; va_start(ap, ringwidth); result = vips_call_split("mask_butterworth_ring", ap, out, width, height, order, frequency_cutoff, amplitude_cutoff, ringwidth); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_fractal.c000066400000000000000000000065561516303661500210120ustar00rootroot00000000000000/* creates a fractal filter. * * 02/01/14 * - from ideal.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskFractal { VipsMask parent_instance; double fractal_dimension; } VipsMaskFractal; typedef VipsMaskClass VipsMaskFractalClass; G_DEFINE_TYPE(VipsMaskFractal, vips_mask_fractal, VIPS_TYPE_MASK); static double vips_mask_fractal_point(VipsMask *mask, double dx, double dy) { VipsMaskFractal *fractal = (VipsMaskFractal *) mask; double fd = (fractal->fractal_dimension - 4.0) / 2.0; double d2 = dx * dx + dy * dy; return pow(d2, fd); } static void vips_mask_fractal_class_init(VipsMaskFractalClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_fractal"; vobject_class->description = _("make fractal filter"); mask_class->point = vips_mask_fractal_point; VIPS_ARG_DOUBLE(class, "fractal_dimension", 8, _("Fractal dimension"), _("Fractal dimension"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskFractal, fractal_dimension), 2.0, 3.0, 2.5); } static void vips_mask_fractal_init(VipsMaskFractal *fractal) { fractal->fractal_dimension = 2.5; } /** * vips_mask_fractal: * @out: (out): output image * @width: image size * @height: image size * @fractal_dimension: fractal dimension * @...: `NULL`-terminated list of optional named arguments * * This operation should be used to create fractal images by filtering the * power spectrum of Gaussian white noise. * * See [ctor@Image.gaussnoise]. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_fractal(VipsImage **out, int width, int height, double fractal_dimension, ...) { va_list ap; int result; va_start(ap, fractal_dimension); result = vips_call_split("mask_fractal", ap, out, width, height, fractal_dimension); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_gaussian.c000066400000000000000000000071661516303661500212060ustar00rootroot00000000000000/* creates a gaussian filter. * * 02/01/14 * - from gaussian.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" G_DEFINE_TYPE(VipsMaskGaussian, vips_mask_gaussian, VIPS_TYPE_MASK); static double vips_mask_gaussian_point(VipsMask *mask, double dx, double dy) { VipsMaskGaussian *gaussian = (VipsMaskGaussian *) mask; double fc = gaussian->frequency_cutoff; double ac = gaussian->amplitude_cutoff; double cnst = log(ac); double fc2 = fc * fc; double dist2 = (dx * dx + dy * dy) / fc2; return 1.0 - exp(cnst * dist2); } static void vips_mask_gaussian_class_init(VipsMaskGaussianClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_gaussian"; vobject_class->description = _("make a gaussian filter"); mask_class->point = vips_mask_gaussian_point; VIPS_ARG_DOUBLE(class, "frequency_cutoff", 7, _("Frequency cutoff"), _("Frequency cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussian, frequency_cutoff), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "amplitude_cutoff", 8, _("Amplitude cutoff"), _("Amplitude cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussian, amplitude_cutoff), 0.0, 1.0, 0.5); } static void vips_mask_gaussian_init(VipsMaskGaussian *gaussian) { gaussian->frequency_cutoff = 0.5; gaussian->amplitude_cutoff = 0.5; } /** * vips_mask_gaussian: * @out: (out): output image * @width: image size * @height: image size * @frequency_cutoff: frequency threshold * @amplitude_cutoff: amplitude threshold * @...: `NULL`-terminated list of optional named arguments * * Make a gaussian high- or low-pass filter, that is, one with a variable, * smooth transition positioned at @frequency_cutoff. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_gaussian(VipsImage **out, int width, int height, double frequency_cutoff, double amplitude_cutoff, ...) { va_list ap; int result; va_start(ap, amplitude_cutoff); result = vips_call_split("mask_gaussian", ap, out, width, height, frequency_cutoff, amplitude_cutoff); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_gaussian_band.c000066400000000000000000000117041516303661500221630ustar00rootroot00000000000000/* creates a gaussian filter. * * 02/01/14 * - from gaussian.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskGaussianBand { VipsMask parent_instance; double frequency_cutoff_x; double frequency_cutoff_y; double radius; double amplitude_cutoff; } VipsMaskGaussianBand; typedef VipsMaskClass VipsMaskGaussianBandClass; G_DEFINE_TYPE(VipsMaskGaussianBand, vips_mask_gaussian_band, VIPS_TYPE_MASK); static double vips_mask_gaussian_band_point(VipsMask *mask, double dx, double dy) { VipsMaskGaussianBand *gaussian_band = (VipsMaskGaussianBand *) mask; double fcx = gaussian_band->frequency_cutoff_x; double fcy = gaussian_band->frequency_cutoff_y; double r2 = gaussian_band->radius * gaussian_band->radius; double ac = gaussian_band->amplitude_cutoff; double cnst = log(ac); double d1 = (dx - fcx) * (dx - fcx) + (dy - fcy) * (dy - fcy); double d2 = (dx + fcx) * (dx + fcx) + (dy + fcy) * (dy + fcy); /* Normalise the amplitude at (fcx, fcy) to 1.0. */ double cnsta = 1.0 / (1.0 + exp(cnst * 4.0 * (fcx * fcx + fcy * fcy) / r2)); return cnsta * (exp(cnst * d1 / r2) + exp(cnst * d2 / r2)); } static void vips_mask_gaussian_band_class_init(VipsMaskGaussianBandClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_gaussian_band"; vobject_class->description = _("make a gaussian filter"); mask_class->point = vips_mask_gaussian_band_point; VIPS_ARG_DOUBLE(class, "frequency_cutoff_x", 7, _("Frequency cutoff x"), _("Frequency cutoff x"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussianBand, frequency_cutoff_x), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "frequency_cutoff_y", 8, _("Frequency cutoff y"), _("Frequency cutoff y"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussianBand, frequency_cutoff_y), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "radius", 9, _("Radius"), _("Radius of circle"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussianBand, radius), 0.0, 1000000.0, 0.1); VIPS_ARG_DOUBLE(class, "amplitude_cutoff", 10, _("Amplitude cutoff"), _("Amplitude cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussianBand, amplitude_cutoff), 0.0, 1.0, 0.5); } static void vips_mask_gaussian_band_init(VipsMaskGaussianBand *gaussian_band) { gaussian_band->frequency_cutoff_x = 0.5; gaussian_band->frequency_cutoff_x = 0.5; gaussian_band->radius = 0.1; gaussian_band->amplitude_cutoff = 0.5; } /** * vips_mask_gaussian_band: * @out: (out): output image * @width: image size * @height: image size * @frequency_cutoff_x: band position * @frequency_cutoff_y: band position * @radius: band radius * @amplitude_cutoff: amplitude threshold * @...: `NULL`-terminated list of optional named arguments * * Make a gaussian band-pass or band-reject filter, that is, one with a * variable, smooth transition positioned at @frequency_cutoff_x, * @frequency_cutoff_y, of radius @radius. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_gaussian_band(VipsImage **out, int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, ...) { va_list ap; int result; va_start(ap, amplitude_cutoff); result = vips_call_split("mask_gaussian_band", ap, out, width, height, frequency_cutoff_x, frequency_cutoff_y, radius, amplitude_cutoff); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_gaussian_ring.c000066400000000000000000000075561516303661500222300ustar00rootroot00000000000000/* creates a gaussian_ring filter. * * 02/01/14 * - from gaussian_ring.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskGaussianRing { VipsMaskGaussian parent_instance; double ringwidth; } VipsMaskGaussianRing; typedef VipsMaskGaussianClass VipsMaskGaussianRingClass; G_DEFINE_TYPE(VipsMaskGaussianRing, vips_mask_gaussian_ring, VIPS_TYPE_MASK_GAUSSIAN); static double vips_mask_gaussian_ring_point(VipsMask *mask, double dx, double dy) { VipsMaskGaussian *gaussian = (VipsMaskGaussian *) mask; VipsMaskGaussianRing *gaussian_ring = (VipsMaskGaussianRing *) mask; double fc = gaussian->frequency_cutoff; double ac = gaussian->amplitude_cutoff; double ringwidth = gaussian_ring->ringwidth; double df = ringwidth / 2.0; double df2 = df * df; double cnst = log(ac); double dist = sqrt(dx * dx + dy * dy); return exp(cnst * (dist - fc) * (dist - fc) / df2); } static void vips_mask_gaussian_ring_class_init(VipsMaskGaussianRingClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_gaussian_ring"; vobject_class->description = _("make a gaussian ring filter"); mask_class->point = vips_mask_gaussian_ring_point; VIPS_ARG_DOUBLE(class, "ringwidth", 20, _("Ringwidth"), _("Ringwidth"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskGaussianRing, ringwidth), 0.0, 1000000.0, 0.5); } static void vips_mask_gaussian_ring_init(VipsMaskGaussianRing *gaussian_ring) { gaussian_ring->ringwidth = 0.5; } /** * vips_mask_gaussian_ring: * @out: (out): output image * @width: image size * @height: image size * @frequency_cutoff: frequency threshold * @amplitude_cutoff: amplitude threshold * @ringwidth: ringwidth * @...: `NULL`-terminated list of optional named arguments * * Make a gaussian ring-pass or ring-reject filter, that is, one with a * variable, smooth transition positioned at @frequency_cutoff of width * @ringwidth. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_gaussian_ring(VipsImage **out, int width, int height, double frequency_cutoff, double amplitude_cutoff, double ringwidth, ...) { va_list ap; int result; va_start(ap, ringwidth); result = vips_call_split("mask_gaussian_ring", ap, out, width, height, frequency_cutoff, amplitude_cutoff, ringwidth); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_ideal.c000066400000000000000000000103651516303661500204450ustar00rootroot00000000000000/* creates an ideal filter. * * 02/01/14 * - from ideal.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" G_DEFINE_TYPE(VipsMaskIdeal, vips_mask_ideal, VIPS_TYPE_MASK); static double vips_mask_ideal_point(VipsMask *mask, double dx, double dy) { VipsMaskIdeal *ideal = (VipsMaskIdeal *) mask; double fc = ideal->frequency_cutoff; double dist2 = dx * dx + dy * dy; double fc2 = fc * fc; return dist2 <= fc2 ? 0.0 : 1.0; } static void vips_mask_ideal_class_init(VipsMaskIdealClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_ideal"; vobject_class->description = _("make an ideal filter"); mask_class->point = vips_mask_ideal_point; VIPS_ARG_DOUBLE(class, "frequency_cutoff", 6, _("Frequency cutoff"), _("Frequency cutoff"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskIdeal, frequency_cutoff), 0.0, 1000000.0, 0.5); } static void vips_mask_ideal_init(VipsMaskIdeal *ideal) { ideal->frequency_cutoff = 0.5; } /** * vips_mask_ideal: * @out: (out): output image * @width: image size * @height: image size * @frequency_cutoff: threshold at which filter ends * @...: `NULL`-terminated list of optional named arguments * * Make an ideal high- or low-pass filter, that is, one with a sharp cutoff * positioned at @frequency_cutoff, where @frequency_cutoff is in * the range 0 - 1. * * This operation creates a one-band float image of the specified size. * The image has * values in the range [0, 1] and is typically used for multiplying against * frequency domain images to filter them. * Masks are created with the DC component at (0, 0). The DC pixel always * has the value 1.0. * * Set @nodc to not set the DC pixel. * * Set @optical to position the DC component in the centre of the image. This * makes the mask suitable for multiplying against optical Fourier transforms. * See [method@Image.wrap]. * * Set @reject to invert the sense of * the filter. For example, low-pass becomes low-reject. * * Set @uchar to output an 8-bit unsigned char image rather than a * float image. In this case, pixels are in the range [0 - 255]. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal], [ctor@Image.mask_ideal_ring], * [ctor@Image.mask_ideal_band], [ctor@Image.mask_butterworth], * [ctor@Image.mask_butterworth_ring], [ctor@Image.mask_butterworth_band], * [ctor@Image.mask_gaussian], [ctor@Image.mask_gaussian_ring], * [ctor@Image.mask_gaussian_band]. * * Returns: 0 on success, -1 on error */ int vips_mask_ideal(VipsImage **out, int width, int height, double frequency_cutoff, ...) { va_list ap; int result; va_start(ap, frequency_cutoff); result = vips_call_split("mask_ideal", ap, out, width, height, frequency_cutoff); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_ideal_band.c000066400000000000000000000104151516303661500214250ustar00rootroot00000000000000/* creates an ideal filter. * * 02/01/14 * - from ideal.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskIdealBand { VipsMask parent_instance; double frequency_cutoff_x; double frequency_cutoff_y; double radius; } VipsMaskIdealBand; typedef VipsMaskClass VipsMaskIdealBandClass; G_DEFINE_TYPE(VipsMaskIdealBand, vips_mask_ideal_band, VIPS_TYPE_MASK); static double vips_mask_ideal_band_point(VipsMask *mask, double dx, double dy) { VipsMaskIdealBand *ideal_band = (VipsMaskIdealBand *) mask; double fcx = ideal_band->frequency_cutoff_x; double fcy = ideal_band->frequency_cutoff_y; double r2 = ideal_band->radius * ideal_band->radius; double d1 = (dx - fcx) * (dx - fcx) + (dy - fcy) * (dy - fcy); double d2 = (dx + fcx) * (dx + fcx) + (dy + fcy) * (dy + fcy); return (d1 < r2 || d2 < r2) ? 1.0 : 0.0; } static void vips_mask_ideal_band_class_init(VipsMaskIdealBandClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_ideal_band"; vobject_class->description = _("make an ideal band filter"); mask_class->point = vips_mask_ideal_band_point; VIPS_ARG_DOUBLE(class, "frequency_cutoff_x", 6, _("Frequency cutoff x"), _("Frequency cutoff x"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskIdealBand, frequency_cutoff_x), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "frequency_cutoff_y", 7, _("Frequency cutoff y"), _("Frequency cutoff y"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskIdealBand, frequency_cutoff_y), 0.0, 1000000.0, 0.5); VIPS_ARG_DOUBLE(class, "radius", 8, _("Radius"), _("Radius of circle"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskIdealBand, radius), 0.0, 1000000.0, 0.1); } static void vips_mask_ideal_band_init(VipsMaskIdealBand *ideal_band) { ideal_band->frequency_cutoff_x = 0.5; ideal_band->frequency_cutoff_y = 0.5; ideal_band->radius = 0.1; } /** * vips_mask_ideal_band: * @out: (out): output image * @width: image size * @height: image size * @frequency_cutoff_x: position of band * @frequency_cutoff_y: position of band * @radius: size of band * @...: `NULL`-terminated list of optional named arguments * * Make an ideal band-pass or band-reject filter, that is, one with a * sharp cutoff around the point @frequency_cutoff_x, @frequency_cutoff_y, * of size @radius. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_ideal_band(VipsImage **out, int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, ...) { va_list ap; int result; va_start(ap, radius); result = vips_call_split("mask_ideal_band", ap, out, width, height, frequency_cutoff_x, frequency_cutoff_y, radius); va_end(ap); return result; } libvips-8.18.2/libvips/create/mask_ideal_ring.c000066400000000000000000000073321516303661500214640ustar00rootroot00000000000000/* creates an ideal ringpass filter. * * 02/01/14 * - from ideal.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" #include "pmask.h" typedef struct _VipsMaskIdealRing { VipsMaskIdeal parent_instance; double ringwidth; } VipsMaskIdealRing; typedef VipsMaskIdealClass VipsMaskIdealRingClass; G_DEFINE_TYPE(VipsMaskIdealRing, vips_mask_ideal_ring, VIPS_TYPE_MASK_IDEAL); static double vips_mask_ideal_ring_point(VipsMask *mask, double dx, double dy) { VipsMaskIdeal *ideal = (VipsMaskIdeal *) mask; VipsMaskIdealRing *ideal_ring = (VipsMaskIdealRing *) mask; double fc = ideal->frequency_cutoff; double ringwidth = ideal_ring->ringwidth; double df = ringwidth / 2.0; double dist2 = dx * dx + dy * dy; double fc2_1 = (fc - df) * (fc - df); double fc2_2 = (fc + df) * (fc + df); return dist2 > fc2_1 && dist2 < fc2_2 ? 1.0 : 0.0; } static void vips_mask_ideal_ring_class_init(VipsMaskIdealClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsMaskClass *mask_class = VIPS_MASK_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mask_ideal_ring"; vobject_class->description = _("make an ideal ring filter"); mask_class->point = vips_mask_ideal_ring_point; VIPS_ARG_DOUBLE(class, "ringwidth", 20, _("Ringwidth"), _("Ringwidth"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaskIdealRing, ringwidth), 0.0, 1000000.0, 0.5); } static void vips_mask_ideal_ring_init(VipsMaskIdealRing *ideal_ring) { ideal_ring->ringwidth = 0.5; } /** * vips_mask_ideal_ring: * @out: (out): output image * @width: image size * @height: image size * @frequency_cutoff: threshold at which filter ends * @ringwidth: ring width * @...: `NULL`-terminated list of optional named arguments * * Make an ideal ring-pass or ring-reject filter, that is, one with a sharp * ring positioned at @frequency_cutoff of width @width, where * @frequency_cutoff and @width are expressed as the range 0 - 1. * * ::: tip "Optional arguments" * * @nodc: `gboolean`, don't set the DC pixel * * @reject: `gboolean`, invert the filter sense * * @optical: `gboolean`, coordinates in optical space * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error */ int vips_mask_ideal_ring(VipsImage **out, int width, int height, double frequency_cutoff, double ringwidth, ...) { va_list ap; int result; va_start(ap, ringwidth); result = vips_call_split("mask_ideal_ring", ap, out, width, height, frequency_cutoff, ringwidth); va_end(ap); return result; } libvips-8.18.2/libvips/create/meson.build000066400000000000000000000016171516303661500203520ustar00rootroot00000000000000create_sources = files( 'black.c', 'buildlut.c', 'create.c', 'eye.c', 'fractsurf.c', 'gaussmat.c', 'gaussnoise.c', 'grey.c', 'identity.c', 'invertlut.c', 'logmat.c', 'mask_butterworth_band.c', 'mask_butterworth.c', 'mask_butterworth_ring.c', 'mask.c', 'mask_fractal.c', 'mask_gaussian_band.c', 'mask_gaussian.c', 'mask_gaussian_ring.c', 'mask_ideal_band.c', 'mask_ideal.c', 'mask_ideal_ring.c', 'perlin.c', 'point.c', 'sdf.c', 'sines.c', 'text.c', 'tonelut.c', 'worley.c', 'xyz.c', 'zone.c', ) create_headers = files( 'pcreate.h', 'pmask.h', 'point.h', ) libvips_sources += create_sources create_lib = static_library('create', create_sources, create_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += create_lib libvips-8.18.2/libvips/create/pcreate.h000066400000000000000000000035241516303661500200030ustar00rootroot00000000000000/* base class for all create operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PCREATE_H #define VIPS_PCREATE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_CREATE (vips_create_get_type()) #define VIPS_CREATE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_CREATE, VipsCreate)) #define VIPS_CREATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_CREATE, VipsCreateClass)) #define VIPS_IS_CREATE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_CREATE)) #define VIPS_IS_CREATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_CREATE)) #define VIPS_CREATE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_CREATE, VipsCreateClass)) typedef struct _VipsCreate { VipsOperation parent_instance; /* All have an output image. */ VipsImage *out; } VipsCreate; typedef struct _VipsCreateClass { VipsOperationClass parent_class; } VipsCreateClass; GType vips_create_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PCREATE_H*/ libvips-8.18.2/libvips/create/perlin.c000066400000000000000000000202101516303661500176330ustar00rootroot00000000000000/* Perlin noise generator. * * 24/7/16 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsPerlin { VipsCreate parent_instance; int width; int height; int cell_size; gboolean uchar; int cells_across; int cells_down; /* Use this to seed this call of our rng. */ guint32 seed; } VipsPerlin; typedef struct _VipsPerlinClass { VipsCreateClass parent_class; } VipsPerlinClass; G_DEFINE_TYPE(VipsPerlin, vips_perlin, VIPS_TYPE_CREATE); /* cos and sin from an angle in 0 - 255. */ float vips_perlin_cos[256]; float vips_perlin_sin[256]; typedef struct _Sequence { VipsPerlin *perlin; /* The position of the last cell we were in. Use this to avoid * regenerating vectors on every pixel lookup. */ int cell_x; int cell_y; /* The 2 x 2 grid of unit vectors, with cell_x/cell_y as the top left. */ float gx[4]; float gy[4]; } Sequence; /* Generate a 3 x 3 grid of cells around a point. */ static void vips_perlin_create_cells(VipsPerlin *perlin, float gx[4], float gy[4], int cell_x, int cell_y) { int x, y; for (y = 0; y < 2; y++) for (x = 0; x < 2; x++) { int ci = x + y * 2; guint32 seed; int cx; int cy; int angle; seed = perlin->seed; cx = cell_x + x; cy = cell_y + y; /* When we calculate the seed for this cell, we wrap * around so that our output will tessellate. */ if (cy >= perlin->cells_down) cy = 0; seed = vips__random_add(seed, cy); if (cx >= perlin->cells_across) cx = 0; seed = vips__random_add(seed, cx); angle = (seed ^ (seed >> 8) ^ (seed >> 16)) & 0xff; gx[ci] = vips_perlin_cos[angle]; gy[ci] = vips_perlin_sin[angle]; } } static int vips_perlin_stop(void *vseq, void *a, void *b) { Sequence *seq = (Sequence *) vseq; VIPS_FREE(seq); return 0; } static void * vips_perlin_start(VipsImage *out, void *a, void *b) { VipsPerlin *perlin = (VipsPerlin *) b; Sequence *seq; if (!(seq = VIPS_NEW(NULL, Sequence))) return NULL; seq->perlin = perlin; seq->cell_x = -1; seq->cell_y = -1; return seq; } /* Smooth linear interpolation, 0 <= x <= 1. * * https://en.wikipedia.org/wiki/Smoothstep */ static float smootherstep(float x) { return x * x * x * (x * (x * 6 - 15) + 10); } static int vips_perlin_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsPerlin *perlin = (VipsPerlin *) a; VipsRect *r = &out_region->valid; Sequence *seq = (Sequence *) vseq; int x, y; for (y = 0; y < r->height; y++) { float *fq = (float *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); VipsPel *q = (VipsPel *) fq; for (x = 0; x < r->width; x++) { int cs = perlin->cell_size; int cell_x = (r->left + x) / cs; int cell_y = (r->top + y) / cs; float dx = (x + r->left - cell_x * cs) / (float) cs; float dy = (y + r->top - cell_y * cs) / (float) cs; float sx = smootherstep(dx); float sy = smootherstep(dy); float n0, n1; float ix0, ix1; float p; if (cell_x != seq->cell_x || cell_y != seq->cell_y) { vips_perlin_create_cells(perlin, seq->gx, seq->gy, cell_x, cell_y); seq->cell_x = cell_x; seq->cell_y = cell_y; } n0 = -dx * seq->gx[0] + -dy * seq->gy[0]; n1 = (1 - dx) * seq->gx[1] + -dy * seq->gy[1]; ix0 = n0 + sx * (n1 - n0); n0 = -dx * seq->gx[2] + (1 - dy) * seq->gy[2]; n1 = (1 - dx) * seq->gx[3] + (1 - dy) * seq->gy[3]; ix1 = n0 + sx * (n1 - n0); p = ix0 + sy * (ix1 - ix0); if (perlin->uchar) q[x] = 128 * p + 128; else fq[x] = p; } } return 0; } static int vips_perlin_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsPerlin *perlin = (VipsPerlin *) object; if (VIPS_OBJECT_CLASS(vips_perlin_parent_class)->build(object)) return -1; /* Be careful if width is a multiple of cell_size. */ perlin->cells_across = VIPS_ROUND_UP(perlin->width, perlin->cell_size) / perlin->cell_size; perlin->cells_down = VIPS_ROUND_UP(perlin->height, perlin->cell_size) / perlin->cell_size; vips_image_init_fields(create->out, perlin->width, perlin->height, 1, perlin->uchar ? VIPS_FORMAT_UCHAR : VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(create->out, vips_perlin_start, vips_perlin_gen, vips_perlin_stop, perlin, NULL)) return -1; return 0; } static void * vips_perlin_make_tables(void *client) { int i; for (i = 0; i < 256; i++) { float angle = 2.0F * VIPS_PI * i / 256.0F; vips_perlin_cos[i] = cosf(angle); vips_perlin_sin[i] = sinf(angle); } return NULL; } static void vips_perlin_class_init(VipsPerlinClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, vips_perlin_make_tables, NULL); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "perlin"; vobject_class->description = _("make a perlin noise image"); vobject_class->build = vips_perlin_build; VIPS_ARG_INT(class, "width", 2, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPerlin, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 3, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPerlin, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "cell_size", 3, _("Cell size"), _("Size of Perlin cells"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsPerlin, cell_size), 1, VIPS_MAX_COORD, 256); VIPS_ARG_BOOL(class, "uchar", 4, _("Uchar"), _("Output an unsigned char image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsPerlin, uchar), FALSE); VIPS_ARG_INT(class, "seed", 5, _("Seed"), _("Random number seed"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsPerlin, seed), INT_MIN, INT_MAX, 0); } static void vips_perlin_init(VipsPerlin *perlin) { perlin->cell_size = 256; perlin->seed = UINT_MAX * g_random_double(); } /** * vips_perlin: * @out: (out): output image * @width: horizontal size * @height: vertical size * @...: `NULL`-terminated list of optional named arguments * * Create a one-band float image of [Perlin * noise](https://en.wikipedia.org/wiki/Perlin_noise). * * Use @cell_size to set the size of the cells from which the image is * constructed. The default is 256 x 256. * * If @width and @height are multiples of @cell_size, the image will tessellate. * * Normally, output pixels are [enum@Vips.BandFormat.FLOAT] in the range * [-1, +1]. Set @uchar to output a uchar image with pixels in [0, 255]. * * ::: tip "Optional arguments" * * @cell_size: `gint`, size of Perlin cells * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.worley], [ctor@Image.fractsurf], [ctor@Image.gaussnoise]. * * Returns: 0 on success, -1 on error */ int vips_perlin(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("perlin", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/pmask.h000066400000000000000000000107651516303661500175000ustar00rootroot00000000000000/* base class for mask generators */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PMASK_H #define VIPS_PMASK_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* vips7compat.h defines VIPS_MASK(), an old compat macro. */ #ifdef VIPS_MASK #undef VIPS_MASK #endif /*VIPS_MASK*/ #define VIPS_TYPE_MASK (vips_mask_get_type()) #define VIPS_MASK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_MASK, VipsMask)) #define VIPS_MASK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_MASK, VipsMaskClass)) #define VIPS_IS_MASK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_MASK)) #define VIPS_IS_MASK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_MASK)) #define VIPS_MASK_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_MASK, VipsMaskClass)) typedef struct _VipsMask { VipsPoint parent_instance; gboolean optical; gboolean reject; gboolean nodc; } VipsMask; typedef struct _VipsMaskClass { VipsPointClass parent_class; double (*point)(VipsMask *, double, double); } VipsMaskClass; GType vips_mask_get_type(void); #define VIPS_TYPE_MASK_IDEAL (vips_mask_ideal_get_type()) #define VIPS_MASK_IDEAL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_MASK_IDEAL, VipsMaskIdeal)) #define VIPS_MASK_IDEAL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_MASK_IDEAL, VipsMaskIdealClass)) #define VIPS_IS_MASK_IDEAL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_MASK_IDEAL)) #define VIPS_IS_MASK_IDEAL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_MASK_IDEAL)) #define VIPS_MASK_IDEAL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_MASK_IDEAL, VipsMaskIdealClass)) typedef struct _VipsMaskIdeal { VipsMask parent_instance; double frequency_cutoff; } VipsMaskIdeal; typedef VipsMaskClass VipsMaskIdealClass; GType vips_mask_ideal_get_type(void); #define VIPS_TYPE_MASK_BUTTERWORTH (vips_mask_butterworth_get_type()) #define VIPS_MASK_BUTTERWORTH(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_MASK_BUTTERWORTH, VipsMaskButterworth)) #define VIPS_MASK_BUTTERWORTH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_MASK_BUTTERWORTH, VipsMaskButterworthClass)) #define VIPS_IS_MASK_BUTTERWORTH(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_MASK_BUTTERWORTH)) #define VIPS_IS_MASK_BUTTERWORTH_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_MASK_BUTTERWORTH)) #define VIPS_MASK_BUTTERWORTH_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_MASK_BUTTERWORTH, VipsMaskButterworthClass)) typedef struct _VipsMaskButterworth { VipsMask parent_instance; double order; double frequency_cutoff; double amplitude_cutoff; } VipsMaskButterworth; typedef VipsMaskClass VipsMaskButterworthClass; GType vips_mask_butterworth_get_type(void); #define VIPS_TYPE_MASK_GAUSSIAN (vips_mask_gaussian_get_type()) #define VIPS_MASK_GAUSSIAN(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_MASK_GAUSSIAN, VipsMaskGaussian)) #define VIPS_MASK_GAUSSIAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_MASK_GAUSSIAN, VipsMaskGaussianClass)) #define VIPS_IS_MASK_GAUSSIAN(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_MASK_GAUSSIAN)) #define VIPS_IS_MASK_GAUSSIAN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_MASK_GAUSSIAN)) #define VIPS_MASK_GAUSSIAN_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_MASK_GAUSSIAN, VipsMaskGaussianClass)) typedef struct _VipsMaskGaussian { VipsMask parent_instance; double frequency_cutoff; double amplitude_cutoff; } VipsMaskGaussian; typedef VipsMaskClass VipsMaskGaussianClass; GType vips_mask_gaussian_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PMASK_H*/ libvips-8.18.2/libvips/create/point.c000066400000000000000000000074351516303661500175110ustar00rootroot00000000000000/* base class for point-wise creators * * 13/6/13 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" G_DEFINE_ABSTRACT_TYPE(VipsPoint, vips_point, VIPS_TYPE_CREATE); static int vips_point_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsPoint *point = (VipsPoint *) a; VipsPointClass *class = VIPS_POINT_GET_CLASS(point); VipsRect *r = &out_region->valid; int x, y; for (y = 0; y < r->height; y++) { int ay = r->top + y; float *q = (float *) VIPS_REGION_ADDR(out_region, r->left, ay); for (x = 0; x < r->width; x++) q[x] = class->point(point, r->left + x, ay); } return 0; } static int vips_point_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsPoint *point = VIPS_POINT(object); VipsPointClass *class = VIPS_POINT_GET_CLASS(point); VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_point_parent_class)->build(object)) return -1; t[0] = vips_image_new(); vips_image_init_fields(t[0], point->width, point->height, 1, VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, class->interpretation, 1.0, 1.0); if (vips_image_pipelinev(t[0], VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(t[0], NULL, vips_point_gen, NULL, point, NULL)) return -1; in = t[0]; if (point->uchar) { float min = class->min; float max = class->max; float range = max - min; if (vips_linear1(in, &t[2], 255.0 / range, -min * 255.0 / range, "uchar", TRUE, NULL)) return -1; in = t[2]; /* We don't want FOURIER or whatever in this case. */ in->Type = VIPS_INTERPRETATION_MULTIBAND; } if (vips_image_write(in, create->out)) return -1; return 0; } static void vips_point_class_init(VipsPointClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "point"; vobject_class->description = _("make a point image"); vobject_class->build = vips_point_build; class->point = NULL; class->min = -1.0F; class->max = 1.0F; class->interpretation = VIPS_INTERPRETATION_MULTIBAND; VIPS_ARG_INT(class, "width", 2, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPoint, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 3, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPoint, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_BOOL(class, "uchar", 4, _("Uchar"), _("Output an unsigned char image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsPoint, uchar), FALSE); } static void vips_point_init(VipsPoint *point) { } libvips-8.18.2/libvips/create/point.h000066400000000000000000000036131516303661500175100ustar00rootroot00000000000000/* base class for point generators */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_POINT_H #define VIPS_POINT_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_POINT (vips_point_get_type()) #define VIPS_POINT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_POINT, VipsPoint)) #define VIPS_POINT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_POINT, VipsPointClass)) #define VIPS_IS_POINT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_POINT)) #define VIPS_IS_POINT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_POINT)) #define VIPS_POINT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_POINT, VipsPointClass)) typedef struct _VipsPoint { VipsCreate parent_instance; int width; int height; gboolean uchar; } VipsPoint; typedef struct _VipsPointClass { VipsCreateClass parent_class; float (*point)(VipsPoint *, int, int); float min; float max; VipsInterpretation interpretation; } VipsPointClass; GType vips_point_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_POINT_H*/ libvips-8.18.2/libvips/create/sdf.c000066400000000000000000000227211516303661500171270ustar00rootroot00000000000000/* make various signed distance fields * * 16/6/24 * - from xyz.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsSdf VipsSdf; typedef float (*PointFn)(VipsSdf *, int x, int y); struct _VipsSdf { VipsCreate parent_instance; int width; int height; VipsSdfShape shape; double *a; // two vec2 double *b; double r; double *corners; // corner radii float cx; // centre float cy; float dx; // difference float dy; float sx; // half size float sy; VipsArea *corners_area; VipsArea *a_area; VipsArea *b_area; PointFn point; }; typedef VipsCreateClass VipsSdfClass; G_DEFINE_TYPE(VipsSdf, vips_sdf, VIPS_TYPE_CREATE); /* SDF functions derived from * * https://iquilezles.org/articles/distfunctions2d/ */ static float vips_sdf_circle(VipsSdf *sdf, int x, int y) { return hypotf(x - sdf->a[0], y - sdf->a[1]) - sdf->r; } static float vips_sdf_box(VipsSdf *sdf, int x, int y) { float px = x - sdf->cx; float py = y - sdf->cy; float dx = fabsf(px) - sdf->sx; float dy = fabsf(py) - sdf->sy; return hypotf(VIPS_MAX(dx, 0), VIPS_MAX(dy, 0)) + VIPS_MIN(VIPS_MAX(dx, dy), 0); } static float vips_sdf_rounded_box(VipsSdf *sdf, int x, int y) { float px = x - sdf->cx; float py = y - sdf->cy; // radius of nearest corner float r_top = px > 0 ? sdf->corners[0] : sdf->corners[2]; float r_bottom = px > 0 ? sdf->corners[1] : sdf->corners[3]; float r = py > 0 ? r_top : r_bottom; float qx = fabsf(px) - sdf->sx + r; float qy = fabsf(py) - sdf->sy + r; return hypotf(VIPS_MAX(qx, 0), VIPS_MAX(qy, 0)) + VIPS_MIN(VIPS_MAX(qx, qy), 0) - r; } static float vips_sdf_line(VipsSdf *sdf, int px, int py) { float pax = px - sdf->a[0]; float pay = py - sdf->a[1]; float dot_paba = pax * sdf->dx + pay * sdf->dy; float dot_baba = sdf->dx * sdf->dx + sdf->dy * sdf->dy; float h = VIPS_FCLIP(0, dot_paba / dot_baba, 1); float dx = pax - h * sdf->dx; float dy = pay - h * sdf->dy; return hypotf(dx, dy); } static int vips_sdf_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsSdf *sdf = (VipsSdf *) a; VipsRect *r = &out_region->valid; for (int y = 0; y < r->height; y++) { int ay = y + r->top; float *q = (float *) VIPS_REGION_ADDR(out_region, r->left, ay); for (int x = 0; x < r->width; x++) q[x] = sdf->point(sdf, x + r->left, ay); } return 0; } static int vips_sdf_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsSdf *sdf = (VipsSdf *) object; if (VIPS_OBJECT_CLASS(vips_sdf_parent_class)->build(object)) return -1; switch (sdf->shape) { case VIPS_SDF_SHAPE_CIRCLE: if (!vips_object_argument_isset(object, "a") || !vips_object_argument_isset(object, "r")) { vips_error(class->nickname, "%s", _("circle needs a, r to be set")); return -1; } if (sdf->a_area->n != 2) { vips_error(class->nickname, "%s", _("rounded-box needs 2 values for a")); return -1; } sdf->a = (double *) sdf->a_area->data; sdf->point = vips_sdf_circle; break; case VIPS_SDF_SHAPE_BOX: if (!vips_object_argument_isset(object, "a") || !vips_object_argument_isset(object, "b")) { vips_error(class->nickname, "%s", _("box needs a, b to be set")); return -1; } if (sdf->a_area->n != 2 || sdf->b_area->n != 2) { vips_error(class->nickname, "%s", _("box needs 2 values for a, b")); return -1; } sdf->a = (double *) sdf->a_area->data; sdf->b = (double *) sdf->b_area->data; sdf->point = vips_sdf_box; break; case VIPS_SDF_SHAPE_ROUNDED_BOX: if (!vips_object_argument_isset(object, "a") || !vips_object_argument_isset(object, "b")) { vips_error(class->nickname, "%s", _("rounded-box needs a, b to be set")); return -1; } if (sdf->a_area->n != 2 || sdf->b_area->n != 2) { vips_error(class->nickname, "%s", _("rounded-box needs 2 values for a, b")); return -1; } if (sdf->corners_area->n != 4) { vips_error(class->nickname, "%s", _("rounded-box needs 4 values for corners")); return -1; } sdf->a = (double *) sdf->a_area->data; sdf->b = (double *) sdf->b_area->data; sdf->corners = (double *) sdf->corners_area->data; sdf->point = vips_sdf_rounded_box; break; case VIPS_SDF_SHAPE_LINE: if (!vips_object_argument_isset(object, "a") || !vips_object_argument_isset(object, "b")) { vips_error(class->nickname, "%s", _("line needs sx, sy to be set")); return -1; } if (sdf->a_area->n != 2 || sdf->b_area->n != 2) { vips_error(class->nickname, "%s", _("line needs 2 values for a, b")); return -1; } sdf->a = (double *) sdf->a_area->data; sdf->b = (double *) sdf->b_area->data; sdf->point = vips_sdf_line; break; default: vips_error(class->nickname, _("unknown SDF %d"), sdf->shape); return -1; } if (sdf->a && sdf->b) { // centre sdf->cx = (sdf->a[0] + sdf->b[0]) / 2.0; sdf->cy = (sdf->a[1] + sdf->b[1]) / 2.0; // difference sdf->dx = sdf->b[0] - sdf->a[0]; sdf->dy = sdf->b[1] - sdf->a[1]; // half size sdf->sx = sdf->dx / 2.0; sdf->sy = sdf->dy / 2.0; } vips_image_init_fields(create->out, sdf->width, sdf->height, 1, VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(create->out, NULL, vips_sdf_gen, NULL, sdf, NULL)) return -1; return 0; } static void vips_sdf_class_init(VipsSdfClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_sdf_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "sdf"; vobject_class->description = _("create an SDF image"); vobject_class->build = vips_sdf_build; VIPS_ARG_INT(class, "width", 2, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSdf, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 3, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSdf, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_ENUM(class, "shape", 8, _("Shape"), _("SDF shape to create"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSdf, shape), VIPS_TYPE_SDF_SHAPE, VIPS_SDF_SHAPE_CIRCLE); VIPS_ARG_DOUBLE(class, "r", 9, _("r"), _("Radius"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSdf, r), 0.0, VIPS_MAX_COORD, 50); VIPS_ARG_BOXED(class, "a", 13, _("a"), _("Point a"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSdf, a_area), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOXED(class, "b", 14, _("b"), _("Point b"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSdf, b_area), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOXED(class, "corners", 15, _("corners"), _("Corner radii"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSdf, corners_area), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_sdf_init(VipsSdf *sdf) { sdf->corners_area = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), 4); } /** * vips_sdf: * @out: (out): output image * @width: horizontal size * @height: vertical size * @shape: SDF to create * @...: `NULL`-terminated list of optional named arguments * * Create a signed distance field (SDF) image of the given @shape. * * Different * shapes use different combinations of the optional arguments, see below. * * @shape [enum@Vips.SdfShape.CIRCLE]: create a circle centred on @a, radius @r. * * @shape [enum@Vips.SdfShape.BOX]: create a box with top-left corner @a and * bottom-right corner @b. * * @shape [enum@Vips.SdfShape.ROUNDED_BOX]: create a box with top-left corner @a * and bottom-right corner @b, whose four corners are * rounded by the four-element float array @corners. @corners will default to * 0.0. * * @shape [enum@Vips.SdfShape.LINE]: draw a line from @a to @b. * * ::: tip "Optional arguments" * * @a: [struct@ArrayDouble], first point * * @b: [struct@ArrayDouble], second point * * @r: `gdouble`, radius * * @corners: [struct@ArrayDouble], corner radii * * ::: seealso * [ctor@Image.grey], [method@Image.grid], [ctor@Image.xyz]. * * Returns: 0 on success, -1 on error */ int vips_sdf(VipsImage **out, int width, int height, VipsSdfShape shape, ...) { va_list ap; int result; va_start(ap, shape); result = vips_call_split("sdf", ap, out, width, height, shape); va_end(ap); return result; } libvips-8.18.2/libvips/create/sines.c000066400000000000000000000105371516303661500174760ustar00rootroot00000000000000/* creates a 2d sinewave * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/02/1990 * Modified on: * 22/7/93 JC * - externs removed * - im_outcheck() added * 1/2/11 * - gtk-doc * 13/6/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" typedef struct _VipsSines { VipsPoint parent_instance; double hfreq; double vfreq; double c; double sintheta; double costheta; } VipsSines; typedef VipsPointClass VipsSinesClass; G_DEFINE_TYPE(VipsSines, vips_sines, VIPS_TYPE_POINT); static float vips_sines_point(VipsPoint *point, int x, int y) { VipsSines *sines = (VipsSines *) point; return cosf(sines->c * (x * sines->costheta - y * sines->sintheta)); } static int vips_sines_build(VipsObject *object) { VipsPoint *point = VIPS_POINT(object); VipsSines *sines = (VipsSines *) object; double theta; double factor; if (VIPS_OBJECT_CLASS(vips_sines_parent_class)->build(object)) return -1; theta = sines->hfreq == 0.0 ? VIPS_PI / 2.0 : atan(sines->vfreq / sines->hfreq); factor = sqrt(sines->hfreq * sines->hfreq + sines->vfreq * sines->vfreq); sines->costheta = cos(theta); sines->sintheta = sin(theta); sines->c = factor * VIPS_PI * 2.0 / point->width; return 0; } static void vips_sines_class_init(VipsSinesClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsPointClass *point_class = VIPS_POINT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "sines"; vobject_class->description = _("make a 2D sine wave"); vobject_class->build = vips_sines_build; point_class->point = vips_sines_point; VIPS_ARG_DOUBLE(class, "hfreq", 6, _("hfreq"), _("Horizontal spatial frequency"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSines, hfreq), 0.0, 10000.0, 0.5); VIPS_ARG_DOUBLE(class, "vfreq", 7, _("vfreq"), _("Vertical spatial frequency"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSines, vfreq), 0.0, 10000.0, 0.5); } static void vips_sines_init(VipsSines *sines) { sines->hfreq = 0.5; sines->vfreq = 0.5; } /** * vips_sines: * @out: (out): output image * @width: image size * @height: image size * @...: `NULL`-terminated list of optional named arguments * * Creates a float one band image of the a sine waveform in two * dimensions. * * The number of horizontal and vertical spatial frequencies are * determined by the variables @hfreq and @vfreq respectively. The * function is useful for creating displayable sine waves and * square waves in two dimensions. * * If horfreq and verfreq are integers the resultant image is periodical * and therefore the Fourier transform does not present spikes * * Pixels are normally in [-1, +1], set @uchar to output [0, 255]. * * ::: tip "Optional arguments" * * @hfreq: `gdouble`, horizontal frequency * * @vreq: `gdouble`, vertical frequency * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.grey], [ctor@Image.xyz]. * * Returns: 0 on success, -1 on error */ int vips_sines(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("sines", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/text.c000066400000000000000000000452601516303661500173420ustar00rootroot00000000000000/* vips_text * * Written on: 20/5/04 * 29/7/04 * - !HAVE_PANGOFT2 was broken, thanks Kenneth * 15/11/04 * - gah, still broken, thanks Stefan * 5/4/06 * - return an error for im_text( "" ) rather than trying to make an * empty image * 2/2/10 * - gtkdoc * 3/6/13 * - rewrite as a class * 20/9/15 leiyangyou * - add @spacing * 29/5/17 * - don't set "font" if unset, it breaks caching * 16/7/17 gargsms * - implement auto fitting of text inside bounds * 12/3/18 * - better fitting of fonts with overhanging edges, thanks Adrià * 26/4/18 fangqiao * - add fontfile option * 5/12/18 * - fitting mode could set wrong dpi * - fitting mode leaked * 16/3/19 * - add `justify` * - set Xoffset/Yoffset to ink left/top * 27/6/19 * - fitting could occasionally terminate early [levmorozov] * 16/5/20 [keiviv] * - don't add fontfiles repeatedly * 12/4/21 * - switch to cairo for text rendering * - add rgba flag * 31/10/22 * - add @wrap * 14/1/23 * - make our own fontmap to prevent conflict with other API users * 15/2/23 * - allow negative line spacing */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef HAVE_PANGOCAIRO #include #include #include #ifdef HAVE_FONTCONFIG /* ftconfig.h also appears to define HAVE_UNISTD_H. */ #ifdef HAVE_UNISTD_H #undef HAVE_UNISTD_H #endif #include #include #endif #include "pcreate.h" typedef struct _VipsText { VipsCreate parent_instance; char *text; char *font; int width; int height; int spacing; VipsAlign align; gboolean justify; int dpi; char *fontfile; gboolean rgba; VipsTextWrap wrap; PangoContext *context; PangoLayout *layout; } VipsText; typedef VipsCreateClass VipsTextClass; G_DEFINE_TYPE(VipsText, vips_text, VIPS_TYPE_CREATE); /* These are expensive and do not unref cleanly on many platforms. We keep a * single value for libvips and reuse it behind a lock. * * Have one shared between libvips threads. */ static PangoFontMap *vips_text_fontmap = NULL; /* ... single-thread vips_text_fontfiles with this. */ static GMutex vips_text_lock; /* All the fontfiles we've loaded. fontconfig lets you add a fontfile * repeatedly, and we obviously don't want that. */ static GHashTable *vips_text_fontfiles = NULL; static void vips_text_dispose(GObject *gobject) { VipsText *text = (VipsText *) gobject; VIPS_UNREF(text->layout); VIPS_UNREF(text->context); G_OBJECT_CLASS(vips_text_parent_class)->dispose(gobject); } static PangoLayout * text_layout_new(PangoContext *context, const char *text, const char *font, int width, int spacing, VipsAlign align, VipsTextWrap wrap, gboolean justify) { PangoLayout *layout; PangoFontDescription *font_description; PangoAlignment palign; PangoWrapMode pwrap; int pwidth; layout = pango_layout_new(context); pango_layout_set_markup(layout, text, -1); font_description = pango_font_description_from_string(font); pango_layout_set_font_description(layout, font_description); pango_font_description_free(font_description); pango_layout_set_justify(layout, justify); pango_layout_set_spacing(layout, spacing * PANGO_SCALE); switch (align) { case VIPS_ALIGN_LOW: palign = PANGO_ALIGN_LEFT; break; case VIPS_ALIGN_CENTRE: palign = PANGO_ALIGN_CENTER; break; case VIPS_ALIGN_HIGH: palign = PANGO_ALIGN_RIGHT; break; default: palign = PANGO_ALIGN_LEFT; break; } pango_layout_set_alignment(layout, palign); switch (wrap) { case VIPS_TEXT_WRAP_NONE: pwrap = PANGO_WRAP_WORD_CHAR; pwidth = -1; break; case VIPS_TEXT_WRAP_CHAR: pwrap = PANGO_WRAP_CHAR; pwidth = width * PANGO_SCALE; break; case VIPS_TEXT_WRAP_WORD: pwrap = PANGO_WRAP_WORD; pwidth = width * PANGO_SCALE; break; case VIPS_TEXT_WRAP_WORD_CHAR: default: pwrap = PANGO_WRAP_WORD_CHAR; pwidth = width * PANGO_SCALE; break; } pango_layout_set_wrap(layout, pwrap); if (pwidth > 0) pango_layout_set_width(layout, width * PANGO_SCALE); return layout; } static int vips_text_get_extents(VipsText *text, VipsRect *extents) { PangoRectangle ink_rect; PangoRectangle logical_rect; pango_cairo_font_map_set_resolution( PANGO_CAIRO_FONT_MAP(vips_text_fontmap), text->dpi); VIPS_UNREF(text->layout); if (!(text->layout = text_layout_new(text->context, text->text, text->font, text->width, text->spacing, text->align, text->wrap, text->justify))) return -1; pango_layout_get_pixel_extents(text->layout, &ink_rect, &logical_rect); extents->left = ink_rect.x; extents->top = ink_rect.y; extents->width = ink_rect.width; extents->height = ink_rect.height; #ifdef DEBUG printf("vips_text_get_extents: dpi = %d\n", text->dpi); printf(" ink left = %d, top = %d, width = %d, height = %d\n", ink_rect.x, ink_rect.y, ink_rect.width, ink_rect.height); printf(" logical left = %d, top = %d, width = %d, height = %d\n", logical_rect.x, logical_rect.y, logical_rect.width, logical_rect.height); #endif /*DEBUG*/ return 0; } /* Return -ve for extents too small, +ve for extents too large. */ static int vips_text_rect_difference(VipsRect *target, VipsRect *extents) { if (vips_rect_includesrect(target, extents)) return -1; else return 1; } /* Adjust text->dpi to try to fit to the bounding box. */ static int vips_text_autofit(VipsText *text) { VipsRect target; VipsRect extents; int difference; int previous_difference; int previous_dpi; int lower_dpi; int upper_dpi; /* First, repeatedly double or halve dpi until we pass the correct * value. This will give us a lower and upper bound. */ target.left = 0; target.top = 0; target.width = text->width; target.height = text->height; previous_dpi = -1; previous_difference = 0; #ifdef DEBUG printf("vips_text_autofit: " "target left = %d, top = %d, width = %d, height = %d\n", target.left, target.top, target.width, target.height); #endif /*DEBUG*/ for (;;) { if (vips_text_get_extents(text, &extents)) return -1; target.left = extents.left; target.top = extents.top; difference = vips_text_rect_difference(&target, &extents); if (previous_dpi == -1) { previous_dpi = text->dpi; previous_difference = difference; } /* Stop if we straddle the target. */ if (difference != previous_difference) break; previous_difference = difference; previous_dpi = text->dpi; text->dpi = difference < 0 ? text->dpi * 2 : text->dpi / 2; // FIXME: Invalidates operation cache /* This can happen with fixed-size fonts. */ if (text->dpi < 2 || text->dpi > 10000) break; } if (difference < 0) { /* We've been coming down. */ lower_dpi = text->dpi; upper_dpi = previous_dpi; } else { lower_dpi = previous_dpi; upper_dpi = text->dpi; } #ifdef DEBUG printf("vips_text_autofit: lower dpi = %d, upper dpi = %d\n", lower_dpi, upper_dpi); #endif /*DEBUG*/ /* Refine lower and upper until they are almost touching. */ while (upper_dpi - lower_dpi > 1 && difference != 0) { text->dpi = (upper_dpi + lower_dpi) / 2; // FIXME: Invalidates operation cache if (vips_text_get_extents(text, &extents)) return -1; target.left = extents.left; target.top = extents.top; difference = vips_text_rect_difference(&target, &extents); if (difference < 0) lower_dpi = text->dpi; else upper_dpi = text->dpi; } /* If we've hit the target exactly and quit the loop, diff will be 0 * and we can use upper. Otherwise we are straddling the target and we * must take lower. */ if (difference == 0) text->dpi = upper_dpi; // FIXME: Invalidates operation cache else text->dpi = lower_dpi; // FIXME: Invalidates operation cache g_object_set(text, "autofit_dpi", text->dpi, NULL); #ifdef DEBUG printf("vips_text_autofit: final dpi = %d\n", text->dpi); #endif /*DEBUG*/ return 0; } static void * vips_text_init_once(void *client) { vips_text_fontmap = pango_cairo_font_map_new(); vips_text_fontfiles = g_hash_table_new(g_str_hash, g_str_equal); return NULL; } static int vips_text_build(VipsObject *object) { static GOnce once = G_ONCE_INIT; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsText *text = (VipsText *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); VipsRect extents; VipsImage *in; cairo_surface_t *surface; cairo_t *cr; cairo_status_t status; if (VIPS_OBJECT_CLASS(vips_text_parent_class)->build(object)) return -1; if (!pango_parse_markup(text->text, -1, 0, NULL, NULL, NULL, NULL)) { vips_error(class->nickname, "%s", _("invalid markup in text")); return -1; } VIPS_ONCE(&once, vips_text_init_once, NULL); text->context = pango_font_map_create_context(vips_text_fontmap); if (text->rgba) { /* Prevent use of subpixel anti-aliasing to avoid artefacts. */ cairo_font_options_t *opts = cairo_font_options_create(); cairo_font_options_set_antialias(opts, CAIRO_ANTIALIAS_GRAY); pango_cairo_context_set_font_options(text->context, opts); cairo_font_options_destroy(opts); } /* Because we set resolution on vips_text_fontmap and that's shared * between all vips_text instances, we must lock all the way to the * end of text rendering. */ g_mutex_lock(&vips_text_lock); #ifdef HAVE_FONTCONFIG if (text->fontfile && !g_hash_table_contains(vips_text_fontfiles, text->fontfile)) { /* This can fail if you eg. add the same font from two * different files. Just warn. */ if (!FcConfigAppFontAddFile(NULL, (const FcChar8 *) text->fontfile)) g_warning("unable to load fontfile \"%s\"", text->fontfile); g_hash_table_insert(vips_text_fontfiles, g_strdup(text->fontfile), NULL); /* We need to inform that pango should invalidate its * fontconfig cache whenever any changes are made. */ if (PANGO_IS_FC_FONT_MAP(vips_text_fontmap)) pango_fc_font_map_cache_clear( PANGO_FC_FONT_MAP(vips_text_fontmap)); } #else /*!HAVE_FONTCONFIG*/ if (text->fontfile) g_warning("ignoring fontfile (no fontconfig support)"); #endif /*HAVE_FONTCONFIG*/ /* If our caller set height and not dpi, we adjust dpi until * we get a fit. */ if (vips_object_argument_isset(object, "height") && !vips_object_argument_isset(object, "dpi")) { if (vips_text_autofit(text)) { g_mutex_unlock(&vips_text_lock); return -1; } } /* Layout. Can fail for "", for example. */ if (vips_text_get_extents(text, &extents)) { g_mutex_unlock(&vips_text_lock); return -1; } if (extents.width == 0 || extents.height == 0) { g_mutex_unlock(&vips_text_lock); vips_error(class->nickname, "%s", _("no text to render")); return -1; } t[0] = vips_image_new_memory(); vips_image_init_fields(t[0], extents.width, extents.height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, text->dpi / 25.4, text->dpi / 25.4); t[0]->Xoffset = extents.left; t[0]->Yoffset = extents.top; if (vips_image_pipelinev(t[0], VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_write_prepare(t[0])) { g_mutex_unlock(&vips_text_lock); return -1; } in = t[0]; surface = cairo_image_surface_create_for_data( VIPS_IMAGE_ADDR(in, 0, 0), CAIRO_FORMAT_ARGB32, in->Xsize, in->Ysize, VIPS_IMAGE_SIZEOF_LINE(in)); status = cairo_surface_status(surface); if (status) { cairo_surface_destroy(surface); g_mutex_unlock(&vips_text_lock); vips_error(class->nickname, "%s", cairo_status_to_string(status)); return -1; } cr = cairo_create(surface); cairo_surface_destroy(surface); cairo_translate(cr, -extents.left, -extents.top); pango_cairo_show_layout(cr, text->layout); cairo_destroy(cr); g_mutex_unlock(&vips_text_lock); if (text->rgba) { /* Cairo makes pre-multipled BRGA -- we must byteswap and * unpremultiply. */ for (int y = 0; y < in->Ysize; y++) vips__premultiplied_bgra2rgba( (guint32 *) VIPS_IMAGE_ADDR(in, 0, y), in->Xsize); } else { /* We just want the alpha channel. */ if (vips_extract_band(in, &t[1], 3, NULL) || vips_copy(t[1], &t[2], "interpretation", VIPS_INTERPRETATION_MULTIBAND, NULL)) return -1; in = t[2]; } if (vips_image_write(in, create->out)) return -1; return 0; } static void vips_text_class_init(VipsTextClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = vips_text_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "text"; vobject_class->description = _("make a text image"); vobject_class->build = vips_text_build; VIPS_ARG_STRING(class, "text", 4, _("Text"), _("Text to render"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsText, text), NULL); VIPS_ARG_STRING(class, "font", 5, _("Font"), _("Font to render with"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, font), NULL); VIPS_ARG_INT(class, "width", 6, _("Width"), _("Maximum image width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, width), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "height", 7, _("Height"), _("Maximum image height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, height), 0, VIPS_MAX_COORD, 0); VIPS_ARG_ENUM(class, "align", 8, _("Align"), _("Align on the low, centre or high edge"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, align), VIPS_TYPE_ALIGN, VIPS_ALIGN_LOW); VIPS_ARG_BOOL(class, "justify", 9, _("Justify"), _("Justify lines"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, justify), FALSE); VIPS_ARG_INT(class, "dpi", 10, _("DPI"), _("DPI to render at"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, dpi), 1, 1000000, 72); VIPS_ARG_INT(class, "autofit_dpi", 11, _("Autofit DPI"), _("DPI selected by autofit"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsText, dpi), 1, 1000000, 72); VIPS_ARG_INT(class, "spacing", 12, _("Spacing"), _("Line spacing"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, spacing), -1000000, 1000000, 0); VIPS_ARG_STRING(class, "fontfile", 13, _("Font file"), _("Load this font file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, fontfile), NULL); VIPS_ARG_BOOL(class, "rgba", 14, _("RGBA"), _("Enable RGBA output"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, rgba), FALSE); VIPS_ARG_ENUM(class, "wrap", 15, _("Wrap"), _("Wrap lines on word or character boundaries"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsText, wrap), VIPS_TYPE_TEXT_WRAP, VIPS_TEXT_WRAP_WORD); } static void vips_text_init(VipsText *text) { text->align = VIPS_ALIGN_LOW; text->dpi = 72; text->wrap = VIPS_TEXT_WRAP_WORD; VIPS_SETSTR(text->font, "sans 12"); } #endif /*HAVE_PANGOCAIRO*/ /** * vips_text: * @out: (out): output image * @text: utf-8 text string to render * @...: `NULL`-terminated list of optional named arguments * * Draw the string @text to an image. * * @out is normally a one-band 8-bit * unsigned char image, with 0 for no text and 255 for text. Values between * are used for anti-aliasing. * * Set @rgba to enable RGBA output. This is useful for colour emoji rendering, * or support for pango markup features like `Red!`. * * @text is the text to render as a UTF-8 string. It can contain Pango markup, * for example `TheGuardian`. * * @font is the font to render with, as a fontconfig name. Examples might be * `sans 12` or perhaps `bitstream charter bold 10`. * * You can specify a font to load with @fontfile. You'll need to also set the * name of the font with @font. * * @width is the number of pixels to word-wrap at. By default, lines of text * wider than this will be broken at word boundaries. * Use @wrap to set lines to wrap on word or character boundaries, or to * disable line breaks. * * Set @justify to turn on line justification. * @align can be used to set the alignment style for multi-line * text to the low (left) edge centre, or high (right) edge. Note that the * output image can be wider than @width if there are no * word breaks, or narrower if the lines don't break exactly at @width. * * @height is the maximum number of pixels high the generated text can be. This * only takes effect when @dpi is not set, and @width is set, making a box. * In this case, [ctor@Image.text] will search for a @dpi and set of line breaks * which will just fit the text into @width and @height. * * You can use @autofit_dpi to read out the DPI selected by auto fit. * * @dpi sets the resolution to render at. "sans 12" at 72 dpi draws characters * approximately 12 pixels high. * * @spacing sets the line spacing, in points. It would typically be something * like font size times 1.2. * * You can read the coordinate of the top edge of the character from `Xoffset` * / `Yoffset`. This can be helpful if you need to line up the output of * several [ctor@Image.text]. * * ::: tip "Optional arguments" * * @font: `gchararray`, font to render with * * @fontfile: `gchararray`, load this font file * * @width: `gint`, image should be no wider than this many pixels * * @height: `gint`, image should be no higher than this many pixels * * @align: [enum@Align], set justification alignment * * @justify: `gboolean`, justify lines * * @dpi: `gint`, render at this resolution * * @autofit_dpi: `gint`, output, auto-fitted DPI * * @rgba: `gboolean`, enable RGBA output * * @spacing: `gint`, space lines by this in points * * @wrap: [enum@TextWrap], wrap lines on characters or words * * ::: seealso * [func@Image.bandjoin], [func@Image.composite]. * * Returns: 0 on success, -1 on error */ int vips_text(VipsImage **out, const char *text, ...) { va_list ap; int result; va_start(ap, text); result = vips_call_split("text", ap, out, text); va_end(ap); return result; } libvips-8.18.2/libvips/create/tonelut.c000066400000000000000000000175401516303661500200500ustar00rootroot00000000000000/* Build a tone curve. * * Author: John Cupitt * Written on: 18/7/1995 * 17/9/96 JC * - restrictions on Ps, Pm, Ph relaxed * - restrictions on S, M, H relaxed * 25/7/01 JC * - patched for im_extract_band() change * 11/7/04 * - generalised to im_tone_build_range() ... so you can use it for any * image, not just LabS * 26/3/10 * - cleanups * - gtkdoc * 20/9/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pcreate.h" typedef struct _VipsTonelut { VipsCreate parent_instance; /* Parameters for tone curve formation. */ double Lb, Lw; double Ps, Pm, Ph; double S, M, H; /* Range we process. */ int in_max; int out_max; /* Derived values. */ double Ls, Lm, Lh; } VipsTonelut; typedef VipsCreateClass VipsTonelutClass; G_DEFINE_TYPE(VipsTonelut, vips_tonelut, VIPS_TYPE_CREATE); /* Calculate shadow curve. */ static double shad(VipsTonelut *lut, double x) { double x1 = (x - lut->Lb) / (lut->Ls - lut->Lb); double x2 = (x - lut->Ls) / (lut->Lm - lut->Ls); double out; if (x < lut->Lb) out = 0; else if (x < lut->Ls) out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1; else if (x < lut->Lm) out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2; else out = 0; return out; } /* Calculate mid-tone curve. */ static double mid(VipsTonelut *lut, double x) { double x1 = (x - lut->Ls) / (lut->Lm - lut->Ls); double x2 = (x - lut->Lm) / (lut->Lh - lut->Lm); double out; if (x < lut->Ls) out = 0; else if (x < lut->Lm) out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1; else if (x < lut->Lh) out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2; else out = 0; return out; } /* Calculate highlight curve. */ static double high(VipsTonelut *lut, double x) { double x1 = (x - lut->Lm) / (lut->Lh - lut->Lm); double x2 = (x - lut->Lh) / (lut->Lw - lut->Lh); double out; if (x < lut->Lm) out = 0; else if (x < lut->Lh) out = 3.0 * x1 * x1 - 2.0 * x1 * x1 * x1; else if (x < lut->Lw) out = 1.0 - 3.0 * x2 * x2 + 2.0 * x2 * x2 * x2; else out = 0; return out; } /* Generate a point on the tone curve. Everything is 0-100. */ static double tone_curve(VipsTonelut *lut, double x) { double out; out = x + lut->S * shad(lut, x) + lut->M * mid(lut, x) + lut->H * high(lut, x); return out; } static int vips_tonelut_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsTonelut *lut = (VipsTonelut *) object; int i; unsigned short buf[65536]; if (VIPS_OBJECT_CLASS(vips_tonelut_parent_class)->build(object)) return -1; g_assert(lut->in_max > 0 && lut->in_max < 65536); g_assert(lut->out_max > 0 && lut->out_max < 65536); /* Note derived params. */ lut->Ls = lut->Lb + lut->Ps * (lut->Lw - lut->Lb); lut->Lm = lut->Lb + lut->Pm * (lut->Lw - lut->Lb); lut->Lh = lut->Lb + lut->Ph * (lut->Lw - lut->Lb); /* Generate curve. */ for (i = 0; i <= lut->in_max; i++) { int v = (lut->out_max / 100.0) * tone_curve(lut, 100.0 * i / lut->in_max); if (v < 0) v = 0; else if (v > lut->out_max) v = lut->out_max; buf[i] = v; } /* Make the output image. */ vips_image_init_fields(create->out, lut->in_max + 1, 1, 1, VIPS_FORMAT_USHORT, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (vips_image_write_line(create->out, 0, (VipsPel *) buf)) return -1; return 0; } static void vips_tonelut_class_init(VipsTonelutClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "tonelut"; vobject_class->description = _("build a look-up table"); vobject_class->build = vips_tonelut_build; VIPS_ARG_INT(class, "in_max", 4, _("In-max"), _("Size of LUT to build"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, in_max), 1, 65535, 32767); VIPS_ARG_INT(class, "out_max", 5, _("Out-max"), _("Maximum value in output LUT"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, out_max), 1, 65535, 32767); VIPS_ARG_DOUBLE(class, "Lb", 6, _("Black point"), _("Lowest value in output"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, Lb), 0, 100, 0); VIPS_ARG_DOUBLE(class, "Lw", 7, _("White point"), _("Highest value in output"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, Lw), 0, 100, 100); VIPS_ARG_DOUBLE(class, "Ps", 8, _("Shadow point"), _("Position of shadow"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, Ps), 0, 1, 0.2); VIPS_ARG_DOUBLE(class, "Pm", 9, _("Mid-tone point"), _("Position of mid-tones"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, Pm), 0, 1, 0.5); VIPS_ARG_DOUBLE(class, "Ph", 10, _("Highlight point"), _("Position of highlights"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, Ph), 0, 1, 0.8); VIPS_ARG_DOUBLE(class, "S", 11, _("Shadow adjust"), _("Adjust shadows by this much"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, S), -30, 30, 0); VIPS_ARG_DOUBLE(class, "M", 12, _("Mid-tone adjust"), _("Adjust mid-tones by this much"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, M), -30, 30, 0); VIPS_ARG_DOUBLE(class, "H", 13, _("Highlight adjust"), _("Adjust highlights by this much"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTonelut, H), -30, 30, 0); } static void vips_tonelut_init(VipsTonelut *lut) { lut->in_max = 32767; lut->out_max = 32767; lut->Lb = 0.0; lut->Lw = 100.0; lut->Ps = 0.2; lut->Pm = 0.5; lut->Ph = 0.8; lut->S = 0.0; lut->M = 0.0; lut->H = 0.0; } /** * vips_tonelut: * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * [ctor@Image.tonelut] generates a tone curve for the adjustment of image * levels. * * This is mostly designed for adjusting the L* part of a LAB image in * a way suitable for print work, but you can use it for other things too. * * The curve is an unsigned 16-bit image with (@in_max + 1) entries, * each in the range [0, @out_max]. * * @Lb, @Lw are expressed as 0-100, as in LAB colour space. You * specify the scaling for the input and output images with the @in_max and * @out_max parameters. * * ::: tip "Optional arguments" * * @in_max: `gint`, input range * * @out_max: `gint`, output range * * @Lb: `gdouble`, black-point [0-100] * * @Lw: `gdouble`, white-point [0-100] * * @Ps: `gdouble`, shadow point (eg. 0.2) * * @Pm: `gdouble`, mid-tone point (eg. 0.5) * * @Ph: `gdouble`, highlight point (eg. 0.8) * * @S: `gdouble`, shadow adjustment (+/- 30) * * @M: `gdouble`, mid-tone adjustment (+/- 30) * * @H: `gdouble`, highlight adjustment (+/- 30) * * Returns: 0 on success, -1 on error */ int vips_tonelut(VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("tonelut", ap, out); va_end(ap); return result; } libvips-8.18.2/libvips/create/worley.c000066400000000000000000000200011516303661500176610ustar00rootroot00000000000000/* Worley noise generator. * * 19/7/16 * * 11/8/16 * - float output */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsWorley { VipsCreate parent_instance; int width; int height; int cell_size; int cells_across; int cells_down; /* Use this to seed this call of our rng. */ guint32 seed; } VipsWorley; typedef struct _VipsWorleyClass { VipsCreateClass parent_class; } VipsWorleyClass; G_DEFINE_TYPE(VipsWorley, vips_worley, VIPS_TYPE_CREATE); #define MAX_FEATURES (10) typedef struct _Cell { /* Cell position, in number of cells. Scale by cell_size to get * absolute image cods. */ int cell_x; int cell_y; /* A cell contains 1 to n features. */ int n_features; /* Feature coordinates, in absolute image space. */ int feature_x[MAX_FEATURES]; int feature_y[MAX_FEATURES]; } Cell; typedef struct _Sequence { VipsWorley *worley; /* The position of the last cell we were in. Use this to avoid * regenerating cells on every pixel lookup. */ int cell_x; int cell_y; /* The 3 x 3 grid of cells around the current point. */ Cell cells[9]; } Sequence; /* Generate a 3 x 3 grid of cells around a point. */ static void vips_worley_create_cells(VipsWorley *worley, Cell cells[9], int cell_x, int cell_y) { int x, y; for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) { Cell *cell = &cells[x + y * 3]; guint32 seed; int value; int j; /* Can go <0 and >width for edges. */ cell->cell_x = cell_x + x - 1; cell->cell_y = cell_y + y - 1; seed = worley->seed; /* When we calculate the seed for this cell, we wrap * around so that our output will tessellate. */ if (cell->cell_x >= worley->cells_across) value = 0; else if (cell->cell_x < 0) value = worley->cells_across - 1; else value = cell->cell_x; seed = vips__random_add(seed, value); if (cell->cell_y >= worley->cells_down) value = 0; else if (cell->cell_y < 0) value = worley->cells_down - 1; else value = cell->cell_y; seed = vips__random_add(seed, value); /* [1, MAX_FEATURES) */ cell->n_features = (seed % (MAX_FEATURES - 1)) + 1; for (j = 0; j < cell->n_features; j++) { seed = vips__random(seed); cell->feature_x[j] = cell->cell_x * worley->cell_size + seed % worley->cell_size; seed = vips__random(seed); cell->feature_y[j] = cell->cell_y * worley->cell_size + seed % worley->cell_size; } } } static int vips_worley_stop(void *vseq, void *a, void *b) { Sequence *seq = (Sequence *) vseq; VIPS_FREE(seq); return 0; } static void * vips_worley_start(VipsImage *out, void *a, void *b) { VipsWorley *worley = (VipsWorley *) b; Sequence *seq; if (!(seq = VIPS_NEW(NULL, Sequence))) return NULL; seq->worley = worley; seq->cell_x = -1; seq->cell_y = -1; return seq; } static float vips_int_hypot(int x, int y) { /* Faster than hypotf() for int args. */ return sqrtf(x * x + y * y); } static float vips_worley_distance(VipsWorley *worley, Cell cells[9], int x, int y) { float distance; int i, j; distance = worley->cell_size * 1.5; for (i = 0; i < 9; i++) { Cell *cell = &cells[i]; for (j = 0; j < cell->n_features; j++) { float d = vips_int_hypot(x - cell->feature_x[j], y - cell->feature_y[j]); distance = VIPS_MIN(distance, d); } } return distance; } static int vips_worley_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsWorley *worley = (VipsWorley *) a; VipsRect *r = &out_region->valid; Sequence *seq = (Sequence *) vseq; int x, y; for (y = 0; y < r->height; y++) { float *q = (float *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); for (x = 0; x < r->width; x++) { int cell_x = (r->left + x) / worley->cell_size; int cell_y = (r->top + y) / worley->cell_size; if (cell_x != seq->cell_x || cell_y != seq->cell_y) { vips_worley_create_cells(worley, seq->cells, cell_x, cell_y); seq->cell_x = cell_x; seq->cell_y = cell_y; } q[x] = vips_worley_distance(worley, seq->cells, r->left + x, r->top + y); } } return 0; } static int vips_worley_build(VipsObject *object) { VipsCreate *create = VIPS_CREATE(object); VipsWorley *worley = (VipsWorley *) object; if (VIPS_OBJECT_CLASS(vips_worley_parent_class)->build(object)) return -1; /* Be careful if width is a multiple of cell_size. */ worley->cells_across = VIPS_ROUND_UP(worley->width, worley->cell_size) / worley->cell_size; worley->cells_down = VIPS_ROUND_UP(worley->height, worley->cell_size) / worley->cell_size; vips_image_init_fields(create->out, worley->width, worley->height, 1, VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(create->out, vips_worley_start, vips_worley_gen, vips_worley_stop, worley, NULL)) return -1; return 0; } static void vips_worley_class_init(VipsWorleyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "worley"; vobject_class->description = _("make a worley noise image"); vobject_class->build = vips_worley_build; VIPS_ARG_INT(class, "width", 2, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsWorley, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 3, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsWorley, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "cell_size", 3, _("Cell size"), _("Size of Worley cells"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsWorley, cell_size), 1, VIPS_MAX_COORD, 256); VIPS_ARG_INT(class, "seed", 4, _("Seed"), _("Random number seed"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsWorley, seed), INT_MIN, INT_MAX, 0); } static void vips_worley_init(VipsWorley *worley) { worley->cell_size = 256; worley->seed = UINT_MAX * g_random_double(); } /** * vips_worley: * @out: (out): output image * @width: horizontal size * @height: vertical size * @...: `NULL`-terminated list of optional named arguments * * Create a one-band float image of [Worley * noise](https://en.wikipedia.org/wiki/Worley_noise). * * Use @cell_size to set the size of the cells from which the image is * constructed. The default is 256 x 256. * * If @width and @height are multiples of @cell_size, the image will tessellate. * * ::: tip "Optional arguments" * * @cell_size: `gint`, size of Worley cells * * ::: seealso * [ctor@Image.perlin], [ctor@Image.fractsurf], [ctor@Image.gaussnoise]. * * Returns: 0 on success, -1 on error */ int vips_worley(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("worley", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/xyz.c000066400000000000000000000142071516303661500172050ustar00rootroot00000000000000/* make an xy index image * * 21/4/04 * - from im_grey * 1/2/11 * - gtk-doc * 31/10/11 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pcreate.h" typedef struct _VipsXyz { VipsCreate parent_instance; int width; int height; int csize; int dsize; int esize; int dimensions; } VipsXyz; typedef VipsCreateClass VipsXyzClass; G_DEFINE_TYPE(VipsXyz, vips_xyz, VIPS_TYPE_CREATE); static int vips_xyz_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsXyz *xyz = (VipsXyz *) a; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int ri = VIPS_RECT_RIGHT(r); int bo = VIPS_RECT_BOTTOM(r); int x, y, i; for (y = to; y < bo; y++) { unsigned int *q = (unsigned int *) VIPS_REGION_ADDR(out_region, le, y); unsigned int dims[5]; int r; int h; h = xyz->height * xyz->csize * xyz->dsize; dims[4] = y / h; r = y % h; h /= xyz->dsize; dims[3] = r / h; r %= h; h /= xyz->csize; dims[2] = r / h; r %= h; dims[1] = r; for (x = le; x < ri; x++) { dims[0] = x; for (i = 0; i < xyz->dimensions; i++) q[i] = dims[i]; q += xyz->dimensions; } } return 0; } static int vips_xyz_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCreate *create = VIPS_CREATE(object); VipsXyz *xyz = (VipsXyz *) object; double d; int ysize; if (VIPS_OBJECT_CLASS(vips_xyz_parent_class)->build(object)) return -1; if ((vips_object_argument_isset(object, "dsize") && !vips_object_argument_isset(object, "csize")) || (vips_object_argument_isset(object, "esize") && !vips_object_argument_isset(object, "dsize"))) { vips_error(class->nickname, "%s", _("lower dimensions not set")); return -1; } if (vips_object_argument_isset(object, "csize")) { xyz->dimensions += 1; if (vips_object_argument_isset(object, "dsize")) { xyz->dimensions += 1; if (vips_object_argument_isset(object, "esize")) xyz->dimensions += 1; } } d = (double) xyz->height * xyz->csize * xyz->dsize * xyz->esize; if (d > INT_MAX) { vips_error(class->nickname, "%s", _("image too large")); return -1; } ysize = d; vips_image_init_fields(create->out, xyz->width, ysize, xyz->dimensions, VIPS_FORMAT_UINT, VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0); if (vips_image_pipelinev(create->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(create->out, NULL, vips_xyz_gen, NULL, xyz, NULL)) return -1; return 0; } static void vips_xyz_class_init(VipsXyzClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_xyz_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "xyz"; vobject_class->description = _("make an image where pixel values are coordinates"); vobject_class->build = vips_xyz_build; VIPS_ARG_INT(class, "width", 4, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsXyz, width), 1, VIPS_MAX_COORD, 64); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsXyz, height), 1, VIPS_MAX_COORD, 64); VIPS_ARG_INT(class, "csize", 6, _("csize"), _("Size of third dimension"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsXyz, csize), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "dsize", 7, _("dsize"), _("Size of fourth dimension"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsXyz, dsize), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "esize", 8, _("esize"), _("Size of fifth dimension"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsXyz, esize), 1, VIPS_MAX_COORD, 1); } static void vips_xyz_init(VipsXyz *xyz) { xyz->width = 64; xyz->height = 64; xyz->dimensions = 2; xyz->csize = 1; xyz->dsize = 1; xyz->esize = 1; } /** * vips_xyz: * @out: (out): output image * @width: horizontal size * @height: vertical size * @...: `NULL`-terminated list of optional named arguments * * Create a two-band uint32 image where the elements in the first band have the * value of their x coordinate and elements in the second band have their y * coordinate. * * You can make any image where the value of a pixel is a function of its (x, * y) coordinate by combining this operator with the arithmetic operators. * * Set @csize, @dsize, @esize to generate higher dimensions and add more * bands. The extra dimensions are placed down the vertical axis. Use * [method@Image.grid] to change the layout. * * ::: tip "Optional arguments" * * @csize: `gint`, size for third dimension * * @dsize: `gint`, size for fourth dimension * * @esize: `gint`, size for fifth dimension * * ::: seealso * [ctor@Image.grey], [method@Image.grid], [ctor@Image.identity]. * * Returns: 0 on success, -1 on error */ int vips_xyz(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("xyz", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/create/zone.c000066400000000000000000000054071516303661500173300ustar00rootroot00000000000000/* square zone plate of size * * N. Dessipris 01/02/1991 * * 22/7/93 JC * - externs removed * - im_outcheck() added * 30/8/95 JC * - modernized * - memory leaks fixed * - split into im_zone() and im_fzone() * 1/2/11 * - gtk-doc * 13/6/13 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pcreate.h" #include "point.h" typedef VipsPoint VipsZone; typedef VipsPointClass VipsZoneClass; G_DEFINE_TYPE(VipsZone, vips_zone, VIPS_TYPE_POINT); static float vips_zone_point(VipsPoint *point, int x, int y) { VipsZone *zone = (VipsZone *) point; int hwidth = point->width / 2; int hheight = point->height / 2; int h2 = (x - hwidth) * (x - hwidth); int v2 = (y - hheight) * (y - hheight); float c = VIPS_PI / zone->width; return cosf(c * (v2 + h2)); } static void vips_zone_class_init(VipsZoneClass *class) { VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsPointClass *point_class = VIPS_POINT_CLASS(class); vobject_class->nickname = "zone"; vobject_class->description = _("make a zone plate"); point_class->point = vips_zone_point; } static void vips_zone_init(VipsZone *zone) { } /** * vips_zone: * @out: (out): output image * @width: image size * @height: image size * @...: `NULL`-terminated list of optional named arguments * * Create a one-band image of a zone plate. * * Pixels are normally in [-1, +1], set @uchar to output [0, 255]. * * ::: tip "Optional arguments" * * @uchar: `gboolean`, output a uchar image * * ::: seealso * [ctor@Image.eye], [ctor@Image.xyz]. * * Returns: 0 on success, -1 on error */ int vips_zone(VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("zone", ap, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/deprecated/000077500000000000000000000000001516303661500170405ustar00rootroot00000000000000libvips-8.18.2/libvips/deprecated/arith_dispatch.c000066400000000000000000000660161516303661500222030ustar00rootroot00000000000000/* Function dispatch tables for arithmetic. * * J. Cupitt, 8/4/93. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Two images in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Image in, number out. */ static im_arg_desc image_in_num_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_DOUBLE("value") }; /* Args for im_recomb. */ static im_arg_desc recomb_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DMASK("matrix") }; /* Call im_recomb via arg vector. */ static int recomb_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_recomb(argv[0], argv[1], mo->mask); } /* Description of im_recomb. */ static im_function recomb_desc = { "im_recomb", /* Name */ "linear recombination with mask", IM_FN_PIO, /* Flags */ recomb_vec, /* Dispatch function */ IM_NUMBER(recomb_args), /* Size of arg list */ recomb_args /* Arg list */ }; /* Call im_abs via arg vector. */ static int abs_vec(im_object *argv) { return im_abs(argv[0], argv[1]); } /* Description of im_abs. */ static im_function abs_desc = { "im_abs", /* Name */ N_("absolute value"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ abs_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_add via arg vector. */ static int add_vec(im_object *argv) { return im_add(argv[0], argv[1], argv[2]); } /* Description of im_add. */ static im_function add_desc = { "im_add", /* Name */ N_("add two images"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ add_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_avg via arg vector. */ static int avg_vec(im_object *argv) { double f; if (im_avg(argv[0], &f)) return -1; *((double *) argv[1]) = f; return 0; } /* Description of im_avg. */ static im_function avg_desc = { "im_avg", /* Name */ N_("average value of image"), /* Description */ IM_FN_PIO, /* Flags */ avg_vec, /* Dispatch function */ IM_NUMBER(image_in_num_out), /* Size of arg list */ image_in_num_out /* Arg list */ }; /* Args to im_point. */ static im_arg_desc point_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_INTERPOLATE("interpolate"), IM_INPUT_DOUBLE("x"), IM_INPUT_DOUBLE("y"), IM_INPUT_INT("band"), IM_OUTPUT_DOUBLE("out") }; /* Call im_point via arg vector. */ static int point_vec(im_object *argv) { VipsInterpolate *interpolate = VIPS_INTERPOLATE(argv[1]); double x = *((double *) argv[2]); double y = *((double *) argv[3]); int band = *((int *) argv[4]); return im_point(argv[0], interpolate, x, y, band, argv[5]); } /* Description of im_point. */ static im_function point_desc = { "im_point", "interpolate value at single point", IM_FN_PIO, point_vec, IM_NUMBER(point_args), point_args }; /* Args to im_point_bilinear. */ static im_arg_desc point_bilinear_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_DOUBLE("x"), IM_INPUT_DOUBLE("y"), IM_INPUT_INT("band"), IM_OUTPUT_DOUBLE("val") }; /* Call im_point_bilinear via arg vector. */ static int point_bilinear_vec(im_object *argv) { return im_point_bilinear(argv[0], *(double *) argv[1], *(double *) argv[2], *(int *) argv[3], argv[4]); } /* Description of im_point_bilinear. */ static im_function point_bilinear_desc = { "im_point_bilinear", "interpolate value at single point, linearly", IM_FN_PIO, point_bilinear_vec, IM_NUMBER(point_bilinear_args), point_bilinear_args }; /* Call im_deviate via arg vector. */ static int deviate_vec(im_object *argv) { double f; if (im_deviate(argv[0], &f)) return -1; *((double *) argv[1]) = f; return 0; } /* Description of im_deviate. */ static im_function deviate_desc = { "im_deviate", /* Name */ N_("standard deviation of image"), /* Description */ IM_FN_PIO, /* Flags */ deviate_vec, /* Dispatch function */ IM_NUMBER(image_in_num_out), /* Size of arg list */ image_in_num_out /* Arg list */ }; /* Call im_exp10tra via arg vector. */ static int exp10tra_vec(im_object *argv) { return im_exp10tra(argv[0], argv[1]); } /* Description of im_exp10tra. */ static im_function exp10tra_desc = { "im_exp10tra", /* Name */ N_("10^pel of image"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ exp10tra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_exptra via arg vector. */ static int exptra_vec(im_object *argv) { return im_exptra(argv[0], argv[1]); } /* Description of im_exptra. */ static im_function exptra_desc = { "im_exptra", /* Name */ N_("e^pel of image"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ exptra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args for im_powtra(). */ static im_arg_desc powtra_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("x") }; /* Call im_expntra via arg vector. */ static int expntra_vec(im_object *argv) { double a = *((double *) argv[2]); return im_expntra(argv[0], argv[1], a); } /* Description of im_expntra. */ static im_function expntra_desc = { "im_expntra", /* Name */ N_("x^pel of image"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ expntra_vec, /* Dispatch function */ IM_NUMBER(powtra_args), /* Size of arg list */ powtra_args /* Arg list */ }; /* Args for im_expntra_vec(). */ static im_arg_desc expntra_vec_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLEVEC("v") }; /* Call im_expntra_vec() via arg vector. */ static int expntra_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_expntra_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_expntra_vec. */ static im_function expntra_vec_desc = { "im_expntra_vec", /* Name */ N_("[x,y,z]^pel of image"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ expntra_vec_vec, /* Dispatch function */ IM_NUMBER(expntra_vec_args), /* Size of arg list */ expntra_vec_args /* Arg list */ }; /* Call im_divide via arg vector. */ static int divide_vec(im_object *argv) { return im_divide(argv[0], argv[1], argv[2]); } /* Description of im_divide. */ static im_function divide_desc = { "im_divide", /* Name */ N_("divide two images"), IM_FN_PIO, /* Flags */ divide_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_invert via arg vector. */ static int invert_vec(im_object *argv) { return im_invert(argv[0], argv[1]); } /* Description of im_invert. */ static im_function invert_desc = { "im_invert", /* Name */ N_("photographic negative"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ invert_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args for im_lintra(). */ static im_arg_desc lintra_args[] = { IM_INPUT_DOUBLE("a"), IM_INPUT_IMAGE("in"), IM_INPUT_DOUBLE("b"), IM_OUTPUT_IMAGE("out") }; /* Call im_lintra() via arg vector. */ static int lintra_vec(im_object *argv) { double a = *((double *) argv[0]); double b = *((double *) argv[2]); return im_lintra(a, argv[1], b, argv[3]); } /* Description of im_lintra(). */ static im_function lintra_desc = { "im_lintra", /* Name */ N_("calculate a*in + b = outfile"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ lintra_vec, /* Dispatch function */ IM_NUMBER(lintra_args), /* Size of arg list */ lintra_args /* Arg list */ }; /* Args for im_lintra_vec(). */ static im_arg_desc lintra_vec_args[] = { IM_INPUT_DOUBLEVEC("a"), IM_INPUT_IMAGE("in"), IM_INPUT_DOUBLEVEC("b"), IM_OUTPUT_IMAGE("out") }; /* Call im_lintra_vec() via arg vector. */ static int lintra_vec_vec(im_object *argv) { im_doublevec_object *dva = (im_doublevec_object *) argv[0]; im_doublevec_object *dvb = (im_doublevec_object *) argv[2]; if (dva->n != dvb->n) { im_error("im_lintra_vec", "%s", _("vectors not equal length")); return -1; } return im_lintra_vec(dva->n, dva->vec, argv[1], dvb->vec, argv[3]); } /* Description of im_lintra_vec(). */ static im_function lintra_vec_desc = { "im_lintra_vec", /* Name */ N_("calculate a*in + b -> out, a and b vectors"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ lintra_vec_vec, /* Dispatch function */ IM_NUMBER(lintra_vec_args), /* Size of arg list */ lintra_vec_args /* Arg list */ }; /* Call im_log10tra via arg vector. */ static int log10tra_vec(im_object *argv) { return im_log10tra(argv[0], argv[1]); } /* Description of im_log10tra. */ static im_function log10tra_desc = { "im_log10tra", /* Name */ N_("log10 of image"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ log10tra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_logtra via arg vector. */ static int logtra_vec(im_object *argv) { return im_logtra(argv[0], argv[1]); } /* Description of im_logtra. */ static im_function logtra_desc = { "im_logtra", /* Name */ N_("ln of image"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ logtra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_tantra via arg vector. */ static int tantra_vec(im_object *argv) { return im_tantra(argv[0], argv[1]); } /* Description of im_tantra. */ static im_function tantra_desc = { "im_tantra", /* Name */ N_("tan of image (angles in degrees)"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ tantra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_atantra via arg vector. */ static int atantra_vec(im_object *argv) { return im_atantra(argv[0], argv[1]); } /* Description of im_atantra. */ static im_function atantra_desc = { "im_atantra", /* Name */ N_("atan of image (result in degrees)"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ atantra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_costra via arg vector. */ static int costra_vec(im_object *argv) { return im_costra(argv[0], argv[1]); } /* Description of im_costra. */ static im_function costra_desc = { "im_costra", /* Name */ N_("cos of image (angles in degrees)"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ costra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_acostra via arg vector. */ static int acostra_vec(im_object *argv) { return im_acostra(argv[0], argv[1]); } /* Description of im_acostra. */ static im_function acostra_desc = { "im_acostra", /* Name */ N_("acos of image (result in degrees)"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ acostra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_ceil via arg vector. */ static int ceil_vec(im_object *argv) { return im_ceil(argv[0], argv[1]); } /* Description of im_ceil. */ static im_function ceil_desc = { "im_ceil", /* Name */ N_("round to smallest integer value not less than"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ ceil_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_floor via arg vector. */ static int floor_vec(im_object *argv) { return im_floor(argv[0], argv[1]); } /* Description of im_floor. */ static im_function floor_desc = { "im_floor", /* Name */ N_("round to largest integer value not greater than"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ floor_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_rint via arg vector. */ static int rint_vec(im_object *argv) { return im_rint(argv[0], argv[1]); } /* Description of im_rint. */ static im_function rint_desc = { "im_rint", /* Name */ N_("round to nearest integer value"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ rint_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_sintra via arg vector. */ static int sintra_vec(im_object *argv) { return im_sintra(argv[0], argv[1]); } /* Description of im_sintra. */ static im_function sintra_desc = { "im_sintra", /* Name */ N_("sin of image (angles in degrees)"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ sintra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_bandmean via arg vector. */ static int bandmean_vec(im_object *argv) { return im_bandmean(argv[0], argv[1]); } /* Description of im_bandmean. */ static im_function bandmean_desc = { "im_bandmean", /* Name */ N_("average image bands"), IM_FN_PIO, /* Flags */ bandmean_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_sign via arg vector. */ static int sign_vec(im_object *argv) { return im_sign(argv[0], argv[1]); } /* Description of im_sign. */ static im_function sign_desc = { "im_sign", /* Name */ N_("unit vector in direction of value"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ sign_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_asintra via arg vector. */ static int asintra_vec(im_object *argv) { return im_asintra(argv[0], argv[1]); } /* Description of im_asintra. */ static im_function asintra_desc = { "im_asintra", /* Name */ N_("asin of image (result in degrees)"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ asintra_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_max via arg vector. */ static int max_vec(im_object *argv) { double f; if (im_max(argv[0], &f)) return -1; *((double *) argv[1]) = f; return 0; } /* Description of im_max. */ static im_function max_desc = { "im_max", /* Name */ N_("maximum value of image"), /* Description */ IM_FN_PIO, /* Flags */ max_vec, /* Dispatch function */ IM_NUMBER(image_in_num_out), /* Size of arg list */ image_in_num_out /* Arg list */ }; /* Args for maxpos (and minpos). */ static im_arg_desc maxpos_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_COMPLEX("position") }; /* Call im_maxpos via arg vector. */ static int maxpos_vec(im_object *argv) { double f; int x, y; if (im_maxpos(argv[0], &x, &y, &f)) return -1; ((double *) argv[1])[0] = x; ((double *) argv[1])[1] = y; return 0; } /* Description of im_maxpos. */ static im_function maxpos_desc = { "im_maxpos", /* Name */ N_("position of maximum value of image"), 0, /* Flags */ maxpos_vec, /* Dispatch function */ IM_NUMBER(maxpos_args), /* Size of arg list */ maxpos_args /* Arg list */ }; /* Args to im_maxpos_avg. */ static im_arg_desc maxpos_avg_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_DOUBLE("x"), IM_OUTPUT_DOUBLE("y"), IM_OUTPUT_DOUBLE("out") }; /* Call im_maxpos_avg via arg vector. */ static int maxpos_avg_vec(im_object *argv) { return im_maxpos_avg(argv[0], argv[1], argv[2], argv[3]); } /* Description of im_maxpos_avg. */ static im_function maxpos_avg_desc = { "im_maxpos_avg", N_("position of maximum value of image, averaging in case of draw"), IM_FN_PIO, maxpos_avg_vec, IM_NUMBER(maxpos_avg_args), maxpos_avg_args }; /* Args to im_min/maxpos_vec. */ static im_arg_desc maxpos_vec_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_INT("n"), IM_OUTPUT_INTVEC("xes"), IM_OUTPUT_INTVEC("yes"), IM_OUTPUT_DOUBLEVEC("maxima") }; /* Call im_maxpos_vec via arg vector. */ static int maxpos_vec_vec(im_object *argv) { int n = *((int *) argv[1]); im_intvec_object *xes = argv[2]; im_intvec_object *yes = argv[3]; im_doublevec_object *maxima = argv[4]; xes->vec = IM_ARRAY(NULL, n, int); xes->n = n; yes->vec = IM_ARRAY(NULL, n, int); yes->n = n; maxima->vec = IM_ARRAY(NULL, n, double); maxima->n = n; if (!xes->vec || !yes->vec || !maxima->vec || im_maxpos_vec(argv[0], xes->vec, yes->vec, maxima->vec, n)) return -1; return 0; } /* Description of im_maxpos_vec. */ static im_function maxpos_vec_desc = { "im_maxpos_vec", N_("position and value of n maxima of image"), IM_FN_PIO, maxpos_vec_vec, IM_NUMBER(maxpos_vec_args), maxpos_vec_args }; /* Call im_minpos_vec via arg vector. */ static int minpos_vec_vec(im_object *argv) { int n = *((int *) argv[1]); im_intvec_object *xes = argv[2]; im_intvec_object *yes = argv[3]; im_doublevec_object *minima = argv[4]; xes->vec = IM_ARRAY(NULL, n, int); xes->n = n; yes->vec = IM_ARRAY(NULL, n, int); yes->n = n; minima->vec = IM_ARRAY(NULL, n, double); minima->n = n; if (!xes->vec || !yes->vec || !minima->vec || im_minpos_vec(argv[0], xes->vec, yes->vec, minima->vec, n)) return -1; return 0; } /* Description of im_minpos_vec. */ static im_function minpos_vec_desc = { "im_minpos_vec", N_("position and value of n minima of image"), IM_FN_PIO, minpos_vec_vec, IM_NUMBER(maxpos_vec_args), maxpos_vec_args }; /* Args for measure. */ static im_arg_desc measure_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_DMASK("mask"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_INT("w"), IM_INPUT_INT("h"), IM_INPUT_INT("h_patches"), IM_INPUT_INT("v_patches") }; /* Call im_measure via arg vector. */ static int measure_vec(im_object *argv) { im_mask_object *mo = argv[1]; int x = *((int *) argv[2]); int y = *((int *) argv[3]); int w = *((int *) argv[4]); int h = *((int *) argv[5]); int u = *((int *) argv[6]); int v = *((int *) argv[7]); if (!(mo->mask = im_measure_area(argv[0], x, y, w, h, u, v, NULL, 0, mo->name))) { return -1; } return 0; } /* Description of im_measure. */ static im_function measure_desc = { "im_measure", /* Name */ N_("measure averages of a grid of patches"), IM_FN_PIO, /* Flags */ measure_vec, /* Dispatch function */ IM_NUMBER(measure_args), /* Size of arg list */ measure_args /* Arg list */ }; /* Call im_min via arg vector. */ static int min_vec(im_object *argv) { double f; if (im_min(argv[0], &f)) return -1; *((double *) argv[1]) = f; return 0; } /* Description of im_min. */ static im_function min_desc = { "im_min", /* Name */ N_("minimum value of image"), /* Description */ IM_FN_PIO, /* Flags */ min_vec, /* Dispatch function */ IM_NUMBER(image_in_num_out), /* Size of arg list */ image_in_num_out /* Arg list */ }; /* Call im_minpos via arg vector. */ static int minpos_vec(im_object *argv) { double f; int x, y; if (im_minpos(argv[0], &x, &y, &f)) return -1; ((double *) argv[1])[0] = x; ((double *) argv[1])[1] = y; return 0; } /* Description of im_minpos. */ static im_function minpos_desc = { "im_minpos", /* Name */ N_("position of minimum value of image"), 0, /* Flags */ minpos_vec, /* Dispatch function */ IM_NUMBER(maxpos_args), /* Size of arg list */ maxpos_args /* Arg list */ }; /* Call im_remainder via arg vector. */ static int remainder_vec(im_object *argv) { return im_remainder(argv[0], argv[1], argv[2]); } /* Description of im_remainder. */ static im_function remainder_desc = { "im_remainder", /* Name */ N_("remainder after integer division"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ remainder_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_remainderconst via arg vector. */ static int remainderconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_remainderconst(argv[0], argv[1], c); } /* Args for im_remainderconst(). */ static im_arg_desc remainderconst_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("x") }; /* Description of im_remainderconst. */ static im_function remainderconst_desc = { "im_remainderconst", /* Name */ N_("remainder after integer division by a constant"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ remainderconst_vec, /* Dispatch function */ IM_NUMBER(remainderconst_args), /* Size of arg list */ remainderconst_args /* Arg list */ }; /* Call im_remainder_vec via arg vector. */ static int remainder_vec_vec(im_object *argv) { im_doublevec_object *dv = (im_doublevec_object *) argv[2]; return im_remainder_vec(argv[0], argv[1], dv->n, dv->vec); } /* Args for im_remainder_vec(). */ static im_arg_desc remainder_vec_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLEVEC("x") }; /* Description of im_remainder_vec. */ static im_function remainder_vec_desc = { "im_remainder_vec", /* Name */ N_("remainder after integer division by a vector of constants"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ remainder_vec_vec, /* Dispatch function */ IM_NUMBER(remainder_vec_args), /* Size of arg list */ remainder_vec_args /* Arg list */ }; /* Call im_multiply via arg vector. */ static int multiply_vec(im_object *argv) { return im_multiply(argv[0], argv[1], argv[2]); } /* Description of im_multiply. */ static im_function multiply_desc = { "im_multiply", /* Name */ N_("multiply two images"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ multiply_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_powtra() via arg vector. */ static int powtra_vec(im_object *argv) { double a = *((double *) argv[2]); return im_powtra(argv[0], argv[1], a); } /* Description of im_powtra(). */ static im_function powtra_desc = { "im_powtra", /* Name */ N_("pel^x of image"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ powtra_vec, /* Dispatch function */ IM_NUMBER(powtra_args), /* Size of arg list */ powtra_args /* Arg list */ }; /* Call im_powtra_vec() via arg vector. */ static int powtra_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_powtra_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_powtra_vec(). */ static im_function powtra_vec_desc = { "im_powtra_vec", /* Name */ N_("pel^[x,y,z] of image"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ powtra_vec_vec, /* Dispatch function */ IM_NUMBER(expntra_vec_args), /* Size of arg list */ expntra_vec_args /* Arg list */ }; /* Args for im_stats. */ static im_arg_desc stats_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_DMASK_STATS("statistics") }; /* Call im_stats() via arg vector. */ static int stats_vec(im_object *argv) { im_mask_object *mo = argv[1]; if (!(mo->mask = im_stats(argv[0]))) return -1; return 0; } /* Description of im_stats(). */ static im_function stats_desc = { "im_stats", /* Name */ N_("many image statistics in one pass"), IM_FN_PIO, /* Flags */ stats_vec, /* Dispatch function */ IM_NUMBER(stats_args), /* Size of arg list */ stats_args /* Arg list */ }; /* Call im_subtract via arg vector. */ static int subtract_vec(im_object *argv) { return im_subtract(argv[0], argv[1], argv[2]); } /* Description of im_subtract. */ static im_function subtract_desc = { "im_subtract", /* Name */ N_("subtract two images"), /* Description */ IM_FN_PIO, /* Flags */ subtract_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Args for im_linreg. */ static im_arg_desc linreg_args[] = { IM_INPUT_IMAGEVEC("ins"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLEVEC("xs") }; /* Call im_linreg() via arg vector. */ static int linreg_vec(im_object *argv) { #define FUNCTION_NAME "im_linreg_vec" im_imagevec_object *ins_vec = (im_imagevec_object *) argv[0]; im_doublevec_object *xs_vec = (im_doublevec_object *) argv[2]; IMAGE *out = (IMAGE *) argv[1]; IMAGE **ins = IM_ARRAY(out, ins_vec->n + 1, IMAGE *); int i; if (!ins) return -1; for (i = 0; i < ins_vec->n; ++i) ins[i] = ins_vec->vec[i]; ins[ins_vec->n] = NULL; if (xs_vec->n != ins_vec->n) { im_error(FUNCTION_NAME, "image vector and x vector differ in length"); return -1; } return im_linreg(ins, out, xs_vec->vec); #undef FUNCTION_NAME } /* Description of im_linreg(). */ static im_function linreg_desc = { "im_linreg", /* Name */ N_("pixelwise linear regression"), IM_FN_PIO | IM_FN_PTOP, /* Flags */ linreg_vec, /* Dispatch function */ IM_NUMBER(linreg_args), /* Size of arg list */ linreg_args /* Arg list */ }; /* Call im_cross_phase via arg vector. */ static int cross_phase_vec(im_object *argv) { return im_cross_phase(argv[0], argv[1], argv[2]); } /* Description of im_cross_phase. */ static im_function cross_phase_desc = { "im_cross_phase", /* Name */ N_("phase of cross power spectrum of two complex images"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ cross_phase_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Package up all these functions. */ static im_function *arith_list[] = { &abs_desc, &acostra_desc, &add_desc, &asintra_desc, &atantra_desc, &avg_desc, &point_desc, &point_bilinear_desc, &bandmean_desc, &ceil_desc, &costra_desc, &cross_phase_desc, &deviate_desc, ÷_desc, &exp10tra_desc, &expntra_desc, &expntra_vec_desc, &exptra_desc, &floor_desc, &invert_desc, &lintra_desc, &linreg_desc, &lintra_vec_desc, &log10tra_desc, &logtra_desc, &max_desc, &maxpos_desc, &maxpos_avg_desc, &maxpos_vec_desc, &measure_desc, &min_desc, &minpos_desc, &minpos_vec_desc, &multiply_desc, &powtra_desc, &powtra_vec_desc, &recomb_desc, &remainder_desc, &remainderconst_desc, &remainder_vec_desc, &rint_desc, &sign_desc, &sintra_desc, &stats_desc, &subtract_desc, &tantra_desc }; /* Package of functions. */ im_package im__arithmetic = { "arithmetic", IM_NUMBER(arith_list), arith_list }; libvips-8.18.2/libvips/deprecated/cimg_dispatch.c000066400000000000000000000102231516303661500220000ustar00rootroot00000000000000/* Function dispatch tables for cimg wrappers. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include static int greyc_vec(im_object *argv) { IMAGE *src = (IMAGE *) argv[0]; IMAGE *dst = (IMAGE *) argv[1]; int iterations = *((int *) argv[2]); double amplitude = *((double *) argv[3]); double sharpness = *((double *) argv[4]); double anisotropy = *((double *) argv[5]); double alpha = *((double *) argv[6]); double sigma = *((double *) argv[7]); double dl = *((double *) argv[8]); double da = *((double *) argv[9]); double gauss_prec = *((double *) argv[10]); int interpolation = *((int *) argv[11]); int fast_approx = *((int *) argv[12]); if (im_greyc_mask(src, dst, NULL, iterations, amplitude, sharpness, anisotropy, alpha, sigma, dl, da, gauss_prec, interpolation, fast_approx)) return -1; return 0; } static im_arg_desc greyc_arg_types[] = { IM_INPUT_IMAGE("src"), IM_OUTPUT_IMAGE("dst"), IM_INPUT_INT("iterations"), IM_INPUT_DOUBLE("amplitude"), IM_INPUT_DOUBLE("sharpness"), IM_INPUT_DOUBLE("anisotropy"), IM_INPUT_DOUBLE("alpha"), IM_INPUT_DOUBLE("sigma"), IM_INPUT_DOUBLE("dl"), IM_INPUT_DOUBLE("da"), IM_INPUT_DOUBLE("gauss_prec"), IM_INPUT_INT("interpolation"), IM_INPUT_INT("fast_approx") }; static im_function greyc_desc = { "im_greyc", /* Name */ "noise-removing filter", /* Description */ (im_fn_flags) (IM_FN_TRANSFORM | IM_FN_PIO), /* Flags */ greyc_vec, /* Dispatch function */ IM_NUMBER(greyc_arg_types), /* Size of arg list */ greyc_arg_types /* Arg list */ }; static int greyc_mask_vec(im_object *argv) { IMAGE *src = (IMAGE *) argv[0]; IMAGE *dst = (IMAGE *) argv[1]; IMAGE *mask = (IMAGE *) argv[2]; int iterations = *((int *) argv[3]); double amplitude = *((double *) argv[4]); double sharpness = *((double *) argv[5]); double anisotropy = *((double *) argv[6]); double alpha = *((double *) argv[7]); double sigma = *((double *) argv[8]); double dl = *((double *) argv[9]); double da = *((double *) argv[10]); double gauss_prec = *((double *) argv[11]); int interpolation = *((int *) argv[12]); int fast_approx = *((int *) argv[13]); if (im_greyc_mask(src, dst, mask, iterations, amplitude, sharpness, anisotropy, alpha, sigma, dl, da, gauss_prec, interpolation, fast_approx)) return -1; return 0; } static im_arg_desc greyc_mask_arg_types[] = { IM_INPUT_IMAGE("src"), IM_OUTPUT_IMAGE("dst"), IM_INPUT_IMAGE("mask"), IM_INPUT_INT("iterations"), IM_INPUT_DOUBLE("amplitude"), IM_INPUT_DOUBLE("sharpness"), IM_INPUT_DOUBLE("anisotropy"), IM_INPUT_DOUBLE("alpha"), IM_INPUT_DOUBLE("sigma"), IM_INPUT_DOUBLE("dl"), IM_INPUT_DOUBLE("da"), IM_INPUT_DOUBLE("gauss_prec"), IM_INPUT_INT("interpolation"), IM_INPUT_INT("fast_approx") }; static im_function greyc_mask_desc = { "im_greyc_mask", /* Name */ "noise-removing filter, with a mask", /* Description */ (im_fn_flags) (IM_FN_TRANSFORM | IM_FN_PIO), /* Flags */ greyc_mask_vec, /* Dispatch function */ IM_NUMBER(greyc_mask_arg_types), /* Size of arg list */ greyc_mask_arg_types /* Arg list */ }; static im_function *function_list[] = { &greyc_desc, &greyc_mask_desc }; /* Package of functions. */ im_package im__cimg = { "cimg", IM_NUMBER(function_list), function_list }; libvips-8.18.2/libvips/deprecated/colour_dispatch.c000066400000000000000000000564201516303661500223750ustar00rootroot00000000000000/* Function dispatch tables for arithmetic. * * J. Cupitt, 8/4/93. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Two images in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Call im_sRGB2XYZ via arg vector. */ static int sRGB2XYZ_vec(im_object *argv) { return im_sRGB2XYZ(argv[0], argv[1]); } /* Description of im_sRGB2XYZ. */ static im_function sRGB2XYZ_desc = { "im_sRGB2XYZ", /* Name */ "convert sRGB to XYZ", /* Description */ IM_FN_PIO, /* Flags */ sRGB2XYZ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_XYZ2sRGB via arg vector. */ static int XYZ2sRGB_vec(im_object *argv) { return im_XYZ2sRGB(argv[0], argv[1]); } /* Description of im_XYZ2sRGB. */ static im_function XYZ2sRGB_desc = { "im_XYZ2sRGB", /* Name */ "convert XYZ to sRGB", /* Description */ IM_FN_PIO, /* Flags */ XYZ2sRGB_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LCh2Lab via arg vector. */ static int LCh2Lab_vec(im_object *argv) { return im_LCh2Lab(argv[0], argv[1]); } /* Description of im_LCh2Lab. */ static im_function LCh2Lab_desc = { "im_LCh2Lab", /* Name */ "convert LCh to Lab", /* Description */ IM_FN_PIO, /* Flags */ LCh2Lab_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LabQ2XYZ via arg vector. */ static int LabQ2XYZ_vec(im_object *argv) { return im_LabQ2XYZ(argv[0], argv[1]); } /* Description of im_LabQ2XYZ. */ static im_function LabQ2XYZ_desc = { "im_LabQ2XYZ", /* Name */ "convert LabQ to XYZ", /* Description */ IM_FN_PIO, /* Flags */ LabQ2XYZ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LCh2UCS via arg vector. */ static int LCh2UCS_vec(im_object *argv) { return im_LCh2UCS(argv[0], argv[1]); } /* Description of im_LCh2UCS. */ static im_function LCh2UCS_desc = { "im_LCh2UCS", /* Name */ "convert LCh to UCS", /* Description */ IM_FN_PIO, /* Flags */ LCh2UCS_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_Lab2LCh via arg vector. */ static int Lab2LCh_vec(im_object *argv) { return im_Lab2LCh(argv[0], argv[1]); } /* Description of im_Lab2LCh. */ static im_function Lab2LCh_desc = { "im_Lab2LCh", /* Name */ "convert Lab to LCh", /* Description */ IM_FN_PIO, /* Flags */ Lab2LCh_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_Lab2LabQ() via arg vector. */ static int Lab2LabQ_vec(im_object *argv) { return im_Lab2LabQ(argv[0], argv[1]); } /* Description of im_Lab2LabQ. */ static im_function Lab2LabQ_desc = { "im_Lab2LabQ", /* Name */ "convert Lab to LabQ", /* Description */ IM_FN_PIO, /* Flags */ Lab2LabQ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_Lab2XYZ() via arg vector. */ static int Lab2XYZ_vec(im_object *argv) { return im_Lab2XYZ(argv[0], argv[1]); } /* Description of im_Lab2XYZ. */ static im_function Lab2XYZ_desc = { "im_Lab2XYZ", /* Name */ "convert D65 Lab to XYZ", /* Description */ IM_FN_PIO, /* Flags */ Lab2XYZ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; static int icc_present_vec(im_object *argv) { int *present = ((int *) argv[0]); *present = im_icc_present(); return 0; } static im_arg_desc icc_present_args[] = { IM_OUTPUT_INT("present") }; /* Description of im_icc_present. */ static im_function icc_present_desc = { "im_icc_present", /* Name */ "test for presence of ICC library", /* Description */ 0, /* Flags */ icc_present_vec, /* Dispatch function */ IM_NUMBER(icc_present_args), /* Size of arg list */ icc_present_args /* Arg list */ }; static int icc_transform_vec(im_object *argv) { int intent = *((int *) argv[4]); return im_icc_transform(argv[0], argv[1], argv[2], argv[3], intent); } static im_arg_desc icc_transform_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("input_profile"), IM_INPUT_STRING("output_profile"), IM_INPUT_INT("intent") }; /* Description of im_icc_transform. */ static im_function icc_transform_desc = { "im_icc_transform", /* Name */ "convert between two device images with a pair of ICC profiles", /* Description */ IM_FN_PIO, /* Flags */ icc_transform_vec, /* Dispatch function */ IM_NUMBER(icc_transform_args), /* Size of arg list */ icc_transform_args /* Arg list */ }; static int icc_import_embedded_vec(im_object *argv) { int intent = *((int *) argv[2]); return im_icc_import_embedded(argv[0], argv[1], intent); } static im_arg_desc icc_import_embedded_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("intent") }; /* Description of im_icc_import_embedded. */ static im_function icc_import_embedded_desc = { "im_icc_import_embedded", /* Name */ "convert a device image to float LAB using the embedded profile", /* Description */ IM_FN_PIO, /* Flags */ icc_import_embedded_vec, /* Dispatch function */ IM_NUMBER(icc_import_embedded_args), /* Size of arg list */ icc_import_embedded_args /* Arg list */ }; static int icc_import_vec(im_object *argv) { int intent = *((int *) argv[3]); return im_icc_import(argv[0], argv[1], argv[2], intent); } static im_arg_desc icc_import_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("input_profile"), IM_INPUT_INT("intent") }; /* Description of im_icc_import. */ static im_function icc_import_desc = { "im_icc_import", /* Name */ "convert a device image to float LAB with an ICC profile", /* Description */ IM_FN_PIO, /* Flags */ icc_import_vec, /* Dispatch function */ IM_NUMBER(icc_import_args), /* Size of arg list */ icc_import_args /* Arg list */ }; static int icc_export_depth_vec(im_object *argv) { int intent = *((int *) argv[4]); int depth = *((int *) argv[2]); return im_icc_export_depth(argv[0], argv[1], depth, argv[3], intent); } static im_arg_desc icc_export_depth_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("depth"), IM_INPUT_STRING("output_profile"), IM_INPUT_INT("intent") }; /* Description of im_icc_export_depth. */ static im_function icc_export_depth_desc = { "im_icc_export_depth", /* Name */ "convert a float LAB to device space with an ICC profile", /* Description */ IM_FN_PIO, /* Flags */ icc_export_depth_vec, /* Dispatch function */ IM_NUMBER(icc_export_depth_args), /* Size of arg list */ icc_export_depth_args /* Arg list */ }; static int icc_ac2rc_vec(im_object *argv) { return im_icc_ac2rc(argv[0], argv[1], argv[2]); } static im_arg_desc icc_ac2rc_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("profile") }; /* Description of im_icc_ac2rc. */ static im_function icc_ac2rc_desc = { "im_icc_ac2rc", /* Name */ "convert LAB from AC to RC using an ICC profile", /* Description */ IM_FN_PIO, /* Flags */ icc_ac2rc_vec, /* Dispatch function */ IM_NUMBER(icc_ac2rc_args), /* Size of arg list */ icc_ac2rc_args /* Arg list */ }; static int Lab2XYZ_temp_vec(im_object *argv) { double X0 = *((double *) argv[2]); double Y0 = *((double *) argv[3]); double Z0 = *((double *) argv[4]); return im_Lab2XYZ_temp(argv[0], argv[1], X0, Y0, Z0); } static im_arg_desc temp_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("X0"), IM_INPUT_DOUBLE("Y0"), IM_INPUT_DOUBLE("Z0") }; /* Description of im_Lab2XYZ_temp. */ static im_function Lab2XYZ_temp_desc = { "im_Lab2XYZ_temp", /* Name */ "convert Lab to XYZ, with a specified colour temperature", /* Description */ IM_FN_PIO, /* Flags */ Lab2XYZ_temp_vec, /* Dispatch function */ IM_NUMBER(temp_args), /* Size of arg list */ temp_args /* Arg list */ }; /* Call im_Lab2UCS() via arg vector. */ static int Lab2UCS_vec(im_object *argv) { return im_Lab2UCS(argv[0], argv[1]); } /* Description of im_Lab2UCS. */ static im_function Lab2UCS_desc = { "im_Lab2UCS", /* Name */ "convert Lab to UCS", /* Description */ IM_FN_PIO, /* Flags */ Lab2UCS_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LabQ2Lab() via arg vector. */ static int LabQ2Lab_vec(im_object *argv) { return im_LabQ2Lab(argv[0], argv[1]); } /* Description of im_LabQ2Lab. */ static im_function LabQ2Lab_desc = { "im_LabQ2Lab", /* Name */ "convert LabQ to Lab", /* Description */ IM_FN_PIO, /* Flags */ LabQ2Lab_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_rad2float() via arg vector. */ static int rad2float_vec(im_object *argv) { return im_rad2float(argv[0], argv[1]); } /* Description of im_rad2float. */ static im_function rad2float_desc = { "im_rad2float", /* Name */ "convert Radiance packed to float", /* Description */ IM_FN_PIO, /* Flags */ rad2float_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_float2rad() via arg vector. */ static int float2rad_vec(im_object *argv) { return im_float2rad(argv[0], argv[1]); } /* Description of im_float2rad */ static im_function float2rad_desc = { "im_float2rad", /* Name */ "convert float to Radiance packed", /* Description */ IM_FN_PIO, /* Flags */ float2rad_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LabQ2LabS() via arg vector. */ static int LabQ2LabS_vec(im_object *argv) { return im_LabQ2LabS(argv[0], argv[1]); } /* Description of im_LabQ2LabS. */ static im_function LabQ2LabS_desc = { "im_LabQ2LabS", /* Name */ "convert LabQ to LabS", /* Description */ IM_FN_PIO, /* Flags */ LabQ2LabS_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_Lab2LabS() via arg vector. */ static int Lab2LabS_vec(im_object *argv) { return im_Lab2LabS(argv[0], argv[1]); } /* Description of im_Lab2LabS. */ static im_function Lab2LabS_desc = { "im_Lab2LabS", /* Name */ "convert Lab to LabS", /* Description */ IM_FN_PIO, /* Flags */ Lab2LabS_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LabS2Lab() via arg vector. */ static int LabS2Lab_vec(im_object *argv) { return im_LabS2Lab(argv[0], argv[1]); } /* Description of im_LabS2Lab. */ static im_function LabS2Lab_desc = { "im_LabS2Lab", /* Name */ "convert LabS to Lab", /* Description */ IM_FN_PIO, /* Flags */ LabS2Lab_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_LabS2LabQ() via arg vector. */ static int LabS2LabQ_vec(im_object *argv) { return im_LabS2LabQ(argv[0], argv[1]); } /* Description of im_LabS2LabQ. */ static im_function LabS2LabQ_desc = { "im_LabS2LabQ", /* Name */ "convert LabS to LabQ", /* Description */ IM_FN_PIO, /* Flags */ LabS2LabQ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_UCS2XYZ() via arg vector. */ static int UCS2XYZ_vec(im_object *argv) { return im_UCS2XYZ(argv[0], argv[1]); } /* Description of im_UCS2XYZ. */ static im_function UCS2XYZ_desc = { "im_UCS2XYZ", /* Name */ "convert UCS to XYZ", /* Description */ IM_FN_PIO, /* Flags */ UCS2XYZ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_UCS2LCh() via arg vector. */ static int UCS2LCh_vec(im_object *argv) { return im_UCS2LCh(argv[0], argv[1]); } /* Description of im_UCS2LCh. */ static im_function UCS2LCh_desc = { "im_UCS2LCh", /* Name */ "convert UCS to LCh", /* Description */ IM_FN_PIO, /* Flags */ UCS2LCh_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_UCS2Lab() via arg vector. */ static int UCS2Lab_vec(im_object *argv) { return im_UCS2Lab(argv[0], argv[1]); } /* Description of im_UCS2Lab. */ static im_function UCS2Lab_desc = { "im_UCS2Lab", /* Name */ "convert UCS to Lab", /* Description */ IM_FN_PIO, /* Flags */ UCS2Lab_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_Yxy2XYZ via arg vector. */ static int Yxy2XYZ_vec(im_object *argv) { return im_Yxy2XYZ(argv[0], argv[1]); } /* Description of im_Yxy2XYZ. */ static im_function Yxy2XYZ_desc = { "im_Yxy2XYZ", /* Name */ "convert Yxy to XYZ", /* Description */ IM_FN_PIO, /* Flags */ Yxy2XYZ_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_XYZ2Yxy via arg vector. */ static int XYZ2Yxy_vec(im_object *argv) { return im_XYZ2Yxy(argv[0], argv[1]); } /* Description of im_XYZ2Yxy. */ static im_function XYZ2Yxy_desc = { "im_XYZ2Yxy", /* Name */ "convert XYZ to Yxy", /* Description */ IM_FN_PIO, /* Flags */ XYZ2Yxy_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_XYZ2Lab via arg vector. */ static int XYZ2Lab_vec(im_object *argv) { return im_XYZ2Lab(argv[0], argv[1]); } /* Description of im_XYZ2Lab. */ static im_function XYZ2Lab_desc = { "im_XYZ2Lab", /* Name */ "convert D65 XYZ to Lab", /* Description */ IM_FN_PIO, /* Flags */ XYZ2Lab_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; static int XYZ2Lab_temp_vec(im_object *argv) { double X0 = *((double *) argv[2]); double Y0 = *((double *) argv[3]); double Z0 = *((double *) argv[4]); return im_XYZ2Lab_temp(argv[0], argv[1], X0, Y0, Z0); } /* Description of im_XYZ2Lab_temp. */ static im_function XYZ2Lab_temp_desc = { "im_XYZ2Lab_temp", /* Name */ "convert XYZ to Lab, with a specified colour temperature", /* Description */ IM_FN_PIO, /* Flags */ XYZ2Lab_temp_vec, /* Dispatch function */ IM_NUMBER(temp_args), /* Size of arg list */ temp_args /* Arg list */ }; /* Call im_XYZ2UCS() via arg vector. */ static int XYZ2UCS_vec(im_object *argv) { return im_XYZ2UCS(argv[0], argv[1]); } /* Description of im_XYZ2UCS. */ static im_function XYZ2UCS_desc = { "im_XYZ2UCS", /* Name */ "convert XYZ to UCS", /* Description */ IM_FN_PIO, /* Flags */ XYZ2UCS_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args to XYZ2disp and disp2XYZ. */ static im_arg_desc XYZ2disp_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DISPLAY("disp") }; /* Call im_XYZ2disp() via arg vector. */ static int XYZ2disp_vec(im_object *argv) { return im_XYZ2disp(argv[0], argv[1], argv[2]); } /* Description of im_XYZ2disp. */ static im_function XYZ2disp_desc = { "im_XYZ2disp", /* Name */ "convert XYZ to displayble", /* Description */ IM_FN_PIO, /* Flags */ XYZ2disp_vec, /* Dispatch function */ IM_NUMBER(XYZ2disp_args), /* Size of arg list */ XYZ2disp_args /* Arg list */ }; /* Call im_Lab2disp() via arg vector. */ static int Lab2disp_vec(im_object *argv) { return im_Lab2disp(argv[0], argv[1], argv[2]); } /* Description of im_Lab2disp. */ static im_function Lab2disp_desc = { "im_Lab2disp", /* Name */ "convert Lab to displayable", /* Description */ IM_FN_PIO, /* Flags */ Lab2disp_vec, /* Dispatch function */ IM_NUMBER(XYZ2disp_args), /* Size of arg list */ XYZ2disp_args /* Arg list */ }; /* Call im_LabQ2disp() via arg vector. */ static int LabQ2disp_vec(im_object *argv) { return im_LabQ2disp(argv[0], argv[1], argv[2]); } /* Description of im_LabQ2disp. */ static im_function LabQ2disp_desc = { "im_LabQ2disp", /* Name */ "convert LabQ to displayable", /* Description */ IM_FN_PIO, /* Flags */ LabQ2disp_vec, /* Dispatch function */ IM_NUMBER(XYZ2disp_args), /* Size of arg list */ XYZ2disp_args /* Arg list */ }; /* Call im_dE00_fromLab() via arg vector. */ static int dE00_fromLab_vec(im_object *argv) { return im_dE00_fromLab(argv[0], argv[1], argv[2]); } /* Description of im_dE00_fromLab. */ static im_function dE00_fromLab_desc = { "im_dE00_fromLab", /* Name */ "calculate delta-E CIE2000 for two Lab images", IM_FN_PIO, /* Flags */ dE00_fromLab_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_dECMC_fromLab() via arg vector. */ static int dECMC_fromLab_vec(im_object *argv) { return im_dECMC_fromLab(argv[0], argv[1], argv[2]); } /* Description of im_dECMC_fromLab. */ static im_function dECMC_fromLab_desc = { "im_dECMC_fromLab", /* Name */ "calculate delta-E CMC(1:1) for two Lab images", IM_FN_PIO, /* Flags */ dECMC_fromLab_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_dE_fromXYZ() via arg vector. */ static int dE_fromXYZ_vec(im_object *argv) { return im_dE_fromXYZ(argv[0], argv[1], argv[2]); } /* Description of im_dE_fromXYZ. */ static im_function dE_fromXYZ_desc = { "im_dE_fromXYZ", /* Name */ "calculate delta-E for two XYZ images", IM_FN_PIO, /* Flags */ dE_fromXYZ_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_dE_fromLab() via arg vector. */ static int dE_fromLab_vec(im_object *argv) { return im_dE_fromLab(argv[0], argv[1], argv[2]); } /* Description of im_dE_fromLab. */ static im_function dE_fromLab_desc = { "im_dE_fromLab", /* Name */ "calculate delta-E for two Lab images", IM_FN_PIO, /* Flags */ dE_fromLab_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Two images in, one out. */ static im_arg_desc dE_fromdisp_args[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DISPLAY("disp") }; /* Call im_dE_fromdisp() via arg vector. */ static int dE_fromdisp_vec(im_object *argv) { return im_dE_fromdisp(argv[0], argv[1], argv[2], argv[3]); } /* Description of im_dE_fromdisp. */ static im_function dE_fromdisp_desc = { "im_dE_fromdisp", /* Name */ "calculate delta-E for two displayable images", IM_FN_PIO, /* Flags */ dE_fromdisp_vec, /* Dispatch function */ IM_NUMBER(dE_fromdisp_args), /* Size of arg list */ dE_fromdisp_args /* Arg list */ }; /* Call im_dECMC_fromdisp() via arg vector. */ static int dECMC_fromdisp_vec(im_object *argv) { return im_dECMC_fromdisp(argv[0], argv[1], argv[2], argv[3]); } /* Description of im_dECMC_fromdisp. */ static im_function dECMC_fromdisp_desc = { "im_dECMC_fromdisp", /* Name */ "calculate delta-E CMC(1:1) for two displayable images", IM_FN_PIO, /* Flags */ dECMC_fromdisp_vec, /* Dispatch function */ IM_NUMBER(dE_fromdisp_args), /* Size of arg list */ dE_fromdisp_args /* Arg list */ }; /* Call im_disp2XYZ() via arg vector. */ static int disp2XYZ_vec(im_object *argv) { return im_disp2XYZ(argv[0], argv[1], argv[2]); } /* Description of im_disp2XYZ. */ static im_function disp2XYZ_desc = { "im_disp2XYZ", /* Name */ "convert displayable to XYZ", /* Description */ IM_FN_PIO, /* Flags */ disp2XYZ_vec, /* Dispatch function */ IM_NUMBER(XYZ2disp_args), /* Size of arg list */ XYZ2disp_args /* Arg list */ }; /* Call im_disp2Lab() via arg vector. */ static int disp2Lab_vec(im_object *argv) { return im_disp2Lab(argv[0], argv[1], argv[2]); } /* Description of im_disp2Lab. */ static im_function disp2Lab_desc = { "im_disp2Lab", /* Name */ "convert displayable to Lab", /* Description */ IM_FN_PIO, /* Flags */ disp2Lab_vec, /* Dispatch function */ IM_NUMBER(XYZ2disp_args), /* Size of arg list */ XYZ2disp_args /* Arg list */ }; static im_arg_desc morph_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DMASK("greyscale"), IM_INPUT_DOUBLE("L_offset"), IM_INPUT_DOUBLE("L_scale"), IM_INPUT_DOUBLE("a_scale"), IM_INPUT_DOUBLE("b_scale") }; static int morph_vec(im_object *argv) { im_mask_object *mo = argv[2]; double L_offset = *((double *) argv[3]); double L_scale = *((double *) argv[4]); double a_scale = *((double *) argv[5]); double b_scale = *((double *) argv[6]); return im_lab_morph(argv[0], argv[1], mo->mask, L_offset, L_scale, a_scale, b_scale); } static im_function morph_desc = { "im_lab_morph", /* Name */ "morph colourspace of a LAB image", IM_FN_PIO | IM_FN_PTOP, /* Flags */ morph_vec, /* Dispatch function */ IM_NUMBER(morph_args), /* Size of arg list */ morph_args /* Arg list */ }; /* Package up all these functions. */ static im_function *colour_list[] = { &LCh2Lab_desc, &LCh2UCS_desc, &Lab2LCh_desc, &Lab2LabQ_desc, &Lab2LabS_desc, &Lab2UCS_desc, &Lab2XYZ_desc, &Lab2XYZ_temp_desc, &Lab2disp_desc, &LabQ2LabS_desc, &LabQ2Lab_desc, &LabQ2XYZ_desc, &LabQ2disp_desc, &LabS2LabQ_desc, &LabS2Lab_desc, &UCS2LCh_desc, &UCS2Lab_desc, &UCS2XYZ_desc, &XYZ2Lab_desc, &XYZ2Lab_temp_desc, &XYZ2UCS_desc, &XYZ2Yxy_desc, &XYZ2disp_desc, &XYZ2sRGB_desc, &Yxy2XYZ_desc, &dE00_fromLab_desc, &dECMC_fromLab_desc, &dECMC_fromdisp_desc, &dE_fromLab_desc, &dE_fromXYZ_desc, &dE_fromdisp_desc, &disp2Lab_desc, &disp2XYZ_desc, &float2rad_desc, &icc_ac2rc_desc, &icc_export_depth_desc, &icc_import_desc, &icc_import_embedded_desc, &icc_present_desc, &icc_transform_desc, &morph_desc, &rad2float_desc, &sRGB2XYZ_desc }; /* Package of functions. */ im_package im__colour = { "colour", IM_NUMBER(colour_list), colour_list }; libvips-8.18.2/libvips/deprecated/conver_dispatch.c000066400000000000000000000724271516303661500223730ustar00rootroot00000000000000/* VIPS function dispatch tables for conversion. * * J. Cupitt, 8/4/93. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include static int system_vec(im_object *argv) { IMAGE *in = argv[0]; char *cmd = argv[1]; char **out = (char **) &argv[2]; if (im_system(in, cmd, out)) return -1; return 0; } static im_arg_desc system_args[] = { IM_INPUT_IMAGE("im"), IM_INPUT_STRING("command"), IM_OUTPUT_STRING("output") }; static im_function system_desc = { "im_system", /* Name */ "run command on image", /* Description */ 0, /* Flags */ system_vec, /* Dispatch function */ IM_NUMBER(system_args), /* Size of arg list */ system_args /* Arg list */ }; static int system_image_vec(im_object *argv) { IMAGE *in = argv[0]; IMAGE *out = argv[1]; char *in_format = argv[2]; char *out_format = argv[3]; char *cmd = argv[4]; char **log = (char **) &argv[5]; IMAGE *out_image; if (!(out_image = im_system_image(in, in_format, out_format, cmd, log))) { im_error("im_system_image", "%s", *log); return -1; } if (im_copy(out_image, out) || im_add_close_callback(out, (im_callback_fn) im_close, out_image, NULL)) { im_close(out_image); return -1; } return 0; } static im_arg_desc system_image_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("in_format"), IM_INPUT_STRING("out_format"), IM_INPUT_STRING("command"), IM_OUTPUT_STRING("log") }; static im_function system_image_desc = { "im_system_image", /* Name */ "run command on image, with image output", /* Description */ 0, /* Flags */ system_image_vec, /* Dispatch function */ IM_NUMBER(system_image_args), /* Size of arg list */ system_image_args /* Arg list */ }; static int subsample_vec(im_object *argv) { IMAGE *in = argv[0]; IMAGE *out = argv[1]; int xsh = *((int *) argv[2]); int ysh = *((int *) argv[3]); if (im_subsample(in, out, xsh, ysh)) return -1; return 0; } static im_arg_desc subsample_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xshrink"), IM_INPUT_INT("yshrink") }; static im_function subsample_desc = { "im_subsample", /* Name */ "subsample image by integer factors", /* Description */ IM_FN_PIO, /* Flags */ subsample_vec, /* Dispatch function */ IM_NUMBER(subsample_args), /* Size of arg list */ subsample_args /* Arg list */ }; /* Args for im_gaussnoise. */ static im_arg_desc gaussnoise_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xsize"), IM_INPUT_INT("ysize"), IM_INPUT_DOUBLE("mean"), IM_INPUT_DOUBLE("sigma") }; /* Call im_gaussnoise via arg vector. */ static int gaussnoise_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); double mean = *((double *) argv[3]); double sigma = *((double *) argv[4]); if (im_gaussnoise(argv[0], xsize, ysize, mean, sigma)) return -1; return 0; } /* Description of im_gaussnoise. */ static im_function gaussnoise_desc = { "im_gaussnoise", /* Name */ "generate image of gaussian noise with specified statistics", IM_FN_PIO | IM_FN_NOCACHE, /* Flags */ gaussnoise_vec, /* Dispatch function */ IM_NUMBER(gaussnoise_args), /* Size of arg list */ gaussnoise_args /* Arg list */ }; /* Args to im_extract. */ static im_arg_desc extract_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("left"), IM_INPUT_INT("top"), IM_INPUT_INT("width"), IM_INPUT_INT("height"), IM_INPUT_INT("band") }; /* Call im_extract via arg vector. */ static int extract_vec(im_object *argv) { int left = *((int *) argv[2]); int top = *((int *) argv[3]); int width = *((int *) argv[4]); int height = *((int *) argv[5]); int band = *((int *) argv[6]); return im_extract_areabands(argv[0], argv[1], left, top, width, height, band, 1); } /* Description of im_extract. */ static im_function extract_desc = { "im_extract", /* Name */ "extract area/band", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ extract_vec, /* Dispatch function */ IM_NUMBER(extract_args), /* Size of arg list */ extract_args /* Arg list */ }; /* Args to im_extract_area. */ static im_arg_desc extract_area_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("left"), IM_INPUT_INT("top"), IM_INPUT_INT("width"), IM_INPUT_INT("height") }; /* Call im_extract_area via arg vector. */ static int extract_area_vec(im_object *argv) { int x = *((int *) argv[2]); int y = *((int *) argv[3]); int w = *((int *) argv[4]); int h = *((int *) argv[5]); return im_extract_area(argv[0], argv[1], x, y, w, h); } /* Description of im_extract_area. */ static im_function extract_area_desc = { "im_extract_area", /* Name */ "extract area", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ extract_area_vec, /* Dispatch function */ IM_NUMBER(extract_area_args), /* Size of arg list */ extract_area_args /* Arg list */ }; /* Args to im_extract_bands. */ static im_arg_desc extract_bands_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("band"), IM_INPUT_INT("nbands"), }; /* Call im_extract_bands via arg vector. */ static int extract_bands_vec(im_object *argv) { int chsel = *((int *) argv[2]); int nbands = *((int *) argv[3]); return im_extract_bands(argv[0], argv[1], chsel, nbands); } /* Description of im_extract_bands. */ static im_function extract_bands_desc = { "im_extract_bands", /* Name */ "extract several bands", /* Description */ IM_FN_PIO, /* Flags */ extract_bands_vec, /* Dispatch function */ IM_NUMBER(extract_bands_args), /* Size of arg list */ extract_bands_args /* Arg list */ }; /* Args to im_extract_band. */ static im_arg_desc extract_band_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("band") }; /* Call im_extract_band via arg vector. */ static int extract_band_vec(im_object *argv) { int chsel = *((int *) argv[2]); return im_extract_band(argv[0], argv[1], chsel); } /* Description of im_extract_band. */ static im_function extract_band_desc = { "im_extract_band", /* Name */ "extract band", /* Description */ IM_FN_PIO, /* Flags */ extract_band_vec, /* Dispatch function */ IM_NUMBER(extract_band_args), /* Size of arg list */ extract_band_args /* Arg list */ }; /* Args to im_extract_areabands. */ static im_arg_desc extract_areabands_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("left"), IM_INPUT_INT("top"), IM_INPUT_INT("width"), IM_INPUT_INT("height"), IM_INPUT_INT("band"), IM_INPUT_INT("nbands") }; /* Call im_extract_areabands via arg vector. */ static int extract_areabands_vec(im_object *argv) { int left = *((int *) argv[2]); int top = *((int *) argv[3]); int width = *((int *) argv[4]); int height = *((int *) argv[5]); int band = *((int *) argv[6]); int nbands = *((int *) argv[7]); return im_extract_areabands(argv[0], argv[1], left, top, width, height, band, nbands); } /* Description of im_extract_areabands. */ static im_function extract_areabands_desc = { "im_extract_areabands", /* Name */ "extract area and bands", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ extract_areabands_vec, /* Dispatch function */ IM_NUMBER(extract_areabands_args), /* Size of arg list */ extract_areabands_args /* Arg list */ }; /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Two images in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Call im_bandjoin via arg vector. */ static int bandjoin_vec(im_object *argv) { return im_bandjoin(argv[0], argv[1], argv[2]); } /* Description of im_bandjoin. */ static im_function bandjoin_desc = { "im_bandjoin", /* Name */ "bandwise join of two images", /* Description */ IM_FN_PIO, /* Flags */ bandjoin_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; static im_arg_desc gbandjoin_args[] = { IM_INPUT_IMAGEVEC("in"), IM_OUTPUT_IMAGE("out") }; static int gbandjoin_vec(im_object *argv) { im_imagevec_object *iv = (im_imagevec_object *) argv[0]; return im_gbandjoin(iv->vec, argv[1], iv->n); } static im_function gbandjoin_desc = { "im_gbandjoin", /* Name */ "bandwise join of many images", /* Description */ IM_FN_PIO, /* Flags */ gbandjoin_vec, /* Dispatch function */ IM_NUMBER(gbandjoin_args), /* Size of arg list */ gbandjoin_args /* Arg list */ }; /* Args to im_text. */ static im_arg_desc text_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("text"), IM_INPUT_STRING("font"), IM_INPUT_INT("width"), IM_INPUT_INT("alignment"), IM_INPUT_INT("dpi") }; /* Call im_text via arg vector. */ static int text_vec(im_object *argv) { int width = *((int *) argv[3]); int alignment = *((int *) argv[4]); int dpi = *((int *) argv[5]); return im_text(argv[0], argv[1], argv[2], width, alignment, dpi); } /* Description of im_text. */ static im_function text_desc = { "im_text", /* Name */ "generate text image", /* Description */ IM_FN_PIO, /* Flags */ text_vec, /* Dispatch function */ IM_NUMBER(text_args), /* Size of arg list */ text_args /* Arg list */ }; /* Args to im_black. */ static im_arg_desc black_args[] = { IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("x_size"), IM_INPUT_INT("y_size"), IM_INPUT_INT("bands") }; /* Call im_black via arg vector. */ static int black_vec(im_object *argv) { int xs = *((int *) argv[1]); int ys = *((int *) argv[2]); int bands = *((int *) argv[3]); return im_black(argv[0], xs, ys, bands); } /* Description of im_black. */ static im_function black_desc = { "im_black", /* Name */ "generate black image", /* Description */ IM_FN_PIO, /* Flags */ black_vec, /* Dispatch function */ IM_NUMBER(black_args), /* Size of arg list */ black_args /* Arg list */ }; /* Args to im_clip2fmt. */ static im_arg_desc clip2fmt_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("ofmt") }; /* Call im_clip2fmt via arg vector. */ static int clip2fmt_vec(im_object *argv) { int ofmt = *((int *) argv[2]); return im_clip2fmt(argv[0], argv[1], ofmt); } /* Description of im_clip2fmt. */ static im_function clip2fmt_desc = { "im_clip2fmt", /* Name */ "convert image format to ofmt", /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ clip2fmt_vec, /* Dispatch function */ IM_NUMBER(clip2fmt_args), /* Size of arg list */ clip2fmt_args /* Arg list */ }; /* Call im_c2rect via arg vector. */ static int c2rect_vec(im_object *argv) { return im_c2rect(argv[0], argv[1]); } /* Description of im_c2rect. */ static im_function c2rect_desc = { "im_c2rect", /* Name */ "convert phase and amplitude to real and imaginary", IM_FN_PTOP | IM_FN_PIO, /* Flags */ c2rect_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_c2amph via arg vector. */ static int c2amph_vec(im_object *argv) { return im_c2amph(argv[0], argv[1]); } /* Description of im_c2amph. */ static im_function c2amph_desc = { "im_c2amph", /* Name */ "convert real and imaginary to phase and amplitude", IM_FN_PTOP | IM_FN_PIO, /* Flags */ c2amph_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_ri2c via arg vector. */ static int ri2c_vec(im_object *argv) { return im_ri2c(argv[0], argv[1], argv[2]); } /* Description of im_ri2c. */ static im_function ri2c_desc = { "im_ri2c", /* Name */ "join two non-complex images to form complex", IM_FN_PTOP | IM_FN_PIO, /* Flags */ ri2c_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_c2imag via arg vector. */ static int c2imag_vec(im_object *argv) { return im_c2imag(argv[0], argv[1]); } /* Description of im_c2imag. */ static im_function c2imag_desc = { "im_c2imag", /* Name */ "extract imaginary part of complex image", IM_FN_PTOP | IM_FN_PIO, /* Flags */ c2imag_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_c2real via arg vector. */ static int c2real_vec(im_object *argv) { return im_c2real(argv[0], argv[1]); } /* Description of im_c2real. */ static im_function c2real_desc = { "im_c2real", /* Name */ "extract real part of complex image", IM_FN_PTOP | IM_FN_PIO, /* Flags */ c2real_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args to im_copy_set. */ static im_arg_desc copy_set_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("Type"), IM_INPUT_DOUBLE("Xres"), IM_INPUT_DOUBLE("Yres"), IM_INPUT_INT("Xoffset"), IM_INPUT_INT("Yoffset") }; /* Call im_copy_set via arg vector. */ static int copy_set_vec(im_object *argv) { int Type = *((int *) argv[2]); float Xres = *((double *) argv[3]); float Yres = *((double *) argv[4]); int Xoffset = *((int *) argv[5]); int Yoffset = *((int *) argv[6]); return im_copy_set(argv[0], argv[1], Type, Xres, Yres, Xoffset, Yoffset); } /* Description of im_copy_set. */ static im_function copy_set_desc = { "im_copy_set", /* Name */ "copy image, setting informational fields", /* Can't set PTOP ... we don't want to zap the LUT, we want the real * image. */ IM_FN_PIO, /* Flags */ copy_set_vec, /* Dispatch function */ IM_NUMBER(copy_set_args), /* Size of arg list */ copy_set_args /* Arg list */ }; /* Args to im_copy_set_meta. */ static im_arg_desc copy_set_meta_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_STRING("field"), IM_INPUT_GVALUE("value") }; /* Call im_copy_set_meta via arg vector. */ static int copy_set_meta_vec(im_object *argv) { const char *field = argv[2]; GValue *value = argv[3]; return im_copy_set_meta(argv[0], argv[1], field, value); } /* Description of im_copy_set_meta. */ static im_function copy_set_meta_desc = { "im_copy_set_meta", /* Name */ "copy image, setting a meta field", /* Can't set PTOP ... we don't want to zap the LUT, we want the real * image. */ IM_FN_PIO, /* Flags */ copy_set_meta_vec, /* Dispatch function */ IM_NUMBER(copy_set_meta_args), /* Size of arg list */ copy_set_meta_args /* Arg list */ }; /* Args to im_copy_morph. */ static im_arg_desc copy_morph_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("Bands"), IM_INPUT_INT("BandFmt"), IM_INPUT_INT("Coding") }; /* Call im_copy_morph via arg vector. */ static int copy_morph_vec(im_object *argv) { int Bands = *((int *) argv[2]); int BandFmt = *((int *) argv[3]); int Coding = *((int *) argv[4]); return im_copy_morph(argv[0], argv[1], Bands, BandFmt, Coding); } /* Description of im_copy_morph. */ static im_function copy_morph_desc = { "im_copy_morph", /* Name */ "copy image, setting pixel layout", /* Can't set PTOP ... we don't want to zap the LUT, we want the real * image. */ IM_FN_PIO, /* Flags */ copy_morph_vec, /* Dispatch function */ IM_NUMBER(copy_morph_args), /* Size of arg list */ copy_morph_args /* Arg list */ }; /* Call im_copy via arg vector. */ static int copy_vec(im_object *argv) { return im_copy(argv[0], argv[1]); } /* Description of im_copy. */ static im_function copy_desc = { "im_copy", /* Name */ "copy image", /* Can't set PTOP ... we don't want to zap the LUT, we want the real * image. * * Don't cache, since we use copy to stop sharing. */ IM_FN_PIO | IM_FN_NOCACHE, copy_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_copy_file via arg vector. */ static int copy_file_vec(im_object *argv) { return im_copy_file(argv[0], argv[1]); } /* Description of im_copy_file. */ static im_function copy_file_desc = { "im_copy_file", /* Name */ "copy image to a file and return that", /* Can't set PTOP ... we don't want to zap the LUT, we want the real * image. */ IM_FN_PIO, /* Flags */ copy_file_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_copy_swap via arg vector. */ static int copy_swap_vec(im_object *argv) { return im_copy_swap(argv[0], argv[1]); } /* Description of im_copy_swap. */ static im_function copy_swap_desc = { "im_copy_swap", /* Name */ "copy image, swapping byte order", /* Can't set PTOP ... we don't want to zap the LUT, we want the real * image. */ IM_FN_PIO, /* Flags */ copy_swap_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_fliphor via arg vector. */ static int fliphor_vec(im_object *argv) { return im_fliphor(argv[0], argv[1]); } /* Description of im_fliphor. */ static im_function fliphor_desc = { "im_fliphor", /* Name */ "flip image left-right", IM_FN_PIO, /* Flags */ fliphor_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_flipver via arg vector. */ static int flipver_vec(im_object *argv) { return im_flipver(argv[0], argv[1]); } /* Description of im_flipver. */ static im_function flipver_desc = { "im_flipver", /* Name */ "flip image top-bottom", IM_FN_PIO, /* Flags */ flipver_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_falsecolour via arg vector. */ static int falsecolour_vec(im_object *argv) { return im_falsecolour(argv[0], argv[1]); } /* Description of im_falsecolour. */ static im_function falsecolour_desc = { "im_falsecolour", /* Name */ "turn luminance changes into chrominance changes", IM_FN_PTOP | IM_FN_PIO, /* Flags */ falsecolour_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args for im_insert. */ static im_arg_desc insert_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_IMAGE("sub"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("x"), IM_INPUT_INT("y") }; /* Call im_insert via arg vector. */ static int insert_vec(im_object *argv) { int x = *((int *) argv[3]); int y = *((int *) argv[4]); return im_insert(argv[0], argv[1], argv[2], x, y); } /* Description of im_insert. */ static im_function insert_desc = { "im_insert", /* Name */ "insert sub-image into main image at position", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ insert_vec, /* Dispatch function */ IM_NUMBER(insert_args), /* Size of arg list */ insert_args /* Arg list */ }; /* Args for im_insertset. */ static im_arg_desc insertset_args[] = { IM_INPUT_IMAGE("main"), IM_INPUT_IMAGE("sub"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INTVEC("x"), IM_INPUT_INTVEC("y") }; /* Call im_insertplaceset via arg vector. */ static int insertset_vec(im_object *argv) { im_intvec_object *xv = (im_intvec_object *) argv[3]; im_intvec_object *yv = (im_intvec_object *) argv[4]; if (xv->n != yv->n) { im_error("im_insertset", "%s", _("vectors not same length")); return -1; } if (im_insertset(argv[0], argv[1], argv[2], xv->n, xv->vec, yv->vec)) return -1; return 0; } /* Description of im_insertset. */ static im_function insertset_desc = { "im_insertset", /* Name */ "insert sub into main at every position in x, y", 0, /* Flags */ insertset_vec, /* Dispatch function */ IM_NUMBER(insertset_args), /* Size of arg list */ insertset_args /* Arg list */ }; /* Call im_insert_noexpand via arg vector. */ static int insert_noexpand_vec(im_object *argv) { int x = *((int *) argv[3]); int y = *((int *) argv[4]); return im_insert_noexpand(argv[0], argv[1], argv[2], x, y); } /* Description of im_insert_noexpand. */ static im_function insert_noexpand_desc = { "im_insert_noexpand", /* Name */ "insert sub-image into main image at position, no expansion", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ insert_noexpand_vec, /* Dispatch function */ IM_NUMBER(insert_args), /* Size of arg list */ insert_args /* Arg list */ }; /* Call im_rot180 via arg vector. */ static int rot180_vec(im_object *argv) { return im_rot180(argv[0], argv[1]); } /* Description of im_rot180. */ static im_function rot180_desc = { "im_rot180", /* Name */ "rotate image 180 degrees", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ rot180_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_rot90 via arg vector. */ static int rot90_vec(im_object *argv) { return im_rot90(argv[0], argv[1]); } /* Description of im_rot90. */ static im_function rot90_desc = { "im_rot90", /* Name */ "rotate image 90 degrees clockwise", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ rot90_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_rot270 via arg vector. */ static int rot270_vec(im_object *argv) { return im_rot270(argv[0], argv[1]); } /* Description of im_rot270. */ static im_function rot270_desc = { "im_rot270", /* Name */ "rotate image 270 degrees clockwise", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ rot270_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_lrjoin via arg vector. */ static int lrjoin_vec(im_object *argv) { return im_lrjoin(argv[0], argv[1], argv[2]); } /* Description of im_lrjoin. */ static im_function lrjoin_desc = { "im_lrjoin", /* Name */ "join two images left-right", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ lrjoin_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_tbjoin via arg vector. */ static int tbjoin_vec(im_object *argv) { return im_tbjoin(argv[0], argv[1], argv[2]); } /* Description of im_tbjoin. */ static im_function tbjoin_desc = { "im_tbjoin", /* Name */ "join two images top-bottom", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ tbjoin_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_scale via arg vector. */ static int scale_vec(im_object *argv) { return im_scale(argv[0], argv[1]); } /* Description of im_scale. */ static im_function scale_desc = { "im_scale", /* Name */ "scale image linearly to fit range 0-255", IM_FN_PIO, /* Flags */ scale_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_scaleps via arg vector. */ static int scaleps_vec(im_object *argv) { return im_scaleps(argv[0], argv[1]); } /* Description of im_scaleps. */ static im_function scaleps_desc = { "im_scaleps", /* Name */ "logarithmic scale of image to fit range 0-255", 0, /* Flags */ scaleps_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args to im_grid. */ static im_arg_desc grid_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("tile_height"), IM_INPUT_INT("across"), IM_INPUT_INT("down") }; /* Call im_grid via arg vector. */ static int grid_vec(im_object *argv) { int tile_height = *((int *) argv[2]); int across = *((int *) argv[3]); int down = *((int *) argv[4]); return im_grid(argv[0], argv[1], tile_height, across, down); } /* Description of im_grid. */ static im_function grid_desc = { "im_grid", /* Name */ "chop a tall thin image into a grid of images", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ grid_vec, /* Dispatch function */ IM_NUMBER(grid_args), /* Size of arg list */ grid_args /* Arg list */ }; /* Args to im_replicate. */ static im_arg_desc replicate_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("across"), IM_INPUT_INT("down") }; /* Call im_replicate via arg vector. */ static int replicate_vec(im_object *argv) { int across = *((int *) argv[2]); int down = *((int *) argv[3]); return im_replicate(argv[0], argv[1], across, down); } /* Description of im_replicate. */ static im_function replicate_desc = { "im_replicate", /* Name */ "replicate an image horizontally and vertically", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ replicate_vec, /* Dispatch function */ IM_NUMBER(replicate_args), /* Size of arg list */ replicate_args /* Arg list */ }; /* Args to im_zoom. */ static im_arg_desc zoom_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_INT("xfac"), IM_INPUT_INT("yfac") }; /* Call im_zoom via arg vector. */ static int zoom_vec(im_object *argv) { int xfac = *((int *) argv[2]); int yfac = *((int *) argv[3]); return im_zoom(argv[0], argv[1], xfac, yfac); } /* Description of im_zoom. */ static im_function zoom_desc = { "im_zoom", /* Name */ "simple zoom of an image by integer factors", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ zoom_vec, /* Dispatch function */ IM_NUMBER(zoom_args), /* Size of arg list */ zoom_args /* Arg list */ }; /* Call im_msb via arg vector. */ static int msb_vec(im_object *argv) { return im_msb(argv[0], argv[1]); } /* Description of im_msb. */ static im_function msb_desc = { "im_msb", /* Name */ "convert to uchar by discarding bits", IM_FN_PIO | IM_FN_PTOP, /* Flags */ msb_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args to im_msb_band. */ static im_arg_desc msb_band_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("band") }; /* Call im_msb_band via arg vector. */ static int msb_band_vec(im_object *argv) { IMAGE *in = (IMAGE *) argv[0]; IMAGE *out = (IMAGE *) argv[1]; int *band = (int *) argv[2]; return im_msb_band(in, out, *band); } /* Description of im_msb_band. */ static im_function msb_band_desc = { "im_msb_band", /* Name */ "convert to single band uchar by discarding bits", IM_FN_PIO | IM_FN_PTOP, /* Flags */ msb_band_vec, /* Dispatch function */ IM_NUMBER(msb_band_args), /* Size of arg list */ msb_band_args /* Arg list */ }; /* Args to im_wrap. */ static im_arg_desc wrap_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("x"), IM_INPUT_INT("y") }; /* Call im_wrap via arg vector. */ static int wrap_vec(im_object *argv) { return im_wrap(argv[0], argv[1], *(int *) argv[2], *(int *) argv[3]); } /* Description of im_wrap. */ static im_function wrap_desc = { "im_wrap", /* Name */ "shift image origin, wrapping at sides", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ wrap_vec, /* Dispatch function */ IM_NUMBER(wrap_args), /* Size of arg list */ wrap_args /* Arg list */ }; /* Args for im_embed. */ static im_arg_desc embed_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("type"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_INT("width"), IM_INPUT_INT("height") }; /* Call im_embed via arg vector. */ static int embed_vec(im_object *argv) { int type = *((int *) argv[2]); int x = *((int *) argv[3]); int y = *((int *) argv[4]); int width = *((int *) argv[5]); int height = *((int *) argv[6]); return im_embed(argv[0], argv[1], type, x, y, width, height); } /* Description of im_embed. */ static im_function embed_desc = { "im_embed", /* Name */ "embed in within a set of borders", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ embed_vec, /* Dispatch function */ IM_NUMBER(embed_args), /* Size of arg list */ embed_args /* Arg list */ }; /* Package up all these functions. */ static im_function *conv_list[] = { &gaussnoise_desc, &bandjoin_desc, &black_desc, &c2amph_desc, &c2imag_desc, &c2real_desc, &c2rect_desc, &clip2fmt_desc, ©_desc, ©_file_desc, ©_morph_desc, ©_swap_desc, ©_set_desc, ©_set_meta_desc, &extract_area_desc, &extract_areabands_desc, &extract_band_desc, &extract_bands_desc, &extract_desc, &falsecolour_desc, &fliphor_desc, &flipver_desc, &gbandjoin_desc, &grid_desc, &insert_desc, &insertset_desc, &insert_noexpand_desc, &embed_desc, &lrjoin_desc, &msb_desc, &msb_band_desc, &replicate_desc, &ri2c_desc, &rot180_desc, &rot270_desc, &rot90_desc, &scale_desc, &scaleps_desc, &subsample_desc, &system_desc, &system_image_desc, &tbjoin_desc, &text_desc, &wrap_desc, &zoom_desc }; /* Package of functions. */ im_package im__conversion = { "conversion", IM_NUMBER(conv_list), conv_list }; libvips-8.18.2/libvips/deprecated/convol_dispatch.c000066400000000000000000000260621516303661500223710ustar00rootroot00000000000000/* VIPS function dispatch tables for convolution. * * J. Cupitt, 14/2/95. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Two images in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Args to im_addgnoise. */ static im_arg_desc addgnoise_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("sigma") }; /* Call im_addgnoise via arg vector. */ static int addgnoise_vec(im_object *argv) { double sigma = *((double *) argv[2]); return im_addgnoise(argv[0], argv[1], sigma); } /* Description of im_addgnoise. */ static im_function addgnoise_desc = { "im_addgnoise", /* Name */ "add gaussian noise with mean 0 and std. dev. sigma", IM_FN_PIO, /* Flags */ addgnoise_vec, /* Dispatch function */ IM_NUMBER(addgnoise_args), /* Size of arg list */ addgnoise_args /* Arg list */ }; /* Args to im_contrast_surface. */ static im_arg_desc contrast_surface_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("half_win_size"), IM_INPUT_INT("spacing") }; /* Call im_contrast_surface via arg vector. */ static int contrast_surface_vec(im_object *argv) { int half_win_size = *((int *) argv[2]); int spacing = *((int *) argv[3]); return im_contrast_surface(argv[0], argv[1], half_win_size, spacing); } /* Description of im_contrast_surface. */ static im_function contrast_surface_desc = { "im_contrast_surface", /* Name */ "find high-contrast points in an image", IM_FN_PIO, /* Flags */ contrast_surface_vec, /* Dispatch function */ IM_NUMBER(contrast_surface_args), /* Size of arg list */ contrast_surface_args /* Arg list */ }; /* Args to im_sharpen. */ static im_arg_desc sharpen_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("mask_size"), IM_INPUT_DOUBLE("x1"), IM_INPUT_DOUBLE("y2"), IM_INPUT_DOUBLE("y3"), IM_INPUT_DOUBLE("m1"), IM_INPUT_DOUBLE("m2") }; /* Call im_sharpen via arg vector. */ static int sharpen_vec(im_object *argv) { int mask_size = *((int *) argv[2]); double x1 = *((double *) argv[3]); double x2 = *((double *) argv[4]); double x3 = *((double *) argv[5]); double m1 = *((double *) argv[6]); double m2 = *((double *) argv[7]); return im_sharpen(argv[0], argv[1], mask_size, x1, x2, x3, m1, m2); } /* Description of im_sharpen. */ static im_function sharpen_desc = { "im_sharpen", /* Name */ "sharpen high frequencies of L channel of LabQ", IM_FN_PIO, /* Flags */ sharpen_vec, /* Dispatch function */ IM_NUMBER(sharpen_args), /* Size of arg list */ sharpen_args /* Arg list */ }; /* Args for convolver with imask. */ static im_arg_desc conv_imask[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMASK("matrix") }; /* Args for convolver with dmask. */ static im_arg_desc conv_dmask[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DMASK("matrix") }; /* Call im_compass via arg vector. */ static int compass_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_compass(argv[0], argv[1], mo->mask); } /* Description of im_compass. */ static im_function compass_desc = { "im_compass", /* Name */ "convolve with 8-way rotating integer mask", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ compass_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Call im_conv via arg vector. */ static int conv_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_conv(argv[0], argv[1], mo->mask); } /* Description of im_conv. */ static im_function conv_desc = { "im_conv", /* Name */ "convolve", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ conv_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Call im_conv_f via arg vector. */ static int conv_f_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_conv_f(argv[0], argv[1], mo->mask); } /* Description of im_conv_f. */ static im_function conv_f_desc = { "im_conv_f", /* Name */ "convolve, with DOUBLEMASK", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ conv_f_vec, /* Dispatch function */ IM_NUMBER(conv_dmask), /* Size of arg list */ conv_dmask /* Arg list */ }; /* Call im_convsep via arg vector. */ static int convsep_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convsep(argv[0], argv[1], mo->mask); } /* Description of im_convsep. */ static im_function convsep_desc = { "im_convsep", /* Name */ "seperable convolution", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ convsep_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Call im_convsep_f via arg vector. */ static int convsep_f_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convsep_f(argv[0], argv[1], mo->mask); } /* Description of im_convsep_f. */ static im_function convsep_f_desc = { "im_convsep_f", /* Name */ "seperable convolution, with DOUBLEMASK", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ convsep_f_vec, /* Dispatch function */ IM_NUMBER(conv_dmask), /* Size of arg list */ conv_dmask /* Arg list */ }; /* Call im_fastcor via arg vector. */ static int fastcor_vec(im_object *argv) { return im_fastcor(argv[0], argv[1], argv[2]); } /* Description of im_fastcor. */ static im_function fastcor_desc = { "im_fastcor", /* Name */ "fast correlate in2 within in1", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ fastcor_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_grad_x via arg vector. */ static int grad_x_vec(im_object *argv) { return im_grad_x(argv[0], argv[1]); } /* Description of im_grad_x. */ static im_function grad_x_desc = { "im_grad_x", /* Name */ "horizontal difference image", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ grad_x_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_grad_y via arg vector. */ static int grad_y_vec(im_object *argv) { return im_grad_y(argv[0], argv[1]); } /* Description of im_grad_y. */ static im_function grad_y_desc = { "im_grad_y", /* Name */ "vertical difference image", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ grad_y_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_gradcor via arg vector. */ static int gradcor_vec(im_object *argv) { return im_gradcor(argv[0], argv[1], argv[2]); } /* Description of im_gradcor. */ static im_function gradcor_desc = { "im_gradcor", /* Name */ "non-normalised correlation of gradient of in2 within in1", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ gradcor_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_gradient via arg vector. */ static int gradient_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_gradient(argv[0], argv[1], mo->mask); } /* Description of im_gradient. */ static im_function gradient_desc = { "im_gradient", /* Name */ "convolve with 2-way rotating mask", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ gradient_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Call im_lindetect via arg vector. */ static int lindetect_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_lindetect(argv[0], argv[1], mo->mask); } /* Description of im_lindetect. */ static im_function lindetect_desc = { "im_lindetect", /* Name */ "convolve with 4-way rotating mask", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ lindetect_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Call im_spcor via arg vector. */ static int spcor_vec(im_object *argv) { return im_spcor(argv[0], argv[1], argv[2]); } /* Description of im_spcor. */ static im_function spcor_desc = { "im_spcor", /* Name */ "normalised correlation of in2 within in1", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ spcor_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Args for im_aconv(). */ static im_arg_desc aconv_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DMASK("matrix"), IM_INPUT_INT("n_layers"), IM_INPUT_INT("cluster") }; /* Call im_aconv via arg vector. */ static int aconv_vec(im_object *argv) { im_mask_object *mo = argv[2]; int n_layers = *((int *) argv[3]); int cluster = *((int *) argv[4]); return im_aconv(argv[0], argv[1], mo->mask, n_layers, cluster); } /* Description of im_aconv. */ static im_function aconv_desc = { "im_aconv", /* Name */ "approximate convolution", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ aconv_vec, /* Dispatch function */ IM_NUMBER(aconv_args), /* Size of arg list */ aconv_args /* Arg list */ }; /* Args for im_aconvsep(). */ static im_arg_desc aconvsep_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DMASK("matrix"), IM_INPUT_INT("n_layers") }; /* Call im_aconvsep via arg vector. */ static int aconvsep_vec(im_object *argv) { im_mask_object *mo = argv[2]; int n_layers = *((int *) argv[3]); return im_aconvsep(argv[0], argv[1], mo->mask, n_layers); } /* Description of im_aconvsep. */ static im_function aconvsep_desc = { "im_aconvsep", /* Name */ "approximate separable convolution", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ aconvsep_vec, /* Dispatch function */ IM_NUMBER(aconvsep_args), /* Size of arg list */ aconvsep_args /* Arg list */ }; /* Package up all these functions. */ static im_function *convol_list[] = { &aconvsep_desc, &aconv_desc, &addgnoise_desc, &compass_desc, &contrast_surface_desc, &conv_desc, &conv_f_desc, &convsep_desc, &convsep_f_desc, &fastcor_desc, &gradcor_desc, &gradient_desc, &grad_x_desc, &grad_y_desc, &lindetect_desc, &sharpen_desc, &spcor_desc, }; /* Package of functions. */ im_package im__convolution = { "convolution", IM_NUMBER(convol_list), convol_list }; libvips-8.18.2/libvips/deprecated/cooc_funcs.c000066400000000000000000000252021516303661500213260ustar00rootroot00000000000000/* @(#) Calculates the cooccurrence matrix of an image and some of its * @(#) features. The 256x256 cooccurrence matrix of im is held by m * @(#) There should be enough margin around the box so the (dx,dy) can * @(#) access neighbouring pixels outside the box * @(#) * @(#) Usage: * @(#) int im_cooc_matrix(im, m, xpos, ypos, xsize, ysize, dx, dy, sym_flag) * @(#) IMAGE *im, *m; * @(#) int xpos, ypos, xsize, ysize; location of the box within im * @(#) int dx, dy; displacements * @(#) int sym_flag; * @(#) * @(#) int im_cooc_asm(m, asmoment) * @(#) IMAGE *m; * @(#) double *asmoment; * @(#) * @(#) int im_cooc_contrast(m, contrast) * @(#) IMAGE *m; * @(#) double *contrast; * @(#) * @(#) int im_cooc_correlation(m, correlation) * @(#) IMAGE *m; * @(#) double *correlation; * @(#) * @(#) int im_cooc_entropy(m, entropy) * @(#) IMAGE *m; * @(#) double *entropy; * @(#) * @(#) All functions return 0 on success and -1 on error * * Copyright: N. Dessipris 1991 * Written on: 2/12/1991 * Updated on: 2/12/1991 * 22/7/93 JC * - extern decls removed * - im_incheck() calls added * 28/5/97 JC * - protos added :( */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include static int im_cooc_sym(IMAGE *im, IMAGE *m, int xpos, int ypos, int xsize, int ysize, int dx, int dy) { VipsPel *input, *cpinput; int *buf, *pnt, *cpnt; double *line, *cpline; int x, y; int offset; int bufofst; int tempA, tempB; int norm; if (im_iocheck(im, m) == -1) return -1; if ((im->Bands != 1) || (im->BandFmt != IM_BANDFMT_UCHAR)) { im_error("im_cooc_sym", "%s", _("Unable to accept input")); return -1; } if ((xpos + xsize + dx > im->Xsize) || (ypos + ysize + dy > im->Ysize)) { im_error("im_cooc_sym", "%s", _("wrong args")); return -1; } if (im_cp_desc(m, im) == -1) return -1; m->Xsize = 256; m->Ysize = 256; m->BandFmt = IM_BANDFMT_DOUBLE; m->Type = IM_TYPE_B_W; if (im_setupout(m) == -1) return -1; /* malloc space to keep the read values */ buf = (int *) calloc((unsigned) m->Xsize * m->Ysize, sizeof(int)); line = (double *) calloc((unsigned) m->Xsize * m->Bands, sizeof(double)); if ((buf == NULL) || (line == NULL)) { im_error("im_cooc_sym", "%s", _("calloc failed")); return -1; } input = im->data; input += (ypos * im->Xsize + xpos); offset = dy * im->Xsize + dx; for (y = 0; y < ysize; y++) { cpinput = input; input += im->Xsize; for (x = 0; x < xsize; x++) { tempA = (int) (*cpinput); tempB = (int) (*(cpinput + offset)); bufofst = tempA + m->Xsize * tempB; (*(buf + bufofst))++; bufofst = tempB + m->Xsize * tempA; (*(buf + bufofst))++; cpinput++; } } norm = xsize * ysize * 2; pnt = buf; for (y = 0; y < m->Ysize; y++) { cpnt = pnt; pnt += m->Xsize; cpline = line; for (x = 0; x < m->Xsize; x++) *cpline++ = (double) (*cpnt++) / (double) norm; if (im_writeline(y, m, (VipsPel *) line) == -1) { im_error("im_cooc_sym", "%s", _("unable to im_writeline")); return -1; } } free((char *) buf); free((char *) line); return 0; } static int im_cooc_ord(IMAGE *im, IMAGE *m, int xpos, int ypos, int xsize, int ysize, int dx, int dy) { VipsPel *input, *cpinput; int *buf, *pnt, *cpnt; double *line, *cpline; int x, y; int offset; int bufofst; int tempA, tempB; int norm; if (im_iocheck(im, m) == -1) return -1; if ((im->Bands != 1) || (im->BandFmt != IM_BANDFMT_UCHAR)) { im_error("im_cooc_ord", "%s", _("Unable to accept input")); return -1; } if ((xpos + xsize + dx > im->Xsize) || (ypos + ysize + dy > im->Ysize)) { im_error("im_cooc_ord", "%s", _("wrong args")); return -1; } if (im_cp_desc(m, im) == -1) return -1; m->Xsize = 256; m->Ysize = 256; m->BandFmt = IM_BANDFMT_DOUBLE; if (im_setupout(m) == -1) return -1; /* malloc space to keep the read values */ buf = (int *) calloc((unsigned) m->Xsize * m->Ysize, sizeof(int)); line = (double *) calloc((unsigned) m->Xsize * m->Bands, sizeof(double)); if ((buf == NULL) || (line == NULL)) { im_error("im_cooc_ord", "%s", _("calloc failed")); return -1; } input = im->data; input += (ypos * im->Xsize + xpos); offset = dy * im->Xsize + dx; for (y = 0; y < ysize; y++) { cpinput = input; input += im->Xsize; for (x = 0; x < xsize; x++) { tempA = (int) (*cpinput); tempB = (int) (*(cpinput + offset)); bufofst = tempA + m->Xsize * tempB; (*(buf + bufofst))++; cpinput++; } } norm = xsize * ysize; pnt = buf; for (y = 0; y < m->Ysize; y++) { cpnt = pnt; pnt += m->Xsize; cpline = line; for (x = 0; x < m->Xsize; x++) *cpline++ = (double) (*cpnt++) / (double) norm; if (im_writeline(y, m, (PEL *) line) == -1) { im_error("im_cooc_ord", "%s", _("unable to im_writeline")); return -1; } } free((char *) buf); free((char *) line); return 0; } /* Keep the coocurrence matrix as a 256x256x1 double image */ int im_cooc_matrix(IMAGE *im, IMAGE *m, int xp, int yp, int xs, int ys, int dx, int dy, int flag) { if (flag == 0) return im_cooc_ord(im, m, xp, yp, xs, ys, dx, dy); else if (flag == 1) /* symmetrical cooc */ return im_cooc_sym(im, m, xp, yp, xs, ys, dx, dy); else { im_error("im_cooc_matrix", "%s", _("wrong flag!")); return -1; } } /* Calculate contrast, asmoment, entropy and correlation */ int im_cooc_asm(IMAGE *m, double *asmoment) { double temp, tmpasm, *pnt; int i; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 256 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_cooc_asm", "%s", _("unable to accept input")); return -1; } tmpasm = 0.0; pnt = (double *) m->data; for (i = 0; i < m->Xsize * m->Ysize; i++) { temp = *pnt++; tmpasm += temp * temp; } *asmoment = tmpasm; return 0; } int im_cooc_contrast(IMAGE *m, double *contrast) { double dtemp, tmpcon, *pnt, *cpnt; int x, y; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 256 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_cooc_contrast", "%s", _("unable to accept input")); return -1; } tmpcon = 0.0; pnt = (double *) m->data; for (y = 0; y < m->Ysize; y++) { cpnt = pnt; pnt += m->Xsize; for (x = 0; x < m->Xsize; x++) { dtemp = (double) ((y - x) * (y - x)); tmpcon += dtemp * (*cpnt); cpnt++; } } *contrast = tmpcon; return 0; } /* buffer contains the frequency distributions f[i] */ /* Note that sum(f[i]) = 1.0 and that the */ /* cooccurence matrix is symmetrical */ static void stats(double *buffer, int size, double *pmean, double *pstd) { double mean, std; register int i; double sumf; /* calculates the sum of f[i] */ double temp; /* temporary variable */ double *pbuffer; double sumf2; /* calculates the sum of f[i]^2 */ double correction; /* calulates the correction term for the variance */ double variance; /* = (sumf2 - correction)/n, n=sum(f[i]) = 1 */ mean = 0.0; std = 0.0; sumf = 0.0; sumf2 = 0.0; pbuffer = buffer; for (i = 0; i < size; i++) { temp = *pbuffer++; sumf += (temp * i); sumf2 += (temp * i * i); } correction = sumf * sumf; mean = sumf; variance = sumf2 - correction; std = sqrt(variance); *pmean = mean; *pstd = std; } int im_cooc_correlation(IMAGE *m, double *correlation) { double mcol, stdcol, mrow, stdrow; /* mean and std of cols and rows */ double *pbuf; double *cpbuf; double dtemp; register int i, j; double *row; /* Keeps the sum of rows entries as double */ double *col; /* Keeps the sum of cols entries as double */ double tmpcor = 0.0; double sum = 0.0; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 256 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_cooc_correlation", "%s", _("unable to accept input")); return -1; } row = (double *) calloc((unsigned) m->Ysize, sizeof(double)); col = (double *) calloc((unsigned) m->Xsize, sizeof(double)); if (row == NULL || col == NULL) { im_error("im_cooc_correlation", "%s", _("unable to calloc")); return -1; } pbuf = (double *) m->data; for (j = 0; j < m->Ysize; j++) { cpbuf = pbuf; pbuf += m->Xsize; sum = 0.0; for (i = 0; i < m->Xsize; i++) sum += *cpbuf++; *(row + j) = sum; } pbuf = (double *) m->data; for (j = 0; j < m->Ysize; j++) { cpbuf = pbuf; pbuf++; sum = 0.0; for (i = 0; i < m->Xsize; i++) { sum += *cpbuf; cpbuf += m->Xsize; } *(col + j) = sum; } stats(row, m->Ysize, &mrow, &stdrow); stats(col, m->Ysize, &mcol, &stdcol); #ifdef DEBUG fprintf(stderr, "rows: mean=%f std=%f\ncols: mean=%f std=%f\n", mrow, stdrow, mcol, stdcol); #endif tmpcor = 0.0; pbuf = (double *) m->data; for (j = 0; j < m->Ysize; j++) { cpbuf = pbuf; pbuf += m->Xsize; for (i = 0; i < m->Xsize; i++) { dtemp = *cpbuf; tmpcor += (((double) i) * ((double) j) * dtemp); cpbuf++; } } #ifdef DEBUG fprintf(stderr, "tmpcor=%f\n", tmpcor); #endif if ((stdcol == 0.0) || (stdrow == 0)) { im_error("im_cooc_correlation", "%s", _("zero std")); return -1; } tmpcor = (tmpcor - (mcol * mrow)) / (stdcol * stdrow); *correlation = tmpcor; free((char *) row); free((char *) col); return 0; } int im_cooc_entropy(IMAGE *m, double *entropy) { double *pbuf, *pbufstart; double *cpbuf; register int i, j; double tmpent, dtemp; double val; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 256 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_cooc_entropy", "%s", _("unable to accept input")); return -1; } pbufstart = (double *) m->data; tmpent = 0.0; pbuf = pbufstart; for (j = 0; j < m->Ysize; j++) { cpbuf = pbuf; pbuf += m->Xsize; for (i = 0; i < m->Xsize; i++) { if (*cpbuf != 0) { dtemp = *cpbuf; tmpent += (dtemp * log10(dtemp)); } cpbuf++; } } val = tmpent * (-1); #ifdef DEBUG fprintf(stderr, "ENT=%f\nwhich is %f bits\n", val, val / log10(2.0)); #endif *entropy = (val / log10(2.0)); return 0; } libvips-8.18.2/libvips/deprecated/deprecated_dispatch.c000066400000000000000000001504061516303661500231710ustar00rootroot00000000000000/* Function dispatch tables for deprecated operations. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; static im_arg_desc quadratic_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMAGE("coeff") }; static int quadratic_vec(im_object *argv) { return im_quadratic(argv[0], argv[1], argv[2]); } static im_function quadratic_desc = { "im_quadratic", /* Name */ "transform via quadratic", IM_FN_PIO, /* Flags */ quadratic_vec, /* Dispatch function */ IM_NUMBER(quadratic_args), /* Size of arg list */ quadratic_args /* Arg list */ }; /* Two images in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Call im_clip via arg vector. */ static int clip_vec(im_object *argv) { return im_clip(argv[0], argv[1]); } /* Description of im_clip. */ static im_function clip_desc = { "im_clip", /* Name */ "convert to unsigned 8-bit integer", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_c2ps via arg vector. */ static int c2ps_vec(im_object *argv) { return im_c2ps(argv[0], argv[1]); } /* Description of im_c2ps. */ static im_function c2ps_desc = { "im_c2ps", /* Name */ "find power spectrum of complex image", IM_FN_PTOP | IM_FN_PIO, /* Flags */ c2ps_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args for im_lhisteq. */ static im_arg_desc lhisteq_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("width"), IM_INPUT_INT("height") }; /* Args for im_stdif. */ static im_arg_desc stdif_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("m0"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("s0"), IM_INPUT_INT("xw"), IM_INPUT_INT("yw") }; /* Args to im_erode. */ static im_arg_desc erode_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMASK("mask") }; /* Args to im_rank. */ static im_arg_desc rank_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xsize"), IM_INPUT_INT("ysize"), IM_INPUT_INT("n") }; /* Args for convolver with imask. */ static im_arg_desc conv_imask[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMASK("matrix") }; /* Args for convolver with dmask. */ static im_arg_desc conv_dmask[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DMASK("matrix") }; /* Call im_cmulnorm via arg vector. */ static int cmulnorm_vec(im_object *argv) { return im_cmulnorm(argv[0], argv[1], argv[2]); } /* Description of im_cmulnorm. */ static im_function cmulnorm_desc = { "im_cmulnorm", /* Name */ N_("multiply two complex images, normalising output"), IM_FN_PIO, /* Flags */ cmulnorm_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Four images in, one out. */ static im_arg_desc fav4_args[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_INPUT_IMAGE("in3"), IM_INPUT_IMAGE("in4"), IM_OUTPUT_IMAGE("out") }; /* Call im_fav4 via arg vector. */ static int fav4_vec(im_object *argv) { IMAGE *buf[4]; buf[0] = argv[0]; buf[1] = argv[1]; buf[2] = argv[2]; buf[3] = argv[3]; return im_fav4(&buf[0], argv[4]); } /* Description of im_fav4. */ static im_function fav4_desc = { "im_fav4", /* Name */ N_("average of 4 images"), 0, /* Flags */ fav4_vec, /* Dispatch function */ IM_NUMBER(fav4_args), /* Size of arg list */ fav4_args /* Arg list */ }; /* Args for im_gadd(). */ static im_arg_desc gadd_args[] = { IM_INPUT_DOUBLE("a"), IM_INPUT_IMAGE("in1"), IM_INPUT_DOUBLE("b"), IM_INPUT_IMAGE("in2"), IM_INPUT_DOUBLE("c"), IM_OUTPUT_IMAGE("out") }; /* Call im_gadd() via arg vector. */ static int gadd_vec(im_object *argv) { double a = *((double *) argv[0]); double b = *((double *) argv[2]); double c = *((double *) argv[4]); return im_gadd(a, argv[1], b, argv[3], c, argv[5]); } /* Description of im_gadd(). */ static im_function gadd_desc = { "im_gadd", /* Name */ N_("calculate a*in1 + b*in2 + c = outfile"), 0, /* Flags */ gadd_vec, /* Dispatch function */ IM_NUMBER(gadd_args), /* Size of arg list */ gadd_args /* Arg list */ }; /* Args for im_litecor(). */ static im_arg_desc litecor_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_IMAGE("white"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("clip"), IM_INPUT_DOUBLE("factor") }; /* Call im_litecor() via arg vector. */ static int litecor_vec(im_object *argv) { int clip = *((int *) argv[3]); double factor = *((double *) argv[4]); return im_litecor(argv[0], argv[1], argv[2], clip, factor); } /* Description of im_litecor(). */ static im_function litecor_desc = { "im_litecor", /* Name */ N_("calculate max(white)*factor*(in/white), if clip == 1"), 0, /* Flags */ litecor_vec, /* Dispatch function */ IM_NUMBER(litecor_args), /* Size of arg list */ litecor_args /* Arg list */ }; /* affine args */ static im_arg_desc affine_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("c"), IM_INPUT_DOUBLE("d"), IM_INPUT_DOUBLE("dx"), IM_INPUT_DOUBLE("dy"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_INT("w"), IM_INPUT_INT("h") }; /* Call im_affine via arg vector. */ static int affine_vec(im_object *argv) { double a = *((double *) argv[2]); double b = *((double *) argv[3]); double c = *((double *) argv[4]); double d = *((double *) argv[5]); double dx = *((double *) argv[6]); double dy = *((double *) argv[7]); int x = *((int *) argv[8]); int y = *((int *) argv[9]); int w = *((int *) argv[10]); int h = *((int *) argv[11]); return im_affine(argv[0], argv[1], a, b, c, d, dx, dy, x, y, w, h); } /* Description of im_affine. */ static im_function affine_desc = { "im_affine", /* Name */ "affine transform", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ affine_vec, /* Dispatch function */ IM_NUMBER(affine_args), /* Size of arg list */ affine_args /* Arg list */ }; /* similarity args */ static im_arg_desc similarity_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("dx"), IM_INPUT_DOUBLE("dy") }; /* Call im_similarity via arg vector. */ static int similarity_vec(im_object *argv) { double a = *((double *) argv[2]); double b = *((double *) argv[3]); double dx = *((double *) argv[4]); double dy = *((double *) argv[5]); return im_similarity(argv[0], argv[1], a, b, dx, dy); } /* Description of im_similarity. */ static im_function similarity_desc = { "im_similarity", /* Name */ "similarity transformation", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ similarity_vec, /* Dispatch function */ IM_NUMBER(similarity_args), /* Size of arg list */ similarity_args /* Arg list */ }; /* similarity_area args */ static im_arg_desc similarity_area_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("dx"), IM_INPUT_DOUBLE("dy"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_INT("w"), IM_INPUT_INT("h") }; /* Call im_similarity_area via arg vector. */ static int similarity_area_vec(im_object *argv) { double a = *((double *) argv[2]); double b = *((double *) argv[3]); double dx = *((double *) argv[4]); double dy = *((double *) argv[5]); int x = *((int *) argv[6]); int y = *((int *) argv[7]); int w = *((int *) argv[8]); int h = *((int *) argv[9]); return im_similarity_area(argv[0], argv[1], a, b, dx, dy, x, y, w, h); } /* Description of im_similarity_area. */ static im_function similarity_area_desc = { "im_similarity_area", /* Name */ "output area xywh of similarity transformation", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ similarity_area_vec, /* Dispatch function */ IM_NUMBER(similarity_area_args), /* Size of arg list */ similarity_area_args /* Arg list */ }; static int icc_export_vec(im_object *argv) { int intent = *((int *) argv[3]); return im_icc_export(argv[0], argv[1], argv[2], intent); } static im_arg_desc icc_export_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("output_profile"), IM_INPUT_INT("intent") }; /* Description of im_icc_export. */ static im_function icc_export_desc = { "im_icc_export", /* Name */ "convert a float LAB to an 8-bit device image with an ICC profile", /* Description */ IM_FN_PIO, /* Flags */ icc_export_vec, /* Dispatch function */ IM_NUMBER(icc_export_args), /* Size of arg list */ icc_export_args /* Arg list */ }; /* Args for im_segment(). */ static im_arg_desc segment_args[] = { IM_INPUT_IMAGE("test"), IM_OUTPUT_IMAGE("mask"), IM_OUTPUT_INT("segments") }; /* Call im_segment() via arg vector. */ static int segment_vec(im_object *argv) { IMAGE *test = argv[0]; IMAGE *mask = argv[1]; int *serial = (int *) argv[2]; return im_segment(test, mask, serial); } /* Description of im_segment(). */ static im_function segment_desc = { "im_segment", /* Name */ "number continuous regions in an image", 0, /* Flags */ segment_vec, /* Dispatch function */ IM_NUMBER(segment_args), /* Size of arg list */ segment_args /* Arg list */ }; static int print_vec(im_object *argv) { const char *message = argv[0]; char **out = (char **) &argv[1]; if (im_print(message)) return -1; *out = im_strdup(NULL, "printed"); return 0; } static im_arg_desc print_arg_types[] = { IM_INPUT_STRING("message"), IM_OUTPUT_STRING("result") }; static im_function print_desc = { "im_print", /* Name */ "print string to stdout", /* Description */ 0, /* Flags */ print_vec, /* Dispatch function */ IM_NUMBER(print_arg_types), /* Size of arg list */ print_arg_types /* Arg list */ }; /* Call im_clip2dcm via arg vector. */ static int clip2dcm_vec(im_object *argv) { return im_clip2dcm(argv[0], argv[1]); } /* Description of im_clip2dcm. */ static im_function clip2dcm_desc = { "im_clip2dcm", /* Name */ "convert to double complex", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2dcm_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2cm via arg vector. */ static int clip2cm_vec(im_object *argv) { return im_clip2cm(argv[0], argv[1]); } /* Description of im_clip2cm. */ static im_function clip2cm_desc = { "im_clip2cm", /* Name */ "convert to complex", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2cm_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2us via arg vector. */ static int clip2us_vec(im_object *argv) { return im_clip2us(argv[0], argv[1]); } /* Description of im_clip2us. */ static im_function clip2us_desc = { "im_clip2us", /* Name */ "convert to unsigned 16-bit integer", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2us_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2ui via arg vector. */ static int clip2ui_vec(im_object *argv) { return im_clip2ui(argv[0], argv[1]); } /* Description of im_clip2ui. */ static im_function clip2ui_desc = { "im_clip2ui", /* Name */ "convert to unsigned 32-bit integer", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2ui_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2s via arg vector. */ static int clip2s_vec(im_object *argv) { return im_clip2s(argv[0], argv[1]); } /* Description of im_clip2s. */ static im_function clip2s_desc = { "im_clip2s", /* Name */ "convert to signed 16-bit integer", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2s_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2i via arg vector. */ static int clip2i_vec(im_object *argv) { return im_clip2i(argv[0], argv[1]); } /* Description of im_clip2i. */ static im_function clip2i_desc = { "im_clip2i", /* Name */ "convert to signed 32-bit integer", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2i_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2d via arg vector. */ static int clip2d_vec(im_object *argv) { return im_clip2d(argv[0], argv[1]); } /* Description of im_clip2d. */ static im_function clip2d_desc = { "im_clip2d", /* Name */ "convert to double-precision float", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2d_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2f via arg vector. */ static int clip2f_vec(im_object *argv) { return im_clip2f(argv[0], argv[1]); } /* Description of im_clip2f. */ static im_function clip2f_desc = { "im_clip2f", /* Name */ "convert to single-precision float", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2f_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_clip2c via arg vector. */ static int clip2c_vec(im_object *argv) { return im_clip2c(argv[0], argv[1]); } /* Description of im_clip2c. */ static im_function clip2c_desc = { "im_clip2c", /* Name */ "convert to signed 8-bit integer", IM_FN_PTOP | IM_FN_PIO, /* Flags */ clip2c_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args to im_thresh. */ static im_arg_desc thresh_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_DOUBLE("threshold") }; /* Call im_thresh via arg vector. */ static int thresh_vec(im_object *argv) { double t1 = *((double *) argv[2]); return im_thresh(argv[0], argv[1], t1); } /* Description of im_thresh. */ static im_function thresh_desc = { "im_thresh", /* Name */ "slice an image at a threshold", 0, /* Flags */ thresh_vec, /* Dispatch function */ IM_NUMBER(thresh_args), /* Size of arg list */ thresh_args /* Arg list */ }; /* Args to im_slice. */ static im_arg_desc slice_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_IMAGE("output"), IM_INPUT_DOUBLE("thresh1"), IM_INPUT_DOUBLE("thresh2") }; /* Call im_slice via arg vector. */ static int slice_vec(im_object *argv) { double t1 = *((double *) argv[2]); double t2 = *((double *) argv[3]); return im_slice(argv[0], argv[1], t1, t2); } /* Description of im_slice. */ static im_function slice_desc = { "im_slice", /* Name */ "slice an image using two thresholds", 0, /* Flags */ slice_vec, /* Dispatch function */ IM_NUMBER(slice_args), /* Size of arg list */ slice_args /* Arg list */ }; /* Args for im_convsub. */ static im_arg_desc convsub_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMASK("matrix"), IM_INPUT_INT("xskip"), IM_INPUT_INT("yskip") }; /* Call im_convsub via arg vector. */ static int convsub_vec(im_object *argv) { im_mask_object *mo = argv[2]; int xskip = *((int *) argv[3]); int yskip = *((int *) argv[4]); return im_convsub(argv[0], argv[1], mo->mask, xskip, yskip); } /* Description of im_convsub. */ static im_function convsub_desc = { "im_convsub", /* Name */ "convolve uchar to uchar, sub-sampling by xskip, yskip", IM_FN_TRANSFORM, /* Flags */ convsub_vec, /* Dispatch function */ IM_NUMBER(convsub_args), /* Size of arg list */ convsub_args /* Arg list */ }; /* Args to im_bernd. */ static im_arg_desc bernd_args[] = { IM_INPUT_STRING("tiffname"), IM_INPUT_INT("left"), IM_INPUT_INT("top"), IM_INPUT_INT("width"), IM_INPUT_INT("height") }; /* Call im_bernd via arg vector. */ static int bernd_vec(im_object *argv) { char *name = argv[0]; int left = *((int *) argv[1]); int top = *((int *) argv[2]); int width = *((int *) argv[3]); int height = *((int *) argv[4]); return im_bernd(name, left, top, width, height); } /* Description of im_bernd. */ static im_function bernd_desc = { "im_bernd", /* Name */ "extract from pyramid as jpeg", /* Description */ 0, /* Flags */ bernd_vec, /* Dispatch function */ IM_NUMBER(bernd_args), /* Size of arg list */ bernd_args /* Arg list */ }; /* Args for im_line. */ static im_arg_desc line_args[] = { IM_RW_IMAGE("im"), IM_INPUT_INT("x1"), IM_INPUT_INT("y1"), IM_INPUT_INT("x2"), IM_INPUT_INT("y2"), IM_INPUT_INT("pelval") }; /* Call im_line via arg vector. */ static int line_vec(im_object *argv) { int x1 = *((int *) argv[1]); int y1 = *((int *) argv[2]); int x2 = *((int *) argv[3]); int y2 = *((int *) argv[4]); int pel = *((int *) argv[5]); return im_line(argv[0], x1, y1, x2, y2, pel); } /* Description of im_line. */ static im_function line_desc = { "im_line", /* Name */ "draw line between points (x1,y1) and (x2,y2)", 0, /* Flags */ line_vec, /* Dispatch function */ IM_NUMBER(line_args), /* Size of arg list */ line_args /* Arg list */ }; /* Args for im_resize_linear. */ static im_arg_desc resize_linear_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("X"), IM_INPUT_INT("Y") }; /* Call im_resize_linear via arg vector. */ static int resize_linear_vec(im_object *argv) { int X = *((int *) argv[2]); int Y = *((int *) argv[3]); return im_resize_linear(argv[0], argv[1], X, Y); } /* Description of im_resize_linear. */ static im_function resize_linear_desc = { "im_resize_linear", /* Name */ "resize to X by Y pixels with linear interpolation", 0, /* Flags */ resize_linear_vec, /* Dispatch function */ IM_NUMBER(resize_linear_args), /* Size of arg list */ resize_linear_args /* Arg list */ }; /* Args for im_insertplaceset. */ static im_arg_desc insertplaceset_args[] = { IM_INPUT_IMAGE("main"), IM_INPUT_IMAGE("sub"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INTVEC("x"), IM_INPUT_INTVEC("y") }; /* Call im_insertplaceplaceset via arg vector. */ static int insertplaceset_vec(im_object *argv) { im_intvec_object *xv = (im_intvec_object *) argv[3]; im_intvec_object *yv = (im_intvec_object *) argv[4]; if (xv->n != yv->n) { im_error("im_insertplaceset", "%s", _("vectors not same length")); return -1; } if (im_insertset(argv[0], argv[1], argv[2], xv->n, xv->vec, yv->vec)) return -1; return 0; } /* Description of im_insertplaceset. */ static im_function insertplaceset_desc = { "im_insertplaceset", /* Name */ "insert sub into main at every position in x, y", 0, /* Flags */ insertplaceset_vec, /* Dispatch function */ IM_NUMBER(insertplaceset_args), /* Size of arg list */ insertplaceset_args /* Arg list */ }; /* Call im_spcor_raw via arg vector. */ static int spcor_raw_vec(im_object *argv) { return im_spcor_raw(argv[0], argv[1], argv[2]); } /* Description of im_spcor_raw. */ static im_function spcor_raw_desc = { "im_spcor_raw", /* Name */ "normalised correlation of in2 within in1, no black padding", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ spcor_raw_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_gradcor_raw via arg vector. */ static int gradcor_raw_vec(im_object *argv) { return im_gradcor_raw(argv[0], argv[1], argv[2]); } /* Description of im_gradcor_raw. */ static im_function gradcor_raw_desc = { "im_gradcor_raw", /* Name */ "non-normalised correlation of gradient of in2 within in1, no padding", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ gradcor_raw_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_fastcor_raw via arg vector. */ static int fastcor_raw_vec(im_object *argv) { return im_fastcor_raw(argv[0], argv[1], argv[2]); } /* Description of im_fastcor_raw. */ static im_function fastcor_raw_desc = { "im_fastcor_raw", /* Name */ "fast correlate in2 within in1, no border", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ fastcor_raw_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_convsepf_raw via arg vector. */ static int convsepf_raw_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convsepf_raw(argv[0], argv[1], mo->mask); } /* Description of im_convsepf_raw. */ static im_function convsepf_raw_desc = { "im_convsepf_raw", /* Name */ "seperable convolution, with DOUBLEMASK, no border", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ convsepf_raw_vec, /* Dispatch function */ IM_NUMBER(conv_dmask), /* Size of arg list */ conv_dmask /* Arg list */ }; /* Call im_convsep_raw via arg vector. */ static int convsep_raw_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convsep_raw(argv[0], argv[1], mo->mask); } /* Description of im_convsep_raw. */ static im_function convsep_raw_desc = { "im_convsep_raw", /* Name */ "seperable convolution, no border", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ convsep_raw_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Call im_convf_raw via arg vector. */ static int convf_raw_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convf_raw(argv[0], argv[1], mo->mask); } /* Description of im_convf_raw. */ static im_function convf_raw_desc = { "im_convf_raw", /* Name */ "convolve, with DOUBLEMASK, no border", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ convf_raw_vec, /* Dispatch function */ IM_NUMBER(conv_dmask), /* Size of arg list */ conv_dmask /* Arg list */ }; /* Call im_conv_raw via arg vector. */ static int conv_raw_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_conv_raw(argv[0], argv[1], mo->mask); } /* Description of im_conv_raw. */ static im_function conv_raw_desc = { "im_conv_raw", /* Name */ "convolve, no border", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ conv_raw_vec, /* Dispatch function */ IM_NUMBER(conv_imask), /* Size of arg list */ conv_imask /* Arg list */ }; /* Args to im_contrast_surface_raw. */ static im_arg_desc contrast_surface_raw_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("half_win_size"), IM_INPUT_INT("spacing") }; /* Call im_contrast_surface_raw via arg vector. */ static int contrast_surface_raw_vec(im_object *argv) { int half_win_size = *((int *) argv[2]); int spacing = *((int *) argv[3]); return im_contrast_surface_raw(argv[0], argv[1], half_win_size, spacing); } /* Description of im_contrast_surface_raw. */ static im_function contrast_surface_raw_desc = { "im_contrast_surface_raw", /* Name */ "find high-contrast points in an image", IM_FN_PIO, /* Flags */ contrast_surface_raw_vec, /* Dispatch function */ IM_NUMBER(contrast_surface_raw_args), /* Size of arg list */ contrast_surface_raw_args /* Arg list */ }; /* Call im_stdif_raw via arg vector. */ static int stdif_raw_vec(im_object *argv) { double a = *((double *) argv[2]); double m0 = *((double *) argv[3]); double b = *((double *) argv[4]); double s0 = *((double *) argv[5]); int xw = *((int *) argv[6]); int yw = *((int *) argv[7]); return im_stdif_raw(argv[0], argv[1], a, m0, b, s0, xw, yw); } /* Description of im_stdif. */ static im_function stdif_raw_desc = { "im_stdif_raw", /* Name */ "statistical differencing, no border", IM_FN_PIO, /* Flags */ stdif_raw_vec, /* Dispatch function */ IM_NUMBER(stdif_args), /* Size of arg list */ stdif_args /* Arg list */ }; /* Call im_lhisteq_raw via arg vector. */ static int lhisteq_raw_vec(im_object *argv) { int xw = *((int *) argv[2]); int yw = *((int *) argv[3]); return im_lhisteq_raw(argv[0], argv[1], xw, yw); } /* Description of im_lhisteq_raw. */ static im_function lhisteq_raw_desc = { "im_lhisteq_raw", /* Name */ "local histogram equalisation, no border", IM_FN_PIO, /* Flags */ lhisteq_raw_vec, /* Dispatch function */ IM_NUMBER(lhisteq_args), /* Size of arg list */ lhisteq_args /* Arg list */ }; /* Call im_rank_raw via arg vector. */ static int rank_raw_vec(im_object *argv) { int xsize = *((int *) argv[2]); int ysize = *((int *) argv[3]); int n = *((int *) argv[4]); return im_rank_raw(argv[0], argv[1], xsize, ysize, n); } /* Description of im_rank_raw. */ static im_function rank_raw_desc = { "im_rank_raw", /* Name */ "rank filter nth element of xsize/ysize window, no border", IM_FN_PIO, /* Flags */ rank_raw_vec, /* Dispatch function */ IM_NUMBER(rank_args), /* Size of arg list */ rank_args /* Arg list */ }; /* Call im_erode_raw via arg vector. */ static int erode_raw_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_erode_raw(argv[0], argv[1], mo->mask); } /* Description of im_erode_raw. */ static im_function erode_raw_desc = { "im_erode_raw", /* Name */ "erode image with mask", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ erode_raw_vec, /* Dispatch function */ IM_NUMBER(erode_args), /* Size of arg list */ erode_args /* Arg list */ }; /* Call im_dilate_raw via arg vector. */ static int dilate_raw_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_dilate_raw(argv[0], argv[1], mo->mask); } /* Description of im_dilate_raw. */ static im_function dilate_raw_desc = { "im_dilate_raw", /* Name */ "dilate image with mask", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ dilate_raw_vec, /* Dispatch function */ IM_NUMBER(erode_args), /* Size of arg list */ erode_args /* Arg list */ }; /* Call im_convsepf via arg vector. */ static int convsepf_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convsepf(argv[0], argv[1], mo->mask); } /* Description of im_convsepf. */ static im_function convsepf_desc = { "im_convsepf", /* Name */ "seperable convolution, with DOUBLEMASK", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ convsepf_vec, /* Dispatch function */ IM_NUMBER(conv_dmask), /* Size of arg list */ conv_dmask /* Arg list */ }; /* Call im_convf via arg vector. */ static int convf_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_convf(argv[0], argv[1], mo->mask); } /* Description of im_convf. */ static im_function convf_desc = { "im_convf", /* Name */ "convolve, with DOUBLEMASK", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ convf_vec, /* Dispatch function */ IM_NUMBER(conv_dmask), /* Size of arg list */ conv_dmask /* Arg list */ }; /* Args for im_circle. */ static im_arg_desc circle_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("cx"), IM_INPUT_INT("cy"), IM_INPUT_INT("radius"), IM_INPUT_INT("intensity") }; /* Call im_circle via arg vector. */ static int circle_vec(im_object *argv) { int cx = *((int *) argv[1]); int cy = *((int *) argv[2]); int radius = *((int *) argv[3]); int intensity = *((int *) argv[4]); return im_circle(argv[0], cx, cy, radius, intensity); } /* Description of im_circle. */ static im_function circle_desc = { "im_circle", /* Name */ "plot circle on image", 0, /* Flags */ circle_vec, /* Dispatch function */ IM_NUMBER(circle_args), /* Size of arg list */ circle_args /* Arg list */ }; /* Args for im_flood_blob_copy(). */ static im_arg_desc flood_blob_copy_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("start_x"), IM_INPUT_INT("start_y"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_flood_blob_copy() via arg vector. */ static int flood_blob_copy_vec(im_object *argv) { IMAGE *in = argv[0]; IMAGE *out = argv[1]; int start_x = *((int *) argv[2]); int start_y = *((int *) argv[3]); im_doublevec_object *dv = (im_doublevec_object *) argv[4]; PEL *ink; if (!(ink = im__vector_to_ink("im_flood_blob_copy", in, dv->n, dv->vec))) return -1; return im_flood_blob_copy(in, out, start_x, start_y, ink); } /* Description of im_flood_blob_copy(). */ static im_function flood_blob_copy_desc = { "im_flood_blob_copy", /* Name */ "flood with ink from start_x, start_y while pixel == start pixel", 0, /* Flags */ flood_blob_copy_vec, /* Dispatch function */ IM_NUMBER(flood_blob_copy_args), /* Size of arg list */ flood_blob_copy_args /* Arg list */ }; /* Args for im_flood_copy(). */ static im_arg_desc flood_copy_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("start_x"), IM_INPUT_INT("start_y"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_flood_copy() via arg vector. */ static int flood_copy_vec(im_object *argv) { IMAGE *in = argv[0]; IMAGE *out = argv[1]; int start_x = *((int *) argv[2]); int start_y = *((int *) argv[3]); im_doublevec_object *dv = (im_doublevec_object *) argv[4]; PEL *ink; if (!(ink = im__vector_to_ink("im_flood_copy", in, dv->n, dv->vec))) return -1; return im_flood_copy(in, out, start_x, start_y, ink); } /* Description of im_flood_copy(). */ static im_function flood_copy_desc = { "im_flood_copy", /* Name */ "flood with ink from start_x, start_y while pixel == start pixel", 0, /* Flags */ flood_copy_vec, /* Dispatch function */ IM_NUMBER(flood_copy_args), /* Size of arg list */ flood_copy_args /* Arg list */ }; /* Args for im_flood_other_copy(). */ static im_arg_desc flood_other_copy_args[] = { IM_INPUT_IMAGE("test"), IM_INPUT_IMAGE("mark"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("start_x"), IM_INPUT_INT("start_y"), IM_INPUT_INT("serial") }; /* Call im_flood_other_copy() via arg vector. */ static int flood_other_copy_vec(im_object *argv) { IMAGE *test = argv[0]; IMAGE *mark = argv[1]; IMAGE *out = argv[2]; int start_x = *((int *) argv[3]); int start_y = *((int *) argv[4]); int serial = *((int *) argv[5]); return im_flood_other_copy(test, mark, out, start_x, start_y, serial); } /* Description of im_flood_other_copy(). */ static im_function flood_other_copy_desc = { "im_flood_other_copy", /* Name */ "flood mark with serial from start_x, start_y while pixel == start pixel", 0, /* Flags */ flood_other_copy_vec, /* Dispatch function */ IM_NUMBER(flood_other_copy_args), /* Size of arg list */ flood_other_copy_args /* Arg list */ }; /* Args for im_insertplace. */ static im_arg_desc insertplace_args[] = { IM_RW_IMAGE("main"), IM_INPUT_IMAGE("sub"), IM_INPUT_INT("x"), IM_INPUT_INT("y") }; /* Call im_insertplace via arg vector. */ static int insertplace_vec(im_object *argv) { int x = *((int *) argv[2]); int y = *((int *) argv[3]); return im_insertplace(argv[0], argv[1], x, y); } /* Description of im_insertplace. */ static im_function insertplace_desc = { "im_insertplace", /* Name */ "draw image sub inside image main at position (x,y)", 0, /* Flags */ insertplace_vec, /* Dispatch function */ IM_NUMBER(insertplace_args), /* Size of arg list */ insertplace_args /* Arg list */ }; /* Used to be called im_remainderconst_vec, stupidly. */ static int remainderconst_vec_vec(im_object *argv) { im_doublevec_object *dv = (im_doublevec_object *) argv[2]; return im_remainder_vec(argv[0], argv[1], dv->n, dv->vec); } static im_arg_desc remainderconst_vec_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLEVEC("x") }; static im_function remainderconst_vec_desc = { "im_remainderconst_vec", /* Name */ N_("remainder after integer division by a vector of constants"), /* Description */ IM_FN_PIO | IM_FN_PTOP, /* Flags */ remainderconst_vec_vec, /* Dispatch function */ IM_NUMBER(remainderconst_vec_args), /* Size of arg list */ remainderconst_vec_args /* Arg list */ }; /* Args to im_mask2vips. */ static im_arg_desc mask2vips_args[] = { IM_INPUT_DMASK("input"), IM_OUTPUT_IMAGE("output"), }; /* Call im_mask2vips via arg vector. */ static int mask2vips_vec(im_object *argv) { im_mask_object *mo = argv[0]; return im_mask2vips(mo->mask, argv[1]); } /* Description of im_mask2vips. */ static im_function mask2vips_desc = { "im_mask2vips", /* Name */ "convert DOUBLEMASK to VIPS image", 0, /* Flags */ mask2vips_vec, /* Dispatch function */ IM_NUMBER(mask2vips_args), /* Size of arg list */ mask2vips_args /* Arg list */ }; /* Args to im_vips2mask. */ static im_arg_desc vips2mask_args[] = { IM_INPUT_IMAGE("input"), IM_OUTPUT_DMASK("output"), }; /* Call im_vips2mask via arg vector. */ static int vips2mask_vec(im_object *argv) { im_mask_object *mo = argv[1]; if (!(mo->mask = im_vips2mask(argv[0], mo->name))) return -1; return 0; } /* Description of im_vips2mask. */ static im_function vips2mask_desc = { "im_vips2mask", /* Name */ "convert VIPS image to DOUBLEMASK", 0, /* Flags */ vips2mask_vec, /* Dispatch function */ IM_NUMBER(vips2mask_args), /* Size of arg list */ vips2mask_args /* Arg list */ }; /* One image plus one constant in, one image out. */ static im_arg_desc int_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("c") }; /* One image plus one constant in, one image out. */ static im_arg_desc double_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("c") }; /* One image plus doublevec in, one image out. */ static im_arg_desc vec_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLEVEC("vec") }; /* Call im_andimage via arg vector. */ static int andimage_vec(im_object *argv) { return im_andimage(argv[0], argv[1], argv[2]); } /* Description of im_andimage. */ static im_function andimage_desc = { "im_andimage", /* Name */ "bitwise and of two images", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ andimage_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_andimageconst via arg vector. */ static int andimageconst_vec(im_object *argv) { int c = *((int *) argv[2]); return im_andimageconst(argv[0], argv[1], c); } /* Description of im_andconst. */ static im_function andimageconst_desc = { "im_andimageconst", /* Name */ "bitwise and of an image with a constant", IM_FN_PTOP | IM_FN_PIO, /* Flags */ andimageconst_vec, /* Dispatch function */ IM_NUMBER(int_in_one_out), /* Size of arg list */ int_in_one_out /* Arg list */ }; /* Call im_andimage_vec via arg vector. */ static int andimage_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_andimage_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_andimageconst. */ static im_function andimage_vec_desc = { "im_andimage_vec", /* Name */ "bitwise and of an image with a vector constant", IM_FN_PTOP | IM_FN_PIO, /* Flags */ andimage_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_orimage via arg vector. */ static int orimage_vec(im_object *argv) { return im_orimage(argv[0], argv[1], argv[2]); } /* Description of im_orimage. */ static im_function orimage_desc = { "im_orimage", /* Name */ "bitwise or of two images", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ orimage_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_orimageconst via arg vector. */ static int orimageconst_vec(im_object *argv) { int c = *((int *) argv[2]); return im_orimageconst(argv[0], argv[1], c); } /* Description of im_orimageconst. */ static im_function orimageconst_desc = { "im_orimageconst", /* Name */ "bitwise or of an image with a constant", IM_FN_PTOP | IM_FN_PIO, /* Flags */ orimageconst_vec, /* Dispatch function */ IM_NUMBER(int_in_one_out), /* Size of arg list */ int_in_one_out /* Arg list */ }; /* Call im_orimage_vec via arg vector. */ static int orimage_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_orimage_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_orimage_vec. */ static im_function orimage_vec_desc = { "im_orimage_vec", /* Name */ "bitwise or of an image with a vector constant", IM_FN_PTOP | IM_FN_PIO, /* Flags */ orimage_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_eorimage via arg vector. */ static int eorimage_vec(im_object *argv) { return im_eorimage(argv[0], argv[1], argv[2]); } /* Description of im_eorimage. */ static im_function eorimage_desc = { "im_eorimage", /* Name */ "bitwise eor of two images", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ eorimage_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_eorimageconst via arg vector. */ static int eorimageconst_vec(im_object *argv) { int c = *((int *) argv[2]); return im_eorimageconst(argv[0], argv[1], c); } /* Description of im_eorimageconst. */ static im_function eorimageconst_desc = { "im_eorimageconst", /* Name */ "bitwise eor of an image with a constant", IM_FN_PTOP | IM_FN_PIO, /* Flags */ eorimageconst_vec, /* Dispatch function */ IM_NUMBER(int_in_one_out), /* Size of arg list */ int_in_one_out /* Arg list */ }; /* Call im_eorimage_vec via arg vector. */ static int eorimage_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_eorimage_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_eorimage_vec. */ static im_function eorimage_vec_desc = { "im_eorimage_vec", /* Name */ "bitwise eor of an image with a vector constant", IM_FN_PTOP | IM_FN_PIO, /* Flags */ eorimage_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_shiftleft via arg vector. */ static int shiftleft_vec(im_object *argv) { int n = *((int *) argv[2]); return im_shiftleft(argv[0], argv[1], n); } /* Description of im_shiftleft. */ static im_function shiftleft_desc = { "im_shiftleft", /* Name */ "shift image n bits to left", IM_FN_PTOP | IM_FN_PIO, /* Flags */ shiftleft_vec, /* Dispatch function */ IM_NUMBER(int_in_one_out), /* Size of arg list */ int_in_one_out /* Arg list */ }; /* Call im_shiftleft_vec via arg vector. */ static int shiftleft_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_shiftleft_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_shiftleft_vec. */ static im_function shiftleft_vec_desc = { "im_shiftleft_vec", /* Name */ "shift image array bits to left", IM_FN_PTOP | IM_FN_PIO, /* Flags */ shiftleft_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_shiftright via arg vector. */ static int shiftright_vec(im_object *argv) { int n = *((int *) argv[2]); return im_shiftright(argv[0], argv[1], n); } /* Description of im_shiftright. */ static im_function shiftright_desc = { "im_shiftright", /* Name */ "shift integer image n bits to right", IM_FN_PTOP | IM_FN_PIO, /* Flags */ shiftright_vec, /* Dispatch function */ IM_NUMBER(int_in_one_out), /* Size of arg list */ int_in_one_out /* Arg list */ }; /* Call im_shiftright_vec via arg vector. */ static int shiftright_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_shiftright_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_shiftright_vec. */ static im_function shiftright_vec_desc = { "im_shiftright_vec", /* Name */ "shift image array bits to right", IM_FN_PTOP | IM_FN_PIO, /* Flags */ shiftright_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_equal via arg vector. */ static int equal_vec(im_object *argv) { return im_equal(argv[0], argv[1], argv[2]); } /* Description of im_equal. */ static im_function equal_desc = { "im_equal", /* Name */ "two images equal in value", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ equal_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_equalconst via arg vector. */ static int equalconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_equalconst(argv[0], argv[1], c); } /* Description of im_equalconst. */ static im_function equalconst_desc = { "im_equalconst", /* Name */ "image equals const", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ equalconst_vec, /* Dispatch function */ IM_NUMBER(double_in_one_out), /* Size of arg list */ double_in_one_out /* Arg list */ }; /* Call im_equal_vec via arg vector. */ static int equal_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_equal_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_equal_vec. */ static im_function equal_vec_desc = { "im_equal_vec", /* Name */ "image equals doublevec", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ equal_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_notequal via arg vector. */ static int notequal_vec(im_object *argv) { return im_notequal(argv[0], argv[1], argv[2]); } /* Description of im_notequal. */ static im_function notequal_desc = { "im_notequal", /* Name */ "two images not equal in value", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ notequal_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_notequalconst via arg vector. */ static int notequalconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_notequalconst(argv[0], argv[1], c); } /* Description of im_notequalconst. */ static im_function notequalconst_desc = { "im_notequalconst", /* Name */ "image does not equal const", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ notequalconst_vec, /* Dispatch function */ IM_NUMBER(double_in_one_out), /* Size of arg list */ double_in_one_out /* Arg list */ }; /* Call im_notequal_vec via arg vector. */ static int notequal_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_notequal_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_notequal_vec. */ static im_function notequal_vec_desc = { "im_notequal_vec", /* Name */ "image does not equal doublevec", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ notequal_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_less via arg vector. */ static int less_vec(im_object *argv) { return im_less(argv[0], argv[1], argv[2]); } /* Description of im_less. */ static im_function less_desc = { "im_less", /* Name */ "in1 less than in2 in value", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ less_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_lessconst via arg vector. */ static int lessconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_lessconst(argv[0], argv[1], c); } /* Description of im_lessconst. */ static im_function lessconst_desc = { "im_lessconst", /* Name */ "in less than const", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ lessconst_vec, /* Dispatch function */ IM_NUMBER(double_in_one_out), /* Size of arg list */ double_in_one_out /* Arg list */ }; /* Call im_less_vec via arg vector. */ static int less_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_less_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_less_vec. */ static im_function less_vec_desc = { "im_less_vec", /* Name */ "in less than doublevec", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ less_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_more via arg vector. */ static int more_vec(im_object *argv) { return im_more(argv[0], argv[1], argv[2]); } /* Description of im_more. */ static im_function more_desc = { "im_more", /* Name */ "in1 more than in2 in value", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ more_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_moreconst via arg vector. */ static int moreconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_moreconst(argv[0], argv[1], c); } /* Description of im_moreconst. */ static im_function moreconst_desc = { "im_moreconst", /* Name */ "in more than const", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ moreconst_vec, /* Dispatch function */ IM_NUMBER(double_in_one_out), /* Size of arg list */ double_in_one_out /* Arg list */ }; /* Call im_more_vec via arg vector. */ static int more_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_more_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_more_vec. */ static im_function more_vec_desc = { "im_more_vec", /* Name */ "in more than doublevec", /* Description */ IM_FN_PTOP | IM_FN_PIO, /* Flags */ more_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_moreeq via arg vector. */ static int moreeq_vec(im_object *argv) { return im_moreeq(argv[0], argv[1], argv[2]); } /* Description of im_moreeq. */ static im_function moreeq_desc = { "im_moreeq", /* Name */ "in1 more than or equal to in2 in value", IM_FN_PTOP | IM_FN_PIO, /* Flags */ moreeq_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_moreeqconst via arg vector. */ static int moreeqconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_moreeqconst(argv[0], argv[1], c); } /* Description of im_moreeqconst. */ static im_function moreeqconst_desc = { "im_moreeqconst", /* Name */ "in more than or equal to const", IM_FN_PTOP | IM_FN_PIO, /* Flags */ moreeqconst_vec, /* Dispatch function */ IM_NUMBER(double_in_one_out), /* Size of arg list */ double_in_one_out /* Arg list */ }; /* Call im_moreeq_vec via arg vector. */ static int moreeq_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_moreeq_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_moreeq_vec. */ static im_function moreeq_vec_desc = { "im_moreeq_vec", /* Name */ "in more than or equal to doublevec", IM_FN_PTOP | IM_FN_PIO, /* Flags */ moreeq_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* Call im_lesseq via arg vector. */ static int lesseq_vec(im_object *argv) { return im_lesseq(argv[0], argv[1], argv[2]); } /* Description of im_lesseq. */ static im_function lesseq_desc = { "im_lesseq", /* Name */ "in1 less than or equal to in2 in value", IM_FN_PTOP | IM_FN_PIO, /* Flags */ lesseq_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_lesseqconst via arg vector. */ static int lesseqconst_vec(im_object *argv) { double c = *((double *) argv[2]); return im_lesseqconst(argv[0], argv[1], c); } /* Description of im_lesseqconst. */ static im_function lesseqconst_desc = { "im_lesseqconst", /* Name */ "in less than or equal to const", IM_FN_PTOP | IM_FN_PIO, /* Flags */ lesseqconst_vec, /* Dispatch function */ IM_NUMBER(double_in_one_out), /* Size of arg list */ double_in_one_out /* Arg list */ }; /* Call im_lesseq_vec via arg vector. */ static int lesseq_vec_vec(im_object *argv) { im_doublevec_object *rv = (im_doublevec_object *) argv[2]; return im_lesseq_vec(argv[0], argv[1], rv->n, rv->vec); } /* Description of im_lesseq_vec. */ static im_function lesseq_vec_desc = { "im_lesseq_vec", /* Name */ "in less than or equal to doublevec", IM_FN_PTOP | IM_FN_PIO, /* Flags */ lesseq_vec_vec, /* Dispatch function */ IM_NUMBER(vec_in_one_out), /* Size of arg list */ vec_in_one_out /* Arg list */ }; /* If-then-else args. */ static im_arg_desc ifthenelse_args[] = { IM_INPUT_IMAGE("cond"), IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Call im_blend via arg vector. */ static int blend_vec(im_object *argv) { return im_blend(argv[0], argv[1], argv[2], argv[3]); } /* Description of im_blend. */ static im_function blend_desc = { "im_blend", /* Name */ "use cond image to blend between images in1 and in2", IM_FN_PTOP | IM_FN_PIO, /* Flags */ blend_vec, /* Dispatch function */ IM_NUMBER(ifthenelse_args), /* Size of arg list */ ifthenelse_args /* Arg list */ }; /* Call im_ifthenelse via arg vector. */ static int ifthenelse_vec(im_object *argv) { return im_ifthenelse(argv[0], argv[1], argv[2], argv[3]); } /* Description of im_ifthenelse. */ static im_function ifthenelse_desc = { "im_ifthenelse", /* Name */ "use cond image to choose pels from image in1 or in2", IM_FN_PTOP | IM_FN_PIO, /* Flags */ ifthenelse_vec, /* Dispatch function */ IM_NUMBER(ifthenelse_args), /* Size of arg list */ ifthenelse_args /* Arg list */ }; /* Call im_argb2rgba() via arg vector. */ static int argb2rgba_vec(im_object *argv) { return im_argb2rgba(argv[0], argv[1]); } /* Description of im_argb2rgba. */ static im_function argb2rgba_desc = { "im_argb2rgba", /* Name */ "convert pre-multipled argb to png-style rgba", /* Description */ IM_FN_PIO, /* Flags */ argb2rgba_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Package up all these functions. */ static im_function *deprecated_list[] = { &argb2rgba_desc, &flood_copy_desc, &flood_blob_copy_desc, &flood_other_copy_desc, &clip_desc, &c2ps_desc, &resize_linear_desc, &cmulnorm_desc, &fav4_desc, &gadd_desc, &icc_export_desc, &litecor_desc, &affine_desc, &clip2c_desc, &clip2cm_desc, &clip2d_desc, &clip2dcm_desc, &clip2f_desc, &clip2i_desc, &convsub_desc, &convf_desc, &convsepf_desc, &clip2s_desc, &clip2ui_desc, &insertplaceset_desc, &clip2us_desc, &print_desc, &slice_desc, &bernd_desc, &segment_desc, &line_desc, &thresh_desc, &convf_raw_desc, &conv_raw_desc, &contrast_surface_raw_desc, &convsepf_raw_desc, &convsep_raw_desc, &fastcor_raw_desc, &gradcor_raw_desc, &spcor_raw_desc, &lhisteq_raw_desc, &stdif_raw_desc, &rank_raw_desc, &dilate_raw_desc, &erode_raw_desc, &similarity_area_desc, &similarity_desc, &remainderconst_vec_desc, &mask2vips_desc, &vips2mask_desc, &insertplace_desc, &circle_desc, &andimage_desc, &andimageconst_desc, &andimage_vec_desc, &orimage_desc, &orimageconst_desc, &orimage_vec_desc, &eorimage_desc, &eorimageconst_desc, &eorimage_vec_desc, &shiftleft_vec_desc, &shiftleft_desc, &shiftright_vec_desc, &shiftright_desc, &blend_desc, &equal_desc, &equal_vec_desc, &equalconst_desc, &ifthenelse_desc, &less_desc, &less_vec_desc, &lessconst_desc, &lesseq_desc, &lesseq_vec_desc, &lesseqconst_desc, &more_desc, &more_vec_desc, &moreconst_desc, &moreeq_desc, &moreeq_vec_desc, &moreeqconst_desc, ¬equal_desc, ¬equal_vec_desc, ¬equalconst_desc, &quadratic_desc }; /* Package of functions. */ im_package im__deprecated = { "deprecated", IM_NUMBER(deprecated_list), deprecated_list }; libvips-8.18.2/libvips/deprecated/dispatch_types.c000066400000000000000000000411561516303661500222360ustar00rootroot00000000000000/* Define built-in VIPS types. * * J. Cupitt, 8/4/93. * * Modified: * 21/5/07 * - any length vector (Tom) * 23/8/10 * - add IM_TYPE_RW flag for im__rw_image */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include /* String containing each of the characters which can be used within a * single command line argument to separate the elements of a vector. */ #define VEC_SEPS " " /* Init function for input displays. Just a stub nowadays. */ static int input_display_init(im_object *obj, char *str) { *obj = NULL; return 0; } /* Input display type. */ im_type_desc im__input_display = { IM_TYPE_DISPLAY, /* It's a display */ 0, /* No storage needed */ IM_TYPE_ARG, /* It requires a command-line arg */ input_display_init, /* Init function */ NULL /* Destroy function */ }; /* Output display type. */ im_type_desc im__output_display = { IM_TYPE_DISPLAY, /* It's a display */ sizeof(void *), /* Memory to allocate */ IM_TYPE_OUTPUT, /* Output object */ NULL, /* Init function */ NULL /* Destroy function */ }; /* Init function for input images. */ static int input_image_init(im_object *obj, char *str) { IMAGE **im = (IMAGE **) obj; return !(*im = vips__deprecated_open_read(str, FALSE)); } /* Input image type. */ im_type_desc im__input_image = { IM_TYPE_IMAGE, /* It's an image */ 0, /* No storage needed */ IM_TYPE_ARG, /* It requires a command-line arg */ (im_init_obj_fn) input_image_init, /* Init function */ (im_dest_obj_fn) im_close /* Destroy function */ }; /* Init function for output images. */ static int output_image_init(im_object *obj, char *str) { IMAGE **im = (IMAGE **) obj; return !(*im = vips__deprecated_open_write(str)); } /* Output image type. */ im_type_desc im__output_image = { IM_TYPE_IMAGE, /* It's an image */ 0, /* No storage to be allocated */ IM_TYPE_OUTPUT | IM_TYPE_ARG, /* Flags! */ (im_init_obj_fn) output_image_init, /* Init function */ (im_dest_obj_fn) im_close /* Destroy function */ }; /* Init function for RW images. */ static int rw_image_init(im_object *obj, char *str) { IMAGE **im = (IMAGE **) obj; return !(*im = im_open(str, "rw")); } /* RW image type. */ im_type_desc im__rw_image = { IM_TYPE_IMAGE, /* It's an image */ 0, /* No storage to be allocated */ IM_TYPE_ARG | IM_TYPE_RW, /* Read-write object, needs an arg */ (im_init_obj_fn) rw_image_init, /* Init function */ (im_dest_obj_fn) im_close /* Destroy function */ }; /* im_imagevec_object destroy function. */ static int imagevec_dest(im_object obj) { im_imagevec_object *iv = obj; if (iv->vec) { int i; for (i = 0; i < iv->n; i++) if (iv->vec[i]) { im_close(iv->vec[i]); iv->vec[i] = NULL; } g_free(iv->vec); iv->vec = NULL; iv->n = 0; } return 0; } /* Init function for imagevec input. */ static int input_imagevec_init(im_object *obj, char *str) { im_imagevec_object *iv = *obj; char **strv; int nargs; int i; strv = g_strsplit(str, VEC_SEPS, -1); nargs = g_strv_length(strv); if (!(iv->vec = VIPS_ARRAY(NULL, nargs, IMAGE *))) { g_strfreev(strv); return -1; } iv->n = nargs; /* Must NULL them out in case we fail halfway though opening them all. */ for (i = 0; i < nargs; i++) iv->vec[i] = NULL; for (i = 0; i < nargs; i++) if (!(iv->vec[i] = im_open(strv[i], "rd"))) { g_strfreev(strv); return -1; } g_strfreev(strv); return 0; } /* Input image vector type. */ im_type_desc im__input_imagevec = { IM_TYPE_IMAGEVEC, /* It's an array of IMAGE */ sizeof(im_imagevec_object), /* Memory to allocate in vec build */ IM_TYPE_ARG, /* It requires a command-line arg */ input_imagevec_init, /* Init function */ imagevec_dest /* Destroy function */ }; /* Init function for masks. "str" can be NULL for output masks. */ static int mask_init(im_object *obj, char *str) { im_mask_object *mo = *obj; /* Install string, clear mask. */ if (str && !(mo->name = im_strdup(NULL, str))) return -1; mo->mask = NULL; return 0; } /* Init function for input dmasks. As above, but read in the mask. */ static int dmask_init(im_object *obj, char *str) { im_mask_object *mo = *obj; if (mask_init(obj, str)) return -1; if (!(mo->mask = im_read_dmask(str))) return -1; return 0; } /* Init function for input imasks. */ static int imask_init(im_object *obj, char *str) { im_mask_object *mo = *obj; if (mask_init(obj, str)) return -1; if (!(mo->mask = im_read_imask(str))) return -1; return 0; } /* DOUBLEMASK destroy function. */ static int dmask_dest(im_object obj) { im_mask_object *mo = obj; VIPS_FREE(mo->name); VIPS_FREEF(im_free_dmask, mo->mask); return 0; } /* INTMASK destroy function. */ static int imask_dest(im_object obj) { im_mask_object *mo = obj; VIPS_FREE(mo->name); VIPS_FREEF(im_free_imask, mo->mask); return 0; } /* As above, but save the mask first. */ static int save_dmask_dest(im_object obj) { im_mask_object *mo = obj; if (mo->mask && im_write_dmask(mo->mask)) return -1; return dmask_dest(obj); } /* As above, but save the mask first. */ static int save_imask_dest(im_object obj) { im_mask_object *mo = obj; if (mo->mask && im_write_imask(mo->mask)) return -1; return imask_dest(obj); } /* Output dmask type. */ im_type_desc im__output_dmask = { IM_TYPE_DMASK, /* It's a mask */ sizeof(im_mask_object), /* Storage for mask object */ IM_TYPE_OUTPUT | IM_TYPE_ARG, /* Flags */ mask_init, /* Init function */ save_dmask_dest /* Save and destroy function */ }; /* Input dmask type. */ im_type_desc im__input_dmask = { IM_TYPE_DMASK, /* It's a mask */ sizeof(im_mask_object), /* Storage for mask object */ IM_TYPE_ARG, /* It requires a command-line arg */ dmask_init, /* Init function */ dmask_dest /* Destroy function */ }; /* Output imask type. */ im_type_desc im__output_imask = { IM_TYPE_IMASK, /* It's a mask */ sizeof(im_mask_object), /* Storage for mask object */ IM_TYPE_OUTPUT | IM_TYPE_ARG, /* Flags */ mask_init, /* Init function */ save_imask_dest /* Save and destroy function */ }; /* Input imask type. */ im_type_desc im__input_imask = { IM_TYPE_IMASK, /* It's a mask */ sizeof(im_mask_object), /* Storage for mask object */ IM_TYPE_ARG, /* It requires a command-line arg */ imask_init, /* Init function */ imask_dest /* Destroy function */ }; /* Output dmask to screen type. Set a `print' function to get actual output. * Used for things like "stats". */ im_type_desc im__output_dmask_screen = { IM_TYPE_DMASK, /* It's a mask */ sizeof(im_mask_object), /* Storage for mask object */ IM_TYPE_OUTPUT, /* It's an output argument */ mask_init, /* Init function */ dmask_dest /* Destroy function */ }; /* Init function for double input. */ static int input_double_init(im_object *obj, char *str) { double *d = (double *) *obj; *d = g_ascii_strtod(str, NULL); return 0; } /* Input double type. */ im_type_desc im__input_double = { IM_TYPE_DOUBLE, /* It's a double */ sizeof(double), /* Memory to allocate */ IM_TYPE_ARG, /* It requires a command-line arg */ input_double_init, /* Init function */ NULL /* Destroy function */ }; /* im_doublevec_object destroy function. */ static int doublevec_dest(im_object obj) { im_doublevec_object *dv = obj; if (dv->vec) { g_free(dv->vec); dv->vec = NULL; dv->n = 0; } return 0; } /* Init function for doublevec input. */ static int input_doublevec_init(im_object *obj, char *str) { im_doublevec_object *dv = *obj; char **strv; int nargs; int i; strv = g_strsplit(str, VEC_SEPS, -1); nargs = g_strv_length(strv); if (!(dv->vec = VIPS_ARRAY(NULL, nargs, double))) { g_strfreev(strv); return -1; } dv->n = nargs; for (i = 0; i < nargs; i++) { dv->vec[i] = g_ascii_strtod(strv[i], NULL); if (errno) { vips_error_system(errno, "input_doublevec_init", _("bad double \"%s\""), strv[i]); g_strfreev(strv); return -1; } } g_strfreev(strv); return 0; } /* Input double vector type. */ im_type_desc im__input_doublevec = { IM_TYPE_DOUBLEVEC, /* It's an array of double */ sizeof(im_doublevec_object), /* Memory to allocate in vec build */ IM_TYPE_ARG, /* It requires a command-line arg */ input_doublevec_init, /* Init function */ doublevec_dest /* Destroy function */ }; /* Print function for doublevec output. */ int im__dvprint(im_object obj) { im_doublevec_object *dv = obj; int i; for (i = 0; i < dv->n; i++) printf("%G ", dv->vec[i]); printf("\n"); return 0; } /* Output double vector type. */ im_type_desc im__output_doublevec = { IM_TYPE_DOUBLEVEC, /* It's an array of double */ sizeof(im_doublevec_object), /* Memory to allocate in vec build */ IM_TYPE_OUTPUT, /* Output type */ NULL, /* Init function */ doublevec_dest /* Destroy function */ }; /* im_intvec_object destroy function. */ static int intvec_dest(im_object obj) { im_intvec_object *iv = obj; if (iv->vec) { g_free(iv->vec); iv->vec = NULL; iv->n = 0; } return 0; } /* Init function for intvec input. */ static int input_intvec_init(im_object *obj, char *str) { im_intvec_object *iv = *obj; char **strv; int nargs; int i; strv = g_strsplit(str, VEC_SEPS, -1); nargs = g_strv_length(strv); if (!(iv->vec = VIPS_ARRAY(NULL, nargs, int))) { g_strfreev(strv); return -1; } iv->n = nargs; for (i = 0; i < nargs; i++) { long int val = strtol(strv[i], NULL, 10); if (errno) { vips_error_system(errno, "input_intvec_init", _("bad integer \"%s\""), strv[i]); g_strfreev(strv); return -1; } if (INT_MAX < val || INT_MIN > val) { vips_error("input_intvec_init", "%ld overflows integer type", val); } iv->vec[i] = (int) val; } g_strfreev(strv); return 0; } /* Input int vector type. */ im_type_desc im__input_intvec = { IM_TYPE_INTVEC, /* It's an array of int */ sizeof(im_intvec_object), /* Memory to allocate in vec build */ IM_TYPE_ARG, /* It requires a command-line arg */ input_intvec_init, /* Init function */ intvec_dest /* Destroy function */ }; /* Print function for intvec output. */ int im__ivprint(im_object obj) { im_intvec_object *iv = obj; int i; for (i = 0; i < iv->n; i++) printf("%d ", iv->vec[i]); printf("\n"); return 0; } /* Output int vector type. */ im_type_desc im__output_intvec = { IM_TYPE_INTVEC, /* It's an array of int */ sizeof(im_intvec_object), /* Memory to allocate in vec build */ IM_TYPE_OUTPUT, /* Output arg */ (im_init_obj_fn) NULL, /* Init function */ (im_dest_obj_fn) intvec_dest /* Destroy function */ }; /* Init function for int input. */ static int input_int_init(im_object *obj, char *str) { int *i = (int *) *obj; if (sscanf(str, "%d", i) != 1) { vips_error("input_int", "%s", _("bad format")); return -1; } return 0; } /* Input int type. */ im_type_desc im__input_int = { IM_TYPE_INT, /* It's an int */ sizeof(int), /* Memory to allocate */ IM_TYPE_ARG, /* It requires a command-line arg */ input_int_init, /* Init function */ NULL /* Destroy function */ }; /* Init function for string input. */ static int input_string_init(im_object *obj, char *str) { if (!(*obj = (im_object) im_strdup(NULL, str))) return -1; return 0; } /* Input string type. */ im_type_desc im__input_string = { IM_TYPE_STRING, /* It's a string */ 0, /* Memory to allocate */ IM_TYPE_ARG, /* It requires a command-line arg */ input_string_init, /* Init function */ vips_free /* Destroy function */ }; /* Output string type. */ im_type_desc im__output_string = { IM_TYPE_STRING, /* It's a string */ 0, /* Memory to allocate */ IM_TYPE_OUTPUT, /* It's an output argument */ NULL, /* Init function */ vips_free /* Destroy function */ }; /* Output double type. */ im_type_desc im__output_double = { IM_TYPE_DOUBLE, /* It's a double */ sizeof(double), /* Memory to allocate */ IM_TYPE_OUTPUT, /* It's an output argument */ NULL, /* Init function */ NULL /* Destroy function */ }; /* Output complex type. */ im_type_desc im__output_complex = { IM_TYPE_COMPLEX, /* It's a complex */ 2 * sizeof(double), /* Memory to allocate */ IM_TYPE_OUTPUT, /* It's an output argument */ NULL, /* Init function */ NULL /* Destroy function */ }; /* Output int type. */ im_type_desc im__output_int = { IM_TYPE_INT, /* It's an int */ sizeof(int), /* Memory to allocate */ IM_TYPE_OUTPUT, /* It's an output argument */ NULL, /* Init function */ NULL /* Destroy function */ }; /* Print function for int output. */ int im__iprint(im_object obj) { int *i = (int *) obj; printf("%d\n", *i); return 0; } /* Print function for string output. */ int im__sprint(im_object obj) { char *s = (char *) obj; printf("%s\n", s); return 0; } /* Print function for double output. */ int im__dprint(im_object obj) { double *d = (double *) obj; printf("%G\n", *d); return 0; } /* Print function for complex output. */ int im__cprint(im_object obj) { double *d = (double *) obj; printf("%G %G\n", d[0], d[1]); return 0; } /* Statistics to stdout. */ int im__dmsprint(im_object obj) { DOUBLEMASK *mask = ((im_mask_object *) obj)->mask; double *row; int i, j; /* Print statistics band stats eg: 2 bands:b 0,1 */ printf("band minimum maximum sum " "sum^2 mean deviation\n"); for (j = 0; j < mask->ysize; j++) { row = mask->coeff + j * mask->xsize; if (j == 0) printf("all"); else printf("%2d ", j); for (i = 0; i < 6; i++) printf("%12g", row[i]); printf("\n"); } return 0; } /* GValue */ /* Init function for input gvalue. Just make a string ... will get cast to * whatever later. */ static int input_gvalue_init(im_object *obj, char *str) { GValue *value = *obj; g_value_init(value, G_TYPE_STRING); g_value_set_string(value, str); return 0; } static int gvalue_free(im_object obj) { GValue *value = obj; /* If it's just zeros (built but not used) we'll get an error if we * unset(). */ if (G_IS_VALUE(value)) g_value_unset(value); return 0; } /* Input GValue type. */ im_type_desc im__input_gvalue = { IM_TYPE_GVALUE, sizeof(GValue), /* Need some storage */ IM_TYPE_ARG, /* It requires a command-line arg */ (im_init_obj_fn) input_gvalue_init, /* Init function */ (im_dest_obj_fn) gvalue_free /* Destroy function */ }; int im__gprint(im_object obj) { GValue *value = obj; char *str_value; str_value = g_strdup_value_contents(value); printf("%s\n", str_value); g_free(str_value); return 0; } /* Init function for output gvalue. Just init to zero. */ static int output_gvalue_init(im_object *obj) { GValue *value = *obj; memset(value, 0, sizeof(GValue)); return 0; } im_type_desc im__output_gvalue = { IM_TYPE_GVALUE, sizeof(GValue), /* Need some storage */ IM_TYPE_OUTPUT, /* No arg needed (just print) */ (im_init_obj_fn) output_gvalue_init, /* Init function */ (im_dest_obj_fn) gvalue_free /* Destroy function */ }; /* Init function for input interpolate. * * This is used as a helper function by the C++ interface, so amke it public. */ int vips__input_interpolate_init(im_object *obj, char *str) { GType type = g_type_from_name("VipsInterpolate"); VipsObjectClass *class = VIPS_OBJECT_CLASS(g_type_class_ref(type)); VipsObject *object; g_assert(class); if (!(object = vips_object_new_from_string(class, str))) return -1; if (vips_object_build(object)) { g_object_unref(object); return -1; } *obj = object; return 0; } static int input_interpolate_dest(im_object obj) { g_object_unref((GObject *) obj); return 0; } im_type_desc im__input_interpolate = { IM_TYPE_INTERPOLATE, 0, /* No storage required */ IM_TYPE_ARG, /* It requires a command-line arg */ vips__input_interpolate_init, /* Init function */ input_interpolate_dest /* Destroy function */ }; libvips-8.18.2/libvips/deprecated/fits.c000066400000000000000000000043621516303661500201560ustar00rootroot00000000000000/* Read FITS files with cfitsio * * 13/12/11 * - just a compat stub now */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include int im_fits2vips(const char *filename, VipsImage *out) { VipsImage *t; if (vips_fitsload(filename, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_vips2fits(VipsImage *in, const char *filename) { if (vips_fitssave(in, filename, NULL)) return -1; return 0; } static int isfits(const char *name) { return vips_foreign_is_a("fitsload", name); } static const char *fits_suffs[] = { ".fits", NULL }; /* fits format adds no new members. */ typedef VipsFormat VipsFormatFits; typedef VipsFormatClass VipsFormatFitsClass; static void vips_format_fits_class_init(VipsFormatFitsClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "fits"; object_class->description = _("FITS"); format_class->is_a = isfits; format_class->load = im_fits2vips; format_class->save = im_vips2fits; format_class->suffs = fits_suffs; } static void vips_format_fits_init(VipsFormatFits *object) { } G_DEFINE_TYPE(VipsFormatFits, vips_format_fits, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/format.c000066400000000000000000000243021516303661500204750ustar00rootroot00000000000000/* VIPS function dispatch tables for image format load/save. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* To iterate over supported formats, we build a temp list of subclasses of * VipsFormat, sort by priority, iterate, and free. */ static void * format_add_class(VipsFormatClass *format, GSList **formats) { if (!G_TYPE_IS_ABSTRACT(G_OBJECT_CLASS_TYPE(format))) /* Append so we don't reverse the list of formats. */ *formats = g_slist_append(*formats, format); return NULL; } static gint format_compare(VipsFormatClass *a, VipsFormatClass *b) { return b->priority - a->priority; } /** * vips_format_map: (skip) * @fn: function to apply to each #VipsFormatClass * @a: user data * @b: user data * * Apply a function to every %VipsFormatClass that VIPS knows about. Formats * are presented to the function in priority order. * * Like all VIPS map functions, if @fn returns %NULL, iteration continues. If * it returns non-%NULL, iteration terminates and that value is returned. The * map function returns %NULL if all calls return %NULL. * * See also: im_slist_map(). * * Returns: the result of iteration */ void * vips_format_map(VSListMap2Fn fn, void *a, void *b) { GSList *formats; void *result; formats = NULL; (void) vips_class_map_all(g_type_from_name("VipsFormat"), (VipsClassMapFn) format_add_class, (void *) &formats); formats = g_slist_sort(formats, (GCompareFunc) format_compare); result = im_slist_map2(formats, fn, a, b); g_slist_free(formats); return result; } /* Abstract base class for image formats. */ G_DEFINE_ABSTRACT_TYPE(VipsFormat, vips_format, VIPS_TYPE_OBJECT); static void vips_format_summary_class(VipsObjectClass *object_class, VipsBuf *buf) { VipsFormatClass *class = VIPS_FORMAT_CLASS(object_class); VIPS_OBJECT_CLASS(vips_format_parent_class) ->summary_class(object_class, buf); vips_buf_appends(buf, ", "); if (class->suffs) { const char **p; vips_buf_appends(buf, "("); for (p = class->suffs; *p; p++) { vips_buf_appendf(buf, "%s", *p); if (p[1]) vips_buf_appends(buf, ", "); } vips_buf_appends(buf, ") "); } if (class->is_a) vips_buf_appends(buf, "is_a "); if (class->header) vips_buf_appends(buf, "header "); if (class->load) vips_buf_appends(buf, "load "); if (class->save) vips_buf_appends(buf, "save "); if (class->get_flags) vips_buf_appends(buf, "get_flags "); } static void vips_format_class_init(VipsFormatClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "format"; object_class->description = _("VIPS file formats"); object_class->summary_class = vips_format_summary_class; /* Hide from UI. */ object_class->deprecated = TRUE; } static void vips_format_init(VipsFormat *object) { } /** * vips_format_get_flags: * @format: format to test * @filename: file to test * * Get a set of flags for this file. * * Returns: flags for this format and file */ VipsFormatFlags vips_format_get_flags(VipsFormatClass *format, const char *filename) { return format->get_flags ? format->get_flags(filename) : 0; } /* VIPS format class. */ static const char *vips_suffs[] = { ".v", ".vips", NULL }; int im_isvips(const char *filename) { unsigned char buf[4]; if (im__get_bytes(filename, buf, 4) == 4) { if (buf[0] == 0x08 && buf[1] == 0xf2 && buf[2] == 0xa6 && buf[3] == 0xb6) /* SPARC-order VIPS image. */ return 1; else if (buf[3] == 0x08 && buf[2] == 0xf2 && buf[1] == 0xa6 && buf[0] == 0xb6) /* INTEL-order VIPS image. */ return 1; } return 0; } static int file2vips(const char *filename, IMAGE *out) { IMAGE *im; if (!(im = im_open_local(out, filename, "r")) || im_copy(im, out)) return -1; return 0; } static VipsFormatFlags vips_flags(const char *filename) { VipsFormatFlags flags; unsigned char buf[4]; flags = VIPS_FORMAT_PARTIAL; if (im__get_bytes(filename, buf, 4) == 4 && buf[0] == 0x08 && buf[1] == 0xf2 && buf[2] == 0xa6 && buf[3] == 0xb6) flags |= VIPS_FORMAT_BIGENDIAN; return flags; } /* Vips format adds no new members. */ typedef VipsFormat VipsFormatVips; typedef VipsFormatClass VipsFormatVipsClass; static int vips_format_vips_save(VipsImage *image, const char *filename) { return vips_image_write_to_file(image, filename, NULL); } static void vips_format_vips_class_init(VipsFormatVipsClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "vips"; object_class->description = _("VIPS"); format_class->priority = 200; format_class->is_a = im_isvips; format_class->header = file2vips; format_class->load = file2vips; format_class->save = vips_format_vips_save; format_class->get_flags = vips_flags; format_class->suffs = vips_suffs; } static void vips_format_vips_init(VipsFormatVips *object) { } G_DEFINE_TYPE(VipsFormatVips, vips_format_vips, VIPS_TYPE_FORMAT); /* Called on startup: register the base vips formats. */ void im__format_init(void) { extern GType vips_format_csv_get_type(void); extern GType vips_format_ppm_get_type(void); extern GType vips_format_analyze_get_type(void); extern GType vips_format_rad_get_type(void); vips_format_vips_get_type(); #ifdef HAVE_JPEG extern GType vips_format_jpeg_get_type(void); vips_format_jpeg_get_type(); #endif /*HAVE_JPEG*/ #if defined(HAVE_PNG) || defined(HAVE_SPNG) extern GType vips_format_png_get_type(void); vips_format_png_get_type(); #endif /*HAVE_PNG*/ #ifdef HAVE_LIBWEBP extern GType vips_format_webp_get_type(void); vips_format_webp_get_type(); #endif /*HAVE_LIBWEBP*/ vips_format_csv_get_type(); vips_format_ppm_get_type(); vips_format_analyze_get_type(); #ifdef HAVE_OPENEXR extern GType vips_format_exr_get_type(void); vips_format_exr_get_type(); #endif /*HAVE_OPENEXR*/ #ifdef HAVE_MATIO extern GType vips_format_mat_get_type(void); vips_format_mat_get_type(); #endif /*HAVE_MATIO*/ #ifdef HAVE_CFITSIO extern GType vips_format_fits_get_type(void); vips_format_fits_get_type(); #endif /*HAVE_CFITSIO*/ vips_format_rad_get_type(); #if defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7) extern GType vips_format_magick_get_type(void); vips_format_magick_get_type(); #endif /*HAVE_MAGICK*/ #ifdef HAVE_TIFF extern GType vips_format_tiff_get_type(void); vips_format_tiff_get_type(); #endif /*HAVE_TIFF*/ extern GType vips_format_openslide_get_type(void); vips_format_openslide_get_type(); extern GType vips_format_nifti_get_type(void); vips_format_nifti_get_type(); } /* Can this format open this file? */ static void * format_for_file_sub(VipsFormatClass *format, const char *name, const char *filename) { if (format->is_a) { if (format->is_a(filename)) return format; } else if (im_filename_suffix_match(filename, format->suffs)) return format; return NULL; } /** * vips_format_for_file: (skip) * @filename: file to find a format for * * Searches for a format you could use to load a file. * * See also: vips_format_read(), vips_format_for_name(). * * Returns: a format on success, %NULL on error */ VipsFormatClass * vips_format_for_file(const char *filename) { char name[FILENAME_MAX]; char options[FILENAME_MAX]; VipsFormatClass *format; /* Break any options off the name ... eg. "fred.tif:jpeg,tile" * etc. */ im_filename_split(filename, name, options); if (!im_existsf("%s", name)) { im_error("VipsFormat", _("file \"%s\" not found"), name); return NULL; } if (!(format = (VipsFormatClass *) vips_format_map( (VSListMap2Fn) format_for_file_sub, (void *) filename, (void *) name))) { im_error("VipsFormat", _("file \"%s\" not a known format"), name); return NULL; } return format; } /* Can we write this filename with this format? Ignore formats without a save * method. */ static void * format_for_name_sub(VipsFormatClass *format, const char *name) { if (format->save && im_filename_suffix_match(name, format->suffs)) return format; return NULL; } /** * vips_format_for_name: (skip) * @filename: name to find a format for * * Searches for a format you could use to save a file. * * See also: vips_format_write(), vips_format_for_file(). * * Returns: a format on success, %NULL on error */ VipsFormatClass * vips_format_for_name(const char *filename) { VipsFormatClass *format; if (!(format = (VipsFormatClass *) vips_format_map( (VSListMap2Fn) format_for_name_sub, (void *) filename, NULL))) { im_error("VipsFormat", _("\"%s\" is not a supported image format."), filename); return NULL; } return format; } /** * vips_format_read: * @filename: file to load * @out: write the file to this image * * Searches for a format for this file, then loads the file into @out. * * See also: vips_format_write(). * * Returns: 0 on success, -1 on error */ int vips_format_read(const char *filename, IMAGE *out) { VipsFormatClass *format; if (!(format = vips_format_for_file(filename)) || format->load(filename, out)) return -1; return 0; } /** * vips_format_write: * @in: image to write * @filename: file to write to * * Searches for a format for this name, then saves @im to it. * * See also: vips_format_read(). * * Returns: 0 on success, -1 on error */ int vips_format_write(IMAGE *in, const char *filename) { VipsFormatClass *format; if (!(format = vips_format_for_name(filename)) || format->save(in, filename)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/format_dispatch.c000066400000000000000000000234171516303661500223620ustar00rootroot00000000000000/* VIPS function dispatch tables for image format load/save. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include static int jpeg2vips_vec(im_object *argv) { char *in = argv[0]; IMAGE *out = argv[1]; if (im_jpeg2vips(in, out)) return -1; return 0; } static im_arg_desc jpeg2vips_args[] = { IM_INPUT_STRING("in"), IM_OUTPUT_IMAGE("out") }; static im_function jpeg2vips_desc = { "im_jpeg2vips", /* Name */ "convert from jpeg", /* Description */ 0, /* Flags */ jpeg2vips_vec, /* Dispatch function */ IM_NUMBER(jpeg2vips_args), /* Size of arg list */ jpeg2vips_args /* Arg list */ }; static int vips2dz_vec(im_object *argv) { IMAGE *in = argv[0]; char *out = argv[1]; if (im_vips2dz(in, out)) return -1; return 0; } static im_arg_desc vips2dz_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_STRING("out") }; static im_function vips2dz_desc = { "im_vips2dz", /* Name */ "save as deepzoom", /* Description */ 0, /* Flags */ vips2dz_vec, /* Dispatch function */ IM_NUMBER(vips2dz_args), /* Size of arg list */ vips2dz_args /* Arg list */ }; static int vips2jpeg_vec(im_object *argv) { IMAGE *in = argv[0]; char *out = argv[1]; if (im_vips2jpeg(in, out)) return -1; return 0; } static im_arg_desc vips2jpeg_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_STRING("out") }; static im_function vips2jpeg_desc = { "im_vips2jpeg", /* Name */ "convert to jpeg", /* Description */ 0, /* Flags */ vips2jpeg_vec, /* Dispatch function */ IM_NUMBER(vips2jpeg_args), /* Size of arg list */ vips2jpeg_args /* Arg list */ }; static int vips2mimejpeg_vec(im_object *argv) { IMAGE *in = argv[0]; int qfac = *((int *) argv[1]); if (im_vips2mimejpeg(in, qfac)) return -1; return 0; } static im_arg_desc vips2mimejpeg_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_INT("qfac") }; static im_function vips2mimejpeg_desc = { "im_vips2mimejpeg", /* Name */ "convert to jpeg as mime type on stdout", /* Description */ 0, /* Flags */ vips2mimejpeg_vec, /* Dispatch function */ IM_NUMBER(vips2mimejpeg_args), /* Size of arg list */ vips2mimejpeg_args /* Arg list */ }; /* Args for vips2png. */ static im_arg_desc vips2png_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_STRING("out") }; /* Call im_vips2png via arg vector. */ static int vips2png_vec(im_object *argv) { return im_vips2png(argv[0], argv[1]); } /* Description of im_vips2png. */ static im_function vips2png_desc = { "im_vips2png", /* Name */ "convert VIPS image to PNG file", /* Description */ 0, vips2png_vec, /* Dispatch function */ IM_NUMBER(vips2png_args), /* Size of arg list */ vips2png_args /* Arg list */ }; /* Args for png2vips. */ static im_arg_desc png2vips_args[] = { IM_INPUT_STRING("in"), IM_OUTPUT_IMAGE("out") }; /* Call im_png2vips via arg vector. */ static int png2vips_vec(im_object *argv) { return im_png2vips(argv[0], argv[1]); } /* Description of im_png2vips. */ static im_function png2vips_desc = { "im_png2vips", /* Name */ "convert PNG file to VIPS image", /* Description */ 0, png2vips_vec, /* Dispatch function */ IM_NUMBER(png2vips_args), /* Size of arg list */ png2vips_args /* Arg list */ }; /* Args for exr2vips. */ static im_arg_desc exr2vips_args[] = { IM_INPUT_STRING("in"), IM_OUTPUT_IMAGE("out") }; /* Call im_exr2vips via arg vector. */ static int exr2vips_vec(im_object *argv) { return im_exr2vips(argv[0], argv[1]); } /* Description of im_exr2vips. */ static im_function exr2vips_desc = { "im_exr2vips", /* Name */ "convert an OpenEXR file to VIPS", /* Description */ 0, exr2vips_vec, /* Dispatch function */ IM_NUMBER(exr2vips_args), /* Size of arg list */ exr2vips_args /* Arg list */ }; /* Args for vips2tiff. */ static im_arg_desc vips2tiff_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_STRING("out") }; /* Call im_vips2tiff via arg vector. */ static int vips2tiff_vec(im_object *argv) { return im_vips2tiff(argv[0], argv[1]); } /* Description of im_vips2tiff. */ static im_function vips2tiff_desc = { "im_vips2tiff", /* Name */ "convert VIPS image to TIFF file", /* Description */ 0, vips2tiff_vec, /* Dispatch function */ IM_NUMBER(vips2tiff_args), /* Size of arg list */ vips2tiff_args /* Arg list */ }; /* Args for magick2vips. */ static im_arg_desc magick2vips_args[] = { IM_INPUT_STRING("in"), IM_OUTPUT_IMAGE("out") }; /* Call im_magick2vips via arg vector. */ static int magick2vips_vec(im_object *argv) { return im_magick2vips(argv[0], argv[1]); } /* Description of im_magick2vips. */ static im_function magick2vips_desc = { "im_magick2vips", /* Name */ "load file with libMagick", /* Description */ 0, magick2vips_vec, /* Dispatch function */ IM_NUMBER(magick2vips_args), /* Size of arg list */ magick2vips_args /* Arg list */ }; /* Args for tiff2vips. */ static im_arg_desc tiff2vips_args[] = { IM_INPUT_STRING("in"), IM_OUTPUT_IMAGE("out") }; /* Call im_tiff2vips via arg vector. */ static int tiff2vips_vec(im_object *argv) { return im_tiff2vips(argv[0], argv[1]); } /* Description of im_tiff2vips. */ static im_function tiff2vips_desc = { "im_tiff2vips", /* Name */ "convert TIFF file to VIPS image", /* Description */ 0, tiff2vips_vec, /* Dispatch function */ IM_NUMBER(tiff2vips_args), /* Size of arg list */ tiff2vips_args /* Arg list */ }; static int analyze2vips_vec(im_object *argv) { const char *in = argv[0]; IMAGE *out = argv[1]; return im_analyze2vips(in, out); } static im_arg_desc analyze2vips_arg_types[] = { IM_INPUT_STRING("filename"), IM_OUTPUT_IMAGE("im") }; static im_function analyze2vips_desc = { "im_analyze2vips", /* Name */ "read a file in analyze format", /* Description */ 0, /* Flags */ analyze2vips_vec, /* Dispatch function */ IM_NUMBER(analyze2vips_arg_types), /* Size of arg list */ analyze2vips_arg_types /* Arg list */ }; static int csv2vips_vec(im_object *argv) { const char *in = argv[0]; IMAGE *out = argv[1]; return im_csv2vips(in, out); } static im_arg_desc csv2vips_arg_types[] = { IM_INPUT_STRING("filename"), IM_OUTPUT_IMAGE("im") }; static im_function csv2vips_desc = { "im_csv2vips", /* Name */ "read a file in csv format", /* Description */ 0, /* Flags */ csv2vips_vec, /* Dispatch function */ IM_NUMBER(csv2vips_arg_types), /* Size of arg list */ csv2vips_arg_types /* Arg list */ }; static int vips2csv_vec(im_object *argv) { IMAGE *in = argv[0]; const char *filename = argv[1]; return im_vips2csv(in, filename); } static im_arg_desc vips2csv_arg_types[] = { IM_INPUT_IMAGE("in"), IM_INPUT_STRING("filename") }; static im_function vips2csv_desc = { "im_vips2csv", /* Name */ "write an image in csv format", /* Description */ 0, /* Flags */ vips2csv_vec, /* Dispatch function */ IM_NUMBER(vips2csv_arg_types), /* Size of arg list */ vips2csv_arg_types /* Arg list */ }; static int ppm2vips_vec(im_object *argv) { const char *in = argv[0]; IMAGE *out = argv[1]; return im_ppm2vips(in, out); } static im_arg_desc ppm2vips_arg_types[] = { IM_INPUT_STRING("filename"), IM_OUTPUT_IMAGE("im") }; static im_function ppm2vips_desc = { "im_ppm2vips", /* Name */ "read a file in pbm/pgm/ppm format", /* Description */ 0, /* Flags */ ppm2vips_vec, /* Dispatch function */ IM_NUMBER(ppm2vips_arg_types), /* Size of arg list */ ppm2vips_arg_types /* Arg list */ }; static int vips2ppm_vec(im_object *argv) { IMAGE *im = argv[0]; const char *filename = argv[1]; return im_vips2ppm(im, filename); } static im_arg_desc vips2ppm_arg_types[] = { IM_INPUT_IMAGE("im"), IM_INPUT_STRING("filename") }; static im_function vips2ppm_desc = { "im_vips2ppm", /* Name */ "write a file in pbm/pgm/ppm format", /* Description */ 0, /* Flags */ vips2ppm_vec, /* Dispatch function */ IM_NUMBER(vips2ppm_arg_types), /* Size of arg list */ vips2ppm_arg_types /* Arg list */ }; static int fits2vips_vec(im_object *argv) { char *in = argv[0]; IMAGE *out = argv[1]; if (im_fits2vips(in, out)) return -1; return 0; } static im_arg_desc fits2vips_args[] = { IM_INPUT_STRING("in"), IM_OUTPUT_IMAGE("out") }; static im_function fits2vips_desc = { "im_fits2vips", /* Name */ "convert from fits", /* Description */ 0, /* Flags */ fits2vips_vec, /* Dispatch function */ IM_NUMBER(fits2vips_args), /* Size of arg list */ fits2vips_args /* Arg list */ }; /* Package up all these functions. */ static im_function *list[] = { &csv2vips_desc, &fits2vips_desc, &jpeg2vips_desc, &magick2vips_desc, &png2vips_desc, &exr2vips_desc, &ppm2vips_desc, &analyze2vips_desc, &tiff2vips_desc, &vips2csv_desc, &vips2dz_desc, &vips2jpeg_desc, &vips2mimejpeg_desc, &vips2png_desc, &vips2ppm_desc, &vips2tiff_desc }; /* Package of functions. */ im_package im__format = { "format", IM_NUMBER(list), list }; libvips-8.18.2/libvips/deprecated/freq_dispatch.c000066400000000000000000000167261516303661500220340ustar00rootroot00000000000000/* Function dispatch tables for freq_filt. * * J. Cupitt, 23/2/95 * 22/4/97 JC * - oops, im_freqflt() was wrong */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Two images in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_IMAGE("in1"), IM_INPUT_IMAGE("in2"), IM_OUTPUT_IMAGE("out") }; /* Args to im_create_fmask(). */ static im_arg_desc create_fmask_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("width"), IM_INPUT_INT("height"), IM_INPUT_INT("type"), IM_INPUT_DOUBLE("p1"), IM_INPUT_DOUBLE("p2"), IM_INPUT_DOUBLE("p3"), IM_INPUT_DOUBLE("p4"), IM_INPUT_DOUBLE("p5") }; /* Call im_create_fmask via arg vector. */ static int create_fmask_vec(im_object *argv) { int width = *((int *) argv[1]); int height = *((int *) argv[2]); int type = *((int *) argv[3]); double p1 = *((double *) argv[4]); double p2 = *((double *) argv[5]); double p3 = *((double *) argv[6]); double p4 = *((double *) argv[7]); double p5 = *((double *) argv[8]); return im_create_fmask(argv[0], width, height, type, p1, p2, p3, p4, p5); } /* Description of im_create_fmask. */ static im_function create_fmask_desc = { "im_create_fmask", /* Name */ "create frequency domain filter mask", 0, /* Flags */ create_fmask_vec, /* Dispatch function */ IM_NUMBER(create_fmask_args), /* Size of arg list */ create_fmask_args /* Arg list */ }; /* Args to im_flt_image_freq(). */ static im_arg_desc flt_image_freq_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("type"), IM_INPUT_DOUBLE("p1"), IM_INPUT_DOUBLE("p2"), IM_INPUT_DOUBLE("p3"), IM_INPUT_DOUBLE("p4"), IM_INPUT_DOUBLE("p5") }; /* Call im_flt_image_freq via arg vector. */ static int flt_image_freq_vec(im_object *argv) { int type = *((int *) argv[2]); double p1 = *((double *) argv[3]); double p2 = *((double *) argv[4]); double p3 = *((double *) argv[5]); double p4 = *((double *) argv[6]); double p5 = *((double *) argv[7]); return im_flt_image_freq(argv[0], argv[1], type, p1, p2, p3, p4, p5); } /* Description of im_flt_image_freq. */ static im_function flt_image_freq_desc = { "im_flt_image_freq", /* Name */ "frequency domain filter image", 0, /* Flags */ flt_image_freq_vec, /* Dispatch function */ IM_NUMBER(flt_image_freq_args), /* Size of arg list */ flt_image_freq_args /* Arg list */ }; /* Args to im_fractsurf(). */ static im_arg_desc fractsurf_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("size"), IM_INPUT_DOUBLE("dimension") }; /* Call im_fractsurf via arg vector. */ static int fractsurf_vec(im_object *argv) { int size = *((int *) argv[1]); double dim = *((double *) argv[2]); return im_fractsurf(argv[0], size, dim); } /* Description of im_fractsurf. */ static im_function fractsurf_desc = { "im_fractsurf", /* Name */ "generate a fractal surface of given dimension", IM_FN_TRANSFORM, /* Flags */ fractsurf_vec, /* Dispatch function */ IM_NUMBER(fractsurf_args), /* Size of arg list */ fractsurf_args /* Arg list */ }; /* Args to im_freqflt(). */ static im_arg_desc freqflt_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_IMAGE("mask"), IM_OUTPUT_IMAGE("out") }; /* Call im_freqflt via arg vector. */ static int freqflt_vec(im_object *argv) { return im_freqflt(argv[0], argv[1], argv[2]); } /* Description of im_freqflt. */ static im_function freqflt_desc = { "im_freqflt", /* Name */ "frequency-domain filter of in with mask", IM_FN_TRANSFORM, /* Flags */ freqflt_vec, /* Dispatch function */ IM_NUMBER(freqflt_args), /* Size of arg list */ freqflt_args /* Arg list */ }; /* Call im_disp_ps via arg vector. */ static int disp_ps_vec(im_object *argv) { return im_disp_ps(argv[0], argv[1]); } /* Description of im_disp_ps. */ static im_function disp_ps_desc = { "im_disp_ps", /* Name */ "make displayable power spectrum", IM_FN_TRANSFORM, /* Flags */ disp_ps_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_rotquad via arg vector. */ static int rotquad_vec(im_object *argv) { return im_rotquad(argv[0], argv[1]); } /* Description of im_rotquad. */ static im_function rotquad_desc = { "im_rotquad", /* Name */ "rotate image quadrants to move origin to centre", IM_FN_TRANSFORM, /* Flags */ rotquad_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_fwfft via arg vector. */ static int fwfft_vec(im_object *argv) { return im_fwfft(argv[0], argv[1]); } /* Description of im_fwfft. */ static im_function fwfft_desc = { "im_fwfft", /* Name */ "forward fast-fourier transform", IM_FN_TRANSFORM, /* Flags */ fwfft_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_invfft via arg vector. */ static int invfft_vec(im_object *argv) { return im_invfft(argv[0], argv[1]); } /* Description of im_invfft. */ static im_function invfft_desc = { "im_invfft", /* Name */ "inverse fast-fourier transform", IM_FN_TRANSFORM, /* Flags */ invfft_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_invfftr via arg vector. */ static int invfftr_vec(im_object *argv) { return im_invfftr(argv[0], argv[1]); } /* Description of im_invfftr. */ static im_function invfftr_desc = { "im_invfftr", /* Name */ "real part of inverse fast-fourier transform", IM_FN_TRANSFORM, /* Flags */ invfftr_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_phasecor_fft via arg vector. */ static int phasecor_fft_vec(im_object *argv) { return im_phasecor_fft(argv[0], argv[1], argv[2]); } /* Description of im_phasecor_fft. */ static im_function phasecor_fft_desc = { "im_phasecor_fft", /* Name */ "non-normalised correlation of gradient of in2 within in1", IM_FN_TRANSFORM, /* Flags */ phasecor_fft_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Package up all these functions. */ static im_function *freq_list[] = { &create_fmask_desc, &disp_ps_desc, &flt_image_freq_desc, &fractsurf_desc, &freqflt_desc, &fwfft_desc, &rotquad_desc, &invfft_desc, &phasecor_fft_desc, &invfftr_desc }; /* Package of functions. */ im_package im__freq_filt = { "freq_filt", IM_NUMBER(freq_list), freq_list }; libvips-8.18.2/libvips/deprecated/glds_funcs.c000066400000000000000000000132021516303661500213310ustar00rootroot00000000000000/* @(#) Calculates the spatial grey level differnce * @(#) matrix of an image and some of its * @(#) features. The 256x1 difference matrix of im is held by m * @(#) There should be enough margin around the box so the (dx,dy) can * @(#) access neighbouring pixels outside the box * @(#) * @(#) Usage: * @(#) int im_glds_matrix(im, m, xpos, ypos, xsize, ysize, dx, dy) * @(#) IMAGE *im, *m; * @(#) int xpos, ypos, xsize, ysize; location of the box within im * @(#) int dx, dy; displacements * @(#) * @(#) int im_glds_asm(m, asmoment) * @(#) IMAGE *m; * @(#) double *asmoment; * @(#) * @(#) int im_glds_contrast(m, contrast) * @(#) IMAGE *m; * @(#) double *contrast; * @(#) * @(#) int im_glds_entropy(m, entropy) * @(#) IMAGE *m; * @(#) double *entropy; * @(#) * @(#) int im_glds_mean(m, mean) * @(#) IMAGE *m; * @(#) double *mean; * @(#) * @(#) All functions return 0 on success and -1 on error * * Copyright: N. Dessipris, 1991 * Written on: 2/12/1991 * Modified on: * 22/7/93 JC * - im_incheck() added */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* Keep the greylevel difference matrix as a 256x1 double image */ int im_glds_matrix(IMAGE *im, IMAGE *m, int xpos, int ypos, int xsize, int ysize, int dx, int dy) { PEL *in, *cpin; int *b, *pb; double *l, *pl; int x, y; int ofs; int tmp; int norm; if (im_iocheck(im, m) == -1) return -1; if ((im->Bands != 1) || (im->BandFmt != IM_BANDFMT_UCHAR)) { im_error("im_glds_matrix", "%s", _("Wrong input")); return -1; } if ((xpos + xsize + dx > im->Xsize) || (ypos + ysize + dy > im->Ysize)) { im_error("im_glds_matrix", "%s", _("wrong args")); return -1; } if (im_cp_desc(m, im) == -1) return -1; m->Xsize = 256; m->Ysize = 1; m->BandFmt = IM_BANDFMT_DOUBLE; m->Type = IM_TYPE_B_W; if (im_setupout(m) == -1) return -1; b = (int *) calloc((unsigned) m->Xsize, sizeof(int)); l = (double *) calloc((unsigned) m->Xsize, sizeof(double)); if ((b == NULL) || (l == NULL)) { im_error("im_glds_matrix", "%s", _("calloc failed")); return -1; } in = (PEL *) im->data; in += (ypos * im->Xsize + xpos); ofs = dy * im->Xsize + dx; for (y = 0; y < ysize; y++) { cpin = in; in += im->Xsize; for (x = 0; x < xsize; x++) { tmp = abs((int) *cpin - (int) (*(cpin + ofs))); pb = (b + tmp); (*pb)++; cpin++; } } norm = xsize * ysize; pb = b; pl = l; for (x = 0; x < m->Xsize; x++) *pl++ = ((double) (*pb++)) / (double) norm; if (im_writeline(0, m, (PEL *) l) == -1) return -1; free((char *) b); free((char *) l); return 0; } /* @(#) Calculates the asmoment of the sglds matrix held by m */ int im_glds_asm(IMAGE *m, double *asmoment) { double temp, tmpasm, *in; int i; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 1 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_glds_asm", "%s", _("unable to accept input")); return -1; } tmpasm = 0.0; in = (double *) m->data; for (i = 0; i < m->Xsize; i++) { temp = *in++; tmpasm += (temp * temp); } *asmoment = tmpasm; return 0; } /* @(#) Calculates the contrast of the coocurence matrix passed in buffer */ int im_glds_contrast(IMAGE *m, double *contrast) { double tmpcon, *in; int i; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 1 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_glds_contrast", "%s", _("wrong input")); return -1; } tmpcon = 0.0; in = (double *) m->data; for (i = 0; i < m->Xsize; i++) { tmpcon += (((double) i) * ((double) i) * (*in)); in++; } *contrast = tmpcon; return 0; } /* @(#) Calculates the entropy of the glds vector passed in buffer * @(#) Function returns the entropy based on log base 2. */ int im_glds_entropy(IMAGE *m, double *entropy) { double tmpent, dtemp, *in; int i; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 1 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_glds_entropy", "%s", _("wrong input")); return -1; } tmpent = 0.0; in = (double *) m->data; for (i = 0; i < m->Xsize; i++) { if (*in != 0) { dtemp = *in; tmpent += (dtemp * log10(dtemp)); } in++; } *entropy = ((-1) * tmpent / log10(2.0)); return 0; } /* @(#) Calculates the mean of the sglds matrix passed in m */ int im_glds_mean(IMAGE *m, double *mean) { double tmpmean, *in; int i; if (im_incheck(m)) return -1; if (m->Xsize != 256 || m->Ysize != 1 || m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) { im_error("im_glds_mean", "%s", _("wrong input")); return -1; } tmpmean = 0.0; in = (double *) m->data; for (i = 0; i < m->Xsize; i++) { tmpmean += (((double) i) * (*in)); in++; } tmpmean = tmpmean / ((double) m->Xsize); *mean = tmpmean; return 0; } libvips-8.18.2/libvips/deprecated/hist_dispatch.c000066400000000000000000000434061516303661500220410ustar00rootroot00000000000000/* VIPS function dispatch tables for histogram_lut. * * J. Cupitt, 24/5/95. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* One image in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Args for im_gammacorrect. */ static im_arg_desc gammacorrect_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("exponent") }; /* Call im_gammacorrect via arg vector. */ static int gammacorrect_vec(im_object *argv) { double exp = *((double *) argv[2]); return im_gammacorrect(argv[0], argv[1], exp); } /* Description of im_gammacorrect. */ static im_function gammacorrect_desc = { "im_gammacorrect", /* Name */ "gamma-correct image", /* Description */ IM_FN_PIO, /* Flags */ gammacorrect_vec, /* Dispatch function */ IM_NUMBER(gammacorrect_args), /* Size of arg list */ gammacorrect_args /* Arg list */ }; /* Image plus number in, image out. */ static im_arg_desc heq_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("band_number") }; /* Call im_heq via arg vector. */ static int heq_vec(im_object *argv) { int bn = *((int *) argv[2]); return im_heq(argv[0], argv[1], bn); } /* Description of im_heq. */ static im_function heq_desc = { "im_heq", /* Name */ "histogram-equalise image", /* Description */ IM_FN_PIO, /* Flags */ heq_vec, /* Dispatch function */ IM_NUMBER(heq_args), /* Size of arg list */ heq_args /* Arg list */ }; static im_arg_desc histindexed_args[] = { IM_INPUT_IMAGE("index"), IM_INPUT_IMAGE("value"), IM_OUTPUT_IMAGE("out") }; /* Call im_histindexed via arg vector. */ static int histindexed_vec(im_object *argv) { return im_hist_indexed(argv[0], argv[1], argv[2]); } /* Description of im_histindexed. */ static im_function histindexed_desc = { "im_hist_indexed", /* Name */ "make a histogram with an index image", /* Description */ IM_FN_PIO, /* Flags */ histindexed_vec, /* Dispatch function */ IM_NUMBER(histindexed_args), /* Size of arg list */ histindexed_args /* Arg list */ }; /* Call im_hist via arg vector. */ static int hist_vec(im_object *argv) { int bn = *((int *) argv[2]); return im_hist(argv[0], argv[1], bn); } /* Description of im_hist. */ static im_function hist_desc = { "im_hist", /* Name */ "find and graph histogram of image", /* Description */ IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ hist_vec, /* Dispatch function */ IM_NUMBER(heq_args), /* Size of arg list */ heq_args /* Arg list */ }; /* Call im_histcum via arg vector. */ static int histcum_vec(im_object *argv) { return im_histcum(argv[0], argv[1]); } /* Description of im_histcum. */ static im_function histcum_desc = { "im_histcum", /* Name */ "turn histogram to cumulative histogram", /* Description */ IM_FN_PIO, /* Flags */ histcum_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_histnorm via arg vector. */ static int histnorm_vec(im_object *argv) { return im_histnorm(argv[0], argv[1]); } /* Description of im_histcum. */ static im_function histnorm_desc = { "im_histnorm", /* Name */ "form normalised histogram", /* Description */ IM_FN_PIO, /* Flags */ histnorm_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_histeq via arg vector. */ static int histeq_vec(im_object *argv) { return im_histeq(argv[0], argv[1]); } /* Description of im_histeq. */ static im_function histeq_desc = { "im_histeq", /* Name */ "form histogram equalistion LUT", /* Description */ IM_FN_PIO, /* Flags */ histeq_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_histgr via arg vector. */ static int histgr_vec(im_object *argv) { int bn = *((int *) argv[2]); return im_histgr(argv[0], argv[1], bn); } /* Description of im_histgr. */ static im_function histgr_desc = { "im_histgr", /* Name */ "find histogram of image", /* Description */ IM_FN_TRANSFORM, /* Flags */ histgr_vec, /* Dispatch function */ IM_NUMBER(heq_args), /* Size of arg list */ heq_args /* Arg list */ }; /* Call im_histnD() via arg vector. */ static int histnD_vec(im_object *argv) { int bins = *((int *) argv[2]); return im_histnD(argv[0], argv[1], bins); } /* Args for im_histnD(). */ static im_arg_desc histnD_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("bins") }; /* Description of im_histnD(). */ static im_function histnD_desc = { "im_histnD", /* Name */ "find 1D, 2D or 3D histogram of image", /* Description */ IM_FN_TRANSFORM, /* Flags */ histnD_vec, /* Dispatch function */ IM_NUMBER(histnD_args), /* Size of arg list */ histnD_args /* Arg list */ }; /* Call im_histplot via arg vector. */ static int histplot_vec(im_object *argv) { return im_histplot(argv[0], argv[1]); } /* Description of im_histplot. */ static im_function histplot_desc = { "im_histplot", /* Name */ "plot graph of histogram", /* Description */ IM_FN_PIO, /* Flags */ histplot_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Args for im_histspec. */ static im_arg_desc histspec_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_IMAGE("ref"), IM_OUTPUT_IMAGE("out"), }; /* Call im_histspec via arg vector. */ static int histspec_vec(im_object *argv) { return im_histspec(argv[0], argv[1], argv[2]); } /* Description of im_histspec. */ static im_function histspec_desc = { "im_histspec", /* Name */ "find histogram which will make pdf of in match ref", 0, /* Flags */ histspec_vec, /* Dispatch function */ IM_NUMBER(histspec_args), /* Size of arg list */ histspec_args /* Arg list */ }; /* Call im_hsp via arg vector. */ static int hsp_vec(im_object *argv) { return im_hsp(argv[0], argv[1], argv[2]); } /* Description of im_hsp. */ static im_function hsp_desc = { "im_hsp", /* Name */ "match stats of in to stats of ref", 0, /* Flags */ hsp_vec, /* Dispatch function */ IM_NUMBER(histspec_args), /* Size of arg list */ histspec_args /* Arg list */ }; /* Args for im_identity. */ static im_arg_desc identity_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("nbands") }; /* Call im_identity via arg vector. */ static int identity_vec(im_object *argv) { int nb = *((int *) argv[1]); return im_identity(argv[0], nb); } /* Description of im_identity. */ static im_function identity_desc = { "im_identity", /* Name */ "generate identity histogram", 0, /* Flags */ identity_vec, /* Dispatch function */ IM_NUMBER(identity_args), /* Size of arg list */ identity_args /* Arg list */ }; /* Args for im_identity_ushort. */ static im_arg_desc identity_ushort_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("nbands"), IM_INPUT_INT("size") }; /* Call im_identity_ushort via arg vector. */ static int identity_ushort_vec(im_object *argv) { int nb = *((int *) argv[1]); int sz = *((int *) argv[2]); return im_identity_ushort(argv[0], nb, sz); } /* Description of im_identity_ushort. */ static im_function identity_ushort_desc = { "im_identity_ushort", /* Name */ "generate ushort identity histogram", 0, /* Flags */ identity_ushort_vec, /* Dispatch function */ IM_NUMBER(identity_ushort_args), /* Size of arg list */ identity_ushort_args /* Arg list */ }; /* Args for im_lhisteq. */ static im_arg_desc lhisteq_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("width"), IM_INPUT_INT("height") }; /* Call im_lhisteq via arg vector. */ static int lhisteq_vec(im_object *argv) { int xw = *((int *) argv[2]); int yw = *((int *) argv[3]); return im_lhisteq(argv[0], argv[1], xw, yw); } /* Description of im_lhisteq. */ static im_function lhisteq_desc = { "im_lhisteq", /* Name */ "local histogram equalisation", IM_FN_PIO, /* Flags */ lhisteq_vec, /* Dispatch function */ IM_NUMBER(lhisteq_args), /* Size of arg list */ lhisteq_args /* Arg list */ }; /* Args for im_maplut. */ static im_arg_desc maplut_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMAGE("lut") }; /* Call im_maplut via arg vector. */ static int maplut_vec(im_object *argv) { return im_maplut(argv[0], argv[1], argv[2]); } /* Description of im_maplut. */ static im_function maplut_desc = { "im_maplut", /* Name */ "map image through LUT", IM_FN_PIO, /* Flags */ maplut_vec, /* Dispatch function */ IM_NUMBER(maplut_args), /* Size of arg list */ maplut_args /* Arg list */ }; /* Call im_project() via arg vector. */ static int project_vec(im_object *argv) { return im_project(argv[0], argv[1], argv[2]); } /* Args for im_project(). */ static im_arg_desc project_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("hout"), IM_OUTPUT_IMAGE("vout") }; /* Description of im_project(). */ static im_function project_desc = { "im_project", /* Name */ "find horizontal and vertical projections of an image", IM_FN_TRANSFORM, /* Flags */ project_vec, /* Dispatch function */ IM_NUMBER(project_args), /* Size of arg list */ project_args /* Arg list */ }; /* Args for im_stdif. */ static im_arg_desc stdif_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("m0"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("s0"), IM_INPUT_INT("xw"), IM_INPUT_INT("yw") }; /* Call im_stdif via arg vector. */ static int stdif_vec(im_object *argv) { double a = *((double *) argv[2]); double m0 = *((double *) argv[3]); double b = *((double *) argv[4]); double s0 = *((double *) argv[5]); int xw = *((int *) argv[6]); int yw = *((int *) argv[7]); return im_stdif(argv[0], argv[1], a, m0, b, s0, xw, yw); } /* Description of im_stdif. */ static im_function stdif_desc = { "im_stdif", /* Name */ "statistical differencing", IM_FN_PIO, /* Flags */ stdif_vec, /* Dispatch function */ IM_NUMBER(stdif_args), /* Size of arg list */ stdif_args /* Arg list */ }; /* Args for im_buildlut. */ static im_arg_desc buildlut_args[] = { IM_INPUT_DMASK("xyes"), IM_OUTPUT_IMAGE("lut") }; /* Call im_buildlut via arg vector. */ static int buildlut_vec(im_object *argv) { im_mask_object *mi = argv[0]; return im_buildlut(mi->mask, argv[1]); } /* Description of im_buildlut. */ static im_function buildlut_desc = { "im_buildlut", /* Name */ "generate LUT table from set of x/y positions", 0, /* Flags */ buildlut_vec, /* Dispatch function */ IM_NUMBER(buildlut_args), /* Size of arg list */ buildlut_args /* Arg list */ }; /* Args for im_invertlut. */ static im_arg_desc invertlut_args[] = { IM_INPUT_DMASK("measures"), IM_OUTPUT_IMAGE("lut"), IM_INPUT_INT("lut_size") }; /* Call im_invertlut via arg vector. */ static int invertlut_vec(im_object *argv) { im_mask_object *mi = argv[0]; int lut_size = *((int *) argv[2]); return im_invertlut(mi->mask, argv[1], lut_size); } /* Description of im_invertlut. */ static im_function invertlut_desc = { "im_invertlut", /* Name */ "generate correction table from set of measures", 0, /* Flags */ invertlut_vec, /* Dispatch function */ IM_NUMBER(invertlut_args), /* Size of arg list */ invertlut_args /* Arg list */ }; /* Args for im_tone_build. */ static im_arg_desc tone_build_args[] = { IM_OUTPUT_IMAGE("hist"), IM_INPUT_DOUBLE("Lb"), IM_INPUT_DOUBLE("Lw"), IM_INPUT_DOUBLE("Ps"), IM_INPUT_DOUBLE("Pm"), IM_INPUT_DOUBLE("Ph"), IM_INPUT_DOUBLE("S"), IM_INPUT_DOUBLE("M"), IM_INPUT_DOUBLE("H") }; /* Call im_tone_build via arg vector. */ static int tone_build_vec(im_object *argv) { double Lb = *((double *) argv[1]); double Lw = *((double *) argv[2]); double Ps = *((double *) argv[3]); double Pm = *((double *) argv[4]); double Ph = *((double *) argv[5]); double S = *((double *) argv[6]); double M = *((double *) argv[7]); double H = *((double *) argv[8]); return im_tone_build(argv[0], Lb, Lw, Ps, Pm, Ph, S, M, H); } /* Description of im_tone_build. */ static im_function tone_build_desc = { "im_tone_build", /* Name */ "create LUT for tone adjustment of LabS images", 0, /* Flags */ tone_build_vec, /* Dispatch function */ IM_NUMBER(tone_build_args), /* Size of arg list */ tone_build_args /* Arg list */ }; /* Args for im_tone_build_range. */ static im_arg_desc tone_build_range_args[] = { IM_OUTPUT_IMAGE("hist"), IM_INPUT_INT("in_max"), IM_INPUT_INT("out_max"), IM_INPUT_DOUBLE("Lb"), IM_INPUT_DOUBLE("Lw"), IM_INPUT_DOUBLE("Ps"), IM_INPUT_DOUBLE("Pm"), IM_INPUT_DOUBLE("Ph"), IM_INPUT_DOUBLE("S"), IM_INPUT_DOUBLE("M"), IM_INPUT_DOUBLE("H") }; /* Call im_tone_build_range via arg vector. */ static int tone_build_range_vec(im_object *argv) { int in_max = *((int *) argv[1]); int out_max = *((int *) argv[2]); double Lb = *((double *) argv[3]); double Lw = *((double *) argv[4]); double Ps = *((double *) argv[5]); double Pm = *((double *) argv[6]); double Ph = *((double *) argv[7]); double S = *((double *) argv[8]); double M = *((double *) argv[9]); double H = *((double *) argv[10]); return im_tone_build_range(argv[0], in_max, out_max, Lb, Lw, Ps, Pm, Ph, S, M, H); } /* Description of im_tone_build_range. */ static im_function tone_build_range_desc = { "im_tone_build_range", /* Name */ "create LUT for tone adjustment", 0, /* Flags */ tone_build_range_vec, /* Dispatch function */ IM_NUMBER(tone_build_range_args), /* Size of arg list */ tone_build_range_args /* Arg list */ }; /* Args for im_tone_analyse. */ static im_arg_desc tone_analyse_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("hist"), IM_INPUT_DOUBLE("Ps"), IM_INPUT_DOUBLE("Pm"), IM_INPUT_DOUBLE("Ph"), IM_INPUT_DOUBLE("S"), IM_INPUT_DOUBLE("M"), IM_INPUT_DOUBLE("H") }; /* Call im_tone_analyse via arg vector. */ static int tone_analyse_vec(im_object *argv) { double Ps = *((double *) argv[2]); double Pm = *((double *) argv[3]); double Ph = *((double *) argv[4]); double S = *((double *) argv[5]); double M = *((double *) argv[6]); double H = *((double *) argv[7]); return im_tone_analyse(argv[0], argv[1], Ps, Pm, Ph, S, M, H); } /* Description of im_tone_analyse. */ static im_function tone_analyse_desc = { "im_tone_analyse", /* Name */ "analyse in and create LUT for tone adjustment", 0, /* Flags */ tone_analyse_vec, /* Dispatch function */ IM_NUMBER(tone_analyse_args), /* Size of arg list */ tone_analyse_args /* Arg list */ }; /* Args for im_ismonotonic. */ static im_arg_desc ismonotonic_args[] = { IM_INPUT_IMAGE("lut"), IM_OUTPUT_INT("mono") }; /* Call im_ismonotonic via arg vector. */ static int ismonotonic_vec(im_object *argv) { int *res = (int *) argv[1]; return im_ismonotonic(argv[0], res); } /* Description of im_ismonotonic. */ static im_function ismonotonic_desc = { "im_ismonotonic", /* Name */ "test LUT for monotonicity", 0, /* Flags */ ismonotonic_vec, /* Dispatch function */ IM_NUMBER(ismonotonic_args), /* Size of arg list */ ismonotonic_args /* Arg list */ }; /* Args for im_tone_map */ static im_arg_desc tone_map_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMAGE("lut") }; /* Call im_tone_map via arg vector. */ static int tone_map_vec(im_object *argv) { return im_tone_map(argv[0], argv[1], argv[2]); } /* Description of im_tone_map. */ static im_function tone_map_desc = { "im_tone_map", /* Name */ "map L channel of LabS or LabQ image through LUT", IM_FN_PIO, /* Flags */ tone_map_vec, /* Dispatch function */ IM_NUMBER(tone_map_args), /* Size of arg list */ tone_map_args /* Arg list */ }; /* Args for im_mpercent. */ static im_arg_desc mpercent_args[] = { IM_INPUT_IMAGE("in"), IM_INPUT_DOUBLE("percent"), IM_OUTPUT_INT("thresh") }; /* Call im_mpercent via arg vector. */ static int mpercent_vec(im_object *argv) { double percent = *((double *) argv[1]); return im_mpercent(argv[0], percent, argv[2]); } /* Description of im_mpercent. */ static im_function mpercent_desc = { "im_mpercent", /* Name */ "find threshold above which there are percent values", 0, /* Flags */ mpercent_vec, /* Dispatch function */ IM_NUMBER(mpercent_args), /* Size of arg list */ mpercent_args /* Arg list */ }; /* Package up all these functions. */ static im_function *hist_list[] = { &gammacorrect_desc, &heq_desc, &hist_desc, &histcum_desc, &histeq_desc, &histindexed_desc, &histgr_desc, &histnD_desc, &histnorm_desc, &histplot_desc, &histspec_desc, &hsp_desc, &identity_desc, &identity_ushort_desc, &ismonotonic_desc, &lhisteq_desc, &mpercent_desc, &invertlut_desc, &buildlut_desc, &maplut_desc, &project_desc, &stdif_desc, &tone_analyse_desc, &tone_build_desc, &tone_build_range_desc, &tone_map_desc }; /* Package of functions. */ im_package im__histograms_lut = { "histograms_lut", IM_NUMBER(hist_list), hist_list }; libvips-8.18.2/libvips/deprecated/im_align_bands.c000066400000000000000000000050611516303661500221340ustar00rootroot00000000000000/* * Brute force align the bands of an image. * * Copyright: Nottingham Trent University * Author: Tom Vajzovic * Written on: 2008-02-04 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include /** * im_align_bands: * @in: image to align * @out: output image * * This operation uses im_phasecor_fft() to find an integer displacement to * align all image bands band 0. It is very slow and not very accurate. * * Use im_estpar() in preference: it's fast and accurate. * * See also: im_global_balancef(), im_remosaic(). * * Returns: 0 on success, -1 on error */ int im_align_bands(IMAGE *in, IMAGE *out) { #define FUNCTION_NAME "im_align_bands" if (im_piocheck(in, out)) return -1; if (1 == in->Bands) return im_copy(in, out); { IMAGE **bands = IM_ARRAY(out, 2 * in->Bands, IMAGE *); IMAGE **wrapped_bands = bands + in->Bands; double x = 0.0; double y = 0.0; int i; if (!bands || im_open_local_array(out, bands, in->Bands, FUNCTION_NAME ": bands", "p") || im_open_local_array(out, wrapped_bands + 1, in->Bands - 1, FUNCTION_NAME ": wrapped_bands", "p")) return -1; for (i = 0; i < in->Bands; ++i) if (im_extract_band(in, bands[i], i)) return -1; wrapped_bands[0] = bands[0]; for (i = 1; i < in->Bands; ++i) { IMAGE *temp = im_open(FUNCTION_NAME ": temp", "t"); double this_x, this_y, val; if (!temp || im_phasecor_fft(bands[i - 1], bands[i], temp) || im_maxpos_avg(temp, &this_x, &this_y, &val) || im_close(temp)) return -1; x += this_x; y += this_y; if (im_wrap(bands[i], wrapped_bands[i], (int) x, (int) y)) return -1; } return im_gbandjoin(wrapped_bands, out, in->Bands); } #undef FUNCTION_NAME } libvips-8.18.2/libvips/deprecated/im_analyze2vips.c000066400000000000000000000043501516303661500223220ustar00rootroot00000000000000/* Read a Analyze file. Old-style header (so called 7.5 format). * * 14/12/11 * - just a compat stub now */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include static VipsFormatFlags analyze_flags(const char *filename) { return (VipsFormatFlags) vips_foreign_flags("analyzeload", filename); } static int isanalyze(const char *filename) { return vips_foreign_is_a("analyzeload", filename); } int im_analyze2vips(const char *filename, IMAGE *out) { VipsImage *t; if (vips_analyzeload(filename, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static const char *analyze_suffs[] = { ".img", ".hdr", NULL }; typedef VipsFormat VipsFormatAnalyze; typedef VipsFormatClass VipsFormatAnalyzeClass; static void vips_format_analyze_class_init(VipsFormatAnalyzeClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "analyze"; object_class->description = _("Analyze 6.0"); format_class->is_a = isanalyze; format_class->load = im_analyze2vips; format_class->get_flags = analyze_flags; format_class->suffs = analyze_suffs; } static void vips_format_analyze_init(VipsFormatAnalyze *object) { } G_DEFINE_TYPE(VipsFormatAnalyze, vips_format_analyze, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_benchmark.c000066400000000000000000000171171516303661500216320ustar00rootroot00000000000000/* a complicated operation for testing * * 6/10/06 * - hacked in * 27/11/06 * - added im_benchmarkn() * 1/2/11 * - gtk-doc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* VIPS SMP benchmark ------------------ This is adapted from the system used to generate images for POD: http://cima.ng-london.org.uk/~john/POD Images from a 10k by 10k studio digital camera are colour processed, resized, cropped and sharpened. The original POD script was written in nip (see below). This operation is a reimplementation in vanilla C to make it easier to run (and less fragile!). This thing was originally processing images off a remote server over a 100mbit network. No attempt was made to make it quick (there was no point): you could make it a lot faster very easily. ------ benchmark in nip2 ----------- #!/home/john/vips/bin/nip2 -s // get command-line arguments image_path = argv?1; crop_id = parse_pint argv?2; crop_left = parse_pint argv?3; crop_top = parse_pint argv?4; crop_width = parse_pint argv?5; crop_height = parse_pint argv?6; width = parse_pint argv?7; height = parse_pint argv?8; sharp = parse_pint argv?9; // scale down by this much to undo photographic's relativisation darken = Vector [1.18, 1, 1]; // fudge factor in XYZ to get a match under NGC lights on uv-durable paper white_point_adjust = Vector [1.06, 1, 1.01]; // brighten by this in XYZ to get relative colorimetry brighten = 1.5; // blacks down by this much in LAB blacks_down = Vector [-2, 0, 0]; // sharpen params for 400, 300, 200 and 150 dpi // just change the size of the area we search sharpen_params_table = [ [ 11, 2.5, 40, 20, 0.5, 1.5 ], [ 7, 2.5, 40, 20, 0.5, 1.5 ], [ 5, 2.5, 40, 20, 0.5, 1.5 ], [ 3, 2.5, 40, 20, 0.5, 1.5 ] ]; // convert D65 XYZ to D50 XYZ D652D50 = recomb D652D50_direct; stage_crop in = extract_area crop_left crop_top crop_width crop_height in, crop_id != 0 = in; // fit within a width / height stage_shrink image = image, factor > 1; // never upscale = resize factor factor Interpolate.BILINEAR image { hfactor = width / get_width image; vfactor = height / get_height image; factor = min_pair hfactor vfactor; } // unphotoize, go to xyz, convert to D50, adjust white point, back to lab stage_colour in = if in?0 > 99 then Vector [100, 0, 0] else in''' { // back to absolute in' = in / darken; xyz = colour_transform_to Image_type.XYZ in'; xyz' = D652D50 xyz * white_point_adjust * brighten; in'' = colour_transform_to Image_type.LAB xyz'; // shadows down in''' = in'' + blacks_down; } stage_sharp in = (sharpen params?0 params?1 params?2 params?3 params?4 params?5 @ colour_transform_to Image_type.LABQ) in { params = sharpen_params_table?sharp; } // This was: // // stage_srgb in // = (icc_export 8 "$VIPSHOME/share/nip2/data/sRGB.icm" 1 @ // colour_transform_to Image_type.LABQ) in; // // but that uses lcms which is single-threaded. So for this benchmark, we use // VIPS's own ->sRGB converter, which is less accurate but does thread. stage_srgb in = colour_transform_to Image_type.sRGB in; main = (get_image @ stage_srgb @ stage_sharp @ stage_colour @ stage_shrink @ stage_crop @ colour_transform_to Image_type.LAB @ Image_file) image_path; ------ benchmark in nip2 ----------- */ /* The main part of the benchmark ... transform labq to labq. Chain several of * these together to get a CPU-bound operation. */ static int benchmark(IMAGE *in, IMAGE *out) { IMAGE *t[18]; double one[3] = { 1.0, 1.0, 1.0 }; double zero[3] = { 0.0, 0.0, 0.0 }; double darken[3] = { 1.0 / 1.18, 1.0, 1.0 }; double whitepoint[3] = { 1.06, 1.0, 1.01 }; double shadow[3] = { -2, 0, 0 }; double white[3] = { 100, 0, 0 }; DOUBLEMASK *d652d50 = im_create_dmaskv("d652d50", 3, 3, 1.13529, -0.0604663, -0.0606321, 0.0975399, 0.935024, -0.0256156, -0.0336428, 0.0414702, 0.994135); im_add_close_callback(out, (im_callback_fn) im_free_dmask, d652d50, NULL); return ( /* Set of descriptors for this operation. */ im_open_local_array(out, t, 18, "im_benchmark", "p") || /* Unpack to float. */ im_LabQ2Lab(in, t[0]) || /* Crop 100 pixels off all edges. */ im_extract_area(t[0], t[1], 100, 100, t[0]->Xsize - 200, t[0]->Ysize - 200) || /* Shrink by 10%, bilinear interp. */ im_affinei_all(t[1], t[2], vips_interpolate_bilinear_static(), 0.9, 0, 0, 0.9, 0, 0) || /* Find L ~= 100 areas (white surround). */ im_extract_band(t[2], t[3], 0) || im_moreconst(t[3], t[4], 99) || /* Adjust white point and shadows. */ im_lintra_vec(3, darken, t[2], zero, t[5]) || im_Lab2XYZ(t[5], t[6]) || im_recomb(t[6], t[7], d652d50) || im_lintra_vec(3, whitepoint, t[7], zero, t[8]) || im_lintra(1.5, t[8], 0.0, t[9]) || im_XYZ2Lab(t[9], t[10]) || im_lintra_vec(3, one, t[10], shadow, t[11]) || /* Make a solid white image. */ im_black(t[12], t[4]->Xsize, t[4]->Ysize, 3) || im_lintra_vec(3, zero, t[12], white, t[13]) || /* Reattach border. */ im_ifthenelse(t[4], t[13], t[11], t[14]) || /* Sharpen. */ im_Lab2LabQ(t[14], t[15]) || im_sharpen(t[15], out, 11, 2.5, 40, 20, 0.5, 1.5)); } /** * im_benchmarkn: * @in: input image * @out: output image * @n: iterations * * This operation runs a complicated set of other operations on image @in, * producing image @out. Use @n to set the number of iterations to run: a * larger number will make the operation more CPU-bound, a smaller number will * make the operation more IO-bound. * * See http://www.vips.ecs.soton.ac.uk/index.php?title=Benchmarks for a * detailed discussion of the benchmark and some sample results. * * See also: im_benchmark2(). * * Returns: 0 on success, -1 on error */ int im_benchmarkn(IMAGE *in, IMAGE *out, int n) { IMAGE *t[2]; if (n == 0) /* To sRGB. */ return im_LabQ2disp(in, out, im_col_displays(7)); else return im_open_local_array(out, t, 2, "benchmarkn", "p") || benchmark(in, t[0]) || /* Expand back to the original size again ... * benchmark does a 200 pixel crop plus a 10% shrink, * so if we chain many of them together the image gets * too small. */ im_affinei_all(t[0], t[1], vips_interpolate_bilinear_static(), (double) in->Xsize / t[0]->Xsize, 0, 0, (double) in->Ysize / t[0]->Ysize, 0, 0) || im_benchmarkn(t[1], out, n - 1); } /** * im_benchmark2: * @in: input image * @out: average image value * * This operation runs a single im_benchmarkn() and calculates the average * pixel value. It's useful if you just want to test image input. * * See also: im_benchmarkn(). * * Returns: 0 on success, -1 on error */ int im_benchmark2(IMAGE *in, double *out) { IMAGE *t; return !(t = im_open_local(in, "benchmarkn", "p")) || im_benchmarkn(in, t, 1) || im_avg(t, out); } libvips-8.18.2/libvips/deprecated/im_bernd.c000066400000000000000000000040021516303661500207570ustar00rootroot00000000000000/* @(#) Extract a tile from a pyramid as a jpeg * @(#) * @(#) int * @(#) im_bernd(const char *tiffname, * @(#) int x, int y, int w, int h) * @(#) * @(#) * @(#) Returns 0 on success and -1 on error * @(#) * * 7/5/99 JC * - from im_tiff2vips and im_vips2jpeg, plus some stuff from Steve * 11/7/01 JC * - page number now in filename * 12/5/09 * - fix signed/unsigned warning */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include static int extract(IMAGE *in, int x, int y, int w, int h) { IMAGE *t1; int len; char *buf; if (!(t1 = im_open_local(in, "im_bernd:2", "p")) || im_extract_area(in, t1, x, y, w, h) || im_vips2bufjpeg(t1, in, 75, &buf, &len)) return -1; if (fwrite(buf, sizeof(char), len, stdout) != (size_t) len) { im_error("im_bernd", "%s", _("error writing output")); return -1; } fflush(stdout); return 0; } int im_bernd(const char *tiffname, int x, int y, int w, int h) { IMAGE *in; if (!(in = im_open("im_bernd:1", "p"))) return -1; if (im_tiff2vips(tiffname, in) || extract(in, x, y, w, h)) { im_close(in); return -1; } im_close(in); return 0; } libvips-8.18.2/libvips/deprecated/im_clamp.c000066400000000000000000000065221516303661500207720ustar00rootroot00000000000000/* @(#) Function to perform black level correction given black image * @(#) designed for PAD camera single field black to apply in blocks * @(#) as each is reused for higher resolution pels (eg: 6 8 for Progres) * @(#) IM_BANDFMT_UCHAR images only. Always writes UCHAR. * @(#) int im_clamp(in, w, out, hstep, vstep) * @(#) IMAGE *in, *w, *out; int hstep, vstep; * @(#) - Compute clip(image - (black)) ie subtract black no negatives * @(#) scales for low res Progres images to replicate black value * @(#) Returns 0 on success and -1 on error * fiddle at your peril - nasty code * Copyright: 1993 KM * 20/8/93 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_clamp(IMAGE *in, IMAGE *out, IMAGE *black, int hstep, int vstep) { PEL *p, *blk, *bline, *bexp; PEL *q, *outbuf; int rep; int x, y, bnd; int temp, blacky, newblacky; if (im_iocheck(in, out)) return -1; if (in->Bbits != 8 || in->Coding != IM_CODING_NONE || in->BandFmt != IM_BANDFMT_UCHAR) { im_error("im_clamp", "%s", _("bad input format")); return -1; } if (black->Bbits != 8 || black->Coding != IM_CODING_NONE || black->BandFmt != IM_BANDFMT_UCHAR) { im_error("im_clamp", "%s", _("bad black format")); return -1; } /* Set up the output header. */ if (im_cp_desc(out, in)) return -1; if (im_setupout(out)) return -1; /* Make buffer for expanded black line */ if (!(bline = (PEL *) im_malloc(out, black->Bands * hstep * in->Xsize))) return -1; /* Make buffer we write to. */ if (!(outbuf = (PEL *) im_malloc(out, out->Bands * out->Xsize))) return -1; blacky = -1; p = (PEL *) in->data; for (y = 0; y < in->Ysize; y++) { /* calc corresponding black line - get new one if different */ newblacky = (vstep * black->Ysize - in->Ysize + y) / vstep; if (newblacky != blacky) { blacky = newblacky; /* time to expand a new black line */ blk = (PEL *) (black->data + black->Xsize * black->Bands * blacky); for (bexp = bline, x = 0; x < black->Xsize; x++) { for (rep = 0; rep < hstep; rep++) for (q = blk, bnd = 0; bnd < in->Bands; bnd++) *bexp++ = *q++; blk += black->Bands; } } /* correct a line of image */ bexp = bline; q = outbuf; for (x = 0; x < (out->Bands * out->Xsize); x++) { temp = ((int) *p++ - *bexp++); if (temp < 0) temp = 0; *q++ = (PEL) temp; } if (im_writeline(y, out, outbuf)) return -1; } /* end of a line */ return 0; } libvips-8.18.2/libvips/deprecated/im_cmulnorm.c000066400000000000000000000036661516303661500215400ustar00rootroot00000000000000/* im_cmulnorm.c * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 15/4/97 JC * - thrown away and redone in terms of im_multiply() * 9/7/02 JC * - im_sign() broken out, done in terms of that * 28/8/09 * - gtkdoc * - tiny polish */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /** * im_cmulnorm * @in1: input #IMAGE 1 * @in2: input #IMAGE 2 * @out: output #IMAGE * * im_cmulnorm() multiplies two complex images. The complex output is * normalised to 1 by dividing both the real and the imaginary part of each * pel with the norm. This is useful for phase correlation. * * This operation used to be important, but now simply calls im_multiply() * then im_sign(). * * See also: im_multiply(), im_sign(). * * Returns: 0 on success, -1 on error */ int im_cmulnorm(IMAGE *in1, IMAGE *in2, IMAGE *out) { IMAGE *t1; if (!(t1 = im_open_local(out, "im_cmulnorm:1", "p")) || im_multiply(in1, in2, t1) || im_sign(t1, out)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/im_convsub.c000066400000000000000000000215401516303661500213520ustar00rootroot00000000000000/* @(#) Function which convolves and subsamples VASARI format picture * @(#) with a mask stored in a file argument. * @(#) * @(#) int im_convsub(in, out, mask, xskip, yskip) * @(#) IMAGE *in, *out; * @(#) INTMASK *mask; details in vips.h * @(#) int xskip, yskip; is the subsamping factor along both directions * @(#) * @(#) Returns either 0 (sucess) or -1 (fail) * @(#) * @(#) Picture can have any number of channels (max 64). * @(#) It is assummed that the output picture is subsampled on * @(#) both directions by a factor of xskip horizontally and yskip vertically. * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 29/04/1991 * Modified on: */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* Create multiplication luts for all non zero elements of the original mask; * which is kept in buffer of length buffersize * cnt is needed for freeing luts */ static int im__create_int_luts(int *buffer, int buffersize, int **orig_luts, int **luts, int *cnt) { int *pbuffer; int *buf1, *buf2, *pbuf1, *pbuf2; int i, j; int min, max; int mark; /* used to mark the buffer mark = max+1 */ int counter; /* counts the no of unique elms in mask; returned in cnt*/ buf1 = (int *) calloc((unsigned) buffersize, sizeof(int)); buf2 = (int *) calloc((unsigned) buffersize, sizeof(int)); if ((buf1 == NULL) || (buf2 == NULL)) { im_error("im_create_int_luts", "%s", _("calloc failed (1)")); return -1; } pbuffer = buffer; pbuf1 = buf1; /* find max and copy mask to buf1 */ max = *pbuffer; for (i = 0; i < buffersize; i++) { if (*pbuffer > max) max = *pbuffer; *pbuf1++ = *pbuffer++; } mark = max + 1; pbuf1 = buf1; pbuf2 = buf2; counter = 0; /* find a min at a time; put it into buf2 and mark all values of * buf1 equal to found min, to INT_MAX */ for (i = 0; i < buffersize; i++) { min = mark + 1; /* force min to be greater than mark */ pbuf1 = buf1; /* find a min */ for (j = 0; j < buffersize; j++) { if (*pbuf1 < min) min = *pbuf1; pbuf1++; } if (min == mark) /* all min are found */ break; *pbuf2++ = min; counter++; pbuf1 = buf1; for (j = 0; j < buffersize; j++) /* mark values equal to min */ { if (*pbuf1 == min) *pbuf1 = mark; pbuf1++; } } /* buf2 should keep now counter unique values of the mask, descending order * Malloc counter luts and initialise them */ pbuf2 = buf2; for (i = 0; i < counter; i++) { orig_luts[i] = (int *) calloc((unsigned) 256, sizeof(int)); if (orig_luts[i] == NULL) { im_error("im_create_int_luts", "%s", _("calloc failed (2)")); return -1; } for (j = 0; j < 256; j++) *(orig_luts[i] + j) = j * (*pbuf2); pbuf2++; } pbuffer = buffer; for (i = 0; i < buffersize; i++) { j = 0; while (1) { if (*(buf2 + j) == *pbuffer) { luts[i] = orig_luts[j]; break; } j++; } pbuffer++; } /* free buf1, buf2 */ free((char *) buf1); free((char *) buf2); *cnt = counter; return 0; } int im_convsub(IMAGE *in, IMAGE *out, INTMASK *m, int xskip, int yskip) { int x; /* horizontal direction */ int y; /* vertical direction */ int n_clipped = 0; int p_clipped = 0; int i, b; PEL **pnts, **cpnt1s, **cpnt2s; /* to keep pointers to data */ PEL **pnt, **cpnt1, **cpnt2; /* to keep pointers to data */ PEL *input, *line, *cpline; int *pm; /* pointer to mask coefficients */ int count; /* no of non zero elms of the original mask */ int *newm, *pnewm; /* pointer to non zero mask coefficients */ int os; /* size of an input line of data */ int ms; /* is m->xsize * m->ysize */ int **lut_orig, **lut; int lutcnt = 0; int rounding, sum; int tempsize; /* Check input, output and vars */ if ((xskip < 1) || (yskip < 1)) { im_error("im_convsub", "%s", _("xskip and yskip must be >= 1")); return -1; } if (im_iocheck(in, out) == -1) return -1; if ((in->Coding != IM_CODING_NONE) || (in->BandFmt != IM_BANDFMT_UCHAR)) { im_error("im_convsub", "%s", _("nput should be unsigned char uncoded")); return -1; } /* Prepare output */ if (im_cp_desc(out, in) == -1) return -1; tempsize = in->Xsize / xskip; while (1) { if (tempsize * xskip + m->xsize < in->Xsize) break; else tempsize--; if (tempsize < 0) break; } out->Xsize = tempsize; tempsize = in->Ysize / yskip; while (1) { if (tempsize * yskip + m->ysize < in->Ysize) break; else tempsize--; if (tempsize < 0) break; } out->Ysize = tempsize; if ((out->Xsize < 2) || (out->Ysize < 2)) { im_error("im_convsub", "%s", _("too small output sizes")); return -1; } if (im_setupout(out) == -1) return -1; /* Malloc one line of output data */ os = out->Xsize * out->Bands; if ((line = (PEL *) calloc((unsigned) os, sizeof(char))) == NULL) { im_error("im_convsub", "%s", _("unable to calloc(1)")); return -1; } /* Malloc pointers and put them at correct location */ ms = m->xsize * m->ysize; count = 0; /* exclude the non-zero elms */ pm = m->coeff; for (i = 0; i < ms; i++) { if (*pm++ != 0) count++; } if (((newm = (int *) calloc((unsigned) count, sizeof(int))) == NULL) || ((pnts = (PEL **) calloc((unsigned) count, sizeof(char *))) == NULL) || ((cpnt1s = (PEL **) calloc((unsigned) count, sizeof(char *))) == NULL) || ((cpnt2s = (PEL **) calloc((unsigned) count, sizeof(char *))) == NULL)) { im_error("im_convsub", "%s", _("unable to calloc(2)")); return -1; } pnt = pnts; cpnt1 = cpnt1s; cpnt2 = cpnt2s; /* copy the non-zero elms of the original mask and set pointers */ i = 0; input = (PEL *) in->data; pm = m->coeff; pnewm = newm; for (y = 0; y < m->ysize; y++) { for (x = 0; x < m->xsize; x++) { if (*pm != 0) { *pnewm++ = *pm; pnt[i] = (input + (x + y * in->Xsize) * in->Bands); i++; } pm++; } } if (i != count) { im_error("im_convsub", "%s", _("impossible state")); return -1; } /* Malloc pointers; not all lut_orig are used necessarily */ lut_orig = (int **) calloc((unsigned) count, sizeof(int **)); lut = (int **) calloc((unsigned) count, sizeof(int **)); if ((lut == NULL) || (lut_orig == NULL)) { im_error("im_conv", "%s", _("unable to calloc(1)")); return -1; } /* Create luts; count is needed for freeing pointers. Not all lut_orig are used * if zero elms are detected. */ if (im__create_int_luts(newm, count, lut_orig, lut, &lutcnt) == -1) { im_error("im_convsub", "%s", _("im_create_int_luts failed")); return -1; } rounding = m->scale / 2; /* Output out->Ysize processed lines */ for (y = 0; y < out->Ysize; y++) { cpline = line; for (i = 0; i < count; i++) { cpnt1[i] = pnt[i]; /* skip yskip input lines */ pnt[i] += (in->Xsize * in->Bands * yskip); } /* process out->Xsize points */ for (x = 0; x < out->Xsize; x++) { for (i = 0; i < count; i++) { /* skip xskip elms */ cpnt2[i] = cpnt1[i]; cpnt1[i] += xskip * in->Bands; } for (b = 0; b < out->Bands; b++) { sum = 0; for (i = 0; i < count; i++) { /* core of convolution */ sum += *(lut[i] + (*cpnt2[i])); cpnt2[i]++; } sum = ((sum + rounding) / m->scale) + m->offset; if (sum < (int) 0) { n_clipped++; sum = (int) 0; } else if (sum > (int) 255) { p_clipped++; sum = (int) 255; } *cpline++ = (unsigned char) sum; } } /* Output the calculated line */ if (im_writeline(y, out, (PEL *) line) == -1) { free((char *) line); free((char *) newm); free((char *) pnts); free((char *) cpnt1s); free((char *) cpnt2s); for (i = 0; i < lutcnt; i++) free((char *) lut_orig[i]); free((char *) lut_orig); free((char *) lut); return -1; } } /* end of the for (..y..) loop */ if (n_clipped || p_clipped) fprintf(stderr, "im_convsub: %d pels over 255 and %d under 0 clipped\n", p_clipped, n_clipped); free((char *) line); free((char *) newm); free((char *) pnts); free((char *) cpnt1s); free((char *) cpnt2s); for (i = 0; i < lutcnt; i++) free((char *) lut_orig[i]); free((char *) lut_orig); free((char *) lut); return 0; } libvips-8.18.2/libvips/deprecated/im_csv2vips.c000066400000000000000000000053101516303661500214470ustar00rootroot00000000000000/* Read a csv file. * * 16/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "../foreign/pforeign.h" int im_csv2vips(const char *filename, IMAGE *out) { /* Read options. */ int start_skip = 0; char *whitespace = " "; char *separator = ";,\t"; int lines = -1; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p, *q, *r; VipsImage *x; /* Parse mode string. */ im_filename_split(filename, name, mode); p = &mode[0]; while ((q = im_getnextoption(&p))) { if (im_isprefix("ski", q) && (r = im_getsuboption(q))) start_skip = atoi(r); else if (im_isprefix("whi", q) && (r = im_getsuboption(q))) whitespace = r; else if (im_isprefix("sep", q) && (r = im_getsuboption(q))) separator = r; else if (im_isprefix("lin", q) && (r = im_getsuboption(q))) lines = atoi(r); } if (vips_csvload(name, &x, "skip", start_skip, "lines", lines, "whitespace", whitespace, "separator", separator, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } static const char *csv_suffs[] = { ".csv", NULL }; /* csv format adds no new members. */ typedef VipsFormat VipsFormatCsv; typedef VipsFormatClass VipsFormatCsvClass; static void vips_format_csv_class_init(VipsFormatCsvClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "csv"; object_class->description = _("CSV"); format_class->load = im_csv2vips; format_class->save = im_vips2csv; format_class->suffs = csv_suffs; } static void vips_format_csv_init(VipsFormatCsv *object) { } G_DEFINE_TYPE(VipsFormatCsv, vips_format_csv, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_debugim.c000066400000000000000000000065211516303661500213110ustar00rootroot00000000000000/* @(#) Function which prints in stdout the values of a picture * @(#) * @(#) For debuging only * @(#) is either memory mapped or in a buffer. * @(#) * @(#) void * @(#) im_debugim(in) * @(#) IMAGE *in; * @(#) * * Copyright: 1991 N. Dessipris * * Author: N. Dessipris * Written on: 18/03/1991 * Modified on: * 15/4/93 J.Cupitt * - returns int, not void now, so error messages work * - detects im->data invalid. * 15/4/93 J.Cupitt * - uses %g format, not %f for printf() * 23/7/93 JC * - im_incheck() added */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include int im_debugim(IMAGE *in) { /* Check our args. */ if (im_incheck(in)) return -1; if (in->Coding != IM_CODING_NONE) { im_error("im_debugim", "%s", _("input must be uncoded")); return -1; } /* What type? First define the loop we want to perform for all types. */ #define loopuc(TYPE) \ { \ TYPE *p = (TYPE *) in->data; \ int x, y, z; \ \ for (y = 0; y < in->Ysize; y++) { \ for (x = 0; x < in->Xsize; x++) { \ for (z = 0; z < in->Bands; z++) { \ fprintf(stderr, "%4d", (TYPE) *p++); \ } \ } \ fprintf(stderr, "\n"); \ } \ } #define loop(TYPE) \ { \ TYPE *p = (TYPE *) in->data; \ int x, y, z; \ \ for (y = 0; y < in->Ysize; y++) { \ for (x = 0; x < in->Xsize; x++) { \ for (z = 0; z < in->Bands; z++) { \ fprintf(stderr, "%g\t", (double) *p++); \ } \ } \ fprintf(stderr, "\n"); \ } \ } #define loopcmplx(TYPE) \ { \ TYPE *p = (TYPE *) in->data; \ int x, y, z; \ \ for (y = 0; y < in->Ysize; y++) { \ for (x = 0; x < in->Xsize; x++) { \ for (z = 0; z < in->Bands; z++) { \ fprintf(stderr, "re=%g\t", (double) *p++); \ fprintf(stderr, "im=%g\t", (double) *p++); \ } \ } \ fprintf(stderr, "\n"); \ } \ } /* Now generate code for all types. */ switch (in->BandFmt) { case IM_BANDFMT_UCHAR: loopuc(unsigned char); break; case IM_BANDFMT_CHAR: loop(char); break; case IM_BANDFMT_USHORT: loop(unsigned short); break; case IM_BANDFMT_SHORT: loop(short); break; case IM_BANDFMT_UINT: loop(unsigned int); break; case IM_BANDFMT_INT: loop(int); break; case IM_BANDFMT_FLOAT: loop(float); break; case IM_BANDFMT_DOUBLE: loop(double); break; case IM_BANDFMT_COMPLEX: loopcmplx(float); break; case IM_BANDFMT_DPCOMPLEX: loopcmplx(double); break; default: im_error("im_debugim", "%s", _("unknown input format")); return -1; } return 0; } libvips-8.18.2/libvips/deprecated/im_dif_std.c000066400000000000000000000061631516303661500213130ustar00rootroot00000000000000/* @(#) Program to calculate the stdev of the differnce image * @(#) at a given displacement vector * * Written : 25/11/1987 * Author : N. Dessipris * Updated : 2/12/1991 * 22/7/93 JC * - im_incheck() added */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include static int im__mean_std_int_buffer(int *buffer, int size, double *pmean, double *pstd) { double mean, std; register int i; int sumf; int temp; int *pbuffer; int sumf2; double correction; /* calulates the correction term for the variance */ double variance; /* = (sumf2 - correction)/n */ if (size <= 0) { im_error("im_mean_std_int_buffer", "%s", _("wrong args")); return -1; } mean = 0.0; std = 0.0; sumf = 0; sumf2 = 0; pbuffer = buffer; for (i = 0; i < size; i++) { temp = *pbuffer++; sumf += temp; sumf2 += (temp * temp); } correction = ((double) (sumf * sumf)) / ((double) size); mean = ((double) sumf) / ((double) size); variance = (sumf2 - correction) / ((double) size); std = sqrt(variance); *pmean = mean; *pstd = std; return 0; } int im_dif_std(IMAGE *im, int xpos, int ypos, int xsize, int ysize, int dx, int dy, double *pmean, double *pstd) { PEL *input, *cpinput; double m, s; int *buf, *pbuf; int x, y; int ofst, bufsize; if (im_incheck(im)) return -1; if ((im->Bands != 1) || (im->BandFmt != IM_BANDFMT_UCHAR)) { im_error("im_dif_std", "%s", _("Unable to accept input")); return -1; } if ((xpos + xsize + dx > im->Xsize) || (ypos + ysize + dy > im->Ysize)) { im_error("im_dif_std", "%s", _("wrong args")); return -1; } bufsize = xsize * ysize; buf = (int *) calloc((unsigned) bufsize, sizeof(int)); if (buf == NULL) { im_error("im_dif_std", "%s", _("calloc failed")); return -1; } input = (PEL *) im->data; input += (ypos * im->Xsize + xpos); ofst = dy * im->Xsize + dx; pbuf = buf; for (y = 0; y < ysize; y++) { cpinput = input; input += im->Xsize; for (x = 0; x < xsize; x++) { *pbuf++ = ((int) (*cpinput)) - ((int) (*(cpinput + ofst))); cpinput++; } } m = 0.0; s = 0.0; if (im__mean_std_int_buffer(buf, bufsize, &m, &s)) { free((char *) buf); return -1; } free((char *) buf); *pmean = m; *pstd = s; return 0; } libvips-8.18.2/libvips/deprecated/im_exr2vips.c000066400000000000000000000047441516303661500214640ustar00rootroot00000000000000/* Convert OpenEXR to VIPS * * 17/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "../foreign/pforeign.h" int im_exr2vips(const char *filename, IMAGE *out) { #ifdef HAVE_OPENEXR return vips__openexr_read(filename, out); #else vips_error("im_exr2vips", "%s", _("no OpenEXR support in your libvips")); return -1; #endif /*HAVE_OPENEXR*/ } static const char *exr_suffs[] = { ".exr", NULL }; static VipsFormatFlags exr_flags(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return (VipsFormatFlags) vips_foreign_flags("openexrload", filename); } static int isexr(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return vips_foreign_is_a("openexrload", filename); } /* exr format adds no new members. */ typedef VipsFormat VipsFormatExr; typedef VipsFormatClass VipsFormatExrClass; static void vips_format_exr_class_init(VipsFormatExrClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "exr"; object_class->description = _("OpenEXR"); format_class->is_a = isexr; format_class->load = im_exr2vips; format_class->get_flags = exr_flags; format_class->suffs = exr_suffs; } static void vips_format_exr_init(VipsFormatExr *object) { } G_DEFINE_TYPE(VipsFormatExr, vips_format_exr, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_fav4.c000066400000000000000000000044111516303661500205310ustar00rootroot00000000000000/* @(#) Optimised 4 frame average Copyright (C) 1992, Kirk Martinez, History of Art Dept, Birkbeck College */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #define ARGS "fav4: frame average 4 frames\nARGS: im1 im2 im3 im4 outfile" #define NFRAMES 4 /** * im_fav4: * @in: array of 4 input #IMAGE s * @out: output #IMAGE * * Average four identical images. * * Deprecated. */ int im_fav4(IMAGE **in, IMAGE *out) { PEL *result, *buffer, *p1, *p2, *p3, *p4; int x, y; int linebytes, PICY; /* check IMAGEs parameters */ if (im_iocheck(in[1], out)) return -1; /* BYTE images only! */ if ((in[0]->BandFmt != IM_BANDFMT_CHAR) && (in[0]->BandFmt != IM_BANDFMT_UCHAR)) return -1; if (im_cp_desc(out, in[1]) == -1) /* copy image descriptors */ return -1; if (im_setupout(out) == -1) return -1; linebytes = in[0]->Xsize * in[0]->Bands; PICY = in[0]->Ysize; buffer = (PEL *) im_malloc(NULL, linebytes); memset(buffer, 0, linebytes); p1 = (PEL *) in[0]->data; p2 = (PEL *) in[1]->data; p3 = (PEL *) in[2]->data; p4 = (PEL *) in[3]->data; for (y = 0; y < PICY; y++) { result = buffer; /* average 4 pels with rounding, for whole line*/ for (x = 0; x < linebytes; x++) { *result++ = (PEL) ((int) ((int) *p1++ + (int) *p2++ + (int) *p3++ + (int) *p4++ + 2) >> 2); } im_writeline(y, out, buffer); } im_free(buffer); return 0; } libvips-8.18.2/libvips/deprecated/im_freq_mask.c000066400000000000000000000112711516303661500216430ustar00rootroot00000000000000/* Create masks and filter with them. * * Copyright: N. Dessipris 1991, * Written on: Nov 1991 * Updated on: Dec 1991 * 20/9/95 JC * - modernised * 22/3/10 * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include /* Make a mask image. */ static int build_freq_mask(IMAGE *out, int xs, int ys, ImMaskType flag, va_list ap) { /* May be fewer than 4 args ... but extract them all anyway. Should be * safe. */ double p0 = va_arg(ap, double); double p1 = va_arg(ap, double); double p2 = va_arg(ap, double); double p3 = va_arg(ap, double); double p4 = va_arg(ap, double); VipsImage *t; switch (flag) { case IM_MASK_IDEAL_HIGHPASS: if (vips_mask_ideal(&t, xs, ys, p0, NULL)) return -1; break; case IM_MASK_IDEAL_LOWPASS: if (vips_mask_ideal(&t, xs, ys, p0, "reject", TRUE, NULL)) return -1; break; case IM_MASK_BUTTERWORTH_HIGHPASS: if (vips_mask_butterworth(&t, xs, ys, p0, p1, p2, NULL)) return -1; break; case IM_MASK_BUTTERWORTH_LOWPASS: if (vips_mask_butterworth(&t, xs, ys, p0, p1, p2, "reject", TRUE, NULL)) return -1; break; case IM_MASK_GAUSS_HIGHPASS: if (vips_mask_gaussian(&t, xs, ys, p0, p1, NULL)) return -1; break; case IM_MASK_GAUSS_LOWPASS: if (vips_mask_gaussian(&t, xs, ys, p0, p1, "reject", TRUE, NULL)) return -1; break; case IM_MASK_IDEAL_RINGPASS: if (vips_mask_ideal_ring(&t, xs, ys, p0, p1, NULL)) return -1; break; case IM_MASK_IDEAL_RINGREJECT: if (vips_mask_ideal_ring(&t, xs, ys, p0, p1, "reject", TRUE, NULL)) return -1; break; case IM_MASK_BUTTERWORTH_RINGPASS: if (vips_mask_butterworth_ring(&t, xs, ys, p0, p1, p2, p3, NULL)) return -1; break; case IM_MASK_BUTTERWORTH_RINGREJECT: if (vips_mask_butterworth_ring(&t, xs, ys, p0, p1, p2, p3, "reject", TRUE, NULL)) return -1; break; case IM_MASK_GAUSS_RINGPASS: if (vips_mask_gaussian_ring(&t, xs, ys, p0, p1, p2, NULL)) return -1; break; case IM_MASK_GAUSS_RINGREJECT: if (vips_mask_gaussian_ring(&t, xs, ys, p0, p1, p2, "reject", TRUE, NULL)) return -1; break; case IM_MASK_FRACTAL_FLT: if (vips_mask_fractal(&t, xs, ys, p0, NULL)) return -1; break; case IM_MASK_IDEAL_BANDPASS: if (vips_mask_ideal_band(&t, xs, ys, p0, p1, p2, NULL)) return -1; break; case IM_MASK_IDEAL_BANDREJECT: if (vips_mask_ideal_band(&t, xs, ys, p0, p1, p2, "reject", TRUE, NULL)) return -1; break; case IM_MASK_BUTTERWORTH_BANDPASS: if (vips_mask_butterworth_band(&t, xs, ys, p0, p1, p2, p3, p4, NULL)) return -1; break; case IM_MASK_BUTTERWORTH_BANDREJECT: if (vips_mask_butterworth_band(&t, xs, ys, p0, p1, p2, p3, p4, "reject", TRUE, NULL)) return -1; break; case IM_MASK_GAUSS_BANDPASS: if (vips_mask_gaussian_band(&t, xs, ys, p0, p1, p2, p3, NULL)) return -1; break; case IM_MASK_GAUSS_BANDREJECT: if (vips_mask_gaussian_band(&t, xs, ys, p0, p1, p2, p3, "reject", TRUE, NULL)) return -1; break; default: im_error("im_freq_mask", "%s", _("unimplemented mask type")); return -1; } if (im_copy(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_flt_image_freq(IMAGE *in, IMAGE *out, ImMaskType flag, ...) { IMAGE *mask = im_open_local(out, "tempmask", "p"); va_list ap; if (!mask) return -1; /* Generate mask. */ va_start(ap, flag); if (build_freq_mask(mask, in->Xsize, in->Ysize, flag, ap)) return -1; va_end(ap); if (im_freqflt(in, mask, out)) return -1; return 0; } int im_create_fmask(IMAGE *out, int xsize, int ysize, ImMaskType flag, ...) { va_list ap; va_start(ap, flag); if (build_freq_mask(out, xsize, ysize, flag, ap)) return -1; va_end(ap); return 0; } libvips-8.18.2/libvips/deprecated/im_gadd.c000066400000000000000000000057511516303661500206000ustar00rootroot00000000000000/* @(#) Generalised addition of two vasari images using the routines * @(#) im_gaddim or im_gfadd * @(#) Convention to ease the complilation time. * @(#) Function im_gadd() assumes that the both input files * @(#) are either memory mapped or in a buffer. * @(#) Images must have the same no of bands and must not be complex * @(#) No check for overflow is carried out. * @(#) * @(#) int im_gadd(a, in1, b, in2, c, out) * @(#) IMAGE *in1, *in2, *out; * @(#) double a, b, c; * @(#) * @(#) Returns 0 on success and -1 on error * @(#) * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_gfadd(double a, IMAGE *in1, double b, IMAGE *in2, double c, IMAGE *out); int im_gaddim(double a, IMAGE *in1, double b, IMAGE *in2, double c, IMAGE *out); /* This function works on either mmaped files or on images in buffer */ /** * im_gadd: * * Deprecated. */ int im_gadd(double a, IMAGE *in1, double b, IMAGE *in2, double c, IMAGE *out) { int flagint = 0; int flagfloat = 0; int value = 0; switch (in1->BandFmt) { case IM_BANDFMT_UCHAR: case IM_BANDFMT_CHAR: case IM_BANDFMT_USHORT: case IM_BANDFMT_SHORT: case IM_BANDFMT_UINT: case IM_BANDFMT_INT: flagint = 1; break; case IM_BANDFMT_FLOAT: case IM_BANDFMT_DOUBLE: flagfloat = 1; break; default: im_error("im_gadd", "%s", _("Unable to accept image1")); return -1; } switch (in2->BandFmt) { case IM_BANDFMT_UCHAR: case IM_BANDFMT_CHAR: case IM_BANDFMT_USHORT: case IM_BANDFMT_SHORT: case IM_BANDFMT_UINT: case IM_BANDFMT_INT: flagint = 1; break; case IM_BANDFMT_FLOAT: case IM_BANDFMT_DOUBLE: flagfloat = 1; break; default: im_error("im_gadd", "%s", _("Unable to accept image1")); return -1; } /* Select output routines */ if (flagfloat == 1) { value = im_gfadd(a, in1, b, in2, c, out); if (value == -1) return -1; } else if (flagint == 1) { value = im_gaddim(a, in1, b, in2, c, out); if (value == -1) return -1; } else assert(0); return 0; } libvips-8.18.2/libvips/deprecated/im_gaddim.c000066400000000000000000000160421516303661500211210ustar00rootroot00000000000000/* @(#) Generalised addition of two vasari images. * @(#)Inputs, outputs are neither float nor double * @(#) Result at each point is a*in1 + b*in2 + c * @(#) Result depends on inputs, rounding is carried out; * @(#) Function im_gaddim() assumes that the both input files * @(#) are either memory mapped or in a buffer. * @(#) Images must have the same no of bands and must not be complex * @(#) No check for overflow is done; * @(#) * @(#) int im_gaddim(a, in1, b, in2, c, out) * @(#) double a, b, c; * @(#) IMAGE *in1, *in2, *out; * @(#) * @(#) Returns 0 on success and -1 on error * @(#) * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* This function works on either mmaped files or on images in buffer */ /* uchar char ushort short uint int */ static int array[6][6] = { /* uchar */ { 2, 3, 2, 3, 4, 5 }, /* char */ { 3, 3, 3, 3, 5, 5 }, /* ushort */ { 2, 3, 2, 3, 4, 5 }, /* short */ { 3, 3, 3, 3, 5, 5 }, /* uint */ { 4, 5, 4, 5, 4, 5 }, /* int */ { 5, 5, 5, 5, 5, 5 } }; #define select_tmp2_for_out_int(OUT) \ case IM_BANDFMT_UCHAR: \ select_tmp1_for_out_int(unsigned char, OUT); \ break; \ case IM_BANDFMT_CHAR: \ select_tmp1_for_out_int(signed char, OUT); \ break; \ case IM_BANDFMT_USHORT: \ select_tmp1_for_out_int(unsigned short, OUT); \ break; \ case IM_BANDFMT_SHORT: \ select_tmp1_for_out_int(signed short, OUT); \ break; \ case IM_BANDFMT_UINT: \ select_tmp1_for_out_int(unsigned int, OUT); \ break; \ case IM_BANDFMT_INT: \ select_tmp1_for_out_int(signed int, OUT); \ break; \ \ default: \ im_error("im_gaddim", "Wrong tmp2 format(1)"); \ free(line); \ return -1; #define select_tmp1_for_out_int(IN2, OUT) \ switch (tmp1->BandFmt) { \ case IM_BANDFMT_UINT: \ loop(unsigned int, IN2, OUT); \ break; \ case IM_BANDFMT_INT: \ loop(int, IN2, OUT); \ break; \ default: \ im_error("im_gaddim", "Wrong tmp2 format(2)"); \ free(line); \ return -1; \ } #define select_tmp2_for_out_short(OUT) \ case IM_BANDFMT_UCHAR: \ select_tmp1_for_out_short(unsigned char, OUT); \ break; \ case IM_BANDFMT_CHAR: \ select_tmp1_for_out_short(signed char, OUT); \ break; \ case IM_BANDFMT_USHORT: \ select_tmp1_for_out_short(unsigned short, OUT); \ break; \ case IM_BANDFMT_SHORT: \ select_tmp1_for_out_short(signed short, OUT); \ break; \ default: \ g_assert(0); #define select_tmp1_for_out_short(IN2, OUT) \ switch (tmp1->BandFmt) { \ case IM_BANDFMT_UCHAR: \ loop(unsigned char, IN2, OUT); \ break; \ case IM_BANDFMT_CHAR: \ loop(signed char, IN2, OUT); \ break; \ case IM_BANDFMT_USHORT: \ loop(unsigned short, IN2, OUT); \ break; \ case IM_BANDFMT_SHORT: \ loop(signed short, IN2, OUT); \ break; \ default: \ im_error("im_gaddim", "Wrong image1 format(4)"); \ free(line); \ return -1; \ } /** * im_gaddim: * * Deprecated. */ int im_gaddim(double a, IMAGE *in1, double b, IMAGE *in2, double c, IMAGE *out) { static int fmt[] = { IM_BANDFMT_UCHAR, IM_BANDFMT_CHAR, IM_BANDFMT_USHORT, IM_BANDFMT_SHORT, IM_BANDFMT_UINT, IM_BANDFMT_INT }; int y, x; int first, second, result; IMAGE *tmp1, *tmp2; PEL *line; int os; /* size of a line of output image */ /* fd, data filename must have been set before the function is called * Check whether they are set properly */ if ((im_iocheck(in1, out) == -1) || (im_iocheck(in2, out) == -1)) { return -1; } /* Checks the arguments entered in in and prepares out */ if ((in1->Xsize != in2->Xsize) || (in1->Ysize != in2->Ysize) || (in1->Bands != in2->Bands) || (in1->Coding != in2->Coding)) { im_error("im_gaddim", " Input images differ"); return -1; } if (in1->Coding != IM_CODING_NONE) { im_error("im_gaddim", " images must be uncoded"); return -1; } switch (in1->BandFmt) { case IM_BANDFMT_UCHAR: first = 0; break; case IM_BANDFMT_CHAR: first = 1; break; case IM_BANDFMT_USHORT: first = 2; break; case IM_BANDFMT_SHORT: first = 3; break; case IM_BANDFMT_UINT: first = 4; break; case IM_BANDFMT_INT: first = 5; break; default: im_error("im_gaddim", " Unable to accept image1"); return -1; } switch (in2->BandFmt) { case IM_BANDFMT_UCHAR: second = 0; break; case IM_BANDFMT_CHAR: second = 1; break; case IM_BANDFMT_USHORT: second = 2; break; case IM_BANDFMT_SHORT: second = 3; break; case IM_BANDFMT_UINT: second = 4; break; case IM_BANDFMT_INT: second = 5; break; default: im_error("im_gaddim", " Unable to accept image2"); return -1; } /* Define the output */ result = array[first][second]; /* Prepare the output header */ if (im_cp_desc(out, in1) == -1) { im_error("im_gaddim", " im_cp_desc failed"); return -1; } out->BandFmt = fmt[result]; if (im_setupout(out) == -1) { im_error("im_gaddim", " im_setupout failed"); return -1; } /* Order in1 and in2 */ if (first >= second) { tmp1 = in1; tmp2 = in2; } else { tmp1 = in2; tmp2 = in1; } /* Define what we do for each band element type. */ #define loop(IN1, IN2, OUT) \ { \ IN1 *input1 = (IN1 *) tmp1->data; \ IN2 *input2 = (IN2 *) tmp2->data; \ \ for (y = 0; y < out->Ysize; y++) { \ OUT *cpline = (OUT *) line; \ for (x = 0; x < os; x++) \ *cpline++ = \ (OUT) (a * (*input1++) + b * (*input2++) + c + 0.5); \ if (im_writeline(y, out, line) == -1) { \ free(line); \ return -1; \ } \ } \ } os = out->Xsize * out->Bands; line = (PEL *) calloc((unsigned) os, sizeof(double)); if (line == NULL) { im_error("im_gaddim", " Unable to calloc"); return -1; } switch (out->BandFmt) { case IM_BANDFMT_INT: switch (tmp2->BandFmt) { select_tmp2_for_out_int(int); } break; case IM_BANDFMT_UINT: switch (tmp2->BandFmt) { select_tmp2_for_out_int(unsigned int); } break; case IM_BANDFMT_SHORT: switch (tmp2->BandFmt) { select_tmp2_for_out_short(short); } break; case IM_BANDFMT_USHORT: switch (tmp2->BandFmt) { select_tmp2_for_out_short(unsigned short); } break; default: im_error("im_gaddim", " Impossible output state"); free(line); return -1; } free(line); return 0; } libvips-8.18.2/libvips/deprecated/im_gfadd.c000066400000000000000000000233501516303661500207410ustar00rootroot00000000000000/* @(#) Generalised addition of two vasari images. Result (double or float) * @(#)depends on inputs * @(#) Function im_gfadd() assumes that the both input files * @(#) are either memory mapped or in a buffer. * @(#) Images must have the same no of bands and can be of any type * @(#) No check for overflow is carried out. If in doubt use im_clip2... * @(#) Result at eachpoint is a*in1 + b*in2 + c * @(#) * @(#) int im_gfadd(a, in1, b, in2, c, out) * @(#) double a, b, c; * @(#) IMAGE *in1, *in2, *out; * @(#) * @(#) Returns 0 on success and -1 on error * @(#) * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on: * 15/6/93 J.Cupitt * - externs removed * - casts added to please ANSI C * - includes rationalised */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* uchar char ushort short uint int float double */ static int array[8][8] = { /* uchar */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* char */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* ushort */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* short */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* uint */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* int */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* float */ { 0, 0, 0, 0, 0, 0, 0, 1 }, /* double */ { 1, 1, 1, 1, 1, 1, 1, 1 } }; #define select_outdouble(IN2, OUT) \ switch (tmp1->BandFmt) { \ case IM_BANDFMT_DOUBLE: \ loop(double, IN2, OUT); \ break; \ default: \ im_error("im_gfadd", "Wrong tmp1 format(d)"); \ free(line); \ return -1; \ } #define outfloat_2uchar(IN2, OUT) \ case IM_BANDFMT_UCHAR: \ loop(unsigned char, IN2, OUT); \ break; \ case IM_BANDFMT_CHAR: \ loop(signed char, IN2, OUT); \ break; \ case IM_BANDFMT_USHORT: \ loop(unsigned short, IN2, OUT); \ break; \ case IM_BANDFMT_SHORT: \ loop(signed short, IN2, OUT); \ break; \ case IM_BANDFMT_UINT: \ loop(unsigned int, IN2, OUT); \ break; \ case IM_BANDFMT_INT: \ loop(signed int, IN2, OUT); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; #define outfloat_2char(IN2, OUT) \ case IM_BANDFMT_CHAR: \ loop(signed char, IN2, OUT); \ break; \ case IM_BANDFMT_USHORT: \ loop(unsigned short, IN2, OUT); \ break; \ case IM_BANDFMT_SHORT: \ loop(signed short, IN2, OUT); \ break; \ case IM_BANDFMT_UINT: \ loop(unsigned int, IN2, OUT); \ break; \ case IM_BANDFMT_INT: \ loop(signed int, IN2, OUT); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; #define outfloat_2ushort(IN2, OUT) \ case IM_BANDFMT_USHORT: \ loop(unsigned short, IN2, OUT); \ break; \ case IM_BANDFMT_SHORT: \ loop(signed short, IN2, OUT); \ break; \ case IM_BANDFMT_UINT: \ loop(unsigned int, IN2, OUT); \ break; \ case IM_BANDFMT_INT: \ loop(signed int, IN2, OUT); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; #define outfloat_2short(IN2, OUT) \ case IM_BANDFMT_SHORT: \ loop(signed short, IN2, OUT); \ break; \ case IM_BANDFMT_UINT: \ loop(unsigned int, IN2, OUT); \ break; \ case IM_BANDFMT_INT: \ loop(signed int, IN2, OUT); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; #define outfloat_2uint(IN2, OUT) \ case IM_BANDFMT_UINT: \ loop(unsigned int, IN2, OUT); \ break; \ case IM_BANDFMT_INT: \ loop(signed int, IN2, OUT); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; #define outfloat_2int(IN2, OUT) \ case IM_BANDFMT_INT: \ loop(signed int, IN2, OUT); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; #define outfloat_2float(IN2, OUT) \ case IM_BANDFMT_FLOAT: \ loop(float, IN2, OUT); \ break; /** * im_gfadd: * * Deprecated. */ int im_gfadd(double a, IMAGE *in1, double b, IMAGE *in2, double c, IMAGE *out) { static int fmt[] = { IM_BANDFMT_FLOAT, IM_BANDFMT_DOUBLE }; int y, x; int first, second, result; IMAGE *tmp1, *tmp2; PEL *line; int os; /* size of a line of output image */ /* fd, data filename must have been set before the function is called * Check whether they are set properly */ if ((im_iocheck(in1, out) == -1) || (im_iocheck(in2, out) == -1)) { im_error("im_gfadd", " im_iocheck failed"); return -1; } /* Checks the arguments entered in in and prepares out */ if ((in1->Xsize != in2->Xsize) || (in1->Ysize != in2->Ysize) || (in1->Bands != in2->Bands) || (in1->Coding != in2->Coding)) { im_error("im_gfadd", " Input images differ"); return -1; } if (in1->Coding != IM_CODING_NONE) { im_error("im_gfadd", " images are coded"); return -1; } switch (in1->BandFmt) { case IM_BANDFMT_UCHAR: first = 0; break; case IM_BANDFMT_CHAR: first = 1; break; case IM_BANDFMT_USHORT: first = 2; break; case IM_BANDFMT_SHORT: first = 3; break; case IM_BANDFMT_UINT: first = 4; break; case IM_BANDFMT_INT: first = 5; break; case IM_BANDFMT_FLOAT: first = 6; break; case IM_BANDFMT_DOUBLE: first = 7; break; default: im_error("im_gfadd", " unable to accept image1"); return -1; } switch (in2->BandFmt) { case IM_BANDFMT_UCHAR: second = 0; break; case IM_BANDFMT_CHAR: second = 1; break; case IM_BANDFMT_USHORT: second = 2; break; case IM_BANDFMT_SHORT: second = 3; break; case IM_BANDFMT_UINT: second = 4; break; case IM_BANDFMT_INT: second = 5; break; case IM_BANDFMT_FLOAT: second = 6; break; case IM_BANDFMT_DOUBLE: second = 7; break; default: im_error("im_gfadd", " unable to accept image2"); return -1; } /* Define the output */ result = array[first][second]; /* Prepare output */ if (im_cp_desc(out, in1) == -1) { im_error("im_gfadd", " im_cp_desc failed"); return -1; } out->BandFmt = fmt[result]; if (im_setupout(out) == -1) { im_error("im_gfadd", " im_setupout failed"); return -1; } /* Order in1 and in2 */ if (first >= second) { tmp1 = in1; tmp2 = in2; } else { tmp1 = in2; tmp2 = in1; } /* Define what we do for each band element type. */ #define loop(IN1, IN2, OUT) \ { \ IN1 *input1 = (IN1 *) tmp1->data; \ IN2 *input2 = (IN2 *) tmp2->data; \ \ for (y = 0; y < out->Ysize; y++) { \ OUT *cpline = (OUT *) line; \ for (x = 0; x < os; x++) \ *cpline++ = (a * ((OUT) *input1++) + \ b * ((OUT) *input2++) + c); \ if (im_writeline(y, out, line)) { \ im_error("im_gfadd", " im_writeline failed"); \ free(line); \ return -1; \ } \ } \ } os = out->Xsize * out->Bands; line = (PEL *) calloc((unsigned) os, sizeof(double)); if (line == NULL) { im_error("im_gfadd", " unable to calloc"); return -1; } switch (out->BandFmt) { case IM_BANDFMT_DOUBLE: switch (tmp2->BandFmt) { case IM_BANDFMT_UCHAR: select_outdouble(unsigned char, double); break; case IM_BANDFMT_CHAR: select_outdouble(signed char, double); break; case IM_BANDFMT_USHORT: select_outdouble(unsigned short, double); break; case IM_BANDFMT_SHORT: select_outdouble(signed short, double); break; case IM_BANDFMT_UINT: select_outdouble(unsigned int, double); break; case IM_BANDFMT_INT: select_outdouble(signed int, double); break; case IM_BANDFMT_FLOAT: select_outdouble(float, double); break; case IM_BANDFMT_DOUBLE: select_outdouble(double, double); break; default: im_error("im_gfadd", "Wrong tmp2 format(d)"); free(line); return -1; } break; case IM_BANDFMT_FLOAT: switch (tmp2->BandFmt) { case IM_BANDFMT_UCHAR: switch (tmp1->BandFmt) { outfloat_2uchar(unsigned char, float); default: im_error("im_gfadd", " Error (a)"); free(line); return -1; } break; case IM_BANDFMT_CHAR: switch (tmp1->BandFmt) { outfloat_2char(signed char, float); default: im_error("im_gfadd", " Error (b)"); free(line); return -1; } break; case IM_BANDFMT_USHORT: switch (tmp1->BandFmt) { outfloat_2ushort(unsigned short, float); default: im_error("im_gfadd", " Error (c)"); free(line); return -1; } break; case IM_BANDFMT_SHORT: switch (tmp1->BandFmt) { outfloat_2short(signed short, float); default: im_error("im_gfadd", " Error (d)"); free(line); return -1; } break; case IM_BANDFMT_UINT: switch (tmp1->BandFmt) { outfloat_2uint(unsigned int, float); default: im_error("im_gfadd", " Error (e)"); free(line); return -1; } break; case IM_BANDFMT_INT: switch (tmp1->BandFmt) { outfloat_2int(signed int, float); default: im_error("im_gfadd", " Error (f)"); free(line); return -1; } break; case IM_BANDFMT_FLOAT: switch (tmp1->BandFmt) { outfloat_2float(float, float); default: im_error("im_gfadd", " Error (g)"); free(line); return -1; } break; default: im_error("im_gfadd", " Wrong tmp2 format(f)"); free(line); return -1; } break; default: im_error("im_gfadd", " Impossible output state"); free(line); return -1; } free(line); return 0; } libvips-8.18.2/libvips/deprecated/im_gradcor.c000066400000000000000000000405101516303661500213120ustar00rootroot00000000000000/* im_gradcor * * Copyright: 2007 Nottingham Trent University * * Author: Tom Vajzovic * Written on: 2007-06-07 * 3/2/10 * - gtkdoc * - cleanups */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include typedef struct { REGION *reg; int *region_xgrad; int *region_ygrad; size_t region_xgrad_area; size_t region_ygrad_area; } gradcor_seq_t; static void *gradcor_start(IMAGE *out, void *vptr_large, void *unrequired); static int gradcor_stop(void *vptr_seq, void *unrequired, void *unreq2); static int gradcor_gen(REGION *to_make, void *vptr_seq, void *unrequired, void *vptr_grads); #define XGRAD_GEN_DECLARATION(TYPE) static int xgrad_gen_##TYPE(REGION *to_make, void *vptr_make_from, void *unrequired, void *unreq2) #define YGRAD_GEN_DECLARATION(TYPE) static int ygrad_gen_##TYPE(REGION *to_make, void *vptr_make_from, void *unrequired, void *unreq2) XGRAD_GEN_DECLARATION(guint8); YGRAD_GEN_DECLARATION(guint8); XGRAD_GEN_DECLARATION(gint8); YGRAD_GEN_DECLARATION(gint8); XGRAD_GEN_DECLARATION(guint16); YGRAD_GEN_DECLARATION(guint16); XGRAD_GEN_DECLARATION(gint16); YGRAD_GEN_DECLARATION(gint16); XGRAD_GEN_DECLARATION(guint32); YGRAD_GEN_DECLARATION(guint32); XGRAD_GEN_DECLARATION(gint32); YGRAD_GEN_DECLARATION(gint32); #if 0 XGRAD_GEN_DECLARATION(float); YGRAD_GEN_DECLARATION(float); XGRAD_GEN_DECLARATION(double); YGRAD_GEN_DECLARATION(double); #endif int im_gradcor_raw(IMAGE *large, IMAGE *small, IMAGE *out) { #define FUNCTION_NAME "im_gradcor_raw" if (im_piocheck(large, out) || im_pincheck(small)) return -1; if (im_check_uncoded("im_gradcor", large) || im_check_mono("im_gradcor", large) || im_check_uncoded("im_gradcor", small) || im_check_mono("im_gradcor", small) || im_check_format_same("im_gradcor", large, small) || im_check_int("im_gradcor", large)) return -1; if (large->Xsize < small->Xsize || large->Ysize < small->Ysize) { im_error(FUNCTION_NAME, "second image must be smaller than first"); return -1; } if (im_cp_desc(out, large)) return -1; out->Xsize = 1 + large->Xsize - small->Xsize; out->Ysize = 1 + large->Ysize - small->Ysize; out->BandFmt = IM_BANDFMT_FLOAT; if (im_demand_hint(out, IM_FATSTRIP, large, NULL)) return -1; { IMAGE *xgrad = im_open_local(out, FUNCTION_NAME ": xgrad", "t"); IMAGE *ygrad = im_open_local(out, FUNCTION_NAME ": ygrad", "t"); IMAGE **grads = im_allocate_input_array(out, xgrad, ygrad, NULL); if (!xgrad || !ygrad || !grads || im_grad_x(small, xgrad) || im_grad_y(small, ygrad)) return -1; if (im_generate(out, gradcor_start, gradcor_gen, gradcor_stop, (void *) large, (void *) grads)) return -1; return 0; } #undef FUNCTION_NAME } /** * im_gradcor: * @in: input image * @ref: reference image * @out: output image * * Calculate a correlation surface. * * @ref is placed at every position in @in and a correlation coefficient * calculated. One-band, integer images only. @in and @ref must have the * same #VipsBandFmt. The output * image is always %IM_BANDFMT_FLOAT. @ref must be smaller than @in. The output * image is the same size as the input. * * The method takes the gradient images of the two images then takes the * dot-product correlation of the two vector images. * The vector expression of this method is my (tcv) own creation. It is * equivalent to the complex-number method of: * * ARGYRIOU, V. et al. 2003. Estimation of sub-pixel motion using * gradient cross correlation. Electronics Letters, 39 (13). * * See also: im_spcor(). * * Returns: 0 on success, -1 on error */ int im_gradcor(IMAGE *in, IMAGE *ref, IMAGE *out) { #define FUNCTION_NAME "im_gradcor" IMAGE *t1 = im_open_local(out, FUNCTION_NAME " intermediate", "p"); if (!t1 || im_embed(in, t1, 1, ref->Xsize / 2, ref->Ysize / 2, in->Xsize + ref->Xsize - 1, in->Ysize + ref->Ysize - 1) || im_gradcor_raw(t1, ref, out)) return -1; out->Xoffset = 0; out->Yoffset = 0; return 0; #undef FUNCTION_NAME } /** * im_grad_x: * @in: input image * @out: output image * * Find horizontal differences between adjacent pixels. * * Generates an image where the value of each pixel is the difference between * it and the pixel to its right. The output has the same height as the input * and one pixel less width. One-band integer formats only. The result is * always %IM_BANDFMT_INT. * * This operation is much faster than (though equivalent to) im_conv() with the * mask [[-1, 1]]. * * See also: im_grad_y(), im_conv(). * * Returns: 0 on success, -1 on error */ int im_grad_x(IMAGE *in, IMAGE *out) { #define FUNCTION_NAME "im_grad_x" if (im_piocheck(in, out)) return -1; if (im_check_uncoded("im_grad_x", in) || im_check_mono("im_grad_x", in) || im_check_int("im_grad_x", in)) return -1; if (im_cp_desc(out, in)) return -1; --out->Xsize; out->BandFmt = IM_BANDFMT_INT; /* do not change without updating im_gradcor() */ if (im_demand_hint(out, IM_THINSTRIP, in, NULL)) return -1; #define RETURN_GENERATE(TYPE) return im_generate(out, im_start_one, xgrad_gen_##TYPE, im_stop_one, (void *) in, NULL) switch (in->BandFmt) { case IM_BANDFMT_UCHAR: RETURN_GENERATE(guint8); case IM_BANDFMT_CHAR: RETURN_GENERATE(gint8); case IM_BANDFMT_USHORT: RETURN_GENERATE(guint16); case IM_BANDFMT_SHORT: RETURN_GENERATE(gint16); case IM_BANDFMT_UINT: RETURN_GENERATE(guint32); case IM_BANDFMT_INT: RETURN_GENERATE(gint32); #if 0 case IM_BANDFMT_FLOAT: RETURN_GENERATE(float); case IM_BANDFMT_DOUBLE: RETURN_GENERATE(double); #endif #undef RETURN_GENERATE default: g_assert(0); } /* Keep gcc happy. */ return 0; #undef FUNCTION_NAME } /** * im_grad_y: * @in: input image * @out: output image * * Find vertical differences between adjacent pixels. * * Generates an image where the value of each pixel is the difference between * it and the pixel below it. The output has the same width as the input * and one pixel less height. One-band integer formats only. The result is * always %IM_BANDFMT_INT. * * This operation is much faster than (though equivalent to) im_conv() with the * mask [[-1], [1]]. * * See also: im_grad_x(), im_conv(). * * Returns: 0 on success, -1 on error */ int im_grad_y(IMAGE *in, IMAGE *out) { #define FUNCTION_NAME "im_grad_y" if (im_piocheck(in, out)) return -1; if (im_check_uncoded("im_grad_y", in) || im_check_mono("im_grad_y", in) || im_check_int("im_grad_y", in)) return -1; if (im_cp_desc(out, in)) return -1; --out->Ysize; out->BandFmt = IM_BANDFMT_INT; /* do not change without updating im_gradcor() */ if (im_demand_hint(out, IM_FATSTRIP, in, NULL)) return -1; #define RETURN_GENERATE(TYPE) return im_generate(out, im_start_one, ygrad_gen_##TYPE, im_stop_one, (void *) in, NULL) switch (in->BandFmt) { case IM_BANDFMT_UCHAR: RETURN_GENERATE(guint8); case IM_BANDFMT_CHAR: RETURN_GENERATE(gint8); case IM_BANDFMT_USHORT: RETURN_GENERATE(guint16); case IM_BANDFMT_SHORT: RETURN_GENERATE(gint16); case IM_BANDFMT_UINT: RETURN_GENERATE(guint32); case IM_BANDFMT_INT: RETURN_GENERATE(gint32); #if 0 case IM_BANDFMT_FLOAT: RETURN_GENERATE(float); case IM_BANDFMT_DOUBLE: RETURN_GENERATE(double); #endif #undef RETURN_GENERATE default: g_assert(0); } /* Keep gcc happy. */ return 0; #undef FUNCTION_NAME } static void * gradcor_start(IMAGE *out, void *vptr_large, void *unrequired) { gradcor_seq_t *seq = IM_NEW(NULL, gradcor_seq_t); if (!seq) return NULL; seq->region_xgrad = (int *) NULL; seq->region_ygrad = (int *) NULL; seq->region_xgrad_area = 0; seq->region_ygrad_area = 0; seq->reg = im_region_create((IMAGE *) vptr_large); if (!seq->reg) { im_free((void *) seq); return NULL; } return (void *) seq; } static int gradcor_stop(void *vptr_seq, void *unrequired, void *unreq2) { gradcor_seq_t *seq = (gradcor_seq_t *) vptr_seq; if (seq) { im_free((void *) seq->region_xgrad); im_free((void *) seq->region_ygrad); im_region_free(seq->reg); seq->region_xgrad = (int *) NULL; seq->region_ygrad = (int *) NULL; seq->reg = (REGION *) NULL; im_free((void *) seq); } return 0; } static int gradcor_gen(REGION *to_make, void *vptr_seq, void *unrequired, void *vptr_grads) { gradcor_seq_t *seq = (gradcor_seq_t *) vptr_seq; REGION *make_from = seq->reg; IMAGE **grads = (IMAGE **) vptr_grads; IMAGE *small_xgrad = grads[0]; IMAGE *small_ygrad = grads[1]; Rect require = { to_make->valid.left, to_make->valid.top, to_make->valid.width + small_xgrad->Xsize, to_make->valid.height + small_ygrad->Ysize }; size_t region_xgrad_width = require.width - 1; size_t region_ygrad_height = require.height - 1; if (im_prepare(make_from, &require)) return -1; #define FILL_BUFFERS(TYPE) /* fill region_xgrad */ \ { \ TYPE *reading = (TYPE *) IM_REGION_ADDR(make_from, require.left, require.top); \ size_t read_skip = (IM_REGION_LSKIP(make_from) / sizeof(TYPE)) - region_xgrad_width; \ size_t area_need = region_xgrad_width * require.height; \ \ if (seq->region_xgrad_area < area_need) { \ free(seq->region_xgrad); \ seq->region_xgrad = malloc(area_need * sizeof(int)); \ if (!seq->region_xgrad) \ return -1; \ seq->region_xgrad_area = area_need; \ } \ { \ int *writing = seq->region_xgrad; \ int *write_end = writing + area_need; \ int *write_stop; \ for (; writing < write_end; reading += read_skip) \ for (write_stop = writing + region_xgrad_width; writing < write_stop; ++reading, ++writing) \ *writing = reading[1] - reading[0]; \ } \ } \ { /* fill region_ygrad */ \ TYPE *reading = (TYPE *) IM_REGION_ADDR(make_from, require.left, require.top); \ size_t read_line = IM_REGION_LSKIP(make_from) / sizeof(TYPE); \ size_t read_skip = read_line - require.width; \ size_t area_need = require.width * region_ygrad_height; \ \ if (seq->region_ygrad_area < area_need) { \ free(seq->region_ygrad); \ seq->region_ygrad = malloc(area_need * sizeof(int)); \ if (!seq->region_ygrad) \ return -1; \ seq->region_ygrad_area = area_need; \ } \ { \ int *writing = seq->region_ygrad; \ int *write_end = writing + area_need; \ int *write_stop; \ for (; writing < write_end; reading += read_skip) \ for (write_stop = writing + require.width; writing < write_stop; ++reading, ++writing) \ *writing = reading[read_line] - reading[0]; \ } \ } switch (make_from->im->BandFmt) { case IM_BANDFMT_UCHAR: FILL_BUFFERS(unsigned char) break; case IM_BANDFMT_CHAR: FILL_BUFFERS(signed char) break; case IM_BANDFMT_USHORT: FILL_BUFFERS(unsigned short int) break; case IM_BANDFMT_SHORT: FILL_BUFFERS(signed short int) break; case IM_BANDFMT_UINT: FILL_BUFFERS(unsigned int) break; case IM_BANDFMT_INT: FILL_BUFFERS(signed int) break; default: g_assert(0); } { /* write to output */ size_t write_skip = IM_REGION_LSKIP(to_make) / sizeof(float); float *writing = (float *) IM_REGION_ADDR_TOPLEFT(to_make); float *write_end = writing + write_skip * to_make->valid.height; float *write_stop; size_t write_width = to_make->valid.width; size_t small_xgrad_width = small_xgrad->Xsize; size_t small_ygrad_width = small_ygrad->Xsize; int *small_xgrad_end = (int *) small_xgrad->data + small_xgrad_width * small_xgrad->Ysize; int *small_ygrad_end = (int *) small_ygrad->data + small_ygrad_width * small_ygrad->Ysize; int *region_xgrad_start = seq->region_xgrad; int *region_ygrad_start = seq->region_ygrad; size_t region_xgrad_start_skip = region_xgrad_width - write_width; size_t region_ygrad_start_skip = require.width - write_width; size_t region_xgrad_read_skip = region_xgrad_width - small_xgrad_width; size_t region_ygrad_read_skip = require.width - small_ygrad_width; write_skip -= write_width; for (; writing < write_end; writing += write_skip, region_xgrad_start += region_xgrad_start_skip, region_ygrad_start += region_ygrad_start_skip) for (write_stop = writing + write_width; writing < write_stop; ++writing, ++region_xgrad_start, ++region_ygrad_start) { gint64 sum = 0; { int *small_xgrad_read = (int *) small_xgrad->data; int *small_xgrad_stop; int *region_xgrad_read = region_xgrad_start; for (; small_xgrad_read < small_xgrad_end; region_xgrad_read += region_xgrad_read_skip) for (small_xgrad_stop = small_xgrad_read + small_xgrad_width; small_xgrad_read < small_xgrad_stop; ++small_xgrad_read, ++region_xgrad_read) sum += *small_xgrad_read * *region_xgrad_read; } { int *small_ygrad_read = (int *) small_ygrad->data; int *small_ygrad_stop; int *region_ygrad_read = region_ygrad_start; for (; small_ygrad_read < small_ygrad_end; region_ygrad_read += region_ygrad_read_skip) for (small_ygrad_stop = small_ygrad_read + small_ygrad_width; small_ygrad_read < small_ygrad_stop; ++small_ygrad_read, ++region_ygrad_read) sum += *small_ygrad_read * *region_ygrad_read; } *writing = sum; } } return 0; } #define XGRAD_GEN_DEFINITION(TYPE) \ static int xgrad_gen_##TYPE(REGION *to_make, void *vptr_make_from, void *unrequired, void *unreq2) \ { \ \ REGION *make_from = (REGION *) vptr_make_from; \ Rect require = { \ to_make->valid.left, \ to_make->valid.top, \ to_make->valid.width + 1, \ to_make->valid.height \ }; \ if (im_prepare(make_from, &require)) \ return -1; \ \ { \ int *writing = (int *) IM_REGION_ADDR_TOPLEFT(to_make); \ size_t write_skip = IM_REGION_LSKIP(to_make) / sizeof(int); \ int *write_end = writing + write_skip * to_make->valid.height; \ size_t write_width = to_make->valid.width; \ int *write_stop; \ \ TYPE *reading = (TYPE *) IM_REGION_ADDR(make_from, require.left, require.top); \ size_t read_skip = (IM_REGION_LSKIP(make_from) / sizeof(TYPE)) - write_width; \ \ write_skip -= write_width; \ \ for (; writing < write_end; writing += write_skip, reading += read_skip) \ for (write_stop = writing + write_width; writing < write_stop; ++writing, ++reading) \ *writing = (int) (reading[1] - reading[0]); \ } \ return 0; \ } #define YGRAD_GEN_DEFINITION(TYPE) \ static int ygrad_gen_##TYPE(REGION *to_make, void *vptr_make_from, void *unrequired, void *unreq2) \ { \ \ REGION *make_from = (REGION *) vptr_make_from; \ Rect require = { \ to_make->valid.left, \ to_make->valid.top, \ to_make->valid.width, \ to_make->valid.height + 1 \ }; \ if (im_prepare(make_from, &require)) \ return -1; \ \ { \ int *writing = (int *) IM_REGION_ADDR_TOPLEFT(to_make); \ size_t write_skip = IM_REGION_LSKIP(to_make) / sizeof(int); \ int *write_end = writing + write_skip * to_make->valid.height; \ size_t write_width = to_make->valid.width; \ int *write_stop; \ \ TYPE *reading = (TYPE *) IM_REGION_ADDR(make_from, require.left, require.top); \ size_t read_line = IM_REGION_LSKIP(make_from) / sizeof(TYPE); \ size_t read_skip = read_line - write_width; \ \ write_skip -= write_width; \ \ for (; writing < write_end; writing += write_skip, reading += read_skip) \ for (write_stop = writing + write_width; writing < write_stop; ++writing, ++reading) \ *writing = (int) (reading[read_line] - reading[0]); \ } \ return 0; \ } XGRAD_GEN_DEFINITION(guint8) YGRAD_GEN_DEFINITION(guint8) XGRAD_GEN_DEFINITION(gint8) YGRAD_GEN_DEFINITION(gint8) XGRAD_GEN_DEFINITION(guint16) YGRAD_GEN_DEFINITION(guint16) XGRAD_GEN_DEFINITION(gint16) YGRAD_GEN_DEFINITION(gint16) XGRAD_GEN_DEFINITION(guint32) YGRAD_GEN_DEFINITION(guint32) XGRAD_GEN_DEFINITION(gint32) YGRAD_GEN_DEFINITION(gint32) #if 0 XGRAD_GEN_DEFINITION(float) YGRAD_GEN_DEFINITION(float) XGRAD_GEN_DEFINITION(double) YGRAD_GEN_DEFINITION(double) #endif libvips-8.18.2/libvips/deprecated/im_jpeg2vips.c000066400000000000000000000107221516303661500216040ustar00rootroot00000000000000/* Convert 1 or 3-band 8-bit VIPS images to/from JPEG. * * 30/11/11 * - now just a stub * 10/7/12 * - use jpeg funcs directly rather than going though vips_jpegload() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "../foreign/pforeign.h" static int jpeg2vips(const char *name, IMAGE *out, gboolean header_only) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p, *q; int shrink; int seq; VipsFailOn fail_on; /* By default, we ignore any warnings. We want to get as much of * the user's data as we can. */ fail_on = VIPS_FAIL_ON_NONE; /* Parse the filename. */ im_filename_split(name, filename, mode); p = &mode[0]; shrink = 1; seq = 0; if ((q = im_getnextoption(&p))) { shrink = atoi(q); if (shrink != 1 && shrink != 2 && shrink != 4 && shrink != 8) { im_error("im_jpeg2vips", _("bad shrink factor %d"), shrink); return -1; } } if ((q = im_getnextoption(&p))) { if (im_isprefix("fail", q)) fail_on = VIPS_FAIL_ON_WARNING; } if ((q = im_getnextoption(&p))) { if (im_isprefix("seq", q)) seq = 1; } /* Don't use vips_jpegload() ... we call the jpeg func directly in * order to avoid the foreign.c mechanisms for load-via-disc and stuff * like that. */ /* We need to be compatible with the pre-sequential mode * im_jpeg2vips(). This returned a "t" if given a "p" image, since it * used writeline. * * If we're writing the image to a "p", switch it to a "t". */ if (!header_only && !seq && out->dtype == VIPS_IMAGE_PARTIAL) { if (vips__image_wio_output(out)) return -1; } #ifdef HAVE_JPEG { VipsSource *source; if (!(source = vips_source_new_from_file(filename))) return -1; if (vips__jpeg_read_source(source, out, header_only, shrink, fail_on, FALSE, FALSE)) { VIPS_UNREF(source); return -1; } VIPS_UNREF(source); } #else vips_error("im_jpeg2vips", "%s", _("no JPEG support in your libvips")); return -1; #endif /*HAVE_JPEG*/ return 0; } int im_jpeg2vips(const char *name, IMAGE *out) { return jpeg2vips(name, out, FALSE); } /* By having a separate header func, we get lazy.c to open via disc/mem. */ static int im_jpeg2vips_header(const char *name, IMAGE *out) { return jpeg2vips(name, out, TRUE); } int im_bufjpeg2vips(void *buf, size_t len, IMAGE *out, gboolean header_only) { VipsImage *t; /* header_only is now automatic ... this call will only decompress on * pixel access. */ if (vips_jpegload_buffer(buf, len, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int isjpeg(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return vips_foreign_is_a("jpegload", filename); } static const char *jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", NULL }; /* jpeg format adds no new members. */ typedef VipsFormat VipsFormatJpeg; typedef VipsFormatClass VipsFormatJpegClass; static void vips_format_jpeg_class_init(VipsFormatJpegClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "jpeg"; object_class->description = _("JPEG"); format_class->is_a = isjpeg; format_class->header = im_jpeg2vips_header; format_class->load = im_jpeg2vips; format_class->save = im_vips2jpeg; format_class->suffs = jpeg_suffs; } static void vips_format_jpeg_init(VipsFormatJpeg *object) { } G_DEFINE_TYPE(VipsFormatJpeg, vips_format_jpeg, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_lab_morph.c000066400000000000000000000135111516303661500216350ustar00rootroot00000000000000/* Morph a lab image. * * 8/3/01 * - added * 2/11/09 * - cleanups * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include int im__colour_unary(const char *domain, IMAGE *in, IMAGE *out, VipsType type, im_wrapone_fn buffer_fn, void *a, void *b) { IMAGE *t[1]; if (im_check_uncoded(domain, in) || im_check_bands(domain, in, 3) || im_open_local_array(out, t, 1, domain, "p") || im_clip2fmt(in, t[0], IM_BANDFMT_FLOAT)) return -1; if (im_cp_desc(out, t[0])) return -1; out->Type = type; if (im_wrapone(t[0], out, (im_wrapone_fn) buffer_fn, a, b)) return -1; return 0; } typedef struct { IMAGE *in, *out; double L_scale, L_offset; double a_offset[101], b_offset[101]; double a_scale, b_scale; } Params; static int morph_init(Params *parm, IMAGE *in, IMAGE *out, double L_scale, double L_offset, DOUBLEMASK *mask, double a_scale, double b_scale) { int i, j; parm->in = in; parm->out = out; parm->L_scale = L_scale; parm->L_offset = L_offset; parm->a_scale = a_scale; parm->b_scale = b_scale; if (mask->xsize != 3 || mask->ysize < 1 || mask->ysize > 100) { im_error("im_lab_morph", "%s", _("bad greyscale mask size")); return -1; } for (i = 0; i < mask->ysize; i++) { double L = mask->coeff[i * 3]; double a = mask->coeff[i * 3 + 1]; double b = mask->coeff[i * 3 + 2]; if (L < 0 || L > 100 || a < -120 || a > 120 || b < -120 || b > 120) { im_error("im_lab_morph", _("bad greyscale mask value, row %d"), i); return -1; } } /* Generate a/b offsets. */ for (i = 0; i <= 100; i++) { double L_low = 0; double a_low = 0; double b_low = 0; double L_high = 100; double a_high = 0; double b_high = 0; /* Search for greyscale L just below i. Don't assume sorted by * L*. */ for (j = 0; j < mask->ysize; j++) { double L = mask->coeff[j * 3]; double a = mask->coeff[j * 3 + 1]; double b = mask->coeff[j * 3 + 2]; if (L < i && L > L_low) { L_low = L; a_low = a; b_low = b; } } /* Search for greyscale L just above i. */ for (j = mask->ysize - 1; j >= 0; j--) { double L = mask->coeff[j * 3]; double a = mask->coeff[j * 3 + 1]; double b = mask->coeff[j * 3 + 2]; if (L >= i && L < L_high) { L_high = L; a_high = a; b_high = b; } } /* Interpolate. */ parm->a_offset[i] = a_low + (a_high - a_low) * ((i - L_low) / (L_high - L_low)); parm->b_offset[i] = b_low + (b_high - b_low) * ((i - L_low) / (L_high - L_low)); } return 0; } static void morph_buffer(float *in, float *out, int width, Params *parm) { int x; for (x = 0; x < width; x++) { double L = in[0]; double a = in[1]; double b = in[2]; L = IM_CLIP(0, L, 100); a -= parm->a_offset[(int) L]; b -= parm->b_offset[(int) L]; L = (L + parm->L_offset) * parm->L_scale; L = IM_CLIP(0, L, 100); a *= parm->a_scale; b *= parm->b_scale; out[0] = L; out[1] = a; out[2] = b; in += 3; out += 3; } } /** * im_lab_morph: * @in: input image * @out: output image * @mask: cast correction table * @L_offset: L adjustment * @L_scale: L adjustment * @a_scale: a scale * @b_scale: b scale * * Morph an image in CIELAB colour space. Useful for certain types of gamut * mapping, or correction of greyscales on some printers. * * We perform three adjustments: * * ## Cast * * Pass in @mask containing CIELAB readings for a neutral greyscale. For * example: * * ``` * 3 4 * 14.23 4.8 -3.95 * 18.74 2.76 -2.62 * 23.46 1.4 -1.95 * 27.53 1.76 -2.01 * ``` * * Interpolation from this makes cast corrector. The top and tail are * interpolated towards [0, 0, 0] and [100, 0, 0], intermediate values are * interpolated along straight lines fitted between the specified points. * Rows may be in any order (ie. they need not be sorted on L*). * * Each pixel is displaced in a/b by the amount specified for that L in the * table. * * ## L* * * Pass in scale and offset for L. L' = (L + offset) * scale. * * ## Saturation * * scale a and b by these amounts, eg. 1.5 increases saturation. * * Find the top two by generating and printing a greyscale. Find the bottom * by printing a Macbeth and looking at a/b spread * * Returns: 0 on success, -1 on error. */ int im_lab_morph(IMAGE *in, IMAGE *out, DOUBLEMASK *mask, double L_offset, double L_scale, double a_scale, double b_scale) { Params *parm; /* Recurse for coded images. */ if (in->Coding == IM_CODING_LABQ) { IMAGE *t[2]; if (im_open_local_array(out, t, 2, "im_lab_morph", "p") || im_LabQ2Lab(in, t[0]) || im_lab_morph(t[0], t[1], mask, L_offset, L_scale, a_scale, b_scale) || im_Lab2LabQ(t[1], out)) return -1; return 0; } if (!(parm = IM_NEW(out, Params)) || morph_init(parm, in, out, L_scale, L_offset, mask, a_scale, b_scale)) return -1; return im__colour_unary("im_lab_morph", in, out, IM_TYPE_LAB, (im_wrapone_fn) morph_buffer, parm, NULL); } libvips-8.18.2/libvips/deprecated/im_line.c000066400000000000000000000066041516303661500206260ustar00rootroot00000000000000/* @#) line drawer. adapted to draw for graphics system * @(#) Modified to be compatible with the vasari library * @(#) In order to use this function, the input file should have been set by * @(#) im_mmapinrw() * * Copyright: N. Dessipris * Written: 02/01/1990 * Modified : * 22/7/93 JC * - im_incheck() added * - externs removed * 16/8/94 JC * - im_incheck() changed to im_makerw() * 5/12/06 * - im_invalidate() after paint */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_line(IMAGE *image, int x1, int y1, int x2, int y2, int pelval) { double x, y, dx, dy, m; long offset; double signx, signy; if (im_rwcheck(image)) return -1; /* check coordinates */ if ((x1 > image->Xsize) || (x1 < 0) || (y1 > image->Ysize) || (y1 < 0) || (x2 > image->Xsize) || (x2 < 0) || (y2 > image->Ysize) || (y2 < 0)) { im_error("im_line", "%s", _("invalid line cooordinates")); return -1; } if ((pelval > 255) || (pelval < 0)) { im_error("im_line", "%s", _("line intensity between 0 and 255")); return -1; } if (image->Bands != 1) { im_error("im_line", "%s", _("image should have one band only")); return -1; } dx = (double) (x2 - x1); dy = (double) (y2 - y1); if (dx < 0.0) signx = -1.0; else signx = 1.0; if (dy < 0.0) signy = -1.0; else signy = 1.0; if (dx == 0.0) { x = x1; y = y1; while (y != y2) { offset = (int) (x + .5) + ((int) (y + .5)) * image->Xsize; *(image->data + offset) = (PEL) pelval; y += signy; } /* Draw point (x2, y2) */ offset = x2 + y2 * image->Xsize; *(image->data + offset) = (PEL) pelval; return 0; } if (dy == 0.0) { y = y1; x = x1; while (x != x2) { offset = (int) (x + .5) + ((int) (y + .5)) * image->Xsize; *(image->data + offset) = (PEL) pelval; x += signx; } /* Draw point (x2, y2) */ offset = x2 + y2 * image->Xsize; *(image->data + offset) = (PEL) pelval; return 0; } if (fabs(dy) < fabs(dx)) { m = fabs(dy / dx) * signy; y = y1; x = x1; while (x != x2) { offset = (int) (x + .5) + ((int) (y + .5)) * image->Xsize; *(image->data + offset) = (PEL) pelval; x += signx; y += m; } } else { m = fabs(dx / dy) * signx; x = x1; y = y1; while (y != y2) { offset = (int) (x + .5) + ((int) (y + .5)) * image->Xsize; *(image->data + offset) = (PEL) pelval; x += m; y += signy; } } /* Draw point (x2, y2) */ offset = x2 + y2 * image->Xsize; *(image->data + offset) = (PEL) pelval; im_invalidate(image); return 0; } libvips-8.18.2/libvips/deprecated/im_linreg.c000066400000000000000000000241411516303661500211530ustar00rootroot00000000000000/* im_linreg.c * * Copyright: 2006, The Nottingham Trent University * * Author: Tom Vajzovic * * Written on: 2006-12-26 * * 12/5/09 * - make x_anal() static, fix some signed/unsigned warnings * 3/9/09 * - gtkdoc comment */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include #include #include typedef struct { unsigned int n; double *xs; double *difs; double mean; double nsig2; double err_term; } x_set; #define LINREG_SEQ(TYPE) \ typedef struct { \ REGION **regs; \ TYPE **ptrs; \ size_t *skips; \ } linreg_seq_##TYPE LINREG_SEQ(gint8); LINREG_SEQ(guint8); LINREG_SEQ(gint16); LINREG_SEQ(guint16); LINREG_SEQ(gint32); LINREG_SEQ(guint32); LINREG_SEQ(float); LINREG_SEQ(double); static x_set *x_anal(IMAGE *im, double *xs, unsigned int n); #define LINREG_START_DECL(TYPE) static void *linreg_start_##TYPE(IMAGE *, void *, void *); #define LINREG_GEN_DECL(TYPE) static int linreg_gen_##TYPE(REGION *, void *, void *, void *); #define LINREG_STOP_DECL(TYPE) static int linreg_stop_##TYPE(void *, void *, void *); #define INCR_ALL_DECL(TYPE) static void incr_all_##TYPE(TYPE **ptrs, unsigned int n) #define SKIP_ALL_DECL(TYPE) static void skip_all_##TYPE(TYPE **ptrs, size_t *skips, unsigned int n) LINREG_START_DECL(gint8); LINREG_START_DECL(guint8); LINREG_START_DECL(gint16); LINREG_START_DECL(guint16); LINREG_START_DECL(gint32); LINREG_START_DECL(guint32); LINREG_START_DECL(float); LINREG_START_DECL(double); LINREG_GEN_DECL(gint8); LINREG_GEN_DECL(guint8); LINREG_GEN_DECL(gint16); LINREG_GEN_DECL(guint16); LINREG_GEN_DECL(gint32); LINREG_GEN_DECL(guint32); LINREG_GEN_DECL(float); LINREG_GEN_DECL(double); LINREG_STOP_DECL(gint8); LINREG_STOP_DECL(guint8); LINREG_STOP_DECL(gint16); LINREG_STOP_DECL(guint16); LINREG_STOP_DECL(gint32); LINREG_STOP_DECL(guint32); LINREG_STOP_DECL(float); LINREG_STOP_DECL(double); INCR_ALL_DECL(gint8); INCR_ALL_DECL(guint8); INCR_ALL_DECL(gint16); INCR_ALL_DECL(guint16); INCR_ALL_DECL(gint32); INCR_ALL_DECL(guint32); INCR_ALL_DECL(float); INCR_ALL_DECL(double); SKIP_ALL_DECL(gint8); SKIP_ALL_DECL(guint8); SKIP_ALL_DECL(gint16); SKIP_ALL_DECL(guint16); SKIP_ALL_DECL(gint32); SKIP_ALL_DECL(guint32); SKIP_ALL_DECL(float); SKIP_ALL_DECL(double); /** * im_linreg: * @ins: NULL-terminated array of input images * @out: results of analysis * @xs: X position of each image (pixel value is Y) * * Function to find perform pixelwise linear regression on an array of * single band images. The output is a seven-band douuble image * * TODO: figure out how this works and fix up these docs! */ int im_linreg(IMAGE **ins, IMAGE *out, double *xs) { #define FUNCTION_NAME "im_linreg" int n; x_set *x_vals; if (im_poutcheck(out)) return -1; for (n = 0; ins[n]; ++n) { /* if (!isfinite(xs[n])) { im_error(FUNCTION_NAME, "invalid argument"); return -1; } */ if (im_pincheck(ins[n])) return -1; if (1 != ins[n]->Bands) { im_error(FUNCTION_NAME, "image is not single band"); return -1; } if (ins[n]->Coding) { im_error(FUNCTION_NAME, "image is not uncoded"); return -1; } if (n) { if (ins[n]->BandFmt != ins[0]->BandFmt) { im_error(FUNCTION_NAME, "image band formats differ"); return -1; } } else { if (vips_band_format_iscomplex(ins[0]->BandFmt)) { im_error(FUNCTION_NAME, "image has non-scalar band format"); return -1; } } if (n && (ins[n]->Xsize != ins[0]->Xsize || ins[n]->Ysize != ins[0]->Ysize)) { im_error(FUNCTION_NAME, "image sizes differ"); return -1; } } if (n < 3) { im_error(FUNCTION_NAME, "not enough input images"); return -1; } if (im_cp_desc_array(out, ins)) return -1; out->Bands = 7; out->BandFmt = IM_BANDFMT_DOUBLE; out->Type = 0; if (im_demand_hint_array(out, IM_THINSTRIP, ins)) return -1; x_vals = x_anal(out, xs, n); if (!x_vals) return -1; switch (ins[0]->BandFmt) { #define LINREG_RET(TYPE) return im_generate(out, linreg_start_##TYPE, linreg_gen_##TYPE, linreg_stop_##TYPE, ins, x_vals) case IM_BANDFMT_CHAR: LINREG_RET(gint8); case IM_BANDFMT_UCHAR: LINREG_RET(guint8); case IM_BANDFMT_SHORT: LINREG_RET(gint16); case IM_BANDFMT_USHORT: LINREG_RET(guint16); case IM_BANDFMT_INT: LINREG_RET(gint32); case IM_BANDFMT_UINT: LINREG_RET(guint32); case IM_BANDFMT_FLOAT: LINREG_RET(float); case IM_BANDFMT_DOUBLE: LINREG_RET(double); default: /* keep -Wall happy */ return -1; } #undef FUNCTION_NAME } static x_set * x_anal(IMAGE *im, double *xs, unsigned int n) { unsigned int i; x_set *x_vals = IM_NEW(im, x_set); if (!x_vals) return NULL; x_vals->xs = IM_ARRAY(im, 2 * n, double); if (!x_vals->xs) return NULL; x_vals->difs = x_vals->xs + n; x_vals->n = n; x_vals->mean = 0.0; for (i = 0; i < n; ++i) { x_vals->xs[i] = xs[i]; x_vals->mean += xs[i]; } x_vals->mean /= n; x_vals->nsig2 = 0.0; for (i = 0; i < n; ++i) { x_vals->difs[i] = xs[i] - x_vals->mean; x_vals->nsig2 += x_vals->difs[i] * x_vals->difs[i]; } x_vals->err_term = (1.0 / (double) n) + ((x_vals->mean * x_vals->mean) / x_vals->nsig2); return x_vals; } #define LINREG_START_DEFN(TYPE) \ static void *linreg_start_##TYPE(IMAGE *out, void *a, void *b) \ { \ IMAGE **ins = (IMAGE **) a; \ x_set *x_vals = (x_set *) b; \ linreg_seq_##TYPE *seq = IM_NEW(out, linreg_seq_##TYPE); \ \ if (!seq) \ return NULL; \ \ seq->regs = im_start_many(NULL, ins, NULL); \ seq->ptrs = IM_ARRAY(out, x_vals->n, TYPE *); \ seq->skips = IM_ARRAY(out, x_vals->n, size_t); \ \ if (!seq->ptrs || !seq->regs || !seq->skips) { \ linreg_stop_##TYPE(seq, NULL, NULL); \ return NULL; \ } \ return (void *) seq; \ } #define N ((double) n) #define y(a) ((double) (*seq->ptrs[(a)])) #define x(a) ((double) (x_vals->xs[(a)])) #define xd(a) ((double) (x_vals->difs[(a)])) #define Sxd2 (x_vals->nsig2) #define mean_x (x_vals->mean) #define mean_y (out[0]) #define dev_y (out[1]) #define y_x0 (out[2]) #define d_y_x0 (out[3]) #define dy_dx (out[4]) #define d_dy_dx (out[5]) #define R (out[6]) #define LINREG_GEN_DEFN(TYPE) \ static int linreg_gen_##TYPE(REGION *to_make, void *vseq, void *unrequired, void *b) \ { \ linreg_seq_##TYPE *seq = (linreg_seq_##TYPE *) vseq; \ x_set *x_vals = (x_set *) b; \ unsigned int n = x_vals->n; \ double *out = (double *) IM_REGION_ADDR_TOPLEFT(to_make); \ size_t out_skip = IM_REGION_LSKIP(to_make) / sizeof(double); \ double *out_end = out + out_skip * to_make->valid.height; \ double *out_stop; \ size_t out_n = IM_REGION_N_ELEMENTS(to_make); \ unsigned int i; \ \ out_skip -= out_n; \ \ if (im_prepare_many(seq->regs, &to_make->valid)) \ return -1; \ \ for (i = 0; i < n; ++i) { \ seq->ptrs[i] = (TYPE *) IM_REGION_ADDR(seq->regs[i], to_make->valid.left, to_make->valid.top); \ seq->skips[i] = (IM_REGION_LSKIP(seq->regs[i]) / sizeof(TYPE)) - IM_REGION_N_ELEMENTS(seq->regs[i]); \ } \ \ for (; out < out_end; out += out_skip, skip_all_##TYPE(seq->ptrs, seq->skips, n)) \ for (out_stop = out + out_n; out < out_stop; out += 7, incr_all_##TYPE(seq->ptrs, n)) { \ double Sy = 0.0; \ double Sxd_y = 0.0; \ double Syd2 = 0.0; \ double Sxd_yd = 0.0; \ double Se2 = 0.0; \ \ for (i = 0; i < n; ++i) { \ Sy += y(i); \ Sxd_y += xd(i) * y(i); \ } \ mean_y = Sy / N; \ dy_dx = Sxd_y / Sxd2; \ y_x0 = mean_y - dy_dx * mean_x; \ \ for (i = 0; i < n; ++i) { \ double yd = y(i) - mean_y; \ double e = y(i) - dy_dx * x(i) - y_x0; \ Syd2 += yd * yd; \ Sxd_yd += xd(i) * yd; \ Se2 += e * e; \ } \ dev_y = sqrt(Syd2 / N); \ Se2 /= (N - 2.0); \ d_dy_dx = sqrt(Se2 / Sxd2); \ d_y_x0 = sqrt(Se2 * x_vals->err_term); \ R = Sxd_yd / sqrt(Sxd2 * Syd2); \ } \ return 0; \ } #define LINREG_STOP_DEFN(TYPE) \ static int linreg_stop_##TYPE(void *vseq, void *a, void *b) \ { \ linreg_seq_##TYPE *seq = (linreg_seq_##TYPE *) vseq; \ if (seq->regs) \ im_stop_many(seq->regs, NULL, NULL); \ return 0; \ } #define INCR_ALL_DEFN(TYPE) \ static void incr_all_##TYPE(TYPE **ptrs, unsigned int n) \ { \ TYPE **stop = ptrs + n; \ for (; ptrs < stop; ++ptrs) \ ++*ptrs; \ } #define SKIP_ALL_DEFN(TYPE) \ static void skip_all_##TYPE(TYPE **ptrs, size_t *skips, unsigned int n) \ { \ TYPE **stop = ptrs + n; \ for (; ptrs < stop; ++ptrs, ++skips) \ *ptrs += *skips; \ } LINREG_START_DEFN(gint8); LINREG_START_DEFN(guint8); LINREG_START_DEFN(gint16); LINREG_START_DEFN(guint16); LINREG_START_DEFN(gint32); LINREG_START_DEFN(guint32); LINREG_START_DEFN(float); LINREG_START_DEFN(double); LINREG_GEN_DEFN(gint8); LINREG_GEN_DEFN(guint8); LINREG_GEN_DEFN(gint16); LINREG_GEN_DEFN(guint16); LINREG_GEN_DEFN(gint32); LINREG_GEN_DEFN(guint32); LINREG_GEN_DEFN(float); LINREG_GEN_DEFN(double); LINREG_STOP_DEFN(gint8); LINREG_STOP_DEFN(guint8); LINREG_STOP_DEFN(gint16); LINREG_STOP_DEFN(guint16); LINREG_STOP_DEFN(gint32); LINREG_STOP_DEFN(guint32); LINREG_STOP_DEFN(float); LINREG_STOP_DEFN(double); INCR_ALL_DEFN(gint8); INCR_ALL_DEFN(guint8); INCR_ALL_DEFN(gint16); INCR_ALL_DEFN(guint16); INCR_ALL_DEFN(gint32); INCR_ALL_DEFN(guint32); INCR_ALL_DEFN(float); INCR_ALL_DEFN(double); SKIP_ALL_DEFN(gint8); SKIP_ALL_DEFN(guint8); SKIP_ALL_DEFN(gint16); SKIP_ALL_DEFN(guint16); SKIP_ALL_DEFN(gint32); SKIP_ALL_DEFN(guint32); SKIP_ALL_DEFN(float); SKIP_ALL_DEFN(double); libvips-8.18.2/libvips/deprecated/im_litecor.c000066400000000000000000000157711516303661500213450ustar00rootroot00000000000000/* @(#) Function to perform lighting correction. * @(#) One band IM_BANDFMT_UCHAR images only. Always writes UCHAR. * @(#) * @(#) Function im_litecor() assumes that imin * @(#) is either memory mapped or in a buffer. * @(#) * @(#) int im_litecor(in, w, out, clip, factor) * @(#) IMAGE *in, *w, *out; * @(#) int clip; * @(#) double factor; * @(#) * @(#) clip==1 * @(#) - Compute max(white)*factor*(image/white), Clip to 255. * @(#) clip==0 * @(#) - Compute factor for you. * @(#) * @(#) * @(#) * @(#) * @(#) Returns 0 on success and -1 on error * * Copyright: 1990, J. Cupitt, 1991 N. Dessipris * * Author: J. Cupitt, N. Dessipris * Written on: 02/08/1990 * Modified on : 6/11/1991, by ND to produce a UCHAR output * 1/4/93 J.Cupitt * - bugs if white is smaller than image fixed * - im_warning() now called * - clip==0 case not tested or changed! do not use! */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* If maximum output is > 255 scale output between minout and maxout, * by normalising maxout to 255. * If maximum output is < 255 do the light correction without scaling */ static int im_litecor0(IMAGE *in, IMAGE *white, IMAGE *out) { PEL *p, *w; PEL *q, *bu; int c; int x, y; float xrat = (float) in->Xsize / white->Xsize; float yrat = (float) in->Ysize / white->Ysize; int xstep = (int) xrat; int ystep = (int) yrat; double max; int wtmp, maxw, maxout, temp; /* Check white is some simple multiple of image. */ if (xrat < 1.0 || xrat != xstep || yrat < 1.0 || yrat != ystep) { im_error("im_litecor", "white not simple scale of image"); return -1; } /* Find the maximum of the white. */ if (im_max(white, &max)) return -1; maxw = (int) max; /* Set up the output header. */ if (im_cp_desc(out, in)) return -1; if (im_setupout(out)) return -1; /* Make buffer for outputting to. */ if (!(bu = (PEL *) im_malloc(out, out->Xsize))) return -1; /* Find largest value we might generate if factor == 1.0 */ maxout = -1; p = (PEL *) in->data; for (y = 0; y < in->Ysize; y++) { /* Point w to the start of the line in the white * corresponding to the line we are about to correct. c counts * up to xstep; each time it wraps, we should move w on one. */ w = (PEL *) (white->data + white->Xsize * (int) (y / ystep)); c = 0; /* Scan along line. */ for (x = 0; x < out->Xsize; x++) { wtmp = (int) *w; temp = (maxw * (int) *p++ + (wtmp >> 1)) / wtmp; if (temp > maxout) maxout = temp; /* Move white pointer on if necessary. */ c++; if (c == xstep) { w++; c = 0; } } } /* Do exactly the same as above by scaling the result with respect to * maxout */ p = (PEL *) in->data; if (maxout <= 255) /* no need for rescaling output */ { for (y = 0; y < in->Ysize; y++) { q = bu; w = (PEL *) (white->data + white->Xsize * (int) (y / ystep)); c = 0; /* Scan along line. */ for (x = 0; x < in->Xsize; x++) { wtmp = (int) *w; *q++ = (PEL) ((maxw * (int) *p++ + (wtmp >> 1)) / wtmp); /* Move white pointer on if necessary. */ c++; if (c == xstep) { w++; c = 0; } } if (im_writeline(y, out, bu)) { im_error("im_litecor", "im_writeline failed"); return -1; } } } else /* rescale output wrt maxout */ { for (y = 0; y < in->Ysize; y++) { q = bu; w = (PEL *) (white->data + white->Xsize * (int) (y / ystep)); c = 0; /* Scan along line. */ for (x = 0; x < in->Xsize; x++) { wtmp = maxout * ((int) *w); *q++ = (PEL) ((maxw * (int) *p++ * 255 + (wtmp >> 1)) / wtmp); /* Move white pointer on if necessary. */ c++; if (c == xstep) { w++; c = 0; } } if (im_writeline(y, out, bu)) { im_error("im_litecor", "im_writeline failed"); return -1; } } } return 0; } /* Clip all corrected values above 255, if any. */ static int im_litecor1(IMAGE *in, IMAGE *white, IMAGE *out, double factor) { PEL *p, *w; PEL *q, *bu; int c; int x, y; float xrat = (float) in->Xsize / white->Xsize; float yrat = (float) in->Ysize / white->Ysize; int xstep = (int) xrat; int ystep = (int) yrat; double max; double maxw, temp; int nclipped = 0; /* Check white is some simple multiple of image. */ if (xrat < 1.0 || xrat != xstep || yrat < 1.0 || yrat != ystep) { im_error("im_litecor", "white not simple scale of image"); return -1; } /* Find the maximum of the white. */ if (im_max(white, &max)) return -1; maxw = max; /* Set up the output header. */ if (im_cp_desc(out, in)) return -1; if (im_setupout(out)) return -1; /* Make buffer we write to. */ if (!(bu = (PEL *) im_malloc(out, out->Xsize))) return -1; /* Loop through sorting max output */ p = (PEL *) in->data; for (y = 0; y < in->Ysize; y++) { q = bu; w = (PEL *) (white->data + white->Xsize * (int) (y / ystep)); c = 0; for (x = 0; x < out->Xsize; x++) { temp = ((factor * maxw * (int) *p++) / ((int) *w)) + 0.5; if (temp > 255.0) { temp = 255; nclipped++; } *q++ = temp; /* Move white pointer on if necessary. */ c++; if (c == xstep) { w++; c = 0; } } if (im_writeline(y, out, bu)) return -1; } if (nclipped) im_warn("im_litecor", "%d pels over 255 clipped", nclipped); return 0; } /* Lighting correction. One band uchar images only. * Assumes the white is some simple multiple of the image in size; ie. the * white has been taken with some smaller or equal set of resolution * parameters. */ int im_litecor(IMAGE *in, IMAGE *white, IMAGE *out, int clip, double factor) { /* Check our args. */ if (im_iocheck(in, out)) return -1; if (in->Bands != 1 || in->Coding != IM_CODING_NONE || in->BandFmt != IM_BANDFMT_UCHAR) { im_error("im_litecor", "bad input format"); return -1; } if (white->Bands != 1 || white->Coding != IM_CODING_NONE || white->BandFmt != IM_BANDFMT_UCHAR) { im_error("im_litecor", "bad white format"); return -1; } switch (clip) { case 1: return im_litecor1(in, white, out, factor); case 0: return im_litecor0(in, white, out); default: im_error("im_litecor", "unknown flag %d", clip); return -1; } } libvips-8.18.2/libvips/deprecated/im_magick2vips.c000066400000000000000000000051401516303661500221100ustar00rootroot00000000000000/* Read a file using libMagick * * 17/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Turn on debugging output. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include int im_magick2vips(const char *filename, IMAGE *out) { VipsImage *t; /* Old behaviour was always to read all frames. */ if (vips_magickload(filename, &t, "n", -1, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int ismagick(const char *filename) { return vips_foreign_is_a("magickload", filename); } static const char *magick_suffs[] = { NULL }; /* magick format adds no new members. */ typedef VipsFormat VipsFormatMagick; typedef VipsFormatClass VipsFormatMagickClass; static void vips_format_magick_class_init(VipsFormatMagickClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "magick"; object_class->description = _("libMagick-supported"); format_class->is_a = ismagick; format_class->load = im_magick2vips; format_class->suffs = magick_suffs; /* This can be very slow :-( Use our own jpeg/tiff/png etc. loaders in * preference if we can. */ format_class->priority = -1000; } static void vips_format_magick_init(VipsFormatMagick *object) { } G_DEFINE_TYPE(VipsFormatMagick, vips_format_magick, VIPS_TYPE_FORMAT); int im_bufmagick2vips(void *buf, size_t len, IMAGE *out, gboolean header_only) { VipsImage *t; /* header_only is automatic ... this call will only decompress on * pixel access. */ if (vips_magickload_buffer(buf, len, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } libvips-8.18.2/libvips/deprecated/im_mask2vips.c000066400000000000000000000044621516303661500216160ustar00rootroot00000000000000/* im_mask2vips * * Author: J.Cupitt * Written on: 6/6/94 * Modified on: * 7/10/94 JC * - new IM_ARRAY() * 1/2/10 * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /** * im_mask2vips: * @in: input mask * @out: output image * * Write a one-band, %IM_BANDFMT_DOUBLE image to @out based on mask @in. * * See also: im_vips2mask(). * * Returns: 0 on success, -1 on error */ int im_mask2vips(DOUBLEMASK *in, IMAGE *out) { int x, y; double *buf, *p, *q; /* Check the mask. */ if (!in || !in->coeff) { im_error("im_mask2vips", "%s", _("bad input mask")); return -1; } /* Make the output image. */ im_initdesc(out, in->xsize, in->ysize, 1, IM_BBITS_DOUBLE, IM_BANDFMT_DOUBLE, IM_CODING_NONE, IM_TYPE_B_W, 1.0, 1.0, 0, 0); if (im_setupout(out)) return -1; /* Make an output buffer. */ if (!(buf = IM_ARRAY(out, in->xsize, double))) return -1; /* Write! */ for (p = in->coeff, y = 0; y < out->Ysize; y++) { q = buf; for (x = 0; x < out->Xsize; x++) *q++ = *p++; if (im_writeline(y, out, (void *) buf)) return -1; } vips_image_set_double(out, "scale", in->scale); vips_image_set_double(out, "offset", in->offset); return 0; } int im_imask2vips(INTMASK *in, IMAGE *out) { DOUBLEMASK *d; int result; if (!(d = im_imask2dmask(in, in->filename))) return -1; result = im_mask2vips(d, out); im_free_dmask(d); return result; } libvips-8.18.2/libvips/deprecated/im_matcat.c000066400000000000000000000041721516303661500211460ustar00rootroot00000000000000/* matrix catenate * * 1994, K. Martinez * * 22/10/10 * - gtk-doc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /** * im_matcat: * @top: input matrix * @bottom: input matrix * @filename: filename for output * * Matrix catenations. Returns a new matrix which is the two source matrices * joined together top-bottom. They must be the same width. * * See also: im_mattrn(), im_matmul(), im_matinv(). * * Returns: the joined mask on success, or NULL on error. */ DOUBLEMASK * im_matcat(DOUBLEMASK *top, DOUBLEMASK *bottom, const char *filename) { int newxsize, newysize; DOUBLEMASK *mat; double *out; /* matrices must be same width */ if (top->xsize != bottom->xsize) { im_error("im_matcat", "%s", _("matrices must be same width")); return NULL; } newxsize = top->xsize; newysize = top->ysize + bottom->ysize; /* Allocate output matrix. */ if (!(mat = im_create_dmask(filename, newxsize, newysize))) return NULL; /* copy first matrix then add second on the end */ memcpy(mat->coeff, top->coeff, top->xsize * top->ysize * sizeof(double)); out = mat->coeff + top->xsize * top->ysize; memcpy(out, bottom->coeff, bottom->xsize * bottom->ysize * sizeof(double)); return mat; } libvips-8.18.2/libvips/deprecated/im_matinv.c000066400000000000000000000256551516303661500212040ustar00rootroot00000000000000/* solve and invert matrices * * Author: Tom Vajzovic * Copyright: 2006, Tom Vajzovic * Written on: 2006-09-08 * * undated: * - page 43-45 of numerical recipes in C 1998 * * 2006-09-08 tcv: * - complete rewrite; algorithm unchanged * * 22/10/10 * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #define TOO_SMALL (2.0 * DBL_MIN) /* DBL_MIN is smallest *normalized* double precision float */ #define MATRIX(mask, i, j) ((mask)->coeff[(j) + (i) * (mask)->xsize]) /* use DOUBLEMASK or INTMASK as matrix type */ static int mat_inv_lu( DOUBLEMASK *inv, const DOUBLEMASK *lu); static int mat_inv_direct( DOUBLEMASK *inv, const DOUBLEMASK *mat, const char *function_name); /** * im_lu_decomp: * @mat: matrix to decompose * @filename: name for output matrix * * This function takes any square NxN #DOUBLEMASK. * It returns a #DOUBLEMASK which is (N+1)xN. * * It calculates the PLU decomposition, storing the upper and diagonal parts * of U, together with the lower parts of L, as an NxN matrix in the first * N rows of the new matrix. The diagonal parts of L are all set to unity * and are not stored. * * The final row of the new #DOUBLEMASK has only integer entries, which * represent the row-wise permutations made by the permuatation matrix P. * * The scale and offset members of the input #DOUBLEMASK are ignored. * * See: * * PRESS, W. et al, 1992. Numerical Recipies in C; The Art of Scientific * Computing, 2nd ed. Cambridge: Cambridge University Press, pp. 43-50. * * See also: im_mattrn(), im_matinv(). * * Returns: the decomposed matrix on success, or NULL on error. */ DOUBLEMASK * im_lu_decomp( const DOUBLEMASK *mat, const char *name) { #define FUNCTION_NAME "im_lu_decomp" int i, j, k; double *row_scale; DOUBLEMASK *lu; if (mat->xsize != mat->ysize) { im_error(FUNCTION_NAME, "non-square matrix"); return NULL; } #define N (mat->xsize) lu = im_create_dmask(name, N, N + 1); row_scale = IM_ARRAY(NULL, N, double); if (!row_scale || !lu) { im_free_dmask(lu); im_free(row_scale); return NULL; } /* copy all coefficients and then perform decomposition in-place */ memcpy(lu->coeff, mat->coeff, N * N * sizeof(double)); #define LU(i, j) MATRIX(lu, (i), (j)) #define perm (lu->coeff + N * N) for (i = 0; i < N; ++i) { row_scale[i] = 0.0; for (j = 0; j < N; ++j) { double abs_val = fabs(LU(i, j)); /* find largest in each ROW */ if (abs_val > row_scale[i]) row_scale[i] = abs_val; } if (!row_scale[i]) { im_error(FUNCTION_NAME, "singular matrix"); im_free_dmask(lu); im_free(row_scale); return NULL; } /* fill array with scaling factors for each ROW */ row_scale[i] = 1.0 / row_scale[i]; } for (j = 0; j < N; ++j) { /* loop over COLs */ double max = -1.0; int i_of_max; /* not needed, but stops a compiler warning */ i_of_max = 0; /* loop over ROWS in upper-half, except diagonal */ for (i = 0; i < j; ++i) for (k = 0; k < i; ++k) LU(i, j) -= LU(i, k) * LU(k, j); /* loop over ROWS in diagonal and lower-half */ for (i = j; i < N; ++i) { double abs_val; for (k = 0; k < j; ++k) LU(i, j) -= LU(i, k) * LU(k, j); /* find largest element in each COLUMN scaled so that */ /* largest in each ROW is 1.0 */ abs_val = row_scale[i] * fabs(LU(i, j)); if (abs_val > max) { max = abs_val; i_of_max = i; } } if (fabs(LU(i_of_max, j)) < TOO_SMALL) { /* divisor is near zero */ im_error(FUNCTION_NAME, "singular or near-singular matrix"); im_free_dmask(lu); im_free(row_scale); return NULL; } if (i_of_max != j) { /* swap ROWS */ for (k = 0; k < N; ++k) { double temp = LU(j, k); LU(j, k) = LU(i_of_max, k); LU(i_of_max, k) = temp; } row_scale[i_of_max] = row_scale[j]; /* no need to copy this scale back up - we won't use it */ } /* record permutation */ perm[j] = i_of_max; /* divide by best (largest scaled) pivot found */ for (i = j + 1; i < N; ++i) LU(i, j) /= LU(j, j); } im_free(row_scale); return lu; #undef N #undef LU #undef perm #undef FUNCTION_NAME } /** * im_lu_solve: * @lu: matrix to solve * @vec: name for output matrix * * Solve the system of linear equations Ax=b, where matrix A has already * been decomposed into LU form in DOUBLEMASK *lu. Input vector b is in * vec and is overwritten with vector x. * * See: * * PRESS, W. et al, 1992. Numerical Recipies in C; The Art of Scientific * Computing, 2nd ed. Cambridge: Cambridge University Press, pp. 43-50. * * See also: im_mattrn(), im_matinv(). * * Returns: the decomposed matrix on success, or NULL on error. */ int im_lu_solve( const DOUBLEMASK *lu, double *vec) { #define FUNCTION_NAME "im_lu_solve" int i, j; if (lu->xsize + 1 != lu->ysize) { im_error(FUNCTION_NAME, "not an LU decomposed matrix"); return -1; } #define N (lu->xsize) #define LU(i, j) MATRIX(lu, (i), (j)) #define perm (lu->coeff + N * N) for (i = 0; i < N; ++i) { int i_perm = perm[i]; if (i_perm != i) { double temp = vec[i]; vec[i] = vec[i_perm]; vec[i_perm] = temp; } for (j = 0; j < i; ++j) vec[i] -= LU(i, j) * vec[j]; } for (i = N - 1; i >= 0; --i) { for (j = i + 1; j < N; ++j) vec[i] -= LU(i, j) * vec[j]; vec[i] /= LU(i, i); } return 0; #undef LU #undef perm #undef N #undef FUNCTION_NAME } /** * im_matinv: * @mat: matrix to invert * @filename: name for output matrix * * Allocate, and return a pointer to, a DOUBLEMASK representing the * inverse of the matrix represented in @mat. Give it the filename * member @filename. Returns NULL on error. Scale and offset are ignored. * * See also: im_mattrn(). * * Returns: the inverted matrix on success, or %NULL on error. */ DOUBLEMASK * im_matinv( const DOUBLEMASK *mat, const char *filename) { #define FUNCTION_NAME "im_matinv" DOUBLEMASK *inv; if (mat->xsize != mat->ysize) { im_error(FUNCTION_NAME, "non-square matrix"); return NULL; } #define N (mat->xsize) inv = im_create_dmask(filename, N, N); if (!inv) return NULL; if (N < 4) { if (mat_inv_direct(inv, (const DOUBLEMASK *) mat, FUNCTION_NAME)) { im_free_dmask(inv); return NULL; } return inv; } else { DOUBLEMASK *lu = im_lu_decomp(mat, "temp"); if (!lu || mat_inv_lu(inv, (const DOUBLEMASK *) lu)) { im_free_dmask(lu); im_free_dmask(inv); return NULL; } im_free_dmask(lu); return inv; } #undef N #undef FUNCTION_NAME } /** * im_matinv_inplace: * @mat: matrix to invert * * Invert the matrix represented by the DOUBLEMASK @mat, and store * it in the place of @mat. Scale and offset * are ignored. * * See also: im_mattrn(). * * Returns: 0 on success, or -1 on error. */ int im_matinv_inplace( DOUBLEMASK *mat) { #define FUNCTION_NAME "im_matinv_inplace" int to_return = 0; if (mat->xsize != mat->ysize) { im_error(FUNCTION_NAME, "non-square matrix"); return -1; } #define N (mat->xsize) if (N < 4) { DOUBLEMASK *dup = im_dup_dmask(mat, "temp"); if (!dup) return -1; to_return = mat_inv_direct(mat, (const DOUBLEMASK *) dup, FUNCTION_NAME); im_free_dmask(dup); return to_return; } { DOUBLEMASK *lu; lu = im_lu_decomp(mat, "temp"); if (!lu || mat_inv_lu(mat, (const DOUBLEMASK *) lu)) to_return = -1; im_free_dmask(lu); return to_return; } #undef N #undef FUNCTION_NAME } /* Invert a square size x size matrix stored in matrix[][] * result is returned in the same matrix */ int im_invmat( double **matrix, int size) { DOUBLEMASK *mat = im_create_dmask("temp", size, size); int i; int to_return = 0; for (i = 0; i < size; ++i) memcpy(mat->coeff + i * size, matrix[i], size * sizeof(double)); to_return = im_matinv_inplace(mat); if (!to_return) for (i = 0; i < size; ++i) memcpy(matrix[i], mat->coeff + i * size, size * sizeof(double)); im_free_dmask(mat); return to_return; } static int mat_inv_lu( DOUBLEMASK *inv, const DOUBLEMASK *lu) { #define N (lu->xsize) #define INV(i, j) MATRIX(inv, (i), (j)) int i, j; double *vec = IM_ARRAY(NULL, N, double); if (!vec) return -1; for (j = 0; j < N; ++j) { for (i = 0; i < N; ++i) vec[i] = 0.0; vec[j] = 1.0; im_lu_solve(lu, vec); for (i = 0; i < N; ++i) INV(i, j) = vec[i]; } im_free(vec); inv->scale = 1.0; inv->offset = 0.0; return 0; #undef N #undef INV } static int mat_inv_direct( DOUBLEMASK *inv, const DOUBLEMASK *mat, const char *function_name) { #define N (mat->xsize) #define MAT(i, j) MATRIX(mat, (i), (j)) #define INV(i, j) MATRIX(inv, (i), (j)) inv->scale = 1.0; inv->offset = 0.0; switch (N) { case 1: { if (fabs(MAT(0, 0)) < TOO_SMALL) { im_error(function_name, "singular or near-singular matrix"); return -1; } INV(0, 0) = 1.0 / MAT(0, 0); return 0; } case 2: { double det = MAT(0, 0) * MAT(1, 1) - MAT(0, 1) * MAT(1, 0); if (fabs(det) < TOO_SMALL) { im_error(function_name, "singular or near-singular matrix"); return -1; } INV(0, 0) = MAT(1, 1) / det; INV(0, 1) = -MAT(0, 1) / det; INV(1, 0) = -MAT(1, 0) / det; INV(1, 1) = MAT(0, 0) / det; return 0; } case 3: { double det = MAT(0, 0) * (MAT(1, 1) * MAT(2, 2) - MAT(1, 2) * MAT(2, 1)) - MAT(0, 1) * (MAT(1, 0) * MAT(2, 2) - MAT(1, 2) * MAT(2, 0)) + MAT(0, 2) * (MAT(1, 0) * MAT(2, 1) - MAT(1, 1) * MAT(2, 0)); if (fabs(det) < TOO_SMALL) { im_error(function_name, "singular or near-singular matrix"); return -1; } INV(0, 0) = (MAT(1, 1) * MAT(2, 2) - MAT(1, 2) * MAT(2, 1)) / det; INV(0, 1) = (MAT(0, 2) * MAT(2, 1) - MAT(0, 1) * MAT(2, 2)) / det; INV(0, 2) = (MAT(0, 1) * MAT(1, 2) - MAT(0, 2) * MAT(1, 1)) / det; INV(1, 0) = (MAT(1, 2) * MAT(2, 0) - MAT(1, 0) * MAT(2, 2)) / det; INV(1, 1) = (MAT(0, 0) * MAT(2, 2) - MAT(0, 2) * MAT(2, 0)) / det; INV(1, 2) = (MAT(0, 2) * MAT(1, 0) - MAT(0, 0) * MAT(1, 2)) / det; INV(2, 0) = (MAT(1, 0) * MAT(2, 1) - MAT(1, 1) * MAT(2, 0)) / det; INV(2, 1) = (MAT(0, 1) * MAT(2, 0) - MAT(0, 0) * MAT(2, 1)) / det; INV(2, 2) = (MAT(0, 0) * MAT(1, 1) - MAT(0, 1) * MAT(1, 0)) / det; return 0; } default: return -1; } #undef N #undef MAT #undef INV } libvips-8.18.2/libvips/deprecated/im_matmul.c000066400000000000000000000043421516303661500211730ustar00rootroot00000000000000/* Multiply two matrices. * * Copyright: 1990, K. Martinez and J. Cupitt * * 23/10/10 * - gtk-doc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /** * im_matmul: * @in1: input matrix * @in2: input matrix * @filename: name for output matrix * * Multiplies two DOUBLEMASKs. Result matrix is made and returned. * Pass the filename to set for the output. * * The scale and offset members of @in1 and @in2 are ignored. * * See also: im_mattrn(), im_matinv(). * * Returns: the result matrix on success, or %NULL on error. */ DOUBLEMASK * im_matmul(DOUBLEMASK *in1, DOUBLEMASK *in2, const char *name) { int xc, yc, col; double sum; DOUBLEMASK *mat; double *out, *a, *b; double *s1, *s2; /* Check matrix sizes. */ if (in1->xsize != in2->ysize) { im_error("im_matmul", "%s", _("bad sizes")); return NULL; } /* Allocate output matrix. */ if (!(mat = im_create_dmask(name, in2->xsize, in1->ysize))) return NULL; /* Multiply. */ out = mat->coeff; s1 = in1->coeff; for (yc = 0; yc < in1->ysize; yc++) { s2 = in2->coeff; for (col = 0; col < in2->xsize; col++) { /* Get ready to sweep a row. */ sum = 0.0; a = s1; b = s2; for (sum = 0.0, xc = 0; xc < in1->xsize; xc++) { sum += *a++ * *b; b += in2->xsize; } *out++ = sum; s2++; } s1 += in1->xsize; } return mat; } libvips-8.18.2/libvips/deprecated/im_mattrn.c000066400000000000000000000034001516303661500211730ustar00rootroot00000000000000/* matrix transpose * * Copyright: 1990, K. Martinez and J. Cupitt * */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /** * im_mattrn: * @in: input matrix * @filename: name for output matrix * * Transposes the input matrix. * Pass the filename to set for the output. * * See also: im_matmul(), im_matinv(). * * Returns: the result matrix on success, or %NULL on error. */ DOUBLEMASK * im_mattrn(DOUBLEMASK *in, const char *name) { int xc, yc; DOUBLEMASK *mat; double *out, *a, *b; /* Allocate output matrix. */ if (!(mat = im_create_dmask(name, in->ysize, in->xsize))) return NULL; mat->scale = in->scale; mat->offset = in->offset; /* Transpose. */ out = mat->coeff; a = in->coeff; for (yc = 0; yc < mat->ysize; yc++) { b = a; for (xc = 0; xc < mat->xsize; xc++) { *out++ = *b; b += in->xsize; } a++; } return mat; } libvips-8.18.2/libvips/deprecated/im_maxpos_avg.c000066400000000000000000000150551516303661500220430ustar00rootroot00000000000000/* im_maxpos_avg.c * * Copyright: 2006, The Nottingham Trent University * Copyright: 2006, Tom Vajzovic * * Author: Tom Vajzovic * * Written on: 2006-09-25 * 15/10/07 JC * - changed spelling of occurrences * - check for !occurrences before using val * - renamed avg as sum, a bit clearer * 2/9/09 * - gtkdoc comment * 8/9/08 * - rewrite from im_maxpos() * - now handles many bands, complex, faster * 27/7/14 * - fix a race ... did not merge states if max was equal * 26/3/15 * - avoid NaN, thanks Paul */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include /* A position and maximum. */ typedef struct _Maxposavg { int xpos; int ypos; double max; /* occurences == 0 means we found no points, or we are uninitialised. */ int occurences; } Maxposavg; /* New sequence value. */ static void * maxposavg_start(IMAGE *in, void *a, void *b) { Maxposavg *global_maxposavg = (Maxposavg *) b; Maxposavg *maxposavg; if (!(maxposavg = IM_NEW(NULL, Maxposavg))) return NULL; *maxposavg = *global_maxposavg; return (void *) maxposavg; } /* Merge the sequence value back into the per-call state. */ static int maxposavg_stop(void *seq, void *a, void *b) { Maxposavg *global_maxposavg = (Maxposavg *) b; Maxposavg *maxposavg = (Maxposavg *) seq; /* Merge. */ if (maxposavg->occurences == 0) { } else if (maxposavg->max > global_maxposavg->max) *global_maxposavg = *maxposavg; else if (maxposavg->max == global_maxposavg->max) { global_maxposavg->xpos += maxposavg->xpos; global_maxposavg->ypos += maxposavg->ypos; global_maxposavg->occurences += maxposavg->occurences; } im_free(seq); return 0; } /* int loop. */ #define ILOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ m = max; \ \ for (x = 0; x < sz; x++) { \ TYPE v = p[x]; \ \ if (occurences == 0 || v > m) { \ m = v; \ xpos = r->left + x / reg->im->Bands; \ ypos = r->top + y; \ occurences = 1; \ } \ else if (v == m) { \ xpos += r->left + x / reg->im->Bands; \ ypos += r->top + y; \ occurences += 1; \ } \ } \ \ max = m; \ } /* float/double loop ... avoid NaN. */ #define FLOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ TYPE m; \ \ m = max; \ \ for (x = 0; x < sz; x++) { \ TYPE v = p[x]; \ \ if (isnan(v)) { \ } \ else if (occurences == 0 || v > m) { \ m = v; \ xpos = r->left + x / reg->im->Bands; \ ypos = r->top + y; \ occurences = 1; \ } \ else if (v == m) { \ xpos += r->left + x / reg->im->Bands; \ ypos += r->top + y; \ occurences += 1; \ } \ } \ \ max = m; \ } /* complex/dpcomplex loop ... avoid NaN. */ #define CLOOP(TYPE) \ { \ TYPE *p = (TYPE *) in; \ \ for (x = 0; x < sz; x++) { \ double mod, re, im; \ \ re = p[0]; \ im = p[1]; \ p += 2; \ mod = re * re + im * im; \ \ if (isnan(mod)) { \ } \ else if (occurences == 0 || mod > max) { \ max = mod; \ xpos = r->left + x / reg->im->Bands; \ ypos = r->top + y; \ occurences = 1; \ } \ else if (mod == max) { \ xpos += r->left + x / reg->im->Bands; \ ypos += r->top + y; \ occurences += 1; \ } \ } \ } /* Loop over region, adding to seq. */ static int maxposavg_scan(REGION *reg, void *seq, void *a, void *b, gboolean *stop) { const Rect *r = ®->valid; const int sz = IM_REGION_N_ELEMENTS(reg); Maxposavg *maxposavg = (Maxposavg *) seq; int x, y; double max; int xpos, ypos, occurences; xpos = maxposavg->xpos; ypos = maxposavg->ypos; max = maxposavg->max; occurences = maxposavg->occurences; for (y = 0; y < r->height; y++) { VipsPel *in = VIPS_REGION_ADDR(reg, r->left, r->top + y); switch (reg->im->BandFmt) { case IM_BANDFMT_UCHAR: ILOOP(unsigned char); break; case IM_BANDFMT_CHAR: ILOOP(signed char); break; case IM_BANDFMT_USHORT: ILOOP(unsigned short); break; case IM_BANDFMT_SHORT: ILOOP(signed short); break; case IM_BANDFMT_UINT: ILOOP(unsigned int); break; case IM_BANDFMT_INT: ILOOP(signed int); break; case IM_BANDFMT_FLOAT: FLOOP(float); break; case IM_BANDFMT_DOUBLE: FLOOP(double); break; case IM_BANDFMT_COMPLEX: CLOOP(float); break; case IM_BANDFMT_DPCOMPLEX: CLOOP(double); break; default: g_assert(0); } } maxposavg->xpos = xpos; maxposavg->ypos = ypos; maxposavg->max = max; maxposavg->occurences = occurences; return 0; } /** * im_maxpos_avg: * @im: image to scan * @xpos: returned X position * @ypos: returned Y position * @out: returned value * * Function to find the maximum of an image. Returns coords and value at * double precision. In the event of a draw, returns average of all * drawing coords. * * See also: im_maxpos(), im_min(), im_stats(). * * Returns: 0 on success, -1 on error */ int im_maxpos_avg(IMAGE *in, double *xpos, double *ypos, double *out) { Maxposavg *global_maxposavg; if (im_pincheck(in) || im_check_uncoded("im_maxpos_avg", in)) return -1; if (!(global_maxposavg = IM_NEW(in, Maxposavg))) return -1; global_maxposavg->occurences = 0; if (vips_sink(in, maxposavg_start, maxposavg_scan, maxposavg_stop, in, global_maxposavg)) return -1; if (global_maxposavg->occurences == 0) { *xpos = nan(""); *ypos = nan(""); *out = nan(""); } else { /* Back to modulus. */ if (vips_band_format_iscomplex(in->BandFmt)) global_maxposavg->max = sqrt(global_maxposavg->max); if (xpos) *xpos = (double) global_maxposavg->xpos / global_maxposavg->occurences; if (ypos) *ypos = (double) global_maxposavg->ypos / global_maxposavg->occurences; if (out) *out = global_maxposavg->max; } return 0; } libvips-8.18.2/libvips/deprecated/im_maxpos_subpel.c000066400000000000000000000104401516303661500225510ustar00rootroot00000000000000/* find position of maximum, subpixel estimation * * Copyright: 2008, Nottingham Trent University * Author: Tom Vajzovic * Written on: 2008-02-07 * * 25/1/11 * - gtk-doc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H */ #include #include #include #define MOST_OF(A, B) ((A) > 0.9 * (B)) #define LITTLE_OF(A, B) ((B) < 0.1 * (B)) /** * im_maxpos_subpel: * @in: input image * @x: output position of maximum * @y: output position of maximum * * This function implements: * * "Extension of Phase Correlation to Subpixel Registration" * by H. Foroosh, from IEEE trans. Im. Proc. 11(3), 2002. * * If the best three matches in the correlation are aranged: * * 02 or 01 * 1 2 * * then we return a subpixel match using the ratio of correlations in the * vertical and horizontal dimension. * * (xs[0], ys[0]) is the best integer alignment * (xs[ use_x ], ys[ use_x ]) is equal in y and (+/-)1 off in x * (xs[ use_y ], ys[ use_y ]) is equal in x and (+/-)1 off in y * * Alternatively if the best four matches in the correlation are aranged in * a square: * * 01 or 03 or 02 or 03 * 32 12 31 21 * * then we return a subpixel match weighting with the sum the two on each * side over the sum of all four, but only if all four of them are very * close to the best, and the fifth is nowhere near. * * This alternative method is not described by Foroosh, but is often the * case where the match is close to n-and-a-half pixels in both dimensions. * * See also: im_maxpos(), im_min(), im_stats(). * * Returns: 0 on success, -1 on error */ int im_maxpos_subpel(IMAGE *in, double *x, double *y) { #define FUNCTION_NAME "im_maxpos_subpel" int xs[5]; int ys[5]; double vals[5]; int xa, ya, xb, yb; double vxa, vya, vxb, vyb; if (im_maxpos_vec(in, xs, ys, vals, 5)) return -1; #define WRAP_TEST_RETURN() \ \ /* wrap around if we have alignment -1 < d <= 0 */ \ /* (change it to: size - 1 <= d < size ) */ \ \ if (!xa && in->Xsize - 1 == xb) \ xa = in->Xsize; \ \ else if (!xb && in->Xsize - 1 == xa) \ xb = in->Xsize; \ \ if (!ya && in->Ysize - 1 == yb) \ ya = in->Ysize; \ \ else if (!yb && in->Ysize - 1 == ya) \ yb = in->Ysize; \ \ if (1 == abs(xb - xa) && 1 == abs(yb - ya)) { \ *x = ((double) xa) + ((double) (xb - xa)) * (vxb / (vxa + vxb)); \ *y = ((double) ya) + ((double) (yb - ya)) * (vyb / (vya + vyb)); \ return 0; \ } #define TEST3(A, B) \ if (xs[0] == xs[A] && ys[0] == ys[B]) { \ xa = xs[0]; \ ya = ys[0]; \ xb = xs[B]; \ yb = ys[A]; \ vxa = vals[0]; \ vya = vals[0]; \ vxb = vals[B]; \ vyb = vals[A]; \ WRAP_TEST_RETURN() \ } TEST3(1, 2) TEST3(2, 1) if (MOST_OF(vals[1], vals[0]) && MOST_OF(vals[2], vals[0]) && MOST_OF(vals[3], vals[0]) && LITTLE_OF(vals[4], vals[0])) { #define TEST4(A, B, C, D, E, F, G, H) \ if (xs[A] == xs[B] && xs[C] == xs[D] && ys[E] == ys[F] && ys[G] == ys[H]) { \ xa = xs[A]; \ xb = xs[C]; \ ya = ys[E]; \ yb = ys[G]; \ vxa = vals[A] + vals[B]; \ vxb = vals[C] + vals[D]; \ vya = vals[E] + vals[F]; \ vyb = vals[G] + vals[H]; \ WRAP_TEST_RETURN() \ } TEST4(0, 3, 1, 2, 0, 1, 2, 3) TEST4(0, 1, 2, 3, 0, 3, 1, 2) TEST4(0, 3, 1, 2, 0, 2, 1, 3) TEST4(0, 2, 1, 3, 0, 3, 1, 2) } im_warn(FUNCTION_NAME, "registration performed to nearest pixel only: correlation does not have the expected distribution for sub-pixel registration"); *x = (double) xs[0]; *y = (double) ys[0]; return 0; } libvips-8.18.2/libvips/deprecated/im_measure.c000066400000000000000000000121701516303661500213330ustar00rootroot00000000000000/* im_measure.c * * Modified: * 19/8/94 JC * - now uses doubles for addressing * - could miss by up to h pixels previously! * - ANSIfied * - now issues warning if any deviations are greater than 20% of the * mean * 31/10/95 JC * - more careful about warning for averages <0, or averages near zero * - can get these cases with im_measure() of IM_TYPE_LAB images * 28/10/02 JC * - number bands from zero in error messages * 7/7/04 * - works on labq * 18/8/08 * - add gtkdoc comments * - remove deprecated im_extract() * 30/11/09 * - changes for im_extract() broke averaging * 9/11/11 * - moved to deprecated, the new VipsMeasure does not have the * select-patches thing, so we have to keep this around */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* Measure into array. */ static int measure_patches(IMAGE *im, double *coeff, int left, int top, int width, int height, int u, int v, int *sel, int nsel) { IMAGE *tmp; int patch; int i, j; int m, n; double avg, dev; int x, y, w, h; /* How large are the patches we are to measure? */ double pw = (double) width / (double) u; double ph = (double) height / (double) v; /* Set up sub to be the size we need for a patch. */ w = (pw + 1) / 2; h = (ph + 1) / 2; /* Loop through sel, picking out areas to measure. */ for (j = 0, patch = 0; patch < nsel; patch++) { /* Sanity check. Is the patch number sensible? */ if (sel[patch] <= 0 || sel[patch] > u * v) { im_error("im_measure", _("patch %d is out of range"), sel[patch]); return 1; } /* Patch coordinates. */ m = (sel[patch] - 1) % u; n = (sel[patch] - 1) / u; /* Move sub to correct position. */ x = left + m * pw + (pw + 2) / 4; y = top + n * ph + (ph + 2) / 4; /* Loop through bands. */ for (i = 0; i < im->Bands; i++, j++) { /* Make temp buffer to extract to. */ if (!(tmp = im_open("patch", "t"))) return -1; /* Extract and measure. */ if (im_extract_areabands(im, tmp, x, y, w, h, i, 1) || im_avg(tmp, &avg) || im_deviate(tmp, &dev)) { im_close(tmp); return -1; } im_close(tmp); /* Is the deviation large compared with the average? * This could be a clue that our parameters have * caused us to miss the patch. Look out for averages * <0, or averages near zero (can get these if use * im_measure() on IM_TYPE_LAB images). */ if (dev * 5 > fabs(avg) && fabs(avg) > 3) im_warn("im_measure", _("patch %d, band %d: " "avg = %g, sdev = %g"), patch, i, avg, dev); /* Save results. */ coeff[j] = avg; } } return 0; } static DOUBLEMASK * internal_im_measure_area(IMAGE *im, int left, int top, int width, int height, int u, int v, int *sel, int nsel, const char *name) { DOUBLEMASK *mask; if (im_check_uncoded("im_measure", im) || im_check_noncomplex("im_measure", im)) return NULL; /* Default to all patches if sel == NULL. */ if (sel == NULL) { int i; nsel = u * v; if (!(sel = IM_ARRAY(im, nsel, int))) return NULL; for (i = 0; i < nsel; i++) sel[i] = i + 1; } /* What size mask do we need? */ if (!(mask = im_create_dmask(name, im->Bands, nsel))) return NULL; /* Perform measure and return. */ if (measure_patches(im, mask->coeff, left, top, width, height, u, v, sel, nsel)) { im_free_dmask(mask); return NULL; } return mask; } DOUBLEMASK * im_measure_area(IMAGE *im, int left, int top, int width, int height, int u, int v, int *sel, int nsel, const char *name) { DOUBLEMASK *mask; VipsImage *t; /* The old im_measure() worked on labq. */ if (im->Coding == IM_CODING_LABQ) { if (!(t = im_open("measure-temp", "p"))) return NULL; if (im_LabQ2Lab(im, t) || !(mask = im_measure_area(t, left, top, width, height, u, v, sel, nsel, name))) { g_object_unref(t); return NULL; } g_object_unref(t); return mask; } if (sel) return internal_im_measure_area(im, left, top, width, height, u, v, sel, nsel, name); else { if (vips_measure(im, &t, u, v, "left", left, "top", top, "width", width, "height", height, NULL)) return NULL; if (!(mask = im_vips2mask(t, name))) { g_object_unref(t); return NULL; } g_object_unref(t); return mask; } } libvips-8.18.2/libvips/deprecated/im_nifti2vips.c000066400000000000000000000051021516303661500217640ustar00rootroot00000000000000/* load nifti images * * 10/9/18 * - from im_openslide2vips */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include static int im_nifti2vips(const char *name, IMAGE *out) { VipsImage *t; if (vips_niftiload(name, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static const char *nifti_suffs[] = { ".nii", ".nii.gz", ".hdr", ".hdr.gz", ".img", ".img.gz", ".nia", ".nia.gz", NULL }; static VipsFormatFlags nifti_flags(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return (VipsFormatFlags) vips_foreign_flags("niftiload", filename); } static int isnifti(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return vips_foreign_is_a("niftiload", filename); } /* nifti format adds no new members. */ typedef VipsFormat VipsFormatNifti; typedef VipsFormatClass VipsFormatNiftiClass; static void vips_format_nifti_class_init(VipsFormatNiftiClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "im_nifti"; object_class->description = _("NIfTI"); format_class->priority = 100; format_class->is_a = isnifti; format_class->load = im_nifti2vips; format_class->get_flags = nifti_flags; format_class->suffs = nifti_suffs; } static void vips_format_nifti_init(VipsFormatNifti *object) { } G_DEFINE_TYPE(VipsFormatNifti, vips_format_nifti, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_openslide2vips.c000066400000000000000000000065401516303661500226440ustar00rootroot00000000000000/* read with openslide * * 17/12/11 * - just a stub * 11/4/12 * - support :level,associated in filenames * 20/9/12 * - add Leica filename suffix */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include static int im_openslide2vips(const char *name, IMAGE *out) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p, *q; char *associated; int level; char *endptr; VipsImage *t; im_filename_split(name, filename, mode); level = 0; associated = NULL; p = &mode[0]; if ((q = im_getnextoption(&p))) { level = strtoul(q, &endptr, 10); if (*endptr) { vips_error("openslide2vips", "%s", _("level must be a number")); return -1; } } if ((q = im_getnextoption(&p))) associated = q; if (vips_openslideload(filename, &t, "level", level, "associated", associated, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static const char *openslide_suffs[] = { ".svs", /* Aperio */ ".vms", ".vmu", ".ndpi", /* Hamamatsu */ ".scn", /* Leica */ ".mrxs", /* MIRAX */ ".svslide", /* Sakura */ ".tif", /* Trestle */ ".bif", /* Ventana */ NULL }; static VipsFormatFlags openslide_flags(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return (VipsFormatFlags) vips_foreign_flags("openslideload", filename); } static int isopenslide(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return vips_foreign_is_a("openslideload", filename); } /* openslide format adds no new members. */ typedef VipsFormat VipsFormatOpenslide; typedef VipsFormatClass VipsFormatOpenslideClass; static void vips_format_openslide_class_init(VipsFormatOpenslideClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "im_openslide"; object_class->description = _("Openslide"); format_class->priority = 100; format_class->is_a = isopenslide; format_class->load = im_openslide2vips; format_class->get_flags = openslide_flags; format_class->suffs = openslide_suffs; } static void vips_format_openslide_init(VipsFormatOpenslide *object) { } G_DEFINE_TYPE(VipsFormatOpenslide, vips_format_openslide, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_png2vips.c000066400000000000000000000042361516303661500214460ustar00rootroot00000000000000/* Convert 1 to 4-band 8 or 16-bit VIPS images to/from PNG. * * 19/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "../foreign/pforeign.h" int im_png2vips(const char *name, IMAGE *out) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; VipsImage *x; im_filename_split(name, filename, mode); if (vips_pngload(filename, &x, NULL)) return -1; if (vips_image_write(x, out)) { VIPS_UNREF(x); return -1; } VIPS_UNREF(x); return 0; } static int ispng(const char *filename) { return vips_foreign_is_a("pngload", filename); } static const char *png_suffs[] = { ".png", NULL }; typedef VipsFormat VipsFormatPng; typedef VipsFormatClass VipsFormatPngClass; static void vips_format_png_class_init(VipsFormatPngClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "png"; object_class->description = _("PNG"); format_class->is_a = ispng; format_class->load = im_png2vips; format_class->save = im_vips2png; format_class->suffs = png_suffs; } static void vips_format_png_init(VipsFormatPng *object) { } G_DEFINE_TYPE(VipsFormatPng, vips_format_png, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_point_bilinear.c000066400000000000000000000053501516303661500226720ustar00rootroot00000000000000/* im_point_bilinear.c * * Copyright: 2006, The Nottingham Trent University * * Author: Tom Vajzovic * * Written on: 2006-09-26 * * 9/9/09 * - rewrite in terms of im_affinei() and im_avg() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include #include /** * im_point: * @im: image to read from * @interpolate: interpolator to sample points with * @x: x position to interpolate * @y: y position to interpolate * @band: band to read * @out: return interpolated value * * Find the value at (@x, @y) in given band of image. * Non-integral values are calculated using the supplied @interpolate. * * See also: im_avg(), #VipsInterpolate * * Returns: 0 on success, -1 on error */ int im_point(IMAGE *im, VipsInterpolate *interpolate, double x, double y, int band, double *out) { IMAGE *mem; IMAGE *t[2]; if (band >= im->Bands || x < 0.0 || y < 0.0 || x > im->Xsize || y > im->Ysize) { im_error("im_point_bilinear", "%s", _("coords outside image")); return -1; } if (!(mem = im_open("im_point", "p"))) return -1; if (im_open_local_array(mem, t, 2, "im_point", "p") || im_extract_band(im, t[0], band) || im_affinei(t[0], t[1], interpolate, 1, 0, 0, 1, floor(x) - x, floor(y) - y, floor(x), floor(y), 1, 1) || im_avg(t[1], out)) { im_close(mem); return -1; } im_close(mem); return 0; } /** * im_point_bilinear: * @im: image to read from * @x: x position to interpolate * @y: y position to interpolate * @band: band to read * @out: return interpolated value * * Find the value at (@x,@y) in given band of image. * Use bilinear interpolation if @x or @y are non-integral. * * See also: im_avg(), im_point(). * * Returns: 0 on success, -1 on error */ int im_point_bilinear(IMAGE *im, double x, double y, int band, double *out) { return im_point(im, vips_interpolate_bilinear_static(), x, y, band, out); } libvips-8.18.2/libvips/deprecated/im_ppm2vips.c000066400000000000000000000042571516303661500214610ustar00rootroot00000000000000/* Read a ppm file. * * 20/12/11 * - just a compat stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include int im_ppm2vips(const char *filename, IMAGE *out) { VipsImage *t; if (vips_ppmload(filename, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int isppm(const char *filename) { return vips_foreign_is_a("ppmload", filename); } static VipsFormatFlags ppm_flags(const char *filename) { return (VipsFormatFlags) vips_foreign_flags("ppmload", filename); } static const char *ppm_suffs[] = { ".ppm", ".pgm", ".pbm", ".pfm", NULL }; /* ppm format adds no new members. */ typedef VipsFormat VipsFormatPpm; typedef VipsFormatClass VipsFormatPpmClass; static void vips_format_ppm_class_init(VipsFormatPpmClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "ppm"; object_class->description = _("PPM/PBM/PNM/PFM"); format_class->is_a = isppm; format_class->load = im_ppm2vips; format_class->save = im_vips2ppm; format_class->get_flags = ppm_flags; format_class->suffs = ppm_suffs; } static void vips_format_ppm_init(VipsFormatPpm *object) { } G_DEFINE_TYPE(VipsFormatPpm, vips_format_ppm, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_print.c000066400000000000000000000022421516303661500210250ustar00rootroot00000000000000/* im_print(): print a string to stdout */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* Print a string to stdout, with a "\n". Sometimes useful for debugging * language bindings. */ int im_print(const char *message) { printf("%s\n", message); return 0; } libvips-8.18.2/libvips/deprecated/im_printlines.c000066400000000000000000000073641516303661500220720ustar00rootroot00000000000000/* @(#) Function which prints in stdout the values of a picture * @(#) * @(#) For debuging only * @(#) is either memory mapped or in a buffer. * @(#) * @(#) void im_printlines(in) * @(#) IMAGE *in; * @(#) * * Copyright: 1991 N. Dessipris * * Author: N. Dessipris * Written on: 18/03/1991 * Modified on: * 15/4/93 J.Cupitt * - returns int, not void now, so error messages work * - detects im->data invalid. * 23/7/93 JC * - im_incheck() added */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* Useful: Call a macro with the name, type pairs for all VIPS functions. */ #define im_for_all_types() \ case IM_BANDFMT_UCHAR: \ loopuc(unsigned char); \ break; \ case IM_BANDFMT_CHAR: \ loop(char); \ break; \ case IM_BANDFMT_USHORT: \ loop(unsigned short); \ break; \ case IM_BANDFMT_SHORT: \ loop(short); \ break; \ case IM_BANDFMT_UINT: \ loop(unsigned int); \ break; \ case IM_BANDFMT_INT: \ loop(int); \ break; \ case IM_BANDFMT_FLOAT: \ loop(float); \ break; \ case IM_BANDFMT_DOUBLE: \ loop(double); \ break; \ case IM_BANDFMT_COMPLEX: \ loopcmplx(float); \ break; \ case IM_BANDFMT_DPCOMPLEX: \ loopcmplx(double); \ break; int im_printlines(IMAGE *in) { if (im_incheck(in)) return -1; if (in->Coding != IM_CODING_NONE) { im_error("im_printlines", "%s", _("input must be uncoded")); return -1; } if (!in->data) { im_error("im_debugim", "%s", _("unsuitable image type")); return -1; } /* What type? First define the loop we want to perform for all types. */ #define loopuc(TYPE) \ { \ TYPE *p = (TYPE *) in->data; \ int x, y, z; \ \ for (y = 0; y < in->Ysize; y++) { \ fprintf(stderr, "line:%5d\n", y); \ for (x = 0; x < in->Xsize; x++) { \ fprintf(stderr, "%5d", x); \ for (z = 0; z < in->Bands; z++) { \ fprintf(stderr, "\t%4d", (TYPE) *p++); \ } \ fprintf(stderr, "\n"); \ } \ } \ } #define loop(TYPE) \ { \ TYPE *p = (TYPE *) in->data; \ int x, y, z; \ \ for (y = 0; y < in->Ysize; y++) { \ fprintf(stderr, "line:%5d\n", y); \ for (x = 0; x < in->Xsize; x++) { \ fprintf(stderr, "%5d", x); \ for (z = 0; z < in->Bands; z++) { \ fprintf(stderr, "\t%f", (double) *p++); \ } \ fprintf(stderr, "\n"); \ } \ } \ } #define loopcmplx(TYPE) \ { \ TYPE *p = (TYPE *) in->data; \ int x, y, z; \ \ for (y = 0; y < in->Ysize; y++) { \ fprintf(stderr, "line:%5d\n", y); \ for (x = 0; x < in->Xsize; x++) { \ fprintf(stderr, "%5d", x); \ for (z = 0; z < in->Bands; z++) { \ fprintf(stderr, "\t%f", (double) *p++); \ fprintf(stderr, "\t%f", (double) *p++); \ } \ fprintf(stderr, "\n"); \ } \ } \ } /* Now generate code for all types. */ switch (in->BandFmt) { im_for_all_types(); default: { im_error("im_printlines", "%s", _("unknown input format")); return -1; } } return 0; } libvips-8.18.2/libvips/deprecated/im_resize_linear.c000066400000000000000000000110031516303661500225170ustar00rootroot00000000000000/* im_lowpass() * History: * 27/10/94 JC * - IM_ARRAY modified to use local allocation * - im_iscomplex() call added * 17/2/95 JC * - modernised a little * 18/8/95 JC * - name changed to reflect function more closely * 2/6/04 * - was detecting edges incorrectly, segv for some images (thanks Javi) */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* What we do for each pel. */ #define LOOP(TYPE) \ if (Xint >= 0 && Yint >= 0 && \ Xint < in->Xsize - 1 && Yint < in->Ysize - 1) \ for (bb = 0; bb < in->Bands; bb++) { \ TYPE s1 = *((TYPE *) p); \ TYPE s2 = *((TYPE *) (p + ips)); \ TYPE s3 = *((TYPE *) (p + ils)); \ TYPE s4 = *((TYPE *) (p + ips + ils)); \ TYPE *t = (TYPE *) q; \ \ *t = (1 - dx) * (1 - dy) * s1 + dx * (1 - dy) * s2 + \ dy * (1 - dx) * s3 + dx * dy * s4; \ \ p += ies; \ q += oes; \ } \ else if (Xint == in->Xsize - 1 && Yint >= 0 && Yint < in->Ysize - 1) \ for (bb = 0; bb < in->Bands; bb++) { \ TYPE s1 = *((TYPE *) p); \ TYPE s3 = *((TYPE *) (p + ils)); \ TYPE *t = (TYPE *) q; \ \ *t = (1 - dy) * s1 + dy * s3; \ \ p += ies; \ q += oes; \ } \ else if (Yint == in->Ysize - 1 && Xint >= 0 && Xint < in->Xsize - 1) \ for (bb = 0; bb < in->Bands; bb++) { \ TYPE s1 = *((TYPE *) p); \ TYPE s2 = *((TYPE *) (p + ips)); \ TYPE *t = (TYPE *) q; \ \ *t = (1 - dx) * s1 + dx * s2; \ \ p += ies; \ q += oes; \ } \ else \ for (bb = 0; bb < in->Bands; bb++) { \ unsigned char s1 = *((unsigned char *) p); \ TYPE *t = (TYPE *) q; \ \ *t = s1; \ \ p += ies; \ q += oes; \ } int im_resize_linear(IMAGE *in, IMAGE *out, int X, int Y) { double dx, dy, xscale, yscale; double Xnew, Ynew; /* inv. coord. of the interpolated pt */ int x, y; int Xint, Yint; int bb; PEL *input, *opline; PEL *q, *p; int ils, ips, ies; /* Input and output line, pel and */ int ols, oes; /* element sizes */ if (im_iocheck(in, out)) return -1; if (vips_band_format_iscomplex(in->BandFmt)) { im_error("im_lowpass", "%s", _("non-complex input only")); return -1; } if (in->Coding != IM_CODING_NONE) { im_error("im_lowpass: ", "%s", _("put should be uncoded")); return -1; } if (im_cp_desc(out, in)) return -1; out->Xsize = X; out->Ysize = Y; if (im_setupout(out)) return -1; ils = IM_IMAGE_SIZEOF_LINE(in); ips = IM_IMAGE_SIZEOF_PEL(in); ies = IM_IMAGE_SIZEOF_ELEMENT(in); ols = IM_IMAGE_SIZEOF_LINE(out); oes = IM_IMAGE_SIZEOF_ELEMENT(out); /* buffer lines ***************/ if (!(opline = IM_ARRAY(out, ols, PEL))) return -1; /* Resampling *************/ input = (PEL *) in->data; xscale = ((double) in->Xsize - 1) / (X - 1); yscale = ((double) in->Ysize - 1) / (Y - 1); for (y = 0; y < Y; y++) { q = opline; for (x = 0; x < X; x++) { Xnew = x * xscale; Ynew = y * yscale; Xint = floor(Xnew); Yint = floor(Ynew); dx = Xnew - Xint; dy = Ynew - Yint; p = input + Xint * ips + Yint * ils; switch (in->BandFmt) { case IM_BANDFMT_UCHAR: LOOP(unsigned char); break; case IM_BANDFMT_USHORT: LOOP(unsigned short); break; case IM_BANDFMT_UINT: LOOP(unsigned int); break; case IM_BANDFMT_CHAR: LOOP(signed char); break; case IM_BANDFMT_SHORT: LOOP(signed short); break; case IM_BANDFMT_INT: LOOP(signed int); break; case IM_BANDFMT_FLOAT: LOOP(float); break; case IM_BANDFMT_DOUBLE: LOOP(double); break; default: im_error("im_lowpass", "%s", _("unsupported image type")); return -1; /*NOTREACHED*/ } } if (im_writeline(y, out, opline)) return -1; } return 0; } libvips-8.18.2/libvips/deprecated/im_setbox.c000066400000000000000000000030551516303661500212000ustar00rootroot00000000000000/* @(#) Copies the coordinates of a box to an IMAGE_BOX * @(#) * @(#) Right call: * @(#) void im_setbox(pbox, xst, yst, xsiz, ysiz, ch_select) * @(#) IMAGE_BOX *pbox; * @(#) int xst, yst, xsiz, ysiz, ch_select; * @(#) ch_select could be 0, 1, 2 or 3 corresponding to * @(#) a, r , g or b respectively. * @(#) * * Copyright: Nicos Dessipris * Written on: 13/02/1990 * Modified on : 04/04/1990 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include void im_setbox(IMAGE_BOX *pbox, int xst, int yst, int xsiz, int ysiz, int ch_select) { pbox->xstart = xst; pbox->ystart = yst; pbox->xsize = xsiz; pbox->ysize = ysiz; pbox->chsel = ch_select; } libvips-8.18.2/libvips/deprecated/im_simcontr.c000066400000000000000000000063051516303661500215330ustar00rootroot00000000000000/* creates a pattern showing the similtaneous constrast effect * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 19/07/1991 * Modified on: * 22/7/93 JC * - externs removed * - im_outcheck() added * 1/2/11 * - gtk-doc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /** * im_simcontr: * @out: output image * @xsize: image size * @ysize: image size * * Creates a pattern showing the similtaneous constrast effect. * * See also: im_eye(). * * Returns: 0 on success, -1 on error */ int im_simcontr(IMAGE *out, int xsize, int ysize) { int x, y; unsigned char *line1, *line2, *cpline; /* Check input args */ if (im_outcheck(out)) return -1; /* Set now image properly */ im_initdesc(out, xsize, ysize, 1, IM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, IM_TYPE_B_W, 1.0, 1.0, 0, 0); /* Set up image checking whether the output is a buffer or a file */ if (im_setupout(out) == -1) return -1; /* Create data */ line1 = (unsigned char *) calloc((unsigned) xsize, sizeof(char)); line2 = (unsigned char *) calloc((unsigned) xsize, sizeof(char)); if ((line1 == NULL) || (line2 == NULL)) { im_error("im_simcontr", "%s", _("calloc failed")); return -1; } cpline = line1; for (x = 0; x < xsize; x++) *cpline++ = (PEL) 255; cpline = line1; for (x = 0; x < xsize / 2; x++) *cpline++ = (PEL) 0; cpline = line2; for (x = 0; x < xsize; x++) *cpline++ = (PEL) 255; cpline = line2; for (x = 0; x < xsize / 8; x++) *cpline++ = (PEL) 0; for (x = 0; x < xsize / 4; x++) *cpline++ = (PEL) 128; for (x = 0; x < xsize / 8; x++) *cpline++ = (PEL) 0; for (x = 0; x < xsize / 8; x++) *cpline++ = (PEL) 255; for (x = 0; x < xsize / 4; x++) *cpline++ = (PEL) 128; for (y = 0; y < ysize / 4; y++) { if (im_writeline(y, out, (PEL *) line1) == -1) { free((char *) line1); free((char *) line2); return -1; } } for (y = ysize / 4; y < (ysize / 4 + ysize / 2); y++) { if (im_writeline(y, out, (PEL *) line2) == -1) { free((char *) line1); free((char *) line2); return -1; } } for (y = (ysize / 4 + ysize / 2); y < ysize; y++) { if (im_writeline(y, out, (PEL *) line1) == -1) { free((char *) line1); free((char *) line2); return -1; } } free((char *) line1); free((char *) line2); return 0; } libvips-8.18.2/libvips/deprecated/im_slice.c000066400000000000000000000074521516303661500210000ustar00rootroot00000000000000/* @(#) Slices an image using two thresholds. Works for any non-complex type. * @(#) Output has three levels 0 128 and 255. Values below or = t1 are 0, * @(#) above t2 are 255 and the remaining are 128. * @(#) Input is either memory mapped or in a buffer. * @(#) It is implied that t1 is less than t2; however the program checks * @(#) if they are the wrong way and swaps them * @(#) * @(#) int im_slice(in, out, t1, t2) * @(#) IMAGE *in, *out; * @(#) double t1, t2; * @(#) * @(#) Returns 0 on success and -1 on error * * Copyright: 1991, N. Dessipris * * Author: N. Dessipris * Written on: 15/03/1991 * Modified on : */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #define BRIGHT 255 #define GREY 128 #define DARK 0 /* Useful: Call a macro with the name, type pairs for all VIPS functions. */ #define im_for_all_types(A) \ case IM_BANDFMT_UCHAR: \ A(unsigned char); \ break; \ case IM_BANDFMT_CHAR: \ A(signed char); \ break; \ case IM_BANDFMT_USHORT: \ A(unsigned short); \ break; \ case IM_BANDFMT_SHORT: \ A(signed short); \ break; \ case IM_BANDFMT_UINT: \ A(unsigned int); \ break; \ case IM_BANDFMT_INT: \ A(signed int); \ break; \ case IM_BANDFMT_FLOAT: \ A(float); \ break; /* Replacement for im_slice */ int im_slice(IMAGE *in, IMAGE *out, double t1, double t2) { int x, y, z; PEL *bu; /* Buffer we write to */ int s, epl; /* Size and els per line */ double thresh1, thresh2; /* Check our args. */ if (im_iocheck(in, out)) { im_error("im_slice", "%s", _("im_iocheck failed")); return -1; } if (in->Coding != IM_CODING_NONE) { im_error("im_slice", "%s", _("input should be uncoded")); return -1; } /* Set up the output header. */ if (im_cp_desc(out, in)) { im_error("im_slice", "%s", _("im_cp_desc failed")); return -1; } out->BandFmt = IM_BANDFMT_UCHAR; if (im_setupout(out)) { im_error("im_slice", "%s", _("im_setupout failed")); return -1; } if (t1 <= t2) { thresh1 = t1; thresh2 = t2; } else { thresh1 = t2; thresh2 = t1; } /* Make buffer for building o/p in. */ epl = in->Xsize * in->Bands; s = epl * sizeof(PEL); if ((bu = (PEL *) im_malloc(out, (unsigned) s)) == NULL) return -1; /* Define what we do for each band element type. */ #define im_slice_loop(TYPE) \ { \ TYPE *a = (TYPE *) in->data; \ \ for (y = 0; y < in->Ysize; y++) { \ PEL *b = bu; \ \ for (x = 0; x < in->Xsize; x++) \ for (z = 0; z < in->Bands; z++) { \ double f = (double) *a++; \ if (f <= thresh1) \ *b++ = (PEL) DARK; \ else if (f > thresh2) \ *b++ = (PEL) BRIGHT; \ else \ *b++ = (PEL) GREY; \ } \ \ if (im_writeline(y, out, bu)) \ return -1; \ } \ } /* Do the above for all image types. */ switch (in->BandFmt) { im_for_all_types(im_slice_loop); default: im_error("im_slice", "%s", _("Unknown input format")); return -1; } return 0; } libvips-8.18.2/libvips/deprecated/im_spatres.c000066400000000000000000000072661516303661500213650ustar00rootroot00000000000000/* @(#) Function which changes the spatial resolution of an image according to * @(#) step * @(#) * @(#) int im_spatres(in, out, step) * @(#) IMAGE *in, *out; * @(#) int step; * @(#) Returns either 0 (sucess) or -1 (fail) * @(#) * @(#) Picture can have any number of channels (max 64). * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 08/11/1989. * Modified on: 19/01/1990. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_spatres(IMAGE *in, IMAGE *out, int step) { int x, y; /* horizontal and vertical direction */ int z; /* 0 <= z < channel */ int i, j; int rounding, step2, sum; unsigned char *values; unsigned char *input, *cpinput, *cp2input, *line, *cpline, *pnt, *cpnt; int os; /* Check args */ if (step < 1) { im_error("im_spatres", _("Invalid step %d"), step); return -1; } if ((in->Xsize / step == 0) || (in->Ysize / step == 0)) { im_error("im_spatres", _("Invalid step %d"), step); return -1; } if (im_iocheck(in, out) == -1) return -1; if ((in->Coding != IM_CODING_NONE) || (in->BandFmt != IM_BANDFMT_UCHAR)) { im_error("im_spatres", "%s", _("wrong input")); return -1; } /* Prepare output */ if (im_cp_desc(out, in) == -1) return -1; out->Xsize = in->Xsize - in->Xsize % step; out->Ysize = in->Ysize - in->Ysize % step; if (im_setupout(out) == -1) return -1; /* Malloc buffer for one 'line' of input data */ os = in->Xsize * in->Bands; line = (unsigned char *) calloc((unsigned) os, sizeof(char)); /* Malloc space for values */ values = (unsigned char *) calloc((unsigned) out->Bands, sizeof(char)); if (line == NULL || values == NULL) { im_error("im_spatres", "%s", _("calloc failed")); return -1; } step2 = step * step; rounding = step2 / 2; input = (unsigned char *) in->data; for (y = 0; y < out->Ysize; y += step) { cpinput = input; input += os * step; /* do the x loop out->Xsize / step times */ cpline = line; for (x = 0; x < out->Xsize; x += step) { cp2input = cpinput; cpinput += step * out->Bands; /* ??? */ for (z = 0; z < out->Bands; z++) { pnt = cp2input + z; sum = 0; for (j = 0; j < step; j++) { cpnt = pnt; pnt += os; for (i = 0; i < step; i++) { sum += (int) *cpnt; cpnt += out->Bands; } } *(values + z) = (PEL) ((sum + rounding) / step2); } /* for this x, write step*bands data */ for (j = 0; j < step; j++) for (z = 0; z < out->Bands; z++) *cpline++ = *(values + z); } /* line is now ready. Write now step lines */ for (j = 0; j < step; j++) if (im_writeline(y + j, out, (PEL *) line) == -1) { free((char *) line); free((char *) values); return -1; } } /* end of the for (..y..) loop */ free((char *) line); free((char *) values); return 0; } libvips-8.18.2/libvips/deprecated/im_stretch3.c000066400000000000000000000161231516303661500214330ustar00rootroot00000000000000/* Function to stretch an image by 3%, and displace in x and y. Cubic * interpolation with a seperable mask. Displacements are: * * 0 <= xdisp < 1.0. * 0 <= ydisp < 1.0. * * Each horizontal block of 33 pixels is stretched to 34. * * Written by Ahmed Abbood * August-1994 * * Any unsigned short image. Output image is 3 pixels smaller because of * convolution, but x is larger by 3%: * * out->Xsize = 34*(in->Xsize / 33) + in->Xsize%33 - 3; * out->Ysize = in->Ysize - 3; * * 20/10/95 JC * - was not freeing regions correctly * - tidied up * 29/3/96 JC * - completely rewritten ... now produces correct result, and is 2x * faster * 18/9/97 JC * - added to VIPS library as im_stretch3 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* Data for the cubic interpolation function. */ typedef struct { IMAGE *in; double dx, dy; int xoff, yoff; /* Mask we start with for this disp. */ int mask[34][4]; /* Fixed-point masks for each output pixel */ } StretchInfo; /* Per-thread info. */ typedef struct seq_info { StretchInfo *sin; REGION *ir; unsigned short *buf; int lsk; } SeqInfo; static int stretch_stop(void *vseq, void *a, void *b) { SeqInfo *seq = (SeqInfo *) vseq; IM_FREEF(im_region_free, seq->ir); return 0; } static void * stretch_start(IMAGE *out, void *a, void *b) { IMAGE *in = (IMAGE *) a; StretchInfo *sin = (StretchInfo *) b; SeqInfo *seq; if (!(seq = IM_NEW(out, SeqInfo))) return NULL; seq->sin = sin; seq->ir = im_region_create(in); seq->lsk = IM_IMAGE_N_ELEMENTS(out); seq->buf = IM_ARRAY(out, 4 * seq->lsk, unsigned short); if (!seq->buf || !seq->ir) { stretch_stop(seq, NULL, NULL); return NULL; } return (void *) seq; } /* Stretch a line of pels into a line in the buffer. */ static void make_xline(StretchInfo *sin, unsigned short *p, unsigned short *q, int w, int m) { int bands = sin->in->Bands; int tot; int x, b; /* Offsets for subsequent pixels. */ int o1 = 1 * bands; int o2 = 2 * bands; int o3 = 3 * bands; for (x = 0; x < w; x++) { int *mask = &sin->mask[m][0]; unsigned short *p1 = p; /* Loop for this pel. */ for (b = 0; b < bands; b++) { tot = p1[0] * mask[0] + p1[o1] * mask[1] + p1[o2] * mask[2] + p1[o3] * mask[3]; tot = IM_MAX(0, tot); p1++; *q++ = (tot + 16384) >> 15; } /* Move to next mask. */ m++; if (m == 34) /* Back to mask 0, reuse this input pel. */ m = 0; else /* Move to next input pel. */ p += bands; } } /* As above, but do the vertical resample. lsk is how much we add to move down * a line in p, boff is [0,1,2,3] for which buffer line is mask[3]. */ static void make_yline(StretchInfo *sin, int lsk, int boff, unsigned short *p, unsigned short *q, int w, int m) { int bands = sin->in->Bands; int we = w * bands; int *mask = &sin->mask[m][0]; int tot; int x; /* Offsets for subsequent pixels. Down a line each time. */ int o0 = lsk * boff; int o1 = lsk * ((boff + 1) % 4); int o2 = lsk * ((boff + 2) % 4); int o3 = lsk * ((boff + 3) % 4); for (x = 0; x < we; x++) { tot = p[o0] * mask[0] + p[o1] * mask[1] + p[o2] * mask[2] + p[o3] * mask[3]; tot = IM_MAX(0, tot); p++; *q++ = (tot + 16384) >> 15; } } static int stretch_gen(REGION *out_region, void *vseq, void *a, void *b) { SeqInfo *seq = (SeqInfo *) vseq; StretchInfo *sin = (StretchInfo *) b; REGION *ir = seq->ir; Rect *r = &out_region->valid; Rect r1; int x, y; /* What mask do we start with? */ int xstart = (r->left + sin->xoff) % 34; /* What part of input do we need for this output? */ r1.left = r->left - (r->left + sin->xoff) / 34; r1.top = r->top; x = IM_RECT_RIGHT(r); x = x - (x + sin->xoff) / 34 + 3; r1.width = x - r1.left; r1.height = r->height + 3; if (im_prepare(ir, &r1)) return -1; /* Fill the first three lines of the buffer. */ for (y = 0; y < 3; y++) { unsigned short *p = (unsigned short *) IM_REGION_ADDR(ir, r1.left, y + r1.top); unsigned short *q = seq->buf + seq->lsk * y; make_xline(sin, p, q, r->width, xstart); } /* Loop for subsequent lines: stretch a new line of x pels, and * interpolate a line of output from the 3 previous xes plus this new * one. */ for (y = 0; y < r->height; y++) { /* Next line of fresh input pels. */ unsigned short *p = (unsigned short *) IM_REGION_ADDR(ir, r1.left, y + r1.top + 3); /* Next line we fill in the buffer. */ int boff = (y + 3) % 4; unsigned short *q = seq->buf + boff * seq->lsk; /* Line we write in output. */ unsigned short *q1 = (unsigned short *) IM_REGION_ADDR(out_region, r->left, y + r->top); /* Process this new xline. */ make_xline(sin, p, q, r->width, xstart); /* Generate new output line. */ make_yline(sin, seq->lsk, boff, seq->buf, q1, r->width, sin->yoff); } return 0; } int im_stretch3(IMAGE *in, IMAGE *out, double dx, double dy) { StretchInfo *sin; int i; /* Check our args. */ if (in->Coding != IM_CODING_NONE || in->BandFmt != IM_BANDFMT_USHORT) { im_error("im_stretch3", "%s", _("not uncoded unsigned short")); return -1; } if (dx < 0 || dx >= 1.0 || dy < 0 || dy >= 1.0) { im_error("im_stretch3", "%s", _("displacements out of range [0,1)")); return -1; } if (im_piocheck(in, out)) return -1; /* Prepare the output image. */ if (im_cp_desc(out, in)) return -1; out->Xsize = 34 * (in->Xsize / 33) + in->Xsize % 33 - 3; out->Ysize = in->Ysize - 3; if (im_demand_hint(out, IM_FATSTRIP, in, NULL)) return -1; if (!(sin = IM_NEW(out, StretchInfo))) return -1; /* Save parameters. */ sin->in = in; sin->dx = dx; sin->dy = dy; /* Generate masks. */ for (i = 0; i < 34; i++) { double d = (34.0 - i) / 34.0; double y0 = 2.0 * d * d - d - d * d * d; double y1 = 1.0 - 2.0 * d * d + d * d * d; double y2 = d + d * d - d * d * d; double y3 = -d * d + d * d * d; sin->mask[i][0] = IM_RINT(y0 * 32768); sin->mask[i][1] = IM_RINT(y1 * 32768); sin->mask[i][2] = IM_RINT(y2 * 32768); sin->mask[i][3] = IM_RINT(y3 * 32768); } /* Which mask do we start with to apply these offsets? */ sin->xoff = (dx * 33.0) + 0.5; sin->yoff = (dy * 33.0) + 0.5; if (im_generate(out, stretch_start, stretch_gen, stretch_stop, in, sin)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/im_thresh.c000066400000000000000000000063621516303661500211750ustar00rootroot00000000000000/* @(#) Thresholds an image. Works for any non-complex type. * @(#) Output is a binary image with 0 and 255 only * @(#) Input is either memory mapped or in a buffer. * @(#) * @(#) int im_thresh(imin, imout, threshold) * @(#) IMAGE *imin, *imout; * @(#) double threshold; * @(#) * @(#) Returns 0 on success and -1 on error * * Copyright: 1991, N. Dessipris, J Cupitt * * Author: N. Dessipris, J. Cupitt * Written on: 15/03/1991 * Modified on : */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* Useful: Call a macro with the name, type pairs for all VIPS functions. */ #define BRIGHT 255 #define DARK 0 #define im_for_all_types(A) \ case IM_BANDFMT_UCHAR: \ A(unsigned char); \ break; \ case IM_BANDFMT_CHAR: \ A(signed char); \ break; \ case IM_BANDFMT_USHORT: \ A(unsigned short); \ break; \ case IM_BANDFMT_SHORT: \ A(signed short); \ break; \ case IM_BANDFMT_UINT: \ A(unsigned int); \ break; \ case IM_BANDFMT_INT: \ A(signed int); \ break; \ case IM_BANDFMT_FLOAT: \ A(float); \ break; \ case IM_BANDFMT_DOUBLE: \ A(double); \ break; /* Replacement for im_thresh */ int im_thresh(IMAGE *in, IMAGE *out, double threshold) { int x, y; PEL *bu; /* Buffer we write to */ int s, epl; /* Size and els per line */ /* Check our args. */ if (im_iocheck(in, out)) return -1; if (in->Coding != IM_CODING_NONE) { im_error("im_thresh", "%s", _("input should be uncoded")); return -1; } /* Set up the output header. */ if (im_cp_desc(out, in)) return -1; out->BandFmt = IM_BANDFMT_UCHAR; if (im_setupout(out)) return -1; /* Make buffer for building o/p in. */ epl = in->Xsize * in->Bands; s = epl * sizeof(PEL); if ((bu = (PEL *) im_malloc(out, (unsigned) s)) == NULL) return -1; /* Define what we do for each band element type. */ #define im_thresh_loop(TYPE) \ { \ TYPE *a = (TYPE *) in->data; \ \ for (y = 0; y < in->Ysize; y++) { \ PEL *b = bu; \ \ for (x = 0; x < epl; x++) { \ double f = (double) *a++; \ if (f >= threshold) \ *b++ = (PEL) BRIGHT; \ else \ *b++ = (PEL) DARK; \ } \ \ if (im_writeline(y, out, bu)) \ return -1; \ } \ } /* Do the above for all image types. */ switch (in->BandFmt) { im_for_all_types(im_thresh_loop); default: im_error("im_thresh", "%s", _("Unknown input format")); return -1; } return 0; } libvips-8.18.2/libvips/deprecated/im_tiff2vips.c000066400000000000000000000115311516303661500216060ustar00rootroot00000000000000/* vips7 compat stub for tiff loading ... see foreign/tiff2vips for the * replacement * * 6/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "../foreign/pforeign.h" #ifdef HAVE_TIFF static gboolean im_istifftiled(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips__istiff_source(source); VIPS_UNREF(source); return result; } static int im_tiff_read_header(const char *filename, VipsImage *out, int page, int n, gboolean autorotate) { VipsSource *source; if (!(source = vips_source_new_from_file(filename))) return -1; if (vips__tiff_read_header_source(source, out, page, n, autorotate, -1, VIPS_FAIL_ON_ERROR, TRUE)) { VIPS_UNREF(source); return -1; } VIPS_UNREF(source); return 0; } static int im_tiff_read(const char *filename, VipsImage *out, int page, int n, gboolean autorotate) { VipsSource *source; if (!(source = vips_source_new_from_file(filename))) return -1; if (vips__tiff_read_source(source, out, page, n, autorotate, -1, VIPS_FAIL_ON_ERROR, TRUE)) { VIPS_UNREF(source); return -1; } VIPS_UNREF(source); return 0; } #endif /*HAVE_TIFF*/ static int tiff2vips(const char *name, IMAGE *out, gboolean header_only) { #ifdef HAVE_TIFF char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p, *q; int page; int seq; im_filename_split(name, filename, mode); page = 0; seq = 0; p = &mode[0]; if ((q = im_getnextoption(&p))) { page = atoi(q); } if ((q = im_getnextoption(&p))) { if (im_isprefix("seq", q)) seq = 1; } /* We need to be compatible with the pre-sequential mode * im_tiff2vips(). This returned a "t" if given a "p" image, since it * used writeline. * * If we're writing the image to a "p", switch it to a "t". And only * for non-tiled (strip) images which we write with writeline. * * Don't do this for header read, since we don't want to force a * malloc if all we are doing is looking at fields. */ if (!header_only && !seq && !im_istifftiled(filename) && out->dtype == VIPS_IMAGE_PARTIAL) { if (vips__image_wio_output(out)) return -1; } if (header_only) { if (im_tiff_read_header(filename, out, page, 1, FALSE)) return -1; } else { if (im_tiff_read(filename, out, page, 1, FALSE)) return -1; } #else vips_error("im_tiff2vips", "%s", _("no TIFF support in your libvips")); return -1; #endif /*HAVE_TIFF*/ return 0; } int im_tiff2vips(const char *name, IMAGE *out) { return tiff2vips(name, out, FALSE); } /* By having a separate header func, we get lazy.c to open via disc/mem. */ static int im_tiff2vips_header(const char *name, IMAGE *out) { return tiff2vips(name, out, TRUE); } static VipsFormatFlags tiff_flags(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return (VipsFormatFlags) vips_foreign_flags("tiffload", filename); } static int istiff(const char *name) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); return vips_foreign_is_a("tiffload", filename); } static const char *tiff_suffs[] = { ".tif", ".tiff", NULL }; typedef VipsFormat VipsFormatTiff; typedef VipsFormatClass VipsFormatTiffClass; static void vips_format_tiff_class_init(VipsFormatTiffClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "tiff"; object_class->description = _("TIFF"); format_class->is_a = istiff; format_class->header = im_tiff2vips_header; format_class->load = im_tiff2vips; format_class->save = im_vips2tiff; format_class->get_flags = tiff_flags; format_class->suffs = tiff_suffs; } static void vips_format_tiff_init(VipsFormatTiff *object) { } G_DEFINE_TYPE(VipsFormatTiff, vips_format_tiff, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/im_video_test.c000066400000000000000000000027001516303661500220350ustar00rootroot00000000000000/* test video grabber ... just generates noise and optional errors */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include /** * im_video_test: * @im: write image here * @brightness: brightness setting * @error: set this to make the function return an error * * Make a test video image. Set @error to trigger an error. * * Returns: 0 on success, -1 on error */ int im_video_test(IMAGE *im, int brightness, int error) { if (error) { im_error("im_video_test", "%s", _("error requested")); return -1; } else return im_gaussnoise(im, 720, 576, brightness, 20); } libvips-8.18.2/libvips/deprecated/im_vips2csv.c000066400000000000000000000026411516303661500214530ustar00rootroot00000000000000/* Write a csv file. * * 16/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include int im_vips2csv(IMAGE *in, const char *filename) { char *separator = "\t"; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p, *q, *r; /* Parse mode string. */ im_filename_split(filename, name, mode); p = &mode[0]; while ((q = im_getnextoption(&p))) { if (im_isprefix("sep", q) && (r = im_getsuboption(q))) separator = r; } if (vips_csvsave(in, name, "separator", separator, NULL)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/im_vips2dz.c000066400000000000000000000055051516303661500212770ustar00rootroot00000000000000/* vips7 compat stub for vips_dzsave() * * 11/6/13 * - from im_vips2tiff() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Turn on IM_REGION_ADDR() range checks, don't delete intermediates. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_vips2dz(IMAGE *in, const char *filename) { char *p, *q; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char buf[FILENAME_MAX]; int i; VipsForeignDzLayout layout = VIPS_FOREIGN_DZ_LAYOUT_DZ; char *suffix = ".jpeg"; int overlap = 0; int tile_size = 256; VipsForeignDzDepth depth = VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL; gboolean centre = FALSE; VipsAngle angle = VIPS_ANGLE_D0; /* We can't use im_filename_split() -- it assumes that we have a * filename with an extension before the ':', and filename here is * actually a dirname. * * Just split on the first ':'. */ im_strncpy(name, filename, FILENAME_MAX); if ((p = strchr(name, ':'))) { *p = '\0'; im_strncpy(mode, p + 1, FILENAME_MAX); } else strcpy(mode, ""); strcpy(buf, mode); p = &buf[0]; if ((q = im_getnextoption(&p))) { if ((i = vips_enum_from_nick("im_vips2dz", VIPS_TYPE_FOREIGN_DZ_LAYOUT, q)) < 0) return -1; layout = i; } if ((q = im_getnextoption(&p))) suffix = g_strdup(q); if ((q = im_getnextoption(&p))) overlap = atoi(q); if ((q = im_getnextoption(&p))) tile_size = atoi(q); if ((q = im_getnextoption(&p))) { if ((i = vips_enum_from_nick("im_vips2dz", VIPS_TYPE_FOREIGN_DZ_DEPTH, q)) < 0) return -1; depth = i; } if ((q = im_getnextoption(&p))) { if (im_isprefix("cen", q)) centre = TRUE; } if ((q = im_getnextoption(&p))) { if ((i = vips_enum_from_nick("im_vips2dz", VIPS_TYPE_ANGLE, q)) < 0) return -1; angle = i; } if (vips_dzsave(in, name, "layout", layout, "suffix", suffix, "overlap", overlap, "tile_size", tile_size, "depth", depth, "centre", centre, "angle", angle, NULL)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/im_vips2jpeg.c000066400000000000000000000045161516303661500216100ustar00rootroot00000000000000/* Convert 8-bit VIPS images to/from JPEG. * * 30/11/11 * - now just a stub calling the new system */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_vips2jpeg(IMAGE *in, const char *filename) { int qfac = 75; /* profile has to default to NULL, meaning "no param". If we default * to "none" we will not attach the profile from the metadata. */ char *profile = NULL; char *p, *q; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char buf[FILENAME_MAX]; /* Parse mode from filename. */ im_filename_split(filename, name, mode); strcpy(buf, mode); p = &buf[0]; if ((q = im_getnextoption(&p))) { if (strcmp(q, "") != 0) qfac = atoi(mode); } if ((q = im_getnextoption(&p))) { if (strcmp(q, "") != 0) profile = q; } if ((q = im_getnextoption(&p))) { im_error("im_vips2jpeg", _("unknown extra options \"%s\""), q); return -1; } return vips_jpegsave(in, name, "Q", qfac, "profile", profile, NULL); } int im_vips2bufjpeg(IMAGE *in, IMAGE *out, int qfac, char **obuf, int *olen) { size_t len; if (vips_jpegsave_buffer(in, (void **) obuf, &len, "Q", qfac, NULL)) return -1; if (out) im_add_callback(out, "close", (im_callback_fn) vips_free, obuf, NULL); if (olen) *olen = len; return 0; } int im_vips2mimejpeg(IMAGE *in, int qfac) { return vips_jpegsave_mime(in, "Q", qfac, NULL); } libvips-8.18.2/libvips/deprecated/im_vips2mask.c000066400000000000000000000127271516303661500216210ustar00rootroot00000000000000/* im_vips2mask * * Author: J.Cupitt * Written on: 6/6/94 * Modified on: * * 16/10/06 * - allow 1xn-band images too * 23/2/07 * - oop, broken for nx1 m-band images * - now casts to double for you * 1/2/10 * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /** * im_vips2mask: * @in: input image * @filename: name for output mask * * Make a mask from an image. All images are cast to %IM_BANDFMT_DOUBLE * before processing. There are two cases for handling bands: * * If the image has a single band, im_vips2mask() will write a mask the same * size as the image. * * If the image has more than one band, it must be one pixel high or wide. In * this case the output mask uses that axis to represent band values. * * See also: im_mask2vips(), im_measure_area(). * * Returns: a #DOUBLEMASK with @outname set as the name, or NULL on error */ DOUBLEMASK * im_vips2mask(IMAGE *in, const char *filename) { int width, height; DOUBLEMASK *out; /* double* only: cast if necessary. */ if (in->BandFmt != IM_BANDFMT_DOUBLE) { IMAGE *t; if (!(t = im_open("im_vips2mask", "p"))) return NULL; if (im_clip2fmt(in, t, IM_BANDFMT_DOUBLE) || !(out = im_vips2mask(t, filename))) { im_close(t); return NULL; } im_close(t); return out; } /* Check the image. */ if (im_incheck(in) || im_check_uncoded("im_vips2mask", in)) return NULL; if (in->Bands == 1) { width = in->Xsize; height = in->Ysize; } else if (in->Xsize == 1) { width = in->Bands; height = in->Ysize; } else if (in->Ysize == 1) { width = in->Xsize; height = in->Bands; } else { im_error("im_vips2mask", "%s", _("one band, nx1, or 1xn images only")); return NULL; } if (!(out = im_create_dmask(filename, width, height))) return NULL; if (in->Bands > 1 && in->Ysize == 1) { double *data = (double *) in->data; int x, y; /* Need to transpose: the image is RGBRGBRGB, we need RRRGGGBBB. */ for (y = 0; y < height; y++) for (x = 0; x < width; x++) out->coeff[x + y * width] = data[x * height + y]; } else memcpy(out->coeff, in->data, width * height * sizeof(double)); out->scale = vips_image_get_scale(in); out->offset = vips_image_get_offset(in); return out; } INTMASK * im_vips2imask(IMAGE *in, const char *filename) { int width, height; INTMASK *out; double *data; int x, y; double double_result; int int_result; /* double* only: cast if necessary. */ if (in->BandFmt != IM_BANDFMT_DOUBLE) { IMAGE *t; if (!(t = im_open("im_vips2imask", "p"))) return NULL; if (im_clip2fmt(in, t, IM_BANDFMT_DOUBLE) || !(out = im_vips2imask(t, filename))) { im_close(t); return NULL; } im_close(t); return out; } /* Check the image. */ if (im_incheck(in) || im_check_uncoded("im_vips2imask", in)) return NULL; if (in->Bands == 1) { width = in->Xsize; height = in->Ysize; } else if (in->Xsize == 1) { width = in->Bands; height = in->Ysize; } else if (in->Ysize == 1) { width = in->Xsize; height = in->Bands; } else { im_error("im_vips2imask", "%s", _("one band, nx1, or 1xn images only")); return NULL; } data = (double *) in->data; if (!(out = im_create_imask(filename, width, height))) return NULL; /* We want to make an intmask which has the same input to output ratio * as the double image. * * Imagine convolving with the double image, what's the ratio of * brightness between input and output? We want the same ratio for the * int version, if we can. * * Imagine an input image where every pixel is 1, what will the output * be? */ double_result = 0; for (y = 0; y < height; y++) for (x = 0; x < width; x++) double_result += data[x + width * y]; double_result /= vips_image_get_scale(in); for (y = 0; y < height; y++) for (x = 0; x < width; x++) if (in->Bands > 1 && in->Ysize == 1) /* Need to transpose: the image is RGBRGBRGB, * we need RRRGGGBBB. */ out->coeff[x + y * width] = rint(data[x * height + y]); else out->coeff[x + y * width] = rint(data[x + y * width]); out->scale = rint(vips_image_get_scale(in)); if (out->scale == 0) out->scale = 1; out->offset = rint(vips_image_get_offset(in)); /* Now convolve a 1 everywhere image with the int version we've made, * what do we get? */ int_result = 0; for (y = 0; y < height; y++) for (x = 0; x < width; x++) int_result += out->coeff[x + width * y]; int_result /= out->scale; /* And adjust the scale to get as close to a match as we can. */ out->scale = rint(out->scale + (int_result - double_result)); if (out->scale == 0) out->scale = 1; return out; } libvips-8.18.2/libvips/deprecated/im_vips2png.c000066400000000000000000000040271516303661500214440ustar00rootroot00000000000000/* Convert 1 to 4-band 8 or 16-bit VIPS images to/from PNG. * * 19/12/11 * - just a stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include int im_vips2png(IMAGE *in, const char *filename) { int compression; int interlace; char *p, *q; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char buf[FILENAME_MAX]; /* Extract write mode from filename and parse. */ im_filename_split(filename, name, mode); strcpy(buf, mode); p = &buf[0]; compression = 6; interlace = 0; if ((q = im_getnextoption(&p))) compression = atoi(q); if ((q = im_getnextoption(&p))) interlace = atoi(q); return vips_pngsave(in, name, "compression", compression, "interlace", interlace, NULL); } int im_vips2bufpng(IMAGE *in, IMAGE *out, int compression, int interlace, char **obuf, size_t *olen) { if (vips_pngsave_buffer(in, (void **) obuf, olen, "compression", compression, "interlace", interlace, NULL)) return -1; if (out) im_add_callback(out, "close", (im_callback_fn) vips_free, obuf, NULL); return 0; } libvips-8.18.2/libvips/deprecated/im_vips2ppm.c000066400000000000000000000031261516303661500214530ustar00rootroot00000000000000/* Write a ppm file. * * 20/12/11 * - just a compat stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include int im_vips2ppm(IMAGE *in, const char *filename) { int ascii; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; /* Default to binary output ... much smaller. */ ascii = 0; /* Extract write mode from filename. */ im_filename_split(filename, name, mode); if (strcmp(mode, "") != 0) { if (im_isprefix("binary", mode)) ascii = 0; else if (im_isprefix("ascii", mode)) ascii = 1; else { im_error("im_vips2ppm", "%s", _("bad mode string, " "should be \"binary\" or \"ascii\"")); return -1; } } return vips_ppmsave(in, name, "ascii", ascii, NULL); } libvips-8.18.2/libvips/deprecated/im_vips2tiff.c000066400000000000000000000135451516303661500216150ustar00rootroot00000000000000/* vips7 compat stub for im_vips2tiff.c * * 4/12/11 * - just a stub calling vips_tiffsave() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Turn on IM_REGION_ADDR() range checks, don't delete intermediates. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include int im_vips2tiff(IMAGE *in, const char *filename) { char *p, *q, *r; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char buf[FILENAME_MAX]; VipsForeignTiffCompression compression = VIPS_FOREIGN_TIFF_COMPRESSION_NONE; int Q = 75; VipsForeignTiffPredictor predictor = VIPS_FOREIGN_TIFF_PREDICTOR_NONE; char *profile = NULL; gboolean tile = FALSE; int tile_width = 128; int tile_height = 128; gboolean pyramid = FALSE; gboolean squash = FALSE; VipsForeignTiffResunit resunit = VIPS_FOREIGN_TIFF_RESUNIT_CM; double xres = in->Xres * 10.0; double yres = in->Yres * 10.0; gboolean bigtiff = FALSE; im_filename_split(filename, name, mode); strcpy(buf, mode); p = &buf[0]; if ((q = im_getnextoption(&p))) { if (im_isprefix("none", q)) compression = VIPS_FOREIGN_TIFF_COMPRESSION_NONE; else if (im_isprefix("packbits", q)) compression = VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS; else if (im_isprefix("ccittfax4", q)) compression = VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4; else if (im_isprefix("lzw", q)) { compression = VIPS_FOREIGN_TIFF_COMPRESSION_LZW; if ((r = im_getsuboption(q))) { int i; if (sscanf(r, "%d", &i) != 1) { im_error("im_vips2tiff", "%s", _("bad predictor " "parameter")); return -1; } predictor = i; } } else if (im_isprefix("deflate", q)) { compression = VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE; if ((r = im_getsuboption(q))) { int i; if (sscanf(r, "%d", &i) != 1) { im_error("im_vips2tiff", "%s", _("bad predictor " "parameter")); return -1; } predictor = i; } } else if (im_isprefix("jpeg", q)) { compression = VIPS_FOREIGN_TIFF_COMPRESSION_JPEG; if ((r = im_getsuboption(q))) if (sscanf(r, "%d", &Q) != 1) { im_error("im_vips2tiff", "%s", _("bad JPEG quality " "parameter")); return -1; } } else { im_error("im_vips2tiff", _("unknown compression mode " "\"%s\"\nshould be one of \"none\", " "\"packbits\", \"ccittfax4\", \"lzw\", " "\"deflate\" or \"jpeg\""), q); return -1; } } if ((q = im_getnextoption(&p))) { if (im_isprefix("tile", q)) { tile = TRUE; if ((r = im_getsuboption(q))) { if (sscanf(r, "%dx%d", &tile_width, &tile_height) != 2) { im_error("im_vips2tiff", "%s", _("bad tile sizes")); return -1; } } } else if (im_isprefix("strip", q)) tile = FALSE; else { im_error("im_vips2tiff", _("unknown layout mode " "\"%s\"\nshould be one of \"tile\" or " "\"strip\""), q); return -1; } } if ((q = im_getnextoption(&p))) { if (im_isprefix("pyramid", q)) pyramid = TRUE; else if (im_isprefix("flat", q)) pyramid = FALSE; else { im_error("im_vips2tiff", _("unknown multi-res mode " "\"%s\"\nshould be one of \"flat\" or " "\"pyramid\""), q); return -1; } } if ((q = im_getnextoption(&p))) { if (im_isprefix("onebit", q)) squash = TRUE; else if (im_isprefix("manybit", q)) squash = FALSE; else { im_error("im_vips2tiff", _("unknown format " "\"%s\"\nshould be one of \"onebit\" or " "\"manybit\""), q); return -1; } } if ((q = im_getnextoption(&p))) { if (im_isprefix("res_cm", q)) resunit = VIPS_FOREIGN_TIFF_RESUNIT_CM; else if (im_isprefix("res_inch", q)) resunit = VIPS_FOREIGN_TIFF_RESUNIT_INCH; else { im_error("im_vips2tiff", _("unknown resolution unit " "\"%s\"\nshould be one of \"res_cm\" or " "\"res_inch\""), q); return -1; } if ((r = im_getsuboption(q))) { if (sscanf(r, "%lfx%lf", &xres, &yres) != 2) { if (sscanf(r, "%lf", &xres) != 1) { im_error("im_vips2tiff", "%s", _("bad resolution values")); return -1; } yres = xres; } /* vips resolutions are always in pixels/mm. If the * user specifies ",res_inch:72x72" then they are * using pixels/inch instead and we must convert. */ if (resunit == VIPS_FOREIGN_TIFF_RESUNIT_INCH) { xres /= 2.54; yres /= 2.54; } } } if ((q = im_getnextoption(&p)) && strcmp(q, "") != 0) profile = im_strdup(NULL, q); if ((q = im_getnextoption(&p)) && strcmp(q, "8") == 0) bigtiff = TRUE; if ((q = im_getnextoption(&p))) { im_error("im_vips2tiff", _("unknown extra options \"%s\""), q); return -1; } if (vips_tiffsave(in, name, "compression", compression, "Q", Q, "predictor", predictor, "profile", profile, "tile", tile, "tile_width", tile_width, "tile_height", tile_height, "pyramid", pyramid, "squash", squash, "resunit", resunit, "xres", xres, "yres", yres, "bigtiff", bigtiff, NULL)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/im_vips2webp.c000066400000000000000000000030411516303661500216100ustar00rootroot00000000000000/* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include int im_vips2webp(IMAGE *in, const char *filename) { int compression; int lossless; char *p, *q; char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char buf[FILENAME_MAX]; im_filename_split(filename, name, mode); strcpy(buf, mode); p = &buf[0]; compression = 6; lossless = 0; if ((q = im_getnextoption(&p))) compression = atoi(q); if ((q = im_getnextoption(&p))) lossless = atoi(q); return vips_webpsave(in, name, "Q", compression, "lossless", lossless, NULL); } libvips-8.18.2/libvips/deprecated/im_webp2vips.c000066400000000000000000000055171516303661500216220ustar00rootroot00000000000000/* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "../foreign/pforeign.h" static int webp2vips(const char *name, IMAGE *out, gboolean header_only) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(name, filename, mode); #ifdef HAVE_LIBWEBP { VipsSource *source; int result; if (!(source = vips_source_new_from_file(filename))) return -1; if (header_only) result = vips__webp_read_header_source(source, out, 0, 1, 1); else result = vips__webp_read_source(source, out, 0, 1, 1); VIPS_UNREF(source); if (result) return result; } #else vips_error("im_webp2vips", "%s", _("no webp support in your libvips")); return -1; #endif /*HAVE_LIBWEBP*/ return 0; } int im_webp2vips(const char *name, IMAGE *out) { return webp2vips(name, out, FALSE); } #ifdef HAVE_LIBWEBP static gboolean vips__iswebp(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips__iswebp_source(source); VIPS_UNREF(source); return result; } static int im_webp2vips_header(const char *name, IMAGE *out) { return webp2vips(name, out, TRUE); } static const char *webp_suffs[] = { ".webp", NULL }; typedef VipsFormat VipsFormatWebp; typedef VipsFormatClass VipsFormatWebpClass; static void vips_format_webp_class_init(VipsFormatWebpClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "webp"; object_class->description = _("webp"); format_class->is_a = vips__iswebp; format_class->header = im_webp2vips_header; format_class->load = im_webp2vips; format_class->save = im_vips2webp; format_class->suffs = webp_suffs; } static void vips_format_webp_init(VipsFormatWebp *object) { } G_DEFINE_TYPE(VipsFormatWebp, vips_format_webp, VIPS_TYPE_FORMAT); #endif /*HAVE_LIBWEBP*/ libvips-8.18.2/libvips/deprecated/im_zerox.c000066400000000000000000000103121516303661500210350ustar00rootroot00000000000000/* detect zero-crossings * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 12/02/1990 * Modified on : * 1/2/95 JC * - rewritten for PIO * - some bugs removed * 11/5/06 * - small clean ups * 11/11/10 * - small cleanups * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #define LOOP(TYPE) \ { \ for (i = 0; i < ne; i++) { \ TYPE p1 = ((TYPE *) p)[i]; \ TYPE p2 = ((TYPE *) p)[i + ba]; \ \ if (flag == 1 && p1 > 0 && p2 <= 0) \ q[i] = 255; \ else if (flag == -1 && p1 < 0 && p2 >= 0) \ q[i] = 255; \ else \ q[i] = 0; \ } \ } /* Zerox generate function. */ static int zerox_gen(REGION *out_region, void *seq, void *a, void *b) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; int flag = GPOINTER_TO_INT(b); Rect irect; Rect *r = &out_region->valid; /* Range of pixels we loop over. */ int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); int ba = in->Bands; int ne = ba * r->width; int i, y; /* We need to be able to see one pixel to the right. */ irect.top = r->top; irect.left = r->left; irect.width = r->width + 1; irect.height = r->height; if (im_prepare(ir, &irect)) return -1; for (y = to; y < bo; y++) { VipsPel *p = IM_REGION_ADDR(ir, le, y); VipsPel *q = IM_REGION_ADDR(out_region, le, y); switch (in->BandFmt) { case IM_BANDFMT_CHAR: LOOP(signed char); break; case IM_BANDFMT_SHORT: LOOP(signed short); break; case IM_BANDFMT_INT: LOOP(signed int); break; case IM_BANDFMT_FLOAT: LOOP(float); break; case IM_BANDFMT_DOUBLE: LOOP(double); break; default: g_assert(0); } } return 0; } /** * im_zerox: * @in: input image * @out: output image * @sign: detect positive or negative zero crossings * * im_zerox() detects the positive or negative zero crossings @in, * depending on @sign. If @sign is -1, negative zero crossings are returned, * if @sign is 1, positive zero crossings are returned. * * The output image is byte with zero crossing set to 255 and all other values * set to zero. Input can have any number of channels, and be any non-complex * type. * * See also: im_conv(), im_rot90. * * Returns: 0 on success, -1 on error */ int im_zerox(IMAGE *in, IMAGE *out, int sign) { IMAGE *t1; if (sign != -1 && sign != 1) { im_error("im_zerox", "%s", _("flag not -1 or 1")); return -1; } if (in->Xsize < 2) { im_error("im_zerox", "%s", _("image too narrow")); return -1; } if (!(t1 = im_open_local(out, "im_zerox", "p")) || im_piocheck(in, t1) || im_check_uncoded("im_zerox", in) || im_check_noncomplex("im_zerox", in)) return -1; if (vips_bandfmt_isuint(in->BandFmt)) /* Unsigned type, therefore there will be no zero-crossings. */ return im_black(out, in->Xsize, in->Ysize, in->Bands); /* Force output to be BYTE. Output is narrower than input by 1 pixel. */ if (im_cp_desc(t1, in)) return -1; t1->BandFmt = IM_BANDFMT_UCHAR; t1->Xsize -= 1; /* Set hints - THINSTRIP is ok with us. */ if (im_demand_hint(t1, IM_THINSTRIP, NULL)) return -1; /* Generate image. */ if (im_generate(t1, im_start_one, zerox_gen, im_stop_one, in, GINT_TO_POINTER(sign))) return -1; /* Now embed it in a larger image. */ if (im_embed(t1, out, 0, 0, 0, in->Xsize, in->Ysize)) return -1; return 0; } libvips-8.18.2/libvips/deprecated/inplace_dispatch.c000066400000000000000000000327701516303661500225070ustar00rootroot00000000000000/* Function dispatch tables for inplace. * * J. Cupitt, 8/2/95 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* Calculate a pixel for an image from a vec of double. Valid while im is * valid. */ VipsPel * im__vector_to_ink(const char *domain, IMAGE *im, int n, double *vec) { IMAGE *t[3]; double *zeros; int i; if (im_check_vector(domain, n, im)) return NULL; if (im_open_local_array(im, t, 3, domain, "t") || !(zeros = IM_ARRAY(im, n, double))) return NULL; for (i = 0; i < n; i++) zeros[i] = 0.0; if (im_black(t[0], 1, 1, im->Bands) || im_lintra_vec(n, zeros, t[0], vec, t[1]) || im_clip2fmt(t[1], t[2], im->BandFmt)) return NULL; return t[2]->data; } double * im__ink_to_vector(const char *domain, IMAGE *im, VipsPel *ink) { double *vec; int i; if (im_check_uncoded("im__ink_to_vector", im) || im_check_noncomplex("im__ink_to_vector", im)) return NULL; if (!(vec = IM_ARRAY(NULL, im->Bands, double))) return NULL; #define READ(TYPE) \ vec[i] = ((TYPE *) ink)[i]; for (i = 0; i < im->Bands; i++) switch (im->BandFmt) { case IM_BANDFMT_UCHAR: READ(unsigned char); break; case IM_BANDFMT_CHAR: READ(signed char); break; case IM_BANDFMT_USHORT: READ(unsigned short); break; case IM_BANDFMT_SHORT: READ(signed short); break; case IM_BANDFMT_UINT: READ(unsigned int); break; case IM_BANDFMT_INT: READ(signed int); break; case IM_BANDFMT_FLOAT: READ(float); break; case IM_BANDFMT_DOUBLE: READ(double); break; default: g_assert(0); } return vec; } /* Args for im_draw_image. */ static im_arg_desc draw_image_args[] = { IM_RW_IMAGE("image"), IM_INPUT_IMAGE("sub"), IM_INPUT_INT("x"), IM_INPUT_INT("y") }; /* Call im_draw_image via arg vector. */ static int draw_image_vec(im_object *argv) { int x = *((int *) argv[2]); int y = *((int *) argv[3]); return im_draw_image(argv[0], argv[1], x, y); } /* Description of im_draw_image. */ static im_function draw_image_desc = { "im_draw_image", /* Name */ "draw image sub inside image main at position (x,y)", 0, /* Flags */ draw_image_vec, /* Dispatch function */ IM_NUMBER(draw_image_args), /* Size of arg list */ draw_image_args /* Arg list */ }; /* Args for im_lineset. */ static im_arg_desc lineset_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMAGE("mask"), IM_INPUT_IMAGE("ink"), IM_INPUT_INTVEC("x1"), IM_INPUT_INTVEC("y1"), IM_INPUT_INTVEC("x2"), IM_INPUT_INTVEC("y2") }; /* Call im_lineset via arg vector. */ static int lineset_vec(im_object *argv) { im_intvec_object *x1v = (im_intvec_object *) argv[4]; im_intvec_object *y1v = (im_intvec_object *) argv[5]; im_intvec_object *x2v = (im_intvec_object *) argv[6]; im_intvec_object *y2v = (im_intvec_object *) argv[7]; if (x1v->n != y1v->n || x1v->n != x2v->n || x1v->n != y2v->n) { im_error("im_lineset", "%s", _("vectors not same length")); return -1; } return im_lineset(argv[0], argv[1], argv[2], argv[3], x1v->n, x1v->vec, y1v->vec, x2v->vec, y2v->vec); } /* Description of im_lineset. */ static im_function lineset_desc = { "im_lineset", /* Name */ "draw line between points (x1,y1) and (x2,y2)", 0, /* Flags */ lineset_vec, /* Dispatch function */ IM_NUMBER(lineset_args), /* Size of arg list */ lineset_args /* Arg list */ }; /* Args for im_draw_mask. */ static im_arg_desc draw_mask_args[] = { IM_RW_IMAGE("image"), IM_INPUT_IMAGE("mask"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_mask via arg vector. */ static int draw_mask_vec(im_object *argv) { IMAGE *image = argv[0]; IMAGE *mask = argv[1]; int x = *((int *) argv[2]); int y = *((int *) argv[3]); im_doublevec_object *dv = (im_doublevec_object *) argv[4]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_mask", image, dv->n, dv->vec))) return -1; return im_draw_mask(image, mask, x, y, ink); } /* Description of im_draw_mask. */ static im_function draw_mask_desc = { "im_draw_mask", /* Name */ "draw mask sub inside image main at position (x,y)", 0, /* Flags */ draw_mask_vec, /* Dispatch function */ IM_NUMBER(draw_mask_args), /* Size of arg list */ draw_mask_args /* Arg list */ }; /* Args for im_draw_flood_blob(). */ static im_arg_desc draw_flood_blob_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_flood_blob() via arg vector. */ static int draw_flood_blob_vec(im_object *argv) { IMAGE *image = argv[0]; int x = *((int *) argv[1]); int y = *((int *) argv[2]); im_doublevec_object *dv = (im_doublevec_object *) argv[3]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_flood_blob", image, dv->n, dv->vec))) return -1; return im_draw_flood_blob(image, x, y, ink, NULL); } /* Description of im_draw_flood_blob(). */ static im_function draw_flood_blob_desc = { "im_draw_flood_blob", /* Name */ "flood with ink from x, y while pixel == start", 0, /* Flags */ draw_flood_blob_vec, /* Dispatch function */ IM_NUMBER(draw_flood_blob_args), /* Size of arg list */ draw_flood_blob_args /* Arg list */ }; /* Args for im_draw_flood(). */ static im_arg_desc draw_flood_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_flood() via arg vector. */ static int draw_flood_vec(im_object *argv) { IMAGE *image = argv[0]; int x = *((int *) argv[1]); int y = *((int *) argv[2]); im_doublevec_object *dv = (im_doublevec_object *) argv[3]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_flood", image, dv->n, dv->vec))) return -1; return im_draw_flood(image, x, y, ink, NULL); } /* Description of im_draw_flood(). */ static im_function draw_flood_desc = { "im_draw_flood", /* Name */ "flood with ink from x, y while pixel != ink", 0, /* Flags */ draw_flood_vec, /* Dispatch function */ IM_NUMBER(draw_flood_args), /* Size of arg list */ draw_flood_args /* Arg list */ }; /* Args for im_draw_flood_other(). */ static im_arg_desc draw_flood_other_args[] = { IM_RW_IMAGE("image"), IM_INPUT_IMAGE("test"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_INT("serial") }; /* Call im_draw_flood_other() via arg vector. */ static int draw_flood_other_vec(im_object *argv) { IMAGE *image = argv[0]; IMAGE *test = argv[1]; int x = *((int *) argv[2]); int y = *((int *) argv[3]); int serial = *((int *) argv[4]); return im_draw_flood_other(image, test, x, y, serial, NULL); } /* Description of im_draw_flood_other(). */ static im_function draw_flood_other_desc = { "im_draw_flood_other", /* Name */ "flood image with serial from x, y while pixel == start", 0, /* Flags */ draw_flood_other_vec, /* Dispatch function */ IM_NUMBER(draw_flood_other_args), /* Size of arg list */ draw_flood_other_args /* Arg list */ }; /* Args for im_draw_point. */ static im_arg_desc draw_point_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_point via arg vector. */ static int draw_point_vec(im_object *argv) { IMAGE *image = argv[0]; int x = *((int *) argv[1]); int y = *((int *) argv[2]); im_doublevec_object *dv = (im_doublevec_object *) argv[3]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_point", image, dv->n, dv->vec))) return -1; return im_draw_point(image, x, y, ink); } /* Description of im_draw_point. */ static im_function draw_point_desc = { "im_draw_point", /* Name */ "draw point on image", 0, /* Flags */ draw_point_vec, /* Dispatch function */ IM_NUMBER(draw_point_args), /* Size of arg list */ draw_point_args /* Arg list */ }; /* Args for im_read_point. */ static im_arg_desc read_point_args[] = { IM_INPUT_IMAGE("image"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_OUTPUT_DOUBLEVEC("ink") }; /* Call im_read_point via arg vector. */ static int read_point_vec(im_object *argv) { IMAGE *image = argv[0]; int x = *((int *) argv[1]); int y = *((int *) argv[2]); im_doublevec_object *dv = (im_doublevec_object *) argv[3]; VipsPel *ink; if (!(ink = IM_ARRAY(image, IM_IMAGE_SIZEOF_PEL(image), VipsPel)) || im_read_point(image, x, y, ink) || !(dv->vec = im__ink_to_vector("im_read_point", image, ink))) return -1; dv->n = image->Bands; return 0; } /* Description of im_read_point. */ static im_function read_point_desc = { "im_read_point", /* Name */ "read point from image", 0, /* Flags */ read_point_vec, /* Dispatch function */ IM_NUMBER(read_point_args), /* Size of arg list */ read_point_args /* Arg list */ }; /* Args for im_draw_line. */ static im_arg_desc draw_line_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("x1"), IM_INPUT_INT("y1"), IM_INPUT_INT("x2"), IM_INPUT_INT("y2"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_line via arg vector. */ static int draw_line_vec(im_object *argv) { IMAGE *image = argv[0]; int x1 = *((int *) argv[1]); int y1 = *((int *) argv[2]); int x2 = *((int *) argv[3]); int y2 = *((int *) argv[4]); im_doublevec_object *dv = (im_doublevec_object *) argv[5]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_line", image, dv->n, dv->vec))) return -1; return im_draw_line(image, x1, y1, x2, y2, ink); } /* Description of im_draw_line. */ static im_function draw_line_desc = { "im_draw_line", /* Name */ "draw line on image", 0, /* Flags */ draw_line_vec, /* Dispatch function */ IM_NUMBER(draw_line_args), /* Size of arg list */ draw_line_args /* Arg list */ }; /* Args for im_draw_smudge. */ static im_arg_desc draw_smudge_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("left"), IM_INPUT_INT("top"), IM_INPUT_INT("width"), IM_INPUT_INT("height") }; /* Call im_draw_smudge via arg vector. */ static int draw_smudge_vec(im_object *argv) { IMAGE *image = argv[0]; int left = *((int *) argv[1]); int top = *((int *) argv[2]); int width = *((int *) argv[3]); int height = *((int *) argv[4]); return im_draw_smudge(image, left, top, width, height); } /* Description of im_draw_smudge. */ static im_function draw_smudge_desc = { "im_draw_smudge", /* Name */ "smudge part of an image", 0, /* Flags */ draw_smudge_vec, /* Dispatch function */ IM_NUMBER(draw_smudge_args), /* Size of arg list */ draw_smudge_args /* Arg list */ }; /* Args for im_draw_rect. */ static im_arg_desc draw_rect_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("left"), IM_INPUT_INT("top"), IM_INPUT_INT("width"), IM_INPUT_INT("height"), IM_INPUT_INT("fill"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_rect via arg vector. */ static int draw_rect_vec(im_object *argv) { IMAGE *image = argv[0]; int left = *((int *) argv[1]); int top = *((int *) argv[2]); int width = *((int *) argv[3]); int height = *((int *) argv[4]); int fill = *((int *) argv[5]); im_doublevec_object *dv = (im_doublevec_object *) argv[6]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_rect", image, dv->n, dv->vec))) return -1; return im_draw_rect(image, left, top, width, height, fill, ink); } /* Description of im_draw_rect. */ static im_function draw_rect_desc = { "im_draw_rect", /* Name */ "draw rect on image", 0, /* Flags */ draw_rect_vec, /* Dispatch function */ IM_NUMBER(draw_rect_args), /* Size of arg list */ draw_rect_args /* Arg list */ }; /* Args for im_draw_circle. */ static im_arg_desc draw_circle_args[] = { IM_RW_IMAGE("image"), IM_INPUT_INT("cx"), IM_INPUT_INT("cy"), IM_INPUT_INT("radius"), IM_INPUT_INT("fill"), IM_INPUT_DOUBLEVEC("ink") }; /* Call im_draw_circle via arg vector. */ static int draw_circle_vec(im_object *argv) { IMAGE *image = argv[0]; int cx = *((int *) argv[1]); int cy = *((int *) argv[2]); int radius = *((int *) argv[3]); int fill = *((int *) argv[4]); im_doublevec_object *dv = (im_doublevec_object *) argv[5]; VipsPel *ink; if (!(ink = im__vector_to_ink("im_draw_circle", image, dv->n, dv->vec))) return -1; return im_draw_circle(image, cx, cy, radius, fill, ink); } /* Description of im_draw_circle. */ static im_function draw_circle_desc = { "im_draw_circle", /* Name */ "draw circle on image", 0, /* Flags */ draw_circle_vec, /* Dispatch function */ IM_NUMBER(draw_circle_args), /* Size of arg list */ draw_circle_args /* Arg list */ }; /* Package up all these functions. */ static im_function *inplace_list[] = { &draw_circle_desc, &draw_rect_desc, &draw_line_desc, &draw_point_desc, &read_point_desc, &draw_smudge_desc, &draw_flood_desc, &draw_flood_blob_desc, &draw_flood_other_desc, &draw_image_desc, &draw_mask_desc, &lineset_desc }; /* Package of functions. */ im_package im__inplace = { "inplace", IM_NUMBER(inplace_list), inplace_list }; libvips-8.18.2/libvips/deprecated/lazy.c000066400000000000000000000165741516303661500202000ustar00rootroot00000000000000/* lazy open/save ... compat funcs for old im_open() behaviour * * 30/11/11 * - cut from old image.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include static gboolean vips_format_is_vips(VipsFormatClass *format) { return strcmp(VIPS_OBJECT_CLASS(format)->nickname, "vips") == 0; } /* Lazy open. */ /* What we track during a delayed open. */ typedef struct { VipsImage *image; VipsFormatClass *format; /* Read in pixels with this */ char *filename; /* Get pixels from here */ gboolean sequential; /* Sequential read requested */ VipsImage *real; /* The real decompressed image */ } Lazy; static void lazy_free_cb(VipsImage *image, Lazy *lazy) { VIPS_DEBUG_MSG("lazy_free: %p \"%s\"\n", lazy, lazy->filename); g_free(lazy->filename); VIPS_UNREF(lazy->real); g_free(lazy); } static Lazy * lazy_new(VipsImage *image, VipsFormatClass *format, const char *filename, gboolean sequential) { Lazy *lazy; lazy = g_new(Lazy, 1); VIPS_DEBUG_MSG("lazy_new: %p \"%s\"\n", lazy, filename); lazy->image = image; lazy->format = format; lazy->filename = g_strdup(filename); lazy->sequential = sequential; lazy->real = NULL; g_signal_connect(image, "close", G_CALLBACK(lazy_free_cb), lazy); return lazy; } static size_t disc_threshold(void) { static gboolean done = FALSE; static size_t threshold; if (!done) { const char *env; done = TRUE; /* 100mb default. */ threshold = 100 * 1024 * 1024; if ((env = g_getenv("IM_DISC_THRESHOLD"))) threshold = vips__parse_size(env); if (vips__disc_threshold) threshold = vips__parse_size(vips__disc_threshold); VIPS_DEBUG_MSG("disc_threshold: %zd bytes\n", threshold); } return threshold; } /* Make the real underlying image: either a direct disc file, or a temp file * somewhere. */ static VipsImage * lazy_real_image(Lazy *lazy) { VipsImage *real; /* We open via disc if: * - 'sequential' is not set * - disc_threshold() has not been set to zero * - the format does not support lazy read * - the uncompressed image will be larger than disc_threshold() */ real = NULL; if (!lazy->sequential && disc_threshold() && !(vips_format_get_flags(lazy->format, lazy->filename) & VIPS_FORMAT_PARTIAL) && VIPS_IMAGE_SIZEOF_IMAGE(lazy->image) > disc_threshold()) if (!(real = vips_image_new_temp_file("%s.v"))) return NULL; /* Otherwise, fall back to a "p". */ if (!real && !(real = vips_image_new())) return NULL; return real; } /* Our start function ... do the lazy open, if necessary, and return a region * on the new image. */ static void * open_lazy_start(VipsImage *out, void *a, void *dummy) { Lazy *lazy = (Lazy *) a; if (!lazy->real) { if (!(lazy->real = lazy_real_image(lazy)) || lazy->format->load(lazy->filename, lazy->real) || vips_image_pio_input(lazy->real)) { VIPS_UNREF(lazy->real); return NULL; } } return vips_region_new(lazy->real); } /* Just copy. */ static int open_lazy_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; /* Ask for input we need. */ if (vips_region_prepare(ir, r)) return -1; /* Attach output region to that. */ if (vips_region_region(out_region, ir, r, r->left, r->top)) return -1; return 0; } /* Lazy open ... init the header with the first OpenLazyFn, delay actually * decoding pixels with the second OpenLazyFn until the first generate(). */ static int vips_image_open_lazy(VipsImage *image, VipsFormatClass *format, const char *filename, gboolean sequential) { Lazy *lazy; lazy = lazy_new(image, format, filename, sequential); /* Is there a ->header() function? We need to do a lazy load. */ if (format->header) { /* Read header fields to init the return image. */ if (format->header(filename, image)) return -1; /* Then 'start' creates the real image and 'gen' paints 'image' * with pixels from the real image on demand. */ if (vips_image_pipelinev(image, image->dhint, NULL) || vips_image_generate(image, open_lazy_start, open_lazy_generate, vips_stop_one, lazy, NULL)) return -1; } else if (format->load) { if (format->load(filename, image)) return -1; } else g_assert(0); return 0; } /* Lazy save. */ /* If we write to (eg.) TIFF, actually do the write * to a "p" and on "written" do im_vips2tiff() or whatever. Track save * parameters here. */ typedef int (*VipsSaveFn)(VipsImage *image, const char *filename); typedef struct { VipsSaveFn save_fn; /* Save function */ char *filename; /* Save args */ } SaveBlock; /* From "written" callback: invoke a delayed save. */ static void vips_image_save_cb(VipsImage *image, int *result, SaveBlock *sb) { if (sb->save_fn(image, sb->filename)) *result = -1; g_free(sb->filename); g_free(sb); } static void vips_attach_save(VipsImage *image, VipsSaveFn save_fn, const char *filename) { SaveBlock *sb; sb = g_new(SaveBlock, 1); sb->save_fn = save_fn; sb->filename = g_strdup(filename); g_signal_connect(image, "written", G_CALLBACK(vips_image_save_cb), sb); } IMAGE * vips__deprecated_open_read(const char *filename, gboolean sequential) { VipsFormatClass *format; if (!(format = vips_format_for_file(filename))) return NULL; if (vips_format_is_vips(format)) { /* For vips format, we can just the main vips path. */ return vips_image_new_mode(filename, "rd"); } else { /* For non-vips formats we must go via the old VipsFormat * system to make sure we support the "filename:options" * syntax. */ IMAGE *image; image = vips_image_new(); if (vips_image_open_lazy(image, format, filename, sequential)) { g_object_unref(image); return NULL; } /* Yuk. Can't g_object_set() filename since it's after * construct. Just zap the new filename in. */ VIPS_SETSTR(image->filename, filename); return image; } } IMAGE * vips__deprecated_open_write(const char *filename) { VipsFormatClass *format; if (!(format = vips_format_for_name(filename))) return NULL; if (vips_format_is_vips(format)) /* For vips format, we can just the main vips path. */ return vips_image_new_mode(filename, "w"); else { /* For non-vips formats we must go via the old VipsFormat * system to make sure we support the "filename:options" * syntax. */ IMAGE *image; if (!(image = vips_image_new())) return NULL; vips_attach_save(image, format->save, filename); return image; } } libvips-8.18.2/libvips/deprecated/mask_dispatch.c000066400000000000000000000317231516303661500220240ustar00rootroot00000000000000/* VIPS function dispatch tables for matrices. * * J. Cupitt, 14/2/95. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* One matrix in, one out. */ static im_arg_desc one_in_one_out[] = { IM_INPUT_DMASK("in"), IM_OUTPUT_DMASK("out") }; /* Two matrices in, one out. */ static im_arg_desc two_in_one_out[] = { IM_INPUT_DMASK("in1"), IM_INPUT_DMASK("in2"), IM_OUTPUT_DMASK("out") }; /* Call im_matinv via arg vector. */ static int matinv_vec(im_object *argv) { im_mask_object *in = argv[0]; im_mask_object *out = argv[1]; if (!(out->mask = im_matinv(in->mask, out->name))) return -1; return 0; } /* Description of im_matinv. */ static im_function matinv_desc = { "im_matinv", /* Name */ "invert matrix", 0, /* Flags */ matinv_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_mattrn via arg vector. */ static int mattrn_vec(im_object *argv) { im_mask_object *in = argv[0]; im_mask_object *out = argv[1]; if (!(out->mask = im_mattrn(in->mask, out->name))) return -1; return 0; } /* Description of im_mattrn. */ static im_function mattrn_desc = { "im_mattrn", /* Name */ "transpose matrix", 0, /* Flags */ mattrn_vec, /* Dispatch function */ IM_NUMBER(one_in_one_out), /* Size of arg list */ one_in_one_out /* Arg list */ }; /* Call im_matcat via arg vector. */ static int matcat_vec(im_object *argv) { im_mask_object *in1 = argv[0]; im_mask_object *in2 = argv[1]; im_mask_object *out = argv[2]; if (!(out->mask = im_matcat(in1->mask, in2->mask, out->name))) return -1; return 0; } /* Description of im_matcat. */ static im_function matcat_desc = { "im_matcat", /* Name */ "append matrix in2 to the end of matrix in1", 0, /* Flags */ matcat_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Call im_matmul via arg vector. */ static int matmul_vec(im_object *argv) { im_mask_object *in1 = argv[0]; im_mask_object *in2 = argv[1]; im_mask_object *out = argv[2]; if (!(out->mask = im_matmul(in1->mask, in2->mask, out->name))) return -1; return 0; } /* Description of im_matmul. */ static im_function matmul_desc = { "im_matmul", /* Name */ "multiply matrix in1 by matrix in2", 0, /* Flags */ matmul_vec, /* Dispatch function */ IM_NUMBER(two_in_one_out), /* Size of arg list */ two_in_one_out /* Arg list */ }; /* Args for im_read_dmask() */ static im_arg_desc read_dmask_args[] = { IM_INPUT_STRING("filename"), IM_OUTPUT_DMASK("mask") }; /* Call im_read_dmask via arg vector. */ static int read_dmask_vec(im_object *argv) { im_mask_object *mo = argv[1]; if (!(mo->mask = im_read_dmask(argv[0]))) return -1; return 0; } /* Description of im_read_dmask(). */ static im_function read_dmask_desc = { "im_read_dmask", /* Name */ "read matrix of double from file", 0, /* Flags */ read_dmask_vec, /* Dispatch function */ IM_NUMBER(read_dmask_args), /* Size of arg list */ read_dmask_args /* Arg list */ }; /* Args for im_gauss_dmask. */ static im_arg_desc gauss_dmask_args[] = { IM_OUTPUT_DMASK("mask"), IM_INPUT_DOUBLE("sigma"), IM_INPUT_DOUBLE("min_amp") }; /* Call im_gauss_dmask via arg vector. */ static int gauss_dmask_vec(im_object *argv) { im_mask_object *mo = argv[0]; double sigma = *((double *) argv[1]); double min_amp = *((double *) argv[2]); if (!(mo->mask = im_gauss_dmask(mo->name, sigma, min_amp))) return -1; return 0; } /* Description of im_gauss_dmask. */ static im_function gauss_dmask_desc = { "im_gauss_dmask", /* Name */ "generate gaussian DOUBLEMASK", 0, /* Flags */ gauss_dmask_vec, /* Dispatch function */ IM_NUMBER(gauss_dmask_args), /* Size of arg list */ gauss_dmask_args /* Arg list */ }; /* Call im_gauss_dmask_sep via arg vector. */ static int gauss_dmask_sep_vec(im_object *argv) { im_mask_object *mo = argv[0]; double sigma = *((double *) argv[1]); double min_amp = *((double *) argv[2]); if (!(mo->mask = im_gauss_dmask_sep(mo->name, sigma, min_amp))) return -1; return 0; } /* Description of im_gauss_dmask_sep. */ static im_function gauss_dmask_sep_desc = { "im_gauss_dmask_sep", /* Name */ "generate separable gaussian DOUBLEMASK", 0, /* Flags */ gauss_dmask_sep_vec, /* Dispatch function */ IM_NUMBER(gauss_dmask_args), /* Size of arg list */ gauss_dmask_args /* Arg list */ }; /* Args for im_gauss_imask. */ static im_arg_desc gauss_imask_args[] = { IM_OUTPUT_IMASK("mask"), IM_INPUT_DOUBLE("sigma"), IM_INPUT_DOUBLE("min_amp") }; /* Call im_gauss_imask via arg vector. */ static int gauss_imask_vec(im_object *argv) { im_mask_object *mo = argv[0]; double sigma = *((double *) argv[1]); double min_amp = *((double *) argv[2]); if (!(mo->mask = im_gauss_imask(mo->name, sigma, min_amp))) return -1; return 0; } /* Description of im_gauss_imask. */ static im_function gauss_imask_desc = { "im_gauss_imask", /* Name */ "generate gaussian INTMASK", 0, /* Flags */ gauss_imask_vec, /* Dispatch function */ IM_NUMBER(gauss_imask_args), /* Size of arg list */ gauss_imask_args /* Arg list */ }; /* Call im_gauss_imask_sep via arg vector. */ static int gauss_imask_sep_vec(im_object *argv) { im_mask_object *mo = argv[0]; double sigma = *((double *) argv[1]); double min_amp = *((double *) argv[2]); if (!(mo->mask = im_gauss_imask_sep(mo->name, sigma, min_amp))) return -1; return 0; } /* Description of im_gauss_imask_sep. */ static im_function gauss_imask_sep_desc = { "im_gauss_imask_sep", /* Name */ "generate separable gaussian INTMASK", 0, /* Flags */ gauss_imask_sep_vec, /* Dispatch function */ IM_NUMBER(gauss_imask_args), /* Size of arg list */ gauss_imask_args /* Arg list */ }; /* Args for im_log_imask. */ static im_arg_desc log_imask_args[] = { IM_OUTPUT_IMASK("mask"), IM_INPUT_DOUBLE("sigma"), IM_INPUT_DOUBLE("min_amp") }; /* Call im_log_imask via arg vector. */ static int log_imask_vec(im_object *argv) { im_mask_object *mo = argv[0]; double sigma = *((double *) argv[1]); double min_amp = *((double *) argv[2]); if (!(mo->mask = im_log_imask(mo->name, sigma, min_amp))) return -1; return 0; } /* Description of im_log_imask. */ static im_function log_imask_desc = { "im_log_imask", /* Name */ "generate laplacian of gaussian INTMASK", 0, /* Flags */ log_imask_vec, /* Dispatch function */ IM_NUMBER(log_imask_args), /* Size of arg list */ log_imask_args /* Arg list */ }; /* Args for im_log_dmask. */ static im_arg_desc log_dmask_args[] = { IM_OUTPUT_DMASK("maskfile"), IM_INPUT_DOUBLE("sigma"), IM_INPUT_DOUBLE("min_amp") }; /* Call im_log_dmask via arg vector. */ static int log_dmask_vec(im_object *argv) { im_mask_object *mo = argv[0]; double sigma = *((double *) argv[1]); double min_amp = *((double *) argv[2]); if (!(mo->mask = im_log_dmask(mo->name, sigma, min_amp))) return -1; return 0; } /* Description of im_log_dmask. */ static im_function log_dmask_desc = { "im_log_dmask", /* Name */ "generate laplacian of gaussian DOUBLEMASK", 0, /* Flags */ log_dmask_vec, /* Dispatch function */ IM_NUMBER(log_dmask_args), /* Size of arg list */ log_dmask_args /* Arg list */ }; static im_arg_desc imask_args[] = { IM_INPUT_IMASK("in"), IM_OUTPUT_IMASK("out") }; static im_arg_desc dmask_args[] = { IM_INPUT_DMASK("in"), IM_OUTPUT_DMASK("out") }; /* Call im_rotate_imask45 via arg vector. */ static int rotate_imask45_vec(im_object *argv) { im_mask_object *min = argv[0]; im_mask_object *mout = argv[1]; if (!(mout->mask = im_rotate_imask45(min->mask, mout->name))) return -1; return 0; } /* Description of im_rotate_imask45. */ static im_function rotate_imask45_desc = { "im_rotate_imask45", /* Name */ "rotate INTMASK clockwise by 45 degrees", 0, /* Flags */ rotate_imask45_vec, /* Dispatch function */ IM_NUMBER(imask_args), /* Size of arg list */ imask_args /* Arg list */ }; /* Call im_rotate_imask90 via arg vector. */ static int rotate_imask90_vec(im_object *argv) { im_mask_object *min = argv[0]; im_mask_object *mout = argv[1]; if (!(mout->mask = im_rotate_imask90(min->mask, mout->name))) return -1; return 0; } /* Description of im_rotate_imask90. */ static im_function rotate_imask90_desc = { "im_rotate_imask90", /* Name */ "rotate INTMASK clockwise by 90 degrees", 0, /* Flags */ rotate_imask90_vec, /* Dispatch function */ IM_NUMBER(imask_args), /* Size of arg list */ imask_args /* Arg list */ }; /* Call im_rotate_dmask45 via arg vector. */ static int rotate_dmask45_vec(im_object *argv) { im_mask_object *min = argv[0]; im_mask_object *mout = argv[1]; if (!(mout->mask = im_rotate_dmask45(min->mask, mout->name))) return -1; return 0; } /* Description of im_rotate_dmask45. */ static im_function rotate_dmask45_desc = { "im_rotate_dmask45", /* Name */ "rotate DOUBLEMASK clockwise by 45 degrees", 0, /* Flags */ rotate_dmask45_vec, /* Dispatch function */ IM_NUMBER(dmask_args), /* Size of arg list */ dmask_args /* Arg list */ }; /* Call im_rotate_dmask90 via arg vector. */ static int rotate_dmask90_vec(im_object *argv) { im_mask_object *min = argv[0]; im_mask_object *mout = argv[1]; if (!(mout->mask = im_rotate_dmask90(min->mask, mout->name))) return -1; return 0; } /* Description of im_rotate_dmask90. */ static im_function rotate_dmask90_desc = { "im_rotate_dmask90", /* Name */ "rotate DOUBLEMASK clockwise by 90 degrees", 0, /* Flags */ rotate_dmask90_vec, /* Dispatch function */ IM_NUMBER(dmask_args), /* Size of arg list */ dmask_args /* Arg list */ }; static int imask_xsize_vec(im_object *argv) { *((int *) argv[1]) = ((INTMASK *) (((im_mask_object *) argv[0])->mask))->xsize; return 0; } static int imask_ysize_vec(im_object *argv) { *((int *) argv[1]) = ((INTMASK *) (((im_mask_object *) argv[0])->mask))->ysize; return 0; } static int dmask_xsize_vec(im_object *argv) { *((int *) argv[1]) = ((DOUBLEMASK *) (((im_mask_object *) argv[0])->mask))->xsize; return 0; } static int dmask_ysize_vec(im_object *argv) { *((int *) argv[1]) = ((DOUBLEMASK *) (((im_mask_object *) argv[0])->mask))->ysize; return 0; } static im_arg_desc imask_size_args[] = { IM_INPUT_IMASK("mask"), IM_OUTPUT_INT("size") }; static im_arg_desc dmask_size_args[] = { IM_INPUT_DMASK("mask"), IM_OUTPUT_INT("size") }; static im_function imask_xsize_desc = { "im_imask_xsize", /* Name */ "horizontal size of an intmask", /* Description */ 0, /* Flags */ imask_xsize_vec, /* Dispatch function */ IM_NUMBER(imask_size_args), /* Size of arg list */ imask_size_args /* Arg list */ }; static im_function imask_ysize_desc = { "im_imask_ysize", /* Name */ "vertical size of an intmask", /* Description */ 0, /* Flags */ imask_ysize_vec, /* Dispatch function */ IM_NUMBER(imask_size_args), /* Size of arg list */ imask_size_args /* Arg list */ }; static im_function dmask_xsize_desc = { "im_dmask_xsize", /* Name */ "horizontal size of a doublemask", /* Description */ 0, /* Flags */ dmask_xsize_vec, /* Dispatch function */ IM_NUMBER(dmask_size_args), /* Size of arg list */ dmask_size_args /* Arg list */ }; static im_function dmask_ysize_desc = { "im_dmask_ysize", /* Name */ "vertical size of a doublemask", /* Description */ 0, /* Flags */ dmask_ysize_vec, /* Dispatch function */ IM_NUMBER(dmask_size_args), /* Size of arg list */ dmask_size_args /* Arg list */ }; /* Package up all these functions. */ static im_function *mask_list[] = { &gauss_dmask_desc, &gauss_dmask_sep_desc, &log_dmask_desc, &log_imask_desc, &gauss_imask_desc, &gauss_imask_sep_desc, &dmask_xsize_desc, &dmask_ysize_desc, &imask_xsize_desc, &imask_ysize_desc, &read_dmask_desc, &rotate_dmask45_desc, &rotate_dmask90_desc, &rotate_imask45_desc, &rotate_imask90_desc, &matcat_desc, &matinv_desc, &matmul_desc, &mattrn_desc }; /* Package of functions. */ im_package im__mask = { "mask", IM_NUMBER(mask_list), mask_list }; libvips-8.18.2/libvips/deprecated/matalloc.c000066400000000000000000000111761516303661500210060ustar00rootroot00000000000000/* @(#) Programs for allocating and freeing matrices * @(#) pages 705- of numerical recipes in C 1998 * @(#) */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #define TINY 1.0e-200 /* @(#) Allocates and returns an pointer at the beginning of * @(#) an integer array array[nl,nh] or * @(#) float array array[nl,nh] or * @(#) double array array[nl,nh] * @(#) * @(#) Right call * @(#) int *im_ivector(nl, nh) * @(#) int nl, nh; * @(#) returns a pointer to an int array or NULL on error * @(#) * @(#) Right call * @(#) float *im_fvector(nl, nh) * @(#) int nl, nh; * @(#) returns a pointer to a float array or NULL on error * @(#) * @(#) Right call * @(#) double *im_dvector(nl, nh) * @(#) int nl, nh; * @(#) returns a pointer to a double array or NULL on error * @(#) * @(#) The following functions free the array allocated by the functions above * @(#) * @(#) void im_free_ivector(v, nl, nh) * @(#) int *v; * @(#) int nl, nh; * @(#) * @(#) void im_free_fvector(v, nl, nh) * @(#) float *v; * @(#) int nl, nh; * @(#) * @(#) void im_free_dvector(v, nl, nh) * @(#) double *v; * @(#) int nl, nh; * @(#) */ int * im_ivector(int nl, int nh) { int *v; v = (int *) im_malloc(NULL, (unsigned) (nh - nl + 1) * sizeof(int)); if (v == NULL) return NULL; else return v - nl; } float * im_fvector(int nl, int nh) { float *v; v = (float *) im_malloc(NULL, (unsigned) (nh - nl + 1) * sizeof(float)); if (v == NULL) return NULL; else return v - nl; } double * im_dvector(int nl, int nh) { double *v; v = (double *) im_malloc(NULL, (unsigned) (nh - nl + 1) * sizeof(double)); if (v == NULL) return NULL; else return v - nl; } void im_free_ivector(int *v, int nl, int nh) { im_free((char *) (v + nl)); } void im_free_fvector(float *v, int nl, int nh) { im_free((char *) (v + nl)); } void im_free_dvector(double *v, int nl, int nh) { im_free((char *) (v + nl)); } /* @(#) Allocates and returns an pointer at the beginning of * @(#) an int, float or double, two dimensional matrix[nrl,nrh][ncl,nch] * @(#) * @(#) Right call * @(#) int **im_imat_alloc(nrl, nrh, ncl, nch) * @(#) int nrl, nrh, ncl, nch; * @(#) returns a pointer to an int matrix or NULL on error * @(#) * @(#) float **im_fmat_alloc(nrl, nrh, ncl, nch) * @(#) int nrl, nrh, ncl, nch; * @(#) returns a pointer to an int matrix or NULL on error * @(#) * @(#) double **im_dmat_alloc(nrl, nrh, ncl, nch) * @(#) int nrl, nrh, ncl, nch; * @(#) returns a pointer to a double matrix or NULL on error * @(#) * @(#) The following routines free the matrix allocated by the functions above * @(#) void im_free_imat(m, nrl, nrh, ncl, nch) * @(#) int **m; * @(#) int nrl, nrh, ncl, nch; * @(#) * @(#) void im_free_fmat(m, nrl, nrh, ncl, nch) * @(#) float **m; * @(#) int nrl, nrh, ncl, nch; * @(#) * @(#) void im_free_dmat(m, nrl, nrh, ncl, nch) * @(#) double **m; * @(#) int nrl, nrh, ncl, nch; * @(#) */ int ** im_imat_alloc(int nrl, int nrh, int ncl, int nch) { int i; int **m; m = (int **) im_malloc(NULL, (unsigned) (nrh - nrl + 1) * sizeof(int *)); if (m == NULL) return NULL; m -= nrl; for (i = nrl; i <= nrh; i++) { m[i] = (int *) im_malloc(NULL, (unsigned) (nch - ncl + 1) * sizeof(int)); if (m[i] == NULL) return NULL; m[i] -= ncl; } return m; } void im_free_imat(int **m, int nrl, int nrh, int ncl, int nch) { int i; for (i = nrh; i >= nrl; i--) im_free((char *) (m[i] + ncl)); im_free((char *) (m + nrl)); } float ** im_fmat_alloc(int nrl, int nrh, int ncl, int nch) { int i; float **m; m = (float **) im_malloc(NULL, (unsigned) (nrh - nrl + 1) * sizeof(float *)); if (m == NULL) return NULL; m -= nrl; for (i = nrl; i <= nrh; i++) { m[i] = (float *) im_malloc(NULL, (unsigned) (nch - ncl + 1) * sizeof(float)); if (m[i] == NULL) return NULL; m[i] -= ncl; } return m; } void im_free_fmat(float **m, int nrl, int nrh, int ncl, int nch) { int i; for (i = nrh; i >= nrl; i--) im_free((char *) (m[i] + ncl)); im_free((char *) (m + nrl)); } double ** im_dmat_alloc(int nrl, int nrh, int ncl, int nch) { int i; double **m; m = (double **) im_malloc(NULL, (unsigned) (nrh - nrl + 1) * sizeof(double *)); if (m == NULL) return NULL; m -= nrl; for (i = nrl; i <= nrh; i++) { m[i] = (double *) im_malloc(NULL, (unsigned) (nch - ncl + 1) * sizeof(double)); if (m[i] == NULL) return NULL; m[i] -= ncl; } return m; } void im_free_dmat(double **m, int nrl, int nrh, int ncl, int nch) { int i; for (i = nrh; i >= nrl; i--) im_free((char *) (m[i] + ncl)); im_free((char *) (m + nrl)); } libvips-8.18.2/libvips/deprecated/matlab.c000066400000000000000000000037171516303661500204540ustar00rootroot00000000000000/* Read matlab save files with libmatio * * 20/12/11 * - just a compat stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include int im_mat2vips(const char *filename, IMAGE *out) { VipsImage *t; if (vips_matload(filename, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int ismat(const char *filename) { return vips_foreign_is_a("matload", filename); } static const char *mat_suffs[] = { ".mat", NULL }; typedef VipsFormat VipsFormatMat; typedef VipsFormatClass VipsFormatMatClass; static void vips_format_mat_class_init(VipsFormatMatClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "mat"; object_class->description = _("Matlab"); format_class->is_a = ismat; format_class->load = im_mat2vips; format_class->save = NULL; format_class->suffs = mat_suffs; } static void vips_format_mat_init(VipsFormatMat *object) { } G_DEFINE_TYPE(VipsFormatMat, vips_format_mat, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/meson.build000066400000000000000000000041721516303661500212060ustar00rootroot00000000000000deprecated_sources = files( 'video_dispatch.c', 'im_video_test.c', 'cimg_dispatch.c', 'inplace_dispatch.c', 'tone.c', 'freq_dispatch.c', 'im_linreg.c', 'im_point_bilinear.c', 'resample_dispatch.c', 'im_openslide2vips.c', 'im_nifti2vips.c', 'im_lab_morph.c', 'deprecated_dispatch.c', 'mosaicing_dispatch.c', 'im_maxpos_subpel.c', 'im_align_bands.c', 'morph_dispatch.c', 'colour_dispatch.c', 'convol_dispatch.c', 'im_zerox.c', 'arith_dispatch.c', 'hist_dispatch.c', 'other_dispatch.c', 'im_maxpos_avg.c', 'lazy.c', 'im_dif_std.c', 'im_simcontr.c', 'im_spatres.c', 'im_stretch3.c', 'im_clamp.c', 'cooc_funcs.c', 'glds_funcs.c', 'im_fav4.c', 'im_benchmark.c', 'im_gadd.c', 'im_gaddim.c', 'im_gradcor.c', 'im_cmulnorm.c', 'im_printlines.c', 'im_convsub.c', 'im_line.c', 'im_measure.c', 'im_resize_linear.c', 'im_debugim.c', 'im_gfadd.c', 'im_setbox.c', 'rename.c', 'vips7compat.c', 'dispatch_types.c', 'package.c', 'im_bernd.c', 'im_thresh.c', 'im_slice.c', 'im_print.c', 'im_litecor.c', 'im_mask2vips.c', 'im_vips2mask.c', 'rotmask.c', 'rw_mask.c', 'im_matcat.c', 'im_matinv.c', 'im_matmul.c', 'im_mattrn.c', 'matalloc.c', 'mask_dispatch.c', 'fits.c', 'format.c', 'format_dispatch.c', 'im_analyze2vips.c', 'im_csv2vips.c', 'im_exr2vips.c', 'im_jpeg2vips.c', 'im_magick2vips.c', 'im_png2vips.c', 'im_webp2vips.c', 'im_ppm2vips.c', 'im_tiff2vips.c', 'im_vips2csv.c', 'im_vips2jpeg.c', 'im_vips2png.c', 'im_vips2webp.c', 'im_vips2ppm.c', 'im_vips2tiff.c', 'conver_dispatch.c', 'im_vips2dz.c', 'im_freq_mask.c', 'matlab.c', 'radiance.c', 'raw.c' ) libvips_sources += deprecated_sources deprecated_lib = static_library('deprecated', deprecated_sources, dependencies: libvips_deps, c_args: [ '-DVIPS_DISABLE_DEPRECATION_WARNINGS' ], gnu_symbol_visibility: 'hidden', ) libvips_components += deprecated_lib libvips-8.18.2/libvips/deprecated/morph_dispatch.c000066400000000000000000000152651516303661500222210ustar00rootroot00000000000000/* VIPS function dispatch tables for morphology. * * J. Cupitt, 19/9/95 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* Args to im_profile. */ static im_arg_desc profile_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("direction") }; /* Call im_profile via arg vector. */ static int profile_vec(im_object *argv) { int dir = *((int *) argv[2]); return im_profile(argv[0], argv[1], dir); } /* Description of im_profile. */ static im_function profile_desc = { "im_profile", /* Name */ "find first horizontal/vertical edge", /* Descr. */ IM_FN_TRANSFORM, /* Flags */ profile_vec, /* Dispatch function */ IM_NUMBER(profile_args), /* Size of arg list */ profile_args /* Arg list */ }; /* Args to im_erode. */ static im_arg_desc erode_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_IMASK("mask") }; /* Call im_dilate via arg vector. */ static int dilate_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_dilate(argv[0], argv[1], mo->mask); } /* Description of im_dilate. */ static im_function dilate_desc = { "im_dilate", /* Name */ "dilate image with mask, adding a black border", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ dilate_vec, /* Dispatch function */ IM_NUMBER(erode_args), /* Size of arg list */ erode_args /* Arg list */ }; /* Call im_erode via arg vector. */ static int erode_vec(im_object *argv) { im_mask_object *mo = argv[2]; return im_erode(argv[0], argv[1], mo->mask); } /* Description of im_erode. */ static im_function erode_desc = { "im_erode", /* Name */ "erode image with mask, adding a black border", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ erode_vec, /* Dispatch function */ IM_NUMBER(erode_args), /* Size of arg list */ erode_args /* Arg list */ }; /* Args to im_cntlines. */ static im_arg_desc cntlines_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_DOUBLE("nlines"), IM_INPUT_INT("direction") }; /* Call im_cntlines via arg vector. */ static int cntlines_vec(im_object *argv) { double *out = (double *) argv[1]; int dir = *((int *) argv[2]); return im_cntlines(argv[0], out, dir); } /* Description of im_cntlines. */ static im_function cntlines_desc = { "im_cntlines", /* Name */ "count horizontal or vertical lines", 0, /* Flags */ cntlines_vec, /* Dispatch function */ IM_NUMBER(cntlines_args), /* Size of arg list */ cntlines_args /* Arg list */ }; /* Args to im_rank. */ static im_arg_desc rank_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xsize"), IM_INPUT_INT("ysize"), IM_INPUT_INT("n") }; /* Call im_rank via arg vector. */ static int rank_vec(im_object *argv) { int xsize = *((int *) argv[2]); int ysize = *((int *) argv[3]); int n = *((int *) argv[4]); return im_rank(argv[0], argv[1], xsize, ysize, n); } /* Description of im_rank. */ static im_function rank_desc = { "im_rank", /* Name */ "rank filter nth element of xsize/ysize window", IM_FN_PIO, /* Flags */ rank_vec, /* Dispatch function */ IM_NUMBER(rank_args), /* Size of arg list */ rank_args /* Arg list */ }; /* Args for im_zerox. */ static im_arg_desc zerox_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("flag") }; /* Call im_zerox via arg vector. */ static int zerox_vec(im_object *argv) { int flag = *((int *) argv[2]); return im_zerox(argv[0], argv[1], flag); } /* Description of im_zerox. */ static im_function zerox_desc = { "im_zerox", /* Name */ "find +ve or -ve zero crossings in image", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ zerox_vec, /* Dispatch function */ IM_NUMBER(zerox_args), /* Size of arg list */ zerox_args /* Arg list */ }; static im_arg_desc maxvalue_args[] = { IM_INPUT_IMAGEVEC("in"), IM_OUTPUT_IMAGE("out") }; static int maxvalue_vec(im_object *argv) { im_imagevec_object *iv = (im_imagevec_object *) argv[0]; return im_maxvalue(iv->vec, argv[1], iv->n); } static im_function maxvalue_desc = { "im_maxvalue", /* Name */ "point-wise maximum value", /* Description */ IM_FN_PIO, /* Flags */ maxvalue_vec, /* Dispatch function */ IM_NUMBER(maxvalue_args), /* Size of arg list */ maxvalue_args /* Arg list */ }; static im_arg_desc rank_image_args[] = { IM_INPUT_IMAGEVEC("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("index") }; static int rank_image_vec(im_object *argv) { im_imagevec_object *iv = (im_imagevec_object *) argv[0]; int index = *((int *) argv[2]); return im_rank_image(iv->vec, argv[1], iv->n, index); } static im_function rank_image_desc = { "im_rank_image", /* Name */ "point-wise pixel rank", /* Description */ IM_FN_PIO, /* Flags */ rank_image_vec, /* Dispatch function */ IM_NUMBER(rank_image_args), /* Size of arg list */ rank_image_args /* Arg list */ }; /* Args for im_label_regions(). */ static im_arg_desc label_regions_args[] = { IM_INPUT_IMAGE("test"), IM_OUTPUT_IMAGE("mask"), IM_OUTPUT_INT("segments") }; /* Call im_label_regions() via arg vector. */ static int label_regions_vec(im_object *argv) { IMAGE *test = argv[0]; IMAGE *mask = argv[1]; int *serial = (int *) argv[2]; return im_label_regions(test, mask, serial); } /* Description of im_label_regions(). */ static im_function label_regions_desc = { "im_label_regions", /* Name */ "number continuous regions in an image", 0, /* Flags */ label_regions_vec, /* Dispatch function */ IM_NUMBER(label_regions_args), /* Size of arg list */ label_regions_args /* Arg list */ }; /* Package up all these functions. */ static im_function *morph_list[] = { &cntlines_desc, &dilate_desc, &rank_desc, &rank_image_desc, &maxvalue_desc, &label_regions_desc, &zerox_desc, &erode_desc, &profile_desc }; /* Package of functions. */ im_package im__morphology = { "morphology", IM_NUMBER(morph_list), morph_list }; libvips-8.18.2/libvips/deprecated/mosaicing_dispatch.c000066400000000000000000000442171516303661500230440ustar00rootroot00000000000000/* Function dispatch tables for mosaicing. * * J. Cupitt, 23/2/95 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* Merge args. */ static im_arg_desc merge_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("dx"), IM_INPUT_INT("dy"), IM_INPUT_INT("mwidth") }; /* Merge1 args. */ static im_arg_desc merge1_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xr1"), IM_INPUT_INT("yr1"), IM_INPUT_INT("xs1"), IM_INPUT_INT("ys1"), IM_INPUT_INT("xr2"), IM_INPUT_INT("yr2"), IM_INPUT_INT("xs2"), IM_INPUT_INT("ys2"), IM_INPUT_INT("mwidth") }; /* Mosaic args. */ static im_arg_desc mosaic_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("bandno"), IM_INPUT_INT("xr"), IM_INPUT_INT("yr"), IM_INPUT_INT("xs"), IM_INPUT_INT("ys"), IM_INPUT_INT("halfcorrelation"), IM_INPUT_INT("halfarea"), IM_INPUT_INT("balancetype"), // Deprecated IM_INPUT_INT("mwidth") }; /* Mosaic1 args. */ static im_arg_desc mosaic1_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("bandno"), // Deprecated IM_INPUT_INT("xr1"), IM_INPUT_INT("yr1"), IM_INPUT_INT("xs1"), IM_INPUT_INT("ys1"), IM_INPUT_INT("xr2"), IM_INPUT_INT("yr2"), IM_INPUT_INT("xs2"), IM_INPUT_INT("ys2"), IM_INPUT_INT("halfcorrelation"), IM_INPUT_INT("halfarea"), IM_INPUT_INT("balancetype"), // Deprecated IM_INPUT_INT("mwidth") }; /* Call im_lrmosaic via arg vector. */ static int lrmosaic_vec(im_object *argv) { int bandno = *((int *) argv[3]); int xr = *((int *) argv[4]); int yr = *((int *) argv[5]); int xs = *((int *) argv[6]); int ys = *((int *) argv[7]); int halfcorrelation = *((int *) argv[8]); int halfarea = *((int *) argv[9]); int mwidth = *((int *) argv[11]); return vips__lrmosaic(argv[0], argv[1], argv[2], bandno, xr, yr, xs, ys, halfcorrelation, halfarea, mwidth); } /* Call im_lrmosaic1 via arg vector. */ static int lrmosaic1_vec(im_object *argv) { int xr1 = *((int *) argv[4]); int yr1 = *((int *) argv[5]); int xs1 = *((int *) argv[6]); int ys1 = *((int *) argv[7]); int xr2 = *((int *) argv[8]); int yr2 = *((int *) argv[9]); int xs2 = *((int *) argv[10]); int ys2 = *((int *) argv[11]); int halfcorrelation = *((int *) argv[12]); int halfarea = *((int *) argv[13]); int mwidth = *((int *) argv[15]); return im_lrmosaic1(argv[0], argv[1], argv[2], 0, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, halfcorrelation, halfarea, 0, mwidth); } /* Description of im_lrmosaic. */ static im_function lrmosaic_desc = { "im_lrmosaic", /* Name */ "left-right mosaic of ref and sec", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ lrmosaic_vec, /* Dispatch function */ IM_NUMBER(mosaic_args), /* Size of arg list */ mosaic_args /* Arg list */ }; static im_arg_desc find_overlap_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_INPUT_INT("bandno"), IM_INPUT_INT("xr"), IM_INPUT_INT("yr"), IM_INPUT_INT("xs"), IM_INPUT_INT("ys"), IM_INPUT_INT("halfcorrelation"), IM_INPUT_INT("halfarea"), IM_OUTPUT_INT("dx0"), IM_OUTPUT_INT("dy0"), IM_OUTPUT_DOUBLE("scale1"), IM_OUTPUT_DOUBLE("angle1"), IM_OUTPUT_DOUBLE("dx1"), IM_OUTPUT_DOUBLE("dy1") }; /* Call im__find_lroverlap via arg vector. */ static int find_lroverlap_vec(im_object *argv) { int bandno = *((int *) argv[2]); int xr = *((int *) argv[3]); int yr = *((int *) argv[4]); int xs = *((int *) argv[5]); int ys = *((int *) argv[6]); int halfcorrelation = *((int *) argv[7]); int halfarea = *((int *) argv[8]); int *dx0 = (int *) argv[9]; int *dy0 = (int *) argv[10]; double *scale1 = (double *) argv[11]; double *angle1 = (double *) argv[12]; double *dx1 = (double *) argv[13]; double *dy1 = (double *) argv[14]; IMAGE *t; int result; if (!(t = im_open("find_lroverlap_vec", "p"))) return -1; result = vips__find_lroverlap(argv[0], argv[1], t, bandno, xr, yr, xs, ys, halfcorrelation, halfarea, dx0, dy0, scale1, angle1, dx1, dy1); im_close(t); return result; } /* Description of im__find_lroverlap. */ static im_function find_lroverlap_desc = { "im__find_lroverlap", /* Name */ "search for left-right overlap of ref and sec", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ find_lroverlap_vec, /* Dispatch function */ IM_NUMBER(find_overlap_args), /* Size of arg list */ find_overlap_args /* Arg list */ }; /* Description of im_lrmosaic1. */ static im_function lrmosaic1_desc = { "im_lrmosaic1", /* Name */ "first-order left-right mosaic of ref and sec", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ lrmosaic1_vec, /* Dispatch function */ IM_NUMBER(mosaic1_args), /* Size of arg list */ mosaic1_args /* Arg list */ }; /* Call im_tbmosaic via arg vector. */ static int tbmosaic_vec(im_object *argv) { int bandno = *((int *) argv[3]); int x1 = *((int *) argv[4]); int y1 = *((int *) argv[5]); int x2 = *((int *) argv[6]); int y2 = *((int *) argv[7]); int halfcorrelation = *((int *) argv[8]); int halfarea = *((int *) argv[9]); int mwidth = *((int *) argv[11]); return vips__tbmosaic(argv[0], argv[1], argv[2], bandno, x1, y1, x2, y2, halfcorrelation, halfarea, mwidth); } /* Call im_tbmosaic1 via arg vector. */ static int tbmosaic1_vec(im_object *argv) { int xr1 = *((int *) argv[4]); int yr1 = *((int *) argv[5]); int xs1 = *((int *) argv[6]); int ys1 = *((int *) argv[7]); int xr2 = *((int *) argv[8]); int yr2 = *((int *) argv[9]); int xs2 = *((int *) argv[10]); int ys2 = *((int *) argv[11]); int halfcorrelation = *((int *) argv[12]); int halfarea = *((int *) argv[13]); int mwidth = *((int *) argv[15]); return im_tbmosaic1(argv[0], argv[1], argv[2], 0, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, halfcorrelation, halfarea, 0, mwidth); } /* Call im__find_tboverlap via arg vector. */ static int find_tboverlap_vec(im_object *argv) { int bandno = *((int *) argv[2]); int xr = *((int *) argv[3]); int yr = *((int *) argv[4]); int xs = *((int *) argv[5]); int ys = *((int *) argv[6]); int halfcorrelation = *((int *) argv[7]); int halfarea = *((int *) argv[8]); int *dx0 = (int *) argv[9]; int *dy0 = (int *) argv[10]; double *scale1 = (double *) argv[11]; double *angle1 = (double *) argv[12]; double *dx1 = (double *) argv[13]; double *dy1 = (double *) argv[14]; IMAGE *t; int result; if (!(t = im_open("find_tboverlap_vec", "p"))) return -1; result = vips__find_tboverlap(argv[0], argv[1], t, bandno, xr, yr, xs, ys, halfcorrelation, halfarea, dx0, dy0, scale1, angle1, dx1, dy1); im_close(t); return result; } /* Description of im__find_tboverlap. */ static im_function find_tboverlap_desc = { "im__find_tboverlap", /* Name */ "search for top-bottom overlap of ref and sec", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ find_tboverlap_vec, /* Dispatch function */ IM_NUMBER(find_overlap_args), /* Size of arg list */ find_overlap_args /* Arg list */ }; /* Description of im_tbmosaic. */ static im_function tbmosaic_desc = { "im_tbmosaic", /* Name */ "top-bottom mosaic of in1 and in2", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ tbmosaic_vec, /* Dispatch function */ IM_NUMBER(mosaic_args), /* Size of arg list */ mosaic_args /* Arg list */ }; /* Description of im_tbmosaic1. */ static im_function tbmosaic1_desc = { "im_tbmosaic1", /* Name */ "first-order top-bottom mosaic of ref and sec", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ tbmosaic1_vec, /* Dispatch function */ IM_NUMBER(mosaic1_args), /* Size of arg list */ mosaic1_args /* Arg list */ }; /* Call im_lrmerge via arg vector. */ static int lrmerge_vec(im_object *argv) { int dx = *((int *) argv[3]); int dy = *((int *) argv[4]); int mwidth = *((int *) argv[5]); return im_lrmerge(argv[0], argv[1], argv[2], dx, dy, mwidth); } /* Call im_lrmerge1 via arg vector. */ static int lrmerge1_vec(im_object *argv) { int xr1 = *((int *) argv[3]); int yr1 = *((int *) argv[4]); int xs1 = *((int *) argv[5]); int ys1 = *((int *) argv[6]); int xr2 = *((int *) argv[7]); int yr2 = *((int *) argv[8]); int xs2 = *((int *) argv[9]); int ys2 = *((int *) argv[10]); int mwidth = *((int *) argv[11]); return im_lrmerge1(argv[0], argv[1], argv[2], xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, mwidth); } /* Description of im_lrmerge. */ static im_function lrmerge_desc = { "im_lrmerge", /* Name */ "left-right merge of in1 and in2", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ lrmerge_vec, /* Dispatch function */ IM_NUMBER(merge_args), /* Size of arg list */ merge_args /* Arg list */ }; /* Description of im_lrmerge1. */ static im_function lrmerge1_desc = { "im_lrmerge1", /* Name */ "first-order left-right merge of ref and sec", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ lrmerge1_vec, /* Dispatch function */ IM_NUMBER(merge1_args), /* Size of arg list */ merge1_args /* Arg list */ }; /* Call im_tbmerge via arg vector. */ static int tbmerge_vec(im_object *argv) { int dx = *((int *) argv[3]); int dy = *((int *) argv[4]); int mwidth = *((int *) argv[5]); return im_tbmerge(argv[0], argv[1], argv[2], dx, dy, mwidth); } /* Call im_tbmerge1 via arg vector. */ static int tbmerge1_vec(im_object *argv) { int xr1 = *((int *) argv[3]); int yr1 = *((int *) argv[4]); int xs1 = *((int *) argv[5]); int ys1 = *((int *) argv[6]); int xr2 = *((int *) argv[7]); int yr2 = *((int *) argv[8]); int xs2 = *((int *) argv[9]); int ys2 = *((int *) argv[10]); int mwidth = *((int *) argv[11]); return im_tbmerge1(argv[0], argv[1], argv[2], xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, mwidth); } /* Description of im_tbmerge. */ static im_function tbmerge_desc = { "im_tbmerge", /* Name */ "top-bottom merge of in1 and in2", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ tbmerge_vec, /* Dispatch function */ IM_NUMBER(merge_args), /* Size of arg list */ merge_args /* Arg list */ }; /* Description of im_tbmerge1. */ static im_function tbmerge1_desc = { "im_tbmerge1", /* Name */ "first-order top-bottom merge of in1 and in2", /* Description */ IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ tbmerge1_vec, /* Dispatch function */ IM_NUMBER(merge1_args), /* Size of arg list */ merge1_args /* Arg list */ }; /* match_linear args */ static im_arg_desc match_linear_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xref1"), IM_INPUT_INT("yref1"), IM_INPUT_INT("xsec1"), IM_INPUT_INT("ysec1"), IM_INPUT_INT("xref2"), IM_INPUT_INT("yref2"), IM_INPUT_INT("xsec2"), IM_INPUT_INT("ysec2") }; /* Call im_match_linear via arg vector. */ static int match_linear_vec(im_object *argv) { int xref1 = *((int *) argv[3]); int yref1 = *((int *) argv[4]); int xsec1 = *((int *) argv[5]); int ysec1 = *((int *) argv[6]); int xref2 = *((int *) argv[7]); int yref2 = *((int *) argv[8]); int xsec2 = *((int *) argv[9]); int ysec2 = *((int *) argv[10]); return im_match_linear(argv[0], argv[1], argv[2], xref1, yref1, xsec1, ysec1, xref2, yref2, xsec2, ysec2); } /* Description of im_match_linear. */ static im_function match_linear_desc = { "im_match_linear", /* Name */ "resample ref so that tie-points match", IM_FN_PIO, /* Flags */ match_linear_vec, /* Dispatch function */ IM_NUMBER(match_linear_args), /* Size of arg list */ match_linear_args /* Arg list */ }; /* match_linear_search args */ static im_arg_desc match_linear_search_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xref1"), IM_INPUT_INT("yref1"), IM_INPUT_INT("xsec1"), IM_INPUT_INT("ysec1"), IM_INPUT_INT("xref2"), IM_INPUT_INT("yref2"), IM_INPUT_INT("xsec2"), IM_INPUT_INT("ysec2"), IM_INPUT_INT("hwindowsize"), IM_INPUT_INT("hsearchsize") }; /* Call im_match_linear_search via arg vector. */ static int match_linear_search_vec(im_object *argv) { int xref1 = *((int *) argv[3]); int yref1 = *((int *) argv[4]); int xsec1 = *((int *) argv[5]); int ysec1 = *((int *) argv[6]); int xref2 = *((int *) argv[7]); int yref2 = *((int *) argv[8]); int xsec2 = *((int *) argv[9]); int ysec2 = *((int *) argv[10]); int hwin = *((int *) argv[11]); int hsrch = *((int *) argv[12]); return im_match_linear_search(argv[0], argv[1], argv[2], xref1, yref1, xsec1, ysec1, xref2, yref2, xsec2, ysec2, hwin, hsrch); } /* Description of im_match_linear_search. */ static im_function match_linear_search_desc = { "im_match_linear_search", /* Name */ "search sec, then resample so that tie-points match", IM_FN_PIO, /* Flags */ match_linear_search_vec, /* Dispatch function */ IM_NUMBER(match_linear_search_args), /* Size of arg list */ match_linear_search_args /* Arg list */ }; /* correl args */ static im_arg_desc correl_args[] = { IM_INPUT_IMAGE("ref"), IM_INPUT_IMAGE("sec"), IM_INPUT_INT("xref"), IM_INPUT_INT("yref"), IM_INPUT_INT("xsec"), IM_INPUT_INT("ysec"), IM_INPUT_INT("hwindowsize"), IM_INPUT_INT("hsearchsize"), IM_OUTPUT_DOUBLE("correlation"), IM_OUTPUT_INT("x"), IM_OUTPUT_INT("y") }; /* Call im_correl via arg vector. */ static int correl_vec(im_object *argv) { int xref = *((int *) argv[2]); int yref = *((int *) argv[3]); int xsec = *((int *) argv[4]); int ysec = *((int *) argv[5]); int cor = *((int *) argv[6]); int area = *((int *) argv[7]); int *x = (int *) argv[8]; int *y = (int *) argv[9]; double *correlation = (double *) argv[10]; return vips__correl(argv[0], argv[1], xref, yref, xsec, ysec, cor, area, correlation, x, y); } /* Description of im_correl. */ static im_function correl_desc = { "im_correl", /* Name */ "search area around sec for match for area around ref", IM_FN_PIO, /* Flags */ correl_vec, /* Dispatch function */ IM_NUMBER(correl_args), /* Size of arg list */ correl_args /* Arg list */ }; /* global_balance args */ static im_arg_desc global_balance_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("gamma") }; /* Call im_global_balance via arg vector. */ static int global_balance_vec(im_object *argv) { double gamma = *((double *) argv[2]); return im_global_balance(argv[0], argv[1], gamma); } /* Description of im_global_balance. */ static im_function global_balance_desc = { "im_global_balance", /* Name */ "automatically rebuild mosaic with balancing", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ global_balance_vec, /* Dispatch function */ IM_NUMBER(global_balance_args), /* Size of arg list */ global_balance_args /* Arg list */ }; /* Call im_global_balancef via arg vector. */ static int global_balancef_vec(im_object *argv) { double gamma = *((double *) argv[2]); return im_global_balancef(argv[0], argv[1], gamma); } /* Description of im_global_balancef. */ static im_function global_balancef_desc = { "im_global_balancef", /* Name */ "automatically rebuild mosaic with balancing, float output", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ global_balancef_vec, /* Dispatch function */ IM_NUMBER(global_balance_args), /* Size of arg list */ global_balance_args /* Arg list */ }; /* remosaic args */ static im_arg_desc remosaic_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("old_str"), IM_INPUT_STRING("new_str") }; /* Call im_remosaic via arg vector. */ static int remosaic_vec(im_object *argv) { return im_remosaic(argv[0], argv[1], argv[2], argv[3]); } /* Description of im_remosaic. */ static im_function remosaic_desc = { "im_remosaic", /* Name */ "automatically rebuild mosaic with new files", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ remosaic_vec, /* Dispatch function */ IM_NUMBER(remosaic_args), /* Size of arg list */ remosaic_args /* Arg list */ }; static int align_bands_vec(im_object *argv) { return im_align_bands((IMAGE *) argv[0], (IMAGE *) argv[1]); } static im_arg_desc align_bands_arg_types[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; static im_function align_bands_desc = { "im_align_bands", "align the bands of an image", 0, align_bands_vec, IM_NUMBER(align_bands_arg_types), align_bands_arg_types }; static int maxpos_subpel_vec(im_object *argv) { return im_maxpos_subpel((IMAGE *) argv[0], (double *) argv[1], (double *) argv[2]); } static im_arg_desc maxpos_subpel_arg_types[] = { IM_INPUT_IMAGE("im"), IM_OUTPUT_DOUBLE("x"), IM_OUTPUT_DOUBLE("y") }; static im_function maxpos_subpel_desc = { "im_maxpos_subpel", "subpixel position of maximum of (phase correlation) image", IM_FN_PIO, maxpos_subpel_vec, IM_NUMBER(maxpos_subpel_arg_types), maxpos_subpel_arg_types }; /* Package up all these functions. */ static im_function *mos_list[] = { &align_bands_desc, &correl_desc, &find_lroverlap_desc, &find_tboverlap_desc, &global_balance_desc, &global_balancef_desc, &lrmerge_desc, &lrmerge1_desc, &lrmosaic_desc, &lrmosaic1_desc, &match_linear_desc, &match_linear_search_desc, &maxpos_subpel_desc, &remosaic_desc, &tbmerge_desc, &tbmerge1_desc, &tbmosaic_desc, &tbmosaic1_desc }; /* Package of functions. */ im_package im__mosaicing = { "mosaicing", IM_NUMBER(mos_list), mos_list }; libvips-8.18.2/libvips/deprecated/other_dispatch.c000066400000000000000000000176001516303661500222100ustar00rootroot00000000000000/* Function dispatch tables for other. * * J. Cupitt, 8/2/95 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* Args for im_sines. */ static im_arg_desc sines_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xsize"), IM_INPUT_INT("ysize"), IM_INPUT_DOUBLE("horfreq"), IM_INPUT_DOUBLE("verfreq") }; /* Call im_sines via arg vector. */ static int sines_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); double horfreq = *((double *) argv[3]); double verfreq = *((double *) argv[4]); return im_sines(argv[0], xsize, ysize, horfreq, verfreq); } /* Description of im_sines. */ static im_function sines_desc = { "im_sines", /* Name */ "generate 2D sine image", 0, /* Flags */ sines_vec, /* Dispatch function */ IM_NUMBER(sines_args), /* Size of arg list */ sines_args /* Arg list */ }; /* Args for im_eye. */ static im_arg_desc eye_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xsize"), IM_INPUT_INT("ysize"), IM_INPUT_DOUBLE("factor") }; /* Call im_eye via arg vector. */ static int eye_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); double factor = *((double *) argv[3]); return im_eye(argv[0], xsize, ysize, factor); } /* Description of im_eye. */ static im_function eye_desc = { "im_eye", /* Name */ "generate IM_BANDFMT_UCHAR [0,255] frequency/amplitude image", 0, /* Flags */ eye_vec, /* Dispatch function */ IM_NUMBER(eye_args), /* Size of arg list */ eye_args /* Arg list */ }; /* Call im_feye via arg vector. */ static int feye_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); double factor = *((double *) argv[3]); return im_feye(argv[0], xsize, ysize, factor); } /* Description of im_feye. */ static im_function feye_desc = { "im_feye", /* Name */ "generate IM_BANDFMT_FLOAT [-1,1] frequency/amplitude image", 0, /* Flags */ feye_vec, /* Dispatch function */ IM_NUMBER(eye_args), /* Size of arg list */ eye_args /* Arg list */ }; /* Args for im_zone. */ static im_arg_desc zone_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("size") }; /* Call im_zone via arg vector. */ static int zone_vec(im_object *argv) { int size = *((int *) argv[1]); return im_zone(argv[0], size); } /* Description of im_zone. */ static im_function zone_desc = { "im_zone", /* Name */ "generate IM_BANDFMT_UCHAR [0,255] zone plate image", /* Description */ 0, /* Flags */ zone_vec, /* Dispatch function */ IM_NUMBER(zone_args), /* Size of arg list */ zone_args /* Arg list */ }; /* Call im_fzone via arg vector. */ static int fzone_vec(im_object *argv) { int size = *((int *) argv[1]); return im_fzone(argv[0], size); } /* Description of im_fzone. */ static im_function fzone_desc = { "im_fzone", /* Name */ "generate IM_BANDFMT_FLOAT [-1,1] zone plate image", /* Description */ 0, /* Flags */ fzone_vec, /* Dispatch function */ IM_NUMBER(zone_args), /* Size of arg list */ zone_args /* Arg list */ }; /* Args for im_benchmark. */ static im_arg_desc benchmark_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out") }; /* Call im_benchmark via arg vector. */ static int benchmark_vec(im_object *argv) { return im_benchmarkn(argv[0], argv[1], 1); } /* Description of im_benchmark. */ static im_function benchmark_desc = { "im_benchmark", /* Name */ "do something complicated for testing", /* Description */ IM_FN_PIO, /* Flags */ benchmark_vec, /* Dispatch function */ IM_NUMBER(benchmark_args), /* Size of arg list */ benchmark_args /* Arg list */ }; /* Args for im_benchmark2. */ static im_arg_desc benchmark2_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_DOUBLE("value") }; /* Call im_benchmark2 via arg vector. */ static int benchmark2_vec(im_object *argv) { double f; if (im_benchmark2(argv[0], &f)) return -1; *((double *) argv[1]) = f; return 0; } /* Description of im_benchmark2. */ static im_function benchmark2_desc = { "im_benchmark2", /* Name */ "do something complicated for testing", /* Description */ IM_FN_PIO, /* Flags */ benchmark2_vec, /* Dispatch function */ IM_NUMBER(benchmark2_args), /* Size of arg list */ benchmark2_args /* Arg list */ }; /* Args for im_benchmarkn. */ static im_arg_desc benchmarkn_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("n") }; /* Call im_benchmarkn via arg vector. */ static int benchmarkn_vec(im_object *argv) { int n = *((int *) argv[2]); return im_benchmarkn(argv[0], argv[1], n); } /* Description of im_benchmarkn. */ static im_function benchmarkn_desc = { "im_benchmarkn", /* Name */ "do something complicated for testing", /* Description */ IM_FN_PIO, /* Flags */ benchmarkn_vec, /* Dispatch function */ IM_NUMBER(benchmarkn_args), /* Size of arg list */ benchmarkn_args /* Arg list */ }; /* Args for im_grey. */ static im_arg_desc grey_args[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xsize"), IM_INPUT_INT("ysize") }; /* Call im_grey via arg vector. */ static int grey_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); return im_grey(argv[0], xsize, ysize); } /* Description of im_grey. */ static im_function grey_desc = { "im_grey", /* Name */ "generate IM_BANDFMT_UCHAR [0,255] grey scale image", /* Description */ 0, /* Flags */ grey_vec, /* Dispatch function */ IM_NUMBER(grey_args), /* Size of arg list */ grey_args /* Arg list */ }; /* Call im_fgrey via arg vector. */ static int fgrey_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); return im_fgrey(argv[0], xsize, ysize); } /* Description of im_fgrey. */ static im_function fgrey_desc = { "im_fgrey", /* Name */ "generate IM_BANDFMT_FLOAT [0,1] grey scale image", /* Description */ 0, /* Flags */ fgrey_vec, /* Dispatch function */ IM_NUMBER(grey_args), /* Size of arg list */ grey_args /* Arg list */ }; /* Call im_make_xy via arg vector. */ static int make_xy_vec(im_object *argv) { int xsize = *((int *) argv[1]); int ysize = *((int *) argv[2]); return im_make_xy(argv[0], xsize, ysize); } /* Description of im_make_xy. */ static im_function make_xy_desc = { "im_make_xy", /* Name */ "generate image with pixel value equal to coordinate", /* Description */ 0, /* Flags */ make_xy_vec, /* Dispatch function */ IM_NUMBER(grey_args), /* Size of arg list */ grey_args /* Arg list */ }; /* Package up all these functions. */ static im_function *other_list[] = { &benchmark_desc, &benchmark2_desc, &benchmarkn_desc, &eye_desc, &grey_desc, &feye_desc, &fgrey_desc, &fzone_desc, &make_xy_desc, &sines_desc, &zone_desc }; /* Package of functions. */ im_package im__other = { "other", IM_NUMBER(other_list), other_list }; libvips-8.18.2/libvips/deprecated/package.c000066400000000000000000000612101516303661500205770ustar00rootroot00000000000000/* VIPS package handling. * * J. Cupitt, 8/4/93. * * 18/2/04 JC * - now uses g_module_*() instead of dlopen() * 9/8/04 * - uses glib dir scanning stuff instead of dirent.h * 20/5/08 * - note_dependencies() does IMAGEVEC as well as IMAGE * 5/8/08 * - silent success in loading plugins if the dir isn't there */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_SYS_PARAM_H #include #endif /*HAVE_SYS_PARAM_H*/ #include #include #include #include #include #include /* Standard VIPS packages. */ extern im_package im__arithmetic; extern im_package im__cimg; extern im_package im__colour; extern im_package im__conversion; extern im_package im__convolution; extern im_package im__deprecated; extern im_package im__format; extern im_package im__freq_filt; extern im_package im__histograms_lut; extern im_package im__inplace; extern im_package im__mask; extern im_package im__morphology; extern im_package im__mosaicing; extern im_package im__other; extern im_package im__resample; extern im_package im__video; /* im_guess_prefix() args. */ static im_arg_desc guess_prefix_args[] = { IM_INPUT_STRING("argv0"), IM_INPUT_STRING("env_name"), IM_OUTPUT_STRING("PREFIX") }; /* Call im_guess_prefix() via arg vector. */ static int guess_prefix_vec(im_object *argv) { const char *prefix = vips_guess_prefix(argv[0], argv[1]); if (!prefix) { argv[2] = NULL; return -1; } argv[2] = im_strdup(NULL, prefix); return 0; } /* Description of im_guess_prefix. */ static im_function guess_prefix_desc = { "im_guess_prefix", /* Name */ "guess install area", /* Description */ 0, /* Flags */ guess_prefix_vec, /* Dispatch function */ VIPS_NUMBER(guess_prefix_args), /* Size of arg list */ guess_prefix_args /* Arg list */ }; /* im_guess_libdir() args. */ static im_arg_desc guess_libdir_args[] = { IM_INPUT_STRING("argv0"), IM_INPUT_STRING("env_name"), IM_OUTPUT_STRING("LIBDIR") }; /* Call im_guess_libdir() via arg vector. */ static int guess_libdir_vec(im_object *argv) { const char *libdir = vips_guess_libdir(argv[0], argv[1]); if (!libdir) { argv[2] = NULL; return -1; } argv[2] = im_strdup(NULL, libdir); return 0; } /* Description of im_guess_libdir. */ static im_function guess_libdir_desc = { "im_guess_libdir", /* Name */ "guess library area", /* Description */ 0, /* Flags */ guess_libdir_vec, /* Dispatch function */ VIPS_NUMBER(guess_libdir_args), /* Size of arg list */ guess_libdir_args /* Arg list */ }; /* im_header_int() args. */ static im_arg_desc header_int_args[] = { IM_INPUT_STRING("field"), IM_INPUT_IMAGE("image"), IM_OUTPUT_INT("value") }; /* Call im_header_int() via arg vector. */ static int header_int_vec(im_object *argv) { return im_header_int((IMAGE *) argv[1], (const char *) argv[0], (int *) argv[2]); } /* Description of im_header_int(). */ static im_function header_int_desc = { "im_header_int", /* Name */ "extract int fields from header", /* Description */ 0, /* Flags */ header_int_vec, /* Dispatch function */ VIPS_NUMBER(header_int_args), /* Size of arg list */ header_int_args /* Arg list */ }; /* im_header_get_typeof() args. */ static im_arg_desc header_get_typeof_args[] = { IM_INPUT_STRING("field"), IM_INPUT_IMAGE("image"), IM_OUTPUT_INT("gtype") }; /* Call im_header_get_typeof() via arg vector. */ static int header_get_typeof_vec(im_object *argv) { int *out = (int *) argv[2]; *out = im_header_get_typeof((IMAGE *) argv[1], (const char *) argv[0]); return 0; } /* Description of im_header_get_typeof(). */ static im_function header_get_typeof_desc = { "im_header_get_typeof", /* Name */ "return field type", /* Description */ 0, /* Flags */ header_get_typeof_vec, /* Dispatch function */ VIPS_NUMBER(header_get_typeof_args), /* Size of arg list */ header_get_typeof_args /* Arg list */ }; /* im_header_double() args. */ static im_arg_desc header_double_args[] = { IM_INPUT_STRING("field"), IM_INPUT_IMAGE("image"), IM_OUTPUT_DOUBLE("value") }; /* Call im_header_double() via arg vector. */ static int header_double_vec(im_object *argv) { return im_header_double((IMAGE *) argv[1], (const char *) argv[0], (double *) argv[2]); } /* Description of im_header_double(). */ static im_function header_double_desc = { "im_header_double", /* Name */ "extract double fields from header", /* Description */ 0, /* Flags */ header_double_vec, /* Dispatch function */ VIPS_NUMBER(header_double_args), /* Size of arg list */ header_double_args /* Arg list */ }; /* im_header_string() args. */ static im_arg_desc header_string_args[] = { IM_INPUT_STRING("field"), IM_INPUT_IMAGE("image"), IM_OUTPUT_STRING("value") }; /* Call im_header_string() via arg vector. */ static int header_string_vec(im_object *argv) { char **out = (char **) &argv[2]; /* Actually, we call im_header_as_string(), so we can do any field and * not just the string-valued ones. */ if (im_header_as_string((IMAGE *) argv[1], (const char *) argv[0], out)) return -1; return 0; } /* Description of im_header_string(). */ static im_function header_string_desc = { "im_header_string", /* Name */ "extract fields from headers as strings", /* Description */ 0, /* Flags */ header_string_vec, /* Dispatch function */ VIPS_NUMBER(header_string_args), /* Size of arg list */ header_string_args /* Arg list */ }; /* im_history_get() args. */ static im_arg_desc history_get_args[] = { IM_INPUT_IMAGE("image"), IM_OUTPUT_STRING("history") }; /* Call im_history_get() via arg vector. */ static int history_get_vec(im_object *argv) { char **out = (char **) &argv[1]; const char *str; if (!(str = im_history_get((IMAGE *) argv[0])) || !(*out = im_strdup(NULL, str))) return -1; return 0; } /* Description of im_history_get(). */ static im_function history_get_desc = { "im_history_get", /* Name */ "return the image history as a string", /* Description */ 0, /* Flags */ history_get_vec, /* Dispatch function */ VIPS_NUMBER(history_get_args), /* Size of arg list */ history_get_args /* Arg list */ }; /* im_getext() args. */ static im_arg_desc getext_args[] = { IM_INPUT_IMAGE("image"), IM_OUTPUT_STRING("history") }; /* Call im_getext() via arg vector. */ static int getext_vec(im_object *argv) { void **out = (void **) &argv[1]; size_t size; /* void/char confusion is fine. */ if (!(*out = im__read_extension_block((IMAGE *) argv[0], &size))) return -1; return 0; } /* Description of im_getext(). */ static im_function getext_desc = { "im_getext", /* Name */ "return the image metadata XML as a string", /* Description */ 0, /* Flags */ getext_vec, /* Dispatch function */ VIPS_NUMBER(getext_args), /* Size of arg list */ getext_args /* Arg list */ }; /* im_printdesc() args. */ static im_arg_desc printdesc_args[] = { IM_INPUT_IMAGE("image"), }; /* Call im_printdesc() via arg vector. */ static int printdesc_vec(im_object *argv) { vips_object_print_dump(VIPS_OBJECT(argv[0])); return 0; } /* Description of im_printdesc(). */ static im_function printdesc_desc = { "im_printdesc", /* Name */ "print an image header to stdout", /* Description */ 0, /* Flags */ printdesc_vec, /* Dispatch function */ VIPS_NUMBER(printdesc_args), /* Size of arg list */ printdesc_args /* Arg list */ }; /* im_version_string() args. */ static im_arg_desc version_string_args[] = { IM_OUTPUT_STRING("version") }; /* Call im_version_string() via arg vector. */ static int version_string_vec(im_object *argv) { if (!(argv[0] = im_strdup(NULL, vips_version_string()))) return -1; return 0; } /* Description of im_version_string. */ static im_function version_string_desc = { "im_version_string", /* Name */ "VIPS version string", /* Description */ 0, /* Flags */ version_string_vec, /* Dispatch function */ VIPS_NUMBER(version_string_args), /* Size of arg list */ version_string_args /* Arg list */ }; /* im_version() args. */ static im_arg_desc version_args[] = { IM_INPUT_INT("flag"), IM_OUTPUT_INT("version") }; /* Call im_version() via arg vector. */ static int version_vec(im_object *argv) { int flag = *((int *) argv[0]); int *out = ((int *) argv[1]); int version = vips_version(flag); if (version < 0) return -1; *out = version; return 0; } /* Description of im_version. */ static im_function version_desc = { "im_version", /* Name */ "VIPS version number", /* Description */ 0, /* Flags */ version_vec, /* Dispatch function */ VIPS_NUMBER(version_args), /* Size of arg list */ version_args /* Arg list */ }; /* im_concurrency_get() args. */ static im_arg_desc concurrency_get_args[] = { IM_OUTPUT_INT("concurrency") }; /* Call im_concurrency_get() via arg vector. */ static int concurrency_get_vec(im_object *argv) { int *out = ((int *) argv[0]); *out = vips_concurrency_get(); return 0; } /* Description of im_concurrency_get. */ static im_function concurrency_get_desc = { "im_concurrency_get", /* Name */ "get concurrency level", /* Description */ 0, /* Flags */ concurrency_get_vec, /* Dispatch function */ VIPS_NUMBER(concurrency_get_args), /* Size of arg list */ concurrency_get_args /* Arg list */ }; /* im_cache() args. */ static im_arg_desc cache_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("tile_width"), IM_INPUT_INT("tile_height"), IM_INPUT_INT("max_tiles") }; /* Call im_cache() via arg vector. */ static int cache_vec(im_object *argv) { int tile_width = *((int *) argv[2]); int tile_height = *((int *) argv[3]); int max_tiles = *((int *) argv[4]); return im_cache(argv[0], argv[1], tile_width, tile_height, max_tiles); } /* Description of im_cache. */ static im_function cache_desc = { "im_cache", /* Name */ "cache results of an operation", /* Description */ 0, /* Flags */ cache_vec, /* Dispatch function */ VIPS_NUMBER(cache_args), /* Size of arg list */ cache_args /* Arg list */ }; static int tile_cache_random_vec(im_object *argv) { int tile_width = *((int *) argv[2]); int tile_height = *((int *) argv[3]); int max_tiles = *((int *) argv[4]); return im_tile_cache_random(argv[0], argv[1], tile_width, tile_height, max_tiles); } /* Description of im_cache. */ static im_function tile_cache_random_desc = { "im_tile_cache_random", /* Name */ "cache results of an operation", /* Description */ 0, /* Flags */ tile_cache_random_vec, /* Dispatch function */ VIPS_NUMBER(cache_args), /* Size of arg list */ cache_args /* Arg list */ }; /* im_binfile() args. */ static im_arg_desc binfile_args[] = { IM_INPUT_STRING("filename"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("width"), IM_INPUT_INT("height"), IM_INPUT_INT("bands"), IM_INPUT_INT("offset") }; /* Call im_binfile() via arg vector. */ static int binfile_vec(im_object *argv) { int width = *((int *) argv[2]); int height = *((int *) argv[3]); int bands = *((int *) argv[4]); int offset = *((int *) argv[5]); VipsImage *im; if (!(im = vips_image_new_from_file_raw(argv[0], width, height, bands, offset))) return -1; vips_object_local(argv[1], im); if (im_copy(im, argv[1])) return -1; return 0; } /* Description of im_binfile. */ static im_function binfile_desc = { "im_binfile", /* Name */ "open a headerless binary file", /* Description */ 0, /* Flags */ binfile_vec, /* Dispatch function */ VIPS_NUMBER(binfile_args), /* Size of arg list */ binfile_args /* Arg list */ }; /* Package up iofuncs functions. */ static im_function *iofuncs_list[] = { &binfile_desc, &cache_desc, &tile_cache_random_desc, &concurrency_get_desc, &getext_desc, &guess_prefix_desc, &guess_libdir_desc, &header_get_typeof_desc, &header_int_desc, &header_double_desc, &header_string_desc, &history_get_desc, &printdesc_desc, &version_desc, &version_string_desc }; /* Package of io functions. */ static im_package im__iofuncs = { "iofuncs", VIPS_NUMBER(iofuncs_list), iofuncs_list }; /* List of built-in VIPS packages. */ static im_package *built_in[] = { &im__arithmetic, &im__cimg, &im__colour, &im__conversion, &im__convolution, &im__deprecated, &im__format, &im__freq_filt, &im__histograms_lut, &im__inplace, &im__iofuncs, &im__mask, &im__morphology, &im__mosaicing, &im__other, &im__resample, &im__video }; #ifdef ENABLE_MODULES /* How we represent a loaded plugin. */ typedef struct _Plugin { GModule *module; /* As loaded by g_module_open() */ char *name; /* Name we loaded */ im_package *pack; /* Package table */ } Plugin; /* List of loaded plugins. */ static GSList *plugin_list = NULL; /* Free a plugin. */ static int plugin_free(Plugin *plug) { char *name = plug->name ? plug->name : ""; if (plug->module) { if (!g_module_close(plug->module)) { vips_error("plugin", _("unable to close plugin \"%s\""), name); vips_error("plugin", "%s", g_module_error()); return -1; } plug->module = NULL; } VIPS_FREE(plug->name); plug->pack = NULL; plugin_list = g_slist_remove(plugin_list, plug); g_free(plug); return 0; } #endif /*ENABLE_MODULES*/ /* Load a plugin. */ im_package * im_load_plugin(const char *name) { #ifdef ENABLE_MODULES Plugin *plug; g_info("im_load_plugin: loading \"%s\" ...", name); if (!g_module_supported()) { vips_error("plugin", "%s", _("plugins not supported on this platform")); return NULL; } /* Build a new plugin. */ plug = VIPS_NEW(NULL, Plugin); plug->module = NULL; plug->name = g_strdup(name); plug->pack = NULL; plugin_list = g_slist_prepend(plugin_list, plug); /* Open library. */ if (!(plug->module = g_module_open(name, 0))) { vips_error("plugin", _("unable to open plugin \"%s\""), name); vips_error("plugin", "%s", g_module_error()); plugin_free(plug); return NULL; } /* Find package. */ /* Bizarre double-cast stops a bogus gcc 4.1 compiler warning. */ if (!g_module_symbol(plug->module, "package_table", (gpointer *) ((void *) &plug->pack))) { vips_error("plugin", _("unable to find symbol \"package_table\" " "in plugin \"%s\""), name); vips_error("plugin", "%s", g_module_error()); plugin_free(plug); return NULL; } /* Sanity check. */ if (!plug->pack->name || plug->pack->nfuncs < 0 || plug->pack->nfuncs > 10000) { vips_error("plugin", _("corrupted package table in plugin \"%s\""), name); plugin_free(plug); return NULL; } g_info("im_load_plugin: added package \"%s\"", plug->pack->name); return plug->pack; #else /*!ENABLE_MODULES*/ vips_error("plugin", "%s", _("libvips built without modules support")); return NULL; #endif /*ENABLE_MODULES*/ } /* Load all plugins in a directory ... look for '.plg' suffix. Error if we had * any probs. */ int im_load_plugins(const char *fmt, ...) { #ifdef ENABLE_MODULES va_list ap; char dir_name[VIPS_PATH_MAX]; GDir *dir; const char *name; int result; /* Silently succeed if we can't do modules. */ if (!g_module_supported()) return 0; va_start(ap, fmt); (void) im_vsnprintf(dir_name, VIPS_PATH_MAX, fmt, ap); va_end(ap); g_info("im_load_plugins: searching \"%s\"", dir_name); if (!(dir = g_dir_open(dir_name, 0, NULL))) /* Silent success for dir not there. */ return 0; result = 0; while ((name = g_dir_read_name(dir))) if (im_ispostfix(name, ".plg")) { char path[VIPS_PATH_MAX]; im_snprintf(path, VIPS_PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", dir_name, name); if (!im_load_plugin(path)) result = -1; } g_dir_close(dir); return result; #else /*!ENABLE_MODULES*/ /* Silently succeed if we can't do modules. */ return 0; #endif /*ENABLE_MODULES*/ } /* Close all loaded plugins. */ int im_close_plugins(void) { #ifdef ENABLE_MODULES while (plugin_list) if (plugin_free((Plugin *) plugin_list->data)) return -1; #endif /*ENABLE_MODULES*/ return 0; } #ifdef ENABLE_MODULES /* Apply a user-function to a plugin package. */ static void * apply_plugin(Plugin *plug, VSListMap2Fn fn, void *a) { if (!plug->pack) return NULL; else return fn(plug->pack, a, NULL); } #endif /*ENABLE_MODULES*/ /* Map a function over all packages. Map over plugins first, to allow * overriding of VIPS functions. */ void * im_map_packages(VSListMap2Fn fn, void *a) { #ifdef ENABLE_MODULES void *r = im_slist_map2(plugin_list, (VSListMap2Fn) apply_plugin, (void *) fn, a); #else /*!ENABLE_MODULES*/ void *r = NULL; #endif /*ENABLE_MODULES*/ /* If not there, try main VIPS package list. */ if (!r) { int i; for (i = 0; i < VIPS_NUMBER(built_in); i++) if ((r = fn(built_in[i], a, NULL))) return r; } return r; } /* Search a package for a function. */ static im_function * search_package(im_package *pack, const char *name) { int i; for (i = 0; i < pack->nfuncs; i++) if (strcmp(pack->table[i]->name, name) == 0) return pack->table[i]; return NULL; } /* Search all packages for a function. */ im_function * im_find_function(const char *name) { im_function *fn = im_map_packages( (VSListMap2Fn) search_package, (void *) name); if (!fn) { vips_error("im_find_function", _("\"%s\" not found"), name); return NULL; } return fn; } /* Test for package is of name. */ static im_package * package_name(im_package *pack, const char *name) { if (strcmp(pack->name, name) == 0) return pack; return NULL; } /* Find a package. */ im_package * im_find_package(const char *name) { im_package *pack = im_map_packages( (VSListMap2Fn) package_name, (void *) name); if (!pack) { vips_error("im_find_package", _("\"%s\" not found"), name); return NULL; } return pack; } /* Test for package contains a function. */ static im_package * package_function(im_package *pack, const char *name) { if (search_package(pack, name)) return pack; else return NULL; } /* Find a function's package by name. */ im_package * im_package_of_function(const char *name) { im_package *pack = im_map_packages( (VSListMap2Fn) package_function, (void *) name); if (!pack) { vips_error("im_package_of_function", _("\"%s\" not found"), name); return NULL; } return pack; } /* Free any store we allocated for the argument list. */ int im_free_vargv(im_function *fn, im_object *vargv) { int i; int vargc = fn->argc; /* Free all elements. */ for (i = 0; i < vargc; i++) if (vargv[i]) { /* If there is local storage, free it. */ if (fn->argv[i].desc->size != 0) g_free(vargv[i]); /* NULL out pointer. */ vargv[i] = NULL; } return 0; } /* Allocate any local store the args will need; NULL out all others. */ int im_allocate_vargv(im_function *fn, im_object *vargv) { int i; int vargc = fn->argc; /* NULL out all pointers. */ for (i = 0; i < vargc; i++) vargv[i] = NULL; /* Allocate any space we will need. */ for (i = 0; i < vargc; i++) { int sz = fn->argv[i].desc->size; if (sz != 0) if (!(vargv[i] = vips_malloc(NULL, sz))) { /* Free anything we did allocate. */ (void) im_free_vargv(fn, vargv); return -1; } /* Zero memory. */ memset(vargv[i], 0, sz); } return 0; } /* Destroy the objects in the arg list. */ static int destroy_args(im_function *fn, im_object *vargv) { int i; int vargc = fn->argc; /* Destroy all elements with destroy functions. */ for (i = 0; i < vargc; i++) if (vargv[i]) /* If there's a destroy function for this type, * trigger it. */ if (fn->argv[i].desc->dest && fn->argv[i].desc->dest(vargv[i])) return -1; return 0; } /* Init an im_object array from a set of command-line arguments. */ static int build_args(im_function *fn, im_object *vargv, int argc, char **argv) { im_arg_desc *arg = fn->argv; int vargc = fn->argc; char *str; int i, j; /* Loop, constructing each im_arg. */ for (i = 0, j = 0; i < vargc; i++) { /* Find type for this arg. */ im_type_desc *type = arg[i].desc; /* Do we need to use up a command line argument? */ if (type->flags & IM_TYPE_ARG) { if (!argv[j]) { vips_error("im_run_command", "%s", _("too few arguments")); return -1; } str = argv[j++]; /* Init object. */ if (type->init && type->init(&vargv[i], str)) return -1; } else { /* Init object with no arg. */ if (type->init && type->init(&vargv[i], "no arg")) return -1; } } /* Have we used up all the command-line args? */ if (argv[j]) { vips_error("im_run_command", "%s", _("too many arguments")); return -1; } return 0; } /* Make a region on sub, closed by callback on main. */ static int region_local_image(IMAGE *main, IMAGE *sub) { VipsRegion *reg; if (!(reg = vips_region_new(sub))) return -1; vips_object_local(main, reg); return 0; } /* vargv[i] is an output image on a PIO function ... make all input images * depend on it. */ static int note_dependencies(im_function *fn, im_object *vargv, int i) { int j; for (j = 0; j < fn->argc; j++) { im_type_desc *type = fn->argv[j].desc; if (!(type->flags & IM_TYPE_OUTPUT)) { if (strcmp(type->type, IM_TYPE_IMAGE) == 0) { if (region_local_image(vargv[i], vargv[j])) return -1; } else if (strcmp(type->type, IM_TYPE_IMAGEVEC) == 0) { im_imagevec_object *iv = vargv[j]; int k; for (k = 0; k < iv->n; k++) if (region_local_image(vargv[i], iv->vec[k])) return -1; } } } return 0; } /* Call all defined print functions. */ static int print_args(im_function *fn, im_object *vargv) { int i; int vargc = fn->argc; /* Print all elements. */ for (i = 0; i < vargc; i++) if (fn->argv[i].print && vargv[i]) if (fn->argv[i].print(vargv[i])) return -1; return 0; } /* Add to the hist of all output images. */ static int add_hist(im_function *fn, im_object *vargv, int argc, char **argv) { int i; int vargc = fn->argc; /* Search for output images. */ for (i = 0; i < vargc; i++) if (strcmp(fn->argv[i].desc->type, IM_TYPE_IMAGE) == 0 && (fn->argv[i].desc->flags & IM_TYPE_OUTPUT)) if (im_updatehist(vargv[i], fn->name, argc, argv)) return -1; return 0; } /* Call a VIPS function. */ static int dispatch_function(im_function *fn, im_object *vargv, int argc, char **argv) { /* Init memory from command line arguments. */ if (build_args(fn, vargv, argc, argv)) return -1; /* If this is a PIO function, we need to make sure that we close * the input images after the output images, since the output image * may include delayed image conversion filters which will not run * until the output is closed. * * Do this by: * - for each output image * - for each input image * - create a region on the input, closed by a * close callback on the output image */ if (fn->flags & IM_FN_PIO) { int i; for (i = 0; i < fn->argc; i++) { im_type_desc *type = fn->argv[i].desc; if (type->flags & IM_TYPE_OUTPUT && strcmp(type->type, IM_TYPE_IMAGE) == 0) if (note_dependencies(fn, vargv, i)) return -1; } } /* Call function. */ if (fn->disp(vargv)) return -1; /* Print output. */ if (print_args(fn, vargv)) return -1; /* Add to history of all output images. */ if (add_hist(fn, vargv, argc, argv)) return -1; /* All ok! */ return 0; } /* Run a command. */ int im_run_command(char *name, int argc, char **argv) { static im_object object_array[IM_MAX_ARGS]; im_object *vargv = object_array; im_function *fn; /* Search packages for a matching function. */ if (!(fn = im_find_function(name))) return -1; /* Allocate space for arguments. */ if (im_allocate_vargv(fn, vargv)) return -1; /* Call it. */ if (dispatch_function(fn, vargv, argc, argv)) { destroy_args(fn, vargv); im_free_vargv(fn, vargv); return -1; } /* Clean up and exit. */ if (destroy_args(fn, vargv)) return -1; im_free_vargv(fn, vargv); return 0; } libvips-8.18.2/libvips/deprecated/radiance.c000066400000000000000000000040561516303661500207570ustar00rootroot00000000000000/* Read Radiance (.hdr) files * * 20/12/11 * - just a compat stub */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include int im_rad2vips(const char *filename, IMAGE *out) { VipsImage *t; if (vips_radload(filename, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int israd(const char *filename) { return vips_foreign_is_a("radload", filename); } int im_vips2rad(IMAGE *in, const char *filename) { return vips_radsave(in, filename, NULL); } static const char *rad_suffs[] = { ".hdr", NULL }; typedef VipsFormat VipsFormatRad; typedef VipsFormatClass VipsFormatRadClass; static void vips_format_rad_class_init(VipsFormatRadClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsFormatClass *format_class = (VipsFormatClass *) class; object_class->nickname = "rad"; object_class->description = _("Radiance"); format_class->is_a = israd; format_class->load = im_rad2vips; format_class->save = im_vips2rad; format_class->suffs = rad_suffs; } static void vips_format_rad_init(VipsFormatRad *object) { } G_DEFINE_TYPE(VipsFormatRad, vips_format_rad, VIPS_TYPE_FORMAT); libvips-8.18.2/libvips/deprecated/raw.c000066400000000000000000000026661516303661500200070ustar00rootroot00000000000000/* Read raw image. Just a wrapper over im_binfile(). * * 15/12/11 * - just a compat stub now */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include int im_raw2vips(const char *filename, IMAGE *out, int width, int height, int bpp, int offset) { VipsImage *t; if (vips_rawload(filename, &t, width, height, bpp, "offset", offset, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_vips2raw(IMAGE *in, int fd) { return vips_rawsave_fd(in, fd, NULL); } libvips-8.18.2/libvips/deprecated/rename.c000066400000000000000000000417331516303661500204630ustar00rootroot00000000000000/* rename.c -- wrappers for various renamed functions * * 20/9/09 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include int im_remainderconst_vec(IMAGE *in, IMAGE *out, int n, double *c) { return im_remainder_vec(in, out, n, c); } int im_and_vec(IMAGE *in, IMAGE *out, int n, double *c) { return im_andimage_vec(in, out, n, c); } int im_or_vec(IMAGE *in, IMAGE *out, int n, double *c) { return im_orimage_vec(in, out, n, c); } int im_eor_vec(IMAGE *in, IMAGE *out, int n, double *c) { return im_eorimage_vec(in, out, n, c); } int im_andconst(IMAGE *in, IMAGE *out, double c) { return im_andimageconst(in, out, c); } int im_orconst(IMAGE *in, IMAGE *out, double c) { return im_orimageconst(in, out, c); } int im_eorconst(IMAGE *in, IMAGE *out, double c) { return im_eorimageconst(in, out, c); } void im_errormsg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); im_verror("untranslated", fmt, ap); va_end(ap); } void im_verrormsg(const char *fmt, va_list ap) { im_verror("untranslated", fmt, ap); } void im_errormsg_system(int err, const char *fmt, ...) { va_list ap; va_start(ap, fmt); im_verror_system(err, "untranslated", fmt, ap); va_end(ap); } void im_diagnostics(const char *fmt, ...) { va_list ap; va_start(ap, fmt); im_vdiag("untranslated", fmt, ap); va_end(ap); } void im_warning(const char *fmt, ...) { va_list ap; va_start(ap, fmt); im_vwarn("untranslated", fmt, ap); va_end(ap); } GMutex * vips_g_mutex_new(void) { GMutex *mutex; mutex = g_new(GMutex, 1); g_mutex_init(mutex); return mutex; } void vips_g_mutex_free(GMutex *mutex) { g_mutex_clear(mutex); g_free(mutex); } GCond * vips_g_cond_new(void) { GCond *cond; cond = g_new(GCond, 1); g_cond_init(cond); return cond; } void vips_g_cond_free(GCond *cond) { g_cond_clear(cond); g_free(cond); } void * vips_g_thread_join(GThread *thread) { return g_thread_join(thread); } int im_affine(IMAGE *in, IMAGE *out, double a, double b, double c, double d, double dx, double dy, int ox, int oy, int ow, int oh) { return im_affinei(in, out, vips_interpolate_bilinear_static(), a, b, c, d, dx, dy, ox, oy, ow, oh); } int im_similarity_area(IMAGE *in, IMAGE *out, double a, double b, double dx, double dy, int ox, int oy, int ow, int oh) { return im_affinei(in, out, vips_interpolate_bilinear_static(), a, -b, b, a, dx, dy, ox, oy, ow, oh); } int im_similarity(IMAGE *in, IMAGE *out, double a, double b, double dx, double dy) { return im_affinei_all(in, out, vips_interpolate_bilinear_static(), a, -b, b, a, dx, dy); } DOUBLEMASK * im_measure(IMAGE *im, IMAGE_BOX *box, int h, int v, int *sel, int nsel, const char *name) { return im_measure_area(im, box->xstart, box->ystart, box->xsize, box->ysize, h, v, sel, nsel, name); } int im_extract(IMAGE *in, IMAGE *out, IMAGE_BOX *box) { if (box->chsel == -1) return im_extract_areabands(in, out, box->xstart, box->ystart, box->xsize, box->ysize, 0, in->Bands); else return im_extract_areabands(in, out, box->xstart, box->ystart, box->xsize, box->ysize, box->chsel, 1); } /* The public proto has this in the argument. */ typedef void (*notify_fn)(IMAGE *, Rect *, void *); int im_render_fade(IMAGE *in, IMAGE *out, IMAGE *mask, int width, int height, int max, int fps, int steps, int priority, notify_fn notify, void *client) { return im_render_priority(in, out, mask, width, height, max, priority, notify, client); } int im_render(IMAGE *in, IMAGE *out, IMAGE *mask, int width, int height, int max, notify_fn notify, void *client) { return im_render_priority( in, out, mask, width, height, max, 0, notify, client); } int im_makerw(IMAGE *im) { return im_rwcheck(im); } int im_icc_export(IMAGE *in, IMAGE *out, const char *output_profile_filename, int intent) { return im_icc_export_depth(in, out, 8, output_profile_filename, (VipsIntent) intent); } int im_segment(IMAGE *test, IMAGE *mask, int *segments) { return im_label_regions(test, mask, segments); } int im_convf(IMAGE *in, IMAGE *out, DOUBLEMASK *mask) { return im_conv_f(in, out, mask); } int im_convf_raw(IMAGE *in, IMAGE *out, DOUBLEMASK *mask) { return im_conv_f_raw(in, out, mask); } int im_convsepf(IMAGE *in, IMAGE *out, DOUBLEMASK *mask) { return im_convsep_f(in, out, mask); } int im_convsepf_raw(IMAGE *in, IMAGE *out, DOUBLEMASK *mask) { return im_convsep_f_raw(in, out, mask); } gboolean im_isint(IMAGE *im) { return vips_bandfmt_isint(im->BandFmt); } gboolean im_isuint(IMAGE *im) { return vips_bandfmt_isuint(im->BandFmt); } gboolean im_isfloat(IMAGE *im) { return vips_bandfmt_isfloat(im->BandFmt); } gboolean im_iscomplex(IMAGE *im) { return vips_band_format_iscomplex(im->BandFmt); } gboolean im_isscalar(IMAGE *im) { return !im_iscomplex(im); } int im_c2ps(IMAGE *in, IMAGE *out) { return im_abs(in, out); } int im_clip(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_UCHAR); } int im_clip2c(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_CHAR); } int im_clip2us(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_USHORT); } int im_clip2s(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_SHORT); } int im_clip2ui(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_UINT); } int im_clip2i(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_INT); } int im_clip2f(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_FLOAT); } int im_clip2d(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_DOUBLE); } int im_clip2cm(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_COMPLEX); } int im_clip2dcm(IMAGE *in, IMAGE *out) { return im_clip2fmt(in, out, IM_BANDFMT_DPCOMPLEX); } int im_copy_from(IMAGE *in, IMAGE *out, im_arch_type architecture) { switch (architecture) { case IM_ARCH_NATIVE: return im_copy(in, out); case IM_ARCH_BYTE_SWAPPED: return im_copy_swap(in, out); case IM_ARCH_LSB_FIRST: return im_amiMSBfirst() ? im_copy_swap(in, out) : im_copy(in, out); case IM_ARCH_MSB_FIRST: return im_amiMSBfirst() ? im_copy(in, out) : im_copy_swap(in, out); default: im_error("im_copy_from", _("bad architecture: %d"), architecture); return -1; } } /* Check whether arch corresponds to native byte order. */ gboolean im_isnative(im_arch_type arch) { switch (arch) { case IM_ARCH_NATIVE: return TRUE; case IM_ARCH_BYTE_SWAPPED: return FALSE; case IM_ARCH_LSB_FIRST: return !im_amiMSBfirst(); case IM_ARCH_MSB_FIRST: return im_amiMSBfirst(); default: g_assert(0); } /* Keep -Wall happy. */ return -1; } int im_iterate(IMAGE *im, im_start_fn start, im_generate_fn generate, im_stop_fn stop, void *b, void *c) { return vips_sink(im, start, (VipsGenerateFn) generate, stop, b, c); } int im_render_priority(IMAGE *in, IMAGE *out, IMAGE *mask, int width, int height, int max, int priority, notify_fn notify, void *client) { return vips_sink_screen(in, out, mask, width, height, max, priority, notify, client); } int vips_rawsave_fd(VipsImage *in, int fd, ...) { va_list ap; int result; VipsTarget *target; if (!(target = vips_target_new_to_descriptor(fd))) return -1; va_start(ap, fd); result = vips_call_split("rawsave_target", ap, in, target); va_end(ap); return result; } /** * im_circle: * @im: image to draw on * @cx: centre of circle * @cy: centre of circle * @radius: circle radius * @intensity: value to draw * * Draws a circle on a 1-band 8-bit image. * * This an inplace operation, so @im is changed. It does not thread and will * not work well as part of a pipeline. On 32-bit machines it will be limited * to 2GB images. * * See also: im_fastline(). * * Returns: 0 on success, or -1 on error. */ int im_circle(IMAGE *im, int cx, int cy, int radius, int intensity) { PEL ink[1]; if (im_rwcheck(im) || im_check_uncoded("im_circle", im) || im_check_mono("im_circle", im) || im_check_format("im_circle", im, IM_BANDFMT_UCHAR)) return -1; ink[0] = intensity; return im_draw_circle(im, cx, cy, radius, FALSE, ink); } /* A flood blob we can call from nip. Grr! Should be a way to wrap these * automatically. Maybe nip could do it if it sees a RW image argument? */ int im_flood_copy(IMAGE *in, IMAGE *out, int x, int y, PEL *ink) { IMAGE *t; if (!(t = im_open_local(out, "im_flood_blob_copy", "t")) || im_copy(in, t) || im_flood(t, x, y, ink, NULL) || im_copy(t, out)) return -1; return 0; } int im_flood_blob_copy(IMAGE *in, IMAGE *out, int x, int y, PEL *ink) { IMAGE *t; if (!(t = im_open_local(out, "im_flood_blob_copy", "t")) || im_copy(in, t) || im_flood_blob(t, x, y, ink, NULL) || im_copy(t, out)) return -1; return 0; } int im_flood_other_copy(IMAGE *test, IMAGE *mark, IMAGE *out, int x, int y, int serial) { IMAGE *t; if (!(t = im_open_local(out, "im_flood_other_copy", "t")) || im_copy(mark, t) || im_flood_other(test, t, x, y, serial, NULL) || im_copy(t, out)) return -1; return 0; } int im_paintrect(IMAGE *im, Rect *r, PEL *ink) { return im_draw_rect(im, r->left, r->top, r->width, r->height, 1, ink); } int im_insertplace(IMAGE *main, IMAGE *sub, int x, int y) { return im_draw_image(main, sub, x, y); } int im_fastline(IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel) { return im_draw_line(im, x1, y1, x2, y2, pel); } int im_fastlineuser(IMAGE *im, int x1, int y1, int x2, int y2, VipsPlotFn fn, void *client1, void *client2, void *client3) { return im_draw_line_user(im, x1, y1, x2, y2, fn, client1, client2, client3); } int im_plotmask(IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, Rect *r) { IMAGE *mask_im; if (!(mask_im = im_image(mask, r->width, r->height, 1, IM_BANDFMT_UCHAR))) return -1; if (im_draw_mask(im, mask_im, ix + r->left, iy + r->top, ink)) { im_close(mask_im); return -1; } im_close(mask_im); return 0; } int im_readpoint(IMAGE *im, int x, int y, PEL *pel) { return im_read_point(im, x, y, pel); } int im_plotpoint(IMAGE *im, int x, int y, PEL *pel) { return im_draw_point(im, x, y, pel); } /* Smear a section of an IMAGE. As above, but shift it left a bit. */ int im_smear(IMAGE *im, int ix, int iy, Rect *r) { int x, y, a, b, c; int ba = im->Bands; int el = ba * im->Xsize; Rect area, image, clipped; double total[256]; if (im_rwcheck(im)) return -1; /* Don't do the margins. */ area = *r; area.left += ix; area.top += iy; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_marginadjust(&image, -1); image.left--; im_rect_intersectrect(&area, &image, &clipped); /* Any left? */ if (im_rect_isempty(&clipped)) return 0; /* What we do for each type. */ #define SMEAR(TYPE) \ for (y = clipped.top; y < clipped.top + clipped.height; y++) \ for (x = clipped.left; \ x < clipped.left + clipped.width; x++) { \ TYPE *to = (TYPE *) im->data + x * ba + y * el; \ TYPE *from = to - el; \ TYPE *f; \ \ for (a = 0; a < ba; a++) \ total[a] = 0.0; \ \ for (a = 0; a < 3; a++) { \ f = from; \ for (b = 0; b < 3; b++) \ for (c = 0; c < ba; c++) \ total[c] += *f++; \ from += el; \ } \ \ for (a = 0; a < ba; a++) \ to[a] = (40 * (double) to[a + ba] + total[a]) / 49.0; \ } /* Loop through the remaining pixels. */ switch (im->BandFmt) { case IM_BANDFMT_UCHAR: SMEAR(unsigned char); break; case IM_BANDFMT_CHAR: SMEAR(char); break; case IM_BANDFMT_USHORT: SMEAR(unsigned short); break; case IM_BANDFMT_SHORT: SMEAR(short); break; case IM_BANDFMT_UINT: SMEAR(unsigned int); break; case IM_BANDFMT_INT: SMEAR(int); break; case IM_BANDFMT_FLOAT: SMEAR(float); break; case IM_BANDFMT_DOUBLE: SMEAR(double); break; /* Do complex types too. Just treat as float and double, but with * twice the number of bands. */ case IM_BANDFMT_COMPLEX: /* Twice number of bands: double size and bands. */ ba *= 2; el *= 2; SMEAR(float); break; case IM_BANDFMT_DPCOMPLEX: /* Twice number of bands: double size and bands. */ ba *= 2; el *= 2; SMEAR(double); break; default: im_error("im_smear", "%s", _("unknown band format")); return -1; } return 0; } int im_smudge(VipsImage *image, int ix, int iy, Rect *r) { return im_draw_smudge(image, r->left + ix, r->top + iy, r->width, r->height); } int im_flood(IMAGE *im, int x, int y, PEL *ink, Rect *dout) { return im_draw_flood(im, x, y, ink, dout); } int im_flood_blob(IMAGE *im, int x, int y, PEL *ink, Rect *dout) { return im_draw_flood_blob(im, x, y, ink, dout); } int im_flood_other(IMAGE *test, IMAGE *mark, int x, int y, int serial, Rect *dout) { return im_draw_flood_other(mark, test, x, y, serial, dout); } int vips_check_coding_rad(const char *domain, VipsImage *im) { return vips_check_coding(domain, im, VIPS_CODING_RAD); } int vips_check_coding_labq(const char *domain, VipsImage *im) { return vips_check_coding(domain, im, VIPS_CODING_LABQ); } int vips_check_bands_3ormore(const char *domain, VipsImage *im) { return vips_check_bands_atleast(domain, im, 3); } /* The old vips_info() stuff, now replaced by g_warning() / g_info(). */ int vips__info = 0; void vips_info_set(gboolean info) { vips__info = info; if (info) { const char *old; char *new; old = g_getenv("G_MESSAGES_DEBUG"); if (!old) old = ""; new = g_strdup_printf("%s VIPS", old); g_setenv("G_MESSAGES_DEBUG", new, TRUE); g_free(new); } } void vips_vinfo(const char *domain, const char *fmt, va_list ap) { if (vips__info) { g_mutex_lock(&vips__global_lock); (void) fprintf(stderr, _("%s: "), _("info")); if (domain) (void) fprintf(stderr, _("%s: "), domain); (void) vfprintf(stderr, fmt, ap); (void) fprintf(stderr, "\n"); g_mutex_unlock(&vips__global_lock); } } void vips_info(const char *domain, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vips_vinfo(domain, fmt, ap); va_end(ap); } void vips_vwarn(const char *domain, const char *fmt, va_list ap) { if (!g_getenv("IM_WARNING") && !g_getenv("VIPS_WARNING")) { g_mutex_lock(&vips__global_lock); (void) fprintf(stderr, _("%s: "), _("vips warning")); if (domain) (void) fprintf(stderr, _("%s: "), domain); (void) vfprintf(stderr, fmt, ap); (void) fprintf(stderr, "\n"); g_mutex_unlock(&vips__global_lock); } if (vips__fatal) vips_error_exit("vips__fatal"); } void vips_warn(const char *domain, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vips_vwarn(domain, fmt, ap); va_end(ap); } /** * vips_autorot_get_angle: * @image: image to fetch orientation from * * This function is deprecated. Use vips_autorot() instead. */ VipsAngle vips_autorot_get_angle(VipsImage *im) { return VIPS_ANGLE_D0; } /* The old vips_free(), now replaced by g_free() and vips_area_free_cb(). */ int vips_free(void *buf) { g_free(buf); return 0; } /* Use vips_thread_isvips() instead. */ gboolean vips_thread_isworker(void) { return vips_thread_isvips(); } /** * vips_cache_operation_add: (skip) * * No longer in the public API. */ void vips_cache_operation_add(VipsOperation *operation) { } /** * vips_cache_operation_lookup: (skip) * * No longer in the public API. */ VipsOperation * vips_cache_operation_lookup(VipsOperation *operation) { return NULL; } /** * vips_target_finish: * @target: target to operate on * @buffer: bytes to write * @length: length of @buffer in bytes * * Deprecated in favour of vips_target_end(). */ void vips_target_finish(VipsTarget *target) { (void) vips_target_end(target); } /* Use g_strlcpy() instead. */ char * vips_strncpy(char *dest, const char *src, int n) { (void) g_strlcpy(dest, src, n); return dest; } /* Use g_strrstr() instead. */ char * vips_strrstr(const char *haystack, const char *needle) { return g_strrstr(haystack, needle); } /* Use g_str_has_suffix() instead. */ gboolean vips_ispostfix(const char *a, const char *b) { return g_str_has_suffix(a, b); } /* Use g_vsnprintf() instead. */ int vips_vsnprintf(char *str, size_t size, const char *format, va_list ap) { return g_vsnprintf(str, size, format, ap); } /* Use g_snprintf() instead. */ int vips_snprintf(char *str, size_t size, const char *format, ...) { va_list ap; int n; va_start(ap, format); n = g_vsnprintf(str, size, format, ap); va_end(ap); return n; } libvips-8.18.2/libvips/deprecated/resample_dispatch.c000066400000000000000000000134561516303661500227040ustar00rootroot00000000000000/* Function dispatch tables for mosaicing. * * J. Cupitt, 23/2/95 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* Args to im_rightshift_size. */ static im_arg_desc rightshift_size_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("xshift"), IM_INPUT_INT("yshift"), IM_INPUT_INT("band_fmt") }; /* Call im_rightshift_size via arg vector. */ static int rightshift_size_vec(im_object *argv) { IMAGE *in = (IMAGE *) argv[0]; IMAGE *out = (IMAGE *) argv[1]; int *xshift = (int *) argv[2]; int *yshift = (int *) argv[3]; int *band_fmt = (int *) argv[4]; return im_rightshift_size(in, out, *xshift, *yshift, *band_fmt); } /* Description of im_rightshift_size. */ static im_function rightshift_size_desc = { "im_rightshift_size", /* Name */ "decrease size by a power-of-two factor", IM_FN_PIO | IM_FN_TRANSFORM, /* Flags */ rightshift_size_vec, /* Dispatch function */ IM_NUMBER(rightshift_size_args), /* Size of arg list */ rightshift_size_args /* Arg list */ }; /* affinei args */ static im_arg_desc affinei_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INTERPOLATE("interpolate"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("c"), IM_INPUT_DOUBLE("d"), IM_INPUT_DOUBLE("dx"), IM_INPUT_DOUBLE("dy"), IM_INPUT_INT("x"), IM_INPUT_INT("y"), IM_INPUT_INT("w"), IM_INPUT_INT("h") }; /* Call im_affinei via arg vector. */ static int affinei_vec(im_object *argv) { VipsInterpolate *interpolate = VIPS_INTERPOLATE(argv[2]); double a = *((double *) argv[3]); double b = *((double *) argv[4]); double c = *((double *) argv[5]); double d = *((double *) argv[6]); double dx = *((double *) argv[7]); double dy = *((double *) argv[8]); int x = *((int *) argv[9]); int y = *((int *) argv[10]); int w = *((int *) argv[11]); int h = *((int *) argv[12]); return im_affinei(argv[0], argv[1], interpolate, a, b, c, d, dx, dy, x, y, w, h); } /* Description of im_affinei. */ static im_function affinei_desc = { "im_affinei", /* Name */ "affine transform", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ affinei_vec, /* Dispatch function */ IM_NUMBER(affinei_args), /* Size of arg list */ affinei_args /* Arg list */ }; /* affinei_all args */ static im_arg_desc affinei_all_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_INTERPOLATE("interpolate"), IM_INPUT_DOUBLE("a"), IM_INPUT_DOUBLE("b"), IM_INPUT_DOUBLE("c"), IM_INPUT_DOUBLE("d"), IM_INPUT_DOUBLE("dx"), IM_INPUT_DOUBLE("dy") }; /* Call im_affinei_all via arg vector. */ static int affinei_all_vec(im_object *argv) { VipsInterpolate *interpolate = VIPS_INTERPOLATE(argv[2]); double a = *((double *) argv[3]); double b = *((double *) argv[4]); double c = *((double *) argv[5]); double d = *((double *) argv[6]); double dx = *((double *) argv[7]); double dy = *((double *) argv[8]); return im_affinei_all(argv[0], argv[1], interpolate, a, b, c, d, dx, dy); } /* Description of im_affinei_all. */ static im_function affinei_all_desc = { "im_affinei_all", /* Name */ "affine transform of whole image", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ affinei_all_vec, /* Dispatch function */ IM_NUMBER(affinei_all_args), /* Size of arg list */ affinei_all_args /* Arg list */ }; /* Args for im_shrink. */ static im_arg_desc shrink_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("xfac"), IM_INPUT_DOUBLE("yfac") }; /* Call im_shrink via arg vector. */ static int shrink_vec(im_object *argv) { double xshrink = *((double *) argv[2]); double yshrink = *((double *) argv[3]); return im_shrink(argv[0], argv[1], xshrink, yshrink); } /* Description of im_shrink. */ static im_function shrink_desc = { "im_shrink", /* Name */ "shrink image by xfac, yfac times", IM_FN_TRANSFORM | IM_FN_PIO, /* Flags */ shrink_vec, /* Dispatch function */ IM_NUMBER(shrink_args), /* Size of arg list */ shrink_args /* Arg list */ }; /* Args to im_stretch3. */ static im_arg_desc stretch3_args[] = { IM_INPUT_IMAGE("in"), IM_OUTPUT_IMAGE("out"), IM_INPUT_DOUBLE("xdisp"), IM_INPUT_DOUBLE("ydisp") }; /* Call im_stretch3 via arg vector. */ static int stretch3_vec(im_object *argv) { double xdisp = *((int *) argv[2]); double ydisp = *((int *) argv[3]); return im_stretch3(argv[0], argv[1], xdisp, ydisp); } /* Description of im_stretch3. */ static im_function stretch3_desc = { "im_stretch3", /* Name */ "stretch 3%, sub-pixel displace by xdisp/ydisp", IM_FN_PIO, /* Flags */ stretch3_vec, /* Dispatch function */ IM_NUMBER(stretch3_args), /* Size of arg list */ stretch3_args /* Arg list */ }; /* Package up all these functions. */ static im_function *resample_list[] = { &rightshift_size_desc, &shrink_desc, &stretch3_desc, &affinei_desc, &affinei_all_desc }; /* Package of functions. */ im_package im__resample = { "resample", IM_NUMBER(resample_list), resample_list }; libvips-8.18.2/libvips/deprecated/rotmask.c000066400000000000000000000063571516303661500206770ustar00rootroot00000000000000/* Functions to create offsets for rotating square masks. * * Author: N. Dessipris (Copyright, N. Dessipris 1991) * Written on: 08/05/1991 * Modified on: 28/05/1991 * 12/10/95 JC * - small revisions, needs rewriting really * 7/8/96 JC * - absolutely foul desp code revised * - many bugs and mem leaks fixed * 1/3/99 JC * - oops, fns were not preserving scale and offset * 1/12/10 * - allow any size mask for the 90 degree rotates by using im_rot90(). */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define PIM_RINT 1 */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* The type of the vips operations we support. */ typedef int (*vips_fn)(IMAGE *in, IMAGE *out); /* Pass a mask through a vips operation, eg. im_rot90(). */ static INTMASK * vapplyimask(INTMASK *in, const char *name, vips_fn fn) { IMAGE *x; IMAGE *t[2]; DOUBLEMASK *d[2]; INTMASK *out; if (!(x = im_open(name, "p"))) return NULL; if (!(d[0] = im_local_dmask(x, im_imask2dmask(in, name))) || im_open_local_array(x, t, 2, name, "p") || im_mask2vips(d[0], t[0]) || fn(t[0], t[1]) || !(d[1] = im_local_dmask(x, im_vips2mask(t[1], name))) || !(out = im_dmask2imask(d[1], name))) { im_close(x); return NULL; } im_close(x); out->scale = in->scale; out->offset = in->offset; return out; } static DOUBLEMASK * vapplydmask(DOUBLEMASK *in, const char *name, vips_fn fn) { IMAGE *x; IMAGE *t[2]; DOUBLEMASK *out; if (!(x = im_open(name, "p"))) return NULL; if (im_open_local_array(x, t, 2, name, "p") || im_mask2vips(in, t[0]) || fn(t[0], t[1]) || !(out = im_vips2mask(t[1], name))) { im_close(x); return NULL; } im_close(x); out->scale = in->scale; out->offset = in->offset; return out; } INTMASK * im_rotate_imask90(INTMASK *in, const char *filename) { return vapplyimask(in, filename, im_rot90); } DOUBLEMASK * im_rotate_dmask90(DOUBLEMASK *in, const char *filename) { return vapplydmask(in, filename, im_rot90); } static int im_rot45(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_rot45(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } INTMASK * im_rotate_imask45(INTMASK *in, const char *filename) { return vapplyimask(in, filename, im_rot45); } DOUBLEMASK * im_rotate_dmask45(DOUBLEMASK *in, const char *filename) { return vapplydmask(in, filename, im_rot45); } libvips-8.18.2/libvips/deprecated/rw_mask.c000066400000000000000000000544771516303661500206700ustar00rootroot00000000000000/* read and write masks */ /* Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 29/04/1991 * Modified on: 10/8/1992, J.Cupitt * - Mask reading routines no longer fail if scale and offset are missing. * Instead, they set default values of scale=1, offset=0. * - Code tidied up, better error recovery. * - Bugs fixed in im_dup_*mask. No longer coredump. * - Bugs fixed in im_write_*mask. Now work for non-square matrices. * - im_copy_*mask_matrix, im_copy_matrix_*mask added: copy VIPS mask * structures into Numerical Recipies in C style matrices and vice * versa. Both structures should have been built before copy attempted. * See im_create_*mask, im_*mat_alloc. The matrix should be indexed by 0 * to size-1. * 9/7/93 JC * - some ANSIfication and tidies * - im_free_*mask() now return zero, so they can be used as close * callbacks. * 7/10/94 JC * - new IM_NEW(), IM_ARRAY() macros added * 27/4/95 JC * - oops! forgot to init IM_ARRAY() memory to zero * 7/8/96 JC * - im_scale_dmask() rewritten * 7/5/98 JC * - im_read_*mask() rewritten, now more robust * - im_write_*mask() rewritten * - new functions im_write_*mask_name() * 28/7/99 JC * - im_create_imaskv(), im_create_dmaskv() make masks and init from * varargs * - tabs allowed as column separators * 9/2/05 * - "," allowed as column separator ... helps CSV read * 31/5/06 * - use g_ascii_strtod() and friends * 2006-09-08 tcv * - add im_norm_dmask() * 1/9/09 * - move im_print_*mask() here * 12/11/09 * - reading a float mask with im_read_imask() produced an incorrect * error messagge * 21/10/10 * - gtk-doc * - you can use commas to separate header fields * - small cleanups * 30/11/10 * - im_scale_dmask() normalises to 20, not 100 ... we hit the fast * conv path more often * 24/1/10 * - oops, missing braces in write dmask removed spaces between items */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include /** * INTMASK: * @xsize: mask width * @ysize: mask height * @scale: mask scale factor * @offset: mask offset * @coeff: array of mask elements * @filename: the file this mask was read from, or should be written to * * An integer mask. * * @scale lets the mask represent fractional values: for * example, in integer convolution (see im_conv()) the result of the * convolution is divided by @scale and then added to @offset before being * written to the output image. * * @scale and @offset default to 1 and 0. Various functions, such as * im_conv(), will fail if @scale is zero. * * You can read and write the matrix elements in @coeff. */ /** * DOUBLEMASK: * @xsize: mask width * @ysize: mask height * @scale: mask scale factor * @offset: mask offset * @coeff: array of mask elements * @filename: the file this mask was read from, or should be written to * * A floating-point mask. * * As with #INTMASK, in convolution (see im_convf()) the result of the * convolution is divided by @scale and then added to @offset before being * written to the output image. * * @scale and @offset default to 1.0 and 0.0. Various functions, such as * im_conv(), will fail if @scale is zero. * * You can read and write the matrix elements in @coeff. */ /* Size of line buffer for reading. */ #define MAX_LINE (32768) /** * im_free_imask: * @in: mask to free * * Free mask structure and any attached arrays. Return zero, so we can use * these functions as close callbacks. * * See also: im_free_dmask(). * * Returns: zero. */ int im_free_imask(INTMASK *in) { if (!in) return 0; IM_FREE(in->coeff); IM_FREE(in->filename); IM_FREE(in); return 0; } /** * im_free_dmask: * @in: mask to free * * Free mask structure and any attached arrays. Return zero, so we can use * these functions as close callbacks. * * See also: im_free_dmask(). * * Returns: zero. */ int im_free_dmask(DOUBLEMASK *in) { if (!in) return 0; IM_FREE(in->coeff); IM_FREE(in->filename); IM_FREE(in); return 0; } /** * im_create_imask: * @filename: set mask filename to this * @xsize: mask width * @ysize: mask height * * Create an empty imask. You need to loop over @coeff to set the values. * * See also: im_create_imaskv(). * * Returns: The newly-allocated mask. */ INTMASK * im_create_imask(const char *filename, int xsize, int ysize) { INTMASK *out; int size = xsize * ysize; /* Check args. */ if (xsize <= 0 || ysize <= 0 || filename == NULL) { im_error("im_create_imask", "%s", _("bad arguments")); return NULL; } /* Allocate and initialise structure. */ if (!(out = IM_NEW(NULL, INTMASK))) return NULL; out->coeff = NULL; out->filename = NULL; out->scale = 1; out->offset = 0; out->xsize = 0; out->ysize = 0; if (!(out->coeff = IM_ARRAY(NULL, size, int))) { im_free_imask(out); return NULL; } (void) memset((char *) out->coeff, 0, size * sizeof(int)); if (!(out->filename = im_strdup(NULL, filename))) { im_free_imask(out); return NULL; } out->xsize = xsize; out->ysize = ysize; return out; } /** * im_create_imaskv: * @filename: set mask filename to this * @xsize: mask width * @ysize: mask height * @...: values to set for the mask * * Create an imask and initialise it from the function parameter list. * * See also: im_create_imask(). * * Returns: The newly-allocated mask. */ INTMASK * im_create_imaskv(const char *filename, int xsize, int ysize, ...) { va_list ap; INTMASK *out; int i; if (!(out = im_create_imask(filename, xsize, ysize))) return NULL; va_start(ap, ysize); for (i = 0; i < xsize * ysize; i++) out->coeff[i] = va_arg(ap, int); va_end(ap); return out; } /** * im_create_dmask: * @filename: set mask filename to this * @xsize: mask width * @ysize: mask height * * Create an empty dmask. You need to loop over @coeff to set the values. * * See also: im_create_dmaskv(), im_vips2mask(). * * Returns: The newly-allocated mask. */ DOUBLEMASK * im_create_dmask(const char *filename, int xsize, int ysize) { DOUBLEMASK *out; int size = xsize * ysize; /* Check args. */ if (xsize <= 0 || ysize <= 0 || filename == NULL) { im_error("im_create_dmask", "%s", _("bad arguments")); return NULL; } /* Allocate and initialise structure. */ if (!(out = IM_NEW(NULL, DOUBLEMASK))) return NULL; out->coeff = NULL; out->filename = NULL; out->scale = 1.0; out->offset = 0.0; out->xsize = 0; out->ysize = 0; if (!(out->coeff = IM_ARRAY(NULL, size, double))) { im_free_dmask(out); return NULL; } (void) memset((char *) out->coeff, 0, size * sizeof(double)); if (!(out->filename = im_strdup(NULL, filename))) { im_free_dmask(out); return NULL; } out->xsize = xsize; out->ysize = ysize; return out; } /** * im_create_dmaskv: * @filename: set mask filename to this * @xsize: mask width * @ysize: mask height * @...: values to set for the mask * * Create a dmask and initialise it from the function parameter list. * * See also: im_create_dmask(). * * Returns: The newly-allocated mask. */ DOUBLEMASK * im_create_dmaskv(const char *filename, int xsize, int ysize, ...) { va_list ap; DOUBLEMASK *out; int i; if (!(out = im_create_dmask(filename, xsize, ysize))) return NULL; va_start(ap, ysize); for (i = 0; i < xsize * ysize; i++) out->coeff[i] = va_arg(ap, double); va_end(ap); return out; } /* Read a line from a file! */ static int get_line(FILE *fp, char *buf) { if (!fgets(buf, MAX_LINE, fp)) { im_error("read_mask", "%s", _("unexpected EOF")); return -1; } return 0; } /* width, height, optional scale, optional offset. */ static int read_header(FILE *fp, int *xs, int *ys, double *scale, double *offset) { char buf[MAX_LINE]; char *p, *q; double v[4]; int i; /* Read the first line: should contain size and optional * scale + offset. */ if (get_line(fp, buf)) return -1; /* Read as space separated doubles. \n is in the break list because * our line will (usually) have a trailing \n which we want to count * as whitespace. */ p = buf; for (i = 0, p = buf; i < 4 && (q = im_break_token(p, " \";,\t\n")); i++, p = q) v[i] = g_ascii_strtod(p, NULL); if ((i != 2 && i != 4) || ceil(v[0]) != v[0] || ceil(v[1]) != v[1] || v[0] <= 0 || v[1] <= 0) { im_error("read_header", "%s", _("error reading matrix header")); return -1; } if (i == 4 && v[2] == 0) { im_error("read_header", "%s", _("scale should be non-zero")); return -1; } *xs = v[0]; *ys = v[1]; if (i == 2) { *scale = 1.0; *offset = 0.0; } else { *scale = v[2]; *offset = v[3]; } return 0; } /** * im_read_dmask: * @filename: read matrix from this file * * Reads a matrix from a file. * * Matrix files have a simple format that's supposed to be easy to create with * a text editor or a spreadsheet. * * The first line has four numbers for width, height, scale and * offset (scale and offset may be omitted, in which case they default to 1.0 * and 0.0). Scale must be non-zero. Width and height must be positive * integers. The numbers are separated by any mixture of spaces, commas, * tabs and quotation marks ("). The scale and offset fields may be * floating-point, and must use '.' * as a decimal separator. * * Subsequent lines each hold one line of matrix data, with numbers again * separated by any mixture of spaces, commas, * tabs and quotation marks ("). The numbers may be floating-point, and must * use '.' * as a decimal separator. * * Extra characters at the ends of lines or at the end of the file are * ignored. * * See also: im_read_imask(), im_gauss_dmask(). * * Returns: the loaded mask on success, or NULL on error. */ DOUBLEMASK * im_read_dmask(const char *filename) { FILE *fp; double sc, off; int xs, ys; DOUBLEMASK *out; int x, y, i; char buf[MAX_LINE]; if (!(fp = im__file_open_read(filename, NULL, TRUE))) return NULL; if (read_header(fp, &xs, &ys, &sc, &off)) { fclose(fp); return NULL; } if (!(out = im_create_dmask(filename, xs, ys))) { fclose(fp); return NULL; } out->scale = sc; out->offset = off; for (i = 0, y = 0; y < ys; y++) { char *p; if (get_line(fp, buf)) { im_free_dmask(out); fclose(fp); return NULL; } for (p = buf, x = 0; p && x < xs; x++, i++, p = im_break_token(p, " \t,\";")) out->coeff[i] = g_ascii_strtod(p, NULL); } fclose(fp); return out; } /** * im_read_imask: * @filename: read matrix from this file * * Reads an integer matrix from a file. * * This function works exactly as im_read_dmask(), but the loaded matrix is * checked for 'int-ness'. All coefficients must be integers, and scale and * offset must be integers. * * See also: im_read_dmask(). * * Returns: the loaded mask on success, or NULL on error. */ INTMASK * im_read_imask(const char *filename) { DOUBLEMASK *dmask; INTMASK *imask; int i; if (!(dmask = im_read_dmask(filename))) return NULL; if (ceil(dmask->scale) != dmask->scale || ceil(dmask->offset) != dmask->offset) { im_error("im_read_imask", "%s", _("scale and offset should be int")); im_free_dmask(dmask); return NULL; } for (i = 0; i < dmask->xsize * dmask->ysize; i++) if (ceil(dmask->coeff[i]) != dmask->coeff[i]) { im_error("im_read_imask", _("ceofficient at " "position (%d, %d) is not int"), i % dmask->xsize, i / dmask->xsize); im_free_dmask(dmask); return NULL; } if (!(imask = im_create_imask(filename, dmask->xsize, dmask->ysize))) { im_free_dmask(dmask); return NULL; } imask->scale = dmask->scale; imask->offset = dmask->offset; for (i = 0; i < dmask->xsize * dmask->ysize; i++) imask->coeff[i] = dmask->coeff[i]; im_free_dmask(dmask); return imask; } /** * im_scale_dmask: * @in: mask to scale * @filename: filename for returned mask * * Scale the dmask to make an imask with a maximum value of 20. * * See also: im_norm_dmask(). * * Returns: the converted mask, or NULL on error. */ INTMASK * im_scale_dmask(DOUBLEMASK *in, const char *filename) { const int size = in->xsize * in->ysize; INTMASK *out; double maxval, dsum; int i; int isum; if (im_check_dmask("im_scale_dmask", in) || !(out = im_create_imask(filename, in->xsize, in->ysize))) return NULL; /* Find mask max. */ maxval = in->coeff[0]; for (i = 0; i < size; i++) if (in->coeff[i] > maxval) maxval = in->coeff[i]; /* Copy and scale, setting max to 20. */ for (i = 0; i < size; i++) out->coeff[i] = IM_RINT(in->coeff[i] * 20.0 / maxval); out->offset = in->offset; /* Set the scale to match the adjustment to max. */ isum = 0; dsum = 0.0; for (i = 0; i < size; i++) { isum += out->coeff[i]; dsum += in->coeff[i]; } if (dsum == in->scale) out->scale = isum; else if (dsum == 0.0) out->scale = 1.0; else out->scale = IM_RINT(in->scale * isum / dsum); return out; } /** * im_dmask2imask: * @in: mask to convert * @filename: filename for returned mask * * Make an imask from the dmask, rounding to nearest. * * See also: im_scale_dmask(). * * Returns: the converted mask, or NULL on error. */ INTMASK * im_dmask2imask(DOUBLEMASK *in, const char *filename) { const int size = in->xsize * in->ysize; INTMASK *out; int i; if (im_check_dmask("im_dmask2imask", in) || !(out = im_create_imask(filename, in->xsize, in->ysize))) return NULL; for (i = 0; i < size; i++) out->coeff[i] = IM_RINT(in->coeff[i]); out->offset = IM_RINT(in->offset); out->scale = IM_RINT(in->scale); return out; } /** * im_imask2dmask: * @in: mask to convert * @filename: filename for returned mask * * Make a dmask from the imask. * * See also: im_dmask2imask(). * * Returns: the converted mask, or NULL on error. */ DOUBLEMASK * im_imask2dmask(INTMASK *in, const char *filename) { const int size = in->xsize * in->ysize; DOUBLEMASK *out; int i; if (im_check_imask("im_imask2dmask", in) || !(out = im_create_dmask(filename, in->xsize, in->ysize))) return NULL; for (i = 0; i < size; i++) out->coeff[i] = in->coeff[i]; out->offset = in->offset; out->scale = in->scale; return out; } /** * im_norm_dmask: * @mask: mask to scale * * Normalise the dmask. Apply the scale and offset to each element to make * a mask with scale 1, offset zero. * * See also: im_scale_dmask(). * * Returns: 0 on success, or -1 on error. */ void im_norm_dmask(DOUBLEMASK *mask) { const int n = mask->xsize * mask->ysize; const double scale = (mask->scale == 0) ? 0 : (1.0 / mask->scale); int i; if (im_check_dmask("im_norm_dmask", mask) || (1.0 == scale && 0.0 == mask->offset)) return; for (i = 0; i < n; i++) mask->coeff[i] = mask->coeff[i] * scale + mask->offset; mask->scale = 1.0; mask->offset = 0.0; } /** * im_dup_imask: * @in: mask to duplicate * @filename: filename to set for the new mask * * Duplicate an imask. * * See also: im_dup_dmask(). * * Returns: the mask copy, or NULL on error. */ INTMASK * im_dup_imask(INTMASK *in, const char *filename) { INTMASK *out; int i; if (im_check_imask("im_dup_imask", in) || !(out = im_create_imask(filename, in->xsize, in->ysize))) return NULL; out->offset = in->offset; out->scale = in->scale; for (i = 0; i < in->xsize * in->ysize; i++) out->coeff[i] = in->coeff[i]; return out; } /** * im_dup_dmask: * @in: mask to duplicate * @filename: filename to set for the new mask * * Duplicate a dmask. * * See also: im_dup_imask(). * * Returns: the mask copy, or NULL on error. */ DOUBLEMASK * im_dup_dmask(DOUBLEMASK *in, const char *filename) { DOUBLEMASK *out; int i; if (im_check_dmask("im_dup_dmask", in) || !(out = im_create_dmask(filename, in->xsize, in->ysize))) return NULL; out->offset = in->offset; out->scale = in->scale; for (i = 0; i < in->xsize * in->ysize; i++) out->coeff[i] = in->coeff[i]; return out; } /* Write to file. */ static int write_line(FILE *fp, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (!vfprintf(fp, fmt, ap)) { im_error("write_mask", "%s", _("write error, disc full?")); return -1; } va_end(ap); return 0; } static int write_double(FILE *fp, double d) { char buf[G_ASCII_DTOSTR_BUF_SIZE]; fprintf(fp, "%s", g_ascii_dtostr(buf, sizeof(buf), d)); return 0; } /** * im_write_imask_name: * @in: mask to write * @filename: filename to write to * * Write an imask to a file. See im_read_dmask() for a description of the mask * file format. * * See also: im_write_imask(). * * Returns: 0 on success, or -1 on error. */ int im_write_imask_name(INTMASK *in, const char *filename) { FILE *fp; int x, y, i; if (im_check_imask("im_write_imask_name", in) || !(fp = im__file_open_write(filename, TRUE))) return -1; if (write_line(fp, "%d %d", in->xsize, in->ysize)) { fclose(fp); return -1; } if (in->scale != 1 || in->offset != 0) write_line(fp, " %d %d", in->scale, in->offset); write_line(fp, "\n"); for (i = 0, y = 0; y < in->ysize; y++) { for (x = 0; x < in->xsize; x++, i++) write_line(fp, "%d ", in->coeff[i]); if (write_line(fp, "\n")) { fclose(fp); return -1; } } fclose(fp); return 0; } /** * im_write_imask: * @in: mask to write * * Write an imask to a file. * * See also: im_write_imask_name(). * * Returns: 0 on success, or -1 on error. */ int im_write_imask(INTMASK *in) { if (!in->filename) { im_error("im_write_imask", "%s", _("filename not set")); return -1; } return im_write_imask_name(in, in->filename); } /** * im_write_dmask_name: * @in: mask to write * @filename: filename to write to * * Write a dmask to a file. See im_read_dmask() for a description of the mask * file format. * * See also: im_write_dmask(). * * Returns: 0 on success, or -1 on error. */ int im_write_dmask_name(DOUBLEMASK *in, const char *filename) { FILE *fp; int x, y, i; if (im_check_dmask("im_write_dmask_name", in) || !(fp = im__file_open_write(filename, TRUE))) return -1; if (write_line(fp, "%d %d", in->xsize, in->ysize)) { fclose(fp); return -1; } if (in->scale != 1.0 || in->offset != 0.0) { write_line(fp, " "); write_double(fp, in->scale); write_line(fp, " "); write_double(fp, in->offset); } write_line(fp, "\n"); for (i = 0, y = 0; y < in->ysize; y++) { for (x = 0; x < in->xsize; x++, i++) { write_double(fp, in->coeff[i]); write_line(fp, " "); } if (write_line(fp, "\n")) { fclose(fp); return -1; } } fclose(fp); return 0; } /** * im_write_dmask: * @in: mask to write * * Write a dmask to a file. See im_read_dmask() for a description of the mask * file format. * * See also: im_write_dmask_name(). * * Returns: 0 on success, or -1 on error. */ int im_write_dmask(DOUBLEMASK *in) { if (!in->filename) { im_error("im_write_dmask", "%s", _("filename not set")); return -1; } return im_write_dmask_name(in, in->filename); } /* Copy an imask into a matrix. Only used internally by matrix package for * invert. */ void im_copy_imask_matrix(INTMASK *mask, int **matrix) { int x, y; int *p = mask->coeff; for (y = 0; y < mask->ysize; y++) for (x = 0; x < mask->xsize; x++) matrix[x][y] = *p++; } /* Copy a matrix into an imask. */ void im_copy_matrix_imask(int **matrix, INTMASK *mask) { int x, y; int *p = mask->coeff; for (y = 0; y < mask->ysize; y++) for (x = 0; x < mask->xsize; x++) *p++ = matrix[x][y]; } /* Copy a dmask into a matrix. */ void im_copy_dmask_matrix(DOUBLEMASK *mask, double **matrix) { int x, y; double *p = mask->coeff; for (y = 0; y < mask->ysize; y++) for (x = 0; x < mask->xsize; x++) matrix[x][y] = *p++; } /* Copy a matrix to a dmask. */ void im_copy_matrix_dmask(double **matrix, DOUBLEMASK *mask) { int x, y; double *p = mask->coeff; for (y = 0; y < mask->ysize; y++) for (x = 0; x < mask->xsize; x++) *p++ = matrix[x][y]; } /** * im_print_imask: * @in: mask to print * * Print an imask to stdout. * * See also: im_print_dmask(). */ void im_print_imask(INTMASK *in) { int i, j, k; printf("%s: %d %d %d %d\n", in->filename, in->xsize, in->ysize, in->scale, in->offset); for (k = 0, j = 0; j < in->ysize; j++) { for (i = 0; i < in->xsize; i++, k++) printf("%d\t", in->coeff[k]); printf("\n"); } } /** * im_print_dmask: * @in: mask to print * * Print a dmask to stdout. * * See also: im_print_imask(). */ void im_print_dmask(DOUBLEMASK *in) { int i, j, k; printf("%s: %d %d %f %f\n", in->filename, in->xsize, in->ysize, in->scale, in->offset); for (k = 0, j = 0; j < in->ysize; j++) { for (i = 0; i < in->xsize; i++, k++) printf("%f\t", in->coeff[k]); printf("\n"); } } /** * im_local_dmask: * @out: image to make the mask local to * @mask: mask to local-ize * * @out takes ownership of @mask: when @out is closed, @mask will be closed * for you. If im_local_dmask() itself fails, the mask is also freed. * * See also: im_local_imask(). * * Returns: the mask, or NULL on error. */ DOUBLEMASK * im_local_dmask(VipsImage *out, DOUBLEMASK *mask) { if (im_check_dmask("im_local_dmask", mask)) return NULL; if (im_add_close_callback(out, (im_callback_fn) im_free_dmask, mask, NULL)) { im_free_dmask(mask); return NULL; } return mask; } /** * im_local_imask: * @out: image to make the mask local to * @mask: mask to local-ize * * @out takes ownership of @mask: when @out is closed, @mask will be closed * for you. If im_local_imask() itself fails, the mask is also freed. * * See also: im_local_dmask(). * * Returns: the mask, or NULL on error. */ INTMASK * im_local_imask(VipsImage *out, INTMASK *mask) { if (im_check_imask("im_local_dmask", mask)) return NULL; if (im_add_close_callback(out, (im_callback_fn) im_free_imask, mask, NULL)) { im_free_imask(mask); return NULL; } return mask; } libvips-8.18.2/libvips/deprecated/tone.c000066400000000000000000000077271516303661500201660ustar00rootroot00000000000000/* Various functions relating to tone curve adjustment. * * Author: John Cupitt * Written on: 18/7/1995 * 17/9/96 JC * - restrictions on Ps, Pm, Ph relaxed * - restrictions on S, M, H relaxed * 25/7/01 JC * - patched for im_extract_band() change * 11/7/04 * - generalised to im_tone_build_range() ... so you can use it for any * image, not just LabS * 26/3/10 * - cleanups * - gtkdoc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /** * im_tone_map: * @in: input image * @out: output image * @lut: look-up table * * Map the first channel of @in through @lut. If @in is IM_CODING_LABQ, unpack * to LABS, map L and then repack. * * @in should be a LABS or LABQ image for this to work * sensibly. * * See also: im_maplut(). * * Returns: 0 on success, -1 on error */ int im_tone_map(IMAGE *in, IMAGE *out, IMAGE *lut) { IMAGE *t[8]; if (im_check_hist("im_tone_map", lut) || im_open_local_array(out, t, 8, "im_tone_map", "p")) return -1; /* If in is IM_CODING_LABQ, unpack. */ if (in->Coding == IM_CODING_LABQ) { if (im_LabQ2LabS(in, t[0])) return -1; } else t[0] = in; /* Split into bands. */ if (im_extract_band(t[0], t[1], 0)) return -1; if (t[0]->Bands > 1) { if (im_extract_bands(t[0], t[2], 1, t[0]->Bands - 1)) return -1; } /* Map L. */ if (im_maplut(t[1], t[3], lut)) return -1; /* Recombine bands. */ if (t[0]->Bands > 1) { if (im_bandjoin(t[3], t[2], t[4])) return -1; } else t[4] = t[3]; /* If input was LabQ, repack. */ if (in->Coding == IM_CODING_LABQ) { if (im_LabS2LabQ(t[4], t[5])) return -1; } else t[5] = t[4]; return im_copy(t[4], out); } /** * im_tone_analyse: * @in: input image * @out: output image * @Ps: shadow point (eg. 0.2) * @Pm: mid-tone point (eg. 0.5) * @Ph: highlight point (eg. 0.8) * @S: shadow adjustment (+/- 30) * @M: mid-tone adjustment (+/- 30) * @H: highlight adjustment (+/- 30) * * As im_tone_build(), but analyse the histogram of @in and use it to * pick the 0.1% and 99.9% points for @Lb and @Lw. * * See also: im_tone_build(). * * Returns: 0 on success, -1 on error */ int im_tone_analyse( IMAGE *in, IMAGE *out, double Ps, double Pm, double Ph, double S, double M, double H) { IMAGE *t[4]; int low, high; double Lb, Lw; if (im_open_local_array(out, t, 4, "im_tone_map", "p")) return -1; /* If in is IM_CODING_LABQ, unpack. */ if (in->Coding == IM_CODING_LABQ) { if (im_LabQ2LabS(in, t[0])) return -1; } else t[0] = in; /* Should now be 3-band short. */ if (im_check_uncoded("im_tone_analyse", t[0]) || im_check_bands("im_tone_analyse", t[0], 3) || im_check_format("im_tone_analyse", t[0], IM_BANDFMT_SHORT)) return -1; if (im_extract_band(t[0], t[1], 0) || im_clip2fmt(t[1], t[2], IM_BANDFMT_USHORT)) return -1; if (im_mpercent(t[2], 0.1 / 100.0, &high) || im_mpercent(t[2], 99.9 / 100.0, &low)) return -1; Lb = 100 * low / 32768; Lw = 100 * high / 32768; im_diag("im_tone_analyse", "set Lb = %g, Lw = %g", Lb, Lw); return im_tone_build(out, Lb, Lw, Ps, Pm, Ph, S, M, H); } libvips-8.18.2/libvips/deprecated/video_dispatch.c000066400000000000000000000053361516303661500222000ustar00rootroot00000000000000/* function dispatch tables for video */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include static int video_v4l1_vec(im_object *argv) { IMAGE *out = argv[0]; char *device = (char *) argv[1]; int channel = *((int *) argv[2]); int brightness = *((int *) argv[3]); int colour = *((int *) argv[4]); int contrast = *((int *) argv[5]); int hue = *((int *) argv[6]); int ngrabs = *((int *) argv[7]); return im_video_v4l1(out, device, channel, brightness, colour, contrast, hue, ngrabs); } static im_arg_desc video_v4l1_arg_types[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_STRING("device"), IM_INPUT_INT("channel"), IM_INPUT_INT("brightness"), IM_INPUT_INT("colour"), IM_INPUT_INT("contrast"), IM_INPUT_INT("hue"), IM_INPUT_INT("ngrabs") }; static im_function video_v4l1_desc = { "im_video_v4l1", /* Name */ "grab a video frame with v4l1", /* Description */ IM_FN_NOCACHE, /* Flags */ video_v4l1_vec, /* Dispatch function */ IM_NUMBER(video_v4l1_arg_types), /* Size of arg list */ video_v4l1_arg_types /* Arg list */ }; static int video_test_vec(im_object *argv) { IMAGE *out = argv[0]; int brightness = *((int *) argv[1]); int error = *((int *) argv[2]); return im_video_test(out, brightness, error); } static im_arg_desc video_test_arg_types[] = { IM_OUTPUT_IMAGE("out"), IM_INPUT_INT("brightness"), IM_INPUT_INT("error") }; static im_function video_test_desc = { "im_video_test", /* Name */ "test video grabber", /* Description */ IM_FN_NOCACHE, /* Flags */ video_test_vec, /* Dispatch function */ IM_NUMBER(video_test_arg_types), /* Size of arg list */ video_test_arg_types /* Arg list */ }; static im_function *video_list[] = { &video_test_desc, &video_v4l1_desc }; im_package im__video = { "video", /* Package name */ IM_NUMBER(video_list), /* Function list */ video_list }; libvips-8.18.2/libvips/deprecated/vips7compat.c000066400000000000000000003107001516303661500214610ustar00rootroot00000000000000/* compat stuff for vips7 * * 4/3/11 * - hacked up */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include /* Split filename into name / mode components. name and mode should both be * FILENAME_MAX chars. * * We look for the ':' splitting the name and mode by searching for the * rightmost occurrence of the regexp "\.[A-Za-z0-9]+:". The initial dot can * be missing if there's a dirsep or start of string, meaning this is a * filename without an extension. * * Examples: * * c:\silly:dir:name\fr:ed.tif:jpeg:95,,,,c:\icc\srgb.icc * -> c:\silly:dir:name\fr:ed.tif jpeg:95,,,,c:\icc\srgb.icc * I180: * -> I180 "" * c:\silly: * -> c:\silly "" * c:\silly * -> c:\silly "" * C:\fixtures\2569067123_aca715a2ee_o.jpg * -> C:\fixtures\2569067123_aca715a2ee_o.jpg "" * * vips8 handles this in a much better way :( */ void im_filename_split(const char *path, char *name, char *mode) { char *p; size_t len; g_strlcpy(name, path, FILENAME_MAX); strcpy(mode, ""); if ((len = strlen(name)) == 0) return; /* Search backwards towards start, stopping at each ':' char. */ for (p = name + len - 1; p > name; p -= 1) if (*p == ':') { char *q; /* We are skipping back over the file extension, * g_ascii_isalnum() is probably sufficient. */ for (q = p - 1; g_ascii_isalnum(*q) && q > name; q -= 1) ; if (*q == '.') { break; } /* All the way back to the start? We probably have a * filename with no extension, eg. "I180:" */ if (q == name) break; /* .. or we could hit a dirsep. Allow win or nix * separators. */ if (*q == '/' || *q == '\\') break; } /* Ignore a ':' in column 1, it's probably a drive letter on a * Windows path. */ if (*p == ':' && p - name != 1) { g_strlcpy(mode, p + 1, FILENAME_MAX); *p = '\0'; } } /** * vips_path_filename7: * @path: path to split * * Return the filename part of a vips7 path. For testing only. */ char * vips_path_filename7(const char *path) { char name[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(path, name, mode); return g_strdup(name); } /** * vips_path_mode7: * @path: path to split * * Return the mode part of a vips7 path. For testing only. */ char * vips_path_mode7(const char *path) { char name[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split(path, name, mode); return g_strdup(mode); } /* Skip any leading path stuff. Horrible: if this is a filename which came * from win32 and we're a *nix machine, it'll have '\\' not '/' as the * separator :-( * * Try to fudge this ... if the file doesn't contain any of our native * separators, look for the opposite one as well. If there are none of those * either, just return the filename. */ const char * im_skip_dir(const char *path) { char name[FILENAME_MAX]; char mode[FILENAME_MAX]; const char *p; const char *q; const char native_dir_sep = G_DIR_SEPARATOR; const char non_native_dir_sep = native_dir_sep == '/' ? '\\' : '/'; /* Remove any trailing save modifiers: we don't want '/' or '\' in the * modifier confusing us. */ im_filename_split(path, name, mode); /* The '\0' char at the end of the string. */ p = name + strlen(name); /* Search back for the first native dir sep, or failing that, the first * non-native dir sep. */ for (q = p; q > name && q[-1] != native_dir_sep; q--) ; if (q == name) for (q = p; q > name && q[-1] != non_native_dir_sep; q--) ; return path + (q - name); } /* Extract suffix from filename, ignoring any mode string. Suffix should be * FILENAME_MAX chars. Include the "." character, if any. */ void im_filename_suffix(const char *path, char *suffix) { char name[FILENAME_MAX]; char mode[FILENAME_MAX]; char *p; im_filename_split(path, name, mode); if ((p = strrchr(name, '.'))) strcpy(suffix, p); else strcpy(suffix, ""); } /* Does a filename have one of a set of suffixes. Ignore case. */ int im_filename_suffix_match(const char *path, const char *suffixes[]) { char suffix[FILENAME_MAX]; const char **p; im_filename_suffix(path, suffix); for (p = suffixes; *p; p++) if (g_ascii_strcasecmp(suffix, *p) == 0) return 1; return 0; } /* p points to the start of a buffer ... move it on through the buffer (ready * for the next call), and return the current option (or NULL for option * missing). ',' characters inside options can be escaped with a '\'. */ char * im_getnextoption(char **in) { char *p; char *q; p = *in; q = p; if (!p || !*p) return NULL; /* Find the next ',' not prefixed with a '\'. If the first character * of p is ',', there can't be a previous escape character. */ for (;;) { if (!(p = strchr(p, ','))) break; if (p == q) break; if (p[-1] != '\\') break; p += 1; } if (p) { /* Another option follows this one .. set up to pick that out * next time. */ *p = '\0'; *in = p + 1; } else { /* This is the last one. */ *in = NULL; } if (strlen(q) > 0) return q; else return NULL; } /* Get a suboption string, or NULL. */ char * im_getsuboption(const char *buf) { char *p, *q, *r; if (!(p = strchr(buf, ':'))) /* No suboption. */ return NULL; /* Step over the ':'. */ p += 1; /* Need to unescape any \, pairs. Shift stuff down one if we find one. */ for (q = p; *q; q++) if (q[0] == '\\' && q[1] == ',') for (r = q; *r; r++) r[0] = r[1]; return p; } VipsImage * im_open(const char *filename, const char *mode) { VipsImage *image; vips_check_init(); /* We have to go via the old VipsFormat system so we can support the * "filename:option" syntax. * * Use "rs" to turn on seq mode. */ if (strcmp(mode, "r") == 0 || strcmp(mode, "rd") == 0) { if (!(image = vips__deprecated_open_read(filename, FALSE))) return NULL; } else if (strcmp(mode, "rs") == 0) { if (!(image = vips__deprecated_open_read(filename, TRUE))) return NULL; } else if (strcmp(mode, "w") == 0) { if (!(image = vips__deprecated_open_write(filename))) return NULL; } else { if (!(image = vips_image_new_mode(filename, mode))) return NULL; } return image; } /* Just for compatibility. New code should use vips_object_local() directly. */ VipsImage * im_open_local(VipsImage *parent, const char *filename, const char *mode) { VipsImage *image; if (!(image = im_open(filename, mode))) return NULL; vips_object_local(parent, image); return image; } /* Just for compatibility. New code should use vips_object_local_array(). */ int im_open_local_array(VipsImage *parent, VipsImage **images, int n, const char *filename, const char *mode) { int i; for (i = 0; i < n; i++) if (!(images[i] = im_open_local(parent, filename, mode))) return -1; return 0; } typedef struct { im_callback_fn fn; void *a; void *b; } Callback; static void im_add_callback_cb(VipsImage *im, Callback *callback) { if (callback->fn(callback->a, callback->b)) vips_image_set_kill(im, TRUE); } int im_add_callback(VipsImage *im, const char *name, im_callback_fn fn, void *a, void *b) { Callback *callback; callback = VIPS_NEW(VIPS_OBJECT(im), Callback); callback->fn = fn; callback->a = a; callback->b = b; g_signal_connect(im, name, G_CALLBACK(im_add_callback_cb), callback); return 0; } static void im_add_callback_cb1(VipsImage *im, void *x, Callback *callback) { if (callback->fn(callback->a, callback->b)) vips_image_set_kill(im, TRUE); } int im_add_callback1(VipsImage *im, const char *name, im_callback_fn fn, void *a, void *b) { Callback *callback; callback = VIPS_NEW(VIPS_OBJECT(im), Callback); callback->fn = fn; callback->a = a; callback->b = b; g_signal_connect(im, name, G_CALLBACK(im_add_callback_cb1), callback); return 0; } /* Make something local to an image descriptor ... pass in a constructor * and a destructor, plus three args. */ void * im_local(IMAGE *im, im_construct_fn cons, im_callback_fn dest, void *a, void *b, void *c) { void *obj; if (!im) { im_error("im_local", "%s", _("NULL image descriptor")); return NULL; } if (!(obj = cons(a, b, c))) return NULL; if (im_add_close_callback(im, (im_callback_fn) dest, obj, a)) { dest(obj, a); return NULL; } return obj; } /* Make an array of things local to a descriptor ... eg. make 6 local temp * images. */ int im_local_array(IMAGE *im, void **out, int n, im_construct_fn cons, im_callback_fn dest, void *a, void *b, void *c) { int i; for (i = 0; i < n; i++) if (!(out[i] = im_local(im, cons, dest, a, b, c))) return -1; return 0; } int im_close(VipsImage *im) { g_object_unref(im); return 0; } /* edvips.c needs this */ VipsImage * im_init(const char *filename) { VipsImage *image; image = vips_image_new(); IM_SETSTR(image->filename, filename); return image; } /* We can't do this with a rename macro since the C++ interface needs * this entrypoint, see VImage.h. * * As a result our fancy ABI check will not work with the vips7 interface. */ int im_init_world(const char *argv0) { return vips_init(argv0); } /* Prettyprint various header fields. Just for vips7 compat, use * vips_enum_value() instead. */ const char * im_Type2char(VipsInterpretation type) { return vips_enum_string(VIPS_TYPE_INTERPRETATION, type); } const char * im_BandFmt2char(VipsBandFormat format) { return vips_enum_string(VIPS_TYPE_BAND_FORMAT, format); } const char * im_Coding2char(VipsCoding coding) { return vips_enum_string(VIPS_TYPE_CODING, coding); } const char * im_dtype2char(VipsImageType n) { return vips_enum_string(VIPS_TYPE_IMAGE_TYPE, n); } const char * im_dhint2char(VipsDemandStyle style) { return vips_enum_string(VIPS_TYPE_DEMAND_STYLE, style); } /* Old names for enums, for compat. */ static const char *im_Type[] = { "IM_TYPE_MULTIBAND", /* 0 */ "IM_TYPE_B_W", /* 1 */ "LUMINACE", /* 2 */ "XRAY", /* 3 */ "IR", /* 4 */ "YUV", /* 5 */ "RED_ONLY", /* 6 */ "GREEN_ONLY", /* 7 */ "BLUE_ONLY", /* 8 */ "POWER_SPECTRUM", /* 9 */ "IM_TYPE_HISTOGRAM", /* 10 */ "LUT", /* 11 */ "IM_TYPE_XYZ", /* 12 */ "IM_TYPE_LAB", /* 13 */ "CMC", /* 14 */ "IM_TYPE_CMYK", /* 15 */ "IM_TYPE_LABQ", /* 15 */ "IM_TYPE_RGB", /* 17 */ "IM_TYPE_UCS", /* 18 */ "IM_TYPE_LCH", /* 19 */ "IM_TYPE_LABS", /* 20 */ "", /* 21 */ "IM_TYPE_sRGB", /* 22 */ "IM_TYPE_YXY", /* 23 */ "IM_TYPE_FOURIER", /* 24 */ "IM_TYPE_RGB16", /* 25 */ "IM_TYPE_GREY16", /* 26 */ NULL }; static const char *im_BandFmt[] = { "IM_BANDFMT_UCHAR", "IM_BANDFMT_CHAR", "IM_BANDFMT_USHORT", "IM_BANDFMT_SHORT", "IM_BANDFMT_UINT", "IM_BANDFMT_INT", "IM_BANDFMT_FLOAT", "IM_BANDFMT_COMPLEX", "IM_BANDFMT_DOUBLE", "IM_BANDFMT_DPCOMPLEX", NULL }; static const char *im_Coding[] = { "IM_CODING_NONE", "COLQUANT8", "IM_CODING_LABQ", "IM_CODING_LABQ_COMPRESSED", "RGB_COMPRESSED", "LUM_COMPRESSED", "IM_CODING_RAD", NULL }; static const char *im_dtype[] = { "IM_NONE", "IM_SETBUF", "IM_SETBUF_FOREIGN", "IM_OPENIN", "IM_MMAPIN", "IM_MMAPINRW", "IM_OPENOUT", "IM_PARTIAL", NULL }; static const char *im_dhint[] = { "IM_SMALLTILE", "IM_FATSTRIP", "IM_THINSTRIP", "IM_ANY", NULL }; /* enum string to int, try the GEnum first, then use a compat *char[] for old * names. */ static int lookup_enum(GType type, const char *names[], const char *name) { GEnumClass *class; GEnumValue *value; int i; class = g_type_class_ref(type); if ((value = g_enum_get_value_by_nick(class, name))) return value->value; if ((value = g_enum_get_value_by_name(class, name))) return value->value; for (i = 0; names[i]; i++) if (g_ascii_strcasecmp(names[i], name) == 0) return i; return -1; } VipsInterpretation im_char2Type(const char *str) { return lookup_enum(VIPS_TYPE_INTERPRETATION, im_Type, str); } VipsBandFormat im_char2BandFmt(const char *str) { return lookup_enum(VIPS_TYPE_BAND_FORMAT, im_BandFmt, str); } VipsCoding im_char2Coding(const char *str) { return lookup_enum(VIPS_TYPE_CODING, im_Coding, str); } VipsImageType im_char2dtype(const char *str) { return lookup_enum(VIPS_TYPE_IMAGE_TYPE, im_dtype, str); } VipsDemandStyle im_char2dhint(const char *str) { return lookup_enum(VIPS_TYPE_DEMAND_STYLE, im_dhint, str); } /* Totally useless now. */ const char * im_Compression2char(int n) { return "NONE"; } int im_char2Compression(const char *str) { return -1; } /* Wrap one / many is being replaced by a class thing. */ typedef struct { im_wrapmany_fn fn; /* Function we call */ void *a, *b; /* User values for function */ } Bundle; /* Maximum number of input images -- why not? */ #define MAX_INPUT_IMAGES (64) /* Convert a VipsRegion. */ static int process_region(VipsRegion *out_region, void *seq, void *a, void *b) { VipsRegion **ir = (VipsRegion **) seq; Bundle *bun = (Bundle *) b; PEL *p[MAX_INPUT_IMAGES], *q; int i, y; /* Prepare all input regions and make buffer pointers. */ if (vips_reorder_prepare_many(out_region->im, ir, &out_region->valid)) return -1; for (i = 0; ir[i]; i++) p[i] = (PEL *) VIPS_REGION_ADDR(ir[i], out_region->valid.left, out_region->valid.top); p[i] = NULL; q = (PEL *) VIPS_REGION_ADDR(out_region, out_region->valid.left, out_region->valid.top); /* Convert linewise. */ for (y = 0; y < out_region->valid.height; y++) { PEL *p1[MAX_INPUT_IMAGES]; /* Make a copy of p[] which the buffer function can mess up if * it wants. */ for (i = 0; ir[i]; i++) p1[i] = p[i]; /* Bizarre double-cast stops a bogus gcc 4.1 compiler warning. */ bun->fn((void **) ((void *) p1), q, out_region->valid.width, bun->a, bun->b); /* Move pointers on. */ for (i = 0; ir[i]; i++) p[i] += VIPS_REGION_LSKIP(ir[i]); q += VIPS_REGION_LSKIP(out_region); } return 0; } /* Make a copy of an array of input images. */ static IMAGE ** dupims(IMAGE *out, IMAGE **in) { IMAGE **new; int i, n; for (n = 0; in[n]; n++) ; new = VIPS_ARRAY(VIPS_OBJECT(out), n + 1, IMAGE *); for (i = 0; i < n; i++) new[i] = in[i]; new[n] = NULL; return new; } int im_wrapmany(IMAGE **in, IMAGE *out, im_wrapmany_fn fn, void *a, void *b) { Bundle *bun; int i, n; /* Count input images. */ for (n = 0; in[n]; n++) ; if (n >= MAX_INPUT_IMAGES - 1) { vips_error("im_wrapmany", "%s", _("too many input images")); return -1; } /* Save args. */ bun = VIPS_NEW(VIPS_OBJECT(out), Bundle); if (!(in = dupims(out, in))) return -1; bun->fn = fn; bun->a = a; bun->b = b; /* Check descriptors -- make sure that our caller has done this * correctly. */ for (i = 0; i < n; i++) { if (in[i]->Xsize != out->Xsize || in[i]->Ysize != out->Ysize) { vips_error("im_wrapmany", "%s", _("descriptors differ in size")); return -1; } /* Check io style. */ if (vips_image_pio_input(in[i])) return -1; } /* Don't call vips_image_pipeline_array(), we don't want to copy * fields. */ vips__demand_hint_array(out, VIPS_DEMAND_STYLE_THINSTRIP, in); if (vips__reorder_set_input(out, in)) return -1; /* Generate! */ if (vips_image_generate(out, vips_start_many, (VipsGenerateFn) process_region, vips_stop_many, in, bun)) return -1; return 0; } static void wrapone_gen(void **ins, void *out, int width, Bundle *bun, void *dummy) { ((im_wrapone_fn) (bun->fn))(ins[0], out, width, bun->a, bun->b); } int im_wrapone(IMAGE *in, IMAGE *out, im_wrapone_fn fn, void *a, void *b) { Bundle *bun; IMAGE *invec[2]; /* Heh, yuk. We cast back above. */ bun = VIPS_NEW(VIPS_OBJECT(out), Bundle); bun->fn = (im_wrapmany_fn) fn; bun->a = a; bun->b = b; invec[0] = in; invec[1] = NULL; return im_wrapmany(invec, out, (im_wrapmany_fn) wrapone_gen, bun, NULL); } static void wraptwo_gen(void **ins, void *out, int width, Bundle *bun, void *dummy) { ((im_wraptwo_fn) (bun->fn))(ins[0], ins[1], out, width, bun->a, bun->b); } int im_wraptwo(IMAGE *in1, IMAGE *in2, IMAGE *out, im_wraptwo_fn fn, void *a, void *b) { Bundle *bun; IMAGE *invec[3]; bun = VIPS_NEW(VIPS_OBJECT(out), Bundle); bun->fn = (im_wrapmany_fn) fn; bun->a = a; bun->b = b; invec[0] = in1; invec[1] = in2; invec[2] = NULL; return im_wrapmany(invec, out, (im_wrapmany_fn) wraptwo_gen, bun, NULL); } /* Save a bit of typing. */ #define UC IM_BANDFMT_UCHAR #define C IM_BANDFMT_CHAR #define US IM_BANDFMT_USHORT #define S IM_BANDFMT_SHORT #define UI IM_BANDFMT_UINT #define I IM_BANDFMT_INT #define F IM_BANDFMT_FLOAT #define X IM_BANDFMT_COMPLEX #define D IM_BANDFMT_DOUBLE #define DX IM_BANDFMT_DPCOMPLEX /* For two integer types, the "largest", ie. one which can represent the * full range of both. */ static int bandfmt_largest[6][6] = { /* UC C US S UI I */ /* UC */ { UC, S, US, S, UI, I }, /* C */ { S, C, I, S, I, I }, /* US */ { US, I, US, I, UI, I }, /* S */ { S, S, I, S, I, I }, /* UI */ { UI, I, UI, I, UI, I }, /* I */ { I, I, I, I, I, I } }; /* For two formats, find one which can represent the full range of both. */ static VipsBandFmt im__format_common(VipsBandFmt in1, VipsBandFmt in2) { if (vips_band_format_iscomplex(in1) || vips_band_format_iscomplex(in2)) { /* What kind of complex? */ if (in1 == IM_BANDFMT_DPCOMPLEX || in2 == IM_BANDFMT_DPCOMPLEX) /* Output will be DPCOMPLEX. */ return IM_BANDFMT_DPCOMPLEX; else return IM_BANDFMT_COMPLEX; } else if (vips_bandfmt_isfloat(in1) || vips_bandfmt_isfloat(in2)) { /* What kind of float? */ if (in1 == IM_BANDFMT_DOUBLE || in2 == IM_BANDFMT_DOUBLE) return IM_BANDFMT_DOUBLE; else return IM_BANDFMT_FLOAT; } else /* Must be int+int -> int. */ return bandfmt_largest[in1][in2]; } int im__formatalike_vec(IMAGE **in, IMAGE **out, int n) { int i; VipsBandFmt fmt; g_assert(n >= 1); fmt = in[0]->BandFmt; for (i = 1; i < n; i++) fmt = im__format_common(fmt, in[i]->BandFmt); for (i = 0; i < n; i++) if (im_clip2fmt(in[i], out[i], fmt)) return -1; return 0; } int im__formatalike(IMAGE *in1, IMAGE *in2, IMAGE *out1, IMAGE *out2) { IMAGE *in[2]; IMAGE *out[2]; in[0] = in1; in[1] = in2; out[0] = out1; out[1] = out2; return im__formatalike_vec(in, out, 2); } /* Make an n-band image. Input 1 or n bands. */ int im__bandup(const char *domain, IMAGE *in, IMAGE *out, int n) { IMAGE *bands[256]; int i; if (in->Bands == n) return vips_image_write(in, out); if (in->Bands != 1) { im_error(domain, _("not one band or %d bands"), n); return -1; } if (n > 256 || n < 1) { im_error(domain, "%s", _("bad bands")); return -1; } for (i = 0; i < n; i++) bands[i] = in; return im_gbandjoin(bands, out, n); } int im__bandalike_vec(const char *domain, IMAGE **in, IMAGE **out, int n) { int i; int max_bands; g_assert(n >= 1); max_bands = in[0]->Bands; for (i = 1; i < n; i++) max_bands = IM_MAX(max_bands, in[i]->Bands); for (i = 0; i < n; i++) if (im__bandup(domain, in[i], out[i], max_bands)) return -1; return 0; } int im__bandalike(const char *domain, IMAGE *in1, IMAGE *in2, IMAGE *out1, IMAGE *out2) { IMAGE *in[2]; IMAGE *out[2]; in[0] = in1; in[1] = in2; out[0] = out1; out[1] = out2; if (im__bandalike_vec(domain, in, out, 2)) return -1; return 0; } /* This is deprecated to make room for highway. */ void vips_vector_init(void) { vips_error("vips_vector_init", "%s", _("deprecated")); } void vips_vector_free(VipsVector *vector) { vips_error("vips_vector_free", "%s", _("deprecated")); } VipsVector * vips_vector_new(const char *name, int dsize) { vips_error("vips_vector_new", "%s", _("deprecated")); return NULL; } void vips_vector_asm2(VipsVector *vector, const char *op, const char *a, const char *b) { vips_error("vips_vector_asm2", "%s", _("deprecated")); } void vips_vector_asm3(VipsVector *vector, const char *op, const char *a, const char *b, const char *c) { vips_error("vips_vector_asm3", "%s", _("deprecated")); } void vips_vector_constant(VipsVector *vector, char *name, int value, int size) { vips_error("vips_vector_constant", "%s", _("deprecated")); } void vips_vector_source_scanline(VipsVector *vector, char *name, int line, int size) { vips_error("vips_vector_source_scanline", "%s", _("deprecated")); } int vips_vector_source_name(VipsVector *vector, const char *name, int size) { vips_error("vips_vector_source_name", "%s", _("deprecated")); return -1; } void vips_vector_temporary(VipsVector *vector, const char *name, int size) { vips_error("vips_vector_temporary", "%s", _("deprecated")); } int vips_vector_parameter(VipsVector *vector, const char *name, int size) { vips_error("vips_vector_parameter", "%s", _("deprecated")); return -1; } int vips_vector_destination(VipsVector *vector, const char *name, int size) { vips_error("vips_vector_destination", "%s", _("deprecated")); return -1; } gboolean vips_vector_full(VipsVector *vector) { vips_error("vips_vector_full", "%s", _("deprecated")); return FALSE; } gboolean vips_vector_compile(VipsVector *vector) { vips_error("vips_vector_compile", "%s", _("deprecated")); return TRUE; } void vips_vector_print(VipsVector *vector) { vips_error("vips_vector_print", "%s", _("deprecated")); } void vips_executor_set_program(VipsExecutor *executor, VipsVector *vector, int n) { vips_error("vips_executor_set_program", "%s", _("deprecated")); } void vips_executor_set_array(VipsExecutor *executor, int var, void *value) { vips_error("vips_executor_set_array", "%s", _("deprecated")); } void vips_executor_set_parameter(VipsExecutor *executor, int var, int value) { vips_error("vips_executor_set_parameter", "%s", _("deprecated")); } void vips_executor_set_scanline(VipsExecutor *executor, VipsRegion *ir, int x, int y) { vips_error("vips_executor_set_scanline", "%s", _("deprecated")); } void vips_executor_set_destination(VipsExecutor *executor, void *value) { vips_error("vips_executor_set_destination", "%s", _("deprecated")); } void vips_executor_run(VipsExecutor *executor) { vips_error("vips_executor_run", "%s", _("deprecated")); } void vips_vector_to_fixed_point(double *in, int *out, int n, int scale) { vips_error("vips_vector_to_fixed_point", "%s", _("deprecated")); } int im_add(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_call("add", in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_subtract(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_call("subtract", in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_multiply(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_call("multiply", in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_divide(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_call("divide", in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_avg(IMAGE *in, double *out) { return vips_avg(in, out, NULL); } int im_deviate(IMAGE *in, double *out) { return vips_deviate(in, out, NULL); } int im_generate(VipsImage *im, im_start_fn start, im_generate_fn generate, im_stop_fn stop, void *a, void *b) { return vips_image_generate(im, start, (VipsGenerateFn) generate, stop, a, b); } int im_minpos(IMAGE *in, int *xpos, int *ypos, double *out) { return vips_min(in, out, "x", xpos, "y", ypos, NULL); } int im_min(IMAGE *in, double *out) { return im_minpos(in, NULL, NULL, out); } int im_maxpos(IMAGE *in, int *xpos, int *ypos, double *out) { return vips_max(in, out, "x", xpos, "y", ypos, NULL); } int im_max(IMAGE *in, double *out) { return im_maxpos(in, NULL, NULL, out); } #define MAX_IMAGES 100 int im_demand_hint(IMAGE *im, VipsDemandStyle hint, ...) { va_list ap; int i; IMAGE *ar[MAX_IMAGES]; va_start(ap, hint); for (i = 0; i < MAX_IMAGES && (ar[i] = va_arg(ap, IMAGE *)); i++) ; va_end(ap); if (i == MAX_IMAGES) { im_error("im_demand_hint", "%s", _("too many images")); return -1; } vips__demand_hint_array(im, hint, ar); return 0; } int im_cp_descv(IMAGE *im, ...) { va_list ap; int i; IMAGE *ar[MAX_IMAGES]; va_start(ap, im); for (i = 0; i < MAX_IMAGES && (ar[i] = va_arg(ap, IMAGE *)); i++) ; va_end(ap); if (i == MAX_IMAGES) { im_error("im_cp_descv", "%s", _("too many images")); return -1; } return vips__image_copy_fields_array(im, ar); } int im_cp_desc(IMAGE *out, IMAGE *in) { return im_cp_descv(out, in, NULL); } int im_copy_set(IMAGE *in, IMAGE *out, VipsType type, float xres, float yres, int xoffset, int yoffset) { VipsImage *x; if (vips_copy(in, &x, "interpretation", type, "xres", xres, "yres", yres, "xoffset", xoffset, "yoffset", yoffset, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_copy_morph(IMAGE *in, IMAGE *out, int bands, VipsBandFmt bandfmt, VipsCoding coding) { VipsImage *x; if (vips_copy(in, &x, "bands", bands, "format", bandfmt, "coding", coding, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_copy(IMAGE *in, IMAGE *out) { return vips_image_write(in, out); } int im_copy_swap(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_byteswap(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_copy_set_meta(IMAGE *in, IMAGE *out, const char *field, GValue *value) { if (vips_image_write(in, out)) return -1; (void) im_meta_set(out, field, value); return 0; } int im_copy_native(IMAGE *in, IMAGE *out, gboolean is_msb_first) { if (is_msb_first != im_amiMSBfirst()) return im_copy_swap(in, out); else return vips_image_write(in, out); } int im_embed(IMAGE *in, IMAGE *out, int type, int x, int y, int width, int height) { VipsImage *t; if (vips_embed(in, &t, x, y, width, height, "extend", type, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_fliphor(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_flip(in, &t, VIPS_DIRECTION_HORIZONTAL, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_rot90(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_rot(in, &t, VIPS_ANGLE_D90, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_rot180(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_rot(in, &t, VIPS_ANGLE_D180, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_rot270(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_rot(in, &t, VIPS_ANGLE_D270, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_flipver(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_flip(in, &t, VIPS_DIRECTION_VERTICAL, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_insert(IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y) { VipsImage *t; if (vips_insert(main, sub, &t, x, y, "expand", TRUE, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_insert_noexpand(IMAGE *main, IMAGE *sub, IMAGE *out, int x, int y) { VipsImage *t; if (vips_insert(main, sub, &t, x, y, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_lrjoin(IMAGE *left, IMAGE *right, IMAGE *out) { VipsImage *t; if (vips_join(left, right, &t, VIPS_DIRECTION_HORIZONTAL, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_tbjoin(IMAGE *left, IMAGE *right, IMAGE *out) { VipsImage *t; if (vips_join(left, right, &t, VIPS_DIRECTION_VERTICAL, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_extract_area(IMAGE *in, IMAGE *out, int left, int top, int width, int height) { VipsImage *t; if (vips_extract_area(in, &t, left, top, width, height, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_extract_bands(IMAGE *in, IMAGE *out, int band, int nbands) { VipsImage *t; if (vips_extract_band(in, &t, band, "n", nbands, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_extract_band(IMAGE *in, IMAGE *out, int band) { return im_extract_bands(in, out, band, 1); } int im_extract_areabands(IMAGE *in, IMAGE *out, int left, int top, int width, int height, int band, int nbands) { VipsImage *t1, *t2; if (vips_extract_area(in, &t1, left, top, width, height, NULL)) return -1; if (vips_extract_band(t1, &t2, band, "n", nbands, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_replicate(IMAGE *in, IMAGE *out, int across, int down) { VipsImage *t; if (vips_replicate(in, &t, across, down, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_clip2fmt(IMAGE *in, IMAGE *out, VipsBandFmt fmt) { VipsImage *t; if (vips_cast(in, &t, fmt, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } size_t im_ref_string_get_length(const GValue *value) { size_t length; (void) vips_value_get_ref_string(value, &length); return length; } int im_bandjoin(VipsImage *in1, VipsImage *in2, VipsImage *out) { VipsImage *t; if (vips_bandjoin2(in1, in2, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_gbandjoin(VipsImage **in, VipsImage *out, int n) { VipsImage *t; if (vips_bandjoin(in, &t, n, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_rank_image(VipsImage **in, VipsImage *out, int n, int index) { VipsImage *t; if (vips_bandrank(in, &t, n, "index", index, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_maxvalue(IMAGE **in, IMAGE *out, int n) { return im_rank_image(in, out, n, n - 1); } int im_invert(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_invert(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_sign(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_sign(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_abs(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_abs(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_bandmean(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_bandmean(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_lintra(double a, IMAGE *in, double b, IMAGE *out) { VipsImage *t; if (vips_linear1(in, &t, a, b, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_lintra_vec(int n, double *a, IMAGE *in, double *b, IMAGE *out) { VipsImage *t; if (vips_linear(in, &t, a, b, n, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_black(IMAGE *out, int x, int y, int bands) { VipsImage *t; if (vips_black(&t, x, y, "bands", bands, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_identity_ushort(VipsImage *lut, int bands, int sz) { VipsImage *t; if (vips_identity(&t, "bands", bands, "ushort", TRUE, "size", sz, NULL)) return -1; if (vips_image_write(t, lut)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_identity(VipsImage *lut, int bands) { VipsImage *t; if (vips_identity(&t, "bands", bands, NULL)) return -1; if (vips_image_write(t, lut)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_gaussnoise(VipsImage *out, int x, int y, double mean, double sigma) { VipsImage *t; if (vips_gaussnoise(&t, x, y, "mean", mean, "sigma", sigma, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_grid(VipsImage *in, VipsImage *out, int tile_height, int across, int down) { VipsImage *t; if (vips_grid(in, &t, tile_height, across, down, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_scale(VipsImage *in, VipsImage *out) { VipsImage *t; if (vips_scale(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_msb(VipsImage *in, VipsImage *out) { VipsImage *t; if (vips_msb(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_msb_band(VipsImage *in, VipsImage *out, int band) { VipsImage *t; if (vips_msb(in, &t, "band", band, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_make_xy(IMAGE *out, const int xsize, const int ysize) { VipsImage *t; if (vips_xyz(&t, xsize, ysize, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_zone(IMAGE *out, int size) { VipsImage *t; if (vips_zone(&t, size, size, "uchar", TRUE, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_fzone(IMAGE *out, int size) { VipsImage *t; if (vips_zone(&t, size, size, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_sines(IMAGE *out, int xsize, int ysize, double horfreq, double verfreq) { VipsImage *t; if (vips_sines(&t, xsize, ysize, "hfreq", horfreq, "vfreq", verfreq, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_text(IMAGE *out, const char *text, const char *font, int width, int align, int dpi) { VipsImage *t; if (vips_text(&t, text, "font", font, "width", width, "align", align, "dpi", dpi, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_system(VipsImage *im, const char *cmd, char **out) { VipsArea *area; VipsImage **array; char *str; area = vips_area_new_array_object(1); array = (VipsImage **) area->data; array[0] = im; if (vips_system(cmd, "in", area, "in_format", "%s.v", "log", &str, NULL)) { vips_area_unref(area); return -1; } vips_area_unref(area); if (out) *out = str; return 0; } VipsImage * im_system_image(VipsImage *im, const char *in_format, const char *out_format, const char *cmd_format, char **log) { VipsArrayImage *array; char *str; VipsImage *out; array = vips_array_image_newv(1, im); /* im will be unreffed when area is unreffed. */ g_object_ref(im); if (vips_system(cmd_format, "in", array, "out", &out, "in_format", in_format, "out_format", out_format, "log", &str, NULL)) { vips_area_unref(VIPS_AREA(array)); return NULL; } vips_area_unref(VIPS_AREA(array)); if (log) *log = str; else g_free(str); return out; } int im_wrap(IMAGE *in, IMAGE *out, int x, int y) { VipsImage *t; if (vips_wrap(in, &t, "x", x, "y", y, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_rotquad(IMAGE *in, IMAGE *out) { return im_wrap(in, out, in->Xsize / 2, in->Ysize / 2); } int im_scaleps(VipsImage *in, VipsImage *out) { VipsImage *t; if (vips_scale(in, &t, "log", TRUE, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_zoom(VipsImage *in, VipsImage *out, int xfac, int yfac) { VipsImage *t; if (vips_zoom(in, &t, xfac, yfac, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_subsample(VipsImage *in, VipsImage *out, int xfac, int yfac) { VipsImage *t; if (vips_subsample(in, &t, xfac, yfac, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int vips__math(VipsImage *in, VipsImage *out, VipsOperationMath math) { VipsImage *t; if (vips_math(in, &t, math, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_sintra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_SIN); } int im_costra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_COS); } int im_tantra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_TAN); } int im_asintra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_ASIN); } int im_acostra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_ACOS); } int im_atantra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_ATAN); } int im_logtra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_LOG); } int im_log10tra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_LOG10); } int im_exptra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_EXP); } int im_exp10tra(IMAGE *in, IMAGE *out) { return vips__math(in, out, VIPS_OPERATION_MATH_EXP10); } DOUBLEMASK * im_stats(VipsImage *in) { VipsImage *t; DOUBLEMASK *msk; if (vips_stats(in, &t, NULL)) return NULL; if (!(msk = im_vips2mask(t, "im_stats"))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } DOUBLEMASK * im_gauss_dmask(const char *filename, double sigma, double min_ampl) { VipsImage *t; DOUBLEMASK *msk; if (vips_gaussmat(&t, sigma, min_ampl, "precision", VIPS_PRECISION_FLOAT, NULL)) return NULL; if (!(msk = im_vips2mask(t, filename))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } DOUBLEMASK * im_gauss_dmask_sep(const char *filename, double sigma, double min_ampl) { VipsImage *t; DOUBLEMASK *msk; if (vips_gaussmat(&t, sigma, min_ampl, "precision", VIPS_PRECISION_FLOAT, "separable", TRUE, NULL)) return NULL; if (!(msk = im_vips2mask(t, filename))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } INTMASK * im_gauss_imask(const char *filename, double sigma, double min_ampl) { VipsImage *t; INTMASK *msk; if (vips_gaussmat(&t, sigma, min_ampl, NULL)) return NULL; if (!(msk = im_vips2imask(t, filename))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } INTMASK * im_gauss_imask_sep(const char *filename, double sigma, double min_ampl) { VipsImage *t; INTMASK *msk; if (vips_gaussmat(&t, sigma, min_ampl, "separable", TRUE, NULL)) return NULL; if (!(msk = im_vips2imask(t, filename))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } INTMASK * im_log_imask(const char *filename, double sigma, double min_ampl) { VipsImage *t; INTMASK *msk; if (vips_logmat(&t, sigma, min_ampl, NULL)) return NULL; if (!(msk = im_vips2imask(t, filename))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } DOUBLEMASK * im_log_dmask(const char *filename, double sigma, double min_ampl) { VipsImage *t; DOUBLEMASK *msk; if (vips_logmat(&t, sigma, min_ampl, "precision", VIPS_PRECISION_FLOAT, NULL)) return NULL; if (!(msk = im_vips2mask(t, filename))) { g_object_unref(t); return NULL; } g_object_unref(t); return msk; } int im_recomb(IMAGE *in, IMAGE *out, DOUBLEMASK *recomb) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_mask2vips(recomb, t1)) return -1; if (vips_recomb(in, &t2, t1, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_compass(VipsImage *in, VipsImage *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_compass(in, &t2, t1, "times", 8, "angle", VIPS_ANGLE45_D45, "precision", VIPS_PRECISION_INTEGER, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_lindetect(IMAGE *in, IMAGE *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_compass(in, &t2, t1, "times", 4, "angle", VIPS_ANGLE45_D45, "precision", VIPS_PRECISION_INTEGER, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_gradient(IMAGE *in, IMAGE *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_compass(in, &t2, t1, "times", 2, "angle", VIPS_ANGLE45_D90, "combine", VIPS_COMBINE_SUM, "precision", VIPS_PRECISION_INTEGER, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_convsep_raw(IMAGE *in, IMAGE *out, INTMASK *mask) { im_error("im_convsep_raw", "no compat function"); return -1; } int im_convsep(IMAGE *in, IMAGE *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_convsep(in, &t2, t1, "precision", VIPS_PRECISION_INTEGER, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_convsep_f_raw(IMAGE *in, IMAGE *out, DOUBLEMASK *mask) { im_error("im_convsep_raw", "no compat function"); return -1; } int im_convsep_f(IMAGE *in, IMAGE *out, DOUBLEMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_mask2vips(mask, t1)) return -1; if (vips_convsep(in, &t2, t1, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_conv(VipsImage *in, VipsImage *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_convi(in, &t2, t1, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_conv_raw(VipsImage *in, VipsImage *out, INTMASK *mask) { im_error("im_conv_raw", "no compat function"); return -1; } int im_conv_f(VipsImage *in, VipsImage *out, DOUBLEMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_mask2vips(mask, t1)) return -1; if (vips_convf(in, &t2, t1, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_aconvsep(VipsImage *in, VipsImage *out, DOUBLEMASK *mask, int n_layers) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_mask2vips(mask, t1)) return -1; if (vips_convasep(in, &t2, t1, "layers", n_layers, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_aconv(VipsImage *in, VipsImage *out, DOUBLEMASK *mask, int n_layers, int cluster) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_mask2vips(mask, t1)) return -1; if (vips_conva(in, &t2, t1, "layers", n_layers, "cluster", cluster, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_conv_f_raw(VipsImage *in, VipsImage *out, DOUBLEMASK *mask) { im_error("im_conv_f_raw", "no compat function"); return -1; } int im_addgnoise(IMAGE *in, IMAGE *out, double sigma) { IMAGE *t; if (!(t = im_open_local(out, "im_addgnoise", "p")) || im_gaussnoise(t, in->Xsize, in->Ysize, 0, sigma) || im_add(in, t, out)) return -1; return 0; } int im_contrast_surface_raw(IMAGE *in, IMAGE *out, int half_win_size, int spacing) { im_error("im_contrast_surface_raw", "no compat function"); return -1; } /* This replaces some custom code in 7.36 and earlier. The hand-made one was * slower for spacing == 1, though faster for large values of spacing. * * Not worth maintaining a special operator for. */ int im_contrast_surface(IMAGE *in, IMAGE *out, int half_win_size, int spacing) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 10); int size = half_win_size * 2; int x, y; t[0] = vips_image_new_matrixv(1, 2, -1.0, 1.0); t[1] = vips_image_new_matrixv(2, 1, -1.0, 1.0); t[8] = vips_image_new_matrix(size, size); for (y = 0; y < size; y++) for (x = 0; x < size; x++) *VIPS_MATRIX(t[8], x, y) = 1.0; if (vips_conv(in, &t[2], t[0], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_conv(in, &t[3], t[1], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_abs(t[2], &t[4], NULL) || vips_abs(t[3], &t[5], NULL) || vips_add(t[4], t[5], &t[6], NULL) || vips_conv(t[6], &t[7], t[8], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_subsample(t[7], &t[9], spacing, spacing, NULL) || vips_image_write(t[9], out)) return -1; return 0; } int im_spcor_raw(IMAGE *in, IMAGE *ref, IMAGE *out) { im_error("im_spcor_raw", "no compat function"); return -1; } int im_spcor(IMAGE *in, IMAGE *ref, IMAGE *out) { VipsImage *x; if (vips_call("spcor", in, ref, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_fastcor_raw(IMAGE *in, IMAGE *ref, IMAGE *out) { im_error("im_fastcor_raw", "no compat function"); return -1; } int im_fastcor(IMAGE *in, IMAGE *ref, IMAGE *out) { VipsImage *x; if (vips_call("fastcor", in, ref, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_sharpen(IMAGE *in, IMAGE *out, int mask_size, double x1, double y2, double y3, double m1, double m2) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 2); /* im_sharpen() always recoded as labq and im_benchmark() depends * upon this behaviour. */ if (vips_call("sharpen", in, &t[0], "sigma", mask_size / 4.0, "x1", x1, "y2", y2, "y3", y3, "m1", m1, "m2", m2, NULL) || vips_colourspace(t[0], &t[1], VIPS_INTERPRETATION_LABQ, NULL) || vips_image_write(t[1], out)) return -1; return 0; } static int vips__round(VipsImage *in, VipsImage *out, VipsOperationRound round) { VipsImage *t; if (vips_round(in, &t, round, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_rint(IMAGE *in, IMAGE *out) { return vips__round(in, out, VIPS_OPERATION_ROUND_RINT); } int im_floor(IMAGE *in, IMAGE *out) { return vips__round(in, out, VIPS_OPERATION_ROUND_FLOOR); } int im_ceil(IMAGE *in, IMAGE *out) { return vips__round(in, out, VIPS_OPERATION_ROUND_CEIL); } static int vips__relational(IMAGE *in1, IMAGE *in2, IMAGE *out, VipsOperationRelational relational) { VipsImage *t; if (vips_relational(in1, in2, &t, relational, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_equal(IMAGE *in1, IMAGE *in2, IMAGE *out) { return vips__relational(in1, in2, out, VIPS_OPERATION_RELATIONAL_EQUAL); } int im_notequal(IMAGE *in1, IMAGE *in2, IMAGE *out) { return vips__relational(in1, in2, out, VIPS_OPERATION_RELATIONAL_NOTEQ); } int im_less(IMAGE *in1, IMAGE *in2, IMAGE *out) { return vips__relational(in1, in2, out, VIPS_OPERATION_RELATIONAL_LESS); } int im_lesseq(IMAGE *in1, IMAGE *in2, IMAGE *out) { return vips__relational(in1, in2, out, VIPS_OPERATION_RELATIONAL_LESSEQ); } int im_more(IMAGE *in1, IMAGE *in2, IMAGE *out) { return vips__relational(in1, in2, out, VIPS_OPERATION_RELATIONAL_MORE); } int im_moreeq(IMAGE *in1, IMAGE *in2, IMAGE *out) { return vips__relational(in1, in2, out, VIPS_OPERATION_RELATIONAL_MOREEQ); } static int vips__relational_vec(IMAGE *in, IMAGE *out, VipsOperationRelational relational, double *c, int n) { VipsImage *t; if (vips_relational_const(in, &t, relational, c, n, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_equal_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__relational_vec(in, out, VIPS_OPERATION_RELATIONAL_EQUAL, c, n); } int im_notequal_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__relational_vec(in, out, VIPS_OPERATION_RELATIONAL_NOTEQ, c, n); } int im_less_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__relational_vec(in, out, VIPS_OPERATION_RELATIONAL_LESS, c, n); } int im_lesseq_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__relational_vec(in, out, VIPS_OPERATION_RELATIONAL_LESSEQ, c, n); } int im_more_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__relational_vec(in, out, VIPS_OPERATION_RELATIONAL_MORE, c, n); } int im_moreeq_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__relational_vec(in, out, VIPS_OPERATION_RELATIONAL_MOREEQ, c, n); } int im_equalconst(IMAGE *in, IMAGE *out, double c) { return im_equal_vec(in, out, 1, &c); } int im_notequalconst(IMAGE *in, IMAGE *out, double c) { return im_notequal_vec(in, out, 1, &c); } int im_lessconst(IMAGE *in, IMAGE *out, double c) { return im_less_vec(in, out, 1, &c); } int im_lesseqconst(IMAGE *in, IMAGE *out, double c) { return im_lesseq_vec(in, out, 1, &c); } int im_moreconst(IMAGE *in, IMAGE *out, double c) { return im_more_vec(in, out, 1, &c); } int im_moreeqconst(IMAGE *in, IMAGE *out, double c) { return im_moreeq_vec(in, out, 1, &c); } int im_remainder(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *t; if (vips_remainder(in1, in2, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_remainder_vec(IMAGE *in, IMAGE *out, int n, double *c) { VipsImage *t; if (vips_remainder_const(in, &t, c, n, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_remainderconst(IMAGE *in, IMAGE *out, double c) { return im_remainder_vec(in, out, 1, &c); } static int vips__boolean(IMAGE *in1, IMAGE *in2, IMAGE *out, VipsOperationBoolean boolean) { VipsImage *t; if (vips_boolean(in1, in2, &t, boolean, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_andimage(VipsImage *in1, VipsImage *in2, VipsImage *out) { return vips__boolean(in1, in2, out, VIPS_OPERATION_BOOLEAN_AND); } int im_orimage(VipsImage *in1, VipsImage *in2, VipsImage *out) { return vips__boolean(in1, in2, out, VIPS_OPERATION_BOOLEAN_OR); } int im_eorimage(VipsImage *in1, VipsImage *in2, VipsImage *out) { return vips__boolean(in1, in2, out, VIPS_OPERATION_BOOLEAN_EOR); } static int vips__boolean_vec(IMAGE *in, IMAGE *out, VipsOperationBoolean boolean, double *c, int n) { VipsImage *t; if (vips_boolean_const(in, &t, boolean, c, n, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_andimage_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__boolean_vec(in, out, VIPS_OPERATION_BOOLEAN_AND, c, n); } int im_orimage_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__boolean_vec(in, out, VIPS_OPERATION_BOOLEAN_OR, c, n); } int im_eorimage_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__boolean_vec(in, out, VIPS_OPERATION_BOOLEAN_EOR, c, n); } int im_shiftleft_vec(IMAGE *in, IMAGE *out, int n, double *c) { return vips__boolean_vec(in, out, VIPS_OPERATION_BOOLEAN_LSHIFT, c, n); } int im_shiftright_vec(IMAGE *in, IMAGE *out, int n, double *c) { return vips__boolean_vec(in, out, VIPS_OPERATION_BOOLEAN_RSHIFT, c, n); } int im_andimageconst(IMAGE *in, IMAGE *out, double c) { return im_andimage_vec(in, out, 1, &c); } int im_orimageconst(IMAGE *in, IMAGE *out, double c) { return im_orimage_vec(in, out, 1, &c); } int im_eorimageconst(IMAGE *in, IMAGE *out, double c) { return im_eorimage_vec(in, out, 1, &c); } int im_shiftleft(IMAGE *in, IMAGE *out, int n) { double c = n; return im_shiftleft_vec(in, out, 1, &c); } int im_shiftright(IMAGE *in, IMAGE *out, int n) { double c = n; return im_shiftright_vec(in, out, 1, &c); } static int vips__math2_vec(IMAGE *in, IMAGE *out, VipsOperationMath2 math2, double *c, int n) { VipsImage *t; if (vips_math2_const(in, &t, math2, c, n, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_powtra_vec(VipsImage *in, VipsImage *out, int n, double *c) { return vips__math2_vec(in, out, VIPS_OPERATION_MATH2_POW, c, n); } int im_powtra(IMAGE *in, IMAGE *out, double c) { return im_powtra_vec(in, out, 1, &c); } int im_expntra_vec(IMAGE *in, IMAGE *out, int n, double *c) { return vips__math2_vec(in, out, VIPS_OPERATION_MATH2_WOP, c, n); } int im_expntra(IMAGE *in, IMAGE *out, double c) { return im_expntra_vec(in, out, 1, &c); } int im_ifthenelse(VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out) { VipsImage *t; if (vips_ifthenelse(c, a, b, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_blend(VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out) { VipsImage *t; if (vips_ifthenelse(c, a, b, &t, "blend", TRUE, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int vips__complex(VipsImage *in, VipsImage *out, VipsOperationComplex cmplx) { VipsImage *t; if (vips_complex(in, &t, cmplx, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_c2amph(IMAGE *in, IMAGE *out) { return vips__complex(in, out, VIPS_OPERATION_COMPLEX_POLAR); } int im_c2rect(IMAGE *in, IMAGE *out) { return vips__complex(in, out, VIPS_OPERATION_COMPLEX_RECT); } static int vips__complexget(VipsImage *in, VipsImage *out, VipsOperationComplexget get) { VipsImage *t; if (vips_complexget(in, &t, get, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_c2real(IMAGE *in, IMAGE *out) { return vips__complexget(in, out, VIPS_OPERATION_COMPLEXGET_REAL); } int im_c2imag(IMAGE *in, IMAGE *out) { return vips__complexget(in, out, VIPS_OPERATION_COMPLEXGET_IMAG); } int im_ri2c(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_call("complexform", in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_cache(VipsImage *in, VipsImage *out, int width, int height, int max) { return vips_sink_screen(in, out, NULL, width, height, max, 0, NULL, NULL); } int im_argb2rgba(VipsImage *in, VipsImage *out) { /* No longer exists, just a null op. */ return vips_image_write(in, out); } int im_shrink(VipsImage *in, VipsImage *out, double xshrink, double yshrink) { VipsImage *x; if (vips_shrink(in, &x, xshrink, yshrink, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_eye(IMAGE *out, const int xsize, const int ysize, const double factor) { VipsImage *x; if (vips_eye(&x, xsize, ysize, "factor", factor, "uchar", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_feye(IMAGE *out, const int xsize, const int ysize, const double factor) { VipsImage *x; if (vips_eye(&x, xsize, ysize, "factor", factor, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_grey(IMAGE *out, const int xsize, const int ysize) { VipsImage *x; if (vips_grey(&x, xsize, ysize, "uchar", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_fgrey(IMAGE *out, const int xsize, const int ysize) { VipsImage *x; if (vips_grey(&x, xsize, ysize, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_buildlut(DOUBLEMASK *input, VipsImage *out) { VipsImage *mat; VipsImage *x; mat = vips_image_new(); if (im_mask2vips(input, mat)) return -1; if (vips_buildlut(mat, &x, NULL)) { g_object_unref(mat); return -1; } g_object_unref(mat); if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_invertlut(DOUBLEMASK *input, VipsImage *out, int size) { VipsImage *mat; VipsImage *x; mat = vips_image_new(); if (im_mask2vips(input, mat)) return -1; if (vips_invertlut(mat, &x, "size", size, NULL)) { g_object_unref(mat); return -1; } g_object_unref(mat); if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_tone_build_range(IMAGE *out, int in_max, int out_max, double Lb, double Lw, double Ps, double Pm, double Ph, double S, double M, double H) { VipsImage *t; if (vips_tonelut(&t, "in_max", in_max, "out_max", out_max, "Lb", Lb, "Lw", Lw, "Ps", Ps, "Pm", Pm, "Ph", Ph, "S", S, "M", M, "H", H, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_tone_build(IMAGE *out, double Lb, double Lw, double Ps, double Pm, double Ph, double S, double M, double H) { IMAGE *t1; if (!(t1 = im_open_local(out, "im_tone_build", "p")) || im_tone_build_range(t1, 32767, 32767, Lb, Lw, Ps, Pm, Ph, S, M, H) || im_clip2fmt(t1, out, IM_BANDFMT_SHORT)) return -1; return 0; } int im_rightshift_size(IMAGE *in, IMAGE *out, int xshift, int yshift, int band_fmt) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 2); if (vips_shrink(in, &t[0], 1 << xshift, 1 << yshift, NULL) || vips_cast(t[0], &t[1], band_fmt, NULL) || vips_image_write(t[1], out)) return -1; return 0; } int im_Lab2XYZ_temp(IMAGE *in, IMAGE *out, double X0, double Y0, double Z0) { VipsArea *temp; VipsImage *x; temp = VIPS_AREA(vips_array_double_newv(3, X0, Y0, Z0)); if (vips_Lab2XYZ(in, &x, "temp", temp, NULL)) { vips_area_unref(temp); return -1; } vips_area_unref(temp); if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_Lab2XYZ(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_Lab2XYZ(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_XYZ2Lab_temp(IMAGE *in, IMAGE *out, double X0, double Y0, double Z0) { double ary[3]; VipsArea *temp; VipsImage *x; ary[0] = X0; ary[1] = Y0; ary[2] = Z0; temp = VIPS_AREA(vips_array_double_new(ary, 3)); if (vips_XYZ2Lab(in, &x, "temp", temp, NULL)) { vips_area_unref(temp); return -1; } vips_area_unref(temp); if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_XYZ2Lab(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_XYZ2Lab(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_Lab2LCh(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_Lab2LCh(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_LCh2Lab(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LCh2Lab(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_LCh2UCS(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LCh2CMC(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_UCS2LCh(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_CMC2LCh(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_XYZ2Yxy(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_XYZ2Yxy(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_Yxy2XYZ(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_Yxy2XYZ(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_float2rad(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_float2rad(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_rad2float(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_rad2float(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_Lab2LabQ(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_Lab2LabQ(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_LabQ2Lab(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LabQ2Lab(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_Lab2LabS(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_Lab2LabS(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_LabS2Lab(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LabS2Lab(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_LabQ2LabS(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LabQ2LabS(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_LabS2LabQ(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LabS2LabQ(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_Lab2disp(IMAGE *in, IMAGE *out, struct im_col_display *disp) { IMAGE *t[1]; if (im_open_local_array(out, t, 1, "im_Lab2disp:1", "p") || im_Lab2XYZ(in, t[0]) || im_XYZ2disp(t[0], out, disp)) return -1; return 0; } int im_dECMC_fromdisp(IMAGE *im1, IMAGE *im2, IMAGE *out, struct im_col_display *d) { IMAGE *t[4]; if (im_open_local_array(out, t, 4, "im_dECMC_fromdisp:1", "p") || im_disp2XYZ(im1, t[0], d) || im_XYZ2Lab(t[0], t[1]) || im_disp2XYZ(im2, t[2], d) || im_XYZ2Lab(t[2], t[3]) || im_dECMC_fromLab(t[1], t[3], out)) return -1; return 0; } int im_dE_fromdisp(IMAGE *im1, IMAGE *im2, IMAGE *out, struct im_col_display *d) { IMAGE *t[2]; if (im_open_local_array(out, t, 2, "im_dE_fromdisp:1", "p") || im_disp2XYZ(im1, t[0], d) || im_disp2XYZ(im2, t[1], d) || im_dE_fromXYZ(t[0], t[1], out)) return -1; return 0; } int im_disp2Lab(IMAGE *in, IMAGE *out, struct im_col_display *d) { VipsImage *t[1]; if (im_open_local_array(out, t, 1, "im_disp2Lab:1", "p") || im_disp2XYZ(in, t[0], d) || im_XYZ2Lab(t[0], out)) return -1; return 0; } int im_sRGB2XYZ(IMAGE *in, IMAGE *out) { VipsImage **t = (VipsImage **) vips_object_local_array((VipsObject *) out, 2); if (vips_sRGB2scRGB(in, &t[0], NULL) || vips_scRGB2XYZ(t[0], &t[1], NULL) || vips_image_write(t[1], out)) return -1; return 0; } int im_XYZ2sRGB(IMAGE *in, IMAGE *out) { VipsImage **t = (VipsImage **) vips_object_local_array((VipsObject *) out, 2); if (vips_XYZ2scRGB(in, &t[0], NULL) || vips_scRGB2sRGB(t[0], &t[1], NULL) || vips_image_write(t[1], out)) return -1; return 0; } int im_LabQ2sRGB(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_LabQ2sRGB(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_icc_transform(VipsImage *in, VipsImage *out, const char *input_profile_filename, const char *output_profile_filename, VipsIntent intent) { VipsImage *x; if (vips_icc_transform(in, &x, output_profile_filename, "input_profile", input_profile_filename, "intent", intent, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_icc_import(VipsImage *in, VipsImage *out, const char *input_profile_filename, VipsIntent intent) { VipsImage *x; if (vips_icc_import(in, &x, "input_profile", input_profile_filename, "intent", intent, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_icc_import_embedded(VipsImage *in, VipsImage *out, VipsIntent intent) { VipsImage *x; if (vips_icc_import(in, &x, "embedded", TRUE, "intent", intent, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_icc_export_depth(VipsImage *in, VipsImage *out, int depth, const char *output_profile_filename, VipsIntent intent) { VipsImage *x; if (vips_icc_export(in, &x, "output_profile", output_profile_filename, "depth", depth, "intent", intent, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } /** * im_LabQ2XYZ: * @in: input image * @out: output image * * Convert an image from LabQ (Coding == IM_CODING_LABQ) to XYZ. * * Returns: 0 on success, -1 on error. */ int im_LabQ2XYZ(IMAGE *in, IMAGE *out) { IMAGE *t[1]; if (im_open_local_array(out, t, 1, "im_LabQ2XYZ:1", "p") || im_LabQ2Lab(in, t[0]) || im_Lab2XYZ(t[0], out)) return -1; return 0; } int im_Lab2UCS(IMAGE *in, IMAGE *out) { IMAGE *t[1]; if (im_open_local_array(out, t, 1, "im_Lab2UCS:1", "p") || im_Lab2LCh(in, t[0]) || im_LCh2UCS(t[0], out)) return -1; return 0; } int im_UCS2Lab(IMAGE *in, IMAGE *out) { IMAGE *t[1]; if (im_open_local_array(out, t, 1, "im_UCS2Lab:1", "p") || im_UCS2LCh(in, t[0]) || im_LCh2Lab(t[0], out)) return -1; return 0; } int im_UCS2XYZ(IMAGE *in, IMAGE *out) { IMAGE *t[1]; if (im_open_local_array(out, t, 1, "im_UCS2XYZ:1", "p") || im_UCS2Lab(in, t[0]) || im_Lab2XYZ(t[0], out)) return -1; return 0; } int im_XYZ2UCS(IMAGE *in, IMAGE *out) { IMAGE *t[1]; if (im_open_local_array(out, t, 1, "im_XYZ2UCS:1", "p") || im_XYZ2Lab(in, t[0]) || im_Lab2UCS(t[0], out)) return -1; return 0; } int im_dE_fromXYZ(IMAGE *in1, IMAGE *in2, IMAGE *out) { IMAGE *t[2]; if (im_open_local_array(out, t, 2, "im_dE_fromXYZ:1", "p") || im_XYZ2Lab(in1, t[0]) || im_XYZ2Lab(in2, t[1]) || im_dE_fromLab(t[0], t[1], out)) return -1; return 0; } int im_dE_fromLab(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_dE76(in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_dECMC_fromLab(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_dECMC(in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_dE00_fromLab(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_dE00(in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_icc_ac2rc(VipsImage *in, VipsImage *out, const char *profile_filename) { VipsImage *x; if (vips_icc_ac2rc(in, &x, profile_filename)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_quadratic(IMAGE *in, IMAGE *out, IMAGE *coeff) { VipsImage *x; if (vips_quadratic(in, &x, coeff, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_maxpos_vec(VipsImage *im, int *xpos, int *ypos, double *maxima, int n) { double max; VipsArrayDouble *out_array; VipsArrayInt *x_array; VipsArrayInt *y_array; if (vips_max(im, &max, "size", n, "out_array", &out_array, "x_array", &x_array, "y_array", &y_array, NULL)) return -1; memcpy(xpos, VIPS_ARRAY_ADDR(x_array, 0), n * sizeof(int)); memcpy(ypos, VIPS_ARRAY_ADDR(y_array, 0), n * sizeof(int)); memcpy(maxima, VIPS_ARRAY_ADDR(out_array, 0), n * sizeof(double)); vips_area_unref(VIPS_AREA(out_array)); vips_area_unref(VIPS_AREA(x_array)); vips_area_unref(VIPS_AREA(y_array)); return 0; } int im_minpos_vec(VipsImage *im, int *xpos, int *ypos, double *minima, int n) { double min; VipsArrayDouble *out_array; VipsArrayInt *x_array; VipsArrayInt *y_array; if (vips_min(im, &min, "size", n, "out_array", &out_array, "x_array", &x_array, "y_array", &y_array, NULL)) return -1; memcpy(xpos, VIPS_ARRAY_ADDR(x_array, 0), n * sizeof(int)); memcpy(ypos, VIPS_ARRAY_ADDR(y_array, 0), n * sizeof(int)); memcpy(minima, VIPS_ARRAY_ADDR(out_array, 0), n * sizeof(double)); vips_area_unref(VIPS_AREA(out_array)); vips_area_unref(VIPS_AREA(x_array)); vips_area_unref(VIPS_AREA(y_array)); return 0; } int im_cross_phase(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_call("cross_phase", in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_maplut(IMAGE *in, IMAGE *out, IMAGE *lut) { VipsImage *x; if (vips_maplut(in, &x, lut, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_ismonotonic(IMAGE *lut, int *out) { gboolean monotonic; if (vips_hist_ismonotonic(lut, &monotonic, NULL)) return -1; *out = monotonic ? 255 : 0; return 0; } int im_histcum(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_hist_cum(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_histnorm(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_hist_norm(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_histeq(IMAGE *in, IMAGE *out) { IMAGE *t1; if (!(t1 = im_open_local(out, "im_histeq", "p")) || im_histcum(in, t1) || im_histnorm(t1, out)) return -1; return 0; } int im_heq(VipsImage *in, VipsImage *out, int bandno) { VipsImage *x; if (vips_hist_equal(in, &x, "band", bandno, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_hist(IMAGE *in, IMAGE *out, int bandno) { IMAGE *hist; if (!(hist = im_open_local(out, "im_hist", "p")) || im_histgr(in, hist, bandno) || im_histplot(hist, out)) return -1; return 0; } int im_histgr(IMAGE *in, IMAGE *out, int bandno) { VipsImage *x; if (vips_hist_find(in, &x, "band", bandno, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_stdif(IMAGE *in, IMAGE *out, double a, double m0, double b, double s0, int width, int height) { VipsImage *x; if (vips_stdif(in, &x, width, height, "a", a, "b", b, "m0", m0, "s0", s0, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_lhisteq(VipsImage *in, VipsImage *out, int width, int height) { VipsImage *x; if (vips_hist_local(in, &x, width, height, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_histnD(VipsImage *in, VipsImage *out, int bins) { VipsImage *x; if (vips_hist_find_ndim(in, &x, "bins", bins, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_hist_indexed(VipsImage *index, VipsImage *value, VipsImage *out) { VipsImage *x; if (vips_hist_find_indexed(value, index, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_project(IMAGE *in, IMAGE *hout, IMAGE *vout) { VipsImage *x, *y; if (vips_project(in, &x, &y, NULL)) return -1; if (vips_image_write(x, hout)) { g_object_unref(x); g_object_unref(y); return -1; } g_object_unref(x); if (vips_image_write(y, vout)) { g_object_unref(y); return -1; } g_object_unref(y); return 0; } int im_profile(IMAGE *in, IMAGE *out, int dir) { VipsImage *columns, *rows; VipsImage *t1, *t2; if (vips_profile(in, &columns, &rows, NULL)) return -1; if (dir == 0) { t1 = columns; g_object_unref(rows); } else { t1 = rows; g_object_unref(columns); } if (vips_cast(t1, &t2, VIPS_FORMAT_USHORT, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_erode(IMAGE *in, IMAGE *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_morph(in, &t2, t1, VIPS_OPERATION_MORPHOLOGY_ERODE, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_erode_raw(IMAGE *in, IMAGE *out, INTMASK *m) { return im_erode(in, out, m); } int im_dilate(IMAGE *in, IMAGE *out, INTMASK *mask) { VipsImage *t1, *t2; if (!(t1 = vips_image_new()) || im_imask2vips(mask, t1)) return -1; if (vips_morph(in, &t2, t1, VIPS_OPERATION_MORPHOLOGY_DILATE, NULL)) { g_object_unref(t1); return -1; } g_object_unref(t1); if (vips_image_write(t2, out)) { g_object_unref(t2); return -1; } g_object_unref(t2); return 0; } int im_dilate_raw(IMAGE *in, IMAGE *out, INTMASK *m) { return im_dilate(in, out, m); } int im_mpercent(IMAGE *in, double percent, int *out) { if (vips_percent(in, percent * 100.0, out, NULL)) return -1; return 0; } int im_mpercent_hist(IMAGE *in, double percent, int *out) { /* Hard to do this in a wrapper. */ vips_error("im_mpercent_hist", "%s", _("no compat implemented")); return -1; } int im_hsp(IMAGE *in, IMAGE *ref, IMAGE *out) { IMAGE *t[3]; if (im_open_local_array(out, t, 3, "im_hsp", "p") || im_histgr(in, t[0], -1) || im_histgr(ref, t[1], -1) || im_histspec(t[0], t[1], t[2]) || im_maplut(in, out, t[2])) return -1; return 0; } static int match(VipsImage *in, VipsImage *ref, VipsImage *out) { VipsImage *x; if (vips_hist_match(in, ref, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_histspec(IMAGE *in, IMAGE *ref, IMAGE *out) { IMAGE *t[5]; guint64 px; int fmt; if (im_check_uint("im_histspec", in) || im_check_uint("im_histspec", ref)) return -1; if (im_open_local_array(out, t, 5, "im_histspec", "p") || im_histeq(in, t[0]) || im_histeq(ref, t[2]) || match(t[0], t[2], t[4])) return -1; px = VIPS_IMAGE_N_PELS(t[4]); if (px <= 256) fmt = IM_BANDFMT_UCHAR; else if (px <= 65536) fmt = IM_BANDFMT_USHORT; else fmt = IM_BANDFMT_UINT; if (im_clip2fmt(t[4], out, fmt)) return -1; return 0; } int im_falsecolour(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_falsecolour(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_gammacorrect(IMAGE *in, IMAGE *out, double exponent) { VipsImage *x; if (vips_gamma(in, &x, "exponent", 1.0 / exponent, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } /* This is used by the carrierwave shrinker to cache the * output of shrink before doing the final affine. * * We use the vips8 threaded tilecache to avoid a deadlock: suppose thread1, * evaluating the top block of the output is delayed, and thread2, evaluating * the second block gets here first (this can happen on a heavily-loaded * system). * * With an unthreaded tilecache (as we had before), thread2 will get * the cache lock and start evaling the second block of the shrink. When it * reaches the png reader it will stall until the first block has been used ... * but it never will, since thread1 will block on this cache lock. * * This function is only used in this place (I think), so it's OK to * hard-wire this to be a sequential threaded cache. */ int im_tile_cache(IMAGE *in, IMAGE *out, int tile_width, int tile_height, int max_tiles) { VipsImage *x; if (vips_tilecache(in, &x, "tile_width", tile_width, "tile_height", tile_height, "max_tiles", max_tiles, "access", VIPS_ACCESS_SEQUENTIAL, "threaded", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } /* This is the one used by nip2's menu for caching images. Random access and * persistent. */ int im_tile_cache_random(IMAGE *in, IMAGE *out, int tile_width, int tile_height, int max_tiles) { VipsImage *x; if (vips_tilecache(in, &x, "tile_width", tile_width, "tile_height", tile_height, "max_tiles", max_tiles, "access", VIPS_ACCESS_RANDOM, "persistent", TRUE, "threaded", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } static int im__affinei(VipsImage *in, VipsImage *out, VipsInterpolate *interpolate, VipsTransformation *trn) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 2); VipsArea *oarea; gboolean repack; oarea = VIPS_AREA(vips_array_int_newv(4, trn->oarea.left, trn->oarea.top, trn->oarea.width, trn->oarea.height)); /* vips7 affine would repack labq and im_benchmark() depends upon * this. */ repack = in->Coding == IM_CODING_LABQ; if (vips_affine(in, &t[0], trn->a, trn->b, trn->c, trn->d, "interpolate", interpolate, "oarea", oarea, "odx", trn->odx, "ody", trn->ody, NULL)) { vips_area_unref(oarea); return -1; } vips_area_unref(oarea); in = t[0]; if (repack) { if (vips_colourspace(in, &t[1], VIPS_INTERPRETATION_LABQ, NULL)) return -1; in = t[1]; } if (vips_image_write(in, out)) return -1; return 0; } int im_affinei(VipsImage *in, VipsImage *out, VipsInterpolate *interpolate, double a, double b, double c, double d, double odx, double ody, int ox, int oy, int ow, int oh) { VipsTransformation trn; trn.iarea.left = 0; trn.iarea.top = 0; trn.iarea.width = in->Xsize; trn.iarea.height = in->Ysize; trn.oarea.left = ox; trn.oarea.top = oy; trn.oarea.width = ow; trn.oarea.height = oh; trn.a = a; trn.b = b; trn.c = c; trn.d = d; trn.idx = 0; trn.idy = 0; trn.odx = odx; trn.ody = ody; return im__affinei(in, out, interpolate, &trn); } int im_affinei_all(VipsImage *in, VipsImage *out, VipsInterpolate *interpolate, double a, double b, double c, double d, double odx, double ody) { VipsTransformation trn; trn.iarea.left = 0; trn.iarea.top = 0; trn.iarea.width = in->Xsize; trn.iarea.height = in->Ysize; trn.a = a; trn.b = b; trn.c = c; trn.d = d; trn.idx = 0; trn.idy = 0; trn.odx = odx; trn.ody = ody; vips__transform_set_area(&trn); return im__affinei(in, out, interpolate, &trn); } /* Still needed by some parts of mosaic. */ int vips__affine(VipsImage *in, VipsImage *out, VipsTransformation *trn) { return im__affinei(in, out, vips_interpolate_bilinear_static(), trn); } int im_copy_file(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_copy_file(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_video_v4l1(IMAGE *im, const char *device, int channel, int brightness, int colour, int contrast, int hue, int ngrabs) { im_error("im_video_v4l1", "%s", _("compiled without im_video_v4l1 support")); return -1; } int im_fwfft(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_fwfft(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_invfft(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_invfft(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_invfftr(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_invfft(in, &x, "real", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_freqflt(IMAGE *in, IMAGE *mask, IMAGE *out) { VipsImage *x; if (vips_freqmult(in, mask, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_disp_ps(IMAGE *in, IMAGE *out) { VipsImage *t; if (vips_spectrum(in, &t, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_fractsurf(IMAGE *out, int size, double frd) { VipsImage *t; if (vips_fractsurf(&t, size, size, frd, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } int im_phasecor_fft(IMAGE *in1, IMAGE *in2, IMAGE *out) { VipsImage *x; if (vips_phasecor(in1, in2, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_cntlines(VipsImage *im, double *nolines, int flag) { return vips_countlines(im, nolines, flag == 0 ? VIPS_DIRECTION_HORIZONTAL : VIPS_DIRECTION_VERTICAL, NULL); } int im_label_regions(IMAGE *test, IMAGE *mask, int *segments) { VipsImage *x; if (vips_labelregions(test, &x, "segments", segments, NULL)) return -1; if (vips_image_write(x, mask)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_rank(IMAGE *in, IMAGE *out, int width, int height, int index) { VipsImage *x; if (vips_rank(in, &x, width, height, index, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_rank_raw(IMAGE *in, IMAGE *out, int width, int height, int index) { im_error("im_rank_raw", "no compat function"); return -1; } int im_draw_circle(VipsImage *image, int x, int y, int radius, gboolean fill, VipsPel *ink) { double *vec; int n; if (!(vec = vips__ink_to_vector("im_draw_circle", image, ink, &n))) return -1; return vips_draw_circle(image, vec, n, x, y, radius, "fill", fill, NULL); } int im_draw_line(VipsImage *image, int x1, int y1, int x2, int y2, VipsPel *ink) { double *vec; int n; if (!(vec = vips__ink_to_vector("im_draw_line", image, ink, &n))) return -1; return vips_draw_line(image, vec, n, x1, y1, x2, y2, NULL); } typedef struct _Line { VipsPlotFn plot; void *a; void *b; void *c; } Line; static void draw_line_wrapper(VipsImage *image, int x, int y, void *client) { Line *line = (Line *) client; line->plot(image, x, y, line->a, line->b, line->c); } int im_draw_line_user(VipsImage *image, int x1, int y1, int x2, int y2, VipsPlotFn plot, void *a, void *b, void *c) { Line line; line.plot = plot; line.a = a; line.b = b; line.c = c; vips__draw_line_direct(image, x1, y1, x2, y2, draw_line_wrapper, &line); return 0; } int im_draw_mask(VipsImage *image, VipsImage *mask, int x, int y, VipsPel *ink) { /* Direct call, since this has to be very quick. */ return vips__draw_mask_direct(image, mask, ink, x, y); } int im_draw_image(VipsImage *image, VipsImage *sub, int x, int y) { return vips_draw_image(image, sub, x, y, NULL); } int im_draw_rect(IMAGE *image, int left, int top, int width, int height, int fill, VipsPel *ink) { double *vec; int n; if (!(vec = vips__ink_to_vector("im_draw_rect", image, ink, &n))) return -1; return vips_draw_rect(image, vec, n, left, top, width, height, "fill", fill, NULL); } int im_draw_point(VipsImage *image, int x, int y, VipsPel *ink) { double *vec; int n; if (!(vec = vips__ink_to_vector("im_draw_rect", image, ink, &n))) return -1; return vips_draw_point(image, vec, n, x, y, NULL); } int im_draw_smudge(VipsImage *im, int left, int top, int width, int height) { return vips_draw_smudge(im, left, top, width, height, NULL); } int im_read_point(VipsImage *image, int x, int y, VipsPel *ink) { double *vector; int n; VipsPel *pixel_vector; if (vips_getpoint(image, &vector, &n, x, y, NULL)) return -1; if (!(pixel_vector = vips__vector_to_ink("im_read_point", image, vector, NULL, n))) { g_free(vector); return -1; } memcpy(ink, pixel_vector, VIPS_IMAGE_SIZEOF_PEL(image)); g_free(vector); return 0; } int im_draw_flood(IMAGE *image, int x, int y, VipsPel *ink, Rect *dout) { double *vec; int n; int left; int top; int width; int height; if (!(vec = vips__ink_to_vector("im_draw_flood", image, ink, &n))) return -1; if (vips_draw_flood(image, vec, n, x, y, "left", &left, "top", &top, "width", &width, "height", &height, NULL)) return -1; if (dout) { dout->left = left; dout->top = top; dout->width = width; dout->height = height; } return 0; } int im_draw_flood_blob(IMAGE *image, int x, int y, VipsPel *ink, Rect *dout) { double *vec; int n; int left; int top; int width; int height; if (!(vec = vips__ink_to_vector("im_draw_flood", image, ink, &n))) return -1; if (vips_draw_flood(image, vec, n, x, y, "equal", TRUE, "left", &left, "top", &top, "width", &width, "height", &height, NULL)) return -1; if (dout) { dout->left = left; dout->top = top; dout->width = width; dout->height = height; } return 0; } int im_draw_flood_other(IMAGE *image, IMAGE *test, int x, int y, int serial, Rect *dout) { int left; int top; int width; int height; if (vips_draw_flood1(image, serial, x, y, "test", test, "equal", TRUE, "left", &left, "top", &top, "width", &width, "height", &height, NULL)) return -1; if (dout) { dout->left = left; dout->top = top; dout->width = width; dout->height = height; } return 0; } int im_lineset(IMAGE *in, IMAGE *out, IMAGE *mask, IMAGE *ink, int n, int *x1v, int *y1v, int *x2v, int *y2v) { Rect mask_rect; int i; if (mask->Bands != 1 || mask->BandFmt != IM_BANDFMT_UCHAR || mask->Coding != IM_CODING_NONE) { im_error("im_lineset", "%s", _("mask image not 1 band 8 bit uncoded")); return -1; } if (ink->Bands != in->Bands || ink->BandFmt != in->BandFmt || ink->Coding != in->Coding) { im_error("im_lineset", "%s", _("ink image does not match in image")); return -1; } if (ink->Xsize != 1 || ink->Ysize != 1) { im_error("im_lineset", "%s", _("ink image not 1x1 pixels")); return -1; } /* Copy the image then fastline to it ... this will render to a "t" * usually. */ if (vips_image_write(in, out)) return -1; mask_rect.left = mask->Xsize / 2; mask_rect.top = mask->Ysize / 2; mask_rect.width = mask->Xsize; mask_rect.height = mask->Ysize; if (im_incheck(ink) || im_incheck(mask)) return -1; for (i = 0; i < n; i++) { if (im_fastlineuser(out, x1v[i], y1v[i], x2v[i], y2v[i], (VipsPlotFn) im_plotmask, ink->data, mask->data, &mask_rect)) return -1; } return 0; } int im_match_linear_search(IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int hwindowsize, int hsearchsize) { VipsImage *x; if (vips_match(ref, sec, &x, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, "search", TRUE, "hwindow", hwindowsize, "harea", hsearchsize, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_match_linear(IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2) { VipsImage *x; if (vips_match(ref, sec, &x, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_global_balance(IMAGE *in, IMAGE *out, double gamma) { VipsImage *x; if (vips_globalbalance(in, &x, "gamma", gamma, "int_output", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_histplot(IMAGE *in, IMAGE *out) { VipsImage *x; if (vips_hist_plot(in, &x, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_global_balancef(IMAGE *in, IMAGE *out, double gamma) { VipsImage *x; if (vips_globalbalance(in, &x, "gamma", gamma, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_remosaic(IMAGE *in, IMAGE *out, const char *old_str, const char *new_str) { VipsImage *x; if (vips_remosaic(in, &x, old_str, new_str, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_lrmosaic(IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int balancetype, int mwidth) { VipsImage *x; if (vips_mosaic(ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, xref, yref, xsec, ysec, "hwindow", hwindowsize, "harea", hsearchsize, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_lrmosaic1(IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int hwindowsize, int hsearchsize, int balancetype, int mwidth) { VipsImage *x; if (vips_mosaic1(ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, "search", TRUE, "hwindow", hwindowsize, "harea", hsearchsize, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_tbmosaic(IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int balancetype, int mwidth) { VipsImage *x; if (vips_mosaic(ref, sec, &x, VIPS_DIRECTION_VERTICAL, xref, yref, xsec, ysec, "hwindow", hwindowsize, "harea", hsearchsize, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_tbmosaic1(IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int hwindowsize, int hsearchsize, int balancetype, int mwidth) { VipsImage *x; if (vips_mosaic1(ref, sec, &x, VIPS_DIRECTION_VERTICAL, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, "search", TRUE, "hwindow", hwindowsize, "harea", hsearchsize, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_correl(VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y) { return vips__correl(ref, sec, xref, yref, xsec, ysec, hwindowsize, hsearchsize, correlation, x, y); } int im_lrmerge(IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth) { VipsImage *x; if (vips_merge(ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx, dy, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_lrmerge1(IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int mwidth) { VipsImage *x; if (vips_mosaic1(ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_tbmerge(IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth) { VipsImage *x; if (vips_merge(ref, sec, &x, VIPS_DIRECTION_VERTICAL, dx, dy, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } int im_tbmerge1(IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int mwidth) { VipsImage *x; if (vips_mosaic1(ref, sec, &x, VIPS_DIRECTION_VERTICAL, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } /* The common part of most binary conversion * operators. We: * * - check in and out * - cast in1 and in2 up to a common format * - equalise bands * - make an input array * - return the matched images in vec[0] and vec[1] * * A left-over, remove soon. */ IMAGE ** im__insert_base(const char *domain, IMAGE *in1, IMAGE *in2, IMAGE *out) { IMAGE *t[4]; IMAGE **vec; if (im_piocheck(in1, out) || im_pincheck(in2) || im_check_bands_1orn(domain, in1, in2) || im_check_coding_known(domain, in1) || im_check_coding_same(domain, in1, in2)) return NULL; /* Cast our input images up to a common format and bands. */ if (im_open_local_array(out, t, 4, domain, "p") || im__formatalike(in1, in2, t[0], t[1]) || im__bandalike(domain, t[0], t[1], t[2], t[3]) || !(vec = im_allocate_input_array(out, t[2], t[3], NULL))) return NULL; /* Generate the output. */ if (im_cp_descv(out, vec[0], vec[1], NULL) || im_demand_hint_array(out, IM_SMALLTILE, vec)) return NULL; return vec; } /** * im_insertset: * @main: big image * @sub: small image * @out: output image * @n: number of positions * @x: left positions of @sub * @y: top positions of @sub * * Insert @sub repeatedly into @main at the positions listed in the arrays @x, * @y of length @n. @out is the same * size as @main. @sub is clipped against the edges of @main. * * This operation is fast for large @n, but will use a memory buffer the size * of @out. It's useful for things like making scatter plots. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * See also: im_insert(), im_lrjoin(). * * Returns: 0 on success, -1 on error */ int im_insertset(IMAGE *main, IMAGE *sub, IMAGE *out, int n, int *x, int *y) { IMAGE **vec; IMAGE *t; int i; if (!(vec = im__insert_base("im_insert", main, sub, out))) return -1; /* Copy to a memory image, zap that, then copy to out. */ if (!(t = im_open_local(out, "im_insertset", "t")) || im_copy(vec[0], t)) return -1; for (i = 0; i < n; i++) if (im_insertplace(t, vec[1], x[i], y[i])) return -1; if (im_copy(t, out)) return -1; return 0; } /* We had this entry point in earlier libvipses, hilariously. */ int vips__init(const char *argv0) { return vips_init(argv0); } int im_greyc_mask(IMAGE *in, IMAGE *out, IMAGE *mask, int iterations, float amplitude, float sharpness, float anisotropy, float alpha, float sigma, float dl, float da, float gauss_prec, int interpolation, int fast_approx) { vips_error("im_greyc_mask", "This function is no longer in the core library"); return -1; } int vips_check_imask(const char *domain, INTMASK *mask) { if (!mask || mask->xsize > 1000 || mask->ysize > 1000 || mask->xsize <= 0 || mask->ysize <= 0 || mask->scale == 0 || !mask->coeff) { vips_error(domain, "%s", _("nonsense mask parameters")); return -1; } return 0; } int vips_check_dmask(const char *domain, DOUBLEMASK *mask) { if (!mask || mask->xsize > 1000 || mask->ysize > 1000 || mask->xsize <= 0 || mask->ysize <= 0 || mask->scale == 0 || !mask->coeff) { vips_error(domain, "%s", _("nonsense mask parameters")); return -1; } return 0; } int vips_check_dmask_1d(const char *domain, DOUBLEMASK *mask) { if (vips_check_dmask(domain, mask)) return -1; if (mask->xsize != 1 && mask->ysize != 1) { vips_error(domain, "%s", _("mask must be 1D")); return -1; } return 0; } GOptionGroup * vips_get_option_group(void) { static GOptionGroup *option_group = NULL; if (!option_group) { option_group = g_option_group_new("vips", _("VIPS Options"), _("Show VIPS options"), NULL, NULL); vips_add_option_entries(option_group); } return option_group; } /* We used to use this for system() back in the day. But it's awkward to make * it work properly on win32, so this is now deprecated. */ FILE * vips_popenf(const char *fmt, const char *mode, ...) { vips_error("popenf", "%s", _("deprecated")); return NULL; } /* We used to use this for getpoint(), but since it was the only caller in * vips8 it's now deprecated. */ double * vips__ink_to_vector(const char *domain, VipsImage *im, VipsPel *ink, int *n) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(im), 6); double *result; #ifdef VIPS_DEBUG printf("vips__ink_to_vector: starting\n"); #endif /*VIPS_DEBUG*/ /* Wrap a VipsImage around ink. */ t[0] = vips_image_new_from_memory(ink, VIPS_IMAGE_SIZEOF_PEL(im), 1, 1, VIPS_IMAGE_SIZEOF_PEL(im), VIPS_FORMAT_UCHAR); if (vips_copy(t[0], &t[1], "bands", im->Bands, "format", im->BandFmt, "coding", im->Coding, "interpretation", im->Type, NULL)) return NULL; /* The image may be coded .. unpack to double. */ if (vips_image_decode(t[1], &t[2]) || vips_cast(t[2], &t[3], VIPS_FORMAT_DOUBLE, NULL)) return NULL; /* To a mem buffer, then copy to out. */ if (!(t[4] = vips_image_new_memory()) || vips_image_write(t[3], t[4])) return NULL; if (!(result = VIPS_ARRAY(im, t[4]->Bands, double))) return NULL; memcpy(result, t[4]->data, VIPS_IMAGE_SIZEOF_PEL(t[4])); *n = t[4]->Bands; #ifdef VIPS_DEBUG { int i; printf("vips__ink_to_vector:\n"); printf("\tink = "); for (i = 0; i < n; i++) printf("%d ", ink[i]); printf("\n"); printf("\tvec = "); for (i = 0; i < *n; i++) printf("%g ", result[i]); printf("\n"); } #endif /*VIPS_DEBUG*/ return result; } /* Old API. Just a compat stub now. */ VipsWindow * vips_window_ref(VipsImage *im, int top, int height) { return NULL; } /* Deprecated. */ size_t vips__get_sizeof_vipsobject(void) { return sizeof(VipsObject); } libvips-8.18.2/libvips/draw/000077500000000000000000000000001516303661500156755ustar00rootroot00000000000000libvips-8.18.2/libvips/draw/draw.c000066400000000000000000000066201516303661500170020ustar00rootroot00000000000000/* base class for drawing operations * * 27/9/10 * - from im_draw_circle() * 17/11/10 * - oops, scanline clipping was off by 1 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pdraw.h" /** * VipsCombineMode: * @VIPS_COMBINE_MODE_SET: set pixels to the new value * @VIPS_COMBINE_MODE_ADD: add pixels * * See [method@Image.draw_image] and so on. * * Operations like [method@Image.draw_image] need to be told how to combine images * from two sources. * * ::: seealso * [method@Image.join]. */ G_DEFINE_ABSTRACT_TYPE(VipsDraw, vips_draw, VIPS_TYPE_OPERATION); static int vips_draw_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsDraw *draw = VIPS_DRAW(object); #ifdef DEBUG printf("vips_draw_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_draw_parent_class)->build(object)) return -1; if (vips_check_coding_known(class->nickname, draw->image) || vips_image_inplace(draw->image)) return -1; draw->lsize = VIPS_IMAGE_SIZEOF_LINE(draw->image); draw->psize = VIPS_IMAGE_SIZEOF_PEL(draw->image); draw->noclip = FALSE; return 0; } static void vips_draw_class_init(VipsDrawClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw"; vobject_class->description = _("draw operations"); vobject_class->build = vips_draw_build; // no draw operation is cached operation_class->flags |= VIPS_OPERATION_NOCACHE; VIPS_ARG_IMAGE(class, "image", 1, _("Image"), _("Image to draw on"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_MODIFY, G_STRUCT_OFFSET(VipsDraw, image)); } static void vips_draw_init(VipsDraw *draw) { } void vips_draw_operation_init(void) { extern GType vips_draw_rect_get_type(void); extern GType vips_draw_image_get_type(void); extern GType vips_draw_mask_get_type(void); extern GType vips_draw_line_get_type(void); extern GType vips_draw_circle_get_type(void); extern GType vips_draw_flood_get_type(void); extern GType vips_draw_smudge_get_type(void); vips_draw_rect_get_type(); vips_draw_image_get_type(); vips_draw_mask_get_type(); vips_draw_line_get_type(); vips_draw_circle_get_type(); vips_draw_flood_get_type(); vips_draw_smudge_get_type(); } libvips-8.18.2/libvips/draw/draw_circle.c000066400000000000000000000202051516303661500203160ustar00rootroot00000000000000/* draw a draw_circle on an image * * Author N. Dessipris * Written on 30/05/1990 * Updated on: * 22/7/93 JC * - im_incheck() call added * 16/8/94 JC * - im_incheck() changed to im_makerw() * 5/12/06 * - im_invalidate() after paint * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 18/8/10 * - gtkdoc * - rewritten: clips, fills, any bands, any format * 27/9/10 * - break base out to Draw * 3/2/14 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "drawink.h" typedef struct _VipsDrawCircle { VipsDrawink parent_object; int cx; int cy; int radius; gboolean fill; } VipsDrawCircle; typedef struct _VipsDrawCircleClass { VipsDrawinkClass parent_class; } VipsDrawCircleClass; G_DEFINE_TYPE(VipsDrawCircle, vips_draw_circle, VIPS_TYPE_DRAWINK); void vips__draw_circle_direct(VipsImage *image, int cx, int cy, int r, VipsDrawScanline draw_scanline, void *client) { int x, y; int64_t d; y = r; d = 3 - 2 * r; for (x = 0; x < y; x++) { draw_scanline(image, cy + y, cx - x, cx + x, 0, client); draw_scanline(image, cy - y, cx - x, cx + x, 1, client); draw_scanline(image, cy + x, cx - y, cx + y, 2, client); draw_scanline(image, cy - x, cx - y, cx + y, 3, client); if (d < 0) d += (int64_t) 4 * x + 6; else { d += (int64_t) 4 * (x - y) + 10; y--; } } if (x == y) { draw_scanline(image, cy + y, cx - x, cx + x, 0, client); draw_scanline(image, cy - y, cx - x, cx + x, 1, client); draw_scanline(image, cy + x, cx - y, cx + y, 2, client); draw_scanline(image, cy - x, cx - y, cx + y, 3, client); } } static inline void vips_draw_circle_draw_point(VipsImage *image, int x, int y, void *client) { VipsPel *ink = (VipsPel *) client; VipsPel *q = VIPS_IMAGE_ADDR(image, x, y); int psize = VIPS_IMAGE_SIZEOF_PEL(image); int j; /* Faster than memcopy() for n < about 20. */ for (j = 0; j < psize; j++) q[j] = ink[j]; } /* Paint endpoints, with clip. */ static void vips_draw_circle_draw_endpoints_clip(VipsImage *image, int y, int x1, int x2, int quadrant, void *client) { if (y >= 0 && y < image->Ysize) { if (x1 >= 0 && x1 < image->Xsize) vips_draw_circle_draw_point(image, x1, y, client); if (x2 >= 0 && x2 < image->Xsize) vips_draw_circle_draw_point(image, x2, y, client); } } /* Paint endpoints, no clip. */ static void vips_draw_circle_draw_endpoints_noclip(VipsImage *image, int y, int x1, int x2, int quadrant, void *client) { vips_draw_circle_draw_point(image, x1, y, client); vips_draw_circle_draw_point(image, x2, y, client); } /* Paint scanline. */ static void vips_draw_circle_draw_scanline(VipsImage *image, int y, int x1, int x2, int quadrant, void *client) { VipsPel *ink = (VipsPel *) client; int psize = VIPS_IMAGE_SIZEOF_PEL(image); VipsPel *q; int len; int i, j; g_assert(x1 <= x2); if (y < 0 || y >= image->Ysize) return; if (x1 < 0 && x2 < 0) return; if (x1 >= image->Xsize && x2 >= image->Xsize) return; x1 = VIPS_CLIP(0, x1, image->Xsize - 1); x2 = VIPS_CLIP(0, x2, image->Xsize - 1); q = VIPS_IMAGE_ADDR(image, x1, y); len = x2 - x1 + 1; for (i = 0; i < len; i++) { for (j = 0; j < psize; j++) q[j] = ink[j]; q += psize; } } static int vips_draw_circle_build(VipsObject *object) { VipsDraw *draw = VIPS_DRAW(object); VipsDrawink *drawink = VIPS_DRAWINK(object); VipsDrawCircle *circle = (VipsDrawCircle *) object; VipsDrawScanline draw_scanline; if (VIPS_OBJECT_CLASS(vips_draw_circle_parent_class)->build(object)) return -1; if (circle->fill) draw_scanline = vips_draw_circle_draw_scanline; else if (circle->cx - circle->radius >= 0 && circle->cx + circle->radius < draw->image->Xsize && circle->cy - circle->radius >= 0 && circle->cy + circle->radius < draw->image->Ysize) draw_scanline = vips_draw_circle_draw_endpoints_noclip; else draw_scanline = vips_draw_circle_draw_endpoints_clip; vips__draw_circle_direct(draw->image, circle->cx, circle->cy, circle->radius, draw_scanline, drawink->pixel_ink); return 0; } static void vips_draw_circle_class_init(VipsDrawCircleClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_circle"; vobject_class->description = _("draw a circle on an image"); vobject_class->build = vips_draw_circle_build; VIPS_ARG_INT(class, "cx", 3, _("cx"), _("Centre of draw_circle"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawCircle, cx), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "cy", 4, _("cy"), _("Centre of draw_circle"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawCircle, cy), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "radius", 5, _("Radius"), _("Radius in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawCircle, radius), 0, 1000000000, 0); VIPS_ARG_BOOL(class, "fill", 6, _("Fill"), _("Draw a solid object"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsDrawCircle, fill), FALSE); } static void vips_draw_circle_init(VipsDrawCircle *circle) { circle->fill = FALSE; } static int vips_draw_circlev(VipsImage *image, double *ink, int n, int cx, int cy, int radius, va_list ap) { VipsArea *area_ink; int result; area_ink = VIPS_AREA(vips_array_double_new(ink, n)); result = vips_call_split("draw_circle", ap, image, area_ink, cx, cy, radius); vips_area_unref(area_ink); return result; } /** * vips_draw_circle: (method) * @image: image to draw on * @ink: (array length=n): value to draw * @n: length of ink array * @cx: centre of draw_circle * @cy: centre of draw_circle * @radius: draw_circle radius * @...: `NULL`-terminated list of optional named arguments * * Draws a circle on @image. * * If @fill is `TRUE` then the circle is filled, * otherwise a 1-pixel-wide perimeter is drawn. * * @ink is an array of double containing values to draw. * * ::: tip "Optional arguments" * * @fill: `gboolean`, fill the draw_circle * * ::: seealso * [method@Image.draw_circle1], [method@Image.draw_line]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_circle(VipsImage *image, double *ink, int n, int cx, int cy, int radius, ...) { va_list ap; int result; va_start(ap, radius); result = vips_draw_circlev(image, ink, n, cx, cy, radius, ap); va_end(ap); return result; } /** * vips_draw_circle1: (method) * @image: image to draw on * @ink: value to draw * @cx: centre of draw_circle * @cy: centre of draw_circle * @radius: draw_circle radius * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_circle], but just takes a single double for @ink. * * ::: tip "Optional arguments" * * @fill: `gboolean`, fill the draw_circle * * ::: seealso * [method@Image.draw_circle]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_circle1(VipsImage *image, double ink, int cx, int cy, int radius, ...) { double array_ink[1]; va_list ap; int result; array_ink[0] = ink; va_start(ap, radius); result = vips_draw_circlev(image, array_ink, 1, cx, cy, radius, ap); va_end(ap); return result; } libvips-8.18.2/libvips/draw/draw_flood.c000066400000000000000000000435021516303661500201650ustar00rootroot00000000000000/* draw_flood-fill * * JC 30/8/97 * - VIPSified, cleaned up, from "John Robinson's prog to fill * enclosed areas" * - something Kirk gave me, so thanks John * JC 1/10/97 * - swapped inner memcmp/cpy for a loop ... faster for small pixels * 13/7/02 JC * - im_draw_flood_blob() added * 5/12/06 * - im_invalidate() after paint * 24/3/09 * - added IM_CODING_RAD support * 28/9/09 * - ooops, tiny memleak * 17/12/09 * - use inline rather than defines, so we can add scanline fills more * easily * - gtk-doc comments * 21/12/09 * - rewrite for a scanline based fill, about 4x faster! * - allow separate test and mark images * 22/1/10 * - draw_flood_blob could loop if start point == ink * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 27/9/10 * - use Draw base class * 21/1/14 * - redo as a class * 5/4/20 * - could fail to complete for some very complex shapes */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "drawink.h" /* Size of a scanline buffer. We allocate a list of these to hold scanlines * we need to visit. */ #define PBUFSIZE (1000) /* A scanline we know could contain pixels connected to us. * * Dir is the direction of connection: +1 means y is increasing, ie. the line * above this one is filled. -1 if y is decreasing. */ typedef struct { int x1, x2; int y; int dir; } Scan; /* A buffer of scanlines, and how many of them have been used. If ->next is * non-NULL, the next block could contain more of them. * * We keep a pair of these, then loop over one and write to the other. */ typedef struct _Buffer { struct _Buffer *next; int n; Scan scan[PBUFSIZE]; } Buffer; /* What we track during a flood. We have this in a separate struct so that we * can support vips__draw_flood_direct() ... a fast path for * vips_labelregions() that avoids all of the GObject call overhead. This * gives a huge speedup, >x10 in many cases. */ typedef struct _Flood { /* Test pixels here. */ VipsImage *test; /* Draw pixels here, can be equal to test. */ VipsImage *image; /* Sizeof pel in test. */ int tsize; /* Pixel we compare test to for edges. */ VipsPel *edge; /* True for flood while test == edge, false for flood while test != * edge. */ gboolean equal; /* Sizeof pel in @image. */ int psize; /* Ink we write to @image. */ VipsPel *ink; /* Add to move down a line in @image. */ int lsize; /* Record bounding box of modified pixels. */ int left; int right; int top; int bottom; /* Our todo list. */ Buffer *in; Buffer *out; } Flood; /* Alloc a new buffer. */ static Buffer * buffer_build(void) { Buffer *buf; buf = g_new(Buffer, 1); buf->next = NULL; buf->n = 0; return buf; } /* Free a chain of buffers. */ static void buffer_free(Buffer *buf) { while (buf) { Buffer *p; p = buf->next; g_free(buf); buf = p; } } /* Add a scanline to a buffer, prepending a new buffer if necessary. Return * the new head buffer. */ static Buffer * buffer_add(Buffer *buf, Flood *flood, int x1, int x2, int y, int dir) { /* Clip against image size. */ if (y < 0 || y >= flood->test->Ysize) return buf; x1 = VIPS_CLIP(0, x1, flood->test->Xsize - 1); x2 = VIPS_CLIP(0, x2, flood->test->Xsize - 1); if (x2 - x1 < 0) return buf; if (buf->n == PBUFSIZE) { Buffer *new; new = buffer_build(); new->next = buf; buf = new; } buf->scan[buf->n].x1 = x1; buf->scan[buf->n].x2 = x2; buf->scan[buf->n].y = y; buf->scan[buf->n].dir = dir; buf->n += 1; return buf; } /* Is p "connected"? ie. is equal to or not equal to flood->edge, depending on * whether we are flooding to the edge boundary or flooding edge-coloured * pixels. p is a pel in @test. */ static gboolean flood_connected(Flood *flood, VipsPel *p) { int j; for (j = 0; j < flood->tsize; j++) if (p[j] != flood->edge[j]) break; /* If flood->equal, true if point == edge. */ return flood->equal ^ (j < flood->tsize); } /* Is p painted? p is a pel in @image. */ static gboolean flood_painted(Flood *flood, VipsPel *p) { int j; for (j = 0; j < flood->psize; j++) if (p[j] != flood->ink[j]) break; return j == flood->psize; } static void flood_pel(Flood *flood, VipsPel *q) { int j; /* Faster than memcopy() for n < about 20. */ for (j = 0; j < flood->psize; j++) q[j] = flood->ink[j]; } /* Fill a scanline between points x1 and x2 inclusive. x1 < x2. */ static void flood_draw_scanline(Flood *flood, int y, int x1, int x2) { VipsPel *p; int i; int len; g_assert(x1 <= x2); if (y < 0 || y >= flood->image->Ysize) return; if (x1 < 0 && x2 < 0) return; if (x1 >= flood->image->Xsize && x2 >= flood->image->Xsize) return; x1 = VIPS_CLIP(0, x1, flood->image->Xsize - 1); x2 = VIPS_CLIP(0, x2, flood->image->Xsize - 1); p = VIPS_IMAGE_ADDR(flood->image, x1, y); len = x2 - x1 + 1; for (i = 0; i < len; i++) { flood_pel(flood, p); p += flood->psize; } } /* Fill left and right, return the endpoints. The start point (x, y) must be * connected and unpainted. */ static void flood_scanline(Flood *flood, int x, int y, int *x1, int *x2) { const int width = flood->test->Xsize; int i; g_assert(flood_connected(flood, VIPS_IMAGE_ADDR(flood->test, x, y))); g_assert(!flood_painted(flood, VIPS_IMAGE_ADDR(flood->image, x, y))); /* Search to the right for the first non-connected pixel. If the start * pixel is unpainted, we know all the intervening pixels must be * unpainted too. */ if (x < width) { VipsPel *p = VIPS_IMAGE_ADDR(flood->test, x + 1, y); for (i = x + 1; i < width; i++) { if (!flood_connected(flood, p)) break; p += flood->tsize; } *x2 = i - 1; } else *x2 = width; /* Search left. */ if (x > 0) { VipsPel *p = VIPS_IMAGE_ADDR(flood->test, x - 1, y); for (i = x - 1; i >= 0; i--) { if (!flood_connected(flood, p)) break; p -= flood->tsize; } *x1 = i + 1; } else *x1 = 0; /* Paint the range we discovered. */ flood_draw_scanline(flood, y, *x1, *x2); flood->left = VIPS_MIN(flood->left, *x1); flood->right = VIPS_MAX(flood->right, *x2); flood->top = VIPS_MIN(flood->top, y); flood->bottom = VIPS_MAX(flood->bottom, y); } /* We know the line below or above us is filled between x1 and x2. Search our * line in this range looking for an edge pixel we can flood from. */ static void flood_around(Flood *flood, Scan *scan) { VipsPel *p; int x; g_assert(scan->dir == 1 || scan->dir == -1); for (p = VIPS_IMAGE_ADDR(flood->test, scan->x1, scan->y), x = scan->x1; x <= scan->x2; p += flood->tsize, x++) { if (flood_connected(flood, p)) { int x1a; int x2a; /* If mark and test are different images, we also need * to check for painted. Otherwise we can get stuck in * connected loops. */ if (flood->image != flood->test) { VipsPel *mp = VIPS_IMAGE_ADDR( flood->image, x, scan->y); if (flood_painted(flood, mp)) continue; } flood_scanline(flood, x, scan->y, &x1a, &x2a); /* Our new scanline can have up to three more * scanlines connected to it: above, below left, below * right. */ if (x1a < scan->x1 - 1) flood->out = buffer_add(flood->out, flood, x1a, scan->x1 - 2, scan->y - scan->dir, -scan->dir); if (x2a > scan->x2 + 1) flood->out = buffer_add(flood->out, flood, scan->x2 + 2, x2a, scan->y - scan->dir, -scan->dir); flood->out = buffer_add(flood->out, flood, x1a, x2a, scan->y + scan->dir, scan->dir); x = x2a + 1; p = VIPS_IMAGE_ADDR(flood->test, x, scan->y); } } } static void flood_all(Flood *flood, int x, int y) { int x1, x2; /* Test start pixel ... nothing to do? */ if (!flood_connected(flood, VIPS_IMAGE_ADDR(flood->test, x, y))) return; flood->in = buffer_build(); flood->out = buffer_build(); flood_scanline(flood, x, y, &x1, &x2); flood->in = buffer_add(flood->in, flood, x1, x2, y + 1, 1); flood->in = buffer_add(flood->in, flood, x1, x2, y - 1, -1); while (flood->in->n) { Buffer *p; for (p = flood->in; p; p = p->next) { int i; for (i = 0; i < p->n; i++) flood_around(flood, &p->scan[i]); p->n = 0; } VIPS_SWAP(Buffer *, flood->in, flood->out); } VIPS_FREEF(buffer_free, flood->in); VIPS_FREEF(buffer_free, flood->out); } /* Base class. */ typedef struct _VipsDrawFlood { VipsDrawink parent_object; /* Parameters. */ int x; int y; VipsImage *test; gboolean equal; int left; int top; int width; int height; } VipsDrawFlood; typedef VipsDrawinkClass VipsDrawFloodClass; G_DEFINE_TYPE(VipsDrawFlood, vips_draw_flood, VIPS_TYPE_DRAWINK); static int vips_draw_flood_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsDraw *draw = VIPS_DRAW(object); VipsDrawink *drawink = VIPS_DRAWINK(object); VipsDrawFlood *drawflood = (VipsDrawFlood *) object; Flood flood; int j; if (VIPS_OBJECT_CLASS(vips_draw_flood_parent_class)->build(object)) return -1; /* @test defaults to @image. */ if (!vips_object_argument_isset(object, "test")) /* Setting input params like this will break caching, but we * don't cache draw ops anyway. */ g_object_set(object, "test", draw->image, NULL); if (vips_image_wio_input(drawflood->test) || vips_check_coding_known(class->nickname, drawflood->test) || vips_check_size_same(class->nickname, drawflood->test, draw->image)) return -1; if (drawflood->x >= draw->image->Xsize || drawflood->y >= draw->image->Ysize) { vips_error(class->nickname, "%s", _("start point out of image")); return -1; } flood.test = drawflood->test; flood.image = draw->image; flood.tsize = VIPS_IMAGE_SIZEOF_PEL(flood.test); flood.equal = drawflood->equal; flood.psize = VIPS_IMAGE_SIZEOF_PEL(flood.image); flood.ink = drawink->pixel_ink; flood.lsize = VIPS_IMAGE_SIZEOF_LINE(flood.image); flood.left = drawflood->x; flood.right = drawflood->x; flood.top = drawflood->y; flood.bottom = drawflood->y; if (flood.equal) { /* Edge is set by colour of the start pixel in @test. */ if (!(flood.edge = VIPS_ARRAY(object, flood.tsize, VipsPel))) return -1; memcpy(flood.edge, VIPS_IMAGE_ADDR(flood.test, drawflood->x, drawflood->y), flood.tsize); /* If @test and @image are the same and edge == ink, we'll * never stop :-( or rather, there's nothing to do. */ if (flood.test == flood.image) { for (j = 0; j < flood.tsize; j++) if (flood.edge[j] != flood.ink[j]) break; if (j != flood.tsize) flood_all(&flood, drawflood->x, drawflood->y); } else flood_all(&flood, drawflood->x, drawflood->y); } else { /* Flood to ink colour. We need to be able to compare @test to * @ink. */ if (!(flood.edge = vips__vector_to_ink(class->nickname, flood.test, VIPS_ARRAY_ADDR(drawink->ink, 0), NULL, VIPS_AREA(drawink->ink)->n))) return -1; flood_all(&flood, drawflood->x, drawflood->y); } g_object_set(object, "left", flood.left, "top", flood.top, "width", flood.right - flood.left + 1, "height", flood.bottom - flood.top + 1, NULL); return 0; } static void vips_draw_flood_class_init(VipsDrawFloodClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_flood"; vobject_class->description = _("flood-fill an area"); vobject_class->build = vips_draw_flood_build; VIPS_ARG_INT(class, "x", 3, _("x"), _("DrawFlood start point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawFlood, x), 0, 1000000000, 0); VIPS_ARG_INT(class, "y", 4, _("y"), _("DrawFlood start point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawFlood, y), 0, 1000000000, 0); VIPS_ARG_IMAGE(class, "test", 5, _("Test"), _("Test pixels in this image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsDrawFlood, test)); VIPS_ARG_BOOL(class, "equal", 6, _("Equal"), _("DrawFlood while equal to edge"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsDrawFlood, equal), FALSE); VIPS_ARG_INT(class, "left", 7, _("Left"), _("Left edge of modified area"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsDrawFlood, left), 0, 1000000000, 0); VIPS_ARG_INT(class, "top", 8, _("Top"), _("Top edge of modified area"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsDrawFlood, top), 0, 1000000000, 0); VIPS_ARG_INT(class, "width", 9, _("Width"), _("Width of modified area"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsDrawFlood, width), 0, 1000000000, 0); VIPS_ARG_INT(class, "height", 10, _("Height"), _("Height of modified area"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsDrawFlood, height), 0, 1000000000, 0); } static void vips_draw_flood_init(VipsDrawFlood *draw_flood) { } /* Direct path to flood for vips_labelregions(). We need to avoid the function * dispatch system for speed. * * Equivalent to: * * vips_draw_flood1(image, serial, x, y, * "test", test, * "equal", TRUE, * NULL); * * image must be 1-band int. */ int vips__draw_flood_direct(VipsImage *image, VipsImage *test, int serial, int x, int y) { Flood flood; if (vips_check_format("vips__draw_flood_direct", image, VIPS_FORMAT_INT) || vips_check_mono("vips__draw_flood_direct", image) || vips_check_coding_known("vips__draw_flood_direct", test) || vips_check_size_same("vips__draw_flood_direct", test, image) || vips_image_wio_input(test) || vips_image_inplace(image)) return -1; flood.test = test; flood.image = image; flood.tsize = VIPS_IMAGE_SIZEOF_PEL(test); flood.equal = TRUE; flood.psize = VIPS_IMAGE_SIZEOF_PEL(image); flood.ink = (VipsPel *) &serial; flood.lsize = VIPS_IMAGE_SIZEOF_LINE(image); flood.left = x; flood.right = x; flood.top = y; flood.bottom = y; if (!(flood.edge = VIPS_ARRAY(image, flood.tsize, VipsPel))) return -1; memcpy(flood.edge, VIPS_IMAGE_ADDR(test, x, y), flood.tsize); flood_all(&flood, x, y); return 0; } static int vips_draw_floodv(VipsImage *image, double *ink, int n, int x, int y, va_list ap) { VipsArea *area_ink; int result; area_ink = VIPS_AREA(vips_array_double_new(ink, n)); result = vips_call_split("draw_flood", ap, image, area_ink, x, y); vips_area_unref(area_ink); return result; } /** * vips_draw_flood: (method) * @image: image to draw on * @ink: (array length=n): value to draw * @n: length of ink array * @x: centre of circle * @y: centre of circle * @...: `NULL`-terminated list of optional named arguments * * Flood-fill @image with @ink, starting at position @x, @y. * * The filled area is * bounded by pixels that are equal to the ink colour, in other words, it * searches for pixels enclosed by an edge of @ink. * * If @equal is set, it instead searches for pixels which are equal to the * start point and fills them with @ink. * * Normally it will test and set pixels in @image. If @test is set, it will * test pixels in @test and set pixels in @image. This lets you search an * image (@test) for continuous areas of pixels without modifying it. * * @left, @top, @width, @height output the bounding box of the modified * pixels. * * ::: tip "Optional arguments" * * @test: [class@Image], test this image * * @equal: `gboolean`, fill while equal to edge * * @left: `gint`, output left edge of bounding box of modified area * * @top: `gint`, output top edge of bounding box of modified area * * @width: `gint`, output width of bounding box of modified area * * @height: `gint`, output height of bounding box of modified area * * @ink is an array of double containing values to draw. * * ::: seealso * [method@Image.draw_flood1]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_flood(VipsImage *image, double *ink, int n, int x, int y, ...) { va_list ap; int result; va_start(ap, y); result = vips_draw_floodv(image, ink, n, x, y, ap); va_end(ap); return result; } /** * vips_draw_flood1: (method) * @image: image to draw on * @ink: value to draw * @x: centre of circle * @y: centre of circle * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_flood], but just takes a single double for @ink. * * ::: tip "Optional arguments" * * @test: [class@Image], test this image * * @equal: `gboolean`, fill while equal to edge * * @left: `gint`, output, left edge of bounding box of modified area * * @top: `gint`, output, top edge of bounding box of modified area * * @width: `gint`, output, width of bounding box of modified area * * @height: `gint`, output, height of bounding box of modified area * * ::: seealso * [method@Image.draw_flood]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_flood1(VipsImage *image, double ink, int x, int y, ...) { double array_ink[1]; va_list ap; int result; array_ink[0] = ink; va_start(ap, y); result = vips_draw_floodv(image, array_ink, 1, x, y, ap); va_end(ap); return result; } libvips-8.18.2/libvips/draw/draw_image.c000066400000000000000000000174301516303661500201450ustar00rootroot00000000000000/* in-place insert * * Copyright: J. Cupitt * Written: 15/06/1992 * 22/7/93 JC * - im_incheck() added * 16/8/94 JC * - im_incheck() changed to im_makerw() * 1/9/04 JC * - checks bands/types/etc match (thanks Matt) * - smarter pixel size calculations * 5/12/06 * - im_invalidate() after paint * 24/3/09 * - added IM_CODING_RAD support * 21/10/09 * - allow sub to be outside main * - gtkdoc * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 25/8/10 * - cast and bandalike sub to main * 22/9/10 * - rename to im_draw_image() * - gtk-doc * 9/2/14 * - redo as a class, based on draw_image * 28/3/14 * - add "mode" param */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pdraw.h" typedef struct _VipsDrawImage { VipsDraw parent_object; /* Parameters. */ VipsImage *sub; int x; int y; VipsCombineMode mode; } VipsDrawImage; typedef struct _VipsDrawImageClass { VipsDrawClass parent_class; } VipsDrawImageClass; G_DEFINE_TYPE(VipsDrawImage, vips_draw_image, VIPS_TYPE_DRAW); #define LOOP(TYPE, TEMP, MIN, MAX) \ { \ TYPE *restrict pt = (TYPE *) p; \ TYPE *restrict qt = (TYPE *) q; \ \ for (x = 0; x < sz; x++) { \ TEMP v; \ \ v = pt[x] + qt[x]; \ \ qt[x] = VIPS_CLIP(MIN, v, MAX); \ } \ } #define LOOPF(TYPE) \ { \ TYPE *restrict pt = (TYPE *) p; \ TYPE *restrict qt = (TYPE *) q; \ \ for (x = 0; x < sz; x++) \ qt[x] += pt[x]; \ } static void vips_draw_image_mode_add(VipsDrawImage *draw_image, VipsImage *im, VipsPel *q, VipsPel *p, int n) { /* Complex just doubles the size. */ const int sz = n * im->Bands * (vips_band_format_iscomplex(im->BandFmt) ? 2 : 1); int x; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: LOOP(unsigned char, int, 0, UCHAR_MAX); break; case VIPS_FORMAT_CHAR: LOOP(signed char, int, SCHAR_MIN, SCHAR_MAX); break; case VIPS_FORMAT_USHORT: LOOP(unsigned short, int, 0, USHRT_MAX); break; case VIPS_FORMAT_SHORT: LOOP(signed short, int, SCHAR_MIN, SCHAR_MAX); break; case VIPS_FORMAT_UINT: LOOP(unsigned int, gint64, 0, UINT_MAX); break; case VIPS_FORMAT_INT: LOOP(signed int, gint64, INT_MIN, INT_MAX); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: LOOPF(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: LOOPF(double); break; default: g_assert_not_reached(); } } static int vips_draw_image_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsDraw *draw = VIPS_DRAW(object); VipsDrawImage *draw_image = (VipsDrawImage *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); VipsImage *im; VipsRect image_rect; VipsRect sub_rect; VipsRect clip_rect; if (VIPS_OBJECT_CLASS(vips_draw_image_parent_class)->build(object)) return -1; if (vips_check_coding_known(class->nickname, draw->image) || vips_check_coding_same(class->nickname, draw->image, draw_image->sub) || vips_check_bands_1orn_unary(class->nickname, draw_image->sub, draw->image->Bands)) return -1; /* SET will work for any matching coding, but every other mode needs * uncoded images. */ if (draw_image->mode != VIPS_COMBINE_MODE_SET && vips_check_uncoded(class->nickname, draw->image)) return -1; /* Cast sub to match main in bands and format. */ im = draw_image->sub; if (im->Coding == VIPS_CODING_NONE) { if (vips__bandup(class->nickname, im, &t[0], draw->image->Bands) || vips_cast(t[0], &t[1], draw->image->BandFmt, NULL)) return -1; im = t[1]; } /* Make rects for main and sub and clip. */ image_rect.left = 0; image_rect.top = 0; image_rect.width = draw->image->Xsize; image_rect.height = draw->image->Ysize; sub_rect.left = draw_image->x; sub_rect.top = draw_image->y; sub_rect.width = im->Xsize; sub_rect.height = im->Ysize; vips_rect_intersectrect(&image_rect, &sub_rect, &clip_rect); if (!vips_rect_isempty(&clip_rect)) { VipsPel *p, *q; int y; if (vips_image_wio_input(im)) return -1; p = VIPS_IMAGE_ADDR(im, clip_rect.left - draw_image->x, clip_rect.top - draw_image->y); q = VIPS_IMAGE_ADDR(draw->image, clip_rect.left, clip_rect.top); for (y = 0; y < clip_rect.height; y++) { switch (draw_image->mode) { case VIPS_COMBINE_MODE_SET: memcpy((char *) q, (char *) p, clip_rect.width * VIPS_IMAGE_SIZEOF_PEL(im)); break; case VIPS_COMBINE_MODE_ADD: vips_draw_image_mode_add(draw_image, im, q, p, clip_rect.width); break; default: g_assert_not_reached(); } p += VIPS_IMAGE_SIZEOF_LINE(im); q += VIPS_IMAGE_SIZEOF_LINE(draw->image); } } return 0; } static void vips_draw_image_class_init(VipsDrawImageClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_image"; vobject_class->description = _("paint an image into another image"); vobject_class->build = vips_draw_image_build; VIPS_ARG_IMAGE(class, "sub", 5, _("Sub-image"), _("Sub-image to insert into main image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawImage, sub)); VIPS_ARG_INT(class, "x", 6, _("x"), _("Draw image here"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawImage, x), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "y", 7, _("y"), _("Draw image here"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawImage, y), -1000000000, 1000000000, 0); VIPS_ARG_ENUM(class, "mode", 8, _("Mode"), _("Combining mode"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsDrawImage, mode), VIPS_TYPE_COMBINE_MODE, VIPS_COMBINE_MODE_SET); } static void vips_draw_image_init(VipsDrawImage *draw_image) { draw_image->mode = VIPS_COMBINE_MODE_SET; } /** * vips_draw_image: (method) * @image: image to draw on * @sub: image to paint * @x: draw @sub here * @y: draw @sub here * @...: `NULL`-terminated list of optional named arguments * * Draw @sub on top of @image at position @x, @y. * * The two images must have the * same Coding. If @sub has 1 band, the bands will be duplicated to match the * number of bands in @image. @sub will be converted to @image's format, see * [method@Image.cast]. * * Use @mode to set how pixels are combined. If you use * [enum@Vips.CombineMode.ADD], both images must be uncoded. * * ::: tip "Optional arguments" * * @mode: [enum@CombineMode], how to combine pixels * * ::: seealso * [method@Image.draw_mask], [method@Image.insert]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_image(VipsImage *image, VipsImage *sub, int x, int y, ...) { va_list ap; int result; va_start(ap, y); result = vips_call_split("draw_image", ap, image, sub, x, y); va_end(ap); return result; } libvips-8.18.2/libvips/draw/draw_line.c000066400000000000000000000206361516303661500200140ustar00rootroot00000000000000/* draw straight draw_lines * * Copyright: J. Cupitt * Written: 15/06/1992 * Modified : 22/10/92 - clipping constraints changed * 22/7/93 JC * - im_incheck() added * 16/8/94 JC * - im_incheck() changed to im_makerw() * 5/12/06 * - im_invalidate() after paint * 1/3/10 * - oops, draw_lineset needs to ask for WIO of mask and ink * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 27/9/10 * - gtk-doc * - use draw.c base class * - do pointwise clipping * - rename as im_draw_line() for consistency * - cleanups! * 6/2/14 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "drawink.h" typedef struct _VipsDrawLine { VipsDrawink parent_object; int x1; int y1; int x2; int y2; } VipsDrawLine; typedef struct _VipsDrawLineClass { VipsDrawinkClass parent_class; } VipsDrawLineClass; G_DEFINE_TYPE(VipsDrawLine, vips_draw_line, VIPS_TYPE_DRAWINK); void vips__draw_line_direct(VipsImage *image, int x1, int y1, int x2, int y2, VipsDrawPoint draw_point, void *client) { int dx, dy; int x, y, err; dx = x2 - x1; dy = y2 - y1; /* Swap endpoints to reduce number of cases. */ if (abs(dx) >= abs(dy) && dx < 0) { /* Swap to get all x greater or equal cases going to the * right. Do diagonals here .. just have up and right and down * and right now. */ VIPS_SWAP(int, x1, x2); VIPS_SWAP(int, y1, y2); } else if (abs(dx) < abs(dy) && dy < 0) { /* Swap to get all y greater cases going down the screen. */ VIPS_SWAP(int, x1, x2); VIPS_SWAP(int, y1, y2); } dx = x2 - x1; dy = y2 - y1; x = x1; y = y1; /* Special case: zero width and height is single point. */ if (dx == 0 && dy == 0) draw_point(image, x, y, client); /* Special case vertical and horizontal lines for speed. */ else if (dx == 0) { /* Vertical line going down. */ for (; y <= y2; y++) draw_point(image, x, y, client); } else if (dy == 0) { /* Horizontal line to the right. */ for (; x <= x2; x++) draw_point(image, x, y, client); } /* Special case diagonal lines. */ else if (abs(dy) == abs(dx) && dy > 0) { /* Diagonal line going down and right. */ for (; x <= x2; x++, y++) draw_point(image, x, y, client); } else if (abs(dy) == abs(dx) && dy < 0) { /* Diagonal line going up and right. */ for (; x <= x2; x++, y--) draw_point(image, x, y, client); } else if (abs(dy) < abs(dx) && dy > 0) { /* Between -45 and 0 degrees. */ for (err = 0; x <= x2; x++) { draw_point(image, x, y, client); err += dy; if (err >= dx) { err -= dx; y++; } } } else if (abs(dy) < abs(dx) && dy < 0) { /* Between 0 and 45 degrees. */ for (err = 0; x <= x2; x++) { draw_point(image, x, y, client); err -= dy; if (err >= dx) { err -= dx; y--; } } } else if (abs(dy) > abs(dx) && dx > 0) { /* Between -45 and -90 degrees. */ for (err = 0; y <= y2; y++) { draw_point(image, x, y, client); err += dx; if (err >= dy) { err -= dy; x++; } } } else if (abs(dy) > abs(dx) && dx < 0) { /* Between -90 and -135 degrees. */ for (err = 0; y <= y2; y++) { draw_point(image, x, y, client); err -= dx; if (err >= dy) { err -= dy; x--; } } } else g_assert_not_reached(); } static void vips_draw_line_draw_point_noclip(VipsImage *image, int x, int y, void *client) { VipsPel *ink = (VipsPel *) client; VipsPel *q = VIPS_IMAGE_ADDR(image, x, y); int psize = VIPS_IMAGE_SIZEOF_PEL(image); int j; /* Faster than memcopy() for n < about 20. */ for (j = 0; j < psize; j++) q[j] = ink[j]; } static void vips_draw_line_draw_point_clip(VipsImage *image, int x, int y, void *client) { if (x >= 0 && x < image->Xsize && y >= 0 && y < image->Ysize) vips_draw_line_draw_point_noclip(image, x, y, client); } static int vips_draw_line_build(VipsObject *object) { VipsDraw *draw = VIPS_DRAW(object); VipsDrawink *drawink = VIPS_DRAWINK(object); VipsDrawLine *line = (VipsDrawLine *) object; VipsDrawPoint draw_point; if (VIPS_OBJECT_CLASS(vips_draw_line_parent_class)->build(object)) return -1; if (line->x1 < draw->image->Xsize && line->x1 >= 0 && line->x2 < draw->image->Xsize && line->x2 >= 0 && line->y1 < draw->image->Ysize && line->y1 >= 0 && line->y2 < draw->image->Ysize && line->y2 >= 0) draw_point = vips_draw_line_draw_point_noclip; else draw_point = vips_draw_line_draw_point_clip; vips__draw_line_direct(draw->image, line->x1, line->y1, line->x2, line->y2, draw_point, drawink->pixel_ink); return 0; } static void vips_draw_line_class_init(VipsDrawLineClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_line"; vobject_class->description = _("draw a line on an image"); vobject_class->build = vips_draw_line_build; VIPS_ARG_INT(class, "x1", 3, _("x1"), _("Start of draw_line"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawLine, x1), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "y1", 4, _("y1"), _("Start of draw_line"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawLine, y1), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "x2", 5, _("x2"), _("End of draw_line"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawLine, x2), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "y2", 6, _("y2"), _("End of draw_line"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawLine, y2), -1000000000, 1000000000, 0); } static void vips_draw_line_init(VipsDrawLine *draw_line) { } static int vips_draw_linev(VipsImage *image, double *ink, int n, int x1, int y1, int x2, int y2, va_list ap) { VipsArea *area_ink; int result; area_ink = VIPS_AREA(vips_array_double_new(ink, n)); result = vips_call_split("draw_line", ap, image, area_ink, x1, y1, x2, y2); vips_area_unref(area_ink); return result; } /** * vips_draw_line: (method) * @image: image to draw on * @ink: (array length=n): value to draw * @n: length of ink array * @x1: start of draw_line * @y1: start of draw_line * @x2: end of draw_line * @y2: end of draw_line * @...: `NULL`-terminated list of optional named arguments * * Draws a 1-pixel-wide line on an image. * * @ink is an array of double containing values to draw. * * ::: seealso * [method@Image.draw_line1], [method@Image.draw_circle], [method@Image.draw_mask]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_line(VipsImage *image, double *ink, int n, int x1, int y1, int x2, int y2, ...) { va_list ap; int result; va_start(ap, y2); result = vips_draw_linev(image, ink, n, x1, y1, x2, y2, ap); va_end(ap); return result; } /** * vips_draw_line1: (method) * @image: image to draw on * @ink: value to draw * @x1: start of draw_line * @y1: start of draw_line * @x2: end of draw_line * @y2: end of draw_line * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_line], but just take a single double for @ink. * * ::: seealso * [method@Image.draw_line]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_line1(VipsImage *image, double ink, int x1, int y1, int x2, int y2, ...) { double array_ink[1]; va_list ap; int result; array_ink[0] = ink; va_start(ap, y2); result = vips_draw_linev(image, array_ink, 1, x1, y1, x2, y2, ap); va_end(ap); return result; } libvips-8.18.2/libvips/draw/draw_mask.c000066400000000000000000000231141516303661500200120ustar00rootroot00000000000000/* Draw a mask on an image. * * Copyright: J. Cupitt * Written: 15/06/1992 * 22/7/93 JC * - im_incheck() added * 16/8/94 JC * - im_incheck() changed to im_makerw() * 24/10/03 JC * - now blends with 0-255 mask * 5/12/06 * - im_invalidate() after paint * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 28/9/10 * - gtk-doc * - renamed as im_draw_mask() * - use Draw base class * 7/2/14 * - redo as a class * - now it's VipsDrawMask */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "drawink.h" typedef struct _VipsDrawMask { VipsDrawink parent_object; /* Parameters. */ VipsImage *mask; int x; int y; /* Derived. */ VipsRect image_clip; VipsRect mask_clip; } VipsDrawMask; typedef struct _VipsDrawMaskClass { VipsDrawinkClass parent_class; } VipsDrawMaskClass; G_DEFINE_TYPE(VipsDrawMask, vips_draw_mask, VIPS_TYPE_DRAWINK); /* Paint ink into an 8 or 16 bit integer image. */ #define IBLEND(TYPE, TO, INK) \ { \ TYPE *tto = (TYPE *) (TO); \ TYPE *tink = (TYPE *) (INK); \ \ int x, i, j; \ \ for (j = 0, x = 0; x < width; x++) \ for (i = 0; i < bands; i++, j++) \ tto[j] = \ (tink[i] * m[x] + \ tto[j] * (255 - m[x])) / \ 255; \ } /* Do the blend with doubles. */ #define DBLEND(TYPE, TO, INK) \ { \ TYPE *tto = (TYPE *) (TO); \ TYPE *tink = (TYPE *) (INK); \ \ int x, i, j; \ \ for (j = 0, x = 0; x < width; x++) \ for (i = 0; i < bands; i++, j++) \ tto[j] = ((double) tink[i] * m[x] + \ (double) tto[j] * (255 - m[x])) / \ 255; \ } /* Blend of complex. */ #define CBLEND(TYPE, TO, INK) \ { \ TYPE *tto = (TYPE *) (TO); \ TYPE *tink = (TYPE *) (INK); \ \ int x, i, j; \ \ for (j = 0, x = 0; x < width; x++) \ for (i = 0; i < bands * 2; i += 2, j += 2) { \ tto[j] = \ ((double) tink[i] * m[x] + \ (double) tto[j] * (255 - m[x])) / \ 255; \ tto[j + 1] = \ ((double) tink[i + 1] * m[x] + \ (double) tto[j + 1] * (255 - m[x])) / \ 255; \ } \ } static int vips_draw_mask_draw_labq(VipsImage *image, VipsImage *mask, VipsPel *ink, VipsRect *image_clip, VipsRect *mask_clip) { int width = image_clip->width; int height = image_clip->height; int bands = image->Bands; float *lab_buffer; int y; if (!(lab_buffer = VIPS_ARRAY(NULL, width * 3, float))) return -1; for (y = 0; y < height; y++) { VipsPel *to = VIPS_IMAGE_ADDR(image, image_clip->left, y + image_clip->top); VipsPel *m = VIPS_IMAGE_ADDR(mask, mask_clip->left, y + mask_clip->top); vips__LabQ2Lab_vec(lab_buffer, to, width); DBLEND(float, lab_buffer, (double *) ink); vips__Lab2LabQ_vec(to, lab_buffer, width); } g_free(lab_buffer); return 0; } static int vips_draw_mask_draw(VipsImage *image, VipsImage *mask, VipsPel *ink, VipsRect *image_clip, VipsRect *mask_clip) { int width = image_clip->width; int height = image_clip->height; int bands = image->Bands; int y; for (y = 0; y < height; y++) { VipsPel *to = VIPS_IMAGE_ADDR(image, image_clip->left, y + image_clip->top); VipsPel *m = VIPS_IMAGE_ADDR(mask, mask_clip->left, y + mask_clip->top); switch (image->BandFmt) { case VIPS_FORMAT_UCHAR: IBLEND(unsigned char, to, ink); break; case VIPS_FORMAT_CHAR: IBLEND(signed char, to, ink); break; case VIPS_FORMAT_USHORT: IBLEND(unsigned short, to, ink); break; case VIPS_FORMAT_SHORT: IBLEND(signed short, to, ink); break; case VIPS_FORMAT_UINT: DBLEND(unsigned int, to, ink); break; case VIPS_FORMAT_INT: DBLEND(signed int, to, ink); break; case VIPS_FORMAT_FLOAT: DBLEND(float, to, ink); break; case VIPS_FORMAT_DOUBLE: DBLEND(double, to, ink); break; case VIPS_FORMAT_COMPLEX: CBLEND(float, to, ink); break; case VIPS_FORMAT_DPCOMPLEX: CBLEND(double, to, ink); break; default: g_assert_not_reached(); } } return 0; } /* Direct path for draw-mask-along-line or draw-mask-along-circle. We want to * avoid function dispatch overhead. * * The vips7 im_draw_mask() wrapper calls this as well. */ int vips__draw_mask_direct(VipsImage *image, VipsImage *mask, VipsPel *ink, int x, int y) { VipsRect image_rect; VipsRect area_rect; VipsRect image_clip; VipsRect mask_clip; if (vips_check_coding_noneorlabq("draw_mask_direct", image) || vips_image_inplace(image) || vips_image_wio_input(mask) || vips_check_mono("draw_mask_direct", mask) || vips_check_uncoded("draw_mask_direct", mask) || vips_check_format("draw_mask_direct", mask, VIPS_FORMAT_UCHAR)) return -1; /* Find the area we draw on the image. */ area_rect.left = x; area_rect.top = y; area_rect.width = mask->Xsize; area_rect.height = mask->Ysize; image_rect.left = 0; image_rect.top = 0; image_rect.width = image->Xsize; image_rect.height = image->Ysize; vips_rect_intersectrect(&area_rect, &image_rect, &image_clip); /* And the area of the mask image we use. */ mask_clip = image_clip; mask_clip.left -= x; mask_clip.top -= y; if (!vips_rect_isempty(&image_clip)) switch (image->Coding) { case VIPS_CODING_LABQ: if (vips_draw_mask_draw_labq(image, mask, ink, &image_clip, &mask_clip)) return -1; break; case VIPS_CODING_NONE: if (vips_draw_mask_draw(image, mask, ink, &image_clip, &mask_clip)) return -1; break; default: g_assert_not_reached(); } return 0; } static int vips_draw_mask_build(VipsObject *object) { VipsDraw *draw = VIPS_DRAW(object); VipsDrawink *drawink = VIPS_DRAWINK(object); VipsDrawMask *mask = (VipsDrawMask *) object; if (VIPS_OBJECT_CLASS(vips_draw_mask_parent_class)->build(object)) return -1; if (vips__draw_mask_direct(draw->image, mask->mask, drawink->pixel_ink, mask->x, mask->y)) return -1; return 0; } static void vips_draw_mask_class_init(VipsDrawMaskClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_mask"; vobject_class->description = _("draw a mask on an image"); vobject_class->build = vips_draw_mask_build; VIPS_ARG_IMAGE(class, "mask", 5, _("Mask"), _("Mask of pixels to draw"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawMask, mask)); VIPS_ARG_INT(class, "x", 6, _("x"), _("Draw mask here"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawMask, x), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "y", 7, _("y"), _("Draw mask here"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawMask, y), -1000000000, 1000000000, 0); } static void vips_draw_mask_init(VipsDrawMask *draw_mask) { } static int vips_draw_maskv(VipsImage *image, double *ink, int n, VipsImage *mask, int x, int y, va_list ap) { VipsArea *area_ink; int result; area_ink = VIPS_AREA(vips_array_double_new(ink, n)); result = vips_call_split("draw_mask", ap, image, area_ink, mask, x, y); vips_area_unref(area_ink); return result; } /** * vips_draw_mask: (method) * @image: image to draw on * @ink: (array length=n): value to draw * @n: size of ink array * @mask: mask of 0/255 values showing where to plot * @x: draw mask here * @y: draw mask here * @...: `NULL`-terminated list of optional named arguments * * Draw @mask on the image. @mask is a monochrome 8-bit image with 0/255 * for transparent or @ink coloured points. Intermediate values blend the ink * with the pixel. Use with [ctor@Image.text] to draw text on an image. Use in a * [method@Image.draw_line] subclass to draw an object along a line. * * @ink is an array of double containing values to draw. * * ::: seealso * [ctor@Image.text], [method@Image.draw_line]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_mask(VipsImage *image, double *ink, int n, VipsImage *mask, int x, int y, ...) { va_list ap; int result; va_start(ap, y); result = vips_draw_maskv(image, ink, n, mask, x, y, ap); va_end(ap); return result; } /** * vips_draw_mask1: (method) * @image: image to draw on * @ink: value to draw * @mask: mask of 0/255 values showing where to plot * @x: draw mask here * @y: draw mask here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_mask], but just takes a single double for @ink. * * ::: seealso * [method@Image.draw_mask]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_mask1(VipsImage *image, double ink, VipsImage *mask, int x, int y, ...) { double array_ink[1]; va_list ap; int result; array_ink[0] = ink; va_start(ap, y); result = vips_draw_maskv(image, array_ink, 1, mask, x, y, ap); va_end(ap); return result; } libvips-8.18.2/libvips/draw/draw_rect.c000066400000000000000000000200141516303661500200100ustar00rootroot00000000000000/* Fill Rect r of image im with pels of colour ink. * * Copyright: J. Cupitt * Written: 15/06/1992 * 22/7/93 JC * - im_incheck() added * 16/8/94 JC * - im_incheck() changed to im_makerw() * 5/12/06 * - im_invalidate() after paint * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 22/9/10 * - gtk-doc * - added 'fill' * - renamed as im_draw_rect() for consistency * 27/9/10 * - memcpy() subsequent lines of the rect * 10/2/14 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "drawink.h" typedef struct _VipsDrawRect { VipsDrawink parent_object; /* Parameters. */ int left; int top; int width; int height; gboolean fill; } VipsDrawRect; typedef struct _VipsDrawRectClass { VipsDrawinkClass parent_class; } VipsDrawRectClass; G_DEFINE_TYPE(VipsDrawRect, vips_draw_rect, VIPS_TYPE_DRAWINK); static int vips_draw_rect_build(VipsObject *object) { VipsDraw *draw = VIPS_DRAW(object); VipsDrawink *drawink = VIPS_DRAWINK(object); VipsArea *ink = VIPS_AREA(drawink->ink); VipsDrawRect *draw_rect = (VipsDrawRect *) object; int left = draw_rect->left; int top = draw_rect->top; int width = draw_rect->width; int height = draw_rect->height; VipsRect image; VipsRect rect; VipsRect clip; if (VIPS_OBJECT_CLASS(vips_draw_rect_parent_class)->build(object)) return -1; /* Also use a solid fill for very narrow unfilled rects. */ if (!draw_rect->fill && width > 2 && height > 2) return vips_draw_rect(draw->image, ink->data, ink->n, left, top, width, 1, NULL) || vips_draw_rect(draw->image, ink->data, ink->n, left + width - 1, top, 1, height, NULL) || vips_draw_rect(draw->image, ink->data, ink->n, left, top + height - 1, width, 1, NULL) || vips_draw_rect(draw->image, ink->data, ink->n, left, top, 1, height, NULL); image.left = 0; image.top = 0; image.width = draw->image->Xsize; image.height = draw->image->Ysize; rect.left = left; rect.top = top; rect.width = width; rect.height = height; vips_rect_intersectrect(&rect, &image, &clip); if (!vips_rect_isempty(&clip)) { VipsPel *to = VIPS_IMAGE_ADDR(draw->image, clip.left, clip.top); VipsPel *q; int x, y; /* We plot the first line pointwise, then memcpy() it for the * subsequent lines. */ q = to; for (x = 0; x < clip.width; x++) { vips__drawink_pel(drawink, q); q += draw->psize; } q = to + draw->lsize; for (y = 1; y < clip.height; y++) { memcpy(q, to, clip.width * draw->psize); q += draw->lsize; } } return 0; } static void vips_draw_rect_class_init(VipsDrawRectClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_rect"; vobject_class->description = _("paint a rectangle on an image"); vobject_class->build = vips_draw_rect_build; VIPS_ARG_INT(class, "left", 6, _("Left"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawRect, left), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "top", 7, _("Top"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawRect, top), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "width", 8, _("Width"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawRect, width), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "height", 9, _("Height"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawRect, height), -1000000000, 1000000000, 0); VIPS_ARG_BOOL(class, "fill", 10, _("Fill"), _("Draw a solid object"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsDrawRect, fill), FALSE); } static void vips_draw_rect_init(VipsDrawRect *draw_rect) { } static int vips_draw_rectv(VipsImage *image, double *ink, int n, int left, int top, int width, int height, va_list ap) { VipsArea *area_ink; int result; area_ink = VIPS_AREA(vips_array_double_new(ink, n)); result = vips_call_split("draw_rect", ap, image, area_ink, left, top, width, height); vips_area_unref(area_ink); return result; } /** * vips_draw_rect: (method) * @image: image to draw on * @ink: (array length=n): value to draw * @n: length of ink array * @left: area to paint * @top: area to paint * @width: area to paint * @height: area to paint * @...: `NULL`-terminated list of optional named arguments * * Paint pixels within @left, @top, @width, @height in @image with @ink. * * If @fill is zero, just paint a 1-pixel-wide outline. * * ::: tip "Optional arguments" * * @fill: `gboolean`, fill the rect * * ::: seealso * [method@Image.draw_circle]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_rect(VipsImage *image, double *ink, int n, int left, int top, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_draw_rectv(image, ink, n, left, top, width, height, ap); va_end(ap); return result; } /** * vips_draw_rect1: (method) * @image: image to draw on * @ink: value to draw * @left: area to paint * @top: area to paint * @width: area to paint * @height: area to paint * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_rect], but just take a single double for @ink. * * ::: tip "Optional arguments" * * @fill: `gboolean`, fill the rect * * ::: seealso * [method@Image.draw_rect]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_rect1(VipsImage *image, double ink, int left, int top, int width, int height, ...) { double array_ink[1]; va_list ap; int result; array_ink[0] = ink; va_start(ap, height); result = vips_draw_rectv(image, array_ink, 1, left, top, width, height, ap); va_end(ap); return result; } /** * vips_draw_point: (method) * @image: image to draw on * @ink: (array length=n): value to draw * @n: length of ink array * @x: point to paint * @y: point to paint * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_rect], but draw a single pixel at @x, @y. * * ::: seealso * [method@Image.draw_rect]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_point(VipsImage *image, double *ink, int n, int x, int y, ...) { va_list ap; int result; va_start(ap, y); result = vips_draw_rectv(image, ink, n, x, y, 1, 1, ap); va_end(ap); return result; } /** * vips_draw_point1: (method) * @image: image to draw on * @ink: value to draw * @x: point to draw * @y: point to draw * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.draw_point], but just take a single double for @ink. * * ::: seealso * [method@Image.draw_point]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_point1(VipsImage *image, double ink, int x, int y, ...) { double array_ink[1]; va_list ap; int result; array_ink[0] = ink; va_start(ap, y); result = vips_draw_rectv(image, array_ink, 1, x, y, 1, 1, ap); va_end(ap); return result; } libvips-8.18.2/libvips/draw/draw_smudge.c000066400000000000000000000137651516303661500203560ustar00rootroot00000000000000/* Smudge a piece of image. * * Copyright: J. Cupitt * Written: 15/06/1992 * 22/7/93 JC * - im_incheck() added * 16/8/94 JC * - im_incheck() changed to im_makerw() * ? JC * - im_makerw() changed to im_rwcheck() * 5/12/06 * - im_invalidate() after paint * 6/3/10 * - don't im_invalidate() after paint, this now needs to be at a higher * level * 30/9/10 * - gtk-doc * - deprecate im_smear() * 30/1/12 * - back to the custom smear, the conv one was too slow * 11/2/14 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pdraw.h" typedef struct _VipsDrawSmudge { VipsDraw parent_object; /* Parameters. */ int left; int top; int width; int height; } VipsDrawSmudge; typedef struct _VipsDrawSmudgeClass { VipsDrawClass parent_class; } VipsDrawSmudgeClass; G_DEFINE_TYPE(VipsDrawSmudge, vips_draw_smudge, VIPS_TYPE_DRAW); static int vips_draw_smudge_build(VipsObject *object) { VipsDraw *draw = VIPS_DRAW(object); VipsImage *im = draw->image; VipsDrawSmudge *smudge = (VipsDrawSmudge *) object; int left = smudge->left; int top = smudge->top; int width = smudge->width; int height = smudge->height; /* Double bands for complex images. */ int bands = vips_image_get_bands(draw->image) * (vips_band_format_iscomplex(vips_image_get_format(im)) ? 2 : 1); int elements = bands * vips_image_get_width(im); VipsRect area, image, clipped; double *total; int x, y, i, j, b; if (VIPS_OBJECT_CLASS(vips_draw_smudge_parent_class)->build(object)) return -1; area.left = left; area.top = top; area.width = width; area.height = height; /* Don't do the margins. */ image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; vips_rect_marginadjust(&image, -1); vips_rect_intersectrect(&area, &image, &clipped); if (vips_rect_isempty(&clipped)) return 0; if (!(total = VIPS_ARRAY(im, bands, double))) return -1; /* What we do for each type. */ #define SMUDGE(TYPE) \ for (y = 0; y < clipped.height; y++) { \ TYPE *q; \ TYPE *p; \ \ q = (TYPE *) VIPS_IMAGE_ADDR(im, \ clipped.left, clipped.top + y); \ p = q - elements - bands; \ for (x = 0; x < clipped.width; x++) { \ TYPE *p1, *p2; \ \ for (b = 0; b < bands; b++) \ total[b] = 0.0; \ \ p1 = p; \ for (i = 0; i < 3; i++) { \ p2 = p1; \ for (j = 0; j < 3; j++) \ for (b = 0; b < bands; b++) \ total[b] += *p2++; \ \ p1 += elements; \ } \ \ for (b = 0; b < bands; b++) \ q[b] = (16 * (double) q[b] + total[b]) / 25.0; \ \ p += bands; \ q += bands; \ } \ } switch (vips_image_get_format(im)) { case VIPS_FORMAT_UCHAR: SMUDGE(unsigned char); break; case VIPS_FORMAT_CHAR: SMUDGE(char); break; case VIPS_FORMAT_USHORT: SMUDGE(unsigned short); break; case VIPS_FORMAT_SHORT: SMUDGE(short); break; case VIPS_FORMAT_UINT: SMUDGE(unsigned int); break; case VIPS_FORMAT_INT: SMUDGE(int); break; case VIPS_FORMAT_FLOAT: SMUDGE(float); break; case VIPS_FORMAT_DOUBLE: SMUDGE(double); break; case VIPS_FORMAT_COMPLEX: SMUDGE(float); break; case VIPS_FORMAT_DPCOMPLEX: SMUDGE(double); break; default: g_assert_not_reached(); } return 0; } static void vips_draw_smudge_class_init(VipsDrawSmudgeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "draw_smudge"; vobject_class->description = _("blur a rectangle on an image"); vobject_class->build = vips_draw_smudge_build; VIPS_ARG_INT(class, "left", 6, _("Left"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawSmudge, left), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "top", 7, _("Top"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawSmudge, top), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "width", 8, _("Width"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawSmudge, width), -1000000000, 1000000000, 0); VIPS_ARG_INT(class, "height", 9, _("Height"), _("Rect to fill"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawSmudge, height), -1000000000, 1000000000, 0); } static void vips_draw_smudge_init(VipsDrawSmudge *draw_smudge) { } /** * vips_draw_smudge: (method) * @image: image to draw on * @left: point to paint * @top: point to paint * @width: area to paint * @height: area to paint * @...: `NULL`-terminated list of optional named arguments * * Smudge a section of @image. Each pixel in the area @left, @top, @width, * @height is replaced by the average of the surrounding 3x3 pixels. * * ::: seealso * [method@Image.draw_line]. * * Returns: 0 on success, or -1 on error. */ int vips_draw_smudge(VipsImage *image, int left, int top, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("draw_smudge", ap, image, left, top, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/draw/drawink.c000066400000000000000000000061631516303661500175060ustar00rootroot00000000000000/* drawink with a constant ink * * 27/9/10 * - from im_drawink_circle() * 17/11/10 * - oops, scanline clipping was off by 1 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "drawink.h" G_DEFINE_ABSTRACT_TYPE(VipsDrawink, vips_drawink, VIPS_TYPE_DRAW); static int vips_drawink_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsDraw *draw = VIPS_DRAW(object); VipsDrawink *drawink = VIPS_DRAWINK(object); #ifdef DEBUG printf("vips_drawink_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_drawink_parent_class)->build(object)) return -1; if (drawink->ink && !(drawink->pixel_ink = vips__vector_to_ink(class->nickname, draw->image, VIPS_ARRAY_ADDR(drawink->ink, 0), NULL, VIPS_AREA(drawink->ink)->n))) return -1; return 0; } static void vips_drawink_class_init(VipsDrawinkClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "drawink"; vobject_class->description = _("draw with ink operations"); vobject_class->build = vips_drawink_build; VIPS_ARG_BOXED(class, "ink", 2, _("Ink"), _("Color for pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsDrawink, ink), VIPS_TYPE_ARRAY_DOUBLE); } static void vips_drawink_init(VipsDrawink *drawink) { drawink->ink = vips_array_double_newv(1, 0.0); } /* Fill a scanline between points x1 and x2 inclusive. x1 < x2. */ int vips__drawink_scanline(VipsDrawink *drawink, int y, int x1, int x2) { VipsDraw *draw = (VipsDraw *) drawink; VipsPel *mp; int i; int len; g_assert(x1 <= x2); if (y < 0 || y >= draw->image->Ysize) return 0; if (x1 < 0 && x2 < 0) return 0; if (x1 >= draw->image->Xsize && x2 >= draw->image->Xsize) return 0; x1 = VIPS_CLIP(0, x1, draw->image->Xsize - 1); x2 = VIPS_CLIP(0, x2, draw->image->Xsize - 1); mp = VIPS_IMAGE_ADDR(draw->image, x1, y); len = x2 - x1 + 1; for (i = 0; i < len; i++) { vips__drawink_pel(drawink, mp); mp += draw->psize; } return 0; } libvips-8.18.2/libvips/draw/drawink.h000066400000000000000000000054131516303661500175100ustar00rootroot00000000000000/* a drawink operation with an ink param */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_DRAWINK_H #define VIPS_DRAWINK_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include "pdraw.h" #define VIPS_TYPE_DRAWINK (vips_drawink_get_type()) #define VIPS_DRAWINK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_DRAWINK, VipsDrawink)) #define VIPS_DRAWINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_DRAWINK, VipsDrawinkClass)) #define VIPS_IS_DRAWINK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_DRAWINK)) #define VIPS_IS_DRAWINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_DRAWINK)) #define VIPS_DRAWINK_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_DRAWINK, VipsDrawinkClass)) typedef struct _VipsDrawink { VipsDraw parent_instance; VipsArrayDouble *ink; /* Ink cast to pixel type. */ VipsPel *pixel_ink; } VipsDrawink; typedef struct _VipsDrawinkClass { VipsDrawClass parent_class; } VipsDrawinkClass; GType vips_drawink_get_type(void); static inline int vips__drawink_pel(VipsDrawink *drawink, VipsPel *q) { VipsDraw *draw = (VipsDraw *) drawink; int j; /* Faster than memcopy() for n < about 20. */ for (j = 0; j < draw->psize; j++) q[j] = drawink->pixel_ink[j]; return 0; } /* Paint, with clip. */ static inline int vips__drawink_pel_clip(VipsDrawink *drawink, int x, int y) { VipsDraw *draw = (VipsDraw *) drawink; if (x < 0 || x >= draw->image->Xsize) return 0; if (y < 0 || y >= draw->image->Ysize) return 0; vips__drawink_pel(drawink, VIPS_IMAGE_ADDR(draw->image, x, y)); return 0; } /* Is p painted? */ static inline gboolean vips__drawink_painted(VipsDrawink *drawink, VipsPel *p) { VipsDraw *draw = (VipsDraw *) drawink; int j; for (j = 0; j < draw->psize; j++) if (p[j] != drawink->pixel_ink[j]) break; return j == draw->psize; } int vips__drawink_scanline(VipsDrawink *drawink, int y, int x1, int x2); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_DRAWINK_H*/ libvips-8.18.2/libvips/draw/meson.build000066400000000000000000000007121516303661500200370ustar00rootroot00000000000000draw_sources = files( 'draw.c', 'drawink.c', 'draw_circle.c', 'draw_flood.c', 'draw_mask.c', 'draw_image.c', 'draw_rect.c', 'draw_line.c', 'draw_smudge.c', ) draw_headers = files( 'pdraw.h', 'drawink.h', ) libvips_sources += draw_sources draw_lib = static_library('draw', draw_sources, draw_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += draw_lib libvips-8.18.2/libvips/draw/pdraw.h000066400000000000000000000036631516303661500171730ustar00rootroot00000000000000/* base class for drawing operations */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PDRAW_H #define VIPS_PDRAW_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_DRAW (vips_draw_get_type()) #define VIPS_DRAW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_DRAW, VipsDraw)) #define VIPS_DRAW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_DRAW, VipsDrawClass)) #define VIPS_IS_DRAW(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_DRAW)) #define VIPS_IS_DRAW_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_DRAW)) #define VIPS_DRAW_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_DRAW, VipsDrawClass)) typedef struct _VipsDraw { VipsOperation parent_instance; /* Parameters. */ VipsImage *image; /* Draw here */ /* Derived stuff. */ size_t lsize; size_t psize; /* If the object to draw is entirely within the image, we have a * faster noclip path. */ gboolean noclip; } VipsDraw; typedef struct _VipsDrawClass { VipsOperationClass parent_class; } VipsDrawClass; GType vips_draw_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PDRAW_H*/ libvips-8.18.2/libvips/foreign/000077500000000000000000000000001516303661500163715ustar00rootroot00000000000000libvips-8.18.2/libvips/foreign/analyze2vips.c000066400000000000000000000356401516303661500211740ustar00rootroot00000000000000/* Read a Analyze file. Old-style header (so called 7.5 format). * * 3/8/05 * - dbh.h header from Ralph Myers * 22/8/05 * - better byteswapper * 12/5/09 * - fix signed/unsigned warning * 13/1/09 * - try harder not to generate error messages in "isanalyze" * 4/2/10 * - gtkdoc * 14/12/11 * - redo as a set of fns ready for wrapping in a new-style class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_ANALYZE #include #include #include #include #include #include #include #include "dbh.h" #include "pforeign.h" /* The things we can have in header fields. Can't use GType, since we want a * static value we can use in a declaration. */ typedef enum { BYTE, SHORT, INT, FLOAT, STRING } Type; /* A field in the dsr header. */ typedef struct { const char *name; /* Eg. "header_key.sizeof_hdr" */ Type type; glong offset; /* Offset in struct */ int len; /* Sizeof ... useful for string types */ } Field; static Field dsr_header[] = { { "dsr-header_key.sizeof_hdr", INT, G_STRUCT_OFFSET(struct dsr, hk.sizeof_hdr), 4 }, { "dsr-header_key.data_type", STRING, G_STRUCT_OFFSET(struct dsr, hk.data_type), 10 }, { "dsr-header_key.db_name", STRING, G_STRUCT_OFFSET(struct dsr, hk.db_name), 18 }, { "dsr-header_key.extents", INT, G_STRUCT_OFFSET(struct dsr, hk.extents), 4 }, { "dsr-header_key.session_error", SHORT, G_STRUCT_OFFSET(struct dsr, hk.session_error), 2 }, { "dsr-header_key.regular", BYTE, G_STRUCT_OFFSET(struct dsr, hk.regular), 1 }, { "dsr-header_key.hkey_un0", BYTE, G_STRUCT_OFFSET(struct dsr, hk.hkey_un0), 1 }, { "dsr-image_dimension.dim[0]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[0]), 2 }, { "dsr-image_dimension.dim[1]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[1]), 2 }, { "dsr-image_dimension.dim[2]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[2]), 2 }, { "dsr-image_dimension.dim[3]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[3]), 2 }, { "dsr-image_dimension.dim[4]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[4]), 2 }, { "dsr-image_dimension.dim[5]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[5]), 2 }, { "dsr-image_dimension.dim[6]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[6]), 2 }, { "dsr-image_dimension.dim[7]", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim[7]), 2 }, { "dsr-image_dimension.vox_units[0]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.vox_units[0]), 1 }, { "dsr-image_dimension.vox_units[1]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.vox_units[1]), 1 }, { "dsr-image_dimension.vox_units[2]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.vox_units[2]), 1 }, { "dsr-image_dimension.vox_units[3]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.vox_units[3]), 1 }, { "dsr-image_dimension.cal_units[0]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[0]), 1 }, { "dsr-image_dimension.cal_units[1]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[1]), 1 }, { "dsr-image_dimension.cal_units[2]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[2]), 1 }, { "dsr-image_dimension.cal_units[3]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[3]), 1 }, { "dsr-image_dimension.cal_units[4]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[4]), 1 }, { "dsr-image_dimension.cal_units[5]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[5]), 1 }, { "dsr-image_dimension.cal_units[6]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[6]), 1 }, { "dsr-image_dimension.cal_units[7]", BYTE, G_STRUCT_OFFSET(struct dsr, dime.cal_units[7]), 1 }, { "dsr-image_dimension.data_type", SHORT, G_STRUCT_OFFSET(struct dsr, dime.datatype), 2 }, { "dsr-image_dimension.bitpix", SHORT, G_STRUCT_OFFSET(struct dsr, dime.bitpix), 2 }, { "dsr-image_dimension.dim_un0", SHORT, G_STRUCT_OFFSET(struct dsr, dime.dim_un0), 2 }, { "dsr-image_dimension.pixdim[0]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[0]), 4 }, { "dsr-image_dimension.pixdim[1]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[1]), 4 }, { "dsr-image_dimension.pixdim[2]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[2]), 4 }, { "dsr-image_dimension.pixdim[3]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[3]), 4 }, { "dsr-image_dimension.pixdim[4]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[4]), 4 }, { "dsr-image_dimension.pixdim[5]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[5]), 4 }, { "dsr-image_dimension.pixdim[6]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[6]), 4 }, { "dsr-image_dimension.pixdim[7]", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.pixdim[7]), 4 }, { "dsr-image_dimension.vox_offset", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.vox_offset), 4 }, { "dsr-image_dimension.cal_max", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.cal_max), 4 }, { "dsr-image_dimension.cal_min", FLOAT, G_STRUCT_OFFSET(struct dsr, dime.cal_min), 4 }, { "dsr-image_dimension.compressed", INT, G_STRUCT_OFFSET(struct dsr, dime.compressed), 4 }, { "dsr-image_dimension.verified", INT, G_STRUCT_OFFSET(struct dsr, dime.verified), 4 }, { "dsr-image_dimension.glmax", INT, G_STRUCT_OFFSET(struct dsr, dime.glmax), 4 }, { "dsr-image_dimension.glmin", INT, G_STRUCT_OFFSET(struct dsr, dime.glmin), 4 }, { "dsr-data_history.descrip", STRING, G_STRUCT_OFFSET(struct dsr, hist.descrip), 80 }, { "dsr-data_history.aux_file", STRING, G_STRUCT_OFFSET(struct dsr, hist.aux_file), 24 }, { "dsr-data_history.orient", BYTE, G_STRUCT_OFFSET(struct dsr, hist.orient), 1 }, { "dsr-data_history.originator", STRING, G_STRUCT_OFFSET(struct dsr, hist.originator), 10 }, { "dsr-data_history.generated", STRING, G_STRUCT_OFFSET(struct dsr, hist.generated), 10 }, { "dsr-data_history.scannum", STRING, G_STRUCT_OFFSET(struct dsr, hist.scannum), 10 }, { "dsr-data_history.patient_id", STRING, G_STRUCT_OFFSET(struct dsr, hist.patient_id), 10 }, { "dsr-data_history.exp_date", STRING, G_STRUCT_OFFSET(struct dsr, hist.exp_date), 10 }, { "dsr-data_history.exp_time", STRING, G_STRUCT_OFFSET(struct dsr, hist.exp_time), 10 }, { "dsr-data_history.hist_un0", STRING, G_STRUCT_OFFSET(struct dsr, hist.hist_un0), 3 }, { "dsr-data_history.views", INT, G_STRUCT_OFFSET(struct dsr, hist.views), 4 }, { "dsr-data_history.vols_added", INT, G_STRUCT_OFFSET(struct dsr, hist.vols_added), 4 }, { "dsr-data_history.start_field", INT, G_STRUCT_OFFSET(struct dsr, hist.start_field), 4 }, { "dsr-data_history.field_skip", INT, G_STRUCT_OFFSET(struct dsr, hist.field_skip), 4 }, { "dsr-data_history.omax", INT, G_STRUCT_OFFSET(struct dsr, hist.omax), 4 }, { "dsr-data_history.omin", INT, G_STRUCT_OFFSET(struct dsr, hist.omin), 4 }, { "dsr-data_history.smax", INT, G_STRUCT_OFFSET(struct dsr, hist.smax), 4 }, { "dsr-data_history.smin", INT, G_STRUCT_OFFSET(struct dsr, hist.smin), 4 } }; /* Given a filename, generate the names for the header and the image data. * * Eg. * "fred" -> "fred.hdr", "fred.img" * "fred.img" -> "fred.hdr", "fred.img" */ static void generate_filenames(const char *path, char *header, char *image) { const char *olds[] = { ".img", ".hdr" }; vips__change_suffix(path, header, FILENAME_MAX, ".hdr", olds, 2); vips__change_suffix(path, image, FILENAME_MAX, ".img", olds, 2); } /* str is a str which may not be NULL-terminated. Return a pointer to a static * buffer with a NULL-terminated version so we can safely printf() the string. * Also, make sure the string is plain ascii. */ static char * getstr(int mx, const char *str) { static char buf[256]; int i; g_assert(mx < 256); g_strlcpy(buf, str, mx); buf[mx] = '\0'; /* How annoying, patient_id has some funny ctrlchars in that mess up * xml encode later. */ for (i = 0; i < mx && buf[i]; i++) if (!isascii(buf[i]) || buf[i] < 32) buf[i] = '@'; return buf; } #ifdef DEBUG static void print_dsr(struct dsr *d) { int i; for (i = 0; i < VIPS_NUMBER(dsr_header); i++) { printf("%s = ", dsr_header[i].name); switch (dsr_header[i].type) { case BYTE: printf("%d\n", G_STRUCT_MEMBER(char, d, dsr_header[i].offset)); break; case SHORT: printf("%d\n", G_STRUCT_MEMBER(short, d, dsr_header[i].offset)); break; case INT: printf("%d\n", G_STRUCT_MEMBER(int, d, dsr_header[i].offset)); break; case FLOAT: printf("%g\n", G_STRUCT_MEMBER(float, d, dsr_header[i].offset)); break; case STRING: printf("\"%s\"\n", getstr(dsr_header[i].len, &G_STRUCT_MEMBER(char, d, dsr_header[i].offset))); break; default: g_assert_not_reached(); } } } #endif /*DEBUG*/ static struct dsr * read_header(const char *header) { struct dsr *d; size_t len; if (!(d = (struct dsr *) vips__file_read_name(header, NULL, &len))) return NULL; if (len != sizeof(struct dsr)) { vips_error("analyze2vips", "%s", _("header file size incorrect")); g_free(d); return NULL; } /* Ouch! Should check at configure time I guess. */ g_assert(sizeof(struct dsr) == 348); /* dsr headers are always SPARC byte order (MSB first). Do we need to * swap? */ if (!vips_amiMSBfirst()) { int i; for (i = 0; i < VIPS_NUMBER(dsr_header); i++) { unsigned char *p; switch (dsr_header[i].type) { case SHORT: p = &G_STRUCT_MEMBER(unsigned char, d, dsr_header[i].offset); vips__copy_2byte(TRUE, p, p); break; case INT: case FLOAT: p = &G_STRUCT_MEMBER(unsigned char, d, dsr_header[i].offset); vips__copy_4byte(TRUE, p, p); break; case BYTE: case STRING: break; default: g_assert_not_reached(); } } } if ((int) len != d->hk.sizeof_hdr) { vips_error("analyze2vips", "%s", _("header size incorrect")); g_free(d); return NULL; } return d; } /* Try to get VIPS header properties from a dsr. */ static int get_vips_properties(struct dsr *d, int *width, int *height, int *bands, VipsBandFormat *fmt) { int i; if (d->dime.dim[0] < 2 || d->dime.dim[0] > 7) { vips_error("analyze2vips", _("%d-dimensional images not supported"), d->dime.dim[0]); return -1; } /* Size of base 2d images. */ *width = d->dime.dim[1]; *height = d->dime.dim[2]; for (i = 3; i <= d->dime.dim[0]; i++) *height *= d->dime.dim[i]; /* Check it's a datatype we can handle. */ switch (d->dime.datatype) { case DT_UNSIGNED_CHAR: *bands = 1; *fmt = VIPS_FORMAT_UCHAR; break; case DT_SIGNED_SHORT: *bands = 1; *fmt = VIPS_FORMAT_SHORT; break; case DT_SIGNED_INT: *bands = 1; *fmt = VIPS_FORMAT_INT; break; case DT_FLOAT: *bands = 1; *fmt = VIPS_FORMAT_FLOAT; break; case DT_COMPLEX: *bands = 1; *fmt = VIPS_FORMAT_COMPLEX; break; case DT_DOUBLE: *bands = 1; *fmt = VIPS_FORMAT_DOUBLE; break; case DT_RGB: *bands = 3; *fmt = VIPS_FORMAT_UCHAR; break; default: vips_error("analyze2vips", _("datatype %d not supported"), d->dime.datatype); return -1; } #ifdef DEBUG printf("get_vips_properties: width = %d\n", *width); printf("get_vips_properties: height = %d\n", *height); printf("get_vips_properties: bands = %d\n", *bands); printf("get_vips_properties: fmt = %d\n", *fmt); #endif /*DEBUG*/ return 0; } static void attach_meta(VipsImage *out, struct dsr *d) { int i; vips_image_set_blob(out, "dsr", (VipsCallbackFn) vips_area_free_cb, d, d->hk.sizeof_hdr); for (i = 0; i < VIPS_NUMBER(dsr_header); i++) { switch (dsr_header[i].type) { case BYTE: vips_image_set_int(out, dsr_header[i].name, G_STRUCT_MEMBER(char, d, dsr_header[i].offset)); break; case SHORT: vips_image_set_int(out, dsr_header[i].name, G_STRUCT_MEMBER(short, d, dsr_header[i].offset)); break; case INT: vips_image_set_int(out, dsr_header[i].name, G_STRUCT_MEMBER(int, d, dsr_header[i].offset)); break; case FLOAT: vips_image_set_double(out, dsr_header[i].name, G_STRUCT_MEMBER(float, d, dsr_header[i].offset)); break; case STRING: vips_image_set_string(out, dsr_header[i].name, getstr(dsr_header[i].len, &G_STRUCT_MEMBER(char, d, dsr_header[i].offset))); break; default: g_assert_not_reached(); } } } int vips__isanalyze(const char *filename) { char header[FILENAME_MAX]; char image[FILENAME_MAX]; struct dsr *d; int width, height; int bands; VipsBandFormat fmt; int result; generate_filenames(filename, header, image); if (!vips_existsf("%s", header)) return 0; vips_error_freeze(); d = read_header(header); vips_error_thaw(); if (!d) return 0; #ifdef DEBUG print_dsr(d); #endif /*DEBUG*/ vips_error_freeze(); result = get_vips_properties(d, &width, &height, &bands, &fmt); vips_error_thaw(); g_free(d); return result == 0; } int vips__analyze_read_header(const char *filename, VipsImage *out) { char header[FILENAME_MAX]; char image[FILENAME_MAX]; struct dsr *d; int width, height; int bands; VipsBandFormat fmt; generate_filenames(filename, header, image); if (!(d = read_header(header))) return -1; #ifdef DEBUG print_dsr(d); #endif /*DEBUG*/ if (get_vips_properties(d, &width, &height, &bands, &fmt)) { g_free(d); return -1; } vips_image_init_fields(out, width, height, bands, fmt, VIPS_CODING_NONE, bands == 1 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB, 1.0, 1.0); attach_meta(out, d); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; return 0; } int vips__analyze_read(const char *filename, VipsImage *out) { char header[FILENAME_MAX]; char image[FILENAME_MAX]; struct dsr *d; VipsImage *x = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(x), 3); int width, height; int bands; VipsBandFormat fmt; generate_filenames(filename, header, image); if (!(d = read_header(header))) { g_object_unref(x); return -1; } attach_meta(out, d); #ifdef DEBUG print_dsr(d); #endif /*DEBUG*/ if (get_vips_properties(d, &width, &height, &bands, &fmt) || !(t[0] = vips_image_new_from_file_raw(image, width, height, bands * vips_format_sizeof(fmt), 0))) { g_object_unref(x); return -1; } if (vips_copy(t[0], &t[1], "bands", bands, "format", fmt, NULL) || vips__byteswap_bool(t[1], &t[2], !vips_amiMSBfirst()) || vips_image_write(t[2], out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } #endif /*HAVE_ANALYZE*/ libvips-8.18.2/libvips/foreign/analyzeload.c000066400000000000000000000107101516303661500210370ustar00rootroot00000000000000/* load analyze from a file * * 5/12/11 * - from openslideload.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_ANALYZE #include "pforeign.h" typedef struct _VipsForeignLoadAnalyze { VipsForeignLoad parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadAnalyze; typedef VipsForeignLoadClass VipsForeignLoadAnalyzeClass; G_DEFINE_TYPE(VipsForeignLoadAnalyze, vips_foreign_load_analyze, VIPS_TYPE_FOREIGN_LOAD); static VipsForeignFlags vips_foreign_load_analyze_get_flags_filename(const char *filename) { return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_analyze_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static int vips_foreign_load_analyze_header(VipsForeignLoad *load) { VipsForeignLoadAnalyze *analyze = (VipsForeignLoadAnalyze *) load; if (vips__analyze_read_header(analyze->filename, load->out)) return -1; VIPS_SETSTR(load->out->filename, analyze->filename); return 0; } static int vips_foreign_load_analyze_load(VipsForeignLoad *load) { VipsForeignLoadAnalyze *analyze = (VipsForeignLoadAnalyze *) load; if (vips__analyze_read(analyze->filename, load->real)) return -1; return 0; } static const char *vips_foreign_analyze_suffs[] = { ".img", ".hdr", NULL }; static void vips_foreign_load_analyze_class_init(VipsForeignLoadAnalyzeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "analyzeload"; object_class->description = _("load an Analyze6 image"); /* This is fuzzed, but you're unlikely to want to use it on * untrusted files. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips_foreign_analyze_suffs; /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; load_class->is_a = vips__isanalyze; load_class->get_flags_filename = vips_foreign_load_analyze_get_flags_filename; load_class->get_flags = vips_foreign_load_analyze_get_flags; load_class->header = vips_foreign_load_analyze_header; load_class->load = vips_foreign_load_analyze_load; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadAnalyze, filename), NULL); } static void vips_foreign_load_analyze_init(VipsForeignLoadAnalyze *analyze) { } #endif /*HAVE_ANALYZE*/ /** * vips_analyzeload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Load an Analyze 6.0 file. If @filename is "fred.img", this will look for * an image header called "fred.hdr" and pixel data in "fred.img". You can * also load "fred" or "fred.hdr". * * Images are * loaded lazilly and byte-swapped, if necessary. The Analyze metadata is read * and attached. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_analyzeload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("analyzeload", ap, filename, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/archive.c000066400000000000000000000154301516303661500201610ustar00rootroot00000000000000/* wrapper around libarchive * * 8/9/23 * - extracted from dzsave */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_LIBARCHIVE #include #include static GMutex vips_libarchive_mutex; struct _VipsArchive { // prepend filenames with this for filesystem output char *base_dirname; // write a zip to a target struct archive *archive; VipsTarget *target; }; void vips__archive_free(VipsArchive *archive) { // flush any pending writes to zip output if (archive->archive) archive_write_close(archive->archive); VIPS_FREE(archive->base_dirname); VIPS_FREEF(archive_write_free, archive->archive); VIPS_FREE(archive); } static ssize_t zip_write_target_cb(struct archive *a, void *client_data, const void *data, size_t length) { VipsArchive *archive = (VipsArchive *) client_data; if (vips_target_write(archive->target, data, length)) return -1; return length; } static int zip_close_target_cb(struct archive *a, void *client_data) { VipsArchive *archive = (VipsArchive *) client_data; if (vips_target_end(archive->target)) return ARCHIVE_FATAL; return ARCHIVE_OK; } // write to a filesystem directory VipsArchive * vips__archive_new_to_dir(const char *base_dirname) { VipsArchive *archive; if (!(archive = VIPS_NEW(NULL, VipsArchive))) return NULL; archive->base_dirname = g_strdup(base_dirname); return archive; } // write a zip to a target VipsArchive * vips__archive_new_to_target(VipsTarget *target, const char *base_dirname, int compression) { VipsArchive *archive; #ifdef DEBUG printf("vips__archive_new_to_target: base_dirname = %s, compression = %d\n", base_dirname, compression); #endif /*DEBUG*/ if (!(archive = VIPS_NEW(NULL, VipsArchive))) return NULL; archive->target = target; archive->base_dirname = g_strdup(base_dirname); if (!(archive->archive = archive_write_new())) { vips_error("archive", "%s", _("unable to create archive")); vips__archive_free(archive); return NULL; } /* Set format to zip. */ if (archive_write_set_format(archive->archive, ARCHIVE_FORMAT_ZIP)) { vips_error("archive", "%s", _("unable to set zip format")); vips__archive_free(archive); return NULL; } /* Remap compression=-1 to compression=6. */ if (compression == -1) compression = 6; /* Z_DEFAULT_COMPRESSION */ #if ARCHIVE_VERSION_NUMBER >= 3002000 /* Deflate compression requires libarchive >= v3.2.0. * https://github.com/libarchive/libarchive/pull/84 */ char compression_string[2] = { '0' + compression, 0 }; if (archive_write_set_format_option(archive->archive, "zip", "compression-level", compression_string)) { vips_error("archive", "%s", _("unable to set compression")); vips__archive_free(archive); return NULL; } #else if (compression > 0) g_warning("libarchive >= v3.2.0 required for Deflate compression"); #endif /* Do not pad last block. */ if (archive_write_set_bytes_in_last_block(archive->archive, 1)) { vips_error("archive", "%s", _("unable to set padding")); vips__archive_free(archive); return NULL; } /* Register target callback functions. */ if (archive_write_open(archive->archive, archive, NULL, zip_write_target_cb, zip_close_target_cb)) { vips_error("archive", "%s", _("unable to open for write")); vips__archive_free(archive); return NULL; } return archive; } static int vips__archive_mkdir_file(VipsArchive *archive, const char *dirname) { char *path; path = g_build_filename(archive->base_dirname, dirname, NULL); if (g_mkdir_with_parents(path, 0777) && errno != EEXIST) { int save_errno = errno; char *utf8name; utf8name = g_filename_display_name(path); vips_error("archive", _("unable to create directory \"%s\", %s"), utf8name, g_strerror(save_errno)); g_free(utf8name); g_free(path); return -1; } g_free(path); return 0; } int vips__archive_mkdir(VipsArchive *archive, const char *dirname) { /* The ZIP format maintains a hierarchical structure, avoiding * the need to create individual entries for each (sub-)directory. */ if (archive->archive) return 0; return vips__archive_mkdir_file(archive, dirname); } static int vips__archive_mkfile_zip(VipsArchive *archive, const char *filename, void *buf, size_t len) { struct archive_entry *entry; vips__worker_lock(&vips_libarchive_mutex); if (!(entry = archive_entry_new())) { vips_error("archive", "%s", _("unable to create entry")); g_mutex_unlock(&vips_libarchive_mutex); return -1; } char *path; path = g_build_filename(archive->base_dirname, filename, NULL); archive_entry_set_pathname(entry, path); archive_entry_set_mode(entry, S_IFREG | 0664); archive_entry_set_size(entry, len); g_free(path); if (archive_write_header(archive->archive, entry)) { vips_error("archive", "%s", _("unable to write header")); archive_entry_free(entry); g_mutex_unlock(&vips_libarchive_mutex); return -1; } archive_entry_free(entry); if (archive_write_data(archive->archive, buf, len) != len) { vips_error("archive", "%s", _("unable to write data")); g_mutex_unlock(&vips_libarchive_mutex); return -1; } g_mutex_unlock(&vips_libarchive_mutex); return 0; } static int vips__archive_mkfile_file(VipsArchive *archive, const char *filename, void *buf, size_t len) { char *path; FILE *f; path = g_build_filename(archive->base_dirname, filename, NULL); if (!(f = vips__file_open_write(path, FALSE))) { g_free(path); return -1; } if (vips__file_write(buf, sizeof(char), len, f)) { g_free(path); fclose(f); return -1; } fclose(f); g_free(path); return 0; } int vips__archive_mkfile(VipsArchive *archive, const char *filename, void *buf, size_t len) { return ((archive->archive) ? vips__archive_mkfile_zip : vips__archive_mkfile_file)(archive, filename, buf, len); } #endif /*HAVE_LIBARCHIVE*/ libvips-8.18.2/libvips/foreign/cairo.c000066400000000000000000000067771516303661500176530ustar00rootroot00000000000000/* Shared code for cairo based loaders like svgload and pdfload. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include /* Convert from Cairo-style premultiplied BGRA to RGBA. * * See also openslide's argb2rgba(). */ void vips__premultiplied_bgra2rgba(guint32 *restrict p, int n) { int x; for (x = 0; x < n; x++) { guint32 bgra = GUINT32_FROM_BE(p[x]); guint8 a = bgra & 0xff; guint32 rgba; if (a == 0 || a == 255) rgba = (bgra & 0x00ff00ff) | (bgra & 0x0000ff00) << 16 | (bgra & 0xff000000) >> 16; else /* Undo premultiplication. */ rgba = ((255 * ((bgra >> 8) & 0xff) / a) << 24) | ((255 * ((bgra >> 16) & 0xff) / a) << 16) | ((255 * ((bgra >> 24) & 0xff) / a) << 8) | a; p[x] = GUINT32_TO_BE(rgba); } } /* Unpremultiplied RGBA (vips convention) to cairo-style premul BGRA. */ void vips__rgba2bgra_premultiplied(guint32 *restrict p, int n) { int x; for (x = 0; x < n; x++) { guint32 rgba = GUINT32_FROM_BE(p[x]); guint8 a = rgba & 0xff; guint32 bgra; if (a == 0) bgra = 0; else if (a == 255) bgra = (rgba & 0x00ff00ff) | (rgba & 0x0000ff00) << 16 | (rgba & 0xff000000) >> 16; else { int r = (rgba >> 24) & 0xff; int g = (rgba >> 16) & 0xff; int b = (rgba >> 8) & 0xff; r = ((r * a) + 128) >> 8; g = ((g * a) + 128) >> 8; b = ((b * a) + 128) >> 8; bgra = (b << 24) | (g << 16) | (r << 8) | a; } p[x] = GUINT32_TO_BE(bgra); } } /* Convert from PDFium-style BGRA to RGBA. */ void vips__bgra2rgba(guint32 *restrict p, int n) { int x; for (x = 0; x < n; x++) { guint32 bgra = GUINT32_FROM_BE(p[x]); guint rgba; /* Leave G and A, swap R and B. */ rgba = (bgra & 0x00ff00ff) | (bgra & 0x0000ff00) << 16 | (bgra & 0xff000000) >> 16; p[x] = GUINT32_TO_BE(rgba); } } /* * Convert from Cairo-style premultiplied RGBA128F to straight RGBA, for one row. * It also linearizes the pixel values. * Processes 'n' pixels in the 'p' buffer. * The data is assumed to be RGBA (R, G, B, A) 32-bit floats per pixel. */ void vips__premultiplied_rgb1282scrgba(float *restrict p, int n) { vips_col_make_tables_RGB_16(); for (int x = 0; x < n; x++) { // CLIP is much faster than FCLIP, and we want an int result int ri = VIPS_CLIP(0, (int) (p[0] * 65535), 65535); int gi = VIPS_CLIP(0, (int) (p[1] * 65535), 65535); int bi = VIPS_CLIP(0, (int) (p[2] * 65535), 65535); // linearize the values with LUT float r = vips_v2Y_16[ri]; float g = vips_v2Y_16[gi]; float b = vips_v2Y_16[bi]; float a = p[3]; p[0] = a > 0.00001 ? r / a : 0.0F; p[1] = a > 0.00001 ? g / a : 0.0F; p[2] = a > 0.00001 ? b / a : 0.0F; p += 4; } } libvips-8.18.2/libvips/foreign/cgifsave.c000066400000000000000000001062721516303661500203340ustar00rootroot00000000000000/* save as GIF * * 22/8/21 lovell * 18/1/22 TheEssem * - fix change detector * 3/12/22 * - deprecate reoptimise, add reuse */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pforeign.h" #include "quantise.h" #if defined(HAVE_CGIF) && defined(HAVE_QUANTIZATION) #include /* The modes we work in. * * VIPS_FOREIGN_SAVE_CGIF_MODE_LOCAL: * * We find a global palette from the first frame, then write subsequent * frames with a local palette if they start to drift too far from the * first frame. * * VIPS_FOREIGN_SAVE_CGIF_MODE_GLOBAL: * * Each frame is dithered to single global colour table taken from the * input image "gif-palette" metadata item. * * We use LOCAL by default. We use GLOBAL if @reuse is set and there's * a palette attached to the image to be saved. */ typedef enum _VipsForeignSaveCgifMode { VIPS_FOREIGN_SAVE_CGIF_MODE_GLOBAL, VIPS_FOREIGN_SAVE_CGIF_MODE_LOCAL } VipsForeignSaveCgifMode; typedef struct _VipsForeignSaveCgif { VipsForeignSave parent_object; double dither; int effort; int bitdepth; double interframe_maxerror; gboolean reuse; gboolean interlace; gboolean keep_duplicate_frames; double interpalette_maxerror; VipsTarget *target; /* Derived write params. */ VipsForeignSaveCgifMode mode; VipsImage *in; /* Not a reference */ int *delay; int delay_length; int loop; /* The RGBA palette attached to the input image (if any). */ int *palette; int n_colours; /* The frame we are building, the y position in the frame. */ int frame_width; int frame_height; VipsPel *frame_bytes; int write_y; int page_number; /* The current frame as seen by libimagequant. */ VipsQuantiseAttr *attr; VipsQuantiseResult *quantisation_result; /* The palette we used for the previous frame. This can be equal to * quantisation_result if we used the global palette for the previous * frame, so don't free this. */ VipsQuantiseResult *previous_quantisation_result; /* ... and a palette we will need to free. */ VipsQuantiseResult *free_quantisation_result; /* The index frame we get libimagequant to generate. */ VipsPel *index; /* The previous RGBA frame (needed for transparency trick). */ VipsPel *previous_frame; /* The frame as written by libcgif. */ CGIF *cgif_context; CGIF_Config cgif_config; int n_palettes_generated; /* Deprecated. */ gboolean reoptimise; } VipsForeignSaveCgif; typedef VipsForeignSaveClass VipsForeignSaveCgifClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveCgif, vips_foreign_save_cgif, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_cgif_dispose(GObject *gobject) { VipsForeignSaveCgif *cgif = (VipsForeignSaveCgif *) gobject; g_info("cgifsave: %d frames", cgif->page_number); g_info("cgifsave: %d unique palettes", cgif->n_palettes_generated); VIPS_FREEF(cgif_close, cgif->cgif_context); VIPS_FREEF(vips__quantise_result_destroy, cgif->quantisation_result); VIPS_FREEF(vips__quantise_result_destroy, cgif->free_quantisation_result); VIPS_FREEF(vips__quantise_attr_destroy, cgif->attr); VIPS_UNREF(cgif->target); VIPS_FREE(cgif->index); VIPS_FREE(cgif->frame_bytes); VIPS_FREE(cgif->previous_frame); G_OBJECT_CLASS(vips_foreign_save_cgif_parent_class)->dispose(gobject); } static int vips__cgif_write(void *client, const uint8_t *buffer, const size_t length) { VipsTarget *target = VIPS_TARGET(client); return vips_target_write(target, (const void *) buffer, (size_t) length); } #define TRANS_STATE_NONE 0 #define TRANS_STATE_SINGLE 1 #define TRANS_STATE_ROW 2 /* Set pixels in index transparent if they are equal RGB to the previous * frame. * * In combination with the GIF transparency optimization this leads to * less difference between frames and therefore improves the compression ratio. */ static void vips_foreign_save_cgif_set_transparent(VipsForeignSaveCgif *cgif, VipsPel *old, VipsPel *new, VipsPel *index, int n_pels, int width, int trans) { int sq_maxerror = cgif->interframe_maxerror * cgif->interframe_maxerror; gboolean this_trans = FALSE; int trans_state = TRANS_STATE_NONE; int trans_count = 0; int same_count = 0; VipsPel *trans_start_index = index; VipsPel *trans_start_old = old; VipsPel *trans_start_new = new; for (int i = 0; i < n_pels; i++) { /* Alpha must match */ if (old[3] == new[3]) { /* Both transparent ... no need to check RGB. */ if (!old[3] && !new[3]) { *index = trans; this_trans = TRUE; } else { /* Compare RGB. */ const int dR = old[0] - new[0]; const int dG = old[1] - new[1]; const int dB = old[2] - new[2]; this_trans = dR * dR + dG * dG + dB * dB <= sq_maxerror; } } if (i && index[-1] == *index) same_count++; else same_count = 1; if (!this_trans) { /* Found an opaque pixel. * * If we found a single transparent pixel before, we haven't been * copying new to old since then. Time to do it now. */ if (trans_state == TRANS_STATE_SINGLE) memcpy(trans_start_old, trans_start_new, old - trans_start_old); /* And reset the transparent pixels state */ trans_state = TRANS_STATE_NONE; trans_count = 0; } else { int x = i % width; trans_count++; if (trans_state == TRANS_STATE_NONE) { /* Found the first pixel that should be transparent. */ if (x == 0) /* If we are at the start of the row, start making pixels * transparent right away to help CGIF to trim the * frame. */ trans_state = TRANS_STATE_ROW; else { /* Otherwise, just mark the point where we found it and * update the transparent pixels state. */ trans_start_index = index; trans_start_old = old; trans_start_new = new; trans_state = TRANS_STATE_SINGLE; } /* We don't want to break a row of identical indexes with a * transparent pixel because this would be unoptimal for LZW. * The only exception is if we are at the end of the * row. In this case, transparent pixels will help CGIF * to trim the frame. */ } else if (trans_state == TRANS_STATE_SINGLE && (trans_count * 2 >= same_count + 32 || x == width - 1 || *index != index[-1])) { /* We found a transparent pixel before and the previous index * doesn't match the current index. Make all pixels from the * marked point to the current point transparent and update * the transparent pixels state. */ trans_state = TRANS_STATE_ROW; memset(trans_start_index, trans, index - trans_start_index); } } if (trans_state == TRANS_STATE_ROW) /* Since we have more than one transparent pixel in a row, it's * safe to make the current pixel transparent. */ *index = trans; else if (trans_state == TRANS_STATE_NONE) { /* We did not find a pixel that should be transparent before. Just * copy new to old. */ old[0] = new[0]; old[1] = new[1]; old[2] = new[2]; old[3] = new[3]; } old += 4; new += 4; index += 1; this_trans = FALSE; } /* If we are still in the single transparent pixel state, make the rest * of pixels transparent */ if (trans_state == TRANS_STATE_SINGLE) memset(trans_start_index, trans, index - trans_start_index); } static double vips__cgif_compare_palettes(const VipsQuantisePalette *new, const VipsQuantisePalette *old) { double best_dist, dist, rd, gd, bd; double total_dist; g_assert(new->count <= 256); g_assert(old->count <= 256); total_dist = 0; for (int i = 0; i < new->count; i++) { best_dist = 255 * 255 * 3; for (int j = 0; j < old->count; j++) { if (new->entries[i].a) { /* The new entry is solid. * If the old entry is transparent, ignore it. Otherwise, * compare RGB. */ if (!old->entries[j].a) continue; rd = new->entries[i].r - old->entries[j].r; gd = new->entries[i].g - old->entries[j].g; bd = new->entries[i].b - old->entries[j].b; dist = rd * rd + gd * gd + bd * bd; best_dist = VIPS_MIN(best_dist, dist); /* We found the closest entry. */ if (best_dist == 0) break; } else { /* The new entry is transparent. * If the old entry is transparent too, it's the closest * color. Otherwise, ignore it. */ if (!old->entries[j].a) { best_dist = 0; break; } } } total_dist += best_dist; } return sqrt(total_dist / (3 * new->count)); } /* Extract the generated palette as RGB. */ static void vips_foreign_save_cgif_get_rgb_palette(VipsForeignSaveCgif *cgif, VipsQuantiseResult *quantisation_result, VipsPel *rgb) { const VipsQuantisePalette *lp = vips__quantise_get_palette(quantisation_result); g_assert(lp->count <= 256); for (int i = 0; i < lp->count; i++) { rgb[0] = lp->entries[i].r; rgb[1] = lp->entries[i].g; rgb[2] = lp->entries[i].b; rgb += 3; } } int vips_foreign_save_cgif_pick_quantiser(VipsForeignSaveCgif *cgif, VipsQuantiseImage *image, VipsQuantiseResult **result, gboolean *use_local) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(cgif); VipsQuantiseResult *this_result; if (vips__quantise_image_quantize_fixed(image, cgif->attr, &this_result)) { vips_error(class->nickname, "%s", _("quantisation failed")); return -1; } /* No global quantiser set up yet? Use this result. */ if (!cgif->quantisation_result) { #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_pick_quantiser: " "global palette from first frame\n"); #endif /*DEBUG_VERBOSE*/ cgif->quantisation_result = this_result; cgif->n_palettes_generated += 1; *result = this_result; *use_local = FALSE; } else { /* Compare the palette we just made to the palette for the previous * frame, and to the global palette. */ const VipsQuantisePalette *global = vips__quantise_get_palette( cgif->quantisation_result); const VipsQuantisePalette *this = vips__quantise_get_palette( this_result); const VipsQuantisePalette *prev = vips__quantise_get_palette( cgif->previous_quantisation_result); double global_diff = vips__cgif_compare_palettes(this, global); double prev_diff = prev == global ? global_diff : vips__cgif_compare_palettes(this, prev); #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_write_frame: " "this -> global distance = %g\n", global_diff); printf("vips_foreign_save_cgif_write_frame: " "this -> prev distance = %g\n", prev_diff); printf("vips_foreign_save_cgif_write_frame: " "threshold = %g\n", cgif->interpalette_maxerror); #endif /*DEBUG_VERBOSE*/ if (global_diff <= prev_diff && global_diff < cgif->interpalette_maxerror) { /* Global is good enough, use that. */ #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_write_frame: " "using global palette\n"); #endif /*DEBUG_VERBOSE*/ VIPS_FREEF(vips__quantise_result_destroy, this_result); VIPS_FREEF(vips__quantise_result_destroy, cgif->free_quantisation_result); *result = cgif->quantisation_result; *use_local = FALSE; } else if (prev_diff < cgif->interpalette_maxerror) { /* Previous is good enough, use that again. */ #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_write_frame: " "using previous palette\n"); #endif /*DEBUG_VERBOSE*/ VIPS_FREEF(vips__quantise_result_destroy, this_result); *result = cgif->previous_quantisation_result; *use_local = TRUE; } else { /* Nothing else works, we need a new local palette. */ #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_write_frame: " "using new local palette\n"); #endif /*DEBUG_VERBOSE*/ VIPS_FREEF(vips__quantise_result_destroy, cgif->free_quantisation_result); cgif->free_quantisation_result = this_result; cgif->n_palettes_generated += 1; *result = this_result; *use_local = TRUE; } } cgif->previous_quantisation_result = *result; return 0; } /* We have a complete frame -- write! */ static int vips_foreign_save_cgif_write_frame(VipsForeignSaveCgif *cgif) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(cgif); int n_pels = cgif->frame_height * cgif->frame_width; gboolean has_transparency; gboolean has_alpha_constraint; VipsPel *restrict p; VipsQuantiseImage *image; gboolean use_local; VipsQuantiseResult *quantisation_result; const VipsQuantisePalette *lp; CGIF_FrameConfig frame_config = { 0 }; int n_colours; VipsPel palette_rgb[256 * 3]; #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_write_frame: %d\n", cgif->page_number); #endif /*DEBUG_VERBOSE*/ /* Threshold the alpha channel. * * Also, check if the alpha channel of the current frame matches the * frame before. * * If the current frame has an alpha component which is not identical * to the previous frame we are forced to use the transparency index * for the alpha channel instead of for the transparency size * optimization (maxerror). */ p = cgif->frame_bytes; has_alpha_constraint = FALSE; for (int i = 0; i < n_pels; i++) { if (p[3] >= 128) p[3] = 255; else { /* Helps the quantiser generate a better palette. */ p[0] = 0; p[1] = 0; p[2] = 0; p[3] = 0; if (cgif->page_number > 0 && cgif->previous_frame[i * 4 + 3]) has_alpha_constraint = TRUE; } p += 4; } /* Set up new frame for libimagequant. */ image = vips__quantise_image_create_rgba(cgif->attr, cgif->frame_bytes, cgif->frame_width, cgif->frame_height, 0); if (cgif->mode == VIPS_FOREIGN_SAVE_CGIF_MODE_LOCAL || !cgif->quantisation_result) { /* Reoptimising each frame, or no global palette set up yet. */ if (vips_foreign_save_cgif_pick_quantiser(cgif, image, &quantisation_result, &use_local)) return -1; } else { quantisation_result = cgif->quantisation_result; use_local = FALSE; } lp = vips__quantise_get_palette(quantisation_result); /* If there's a transparent pixel, it's always first. */ has_transparency = lp->entries[0].a == 0; n_colours = lp->count; vips_foreign_save_cgif_get_rgb_palette(cgif, quantisation_result, palette_rgb); /* Dither frame into @index. */ vips__quantise_set_dithering_level(quantisation_result, cgif->dither); if (vips__quantise_write_remapped_image(quantisation_result, image, cgif->index, n_pels)) { vips_error(class->nickname, "%s", _("dither failed")); VIPS_FREEF(vips__quantise_image_destroy, image); return -1; } VIPS_FREEF(vips__quantise_image_destroy, image); /* Remapping is relatively slow, trigger eval callbacks. */ vips_image_eval(cgif->in, n_pels); if (vips_image_iskilled(cgif->in)) return -1; /* Set up cgif on first use. */ if (!cgif->cgif_context) { #ifdef HAVE_CGIF_GEN_KEEP_IDENT_FRAMES if (cgif->keep_duplicate_frames) cgif->cgif_config.genFlags = CGIF_GEN_KEEP_IDENT_FRAMES; #endif #ifdef HAVE_CGIF_ATTR_NO_LOOP cgif->cgif_config.attrFlags = CGIF_ATTR_IS_ANIMATED | (cgif->loop == 1 ? CGIF_ATTR_NO_LOOP : 0); cgif->cgif_config.numLoops = cgif->loop > 1 ? cgif->loop - 1 : cgif->loop; #else /*!HAVE_CGIF_ATTR_NO_LOOP*/ cgif->cgif_config.attrFlags = CGIF_ATTR_IS_ANIMATED; cgif->cgif_config.numLoops = cgif->loop; #endif /*HAVE_CGIF_ATTR_NO_LOOP*/ cgif->cgif_config.width = cgif->frame_width; cgif->cgif_config.height = cgif->frame_height; cgif->cgif_config.pGlobalPalette = palette_rgb; cgif->cgif_config.numGlobalPaletteEntries = n_colours; cgif->cgif_config.pWriteFn = vips__cgif_write; cgif->cgif_config.pContext = (void *) cgif->target; cgif->cgif_context = cgif_newgif(&cgif->cgif_config); } /* Allow cgif to optimise by adding transparency. These optimisations * will be automatically disabled if they are not possible. */ frame_config.genFlags = CGIF_FRAME_GEN_USE_TRANSPARENCY | CGIF_FRAME_GEN_USE_DIFF_WINDOW; frame_config.attrFlags = 0; /* Switch per-frame alpha channel on. Index 0 is used for pixels * with alpha channel. */ if (has_transparency) { frame_config.attrFlags |= CGIF_FRAME_ATTR_HAS_ALPHA; frame_config.transIndex = 0; } /* Pixels which are equal to pixels in the previous frame can be made * transparent, provided no alpha channel constraint is present. */ if (cgif->page_number > 0 && !has_alpha_constraint) { int trans = has_transparency ? 0 : n_colours; vips_foreign_save_cgif_set_transparent(cgif, cgif->previous_frame, cgif->frame_bytes, cgif->index, n_pels, cgif->frame_width, trans); if (has_transparency) frame_config.attrFlags &= ~CGIF_FRAME_ATTR_HAS_ALPHA; frame_config.attrFlags |= CGIF_FRAME_ATTR_HAS_SET_TRANS; frame_config.transIndex = trans; } else { /* Take a copy of the RGBA frame. */ memcpy(cgif->previous_frame, cgif->frame_bytes, 4 * n_pels); } if (cgif->delay && cgif->page_number < cgif->delay_length) frame_config.delay = rint(cgif->delay[cgif->page_number] / 10.0); /* Attach a local palette, if we need one. */ if (use_local) { frame_config.attrFlags |= CGIF_FRAME_ATTR_USE_LOCAL_TABLE; frame_config.pLocalPalette = palette_rgb; frame_config.numLocalPaletteEntries = n_colours; } /* Write an interlaced GIF, if requested. */ if (cgif->interlace) { #ifdef HAVE_CGIF_FRAME_ATTR_INTERLACED frame_config.attrFlags |= CGIF_FRAME_ATTR_INTERLACED; #else /*!HAVE_CGIF_FRAME_ATTR_INTERLACED*/ g_warning("cgif >= v0.3.0 required for interlaced GIF write"); #endif /*HAVE_CGIF_FRAME_ATTR_INTERLACED*/ } /* Write frame to cgif. */ frame_config.pImageData = cgif->index; cgif_addframe(cgif->cgif_context, &frame_config); return 0; } /* Another chunk of pixels have arrived from the pipeline. Add to frame, and * if the frame completes, compress and write to the target. */ static int vips_foreign_save_cgif_sink_disc(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveCgif *cgif = (VipsForeignSaveCgif *) a; int line_size = cgif->frame_width * 4; #ifdef DEBUG_VERBOSE printf("vips_foreign_save_cgif_sink_disc: strip at %d, height %d\n", area->top, area->height); #endif /*DEBUG_VERBOSE*/ for (int y = 0; y < area->height; y++) { memcpy(cgif->frame_bytes + cgif->write_y * line_size, VIPS_REGION_ADDR(region, 0, area->top + y), line_size); cgif->write_y += 1; if (cgif->write_y >= cgif->frame_height) { if (vips_foreign_save_cgif_write_frame(cgif)) return -1; cgif->write_y = 0; cgif->page_number += 1; } } return 0; } static int vips_foreign_save_cgif_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveCgif *cgif = (VipsForeignSaveCgif *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(cgif); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(cgif), 2); if (VIPS_OBJECT_CLASS(vips_foreign_save_cgif_parent_class)->build(object)) return -1; cgif->in = save->ready; /* libimagequant only works with RGBA images. */ if (!vips_image_hasalpha(cgif->in)) { if (vips_addalpha(cgif->in, &t[1], NULL)) return -1; cgif->in = t[1]; } /* Animation properties. */ if (vips_image_get_typeof(cgif->in, "delay")) vips_image_get_array_int(cgif->in, "delay", &cgif->delay, &cgif->delay_length); if (vips_image_get_typeof(cgif->in, "loop")) vips_image_get_int(cgif->in, "loop", &cgif->loop); cgif->frame_height = vips_image_get_page_height(cgif->in); cgif->frame_width = cgif->in->Xsize; /* Reject images that exceed the pixel limit of libimagequant, * or that exceed the GIF limit of 64k per axis. * * Frame width * height will fit in an int, though frame size will * need at least a uint. */ if ((guint64) cgif->frame_width * cgif->frame_height > INT_MAX / 4 || cgif->frame_width > 65535 || cgif->frame_height > 65535) { vips_error(class->nickname, "%s", _("frame too large")); return -1; } /* This RGBA frame as a contiguous buffer. */ cgif->frame_bytes = g_malloc0((size_t) 4 * cgif->frame_width * cgif->frame_height); /* The previous RGBA frame (for spotting pixels which haven't changed). */ cgif->previous_frame = g_malloc0((size_t) 4 * cgif->frame_width * cgif->frame_height); /* The frame index buffer. */ cgif->index = g_malloc0((size_t) cgif->frame_width * cgif->frame_height); /* Set up libimagequant. */ cgif->attr = vips__quantise_attr_create(); /* Limit the number of colours to 255 so there is always one index * free for transparency optimization. */ vips__quantise_set_max_colors(cgif->attr, VIPS_MIN(255, 1 << cgif->bitdepth)); vips__quantise_set_quality(cgif->attr, 0, 100); vips__quantise_set_speed(cgif->attr, 11 - cgif->effort); /* Read the palette on the input if we've not been asked to * reoptimise. */ if (cgif->reuse && vips_image_get_typeof(cgif->in, "gif-palette")) { if (vips_image_get_array_int(cgif->in, "gif-palette", &cgif->palette, &cgif->n_colours)) return -1; if (cgif->n_colours > 256) { vips_error(class->nickname, "%s", _("gif-palette too large")); return -1; } } if (cgif->palette) { /* Make a fake image from the input palette, and quantise that. * Add a zero pixel (transparent) in case the input image has * transparency. * * We know palette fits in 256 entries. */ guint32 fake_image[257]; VipsQuantiseImage *image; memcpy(fake_image, cgif->palette, cgif->n_colours * sizeof(int)); fake_image[cgif->n_colours] = 0; image = vips__quantise_image_create_rgba(cgif->attr, fake_image, cgif->n_colours + 1, 1, 0); if (vips__quantise_image_quantize_fixed(image, cgif->attr, &cgif->quantisation_result)) { vips_error(class->nickname, "%s", _("quantisation failed")); return -1; } VIPS_FREEF(vips__quantise_image_destroy, image); } /* Global mode if there's an input palette, or palette maxerror is * huge. */ if (cgif->palette || cgif->interpalette_maxerror > 255) cgif->mode = VIPS_FOREIGN_SAVE_CGIF_MODE_GLOBAL; else cgif->mode = VIPS_FOREIGN_SAVE_CGIF_MODE_LOCAL; if (vips_sink_disc(cgif->in, vips_foreign_save_cgif_sink_disc, cgif)) return -1; VIPS_FREEF(cgif_close, cgif->cgif_context); if (vips_target_end(cgif->target)) return -1; return 0; } static const char *vips__save_cgif_suffs[] = { ".gif", NULL }; #define UC VIPS_FORMAT_UCHAR /* Type promotion for save ... just always go to uchar. */ static VipsBandFormat bandfmt_gif[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static void vips_foreign_save_cgif_class_init(VipsForeignSaveCgifClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_cgif_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifsave_base"; object_class->description = _("save as gif"); object_class->build = vips_foreign_save_cgif_build; foreign_class->suffs = vips__save_cgif_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA; save_class->format_table = bandfmt_gif; VIPS_ARG_DOUBLE(class, "dither", 10, _("Dithering"), _("Amount of dithering"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, dither), 0.0, 1.0, 1.0); VIPS_ARG_INT(class, "effort", 11, _("Effort"), _("Quantisation effort"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, effort), 1, 10, 7); VIPS_ARG_INT(class, "bitdepth", 12, _("Bit depth"), _("Number of bits per pixel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, bitdepth), 1, 8, 8); VIPS_ARG_DOUBLE(class, "interframe_maxerror", 13, _("Maximum inter-frame error"), _("Maximum inter-frame error for transparency"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, interframe_maxerror), 0, 32, 0.0); VIPS_ARG_BOOL(class, "reuse", 14, _("Reuse palette"), _("Reuse palette from input"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, reuse), FALSE); VIPS_ARG_DOUBLE(class, "interpalette_maxerror", 15, _("Maximum inter-palette error"), _("Maximum inter-palette error for palette reusage"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, interpalette_maxerror), 0, 256, 3.0); VIPS_ARG_BOOL(class, "interlace", 16, _("Interlaced"), _("Generate an interlaced (progressive) GIF"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, interlace), FALSE); /* Not a good thing to have enabled by default since it can cause very * mysterious behaviour that varies with the input image. */ VIPS_ARG_BOOL(class, "reoptimise", 17, _("Reoptimise palettes"), _("Reoptimise colour palettes"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveCgif, reoptimise), FALSE); VIPS_ARG_BOOL(class, "keep_duplicate_frames", 18, _("Keep duplicate frames"), _("Keep duplicate frames in the output instead of combining them"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgif, keep_duplicate_frames), FALSE); } static void vips_foreign_save_cgif_init(VipsForeignSaveCgif *gif) { gif->dither = 1.0; gif->effort = 7; gif->bitdepth = 8; gif->interframe_maxerror = 0.0; gif->reuse = FALSE; gif->interlace = FALSE; gif->interpalette_maxerror = 3.0; gif->mode = VIPS_FOREIGN_SAVE_CGIF_MODE_GLOBAL; } typedef struct _VipsForeignSaveCgifTarget { VipsForeignSaveCgif parent_object; VipsTarget *target; } VipsForeignSaveCgifTarget; typedef VipsForeignSaveCgifClass VipsForeignSaveCgifTargetClass; G_DEFINE_TYPE(VipsForeignSaveCgifTarget, vips_foreign_save_cgif_target, vips_foreign_save_cgif_get_type()); static int vips_foreign_save_cgif_target_build(VipsObject *object) { VipsForeignSaveCgif *gif = (VipsForeignSaveCgif *) object; VipsForeignSaveCgifTarget *target = (VipsForeignSaveCgifTarget *) object; gif->target = target->target; g_object_ref(gif->target); return VIPS_OBJECT_CLASS(vips_foreign_save_cgif_target_parent_class) ->build(object); } static void vips_foreign_save_cgif_target_class_init( VipsForeignSaveCgifTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifsave_target"; object_class->build = vips_foreign_save_cgif_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgifTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_cgif_target_init(VipsForeignSaveCgifTarget *target) { } typedef struct _VipsForeignSaveCgifFile { VipsForeignSaveCgif parent_object; char *filename; } VipsForeignSaveCgifFile; typedef VipsForeignSaveCgifClass VipsForeignSaveCgifFileClass; G_DEFINE_TYPE(VipsForeignSaveCgifFile, vips_foreign_save_cgif_file, vips_foreign_save_cgif_get_type()); static int vips_foreign_save_cgif_file_build(VipsObject *object) { VipsForeignSaveCgif *gif = (VipsForeignSaveCgif *) object; VipsForeignSaveCgifFile *file = (VipsForeignSaveCgifFile *) object; if (!(gif->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_cgif_file_parent_class) ->build(object); } static void vips_foreign_save_cgif_file_class_init(VipsForeignSaveCgifFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifsave"; object_class->build = vips_foreign_save_cgif_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCgifFile, filename), NULL); } static void vips_foreign_save_cgif_file_init(VipsForeignSaveCgifFile *file) { } typedef struct _VipsForeignSaveCgifBuffer { VipsForeignSaveCgif parent_object; VipsArea *buf; } VipsForeignSaveCgifBuffer; typedef VipsForeignSaveCgifClass VipsForeignSaveCgifBufferClass; G_DEFINE_TYPE(VipsForeignSaveCgifBuffer, vips_foreign_save_cgif_buffer, vips_foreign_save_cgif_get_type()); static int vips_foreign_save_cgif_buffer_build(VipsObject *object) { VipsForeignSaveCgif *gif = (VipsForeignSaveCgif *) object; VipsForeignSaveCgifBuffer *buffer = (VipsForeignSaveCgifBuffer *) object; VipsBlob *blob; if (!(gif->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_cgif_buffer_parent_class) ->build(object)) return -1; g_object_get(gif->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_cgif_buffer_class_init( VipsForeignSaveCgifBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifsave_buffer"; object_class->build = vips_foreign_save_cgif_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveCgifBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_cgif_buffer_init(VipsForeignSaveCgifBuffer *buffer) { } #endif /*defined(HAVE_CGIF) && defined(HAVE_IMAGEQUANT)*/ /** * vips_gifsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write to a file in GIF format. * * Use @dither to set the degree of Floyd-Steinberg dithering * and @effort to control the CPU effort (1 is the fastest, * 10 is the slowest, 7 is the default). * * Use @bitdepth (from 1 to 8, default 8) to control the number * of colours in the palette. The first entry in the palette is * always reserved for transparency. For example, a bitdepth of * 4 will allow the output to contain up to 15 colours. * * Use @interframe_maxerror to set the threshold below which pixels are * considered equal. * Pixels which don't change from frame to frame can be made transparent, * improving the compression rate. Default 0. * * Use @interpalette_maxerror to set the threshold below which the * previously generated palette will be reused. * * If @reuse is `TRUE`, the GIF will be saved with a single global * palette taken from the metadata in @in, and no new palette optimisation * will be done. * * If @interlace is `TRUE`, the GIF file will be interlaced (progressive GIF). * These files may be better for display over a slow network * connection, but need more memory to encode. * * If @keep_duplicate_frames is `TRUE`, duplicate frames in the input will be * kept in the output instead of combining them. * * ::: tip "Optional arguments" * * @dither: `gdouble`, quantisation dithering level * * @effort: `gint`, quantisation CPU effort * * @bitdepth: `gint`, number of bits per pixel * * @interframe_maxerror: `gdouble`, maximum inter-frame error for * transparency * * @reuse: `gboolean`, reuse palette from input * * @interlace: `gboolean`, write an interlaced (progressive) GIF * * @interpalette_maxerror: `gdouble`, maximum inter-palette error for * palette reusage * * @keep_duplicate_frames: `gboolean`, keep duplicate frames in the output * instead of combining them * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_gifsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("gifsave", ap, in, filename); va_end(ap); return result; } /** * vips_gifsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.gifsave], but save to a memory buffer. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: tip "Optional arguments" * * @dither: `gdouble`, quantisation dithering level * * @effort: `gint`, quantisation CPU effort * * @bitdepth: `gint`, number of bits per pixel * * @interframe_maxerror: `gdouble`, maximum inter-frame error for * transparency * * @reuse: `gboolean`, reuse palette from input * * @interlace: `gboolean`, write an interlaced (progressive) GIF * * @interpalette_maxerror: `gdouble`, maximum inter-palette error for * palette reusage * * @keep_duplicate_frames: `gboolean`, keep duplicate frames in the output * instead of combining them * * ::: seealso * [method@Image.gifsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_gifsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("gifsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_gifsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.gifsave], but save to a target. * * ::: tip "Optional arguments" * * @dither: `gdouble`, quantisation dithering level * * @effort: `gint`, quantisation CPU effort * * @bitdepth: `gint`, number of bits per pixel * * @interframe_maxerror: `gdouble`, maximum inter-frame error for * transparency * * @reuse: `gboolean`, reuse palette from input * * @interlace: `gboolean`, write an interlaced (progressive) GIF * * @interpalette_maxerror: `gdouble`, maximum inter-palette error for * palette reusage * * @keep_duplicate_frames: `gboolean`, keep duplicate frames in the output * instead of combining them * * ::: seealso * [method@Image.gifsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_gifsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("gifsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/csvload.c000066400000000000000000000433771516303661500202060ustar00rootroot00000000000000/* load csv from a file * * 5/12/11 * - from csvload.c * 21/2/20 * - rewrite for new source API */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" /* The largest item we can read. It only needs to be big enough for a double. */ #define MAX_ITEM_SIZE (256) typedef struct _VipsForeignLoadCsv { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Buffered source. */ VipsSbuf *sbuf; /* Load options. */ int skip; int lines; const char *whitespace; const char *separator; /* Current position in file for error messages. */ int lineno; int colno; /* Our whitespace and separator strings turned into LUTs. */ char whitemap[256]; char sepmap[256]; /* Fetch items into this buffer. It just needs to be large enough for * a double. */ char item[MAX_ITEM_SIZE]; /* A line of pixels. */ double *linebuf; } VipsForeignLoadCsv; typedef VipsForeignLoadClass VipsForeignLoadCsvClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadCsv, vips_foreign_load_csv, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_csv_dispose(GObject *gobject) { VipsForeignLoadCsv *csv = (VipsForeignLoadCsv *) gobject; VIPS_UNREF(csv->source); VIPS_UNREF(csv->sbuf); VIPS_FREE(csv->linebuf); G_OBJECT_CLASS(vips_foreign_load_csv_parent_class)->dispose(gobject); } static int vips_foreign_load_csv_build(VipsObject *object) { VipsForeignLoadCsv *csv = (VipsForeignLoadCsv *) object; int i; const char *p; if (!g_str_is_ascii(csv->whitespace) || !g_str_is_ascii(csv->separator)) { vips_error("csvload", "%s", _("whitespace and separator must be ASCII")); return -1; } if (!(csv->sbuf = vips_sbuf_new_from_source(csv->source))) return -1; /* Make our char maps. */ for (i = 0; i < 256; i++) { csv->whitemap[i] = 0; csv->sepmap[i] = 0; } for (p = csv->whitespace; *p; p++) csv->whitemap[(int) *p] = 1; for (p = csv->separator; *p; p++) csv->sepmap[(int) *p] = 1; /* \n must not be in the maps or we'll get very confused. */ csv->sepmap[(int) '\n'] = 0; csv->whitemap[(int) '\n'] = 0; return VIPS_OBJECT_CLASS(vips_foreign_load_csv_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_csv_get_flags(VipsForeignLoad *load) { return 0; } /* Skip to the start of the next block of non-whitespace. * * Result: !white, \n, EOF */ static int vips_foreign_load_csv_skip_white(VipsForeignLoadCsv *csv) { int ch; do { ch = VIPS_SBUF_GETC(csv->sbuf); } while (ch != EOF && ch != '\n' && csv->whitemap[ch]); VIPS_SBUF_UNGETC(csv->sbuf); return ch; } /* We have just seen " (open quotes). Skip to just after the matching close * quotes. * * If there is no matching close quotes before the end of the line, don't * skip to the next line. * * Result: ", \n, EOF */ static int vips_foreign_load_csv_skip_quoted(VipsForeignLoadCsv *csv) { int ch; do { ch = VIPS_SBUF_GETC(csv->sbuf); /* Ignore \" (actually \anything) in strings. */ if (ch == '\\') ch = VIPS_SBUF_GETC(csv->sbuf); else if (ch == '"') break; } while (ch != EOF && ch != '\n'); if (ch == '\n') VIPS_SBUF_UNGETC(csv->sbuf); return ch; } /* Fetch the next item (not whitespace, separator or \n), as a string. The * returned string is valid until the next call to fetch item. NULL for EOF. */ static const char * vips_foreign_load_csv_fetch_item(VipsForeignLoadCsv *csv) { int write_point; int space_remaining; int ch; /* -1 so there's space for the \0 terminator. */ space_remaining = MAX_ITEM_SIZE - 1; write_point = 0; while ((ch = VIPS_SBUF_GETC(csv->sbuf)) != -1 && ch != '\n' && !csv->whitemap[ch] && !csv->sepmap[ch] && space_remaining > 0) { csv->item[write_point] = ch; write_point += 1; space_remaining -= 1; } csv->item[write_point] = '\0'; /* If we hit EOF immediately, return EOF. */ if (ch == -1 && write_point == 0) return NULL; /* If we filled the item buffer without seeing the end of the item, * read up to the item end. */ while (ch != -1 && ch != '\n' && !csv->whitemap[ch] && !csv->sepmap[ch]) ch = VIPS_SBUF_GETC(csv->sbuf); /* We've (probably) read the end of item character. Push it back. */ if (ch == -1 || ch == '\n' || csv->whitemap[ch] || csv->sepmap[ch]) VIPS_SBUF_UNGETC(csv->sbuf); return csv->item; } /* Read a single item. The syntax is: * * element : * whitespace* item whitespace* [EOF|EOL|separator] * * item : * double | * "anything" | * empty * * the anything in quotes can contain " escaped with \, and can contain * separator and whitespace characters. * * Result: sep, \n, EOF */ static int vips_foreign_load_csv_read_double(VipsForeignLoadCsv *csv, double *out) { int ch; /* The strtod() may change this ... but all other cases need a zero. */ *out = 0; ch = vips_foreign_load_csv_skip_white(csv); if (ch == EOF || ch == '\n') return ch; if (ch == '"') { (void) VIPS_SBUF_GETC(csv->sbuf); ch = vips_foreign_load_csv_skip_quoted(csv); } else if (!csv->sepmap[ch]) { const char *item; item = vips_foreign_load_csv_fetch_item(csv); if (!item) return EOF; if (vips_strtod(item, out)) /* Only a warning, since (for example) exported * spreadsheets will often have text or date fields. */ g_warning("bad number, line %d, column %d", csv->lineno, csv->colno); } ch = vips_foreign_load_csv_skip_white(csv); if (ch == EOF || ch == '\n') return ch; /* If it's a separator, we have to step over it. */ if (csv->sepmap[ch]) (void) VIPS_SBUF_GETC(csv->sbuf); return ch; } static int vips_foreign_load_csv_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadCsv *csv = (VipsForeignLoadCsv *) load; int i; double value; int ch; int width; int height; /* Rewind. */ vips_sbuf_unbuffer(csv->sbuf); if (vips_source_rewind(csv->source)) return -1; /* Skip the first few lines. */ for (i = 0; i < csv->skip; i++) if (!vips_sbuf_get_line(csv->sbuf)) { vips_error(class->nickname, "%s", _("unexpected end of file")); return -1; } /* Parse the first line to get the number of columns. */ csv->lineno = csv->skip + 1; csv->colno = 0; do { csv->colno += 1; ch = vips_foreign_load_csv_read_double(csv, &value); } while (ch != '\n' && ch != EOF); width = csv->colno; if (!(csv->linebuf = VIPS_ARRAY(NULL, width, double))) return -1; /* If @lines is -1, we must scan the whole file to get the height. */ if (csv->lines == -1) for (height = 0; vips_sbuf_get_line(csv->sbuf); height++) ; else height = csv->lines; vips_image_init_fields(load->out, width, height, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0); if (vips_image_pipelinev(load->out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; VIPS_SETSTR(load->out->filename, vips_connection_filename(VIPS_CONNECTION(csv->source))); return 0; } static int vips_foreign_load_csv_load(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadCsv *csv = (VipsForeignLoadCsv *) load; int i; int x, y; int ch; /* Rewind. */ vips_sbuf_unbuffer(csv->sbuf); if (vips_source_rewind(csv->source)) return -1; /* Skip the first few lines. */ for (i = 0; i < csv->skip; i++) if (!vips_sbuf_get_line(csv->sbuf)) { vips_error(class->nickname, "%s", _("unexpected end of file")); return -1; } vips_image_init_fields(load->real, load->out->Xsize, load->out->Ysize, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0); if (vips_image_pipelinev(load->real, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; csv->lineno = csv->skip + 1; for (y = 0; y < load->real->Ysize; y++) { csv->colno = 0; /* Not needed, but stops a used-before-set compiler warning. */ ch = EOF; /* Some lines may be shorter. */ memset(csv->linebuf, 0, load->real->Xsize * sizeof(double)); for (x = 0; x < load->real->Xsize; x++) { double value; csv->colno += 1; ch = vips_foreign_load_csv_read_double(csv, &value); if (ch == EOF && load->fail_on >= VIPS_FAIL_ON_TRUNCATED) { vips_error(class->nickname, "%s", _("unexpected end of file")); return -1; } if (ch == '\n' && x != load->real->Xsize - 1) { vips_error(class->nickname, _("line %d has only %d columns"), csv->lineno, csv->colno); /* Unequal length lines, but no EOF. */ if (load->fail_on >= VIPS_FAIL_ON_ERROR) return -1; } csv->linebuf[x] = value; } /* Step over the line separator. */ if (ch == '\n') { (void) VIPS_SBUF_GETC(csv->sbuf); csv->lineno += 1; } if (vips_image_write_line(load->real, y, (VipsPel *) csv->linebuf)) return -1; } return 0; } static void vips_foreign_load_csv_class_init(VipsForeignLoadCsvClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_csv_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "csvload_base"; object_class->description = _("load csv"); object_class->build = vips_foreign_load_csv_build; /* This is fuzzed, but you're unlikely to want to use it on * untrusted files. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; load_class->get_flags = vips_foreign_load_csv_get_flags; load_class->header = vips_foreign_load_csv_header; load_class->load = vips_foreign_load_csv_load; VIPS_ARG_INT(class, "skip", 20, _("Skip"), _("Skip this many lines at the start of the file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadCsv, skip), 0, 10000000, 0); VIPS_ARG_INT(class, "lines", 21, _("Lines"), _("Read this many lines from the file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadCsv, lines), -1, 10000000, -1); VIPS_ARG_STRING(class, "whitespace", 22, _("Whitespace"), _("Set of whitespace characters"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadCsv, whitespace), " "); VIPS_ARG_STRING(class, "separator", 23, _("Separator"), _("Set of separator characters"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadCsv, separator), ";,\t"); } static void vips_foreign_load_csv_init(VipsForeignLoadCsv *csv) { csv->lines = -1; csv->whitespace = g_strdup(" "); csv->separator = g_strdup(";,\t"); } typedef struct _VipsForeignLoadCsvFile { VipsForeignLoadCsv parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadCsvFile; typedef VipsForeignLoadCsvClass VipsForeignLoadCsvFileClass; G_DEFINE_TYPE(VipsForeignLoadCsvFile, vips_foreign_load_csv_file, vips_foreign_load_csv_get_type()); static VipsForeignFlags vips_foreign_load_csv_file_get_flags_filename(const char *filename) { return 0; } static int vips_foreign_load_csv_file_build(VipsObject *object) { VipsForeignLoadCsv *csv = (VipsForeignLoadCsv *) object; VipsForeignLoadCsvFile *file = (VipsForeignLoadCsvFile *) object; if (file->filename) if (!(csv->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_csv_file_parent_class) ->build(object); } static const char *vips_foreign_load_csv_suffs[] = { ".csv", NULL }; static void vips_foreign_load_csv_file_class_init(VipsForeignLoadCsvFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "csvload"; object_class->build = vips_foreign_load_csv_file_build; foreign_class->suffs = vips_foreign_load_csv_suffs; load_class->get_flags_filename = vips_foreign_load_csv_file_get_flags_filename; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadCsvFile, filename), NULL); } static void vips_foreign_load_csv_file_init(VipsForeignLoadCsvFile *file) { } typedef struct _VipsForeignLoadCsvSource { VipsForeignLoadCsv parent_object; VipsSource *source; } VipsForeignLoadCsvSource; typedef VipsForeignLoadCsvClass VipsForeignLoadCsvSourceClass; G_DEFINE_TYPE(VipsForeignLoadCsvSource, vips_foreign_load_csv_source, vips_foreign_load_csv_get_type()); static int vips_foreign_load_csv_source_build(VipsObject *object) { VipsForeignLoadCsv *csv = (VipsForeignLoadCsv *) object; VipsForeignLoadCsvSource *source = (VipsForeignLoadCsvSource *) object; if (source->source) { csv->source = source->source; g_object_ref(csv->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_csv_source_parent_class) ->build(object); } static gboolean vips_foreign_load_csv_source_is_a_source(VipsSource *source) { /* Detecting CSV files automatically is tricky. Define this method to * prevent a warning, but users will need to run the csv loader * explicitly. */ return FALSE; } static void vips_foreign_load_csv_source_class_init(VipsForeignLoadCsvFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "csvload_source"; object_class->build = vips_foreign_load_csv_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_csv_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadCsvSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_csv_source_init(VipsForeignLoadCsvSource *source) { } /** * vips_csvload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Load a CSV (comma-separated values) file. * * The output image is always 1 band (monochrome), * [enum@Vips.BandFormat.DOUBLE]. Use [method@Image.bandfold] to turn * RGBRGBRGB mono images into colour images. * * Items in lines can be either floating point numbers in the C locale, or * strings enclosed in double-quotes ("), or empty. * You can use a backslash (\) within the quotes to escape special characters, * such as quote marks. * * @skip sets the number of lines to skip at the start of the file. * Default zero. * * @lines sets the number of lines to read from the file. Default -1, * meaning read all lines to end of file. * * @whitespace sets the skippable whitespace characters. * Default *space*. * Whitespace characters are always run together. * * @separator sets the characters that separate fields. * Default ;,*tab*. Separators are never run together. * * Use @fail_on to set the type of error that will cause load to fail. By * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE]. * * ::: tip "Optional arguments" * * @skip: `gint`, skip this many lines at start of file * * @lines: `gint`, read this many lines from file * * @whitespace: `gchararray`, set of whitespace characters * * @separator: `gchararray`, set of separator characters * * @fail_on: [enum@FailOn], types of read error to fail on * * ::: seealso * [ctor@Image.new_from_file], [method@Image.bandfold]. * * Returns: 0 on success, -1 on error. */ int vips_csvload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("csvload", ap, filename, out); va_end(ap); return result; } /** * vips_csvload_source: * @source: source to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.csvload], but read from a source. * * ::: tip "Optional arguments" * * @skip: `gint`, skip this many lines at start of file * * @lines: `gint`, read this many lines from file * * @whitespace: `gchararray`, set of whitespace characters * * @separator: `gchararray`, set of separator characters * * @fail_on: [enum@FailOn], types of read error to fail on * * ::: seealso * [ctor@Image.csvload]. * * Returns: 0 on success, -1 on error. */ int vips_csvload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("csvload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/csvsave.c000066400000000000000000000230701516303661500202110ustar00rootroot00000000000000/* save to csv * * 2/12/11 * - wrap a class around the csv writer * 21/2/20 * - rewrite for the VipsTarget API */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pforeign.h" typedef struct _VipsForeignSaveCsv { VipsForeignSave parent_object; VipsTarget *target; const char *separator; } VipsForeignSaveCsv; typedef VipsForeignSaveClass VipsForeignSaveCsvClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveCsv, vips_foreign_save_csv, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_csv_dispose(GObject *gobject) { VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) gobject; VIPS_UNREF(csv->target); G_OBJECT_CLASS(vips_foreign_save_csv_parent_class)->dispose(gobject); } #define PRINT_INT(TYPE) \ { \ TYPE *pt = (TYPE *) p; \ \ for (x = 0; x < image->Xsize; x++) { \ if (x > 0) \ vips_target_writes(csv->target, csv->separator); \ vips_target_writef(csv->target, "%d", pt[x]); \ } \ } #define PRINT_FLOAT(TYPE) \ { \ TYPE *pt = (TYPE *) p; \ char buf[G_ASCII_DTOSTR_BUF_SIZE]; \ \ for (x = 0; x < image->Xsize; x++) { \ if (x > 0) \ vips_target_writes(csv->target, csv->separator); \ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, pt[x]); \ vips_target_writes(csv->target, buf); \ } \ } #define PRINT_COMPLEX(TYPE) \ { \ TYPE *pt = (TYPE *) p; \ char buf[G_ASCII_DTOSTR_BUF_SIZE]; \ \ for (x = 0; x < image->Xsize; x++) { \ if (x > 0) \ vips_target_writes(csv->target, csv->separator); \ VIPS_TARGET_PUTC(csv->target, '('); \ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, pt[0]); \ vips_target_writes(csv->target, buf); \ VIPS_TARGET_PUTC(csv->target, ','); \ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, pt[1]); \ vips_target_writes(csv->target, buf); \ VIPS_TARGET_PUTC(csv->target, ')'); \ pt += 2; \ } \ } static int vips_foreign_save_csv_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) a; VipsImage *image = region->im; int x, y; for (y = 0; y < area->height; y++) { VipsPel *p = VIPS_REGION_ADDR(region, 0, area->top + y); switch (image->BandFmt) { case VIPS_FORMAT_UCHAR: PRINT_INT(unsigned char); break; case VIPS_FORMAT_CHAR: PRINT_INT(char); break; case VIPS_FORMAT_USHORT: PRINT_INT(unsigned short); break; case VIPS_FORMAT_SHORT: PRINT_INT(short); break; case VIPS_FORMAT_UINT: PRINT_INT(unsigned int); break; case VIPS_FORMAT_INT: PRINT_INT(int); break; case VIPS_FORMAT_FLOAT: PRINT_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: PRINT_FLOAT(double); break; case VIPS_FORMAT_COMPLEX: PRINT_COMPLEX(float); break; case VIPS_FORMAT_DPCOMPLEX: PRINT_COMPLEX(double); break; default: g_assert_not_reached(); } if (vips_target_writes(csv->target, "\n")) return -1; } return 0; } static int vips_foreign_save_csv_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); if (VIPS_OBJECT_CLASS(vips_foreign_save_csv_parent_class)->build(object)) return -1; if (vips_check_mono(class->nickname, save->ready) || vips_check_uncoded(class->nickname, save->ready)) return -1; if (vips_sink_disc(save->ready, vips_foreign_save_csv_block, csv)) return -1; if (vips_target_end(csv->target)) return -1; return 0; } static const char *vips_foreign_save_csv_suffs[] = { ".csv", NULL }; static void vips_foreign_save_csv_class_init(VipsForeignSaveCsvClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_csv_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "csvsave_base"; object_class->description = _("save image to csv"); object_class->build = vips_foreign_save_csv_build; foreign_class->suffs = vips_foreign_save_csv_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_MONO; VIPS_ARG_STRING(class, "separator", 13, _("Separator"), _("Separator characters"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCsv, separator), "\t"); } static void vips_foreign_save_csv_init(VipsForeignSaveCsv *csv) { csv->separator = g_strdup("\t"); } typedef struct _VipsForeignSaveCsvFile { VipsForeignSaveCsv parent_object; char *filename; } VipsForeignSaveCsvFile; typedef VipsForeignSaveCsvClass VipsForeignSaveCsvFileClass; G_DEFINE_TYPE(VipsForeignSaveCsvFile, vips_foreign_save_csv_file, vips_foreign_save_csv_get_type()); static int vips_foreign_save_csv_file_build(VipsObject *object) { VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) object; VipsForeignSaveCsvFile *file = (VipsForeignSaveCsvFile *) object; if (file->filename && !(csv->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_csv_file_parent_class) ->build(object); } static void vips_foreign_save_csv_file_class_init(VipsForeignSaveCsvFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "csvsave"; object_class->build = vips_foreign_save_csv_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCsvFile, filename), NULL); } static void vips_foreign_save_csv_file_init(VipsForeignSaveCsvFile *file) { } typedef struct _VipsForeignSaveCsvTarget { VipsForeignSaveCsv parent_object; VipsTarget *target; } VipsForeignSaveCsvTarget; typedef VipsForeignSaveCsvClass VipsForeignSaveCsvTargetClass; G_DEFINE_TYPE(VipsForeignSaveCsvTarget, vips_foreign_save_csv_target, vips_foreign_save_csv_get_type()); static int vips_foreign_save_csv_target_build(VipsObject *object) { VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) object; VipsForeignSaveCsvTarget *target = (VipsForeignSaveCsvTarget *) object; if (target->target) { csv->target = target->target; g_object_ref(csv->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_csv_target_parent_class) ->build(object); } static void vips_foreign_save_csv_target_class_init(VipsForeignSaveCsvTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "csvsave_target"; object_class->build = vips_foreign_save_csv_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveCsvTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_csv_target_init(VipsForeignSaveCsvTarget *target) { } /** * vips_csvsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Writes the pixels in @in to the @filename as CSV (comma-separated values). * * The image is written * one line of text per scanline. Complex numbers are written as * "(real,imaginary)" and will need extra parsing I guess. Only the first band * is written. * * @separator gives the string to use to separate numbers in the output. * The default is "\\t" (tab). * * ::: tip "Optional arguments" * * @separator: `gchararray`, separator string * * ::: seealso * [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_csvsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("csvsave", ap, in, filename); va_end(ap); return result; } /** * vips_csvsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.csvsave], but save to a target. * * ::: tip "Optional arguments" * * @separator: `gchararray`, separator string * * ::: seealso * [method@Image.csvsave]. * * Returns: 0 on success, -1 on error. */ int vips_csvsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("csvsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/dbh.h000066400000000000000000000056241516303661500173060ustar00rootroot00000000000000/* * * (c) Copyright, 1986-1991 * Biodynamics Research Unit * Mayo Foundation * * dbh.h * * * database sub-definitions */ /* * * The previous-generation header for Analyze images. Although (c) Mayo * Foundation, it has been in the public domain for many years. * * Analyze images have a 348 byte header stored in a file with a .hdr suffix, * and a corresponding .img file containing just the pixel data. * */ struct header_key /* header_key */ { /* off + size*/ int sizeof_hdr; /* 0 + 4 */ char data_type[10]; /* 4 + 10 */ char db_name[18]; /* 14 + 18 */ int extents; /* 32 + 4 */ short int session_error; /* 36 + 2 */ char regular; /* 38 + 1 */ char hkey_un0; /* 39 + 1 */ }; /* total=40 */ struct image_dimension /* image_dimension */ { /* off + size*/ short int dim[8]; /* 0 + 16 */ char vox_units[4]; /* 16 + 4 */ char cal_units[8]; /* 20 + 4 */ short int unused1; /* 24 + 2 */ short int datatype; /* 30 + 2 */ short int bitpix; /* 32 + 2 */ short int dim_un0; /* 34 + 2 */ float pixdim[8]; /* 36 + 32 */ /* pixdim[] specifies the voxel dimensions: pixdim[1] - voxel width pixdim[2] - voxel height pixdim[3] - interslice distance ..etc */ float vox_offset; /* 68 + 4 */ float funused1; /* 72 + 4 */ float funused2; /* 76 + 4 */ float funused3; /* 80 + 4 */ float cal_max; /* 84 + 4 */ float cal_min; /* 88 + 4 */ int compressed; /* 92 + 4 */ int verified; /* 96 + 4 */ int glmax, glmin; /* 100 + 8 */ }; struct data_history /* data_history */ { /* off + size*/ char descrip[80]; /* 0 + 80 */ char aux_file[24]; /* 80 + 24 */ char orient; /* 104 + 1 */ char originator[10]; /* 105 + 10 */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax, omin; /* 184 + 8 */ int smax, smin; /* 192 + 8 */ }; /* total=200 */ struct dsr /* dsr */ { /* off + size*/ struct header_key hk; /* 0 + 40 */ struct image_dimension dime; /* 40 + 108 */ struct data_history hist; /* 148 + 200 */ }; /* total=348 */ /* Acceptable values for hdr.dime.datatype */ /* * commented this one out: we don't use it, and dirent.h defines this on some * platforms. * #define DT_UNKNOWN 0 */ #define DT_BINARY 1 #define DT_UNSIGNED_CHAR 2 #define DT_SIGNED_SHORT 4 #define DT_SIGNED_INT 8 #define DT_FLOAT 16 #define DT_COMPLEX 32 #define DT_DOUBLE 64 #define DT_RGB 128 libvips-8.18.2/libvips/foreign/dcrawload.c000066400000000000000000000462531516303661500205070ustar00rootroot00000000000000/* load RAW camera files with libraw * * 15/8/25 dvdkon * - handle image rotation */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #ifdef HAVE_LIBRAW #include #define VIPS_TYPE_FOREIGN_LOAD_DCRAW (vips_foreign_load_dcraw_get_type()) #define VIPS_FOREIGN_LOAD_DCRAW(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_LOAD_DCRAW, VipsForeignLoadDcRaw)) static const char *vips_foreign_dcraw_suffs[] = { ".3fr", ".ari", ".arw", ".cap", ".cin", ".cr2", ".cr3", ".crw", ".dcr", ".dng", ".erf", ".fff", ".iiq", ".k25", ".kdc", ".mdc", ".mos", ".mrw", ".nef", ".nrw", ".orf", ".ori", ".pef", ".pxn", ".raf", ".raw", ".rw2", ".rwl", ".sr2", ".srf", ".srw", ".x3f", NULL }; typedef struct _VipsForeignLoadDcRaw { VipsForeignLoad parent_object; int bitdepth; /* LibRaw processor. */ libraw_data_t *raw_processor; /* Internal Libraw processed image */ libraw_processed_image_t *processed; /* Load from this source (set by subclasses). */ VipsSource *source; } VipsForeignLoadDcRaw; typedef VipsForeignLoadClass VipsForeignLoadDcRawClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadDcRaw, vips_foreign_load_dcraw, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_dcraw_dispose(GObject *gobject) { VipsForeignLoadDcRaw *raw = (VipsForeignLoadDcRaw *) gobject; VIPS_FREEF(libraw_dcraw_clear_mem, raw->processed); VIPS_FREEF(libraw_close, raw->raw_processor); VIPS_UNREF(raw->source); G_OBJECT_CLASS(vips_foreign_load_dcraw_parent_class)->dispose(gobject); } static VipsForeignFlags vips_foreign_load_dcraw_get_flags(VipsForeignLoad *load) { return 0; } static void vips_foreign_load_dcraw_error(VipsForeignLoadDcRaw *raw, const char *message, int code) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(raw); vips_error(class->nickname, "%s: %s", message, libraw_strerror(code)); } static void vips_foreign_load_dcraw_close(VipsImage *image, libraw_processed_image_t *processed) { VIPS_FREEF(libraw_dcraw_clear_mem, processed); } static int vips_foreign_load_dcraw_set_metadata(VipsForeignLoadDcRaw *raw, VipsImage *image) { VIPS_SETSTR(image->filename, vips_connection_filename(VIPS_CONNECTION(raw->source))); /* Set custom metadata. */ vips_image_set_string(image, "raw-make", raw->raw_processor->idata.make); vips_image_set_string(image, "raw-model", raw->raw_processor->idata.model); #if LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 17) vips_image_set_string(image, "raw-software", raw->raw_processor->idata.software); #endif /*LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 17)*/ vips_image_set_double(image, "raw-iso", raw->raw_processor->other.iso_speed); vips_image_set_double(image, "raw-shutter", raw->raw_processor->other.shutter); vips_image_set_double(image, "raw-aperture", raw->raw_processor->other.aperture); vips_image_set_double(image, "raw-focal-length", raw->raw_processor->other.focal_len); /* See also: vips__get_iso8601() */ #if GLIB_CHECK_VERSION(2, 62, 0) GDateTime *dt = g_date_time_new_from_unix_utc(raw->raw_processor->other.timestamp); if (dt) { char *str = g_date_time_format_iso8601(dt); if (str) { vips_image_set_string(image, "raw-timestamp", str); g_free(str); } g_date_time_unref(dt); } #else /*!GLIB_CHECK_VERSION(2, 62, 0)*/ GTimeVal val = { raw->raw_processor->other.timestamp, 0 }; char *str = g_time_val_to_iso8601(&val); if (str) { vips_image_set_string(image, "raw-timestamp", str); g_free(str); } #endif /*GLIB_CHECK_VERSION(2, 62, 0)*/ #if LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 17) if (raw->raw_processor->idata.xmpdata) vips_image_set_blob_copy(image, VIPS_META_XMP_NAME, raw->raw_processor->idata.xmpdata, raw->raw_processor->idata.xmplen); vips_image_set_string(image, "raw-lens", raw->raw_processor->lens.Lens); #endif /*LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 17)*/ if (raw->raw_processor->color.profile) vips_image_set_blob_copy(image, VIPS_META_ICC_NAME, raw->raw_processor->color.profile, raw->raw_processor->color.profile_length); int orientation; switch (raw->raw_processor->sizes.flip) { case 0: orientation = 1; break; case 3: orientation = 3; break; case 5: orientation = 8; break; case 6: orientation = 6; break; default: /* dcrawload allows other values, but they are not well documented. */ g_warning("dcrawload: unimplemented dcraw flip value\n"); orientation = 0; break; } vips_image_set_int(image, VIPS_META_ORIENTATION, orientation); #if LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 21) /* Search the available thumbnails for the largest that's smaller than * the main image and has a known type. */ libraw_image_sizes_t *sizes = &raw->raw_processor->sizes; libraw_thumbnail_list_t *thumbs_list = &raw->raw_processor->thumbs_list; int thumb_index; thumb_index = -1; for (int i = 0; i < thumbs_list->thumbcount; i++) { libraw_thumbnail_item_t *best = thumb_index == -1 ? NULL : &thumbs_list->thumblist[thumb_index]; libraw_thumbnail_item_t *this = &thumbs_list->thumblist[i]; // only support JPEG thumbnails for now if (this->tformat != LIBRAW_INTERNAL_THUMBNAIL_JPEG) continue; // useless thumbnails the same size as the main image are very // common if (this->twidth >= sizes->iwidth && this->theight >= sizes->iheight) continue; // must be 8-bit, must match the main image in bands int bpp = this->tmisc & ((1 << 5) - 1); int bands = this->tmisc >> 5; if (bpp != 8 || bands != raw->raw_processor->idata.colors) continue; // size must be sane (under 1mb). if (this->tlength > 1024 * 1024) continue; if (!best || this->twidth > best->twidth || this->theight > best->theight) thumb_index = i; } if (thumb_index != -1) { int result; result = libraw_unpack_thumb_ex(raw->raw_processor, thumb_index); if (result != LIBRAW_SUCCESS) { vips_foreign_load_dcraw_error(raw, _("unable to unpack thumbnail"), result); return -1; } vips_image_set_blob_copy(image, "raw-thumbnail-data", raw->raw_processor->thumbnail.thumb, raw->raw_processor->thumbnail.tlength); } #endif /*LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 21)*/ return 0; } static int vips_foreign_load_dcraw_header(VipsForeignLoad *load) { VipsForeignLoadDcRaw *raw = (VipsForeignLoadDcRaw *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(raw); int result; raw->raw_processor = libraw_init(0); if (!raw->raw_processor) { vips_error(class->nickname, "%s", _("unable to initialize libraw")); return -1; } if (raw->bitdepth != 8 && raw->bitdepth != 16) { vips_error(class->nickname, "%s", _("bad bitdepth")); return -1; } raw->raw_processor->params.output_bps = raw->bitdepth; /* Apply camera white balance. */ raw->raw_processor->params.use_camera_wb = 1; /* Don't autorotate, we set EXIF rotation later instead. If we enable * autorotate, then the image size reported during libraw_open_buffer() * may not match the decoded size. */ raw->raw_processor->params.user_flip = 0; /* We can use the libraw file interface for filename sources. This * interface can often read more metadata, since it can open secondary * files. */ if (vips_source_is_file(raw->source)) { const char *filename = vips_connection_filename(VIPS_CONNECTION(raw->source)); result = libraw_open_file(raw->raw_processor, filename); } else { size_t length; const void *data; if (!(data = vips_source_map(raw->source, &length))) return -1; result = libraw_open_buffer(raw->raw_processor, data, length); } if (result != LIBRAW_SUCCESS) { vips_foreign_load_dcraw_error(raw, _("unable to read"), result); return -1; } vips_image_init_fields(load->out, raw->raw_processor->sizes.iwidth, raw->raw_processor->sizes.iheight, raw->raw_processor->idata.colors, raw->bitdepth > 8 ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_ERROR, 1.0, 1.0); load->out->Type = vips_image_guess_interpretation(load->out); if (vips_foreign_load_dcraw_set_metadata(raw, load->out)) return -1; return 0; } static int vips_foreign_load_dcraw_load(VipsForeignLoad *load) { VipsForeignLoadDcRaw *raw = (VipsForeignLoadDcRaw *) load; int result; g_assert(raw->raw_processor); result = libraw_unpack(raw->raw_processor); if (result != LIBRAW_SUCCESS) { vips_foreign_load_dcraw_error(raw, _("unable to unpack"), result); return -1; } /* Process the image (demosaicing, white balance, etc.). */ result = libraw_dcraw_process(raw->raw_processor); if (result != LIBRAW_SUCCESS) { vips_foreign_load_dcraw_error(raw, _("unable to process"), result); return -1; } if (!(raw->processed = libraw_dcraw_make_mem_image(raw->raw_processor, &result))) { vips_foreign_load_dcraw_error(raw, _("unable to build image"), result); return -1; } VipsImage *image; if (!(image = vips_image_new_from_memory( raw->processed->data, raw->processed->data_size, raw->processed->width, raw->processed->height, raw->processed->colors, raw->bitdepth > 8 ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR))) return -1; image->Type = vips_image_guess_interpretation(image); if (vips_foreign_load_dcraw_set_metadata(raw, image)) { VIPS_UNREF(image); return -1; } /* We must only free the memory when this image closes. */ g_signal_connect(image, "close", G_CALLBACK(vips_foreign_load_dcraw_close), raw->processed); raw->processed = NULL; if (vips_image_write(image, load->real)) { VIPS_UNREF(image); return -1; } VIPS_UNREF(image); return 0; } static void vips_foreign_load_dcraw_class_init(VipsForeignLoadDcRawClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_dcraw_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dcrawload_base"; object_class->description = _("load RAW camera files"); operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* We need to be ahead of JPEG and TIFF, since many cameras use those * formats as containers. We are slow to open, but we only test the * filename suffix, so that's fine. */ foreign_class->priority = 100; load_class->get_flags = vips_foreign_load_dcraw_get_flags; load_class->header = vips_foreign_load_dcraw_header; load_class->load = vips_foreign_load_dcraw_load; VIPS_ARG_INT(class, "bitdepth", 12, _("Bit depth"), _("Number of bits per pixel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadDcRaw, bitdepth), 8, 16, 8); } static void vips_foreign_load_dcraw_init(VipsForeignLoadDcRaw *raw) { raw->bitdepth = 8; } typedef struct _VipsForeignLoadDcRawSource { VipsForeignLoadDcRaw parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadDcRawSource; typedef VipsForeignLoadDcRawClass VipsForeignLoadDcRawSourceClass; G_DEFINE_TYPE(VipsForeignLoadDcRawSource, vips_foreign_load_dcraw_source, vips_foreign_load_dcraw_get_type()); static int vips_foreign_load_dcraw_source_build(VipsObject *object) { VipsForeignLoadDcRaw *dcraw = (VipsForeignLoadDcRaw *) object; VipsForeignLoadDcRawSource *source = (VipsForeignLoadDcRawSource *) object; if (source->source) { dcraw->source = source->source; g_object_ref(dcraw->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_dcraw_source_parent_class) ->build(object); } static gboolean vips_foreign_load_dcrawload_source_is_a_source(VipsSource *source) { return FALSE; } static void vips_foreign_load_dcraw_source_class_init( VipsForeignLoadDcRawSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dcrawload_source"; object_class->build = vips_foreign_load_dcraw_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_dcrawload_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadDcRawSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_dcraw_source_init(VipsForeignLoadDcRawSource *source) { } typedef struct _VipsForeignLoadDcRawFile { VipsForeignLoadDcRaw parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadDcRawFile; typedef VipsForeignLoadDcRawClass VipsForeignLoadDcRawFileClass; G_DEFINE_TYPE(VipsForeignLoadDcRawFile, vips_foreign_load_dcraw_file, vips_foreign_load_dcraw_get_type()); static int vips_foreign_load_dcraw_file_build(VipsObject *object) { VipsForeignLoadDcRaw *raw = VIPS_FOREIGN_LOAD_DCRAW(object); VipsForeignLoadDcRawFile *file = (VipsForeignLoadDcRawFile *) object; if (file->filename && !(raw->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_dcraw_file_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_dcraw_file_get_flags_filename(const char *filename) { return 0; } static void vips_foreign_load_dcraw_file_class_init(VipsForeignLoadDcRawFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dcrawload"; object_class->build = vips_foreign_load_dcraw_file_build; foreign_class->suffs = vips_foreign_dcraw_suffs; load_class->get_flags_filename = vips_foreign_load_dcraw_file_get_flags_filename; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadDcRawFile, filename), NULL); } static void vips_foreign_load_dcraw_file_init(VipsForeignLoadDcRawFile *file) { } typedef struct _VipsForeignLoadRawBuffer { VipsForeignLoadDcRaw parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadDcRawBuffer; typedef VipsForeignLoadDcRawClass VipsForeignLoadDcRawBufferClass; G_DEFINE_TYPE(VipsForeignLoadDcRawBuffer, vips_foreign_load_dcraw_buffer, vips_foreign_load_dcraw_get_type()); static int vips_foreign_load_dcraw_buffer_build(VipsObject *object) { VipsForeignLoadDcRaw *raw = (VipsForeignLoadDcRaw *) object; VipsForeignLoadDcRawBuffer *buffer = (VipsForeignLoadDcRawBuffer *) object; if (buffer->blob && !(raw->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_dcraw_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_dcrawload_buffer_is_a_buffer(const void *buf, size_t len) { return FALSE; } static void vips_foreign_load_dcraw_buffer_class_init( VipsForeignLoadDcRawBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dcrawload_buffer"; object_class->build = vips_foreign_load_dcraw_buffer_build; load_class->is_a_buffer = vips_foreign_load_dcrawload_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadDcRawBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_dcraw_buffer_init(VipsForeignLoadDcRawBuffer *buffer) { } #endif /*HAVE_LIBRAW*/ /** * vips_dcrawload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Read a RAW camera file using LibRaw. * * This loader supports the most RAW formats, including * ARW, CR2, CR3, CRW, DNG, NEF, NRW, ORF, PEF, RAF, RAW, RW2, SRW, X3F, and * many others. * * The loader applies demosaicing and basic processing to produce an RGB or * grayscale image suitable for further processing. It attaches XMP and ICC * metadata, if present. * * ::: tip "Optional arguments" * * @bitdepth: `gint`, load as 8 or 16 bit data * * Returns: 0 on success, -1 on error. */ int vips_dcrawload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("dcrawload", ap, filename, out); va_end(ap); return result; } /** * vips_dcrawload_source: * @source: source to load from * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.dcrawload], but read from a source. * * ::: tip "Optional arguments" * * @bitdepth: `gint`, load as 8 or 16 bit data * * ::: seealso * [ctor@Image.dcrawload]. * * Returns: 0 on success, -1 on error. */ int vips_dcrawload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("dcrawload_source", ap, source, out); va_end(ap); return result; } /** * vips_dcrawload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.dcrawload], but read from a buffer. * * ::: tip "Optional arguments" * * @bitdepth: `gint`, load as 8 or 16 bit data * * ::: seealso * [ctor@Image.dcrawload]. * * Returns: 0 on success, -1 on error. */ int vips_dcrawload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("dcrawload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } libvips-8.18.2/libvips/foreign/dzsave.c000066400000000000000000002242401516303661500200350ustar00rootroot00000000000000/* save to deep zoom format * * 21/3/12 * - from the tiff pyramid writer * 5/7/12 (thanks Alexander Koshman) * - make tiles down to 1x1 pixels * - oop make right-hand edge tiles * - improve overlap handling * 7/7/12 * - threaded write * 6/8/12 (thanks to Benjamin Gilbert for pointing out the errors) * - shrink down to a 1x1 pixel tile, even for very long and thin images * - round image size up on shrink * - write a .dzi file with the pyramid params * - default tile size and overlap now matches the openslide writer * 7/8/12 (thanks to Benjamin Gilbert again for more testing) * - reorganise the directory structure * - rename to basename and tile_size * - deprecate tile_width/_height and dirname * 1/10/12 * - did not write low pyramid levels for images with an odd number of * scan lines (thanks Martin) * 2/10/12 * - remove filename options from format string in .dzi (thanks Martin) * 3/10/12 * - add zoomify and google maps output * 10/10/12 * - add @background option * 1/11/12 * - add @depth option * 21/1/13 * - add @centre option * 26/2/13 * - fix another corner case, thanks Martin * 29/5/13 * - add --angle option * 19/6/13 * - faster --centre logic, thanks Kacey * 18/4/14 * - use libgsf for output so we can write to .zip etc. as well as the * filesystem * 8/5/14 * - set Type on strips so we can convert for save correctly, thanks * philipgiuliani * 25/6/14 * - stop on zip write >4gb, thanks bgilbert * - save metadata, see https://github.com/libvips/libvips/issues/137 * 18/8/14 * - use g_ date funcs, helps Windows * 14/2/15 * - use vips_region_shrink() * 22/2/15 * - use a better temp dir name for fs dz output * 8/8/15 * - allow zip > 4gb if we have a recent libgsf * 9/9/15 * - better overlap handling, thanks robclouth * 24/11/15 * - don't write almost blank tiles in google mode * 25/11/15 * - always strip tile metadata * 16/12/15 * - fix overlap handling again, thanks erdmann * 8/6/16 Felix Bünemann * - add @compression option * 5/9/16 * - more overlap changes to help gmaps mode * 8/9/16 Felix Bünemann * - move vips-properties out of subdir for gm and zoomify layouts * 15/10/16 * - add dzsave_buffer * 11/11/16 Felix Bünemann * - better >4gb detection for zip output on older libgsfs * 18/8/17 * - shut down the output earlier to flush zip output * 24/11/17 * - output overlap-only tiles on edges for better deepzoom spec * compliance * 6/1/18 * - add scan-properties.xml for szi output * - write all associated images * 19/12/18 * - add @skip_blanks * 21/10/19 * - add @no_strip * 9/11/19 * - add IIIF layout * 24/4/20 [IllyaMoskvin] * - better IIIF tile naming * 15/10/21 martimpassos * - add IIIF3 layout * 21/12/21 whalehub * - remove trailing comma from IIIFv3 folder names * 29/3/22 * - always write a properties file * - add .szi as a registered suffix * 9/5/22 * - add dzsave_target * 8/9/23 * - add direct mode * 24/11/25 * - add gainmap support */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* This is difficult to test, there are so many options. It's failed in the past in these cases. These have levels with strips which exactly align with image edges, or which have orphan scanlines which need adding for the shrink. 1. $ header test.v test.v: 14016x16448 uchar, 3 bands, srgb, openin VipsImage (0x11e7060) $ time vips dzsave test.v x --overlap 0 Not all levels written. 2. $ header ~/Desktop/leicaimage.scn /home/john/Desktop/leicaimage.scn: 4225x7905 uchar, 4 bands, rgb Not all levels written. 3. $ header ~/leicatest1.scn /home/john/leicatest1.scn: 11585x8449 uchar, 4 bands, rgb Not all levels written. various combinations of odd and even tile-size and overlap need testing too. Overlap handling For deepzoom, tile-size == 254 and overlap == 1 means that edge tiles are 255 x 255 (though less at the bottom right) and non-edge tiles are 256 x 256. Tiles are positioned across the image in tile-size steps. This means (confusingly) that two adjoining tiles will have two pixels in common. This has caused bugs in the past. */ /* #define DEBUG_VERBOSE #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_LIBARCHIVE typedef struct _VipsForeignSaveDz VipsForeignSaveDz; typedef struct _Level Level; /* A level in the pyramid. */ struct _Level { VipsForeignSaveDz *dz; /* The size of this image in pixels. @image can be a bit bigger since it * gets padded up to an even size. */ int width; int height; /* Number of tiles across and down in width/height. Zoomify needs this * to calculate the directory to put each tile in. */ int tiles_across; int tiles_down; /* The rect we save. It can be a lot smaller than @image, and * not at (0, 0), if we're skipping blank tiles. */ VipsRect save_area; /* The image for this level. Might be bigger than width/height since it's * always rounded up to even. */ VipsImage *image; /* The top of this strip of tiles. */ int y; /* The next line we write to in this strip. */ int write_y; VipsRegion *strip; /* The current strip of pixels */ VipsRegion *copy; /* Pixels we copy to the next strip */ int sub; /* Subsample factor for this level */ int n; /* Level number ... 0 for smallest */ Level *below; /* Tiles go to here */ Level *above; /* Tiles come from here */ }; struct _VipsForeignSaveDz { VipsForeignSave parent_object; /* The target we are writing to. This is set by our subclasses. */ VipsTarget *target; /* Alternatively, the filename, for filesystem output. */ char *filename; char *suffix; int overlap; int tile_size; VipsForeignDzLayout layout; VipsForeignDzDepth depth; gboolean centre; gboolean properties; VipsAngle angle; VipsForeignDzContainer container; int compression; VipsRegionShrink region_shrink; int skip_blanks; gboolean no_strip; char *id; int Q; /* In direct save mode, we write regions of pixels to the output and * avoid creating a pipeline for each tile. This must be disabled if * --suffix has been used. */ gboolean direct; /* Tile and overlap geometry. The members above are the parameters we * accept, this next set are the derived values which are actually * used in pyramid generation. * * Tiles have a base tile_size. Imagine a square placed at the top left. * This is the size of that square. * * Tiles have a margin. The square from tile_size is expanded outward * up/down/left/right by this amount. Parts going off the image are * clipped. * * Each time we write a new tile, we step the position by tile_step * pixels. * * We need all three of tile_size, tile_margin and tile_step since * deepzoom and google maps have different meanings for overlap and we * want to be able to support both models. * * For deepzoom: * * tile_margin = overlap * tile_step = tile_size * * For google maps: * * tile_margin = 0 * tile_step = tile_size - overlap */ int tile_margin; int tile_step; Level *level; /* x2 shrink pyr level */ /* Count zoomify tiles we write. */ int tile_count; // (atomic) /* Where we write ... can be the filesystem, or a zip. */ VipsArchive *archive; /* The name to save as, eg. deepzoom tiles go into ${imagename}_files. * No suffix, no path at the start. */ char *imagename; /* The directory we write the output to. */ char *dirname; /* The name of the directory containing the levels ... eg. perhaps * $(imagename)_files, etc. */ char *root_name; /* @suffix, but without any options. So @suffix == ".jpg[Q=90]" * becomes ".jpg". */ char *file_suffix; /* save->background turned into a pixel that matches the image we are * saving .. used to test for blank tiles. */ VipsPel *ink; /* The gainmap, if this image has one. Workers shrink and crop this during * tile save. */ VipsImage *gainmap; /* Scale main image cods by this to get gainmap cods. */ double gainmap_hscale; double gainmap_vscale; }; typedef VipsForeignSaveClass VipsForeignSaveDzClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveDz, vips_foreign_save_dz, VIPS_TYPE_FOREIGN_SAVE); /* ZIP and SZI are both written as zip files. */ static gboolean iszip(VipsForeignDzContainer container) { switch (container) { case VIPS_FOREIGN_DZ_CONTAINER_ZIP: case VIPS_FOREIGN_DZ_CONTAINER_SZI: return TRUE; default: return FALSE; } } static int write_image(VipsForeignSaveDz *dz, VipsImage *image, const char *filename, const char *format) { VipsForeignSave *save = VIPS_FOREIGN_SAVE(dz); VipsImage *t; /* We need to block progress signalling on individual image write, so * we need a copy of the tile in case it's shared (eg. associated * images). */ if (vips_copy(image, &t, NULL)) return -1; vips_image_set_int(t, "hide-progress", 1); void *buf; size_t len; if (vips_image_write_to_buffer(t, format, &buf, &len, "keep", save->keep, NULL)) { VIPS_UNREF(t); return -1; } VIPS_UNREF(t); if (vips__archive_mkfile(dz->archive, filename, buf, len)) { g_free(buf); return -1; } g_free(buf); return 0; } /* Free a pyramid. */ static void level_free(Level *level) { VIPS_FREEF(g_object_unref, level->strip); VIPS_FREEF(g_object_unref, level->copy); VIPS_FREEF(g_object_unref, level->image); VIPS_FREEF(level_free, level->below); } static void vips_foreign_save_dz_dispose(GObject *gobject) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) gobject; VIPS_FREEF(vips__archive_free, dz->archive); VIPS_UNREF(dz->target); VIPS_UNREF(dz->gainmap); VIPS_FREEF(level_free, dz->level); VIPS_FREE(dz->imagename); VIPS_FREE(dz->dirname); VIPS_FREE(dz->root_name); VIPS_FREE(dz->file_suffix); G_OBJECT_CLASS(vips_foreign_save_dz_parent_class)->dispose(gobject); } /* Build a pyramid. * * width/height is the size of this level, real_* the subsection of the level * which is real pixels (as opposed to background). left/top of save_area * can be >0 if we are centring. */ static Level * pyramid_build(VipsForeignSaveDz *dz, Level *above, int width, int height, VipsRect *save_area) { VipsForeignSave *save = VIPS_FOREIGN_SAVE(dz); Level *level; VipsRect strip; int limit; if (!(level = VIPS_NEW(dz, Level))) return NULL; level->dz = dz; level->width = width; level->height = height; /* We need to output all possible tiles, even if they give no new * pixels. */ level->tiles_across = VIPS_ROUND_UP(width, dz->tile_step) / dz->tile_step; level->tiles_down = VIPS_ROUND_UP(height, dz->tile_step) / dz->tile_step; level->save_area = *save_area; level->image = NULL; level->strip = NULL; level->copy = NULL; if (!above) /* Top of pyramid. */ level->sub = 1; else level->sub = above->sub * 2; level->below = NULL; level->above = above; /* We round the image size up to an even number to make x2 shrink * easy. */ level->image = vips_image_new(); if (vips_image_pipelinev(level->image, VIPS_DEMAND_STYLE_ANY, save->ready, NULL)) { level_free(level); return NULL; } level->image->Xsize = width + (width & 1); level->image->Ysize = height + (height & 1); level->strip = vips_region_new(level->image); level->copy = vips_region_new(level->image); /* The regions will get used in the bg thread callback, so make sure * we don't own them. */ vips__region_no_ownership(level->strip); vips__region_no_ownership(level->copy); /* Build a line of tiles here. * * Expand the strip if necessary to make sure we have an even * number of lines. * * This is just the height of the first row of tiles, so only add 1* * tile_margin. */ level->y = 0; level->write_y = 0; strip.left = 0; strip.top = 0; strip.width = level->image->Xsize; strip.height = dz->tile_size + dz->tile_margin; if ((strip.height & 1) == 1) strip.height += 1; if (vips_region_buffer(level->strip, &strip)) { level_free(level); return NULL; } switch (dz->depth) { case VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL: limit = 1; break; case VIPS_FOREIGN_DZ_DEPTH_ONETILE: limit = dz->tile_size; break; case VIPS_FOREIGN_DZ_DEPTH_ONE: limit = VIPS_MAX(width, height); break; default: g_assert_not_reached(); /* Stop compiler warnings. */ limit = 1; } if (width > limit || height > limit) { /* Round up, so eg. a 5 pixel wide image becomes 3 a level * down. */ VipsRect half; half.left = (save_area->left + 1) / 2; half.top = (save_area->top + 1) / 2; half.width = (save_area->width + 1) / 2; half.height = (save_area->height + 1) / 2; if (!(level->below = pyramid_build(dz, level, (width + 1) / 2, (height + 1) / 2, &half))) { level_free(level); return NULL; } level->n = level->below->n + 1; } else level->n = 0; #ifdef DEBUG printf("pyramid_build:\n"); printf("\tn = %d\n", level->n); printf("\twidth = %d, height = %d\n", width, height); printf("\tXsize = %d, Ysize = %d\n", level->image->Xsize, level->image->Ysize); printf("\ttiles_across = %d, tiles_down = %d\n", level->tiles_across, level->tiles_down); printf("\tsave_area.left = %d, save_area.top = %d\n", save_area->left, save_area->top); printf("\tsave_area.width = %d, save_area.height = %d\n", save_area->width, save_area->height); #endif /*DEBUG*/ return level; } static int write_dzi(VipsForeignSaveDz *dz) { VipsDbuf dbuf = { 0 }; char filename[VIPS_PATH_MAX]; char format[VIPS_PATH_MAX]; char *p; void *buf; size_t len; g_snprintf(filename, VIPS_PATH_MAX, "%s.dzi", dz->imagename); g_snprintf(format, VIPS_PATH_MAX, "%s", dz->suffix + 1); if ((p = (char *) vips__find_rightmost_brackets(format))) *p = '\0'; vips_dbuf_writef(&dbuf, "\n"); vips_dbuf_writef(&dbuf, "overlap); vips_dbuf_writef(&dbuf, " TileSize=\"%d\"\n", dz->tile_size); vips_dbuf_writef(&dbuf, " >\n"); vips_dbuf_writef(&dbuf, " level->height); vips_dbuf_writef(&dbuf, " Width=\"%d\"\n", dz->level->width); vips_dbuf_writef(&dbuf, " />\n"); vips_dbuf_writef(&dbuf, "\n"); if ((buf = vips_dbuf_steal(&dbuf, &len))) { if (vips__archive_mkfile(dz->archive, filename, buf, len)) { g_free(buf); return -1; } g_free(buf); } return 0; } static int write_properties(VipsForeignSaveDz *dz) { VipsDbuf dbuf = { 0 }; char *filename; void *buf; size_t len; filename = g_build_filename(dz->root_name, "ImageProperties.xml", NULL); vips_dbuf_writef(&dbuf, "\n", dz->level->width, dz->level->height, g_atomic_int_get(&dz->tile_count), dz->tile_size); if ((buf = vips_dbuf_steal(&dbuf, &len))) { if (vips__archive_mkfile(dz->archive, filename, buf, len)) { g_free(buf); g_free(filename); return -1; } g_free(buf); } g_free(filename); return 0; } static int write_blank(VipsForeignSaveDz *dz) { VipsForeignSave *save = (VipsForeignSave *) dz; VipsImage *x, *t; int n; VipsArea *ones; double *d; double *bg; int i; char *filename; /* Number of bands we will end up making. We need to set this in * vips_black() to make sure we set Type correctly, otherwise we can * try saving a B_W image as PNG, with disastrous results. */ bg = (double *) vips_area_get_data(VIPS_AREA(save->background), NULL, &n, NULL, NULL); if (vips_black(&x, dz->tile_size, dz->tile_size, "bands", n, NULL)) return -1; ones = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); d = (double *) vips_area_get_data(ones, NULL, NULL, NULL, NULL); for (i = 0; i < n; i++) d[i] = 1.0; if (vips_linear(x, &t, d, bg, n, NULL)) { vips_area_unref(ones); g_object_unref(x); return -1; } vips_area_unref(ones); g_object_unref(x); x = t; filename = g_build_filename(dz->root_name, "blank.png", NULL); if (write_image(dz, x, filename, ".png")) { g_free(filename); g_object_unref(x); return -1; } g_free(filename); g_object_unref(x); return 0; } /* Write IIIF/IIF3 JSON metadata. */ static int write_json(VipsForeignSaveDz *dz) { VipsDbuf dbuf = { 0 }; /* dz->file_suffix has a leading "." character. */ const char *suffix = dz->file_suffix[0] == '.' ? dz->file_suffix + 1 : dz->file_suffix; char *filename; void *buf; size_t len; int i; filename = g_build_filename(dz->root_name, "info.json", NULL); if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF3) vips_dbuf_writef(&dbuf, "{\n" " \"@context\": " "\"http://iiif.io/api/image/3/context.json\",\n" " \"id\": \"%s/%s\",\n" " \"type\": \"ImageService3\",\n" " \"profile\": \"level0\",\n" " \"protocol\": \"http://iiif.io/api/image\",\n", dz->id ? dz->id : "https://example.com/iiif", dz->imagename); else vips_dbuf_writef(&dbuf, "{\n" " \"@context\": " "\"http://iiif.io/api/image/2/context.json\",\n" " \"@id\": \"%s/%s\",\n" " \"profile\": [\n" " \"http://iiif.io/api/image/2/level0.json\",\n" " {\n" " \"formats\": [\n" " \"%s\"\n" " ],\n" " \"qualities\": [\n" " \"default\"\n" " ]\n" " }\n" " ],\n" " \"protocol\": \"http://iiif.io/api/image\",\n", dz->id ? dz->id : "https://example.com/iiif", dz->imagename, suffix); /* "sizes" is needed for the full/ set of untiled images, which we * don't yet support. Leave this commented out for now. vips_dbuf_writef(&dbuf, " \"sizes\": [\n"); for (i = 0; i < dz->level->n + 5; i++) { vips_dbuf_writef(&dbuf, " {\n" " \"width\": %d,\n" " \"height\": \"full\"\n" " }", 1 << (i + 4)); if (i != dz->level->n - 4) vips_dbuf_writef(&dbuf, ","); vips_dbuf_writef(&dbuf, "\n"); } vips_dbuf_writef(&dbuf, " ],\n"); */ /* The set of pyramid levels we have written. */ vips_dbuf_writef(&dbuf, " \"tiles\": [\n" " {\n" " \"scaleFactors\": [\n"); for (i = 0; i <= dz->level->n; i++) { vips_dbuf_writef(&dbuf, " %d", 1 << i); if (i != dz->level->n) vips_dbuf_writef(&dbuf, ","); vips_dbuf_writef(&dbuf, "\n"); } vips_dbuf_writef(&dbuf, " ],\n" " \"width\": %d\n" " }\n" " ],\n", dz->tile_size); vips_dbuf_writef(&dbuf, " \"width\": %d,\n" " \"height\": %d\n", dz->level->width, dz->level->height); vips_dbuf_writef(&dbuf, "}\n"); if ((buf = vips_dbuf_steal(&dbuf, &len))) { if (vips__archive_mkfile(dz->archive, filename, buf, len)) { g_free(filename); g_free(buf); return -1; } g_free(buf); } g_free(filename); return 0; } static int write_vips_meta(VipsForeignSaveDz *dz) { VipsForeignSave *save = (VipsForeignSave *) dz; char *filename; char *dump; /* For deepzoom the props must go inside the ${name}_files subdir, for * gm and zoomify it can sit in the main folder. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_DZ) filename = g_build_filename(dz->root_name, "vips-properties.xml", NULL); else filename = g_strdup("vips-properties.xml"); if (filename == NULL) return -1; if (!(dump = vips__xml_properties(save->ready))) { g_free(filename); return -1; } if (vips__archive_mkfile(dz->archive, filename, dump, strlen(dump))) { g_free(filename); g_free(dump); return -1; } g_free(filename); g_free(dump); return 0; } static void build_scan_property(VipsDbuf *dbuf, VipsImage *image, const char *vips_name, const char *szi_name) { char *str; GValue value = G_VALUE_INIT; GValue save_value = G_VALUE_INIT; GType type; if (!vips_image_get_typeof(image, vips_name)) return; if (vips_image_get(image, vips_name, &value)) return; type = G_VALUE_TYPE(&value); if (!g_value_type_transformable(type, VIPS_TYPE_SAVE_STRING)) { g_value_unset(&value); return; } g_value_init(&save_value, VIPS_TYPE_SAVE_STRING); if (!g_value_transform(&value, &save_value)) { g_value_unset(&value); return; } g_value_unset(&value); if (!(str = g_utf8_make_valid( vips_value_get_save_string(&save_value), -1))) { g_value_unset(&save_value); return; } vips_dbuf_writef(dbuf, " \n"); vips_dbuf_writef(dbuf, " "); vips_dbuf_write_amp(dbuf, szi_name); vips_dbuf_writef(dbuf, "\n"); vips_dbuf_writef(dbuf, " ", g_type_name(type)); vips_dbuf_write_amp(dbuf, str); vips_dbuf_writef(dbuf, "\n"); vips_dbuf_writef(dbuf, " \n"); g_free(str); g_value_unset(&save_value); } static char *scan_property_names[][2] = { { "openslide.vendor", "Vendor" }, { "openslide.objective-power", "ObjectiveMagnification" }, { "openslide.mpp-x", "MicronsPerPixelX" }, { "openslide.mpp-y", "MicronsPerPixelY" }, { "width", "ImageWidth" }, { "height", "ImageHeight" } }; /* Make the xml we write to scan-properties.xml in szi write. * Free with g_free(). */ static char * build_scan_properties(VipsImage *image, size_t *len) { VipsDbuf dbuf = { 0 }; char *date; int i; date = vips__get_iso8601(); vips_dbuf_writef(&dbuf, "\n"); vips_dbuf_writef(&dbuf, "\n", date); vips_dbuf_writef(&dbuf, " \n"); g_free(date); for (i = 0; i < VIPS_NUMBER(scan_property_names); i++) build_scan_property(&dbuf, image, scan_property_names[i][0], scan_property_names[i][1]); vips_dbuf_writef(&dbuf, " \n"); vips_dbuf_writef(&dbuf, "\n"); return (char *) vips_dbuf_steal(&dbuf, len); } static int write_scan_properties(VipsForeignSaveDz *dz) { VipsForeignSave *save = (VipsForeignSave *) dz; char *dump; size_t len; if (!(dump = build_scan_properties(save->ready, &len))) return -1; if (vips__archive_mkfile(dz->archive, "scan-properties.xml", dump, len)) { g_free(dump); return -1; } g_free(dump); return 0; } static void * write_associated_images(VipsImage *image, const char *field, GValue *value, void *a) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) a; if (vips_isprefix("openslide.associated.", field) && vips_image_get_typeof(image, field) == VIPS_TYPE_IMAGE) { VipsImage *associated; const char *p; const char *q; char *out; char buf[VIPS_PATH_MAX]; p = field + strlen("openslide.associated."); /* Make sure there are no '/' in the filename. */ if ((q = strrchr(p, '/'))) p = q + 1; if (vips_image_get_image(image, field, &associated)) return image; if (vips__archive_mkdir(dz->archive, "associated_images")) return image; g_snprintf(buf, VIPS_PATH_MAX, "%s.jpg", p); out = g_build_filename("associated_images", buf, NULL); if (write_image(dz, associated, out, ".jpg")) { g_free(out); g_object_unref(associated); return image; } g_free(out); g_object_unref(associated); } return NULL; } static int write_associated(VipsForeignSaveDz *dz) { VipsForeignSave *save = (VipsForeignSave *) dz; if (vips_image_map(save->ready, write_associated_images, dz)) return -1; return 0; } /* Our state during a threaded write of a strip using the image API. */ typedef struct _Strip { Level *level; VipsImage *image; /* Allocate the next tile on this boundary. */ int x; } ImageStrip; static void image_strip_free(ImageStrip *strip) { g_object_unref(strip->image); } static void image_strip_init(ImageStrip *strip, Level *level) { VipsForeignSaveDz *dz = level->dz; VipsRect line, image; strip->level = level; strip->image = NULL; strip->x = 0; /* The image we wrap around our pixel buffer must be the full width, * including any rounding up, since we must have contiguous pixels. * We can trim the height down though. * * When we loop across the strip writing tiles we have to look out for * the smaller width. */ image.left = 0; image.top = 0; image.width = level->image->Xsize; image.height = level->height; line.left = 0; line.top = level->y; line.width = image.width; line.height = dz->tile_size; vips_rect_marginadjust(&line, dz->tile_margin); vips_rect_intersectrect(&image, &line, &line); if (!(strip->image = vips_image_new_from_memory( VIPS_REGION_ADDR(level->strip, 0, line.top), VIPS_IMAGE_SIZEOF_LINE(level->image) * line.height, line.width, line.height, level->image->Bands, level->image->BandFmt))) { image_strip_free(strip); return; } /* The strip needs to inherit the level's metadata. */ if (vips__image_meta_copy(strip->image, level->image)) { image_strip_free(strip); return; } /* Type needs to be set so we know how to convert for save correctly. */ strip->image->Type = level->image->Type; } static int image_strip_allocate(VipsThreadState *state, void *a, gboolean *stop) { ImageStrip *strip = (ImageStrip *) a; Level *level = strip->level; VipsForeignSaveDz *dz = level->dz; VipsRect image; #ifdef DEBUG_VERBOSE printf("image_strip_allocate\n"); #endif /*DEBUG_VERBOSE*/ /* We can't test for allocated area empty, since it might just have * bits of the left-hand overlap in and no new pixels. Safest to count * tiles across. */ if (strip->x / dz->tile_step >= level->tiles_across) { *stop = TRUE; #ifdef DEBUG_VERBOSE printf("image_strip_allocate: done\n"); #endif /*DEBUG_VERBOSE*/ return 0; } image.left = 0; image.top = 0; image.width = level->width; image.height = level->height; /* Position this tile. */ state->pos.left = strip->x; state->pos.top = level->y; state->pos.width = dz->tile_size; state->pos.height = dz->tile_size; vips_rect_marginadjust(&state->pos, dz->tile_margin); vips_rect_intersectrect(&image, &state->pos, &state->pos); state->x = strip->x; state->y = level->y; strip->x += dz->tile_step; return 0; } /* Make a name for a tile in the current layout. */ static char * tile_name(Level *level, int x, int y) { VipsForeignSaveDz *dz = level->dz; VipsForeignSave *save = (VipsForeignSave *) dz; char *out; char *dirname; char name[VIPS_PATH_MAX]; char subdir[VIPS_PATH_MAX]; Level *p; int n; switch (dz->layout) { case VIPS_FOREIGN_DZ_LAYOUT_DZ: g_snprintf(subdir, VIPS_PATH_MAX, "%d", level->n); g_snprintf(name, VIPS_PATH_MAX, "%d_%d%s", x, y, dz->file_suffix); break; case VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY: /* We need to work out the tile number so we can calculate the * directory to put this tile in. * * Tiles are numbered from 0 for the most-zoomed-out tile. */ n = 0; /* Count all tiles in levels below this one. */ for (p = level->below; p; p = p->below) n += p->tiles_across * p->tiles_down; /* And count tiles so far in this level. */ n += y * level->tiles_across + x; g_snprintf(subdir, VIPS_PATH_MAX, "TileGroup%d", n / 256); g_snprintf(name, VIPS_PATH_MAX, "%d-%d-%d%s", level->n, x, y, dz->file_suffix); /* Used at the end in ImageProperties.xml */ g_atomic_int_inc(&dz->tile_count); break; case VIPS_FOREIGN_DZ_LAYOUT_GOOGLE: g_snprintf(subdir, VIPS_PATH_MAX, "%d" G_DIR_SEPARATOR_S "%d", level->n, y); g_snprintf(name, VIPS_PATH_MAX, "%d%s", x, dz->file_suffix); break; case VIPS_FOREIGN_DZ_LAYOUT_IIIF: case VIPS_FOREIGN_DZ_LAYOUT_IIIF3: { /* Tiles are addressed in full resolution coordinates, so * scale up by level->sub and dz->tile_size * * We always clip against the full-sized image, not the scaled * up level. * * This will break for overlap != 0, but hopefully no one will * ever use that. */ int left = x * dz->tile_size * level->sub; int top = y * dz->tile_size * level->sub; int width = VIPS_MIN(dz->tile_size * level->sub, save->ready->Xsize - left); int height = VIPS_MIN(dz->tile_size * level->sub, save->ready->Ysize - top); gboolean is_region_full = left == 0 && top == 0 && width == save->ready->Xsize && height == save->ready->Ysize; /* Rotation is always 0. */ int rotation = 0; if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF3) { int xsize = VIPS_MIN(dz->tile_size, level->width - x * dz->tile_size); int ysize = VIPS_MIN(dz->tile_size, level->height - y * dz->tile_size); if (is_region_full) g_snprintf(subdir, VIPS_PATH_MAX, "full" G_DIR_SEPARATOR_S "%d,%d" G_DIR_SEPARATOR_S "%d", xsize, ysize, rotation); else g_snprintf(subdir, VIPS_PATH_MAX, "%d,%d,%d,%d" G_DIR_SEPARATOR_S "%d,%d" G_DIR_SEPARATOR_S "%d", left, top, width, height, xsize, ysize, rotation); } else { /* IIIF2 "size" is just real tile width, I think. */ int size = VIPS_MIN(dz->tile_size, level->width - x * dz->tile_size); if (is_region_full) g_snprintf(subdir, VIPS_PATH_MAX, "full" G_DIR_SEPARATOR_S "%d," G_DIR_SEPARATOR_S "%d", size, rotation); else g_snprintf(subdir, VIPS_PATH_MAX, "%d,%d,%d,%d" G_DIR_SEPARATOR_S "%d," G_DIR_SEPARATOR_S "%d", left, top, width, height, size, rotation); } g_snprintf(name, VIPS_PATH_MAX, "default%s", dz->file_suffix); } break; default: g_assert_not_reached(); } dirname = g_build_filename(dz->root_name, subdir, NULL); if (vips__archive_mkdir(dz->archive, dirname)) { g_free(dirname); return NULL; } out = g_build_filename(dirname, name, NULL); g_free(dirname); #ifdef DEBUG_VERBOSE printf("tile_name: writing to %s\n", out); #endif /*DEBUG_VERBOSE*/ return out; } /* Test for region nearly equal to background colour. In google maps mode, we * skip blank background tiles. * * Don't use exactly equality since compression artefacts or noise can upset * this. */ static gboolean region_tile_equal(VipsRegion *region, VipsRect *rect, int threshold, VipsPel *restrict ink) { int bytes = VIPS_REGION_SIZEOF_PEL(region); int x, y, b; for (y = 0; y < rect->height; y++) { VipsPel *restrict p = VIPS_REGION_ADDR(region, rect->left, rect->top + y); for (x = 0; x < rect->width; x++) { for (b = 0; b < bytes; b++) if (abs(p[b] - ink[b]) > threshold) return FALSE; p += bytes; } } return TRUE; } static gboolean image_tile_equal(VipsImage *image, int threshold, VipsPel *restrict ink) { VipsRect rect; VipsRegion *region; region = vips_region_new(image); /* We know @image is part of a memory buffer, so this will be quick. */ rect.left = 0; rect.top = 0; rect.width = image->Xsize; rect.height = image->Ysize; if (vips_region_prepare(region, &rect)) { g_object_unref(region); return FALSE; } if (!region_tile_equal(region, &rect, threshold, ink)) { g_object_unref(region); return FALSE; } g_object_unref(region); return TRUE; } static int image_strip_work(VipsThreadState *state, void *a) { ImageStrip *strip = (ImageStrip *) a; Level *level = strip->level; VipsForeignSaveDz *dz = level->dz; VipsForeignSave *save = (VipsForeignSave *) dz; int tile_x = state->x / dz->tile_step; int tile_y = state->y / dz->tile_step; VipsRect tile; VipsImage *x; char *out; #ifdef DEBUG_VERBOSE printf("image_strip_work\n"); #endif /*DEBUG_VERBOSE*/ /* killed is checked by sink_disc, but that's only once per strip, and * they can be huge. Check per output tile as well. */ if (vips_image_iskilled(save->in)) return -1; /* We may be outside the real pixels. */ tile.left = state->x; tile.top = state->y; tile.width = dz->tile_size; tile.height = dz->tile_size; if (!vips_rect_overlapsrect(&tile, &level->save_area)) { #ifdef DEBUG_VERBOSE printf("image_strip_work: skipping tile %d x %d\n", tile_x, tile_y); #endif /*DEBUG_VERBOSE*/ return 0; } g_assert(vips_object_sanity(VIPS_OBJECT(strip->image))); /* Extract relative to the strip top-left corner. */ if (vips_extract_area(strip->image, &x, state->pos.left, 0, state->pos.width, state->pos.height, NULL)) return -1; if (dz->skip_blanks >= 0 && image_tile_equal(x, dz->skip_blanks, dz->ink)) { #ifdef DEBUG_VERBOSE printf("image_strip_work: skipping blank tile %d x %d\n", tile_x, tile_y); #endif /*DEBUG_VERBOSE*/ VIPS_UNREF(x); return 0; } /* If there's a gainmap, generate and attach that too. */ if (dz->gainmap) { VipsImage *a, *b; if (vips_resize(dz->gainmap, &a, 1.0 / level->sub, "vscale", 1.0 / level->sub, "kernel", VIPS_KERNEL_LINEAR, NULL)) { VIPS_UNREF(x); return -1; } int left = dz->gainmap_hscale * tile_x * dz->tile_size; int top = dz->gainmap_vscale * tile_y * dz->tile_size; int width = VIPS_MAX(1, dz->gainmap_hscale * state->pos.width); int height = VIPS_MAX(1, dz->gainmap_vscale * state->pos.height); if (vips_extract_area(a, &b, left, top, width, height, NULL)) { VIPS_UNREF(a); VIPS_UNREF(x); return -1; } VIPS_UNREF(a); vips_image_set_image(x, "gainmap", b); VIPS_UNREF(b); } if (!(out = tile_name(level, tile_x, tile_y))) { VIPS_UNREF(x); return -1; } /* Don't do a threaded write -- this pipeline is too small to have useful * concurrency, and we are already writing tiles in parallel. */ vips_image_set_int(x, VIPS_META_CONCURRENCY, 1); if (write_image(dz, x, out, dz->suffix)) { VIPS_FREE(out); VIPS_UNREF(x); return -1; } VIPS_FREE(out); VIPS_UNREF(x); #ifdef DEBUG_VERBOSE printf("image_strip_work: success\n"); #endif /*DEBUG_VERBOSE*/ return 0; } /* Our state during a direct write of a strip. */ typedef struct _DirectStrip { Level *level; /* Private image for this strip write. */ VipsImage *image; /* Allocate the next tile on this boundary. */ int x; } DirectStrip; static int direct_strip_init(DirectStrip *strip, Level *level) { strip->level = level; strip->x = 0; /* We need a private image so we can modify the metadata. */ if (vips_copy(level->image, &strip->image, NULL)) return -1; /* We don't want threadpool_run to minimise on completion -- we need to * keep the cache on the pipeline before us. */ vips_image_set_int(strip->image, "vips-no-minimise", 1); return 0; } static void direct_strip_free(DirectStrip *strip) { VIPS_UNREF(strip->image); } static int direct_strip_allocate(VipsThreadState *state, void *a, gboolean *stop) { DirectStrip *strip = (DirectStrip *) a; Level *level = strip->level; VipsForeignSaveDz *dz = level->dz; VipsRect image; #ifdef DEBUG_VERBOSE printf("direct_strip_allocate\n"); #endif /*DEBUG_VERBOSE*/ /* We can't test for allocated area empty, since it might just have * bits of the left-hand overlap in and no new pixels. Safest to count * tiles across. */ if (strip->x / dz->tile_step >= level->tiles_across) { *stop = TRUE; #ifdef DEBUG_VERBOSE printf("direct_strip_allocate: done\n"); #endif /*DEBUG_VERBOSE*/ return 0; } /* Position this tile. */ image.left = 0; image.top = 0; image.width = level->width; image.height = level->height; state->pos.left = strip->x; state->pos.top = level->y; state->pos.width = dz->tile_size; state->pos.height = dz->tile_size; vips_rect_marginadjust(&state->pos, dz->tile_margin); vips_rect_intersectrect(&image, &state->pos, &state->pos); state->x = strip->x; state->y = level->y; strip->x += dz->tile_step; return 0; } static int direct_image_write(VipsForeignSaveDz *dz, VipsRegion *region, VipsRect *rect, const char *filename) { VipsForeignSave *save = VIPS_FOREIGN_SAVE(dz); VipsTarget *target; if (!(target = vips_target_new_to_memory())) return -1; if (vips__jpeg_region_write_target(region, rect, target, dz->Q, NULL, FALSE, FALSE, save->keep, FALSE, FALSE, FALSE, 0, 0, 0)) { g_object_unref(target); return -1; } VipsBlob *blob; const void *buf; size_t len; g_object_get(target, "blob", &blob, NULL); buf = vips_blob_get(blob, &len); if (vips__archive_mkfile(dz->archive, filename, (void *) buf, len)) { vips_area_unref(VIPS_AREA(blob)); g_object_unref(target); return -1; } vips_area_unref(VIPS_AREA(blob)); g_object_unref(target); return 0; } static int direct_strip_work(VipsThreadState *state, void *a) { DirectStrip *strip = (DirectStrip *) a; Level *level = strip->level; VipsForeignSaveDz *dz = level->dz; VipsForeignSave *save = (VipsForeignSave *) dz; int tile_x = state->x / dz->tile_step; int tile_y = state->y / dz->tile_step; VipsRect tile; /* killed is checked by sink_disc, but that's only once per strip, and * they can be huge. Check per output tile as well. */ if (vips_image_iskilled(save->in)) return -1; /* We may be outside the real pixels. */ tile.left = state->x; tile.top = state->y; tile.width = dz->tile_size; tile.height = dz->tile_size; if (!vips_rect_overlapsrect(&tile, &level->save_area)) { #ifdef DEBUG_VERBOSE printf("direct_strip_work: level %d, skipping tile %d x %d\n", level->n, tile_x, tile_y); #endif /*DEBUG_VERBOSE*/ return 0; } if (dz->skip_blanks >= 0 && region_tile_equal(level->strip, &state->pos, dz->skip_blanks, dz->ink)) { #ifdef DEBUG_VERBOSE printf("direct_strip_work: level %d, skipping blank tile %d x %d\n", level->n, tile_x, tile_y); #endif /*DEBUG_VERBOSE*/ return 0; } char *name; if (!(name = tile_name(level, tile_x, tile_y))) return -1; if (direct_image_write(dz, level->strip, &state->pos, name)) { g_free(name); return -1; } g_free(name); return 0; } /* Write a line of tiles with a threadpool. */ static int strip_save(Level *level) { #ifdef DEBUG_VERBOSE printf("strip_save: n = %d, y = %d\n", level->n, level->y); #endif /*DEBUG_VERBOSE*/ if (level->dz->direct) { DirectStrip strip; if (direct_strip_init(&strip, level)) return -1; if (vips_threadpool_run(strip.image, vips_thread_state_new, direct_strip_allocate, direct_strip_work, NULL, &strip)) { direct_strip_free(&strip); return -1; } direct_strip_free(&strip); } else { ImageStrip strip; image_strip_init(&strip, level); vips_image_set_int(strip.image, "vips-no-minimise", 1); if (vips_threadpool_run(strip.image, vips_thread_state_new, image_strip_allocate, image_strip_work, NULL, &strip)) { image_strip_free(&strip); return -1; } image_strip_free(&strip); } #ifdef DEBUG_VERBOSE printf("strip_save: success\n"); #endif /*DEBUG_VERBOSE*/ return 0; } /* A strip has filled, but the rightmost column and the bottom-most row may * not have been if we've rounded the size up. * * Fill them, if necessary, by copying the previous row/column. */ static void level_generate_extras(Level *level) { VipsRegion *strip = level->strip; /* We only work for full-width strips. */ g_assert(strip->valid.width == level->image->Xsize); if (level->width < level->image->Xsize) { int ps = VIPS_IMAGE_SIZEOF_PEL(strip->im); int b, y; /* Need to add a right-most column. */ for (y = 0; y < strip->valid.height; y++) { VipsPel *p = VIPS_REGION_ADDR(strip, level->width - 1, strip->valid.top + y); VipsPel *q = p + ps; for (b = 0; b < ps; b++) q[b] = p[b]; } } if (level->height < level->image->Ysize) { VipsRect last; /* The last two lines of the image. */ last.left = 0; last.top = level->image->Ysize - 2; last.width = level->image->Xsize; last.height = 2; /* Do we have them both? Fill the last with the next-to-last. */ vips_rect_intersectrect(&last, &strip->valid, &last); if (last.height == 2) { last.height = 1; vips_region_copy(strip, strip, &last, 0, last.top + 1); } } } static int strip_arrived(Level *level); /* Shrink what pixels we can from this strip into the level below. If the * strip below fills, recurse. */ static int strip_shrink(Level *level) { Level *below = level->below; VipsRegion *from = level->strip; VipsRegion *to = below->strip; VipsForeignSaveDz *dz = level->dz; VipsRegionShrink region_shrink = dz->region_shrink; VipsRect target; VipsRect source; #ifdef DEBUG_VERBOSE printf("strip_shrink: %d lines in level %d to level %d\n", from->valid.height, level->n, below->n); #endif /*DEBUG_VERBOSE*/ /* We may have an extra column of pixels on the right or * bottom that need filling: generate them. */ level_generate_extras(level); /* Our pixels might cross a strip boundary in the level below, so we * have to write repeatedly until we run out of pixels. */ for (;;) { /* The pixels the level below needs. */ target.left = 0; target.top = below->write_y; target.width = below->image->Xsize; target.height = to->valid.height; vips_rect_intersectrect(&target, &to->valid, &target); /* Those pixels need this area of this level. */ source.left = target.left * 2; source.top = target.top * 2; source.width = target.width * 2; source.height = target.height * 2; /* Of which we have these available. */ vips_rect_intersectrect(&source, &from->valid, &source); /* So these are the pixels in the level below we can provide. */ target.left = source.left / 2; target.top = source.top / 2; target.width = source.width / 2; target.height = source.height / 2; /* None? All done. */ if (vips_rect_isempty(&target)) break; (void) vips_region_shrink_method(from, to, &target, region_shrink); below->write_y += target.height; /* If we've filled the strip below, let it know. * We can either fill the region, if it's somewhere half-way * down the image, or, if it's at the bottom, get to the last * real line of pixels. */ if (below->write_y == VIPS_RECT_BOTTOM(&to->valid) || below->write_y == below->height) { if (strip_arrived(below)) return -1; } } return 0; } /* A new strip has arrived! The strip has enough pixels in to write a line of * tiles. * * - write a line of tiles * - shrink what we can to the level below * - move our strip down by the tile step * - copy the overlap with the previous strip */ static int strip_arrived(Level *level) { VipsForeignSaveDz *dz = level->dz; VipsRect new_strip; VipsRect overlap; VipsRect image_area; #ifdef DEBUG_VERBOSE printf("strip_arrived: level %d, strip at %d, height %d\n", level->n, level->y, level->strip->valid.height); #endif /*DEBUG_VERBOSE*/ if (strip_save(level)) return -1; if (level->below && strip_shrink(level)) return -1; /* Position our strip down the image. * * Expand the strip if necessary to make sure we have an even * number of lines. */ level->y += dz->tile_step; new_strip.left = 0; new_strip.top = level->y - dz->tile_margin; new_strip.width = level->image->Xsize; new_strip.height = dz->tile_size + 2 * dz->tile_margin; image_area.left = 0; image_area.top = 0; image_area.width = level->image->Xsize; image_area.height = level->image->Ysize; vips_rect_intersectrect(&new_strip, &image_area, &new_strip); if ((new_strip.height & 1) == 1) new_strip.height += 1; /* We may exactly hit the bottom of the real image (ie. before borders * have been possibly expanded by 1 pixel). In this case, we'll not * be able to do the expansion in level_generate_extras(), since the * region won't be large enough, and we'll not get another chance * since this is the bottom. * * Add another scanline if this has happened. */ if (VIPS_RECT_BOTTOM(&new_strip) == level->height) new_strip.height = level->image->Ysize - new_strip.top; /* What pixels that we will need do we already have? Save them in * overlap. */ vips_rect_intersectrect(&new_strip, &level->strip->valid, &overlap); if (!vips_rect_isempty(&overlap)) { if (vips_region_buffer(level->copy, &overlap)) return -1; vips_region_copy(level->strip, level->copy, &overlap, overlap.left, overlap.top); } if (!vips_rect_isempty(&new_strip)) { if (vips_region_buffer(level->strip, &new_strip)) return -1; /* And copy back again. */ if (!vips_rect_isempty(&overlap)) vips_region_copy(level->copy, level->strip, &overlap, overlap.left, overlap.top); } return 0; } /* The image has been completely written. Flush any strips which might have * overlaps in. */ static int strip_flush(Level *level) { if (level->y < level->height) if (strip_save(level)) return -1; if (level->below) if (strip_flush(level->below)) return -1; return 0; } /* Another strip of image pixels from vips_sink_disc(). Write into the top * pyramid level. */ static int pyramid_strip(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) a; Level *level = dz->level; #ifdef DEBUG_VERBOSE printf("pyramid_strip: strip at %d, height %d\n", area->top, area->height); #endif /*DEBUG_VERBOSE*/ for (;;) { VipsRect *to = &level->strip->valid; VipsRect target; /* The bit of strip that needs filling. */ target.left = 0; target.top = level->write_y; target.width = level->image->Xsize; target.height = to->height; vips_rect_intersectrect(&target, to, &target); /* Clip against what we have available. */ vips_rect_intersectrect(&target, area, &target); /* Have we written all the pixels we were given? We are done. */ if (vips_rect_isempty(&target)) break; /* And copy those pixels in. * * FIXME: If the strip fits inside the region we've just * received, we could skip the copy. Will this happen very * often? Unclear. */ vips_region_copy(region, level->strip, &target, target.left, target.top); level->write_y += target.height; /* We can either fill the strip, if it's somewhere half-way * down the image, or, if it's at the bottom, get to the last * real line of pixels. */ if (level->write_y == VIPS_RECT_BOTTOM(to) || level->write_y == level->height) { if (strip_arrived(level)) return -1; } } /* If we've reached the bottom of the image, we won't get called again. * * However, there may be some unwritten pixels in the pyramid still! * Suppose a level is exactly a multiple of tile_step in height. * When we finished that last strip, we will have copied the last few * lines of overlap over into the top of the next row. Deepzoom says we * must flush these half-written strips to the output. */ if (level->write_y == level->height) { #ifdef DEBUG printf("pyramid_strip: flushing ..\n"); #endif /*DEBUG*/ if (strip_flush(level)) return -1; } return 0; } #define UC VIPS_FORMAT_UCHAR /* We force all types to uchar for save. */ static VipsBandFormat bandfmt_dzsave[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static int vips_foreign_save_dz_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveDz *dz = (VipsForeignSaveDz *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(dz); VipsRect save_area; char *p; // direct mode won't work if the suffix has been set if (!vips_object_argument_isset(object, "suffix")) dz->direct = TRUE; /* We default to stripping all metadata as most people * don't want metadata on every tile. Setting "keep" * or the deprecated "no_strip" turns this off. */ if (!vips_object_argument_isset(object, "keep") && !dz->no_strip) save->keep = VIPS_FOREIGN_KEEP_NONE; /* Google, zoomify and iiif default to zero overlap, ".jpg". */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY || dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE || dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF || dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF3) { if (!vips_object_argument_isset(object, "overlap")) dz->overlap = 0; if (!vips_object_argument_isset(object, "suffix")) VIPS_SETSTR(dz->suffix, ".jpg"); } /* Google and zoomify default to 256 pixel tiles. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY || dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE) { if (!vips_object_argument_isset(object, "tile_size")) dz->tile_size = 256; } /* Some iiif writers default to 256, some to 512. We pick 512. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF || dz->layout == VIPS_FOREIGN_DZ_LAYOUT_IIIF3) { if (!vips_object_argument_isset(object, "tile_size")) dz->tile_size = 512; } /* skip_blanks defaults to 5 in google mode. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE && !vips_object_argument_isset(object, "skip_blanks")) dz->skip_blanks = 5; /* Our tile layout. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_DZ) { dz->tile_margin = dz->overlap; dz->tile_step = dz->tile_size; } else { dz->tile_margin = 0; dz->tile_step = dz->tile_size - dz->overlap; } if (dz->tile_step <= 0) { vips_error("dzsave", "%s", _("overlap too large")); return -1; } /* DeepZoom stops at 1x1 pixels, others when the image fits within a * tile. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_DZ) { if (!vips_object_argument_isset(object, "depth")) dz->depth = VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL; } else if (!vips_object_argument_isset(object, "depth")) dz->depth = VIPS_FOREIGN_DZ_DEPTH_ONETILE; /* We don't support onepixel pyramids in gmaps mode. It doesn't make a lot * of sense anyway, since gmaps tiles are never clipped, so you can't have * a 1x1 pixel tile. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE && dz->depth == VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL) dz->depth = VIPS_FOREIGN_DZ_DEPTH_ONETILE; if (VIPS_OBJECT_CLASS(vips_foreign_save_dz_parent_class)->build(object)) return -1; /* Optional rotate. */ { VipsImage *z; if (vips_rot(save->ready, &z, dz->angle, NULL)) return -1; VIPS_UNREF(save->ready); save->ready = z; } /* If we're saving to direct JPEG we need to convert to 8-bit * RGB | mono | cmyk. */ if (dz->direct) { VipsImage *z; if (vips__foreign_convert_saveable(save->ready, &z, VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_CMYK, bandfmt_dzsave, VIPS_FOREIGN_CODING_NONE, save->background)) return -1; VIPS_UNREF(save->ready); save->ready = z; } /* The real (not background) pixels we have. save->ready can be a lot * bigger. left/top are moved if we centre. */ save_area.left = 0; save_area.top = 0; save_area.width = save->ready->Xsize; save_area.height = save->ready->Ysize; /* Load the gainmap, if any. */ if ((dz->gainmap = vips_image_get_gainmap(save->ready))) { dz->gainmap_hscale = (double) dz->gainmap->Xsize / save->ready->Xsize; dz->gainmap_vscale = (double) dz->gainmap->Ysize / save->ready->Ysize; /* Don't check for blanks, too annoying with a gainmap as well. */ dz->skip_blanks = -1; /* Direct mode does not support gainmaps. */ dz->direct = FALSE; } /* We use ink to check for blank tiles. */ if (dz->skip_blanks >= 0) { if (!(dz->ink = vips__vector_to_ink(class->nickname, save->ready, VIPS_AREA(save->background)->data, NULL, VIPS_AREA(save->background)->n))) return -1; } /* In google mode, we expand the image so we have complete tiles in every * level. We shrink to fit in one tile, then expand those dimensions out * again. */ if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_GOOGLE) { VipsImage *z; Level *level; Level *p; int width; int height; if (!(level = pyramid_build(dz, NULL, save->ready->Xsize, save->ready->Ysize, &save_area))) return -1; // find the deepest (smallest) level for (p = level; p->below; p = p->below) ; // round image size up so we have complete tiles in the base level width = VIPS_ROUND_UP(p->width, dz->tile_step) + dz->overlap; height = VIPS_ROUND_UP(p->height, dz->tile_step) + dz->overlap; // and scale up by 2^depth ... we'll have complete tiles in every // level width *= 1 << level->n; height *= 1 << level->n; level_free(level); #ifdef DEBUG printf("vips_foreign_save_dz_build: " "google mode outputs a %d x %d pixel image\n", width, height); #endif /*DEBUG*/ if (dz->centre) { #ifdef DEBUG printf("vips_foreign_save_dz_build: centring\n"); #endif /*DEBUG*/ save_area.left = (width - save->ready->Xsize) / 2; save_area.top = (height - save->ready->Ysize) / 2; } if (vips_embed(save->ready, &z, save_area.left, save_area.top, width, height, "background", save->background, NULL)) return -1; VIPS_UNREF(save->ready); save->ready = z; if (dz->gainmap) { if (vips_embed(dz->gainmap, &z, save_area.left * dz->gainmap_hscale, save_area.top * dz->gainmap_vscale, width * dz->gainmap_hscale, height * dz->gainmap_vscale, "background", save->background, NULL)) return -1; VIPS_UNREF(dz->gainmap); dz->gainmap = z; } } /* Force gainmap decode -- we don't want to delay this until first tile * write. */ if (dz->gainmap && vips_image_wio_input(dz->gainmap)) return -1; #ifdef DEBUG printf("vips_foreign_save_dz_build: tile_size == %d\n", dz->tile_size); printf("vips_foreign_save_dz_build: overlap == %d\n", dz->overlap); printf("vips_foreign_save_dz_build: tile_margin == %d\n", dz->tile_margin); printf("vips_foreign_save_dz_build: tile_step == %d\n", dz->tile_step); #endif /*DEBUG*/ /* Init imagename and dirname from the associated filesystem names, if * we can. */ { const char *filename = dz->filename ? dz->filename : vips_connection_filename(VIPS_CONNECTION(dz->target)); if (!vips_object_argument_isset(object, "imagename") && !vips_object_argument_isset(object, "basename")) { if (filename) { dz->imagename = g_path_get_basename(filename); /* Remove any [options] we may have picked up from the * filename. */ if ((p = (char *) vips__find_rightmost_brackets(dz->imagename))) *p = '\0'; } else dz->imagename = g_strdup("untitled"); } if (!vips_object_argument_isset(object, "dirname")) { if (filename) dz->dirname = g_path_get_dirname(filename); else dz->dirname = g_strdup("."); } } /* If we're writing thing.zip or thing.szi, default to zip * container. */ if ((p = strrchr(dz->imagename, '.'))) { if (!vips_object_argument_isset(object, "container")) { if (g_ascii_strcasecmp(p + 1, "zip") == 0) dz->container = VIPS_FOREIGN_DZ_CONTAINER_ZIP; if (g_ascii_strcasecmp(p + 1, "szi") == 0) dz->container = VIPS_FOREIGN_DZ_CONTAINER_SZI; } /* Remove any legal suffix. We don't remove all suffixes * since we might be writing to a dirname with a dot in. */ if (g_ascii_strcasecmp(p + 1, "zip") == 0 || g_ascii_strcasecmp(p + 1, "szi") == 0 || g_ascii_strcasecmp(p + 1, "dz") == 0) *p = '\0'; } /* Build the skeleton of the image pyramid. */ if (!(dz->level = pyramid_build(dz, NULL, save->ready->Xsize, save->ready->Ysize, &save_area))) return -1; if (dz->layout == VIPS_FOREIGN_DZ_LAYOUT_DZ) dz->root_name = g_strdup_printf("%s_files", dz->imagename); else dz->root_name = g_strdup(dz->imagename); /* Drop any [options] from @suffix. */ dz->file_suffix = g_strdup(dz->suffix); if ((p = (char *) vips__find_rightmost_brackets(dz->file_suffix))) *p = '\0'; /* Make the zip archive we write the tiles into. */ if (iszip(dz->container)) { /* We can have dzsave("x.zip", container="fs"), ie. zip output * from write to file. Make a target if we need one. */ if (!dz->target) { if (!(dz->target = vips_target_new_to_file(dz->filename))) return -1; } // SZI needs an enclosing folder named after the image, according to // the spec char *path = dz->container == VIPS_FOREIGN_DZ_CONTAINER_SZI ? dz->imagename : ""; if (!(dz->archive = vips__archive_new_to_target(dz->target, path, dz->compression))) return -1; } else { if (!(dz->archive = vips__archive_new_to_dir(dz->dirname))) return -1; } if (vips_sink_disc(save->ready, pyramid_strip, dz)) return -1; switch (dz->layout) { case VIPS_FOREIGN_DZ_LAYOUT_DZ: if (write_dzi(dz)) return -1; break; case VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY: if (write_properties(dz)) return -1; break; case VIPS_FOREIGN_DZ_LAYOUT_GOOGLE: if (write_blank(dz)) return -1; break; case VIPS_FOREIGN_DZ_LAYOUT_IIIF: case VIPS_FOREIGN_DZ_LAYOUT_IIIF3: if (write_json(dz)) return -1; break; default: g_assert_not_reached(); } if (write_vips_meta(dz)) return -1; if (dz->container == VIPS_FOREIGN_DZ_CONTAINER_SZI && write_scan_properties(dz)) return -1; if (dz->container == VIPS_FOREIGN_DZ_CONTAINER_SZI && write_associated(dz)) return -1; /* Shut down the output to flush everything. */ VIPS_FREEF(vips__archive_free, dz->archive); return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat bandfmt_dz[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, F, D, D }; static const char *dz_suffs[] = { ".dz", ".szi", NULL }; static void vips_foreign_save_dz_class_init(VipsForeignSaveDzClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_dz_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dzsave_base"; object_class->description = _("save image to deep zoom format"); object_class->build = vips_foreign_save_dz_build; foreign_class->suffs = dz_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->format_table = bandfmt_dz; save_class->coding |= VIPS_FOREIGN_CODING_LABQ; VIPS_ARG_STRING(class, "imagename", 2, _("Image name"), _("Image name"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, imagename), NULL); VIPS_ARG_ENUM(class, "layout", 8, _("Layout"), _("Directory layout"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, layout), VIPS_TYPE_FOREIGN_DZ_LAYOUT, VIPS_FOREIGN_DZ_LAYOUT_DZ); VIPS_ARG_STRING(class, "suffix", 9, _("Suffix"), _("Filename suffix for tiles"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, suffix), ".jpeg"); VIPS_ARG_INT(class, "overlap", 10, _("Overlap"), _("Tile overlap in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, overlap), 0, 8192, 1); VIPS_ARG_INT(class, "tile_size", 11, _("Tile size"), _("Tile size in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, tile_size), 1, 8192, 254); VIPS_ARG_ENUM(class, "depth", 13, _("Depth"), _("Pyramid depth"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, depth), VIPS_TYPE_FOREIGN_DZ_DEPTH, VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL); VIPS_ARG_BOOL(class, "centre", 13, _("Center"), _("Center image in tile"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, centre), FALSE); VIPS_ARG_ENUM(class, "angle", 14, _("Angle"), _("Rotate image during save"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, angle), VIPS_TYPE_ANGLE, VIPS_ANGLE_D0); VIPS_ARG_ENUM(class, "container", 15, _("Container"), _("Pyramid container type"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, container), VIPS_TYPE_FOREIGN_DZ_CONTAINER, VIPS_FOREIGN_DZ_CONTAINER_FS); VIPS_ARG_INT(class, "compression", 17, _("Compression"), _("ZIP deflate compression level"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, compression), -1, 9, 0); VIPS_ARG_ENUM(class, "region_shrink", 18, _("Region shrink"), _("Method to shrink regions"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, region_shrink), VIPS_TYPE_REGION_SHRINK, VIPS_REGION_SHRINK_MEAN); VIPS_ARG_INT(class, "skip_blanks", 19, _("Skip blanks"), _("Skip tiles which are nearly equal to the background"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, skip_blanks), -1, 65535, -1); VIPS_ARG_STRING(class, "id", 20, _("id"), _("Resource ID"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, id), "https://example.com/iiif"); VIPS_ARG_INT(class, "Q", 21, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDz, Q), 1, 100, 75); /* How annoying. We stupidly had these in earlier versions. */ VIPS_ARG_BOOL(class, "no_strip", 22, _("No strip"), _("Don't strip tile metadata"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveDz, no_strip), FALSE); VIPS_ARG_STRING(class, "basename", 23, _("Base name"), _("Base name to save to"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveDz, imagename), NULL); VIPS_ARG_STRING(class, "dirname", 1, _("Directory name"), _("Directory name to save to"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveDz, dirname), NULL); VIPS_ARG_INT(class, "tile_width", 12, _("Tile width"), _("Tile width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveDz, tile_size), 1, 8192, 254); VIPS_ARG_INT(class, "tile_height", 12, _("Tile height"), _("Tile height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveDz, tile_size), 1, 8192, 254); VIPS_ARG_BOOL(class, "properties", 16, _("Properties"), _("Write a properties file to the output directory"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveDz, properties), FALSE); } static void vips_foreign_save_dz_init(VipsForeignSaveDz *dz) { VIPS_SETSTR(dz->suffix, ".jpeg"); dz->layout = VIPS_FOREIGN_DZ_LAYOUT_DZ; dz->overlap = 1; dz->tile_size = 254; dz->tile_count = 0; dz->depth = VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL; dz->angle = VIPS_ANGLE_D0; dz->container = VIPS_FOREIGN_DZ_CONTAINER_FS; dz->compression = 0; dz->region_shrink = VIPS_REGION_SHRINK_MEAN; dz->skip_blanks = -1; dz->Q = 75; // we default background to 255 (not 0), see vips_foreign_save_init() VipsForeignSave *save = (VipsForeignSave *) dz; if (save->background) vips_area_unref(VIPS_AREA(save->background)); save->background = vips_array_double_newv(1, 255.0); } typedef struct _VipsForeignSaveDzTarget { VipsForeignSaveDz parent_object; VipsTarget *target; } VipsForeignSaveDzTarget; typedef VipsForeignSaveDzClass VipsForeignSaveDzTargetClass; G_DEFINE_TYPE(VipsForeignSaveDzTarget, vips_foreign_save_dz_target, vips_foreign_save_dz_get_type()); static int vips_foreign_save_dz_target_build(VipsObject *object) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) object; VipsForeignSaveDzTarget *target = (VipsForeignSaveDzTarget *) object; dz->target = target->target; g_object_ref(dz->target); return VIPS_OBJECT_CLASS(vips_foreign_save_dz_target_parent_class) ->build(object); } static void vips_foreign_save_dz_target_class_init(VipsForeignSaveDzTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dzsave_target"; object_class->description = _("save image to deepzoom target"); object_class->build = vips_foreign_save_dz_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDzTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_dz_target_init(VipsForeignSaveDzTarget *target) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) target; /* zip default for target output. */ dz->container = VIPS_FOREIGN_DZ_CONTAINER_ZIP; } typedef struct _VipsForeignSaveDzFile { VipsForeignSaveDz parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveDzFile; typedef VipsForeignSaveDzClass VipsForeignSaveDzFileClass; G_DEFINE_TYPE(VipsForeignSaveDzFile, vips_foreign_save_dz_file, vips_foreign_save_dz_get_type()); static int vips_foreign_save_dz_file_build(VipsObject *object) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) object; VipsForeignSaveDzFile *file = (VipsForeignSaveDzFile *) object; dz->filename = file->filename; return VIPS_OBJECT_CLASS(vips_foreign_save_dz_file_parent_class) ->build(object); } static void vips_foreign_save_dz_file_class_init(VipsForeignSaveDzFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dzsave"; object_class->description = _("save image to deepzoom file"); object_class->build = vips_foreign_save_dz_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveDzFile, filename), NULL); } static void vips_foreign_save_dz_file_init(VipsForeignSaveDzFile *file) { } typedef struct _VipsForeignSaveDzBuffer { VipsForeignSaveDz parent_object; VipsArea *buf; } VipsForeignSaveDzBuffer; typedef VipsForeignSaveDzClass VipsForeignSaveDzBufferClass; G_DEFINE_TYPE(VipsForeignSaveDzBuffer, vips_foreign_save_dz_buffer, vips_foreign_save_dz_get_type()); static int vips_foreign_save_dz_buffer_build(VipsObject *object) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) object; VipsForeignSaveDzBuffer *buffer = (VipsForeignSaveDzBuffer *) object; VipsBlob *blob; if (!(dz->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_dz_buffer_parent_class) ->build(object)) return -1; g_object_get(dz->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_dz_buffer_class_init(VipsForeignSaveDzBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "dzsave_buffer"; object_class->description = _("save image to dz buffer"); object_class->build = vips_foreign_save_dz_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveDzBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_dz_buffer_init(VipsForeignSaveDzBuffer *buffer) { VipsForeignSaveDz *dz = (VipsForeignSaveDz *) buffer; /* zip default for memory output. */ dz->container = VIPS_FOREIGN_DZ_CONTAINER_ZIP; } #endif /*HAVE_LIBARCHIVE*/ /** * vips_dzsave: (method) * @in: image to save * @name: name to save to * @...: `NULL`-terminated list of optional named arguments * * Save an image as a set of tiles at various resolutions. By default dzsave * uses DeepZoom layout -- use @layout to pick other conventions. * * [method@Image.dzsave] creates a directory called @name to hold the tiles. * If @name ends `.zip`, [method@Image.dzsave] will create a zip file called * @name to hold the tiles. You can use @container to force zip file output. * * Use @basename to set the name of the image we are creating. The * default value is set from @name. * * By default, tiles are written as JPEGs. Use @Q set set the JPEG quality * factor. * * You can set @suffix to something like `".png[bitdepth=4]"` to write tiles * in another format. * * In Google layout mode, edge tiles are expanded to @tile_size by @tile_size * pixels. Normally they are filled with white, but you can set another colour * with @background. Images are usually placed at the top-left of the tile, * but you can have them centred by turning on @centre. * * You can set the size and overlap of tiles with @tile_size and @overlap. * They default to the correct settings for the selected @layout. The deepzoom * defaults produce 256x256 jpeg files for centre tiles, the most efficient * size. * * Use @depth to control how low the pyramid goes. This defaults to the * correct setting for the @layout you select. * * You can rotate the image during write with the @angle argument. However, * this will only work for images which support random access, like openslide, * and not for things like JPEG. You'll need to rotate those images * yourself with [method@Image.rot]. Note that the `autorotate` option to the loader * may do what you need. * * By default, all tiles are stripped since usually you do not want a copy of * all metadata in every tile. Set @keep if you want to keep metadata. * * If @container is set to `zip`, you can set a compression level from -1 * (use zlib default), 0 (store, compression disabled) to 9 (max compression). * If no value is given, the default is to store files without compression. * * You can use @region_shrink to control the method for shrinking each 2x2 * region. This defaults to using the average of the 4 input pixels but you can * also use the median in cases where you want to preserve the range of values. * * If you set @skip_blanks to a value greater than or equal to zero, tiles * which are all within that many pixel values to the background are skipped. * This can save a lot of space for some image types. This option defaults to * 5 in Google layout mode, -1 otherwise. * * In IIIF layout, you can set the base of the `id` property in `info.json` * with @id. The default is `https://example.com/iiif`. * * Use @layout [enum@Vips.ForeignDzLayout.IIIF3] for IIIF v3 layout. * * ::: tip "Optional arguments" * * @basename: `gchararray`, base part of name * * @layout: [enum@ForeignDzLayout], directory layout convention * * @suffix: `gchararray`, suffix for tiles * * @overlap: `gint`, set tile overlap * * @tile_size: `gint`, set tile size * * @background: [struct@ArrayDouble], background colour * * @depth: [enum@ForeignDzDepth], how deep to make the pyramid * * @centre: `gboolean`, centre the tiles * * @angle: [enum@Angle], rotate the image by this much * * @container: [enum@ForeignDzContainer], set container type * * @compression: `gint`, zip deflate compression level * * @region_shrink: [enum@RegionShrink], how to shrink each 2x2 region * * @skip_blanks: `gint`, skip tiles which are nearly equal to the * background * * @id: `gchararray`, id for IIIF properties * * @Q: `gint`, quality factor * * ::: seealso * [method@Image.tiffsave]. * * Returns: 0 on success, -1 on error. */ int vips_dzsave(VipsImage *in, const char *name, ...) { va_list ap; int result; va_start(ap, name); result = vips_call_split("dzsave", ap, in, name); va_end(ap); return result; } /** * vips_dzsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.dzsave], but save to a memory buffer. * * Output is always in a zip container. Use @basename to set the name of the * directory that the zip will create when unzipped. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: tip "Optional arguments" * * @basename: `gchararray`, base part of name * * @layout: [enum@ForeignDzLayout], directory layout convention * * @suffix: `gchararray`, suffix for tiles * * @overlap: `gint`, set tile overlap * * @tile_size: `gint`, set tile size * * @background: [struct@ArrayDouble], background colour * * @depth: [enum@ForeignDzDepth], how deep to make the pyramid * * @centre: `gboolean`, centre the tiles * * @angle: [enum@Angle], rotate the image by this much * * @container: [enum@ForeignDzContainer], set container type * * @compression: `gint`, zip deflate compression level * * @region_shrink: [enum@RegionShrink], how to shrink each 2x2 region * * @skip_blanks: `gint`, skip tiles which are nearly equal to the * background * * @id: `gchararray`, id for IIIF properties * * @Q: `gint`, quality factor * * ::: seealso * [method@Image.dzsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_dzsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("dzsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_dzsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.dzsave], but save to a target. * * ::: tip "Optional arguments" * * @basename: `gchararray`, base part of name * * @layout: [enum@ForeignDzLayout], directory layout convention * * @suffix: `gchararray`, suffix for tiles * * @overlap: `gint`, set tile overlap * * @tile_size: `gint`, set tile size * * @background: [struct@ArrayDouble], background colour * * @depth: [enum@ForeignDzDepth], how deep to make the pyramid * * @centre: `gboolean`, centre the tiles * * @angle: [enum@Angle], rotate the image by this much * * @container: [enum@ForeignDzContainer], set container type * * @compression: `gint`, zip deflate compression level * * @region_shrink: [enum@RegionShrink], how to shrink each 2x2 region * * @skip_blanks: `gint`, skip tiles which are nearly equal to the * background * * @id: `gchararray`, id for IIIF properties * * @Q: `gint`, quality factor * * ::: seealso * [method@Image.dzsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_dzsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("dzsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/exif.c000066400000000000000000001077051516303661500175020ustar00rootroot00000000000000/* parse EXIF metadata block out into a set of fields, and reassemble EXIF * block from original block, plus modified fields * * 7/11/16 * - from jpeg2vips * 14/10/17 * - only read orientation from ifd0 * 1/2/18 * - remove exif thumbnail if "jpeg-thumbnail-data" has been removed * 3/7/18 * - add support for writing string-valued fields * 9/7/18 [@Nan619] * - get tag name from tag plus ifd * 13/11/21 * - better handling of strings with embedded metacharacters */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #ifdef HAVE_EXIF #ifdef UNTAGGED_EXIF #include #include #include #include #else /*!UNTAGGED_EXIF*/ #include #include #include #include #endif /*UNTAGGED_EXIF*/ #include "pforeign.h" // render an entry as a utf8 string static char * entry_to_s(ExifEntry *entry) { /* Some extra space for conversion to string ... this can be quite a bit * for formats like float. Ban crazy size values. */ int size = VIPS_MIN(entry->size, 10000); int max_size = size * 3 + 32; char *text = VIPS_MALLOC(NULL, max_size + 1); // this renders floats as eg. "12.2345", enums as "Inch", etc. exif_entry_get_value(entry, text, max_size); // libexif does not null-terminate ASCII strings, we must add the \0 // ourselves if (entry->format == EXIF_FORMAT_ASCII) text[size] = '\0'; char *utf8 = g_utf8_make_valid(text, -1); g_free(text); return utf8; } #ifdef DEBUG_VERBOSE /* Print exif for debugging ... hacked from exif-0.6.9/actions.c */ static void show_tags(ExifData *data) { int i; unsigned int tag; const char *name; printf("show EXIF tags:\n"); for (i = 0; i < EXIF_IFD_COUNT; i++) printf("%-7.7s", exif_ifd_get_name(i)); printf("\n"); for (tag = 0; tag < 0xffff; tag++) { name = exif_tag_get_title(tag); if (!name) continue; printf(" 0x%04x %-29.29s", tag, name); for (i = 0; i < EXIF_IFD_COUNT; i++) if (exif_content_get_entry(data->ifd[i], tag)) printf(" * "); else printf(" - "); printf("\n"); } } static void show_entry(ExifEntry *entry, void *client) { char *text = entry_to_s(entry); printf("%s", exif_tag_get_title(entry->tag)); printf("|"); printf("%s", text); printf("|"); printf("%s", exif_format_get_name(entry->format)); printf("|"); printf("%d bytes", entry->size); printf("\n"); g_free(text); } static void show_ifd(ExifContent *content, void *client) { int *ifd = (int *) client; printf("- ifd %d\n", *ifd); exif_content_foreach_entry(content, show_entry, client); *ifd += 1; } static void show_values(ExifData *data) { ExifByteOrder order; int ifd; order = exif_data_get_byte_order(data); printf("EXIF tags in '%s' byte order\n", exif_byte_order_get_name(order)); printf("Title|Value|Format|Size\n"); ifd = 0; exif_data_foreach_content(data, show_ifd, &ifd); if (data->size) printf("contains thumbnail of %d bytes\n", data->size); } #endif /*DEBUG_VERBOSE*/ /* Like exif_data_new_from_data(), but don't default missing fields. * * If we do exif_data_new_from_data(), then missing fields are set to * their default value and we won't know about it. */ static ExifData * vips_exif_load_data_without_fix(const void *data, size_t length) { ExifData *ed; /* exif_data_load_data() only allows uint for length. Limit it to less * than that: 2**23 should be enough for anyone. */ if (length < 4) { vips_error("exif", "%s", _("exif too small")); return NULL; } if (length > 1 << 23) { vips_error("exif", "%s", _("exif too large")); return NULL; } if (!(ed = exif_data_new())) { vips_error("exif", "%s", _("unable to init exif")); return NULL; } exif_data_unset_option(ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); if (!vips_isprefix("Exif", (char *) data)) { /* Ensure "Exif" prefix as loaders may not provide it. */ void *data_with_prefix; data_with_prefix = g_malloc0(length + 6); memcpy(data_with_prefix, "Exif\0\0", 6); memcpy((char *) data_with_prefix + 6, data, length); exif_data_load_data(ed, data_with_prefix, length + 6); g_free(data_with_prefix); } else exif_data_load_data(ed, data, length); return ed; } static int vips_exif_get_int(ExifData *ed, ExifEntry *entry, unsigned long component, int *out) { ExifByteOrder bo = exif_data_get_byte_order(ed); size_t sizeof_component = entry->size / entry->components; size_t offset = component * sizeof_component; switch (entry->format) { case EXIF_FORMAT_SHORT: *out = exif_get_short(entry->data + offset, bo); break; case EXIF_FORMAT_SSHORT: *out = exif_get_sshort(entry->data + offset, bo); break; case EXIF_FORMAT_LONG: /* This won't work for huge values, but who cares. */ *out = (int) exif_get_long(entry->data + offset, bo); break; case EXIF_FORMAT_SLONG: *out = exif_get_slong(entry->data + offset, bo); break; default: return -1; } return 0; } static int vips_exif_get_rational(ExifData *ed, ExifEntry *entry, unsigned long component, ExifRational *out) { if (entry->format == EXIF_FORMAT_RATIONAL) { ExifByteOrder bo = exif_data_get_byte_order(ed); size_t sizeof_component = entry->size / entry->components; size_t offset = component * sizeof_component; *out = exif_get_rational(entry->data + offset, bo); } else return -1; return 0; } static int vips_exif_get_srational(ExifData *ed, ExifEntry *entry, unsigned long component, ExifSRational *out) { if (entry->format == EXIF_FORMAT_SRATIONAL) { ExifByteOrder bo = exif_data_get_byte_order(ed); size_t sizeof_component = entry->size / entry->components; size_t offset = component * sizeof_component; *out = exif_get_srational(entry->data + offset, bo); } else return -1; return 0; } static int vips_exif_get_double(ExifData *ed, ExifEntry *entry, unsigned long component, double *out) { ExifRational rv; ExifSRational srv; double value; if (!vips_exif_get_rational(ed, entry, component, &rv)) { if (rv.denominator == 0) value = 0; else value = (double) rv.numerator / rv.denominator; } else if (!vips_exif_get_srational(ed, entry, component, &srv)) { if (srv.denominator == 0) value = 0; else value = (double) srv.numerator / srv.denominator; } else return -1; *out = value; return 0; } /* Save an exif value to a string in a way that we can restore. We only bother * for the simple formats (that a client might try to change) though. * * Keep in sync with vips_exif_from_s() below. */ static void vips_exif_to_s(ExifData *ed, ExifEntry *entry, VipsDbuf *buf) { char *text = entry_to_s(entry); unsigned long i; int iv; ExifRational rv; ExifSRational srv; if (entry->components == 0 || entry->components >= 10) { vips_dbuf_writef(buf, "%s ", text); } else { switch (entry->format) { case EXIF_FORMAT_SHORT: case EXIF_FORMAT_SSHORT: case EXIF_FORMAT_LONG: case EXIF_FORMAT_SLONG: for (i = 0; i < entry->components; i++) { vips_exif_get_int(ed, entry, i, &iv); vips_dbuf_writef(buf, "%d ", iv); } break; case EXIF_FORMAT_RATIONAL: for (i = 0; i < entry->components; i++) { vips_exif_get_rational(ed, entry, i, &rv); vips_dbuf_writef(buf, "%u/%u ", rv.numerator, rv.denominator); } break; case EXIF_FORMAT_SRATIONAL: for (i = 0; i < entry->components; i++) { vips_exif_get_srational(ed, entry, i, &srv); vips_dbuf_writef(buf, "%d/%d ", srv.numerator, srv.denominator); } break; default: vips_dbuf_writef(buf, "%s ", text); break; } } vips_dbuf_writef(buf, "(%s, %s, %lu components, %d bytes)", text, exif_format_get_name(entry->format), entry->components, entry->size); g_free(text); } typedef struct _VipsExifParams { VipsImage *image; ExifData *ed; } VipsExifParams; /* tags do not uniquely set tag names: the same tag can have different * names in different ifds. * * As long as this entry has been linked to an ifd, get the tag name. */ static const char * vips_exif_entry_get_name(ExifEntry *entry) { if (!entry->parent) return NULL; return exif_tag_get_name_in_ifd(entry->tag, exif_entry_get_ifd(entry)); } static void vips_exif_attach_entry(ExifEntry *entry, VipsExifParams *params) { const char *tag_name; char vips_name_txt[256]; VipsBuf vips_name = VIPS_BUF_STATIC(vips_name_txt); VipsDbuf value = { 0 }; if (!(tag_name = vips_exif_entry_get_name(entry))) return; vips_buf_appendf(&vips_name, "exif-ifd%d-%s", exif_entry_get_ifd(entry), tag_name); vips_exif_to_s(params->ed, entry, &value); /* Can't do anything sensible with the error return. */ (void) vips_image_set_string(params->image, vips_buf_all(&vips_name), (char *) vips_dbuf_string(&value, NULL)); vips_dbuf_destroy(&value); } static void vips_exif_get_content(ExifContent *content, VipsExifParams *params) { exif_content_foreach_entry(content, (ExifContentForeachEntryFunc) vips_exif_attach_entry, params); } static int vips_exif_entry_get_double(ExifData *ed, int ifd, ExifTag tag, double *out) { ExifEntry *entry; if (!(entry = exif_content_get_entry(ed->ifd[ifd], tag)) || entry->components != 1) return -1; return vips_exif_get_double(ed, entry, 0, out); } static int vips_exif_entry_get_int(ExifData *ed, int ifd, ExifTag tag, int *out) { ExifEntry *entry; if (!(entry = exif_content_get_entry(ed->ifd[ifd], tag)) || entry->components != 1) return -1; return vips_exif_get_int(ed, entry, 0, out); } /* Set the image resolution from the EXIF tags. */ static int vips_image_resolution_from_exif(VipsImage *image, ExifData *ed) { double xres, yres; int unit; /* The main image xres/yres are in ifd0. ifd1 has xres/yres of the * image thumbnail, if any. * * Don't warn about missing res fields, it's very common, especially for * things like webp. */ if (vips_exif_entry_get_double(ed, 0, EXIF_TAG_X_RESOLUTION, &xres) || vips_exif_entry_get_double(ed, 0, EXIF_TAG_Y_RESOLUTION, &yres)) return -1; /* resuint is optional and defaults to inch. */ unit = 2; (void) vips_exif_entry_get_int(ed, 0, EXIF_TAG_RESOLUTION_UNIT, &unit); #ifdef DEBUG printf("vips_image_resolution_from_exif: seen exif tags " "xres = %g, yres = %g, unit = %d\n", xres, yres, unit); #endif /*DEBUG*/ switch (unit) { case 1: /* No units, instead xres / yres gives the pixel aspect ratio. */ break; case 2: /* In inches. */ xres /= 25.4; yres /= 25.4; vips_image_set_string(image, VIPS_META_RESOLUTION_UNIT, "in"); break; case 3: /* In cm. */ xres /= 10.0; yres /= 10.0; vips_image_set_string(image, VIPS_META_RESOLUTION_UNIT, "cm"); break; default: g_warning("unknown EXIF resolution unit"); return -1; } #ifdef DEBUG printf("vips_image_resolution_from_exif: " "seen exif resolution %g, %g p/mm\n", xres, yres); #endif /*DEBUG*/ /* Don't allow negative resolution. */ image->Xres = VIPS_MAX(0, xres); image->Yres = VIPS_MAX(0, yres); return 0; } /* Need to fwd ref this. */ static int vips_exif_resolution_from_image(ExifData *ed, VipsImage *image); /* Scan the exif block on the image, if any, and make a set of vips metadata * tags for what we find. */ int vips__exif_parse(VipsImage *image) { const void *data; size_t size; ExifData *ed; VipsExifParams params; const char *str; if (!vips_image_get_typeof(image, VIPS_META_EXIF_NAME)) return 0; if (vips_image_get_blob(image, VIPS_META_EXIF_NAME, &data, &size)) return -1; if (!(ed = vips_exif_load_data_without_fix(data, size))) return -1; #ifdef DEBUG_VERBOSE show_tags(ed); show_values(ed); #endif /*DEBUG_VERBOSE*/ /* Look for resolution fields and use them to set the VIPS xres/yres * fields. * * If the fields are missing, set them from the image, which will have * previously had them set from something like JFIF. */ if (vips_image_resolution_from_exif(image, ed) && vips_exif_resolution_from_image(ed, image)) { exif_data_free(ed); return -1; } /* Make sure all required fields are there before we attach the vips * metadata. */ exif_data_fix(ed); /* Attach informational fields for what we find. */ params.image = image; params.ed = ed; exif_data_foreach_content(ed, (ExifDataForeachContentFunc) vips_exif_get_content, ¶ms); vips_image_set_blob_copy(image, "jpeg-thumbnail-data", ed->data, ed->size); exif_data_free(ed); /* Orientation handling. ifd0 has the Orientation tag for the main * image. */ if (vips_image_get_typeof(image, "exif-ifd0-Orientation") != 0 && !vips_image_get_string(image, "exif-ifd0-Orientation", &str)) { int orientation; orientation = atoi(str); if (orientation < 1 || orientation > 8) orientation = 1; vips_image_set_int(image, VIPS_META_ORIENTATION, orientation); } return 0; } static void vips_exif_set_int(ExifData *ed, ExifEntry *entry, unsigned long component, void *data) { int value = *((int *) data); ExifByteOrder bo; size_t sizeof_component; size_t offset = component; if (entry->components <= component) { VIPS_DEBUG_MSG("vips_exif_set_int: too few components\n"); return; } /* Wait until after the component check to make sure we can't get /0. */ bo = exif_data_get_byte_order(ed); sizeof_component = entry->size / entry->components; offset = component * sizeof_component; VIPS_DEBUG_MSG("vips_exif_set_int: %s = %d\n", vips_exif_entry_get_name(entry), value); if (entry->format == EXIF_FORMAT_SHORT) exif_set_short(entry->data + offset, bo, value); else if (entry->format == EXIF_FORMAT_SSHORT) exif_set_sshort(entry->data + offset, bo, value); else if (entry->format == EXIF_FORMAT_LONG) exif_set_long(entry->data + offset, bo, value); else if (entry->format == EXIF_FORMAT_SLONG) exif_set_slong(entry->data + offset, bo, value); } static void vips_exif_double_to_rational(double value, ExifRational *rv) { /* We will usually set factors of 10, so use 1000 as the denominator * and it'll probably be OK. */ rv->numerator = value * 1000; rv->denominator = 1000; } static void vips_exif_double_to_srational(double value, ExifSRational *srv) { /* We will usually set factors of 10, so use 1000 as the denominator * and it'll probably be OK. */ srv->numerator = value * 1000; srv->denominator = 1000; } /* Parse a char * into an ExifRational. We allow floats as well. */ static void vips_exif_parse_rational(const char *str, ExifRational *rv) { if (sscanf(str, " %u / %u ", &rv->numerator, &rv->denominator) == 2) return; vips_exif_double_to_rational(g_ascii_strtod(str, NULL), rv); } /* Parse a char * into an ExifSRational. We allow floats as well. */ static void vips_exif_parse_srational(const char *str, ExifSRational *srv) { if (sscanf(str, " %d / %d ", &srv->numerator, &srv->denominator) == 2) return; vips_exif_double_to_srational(g_ascii_strtod(str, NULL), srv); } /* Does both signed and unsigned rationals from a char *. */ static void vips_exif_set_rational(ExifData *ed, ExifEntry *entry, unsigned long component, void *data) { char *value = (char *) data; ExifByteOrder bo; size_t sizeof_component; size_t offset; if (entry->components <= component) { VIPS_DEBUG_MSG("vips_exif_set_rational: too few components\n"); return; } /* Wait until after the component check to make sure we can't get /0. */ bo = exif_data_get_byte_order(ed); sizeof_component = entry->size / entry->components; offset = component * sizeof_component; VIPS_DEBUG_MSG("vips_exif_set_rational: %s = \"%s\"\n", vips_exif_entry_get_name(entry), value); if (entry->format == EXIF_FORMAT_RATIONAL) { ExifRational rv; vips_exif_parse_rational(value, &rv); VIPS_DEBUG_MSG("vips_exif_set_rational: %u / %u\n", rv.numerator, rv.denominator); exif_set_rational(entry->data + offset, bo, rv); } else if (entry->format == EXIF_FORMAT_SRATIONAL) { ExifSRational srv; vips_exif_parse_srational(value, &srv); VIPS_DEBUG_MSG("vips_exif_set_rational: %d / %d\n", srv.numerator, srv.denominator); exif_set_srational(entry->data + offset, bo, srv); } } /* Does both signed and unsigned rationals from a double*. * * Don't change the exit entry if the value currently there is a good * approximation of the double we are trying to set. */ static void vips_exif_set_double(ExifData *ed, ExifEntry *entry, unsigned long component, void *data) { double value = *((double *) data); ExifByteOrder bo; size_t sizeof_component; size_t offset; double old_value; if (entry->components <= component) { VIPS_DEBUG_MSG("vips_exif_set_double: too few components\n"); return; } /* Wait until after the component check to make sure we can't get /0. */ bo = exif_data_get_byte_order(ed); sizeof_component = entry->size / entry->components; offset = component * sizeof_component; VIPS_DEBUG_MSG("vips_exif_set_double: %s = %g\n", vips_exif_entry_get_name(entry), value); if (entry->format == EXIF_FORMAT_RATIONAL) { ExifRational rv; rv = exif_get_rational(entry->data + offset, bo); if (rv.denominator == 0) old_value = 0; else old_value = (double) rv.numerator / rv.denominator; if (fabs(old_value - value) > 0.0001) { vips_exif_double_to_rational(value, &rv); VIPS_DEBUG_MSG("vips_exif_set_double: %u / %u\n", rv.numerator, rv.denominator); exif_set_rational(entry->data + offset, bo, rv); } } else if (entry->format == EXIF_FORMAT_SRATIONAL) { ExifSRational srv; srv = exif_get_srational(entry->data + offset, bo); if (srv.denominator == 0) old_value = 0; else old_value = (double) srv.numerator / srv.denominator; if (fabs(old_value - value) > 0.0001) { vips_exif_double_to_srational(value, &srv); VIPS_DEBUG_MSG("vips_exif_set_double: %d / %d\n", srv.numerator, srv.denominator); exif_set_srational(entry->data + offset, bo, srv); } } } typedef void (*write_fn)(ExifData *ed, ExifEntry *entry, unsigned long component, void *data); /* String-valued tags need special treatment, sadly. * * Strings are written in three ways: * * 1. As ASCII, but with an 8-byte preamble giving the encoding (it's always * ASCII though) and the format undefined. * 2. As plain ASCII, with the format giving the encoding. * 3. As UTF16 in the MS tags. */ static gboolean tag_is_encoding(ExifTag tag) { return tag == EXIF_TAG_USER_COMMENT; } static gboolean tag_is_ascii(ExifTag tag) { return tag == EXIF_TAG_MAKE || tag == EXIF_TAG_MODEL || tag == EXIF_TAG_IMAGE_DESCRIPTION || tag == EXIF_TAG_ARTIST || tag == EXIF_TAG_SOFTWARE || tag == EXIF_TAG_COPYRIGHT || tag == EXIF_TAG_DATE_TIME || tag == EXIF_TAG_DATE_TIME_ORIGINAL || tag == EXIF_TAG_DATE_TIME_DIGITIZED || tag == EXIF_TAG_SUB_SEC_TIME || tag == EXIF_TAG_SUB_SEC_TIME_ORIGINAL || tag == EXIF_TAG_SUB_SEC_TIME_DIGITIZED #ifdef HAVE_EXIF_0_6_22 || tag == EXIF_TAG_CAMERA_OWNER_NAME || tag == EXIF_TAG_BODY_SERIAL_NUMBER || tag == EXIF_TAG_LENS_MAKE || tag == EXIF_TAG_LENS_MODEL || tag == EXIF_TAG_LENS_SERIAL_NUMBER #endif #ifdef HAVE_EXIF_0_6_23 || tag == EXIF_TAG_OFFSET_TIME || tag == EXIF_TAG_OFFSET_TIME_ORIGINAL || tag == EXIF_TAG_OFFSET_TIME_DIGITIZED || tag == EXIF_TAG_GPS_LATITUDE_REF || tag == EXIF_TAG_GPS_LONGITUDE_REF || tag == EXIF_TAG_GPS_SATELLITES || tag == EXIF_TAG_GPS_STATUS || tag == EXIF_TAG_GPS_MEASURE_MODE || tag == EXIF_TAG_GPS_SPEED_REF || tag == EXIF_TAG_GPS_TRACK_REF || tag == EXIF_TAG_GPS_IMG_DIRECTION_REF || tag == EXIF_TAG_GPS_MAP_DATUM || tag == EXIF_TAG_GPS_DEST_LATITUDE_REF || tag == EXIF_TAG_GPS_DEST_LONGITUDE_REF || tag == EXIF_TAG_GPS_DEST_BEARING_REF || tag == EXIF_TAG_GPS_DEST_DISTANCE_REF || tag == EXIF_TAG_GPS_DATE_STAMP #endif ; } static gboolean tag_is_utf16(ExifTag tag) { return tag == EXIF_TAG_XP_TITLE || tag == EXIF_TAG_XP_COMMENT || tag == EXIF_TAG_XP_AUTHOR || tag == EXIF_TAG_XP_KEYWORDS || tag == EXIF_TAG_XP_SUBJECT; } /* Set a libexif-formatted string entry. */ static void vips_exif_alloc_string(ExifEntry *entry, unsigned long components) { ExifMem *mem; g_assert(!entry->data); /* The string in the entry must be allocated with the same allocator * that was used to allocate the entry itself. We can't do this * because the allocator is private :( so we must assume the entry was * created with the default one. */ mem = exif_mem_new_default(); /* EXIF_FORMAT_UNDEFINED is correct for EXIF_TAG_USER_COMMENT, our * caller should change this if it wishes. */ entry->data = exif_mem_alloc(mem, components); entry->size = components; entry->components = components; entry->format = EXIF_FORMAT_UNDEFINED; VIPS_FREEF(exif_mem_unref, mem); } /* The final " (xx, yy, zz, kk)" part of the string (if present) was * added by us in _to_s(), we must remove it before setting the string * back again. * * It may not be there if the user has changed the string. */ static char * drop_tail(const char *data) { char *str; char *p; str = g_strdup(data); p = str + strlen(str); if (p > str && *g_utf8_prev_char(p) == ')' && (p = g_utf8_strrchr(str, -1, (gunichar) '(')) && p > str && *(p = g_utf8_prev_char(p)) == ' ') *p = '\0'; return str; } /* special header required for EXIF_TAG_USER_COMMENT. */ #define ASCII_COMMENT "ASCII\0\0\0" /* Write a libvips NULL-terminated utf-8 string into a entry tagged with a * encoding. UserComment is like this, for example. */ static void vips_exif_set_string_encoding(ExifData *ed, ExifEntry *entry, unsigned long component, const char *data) { char *str; char *ascii; int len; str = drop_tail(data); /* libexif can only really save ASCII to things like UserComment. */ ascii = g_str_to_ascii(str, NULL); g_free(str); str = ascii; /* libexif comment strings are not NULL-terminated, and have an * encoding tag (always ASCII) in the first 8 bytes. */ len = strlen(str); vips_exif_alloc_string(entry, sizeof(ASCII_COMMENT) - 1 + len); memcpy(entry->data, ASCII_COMMENT, sizeof(ASCII_COMMENT) - 1); memcpy(entry->data + sizeof(ASCII_COMMENT) - 1, str, len); g_free(str); } /* Write a libvips NULL-terminated utf-8 string into an ASCII entry. Tags like * ImageDescription work like this. */ static void vips_exif_set_string_ascii(ExifData *ed, ExifEntry *entry, unsigned long component, const char *data) { char *str; char *ascii; int len; str = drop_tail(data); /* libexif can only really save ASCII to things like UserComment. */ ascii = g_str_to_ascii(str, NULL); g_free(str); str = ascii; /* ASCII strings are NULL-terminated. */ len = strlen(str); vips_exif_alloc_string(entry, len + 1); memcpy(entry->data, str, len + 1); entry->format = EXIF_FORMAT_ASCII; g_free(str); } /* Write a libvips NULL-terminated utf-8 string into a utf16 entry. */ static void vips_exif_set_string_utf16(ExifData *ed, ExifEntry *entry, unsigned long component, const char *data) { char *str; gunichar2 *utf16; glong len; str = drop_tail(data); utf16 = g_utf8_to_utf16(str, -1, NULL, &len, NULL); /* libexif utf16 strings are NULL-terminated. */ vips_exif_alloc_string(entry, (len + 1) * 2); memcpy(entry->data, utf16, (len + 1) * 2); entry->format = EXIF_FORMAT_BYTE; g_free(utf16); g_free(str); } /* Write a tag. Update what's there, or make a new one. */ static void vips_exif_set_tag(ExifData *ed, int ifd, ExifTag tag, write_fn fn, void *data) { ExifEntry *entry; if ((entry = exif_content_get_entry(ed->ifd[ifd], tag))) { fn(ed, entry, 0, data); } else { entry = exif_entry_new(); /* tag must be set before calling exif_content_add_entry. */ entry->tag = tag; exif_content_add_entry(ed->ifd[ifd], entry); exif_entry_unref(entry); /* libexif makes us have a special path for string-valued * fields :( */ if (tag_is_encoding(tag)) vips_exif_set_string_encoding(ed, entry, 0, data); else if (tag_is_ascii(tag)) vips_exif_set_string_ascii(ed, entry, 0, data); else if (tag_is_utf16(tag)) vips_exif_set_string_utf16(ed, entry, 0, data); else { exif_entry_initialize(entry, tag); fn(ed, entry, 0, data); } } } /* Set the EXIF resolution from the vips xres/yres tags. */ static int vips_exif_resolution_from_image(ExifData *ed, VipsImage *image) { double xres, yres; const char *p; int unit; VIPS_DEBUG_MSG("vips_exif_resolution_from_image: vips res of %g, %g\n", image->Xres, image->Yres); /* Default to inches, more progs support it. */ unit = 2; if (vips_image_get_typeof(image, VIPS_META_RESOLUTION_UNIT) && !vips_image_get_string(image, VIPS_META_RESOLUTION_UNIT, &p)) { if (vips_isprefix("cm", p)) unit = 3; else if (vips_isprefix("none", p)) unit = 1; } switch (unit) { case 1: xres = image->Xres; yres = image->Yres; break; case 2: xres = image->Xres * 25.4; yres = image->Yres * 25.4; break; case 3: xres = image->Xres * 10.0; yres = image->Yres * 10.0; break; default: g_warning("unknown EXIF resolution unit"); return 0; } /* Main image xres/yres/unit are in ifd0. ifd1 has the thumbnail * xres/yres/unit. */ vips_exif_set_tag(ed, 0, EXIF_TAG_X_RESOLUTION, vips_exif_set_double, (void *) &xres); vips_exif_set_tag(ed, 0, EXIF_TAG_Y_RESOLUTION, vips_exif_set_double, (void *) &yres); vips_exif_set_tag(ed, 0, EXIF_TAG_RESOLUTION_UNIT, vips_exif_set_int, (void *) &unit); return 0; } /* Exif also tracks image dimensions. */ static int vips_exif_set_dimensions(ExifData *ed, VipsImage *im) { VIPS_DEBUG_MSG("vips_exif_set_dimensions: vips size of %d, %d\n", im->Xsize, im->Ysize); vips_exif_set_tag(ed, 2, EXIF_TAG_PIXEL_X_DIMENSION, vips_exif_set_int, (void *) &im->Xsize); vips_exif_set_tag(ed, 2, EXIF_TAG_PIXEL_Y_DIMENSION, vips_exif_set_int, (void *) &im->Ysize); return 0; } /* And orientation. */ static int vips_exif_set_orientation(ExifData *ed, VipsImage *im) { int orientation; /* We set the tag, even if it's been deleted, since it's a required * field. */ if (!vips_image_get_typeof(im, VIPS_META_ORIENTATION) || vips_image_get_int(im, VIPS_META_ORIENTATION, &orientation)) orientation = 1; VIPS_DEBUG_MSG("set_exif_orientation: %d\n", orientation); vips_exif_set_tag(ed, 0, EXIF_TAG_ORIENTATION, vips_exif_set_int, (void *) &orientation); return 0; } /* And thumbnail. */ static int vips_exif_set_thumbnail(ExifData *ed, VipsImage *im) { /* Delete any old thumbnail data. We should use the exif free func, * but the memory allocator is not exposed by libexif! Hopefully they * are just using free(). * * exif.c makes this assumption too when it tries to update a * thumbnail. */ if (ed->data) { free(ed->data); ed->data = NULL; } ed->size = 0; /* Update EXIF thumbnail from metadata, if any. */ if (vips_image_get_typeof(im, "jpeg-thumbnail-data")) { const void *data; size_t size; if (vips_image_get_blob(im, "jpeg-thumbnail-data", &data, &size)) return -1; /* Again, we should use the exif allocator attached to this * entry, but it is not exposed! */ if (size > 0 && data) { ed->data = malloc(size); memcpy(ed->data, data, size); ed->size = size; } } return 0; } /* Skip any spaces. */ static const char * skip_space(const char *p) { while (p && *p == ' ') p += 1; return p; } /* Skip to the end of this non-space sequence. */ static const char * skip_nonspace(const char *p) { while (p && *p && *p != ' ') p += 1; return p; } /* See also vips_exif_to_s() ... keep in sync. Only the numeric types are * handled here, since they can be updated. For string types, we have to * destroy and recreate, see above. */ static void vips_exif_from_s(ExifData *ed, ExifEntry *entry, const char *value) { unsigned long i; const char *p; int v; if (entry->format == EXIF_FORMAT_SHORT || entry->format == EXIF_FORMAT_SSHORT || entry->format == EXIF_FORMAT_LONG || entry->format == EXIF_FORMAT_SLONG) { if (entry->components >= 10) return; p = value; for (i = 0; i < entry->components; i++) { if (!(p = skip_space(p))) break; v = atof(p); vips_exif_set_int(ed, entry, i, &v); p = skip_nonspace(p); } } else if (entry->format == EXIF_FORMAT_RATIONAL || entry->format == EXIF_FORMAT_SRATIONAL) { if (entry->components >= 10) return; p = value; for (i = 0; i < entry->components; i++) { if (!(p = skip_space(p))) break; vips_exif_set_rational(ed, entry, i, (void *) p); p = skip_nonspace(p); } } } static void vips_exif_set_entry(ExifData *ed, ExifEntry *entry, unsigned long component, void *data) { const char *string = (const char *) data; vips_exif_from_s(ed, entry, string); } static void * vips_exif_image_field(VipsImage *image, const char *field, GValue *value, void *data) { ExifData *ed = (ExifData *) data; const char *string; int ifd; const char *p; ExifTag tag; if (!vips_isprefix("exif-ifd", field)) return NULL; /* value must be a string. */ if (vips_image_get_string(image, field, &string)) { g_warning("bad exif meta \"%s\"", field); return NULL; } p = field + strlen("exif-ifd"); ifd = atoi(p); if (ifd < 0 || ifd >= EXIF_IFD_COUNT) { g_warning("bad exif ifd %d in \"%s\"", ifd, field); return NULL; } for (; g_ascii_isdigit(*p); p++) ; if (*p != '-') { g_warning("bad exif meta \"%s\"", field); return NULL; } /* GPSVersionID is tag 0 (the error return) so we have to * test the name too. */ if (!(tag = exif_tag_from_name(p + 1)) && strcmp(p + 1, "GPSVersionID") != 0) { g_warning("bad exif meta \"%s\"", field); return NULL; } vips_exif_set_tag(ed, ifd, tag, vips_exif_set_entry, (void *) string); return NULL; } typedef struct _VipsExifRemove { VipsImage *image; ExifData *ed; ExifContent *content; GSList *to_remove; } VipsExifRemove; static void vips_exif_exif_entry(ExifEntry *entry, VipsExifRemove *ve) { const char *tag_name; char vips_name_txt[256]; VipsBuf vips_name_buf = VIPS_BUF_STATIC(vips_name_txt); const char *vips_name; const char *vips_value; if (!(tag_name = vips_exif_entry_get_name(entry))) return; vips_buf_appendf(&vips_name_buf, "exif-ifd%d-%s", exif_entry_get_ifd(entry), tag_name); vips_name = vips_buf_all(&vips_name_buf); /* Is there a image metadata item for this tag? */ vips_value = NULL; if (vips_image_get_typeof(ve->image, vips_name)) { /* No easy way to return an error code from here, sadly. */ if (vips_image_get_string(ve->image, vips_name, &vips_value)) g_warning("bad exif meta \"%s\"", vips_name); } /* Does this field exist on the image? If not, schedule it for * removal. */ if (!vips_value) ve->to_remove = g_slist_prepend(ve->to_remove, entry); /* Orientation is really set from the vips * VIPS_META_ORIENTATION tag. If that's been deleted, we must delete * any matching EXIF tags too. */ if (strcmp(tag_name, "Orientation") == 0 && vips_value) ve->to_remove = g_slist_prepend(ve->to_remove, entry); /* If this is a string tag with a new value, we must also remove it * ready for recreation, see the comment below. */ if (vips_value && (tag_is_encoding(entry->tag) || tag_is_ascii(entry->tag) || tag_is_utf16(entry->tag))) { VipsDbuf value = { 0 }; /* Render the original exif-data value to a string and see * if the user has changed it. If they have, remove it ready * for re-adding. * * Leaving it there prevents it being recreated. */ vips_exif_to_s(ve->ed, entry, &value); if (strcmp((char *) vips_dbuf_string(&value, NULL), vips_value) != 0) ve->to_remove = g_slist_prepend(ve->to_remove, entry); vips_dbuf_destroy(&value); } } static void * vips_exif_exif_remove(ExifEntry *entry, VipsExifRemove *ve, void *b) { #ifdef DEBUG { const char *tag_name; char vips_name_txt[256]; VipsBuf vips_name = VIPS_BUF_STATIC(vips_name_txt); tag_name = vips_exif_entry_get_name(entry); vips_buf_appendf(&vips_name, "exif-ifd%d-%s", exif_entry_get_ifd(entry), tag_name); printf("vips_exif_exif_remove: %s\n", vips_buf_all(&vips_name)); } #endif /*DEBUG*/ exif_content_remove_entry(ve->content, entry); return NULL; } static void vips_exif_exif_content(ExifContent *content, VipsExifRemove *ve) { ve->content = content; ve->to_remove = NULL; exif_content_foreach_entry(content, (ExifContentForeachEntryFunc) vips_exif_exif_entry, ve); vips_slist_map2(ve->to_remove, (VipsSListMap2Fn) vips_exif_exif_remove, ve, NULL); VIPS_FREEF(g_slist_free, ve->to_remove); } static void vips_exif_update(ExifData *ed, VipsImage *image) { VipsExifRemove ve; VIPS_DEBUG_MSG("vips_exif_update: \n"); /* If this exif came from the image (rather than being an exif block we * have made afresh), then any fields which are in the block but not on * the image must have been deliberately removed. Remove them from the * block as well. * * Any string-valued fields (eg. comment etc.) which exist as libvips * metadata tags with changed whose values have changed must also be * removed. * * libexif does not allow you to change string lengths (you must make * new tags) so we have to remove ready to re-add. */ if (vips_image_get_typeof(image, VIPS_META_EXIF_NAME)) { ve.image = image; ve.ed = ed; exif_data_foreach_content(ed, (ExifDataForeachContentFunc) vips_exif_exif_content, &ve); } /* Walk the image and add any exif- that's set in image metadata. */ vips_image_map(image, vips_exif_image_field, ed); } /* Examine the metadata tags on the image and update the EXIF block. */ int vips__exif_update(VipsImage *image) { unsigned char *data; size_t length; unsigned int idl; ExifData *ed; /* Either parse from the embedded EXIF, or if there's none, make * some fresh EXIF we can write the resolution to. */ if (vips_image_get_typeof(image, VIPS_META_EXIF_NAME)) { if (vips_image_get_blob(image, VIPS_META_EXIF_NAME, (void *) &data, &length)) return -1; if (!(ed = vips_exif_load_data_without_fix(data, length))) return -1; } else { ed = exif_data_new(); exif_data_set_option(ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); exif_data_set_data_type(ed, EXIF_DATA_TYPE_COMPRESSED); exif_data_set_byte_order(ed, EXIF_BYTE_ORDER_INTEL); } /* Make sure all required fields are there before we attach the vips * metadata. */ exif_data_fix(ed); /* Update EXIF tags from the image metadata. */ vips_exif_update(ed, image); /* Update EXIF resolution from the vips image header. */ if (vips_exif_resolution_from_image(ed, image)) { exif_data_free(ed); return -1; } /* Update EXIF image dimensions from the vips image header. */ if (vips_exif_set_dimensions(ed, image)) { exif_data_free(ed); return -1; } /* Update EXIF orientation from the vips image header. */ if (vips_exif_set_orientation(ed, image)) { exif_data_free(ed); return -1; } /* Update the thumbnail. */ if (vips_exif_set_thumbnail(ed, image)) { exif_data_free(ed); return -1; } /* Reserialise and write. exif_data_save_data() returns an int for some * reason. */ exif_data_save_data(ed, &data, &idl); if (!idl) { vips_error("exif", "%s", _("error saving EXIF")); exif_data_free(ed); return -1; } length = idl; #ifdef DEBUG printf("vips__exif_update: generated %zd bytes of EXIF\n", length); #endif /*DEBUG*/ vips_image_set_blob(image, VIPS_META_EXIF_NAME, (VipsCallbackFn) vips_area_free_cb, data, length); exif_data_free(ed); return 0; } #else /*!HAVE_EXIF*/ int vips__exif_parse(VipsImage *image) { return 0; } int vips__exif_update(VipsImage *image) { return 0; } #endif /*!HAVE_EXIF*/ libvips-8.18.2/libvips/foreign/fits.c000066400000000000000000000441001516303661500175010ustar00rootroot00000000000000/* Read FITS files with cfitsio * * 26/10/10 * - from matlab.c * 27/10/10 * - oops, forgot to init status in close * 30/11/10 * - set RGB16/GREY16 if appropriate * - allow up to 10 dimensions as long as they are empty * 27/1/11 * - lazy read * 31/1/11 * - read in planes and combine with im_bandjoin() * - read whole tiles with fits_read_subset() when we can * 17/3/11 * - renames, updates etc. ready for adding fits write * - fits write! * 21/3/11 * - read/write metadata as whole records to avoid changing things * - cast input to a supported format * - bandsplit for write * 13/12/11 * - redo as a set of fns ready for wrapping in a new-style class * 23/6/13 * - fix ushort save with values >32k, thanks weaverwb * 4/1/17 * - load to equivalent data type, not raw image data type ... improves * support for BSCALE / BZERO settings * 17/1/17 * - invalidate operation on read error * 26/1/17 aferrero2707 * - use fits_open_diskfile(), not fits_open_file() ... we don't want the * extended filename syntax * 15/4/17 * - skip HDUs with zero dimensions, thanks benepo * 27/10/22 * - band interleave ourselves on read * - don't duplicate metadata * 6/1/23 ewelot * - save mono images as NAXIS=2 * 18/1/23 ewelot * - dedupe header fields */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_CFITSIO #include #include #include #include #include #include #include #include "pforeign.h" /* vips only supports 3 dimensions, but we allow up to MAX_DIMENSIONS as long * as the higher dimensions are all empty. If you change this value, change * fits2vips_get_header() as well. */ #define MAX_DIMENSIONS (10) /* What we track during a cfitsio-file read or write. */ typedef struct { char *filename; VipsImage *image; fitsfile *fptr; int datatype; int naxis; long long int naxes[MAX_DIMENSIONS]; GMutex lock; /* Lock fits_*() calls with this */ /* One line of pels ready for scatter/gather. */ VipsPel *line; /* All the lines or part lines we've written so we can dedupe * metadata. */ GSList *dedupe; } VipsFits; const char *vips__fits_suffs[] = { ".fits", ".fit", ".fts", NULL }; static void vips_fits_error(int status) { char buf[80]; fits_get_errstatus(status, buf); vips_error("fits", "%s", buf); } /* Shut down. Can be called many times. */ static void vips_fits_close(VipsFits *fits) { VIPS_FREE(fits->filename); if (fits->line) g_mutex_clear(&fits->lock); VIPS_FREEF(vips_slist_free_all, fits->dedupe); if (fits->fptr) { int status; status = 0; if (fits_close_file(fits->fptr, &status)) vips_fits_error(status); fits->fptr = NULL; } VIPS_FREE(fits->line); } static void vips_fits_close_cb(VipsImage *image, VipsFits *fits) { vips_fits_close(fits); } static VipsFits * vips_fits_new_read(const char *filename, VipsImage *out) { VipsFits *fits; int status; if (!(fits = VIPS_NEW(out, VipsFits))) return NULL; fits->filename = vips_strdup(NULL, filename); fits->image = out; fits->fptr = NULL; g_mutex_init(&fits->lock); fits->line = NULL; g_signal_connect(out, "close", G_CALLBACK(vips_fits_close_cb), fits); status = 0; if (fits_open_diskfile(&fits->fptr, filename, READONLY, &status)) { vips_error("fits", _("unable to open \"%s\""), filename); vips_fits_error(status); return NULL; } return fits; } /* fits image types -> VIPS band formats. VIPS doesn't have 64-bit int, so no * entry for LONGLONG_IMG (64). */ static int fits2vips_formats[][3] = { { BYTE_IMG, VIPS_FORMAT_UCHAR, TBYTE }, { SHORT_IMG, VIPS_FORMAT_SHORT, TSHORT }, { USHORT_IMG, VIPS_FORMAT_USHORT, TUSHORT }, { LONG_IMG, VIPS_FORMAT_INT, TINT }, { ULONG_IMG, VIPS_FORMAT_UINT, TUINT }, { FLOAT_IMG, VIPS_FORMAT_FLOAT, TFLOAT }, { DOUBLE_IMG, VIPS_FORMAT_DOUBLE, TDOUBLE } }; static int vips_fits_get_header(VipsFits *fits, VipsImage *out) { int status; int bitpix; int width, height, bands; VipsBandFormat format; VipsInterpretation interpretation; int keysexist; int i; status = 0; /* Some FITS images have the first HDU for extra metadata ... skip * forward until we find a header unit we can load as an image. */ for (;;) { if (fits_get_img_paramll(fits->fptr, 10, &bitpix, &fits->naxis, fits->naxes, &status)) { vips_fits_error(status); return -1; } if (fits->naxis > 0) break; if (fits_movrel_hdu(fits->fptr, 1, NULL, &status)) { vips_fits_error(status); vips_error("fits", "%s", _("no HDU found with naxes > 0")); return -1; } } /* cfitsio does automatic conversion from the format stored in * the file to the equivalent type after scale/offset. We need * to allocate a vips image of the equivalent type, not the original * type. */ if (fits_get_img_equivtype(fits->fptr, &bitpix, &status)) { vips_fits_error(status); return -1; } #ifdef VIPS_DEBUG VIPS_DEBUG_MSG("naxis = %d\n", fits->naxis); for (i = 0; i < fits->naxis; i++) VIPS_DEBUG_MSG("%d) %lld\n", i, fits->naxes[i]); VIPS_DEBUG_MSG("fits2vips: bitpix = %d\n", bitpix); #endif /*VIPS_DEBUG*/ height = 1; bands = 1; switch (fits->naxis) { /* If you add more dimensions here, adjust data read below. See also * the definition of MAX_DIMENSIONS above. */ case 10: case 9: case 8: case 7: case 6: case 5: case 4: for (i = fits->naxis; i > 3; i--) if (fits->naxes[i - 1] != 1) { vips_error("fits", "%s", _("dimensions above 3 must be size 1")); return -1; } case 3: bands = fits->naxes[2]; case 2: height = fits->naxes[1]; case 1: width = fits->naxes[0]; break; default: vips_error("fits", _("bad number of axis %d"), fits->naxis); return -1; } /* Get image format. This is the equivalent format, or the format * stored in the file. */ for (i = 0; i < VIPS_NUMBER(fits2vips_formats); i++) if (fits2vips_formats[i][0] == bitpix) break; if (i == VIPS_NUMBER(fits2vips_formats)) { vips_error("fits", _("unsupported bitpix %d\n"), bitpix); return -1; } format = fits2vips_formats[i][1]; fits->datatype = fits2vips_formats[i][2]; if (bands == 1) { if (format == VIPS_FORMAT_USHORT) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_B_W; } else if (bands == 3) { if (format == VIPS_FORMAT_USHORT) interpretation = VIPS_INTERPRETATION_RGB16; else interpretation = VIPS_INTERPRETATION_sRGB; } else interpretation = VIPS_INTERPRETATION_MULTIBAND; vips_image_init_fields(out, width, height, bands, format, VIPS_CODING_NONE, interpretation, 1.0, 1.0); /* We read in lines, so SMALLTILE ends up being too small. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_FATSTRIP, NULL)) return -1; /* We need to be able to hold one scanline of one band for * scatter/gather. */ if (!(fits->line = VIPS_ARRAY(NULL, VIPS_IMAGE_SIZEOF_ELEMENT(out) * out->Xsize, VipsPel))) return -1; /* Read all keys into meta. */ if (fits_get_hdrspace(fits->fptr, &keysexist, NULL, &status)) { vips_fits_error(status); return -1; } for (i = 0; i < keysexist; i++) { char record[81]; char vipsname[100]; if (fits_read_record(fits->fptr, i + 1, record, &status)) { vips_fits_error(status); return -1; } VIPS_DEBUG_MSG("fits2vips: setting meta on vips image:\n"); VIPS_DEBUG_MSG(" record == \"%s\"\n", record); /* FITS lets keys repeat. For example, HISTORY appears many * times, each time with a fresh line of history attached. We * have to include the key index in the vips name we assign. */ g_snprintf(vipsname, 100, "fits-%d", i); vips_image_set_string(out, vipsname, record); } return 0; } int vips__fits_read_header(const char *filename, VipsImage *out) { VipsFits *fits; VIPS_DEBUG_MSG("fits2vips_header: reading \"%s\"\n", filename); if (!(fits = vips_fits_new_read(filename, out))) return -1; if (vips_fits_get_header(fits, out)) { vips_fits_close(fits); return -1; } vips_fits_close(fits); return 0; } static int vips_fits_read_subset(VipsFits *fits, long *fpixel, long *lpixel, long *inc, VipsPel *q) { int status; /* We must zero this or fits_read_subset() fails. */ status = 0; /* Break on ffgsv() for this call. */ if (fits_read_subset(fits->fptr, fits->datatype, fpixel, lpixel, inc, NULL, q, NULL, &status)) { vips_fits_error(status); vips_foreign_load_invalidate(fits->image); return -1; } return 0; } #define SCATTER(TYPE) \ { \ TYPE *tp = (TYPE *) p; \ TYPE *tq = ((TYPE *) q) + band; \ \ for (int x = 0; x < width; x++) { \ *tq = tp[x]; \ tq += bands; \ } \ } static void vips_fits_scatter(VipsFits *fits, VipsPel *q, VipsPel *p, int width, int band) { int bands = fits->image->Bands; switch (fits->image->BandFmt) { case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_CHAR: SCATTER(guchar); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: SCATTER(gushort); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: case VIPS_FORMAT_FLOAT: SCATTER(guint); break; case VIPS_FORMAT_DOUBLE: SCATTER(double); break; default: g_assert_not_reached(); } } static int vips_fits_generate(VipsRegion *out, void *seq, void *a, void *b, gboolean *stop) { VipsFits *fits = (VipsFits *) a; VipsRect *r = &out->valid; VIPS_DEBUG_MSG("fits2vips_generate: " "generating left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); vips__worker_lock(&fits->lock); for (int w = 0; w < out->im->Bands; w++) { for (int y = r->top; y < VIPS_RECT_BOTTOM(r); y++) { long fpixel[MAX_DIMENSIONS]; long lpixel[MAX_DIMENSIONS]; long inc[MAX_DIMENSIONS]; for (int z = 0; z < MAX_DIMENSIONS; z++) fpixel[z] = 1; fpixel[0] = r->left + 1; fpixel[1] = y + 1; fpixel[2] = w + 1; for (int z = 0; z < MAX_DIMENSIONS; z++) lpixel[z] = 1; lpixel[0] = VIPS_RECT_RIGHT(r); lpixel[1] = y + 1; lpixel[2] = w + 1; for (int z = 0; z < MAX_DIMENSIONS; z++) inc[z] = 1; /* We're inside a lock, so it's OK to write to ->line. */ if (vips_fits_read_subset(fits, fpixel, lpixel, inc, fits->line)) { g_mutex_unlock(&fits->lock); return -1; } vips_fits_scatter(fits, VIPS_REGION_ADDR(out, r->left, y), fits->line, r->width, w); } } g_mutex_unlock(&fits->lock); return 0; } int vips__fits_read(const char *filename, VipsImage *out) { VipsFits *fits; if (!(fits = vips_fits_new_read(filename, out))) return -1; if (vips_fits_get_header(fits, out) || vips_image_generate(out, NULL, vips_fits_generate, NULL, fits, NULL)) { vips_fits_close(fits); return -1; } return 0; } int vips__fits_isfits(const char *filename) { fitsfile *fptr; int status; VIPS_DEBUG_MSG("isfits: testing \"%s\"\n", filename); status = 0; if (fits_open_diskfile(&fptr, filename, READONLY, &status)) { VIPS_DEBUG_MSG("isfits: error reading \"%s\"\n", filename); #ifdef VIPS_DEBUG vips_fits_error(status); VIPS_DEBUG_MSG("isfits: %s\n", vips_error_buffer()); #endif /*VIPS_DEBUG*/ return 0; } fits_close_file(fptr, &status); return 1; } static VipsFits * vips_fits_new_write(VipsImage *in, const char *filename) { VipsFits *fits; int status; status = 0; if (!(fits = VIPS_NEW(in, VipsFits))) return NULL; fits->filename = vips_strdup(VIPS_OBJECT(in), filename); fits->image = in; fits->fptr = NULL; g_mutex_init(&fits->lock); fits->line = NULL; g_signal_connect(in, "close", G_CALLBACK(vips_fits_close_cb), fits); if (!(fits->filename = vips_strdup(NULL, filename))) return NULL; /* We need to be able to hold one scanline of one band. */ if (!(fits->line = VIPS_ARRAY(NULL, VIPS_IMAGE_SIZEOF_ELEMENT(in) * in->Xsize, VipsPel))) return NULL; /* fits_create_file() will fail if there's a file of that name, unless * we put a "!" in front of the filename. This breaks conventions with * the rest of vips, so just unlink explicitly. */ g_unlink(filename); if (fits_create_file(&fits->fptr, filename, &status)) { vips_error("fits", _("unable to write to \"%s\""), filename); vips_fits_error(status); return NULL; } return fits; } /* Header fields which cfitsio 4.1 writes for us start like this. It'll use * BZERO and BSCALE for 16- and 32-bit signed data. */ const char *vips_fits_basic[] = { "SIMPLE ", "BITPIX ", "NAXIS ", "NAXIS1 ", "NAXIS2 ", "NAXIS3 ", "EXTEND ", "BZERO ", "BSCALE ", "COMMENT FITS (Flexible Image Transport System) format", "COMMENT and Astrophysics', volume 376, page 359; bibcode:", // may be present in a multi HDU file, but not allowed in a single HDU // file "XTENSION", "PCOUNT ", "GCOUNT ", }; /* Header fields which can be duplicated start like this. */ const char *vips_fits_duplicate[] = { " ", "COMMENT ", "HISTORY ", "CONTINUE", }; /* Write a line of header text. Lines can be eg.: * * "EXTEND = T / FITS dataset may contain extensions" * "COMMENT FITS (Flexible Image Transport System) format is defined * "" * * - always left justified * - keyword is always 8 characters, right padded with spaces * - "= ", if present, is cols 9 and 10 * - lines are variable length, can be zero length for blank lines */ static int vips_fits_write_record(VipsFits *fits, const char *line) { char keyword[9]; int i; GSList *p; int status; VIPS_DEBUG_MSG("vips_fits_write_record: %s\n", line); /* cfitsio writes lines like these for us, don't write them again. */ for (i = 0; i < VIPS_NUMBER(vips_fits_basic); i++) if (vips_isprefix(vips_fits_basic[i], line)) return 0; /* Dedupe on the keyword, with some exceptions (see below). */ g_strlcpy(keyword, line, 9); for (p = fits->dedupe; p; p = p->next) { const char *written = (const char *) p->data; if (strcmp(keyword, written) == 0) return 0; } status = 0; if (fits_write_record(fits->fptr, line, &status)) { vips_fits_error(status); return -1; } /* Add this keyword to the dedupe list if it's not on the allowed * dupe table, or a blank line. */ if (strcmp(line, "") != 0) { for (i = 0; i < VIPS_NUMBER(vips_fits_duplicate); i++) if (vips_isprefix(vips_fits_duplicate[i], keyword)) break; if (i == VIPS_NUMBER(vips_fits_duplicate)) fits->dedupe = g_slist_prepend(fits->dedupe, g_strdup(keyword)); } return 0; } static void * vips_fits_write_meta(VipsImage *image, const char *field, GValue *value, void *a) { VipsFits *fits = (VipsFits *) a; const char *value_str; /* We want fields which start "fits-". */ if (!vips_isprefix("fits-", field)) return NULL; /* The value should be a refstring, since we wrote it in fits2vips * above ^^. */ value_str = vips_value_get_ref_string(value, NULL); if (vips_fits_write_record(fits, value_str)) return a; return NULL; } static int vips_fits_set_header(VipsFits *fits, VipsImage *in) { int status; int bitpix; int i; status = 0; fits->naxis = in->Bands == 1 ? 2 : 3; fits->naxes[0] = in->Xsize; fits->naxes[1] = in->Ysize; fits->naxes[2] = in->Bands; for (i = 0; i < VIPS_NUMBER(fits2vips_formats); i++) if (fits2vips_formats[i][1] == in->BandFmt) break; if (i == VIPS_NUMBER(fits2vips_formats)) { vips_error("fits", _("unsupported BandFmt %d\n"), in->BandFmt); return -1; } bitpix = fits2vips_formats[i][0]; fits->datatype = fits2vips_formats[i][2]; #ifdef VIPS_DEBUG VIPS_DEBUG_MSG("naxis = %d\n", fits->naxis); for (i = 0; i < fits->naxis; i++) VIPS_DEBUG_MSG("%d) %lld\n", i, fits->naxes[i]); VIPS_DEBUG_MSG("bitpix = %d\n", bitpix); #endif /*VIPS_DEBUG*/ if (fits_create_imgll(fits->fptr, bitpix, fits->naxis, fits->naxes, &status)) { vips_fits_error(status); return -1; } if (vips_image_map(in, (VipsImageMapFn) vips_fits_write_meta, fits)) return -1; return 0; } static int vips_fits_write(VipsRegion *region, VipsRect *area, void *a) { VipsFits *fits = (VipsFits *) a; VipsImage *image = fits->image; int es = VIPS_IMAGE_SIZEOF_ELEMENT(image); int ps = VIPS_IMAGE_SIZEOF_PEL(image); int status; int y, b, x, k; status = 0; VIPS_DEBUG_MSG("vips_fits_write: " "writing left = %d, top = %d, width = %d, height = %d\n", area->left, area->top, area->width, area->height); /* We need to write a band at a time. We can't bandsplit in vips, * since vips_sink_disc() can't loop over many images at once, sadly. */ for (y = 0; y < area->height; y++) { VipsPel *p = VIPS_REGION_ADDR(region, area->left, area->top + y); for (b = 0; b < image->Bands; b++) { VipsPel *p1, *q; long fpixel[3]; p1 = p + b * es; q = fits->line; for (x = 0; x < area->width; x++) { for (k = 0; k < es; k++) q[k] = p1[k]; q += es; p1 += ps; } fpixel[0] = area->left + 1; fpixel[1] = area->top + y + 1; fpixel[2] = b + 1; /* No need to lock, write functions are single-threaded. */ if (fits_write_pix(fits->fptr, fits->datatype, fpixel, area->width, fits->line, &status)) { vips_fits_error(status); return -1; } } } return 0; } int vips__fits_write(VipsImage *in, const char *filename) { VipsFits *fits; VIPS_DEBUG_MSG("vips2fits: writing \"%s\"\n", filename); if (!(fits = vips_fits_new_write(in, filename))) return -1; if (vips_fits_set_header(fits, fits->image) || vips_sink_disc(fits->image, vips_fits_write, fits)) { vips_fits_close(fits); return -1; } vips_fits_close(fits); return 0; } #endif /*HAVE_CFITSIO*/ libvips-8.18.2/libvips/foreign/fitsload.c000066400000000000000000000234021516303661500203430ustar00rootroot00000000000000/* load fits from a file * * 5/12/11 * - from openslideload.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_CFITSIO #include "pforeign.h" typedef struct _VipsForeignLoadFits { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Filename from source. */ const char *filename; } VipsForeignLoadFits; typedef VipsForeignLoadClass VipsForeignLoadFitsClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadFits, vips_foreign_load_fits, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_fits_dispose(GObject *gobject) { VipsForeignLoadFits *fits = (VipsForeignLoadFits *) gobject; VIPS_UNREF(fits->source); G_OBJECT_CLASS(vips_foreign_load_fits_parent_class)->dispose(gobject); } static int vips_foreign_load_fits_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignLoadFits *fits = (VipsForeignLoadFits *) object; /* We can only open sources which have an associated filename, since * the fits library works in terms of filenames. */ if (fits->source) { VipsConnection *connection = VIPS_CONNECTION(fits->source); const char *filename; if (!vips_source_is_file(fits->source) || !(filename = vips_connection_filename(connection))) { vips_error(class->nickname, "%s", _("no filename available")); return -1; } fits->filename = filename; } return VIPS_OBJECT_CLASS(vips_foreign_load_fits_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_fits_get_flags_source(VipsSource *source) { return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_fits_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_fits_get_flags_filename(const char *filename) { VipsSource *source; VipsForeignFlags flags; if (!(source = vips_source_new_from_file(filename))) return 0; flags = vips_foreign_load_fits_get_flags_source(source); VIPS_UNREF(source); return flags; } static int vips_foreign_load_fits_header(VipsForeignLoad *load) { VipsForeignLoadFits *fits = (VipsForeignLoadFits *) load; if (vips__fits_read_header(fits->filename, load->out)) return -1; VIPS_SETSTR(load->out->filename, fits->filename); return 0; } static int vips_foreign_load_fits_load(VipsForeignLoad *load) { VipsForeignLoadFits *fits = (VipsForeignLoadFits *) load; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(fits), 2); t[0] = vips_image_new(); if (vips__fits_read(fits->filename, t[0]) || vips_flip(t[0], &t[1], VIPS_DIRECTION_VERTICAL, NULL) || vips_image_write(t[1], load->real)) return -1; return 0; } static void vips_foreign_load_fits_class_init(VipsForeignLoadFitsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_fits_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "fitsload_base"; object_class->description = _("FITS loader base class"); object_class->build = vips_foreign_load_fits_build; /* cfitsio has not been fuzzed, so should not be used with * untrusted input unless you are very careful. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; load_class->get_flags_filename = vips_foreign_load_fits_get_flags_filename; load_class->get_flags = vips_foreign_load_fits_get_flags; load_class->is_a = vips__fits_isfits; load_class->header = vips_foreign_load_fits_header; load_class->load = vips_foreign_load_fits_load; } static void vips_foreign_load_fits_init(VipsForeignLoadFits *fits) { } typedef struct _VipsForeignLoadFitsFile { VipsForeignLoadFits parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadFitsFile; typedef VipsForeignLoadFitsClass VipsForeignLoadFitsFileClass; G_DEFINE_TYPE(VipsForeignLoadFitsFile, vips_foreign_load_fits_file, vips_foreign_load_fits_get_type()); static int vips_foreign_load_fits_file_build(VipsObject *object) { VipsForeignLoadFits *fits = (VipsForeignLoadFits *) object; VipsForeignLoadFitsFile *file = (VipsForeignLoadFitsFile *) object; if (file->filename && !(fits->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_fits_file_parent_class) ->build(object); } static void vips_foreign_load_fits_file_class_init(VipsForeignLoadFitsFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "fitsload"; object_class->description = _("load a FITS image"); object_class->build = vips_foreign_load_fits_file_build; foreign_class->suffs = vips__fits_suffs; load_class->is_a = vips__fits_isfits; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadFitsFile, filename), NULL); } static void vips_foreign_load_fits_file_init(VipsForeignLoadFitsFile *file) { } typedef struct _VipsForeignLoadFitsSource { VipsForeignLoadFits parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadFitsSource; typedef VipsForeignLoadFitsClass VipsForeignLoadFitsSourceClass; G_DEFINE_TYPE(VipsForeignLoadFitsSource, vips_foreign_load_fits_source, vips_foreign_load_fits_get_type()); static int vips_foreign_load_fits_source_build(VipsObject *object) { VipsForeignLoadFits *fits = (VipsForeignLoadFits *) object; VipsForeignLoadFitsSource *source = (VipsForeignLoadFitsSource *) object; if (source->source) { fits->source = source->source; g_object_ref(fits->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_fits_source_parent_class) ->build(object); } static gboolean vips_foreign_load_fits_source_is_a_source(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); const char *filename; return vips_source_is_file(source) && (filename = vips_connection_filename(connection)) && vips__fits_isfits(filename); } static void vips_foreign_load_fits_source_class_init( VipsForeignLoadFitsSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "fitsload_source"; object_class->description = _("load FITS from a source"); object_class->build = vips_foreign_load_fits_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_fits_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadFitsSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_fits_source_init(VipsForeignLoadFitsSource *fits) { } #endif /*HAVE_CFITSIO*/ /** * vips_fitsload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a FITS image file into a VIPS image. * * This operation can read images with up to three dimensions. Any higher * dimensions must be empty. * * It can read 8, 16 and 32-bit integer images, signed and unsigned, float and * double. * * FITS metadata is attached with the "fits-" prefix. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_fitsload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("fitsload", ap, filename, out); va_end(ap); return result; } /** * vips_fitsload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.fitsload], but read from a source. * * Returns: 0 on success, -1 on error. */ int vips_fitsload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("fitsload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/fitssave.c000066400000000000000000000107651516303661500203720ustar00rootroot00000000000000/* save to fits * * 2/12/11 * - wrap a class around the fits writer * 2/7/14 * - cache the image before write so we are sequential */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef HAVE_CFITSIO #include "pforeign.h" typedef struct _VipsForeignSaveFits { VipsForeignSave parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveFits; typedef VipsForeignSaveClass VipsForeignSaveFitsClass; G_DEFINE_TYPE(VipsForeignSaveFits, vips_foreign_save_fits, VIPS_TYPE_FOREIGN_SAVE); static int vips_foreign_save_fits_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveFits *fits = (VipsForeignSaveFits *) object; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(fits), 2); if (VIPS_OBJECT_CLASS(vips_foreign_save_fits_parent_class)->build(object)) return -1; /* FITS is written bottom-to-top, so we must flip. * * But all vips readers must work top-to-bottom (or vips_copy()'s seq * hint won't work) so we must cache the input image. * * We cache to RAM, but perhaps we should use something like * vips_get_disc_threshold() and copy to a tempfile. */ t[0] = vips_image_new_memory(); if (vips_image_write(save->ready, t[0]) || vips_flip(t[0], &t[1], VIPS_DIRECTION_VERTICAL, NULL) || vips__fits_write(t[1], fits->filename)) return -1; return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat bandfmt_fits[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, UI, UI, F, X, D, DX }; static void vips_foreign_save_fits_class_init(VipsForeignSaveFitsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "fitssave"; object_class->description = _("save image to fits file"); object_class->build = vips_foreign_save_fits_build; /* cfitsio has not been fuzzed, so should not be used with * untrusted input unless you are very careful. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips__fits_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->format_table = bandfmt_fits; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveFits, filename), NULL); } static void vips_foreign_save_fits_init(VipsForeignSaveFits *fits) { } #endif /*HAVE_CFITSIO*/ /** * vips_fitssave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file in FITS format. * * ::: seealso * [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_fitssave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("fitssave", ap, in, filename); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/foreign.c000066400000000000000000002701711516303661500201760ustar00rootroot00000000000000/* foreign file formats base class * * 7/2/12 * - add support for sequential reads * 18/6/12 * - flatten alpha with vips_flatten() * 28/5/13 * - auto rshift down to 8 bits during save * 19/1/14 * - pack and unpack rad to scrgb * 18/8/14 * - fix conversion to 16-bit RGB, thanks John * 18/6/15 * - forward progress signals from load * 23/5/16 * - remove max-alpha stuff, this is now automatic * 12/6/17 * - transform cmyk->rgb if there's an embedded profile * 16/6/17 * - add page_height * 1/1/18 * - META_SEQ support moved here * 5/3/18 * - block _start if one start fails, see #893 * 1/4/18 * - drop incompatible ICC profiles before save * 24/7/21 * - add fail_on */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pforeign.h" /** * VipsForeign: * * An abstract base class to load and save images in a variety of formats. * * ## Load and save * * You can load and save from and to files, memory areas, and the libvips IO * abstractions, [class@Source] and [class@Target]. * * Use [func@Foreign.find_load] [func@Foreign.find_load_buffer] and * [func@Foreign.find_load_source] to find a loader for an object. Use * [func@Foreign.find_save], [func@Foreign.find_save_buffer] and * [func@Foreign.find_save_target] to find a saver for a format. You can then * run these operations using [func@call] and friends to perform the load or * save. * * [method@Image.write_to_file] and [ctor@Image.new_from_file] and friends use * these functions to automate file load and save. * * You can also invoke the operations directly, for example: * * ```c * vips_tiffsave(my_image, "frank.anything", * "compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, * NULL); * ``` * * ## Image metadata * * All loaders attach all image metadata as libvips properties on load. * * You can change metadata with [method@Image.set_int] and friends. * * During save, you can use `keep` to specify which metadata to retain, * defaults to all, see [flags@ForeignKeep]. Setting `profile` will * automatically keep the ICC profile. * * ## Many page images * * By default, libvips will only load the first page of many page or animated * images. Use `page` and `n` to set the start page and the number of pages to * load. Set `n` to -1 to load all pages. * * Many page images are loaded as a tall, thin strip of pages. * * Use [method@Image.get_page_height] and [method@Image.get_n_pages] to find * the page height and number of pages of a loaded image. * * Use `page_height` to set the page height for image save. * * ## Alpha save * * Not all image formats support alpha. If you try to save an image with an * alpha channel to a format that does not support it, the alpha will be * automatically flattened out. Use `background` (default 0) to set the colour * that alpha should be flattened against. * * ## Adding new formats * * To add support for a new file format to vips, simply define a new subclass * of [class@ForeignLoad] or [class@ForeignSave]. * * If you define a new operation which is a subclass of [class@Foreign], * support for it automatically appears in all libvips user-interfaces. It * will also be transparently supported by [ctor@Image.new_from_file] and * friends. */ /** * VipsForeignLoad: * * An abstract base class to load images in a variety of formats. * * ## Writing a new loader * * Add a new loader to libvips by subclassing [class@ForeignLoad]. Subclasses * need to implement at least [vfunc@ForeignLoad.header]. * * [vfunc@ForeignLoad.header] must set at least the header fields of `out`. * [vfunc@ForeignLoad.load], if defined, must load the pixels to `real`. * * The suffix list is used to select a format to save a file in, and to pick a * loader if you don't define [func@Foreign.is_a]. * * You should also define [property@Object:nickname] and * [property@Object:description] in [class@Object]. * * As a complete example, here's code for a PNG loader, minus the actual * calls to libpng. * * ```c * typedef struct _VipsForeignLoadPng { * VipsForeignLoad parent_object; * * char *filename; * } VipsForeignLoadPng; * * typedef VipsForeignLoadClass VipsForeignLoadPngClass; * * G_DEFINE_TYPE(VipsForeignLoadPng, vips_foreign_load_png, * VIPS_TYPE_FOREIGN_LOAD); * * static VipsForeignFlags * vips_foreign_load_png_get_flags_filename(const char *filename) * { * VipsForeignFlags flags; * * flags = 0; * if (vips__png_isinterlaced(filename)) * flags = VIPS_FOREIGN_PARTIAL; * else * flags = VIPS_FOREIGN_SEQUENTIAL; * * return flags; * } * * static VipsForeignFlags * vips_foreign_load_png_get_flags(VipsForeignLoad *load) * { * VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; * * return vips_foreign_load_png_get_flags_filename(png->filename); * } * * static int * vips_foreign_load_png_header(VipsForeignLoad *load) * { * VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; * * if (vips__png_header(png->filename, load->out)) * return -1; * * return 0; * } * * static int * vips_foreign_load_png_load(VipsForeignLoad *load) * { * VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; * * if (vips__png_read(png->filename, load->real)) * return -1; * * return 0; * } * * static void * vips_foreign_load_png_class_init(VipsForeignLoadPngClass *class) * { * GObjectClass *gobject_class = G_OBJECT_CLASS(class); * VipsObjectClass *object_class = (VipsObjectClass *) class; * VipsForeignClass *foreign_class = (VipsForeignClass *) class; * VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; * * gobject_class->set_property = vips_object_set_property; * gobject_class->get_property = vips_object_get_property; * * object_class->nickname = "pngload"; * object_class->description = _("load png from file"); * * foreign_class->suffs = vips__png_suffs; * * load_class->is_a = vips__png_ispng; * load_class->get_flags_filename = * vips_foreign_load_png_get_flags_filename; * load_class->get_flags = vips_foreign_load_png_get_flags; * load_class->header = vips_foreign_load_png_header; * load_class->load = vips_foreign_load_png_load; * * VIPS_ARG_STRING(class, "filename", 1, * _("Filename"), * _("Filename to load from"), * VIPS_ARGUMENT_REQUIRED_INPUT, * G_STRUCT_OFFSET(VipsForeignLoadPng, filename), * NULL); * } * * static void * vips_foreign_load_png_init(VipsForeignLoadPng *png) * { * } * ``` */ /** * VipsForeignSave: * * An abstract base class to save images in a variety of formats. * * ## Writing a new saver * * Call your saver in the class' [vfunc@Object.build] method after chaining up. * The prepared image should be ready for you to save in `ready`. * * As a complete example, here's the code for the CSV saver, minus the calls * to the actual save routines. * * ```c * typedef struct _VipsForeignSaveCsv { * VipsForeignSave parent_object; * * char *filename; * const char *separator; * } VipsForeignSaveCsv; * * typedef VipsForeignSaveClass VipsForeignSaveCsvClass; * * G_DEFINE_TYPE(VipsForeignSaveCsv, vips_foreign_save_csv, * VIPS_TYPE_FOREIGN_SAVE); * * static int * vips_foreign_save_csv_build(VipsObject *object) * { * VipsForeignSave *save = (VipsForeignSave *) object; * VipsForeignSaveCsv *csv = (VipsForeignSaveCsv *) object; * * if (VIPS_OBJECT_CLASS(vips_foreign_save_csv_parent_class) * ->build(object)) * return -1; * * if (vips__csv_write(save->ready, csv->filename, csv->separator)) * return -1; * * return 0; * } * * static void * vips_foreign_save_csv_class_init(VipsForeignSaveCsvClass *class) * { * GObjectClass *gobject_class = G_OBJECT_CLASS(class); * VipsObjectClass *object_class = (VipsObjectClass *) class; * VipsForeignClass *foreign_class = (VipsForeignClass *) class; * VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; * * gobject_class->set_property = vips_object_set_property; * gobject_class->get_property = vips_object_get_property; * * object_class->nickname = "csvsave"; * object_class->description = _("save image to csv file"); * object_class->build = vips_foreign_save_csv_build; * * foreign_class->suffs = vips__foreign_csv_suffs; * * save_class->saveable = VIPS_FOREIGN_SAVEABLE_MONO; * // no need to define ->format_table, we don't want the input * // cast for us * * VIPS_ARG_STRING(class, "filename", 1, * _("Filename"), * _("Filename to save to"), * VIPS_ARGUMENT_REQUIRED_INPUT, * G_STRUCT_OFFSET(VipsForeignSaveCsv, filename), * NULL); * * VIPS_ARG_STRING(class, "separator", 13, * _("Separator"), * _("Separator characters"), * VIPS_ARGUMENT_OPTIONAL_INPUT, * G_STRUCT_OFFSET(VipsForeignSaveCsv, separator), * "\t"); * } * * static void * vips_foreign_save_csv_init(VipsForeignSaveCsv *csv) * { * csv->separator = g_strdup("\t"); * } * ``` */ /* Use this to link images to the load operation that made them. */ static GQuark vips__foreign_load_operation = 0; /** * VipsForeignFlags: * @VIPS_FOREIGN_NONE: no flags set * @VIPS_FOREIGN_PARTIAL: the image may be read lazilly * @VIPS_FOREIGN_BIGENDIAN: image pixels are most-significant byte first * @VIPS_FOREIGN_SEQUENTIAL: top-to-bottom lazy reading * * Some hints about the image loader. * * [flags@Vips.ForeignFlags.PARTIAL] means that the image can be read directly * from the file without needing to be unpacked to a temporary image first. * * [flags@Vips.ForeignFlags.SEQUENTIAL] means that the loader supports lazy * reading, but only top-to-bottom (sequential) access. Formats like PNG can * read sets of scanlines, for example, but only in order. * * If neither PARTIAL or SEQUENTIAL is set, the loader only supports whole * image read. Setting both PARTIAL and SEQUENTIAL is an error. * * [flags@Vips.ForeignFlags.BIGENDIAN] means that image pixels are * most-significant byte first. Depending on the native byte order of the * host machine, you may need to swap bytes. See [method@Image.copy]. */ G_DEFINE_ABSTRACT_TYPE(VipsForeign, vips_foreign, VIPS_TYPE_OPERATION); static void vips_foreign_summary_class(VipsObjectClass *object_class, VipsBuf *buf) { VipsForeignClass *class = VIPS_FOREIGN_CLASS(object_class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(object_class); VIPS_OBJECT_CLASS(vips_foreign_parent_class) ->summary_class(object_class, buf); if (class->suffs) { const char **p; vips_buf_appends(buf, " ("); for (p = class->suffs; *p; p++) { vips_buf_appendf(buf, "%s", *p); if (p[1]) vips_buf_appends(buf, ", "); } vips_buf_appends(buf, ")"); } vips_buf_appendf(buf, ", priority=%d", class->priority); if (operation_class->flags & VIPS_OPERATION_UNTRUSTED) vips_buf_appendf(buf, ", untrusted"); if (operation_class->flags & VIPS_OPERATION_BLOCKED) vips_buf_appendf(buf, ", blocked"); } static void vips_foreign_class_init(VipsForeignClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "foreign"; object_class->description = _("load and save image files"); object_class->summary_class = vips_foreign_summary_class; } static void vips_foreign_init(VipsForeign *object) { } /* To iterate over supported files we build a temp list of subclasses of * VipsForeign, sort by priority, iterate, and free. */ static void * file_add_class(VipsForeignClass *class, GSList **files) { VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); // don't consider blocked classes ... we don't want eg. sniffers to run if (operation_class->flags & VIPS_OPERATION_BLOCKED) return NULL; // exclude "rawload" as it has a different API. if (vips_isprefix("rawload", VIPS_OBJECT_CLASS(class)->nickname)) return NULL; /* Append so we don't reverse the list of files. Sort will * not reorder items of equal priority. */ *files = g_slist_append(*files, class); return NULL; } static gint file_compare(VipsForeignClass *a, VipsForeignClass *b, void *user_data) { return b->priority - a->priority; } /** * vips_foreign_map: * @base: base class to search below (eg. "VipsForeignLoad") * @fn: (scope call): function to apply to each [class@Foreign] * @a: user data * @b: user data * * Apply a function to every [class@Foreign] that VIPS knows about. Foreigns * are presented to the function in priority order. * * Like all VIPS map functions, if @fn returns `NULL`, iteration continues. If * it returns non-`NULL`, iteration terminates and that value is returned. The * map function returns `NULL` if all calls return `NULL`. * * ::: seealso * [func@slist_map2]. * * Returns: (transfer none): the result of iteration */ void * vips_foreign_map(const char *base, VipsSListMap2Fn fn, void *a, void *b) { GSList *files; void *result; files = NULL; (void) vips_class_map_all(g_type_from_name(base), (VipsClassMapFn) file_add_class, (void *) &files); files = g_slist_sort(files, (GCompareFunc) file_compare); #ifdef DEBUG { GSList *p; printf("vips_foreign_map: search order\n"); for (p = files; p; p = p->next) { VipsForeignClass *class = (VipsForeignClass *) p->data; printf("\t%s\n", VIPS_OBJECT_CLASS(class)->nickname); } } #endif /*DEBUG*/ result = vips_slist_map2(files, fn, a, b); g_slist_free(files); return result; } /* Abstract base class for image load. */ G_DEFINE_ABSTRACT_TYPE(VipsForeignLoad, vips_foreign_load, VIPS_TYPE_FOREIGN); static void vips_foreign_load_dispose(GObject *gobject) { VipsForeignLoad *load = VIPS_FOREIGN_LOAD(gobject); VIPS_UNREF(load->real); G_OBJECT_CLASS(vips_foreign_load_parent_class)->dispose(gobject); } static void vips_foreign_load_summary_class(VipsObjectClass *object_class, VipsBuf *buf) { VipsForeignLoadClass *class = VIPS_FOREIGN_LOAD_CLASS(object_class); VIPS_OBJECT_CLASS(vips_foreign_load_parent_class) ->summary_class(object_class, buf); if (!G_TYPE_IS_ABSTRACT(G_TYPE_FROM_CLASS(class))) { if (class->is_a) vips_buf_appends(buf, ", is_a"); if (class->is_a_buffer) vips_buf_appends(buf, ", is_a_buffer"); if (class->is_a_source) vips_buf_appends(buf, ", is_a_source"); if (class->get_flags) vips_buf_appends(buf, ", get_flags"); if (class->get_flags_filename) vips_buf_appends(buf, ", get_flags_filename"); if (class->header) vips_buf_appends(buf, ", header"); if (class->load) vips_buf_appends(buf, ", load"); /* You can omit ->load(), you must not omit ->header(). */ g_assert(class->header); } } /* Can this VipsForeign open this file? */ static void * vips_foreign_find_load_sub(VipsForeignLoadClass *load_class, const char *filename, void *b) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(load_class); VipsForeignClass *class = VIPS_FOREIGN_CLASS(load_class); /* Ignore the buffer and source loaders. */ if (g_str_has_suffix(object_class->nickname, "_buffer") || g_str_has_suffix(object_class->nickname, "_source")) return NULL; #ifdef DEBUG printf("vips_foreign_find_load_sub: %s\n", VIPS_OBJECT_CLASS(class)->nickname); #endif /*DEBUG*/ /* Try to sniff the filetype from the first few bytes, if we can, * otherwise fall back to checking the filename suffix. */ if (load_class->is_a) { if (load_class->is_a(filename)) return load_class; #ifdef DEBUG printf("vips_foreign_find_load_sub: is_a failed\n"); #endif /*DEBUG*/ } else if (class->suffs) { if (vips_filename_suffix_match(filename, class->suffs)) return load_class; } else g_warning("loader %s has no is_a method and no suffix list", object_class->nickname); return NULL; } /** * vips_foreign_find_load: * @filename: file to find a loader for * * Searches for an operation you could use to load @filename. Any trailing * options on @filename are stripped and ignored. * * ::: seealso * [func@Foreign.find_load_buffer], [ctor@Image.new_from_file]. * * Returns: the name of an operation on success, `NULL` on error */ const char * vips_foreign_find_load(const char *name) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; VipsForeignLoadClass *load_class; vips__filename_split8(name, filename, option_string); /* Very common, so make a better error message for this case. */ if (!vips_existsf("%s", filename)) { vips_error("VipsForeignLoad", _("file \"%s\" does not exist"), name); return NULL; } if (vips_isdirf("%s", filename)) { vips_error("VipsForeignLoad", _("\"%s\" is a directory"), name); return NULL; } if (!(load_class = (VipsForeignLoadClass *) vips_foreign_map( "VipsForeignLoad", (VipsSListMap2Fn) vips_foreign_find_load_sub, (void *) filename, NULL))) { vips_error("VipsForeignLoad", _("\"%s\" is not a known file format"), name); return NULL; } #ifdef DEBUG printf("vips_foreign_find_load: selected %s\n", VIPS_OBJECT_CLASS(load_class)->nickname); #endif /*DEBUG*/ return G_OBJECT_CLASS_NAME(load_class); } /* Kept for compat with earlier version of the vip8 API. Use * vips_image_new_from_file() now. */ int vips_foreign_load(const char *name, VipsImage **out, ...) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; va_list ap; int result; vips__filename_split8(name, filename, option_string); if (!(operation_name = vips_foreign_find_load(filename))) return -1; va_start(ap, out); result = vips_call_split_option_string(operation_name, option_string, ap, filename, out); va_end(ap); return result; } /* Can this VipsForeign open this buffer? */ static void * vips_foreign_find_load_buffer_sub(VipsForeignLoadClass *load_class, const void **buf, size_t *len) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(load_class); /* Skip non-buffer loaders. */ if (!g_str_has_suffix(object_class->nickname, "_buffer")) return NULL; if (load_class->is_a_buffer) { if (load_class->is_a_buffer(*buf, *len)) return load_class; } else g_warning("loader %s has no is_a_buffer method", object_class->nickname); return NULL; } /** * vips_foreign_find_load_buffer: * @data: (array length=size) (element-type guint8) (transfer none): start of * memory buffer * @size: (type gsize): number of bytes in @data * * Searches for an operation you could use to load a memory buffer. To see the * range of buffer loaders supported by your vips, try something like: * * vips -l | grep load_buffer * * ::: seealso * [ctor@Image.new_from_buffer]. * * Returns: (transfer none): the name of an operation on success, `NULL` on * error. */ const char * vips_foreign_find_load_buffer(const void *data, size_t size) { VipsForeignLoadClass *load_class; if (!(load_class = (VipsForeignLoadClass *) vips_foreign_map( "VipsForeignLoad", (VipsSListMap2Fn) vips_foreign_find_load_buffer_sub, &data, &size))) { vips_error("VipsForeignLoad", "%s", _("buffer is not in a known format")); return NULL; } return G_OBJECT_CLASS_NAME(load_class); } /* Can this VipsForeign open this source? */ static void * vips_foreign_find_load_source_sub(void *item, void *a, void *b) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(item); VipsForeignLoadClass *load_class = VIPS_FOREIGN_LOAD_CLASS(item); VipsSource *source = VIPS_SOURCE(a); /* Skip non-source loaders. */ if (!g_str_has_suffix(object_class->nickname, "_source")) return NULL; if (load_class->is_a_source) { /* We may have done a _read() rather than a _sniff() in one of * the is_a testers. Always rewind. */ (void) vips_source_rewind(source); if (load_class->is_a_source(source)) return load_class; } else g_warning("loader %s has no is_a_source method", object_class->nickname); return NULL; } /** * vips_foreign_find_load_source: * @source: source to load from * * Searches for an operation you could use to load a source. To see the * range of source loaders supported by your vips, try something like: * * vips -l | grep load_source * * ::: seealso * [ctor@Image.new_from_source]. * * Returns: (transfer none): the name of an operation on success, `NULL` on * error. */ const char * vips_foreign_find_load_source(VipsSource *source) { VipsForeignLoadClass *load_class; if (!(load_class = (VipsForeignLoadClass *) vips_foreign_map( "VipsForeignLoad", vips_foreign_find_load_source_sub, source, NULL))) { vips_error("VipsForeignLoad", "%s", _("source is not in a known format")); return NULL; } return G_OBJECT_CLASS_NAME(load_class); } /** * vips_foreign_is_a: * @loader: name of loader to use for test * @filename: file to test * * Return `TRUE` if @filename can be loaded by @loader. @loader is something * like "tiffload" or "VipsForeignLoadTiff". * * Returns: `TRUE` if @filename can be loaded by @loader. */ gboolean vips_foreign_is_a(const char *loader, const char *filename) { const VipsObjectClass *class; VipsForeignLoadClass *load_class; if (!(class = vips_class_find("VipsForeignLoad", loader))) return FALSE; load_class = VIPS_FOREIGN_LOAD_CLASS(class); if (load_class->is_a && load_class->is_a(filename)) return TRUE; return FALSE; } /** * vips_foreign_is_a_buffer: * @loader: name of loader to use for test * @data: (array length=size) (element-type guint8): pointer to the buffer to test * @size: (type gsize): size of the buffer to test * * Return `TRUE` if @data can be loaded by @loader. @loader is something * like "tiffload_buffer" or "VipsForeignLoadTiffBuffer". * * Returns: `TRUE` if @data can be loaded by @loader. */ gboolean vips_foreign_is_a_buffer(const char *loader, const void *data, size_t size) { const VipsObjectClass *class; VipsForeignLoadClass *load_class; if (!(class = vips_class_find("VipsForeignLoad", loader))) return FALSE; load_class = VIPS_FOREIGN_LOAD_CLASS(class); if (load_class->is_a_buffer && load_class->is_a_buffer(data, size)) return TRUE; return FALSE; } /** * vips_foreign_is_a_source: * @loader: name of loader to use for test * @source: source to test * * Return `TRUE` if @source can be loaded by @loader. @loader is something * like "tiffload_source" or "VipsForeignLoadTiffSource". * * Returns: `TRUE` if @data can be loaded by @source. */ gboolean vips_foreign_is_a_source(const char *loader, VipsSource *source) { const VipsObjectClass *class; VipsForeignLoadClass *load_class; if (!(class = vips_class_find("VipsForeignLoad", loader))) return FALSE; load_class = VIPS_FOREIGN_LOAD_CLASS(class); if (load_class->is_a_source && load_class->is_a_source(source)) return TRUE; return FALSE; } /** * vips_foreign_flags: * @loader: name of loader to use for test * @filename: file to test * * Return the flags for @filename using @loader. * @loader is something like "tiffload" or "VipsForeignLoadTiff". * * Returns: the flags for @filename. */ VipsForeignFlags vips_foreign_flags(const char *loader, const char *filename) { const VipsObjectClass *class; if ((class = vips_class_find("VipsForeignLoad", loader))) { VipsForeignLoadClass *load_class = VIPS_FOREIGN_LOAD_CLASS(class); if (load_class->get_flags_filename) return load_class->get_flags_filename(filename); } return 0; } static VipsObject * vips_foreign_load_new_from_string(const char *string) { const char *file_op; GType type; VipsForeignLoad *load; if (!(file_op = vips_foreign_find_load(string))) return NULL; type = g_type_from_name(file_op); g_assert(type); load = VIPS_FOREIGN_LOAD(g_object_new(type, NULL)); g_object_set(load, "filename", string, NULL); return VIPS_OBJECT(load); } static VipsImage * vips_foreign_load_temp(VipsForeignLoad *load) { const guint64 disc_threshold = vips_get_disc_threshold(); const guint64 image_size = VIPS_IMAGE_SIZEOF_IMAGE(load->out); /* ->memory used to be called ->disc and default TRUE. If it's been * forced FALSE, set memory TRUE. */ if (!load->disc) load->memory = TRUE; if (load->memory) { #ifdef DEBUG printf("vips_foreign_load_temp: forced memory temp\n"); #endif /*DEBUG*/ return vips_image_new_memory(); } /* If this is a partial operation, we can open directly. */ if (load->flags & VIPS_FOREIGN_PARTIAL) { #ifdef DEBUG printf("vips_foreign_load_temp: partial temp\n"); #endif /*DEBUG*/ return vips_image_new(); } /* If it can do sequential access and it's been requested, we can open * directly. */ if ((load->flags & VIPS_FOREIGN_SEQUENTIAL) && load->access != VIPS_ACCESS_RANDOM) { #ifdef DEBUG printf("vips_foreign_load_temp: partial sequential temp\n"); #endif /*DEBUG*/ return vips_image_new(); } /* We open via disc if the uncompressed image will be larger than * vips_get_disc_threshold(). */ if (image_size > disc_threshold) { #ifdef DEBUG printf("vips_foreign_load_temp: disc temp\n"); #endif /*DEBUG*/ return vips_image_new_temp_file("%s.v"); } #ifdef DEBUG printf("vips_foreign_load_temp: fallback memory temp\n"); #endif /*DEBUG*/ /* Otherwise, fall back to a memory buffer. */ return vips_image_new_memory(); } /* Check two images for compatibility: their geometries need to match. */ static gboolean vips_foreign_load_iscompat(VipsForeignLoad *load, VipsImage *image) { if (load->real->Xsize != image->Xsize || load->real->Ysize != image->Ysize || load->real->Bands != image->Bands || load->real->Coding != image->Coding || load->real->BandFmt != image->BandFmt) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); vips_error(class->nickname, "%s", _("images do not match between header and load")); return FALSE; } return TRUE; } /* Our start function ... do the lazy open, if necessary, and return a region * on the new image. */ static void * vips_foreign_load_start(VipsImage *out, void *a, void *b) { VipsForeignLoad *load = VIPS_FOREIGN_LOAD(b); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadClass *load_class = VIPS_FOREIGN_LOAD_CLASS(class); /* If this start has failed before, either in another thread or in an * earlier load, we can fail now. */ if (load->error) { /* We must set an error, since failing without an error message could * confuse our caller. */ vips_error(class->nickname, "%s", _("load error")); return NULL; } if (!load->real) { if (!(load->real = vips_foreign_load_temp(load))) return NULL; #ifdef DEBUG printf("vips_foreign_load_start: triggering ->load\n"); #endif /*DEBUG*/ /* Read the image in. This may involve a long computation and * will finish with load->real holding the decompressed image. * * We want our caller to be able to see this computation on * @out, so eval signals on ->real need to appear on ->out. */ load->real->progress_signal = load->out; /* Note the load object on the image. Loaders can use * this to signal invalidate if they hit a load error. See * vips_foreign_load_invalidate() below. */ g_object_set_qdata(G_OBJECT(load->real), vips__foreign_load_operation, load); /* Load the image and check the result. * * ->header() read the header into @out, load will read the * image into @real. They must match exactly in size, bands, * format and coding for the copy to work. * * Some versions of ImageMagick give different results between * Ping and Load for some formats, for example. * * If the load fails, we need to stop. */ if (load_class->load(load) || !vips_object_sanity(VIPS_OBJECT(load->real)) || vips_image_pio_input(load->real) || !vips_foreign_load_iscompat(load, out)) { vips_operation_invalidate(VIPS_OPERATION(load)); load->error = TRUE; return NULL; } /* We have to tell vips that out depends on real. We've set * the demand hint below, but not given an input there. */ if (vips_image_pipelinev(load->out, load->out->dhint, load->real, NULL)) return NULL; } return vips_region_new(load->real); } /* Just pointer-copy. */ static int vips_foreign_load_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; /* Ask for input we need. */ if (vips_region_prepare(ir, r)) return -1; /* Attach output region to that. */ if (vips_region_region(out_region, ir, r, r->left, r->top)) return -1; return 0; } static int vips_foreign_load_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignLoad *load = VIPS_FOREIGN_LOAD(object); VipsForeignLoadClass *fclass = VIPS_FOREIGN_LOAD_GET_CLASS(object); VipsForeignFlags flags; #ifdef DEBUG printf("vips_foreign_load_build:\n"); #endif /*DEBUG*/ flags = 0; if (fclass->get_flags) flags |= fclass->get_flags(load); if ((flags & VIPS_FOREIGN_PARTIAL) && (flags & VIPS_FOREIGN_SEQUENTIAL)) { g_warning("VIPS_FOREIGN_PARTIAL and VIPS_FOREIGN_SEQUENTIAL " "both set -- using SEQUENTIAL"); flags ^= VIPS_FOREIGN_PARTIAL; } g_object_set(load, "flags", flags, NULL); /* We must block caching of seq loaders running in seq mode. A seq * loader in random mode is fine, since we'll read to ram or a temp * file. */ if ((load->flags & VIPS_FOREIGN_SEQUENTIAL) && load->access != VIPS_ACCESS_RANDOM) load->nocache = TRUE; /* The deprecated "fail" field sets fail_on warning. */ if (vips_object_argument_isset(object, "fail") && !vips_object_argument_isset(object, "fail_on")) load->fail_on = load->fail ? VIPS_FAIL_ON_WARNING : VIPS_FAIL_ON_NONE; if (VIPS_OBJECT_CLASS(vips_foreign_load_parent_class)->build(object)) return -1; if (load->sequential) g_warning("ignoring deprecated \"sequential\" mode -- " "please use \"access\" instead"); g_object_set(object, "out", vips_image_new(), NULL); vips_image_set_string(load->out, VIPS_META_LOADER, class->nickname); #ifdef DEBUG printf("vips_foreign_load_build: triggering ->header\n"); #endif /*DEBUG*/ /* Read the header into @out. */ if (fclass->header) { if (fclass->header(load) || !vips_object_sanity(VIPS_OBJECT(load->out))) return -1; } /* If there's no ->load() method then the header read has done * everything. Otherwise, it's just set fields and we must also * load pixels. * * Delay the load until the first pixel is requested by doing the work * in the start function of the copy. */ if (fclass->load) { #ifdef DEBUG printf("vips_foreign_load_build: delaying read ...\n"); #endif /*DEBUG*/ /* ->header() should set the dhint. It'll default to the safe * SMALLTILE if header() did not set it. */ if (vips_image_pipelinev(load->out, load->out->dhint, NULL)) return -1; /* Then 'start' creates the real image and 'gen' fetches * pixels for @out from @real on demand. */ if (vips_image_generate(load->out, vips_foreign_load_start, vips_foreign_load_generate, vips_stop_one, NULL, load)) return -1; } /* Tell downstream if seq mode was requested. */ if (load->access != VIPS_ACCESS_RANDOM) vips_image_set_int(load->out, VIPS_META_SEQUENTIAL, 1); return 0; } static VipsOperationFlags vips_foreign_load_operation_get_flags(VipsOperation *operation) { VipsForeignLoad *load = VIPS_FOREIGN_LOAD(operation); VipsOperationFlags flags; flags = VIPS_OPERATION_CLASS(vips_foreign_load_parent_class) ->get_flags(operation); if (load->nocache) flags |= VIPS_OPERATION_NOCACHE; if (load->revalidate) flags |= VIPS_OPERATION_REVALIDATE; return flags; } static void vips_foreign_load_class_init(VipsForeignLoadClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; gobject_class->dispose = vips_foreign_load_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->build = vips_foreign_load_build; object_class->summary_class = vips_foreign_load_summary_class; object_class->new_from_string = vips_foreign_load_new_from_string; object_class->nickname = "load"; object_class->description = _("loaders"); operation_class->get_flags = vips_foreign_load_operation_get_flags; VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignLoad, out)); VIPS_ARG_FLAGS(class, "flags", 106, _("Flags"), _("Flags for this file"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsForeignLoad, flags), VIPS_TYPE_FOREIGN_FLAGS, VIPS_FOREIGN_NONE); VIPS_ARG_BOOL(class, "memory", 107, _("Memory"), _("Force open via memory"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoad, memory), FALSE); VIPS_ARG_ENUM(class, "access", 108, _("Access"), _("Required access pattern for this file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoad, access), VIPS_TYPE_ACCESS, VIPS_ACCESS_RANDOM); VIPS_ARG_ENUM(class, "fail_on", 109, _("Fail on"), _("Error level to fail on"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoad, fail_on), VIPS_TYPE_FAIL_ON, VIPS_FAIL_ON_NONE); VIPS_ARG_BOOL(class, "revalidate", 110, _("Revalidate"), _("Don't use a cached result for this operation"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_NON_HASHABLE, G_STRUCT_OFFSET(VipsForeignLoad, revalidate), FALSE); VIPS_ARG_BOOL(class, "sequential", 111, _("Sequential"), _("Sequential read only"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoad, sequential), FALSE); VIPS_ARG_BOOL(class, "fail", 112, _("Fail"), _("Fail on first warning"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoad, fail), FALSE); VIPS_ARG_BOOL(class, "disc", 113, _("Disc"), _("Open to disc"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoad, disc), TRUE); } static void vips_foreign_load_init(VipsForeignLoad *load) { load->disc = TRUE; load->access = VIPS_ACCESS_RANDOM; load->fail_on = VIPS_FAIL_ON_NONE; } /* * Loaders can call this */ /** * vips_foreign_load_invalidate: (method) * @image: image to invalidate * * Loaders can call this on the image they are making if they see a read error * from the load library. It signals "invalidate" on the load operation and * will cause it to be dropped from cache. * * If we know a file will cause a read error, we don't want to cache the * failing operation, we want to make sure the image will really be opened * again if our caller tries again. For example, a broken file might be * replaced by a working one. */ void vips_foreign_load_invalidate(VipsImage *image) { VipsOperation *operation; #ifdef DEBUG printf("vips_foreign_load_invalidate: %p\n", image); #endif /*DEBUG*/ if ((operation = g_object_get_qdata(G_OBJECT(image), vips__foreign_load_operation))) { vips_operation_invalidate(operation); } } /* Abstract base class for image savers. */ G_DEFINE_ABSTRACT_TYPE(VipsForeignSave, vips_foreign_save, VIPS_TYPE_FOREIGN); static void vips_foreign_save_dispose(GObject *gobject) { VipsForeignSave *save = VIPS_FOREIGN_SAVE(gobject); VIPS_UNREF(save->ready); G_OBJECT_CLASS(vips_foreign_save_parent_class)->dispose(gobject); } static void vips_foreign_save_summary_class(VipsObjectClass *object_class, VipsBuf *buf) { VipsForeignSaveClass *class = VIPS_FOREIGN_SAVE_CLASS(object_class); VIPS_OBJECT_CLASS(vips_foreign_save_parent_class) ->summary_class(object_class, buf); GValue value = { 0 }; g_value_init(&value, VIPS_TYPE_FOREIGN_SAVEABLE); g_value_set_flags(&value, class->saveable); vips_buf_appends(buf, ", "); vips_buf_appendgv(buf, &value); g_value_unset(&value); } static VipsObject * vips_foreign_save_new_from_string(const char *string) { const char *file_op; GType type; VipsForeignSave *save; if (!(file_op = vips_foreign_find_save(string))) return NULL; type = g_type_from_name(file_op); g_assert(type); save = VIPS_FOREIGN_SAVE(g_object_new(type, NULL)); g_object_set(save, "filename", string, NULL); return VIPS_OBJECT(save); } /* Apply a set of saveable flags. * * - unpack rad and labq * - if the saver supports mono and we have a mono-looking image, we are done * - if the saver supports CMYK and we have a CMYK-looking image, we are done * - if this is a CMYK-looking image, import to XYZ * - if the saver supports rgb, go to rgb * - if the saver supports cmyk, go to cmyk * - if the saver supports mono, go to mono * * we output 16 bit images if the source is 16 bits ... a later stage * uses the format[] table to cut this down to the size the saver wants */ static int vips_foreign_apply_saveable(VipsImage *in, VipsImage **ready, VipsForeignSaveable saveable) { // is this a 16-bit source image gboolean sixteenbit = in->BandFmt == VIPS_FORMAT_USHORT; VipsImage *out; VipsInterpretation interpretation; /* in holds a reference to the output of our chain as we build it. */ g_object_ref(in); /* ANY? we are done. */ if (saveable == VIPS_FOREIGN_SAVEABLE_ANY) { *ready = in; return 0; } /* If this is VIPS_CODING_LABQ, we can go straight to RGB. */ if (in->Coding == VIPS_CODING_LABQ) { if (vips_LabQ2sRGB(in, &out, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } /* If this is VIPS_CODING_RAD, we unpack to float. This could be * scRGB or XYZ. */ if (in->Coding == VIPS_CODING_RAD) { if (vips_rad2float(in, &out, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } /* If this is a mono-ish looking image and our saver supports mono, we * are done. We are not too strict about what a mono image is! We need to * work for things like "extract_band 1" on an RGB image. */ if ((saveable & VIPS_FOREIGN_SAVEABLE_MONO) && in->Bands < 3) { *ready = in; return 0; } /* CMYK image? Use the sanity-checked interpretation value. */ if (vips_image_guess_interpretation(in) == VIPS_INTERPRETATION_CMYK && in->Bands >= 4) { /* If our saver supports CMYK we are done, otherwise import to XYZ. */ if (saveable & VIPS_FOREIGN_SAVEABLE_CMYK) { *ready = in; return 0; } if (vips_icc_import(in, &out, "pcs", VIPS_PCS_XYZ, "embedded", TRUE, "input_profile", "cmyk", NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } /* If the saver supports RGB, go to RGB, or RGB16 if this is a ushort * source. */ if (saveable & VIPS_FOREIGN_SAVEABLE_RGB) { interpretation = sixteenbit ? VIPS_INTERPRETATION_RGB16 : VIPS_INTERPRETATION_sRGB; if (vips_colourspace(in, &out, interpretation, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; *ready = in; return 0; } /* If the saver supports CMYK, go to CMYK, 16 bits if this is a ushort * source. */ if (saveable & VIPS_FOREIGN_SAVEABLE_CMYK) { if (vips_icc_export(in, &out, "output-profile", "cmyk", "depth", sixteenbit ? 16 : 8, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; *ready = in; return 0; } /* If the saver supports mono, go to B_W, or GREY16 if this is a ushort * source. */ if (saveable & VIPS_FOREIGN_SAVEABLE_MONO) { interpretation = sixteenbit ? VIPS_INTERPRETATION_GREY16 : VIPS_INTERPRETATION_B_W; if (vips_colourspace(in, &out, interpretation, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; *ready = in; return 0; } vips_error("VipsForeignSave", _("saver does not support any output type")); return -1; } /* Do all the colourspace conversions to get an image ready for saving. Don't * finalize alpha or numeric format. */ int vips__foreign_convert_saveable(VipsImage *in, VipsImage **ready, VipsForeignSaveable saveable, VipsBandFormat *format, VipsForeignCoding coding, VipsArrayDouble *background) { VipsImage *out; /* in holds a reference to the output of our chain as we build it. */ g_object_ref(in); g_assert(format); /* For coded images, can this class save the coding we are in now? * Nothing to do. */ if ((in->Coding == VIPS_CODING_LABQ && (coding & VIPS_FOREIGN_CODING_LABQ)) || (in->Coding == VIPS_CODING_RAD && (coding & VIPS_FOREIGN_CODING_RAD))) { *ready = in; return 0; } /* For uncoded images, if this saver supports ANY and this * format, we have nothing to do. */ if (in->Coding == VIPS_CODING_NONE && (saveable == VIPS_FOREIGN_SAVEABLE_ANY) && format[in->BandFmt] == in->BandFmt) { *ready = in; return 0; } /* Otherwise ... we need to decode and then (possibly) recode at the * end. */ /* Apply saveable conversions to get mono/rgb/cmyk. */ if (vips_foreign_apply_saveable(in, &out, saveable)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; /* Flatten alpha, if the saver does not support it. */ if (in->Coding == VIPS_CODING_NONE && vips_image_hasalpha(in) && !(saveable & VIPS_FOREIGN_SAVEABLE_ALPHA)) { if (vips_flatten(in, &out, "background", background, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } /* There might be more than one alpha ... drop any remaining excess * bands. */ if (in->Coding == VIPS_CODING_NONE) { // use a sanity-checked interpretation VipsInterpretation interpretation = vips_image_guess_interpretation(in); int bands; bands = vips_interpretation_bands(interpretation); if (saveable == VIPS_FOREIGN_SAVEABLE_ANY) bands = in->Bands; else if (saveable & VIPS_FOREIGN_SAVEABLE_ALPHA) bands += 1; if (bands > 0 && in->Bands > bands) { if (vips_extract_band(in, &out, 0, "n", bands, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } } /* Convert to the format the saver likes. */ if (in->Coding == VIPS_CODING_NONE) { /* If the saver does not support 16-bit output, automatically * shift it down. This is the behaviour we want for saving an * RGB16 image as JPEG, for example. */ gboolean needs_shift = !vips_band_format_is8bit(in->BandFmt) && vips_band_format_is8bit(format[in->BandFmt]); if (vips_cast(in, &out, format[in->BandFmt], "shift", needs_shift, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } /* Does this class want a coded image? */ if ((in->Coding == VIPS_CODING_NONE && (coding & VIPS_FOREIGN_CODING_NONE)) || (in->Coding == VIPS_CODING_LABQ && (coding & VIPS_FOREIGN_CODING_LABQ)) || (in->Coding == VIPS_CODING_RAD && (coding & VIPS_FOREIGN_CODING_RAD))) { /* Already there, nothing to do. */ } else if (coding & VIPS_FOREIGN_CODING_LABQ) { if (vips_Lab2LabQ(in, &out, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } else if (coding & VIPS_FOREIGN_CODING_RAD) { if (vips_float2rad(in, &out, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } else if (coding & VIPS_FOREIGN_CODING_NONE) { if (vips_image_decode(in, &out)) { g_object_unref(in); return -1; } g_object_unref(in); in = out; } *ready = in; return 0; } /* What VipsKeep does a metadata item belong to? * * Return 0 (KEEP_NONE) for never remove, ie. an unrecognised field, or * one which is used to control saver behaviour, like "delay" or * "orientation". */ static VipsForeignKeep vips_foreign_get_keep(const char *field) { if (g_str_equal(field, VIPS_META_EXIF_NAME) || // derived from exif vips_isprefix("exif-", field) || // also comes from exif vips_isprefix("jpeg-thumbnail-data", field)) return VIPS_FOREIGN_KEEP_EXIF; if (g_str_equal(field, VIPS_META_XMP_NAME)) return VIPS_FOREIGN_KEEP_XMP; if (g_str_equal(field, VIPS_META_IPTC_NAME)) return VIPS_FOREIGN_KEEP_IPTC; if (g_str_equal(field, VIPS_META_ICC_NAME)) return VIPS_FOREIGN_KEEP_ICC; if (vips_isprefix("gainmap", field)) return VIPS_FOREIGN_KEEP_GAINMAP; /* OTHER is a metadata item that: * * - one or more savers will write to a format * - is optional * - is not used to control saver behaviour */ if (vips_isprefix("png-comment-", field) || g_str_equal(field, VIPS_META_IMAGEDESCRIPTION) || g_str_equal(field, VIPS_META_PHOTOSHOP_NAME) || vips_isprefix("magickprofile-", field) || vips_isprefix("magick-", field)) return VIPS_FOREIGN_KEEP_OTHER; return 0; } static void * vips_foreign_save_remove_metadata(VipsImage *image, const char *field, GValue *value, void *user_data) { VipsForeignKeep keep_mask = *((VipsForeignKeep *) user_data); VipsForeignKeep keep_field = vips_foreign_get_keep(field); if (keep_field && !(keep_mask & keep_field)) vips_image_remove(image, field); return NULL; } int vips__foreign_update_metadata(VipsImage *in, VipsForeignKeep keep) { /* Rebuild exif from tags, if we'll be saving it. */ if ((keep & VIPS_FOREIGN_KEEP_EXIF) && vips__exif_update(in)) return -1; /* Remove metadata, if any. */ if (keep != VIPS_FOREIGN_KEEP_ALL && vips_image_map(in, vips_foreign_save_remove_metadata, &keep)) return -1; /* Some format libraries, like libpng, will throw a hard error if the * profile is inappropriate for this image type. With profiles inherited * from a source image, this can happen all the time, so we * want to silently drop the profile in this case. */ if ((keep & VIPS_FOREIGN_KEEP_ICC) && vips_image_get_typeof(in, VIPS_META_ICC_NAME)) { const void *data; size_t length; if (!vips_image_get_blob(in, VIPS_META_ICC_NAME, &data, &length) && !vips_icc_is_compatible_profile(in, data, length) && !vips_image_remove(in, VIPS_META_ICC_NAME)) return -1; } return 0; } static int vips_foreign_save_build(VipsObject *object) { VipsForeignSave *save = VIPS_FOREIGN_SAVE(object); /* The deprecated "strip" field sets "keep" to none. */ if (vips_object_argument_isset(object, "strip") && !vips_object_argument_isset(object, "keep")) save->keep = save->strip ? VIPS_FOREIGN_KEEP_NONE : VIPS_FOREIGN_KEEP_ALL; /* Keep ICC profile by default when a user profile has been set. */ if ((save->keep & VIPS_FOREIGN_KEEP_ICC) == 0 && vips_object_argument_isset(object, "profile")) save->keep |= VIPS_FOREIGN_KEEP_ICC; if (save->in) { VipsForeignSaveClass *class = VIPS_FOREIGN_SAVE_GET_CLASS(save); VipsImage *ready; VipsImage *x; if (vips__foreign_convert_saveable(save->in, &ready, class->saveable, class->format_table, class->coding, save->background)) return -1; /* Updating metadata, need to copy the image. */ if (vips_copy(ready, &x, NULL)) { VIPS_UNREF(ready); return -1; } VIPS_UNREF(ready); ready = x; if (vips__foreign_update_metadata(ready, save->keep)) { VIPS_UNREF(ready); return -1; } if (save->page_height) vips_image_set_int(ready, VIPS_META_PAGE_HEIGHT, save->page_height); VIPS_UNREF(save->ready); save->ready = ready; } return VIPS_OBJECT_CLASS(vips_foreign_save_parent_class)->build(object); } #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat vips_foreign_save_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_foreign_save_class_init(VipsForeignSaveClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; gobject_class->dispose = vips_foreign_save_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->build = vips_foreign_save_build; object_class->summary_class = vips_foreign_save_summary_class; object_class->new_from_string = vips_foreign_save_new_from_string; object_class->nickname = "save"; object_class->description = _("savers"); /* All savers are sequential by definition. Things like tiled tiff * write and interlaced png write, which are not, add extra caches * on their input. */ operation_class->flags |= VIPS_OPERATION_SEQUENTIAL; /* Must not cache savers. */ operation_class->flags |= VIPS_OPERATION_NOCACHE; /* Default to no coding allowed. */ class->coding = VIPS_FOREIGN_CODING_NONE; /* Default to no cast on save. */ class->format_table = vips_foreign_save_format_table; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Image to save"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSave, in)); VIPS_ARG_FLAGS(class, "keep", 100, _("Keep"), _("Which metadata to retain"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSave, keep), VIPS_TYPE_FOREIGN_KEEP, VIPS_FOREIGN_KEEP_ALL); VIPS_ARG_BOXED(class, "background", 101, _("Background"), _("Background value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSave, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_INT(class, "page_height", 102, _("Page height"), _("Set page height for multipage save"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSave, page_height), 0, VIPS_MAX_COORD, 0); VIPS_ARG_STRING(class, "profile", 103, _("Profile"), _("Filename of ICC profile to embed"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSave, profile), NULL); VIPS_ARG_BOOL(class, "strip", 104, _("Strip"), _("Strip all metadata from image"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSave, strip), FALSE); } static void vips_foreign_save_init(VipsForeignSave *save) { save->keep = VIPS_FOREIGN_KEEP_ALL; save->background = vips_array_double_newv(1, 0.0); } /* Can we write this filename with this class? */ static void * vips_foreign_find_save_sub(VipsForeignSaveClass *save_class, const char *filename, void *b) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(save_class); VipsForeignClass *class = VIPS_FOREIGN_CLASS(save_class); const char **p; /* All savers needs suffs defined since we use the suff to pick the * saver. */ if (!class->suffs) { g_warning("no suffix defined for %s", object_class->nickname); return NULL; } /* Skip non-file savers. */ if (g_str_has_suffix(object_class->nickname, "_buffer") || g_str_has_suffix(object_class->nickname, "_target")) return NULL; /* vips_foreign_find_save() has already removed any options from the * end of the filename, so we can test directly against the suffix. */ for (p = class->suffs; *p; p++) if (vips_iscasepostfix(filename, *p)) return save_class; return NULL; } /** * vips_foreign_find_save: * @filename: name to find a saver for * * Searches for an operation you could use to write to @filename. * Any trailing options on @filename are stripped and ignored. * * ::: seealso * [func@Foreign.find_save_buffer], [method@Image.write_to_file]. * * Returns: (nullable): the name of an operation on success, `NULL` on error */ const char * vips_foreign_find_save(const char *name) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; VipsForeignSaveClass *save_class; vips__filename_split8(name, filename, option_string); if (!(save_class = (VipsForeignSaveClass *) vips_foreign_map( "VipsForeignSave", (VipsSListMap2Fn) vips_foreign_find_save_sub, (void *) filename, NULL))) { vips_error("VipsForeignSave", _("\"%s\" is not a known file format"), name); return NULL; } return G_OBJECT_CLASS_NAME(save_class); } static void * vips_foreign_get_suffixes_count_cb(VipsForeignSaveClass *save_class, void *a, void *b) { VipsForeignClass *foreign_class = VIPS_FOREIGN_CLASS(save_class); int *n_fields = (int *) a; int i; if (foreign_class->suffs) for (i = 0; foreign_class->suffs[i]; i++) *n_fields += 1; return NULL; } static void * vips_foreign_get_suffixes_add_cb(VipsForeignSaveClass *save_class, void *a, void *b) { VipsForeignClass *foreign_class = VIPS_FOREIGN_CLASS(save_class); gchar ***p = (gchar ***) a; int i; if (foreign_class->suffs) for (i = 0; foreign_class->suffs[i]; i++) { **p = g_strdup(foreign_class->suffs[i]); *p += 1; } return NULL; } /** * vips_foreign_get_suffixes: * * Get a `NULL`-terminated array listing all the supported suffixes. * * This is not the same as all the supported file types, since libvips * detects image format for load by testing the first few bytes. * * Use [func@Foreign.find_load] to detect type for a specific file. * * Free the return result with [func@GLib.strfreev]. * * Returns: (transfer full) (array): all supported file extensions, as a * `NULL`-terminated array. */ gchar ** vips_foreign_get_suffixes(void) { int n_suffs; gchar **suffs; gchar **p; n_suffs = 0; (void) vips_foreign_map( "VipsForeignSave", (VipsSListMap2Fn) vips_foreign_get_suffixes_count_cb, &n_suffs, NULL); suffs = g_new0(gchar *, n_suffs + 1); p = suffs; (void) vips_foreign_map( "VipsForeignSave", (VipsSListMap2Fn) vips_foreign_get_suffixes_add_cb, &p, NULL); return suffs; } /* Kept for early vips8 API compat. */ int vips_foreign_save(VipsImage *in, const char *name, ...) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; va_list ap; int result; vips__filename_split8(name, filename, option_string); if (!(operation_name = vips_foreign_find_save(filename))) return -1; va_start(ap, name); result = vips_call_split_option_string(operation_name, option_string, ap, in, filename); va_end(ap); return result; } /* Can this class write this filetype to a target? */ static void * vips_foreign_find_save_target_sub(VipsForeignSaveClass *save_class, const char *suffix, void *b) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(save_class); VipsForeignClass *class = VIPS_FOREIGN_CLASS(save_class); /* All concrete savers needs suffs, since we use the suff to pick the * saver. */ if (!G_TYPE_IS_ABSTRACT(G_TYPE_FROM_CLASS(class)) && !class->suffs) g_warning("no suffix defined for %s", object_class->nickname); if (!G_TYPE_IS_ABSTRACT(G_TYPE_FROM_CLASS(class)) && class->suffs && g_str_has_suffix(object_class->nickname, "_target") && vips_filename_suffix_match(suffix, class->suffs)) return save_class; return NULL; } /** * vips_foreign_find_save_target: * @suffix: format to find a saver for * * Searches for an operation you could use to write to a target in @suffix * format. * * ::: seealso * [method@Image.write_to_buffer]. * * Returns: (nullable): the name of an operation on success, `NULL` on error */ const char * vips_foreign_find_save_target(const char *name) { char suffix[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; VipsForeignSaveClass *save_class; vips__filename_split8(name, suffix, option_string); if (!(save_class = (VipsForeignSaveClass *) vips_foreign_map( "VipsForeignSave", (VipsSListMap2Fn) vips_foreign_find_save_target_sub, (void *) suffix, NULL))) { vips_error("VipsForeignSave", _("\"%s\" is not a known target format"), name); return NULL; } return G_OBJECT_CLASS_NAME(save_class); } /* Can we write this buffer with this file type? */ static void * vips_foreign_find_save_buffer_sub(VipsForeignSaveClass *save_class, const char *suffix, void *b) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(save_class); VipsForeignClass *class = VIPS_FOREIGN_CLASS(save_class); /* All concrete savers needs suffs, since we use the suff to pick the * saver. */ if (!G_TYPE_IS_ABSTRACT(G_TYPE_FROM_CLASS(class)) && !class->suffs) g_warning("no suffix defined for %s", object_class->nickname); if (!G_TYPE_IS_ABSTRACT(G_TYPE_FROM_CLASS(class)) && class->suffs && g_str_has_suffix(object_class->nickname, "_buffer") && vips_filename_suffix_match(suffix, class->suffs)) return save_class; return NULL; } /** * vips_foreign_find_save_buffer: * @suffix: name to find a saver for * * Searches for an operation you could use to write to a buffer in @suffix * format. * * ::: seealso * [method@Image.write_to_buffer]. * * Returns: (nullable): the name of an operation on success, `NULL` on error */ const char * vips_foreign_find_save_buffer(const char *name) { char suffix[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; VipsForeignSaveClass *save_class; vips__filename_split8(name, suffix, option_string); if (!(save_class = (VipsForeignSaveClass *) vips_foreign_map( "VipsForeignSave", (VipsSListMap2Fn) vips_foreign_find_save_buffer_sub, (void *) suffix, NULL))) { vips_error("VipsForeignSave", _("\"%s\" is not a known buffer format"), name); return NULL; } return G_OBJECT_CLASS_NAME(save_class); } /* C API wrappers for loadable modules go here. */ /** * vips_heifload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a HEIF image file into a VIPS image. * * Use @page to select a page to render, numbering from zero. If neither @n * nor @page are set, @page defaults to the primary page, otherwise to 0. * * Use @n to select the number of pages to render. The default is 1. Pages are * rendered in a vertical column. Set to -1 to mean "until the end of the * document". Use [method@Image.grid] to reorganise pages. * * HEIF images have a primary image. The metadata item `heif-primary` gives * the page number of the primary. * * If @thumbnail is `TRUE`, then fetch a stored thumbnail rather than the * image. * * By default, input image dimensions are limited to 16384x16384. * If @unlimited is `TRUE`, this increases to the maximum of 65535x65535. * * The bitdepth of the heic image is recorded in the metadata item * `heif-bitdepth`. * * ::: tip "Optional arguments" * * @page: `gint`, page (top-level image number) to read * * @n: `gint`, load this many pages * * @thumbnail: `gboolean`, fetch thumbnail instead of image * * @unlimited: `gboolean`, remove all denial of service limits * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_heifload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("heifload", ap, filename, out); va_end(ap); return result; } /** * vips_heifload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a HEIF image file into a VIPS image. * Exactly as [ctor@Image.heifload], but read from a memory buffer. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, page (top-level image number) to read * * @n: `gint`, load this many pages * * @thumbnail: `gboolean`, fetch thumbnail instead of image * * @unlimited: `gboolean`, remove all denial of service limits * * ::: seealso * [ctor@Image.heifload]. * * Returns: 0 on success, -1 on error. */ int vips_heifload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("heifload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_heifload_source: * @source: source to load from * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.heifload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, page (top-level image number) to read * * @n: `gint`, load this many pages * * @thumbnail: `gboolean`, fetch thumbnail instead of image * * @unlimited: `gboolean`, remove all denial of service limits * * ::: seealso * [ctor@Image.heifload]. * * Returns: 0 on success, -1 on error. */ int vips_heifload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("heifload_source", ap, source, out); va_end(ap); return result; } /** * vips_heifsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file in HEIF format. * * Use @Q to set the compression factor. Default 50, which seems to be roughly * what the iphone uses. Q 30 gives about the same quality as JPEG Q 75. * * Set @lossless `TRUE` to switch to lossless compression. * * Use @compression to set the compression format e.g. HEVC, AVC, AV1 to use. * It defaults to AV1 if the target filename ends with ".avif", otherwise HEVC. * * Use @effort to control the CPU effort spent improving compression. * This is currently only applicable to AV1 encoders. Defaults to 4, 0 is * fastest, 9 is slowest. * * Chroma subsampling is normally automatically disabled for Q >= 90. You can * force the subsampling mode with @subsample_mode. * * Use @bitdepth to set the bitdepth of the output file. HEIC supports at * least 8, 10 and 12 bits; other codecs may support more or fewer options. * * Use @encoder to set the encode library to use, e.g. aom, SVT-AV1, rav1e etc. * * Use @tune to pass a set of tuning parameters to the encoder, see the * libheif documentation. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @bitdepth: `gint`, set write bit depth to 8, 10, or 12 bits * * @lossless: `gboolean`, enable lossless encoding * * @compression: [enum@ForeignHeifCompression], write with this * compression * * @effort: `gint`, encoding effort * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @encoder: [enum@ForeignHeifEncoder], select encoder to use * * @tune: `gchararray`, encoder tuning parameters * * ::: seealso * [method@Image.write_to_file], [ctor@Image.heifload]. * * Returns: 0 on success, -1 on error. */ int vips_heifsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("heifsave", ap, in, filename); va_end(ap); return result; } /** * vips_heifsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.heifsave], but save to a memory buffer. * * The address of the buffer is returned in @obuf, the length of the buffer in * @olen. You are responsible for freeing the buffer with [func@GLib.free] * when you are done with it. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @bitdepth: `gint`, set write bit depth to 8, 10, or 12 bits * * @lossless: `gboolean`, enable lossless encoding * * @compression: [enum@ForeignHeifCompression], write with this * compression * * @effort: `gint`, encoding effort * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @encoder: [enum@ForeignHeifEncoder], select encoder to use * * @tune: `gchararray`, encoder tuning parameters * * ::: seealso * [method@Image.heifsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_heifsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("heifsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_heifsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.heifsave], but save to a target. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @bitdepth: `gint`, set write bit depth to 8, 10, or 12 bits * * @lossless: `gboolean`, enable lossless encoding * * @compression: [enum@ForeignHeifCompression], write with this * compression * * @effort: `gint`, encoding effort * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @encoder: [enum@ForeignHeifEncoder], select encoder to use * * @tune: `gchararray`, encoder tuning parameters * * ::: seealso * [method@Image.heifsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_heifsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("heifsave_target", ap, in, target); va_end(ap); return result; } /** * vips_jxlload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a JPEG-XL image. * * The JPEG-XL loader and saver are experimental features and may change * in future libvips versions. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_jxlload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("jxlload", ap, filename, out); va_end(ap); return result; } /** * vips_jxlload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.jxlload], but read from a buffer. * * Returns: 0 on success, -1 on error. */ int vips_jxlload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("jxlload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_jxlload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.jxlload], but read from a source. * * Returns: 0 on success, -1 on error. */ int vips_jxlload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("jxlload_source", ap, source, out); va_end(ap); return result; } /** * vips_jxlsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file in JPEG-XL format. The image can be unsigned * 8 or 16-bit integer, or float. Use @bitdepth for fine control of the image * bitdepth. * * @tier sets the overall decode speed the encoder will target. Minimum is 0 * (highest quality), and maximum is 4 (lowest quality). Default is 0. * * @distance sets the target maximum encoding error. Minimum is 0 * (highest quality), and maximum is 15 (lowest quality). Default is 1.0 * (visually lossless). * * As a convenience, you can also use @Q to set @distance. @Q uses * approximately the same scale as regular JPEG. * * @bitdepth sets the bitdepth to save at. It defaults to the full range of * the image numeric type, but can be set lower. It has no effect on float * images. * * Set @lossless to enable lossless compression. * * ::: tip "Optional arguments" * * @tier: `gint`, decode speed tier * * @distance: `gdouble`, maximum encoding error * * @effort: `gint`, encoding effort * * @lossless: `gboolean`, enables lossless compression * * @Q: `gint`, quality setting * * @bitdepth: `gint`, image bitdepth * * Returns: 0 on success, -1 on error. */ int vips_jxlsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("jxlsave", ap, in, filename); va_end(ap); return result; } /** * vips_jxlsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jxlsave], but save to a memory buffer. * * ::: tip "Optional arguments" * * @tier: `gint`, decode speed tier * * @distance: `gdouble`, maximum encoding error * * @effort: `gint`, encoding effort * * @lossless: `gboolean`, enables lossless compression * * @Q: `gint`, quality setting * * ::: seealso * [method@Image.jxlsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_jxlsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("jxlsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_jxlsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jxlsave], but save to a target. * * ::: tip "Optional arguments" * * @tier: `gint`, decode speed tier * * @distance: `gdouble`, maximum encoding error * * @effort: `gint`, encoding effort * * @lossless: `gboolean`, enables lossless compression * * @Q: `gint`, quality setting * * ::: seealso * [method@Image.jxlsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_jxlsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("jxlsave_target", ap, in, target); va_end(ap); return result; } /** * vips_pdfload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Render a PDF file into a VIPS image. * * The output image is always RGBA -- CMYK PDFs will be * converted. If you need CMYK bitmaps, you should use [ctor@Image.magickload] * instead. * * Use @page to select a page to render, numbering from zero. * * Use @n to select the number of pages to render. The default is 1. Pages are * rendered in a vertical column, with each individual page aligned to the * left. Set to -1 to mean "until the end of the document". Use * [method@Image.grid] to change page layout. * * Use @dpi to set the rendering resolution. The default is 72. Additionally, * you can scale by setting @scale. If you set both, they combine. * * Use @background to set the background RGBA colour. The default is 255 * (solid white), use eg. 0 for a transparent background. * * Use @password to supply a decryption password. * * When using pdfium, the region of a page to render can be selected with * @page_box, defaulting to the crop box. * * The operation fills a number of header fields with metadata, for example * "pdf-author". They may be useful. * * This function only reads the image header and does not render any pixel * data. Rendering occurs when pixels are accessed. * * ::: tip "Optional arguments" * * @page: `gint`, load this page, numbered from zero * * @n: `gint`, load this many pages * * @dpi: `gdouble`, render at this DPI * * @scale: `gdouble`, scale render by this factor * * @background: [struct@ArrayDouble], background colour * * @page_box: [enum@ForeignPdfPageBox], use this page box (pdfium only) * * ::: seealso * [ctor@Image.new_from_file], [ctor@Image.magickload]. * * Returns: 0 on success, -1 on error. */ int vips_pdfload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("pdfload", ap, filename, out); va_end(ap); return result; } /** * vips_pdfload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a PDF-formatted memory buffer into a VIPS image. Exactly as * [ctor@Image.pdfload], but read from memory. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, load this page, numbered from zero * * @n: `gint`, load this many pages * * @dpi: `gdouble`, render at this DPI * * @scale: `gdouble`, scale render by this factor * * @background: [struct@ArrayDouble], background colour * * @page_box: [enum@ForeignPdfPageBox], use this page box (pdfium only) * * ::: seealso * [ctor@Image.pdfload]. * * Returns: 0 on success, -1 on error. */ int vips_pdfload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("pdfload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_pdfload_source: * @source: source to load from * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.pdfload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, load this page, numbered from zero * * @n: `gint`, load this many pages * * @dpi: `gdouble`, render at this DPI * * @scale: `gdouble`, scale render by this factor * * @background: [struct@ArrayDouble], background colour * * @page_box: [enum@ForeignPdfPageBox], use this page box (pdfium only) * * ::: seealso * [ctor@Image.pdfload] * * Returns: 0 on success, -1 on error. */ int vips_pdfload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("pdfload_source", ap, source, out); va_end(ap); return result; } /** * vips_openslideload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a virtual slide supported by the OpenSlide library into a VIPS image. * OpenSlide supports images in Aperio, Hamamatsu, MIRAX, Sakura, Trestle, * and Ventana formats. * * To facilitate zooming, virtual slide formats include multiple scaled-down * versions of the high-resolution image. These are typically called * "levels". By default, [ctor@Image.openslideload] reads the * highest-resolution level (level 0). Set @level to the level number you want. * * In addition to the slide image itself, virtual slide formats sometimes * include additional images, such as a scan of the slide's barcode. * OpenSlide calls these "associated images". To read an associated image, * set @associated to the image's name. * A slide's associated images are listed in the * "slide-associated-images" metadata item. * * If you set @attach_associated, then all associated images are attached as * metadata items. Use [method@Image.get_image] on @out to retrieve them. Images * are attached as "openslide-associated-XXXXX", where XXXXX is the name of the * associated image. * * By default, the output of this operator is RGBA. Set @rgb to enable RGB * output. * * ::: tip "Optional arguments" * * @level: `gint`, load this level * * @associated: `gchararray`, load this associated image * * @attach_associated: `gboolean`, attach all associated images as metadata * * @autocrop: `gboolean`, crop to image bounds * * @rgb: `gboolean`, output RGB (not RGBA) pixels * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_openslideload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("openslideload", ap, filename, out); va_end(ap); return result; } /** * vips_openslideload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.openslideload], but read from a source. * * ::: tip "Optional arguments" * * @level: `gint`, load this level * * @associated: `gchararray`, load this associated image * * @attach_associated: `gboolean`, attach all associated images as metadata * * @autocrop: `gboolean`, crop to image bounds * * @rgb: `gboolean`, output RGB (not RGBA) pixels * * Returns: 0 on success, -1 on error. */ int vips_openslideload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("openslideload_source", ap, source, out); va_end(ap); return result; } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_foreign_operation_init(void) { extern GType vips_foreign_load_rad_file_get_type(void); extern GType vips_foreign_load_rad_buffer_get_type(void); extern GType vips_foreign_load_rad_source_get_type(void); extern GType vips_foreign_save_rad_file_get_type(void); extern GType vips_foreign_save_rad_buffer_get_type(void); extern GType vips_foreign_save_rad_target_get_type(void); extern GType vips_foreign_load_mat_get_type(void); extern GType vips_foreign_load_ppm_file_get_type(void); extern GType vips_foreign_load_ppm_buffer_get_type(void); extern GType vips_foreign_load_ppm_source_get_type(void); extern GType vips_foreign_save_ppm_file_get_type(void); extern GType vips_foreign_save_pbm_target_get_type(void); extern GType vips_foreign_save_pgm_target_get_type(void); extern GType vips_foreign_save_ppm_target_get_type(void); extern GType vips_foreign_save_pfm_target_get_type(void); extern GType vips_foreign_save_pnm_target_get_type(void); extern GType vips_foreign_load_png_file_get_type(void); extern GType vips_foreign_load_png_buffer_get_type(void); extern GType vips_foreign_load_png_source_get_type(void); extern GType vips_foreign_save_png_file_get_type(void); extern GType vips_foreign_save_png_buffer_get_type(void); extern GType vips_foreign_save_png_target_get_type(void); extern GType vips_foreign_save_spng_file_get_type(void); extern GType vips_foreign_save_spng_buffer_get_type(void); extern GType vips_foreign_save_spng_target_get_type(void); extern GType vips_foreign_load_csv_file_get_type(void); extern GType vips_foreign_load_csv_source_get_type(void); extern GType vips_foreign_save_csv_file_get_type(void); extern GType vips_foreign_save_csv_target_get_type(void); extern GType vips_foreign_load_matrix_file_get_type(void); extern GType vips_foreign_load_matrix_source_get_type(void); extern GType vips_foreign_save_matrix_file_get_type(void); extern GType vips_foreign_save_matrix_target_get_type(void); extern GType vips_foreign_print_matrix_get_type(void); extern GType vips_foreign_load_fits_file_get_type(void); extern GType vips_foreign_load_fits_source_get_type(void); extern GType vips_foreign_save_fits_get_type(void); extern GType vips_foreign_load_analyze_get_type(void); extern GType vips_foreign_load_openexr_get_type(void); extern GType vips_foreign_load_openslide_file_get_type(void); extern GType vips_foreign_load_openslide_source_get_type(void); extern GType vips_foreign_load_vips_file_get_type(void); extern GType vips_foreign_load_vips_source_get_type(void); extern GType vips_foreign_save_vips_file_get_type(void); extern GType vips_foreign_save_vips_target_get_type(void); extern GType vips_foreign_load_jpeg_file_get_type(void); extern GType vips_foreign_load_jpeg_buffer_get_type(void); extern GType vips_foreign_load_jpeg_source_get_type(void); extern GType vips_foreign_save_jpeg_file_get_type(void); extern GType vips_foreign_save_jpeg_buffer_get_type(void); extern GType vips_foreign_save_jpeg_target_get_type(void); extern GType vips_foreign_save_jpeg_mime_get_type(void); extern GType vips_foreign_load_tiff_file_get_type(void); extern GType vips_foreign_load_tiff_buffer_get_type(void); extern GType vips_foreign_load_tiff_source_get_type(void); extern GType vips_foreign_save_tiff_file_get_type(void); extern GType vips_foreign_save_tiff_buffer_get_type(void); extern GType vips_foreign_save_tiff_target_get_type(void); extern GType vips_foreign_load_raw_get_type(void); extern GType vips_foreign_save_raw_file_get_type(void); extern GType vips_foreign_save_raw_buffer_get_type(void); extern GType vips_foreign_save_raw_target_get_type(void); extern GType vips_foreign_load_magick_file_get_type(void); extern GType vips_foreign_load_magick_buffer_get_type(void); extern GType vips_foreign_load_magick_source_get_type(void); extern GType vips_foreign_load_magick7_file_get_type(void); extern GType vips_foreign_load_magick7_buffer_get_type(void); extern GType vips_foreign_load_magick7_source_get_type(void); extern GType vips_foreign_save_magick_file_get_type(void); extern GType vips_foreign_save_magick_buffer_get_type(void); extern GType vips_foreign_save_magick_bmp_file_get_type(void); extern GType vips_foreign_save_magick_bmp_buffer_get_type(void); extern GType vips_foreign_save_magick_gif_file_get_type(void); extern GType vips_foreign_save_magick_gif_buffer_get_type(void); extern GType vips_foreign_save_dz_file_get_type(void); extern GType vips_foreign_save_dz_buffer_get_type(void); extern GType vips_foreign_save_dz_target_get_type(void); extern GType vips_foreign_load_webp_file_get_type(void); extern GType vips_foreign_load_webp_buffer_get_type(void); extern GType vips_foreign_load_webp_source_get_type(void); extern GType vips_foreign_save_webp_file_get_type(void); extern GType vips_foreign_save_webp_buffer_get_type(void); extern GType vips_foreign_save_webp_target_get_type(void); extern GType vips_foreign_save_webp_mime_get_type(void); extern GType vips_foreign_load_pdf_file_get_type(void); extern GType vips_foreign_load_pdf_buffer_get_type(void); extern GType vips_foreign_load_pdf_source_get_type(void); extern GType vips_foreign_load_svg_file_get_type(void); extern GType vips_foreign_load_svg_buffer_get_type(void); extern GType vips_foreign_load_svg_source_get_type(void); extern GType vips_foreign_load_jp2k_file_get_type(void); extern GType vips_foreign_load_jp2k_buffer_get_type(void); extern GType vips_foreign_load_jp2k_source_get_type(void); extern GType vips_foreign_save_jp2k_file_get_type(void); extern GType vips_foreign_save_jp2k_buffer_get_type(void); extern GType vips_foreign_save_jp2k_target_get_type(void); extern GType vips_foreign_load_jxl_file_get_type(void); extern GType vips_foreign_load_jxl_buffer_get_type(void); extern GType vips_foreign_load_jxl_source_get_type(void); extern GType vips_foreign_save_jxl_file_get_type(void); extern GType vips_foreign_save_jxl_buffer_get_type(void); extern GType vips_foreign_save_jxl_target_get_type(void); extern GType vips_foreign_load_heif_file_get_type(void); extern GType vips_foreign_load_heif_buffer_get_type(void); extern GType vips_foreign_load_heif_source_get_type(void); extern GType vips_foreign_save_heif_file_get_type(void); extern GType vips_foreign_save_heif_buffer_get_type(void); extern GType vips_foreign_save_heif_target_get_type(void); extern GType vips_foreign_save_avif_target_get_type(void); extern GType vips_foreign_load_nifti_file_get_type(void); extern GType vips_foreign_load_nifti_source_get_type(void); extern GType vips_foreign_save_nifti_get_type(void); extern GType vips_foreign_load_nsgif_file_get_type(void); extern GType vips_foreign_load_nsgif_buffer_get_type(void); extern GType vips_foreign_load_nsgif_source_get_type(void); extern GType vips_foreign_save_cgif_file_get_type(void); extern GType vips_foreign_save_cgif_buffer_get_type(void); extern GType vips_foreign_save_cgif_target_get_type(void); extern GType vips_foreign_load_dcraw_file_get_type(void); extern GType vips_foreign_load_dcraw_buffer_get_type(void); extern GType vips_foreign_load_dcraw_source_get_type(void); extern GType vips_foreign_load_uhdr_file_get_type(void); extern GType vips_foreign_load_uhdr_buffer_get_type(void); extern GType vips_foreign_load_uhdr_source_get_type(void); extern GType vips_foreign_save_uhdr_file_get_type(void); extern GType vips_foreign_save_uhdr_buffer_get_type(void); extern GType vips_foreign_save_uhdr_target_get_type(void); vips_foreign_load_csv_file_get_type(); vips_foreign_load_csv_source_get_type(); vips_foreign_save_csv_file_get_type(); vips_foreign_save_csv_target_get_type(); vips_foreign_load_matrix_file_get_type(); vips_foreign_load_matrix_source_get_type(); vips_foreign_save_matrix_file_get_type(); vips_foreign_save_matrix_target_get_type(); vips_foreign_print_matrix_get_type(); vips_foreign_load_raw_get_type(); vips_foreign_save_raw_file_get_type(); vips_foreign_save_raw_buffer_get_type(); vips_foreign_save_raw_target_get_type(); vips_foreign_load_vips_file_get_type(); vips_foreign_load_vips_source_get_type(); vips_foreign_save_vips_file_get_type(); vips_foreign_save_vips_target_get_type(); #ifdef HAVE_ANALYZE vips_foreign_load_analyze_get_type(); #endif /*HAVE_ANALYZE*/ #ifdef HAVE_PPM vips_foreign_load_ppm_file_get_type(); vips_foreign_load_ppm_buffer_get_type(); vips_foreign_load_ppm_source_get_type(); vips_foreign_save_ppm_file_get_type(); vips_foreign_save_pbm_target_get_type(); vips_foreign_save_pgm_target_get_type(); vips_foreign_save_ppm_target_get_type(); vips_foreign_save_pfm_target_get_type(); vips_foreign_save_pnm_target_get_type(); #endif /*HAVE_PPM*/ #ifdef HAVE_RADIANCE vips_foreign_load_rad_file_get_type(); vips_foreign_load_rad_buffer_get_type(); vips_foreign_load_rad_source_get_type(); vips_foreign_save_rad_file_get_type(); vips_foreign_save_rad_buffer_get_type(); vips_foreign_save_rad_target_get_type(); #endif /*HAVE_RADIANCE*/ #if defined(HAVE_POPPLER) && !defined(POPPLER_MODULE) vips_foreign_load_pdf_file_get_type(); vips_foreign_load_pdf_buffer_get_type(); vips_foreign_load_pdf_source_get_type(); #endif /*defined(HAVE_POPPLER) && !defined(POPPLER_MODULE)*/ #ifdef HAVE_PDFIUM vips_foreign_load_pdf_file_get_type(); vips_foreign_load_pdf_buffer_get_type(); vips_foreign_load_pdf_source_get_type(); #endif /*HAVE_PDFIUM*/ #ifdef HAVE_RSVG vips_foreign_load_svg_file_get_type(); vips_foreign_load_svg_buffer_get_type(); vips_foreign_load_svg_source_get_type(); #endif /*HAVE_RSVG*/ #if defined(HAVE_LIBJXL) && !defined(LIBJXL_MODULE) vips_foreign_load_jxl_file_get_type(); vips_foreign_load_jxl_buffer_get_type(); vips_foreign_load_jxl_source_get_type(); vips_foreign_save_jxl_file_get_type(); vips_foreign_save_jxl_buffer_get_type(); vips_foreign_save_jxl_target_get_type(); #endif /*defined(HAVE_LIBJXL) && !defined(LIBJXL_MODULE)*/ #ifdef HAVE_LIBOPENJP2 vips_foreign_load_jp2k_file_get_type(); vips_foreign_load_jp2k_buffer_get_type(); vips_foreign_load_jp2k_source_get_type(); vips_foreign_save_jp2k_file_get_type(); vips_foreign_save_jp2k_buffer_get_type(); vips_foreign_save_jp2k_target_get_type(); #endif /*HAVE_LIBOPENJP2*/ #ifdef HAVE_NSGIF vips_foreign_load_nsgif_file_get_type(); vips_foreign_load_nsgif_buffer_get_type(); vips_foreign_load_nsgif_source_get_type(); #endif /*HAVE_NSGIF*/ #ifdef HAVE_LIBRAW vips_foreign_load_dcraw_file_get_type(); vips_foreign_load_dcraw_buffer_get_type(); vips_foreign_load_dcraw_source_get_type(); #endif /*HAVE_LIBRAW*/ #ifdef HAVE_UHDR vips_foreign_load_uhdr_file_get_type(); vips_foreign_load_uhdr_buffer_get_type(); vips_foreign_load_uhdr_source_get_type(); vips_foreign_save_uhdr_file_get_type(); vips_foreign_save_uhdr_buffer_get_type(); vips_foreign_save_uhdr_target_get_type(); #endif /*HAVE_UHDR*/ #ifdef HAVE_CGIF vips_foreign_save_cgif_file_get_type(); vips_foreign_save_cgif_buffer_get_type(); vips_foreign_save_cgif_target_get_type(); #endif /*HAVE_CGIF*/ #ifdef HAVE_LIBARCHIVE vips_foreign_save_dz_file_get_type(); vips_foreign_save_dz_buffer_get_type(); vips_foreign_save_dz_target_get_type(); #endif /*HAVE_LIBARCHIVE*/ #ifdef HAVE_PNG vips_foreign_load_png_file_get_type(); vips_foreign_load_png_buffer_get_type(); vips_foreign_load_png_source_get_type(); vips_foreign_save_png_file_get_type(); vips_foreign_save_png_buffer_get_type(); vips_foreign_save_png_target_get_type(); #endif /*HAVE_PNG*/ #ifdef HAVE_SPNG vips_foreign_load_png_file_get_type(); vips_foreign_load_png_buffer_get_type(); vips_foreign_load_png_source_get_type(); vips_foreign_save_spng_file_get_type(); vips_foreign_save_spng_buffer_get_type(); vips_foreign_save_spng_target_get_type(); #endif /*HAVE_SPNG*/ #ifdef HAVE_MATIO vips_foreign_load_mat_get_type(); #endif /*HAVE_MATIO*/ #ifdef HAVE_JPEG vips_foreign_load_jpeg_file_get_type(); vips_foreign_load_jpeg_buffer_get_type(); vips_foreign_load_jpeg_source_get_type(); vips_foreign_save_jpeg_file_get_type(); vips_foreign_save_jpeg_buffer_get_type(); vips_foreign_save_jpeg_target_get_type(); vips_foreign_save_jpeg_mime_get_type(); #endif /*HAVE_JPEG*/ #ifdef HAVE_LIBWEBP vips_foreign_load_webp_file_get_type(); vips_foreign_load_webp_buffer_get_type(); vips_foreign_load_webp_source_get_type(); vips_foreign_save_webp_file_get_type(); vips_foreign_save_webp_buffer_get_type(); vips_foreign_save_webp_target_get_type(); vips_foreign_save_webp_mime_get_type(); #endif /*HAVE_LIBWEBP*/ #ifdef HAVE_TIFF vips_foreign_load_tiff_file_get_type(); vips_foreign_load_tiff_buffer_get_type(); vips_foreign_load_tiff_source_get_type(); vips_foreign_save_tiff_file_get_type(); vips_foreign_save_tiff_buffer_get_type(); vips_foreign_save_tiff_target_get_type(); #endif /*HAVE_TIFF*/ #if defined(HAVE_OPENSLIDE) && !defined(OPENSLIDE_MODULE) vips_foreign_load_openslide_file_get_type(); vips_foreign_load_openslide_source_get_type(); #endif /*defined(HAVE_OPENSLIDE) && !defined(OPENSLIDE_MODULE)*/ #if defined(ENABLE_MAGICKLOAD) && !defined(MAGICK_MODULE) #ifdef HAVE_MAGICK6 vips_foreign_load_magick_file_get_type(); vips_foreign_load_magick_buffer_get_type(); vips_foreign_load_magick_source_get_type(); #endif /*HAVE_MAGICK6*/ #ifdef HAVE_MAGICK7 vips_foreign_load_magick7_file_get_type(); vips_foreign_load_magick7_buffer_get_type(); vips_foreign_load_magick7_source_get_type(); #endif /*HAVE_MAGICK7*/ #endif /*defined(ENABLE_MAGICKLOAD) && !defined(MAGICK_MODULE)*/ #if defined(ENABLE_MAGICKSAVE) && !defined(MAGICK_MODULE) vips_foreign_save_magick_file_get_type(); vips_foreign_save_magick_buffer_get_type(); vips_foreign_save_magick_bmp_file_get_type(); vips_foreign_save_magick_bmp_buffer_get_type(); vips_foreign_save_magick_gif_file_get_type(); vips_foreign_save_magick_gif_buffer_get_type(); #endif /*defined(ENABLE_MAGICKSAVE) && !defined(MAGICK_MODULE)*/ #ifdef HAVE_CFITSIO vips_foreign_load_fits_file_get_type(); vips_foreign_load_fits_source_get_type(); vips_foreign_save_fits_get_type(); #endif /*HAVE_CFITSIO*/ #ifdef HAVE_OPENEXR vips_foreign_load_openexr_get_type(); #endif /*HAVE_OPENEXR*/ #ifdef HAVE_NIFTI vips_foreign_load_nifti_file_get_type(); vips_foreign_load_nifti_source_get_type(); vips_foreign_save_nifti_get_type(); #endif /*HAVE_NIFTI*/ #if defined(HAVE_HEIF) && !defined(HEIF_MODULE) vips_foreign_load_heif_file_get_type(); vips_foreign_load_heif_buffer_get_type(); vips_foreign_load_heif_source_get_type(); vips_foreign_save_heif_file_get_type(); vips_foreign_save_heif_buffer_get_type(); vips_foreign_save_heif_target_get_type(); vips_foreign_save_avif_target_get_type(); #endif /*defined(HAVE_HEIF) && !defined(HEIF_MODULE)*/ vips__foreign_load_operation = g_quark_from_static_string("vips-foreign-load-operation"); } libvips-8.18.2/libvips/foreign/heifload.c000066400000000000000000001072731516303661500203220ustar00rootroot00000000000000/* load heif images with libheif * * 19/1/19 * - from niftiload.c * 24/7/19 [zhoux2016] * - always fetch metadata from the main image (thumbs don't have it) * 24/7/19 * - close early on minimise * - close early on error * 1/9/19 [meyermarcel] * - handle alpha * 30/9/19 * - much faster handling of thumbnail=TRUE and missing thumbnail ... we * were reselecting the image for each scanline * 3/10/19 * - restart after minimise * 15/3/20 * - revise for new VipsSource API * 10/5/20 * - deprecate autorotate -- it's too difficult to support properly * 31/7/20 * - block broken thumbnails, if we can * 14/2/21 kleisauke * - move GObject part to heif2vips.c * 22/12/21 * - add >8 bit support * 23/2/22 lovell * - add @unlimited * 13/03/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include /* These are shared with the encoder. */ #ifdef HAVE_HEIF #include "pforeign.h" const char *vips__heic_suffs[] = { ".heic", ".heif", NULL }; const char *vips__avif_suffs[] = { ".avif", NULL }; const char *vips__heif_suffs[] = { ".heic", ".heif", ".avif", NULL }; #include #define VIPS_TYPE_FOREIGN_LOAD_HEIF (vips_foreign_load_heif_get_type()) #define VIPS_FOREIGN_LOAD_HEIF(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_LOAD_HEIF, VipsForeignLoadHeif)) #define VIPS_FOREIGN_LOAD_HEIF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN_LOAD_HEIF, VipsForeignLoadHeifClass)) #define VIPS_IS_FOREIGN_LOAD_HEIF(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN_LOAD_HEIF)) #define VIPS_IS_FOREIGN_LOAD_HEIF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN_LOAD_HEIF)) #define VIPS_FOREIGN_LOAD_HEIF_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN_LOAD_HEIF, VipsForeignLoadHeifClass)) typedef struct _VipsForeignLoadHeif { VipsForeignLoad parent_object; /* Pages to load. */ int page; int n; /* Fetch the thumbnail instead of the image. If there is no thumbnail, * just fetch the image. */ gboolean thumbnail; /* Apply any orientation tags in the header. * * This is deprecated and does nothing. Non-autorotated reads from * libheif are surprisingly hard to support well, since orientation can * be represented in several different ways in HEIC files and devices * vary in how they do this. */ gboolean autorotate; /* remove all denial of service limits. */ gboolean unlimited; /* Context for this image. */ struct heif_context *ctx; /* Number of top-level images in this file. */ int n_top; /* TRUE for RGBA ... otherwise, RGB. */ gboolean has_alpha; /* Size of final output image. */ int width; int height; /* Size of each page. */ int page_width; int page_height; /* Eg. 8 or 12, typically. */ int bits_per_pixel; /* The page number currently in @handle. */ int page_no; /* TRUE if @handle has selected the thumbnail rather than the main * image. */ gboolean thumbnail_set; /* The page number of the primary image. */ int primary_page; /* Array of top-level image IDs. */ heif_item_id *id; /* Handle for the currently selected image. */ struct heif_image_handle *handle; /* Decoded pixel data for the current image. */ struct heif_image *img; /* Valid until img is released. */ int stride; const uint8_t *data; /* Set from subclasses. */ VipsSource *source; /* The reader struct. We use this to attach to our VipsSource. This * has to be alloced rather than in our struct, since it may change * size in libheif API versions. */ struct heif_reader *reader; } VipsForeignLoadHeif; #ifdef HAVE_HEIF_INIT static void * vips__heif_init_once(void *client) { struct heif_error error; error = heif_init(NULL); if (error.code) g_warning("heif_init: %s (%d.%d)\n", error.message ? error.message : "(null)", error.code, error.subcode); return NULL; } #endif /*HAVE_HEIF_INIT*/ void vips__heif_init(void) { #ifdef HAVE_HEIF_INIT static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, vips__heif_init_once, NULL); #endif /*HAVE_HEIF_INIT*/ } void vips__heif_error(struct heif_error *error) { if (error->code) vips_error("heif", "%s (%d.%d)", error->message ? error->message : "(null)", error->code, error->subcode); } #ifdef DEBUG void vips__heif_image_print(struct heif_image *img) { const static enum heif_channel channel[] = { heif_channel_Y, heif_channel_Cb, heif_channel_Cr, heif_channel_R, heif_channel_G, heif_channel_B, heif_channel_Alpha, heif_channel_interleaved }; const static char *channel_name[] = { "heif_channel_Y", "heif_channel_Cb", "heif_channel_Cr", "heif_channel_R", "heif_channel_G", "heif_channel_B", "heif_channel_Alpha", "heif_channel_interleaved" }; int i; printf("vips__heif_image_print:\n"); for (i = 0; i < VIPS_NUMBER(channel); i++) { if (!heif_image_has_channel(img, channel[i])) continue; printf("\t%s:\n", channel_name[i]); printf("\t\twidth = %d\n", heif_image_get_width(img, channel[i])); printf("\t\theight = %d\n", heif_image_get_height(img, channel[i])); printf("\t\tbits = %d\n", heif_image_get_bits_per_pixel(img, channel[i])); } } #endif /*DEBUG*/ /* Pick a chroma format. Shared with heifsave. */ int vips__heif_chroma(int bits_per_pixel, gboolean has_alpha) { if (bits_per_pixel == 8) { if (has_alpha) return heif_chroma_interleaved_RGBA; else return heif_chroma_interleaved_RGB; } else { if (has_alpha) return heif_chroma_interleaved_RRGGBBAA_BE; else return heif_chroma_interleaved_RRGGBB_BE; } } typedef struct _VipsForeignLoadHeifClass { VipsForeignLoadClass parent_class; } VipsForeignLoadHeifClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadHeif, vips_foreign_load_heif, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_heif_dispose(GObject *gobject) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) gobject; heif->data = NULL; VIPS_FREEF(heif_image_release, heif->img); VIPS_FREEF(heif_image_handle_release, heif->handle); VIPS_FREEF(heif_context_free, heif->ctx); VIPS_FREE(heif->id); VIPS_FREE(heif->reader); VIPS_UNREF(heif->source); G_OBJECT_CLASS(vips_foreign_load_heif_parent_class)->dispose(gobject); } static int vips_foreign_load_heif_build(VipsObject *object) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object; #ifdef DEBUG printf("vips_foreign_load_heif_build:\n"); #endif /*DEBUG*/ if (heif->source && vips_source_rewind(heif->source)) return -1; if (!heif->ctx) { struct heif_error error; heif->ctx = heif_context_alloc(); /* heifsave is limited to a maximum image size of 16384x16384, * so align the heifload defaults accordingly. */ heif_context_set_maximum_image_size_limit(heif->ctx, heif->unlimited ? USHRT_MAX : 0x4000); #ifdef HAVE_HEIF_MAX_TOTAL_MEMORY if (!heif->unlimited) heif_context_get_security_limits(heif->ctx) ->max_total_memory = 2UL * 1024 * 1024 * 1024; #endif /* HAVE_HEIF_MAX_TOTAL_MEMORY */ #ifdef HAVE_HEIF_GET_DISABLED_SECURITY_LIMITS if (heif->unlimited) heif_context_set_security_limits(heif->ctx, heif_get_disabled_security_limits()); #endif /* HAVE_HEIF_GET_DISABLED_SECURITY_LIMITS */ error = heif_context_read_from_reader(heif->ctx, heif->reader, heif, NULL); if (error.code) { vips__heif_error(&error); return -1; } } return VIPS_OBJECT_CLASS(vips_foreign_load_heif_parent_class) ->build(object); } static const char *heif_magic[] = { "ftypheic", /* A regular heif image */ "ftypheix", /* Extended range (>8 bit) image */ "ftyphevc", /* Image sequence */ "ftypheim", /* Image sequence */ "ftypheis", /* Scalable image */ "ftyphevm", /* Multiview sequence */ "ftyphevs", /* Scalable sequence */ "ftypmif1", /* Nokia alpha_ image */ "ftypmsf1", /* Nokia animation image */ "ftypavif" /* AV1 image format */ }; /* The API has: * * enum heif_filetype_result result = heif_check_filetype(buf, 12); * * but it's very conservative and seems to be missing some of the Nokia heif * types. */ static int vips_foreign_load_heif_is_a(const char *buf, int len) { if (len >= 12) { unsigned char *p = (unsigned char *) buf; guint32 chunk_len = VIPS_LSHIFT_INT(p[0], 24) | VIPS_LSHIFT_INT(p[1], 16) | VIPS_LSHIFT_INT(p[2], 8) | VIPS_LSHIFT_INT(p[3], 0); int i; /* chunk_len can be pretty big for eg. animated AVIF. */ if (chunk_len > 2048 || chunk_len % 4 != 0) return 0; for (i = 0; i < VIPS_NUMBER(heif_magic); i++) if (strncmp(buf + 4, heif_magic[i], 8) == 0) return 1; } return 0; } static VipsForeignFlags vips_foreign_load_heif_get_flags(VipsForeignLoad *load) { /* FIXME .. could support random access for grid images. */ return VIPS_FOREIGN_SEQUENTIAL; } /* We've selected the page. Try to select the associated thumbnail instead, * if we can. */ static int vips_foreign_load_heif_set_thumbnail(VipsForeignLoadHeif *heif) { heif_item_id thumb_ids[1]; int n_thumbs; struct heif_image_handle *thumb_handle; struct heif_image *thumb_img; struct heif_error error; double main_aspect; double thumb_aspect; #ifdef DEBUG printf("vips_foreign_load_heif_set_thumbnail:\n"); #endif /*DEBUG*/ n_thumbs = heif_image_handle_get_list_of_thumbnail_IDs( heif->handle, thumb_ids, 1); if (n_thumbs == 0) return 0; error = heif_image_handle_get_thumbnail(heif->handle, thumb_ids[0], &thumb_handle); if (error.code) { vips__heif_error(&error); return -1; } /* Just checking the width and height of the handle isn't * enough -- we have to experimentally decode it and test the * decoded dimensions. */ error = heif_decode_image(thumb_handle, &thumb_img, heif_colorspace_RGB, heif_chroma_interleaved_RGB, NULL); if (error.code) { VIPS_FREEF(heif_image_handle_release, thumb_handle); vips__heif_error(&error); return -1; } thumb_aspect = (double) heif_image_get_width(thumb_img, heif_channel_interleaved) / heif_image_get_height(thumb_img, heif_channel_interleaved); VIPS_FREEF(heif_image_release, thumb_img); main_aspect = (double) heif_image_handle_get_width(heif->handle) / heif_image_handle_get_height(heif->handle); /* The bug we are working around has decoded thumbs as 512x512 * with the main image as 6kx4k, so a 0.1 threshold is more * than tight enough to spot the error. */ if (fabs(main_aspect - thumb_aspect) > 0.1) { VIPS_FREEF(heif_image_handle_release, thumb_handle); return 0; } VIPS_FREEF(heif_image_handle_release, heif->handle); heif->handle = thumb_handle; return 0; } /* Select a page. If thumbnail is set, select the thumbnail for that page, if * there is one. */ static int vips_foreign_load_heif_set_page(VipsForeignLoadHeif *heif, int page_no, gboolean thumbnail) { if (!heif->handle || page_no != heif->page_no || thumbnail != heif->thumbnail_set) { struct heif_error error; #ifdef DEBUG printf("vips_foreign_load_heif_set_page: %d, thumbnail = %d\n", page_no, thumbnail); #endif /*DEBUG*/ VIPS_FREEF(heif_image_handle_release, heif->handle); VIPS_FREEF(heif_image_release, heif->img); heif->data = NULL; heif->thumbnail_set = FALSE; error = heif_context_get_image_handle(heif->ctx, heif->id[page_no], &heif->handle); if (error.code) { vips__heif_error(&error); return -1; } if (thumbnail) { if (vips_foreign_load_heif_set_thumbnail(heif)) return -1; /* If we were asked to select the thumbnail, say we * did, even if there are no thumbnails and we just * selected the main image. * * If we don't do this, next time around in _generate * we'll try to select the thumbnail again, which will * be horribly slow. */ heif->thumbnail_set = TRUE; } heif->page_no = page_no; } return 0; } static int vips_foreign_load_heif_set_header(VipsForeignLoadHeif *heif, VipsImage *out) { VipsForeignLoad *load = (VipsForeignLoad *) heif; int bands; int i; /* Surely, 16 metadata items will be enough for anyone. */ heif_item_id id[16]; int n_metadata; struct heif_error error; VipsForeignHeifCompression compression; VipsInterpretation interpretation; VipsBandFormat format; const unsigned char *brand_data; /* We take the metadata from the non-thumbnail first page. HEIC * thumbnails don't have metadata. */ if (vips_foreign_load_heif_set_page(heif, heif->page, FALSE)) return -1; /* Verify dimensions */ if (heif->page_width < 1 || heif->page_height < 1) { vips_error("heifload", "%s", _("bad dimensions")); return -1; } heif->has_alpha = heif_image_handle_has_alpha_channel(heif->handle); #ifdef DEBUG printf("heif_image_handle_has_alpha_channel() = %d\n", heif->has_alpha); #endif /*DEBUG*/ bands = heif->has_alpha ? 4 : 3; #ifdef DEBUG printf("heif_image_handle_get_luma_bits_per_pixel() = %d\n", heif_image_handle_get_luma_bits_per_pixel(heif->handle)); #endif /*DEBUG*/ /* FIXME .. IPTC as well? */ n_metadata = heif_image_handle_get_list_of_metadata_block_IDs( heif->handle, NULL, id, VIPS_NUMBER(id)); for (i = 0; i < n_metadata; i++) { size_t length = heif_image_handle_get_metadata_size(heif->handle, id[i]); const char *type = heif_image_handle_get_metadata_type(heif->handle, id[i]); const char *content_type = heif_image_handle_get_metadata_content_type(heif->handle, id[i]); unsigned char *data; char name[256]; #ifdef DEBUG printf("metadata type = %s, length = %zu\n", type, length); #endif /*DEBUG*/ if (!length) continue; if (!(data = VIPS_ARRAY(NULL, length, unsigned char))) return -1; error = heif_image_handle_get_metadata(heif->handle, id[i], data); if (error.code) { VIPS_FREE(data); vips__heif_error(&error); return -1; } /* We need to skip the first four bytes of EXIF, they just * contain the offset. */ if (length > 4 && g_ascii_strcasecmp(type, "exif") == 0) { length -= 4; memmove(data, data + 4, length); } /* Exif data will have the type string "exif". * * For XMP, the content type is "application/rdf+xml". */ if (g_ascii_strcasecmp(type, "exif") == 0) g_snprintf(name, 256, VIPS_META_EXIF_NAME); else if (g_ascii_strcasecmp(content_type, "application/rdf+xml") == 0) g_snprintf(name, 256, VIPS_META_XMP_NAME); else g_snprintf(name, 256, "heif-%s-%d", type, i); vips_image_set_blob(out, name, (VipsCallbackFn) vips_area_free_cb, data, length); /* image_set will automatically parse EXIF, if necessary. */ } /* We use libheif's autorotate, so we need to remove any EXIF * orientation tags. * * According to the HEIF standard, EXIF orientation tags are only * informational and images should not be rotated because of them. * Unless we strip these tags, there's a danger downstream processing * could double-rotate. */ vips_autorot_remove_angle(out); enum heif_color_profile_type profile_type = heif_image_handle_get_color_profile_type(heif->handle); #ifdef DEBUG { printf("profile type = "); switch (profile_type) { case heif_color_profile_type_not_present: printf("none"); break; case heif_color_profile_type_nclx: printf("nclx"); break; case heif_color_profile_type_rICC: printf("rICC"); break; case heif_color_profile_type_prof: printf("prof"); break; default: printf("unknown"); break; } printf("\n"); } #endif /*DEBUG*/ /* lcms can load standard (prof) and reduced (rICC) profiles */ if (profile_type == heif_color_profile_type_prof || profile_type == heif_color_profile_type_rICC) { size_t length = heif_image_handle_get_raw_color_profile_size( heif->handle); unsigned char *data; if (!(data = VIPS_ARRAY(NULL, length, unsigned char))) return -1; error = heif_image_handle_get_raw_color_profile(heif->handle, data); if (error.code) { VIPS_FREE(data); vips__heif_error(&error); return -1; } #ifdef DEBUG printf("profile data, length = %zd\n", length); #endif /*DEBUG*/ vips_image_set_blob(out, VIPS_META_ICC_NAME, (VipsCallbackFn) vips_area_free_cb, data, length); } else if (profile_type == heif_color_profile_type_nclx) { g_info("heifload: ignoring nclx profile"); } vips_image_set_int(out, "heif-primary", heif->primary_page); vips_image_set_int(out, VIPS_META_N_PAGES, heif->n_top); /* Only set page-height if we have more than one page, or this could * accidentally turn into an animated image later. */ if (heif->n > 1) vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, heif->page_height); /* Determine compression from HEIF "brand". heif_avif and heif_avis * were added in v1.7. */ compression = VIPS_FOREIGN_HEIF_COMPRESSION_HEVC; if ((brand_data = vips_source_sniff(heif->source, 12))) { enum heif_brand brand; brand = heif_main_brand(brand_data, 12); if (brand == heif_avif || brand == heif_avis) compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1; } vips_image_set_string(out, "heif-compression", vips_enum_nick(VIPS_TYPE_FOREIGN_HEIF_COMPRESSION, compression)); vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, heif->bits_per_pixel); /* Deprecated "heif-bitdepth" use "bits-per-sample" instead. */ vips_image_set_int(out, "heif-bitdepth", heif->bits_per_pixel); if (heif->bits_per_pixel > 8) { interpretation = VIPS_INTERPRETATION_RGB16; format = VIPS_FORMAT_USHORT; } else { interpretation = VIPS_INTERPRETATION_sRGB; format = VIPS_FORMAT_UCHAR; } /* FIXME .. we always decode to RGB in generate. We should check for * all grey images, perhaps. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; vips_image_init_fields(out, heif->page_width, heif->page_height * heif->n, bands, format, VIPS_CODING_NONE, interpretation, 1.0, 1.0); VIPS_SETSTR(load->out->filename, vips_connection_filename(VIPS_CONNECTION(heif->source))); return 0; } static int vips_foreign_load_heif_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) load; struct heif_error error; heif_item_id primary_id; int i; #ifdef DEBUG printf("vips_foreign_load_heif_header:\n"); #endif /*DEBUG*/ heif->n_top = heif_context_get_number_of_top_level_images(heif->ctx); heif->id = VIPS_ARRAY(NULL, heif->n_top, heif_item_id); heif_context_get_list_of_top_level_image_IDs(heif->ctx, heif->id, heif->n_top); /* Note page number of primary image. */ error = heif_context_get_primary_image_ID(heif->ctx, &primary_id); if (error.code) { vips__heif_error(&error); return -1; } for (i = 0; i < heif->n_top; i++) if (heif->id[i] == primary_id) heif->primary_page = i; /* If @n and @page have not been set, @page defaults to the primary * page. */ if (!vips_object_argument_isset(VIPS_OBJECT(load), "page") && !vips_object_argument_isset(VIPS_OBJECT(load), "n")) heif->page = heif->primary_page; // FIXME: Invalidates operation cache if (heif->n == -1) heif->n = heif->n_top - heif->page; // FIXME: Invalidates operation cache if (heif->page < 0 || heif->n <= 0 || heif->page + heif->n > heif->n_top) { vips_error(class->nickname, "%s", _("bad page number")); return -1; } #ifdef DEBUG for (i = heif->page; i < heif->page + heif->n; i++) { heif_item_id thumb_ids[1]; int n_items; int n_thumbs; int j; if (vips_foreign_load_heif_set_page(heif, i, FALSE)) return -1; n_thumbs = heif_image_handle_get_number_of_thumbnails(heif->handle); n_items = heif_image_handle_get_list_of_thumbnail_IDs(heif->handle, thumb_ids, 1); printf("page = %d\n", i); printf("n_thumbs = %d\n", n_thumbs); printf("n_items = %d\n", n_items); for (j = 0; j < n_items; j++) { struct heif_image_handle *thumb_handle; error = heif_image_handle_get_thumbnail(heif->handle, thumb_ids[j], &thumb_handle); if (error.code) { vips__heif_error(&error); return -1; } printf(" thumb %d\n", j); printf(" width = %d\n", heif_image_handle_get_width(thumb_handle)); printf(" height = %d\n", heif_image_handle_get_height(thumb_handle)); printf(" bits_per_pixel = %d\n", heif_image_handle_get_luma_bits_per_pixel(thumb_handle)); } } #endif /*DEBUG*/ /* All pages must be the same size for libvips toilet roll images. */ if (vips_foreign_load_heif_set_page(heif, heif->page, heif->thumbnail)) return -1; heif->page_width = heif_image_handle_get_width(heif->handle); heif->page_height = heif_image_handle_get_height(heif->handle); heif->bits_per_pixel = heif_image_handle_get_luma_bits_per_pixel(heif->handle); if (heif->bits_per_pixel < 0) { vips_error(class->nickname, "%s", _("undefined bits per pixel")); return -1; } for (i = heif->page + 1; i < heif->page + heif->n; i++) { if (vips_foreign_load_heif_set_page(heif, i, heif->thumbnail)) return -1; if (heif_image_handle_get_width(heif->handle) != heif->page_width || heif_image_handle_get_height(heif->handle) != heif->page_height || heif_image_handle_get_luma_bits_per_pixel(heif->handle) != heif->bits_per_pixel) { vips_error(class->nickname, "%s", _("not all pages are the same size")); return -1; } } #ifdef DEBUG printf("page_width = %d\n", heif->page_width); printf("page_height = %d\n", heif->page_height); printf("bits_per_pixel = %d\n", heif->bits_per_pixel); printf("n_top = %d\n", heif->n_top); for (i = 0; i < heif->n_top; i++) { printf(" id[%d] = %d\n", i, heif->id[i]); if (vips_foreign_load_heif_set_page(heif, i, FALSE)) return -1; printf(" width = %d\n", heif_image_handle_get_width(heif->handle)); printf(" height = %d\n", heif_image_handle_get_height(heif->handle)); printf(" bits_per_pixel = %d\n", heif_image_handle_get_luma_bits_per_pixel(heif->handle)); printf(" has_depth = %d\n", heif_image_handle_has_depth_image(heif->handle)); printf(" has_alpha = %d\n", heif_image_handle_has_alpha_channel(heif->handle)); printf(" n_metadata = %d\n", heif_image_handle_get_number_of_metadata_blocks( heif->handle, NULL)); printf(" colour profile type = 0x%xd\n", heif_image_handle_get_color_profile_type(heif->handle)); } #endif /*DEBUG*/ if (vips_foreign_load_heif_set_header(heif, load->out)) return -1; vips_source_minimise(heif->source); return 0; } static int vips_foreign_load_heif_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) a; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(heif); VipsRect *r = &out_region->valid; int page = r->top / heif->page_height + heif->page; int line = r->top % heif->page_height; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_heif_generate: line %d\n", r->top); #endif /*DEBUG_VERBOSE*/ g_assert(r->height == 1); if (vips_foreign_load_heif_set_page(heif, page, heif->thumbnail)) return -1; if (!heif->img) { enum heif_chroma chroma = vips__heif_chroma(heif->bits_per_pixel, heif->has_alpha); struct heif_error error; struct heif_decoding_options *options; options = heif_decoding_options_alloc(); error = heif_decode_image(heif->handle, &heif->img, heif_colorspace_RGB, chroma, options); heif_decoding_options_free(options); if (error.code) { vips__heif_error(&error); return -1; } #ifdef DEBUG vips__heif_image_print(heif->img); #endif /*DEBUG*/ } if (!heif->data) { int image_width = heif_image_get_width(heif->img, heif_channel_interleaved); int image_height = heif_image_get_height(heif->img, heif_channel_interleaved); /* We can sometimes get inconsistency between the dimensions * reported on the handle, and the final image we fetch. Error * out to prevent a segv. */ if (image_width != heif->page_width || image_height != heif->page_height) { vips_error(class->nickname, "%s", _("bad image dimensions on decode")); return -1; } if (!(heif->data = heif_image_get_plane_readonly(heif->img, heif_channel_interleaved, &heif->stride))) { vips_error(class->nickname, "%s", _("unable to get image data")); return -1; } } memcpy(VIPS_REGION_ADDR(out_region, 0, r->top), heif->data + (size_t) heif->stride * line, VIPS_IMAGE_SIZEOF_LINE(out_region->im)); /* We may need to swap bytes and shift to fill 16 bits. */ if (heif->bits_per_pixel > 8) { int shift = 16 - heif->bits_per_pixel; int ne = VIPS_REGION_N_ELEMENTS(out_region); int i; VipsPel *p; p = VIPS_REGION_ADDR(out_region, 0, r->top); for (i = 0; i < ne; i++) { /* We've asked for big endian, we must write native. */ guint16 v = ((p[0] << 8) | p[1]) << shift; *((guint16 *) p) = v; p += 2; } } return 0; } static void vips_foreign_load_heif_minimise(VipsObject *object, VipsForeignLoadHeif *heif) { vips_source_minimise(heif->source); } static int vips_foreign_load_heif_load(VipsForeignLoad *load) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) load; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(load), 3); #ifdef DEBUG printf("vips_foreign_load_heif_load: loading image\n"); #endif /*DEBUG*/ t[0] = vips_image_new(); if (vips_foreign_load_heif_set_header(heif, t[0])) return -1; /* Close input immediately at end of read. */ g_signal_connect(t[0], "minimise", G_CALLBACK(vips_foreign_load_heif_minimise), heif); if (vips_image_generate(t[0], NULL, vips_foreign_load_heif_generate, NULL, heif, NULL) || vips_sequential(t[0], &t[1], NULL) || vips_image_write(t[1], load->real)) return -1; if (vips_source_decode(heif->source)) return -1; return 0; } static void vips_foreign_load_heif_class_init(VipsForeignLoadHeifClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; vips__heif_init(); gobject_class->dispose = vips_foreign_load_heif_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifload_base"; object_class->description = _("load a HEIF image"); object_class->build = vips_foreign_load_heif_build; load_class->get_flags = vips_foreign_load_heif_get_flags; load_class->header = vips_foreign_load_heif_header; load_class->load = vips_foreign_load_heif_load; VIPS_ARG_INT(class, "page", 2, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeif, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 3, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeif, n), -1, 100000, 1); VIPS_ARG_BOOL(class, "thumbnail", 4, _("Thumbnail"), _("Fetch thumbnail image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeif, thumbnail), FALSE); VIPS_ARG_BOOL(class, "autorotate", 21, _("Autorotate"), _("Rotate image using exif orientation"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoadHeif, autorotate), FALSE); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VIPS_ARG_BOOL(class, "unlimited", 22, _("Unlimited"), _("Remove all denial of service limits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeif, unlimited), FALSE); #endif } static gint64 vips_foreign_load_heif_get_position(void *userdata) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata; return vips_source_seek(heif->source, 0L, SEEK_CUR); } /* libheif read() does not work like unix read(). * * This method is cannot return EOF. Instead, the separate wait_for_file_size() * is called beforehand to make sure that there's enough data there. */ static int vips_foreign_load_heif_read(void *data, size_t size, void *userdata) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata; while (size > 0) { gint64 bytes_read; bytes_read = vips_source_read(heif->source, data, size); if (bytes_read <= 0) return -1; size -= bytes_read; data = (char *) data + bytes_read; } return 0; } static int vips_foreign_load_heif_seek(gint64 position, void *userdata) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata; /* Return 0 on success. */ return vips_source_seek(heif->source, position, SEEK_SET) == -1; } /* libheif calls this to mean "I intend to read() to this position, please * check it is OK". */ static enum heif_reader_grow_status vips_foreign_load_heif_wait_for_file_size(gint64 target_size, void *userdata) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata; gint64 old_position; gint64 result; enum heif_reader_grow_status status; /* We seek the VipsSource to the position and check for errors. */ old_position = vips_source_seek(heif->source, 0L, SEEK_CUR); result = vips_source_seek(heif->source, target_size, SEEK_SET); vips_source_seek(heif->source, old_position, SEEK_SET); if (result < 0 || old_position < 0) /* Unable to seek to this point, so it's beyond EOF. */ status = heif_reader_grow_status_size_beyond_eof; else /* Successfully read to the requested point, but the requested * point is not necessarily EOF. */ status = heif_reader_grow_status_size_reached; return status; } static void vips_foreign_load_heif_init(VipsForeignLoadHeif *heif) { heif->n = 1; heif->reader = VIPS_ARRAY(NULL, 1, struct heif_reader); /* The first version to support heif_reader. */ heif->reader->reader_api_version = 1; heif->reader->get_position = vips_foreign_load_heif_get_position; heif->reader->read = vips_foreign_load_heif_read; heif->reader->seek = vips_foreign_load_heif_seek; heif->reader->wait_for_file_size = vips_foreign_load_heif_wait_for_file_size; } typedef struct _VipsForeignLoadHeifFile { VipsForeignLoadHeif parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadHeifFile; typedef VipsForeignLoadHeifClass VipsForeignLoadHeifFileClass; G_DEFINE_TYPE(VipsForeignLoadHeifFile, vips_foreign_load_heif_file, vips_foreign_load_heif_get_type()); static int vips_foreign_load_heif_file_build(VipsObject *object) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object; VipsForeignLoadHeifFile *file = (VipsForeignLoadHeifFile *) object; if (file->filename && !(heif->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_heif_file_parent_class) ->build(object); } static int vips_foreign_load_heif_file_is_a(const char *filename) { char buf[12]; if (vips__get_bytes(filename, (unsigned char *) buf, 12) != 12) return 0; return vips_foreign_load_heif_is_a(buf, 12); } static void vips_foreign_load_heif_file_class_init(VipsForeignLoadHeifFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifload"; object_class->build = vips_foreign_load_heif_file_build; foreign_class->suffs = vips__heif_suffs; load_class->is_a = vips_foreign_load_heif_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeifFile, filename), NULL); } static void vips_foreign_load_heif_file_init(VipsForeignLoadHeifFile *file) { } typedef struct _VipsForeignLoadHeifBuffer { VipsForeignLoadHeif parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadHeifBuffer; typedef VipsForeignLoadHeifClass VipsForeignLoadHeifBufferClass; G_DEFINE_TYPE(VipsForeignLoadHeifBuffer, vips_foreign_load_heif_buffer, vips_foreign_load_heif_get_type()); static int vips_foreign_load_heif_buffer_build(VipsObject *object) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object; VipsForeignLoadHeifBuffer *buffer = (VipsForeignLoadHeifBuffer *) object; if (buffer->buf && !(heif->source = vips_source_new_from_memory( VIPS_AREA(buffer->buf)->data, VIPS_AREA(buffer->buf)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_heif_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_heif_buffer_is_a(const void *buf, size_t len) { return vips_foreign_load_heif_is_a(buf, len); } static void vips_foreign_load_heif_buffer_class_init( VipsForeignLoadHeifBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifload_buffer"; object_class->build = vips_foreign_load_heif_buffer_build; load_class->is_a_buffer = vips_foreign_load_heif_buffer_is_a; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeifBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_heif_buffer_init(VipsForeignLoadHeifBuffer *buffer) { } typedef struct _VipsForeignLoadHeifSource { VipsForeignLoadHeif parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadHeifSource; typedef VipsForeignLoadHeifClass VipsForeignLoadHeifSourceClass; G_DEFINE_TYPE(VipsForeignLoadHeifSource, vips_foreign_load_heif_source, vips_foreign_load_heif_get_type()); static int vips_foreign_load_heif_source_build(VipsObject *object) { VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object; VipsForeignLoadHeifSource *source = (VipsForeignLoadHeifSource *) object; if (source->source) { heif->source = source->source; g_object_ref(heif->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_heif_source_parent_class) ->build(object); } static gboolean vips_foreign_load_heif_source_is_a_source(VipsSource *source) { const char *p; return (p = (const char *) vips_source_sniff(source, 12)) && vips_foreign_load_heif_is_a(p, 12); } static void vips_foreign_load_heif_source_class_init( VipsForeignLoadHeifSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifload_source"; object_class->build = vips_foreign_load_heif_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_heif_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadHeifSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_heif_source_init(VipsForeignLoadHeifSource *source) { } #endif /*HAVE_HEIF*/ /* The C API wrappers are defined in foreign.c. */ libvips-8.18.2/libvips/foreign/heifsave.c000066400000000000000000000652341516303661500203410ustar00rootroot00000000000000/* save to heif * * 5/7/18 * - from niftisave.c * 3/7/19 [lovell] * - add "compression" option * 1/9/19 [meyermarcel] * - save alpha when necessary * 15/3/20 * - revise for new VipsTarget API * 14/2/21 kleisauke * - move GObject part to vips2heif.c * 30/7/21 * - rename "speed" as "effort" for consistency with other savers * 22/12/21 * - add >8 bit support * 22/10/11 * - improve rules for 16-bit write [johntrunc] */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_HEIF #include #include #include #include #include #include "pforeign.h" #include typedef struct _VipsForeignSaveHeif { VipsForeignSave parent_object; /* Where to write (set by subclasses). */ VipsTarget *target; /* Coding quality factor (1 - 100). */ int Q; /* bitdepth to save at for >8 bit images. */ int bitdepth; /* Lossless compression. */ gboolean lossless; /* Compression format */ VipsForeignHeifCompression compression; /* CPU effort (0 - 9). */ int effort; /* Chroma subsampling. */ VipsForeignSubsample subsample_mode; /* Encoder to use. For instance: aom, svt etc. */ VipsForeignHeifEncoder selected_encoder; int page_width; int page_height; int n_pages; struct heif_context *ctx; struct heif_encoder *encoder; /* The current page we are writing. */ struct heif_image_handle *handle; /* The current page in memory which we build as we scan down the * image. */ struct heif_image *img; /* The libheif memory area we fill with pixels from the libvips * pipe. */ uint8_t *data; int stride; /* Deprecated ... this is now called effort for consistency with the * other encoders. */ int speed; /* Tuning parameters. */ const char *tune; } VipsForeignSaveHeif; typedef VipsForeignSaveClass VipsForeignSaveHeifClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveHeif, vips_foreign_save_heif, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_heif_dispose(GObject *gobject) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) gobject; VIPS_UNREF(heif->target); VIPS_FREEF(heif_image_release, heif->img); VIPS_FREEF(heif_image_handle_release, heif->handle); VIPS_FREEF(heif_encoder_release, heif->encoder); VIPS_FREEF(heif_context_free, heif->ctx); G_OBJECT_CLASS(vips_foreign_save_heif_parent_class)->dispose(gobject); } typedef struct heif_error (*libheif_metadata_fn)(struct heif_context *, const struct heif_image_handle *, const void *, int); /* String-based metadata fields we add. */ typedef struct _VipsForeignSaveHeifMetadata { const char *name; /* as understood by libvips */ libheif_metadata_fn saver; /* as understood by libheif */ } VipsForeignSaveHeifMetadata; static VipsForeignSaveHeifMetadata libheif_metadata[] = { { VIPS_META_EXIF_NAME, heif_context_add_exif_metadata }, { VIPS_META_XMP_NAME, heif_context_add_XMP_metadata } }; static int vips_foreign_save_heif_write_metadata(VipsForeignSaveHeif *heif) { VipsForeignSave *save = (VipsForeignSave *) heif; struct heif_error error; for (int i = 0; i < VIPS_NUMBER(libheif_metadata); i++) { const char *vips_name = libheif_metadata[i].name; libheif_metadata_fn heif_saver = libheif_metadata[i].saver; if (vips_image_get_typeof(save->ready, vips_name)) { const void *data; size_t length; #ifdef DEBUG printf("attaching %s ..\n", vips_name); #endif /*DEBUG*/ if (vips_image_get_blob(save->ready, vips_name, &data, &length)) return -1; error = heif_saver(heif->ctx, heif->handle, data, length); if (error.code) { vips__heif_error(&error); return -1; } } } return 0; } static int vips_foreign_save_heif_add_icc(VipsForeignSaveHeif *heif, const void *profile, size_t length) { #ifdef DEBUG printf("attaching profile ..\n"); #endif /*DEBUG*/ struct heif_error error; error = heif_image_set_raw_color_profile(heif->img, "rICC", profile, length); if (error.code) { vips__heif_error(&error); return -1; } return 0; } static int vips_foreign_save_heif_add_custom_icc(VipsForeignSaveHeif *heif, const char *profile) { VipsBlob *blob; if (vips_profile_load(profile, &blob, NULL)) return -1; if (blob) { size_t length; const void *data = vips_blob_get(blob, &length); if (vips_foreign_save_heif_add_icc(heif, data, length)) { vips_area_unref((VipsArea *) blob); return -1; } vips_area_unref((VipsArea *) blob); } return 0; } static int vips_foreign_save_heif_add_orig_icc(VipsForeignSaveHeif *heif) { VipsForeignSave *save = (VipsForeignSave *) heif; const void *data; size_t length; if (vips_image_get_blob(save->ready, VIPS_META_ICC_NAME, &data, &length)) return -1; if (vips_foreign_save_heif_add_icc(heif, data, length)) return -1; return 0; } static int vips_foreign_save_heif_write_page(VipsForeignSaveHeif *heif, int page) { VipsForeignSave *save = (VipsForeignSave *) heif; struct heif_error error; struct heif_encoding_options *options; #ifdef HAVE_HEIF_ENCODING_OPTIONS_OUTPUT_NCLX_PROFILE struct heif_color_profile_nclx *nclx = NULL; #endif /* A profile supplied as an argument overrides an embedded * profile. */ if (save->profile) { if (vips_foreign_save_heif_add_custom_icc(heif, save->profile)) return -1; } else if (vips_image_get_typeof(save->ready, VIPS_META_ICC_NAME)) { if (vips_foreign_save_heif_add_orig_icc(heif)) return -1; } options = heif_encoding_options_alloc(); options->save_alpha_channel = save->ready->Bands > 3; #ifdef HAVE_HEIF_ENCODING_OPTIONS_OUTPUT_NCLX_PROFILE /* Matrix coefficients have to be identity (CICP x/y/0) in lossless * mode. */ if (heif->lossless) { if (!(nclx = heif_nclx_color_profile_alloc())) { heif_encoding_options_free(options); return -1; } nclx->matrix_coefficients = heif_matrix_coefficients_RGB_GBR; options->output_nclx_profile = nclx; /* Ensure nclx profile is actually written with libheif < v1.17.2. */ options->macOS_compatibility_workaround_no_nclx_profile = 0; } #endif /*HAVE_HEIF_ENCODING_OPTIONS_OUTPUT_NCLX_PROFILE*/ #ifdef HAVE_HEIF_ENCODING_OPTIONS_IMAGE_ORIENTATION /* EXIF orientation is informational in the HEIF specification. * Orientation is defined using irot and imir transformations. */ options->image_orientation = vips_image_get_orientation(save->ready); #endif #ifdef DEBUG GTimer *timer = g_timer_new(); printf("calling heif_context_encode_image() ...\n"); #endif /*DEBUG*/ error = heif_context_encode_image(heif->ctx, heif->img, heif->encoder, options, &heif->handle); #ifdef DEBUG printf("... libheif took %.2g seconds\n", g_timer_elapsed(timer, NULL)); g_timer_destroy(timer); #endif /*DEBUG*/ heif_encoding_options_free(options); #ifdef HAVE_HEIF_ENCODING_OPTIONS_OUTPUT_NCLX_PROFILE VIPS_FREEF(heif_nclx_color_profile_free, nclx); #endif if (error.code) { vips__heif_error(&error); return -1; } if (vips_image_get_typeof(save->ready, "heif-primary")) { int primary; if (vips_image_get_int(save->ready, "heif-primary", &primary)) return -1; if (page == primary) { error = heif_context_set_primary_image(heif->ctx, heif->handle); if (error.code) { vips__heif_error(&error); return -1; } } } if (vips_foreign_save_heif_write_metadata(heif)) return -1; VIPS_FREEF(heif_image_handle_release, heif->handle); return 0; } static int vips_foreign_save_heif_pack(VipsForeignSaveHeif *heif, VipsPel *q, VipsPel *p, int ne) { VipsForeignSave *save = (VipsForeignSave *) heif; int i; if (save->ready->BandFmt == VIPS_FORMAT_UCHAR && heif->bitdepth == 8) /* Most common case -- 8 bit to 8 bit. */ memcpy(q, p, ne); else if (save->ready->BandFmt == VIPS_FORMAT_UCHAR && heif->bitdepth > 8) { /* 8-bit source, write a bigendian short, shifted up. */ int shift = heif->bitdepth - 8; for (i = 0; i < ne; i++) { guint16 v = p[i] << shift; q[0] = v >> 8; q[1] = v; q += 2; } } else if (save->ready->BandFmt == VIPS_FORMAT_USHORT && heif->bitdepth <= 8) { /* 16-bit native byte order source, 8 bit write. * * Pick the high or low bits of the source. */ int vips_bitdepth = save->ready->Type == VIPS_INTERPRETATION_RGB16 || save->ready->Type == VIPS_INTERPRETATION_GREY16 ? 16 : 8; int shift = vips_bitdepth - heif->bitdepth; for (i = 0; i < ne; i++) { guint16 v = *((gushort *) p) >> shift; q[i] = VIPS_MIN(v, UCHAR_MAX); p += 2; } } else if (save->ready->BandFmt == VIPS_FORMAT_USHORT && heif->bitdepth > 8) { /* 16-bit native byte order source, 16 bit bigendian write. */ int vips_bitdepth = save->ready->Type == VIPS_INTERPRETATION_RGB16 || save->ready->Type == VIPS_INTERPRETATION_GREY16 ? 16 : 8; int shift = vips_bitdepth - heif->bitdepth; for (i = 0; i < ne; i++) { guint16 v = *((gushort *) p) >> shift; q[0] = v >> 8; q[1] = v; p += 2; q += 2; } } else { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(heif); vips_error(class->nickname, "%s", _("unimplemented format conversion")); return -1; } return 0; } static int vips_foreign_save_heif_write_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) a; int y; #ifdef DEBUG printf("vips_foreign_save_heif_write_block: y = %d\n", area->top); #endif /*DEBUG*/ /* Copy a line at a time into our output image, write each time the * image fills. */ for (y = 0; y < area->height; y++) { /* Y in page. */ int page = (area->top + y) / heif->page_height; int line = (area->top + y) % heif->page_height; VipsPel *p = VIPS_REGION_ADDR(region, 0, area->top + y); VipsPel *q = heif->data + (size_t) heif->stride * line; if (vips_foreign_save_heif_pack(heif, q, p, VIPS_REGION_N_ELEMENTS(region))) return -1; /* Did we just write the final line? Write as a new page * into the output. */ if (line == heif->page_height - 1) if (vips_foreign_save_heif_write_page(heif, page)) return -1; } return 0; } struct heif_error vips_foreign_save_heif_write(struct heif_context *ctx, const void *data, size_t length, void *userdata) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) userdata; struct heif_error error; #ifdef HAVE_HEIF_ERROR_SUCCESS error = heif_error_success; #else error.code = heif_error_Ok; #endif /*HAVE_HEIF_ERROR_SUCCESS*/ if (vips_target_write(heif->target, data, length)) { error.code = heif_error_Encoding_error; error.subcode = heif_suberror_Cannot_write_output_data; error.message = "Cannot write output data"; } return error; } static int vips_foreign_save_heif_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object; struct heif_error error; struct heif_writer writer; char *chroma; const struct heif_encoder_descriptor *out_encoder; #ifdef HAVE_HEIF_ENCODER_PARAMETER_GET_VALID_INTEGER_VALUES const struct heif_encoder_parameter *const *param; #endif gboolean has_alpha; if (VIPS_OBJECT_CLASS(vips_foreign_save_heif_parent_class)->build(object)) return -1; /* If the old, deprecated "speed" param is being used and the new * "effort" param is not, use speed to init effort. */ if (vips_object_argument_isset(object, "speed") && !vips_object_argument_isset(object, "effort")) heif->effort = 9 - heif->speed; /* The "lossless" param implies no chroma subsampling. */ if (heif->lossless) heif->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_OFF; /* Default 12 bit save for 16-bit images. */ if (!vips_object_argument_isset(object, "bitdepth")) heif->bitdepth = save->ready->Type == VIPS_INTERPRETATION_RGB16 || save->ready->Type == VIPS_INTERPRETATION_GREY16 ? 12 : 8; /* HEIC and AVIF only implements 8 / 10 / 12 bit depth. */ if (heif->bitdepth != 12 && heif->bitdepth != 10 && heif->bitdepth != 8) { vips_error("heifsave", _("%d-bit colour depth not supported"), heif->bitdepth); return -1; } /* Try to find the selected encoder. */ if (heif->selected_encoder != VIPS_FOREIGN_HEIF_ENCODER_AUTO) { const int count = heif_context_get_encoder_descriptors( heif->ctx, (enum heif_compression_format) heif->compression, vips_enum_nick(VIPS_TYPE_FOREIGN_HEIF_ENCODER, heif->selected_encoder), &out_encoder, 1); if (count > 0) error = heif_context_get_encoder(heif->ctx, out_encoder, &heif->encoder); else g_warning("heifsave: could not find %s", vips_enum_nick(VIPS_TYPE_FOREIGN_HEIF_ENCODER, heif->selected_encoder)); } /* Fallback to default encoder. */ if (!heif->encoder) error = heif_context_get_encoder_for_format(heif->ctx, (enum heif_compression_format) heif->compression, &heif->encoder); if (error.code) { if (error.code == heif_error_Unsupported_filetype) vips_error("heifsave", "%s", _("Unsupported compression")); else vips__heif_error(&error); return -1; } error = heif_encoder_set_lossy_quality(heif->encoder, heif->Q); if (error.code) { vips__heif_error(&error); return -1; } error = heif_encoder_set_lossless(heif->encoder, heif->lossless); if (error.code) { vips__heif_error(&error); return -1; } error = heif_encoder_set_parameter_integer(heif->encoder, "speed", 9 - heif->effort); if (error.code && error.subcode != heif_suberror_Unsupported_parameter) { vips__heif_error(&error); return -1; } chroma = heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF || (heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO && heif->Q >= 90) ? "444" : "420"; error = heif_encoder_set_parameter_string(heif->encoder, "chroma", chroma); if (error.code && error.subcode != heif_suberror_Unsupported_parameter) { vips__heif_error(&error); return -1; } #ifdef HAVE_HEIF_ENCODER_PARAMETER_GET_VALID_INTEGER_VALUES for (param = heif_encoder_list_parameters(heif->encoder); *param; param++) { int have_minimum; int have_maximum; int minimum; int maximum; if (strcmp(heif_encoder_parameter_get_name(*param), "threads") != 0) continue; error = heif_encoder_parameter_get_valid_integer_values(*param, &have_minimum, &have_maximum, &minimum, &maximum, NULL, NULL); if (error.code) { vips__heif_error(&error); return -1; } error = heif_encoder_set_parameter_integer(heif->encoder, "threads", VIPS_CLIP(minimum, vips_concurrency_get(), maximum)); if (error.code && error.subcode != heif_suberror_Unsupported_parameter) { vips__heif_error(&error); return -1; } } #endif /*HAVE_HEIF_ENCODER_PARAMETER_GET_VALID_INTEGER_VALUES*/ /* Try to enable auto_tiles. This can make AVIF encoding a lot faster, * with only a very small increase in file size. */ error = heif_encoder_set_parameter_boolean(heif->encoder, "auto-tiles", TRUE); if (error.code && error.subcode != heif_suberror_Unsupported_parameter) { vips__heif_error(&error); return -1; } /* Try to prevent the AVIF encoder from using intra block copy, * helps ensure encoding time is more predictable. */ error = heif_encoder_set_parameter_boolean(heif->encoder, "enable-intrabc", FALSE); if (error.code && error.subcode != heif_suberror_Unsupported_parameter) { vips__heif_error(&error); return -1; } if (heif->tune) { error = heif_encoder_set_parameter_string(heif->encoder, "tune", heif->tune); if (error.code && error.subcode != heif_suberror_Unsupported_parameter) { vips__heif_error(&error); return -1; } } /* TODO .. support extra per-encoder params with * heif_encoder_list_parameters(). */ heif->page_width = save->ready->Xsize; heif->page_height = vips_image_get_page_height(save->ready); heif->n_pages = save->ready->Ysize / heif->page_height; has_alpha = save->ready->Bands > 3; if (heif->page_width > 16384 || heif->page_height > 16384) { vips_error("heifsave", _("image too large")); return -1; } /* Make a heif image the size of a page. We send sink_disc() output * here and write a frame each time it fills. */ #ifdef DEBUG printf("vips_foreign_save_heif_build:\n"); printf("\twidth = %d\n", heif->page_width); printf("\theight = %d\n", heif->page_height); printf("\talpha = %d\n", has_alpha); #endif /*DEBUG*/ error = heif_image_create(heif->page_width, heif->page_height, heif_colorspace_RGB, vips__heif_chroma(heif->bitdepth, has_alpha), &heif->img); if (error.code) { vips__heif_error(&error); return -1; } error = heif_image_add_plane(heif->img, heif_channel_interleaved, heif->page_width, heif->page_height, heif->bitdepth); if (error.code) { vips__heif_error(&error); return -1; } #ifdef DEBUG vips__heif_image_print(heif->img); #endif /*DEBUG*/ heif->data = heif_image_get_plane(heif->img, heif_channel_interleaved, &heif->stride); /* Write data. */ if (vips_sink_disc(save->ready, vips_foreign_save_heif_write_block, heif)) return -1; /* This has to come right at the end :-( so there's no support for * incremental writes. */ writer.writer_api_version = 1; writer.write = vips_foreign_save_heif_write; error = heif_context_write(heif->ctx, &writer, heif); if (error.code) { vips__heif_error(&error); return -1; } if (vips_target_end(heif->target)) return -1; return 0; } #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT /* Except for 8-bit inputs, we send everything else to 16. We decide on 8-bit * vs. 12 bit save based on Type in_build(), see above. */ static VipsBandFormat vips_heif_bandfmt[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, US, US, US, US, US, US }; static void vips_foreign_save_heif_class_init(VipsForeignSaveHeifClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; vips__heif_init(); gobject_class->dispose = vips_foreign_save_heif_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifsave_base"; object_class->description = _("save image in HEIF format"); object_class->build = vips_foreign_save_heif_build; save_class->saveable = VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA; save_class->format_table = vips_heif_bandfmt; VIPS_ARG_INT(class, "Q", 10, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, Q), 1, 100, 50); VIPS_ARG_INT(class, "bitdepth", 11, _("Bit depth"), _("Number of bits per pixel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, bitdepth), 8, 12, 12); VIPS_ARG_BOOL(class, "lossless", 13, _("Lossless"), _("Enable lossless compression"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, lossless), FALSE); VIPS_ARG_ENUM(class, "compression", 14, _("Compression"), _("Compression format"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, compression), VIPS_TYPE_FOREIGN_HEIF_COMPRESSION, VIPS_FOREIGN_HEIF_COMPRESSION_HEVC); VIPS_ARG_INT(class, "effort", 15, _("Effort"), _("CPU effort"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, effort), 0, 9, 4); VIPS_ARG_ENUM(class, "subsample_mode", 16, _("Subsample mode"), _("Select chroma subsample operation mode"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, subsample_mode), VIPS_TYPE_FOREIGN_SUBSAMPLE, VIPS_FOREIGN_SUBSAMPLE_AUTO); VIPS_ARG_INT(class, "speed", 17, _("Speed"), _("CPU effort"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveHeif, speed), 0, 9, 5); VIPS_ARG_ENUM(class, "encoder", 18, _("Encoder"), _("Select encoder to use"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, selected_encoder), VIPS_TYPE_FOREIGN_HEIF_ENCODER, VIPS_FOREIGN_HEIF_ENCODER_AUTO); VIPS_ARG_STRING(class, "tune", 19, _("Tune"), _("Tuning parameters"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeif, tune), NULL); } static void vips_foreign_save_heif_init(VipsForeignSaveHeif *heif) { heif->ctx = heif_context_alloc(); heif->Q = 50; heif->bitdepth = 12; heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_HEVC; heif->effort = 4; heif->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_AUTO; /* Deprecated. */ heif->speed = 5; } typedef struct _VipsForeignSaveHeifFile { VipsForeignSaveHeif parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveHeifFile; typedef VipsForeignSaveHeifClass VipsForeignSaveHeifFileClass; G_DEFINE_TYPE(VipsForeignSaveHeifFile, vips_foreign_save_heif_file, vips_foreign_save_heif_get_type()); static int vips_foreign_save_heif_file_build(VipsObject *object) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object; VipsForeignSaveHeifFile *file = (VipsForeignSaveHeifFile *) object; if (file->filename && !(heif->target = vips_target_new_to_file(file->filename))) return -1; if (vips_iscasepostfix(file->filename, ".avif")) heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1; return VIPS_OBJECT_CLASS(vips_foreign_save_heif_file_parent_class) ->build(object); } static void vips_foreign_save_heif_file_class_init(VipsForeignSaveHeifFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifsave"; object_class->build = vips_foreign_save_heif_file_build; foreign_class->suffs = vips__heif_suffs; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeifFile, filename), NULL); } static void vips_foreign_save_heif_file_init(VipsForeignSaveHeifFile *file) { } typedef struct _VipsForeignSaveHeifBuffer { VipsForeignSaveHeif parent_object; /* Save to a buffer. */ VipsArea *buf; } VipsForeignSaveHeifBuffer; typedef VipsForeignSaveHeifClass VipsForeignSaveHeifBufferClass; G_DEFINE_TYPE(VipsForeignSaveHeifBuffer, vips_foreign_save_heif_buffer, vips_foreign_save_heif_get_type()); static int vips_foreign_save_heif_buffer_build(VipsObject *object) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object; VipsForeignSaveHeifBuffer *buffer = (VipsForeignSaveHeifBuffer *) object; VipsBlob *blob; if (!(heif->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_heif_buffer_parent_class) ->build(object)) return -1; g_object_get(heif->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_heif_buffer_class_init( VipsForeignSaveHeifBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifsave_buffer"; object_class->build = vips_foreign_save_heif_buffer_build; foreign_class->suffs = vips__heic_suffs; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveHeifBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_heif_buffer_init(VipsForeignSaveHeifBuffer *buffer) { } typedef struct _VipsForeignSaveHeifTarget { VipsForeignSaveHeif parent_object; VipsTarget *target; } VipsForeignSaveHeifTarget; typedef VipsForeignSaveHeifClass VipsForeignSaveHeifTargetClass; G_DEFINE_TYPE(VipsForeignSaveHeifTarget, vips_foreign_save_heif_target, vips_foreign_save_heif_get_type()); static int vips_foreign_save_heif_target_build(VipsObject *object) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object; VipsForeignSaveHeifTarget *target = (VipsForeignSaveHeifTarget *) object; if (target->target) { heif->target = target->target; g_object_ref(heif->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_heif_target_parent_class) ->build(object); } static void vips_foreign_save_heif_target_class_init( VipsForeignSaveHeifTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "heifsave_target"; object_class->build = vips_foreign_save_heif_target_build; foreign_class->suffs = vips__heic_suffs; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveHeifTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_heif_target_init(VipsForeignSaveHeifTarget *target) { } typedef VipsForeignSaveHeifTarget VipsForeignSaveAvifTarget; typedef VipsForeignSaveHeifTargetClass VipsForeignSaveAvifTargetClass; G_DEFINE_TYPE(VipsForeignSaveAvifTarget, vips_foreign_save_avif_target, vips_foreign_save_heif_target_get_type()); static void vips_foreign_save_avif_target_class_init( VipsForeignSaveAvifTargetClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "avifsave_target"; object_class->description = _("save image in AVIF format"); foreign_class->suffs = vips__avif_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_avif_target_init(VipsForeignSaveAvifTarget *target) { VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) target; heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1; } #endif /*HAVE_HEIF*/ /* The C API wrappers are defined in foreign.c. */ libvips-8.18.2/libvips/foreign/jp2kload.c000066400000000000000000001246101516303661500202470ustar00rootroot00000000000000/* load jpeg2000 * * 18/3/20 * - from heifload.c * 4/11/21 * - add untiled load * 17/1/22 * - left-justify bits for eg. 12-bit read * 13/3/23 MathemanFlo * - add bits per sample metadata * 18/9/24 * - revise offset handling * - test that decoded image matches header */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_LIBOPENJP2 #include #include "pforeign.h" /* Surely enough ... does anyone do multispectral imaging with jp2k? */ #define MAX_BANDS (100) typedef struct _VipsForeignLoadJp2k { VipsForeignLoad parent_object; /* Source to load from (set by subclasses). */ VipsSource *source; /* Page set by user, then we translate that into shrink factor. */ int page; int shrink; /* Load images a frame at a time rather than a tile at a time. */ gboolean oneshot; /* Decompress state. */ opj_stream_t *stream; /* Source as an opj stream */ OPJ_CODEC_FORMAT codec_format; /* libopenjp2 format */ opj_codec_t *codec; /* Decompress codec */ opj_dparameters_t parameters; /* Core decompress params */ opj_image_t *image; /* Read image to here */ opj_codestream_info_v2_t *info; /* Tile geometry */ /* Geometry of full size image */ int opj_x0; int opj_y0; int opj_x1; int opj_y1; /* Size of the image we generate. */ int width; int height; /* Number of errors reported during load -- use this to block load of * corrupted images. */ int n_errors; /* If we need to upsample tiles read from opj. */ gboolean upsample; /* If we need to do ycc->rgb conversion on load. */ gboolean ycc_to_rgb; } VipsForeignLoadJp2k; typedef VipsForeignLoadClass VipsForeignLoadJp2kClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadJp2k, vips_foreign_load_jp2k, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_jp2k_dispose(GObject *gobject) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) gobject; #ifdef DEBUG printf("vips_foreign_load_jp2k_dispose:\n"); #endif /*DEBUG*/ /* * FIXME ... do we need this? seems to just cause warnings * if (jp2k->codec && jp2k->stream) opj_end_decompress(jp2k->codec, jp2k->stream); * */ if (jp2k->info) opj_destroy_cstr_info(&jp2k->info); VIPS_FREEF(opj_destroy_codec, jp2k->codec); VIPS_FREEF(opj_stream_destroy, jp2k->stream); VIPS_FREEF(opj_image_destroy, jp2k->image); VIPS_UNREF(jp2k->source); G_OBJECT_CLASS(vips_foreign_load_jp2k_parent_class)->dispose(gobject); } static OPJ_SIZE_T vips_foreign_load_jp2k_read_source(void *buffer, size_t length, void *client) { VipsSource *source = VIPS_SOURCE(client); gint64 bytes_read = vips_source_read(source, buffer, length); /* openjpeg read uses -1 for both EOF and error return. */ return bytes_read == 0 ? -1 : bytes_read; } static OPJ_OFF_T vips_foreign_load_jp2k_skip_source(OPJ_OFF_T n_bytes, void *client) { VipsSource *source = VIPS_SOURCE(client); if (vips_source_seek(source, n_bytes, SEEK_CUR) == -1) /* openjpeg skip uses -1 for both end of stream and error. */ return -1; return n_bytes; } static OPJ_BOOL vips_foreign_load_jp2k_seek_source(OPJ_OFF_T position, void *client) { VipsSource *source = VIPS_SOURCE(client); if (vips_source_seek(source, position, SEEK_SET) == -1) /* openjpeg seek uses FALSE for both end of stream and error. */ return OPJ_FALSE; return OPJ_TRUE; } /* Make a libopenjp2 stream that wraps a VipsSource. */ static opj_stream_t * vips_foreign_load_jp2k_stream(VipsSource *source) { opj_stream_t *stream; /* TRUE means a read stream. */ if (!(stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, TRUE))) return NULL; opj_stream_set_user_data(stream, source, NULL); /* Unfortunately, jp2k requires the length, so pipe sources will have * to buffer in memory. */ opj_stream_set_user_data_length(stream, vips_source_length(source)); opj_stream_set_read_function(stream, vips_foreign_load_jp2k_read_source); opj_stream_set_skip_function(stream, vips_foreign_load_jp2k_skip_source); opj_stream_set_seek_function(stream, vips_foreign_load_jp2k_seek_source); return stream; } static int vips_foreign_load_jp2k_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) object; #ifdef DEBUG printf("vips_foreign_load_jp2k_build:\n"); #endif /*DEBUG*/ /* Default parameters. */ jp2k->parameters.decod_format = -1; jp2k->parameters.cod_format = -1; opj_set_default_decoder_parameters(&jp2k->parameters); /* Link the openjpeg stream to our VipsSource. */ if (jp2k->source) { jp2k->stream = vips_foreign_load_jp2k_stream(jp2k->source); if (!jp2k->stream) { vips_error(class->nickname, "%s", _("unable to create jp2k stream")); return -1; } } return VIPS_OBJECT_CLASS(vips_foreign_load_jp2k_parent_class) ->build(object); } #define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a" #define JP2_MAGIC "\x0d\x0a\x87\x0a" /* position 45: "\xff\x52" */ #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51" /* OpenJPEG supports several different codecs. */ static OPJ_CODEC_FORMAT vips_foreign_load_jp2k_get_codec_format(VipsSource *source) { unsigned char *data; if (vips_source_sniff_at_most(source, &data, 12) < 12) return -1; /* There's also OPJ_CODEC_JPT for xxx.jpt files, but we don't support * that. */ if (memcmp(data, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(data, JP2_MAGIC, 4) == 0) return OPJ_CODEC_JP2; else if (memcmp(data, J2K_CODESTREAM_MAGIC, 4) == 0) return OPJ_CODEC_J2K; else return -1; } static gboolean vips_foreign_load_jp2k_is_a_source(VipsSource *source) { return vips_foreign_load_jp2k_get_codec_format(source) != -1; } static VipsForeignFlags vips_foreign_load_jp2k_get_flags(VipsForeignLoad *load) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) load; if (jp2k->oneshot) return VIPS_FOREIGN_SEQUENTIAL; else return VIPS_FOREIGN_PARTIAL; } /* The openjpeg info and warning callbacks are incredibly chatty. */ static void vips_foreign_load_jp2k_info_callback(const char *msg, void *client) { #ifdef DEBUG VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(client); g_info("%s: %s", class->nickname, msg); #endif /*DEBUG*/ } /* The openjpeg info and warning callbacks are incredibly chatty. */ static void vips_foreign_load_jp2k_warning_callback(const char *msg, void *client) { #ifdef DEBUG VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(client); g_warning("%s: %s", class->nickname, msg); #endif /*DEBUG*/ } static void vips_foreign_load_jp2k_error_callback(const char *msg, void *client) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) client; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jp2k); #ifdef DEBUG printf("%s: %s", class->nickname, msg); #endif /*DEBUG*/ vips_error(class->nickname, "%s", msg); jp2k->n_errors += 1; } static void vips_foreign_load_jp2k_attach_handlers(VipsForeignLoadJp2k *jp2k, opj_codec_t *codec) { opj_set_info_handler(codec, vips_foreign_load_jp2k_info_callback, jp2k); opj_set_warning_handler(codec, vips_foreign_load_jp2k_warning_callback, jp2k); opj_set_error_handler(codec, vips_foreign_load_jp2k_error_callback, jp2k); } #ifdef DEBUG static const char * colorspace2char(OPJ_COLOR_SPACE color_space) { switch (color_space) { case OPJ_CLRSPC_UNKNOWN: return("OPJ_CLRSPC_UNKNOWN"); case OPJ_CLRSPC_UNSPECIFIED: return("OPJ_CLRSPC_UNSPECIFIED"); case OPJ_CLRSPC_SRGB: return("OPJ_CLRSPC_SRGB"); case OPJ_CLRSPC_GRAY: return("OPJ_CLRSPC_GRAY"); case OPJ_CLRSPC_SYCC: return("OPJ_CLRSPC_SYCC"); case OPJ_CLRSPC_EYCC: return("OPJ_CLRSPC_EYCC"); case OPJ_CLRSPC_CMYK: return("OPJ_CLRSPC_CMYK"); default: return(""); } } static void vips_foreign_load_jp2k_print_image(opj_image_t *image) { printf("image:\n"); printf("x0 = %u, y0 = %u, x1 = %u, y1 = %u, numcomps = %u\n", image->x0, image->y0, image->x1, image->y1, image->numcomps); printf("color_space = %u (%s)\n", image->color_space, colorspace2char(image->color_space)); printf("icc_profile_buf = %p, icc_profile_len = %x\n", image->icc_profile_buf, image->icc_profile_len); printf("components:\n"); for (int i = 0; i < image->numcomps; i++) { opj_image_comp_t *this = &image->comps[i]; printf("%i) dx = %u, dy = %u, w = %u, h = %u, " "x0 = %u, y0 = %u\n", i, this->dx, this->dy, this->w, this->h, this->x0, this->y0); printf(" prec = %d, sgnd = %x, resno_decoded = %u, factor = %u\n", this->prec, this->sgnd, this->resno_decoded, this->factor); printf(" data = %p, alpha = %u\n", this->data, this->alpha); } } static void vips_foreign_load_jp2k_print(VipsForeignLoadJp2k *jp2k) { vips_foreign_load_jp2k_print_image(jp2k->image); printf("info:\n"); printf("tx0 = %u, ty0 = %d, tdx = %u, tdy = %u, tw = %u, th = %u\n", jp2k->info->tx0, jp2k->info->ty0, jp2k->info->tdx, jp2k->info->tdy, jp2k->info->tw, jp2k->info->th); printf("nbcomps = %u, tile_info = %p\n", jp2k->info->nbcomps, jp2k->info->tile_info); if (jp2k->info->tw == 1 && jp2k->info->th == 1) printf("untiled\n"); printf("opj_x0 = %d, opj_y0 = %d, opj_x1 = %d, opj_y1 = %d\n", jp2k->opj_x0, jp2k->opj_y0, jp2k->opj_x1, jp2k->opj_y1); printf("width = %d, height = %d\n", jp2k->width, jp2k->height); } #endif /*DEBUG*/ /* Pick a VipsBandFormat for an opj image. */ static VipsBandFormat vips_foreign_load_jp2k_get_format(opj_image_t *image) { opj_image_comp_t *first = &image->comps[0]; VipsBandFormat format; /* OpenJPEG only supports up to 31 bits per pixel. Treat it as 32. */ if (first->prec <= 8) format = first->sgnd ? VIPS_FORMAT_CHAR : VIPS_FORMAT_UCHAR; else if (first->prec <= 16) format = first->sgnd ? VIPS_FORMAT_SHORT : VIPS_FORMAT_USHORT; else format = first->sgnd ? VIPS_FORMAT_INT : VIPS_FORMAT_UINT; return format; } /* Pick an interpretation for a opj image. */ static VipsInterpretation vips_foreign_load_jp2k_get_interpretation(opj_image_t *image, VipsBandFormat format) { VipsInterpretation interpretation; switch (image->color_space) { case OPJ_CLRSPC_SYCC: case OPJ_CLRSPC_EYCC: /* Map these to RGB. */ interpretation = vips_format_sizeof(format) == 1 ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16; break; case OPJ_CLRSPC_GRAY: interpretation = vips_format_sizeof(format) == 1 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_GREY16; break; case OPJ_CLRSPC_SRGB: interpretation = vips_format_sizeof(format) == 1 ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16; break; case OPJ_CLRSPC_CMYK: interpretation = VIPS_INTERPRETATION_CMYK; break; case OPJ_CLRSPC_UNKNOWN: case OPJ_CLRSPC_UNSPECIFIED: /* Try to guess something sensible. */ if (image->numcomps < 3) interpretation = vips_format_sizeof(format) == 1 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_GREY16; else interpretation = vips_format_sizeof(format) == 1 ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16; break; default: interpretation = VIPS_INTERPRETATION_ERROR; break; } return interpretation; } static gboolean vips_foreign_load_jp2k_get_ycc(opj_image_t *image) { gboolean ycc; ycc = FALSE; /* Detect YCC input */ switch (image->color_space) { case OPJ_CLRSPC_SYCC: case OPJ_CLRSPC_EYCC: ycc = TRUE; break; case OPJ_CLRSPC_UNKNOWN: case OPJ_CLRSPC_UNSPECIFIED: /* Unspecified with three bands and subsampling on bands 2 and * 3 is usually YCC. */ if (image->numcomps == 3 && image->comps[0].dx == 1 && image->comps[0].dy == 1 && image->comps[1].dx > 1 && image->comps[1].dy > 1 && image->comps[2].dx > 1 && image->comps[2].dy > 1) ycc = TRUE; break; default: break; } return ycc; } static gboolean vips_foreign_load_jp2k_get_upsample(opj_image_t *image) { for (int i = 0; i < image->numcomps; i++) { opj_image_comp_t *this = &image->comps[i]; if (this->dx != 1 || this->dy != 1) return TRUE; } return FALSE; } static int vips_foreign_load_jp2k_set_header(VipsForeignLoadJp2k *jp2k, VipsImage *out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jp2k); VipsBandFormat format = vips_foreign_load_jp2k_get_format(jp2k->image); VipsInterpretation interpretation = vips_foreign_load_jp2k_get_interpretation(jp2k->image, format); if (interpretation == VIPS_INTERPRETATION_ERROR) { vips_error(class->nickname, _("unsupported colourspace %d"), jp2k->image->color_space); return -1; } /* We use a tilecache on our output. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; /* x0/y0 give the offset to the first pixel in the image. first->w and h * are scaled by the page number. */ vips_image_init_fields(out, jp2k->width, jp2k->height, jp2k->image->numcomps, format, VIPS_CODING_NONE, interpretation, 1.0, 1.0); /* openjpeg allows left and top of the coordinate grid to be * non-zero. These are always in unshrunk coordinates. */ out->Xoffset = -VIPS_ROUND_INT((double) jp2k->image->x0 / jp2k->shrink); out->Yoffset = -VIPS_ROUND_INT((double) jp2k->image->y0 / jp2k->shrink); if (jp2k->image->icc_profile_buf && jp2k->image->icc_profile_len > 0) vips_image_set_blob_copy(out, VIPS_META_ICC_NAME, jp2k->image->icc_profile_buf, jp2k->image->icc_profile_len); /* Map number of layers in image to pages. */ if (jp2k->info && jp2k->info->m_default_tile_info.tccp_info) vips_image_set_int(out, VIPS_META_N_PAGES, jp2k->info->m_default_tile_info.tccp_info->numresolutions); vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, jp2k->image->comps[0].prec); /* Keep in sync with vips_foreign_load_jp2k_load(). */ if (!jp2k->oneshot && (jp2k->info->tw != 1 || jp2k->info->th != 1)) { vips_image_set_int(out, VIPS_META_TILE_WIDTH, jp2k->info->tdx); vips_image_set_int(out, VIPS_META_TILE_HEIGHT, jp2k->info->tdy); } return 0; } /* Is an image a type we handle? We don't support various strange jp2k types. */ static int vips_foreign_load_jp2k_check_supported(opj_image_t *image) { if (image->numcomps > MAX_BANDS) { vips_error("jp2kload", "%s", _("too many image bands")); return -1; } if (image->numcomps == 0) { vips_error("jp2kload", "%s", _("no image components")); return -1; } /* We only allow images where all components have the same format. */ opj_image_comp_t *first = &image->comps[0]; for (int i = 1; i < image->numcomps; i++) { opj_image_comp_t *this = &image->comps[i]; if (this->x0 != first->x0 || this->y0 != first->y0 || this->w * this->dx != first->w * first->dx || this->h * this->dy != first->h * first->dy || this->resno_decoded != first->resno_decoded || this->factor != first->factor) { vips_error("jp2kload", "%s", _("components differ in geometry")); return -1; } if (this->prec != first->prec || this->sgnd != first->sgnd) { vips_error("jp2kload", "%s", _("components differ in precision")); return -1; } } return 0; } static int vips_foreign_load_jp2k_header(VipsForeignLoad *load) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) load; #ifdef DEBUG printf("vips_foreign_load_jp2k_header:\n"); #endif /*DEBUG*/ jp2k->codec_format = vips_foreign_load_jp2k_get_codec_format(jp2k->source); vips_source_rewind(jp2k->source); if (!(jp2k->codec = opj_create_decompress(jp2k->codec_format))) return -1; vips_foreign_load_jp2k_attach_handlers(jp2k, jp2k->codec); jp2k->shrink = 1 << jp2k->page; jp2k->parameters.cp_reduce = jp2k->page; if (!opj_setup_decoder(jp2k->codec, &jp2k->parameters)) return -1; opj_codec_set_threads(jp2k->codec, vips_concurrency_get()); if (!opj_read_header(jp2k->stream, jp2k->codec, &jp2k->image)) return -1; if (!(jp2k->info = opj_get_cstr_info(jp2k->codec))) return -1; if (vips_foreign_load_jp2k_check_supported(jp2k->image)) return -1; /* If any dx/dy are not 1, we'll need to upsample components during * tile packing. */ jp2k->upsample = vips_foreign_load_jp2k_get_upsample(jp2k->image); /* Try to guess if we need ycc->rgb processing. */ jp2k->ycc_to_rgb = vips_foreign_load_jp2k_get_ycc(jp2k->image); /* jp2k->image can change during decode, so we need a copy of the * full-size image geometry. */ jp2k->opj_x0 = jp2k->image->x0; jp2k->opj_y0 = jp2k->image->y0; jp2k->opj_x1 = jp2k->image->x1; jp2k->opj_y1 = jp2k->image->y1; /* The size we generate, ie. the decoded dimensions. */ opj_image_comp_t *first = &jp2k->image->comps[0]; jp2k->width = first->w - VIPS_ROUND_UINT((double) first->x0 / jp2k->shrink); jp2k->height = first->h - VIPS_ROUND_UINT((double) first->y0 / jp2k->shrink); #ifdef DEBUG vips_foreign_load_jp2k_print(jp2k); #endif /*DEBUG*/ if (vips_foreign_load_jp2k_set_header(jp2k, load->out)) return -1; VIPS_SETSTR(load->out->filename, vips_connection_filename(VIPS_CONNECTION(jp2k->source))); return 0; } #define PACK(TYPE) \ { \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < width; x++) { \ for (i = 0; i < b; i++) \ tq[i] = planes[i][x]; \ \ tq += b; \ } \ } #define PACK_UPSAMPLE(TYPE) \ { \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < width; x++) { \ for (i = 0; i < b; i++) { \ int dx = image->comps[i].dx; \ int pixel = planes[i][x / dx]; \ \ tq[i] = pixel; \ } \ \ tq += b; \ } \ } /* Pack a line of openjpeg pixels into libvips format. left/top are the * offsets into the opj image in pixel coordinates where we should start * reading. * * Set upsample if any opj component is subsampled. */ static void vips_foreign_load_jp2k_pack(gboolean upsample, opj_image_t *image, VipsImage *im, VipsPel *q, int left, int top, int width) { int *planes[MAX_BANDS]; int b = image->numcomps; int x, i; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jp2k_pack: " "upsample = %d, left = %d, top = %d, width = %d\n", upsample, left, top, width); #endif /*DEBUG_VERBOSE*/ for (i = 0; i < b; i++) { opj_image_comp_t *comp = &image->comps[i]; planes[i] = comp->data + (top / comp->dy) * comp->w + (left / comp->dx); } if (upsample) switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: PACK_UPSAMPLE(unsigned char); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: PACK_UPSAMPLE(unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: PACK_UPSAMPLE(unsigned int); break; default: g_assert_not_reached(); break; } else /* Fast no-upsample path. */ switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: // PACK(unsigned char); { unsigned char *tq = (unsigned char *) q; for (x = 0; x < width; x++) { for (i = 0; i < b; i++) tq[i] = planes[i][x]; tq += b; } } break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: PACK(unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: PACK(unsigned int); break; default: g_assert_not_reached(); break; } } /* ycc->rgb conversion adapted from openjpeg src/bin/common/color.c * * See also https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion */ #define YCC_TO_RGB(TYPE) \ { \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < length; x++) { \ int y = tq[0]; \ int cb = tq[1] - offset; \ int cr = tq[2] - offset; \ \ int r, g, b; \ \ r = y + (int) (1.402 * (float) cr); \ tq[0] = VIPS_CLIP(0, r, upb); \ \ g = y - (int) (0.344 * (float) cb + 0.714 * (float) cr); \ tq[1] = VIPS_CLIP(0, g, upb); \ \ b = y + (int) (1.772 * (float) cb); \ tq[2] = VIPS_CLIP(0, b, upb); \ \ tq += 3; \ } \ } /* YCC->RGB for a line of pels. */ static void vips_foreign_load_jp2k_ycc_to_rgb(opj_image_t *image, VipsImage *im, VipsPel *q, int length) { int prec = image->comps[0].prec; int offset = 1 << (prec - 1); int upb = (1 << prec) - 1; int x; switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: YCC_TO_RGB(unsigned char); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: YCC_TO_RGB(unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: YCC_TO_RGB(unsigned int); break; default: g_assert_not_reached(); break; } } #define LSHIFT(TYPE) \ { \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < n_elements; x++) \ tq[x] = VIPS_LSHIFT_INT(tq[x], shift); \ } /* Left-justify to the libvips pixel bits. We need 12 bit precision images * (for example) to fill 0-65535. */ static void vips_foreign_load_jp2k_ljust(opj_image_t *image, VipsImage *im, VipsPel *q, int length) { int prec = image->comps[0].prec; int shift = VIPS_IMAGE_SIZEOF_ELEMENT(im) * 8 - prec; if (shift != 0) { int n_elements = length * im->Bands; int x; switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: LSHIFT(unsigned char); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: LSHIFT(unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: LSHIFT(unsigned int); break; default: g_assert_not_reached(); break; } } } /* Does an image match the image we are trying to load? */ static gboolean vips_foreign_load_jp2k_is_match(VipsForeignLoadJp2k *jp2k, opj_image_t *image) { VipsForeignLoad *load = VIPS_FOREIGN_LOAD(jp2k); // do this first to ensure numcomps > 0 if (image->numcomps != load->out->Bands) return FALSE; VipsBandFormat format = vips_foreign_load_jp2k_get_format(image); VipsInterpretation interpretation = vips_foreign_load_jp2k_get_interpretation(image, format); gboolean ycc = vips_foreign_load_jp2k_get_ycc(image); gboolean upsample = vips_foreign_load_jp2k_get_upsample(jp2k->image); if (format != load->out->BandFmt || interpretation != load->out->Type || upsample != jp2k->upsample || ycc != jp2k->ycc_to_rgb) return FALSE; return TRUE; } /* Read a tile from an untiled jp2k file. */ static int vips_foreign_load_jp2k_generate_untiled(VipsRegion *out, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoad *load = (VipsForeignLoad *) a; VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jp2k); VipsRect *r = &out->valid; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jp2k_generate_untiled: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG_VERBOSE*/ /* If openjpeg has flagged an error, the library is not in a known * state and it's not safe to call again. */ if (jp2k->n_errors) return 0; /* To opj image space. Coordinates are always in the highest res level. */ VipsRect opj = { .left = r->left * jp2k->shrink + jp2k->opj_x0, .top = r->top * jp2k->shrink + jp2k->opj_y0, .width = r->width * jp2k->shrink, .height = r->height * jp2k->shrink }; if (!opj_set_decode_area(jp2k->codec, jp2k->image, opj.left, opj.top, VIPS_RECT_RIGHT(&opj), VIPS_RECT_BOTTOM(&opj))) return -1; if (!opj_decode(jp2k->codec, jp2k->stream, jp2k->image)) return -1; if (vips_foreign_load_jp2k_check_supported(jp2k->image)) return -1; /* Tragically, jp2k allows the decoded image to not match the wrapper. */ if (!vips_foreign_load_jp2k_is_match(jp2k, jp2k->image)) { vips_error(class->nickname, "%s", _("decoded image does not match container")); return -1; } /* Unpack decoded pixels to buffer in vips layout. */ for (int y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out, r->left, r->top + y); vips_foreign_load_jp2k_pack(jp2k->upsample, jp2k->image, out->im, q, 0, y, r->width); if (jp2k->ycc_to_rgb) vips_foreign_load_jp2k_ycc_to_rgb(jp2k->image, out->im, q, r->width); vips_foreign_load_jp2k_ljust(jp2k->image, out->im, q, r->width); } /* jp2k files can't be truncated (they fail to open), so all we can * spot is errors. */ if (load->fail_on >= VIPS_FAIL_ON_ERROR && jp2k->n_errors > 0) return -1; return 0; } /* Read a tile from the file. * * - jp2k tiles get smaller with `->shrink`, so we may need to fetch many jp2k * tiles to fill one libvips tile * * - jp2k tiles vary in size across a single image layer due to rounding, so * we must step x and y by a variable amount */ static int vips_foreign_load_jp2k_generate_tiled(VipsRegion *out, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoad *load = (VipsForeignLoad *) a; VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jp2k); VipsRect *r = &out->valid; int x, y, z; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jp2k_generate: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG_VERBOSE*/ /* If openjpeg has flagged an error, the library is not in a known * state and it's not safe to call again. */ if (jp2k->n_errors) return 0; y = 0; while (y < r->height) { VipsRect tile; // stop compiler warnings VipsRect hit = { 0 }; x = 0; while (x < r->width) { /* libvips tile position to opj base resolution coordinates. */ int opj_x = (r->left + x) * jp2k->shrink; int opj_y = (r->top + y) * jp2k->shrink; /* To opj tile coordinates. */ int tx = opj_x / jp2k->info->tdx; int ty = opj_y / jp2k->info->tdy; /* To tile number. */ int tile_index = ty * jp2k->info->tw + tx; #ifdef DEBUG_VERBOSE printf(" fetch tile %d\n", tile_index); #endif /*DEBUG_VERBOSE*/ if (!opj_get_decoded_tile(jp2k->codec, jp2k->stream, jp2k->image, tile_index)) return -1; if (vips_foreign_load_jp2k_check_supported(jp2k->image)) return -1; /* Tragically, jp2k allows the decoded image to not match the * wrapper. */ if (!vips_foreign_load_jp2k_is_match(jp2k, jp2k->image)) { vips_error(class->nickname, "%s", _("decoded image does not match container")); return -1; } /* Tile in libvips space intersected with the request to get the * pixels we need. */ tile = (VipsRect) { .left = r->left + x, .top = r->top + y, .width = jp2k->image->comps[0].w, .height = jp2k->image->comps[0].h }; vips_rect_intersectrect(&tile, r, &hit); /* Unpack hit pixels to buffer in vips layout. */ for (z = 0; z < hit.height; z++) { VipsPel *q = VIPS_REGION_ADDR(out, hit.left, hit.top + z); vips_foreign_load_jp2k_pack(jp2k->upsample, jp2k->image, out->im, q, hit.left - tile.left, hit.top - tile.top + z, hit.width); if (jp2k->ycc_to_rgb) vips_foreign_load_jp2k_ycc_to_rgb(jp2k->image, out->im, q, hit.width); vips_foreign_load_jp2k_ljust(jp2k->image, out->im, q, hit.width); } x += hit.width; } y += hit.height; } /* jp2k files can't be truncated (they fail to open), so all we can * spot is errors. */ if (load->fail_on >= VIPS_FAIL_ON_ERROR && jp2k->n_errors > 0) return -1; return 0; } static int vips_foreign_load_jp2k_load(VipsForeignLoad *load) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) load; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(load), 3); int tile_width; int tile_height; int tiles_across; #ifdef DEBUG printf("vips_foreign_load_jp2k_load:\n"); #endif /*DEBUG*/ t[0] = vips_image_new(); if (vips_foreign_load_jp2k_set_header(jp2k, t[0])) return -1; /* Untiled jp2k images need a different read API. */ if (jp2k->oneshot || (jp2k->info->tw == 1 && jp2k->info->th == 1)) { tile_width = jp2k->width; tile_height = jp2k->height; tiles_across = 1; if (vips_image_generate(t[0], NULL, vips_foreign_load_jp2k_generate_untiled, NULL, jp2k, NULL)) return -1; } else { /* Keep in sync with tile size in vips_foreign_load_jp2k_set_header(). */ tile_width = jp2k->info->tdx; tile_height = jp2k->info->tdy; tiles_across = jp2k->info->tw; if (vips_image_generate(t[0], NULL, vips_foreign_load_jp2k_generate_tiled, NULL, jp2k, NULL)) return -1; } /* Copy to out, adding a cache. Enough tiles for two complete * rows, plus 50%. */ if (vips_tilecache(t[0], &t[1], "tile_width", tile_width, "tile_height", tile_height, "max_tiles", 3 * tiles_across, NULL)) return -1; if (vips_image_write(t[1], load->real)) return -1; return 0; } static void vips_foreign_load_jp2k_class_init(VipsForeignLoadJp2kClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_jp2k_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2kload_base"; object_class->description = _("load JPEG2000 image"); object_class->build = vips_foreign_load_jp2k_build; /* OpenJPEG is fuzzed, but not by us. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; load_class->get_flags = vips_foreign_load_jp2k_get_flags; load_class->header = vips_foreign_load_jp2k_header; load_class->load = vips_foreign_load_jp2k_load; VIPS_ARG_INT(class, "page", 20, _("Page"), _("Load this page from the image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJp2k, page), 0, 100000, 0); VIPS_ARG_BOOL(class, "oneshot", 21, _("One-shot"), _("Load images a frame at a time"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJp2k, oneshot), FALSE); } static void vips_foreign_load_jp2k_init(VipsForeignLoadJp2k *jp2k) { } typedef struct _VipsForeignLoadJp2kFile { VipsForeignLoadJp2k parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadJp2kFile; typedef VipsForeignLoadJp2kClass VipsForeignLoadJp2kFileClass; G_DEFINE_TYPE(VipsForeignLoadJp2kFile, vips_foreign_load_jp2k_file, vips_foreign_load_jp2k_get_type()); static int vips_foreign_load_jp2k_file_build(VipsObject *object) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) object; VipsForeignLoadJp2kFile *file = (VipsForeignLoadJp2kFile *) object; if (file->filename && !(jp2k->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_jp2k_file_parent_class) ->build(object); } const char *vips__jp2k_suffs[] = { ".j2k", ".jp2", ".jpt", ".j2c", ".jpc", NULL }; static int vips_foreign_load_jp2k_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_jp2k_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_jp2k_file_class_init(VipsForeignLoadJp2kFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2kload"; object_class->build = vips_foreign_load_jp2k_file_build; foreign_class->suffs = vips__jp2k_suffs; load_class->is_a = vips_foreign_load_jp2k_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJp2kFile, filename), NULL); } static void vips_foreign_load_jp2k_file_init(VipsForeignLoadJp2kFile *jp2k) { } typedef struct _VipsForeignLoadJp2kBuffer { VipsForeignLoadJp2k parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadJp2kBuffer; typedef VipsForeignLoadJp2kClass VipsForeignLoadJp2kBufferClass; G_DEFINE_TYPE(VipsForeignLoadJp2kBuffer, vips_foreign_load_jp2k_buffer, vips_foreign_load_jp2k_get_type()); static int vips_foreign_load_jp2k_buffer_build(VipsObject *object) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) object; VipsForeignLoadJp2kBuffer *buffer = (VipsForeignLoadJp2kBuffer *) object; if (buffer->buf) if (!(jp2k->source = vips_source_new_from_memory( VIPS_AREA(buffer->buf)->data, VIPS_AREA(buffer->buf)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_jp2k_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_jp2k_buffer_is_a(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_jp2k_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_jp2k_buffer_class_init( VipsForeignLoadJp2kBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2kload_buffer"; object_class->build = vips_foreign_load_jp2k_buffer_build; load_class->is_a_buffer = vips_foreign_load_jp2k_buffer_is_a; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJp2kBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_jp2k_buffer_init(VipsForeignLoadJp2kBuffer *buffer) { } typedef struct _VipsForeignLoadJp2kSource { VipsForeignLoadJp2k parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadJp2kSource; typedef VipsForeignLoadJp2kClass VipsForeignLoadJp2kSourceClass; G_DEFINE_TYPE(VipsForeignLoadJp2kSource, vips_foreign_load_jp2k_source, vips_foreign_load_jp2k_get_type()); static int vips_foreign_load_jp2k_source_build(VipsObject *object) { VipsForeignLoadJp2k *jp2k = (VipsForeignLoadJp2k *) object; VipsForeignLoadJp2kSource *source = (VipsForeignLoadJp2kSource *) object; if (source->source) { jp2k->source = source->source; g_object_ref(jp2k->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_jp2k_source_parent_class) ->build(object); } static void vips_foreign_load_jp2k_source_class_init(VipsForeignLoadJp2kSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2kload_source"; object_class->build = vips_foreign_load_jp2k_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_jp2k_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJp2kSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_jp2k_source_init(VipsForeignLoadJp2kSource *jp2k) { } static void info_callback(const char *msg G_GNUC_UNUSED, void *data G_GNUC_UNUSED) { /* There's a lot of info as well ... */ #ifdef DEBUG printf("info_callback: %s\n", msg); #endif /*DEBUG*/ } static void warning_callback(const char *msg G_GNUC_UNUSED, void *data G_GNUC_UNUSED) { /* There are a lot of warnings ... */ #ifdef DEBUG printf("warning_callback: %s\n", msg); #endif /*DEBUG*/ } static void error_callback(const char *msg, void *data) { #ifdef DEBUG printf("error_callback: %s\n", msg); #endif /*DEBUG*/ vips_error("OpenJPEG", "%s", msg); } typedef struct _TileDecompress { VipsSource *source; opj_stream_t *stream; opj_codec_t *codec; opj_image_t *image; } TileDecompress; static void vips__foreign_load_jp2k_decompress_free(TileDecompress *decompress) { VIPS_FREEF(opj_destroy_codec, decompress->codec); VIPS_FREEF(opj_image_destroy, decompress->image); VIPS_FREEF(opj_stream_destroy, decompress->stream); VIPS_UNREF(decompress->source); } /* Called from tiff2vips to decode a jp2k-compressed tile. * * width/height is the tile size. If this is an edge tile, and smaller than * this, we still write a full-size tile and our caller will clip. */ int vips__foreign_load_jp2k_decompress(VipsImage *out, int width, int height, gboolean ycc_to_rgb, void *from, size_t from_length, void *to, size_t to_length) { size_t pel_size = VIPS_IMAGE_SIZEOF_PEL(out); size_t line_size = pel_size * width; TileDecompress decompress = { 0 }; opj_dparameters_t parameters; gboolean upsample; VipsPel *q; int y; #ifdef DEBUG printf("vips__foreign_load_jp2k_decompress: width = %d, height = %d, " "ycc_to_rgb = %d, from_length = %zd, to_length = %zd\n", width, height, ycc_to_rgb, from_length, to_length); #endif /*DEBUG*/ /* Our ycc->rgb only works for exactly 3 bands. */ ycc_to_rgb = ycc_to_rgb && out->Bands == 3; opj_set_default_decoder_parameters(¶meters); decompress.codec = opj_create_decompress(OPJ_CODEC_J2K); opj_set_info_handler(decompress.codec, info_callback, NULL); opj_set_warning_handler(decompress.codec, warning_callback, NULL); opj_set_error_handler(decompress.codec, error_callback, NULL); opj_setup_decoder(decompress.codec, ¶meters); decompress.source = vips_source_new_from_memory(from, from_length); decompress.stream = vips_foreign_load_jp2k_stream(decompress.source); if (!opj_read_header(decompress.stream, decompress.codec, &decompress.image)) { vips_error("jp2kload", "%s", ("header error")); vips__foreign_load_jp2k_decompress_free(&decompress); return -1; } if (vips_foreign_load_jp2k_check_supported(decompress.image)) return -1; if (decompress.image->x1 > width || decompress.image->y1 > height || decompress.image->numcomps > out->Bands || line_size * height > to_length) { vips_error("jp2kload", "%s", ("bad dimensions")); vips__foreign_load_jp2k_decompress_free(&decompress); return -1; } if (!opj_decode(decompress.codec, decompress.stream, decompress.image)) { vips_error("jp2kload", "%s", ("decode error")); vips__foreign_load_jp2k_decompress_free(&decompress); return -1; } /* Do any components need upsampling? */ upsample = vips_foreign_load_jp2k_get_upsample(decompress.image); /* Unpack hit pixels to buffer in vips layout. */ q = to; for (y = 0; y < height; y++) { vips_foreign_load_jp2k_pack(upsample, decompress.image, out, q, 0, y, width); if (ycc_to_rgb) vips_foreign_load_jp2k_ycc_to_rgb(decompress.image, out, q, width); vips_foreign_load_jp2k_ljust(decompress.image, out, q, width); q += line_size; } vips__foreign_load_jp2k_decompress_free(&decompress); return 0; } #else /*!HAVE_LIBOPENJP2*/ int vips__foreign_load_jp2k_decompress(VipsImage *out, int width, int height, gboolean ycc_to_rgb, void *from, size_t from_length, void *to, size_t to_length) { vips_error("jp2k", "%s", _("libvips built without JPEG2000 support")); return -1; } #endif /*HAVE_LIBOPENJP2*/ /** * vips_jp2kload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a JPEG2000 image. * * The loader supports 8, 16 and 32-bit int pixel * values, signed and unsigned. It supports greyscale, RGB, YCC, CMYK and * multispectral colour spaces. It will read any ICC profile on the image. * * It will only load images where all channels have the same format. * * Use @page to set the page to load, where page 0 is the base resolution * image and higher-numbered pages are x2 reductions. Use the metadata item * "n-pages" to find the number of pyramid layers. * * Some versions of openjpeg can fail to decode some tiled images correctly. * Setting @oneshot will force the loader to decode tiled images in a single * operation and can improve compatibility. * * Use @fail_on to set the type of error that will cause load to fail. By * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE]. * * ::: tip "Optional arguments" * * @page: `gint`, load this page * * @oneshot: `gboolean`, load pages in one-shot mode * * @fail_on: [enum@FailOn], types of read error to fail on * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_jp2kload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("jp2kload", ap, filename, out); va_end(ap); return result; } /** * vips_jp2kload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.jp2kload], but read from a buffer. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, load this page * * @oneshot: `gboolean`, load pages in one-shot mode * * @fail_on: [enum@FailOn], types of read error to fail on * * Returns: 0 on success, -1 on error. */ int vips_jp2kload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("jp2kload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_jp2kload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.jp2kload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, load this page * * @oneshot: `gboolean`, load pages in one-shot mode * * @fail_on: [enum@FailOn], types of read error to fail on * * Returns: 0 on success, -1 on error. */ int vips_jp2kload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("jp2kload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/jp2ksave.c000066400000000000000000001114401516303661500202630ustar00rootroot00000000000000/* save as jpeg2000 * * 18/3/20 * - from jp2kload.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ /* TODO * * - could support tiff-like depth parameter * * - could support png-like bitdepth parameter * * - could support cp_comment field? not very useful * */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #ifdef HAVE_LIBOPENJP2 #include #include "pforeign.h" /* Surely enough ... does anyone do multispectral imaging with jp2k? */ #define MAX_BANDS (100) typedef struct _VipsForeignSaveJp2k { VipsForeignSave parent_object; /* Where to write (set by subclasses). */ VipsTarget *target; int tile_width; int tile_height; /* Lossless mode. */ gboolean lossless; /* Quality factor. */ int Q; /* Chroma subsample mode. */ VipsForeignSubsample subsample_mode; /* Encoder state. */ opj_stream_t *stream; opj_codec_t *codec; opj_cparameters_t parameters; opj_image_t *image; /* The line of tiles we are building, and the buffer we * unpack to for output. */ VipsRegion *strip; VipsPel *tile_buffer; /* If we need to subsample during unpacking. */ gboolean subsample; /* If we convert RGB to YCC during save. */ gboolean save_as_ycc; /* Accumulate a line of sums here during chroma subsample. */ VipsPel *accumulate; } VipsForeignSaveJp2k; typedef VipsForeignSaveClass VipsForeignSaveJp2kClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveJp2k, vips_foreign_save_jp2k, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_jp2k_dispose(GObject *gobject) { VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) gobject; VIPS_FREEF(opj_destroy_codec, jp2k->codec); VIPS_FREEF(opj_stream_destroy, jp2k->stream); VIPS_FREEF(opj_image_destroy, jp2k->image); VIPS_UNREF(jp2k->target); VIPS_UNREF(jp2k->strip); VIPS_FREE(jp2k->tile_buffer); VIPS_FREE(jp2k->accumulate); G_OBJECT_CLASS(vips_foreign_save_jp2k_parent_class)->dispose(gobject); } static OPJ_SIZE_T vips_foreign_save_jp2k_target_write(void *buffer, size_t length, void *client) { VipsTarget *target = VIPS_TARGET(client); if (vips_target_write(target, buffer, length)) return 0; return length; } static OPJ_BOOL vips_foreign_save_jp2k_target_seek(off_t position, void *client) { VipsTarget *target = VIPS_TARGET(client); if (vips_target_seek(target, position, SEEK_SET) < 0) return FALSE; return TRUE; } static OPJ_OFF_T vips_foreign_save_jp2k_target_skip(off_t offset, void *client) { VipsTarget *target = VIPS_TARGET(client); if (vips_target_seek(target, offset, SEEK_CUR) < 0) return -1; return offset; } /* Make a libopenjp2 output stream that wraps a VipsTarget. */ static opj_stream_t * vips_foreign_save_jp2k_target(VipsTarget *target) { opj_stream_t *stream; /* FALSE means a write stream. */ if (!(stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, FALSE))) return NULL; opj_stream_set_user_data(stream, target, NULL); opj_stream_set_write_function(stream, vips_foreign_save_jp2k_target_write); opj_stream_set_seek_function(stream, vips_foreign_save_jp2k_target_seek); opj_stream_set_skip_function(stream, vips_foreign_save_jp2k_target_skip); return stream; } static void vips_foreign_save_jp2k_error_callback(const char *msg, void *client) { vips_error("jp2ksave", "%s", msg); } /* The openjpeg info and warning callbacks are incredibly chatty. */ static void vips_foreign_save_jp2k_warning_callback(const char *msg, void *client) { #ifdef DEBUG #endif /*DEBUG*/ g_warning("jp2ksave: %s", msg); } static void vips_foreign_save_jp2k_info_callback(const char *msg, void *client) { #ifdef DEBUG #endif /*DEBUG*/ g_info("jp2ksave: %s", msg); } static void vips_foreign_save_jp2k_attach_handlers(opj_codec_t *codec) { opj_set_info_handler(codec, vips_foreign_save_jp2k_info_callback, NULL); opj_set_warning_handler(codec, vips_foreign_save_jp2k_warning_callback, NULL); opj_set_error_handler(codec, vips_foreign_save_jp2k_error_callback, NULL); } /* See also https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion */ #define RGB_TO_YCC(TYPE) \ { \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < tile->width; x++) { \ int r = tq[0]; \ int g = tq[1]; \ int b = tq[2]; \ \ int y, cb, cr; \ \ y = 0.299 * r + 0.587 * g + 0.114 * b; \ tq[0] = VIPS_CLIP(0, y, upb); \ \ cb = offset - (int) (0.168736 * r + 0.331264 * g - 0.5 * b); \ tq[1] = VIPS_CLIP(0, cb, upb); \ \ cr = offset - (int) (-0.5 * r + 0.418688 * g + 0.081312 * b); \ tq[2] = VIPS_CLIP(0, cr, upb); \ \ tq += 3; \ } \ } /* In-place RGB->YCC for a line of pels. */ static void vips_foreign_save_jp2k_rgb_to_ycc(VipsRegion *region, VipsRect *tile, int prec) { VipsImage *im = region->im; int offset = 1 << (prec - 1); int upb = (1 << prec) - 1; int x, y; g_assert(im->Bands == 3); for (y = 0; y < tile->height; y++) { VipsPel *q = VIPS_REGION_ADDR(region, tile->left, tile->top + y); switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: RGB_TO_YCC(unsigned char); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: RGB_TO_YCC(unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: RGB_TO_YCC(unsigned int); break; default: g_assert_not_reached(); break; } } } /* Shrink in three stages: * 1. copy the first line of input pels to acc * 2. add subsequent lines in comp.dy. * 3. horizontal average to output line */ #define SHRINK(OUTPUT_TYPE, ACC_TYPE, PIXEL_TYPE) \ { \ ACC_TYPE *acc = (ACC_TYPE *) accumulate; \ OUTPUT_TYPE *tq = (OUTPUT_TYPE *) q; \ const int n_pels = comp->dx * comp->dy; \ \ PIXEL_TYPE *tp; \ ACC_TYPE *ap; \ \ tp = (PIXEL_TYPE *) p; \ for (x = 0; x < tile->width; x++) { \ acc[x] = *tp; \ tp += n_bands; \ } \ \ for (z = 1; z < comp->dy; z++) { \ tp = (PIXEL_TYPE *) (p + z * lskip); \ for (x = 0; x < tile->width; x++) { \ acc[x] += *tp; \ tp += n_bands; \ } \ } \ \ ap = acc; \ for (x = 0; x < output_width; x++) { \ ACC_TYPE sum; \ \ sum = 0; \ for (z = 0; z < comp->dx; z++) \ sum += ap[z]; \ \ tq[x] = (sum + n_pels / 2) / n_pels; \ ap += comp->dx; \ } \ } static void vips_foreign_save_jp2k_unpack_subsample(VipsRegion *region, VipsRect *tile, opj_image_t *image, VipsPel *tile_buffer, VipsPel *accumulate) { VipsImage *im = region->im; size_t sizeof_element = VIPS_REGION_SIZEOF_ELEMENT(region); size_t lskip = VIPS_REGION_LSKIP(region); int n_bands = im->Bands; VipsPel *q; int x, y, z, i; q = tile_buffer; for (i = 0; i < n_bands; i++) { opj_image_comp_t *comp = &image->comps[i]; /* The number of pixels we write for this component. No * padding. */ int output_width = VIPS_ROUND_UINT( (double) tile->width / comp->dx); int output_height = VIPS_ROUND_UINT( (double) tile->height / comp->dy); ; for (y = 0; y < output_height; y++) { VipsPel *p = i * sizeof_element + VIPS_REGION_ADDR(region, tile->left, tile->top + y * comp->dy); /* Shrink a line of pels to q. */ switch (im->BandFmt) { case VIPS_FORMAT_CHAR: SHRINK(signed char, int, signed char); break; case VIPS_FORMAT_UCHAR: SHRINK(unsigned char, int, unsigned char); break; case VIPS_FORMAT_SHORT: SHRINK(signed short, int, signed short); break; case VIPS_FORMAT_USHORT: SHRINK(unsigned short, int, unsigned short); break; case VIPS_FORMAT_INT: SHRINK(signed int, gint64, signed int); break; case VIPS_FORMAT_UINT: SHRINK(unsigned int, gint64, unsigned int); break; default: g_assert_not_reached(); break; } q += sizeof_element * output_width; } } } #define UNPACK(OUT, IN) \ { \ OUT *tq = (OUT *) q; \ IN *tp = (IN *) p + i; \ \ for (x = 0; x < tile->width; x++) { \ tq[x] = *tp; \ tp += b; \ } \ } static void vips_foreign_save_jp2k_unpack(VipsRegion *region, VipsRect *tile, opj_image_t *image, VipsPel *tile_buffer) { VipsImage *im = region->im; size_t sizeof_element = VIPS_REGION_SIZEOF_ELEMENT(region); size_t sizeof_line = sizeof_element * tile->width; size_t sizeof_tile = sizeof_line * tile->height; int b = im->Bands; int x, y, i; for (y = 0; y < tile->height; y++) { VipsPel *p = VIPS_REGION_ADDR(region, tile->left, tile->top + y); for (i = 0; i < b; i++) { VipsPel *q = tile_buffer + i * sizeof_tile + y * sizeof_line; switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: UNPACK(unsigned char, unsigned char); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: UNPACK(unsigned short, unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: UNPACK(unsigned int, unsigned int); break; default: g_assert_not_reached(); break; } } } } static size_t vips_foreign_save_jp2k_sizeof_tile(VipsForeignSaveJp2k *jp2k, VipsRect *tile) { VipsForeignSave *save = (VipsForeignSave *) jp2k; size_t sizeof_element = VIPS_IMAGE_SIZEOF_ELEMENT(save->ready); size_t size; int i; size = 0; for (i = 0; i < jp2k->image->numcomps; i++) { opj_image_comp_t *comp = &jp2k->image->comps[i]; /* The number of pixels we write for this component. Round to * nearest, and we may have to write half-pixels at the edges. */ int output_width = VIPS_ROUND_UINT( (double) tile->width / comp->dx); int output_height = VIPS_ROUND_UINT( (double) tile->height / comp->dy); ; size += (size_t) output_width * output_height * sizeof_element; } return size; } static int vips_foreign_save_jp2k_write_tiles(VipsForeignSaveJp2k *jp2k) { VipsForeignSave *save = (VipsForeignSave *) jp2k; VipsImage *im = save->ready; int tiles_across = VIPS_ROUND_UP(im->Xsize, jp2k->tile_width) / jp2k->tile_width; int x; for (x = 0; x < im->Xsize; x += jp2k->tile_width) { VipsRect tile; size_t sizeof_tile; int tile_index; tile.left = x; tile.top = jp2k->strip->valid.top; tile.width = jp2k->tile_width; tile.height = jp2k->tile_height; vips_rect_intersectrect(&tile, &jp2k->strip->valid, &tile); if (jp2k->save_as_ycc) vips_foreign_save_jp2k_rgb_to_ycc(jp2k->strip, &tile, jp2k->image->comps[0].prec); if (jp2k->subsample) vips_foreign_save_jp2k_unpack_subsample(jp2k->strip, &tile, jp2k->image, jp2k->tile_buffer, jp2k->accumulate); else vips_foreign_save_jp2k_unpack(jp2k->strip, &tile, jp2k->image, jp2k->tile_buffer); sizeof_tile = vips_foreign_save_jp2k_sizeof_tile(jp2k, &tile); tile_index = tiles_across * tile.top / jp2k->tile_height + x / jp2k->tile_width; if (!opj_write_tile(jp2k->codec, tile_index, (VipsPel *) jp2k->tile_buffer, sizeof_tile, jp2k->stream)) return -1; } return 0; } static int vips_foreign_save_jp2k_write_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) a; VipsForeignSave *save = (VipsForeignSave *) jp2k; #ifdef DEBUG_VERBOSE printf("vips_foreign_save_jp2k_write_block: y = %d, nlines = %d\n", area->top, area->height); #endif /*DEBUG_VERBOSE*/ for (;;) { VipsRect *to = &jp2k->strip->valid; VipsRect hit; VipsRect new; VipsRect image; /* The intersection with the strip is the fresh pixels we * have. */ vips_rect_intersectrect(area, to, &hit); /* Write the new pixels into the strip. */ vips_region_copy(region, jp2k->strip, &hit, hit.left, hit.top); /* Have we failed to reach the bottom of the strip? We must * have run out of fresh pixels, so we are done. */ if (VIPS_RECT_BOTTOM(&hit) != VIPS_RECT_BOTTOM(&jp2k->strip->valid)) break; /* We have reached the bottom of the strip. Write this line of * pixels and move the strip down. */ if (vips_foreign_save_jp2k_write_tiles(jp2k)) return -1; new.left = 0; new.top = jp2k->strip->valid.top + jp2k->tile_height; new.width = save->ready->Xsize; new.height = jp2k->tile_height; image.left = 0; image.top = 0; image.width = save->ready->Xsize; image.height = save->ready->Ysize; vips_rect_intersectrect(&new, &image, &new); /* End of image? */ if (vips_rect_isempty(&new)) break; if (vips_region_buffer(jp2k->strip, &new)) return -1; } return 0; } /* We can't call opj_calloc on win, sadly. */ #define VIPS_OPJ_CALLOC(N, TYPE) \ ((TYPE *) calloc((N), sizeof(TYPE))) /* Allocate an openjpeg image structure. Openjpeg has opj_image_create(), but * that always allocates memory for each channel, and we don't want that when * we are doing tiled write. */ static opj_image_t * vips_opj_image_create(OPJ_UINT32 numcmpts, opj_image_cmptparm_t *cmptparms, OPJ_COLOR_SPACE clrspc, gboolean allocate) { OPJ_UINT32 compno; opj_image_t *image = NULL; if (!(image = VIPS_OPJ_CALLOC(1, opj_image_t))) return NULL; image->color_space = clrspc; image->numcomps = numcmpts; image->comps = VIPS_OPJ_CALLOC(image->numcomps, opj_image_comp_t); if (!image->comps) { opj_image_destroy(image); return NULL; } for (compno = 0; compno < numcmpts; compno++) { opj_image_comp_t *comp = &image->comps[compno]; comp->dx = cmptparms[compno].dx; comp->dy = cmptparms[compno].dy; comp->w = cmptparms[compno].w; comp->h = cmptparms[compno].h; comp->x0 = cmptparms[compno].x0; comp->y0 = cmptparms[compno].y0; comp->prec = cmptparms[compno].prec; comp->sgnd = cmptparms[compno].sgnd; if (comp->h != 0 && (OPJ_SIZE_T) comp->w > SIZE_MAX / comp->h / sizeof(OPJ_INT32)) { opj_image_destroy(image); return NULL; } /* Allocation is optional. */ if (allocate) { size_t bytes = (size_t) comp->w * comp->h * sizeof(OPJ_INT32); comp->data = (OPJ_INT32 *) opj_image_data_alloc(bytes); if (!comp->data) { opj_image_destroy(image); return NULL; } memset(comp->data, 0, bytes); } } return image; } static opj_image_t * vips_foreign_save_jp2k_new_image(VipsImage *im, int width, int height, gboolean subsample, gboolean save_as_ycc, gboolean allocate) { OPJ_COLOR_SPACE color_space; int expected_bands; int bits_per_pixel; opj_image_cmptparm_t comps[MAX_BANDS]; opj_image_t *image; int i; if (im->Bands > MAX_BANDS) return NULL; /* CIELAB etc. do not seem to be well documented. */ switch (im->Type) { case VIPS_INTERPRETATION_B_W: case VIPS_INTERPRETATION_GREY16: color_space = OPJ_CLRSPC_GRAY; expected_bands = 1; break; case VIPS_INTERPRETATION_sRGB: case VIPS_INTERPRETATION_RGB16: color_space = save_as_ycc ? OPJ_CLRSPC_SYCC : OPJ_CLRSPC_SRGB; expected_bands = 3; break; case VIPS_INTERPRETATION_CMYK: color_space = OPJ_CLRSPC_CMYK; expected_bands = 4; break; default: color_space = OPJ_CLRSPC_UNSPECIFIED; expected_bands = im->Bands; break; } switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: bits_per_pixel = 8; break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: bits_per_pixel = 16; break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: /* OpenJPEG only supports up to 31. */ bits_per_pixel = 31; break; default: g_assert_not_reached(); break; } for (i = 0; i < im->Bands; i++) { comps[i].dx = (subsample && i > 0) ? 2 : 1; comps[i].dy = (subsample && i > 0) ? 2 : 1; comps[i].w = width; comps[i].h = height; comps[i].x0 = 0; comps[i].y0 = 0; comps[i].prec = bits_per_pixel; comps[i].sgnd = !vips_band_format_isuint(im->BandFmt); } image = vips_opj_image_create(im->Bands, comps, color_space, allocate); image->x1 = width; image->y1 = height; /* Tag alpha channels. */ for (i = 0; i < im->Bands; i++) image->comps[i].alpha = i >= expected_bands; return image; } /* Compression profile derived from the BM's recommendations, see: * * https://purl.pt/24107/1/iPres2013_PDF/An%20Analysis%20of%20Contemporary%20JPEG2000%20Codecs%20for%20Image%20Format%20Migration.pdf * * Some of these settings (eg. numresolution) are overridden later. */ static void vips_foreign_save_jp2k_set_profile(opj_cparameters_t *parameters, gboolean lossless, int Q) { if (lossless) parameters->irreversible = FALSE; else { int i; /* Equivalent command-line flags: * * -I -p RPCL -n 7 \ * -c[256,256],[256,256],[256,256],[256,256],[256,256],[256,256],[256,256] \ * -b 64,64 */ parameters->irreversible = TRUE; parameters->prog_order = OPJ_RPCL; parameters->cblockw_init = 64; parameters->cblockh_init = 64; parameters->cp_disto_alloc = 1; parameters->cp_fixed_quality = TRUE; parameters->tcp_numlayers = 1; parameters->numresolution = 7; /* No idea what this does, but opj_compress sets it. */ parameters->csty = 1; parameters->res_spec = 7; for (i = 0; i < parameters->res_spec; i++) { parameters->prch_init[i] = 256; parameters->prcw_init[i] = 256; parameters->tcp_distoratio[i] = Q + 10 * i; } } } static int vips_foreign_save_jp2k_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object; size_t sizeof_tile; size_t sizeof_line; VipsRect strip_position; if (VIPS_OBJECT_CLASS(vips_foreign_save_jp2k_parent_class)->build(object)) return -1; /* Analyze our arguments. */ if (!vips_band_format_isint(save->ready->BandFmt)) { vips_error(class->nickname, "%s", _("not an integer format")); return -1; } /* The "lossless" param implies no chroma subsampling. */ if (jp2k->lossless) jp2k->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_OFF; switch (jp2k->subsample_mode) { case VIPS_FOREIGN_SUBSAMPLE_AUTO: jp2k->subsample = jp2k->Q < 90 && (save->ready->Type == VIPS_INTERPRETATION_sRGB || save->ready->Type == VIPS_INTERPRETATION_RGB16) && save->ready->Bands == 3; break; case VIPS_FOREIGN_SUBSAMPLE_ON: jp2k->subsample = TRUE; break; case VIPS_FOREIGN_SUBSAMPLE_OFF: jp2k->subsample = FALSE; break; default: g_assert_not_reached(); break; } if (jp2k->subsample) jp2k->save_as_ycc = TRUE; /* Set parameters for compressor. */ opj_set_default_encoder_parameters(&jp2k->parameters); /* Set compression profile. */ vips_foreign_save_jp2k_set_profile(&jp2k->parameters, jp2k->lossless, jp2k->Q); /* Always tile. */ jp2k->parameters.tile_size_on = OPJ_TRUE; jp2k->parameters.cp_tdx = jp2k->tile_width; jp2k->parameters.cp_tdy = jp2k->tile_height; /* Makes many-band, non-subsampled images smaller, somehow. */ jp2k->parameters.tcp_mct = save->ready->Bands >= 3 && !jp2k->subsample; /* Number of layers to write. Smallest layer is c. 2^5 on the smallest * axis. */ jp2k->parameters.numresolution = VIPS_MAX(1, log(VIPS_MIN(save->ready->Xsize, save->ready->Ysize)) / log(2) - 5); #ifdef DEBUG printf("vips_foreign_save_jp2k_build: numresolutions = %d\n", jp2k->parameters.numresolution); #endif /*DEBUG*/ /* Set up compressor. */ /* Save as a jp2 file. */ jp2k->codec = opj_create_compress(OPJ_CODEC_JP2); vips_foreign_save_jp2k_attach_handlers(jp2k->codec); /* FALSE means don't alloc memory for image planes (we write in * tiles, not whole images). */ if (!(jp2k->image = vips_foreign_save_jp2k_new_image(save->ready, save->ready->Xsize, save->ready->Ysize, jp2k->subsample, jp2k->save_as_ycc, FALSE))) return -1; if (!opj_setup_encoder(jp2k->codec, &jp2k->parameters, jp2k->image)) return -1; opj_codec_set_threads(jp2k->codec, vips_concurrency_get()); if (!(jp2k->stream = vips_foreign_save_jp2k_target(jp2k->target))) return -1; if (!opj_start_compress(jp2k->codec, jp2k->image, jp2k->stream)) return -1; /* The buffer we repack tiles to for write. Large enough for one * complete tile. */ sizeof_tile = VIPS_IMAGE_SIZEOF_PEL(save->ready) * jp2k->tile_width * jp2k->tile_height; if (!(jp2k->tile_buffer = VIPS_ARRAY(NULL, sizeof_tile, VipsPel))) return -1; /* We need a line of sums for chroma subsample. At worst, gint64. */ sizeof_line = sizeof(gint64) * jp2k->tile_width; if (!(jp2k->accumulate = VIPS_ARRAY(NULL, sizeof_line, VipsPel))) return -1; /* The line of tiles we are building. It's used by the bg thread, so * no ownership. */ jp2k->strip = vips_region_new(save->ready); vips__region_no_ownership(jp2k->strip); /* Position strip at the top of the image, the height of a row of * tiles. */ strip_position.left = 0; strip_position.top = 0; strip_position.width = save->ready->Xsize; strip_position.height = jp2k->tile_height; if (vips_region_buffer(jp2k->strip, &strip_position)) return -1; /* Write data. */ if (vips_sink_disc(save->ready, vips_foreign_save_jp2k_write_block, jp2k)) return -1; opj_end_compress(jp2k->codec, jp2k->stream); if (vips_target_end(jp2k->target)) return -1; return 0; } static void vips_foreign_save_jp2k_class_init(VipsForeignSaveJp2kClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_jp2k_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2ksave_base"; object_class->description = _("save image in JPEG2000 format"); object_class->build = vips_foreign_save_jp2k_build; foreign_class->suffs = vips__jp2k_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; VIPS_ARG_INT(class, "tile_width", 11, _("Tile width"), _("Tile width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2k, tile_width), 1, 32768, 512); VIPS_ARG_INT(class, "tile_height", 12, _("Tile height"), _("Tile height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2k, tile_height), 1, 32768, 512); VIPS_ARG_BOOL(class, "lossless", 13, _("Lossless"), _("Enable lossless compression"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2k, lossless), FALSE); VIPS_ARG_ENUM(class, "subsample_mode", 19, _("Subsample mode"), _("Select chroma subsample operation mode"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2k, subsample_mode), VIPS_TYPE_FOREIGN_SUBSAMPLE, VIPS_FOREIGN_SUBSAMPLE_OFF); VIPS_ARG_INT(class, "Q", 14, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2k, Q), 1, 100, 48); } static void vips_foreign_save_jp2k_init(VipsForeignSaveJp2k *jp2k) { jp2k->tile_width = 512; jp2k->tile_height = 512; /* Chosen to give about the same filesize as regular jpg Q75. */ jp2k->Q = 48; jp2k->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_OFF; } typedef struct _VipsForeignSaveJp2kFile { VipsForeignSaveJp2k parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveJp2kFile; typedef VipsForeignSaveJp2kClass VipsForeignSaveJp2kFileClass; G_DEFINE_TYPE(VipsForeignSaveJp2kFile, vips_foreign_save_jp2k_file, vips_foreign_save_jp2k_get_type()); static int vips_foreign_save_jp2k_file_build(VipsObject *object) { VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object; VipsForeignSaveJp2kFile *file = (VipsForeignSaveJp2kFile *) object; if (!(jp2k->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_jp2k_file_parent_class) ->build(object); } static void vips_foreign_save_jp2k_file_class_init(VipsForeignSaveJp2kFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2ksave"; object_class->build = vips_foreign_save_jp2k_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2kFile, filename), NULL); } static void vips_foreign_save_jp2k_file_init(VipsForeignSaveJp2kFile *file) { } typedef struct _VipsForeignSaveJp2kBuffer { VipsForeignSaveJp2k parent_object; /* Save to a buffer. */ VipsArea *buf; } VipsForeignSaveJp2kBuffer; typedef VipsForeignSaveJp2kClass VipsForeignSaveJp2kBufferClass; G_DEFINE_TYPE(VipsForeignSaveJp2kBuffer, vips_foreign_save_jp2k_buffer, vips_foreign_save_jp2k_get_type()); static int vips_foreign_save_jp2k_buffer_build(VipsObject *object) { VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object; VipsForeignSaveJp2kBuffer *buffer = (VipsForeignSaveJp2kBuffer *) object; VipsBlob *blob; if (!(jp2k->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_jp2k_buffer_parent_class) ->build(object)) return -1; g_object_get(jp2k->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_jp2k_buffer_class_init( VipsForeignSaveJp2kBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2ksave_buffer"; object_class->build = vips_foreign_save_jp2k_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2kBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_jp2k_buffer_init(VipsForeignSaveJp2kBuffer *buffer) { } typedef struct _VipsForeignSaveJp2kTarget { VipsForeignSaveJp2k parent_object; VipsTarget *target; } VipsForeignSaveJp2kTarget; typedef VipsForeignSaveJp2kClass VipsForeignSaveJp2kTargetClass; G_DEFINE_TYPE(VipsForeignSaveJp2kTarget, vips_foreign_save_jp2k_target, vips_foreign_save_jp2k_get_type()); static int vips_foreign_save_jp2k_target_build(VipsObject *object) { VipsForeignSaveJp2k *jp2k = (VipsForeignSaveJp2k *) object; VipsForeignSaveJp2kTarget *target = (VipsForeignSaveJp2kTarget *) object; if (target->target) { jp2k->target = target->target; g_object_ref(jp2k->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_jp2k_target_parent_class) ->build(object); } static void vips_foreign_save_jp2k_target_class_init( VipsForeignSaveJp2kTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jp2ksave_target"; object_class->build = vips_foreign_save_jp2k_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJp2kTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_jp2k_target_init(VipsForeignSaveJp2kTarget *target) { } /* Stuff we track during tile compress. */ typedef struct _TileCompress { opj_codec_t *codec; opj_image_t *image; opj_stream_t *stream; VipsPel *accumulate; } TileCompress; /* Unpack from @tile within @region to the int data pointers on @image with * subsampling. */ static void vips_foreign_save_jp2k_unpack_subsample_image(VipsRegion *region, VipsRect *tile, opj_image_t *image, VipsPel *accumulate) { VipsImage *im = region->im; size_t sizeof_element = VIPS_REGION_SIZEOF_ELEMENT(region); size_t lskip = VIPS_REGION_LSKIP(region); int n_bands = im->Bands; int x, y, z, i; for (i = 0; i < n_bands; i++) { opj_image_comp_t *comp = &image->comps[i]; int *q = comp->data; /* The number of pixels we write for this component. Lines * align to scanlines on comp. */ int output_width = VIPS_ROUND_UINT( (double) comp->w / comp->dx); int output_height = VIPS_ROUND_UINT( (double) comp->h / comp->dy); for (y = 0; y < output_height; y++) { VipsPel *p = i * sizeof_element + VIPS_REGION_ADDR(region, tile->left, tile->top + y * comp->dy); /* Shrink a line of pels to q. */ switch (im->BandFmt) { case VIPS_FORMAT_CHAR: SHRINK(int, int, signed char); break; case VIPS_FORMAT_UCHAR: SHRINK(int, int, unsigned char); break; case VIPS_FORMAT_SHORT: SHRINK(int, int, signed short); break; case VIPS_FORMAT_USHORT: SHRINK(int, int, unsigned short); break; case VIPS_FORMAT_INT: SHRINK(int, gint64, signed int); break; case VIPS_FORMAT_UINT: SHRINK(int, gint64, unsigned int); break; default: g_assert_not_reached(); break; } q += output_width; } } } /* Unpack from @tile within @region to the int data pointers on @image. No * subsampling. */ static void vips_foreign_save_jp2k_unpack_image(VipsRegion *region, VipsRect *tile, opj_image_t *image) { VipsImage *im = region->im; int b = im->Bands; int x, y, i; for (y = 0; y < tile->height; y++) { VipsPel *p = VIPS_REGION_ADDR(region, tile->left, tile->top + y); for (i = 0; i < b; i++) { opj_image_comp_t *comp = &image->comps[i]; int *q = comp->data + y * comp->w; switch (im->BandFmt) { case VIPS_FORMAT_CHAR: case VIPS_FORMAT_UCHAR: UNPACK(int, unsigned char); break; case VIPS_FORMAT_SHORT: case VIPS_FORMAT_USHORT: UNPACK(int, unsigned short); break; case VIPS_FORMAT_INT: case VIPS_FORMAT_UINT: UNPACK(int, unsigned int); break; default: g_assert_not_reached(); break; } } } } static void vips__foreign_save_jp2k_compress_free(TileCompress *compress) { VIPS_FREEF(opj_destroy_codec, compress->codec); VIPS_FREEF(opj_image_destroy, compress->image); VIPS_FREEF(opj_stream_destroy, compress->stream); VIPS_FREE(compress->accumulate); } /* Compress area @tile within @region and write to @target as a @tile_width by * @tile_height jp2k compressed image. This is called from eg. vips2tiff to * write jp2k-compressed tiles. * * You'd think we could reuse things like the encoder between calls but ... * nope, openjpeg does not allow that. */ int vips__foreign_save_jp2k_compress(VipsRegion *region, VipsRect *tile, VipsTarget *target, int tile_width, int tile_height, gboolean save_as_ycc, gboolean subsample, gboolean lossless, int Q) { TileCompress compress = { 0 }; opj_cparameters_t parameters; size_t sizeof_line; /* Our rgb->ycc only works for exactly 3 bands. */ save_as_ycc = save_as_ycc && region->im->Bands == 3; subsample = subsample && save_as_ycc; /* Set compression params. */ opj_set_default_encoder_parameters(¶meters); /* Set compression profile. */ vips_foreign_save_jp2k_set_profile(¶meters, lossless, Q); /* Makes three band images smaller, somehow. */ parameters.tcp_mct = region->im->Bands >= 3 ? 1 : 0; /* Create output image. TRUE means we alloc memory for the image * planes. */ if (!(compress.image = vips_foreign_save_jp2k_new_image(region->im, tile_width, tile_height, subsample, save_as_ycc, TRUE))) { vips__foreign_save_jp2k_compress_free(&compress); return -1; } /* We need a line of sums for chroma subsample. At worst, gint64. */ sizeof_line = sizeof(gint64) * tile->width; if (!(compress.accumulate = VIPS_ARRAY(NULL, sizeof_line, VipsPel))) { vips__foreign_save_jp2k_compress_free(&compress); return -1; } /* tiff needs a jpeg2000 codestream, not a jp2 file. */ compress.codec = opj_create_compress(OPJ_CODEC_J2K); vips_foreign_save_jp2k_attach_handlers(compress.codec); if (!opj_setup_encoder(compress.codec, ¶meters, compress.image)) { vips__foreign_save_jp2k_compress_free(&compress); return -1; } opj_codec_set_threads(compress.codec, vips_concurrency_get()); if (save_as_ycc) vips_foreign_save_jp2k_rgb_to_ycc(region, tile, compress.image->comps[0].prec); /* we need to unpack to the int arrays on comps[i].data */ if (subsample) vips_foreign_save_jp2k_unpack_subsample_image(region, tile, compress.image, compress.accumulate); else vips_foreign_save_jp2k_unpack_image(region, tile, compress.image); if (!(compress.stream = vips_foreign_save_jp2k_target(target))) { vips__foreign_save_jp2k_compress_free(&compress); return -1; } if (!opj_start_compress(compress.codec, compress.image, compress.stream)) { vips__foreign_save_jp2k_compress_free(&compress); return -1; } if (!opj_encode(compress.codec, compress.stream)) { vips__foreign_save_jp2k_compress_free(&compress); return -1; } opj_end_compress(compress.codec, compress.stream); vips__foreign_save_jp2k_compress_free(&compress); return 0; } #else /*!HAVE_LIBOPENJP2*/ int vips__foreign_save_jp2k_compress(VipsRegion *region, VipsRect *tile, VipsTarget *target, int tile_width, int tile_height, gboolean save_as_ycc, gboolean subsample, gboolean lossless, int Q) { vips_error("jp2k", "%s", _("libvips built without JPEG2000 support")); return -1; } #endif /*HAVE_LIBOPENJP2*/ /** * vips_jp2ksave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file in JPEG2000 format. * * The saver supports 8, 16 and 32-bit int pixel * values, signed and unsigned. It supports greyscale, RGB, CMYK and * multispectral images. * * Use @Q to set the compression quality factor. The default value * produces file with approximately the same size as regular JPEG Q 75. * * Set @lossless to enable lossless compression. * * Use @tile_width and @tile_height to set the tile size. The default is 512. * * Chroma subsampling is normally disabled for compatibility. Set * @subsample_mode to auto to enable chroma subsample for Q < 90. Subsample * mode uses YCC rather than RGB colourspace, and many jpeg2000 decoders do * not support this. * * This operation always writes a pyramid. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @tile_width: `gint`, tile width * * @tile_height: `gint`, tile width * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * ::: seealso * [method@Image.write_to_file], [ctor@Image.jp2kload]. * * Returns: 0 on success, -1 on error. */ int vips_jp2ksave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("jp2ksave", ap, in, filename); va_end(ap); return result; } /** * vips_jp2ksave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jp2ksave], but save to a target. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @tile_width: `gint`, tile width * * @tile_height: `gint`, tile width * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * ::: seealso * [method@Image.jp2ksave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_jp2ksave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("jp2ksave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_jp2ksave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jp2ksave], but save to a target. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @tile_width: `gint`, tile width * * @tile_height: `gint`, tile width * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * ::: seealso * [method@Image.jp2ksave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_jp2ksave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("jp2ksave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/jpeg.h000066400000000000000000000056321516303661500174750ustar00rootroot00000000000000/* common defs for jpeg read/write */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_JPEG_H #define VIPS_JPEG_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* jpeglib defines its own boolean type as an enum which then clashes with * everyone elses. Rename it as jboolean. */ #define boolean jboolean /* Any TRUE/FALSE macros which have crept in will cause terrible confusion as * well. */ #ifdef TRUE #undef TRUE #endif /*TRUE*/ #ifdef FALSE #undef FALSE #endif /*FALSE*/ #include #include #include /* Our custom error message codes. */ #define JERR_VIPS_IMAGE_EOF (1000) #define JWRN_VIPS_IMAGE_EOF JERR_VIPS_IMAGE_EOF #define JERR_VIPS_TARGET_WRITE (1001) /* Define a new error handler for when we bomb out. */ typedef struct { /* Public fields. */ struct jpeg_error_mgr pub; /* Private stuff for us. */ jmp_buf jmp; /* longjmp() here to get back to VIPS */ FILE *fp; /* fclose() if non-NULL */ } ErrorManager; /* Stuff we track during a read. */ typedef struct _ReadJpeg { VipsImage *out; /* Shrink by this much during load. 1, 2, 4, 8. */ int shrink; /* Types of error to cause failure. */ VipsFailOn fail_on; struct jpeg_decompress_struct cinfo; ErrorManager eman; gboolean invert_pels; /* Use orientation tag to automatically rotate and flip image * during load. */ gboolean autorotate; /* Remove DoS limits. */ gboolean unlimited; /* cinfo->output_width and height can be larger than we want since * libjpeg rounds up on shrink-on-load. This is the real size we will * output, as opposed to the size we decompress to. */ int output_width; int output_height; /* The source we read from. */ VipsSource *source; } ReadJpeg; extern const char *vips__jpeg_message_table[]; void vips__new_output_message(j_common_ptr cinfo); void vips__new_error_exit(j_common_ptr cinfo); ReadJpeg *vips__readjpeg_new(VipsSource *source, VipsImage *out, int shrink, VipsFailOn fail_on, gboolean autorotate, gboolean unlimited); int vips__readjpeg_open_input(ReadJpeg *jpeg); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_JPEG_H*/ libvips-8.18.2/libvips/foreign/jpeg2vips.c000066400000000000000000000615671516303661500204650ustar00rootroot00000000000000/* wrap jpeg library for read * * 28/11/03 JC * - better no-overshoot on tile loop * 12/11/04 * - better demand size choice for eval * 30/6/05 JC * - update im_error()/im_warn() * - now loads and saves exif data * 30/7/05 * - now loads ICC profiles * - now saves ICC profiles from the VIPS header * 24/8/05 * - jpeg load sets vips xres/yres from exif, if possible * - jpeg save sets exif xres/yres from vips, if possible * 29/8/05 * - cut from old vips_jpeg.c * 13/10/06 * - add #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_JPEG #include #include #include #include #include #include #include "pforeign.h" #include "jpeg.h" #define SOURCE_BUFFER_SIZE (4096) /* Private struct for source input. */ typedef struct { /* Public jpeg fields. */ struct jpeg_source_mgr pub; /* Private stuff during read. */ ReadJpeg *jpeg; VipsSource *source; unsigned char buf[SOURCE_BUFFER_SIZE]; } Source; static void source_init_source(j_decompress_ptr cinfo) { /* No work necessary here. */ } /* Fill the input buffer -- called whenever buffer is emptied. */ static boolean source_fill_input_buffer(j_decompress_ptr cinfo) { Source *src = (Source *) cinfo->src; gint64 n_bytes; if ((n_bytes = vips_source_read(src->source, src->buf, SOURCE_BUFFER_SIZE)) <= 0) { if (src->jpeg->fail_on >= VIPS_FAIL_ON_TRUNCATED) { /* Knock the output out of cache. */ vips_foreign_load_invalidate(src->jpeg->out); ERREXIT(cinfo, JERR_VIPS_IMAGE_EOF); } else WARNMS(cinfo, JWRN_VIPS_IMAGE_EOF); /* Insert a fake EOI marker. */ src->buf[0] = (JOCTET) 0xFF; src->buf[1] = (JOCTET) JPEG_EOI; n_bytes = 2; } src->pub.next_input_byte = src->buf; src->pub.bytes_in_buffer = n_bytes; return TRUE; } static boolean source_fill_input_buffer_mappable(j_decompress_ptr cinfo) { Source *src = (Source *) cinfo->src; if (src->jpeg->fail_on >= VIPS_FAIL_ON_TRUNCATED) { /* Knock the output out of cache. */ vips_foreign_load_invalidate(src->jpeg->out); ERREXIT(cinfo, JERR_VIPS_IMAGE_EOF); } else WARNMS(cinfo, JWRN_VIPS_IMAGE_EOF); /* Insert a fake EOI marker. */ src->buf[0] = (JOCTET) 0xFF; src->buf[1] = (JOCTET) JPEG_EOI; src->pub.next_input_byte = src->buf; src->pub.bytes_in_buffer = 2; return TRUE; } static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { struct jpeg_source_mgr *src = cinfo->src; if (num_bytes > 0) { while (num_bytes > (long) src->bytes_in_buffer) { num_bytes -= (long) src->bytes_in_buffer; (void) (*src->fill_input_buffer)(cinfo); /* note we assume that fill_input_buffer will never * return FALSE, so suspension need not be handled. */ } src->next_input_byte += (size_t) num_bytes; src->bytes_in_buffer -= (size_t) num_bytes; } } static void skip_input_data_mappable(j_decompress_ptr cinfo, long num_bytes) { struct jpeg_source_mgr *src = cinfo->src; if (num_bytes > (long) src->bytes_in_buffer) { src->next_input_byte += src->bytes_in_buffer; src->bytes_in_buffer = 0; } else { src->next_input_byte += (size_t) num_bytes; src->bytes_in_buffer -= (size_t) num_bytes; } } int vips__readjpeg_open_input(ReadJpeg *jpeg) { j_decompress_ptr cinfo = &jpeg->cinfo; if (jpeg->source && !cinfo->src) { Source *src; if (vips_source_rewind(jpeg->source)) return -1; cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)( (j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(Source)); src = (Source *) cinfo->src; src->jpeg = jpeg; src->source = jpeg->source; src->pub.init_source = source_init_source; /* Use default method. */ src->pub.resync_to_restart = jpeg_resync_to_restart; if (vips_source_is_mappable(jpeg->source)) { size_t src_len; const unsigned char *src_data = vips_source_map(jpeg->source, &src_len); src->pub.fill_input_buffer = source_fill_input_buffer_mappable; src->pub.skip_input_data = skip_input_data_mappable; src->pub.bytes_in_buffer = src_len; src->pub.next_input_byte = src_data; } else { src->pub.fill_input_buffer = source_fill_input_buffer; src->pub.skip_input_data = skip_input_data; /* Forces fill_input_buffer on first read. */ src->pub.bytes_in_buffer = 0; /* Until buffer loaded. */ src->pub.next_input_byte = NULL; } } return 0; } static void readjpeg_emit_message(j_common_ptr cinfo, int msg_level) { ReadJpeg *jpeg = (ReadJpeg *) cinfo->client_data; long num_warnings; if (msg_level < 0) { /* Always count warnings in num_warnings. */ num_warnings = ++cinfo->err->num_warnings; /* Corrupt files may give many warnings, the policy here is to * show only the first warning and treat many warnings as fatal, * unless unlimited is set. */ if (num_warnings == 1) (*cinfo->err->output_message)(cinfo); else if (!jpeg || (!jpeg->unlimited && num_warnings >= 100)) cinfo->err->error_exit(cinfo); } else if (cinfo->err->trace_level >= msg_level) /* It's a trace message. Show it if trace_level >= msg_level. */ (*cinfo->err->output_message)(cinfo); } /* This can be called many times. */ static int readjpeg_free(ReadJpeg *jpeg) { if (jpeg->eman.pub.num_warnings != 0) { g_warning("read gave %ld warnings", jpeg->eman.pub.num_warnings); g_warning("%s", vips_error_buffer()); /* Make the message only appear once. */ jpeg->eman.pub.num_warnings = 0; } /* Don't call jpeg_finish_decompress(). It just checks the tail of the * file and who cares about that. All mem is freed in * jpeg_destroy_decompress(). */ /* I don't think this can fail. It's harmless to call many times. */ jpeg_destroy_decompress(&jpeg->cinfo); VIPS_UNREF(jpeg->source); return 0; } static void readjpeg_close_cb(VipsImage *image, ReadJpeg *jpeg) { (void) readjpeg_free(jpeg); } static void readjpeg_minimise_cb(VipsImage *image, ReadJpeg *jpeg) { vips_source_minimise(jpeg->source); } /* Shared with uhdr load (for fast uhdr detect). */ ReadJpeg * vips__readjpeg_new(VipsSource *source, VipsImage *out, int shrink, VipsFailOn fail_on, gboolean autorotate, gboolean unlimited) { ReadJpeg *jpeg; if (!(jpeg = VIPS_NEW(out, ReadJpeg))) return NULL; jpeg->out = out; jpeg->source = source; g_object_ref(source); jpeg->shrink = shrink; jpeg->fail_on = fail_on; jpeg->cinfo.err = jpeg_std_error(&jpeg->eman.pub); jpeg->cinfo.err->addon_message_table = vips__jpeg_message_table; jpeg->cinfo.err->first_addon_message = 1000; jpeg->cinfo.err->last_addon_message = 1001; jpeg->eman.pub.error_exit = vips__new_error_exit; jpeg->eman.pub.emit_message = readjpeg_emit_message; jpeg->eman.pub.output_message = vips__new_output_message; jpeg->eman.fp = NULL; jpeg->autorotate = autorotate; jpeg->unlimited = unlimited; jpeg->cinfo.client_data = jpeg; /* jpeg_create_decompress() can fail on some sanity checks. Don't * readjpeg_free() since we don't want to jpeg_destroy_decompress(). */ if (setjmp(jpeg->eman.jmp)) return NULL; jpeg_create_decompress(&jpeg->cinfo); g_signal_connect(out, "close", G_CALLBACK(readjpeg_close_cb), jpeg); g_signal_connect(out, "minimise", G_CALLBACK(readjpeg_minimise_cb), jpeg); return jpeg; } static const char * find_chroma_subsample(struct jpeg_decompress_struct *cinfo) { /* libjpeg only uses 4:4:4 and 4:2:0, confusingly. * * http://poynton.ca/PDFs/Chroma_subsampling_notation.pdf */ gboolean has_subsample = cinfo->max_h_samp_factor > 1 || cinfo->max_v_samp_factor > 1; gboolean is_cmyk = cinfo->num_components > 3; return is_cmyk ? (has_subsample ? "4:2:0:4" : "4:4:4:4") : (has_subsample ? "4:2:0" : "4:4:4"); } static void attach_blob(VipsImage *im, const char *field, void *data, size_t data_length) { /* Only use the first one. */ if (vips_image_get_typeof(im, field)) { #ifdef DEBUG printf("attach_blob: second %s block, ignoring\n", field); #endif /*DEBUG*/ return; } #ifdef DEBUG printf("attach_blob: attaching %zd bytes of %s\n", data_length, field); #endif /*DEBUG*/ vips_image_set_blob_copy(im, field, data, data_length); } /* data is the XMP string ... it'll have something like * "http://ns.adobe.com/xap/1.0/" at the front, then a null character, then * the real XMP. */ static void attach_xmp_blob(VipsImage *im, char *data, size_t data_length) { /* Search for a null char within the first few characters. 80 * should be plenty for a basic URL. * * -2 for the extra null. */ char *p = memchr(data, '\0', VIPS_MIN(80, data_length - 2)); if (!p) return; size_t i = p - data; data_length -= i + 1; attach_blob(im, VIPS_META_XMP_NAME, data + i + 1, data_length); } /* Number of app2 sections we can capture. Each one can be 64k, so 6400k should * be enough for anyone (haha). */ #define MAX_APP2_SECTIONS (100) /* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to * do 255-pel. */ static int read_jpeg_header(ReadJpeg *jpeg, VipsImage *out) { struct jpeg_decompress_struct *cinfo = &jpeg->cinfo; jpeg_saved_marker_ptr p; VipsInterpretation interpretation; double xres, yres; /* Capture app2 sections here for assembly. */ void *app2_data[MAX_APP2_SECTIONS] = { 0 }; size_t app2_data_length[MAX_APP2_SECTIONS] = { 0 }; size_t data_length; int i; /* Read JPEG header. libjpeg will set out_color_space sanely for us * for YUV YCCK etc. */ jpeg_read_header(cinfo, TRUE); cinfo->scale_denom = jpeg->shrink; cinfo->scale_num = 1; jpeg_calc_output_dimensions(cinfo); jpeg->invert_pels = FALSE; switch (cinfo->out_color_space) { case JCS_GRAYSCALE: interpretation = VIPS_INTERPRETATION_B_W; break; case JCS_CMYK: interpretation = VIPS_INTERPRETATION_CMYK; /* CMYKs are almost always returned inverted, but see below. */ jpeg->invert_pels = TRUE; break; case JCS_RGB: default: interpretation = VIPS_INTERPRETATION_sRGB; break; } #ifdef DEBUG if (cinfo->saw_JFIF_marker) printf("read_jpeg_header: jfif _density %d, %d, unit %d\n", cinfo->X_density, cinfo->Y_density, cinfo->density_unit); #endif /*DEBUG*/ /* Get the jfif resolution. exif may overwrite this later. Default to * 72dpi (as EXIF does). */ xres = 72.0 / 25.4; yres = 72.0 / 25.4; if (cinfo->saw_JFIF_marker && cinfo->X_density != 1U && cinfo->Y_density != 1U) { switch (cinfo->density_unit) { case 0: /* X_density / Y_density gives the pixel aspect ratio. * Leave xres, but adjust yres. */ if (cinfo->Y_density > 0) yres = xres * cinfo->X_density / cinfo->Y_density; break; case 1: /* Pixels per inch. */ xres = cinfo->X_density / 25.4; yres = cinfo->Y_density / 25.4; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "in"); break; case 2: /* Pixels per cm. */ xres = cinfo->X_density / 10.0; yres = cinfo->Y_density / 10.0; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "cm"); break; default: g_warning("unknown JFIF resolution unit"); break; } #ifdef DEBUG printf("read_jpeg_header: seen jfif resolution %g, %g p/mm\n", xres, yres); #endif /*DEBUG*/ } /* Set VIPS header. */ vips_image_init_fields(out, cinfo->output_width, cinfo->output_height, cinfo->output_components, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, interpretation, xres, yres); VIPS_SETSTR(out->filename, vips_connection_filename(VIPS_CONNECTION(jpeg->source))); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_FATSTRIP, NULL)) return -1; /* cinfo->output_width and cinfo->output_height round up with * shrink-on-load. For example, if the image is 1801 pixels across and * we shrink by 4, the output will be 450.25 pixels across, * cinfo->output_width with be 451, and libjpeg will write a black * column of pixels down the right. * * We must strictly round down, since we don't want fractional pixels * along the bottom and right. */ jpeg->output_width = cinfo->image_width / jpeg->shrink; jpeg->output_height = cinfo->image_height / jpeg->shrink; /* Interlaced jpegs need lots of memory to read, so our caller needs * to know. */ (void) vips_image_set_int(out, "jpeg-multiscan", jpeg_has_multiple_scans(cinfo)); /* 8.7 adds this for PNG as well, so we have a new format-neutral name. */ if (jpeg_has_multiple_scans(cinfo)) vips_image_set_int(out, "interlaced", 1); (void) vips_image_set_string(out, "jpeg-chroma-subsample", find_chroma_subsample(cinfo)); /* Look for EXIF and ICC profile. */ for (p = cinfo->marker_list; p; p = p->next) { #ifdef DEBUG { printf("read_jpeg_header: seen %u bytes of APP%d\n", p->data_length, p->marker - JPEG_APP0); i = 0; for (int row = 0; i < VIPS_MIN(100, p->data_length); row++) { printf(" 0x%02x)", i); for (int col = 0; col < 8 && i < VIPS_MIN(100, p->data_length); col++, i++) { printf(" %02x", p->data[i]); if (p->data[i] > 32 && p->data[i] < 127) printf(" '%c'", p->data[i]); else printf(" "); } printf("\n"); } } #endif /*DEBUG*/ switch (p->marker) { case JPEG_APP0 + 1: /* Possible EXIF or XMP data. */ if (p->data_length > 4 && vips_isprefix("Exif", (char *) p->data)) attach_blob(out, VIPS_META_EXIF_NAME, p->data, p->data_length); if (p->data_length > 4 && vips_isprefix("http", (char *) p->data)) attach_xmp_blob(out, (char *) p->data, p->data_length); break; case JPEG_APP0 + 2: /* Possible ICC profile. */ if (p->data_length > 14 && vips_isprefix("ICC_PROFILE", (char *) p->data)) { /* cur_marker numbers from 1, according to * spec. */ int cur_marker = p->data[12] - 1; if (cur_marker >= 0 && cur_marker < MAX_APP2_SECTIONS) { app2_data[cur_marker] = p->data + 14; app2_data_length[cur_marker] = p->data_length - 14; } } break; case JPEG_APP0 + 13: /* Possible IPTC data block. */ if (p->data_length > 5 && vips_isprefix("Photo", (char *) p->data)) { attach_blob(out, VIPS_META_IPTC_NAME, p->data, p->data_length); /* Older versions of libvips used this misspelt * name :-( attach under this name too for * compatibility. */ attach_blob(out, "ipct-data", p->data, p->data_length); } break; case JPEG_APP0 + 14: /* Adobe block. There's a lot of confusion about * whether or not CMYK jpg images are inverted. For * the images we have, it seems they should always * invert. * * See: https://sno.phy.queensu.ca/~phil/exiftool/\ * TagNames/JPEG.html#Adobe * * data[11] == 0 - unknown * data[11] == 1 - YCbCr * data[11] == 2 - YCCK * * Leave this code here in case we come up with a * better rule. Make sure to also uncomment * jpeg_save_markers() for the APP14 marker. */ if (p->data_length >= 12 && vips_isprefix("Adobe", (char *) p->data)) { if (p->data[11] == 0) { #ifdef DEBUG printf("complete Adobe block, not YCCK image\n"); #endif /*DEBUG*/ // jpeg->invert_pels = FALSE; } } break; default: #ifdef DEBUG printf("read_jpeg_header: " "ignoring %u byte APP%d block\n", p->data_length, p->marker - JPEG_APP0); #endif /*DEBUG*/ break; } } /* Assemble ICC sections. */ data_length = 0; for (i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++) data_length += app2_data_length[i]; if (data_length) { unsigned char *data; int p; #ifdef DEBUG printf("read_jpeg_header: assembled %zd byte ICC profile\n", data_length); #endif /*DEBUG*/ if (!(data = vips_malloc(NULL, data_length))) return -1; p = 0; for (i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++) { memcpy(data + p, app2_data[i], app2_data_length[i]); p += app2_data_length[i]; } vips_image_set_blob(out, VIPS_META_ICC_NAME, (VipsCallbackFn) vips_area_free_cb, data, data_length); } return 0; } static int read_jpeg_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; ReadJpeg *jpeg = (ReadJpeg *) a; struct jpeg_decompress_struct *cinfo = &jpeg->cinfo; int sz = cinfo->output_width * cinfo->output_components; int y; #ifdef DEBUG_VERBOSE printf("read_jpeg_generate: %p line %d, %d rows\n", g_thread_self(), r->top, r->height); #endif /*DEBUG_VERBOSE*/ VIPS_GATE_START("read_jpeg_generate: work"); /* We're inside a tilecache where tiles are the full image width, so * this should always be true. */ g_assert(r->left == 0); g_assert(r->width == out_region->im->Xsize); g_assert(VIPS_RECT_BOTTOM(r) <= out_region->im->Ysize); /* Tiles should always be on a 8-pixel boundary. */ g_assert(r->top % 8 == 0); /* Tiles should always be a strip in height, unless it's the final * strip. */ g_assert(r->height == VIPS_MIN(8, out_region->im->Ysize - r->top)); /* And check that the y position is correct. It should be, since we are * inside a vips_sequential(). */ if (r->top != cinfo->output_scanline) { VIPS_GATE_STOP("read_jpeg_generate: work"); vips_error("VipsJpeg", _("out of order read at line %d"), cinfo->output_scanline); return -1; } /* Here for longjmp() from vips__new_error_exit() during * jpeg_read_scanlines(). */ if (setjmp(jpeg->eman.jmp)) { VIPS_GATE_STOP("read_jpeg_generate: work"); #ifdef DEBUG printf("read_jpeg_generate() exit\n"); #endif /*DEBUG*/ return -1; } if (jpeg->eman.pub.num_warnings > 0 && jpeg->fail_on >= VIPS_FAIL_ON_WARNING) { VIPS_GATE_STOP("read_jpeg_generate: work"); /* Only fail once. */ jpeg->eman.pub.num_warnings = 0; return -1; } for (y = 0; y < r->height; y++) { JSAMPROW row_pointer[1]; row_pointer[0] = (JSAMPLE *) VIPS_REGION_ADDR(out_region, 0, r->top + y); jpeg_read_scanlines(cinfo, &row_pointer[0], 1); if (jpeg->invert_pels) { int x; for (x = 0; x < sz; x++) row_pointer[0][x] = 255 - row_pointer[0][x]; } } VIPS_GATE_STOP("read_jpeg_generate: work"); return 0; } /* Read a cinfo to a VIPS image. */ static int read_jpeg_image(ReadJpeg *jpeg, VipsImage *out) { struct jpeg_decompress_struct *cinfo = &jpeg->cinfo; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 5); VipsImage *im; /* Here for longjmp() from vips__new_error_exit() during * jpeg_read_header() or jpeg_start_decompress(). */ if (setjmp(jpeg->eman.jmp)) return -1; t[0] = vips_image_new(); if (read_jpeg_header(jpeg, t[0])) return -1; /* Switch to pixel decode. */ if (vips_source_decode(jpeg->source)) return -1; jpeg_start_decompress(cinfo); #ifdef DEBUG printf("read_jpeg_image: starting decompress\n"); #endif /*DEBUG*/ /* We must crop after the seq, or our generate may not be asked for * full lines of pixels and will attempt to write beyond the buffer. */ if (vips_image_generate(t[0], NULL, read_jpeg_generate, NULL, jpeg, NULL) || vips_sequential(t[0], &t[1], "tile_height", 8, NULL) || vips_extract_area(t[1], &t[2], 0, 0, jpeg->output_width, jpeg->output_height, NULL)) return -1; im = t[2]; if (jpeg->autorotate && vips_image_get_orientation(im) != 1) { /* We have to copy to memory before calling autorot, since it * needs random access. */ if (!(t[3] = vips_image_copy_memory(im)) || vips_autorot(t[3], &t[4], NULL)) return -1; im = t[4]; } if (vips_image_write(im, out)) return -1; return 0; } static int jpeg_read(ReadJpeg *jpeg, VipsImage *out, gboolean header_only) { /* Need to read in APP1 (EXIF/XMP metadata), APP2 (ICC profile) and APP13 * (photoshop IPTC). */ jpeg_save_markers(&jpeg->cinfo, JPEG_APP0 + 1, 0xffff); jpeg_save_markers(&jpeg->cinfo, JPEG_APP0 + 2, 0xffff); jpeg_save_markers(&jpeg->cinfo, JPEG_APP0 + 13, 0xffff); /* APP14 (Adobe flags), deliberately ignored, see above. */ // jpeg_save_markers(&jpeg->cinfo, JPEG_APP0 + 14, 0xffff); #ifdef DEBUG { int i; /* Handy for debugging ... spot any extra markers. */ for (i = 0; i < 16; i++) jpeg_save_markers(&jpeg->cinfo, JPEG_APP0 + i, 0xffff); } #endif /*DEBUG*/ /* Convert! */ if (header_only) { if (read_jpeg_header(jpeg, out)) return -1; /* Patch in the correct size. */ out->Xsize = jpeg->output_width; out->Ysize = jpeg->output_height; /* Swap width and height if we're going to rotate this image. */ if (jpeg->autorotate) { if (vips_image_get_orientation_swap(out)) VIPS_SWAP(int, out->Xsize, out->Ysize); vips_autorot_remove_angle(out); } } else { if (read_jpeg_image(jpeg, out)) return -1; } return 0; } int vips__jpeg_read_source(VipsSource *source, VipsImage *out, gboolean header_only, int shrink, VipsFailOn fail_on, gboolean autorotate, gboolean unlimited) { ReadJpeg *jpeg; if (!(jpeg = vips__readjpeg_new(source, out, shrink, fail_on, autorotate, unlimited))) return -1; /* Here for longjmp() from vips__new_error_exit() during * cinfo->mem->alloc_small() or jpeg_read_header(). */ if (setjmp(jpeg->eman.jmp)) return -1; if (vips__readjpeg_open_input(jpeg) || jpeg_read(jpeg, out, header_only)) return -1; if (header_only) vips_source_minimise(source); return 0; } int vips__isjpeg_source(VipsSource *source) { const unsigned char *p; if ((p = vips_source_sniff(source, 2)) && p[0] == 0xff && p[1] == 0xd8) return 1; return 0; } #endif /*HAVE_JPEG*/ libvips-8.18.2/libvips/foreign/jpegload.c000066400000000000000000000370071516303661500203310ustar00rootroot00000000000000/* load jpeg from a file * * 24/11/11 * - wrap a class around the jpeg writer * 29/11/11 * - split to make load, load from buffer and load from file * 24/7/21 * - add fail_on support */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_JPEG #ifdef HAVE_EXIF #ifdef UNTAGGED_EXIF #include #include #include #include #else /*!UNTAGGED_EXIF*/ #include #include #include #include #endif /*UNTAGGED_EXIF*/ #endif /*HAVE_EXIF*/ typedef struct _VipsForeignLoadJpeg { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Remove DoS limits. */ gboolean unlimited; /* Shrink by this much during load. */ int shrink; /* Autorotate using exif orientation tag. */ gboolean autorotate; } VipsForeignLoadJpeg; typedef VipsForeignLoadClass VipsForeignLoadJpegClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadJpeg, vips_foreign_load_jpeg, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_jpeg_dispose(GObject *gobject) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) gobject; VIPS_UNREF(jpeg->source); G_OBJECT_CLASS(vips_foreign_load_jpeg_parent_class)->dispose(gobject); } static int vips_foreign_load_jpeg_build(VipsObject *object) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object; if (jpeg->shrink != 1 && jpeg->shrink != 2 && jpeg->shrink != 4 && jpeg->shrink != 8) { vips_error("VipsFormatLoadJpeg", _("bad shrink factor %d"), jpeg->shrink); return -1; } return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_jpeg_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_SEQUENTIAL; } static VipsForeignFlags vips_foreign_load_jpeg_get_flags_filename(const char *filename) { return VIPS_FOREIGN_SEQUENTIAL; } static int vips_foreign_load_jpeg_header(VipsForeignLoad *load) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; if (vips__jpeg_read_source(jpeg->source, load->out, TRUE, jpeg->shrink, load->fail_on, jpeg->autorotate, jpeg->unlimited)) return -1; return 0; } static int vips_foreign_load_jpeg_load(VipsForeignLoad *load) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load; if (vips__jpeg_read_source(jpeg->source, load->real, FALSE, jpeg->shrink, load->fail_on, jpeg->autorotate, jpeg->unlimited)) return -1; return 0; } static void vips_foreign_load_jpeg_class_init(VipsForeignLoadJpegClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_jpeg_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegload_base"; object_class->description = _("load jpeg"); object_class->build = vips_foreign_load_jpeg_build; /* We are fast at is_a(), so high priority. */ foreign_class->priority = 50; load_class->get_flags_filename = vips_foreign_load_jpeg_get_flags_filename; load_class->get_flags = vips_foreign_load_jpeg_get_flags; load_class->header = vips_foreign_load_jpeg_header; load_class->load = vips_foreign_load_jpeg_load; VIPS_ARG_INT(class, "shrink", 20, _("Shrink"), _("Shrink factor on load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJpeg, shrink), 1, 8, 1); VIPS_ARG_BOOL(class, "autorotate", 21, _("Autorotate"), _("Rotate image using exif orientation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJpeg, autorotate), FALSE); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VIPS_ARG_BOOL(class, "unlimited", 22, _("Unlimited"), _("Remove all denial of service limits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJpeg, unlimited), FALSE); #endif } static void vips_foreign_load_jpeg_init(VipsForeignLoadJpeg *jpeg) { jpeg->shrink = 1; } typedef struct _VipsForeignLoadJpegSource { VipsForeignLoadJpeg parent_object; VipsSource *source; } VipsForeignLoadJpegSource; typedef VipsForeignLoadJpegClass VipsForeignLoadJpegSourceClass; G_DEFINE_TYPE(VipsForeignLoadJpegSource, vips_foreign_load_jpeg_source, vips_foreign_load_jpeg_get_type()); static int vips_foreign_load_jpeg_source_build(VipsObject *object) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object; VipsForeignLoadJpegSource *source = (VipsForeignLoadJpegSource *) object; if (source->source) { jpeg->source = source->source; g_object_ref(jpeg->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_source_parent_class) ->build(object); } static gboolean vips_foreign_load_jpeg_source_is_a_source(VipsSource *source) { return vips__isjpeg_source(source); } static void vips_foreign_load_jpeg_source_class_init( VipsForeignLoadJpegSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegload_source"; object_class->description = _("load image from jpeg source"); object_class->build = vips_foreign_load_jpeg_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_jpeg_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJpegSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_jpeg_source_init(VipsForeignLoadJpegSource *source) { } typedef struct _VipsForeignLoadJpegFile { VipsForeignLoadJpeg parent_object; char *filename; } VipsForeignLoadJpegFile; typedef VipsForeignLoadJpegClass VipsForeignLoadJpegFileClass; G_DEFINE_TYPE(VipsForeignLoadJpegFile, vips_foreign_load_jpeg_file, vips_foreign_load_jpeg_get_type()); static int vips_foreign_load_jpeg_file_build(VipsObject *object) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object; VipsForeignLoadJpegFile *file = (VipsForeignLoadJpegFile *) object; if (file->filename && !(jpeg->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_file_parent_class) ->build(object); } static gboolean vips_foreign_load_jpeg_file_is_a(const char *filename) { VipsSource *source; if (!(source = vips_source_new_from_file(filename))) return FALSE; gboolean is_a = vips_foreign_load_jpeg_source_is_a_source(source); VIPS_UNREF(source); return is_a; } static void vips_foreign_load_jpeg_file_class_init(VipsForeignLoadJpegFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegload"; object_class->description = _("load jpeg from file"); object_class->build = vips_foreign_load_jpeg_file_build; foreign_class->suffs = vips__jpeg_suffs; load_class->is_a = vips_foreign_load_jpeg_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJpegFile, filename), NULL); } static void vips_foreign_load_jpeg_file_init(VipsForeignLoadJpegFile *file) { } typedef struct _VipsForeignLoadJpegBuffer { VipsForeignLoadJpeg parent_object; VipsBlob *blob; } VipsForeignLoadJpegBuffer; typedef VipsForeignLoadJpegClass VipsForeignLoadJpegBufferClass; G_DEFINE_TYPE(VipsForeignLoadJpegBuffer, vips_foreign_load_jpeg_buffer, vips_foreign_load_jpeg_get_type()); static int vips_foreign_load_jpeg_buffer_build(VipsObject *object) { VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) object; VipsForeignLoadJpegBuffer *buffer = (VipsForeignLoadJpegBuffer *) object; if (buffer->blob && !(jpeg->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_jpeg_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_jpeg_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_jpeg_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_jpeg_buffer_class_init( VipsForeignLoadJpegBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegload_buffer"; object_class->description = _("load jpeg from buffer"); object_class->build = vips_foreign_load_jpeg_buffer_build; load_class->is_a_buffer = vips_foreign_load_jpeg_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJpegBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_jpeg_buffer_init(VipsForeignLoadJpegBuffer *buffer) { } #endif /*HAVE_JPEG*/ /** * vips_jpegload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a JPEG file into a VIPS image. It can read most 8-bit JPEG images, * including CMYK and YCbCr. * * @shrink means shrink by this integer factor during load. Possible values * are 1, 2, 4 and 8. Shrinking during read is very much faster than * decompressing the whole image and then shrinking later. * * Use @fail_on to set the type of error that will cause load to fail. By * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE]. * * Setting @autorotate to `TRUE` will make the loader interpret the * orientation tag and automatically rotate the image appropriately during * load. * * If @autorotate is `FALSE`, the metadata field [const@META_ORIENTATION] is set * to the value of the orientation tag. Applications may read and interpret * this field * as they wish later in processing. See [method@Image.autorot]. Save * operations will use [const@META_ORIENTATION], if present, to set the * orientation of output images. * * Example: * * ```c * vips_jpegload("fred.jpg", &out, * "shrink", 8, * "fail_on", VIPS_FAIL_ON_TRUNCATED, * NULL); * ``` * * Any embedded ICC profiles are ignored: you always just get the RGB from * the file. Instead, the embedded profile will be attached to the image as * [const@META_ICC_NAME]. You need to use something like * [method@Image.icc_import] to get CIE values from the file. * * EXIF metadata is attached as [const@META_EXIF_NAME], IPTC as * [const@META_IPTC_NAME], and XMP as [const@META_XMP_NAME]. * * The int metadata item "jpeg-multiscan" is set to the result of * `jpeg_has_multiple_scans()`. Interlaced jpeg images need a large amount of * memory to load, so this field gives callers a chance to handle these * images differently. * * The string-valued field "jpeg-chroma-subsample" gives the chroma subsample * in standard notation. 4:4:4 means no subsample, 4:2:0 means YCbCr with * Cb and Cr subsampled horizontally and vertically, 4:4:4:4 means a CMYK * image with no subsampling. * * The EXIF thumbnail, if present, is attached to the image as * "jpeg-thumbnail-data". See [method@Image.get_blob]. * * ::: tip "Optional arguments" * * @shrink: `gint`, shrink by this much on load * * @fail_on: [enum@FailOn], types of read error to fail on * * @autorotate: `gboolean`, use exif Orientation tag to rotate the image * during load * * ::: seealso * [ctor@Image.jpegload_buffer], [method@Image.autorot]. * * Returns: 0 on success, -1 on error. */ int vips_jpegload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("jpegload", ap, filename, out); va_end(ap); return result; } /** * vips_jpegload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a JPEG-formatted memory block into a VIPS image. Exactly as * [ctor@Image.jpegload], but read from a memory buffer. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @shrink: `gint`, shrink by this much on load * * @fail_on: [enum@FailOn], types of read error to fail on * * @autorotate: `gboolean`, use exif Orientation tag to rotate the image * during load * * ::: seealso * [ctor@Image.jpegload]. * * Returns: 0 on success, -1 on error. */ int vips_jpegload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("jpegload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_jpegload_source: * @source: source to load * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a JPEG-formatted memory block into a VIPS image. Exactly as * [ctor@Image.jpegload], but read from a source. * * ::: tip "Optional arguments" * * @shrink: `gint`, shrink by this much on load * * @fail_on: [enum@FailOn], types of read error to fail on * * @autorotate: `gboolean`, use exif Orientation tag to rotate the image * during load * * ::: seealso * [ctor@Image.jpegload]. * * Returns: 0 on success, -1 on error. */ int vips_jpegload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("jpegload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/jpegsave.c000066400000000000000000000536511516303661500203530ustar00rootroot00000000000000/* save to jpeg * * 24/11/11 * - wrap a class around the jpeg writer * 18/2/20 Elad-Laufer * - add subsample_mode, deprecate no_subsample */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_JPEG typedef struct _VipsForeignSaveJpeg { VipsForeignSave parent_object; // set by subclasses VipsTarget *target; /* Quality factor. */ int Q; /* Compute optimal Huffman coding tables. */ gboolean optimize_coding; /* Generate an interlaced (progressive, in jpg terminology) file. */ gboolean interlace; /* Deprecated: Disable chroma subsampling. Use subsample_mode instead. */ gboolean no_subsample; /* Select chroma subsampling mode: * auto will disable subsampling for Q >= 90 * on will always enable subsampling * off will always disable subsampling */ VipsForeignSubsample subsample_mode; /* Apply trellis quantisation to each 8x8 block. */ gboolean trellis_quant; /* Apply overshooting to samples with extreme values e.g. 0 & 255 * for 8-bit. */ gboolean overshoot_deringing; /* Split the spectrum of DCT coefficients into separate scans. */ gboolean optimize_scans; /* Use predefined quantization table with given index. */ int quant_table; /* Use an MCU restart interval. */ int restart_interval; } VipsForeignSaveJpeg; typedef VipsForeignSaveClass VipsForeignSaveJpegClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveJpeg, vips_foreign_save_jpeg, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_jpeg_dispose(GObject *gobject) { VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) gobject; VIPS_UNREF(jpeg->target); G_OBJECT_CLASS(vips_foreign_save_jpeg_parent_class)->dispose(gobject); } #define UC VIPS_FORMAT_UCHAR /* Type promotion for save ... just always go to uchar. */ static VipsBandFormat bandfmt_jpeg[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static int vips_foreign_save_jpeg_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object; if (VIPS_OBJECT_CLASS(vips_foreign_save_jpeg_parent_class)->build(object)) return -1; /* no_subsample is deprecated, but we retain backwards compatibility * new code should use subsample_mode */ if (vips_object_argument_isset(object, "no_subsample")) jpeg->subsample_mode = jpeg->no_subsample ? VIPS_FOREIGN_SUBSAMPLE_OFF : VIPS_FOREIGN_SUBSAMPLE_AUTO; if (vips_image_get_typeof(save->ready, "gainmap-data") || save->ready->Type == VIPS_INTERPRETATION_scRGB) { /* Pass on to uhdrsave. */ if (vips_uhdrsave_target(save->ready, jpeg->target, "Q", jpeg->Q, NULL)) return -1; } else { /* This is a SAVEABLE_ANY image, we need mono, rgb, cmyk for JPEG * save. */ VipsImage *x; if (vips__foreign_convert_saveable(save->ready, &x, VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_CMYK, bandfmt_jpeg, VIPS_FOREIGN_CODING_NONE, save->background)) return -1; if (vips__jpeg_write_target(x, jpeg->target, jpeg->Q, save->profile, jpeg->optimize_coding, jpeg->interlace, jpeg->trellis_quant, jpeg->overshoot_deringing, jpeg->optimize_scans, jpeg->quant_table, jpeg->subsample_mode, jpeg->restart_interval)) { VIPS_UNREF(x); return -1; } VIPS_UNREF(x); } return 0; } static void vips_foreign_save_jpeg_class_init(VipsForeignSaveJpegClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; gobject_class->dispose = vips_foreign_save_jpeg_dispose; object_class->nickname = "jpegsave_base"; object_class->description = _("save as jpeg"); object_class->build = vips_foreign_save_jpeg_build; foreign_class->suffs = vips__jpeg_suffs; /* We need to let scRGB through in case this is an scRGB image. * * See also vips_foreign_save_tiff_build() when saving JPEG in TIFF. */ save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; VIPS_ARG_INT(class, "Q", 10, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, Q), 1, 100, 75); VIPS_ARG_BOOL(class, "optimize_coding", 12, _("Optimize coding"), _("Compute optimal Huffman coding tables"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, optimize_coding), FALSE); VIPS_ARG_BOOL(class, "interlace", 13, _("Interlace"), _("Generate an interlaced (progressive) jpeg"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, interlace), FALSE); VIPS_ARG_BOOL(class, "no_subsample", 14, _("No subsample"), _("Disable chroma subsample"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveJpeg, no_subsample), FALSE); VIPS_ARG_BOOL(class, "trellis_quant", 15, _("Trellis quantisation"), _("Apply trellis quantisation to each 8x8 block"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, trellis_quant), FALSE); VIPS_ARG_BOOL(class, "overshoot_deringing", 16, _("Overshoot de-ringing"), _("Apply overshooting to samples with extreme values"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, overshoot_deringing), FALSE); VIPS_ARG_BOOL(class, "optimize_scans", 17, _("Optimize scans"), _("Split spectrum of DCT coefficients into separate scans"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, optimize_scans), FALSE); VIPS_ARG_INT(class, "quant_table", 18, _("Quantization table"), _("Use predefined quantization table with given index"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, quant_table), 0, 8, 0); VIPS_ARG_ENUM(class, "subsample_mode", 19, _("Subsample mode"), _("Select chroma subsample operation mode"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, subsample_mode), VIPS_TYPE_FOREIGN_SUBSAMPLE, VIPS_FOREIGN_SUBSAMPLE_AUTO); VIPS_ARG_INT(class, "restart_interval", 20, _("Restart interval"), _("Add restart markers every specified number of mcu"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpeg, restart_interval), 0, INT_MAX, 0); } static void vips_foreign_save_jpeg_init(VipsForeignSaveJpeg *jpeg) { jpeg->Q = 75; jpeg->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_AUTO; } typedef struct _VipsForeignSaveJpegTarget { VipsForeignSaveJpeg parent_object; VipsTarget *target; } VipsForeignSaveJpegTarget; typedef VipsForeignSaveJpegClass VipsForeignSaveJpegTargetClass; G_DEFINE_TYPE(VipsForeignSaveJpegTarget, vips_foreign_save_jpeg_target, vips_foreign_save_jpeg_get_type()); static int vips_foreign_save_jpeg_target_build(VipsObject *object) { VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object; VipsForeignSaveJpegTarget *target = (VipsForeignSaveJpegTarget *) object; jpeg->target = target->target; g_object_ref(jpeg->target); if (VIPS_OBJECT_CLASS(vips_foreign_save_jpeg_target_parent_class) ->build(object)) return -1; return 0; } static void vips_foreign_save_jpeg_target_class_init( VipsForeignSaveJpegTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegsave_target"; object_class->build = vips_foreign_save_jpeg_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpegTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_jpeg_target_init(VipsForeignSaveJpegTarget *target) { } typedef struct _VipsForeignSaveJpegFile { VipsForeignSaveJpeg parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveJpegFile; typedef VipsForeignSaveJpegClass VipsForeignSaveJpegFileClass; G_DEFINE_TYPE(VipsForeignSaveJpegFile, vips_foreign_save_jpeg_file, vips_foreign_save_jpeg_get_type()); static int vips_foreign_save_jpeg_file_build(VipsObject *object) { VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object; VipsForeignSaveJpegFile *file = (VipsForeignSaveJpegFile *) object; if (!(jpeg->target = vips_target_new_to_file(file->filename))) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_jpeg_file_parent_class) ->build(object)) return -1; return 0; } static void vips_foreign_save_jpeg_file_class_init(VipsForeignSaveJpegFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegsave"; object_class->build = vips_foreign_save_jpeg_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJpegFile, filename), NULL); } static void vips_foreign_save_jpeg_file_init(VipsForeignSaveJpegFile *file) { } typedef struct _VipsForeignSaveJpegBuffer { VipsForeignSaveJpeg parent_object; /* Save to a buffer. */ VipsArea *buf; } VipsForeignSaveJpegBuffer; typedef VipsForeignSaveJpegClass VipsForeignSaveJpegBufferClass; G_DEFINE_TYPE(VipsForeignSaveJpegBuffer, vips_foreign_save_jpeg_buffer, vips_foreign_save_jpeg_get_type()); static int vips_foreign_save_jpeg_buffer_build(VipsObject *object) { VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object; VipsForeignSaveJpegBuffer *buffer = (VipsForeignSaveJpegBuffer *) object; if (!(jpeg->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_jpeg_buffer_parent_class) ->build(object)) return -1; VipsBlob *blob; g_object_get(jpeg->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_jpeg_buffer_class_init( VipsForeignSaveJpegBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jpegsave_buffer"; object_class->build = vips_foreign_save_jpeg_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveJpegBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_jpeg_buffer_init(VipsForeignSaveJpegBuffer *file) { } typedef struct _VipsForeignSaveJpegMime { VipsForeignSaveJpeg parent_object; } VipsForeignSaveJpegMime; typedef VipsForeignSaveJpegClass VipsForeignSaveJpegMimeClass; G_DEFINE_TYPE(VipsForeignSaveJpegMime, vips_foreign_save_jpeg_mime, vips_foreign_save_jpeg_get_type()); static int vips_foreign_save_jpeg_mime_build(VipsObject *object) { VipsForeignSaveJpeg *jpeg = (VipsForeignSaveJpeg *) object; if (!(jpeg->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_jpeg_mime_parent_class) ->build(object)) return -1; VipsBlob *blob; g_object_get(jpeg->target, "blob", &blob, NULL); const unsigned char *obuf; size_t olen; obuf = vips_blob_get(blob, &olen); printf("Content-length: %zu\r\n", olen); printf("Content-type: image/jpeg\r\n"); printf("\r\n"); (void) fwrite(obuf, sizeof(char), olen, stdout); fflush(stdout); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_jpeg_mime_class_init(VipsForeignSaveJpegMimeClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "jpegsave_mime"; object_class->description = _("save image to jpeg mime"); object_class->build = vips_foreign_save_jpeg_mime_build; } static void vips_foreign_save_jpeg_mime_init(VipsForeignSaveJpegMime *mime) { } #endif /*HAVE_JPEG*/ /** * vips_jpegsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file as JPEG. * * Use @Q to set the JPEG compression factor. Default 75. * * If @optimize_coding is set, the Huffman tables are optimized. This is * slightly slower and produces slightly smaller files. * * If @interlace is set, the jpeg files will be interlaced (progressive jpeg, * in jpg parlance). These files may be better for display over a slow network * connection, but need much more memory to encode and decode. * * Chroma subsampling is normally automatically disabled for Q >= 90. You can * force the subsampling mode with @subsample_mode. * * If @trellis_quant is set and the version of libjpeg supports it * (e.g. mozjpeg >= 3.0), apply trellis quantisation to each 8x8 block. * Reduces file size but increases compression time. * * If @overshoot_deringing is set and the version of libjpeg supports it * (e.g. mozjpeg >= 3.0), apply overshooting to samples with extreme values * for example 0 and 255 for 8-bit. Overshooting may reduce ringing artifacts * from compression, in particular in areas where black text appears on a * white background. * * If @optimize_scans is set and the version of libjpeg supports it * (e.g. mozjpeg >= 3.0), split the spectrum of DCT coefficients into * separate scans. Reduces file size but increases compression time. * * If @quant_table is set and the version of libjpeg supports it * (e.g. mozjpeg >= 3.0) it selects the quantization table to use: * * - 0 — Tables from JPEG Annex K (vips and libjpeg default) * - 1 — Flat table * - 2 — Table tuned for MSSIM on Kodak image set * - 3 — Table from ImageMagick by N. Robidoux (current mozjpeg default) * - 4 — Table tuned for PSNR-HVS-M on Kodak image set * - 5 — Table from Relevance of Human Vision to JPEG-DCT Compression (1992) * - 6 — Table from DCTune Perceptual Optimization of Compressed Dental * X-Rays (1997) * - 7 — Table from A Visual Detection Model for DCT Coefficient * Quantization (1993) * - 8 — Table from An Improved Detection Model for DCT Coefficient * Quantization (1993) * * Quantization table 0 is the default in vips and libjpeg(-turbo), but it * tends to favor detail over color accuracy, producing colored patches and * stripes as well as heavy banding in flat areas at high compression ratios. * Quantization table 2 is a good candidate to try if the default quantization * table produces banding or color shifts and is well suited for hires images. * Quantization table 3 is the default in mozjpeg and has been tuned to produce * good results at the default quality setting; banding at high compression. * Quantization table 4 is the most accurate at the cost of compression ratio. * Tables 5-7 are based on older research papers, but generally achieve worse * compression ratios and/or quality than 2 or 4. * * For maximum compression with mozjpeg, a useful set of options is `strip, * optimize-coding, interlace, optimize-scans, trellis-quant, quant_table=3`. * * By default, the output stream won't have restart markers. If a non-zero * restart_interval is specified, a restart marker will be added after each * specified number of MCU blocks. This makes the stream more recoverable * if there are transmission errors, but also allows for some decoders to read * part of the JPEG without decoding the whole stream. * * The image is automatically converted to RGB, Monochrome or CMYK before * saving. * * EXIF data is constructed from [const@META_EXIF_NAME], then * modified with any other related tags on the image before being written to * the file. [const@META_RESOLUTION_UNIT] is used to set the EXIF resolution * unit. [const@META_ORIENTATION] is used to set the EXIF orientation tag. * * IPTC as [const@META_IPTC_NAME] and XMP as [const@META_XMP_NAME] * are coded and attached. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @optimize_coding: `gboolean`, compute optimal Huffman coding tables * * @interlace: `gboolean`, write an interlaced (progressive) jpeg * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @trellis_quant: `gboolean`, apply trellis quantisation to each 8x8 block * * @overshoot_deringing: `gboolean`, overshoot samples with extreme values * * @optimize_scans: `gboolean`, split DCT coefficients into separate scans * * @quant_table: `gint`, quantization table index * * @restart_interval: `gint`, restart interval in mcu * * ::: seealso * [method@Image.jpegsave_buffer], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_jpegsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("jpegsave", ap, in, filename); va_end(ap); return result; } /** * vips_jpegsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jpegsave], but save to a target. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @optimize_coding: `gboolean`, compute optimal Huffman coding tables * * @interlace: `gboolean`, write an interlaced (progressive) jpeg * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @trellis_quant: `gboolean`, apply trellis quantisation to each 8x8 block * * @overshoot_deringing: `gboolean`, overshoot samples with extreme values * * @optimize_scans: `gboolean`, split DCT coefficients into separate scans * * @quant_table: `gint`, quantization table index * * @restart_interval: `gint`, restart interval in mcu * * ::: seealso * [method@Image.jpegsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_jpegsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("jpegsave_target", ap, in, target); va_end(ap); return result; } /** * vips_jpegsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jpegsave], but save to a memory buffer. * * The address of the buffer is returned in @obuf, the length of the buffer in * @olen. You are responsible for freeing the buffer with [func@GLib.free] * when you are done with it. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @optimize_coding: `gboolean`, compute optimal Huffman coding tables * * @interlace: `gboolean`, write an interlaced (progressive) jpeg * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @trellis_quant: `gboolean`, apply trellis quantisation to each 8x8 block * * @overshoot_deringing: `gboolean`, overshoot samples with extreme values * * @optimize_scans: `gboolean`, split DCT coefficients into separate scans * * @quant_table: `gint`, quantization table index * * @restart_interval: `gint`, restart interval in mcu * * ::: seealso * [method@Image.jpegsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_jpegsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("jpegsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_jpegsave_mime: (method) * @in: image to save * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.jpegsave], but save as a mime jpeg on stdout. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @optimize_coding: `gboolean`, compute optimal Huffman coding tables * * @interlace: `gboolean`, write an interlaced (progressive) jpeg * * @subsample_mode: [enum@ForeignSubsample], chroma subsampling mode * * @trellis_quant: `gboolean`, apply trellis quantisation to each 8x8 block * * @overshoot_deringing: `gboolean`, overshoot samples with extreme values * * @optimize_scans: `gboolean`, split DCT coefficients into separate scans * * @quant_table: `gint`, quantization table index * * @restart_interval: `gint`, restart interval in mcu * * ::: seealso * [method@Image.jpegsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_jpegsave_mime(VipsImage *in, ...) { va_list ap; int result; va_start(ap, in); result = vips_call_split("jpegsave_mime", ap, in); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/jxlload.c000066400000000000000000001010701516303661500201710ustar00rootroot00000000000000/* load jpeg-xl * * 18/3/20 * - from heifload.c * 1/10/21 * - reset read point for _load * 13/3/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_LIBJXL #include #include #include "pforeign.h" /* TODO: * * - add metadata support * * - add animation support * * - add "shrink" option to read out 8x shrunk image? * * - fix scRGB gamma */ #define INPUT_BUFFER_SIZE (4096) typedef struct _VipsForeignLoadJxl { VipsForeignLoad parent_object; /* Source to load from (set by subclasses). */ VipsSource *source; /* Shrink by this much during load. */ int shrink; /* Load this page (frame number). */ int page; /* Load this many pages. */ int n; /* Base image properties. */ JxlBasicInfo info; JxlPixelFormat format; size_t icc_size; uint8_t *icc_data; size_t exif_size; uint8_t *exif_data; size_t xmp_size; uint8_t *xmp_data; int frame_count; GArray *delay; /* JXL multipage and animated images are the same, but multipage has * all the frame delays set to -1 (duration 0xffffffff). */ gboolean is_animated; /* The current accumulated frame as a VipsImage. These are the pixels * we send to the output. It's a info->xsize * info->ysize memory * image. */ VipsImage *frame; /* The frame number currently in @frame. Numbered from 1, so 0 means * before the first frame. */ int frame_no; /* Decompress state. */ void *runner; JxlDecoder *decoder; /* Our input buffer. */ uint8_t input_buffer[INPUT_BUFFER_SIZE]; size_t bytes_in_buffer; /* Pointers to fields where box size and box data should be written to */ size_t *box_size; uint8_t **box_data; /* Number of errors reported during load -- use this to block load of * corrupted images. */ int n_errors; /* If we need to upsample tiles read from opj. */ gboolean upsample; /* If we need to do ycc->rgb conversion on load. */ gboolean ycc_to_rgb; } VipsForeignLoadJxl; typedef VipsForeignLoadClass VipsForeignLoadJxlClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadJxl, vips_foreign_load_jxl, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_jxl_dispose(GObject *gobject) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) gobject; #ifdef DEBUG printf("vips_foreign_load_jxl_dispose:\n"); #endif /*DEBUG*/ VIPS_FREEF(JxlThreadParallelRunnerDestroy, jxl->runner); VIPS_FREEF(JxlDecoderDestroy, jxl->decoder); VIPS_FREE(jxl->icc_data); VIPS_FREE(jxl->exif_data); VIPS_FREE(jxl->xmp_data); VIPS_FREEF(g_array_unref, jxl->delay); VIPS_UNREF(jxl->frame); VIPS_UNREF(jxl->source); G_OBJECT_CLASS(vips_foreign_load_jxl_parent_class)->dispose(gobject); } static void vips_foreign_load_jxl_error(VipsForeignLoadJxl *jxl, const char *details) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jxl); /* TODO ... jxl has no way to get error messages at the moment. */ vips_error(class->nickname, "error %s", details); } static int vips_foreign_load_jxl_build(VipsObject *object) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object; #ifdef DEBUG printf("vips_foreign_load_jxl_build:\n"); #endif /*DEBUG*/ jxl->runner = JxlThreadParallelRunnerCreate(NULL, vips_concurrency_get()); jxl->decoder = JxlDecoderCreate(NULL); if (JxlDecoderSetParallelRunner(jxl->decoder, JxlThreadParallelRunner, jxl->runner)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderSetParallelRunner"); return -1; } return VIPS_OBJECT_CLASS(vips_foreign_load_jxl_parent_class) ->build(object); } static gboolean vips_foreign_load_jxl_is_a_source(VipsSource *source) { const unsigned char *p; JxlSignature sig; return (p = vips_source_sniff(source, 12)) && (sig = JxlSignatureCheck(p, 12)) != JXL_SIG_INVALID && sig != JXL_SIG_NOT_ENOUGH_BYTES; } static VipsForeignFlags vips_foreign_load_jxl_get_flags(VipsForeignLoad *load) { /* FIXME .. could support random access for non-animated images. */ return VIPS_FOREIGN_SEQUENTIAL; } static int vips_foreign_load_jxl_set_box_buffer(VipsForeignLoadJxl *jxl) { if (!jxl->box_data || !jxl->box_size) return 0; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jxl); uint8_t *new_data; size_t new_size; size_t box_size = *jxl->box_size; new_size = box_size + INPUT_BUFFER_SIZE; new_data = g_try_realloc(*jxl->box_data, new_size); if (!new_data) { vips_error(class->nickname, "%s", _("out of memory")); return -1; } *jxl->box_data = new_data; JxlDecoderSetBoxBuffer(jxl->decoder, new_data + box_size, INPUT_BUFFER_SIZE); return 0; } static int vips_foreign_load_jxl_release_box_buffer(VipsForeignLoadJxl *jxl) { if (!jxl->box_data || !jxl->box_size) return 0; size_t remaining = JxlDecoderReleaseBoxBuffer(jxl->decoder); *jxl->box_size += INPUT_BUFFER_SIZE - remaining; return 0; } static int vips_foreign_load_jxl_fill_input(VipsForeignLoadJxl *jxl, size_t bytes_remaining) { gint64 bytes_read; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jxl_fill_input: %zd bytes requested\n", INPUT_BUFFER_SIZE - bytes_remaining); #endif /*DEBUG_VERBOSE*/ memmove(jxl->input_buffer, jxl->input_buffer + jxl->bytes_in_buffer - bytes_remaining, bytes_remaining); bytes_read = vips_source_read(jxl->source, jxl->input_buffer + bytes_remaining, INPUT_BUFFER_SIZE - bytes_remaining); /* Read error. */ if (bytes_read < 0) return -1; jxl->bytes_in_buffer = bytes_read + bytes_remaining; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jxl_fill_input: %zd bytes read\n", bytes_read); #endif /*DEBUG_VERBOSE*/ return bytes_read; } #ifdef DEBUG static void vips_foreign_load_jxl_print_status(JxlDecoderStatus status) { switch (status) { case JXL_DEC_SUCCESS: printf("JXL_DEC_SUCCESS\n"); break; case JXL_DEC_ERROR: printf("JXL_DEC_ERROR\n"); break; case JXL_DEC_NEED_MORE_INPUT: printf("JXL_DEC_NEED_MORE_INPUT\n"); break; case JXL_DEC_NEED_PREVIEW_OUT_BUFFER: printf("JXL_DEC_NEED_PREVIEW_OUT_BUFFER\n"); break; case JXL_DEC_NEED_IMAGE_OUT_BUFFER: printf("JXL_DEC_NEED_IMAGE_OUT_BUFFER\n"); break; case JXL_DEC_JPEG_NEED_MORE_OUTPUT: printf("JXL_DEC_JPEG_NEED_MORE_OUTPUT\n"); break; case JXL_DEC_BOX_NEED_MORE_OUTPUT: printf("JXL_DEC_BOX_NEED_MORE_OUTPUT\n"); break; case JXL_DEC_BASIC_INFO: printf("JXL_DEC_BASIC_INFO\n"); break; case JXL_DEC_COLOR_ENCODING: printf("JXL_DEC_COLOR_ENCODING\n"); break; case JXL_DEC_PREVIEW_IMAGE: printf("JXL_DEC_PREVIEW_IMAGE\n"); break; case JXL_DEC_FRAME: printf("JXL_DEC_FRAME\n"); break; case JXL_DEC_FULL_IMAGE: printf("JXL_DEC_FULL_IMAGE\n"); break; case JXL_DEC_JPEG_RECONSTRUCTION: printf("JXL_DEC_JPEG_RECONSTRUCTION\n"); break; case JXL_DEC_BOX: printf("JXL_DEC_BOX\n"); break; default: printf("JXL_DEC_\n"); break; } } static void vips_foreign_load_jxl_print_info(JxlBasicInfo *info) { printf("JxlBasicInfo:\n"); printf(" have_container = %d\n", info->have_container); printf(" xsize = %d\n", info->xsize); printf(" ysize = %d\n", info->ysize); printf(" bits_per_sample = %d\n", info->bits_per_sample); printf(" exponent_bits_per_sample = %d\n", info->exponent_bits_per_sample); printf(" intensity_target = %g\n", info->intensity_target); printf(" min_nits = %g\n", info->min_nits); printf(" relative_to_max_display = %d\n", info->relative_to_max_display); printf(" linear_below = %g\n", info->linear_below); printf(" uses_original_profile = %d\n", info->uses_original_profile); printf(" have_preview = %d\n", info->have_preview); printf(" have_animation = %d\n", info->have_animation); printf(" orientation = %d\n", info->orientation); printf(" num_color_channels = %d\n", info->num_color_channels); printf(" num_extra_channels = %d\n", info->num_extra_channels); printf(" alpha_bits = %d\n", info->alpha_bits); printf(" alpha_exponent_bits = %d\n", info->alpha_exponent_bits); printf(" alpha_premultiplied = %d\n", info->alpha_premultiplied); printf(" preview.xsize = %d\n", info->preview.xsize); printf(" preview.ysize = %d\n", info->preview.ysize); printf(" animation.tps_numerator = %d\n", info->animation.tps_numerator); printf(" animation.tps_denominator = %d\n", info->animation.tps_denominator); printf(" animation.num_loops = %d\n", info->animation.num_loops); printf(" animation.have_timecodes = %d\n", info->animation.have_timecodes); } static void vips_foreign_load_jxl_print_format(JxlPixelFormat *format) { printf("JxlPixelFormat:\n"); printf(" data_type = "); switch (format->data_type) { case JXL_TYPE_UINT8: printf("JXL_TYPE_UINT8"); break; case JXL_TYPE_UINT16: printf("JXL_TYPE_UINT16"); break; case JXL_TYPE_FLOAT: printf("JXL_TYPE_FLOAT"); break; default: printf("(unknown)"); break; } printf("\n"); printf(" num_channels = %d\n", format->num_channels); printf(" endianness = %d\n", format->endianness); printf(" align = %zd\n", format->align); } static const char * vips_foreign_load_jxl_blend_mode(JxlBlendMode blendmode) { switch (blendmode) { case JXL_BLEND_REPLACE: return "JXL_BLEND_REPLACE"; case JXL_BLEND_ADD: return "JXL_BLEND_ADD"; case JXL_BLEND_BLEND: return "JXL_BLEND_BLEND"; case JXL_BLEND_MULADD: return "JXL_BLEND_MULADD"; case JXL_BLEND_MUL: return "JXL_BLEND_MUL"; default: return "duration); printf(" timecode = %u\n", h->timecode); printf(" name_length = %u\n", h->name_length); printf(" is_last = %s\n", h->is_last ? "TRUE" : "FALSE"); printf(" layer_info.have_crop = %s\n", h->layer_info.have_crop ? "TRUE" : "FALSE"); printf(" layer_info.crop_x0 = %d\n", h->layer_info.crop_x0); printf(" layer_info.crop_y0 = %d\n", h->layer_info.crop_y0); printf(" layer_info.xsize = %u\n", h->layer_info.xsize); printf(" layer_info.ysize = %u\n", h->layer_info.ysize); printf(" layer_info.blend_info.blendmode = %s\n", vips_foreign_load_jxl_blend_mode(h->layer_info.blend_info.blendmode)); printf(" layer_info.blend_info.source = %u\n", h->layer_info.blend_info.source); printf(" layer_info.blend_info.alpha = %u\n", h->layer_info.blend_info.alpha); printf(" layer_info.blend_info.clamp = %s\n", h->layer_info.blend_info.clamp ? "TRUE" : "FALSE"); printf(" layer_info.save_as_reference = %u\n", h->layer_info.save_as_reference); } #endif /*DEBUG*/ static JxlDecoderStatus vips_foreign_load_jxl_process(VipsForeignLoadJxl *jxl) { JxlDecoderStatus status; #ifdef DEBUG printf("vips_foreign_load_jxl_process: starting ...\n"); #endif /*DEBUG*/ while ((status = JxlDecoderProcessInput(jxl->decoder)) == JXL_DEC_NEED_MORE_INPUT) { size_t bytes_remaining; int bytes_read; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jxl_process: reading ...\n"); #endif /*DEBUG_VERBOSE*/ bytes_remaining = JxlDecoderReleaseInput(jxl->decoder); bytes_read = vips_foreign_load_jxl_fill_input(jxl, bytes_remaining); if (bytes_read < 0) return JXL_DEC_ERROR; if (jxl->bytes_in_buffer) JxlDecoderSetInput(jxl->decoder, jxl->input_buffer, jxl->bytes_in_buffer); if (!bytes_read) JxlDecoderCloseInput(jxl->decoder); } #ifdef DEBUG printf("vips_foreign_load_jxl_process: seen "); vips_foreign_load_jxl_print_status(status); #endif /*DEBUG*/ return status; } static int vips_foreign_load_jxl_read_frame(VipsForeignLoadJxl *jxl, VipsImage *frame, int frame_no) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jxl); size_t buffer_size; JxlDecoderStatus status; if (jxl->frame_no >= frame_no) return 0; int skip = frame_no - jxl->frame_no - 1; if (skip > 0) { #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jxl_read_frame: skipping %d frames\n", skip); #endif /*DEBUG_VERBOSE*/ JxlDecoderSkipFrames(jxl->decoder, skip); jxl->frame_no += skip; } /* Read to the end of the image. */ do { switch ((status = vips_foreign_load_jxl_process(jxl))) { case JXL_DEC_ERROR: vips_foreign_load_jxl_error(jxl, "JxlDecoderProcessInput"); return -1; case JXL_DEC_FRAME: jxl->frame_no++; break; case JXL_DEC_NEED_IMAGE_OUT_BUFFER: if (JxlDecoderImageOutBufferSize(jxl->decoder, &jxl->format, &buffer_size)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderImageOutBufferSize"); return -1; } if (buffer_size != VIPS_IMAGE_SIZEOF_IMAGE(frame)) { vips_error(class->nickname, "%s", _("bad buffer size")); return -1; } if (JxlDecoderSetImageOutBuffer(jxl->decoder, &jxl->format, VIPS_IMAGE_ADDR(frame, 0, 0), VIPS_IMAGE_SIZEOF_IMAGE(frame))) { vips_foreign_load_jxl_error(jxl, "JxlDecoderSetImageOutBuffer"); return -1; } break; case JXL_DEC_FULL_IMAGE: /* We decoded the required frame and can return */ if (jxl->frame_no >= frame_no) return 0; break; default: break; } } while (status != JXL_DEC_SUCCESS); /* We didn't find the required frame */ vips_error(class->nickname, "%s", _("not enough frames")); return -1; } static int vips_foreign_load_jxl_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) a; /* jxl->frame_no numbers from 1. */ int frame = 1 + r->top / jxl->info.ysize + jxl->page; int line = r->top % jxl->info.ysize; #ifdef DEBUG_VERBOSE printf("vips_foreign_load_jxl_generate: line %d\n", r->top); #endif /*DEBUG_VERBOSE*/ g_assert(r->height == 1); if (vips_foreign_load_jxl_read_frame(jxl, jxl->frame, frame)) return -1; memcpy(VIPS_REGION_ADDR(out_region, 0, r->top), VIPS_IMAGE_ADDR(jxl->frame, 0, line), VIPS_IMAGE_SIZEOF_LINE(jxl->frame)); return 0; } /* JPEG XL stores EXIF data without leading "Exif\0\0" with offset */ static int vips_foreign_load_jxl_fix_exif(VipsForeignLoadJxl *jxl) { if (!jxl->exif_data || (jxl->exif_size >= 6 && vips_isprefix("Exif\0\0", (char *) jxl->exif_data))) return 0; if (jxl->exif_size < 4) { g_warning("invalid data in EXIF box"); return -1; } /* Offset is stored in big-endian */ size_t offset = GUINT32_FROM_BE(*((guint32 *) jxl->exif_data)); if (offset > jxl->exif_size - 4) { g_warning("invalid data in EXIF box"); return -1; } size_t new_size = jxl->exif_size - 4 - offset + 6; uint8_t *new_data; if (!(new_data = VIPS_MALLOC(NULL, new_size))) return -1; memcpy(new_data, "Exif\0\0", 6); memcpy(new_data + 6, jxl->exif_data + 4 + offset, new_size - 6); VIPS_FREE(jxl->exif_data); jxl->exif_size = new_size; jxl->exif_data = new_data; return 0; } static int vips_foreign_load_jxl_set_header(VipsForeignLoadJxl *jxl, VipsImage *out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jxl); VipsBandFormat format; VipsInterpretation interpretation; if (jxl->info.xsize >= VIPS_MAX_COORD || jxl->info.ysize >= VIPS_MAX_COORD) { vips_error(class->nickname, "%s", _("image size out of bounds")); return -1; } switch (jxl->format.data_type) { case JXL_TYPE_UINT8: format = VIPS_FORMAT_UCHAR; break; case JXL_TYPE_UINT16: format = VIPS_FORMAT_USHORT; break; case JXL_TYPE_FLOAT: format = VIPS_FORMAT_FLOAT; break; default: g_assert_not_reached(); } switch (jxl->info.num_color_channels) { case 1: switch (format) { case VIPS_FORMAT_UCHAR: interpretation = VIPS_INTERPRETATION_B_W; break; case VIPS_FORMAT_USHORT: interpretation = VIPS_INTERPRETATION_GREY16; break; default: interpretation = VIPS_INTERPRETATION_B_W; break; } break; case 3: switch (format) { case VIPS_FORMAT_UCHAR: interpretation = VIPS_INTERPRETATION_sRGB; break; case VIPS_FORMAT_USHORT: interpretation = VIPS_INTERPRETATION_RGB16; break; case VIPS_FORMAT_FLOAT: interpretation = VIPS_INTERPRETATION_scRGB; break; default: interpretation = VIPS_INTERPRETATION_sRGB; break; } break; default: interpretation = VIPS_INTERPRETATION_MULTIBAND; break; } if (jxl->frame_count > 1) { if (jxl->n == -1) jxl->n = jxl->frame_count - jxl->page; // FIXME: Invalidates operation cache if (jxl->page < 0 || jxl->n <= 0 || jxl->page + jxl->n > jxl->frame_count) { vips_error(class->nickname, "%s", _("bad page number")); return -1; } vips_image_set_int(out, VIPS_META_N_PAGES, jxl->frame_count); if (jxl->n > 1) vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, jxl->info.ysize); if (jxl->is_animated) { int *delay = (int *) jxl->delay->data; vips_image_set_array_int(out, "delay", delay, jxl->frame_count); /* gif uses centiseconds for delays */ vips_image_set_int(out, "gif-delay", rint(delay[0] / 10.0)); vips_image_set_int(out, "loop", jxl->info.animation.num_loops); } } else { jxl->n = 1; // FIXME: Invalidates operation cache jxl->page = 0; // FIXME: Invalidates operation cache } /* Init jxl->frame only when we need to decode multiple frames. * Otherwise, we can decode the frame right to the output */ if (jxl->n > 1 && !jxl->frame) { jxl->frame = vips_image_new_memory(); vips_image_init_fields(jxl->frame, jxl->info.xsize, jxl->info.ysize, jxl->format.num_channels, format, VIPS_CODING_NONE, interpretation, 1.0, 1.0); if (vips_image_pipelinev(jxl->frame, VIPS_DEMAND_STYLE_THINSTRIP, NULL) || vips_image_write_prepare(jxl->frame)) return -1; } vips_image_init_fields(out, jxl->info.xsize, jxl->info.ysize * jxl->n, jxl->format.num_channels, format, VIPS_CODING_NONE, interpretation, 1.0, 1.0); /* Even though this is a full image reader, we hint thinstrip since * we are quite happy serving that if anything downstream * would like it. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; if (jxl->icc_data && jxl->icc_size > 0) { vips_image_set_blob(out, VIPS_META_ICC_NAME, (VipsCallbackFn) vips_area_free_cb, jxl->icc_data, jxl->icc_size); jxl->icc_data = NULL; jxl->icc_size = 0; } if (jxl->exif_data && jxl->exif_size > 0) { vips_image_set_blob(out, VIPS_META_EXIF_NAME, (VipsCallbackFn) vips_area_free_cb, jxl->exif_data, jxl->exif_size); jxl->exif_data = NULL; jxl->exif_size = 0; } if (jxl->xmp_data && jxl->xmp_size > 0) { vips_image_set_blob(out, VIPS_META_XMP_NAME, (VipsCallbackFn) vips_area_free_cb, jxl->xmp_data, jxl->xmp_size); jxl->xmp_data = NULL; jxl->xmp_size = 0; } vips_image_set_int(out, VIPS_META_ORIENTATION, jxl->info.orientation); vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, jxl->info.bits_per_sample); return 0; } static int vips_foreign_load_jxl_header(VipsForeignLoad *load) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load; JxlDecoderStatus status; JXL_BOOL decompress_boxes = JXL_TRUE; JxlFrameHeader h; #ifdef DEBUG printf("vips_foreign_load_jxl_header:\n"); #endif /*DEBUG*/ if (vips_source_rewind(jxl->source)) return -1; JxlDecoderRewind(jxl->decoder); if (JxlDecoderSubscribeEvents(jxl->decoder, JXL_DEC_COLOR_ENCODING | JXL_DEC_BASIC_INFO | JXL_DEC_BOX | JXL_DEC_FRAME)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderSubscribeEvents"); return -1; } if (JxlDecoderSetDecompressBoxes(jxl->decoder, JXL_TRUE) != JXL_DEC_SUCCESS) decompress_boxes = JXL_FALSE; if (vips_foreign_load_jxl_fill_input(jxl, 0) < 0) return -1; JxlDecoderSetInput(jxl->decoder, jxl->input_buffer, jxl->bytes_in_buffer); jxl->frame_count = 0; /* Read to the end of the header. */ do { switch ((status = vips_foreign_load_jxl_process(jxl))) { case JXL_DEC_ERROR: vips_foreign_load_jxl_error(jxl, "JxlDecoderProcessInput"); return -1; case JXL_DEC_BOX: /* Flush previous box data if any */ if (vips_foreign_load_jxl_release_box_buffer(jxl)) return -1; JxlBoxType type; if (JxlDecoderGetBoxType( jxl->decoder, type, decompress_boxes) != JXL_DEC_SUCCESS) { vips_foreign_load_jxl_error(jxl, "JxlDecoderGetBoxType"); return -1; } #ifdef DEBUG const char type_s[] = { type[0], type[1], type[2], type[3], 0 }; printf("vips_foreign_load_jxl_header found box %s\n", type_s); #endif /*DEBUG*/ if (!memcmp(type, "Exif", 4)) { jxl->box_size = &jxl->exif_size; jxl->box_data = &jxl->exif_data; } else if (!memcmp(type, "xml ", 4)) { jxl->box_size = &jxl->xmp_size; jxl->box_data = &jxl->xmp_data; } else { jxl->box_size = NULL; jxl->box_data = NULL; } if (vips_foreign_load_jxl_set_box_buffer(jxl)) return -1; break; case JXL_DEC_BOX_NEED_MORE_OUTPUT: if (vips_foreign_load_jxl_release_box_buffer(jxl) || vips_foreign_load_jxl_set_box_buffer(jxl)) return -1; break; case JXL_DEC_BASIC_INFO: if (JxlDecoderGetBasicInfo(jxl->decoder, &jxl->info)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderGetBasicInfo"); return -1; } #ifdef DEBUG vips_foreign_load_jxl_print_info(&jxl->info); #endif /*DEBUG*/ /* Pick a pixel format to decode to. */ jxl->format.num_channels = jxl->info.num_color_channels + jxl->info.num_extra_channels; if (jxl->info.exponent_bits_per_sample > 0 || jxl->info.alpha_exponent_bits > 0) jxl->format.data_type = JXL_TYPE_FLOAT; else if (jxl->info.bits_per_sample > 8) jxl->format.data_type = JXL_TYPE_UINT16; else jxl->format.data_type = JXL_TYPE_UINT8; jxl->format.endianness = JXL_NATIVE_ENDIAN; jxl->format.align = 0; #ifdef DEBUG vips_foreign_load_jxl_print_format(&jxl->format); #endif /*DEBUG*/ break; case JXL_DEC_COLOR_ENCODING: if (JxlDecoderGetICCProfileSize(jxl->decoder, #ifndef HAVE_LIBJXL_0_9 &jxl->format, #endif JXL_COLOR_PROFILE_TARGET_DATA, &jxl->icc_size)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderGetICCProfileSize"); return -1; } #ifdef DEBUG printf("vips_foreign_load_jxl_header: %zd byte profile\n", jxl->icc_size); #endif /*DEBUG*/ if (!(jxl->icc_data = vips_malloc(NULL, jxl->icc_size))) return -1; if (JxlDecoderGetColorAsICCProfile(jxl->decoder, #ifndef HAVE_LIBJXL_0_9 &jxl->format, #endif JXL_COLOR_PROFILE_TARGET_DATA, jxl->icc_data, jxl->icc_size)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderGetColorAsICCProfile"); return -1; } break; case JXL_DEC_FRAME: if (JxlDecoderGetFrameHeader(jxl->decoder, &h) != JXL_DEC_SUCCESS) { vips_foreign_load_jxl_error(jxl, "JxlDecoderGetFrameHeader"); return -1; } #ifdef DEBUG vips_foreign_load_jxl_print_frame_header(&h); #endif /*DEBUG*/ if (jxl->info.have_animation) { // tick duration in seconds double tick = (double) jxl->info.animation.tps_denominator / jxl->info.animation.tps_numerator; // this duration in ms int ms = rint(1000.0 * h.duration * tick); // h.duration of 0xffffffff is used for multipage JXL ... map // this to -1 in delay int duration = h.duration == 0xffffffff ? -1 : ms; jxl->delay = g_array_append_vals(jxl->delay, &duration, 1); } jxl->frame_count++; break; default: break; } } while (status != JXL_DEC_SUCCESS); /* Detect JXL multipage (rather than animated). */ int *delay = (int *) jxl->delay->data; for (int i = 0; i < jxl->delay->len; i++) if (delay[i] != -1) { jxl->is_animated = TRUE; break; } /* Flush box data if any */ if (vips_foreign_load_jxl_release_box_buffer(jxl)) return -1; if (vips_foreign_load_jxl_fix_exif(jxl)) return -1; if (vips_foreign_load_jxl_set_header(jxl, load->out)) return -1; VIPS_SETSTR(load->out->filename, vips_connection_filename(VIPS_CONNECTION(jxl->source))); return 0; } static int vips_foreign_load_jxl_load(VipsForeignLoad *load) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) load; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(load), 3); VipsImage *out; #ifdef DEBUG printf("vips_foreign_load_jxl_load:\n"); #endif /*DEBUG*/ t[0] = vips_image_new(); if (vips_foreign_load_jxl_set_header(jxl, t[0])) return -1; /* We have to rewind ... we can't be certain the header * decoder left the input in the correct place. */ if (vips_source_rewind(jxl->source)) return -1; JxlDecoderRewind(jxl->decoder); if (JxlDecoderSubscribeEvents(jxl->decoder, JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE)) { vips_foreign_load_jxl_error(jxl, "JxlDecoderSubscribeEvents"); return -1; } if (vips_foreign_load_jxl_fill_input(jxl, 0) < 0) return -1; JxlDecoderSetInput(jxl->decoder, jxl->input_buffer, jxl->bytes_in_buffer); if (jxl->n > 1) { if (vips_image_generate(t[0], NULL, vips_foreign_load_jxl_generate, NULL, jxl, NULL) || vips_sequential(t[0], &t[1], NULL)) return -1; out = t[1]; } else { /* We need only a single frame, we can read it right to the output */ if (vips_image_write_prepare(t[0]) || vips_foreign_load_jxl_read_frame(jxl, t[0], jxl->page + 1)) return -1; out = t[0]; } if (vips_image_write(out, load->real)) return -1; /* Switch to pixel decode. */ if (vips_source_decode(jxl->source)) return -1; return 0; } static void vips_foreign_load_jxl_class_init(VipsForeignLoadJxlClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_jxl_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlload_base"; object_class->description = _("load JPEG-XL image"); object_class->build = vips_foreign_load_jxl_build; /* libjxl is fuzzed, but it's relatively young and bugs are * still being found in jan 2022. Revise this status soon. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; load_class->get_flags = vips_foreign_load_jxl_get_flags; load_class->header = vips_foreign_load_jxl_header; load_class->load = vips_foreign_load_jxl_load; VIPS_ARG_INT(class, "page", 20, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJxl, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 21, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJxl, n), -1, 100000, 1); } static void vips_foreign_load_jxl_init(VipsForeignLoadJxl *jxl) { jxl->n = 1; jxl->delay = g_array_new(FALSE, FALSE, sizeof(int)); } typedef struct _VipsForeignLoadJxlFile { VipsForeignLoadJxl parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadJxlFile; typedef VipsForeignLoadJxlClass VipsForeignLoadJxlFileClass; G_DEFINE_TYPE(VipsForeignLoadJxlFile, vips_foreign_load_jxl_file, vips_foreign_load_jxl_get_type()); static int vips_foreign_load_jxl_file_build(VipsObject *object) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object; VipsForeignLoadJxlFile *file = (VipsForeignLoadJxlFile *) object; if (file->filename && !(jxl->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_jxl_file_parent_class) ->build(object); } const char *vips__jxl_suffs[] = { ".jxl", NULL }; static int vips_foreign_load_jxl_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_jxl_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_jxl_file_class_init(VipsForeignLoadJxlFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlload"; object_class->build = vips_foreign_load_jxl_file_build; foreign_class->suffs = vips__jxl_suffs; load_class->is_a = vips_foreign_load_jxl_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJxlFile, filename), NULL); } static void vips_foreign_load_jxl_file_init(VipsForeignLoadJxlFile *jxl) { } typedef struct _VipsForeignLoadJxlBuffer { VipsForeignLoadJxl parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadJxlBuffer; typedef VipsForeignLoadJxlClass VipsForeignLoadJxlBufferClass; G_DEFINE_TYPE(VipsForeignLoadJxlBuffer, vips_foreign_load_jxl_buffer, vips_foreign_load_jxl_get_type()); static int vips_foreign_load_jxl_buffer_build(VipsObject *object) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object; VipsForeignLoadJxlBuffer *buffer = (VipsForeignLoadJxlBuffer *) object; if (buffer->buf) if (!(jxl->source = vips_source_new_from_memory( VIPS_AREA(buffer->buf)->data, VIPS_AREA(buffer->buf)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_jxl_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_jxl_buffer_is_a(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_jxl_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_jxl_buffer_class_init(VipsForeignLoadJxlBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlload_buffer"; object_class->build = vips_foreign_load_jxl_buffer_build; load_class->is_a_buffer = vips_foreign_load_jxl_buffer_is_a; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJxlBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_jxl_buffer_init(VipsForeignLoadJxlBuffer *buffer) { } typedef struct _VipsForeignLoadJxlSource { VipsForeignLoadJxl parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadJxlSource; typedef VipsForeignLoadJxlClass VipsForeignLoadJxlSourceClass; G_DEFINE_TYPE(VipsForeignLoadJxlSource, vips_foreign_load_jxl_source, vips_foreign_load_jxl_get_type()); static int vips_foreign_load_jxl_source_build(VipsObject *object) { VipsForeignLoadJxl *jxl = (VipsForeignLoadJxl *) object; VipsForeignLoadJxlSource *source = (VipsForeignLoadJxlSource *) object; if (source->source) { jxl->source = source->source; g_object_ref(jxl->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_jxl_source_parent_class) ->build(object); } static void vips_foreign_load_jxl_source_class_init(VipsForeignLoadJxlSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlload_source"; object_class->build = vips_foreign_load_jxl_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_jxl_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadJxlSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_jxl_source_init(VipsForeignLoadJxlSource *jxl) { } #endif /*HAVE_LIBJXL*/ /* The C API wrappers are defined in foreign.c. */ libvips-8.18.2/libvips/foreign/jxlsave.c000066400000000000000000001046001516303661500202120ustar00rootroot00000000000000/* save as jpeg-xl * * 18/3/20 * - from heifload.c * 21/5/22 * - add ICC profile support * 8/5/25 * - write with JxlEncoderAddChunkedFrame() for lower memory use */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_LIBJXL #include #include #include #include #include #include #include #include #include "pforeign.h" /* TODO: * * - libjxl is currently missing error messages (I think) * * - add support encoding images with > 4 bands. * * see FIXME note in _build() */ #define OUTPUT_BUFFER_SIZE (4096) typedef struct _VipsForeignSaveJxl { VipsForeignSave parent_object; /* Where to write (set by subclasses). */ VipsTarget *target; /* Encoder options. */ int tier; double distance; int effort; gboolean lossless; int Q; int bitdepth; #ifdef HAVE_LIBJXL_0_9 gboolean error; #endif /* JXL multipage and animated images are the same, but multipage has * all the frame delays set to -1 (duration 0xffffffff). */ gboolean is_animated; /* Animated jxl options. */ int gif_delay; int *delay; int delay_length; /* Image geometry. */ int page_height; int page_count; int page_number; /* Base image properties. */ JxlBasicInfo info; JxlColorEncoding color_encoding; JxlPixelFormat format; /* Encoder state. */ void *runner; JxlEncoder *encoder; /* Write buffer. */ uint8_t output_buffer[OUTPUT_BUFFER_SIZE]; #ifdef HAVE_LIBJXL_0_9 /* Chunk reader. */ struct JxlChunkedFrameInputSource input_source; /* Map thread ids to regions with this hash table, gate access to it with * the mutex. */ GHashTable *tile_hash; GMutex tile_lock; /* Current page we are saving. */ VipsImage *page; /* Track number of pixels saved here for eval reporting. */ guint64 processed; #else /*!defined(HAVE_LIBJXL_0_9)*/ /* Buffer scanlines to make a line of libjxl tiles. */ VipsPel *scanline_buffer; size_t scanline_size; int scanline_y; #endif /*defined(HAVE_LIBJXL_0_9)*/ } VipsForeignSaveJxl; typedef VipsForeignSaveClass VipsForeignSaveJxlClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveJxl, vips_foreign_save_jxl, VIPS_TYPE_FOREIGN_SAVE); #ifdef HAVE_LIBJXL_0_9 static void * vips_foreign_save_jxl_get_buffer(void *opaque, size_t *size) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) opaque; *size = OUTPUT_BUFFER_SIZE; return jxl->output_buffer; } static void vips_foreign_save_jxl_output_release_buffer(void *opaque, size_t written_bytes) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) opaque; if (vips_target_write(jxl->target, jxl->output_buffer, written_bytes)) jxl->error = TRUE; } static void vips_foreign_save_jxl_seek(void *opaque, uint64_t position) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) opaque; if (vips_target_seek(jxl->target, position, SEEK_SET) < 0) jxl->error = TRUE; } static void vips_foreign_save_jxl_set_finalized_position(void *opaque, uint64_t position) { // don't need this } static void vips_foreign_save_jxl_set_output_processor(VipsForeignSaveJxl *jxl) { JxlEncoderSetOutputProcessor(jxl->encoder, (struct JxlEncoderOutputProcessor) { .opaque = jxl, .get_buffer = vips_foreign_save_jxl_get_buffer, .release_buffer = vips_foreign_save_jxl_output_release_buffer, .seek = vips_foreign_save_jxl_seek, .set_finalized_position = vips_foreign_save_jxl_set_finalized_position, }); } static void vips_foreign_save_jxl_pixel_format(void *opaque, JxlPixelFormat *format) { #ifdef DEBUG printf("vips_foreign_save_jxl_pixel_format:\n"); #endif /*DEBUG*/ VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) opaque; *format = jxl->format; } static void vips_foreign_save_jxl_extra_pixel_format(void *opaque, size_t ec_index, JxlPixelFormat *format) { #ifdef DEBUG printf("vips_foreign_save_jxl_extra_pixel_format:\n"); #endif /*DEBUG*/ return vips_foreign_save_jxl_pixel_format(opaque, format); } static const void * vips_foreign_save_jxl_data_at(void *opaque, size_t xpos, size_t ypos, size_t xsize, size_t ysize, size_t *row_offset) { VipsForeignSave *save = (VipsForeignSave *) opaque; VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) opaque; #ifdef DEBUG printf("vips_foreign_save_jxl_data_at: " "left = %zd, top = %zd, width = %zd, height = %zd\n", xpos, ypos, xsize, ysize); #endif /*DEBUG*/ /* Handy for testing. if (ypos > 1000) { jxl->error = TRUE; vips_error("jxlsave", "%s", _("experimental early exit")); return NULL; } */ VipsImage *tile; if (vips_crop(jxl->page, &tile, xpos, ypos, xsize, ysize, NULL)) { jxl->error = TRUE; /* Returning NULL from data_at won't crash, but will cause a lot of * messy libjxl diagnostic output. At least it stops save. */ return NULL; } // disable progress reporting from this copy_memory() vips_image_set_int(tile, "hide-progress", 1); VipsImage *memory; if (!(memory = vips_image_copy_memory(tile))) { VIPS_UNREF(tile); jxl->error = TRUE; return NULL; } VIPS_UNREF(tile); VipsPel *pels = VIPS_IMAGE_ADDR(memory, 0, 0); *row_offset = VIPS_IMAGE_SIZEOF_LINE(memory); g_mutex_lock(&jxl->tile_lock); g_assert(!g_hash_table_lookup(jxl->tile_hash, pels)); g_hash_table_insert(jxl->tile_hash, pels, memory); #ifdef DEBUG printf("\tgenerated pels = %p\n", pels); #endif /*DEBUG*/ g_mutex_unlock(&jxl->tile_lock); /* Trigger any eval callbacks on our source image and * check for cancel. */ jxl->processed += xsize * ysize; vips_image_eval(save->ready, jxl->processed); if (vips_image_iskilled(save->ready)) return NULL; return pels; } static const void * vips_foreign_save_jxl_extra_data_at(void *opaque, size_t ec_index, size_t xpos, size_t ypos, size_t xsize, size_t ysize, size_t *row_offset) { #ifdef DEBUG printf("vips_foreign_save_jxl_extra_data_at:\n"); #endif /*DEBUG*/ return vips_foreign_save_jxl_data_at(opaque, xpos, ypos, xsize, ysize, row_offset); } static void vips_foreign_save_jxl_input_release_buffer(void *opaque, const void *pels) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) opaque; #ifdef DEBUG printf("vips_foreign_save_jxl_input_release_buffer: pels = %p\n", pels); #endif /*DEBUG*/ g_assert(g_hash_table_lookup(jxl->tile_hash, pels)); g_hash_table_remove(jxl->tile_hash, pels); } static void vips_foreign_save_jxl_set_input_source(VipsForeignSaveJxl *jxl) { jxl->input_source = (struct JxlChunkedFrameInputSource) { .opaque = jxl, .get_color_channels_pixel_format = vips_foreign_save_jxl_pixel_format, .get_color_channel_data_at = vips_foreign_save_jxl_data_at, .get_extra_channel_pixel_format = vips_foreign_save_jxl_extra_pixel_format, .get_extra_channel_data_at = vips_foreign_save_jxl_extra_data_at, .release_buffer = vips_foreign_save_jxl_input_release_buffer }; } #endif /*defined(HAVE_LIBJXL_0_9)*/ static void vips_foreign_save_jxl_error(VipsForeignSaveJxl *jxl, const char *details) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jxl); /* TODO ... libjxl seems to have no way to get error messages at the * moment. */ vips_error(class->nickname, "%s error", details); } #ifdef DEBUG static void vips_foreign_save_jxl_print_info(JxlBasicInfo *info) { printf("JxlBasicInfo:\n"); printf(" have_container = %d\n", info->have_container); printf(" xsize = %d\n", info->xsize); printf(" ysize = %d\n", info->ysize); printf(" bits_per_sample = %d\n", info->bits_per_sample); printf(" exponent_bits_per_sample = %d\n", info->exponent_bits_per_sample); printf(" intensity_target = %g\n", info->intensity_target); printf(" min_nits = %g\n", info->min_nits); printf(" relative_to_max_display = %d\n", info->relative_to_max_display); printf(" linear_below = %g\n", info->linear_below); printf(" uses_original_profile = %d\n", info->uses_original_profile); printf(" have_preview = %d\n", info->have_preview); printf(" have_animation = %d\n", info->have_animation); printf(" orientation = %d\n", info->orientation); printf(" num_color_channels = %d\n", info->num_color_channels); printf(" num_extra_channels = %d\n", info->num_extra_channels); printf(" alpha_bits = %d\n", info->alpha_bits); printf(" alpha_exponent_bits = %d\n", info->alpha_exponent_bits); printf(" alpha_premultiplied = %d\n", info->alpha_premultiplied); printf(" preview.xsize = %d\n", info->preview.xsize); printf(" preview.ysize = %d\n", info->preview.ysize); printf(" animation.tps_numerator = %d\n", info->animation.tps_numerator); printf(" animation.tps_denominator = %d\n", info->animation.tps_denominator); printf(" animation.num_loops = %d\n", info->animation.num_loops); printf(" animation.have_timecodes = %d\n", info->animation.have_timecodes); } static void vips_foreign_save_jxl_print_format(JxlPixelFormat *format) { printf("JxlPixelFormat:\n"); printf(" num_channels = %d\n", format->num_channels); printf(" data_type = "); switch (format->data_type) { case JXL_TYPE_UINT8: printf("JXL_TYPE_UINT8"); break; case JXL_TYPE_UINT16: printf("JXL_TYPE_UINT16"); break; case JXL_TYPE_FLOAT: printf("JXL_TYPE_FLOAT"); break; default: printf("(unknown)"); break; } printf("\n"); printf(" endianness = %d\n", format->endianness); printf(" align = %zd\n", format->align); } static void vips_foreign_save_jxl_print_status(JxlEncoderStatus status) { switch (status) { case JXL_ENC_SUCCESS: printf("JXL_ENC_SUCCESS\n"); break; case JXL_ENC_ERROR: printf("JXL_ENC_ERROR\n"); break; case JXL_ENC_NEED_MORE_OUTPUT: printf("JXL_ENC_NEED_MORE_OUTPUT\n"); break; default: printf("JXL_ENC_\n"); break; } } #endif /*DEBUG*/ /* String-based metadata fields we add. */ typedef struct _VipsForeignSaveJxlMetadata { const char *name; /* as understood by libvips */ JxlBoxType box_type; /* as understood by libjxl */ } VipsForeignSaveJxlMetadata; static VipsForeignSaveJxlMetadata libjxl_metadata[] = { { VIPS_META_EXIF_NAME, "Exif" }, { VIPS_META_XMP_NAME, "xml " } }; static void vips_foreign_save_jxl_finalize(GObject *gobject) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) gobject; VIPS_FREEF(JxlThreadParallelRunnerDestroy, jxl->runner); VIPS_FREEF(JxlEncoderDestroy, jxl->encoder); #ifdef HAVE_LIBJXL_0_9 g_mutex_clear(&jxl->tile_lock); #endif G_OBJECT_CLASS(vips_foreign_save_jxl_parent_class)->finalize(gobject); } static void vips_foreign_save_jxl_dispose(GObject *gobject) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) gobject; VIPS_UNREF(jxl->target); #ifdef HAVE_LIBJXL_0_9 VIPS_FREEF(g_hash_table_destroy, jxl->tile_hash); #else VIPS_FREEF(vips_tracked_free, jxl->scanline_buffer); #endif G_OBJECT_CLASS(vips_foreign_save_jxl_parent_class)->dispose(gobject); } static int vips_foreign_save_jxl_set_header(VipsForeignSaveJxl *jxl, VipsImage *in) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(jxl); JxlEncoderInitBasicInfo(&jxl->info); switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: #ifdef HAVE_LIBJXL_0_8 jxl->info.bits_per_sample = VIPS_MIN(jxl->bitdepth, 8); #else jxl->info.bits_per_sample = 8; #endif jxl->info.exponent_bits_per_sample = 0; jxl->format.data_type = JXL_TYPE_UINT8; break; case VIPS_FORMAT_USHORT: #ifdef HAVE_LIBJXL_0_8 jxl->info.bits_per_sample = jxl->bitdepth; #else jxl->info.bits_per_sample = 16; #endif jxl->info.exponent_bits_per_sample = 0; jxl->format.data_type = JXL_TYPE_UINT16; break; case VIPS_FORMAT_FLOAT: jxl->info.bits_per_sample = 32; jxl->info.exponent_bits_per_sample = 8; jxl->format.data_type = JXL_TYPE_FLOAT; break; default: g_assert_not_reached(); break; } switch (in->Type) { case VIPS_INTERPRETATION_B_W: case VIPS_INTERPRETATION_GREY16: jxl->info.num_color_channels = VIPS_MIN(1, in->Bands); break; case VIPS_INTERPRETATION_sRGB: case VIPS_INTERPRETATION_scRGB: case VIPS_INTERPRETATION_RGB16: jxl->info.num_color_channels = VIPS_MIN(3, in->Bands); break; default: jxl->info.num_color_channels = in->Bands; } jxl->info.num_extra_channels = VIPS_MAX(0, in->Bands - jxl->info.num_color_channels); jxl->info.xsize = in->Xsize; jxl->info.ysize = jxl->page_height; jxl->format.num_channels = in->Bands; jxl->format.endianness = JXL_NATIVE_ENDIAN; jxl->format.align = 0; if (jxl->page_count > 1) { int num_loops = 0; if (vips_image_get_typeof(in, "loop")) vips_image_get_int(in, "loop", &num_loops); jxl->info.have_animation = TRUE; jxl->info.animation.tps_numerator = 1000; jxl->info.animation.tps_denominator = 1; jxl->info.animation.num_loops = num_loops; jxl->info.animation.have_timecodes = FALSE; } if (vips_image_hasalpha(in)) { jxl->info.alpha_bits = jxl->info.bits_per_sample; jxl->info.alpha_exponent_bits = jxl->info.exponent_bits_per_sample; } else { jxl->info.alpha_exponent_bits = 0; jxl->info.alpha_bits = 0; } if (vips_image_get_typeof(in, "stonits")) { double stonits; if (vips_image_get_double(in, "stonits", &stonits)) return -1; jxl->info.intensity_target = stonits; } /* uses_original_profile forces libjxl to not use lossy XYB * colourspace. The name is very confusing. */ jxl->info.uses_original_profile = jxl->lossless; if (JxlEncoderSetBasicInfo(jxl->encoder, &jxl->info)) { vips_foreign_save_jxl_error(jxl, "JxlEncoderSetBasicInfo"); return -1; } /* Set any ICC profile. */ if (vips_image_get_typeof(in, VIPS_META_ICC_NAME)) { const void *data; size_t length; if (vips_image_get_blob(in, VIPS_META_ICC_NAME, &data, &length)) return -1; #ifdef DEBUG printf("attaching %zd bytes of ICC\n", length); #endif /*DEBUG*/ if (JxlEncoderSetICCProfile(jxl->encoder, (guint8 *) data, length)) { vips_foreign_save_jxl_error(jxl, "JxlEncoderSetColorEncoding"); return -1; } } else { /* If there's no ICC profile, we must set the colour encoding * ourselves. */ if (in->Type == VIPS_INTERPRETATION_scRGB) { #ifdef DEBUG printf("setting scRGB colourspace\n"); #endif /*DEBUG*/ JxlColorEncodingSetToLinearSRGB(&jxl->color_encoding, jxl->format.num_channels < 3); } else { #ifdef DEBUG printf("setting sRGB colourspace\n"); #endif /*DEBUG*/ JxlColorEncodingSetToSRGB(&jxl->color_encoding, jxl->format.num_channels < 3); } if (JxlEncoderSetColorEncoding(jxl->encoder, &jxl->color_encoding)) { vips_foreign_save_jxl_error(jxl, "JxlEncoderSetColorEncoding"); return -1; } } for (int i = 0; i < VIPS_NUMBER(libjxl_metadata); i++) if (vips_image_get_typeof(in, libjxl_metadata[i].name)) { uint8_t *data; size_t length; #ifdef DEBUG printf("attaching %s ..\n", libjxl_metadata[i].name); #endif /*DEBUG*/ if (vips_image_get_blob(in, libjxl_metadata[i].name, (const void **) &data, &length)) return -1; /* It's safe to call JxlEncoderUseBoxes multiple times */ if (JxlEncoderUseBoxes(jxl->encoder) != JXL_ENC_SUCCESS) { vips_foreign_save_jxl_error(jxl, "JxlEncoderUseBoxes"); return -1; } /* JPEG XL stores EXIF data without leading "Exif\0\0" with offset */ if (!strcmp(libjxl_metadata[i].name, VIPS_META_EXIF_NAME)) { if (length >= 6 && vips_isprefix("Exif", (char *) data)) { data = data + 6; length -= 6; } size_t exif_size = length + 4; uint8_t *exif_data = g_malloc0(exif_size); if (!exif_data) { vips_error(class->nickname, "%s", _("out of memory")); return -1; } /* The first 4 bytes is offset which is 0 in this case */ memcpy(exif_data + 4, data, length); if (JxlEncoderAddBox(jxl->encoder, libjxl_metadata[i].box_type, exif_data, exif_size, JXL_TRUE) != JXL_ENC_SUCCESS) { vips_foreign_save_jxl_error(jxl, "JxlEncoderAddBox"); return -1; } g_free(exif_data); } else { if (JxlEncoderAddBox(jxl->encoder, libjxl_metadata[i].box_type, data, length, JXL_TRUE) != JXL_ENC_SUCCESS) { vips_foreign_save_jxl_error(jxl, "JxlEncoderAddBox"); return -1; } } } /* It's safe to call JxlEncoderCloseBoxes even if we don't use boxes */ JxlEncoderCloseBoxes(jxl->encoder); return 0; } static int vips_foreign_save_jxl_get_delay(VipsForeignSaveJxl *jxl, int page_number) { int delay; if (jxl->delay && page_number < jxl->delay_length) delay = jxl->delay[page_number]; else // the old gif delay field was in centiseconds, so convert to ms delay = jxl->gif_delay * 10; /* Force frames with a small or no duration to 100ms for consistency * with web browsers and other transcoding tools. */ return delay <= 10 ? 100 : delay; } #ifdef HAVE_LIBJXL_0_9 static int vips_foreign_save_jxl_save_page(VipsForeignSaveJxl *jxl, int n, VipsImage *page) { jxl->page = page; jxl->tile_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_object_unref); JxlEncoderFrameSettings *frame_settings = JxlEncoderFrameSettingsCreate(jxl->encoder, NULL); JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_DECODING_SPEED, jxl->tier); JxlEncoderSetFrameDistance(frame_settings, jxl->distance); JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_EFFORT, jxl->effort); JxlEncoderSetFrameLossless(frame_settings, jxl->lossless); if (jxl->info.have_animation) { JxlFrameHeader header = { 0 }; if (!jxl->is_animated) header.duration = 0xffffffff; else header.duration = vips_foreign_save_jxl_get_delay(jxl, n); JxlEncoderSetFrameHeader(frame_settings, &header); } if (JxlEncoderAddChunkedFrame(frame_settings, n == jxl->page_count - 1, jxl->input_source)) { VIPS_FREEF(g_hash_table_destroy, jxl->tile_hash); vips_foreign_save_jxl_error(jxl, "JxlEncoderAddImageFrame"); return -1; } #ifdef DEBUG printf("end of frame encode, %d regions\n", g_hash_table_size(jxl->tile_hash)); #endif /*DEBUG*/ VIPS_FREEF(g_hash_table_destroy, jxl->tile_hash); return 0; } static int vips_foreign_save_jxl_save(VipsForeignSaveJxl *jxl, VipsImage *in) { vips_foreign_save_jxl_set_output_processor(jxl); vips_foreign_save_jxl_set_input_source(jxl); for (int n = 0; n < jxl->page_count; n++) { VipsImage *page; if (vips_crop(in, &page, 0, n * jxl->page_height, in->Xsize, jxl->page_height, NULL)) return -1; if (vips_foreign_save_jxl_save_page(jxl, n, page)) { VIPS_UNREF(page); return -1; } VIPS_UNREF(page); if (jxl->error) return -1; } return 0; } #else /*!defined(HAVE_LIBJXL_0_9)*/ /* Output for sequential write. */ static int vips_foreign_save_jxl_process_output(VipsForeignSaveJxl *jxl) { JxlEncoderStatus status; do { uint8_t *out = jxl->output_buffer; size_t avail_out = OUTPUT_BUFFER_SIZE; status = JxlEncoderProcessOutput(jxl->encoder, &out, &avail_out); switch (status) { case JXL_ENC_SUCCESS: case JXL_ENC_NEED_MORE_OUTPUT: if (OUTPUT_BUFFER_SIZE > avail_out && vips_target_write(jxl->target, jxl->output_buffer, OUTPUT_BUFFER_SIZE - avail_out)) return -1; break; default: vips_foreign_save_jxl_error(jxl, "JxlEncoderProcessOutput"); #ifdef DEBUG vips_foreign_save_jxl_print_status(status); #endif /*DEBUG*/ return -1; } } while (status != JXL_ENC_SUCCESS); return 0; } static int vips_foreign_save_jxl_add_frame(VipsForeignSaveJxl *jxl) { JxlEncoderFrameSettings *frame_settings = JxlEncoderFrameSettingsCreate(jxl->encoder, NULL); JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_DECODING_SPEED, jxl->tier); JxlEncoderSetFrameDistance(frame_settings, jxl->distance); JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_EFFORT, jxl->effort); JxlEncoderSetFrameLossless(frame_settings, jxl->lossless); #ifdef HAVE_LIBJXL_0_8 const JxlBitDepth bitdepth = { .type = JXL_BIT_DEPTH_FROM_CODESTREAM, }; JxlEncoderSetFrameBitDepth(frame_settings, &bitdepth); #endif if (jxl->info.have_animation) { JxlFrameHeader header = { 0 }; if (!jxl->is_animated) header.duration = 0xffffffff; else header.duration = vips_foreign_save_jxl_get_delay(jxl, jxl->page_number); JxlEncoderSetFrameHeader(frame_settings, &header); } if (JxlEncoderAddImageFrame(frame_settings, &jxl->format, jxl->scanline_buffer, jxl->scanline_size)) { vips_foreign_save_jxl_error(jxl, "JxlEncoderAddImageFrame"); return -1; } jxl->page_number += 1; /* We should close frames before processing the output * if we have written the last frame. */ if (jxl->page_number == jxl->page_count) JxlEncoderCloseFrames(jxl->encoder); return vips_foreign_save_jxl_process_output(jxl); } /* Another chunk of pixels have arrived from the pipeline. Add to frame, and * if the frame completes, compress and write to the target. */ static int vips_foreign_save_jxl_sink_disc(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) a; size_t sz = VIPS_IMAGE_SIZEOF_PEL(region->im) * area->width; /* Write the new pixels into the frame. */ for (int i = 0; i < area->height; i++) { memcpy(jxl->scanline_buffer + sz * jxl->scanline_y, VIPS_REGION_ADDR(region, 0, area->top + i), sz); jxl->scanline_y += 1; /* If we've filled the frame, add it to the encoder. */ if (jxl->scanline_y == jxl->page_height) { if (vips_foreign_save_jxl_add_frame(jxl)) return -1; jxl->scanline_y = 0; } } return 0; } static int vips_foreign_save_jxl_save_sequential(VipsForeignSaveJxl *jxl, VipsImage *in) { /* Write the header. */ if (vips_foreign_save_jxl_process_output(jxl)) return -1; /* RGB(A) frame as a contiguous buffer. */ jxl->scanline_size = VIPS_IMAGE_SIZEOF_LINE(in) * jxl->page_height; if (!(jxl->scanline_buffer = vips_tracked_malloc(jxl->scanline_size))) return -1; if (vips_sink_disc(in, vips_foreign_save_jxl_sink_disc, jxl)) return -1; /* This function must be called after the final frame and/or box, * otherwise the codestream will not be encoded correctly. */ JxlEncoderCloseInput(jxl->encoder); /* Flush any remaining libjxl writes. */ if (vips_foreign_save_jxl_process_output(jxl)) return -1; return 0; } #endif /*defined(HAVE_LIBJXL_0_9)*/ static int vips_foreign_save_jxl_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; VipsBandFormat format; if (VIPS_OBJECT_CLASS(vips_foreign_save_jxl_parent_class)->build(object)) return -1; jxl->page_height = vips_image_get_page_height(save->ready); jxl->page_count = save->ready->Ysize / jxl->page_height; /* If Q is set and distance is not, use Q to set a rough distance * value. */ if (!vips_object_argument_isset(object, "distance")) #ifdef HAVE_LIBJXL_0_9 jxl->distance = JxlEncoderDistanceFromQuality((float) jxl->Q); #else jxl->distance = jxl->Q >= 30 ? 0.1 + (100 - jxl->Q) * 0.09 : 53.0 / 3000.0 * jxl->Q * jxl->Q - 23.0 / 20.0 * jxl->Q + 25.0; #endif /* Distance 0 is lossless. libjxl will fail for lossy distance 0. */ if (jxl->distance == 0) jxl->lossless = TRUE; jxl->runner = JxlThreadParallelRunnerCreate(NULL, vips_concurrency_get()); jxl->encoder = JxlEncoderCreate(NULL); if (JxlEncoderSetParallelRunner(jxl->encoder, JxlThreadParallelRunner, jxl->runner)) { vips_foreign_save_jxl_error(jxl, "JxlDecoderSetParallelRunner"); return -1; } in = save->ready; /* Fix the input image format. JXL uses float for 0-1 linear (ie. * scRGB) only. We must convert eg. sRGB float to 8-bit for save. */ if (in->Type == VIPS_INTERPRETATION_scRGB) format = VIPS_FORMAT_FLOAT; else if (in->Type == VIPS_INTERPRETATION_RGB16 || in->Type == VIPS_INTERPRETATION_GREY16) format = VIPS_FORMAT_USHORT; else format = VIPS_FORMAT_UCHAR; /* bitdepth defaults to 16 for ushort images. */ if (!vips_object_argument_isset(object, "bitdepth") && format == VIPS_FORMAT_USHORT) jxl->bitdepth = 16; /* Mimics VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA. * FIXME: add support encoding images with > 4 bands. */ if (in->Bands > 4) { if (vips_extract_band(in, &t[0], 0, "n", 4, NULL)) return -1; in = t[0]; } /* The user can set bitdepth to size the number of bits down for int * formats. libjxl expects input image bits to be right-justified, so * we must shift. */ if (format == VIPS_FORMAT_UCHAR || format == VIPS_FORMAT_USHORT) { int image_bits_per_sample = format == VIPS_FORMAT_UCHAR ? 8 : 16; int bits_per_sample = VIPS_MIN(jxl->bitdepth, image_bits_per_sample); #ifndef HAVE_LIBJXL_0_8 /* libjxl < 0.8 does not support setting input buffer bitdepth, so clamp to 8 or 16. */ bits_per_sample = bits_per_sample > 8 ? 16 : 8; #endif int shift = image_bits_per_sample - bits_per_sample; if (vips_rshift_const1(in, &t[1], shift, NULL)) return -1; in = t[1]; } /* libjxl throws an error if we give it ushort data with <= 8 bitdepth. */ if (format == VIPS_FORMAT_USHORT && jxl->bitdepth <= 8) format = VIPS_FORMAT_UCHAR; /* Cast the image to conform to the format we will give to libjxl. */ if (vips_cast(in, &t[2], format, NULL)) return -1; in = t[2]; /* We need to cache a complete line of jxl 2k x 2k tiles, plus a bit. * We don't need to allow threaded access -- libjxl will never try to * encode tiles in parallel (sadly). */ if (vips_tilecache(in, &t[3], "tile-width", in->Xsize, "tile-height", 512, "max_tiles", 3500 / 512, NULL)) return -1; in = t[3]; if (vips_foreign_save_jxl_set_header(jxl, in)) return -1; if (jxl->info.have_animation) { /* Get delay array * * There might just be the old gif-delay field. This is centiseconds. */ jxl->gif_delay = 10; if (vips_image_get_typeof(in, "gif-delay") && vips_image_get_int(in, "gif-delay", &jxl->gif_delay)) return -1; /* New images have an array of ints instead. */ jxl->delay = NULL; if (vips_image_get_typeof(in, "delay") && vips_image_get_array_int(in, "delay", &jxl->delay, &jxl->delay_length)) return -1; /* If there's delay metadata, this is an animated image (as opposed to * a multipage one). */ if (vips_image_get_typeof(save->ready, "delay") || vips_image_get_typeof(save->ready, "gif-delay")) jxl->is_animated = TRUE; } #ifdef DEBUG vips_foreign_save_jxl_print_info(&jxl->info); vips_foreign_save_jxl_print_format(&jxl->format); printf("JxlEncoderFrameSettings:\n"); printf(" tier = %d\n", jxl->tier); printf(" distance = %g\n", jxl->distance); printf(" effort = %d\n", jxl->effort); printf(" lossless = %d\n", jxl->lossless); #endif /*DEBUG*/ #ifdef HAVE_LIBJXL_0_9 /* _save() is not a vips_sink_*() iterator, so we must emit * the various signals by hand. */ vips_image_preeval(save->ready); int result = vips_foreign_save_jxl_save(jxl, in); vips_image_posteval(save->ready); vips_image_minimise_all(save->ready); if (jxl->error) return -1; #else /*!defined(HAVE_LIBJXL_0_9)*/ int result = vips_foreign_save_jxl_save_sequential(jxl, in); #endif /*defined(HAVE_LIBJXL_0_9)*/ if (vips_target_end(jxl->target)) return -1; return result; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT #define F VIPS_FORMAT_FLOAT /* Type promotion for save ... unsigned ints + float + double. */ static VipsBandFormat bandfmt_jxl[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, F, F, F, F, F, F }; static void vips_foreign_save_jxl_class_init(VipsForeignSaveJxlClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->finalize = vips_foreign_save_jxl_finalize; gobject_class->dispose = vips_foreign_save_jxl_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlsave_base"; object_class->description = _("save image in JPEG-XL format"); object_class->build = vips_foreign_save_jxl_build; /* libjxl is fuzzed, but it's still relatively young and bugs are * still being found in jan 2022. Revise this status soon. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips__jxl_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->format_table = bandfmt_jxl; VIPS_ARG_INT(class, "tier", 10, _("Tier"), _("Decode speed tier"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxl, tier), 0, 4, 0); VIPS_ARG_DOUBLE(class, "distance", 11, _("Distance"), _("Target butteraugli distance"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxl, distance), 0.0, 25.0, 1.0); VIPS_ARG_INT(class, "effort", 12, _("Effort"), _("Encoding effort"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxl, effort), 1, 10, 7); VIPS_ARG_BOOL(class, "lossless", 13, _("Lossless"), _("Enable lossless compression"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxl, lossless), FALSE); VIPS_ARG_INT(class, "Q", 14, _("Q"), _("Quality factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxl, Q), 0, 100, 75); VIPS_ARG_INT(class, "bitdepth", 15, _("Bitdepth"), _("Bit depth"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxl, bitdepth), 1, 16, 8); } static void vips_foreign_save_jxl_init(VipsForeignSaveJxl *jxl) { jxl->distance = 1.0; jxl->effort = 7; jxl->Q = 75; jxl->bitdepth = 8; #ifdef HAVE_LIBJXL_0_9 g_mutex_init(&jxl->tile_lock); #endif } typedef struct _VipsForeignSaveJxlFile { VipsForeignSaveJxl parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveJxlFile; typedef VipsForeignSaveJxlClass VipsForeignSaveJxlFileClass; G_DEFINE_TYPE(VipsForeignSaveJxlFile, vips_foreign_save_jxl_file, vips_foreign_save_jxl_get_type()); static int vips_foreign_save_jxl_file_build(VipsObject *object) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object; VipsForeignSaveJxlFile *file = (VipsForeignSaveJxlFile *) object; if (!(jxl->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_jxl_file_parent_class) ->build(object); } static void vips_foreign_save_jxl_file_class_init(VipsForeignSaveJxlFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlsave"; object_class->build = vips_foreign_save_jxl_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxlFile, filename), NULL); } static void vips_foreign_save_jxl_file_init(VipsForeignSaveJxlFile *file) { } typedef struct _VipsForeignSaveJxlBuffer { VipsForeignSaveJxl parent_object; /* Save to a buffer. */ VipsArea *buf; } VipsForeignSaveJxlBuffer; typedef VipsForeignSaveJxlClass VipsForeignSaveJxlBufferClass; G_DEFINE_TYPE(VipsForeignSaveJxlBuffer, vips_foreign_save_jxl_buffer, vips_foreign_save_jxl_get_type()); static int vips_foreign_save_jxl_buffer_build(VipsObject *object) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object; VipsForeignSaveJxlBuffer *buffer = (VipsForeignSaveJxlBuffer *) object; VipsBlob *blob; if (!(jxl->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_jxl_buffer_parent_class) ->build(object)) return -1; g_object_get(jxl->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_jxl_buffer_class_init( VipsForeignSaveJxlBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlsave_buffer"; object_class->build = vips_foreign_save_jxl_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveJxlBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_jxl_buffer_init(VipsForeignSaveJxlBuffer *buffer) { } typedef struct _VipsForeignSaveJxlTarget { VipsForeignSaveJxl parent_object; VipsTarget *target; } VipsForeignSaveJxlTarget; typedef VipsForeignSaveJxlClass VipsForeignSaveJxlTargetClass; G_DEFINE_TYPE(VipsForeignSaveJxlTarget, vips_foreign_save_jxl_target, vips_foreign_save_jxl_get_type()); static int vips_foreign_save_jxl_target_build(VipsObject *object) { VipsForeignSaveJxl *jxl = (VipsForeignSaveJxl *) object; VipsForeignSaveJxlTarget *target = (VipsForeignSaveJxlTarget *) object; if (target->target) { jxl->target = target->target; g_object_ref(jxl->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_jxl_target_parent_class) ->build(object); } static void vips_foreign_save_jxl_target_class_init( VipsForeignSaveJxlTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "jxlsave_target"; object_class->build = vips_foreign_save_jxl_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveJxlTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_jxl_target_init(VipsForeignSaveJxlTarget *target) { } #endif /*HAVE_LIBJXL*/ /* The C API wrappers are defined in foreign.c. */ libvips-8.18.2/libvips/foreign/libnsgif/000077500000000000000000000000001516303661500201665ustar00rootroot00000000000000libvips-8.18.2/libvips/foreign/libnsgif/COPYING000066400000000000000000000021551516303661500212240ustar00rootroot00000000000000Copyright (C) 2004 Richard Wilson Copyright (C) 2008 Sean Fox Copyright (C) 2013-2021 Michael Drake 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. libvips-8.18.2/libvips/foreign/libnsgif/README-ns.md000066400000000000000000000126601516303661500220700ustar00rootroot00000000000000LibNSGIF: NetSurf GIF decoder ============================= LibNSGIF is a C library for decoding GIF format images and animations. It is licenced under the MIT licence. This library aims to provide a simple API for robust decoding of GIF files. Details ------- The GIF source data is scanned prior to decoding, allowing for efficient decoding. The scanning phase will scan currently available data and will resume from where it left off when called with additional data. Only one frame is ever fully decoded to a bitmap at a time, reducing memory usage for large GIFs. Using ----- LibNSGIF allows the client to allocate the bitmap into which the GIF is decoded. The client can have an arbitrary bitmap structure, that is simply a void pointer to LibNSGIF. The client must provide a callback table for interacting with bitmaps, and the required client bitmap pixel format. The bitmap table must include as a minimum functions to create and destroy bitmaps, and a function to get a pointer to the bitmap's pixel data buffer. LibNSGIF always decodes to a 32bpp, 8 bits per channel bitmap pixel format, however it allows the client to control the colour component ordering. To load a GIF, first create an nsgif object with `nsgif_create()`. ```c err = nsgif_create(&bitmap_callbacks, NSGIF_BITMAP_FMT_R8G8B8A8, &gif); if (err != NSGIF_OK) { fprintf(stderr, "%s\n", nsgif_strerror(err)); // Handle error } ``` Now you can load the GIF source data into the nsgif object with `nsgif_data_scan()`: ```c err = nsgif_data_scan(gif, size, data); if (err != NSGIF_OK) { fprintf(stderr, "%s\n", nsgif_strerror(err)); // Handle error } ``` This scans the source data and decodes information about each frame, however it doesn't decode any of the bitmap data for the frames. The client may call `nsgif_data_scan()` multiple times as source data is fetched. The early frames can be decoded before the later frames are scanned. Frames have to be scanned before they can be decoded. This function will sometimes return an error. That is OK, and even expected. It is fine to proceed to decoding any frames that are available after a scan. Some errors indicate that there is a flaw in the source GIF data (not at all uncommon, GIF is an ancient format that has had many broken encoders), or that it has reached the end of the source data. > **Note**: The client must not free the data until after calling > `nsgif_destroy()`. You can move the data, e.g. if you realloc to a bigger > buffer. Just be sure to call `nsgif_data_scan()` again with the new pointer > before making any other calls against that nsgif object. When all the source data has been provided to `nsgif_data_scan()` it is advisable to call `nsgif_data_complete()` (see below), although this is not necessary to start decoding frames. To decode the frames, you can call `nsgif_get_info()` to get the frame_count, and then call `nsgif_frame_decode()` for each frame, and manage the animation, and non-displayable frames yourself, or you can use the helper function, `nsgif_frame_prepare()`: ```c err = nsgif_frame_prepare(gif, &area, &delay_cs, &frame_new); if (err != NSGIF_OK) { fprintf(stderr, "%s\n", nsgif_strerror(err)); // Handle error } // Update our bitmap to know it should be showing `frame_new` now. // Trigger redraw of `area` of image. if (delay_cs != NSGIF_INFINITE) { // Schedule next frame in delay_cs. } ``` This will return the number of the next frame to be decoded, the delay in cs before the next frame should be decoded, and the area of the bitmap that needs to be redrawn. > **Note**: GIF frames may only occupy a portion of the overall bitmap, and only > redrawing the area that has changed may be more efficient than redrawing the > whole thing. The returned area comprises both any region that has been > changed in the disposal of the previous frame and the new frame. GIF files can limit the number of animation loops to a finite number or they may only have one frame. In either of these cases, the returned delay is `NSGIF_INFINITE` indicating that the animation is complete. Subsequent calls to `nsgif_frame_prepare()` will return `NSGIF_ERR_ANIMATION_END`. To force the repeat of an animation, call `nsgif_reset()`. One reason for the two-step decoding of frames is that it enables deferred decoding. You can call `nsgif_frame_prepare()` and cause a redraw of that portion of your document. If the GIF is off screen (another tab, or scrolled out of sight), there is no need to decode it at all. Once the bitmap is needed for a redraw, you can decode the correct frame on-demand with: ```c err = nsgif_frame_decode(gif, frame_new, &bitmap); if (err != NSGIF_OK) { fprintf(stderr, "%s\n", nsgif_strerror(err)); // Handle error } ``` Note that this will be a no-op if the requested frame already happens to be the decoded frame. You can call `nsgif_frame_prepare()` and `nsgif_frame_decode()` before all of the GIF data has been provided using `nsgif_data_scan()` calls. For example if you want to make a start decoding and displaying the early frames of the GIF before the entire animation file has been downloaded. When you do this, `nsgif_frame_prepare()` will not loop the animation back to the start unless you call `nsgif_data_complete()` to indicate all of the data has been fetched. Calling `nsgif_data_complete()` also lets libnsgif display any trailing truncated frame. ```c nsgif_data_complete(gif); ``` Once you are done with the GIF, free up the nsgif object with: ```c nsgif_destroy(gif); ``` libvips-8.18.2/libvips/foreign/libnsgif/README.md000066400000000000000000000006471516303661500214540ustar00rootroot00000000000000# libnsgif This is [libnsgif](https://www.netsurf-browser.org/projects/libnsgif/), but within the libvips build system. # To update Run `./update.sh` to update this copy of libnsgif from the upstream repo. It will also patch libnsgif.c to prevent it modifying the input. Last updated 22 Jan 2023. # To do No attempt made to run tests or build docs. Though the gif loader is tested as part of the libvips test suite. libvips-8.18.2/libvips/foreign/libnsgif/gif.c000066400000000000000000001432721516303661500211100ustar00rootroot00000000000000/* * Copyright 2004 Richard Wilson * Copyright 2008 Sean Fox * Copyright 2013-2022 Michael Drake * * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/ * Licenced under the MIT License, * http://www.opensource.org/licenses/mit-license.php */ #include #include #include #include #include #include "lzw.h" #include "nsgif.h" /** Default minimum allowable frame delay in cs. */ #define NSGIF_FRAME_DELAY_MIN 2 /** * Default frame delay to apply. * * Used when a frame delay lower than the minimum is requested. */ #define NSGIF_FRAME_DELAY_DEFAULT 10 /** GIF frame data */ typedef struct nsgif_frame { struct nsgif_frame_info info; /** offset (in bytes) to the GIF frame data */ size_t frame_offset; /** whether the frame has previously been decoded. */ bool decoded; /** whether the frame is totally opaque */ bool opaque; /** whether a full image redraw is required */ bool redraw_required; /** Amount of LZW data found in scan */ uint32_t lzw_data_length; /** the index designating a transparent pixel */ uint32_t transparency_index; /** offset to frame colour table */ uint32_t colour_table_offset; /* Frame flags */ uint32_t flags; } nsgif_frame; /** Pixel format: colour component order. */ struct nsgif_colour_layout { uint8_t r; /**< Byte offset within pixel to red component. */ uint8_t g; /**< Byte offset within pixel to green component. */ uint8_t b; /**< Byte offset within pixel to blue component. */ uint8_t a; /**< Byte offset within pixel to alpha component. */ }; /** GIF animation data */ struct nsgif { struct nsgif_info info; /** LZW decode context */ void *lzw_ctx; /** callbacks for bitmap functions */ nsgif_bitmap_cb_vt bitmap; /** decoded frames */ nsgif_frame *frames; /** current frame */ uint32_t frame; /** current frame decoded to bitmap */ uint32_t decoded_frame; /** currently decoded image; stored as bitmap from bitmap_create callback */ nsgif_bitmap_t *frame_image; /** Row span of frame_image in pixels. */ uint32_t rowspan; /** Minimum allowable frame delay. */ uint16_t delay_min; /** Frame delay to apply when delay is less than \ref delay_min. */ uint16_t delay_default; /** number of animation loops so far */ int loop_count; /** number of frames partially decoded */ uint32_t frame_count_partial; /** * Whether all the GIF data has been supplied, or if there may be * more to come. */ bool data_complete; /** pointer to GIF data */ const uint8_t *buf; /** current index into GIF data */ size_t buf_pos; /** total number of bytes of GIF data available */ size_t buf_len; /** current number of frame holders */ uint32_t frame_holders; /** background index */ uint32_t bg_index; /** image aspect ratio (ignored) */ uint32_t aspect_ratio; /** size of global colour table (in entries) */ uint32_t colour_table_size; /** current colour table */ uint32_t *colour_table; /** Client's colour component order. */ struct nsgif_colour_layout colour_layout; /** global colour table */ uint32_t global_colour_table[NSGIF_MAX_COLOURS]; /** local colour table */ uint32_t local_colour_table[NSGIF_MAX_COLOURS]; /** previous frame for NSGIF_FRAME_RESTORE */ void *prev_frame; /** previous frame index */ uint32_t prev_index; }; /** * Helper macro to get number of elements in an array. * * \param[in] _a Array to count elements of. * \return NUlber of elements in array. */ #define NSGIF_ARRAY_LEN(_a) ((sizeof(_a)) / (sizeof(*_a))) /** * * \file * \brief GIF image decoder * * The GIF format is thoroughly documented; a full description can be found at * http://www.w3.org/Graphics/GIF/spec-gif89a.txt * * \todo Plain text and comment extensions should be implemented. */ /** Internal flag that the colour table needs to be processed */ #define NSGIF_PROCESS_COLOURS 0xaa000000 /** Internal flag that a frame is invalid/unprocessed */ #define NSGIF_FRAME_INVALID UINT32_MAX /** Transparent colour */ #define NSGIF_TRANSPARENT_COLOUR 0x00 /** No transparency */ #define NSGIF_NO_TRANSPARENCY (0xFFFFFFFFu) /* GIF Flags */ #define NSGIF_COLOUR_TABLE_MASK 0x80 #define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07 #define NSGIF_BLOCK_TERMINATOR 0x00 #define NSGIF_TRAILER 0x3b /** * Convert an LZW result code to equivalent GIF result code. * * \param[in] l_res LZW response code. * \return GIF result code. */ static nsgif_error nsgif__error_from_lzw(lzw_result l_res) { static const nsgif_error g_res[] = { [LZW_OK] = NSGIF_OK, [LZW_NO_MEM] = NSGIF_ERR_OOM, [LZW_OK_EOD] = NSGIF_ERR_END_OF_DATA, [LZW_NO_DATA] = NSGIF_ERR_END_OF_DATA, [LZW_EOI_CODE] = NSGIF_ERR_DATA_FRAME, [LZW_BAD_ICODE] = NSGIF_ERR_DATA_FRAME, [LZW_BAD_CODE] = NSGIF_ERR_DATA_FRAME, }; assert(l_res != LZW_BAD_PARAM); assert(l_res != LZW_NO_COLOUR); return g_res[l_res]; } /** * Updates the sprite memory size * * \param gif The animation context * \param width The width of the sprite * \param height The height of the sprite * \return NSGIF_ERR_OOM for a memory error NSGIF_OK for success */ static nsgif_error nsgif__initialise_sprite( struct nsgif *gif, uint32_t width, uint32_t height) { /* Already allocated? */ if (gif->frame_image) { return NSGIF_OK; } assert(gif->bitmap.create); gif->frame_image = gif->bitmap.create(width, height); if (gif->frame_image == NULL) { return NSGIF_ERR_OOM; } return NSGIF_OK; } /** * Helper to get the rendering bitmap for a gif. * * \param[in] gif The gif object we're decoding. * \return Client pixel buffer for rendering into. */ static inline uint32_t* nsgif__bitmap_get( struct nsgif *gif) { nsgif_error ret; /* Make sure we have a buffer to decode to. */ ret = nsgif__initialise_sprite(gif, gif->info.width, gif->info.height); if (ret != NSGIF_OK) { return NULL; } gif->rowspan = gif->info.width; if (gif->bitmap.get_rowspan) { gif->rowspan = gif->bitmap.get_rowspan(gif->frame_image); } /* Get the frame data */ assert(gif->bitmap.get_buffer); return (void *)gif->bitmap.get_buffer(gif->frame_image); } /** * Helper to tell the client that their bitmap was modified. * * \param[in] gif The gif object we're decoding. */ static inline void nsgif__bitmap_modified( const struct nsgif *gif) { if (gif->bitmap.modified) { gif->bitmap.modified(gif->frame_image); } } /** * Helper to tell the client that whether the bitmap is opaque. * * \param[in] gif The gif object we're decoding. * \param[in] frame The frame that has been decoded. */ static inline void nsgif__bitmap_set_opaque( const struct nsgif *gif, const struct nsgif_frame *frame) { if (gif->bitmap.set_opaque) { gif->bitmap.set_opaque( gif->frame_image, frame->opaque); } } /** * Helper to get the client to determine if the bitmap is opaque. * * \todo: We don't really need to get the client to do this for us. * * \param[in] gif The gif object we're decoding. * \return true if the bitmap is opaque, false otherwise. */ static inline bool nsgif__bitmap_get_opaque( const struct nsgif *gif) { if (gif->bitmap.test_opaque) { return gif->bitmap.test_opaque( gif->frame_image); } return false; } static void nsgif__record_frame( struct nsgif *gif, const uint32_t *bitmap) { size_t pixel_bytes = sizeof(*bitmap); size_t height = gif->info.height; size_t width = gif->info.width; uint32_t *prev_frame; if (gif->decoded_frame == NSGIF_FRAME_INVALID || gif->decoded_frame == gif->prev_index) { /* No frame to copy, or already have this frame recorded. */ return; } bitmap = nsgif__bitmap_get(gif); if (bitmap == NULL) { return; } if (gif->prev_frame == NULL) { prev_frame = realloc(gif->prev_frame, width * height * pixel_bytes); if (prev_frame == NULL) { return; } } else { prev_frame = gif->prev_frame; } memcpy(prev_frame, bitmap, width * height * pixel_bytes); gif->prev_frame = prev_frame; gif->prev_index = gif->decoded_frame; } static nsgif_error nsgif__recover_frame( const struct nsgif *gif, uint32_t *bitmap) { const uint32_t *prev_frame = gif->prev_frame; size_t pixel_bytes = sizeof(*bitmap); size_t height = gif->info.height; size_t width = gif->info.width; memcpy(bitmap, prev_frame, height * width * pixel_bytes); return NSGIF_OK; } /** * Get the next line for GIF decode. * * Note that the step size must be initialised to 24 at the start of the frame * (when y == 0). This is because of the first two passes of the frame have * the same step size of 8, and the step size is used to determine the current * pass. * * \param[in] height Frame height in pixels. * \param[in,out] y Current row, starting from 0, updated on exit. * \param[in,out] step Current step starting with 24, updated on exit. * \return true if there is a row to process, false at the end of the frame. */ static inline bool nsgif__deinterlace(uint32_t height, uint32_t *y, uint8_t *step) { *y += *step & 0xf; if (*y < height) return true; switch (*step) { case 24: *y = 4; *step = 8; if (*y < height) return true; /* Fall through. */ case 8: *y = 2; *step = 4; if (*y < height) return true; /* Fall through. */ case 4: *y = 1; *step = 2; if (*y < height) return true; /* Fall through. */ default: break; } return false; } /** * Get the next line for GIF decode. * * \param[in] interlace Non-zero if the frame is not interlaced. * \param[in] height Frame height in pixels. * \param[in,out] y Current row, starting from 0, updated on exit. * \param[in,out] step Current step starting with 24, updated on exit. * \return true if there is a row to process, false at the end of the frame. */ static inline bool nsgif__next_row(uint32_t interlace, uint32_t height, uint32_t *y, uint8_t *step) { if (!interlace) { return (++*y != height); } else { return nsgif__deinterlace(height, y, step); } } /** * Get any frame clip adjustment for the image extent. * * \param[in] frame_off Frame's X or Y offset. * \param[in] frame_dim Frame width or height. * \param[in] image_ext Image width or height constraint. * \return the amount the frame needs to be clipped to fit the image in given * dimension. */ static inline uint32_t gif__clip( uint32_t frame_off, uint32_t frame_dim, uint32_t image_ext) { uint32_t frame_ext = frame_off + frame_dim; if (frame_ext <= image_ext) { return 0; } return frame_ext - image_ext; } /** * Perform any jump over decoded data, to accommodate clipped portion of frame. * * \param[in,out] skip Number of pixels of data to jump. * \param[in,out] available Number of pixels of data currently available. * \param[in,out] pos Position in decoded pixel value data. */ static inline void gif__jump_data( uint32_t *skip, uint32_t *available, const uint8_t **pos) { uint32_t jump = (*skip < *available) ? *skip : *available; *skip -= jump; *available -= jump; *pos += jump; } static nsgif_error nsgif__decode_complex( struct nsgif *gif, uint32_t width, uint32_t height, uint32_t offset_x, uint32_t offset_y, uint32_t interlace, const uint8_t *data, uint32_t transparency_index, uint32_t *restrict frame_data, uint32_t *restrict colour_table) { lzw_result res; nsgif_error ret = NSGIF_OK; uint32_t clip_x = gif__clip(offset_x, width, gif->info.width); uint32_t clip_y = gif__clip(offset_y, height, gif->info.height); const uint8_t *uncompressed; uint32_t available = 0; uint8_t step = 24; uint32_t skip = 0; uint32_t y = 0; if (offset_x >= gif->info.width || offset_y >= gif->info.height) { return NSGIF_OK; } width -= clip_x; height -= clip_y; if (width == 0 || height == 0) { return NSGIF_OK; } /* Initialise the LZW decoding */ res = lzw_decode_init(gif->lzw_ctx, data[0], gif->buf, gif->buf_len, data + 1 - gif->buf); if (res != LZW_OK) { return nsgif__error_from_lzw(res); } do { uint32_t x; uint32_t *frame_scanline; frame_scanline = frame_data + offset_x + (y + offset_y) * gif->rowspan; x = width; while (x > 0) { unsigned row_available; while (available == 0) { if (res != LZW_OK) { /* Unexpected end of frame, try to recover */ if (res == LZW_OK_EOD || res == LZW_EOI_CODE) { ret = NSGIF_OK; } else { ret = nsgif__error_from_lzw(res); } return ret; } res = lzw_decode(gif->lzw_ctx, &uncompressed, &available); if (available == 0) { return NSGIF_OK; } gif__jump_data(&skip, &available, &uncompressed); } row_available = x < available ? x : available; x -= row_available; available -= row_available; if (transparency_index > 0xFF) { while (row_available-- > 0) { *frame_scanline++ = colour_table[*uncompressed++]; } } else { while (row_available-- > 0) { register uint32_t colour; colour = *uncompressed++; if (colour != transparency_index) { *frame_scanline = colour_table[colour]; } frame_scanline++; } } } skip = clip_x; gif__jump_data(&skip, &available, &uncompressed); } while (nsgif__next_row(interlace, height, &y, &step)); return ret; } static nsgif_error nsgif__decode_simple( struct nsgif *gif, uint32_t height, uint32_t offset_y, const uint8_t *data, uint32_t transparency_index, uint32_t *restrict frame_data, uint32_t *restrict colour_table) { uint32_t pixels; uint32_t written = 0; nsgif_error ret = NSGIF_OK; lzw_result res; if (offset_y >= gif->info.height) { return NSGIF_OK; } height -= gif__clip(offset_y, height, gif->info.height); if (height == 0) { return NSGIF_OK; } /* Initialise the LZW decoding */ res = lzw_decode_init_map(gif->lzw_ctx, data[0], transparency_index, colour_table, gif->buf, gif->buf_len, data + 1 - gif->buf); if (res != LZW_OK) { return nsgif__error_from_lzw(res); } frame_data += (offset_y * gif->info.width); pixels = gif->info.width * height; while (pixels > 0) { res = lzw_decode_map(gif->lzw_ctx, frame_data, pixels, &written); pixels -= written; frame_data += written; if (res != LZW_OK) { /* Unexpected end of frame, try to recover */ if (res == LZW_OK_EOD || res == LZW_EOI_CODE) { ret = NSGIF_OK; } else { ret = nsgif__error_from_lzw(res); } break; } } if (pixels == 0) { ret = NSGIF_OK; } return ret; } static inline nsgif_error nsgif__decode( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t *data, uint32_t *restrict frame_data) { nsgif_error ret; uint32_t width = frame->info.rect.x1 - frame->info.rect.x0; uint32_t height = frame->info.rect.y1 - frame->info.rect.y0; uint32_t offset_x = frame->info.rect.x0; uint32_t offset_y = frame->info.rect.y0; uint32_t transparency_index = frame->transparency_index; uint32_t *restrict colour_table = gif->colour_table; if (frame->info.interlaced == false && offset_x == 0 && width == gif->info.width && width == gif->rowspan) { ret = nsgif__decode_simple(gif, height, offset_y, data, transparency_index, frame_data, colour_table); } else { ret = nsgif__decode_complex(gif, width, height, offset_x, offset_y, frame->info.interlaced, data, transparency_index, frame_data, colour_table); } if (gif->data_complete && ret == NSGIF_ERR_END_OF_DATA) { /* This is all the data there is, so make do. */ ret = NSGIF_OK; } return ret; } /** * Restore a GIF to the background colour. * * \param[in] gif The gif object we're decoding. * \param[in] frame The frame to clear, or NULL. * \param[in] bitmap The bitmap to clear the frame in. */ static void nsgif__restore_bg( struct nsgif *gif, struct nsgif_frame *frame, uint32_t *bitmap) { size_t pixel_bytes = sizeof(*bitmap); if (frame == NULL) { size_t width = gif->info.width; size_t height = gif->info.height; memset(bitmap, NSGIF_TRANSPARENT_COLOUR, width * height * pixel_bytes); } else { uint32_t width = frame->info.rect.x1 - frame->info.rect.x0; uint32_t height = frame->info.rect.y1 - frame->info.rect.y0; uint32_t offset_x = frame->info.rect.x0; uint32_t offset_y = frame->info.rect.y0; if (frame->info.display == false || frame->info.rect.x0 >= gif->info.width || frame->info.rect.y0 >= gif->info.height) { return; } width -= gif__clip(offset_x, width, gif->info.width); height -= gif__clip(offset_y, height, gif->info.height); if (frame->info.transparency) { for (uint32_t y = 0; y < height; y++) { uint32_t *scanline = bitmap + offset_x + (offset_y + y) * gif->info.width; memset(scanline, NSGIF_TRANSPARENT_COLOUR, width * pixel_bytes); } } else { for (uint32_t y = 0; y < height; y++) { uint32_t *scanline = bitmap + offset_x + (offset_y + y) * gif->info.width; for (uint32_t x = 0; x < width; x++) { scanline[x] = gif->info.background; } } } } } static nsgif_error nsgif__update_bitmap( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t *data, uint32_t frame_idx) { nsgif_error ret; uint32_t *bitmap; gif->decoded_frame = frame_idx; bitmap = nsgif__bitmap_get(gif); if (bitmap == NULL) { return NSGIF_ERR_OOM; } /* Handle any bitmap clearing/restoration required before decoding this * frame. */ if (frame_idx == 0 || gif->decoded_frame == NSGIF_FRAME_INVALID) { nsgif__restore_bg(gif, NULL, bitmap); } else { struct nsgif_frame *prev = &gif->frames[frame_idx - 1]; if (prev->info.disposal == NSGIF_DISPOSAL_RESTORE_BG) { nsgif__restore_bg(gif, prev, bitmap); } else if (prev->info.disposal == NSGIF_DISPOSAL_RESTORE_PREV) { ret = nsgif__recover_frame(gif, bitmap); if (ret != NSGIF_OK) { nsgif__restore_bg(gif, prev, bitmap); } } } if (frame->info.disposal == NSGIF_DISPOSAL_RESTORE_PREV) { /* Store the previous frame for later restoration */ nsgif__record_frame(gif, bitmap); } ret = nsgif__decode(gif, frame, data, bitmap); nsgif__bitmap_modified(gif); if (!frame->decoded) { frame->opaque = nsgif__bitmap_get_opaque(gif); frame->decoded = true; } nsgif__bitmap_set_opaque(gif, frame); return ret; } /** * Parse the graphic control extension * * \param[in] frame The gif frame object we're decoding. * \param[in] data The data to decode. * \param[in] len Byte length of data. * \return NSGIF_ERR_END_OF_DATA if more data is needed, * NSGIF_OK for success. */ static nsgif_error nsgif__parse_extension_graphic_control( struct nsgif_frame *frame, const uint8_t *data, size_t len) { enum { GIF_MASK_TRANSPARENCY = 0x01, GIF_MASK_DISPOSAL = 0x1c, }; /* 6-byte Graphic Control Extension is: * * +0 CHAR Graphic Control Label * +1 CHAR Block Size * +2 CHAR __Packed Fields__ * 3BITS Reserved * 3BITS Disposal Method * 1BIT User Input Flag * 1BIT Transparent Color Flag * +3 SHORT Delay Time * +5 CHAR Transparent Color Index */ if (len < 6) { return NSGIF_ERR_END_OF_DATA; } frame->info.delay = data[3] | (data[4] << 8); if (data[2] & GIF_MASK_TRANSPARENCY) { frame->info.transparency = true; frame->transparency_index = data[5]; } frame->info.disposal = ((data[2] & GIF_MASK_DISPOSAL) >> 2); /* I have encountered documentation and GIFs in the * wild that use 0x04 to restore the previous frame, * rather than the officially documented 0x03. I * believe some (older?) software may even actually * export this way. We handle this as a type of * "quirks" mode. */ if (frame->info.disposal == NSGIF_DISPOSAL_RESTORE_QUIRK) { frame->info.disposal = NSGIF_DISPOSAL_RESTORE_PREV; } /* if we are clearing the background then we need to * redraw enough to cover the previous frame too. */ frame->redraw_required = frame->info.disposal == NSGIF_DISPOSAL_RESTORE_BG || frame->info.disposal == NSGIF_DISPOSAL_RESTORE_PREV; return NSGIF_OK; } /** * Check an app ext identifier and authentication code for loop count extension. * * \param[in] data The data to decode. * \param[in] len Byte length of data. * \return true if extension is a loop count extension. */ static bool nsgif__app_ext_is_loop_count( const uint8_t *data, size_t len) { enum { EXT_LOOP_COUNT_BLOCK_SIZE = 0x0b, }; assert(len > 13); (void)(len); if (data[1] == EXT_LOOP_COUNT_BLOCK_SIZE) { if (strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0 || strncmp((const char *)data + 2, "ANIMEXTS1.0", 11) == 0) { return true; } } return false; } /** * Parse the application extension * * \param[in] gif The gif object we're decoding. * \param[in] data The data to decode. * \param[in] len Byte length of data. * \return NSGIF_ERR_END_OF_DATA if more data is needed, * NSGIF_OK for success. */ static nsgif_error nsgif__parse_extension_application( struct nsgif *gif, const uint8_t *data, size_t len) { /* 14-byte+ Application Extension is: * * +0 CHAR Application Extension Label * +1 CHAR Block Size * +2 8CHARS Application Identifier * +10 3CHARS Appl. Authentication Code * +13 1-256 Application Data (Data sub-blocks) */ if (len < 17) { return NSGIF_ERR_END_OF_DATA; } if (nsgif__app_ext_is_loop_count(data, len)) { enum { EXT_LOOP_COUNT_SUB_BLOCK_SIZE = 0x03, EXT_LOOP_COUNT_SUB_BLOCK_ID = 0x01, }; if ((data[13] == EXT_LOOP_COUNT_SUB_BLOCK_SIZE) && (data[14] == EXT_LOOP_COUNT_SUB_BLOCK_ID)) { gif->info.loop_max = data[15] | (data[16] << 8); /* The value in the source data means repeat N times * after the first implied play. A value of zero has * the special meaning of loop forever. (The only way * to play the animation once is not to have this * extension at all. */ if (gif->info.loop_max > 0) { gif->info.loop_max++; } } } return NSGIF_OK; } /** * Parse the frame's extensions * * \param[in] gif The gif object we're decoding. * \param[in] frame The frame to parse extensions for. * \param[in] pos Current position in data, updated on exit. * \param[in] decode Whether to decode or skip over the extension. * \return NSGIF_ERR_END_OF_DATA if more data is needed, * NSGIF_OK for success. */ static nsgif_error nsgif__parse_frame_extensions( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, bool decode) { enum { GIF_EXT_INTRODUCER = 0x21, GIF_EXT_GRAPHIC_CONTROL = 0xf9, GIF_EXT_COMMENT = 0xfe, GIF_EXT_PLAIN_TEXT = 0x01, GIF_EXT_APPLICATION = 0xff, }; const uint8_t *nsgif_data = *pos; const uint8_t *nsgif_end = gif->buf + gif->buf_len; int nsgif_bytes = nsgif_end - nsgif_data; /* Initialise the extensions */ while (nsgif_bytes > 0 && nsgif_data[0] == GIF_EXT_INTRODUCER) { bool block_step = true; nsgif_error ret; nsgif_data++; nsgif_bytes--; if (nsgif_bytes == 0) { return NSGIF_ERR_END_OF_DATA; } /* Switch on extension label */ switch (nsgif_data[0]) { case GIF_EXT_GRAPHIC_CONTROL: if (decode) { ret = nsgif__parse_extension_graphic_control( frame, nsgif_data, nsgif_bytes); if (ret != NSGIF_OK) { return ret; } } break; case GIF_EXT_APPLICATION: if (decode) { ret = nsgif__parse_extension_application( gif, nsgif_data, nsgif_bytes); if (ret != NSGIF_OK) { return ret; } } break; case GIF_EXT_COMMENT: /* Move the pointer to the first data sub-block Skip 1 * byte for the extension label. */ ++nsgif_data; block_step = false; break; default: break; } if (block_step) { /* Move the pointer to the first data sub-block Skip 2 * bytes for the extension label and size fields Skip * the extension size itself */ if (nsgif_bytes < 2) { return NSGIF_ERR_END_OF_DATA; } nsgif_data += 2 + nsgif_data[1]; } /* Repeatedly skip blocks until we get a zero block or run out * of data. This data is ignored by this gif decoder. */ while (nsgif_data < nsgif_end && nsgif_data[0] != NSGIF_BLOCK_TERMINATOR) { nsgif_data += nsgif_data[0] + 1; if (nsgif_data >= nsgif_end) { return NSGIF_ERR_END_OF_DATA; } } nsgif_data++; nsgif_bytes = nsgif_end - nsgif_data; } if (nsgif_data > nsgif_end) { nsgif_data = nsgif_end; } /* Set buffer position and return */ *pos = nsgif_data; return NSGIF_OK; } /** * Parse a GIF Image Descriptor. * * The format is: * * +0 CHAR Image Separator (0x2c) * +1 SHORT Image Left Position * +3 SHORT Image Top Position * +5 SHORT Width * +7 SHORT Height * +9 CHAR __Packed Fields__ * 1BIT Local Colour Table Flag * 1BIT Interlace Flag * 1BIT Sort Flag * 2BITS Reserved * 3BITS Size of Local Colour Table * * \param[in] gif The gif object we're decoding. * \param[in] frame The frame to parse an image descriptor for. * \param[in] pos Current position in data, updated on exit. * \param[in] decode Whether to decode the image descriptor. * \return NSGIF_OK on success, appropriate error otherwise. */ static nsgif_error nsgif__parse_image_descriptor( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, bool decode) { const uint8_t *data = *pos; size_t len = gif->buf + gif->buf_len - data; enum { NSGIF_IMAGE_DESCRIPTOR_LEN = 10u, NSGIF_IMAGE_SEPARATOR = 0x2Cu, NSGIF_MASK_INTERLACE = 0x40u, }; assert(gif != NULL); assert(frame != NULL); if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) { return NSGIF_ERR_END_OF_DATA; } if (decode) { uint32_t x, y, w, h; if (data[0] != NSGIF_IMAGE_SEPARATOR) { return NSGIF_ERR_DATA_FRAME; } x = data[1] | (data[2] << 8); y = data[3] | (data[4] << 8); w = data[5] | (data[6] << 8); h = data[7] | (data[8] << 8); frame->flags = data[9]; frame->info.rect.x0 = x; frame->info.rect.y0 = y; frame->info.rect.x1 = x + w; frame->info.rect.y1 = y + h; frame->info.interlaced = frame->flags & NSGIF_MASK_INTERLACE; /* Allow first frame to grow image dimensions. */ if (gif->info.frame_count == 0) { if (x + w > gif->info.width) { gif->info.width = x + w; } if (y + h > gif->info.height) { gif->info.height = y + h; } } } *pos += NSGIF_IMAGE_DESCRIPTOR_LEN; return NSGIF_OK; } /** * Extract a GIF colour table into a LibNSGIF colour table buffer. * * \param[in] colour_table The colour table to populate. * \param[in] layout la. * \param[in] colour_table_entries The number of colour table entries. * \param[in] data Raw colour table data. */ static void nsgif__colour_table_decode( uint32_t colour_table[NSGIF_MAX_COLOURS], const struct nsgif_colour_layout *layout, size_t colour_table_entries, const uint8_t *data) { uint8_t *entry = (uint8_t *)colour_table; while (colour_table_entries--) { /* Gif colour map contents are r,g,b. * * We want to pack them bytewise into the colour table, * according to the client colour layout. */ entry[layout->r] = *data++; entry[layout->g] = *data++; entry[layout->b] = *data++; entry[layout->a] = 0xff; entry += sizeof(uint32_t); } } /** * Extract a GIF colour table into a LibNSGIF colour table buffer. * * \param[in] colour_table The colour table to populate. * \param[in] layout The target pixel format to decode to. * \param[in] colour_table_entries The number of colour table entries. * \param[in] data Current position in data. * \param[in] data_len The available length of `data`. * \param[out] used Number of colour table bytes read. * \param[in] decode Whether to decode the colour table. * \return NSGIF_OK on success, appropriate error otherwise. */ static inline nsgif_error nsgif__colour_table_extract( uint32_t colour_table[NSGIF_MAX_COLOURS], const struct nsgif_colour_layout *layout, size_t colour_table_entries, const uint8_t *data, size_t data_len, size_t *used, bool decode) { if (data_len < colour_table_entries * 3) { return NSGIF_ERR_END_OF_DATA; } if (decode) { nsgif__colour_table_decode(colour_table, layout, colour_table_entries, data); } *used = colour_table_entries * 3; return NSGIF_OK; } /** * Get a frame's colour table. * * Sets up gif->colour_table for the frame. * * \param[in] gif The gif object we're decoding. * \param[in] frame The frame to get the colour table for. * \param[in] pos Current position in data, updated on exit. * \param[in] decode Whether to decode the colour table. * \return NSGIF_OK on success, appropriate error otherwise. */ static nsgif_error nsgif__parse_colour_table( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, bool decode) { nsgif_error ret; const uint8_t *data = *pos; size_t len = gif->buf + gif->buf_len - data; size_t used_bytes; assert(gif != NULL); assert(frame != NULL); if ((frame->flags & NSGIF_COLOUR_TABLE_MASK) == 0) { gif->colour_table = gif->global_colour_table; return NSGIF_OK; } if (decode == false) { frame->colour_table_offset = *pos - gif->buf; } ret = nsgif__colour_table_extract( gif->local_colour_table, &gif->colour_layout, 2 << (frame->flags & NSGIF_COLOUR_TABLE_SIZE_MASK), data, len, &used_bytes, decode); if (ret != NSGIF_OK) { return ret; } *pos += used_bytes; if (decode) { gif->colour_table = gif->local_colour_table; } else { frame->info.local_palette = true; } return NSGIF_OK; } /** * Parse the image data for a gif frame. * * Sets up gif->colour_table for the frame. * * \param[in] gif The gif object we're decoding. * \param[in] frame The frame to parse image data for. * \param[in] pos Current position in data, updated on exit. * \param[in] decode Whether to decode the image data. * \return NSGIF_OK on success, appropriate error otherwise. */ static nsgif_error nsgif__parse_image_data( struct nsgif *gif, struct nsgif_frame *frame, const uint8_t **pos, bool decode) { const uint8_t *data = *pos; size_t len = gif->buf + gif->buf_len - data; uint32_t frame_idx = frame - gif->frames; uint8_t minimum_code_size; nsgif_error ret; assert(gif != NULL); assert(frame != NULL); if (!decode) { gif->frame_count_partial = frame_idx + 1; } /* Ensure sufficient data remains. A gif trailer or a minimum lzw code * followed by a gif trailer is treated as OK, although without any * image data. */ switch (len) { default: if (data[0] == NSGIF_TRAILER) return NSGIF_OK; break; case 2: if (data[1] == NSGIF_TRAILER) return NSGIF_OK; /* Fall through. */ case 1: if (data[0] == NSGIF_TRAILER) return NSGIF_OK; /* Fall through. */ case 0: return NSGIF_ERR_END_OF_DATA; } minimum_code_size = data[0]; if (minimum_code_size >= LZW_CODE_MAX) { return NSGIF_ERR_DATA_FRAME; } if (decode) { ret = nsgif__update_bitmap(gif, frame, data, frame_idx); } else { uint32_t block_size = 0; /* Skip the minimum code size. */ data++; len--; while (block_size != 1) { if (len < 1) { return NSGIF_ERR_END_OF_DATA; } block_size = data[0] + 1; /* Check if the frame data runs off the end of the file */ if (block_size > len) { frame->lzw_data_length += len; return NSGIF_ERR_END_OF_DATA; } len -= block_size; data += block_size; frame->lzw_data_length += block_size; } *pos = data; gif->info.frame_count = frame_idx + 1; gif->frames[frame_idx].info.display = true; return NSGIF_OK; } return ret; } static struct nsgif_frame *nsgif__get_frame( struct nsgif *gif, uint32_t frame_idx) { struct nsgif_frame *frame; if (gif->frame_holders > frame_idx) { frame = &gif->frames[frame_idx]; } else { /* Allocate more memory */ size_t count = frame_idx + 1; struct nsgif_frame *temp; temp = realloc(gif->frames, count * sizeof(*frame)); if (temp == NULL) { return NULL; } gif->frames = temp; gif->frame_holders = count; frame = &gif->frames[frame_idx]; frame->info.local_palette = false; frame->info.transparency = false; frame->info.display = false; frame->info.disposal = 0; frame->info.delay = 10; frame->transparency_index = NSGIF_NO_TRANSPARENCY; frame->frame_offset = gif->buf_pos; frame->redraw_required = false; frame->lzw_data_length = 0; frame->decoded = false; } return frame; } /** * Attempts to initialise the next frame * * \param[in] gif The animation context * \param[in] frame_idx The frame number to decode. * \param[in] decode Whether to decode the graphical image data. * \return NSGIF_OK on success, appropriate error otherwise. */ static nsgif_error nsgif__process_frame( struct nsgif *gif, uint32_t frame_idx, bool decode) { nsgif_error ret; const uint8_t *pos; const uint8_t *end; struct nsgif_frame *frame; frame = nsgif__get_frame(gif, frame_idx); if (frame == NULL) { return NSGIF_ERR_OOM; } end = gif->buf + gif->buf_len; if (decode) { pos = gif->buf + frame->frame_offset; /* Ensure this frame is supposed to be decoded */ if (frame->info.display == false) { return NSGIF_OK; } /* Ensure the frame is in range to decode */ if (frame_idx > gif->frame_count_partial) { return NSGIF_ERR_END_OF_DATA; } /* Done if frame is already decoded */ if (frame_idx == gif->decoded_frame) { return NSGIF_OK; } } else { pos = gif->buf + gif->buf_pos; /* Check if we've finished */ if (pos < end && pos[0] == NSGIF_TRAILER) { return NSGIF_OK; } } ret = nsgif__parse_frame_extensions(gif, frame, &pos, !decode); if (ret != NSGIF_OK) { goto cleanup; } ret = nsgif__parse_image_descriptor(gif, frame, &pos, !decode); if (ret != NSGIF_OK) { goto cleanup; } ret = nsgif__parse_colour_table(gif, frame, &pos, decode); if (ret != NSGIF_OK) { goto cleanup; } ret = nsgif__parse_image_data(gif, frame, &pos, decode); if (ret != NSGIF_OK) { goto cleanup; } cleanup: if (!decode) { gif->buf_pos = pos - gif->buf; } return ret; } /* exported function documented in nsgif.h */ void nsgif_destroy(nsgif_t *gif) { if (gif == NULL) { return; } /* Release all our memory blocks */ if (gif->frame_image) { assert(gif->bitmap.destroy); gif->bitmap.destroy(gif->frame_image); gif->frame_image = NULL; } free(gif->frames); gif->frames = NULL; free(gif->prev_frame); gif->prev_frame = NULL; lzw_context_destroy(gif->lzw_ctx); gif->lzw_ctx = NULL; free(gif); } /** * Check whether the host is little endian. * * Checks whether least significant bit is in the first byte of a `uint16_t`. * * \return true if host is little endian. */ static inline bool nsgif__host_is_little_endian(void) { const uint16_t test = 1; return ((const uint8_t *) &test)[0]; } static struct nsgif_colour_layout nsgif__bitmap_fmt_to_colour_layout( nsgif_bitmap_fmt_t bitmap_fmt) { bool le = nsgif__host_is_little_endian(); /* Map endian-dependant formats to byte-wise format for the host. */ switch (bitmap_fmt) { case NSGIF_BITMAP_FMT_RGBA8888: bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_A8B8G8R8 : NSGIF_BITMAP_FMT_R8G8B8A8; break; case NSGIF_BITMAP_FMT_BGRA8888: bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_A8R8G8B8 : NSGIF_BITMAP_FMT_B8G8R8A8; break; case NSGIF_BITMAP_FMT_ARGB8888: bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_B8G8R8A8 : NSGIF_BITMAP_FMT_A8R8G8B8; break; case NSGIF_BITMAP_FMT_ABGR8888: bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_R8G8B8A8 : NSGIF_BITMAP_FMT_A8B8G8R8; break; default: break; } /* Set up colour component order for bitmap format. */ switch (bitmap_fmt) { default: /* Fall through. */ case NSGIF_BITMAP_FMT_R8G8B8A8: return (struct nsgif_colour_layout) { .r = 0, .g = 1, .b = 2, .a = 3, }; case NSGIF_BITMAP_FMT_B8G8R8A8: return (struct nsgif_colour_layout) { .b = 0, .g = 1, .r = 2, .a = 3, }; case NSGIF_BITMAP_FMT_A8R8G8B8: return (struct nsgif_colour_layout) { .a = 0, .r = 1, .g = 2, .b = 3, }; case NSGIF_BITMAP_FMT_A8B8G8R8: return (struct nsgif_colour_layout) { .a = 0, .b = 1, .g = 2, .r = 3, }; } } /* exported function documented in nsgif.h */ nsgif_error nsgif_create( const nsgif_bitmap_cb_vt *bitmap_vt, nsgif_bitmap_fmt_t bitmap_fmt, nsgif_t **gif_out) { nsgif_t *gif; gif = calloc(1, sizeof(*gif)); if (gif == NULL) { return NSGIF_ERR_OOM; } gif->bitmap = *bitmap_vt; gif->decoded_frame = NSGIF_FRAME_INVALID; gif->prev_index = NSGIF_FRAME_INVALID; gif->delay_min = NSGIF_FRAME_DELAY_MIN; gif->delay_default = NSGIF_FRAME_DELAY_DEFAULT; gif->colour_layout = nsgif__bitmap_fmt_to_colour_layout(bitmap_fmt); *gif_out = gif; return NSGIF_OK; } /* exported function documented in nsgif.h */ void nsgif_set_frame_delay_behaviour( nsgif_t *gif, uint16_t delay_min, uint16_t delay_default) { gif->delay_min = delay_min; gif->delay_default = delay_default; } /** * Read GIF header. * * 6-byte GIF file header is: * * +0 3CHARS Signature ('GIF') * +3 3CHARS Version ('87a' or '89a') * * \param[in] gif The GIF object we're decoding. * \param[in,out] pos The current buffer position, updated on success. * \param[in] strict Whether to require a known GIF version. * \return NSGIF_OK on success, appropriate error otherwise. */ static nsgif_error nsgif__parse_header( struct nsgif *gif, const uint8_t **pos, bool strict) { const uint8_t *data = *pos; size_t len = gif->buf + gif->buf_len - data; if (len < 6) { return NSGIF_ERR_END_OF_DATA; } if (strncmp((const char *) data, "GIF", 3) != 0) { return NSGIF_ERR_DATA; } data += 3; if (strict == true) { if ((strncmp((const char *) data, "87a", 3) != 0) && (strncmp((const char *) data, "89a", 3) != 0)) { return NSGIF_ERR_DATA; } } data += 3; *pos = data; return NSGIF_OK; } /** * Read Logical Screen Descriptor. * * 7-byte Logical Screen Descriptor is: * * +0 SHORT Logical Screen Width * +2 SHORT Logical Screen Height * +4 CHAR __Packed Fields__ * 1BIT Global Colour Table Flag * 3BITS Colour Resolution * 1BIT Sort Flag * 3BITS Size of Global Colour Table * +5 CHAR Background Colour Index * +6 CHAR Pixel Aspect Ratio * * \param[in] gif The GIF object we're decoding. * \param[in,out] pos The current buffer position, updated on success. * \return NSGIF_OK on success, appropriate error otherwise. */ static nsgif_error nsgif__parse_logical_screen_descriptor( struct nsgif *gif, const uint8_t **pos) { const uint8_t *data = *pos; size_t len = gif->buf + gif->buf_len - data; if (len < 7) { return NSGIF_ERR_END_OF_DATA; } gif->info.width = data[0] | (data[1] << 8); gif->info.height = data[2] | (data[3] << 8); gif->info.global_palette = data[4] & NSGIF_COLOUR_TABLE_MASK; gif->colour_table_size = 2 << (data[4] & NSGIF_COLOUR_TABLE_SIZE_MASK); gif->bg_index = data[5]; gif->aspect_ratio = data[6]; gif->info.loop_max = 1; *pos += 7; return NSGIF_OK; } /* exported function documented in nsgif.h */ nsgif_error nsgif_data_scan( nsgif_t *gif, size_t size, const uint8_t *data) { const uint8_t *nsgif_data; nsgif_error ret; uint32_t frames; if (gif->data_complete) { return NSGIF_ERR_DATA_COMPLETE; } /* Initialize values */ gif->buf_len = size; gif->buf = data; /* Get our current processing position */ nsgif_data = gif->buf + gif->buf_pos; /* See if we should initialise the GIF */ if (gif->buf_pos == 0) { /* We want everything to be NULL before we start so we've no * chance of freeing bad pointers (paranoia) */ gif->frame_image = NULL; gif->frames = NULL; gif->frame_holders = 0; /* The caller may have been lazy and not reset any values */ gif->info.frame_count = 0; gif->frame_count_partial = 0; gif->decoded_frame = NSGIF_FRAME_INVALID; gif->frame = NSGIF_FRAME_INVALID; ret = nsgif__parse_header(gif, &nsgif_data, false); if (ret != NSGIF_OK) { return ret; } ret = nsgif__parse_logical_screen_descriptor(gif, &nsgif_data); if (ret != NSGIF_OK) { return ret; } /* Remember we've done this now */ gif->buf_pos = nsgif_data - gif->buf; /* Some broken GIFs report the size as the screen size they * were created in. As such, we detect for the common cases and * set the sizes as 0 if they are found which results in the * GIF being the maximum size of the frames. */ if (((gif->info.width == 640) && (gif->info.height == 480)) || ((gif->info.width == 640) && (gif->info.height == 512)) || ((gif->info.width == 800) && (gif->info.height == 600)) || ((gif->info.width == 1024) && (gif->info.height == 768)) || ((gif->info.width == 1280) && (gif->info.height == 1024)) || ((gif->info.width == 1600) && (gif->info.height == 1200)) || ((gif->info.width == 0) || (gif->info.height == 0)) || ((gif->info.width > 2048) || (gif->info.height > 2048))) { gif->info.width = 1; gif->info.height = 1; } /* Set the first colour to a value that will never occur in * reality so we know if we've processed it */ gif->global_colour_table[0] = NSGIF_PROCESS_COLOURS; /* Check if the GIF has no frame data (13-byte header + 1-byte * termination block) Although generally useless, the GIF * specification does not expressly prohibit this */ if (gif->buf_len == gif->buf_pos + 1) { if (nsgif_data[0] == NSGIF_TRAILER) { return NSGIF_OK; } } } /* Do the colour map if we haven't already. As the top byte is always * 0xff or 0x00 depending on the transparency we know if it's been * filled in. */ if (gif->global_colour_table[0] == NSGIF_PROCESS_COLOURS) { /* Check for a global colour map signified by bit 7 */ if (gif->info.global_palette) { size_t remaining = gif->buf + gif->buf_len - nsgif_data; size_t used; ret = nsgif__colour_table_extract( gif->global_colour_table, &gif->colour_layout, gif->colour_table_size, nsgif_data, remaining, &used, true); if (ret != NSGIF_OK) { return ret; } nsgif_data += used; gif->buf_pos = (nsgif_data - gif->buf); } else { /* Create a default colour table with the first two * colours as black and white. */ uint8_t *entry = (uint8_t *)gif->global_colour_table; /* Black */ entry[gif->colour_layout.r] = 0x00; entry[gif->colour_layout.g] = 0x00; entry[gif->colour_layout.b] = 0x00; entry[gif->colour_layout.a] = 0xFF; entry += sizeof(uint32_t); /* White */ entry[gif->colour_layout.r] = 0xFF; entry[gif->colour_layout.g] = 0xFF; entry[gif->colour_layout.b] = 0xFF; entry[gif->colour_layout.a] = 0xFF; gif->colour_table_size = 2; } if (gif->info.global_palette && gif->bg_index < gif->colour_table_size) { size_t bg_idx = gif->bg_index; gif->info.background = gif->global_colour_table[bg_idx]; } else { gif->info.background = gif->global_colour_table[0]; } } if (gif->lzw_ctx == NULL) { lzw_result res = lzw_context_create( (struct lzw_ctx **)&gif->lzw_ctx); if (res != LZW_OK) { return nsgif__error_from_lzw(res); } } /* Try to initialise all frames. */ do { frames = gif->info.frame_count; ret = nsgif__process_frame(gif, frames, false); } while (gif->info.frame_count > frames); if (ret == NSGIF_ERR_END_OF_DATA && gif->info.frame_count > 0) { ret = NSGIF_OK; } return ret; } /* exported function documented in nsgif.h */ void nsgif_data_complete( nsgif_t *gif) { if (gif->data_complete == false) { uint32_t start = gif->info.frame_count; uint32_t end = gif->frame_count_partial; for (uint32_t f = start; f < end; f++) { nsgif_frame *frame = &gif->frames[f]; if (frame->lzw_data_length > 0) { frame->info.display = true; gif->info.frame_count = f + 1; if (f == 0) { frame->info.transparency = true; } break; } } } gif->data_complete = true; } static void nsgif__redraw_rect_extend( const nsgif_rect_t *frame, nsgif_rect_t *redraw) { if (redraw->x1 == 0 || redraw->y1 == 0) { *redraw = *frame; } else { if (redraw->x0 > frame->x0) { redraw->x0 = frame->x0; } if (redraw->x1 < frame->x1) { redraw->x1 = frame->x1; } if (redraw->y0 > frame->y0) { redraw->y0 = frame->y0; } if (redraw->y1 < frame->y1) { redraw->y1 = frame->y1; } } } static uint32_t nsgif__frame_next( const nsgif_t *gif, bool partial, uint32_t frame) { uint32_t frames = partial ? gif->frame_count_partial : gif->info.frame_count; if (frames == 0) { return NSGIF_FRAME_INVALID; } frame++; return (frame >= frames) ? 0 : frame; } static nsgif_error nsgif__next_displayable_frame( const nsgif_t *gif, uint32_t *frame, uint32_t *delay) { uint32_t next = *frame; do { next = nsgif__frame_next(gif, false, next); if (next <= *frame && *frame != NSGIF_FRAME_INVALID && gif->data_complete == false) { return NSGIF_ERR_END_OF_DATA; } else if (next == *frame || next == NSGIF_FRAME_INVALID) { return NSGIF_ERR_FRAME_DISPLAY; } if (delay != NULL) { *delay += gif->frames[next].info.delay; } } while (gif->frames[next].info.display == false); *frame = next; return NSGIF_OK; } static inline bool nsgif__animation_complete(int count, int max) { if (max == 0) { return false; } return (count >= max); } nsgif_error nsgif_reset( nsgif_t *gif) { gif->loop_count = 0; gif->frame = NSGIF_FRAME_INVALID; return NSGIF_OK; } /* exported function documented in nsgif.h */ nsgif_error nsgif_frame_prepare( nsgif_t *gif, nsgif_rect_t *area, uint32_t *delay_cs, uint32_t *frame_new) { nsgif_error ret; nsgif_rect_t rect = { .x1 = 0, .y1 = 0, }; uint32_t delay = 0; uint32_t frame = gif->frame; if (gif->frame != NSGIF_FRAME_INVALID && gif->frame < gif->info.frame_count && gif->frames[gif->frame].info.display) { rect = gif->frames[gif->frame].info.rect; } if (nsgif__animation_complete( gif->loop_count, gif->info.loop_max)) { return NSGIF_ERR_ANIMATION_END; } ret = nsgif__next_displayable_frame(gif, &frame, &delay); if (ret != NSGIF_OK) { return ret; } if (gif->frame != NSGIF_FRAME_INVALID && frame < gif->frame) { gif->loop_count++; } if (gif->data_complete) { /* Check for last frame, which has infinite delay. */ if (gif->info.frame_count == 1) { delay = NSGIF_INFINITE; } else if (gif->info.loop_max != 0) { uint32_t frame_next = frame; ret = nsgif__next_displayable_frame(gif, &frame_next, NULL); if (ret != NSGIF_OK) { return ret; } if (gif->data_complete && frame_next < frame) { if (nsgif__animation_complete( gif->loop_count + 1, gif->info.loop_max)) { delay = NSGIF_INFINITE; } } } } gif->frame = frame; nsgif__redraw_rect_extend(&gif->frames[frame].info.rect, &rect); if (delay < gif->delay_min) { delay = gif->delay_default; } *frame_new = gif->frame; *delay_cs = delay; *area = rect; return NSGIF_OK; } /* exported function documented in nsgif.h */ nsgif_error nsgif_frame_decode( nsgif_t *gif, uint32_t frame, nsgif_bitmap_t **bitmap) { uint32_t start_frame; nsgif_error ret = NSGIF_OK; if (frame >= gif->info.frame_count) { return NSGIF_ERR_BAD_FRAME; } if (gif->decoded_frame == frame) { *bitmap = gif->frame_image; return NSGIF_OK; } else if (gif->decoded_frame >= frame || gif->decoded_frame == NSGIF_FRAME_INVALID) { /* Can skip to first frame or restart. */ start_frame = 0; } else { start_frame = nsgif__frame_next( gif, false, gif->decoded_frame); } for (uint32_t f = start_frame; f <= frame; f++) { ret = nsgif__process_frame(gif, f, true); if (ret != NSGIF_OK) { return ret; } } *bitmap = gif->frame_image; return ret; } /* exported function documented in nsgif.h */ const nsgif_info_t *nsgif_get_info(const nsgif_t *gif) { return &gif->info; } /* exported function documented in nsgif.h */ const nsgif_frame_info_t *nsgif_get_frame_info( const nsgif_t *gif, uint32_t frame) { if (frame >= gif->info.frame_count) { return NULL; } return &gif->frames[frame].info; } /* exported function documented in nsgif.h */ void nsgif_global_palette( const nsgif_t *gif, uint32_t table[NSGIF_MAX_COLOURS], size_t *entries) { size_t len = sizeof(*table) * NSGIF_MAX_COLOURS; memcpy(table, gif->global_colour_table, len); *entries = gif->colour_table_size; } /* exported function documented in nsgif.h */ bool nsgif_local_palette( const nsgif_t *gif, uint32_t frame, uint32_t table[NSGIF_MAX_COLOURS], size_t *entries) { const nsgif_frame *f; if (frame >= gif->frame_count_partial) { return false; } f = &gif->frames[frame]; if (f->info.local_palette == false) { return false; } *entries = 2 << (f->flags & NSGIF_COLOUR_TABLE_SIZE_MASK); nsgif__colour_table_decode(table, &gif->colour_layout, *entries, gif->buf + f->colour_table_offset); return true; } /* exported function documented in nsgif.h */ const char *nsgif_strerror(nsgif_error err) { static const char *const str[] = { [NSGIF_OK] = "Success", [NSGIF_ERR_OOM] = "Out of memory", [NSGIF_ERR_DATA] = "Invalid source data", [NSGIF_ERR_BAD_FRAME] = "Requested frame does not exist", [NSGIF_ERR_DATA_FRAME] = "Invalid frame data", [NSGIF_ERR_END_OF_DATA] = "Unexpected end of GIF source data", [NSGIF_ERR_DATA_COMPLETE] = "Can't add data to completed GIF", [NSGIF_ERR_FRAME_DISPLAY] = "Frame can't be displayed", [NSGIF_ERR_ANIMATION_END] = "Animation complete", }; if (err >= NSGIF_ARRAY_LEN(str) || str[err] == NULL) { return "Unknown error"; } return str[err]; } /* exported function documented in nsgif.h */ const char *nsgif_str_disposal(enum nsgif_disposal disposal) { static const char *const str[] = { [NSGIF_DISPOSAL_UNSPECIFIED] = "Unspecified", [NSGIF_DISPOSAL_NONE] = "None", [NSGIF_DISPOSAL_RESTORE_BG] = "Restore background", [NSGIF_DISPOSAL_RESTORE_PREV] = "Restore previous", [NSGIF_DISPOSAL_RESTORE_QUIRK] = "Restore quirk", }; if (disposal >= NSGIF_ARRAY_LEN(str) || str[disposal] == NULL) { return "Unspecified"; } return str[disposal]; } libvips-8.18.2/libvips/foreign/libnsgif/lzw.c000066400000000000000000000405071516303661500211540ustar00rootroot00000000000000/* * This file is part of NetSurf's LibNSGIF, http://www.netsurf-browser.org/ * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * * Copyright 2017 Michael Drake * Copyright 2021 Michael Drake */ #include #include #include #include #include "lzw.h" /** * \file * \brief LZW decompression (implementation) * * Decoder for GIF LZW data. */ /** Maximum number of lzw table entries. */ #define LZW_TABLE_ENTRY_MAX (1u << LZW_CODE_MAX) /** * Context for reading LZW data. * * LZW data is split over multiple sub-blocks. Each sub-block has a * byte at the start, which says the sub-block size, and then the data. * Zero-size sub-blocks have no data, and the biggest sub-block size is * 255, which means there are 255 bytes of data following the sub-block * size entry. * * Note that an individual LZW code can be split over up to three sub-blocks. */ struct lzw_read_ctx { const uint8_t *restrict data; /**< Pointer to start of input data */ size_t data_len; /**< Input data length */ size_t data_sb_next; /**< Offset to sub-block size */ const uint8_t *sb_data; /**< Pointer to current sub-block in data */ size_t sb_bit; /**< Current bit offset in sub-block */ uint32_t sb_bit_count; /**< Bit count in sub-block */ }; /** * LZW table entry. * * Records in the table are composed of 1 or more entries. * Entries refer to the entry they extend which can be followed to compose * the complete record. To compose the record in reverse order, take * the `value` from each entry, and move to the entry it extends. * If the extended entries index is < the current clear_code, then it * is the last entry in the record. */ struct lzw_table_entry { uint8_t value; /**< Last value for record ending at entry. */ uint8_t first; /**< First value in entry's entire record. */ uint16_t count; /**< Count of values in this entry's record. */ uint16_t extends; /**< Offset in table to previous entry. */ }; /** * LZW decompression context. */ struct lzw_ctx { struct lzw_read_ctx input; /**< Input reading context */ uint16_t prev_code; /**< Code read from input previously. */ uint16_t prev_code_first; /**< First value of previous code. */ uint16_t prev_code_count; /**< Total values for previous code. */ uint8_t initial_code_size; /**< Starting LZW code size. */ uint8_t code_size; /**< Current LZW code size. */ uint16_t code_max; /**< Max code value for current code size. */ uint16_t clear_code; /**< Special Clear code value */ uint16_t eoi_code; /**< Special End of Information code value */ uint16_t table_size; /**< Next position in table to fill. */ uint16_t output_code; /**< Code that has been partially output. */ uint16_t output_left; /**< Number of values left for output_code. */ bool has_transparency; /**< Whether the image is opaque. */ uint8_t transparency_idx; /**< Index representing transparency. */ const uint32_t *restrict colour_map; /**< Index to colour mapping. */ /** LZW code table. Generated during decode. */ struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX]; /** Output value stack. */ uint8_t stack_base[LZW_TABLE_ENTRY_MAX]; }; /* Exported function, documented in lzw.h */ lzw_result lzw_context_create(struct lzw_ctx **ctx) { struct lzw_ctx *c = malloc(sizeof(*c)); if (c == NULL) { return LZW_NO_MEM; } *ctx = c; return LZW_OK; } /* Exported function, documented in lzw.h */ void lzw_context_destroy(struct lzw_ctx *ctx) { free(ctx); } /** * Advance the context to the next sub-block in the input data. * * \param[in] ctx LZW reading context, updated on success. * \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise. */ static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx) { size_t block_size; size_t next_block_pos = ctx->data_sb_next; const uint8_t *data_next = ctx->data + next_block_pos; if (next_block_pos >= ctx->data_len) { return LZW_NO_DATA; } block_size = *data_next; if ((next_block_pos + block_size) >= ctx->data_len) { return LZW_NO_DATA; } ctx->sb_bit = 0; ctx->sb_bit_count = block_size * 8; if (block_size == 0) { ctx->data_sb_next += 1; return LZW_OK_EOD; } ctx->sb_data = data_next + 1; ctx->data_sb_next += block_size + 1; return LZW_OK; } /** * Get the next LZW code of given size from the raw input data. * * Reads codes from the input data stream coping with GIF data sub-blocks. * * \param[in] ctx LZW reading context, updated. * \param[in] code_size Size of LZW code to get from data. * \param[out] code_out Returns an LZW code on success. * \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise. */ static inline lzw_result lzw__read_code( struct lzw_read_ctx *restrict ctx, uint16_t code_size, uint16_t *restrict code_out) { uint32_t code = 0; uint32_t current_bit = ctx->sb_bit & 0x7; if (ctx->sb_bit + 24 <= ctx->sb_bit_count) { /* Fast path: read three bytes from this sub-block */ const uint8_t *data = ctx->sb_data + (ctx->sb_bit >> 3); code |= *data++ << 0; code |= *data++ << 8; code |= *data << 16; ctx->sb_bit += code_size; } else { /* Slow path: code spans sub-blocks */ uint8_t byte_advance = (current_bit + code_size) >> 3; uint8_t byte = 0; uint8_t bits_remaining_0 = (code_size < (8u - current_bit)) ? code_size : (8u - current_bit); uint8_t bits_remaining_1 = code_size - bits_remaining_0; uint8_t bits_used[3] = { [0] = bits_remaining_0, [1] = bits_remaining_1 < 8 ? bits_remaining_1 : 8, [2] = bits_remaining_1 - 8, }; assert(byte_advance <= 2); while (true) { const uint8_t *data = ctx->sb_data; lzw_result res; /* Get any data from end of this sub-block */ while (byte <= byte_advance && ctx->sb_bit < ctx->sb_bit_count) { code |= data[ctx->sb_bit >> 3] << (byte << 3); ctx->sb_bit += bits_used[byte]; byte++; } /* Check if we have all we need */ if (byte > byte_advance) { break; } /* Move to next sub-block */ res = lzw__block_advance(ctx); if (res != LZW_OK) { return res; } } } *code_out = (code >> current_bit) & ((1 << code_size) - 1); return LZW_OK; } /** * Handle clear code. * * \param[in] ctx LZW reading context, updated. * \param[out] code_out Returns next code after a clear code. * \return LZW_OK or error code. */ static inline lzw_result lzw__handle_clear( struct lzw_ctx *ctx, uint16_t *code_out) { uint16_t code; /* Reset table building context */ ctx->code_size = ctx->initial_code_size; ctx->code_max = (1 << ctx->initial_code_size) - 1; ctx->table_size = ctx->eoi_code + 1; /* There might be a sequence of clear codes, so process them all */ do { lzw_result res = lzw__read_code(&ctx->input, ctx->code_size, &code); if (res != LZW_OK) { return res; } } while (code == ctx->clear_code); /* The initial code must be from the initial table. */ if (code > ctx->clear_code) { return LZW_BAD_ICODE; } *code_out = code; return LZW_OK; } /* Exported function, documented in lzw.h */ lzw_result lzw_decode_init( struct lzw_ctx *ctx, uint8_t minimum_code_size, const uint8_t *input_data, size_t input_length, size_t input_pos) { struct lzw_table_entry *table = ctx->table; lzw_result res; uint16_t code; if (minimum_code_size >= LZW_CODE_MAX) { return LZW_BAD_ICODE; } /* Initialise the input reading context */ ctx->input.data = input_data; ctx->input.data_len = input_length; ctx->input.data_sb_next = input_pos; ctx->input.sb_bit = 0; ctx->input.sb_bit_count = 0; /* Initialise the table building context */ ctx->initial_code_size = minimum_code_size + 1; ctx->clear_code = (1 << minimum_code_size) + 0; ctx->eoi_code = (1 << minimum_code_size) + 1; ctx->output_left = 0; /* Initialise the standard table entries */ for (uint16_t i = 0; i < ctx->clear_code; i++) { table[i].first = i; table[i].value = i; table[i].count = 1; } res = lzw__handle_clear(ctx, &code); if (res != LZW_OK) { return res; } /* Store details of this code as "previous code" to the context. */ ctx->prev_code_first = ctx->table[code].first; ctx->prev_code_count = ctx->table[code].count; ctx->prev_code = code; /* Add code to context for immediate output. */ ctx->output_code = code; ctx->output_left = 1; ctx->has_transparency = false; ctx->transparency_idx = 0; ctx->colour_map = NULL; return LZW_OK; } /* Exported function, documented in lzw.h */ lzw_result lzw_decode_init_map( struct lzw_ctx *ctx, uint8_t minimum_code_size, uint32_t transparency_idx, const uint32_t *colour_table, const uint8_t *input_data, size_t input_length, size_t input_pos) { lzw_result res; if (colour_table == NULL) { return LZW_BAD_PARAM; } res = lzw_decode_init(ctx, minimum_code_size, input_data, input_length, input_pos); if (res != LZW_OK) { return res; } ctx->has_transparency = (transparency_idx <= 0xFF); ctx->transparency_idx = transparency_idx; ctx->colour_map = colour_table; return LZW_OK; } /** * Create new table entry. * * \param[in] ctx LZW reading context, updated. * \param[in] code Last value code for new table entry. */ static inline void lzw__table_add_entry( struct lzw_ctx *ctx, uint16_t code) { struct lzw_table_entry *entry = &ctx->table[ctx->table_size]; entry->value = code; entry->first = ctx->prev_code_first; entry->count = ctx->prev_code_count + 1; entry->extends = ctx->prev_code; ctx->table_size++; } typedef uint32_t (*lzw_writer_fn)( struct lzw_ctx *ctx, void *restrict output_data, uint32_t output_length, uint32_t output_pos, uint16_t code, uint16_t left); /** * Get the next LZW code and write its value(s) to output buffer. * * \param[in] ctx LZW reading context, updated. * \param[in] write_fn Function for writing pixels to output. * \param[in] output_data Array to write output values into. * \param[in] output_length Size of output array. * \param[in,out] output_written Number of values written. Updated on exit. * \return LZW_OK on success, or appropriate error code otherwise. */ static inline lzw_result lzw__decode( struct lzw_ctx *ctx, lzw_writer_fn write_fn, void *restrict output_data, uint32_t output_length, uint32_t *restrict output_written) { lzw_result res; uint16_t code; /* Get a new code from the input */ res = lzw__read_code(&ctx->input, ctx->code_size, &code); if (res != LZW_OK) { return res; } /* Handle the new code */ if (code == ctx->eoi_code) { /* Got End of Information code */ return LZW_EOI_CODE; } else if (code > ctx->table_size) { /* Code is invalid */ return LZW_BAD_CODE; } else if (code == ctx->clear_code) { res = lzw__handle_clear(ctx, &code); if (res != LZW_OK) { return res; } } else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) { uint16_t size = ctx->table_size; lzw__table_add_entry(ctx, (code < size) ? ctx->table[code].first : ctx->prev_code_first); /* Ensure code size is increased, if needed. */ if (size == ctx->code_max && ctx->code_size < LZW_CODE_MAX) { ctx->code_size++; ctx->code_max = (1 << ctx->code_size) - 1; } } *output_written += write_fn(ctx, output_data, output_length, *output_written, code, ctx->table[code].count); /* Store details of this code as "previous code" to the context. */ ctx->prev_code_first = ctx->table[code].first; ctx->prev_code_count = ctx->table[code].count; ctx->prev_code = code; return LZW_OK; } /** * Write values for this code to the output stack. * * If there isn't enough space in the output stack, this function will write * the as many as it can into the output. If `ctx->output_left > 0` after * this call, then there is more data for this code left to output. The code * is stored to the context as `ctx->output_code`. * * \param[in] ctx LZW reading context, updated. * \param[in] output_data Array to write output values into. * \param[in] output_length length Size of output array. * \param[in] output_used Current position in output array. * \param[in] code LZW code to output values for. * \param[in] left Number of values remaining to output for this code. * \return Number of pixel values written. */ static inline uint32_t lzw__write_fn(struct lzw_ctx *ctx, void *restrict output_data, uint32_t output_length, uint32_t output_used, uint16_t code, uint16_t left) { uint8_t *restrict output_pos = (uint8_t *)output_data + output_used; const struct lzw_table_entry * const table = ctx->table; uint32_t space = output_length - output_used; uint16_t count = left; if (count > space) { left = count - space; count = space; } else { left = 0; } ctx->output_code = code; ctx->output_left = left; /* Skip over any values we don't have space for. */ for (unsigned i = left; i != 0; i--) { const struct lzw_table_entry *entry = table + code; code = entry->extends; } output_pos += count; for (unsigned i = count; i != 0; i--) { const struct lzw_table_entry *entry = table + code; *--output_pos = entry->value; code = entry->extends; } return count; } /* Exported function, documented in lzw.h */ lzw_result lzw_decode(struct lzw_ctx *ctx, const uint8_t *restrict *const restrict output_data, uint32_t *restrict output_written) { const uint32_t output_length = sizeof(ctx->stack_base); *output_written = 0; *output_data = ctx->stack_base; if (ctx->output_left != 0) { *output_written += lzw__write_fn(ctx, ctx->stack_base, output_length, *output_written, ctx->output_code, ctx->output_left); } while (*output_written != output_length) { lzw_result res = lzw__decode(ctx, lzw__write_fn, ctx->stack_base, output_length, output_written); if (res != LZW_OK) { return res; } } return LZW_OK; } /** * Write colour mapped values for this code to the output. * * If there isn't enough space in the output stack, this function will write * the as many as it can into the output. If `ctx->output_left > 0` after * this call, then there is more data for this code left to output. The code * is stored to the context as `ctx->output_code`. * * \param[in] ctx LZW reading context, updated. * \param[in] output_data Array to write output values into. * \param[in] output_length Size of output array. * \param[in] output_used Current position in output array. * \param[in] code LZW code to output values for. * \param[in] left Number of values remaining to output for code. * \return Number of pixel values written. */ static inline uint32_t lzw__map_write_fn(struct lzw_ctx *ctx, void *restrict output_data, uint32_t output_length, uint32_t output_used, uint16_t code, uint16_t left) { uint32_t *restrict output_pos = (uint32_t *)output_data + output_used; const struct lzw_table_entry * const table = ctx->table; uint32_t space = output_length - output_used; uint16_t count = left; if (count > space) { left = count - space; count = space; } else { left = 0; } ctx->output_code = code; ctx->output_left = left; for (unsigned i = left; i != 0; i--) { const struct lzw_table_entry *entry = table + code; code = entry->extends; } output_pos += count; if (ctx->has_transparency) { for (unsigned i = count; i != 0; i--) { const struct lzw_table_entry *entry = table + code; --output_pos; if (entry->value != ctx->transparency_idx) { *output_pos = ctx->colour_map[entry->value]; } code = entry->extends; } } else { for (unsigned i = count; i != 0; i--) { const struct lzw_table_entry *entry = table + code; *--output_pos = ctx->colour_map[entry->value]; code = entry->extends; } } return count; } /* Exported function, documented in lzw.h */ lzw_result lzw_decode_map(struct lzw_ctx *ctx, uint32_t *restrict output_data, uint32_t output_length, uint32_t *restrict output_written) { *output_written = 0; if (ctx->colour_map == NULL) { return LZW_NO_COLOUR; } if (ctx->output_left != 0) { *output_written += lzw__map_write_fn(ctx, output_data, output_length, *output_written, ctx->output_code, ctx->output_left); } while (*output_written != output_length) { lzw_result res = lzw__decode(ctx, lzw__map_write_fn, output_data, output_length, output_written); if (res != LZW_OK) { return res; } } return LZW_OK; } libvips-8.18.2/libvips/foreign/libnsgif/lzw.h000066400000000000000000000114161516303661500211560ustar00rootroot00000000000000/* * This file is part of NetSurf's LibNSGIF, http://www.netsurf-browser.org/ * Licensed under the MIT License, * http://www.opensource.org/licenses/mit-license.php * * Copyright 2017 Michael Drake * Copyright 2021 Michael Drake */ #ifndef LZW_H_ #define LZW_H_ /** * \file * \brief LZW decompression (interface) * * Decoder for GIF LZW data. */ /** Maximum LZW code size in bits */ #define LZW_CODE_MAX 12 /* Declare lzw internal context structure */ struct lzw_ctx; /** LZW decoding response codes */ typedef enum lzw_result { LZW_OK, /**< Success */ LZW_OK_EOD, /**< Success; reached zero-length sub-block */ LZW_NO_MEM, /**< Error: Out of memory */ LZW_NO_DATA, /**< Error: Out of data */ LZW_EOI_CODE, /**< Error: End of Information code */ LZW_NO_COLOUR, /**< Error: No colour map provided. */ LZW_BAD_ICODE, /**< Error: Bad initial LZW code */ LZW_BAD_PARAM, /**< Error: Bad function parameter. */ LZW_BAD_CODE, /**< Error: Bad LZW code */ } lzw_result; /** * Create an LZW decompression context. * * \param[out] ctx Returns an LZW decompression context. Caller owned, * free with lzw_context_destroy(). * \return LZW_OK on success, or appropriate error code otherwise. */ lzw_result lzw_context_create( struct lzw_ctx **ctx); /** * Destroy an LZW decompression context. * * \param[in] ctx The LZW decompression context to destroy. */ void lzw_context_destroy( struct lzw_ctx *ctx); /** * Initialise an LZW decompression context for decoding. * * \param[in] ctx The LZW decompression context to initialise. * \param[in] minimum_code_size The LZW Minimum Code Size. * \param[in] input_data The compressed data. * \param[in] input_length Byte length of compressed data. * \param[in] input_pos Start position in data. Must be position * of a size byte at sub-block start. * \return LZW_OK on success, or appropriate error code otherwise. */ lzw_result lzw_decode_init( struct lzw_ctx *ctx, uint8_t minimum_code_size, const uint8_t *input_data, size_t input_length, size_t input_pos); /** * Read input codes until end of LZW context owned output buffer. * * Ensure anything in output is used before calling this, as anything * there before this call will be trampled. * * \param[in] ctx LZW reading context, updated. * \param[out] output_data Returns pointer to array of output values. * \param[out] output_written Returns the number of values written to data. * \return LZW_OK on success, or appropriate error code otherwise. */ lzw_result lzw_decode(struct lzw_ctx *ctx, const uint8_t *restrict *const restrict output_data, uint32_t *restrict output_written); /** * Initialise an LZW decompression context for decoding to colour map values. * * For transparency to work correctly, the given client buffer must have * the values from the previous frame. The transparency_idx should be a value * of 256 or above, if the frame does not have transparency. * * \param[in] ctx The LZW decompression context to initialise. * \param[in] minimum_code_size The LZW Minimum Code Size. * \param[in] transparency_idx Index representing transparency. * \param[in] colour_table Index to pixel colour mapping. * \param[in] input_data The compressed data. * \param[in] input_length Byte length of compressed data. * \param[in] input_pos Start position in data. Must be position * of a size byte at sub-block start. * \return LZW_OK on success, or appropriate error code otherwise. */ lzw_result lzw_decode_init_map( struct lzw_ctx *ctx, uint8_t minimum_code_size, uint32_t transparency_idx, const uint32_t *colour_table, const uint8_t *input_data, size_t input_length, size_t input_pos); /** * Read LZW codes into client buffer, mapping output to colours. * * The context must have been initialised using \ref lzw_decode_init_map * before calling this function, in order to provide the colour mapping table * and any transparency index. * * Ensure anything in output is used before calling this, as anything * there before this call will be trampled. * * \param[in] ctx LZW reading context, updated. * \param[in] output_data Client buffer to fill with colour mapped values. * \param[in] output_length Size of output array. * \param[out] output_written Returns the number of values written to data. * \return LZW_OK on success, or appropriate error code otherwise. */ lzw_result lzw_decode_map(struct lzw_ctx *ctx, uint32_t *restrict output_data, uint32_t output_length, uint32_t *restrict output_written); #endif libvips-8.18.2/libvips/foreign/libnsgif/meson.build000066400000000000000000000001751516303661500223330ustar00rootroot00000000000000nsgif_lib = static_library('nsgif', 'nsgif.h', 'gif.c', 'lzw.c', 'lzw.h', ) libvips_components += nsgif_lib libvips-8.18.2/libvips/foreign/libnsgif/nsgif.h000066400000000000000000000357261516303661500214620ustar00rootroot00000000000000/* * Copyright 2004 Richard Wilson * Copyright 2008 Sean Fox * Copyright 2013-2022 Michael Drake * * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/ * Licenced under the MIT License, * http://www.opensource.org/licenses/mit-license.php */ /** * \file * Interface to progressive animated GIF file decoding. */ #ifndef NSNSGIF_H #define NSNSGIF_H #include #include #include /** Representation of infinity. */ #define NSGIF_INFINITE (UINT32_MAX) /** Maximum colour table size */ #define NSGIF_MAX_COLOURS 256 /** * Opaque type used by LibNSGIF to represent a GIF object in memory. */ typedef struct nsgif nsgif_t; /** * LibNSGIF rectangle structure. * * * Top left coordinate is `(x0, y0)`. * * Width is `x1 - x0`. * * Height is `y1 - y0`. * * Units are pixels. */ typedef struct nsgif_rect { /** x co-ordinate of redraw rectangle, left */ uint32_t x0; /** y co-ordinate of redraw rectangle, top */ uint32_t y0; /** x co-ordinate of redraw rectangle, right */ uint32_t x1; /** y co-ordinate of redraw rectangle, bottom */ uint32_t y1; } nsgif_rect_t; /** * LibNSGIF return codes. */ typedef enum { /** * Success. */ NSGIF_OK, /** * Out of memory error. */ NSGIF_ERR_OOM, /** * GIF source data is invalid, and no frames are recoverable. */ NSGIF_ERR_DATA, /** * Frame number is not valid. */ NSGIF_ERR_BAD_FRAME, /** * GIF source data contained an error in a frame. */ NSGIF_ERR_DATA_FRAME, /** * Unexpected end of GIF source data. */ NSGIF_ERR_END_OF_DATA, /** * Can't supply more data after calling \ref nsgif_data_complete. */ NSGIF_ERR_DATA_COMPLETE, /** * The current frame cannot be displayed. */ NSGIF_ERR_FRAME_DISPLAY, /** * Indicates an animation is complete, and \ref nsgif_reset must be * called to restart the animation from the beginning. */ NSGIF_ERR_ANIMATION_END, } nsgif_error; /** * NSGIF \ref nsgif_bitmap_t pixel format. * * All pixel formats are 32 bits per pixel (bpp). The different formats * allow control over the ordering of the colour channels. All colour * channels are 8 bits wide. * * Note that the GIF file format only supports an on/off mask, so the * alpha (A) component (opacity) will always have a value of `0` (fully * transparent) or `255` (fully opaque). */ typedef enum nsgif_bitmap_fmt { /** Bite-wise RGBA: Byte order: 0xRR, 0xGG, 0xBB, 0xAA. */ NSGIF_BITMAP_FMT_R8G8B8A8, /** Bite-wise BGRA: Byte order: 0xBB, 0xGG, 0xRR, 0xAA. */ NSGIF_BITMAP_FMT_B8G8R8A8, /** Bite-wise ARGB: Byte order: 0xAA, 0xRR, 0xGG, 0xBB. */ NSGIF_BITMAP_FMT_A8R8G8B8, /** Bite-wise ABGR: Byte order: 0xAA, 0xBB, 0xGG, 0xRR. */ NSGIF_BITMAP_FMT_A8B8G8R8, /** * 32-bit RGBA (0xRRGGBBAA). * * * On little endian host, same as \ref NSGIF_BITMAP_FMT_A8B8G8R8. * * On big endian host, same as \ref NSGIF_BITMAP_FMT_R8G8B8A8. */ NSGIF_BITMAP_FMT_RGBA8888, /** * 32-bit BGRA (0xBBGGRRAA). * * * On little endian host, same as \ref NSGIF_BITMAP_FMT_A8R8G8B8. * * On big endian host, same as \ref NSGIF_BITMAP_FMT_B8G8R8A8. */ NSGIF_BITMAP_FMT_BGRA8888, /** * 32-bit ARGB (0xAARRGGBB). * * * On little endian host, same as \ref NSGIF_BITMAP_FMT_B8G8R8A8. * * On big endian host, same as \ref NSGIF_BITMAP_FMT_A8R8G8B8. */ NSGIF_BITMAP_FMT_ARGB8888, /** * 32-bit BGRA (0xAABBGGRR). * * * On little endian host, same as \ref NSGIF_BITMAP_FMT_R8G8B8A8. * * On big endian host, same as \ref NSGIF_BITMAP_FMT_A8B8G8R8. */ NSGIF_BITMAP_FMT_ABGR8888, } nsgif_bitmap_fmt_t; /** * Client bitmap type. * * These are client-created and destroyed, via the \ref nsgif_bitmap_cb_vt * callbacks, but they are owned by a \ref nsgif_t. * * See \ref nsgif_bitmap_fmt for pixel format information. * * The bitmap may have a row_span greater than the bitmap width, but the * difference between row span and width must be a whole number of pixels * (a multiple of four bytes). */ typedef void nsgif_bitmap_t; /** Bitmap callbacks function table */ typedef struct nsgif_bitmap_cb_vt { /** * Callback to create a bitmap with the given dimensions. * * \param[in] width Required bitmap width in pixels. * \param[in] height Required bitmap height in pixels. * \return pointer to client's bitmap structure or NULL on error. */ nsgif_bitmap_t* (*create)(int width, int height); /** * Callback to free a bitmap. * * \param[in] bitmap The bitmap to destroy. */ void (*destroy)(nsgif_bitmap_t *bitmap); /** * Get pointer to pixel buffer in a bitmap. * * The pixel buffer must be `(width + N) * height * sizeof(uint32_t)`. * Where `N` is any number greater than or equal to 0. * Note that the returned pointer to uint8_t must be 4-byte aligned. * * \param[in] bitmap The bitmap. * \return pointer to bitmap's pixel buffer. */ uint8_t* (*get_buffer)(nsgif_bitmap_t *bitmap); /* The following functions are optional. */ /** * Set whether a bitmap can be plotted opaque. * * \param[in] bitmap The bitmap. * \param[in] opaque Whether the current frame is opaque. */ void (*set_opaque)(nsgif_bitmap_t *bitmap, bool opaque); /** * Tests whether a bitmap has an opaque alpha channel. * * \param[in] bitmap The bitmap. * \return true if the bitmap is opaque, false otherwise. */ bool (*test_opaque)(nsgif_bitmap_t *bitmap); /** * Bitmap modified notification. * * \param[in] bitmap The bitmap. */ void (*modified)(nsgif_bitmap_t *bitmap); /** * Get row span in pixels. * * If this callback is not provided, LibNSGIF will use the width. * * If row span is greater than width, this callback must be provided. * * \param[in] bitmap The bitmap. */ uint32_t (*get_rowspan)(nsgif_bitmap_t *bitmap); } nsgif_bitmap_cb_vt; /** * Convert an error code to a string. * * \param[in] err The error code to convert. * \return String representation of given error code. */ const char *nsgif_strerror(nsgif_error err); /** * Create the NSGIF object. * * \param[in] bitmap_vt Bitmap operation functions v-table. * \param[in] bitmap_fmt Bitmap pixel format specification. * \param[out] gif_out Return \ref nsgif_t object on success. * * \return NSGIF_OK on success, or appropriate error otherwise. */ nsgif_error nsgif_create( const nsgif_bitmap_cb_vt *bitmap_vt, nsgif_bitmap_fmt_t bitmap_fmt, nsgif_t **gif_out); /** * Free a NSGIF object. * * \param[in] gif The NSGIF to free. */ void nsgif_destroy(nsgif_t *gif); /** * Scan the source image data. * * This is used to feed the source data into LibNSGIF. This must be called * before calling \ref nsgif_frame_decode. * * It can be called multiple times with, with increasing sizes. If it is called * several times, as more data is available (e.g. slow network fetch) the data * already given to \ref nsgif_data_scan must be provided each time. * * Once all the data has been provided, call \ref nsgif_data_complete. * * For example, if you call \ref nsgif_data_scan with 25 bytes of data, and then * fetch another 10 bytes, you would need to call \ref nsgif_data_scan with a * size of 35 bytes, and the whole 35 bytes must be contiguous memory. It is * safe to `realloc` the source buffer between calls to \ref nsgif_data_scan. * (The actual data pointer is allowed to be different.) * * If an error occurs, all previously scanned frames are retained. * * Note that an error returned from this function is purely informational. * So long as at least one frame is available, you can display frames. * * \param[in] gif The \ref nsgif_t object. * \param[in] size Number of bytes in data. * \param[in] data Raw source GIF data. * * \return NSGIF_OK on success, or appropriate error otherwise. */ nsgif_error nsgif_data_scan( nsgif_t *gif, size_t size, const uint8_t *data); /** * Tell libnsgif that all the gif data has been provided. * * Call this after calling \ref nsgif_data_scan with the the entire GIF * source data. You can call \ref nsgif_data_scan multiple times up until * this is called, and after this is called, \ref nsgif_data_scan will * return an error. * * You can decode a GIF before this is called, however, it will fail to * decode any truncated final frame data and will not perform loops when * driven via \ref nsgif_frame_prepare (because it doesn't know if there * will be more frames supplied in future data). * * \param[in] gif The \ref nsgif_t object. */ void nsgif_data_complete( nsgif_t *gif); /** * Prepare to show a frame. * * If this is the last frame of an animation with a finite loop count, the * returned `delay_cs` will be \ref NSGIF_INFINITE, indicating that the frame * should be shown forever. * * Note that if \ref nsgif_data_complete has not been called on this gif, * animated GIFs will not loop back to the start. Instead it will return * \ref NSGIF_ERR_END_OF_DATA. * * \param[in] gif The \ref nsgif_t object. * \param[out] area The area in pixels that must be redrawn. * \param[out] delay_cs Time to wait after frame_new before next frame in cs. * \param[out] frame_new The frame to decode. * * \return NSGIF_OK on success, or appropriate error otherwise. */ nsgif_error nsgif_frame_prepare( nsgif_t *gif, nsgif_rect_t *area, uint32_t *delay_cs, uint32_t *frame_new); /** * Decodes a GIF frame. * * \param[in] gif The \ref nsgif_t object. * \param[in] frame The frame number to decode. * \param[out] bitmap On success, returns pointer to the client-allocated, * nsgif-owned client bitmap structure. * * \return NSGIF_OK on success, or appropriate error otherwise. */ nsgif_error nsgif_frame_decode( nsgif_t *gif, uint32_t frame, nsgif_bitmap_t **bitmap); /** * Reset a GIF animation. * * Some animations are only meant to loop N times, and then show the * final frame forever. This function resets the loop and frame counters, * so that the animation can be replayed without the overhead of recreating * the \ref nsgif_t object and rescanning the raw data. * * \param[in] gif A \ref nsgif_t object. * * \return NSGIF_OK on success, or appropriate error otherwise. */ nsgif_error nsgif_reset( nsgif_t *gif); /** * Information about a GIF. */ typedef struct nsgif_info { /** width of GIF (may increase during decoding) */ uint32_t width; /** height of GIF (may increase during decoding) */ uint32_t height; /** number of frames decoded */ uint32_t frame_count; /** number of times to play animation (zero means loop forever) */ int loop_max; /** background colour in same pixel format as \ref nsgif_bitmap_t. */ uint32_t background; /** whether the GIF has a global colour table */ bool global_palette; } nsgif_info_t; /** * Frame disposal method. * * Clients do not need to know about this, it is provided purely for dumping * raw information about GIF frames. */ enum nsgif_disposal { NSGIF_DISPOSAL_UNSPECIFIED, /**< No disposal method specified. */ NSGIF_DISPOSAL_NONE, /**< Frame remains. */ NSGIF_DISPOSAL_RESTORE_BG, /**< Clear frame to background colour. */ NSGIF_DISPOSAL_RESTORE_PREV, /**< Restore previous frame. */ NSGIF_DISPOSAL_RESTORE_QUIRK, /**< Alias for NSGIF_DISPOSAL_RESTORE_PREV. */ }; /** * Convert a disposal method to a string. * * \param[in] disposal The disposal method to convert. * \return String representation of given disposal method. */ const char *nsgif_str_disposal(enum nsgif_disposal disposal); /** * Information about a GIF frame. */ typedef struct nsgif_frame_info { /** whether the frame should be displayed/animated */ bool display; /** whether the frame may have transparency */ bool transparency; /** whether the frame has a local colour table */ bool local_palette; /** whether the frame is interlaced */ bool interlaced; /** Disposal method for previous frame; affects plotting */ uint8_t disposal; /** delay (in cs) before animating the frame */ uint32_t delay; /** Frame's redraw rectangle. */ nsgif_rect_t rect; } nsgif_frame_info_t; /** * Get information about a GIF from an \ref nsgif_t object. * * \param[in] gif The \ref nsgif_t object to get info for. * * \return The gif info, or NULL on error. */ const nsgif_info_t *nsgif_get_info(const nsgif_t *gif); /** * Get information about a GIF from an \ref nsgif_t object. * * \param[in] gif The \ref nsgif_t object to get frame info for. * \param[in] frame The frame number to get info for. * * \return The gif frame info, or NULL on error. */ const nsgif_frame_info_t *nsgif_get_frame_info( const nsgif_t *gif, uint32_t frame); /** * Get the global colour palette. * * If the GIF has no global colour table, this will return the default * colour palette. * * Colours in same pixel format as \ref nsgif_bitmap_t. * * \param[in] gif The \ref nsgif_t object. * \param[out] table Client buffer to hold the colour table. * \param[out] entries The number of used entries in the colour table. */ void nsgif_global_palette( const nsgif_t *gif, uint32_t table[NSGIF_MAX_COLOURS], size_t *entries); /** * Get the local colour palette for a frame. * * Frames may have no local palette. In this case they use the global palette. * This function returns false if the frame has no local palette. * * Colours in same pixel format as \ref nsgif_bitmap_t. * * \param[in] gif The \ref nsgif_t object. * \param[in] frame The frame to get the palette for. * \param[out] table Client buffer to hold the colour table. * \param[out] entries The number of used entries in the colour table. * \return true if a palette is returned, false otherwise. */ bool nsgif_local_palette( const nsgif_t *gif, uint32_t frame, uint32_t table[NSGIF_MAX_COLOURS], size_t *entries); /** * Configure handling of small frame delays. * * Historically people created GIFs with a tiny frame delay, however the slow * hardware of the time meant they actually played much slower. As computers * sped up, to prevent animations playing faster than intended, decoders came * to ignore overly small frame delays. * * By default a \ref nsgif_frame_prepare() managed animation will override * frame delays of less than 2 centiseconds with a default frame delay of * 10 centiseconds. This matches the behaviour of web browsers and other * renderers. * * Both the minimum and the default values can be overridden for a given GIF * by the client. To get frame delays exactly as specified by the GIF file, set * `delay_min` to zero. * * Note that this does not affect the frame delay in the frame info * (\ref nsgif_frame_info_t) structure, which will always contain values * specified by the GIF. * * \param[in] gif The \ref nsgif_t object to configure. * \param[in] delay_min The minimum frame delay in centiseconds. * \param[in] delay_default The delay to use if a frame delay is less than * `delay_min`. */ void nsgif_set_frame_delay_behaviour( nsgif_t *gif, uint16_t delay_min, uint16_t delay_default); #endif libvips-8.18.2/libvips/foreign/libnsgif/patches/000077500000000000000000000000001516303661500216155ustar00rootroot00000000000000libvips-8.18.2/libvips/foreign/libnsgif/test/000077500000000000000000000000001516303661500211455ustar00rootroot00000000000000libvips-8.18.2/libvips/foreign/libnsgif/test/cli.c000066400000000000000000000460501516303661500220650ustar00rootroot00000000000000/* * SPDX-License-Identifier: ISC * * Copyright (C) 2021-2022 Michael Drake */ /** * \file * \brief Command line argument handling. */ #include #include #include #include #include #include "cli.h" /** * CLI parsing context. */ struct cli_ctx { const struct cli_table *cli; /**< Client CLI spec. */ size_t pos_count; /**< The number of positional arguments found. */ bool no_pos; /**< Have an argument that negates min_positional. */ }; /** * Check whether a CLI argument type should have a numerical value. * * \param[in] type An argument type. * \return true if the argument needs a numerical value, or false otherwise. */ static inline bool cli__arg_is_numerical(enum cli_arg_type type) { return (type != CLI_STRING && type != CLI_BOOL); } /** * Parse a signed integer value from an argument. * * \param[in] str String containing value to parse. * \param[out] i Pointer to place to store parsed value. * \param[in,out] pos Current position in str, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_value_int( const char *str, int64_t *i, size_t *pos) { long long temp; char *end = NULL; str += *pos; errno = 0; temp = strtoll(str, &end, 0); if (end == str || errno == ERANGE || temp > INT64_MAX || temp < INT64_MIN) { fprintf(stderr, "Failed to parse integer from '%s'\n", str); return false; } *i = (int64_t)temp; *pos += (size_t)(end - str); return true; } /** * Parse an unsigned integer value from an argument. * * \param[in] str String containing value to parse. * \param[out] u Pointer to place to store parsed value. * \param[in,out] pos Current position in str, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_value_uint( const char *str, uint64_t *u, size_t *pos) { unsigned long long temp; char *end = NULL; str += *pos; errno = 0; temp = strtoull(str, &end, 0); if (end == str || errno == ERANGE || temp > UINT64_MAX) { fprintf(stderr, "Failed to parse unsigned from '%s'\n", str); return false; } *u = (uint64_t)temp; *pos += (size_t)(end - str); return true; } /** * Parse an enum value from an argument. * * \param[in] str String containing value to parse. * \param[out] e Enum details. * \param[in,out] pos Current position in str, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_value_enum( const char *str, const struct cli_enum *e, size_t *pos) { str += *pos; *pos += strlen(str); for (const struct cli_str_val *sv = e->desc; sv->str != NULL; sv++) { if (strcmp(str, sv->str) == 0) { *e->e = sv->val; return true; } } fprintf(stderr, "ERROR: Unknown enum value '%s'.\n", str); return false; } /** * Parse a string value from an argument. * * \param[in] str String containing value to parse. * \param[out] s Pointer to place to store parsed value. * \param[in,out] pos Current position in str, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_value_string( const char *str, const char **s, size_t *pos) { *s = str + *pos; *pos += strlen(*s); return true; } /** * Parse a value from an argument. * * \param[in] entry Client command line interface argument specification. * \param[in] arg Argument to parse a value from. * \param[in,out] pos Current position in argument, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_value( const struct cli_table_entry *entry, const char *arg, size_t *pos) { switch (entry->t) { case CLI_CMD: if (strcmp(arg + *pos, entry->l) == 0) { *pos += strlen(arg); return true; } return false; case CLI_INT: return cli__parse_value_int(arg, entry->v.i, pos); case CLI_UINT: return cli__parse_value_uint(arg, entry->v.u, pos); case CLI_ENUM: return cli__parse_value_enum(arg, &entry->v.e, pos); case CLI_STRING: return cli__parse_value_string(arg, entry->v.s, pos); default: fprintf(stderr, "Unexpected value for '%s': %s\n", entry->l, arg); break; } return false; } /** * Parse a value from an argument. * * \param[in] entry Client command line interface argument specification. * \param[in] argc Number of command line arguments. * \param[in] argv String vector containing command line arguments. * \param[in] arg_pos Current position in argv. * \param[in,out] pos Current pos in current argument, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_argv_value(const struct cli_table_entry *entry, int argc, const char **argv, int arg_pos, size_t *pos) { const char *arg = argv[arg_pos]; if (arg_pos >= argc) { fprintf(stderr, "Value not given for '%s'\n", entry->l); return false; } return cli__parse_value(entry, arg, pos); } /** * Check whether a CLI argument is a positional value. * * \param[in] entry Client command line interface argument specification. * \return true if the argument is positional, or false otherwise. */ static inline bool cli__entry_is_positional(const struct cli_table_entry *entry) { return entry->p; } /** * Look up a short argument flag. * * \param[in] cli Client command line interface specification. * \param[in] s Argument flag to look up in client CLI spec. * \return Client CLI spec entry on success, or NULL otherwise. */ static const struct cli_table_entry *cli__lookup_short( const struct cli_table *cli, char s) { for (size_t i = 0; i < cli->count; i++) { if (cli__entry_is_positional(&cli->entries[i])) { continue; } if (cli->entries[i].s == s) { return &cli->entries[i]; } } fprintf(stderr, "Unknown flag: '%c'\n", s); return NULL; } /** * Handle an argument with a type that requires a value. * * This can handle the value being in the current argument, optionally split by * a separator, or in the next argument. * * \param[in] entry Client command line interface argument specification. * \param[in] argc Number of command line arguments. * \param[in] argv String vector containing command line arguments. * \param[in,out] arg_pos Current position in argv, updated on exit. * \param[in] pos Current position in current argument string. * \param[in] sep Name/value separator character, or '\0' if none. * \return true on success, or false otherwise. */ static bool cli__handle_arg_value(const struct cli_table_entry *entry, int argc, const char **argv, int *arg_pos, size_t pos, char sep) { const char *arg = argv[*arg_pos]; size_t orig_pos; bool ret; if (arg[pos] == '\0') { (*arg_pos)++; pos = 0; } else if (arg[pos] == sep) { pos++; } else if (cli__arg_is_numerical(entry->t) == false) { fprintf(stderr, "Separator required for non-numerical value\n"); return false; } if (isspace(argv[*arg_pos][pos])) { fprintf(stderr, "Unexpected white space in '%s' " "for argument '%s'\n", &argv[*arg_pos][pos], entry->l); return false; } orig_pos = pos; ret = cli__parse_argv_value(entry, argc, argv, *arg_pos, &pos); if (ret != true) { return ret; } if (argv[*arg_pos][pos] != '\0') { fprintf(stderr, "Invalid value '%s' for argument '%s'\n", &argv[*arg_pos][orig_pos], entry->l); return false; } return true; } static inline bool cli__is_negative(const char *arg) { int64_t i; size_t pos = 0; return cli__parse_value_int(arg, &i, &pos) && pos == strlen(arg) && i < 0; } /** * Parse a positional argument according to the given CLI spec entry. * * \param[in] ctx Command line interface parsing context. * \param[in] entry Client command line interface argument specification. * \param[in] arg Argument to parse. * \return true on success, or false otherwise. */ static bool cli__parse_positional_entry(struct cli_ctx *ctx, const struct cli_table_entry *entry, const char *arg) { size_t pos = 0; bool ret; ret = cli__parse_value(entry, arg, &pos); if (ret != true) { return ret; } else if (arg[pos] != '\0') { fprintf(stderr, "Failed to parse value '%s' for arg '%s'\n", arg, entry->l); return false; } ctx->pos_count++; return true; } /** * Parse a positional argument. * * \param[in] ctx Command line interface parsing context. * \param[in] arg Argument to parse. * \return true on success, or false otherwise. */ static bool cli__parse_positional(struct cli_ctx *ctx, const char *arg) { const struct cli_table *cli = ctx->cli; size_t positional = 0; for (size_t i = 0; i < cli->count; i++) { if (cli__entry_is_positional(&cli->entries[i])) { if (positional == ctx->pos_count) { return cli__parse_positional_entry(ctx, &cli->entries[i], arg); } positional++; } } fprintf(stderr, "Unexpected positional argument: '%s'\n", arg); return false; } /** * Parse a flags argument. * * \param[in] ctx Command line interface parsing context. * \param[in] argc Number of command line arguments. * \param[in] argv String vector containing command line arguments. * \param[out] arg_pos Current position in argv, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_short(struct cli_ctx *ctx, int argc, const char **argv, int *arg_pos) { const char *arg = argv[*arg_pos]; size_t pos = 1; if (arg[0] != '-') { return false; } while (arg[pos] != '\0') { const struct cli_table_entry *entry; entry = cli__lookup_short(ctx->cli, arg[pos]); if (entry == NULL) { if (cli__is_negative(argv[pos])) { return cli__parse_positional(ctx, argv[pos]); } return false; } if (entry->no_pos) { ctx->no_pos = true; } if (entry->t == CLI_BOOL) { *entry->v.b = true; } else { return cli__handle_arg_value(entry, argc, argv, arg_pos, pos + 1, '\0'); } pos++; } return true; } /** * Look up a long argument name. * * \param[in] cli Client command line interface specification. * \param[in] arg Argument name to look up in cli spec. * \param[in,out] pos Current position in arg, updated on exit. * \return Client CLI spec entry on success, or NULL otherwise. */ static const struct cli_table_entry *cli__lookup_long( const struct cli_table *cli, const char *arg, size_t *pos) { arg += *pos; for (size_t i = 0; i < cli->count; i++) { if (cli__entry_is_positional(&cli->entries[i]) == false) { const char *name = cli->entries[i].l; size_t name_len = strlen(cli->entries[i].l); if (strncmp(name, arg, name_len) == 0) { if (arg[name_len] != '\0' && arg[name_len] != '=') { continue; } *pos += name_len; return &cli->entries[i]; } } } fprintf(stderr, "Unknown argument: '%s'\n", arg); return NULL; } /** * Parse a long argument. * * \param[in] ctx Command line interface parsing context. * \param[in] argc Number of command line arguments. * \param[in] argv String vector containing command line arguments. * \param[out] arg_pos Current position in argv, updated on exit. * \return true on success, or false otherwise. */ static bool cli__parse_long(struct cli_ctx *ctx, int argc, const char **argv, int *arg_pos) { const struct cli_table_entry *entry; const char *arg = argv[*arg_pos]; size_t pos = 2; if (arg[0] != '-' || arg[1] != '-') { return false; } entry = cli__lookup_long(ctx->cli, arg, &pos); if (entry == NULL) { return false; } if (entry->no_pos) { ctx->no_pos = true; } if (entry->t == CLI_BOOL) { if (arg[pos] != '\0') { fprintf(stderr, "Unexpected value for argument '%s'\n", arg); return false; } *entry->v.b = true; } else { bool ret; ret = cli__handle_arg_value(entry, argc, argv, arg_pos, pos, '='); if (ret != true) { return ret; } } return true; } /** * Get the string to indicate type of value expected for an argument. * * \param[in] type The argument type. * \return String for value type. */ static const char *cli__string_from_type(enum cli_arg_type type) { static const char *const strings[] = { [CLI_BOOL] = "", [CLI_INT] = "INT", [CLI_UINT] = "UINT", [CLI_ENUM] = "ENUM", [CLI_STRING] = "STRING", }; if (type >= CLI_ARRAY_LEN(strings) || strings[type] == NULL) { return ""; } return strings[type]; } /** * Helper to update a maximum adjusted string length if new values is greater. * * \param[in] str String to check. * \param[in] adjustment Amount to modify length of string by (bytes). * \param[out] len Returns the maximum of existing and this length. */ static void cli__max_len(const char *str, size_t adjustment, size_t *len) { size_t str_len = strlen(str) + adjustment; if (str_len > *len) { *len = str_len; } } /** * Count up various properties of the client CLI interface specification. * * \param[in] cli Client command line interface specification. * \param[out] count Returns number of non-positional arguments. * \param[out] pcount Returns number of positional arguments. * \param[out] max_len Returns max string length of non-positional arguments. * \param[out] pmax_len Returns max string length of positional arguments. * \param[out] phas_desc Returns number of positional args with descriptions. */ static void cli__count(const struct cli_table *cli, size_t *count, size_t *pcount, size_t *max_len, size_t *pmax_len, size_t *phas_desc) { if (count != NULL) *count = 0; if (pcount != NULL) *pcount = 0; if (max_len != NULL) *max_len = 0; if (pmax_len != NULL) *pmax_len = 0; if (phas_desc != NULL) *phas_desc = 0; for (size_t i = 0; i < cli->count; i++) { const struct cli_table_entry *entry = &cli->entries[i]; if (cli__entry_is_positional(entry)) { if (pcount != NULL) { (*pcount)++; } if (pmax_len != NULL) { cli__max_len(entry->l, 0, pmax_len); } if (phas_desc != NULL) { (*phas_desc)++; } } else { if (count != NULL) { (*count)++; } if (max_len != NULL) { const char *type_str; size_t type_len; type_str = cli__string_from_type(entry->t); type_len = strlen(type_str); cli__max_len(entry->l, type_len, max_len); } } } } /* Documented in cli.h */ bool cli_parse(const struct cli_table *cli, int argc, const char **argv) { struct cli_ctx ctx = { .cli = cli, }; enum { ARG_PROG_NAME, ARG_FIRST, }; for (int i = ARG_FIRST; i < argc; i++) { const char *arg = argv[i]; bool ret; if (arg[0] == '-') { if (arg[1] == '-') { ret = cli__parse_long(&ctx, argc, argv, &i); } else { ret = cli__parse_short(&ctx, argc, argv, &i); } } else { ret = cli__parse_positional(&ctx, argv[i]); } if (ret != true) { return ret; } } if (ctx.no_pos == false && ctx.pos_count < cli->min_positional) { fprintf(stderr, "Insufficient positional arguments found.\n"); return false; } return true; } /** * Get terminal width. * * \return terminal width in characters. */ static size_t cli__terminal_width(void) { return 80; } /** * Print a wrapped string, with a given indent. * * The indent is assumed to already be applied for the first line of the * output by the caller. * * \param[in] str The string to print. * \param[in] indent The number of spaces to pad the left margin with. */ static void cli__print_wrapping_string(const char *str, size_t indent) { size_t terminal_width = cli__terminal_width(); size_t avail = (indent > terminal_width) ? 0 : terminal_width - indent; size_t space = avail; while (*str != '\0') { size_t word_len = strcspn(str, " \n\t"); if (word_len <= space || space == avail) { fprintf(stderr, "%*.*s", (int)word_len, (int)word_len, str); str += word_len; if (word_len <= space) { space -= word_len; } if (space > 0) { fprintf(stderr, " "); space--; } } else { fprintf(stderr, "\n%*s", (int)indent, ""); space = avail; } str += strspn(str, " \n\t"); } } /** * Print an entry's description, with a given indent. * * The indent is assumed to already be applied for the first line of the * output by the caller. * * \param[in] entry The entry to print the description for. * \param[in] indent The number of spaces to pad the left margin with. */ static void cli__print_description(const struct cli_table_entry *entry, size_t indent) { if (entry->d != NULL) { cli__print_wrapping_string(entry->d, indent); } fprintf(stderr, "\n"); if (entry->t == CLI_ENUM) { size_t max_len = 0; for (const struct cli_str_val *e = entry->v.e.desc; e->str != NULL; e++) { size_t len = strlen(e->str); if (max_len < len) { max_len = len; } } fprintf(stderr, "\n"); for (const struct cli_str_val *e = entry->v.e.desc; e->str != NULL; e++) { fprintf(stderr, " "); if (e->d == NULL || e->d[0] == '\0') { fprintf(stderr, "%s\n", e->str); } else { fprintf(stderr, "%-*s - ", (int)(max_len), e->str); cli__print_wrapping_string(e->d, 8 + max_len + 3); fprintf(stderr, "\n"); } } } } /* Documented in cli.h */ void cli_help(const struct cli_table *cli, const char *prog_name) { size_t count; size_t pcount; size_t max_len; size_t pmax_len; size_t phas_desc; size_t required = 0; enum { ARG_PROG_NAME, }; cli__count(cli, &count, &pcount, &max_len, &pmax_len, &phas_desc); if (cli->d != NULL) { fprintf(stderr, "\n"); cli__print_wrapping_string(cli->d, 0); fprintf(stderr, "\n"); } fprintf(stderr, "\nUsage: %s", prog_name); if (pcount > 0) { for (size_t i = 0; i < cli->count; i++) { if (cli__entry_is_positional(&cli->entries[i])) { const char *punctuation = (required == cli->min_positional) ? " [" : " "; if (cli->entries[i].t == CLI_CMD) { fprintf(stderr, "%s%s", punctuation, cli->entries[i].l); } else { fprintf(stderr, "%s<%s>", punctuation, cli->entries[i].l); } required++; } } if (required == pcount && required > cli->min_positional) { fprintf(stderr, "]"); } } if (count > 0) { fprintf(stderr, " [options]"); } fprintf(stderr, "\n\n"); if (phas_desc > 0) { fprintf(stderr, "Where:\n\n"); for (size_t i = 0; i < cli->count; i++) { const struct cli_table_entry *entry = &cli->entries[i]; if (entry->d == NULL) { continue; } if (cli__entry_is_positional(entry)) { fprintf(stderr, " %*.*s ", (int)pmax_len, (int)pmax_len, entry->l); cli__print_description(entry, pmax_len + 4); fprintf(stderr, "\n"); } } } if (count > 0) { fprintf(stderr, "Options:\n\n"); for (size_t i = 0; i < cli->count; i++) { const struct cli_table_entry *entry = &cli->entries[i]; const char *type_str; size_t type_len; size_t arg_len; if (cli__entry_is_positional(entry)) { continue; } if (entry->s != '\0') { fprintf(stderr, " -%c", entry->s); } else { fprintf(stderr, " "); } type_str = cli__string_from_type(entry->t); type_len = strlen(type_str); arg_len = strlen(entry->l); fprintf(stderr, " --%s %s%*.s ", entry->l, type_str, (int)(max_len - arg_len - type_len), ""); cli__print_description(entry, max_len + 11); fprintf(stderr, "\n"); } } } libvips-8.18.2/libvips/foreign/libnsgif/test/cli.h000066400000000000000000000055461516303661500220770ustar00rootroot00000000000000/* * SPDX-License-Identifier: ISC * * Copyright (C) 2021-2022 Michael Drake */ /** * \file * \brief Command line argument handling API. */ #ifndef _PELTAR_CLI_H_ #define _PELTAR_CLI_H_ #include #include /** * Helper to get element count for an array, * * \param[in] _a Array to get number of elements for. */ #define CLI_ARRAY_LEN(_a) ((sizeof(_a))/(sizeof(*(_a)))) /** * CLI argument type. */ enum cli_arg_type { CLI_CMD, /**< A sub-command. Must match long argument name. */ CLI_BOOL, /**< Has no value; presence of flag indicates true. */ CLI_INT, /**< Has signed integer value. */ CLI_UINT, /**< Has unsigned integer value. */ CLI_ENUM, /**< Has enumeration value. */ CLI_STRING, /**< Has string value. */ }; /** Enum value descriptor. */ struct cli_str_val { const char *str; /**< String for the enum value name. */ int64_t val; /**< The value for this string. */ const char *d; /**< Description of this value for help output. */ }; /** Enum data. */ struct cli_enum { const struct cli_str_val *desc; /**< Array describing enum values. */ int64_t *e; /**< Location to store \ref CLI_ENUM value. */ }; /** * Client description for a command line argument. */ struct cli_table_entry { const char *l; /**< Long argument name. */ const char s; /**< Short flag name. (Non-positional arguments.) */ bool p; /**< Whether the argument is a positional argument. */ bool no_pos; /**< When present, no positional arguments are required. */ enum cli_arg_type t; /**< Argument type. */ union { bool *b; /**< Location to store \ref CLI_BOOL value. */ int64_t *i; /**< Location to store \ref CLI_INT value. */ uint64_t *u; /**< Location to store \ref CLI_UINT value. */ const char **s; /**< Location to store \ref CLI_STRING value. */ struct cli_enum e; /**< \ref CLI_ENUM value details. */ } v; /**< Where to store type-specific values. */ const char *d; /**< Description of this argument for help output. */ }; /** * Client command line interface specification. */ struct cli_table { const struct cli_table_entry *entries; size_t count; size_t min_positional; const char *d; /**< Description of this application for help output. */ }; /** * Parse the command line arguments. * * \param[in] cli Client command line interface specification. * \param[in] argc Number of command line arguments. * \param[in] argv String vector containing command line arguments. * \return true on success, false on error. */ bool cli_parse(const struct cli_table *cli, int argc, const char **argv); /** * Print usage and help output. * * Note: Assumes non-Unicode. (One byte per character.) * * \param[in] cli Client command line interface specification. * \param[in] prog_name Program name. */ void cli_help(const struct cli_table *cli, const char *prog_name); #endif libvips-8.18.2/libvips/foreign/libnsgif/test/nsgif.c000066400000000000000000000237011516303661500224220ustar00rootroot00000000000000/* * Copyright 2008 Sean Fox * Copyright 2008 James Bursa * Copyright 2022 Michael Drake * * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/ * Licenced under the MIT License, * http://www.opensource.org/licenses/mit-license.php */ #include #include #include #include #include #include #include #include "../include/nsgif.h" #include "cli.h" #include "cli.c" #define STR_VAL(_S) STR(_S) #define STR(_S) #_S #define BYTES_PER_PIXEL 4 static struct nsgif_options { const char *file; const char *ppm; uint64_t loops; bool palette; bool version; bool info; bool help; } nsgif_options; static const struct cli_table_entry cli_entries[] = { { .s = 'h', .l = "help", .t = CLI_BOOL, .no_pos = true, .v.b = &nsgif_options.help, .d = "Print this text.", }, { .s = 'i', .l = "info", .t = CLI_BOOL, .v.b = &nsgif_options.info, .d = "Dump GIF info to stdout." }, { .s = 'l', .l = "loops", .t = CLI_UINT, .v.u = &nsgif_options.loops, .d = "Loop through decoding all frames N times. " "The default is 1." }, { .s = 'm', .l = "ppm", .t = CLI_STRING, .v.s = &nsgif_options.ppm, .d = "Convert frames to PPM image at given path." }, { .s = 'p', .l = "palette", .t = CLI_BOOL, .v.b = &nsgif_options.palette, .d = "Save palette images." }, { .s = 'V', .l = "version", .t = CLI_BOOL, .no_pos = true, .v.b = &nsgif_options.version, .d = "Print version number." }, { .p = true, .l = "FILE", .t = CLI_STRING, .v.s = &nsgif_options.file, .d = "Path to GIF file to load." }, }; const struct cli_table cli = { .entries = cli_entries, .count = (sizeof(cli_entries))/(sizeof(*cli_entries)), .min_positional = 1, .d = "NSGIF - A utility for inspecting and decoding GIFs with libnsgif", }; static void *bitmap_create(int width, int height) { /* Ensure a stupidly large bitmap is not created */ if (width > 4096 || height > 4096) { return NULL; } return calloc(width * height, BYTES_PER_PIXEL); } static unsigned char *bitmap_get_buffer(void *bitmap) { return bitmap; } static void bitmap_destroy(void *bitmap) { free(bitmap); } static uint8_t *load_file(const char *path, size_t *data_size) { FILE *fd; struct stat sb; unsigned char *buffer; size_t size; size_t n; fd = fopen(path, "rb"); if (!fd) { perror(path); exit(EXIT_FAILURE); } if (stat(path, &sb)) { perror(path); exit(EXIT_FAILURE); } size = sb.st_size; buffer = malloc(size); if (!buffer) { fprintf(stderr, "Unable to allocate %lld bytes\n", (long long) size); exit(EXIT_FAILURE); } n = fread(buffer, 1, size, fd); if (n != size) { perror(path); exit(EXIT_FAILURE); } fclose(fd); *data_size = size; return buffer; } static void warning(const char *context, nsgif_error err) { fprintf(stderr, "%s: %s\n", context, nsgif_strerror(err)); } static void print_gif_info(const nsgif_info_t *info) { const uint8_t *bg = (uint8_t *) &info->background; fprintf(stdout, "gif:\n"); fprintf(stdout, " width: %"PRIu32"\n", info->width); fprintf(stdout, " height: %"PRIu32"\n", info->height); fprintf(stdout, " max-loops: %"PRIu32"\n", info->loop_max); fprintf(stdout, " frame-count: %"PRIu32"\n", info->frame_count); fprintf(stdout, " global palette: %s\n", info->global_palette ? "yes" : "no"); fprintf(stdout, " background:\n"); fprintf(stdout, " red: 0x%"PRIx8"\n", bg[0]); fprintf(stdout, " green: 0x%"PRIx8"\n", bg[1]); fprintf(stdout, " blue: 0x%"PRIx8"\n", bg[2]); fprintf(stdout, " frames:\n"); } static void print_gif_frame_info(const nsgif_frame_info_t *info, uint32_t i) { const char *disposal = nsgif_str_disposal(info->disposal); fprintf(stdout, " - frame: %"PRIu32"\n", i); fprintf(stdout, " local palette: %s\n", info->local_palette ? "yes" : "no"); fprintf(stdout, " disposal-method: %s\n", disposal); fprintf(stdout, " transparency: %s\n", info->transparency ? "yes" : "no"); fprintf(stdout, " interlaced: %s\n", info->interlaced ? "yes" : "no"); fprintf(stdout, " display: %s\n", info->display ? "yes" : "no"); fprintf(stdout, " delay: %"PRIu32"\n", info->delay); fprintf(stdout, " rect:\n"); fprintf(stdout, " x: %"PRIu32"\n", info->rect.x0); fprintf(stdout, " y: %"PRIu32"\n", info->rect.y0); fprintf(stdout, " w: %"PRIu32"\n", info->rect.x1 - info->rect.x0); fprintf(stdout, " h: %"PRIu32"\n", info->rect.y1 - info->rect.y0); } static bool save_palette( const char *img_filename, const char *palette_filename, const uint32_t palette[NSGIF_MAX_COLOURS], size_t used_entries) { enum { SIZE = 32, COUNT = 16, }; FILE *f; int size = COUNT * SIZE + 1; f = fopen(palette_filename, "w+"); if (f == NULL) { fprintf(stderr, "Unable to open %s for writing\n", palette_filename); return false; } fprintf(f, "P3\n"); fprintf(f, "# %s: %s\n", img_filename, palette_filename); fprintf(f, "# Colour count: %zu\n", used_entries); fprintf(f, "%u %u 256\n", size, size); for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { if (x % SIZE == 0 || y % SIZE == 0) { fprintf(f, "0 0 0 "); } else { size_t offset = y / SIZE * COUNT + x / SIZE; uint8_t *entry = (uint8_t *)&palette[offset]; fprintf(f, "%u %u %u ", entry[0], entry[1], entry[2]); } } fprintf(f, "\n"); } fclose(f); return true; } static bool save_global_palette(const nsgif_t *gif) { uint32_t table[NSGIF_MAX_COLOURS]; size_t entries; nsgif_global_palette(gif, table, &entries); return save_palette(nsgif_options.file, "global-palette.ppm", table, entries); } static bool save_local_palette(const nsgif_t *gif, uint32_t frame) { static uint32_t table[NSGIF_MAX_COLOURS]; char filename[64]; size_t entries; snprintf(filename, sizeof(filename), "local-palette-%"PRIu32".ppm", frame); if (!nsgif_local_palette(gif, frame, table, &entries)) { return false; } return save_palette(nsgif_options.file, filename, table, entries); } static void decode(FILE* ppm, const char *name, nsgif_t *gif, bool first) { nsgif_error err; uint32_t frame_prev = 0; const nsgif_info_t *info; info = nsgif_get_info(gif); if (first && ppm != NULL) { fprintf(ppm, "P3\n"); fprintf(ppm, "# %s\n", name); fprintf(ppm, "# width %u \n", info->width); fprintf(ppm, "# height %u \n", info->height); fprintf(ppm, "# frame_count %u \n", info->frame_count); fprintf(ppm, "# loop_max %u \n", info->loop_max); fprintf(ppm, "%u %u 256\n", info->width, info->height * info->frame_count); } if (first && nsgif_options.info) { print_gif_info(info); } if (first && nsgif_options.palette && info->global_palette) { save_global_palette(gif); } /* decode the frames */ while (true) { nsgif_bitmap_t *bitmap; const uint8_t *image; uint32_t frame_new; uint32_t delay_cs; nsgif_rect_t area; err = nsgif_frame_prepare(gif, &area, &delay_cs, &frame_new); if (err != NSGIF_OK) { warning("nsgif_frame_prepare", err); return; } if (frame_new < frame_prev) { /* Must be an animation that loops. We only care about * decoding each frame once in this utility. */ return; } frame_prev = frame_new; if (first && nsgif_options.info) { const nsgif_frame_info_t *f_info; f_info = nsgif_get_frame_info(gif, frame_new); if (f_info != NULL) { print_gif_frame_info(f_info, frame_new); } } if (first && nsgif_options.palette) { save_local_palette(gif, frame_new); } err = nsgif_frame_decode(gif, frame_new, &bitmap); if (err != NSGIF_OK) { fprintf(stderr, "Frame %"PRIu32": " "nsgif_decode_frame failed: %s\n", frame_new, nsgif_strerror(err)); /* Continue decoding the rest of the frames. */ } else if (first && ppm != NULL) { fprintf(ppm, "# frame %u:\n", frame_new); image = (const uint8_t *) bitmap; for (uint32_t y = 0; y != info->height; y++) { for (uint32_t x = 0; x != info->width; x++) { size_t z = (y * info->width + x) * 4; fprintf(ppm, "%u %u %u ", image[z], image[z + 1], image[z + 2]); } fprintf(ppm, "\n"); } } if (delay_cs == NSGIF_INFINITE) { /** This frame is the last. */ return; } } } int main(int argc, char *argv[]) { const nsgif_bitmap_cb_vt bitmap_callbacks = { .create = bitmap_create, .destroy = bitmap_destroy, .get_buffer = bitmap_get_buffer, }; size_t size; nsgif_t *gif; uint8_t *data; nsgif_error err; FILE *ppm = NULL; /* Override default options with any command line args */ if (!cli_parse(&cli, argc, (void *)argv)) { cli_help(&cli, argv[0]); return EXIT_FAILURE; } if (nsgif_options.help) { cli_help(&cli, argv[0]); return EXIT_SUCCESS; } if (nsgif_options.version) { printf("%s %s\n", STR_VAL(NSGIF_NAME), STR_VAL(NSGIF_VERSION)); return EXIT_SUCCESS; } if (nsgif_options.ppm != NULL) { ppm = fopen(nsgif_options.ppm, "w+"); if (ppm == NULL) { fprintf(stderr, "Unable to open %s for writing\n", nsgif_options.ppm); return EXIT_FAILURE; } } /* create our gif animation */ err = nsgif_create(&bitmap_callbacks, NSGIF_BITMAP_FMT_R8G8B8A8, &gif); if (err != NSGIF_OK) { warning("nsgif_create", err); return EXIT_FAILURE; } /* load file into memory */ data = load_file(nsgif_options.file, &size); /* Scan the raw data */ err = nsgif_data_scan(gif, size, data); if (err != NSGIF_OK) { /* Not fatal; some GIFs are nasty. Can still try to decode * any frames that were decoded successfully. */ warning("nsgif_data_scan", err); } nsgif_data_complete(gif); if (nsgif_options.loops == 0) { nsgif_options.loops = 1; } for (uint64_t i = 0; i < nsgif_options.loops; i++) { decode(ppm, nsgif_options.file, gif, i == 0); /* We want to ignore any loop limit in the GIF. */ nsgif_reset(gif); } if (ppm != NULL) { fclose(ppm); } /* clean up */ nsgif_destroy(gif); free(data); return 0; } libvips-8.18.2/libvips/foreign/libnsgif/update.sh000077500000000000000000000010701516303661500220050ustar00rootroot00000000000000#!/bin/bash # attempt to update our copy of libnsgif from the upstream repo set -e git clone git://git.netsurf-browser.org/libnsgif.git echo copying out source files ... cp libnsgif/README.md README-ns.md cp libnsgif/COPYING . cp libnsgif/include/nsgif.h . cp libnsgif/src/lzw.[ch] . cp libnsgif/src/gif.c . cp libnsgif/test/cli.[ch] test/ cp libnsgif/test/nsgif.c test/ if [ -d patches ]; then echo applying patches ... for patch in patches/*.patch; do [ -f "$patch" ] || continue patch -p0 <$patch done fi echo cleaning up ... rm -rf libnsgif libvips-8.18.2/libvips/foreign/magick.c000066400000000000000000000551131516303661500177750ustar00rootroot00000000000000/* Common functions for interfacing with ImageMagick. * * 22/12/17 dlemstra * * 24/7/18 * - add the sniffer * 16/10/20 [bfriesen] * - set matte and depth appropriately for GM in magick_import_pixels() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pforeign.h" #include "magick.h" #if defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7) /* Imagemagick has weak support for some formats -- for example, AVI is * delegated to ffmpeg, and just getting the header can take many seconds and * many GB of memory. * * This function detects blocked formats which we don't pass to * imagemagick. */ static gboolean magick_block(const unsigned char *bytes, size_t length) { // AVI is a RIFF with AVI as the first chunk if (length > 12 && bytes[0] == 'R' && bytes[1] == 'I' && bytes[2] == 'F' && bytes[3] == 'F' && bytes[8] == 'A' && bytes[9] == 'V' && bytes[10] == 'I' && bytes[11] == ' ') return TRUE; // XML is very slow for some reason, and we handle SVG, so ... if (length > 5 && bytes[0] == '<' && bytes[1] == '?' && bytes[2] == 'x' && bytes[3] == 'm' && bytes[4] == 'l' && bytes[5] == ' ') return TRUE; if (length > 5 && bytes[0] == '<' && bytes[1] == '?' && bytes[2] == 'X' && bytes[3] == 'M' && bytes[4] == 'L' && bytes[5] == ' ') return TRUE; return FALSE; } /* ImageMagick can't detect some formats (eg. ICO and TGA) by examining the * contents -- ico.c and tga.c simply do not have recognisers. * * For these formats, do the detection ourselves. * Return an IM format specifier, or NULL to let IM do the detection. * * For sniffing TGAs, we check that there is at least enough room for the * header and that the preamble contains valid values: * * ----------------------------------------------------------- * |0x00 | 0-255 idlength, skip | * |0x01 | 0-1, color map present | * |0x02 | Any of (0, 1, 2, 3, 9, 10, 11), Image type | * ----------------------------------------------------------- * * However, this would catch ISOBMFF formats, so we must also check for the * 'ftyp' signature at offset 4. * * References: * * https://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf * * http://www.paulbourke.net/dataformats/tga/ * * https://en.wikipedia.org/wiki/Truevision_TGA#Technical_details * * https://en.wikipedia.org/wiki/ISO_base_media_file_format#Technical_details */ static const char * magick_sniff(const unsigned char *bytes, size_t length) { if (length >= 5 && bytes[0] == 0 && bytes[1] == 1 && bytes[2] == 0 && bytes[3] == 0 && bytes[4] == 0) return "TTF"; if (length >= 6 && bytes[0] == 0 && bytes[1] == 0 && (bytes[2] == 1 || bytes[2] == 2) && bytes[3] == 0 && (bytes[4] != 0 || bytes[5] != 0)) return "ICO"; if (length >= 8 && bytes[1] == 0 && bytes[2] == 0 && bytes[5] == 0 && bytes[6] == 0 && (bytes[4] == 7 || bytes[7] == 7)) return "XWD"; if (length >= 18 && (bytes[1] == 0 || bytes[1] == 1) && (bytes[2] == 0 || bytes[2] == 1 || bytes[2] == 2 || bytes[2] == 3 || bytes[2] == 9 || bytes[2] == 10 || bytes[2] == 11) && memcmp(bytes + 4, "ftyp", 4) != 0) return "TGA"; #if defined(HAVE_GETMAGICINFO) || defined(HAVE_MAGICK7) /* Try to search the internal magic list for a match. */ ExceptionInfo *exception = magick_acquire_exception(); const MagicInfo *magic_info = GetMagicInfo(bytes, length, exception); magick_destroy_exception(exception); if (magic_info) { const char *magic_name = GetMagicName(magic_info); /* Avoid using TIFF as a format hint since RAW/DNG images often * share the same magic signature as TIFF. */ if (magic_name && g_ascii_strcasecmp(magic_name, "TIFF") != 0) { return magic_name; } } #endif return NULL; } void magick_sniff_bytes(ImageInfo *image_info, const unsigned char *bytes, size_t length) { const char *format; if ((format = magick_sniff(bytes, length))) g_strlcpy(image_info->magick, format, MaxTextExtent); } void magick_sniff_file(ImageInfo *image_info, const char *filename) { unsigned char bytes[256]; size_t length; if ((length = vips__get_bytes(filename, bytes, 256)) >= 4) magick_sniff_bytes(image_info, bytes, length); } #endif /*defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7)*/ #ifdef HAVE_MAGICK7 Image * magick_acquire_image(const ImageInfo *image_info, ExceptionInfo *exception) { return AcquireImage(image_info, exception); } void magick_acquire_next_image(const ImageInfo *image_info, Image *image, ExceptionInfo *exception) { AcquireNextImage(image_info, image, exception); } int magick_set_image_size(Image *image, const size_t width, const size_t height, ExceptionInfo *exception) { return SetImageExtent(image, width, height, exception); } int magick_import_pixels(Image *image, const gssize x, const gssize y, const size_t width, const size_t height, const char *map, const StorageType type, const void *pixels, ExceptionInfo *exception) { return ImportImagePixels(image, x, y, width, height, map, type, pixels, exception); } void * magick_images_to_blob(const ImageInfo *image_info, Image *images, size_t *length, ExceptionInfo *exception) { return ImagesToBlob(image_info, images, length, exception); } void magick_set_property(Image *image, const char *property, const char *value, ExceptionInfo *exception) { (void) SetImageProperty(image, property, value, exception); } int magick_set_profile(Image *image, const char *name, const void *data, size_t length, ExceptionInfo *exception) { StringInfo *string; MagickBooleanType result; string = BlobToStringInfo(data, length); result = SetImageProfile(image, name, string, exception); DestroyStringInfo(string); return result; } void * magick_profile_map(Image *image, MagickMapProfileFn fn, void *a) { char *name; ResetImageProfileIterator(image); while ((name = GetNextImageProfile(image))) { const StringInfo *profile; void *data; size_t length; void *result; profile = GetImageProfile(image, name); data = GetStringInfoDatum(profile); length = GetStringInfoLength(profile); if ((result = fn(image, name, data, length, a))) return result; } return NULL; } ExceptionInfo * magick_acquire_exception(void) { return AcquireExceptionInfo(); } void magick_destroy_exception(ExceptionInfo *exception) { VIPS_FREEF(DestroyExceptionInfo, exception); } void magick_inherit_exception(ExceptionInfo *exception, Image *image) { (void) exception; (void) image; } void magick_set_number_scenes(ImageInfo *image_info, int scene, int number_scenes) { /* I can't find docs for these fields, but this seems to work. */ char page[256]; image_info->scene = scene; image_info->number_scenes = number_scenes; /* Some IMs must have the string version set as well. */ g_snprintf(page, 256, "%d-%d", scene, scene + number_scenes); image_info->scenes = g_strdup(page); } int magick_optimize_image_layers(Image **images, ExceptionInfo *exception) { Image *tmp; tmp = OptimizePlusImageLayers(*images, exception); if (exception->severity != UndefinedException) { VIPS_FREEF(DestroyImageList, tmp); return MagickFalse; } VIPS_FREEF(DestroyImageList, *images); *images = tmp; return MagickTrue; } int magick_optimize_image_transparency(const Image *images, ExceptionInfo *exception) { OptimizeImageTransparency(images, exception); return exception->severity == UndefinedException; } /* Does a few bytes look like a file IM can handle? */ gboolean magick_ismagick(const unsigned char *bytes, size_t length) { char format[MagickPathExtent]; magick_genesis(); /* Try with our custom sniffers first. */ return !magick_block(bytes, length) && (magick_sniff(bytes, length) || GetImageMagick(bytes, length, format)); } int magick_quantize_images(Image *images, const size_t depth, ExceptionInfo *exception) { QuantizeInfo info; GetQuantizeInfo(&info); info.number_colors = 1 << depth; QuantizeImages(&info, images, exception); return exception->severity == UndefinedException; } #endif /*HAVE_MAGICK7*/ #ifdef HAVE_MAGICK6 Image * magick_acquire_image(const ImageInfo *image_info, ExceptionInfo *exception) { (void) exception; #ifdef HAVE_ACQUIREIMAGE return AcquireImage(image_info); #else /*!HAVE_ACQUIREIMAGE*/ /* IM5-ish and GraphicsMagick use AllocateImage(). */ return AllocateImage(image_info); #endif } void magick_acquire_next_image(const ImageInfo *image_info, Image *image, ExceptionInfo *exception) { (void) exception; #ifdef HAVE_ACQUIREIMAGE AcquireNextImage(image_info, image); #else /*!HAVE_ACQUIREIMAGE*/ /* IM5-ish and GraphicsMagick use AllocateNextImage(). */ AllocateNextImage(image_info, image); #endif } int magick_set_image_size(Image *image, const size_t width, const size_t height, ExceptionInfo *exception) { #ifdef HAVE_SETIMAGEEXTENT int result = SetImageExtent(image, width, height); /* IM6 sets the exception on the image. */ if (!result) magick_inherit_exception(exception, image); return result; #else /*!HAVE_SETIMAGEEXTENT*/ (void) exception; image->columns = width; image->rows = height; /* imagemagick does a SyncImagePixelCache() at the end of * SetImageExtent(), but GM does not really have an equivalent. Just * always return True. */ return MagickTrue; #endif /*HAVE_SETIMAGEEXTENT*/ } int magick_import_pixels(Image *image, const gssize x, const gssize y, const size_t width, const size_t height, const char *map, const StorageType type, const void *pixels, ExceptionInfo *exception) { #ifdef HAVE_IMPORTIMAGEPIXELS return ImportImagePixels(image, x, y, width, height, map, type, pixels); #else /*!HAVE_IMPORTIMAGEPIXELS*/ Image *constitute_image; unsigned int storage_type_depth; g_assert(image); g_assert(image->signature == MagickSignature); constitute_image = ConstituteImage(width, height, map, type, pixels, &image->exception); if (!constitute_image) return MagickFalse; /* image needs to inherit these fields from constitute_image. */ switch (type) { case CharPixel: storage_type_depth = sizeof(unsigned char) * 8; break; case ShortPixel: storage_type_depth = sizeof(unsigned short) * 8; break; case IntegerPixel: storage_type_depth = sizeof(unsigned short) * 8; break; case LongPixel: storage_type_depth = sizeof(unsigned long) * 8; break; case FloatPixel: storage_type_depth = sizeof(float) * 8; break; case DoublePixel: storage_type_depth = sizeof(double) * 8; break; default: storage_type_depth = QuantumDepth; break; } image->depth = VIPS_MIN(storage_type_depth, QuantumDepth); image->matte = constitute_image->matte; (void) CompositeImage(image, CopyCompositeOp, constitute_image, x, y); DestroyImage(constitute_image); return image->exception.severity == UndefinedException; #endif /*HAVE_IMPORTIMAGEPIXELS*/ } void * magick_images_to_blob(const ImageInfo *image_info, Image *images, size_t *length, ExceptionInfo *exception) { #ifdef HAVE_IMAGESTOBLOB return ImagesToBlob(image_info, images, length, exception); #else return ImageToBlob(image_info, images, length, exception); #endif /*HAVE_IMAGESTOBLOB*/ } void magick_set_property(Image *image, const char *property, const char *value, ExceptionInfo *exception) { (void) exception; #ifdef HAVE_SETIMAGEPROPERTY (void) SetImageProperty(image, property, value); #else /*!HAVE_SETIMAGEPROPERTY*/ (void) SetImageAttribute(image, property, value); #endif /*HAVE_SETIMAGEPROPERTY*/ } int magick_set_profile(Image *image, const char *name, const void *data, size_t length, ExceptionInfo *exception) { int result; #ifdef HAVE_BLOBTOSTRINGINFO StringInfo *string; string = BlobToStringInfo(data, length); result = SetImageProfile(image, name, string); DestroyStringInfo(string); #else /*!HAVE_BLOBTOSTRINGINFO*/ result = SetImageProfile(image, name, data, length); #endif /*HAVE_BLOBTOSTRINGINFO*/ return result; } void * magick_profile_map(Image *image, MagickMapProfileFn fn, void *a) { const char *name; const void *data; size_t length; void *result; #ifdef HAVE_RESETIMAGEPROFILEITERATOR ResetImageProfileIterator(image); while ((name = GetNextImageProfile(image))) { const StringInfo *profile; profile = GetImageProfile(image, name); data = GetStringInfoDatum(profile); length = GetStringInfoLength(profile); if ((result = fn(image, name, data, length, a))) return result; } #else /*!HAVE_RESETIMAGEPROFILEITERATOR*/ { ImageProfileIterator *iter; iter = AllocateImageProfileIterator(image); while (NextImageProfile(iter, &name, (const unsigned char **) &data, &length)) { if ((result = fn(image, name, data, length, a))) { DeallocateImageProfileIterator(iter); return result; } } DeallocateImageProfileIterator(iter); } #endif /*HAVE_RESETIMAGEPROFILEITERATOR*/ return NULL; } ExceptionInfo * magick_acquire_exception(void) { ExceptionInfo *exception; #ifdef HAVE_ACQUIREEXCEPTIONINFO /* IM6+ */ exception = AcquireExceptionInfo(); #else /*!HAVE_ACQUIREEXCEPTIONINFO*/ /* gm */ exception = g_new(ExceptionInfo, 1); GetExceptionInfo(exception); #endif /*HAVE_ACQUIREEXCEPTIONINFO*/ return exception; } void magick_destroy_exception(ExceptionInfo *exception) { #ifdef HAVE_ACQUIREEXCEPTIONINFO /* IM6+ will free the exception in destroy. */ VIPS_FREEF(DestroyExceptionInfo, exception); #else /*!HAVE_ACQUIREEXCEPTIONINFO*/ /* gm and very old IM need to free the memory too. */ if (exception) { DestroyExceptionInfo(exception); g_free(exception); } #endif /*HAVE_ACQUIREEXCEPTIONINFO*/ } void magick_inherit_exception(ExceptionInfo *exception, Image *image) { #ifdef HAVE_INHERITEXCEPTION InheritException(exception, &image->exception); #endif /*HAVE_INHERITEXCEPTION*/ } void magick_set_number_scenes(ImageInfo *image_info, int scene, int number_scenes) { #ifdef HAVE_NUMBER_SCENES /* I can't find docs for these fields, but this seems to work. */ char page[256]; image_info->scene = scene; image_info->number_scenes = number_scenes; /* Some IMs must have the string version set as well. */ g_snprintf(page, 256, "%d-%d", scene, scene + number_scenes); image_info->scenes = g_strdup(page); #else /*!HAVE_NUMBER_SCENES*/ /* This works with GM 1.2.31 and probably others. */ image_info->subimage = scene; image_info->subrange = number_scenes; #endif } int magick_optimize_image_layers(Image **images, ExceptionInfo *exception) { #ifdef HAVE_OPTIMIZEPLUSIMAGELAYERS Image *tmp; tmp = OptimizePlusImageLayers(*images, exception); if (exception->severity != UndefinedException) return MagickFalse; VIPS_FREEF(DestroyImageList, *images); *images = tmp; return MagickTrue; #else /*!HAVE_OPTIMIZEPLUSIMAGELAYERS*/ g_warning("layer optimization is not supported by " "your version of libMagick"); return MagickTrue; #endif /*HAVE_OPTIMIZEPLUSIMAGELAYERS*/ } int magick_optimize_image_transparency(const Image *images, ExceptionInfo *exception) { #ifdef HAVE_OPTIMIZEIMAGETRANSPARENCY OptimizeImageTransparency(images, exception); return exception->severity == UndefinedException; #else /*!HAVE_OPTIMIZEIMAGETRANSPARENCY*/ g_warning("transparency optimization is not supported by " "your version of libMagick"); return MagickTrue; #endif /*HAVE_OPTIMIZEIMAGETRANSPARENCY*/ } /* Does a few bytes look like a file IM can handle? */ gboolean magick_ismagick(const unsigned char *bytes, size_t length) { magick_genesis(); /* Try with our custom sniffers first. */ #ifdef HAVE_GETIMAGEMAGICK3 { char format[MaxTextExtent]; return !magick_block(bytes, length) && (magick_sniff(bytes, length) || GetImageMagick(bytes, length, format)); } #else /*!HAVE_GETIMAGEMAGICK3*/ /* The GM one returns a static string. */ return !magick_block(bytes, length) && (magick_sniff(bytes, length) || GetImageMagick(bytes, length)); #endif } int magick_quantize_images(Image *images, const size_t depth, ExceptionInfo *exception) { QuantizeInfo info; GetQuantizeInfo(&info); info.number_colors = (1 << depth); return QuantizeImages(&info, images); } #endif /*HAVE_MAGICK6*/ #if defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7) void magick_set_image_option(ImageInfo *image_info, const char *name, const char *value) { #ifdef HAVE_SETIMAGEOPTION SetImageOption(image_info, name, value); #endif /*HAVE_SETIMAGEOPTION*/ } typedef struct _MagickColorspaceTypeNames { ColorspaceType colorspace; const char *name; } MagickColorspaceTypeNames; static MagickColorspaceTypeNames magick_colorspace_names[] = { { UndefinedColorspace, "UndefinedColorspace" }, { CMYKColorspace, "CMYKColorspace" }, { GRAYColorspace, "GRAYColorspace" }, { HSLColorspace, "HSLColorspace" }, { HWBColorspace, "HWBColorspace" }, { OHTAColorspace, "OHTAColorspace" }, { Rec601YCbCrColorspace, "Rec601YCbCrColorspace" }, { Rec709YCbCrColorspace, "Rec709YCbCrColorspace" }, { RGBColorspace, "RGBColorspace" }, { sRGBColorspace, "sRGBColorspace" }, { TransparentColorspace, "TransparentColorspace" }, { XYZColorspace, "XYZColorspace" }, { YCbCrColorspace, "YCbCrColorspace" }, { YCCColorspace, "YCCColorspace" }, { YIQColorspace, "YIQColorspace" }, { YPbPrColorspace, "YPbPrColorspace" }, { YUVColorspace, "YUVColorspace" }, /* More recent imagemagicks add these. */ #ifdef HAVE_CMYCOLORSPACE { CMYColorspace, "CMYColorspace" }, { HCLColorspace, "HCLColorspace" }, { HSBColorspace, "HSBColorspace" }, { LabColorspace, "LabColorspace" }, { LogColorspace, "LogColorspace" }, { LuvColorspace, "LuvColorspace" }, #endif /*HAVE_CMYCOLORSPACE*/ #ifdef HAVE_HCLPCOLORSPACE { HCLpColorspace, "HCLpColorspace" }, { HSIColorspace, "HSIColorspace" }, { HSVColorspace, "HSVColorspace" }, { LCHColorspace, "LCHColorspace" }, { LCHabColorspace, "LCHabColorspace" }, { LCHuvColorspace, "LCHuvColorspace" }, { LMSColorspace, "LMSColorspace" }, { scRGBColorspace, "scRGBColorspace" }, { xyYColorspace, "xyYColorspace" }, { YDbDrColorspace, "YDbDrColorspace" }, #endif /*HAVE_HCLPCOLORSPACE*/ /* im7 has this, I think * { LinearGRAYColorspace, "LinearGRAYColorspace" } * */ }; const char * magick_ColorspaceType2str(ColorspaceType colorspace) { int i; for (i = 0; i < VIPS_NUMBER(magick_colorspace_names); i++) if (magick_colorspace_names[i].colorspace == colorspace) return magick_colorspace_names[i].name; return ""; } void magick_vips_error(const char *domain, ExceptionInfo *exception) { if (exception) { if (exception->reason && exception->description) vips_error(domain, _("libMagick error: %s %s"), exception->reason, exception->description); else if (exception->reason) vips_error(domain, _("libMagick error: %s"), exception->reason); else vips_error(domain, "%s", _("libMagick error:")); } } static void * magick_genesis_cb(void *client) { ExceptionInfo *exception; #ifdef DEBUG printf("magick_genesis_cb:\n"); #endif /*DEBUG*/ #if defined(HAVE_MAGICKCOREGENESIS) || defined(HAVE_MAGICK7) MagickCoreGenesis(vips_get_argv0(), MagickFalse); #else /*!HAVE_MAGICKCOREGENESIS*/ InitializeMagick(vips_get_argv0()); #endif /*HAVE_MAGICKCOREGENESIS*/ /* This forces *magick to init all loaders. We have to do this so we * can sniff files with GetImageMagick(). * * We don't care about errors from magickinit. */ exception = magick_acquire_exception(); (void) GetMagickInfo("*", exception); magick_destroy_exception(exception); return NULL; } void magick_genesis(void) { static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, magick_genesis_cb, NULL); } /* Set vips metadata from a magick profile. */ static void * magick_set_vips_profile_cb(Image *image, const char *name, const void *data, size_t length, void *a) { VipsImage *im = (VipsImage *) a; char name_text[256]; VipsBuf vips_name = VIPS_BUF_STATIC(name_text); if (g_ascii_strcasecmp(name, "XMP") == 0) vips_buf_appendf(&vips_name, VIPS_META_XMP_NAME); else if (g_ascii_strcasecmp(name, "IPTC") == 0) vips_buf_appendf(&vips_name, VIPS_META_IPTC_NAME); else if (g_ascii_strcasecmp(name, "ICC") == 0) vips_buf_appendf(&vips_name, VIPS_META_ICC_NAME); else if (g_ascii_strcasecmp(name, "EXIF") == 0) vips_buf_appendf(&vips_name, VIPS_META_EXIF_NAME); else vips_buf_appendf(&vips_name, "magickprofile-%s", name); vips_image_set_blob_copy(im, vips_buf_all(&vips_name), data, length); if (strcmp(name, "exif") == 0) (void) vips__exif_parse(im); return NULL; } /* Set vips metadata from ImageMagick profiles. */ int magick_set_vips_profile(VipsImage *im, Image *image) { if (magick_profile_map(image, magick_set_vips_profile_cb, im)) return -1; return 0; } typedef struct { Image *image; ExceptionInfo *exception; } CopyProfileInfo; static void * magick_set_magick_profile_cb(VipsImage *im, const char *name, GValue *value, CopyProfileInfo *info) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC(txt); const void *data; size_t length; if (strcmp(name, VIPS_META_XMP_NAME) == 0) vips_buf_appendf(&buf, "XMP"); else if (strcmp(name, VIPS_META_IPTC_NAME) == 0) vips_buf_appendf(&buf, "IPTC"); else if (strcmp(name, VIPS_META_ICC_NAME) == 0) vips_buf_appendf(&buf, "ICC"); else if (strcmp(name, VIPS_META_EXIF_NAME) == 0) vips_buf_appendf(&buf, "EXIF"); else if (vips_isprefix("magickprofile-", name)) vips_buf_appendf(&buf, "%s", name + strlen("magickprofile-")); if (vips_buf_is_empty(&buf)) return NULL; if (!vips_image_get_typeof(im, name)) return NULL; if (vips_image_get_blob(im, name, &data, &length)) return im; if (!magick_set_profile(info->image, vips_buf_all(&buf), data, length, info->exception)) return im; return NULL; } /* Set magick metadata from a VipsImage. */ int magick_set_magick_profile(Image *image, VipsImage *im, ExceptionInfo *exception) { CopyProfileInfo info; info.image = image; info.exception = exception; if (vips_image_map(im, (VipsImageMapFn) magick_set_magick_profile_cb, &info)) return -1; return 0; } #endif /*defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7)*/ libvips-8.18.2/libvips/foreign/magick.h000066400000000000000000000064711516303661500200050ustar00rootroot00000000000000/* Common functions for interfacing with ImageMagick. * * 22/12/17 dlemstra */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #if defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7) #ifdef HAVE_MAGICK6 #include #define MaxPathExtent MaxTextExtent #endif /*HAVE_MAGICK6*/ #ifdef HAVE_MAGICK7 #include #define MaxPathExtent MagickPathExtent #endif /*HAVE_MAGICK7*/ Image *magick_acquire_image(const ImageInfo *image_info, ExceptionInfo *exception); void magick_acquire_next_image(const ImageInfo *image_info, Image *image, ExceptionInfo *exception); int magick_set_image_size(Image *image, const size_t width, const size_t height, ExceptionInfo *exception); int magick_import_pixels(Image *image, const gssize x, const gssize y, const size_t width, const size_t height, const char *map, const StorageType type, const void *pixels, ExceptionInfo *exception); void *magick_images_to_blob(const ImageInfo *image_info, Image *images, size_t *length, ExceptionInfo *exception); void magick_set_property(Image *image, const char *property, const char *value, ExceptionInfo *exception); typedef void *(*MagickMapProfileFn)(Image *image, const char *name, const void *data, size_t length, void *a); void *magick_profile_map(Image *image, MagickMapProfileFn fn, void *a); int magick_set_profile(Image *image, const char *name, const void *data, size_t length, ExceptionInfo *exception); void magick_set_image_option(ImageInfo *image_info, const char *name, const char *value); void magick_set_number_scenes(ImageInfo *image_info, int scene, int number_scenes); const char *magick_ColorspaceType2str(ColorspaceType colorspace); ExceptionInfo *magick_acquire_exception(void); void magick_destroy_exception(ExceptionInfo *exception); void magick_inherit_exception(ExceptionInfo *exception, Image *image); void magick_sniff_bytes(ImageInfo *image_info, const unsigned char *bytes, size_t length); void magick_sniff_file(ImageInfo *image_info, const char *filename); void magick_vips_error(const char *domain, ExceptionInfo *exception); void magick_genesis(void); int magick_set_vips_profile(VipsImage *im, Image *image); int magick_set_magick_profile(Image *image, VipsImage *im, ExceptionInfo *exception); int magick_optimize_image_layers(Image **images, ExceptionInfo *exception); int magick_optimize_image_transparency(const Image *images, ExceptionInfo *exception); int magick_quantize_images(Image *images, const size_t depth, ExceptionInfo *exception); gboolean magick_ismagick(const unsigned char *bytes, size_t length); #endif /*HAVE_MAGICK6*/ libvips-8.18.2/libvips/foreign/magick6load.c000066400000000000000000000727441516303661500207340ustar00rootroot00000000000000/* load with libMagick * * 7/1/03 JC * - from im_tiff2vips * 3/2/03 JC * - some InitializeMagick() fail with NULL arg * 2/11/04 * - im_magick2vips_header() also checks sensible width/height * 28/10/05 * - copy attributes to meta * - write many-frame images as a big column if all frames have identical * width/height/bands/depth * 31/3/06 * - test for magick attr support * 8/5/06 * - set RGB16/GREY16 if appropriate * 10/8/07 * - support 32/64 bit imagemagick too * 21/2/08 * - use MaxRGB if QuantumRange is missing (thanks Bob) * - look for MAGICKCORE_HDRI_SUPPORT (thanks Marcel) * - use image->attributes if GetNextImageAttribute() is missing * 3/3/09 * - allow funky bit depths, like 14 (thanks Mikkel) * 17/3/09 * - reset dcm:display-range to help DICOM read * 20/4/09 * - argh libMagick uses 255 == transparent ... we must invert all * alpha channels * 12/5/09 * - fix signed/unsigned warnings * 23/7/09 * - SetImageOption() is optional (to help GM) * 4/2/10 * - gtkdoc * 30/4/10 * - better number of bands detection with GetImageType() * - use new API stuff, argh * 17/12/11 * - turn into a set of read fns ready to be called from a class * 17/1/12 * - remove header-only loads * 11/6/13 * - add @all_frames option, off by default * 4/12/14 Lovell * - add @density option * 16/2/15 mcuelenaere * - add blob read * 26/2/15 * - close the read down early for a header read ... this saves an * fd during file read, handy for large numbers of input images * 14/2/16 * - add @page option, 0 by default * 18/4/16 * - fix @page with graphicsmagick * 25/11/16 * - add @n, deprecate @all_frames (just sets n = -1) * 23/2/17 * - try using GetImageChannelDepth() instead of ->depth * 8/9/17 * - don't cache magickload * 25/5/18 * - don't use Ping, it's too unreliable * 24/7/18 * - sniff extra filetypes * 4/1/19 kleisauke * - we did not chain exceptions correctly, causing a memory leak * - added wrapper funcs for exception handling * 4/2/19 * - add profile (xmp, ipct, etc.) read * 21/4/21 kleisauke * - include GObject part from magickload.c * 12/11/21 * - set "orientation" * 26/8/22 * - set "magick-format" * 13/3/23 MathemanFlo * - add bits per sample metadata * 08/11/24 kleisauke * - merge with magick2vips.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #ifdef ENABLE_MAGICKLOAD #ifdef HAVE_MAGICK6 #include #include "pforeign.h" #include "magick.h" /* pre-float Magick used to call this MaxRGB. */ #if !defined(QuantumRange) #define QuantumRange MaxRGB #endif /* And this used to be UseHDRI. */ #if MAGICKCORE_HDRI_SUPPORT #define UseHDRI 1 #endif typedef struct _VipsForeignLoadMagick { VipsForeignLoad parent_object; /* Deprecated. Just sets n = -1. */ gboolean all_frames; char *density; /* Load at this resolution */ int page; /* Load this page (frame) */ int n; /* Load this many pages */ Image *image; ImageInfo *image_info; ExceptionInfo *exception; /* Number of pages in image. */ int n_pages; int n_frames; /* Number of frames we will read */ Image **frames; /* An Image* for each frame */ int frame_height; /* Mutex to serialise calls to libMagick during threaded read. */ GMutex lock; } VipsForeignLoadMagick; typedef VipsForeignLoadClass VipsForeignLoadMagickClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadMagick, vips_foreign_load_magick, VIPS_TYPE_FOREIGN_LOAD); static VipsForeignFlags vips_foreign_load_magick_get_flags_filename(const char *filename) { return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_magick_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static void vips_foreign_load_magick_finalize(GObject *gobject) { VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) gobject; #ifdef DEBUG printf("vips_foreign_load_magick_finalize: %p\n", gobject); #endif /*DEBUG*/ VIPS_FREEF(DestroyImageList, magick->image); VIPS_FREEF(DestroyImageInfo, magick->image_info); VIPS_FREE(magick->frames); VIPS_FREEF(magick_destroy_exception, magick->exception); g_mutex_clear(&magick->lock); G_OBJECT_CLASS(vips_foreign_load_magick_parent_class)->finalize(gobject); } static int vips_foreign_load_magick_build(VipsObject *object) { VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) object; #ifdef DEBUG printf("vips_foreign_load_magick_build: %p\n", object); #endif /*DEBUG*/ magick_genesis(); magick->image_info = CloneImageInfo(NULL); magick->exception = magick_acquire_exception(); if (!magick->image_info) return -1; if (magick->all_frames) magick->n = -1; /* IM doesn't use the -1 means end-of-file convention, change it to a * very large number. */ if (magick->n == -1) magick->n = 10000000; /* Canvas resolution for rendering vector formats like SVG. */ VIPS_SETSTR(magick->image_info->density, magick->density); /* When reading DICOM images, we want to ignore any * window_center/_width setting, since it may put pixels outside the * 0-65535 range and lose data. * * These window settings are attached as vips metadata, so our caller * can interpret them if it wants. */ magick_set_image_option(magick->image_info, "dcm:display-range", "reset"); if (magick->page > 0) magick_set_number_scenes(magick->image_info, magick->page, magick->n); return VIPS_OBJECT_CLASS(vips_foreign_load_magick_parent_class) ->build(object); } static void vips_foreign_load_magick_class_init(VipsForeignLoadMagickClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->finalize = vips_foreign_load_magick_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload_base"; object_class->description = _("load with ImageMagick"); object_class->build = vips_foreign_load_magick_build; /* Don't cache magickload: it can gobble up memory and disc. */ operation_class->flags |= VIPS_OPERATION_NOCACHE; /* *magick is fuzzed, but it's such a huge thing it's safer to * disable it. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* We need to be well to the back of the queue since vips's * dedicated loaders are usually preferable. */ foreign_class->priority = -100; load_class->get_flags_filename = vips_foreign_load_magick_get_flags_filename; load_class->get_flags = vips_foreign_load_magick_get_flags; VIPS_ARG_STRING(class, "density", 21, _("Density"), _("Canvas resolution for rendering vector formats like SVG"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick, density), NULL); VIPS_ARG_INT(class, "page", 22, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 23, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick, n), -1, 100000, 1); VIPS_ARG_BOOL(class, "all_frames", 20, _("All frames"), _("Read all frames from an image"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoadMagick, all_frames), FALSE); } static void vips_foreign_load_magick_init(VipsForeignLoadMagick *magick) { magick->n = 1; g_mutex_init(&magick->lock); } static int magick_get_bands(Image *image) { int bands; ImageType type = GetImageType(image, &image->exception); switch (type) { case BilevelType: case GrayscaleType: bands = 1; break; case GrayscaleMatteType: /* ImageMagick also has PaletteBilevelMatteType, but GraphicsMagick * does not. Skip for portability. */ bands = 2; break; case PaletteType: case TrueColorType: bands = 3; break; case PaletteMatteType: case TrueColorMatteType: case ColorSeparationType: bands = 4; break; case ColorSeparationMatteType: bands = 5; break; default: vips_error("magick2vips", _("unsupported image type %d"), (int) type); return -1; } return bands; } static int vips_foreign_load_magick_parse(VipsForeignLoadMagick *magick, Image *image, VipsImage *out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); int depth; Image *p; #ifdef DEBUG printf("GetImageChannelDepth(AllChannels) = %zd\n", GetImageChannelDepth(image, AllChannels, &image->exception)); printf("GetImageDepth() = %zd\n", GetImageDepth(image, &image->exception)); printf("image->depth = %zd\n", image->depth); printf("GetImageType() = %d\n", GetImageType(image, &image->exception)); printf("IsGrayImage() = %d\n", IsGrayImage(image, &image->exception)); printf("IsMonochromeImage() = %d\n", IsMonochromeImage(image, &image->exception)); printf("IsOpaqueImage() = %d\n", IsOpaqueImage(image, &image->exception)); printf("image->columns = %zd\n", image->columns); printf("image->rows = %zd\n", image->rows); #endif /*DEBUG*/ /* Ysize updated below once we have worked out how many frames to load. */ out->Coding = VIPS_CODING_NONE; out->Xsize = image->columns; out->Ysize = image->rows; magick->frame_height = image->rows; out->Bands = magick_get_bands(image); if (out->Xsize <= 0 || out->Ysize <= 0 || out->Bands <= 0 || out->Xsize >= VIPS_MAX_COORD || out->Ysize >= VIPS_MAX_COORD || out->Bands >= VIPS_MAX_COORD) { vips_error(class->nickname, _("bad image dimensions %d x %d pixels, %d bands"), out->Xsize, out->Ysize, out->Bands); return -1; } /* Depth can be 'fractional'. You'd think we should use * GetImageDepth() but that seems unreliable. 16-bit mono DICOM images * are reported as depth 1, for example. * * Try GetImageChannelDepth(), maybe that works. */ depth = GetImageChannelDepth(image, AllChannels, &image->exception); out->BandFmt = -1; if (depth >= 1 && depth <= 8) out->BandFmt = VIPS_FORMAT_UCHAR; if (depth >= 9 && depth <= 16) out->BandFmt = VIPS_FORMAT_USHORT; #ifdef UseHDRI if (depth == 32) out->BandFmt = VIPS_FORMAT_FLOAT; if (depth == 64) out->BandFmt = VIPS_FORMAT_DOUBLE; #else /*!UseHDRI*/ if (depth == 32) out->BandFmt = VIPS_FORMAT_UINT; #endif /*UseHDRI*/ if (out->BandFmt == -1) { vips_error(class->nickname, _("unsupported bit depth %d"), depth); return -1; } switch (image->units) { case PixelsPerInchResolution: out->Xres = image->x_resolution / 25.4; out->Yres = image->y_resolution / 25.4; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "in"); break; case PixelsPerCentimeterResolution: out->Xres = image->x_resolution / 10.0; out->Yres = image->y_resolution / 10.0; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "cm"); break; default: /* Things like GIF have no resolution info. */ out->Xres = 1.0; out->Yres = 1.0; break; } // this can be wrong for some GM versions and must be sanity checked (see // below) switch (image->colorspace) { case GRAYColorspace: if (out->BandFmt == VIPS_FORMAT_USHORT) out->Type = VIPS_INTERPRETATION_GREY16; else out->Type = VIPS_INTERPRETATION_B_W; break; case sRGBColorspace: case RGBColorspace: if (out->BandFmt == VIPS_FORMAT_USHORT) out->Type = VIPS_INTERPRETATION_RGB16; else out->Type = VIPS_INTERPRETATION_sRGB; break; case CMYKColorspace: out->Type = VIPS_INTERPRETATION_CMYK; break; default: out->Type = VIPS_INTERPRETATION_ERROR; break; } // revise the interpretation if it seems crazy out->Type = vips_image_guess_interpretation(out); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; #ifdef HAVE_RESETIMAGEPROPERTYITERATOR { char *key; /* This is the most recent imagemagick API, test for this first. */ ResetImagePropertyIterator(image); while ((key = GetNextImageProperty(image))) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC(name_text); vips_buf_appendf(&name, "magick-%s", key); vips_image_set_string(out, vips_buf_all(&name), GetImageProperty(image, key)); } } #elif defined(HAVE_RESETIMAGEATTRIBUTEITERATOR) { const ImageAttribute *attr; /* magick6.1-ish and later, deprecated in 6.5ish. */ ResetImageAttributeIterator(image); while ((attr = GetNextImageAttribute(image))) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC(name_text); vips_buf_appendf(&name, "magick-%s", attr->key); vips_image_set_string(out, vips_buf_all(&name), attr->value); } } #else { const ImageAttribute *attr; /* GraphicsMagick is missing the iterator: we have to loop ourselves. * ->attributes is marked as private in the header, but there's no * getter so we have to access it directly. */ for (attr = image->attributes; attr; attr = attr->next) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC(name_text); vips_buf_appendf(&name, "magick-%s", attr->key); vips_image_set_string(out, vips_buf_all(&name), attr->value); } } #endif /* Set vips metadata from ImageMagick profiles. */ if (magick_set_vips_profile(out, image)) return -1; /* Something like "BMP". */ if (strlen(magick->image->magick) > 0) vips_image_set_string(out, "magick-format", magick->image->magick); magick->n_pages = GetImageListLength(image); #ifdef DEBUG printf("image has %d pages\n", magick->n_pages); #endif /*DEBUG*/ /* Do we have a set of equal-sized frames? Append them. FIXME ... there must be an attribute somewhere from dicom read which says this is a volumetric image */ magick->n_frames = 0; for (p = image; p; (p = GetNextImageInList(p))) { int p_depth = GetImageChannelDepth(p, AllChannels, &p->exception); if (p->columns != (unsigned int) out->Xsize || p->rows != (unsigned int) out->Ysize || magick_get_bands(p) != out->Bands || p_depth != depth) { #ifdef DEBUG printf("frame %d differs\n", read->n_frames); printf("%zdx%zd, %d bands\n", p->columns, p->rows, get_bands(p)); printf("first frame is %dx%d, %d bands\n", im->Xsize, im->Ysize, im->Bands); #endif /*DEBUG*/ break; } magick->n_frames += 1; } if (p) /* Nope ... just do the first image in the list. */ magick->n_frames = 1; #ifdef DEBUG printf("will read %d frames\n", magick->n_frames); #endif /*DEBUG*/ if (magick->n != -1) magick->n_frames = VIPS_MIN(magick->n_frames, magick->n); /* So we can finally set the height. */ if (magick->n_frames > 1) { vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, out->Ysize); out->Ysize *= magick->n_frames; } vips_image_set_int(out, VIPS_META_N_PAGES, magick->n_pages); vips_image_set_int(out, VIPS_META_ORIENTATION, VIPS_CLIP(1, image->orientation, 8)); vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, depth); return 0; } /* Divide by this to get 0 - MAX from a Quantum. Eg. consider QuantumRange == * 65535, MAX == 255 (a Q16 ImageMagic representing an 8-bit image). Make sure * this can't be zero (if QuantumRange < MAX) .. can happen if we have a Q8 * ImageMagick trying to represent a 16-bit image. */ #define SCALE(MAX) \ (QuantumRange < (MAX) \ ? 1 \ : ((QuantumRange + 1) / ((MAX) + 1))) #define GRAY_LOOP(TYPE, MAX) \ { \ TYPE *q = (TYPE *) q8; \ \ for (x = 0; x < n; x++) \ q[x] = pixels[x].green / SCALE(MAX); \ } #define GRAYA_LOOP(TYPE, MAX) \ { \ TYPE *q = (TYPE *) q8; \ \ for (x = 0; x < n; x++) { \ q[0] = pixels[x].green / SCALE(MAX); \ q[1] = MAX - pixels[x].opacity / SCALE(MAX); \ \ q += 2; \ } \ } #define RGB_LOOP(TYPE, MAX) \ { \ TYPE *q = (TYPE *) q8; \ \ for (x = 0; x < n; x++) { \ q[0] = pixels[x].red / SCALE(MAX); \ q[1] = pixels[x].green / SCALE(MAX); \ q[2] = pixels[x].blue / SCALE(MAX); \ \ q += 3; \ } \ } #define RGBA_LOOP(TYPE, MAX) \ { \ TYPE *q = (TYPE *) q8; \ \ for (x = 0; x < n; x++) { \ q[0] = pixels[x].red / SCALE(MAX); \ q[1] = pixels[x].green / SCALE(MAX); \ q[2] = pixels[x].blue / SCALE(MAX); \ q[3] = MAX - pixels[x].opacity / SCALE(MAX); \ \ q += 4; \ } \ } static void unpack_pixels(VipsImage *im, VipsPel *q8, PixelPacket *pixels, int n) { int x; switch (im->Bands) { case 1: /* Gray. */ switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: GRAY_LOOP(unsigned char, 255); break; case VIPS_FORMAT_USHORT: GRAY_LOOP(unsigned short, 65535); break; case VIPS_FORMAT_UINT: GRAY_LOOP(unsigned int, 4294967295UL); break; case VIPS_FORMAT_DOUBLE: GRAY_LOOP(double, QuantumRange); break; default: g_assert_not_reached(); } break; case 2: /* Gray plus alpha. */ switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: GRAYA_LOOP(unsigned char, 255); break; case VIPS_FORMAT_USHORT: GRAYA_LOOP(unsigned short, 65535); break; case VIPS_FORMAT_UINT: GRAYA_LOOP(unsigned int, 4294967295UL); break; case VIPS_FORMAT_DOUBLE: GRAYA_LOOP(double, QuantumRange); break; default: g_assert_not_reached(); } break; case 3: /* RGB. */ switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: RGB_LOOP(unsigned char, 255); break; case VIPS_FORMAT_USHORT: RGB_LOOP(unsigned short, 65535); break; case VIPS_FORMAT_UINT: RGB_LOOP(unsigned int, 4294967295UL); break; case VIPS_FORMAT_DOUBLE: RGB_LOOP(double, QuantumRange); break; default: g_assert_not_reached(); } break; case 4: /* RGBA or CMYK. */ switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: RGBA_LOOP(unsigned char, 255); break; case VIPS_FORMAT_USHORT: RGBA_LOOP(unsigned short, 65535); break; case VIPS_FORMAT_UINT: RGBA_LOOP(unsigned int, 4294967295UL); break; case VIPS_FORMAT_DOUBLE: RGBA_LOOP(double, QuantumRange); break; default: g_assert_not_reached(); } break; default: g_assert_not_reached(); } } static PixelPacket * get_pixels(Image *image, int left, int top, int width, int height) { PixelPacket *pixels; #ifdef HAVE_GETVIRTUALPIXELS if (!(pixels = (PixelPacket *) GetVirtualPixels(image, left, top, width, height, &image->exception))) #else if (!(pixels = GetImagePixels(image, left, top, width, height))) #endif return NULL; /* Can't happen if red/green/blue are doubles. */ #ifndef UseHDRI /* Unpack palette. */ if (image->storage_class == PseudoClass) { #ifdef HAVE_GETVIRTUALPIXELS IndexPacket *indexes = (IndexPacket *) GetVirtualIndexQueue(image); #else /* Was GetIndexes(), but that's now deprecated. */ IndexPacket *indexes = AccessMutableIndexes(image); #endif int i; for (i = 0; i < width * height; i++) { IndexPacket x = indexes[i]; if (x < image->colors) { pixels[i].red = image->colormap[x].red; pixels[i].green = image->colormap[x].green; pixels[i].blue = image->colormap[x].blue; } } } #endif /*UseHDRI*/ return pixels; } static int vips_foreign_load_magick_fill_region(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) a; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); VipsRect *r = &out_region->valid; VipsImage *im = out_region->im; int y; for (y = 0; y < r->height; y++) { int top = r->top + y; int frame = top / magick->frame_height; int line = top % magick->frame_height; PixelPacket *pixels; vips__worker_lock(&magick->lock); pixels = get_pixels(magick->frames[frame], r->left, line, r->width, 1); g_mutex_unlock(&magick->lock); if (!pixels) { vips_foreign_load_invalidate(im); vips_error(class->nickname, "%s", _("unable to read pixels")); return -1; } unpack_pixels(im, VIPS_REGION_ADDR(out_region, r->left, top), pixels, r->width); } return 0; } static int vips_foreign_load_magick_load(VipsForeignLoadMagick *magick) { VipsForeignLoad *load = (VipsForeignLoad *) magick; Image *p; #ifdef DEBUG printf("vips_foreign_load_magick_load: %p\n", magick); #endif /*DEBUG*/ if (vips_foreign_load_magick_parse(magick, magick->image, load->out)) return -1; /* Record frame pointers. */ g_assert(!magick->frames); if (!(magick->frames = VIPS_ARRAY(NULL, magick->n_frames, Image *))) return -1; p = magick->image; for (int i = 0; i < magick->n_frames; i++) { magick->frames[i] = p; p = GetNextImageInList(p); } if (vips_image_generate(load->out, NULL, vips_foreign_load_magick_fill_region, NULL, magick, NULL)) return -1; return 0; } typedef struct _VipsForeignLoadMagickFile { VipsForeignLoadMagick parent_object; char *filename; } VipsForeignLoadMagickFile; typedef VipsForeignLoadMagickClass VipsForeignLoadMagickFileClass; G_DEFINE_TYPE(VipsForeignLoadMagickFile, vips_foreign_load_magick_file, vips_foreign_load_magick_get_type()); static gboolean ismagick(const char *filename) { /* Fetch up to the first 100 bytes. Hopefully that'll be enough. */ unsigned char buf[100]; int len; return (len = vips__get_bytes(filename, buf, 100)) > 10 && magick_ismagick(buf, len); } /* Unfortunately, libMagick does not support header-only reads very well. See * * http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=20017 * * Test especially with BMP, GIF, TGA. So we are forced to read the entire * image in the @header() method. */ static int vips_foreign_load_magick_file_header(VipsForeignLoad *load) { VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) load; VipsForeignLoadMagickFile *file = (VipsForeignLoadMagickFile *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); #ifdef DEBUG printf("vips_foreign_load_magick_file_header: %p\n", load); #endif /*DEBUG*/ g_strlcpy(magick->image_info->filename, file->filename, MaxTextExtent); magick_sniff_file(magick->image_info, file->filename); magick->image = ReadImage(magick->image_info, magick->exception); if (!magick->image) { magick_vips_error(class->nickname, magick->exception); vips_error(class->nickname, _("unable to read file \"%s\""), file->filename); return -1; } if (vips_foreign_load_magick_load(magick)) return -1; VIPS_SETSTR(load->out->filename, file->filename); return 0; } static void vips_foreign_load_magick_file_class_init( VipsForeignLoadMagickFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload"; object_class->description = _("load file with ImageMagick"); load_class->is_a = ismagick; load_class->header = vips_foreign_load_magick_file_header; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagickFile, filename), NULL); } static void vips_foreign_load_magick_file_init(VipsForeignLoadMagickFile *magick_file) { } typedef struct _VipsForeignLoadMagickBuffer { VipsForeignLoadMagick parent_object; VipsArea *buf; } VipsForeignLoadMagickBuffer; typedef VipsForeignLoadMagickClass VipsForeignLoadMagickBufferClass; G_DEFINE_TYPE(VipsForeignLoadMagickBuffer, vips_foreign_load_magick_buffer, vips_foreign_load_magick_get_type()); static gboolean vips_foreign_load_magick_buffer_is_a_buffer(const void *buf, size_t len) { return len > 10 && magick_ismagick((const unsigned char *) buf, len); } /* Unfortunately, libMagick does not support header-only reads very well. See * * http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=20017 * * Test especially with BMP, GIF, TGA. So we are forced to read the entire * image in the @header() method. */ static int vips_foreign_load_magick_buffer_header(VipsForeignLoad *load) { VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) load; VipsForeignLoadMagickBuffer *magick_buffer = (VipsForeignLoadMagickBuffer *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); #ifdef DEBUG printf("vips_foreign_load_magick_buffer_header: %p\n", load); #endif /*DEBUG*/ /* It would be great if we could PingImage and just read the header, * but sadly many IM coders do not support ping. The critical one for * us is DICOM. TGA also has issues. */ magick_sniff_bytes(magick->image_info, magick_buffer->buf->data, magick_buffer->buf->length); magick->image = BlobToImage(magick->image_info, magick_buffer->buf->data, magick_buffer->buf->length, magick->exception); if (!magick->image) { magick_vips_error(class->nickname, magick->exception); vips_error(class->nickname, _("unable to read buffer")); return -1; } if (vips_foreign_load_magick_load(magick)) return -1; return 0; } static void vips_foreign_load_magick_buffer_class_init( VipsForeignLoadMagickBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload_buffer"; object_class->description = _("load buffer with ImageMagick"); load_class->is_a_buffer = vips_foreign_load_magick_buffer_is_a_buffer; load_class->header = vips_foreign_load_magick_buffer_header; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagickBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_magick_buffer_init(VipsForeignLoadMagickBuffer *buffer) { } typedef struct _VipsForeignLoadMagickSource { VipsForeignLoadMagick parent_object; VipsSource *source; } VipsForeignLoadMagickSource; typedef VipsForeignLoadMagickClass VipsForeignLoadMagickSourceClass; G_DEFINE_TYPE(VipsForeignLoadMagickSource, vips_foreign_load_magick_source, vips_foreign_load_magick_get_type()); static gboolean vips_foreign_load_magick_source_is_a_source(VipsSource *source) { const unsigned char *p; // just use the first 100 bytes, we don't want to force too much into // memory return (p = vips_source_sniff(source, 100)) && magick_ismagick(p, 100); } /* Unfortunately, libMagick does not support header-only reads very well. See * * http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=20017 * * Test especially with BMP, GIF, TGA. So we are forced to read the entire * image in the @header() method. */ static int vips_foreign_load_magick_source_header(VipsForeignLoad *load) { VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) load; VipsForeignLoadMagickSource *magick_source = (VipsForeignLoadMagickSource *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); #ifdef DEBUG printf("vips_foreign_load_magick_source_header: %p\n", load); #endif /*DEBUG*/ if (vips_source_is_file(magick_source->source)) { const char *filename = vips_connection_filename(VIPS_CONNECTION(magick_source->source)); g_strlcpy(magick->image_info->filename, filename, MaxPathExtent); magick_sniff_file(magick->image_info, filename); magick->image = ReadImage(magick->image_info, magick->exception); } else { size_t length; const void *data; if (!(data = vips_source_map(magick_source->source, &length))) return -1; magick_sniff_bytes(magick->image_info, data, length); magick->image = BlobToImage(magick->image_info, data, length, magick->exception); } /* It would be great if we could PingImage and just read the header, * but sadly many IM coders do not support ping. The critical one for * us is DICOM. TGA also has issues. */ if (!magick->image) { magick_vips_error(class->nickname, magick->exception); vips_error(class->nickname, _("unable to read source")); return -1; } if (vips_foreign_load_magick_load(magick)) return -1; return 0; } static void vips_foreign_load_magick_source_class_init( VipsForeignLoadMagickSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload_source"; object_class->description = _("load source with ImageMagick"); load_class->is_a_source = vips_foreign_load_magick_source_is_a_source; load_class->header = vips_foreign_load_magick_source_header; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagickSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_magick_source_init(VipsForeignLoadMagickSource *source) { } #endif /*HAVE_MAGICK6*/ #endif /*ENABLE_MAGICKLOAD*/ libvips-8.18.2/libvips/foreign/magick7load.c000066400000000000000000000636701516303661500207330ustar00rootroot00000000000000/* load with libMagick7 * * 8/7/16 * - from magickload * 25/11/16 * - add @n, deprecate @all_frames (just sets n = -1) * 24/7/18 * - sniff extra filetypes * 4/2/19 * - add profile (xmp, ipct, etc.) read * 12/11/21 * - set "orientation" * 22/3/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef ENABLE_MAGICKLOAD #ifdef HAVE_MAGICK7 #include #include "magick.h" typedef struct _VipsForeignLoadMagick7 { VipsForeignLoad parent_object; /* Deprecated. Just sets n = -1. */ gboolean all_frames; char *density; /* Load at this resolution */ int page; /* Load this page (frame) */ int n; /* Load this many pages */ Image *image; ImageInfo *image_info; ExceptionInfo *exception; /* Number of pages in image. */ int n_pages; int n_frames; /* Number of frames we will read */ Image **frames; /* An Image* for each frame */ CacheView **cache_view; /* A CacheView for each frame */ int frame_height; /* Mutex to serialise calls to libMagick during threaded read. */ GMutex lock; } VipsForeignLoadMagick7; typedef VipsForeignLoadClass VipsForeignLoadMagick7Class; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadMagick7, vips_foreign_load_magick7, VIPS_TYPE_FOREIGN_LOAD); #ifdef DEBUG static void vips_magick7_print_traits(Image *image) { static const int trait_bits[] = { CopyPixelTrait, UpdatePixelTrait, BlendPixelTrait }; static const char *trait_names[] = { "CopyPixelTrait", "UpdatePixelTrait", "BlendPixelTrait" }; int b; int i; printf("vips_magick7_print_traits: channel traits:\n"); for (b = 0; b < GetPixelChannels(image); b++) { PixelChannel channel = GetPixelChannelChannel(image, b); PixelTrait traits = GetPixelChannelTraits(image, channel); printf("\t%d) ", b); for (i = 0; i < VIPS_NUMBER(trait_bits); i++) if (traits & trait_bits[i]) printf("%s ", trait_names[i]); if (traits == 0) printf("undefined"); printf("\n"); } } static void vips_magick7_print_channel_names(Image *image) { static const int pixel_channels[] = { UndefinedPixelChannel, RedPixelChannel, CyanPixelChannel, GrayPixelChannel, LPixelChannel, LabelPixelChannel, YPixelChannel, aPixelChannel, GreenPixelChannel, MagentaPixelChannel, CbPixelChannel, bPixelChannel, BluePixelChannel, YellowPixelChannel, CrPixelChannel, BlackPixelChannel, AlphaPixelChannel, IndexPixelChannel, ReadMaskPixelChannel, WriteMaskPixelChannel, MetaPixelChannel, IntensityPixelChannel, CompositePixelChannel, SyncPixelChannel }; static const char *pixel_channel_names[] = { "UndefinedPixelChannel", "RedPixelChannel", "CyanPixelChannel", "GrayPixelChannel", "LPixelChannel", "LabelPixelChannel", "YPixelChannel", "aPixelChannel", "GreenPixelChannel", "MagentaPixelChannel", "CbPixelChannel", "bPixelChannel", "BluePixelChannel", "YellowPixelChannel", "CrPixelChannel", "BlackPixelChannel", "AlphaPixelChannel", "IndexPixelChannel", "ReadMaskPixelChannel", "WriteMaskPixelChannel", "MetaPixelChannel", "IntensityPixelChannel", "CompositePixelChannel", "SyncPixelChannel", }; int b; int i; printf("vips_magick7_print_channel_names: channel names:\n"); for (b = 0; b < GetPixelChannels(image); b++) { PixelChannel channel = GetPixelChannelChannel(image, b); printf("\t%d) ", b); for (i = 0; i < VIPS_NUMBER(pixel_channels); i++) /* Don't break on found, many channel names repeat. */ if (channel == pixel_channels[i]) printf("%s ", pixel_channel_names[i]); printf("\n"); } } static void vips_magick7_print_image_type(Image *image) { static const int image_types[] = { UndefinedType, BilevelType, GrayscaleType, GrayscaleAlphaType, PaletteType, PaletteAlphaType, TrueColorType, TrueColorAlphaType, ColorSeparationType, ColorSeparationAlphaType, OptimizeType, PaletteBilevelAlphaType }; static const char *image_type_names[] = { "UndefinedType", "BilevelType", "GrayscaleType", "GrayscaleAlphaType", "PaletteType", "PaletteAlphaType", "TrueColorType", "TrueColorAlphaType", "ColorSeparationType", "ColorSeparationAlphaType", "OptimizeType", "PaletteBilevelAlphaType" }; int i; for (i = 0; i < VIPS_NUMBER(image_types); i++) if (GetImageType(image) == image_types[i]) { printf("\t%s\n", image_type_names[i]); break; } if (i == VIPS_NUMBER(image_types)) printf("\tunknown GetImageType()\n"); } #endif /*DEBUG*/ static VipsForeignFlags vips_foreign_load_magick7_get_flags_filename(const char *filename) { return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_magick7_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static void vips_foreign_load_magick7_finalize(GObject *gobject) { VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) gobject; int i; #ifdef DEBUG printf("vips_foreign_load_magick7_finalize: %p\n", gobject); #endif /*DEBUG*/ for (i = 0; i < magick7->n_frames; i++) { VIPS_FREEF(DestroyCacheView, magick7->cache_view[i]); } VIPS_FREEF(DestroyImageList, magick7->image); VIPS_FREEF(DestroyImageInfo, magick7->image_info); VIPS_FREE(magick7->frames); VIPS_FREE(magick7->cache_view); VIPS_FREEF(magick_destroy_exception, magick7->exception); g_mutex_clear(&magick7->lock); G_OBJECT_CLASS(vips_foreign_load_magick7_parent_class)->finalize(gobject); } static int vips_foreign_load_magick7_build(VipsObject *object) { VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) object; #ifdef DEBUG printf("vips_foreign_load_magick7_build: %p\n", object); #endif /*DEBUG*/ magick_genesis(); magick7->image_info = CloneImageInfo(NULL); magick7->exception = magick_acquire_exception(); if (!magick7->image_info) return -1; if (magick7->all_frames) magick7->n = -1; /* Canvas resolution for rendering vector formats like SVG. */ VIPS_SETSTR(magick7->image_info->density, magick7->density); /* When reading DICOM images, we want to ignore any * window_center/_width setting, since it may put pixels outside the * 0-65535 range and lose data. * * These window settings are attached as vips metadata, so our caller * can interpret them if it wants. */ magick_set_image_option(magick7->image_info, "dcm:display-range", "reset"); if (magick7->page > 0) magick_set_number_scenes(magick7->image_info, magick7->page, magick7->n); return VIPS_OBJECT_CLASS(vips_foreign_load_magick7_parent_class)-> build(object); } static void vips_foreign_load_magick7_class_init(VipsForeignLoadMagick7Class *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->finalize = vips_foreign_load_magick7_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload_base"; object_class->description = _("load with ImageMagick7"); object_class->build = vips_foreign_load_magick7_build; /* Don't cache magickload: it can gobble up memory and disc. */ operation_class->flags |= VIPS_OPERATION_NOCACHE; /* *magick is fuzzed, but it's such a huge thing it's safer to * disable it. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* We need to be well to the back of the queue since vips's * dedicated loaders are usually preferable. */ foreign_class->priority = -100; load_class->get_flags_filename = vips_foreign_load_magick7_get_flags_filename; load_class->get_flags = vips_foreign_load_magick7_get_flags; VIPS_ARG_STRING(class, "density", 20, _("Density"), _("Canvas resolution for rendering vector formats like SVG"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick7, density), NULL); VIPS_ARG_INT(class, "page", 21, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick7, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 22, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick7, n), -1, 100000, 1); VIPS_ARG_BOOL(class, "all_frames", 23, _("All frames"), _("Read all frames from an image"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoadMagick7, all_frames), FALSE); } static void vips_foreign_load_magick7_init(VipsForeignLoadMagick7 *magick7) { magick7->n = 1; g_mutex_init(&magick7->lock); } static void vips_foreign_load_magick7_error(VipsForeignLoadMagick7 *magick7) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick7); vips_error(class->nickname, _("Magick: %s %s"), magick7->exception->reason, magick7->exception->description); } static int magick7_get_bands(Image *image) { int bands; int i; /* We skip all index channels. Lots of images can have these, it's not * just the palette ones. */ bands = 0; for (i = 0; i < GetPixelChannels(image); i++) { PixelChannel channel = GetPixelChannelChannel(image, i); if (channel != IndexPixelChannel) bands += 1; } return bands; } static int vips_foreign_load_magick7_parse(VipsForeignLoadMagick7 *magick7, Image *image, VipsImage *out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick7); const char *key; Image *p; #ifdef DEBUG printf("image->depth = %zd\n", image->depth); printf("GetImageType() = %d\n", GetImageType(image)); vips_magick7_print_image_type(image); printf("GetPixelChannels() = %zd\n", GetPixelChannels(image)); printf("image->columns = %zd\n", image->columns); printf("image->rows = %zd\n", image->rows); #endif /*DEBUG*/ /* Ysize updated below once we have worked out how many frames to load. */ out->Coding = VIPS_CODING_NONE; out->Xsize = image->columns; out->Ysize = image->rows; magick7->frame_height = image->rows; out->Bands = magick7_get_bands(image); if (out->Xsize <= 0 || out->Ysize <= 0 || out->Bands <= 0 || out->Xsize >= VIPS_MAX_COORD || out->Ysize >= VIPS_MAX_COORD || out->Bands >= VIPS_MAX_COORD) { vips_error(class->nickname, _("bad image dimensions %d x %d pixels, %d bands"), out->Xsize, out->Ysize, out->Bands); return -1; } /* Depth can be 'fractional'. You'd think we should use * GetImageDepth() but that seems to compute something very complex. */ out->BandFmt = -1; if (image->depth >= 1 && image->depth <= 8) out->BandFmt = VIPS_FORMAT_UCHAR; if (image->depth >= 9 && image->depth <= 16) out->BandFmt = VIPS_FORMAT_USHORT; if (image->depth == 32) out->BandFmt = VIPS_FORMAT_FLOAT; if (image->depth == 64) out->BandFmt = VIPS_FORMAT_DOUBLE; if (out->BandFmt == -1) { vips_error(class->nickname, _("unsupported bit depth %zd"), image->depth); return -1; } switch (image->units) { case PixelsPerInchResolution: out->Xres = image->resolution.x / 25.4; out->Yres = image->resolution.y / 25.4; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "in"); break; case PixelsPerCentimeterResolution: out->Xres = image->resolution.x / 10.0; out->Yres = image->resolution.y / 10.0; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "cm"); break; default: /* Things like GIF have no resolution info. */ out->Xres = 1.0; out->Yres = 1.0; break; } switch (image->colorspace) { case GRAYColorspace: if (out->BandFmt == VIPS_FORMAT_USHORT) out->Type = VIPS_INTERPRETATION_GREY16; else out->Type = VIPS_INTERPRETATION_B_W; break; case sRGBColorspace: case RGBColorspace: if (out->BandFmt == VIPS_FORMAT_USHORT) out->Type = VIPS_INTERPRETATION_RGB16; else out->Type = VIPS_INTERPRETATION_sRGB; break; case CMYKColorspace: out->Type = VIPS_INTERPRETATION_CMYK; break; default: out->Type = VIPS_INTERPRETATION_ERROR; break; } // revise the interpretation if it seems crazy out->Type = vips_image_guess_interpretation(out); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; /* Get all the string metadata. */ ResetImagePropertyIterator(image); while ((key = GetNextImageProperty(image))) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC(name_text); const char *value; value = GetImageProperty(image, key, magick7->exception); if (!value) { vips_foreign_load_magick7_error(magick7); return -1; } vips_buf_appendf(&name, "magick-%s", key); vips_image_set_string(out, vips_buf_all(&name), value); } /* Set vips metadata from ImageMagick profiles. */ if (magick_set_vips_profile(out, image)) return -1; /* Something like "BMP". */ if (strlen(magick7->image->magick) > 0) vips_image_set_string(out, "magick-format", magick7->image->magick); magick7->n_pages = GetImageListLength(GetFirstImageInList(image)); #ifdef DEBUG printf("image has %d pages\n", magick7->n_pages); #endif /*DEBUG*/ /* Do we have a set of equal-sized frames? Append them. FIXME ... there must be an attribute somewhere from dicom read which says this is a volumetric image */ magick7->n_frames = 0; for (p = image; p; (p = GetNextImageInList(p))) { if (p->columns != (unsigned int) out->Xsize || p->rows != (unsigned int) out->Ysize || magick7_get_bands(p) != out->Bands || p->depth != image->depth) { #ifdef DEBUG printf("frame %d differs\n", magick7->n_frames); printf("%zdx%zd, %d bands\n", p->columns, p->rows, magick7_get_bands(p)); printf("first frame is %dx%d, %d bands\n", out->Xsize, out->Ysize, out->Bands); #endif /*DEBUG*/ break; } magick7->n_frames += 1; } if (p) /* Nope ... just do the first image in the list. */ magick7->n_frames = 1; #ifdef DEBUG printf("will read %d frames\n", magick7->n_frames); #endif /*DEBUG*/ if (magick7->n != -1) magick7->n_frames = VIPS_MIN(magick7->n_frames, magick7->n); /* So we can finally set the height. */ if (magick7->n_frames > 1) { vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, out->Ysize); out->Ysize *= magick7->n_frames; } vips_image_set_int(out, VIPS_META_N_PAGES, magick7->n_pages); vips_image_set_int(out, VIPS_META_ORIENTATION, VIPS_CLIP(1, image->orientation, 8)); vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, image->depth); return 0; } /* We don't bother with GetPixelReadMask(), assume it's everywhere. Don't * bother with traits, assume that's always updated. * * We do skip index channels. Palette images add extra index channels * containing the index value from the file before colourmap lookup. */ #define UNPACK(TYPE) \ { \ TYPE *restrict tq = (TYPE *) q; \ int x; \ int b; \ \ for (x = 0; x < r->width; x++) { \ for (b = 0; b < GetPixelChannels(image); b++) { \ PixelChannel channel = \ GetPixelChannelChannel(image, b); \ \ if (channel != IndexPixelChannel) \ *tq++ = p[b]; \ } \ \ p += GetPixelChannels(image); \ } \ } static int vips_foreign_load_magick7_fill_region(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) a; VipsRect *r = &out_region->valid; VipsImage *im = out_region->im; int y; for (y = 0; y < r->height; y++) { int top = r->top + y; int frame = top / magick7->frame_height; int line = top % magick7->frame_height; Image *image = magick7->frames[frame]; Quantum *restrict p; VipsPel *restrict q; vips__worker_lock(&magick7->lock); p = GetCacheViewAuthenticPixels(magick7->cache_view[frame], r->left, line, r->width, 1, magick7->exception); g_mutex_unlock(&magick7->lock); if (!p) /* This can happen if, for example, some frames of a * gif are shorter than others. It's not always * an error. */ continue; q = VIPS_REGION_ADDR(out_region, r->left, top); switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: UNPACK(unsigned char); break; case VIPS_FORMAT_USHORT: UNPACK(unsigned short); break; case VIPS_FORMAT_FLOAT: UNPACK(float); break; case VIPS_FORMAT_DOUBLE: UNPACK(double); break; default: g_assert_not_reached(); } } return 0; } static int vips_foreign_load_magick7_load(VipsForeignLoadMagick7 *magick7) { VipsForeignLoad *load = (VipsForeignLoad *) magick7; Image *p; int i; #ifdef DEBUG printf("vips_foreign_load_magick7_load: %p\n", magick7); #endif /*DEBUG*/ if (vips_foreign_load_magick7_parse(magick7, magick7->image, load->out)) return -1; /* Record frame pointers. */ g_assert(!magick7->frames); if (!(magick7->frames = VIPS_ARRAY(NULL, magick7->n_frames, Image *))) return -1; p = magick7->image; for (i = 0; i < magick7->n_frames; i++) { magick7->frames[i] = p; p = GetNextImageInList(p); } /* And a cache_view for each frame. */ g_assert(!magick7->cache_view); if (!(magick7->cache_view = VIPS_ARRAY(NULL, magick7->n_frames, CacheView *))) return -1; for (i = 0; i < magick7->n_frames; i++) { magick7->cache_view[i] = AcquireAuthenticCacheView( magick7->frames[i], magick7->exception); } #ifdef DEBUG /* Only display the traits from frame0, they should all be the same. */ vips_magick7_print_traits(magick7->frames[0]); vips_magick7_print_channel_names(magick7->frames[0]); #endif /*DEBUG*/ if (vips_image_generate(load->out, NULL, vips_foreign_load_magick7_fill_region, NULL, magick7, NULL)) return -1; return 0; } typedef struct _VipsForeignLoadMagick7File { VipsForeignLoadMagick7 parent_object; char *filename; } VipsForeignLoadMagick7File; typedef VipsForeignLoadMagick7Class VipsForeignLoadMagick7FileClass; G_DEFINE_TYPE(VipsForeignLoadMagick7File, vips_foreign_load_magick7_file, vips_foreign_load_magick7_get_type()); static gboolean ismagick7(const char *filename) { /* Fetch up to the first 100 bytes. Hopefully that'll be enough. */ unsigned char buf[100]; int len; return (len = vips__get_bytes(filename, buf, 100)) > 10 && magick_ismagick(buf, len); } static int vips_foreign_load_magick7_file_header(VipsForeignLoad *load) { VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) load; VipsForeignLoadMagick7File *file = (VipsForeignLoadMagick7File *) load; #ifdef DEBUG printf("vips_foreign_load_magick7_file_header: %p\n", load); #endif /*DEBUG*/ g_strlcpy(magick7->image_info->filename, file->filename, MagickPathExtent); magick_sniff_file(magick7->image_info, file->filename); /* It would be great if we could PingImage and just read the header, * but sadly many IM coders do not support ping. The critical one for * us is DICOM. * * We have to read the whole image in _header. */ magick7->image = ReadImage(magick7->image_info, magick7->exception); if (!magick7->image) { vips_foreign_load_magick7_error(magick7); return -1; } if (vips_foreign_load_magick7_load(magick7)) return -1; VIPS_SETSTR(load->out->filename, file->filename); return 0; } static void vips_foreign_load_magick7_file_class_init( VipsForeignLoadMagick7FileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload"; object_class->description = _("load file with ImageMagick7"); load_class->is_a = ismagick7; load_class->header = vips_foreign_load_magick7_file_header; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick7File, filename), NULL); } static void vips_foreign_load_magick7_file_init(VipsForeignLoadMagick7File *magick7_file) { } typedef struct _VipsForeignLoadMagick7Buffer { VipsForeignLoadMagick7 parent_object; VipsArea *buf; } VipsForeignLoadMagick7Buffer; typedef VipsForeignLoadMagick7Class VipsForeignLoadMagick7BufferClass; G_DEFINE_TYPE(VipsForeignLoadMagick7Buffer, vips_foreign_load_magick7_buffer, vips_foreign_load_magick7_get_type()); static gboolean vips_foreign_load_magick7_buffer_is_a_buffer(const void *buf, size_t len) { return len > 10 && magick_ismagick((const unsigned char *) buf, len); } static int vips_foreign_load_magick7_buffer_header(VipsForeignLoad *load) { VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) load; VipsForeignLoadMagick7Buffer *magick7_buffer = (VipsForeignLoadMagick7Buffer *) load; #ifdef DEBUG printf("vips_foreign_load_magick7_buffer_header: %p\n", load); #endif /*DEBUG*/ /* It would be great if we could PingBlob and just read the header, * but sadly many IM coders do not support ping. The critical one for * us is DICOM. * * We have to read the whole image in _header. */ magick_sniff_bytes(magick7->image_info, magick7_buffer->buf->data, magick7_buffer->buf->length); magick7->image = BlobToImage(magick7->image_info, magick7_buffer->buf->data, magick7_buffer->buf->length, magick7->exception); if (!magick7->image) { vips_foreign_load_magick7_error(magick7); return -1; } if (vips_foreign_load_magick7_load(magick7)) return -1; return 0; } static void vips_foreign_load_magick7_buffer_class_init( VipsForeignLoadMagick7BufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload_buffer"; object_class->description = _("load buffer with ImageMagick7"); load_class->is_a_buffer = vips_foreign_load_magick7_buffer_is_a_buffer; load_class->header = vips_foreign_load_magick7_buffer_header; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick7Buffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_magick7_buffer_init(VipsForeignLoadMagick7Buffer *buffer) { } typedef struct _VipsForeignLoadMagick7Source { VipsForeignLoadMagick7 parent_object; VipsSource *source; } VipsForeignLoadMagick7Source; typedef VipsForeignLoadMagick7Class VipsForeignLoadMagick7SourceClass; G_DEFINE_TYPE(VipsForeignLoadMagick7Source, vips_foreign_load_magick7_source, vips_foreign_load_magick7_get_type()); static gboolean vips_foreign_load_magick7_source_is_a_source(VipsSource *source) { const unsigned char *p; // just use the first 100 bytes, we don't want to force too much into // memory return (p = vips_source_sniff(source, 100)) && magick_ismagick(p, 100); } /* Unfortunately, libMagick7 does not support header-only reads very well. See * * http://www.imagemagick7.org/discourse-server/viewtopic.php?f=1&t=20017 * * Test especially with BMP, GIF, TGA. So we are forced to read the entire * image in the @header() method. */ static int vips_foreign_load_magick7_source_header(VipsForeignLoad *load) { VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) load; VipsForeignLoadMagick7Source *magick7_source = (VipsForeignLoadMagick7Source *) load; #ifdef DEBUG printf("vips_foreign_load_magick7_source_header: %p\n", load); #endif /*DEBUG*/ if (vips_source_is_file(magick7_source->source)) { const char *filename = vips_connection_filename(VIPS_CONNECTION(magick7_source->source)); g_strlcpy(magick7->image_info->filename, filename, MaxTextExtent); magick_sniff_file(magick7->image_info, filename); magick7->image = ReadImage(magick7->image_info, magick7->exception); } else { size_t length; const void *data; if (!(data = vips_source_map(magick7_source->source, &length))) return -1; magick_sniff_bytes(magick7->image_info, data, length); magick7->image = BlobToImage(magick7->image_info, data, length, magick7->exception); } /* It would be great if we could PingImage and just read the header, * but sadly many IM coders do not support ping. The critical one for * us is DICOM. TGA also has issues. */ if (!magick7->image) { vips_foreign_load_magick7_error(magick7); return -1; } if (vips_foreign_load_magick7_load(magick7)) return -1; return 0; } static void vips_foreign_load_magick7_source_class_init( VipsForeignLoadMagick7SourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magickload_source"; object_class->description = _("load source with ImageMagick7"); load_class->is_a_source = vips_foreign_load_magick7_source_is_a_source; load_class->header = vips_foreign_load_magick7_source_header; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMagick7Source, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_magick7_source_init(VipsForeignLoadMagick7Source *source) { } #endif /*HAVE_MAGICK7*/ #endif /*ENABLE_MAGICKLOAD*/ libvips-8.18.2/libvips/foreign/magickload.c000066400000000000000000000117411516303661500206340ustar00rootroot00000000000000/* load with libMagick * * 5/12/11 * - from openslideload.c * 17/1/12 * - remove header-only loads * 11/6/13 * - add @all_frames option, off by default * 14/2/16 * - add @page option, 0 by default * 25/11/16 * - add @n, deprecate @all_frames (just sets n = -1) * 8/9/17 * - don't cache magickload * 21/4/21 kleisauke * - move GObject part to magick6load.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include /** * vips_magickload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read in an image using libMagick, the ImageMagick library. * * This library can read more than 80 file formats, including BMP, EPS, * DICOM and many others. * The reader can handle any ImageMagick image, including the float and double * formats. It will work with any quantum size, including HDR. Any metadata * attached to the libMagick image is copied on to the VIPS image. * * The reader should also work with most versions of GraphicsMagick. See the * `-Dmagick-package` configure option. * * The file format is usually guessed from the filename suffix, or sniffed * from the file contents. * * Normally it will only load the first image in a many-image sequence (such * as a GIF or a PDF). Use @page and @n to set the start page and number of * pages to load. Set @n to -1 to load all pages from @page onwards. * * @density is "WxH" in DPI, e.g. "600x300" or "600" (default is "72x72"). See * the [density * docs](http://www.imagemagick.org/script/command-line-options.php#density) * on the imagemagick website. * * ::: tip "Optional arguments" * * @page: `gint`, load from this page * * @n: `gint`, load this many pages * * @density: `gchararray`, canvas resolution for rendering vector formats * like SVG * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_magickload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("magickload", ap, filename, out); va_end(ap); return result; } /** * vips_magickload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read an image memory block using libMagick into a VIPS image. Exactly as * [ctor@Image.magickload], but read from a memory source. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, load from this page * * @n: `gint`, load this many pages * * @density: `gchararray`, canvas resolution for rendering vector formats * like SVG * * ::: seealso * [ctor@Image.magickload]. * * Returns: 0 on success, -1 on error. */ int vips_magickload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("magickload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_magickload_source: * @source: source to load * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.magickload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, load from this page * * @n: `gint`, load this many pages * * @density: `gchararray`, canvas resolution for rendering vector formats * like SVG * * ::: seealso * [ctor@Image.magickload]. * * Returns: 0 on success, -1 on error. */ int vips_magickload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("magickload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/magicksave.c000066400000000000000000000106171516303661500206540ustar00rootroot00000000000000/* save with libMagick * * 22/12/17 dlemstra * 6/2/19 DarthSim * - fix GraphicsMagick support * 17/2/19 * - support ICC, XMP, EXIF, IPTC metadata * - write with a single call to vips_sink_disc() * 29/6/19 * - support "strip" option * 6/7/19 [deftomat] * - support array of delays * 5/8/19 DarthSim * - support GIF optimization * 21/4/21 kleisauke * - move GObject part to vips2magick.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /** * vips_magicksave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write an image using libMagick. * * Use @quality to set the quality factor. Default 0. * * Use @format to explicitly set the save format, for example, "BMP". Otherwise * the format is guessed from the filename suffix. * * If @optimize_gif_frames is set, GIF frames are cropped to the smallest size * while preserving the results of the GIF animation. This takes some time for * computation but saves some time on encoding and produces smaller files in * some cases. * * If @optimize_gif_transparency is set, pixels that don't change the image * through animation are made transparent. This takes some time for computation * but saves some time on encoding and produces smaller files in some cases. * * @bitdepth specifies the number of bits per pixel. The image will be quantized * and dithered if the value is within the valid range (1 to 8). * * ::: tip "Optional arguments" * * @quality: `gint`, quality factor * * @format: `gchararray`, format to save as * * @optimize_gif_frames: `gboolean`, apply GIF frames optimization * * @optimize_gif_transparency: `gboolean`, apply GIF transparency * optimization * * @bitdepth: `gint`, number of bits per pixel * * ::: seealso * [method@Image.magicksave_buffer], [ctor@Image.magickload]. * * Returns: 0 on success, -1 on error. */ int vips_magicksave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("magicksave", ap, in, filename); va_end(ap); return result; } /** * vips_magicksave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.magicksave], but save to a memory buffer. * * The address of the buffer is returned in @obuf, the length of the buffer in * @olen. You are responsible for freeing the buffer with [func@GLib.free] * when you are done with it. * * ::: tip "Optional arguments" * * @quality: `gint`, quality factor * * @format: `gchararray`, format to save as * * @optimize_gif_frames: `gboolean`, apply GIF frames optimization * * @optimize_gif_transparency: `gboolean`, apply GIF transparency * optimization * * @bitdepth: `gint`, number of bits per pixel * * ::: seealso * [method@Image.magicksave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_magicksave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("magicksave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } libvips-8.18.2/libvips/foreign/matlab.c000066400000000000000000000153461516303661500200060ustar00rootroot00000000000000/* Read matlab save files with libmatio * * 4/8/09 * - transpose on load, assemble planes into bands (thanks Mikhail) * 20/12/11 * - reworked as some fns ready for new-style classes * 21/8/14 * - swap width/height * - set interpretation to rgb16 etc. * 16/2/16 * - more specific is_a test */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Remaining issues: + it will not do complex images + it will not handle sparse matrices + it loads the first variable in the file with between 1 and 3 dimensions, is this sensible behaviour? + load only, no save */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_MATIO #include #include #include #include #include #include #include "pforeign.h" /* What we track during a Mat-file read. */ typedef struct { char *filename; VipsImage *out; mat_t *mat; matvar_t *var; } Read; static void read_destroy(Read *read) { VIPS_FREE(read->filename); VIPS_FREEF(Mat_VarFree, read->var); VIPS_FREEF(Mat_Close, read->mat); g_free(read); } static Read * read_new(const char *filename, VipsImage *out) { Read *read; if (!(read = VIPS_NEW(NULL, Read))) return NULL; read->filename = vips_strdup(NULL, filename); read->out = out; read->mat = NULL; read->var = NULL; if (!(read->mat = Mat_Open(filename, MAT_ACC_RDONLY))) { vips_error("mat2vips", _("unable to open \"%s\""), filename); read_destroy(read); return NULL; } for (;;) { if (!(read->var = Mat_VarReadNextInfo(read->mat))) { vips_error("mat2vips", _("no matrix variables in \"%s\""), filename); read_destroy(read); return NULL; } #ifdef DEBUG printf("mat2vips: seen:\n"); printf("var->name == %s\n", read->var->name); printf("var->class_type == %d\n", read->var->class_type); printf("var->rank == %d\n", read->var->rank); #endif /*DEBUG*/ /* Vector to colour image is OK for us. */ if (read->var->rank >= 1 && read->var->rank <= 3) break; VIPS_FREEF(Mat_VarFree, read->var); } return read; } /* Matlab classes -> VIPS band formats. */ static int mat2vips_formats[][2] = { { MAT_C_UINT8, VIPS_FORMAT_UCHAR }, { MAT_C_INT8, VIPS_FORMAT_CHAR }, { MAT_C_UINT16, VIPS_FORMAT_USHORT }, { MAT_C_INT16, VIPS_FORMAT_SHORT }, { MAT_C_UINT32, VIPS_FORMAT_UINT }, { MAT_C_INT32, VIPS_FORMAT_INT }, { MAT_C_SINGLE, VIPS_FORMAT_FLOAT }, { MAT_C_DOUBLE, VIPS_FORMAT_DOUBLE } }; /* Pick an interpretation. */ static VipsInterpretation mat2vips_pick_interpretation(int bands, VipsBandFormat format) { if (bands == 3 && vips_band_format_is8bit(format)) return VIPS_INTERPRETATION_sRGB; if (bands == 3 && (format == VIPS_FORMAT_USHORT || format == VIPS_FORMAT_SHORT)) return VIPS_INTERPRETATION_RGB16; if (bands == 1 && (format == VIPS_FORMAT_USHORT || format == VIPS_FORMAT_SHORT)) return VIPS_INTERPRETATION_GREY16; if (bands > 1) return VIPS_INTERPRETATION_MULTIBAND; return VIPS_INTERPRETATION_MULTIBAND; } static int mat2vips_get_header(matvar_t *var, VipsImage *im) { int width, height, bands; VipsBandFormat format; VipsInterpretation interpretation; int i; width = 1; bands = 1; switch (var->rank) { case 3: bands = var->dims[2]; case 2: width = var->dims[1]; case 1: height = var->dims[0]; break; default: vips_error("mat2vips", _("unsupported rank %d\n"), var->rank); return -1; } for (i = 0; i < VIPS_NUMBER(mat2vips_formats); i++) if (mat2vips_formats[i][0] == var->class_type) break; if (i == VIPS_NUMBER(mat2vips_formats)) { vips_error("mat2vips", _("unsupported class type %d\n"), var->class_type); return -1; } format = mat2vips_formats[i][1]; interpretation = mat2vips_pick_interpretation(bands, format); vips_image_init_fields(im, width, height, bands, format, VIPS_CODING_NONE, interpretation, 1.0, 1.0); /* We read to a huge memory area. */ if (vips_image_pipelinev(im, VIPS_DEMAND_STYLE_ANY, NULL)) return -1; return 0; } int vips__mat_header(const char *filename, VipsImage *out) { Read *read; #ifdef DEBUG printf("mat2vips_header: reading \"%s\"\n", filename); #endif /*DEBUG*/ if (!(read = read_new(filename, out))) return -1; if (mat2vips_get_header(read->var, read->out)) { read_destroy(read); return -1; } read_destroy(read); return 0; } static int mat2vips_get_data(mat_t *mat, matvar_t *var, VipsImage *im) { int y; VipsPel *buffer; const int es = VIPS_IMAGE_SIZEOF_ELEMENT(im); /* Matlab images are plane-separate, so we have to assemble bands in * image-size chunks. */ const guint64 is = es * VIPS_IMAGE_N_PELS(im); if (Mat_VarReadDataAll(mat, var)) { vips_error("mat2vips", "%s", _("Mat_VarReadDataAll failed")); return -1; } /* Matlab images are in columns, so we have to transpose into * scanlines with this buffer. */ if (!(buffer = VIPS_ARRAY(im, VIPS_IMAGE_SIZEOF_LINE(im), VipsPel))) return -1; for (y = 0; y < im->Ysize; y++) { const VipsPel *p = (VipsPel *) var->data + y * es; int x; VipsPel *q; q = buffer; for (x = 0; x < im->Xsize; x++) { int b; for (b = 0; b < im->Bands; b++) { const VipsPel *p2 = p + b * is; int z; for (z = 0; z < es; z++) q[z] = p2[z]; q += es; } p += es * im->Ysize; } if (vips_image_write_line(im, y, buffer)) return -1; } return 0; } int vips__mat_load(const char *filename, VipsImage *out) { Read *read; #ifdef DEBUG printf("mat2vips: reading \"%s\"\n", filename); #endif /*DEBUG*/ if (!(read = read_new(filename, out))) return -1; if (mat2vips_get_header(read->var, read->out) || mat2vips_get_data(read->mat, read->var, read->out)) { read_destroy(read); return -1; } read_destroy(read); return 0; } int vips__mat_ismat(const char *filename) { unsigned char buf[15]; if (vips__get_bytes(filename, buf, 10) == 10 && vips_isprefix("MATLAB 5.0", (char *) buf)) return 1; return 0; } const char *vips__mat_suffs[] = { ".mat", NULL }; #endif /*HAVE_MATIO*/ libvips-8.18.2/libvips/foreign/matload.c000066400000000000000000000102471516303661500201620ustar00rootroot00000000000000/* load matlab from a file * * 5/12/11 * - from tiffload.c * 3/7/13 * - lower priority to reduce segvs from Mat_Open() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_MATIO #include "pforeign.h" typedef struct _VipsForeignLoadMat { VipsForeignLoad parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadMat; typedef VipsForeignLoadClass VipsForeignLoadMatClass; G_DEFINE_TYPE(VipsForeignLoadMat, vips_foreign_load_mat, VIPS_TYPE_FOREIGN_LOAD); static VipsForeignFlags vips_foreign_load_mat_get_flags_filename(const char *filename) { return 0; } static VipsForeignFlags vips_foreign_load_mat_get_flags(VipsForeignLoad *load) { VipsForeignLoadMat *mat = (VipsForeignLoadMat *) load; return vips_foreign_load_mat_get_flags_filename(mat->filename); } static int vips_foreign_load_mat_header(VipsForeignLoad *load) { VipsForeignLoadMat *mat = (VipsForeignLoadMat *) load; if (vips__mat_header(mat->filename, load->out)) return -1; VIPS_SETSTR(load->out->filename, mat->filename); return 0; } static int vips_foreign_load_mat_load(VipsForeignLoad *load) { VipsForeignLoadMat *mat = (VipsForeignLoadMat *) load; if (vips__mat_load(mat->filename, load->real)) return -1; return 0; } static void vips_foreign_load_mat_class_init(VipsForeignLoadMatClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "matload"; object_class->description = _("load mat from file"); /* libmatio is fuzzed, but not by us. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips__mat_suffs; load_class->is_a = vips__mat_ismat; load_class->get_flags_filename = vips_foreign_load_mat_get_flags_filename; load_class->get_flags = vips_foreign_load_mat_get_flags; load_class->header = vips_foreign_load_mat_header; load_class->load = vips_foreign_load_mat_load; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMat, filename), NULL); } static void vips_foreign_load_mat_init(VipsForeignLoadMat *mat) { } #endif /*HAVE_MATIO*/ /** * vips_matload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Read a Matlab save file into a VIPS image. * * This operation searches the save * file for the first array variable with between 1 and 3 dimensions and loads * it as an image. It will not handle complex images. It does not handle * sparse matrices. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_matload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("matload", ap, filename, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/matrixload.c000066400000000000000000000313031516303661500207010ustar00rootroot00000000000000/* load matrix from a file * * 5/12/11 * - from csvload.c * 22/2/20 * - rewrite for source API */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" typedef struct _VipsForeignLoadMatrix { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Buffered source. */ VipsSbuf *sbuf; /* A line of pixels. */ double *linebuf; } VipsForeignLoadMatrix; typedef VipsForeignLoadClass VipsForeignLoadMatrixClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadMatrix, vips_foreign_load_matrix, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_matrix_dispose(GObject *gobject) { VipsForeignLoadMatrix *matrix = (VipsForeignLoadMatrix *) gobject; VIPS_UNREF(matrix->source); VIPS_UNREF(matrix->sbuf); VIPS_FREE(matrix->linebuf); G_OBJECT_CLASS(vips_foreign_load_matrix_parent_class)->dispose(gobject); } static int vips_foreign_load_matrix_build(VipsObject *object) { VipsForeignLoadMatrix *matrix = (VipsForeignLoadMatrix *) object; if (!(matrix->sbuf = vips_sbuf_new_from_source(matrix->source))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_matrix_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_matrix_get_flags(VipsForeignLoad *load) { return 0; } /* Parse a header line. Two numbers for width and height, and two optional * numbers for scale and offset. * * We can have scale and no offset, in which case we assume offset = 0. */ static int parse_matrix_header(char *line, int *width, int *height, double *scale, double *offset) { double header[4]; char *p, *q; int i; /* Stop at newline. */ if ((p = strchr(line, '\r')) || ((p = strchr(line, '\n')))) *p = '\0'; for (i = 0, p = line; (q = vips_break_token(p, " \t")) && i < 4; i++, p = q) if (vips_strtod(p, &header[i])) { vips_error("matrixload", _("bad number \"%s\""), p); return -1; } if (i < 4) header[3] = 0.0; if (i < 3) header[2] = 1.0; if (i < 2) { vips_error("matrixload", "%s", _("no width / height")); return -1; } if (floor(header[0]) != header[0] || floor(header[1]) != header[1]) { vips_error("matrixload", "%s", _("width / height not int")); return -1; } /* Width / height can be 65536 for a 16-bit LUT, for example. */ *width = header[0]; *height = header[1]; if (*width <= 0 || *width > 100000 || *height <= 0 || *height > 100000) { vips_error("matrixload", "%s", _("width / height out of range")); return -1; } if (header[2] == 0.0) { vips_error("matrixload", "%s", _("zero scale")); return -1; } *scale = header[2]; *offset = header[3]; return 0; } static int vips_foreign_load_matrix_header(VipsForeignLoad *load) { VipsForeignLoadMatrix *matrix = (VipsForeignLoadMatrix *) load; char *line; int width; int height; double scale; double offset; int result; /* Rewind. */ vips_sbuf_unbuffer(matrix->sbuf); if (vips_source_rewind(matrix->source)) return -1; if (!(line = vips_sbuf_get_line_copy(matrix->sbuf))) { vips_error("matrixload", "%s", _("invalid header")); return -1; } result = parse_matrix_header(line, &width, &height, &scale, &offset); g_free(line); if (result) return -1; if (vips_image_pipelinev(load->out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; vips_image_init_fields(load->out, width, height, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0); vips_image_set_double(load->out, "scale", scale); vips_image_set_double(load->out, "offset", offset); VIPS_SETSTR(load->out->filename, vips_connection_filename(VIPS_CONNECTION(matrix->source))); if (!(matrix->linebuf = VIPS_ARRAY(NULL, width, double))) return -1; return 0; } static int vips_foreign_load_matrix_load(VipsForeignLoad *load) { VipsForeignLoadMatrix *matrix = (VipsForeignLoadMatrix *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); int x, y; if (vips_image_pipelinev(load->real, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; vips_image_init_fields(load->real, load->out->Xsize, load->out->Ysize, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0); for (y = 0; y < load->real->Ysize; y++) { char *line; char *p, *q; line = vips_sbuf_get_line_copy(matrix->sbuf); for (x = 0, p = line; (q = vips_break_token(p, " \t")) && x < load->out->Xsize; x++, p = q) if (vips_strtod(p, &matrix->linebuf[x])) { vips_error(class->nickname, _("bad number \"%s\""), p); g_free(line); return -1; } g_free(line); if (x != load->out->Xsize) { vips_error(class->nickname, _("line %d too short"), y); return -1; } if (vips_image_write_line(load->real, y, (VipsPel *) matrix->linebuf)) return -1; } return 0; } static void vips_foreign_load_matrix_class_init(VipsForeignLoadMatrixClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_matrix_dispose; object_class->nickname = "matrixload_base"; object_class->description = _("load matrix"); object_class->build = vips_foreign_load_matrix_build; load_class->get_flags = vips_foreign_load_matrix_get_flags; load_class->header = vips_foreign_load_matrix_header; load_class->load = vips_foreign_load_matrix_load; } static void vips_foreign_load_matrix_init(VipsForeignLoadMatrix *matrix) { } typedef struct _VipsForeignLoadMatrixFile { VipsForeignLoadMatrix parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadMatrixFile; typedef VipsForeignLoadMatrixClass VipsForeignLoadMatrixFileClass; G_DEFINE_TYPE(VipsForeignLoadMatrixFile, vips_foreign_load_matrix_file, vips_foreign_load_matrix_get_type()); static VipsForeignFlags vips_foreign_load_matrix_file_get_flags_filename(const char *filename) { return 0; } static int vips_foreign_load_matrix_file_build(VipsObject *object) { VipsForeignLoadMatrix *matrix = (VipsForeignLoadMatrix *) object; VipsForeignLoadMatrixFile *file = (VipsForeignLoadMatrixFile *) object; if (file->filename) if (!(matrix->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_matrix_file_parent_class) ->build(object); } static const char *vips_foreign_load_matrix_suffs[] = { ".mat", NULL }; static gboolean vips_foreign_load_matrix_file_is_a(const char *filename) { unsigned char line[80]; gint64 bytes; int width; int height; double scale; double offset; int result; if ((bytes = vips__get_bytes(filename, line, 79)) <= 0) return FALSE; line[bytes] = '\0'; vips_error_freeze(); result = parse_matrix_header((char *) line, &width, &height, &scale, &offset); vips_error_thaw(); return result == 0; } static void vips_foreign_load_matrix_file_class_init( VipsForeignLoadMatrixFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "matrixload"; object_class->build = vips_foreign_load_matrix_file_build; foreign_class->suffs = vips_foreign_load_matrix_suffs; load_class->is_a = vips_foreign_load_matrix_file_is_a; load_class->get_flags_filename = vips_foreign_load_matrix_file_get_flags_filename; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMatrixFile, filename), NULL); } static void vips_foreign_load_matrix_file_init(VipsForeignLoadMatrixFile *file) { } typedef struct _VipsForeignLoadMatrixSource { VipsForeignLoadMatrix parent_object; VipsSource *source; } VipsForeignLoadMatrixSource; typedef VipsForeignLoadMatrixClass VipsForeignLoadMatrixSourceClass; G_DEFINE_TYPE(VipsForeignLoadMatrixSource, vips_foreign_load_matrix_source, vips_foreign_load_matrix_get_type()); static int vips_foreign_load_matrix_source_build(VipsObject *object) { VipsForeignLoadMatrix *matrix = (VipsForeignLoadMatrix *) object; VipsForeignLoadMatrixSource *source = (VipsForeignLoadMatrixSource *) object; if (source->source) { matrix->source = source->source; g_object_ref(matrix->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_matrix_source_parent_class) ->build(object); } static int vips_foreign_load_matrix_source_is_a_source(VipsSource *source) { unsigned char *data; gint64 bytes_read; char line[80]; int width; int height; double scale; double offset; int result; if ((bytes_read = vips_source_sniff_at_most(source, &data, 79)) <= 0) return FALSE; data[bytes_read] = '\0'; g_strlcpy(line, (const char *) data, sizeof(line)); vips_error_freeze(); result = parse_matrix_header(line, &width, &height, &scale, &offset); vips_error_thaw(); return result == 0; } static void vips_foreign_load_matrix_source_class_init( VipsForeignLoadMatrixFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "matrixload_source"; object_class->build = vips_foreign_load_matrix_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_matrix_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadMatrixSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_matrix_source_init(VipsForeignLoadMatrixSource *source) { } /** * vips_matrixload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Reads a matrix from a file. * * Matrix files have a simple format that's supposed to be easy to create with * a text editor or a spreadsheet. * * The first line has four numbers for width, height, scale and * offset (scale and offset may be omitted, in which case they default to 1.0 * and 0.0). Scale must be non-zero. Width and height must be positive * integers. The numbers are separated by any mixture of spaces, commas, * tabs and quotation marks ("). The scale and offset fields may be * floating-point, and must use '.' * as a decimal separator. * * Subsequent lines each hold one row of matrix data, with numbers again * separated by any mixture of spaces, commas, * tabs and quotation marks ("). The numbers may be floating-point, and must * use '.' * as a decimal separator. * * Extra characters at the ends of lines or at the end of the file are * ignored. * * ::: seealso * [ctor@Image.matrixload]. * * Returns: 0 on success, -1 on error. */ int vips_matrixload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("matrixload", ap, filename, out); va_end(ap); return result; } /** * vips_matrixload_source: * @source: source to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.matrixload], but read from a source. * * ::: seealso * [ctor@Image.matrixload]. * * Returns: 0 on success, -1 on error. */ int vips_matrixload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("matrixload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/matrixsave.c000066400000000000000000000234611516303661500207260ustar00rootroot00000000000000/* save to matrix * * 2/12/11 * - wrap a class around the matrix writer * 21/2/20 * - rewrite for the VipsTarget API */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pforeign.h" typedef struct _VipsForeignSaveMatrix { VipsForeignSave parent_object; VipsTarget *target; const char *separator; } VipsForeignSaveMatrix; typedef VipsForeignSaveClass VipsForeignSaveMatrixClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveMatrix, vips_foreign_save_matrix, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_matrix_dispose(GObject *gobject) { VipsForeignSaveMatrix *matrix = (VipsForeignSaveMatrix *) gobject; VIPS_UNREF(matrix->target); G_OBJECT_CLASS(vips_foreign_save_matrix_parent_class)->dispose(gobject); } static int vips_foreign_save_matrix_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveMatrix *matrix = (VipsForeignSaveMatrix *) a; int x, y; for (y = 0; y < area->height; y++) { double *p = (double *) VIPS_REGION_ADDR(region, 0, area->top + y); char buf[G_ASCII_DTOSTR_BUF_SIZE]; for (x = 0; x < area->width; x++) { if (x > 0) vips_target_writes(matrix->target, " "); g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, p[x]); vips_target_writes(matrix->target, buf); } if (vips_target_writes(matrix->target, "\n")) return -1; } return 0; } static int vips_foreign_save_matrix_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveMatrix *matrix = (VipsForeignSaveMatrix *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); double scale; double offset; if (VIPS_OBJECT_CLASS(vips_foreign_save_matrix_parent_class)->build(object)) return -1; if (vips_check_mono(class->nickname, save->ready) || vips_check_uncoded(class->nickname, save->ready)) return -1; vips_target_writef(matrix->target, "%d %d", save->ready->Xsize, save->ready->Ysize); scale = vips_image_get_scale(save->ready); offset = vips_image_get_offset(save->ready); if (scale != 1.0 || offset != 0.0) vips_target_writef(matrix->target, " %g %g", scale, offset); if (vips_target_writes(matrix->target, "\n")) return -1; if (vips_sink_disc(save->ready, vips_foreign_save_matrix_block, matrix)) return -1; if (vips_target_end(matrix->target)) return -1; return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat bandfmt_matrix[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ D, D, D, D, D, D, D, D, D, D }; static const char *vips_foreign_save_matrix_suffs[] = { ".mat", NULL }; static void vips_foreign_save_matrix_class_init(VipsForeignSaveMatrixClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_matrix_dispose; object_class->nickname = "matrixsave_base"; object_class->description = _("save image to matrix"); object_class->build = vips_foreign_save_matrix_build; foreign_class->suffs = vips_foreign_save_matrix_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_MONO; save_class->format_table = bandfmt_matrix; } static void vips_foreign_save_matrix_init(VipsForeignSaveMatrix *matrix) { } typedef struct _VipsForeignSaveMatrixFile { VipsForeignSaveMatrix parent_object; char *filename; } VipsForeignSaveMatrixFile; typedef VipsForeignSaveMatrixClass VipsForeignSaveMatrixFileClass; G_DEFINE_TYPE(VipsForeignSaveMatrixFile, vips_foreign_save_matrix_file, vips_foreign_save_matrix_get_type()); static int vips_foreign_save_matrix_file_build(VipsObject *object) { VipsForeignSaveMatrix *matrix = (VipsForeignSaveMatrix *) object; VipsForeignSaveMatrixFile *file = (VipsForeignSaveMatrixFile *) object; if (file->filename && !(matrix->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_matrix_file_parent_class) ->build(object); } static void vips_foreign_save_matrix_file_class_init( VipsForeignSaveMatrixFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "matrixsave"; object_class->build = vips_foreign_save_matrix_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMatrixFile, filename), NULL); } static void vips_foreign_save_matrix_file_init(VipsForeignSaveMatrixFile *file) { } typedef struct _VipsForeignSaveMatrixTarget { VipsForeignSaveMatrix parent_object; VipsTarget *target; } VipsForeignSaveMatrixTarget; typedef VipsForeignSaveMatrixClass VipsForeignSaveMatrixTargetClass; G_DEFINE_TYPE(VipsForeignSaveMatrixTarget, vips_foreign_save_matrix_target, vips_foreign_save_matrix_get_type()); static int vips_foreign_save_matrix_target_build(VipsObject *object) { VipsForeignSaveMatrix *matrix = (VipsForeignSaveMatrix *) object; VipsForeignSaveMatrixTarget *target = (VipsForeignSaveMatrixTarget *) object; if (target->target) { matrix->target = target->target; g_object_ref(matrix->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_matrix_target_parent_class) ->build(object); } static void vips_foreign_save_matrix_target_class_init( VipsForeignSaveMatrixTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "matrixsave_target"; object_class->build = vips_foreign_save_matrix_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMatrixTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_matrix_target_init(VipsForeignSaveMatrixTarget *target) { } typedef struct _VipsForeignPrintMatrix { VipsForeignSaveMatrix parent_object; } VipsForeignPrintMatrix; typedef VipsForeignSaveClass VipsForeignPrintMatrixClass; G_DEFINE_TYPE(VipsForeignPrintMatrix, vips_foreign_print_matrix, vips_foreign_save_matrix_get_type()); static int vips_foreign_print_matrix_build(VipsObject *object) { VipsForeignSaveMatrix *matrix = (VipsForeignSaveMatrix *) object; if (!(matrix->target = vips_target_new_to_descriptor(1))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_print_matrix_parent_class) ->build(object); } static void vips_foreign_print_matrix_class_init(VipsForeignPrintMatrixClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "matrixprint"; object_class->description = _("print matrix"); object_class->build = vips_foreign_print_matrix_build; } static void vips_foreign_print_matrix_init(VipsForeignPrintMatrix *matrix) { } /** * vips_matrixsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write @in to @filename in matrix format. See [ctor@Image.matrixload] for a * description of the format. * * ::: seealso * [ctor@Image.matrixload]. * * Returns: 0 on success, -1 on error. */ int vips_matrixsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("matrixsave", ap, in, filename); va_end(ap); return result; } /** * vips_matrixsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.matrixsave], but save to a target. * * ::: seealso * [method@Image.matrixsave]. * * Returns: 0 on success, -1 on error. */ int vips_matrixsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("matrixsave_target", ap, in, target); va_end(ap); return result; } /** * vips_matrixprint: (method) * @in: image to print * @...: `NULL`-terminated list of optional named arguments * * Print @in to %stdout in matrix format. See [ctor@Image.matrixload] for a * description of the format. * * ::: seealso * [ctor@Image.matrixload]. * * Returns: 0 on success, -1 on error. */ int vips_matrixprint(VipsImage *in, ...) { va_list ap; int result; va_start(ap, in); result = vips_call_split("matrixprint", ap, in); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/meson.build000066400000000000000000000046361516303661500205440ustar00rootroot00000000000000if get_option('nsgif') subdir('libnsgif') endif foreign_sources = files( 'archive.c', 'analyze2vips.c', 'analyzeload.c', 'cairo.c', 'cgifsave.c', 'csvload.c', 'csvsave.c', 'dcrawload.c', 'dzsave.c', 'exif.c', 'fits.c', 'fitsload.c', 'fitssave.c', 'foreign.c', 'jp2kload.c', 'jp2ksave.c', 'jpeg2vips.c', 'jpegload.c', 'jpegsave.c', 'magickload.c', 'magicksave.c', 'matlab.c', 'matload.c', 'matrixload.c', 'matrixsave.c', 'niftiload.c', 'niftisave.c', 'nsgifload.c', 'openexr2vips.c', 'openexrload.c', 'pdf.c', 'pdfiumload.c', 'pngload.c', 'pngsave.c', 'ppmload.c', 'ppmsave.c', 'quantise.c', 'radiance.c', 'radload.c', 'radsave.c', 'rawload.c', 'rawsave.c', 'spngload.c', 'spngsave.c', 'svgload.c', 'tiff2vips.c', 'tiff.c', 'tiffload.c', 'tiffsave.c', 'uhdrload.c', 'uhdrsave.c', 'vips2jpeg.c', 'vips2tiff.c', 'vipsload.c', 'vipspng.c', 'vipssave.c', 'webp2vips.c', 'webpload.c', 'webpsave.c', ) foreign_headers = files( 'dbh.h', 'jpeg.h', 'pforeign.h', 'quantise.h', 'tiff.h', ) # We still need to include the GObject part of a loader/saver # if it is not built as a dynamically loadable module. magick_module_sources = files( 'magick.c', 'magick6load.c', 'magick7load.c', 'vips2magick.c', ) magick_module_headers = files( 'magick.h', ) if not magick_module foreign_sources += magick_module_sources foreign_headers += magick_module_headers endif jpeg_xl_module_sources = files( 'jxlload.c', 'jxlsave.c', ) if not libjxl_module foreign_sources += jpeg_xl_module_sources endif heif_module_sources = files( 'heifload.c', 'heifsave.c', ) if not libheif_module foreign_sources += heif_module_sources endif poppler_module_sources = files( 'popplerload.c', 'pdf.c', ) if not libpoppler_module foreign_sources += poppler_module_sources endif openslide_module_sources = files( 'openslideload.c', 'openslideconnection.c', ) if not openslide_module foreign_sources += openslide_module_sources endif libvips_sources += foreign_sources foreign_lib = static_library('foreign', foreign_sources, foreign_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += foreign_lib libvips-8.18.2/libvips/foreign/niftiload.c000066400000000000000000000534501516303661500205150ustar00rootroot00000000000000/* load nifti from a file * * 29/6/18 * - from fitsload.c * 9/9/19 * - use double for all floating point scalar metadata, like other loaders * - remove stray use of "n" property */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define VIPS_DEBUG */ /* TODO * * - for uncompressed images, we could do direct mapping of the input * - perhaps we could stream compressed images? but only if ext is defined at * the start of the file * (yes, file format is magic number, 348-byte header, extension data, * pixel data, then all gz'd) * - we could use the much faster byteswap in glib? * - I have not been able to test the ext stuff :( * * There should be at least a x2 speedup possible. */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_NIFTI #include #include "pforeign.h" typedef struct _VipsForeignLoadNifti { VipsForeignLoad parent_object; /* Source to load from (set by subclasses). */ VipsSource *source; /* Filename from source. */ const char *filename; /* The NIFTI image loaded to memory. */ nifti_image *nim; /* Wrap this VipsImage around the NIFTI pointer, then redirect read * requests to that. Saves a copy. */ VipsImage *memory; } VipsForeignLoadNifti; typedef VipsForeignLoadClass VipsForeignLoadNiftiClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadNifti, vips_foreign_load_nifti, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_nifti_dispose(GObject *gobject) { VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) gobject; VIPS_UNREF(nifti->source); VIPS_UNREF(nifti->memory); VIPS_FREEF(nifti_image_free, nifti->nim); G_OBJECT_CLASS(vips_foreign_load_nifti_parent_class)->dispose(gobject); } static int vips_foreign_load_nifti_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) object; /* We can only open source which have an associated filename, since * the nifti library works in terms of filenames. */ if (nifti->source) { VipsConnection *connection = VIPS_CONNECTION(nifti->source); const char *filename; if (!vips_source_is_file(nifti->source) || !(filename = vips_connection_filename(connection))) { vips_error(class->nickname, "%s", _("no filename available")); return -1; } nifti->filename = filename; } return VIPS_OBJECT_CLASS(vips_foreign_load_nifti_parent_class) ->build(object); } /* Map DT_* datatype values to VipsBandFormat. */ typedef struct _VipsForeignDT2Vips { int datatype; VipsBandFormat fmt; } VipsForeignDT2Vips; static VipsForeignDT2Vips vips_foreign_nifti_DT2Vips[] = { { DT_UINT8, VIPS_FORMAT_UCHAR }, { DT_INT8, VIPS_FORMAT_CHAR }, { DT_UINT16, VIPS_FORMAT_USHORT }, { DT_INT16, VIPS_FORMAT_SHORT }, { DT_UINT32, VIPS_FORMAT_UINT }, { DT_INT32, VIPS_FORMAT_INT }, { DT_FLOAT32, VIPS_FORMAT_FLOAT }, { DT_FLOAT64, VIPS_FORMAT_DOUBLE }, { DT_COMPLEX64, VIPS_FORMAT_COMPLEX }, { DT_COMPLEX128, VIPS_FORMAT_DPCOMPLEX }, { DT_RGB, VIPS_FORMAT_UCHAR }, { DT_RGBA32, VIPS_FORMAT_UCHAR } }; VipsBandFormat vips__foreign_nifti_datatype2BandFmt(int datatype) { int i; for (i = 0; i < VIPS_NUMBER(vips_foreign_nifti_DT2Vips); i++) if (vips_foreign_nifti_DT2Vips[i].datatype == datatype) return vips_foreign_nifti_DT2Vips[i].fmt; return VIPS_FORMAT_NOTSET; } int vips__foreign_nifti_BandFmt2datatype(VipsBandFormat fmt) { int i; for (i = 0; i < VIPS_NUMBER(vips_foreign_nifti_DT2Vips); i++) if (vips_foreign_nifti_DT2Vips[i].fmt == fmt) return vips_foreign_nifti_DT2Vips[i].datatype; return -1; } /* All the header fields we attach as metadata. */ typedef struct _VipsForeignNiftiFields { char *name; GType type; glong offset; } VipsForeignNiftiFields; static VipsForeignNiftiFields vips_foreign_nifti_fields[] = { /* The first 8 must be the dims[] fields, see * vips_foreign_save_nifti_make_nim(). */ { "ndim", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, ndim) }, { "nx", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nx) }, { "ny", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, ny) }, { "nz", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nz) }, { "nt", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nt) }, { "nu", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nu) }, { "nv", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nv) }, { "nw", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nw) }, { "dx", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, dx) }, { "dy", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, dy) }, { "dz", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, dz) }, { "dt", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, dt) }, { "du", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, du) }, { "dv", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, dv) }, { "dw", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, dw) }, { "scl_slope", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, scl_slope) }, { "scl_inter", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, scl_inter) }, { "cal_min", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, cal_min) }, { "cal_max", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, cal_max) }, { "qform_code", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, qform_code) }, { "sform_code", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, sform_code) }, { "freq_dim", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, freq_dim) }, { "phase_dim", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, phase_dim) }, { "slice_dim", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, slice_dim) }, { "slice_code", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, slice_code) }, { "slice_start", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, slice_start) }, { "slice_end", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, slice_end) }, { "slice_duration", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, slice_duration) }, { "quatern_b", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, quatern_b) }, { "quatern_c", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, quatern_c) }, { "quatern_d", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, quatern_d) }, { "qoffset_x", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, qoffset_x) }, { "qoffset_y", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, qoffset_y) }, { "qoffset_z", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, qoffset_z) }, { "qfac", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, qfac) }, { "sto_xyz00", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[0][0]) }, { "sto_xyz01", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[0][1]) }, { "sto_xyz02", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[0][2]) }, { "sto_xyz03", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[0][3]) }, { "sto_xyz10", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[1][0]) }, { "sto_xyz11", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[1][1]) }, { "sto_xyz12", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[1][2]) }, { "sto_xyz13", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[1][3]) }, { "sto_xyz20", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[2][0]) }, { "sto_xyz21", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[2][1]) }, { "sto_xyz22", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[2][2]) }, { "sto_xyz23", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[2][3]) }, { "sto_xyz30", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[3][0]) }, { "sto_xyz31", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[3][1]) }, { "sto_xyz32", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[3][2]) }, { "sto_xyz33", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, sto_xyz.m[3][3]) }, { "toffset", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, toffset) }, { "xyz_units", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, xyz_units) }, { "time_units", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, time_units) }, { "nifti_type", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, nifti_type) }, { "intent_code", G_TYPE_INT, G_STRUCT_OFFSET(nifti_image, intent_code) }, { "intent_p1", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, intent_p1) }, { "intent_p2", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, intent_p2) }, { "intent_p3", G_TYPE_DOUBLE, G_STRUCT_OFFSET(nifti_image, intent_p3) }, }; void * vips__foreign_nifti_map(VipsNiftiMapFn fn, void *a, void *b) { int i; void *result; for (i = 0; i < VIPS_NUMBER(vips_foreign_nifti_fields); i++) { GValue value = G_VALUE_INIT; g_value_init(&value, vips_foreign_nifti_fields[i].type); result = fn(vips_foreign_nifti_fields[i].name, &value, vips_foreign_nifti_fields[i].offset, a, b); g_value_unset(&value); if (result) return result; } return NULL; } /* How I wish glib had something like this :( Just implement the ones we need * for vips_foreign_nifti_fields above. */ static void vips_gvalue_read(GValue *value, void *p) { switch (G_VALUE_TYPE(value)) { case G_TYPE_INT: g_value_set_int(value, *((int *) p)); break; case G_TYPE_DOUBLE: /* We set as double rather than float, as things like pyvips * expect double for metadata items. */ g_value_set_double(value, *((float *) p)); break; default: g_warning("vips_gvalue_read: unsupported GType %s", g_type_name(G_VALUE_TYPE(value))); } } static void * vips_foreign_load_nifti_set(const char *name, GValue *value, glong offset, void *a, void *b) { nifti_image *nim = (nifti_image *) a; VipsImage *out = VIPS_IMAGE(b); char vips_name[256]; vips_gvalue_read(value, (char *) nim + offset); g_snprintf(vips_name, 256, "nifti-%s", name); vips_image_set(out, vips_name, value); return NULL; } static int vips_foreign_load_nifti_set_header(VipsForeignLoadNifti *nifti, nifti_image *nim, VipsImage *out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(nifti); guint width; guint height; guint bands; VipsBandFormat fmt; double xres; double yres; int i; char txt[256]; if (nim->ndim < 1 || nim->ndim > 7) { vips_error(class->nickname, _("%d-dimensional images not supported"), nim->ndim); return 0; } for (i = 1; i < 8 && i < nim->ndim + 1; i++) { if (nim->dim[i] <= 0) { vips_error(class->nickname, "%s", _("invalid dimension")); return 0; } /* If we have several images in a dimension, the spacing must * be non-zero or we'll get a /0 error in resolution * calculation. */ if (nim->dim[i] > 1 && nim->pixdim[i] == 0) { vips_error(class->nickname, "%s", _("invalid resolution")); return 0; } } /* Unfold higher dimensions vertically. bands is updated below for * DT_RGB. Be careful to avoid height going over 2^31. */ bands = 1; width = (guint) nim->nx; height = (guint) nim->ny; for (i = 3; i < 8 && i < nim->ndim + 1; i++) if (!g_uint_checked_mul(&height, height, nim->dim[i])) { vips_error(class->nickname, "%s", _("dimension overflow")); return 0; } if (height > INT_MAX) { vips_error(class->nickname, "%s", _("dimension overflow")); return 0; } fmt = vips__foreign_nifti_datatype2BandFmt(nim->datatype); if (fmt == VIPS_FORMAT_NOTSET) { vips_error(class->nickname, _("datatype %d not supported"), nim->datatype); return -1; } if (nim->datatype == DT_RGB) bands = 3; if (nim->datatype == DT_RGBA32) bands = 4; /* We fold y and z together, so they must have the same resolution.. */ xres = 1.0; yres = 1.0; if (nim->nz == 1 || nim->dz == nim->dy) switch (nim->xyz_units) { case NIFTI_UNITS_METER: xres = 1000.0 / nim->dx; yres = 1000.0 / nim->dy; break; case NIFTI_UNITS_MM: xres = 1.0 / nim->dx; yres = 1.0 / nim->dy; break; case NIFTI_UNITS_MICRON: xres = 1.0 / (1000.0 * nim->dx); yres = 1.0 / (1000.0 * nim->dy); break; default: break; } #ifdef DEBUG printf("get_vips_properties: width = %d\n", width); printf("get_vips_properties: height = %d\n", height); printf("get_vips_properties: bands = %d\n", bands); printf("get_vips_properties: fmt = %d\n", fmt); #endif /*DEBUG*/ /* We load to memory then write to out, so we'll hint THINSTRIP. */ vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL); vips_image_init_fields(out, width, height, bands, fmt, VIPS_CODING_NONE, bands == 1 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB, xres, yres); /* Set some vips metadata for every nifti header field. */ if (vips__foreign_nifti_map(vips_foreign_load_nifti_set, nim, out)) return -1; /* One byte longer than the spec to leave space for any extra * '\0' termination. */ g_strlcpy(txt, nim->intent_name, 17); vips_image_set_string(out, "nifti-intent_name", txt); g_strlcpy(txt, nim->descrip, 81); vips_image_set_string(out, "nifti-descrip", txt); for (i = 0; i < nim->num_ext; i++) { nifti1_extension *ext = &nim->ext_list[i]; g_snprintf(txt, 256, "nifti-ext-%d-%d", i, ext->ecode); vips_image_set_blob_copy(out, txt, ext->edata, ext->esize); } vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, nim->ny); return 0; } static int vips_foreign_load_nifti_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) load; /* We can't use the (much faster) nifti_read_header() since it just * reads the 348 bytes of the analyze struct and does not read any of * the extension fields. */ /* FALSE means don't read data, just the header. Use * nifti_image_load() later to pull the data in. */ if (!(nifti->nim = nifti_image_read(nifti->filename, FALSE))) { vips_error(class->nickname, "%s", _("unable to read NIFTI header")); return 0; } if (vips_foreign_load_nifti_set_header(nifti, nifti->nim, load->out)) { return -1; } VIPS_SETSTR(load->out->filename, nifti->filename); return 0; } static int vips_foreign_load_nifti_load(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) load; #ifdef DEBUG printf("vips_foreign_load_nifti_load: loading image\n"); #endif /*DEBUG*/ /* We just read the entire image to memory. */ if (nifti_image_load(nifti->nim)) { vips_error(class->nickname, "%s", _("unable to load NIFTI file")); return -1; } if (!(nifti->memory = vips_image_new_from_memory( nifti->nim->data, VIPS_IMAGE_SIZEOF_IMAGE(load->out), load->out->Xsize, load->out->Ysize, load->out->Bands, load->out->BandFmt))) return -1; if (vips_image_write(nifti->memory, load->real)) return -1; return 0; } static void vips_foreign_load_nifti_class_init(VipsForeignLoadNiftiClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_nifti_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "niftiload_base"; object_class->description = _("load a NIFTI image"); object_class->build = vips_foreign_load_nifti_build; /* nificlib has not been fuzzed, so should not be used with * untrusted input unless you are very careful. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; load_class->header = vips_foreign_load_nifti_header; load_class->load = vips_foreign_load_nifti_load; } static void vips_foreign_load_nifti_init(VipsForeignLoadNifti *nifti) { } typedef struct _VipsForeignLoadNiftiFile { VipsForeignLoadNifti parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadNiftiFile; typedef VipsForeignLoadNiftiClass VipsForeignLoadNiftiFileClass; G_DEFINE_TYPE(VipsForeignLoadNiftiFile, vips_foreign_load_nifti_file, vips_foreign_load_nifti_get_type()); static int vips_foreign_load_nifti_file_build(VipsObject *object) { VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) object; VipsForeignLoadNiftiFile *file = (VipsForeignLoadNiftiFile *) object; if (file->filename && !(nifti->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_nifti_file_parent_class) ->build(object); } const char *vips_foreign_nifti_suffs[] = { ".nii", ".nii.gz", ".hdr", ".hdr.gz", ".img", ".img.gz", ".nia", ".nia.gz", NULL }; static int vips_foreign_load_nifti_is_a(const char *filename) { char *hfile; znzFile fp; nifti_1_header nhdr; /* Unfortunately is_nifti_file() is very slow and produces lots of * output. We have to make our own. */ if (!(hfile = nifti_findhdrname(filename))) return 0; fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if (znz_isnull(fp)) { free(hfile); return 0; } free(hfile); (void) znzread(&nhdr, 1, sizeof(nhdr), fp); znzclose(fp); /* Test for sanity both ways around. There's a thing to test for byte * order in niftilib, but it's static :( */ if (nifti_hdr_looks_good(&nhdr)) return 1; swap_nifti_header(&nhdr, FALSE); if (nifti_hdr_looks_good(&nhdr)) return 1; return 0; } static void vips_foreign_load_nifti_file_class_init( VipsForeignLoadNiftiFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "niftiload"; object_class->description = _("load NIfTI volume"); object_class->build = vips_foreign_load_nifti_file_build; foreign_class->suffs = vips_foreign_nifti_suffs; load_class->is_a = vips_foreign_load_nifti_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNiftiFile, filename), NULL); } static void vips_foreign_load_nifti_file_init(VipsForeignLoadNiftiFile *nifti) { } typedef struct _VipsForeignLoadNiftiSource { VipsForeignLoadNifti parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadNiftiSource; typedef VipsForeignLoadNiftiClass VipsForeignLoadNiftiSourceClass; G_DEFINE_TYPE(VipsForeignLoadNiftiSource, vips_foreign_load_nifti_source, vips_foreign_load_nifti_get_type()); static int vips_foreign_load_nifti_source_build(VipsObject *object) { VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) object; VipsForeignLoadNiftiSource *source = (VipsForeignLoadNiftiSource *) object; if (source->source) { nifti->source = source->source; g_object_ref(nifti->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_nifti_source_parent_class) ->build(object); } static gboolean vips_foreign_load_nifti_source_is_a_source(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); const char *filename; return vips_source_is_file(source) && (filename = vips_connection_filename(connection)) && vips_foreign_load_nifti_is_a(filename); } static void vips_foreign_load_nifti_source_class_init( VipsForeignLoadNiftiSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "niftiload_source"; object_class->description = _("load NIfTI volumes"); object_class->build = vips_foreign_load_nifti_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_nifti_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNiftiSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_nifti_source_init( VipsForeignLoadNiftiSource *nifti) { } #endif /*HAVE_NIFTI*/ /** * vips_niftiload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a NIFTI image file into a VIPS image. * * NIFTI metadata is attached with the "nifti-" prefix. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_niftiload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("niftiload", ap, filename, out); va_end(ap); return result; } /** * vips_niftiload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.niftiload], but read from a source. * * Returns: 0 on success, -1 on error. */ int vips_niftiload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("niftiload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/niftisave.c000066400000000000000000000255141516303661500205340ustar00rootroot00000000000000/* save to nifti * * 5/7/18 * - from fitssave.c * 9/9/19 * - use double for all floating point scalar metadata, like other loaders */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef HAVE_NIFTI #include #include "pforeign.h" typedef struct _VipsForeignSaveNifti { VipsForeignSave parent_object; /* Filename for save. */ char *filename; nifti_image *nim; } VipsForeignSaveNifti; typedef VipsForeignSaveClass VipsForeignSaveNiftiClass; G_DEFINE_TYPE(VipsForeignSaveNifti, vips_foreign_save_nifti, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_nifti_dispose(GObject *gobject) { VipsForeignSaveNifti *nifti = (VipsForeignSaveNifti *) gobject; VIPS_FREEF(nifti_image_free, nifti->nim); G_OBJECT_CLASS(vips_foreign_save_nifti_parent_class)->dispose(gobject); } /* Make ->nim from the vips header fields. */ static int vips_foreign_save_nifti_header_vips(VipsForeignSaveNifti *nifti, VipsImage *image) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(nifti); int dims[8]; int datatype; int i; /* Most nifti images have this defaulted as 1. */ for (i = 0; i < VIPS_NUMBER(dims); i++) dims[i] = 1; dims[0] = 2; dims[1] = image->Xsize; dims[2] = vips_image_get_page_height(image); /* Multipage image? */ if (dims[2] < image->Ysize) { dims[0] = 3; dims[3] = image->Ysize / dims[2]; } datatype = vips__foreign_nifti_BandFmt2datatype(image->BandFmt); if (datatype == -1) { vips_error(class->nickname, "%s", _("unsupported libvips image type")); return -1; } if (image->Bands > 1) { if (image->BandFmt != VIPS_FORMAT_UCHAR) { vips_error(class->nickname, "%s", _("8-bit colour images only")); return -1; } if (image->Bands == 3) datatype = DT_RGB; else if (image->Bands == 4) datatype = DT_RGBA32; else { vips_error(class->nickname, "%s", _("3 or 4 band colour images only")); return -1; } } if (!(nifti->nim = nifti_make_new_nim(dims, datatype, FALSE))) return -1; nifti->nim->dx = 1.0 / image->Xres; nifti->nim->dy = 1.0 / image->Yres; nifti->nim->dz = 1.0 / image->Yres; nifti->nim->xyz_units = NIFTI_UNITS_MM; g_snprintf(nifti->nim->descrip, sizeof(nifti->nim->descrip), "libvips-%s", VIPS_VERSION); /* All other fields can stay at their default value. */ return 0; } typedef struct _VipsNdimInfo { VipsImage *image; nifti_image *nim; int *dims; int n; } VipsNdimInfo; static void * vips_foreign_save_nifti_set_dims(const char *name, GValue *value, glong offset, void *a, void *b) { VipsNdimInfo *info = (VipsNdimInfo *) a; /* The first 8 members are the dims fields. */ if (info->n < 8) { char vips_name[256]; int i; g_snprintf(vips_name, 256, "nifti-%s", name); if (vips_image_get_int(info->image, vips_name, &i) || i <= 0 || i >= VIPS_MAX_COORD) return info; info->dims[info->n] = i; } info->n += 1; return NULL; } /* How I wish glib had something like this :( Just implement the ones we need * for vips_foreign_nifti_fields above. */ static void vips_gvalue_write(GValue *value, void *p) { switch (G_VALUE_TYPE(value)) { case G_TYPE_INT: *((int *) p) = g_value_get_int(value); break; case G_TYPE_DOUBLE: *((float *) p) = g_value_get_double(value); break; default: g_warning("vips_gvalue_write: unsupported GType %s", g_type_name(G_VALUE_TYPE(value))); } } static void * vips_foreign_save_nifti_set_fields(const char *name, GValue *value, glong offset, void *a, void *b) { VipsNdimInfo *info = (VipsNdimInfo *) a; /* The first 8 members are the dims fields. We set them above ^^^ -- * do the others in this pass. */ if (info->n >= 8) { char vips_name[256]; GValue value_copy = G_VALUE_INIT; g_snprintf(vips_name, 256, "nifti-%s", name); if (vips_image_get(info->image, vips_name, &value_copy)) return info; vips_gvalue_write(&value_copy, (char *) info->nim + offset); g_value_unset(&value_copy); } info->n += 1; return NULL; } static void * vips_foreign_save_nifti_ext(VipsImage *image, const char *field, GValue *value, void *a) { nifti_image *nim = (nifti_image *) a; int i; int ecode; char *data; size_t length; if (!vips_isprefix("nifti-ext-", field)) return NULL; /* The name is "nifti-ext-N-XX" where N is the index (discard this) * and XX is the nifti ext ecode. */ if (sscanf(field, "nifti-ext-%d-%d", &i, &ecode) != 2) { vips_error("niftisave", "%s", _("bad nifti-ext- field name")); return image; } if (vips_image_get_blob(image, field, (void *) &data, &length)) return image; if (nifti_add_extension(nim, data, length, ecode)) { vips_error("niftisave", "%s", _("unable to attach nifti ext")); return image; } return NULL; } /* Make ->nim from the nifti- fields. */ static int vips_foreign_save_nifti_header_nifti(VipsForeignSaveNifti *nifti, VipsImage *image) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(nifti); VipsNdimInfo info; int dims[8]; int datatype; guint height; int i; /* Most nifti images have this defaulted as 1. */ for (i = 0; i < VIPS_NUMBER(dims); i++) dims[i] = 1; info.image = image; info.dims = dims; info.n = 0; if (vips__foreign_nifti_map( vips_foreign_save_nifti_set_dims, &info, NULL)) return -1; /* page-height overrides ny if it makes sense. This might not be * correct :( */ dims[2] = vips_image_get_page_height(image); /* Multipage image? */ if (dims[2] < image->Ysize) { dims[0] = 3; dims[3] = image->Ysize / dims[2]; } height = 1; for (i = 2; i < VIPS_NUMBER(dims) && i < dims[0] + 1; i++) if (!g_uint_checked_mul(&height, height, dims[i])) { vips_error(class->nickname, "%s", _("dimension overflow")); return 0; } if (image->Xsize != dims[1] || image->Ysize != height) { vips_error(class->nickname, "%s", _("bad image dimensions")); return -1; } datatype = vips__foreign_nifti_BandFmt2datatype(image->BandFmt); if (datatype == -1) { vips_error(class->nickname, "%s", _("unsupported libvips image type")); return -1; } if (!(nifti->nim = nifti_make_new_nim(dims, datatype, FALSE))) return -1; info.image = image; info.nim = nifti->nim; info.n = 0; if (vips__foreign_nifti_map( vips_foreign_save_nifti_set_fields, &info, NULL)) return -1; /* Attach any ext blocks. */ if (vips_image_map(image, (VipsImageMapFn) vips_foreign_save_nifti_ext, nifti->nim)) return -1; return 0; } static int vips_foreign_save_nifti_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveNifti *nifti = (VipsForeignSaveNifti *) object; if (VIPS_OBJECT_CLASS(vips_foreign_save_nifti_parent_class)->build(object)) return -1; /* This could be an image (indirectly) from niftiload, or something * like OME_TIFF, which does not have all the "nifti-ndim" fields. * * If it doesn't look like a nifti, try to make a nifti header from * what we have. */ if (vips_image_get_typeof(save->ready, "nifti-ndim")) { if (vips_foreign_save_nifti_header_nifti(nifti, save->ready)) return -1; } else { if (vips_foreign_save_nifti_header_vips(nifti, save->ready)) return -1; } /* set ext, plus other stuff */ if (nifti_set_filenames(nifti->nim, nifti->filename, FALSE, TRUE)) { vips_error(class->nickname, "%s", _("unable to set nifti filename")); return -1; } if (!(nifti->nim->data = vips_image_write_to_memory(save->ready, NULL))) return -1; /* No return code!??!?!! */ nifti_image_write(nifti->nim); /* We must free and NULL the pointer or nifti will try to free it for * us. */ VIPS_FREE(nifti->nim->data); return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat vips_nifti_bandfmt[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, C, US, S, UI, I, F, X, D, DX }; static void vips_foreign_save_nifti_class_init(VipsForeignSaveNiftiClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_nifti_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "niftisave"; object_class->description = _("save image to nifti file"); object_class->build = vips_foreign_save_nifti_build; /* nificlib has not been fuzzed, so should not be used with * untrusted input unless you are very careful. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips_foreign_nifti_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->format_table = vips_nifti_bandfmt; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveNifti, filename), NULL); } static void vips_foreign_save_nifti_init(VipsForeignSaveNifti *nifti) { } #endif /*HAVE_NIFTI*/ /** * vips_niftisave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file in NIFTI format. * * Use the various NIFTI suffixes to pick the nifti save format. * * ::: seealso * [method@Image.write_to_file], [ctor@Image.niftiload]. * * Returns: 0 on success, -1 on error. */ int vips_niftisave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("niftisave", ap, in, filename); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/nsgifload.c000066400000000000000000000621361516303661500205130ustar00rootroot00000000000000/* load a GIF with libnsgif * * 6/10/18 * - from gifload.c * 3/3/22 tlsa * - update libnsgif API * 9/5/22 * - attach GIF palette as metadata * 26/11/22 kleisauke * - avoid minimise after mapping -- not reliable on Win32 * 25/1/23 kleisauke * - set interlaced=1 for interlaced images * 13/3/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VERBOSE #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include /* TODO: * * - libnsgif does not seem to support comment metadata * * - it always loads the entire source file into memory * * Notes: * * - hard to detect mono images -- local_colour_table in libnsgif is only set * when we decode a frame, so we can't tell just from init whether any * frames have colour info */ #ifdef HAVE_NSGIF #include #define VIPS_TYPE_FOREIGN_LOAD_GIF (vips_foreign_load_nsgif_get_type()) #define VIPS_FOREIGN_LOAD_GIF(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_LOAD_GIF, VipsForeignLoadNsgif)) #define VIPS_FOREIGN_LOAD_GIF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN_LOAD_GIF, VipsForeignLoadNsgifClass)) #define VIPS_IS_FOREIGN_LOAD_GIF(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN_LOAD_GIF)) #define VIPS_IS_FOREIGN_LOAD_GIF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN_LOAD_GIF)) #define VIPS_FOREIGN_LOAD_GIF_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN_LOAD_GIF, VipsForeignLoadNsgifClass)) typedef struct _VipsForeignLoadNsgif { VipsForeignLoad parent_object; /* Load this page (frame number). */ int page; /* Load this many pages. */ int n; /* Load from this source (set by subclasses). */ VipsSource *source; /* The animation created by libnsgif. */ nsgif_t *anim; /* The data/size pair we pass to libnsgif. */ unsigned char *data; size_t size; /* Information about the current GIF. */ const nsgif_info_t *info; /* Delays between frames (in milliseconds). Array of length * @info->frame_count. */ int *delay; /* A single centisecond value for compatibility. */ int gif_delay; /* n, ready for libnsgif. */ int gif_n; /* If the GIF contains any frames with transparent elements. */ gboolean has_transparency; /* If the GIF has any interlaced frames. */ gboolean interlaced; /* If the GIF has any local palettes. */ gboolean local_palette; /* The current frame bitmap and the frame number for it. */ nsgif_bitmap_t *bitmap; int frame_number; } VipsForeignLoadNsgif; typedef VipsForeignLoadClass VipsForeignLoadNsgifClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadNsgif, vips_foreign_load_nsgif, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_nsgif_error(VipsForeignLoadNsgif *gif, nsgif_error result) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(gif); vips_error(class->nickname, "%s", nsgif_strerror(result)); } static void vips_foreign_load_nsgif_dispose(GObject *gobject) { VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) gobject; VIPS_DEBUG_MSG("vips_foreign_load_nsgif_dispose:\n"); VIPS_FREEF(nsgif_destroy, gif->anim); VIPS_UNREF(gif->source); VIPS_FREE(gif->delay); G_OBJECT_CLASS(vips_foreign_load_nsgif_parent_class)->dispose(gobject); } static VipsForeignFlags vips_foreign_load_nsgif_get_flags_filename(const char *filename) { return VIPS_FOREIGN_SEQUENTIAL; } static VipsForeignFlags vips_foreign_load_nsgif_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_SEQUENTIAL; } static gboolean vips_foreign_load_nsgif_is_a_source(VipsSource *source) { const unsigned char *data; if ((data = vips_source_sniff(source, 4)) && data[0] == 'G' && data[1] == 'I' && data[2] == 'F' && data[3] == '8') return TRUE; return FALSE; } #ifdef VERBOSE static void print_frame(const nsgif_frame_info_t *frame_info) { if (frame_info == NULL) return; printf("frame_info:\n"); printf(" display = %d\n", frame_info->display); printf(" local_palette = %d\n", frame_info->local_palette); printf(" transparency = %d\n", frame_info->transparency); printf(" interlaced = %d\n", frame_info->interlaced); printf(" disposal = %d (%s)\n", frame_info->disposal, nsgif_str_disposal(frame_info->disposal)); printf(" delay = %d\n", frame_info->delay); printf(" rect.x0 = %u\n", frame_info->rect.x0); printf(" rect.y0 = %u\n", frame_info->rect.y0); printf(" rect.x1 = %u\n", frame_info->rect.x1); printf(" rect.y1 = %u\n", frame_info->rect.y1); } static void print_animation(nsgif_t *anim, const nsgif_info_t *info) { int i; const uint8_t *bg = (uint8_t *) &info->background; printf("animation:\n"); printf(" width = %d\n", info->width); printf(" height = %d\n", info->height); printf(" frame_count = %d\n", info->frame_count); printf(" global_palette = %d\n", info->global_palette); printf(" loop_max = %d\n", info->loop_max); printf(" background = %d %d %d %d\n", bg[0], bg[1], bg[2], bg[3]); for (i = 0; i < info->frame_count; i++) { printf("%d ", i); print_frame(nsgif_get_frame_info(anim, i)); } } #endif /*VERBOSE*/ static int vips_foreign_load_nsgif_set_header(VipsForeignLoadNsgif *gif, VipsImage *image) { double array[3]; const uint8_t *bg; size_t entries; uint32_t table[NSGIF_MAX_COLOURS]; int colours; VIPS_DEBUG_MSG("vips_foreign_load_nsgif_set_header:\n"); vips_image_init_fields(image, gif->info->width, gif->info->height * gif->gif_n, gif->has_transparency ? 4 : 3, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); vips_image_pipelinev(image, VIPS_DEMAND_STYLE_FATSTRIP, NULL); /* Only set page-height if we have more than one page, or this could * accidentally turn into an animated image later. */ if (gif->gif_n > 1) vips_image_set_int(image, VIPS_META_PAGE_HEIGHT, gif->info->height); vips_image_set_int(image, VIPS_META_N_PAGES, gif->info->frame_count); vips_image_set_int(image, "loop", gif->info->loop_max); vips_image_set_array_int(image, "delay", gif->delay, gif->info->frame_count); bg = (uint8_t *) &gif->info->background; array[0] = bg[0]; array[1] = bg[1]; array[2] = bg[2]; vips_image_set_array_double(image, "background", array, 3); VIPS_SETSTR(image->filename, vips_connection_filename(VIPS_CONNECTION(gif->source))); /* DEPRECATED "gif-loop" * * Not the correct behavior as loop=1 became gif-loop=0 * but we want to keep the old behavior untouched! */ vips_image_set_int(image, "gif-loop", gif->info->loop_max == 0 ? 0 : gif->info->loop_max - 1); /* The deprecated gif-delay field is in centiseconds. */ vips_image_set_int(image, "gif-delay", gif->gif_delay); /* If there are no local palettes, we can attach the global palette as * metadata. */ if (!gif->local_palette) { nsgif_global_palette(gif->anim, table, &entries); vips_image_set_array_int(image, "gif-palette", (const int *) table, entries); colours = entries; } else { int i; colours = 0; if (gif->info->global_palette) { nsgif_global_palette(gif->anim, table, &entries); colours = entries; } for (i = 0; i < gif->info->frame_count; i++) { if (nsgif_local_palette(gif->anim, i, table, &entries)) colours = VIPS_MAX(colours, entries); } } vips_image_set_int(image, VIPS_META_BITS_PER_SAMPLE, ceil(log2(colours))); /* Deprecated "palette-bit-depth" use "bits-per-sample" instead. */ vips_image_set_int(image, "palette-bit-depth", ceil(log2(colours))); vips_image_set_int(image, VIPS_META_PALETTE, 1); /* Let our caller know if the GIF is interlaced. */ if (gif->interlaced) vips_image_set_int(image, "interlaced", 1); return 0; } /* Scan the GIF as quickly as we can and extract transparency, bands, pages, * etc. * * Don't flag any errors unless we have to: we want to work for corrupt or * malformed GIFs. */ static int vips_foreign_load_nsgif_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) load; const void *data; size_t size; nsgif_error result; int i; VIPS_DEBUG_MSG("vips_foreign_load_nsgif_header:\n"); /* Map the whole source into memory. */ if (!(data = vips_source_map(gif->source, &size))) return -1; /* Treat errors from _scan() as warnings. If libnsgif really can't do * something it'll fail gracefully later when we try to read out * frame data. */ result = nsgif_data_scan(gif->anim, size, (void *) data); VIPS_DEBUG_MSG("nsgif_data_scan() = %s\n", nsgif_strerror(result)); switch (result) { case NSGIF_ERR_END_OF_DATA: if (load->fail_on >= VIPS_FAIL_ON_TRUNCATED) { vips_foreign_load_nsgif_error(gif, result); return -1; } else g_warning("%s", nsgif_strerror(result)); break; case NSGIF_OK: break; default: if (load->fail_on >= VIPS_FAIL_ON_WARNING) { vips_foreign_load_nsgif_error(gif, result); return -1; } else g_warning("%s", nsgif_strerror(result)); break; } /* Tell libnsgif that that's all the data we have. This will let us * read out any truncated final frames. */ nsgif_data_complete(gif->anim); gif->info = nsgif_get_info(gif->anim); #ifdef VERBOSE print_animation(gif->anim, gif->info); #endif /*VERBOSE*/ if (!gif->info->frame_count) { vips_error(class->nickname, "%s", _("no frames in GIF")); return -1; } /* Update our global struct based on the information in the * individual frames. */ for (i = 0; i < gif->info->frame_count; i++) { const nsgif_frame_info_t *frame_info; if ((frame_info = nsgif_get_frame_info(gif->anim, i))) { if (frame_info->transparency) gif->has_transparency = TRUE; if (frame_info->interlaced) gif->interlaced = TRUE; if (frame_info->local_palette) gif->local_palette = TRUE; } } if (gif->n == -1) gif->gif_n = gif->info->frame_count - gif->page; else gif->gif_n = gif->n; if (gif->page < 0 || gif->gif_n <= 0 || gif->page + gif->gif_n > gif->info->frame_count) { vips_error(class->nickname, "%s", _("bad page number")); return -1; } /* In ms, frame_delay in cs. */ VIPS_FREE(gif->delay); if (!(gif->delay = VIPS_ARRAY(NULL, gif->info->frame_count, int))) return -1; for (i = 0; i < gif->info->frame_count; i++) { const nsgif_frame_info_t *frame_info; frame_info = nsgif_get_frame_info(gif->anim, i); if (frame_info == NULL) { vips_error(class->nickname, "%s", _("bad frame")); return -1; } gif->delay[i] = 10 * frame_info->delay; } gif->gif_delay = gif->delay[0] / 10; vips_foreign_load_nsgif_set_header(gif, load->out); return 0; } static int vips_foreign_load_nsgif_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) a; int y; #ifdef VERBOSE VIPS_DEBUG_MSG("vips_foreign_load_nsgif_generate: " "top = %d, height = %d\n", r->top, r->height); #endif /*VERBOSE*/ for (y = 0; y < r->height; y++) { /* The page for this output line, and the line number in page. */ int page = (r->top + y) / gif->info->height + gif->page; int line = (r->top + y) % gif->info->height; nsgif_error result; VipsPel *p, *q; g_assert(line >= 0 && line < gif->info->height); g_assert(page >= 0 && page < gif->info->frame_count); if (gif->frame_number != page) { result = nsgif_frame_decode(gif->anim, page, &gif->bitmap); VIPS_DEBUG_MSG(" nsgif_frame_decode(%d) = %d\n", page, result); if (result != NSGIF_OK) { vips_foreign_load_nsgif_error(gif, result); return -1; } #ifdef VERBOSE print_frame(nsgif_get_frame_info(gif->anim, page)); #endif /*VERBOSE*/ gif->frame_number = page; } p = (VipsPel *) gif->bitmap + (size_t) line * gif->info->width * sizeof(int); q = VIPS_REGION_ADDR(out_region, 0, r->top + y); if (gif->has_transparency) memcpy(q, p, VIPS_REGION_SIZEOF_LINE(out_region)); else { int i; for (i = 0; i < r->width; i++) { q[0] = p[0]; q[1] = p[1]; q[2] = p[2]; q += 3; p += 4; } } } return 0; } int vips_foreign_load_nsgif_tile_height(VipsForeignLoadNsgif *gif) { int height = gif->info->height; int i; /* First, check the perfect size. */ if (height % 16 == 0) return 16; /* Next, check larger and smaller sizes. */ for (i = 1; i < 16; i++) { if (height % (16 + i) == 0) return 16 + i; if (height % (16 - i) == 0) return 16 - i; } return 1; } static int vips_foreign_load_nsgif_load(VipsForeignLoad *load) { VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) load; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(load), 2); VIPS_DEBUG_MSG("vips_foreign_load_nsgif_load:\n"); /* Make the output pipeline. */ t[0] = vips_image_new(); if (vips_foreign_load_nsgif_set_header(gif, t[0])) return -1; /* Strips 8 pixels high to avoid too many tiny regions. */ if (vips_image_generate(t[0], NULL, vips_foreign_load_nsgif_generate, NULL, gif, NULL) || vips_sequential(t[0], &t[1], "tile_height", vips_foreign_load_nsgif_tile_height(gif), NULL) || vips_image_write(t[1], load->real)) return -1; return 0; } static void vips_foreign_load_nsgif_class_init(VipsForeignLoadNsgifClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_nsgif_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifload_base"; object_class->description = _("load GIF with libnsgif"); /* High priority, so that we handle vipsheader etc. */ foreign_class->priority = 50; load_class->get_flags_filename = vips_foreign_load_nsgif_get_flags_filename; load_class->get_flags = vips_foreign_load_nsgif_get_flags; load_class->header = vips_foreign_load_nsgif_header; load_class->load = vips_foreign_load_nsgif_load; VIPS_ARG_INT(class, "page", 10, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNsgif, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 6, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNsgif, n), -1, 100000, 1); } static void * vips_foreign_load_nsgif_bitmap_create(int width, int height) { /* GIF has a limit of 64k per axis -- double-check this. * * gifsave also enforces a pixel count limit, apply the same * constraint here. */ if (width <= 0 || width > 65535 || height <= 0 || height > 65535 || (guint64) width * height > INT_MAX / 4) { vips_error("gifload", "%s", _("bad image dimensions")); return NULL; } return g_malloc0((gsize) width * height * 4); } static unsigned char * vips_foreign_load_nsgif_bitmap_get_buffer(void *bitmap) { g_assert(bitmap); return bitmap; } static void vips_foreign_load_nsgif_bitmap_destroy(void *bitmap) { g_assert(bitmap); g_free(bitmap); } static nsgif_bitmap_cb_vt vips_foreign_load_nsgif_bitmap_callbacks = { vips_foreign_load_nsgif_bitmap_create, vips_foreign_load_nsgif_bitmap_destroy, vips_foreign_load_nsgif_bitmap_get_buffer, }; static void vips_foreign_load_nsgif_init(VipsForeignLoadNsgif *gif) { nsgif_error result = nsgif_create( &vips_foreign_load_nsgif_bitmap_callbacks, NSGIF_BITMAP_FMT_R8G8B8A8, &gif->anim); if (result != NSGIF_OK) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(gif); vips_error(class->nickname, "%s", nsgif_strerror(result)); return; } gif->n = 1; gif->gif_n = 1; gif->frame_number = -1; gif->bitmap = NULL; } typedef struct _VipsForeignLoadNsgifFile { VipsForeignLoadNsgif parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadNsgifFile; typedef VipsForeignLoadNsgifClass VipsForeignLoadNsgifFileClass; G_DEFINE_TYPE(VipsForeignLoadNsgifFile, vips_foreign_load_nsgif_file, vips_foreign_load_nsgif_get_type()); static int vips_foreign_load_gif_file_build(VipsObject *object) { VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) object; VipsForeignLoadNsgifFile *file = (VipsForeignLoadNsgifFile *) object; if (file->filename) if (!(gif->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_nsgif_file_parent_class) ->build(object); } static const char *vips_foreign_nsgif_suffs[] = { ".gif", NULL }; static gboolean vips_foreign_load_nsgif_file_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_nsgif_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_nsgif_file_class_init( VipsForeignLoadNsgifFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifload"; object_class->description = _("load GIF with libnsgif"); object_class->build = vips_foreign_load_gif_file_build; foreign_class->suffs = vips_foreign_nsgif_suffs; load_class->is_a = vips_foreign_load_nsgif_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNsgifFile, filename), NULL); } static void vips_foreign_load_nsgif_file_init(VipsForeignLoadNsgifFile *file) { } typedef struct _VipsForeignLoadNsgifBuffer { VipsForeignLoadNsgif parent_object; /* Load from a buffer. */ VipsArea *blob; } VipsForeignLoadNsgifBuffer; typedef VipsForeignLoadNsgifClass VipsForeignLoadNsgifBufferClass; G_DEFINE_TYPE(VipsForeignLoadNsgifBuffer, vips_foreign_load_nsgif_buffer, vips_foreign_load_nsgif_get_type()); static int vips_foreign_load_nsgif_buffer_build(VipsObject *object) { VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) object; VipsForeignLoadNsgifBuffer *buffer = (VipsForeignLoadNsgifBuffer *) object; if (buffer->blob && !(gif->source = vips_source_new_from_memory( buffer->blob->data, buffer->blob->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_nsgif_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_nsgif_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_nsgif_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_nsgif_buffer_class_init( VipsForeignLoadNsgifBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifload_buffer"; object_class->description = _("load GIF with libnsgif"); object_class->build = vips_foreign_load_nsgif_buffer_build; load_class->is_a_buffer = vips_foreign_load_nsgif_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNsgifBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_nsgif_buffer_init(VipsForeignLoadNsgifBuffer *buffer) { } typedef struct _VipsForeignLoadNsgifSource { VipsForeignLoadNsgif parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadNsgifSource; typedef VipsForeignLoadClass VipsForeignLoadNsgifSourceClass; G_DEFINE_TYPE(VipsForeignLoadNsgifSource, vips_foreign_load_nsgif_source, vips_foreign_load_nsgif_get_type()); static int vips_foreign_load_nsgif_source_build(VipsObject *object) { VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) object; VipsForeignLoadNsgifSource *source = (VipsForeignLoadNsgifSource *) object; if (source->source) { gif->source = source->source; g_object_ref(gif->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_nsgif_source_parent_class) ->build(object); } static void vips_foreign_load_nsgif_source_class_init( VipsForeignLoadNsgifSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "gifload_source"; object_class->description = _("load gif from source"); object_class->build = vips_foreign_load_nsgif_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_nsgif_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadNsgifSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_nsgif_source_init(VipsForeignLoadNsgifSource *source) { } #endif /*HAVE_NSGIF*/ /** * vips_gifload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Read a GIF file into a libvips image. * * Use @page to select a page to render, numbering from zero. * * Use @n to select the number of pages to render. The default is 1. Pages are * rendered in a vertical column. Set to -1 to mean "until the end of the * document". Use [method@Image.grid] to change page layout. * * Use @fail_on to set the type of error that will cause load to fail. By * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE]. * * The output image is RGBA for GIFs containing transparent elements, RGB * otherwise. * * ::: tip "Optional arguments" * * @page: `gint`, page (frame) to read * * @n: `gint`, load this many pages * * @fail_on: [enum@FailOn], types of read error to fail on * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_gifload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("gifload", ap, filename, out); va_end(ap); return result; } /** * vips_gifload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.gifload], but read from a memory buffer. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, page (frame) to read * * @n: `gint`, load this many pages * * @fail_on: [enum@FailOn], types of read error to fail on * * ::: seealso * [ctor@Image.gifload]. * * Returns: 0 on success, -1 on error. */ int vips_gifload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("gifload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_gifload_source: * @source: source to load * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.gifload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, page (frame) to read * * @n: `gint`, load this many pages * * @fail_on: [enum@FailOn], types of read error to fail on * * ::: seealso * [ctor@Image.gifload]. * * Returns: 0 on success, -1 on error. */ int vips_gifload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("gifload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/openexr2vips.c000066400000000000000000000217601516303661500212070ustar00rootroot00000000000000/* Convert OpenEXR to VIPS * * 1/5/06 * - from im_png2vips.c * 17/5/06 * - oops, buffer calcs were wrong * 19/5/06 * - added tiled read, with a separate cache * - removed *255 we had before, better to do something clever with * chromaticities * 4/2/10 * - gtkdoc * 12/12/11 * - redo as a set of fns ready for wrapping in a new-style class * 17/9/16 * - tag output as scRGB * 16/8/18 * - shut down the input file as soon as we can [kleisauke] */ /* TODO - colour management - attributes - more of OpenEXR's pixel formats - more than just RGBA channels - turn alpha to vips 0 - 255 from exr 0 - 1 the openexr C API is very limited ... it seems RGBA half pixels is all you can do openexr lets you have different formats in different channels :-( there's no API to read the "chromaticities" attribute :-( best redo with the C++ API now we support C++ operations */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_OPENEXR #include #include #include #include #include #include #include #include "pforeign.h" /* What we track during a OpenEXR read. */ typedef struct { char *filename; VipsImage *out; ImfTiledInputFile *tiles; ImfInputFile *lines; const ImfHeader *header; VipsRect window; int tile_width; int tile_height; } Read; gboolean vips__openexr_isexr(const char *filename) { unsigned char buf[4]; if (vips__get_bytes(filename, buf, 4) == 4) if (buf[0] == 0x76 && buf[1] == 0x2f && buf[2] == 0x31 && buf[3] == 0x01) return TRUE; return FALSE; } static void get_imf_error(void) { vips_error("exr2vips", _("EXR error: %s"), ImfErrorMessage()); } static void read_close(Read *read) { VIPS_FREEF(ImfCloseTiledInputFile, read->tiles); VIPS_FREEF(ImfCloseInputFile, read->lines); } static void read_destroy(VipsImage *out, Read *read) { VIPS_FREE(read->filename); read_close(read); g_free(read); } static Read * read_new(const char *filename, VipsImage *out) { Read *read; int xmin, ymin; int xmax, ymax; if (!(read = VIPS_NEW(NULL, Read))) return NULL; read->filename = vips_strdup(NULL, filename); read->out = out; read->tiles = NULL; read->lines = NULL; if (out) g_signal_connect(out, "close", G_CALLBACK(read_destroy), read); /* Try to open tiled first ... if that fails, fall back to scanlines. FIXME ... seems a bit ugly, but how else can you spot a tiled EXR image? */ if (!(read->tiles = ImfOpenTiledInputFile(read->filename)) && !(read->lines = ImfOpenInputFile(read->filename))) { get_imf_error(); if (!out) read_destroy(NULL, read); return NULL; } #ifdef DEBUG if (read->tiles) printf("exr2vips: opening in tiled mode\n"); else printf("exr2vips: opening in scanline mode\n"); #endif /*DEBUG*/ if (read->tiles) { read->header = ImfTiledInputHeader(read->tiles); read->tile_width = ImfTiledInputTileXSize(read->tiles); read->tile_height = ImfTiledInputTileYSize(read->tiles); } else read->header = ImfInputHeader(read->lines); ImfHeaderDataWindow(read->header, &xmin, &ymin, &xmax, &ymax); read->window.left = xmin; read->window.top = ymin; read->window.width = xmax - xmin + 1; read->window.height = ymax - ymin + 1; return read; } gboolean vips__openexr_istiled(const char *filename) { Read *read; gboolean tiled; if (!(read = read_new(filename, NULL))) return FALSE; tiled = read->tiles != NULL; read_destroy(NULL, read); return tiled; } /* Read a OpenEXR file (header) into a VIPS (header). */ static void read_header(Read *read, VipsImage *out) { VipsDemandStyle hint; /* FIXME ... not really scRGB, you should get the chromaticities from the header and transform */ vips_image_init_fields(out, read->window.width, read->window.height, 4, VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_scRGB, 1.0, 1.0); if (read->tiles) { vips_image_set_int(out, VIPS_META_TILE_WIDTH, read->tile_width); vips_image_set_int(out, VIPS_META_TILE_HEIGHT, read->tile_height); /* Even though this is a tiled reader, we hint thinstrip * since with the cache we are quite happy serving that if * anything downstream would like it. */ hint = VIPS_DEMAND_STYLE_THINSTRIP; } else hint = VIPS_DEMAND_STYLE_FATSTRIP; (void) vips_image_pipelinev(out, hint, NULL); } int vips__openexr_read_header(const char *filename, VipsImage *out) { Read *read; if (!(read = read_new(filename, out))) return -1; read_header(read, out); read_close(read); return 0; } /* Allocate a tile buffer. */ static void * vips__openexr_start(VipsImage *out, void *a, void *b) { Read *read = (Read *) a; ImfRgba *imf_buffer; if (!(imf_buffer = VIPS_ARRAY(out, read->tile_width * read->tile_height, ImfRgba))) return NULL; return imf_buffer; } static int vips__openexr_generate(VipsRegion *out, void *seq, void *a, void *b, gboolean *top) { ImfRgba *imf_buffer = (ImfRgba *) seq; Read *read = (Read *) a; VipsRect *r = &out->valid; const int tw = read->tile_width; const int th = read->tile_height; /* Find top left of tiles we need. */ const int xs = (r->left / tw) * tw; const int ys = (r->top / th) * th; int x, y, z; VipsRect image; /* Area of image. */ image.left = 0; image.top = 0; image.width = read->out->Xsize; image.height = read->out->Ysize; for (y = ys; y < VIPS_RECT_BOTTOM(r); y += th) for (x = xs; x < VIPS_RECT_RIGHT(r); x += tw) { VipsRect tile; VipsRect hit; int result; if (!ImfTiledInputSetFrameBuffer(read->tiles, imf_buffer - (read->window.left + x) - (read->window.top + y) * tw, 1, tw)) { vips_foreign_load_invalidate(read->out); get_imf_error(); return -1; } #ifdef DEBUG printf("exr2vips: requesting tile %d x %d\n", x / tw, y / th); #endif /*DEBUG*/ result = ImfTiledInputReadTile(read->tiles, x / tw, y / th, 0, 0); if (!result) { get_imf_error(); return -1; } /* The tile in the file, in VIPS coordinates. */ tile.left = x; tile.top = y; tile.width = tw; tile.height = th; vips_rect_intersectrect(&tile, &image, &tile); /* The part of this tile that hits the region. */ vips_rect_intersectrect(&tile, r, &hit); /* Convert to float and write to the region. */ for (z = 0; z < hit.height; z++) { ImfRgba *p = imf_buffer + (hit.left - tile.left) + (hit.top - tile.top + z) * tw; float *q = (float *) VIPS_REGION_ADDR(out, hit.left, hit.top + z); ImfHalfToFloatArray(4 * hit.width, (ImfHalf *) p, q); } } return 0; } int vips__openexr_read(const char *filename, VipsImage *out) { Read *read; if (!(read = read_new(filename, out))) return -1; if (read->tiles) { VipsImage *raw; VipsImage *t; /* Tile cache: keep enough for two complete rows of tiles, * plus 50%. */ raw = vips_image_new(); vips_object_local(out, raw); read_header(read, raw); if (vips_image_generate(raw, vips__openexr_start, vips__openexr_generate, NULL, read, NULL)) return -1; if (vips_tilecache(raw, &t, "tile_width", read->tile_width, "tile_height", read->tile_height, "max_tiles", (int) (2.5 * (1 + raw->Xsize / read->tile_width)), NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); } else { const int left = read->window.left; const int top = read->window.top; const int width = read->window.width; const int height = read->window.height; ImfRgba *imf_buffer; float *vips_buffer; int y; if (!(imf_buffer = VIPS_ARRAY(out, width, ImfRgba)) || !(vips_buffer = VIPS_ARRAY(out, 4 * width, float))) return -1; read_header(read, out); for (y = 0; y < height; y++) { if (!ImfInputSetFrameBuffer(read->lines, imf_buffer - left - (top + y) * width, 1, width)) { get_imf_error(); return -1; } if (!ImfInputReadPixels(read->lines, top + y, top + y)) { get_imf_error(); return -1; } ImfHalfToFloatArray(4 * width, (ImfHalf *) imf_buffer, vips_buffer); if (vips_image_write_line(out, y, (VipsPel *) vips_buffer)) return -1; } read_close(read); } return 0; } #endif /*HAVE_OPENEXR*/ libvips-8.18.2/libvips/foreign/openexrload.c000066400000000000000000000111571516303661500210620ustar00rootroot00000000000000/* load openexr from a file * * 5/12/11 * - from openslideload.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_OPENEXR #include "pforeign.h" typedef struct _VipsForeignLoadOpenexr { VipsForeignLoad parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadOpenexr; typedef VipsForeignLoadClass VipsForeignLoadOpenexrClass; G_DEFINE_TYPE(VipsForeignLoadOpenexr, vips_foreign_load_openexr, VIPS_TYPE_FOREIGN_LOAD); static VipsForeignFlags vips_foreign_load_openexr_get_flags_filename(const char *filename) { VipsForeignFlags flags; flags = 0; if (vips__openexr_istiled(filename)) flags |= VIPS_FOREIGN_PARTIAL; return flags; } static VipsForeignFlags vips_foreign_load_openexr_get_flags(VipsForeignLoad *load) { VipsForeignLoadOpenexr *openexr = (VipsForeignLoadOpenexr *) load; return vips_foreign_load_openexr_get_flags_filename( openexr->filename); } static int vips_foreign_load_openexr_header(VipsForeignLoad *load) { VipsForeignLoadOpenexr *openexr = (VipsForeignLoadOpenexr *) load; if (vips__openexr_read_header(openexr->filename, load->out)) return -1; VIPS_SETSTR(load->out->filename, openexr->filename); return 0; } static int vips_foreign_load_openexr_load(VipsForeignLoad *load) { VipsForeignLoadOpenexr *openexr = (VipsForeignLoadOpenexr *) load; if (vips__openexr_read(openexr->filename, load->real)) return -1; return 0; } static const char *vips_foreign_openexr_suffs[] = { ".exr", NULL }; static void vips_foreign_load_openexr_class_init(VipsForeignLoadOpenexrClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "openexrload"; object_class->description = _("load an OpenEXR image"); /* OpenEXR is fuzzed, but not by us. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips_foreign_openexr_suffs; /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; load_class->is_a = vips__openexr_isexr; load_class->get_flags_filename = vips_foreign_load_openexr_get_flags_filename; load_class->get_flags = vips_foreign_load_openexr_get_flags; load_class->header = vips_foreign_load_openexr_header; load_class->load = vips_foreign_load_openexr_load; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenexr, filename), NULL); } static void vips_foreign_load_openexr_init(VipsForeignLoadOpenexr *openexr) { } #endif /*HAVE_OPENEXR*/ /** * vips_openexrload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a OpenEXR file into a VIPS image. * * The reader can handle scanline and tiled OpenEXR images. It can't handle * OpenEXR colour management, image attributes, many pixel formats, anything * other than RGBA. * * This reader uses the rather limited OpenEXR C API. It should really be * redone in C++. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_openexrload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("openexrload", ap, filename, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/openslideconnection.c000066400000000000000000000162571516303661500226120ustar00rootroot00000000000000/* Share and reuse openslide_t between many openslideload operations. * * 1/4/25 * - first version! */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_OPENSLIDE #include #include #include "pforeign.h" #include // we keep this many connections around after they are closed, ready for reuse #define OPENSLIDECONNECTION (3) // a tile cache shared between all active openslide connections ... 32mb #define OPENSLIDECONNECTION_CACHE_SIZE (64 * 1024 * 1024) typedef struct _VipsOpenslideConnection { char *filename; // protected by vips_openslideconnection_lock int ref_count; // first access protected by separate lock, since initialization // is slow openslide_t *osr; GMutex osr_lock; } VipsOpenslideConnection; static GHashTable *vips_openslideconnection_cache = NULL; static GQueue *vips_openslideconnection_unused = NULL; static GMutex vips_openslideconnection_lock; /* Added in 4.0 ... this is a tile cache that's shared between all active * openslide connections. */ #ifdef HAVE_OPENSLIDE_CACHE_CREATE openslide_cache_t *vips_openslideconnection_openslide_cache; #endif /*HAVE_OPENSLIDE_CACHE_CREATE*/ static void vips_openslideconnection_free(VipsOpenslideConnection *connection) { #ifdef DEBUG printf("vips_openslideconnection_free: %s\n", connection->filename); #endif /*DEBUG*/ VipsOpenslideConnection *cached G_GNUC_UNUSED = g_hash_table_lookup(vips_openslideconnection_cache, connection->filename); g_assert(cached); g_assert(cached == connection); g_hash_table_remove(vips_openslideconnection_cache, connection->filename); g_queue_remove(vips_openslideconnection_unused, connection); g_mutex_lock(&connection->osr_lock); VIPS_FREEF(openslide_close, connection->osr); g_mutex_unlock(&connection->osr_lock); g_mutex_clear(&connection->osr_lock); VIPS_FREE(connection->filename); g_free(connection); } static void vips_openslideconnection_trim(void) { while (vips_openslideconnection_unused->length > OPENSLIDECONNECTION) { VipsOpenslideConnection *oldest = g_queue_pop_head(vips_openslideconnection_unused); vips_openslideconnection_free(oldest); } } static void vips_openslideconnection_unref(VipsOpenslideConnection *connection) { #ifdef DEBUG printf("vips_openslideconnection_unref: %s\n", connection->filename); #endif /*DEBUG*/ g_assert(connection->ref_count > 0); connection->ref_count -= 1; if (connection->ref_count == 0) { /* If the openslide_t is in an error state, or we've no connection, * don't leave it in the cache. */ if (!connection->osr || openslide_get_error(connection->osr)) vips_openslideconnection_free(connection); else { g_queue_push_tail(vips_openslideconnection_unused, connection); vips_openslideconnection_trim(); } } } static void vips_openslideconnection_ref(VipsOpenslideConnection *connection) { #ifdef DEBUG printf("vips_openslideconnection_ref: %s\n", connection->filename); #endif /*DEBUG*/ g_assert(connection->ref_count >= 0); if (connection->ref_count == 0) g_queue_remove(vips_openslideconnection_unused, connection); connection->ref_count += 1; } static VipsOpenslideConnection * vips_openslideconnection_new(const char *filename) { #ifdef DEBUG printf("vips_openslideconnection_new: %s\n", filename); #endif /*DEBUG*/ VipsOpenslideConnection *connection; connection = g_new0(VipsOpenslideConnection, 1); connection->filename = g_strdup(filename); g_mutex_init(&connection->osr_lock); g_assert(!g_hash_table_lookup(vips_openslideconnection_cache, filename)); g_hash_table_insert(vips_openslideconnection_cache, connection->filename, connection); return connection; } openslide_t * vips__openslideconnection_open(const char *filename, gboolean revalidate) { #ifdef DEBUG printf("vips_openslideconnection_open: %s, revalidate = %d\n", filename, revalidate); #endif /*DEBUG*/ g_mutex_lock(&vips_openslideconnection_lock); if (!vips_openslideconnection_cache) { vips_openslideconnection_cache = g_hash_table_new(g_str_hash, g_str_equal); vips_openslideconnection_unused = g_queue_new(); #ifdef HAVE_OPENSLIDE_CACHE_CREATE vips_openslideconnection_openslide_cache = openslide_cache_create(OPENSLIDECONNECTION_CACHE_SIZE); #endif /*HAVE_OPENSLIDE_CACHE_CREATE*/ } VipsOpenslideConnection *connection; connection = g_hash_table_lookup(vips_openslideconnection_cache, filename); // discard any cached connection on revalidate if (connection && connection->ref_count == 0 && revalidate) VIPS_FREEF(vips_openslideconnection_free, connection); if (!connection) connection = vips_openslideconnection_new(filename); vips_openslideconnection_ref(connection); g_mutex_unlock(&vips_openslideconnection_lock); g_mutex_lock(&connection->osr_lock); gboolean unref; /* We do the open outside the main lock (just in the connection lock) * since it can take many seconds for some slides. */ unref = FALSE; if (!connection->osr) { connection->osr = openslide_open(connection->filename); /* If open fails, we must unref the connection, since we'll return * NULL. */ if (!connection->osr) unref = TRUE; #ifdef HAVE_OPENSLIDE_CACHE_CREATE if (connection->osr) openslide_set_cache(connection->osr, vips_openslideconnection_openslide_cache); #endif /*HAVE_OPENSLIDE_CACHE_CREATE*/ } openslide_t *osr = connection->osr; g_mutex_unlock(&connection->osr_lock); if (unref) { g_mutex_lock(&vips_openslideconnection_lock); vips_openslideconnection_unref(connection); g_mutex_unlock(&vips_openslideconnection_lock); } return osr; } void vips__openslideconnection_close(const char *filename) { #ifdef DEBUG printf("vips_openslideconnection_close: %s\n", filename); #endif /*DEBUG*/ g_mutex_lock(&vips_openslideconnection_lock); VipsOpenslideConnection *connection; connection = g_hash_table_lookup(vips_openslideconnection_cache, filename); if (connection) vips_openslideconnection_unref(connection); g_mutex_unlock(&vips_openslideconnection_lock); } int vips__openslideconnection_leak(void) { int n_leaks; n_leaks = 0; g_mutex_lock(&vips_openslideconnection_lock); if (vips_openslideconnection_cache) n_leaks += g_hash_table_size(vips_openslideconnection_cache) - vips_openslideconnection_unused->length; g_mutex_unlock(&vips_openslideconnection_lock); if (n_leaks > 0) printf("vips__openslideconnection_leak: %d leaked connections\n", n_leaks); return n_leaks; } #endif /*HAVE_OPENSLIDE*/ libvips-8.18.2/libvips/foreign/openslideload.c000066400000000000000000000744301516303661500213670ustar00rootroot00000000000000/* Read a virtual microscope slide using OpenSlide. * * Benjamin Gilbert * * Copyright (c) 2011-2015 Carnegie Mellon University * * 26/11/11 * - initial version * 27/11/11 * - fix black background in transparent areas * - no need to set *stop on fill_region() error return * - add OpenSlide properties to image metadata * - consolidate setup into one function * - support reading arbitrary layers * - use VIPS_ARRAY() * - add helper to copy a line of pixels * - support reading associated images * 7/12/11 * - redirect OpenSlide error logging to vips_error() * 8/12/11 * - add more exposition to documentation * 9/12/11 * - unpack to a tile cache * 11/12/11 * - move argb->rgba into conversion * - turn into a set of read fns ready to be called from a class * 28/2/12 * - convert "layer" to "level" where externally visible * 9/4/12 * - move argb2rgba back in here, we don't have a use for coded pixels * - small cleanups * 11/4/12 * - fail if both level and associated image are specified * 20/9/12 * - update openslide_open error handling for 3.3.0 semantics * - switch from deprecated _layer_ functions * 11/10/12 * - look for tile-width and tile-height properties * - use threaded tile cache * 6/8/13 * - always output solid (not transparent) pixels * 25/1/14 * - use openslide_detect_vendor() on >= 3.4.0 * 30/7/14 * - add autocrop toggle * 9/8/14 * - do argb -> rgba for associated as well * 27/1/15 * - unpremultiplication speedups for fully opaque/transparent pixels * 18/1/17 * - reorganise to support invalidate on read error * 27/1/18 * - option to attach associated images as metadata * 22/6/20 adamu * - set libvips xres/yres from openslide mpp-x/mpp-y * 13/2/21 kleisauke * - include GObject part from openslideload.c * 2/10/22 * - add "rgb" option * 1/10/23 * - add openslide4 icc profile support */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_OPENSLIDE #include #include #include #include #include #include #include "pforeign.h" #include /* From openslideconnection.c */ openslide_t *vips__openslideconnection_open(const char *filename, gboolean revalidate); void vips__openslideconnection_close(const char *filename); typedef struct { /* Params. */ char *filename; VipsImage *out; int32_t level; gboolean autocrop; char *associated; gboolean attach_associated; gboolean rgb; gboolean revalidate; openslide_t *osr; /* Crop to image bounds if @autocrop is set. */ VipsRect bounds; /* Only valid if associated == NULL. */ double downsample; uint32_t bg; /* Try to get these from openslide properties. */ int tile_width; int tile_height; } ReadSlide; static int vips__openslide_isslide(const char *filename) { const char *vendor; int ok; vendor = openslide_detect_vendor(filename); /* Generic tiled tiff images can be opened by openslide as well. * Only offer to load this file if it's not a generic tiff since * we want vips_tiffload() to handle these. */ ok = vendor && strcmp(vendor, "generic-tiff") != 0; VIPS_DEBUG_MSG("vips__openslide_isslide: %s - %d\n", filename, ok); return ok; } static void readslide_destroy_cb(VipsImage *image, ReadSlide *rslide) { if (rslide->osr) { vips__openslideconnection_close(rslide->filename); rslide->osr = NULL; } VIPS_FREE(rslide->associated); VIPS_FREE(rslide->filename); VIPS_FREE(rslide); } static int check_associated_image(openslide_t *osr, const char *name) { const char *const *associated; for (associated = openslide_get_associated_image_names(osr); *associated != NULL; associated++) if (strcmp(*associated, name) == 0) return 0; vips_error("openslide2vips", "%s", _("invalid associated image name")); return -1; } static gboolean get_bounds(openslide_t *osr, VipsRect *rect) { static const char *openslide_names[] = { "openslide.bounds-x", "openslide.bounds-y", "openslide.bounds-width", "openslide.bounds-height" }; static int vips_offsets[] = { G_STRUCT_OFFSET(VipsRect, left), G_STRUCT_OFFSET(VipsRect, top), G_STRUCT_OFFSET(VipsRect, width), G_STRUCT_OFFSET(VipsRect, height) }; const char *value; int i; for (i = 0; i < 4; i++) { if (!(value = openslide_get_property_value(osr, openslide_names[i]))) return FALSE; G_STRUCT_MEMBER(int, rect, vips_offsets[i]) = atoi(value); } return TRUE; } static ReadSlide * readslide_new(const char *filename, VipsImage *out, int level, gboolean autocrop, const char *associated, gboolean attach_associated, gboolean rgb, gboolean revalidate) { ReadSlide *rslide; if (level && associated) { vips_error("openslide2vips", "%s", _("specify only one of level and associated image")); return NULL; } if (attach_associated && associated) { vips_error("openslide2vips", "%s", _("specify only one of attach_assicated and associated image")); return NULL; } rslide = VIPS_NEW(NULL, ReadSlide); memset(rslide, 0, sizeof(*rslide)); g_signal_connect(out, "close", G_CALLBACK(readslide_destroy_cb), rslide); rslide->filename = g_strdup(filename); rslide->out = out; rslide->level = level; rslide->autocrop = autocrop; rslide->associated = g_strdup(associated); rslide->attach_associated = attach_associated; rslide->rgb = rgb; rslide->revalidate = revalidate; /* Non-crazy defaults, override in _parse() if we can. */ rslide->tile_width = 256; rslide->tile_height = 256; return rslide; } /* Convert from ARGB to RGBA and undo premultiplication. * * We throw away transparency. Formats like Mirax use transparent + bg * colour for areas with no useful pixels. But if we output * transparent pixels and then convert to RGB for jpeg write later, we * would have to pass the bg colour down the pipe somehow. The * structure of dzsave makes this tricky. * * We could output plain RGB instead, but that would break * compatibility with older vipses. */ static void argb2rgba(uint32_t *restrict buf, int64_t n, uint32_t bg) { const uint32_t pbg = GUINT32_TO_BE((bg << 8) | 255); int64_t i; for (i = 0; i < n; i++) { uint32_t *restrict p = buf + i; uint32_t x = *p; uint8_t a = x >> 24; VipsPel *restrict out = (VipsPel *) p; if (a == 255) *p = GUINT32_TO_BE((x << 8) | 255); else if (a == 0) /* Use background color. */ *p = pbg; else { /* Undo premultiplication. */ out[0] = 255 * ((x >> 16) & 255) / a; out[1] = 255 * ((x >> 8) & 255) / a; out[2] = 255 * (x & 255) / a; out[3] = 255; } } } /* Convert from ARGB to RGB. In RGB mode, assume a is always 255. */ static void argb2rgb(uint32_t *restrict buf, VipsPel *restrict q, int64_t n) { int64_t i; for (i = 0; i < n; i++) { uint32_t x = buf[i]; q[0] = ((x >> 16) & 0xff); q[1] = ((x >> 8) & 0xff); q[2] = (x & 0xff); q += 3; } } static VipsImage * vips__openslide_get_associated(ReadSlide *rslide, const char *associated_name) { VipsImage *associated; int64_t w, h; const char *error; associated = vips_image_new_memory(); openslide_get_associated_image_dimensions(rslide->osr, associated_name, &w, &h); /* Always 4 bands, since this is the image that gets the ARGB from * cairo. */ vips_image_init_fields(associated, w, h, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); #ifdef HAVE_OPENSLIDE_ICC int64_t len; if ((len = openslide_get_associated_image_icc_profile_size(rslide->osr, associated_name)) > 0) { void *data; if (!(data = VIPS_MALLOC(NULL, len))) { g_object_unref(associated); return NULL; } openslide_read_associated_image_icc_profile(rslide->osr, associated_name, data); error = openslide_get_error(rslide->osr); if (error) { g_free(data); g_object_unref(associated); vips_error("openslide2vips", _( "opening slide: %s" ), error); return NULL; } vips_image_set_blob(associated, VIPS_META_ICC_NAME, (VipsCallbackFn) g_free, data, len); } #endif /*HAVE_OPENSLIDE_ICC*/ if (vips_image_pipelinev(associated, VIPS_DEMAND_STYLE_THINSTRIP, NULL) || vips_image_write_prepare(associated)) { g_object_unref(associated); return NULL; } openslide_read_associated_image(rslide->osr, associated_name, (uint32_t *) VIPS_IMAGE_ADDR(associated, 0, 0)); error = openslide_get_error(rslide->osr); if (error) { vips_error("openslide2vips", _("reading associated image: %s"), error); g_object_unref(associated); return NULL; } /* In RGB mode we make a second RGB image and repack to that. */ if (rslide->rgb) { VipsImage *rgb; rgb = vips_image_new_memory(); vips_object_local(rgb, associated); vips_image_init_fields(rgb, w, h, 3, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); if (vips_image_pipelinev(rgb, VIPS_DEMAND_STYLE_THINSTRIP, NULL) || vips_image_write_prepare(rgb)) { g_object_unref(rgb); return NULL; } argb2rgb((uint32_t *) VIPS_IMAGE_ADDR(associated, 0, 0), VIPS_IMAGE_ADDR(rgb, 0, 0), w * h); associated = rgb; } else /* We can do this in place. */ argb2rgba((uint32_t *) VIPS_IMAGE_ADDR(associated, 0, 0), w * h, rslide->bg); return associated; } static int readslide_attach_associated(ReadSlide *rslide, VipsImage *image) { const char *const *associated_name; for (associated_name = openslide_get_associated_image_names(rslide->osr); *associated_name != NULL; associated_name++) { VipsImage *associated; char buf[256]; if (!(associated = vips__openslide_get_associated(rslide, *associated_name))) return -1; g_snprintf(buf, 256, "openslide.associated.%s", *associated_name); vips_image_set_image(image, buf, associated); g_object_unref(associated); } return 0; } /* Read out a resolution field, converting to pixels per mm. */ static double readslice_parse_res(ReadSlide *rslide, const char *name) { const char *value = openslide_get_property_value(rslide->osr, name); double mpp = g_ascii_strtod(value, NULL); return mpp == 0 ? 1.0 : 1000.0 / mpp; } static int readslide_parse(ReadSlide *rslide, VipsImage *image) { int64_t w, h; const char *error; const char *background; const char *const *properties; char *associated_names; double xres; double yres; rslide->osr = vips__openslideconnection_open(rslide->filename, rslide->revalidate); if (!rslide->osr) { vips_error("openslide2vips", "%s", _("unsupported slide format")); return -1; } error = openslide_get_error(rslide->osr); if (error) { vips_error("openslide2vips", _("opening slide: %s"), error); return -1; } if (rslide->level < 0 || rslide->level >= openslide_get_level_count(rslide->osr)) { vips_error("openslide2vips", "%s", _("invalid slide level")); return -1; } if (rslide->associated && check_associated_image(rslide->osr, rslide->associated)) return -1; if (rslide->associated) { openslide_get_associated_image_dimensions(rslide->osr, rslide->associated, &w, &h); vips_image_set_string(image, "slide-associated-image", rslide->associated); if (vips_image_pipelinev(image, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; } else { char buf[256]; const char *value; openslide_get_level_dimensions(rslide->osr, rslide->level, &w, &h); rslide->downsample = openslide_get_level_downsample( rslide->osr, rslide->level); vips_image_set_int(image, "slide-level", rslide->level); if (vips_image_pipelinev(image, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; /* Try to get tile width/height. An undocumented, experimental * feature. */ g_snprintf(buf, 256, "openslide.level[%d].tile-width", rslide->level); if ((value = openslide_get_property_value(rslide->osr, buf))) { rslide->tile_width = atoi(value); vips_image_set_int(image, VIPS_META_TILE_WIDTH, rslide->tile_width); } g_snprintf(buf, 256, "openslide.level[%d].tile-height", rslide->level); if ((value = openslide_get_property_value(rslide->osr, buf))) { rslide->tile_height = atoi(value); vips_image_set_int(image, VIPS_META_TILE_HEIGHT, rslide->tile_height); } if (value) VIPS_DEBUG_MSG("readslide_new: found tile-size\n"); /* Some images have a bounds in the header. Crop to * that if autocrop is set. */ if (rslide->autocrop) if (!get_bounds(rslide->osr, &rslide->bounds)) rslide->autocrop = FALSE; if (rslide->autocrop) { VipsRect whole; rslide->bounds.left /= rslide->downsample; rslide->bounds.top /= rslide->downsample; rslide->bounds.width /= rslide->downsample; rslide->bounds.height /= rslide->downsample; /* Clip against image size. */ whole.left = 0; whole.top = 0; whole.width = w; whole.height = h; vips_rect_intersectrect(&rslide->bounds, &whole, &rslide->bounds); /* If we've clipped to nothing, ignore bounds. */ if (vips_rect_isempty(&rslide->bounds)) rslide->autocrop = FALSE; } if (rslide->autocrop) { w = rslide->bounds.width; h = rslide->bounds.height; } /* Attach all associated images. */ if (rslide->attach_associated && readslide_attach_associated(rslide, image)) return -1; } rslide->bg = 0xffffff; if ((background = openslide_get_property_value(rslide->osr, OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR))) rslide->bg = strtoul(background, NULL, 16); if (w <= 0 || h <= 0 || rslide->downsample < 0) { vips_error("openslide2vips", _("getting dimensions: %s"), openslide_get_error(rslide->osr)); return -1; } if (w > INT_MAX || h > INT_MAX) { vips_error("openslide2vips", "%s", _("image dimensions overflow int")); return -1; } if (!rslide->autocrop) { rslide->bounds.left = 0; rslide->bounds.top = 0; rslide->bounds.width = w; rslide->bounds.height = h; } /* Try to get resolution from openslide properties. */ xres = 1.0; yres = 1.0; for (properties = openslide_get_property_names(rslide->osr); *properties != NULL; properties++) { const char *name = *properties; const char *value = openslide_get_property_value(rslide->osr, name); /* Can be NULL for some openslides with some images. */ if (value) { vips_image_set_string(image, name, value); if (strcmp(*properties, "openslide.mpp-x") == 0) xres = readslice_parse_res(rslide, name); if (strcmp(*properties, "openslide.mpp-y") == 0) yres = readslice_parse_res(rslide, name); } } associated_names = g_strjoinv(", ", (char **) openslide_get_associated_image_names(rslide->osr)); vips_image_set_string(image, "slide-associated-images", associated_names); VIPS_FREE(associated_names); vips_image_init_fields(image, w, h, rslide->rgb ? 3 : 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, xres, yres); #ifdef HAVE_OPENSLIDE_ICC int64_t len; if ((len = openslide_get_icc_profile_size(rslide->osr)) > 0) { void *data; if (!(data = VIPS_MALLOC(NULL, len))) return -1; openslide_read_icc_profile(rslide->osr, data); error = openslide_get_error(rslide->osr); if (error) { g_free(data); vips_error("openslide2vips", _( "opening slide: %s" ), error); return -1; } vips_image_set_blob(image, VIPS_META_ICC_NAME, (VipsCallbackFn) g_free, data, len); } #endif /*HAVE_OPENSLIDE_ICC*/ return 0; } static int vips__openslide_read_header(const char *filename, VipsImage *out, int level, gboolean autocrop, char *associated, gboolean attach_associated, gboolean rgb, gboolean revalidate) { ReadSlide *rslide; if (!(rslide = readslide_new(filename, out, level, autocrop, associated, attach_associated, rgb, revalidate)) || readslide_parse(rslide, out)) return -1; return 0; } /* Allocate a tile buffer. Have one of these for each thread so we can unpack * to vips in parallel. */ static void * vips__openslide_start(VipsImage *out, void *a, void *b) { ReadSlide *rslide = (ReadSlide *) a; uint32_t *tile_buffer; if (!(tile_buffer = VIPS_MALLOC(NULL, (size_t) rslide->tile_width * rslide->tile_height * 4))) return NULL; return (void *) tile_buffer; } static int vips__openslide_generate(VipsRegion *out, void *_seq, void *_rslide, void *unused, gboolean *stop) { uint32_t *tile_buffer = (uint32_t *) _seq; ReadSlide *rslide = _rslide; uint32_t bg = rslide->bg; VipsRect *r = &out->valid; int n = r->width * r->height; uint32_t *buf; const char *error; VIPS_DEBUG_MSG("vips__openslide_generate: %dx%d @ %dx%d\n", r->width, r->height, r->left, r->top); /* We're inside a cache, so requests should always be * tile_width by tile_height pixels and on a tile boundary. */ g_assert((r->left % rslide->tile_width) == 0); g_assert((r->top % rslide->tile_height) == 0); g_assert(r->width <= rslide->tile_width); g_assert(r->height <= rslide->tile_height); /* The memory on the region should be contiguous. */ g_assert(VIPS_REGION_LSKIP(out) == r->width * out->im->Bands); /* In RGB mode we need to read to the tile buffer. */ if (rslide->rgb) { g_assert(tile_buffer); g_assert(rslide->tile_width >= r->width); g_assert(rslide->tile_height >= r->height); buf = tile_buffer; } else buf = (uint32_t *) VIPS_REGION_ADDR(out, r->left, r->top); openslide_read_region(rslide->osr, buf, (r->left + rslide->bounds.left) * rslide->downsample, (r->top + rslide->bounds.top) * rslide->downsample, rslide->level, r->width, r->height); error = openslide_get_error(rslide->osr); if (error) { vips_error("openslide2vips", _("reading region: %s"), error); /* Knock the output out of cache ... openslide errors are terminal, so * we need to force a reopen. */ vips_foreign_load_invalidate(rslide->out); return -1; } if (rslide->rgb) argb2rgb(tile_buffer, VIPS_REGION_ADDR(out, r->left, r->top), n); else argb2rgba(buf, n, bg); return 0; } static int vips__openslide_stop(void *_seq, void *a, void *b) { uint32_t *tile_buffer = (uint32_t *) _seq; VIPS_FREE(tile_buffer); return 0; } static int vips__openslide_read(const char *filename, VipsImage *out, int level, gboolean autocrop, gboolean attach_associated, gboolean rgb, gboolean revalidate) { ReadSlide *rslide; VipsImage *raw; VipsImage *t; VIPS_DEBUG_MSG("vips__openslide_read: %s %d\n", filename, level); if (!(rslide = readslide_new(filename, out, level, autocrop, NULL, attach_associated, rgb, revalidate))) return -1; raw = vips_image_new(); vips_object_local(out, raw); if (readslide_parse(rslide, raw) || vips_image_generate(raw, vips__openslide_start, vips__openslide_generate, vips__openslide_stop, rslide, NULL)) return -1; /* Copy to out, adding a cache. Enough tiles for two complete rows, * plus 50%. We need at least two rows, or we'll constantly reload * tiles if they cross a tile boundary. */ if (vips_tilecache(raw, &t, "tile_width", rslide->tile_width, "tile_height", rslide->tile_height, "max_tiles", (int) (2.5 * (1 + raw->Xsize / rslide->tile_width)), "threaded", TRUE, NULL)) return -1; if (vips_image_write(t, out)) { g_object_unref(t); return -1; } g_object_unref(t); return 0; } static int vips__openslide_read_associated(const char *filename, VipsImage *out, const char *associated_name, gboolean rgb, gboolean revalidate) { ReadSlide *rslide; VipsImage *associated; VIPS_DEBUG_MSG("vips__openslide_read_associated: %s %s\n", filename, associated_name); if (!(rslide = readslide_new(filename, out, 0, FALSE, associated_name, FALSE, rgb, revalidate))) return -1; rslide->osr = vips__openslideconnection_open(rslide->filename, revalidate); if (!(associated = vips__openslide_get_associated(rslide, associated_name))) return -1; if (vips_image_write(associated, out)) { VIPS_UNREF(associated); return -1; } VIPS_UNREF(associated); return 0; } typedef struct _VipsForeignLoadOpenslide { VipsForeignLoad parent_object; /* Source to load from (set by subclasses). */ VipsSource *source; /* Filename from source. */ const char *filename; /* Load this level. */ int level; /* Crop to image bounds. */ gboolean autocrop; /* Load just this associated image. */ char *associated; /* Attach all associated images as metadata items. */ gboolean attach_associated; /* Read as RGB, not RGBA. */ gboolean rgb; } VipsForeignLoadOpenslide; typedef VipsForeignLoadClass VipsForeignLoadOpenslideClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadOpenslide, vips_foreign_load_openslide, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_openslide_dispose(GObject *gobject) { VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) gobject; VIPS_UNREF(openslide->source); G_OBJECT_CLASS(vips_foreign_load_openslide_parent_class)->dispose(gobject); } static int vips_foreign_load_openslide_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) object; /* We can only open source which have an associated filename, since * the openslide library works in terms of filenames. */ if (openslide->source) { VipsConnection *connection = VIPS_CONNECTION(openslide->source); const char *filename; if (!vips_source_is_file(openslide->source) || !(filename = vips_connection_filename(connection))) { vips_error(class->nickname, "%s", _("no filename available")); return -1; } openslide->filename = filename; } return VIPS_OBJECT_CLASS(vips_foreign_load_openslide_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_openslide_get_flags_source(VipsSource *source) { /* We can't tell from just the source, we need to know what part of * the file the user wants. But it'll usually be partial. */ return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_openslide_get_flags(VipsForeignLoad *load) { VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load; VipsForeignFlags flags; flags = 0; if (!openslide->associated) flags |= VIPS_FOREIGN_PARTIAL; return flags; } static VipsForeignFlags vips_foreign_load_openslide_get_flags_filename(const char *filename) { VipsSource *source; VipsForeignFlags flags; if (!(source = vips_source_new_from_file(filename))) return 0; flags = vips_foreign_load_openslide_get_flags_source(source); VIPS_UNREF(source); return flags; } static int vips_foreign_load_openslide_header(VipsForeignLoad *load) { VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load; if (vips__openslide_read_header(openslide->filename, load->out, openslide->level, openslide->autocrop, openslide->associated, openslide->attach_associated, openslide->rgb, load->revalidate)) return -1; VIPS_SETSTR(load->out->filename, openslide->filename); return 0; } static int vips_foreign_load_openslide_load(VipsForeignLoad *load) { VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) load; if (!openslide->associated) { if (vips__openslide_read(openslide->filename, load->real, openslide->level, openslide->autocrop, openslide->attach_associated, openslide->rgb, load->revalidate)) return -1; } else { if (vips__openslide_read_associated(openslide->filename, load->real, openslide->associated, openslide->rgb, load->revalidate)) return -1; } return 0; } static void vips_foreign_load_openslide_class_init(VipsForeignLoadOpenslideClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_openslide_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "openslideload_base"; object_class->description = _("load OpenSlide base class"); object_class->build = vips_foreign_load_openslide_build; /* We need to be ahead of the tiff sniffer since many OpenSlide * formats are tiff derivatives. If we see a tiff which would be * better handled by the vips tiff loader we are careful to say no. * * We need to be ahead of JPEG, since MRXS images are also * JPEGs. */ foreign_class->priority = 100; /* openslide is not fuzzed too heavily. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; load_class->get_flags_filename = vips_foreign_load_openslide_get_flags_filename; load_class->get_flags = vips_foreign_load_openslide_get_flags; load_class->header = vips_foreign_load_openslide_header; load_class->load = vips_foreign_load_openslide_load; VIPS_ARG_INT(class, "level", 20, _("Level"), _("Load this level from the file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslide, level), 0, 100000, 0); VIPS_ARG_BOOL(class, "autocrop", 21, _("Autocrop"), _("Crop to image bounds"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslide, autocrop), FALSE); VIPS_ARG_STRING(class, "associated", 22, _("Associated"), _("Load this associated image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslide, associated), NULL); VIPS_ARG_BOOL(class, "attach_associated", 23, _("Attach associated"), _("Attach all associated images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslide, attach_associated), FALSE); VIPS_ARG_BOOL(class, "rgb", 24, _("RGB"), _("Output RGB (not RGBA)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslide, rgb), FALSE); } static void vips_foreign_load_openslide_init(VipsForeignLoadOpenslide *openslide) { } typedef struct _VipsForeignLoadOpenslideFile { VipsForeignLoadOpenslide parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadOpenslideFile; typedef VipsForeignLoadOpenslideClass VipsForeignLoadOpenslideFileClass; G_DEFINE_TYPE(VipsForeignLoadOpenslideFile, vips_foreign_load_openslide_file, vips_foreign_load_openslide_get_type()); static int vips_foreign_load_openslide_file_build(VipsObject *object) { VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) object; VipsForeignLoadOpenslideFile *file = (VipsForeignLoadOpenslideFile *) object; if (file->filename && !(openslide->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_openslide_file_parent_class) ->build(object); } static const char *vips_foreign_openslide_suffs[] = { ".svs", /* Aperio */ ".vms", ".vmu", ".ndpi", /* Hamamatsu */ ".scn", /* Leica */ ".mrxs", /* MIRAX */ ".svslide", /* Sakura */ ".tif", /* Trestle */ ".bif", /* Ventana */ ".dcm", /* DICOM */ NULL }; static void vips_foreign_load_openslide_file_class_init( VipsForeignLoadOpenslideFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "openslideload"; object_class->description = _("load file with OpenSlide"); object_class->build = vips_foreign_load_openslide_file_build; foreign_class->suffs = vips_foreign_openslide_suffs; load_class->is_a = vips__openslide_isslide; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslideFile, filename), NULL); } static void vips_foreign_load_openslide_file_init(VipsForeignLoadOpenslideFile *openslide) { } typedef struct _VipsForeignLoadOpenslideSource { VipsForeignLoadOpenslide parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadOpenslideSource; typedef VipsForeignLoadOpenslideClass VipsForeignLoadOpenslideSourceClass; G_DEFINE_TYPE(VipsForeignLoadOpenslideSource, vips_foreign_load_openslide_source, vips_foreign_load_openslide_get_type()); static int vips_foreign_load_openslide_source_build(VipsObject *object) { VipsForeignLoadOpenslide *openslide = (VipsForeignLoadOpenslide *) object; VipsForeignLoadOpenslideSource *source = (VipsForeignLoadOpenslideSource *) object; if (source->source) { openslide->source = source->source; g_object_ref(openslide->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_openslide_source_parent_class) ->build(object); } static gboolean vips_foreign_load_openslide_source_is_a_source(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); const char *filename; return vips_source_is_file(source) && (filename = vips_connection_filename(connection)) && vips__openslide_isslide(filename); } static void vips_foreign_load_openslide_source_class_init( VipsForeignLoadOpenslideSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "openslideload_source"; object_class->description = _("load source with OpenSlide"); object_class->build = vips_foreign_load_openslide_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_openslide_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadOpenslideSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_openslide_source_init( VipsForeignLoadOpenslideSource *openslide) { } #endif /*HAVE_OPENSLIDE*/ /* The C API wrappers are defined in foreign.c. */ libvips-8.18.2/libvips/foreign/pdf.c000066400000000000000000000045301516303661500173100ustar00rootroot00000000000000/* Utility functions for the PDF loaders. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" #if defined(HAVE_POPPLER) || defined(HAVE_PDFIUM) const char *vips__pdf_suffs[] = { ".pdf", NULL }; gboolean vips__pdf_is_a_buffer(const void *buf, size_t len) { const char *str = (const char *) buf; if (len < 4) return FALSE; for (size_t i = 0; i < len - 4; i++) if (vips_isprefix("%PDF", str + i)) return TRUE; return FALSE; } /* PDF v2 allows for offset headers, ie. there may be any number of * characters of padding before the "%PDF" file marker. These can be * arbitrary printer control characters, whitespace, etc. * * In practice, the amount of padding is usually small (less than 32 * bytes). * * Another strategy is to look for "%EOF" in the final 1k of the file, but of * course that won't work well for streamed data. */ #define MAX_OFFSET (32) gboolean vips__pdf_is_a_file(const char *filename) { unsigned char buf[MAX_OFFSET]; if (vips__get_bytes(filename, buf, MAX_OFFSET) == MAX_OFFSET && vips__pdf_is_a_buffer(buf, MAX_OFFSET)) return TRUE; return FALSE; } gboolean vips__pdf_is_a_source(VipsSource *source) { const unsigned char *p; return (p = vips_source_sniff(source, MAX_OFFSET)) && vips__pdf_is_a_buffer(p, MAX_OFFSET); } #endif /*defined(HAVE_POPPLER) || defined (HAVE_PDFIUM)*/ libvips-8.18.2/libvips/foreign/pdfiumload.c000066400000000000000000000612211516303661500206630ustar00rootroot00000000000000/* load PDF with PDFium * * 5/4/18 * - from pdfload.c * 8/6/18 * - add background param * 16/8/18 * - shut down the input file as soon as we can [kleisauke] * 8/8/19 * - add locks, since pdfium is not threadsafe in any way * 13/10/20 * - have a lock just for pdfium [DarthSim] * - update for current pdfium * - add _source input * 28/1/22 * - add password * 21/5/22 * - improve transparency handling [DarthSim] * 21/4/23 * - add support for forms [kleisauke] */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* TODO * * - what about filename encodings? * - need to test on Windows */ /* How to build against PDFium: * * Download the prebuilt binary from: * * https://github.com/bblanchon/pdfium-binaries * * Untar to the libvips install prefix, for example: * * cd ~/vips * tar xf ~/pdfium-linux.tgz * * Create a pdfium.pc like this (update the version number): * VIPSHOME=/home/john/vips cat > $VIPSHOME/lib/pkgconfig/pdfium.pc << EOF prefix=$VIPSHOME exec_prefix=\${prefix} libdir=\${exec_prefix}/lib includedir=\${prefix}/include Name: pdfium Description: pdfium Version: 4290 Requires: Libs: -L\${libdir} -lpdfium Cflags: -I\${includedir} EOF * */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_PDFIUM #include #include #include #include #include #define TILE_SIZE (4000) typedef struct _VipsForeignLoadPdf { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Load this page. */ int page_no; /* Load this many pages. */ int n; /* Render at this DPI. */ double dpi; /* Scale by this factor. */ double scale; /* The total scale factor we render with. */ double total_scale; /* Background colour. */ VipsArrayDouble *background; /* Decrypt with this. */ const char *password; FPDF_FILEACCESS file_access; FPDF_DOCUMENT doc; FPDF_PAGE page; FPDF_FORMFILLINFO form_callbacks; FPDF_FORMHANDLE form; int current_page; /* Doc has this many pages. */ int n_pages; /* We need to read out the size of each page we will render, and lay * them out in the final image. */ VipsRect image; VipsRect *pages; /* The [double] background converted to image format. */ VipsPel *ink; /* Render this page box. */ VipsForeignPdfPageBox page_box; } VipsForeignLoadPdf; typedef VipsForeignLoadClass VipsForeignLoadPdfClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadPdf, vips_foreign_load_pdf, VIPS_TYPE_FOREIGN_LOAD); static char *vips_pdfium_errors[] = { "no error", "unknown error", "file not found or could not be opened", "file not in PDF format or corrupted", "password required or incorrect password", "unsupported security scheme", "page not found or content error" }; static GMutex vips_pdfium_mutex; static void vips_pdfium_error(void) { int err = FPDF_GetLastError(); if (err >= 0 && err < VIPS_NUMBER(vips_pdfium_errors)) vips_error("pdfload", "%s", _(vips_pdfium_errors[err])); else vips_error("pdfload", "%s", _("unknown error")); } static void vips_foreign_load_pdf_close(VipsForeignLoadPdf *pdf) { g_mutex_lock(&vips_pdfium_mutex); VIPS_FREEF(FPDF_ClosePage, pdf->page); VIPS_FREEF(FPDFDOC_ExitFormFillEnvironment, pdf->form); VIPS_FREEF(FPDF_CloseDocument, pdf->doc); VIPS_UNREF(pdf->source); g_mutex_unlock(&vips_pdfium_mutex); } static void vips_foreign_load_pdf_dispose(GObject *gobject) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) gobject; vips_foreign_load_pdf_close(pdf); G_OBJECT_CLASS(vips_foreign_load_pdf_parent_class)->dispose(gobject); } static void * vips_pdfium_init_cb(void *dummy) { FPDF_LIBRARY_CONFIG config; config.version = 2; config.m_pUserFontPaths = NULL; config.m_pIsolate = NULL; config.m_v8EmbedderSlot = 0; FPDF_InitLibraryWithConfig(&config); return NULL; } /* This is the m_GetBlock function for FPDF_FILEACCESS. */ static gboolean vips_pdfium_GetBlock(void *param, unsigned long position, unsigned char *pBuf, unsigned long size) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) param; /* PDFium guarantees these. */ g_assert(size > 0); g_assert(position >= 0); g_assert(position + size <= pdf->file_access.m_FileLen); if (vips_source_seek(pdf->source, position, SEEK_SET) < 0) return FALSE; while (size > 0) { gint64 bytes_read; if ((bytes_read = vips_source_read(pdf->source, pBuf, size)) < 0) return FALSE; pBuf += bytes_read; size -= bytes_read; } return TRUE; } static int vips_foreign_load_pdf_build(VipsObject *object) { static GOnce once = G_ONCE_INIT; VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(pdf); gint64 length; VIPS_ONCE(&once, vips_pdfium_init_cb, NULL); pdf->total_scale = pdf->scale * pdf->dpi / 72.0; pdf->form_callbacks.version = 2; /* pdfium must know the file length, unfortunately. */ if (pdf->source) { if ((length = vips_source_length(pdf->source)) <= 0) return -1; if (length > 1 << 30) { vips_error(class->nickname, _("%s: too large for pdfium"), vips_connection_nick( VIPS_CONNECTION(pdf->source))); return -1; } pdf->file_access.m_FileLen = length; pdf->file_access.m_GetBlock = vips_pdfium_GetBlock; pdf->file_access.m_Param = pdf; g_mutex_lock(&vips_pdfium_mutex); if (!(pdf->doc = FPDF_LoadCustomDocument(&pdf->file_access, pdf->password))) { g_mutex_unlock(&vips_pdfium_mutex); vips_pdfium_error(); vips_error("pdfload", _("%s: unable to load"), vips_connection_nick( VIPS_CONNECTION(pdf->source))); return -1; } if (!(pdf->form = FPDFDOC_InitFormFillEnvironment(pdf->doc, &pdf->form_callbacks))) { g_mutex_unlock(&vips_pdfium_mutex); vips_pdfium_error(); vips_error("pdfload", _("%s: unable to initialize form fill environment"), vips_connection_nick( VIPS_CONNECTION(pdf->source))); return -1; } g_mutex_unlock(&vips_pdfium_mutex); } return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_pdf_get_flags_filename(const char *filename) { /* We can render any part of the page on demand. */ return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_pdf_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static int vips_foreign_load_pdf_get_page(VipsForeignLoadPdf *pdf, int page_no) { if (pdf->current_page != page_no) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(pdf); g_mutex_lock(&vips_pdfium_mutex); VIPS_FREEF(FPDF_ClosePage, pdf->page); pdf->current_page = -1; #ifdef DEBUG printf("vips_foreign_load_pdf_get_page: %d\n", page_no); #endif /*DEBUG*/ if (!(pdf->page = FPDF_LoadPage(pdf->doc, page_no))) { g_mutex_unlock(&vips_pdfium_mutex); vips_pdfium_error(); vips_error(class->nickname, _("unable to load page %d"), page_no); return -1; } pdf->current_page = page_no; g_mutex_unlock(&vips_pdfium_mutex); } return 0; } /* String-based metadata fields we extract. */ typedef struct _VipsForeignLoadPdfMetadata { char *tag; /* as understood by PDFium */ char *field; /* as understood by libvips */ } VipsForeignLoadPdfMetadata; static VipsForeignLoadPdfMetadata vips_foreign_load_pdf_metadata[] = { { "Title", "pdf-title" }, { "Author", "pdf-author" }, { "Subject", "pdf-subject" }, { "Keywords", "pdf-keywords" }, { "Creator", "pdf-creator" }, { "Producer", "pdf-producer" }, /* poppler has "metadata" as well, but pdfium does not support this */ }; static int n_metadata = VIPS_NUMBER(vips_foreign_load_pdf_metadata); static int vips_foreign_load_pdf_set_image(VipsForeignLoadPdf *pdf, VipsImage *out) { int i; double res; #ifdef DEBUG printf("vips_foreign_load_pdf_set_image: %p\n", pdf); #endif /*DEBUG*/ /* We render to a tilecache, so it has to be SMALLTILE. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; /* Extract and attach metadata. Set the old name too for compat. */ vips_image_set_int(out, "pdf-n_pages", pdf->n_pages); vips_image_set_int(out, VIPS_META_N_PAGES, pdf->n_pages); g_mutex_lock(&vips_pdfium_mutex); for (i = 0; i < n_metadata; i++) { VipsForeignLoadPdfMetadata *metadata = &vips_foreign_load_pdf_metadata[i]; char text[1024]; int len; len = FPDF_GetMetaText(pdf->doc, metadata->tag, text, 1024); if (len > 0) { char *str; /* Silently ignore coding errors. */ if ((str = g_utf16_to_utf8((gunichar2 *) text, len, NULL, NULL, NULL))) { vips_image_set_string(out, metadata->field, str); g_free(str); } } } g_mutex_unlock(&vips_pdfium_mutex); /* We need pixels/mm for vips. */ res = pdf->dpi / 25.4; vips_image_init_fields(out, pdf->image.width, pdf->image.height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, res, res); return 0; } static void vips_foreign_load_pdf_apply_page_box(FPDF_PAGE page, VipsForeignPdfPageBox box) { float left, bottom, right, top; /* Avoid locking when no change in region to render. */ if (box == VIPS_FOREIGN_PDF_PAGE_BOX_CROP) return; g_mutex_lock(&vips_pdfium_mutex); switch (box) { case VIPS_FOREIGN_PDF_PAGE_BOX_MEDIA: if (FPDFPage_GetMediaBox(page, &left, &bottom, &right, &top)) FPDFPage_SetCropBox(page, left, bottom, right, top); else g_warning("missing media box, using default crop box"); break; case VIPS_FOREIGN_PDF_PAGE_BOX_TRIM: if (FPDFPage_GetTrimBox(page, &left, &bottom, &right, &top)) FPDFPage_SetCropBox(page, left, bottom, right, top); else g_warning("missing trim box, using default crop box"); break; case VIPS_FOREIGN_PDF_PAGE_BOX_BLEED: if (FPDFPage_GetBleedBox(page, &left, &bottom, &right, &top)) FPDFPage_SetCropBox(page, left, bottom, right, top); else g_warning("missing bleed box, using default crop box"); break; case VIPS_FOREIGN_PDF_PAGE_BOX_ART: if (FPDFPage_GetArtBox(page, &left, &bottom, &right, &top)) FPDFPage_SetCropBox(page, left, bottom, right, top); else g_warning("missing art box, using default crop box"); break; case VIPS_FOREIGN_PDF_PAGE_BOX_CROP: default: break; } g_mutex_unlock(&vips_pdfium_mutex); } static int vips_foreign_load_pdf_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) load; int top; #ifdef DEBUG printf("vips_foreign_load_pdf_header: %p\n", pdf); #endif /*DEBUG*/ g_mutex_lock(&vips_pdfium_mutex); pdf->n_pages = FPDF_GetPageCount(pdf->doc); g_mutex_unlock(&vips_pdfium_mutex); /* @n == -1 means until the end of the doc. */ if (pdf->n == -1) pdf->n = pdf->n_pages - pdf->page_no; // FIXME: Invalidates operation cache if (pdf->page_no + pdf->n > pdf->n_pages || pdf->page_no < 0 || pdf->n <= 0) { vips_error(class->nickname, "%s", _("pages out of range")); return -1; } /* Lay out the pages in our output image. */ if (!(pdf->pages = VIPS_ARRAY(pdf, pdf->n, VipsRect))) return -1; top = 0; pdf->image.left = 0; pdf->image.top = 0; pdf->image.width = 0; pdf->image.height = 0; for (int i = 0; i < pdf->n; i++) { if (vips_foreign_load_pdf_get_page(pdf, pdf->page_no + i)) return -1; pdf->pages[i].left = 0; pdf->pages[i].top = top; /* Attempt to apply selected page box using the page coordinate * system (bottom left) before calculating render dimensions * using the client coordinate system (top left). */ vips_foreign_load_pdf_apply_page_box(pdf->page, pdf->page_box); /* We do round to nearest, in the same way that vips_resize() * does round to nearest. Without this, things like * shrink-on-load will break. */ pdf->pages[i].width = rint( FPDF_GetPageWidth(pdf->page) * pdf->total_scale); pdf->pages[i].height = rint( FPDF_GetPageHeight(pdf->page) * pdf->total_scale); /* PDFium allows page width or height to be less than 1 (!!). */ if (pdf->pages[i].width < 1 || pdf->pages[i].height < 1 || pdf->pages[i].width > VIPS_MAX_COORD || pdf->pages[i].height > VIPS_MAX_COORD) { vips_error(class->nickname, "%s", _("page size out of range")); return -1; } if (pdf->pages[i].width > pdf->image.width) pdf->image.width = pdf->pages[i].width; pdf->image.height += pdf->pages[i].height; top += pdf->pages[i].height; } /* If all pages are the same height, we can tag this as a toilet roll * image. */ for (int i = 1; i < pdf->n; i++) if (pdf->pages[i].height != pdf->pages[0].height) break; /* Only set page-height if we have more than one page, or this could * accidentally turn into an animated image later. */ if (pdf->n > 1) vips_image_set_int(load->out, VIPS_META_PAGE_HEIGHT, pdf->pages[0].height); vips_foreign_load_pdf_set_image(pdf, load->out); /* Convert the background to the image format. */ if (!(pdf->ink = vips__vector_to_ink(class->nickname, load->out, VIPS_AREA(pdf->background)->data, NULL, VIPS_AREA(pdf->background)->n))) return -1; vips__bgra2rgba((guint32 *) pdf->ink, 1); return 0; } static void vips_foreign_load_pdf_minimise(VipsObject *object, VipsForeignLoadPdf *pdf) { vips_source_minimise(pdf->source); } static int vips_foreign_load_pdf_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) a; VipsRect *r = &out_region->valid; int top; int i; /* printf("vips_foreign_load_pdf_generate: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); */ /* Search through the pages we are drawing for the first containing * this rect. This could be quicker, perhaps a binary search, but who * cares. */ for (i = 0; i < pdf->n; i++) if (VIPS_RECT_BOTTOM(&pdf->pages[i]) > r->top) break; /* Reset out region. Otherwise there might be parts of previous pages * left. */ vips_region_black(out_region); top = r->top; while (top < VIPS_RECT_BOTTOM(r)) { FPDF_BITMAP bitmap; /* Is the rect within this page? It might not be if the output is more * than one tile wide and this page is narrower. */ VipsRect rect; vips_rect_intersectrect(r, &pdf->pages[i], &rect); if (rect.width > 0 && rect.height > 0) { if (vips_foreign_load_pdf_get_page(pdf, pdf->page_no + i)) return -1; vips__worker_lock(&vips_pdfium_mutex); /* 4 means RGBA. */ bitmap = FPDFBitmap_CreateEx(rect.width, rect.height, 4, VIPS_REGION_ADDR(out_region, rect.left, rect.top), VIPS_REGION_LSKIP(out_region)); /* Only paint the background if there's no transparency. */ if (!FPDFPage_HasTransparency(pdf->page)) { FPDF_DWORD ink = *((guint32 *) pdf->ink); FPDFBitmap_FillRect(bitmap, 0, 0, rect.width, rect.height, ink); } // pdfium writes bgra by default, we need rgba FPDF_RenderPageBitmap(bitmap, pdf->page, pdf->pages[i].left - rect.left, pdf->pages[i].top - rect.top, pdf->pages[i].width, pdf->pages[i].height, 0, FPDF_ANNOT | FPDF_REVERSE_BYTE_ORDER); FPDF_FFLDraw(pdf->form, bitmap, pdf->page, pdf->pages[i].left - rect.left, pdf->pages[i].top - rect.top, pdf->pages[i].width, pdf->pages[i].height, 0, FPDF_ANNOT | FPDF_REVERSE_BYTE_ORDER); FPDFBitmap_Destroy(bitmap); g_mutex_unlock(&vips_pdfium_mutex); } top += rect.height; i += 1; } return 0; } static int vips_foreign_load_pdf_load(VipsForeignLoad *load) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) load; VipsImage **t = (VipsImage **) vips_object_local_array((VipsObject *) load, 2); #ifdef DEBUG printf("vips_foreign_load_pdf_load: %p\n", pdf); #endif /*DEBUG*/ /* Read to this image, then cache to out, see below. */ t[0] = vips_image_new(); /* Close input immediately at end of read. */ g_signal_connect(t[0], "minimise", G_CALLBACK(vips_foreign_load_pdf_minimise), pdf); vips_foreign_load_pdf_set_image(pdf, t[0]); if (vips_image_generate(t[0], NULL, vips_foreign_load_pdf_generate, NULL, pdf, NULL) || vips_tilecache(t[0], &t[1], "tile_width", TILE_SIZE, "tile_height", TILE_SIZE, "max_tiles", 2 * (1 + t[0]->Xsize / TILE_SIZE), NULL) || vips_image_write(t[1], load->real)) return -1; return 0; } static void vips_foreign_load_pdf_class_init(VipsForeignLoadPdfClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_pdf_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload_base"; object_class->description = _("load PDF with PDFium"); object_class->build = vips_foreign_load_pdf_build; load_class->get_flags_filename = vips_foreign_load_pdf_get_flags_filename; load_class->get_flags = vips_foreign_load_pdf_get_flags; load_class->header = vips_foreign_load_pdf_header; load_class->load = vips_foreign_load_pdf_load; VIPS_ARG_INT(class, "page", 10, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, page_no), 0, 100000, 0); VIPS_ARG_INT(class, "n", 11, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, n), -1, 100000, 1); VIPS_ARG_DOUBLE(class, "dpi", 12, _("DPI"), _("DPI to render at"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, dpi), 0.001, 100000.0, 72.0); VIPS_ARG_DOUBLE(class, "scale", 13, _("Scale"), _("Factor to scale by"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, scale), 0.0, 100000.0, 1.0); VIPS_ARG_BOXED(class, "background", 14, _("Background"), _("Background colour"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_STRING(class, "password", 25, _("Password"), _("Password to decrypt with"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, password), NULL); VIPS_ARG_ENUM(class, "page_box", 26, _("Page box"), _("The region of the page to render"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, page_box), VIPS_TYPE_FOREIGN_PDF_PAGE_BOX, VIPS_FOREIGN_PDF_PAGE_BOX_CROP); } static void vips_foreign_load_pdf_init(VipsForeignLoadPdf *pdf) { pdf->dpi = 72.0; pdf->scale = 1.0; pdf->n = 1; pdf->current_page = -1; pdf->background = vips_array_double_newv(1, 255.0); pdf->page_box = VIPS_FOREIGN_PDF_PAGE_BOX_CROP; } typedef struct _VipsForeignLoadPdfFile { VipsForeignLoadPdf parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadPdfFile; typedef VipsForeignLoadPdfClass VipsForeignLoadPdfFileClass; G_DEFINE_TYPE(VipsForeignLoadPdfFile, vips_foreign_load_pdf_file, vips_foreign_load_pdf_get_type()); static int vips_foreign_load_pdf_file_header(VipsForeignLoad *load) { VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) load; VIPS_SETSTR(load->out->filename, file->filename); return VIPS_FOREIGN_LOAD_CLASS(vips_foreign_load_pdf_file_parent_class) ->header(load); } static int vips_foreign_load_pdf_file_build(VipsObject *object) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object; VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) pdf; #ifdef DEBUG printf("vips_foreign_load_pdf_file_build: %s\n", file->filename); #endif /*DEBUG*/ if (file->filename && !(pdf->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_file_parent_class) ->build(object); } static void vips_foreign_load_pdf_file_class_init( VipsForeignLoadPdfFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload"; object_class->description = _("load PDF from file (pdfium)"); object_class->build = vips_foreign_load_pdf_file_build; foreign_class->suffs = vips__pdf_suffs; load_class->is_a = vips__pdf_is_a_file; load_class->header = vips_foreign_load_pdf_file_header; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdfFile, filename), NULL); } static void vips_foreign_load_pdf_file_init(VipsForeignLoadPdfFile *file) { } typedef struct _VipsForeignLoadPdfBuffer { VipsForeignLoadPdf parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadPdfBuffer; typedef VipsForeignLoadPdfClass VipsForeignLoadPdfBufferClass; G_DEFINE_TYPE(VipsForeignLoadPdfBuffer, vips_foreign_load_pdf_buffer, vips_foreign_load_pdf_get_type()); static int vips_foreign_load_pdf_buffer_build(VipsObject *object) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object; VipsForeignLoadPdfBuffer *buffer = (VipsForeignLoadPdfBuffer *) pdf; if (buffer->buf && !(pdf->source = vips_source_new_from_memory( VIPS_AREA(buffer->buf)->data, VIPS_AREA(buffer->buf)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_buffer_parent_class) ->build(object); } static void vips_foreign_load_pdf_buffer_class_init( VipsForeignLoadPdfBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload_buffer"; object_class->description = _("load PDF from buffer (pdfium)"); object_class->build = vips_foreign_load_pdf_buffer_build; load_class->is_a_buffer = vips__pdf_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdfBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_pdf_buffer_init(VipsForeignLoadPdfBuffer *buffer) { } typedef struct _VipsForeignLoadPdfSource { VipsForeignLoadPdf parent_object; VipsSource *source; } VipsForeignLoadPdfSource; typedef VipsForeignLoadPdfClass VipsForeignLoadPdfSourceClass; G_DEFINE_TYPE(VipsForeignLoadPdfSource, vips_foreign_load_pdf_source, vips_foreign_load_pdf_get_type()); static int vips_foreign_load_pdf_source_build(VipsObject *object) { VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) object; VipsForeignLoadPdfSource *source = (VipsForeignLoadPdfSource *) pdf; if (source->source) { pdf->source = source->source; g_object_ref(pdf->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_source_parent_class) ->build(object); } static void vips_foreign_load_pdf_source_class_init( VipsForeignLoadPdfSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload_source"; object_class->description = _("load PDF from source (pdfium)"); object_class->build = vips_foreign_load_pdf_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips__pdf_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdfSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_pdf_source_init(VipsForeignLoadPdfSource *source) { } #endif /*HAVE_PDFIUM*/ libvips-8.18.2/libvips/foreign/pforeign.h000066400000000000000000000165411516303661500203620ustar00rootroot00000000000000/* Private decls shared by all foreign. */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PFOREIGN_H #define VIPS_PFOREIGN_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* We've seen real images with 28 chunks, so set 50. */ #define MAX_PNG_TEXT_CHUNKS 50 int vips__foreign_update_metadata(VipsImage *in, VipsForeignKeep keep); void vips__tiff_init(void); int vips__tiff_write_target(VipsImage *in, VipsTarget *target, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, gboolean miniswhite, VipsForeignTiffResunit resunit, double xres, double yres, gboolean bigtiff, gboolean rgbjpeg, gboolean properties, VipsRegionShrink region_shrink, int level, gboolean lossless, VipsForeignDzDepth depth, gboolean subifd, gboolean premultiply, int page_height); gboolean vips__istiff_source(VipsSource *source); gboolean vips__istifftiled_source(VipsSource *source); int vips__tiff_read_header_source(VipsSource *source, VipsImage *out, int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on, gboolean unlimited); int vips__tiff_read_source(VipsSource *source, VipsImage *out, int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on, gboolean unlimited); extern const char *vips__foreign_tiff_suffs[]; int vips__isanalyze(const char *filename); int vips__analyze_read_header(const char *filename, VipsImage *out); int vips__analyze_read(const char *filename, VipsImage *out); extern const char *vips__foreign_csv_suffs[]; extern const char *vips__foreign_matrix_suffs[]; int vips__openexr_isexr(const char *filename); gboolean vips__openexr_istiled(const char *filename); int vips__openexr_read_header(const char *filename, VipsImage *out); int vips__openexr_read(const char *filename, VipsImage *out); extern const char *vips__fits_suffs[]; int vips__fits_isfits(const char *filename); int vips__fits_read_header(const char *filename, VipsImage *out); int vips__fits_read(const char *filename, VipsImage *out); int vips__fits_write(VipsImage *in, const char *filename); extern const char *vips__mat_suffs[]; int vips__mat_load(const char *filename, VipsImage *out); int vips__mat_header(const char *filename, VipsImage *out); int vips__mat_ismat(const char *filename); extern const char *vips__ppm_suffs[]; extern const char *vips__save_pbm_suffs[]; extern const char *vips__save_pgm_suffs[]; extern const char *vips__save_ppm_suffs[]; extern const char *vips__save_pfm_suffs[]; extern const char *vips__save_pnm_suffs[]; int vips__rad_israd(VipsSource *source); int vips__rad_header(VipsSource *source, VipsImage *out); int vips__rad_load(VipsSource *source, VipsImage *out); int vips__rad_save(VipsImage *in, VipsTarget *target); extern const char *vips__rad_suffs[]; extern const char *vips__jpeg_suffs[]; int vips__jpeg_write_target(VipsImage *in, VipsTarget *target, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval); int vips__jpeg_region_write_target(VipsRegion *region, VipsRect *rect, VipsTarget *target, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, VipsForeignKeep keep, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval); int vips__jpeg_read_source(VipsSource *source, VipsImage *out, gboolean header_only, int shrink, VipsFailOn fail_on, gboolean autorotate, gboolean unlimited); int vips__isjpeg_source(VipsSource *source); int vips__png_ispng_source(VipsSource *source); int vips__png_header_source(VipsSource *source, VipsImage *out, gboolean unlimited); int vips__png_read_source(VipsSource *source, VipsImage *out, VipsFailOn fail_on, gboolean unlimited); gboolean vips__png_isinterlaced_source(VipsSource *source); extern const char *vips__png_suffs[]; int vips__png_write_target(VipsImage *in, VipsTarget *target, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean palette, int Q, double dither, int bitdepth, int effort); /* Map WEBP metadata names to vips names. */ typedef struct _VipsWebPNames { const char *vips; const char *webp; int flags; } VipsWebPNames; extern const VipsWebPNames vips__webp_names[]; extern const int vips__n_webp_names; extern const char *vips__webp_suffs[]; int vips__iswebp_source(VipsSource *source); int vips__webp_read_header_source(VipsSource *source, VipsImage *out, int page, int n, double scale); int vips__webp_read_source(VipsSource *source, VipsImage *out, int page, int n, double scale); extern const char *vips_foreign_nifti_suffs[]; VipsBandFormat vips__foreign_nifti_datatype2BandFmt(int datatype); int vips__foreign_nifti_BandFmt2datatype(VipsBandFormat fmt); typedef void *(*VipsNiftiMapFn)(const char *name, GValue *value, glong offset, void *a, void *b); void *vips__foreign_nifti_map(VipsNiftiMapFn fn, void *a, void *b); extern const char *vips__heic_suffs[]; extern const char *vips__avif_suffs[]; extern const char *vips__heif_suffs[]; struct heif_image; struct heif_error; void vips__heif_init(void); int vips__heif_chroma(int bits_per_pixel, gboolean has_alpha); void vips__heif_image_print(struct heif_image *img); void vips__heif_error(struct heif_error *error); extern const char *vips__jp2k_suffs[]; int vips__foreign_load_jp2k_decompress(VipsImage *out, int width, int height, gboolean ycc_to_rgb, void *from, size_t from_length, void *to, size_t to_length); int vips__foreign_save_jp2k_compress(VipsRegion *region, VipsRect *tile, VipsTarget *target, int tile_width, int tile_height, gboolean save_as_ycc, gboolean subsample, gboolean lossless, int Q); extern const char *vips__jxl_suffs[]; struct _VipsArchive; typedef struct _VipsArchive VipsArchive; void vips__archive_free(VipsArchive *archive); VipsArchive *vips__archive_new_to_dir(const char *base_dirname); VipsArchive *vips__archive_new_to_target(VipsTarget *target, const char *base_dirname, int compression); int vips__archive_mkdir(VipsArchive *archive, const char *dirname); int vips__archive_mkfile(VipsArchive *archive, const char *filename, void *buf, size_t len); extern const char *vips__pdf_suffs[]; gboolean vips__pdf_is_a_buffer(const void *buf, size_t len); gboolean vips__pdf_is_a_file(const char *filename); gboolean vips__pdf_is_a_source(VipsSource *source); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PFOREIGN_H*/ libvips-8.18.2/libvips/foreign/pngload.c000066400000000000000000000312571516303661500201710ustar00rootroot00000000000000/* load png from a file * * 5/12/11 * - from tiffload.c * 29/8/21 joshuamsager * - add "unlimited" flag to png load */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #if defined(HAVE_PNG) typedef struct _VipsForeignLoadPng { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* remove all denial of service limits. */ gboolean unlimited; } VipsForeignLoadPng; typedef VipsForeignLoadClass VipsForeignLoadPngClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadPng, vips_foreign_load_png, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_png_dispose(GObject *gobject) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) gobject; VIPS_UNREF(png->source); G_OBJECT_CLASS(vips_foreign_load_png_parent_class)->dispose(gobject); } static VipsForeignFlags vips_foreign_load_png_get_flags_source(VipsSource *source) { VipsForeignFlags flags; flags = 0; if (vips__png_isinterlaced_source(source)) flags |= VIPS_FOREIGN_PARTIAL; else flags |= VIPS_FOREIGN_SEQUENTIAL; return flags; } static VipsForeignFlags vips_foreign_load_png_get_flags(VipsForeignLoad *load) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; return vips_foreign_load_png_get_flags_source(png->source); } static VipsForeignFlags vips_foreign_load_png_get_flags_filename(const char *filename) { VipsSource *source; VipsForeignFlags flags; if (!(source = vips_source_new_from_file(filename))) return 0; flags = vips_foreign_load_png_get_flags_source(source); VIPS_UNREF(source); return flags; } static int vips_foreign_load_png_header(VipsForeignLoad *load) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; if (vips__png_header_source(png->source, load->out, png->unlimited)) return -1; return 0; } static int vips_foreign_load_png_load(VipsForeignLoad *load) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; if (vips__png_read_source(png->source, load->real, load->fail_on, png->unlimited)) return -1; return 0; } static void vips_foreign_load_png_class_init(VipsForeignLoadPngClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_png_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload_base"; object_class->description = _("load png base class"); /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; load_class->get_flags_filename = vips_foreign_load_png_get_flags_filename; load_class->get_flags = vips_foreign_load_png_get_flags; load_class->header = vips_foreign_load_png_header; load_class->load = vips_foreign_load_png_load; #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VIPS_ARG_BOOL(class, "unlimited", 23, _("Unlimited"), _("Remove all denial of service limits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPng, unlimited), FALSE); #endif } static void vips_foreign_load_png_init(VipsForeignLoadPng *png) { } typedef struct _VipsForeignLoadPngSource { VipsForeignLoadPng parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadPngSource; typedef VipsForeignLoadPngClass VipsForeignLoadPngSourceClass; G_DEFINE_TYPE(VipsForeignLoadPngSource, vips_foreign_load_png_source, vips_foreign_load_png_get_type()); static int vips_foreign_load_png_source_build(VipsObject *object) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) object; VipsForeignLoadPngSource *source = (VipsForeignLoadPngSource *) object; if (source->source) { png->source = source->source; g_object_ref(png->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_png_source_parent_class) ->build(object); } static gboolean vips_foreign_load_png_source_is_a_source(VipsSource *source) { return vips__png_ispng_source(source); } static void vips_foreign_load_png_source_class_init(VipsForeignLoadPngSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload_source"; object_class->description = _("load png from source"); object_class->build = vips_foreign_load_png_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_png_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPngSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_png_source_init(VipsForeignLoadPngSource *source) { } typedef struct _VipsForeignLoadPngFile { VipsForeignLoadPng parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadPngFile; typedef VipsForeignLoadPngClass VipsForeignLoadPngFileClass; G_DEFINE_TYPE(VipsForeignLoadPngFile, vips_foreign_load_png_file, vips_foreign_load_png_get_type()); static int vips_foreign_load_png_file_build(VipsObject *object) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) object; VipsForeignLoadPngFile *file = (VipsForeignLoadPngFile *) object; if (file->filename && !(png->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_png_file_parent_class) ->build(object); } static gboolean vips_foreign_load_png_file_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_png_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_png_file_class_init(VipsForeignLoadPngFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload"; object_class->description = _("load png from file"); object_class->build = vips_foreign_load_png_file_build; foreign_class->suffs = vips__png_suffs; load_class->is_a = vips_foreign_load_png_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPngFile, filename), NULL); } static void vips_foreign_load_png_file_init(VipsForeignLoadPngFile *file) { } typedef struct _VipsForeignLoadPngBuffer { VipsForeignLoadPng parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadPngBuffer; typedef VipsForeignLoadPngClass VipsForeignLoadPngBufferClass; G_DEFINE_TYPE(VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer, vips_foreign_load_png_get_type()); static int vips_foreign_load_png_buffer_build(VipsObject *object) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) object; VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) object; if (buffer->blob && !(png->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_png_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_png_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_png_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_png_buffer_class_init(VipsForeignLoadPngBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload_buffer"; object_class->description = _("load png from buffer"); object_class->build = vips_foreign_load_png_buffer_build; load_class->is_a_buffer = vips_foreign_load_png_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPngBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_png_buffer_init(VipsForeignLoadPngBuffer *buffer) { } #endif /*HAVE_PNG*/ /** * vips_pngload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a PNG file into a VIPS image. It can read all png images, including 8- * and 16-bit images, 1 and 3 channel, with and without an alpha channel. * * Any ICC profile is read and attached to the VIPS image. It also supports * XMP metadata. * * Use @fail_on to set the type of error that will cause load to fail. By * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE]. * * By default, the PNG loader limits the number of text and data chunks to * block some denial of service attacks. Set @unlimited to disable these * limits. * * ::: tip "Optional arguments" * * @fail_on: [enum@FailOn], types of read error to fail on * * @unlimited: `gboolean`, Remove all denial of service limits * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_pngload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("pngload", ap, filename, out); va_end(ap); return result; } /** * vips_pngload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.pngload], but read from a PNG-formatted memory block. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @fail_on: [enum@FailOn], types of read error to fail on * * @unlimited: `gboolean`, Remove all denial of service limits * * ::: seealso * [ctor@Image.pngload]. * * Returns: 0 on success, -1 on error. */ int vips_pngload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("pngload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_pngload_source: * @source: source to load from * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.pngload], but read from a source. * * ::: tip "Optional arguments" * * @fail_on: [enum@FailOn], types of read error to fail on * * @unlimited: `gboolean`, Remove all denial of service limits * * ::: seealso * [ctor@Image.pngload]. * * Returns: 0 on success, -1 on error. */ int vips_pngload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("pngload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/pngsave.c000066400000000000000000000402301516303661500201770ustar00rootroot00000000000000/* save to png * * 2/12/11 * - wrap a class around the png writer * 16/7/12 * - compression should be 0-9, not 1-10 * 20/6/18 [felixbuenemann] * - support png8 palette write with palette, colours, Q, dither * 24/6/20 * - add @bitdepth, deprecate @colours * 15/7/22 [lovell] * - default filter to none */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_PNG typedef struct _VipsForeignSavePng { VipsForeignSave parent_object; int compression; gboolean interlace; VipsForeignPngFilter filter; gboolean palette; int Q; double dither; int bitdepth; int effort; /* Set by subclasses. */ VipsTarget *target; /* Deprecated. */ int colours; } VipsForeignSavePng; typedef VipsForeignSaveClass VipsForeignSavePngClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSavePng, vips_foreign_save_png, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_png_dispose(GObject *gobject) { VipsForeignSavePng *png = (VipsForeignSavePng *) gobject; VIPS_UNREF(png->target); G_OBJECT_CLASS(vips_foreign_save_png_parent_class)->dispose(gobject); } static int vips_foreign_save_png_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSavePng *png = (VipsForeignSavePng *) object; VipsImage *in; VipsImage *x; if (VIPS_OBJECT_CLASS(vips_foreign_save_png_parent_class)->build(object)) return -1; in = save->ready; g_object_ref(in); /* If no output bitdepth has been specified, use input Type to pick. */ if (!vips_object_argument_isset(object, "bitdepth")) png->bitdepth = in->Type == VIPS_INTERPRETATION_RGB16 || in->Type == VIPS_INTERPRETATION_GREY16 ? 16 : 8; /* Deprecated "colours" arg just sets bitdepth large enough to hold * that many colours. */ if (vips_object_argument_isset(object, "colours")) png->bitdepth = ceil(log2(png->colours)); /* The bitdepth param can change the interpretation. */ VipsInterpretation interpretation; if (in->Bands > 2) { if (png->bitdepth > 8) interpretation = VIPS_INTERPRETATION_RGB16; else interpretation = VIPS_INTERPRETATION_sRGB; } else { if (png->bitdepth > 8) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_B_W; } if (vips_colourspace(in, &x, interpretation, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = x; /* If this is a RGB or RGBA image and a low bit depth has been * requested, enable palettization. */ if (in->Bands > 2 && png->bitdepth < 8) png->palette = TRUE; /* Disable palettization for >8 bit save. */ if (png->bitdepth > 8) png->palette = FALSE; if (vips__png_write_target(in, png->target, png->compression, png->interlace, save->profile, png->filter, png->palette, png->Q, png->dither, png->bitdepth, png->effort)) { g_object_unref(in); return -1; } if (vips_target_end(png->target)) return -1; g_object_unref(in); return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX /* Except for 8-bit inputs, we send everything else to 16. We decide on png8 * vs. png16 based on Type in_build(), see above. */ static VipsBandFormat bandfmt_png[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, US, US, US, US, US, US }; static void vips_foreign_save_png_class_init(VipsForeignSavePngClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_png_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave_base"; object_class->description = _("save png"); object_class->build = vips_foreign_save_png_build; foreign_class->suffs = vips__png_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA; save_class->format_table = bandfmt_png; VIPS_ARG_INT(class, "compression", 6, _("Compression"), _("Compression factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, compression), 0, 9, 6); VIPS_ARG_BOOL(class, "interlace", 7, _("Interlace"), _("Interlace image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, interlace), FALSE); VIPS_ARG_FLAGS(class, "filter", 12, _("Filter"), _("libpng row filter flag(s)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, filter), VIPS_TYPE_FOREIGN_PNG_FILTER, VIPS_FOREIGN_PNG_FILTER_NONE); VIPS_ARG_BOOL(class, "palette", 13, _("Palette"), _("Quantise to 8bpp palette"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, palette), FALSE); VIPS_ARG_INT(class, "Q", 15, _("Quality"), _("Quantisation quality"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, Q), 0, 100, 100); VIPS_ARG_DOUBLE(class, "dither", 16, _("Dithering"), _("Amount of dithering"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, dither), 0.0, 1.0, 1.0); VIPS_ARG_INT(class, "bitdepth", 17, _("Bit depth"), _("Write as a 1, 2, 4, 8 or 16 bit image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, bitdepth), 1, 16, 8); VIPS_ARG_INT(class, "effort", 18, _("Effort"), _("Quantisation CPU effort"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePng, effort), 1, 10, 7); VIPS_ARG_INT(class, "colours", 14, _("Colours"), _("Max number of palette colours"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSavePng, colours), 2, 256, 256); } static void vips_foreign_save_png_init(VipsForeignSavePng *png) { png->compression = 6; png->filter = VIPS_FOREIGN_PNG_FILTER_NONE; png->Q = 100; png->dither = 1.0; png->effort = 7; } typedef struct _VipsForeignSavePngTarget { VipsForeignSavePng parent_object; VipsTarget *target; } VipsForeignSavePngTarget; typedef VipsForeignSavePngClass VipsForeignSavePngTargetClass; G_DEFINE_TYPE(VipsForeignSavePngTarget, vips_foreign_save_png_target, vips_foreign_save_png_get_type()); static int vips_foreign_save_png_target_build(VipsObject *object) { VipsForeignSavePng *png = (VipsForeignSavePng *) object; VipsForeignSavePngTarget *target = (VipsForeignSavePngTarget *) object; png->target = target->target; g_object_ref(png->target); return VIPS_OBJECT_CLASS(vips_foreign_save_png_target_parent_class) ->build(object); } static void vips_foreign_save_png_target_class_init(VipsForeignSavePngTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave_target"; object_class->description = _("save image to target as PNG"); object_class->build = vips_foreign_save_png_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSavePngTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_png_target_init(VipsForeignSavePngTarget *target) { } typedef struct _VipsForeignSavePngFile { VipsForeignSavePng parent_object; char *filename; } VipsForeignSavePngFile; typedef VipsForeignSavePngClass VipsForeignSavePngFileClass; G_DEFINE_TYPE(VipsForeignSavePngFile, vips_foreign_save_png_file, vips_foreign_save_png_get_type()); static int vips_foreign_save_png_file_build(VipsObject *object) { VipsForeignSavePng *png = (VipsForeignSavePng *) object; VipsForeignSavePngFile *file = (VipsForeignSavePngFile *) object; if (!(png->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_png_file_parent_class)-> build(object); } static void vips_foreign_save_png_file_class_init(VipsForeignSavePngFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave"; object_class->description = _("save image to file as png"); object_class->build = vips_foreign_save_png_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSavePngFile, filename), NULL); } static void vips_foreign_save_png_file_init(VipsForeignSavePngFile *file) { } typedef struct _VipsForeignSavePngBuffer { VipsForeignSavePng parent_object; VipsArea *buf; } VipsForeignSavePngBuffer; typedef VipsForeignSavePngClass VipsForeignSavePngBufferClass; G_DEFINE_TYPE(VipsForeignSavePngBuffer, vips_foreign_save_png_buffer, vips_foreign_save_png_get_type()); static int vips_foreign_save_png_buffer_build(VipsObject *object) { VipsForeignSavePng *png = (VipsForeignSavePng *) object; VipsForeignSavePngBuffer *buffer = (VipsForeignSavePngBuffer *) object; VipsBlob *blob; if (!(png->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_png_buffer_parent_class) ->build(object)) return -1; g_object_get(png->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_png_buffer_class_init(VipsForeignSavePngBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave_buffer"; object_class->description = _("save image to buffer as png"); object_class->build = vips_foreign_save_png_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSavePngBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_png_buffer_init(VipsForeignSavePngBuffer *buffer) { } #endif /*HAVE_PNG*/ /** * vips_pngsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file as PNG. * * @compression means compress with this much effort (0 - 9). Default 6. * * Set @interlace to `TRUE` to interlace the image with ADAM7 * interlacing. Beware * than an interlaced PNG can be up to 7 times slower to write than a * non-interlaced image. * * Use @filter to specify one or more filters, defaults to none, * see [flags@ForeignPngFilter]. * * The image is automatically converted to RGB, RGBA, Monochrome or Mono + * alpha before saving. Images with more than one byte per band element are * saved as 16-bit PNG, others are saved as 8-bit PNG. * * Set @palette to `TRUE` to enable palette mode for RGB or RGBA images. A * palette will be computed with enough space for @bitdepth (1, 2, 4 or 8) * bits. Use @Q to set the optimisation effort, @dither to set the degree of * Floyd-Steinberg dithering and @effort to control the CPU effort * (1 is the fastest, 10 is the slowest, 7 is the default). * This feature requires libvips to be compiled with libimagequant. * * The default @bitdepth is either 8 or 16 depending on the interpretation. * You can also set @bitdepth for mono and mono + alpha images, and the image * will be quantized. * * XMP metadata is written to the XMP chunk. PNG comments are written to * separate text chunks. * * ::: tip "Optional arguments" * * @compression: `gint`, compression level * * @interlace: `gboolean`, interlace image * * @filter: [flags@ForeignPngFilter], row filter flag(s) * * @palette: `gboolean`, enable quantisation to 8bpp palette * * @Q: `gint`, quality for 8bpp quantisation * * @dither: `gdouble`, amount of dithering for 8bpp quantization * * @bitdepth: `gint`, set write bit depth to 1, 2, 4, 8 or 16 * * @effort: `gint`, quantisation CPU effort * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_pngsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("pngsave", ap, in, filename); va_end(ap); return result; } /** * vips_pngsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.pngsave], but save to a memory buffer. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: tip "Optional arguments" * * @compression: `gint`, compression level * * @interlace: `gboolean`, interlace image * * @filter: [flags@ForeignPngFilter], row filter flag(s) * * @palette: `gboolean`, enable quantisation to 8bpp palette * * @Q: `gint`, quality for 8bpp quantisation * * @dither: `gdouble`, amount of dithering for 8bpp quantization * * @bitdepth: `gint`, set write bit depth to 1, 2, 4, 8 or 16 * * @effort: `gint`, quantisation CPU effort * * ::: seealso * [method@Image.pngsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_pngsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("pngsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_pngsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.pngsave], but save to a target. * * ::: tip "Optional arguments" * * @compression: `gint`, compression level * * @interlace: `gboolean`, interlace image * * @filter: [flags@ForeignPngFilter], row filter flag(s) * * @palette: `gboolean`, enable quantisation to 8bpp palette * * @Q: `gint`, quality for 8bpp quantisation * * @dither: `gdouble`, amount of dithering for 8bpp quantization * * @bitdepth: `gint`, set write bit depth to 1, 2, 4, 8 or 16 * * @effort: `gint`, quantisation CPU effort * * ::: seealso * [method@Image.pngsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_pngsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("pngsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/popplerload.c000066400000000000000000000522741516303661500210700ustar00rootroot00000000000000/* load PDF with libpoppler * * 7/2/16 * - from openslideload.c * 12/5/16 * - add @n ... number of pages to load * 23/11/16 * - set page-height, if we can * 28/6/17 * - use a much larger strip size, thanks bubba * 8/6/18 * - add background param * 16/8/18 [kleisauke] * - shut down the input file as soon as we can * 19/9/19 * - reopen the input if we minimised too early * 11/3/20 * - move on top of VipsSource * 21/9/20 * - allow dpi and scale to both be set [le0daniel] * 21/4/21 kleisauke * - include GObject part from pdfload.c * 28/1/22 * - add password */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_POPPLER #include #include /* Render PDFs with tiles this size. They need to be pretty big to limit * overcomputation. * * An A4 page at 300dpi is 3508 pixels, so this should be enough to prevent * most rerendering. */ #define TILE_SIZE (4000) #define VIPS_TYPE_FOREIGN_LOAD_PDF (vips_foreign_load_pdf_get_type()) #define VIPS_FOREIGN_LOAD_PDF(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_LOAD_PDF, VipsForeignLoadPdf)) #define VIPS_FOREIGN_LOAD_PDF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN_LOAD_PDF, VipsForeignLoadPdfClass)) #define VIPS_IS_FOREIGN_LOAD_PDF(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN_LOAD_PDF)) #define VIPS_IS_FOREIGN_LOAD_PDF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN_LOAD_PDF)) #define VIPS_FOREIGN_LOAD_PDF_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN_LOAD_PDF, VipsForeignLoadPdfClass)) typedef struct _VipsForeignLoadPdf { VipsForeignLoad parent_object; /* The VipsSource we load from, and the GInputStream we wrap around * it. Set from subclasses. */ VipsSource *source; GInputStream *stream; /* Load this page. */ int page_no; /* Load this many pages. */ int n; /* Render at this DPI. */ double dpi; /* Scale by this factor. */ double scale; /* The total scale factor we render with. */ double total_scale; /* Background colour. */ VipsArrayDouble *background; /* Decrypt with this. */ const char *password; /* Poppler is not thread-safe, so we run inside a single-threaded * cache. On the plus side, this means we only need one @page pointer, * even though we change this during _generate(). */ PopplerDocument *doc; PopplerPage *page; int current_page; /* Doc has this many pages. */ int n_pages; /* We need to read out the size of each page we will render, and lay * them out in the final image. */ VipsRect image; VipsRect *pages; /* The [double] background converted to the image format. */ VipsPel *ink; /* Render this page box, currently only crop is supported. */ VipsForeignPdfPageBox page_box; } VipsForeignLoadPdf; typedef struct _VipsForeignLoadPdfClass { VipsForeignLoadClass parent_class; } VipsForeignLoadPdfClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadPdf, vips_foreign_load_pdf, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_pdf_dispose(GObject *gobject) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(gobject); VIPS_UNREF(pdf->page); VIPS_UNREF(pdf->doc); VIPS_UNREF(pdf->source); VIPS_UNREF(pdf->stream); G_OBJECT_CLASS(vips_foreign_load_pdf_parent_class)->dispose(gobject); } static int vips_foreign_load_pdf_build(VipsObject *object) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(object); GError *error = NULL; if (vips_source_rewind(pdf->source)) return -1; pdf->total_scale = pdf->scale * pdf->dpi / 72.0; pdf->stream = vips_g_input_stream_new_from_source(pdf->source); if (!(pdf->doc = poppler_document_new_from_stream(pdf->stream, vips_source_length(pdf->source), pdf->password, NULL, &error))) { vips_g_error(&error); return -1; } return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_pdf_get_flags_filename(const char *filename) { /* We can render any part of the page on demand. */ return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_pdf_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static int vips_foreign_load_pdf_get_page(VipsForeignLoadPdf *pdf, int page_no) { if (pdf->current_page != page_no || !pdf->page) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(pdf); VIPS_UNREF(pdf->page); pdf->current_page = -1; #ifdef DEBUG printf("vips_foreign_load_pdf_get_page: %d\n", page_no); #endif /*DEBUG*/ if (!(pdf->page = poppler_document_get_page(pdf->doc, page_no))) { vips_error(class->nickname, _("unable to load page %d"), page_no); return -1; } pdf->current_page = page_no; } return 0; } /* String-based metadata fields we extract. */ typedef struct _VipsForeignLoadPdfMetadata { char *(*pdf_fetch)(PopplerDocument *doc); char *field; } VipsForeignLoadPdfMetadata; static VipsForeignLoadPdfMetadata vips_foreign_load_pdf_metadata[] = { { poppler_document_get_title, "pdf-title" }, { poppler_document_get_author, "pdf-author" }, { poppler_document_get_subject, "pdf-subject" }, { poppler_document_get_keywords, "pdf-keywords" }, { poppler_document_get_creator, "pdf-creator" }, { poppler_document_get_producer, "pdf-producer" }, { poppler_document_get_metadata, "pdf-metadata" }, }; static int n_metadata = VIPS_NUMBER(vips_foreign_load_pdf_metadata); static int vips_foreign_load_pdf_set_image(VipsForeignLoadPdf *pdf, VipsImage *out) { int i; double res; #ifdef DEBUG printf("vips_foreign_load_pdf_set_image: %p\n", pdf); #endif /*DEBUG*/ /* Extract and attach metadata. Set the old name too for compat. */ vips_image_set_int(out, "pdf-n_pages", pdf->n_pages); vips_image_set_int(out, VIPS_META_N_PAGES, pdf->n_pages); for (i = 0; i < n_metadata; i++) { VipsForeignLoadPdfMetadata *metadata = &vips_foreign_load_pdf_metadata[i]; char *str; if ((str = metadata->pdf_fetch(pdf->doc))) { vips_image_set_string(out, metadata->field, str); g_free(str); } } /* We need pixels/mm for vips. */ res = pdf->dpi / 25.4; vips_image_init_fields(out, pdf->image.width, pdf->image.height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, res, res); /* We render to a tilecache, so it has to be SMALLTILE. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; return 0; } static int vips_foreign_load_pdf_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(load); int top; #ifdef DEBUG printf("vips_foreign_load_pdf_header: %p\n", pdf); #endif /*DEBUG*/ pdf->n_pages = poppler_document_get_n_pages(pdf->doc); /* @n == -1 means until the end of the doc. */ if (pdf->n == -1) pdf->n = pdf->n_pages - pdf->page_no; // FIXME: Invalidates operation cache if (pdf->page_no + pdf->n > pdf->n_pages || pdf->page_no < 0 || pdf->n <= 0) { vips_error(class->nickname, "%s", _("pages out of range")); return -1; } /* Lay out the pages in our output image. */ if (!(pdf->pages = VIPS_ARRAY(pdf, pdf->n, VipsRect))) return -1; if (pdf->page_box != VIPS_FOREIGN_PDF_PAGE_BOX_CROP) g_warning("only crop page box is supported"); top = 0; pdf->image.left = 0; pdf->image.top = 0; pdf->image.width = 0; pdf->image.height = 0; for (int i = 0; i < pdf->n; i++) { double width; double height; if (vips_foreign_load_pdf_get_page(pdf, pdf->page_no + i)) return -1; poppler_page_get_size(pdf->page, &width, &height); pdf->pages[i].left = 0; pdf->pages[i].top = top; /* We do round to nearest, in the same way that vips_resize() * does round to nearest. Without this, things like * shrink-on-load will break. */ pdf->pages[i].width = rint(width * pdf->total_scale); pdf->pages[i].height = rint(height * pdf->total_scale); if (pdf->pages[i].width <= 0 || pdf->pages[i].height <= 0) { vips_error(class->nickname, "%s", _("zero-sized image")); return -1; } if (pdf->pages[i].width > pdf->image.width) pdf->image.width = pdf->pages[i].width; pdf->image.height += pdf->pages[i].height; top += pdf->pages[i].height; } /* If all pages are the same height, we can tag this as a toilet roll * image. */ for (int i = 1; i < pdf->n; i++) if (pdf->pages[i].height != pdf->pages[0].height) break; /* Only set page-height if we have more than one page, or this could * accidentally turn into an animated image later. */ if (pdf->n > 1) vips_image_set_int(load->out, VIPS_META_PAGE_HEIGHT, pdf->pages[0].height); vips_foreign_load_pdf_set_image(pdf, load->out); /* Convert the background to the image format. */ if (!(pdf->ink = vips__vector_to_ink(class->nickname, load->out, VIPS_AREA(pdf->background)->data, NULL, VIPS_AREA(pdf->background)->n))) return -1; /* Swap to cairo-style premultiplied bgra. */ vips__rgba2bgra_premultiplied((guint32 *) pdf->ink, 1); vips_source_minimise(pdf->source); return 0; } static void vips_foreign_load_pdf_minimise(VipsImage *image, VipsForeignLoadPdf *pdf) { vips_source_minimise(pdf->source); } static int vips_foreign_load_pdf_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(a); VipsRect *r = &out_region->valid; int top; int i; int y; /* printf("vips_foreign_load_pdf_generate: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); */ /* Poppler won't always paint the background. */ vips_region_paint_pel(out_region, r, pdf->ink); /* Search through the pages we are drawing for the first containing * this rect. This could be quicker, perhaps a binary search, but who * cares. */ for (i = 0; i < pdf->n; i++) if (VIPS_RECT_BOTTOM(&pdf->pages[i]) > r->top) break; top = r->top; while (top < VIPS_RECT_BOTTOM(r)) { VipsRect rect; cairo_surface_t *surface; cairo_t *cr; vips_rect_intersectrect(r, &pdf->pages[i], &rect); surface = cairo_image_surface_create_for_data( VIPS_REGION_ADDR(out_region, rect.left, rect.top), CAIRO_FORMAT_ARGB32, rect.width, rect.height, VIPS_REGION_LSKIP(out_region)); cr = cairo_create(surface); cairo_surface_destroy(surface); cairo_scale(cr, pdf->total_scale, pdf->total_scale); cairo_translate(cr, (pdf->pages[i].left - rect.left) / pdf->total_scale, (pdf->pages[i].top - rect.top) / pdf->total_scale); /* poppler is single-threaded, but we don't need to lock since * we're running inside a non-threaded tilecache. */ if (vips_foreign_load_pdf_get_page(pdf, pdf->page_no + i)) return -1; poppler_page_render(pdf->page, cr); cairo_destroy(cr); top += rect.height; i += 1; } /* Cairo makes pre-multipled BRGA, we must byteswap and unpremultiply. */ for (y = 0; y < r->height; y++) { guint32 *scanline = (guint32 *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); vips__premultiplied_bgra2rgba(scanline, r->width); } return 0; } static int vips_foreign_load_pdf_load(VipsForeignLoad *load) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(load); VipsImage **t = (VipsImage **) vips_object_local_array((VipsObject *) load, 2); #ifdef DEBUG printf("vips_foreign_load_pdf_load: %p\n", pdf); #endif /*DEBUG*/ /* Read to this image, then cache to out, see below. */ t[0] = vips_image_new(); /* Close input immediately at end of read. */ g_signal_connect(t[0], "minimise", G_CALLBACK(vips_foreign_load_pdf_minimise), pdf); vips_foreign_load_pdf_set_image(pdf, t[0]); if (vips_image_generate(t[0], NULL, vips_foreign_load_pdf_generate, NULL, pdf, NULL) || vips_tilecache(t[0], &t[1], "tile_width", TILE_SIZE, "tile_height", TILE_SIZE, "max_tiles", 2 * (1 + t[0]->Xsize / TILE_SIZE), NULL) || vips_image_write(t[1], load->real)) return -1; return 0; } static void vips_foreign_load_pdf_class_init(VipsForeignLoadPdfClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_pdf_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload_base"; object_class->description = _("load PDF with libpoppler"); object_class->build = vips_foreign_load_pdf_build; /* libpoppler is fuzzed, but not by us. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; load_class->get_flags_filename = vips_foreign_load_pdf_get_flags_filename; load_class->get_flags = vips_foreign_load_pdf_get_flags; load_class->header = vips_foreign_load_pdf_header; load_class->load = vips_foreign_load_pdf_load; VIPS_ARG_INT(class, "page", 20, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, page_no), 0, 100000, 0); VIPS_ARG_INT(class, "n", 21, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, n), -1, 100000, 1); VIPS_ARG_DOUBLE(class, "dpi", 22, _("DPI"), _("DPI to render at"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, dpi), 0.001, 100000.0, 72.0); VIPS_ARG_DOUBLE(class, "scale", 23, _("Scale"), _("Factor to scale by"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, scale), 0.0, 100000.0, 1.0); VIPS_ARG_BOXED(class, "background", 24, _("Background"), _("Background colour"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_STRING(class, "password", 25, _("Password"), _("Password to decrypt with"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, password), NULL); VIPS_ARG_ENUM(class, "page_box", 26, _("Page box"), _("The region of the page to render"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdf, page_box), VIPS_TYPE_FOREIGN_PDF_PAGE_BOX, VIPS_FOREIGN_PDF_PAGE_BOX_CROP); } static void vips_foreign_load_pdf_init(VipsForeignLoadPdf *pdf) { pdf->dpi = 72.0; pdf->scale = 1.0; pdf->n = 1; pdf->current_page = -1; pdf->background = vips_array_double_newv(1, 255.0); pdf->page_box = VIPS_FOREIGN_PDF_PAGE_BOX_CROP; } typedef struct _VipsForeignLoadPdfFile { VipsForeignLoadPdf parent_object; /* Filename for load. */ char *filename; char *uri; } VipsForeignLoadPdfFile; typedef VipsForeignLoadPdfClass VipsForeignLoadPdfFileClass; G_DEFINE_TYPE(VipsForeignLoadPdfFile, vips_foreign_load_pdf_file, vips_foreign_load_pdf_get_type()); static void vips_foreign_load_pdf_file_dispose(GObject *gobject) { VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) gobject; VIPS_FREE(file->uri); G_OBJECT_CLASS(vips_foreign_load_pdf_file_parent_class)->dispose(gobject); } static int vips_foreign_load_pdf_file_header(VipsForeignLoad *load) { VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) load; VIPS_SETSTR(load->out->filename, file->filename); return VIPS_FOREIGN_LOAD_CLASS(vips_foreign_load_pdf_file_parent_class) ->header(load); } static int vips_foreign_load_pdf_file_build(VipsObject *object) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(object); VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) pdf; #ifdef DEBUG printf("vips_foreign_load_pdf_file_build: %s\n", file->filename); #endif /*DEBUG*/ if (file->filename) { char *path; GError *error = NULL; /* We need an absolute path for a URI. */ path = vips_realpath(file->filename); if (!(file->uri = g_filename_to_uri(path, NULL, &error))) { g_free(path); vips_g_error(&error); return -1; } g_free(path); if (!(pdf->source = vips_source_new_from_file(file->filename))) return -1; } return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_file_parent_class) ->build(object); } static void vips_foreign_load_pdf_file_class_init( VipsForeignLoadPdfFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_pdf_file_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload"; object_class->description = _("load PDF from file (poppler)"); object_class->build = vips_foreign_load_pdf_file_build; foreign_class->suffs = vips__pdf_suffs; load_class->is_a = vips__pdf_is_a_file; load_class->header = vips_foreign_load_pdf_file_header; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdfFile, filename), NULL); } static void vips_foreign_load_pdf_file_init(VipsForeignLoadPdfFile *file) { } typedef struct _VipsForeignLoadPdfBuffer { VipsForeignLoadPdf parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadPdfBuffer; typedef VipsForeignLoadPdfClass VipsForeignLoadPdfBufferClass; G_DEFINE_TYPE(VipsForeignLoadPdfBuffer, vips_foreign_load_pdf_buffer, vips_foreign_load_pdf_get_type()); static int vips_foreign_load_pdf_buffer_build(VipsObject *object) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(object); VipsForeignLoadPdfBuffer *buffer = (VipsForeignLoadPdfBuffer *) pdf; if (buffer->buf && !(pdf->source = vips_source_new_from_memory( VIPS_AREA(buffer->buf)->data, VIPS_AREA(buffer->buf)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_buffer_parent_class) ->build(object); } static void vips_foreign_load_pdf_buffer_class_init( VipsForeignLoadPdfBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload_buffer"; object_class->description = _("load PDF from buffer (poppler)"); object_class->build = vips_foreign_load_pdf_buffer_build; load_class->is_a_buffer = vips__pdf_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdfBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_pdf_buffer_init(VipsForeignLoadPdfBuffer *buffer) { } typedef struct _VipsForeignLoadPdfSource { VipsForeignLoadPdf parent_object; VipsSource *source; } VipsForeignLoadPdfSource; typedef VipsForeignLoadPdfClass VipsForeignLoadPdfSourceClass; G_DEFINE_TYPE(VipsForeignLoadPdfSource, vips_foreign_load_pdf_source, vips_foreign_load_pdf_get_type()); static int vips_foreign_load_pdf_source_build(VipsObject *object) { VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF(object); VipsForeignLoadPdfSource *source = (VipsForeignLoadPdfSource *) pdf; if (source->source) { pdf->source = source->source; g_object_ref(pdf->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_pdf_source_parent_class) ->build(object); } static void vips_foreign_load_pdf_source_class_init( VipsForeignLoadPdfSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pdfload_source"; object_class->description = _("load PDF from source (poppler)"); object_class->build = vips_foreign_load_pdf_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips__pdf_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPdfSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_pdf_source_init(VipsForeignLoadPdfSource *source) { } #endif /*defined(HAVE_POPPLER)*/ /* The C API wrappers are defined in foreign.c. */ libvips-8.18.2/libvips/foreign/ppmload.c000066400000000000000000000606741516303661500202060ustar00rootroot00000000000000/* load ppm from a file * * Stephen Chan ... original code * * 21/11/00 JC * - hacked for VIPS * - reads ppm/pgm/pbm * - mmaps binary pgm/ppm * - reads all ascii formats (slowly!) * 22/11/00 JC * - oops, ascii read was broken * - does 16/32 bit ascii now as well * 24/5/01 * - im_ppm2vips_header() added * 28/11/03 JC * - better no-overshoot on tile loop * 22/5/04 * - does 16/32 bit binary too * - tiny fix for missing file close on read error * 19/8/05 * - use im_raw2vips() for binary read * 9/9/05 * - tiny cleanups * 3/11/07 * - use im_wbuffer() for bg writes * 1/5/10 * - add PFM (portable float map) support * 19/12/11 * - rework as a set of fns ready to be called from a class * 8/11/14 * - add 1 bit write * 29/7/19 Kyle-Kyle * - fix a loop with malformed ppm * 13/11/19 * - redone with source/target * - sequential load, plus mmap for filename sources * - faster plus lower memory use * 02/02/20 * - ban max_vaue < 0 * 27/6/20 * - add ppmload_source * 22/11/20 * - fix msb_first default [ewelot] * 26/12/20 * - don't byteswap ascii formats * - set metadata for map loads * - byteswap binary loads * 9/3/23 * - pfm assumes linear 0-1 [NiHoel] * 2/6/25 * - add ppmload_buffer [kleisauke] */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_PPM typedef struct _VipsForeignLoadPpm { VipsForeignLoad parent_object; /* The source we load from, and the buffered wrapper for it. */ VipsSource *source; VipsSbuf *sbuf; /* Properties of this ppm, from the header. */ int width; int height; int bands; VipsBandFormat format; VipsInterpretation interpretation; float scale; int max_value; int index; /* ppm type .. index in magic_names[] */ int bits; /* 1, 8, 16 or 32 */ gboolean ascii; /* TRUE for ascii encoding */ gboolean msb_first; /* TRUE if most sig byte is first */ gboolean have_read_header; } VipsForeignLoadPpm; typedef VipsForeignLoadClass VipsForeignLoadPpmClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadPpm, vips_foreign_load_ppm, VIPS_TYPE_FOREIGN_LOAD); /* ppm types. */ static char *magic_names[] = { "P1", /* pbm ... 1 band 1 bit, ascii */ "P2", /* pgm ... 1 band many bit, ascii */ "P3", /* ppm ... 3 band many bit, ascii */ "P4", /* pbm ... 1 band 1 bit, binary */ "P5", /* pgm ... 1 band 8 bit, binary */ "P6", /* ppm ... 3 band 8 bit, binary */ "PF", /* pfm ... 3 band 32 bit, binary */ "Pf" /* pfm ... 1 band 32 bit, binary */ }; /* Shared with ppmsave. */ const char *vips__ppm_suffs[] = { ".pbm", ".pgm", ".ppm", ".pfm", ".pnm", NULL }; const char *vips__save_pbm_suffs[] = { ".pbm", NULL }; const char *vips__save_pgm_suffs[] = { ".pgm", NULL }; const char *vips__save_ppm_suffs[] = { ".ppm", NULL }; const char *vips__save_pfm_suffs[] = { ".pfm", NULL }; const char *vips__save_pnm_suffs[] = { ".pnm", NULL }; static gboolean vips_foreign_load_ppm_is_a_source(VipsSource *source) { const unsigned char *data; if ((data = vips_source_sniff(source, 2))) { int i; for (i = 0; i < VIPS_NUMBER(magic_names); i++) if (vips_isprefix(magic_names[i], (char *) data)) return TRUE; } return FALSE; } static int get_int(VipsSbuf *sbuf, int *i) { const char *txt; if (vips_sbuf_skip_whitespace(sbuf) || !(txt = vips_sbuf_get_non_whitespace(sbuf))) return -1; *i = atoi(txt); return 0; } static int get_float(VipsSbuf *sbuf, float *f) { const char *txt; if (vips_sbuf_skip_whitespace(sbuf) || !(txt = vips_sbuf_get_non_whitespace(sbuf))) return -1; /* We don't want the locale str -> float conversion. */ *f = g_ascii_strtod(txt, NULL); return 0; } static void vips_foreign_load_ppm_dispose(GObject *gobject) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) gobject; #ifdef DEBUG printf("vips_foreign_load_ppm_dispose: %p\n", ppm); #endif /*DEBUG*/ VIPS_UNREF(ppm->sbuf); VIPS_UNREF(ppm->source); G_OBJECT_CLASS(vips_foreign_load_ppm_parent_class)->dispose(gobject); } static int vips_foreign_load_ppm_build(VipsObject *object) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) object; if (ppm->source) ppm->sbuf = vips_sbuf_new_from_source(ppm->source); return VIPS_OBJECT_CLASS(vips_foreign_load_ppm_parent_class) ->build(object); } /* Scan the header into our class. */ static int vips_foreign_load_ppm_parse_header(VipsForeignLoadPpm *ppm) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(ppm); int i; char buf[2]; /* Characteristics, indexed by ppm type. */ static int lookup_bits[] = { 1, 8, 8, 1, 8, 8, 32, 32 }; static int lookup_bands[] = { 1, 1, 3, 1, 1, 3, 3, 1 }; static int lookup_ascii[] = { 1, 1, 1, 0, 0, 0, 0, 0 }; if (vips_source_rewind(ppm->source)) return -1; /* Read in the magic number. */ buf[0] = VIPS_SBUF_GETC(ppm->sbuf); buf[1] = VIPS_SBUF_GETC(ppm->sbuf); for (i = 0; i < VIPS_NUMBER(magic_names); i++) if (vips_isprefix(magic_names[i], buf)) break; if (i == VIPS_NUMBER(magic_names)) { vips_error(class->nickname, "%s", _("bad magic number")); return -1; } ppm->index = i; ppm->bits = lookup_bits[i]; ppm->bands = lookup_bands[i]; ppm->ascii = lookup_ascii[i]; /* Default ... can be changed below for PFM images. */ ppm->msb_first = 1; /* Read in size. */ if (get_int(ppm->sbuf, &ppm->width) || get_int(ppm->sbuf, &ppm->height)) return -1; /* Read in max value / scale for >1 bit images. */ if (ppm->bits > 1) { if (ppm->index == 6 || ppm->index == 7) { if (get_float(ppm->sbuf, &ppm->scale)) return -1; /* Scale > 0 means big-endian. */ ppm->msb_first = ppm->scale > 0; } else { if (get_int(ppm->sbuf, &ppm->max_value)) return -1; /* max_value must be > 0 and <= 65535, according to * the spec, but we allow up to 32 bits per pixel. */ if (ppm->max_value < 0) ppm->max_value = 0; if (ppm->max_value > 255) ppm->bits = 16; if (ppm->max_value > 65535) ppm->bits = 32; } } /* Read the end of line character after the scale so we are positioned * exactly at the start of the data. This matters for binary formats. */ (void) vips_sbuf_get_line(ppm->sbuf); /* Choose a VIPS bandfmt. */ switch (ppm->bits) { case 1: case 8: ppm->format = VIPS_FORMAT_UCHAR; break; case 16: ppm->format = VIPS_FORMAT_USHORT; break; case 32: if (ppm->index == 6 || ppm->index == 7) ppm->format = VIPS_FORMAT_FLOAT; else ppm->format = VIPS_FORMAT_UINT; break; default: g_assert_not_reached(); /* Stop compiler warnings. */ ppm->format = VIPS_FORMAT_UCHAR; } if (ppm->bands == 1) { if (ppm->format == VIPS_FORMAT_USHORT) ppm->interpretation = VIPS_INTERPRETATION_GREY16; else ppm->interpretation = VIPS_INTERPRETATION_B_W; } else { if (ppm->format == VIPS_FORMAT_USHORT) ppm->interpretation = VIPS_INTERPRETATION_RGB16; else if (ppm->format == VIPS_FORMAT_FLOAT) ppm->interpretation = VIPS_INTERPRETATION_scRGB; else ppm->interpretation = VIPS_INTERPRETATION_sRGB; } ppm->have_read_header = TRUE; #ifdef DEBUG printf("vips_foreign_load_ppm_parse_header:\n"); printf("\twidth = %d\n", ppm->width); printf("\theight = %d\n", ppm->height); printf("\tbands = %d\n", ppm->bands); printf("\tformat = %s\n", vips_enum_nick(VIPS_TYPE_BAND_FORMAT, ppm->format)); printf("\tinterpretation = %s\n", vips_enum_nick(VIPS_TYPE_INTERPRETATION, ppm->interpretation)); printf("\tscale = %g\n", ppm->scale); printf("\tmax_value = %d\n", ppm->max_value); printf("\tbits = %d\n", ppm->bits); printf("\tacsii = %d\n", ppm->ascii); printf("\tmsb_first = %d\n", ppm->msb_first); #endif /*DEBUG*/ return 0; } static VipsForeignFlags vips_foreign_load_ppm_get_flags(VipsForeignLoad *load) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; VipsForeignFlags flags; flags = 0; /* If this source supports fast mmap and this PPM is >=8 bit binary, * then we can mmap the file and support partial load. Otherwise, * it's sequential. */ if (!ppm->have_read_header && vips_foreign_load_ppm_parse_header(ppm)) return 0; if (vips_source_is_mappable(ppm->source) && !ppm->ascii && ppm->bits >= 8) flags |= VIPS_FOREIGN_PARTIAL; else flags |= VIPS_FOREIGN_SEQUENTIAL; return flags; } static void vips_foreign_load_ppm_set_image_metadata(VipsForeignLoadPpm *ppm, VipsImage *image) { image->Type = ppm->interpretation; if (ppm->index == 6 || ppm->index == 7) vips_image_set_double(image, "pfm-scale", fabs(ppm->scale)); else vips_image_set_double(image, "ppm-max-value", abs(ppm->max_value)); VIPS_SETSTR(image->filename, vips_connection_filename(VIPS_CONNECTION(ppm->sbuf->source))); #ifdef DEBUG printf("vips_foreign_load_ppm_set_image: "); vips_object_print_summary(VIPS_OBJECT(image)); #endif /*DEBUG*/ } static void vips_foreign_load_ppm_set_image(VipsForeignLoadPpm *ppm, VipsImage *image) { vips_image_init_fields(image, ppm->width, ppm->height, ppm->bands, ppm->format, VIPS_CODING_NONE, ppm->interpretation, 1.0, 1.0); (void) vips_image_pipelinev(image, VIPS_DEMAND_STYLE_THINSTRIP, NULL); vips_foreign_load_ppm_set_image_metadata(ppm, image); #ifdef DEBUG printf("vips_foreign_load_ppm_set_image: "); vips_object_print_summary(VIPS_OBJECT(image)); #endif /*DEBUG*/ } static int vips_foreign_load_ppm_header(VipsForeignLoad *load) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; if (!ppm->have_read_header && vips_foreign_load_ppm_parse_header(ppm)) return 0; vips_foreign_load_ppm_set_image(ppm, load->out); vips_source_minimise(ppm->source); return 0; } /* Read a ppm/pgm file using mmap(). */ static VipsImage * vips_foreign_load_ppm_map(VipsForeignLoadPpm *ppm) { gint64 header_offset; size_t length; const void *data; VipsImage *out; #ifdef DEBUG printf("vips_foreign_load_ppm_map:\n"); #endif /*DEBUG*/ vips_sbuf_unbuffer(ppm->sbuf); header_offset = vips_source_seek(ppm->source, 0, SEEK_CUR); data = vips_source_map(ppm->source, &length); if (header_offset < 0 || !data) return NULL; data = (char *) data + header_offset; length -= header_offset; if (!(out = vips_image_new_from_memory(data, length, ppm->width, ppm->height, ppm->bands, ppm->format))) return NULL; vips_foreign_load_ppm_set_image_metadata(ppm, out); return out; } static int vips_foreign_load_ppm_generate_binary(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(ppm); VipsImage *image = out_region->im; size_t sizeof_line = VIPS_IMAGE_SIZEOF_LINE(image); int y; for (y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, 0, r->top + y); size_t n_bytes; n_bytes = sizeof_line; while (n_bytes > 0) { gint64 bytes_read; bytes_read = vips_source_read(ppm->source, q, n_bytes); if (bytes_read < 0) return -1; if (bytes_read == 0) { vips_error(class->nickname, "%s", _("file truncated")); return -1; } q += bytes_read; n_bytes -= bytes_read; } } return 0; } static int vips_foreign_load_ppm_generate_1bit_ascii(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; VipsImage *image = out_region->im; int x, y; for (y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, 0, r->top + y); for (x = 0; x < image->Xsize; x++) { int val; if (get_int(ppm->sbuf, &val)) return -1; if (val) q[x] = 0; else q[x] = 255; } } return 0; } static int vips_foreign_load_ppm_generate_1bit_binary(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; VipsImage *image = out_region->im; int x, y; for (y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, 0, r->top + y); int bits; /* Not needed, but stop a compiler warning. */ bits = 0; for (x = 0; x < image->Xsize; x++) { if ((x & 7) == 0) bits = VIPS_SBUF_GETC(ppm->sbuf); q[x] = (bits & 128) ? 0 : 255; bits = VIPS_LSHIFT_INT(bits, 1); } } return 0; } static int vips_foreign_load_ppm_generate_ascii_int(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) a; VipsImage *image = out_region->im; int n_elements = image->Xsize * image->Bands; int i, y; for (y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); for (i = 0; i < n_elements; i++) { int val; if (get_int(ppm->sbuf, &val)) return -1; switch (image->BandFmt) { case VIPS_FORMAT_UCHAR: q[i] = VIPS_CLIP(0, val, 255); break; case VIPS_FORMAT_USHORT: ((unsigned short *) q)[i] = VIPS_CLIP(0, val, 65535); break; case VIPS_FORMAT_UINT: ((unsigned int *) q)[i] = val; break; default: g_assert_not_reached(); } } } return 0; } static VipsImage * vips_foreign_load_ppm_scan(VipsForeignLoadPpm *ppm) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(ppm), 2); VipsImage *out; VipsGenerateFn generate; /* What sort of read are we doing? */ if (!ppm->ascii && ppm->bits >= 8) { #ifdef DEBUG printf("vips_foreign_load_ppm_source: >1 bit binary load\n"); #endif /*DEBUG*/ generate = vips_foreign_load_ppm_generate_binary; /* The binary loader does not use the buffered IO * object. */ vips_sbuf_unbuffer(ppm->sbuf); } else if (!ppm->ascii && ppm->bits == 1) { #ifdef DEBUG printf("vips_foreign_load_ppm_source: 1-bit binary load\n"); #endif /*DEBUG*/ generate = vips_foreign_load_ppm_generate_1bit_binary; } else if (ppm->ascii && ppm->bits == 1) { #ifdef DEBUG printf("vips_foreign_load_ppm_source: 1-bit ascii load\n"); #endif /*DEBUG*/ generate = vips_foreign_load_ppm_generate_1bit_ascii; } else { #ifdef DEBUG printf("vips_foreign_load_ppm_source: >1-bit ascii load\n"); #endif /*DEBUG*/ generate = vips_foreign_load_ppm_generate_ascii_int; } t[0] = vips_image_new(); vips_foreign_load_ppm_set_image(ppm, t[0]); if (vips_image_generate(t[0], NULL, generate, NULL, ppm, NULL) || vips_sequential(t[0], &out, NULL)) return NULL; return out; } static int vips_foreign_load_ppm_load(VipsForeignLoad *load) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) load; VipsImage **t = (VipsImage **) vips_object_local_array((VipsObject *) load, 2); if (!ppm->have_read_header && vips_foreign_load_ppm_parse_header(ppm)) return 0; /* If the source is mappable and this is a binary file, we can map it. */ if (vips_source_is_mappable(ppm->source) && !ppm->ascii && ppm->bits >= 8) { if (!(t[0] = vips_foreign_load_ppm_map(ppm))) return -1; } else { if (!(t[0] = vips_foreign_load_ppm_scan(ppm))) return -1; } #ifdef DEBUG printf("vips_foreign_load_ppm: byteswap = %d\n", vips_amiMSBfirst() != ppm->msb_first); #endif /*DEBUG*/ /* Don't byteswap the ascii formats. */ if (vips__byteswap_bool(t[0], &t[1], !ppm->ascii && vips_amiMSBfirst() != ppm->msb_first) || vips_image_write(t[1], load->real)) return -1; if (vips_source_decode(ppm->source)) return -1; return 0; } static void vips_foreign_load_ppm_class_init(VipsForeignLoadPpmClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_ppm_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmload_base"; object_class->description = _("load ppm base class"); object_class->build = vips_foreign_load_ppm_build; /* You're unlikely to want to use this on untrusted files. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; foreign_class->suffs = vips__ppm_suffs; /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; load_class->get_flags = vips_foreign_load_ppm_get_flags; load_class->header = vips_foreign_load_ppm_header; load_class->load = vips_foreign_load_ppm_load; } static void vips_foreign_load_ppm_init(VipsForeignLoadPpm *ppm) { ppm->scale = 1.0F; } typedef struct _VipsForeignLoadPpmFile { VipsForeignLoadPpm parent_object; char *filename; } VipsForeignLoadPpmFile; typedef VipsForeignLoadPpmClass VipsForeignLoadPpmFileClass; G_DEFINE_TYPE(VipsForeignLoadPpmFile, vips_foreign_load_ppm_file, vips_foreign_load_ppm_get_type()); static gboolean vips_foreign_load_ppm_file_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_ppm_is_a_source(source); VIPS_UNREF(source); return result; } static int vips_foreign_load_ppm_file_build(VipsObject *object) { VipsForeignLoadPpmFile *file = (VipsForeignLoadPpmFile *) object; VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) object; if (file->filename && !(ppm->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_ppm_file_parent_class) ->build(object); } static void vips_foreign_load_ppm_file_class_init(VipsForeignLoadPpmClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmload"; object_class->description = _("load ppm from file"); object_class->build = vips_foreign_load_ppm_file_build; load_class->is_a = vips_foreign_load_ppm_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPpmFile, filename), NULL); } static void vips_foreign_load_ppm_file_init(VipsForeignLoadPpmFile *file) { } typedef struct _VipsForeignLoadPpmBuffer { VipsForeignLoadPpm parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadPpmBuffer; typedef VipsForeignLoadPpmClass VipsForeignLoadPpmBufferClass; G_DEFINE_TYPE(VipsForeignLoadPpmBuffer, vips_foreign_load_ppm_buffer, vips_foreign_load_ppm_get_type()); static int vips_foreign_load_ppm_buffer_build(VipsObject *object) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) object; VipsForeignLoadPpmBuffer *buffer = (VipsForeignLoadPpmBuffer *) object; if (buffer->blob && !(ppm->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_ppm_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_ppm_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_ppm_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_ppm_buffer_class_init(VipsForeignLoadPpmBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmload_buffer"; object_class->description = _("load ppm from buffer"); object_class->build = vips_foreign_load_ppm_buffer_build; load_class->is_a_buffer = vips_foreign_load_ppm_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPpmBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_ppm_buffer_init(VipsForeignLoadPpmBuffer *buffer) { } typedef struct _VipsForeignLoadPpmSource { VipsForeignLoadPpm parent_object; VipsSource *source; } VipsForeignLoadPpmSource; typedef VipsForeignLoadPpmClass VipsForeignLoadPpmSourceClass; G_DEFINE_TYPE(VipsForeignLoadPpmSource, vips_foreign_load_ppm_source, vips_foreign_load_ppm_get_type()); static int vips_foreign_load_ppm_source_build(VipsObject *object) { VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) object; VipsForeignLoadPpmSource *source = (VipsForeignLoadPpmSource *) object; if (source->source) { ppm->source = source->source; g_object_ref(ppm->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_ppm_source_parent_class) ->build(object); } static void vips_foreign_load_ppm_source_class_init(VipsForeignLoadPpmFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmload_source"; object_class->description = _("load ppm from source"); object_class->build = vips_foreign_load_ppm_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_ppm_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPpmSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_ppm_source_init(VipsForeignLoadPpmSource *source) { } #endif /*HAVE_PPM*/ /** * vips_ppmload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Read a PPM/PBM/PGM/PFM file into a VIPS image. * * It can read 1, 8, 16 and 32 bit images, colour or monochrome, * stored in binary or in ASCII. One bit images become 8 bit VIPS images, * with 0 and 255 for 0 and 1. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_ppmload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("ppmload", ap, filename, out); va_end(ap); return result; } /** * vips_ppmload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.ppmload], but read from a memory source. * * ::: seealso * [ctor@Image.ppmload]. * * Returns: 0 on success, -1 on error. */ int vips_ppmload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("ppmload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_ppmload_source: * @source: source to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.ppmload], but read from a source. * * ::: seealso * [ctor@Image.ppmload]. * * Returns: 0 on success, -1 on error. */ int vips_ppmload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("ppmload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/ppmsave.c000066400000000000000000000517611516303661500202220ustar00rootroot00000000000000/* save to ppm * * 2/12/11 * - wrap a class around the ppm writer * 13/11/19 * - redone with targets * 18/6/20 * - add "bitdepth" param, cf. tiffsave * 27/6/20 * - add ppmsave_target * 20/11/20 * - byteswap on save, if necessary [ewelot] * 2/12/20 * - don't add date with @strip [ewelot] * 28/10/21 * - add @format, default type by filename * 30/8/22 * - add ".pnm", save as image format [ewelot] * 9/3/23 * - pfm saves as linear 0-1 [NiHoel] * - append spaces to the scale field to hit a 4 byte boundary for data */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_PPM typedef struct _VipsForeignSavePpm VipsForeignSavePpm; typedef int (*VipsSavePpmFn)(VipsForeignSavePpm *, VipsImage *, VipsPel *); struct _VipsForeignSavePpm { VipsForeignSave parent_object; VipsTarget *target; VipsForeignPpmFormat format; gboolean ascii; int bitdepth; VipsSavePpmFn fn; /* Deprecated. */ gboolean squash; }; typedef VipsForeignSaveClass VipsForeignSavePpmClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSavePpm, vips_foreign_save_ppm, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_ppm_dispose(GObject *gobject) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) gobject; VIPS_UNREF(ppm->target); G_OBJECT_CLASS(vips_foreign_save_ppm_parent_class)->dispose(gobject); } static int vips_foreign_save_ppm_line_ascii(VipsForeignSavePpm *ppm, VipsImage *image, VipsPel *p) { const int n_elements = image->Xsize * image->Bands; int i; for (i = 0; i < n_elements; i++) { switch (image->BandFmt) { case VIPS_FORMAT_UCHAR: vips_target_writef(ppm->target, "%d ", p[i]); break; case VIPS_FORMAT_USHORT: vips_target_writef(ppm->target, "%d ", ((unsigned short *) p)[i]); break; case VIPS_FORMAT_UINT: vips_target_writef(ppm->target, "%d ", ((unsigned int *) p)[i]); break; default: g_assert_not_reached(); } } if (vips_target_writes(ppm->target, "\n")) return -1; return 0; } static int vips_foreign_save_ppm_line_ascii_1bit(VipsForeignSavePpm *ppm, VipsImage *image, VipsPel *p) { int x; for (x = 0; x < image->Xsize; x++) vips_target_writef(ppm->target, "%d ", p[x] > 127 ? 0 : 1); if (vips_target_writes(ppm->target, "\n")) return -1; return 0; } static int vips_foreign_save_ppm_line_binary(VipsForeignSavePpm *ppm, VipsImage *image, VipsPel *p) { if (vips_target_write(ppm->target, p, VIPS_IMAGE_SIZEOF_LINE(image))) return -1; return 0; } static int vips_foreign_save_ppm_line_binary_1bit(VipsForeignSavePpm *ppm, VipsImage *image, VipsPel *p) { int x; int bits; int n_bits; bits = 0; n_bits = 0; for (x = 0; x < image->Xsize; x++) { bits = VIPS_LSHIFT_INT(bits, 1); n_bits += 1; bits |= p[x] > 127 ? 0 : 1; if (n_bits == 8) { if (VIPS_TARGET_PUTC(ppm->target, bits)) return -1; bits = 0; n_bits = 0; } } /* Flush any remaining bits in this line. */ if (n_bits && VIPS_TARGET_PUTC(ppm->target, bits)) return -1; return 0; } static int vips_foreign_save_ppm_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) a; VipsImage *image = region->im; int y; for (y = 0; y < area->height; y++) { VipsPel *p = VIPS_REGION_ADDR(region, 0, area->top + y); if (ppm->fn(ppm, image, p)) return -1; } return 0; } static int vips_foreign_save_ppm_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *image; char *magic; char *date; VipsInterpretation target_interpretation; int target_bands; if (VIPS_OBJECT_CLASS(vips_foreign_save_ppm_parent_class)->build(object)) return -1; image = save->ready; /* We don't allow alpha. Just flatten it out. */ if (vips_image_hasalpha(image)) { if (vips_flatten(image, &t[0], "background", save->background, NULL)) return -1; image = t[0]; } /* ppm types to set the defaults for bitdepth etc. * * pbm ... 1 band 1 bit * pgm ... 1 band many bit * ppm ... 3 band many bit * pfm ... 1 or 3 bands, 32 bit * pnm ... pick from input */ switch (ppm->format) { case VIPS_FOREIGN_PPM_FORMAT_PBM: if (!vips_object_argument_isset(object, "bitdepth")) ppm->bitdepth = 1; target_interpretation = VIPS_INTERPRETATION_B_W; target_bands = 1; break; case VIPS_FOREIGN_PPM_FORMAT_PGM: if (image->BandFmt == VIPS_FORMAT_USHORT) target_interpretation = VIPS_INTERPRETATION_GREY16; else target_interpretation = VIPS_INTERPRETATION_B_W; target_bands = 1; break; case VIPS_FOREIGN_PPM_FORMAT_PPM: if (image->BandFmt == VIPS_FORMAT_USHORT) target_interpretation = VIPS_INTERPRETATION_RGB16; else target_interpretation = VIPS_INTERPRETATION_sRGB; target_bands = 3; break; case VIPS_FOREIGN_PPM_FORMAT_PFM: target_interpretation = VIPS_INTERPRETATION_scRGB; if (image->Bands > 1) target_bands = 3; else // can have mono pfm, curiously target_bands = 1; break; case VIPS_FOREIGN_PPM_FORMAT_PNM: default: /* Just use the input interpretation and bands. */ target_interpretation = image->Type; target_bands = image->Bands; break; } if (vips_colourspace(image, &t[1], target_interpretation, NULL)) return -1; image = t[1]; /* Get bands right. */ if (image->Bands > target_bands) { if (vips_extract_band(image, &t[2], 0, "n", target_bands, NULL)) return -1; image = t[2]; } if (image->Bands < target_bands) { vips_error(class->nickname, "%s", _("too few bands for format")); return -1; } /* Handle the deprecated squash parameter. */ if (ppm->squash) ppm->bitdepth = 1; if (vips_check_uintorf("vips2ppm", image) || vips_check_bands_1or3("vips2ppm", image) || vips_check_uncoded("vips2ppm", image) || vips_image_pio_input(image)) return -1; if (ppm->ascii && image->BandFmt == VIPS_FORMAT_FLOAT) { g_warning("float images must be binary -- disabling ascii"); ppm->ascii = FALSE; } /* One bit images must come from a 8 bit, one band source. */ if (ppm->bitdepth && (image->Bands != 1 || image->BandFmt != VIPS_FORMAT_UCHAR)) { g_warning("can only save 1 band uchar images as 1 bit -- " "disabling 1 bit save"); ppm->bitdepth = 0; } magic = "unset"; if (image->BandFmt == VIPS_FORMAT_FLOAT && image->Bands == 3) magic = "PF"; else if (image->BandFmt == VIPS_FORMAT_FLOAT && image->Bands == 1) magic = "Pf"; else if (image->Bands == 1 && ppm->ascii && ppm->bitdepth) magic = "P1"; else if (image->Bands == 1 && ppm->ascii) magic = "P2"; else if (image->Bands == 1 && !ppm->ascii && ppm->bitdepth) magic = "P4"; else if (image->Bands == 1 && !ppm->ascii) magic = "P5"; else if (image->Bands == 3 && ppm->ascii) magic = "P3"; else if (image->Bands == 3 && !ppm->ascii) magic = "P6"; else g_assert_not_reached(); vips_target_writef(ppm->target, "%s\n", magic); if (save->keep & VIPS_FOREIGN_KEEP_OTHER) { date = vips__get_iso8601(); vips_target_writef(ppm->target, "#vips2ppm - %s\n", date); g_free(date); } vips_target_writef(ppm->target, "%d %d\n", image->Xsize, image->Ysize); if (!ppm->bitdepth) switch (image->BandFmt) { case VIPS_FORMAT_UCHAR: vips_target_writef(ppm->target, "%d\n", UCHAR_MAX); break; case VIPS_FORMAT_USHORT: vips_target_writef(ppm->target, "%d\n", USHRT_MAX); break; case VIPS_FORMAT_UINT: vips_target_writef(ppm->target, "%d\n", UINT_MAX); break; case VIPS_FORMAT_FLOAT: { double scale; char buf[G_ASCII_DTOSTR_BUF_SIZE]; scale = 1.0; if (vips_image_get_typeof(image, "pfm-scale")) vips_image_get_double(image, "pfm-scale", &scale); /* Need to be locale independent. */ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, scale); vips_target_writes(ppm->target, buf); /* Add some secret trailing spaces to the scale field to try to * get the data to land on a 4 byte (the largest pixel ppm can * handle) boundary. * * This means values in the file will be aligned when it's read * back, making vector operations like byteswap a lot quicker. */ if (!ppm->ascii) { gint64 position = vips_target_seek(ppm->target, 0, SEEK_CUR); // +1 for the \n after the padding int padding = 4 - (position + 1) % 4; vips_target_writef(ppm->target, "%*c", padding, ' '); } vips_target_writes(ppm->target, "\n"); } break; default: g_assert_not_reached(); } if (ppm->bitdepth) ppm->fn = ppm->ascii ? vips_foreign_save_ppm_line_ascii_1bit : vips_foreign_save_ppm_line_binary_1bit; else ppm->fn = ppm->ascii ? vips_foreign_save_ppm_line_ascii : vips_foreign_save_ppm_line_binary; /* 16 and 32-bit binary write might need byteswapping. */ if (!ppm->ascii && (image->BandFmt == VIPS_FORMAT_USHORT || image->BandFmt == VIPS_FORMAT_UINT || image->BandFmt == VIPS_FORMAT_FLOAT)) { if (vips__byteswap_bool(image, &t[3], !vips_amiMSBfirst())) return -1; image = t[3]; } if (vips_sink_disc(image, vips_foreign_save_ppm_block, ppm)) return -1; if (vips_target_end(ppm->target)) return -1; return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat bandfmt_ppm[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, UI, UI, F, F, F, F }; static void vips_foreign_save_ppm_class_init(VipsForeignSavePpmClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_ppm_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmsave_base"; object_class->description = _("save to ppm"); object_class->build = vips_foreign_save_ppm_build; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->format_table = bandfmt_ppm; VIPS_ARG_ENUM(class, "format", 2, _("Format"), _("Format to save in"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePpm, format), VIPS_TYPE_FOREIGN_PPM_FORMAT, VIPS_FOREIGN_PPM_FORMAT_PPM); VIPS_ARG_BOOL(class, "ascii", 10, _("ASCII"), _("Save as ascii"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePpm, ascii), FALSE); VIPS_ARG_INT(class, "bitdepth", 15, _("Bit depth"), _("Set to 1 to write as a 1 bit image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSavePpm, bitdepth), 0, 1, 0); VIPS_ARG_BOOL(class, "squash", 11, _("Squash"), _("Save as one bit"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSavePpm, squash), FALSE); } static void vips_foreign_save_ppm_init(VipsForeignSavePpm *ppm) { ppm->format = VIPS_FOREIGN_PPM_FORMAT_PPM; } typedef struct _VipsForeignSavePpmFile { VipsForeignSavePpm parent_object; char *filename; } VipsForeignSavePpmFile; typedef VipsForeignSavePpmClass VipsForeignSavePpmFileClass; G_DEFINE_TYPE(VipsForeignSavePpmFile, vips_foreign_save_ppm_file, vips_foreign_save_ppm_get_type()); static int vips_foreign_save_ppm_file_build(VipsObject *object) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object; VipsForeignSavePpmFile *file = (VipsForeignSavePpmFile *) object; if (file->filename && !(ppm->target = vips_target_new_to_file(file->filename))) return -1; if (vips_iscasepostfix(file->filename, ".pbm")) ppm->format = VIPS_FOREIGN_PPM_FORMAT_PBM; else if (vips_iscasepostfix(file->filename, ".pgm")) ppm->format = VIPS_FOREIGN_PPM_FORMAT_PGM; else if (vips_iscasepostfix(file->filename, ".pfm")) ppm->format = VIPS_FOREIGN_PPM_FORMAT_PFM; else if (vips_iscasepostfix(file->filename, ".pnm")) ppm->format = VIPS_FOREIGN_PPM_FORMAT_PNM; return VIPS_OBJECT_CLASS(vips_foreign_save_ppm_file_parent_class) ->build(object); } static void vips_foreign_save_ppm_file_class_init(VipsForeignSavePpmFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmsave"; object_class->description = _("save image to ppm file"); object_class->build = vips_foreign_save_ppm_file_build; foreign_class->suffs = vips__ppm_suffs; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSavePpmFile, filename), NULL); } static void vips_foreign_save_ppm_file_init(VipsForeignSavePpmFile *file) { } typedef struct _VipsForeignSavePpmTarget { VipsForeignSavePpm parent_object; VipsTarget *target; } VipsForeignSavePpmTarget; typedef VipsForeignSavePpmClass VipsForeignSavePpmTargetClass; G_DEFINE_TYPE(VipsForeignSavePpmTarget, vips_foreign_save_ppm_target, vips_foreign_save_ppm_get_type()); static int vips_foreign_save_ppm_target_build(VipsObject *object) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) object; VipsForeignSavePpmTarget *target = (VipsForeignSavePpmTarget *) object; if (target->target) { ppm->target = target->target; g_object_ref(ppm->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_ppm_target_parent_class) ->build(object); } static void vips_foreign_save_ppm_target_class_init( VipsForeignSavePpmTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "ppmsave_target"; object_class->build = vips_foreign_save_ppm_target_build; foreign_class->suffs = vips__save_ppm_suffs; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSavePpmTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_ppm_target_init(VipsForeignSavePpmTarget *target) { } typedef VipsForeignSavePpmTarget VipsForeignSavePbmTarget; typedef VipsForeignSavePpmTargetClass VipsForeignSavePbmTargetClass; G_DEFINE_TYPE(VipsForeignSavePbmTarget, vips_foreign_save_pbm_target, vips_foreign_save_ppm_target_get_type()); static void vips_foreign_save_pbm_target_class_init( VipsForeignSavePbmTargetClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "pbmsave_target"; object_class->description = _("save image in pbm format"); foreign_class->suffs = vips__save_pbm_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_pbm_target_init(VipsForeignSavePbmTarget *target) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; ppm->format = VIPS_FOREIGN_PPM_FORMAT_PBM; } typedef VipsForeignSavePpmTarget VipsForeignSavePgmTarget; typedef VipsForeignSavePpmTargetClass VipsForeignSavePgmTargetClass; G_DEFINE_TYPE(VipsForeignSavePgmTarget, vips_foreign_save_pgm_target, vips_foreign_save_ppm_target_get_type()); static void vips_foreign_save_pgm_target_class_init( VipsForeignSavePgmTargetClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "pgmsave_target"; object_class->description = _("save image in pgm format"); foreign_class->suffs = vips__save_pgm_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_pgm_target_init(VipsForeignSavePgmTarget *target) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; ppm->format = VIPS_FOREIGN_PPM_FORMAT_PGM; } typedef VipsForeignSavePpmTarget VipsForeignSavePfmTarget; typedef VipsForeignSavePpmTargetClass VipsForeignSavePfmTargetClass; G_DEFINE_TYPE(VipsForeignSavePfmTarget, vips_foreign_save_pfm_target, vips_foreign_save_ppm_target_get_type()); static void vips_foreign_save_pfm_target_class_init( VipsForeignSavePfmTargetClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "pfmsave_target"; object_class->description = _("save image in pfm format"); foreign_class->suffs = vips__save_pfm_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_pfm_target_init(VipsForeignSavePfmTarget *target) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; ppm->format = VIPS_FOREIGN_PPM_FORMAT_PFM; } typedef VipsForeignSavePpmTarget VipsForeignSavePnmTarget; typedef VipsForeignSavePpmTargetClass VipsForeignSavePnmTargetClass; G_DEFINE_TYPE(VipsForeignSavePnmTarget, vips_foreign_save_pnm_target, vips_foreign_save_ppm_target_get_type()); static void vips_foreign_save_pnm_target_class_init( VipsForeignSavePfmTargetClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "pnmsave_target"; object_class->description = _("save image in pnm format"); foreign_class->suffs = vips__save_pnm_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_pnm_target_init(VipsForeignSavePfmTarget *target) { VipsForeignSavePpm *ppm = (VipsForeignSavePpm *) target; ppm->format = VIPS_FOREIGN_PPM_FORMAT_PNM; } #endif /*HAVE_PPM*/ /** * vips_ppmsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file as PPM. * * It can write 1, 8, 16 or * 32 bit unsigned integer images, float images, colour or monochrome, * stored as binary or ASCII. * Integer images of more than 8 bits can only be stored in ASCII. * * When writing float (PFM) images the scale factor is set from the * "pfm-scale" metadata. * * Set @ascii to `TRUE` to write as human-readable ASCII. Normally data is * written in binary. * * Set @bitdepth to 1 to write a one-bit image. * * @format defaults to the sub-type for this filename suffix. * * ::: tip "Optional arguments" * * @format: [enum@ForeignPpmFormat], format to save in * * @ascii: `gboolean`, save as ASCII rather than binary * * @bitdepth: `gint`, bitdepth to save at * * ::: seealso * [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_ppmsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("ppmsave", ap, in, filename); va_end(ap); return result; } /** * vips_ppmsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.ppmsave], but save to a target. * * ::: tip "Optional arguments" * * @format: [enum@ForeignPpmFormat], format to save in * * @ascii: `gboolean`, save as ASCII rather than binary * * @bitdepth: `gint`, bitdepth to save at * * ::: seealso * [method@Image.ppmsave]. * * Returns: 0 on success, -1 on error. */ int vips_ppmsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("ppmsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/quantise.c000066400000000000000000000256741516303661500204040ustar00rootroot00000000000000/* quantise an image * * 20/6/18 * - from vipspng.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include "quantise.h" #ifdef HAVE_QUANTIZATION #ifdef HAVE_IMAGEQUANT VipsQuantiseAttr * vips__quantise_attr_create(void) { return liq_attr_create(); } VipsQuantiseError vips__quantise_set_max_colors(VipsQuantiseAttr *attr, int colors) { return liq_set_max_colors(attr, colors); } VipsQuantiseError vips__quantise_set_quality(VipsQuantiseAttr *attr, int minimum, int maximum) { return liq_set_quality(attr, minimum, maximum); } VipsQuantiseError vips__quantise_set_speed(VipsQuantiseAttr *attr, int speed) { return liq_set_speed(attr, speed); } VipsQuantiseImage * vips__quantise_image_create_rgba(const VipsQuantiseAttr *attr, const void *bitmap, int width, int height, double gamma) { return liq_image_create_rgba(attr, bitmap, width, height, gamma); } VipsQuantiseError vips__quantise_image_quantize(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output) { return liq_image_quantize(input_image, options, result_output); } /* Like vips__quantise_image_quantize(), but make a fixed palette that won't * get remapped during dithering. */ VipsQuantiseError vips__quantise_image_quantize_fixed(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output) { int i; liq_result *result; const liq_palette *palette; liq_error err; liq_image *fake_image; char fake_image_pixels[4] = { 0 }; /* First, quantize the image and get its palette. */ err = liq_image_quantize(input_image, options, &result); if (err != LIQ_OK) return err; palette = liq_get_palette(result); /* Now, we need a fake 1 pixel image that will be quantized on the * next step. Its pixel color doesn't matter since we'll add all the * colors from the palette further. */ fake_image = liq_image_create_rgba(options, fake_image_pixels, 1, 1, 0); if (!fake_image) { liq_result_destroy(result); return LIQ_OUT_OF_MEMORY; } /* Add all the colors from the palette as fixed colors to the fake * image. Since the fixed colors number is the same as required colors * number, no new colors will be added. */ for (i = 0; i < palette->count; i++) liq_image_add_fixed_color(fake_image, palette->entries[i]); liq_result_destroy(result); /* Finally, quantize the fake image with fixed colors to make a * VipsQuantiseResult with a fixed palette. */ err = liq_image_quantize(fake_image, options, result_output); liq_image_destroy(fake_image); return err; } VipsQuantiseError vips__quantise_set_dithering_level(VipsQuantiseResult *res, float dither_level) { return liq_set_dithering_level(res, dither_level); } const VipsQuantisePalette * vips__quantise_get_palette(VipsQuantiseResult *result) { return liq_get_palette(result); } VipsQuantiseError vips__quantise_write_remapped_image(VipsQuantiseResult *result, VipsQuantiseImage *input_image, void *buffer, size_t buffer_size) { return liq_write_remapped_image( result, input_image, buffer, buffer_size); } void vips__quantise_result_destroy(VipsQuantiseResult *result) { liq_result_destroy(result); } void vips__quantise_image_destroy(VipsQuantiseImage *img) { liq_image_destroy(img); } void vips__quantise_attr_destroy(VipsQuantiseAttr *attr) { liq_attr_destroy(attr); } #elif defined(HAVE_QUANTIZR) /*!HAVE_IMAGEQUANT*/ VipsQuantiseAttr * vips__quantise_attr_create(void) { return quantizr_new_options(); } VipsQuantiseError vips__quantise_set_max_colors(VipsQuantiseAttr *attr, int colors) { return quantizr_set_max_colors(attr, colors); } VipsQuantiseError vips__quantise_set_quality(VipsQuantiseAttr *attr, int minimum, int maximum) { /* Not supported by quantizr */ return 0; } VipsQuantiseError vips__quantise_set_speed(VipsQuantiseAttr *attr, int speed) { /* Not supported by quantizr */ return 0; } VipsQuantiseImage * vips__quantise_image_create_rgba(const VipsQuantiseAttr *attr, const void *bitmap, int width, int height, double gamma) { /* attr and gamma ununused by quantizr */ return quantizr_create_image_rgba( (unsigned char *) bitmap, width, height); } VipsQuantiseError vips__quantise_image_quantize(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output) { *result_output = quantizr_quantize(input_image, options); return 0; } VipsQuantiseError vips__quantise_image_quantize_fixed(VipsQuantiseImage *const input_image, VipsQuantiseAttr *const options, VipsQuantiseResult **result_output) { /* Quantizr doesn't change the palette during remapping, so we don't * need a special implementation for this */ return vips__quantise_image_quantize(input_image, options, result_output); } VipsQuantiseError vips__quantise_set_dithering_level(VipsQuantiseResult *res, float dither_level) { return quantizr_set_dithering_level(res, dither_level); } const VipsQuantisePalette * vips__quantise_get_palette(VipsQuantiseResult *result) { return quantizr_get_palette(result); } VipsQuantiseError vips__quantise_write_remapped_image(VipsQuantiseResult *result, VipsQuantiseImage *input_image, void *buffer, size_t buffer_size) { return quantizr_remap(result, input_image, buffer, buffer_size); } void vips__quantise_result_destroy(VipsQuantiseResult *result) { quantizr_free_result(result); } void vips__quantise_image_destroy(VipsQuantiseImage *img) { quantizr_free_image(img); } void vips__quantise_attr_destroy(VipsQuantiseAttr *attr) { quantizr_free_options(attr); } #endif /*HAVE_IMAGEQUANT*/ /* Track during a quantisation. */ typedef struct _Quantise { VipsImage *in; VipsImage **index_out; VipsImage **palette_out; int colours; int Q; double dither; int effort; VipsQuantiseAttr *attr; VipsQuantiseImage *input_image; VipsQuantiseResult *quantisation_result; VipsImage *t[5]; } Quantise; static void vips__quantise_free(Quantise *quantise) { int i; VIPS_FREEF(vips__quantise_result_destroy, quantise->quantisation_result); VIPS_FREEF(vips__quantise_image_destroy, quantise->input_image); VIPS_FREEF(vips__quantise_attr_destroy, quantise->attr); for (i = 0; i < VIPS_NUMBER(quantise->t); i++) VIPS_UNREF(quantise->t[i]); VIPS_FREE(quantise); } static Quantise * vips__quantise_new(VipsImage *in, VipsImage **index_out, VipsImage **palette_out, int colours, int Q, double dither, int effort) { Quantise *quantise; int i; quantise = VIPS_NEW(NULL, Quantise); quantise->in = in; quantise->index_out = index_out; quantise->palette_out = palette_out; quantise->colours = colours; quantise->Q = Q; quantise->dither = dither; quantise->effort = effort; for (i = 0; i < VIPS_NUMBER(quantise->t); i++) quantise->t[i] = NULL; return quantise; } int vips__quantise_image(VipsImage *in, VipsImage **index_out, VipsImage **palette_out, int colours, int Q, double dither, int effort, gboolean threshold_alpha) { Quantise *quantise; VipsImage *index; VipsImage *palette; const VipsQuantisePalette *lp; gint64 i; VipsPel *restrict p; gboolean added_alpha; quantise = vips__quantise_new(in, index_out, palette_out, colours, Q, dither, effort); /* Ensure input is sRGB. */ if (in->Type != VIPS_INTERPRETATION_sRGB) { if (vips_colourspace(in, &quantise->t[0], VIPS_INTERPRETATION_sRGB, NULL)) { vips__quantise_free(quantise); return -1; } in = quantise->t[0]; } /* Add alpha channel if missing. */ added_alpha = FALSE; if (!vips_image_hasalpha(in)) { if (vips_bandjoin_const1(in, &quantise->t[1], 255, NULL)) { vips__quantise_free(quantise); return -1; } added_alpha = TRUE; in = quantise->t[1]; } if (!(quantise->t[2] = vips_image_copy_memory(in))) { vips__quantise_free(quantise); return -1; } in = quantise->t[2]; /* Threshold alpha channel. */ if (threshold_alpha && !added_alpha) { const guint64 n_pels = VIPS_IMAGE_N_PELS(in); p = VIPS_IMAGE_ADDR(in, 0, 0); for (i = 0; i < n_pels; i++) { p[3] = p[3] > 128 ? 255 : 0; p += 4; } } quantise->attr = vips__quantise_attr_create(); vips__quantise_set_max_colors(quantise->attr, colours); vips__quantise_set_quality(quantise->attr, 0, Q); vips__quantise_set_speed(quantise->attr, 11 - effort); quantise->input_image = vips__quantise_image_create_rgba(quantise->attr, VIPS_IMAGE_ADDR(in, 0, 0), in->Xsize, in->Ysize, 0); if (vips__quantise_image_quantize(quantise->input_image, quantise->attr, &quantise->quantisation_result)) { vips_error("quantise", "%s", _("quantisation failed")); vips__quantise_free(quantise); return -1; } vips__quantise_set_dithering_level(quantise->quantisation_result, dither); index = quantise->t[3] = vips_image_new_memory(); vips_image_init_fields(index, in->Xsize, in->Ysize, 1, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0); if (vips_image_write_prepare(index)) { vips__quantise_free(quantise); return -1; } if (vips__quantise_write_remapped_image(quantise->quantisation_result, quantise->input_image, VIPS_IMAGE_ADDR(index, 0, 0), VIPS_IMAGE_N_PELS(index))) { vips_error("quantise", "%s", _("quantisation failed")); vips__quantise_free(quantise); return -1; } lp = vips__quantise_get_palette(quantise->quantisation_result); palette = quantise->t[4] = vips_image_new_memory(); vips_image_init_fields(palette, lp->count, 1, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); if (vips_image_write_prepare(palette)) { vips__quantise_free(quantise); return -1; } p = VIPS_IMAGE_ADDR(palette, 0, 0); for (i = 0; i < lp->count; i++) { p[0] = lp->entries[i].r; p[1] = lp->entries[i].g; p[2] = lp->entries[i].b; p[3] = lp->entries[i].a; p += 4; } *index_out = index; g_object_ref(index); *palette_out = palette; g_object_ref(palette); vips__quantise_free(quantise); return 0; } #else /*!HAVE_QUANTIZATION*/ int vips__quantise_image(VipsImage *in, VipsImage **index_out, VipsImage **palette_out, int colours, int Q, double dither, int effort, gboolean threshold_alpha) { vips_error("vips__quantise_image", "%s", _("libvips not built with quantisation support")); return -1; } #endif /*HAVE_QUANTIZATION*/ libvips-8.18.2/libvips/foreign/quantise.h000066400000000000000000000060641516303661500204010ustar00rootroot00000000000000/* common defs for image quantisation */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_QUANTISE_H #define VIPS_QUANTISE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #if defined(HAVE_IMAGEQUANT) #define HAVE_QUANTIZATION #include #define VipsQuantiseAttr liq_attr #define VipsQuantiseImage liq_image #define VipsQuantiseResult liq_result #define VipsQuantisePalette liq_palette #define VipsQuantiseError liq_error #elif defined(HAVE_QUANTIZR) #define HAVE_QUANTIZATION #include #define VipsQuantiseAttr QuantizrOptions #define VipsQuantiseImage QuantizrImage #define VipsQuantiseResult QuantizrResult #define VipsQuantisePalette QuantizrPalette #define VipsQuantiseError QuantizrError #endif #ifdef HAVE_QUANTIZATION VipsQuantiseAttr *vips__quantise_attr_create(void); VipsQuantiseError vips__quantise_set_max_colors(VipsQuantiseAttr *attr, int colors); VipsQuantiseError vips__quantise_set_quality(VipsQuantiseAttr *attr, int minimum, int maximum); VipsQuantiseError vips__quantise_set_speed(VipsQuantiseAttr *attr, int speed); VipsQuantiseImage *vips__quantise_image_create_rgba(const VipsQuantiseAttr *attr, const void *bitmap, int width, int height, double gamma); VipsQuantiseError vips__quantise_image_quantize(VipsQuantiseImage *input_image, VipsQuantiseAttr *options, VipsQuantiseResult **result_output); VipsQuantiseError vips__quantise_image_quantize_fixed(VipsQuantiseImage *input_image, VipsQuantiseAttr *options, VipsQuantiseResult **result_output); VipsQuantiseError vips__quantise_set_dithering_level(VipsQuantiseResult *res, float dither_level); const VipsQuantisePalette *vips__quantise_get_palette(VipsQuantiseResult *result); VipsQuantiseError vips__quantise_write_remapped_image(VipsQuantiseResult *result, VipsQuantiseImage *input_image, void *buffer, size_t buffer_size); void vips__quantise_result_destroy(VipsQuantiseResult *result); void vips__quantise_image_destroy(VipsQuantiseImage *img); void vips__quantise_attr_destroy(VipsQuantiseAttr *attr); #endif /*HAVE_QUANTIZATION*/ int vips__quantise_image(VipsImage *in, VipsImage **index_out, VipsImage **palette_out, int colours, int Q, double dither, int effort, gboolean threshold_alpha); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_QUANTISE_H*/ libvips-8.18.2/libvips/foreign/radiance.c000066400000000000000000000572221516303661500203130ustar00rootroot00000000000000/* Read Radiance (.hdr) files * * 3/3/09 * - write packed data, a separate im_rad2float() operation can unpack * 23/3/09 * - add radiance write * 20/12/11 * - reworked as some fns ready for new-style classes * 13/12/12 * - tag RGB rad images as scRGB * 4/11/13 * - support sequential read * 5/11/13 * - rewritten scanline encode and decode, now much faster * 23/1/14 * - put the reader globals into a struct so we can have many active * readers * 23/5/16 * - add buffer save functions * 28/2/17 * - use dbuf for buffer output * 4/4/17 * - reduce stack use to help musl * 22/7/18 * - update code from radiance ... pasted in from rad5R1 * - expand fs[] buffer to prevent out of bounds write [HongxuChen] * 23/7/18 * - fix a buffer overflow for incorrectly coded old-style RLE * [HongxuChen] * 6/11/19 * - revise for VipsConnection * 28/1/23 kleisauke * - clean-up unused macros/externs * - sync with radiance 5.3 * 15/07/24 kleisauke * - sync with radiance 5.4 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Remaining issues: + it ignores some header fields, like VIEW and DATE + it will not rotate/flip as the FORMAT string asks */ /* Sections of this reader from Greg Ward and Radiance with kind permission. The Radience copyright notice appears below. */ /* ==================================================================== * The Radiance Software License, Version 2.0 * * Radiance v5.4 Copyright (c) 1990 to 2022, The Regents of the University of * California, through Lawrence Berkeley National Laboratory (subject to receipt * of any required approvals from the U.S. Dept. of Energy). All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * (1) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * (2) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * (3) Neither the name of the University of California, Lawrence Berkeley * National Laboratory, U.S. Dept. of Energy nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * You are under no obligation whatsoever to provide any bug fixes, patches, * or upgrades to the features, functionality or performance of the source * code ("Enhancements") to anyone; however, if you choose to make your * Enhancements available either publicly, or directly to Lawrence Berkeley * National Laboratory, without imposing a separate written license agreement * for such Enhancements, then you hereby grant the following license: a * non-exclusive, royalty-free perpetual license to install, use, modify, * prepare derivative works, incorporate into other computer software, * distribute, and sublicense such enhancements or derivative works thereof, * in binary and source code form. * ==================================================================== */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_RADIANCE #include #include #include #include #include #include #include #include #include #include #include "pforeign.h" /* Begin copy-paste from Radiance sources. * * To update: * * 1. Download and unpack latest stable radiance * 2. ray/src/common has the files we need ... copy in this order: * color.h * resolu.h * rtio.h * fputword.c * color.c * resolu.c * header.c * 3. trim each one down, removing extern decls * 4. make all functions static * 5. reorder to remove forward refs * 6. remove unused funcs/macros, mostly related to HDR write */ #define RED 0 #define GRN 1 #define BLU 2 #define CIEX 0 /* or, if input is XYZ... */ #define CIEY 1 #define EXP 3 /* exponent same for either format */ #define COLXS 128 /* excess used for exponent */ #define WHT 3 /* used for RGBPRIMS type */ typedef unsigned char COLR[4]; /* red, green, blue (or X,Y,Z), exponent */ typedef float COLOR[3]; /* red, green, blue (or X,Y,Z) */ typedef float RGBPRIMS[4][2]; /* (x,y) chromaticities for RGBW */ #define copycolr(c1, c2) (c1[0] = c2[0], c1[1] = c2[1], \ c1[2] = c2[2], c1[3] = c2[3]) #define CIE_x_r 0.640 /* nominal CRT primaries */ #define CIE_y_r 0.330 #define CIE_x_g 0.290 #define CIE_y_g 0.600 #define CIE_x_b 0.150 #define CIE_y_b 0.060 #define CIE_x_w (1. / 3.) /* use EE white */ #define CIE_y_w (1. / 3.) /* picture format identifier */ #define COLRFMT "32-bit_rle_rgbe" #define CIEFMT "32-bit_rle_xyze" /* macros for exposures */ #define EXPOSSTR "EXPOSURE=" #define LEXPOSSTR 9 #define isexpos(hl) (!strncmp(hl, EXPOSSTR, LEXPOSSTR)) #define exposval(hl) atof((hl) + LEXPOSSTR) /* macros for pixel aspect ratios */ #define ASPECTSTR "PIXASPECT=" #define LASPECTSTR 10 #define isaspect(hl) (!strncmp(hl, ASPECTSTR, LASPECTSTR)) #define aspectval(hl) atof((hl) + LASPECTSTR) /* macros for primary specifications */ #define PRIMARYSTR "PRIMARIES=" #define LPRIMARYSTR 10 #define isprims(hl) (!strncmp(hl, PRIMARYSTR, LPRIMARYSTR)) #define primsval(p, hl) (sscanf((hl) + LPRIMARYSTR, \ "%f %f %f %f %f %f %f %f", \ &(p)[RED][CIEX], &(p)[RED][CIEY], \ &(p)[GRN][CIEX], &(p)[GRN][CIEY], \ &(p)[BLU][CIEX], &(p)[BLU][CIEY], \ &(p)[WHT][CIEX], &(p)[WHT][CIEY]) == 8) /* macros for color correction */ #define COLCORSTR "COLORCORR=" #define LCOLCORSTR 10 #define iscolcor(hl) (!strncmp(hl, COLCORSTR, LCOLCORSTR)) #define colcorval(cc, hl) (sscanf((hl) + LCOLCORSTR, "%f %f %f", \ &(cc)[RED], &(cc)[GRN], &(cc)[BLU]) == 3) #define MINELEN 8 /* minimum scanline length for encoding */ #define MAXELEN 0x7fff /* maximum scanline length for encoding */ #define MINRUN 4 /* minimum run length */ /* flags for scanline ordering */ #define XDECR 1 #define YDECR 2 #define YMAJOR 4 /* structure for image dimensions */ typedef struct { int rt; /* orientation (from flags above) */ int xr, yr; /* x and y resolution */ } RESOLU; /* macros to get scanline length and number */ #define scanlen(rs) ((rs)->rt & YMAJOR ? (rs)->xr : (rs)->yr) #define numscans(rs) ((rs)->rt & YMAJOR ? (rs)->yr : (rs)->xr) /* resolution string buffer and its size */ #define RESOLU_BUFLEN 32 static char resolu_buf[RESOLU_BUFLEN]; /* identify header lines */ #define isformat(s) formatval(NULL, s) typedef int gethfunc(char *s, void *p); /* callback to process header lines */ /* convert resolution struct to line */ static char * resolu2str(char *buf, register RESOLU *rp) { if (rp->rt & YMAJOR) sprintf(buf, "%cY %8d %cX %8d\n", rp->rt & YDECR ? '-' : '+', rp->yr, rp->rt & XDECR ? '-' : '+', rp->xr); else sprintf(buf, "%cX %8d %cY %8d\n", rp->rt & XDECR ? '-' : '+', rp->xr, rp->rt & YDECR ? '-' : '+', rp->yr); return buf; } /* convert resolution line to struct */ static int str2resolu(register RESOLU *rp, char *buf) { register char *xndx, *yndx; register char *cp; if (buf == NULL) return 0; xndx = yndx = NULL; for (cp = buf; *cp; cp++) if (*cp == 'X') xndx = cp; else if (*cp == 'Y') yndx = cp; if (xndx == NULL || yndx == NULL) return 0; rp->rt = 0; if (xndx > yndx) rp->rt |= YMAJOR; if (xndx[-1] == '-') rp->rt |= XDECR; if (yndx[-1] == '-') rp->rt |= YDECR; if ((rp->xr = atoi(xndx + 1)) <= 0) return 0; if ((rp->yr = atoi(yndx + 1)) <= 0) return 0; return 1; } #define MAXFMTLEN 64 static const char FMTSTR[] = "FORMAT="; /* format identifier */ /* get format value (return true if format) */ static int formatval(char fmt[MAXFMTLEN], const char *s) { const char *cp = FMTSTR; char *r = fmt; /* check against format string */ while (*cp) if (*cp++ != *s++) return 0; while (g_ascii_isspace(*s)) s++; if (!*s) return 0; if (r == NULL) /* just checking if format? */ return 1; do /* copy format ID */ *r++ = *s++; while (*s && r - fmt < MAXFMTLEN - 1); do /* remove trailing white space */ *r-- = '\0'; while (r > fmt && g_ascii_isspace(*r)); return 1; } /* Get header from source. */ static int getheader(VipsSbuf *sbuf, gethfunc *f, void *p) { for (;;) { const char *line; if (!(line = vips_sbuf_get_line(sbuf))) return -1; if (strcmp(line, "") == 0) /* Blank line. We've parsed the header successfully. */ break; if (f != NULL && (*f)((char *) line, p) < 0) return -1; } return 0; } /* Read a single scanline, encoded in the old style. */ static int scanline_read_old(VipsSbuf *sbuf, COLR *scanline, int width) { int rshift; rshift = 0; while (width > 0) { if (VIPS_SBUF_REQUIRE(sbuf, 4)) return -1; scanline[0][RED] = VIPS_SBUF_FETCH(sbuf); scanline[0][GRN] = VIPS_SBUF_FETCH(sbuf); scanline[0][BLU] = VIPS_SBUF_FETCH(sbuf); scanline[0][EXP] = VIPS_SBUF_FETCH(sbuf); if (scanline[0][RED] == 1 && scanline[0][GRN] == 1 && scanline[0][BLU] == 1) { guint i; for (i = ((guint32) scanline[0][EXP] << rshift); i > 0 && width > 0; i--) { copycolr(scanline[0], scanline[-1]); scanline += 1; width -= 1; } rshift += 8; /* This can happen with badly-formed input files. */ if (rshift > 24) return -1; } else { scanline += 1; width -= 1; rshift = 0; } } return 0; } /* Read a single encoded scanline. */ static int scanline_read(VipsSbuf *sbuf, COLR *scanline, int width) { int i, j; /* Detect old-style scanlines. */ if (width < MINELEN || width > MAXELEN) return scanline_read_old(sbuf, scanline, width); if (VIPS_SBUF_REQUIRE(sbuf, 4)) return -1; if (VIPS_SBUF_PEEK(sbuf)[0] != 2) return scanline_read_old(sbuf, scanline, width); scanline[0][RED] = VIPS_SBUF_FETCH(sbuf); scanline[0][GRN] = VIPS_SBUF_FETCH(sbuf); scanline[0][BLU] = VIPS_SBUF_FETCH(sbuf); scanline[0][EXP] = VIPS_SBUF_FETCH(sbuf); if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) return scanline_read_old(sbuf, scanline + 1, width - 1); if (((scanline[0][BLU] << 8) | scanline[0][EXP]) != width) { vips_error("rad2vips", "%s", _("scanline length mismatch")); return -1; } for (i = 0; i < 4; i++) for (j = 0; j < width;) { int code, len; gboolean run; if (VIPS_SBUF_REQUIRE(sbuf, 2)) return -1; code = VIPS_SBUF_FETCH(sbuf); run = code > 128; len = run ? code & 127 : code; if (j + len > width) { vips_error("rad2vips", "%s", _("overrun")); return -1; } if (run) { int val; val = VIPS_SBUF_FETCH(sbuf); while (len--) scanline[j++][i] = val; } else { if (VIPS_SBUF_REQUIRE(sbuf, len)) return -1; while (len--) scanline[j++][i] = VIPS_SBUF_FETCH(sbuf); } } return 0; } /* An encoded scanline can't be larger than this. */ #define MAX_LINE (2 * MAXELEN * sizeof(COLR)) /* write an RLE scanline. Write magic header. */ static void rle_scanline_write(COLR *scanline, int width, unsigned char *buffer, int *length) { int i, j, beg, cnt; #define PUTC(CH) \ { \ buffer[(*length)++] = (CH); \ g_assert(*length <= MAX_LINE); \ } *length = 0; PUTC(2); PUTC(2); PUTC(width >> 8); PUTC(width & 255); for (i = 0; i < 4; i++) { for (j = 0; j < width;) { /* Not needed, but keeps gcc used-before-set warning * quiet. */ cnt = 1; /* Set beg / cnt to the start and length of the next * run longer than MINRUN. */ for (beg = j; beg < width; beg += cnt) { for (cnt = 1; cnt < 127 && beg + cnt < width && scanline[beg + cnt][i] == scanline[beg][i]; cnt++) ; if (cnt >= MINRUN) break; } /* Code pixels leading up to the run as a set of * non-runs. */ while (j < beg) { int len = VIPS_MIN(128, beg - j); COLR *p = scanline + j; int k; PUTC(len); for (k = 0; k < len; k++) PUTC(p[k][i]); j += len; } /* Code the run we found, if any */ if (cnt >= MINRUN) { PUTC(128 + cnt); PUTC(scanline[j][i]); j += cnt; } } } } /* What we track during radiance file read. */ typedef struct { VipsSbuf *sbuf; VipsImage *out; char format[256]; double expos; COLOR colcor; double aspect; RGBPRIMS prims; RESOLU rs; } Read; int vips__rad_israd(VipsSource *source) { VipsSbuf *sbuf; const char *line; int result; /* Just test that the first line is the magic string. */ sbuf = vips_sbuf_new_from_source(source); result = (line = vips_sbuf_get_line(sbuf)) && strcmp(line, "#?RADIANCE") == 0; VIPS_UNREF(sbuf); return result; } static void read_destroy(VipsImage *image, Read *read) { VIPS_UNREF(read->sbuf); } static void read_minimise_cb(VipsImage *image, Read *read) { if (read->sbuf) vips_source_minimise(read->sbuf->source); } static Read * read_new(VipsSource *source, VipsImage *out) { Read *read; int i; if (vips_source_rewind(source)) return NULL; if (!(read = VIPS_NEW(out, Read))) return NULL; read->sbuf = vips_sbuf_new_from_source(source); read->out = out; strcpy(read->format, COLRFMT); read->expos = 1.0; for (i = 0; i < 3; i++) read->colcor[i] = 1.0F; read->aspect = 1.0; read->prims[0][0] = CIE_x_r; read->prims[0][1] = CIE_y_r; read->prims[1][0] = CIE_x_g; read->prims[1][1] = CIE_y_g; read->prims[2][0] = CIE_x_b; read->prims[2][1] = CIE_y_b; read->prims[3][0] = CIE_x_w; read->prims[3][1] = CIE_y_w; g_signal_connect(out, "close", G_CALLBACK(read_destroy), read); g_signal_connect(out, "minimise", G_CALLBACK(read_minimise_cb), read); return read; } static int rad2vips_process_line(char *line, Read *read) { if (isformat(line)) { if (formatval(line, read->format)) return -1; } else if (isexpos(line)) { read->expos *= exposval(line); } else if (iscolcor(line)) { COLOR cc; int i; if (!colcorval(cc, line)) return -1; for (i = 0; i < 3; i++) read->colcor[i] *= cc[i]; } else if (isaspect(line)) { read->aspect *= aspectval(line); } else if (isprims(line)) { if (!primsval(read->prims, line)) return -1; } return 0; } static const char *prims_name[4][2] = { { "rad-prims-rx", "rad-prims-ry" }, { "rad-prims-gx", "rad-prims-gy" }, { "rad-prims-bx", "rad-prims-by" }, { "rad-prims-wx", "rad-prims-wy" } }; static const char *colcor_name[3] = { "rad-colcor-r", "rad-colcor-g", "rad-colcor-b" }; static int rad2vips_get_header(Read *read, VipsImage *out) { VipsInterpretation interpretation; const char *line; int width; int height; int i, j; if (getheader(read->sbuf, (gethfunc *) rad2vips_process_line, read) || !(line = vips_sbuf_get_line(read->sbuf)) || !str2resolu(&read->rs, (char *) line)) { vips_error("rad2vips", "%s", _("error reading radiance header")); return -1; } if (strcmp(read->format, COLRFMT) == 0) interpretation = VIPS_INTERPRETATION_scRGB; else if (strcmp(read->format, CIEFMT) == 0) interpretation = VIPS_INTERPRETATION_XYZ; else interpretation = VIPS_INTERPRETATION_MULTIBAND; width = scanlen(&read->rs); height = numscans(&read->rs); if (width <= 0 || width >= VIPS_MAX_COORD || height <= 0 || height >= VIPS_MAX_COORD) { vips_error("rad2vips", "%s", _("image size out of bounds")); return -1; } vips_image_init_fields(out, width, height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_RAD, interpretation, 1, read->aspect); VIPS_SETSTR(out->filename, vips_connection_filename( VIPS_CONNECTION(read->sbuf->source))); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; vips_image_set_string(out, "rad-format", read->format); vips_image_set_double(out, "rad-expos", read->expos); for (i = 0; i < 3; i++) vips_image_set_double(out, colcor_name[i], read->colcor[i]); vips_image_set_double(out, "rad-aspect", read->aspect); for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) vips_image_set_double(out, prims_name[i][j], read->prims[i][j]); return 0; } int vips__rad_header(VipsSource *source, VipsImage *out) { Read *read; if (!(read = read_new(source, out))) return -1; if (rad2vips_get_header(read, read->out)) return -1; vips_source_minimise(source); return 0; } static int rad2vips_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; Read *read = (Read *) a; int y; #ifdef DEBUG printf("rad2vips_generate: line %d, %d rows\n", r->top, r->height); #endif /*DEBUG*/ VIPS_GATE_START("rad2vips_generate: work"); for (y = 0; y < r->height; y++) { COLR *buf = (COLR *) VIPS_REGION_ADDR(out_region, 0, r->top + y); if (scanline_read(read->sbuf, buf, out_region->im->Xsize)) { vips_error("rad2vips", _("read error line %d"), r->top + y); VIPS_GATE_STOP("rad2vips_generate: work"); return -1; } } VIPS_GATE_STOP("rad2vips_generate: work"); return 0; } int vips__rad_load(VipsSource *source, VipsImage *out) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 3); Read *read; #ifdef DEBUG printf("rad2vips: reading \"%s\"\n", vips_connection_nick(VIPS_CONNECTION(source))); #endif /*DEBUG*/ if (!(read = read_new(source, out))) return -1; t[0] = vips_image_new(); if (rad2vips_get_header(read, t[0])) return -1; if (vips_image_generate(t[0], NULL, rad2vips_generate, NULL, read, NULL) || vips_sequential(t[0], &t[1], "tile_height", VIPS__FATSTRIP_HEIGHT, NULL) || vips_image_write(t[1], out)) return -1; if (vips_source_decode(source)) return -1; return 0; } /* What we track during a radiance write. */ typedef struct { VipsImage *in; VipsTarget *target; char format[256]; double expos; COLOR colcor; double aspect; RGBPRIMS prims; RESOLU rs; unsigned char *line; } Write; static void write_destroy(Write *write) { VIPS_FREE(write->line); VIPS_UNREF(write->target); g_free(write); } static Write * write_new(VipsImage *in, VipsTarget *target) { Write *write; int i; if (!(write = VIPS_NEW(NULL, Write))) return NULL; write->in = in; write->target = target; g_object_ref(target); strcpy(write->format, COLRFMT); write->expos = 1.0; for (i = 0; i < 3; i++) write->colcor[i] = 1.0F; write->aspect = 1.0; write->prims[0][0] = CIE_x_r; write->prims[0][1] = CIE_y_r; write->prims[1][0] = CIE_x_g; write->prims[1][1] = CIE_y_g; write->prims[2][0] = CIE_x_b; write->prims[2][1] = CIE_y_b; write->prims[3][0] = CIE_x_w; write->prims[3][1] = CIE_y_w; if (!(write->line = VIPS_ARRAY(NULL, MAX_LINE, unsigned char))) { write_destroy(write); return NULL; } return write; } static void vips2rad_make_header(Write *write) { const char *str; int i, j; double d; if (vips_image_get_typeof(write->in, "rad-expos")) vips_image_get_double(write->in, "rad-expos", &write->expos); if (vips_image_get_typeof(write->in, "rad-aspect")) vips_image_get_double(write->in, "rad-aspect", &write->aspect); if (vips_image_get_typeof(write->in, "rad-format") && !vips_image_get_string(write->in, "rad-format", &str)) g_strlcpy(write->format, str, 256); if (write->in->Type == VIPS_INTERPRETATION_scRGB) strcpy(write->format, COLRFMT); if (write->in->Type == VIPS_INTERPRETATION_XYZ) strcpy(write->format, CIEFMT); for (i = 0; i < 3; i++) if (vips_image_get_typeof(write->in, colcor_name[i]) && !vips_image_get_double(write->in, colcor_name[i], &d)) write->colcor[i] = d; for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) { const char *name = prims_name[i][j]; if (vips_image_get_typeof(write->in, name) && !vips_image_get_double(write->in, name, &d)) write->prims[i][j] = d; } /* Make y decreasing for consistency with vips. */ write->rs.rt = YDECR | YMAJOR; write->rs.xr = write->in->Xsize; write->rs.yr = write->in->Ysize; } static int vips2rad_put_header(Write *write) { vips2rad_make_header(write); vips_target_writes(write->target, "#?RADIANCE\n"); vips_target_writef(write->target, "%s%s\n", FMTSTR, write->format); vips_target_writef(write->target, "%s%e\n", EXPOSSTR, write->expos); vips_target_writef(write->target, "%s %f %f %f\n", COLCORSTR, write->colcor[RED], write->colcor[GRN], write->colcor[BLU]); vips_target_writef(write->target, "SOFTWARE=vips %s\n", vips_version_string()); vips_target_writef(write->target, "%s%f\n", ASPECTSTR, write->aspect); vips_target_writef(write->target, "%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n", PRIMARYSTR, write->prims[RED][CIEX], write->prims[RED][CIEY], write->prims[GRN][CIEX], write->prims[GRN][CIEY], write->prims[BLU][CIEX], write->prims[BLU][CIEY], write->prims[WHT][CIEX], write->prims[WHT][CIEY]); vips_target_writes(write->target, "\n"); vips_target_writes(write->target, resolu2str(resolu_buf, &write->rs)); return 0; } /* Write a single scanline to buffer. */ static int scanline_write(Write *write, COLR *scanline, int width) { if (width < MINELEN || width > MAXELEN) { /* Too large or small for RLE ... do a simple write. */ if (vips_target_write(write->target, scanline, sizeof(COLR) * width)) return -1; } else { int length; /* An RLE scanline. */ rle_scanline_write(scanline, width, write->line, &length); if (vips_target_write(write->target, write->line, length)) return -1; } return 0; } static int vips2rad_put_data_block(VipsRegion *region, VipsRect *area, void *a) { Write *write = (Write *) a; int i; for (i = 0; i < area->height; i++) { VipsPel *p = VIPS_REGION_ADDR(region, 0, area->top + i); if (scanline_write(write, (COLR *) p, area->width)) return -1; } return 0; } static int vips2rad_put_data(Write *write) { if (vips_sink_disc(write->in, vips2rad_put_data_block, write)) return -1; return 0; } int vips__rad_save(VipsImage *in, VipsTarget *target) { Write *write; #ifdef DEBUG printf("vips2rad: writing to buffer\n"); #endif /*DEBUG*/ if (vips_image_pio_input(in) || vips_check_coding("vips2rad", in, VIPS_CODING_RAD)) return -1; if (!(write = write_new(in, target))) return -1; if (vips2rad_put_header(write) || vips2rad_put_data(write)) { write_destroy(write); return -1; } if (vips_target_end(target)) return -1; write_destroy(write); return 0; } const char *vips__rad_suffs[] = { ".hdr", NULL }; #endif /*HAVE_RADIANCE*/ libvips-8.18.2/libvips/foreign/radload.c000066400000000000000000000267001516303661500201500ustar00rootroot00000000000000/* load radlab from a file * * 5/12/11 * - from tiffload.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_RADIANCE typedef struct _VipsForeignLoadRad { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; } VipsForeignLoadRad; typedef VipsForeignLoadClass VipsForeignLoadRadClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadRad, vips_foreign_load_rad, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_rad_dispose(GObject *gobject) { VipsForeignLoadRad *rad = (VipsForeignLoadRad *) gobject; VIPS_UNREF(rad->source); G_OBJECT_CLASS(vips_foreign_load_rad_parent_class)->dispose(gobject); } static VipsForeignFlags vips_foreign_load_rad_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_SEQUENTIAL; } static VipsForeignFlags vips_foreign_load_rad_get_flags_filename(const char *filename) { return VIPS_FOREIGN_SEQUENTIAL; } static int vips_foreign_load_rad_header(VipsForeignLoad *load) { VipsForeignLoadRad *rad = (VipsForeignLoadRad *) load; if (vips__rad_header(rad->source, load->out)) return -1; return 0; } static int vips_foreign_load_rad_load(VipsForeignLoad *load) { VipsForeignLoadRad *rad = (VipsForeignLoadRad *) load; if (vips__rad_load(rad->source, load->real)) return -1; return 0; } static void vips_foreign_load_rad_class_init(VipsForeignLoadRadClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_rad_dispose; object_class->nickname = "radload_base"; object_class->description = _("load rad base class"); /* You're unlikely to want to use this on untrusted files. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -50; load_class->get_flags_filename = vips_foreign_load_rad_get_flags_filename; load_class->get_flags = vips_foreign_load_rad_get_flags; load_class->header = vips_foreign_load_rad_header; load_class->load = vips_foreign_load_rad_load; } static void vips_foreign_load_rad_init(VipsForeignLoadRad *rad) { } typedef struct _VipsForeignLoadRadSource { VipsForeignLoadRad parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadRadSource; typedef VipsForeignLoadRadClass VipsForeignLoadRadSourceClass; G_DEFINE_TYPE(VipsForeignLoadRadSource, vips_foreign_load_rad_source, vips_foreign_load_rad_get_type()); static int vips_foreign_load_rad_source_build(VipsObject *object) { VipsForeignLoadRad *rad = (VipsForeignLoadRad *) object; VipsForeignLoadRadSource *source = (VipsForeignLoadRadSource *) object; if (source->source) { rad->source = source->source; g_object_ref(rad->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_rad_source_parent_class) ->build(object); } static gboolean vips_foreign_load_rad_source_is_a_source(VipsSource *source) { return vips__rad_israd(source); } static void vips_foreign_load_rad_source_class_init(VipsForeignLoadRadSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "radload_source"; object_class->description = _("load rad from source"); object_class->build = vips_foreign_load_rad_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_rad_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRadSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_rad_source_init(VipsForeignLoadRadSource *source) { } typedef struct _VipsForeignLoadRadFile { VipsForeignLoadRad parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadRadFile; typedef VipsForeignLoadRadClass VipsForeignLoadRadFileClass; G_DEFINE_TYPE(VipsForeignLoadRadFile, vips_foreign_load_rad_file, vips_foreign_load_rad_get_type()); static int vips_foreign_load_rad_file_build(VipsObject *object) { VipsForeignLoadRad *rad = (VipsForeignLoadRad *) object; VipsForeignLoadRadFile *file = (VipsForeignLoadRadFile *) object; if (file->filename && !(rad->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_rad_file_parent_class) ->build(object); } static int vips_foreign_load_rad_file_is_a(const char *filename) { VipsSource *source; int result; if (!(source = vips_source_new_from_file(filename))) return -1; result = vips_foreign_load_rad_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_rad_file_class_init(VipsForeignLoadRadFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "radload"; object_class->description = _("load a Radiance image from a file"); object_class->build = vips_foreign_load_rad_file_build; foreign_class->suffs = vips__rad_suffs; load_class->is_a = vips_foreign_load_rad_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRadFile, filename), NULL); } static void vips_foreign_load_rad_file_init(VipsForeignLoadRadFile *file) { } typedef struct _VipsForeignLoadRadBuffer { VipsForeignLoadRad parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadRadBuffer; typedef VipsForeignLoadRadClass VipsForeignLoadRadBufferClass; G_DEFINE_TYPE(VipsForeignLoadRadBuffer, vips_foreign_load_rad_buffer, vips_foreign_load_rad_get_type()); static int vips_foreign_load_rad_buffer_build(VipsObject *object) { VipsForeignLoadRad *rad = (VipsForeignLoadRad *) object; VipsForeignLoadRadBuffer *buffer = (VipsForeignLoadRadBuffer *) object; if (buffer->blob && !(rad->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_rad_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_rad_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_rad_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_rad_buffer_class_init(VipsForeignLoadRadBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "radload_buffer"; object_class->description = _("load rad from buffer"); object_class->build = vips_foreign_load_rad_buffer_build; load_class->is_a_buffer = vips_foreign_load_rad_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRadBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_rad_buffer_init(VipsForeignLoadRadBuffer *buffer) { } #endif /*HAVE_RADIANCE*/ /** * vips_radload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Read a Radiance (HDR) file into a VIPS image. * * Radiance files are read as [enum@Vips.Coding.RAD]. They have one byte for each of * red, green and blue, and one byte of shared exponent. Some operations (like * [method@Image.extract_area]) can work directly with images in this format, but * mmany (all the arithmetic operations, for example) will not. Unpack * [enum@Vips.Coding.RAD] images to 3 band float with [method@Image.rad2float] if * you want to do arithmetic on them. * * This operation ignores some header fields, like VIEW and DATE. It will not * rotate/flip as the FORMAT string asks. * * Sections of this reader from Greg Ward and Radiance with kind permission. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_radload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("radload", ap, filename, out); va_end(ap); return result; } /** * vips_radload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.radload], but read from a HDR-formatted memory block. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: seealso * [ctor@Image.radload]. * * Returns: 0 on success, -1 on error. */ int vips_radload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("radload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_radload_source: * @source: source to load from * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.radload], but read from a source. * * ::: seealso * [ctor@Image.radload]. * * Returns: 0 on success, -1 on error. */ int vips_radload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("radload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/radsave.c000066400000000000000000000221571516303661500201710ustar00rootroot00000000000000/* save to rad * * 2/12/11 * - wrap a class around the rad writer * 23/5/16 * - split into file and buffer save classes */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_RADIANCE typedef struct _VipsForeignSaveRad { VipsForeignSave parent_object; } VipsForeignSaveRad; typedef VipsForeignSaveClass VipsForeignSaveRadClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveRad, vips_foreign_save_rad, VIPS_TYPE_FOREIGN_SAVE); /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static VipsBandFormat vips_foreign_save_rad_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ F, F, F, F, F, F, F, F, F, F }; static void vips_foreign_save_rad_class_init(VipsForeignSaveRadClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; object_class->nickname = "radsave_base"; object_class->description = _("save Radiance"); foreign_class->suffs = vips__rad_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB; save_class->format_table = vips_foreign_save_rad_format_table; save_class->coding = VIPS_FOREIGN_CODING_RAD; } static void vips_foreign_save_rad_init(VipsForeignSaveRad *rad) { } typedef struct _VipsForeignSaveRadFile { VipsForeignSaveRad parent_object; char *filename; } VipsForeignSaveRadFile; typedef VipsForeignSaveRadClass VipsForeignSaveRadFileClass; G_DEFINE_TYPE(VipsForeignSaveRadFile, vips_foreign_save_rad_file, vips_foreign_save_rad_get_type()); static int vips_foreign_save_rad_file_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveRadFile *file = (VipsForeignSaveRadFile *) object; VipsTarget *target; if (VIPS_OBJECT_CLASS(vips_foreign_save_rad_file_parent_class)-> build(object)) return -1; if (!(target = vips_target_new_to_file(file->filename))) return -1; if (vips__rad_save(save->ready, target)) { VIPS_UNREF(target); return -1; } VIPS_UNREF(target); return 0; } static void vips_foreign_save_rad_file_class_init(VipsForeignSaveRadFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "radsave"; object_class->description = _("save image to Radiance file"); object_class->build = vips_foreign_save_rad_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveRadFile, filename), NULL); } static void vips_foreign_save_rad_file_init(VipsForeignSaveRadFile *file) { } typedef struct _VipsForeignSaveRadTarget { VipsForeignSaveRad parent_object; VipsTarget *target; } VipsForeignSaveRadTarget; typedef VipsForeignSaveRadClass VipsForeignSaveRadTargetClass; G_DEFINE_TYPE(VipsForeignSaveRadTarget, vips_foreign_save_rad_target, vips_foreign_save_rad_get_type()); static int vips_foreign_save_rad_target_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveRadTarget *target = (VipsForeignSaveRadTarget *) object; if (VIPS_OBJECT_CLASS(vips_foreign_save_rad_target_parent_class) ->build(object)) return -1; if (vips__rad_save(save->ready, target->target)) return -1; return 0; } static void vips_foreign_save_rad_target_class_init(VipsForeignSaveRadTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "radsave_target"; object_class->description = _("save image to Radiance target"); object_class->build = vips_foreign_save_rad_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveRadTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_rad_target_init(VipsForeignSaveRadTarget *target) { } typedef struct _VipsForeignSaveRadBuffer { VipsForeignSaveRad parent_object; VipsArea *buf; } VipsForeignSaveRadBuffer; typedef VipsForeignSaveRadClass VipsForeignSaveRadBufferClass; G_DEFINE_TYPE(VipsForeignSaveRadBuffer, vips_foreign_save_rad_buffer, vips_foreign_save_rad_get_type()); static int vips_foreign_save_rad_buffer_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsTarget *target; VipsBlob *blob; if (VIPS_OBJECT_CLASS(vips_foreign_save_rad_buffer_parent_class) ->build(object)) return -1; if (!(target = vips_target_new_to_memory())) return -1; if (vips__rad_save(save->ready, target)) { VIPS_UNREF(target); return -1; } g_object_get(target, "blob", &blob, NULL); g_object_set(save, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); VIPS_UNREF(target); return 0; } static void vips_foreign_save_rad_buffer_class_init(VipsForeignSaveRadBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "radsave_buffer"; object_class->description = _("save image to Radiance buffer"); object_class->build = vips_foreign_save_rad_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveRadBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_rad_buffer_init(VipsForeignSaveRadBuffer *buffer) { } #endif /*HAVE_RADIANCE*/ /** * vips_radsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image in Radiance (HDR) format. * * Sections of this reader from Greg Ward and Radiance with kind permission. * * ::: seealso * [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_radsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("radsave", ap, in, filename); va_end(ap); return result; } /** * vips_radsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.radsave], but save to a memory buffer. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: seealso * [method@Image.radsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_radsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("radsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_radsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.radsave], but save to a target. * * ::: seealso * [method@Image.radsave]. * * Returns: 0 on success, -1 on error. */ int vips_radsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("radsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/rawload.c000066400000000000000000000137301516303661500201720ustar00rootroot00000000000000/* load raw data from a file * * 14/12/11 * 5/8/19 * - add @format and @interpretation */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsForeignLoadRaw { VipsForeignLoad parent_object; char *filename; int width; int height; int bands; guint64 offset; VipsBandFormat format; VipsInterpretation interpretation; } VipsForeignLoadRaw; typedef VipsForeignLoadClass VipsForeignLoadRawClass; G_DEFINE_TYPE(VipsForeignLoadRaw, vips_foreign_load_raw, VIPS_TYPE_FOREIGN_LOAD); static VipsForeignFlags vips_foreign_load_raw_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_raw_get_flags_filename(const char *filename) { return VIPS_FOREIGN_PARTIAL; } static int vips_foreign_load_raw_header(VipsForeignLoad *load) { VipsForeignLoadRaw *raw = (VipsForeignLoadRaw *) load; VipsImage *out; VipsImage *x; if (!(out = vips_image_new_from_file_raw(raw->filename, raw->width, raw->height, vips_format_sizeof_unsafe(raw->format) * raw->bands, raw->offset))) return -1; if (vips_copy(out, &x, "interpretation", raw->interpretation, "format", raw->format, "bands", raw->bands, NULL)) { g_object_unref(out); return -1; } g_object_unref(out); out = x; /* Remove the @out that's there now. */ g_object_get(load, "out", &x, NULL); g_object_unref(x); g_object_unref(x); g_object_set(load, "out", out, NULL); return 0; } static void vips_foreign_load_raw_class_init(VipsForeignLoadRawClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; /* You're unlikely to want to use this on untrusted files. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; object_class->nickname = "rawload"; object_class->description = _("load raw data from a file"); load_class->get_flags = vips_foreign_load_raw_get_flags; load_class->get_flags_filename = vips_foreign_load_raw_get_flags_filename; load_class->header = vips_foreign_load_raw_header; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, filename), NULL); VIPS_ARG_INT(class, "width", 20, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, width), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "height", 21, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, height), 0, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "bands", 22, _("Bands"), _("Number of bands in image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, bands), 0, VIPS_MAX_COORD, 0); VIPS_ARG_UINT64(class, "offset", 23, _("Size of header"), _("Offset in bytes from start of file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, offset), 0, 100000000000, 0); VIPS_ARG_ENUM(class, "format", 24, _("Format"), _("Pixel format in image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, format), VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR); VIPS_ARG_ENUM(class, "interpretation", 25, _("Interpretation"), _("Pixel interpretation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadRaw, interpretation), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND); } static void vips_foreign_load_raw_init(VipsForeignLoadRaw *raw) { raw->format = VIPS_FORMAT_UCHAR; raw->interpretation = VIPS_INTERPRETATION_MULTIBAND; } /** * vips_rawload: * @filename: file to load * @out: (out): output image * @width: width of image in pixels * @height: height of image in pixels * @bands: number of image bands * @...: `NULL`-terminated list of optional named arguments * * This operation mmaps the file, setting up @out so that access to that * image will read from the file. * * By default, it assumes uchar pixels. Use @format to select something else. * * The image will be tagged as [enum@Vips.Interpretation.MULTIBAND]. Use * @interpretation to select something else. * * Use [method@Image.byteswap] to reverse the byte ordering if necessary. * * ::: tip "Optional arguments" * * @offset: `guint64`, offset in bytes from start of file * * @format: [enum@BandFormat], set image format * * @interpretation: [enum@Interpretation], set image interpretation * * ::: seealso * [ctor@Image.new_from_file], [method@Image.copy], [method@Image.byteswap]. * * Returns: 0 on success, -1 on error. */ int vips_rawload(const char *filename, VipsImage **out, int width, int height, int bands, ...) { va_list ap; int result; va_start(ap, bands); result = vips_call_split("rawload", ap, filename, out, width, height, bands); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/rawsave.c000066400000000000000000000245461516303661500202200ustar00rootroot00000000000000/* save to raw * * Write raw image data to file. Useful when defining new formats... * * Jesper Friis * * 10/06/08 JF * - initial code based on im_vips2ppm() * 04/07/08 JF * - replaced FILE with plain file handlers for reducing * confusion about binary vs. non-binary file modes. * 4/2/10 * - gtkdoc * 15/12/11 * - rework as a class * - added save raw to filename * 21/04/24 akash-akya * - reworked based on ppmsave.c * - added save to target * - added save to buffer * - deprecate vips_rawsave_fd() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include typedef struct _VipsForeignSaveRaw { VipsForeignSave parent_object; VipsTarget *target; } VipsForeignSaveRaw; typedef VipsForeignSaveClass VipsForeignSaveRawClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveRaw, vips_foreign_save_raw, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_raw_dispose(GObject *gobject) { VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) gobject; VIPS_UNREF(raw->target); G_OBJECT_CLASS(vips_foreign_save_raw_parent_class)->dispose(gobject); } static int vips_foreign_save_raw_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) a; for (int y = 0; y < area->height; y++) if (vips_target_write(raw->target, VIPS_REGION_ADDR(region, area->left, area->top + y), VIPS_IMAGE_SIZEOF_PEL(region->im) * area->width)) return -1; return 0; } static int vips_foreign_save_raw_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) object; if (VIPS_OBJECT_CLASS(vips_foreign_save_raw_parent_class)->build(object)) return -1; if (vips_image_pio_input(save->in) || vips_sink_disc(save->in, vips_foreign_save_raw_block, raw)) return -1; if (vips_target_end(raw->target)) return -1; return 0; } static void vips_foreign_save_raw_class_init(VipsForeignSaveRawClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_raw_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "rawsave_base"; object_class->description = _("save image to raw"); object_class->build = vips_foreign_save_raw_build; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; } static void vips_foreign_save_raw_init(VipsForeignSaveRaw *raw) { } typedef struct _VipsForeignSaveRawFile { VipsForeignSaveRaw parent_object; char *filename; } VipsForeignSaveRawFile; typedef VipsForeignSaveRawClass VipsForeignSaveRawFileClass; G_DEFINE_TYPE(VipsForeignSaveRawFile, vips_foreign_save_raw_file, vips_foreign_save_raw_get_type()); static int vips_foreign_save_raw_file_build(VipsObject *object) { VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) object; VipsForeignSaveRawFile *file = (VipsForeignSaveRawFile *) object; if (file->filename && !(raw->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_raw_file_parent_class) ->build(object); } static const char *vips_foreign_save_raw_suffs[] = { ".raw", NULL }; static void vips_foreign_save_raw_file_class_init(VipsForeignSaveRawFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "rawsave"; object_class->description = _("save image to raw file"); object_class->build = vips_foreign_save_raw_file_build; foreign_class->suffs = vips_foreign_save_raw_suffs; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveRawFile, filename), NULL); } static void vips_foreign_save_raw_file_init(VipsForeignSaveRawFile *raw) { } typedef struct _VipsForeignSaveRawTarget { VipsForeignSaveRaw parent_object; VipsTarget *target; } VipsForeignSaveRawTarget; typedef VipsForeignSaveRawClass VipsForeignSaveRawTargetClass; G_DEFINE_TYPE(VipsForeignSaveRawTarget, vips_foreign_save_raw_target, vips_foreign_save_raw_get_type()); static int vips_foreign_save_raw_target_build(VipsObject *object) { VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) object; VipsForeignSaveRawTarget *target = (VipsForeignSaveRawTarget *) object; if (target->target) { raw->target = target->target; g_object_ref(raw->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_raw_target_parent_class) ->build(object); } static void vips_foreign_save_raw_target_class_init( VipsForeignSaveRawTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "rawsave_target"; object_class->description = _("write raw image to target"); object_class->build = vips_foreign_save_raw_target_build; foreign_class->suffs = vips_foreign_save_raw_suffs; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveRawTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_raw_target_init(VipsForeignSaveRawTarget *target) { } typedef struct _VipsForeignSaveRawBuffer { VipsForeignSaveRaw parent_object; VipsArea *buf; } VipsForeignSaveRawBuffer; typedef VipsForeignSaveRawClass VipsForeignSaveRawBufferClass; G_DEFINE_TYPE(VipsForeignSaveRawBuffer, vips_foreign_save_raw_buffer, vips_foreign_save_raw_get_type()); static int vips_foreign_save_raw_buffer_build(VipsObject *object) { VipsForeignSaveRaw *raw = (VipsForeignSaveRaw *) object; VipsForeignSaveRawBuffer *buffer = (VipsForeignSaveRawBuffer *) object; VipsBlob *blob; if (!(raw->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_raw_buffer_parent_class) ->build(object)) return -1; g_object_get(raw->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_raw_buffer_class_init(VipsForeignSaveRawBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "rawsave_buffer"; object_class->description = _("write raw image to buffer"); object_class->build = vips_foreign_save_raw_buffer_build; foreign_class->suffs = vips_foreign_save_raw_suffs; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveRawBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_raw_buffer_init(VipsForeignSaveRawBuffer *buffer) { } /** * vips_rawsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Writes the pixels in @in to the file @filename with no header or other * metadata. * * ::: seealso * [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_rawsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("rawsave", ap, in, filename); va_end(ap); return result; } /** * vips_rawsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.rawsave], but save to a memory buffer. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: seealso * [method@Image.rawsave], [method@Image.write_to_memory], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_rawsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("rawsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_rawsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.rawsave], but save to a target. * * ::: seealso * [method@Image.rawsave]. * * Returns: 0 on success, -1 on error. */ int vips_rawsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("rawsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/spngload.c000066400000000000000000000550571516303661500203600ustar00rootroot00000000000000/* load PNG with libspng * * 1/5/20 * - from pngload.c * 19/2/21 781545872 * - read out background, if we can * 29/8/21 joshuamsager * - add "unlimited" flag to png load * 3/2/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_SPNG #include typedef struct _VipsForeignLoadPng { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Remove DoS limits. */ gboolean unlimited; spng_ctx *ctx; struct spng_ihdr ihdr; enum spng_format fmt; int bands; VipsInterpretation interpretation; VipsBandFormat format; int y_pos; } VipsForeignLoadPng; typedef VipsForeignLoadClass VipsForeignLoadPngClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadPng, vips_foreign_load_png, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_png_dispose(GObject *gobject) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) gobject; VIPS_FREEF(spng_ctx_free, png->ctx); VIPS_UNREF(png->source); G_OBJECT_CLASS(vips_foreign_load_png_parent_class)->dispose(gobject); } static int vips_foreign_load_png_stream(spng_ctx *ctx, void *user, void *dest, size_t length) { VipsSource *source = VIPS_SOURCE(user); while (length > 0) { gint64 bytes_read; bytes_read = vips_source_read(source, dest, length); if (bytes_read < 0) return SPNG_IO_ERROR; if (bytes_read == 0) return SPNG_IO_EOF; dest = (char *) dest + bytes_read; length -= bytes_read; } return 0; } static VipsForeignFlags vips_foreign_load_png_get_flags_source(VipsSource *source) { spng_ctx *ctx; struct spng_ihdr ihdr; VipsForeignFlags flags; ctx = spng_ctx_new(SPNG_CTX_IGNORE_ADLER32); spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE); if (vips_source_rewind(source)) return 0; spng_set_png_stream(ctx, vips_foreign_load_png_stream, source); if (spng_get_ihdr(ctx, &ihdr)) { spng_ctx_free(ctx); return 0; } spng_ctx_free(ctx); flags = 0; if (ihdr.interlace_method != SPNG_INTERLACE_NONE) flags |= VIPS_FOREIGN_PARTIAL; else flags |= VIPS_FOREIGN_SEQUENTIAL; return flags; } static VipsForeignFlags vips_foreign_load_png_get_flags(VipsForeignLoad *load) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; return vips_foreign_load_png_get_flags_source(png->source); } static VipsForeignFlags vips_foreign_load_png_get_flags_filename(const char *filename) { VipsSource *source; VipsForeignFlags flags; if (!(source = vips_source_new_from_file(filename))) return 0; flags = vips_foreign_load_png_get_flags_source(source); VIPS_UNREF(source); return flags; } /* Set the png text data as metadata on the vips image. These are always * null-terminated strings. */ static void vips_foreign_load_png_set_text(VipsImage *out, int i, const char *key, const char *value) { #ifdef DEBUG printf("vips_foreign_load_png_set_text: key %s, value %s\n", key, value); #endif /*DEBUG*/ if (strcmp(key, "XML:com.adobe.xmp") == 0) { /* Save as an XMP tag. This must be a BLOB, for compatibility * for things like the XMP blob that the tiff loader adds. * * Note that this will remove the null-termination from the * string. We must carefully reattach this. */ vips_image_set_blob_copy(out, VIPS_META_XMP_NAME, value, strlen(value)); } else { char name[256]; /* Save as a string comment. Some PNGs have EXIF data as * text segments, unfortunately. */ g_snprintf(name, 256, "png-comment-%d-%s", i, key); vips_image_set_string(out, name, value); } } static int vips_foreign_load_png_set_header(VipsForeignLoadPng *png, VipsImage *image) { double xres, yres; struct spng_iccp iccp; struct spng_exif exif; struct spng_phys phys; struct spng_bkgd bkgd; guint32 n_text; /* Get resolution. Default to 72 pixels per inch. */ xres = 72.0 / 25.4; yres = 72.0 / 25.4; if (!spng_get_phys(png->ctx, &phys)) { /* unit 1 means pixels per metre, otherwise unspecified. */ xres = phys.unit_specifier == 1 ? phys.ppu_x / 1000.0 : phys.ppu_x; yres = phys.unit_specifier == 1 ? phys.ppu_y / 1000.0 : phys.ppu_y; } vips_image_init_fields(image, png->ihdr.width, png->ihdr.height, png->bands, png->format, VIPS_CODING_NONE, png->interpretation, xres, yres); VIPS_SETSTR(image->filename, vips_connection_filename(VIPS_CONNECTION(png->source))); if (vips_image_pipelinev(image, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; if (!spng_get_iccp(png->ctx, &iccp)) vips_image_set_blob_copy(image, VIPS_META_ICC_NAME, iccp.profile, iccp.profile_len); if (!spng_get_text(png->ctx, NULL, &n_text)) { struct spng_text *text; /* Very large numbers of text chunks are used in DoS * attacks. */ if (!png->unlimited && n_text > MAX_PNG_TEXT_CHUNKS) { g_warning("%d text chunks, only %d text chunks will be loaded", n_text, MAX_PNG_TEXT_CHUNKS); n_text = MAX_PNG_TEXT_CHUNKS; } text = VIPS_ARRAY(VIPS_OBJECT(png), n_text, struct spng_text); if (!spng_get_text(png->ctx, text, &n_text)) { guint32 i; for (i = 0; i < n_text; i++) /* .text is always a null-terminated C string. */ vips_foreign_load_png_set_text(image, i, text[i].keyword, text[i].text); } } if (!spng_get_exif(png->ctx, &exif)) vips_image_set_blob_copy(image, VIPS_META_EXIF_NAME, exif.data, exif.length); vips_image_set_int(image, VIPS_META_BITS_PER_SAMPLE, png->ihdr.bit_depth); if (png->ihdr.color_type == SPNG_COLOR_TYPE_INDEXED) { /* Deprecated "palette-bit-depth" use "bits-per-sample" instead. */ vips_image_set_int(image, "palette-bit-depth", png->ihdr.bit_depth); vips_image_set_int(image, VIPS_META_PALETTE, 1); } /* Let our caller know. These are very expensive to decode. */ if (png->ihdr.interlace_method != SPNG_INTERLACE_NONE) vips_image_set_int(image, "interlaced", 1); if (!spng_get_bkgd(png->ctx, &bkgd)) { const int scale = image->BandFmt == VIPS_FORMAT_UCHAR ? 1 : 256; double array[3]; int n; switch (png->ihdr.color_type) { case SPNG_COLOR_TYPE_GRAYSCALE: case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA: array[0] = bkgd.gray / scale; n = 1; break; case SPNG_COLOR_TYPE_TRUECOLOR: case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA: array[0] = bkgd.red / scale; array[1] = bkgd.green / scale; array[2] = bkgd.blue / scale; n = 3; break; case SPNG_COLOR_TYPE_INDEXED: default: /* Not sure what to do here. I suppose we should read * the palette. */ n = 0; break; } if (n > 0) vips_image_set_array_double(image, "background", array, n); } return 0; } static int vips_foreign_load_png_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; int flags; int error; struct spng_trns trns; /* In non-fail mode, ignore CRC errors. */ flags = 0; if (load->fail_on < VIPS_FAIL_ON_ERROR) flags |= SPNG_CTX_IGNORE_ADLER32; png->ctx = spng_ctx_new(flags); if (load->fail_on < VIPS_FAIL_ON_ERROR) /* Ignore and don't calculate checksums. */ spng_set_crc_action(png->ctx, SPNG_CRC_USE, SPNG_CRC_USE); /* Set limits to avoid decompression bombs. Set chunk limits to 60mb * -- we've seen 50mb XMP blocks in the wild. * * No need to test the decoded image size -- the user can do that if * they wish. */ if (!png->unlimited) { spng_set_image_limits(png->ctx, VIPS_MAX_COORD, VIPS_MAX_COORD); spng_set_chunk_limits(png->ctx, 60 * 1024 * 1024, 60 * 1024 * 1024); } if (vips_source_rewind(png->source)) return -1; spng_set_png_stream(png->ctx, vips_foreign_load_png_stream, png->source); if ((error = spng_get_ihdr(png->ctx, &png->ihdr))) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } #ifdef DEBUG printf("width: %d\nheight: %d\nbit depth: %d\ncolor type: %d\n", png->ihdr.width, png->ihdr.height, png->ihdr.bit_depth, png->ihdr.color_type); printf("compression method: %d\nfilter method: %d\n" "interlace method: %d\n", png->ihdr.compression_method, png->ihdr.filter_method, png->ihdr.interlace_method); #endif /*DEBUG*/ /* Just convert to host-endian if nothing else applies. */ png->fmt = SPNG_FMT_PNG; switch (png->ihdr.color_type) { case SPNG_COLOR_TYPE_INDEXED: png->bands = 3; break; case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA: case SPNG_COLOR_TYPE_GRAYSCALE: png->bands = 1; break; case SPNG_COLOR_TYPE_TRUECOLOR: case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA: png->bands = 3; break; default: vips_error(class->nickname, "%s", _("unknown color type")); return -1; } /* Set libvips format and interpretation. */ if (png->ihdr.bit_depth > 8) { if (png->bands < 3) png->interpretation = VIPS_INTERPRETATION_GREY16; else png->interpretation = VIPS_INTERPRETATION_RGB16; png->format = VIPS_FORMAT_USHORT; } else { if (png->bands < 3) png->interpretation = VIPS_INTERPRETATION_B_W; else png->interpretation = VIPS_INTERPRETATION_sRGB; png->format = VIPS_FORMAT_UCHAR; } /* Expand palette images. */ if (png->ihdr.color_type == SPNG_COLOR_TYPE_INDEXED) png->fmt = SPNG_FMT_RGB8; /* Expand <8 bit images to full bytes. */ if (png->ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE && png->ihdr.bit_depth < 8) png->fmt = SPNG_FMT_G8; /* Try reading the optional transparency chunk. This will cause all * chunks up to the first IDAT to be read in, so it can fail if any * chunk has an error. */ error = spng_get_trns(png->ctx, &trns); if (error && error != SPNG_ECHUNKAVAIL) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } /* Expand transparency. * * The _ALPHA types should not have the optional trns chunk (they * always have a transparent band), see * https://www.w3.org/TR/2003/REC-PNG-20031110/#11tRNS * * It's quick and safe to call spng_get_trns() again, and we now know * it will only fail for no transparency chunk. */ if (png->ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA || png->ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA) png->bands += 1; else if (!spng_get_trns(png->ctx, &trns)) { png->bands += 1; if (png->ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR) { if (png->ihdr.bit_depth == 16) png->fmt = SPNG_FMT_RGBA16; else png->fmt = SPNG_FMT_RGBA8; } else if (png->ihdr.color_type == SPNG_COLOR_TYPE_INDEXED) png->fmt = SPNG_FMT_RGBA8; else if (png->ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE) { if (png->ihdr.bit_depth == 16) png->fmt = SPNG_FMT_GA16; else png->fmt = SPNG_FMT_GA8; } } vips_source_minimise(png->source); if (vips_foreign_load_png_set_header(png, load->out)) return -1; return 0; } static void vips_foreign_load_png_minimise(VipsObject *object, VipsForeignLoadPng *png) { vips_source_minimise(png->source); } static int vips_foreign_load_png_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsForeignLoad *load = VIPS_FOREIGN_LOAD(a); VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(png); int y; int error; #ifdef DEBUG printf("vips_foreign_load_png_generate: line %d, %d rows\n", r->top, r->height); printf("vips_foreign_load_png_generate: y_top = %d\n", png->y_pos); #endif /*DEBUG*/ /* We're inside a tilecache where tiles are the full image width, so * this should always be true. */ g_assert(r->left == 0); g_assert(r->width == out_region->im->Xsize); g_assert(VIPS_RECT_BOTTOM(r) <= out_region->im->Ysize); /* Tiles should always be a strip in height, unless it's the final * strip. */ g_assert(r->height == VIPS_MIN(VIPS__FATSTRIP_HEIGHT, out_region->im->Ysize - r->top)); /* And check that y_pos is correct. It should be, since we are inside * a vips_sequential(). */ if (r->top != png->y_pos) { vips_error(class->nickname, _("out of order read at line %d"), png->y_pos); return -1; } for (y = 0; y < r->height; y++) { /* libspng returns EOI when successfully reading the * final line of input. */ error = spng_decode_row(png->ctx, VIPS_REGION_ADDR(out_region, 0, r->top + y), VIPS_REGION_SIZEOF_LINE(out_region)); if (error != 0 && error != SPNG_EOI) { /* We've failed to read some pixels. Knock this * operation out of cache. */ vips_operation_invalidate(VIPS_OPERATION(png)); #ifdef DEBUG printf("vips_foreign_load_png_generate:\n"); printf(" spng_decode_row() failed, line %d\n", r->top + y); printf(" thread %p\n", g_thread_self()); printf(" error %s\n", spng_strerror(error)); #endif /*DEBUG*/ g_warning("%s: %s", class->nickname, spng_strerror(error)); /* And bail if trunc is on. */ if (load->fail_on >= VIPS_FAIL_ON_TRUNCATED) { vips_error(class->nickname, "%s", _("libspng read error")); return -1; } } png->y_pos += 1; } return 0; } static int vips_foreign_load_png_load(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadPng *png = (VipsForeignLoadPng *) load; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(load), 3); enum spng_decode_flags flags; int error; if (vips_source_decode(png->source)) return -1; /* Decode transparency, if available. */ flags = SPNG_DECODE_TRNS; if (png->ihdr.interlace_method != SPNG_INTERLACE_NONE) { /* Arg awful interlaced image. We have to load to a huge mem * buffer, then copy to out. */ t[0] = vips_image_new_memory(); if (vips_foreign_load_png_set_header(png, t[0]) || vips_image_write_prepare(t[0])) return -1; if ((error = spng_decode_image(png->ctx, VIPS_IMAGE_ADDR(t[0], 0, 0), VIPS_IMAGE_SIZEOF_IMAGE(t[0]), png->fmt, flags))) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } /* We've now finished reading the file. */ vips_source_minimise(png->source); if (vips_image_write(t[0], load->real)) return -1; } else { t[0] = vips_image_new(); if (vips_foreign_load_png_set_header(png, t[0])) return -1; /* We can decode these progressively. */ flags |= SPNG_DECODE_PROGRESSIVE; if ((error = spng_decode_image(png->ctx, NULL, 0, png->fmt, flags))) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } /* Close input immediately at end of read. */ g_signal_connect(t[0], "minimise", G_CALLBACK(vips_foreign_load_png_minimise), png); if (vips_image_generate(t[0], NULL, vips_foreign_load_png_generate, NULL, png, NULL) || vips_sequential(t[0], &t[1], "tile_height", VIPS__FATSTRIP_HEIGHT, NULL) || vips_image_write(t[1], load->real)) return -1; } return 0; } static void vips_foreign_load_png_class_init(VipsForeignLoadPngClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_png_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload_base"; object_class->description = _("load png base class"); /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; load_class->get_flags_filename = vips_foreign_load_png_get_flags_filename; load_class->get_flags = vips_foreign_load_png_get_flags; load_class->header = vips_foreign_load_png_header; load_class->load = vips_foreign_load_png_load; #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VIPS_ARG_BOOL(class, "unlimited", 23, _("Unlimited"), _("Remove all denial of service limits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPng, unlimited), FALSE); #endif } static void vips_foreign_load_png_init(VipsForeignLoadPng *png) { } typedef struct _VipsForeignLoadPngSource { VipsForeignLoadPng parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadPngSource; typedef VipsForeignLoadPngClass VipsForeignLoadPngSourceClass; G_DEFINE_TYPE(VipsForeignLoadPngSource, vips_foreign_load_png_source, vips_foreign_load_png_get_type()); static int vips_foreign_load_png_source_build(VipsObject *object) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) object; VipsForeignLoadPngSource *source = (VipsForeignLoadPngSource *) object; if (source->source) { png->source = source->source; g_object_ref(png->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_png_source_parent_class) ->build(object); } static gboolean vips_foreign_load_png_source_is_a_source(VipsSource *source) { static unsigned char signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; const unsigned char *p; if ((p = vips_source_sniff(source, 8)) && memcmp(p, signature, 8) == 0) return TRUE; return FALSE; } static void vips_foreign_load_png_source_class_init(VipsForeignLoadPngSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload_source"; object_class->description = _("load png from source"); object_class->build = vips_foreign_load_png_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_png_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPngSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_png_source_init(VipsForeignLoadPngSource *source) { } typedef struct _VipsForeignLoadPngFile { VipsForeignLoadPng parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadPngFile; typedef VipsForeignLoadPngClass VipsForeignLoadPngFileClass; G_DEFINE_TYPE(VipsForeignLoadPngFile, vips_foreign_load_png_file, vips_foreign_load_png_get_type()); static int vips_foreign_load_png_file_build(VipsObject *object) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) object; VipsForeignLoadPngFile *file = (VipsForeignLoadPngFile *) object; if (file->filename && !(png->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_png_file_parent_class) ->build(object); } static gboolean vips_foreign_load_png_file_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_png_source_is_a_source(source); VIPS_UNREF(source); return result; } const char *vips_foreign_load_png_file_suffs[] = { ".png", NULL }; static void vips_foreign_load_png_file_class_init(VipsForeignLoadPngFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload"; object_class->description = _("load png from file"); object_class->build = vips_foreign_load_png_file_build; foreign_class->suffs = vips_foreign_load_png_file_suffs; load_class->is_a = vips_foreign_load_png_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPngFile, filename), NULL); } static void vips_foreign_load_png_file_init(VipsForeignLoadPngFile *file) { } typedef struct _VipsForeignLoadPngBuffer { VipsForeignLoadPng parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadPngBuffer; typedef VipsForeignLoadPngClass VipsForeignLoadPngBufferClass; G_DEFINE_TYPE(VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer, vips_foreign_load_png_get_type()); static int vips_foreign_load_png_buffer_build(VipsObject *object) { VipsForeignLoadPng *png = (VipsForeignLoadPng *) object; VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) object; if (buffer->blob && !(png->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_png_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_png_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_png_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_png_buffer_class_init(VipsForeignLoadPngBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngload_buffer"; object_class->description = _("load png from buffer"); object_class->build = vips_foreign_load_png_buffer_build; load_class->is_a_buffer = vips_foreign_load_png_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadPngBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_png_buffer_init(VipsForeignLoadPngBuffer *buffer) { } #endif /*HAVE_SPNG*/ libvips-8.18.2/libvips/foreign/spngsave.c000066400000000000000000000540461516303661500203740ustar00rootroot00000000000000/* save to spng * * 2/12/11 * - wrap a class around the spng writer * 16/7/12 * - compression should be 0-9, not 1-10 * 20/6/18 [felixbuenemann] * - support spng8 palette write with palette, colours, Q, dither * 24/6/20 * - add @bitdepth, deprecate @colours * 11/11/21 * - use libspng for save * 15/7/22 [lovell] * - default filter to none * 17/11/22 * - add exif save */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #include "quantise.h" #ifdef HAVE_SPNG #include typedef struct _VipsForeignSaveSpng { VipsForeignSave parent_object; int compression; gboolean interlace; VipsForeignPngFilter filter; gboolean palette; int Q; double dither; int bitdepth; int effort; /* Set by subclasses. */ VipsTarget *target; /* Write state. */ spng_ctx *ctx; GSList *text_chunks; VipsImage *memory; size_t sizeof_line; VipsPel *line; /* Deprecated. */ int colours; } VipsForeignSaveSpng; typedef VipsForeignSaveClass VipsForeignSaveSpngClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveSpng, vips_foreign_save_spng, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_spng_dispose(GObject *gobject) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) gobject; GSList *p; VIPS_UNREF(spng->target); VIPS_UNREF(spng->memory); VIPS_FREEF(spng_ctx_free, spng->ctx); for (p = spng->text_chunks; p; p = p->next) { struct spng_text *text = (struct spng_text *) p->data; VIPS_FREE(text->text); VIPS_FREE(text); } VIPS_FREEF(g_slist_free, spng->text_chunks); VIPS_FREE(spng->line); G_OBJECT_CLASS(vips_foreign_save_spng_parent_class)->dispose(gobject); } static int vips_foreign_save_spng_text(VipsForeignSaveSpng *spng, const char *keyword, const char *value) { struct spng_text *text = VIPS_NEW(NULL, struct spng_text); g_strlcpy(text->keyword, keyword, sizeof(text->keyword)); /* FIXME ... is this right? */ text->type = SPNG_TEXT; text->length = strlen(value); text->text = g_strdup(value); spng->text_chunks = g_slist_prepend(spng->text_chunks, text); return 0; } static void * vips_foreign_save_spng_comment(VipsImage *image, const char *field, GValue *value, void *user_data) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) user_data; if (vips_isprefix("png-comment-", field)) { const char *value; int i; char key[256]; if (vips_image_get_string(image, field, &value)) return image; if (strlen(field) > 256 || sscanf(field, "png-comment-%d-%80s", &i, key) != 2) { vips_error("vips2png", "%s", _("bad png comment key")); return image; } vips_foreign_save_spng_text(spng, key, value); } return NULL; } static int vips_foreign_save_spng_profile(VipsForeignSaveSpng *spng, VipsImage *in) { VipsForeignSave *save = (VipsForeignSave *) spng; struct spng_iccp iccp; /* A profile supplied as an argument overrides an embedded * profile. */ if (save->profile) { VipsBlob *blob; if (vips_profile_load(save->profile, &blob, NULL)) return -1; if (blob) { size_t length; const void *data = vips_blob_get(blob, &length); char *basename = g_path_get_basename(save->profile); #ifdef DEBUG printf("write_vips: attaching %zd bytes of ICC profile\n", length); #endif /*DEBUG*/ g_strlcpy(iccp.profile_name, basename, sizeof(iccp.profile_name)); iccp.profile_len = length; iccp.profile = (void *) data; spng_set_iccp(spng->ctx, &iccp); vips_area_unref((VipsArea *) blob); g_free(basename); } } else if (vips_image_get_typeof(in, VIPS_META_ICC_NAME)) { const void *data; size_t length; if (vips_image_get_blob(in, VIPS_META_ICC_NAME, &data, &length)) return -1; #ifdef DEBUG printf("write_vips: attaching %zd bytes of ICC profile\n", length); #endif /*DEBUG*/ g_strlcpy(iccp.profile_name, "icc", sizeof(iccp.profile_name)); iccp.profile_len = length; iccp.profile = (void *) data; spng_set_iccp(spng->ctx, &iccp); } return 0; } static int vips_foreign_save_spng_metadata(VipsForeignSaveSpng *spng, VipsImage *in) { uint32_t n_text; struct spng_text *text_chunk_array; struct spng_exif exif; int i; GSList *p; if (vips_image_get_typeof(in, VIPS_META_XMP_NAME)) { const void *data; size_t length; char *str; if (vips_image_get_blob(in, VIPS_META_XMP_NAME, &data, &length)) return -1; /* The blob form of the XMP metadata is missing the * terminating \0 bytes, we have to paste it back, * unfortunately. See pngload. */ str = g_malloc(length + 1); g_strlcpy(str, data, length + 1); vips_foreign_save_spng_text(spng, "XML:com.adobe.xmp", str); g_free(str); } if (vips_image_get_typeof(in, VIPS_META_EXIF_NAME)) { if (vips_image_get_blob(in, VIPS_META_EXIF_NAME, (const void **) &exif.data, &exif.length)) return -1; /* libspng does not want the JFIF "Exif\0\0" prefix. */ if (exif.length >= 6 && vips_isprefix("Exif", exif.data)) { exif.data += 6; exif.length -= 6; } spng_set_exif(spng->ctx, &exif); } if (vips_image_map(in, vips_foreign_save_spng_comment, spng)) return -1; n_text = g_slist_length(spng->text_chunks); text_chunk_array = VIPS_ARRAY(NULL, n_text, struct spng_text); for (i = 0, p = spng->text_chunks; p; p = p->next, i++) { struct spng_text *text = (struct spng_text *) p->data; text_chunk_array[i] = *text; } #ifdef DEBUG printf("attaching %u text items\n", n_text); #endif /*DEBUG*/ spng_set_text(spng->ctx, text_chunk_array, n_text); VIPS_FREE(text_chunk_array); return 0; } /* Pack a line of 1/2/4 bit index values. */ static void vips_foreign_save_spng_pack(VipsForeignSaveSpng *spng, VipsPel *q, VipsPel *p, size_t n) { int pixel_mask = 8 / spng->bitdepth - 1; int shift = spng->palette ? 0 : 8 - spng->bitdepth; VipsPel bits; size_t x; bits = 0; for (x = 0; x < n; x++) { bits <<= spng->bitdepth; bits |= p[x] >> shift; if ((x & pixel_mask) == pixel_mask) *q++ = bits; } /* Any left-over bits? Need to be left-aligned. */ if ((x & pixel_mask) != 0) { /* The number of bits we've collected and must * left-align and flush. */ int collected_bits = (x & pixel_mask) << (spng->bitdepth - 1); *q++ = bits << (8 - collected_bits); } } static int vips_foreign_save_spng_write_fn(spng_ctx *ctx, void *user, void *data, size_t n) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) user; if (vips_target_write(spng->target, data, n)) return SPNG_IO_ERROR; return 0; } static int vips_foreign_save_spng_write_block(VipsRegion *region, VipsRect *area, void *user) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) user; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(spng); int y; int error; /* The area to write is always a set of complete scanlines. */ g_assert(area->left == 0); g_assert(area->width == region->im->Xsize); g_assert(area->top + area->height <= region->im->Ysize); for (y = 0; y < area->height; y++) { VipsPel *line; size_t sizeof_line; line = VIPS_REGION_ADDR(region, 0, area->top + y); sizeof_line = VIPS_REGION_SIZEOF_LINE(region); if (spng->bitdepth < 8) { vips_foreign_save_spng_pack(spng, spng->line, line, sizeof_line); line = spng->line; sizeof_line = spng->sizeof_line; } if ((error = spng_encode_row(spng->ctx, line, sizeof_line))) break; } /* You can get SPNG_EOI for the final scanline. */ if (error && error != SPNG_EOI) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } return 0; } static int vips_foreign_save_spng_write(VipsForeignSaveSpng *spng, VipsImage *in) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(spng); int error; struct spng_ihdr ihdr; struct spng_phys phys; int fmt; enum spng_encode_flags encode_flags; spng->ctx = spng_ctx_new(SPNG_CTX_ENCODER); if ((error = spng_set_png_stream(spng->ctx, vips_foreign_save_spng_write_fn, spng))) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } ihdr.width = in->Xsize; ihdr.height = in->Ysize; ihdr.bit_depth = spng->bitdepth; switch (in->Bands) { case 1: ihdr.color_type = SPNG_COLOR_TYPE_GRAYSCALE; break; case 2: ihdr.color_type = SPNG_COLOR_TYPE_GRAYSCALE_ALPHA; break; case 3: ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR; break; case 4: ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA; break; default: vips_error(class->nickname, "%s", _("bad bands")); return -1; } #ifdef HAVE_QUANTIZATION /* Enable image quantisation to paletted 8bpp PNG if palette is set. */ if (spng->palette) ihdr.color_type = SPNG_COLOR_TYPE_INDEXED; #else if (spng->palette) g_warning("ignoring palette (no quantisation support)"); #endif /*HAVE_QUANTIZATION*/ ihdr.compression_method = 0; ihdr.filter_method = 0; ihdr.interlace_method = spng->interlace ? 1 : 0; if ((error = spng_set_ihdr(spng->ctx, &ihdr))) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } spng_set_option(spng->ctx, SPNG_IMG_COMPRESSION_LEVEL, spng->compression); spng_set_option(spng->ctx, SPNG_TEXT_COMPRESSION_LEVEL, spng->compression); spng_set_option(spng->ctx, SPNG_FILTER_CHOICE, spng->filter); /* Set resolution. spng uses pixels per meter. */ phys.unit_specifier = 1; phys.ppu_x = rint(in->Xres * 1000.0); phys.ppu_y = rint(in->Xres * 1000.0); spng_set_phys(spng->ctx, &phys); /* Metadata. */ if (vips_foreign_save_spng_profile(spng, in) || vips_foreign_save_spng_metadata(spng, in)) return -1; #ifdef HAVE_QUANTIZATION if (spng->palette) { struct spng_plte plte = { 0 }; struct spng_trns trns = { 0 }; VipsImage *im_index; VipsImage *im_palette; int palette_count; int i; if (vips__quantise_image(in, &im_index, &im_palette, 1 << spng->bitdepth, spng->Q, spng->dither, spng->effort, FALSE)) return -1; /* PNG is 8-bit index only. */ palette_count = im_palette->Xsize; g_assert(palette_count <= 256); for (i = 0; i < palette_count; i++) { VipsPel *p = (VipsPel *) VIPS_IMAGE_ADDR(im_palette, i, 0); struct spng_plte_entry *entry = &plte.entries[plte.n_entries]; entry->red = p[0]; entry->green = p[1]; entry->blue = p[2]; plte.n_entries += 1; trns.type3_alpha[i] = p[3]; if (p[3] != 255) { trns.n_type3_entries = i + 1; } } #ifdef DEBUG printf("attaching %d entry palette\n", plte.n_entries); if (trns.n_type3_entries) printf("attaching %d transparency values\n", trns.n_type3_entries); #endif /*DEBUG*/ VIPS_UNREF(im_palette); spng_set_plte(spng->ctx, &plte); if (trns.n_type3_entries) spng_set_trns(spng->ctx, &trns); in = spng->memory = im_index; } #endif /*HAVE_QUANTIZATION*/ /* Low-bitdepth write needs an extra buffer for packing pixels. */ if (spng->bitdepth < 8) { spng->sizeof_line = 1 + VIPS_IMAGE_SIZEOF_LINE(in) / (8 / spng->bitdepth); if (!(spng->line = vips_malloc(NULL, VIPS_IMAGE_SIZEOF_LINE(in)))) return -1; } /* SPNG_FMT_PNG is a special value that matches the format in ihdr */ fmt = SPNG_FMT_PNG; encode_flags = SPNG_ENCODE_PROGRESSIVE | SPNG_ENCODE_FINALIZE; if ((error = spng_encode_image(spng->ctx, NULL, -1, fmt, encode_flags))) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } if (spng->interlace) { /* Force the input into memory, if it's not there already. */ if (!spng->memory) { if (!(spng->memory = vips_image_copy_memory(in))) return -1; in = spng->memory; } do { struct spng_row_info row_info; VipsPel *line; size_t sizeof_line; if ((error = spng_get_row_info(spng->ctx, &row_info))) break; line = VIPS_IMAGE_ADDR(in, 0, row_info.row_num); sizeof_line = VIPS_IMAGE_SIZEOF_LINE(in); if (spng->bitdepth < 8) { vips_foreign_save_spng_pack(spng, spng->line, line, sizeof_line); line = spng->line; sizeof_line = spng->sizeof_line; } error = spng_encode_row(spng->ctx, line, sizeof_line); } while (!error); if (error != SPNG_EOI) { vips_error(class->nickname, "%s", spng_strerror(error)); return -1; } } else { if (vips_sink_disc(in, vips_foreign_save_spng_write_block, spng)) return -1; } if (vips_target_end(spng->target)) return -1; return 0; } static int vips_foreign_save_spng_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) object; VipsImage *in; VipsImage *x; if (VIPS_OBJECT_CLASS(vips_foreign_save_spng_parent_class)->build(object)) return -1; in = save->ready; g_object_ref(in); /* If no output bitdepth has been specified, use input Type to pick. */ if (!vips_object_argument_isset(object, "bitdepth")) spng->bitdepth = in->Type == VIPS_INTERPRETATION_RGB16 || in->Type == VIPS_INTERPRETATION_GREY16 ? 16 : 8; /* Deprecated "colours" arg just sets bitdepth large enough to hold * that many colours. */ if (vips_object_argument_isset(object, "colours")) spng->bitdepth = ceil(log2(spng->colours)); /* The bitdepth param can change the interpretation. */ VipsInterpretation interpretation; if (in->Bands > 2) { if (spng->bitdepth > 8) interpretation = VIPS_INTERPRETATION_RGB16; else interpretation = VIPS_INTERPRETATION_sRGB; } else { if (spng->bitdepth > 8) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_B_W; } if (vips_colourspace(in, &x, interpretation, NULL)) { g_object_unref(in); return -1; } g_object_unref(in); in = x; /* If this is a RGB or RGBA image and a low bit depth has been * requested, enable palettisation. */ if (in->Bands > 2 && spng->bitdepth < 8) spng->palette = TRUE; /* Disable palettization for >8 bit save. */ if (spng->bitdepth > 8) spng->palette = FALSE; if (vips_foreign_save_spng_write(spng, in)) { g_object_unref(in); return -1; } g_object_unref(in); return 0; } #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT /* Except for 8-bit inputs, we send everything else to 16. We decide on png8 * vs. png16 based on Type in_build(), see above. */ static VipsBandFormat bandfmt_spng[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, US, US, US, US, US, US }; static void vips_foreign_save_spng_class_init(VipsForeignSaveSpngClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_spng_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "spngsave_base"; object_class->description = _("save spng"); object_class->build = vips_foreign_save_spng_build; foreign_class->suffs = vips__png_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA; save_class->format_table = bandfmt_spng; VIPS_ARG_INT(class, "compression", 6, _("Compression"), _("Compression factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, compression), 0, 9, 6); VIPS_ARG_BOOL(class, "interlace", 7, _("Interlace"), _("Interlace image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, interlace), FALSE); VIPS_ARG_FLAGS(class, "filter", 12, _("Filter"), _("libspng row filter flag(s)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, filter), VIPS_TYPE_FOREIGN_PNG_FILTER, VIPS_FOREIGN_PNG_FILTER_NONE); VIPS_ARG_BOOL(class, "palette", 13, _("Palette"), _("Quantise to 8bpp palette"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, palette), FALSE); VIPS_ARG_INT(class, "Q", 15, _("Quality"), _("Quantisation quality"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, Q), 0, 100, 100); VIPS_ARG_DOUBLE(class, "dither", 16, _("Dithering"), _("Amount of dithering"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, dither), 0.0, 1.0, 1.0); VIPS_ARG_INT(class, "bitdepth", 17, _("Bit depth"), _("Write as a 1, 2, 4, 8 or 16 bit image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, bitdepth), 1, 16, 8); VIPS_ARG_INT(class, "effort", 18, _("Effort"), _("Quantisation CPU effort"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpng, effort), 1, 10, 7); VIPS_ARG_INT(class, "colours", 14, _("Colours"), _("Max number of palette colours"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveSpng, colours), 2, 256, 256); } static void vips_foreign_save_spng_init(VipsForeignSaveSpng *spng) { spng->compression = 6; spng->filter = VIPS_FOREIGN_PNG_FILTER_NONE; spng->Q = 100; spng->dither = 1.0; spng->effort = 7; } typedef struct _VipsForeignSaveSpngTarget { VipsForeignSaveSpng parent_object; VipsTarget *target; } VipsForeignSaveSpngTarget; typedef VipsForeignSaveSpngClass VipsForeignSaveSpngTargetClass; G_DEFINE_TYPE(VipsForeignSaveSpngTarget, vips_foreign_save_spng_target, vips_foreign_save_spng_get_type()); static int vips_foreign_save_spng_target_build(VipsObject *object) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) object; VipsForeignSaveSpngTarget *target = (VipsForeignSaveSpngTarget *) object; spng->target = target->target; g_object_ref(spng->target); return VIPS_OBJECT_CLASS(vips_foreign_save_spng_target_parent_class) ->build(object); } static void vips_foreign_save_spng_target_class_init(VipsForeignSaveSpngTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave_target"; object_class->description = _("save image to target as PNG"); object_class->build = vips_foreign_save_spng_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpngTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_spng_target_init(VipsForeignSaveSpngTarget *target) { } typedef struct _VipsForeignSaveSpngFile { VipsForeignSaveSpng parent_object; char *filename; } VipsForeignSaveSpngFile; typedef VipsForeignSaveSpngClass VipsForeignSaveSpngFileClass; G_DEFINE_TYPE(VipsForeignSaveSpngFile, vips_foreign_save_spng_file, vips_foreign_save_spng_get_type()); static int vips_foreign_save_spng_file_build(VipsObject *object) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) object; VipsForeignSaveSpngFile *file = (VipsForeignSaveSpngFile *) object; if (!(spng->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_spng_file_parent_class) ->build(object); } static void vips_foreign_save_spng_file_class_init(VipsForeignSaveSpngFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave"; object_class->description = _("save image to file as PNG"); object_class->build = vips_foreign_save_spng_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveSpngFile, filename), NULL); } static void vips_foreign_save_spng_file_init(VipsForeignSaveSpngFile *file) { } typedef struct _VipsForeignSaveSpngBuffer { VipsForeignSaveSpng parent_object; VipsArea *buf; } VipsForeignSaveSpngBuffer; typedef VipsForeignSaveSpngClass VipsForeignSaveSpngBufferClass; G_DEFINE_TYPE(VipsForeignSaveSpngBuffer, vips_foreign_save_spng_buffer, vips_foreign_save_spng_get_type()); static int vips_foreign_save_spng_buffer_build(VipsObject *object) { VipsForeignSaveSpng *spng = (VipsForeignSaveSpng *) object; VipsForeignSaveSpngBuffer *buffer = (VipsForeignSaveSpngBuffer *) object; VipsBlob *blob; if (!(spng->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_spng_buffer_parent_class) ->build(object)) return -1; g_object_get(spng->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_spng_buffer_class_init(VipsForeignSaveSpngBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "pngsave_buffer"; object_class->description = _("save image to buffer as PNG"); object_class->build = vips_foreign_save_spng_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveSpngBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_spng_buffer_init(VipsForeignSaveSpngBuffer *buffer) { } #endif /*HAVE_SPNG*/ libvips-8.18.2/libvips/foreign/svgload.c000066400000000000000000000760051516303661500202040ustar00rootroot00000000000000/* load SVG with librsvg * * 7/2/16 * - from svgload.c * 1/8/16 felixbuenemann * - add svgz support * 18/1/17 * - invalidate operation on read error * 8/7/17 * - fix DPI mixup, thanks Fosk * 9/9/17 * - limit max tile width to 30k pixels to prevent overflow in render * 17/9/17 lovell * - handle scaling of svg files missing width and height attributes * 22/3/18 lovell * - svgload was missing is_a * 28/6/19 * - add "unlimited" * - requires us to use the gio API to librsvg * 11/9/19 * - rework as a sequential loader to reduce overcomputation * 11/6/21 * - switch to rsvg_handle_render_document() * - librsvg can no longer render very large images :( * 14/10/21 * - allow utf-8 headers for svg detection * 28/4/22 * - support rsvg_handle_get_intrinsic_size_in_pixels() * 5/6/22 * - allow random access * 20/5/25 * - support high bitdepth rendering (128-bit) */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #if defined(HAVE_RSVG) #include #include /* Render SVGs with tiles this size. They need to be pretty big to limit * overcomputation. */ #define TILE_SIZE (2000) /* The #endif typedef struct _VipsForeignLoadSvg { VipsForeignLoad parent_object; /* Render at this DPI. */ double dpi; /* Scale by this factor. */ double scale; /* The total scale factor we render with. */ double total_scale; /* Allow SVGs of any size. */ gboolean unlimited; /* Enables scRGB 128-bit output (32-bit per channel). */ gboolean high_bitdepth; /* Custom CSS. */ const char *stylesheet; RsvgHandle *page; } VipsForeignLoadSvg; typedef VipsForeignLoadClass VipsForeignLoadSvgClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadSvg, vips_foreign_load_svg, VIPS_TYPE_FOREIGN_LOAD); #ifdef HANDLE_SVGZ static void * vips_foreign_load_svg_zalloc(void *opaque, unsigned items, unsigned size) { return g_malloc0_n(items, size); } static void vips_foreign_load_svg_zfree(void *opaque, void *ptr) { return g_free(ptr); } #endif /*HANDLE_SVGZ*/ /* Find a utf-8 substring within the first len_bytes (not characters). * * - case-insensitive * - needle must be zero-terminated, but haystack need not be * - haystack can be null-terminated * - if haystack is shorter than len bytes, that'll end the search * - if we hit invalid utf-8, we return NULL */ static const char * vips_utf8_strcasestr(const char *haystack_start, const char *needle_start, int len_bytes) { int needle_len = g_utf8_strlen(needle_start, -1); int needle_len_bytes = strlen(needle_start); const char *haystack; for (haystack = haystack_start; haystack - haystack_start <= len_bytes - needle_len_bytes; haystack = g_utf8_find_next_char(haystack, NULL)) { const char *needle_char; const char *haystack_char; int i; haystack_char = haystack; needle_char = needle_start; for (i = 0; i < needle_len; i++) { /* Haystack isn't necessarily null-terminated and * might end half-way through a utf-8 character, so we * need to be careful not to run off the end. */ gunichar a = g_utf8_get_char_validated(haystack_char, haystack_start + len_bytes - haystack); gunichar b = g_utf8_get_char_validated(needle_char, -1); /* Invalid utf8? * * gunichar is a uint32, so we can't compare < 0, we * have to look for -1 and -2 (the two possible error * values). */ if (a == (gunichar) -1 || a == (gunichar) -2 || b == (gunichar) -1 || b == (gunichar) -2) return NULL; #if !GLIB_CHECK_VERSION(2, 63, 0) /* Disallow codepoint U+0000 as it's a nul byte. * This is redundant with GLib >= 2.63.0, see: * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/967 */ if (a == (gunichar) 0) return NULL; #endif /* Mismatch. */ if (g_unichar_tolower(a) != g_unichar_tolower(b)) break; haystack_char = g_utf8_find_next_char(haystack_char, haystack_start + len_bytes); /* End of haystack. There can't be a complete needle * anywhere. */ if (haystack_char == NULL) return NULL; /* needle_char will never be NULL. */ needle_char = g_utf8_find_next_char(needle_char, NULL); } if (i == needle_len) /* Walked the whole of needle, so we must have found a * complete match. */ return haystack; } /* Walked the whole of haystack without finding a match. */ return NULL; } /* This is used by both the file and buffer subclasses. */ static gboolean vips_foreign_load_svg_is_a(const void *buf, size_t len) { char *str; #ifdef HANDLE_SVGZ /* If the buffer looks like a zip, deflate to here and then search * that for = 18 && str[0] == '\037' && str[1] == '\213') { z_stream zs; size_t opos; int err; zs.zalloc = (alloc_func) vips_foreign_load_svg_zalloc; zs.zfree = (free_func) vips_foreign_load_svg_zfree; zs.opaque = Z_NULL; zs.next_in = (unsigned char *) str; zs.avail_in = len; /* There isn't really an error return from is_a_buffer() */ if (inflateInit2(&zs, 15 | 32) != Z_OK) return FALSE; opos = 0; do { zs.avail_out = sizeof(obuf) - opos; zs.next_out = (unsigned char *) obuf + opos; err = inflate(&zs, Z_NO_FLUSH); /* Always update opos after inflate(), even if stream ended. */ opos = sizeof(obuf) - zs.avail_out; if (err == Z_STREAM_END) break; if (err != Z_OK) { inflateEnd(&zs); return FALSE; } } while (opos < sizeof(obuf) && zs.avail_in > 0); inflateEnd(&zs); str = obuf; len = opos; } #endif /*HANDLE_SVGZ*/ /* SVG documents are very freeform. They normally look like: * * * page); G_OBJECT_CLASS(vips_foreign_load_svg_parent_class)->dispose(gobject); } static int vips_foreign_load_svg_build(VipsObject *object) { VipsForeignLoadSvg *svg G_GNUC_UNUSED = (VipsForeignLoadSvg *) object; #ifdef DEBUG printf("vips_foreign_load_svg_build:\n"); #endif /*DEBUG*/ #ifndef HAVE_CAIRO_FORMAT_RGBA128F if (svg->high_bitdepth) { g_warning("ignoring high_bitdepth"); svg->high_bitdepth = FALSE; } #endif /*HAVE_CAIRO_FORMAT_RGBA128F*/ svg->total_scale = svg->scale * svg->dpi / 72.0; return VIPS_OBJECT_CLASS(vips_foreign_load_svg_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_svg_get_flags_filename(const char *filename) { /* We can render any part of the page on demand. */ return VIPS_FOREIGN_PARTIAL; } static VipsForeignFlags vips_foreign_load_svg_get_flags(VipsForeignLoad *load) { return VIPS_FOREIGN_PARTIAL; } #if LIBRSVG_CHECK_VERSION(2, 52, 0) /* Derived from `CssLength::to_user` in librsvg. * https://gitlab.gnome.org/GNOME/librsvg/-/blob/2.60.0/rsvg/src/length.rs#L403 */ static double svg_css_length_to_pixels(RsvgLength length, double dpi) { double value = length.length; /* The following implies that our default font size is 12, which * matches the default in librsvg. */ double font_size = 12.0; switch (length.unit) { case RSVG_UNIT_PX: /* Already a pixel value. */ break; case RSVG_UNIT_EM: value *= font_size; break; case RSVG_UNIT_EX: value *= font_size / 2.0; break; case RSVG_UNIT_IN: value *= dpi; break; case RSVG_UNIT_CM: /* 2.54 cm in an inch. */ value = dpi * value / 2.54; break; case RSVG_UNIT_MM: /* 25.4 mm in an inch. */ value = dpi * value / 25.4; break; case RSVG_UNIT_PT: /* 72 points in an inch. */ value = dpi * value / 72; break; case RSVG_UNIT_PC: /* 6 picas in an inch. */ value = dpi * value / 6; break; default: /* Probably RSVG_UNIT_PERCENT. We can't know what the * pixel value is without more information. */ value = 0; } return value; } #endif static int vips_foreign_load_svg_get_natural_size(VipsForeignLoadSvg *svg, double *out_width, double *out_height) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(svg); double width; double height; #if LIBRSVG_CHECK_VERSION(2, 52, 0) if (!rsvg_handle_get_intrinsic_size_in_pixels(svg->page, &width, &height)) { RsvgRectangle viewbox; /* Try the intrinsic dimensions first. */ gboolean has_width, has_height; RsvgLength iwidth, iheight; gboolean has_viewbox; rsvg_handle_get_intrinsic_dimensions(svg->page, &has_width, &iwidth, &has_height, &iheight, &has_viewbox, &viewbox); #if LIBRSVG_CHECK_VERSION(2, 54, 0) /* After librsvg 2.54.0, the `has_width` and `has_height` * arguments always returns `TRUE`, since with SVG2 all * documents *have* a default width and height of `100%`. */ width = svg_css_length_to_pixels(iwidth, svg->dpi); height = svg_css_length_to_pixels(iheight, svg->dpi); has_width = width > 0.0; has_height = height > 0.0; if (has_width && has_height) { /* Success! Taking the viewbox into account is not * needed. */ } else if (has_width && has_viewbox) { height = width * viewbox.height / viewbox.width; } else if (has_height && has_viewbox) { width = height * viewbox.width / viewbox.height; } else if (has_viewbox) { width = viewbox.width; height = viewbox.height; } #else /*!LIBRSVG_CHECK_VERSION(2, 54, 0)*/ if (has_width && has_height) { /* We can use these values directly. */ width = svg_css_length_to_pixels(iwidth, svg->dpi); height = svg_css_length_to_pixels(iheight, svg->dpi); } else if (has_width && has_viewbox) { width = svg_css_length_to_pixels(iwidth, svg->dpi); height = width * viewbox.height / viewbox.width; } else if (has_height && has_viewbox) { height = svg_css_length_to_pixels(iheight, svg->dpi); width = height * viewbox.width / viewbox.height; } else if (has_viewbox) { width = viewbox.width; height = viewbox.height; } #endif /*!LIBRSVG_CHECK_VERSION(2, 54, 0)*/ if (width <= 0.0 || height <= 0.0) { /* We haven't found a usable set of sizes, so try * working out the visible area. */ rsvg_handle_get_geometry_for_element(svg->page, NULL, &viewbox, NULL, NULL); width = viewbox.x + viewbox.width; height = viewbox.y + viewbox.height; } } #else /*!LIBRSVG_CHECK_VERSION(2, 52, 0)*/ { RsvgDimensionData dimensions; rsvg_handle_get_dimensions(svg->page, &dimensions); width = dimensions.width; height = dimensions.height; } #endif /*LIBRSVG_CHECK_VERSION(2, 52, 0)*/ /* width or height below 0.5 can't be rounded to 1. */ if (width < 0.5 || height < 0.5) { vips_error(class->nickname, "%s", _("bad dimensions")); return -1; } *out_width = width; *out_height = height; return 0; } static int vips_foreign_load_svg_get_scaled_size(VipsForeignLoadSvg *svg, int *out_width, int *out_height) { double width; double height; /* Set target DPI to scale non-pixel units correctly. */ rsvg_handle_set_dpi(svg->page, svg->dpi); if (vips_foreign_load_svg_get_natural_size(svg, &width, &height)) return -1; width *= svg->total_scale; height *= svg->total_scale; *out_width = VIPS_ROUND_UINT(width); *out_height = VIPS_ROUND_UINT(height); return 0; } static int vips_foreign_load_svg_parse(VipsForeignLoadSvg *svg, VipsImage *out) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(svg); int width; int height; double res; if (vips_foreign_load_svg_get_scaled_size(svg, &width, &height)) return -1; if (width <= 0 || height <= 0) { vips_error(class->nickname, "%s", _("zero-sized image")); return -1; } /* We need pixels/mm for vips. */ res = svg->dpi / 25.4; vips_image_init_fields(out, width, height, 4, svg->high_bitdepth ? VIPS_FORMAT_FLOAT : VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, svg->high_bitdepth ? VIPS_INTERPRETATION_scRGB : VIPS_INTERPRETATION_sRGB, res, res); /* We use a tilecache, so it's smalltile. */ if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, NULL)) return -1; return 0; } static int vips_foreign_load_svg_header(VipsForeignLoad *load) { VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load; return vips_foreign_load_svg_parse(svg, load->out); } static int vips_foreign_load_svg_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { const VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) a; const VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(svg); const VipsRect *r = &out_region->valid; cairo_surface_t *surface; cairo_t *cr; int y; #ifdef DEBUG printf("vips_foreign_load_svg_generate: %p \n " "left = %d, top = %d, width = %d, height = %d\n", svg, r->left, r->top, r->width, r->height); #endif /*DEBUG*/ /* rsvg won't always paint the background. */ vips_region_black(out_region); #ifdef HAVE_CAIRO_FORMAT_RGBA128F cairo_format_t format = svg->high_bitdepth ? CAIRO_FORMAT_RGBA128F : CAIRO_FORMAT_ARGB32; #else cairo_format_t format = CAIRO_FORMAT_ARGB32; #endif /*HAVE_CAIRO_FORMAT_RGBA128F*/ surface = cairo_image_surface_create_for_data( VIPS_REGION_ADDR(out_region, r->left, r->top), format, r->width, r->height, VIPS_REGION_LSKIP(out_region)); cr = cairo_create(surface); cairo_surface_destroy(surface); #if LIBRSVG_CHECK_VERSION(2, 48, 0) if (svg->stylesheet && g_utf8_validate(svg->stylesheet, -1, NULL)) { GError *error = NULL; if (!rsvg_handle_set_stylesheet(svg->page, (const guint8 *) svg->stylesheet, g_utf8_strlen(svg->stylesheet, -1), &error)) { cairo_destroy(cr); vips_operation_invalidate(VIPS_OPERATION(svg)); vips_error(class->nickname, "Invalid custom CSS"); vips_g_error(&error); return -1; } } #endif /* rsvg is single-threaded, but we don't need to lock since we're * running inside a non-threaded tilecache. */ #if LIBRSVG_CHECK_VERSION(2, 46, 0) { RsvgRectangle viewport; GError *error = NULL; viewport.x = 0; viewport.y = 0; viewport.width = out_region->im->Xsize; viewport.height = out_region->im->Ysize; /* No need to scale -- we always set the viewport to the * whole image, and set the region to draw on the surface. */ cairo_translate(cr, -r->left, -r->top); if (!rsvg_handle_render_document(svg->page, cr, &viewport, &error)) { cairo_destroy(cr); vips_operation_invalidate(VIPS_OPERATION(svg)); vips_error(class->nickname, "%s", _("SVG rendering failed")); vips_g_error(&error); return -1; } cairo_destroy(cr); } #else /*!LIBRSVG_CHECK_VERSION(2, 46, 0)*/ cairo_scale(cr, svg->total_scale, svg->total_scale); cairo_translate(cr, -r->left / svg->total_scale, -r->top / svg->total_scale); if (!rsvg_handle_render_cairo(svg->page, cr)) { cairo_destroy(cr); vips_operation_invalidate(VIPS_OPERATION(svg)); vips_error(class->nickname, "%s", _("SVG rendering failed")); return -1; } cairo_destroy(cr); #endif /*LIBRSVG_CHECK_VERSION(2, 46, 0)*/ if (svg->high_bitdepth) { /* Assuming the surface is RGBA128F and the data is premultiplied. Loop through each row and unpremultiply the float data. */ for (y = 0; y < r->height; y++) vips__premultiplied_rgb1282scrgba( (float *) VIPS_REGION_ADDR(out_region, r->left, r->top + y), r->width); } else { /* Cairo makes pre-multipled BRGA -- we must byteswap and unpremultiply. */ for (y = 0; y < r->height; y++) vips__premultiplied_bgra2rgba( (guint32 *) VIPS_REGION_ADDR(out_region, r->left, r->top + y), r->width); } return 0; } static int vips_foreign_load_svg_load(VipsForeignLoad *load) { VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load; VipsImage **t = (VipsImage **) vips_object_local_array((VipsObject *) load, 3); /* Enough tiles for two complete rows. */ t[0] = vips_image_new(); if (vips_foreign_load_svg_parse(svg, t[0]) || vips_image_generate(t[0], NULL, vips_foreign_load_svg_generate, NULL, svg, NULL) || vips_tilecache(t[0], &t[1], "tile_width", TILE_SIZE, "tile_height", TILE_SIZE, "max_tiles", 2 * (1 + t[0]->Xsize / TILE_SIZE), NULL) || vips_image_write(t[1], load->real)) return -1; return 0; } static void vips_foreign_load_svg_class_init(VipsForeignLoadSvgClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_svg_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "svgload_base"; object_class->description = _("load SVG with rsvg"); object_class->build = vips_foreign_load_svg_build; /* librsvg has not been fuzzed, so should not be used with * untrusted input unless you are very careful. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* is_a() is not that quick ... lower the priority. */ foreign_class->priority = -5; load_class->get_flags_filename = vips_foreign_load_svg_get_flags_filename; load_class->get_flags = vips_foreign_load_svg_get_flags; load_class->load = vips_foreign_load_svg_load; VIPS_ARG_DOUBLE(class, "dpi", 21, _("DPI"), _("Render at this DPI"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvg, dpi), 0.001, 100000.0, 72.0); VIPS_ARG_DOUBLE(class, "scale", 22, _("Scale"), _("Scale output by this factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvg, scale), 0.0, 100000.0, 1.0); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VIPS_ARG_BOOL(class, "unlimited", 23, _("Unlimited"), _("Allow SVG of any size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvg, unlimited), FALSE); #endif VIPS_ARG_STRING(class, "stylesheet", 24, _("Stylesheet"), _("Custom CSS"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvg, stylesheet), NULL); VIPS_ARG_BOOL(class, "high_bitdepth", 25, _("High bitdepth"), _("Enable scRGB 128-bit output (32-bit per channel)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvg, high_bitdepth), FALSE); } static void vips_foreign_load_svg_init(VipsForeignLoadSvg *svg) { svg->dpi = 72.0; svg->scale = 1.0; } typedef struct _VipsForeignLoadSvgSource { VipsForeignLoadSvg parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadSvgSource; typedef VipsForeignLoadClass VipsForeignLoadSvgSourceClass; G_DEFINE_TYPE(VipsForeignLoadSvgSource, vips_foreign_load_svg_source, vips_foreign_load_svg_get_type()); gboolean vips_foreign_load_svg_source_is_a_source(VipsSource *source) { unsigned char *data; gint64 bytes_read; if ((bytes_read = vips_source_sniff_at_most(source, &data, SVG_HEADER_SIZE)) <= 0) return FALSE; return vips_foreign_load_svg_is_a(data, bytes_read); } static int vips_foreign_load_svg_source_header(VipsForeignLoad *load) { VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load; VipsForeignLoadSvgSource *source = (VipsForeignLoadSvgSource *) load; RsvgHandleFlags flags = svg->unlimited ? RSVG_HANDLE_FLAG_UNLIMITED : 0; GError *error = NULL; GInputStream *gstream; if (vips_source_rewind(source->source)) return -1; gstream = vips_g_input_stream_new_from_source(source->source); if (!(svg->page = rsvg_handle_new_from_stream_sync( gstream, NULL, flags, NULL, &error))) { g_object_unref(gstream); vips_g_error(&error); return -1; } g_object_unref(gstream); return vips_foreign_load_svg_header(load); } static int vips_foreign_load_svg_source_load(VipsForeignLoad *load) { VipsForeignLoadSvgSource *source = (VipsForeignLoadSvgSource *) load; if (vips_source_rewind(source->source) || vips_foreign_load_svg_load(load) || vips_source_decode(source->source)) return -1; return 0; } static void vips_foreign_load_svg_source_class_init(VipsForeignLoadSvgSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "svgload_source"; object_class->description = _("load svg from source"); operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_svg_source_is_a_source; load_class->header = vips_foreign_load_svg_source_header; load_class->load = vips_foreign_load_svg_source_load; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvgSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_svg_source_init(VipsForeignLoadSvgSource *source) { } typedef struct _VipsForeignLoadSvgFile { VipsForeignLoadSvg parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadSvgFile; typedef VipsForeignLoadSvgClass VipsForeignLoadSvgFileClass; G_DEFINE_TYPE(VipsForeignLoadSvgFile, vips_foreign_load_svg_file, vips_foreign_load_svg_get_type()); static gboolean vips_foreign_load_svg_file_is_a(const char *filename) { unsigned char buf[SVG_HEADER_SIZE]; guint64 bytes; return (bytes = vips__get_bytes(filename, buf, SVG_HEADER_SIZE)) > 0 && vips_foreign_load_svg_is_a(buf, bytes); } static int vips_foreign_load_svg_file_header(VipsForeignLoad *load) { VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load; VipsForeignLoadSvgFile *file = (VipsForeignLoadSvgFile *) load; RsvgHandleFlags flags = svg->unlimited ? RSVG_HANDLE_FLAG_UNLIMITED : 0; GError *error = NULL; GFile *gfile; gfile = g_file_new_for_path(file->filename); if (!(svg->page = rsvg_handle_new_from_gfile_sync( gfile, flags, NULL, &error))) { g_object_unref(gfile); vips_g_error(&error); return -1; } g_object_unref(gfile); VIPS_SETSTR(load->out->filename, file->filename); return vips_foreign_load_svg_header(load); } static const char *vips_foreign_svg_suffs[] = { ".svg", /* librsvg supports svgz directly, no need to check for zlib here. */ #if LIBRSVG_CHECK_FEATURE(SVGZ) ".svgz", ".svg.gz", #endif NULL }; static void vips_foreign_load_svg_file_class_init( VipsForeignLoadSvgFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "svgload"; foreign_class->suffs = vips_foreign_svg_suffs; load_class->is_a = vips_foreign_load_svg_file_is_a; load_class->header = vips_foreign_load_svg_file_header; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvgFile, filename), NULL); } static void vips_foreign_load_svg_file_init(VipsForeignLoadSvgFile *file) { } typedef struct _VipsForeignLoadSvgBuffer { VipsForeignLoadSvg parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadSvgBuffer; typedef VipsForeignLoadSvgClass VipsForeignLoadSvgBufferClass; G_DEFINE_TYPE(VipsForeignLoadSvgBuffer, vips_foreign_load_svg_buffer, vips_foreign_load_svg_get_type()); static int vips_foreign_load_svg_buffer_header(VipsForeignLoad *load) { VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load; VipsForeignLoadSvgBuffer *buffer = (VipsForeignLoadSvgBuffer *) load; RsvgHandleFlags flags = svg->unlimited ? RSVG_HANDLE_FLAG_UNLIMITED : 0; GError *error = NULL; GInputStream *gstream; gstream = g_memory_input_stream_new_from_data( buffer->buf->data, buffer->buf->length, NULL); if (!(svg->page = rsvg_handle_new_from_stream_sync( gstream, NULL, flags, NULL, &error))) { g_object_unref(gstream); vips_g_error(&error); return -1; } g_object_unref(gstream); return vips_foreign_load_svg_header(load); } static void vips_foreign_load_svg_buffer_class_init( VipsForeignLoadSvgBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "svgload_buffer"; load_class->is_a_buffer = vips_foreign_load_svg_is_a; load_class->header = vips_foreign_load_svg_buffer_header; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadSvgBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_svg_buffer_init(VipsForeignLoadSvgBuffer *buffer) { } #endif /*HAVE_RSVG*/ /** * vips_svgload: * @filename: file to load * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Render a SVG file into a VIPS image. * * Rendering uses the librsvg library and should be fast. * * Use @dpi to set the rendering resolution. The default is 72. Additionally, * you can scale by setting @scale. If you set both, they combine. * * This function only reads the image header and does not render any pixel * data. Rendering occurs when pixels are accessed. * * SVGs larger than 10MB are normally blocked for security. Set @unlimited to * allow SVGs of any size. * * A UTF-8 string containing custom CSS can be provided via @stylesheet. * During the CSS cascade, the specified stylesheet will be applied with a * User Origin. This feature requires librsvg 2.48.0 or later. * * If @high_bitdepth is set and the version of cairo supports it * (e.g. cairo >= 1.17.2), enable 128-bit scRGB output (32-bit per channel). * * ::: tip "Optional arguments" * * @dpi: `gdouble`, render at this DPI * * @scale: `gdouble`, scale render by this factor * * @unlimited: `gboolean`, allow SVGs of any size * * @stylesheet: `gchararray`, custom CSS * * @high_bitdepth: `gboolean`, enable scRGB 128-bit output * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_svgload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("svgload", ap, filename, out); va_end(ap); return result; } /** * vips_svgload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a SVG-formatted memory block into a VIPS image. Exactly as * [ctor@Image.svgload], but read from a memory buffer. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @dpi: `gdouble`, render at this DPI * * @scale: `gdouble`, scale render by this factor * * @unlimited: `gboolean`, allow SVGs of any size * * @stylesheet: `gchararray`, custom CSS * * @high_bitdepth: `gboolean`, enable scRGB 128-bit output * * ::: seealso * [ctor@Image.svgload]. * * Returns: 0 on success, -1 on error. */ int vips_svgload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("svgload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_svgload_string: * @str: string to load * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.svgload], but read from a string. This function * takes a copy of the string. * * ::: tip "Optional arguments" * * @dpi: `gdouble`, render at this DPI * * @scale: `gdouble`, scale render by this factor * * @unlimited: `gboolean`, allow SVGs of any size * * @stylesheet: `gchararray`, custom CSS * * @high_bitdepth: `gboolean`, enable scRGB 128-bit output * * ::: seealso * [ctor@Image.svgload]. * * Returns: 0 on success, -1 on error. */ int vips_svgload_string(const char *str, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* Copy the string. */ blob = vips_blob_copy((const void *) str, strlen(str)); va_start(ap, out); result = vips_call_split("svgload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_svgload_source: * @source: source to load from * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.svgload], but read from a source. * * ::: seealso * [ctor@Image.svgload]. * * Returns: 0 on success, -1 on error. */ int vips_svgload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("svgload_source", ap, source, out); va_end(ap); return result; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/tiff.c���������������������������������������������������������������0000664�0000000�0000000�00000017732�15163036615�0017477�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Some shared TIFF utilities. * * 14/10/16 * - from vips2tiff.c * * 26/8/17 * - add openout_read, to help tiffsave_buffer for pyramids */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_TIFF #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include "tiff.h" #ifdef HAVE_TIFF_OPEN_OPTIONS void vips__tiff_init(void) {} #else /* Handle TIFF errors here. Shared with vips2tiff.c. These can be called from * more than one thread. */ static void vips__thandler_error(const char *module, const char *fmt, va_list ap) { vips_verror(module, fmt, ap); } /* It'd be nice to be able to support the @fail option for the tiff loader, but * there's no easy way to do this, since libtiff has a global warning handler. */ static void vips__thandler_warning(const char *module, const char *fmt, va_list ap) { g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap); } /* Called during library init. * * libtiff error and warning handlers may be called from other threads * running in other libs. Other libs may install error handlers and capture * messages caused by us. */ void vips__tiff_init(void) { TIFFSetErrorHandler(vips__thandler_error); TIFFSetWarningHandler(vips__thandler_warning); } #endif /*HAVE_TIFF_OPEN_OPTIONS*/ /* TIFF input from a vips source. */ static tsize_t openin_source_read(thandle_t st, tdata_t data, tsize_t size) { VipsSource *source = VIPS_SOURCE(st); gint64 total_read; total_read = 0; while (total_read < size) { gint64 bytes_read; bytes_read = vips_source_read(source, data, size - total_read); if (bytes_read == -1) return -1; if (bytes_read == 0) break; total_read += bytes_read; data = (char *) data + bytes_read; } return total_read; } static tsize_t openin_source_write(thandle_t st, tdata_t buffer, tsize_t size) { g_assert_not_reached(); return 0; } static toff_t openin_source_seek(thandle_t st, toff_t offset, int whence) { VipsSource *source = VIPS_SOURCE(st); return (toff_t) vips_source_seek(source, offset, whence); } static int openin_source_close(thandle_t st) { VipsSource *source = VIPS_SOURCE(st); VIPS_UNREF(source); return 0; } static toff_t openin_source_length(thandle_t st) { VipsSource *source = VIPS_SOURCE(st); /* libtiff will use this to get file size if tags like StripByteCounts * are missing. * * toff_t is usually uint64, with -1 cast to uint64 to indicate error. */ return (toff_t) vips_source_length(source); } static int openin_source_map(thandle_t st, tdata_t *start, toff_t *len) { g_assert_not_reached(); return 0; } static void openin_source_unmap(thandle_t st, tdata_t start, toff_t len) { g_assert_not_reached(); return; } TIFF * vips__tiff_openin_source(VipsSource *source, VipsTiffErrorHandler error_fn, VipsTiffErrorHandler warning_fn, void *user_data, gboolean unlimited) { TIFF *tiff; #ifdef DEBUG printf("vips__tiff_openin_source:\n"); #endif /*DEBUG*/ if (vips_source_rewind(source)) return NULL; /* Disable memory mapped input -- it chews up VM and the performance * gain is very small. * * C enables strip chopping: very large uncompressed strips are * chopped into c. 8kb chunks. This can reduce peak memory use for * this type of file. */ #ifdef HAVE_TIFF_OPEN_OPTIONS TIFFOpenOptions *opts = TIFFOpenOptionsAlloc(); TIFFOpenOptionsSetErrorHandlerExtR(opts, error_fn, user_data); TIFFOpenOptionsSetWarningHandlerExtR(opts, warning_fn, user_data); #ifdef HAVE_TIFF_OPEN_OPTIONS_SET_MAX_CUMULATED_MEM_ALLOC if (!unlimited) { TIFFOpenOptionsSetMaxCumulatedMemAlloc(opts, 50 * 1024 * 1024); } #endif /*HAVE_TIFF_OPEN_OPTIONS_SET_MAX_CUMULATED_MEM_ALLOC*/ if (!(tiff = TIFFClientOpenExt("source input", "rmC", (thandle_t) source, openin_source_read, openin_source_write, openin_source_seek, openin_source_close, openin_source_length, openin_source_map, openin_source_unmap, opts))) { TIFFOpenOptionsFree(opts); vips_error("vips__tiff_openin_source", "%s", _("unable to open source for input")); return NULL; } TIFFOpenOptionsFree(opts); #else if (!(tiff = TIFFClientOpen("source input", "rmC", (thandle_t) source, openin_source_read, openin_source_write, openin_source_seek, openin_source_close, openin_source_length, openin_source_map, openin_source_unmap))) { vips_error("vips__tiff_openin_source", "%s", _("unable to open source for input")); return NULL; } #endif /*HAVE_TIFF_OPEN_OPTIONS*/ /* Unreffed on close(), see above. */ g_object_ref(source); return tiff; } /* TIFF output to a target. */ /* libtiff needs this (!!?!?!) for writing multipage images. */ static tsize_t openout_target_read(thandle_t st, tdata_t data, tsize_t size) { VipsTarget *target = (VipsTarget *) st; return vips_target_read(target, data, size); } static tsize_t openout_target_write(thandle_t st, tdata_t data, tsize_t size) { VipsTarget *target = (VipsTarget *) st; if (vips_target_write(target, data, size)) return (tsize_t) -1; return size; } static toff_t openout_target_seek(thandle_t st, toff_t offset, int whence) { VipsTarget *target = (VipsTarget *) st; return vips_target_seek(target, offset, whence); } static int openout_target_close(thandle_t st) { VipsTarget *target = (VipsTarget *) st; if (vips_target_end(target)) return -1; return 0; } static toff_t openout_target_length(thandle_t st) { g_assert_not_reached(); return (toff_t) -1; } static int openout_target_map(thandle_t st, tdata_t *start, toff_t *len) { g_assert_not_reached(); return -1; } static void openout_target_unmap(thandle_t st, tdata_t start, toff_t len) { g_assert_not_reached(); return; } TIFF * vips__tiff_openout_target(VipsTarget *target, gboolean bigtiff, VipsTiffErrorHandler error_fn, VipsTiffErrorHandler warning_fn, void *user_data) { const char *mode = bigtiff ? "w8" : "w"; TIFF *tiff; #ifdef DEBUG printf("vips__tiff_openout_buffer:\n"); #endif /*DEBUG*/ #ifdef HAVE_TIFF_OPEN_OPTIONS TIFFOpenOptions *opts = TIFFOpenOptionsAlloc(); TIFFOpenOptionsSetErrorHandlerExtR(opts, error_fn, user_data); TIFFOpenOptionsSetWarningHandlerExtR(opts, warning_fn, user_data); if (!(tiff = TIFFClientOpenExt("target output", mode, (thandle_t) target, openout_target_read, openout_target_write, openout_target_seek, openout_target_close, openout_target_length, openout_target_map, openout_target_unmap, opts))) { TIFFOpenOptionsFree(opts); vips_error("vips__tiff_openout_target", "%s", _("unable to open target for output")); return NULL; } TIFFOpenOptionsFree(opts); #else if (!(tiff = TIFFClientOpen("target output", mode, (thandle_t) target, openout_target_read, openout_target_write, openout_target_seek, openout_target_close, openout_target_length, openout_target_map, openout_target_unmap))) { vips_error("vips__tiff_openout_target", "%s", _("unable to open target for output")); return NULL; } #endif /*HAVE_TIFF_OPEN_OPTIONS*/ return tiff; } #endif /*HAVE_TIFF*/ ��������������������������������������libvips-8.18.2/libvips/foreign/tiff.h���������������������������������������������������������������0000664�0000000�0000000�00000003376�15163036615�0017503�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* common defs for tiff read/write */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_TIFF_H #define VIPS_TIFF_H #include /* Aperio TIFFs (svs) use these compression types for jp2k-compressed tiles. */ #define JP2K_YCC (33003) #define JP2K_RGB (33005) /* Bioformats uses this tag for jp2k compressed tiles. */ #define JP2K_LOSSY (33004) #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef int (*VipsTiffErrorHandler)(TIFF *tiff, void *user_data, const char *module, const char *fmt, va_list ap); TIFF *vips__tiff_openin_source(VipsSource *source, VipsTiffErrorHandler error_fn, VipsTiffErrorHandler warning_fn, void *user_data, gboolean unlimited); TIFF *vips__tiff_openout(const char *path, gboolean bigtiff); TIFF *vips__tiff_openout_target(VipsTarget *target, gboolean bigtiff, VipsTiffErrorHandler error_fn, VipsTiffErrorHandler warning_fn, void *user_data); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_TIFF_H*/ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/tiff2vips.c����������������������������������������������������������0000664�0000000�0000000�00000247110�15163036615�0020456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* TIFF parts: Copyright (c) 1988, 1990 by Sam Leffler. * All rights reserved. * * This file is provided for unrestricted use provided that this * legend is included on all tape media and as a part of the * software program in whole or part. Users may copy, modify or * distribute this file at will. * ----------------------------- * Modifications for VIPS: Kirk Martinez 1994 * 22/11/94 JC * - more general * - memory leaks fixed * 20/3/95 JC * - TIFF error handler added * - read errors detected correctly * * Modified to handle LAB in tiff format. * It convert LAB-tiff format to VIPS_INTERPRETATION_LABQ in vips format. * Copyright July-1995 Ahmed Abbood. * * * 19/9/95 JC * - now calls TIFFClose ... stupid * 25/1/96 JC * - typo on MINISBLACK ... * 7/4/97 JC * - completely redone for TIFF 6 * - now full baseline TIFF 6 reader, and does CIELAB as well * 11/4/97 JC * - added partial read for tiled images * 23/4/97 JC * - extra subsample parameter * - im_istiffpyramid() added * 5/12/97 JC * - if loading YCbCr, convert to VIPS_CODING_LABQ * 1/5/98 JC * - now reads 16-bit greyscale and RGB * 26/10/98 JC * - now used "rb" mode on systems that need binary open * 12/11/98 JC * - no sub-sampling if sub == 1 * 26/2/99 JC * - ooops, else missing for subsample stuff above * 2/10/99 JC * - tiled 16-bit greyscale read was broken * - added mutex for TIFFReadTile() calls * 11/5/00 JC * - removed TIFFmalloc/TIFFfree usage * 23/4/01 JC * - HAVE_TIFF turns on TIFF goodness * 24/5/01 JC * - im_tiff2vips_header() added * 11/7/01 JC * - subsample now in input filename * - ... and it's a page number (from 0) instead * 21/8/02 JC * - now reads CMYK * - hmm, dpi -> ppm conversion was wrong! * 10/9/02 JC * - oops, handle TIFF errors better * 2/12/02 JC * - reads 8-bit RGBA * 12/12/02 JC * - reads 16-bit LAB * 13/2/03 JC * - pixels/cm res read was wrong * 17/11/03 Andrey Kiselev * - read 32-bit float greyscale and rgb * 5/4/04 * - better handling of edge tiles (thanks Ruven) * 16/4/04 * - cleanup * - added broken tile read mode * 18/5/04 Andrey Kiselev * - better no resolution diagnostic * 26/5/04 * - reads 16 bit RGBA * 28/7/04 * - arrg, 16bit RGB was broken, thanks haida * 26/11/04 * - add a TIFF warning handler, stops occasional libMagick exceptions * 9/3/05 * - load 32-bit float LAB * 8/4/05 * - onebit read no longer reads one byte too many on multiple of 8 wide * images * 22/6/05 * - 16 bit LAB read was broken * 9/9/05 * - read any ICCPROFILE tag * 8/5/06 * - set RGB16 and GREY16 Type * 21/5/06 * - use external im_tile_cache() operation for great code shrinkage * - less RAM usage too, esp. with >1 CPU * - should be slightly faster * - removed 'broken' read option * 18/7/07 Andrey Kiselev * - remove "b" option on TIFFOpen() * 9/4/08 * - set VIPS_META_RESOLUTION_UNIT * 17/4/08 * - allow CMYKA (thanks Doron) * 17/7/08 * - convert YCbCr to RGB on read (thanks Ole) * 15/8/08 * - reorganise for image format system * 20/12/08 * - dont read with mmap: no performance advantage with libtiff, chews up * VM wastefully * 13/1/09 * - read strip-wise, not scanline-wise ... works with more compression / * subsampling schemes (esp. subsampled YCbCr), and it's a bit quicker * 4/2/10 * - gtkdoc * 12/12/10 * - oops, we can just memcpy() now heh * - avoid unpacking via buffers if we can: either read a tile directly * into the output region, or writeline directly from the tiff buffer * 4/4/11 * - argh int/uint mixup for rows_per_strip, thanks Bubba * 21/4/11 * - palette read can do 1,2,4,8 bits per sample * - palette read can do mono images * 5/12/11 * - make into a simple function call ready to be wrapped as a new-style * VipsForeign class * 18/2/12 * - switch to sequential read * - remove the lock ... tilecache does this for us * 3/6/12 * - always offer THINSTRIP ... later stages can ask for something more * relaxed if they wish * 7/6/12 * - clip rows_per_strip down to image height to avoid overflows for huge * values (thanks Nicolas) * - better error msg for not PLANARCONFIG_CONTIG images * 16/9/13 * - support alpha for 8, 16 and 32-bit greyscale images, thanks Robert * 17/9/13 * - support separate planes for strip read * - big cleanup * - support for many more formats, eg. 32-bit int etc. * 11/4/14 * - support 16 bits per sample palette images * - palette images can have an alpha * 22/4/14 * - add read from buffer * 30/4/14 * - 1/2/4 bit palette images can have alpha * 27/10/14 Lovell * - better istiff detector spots bigtiff * 3/12/14 * - read any XMP metadata * 19/1/15 * - try to handle 8-bit colormaps * 26/2/15 * - close the read down early for a header read ... this saves an * fd during file read, handy for large numbers of input images * 29/9/15 * - load IPTC metadata * - load photoshop metadata * 21/12/15 * - load TIFFTAG_IMAGEDESCRIPTION * 11/4/16 * - non-int RGB images are tagged as scRGB ... matches photoshop * convention * 26/5/16 * - add autorotate support * 17/11/16 * - add multi-page read * 17/1/17 * - invalidate operation on read error * 27/1/17 * - if rows_per_strip is large, read with scanline API instead * 9/5/17 * - remove missing res warning * 19/5/17 * - page > 0 could break edge tiles or strips * 26/4/18 * - add n-pages metadata item * 21/7/18 * - check for non-byte-multiple bits_per_sample [HongxuChen] * 16/8/18 * - shut down the input file as soon as we can [kleisauke] * 28/3/19 omira-sch * - better buffer sizing * - ban chroma-subsampled, non-jpg compressed images * 7/6/19 * - istiff reads the first directory rather than just testing the magic * number, so it ignores more TIFF-like, but not TIFF images * 17/10/19 * - switch to source input * 18/11/19 * - support ASSOCALPHA in any alpha band * 27/1/20 * - read logluv images as XYZ * 11/4/20 petoor * - better handling of aligned reads in multipage tiffs * 28/5/20 * - add subifd * 6/6/20 MathemanFlo * - support 2 and 4 bit greyscale load * 27/3/21 * - add jp2k decompression * 24/7/21 * - add fail_on * 30/9/21 * - fix tiled + packed formats * 31/7/22 * - move jp2k decompress outside the lock * - move jpeg decode outside the lock * - fix demand hinting * 3/2/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_TIFF #include #include #include #include #include #include #include "pforeign.h" #include "tiff.h" /* We do jpeg decompress ourselves, if we can. */ #ifdef HAVE_JPEG #include "jpeg.h" #endif /*HAVE_JPEG*/ /* Compression types we handle ourselves. */ static int rtiff_we_decompress[] = { #ifdef HAVE_JPEG COMPRESSION_JPEG, #endif /*HAVE_JPEG*/ JP2K_YCC, JP2K_RGB, JP2K_LOSSY }; /* What we read from the tiff dir to set our read strategy. For multipage * read, we need to read and compare lots of these, so it needs to be broken * out as a separate thing. */ typedef struct _RtiffHeader { guint32 width; guint32 height; int samples_per_pixel; int bits_per_sample; int photometric_interpretation; int inkset; int sample_format; gboolean separate; int orientation; /* If there's a premultiplied alpha, the band we need to * unpremultiply with. -1 for no unpremultiplication. */ int alpha_band; guint16 compression; /* Is this directory tiled. */ gboolean tiled; /* Fields for tiled images, as returned by libtiff. */ guint32 tile_width; guint32 tile_height; tsize_t tile_size; tsize_t tile_row_size; /* Fields for strip images, as returned by libtiff. */ guint32 rows_per_strip; tsize_t strip_size; tsize_t scanline_size; int number_of_strips; /* If read_scanlinewise is TRUE, the strips are too large to read in a * single lump and we will use the scanline API. */ gboolean read_scanlinewise; /* Strip read geometry. Number of lines we read at once (whole strip * or 1) and size of the buffer we read to (a scanline, or a strip in * size). */ guint32 read_height; tsize_t read_size; /* Scale factor to get absolute cd/m2 from XYZ. */ double stonits; /* Number of subifds, 0 for none. */ int subifd_count; /* Optional IMAGEDESCRIPTION. */ char *image_description; /* TRUE if we decompress ourselves rather than relying on libtiff. */ gboolean we_decompress; /* TRUE if we use TIFFRGBAImage or TIFFReadRGBATile. * Used for COMPRESSION_OJPEG */ gboolean read_as_rgba; } RtiffHeader; /* Scanline-type process function. */ struct _Rtiff; typedef void (*scanline_process_fn)(struct _Rtiff *, VipsPel *q, VipsPel *p, int n, void *client); /* Stuff we track during a read. */ typedef struct _Rtiff { /* Parameters. */ VipsSource *source; VipsImage *out; int page; int n; gboolean autorotate; int subifd; VipsFailOn fail_on; /* We decompress some compression types in parallel, so we need to * lock tile get. */ GRecMutex lock; /* The TIFF we read. */ TIFF *tiff; /* Number of pages (directories) in image. */ int n_pages; /* The current page we have set. */ int current_page; /* Process for this image type. */ scanline_process_fn sfn; void *client; /* Set this is the processfn is just doing a memcpy. */ gboolean memcpy; /* Geometry as read from the TIFF header. This is read for the first * page, and equal for all other pages. */ RtiffHeader header; /* Hold a single strip or tile, possibly just an image plane. */ tdata_t plane_buf; /* Hold a plane-assembled strip or tile ... a set of samples_per_pixel * strips or tiles interleaved. */ tdata_t contig_buf; /* The Y we are reading at. Used to verify strip read is sequential. */ int y_pos; /* Stop processing due to an error or warning. */ gboolean failed; } Rtiff; /* Convert IEEE 754-2008 16-bit float to 32-bit float */ static inline float half_2_float(gushort h) { const float sign = (h >> 15) * -2 + 1; const int exp = ((h & 0x7C00) >> 10) - 15; const float prec = (h & 0x03FF); switch (exp) { case 16: return INFINITY * sign; case -15: return sign / (float) (1 << 14) * (prec / 1024.0F); default: return exp > 0 ? sign * (float) (1 << exp) * (1.0F + prec / 1024.0F) : sign / (float) (1 << -exp) * (1.0F + prec / 1024.0F); } } /* Test for field exists. */ static int tfexists(TIFF *tif, ttag_t tag) { guint32 a, b; if (TIFFGetField(tif, tag, &a, &b)) return 1; else return 0; } /* Get a guint32 field. */ static int tfget32(TIFF *tif, ttag_t tag, guint32 *out) { guint32 fld; if (!TIFFGetFieldDefaulted(tif, tag, &fld)) { vips_error("tiff2vips", _("required field %d missing"), tag); return 0; } *out = fld; return 1; } /* Get a guint16 field. */ static int tfget16(TIFF *tif, ttag_t tag, int *out) { guint16 fld; if (!TIFFGetFieldDefaulted(tif, tag, &fld)) { vips_error("tiff2vips", _("required field %d missing"), tag); return 0; } *out = fld; return 1; } static int get_resolution(TIFF *tiff, VipsImage *out) { float x, y; int ru; if (TIFFGetFieldDefaulted(tiff, TIFFTAG_XRESOLUTION, &x) && TIFFGetFieldDefaulted(tiff, TIFFTAG_YRESOLUTION, &y) && tfget16(tiff, TIFFTAG_RESOLUTIONUNIT, &ru)) { switch (ru) { case RESUNIT_NONE: break; case RESUNIT_INCH: /* In pixels-per-inch ... convert to mm. */ x /= 10.0F * 2.54F; y /= 10.0F * 2.54F; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "in"); break; case RESUNIT_CENTIMETER: /* In pixels-per-centimetre ... convert to mm. */ x /= 10.0F; y /= 10.0F; vips_image_set_string(out, VIPS_META_RESOLUTION_UNIT, "cm"); break; default: vips_error("tiff2vips", "%s", _("unknown resolution unit")); return -1; } } else { /* We used to warn about missing res data, but it happens so * often and is so harmless, why bother. */ x = 1.0F; y = 1.0F; } out->Xres = x; out->Yres = y; return 0; } static int get_sample_format(TIFF *tiff) { int sample_format; guint16 v; sample_format = SAMPLEFORMAT_INT; if (TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLEFORMAT, &v)) { /* Some images have this set to void, bizarre. */ if (v == SAMPLEFORMAT_VOID) v = SAMPLEFORMAT_UINT; sample_format = v; } return sample_format; } static int get_orientation(TIFF *tiff) { int orientation; guint16 v; orientation = ORIENTATION_TOPLEFT; if (TIFFGetFieldDefaulted(tiff, TIFFTAG_ORIENTATION, &v)) /* Can have mad values. */ orientation = VIPS_CLIP(1, v, 8); return orientation; } /* Can be called many times. */ static void rtiff_free(Rtiff *rtiff) { VIPS_FREEF(TIFFClose, rtiff->tiff); g_rec_mutex_clear(&rtiff->lock); VIPS_UNREF(rtiff->source); } static void rtiff_close_cb(VipsImage *image, Rtiff *rtiff) { rtiff_free(rtiff); } static void rtiff_minimise_cb(VipsImage *image, Rtiff *rtiff) { /* We must not minimised tiled images. These can be read from many * threads, and this minimise handler is not inside the lock. */ if (!rtiff->header.tiled && rtiff->source) vips_source_minimise(rtiff->source); } static int rtiff_handler_error(TIFF *tiff, void *user_data, const char *module, const char *fmt, va_list ap) { if (user_data) { Rtiff *rtiff = (Rtiff *) user_data; if (rtiff->fail_on >= VIPS_FAIL_ON_ERROR) { rtiff->failed = TRUE; } else if (fmt) { /* Inspect message for always-fatal errors. */ if (strncmp(fmt, "Cumulated memory", 16) == 0) { rtiff->failed = TRUE; } } } vips_verror("tiff2vips", fmt, ap); return 1; } static int rtiff_handler_warning(TIFF *tiff, void *user_data, const char *module, const char *fmt, va_list ap) { if (user_data) { Rtiff *rtiff = (Rtiff *) user_data; if (rtiff->fail_on >= VIPS_FAIL_ON_WARNING) { rtiff->failed = TRUE; } } g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap); return 1; } static Rtiff * rtiff_new(VipsSource *source, VipsImage *out, int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on, gboolean unlimited) { Rtiff *rtiff; if (!(rtiff = VIPS_NEW(out, Rtiff))) return NULL; g_object_ref(source); rtiff->source = source; rtiff->out = out; rtiff->page = page; rtiff->n = n; rtiff->autorotate = autorotate; rtiff->subifd = subifd; rtiff->fail_on = fail_on; g_rec_mutex_init(&rtiff->lock); rtiff->tiff = NULL; rtiff->n_pages = 0; rtiff->current_page = -1; rtiff->sfn = NULL; rtiff->client = NULL; rtiff->memcpy = FALSE; rtiff->plane_buf = NULL; rtiff->contig_buf = NULL; rtiff->y_pos = 0; rtiff->failed = FALSE; g_signal_connect(out, "close", G_CALLBACK(rtiff_close_cb), rtiff); g_signal_connect(out, "minimise", G_CALLBACK(rtiff_minimise_cb), rtiff); if (rtiff->page < 0 || rtiff->page > 1000000) { vips_error("tiff2vips", _("bad page number %d"), rtiff->page); return NULL; } /* We allow n == -1, meaning all pages. It gets swapped for a real n * value when we open the TIFF. */ if (rtiff->n != -1 && (rtiff->n < 1 || rtiff->n > 1000000)) { vips_error("tiff2vips", _("bad number of pages %d"), rtiff->n); return NULL; } if (!(rtiff->tiff = vips__tiff_openin_source(source, rtiff_handler_error, rtiff_handler_warning, rtiff, unlimited))) return NULL; return rtiff; } static int rtiff_strip_read(Rtiff *rtiff, int strip, tdata_t buf) { tsize_t length; #ifdef DEBUG_VERBOSE printf("rtiff_strip_read: reading strip %d\n", strip); #endif /*DEBUG_VERBOSE*/ if (rtiff->header.read_scanlinewise) length = TIFFReadScanline(rtiff->tiff, buf, strip, (tsample_t) 0); else length = TIFFReadEncodedStrip(rtiff->tiff, strip, buf, (tsize_t) -1); if (length == -1 && rtiff->fail_on >= VIPS_FAIL_ON_WARNING) { vips_foreign_load_invalidate(rtiff->out); vips_error("tiff2vips", "%s", _("read error")); return -1; } if (rtiff->failed) { vips_foreign_load_invalidate(rtiff->out); return -1; } return 0; } static int rtiff_rgba_strip_read(Rtiff *rtiff, int strip, tdata_t buf) { RtiffHeader *header = &rtiff->header; TIFFRGBAImage img; guint32 rows_to_read; char err[1024] = ""; #ifdef DEBUG_VERBOSE printf("rtiff_rgba_strip_read: reading strip %d\n", strip); #endif /*DEBUG_VERBOSE*/ if (!TIFFRGBAImageOK(rtiff->tiff, err) || !TIFFRGBAImageBegin(&img, rtiff->tiff, 0, err)) { vips_foreign_load_invalidate(rtiff->out); vips_error("tiff2vips", "%s", err); return -1; } img.req_orientation = header->orientation; img.row_offset = strip * header->rows_per_strip; img.col_offset = 0; rows_to_read = VIPS_MIN(header->rows_per_strip, header->height - img.row_offset); if (!TIFFRGBAImageGet(&img, buf, header->width, rows_to_read)) { TIFFRGBAImageEnd(&img); vips_foreign_load_invalidate(rtiff->out); vips_error("tiff2vips", "%s", _("read error")); return -1; } TIFFRGBAImageEnd(&img); if (rtiff->failed) { vips_foreign_load_invalidate(rtiff->out); return -1; } return 0; } /* We need to hint to libtiff what format we'd like pixels in. */ static void rtiff_set_decode_format(Rtiff *rtiff) { /* Ask for YCbCr->RGB for jpg data. */ if (rtiff->header.compression == COMPRESSION_JPEG || rtiff->header.compression == COMPRESSION_OJPEG) TIFFSetField(rtiff->tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); /* Ask for SGI LOGLUV as 3xfloat. */ if (rtiff->header.photometric_interpretation == PHOTOMETRIC_LOGLUV) TIFFSetField(rtiff->tiff, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); } static int rtiff_set_page(Rtiff *rtiff, int page) { if (rtiff->current_page != page) { #ifdef DEBUG printf("rtiff_set_page: selecting page %d, subifd %d\n", page, rtiff->subifd); #endif /*DEBUG*/ if (!TIFFSetDirectory(rtiff->tiff, page)) { vips_error("tiff2vips", _("TIFF does not contain page %d"), page); return -1; } if (rtiff->subifd >= 0) { guint16 subifd_count; toff_t *subifd_offsets; if (!TIFFGetField(rtiff->tiff, TIFFTAG_SUBIFD, &subifd_count, &subifd_offsets)) { vips_error("tiff2vips", "%s", _("no SUBIFD tag")); return -1; } if (rtiff->subifd >= subifd_count) { vips_error("tiff2vips", _("subifd %d out of range, only 0-%d available"), rtiff->subifd, subifd_count - 1); return -1; } if (!TIFFSetSubDirectory(rtiff->tiff, subifd_offsets[rtiff->subifd])) { vips_error("tiff2vips", "%s", _("subdirectory unreadable")); return -1; } } rtiff->current_page = page; /* These can get unset when we change directories. Make sure * they are set again. */ rtiff_set_decode_format(rtiff); } return 0; } static int rtiff_n_pages(Rtiff *rtiff) { int n; (void) TIFFSetDirectory(rtiff->tiff, 0); for (n = 1; TIFFReadDirectory(rtiff->tiff); n++) ; /* Make sure the nest set_page() will set the directory. */ rtiff->current_page = -1; #ifdef DEBUG printf("rtiff_n_pages: found %d pages\n", n); #endif /*DEBUG*/ return n; } static int rtiff_check_samples(Rtiff *rtiff, int samples_per_pixel) { if (rtiff->header.samples_per_pixel != samples_per_pixel) { vips_error("tiff2vips", _("not %d bands"), samples_per_pixel); return -1; } return 0; } /* Check n and n+1 so we can have an alpha. */ static int rtiff_check_min_samples(Rtiff *rtiff, int samples_per_pixel) { if (rtiff->header.samples_per_pixel < samples_per_pixel) { vips_error("tiff2vips", _("not at least %d samples per pixel"), samples_per_pixel); return -1; } return 0; } /* Only allow samples which are whole bytes in size. */ static int rtiff_non_fractional(Rtiff *rtiff) { if (rtiff->header.bits_per_sample % 8 != 0 || rtiff->header.bits_per_sample == 0) { vips_error("tiff2vips", "%s", _("samples_per_pixel " "not a whole number of bytes")); return -1; } return 0; } static int rtiff_check_interpretation(Rtiff *rtiff, int photometric_interpretation) { if (rtiff->header.photometric_interpretation != photometric_interpretation) { vips_error("tiff2vips", _("not photometric interpretation %d"), photometric_interpretation); return -1; } return 0; } static int rtiff_check_bits(Rtiff *rtiff, int bits_per_sample) { if (rtiff->header.bits_per_sample != bits_per_sample) { vips_error("tiff2vips", _("not %d bits per sample"), bits_per_sample); return -1; } return 0; } static int rtiff_check_bits_palette(Rtiff *rtiff) { if (rtiff->header.bits_per_sample != 16 && rtiff->header.bits_per_sample != 8 && rtiff->header.bits_per_sample != 4 && rtiff->header.bits_per_sample != 2 && rtiff->header.bits_per_sample != 1) { vips_error("tiff2vips", _("%d bits per sample palette image not supported"), rtiff->header.bits_per_sample); return -1; } return 0; } static VipsBandFormat rtiff_guess_format(Rtiff *rtiff) { int bits_per_sample = rtiff->header.bits_per_sample; int sample_format = rtiff->header.sample_format; switch (bits_per_sample) { case 1: case 2: case 4: case 8: if (sample_format == SAMPLEFORMAT_INT) return VIPS_FORMAT_CHAR; if (sample_format == SAMPLEFORMAT_UINT) return VIPS_FORMAT_UCHAR; break; case 16: if (sample_format == SAMPLEFORMAT_INT) return VIPS_FORMAT_SHORT; if (sample_format == SAMPLEFORMAT_UINT) return VIPS_FORMAT_USHORT; if (sample_format == SAMPLEFORMAT_IEEEFP) return VIPS_FORMAT_FLOAT; break; case 32: if (sample_format == SAMPLEFORMAT_INT) return VIPS_FORMAT_INT; if (sample_format == SAMPLEFORMAT_UINT) return VIPS_FORMAT_UINT; if (sample_format == SAMPLEFORMAT_IEEEFP) return VIPS_FORMAT_FLOAT; break; case 64: if (sample_format == SAMPLEFORMAT_IEEEFP) return VIPS_FORMAT_DOUBLE; if (sample_format == SAMPLEFORMAT_COMPLEXIEEEFP) return VIPS_FORMAT_COMPLEX; break; case 128: if (sample_format == SAMPLEFORMAT_COMPLEXIEEEFP) return VIPS_FORMAT_DPCOMPLEX; break; default: break; } vips_error("tiff2vips", "%s", _("unsupported tiff image type\n")); return VIPS_FORMAT_NOTSET; } /* Per-scanline process function for VIPS_CODING_LABQ. */ static void rtiff_labpack_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy) { int samples_per_pixel = rtiff->header.samples_per_pixel; int x; for (x = 0; x < n; x++) { q[0] = p[0]; q[1] = p[1]; q[2] = p[2]; q[3] = 0; q += 4; p += samples_per_pixel; } } /* Read an 8-bit LAB image. */ static int rtiff_parse_labpack(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_min_samples(rtiff, 3) || rtiff_check_bits(rtiff, 8) || rtiff_check_interpretation(rtiff, PHOTOMETRIC_CIELAB)) return -1; out->Bands = 4; out->BandFmt = VIPS_FORMAT_UCHAR; out->Coding = VIPS_CODING_LABQ; out->Type = VIPS_INTERPRETATION_LAB; rtiff->sfn = rtiff_labpack_line; return 0; } /* Per-scanline process function for 8-bit VIPS_CODING_LAB to 16-bit LabS with * alpha. */ static void rtiff_lab_with_alpha_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy) { int samples_per_pixel = rtiff->header.samples_per_pixel; unsigned char *p1; short *q1; int x; p1 = (unsigned char *) p; q1 = (short *) q; for (x = 0; x < n; x++) { int i; q1[0] = ((unsigned int) p1[0]) * 32767 / 255; q1[1] = ((short) p1[1]) << 8; q1[2] = ((short) p1[2]) << 8; for (i = 3; i < samples_per_pixel; i++) q1[i] = (p1[i] << 8) + p1[i]; q1 += samples_per_pixel; p1 += samples_per_pixel; } } /* Read an 8-bit LAB image with alpha bands into 16-bit LabS. */ static int rtiff_parse_lab_with_alpha(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_min_samples(rtiff, 4) || rtiff_check_bits(rtiff, 8) || rtiff_check_interpretation(rtiff, PHOTOMETRIC_CIELAB)) return -1; out->Bands = rtiff->header.samples_per_pixel; out->BandFmt = VIPS_FORMAT_SHORT; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_LABS; rtiff->sfn = rtiff_lab_with_alpha_line; return 0; } /* Per-scanline process function for LABS. */ static void rtiff_labs_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy) { int samples_per_pixel = rtiff->header.samples_per_pixel; unsigned short *p1; short *q1; int x; int i; p1 = (unsigned short *) p; q1 = (short *) q; for (x = 0; x < n; x++) { /* We use signed int16 for L. */ q1[0] = p1[0] >> 1; for (i = 1; i < samples_per_pixel; i++) q1[i] = p1[i]; q1 += samples_per_pixel; p1 += samples_per_pixel; } } /* Read a 16-bit LAB image. */ static int rtiff_parse_labs(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_min_samples(rtiff, 3) || rtiff_check_bits(rtiff, 16) || rtiff_check_interpretation(rtiff, PHOTOMETRIC_CIELAB)) return -1; out->Bands = rtiff->header.samples_per_pixel; out->BandFmt = VIPS_FORMAT_SHORT; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_LABS; rtiff->sfn = rtiff_labs_line; return 0; } /* libtiff delivers logluv as illuminant-free 0-1 XYZ in 3 x float. */ static void rtiff_logluv_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *dummy) { int samples_per_pixel = rtiff->header.samples_per_pixel; float *p1; float *q1; int x; int i; p1 = (float *) p; q1 = (float *) q; for (x = 0; x < n; x++) { q1[0] = VIPS_D65_X0 * p1[0]; q1[1] = VIPS_D65_Y0 * p1[1]; q1[2] = VIPS_D65_Z0 * p1[2]; for (i = 3; i < samples_per_pixel; i++) q1[i] = p1[i]; q1 += samples_per_pixel; p1 += samples_per_pixel; } } /* LOGLUV images arrive from libtiff as float xyz. */ static int rtiff_parse_logluv(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_min_samples(rtiff, 3) || rtiff_check_interpretation(rtiff, PHOTOMETRIC_LOGLUV)) return -1; out->Bands = rtiff->header.samples_per_pixel; out->BandFmt = VIPS_FORMAT_FLOAT; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_XYZ; rtiff->sfn = rtiff_logluv_line; return 0; } /* Make a N-bit scanline process function. We pass in the code to expand the * bits down the byte since this does not generalize well. */ #define NBIT_LINE(N, EXPAND) \ static void \ rtiff_##N##bit_line(Rtiff *rtiff, \ VipsPel *q, VipsPel *p, int n, void *flg) \ { \ int photometric = rtiff->header.photometric_interpretation; \ int mask = photometric == PHOTOMETRIC_MINISBLACK ? 0 : 0xff; \ int bps = rtiff->header.bits_per_sample; \ int load = 8 / bps - 1; \ \ int x; \ VipsPel bits; \ \ /* Stop a compiler warning. \ */ \ bits = 0; \ \ for (x = 0; x < n; x++) { \ if ((x & load) == 0) \ /* Flip the bits for miniswhite. \ */ \ bits = *p++ ^ mask; \ \ EXPAND(q[x], bits); \ \ bits <<= bps; \ } \ } /* Expand the top bit down a byte. Use a sign-extending shift. */ #define EXPAND1(Q, BITS) \ G_STMT_START \ { \ (Q) = (((signed char) (BITS & 128)) >> 7); \ } \ G_STMT_END /* Expand the top two bits down a byte. Shift down, then expand up. */ #define EXPAND2(Q, BITS) \ G_STMT_START \ { \ VipsPel twobits = BITS >> 6; \ VipsPel fourbits = twobits | (twobits << 2); \ Q = fourbits | (fourbits << 4); \ } \ G_STMT_END /* Expand the top four bits down a byte. */ #define EXPAND4(Q, BITS) \ G_STMT_START \ { \ Q = (BITS & 0xf0) | (BITS >> 4); \ } \ G_STMT_END NBIT_LINE(1, EXPAND1) NBIT_LINE(2, EXPAND2) NBIT_LINE(4, EXPAND4) /* Read a 1-bit TIFF image. */ static int rtiff_parse_onebit(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_samples(rtiff, 1) || rtiff_check_bits(rtiff, 1)) return -1; out->Bands = 1; out->BandFmt = VIPS_FORMAT_UCHAR; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_B_W; rtiff->sfn = rtiff_1bit_line; return 0; } /* Read a 2-bit TIFF image. */ static int rtiff_parse_twobit(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_samples(rtiff, 1) || rtiff_check_bits(rtiff, 2)) return -1; out->Bands = 1; out->BandFmt = VIPS_FORMAT_UCHAR; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_B_W; rtiff->sfn = rtiff_2bit_line; return 0; } /* Read a 4-bit TIFF image. */ static int rtiff_parse_fourbit(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_samples(rtiff, 1) || rtiff_check_bits(rtiff, 4)) return -1; out->Bands = 1; out->BandFmt = VIPS_FORMAT_UCHAR; out->Coding = VIPS_CODING_NONE; out->Type = VIPS_INTERPRETATION_B_W; rtiff->sfn = rtiff_4bit_line; return 0; } /* Swap the sense of the first channel, if necessary. */ #define GREY_LOOP(TYPE, MAX) \ { \ TYPE *p1; \ TYPE *q1; \ \ p1 = (TYPE *) p; \ q1 = (TYPE *) q; \ for (x = 0; x < n; x++) { \ if (invert) \ q1[0] = MAX - p1[0]; \ else \ q1[0] = p1[0]; \ \ for (i = 1; i < samples_per_pixel; i++) \ q1[i] = p1[i]; \ \ q1 += samples_per_pixel; \ p1 += samples_per_pixel; \ } \ } /* GREY_LOOP implementation for 16-bit float */ #define GREY_LOOP_F16 \ { \ gushort *p1; \ float *q1; \ \ p1 = (gushort *) p; \ q1 = (float *) q; \ for (x = 0; x < n; x++) { \ if (invert) \ q1[0] = 1.0 - half_2_float(p1[0]); \ else \ q1[0] = half_2_float(p1[0]); \ \ for (i = 1; i < samples_per_pixel; i++) \ q1[i] = half_2_float(p1[i]); \ \ q1 += samples_per_pixel; \ p1 += samples_per_pixel; \ } \ } /* Per-scanline process function for greyscale images. */ static void rtiff_greyscale_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client) { int samples_per_pixel = rtiff->header.samples_per_pixel; int bits_per_sample = rtiff->header.bits_per_sample; int photometric_interpretation = rtiff->header.photometric_interpretation; VipsBandFormat format = rtiff_guess_format(rtiff); /* Swapping black and white doesn't make sense for the signed formats. */ gboolean invert = photometric_interpretation == PHOTOMETRIC_MINISWHITE && vips_band_format_isuint(format); int x, i; switch (format) { case VIPS_FORMAT_CHAR: GREY_LOOP(gchar, 0); break; case VIPS_FORMAT_UCHAR: GREY_LOOP(guchar, UCHAR_MAX); break; case VIPS_FORMAT_SHORT: GREY_LOOP(gshort, 0); break; case VIPS_FORMAT_USHORT: GREY_LOOP(gushort, USHRT_MAX); break; case VIPS_FORMAT_INT: GREY_LOOP(gint, 0); break; case VIPS_FORMAT_UINT: GREY_LOOP(guint, UINT_MAX); break; case VIPS_FORMAT_FLOAT: if (bits_per_sample == 16) { GREY_LOOP_F16; } else { GREY_LOOP(float, 1.0); } break; case VIPS_FORMAT_DOUBLE: GREY_LOOP(double, 1.0); break; default: g_assert_not_reached(); } } /* Read a grey-scale TIFF image. We have to invert the first band if * PHOTOMETRIC_MINISBLACK is set. */ static int rtiff_parse_greyscale(Rtiff *rtiff, VipsImage *out) { if (rtiff_check_min_samples(rtiff, 1) || rtiff_non_fractional(rtiff)) return -1; out->Bands = rtiff->header.samples_per_pixel; out->BandFmt = rtiff_guess_format(rtiff); if (out->BandFmt == VIPS_FORMAT_NOTSET) return -1; out->Coding = VIPS_CODING_NONE; if (rtiff->header.bits_per_sample == 16) out->Type = VIPS_INTERPRETATION_GREY16; else out->Type = VIPS_INTERPRETATION_B_W; /* rtiff_greyscale_line() doesn't do complex. */ if (vips_check_noncomplex("tiff2vips", out)) return -1; rtiff->sfn = rtiff_greyscale_line; return 0; } typedef struct { /* LUTs mapping image indexes to RGB. */ VipsPel *red8; VipsPel *green8; VipsPel *blue8; guint16 *red16; guint16 *green16; guint16 *blue16; /* All maps equal, so we write mono. */ gboolean mono; } PaletteRead; /* 1/2/4 bit samples with an 8-bit palette. */ static void rtiff_palette_line_bit(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client) { PaletteRead *read = (PaletteRead *) client; int samples_per_pixel = rtiff->header.samples_per_pixel; int bits_per_sample = rtiff->header.bits_per_sample; int bit; VipsPel data; int x; bit = 0; data = 0; for (x = 0; x < n * samples_per_pixel; x++) { int i; if (bit <= 0) { data = *p++; bit = 8; } i = data >> (8 - bits_per_sample); data <<= bits_per_sample; bit -= bits_per_sample; /* The first band goes through the LUT, subsequent bands are * left-justified and copied. */ if (x % samples_per_pixel == 0) { if (read->mono) *q++ = read->red8[i]; else { q[0] = read->red8[i]; q[1] = read->green8[i]; q[2] = read->blue8[i]; q += 3; } } else *q++ = VIPS_LSHIFT_INT(i, 8 - bits_per_sample); } } /* 8-bit samples with an 8-bit palette. */ static void rtiff_palette_line8(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client) { PaletteRead *read = (PaletteRead *) client; int samples_per_pixel = rtiff->header.samples_per_pixel; int x; int s; for (x = 0; x < n; x++) { int i = p[0]; if (read->mono) q[0] = read->red8[i]; else { q[0] = read->red8[i]; q[1] = read->green8[i]; q[2] = read->blue8[i]; q += 2; } for (s = 1; s < samples_per_pixel; s++) q[s] = p[s]; q += samples_per_pixel; p += samples_per_pixel; } } /* 16-bit samples with 16-bit data in the palette. */ static void rtiff_palette_line16(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client) { PaletteRead *read = (PaletteRead *) client; int samples_per_pixel = rtiff->header.samples_per_pixel; guint16 *p16, *q16; int x; int s; q16 = (guint16 *) q; p16 = (guint16 *) p; for (x = 0; x < n; x++) { int i = p16[0]; if (read->mono) q16[0] = read->red16[i]; else { q16[0] = read->red16[i]; q16[1] = read->green16[i]; q16[2] = read->blue16[i]; q16 += 2; } for (s = 1; s < samples_per_pixel; s++) q16[s] = p16[s]; q16 += samples_per_pixel; p16 += samples_per_pixel; } } /* Read a palette-ised TIFF image. */ static int rtiff_parse_palette(Rtiff *rtiff, VipsImage *out) { int samples_per_pixel = rtiff->header.samples_per_pixel; int bits_per_sample = rtiff->header.bits_per_sample; int len; PaletteRead *read; int i; if (rtiff_check_bits_palette(rtiff) || rtiff_check_min_samples(rtiff, 1)) return -1; len = 1 << bits_per_sample; if (!(read = VIPS_NEW(out, PaletteRead)) || !(read->red8 = VIPS_ARRAY(out, len, VipsPel)) || !(read->green8 = VIPS_ARRAY(out, len, VipsPel)) || !(read->blue8 = VIPS_ARRAY(out, len, VipsPel))) return -1; /* Get maps, convert to 8-bit data. */ if (!TIFFGetField(rtiff->tiff, TIFFTAG_COLORMAP, &read->red16, &read->green16, &read->blue16)) { vips_error("tiff2vips", "%s", _("bad colormap")); return -1; } /* Old-style colourmaps were 8-bit. If all the top bytes are zero, * assume we have one of these. * * See: https://github.com/libvips/libvips/issues/220 */ for (i = 0; i < len; i++) if ((read->red16[i] >> 8) | (read->green16[i] >> 8) | (read->blue16[i] >> 8)) break; if (i < len) for (i = 0; i < len; i++) { read->red8[i] = read->red16[i] >> 8; read->green8[i] = read->green16[i] >> 8; read->blue8[i] = read->blue16[i] >> 8; } else { g_warning("assuming 8-bit palette"); for (i = 0; i < len; i++) { read->red8[i] = read->red16[i] & 0xff; read->green8[i] = read->green16[i] & 0xff; read->blue8[i] = read->blue16[i] & 0xff; } } /* Are all the maps equal? We have a mono image. */ read->mono = TRUE; for (i = 0; i < len; i++) if (read->red16[i] != read->green16[i] || read->green16[i] != read->blue16[i]) { read->mono = FALSE; break; } /* There's a TIFF extension, INDEXED, that is the preferred way to * encode mono palette images, but few applications support it. So we * just search the colormap. */ if (bits_per_sample <= 8) out->BandFmt = VIPS_FORMAT_UCHAR; else out->BandFmt = VIPS_FORMAT_USHORT; out->Coding = VIPS_CODING_NONE; if (read->mono) { out->Bands = samples_per_pixel; if (bits_per_sample <= 8) out->Type = VIPS_INTERPRETATION_B_W; else out->Type = VIPS_INTERPRETATION_GREY16; } else { out->Bands = samples_per_pixel + 2; if (bits_per_sample <= 8) out->Type = VIPS_INTERPRETATION_sRGB; else out->Type = VIPS_INTERPRETATION_RGB16; } rtiff->client = read; if (bits_per_sample < 8) rtiff->sfn = rtiff_palette_line_bit; else if (bits_per_sample == 8) rtiff->sfn = rtiff_palette_line8; else if (bits_per_sample == 16) rtiff->sfn = rtiff_palette_line16; else g_assert_not_reached(); return 0; } /* Per-scanline process function when we just need to copy. */ static void rtiff_memcpy_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client) { VipsImage *im = (VipsImage *) client; size_t len = n * VIPS_IMAGE_SIZEOF_PEL(im); memcpy(q, p, len); } /* Per-scanline process function when we just need to copy. */ static void rtiff_memcpy_f16_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client) { VipsImage *im = (VipsImage *) client; size_t len = (size_t) n * im->Bands; if (im->BandFmt == VIPS_FORMAT_COMPLEX || im->BandFmt == VIPS_FORMAT_DPCOMPLEX) len *= 2; int i; gushort *restrict hp = (gushort *) p; float *restrict fq = (float *) q; for (i = 0; i < len; i++) fq[i] = half_2_float(hp[i]); } /* Read a regular multiband image where we can just copy pixels from the tiff * buffer. */ static int rtiff_parse_copy(Rtiff *rtiff, VipsImage *out) { int samples_per_pixel = rtiff->header.samples_per_pixel; int photometric_interpretation = rtiff->header.photometric_interpretation; int bits_per_sample = rtiff->header.bits_per_sample; int sample_format = rtiff->header.sample_format; int inkset = rtiff->header.inkset; if (rtiff_non_fractional(rtiff)) return -1; out->Bands = samples_per_pixel; out->BandFmt = rtiff_guess_format(rtiff); if (out->BandFmt == VIPS_FORMAT_NOTSET) return -1; out->Coding = VIPS_CODING_NONE; if (samples_per_pixel >= 3 && (photometric_interpretation == PHOTOMETRIC_RGB || photometric_interpretation == PHOTOMETRIC_YCBCR)) { if (out->BandFmt == VIPS_FORMAT_USHORT) out->Type = VIPS_INTERPRETATION_RGB16; else if (!vips_band_format_isint(out->BandFmt)) /* Most float images use 0 - 1 for black - white. * Photoshop uses 0 - 1 and no gamma. */ out->Type = VIPS_INTERPRETATION_scRGB; else out->Type = VIPS_INTERPRETATION_sRGB; } else if (samples_per_pixel >= 3 && photometric_interpretation == PHOTOMETRIC_CIELAB) out->Type = VIPS_INTERPRETATION_LAB; else if (photometric_interpretation == PHOTOMETRIC_SEPARATED && samples_per_pixel >= 4 && inkset == INKSET_CMYK) out->Type = VIPS_INTERPRETATION_CMYK; else out->Type = VIPS_INTERPRETATION_MULTIBAND; rtiff->client = out; if (bits_per_sample == 16 && sample_format == SAMPLEFORMAT_IEEEFP) { rtiff->sfn = rtiff_memcpy_f16_line; } else { rtiff->sfn = rtiff_memcpy_line; /* We expand YCBCR images to RGB using JPEGCOLORMODE_RGB, and this * means we need a slightly larger read buffer for the edge pixels. In * turn, this means we can't just memcpy to libvips regions. */ rtiff->memcpy = photometric_interpretation != PHOTOMETRIC_YCBCR; } return 0; } /* Read an image as RGBA using TIFFRGBAImage */ static int rtiff_parse_rgba(Rtiff *rtiff, VipsImage *out) { out->Bands = 4; out->Type = VIPS_INTERPRETATION_sRGB; out->BandFmt = VIPS_FORMAT_UCHAR; out->Coding = VIPS_CODING_NONE; rtiff->client = out; /* We'll have RGBA areas of exact size as we need, so we can just copy it */ rtiff->sfn = rtiff_memcpy_line; rtiff->memcpy = TRUE; return 0; } typedef int (*reader_fn)(Rtiff *rtiff, VipsImage *out); /* We have a range of output paths. Look at the tiff header and try to * route the input image to the best output path. */ static reader_fn rtiff_pick_reader(Rtiff *rtiff) { int bits_per_sample = rtiff->header.bits_per_sample; int photometric_interpretation = rtiff->header.photometric_interpretation; int samples_per_pixel = rtiff->header.samples_per_pixel; int read_as_rgba = rtiff->header.read_as_rgba; if (read_as_rgba) return rtiff_parse_rgba; if (photometric_interpretation == PHOTOMETRIC_CIELAB) { if (bits_per_sample == 8) { if (samples_per_pixel > 3) return rtiff_parse_lab_with_alpha; else return rtiff_parse_labpack; } if (bits_per_sample == 16) return rtiff_parse_labs; } if (photometric_interpretation == PHOTOMETRIC_LOGLUV) return rtiff_parse_logluv; if (photometric_interpretation == PHOTOMETRIC_MINISWHITE || photometric_interpretation == PHOTOMETRIC_MINISBLACK) { if (bits_per_sample == 1) return rtiff_parse_onebit; else if (bits_per_sample == 2) return rtiff_parse_twobit; else if (bits_per_sample == 4) return rtiff_parse_fourbit; else return rtiff_parse_greyscale; } if (photometric_interpretation == PHOTOMETRIC_PALETTE) return rtiff_parse_palette; return rtiff_parse_copy; } /* Set the header on @out from our rtiff. rtiff_header_read() has already been * called. */ static int rtiff_set_header(Rtiff *rtiff, VipsImage *out) { guint32 data_len; void *data; rtiff_set_decode_format(rtiff); if (rtiff->header.photometric_interpretation == PHOTOMETRIC_LOGLUV) vips_image_set_double(out, "stonits", rtiff->header.stonits); out->Xsize = rtiff->header.width; out->Ysize = rtiff->header.height * rtiff->n; VIPS_SETSTR(out->filename, vips_connection_filename(VIPS_CONNECTION(rtiff->source))); if (rtiff->n > 1) vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, rtiff->header.height); if (rtiff->header.subifd_count > 0) vips_image_set_int(out, VIPS_META_N_SUBIFDS, rtiff->header.subifd_count); vips_image_set_int(out, VIPS_META_N_PAGES, rtiff->n_pages); /* We have a range of output paths. Look at the tiff header and try to * route the input image to the best output path. */ if (rtiff_pick_reader(rtiff)(rtiff, out)) return -1; /* Read any ICC profile. */ if (TIFFGetField(rtiff->tiff, TIFFTAG_ICCPROFILE, &data_len, &data)) vips_image_set_blob_copy(out, VIPS_META_ICC_NAME, data, data_len); /* Read any XMP metadata. */ if (TIFFGetField(rtiff->tiff, TIFFTAG_XMLPACKET, &data_len, &data)) vips_image_set_blob_copy(out, VIPS_META_XMP_NAME, data, data_len); /* Read any IPTC metadata. */ if (TIFFGetField(rtiff->tiff, TIFFTAG_RICHTIFFIPTC, &data_len, &data)) { vips_image_set_blob_copy(out, VIPS_META_IPTC_NAME, data, data_len); /* Older versions of libvips used this misspelt name :-( attach * under this name too for compatibility. */ vips_image_set_blob_copy(out, "ipct-data", data, data_len); } /* Read any photoshop metadata. */ if (TIFFGetField(rtiff->tiff, TIFFTAG_PHOTOSHOP, &data_len, &data)) vips_image_set_blob_copy(out, VIPS_META_PHOTOSHOP_NAME, data, data_len); if (rtiff->header.image_description) vips_image_set_string(out, VIPS_META_IMAGEDESCRIPTION, rtiff->header.image_description); /* Hint the tile dimensions to our users. */ if (rtiff->header.tiled) { vips_image_set_int(out, VIPS_META_TILE_WIDTH, rtiff->header.tile_width); vips_image_set_int(out, VIPS_META_TILE_HEIGHT, rtiff->header.tile_height); } if (get_resolution(rtiff->tiff, out)) return -1; vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, rtiff->header.bits_per_sample); /* Set the "orientation" tag. This is picked up later by autorot, if * requested. */ vips_image_set_int(out, VIPS_META_ORIENTATION, rtiff->header.orientation); /* Hint smalltile for tiled images, since we may be decompressing * outside the lock and THINSTRIP would prevent parallel tile decode. */ vips_image_pipelinev(out, rtiff->header.tiled ? VIPS_DEMAND_STYLE_SMALLTILE : VIPS_DEMAND_STYLE_THINSTRIP, NULL); return 0; } /* Tilewise read sequence value. */ typedef struct _RtiffSeq { Rtiff *rtiff; /* Decompressed tile here. */ tdata_t *buf; /* If we are decompressing, we need a buffer to read the raw tile to * before running the decompressor. This needs to be per-thread, since * we decompress in parallel. */ tdata_t compressed_buf; tsize_t compressed_buf_length; } RtiffSeq; /* Allocate a tile buffer. Have one of these for each thread so we can unpack * to vips in parallel. */ static void * rtiff_seq_start(VipsImage *out, void *a, void *b) { Rtiff *rtiff = (Rtiff *) a; RtiffSeq *seq; if (!(seq = VIPS_NEW(out, RtiffSeq))) return NULL; seq->rtiff = rtiff; if (!(seq->buf = vips_malloc(NULL, rtiff->header.tile_size))) return NULL; /* If we will be decompressing, we need a buffer large enough to hold * the largest compressed tile in any page. * * Allocate a buffer 2x the uncompressed tile size ... much simpler * than searching every page for the largest tile with * TIFFTAG_TILEBYTECOUNTS. */ if (rtiff->header.we_decompress) { seq->compressed_buf_length = 2 * rtiff->header.tile_size; if (!(seq->compressed_buf = VIPS_MALLOC(NULL, seq->compressed_buf_length))) return NULL; } return (void *) seq; } #ifdef HAVE_JPEG static void rtiff_decompress_jpeg_init_source(j_decompress_ptr cinfo) { /* Nothing. */ } static boolean rtiff_decompress_jpeg_fill_input_buffer(j_decompress_ptr cinfo) { static const JOCTET mybuffer[4] = { (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 }; /* The whole JPEG data is expected to reside in the supplied memory * buffer, so any request for more data beyond the given buffer size * is treated as an error. */ WARNMS(cinfo, JWRN_VIPS_IMAGE_EOF); /* Insert a fake EOI marker */ cinfo->src->next_input_byte = mybuffer; cinfo->src->bytes_in_buffer = 2; return TRUE; } /* Skip data -- used to skip over a potentially large amount of * uninteresting data (such as an APPn marker). * * Writers of suspendable-input applications must note that skip_input_data * is not granted the right to give a suspension return. If the skip extends * beyond the data currently in the buffer, the buffer can be marked empty so * that the next read will cause a fill_input_buffer call that can suspend. * Arranging for additional bytes to be discarded before reloading the input * buffer is the application writer's problem. */ static void rtiff_decompress_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { struct jpeg_source_mgr *src = cinfo->src; /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway -- large skips are infrequent. */ if (num_bytes > 0) { while (num_bytes > (long) src->bytes_in_buffer) { num_bytes -= (long) src->bytes_in_buffer; (void) (*src->fill_input_buffer)(cinfo); /* note we assume that fill_input_buffer will never * return FALSE, so suspension need not be handled. */ } src->next_input_byte += (size_t) num_bytes; src->bytes_in_buffer -= (size_t) num_bytes; } } static void rtiff_decompress_jpeg_set_memory(j_decompress_ptr cinfo, void *data, size_t data_len) { if (!cinfo->src) cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)( (j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr)); /* Present the whole of data as one chunk. */ cinfo->src->bytes_in_buffer = data_len; cinfo->src->next_input_byte = (JOCTET *) data; cinfo->src->init_source = rtiff_decompress_jpeg_init_source; cinfo->src->fill_input_buffer = rtiff_decompress_jpeg_fill_input_buffer; cinfo->src->skip_input_data = rtiff_decompress_jpeg_skip_input_data; cinfo->src->resync_to_restart = jpeg_resync_to_restart; } static int rtiff_decompress_jpeg_run(Rtiff *rtiff, j_decompress_ptr cinfo, void *data, size_t data_len, void *out) { void *tables; uint32_t tables_len; int bytes_per_pixel; size_t bytes_per_scanline; VipsPel *q; int y; #ifdef DEBUG_VERBOSE printf("rtiff_decompress_jpeg_run: decompressing %zd bytes of jpg\n", data_len); #endif /*DEBUG_VERBOSE*/ /* Tables are optional. */ tables = NULL; tables_len = 0; (void) TIFFGetField(rtiff->tiff, TIFFTAG_JPEGTABLES, &tables_len, &tables); if (tables) { rtiff_decompress_jpeg_set_memory(cinfo, tables, tables_len); if (jpeg_read_header(cinfo, FALSE) != JPEG_HEADER_TABLES_ONLY) return -1; } rtiff_decompress_jpeg_set_memory(cinfo, data, data_len); if (jpeg_read_header(cinfo, TRUE) != JPEG_HEADER_OK) return -1; /* This isn't stored in the tile -- we have to set it from the * enclosing TIFF. */ switch (rtiff->header.photometric_interpretation) { case PHOTOMETRIC_SEPARATED: cinfo->jpeg_color_space = JCS_CMYK; bytes_per_pixel = 4; break; case PHOTOMETRIC_YCBCR: cinfo->jpeg_color_space = JCS_YCbCr; bytes_per_pixel = 3; break; case PHOTOMETRIC_RGB: case PHOTOMETRIC_CIELAB: // RGB-compressed CIELAB is a possibility, amazingly cinfo->jpeg_color_space = JCS_RGB; bytes_per_pixel = 3; break; case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: cinfo->jpeg_color_space = JCS_GRAYSCALE; bytes_per_pixel = 1; break; default: cinfo->jpeg_color_space = JCS_UNKNOWN; bytes_per_pixel = 1; break; } /* bytes_per_pixel from photometric_interpretation must match the number * of components in the JPEG compressed tile. */ jpeg_calc_output_dimensions(cinfo); if (cinfo->output_components != bytes_per_pixel) return -1; bytes_per_scanline = (size_t) cinfo->output_width * bytes_per_pixel; /* Double-check tile dimensions. */ if (cinfo->output_width > rtiff->header.tile_width || cinfo->output_height > rtiff->header.tile_height || bytes_per_scanline > rtiff->header.tile_row_size) return -1; jpeg_start_decompress(cinfo); q = (VipsPel *) out; for (y = 0; y < cinfo->output_height; y++) { JSAMPROW row_pointer[1]; row_pointer[0] = (JSAMPLE *) q; jpeg_read_scanlines(cinfo, &row_pointer[0], 1); q += bytes_per_scanline; } return 0; } static void rtiff_decompress_jpeg_emit_message(j_common_ptr cinfo, int msg_level) { if (msg_level < 0) { long num_warnings; /* Always count warnings in num_warnings. */ num_warnings = ++cinfo->err->num_warnings; /* Corrupt files may give many warnings, the policy here is to * show only the first warning and treat many warnings as fatal, * unless unlimited is set. */ if (num_warnings == 1) (*cinfo->err->output_message)(cinfo); } else if (cinfo->err->trace_level >= msg_level) /* It's a trace message. Show it if trace_level >= msg_level. */ (*cinfo->err->output_message)(cinfo); } /* Decompress a tile of size coefficients into out. */ static int rtiff_decompress_jpeg(Rtiff *rtiff, void *data, size_t data_len, void *out) { struct jpeg_decompress_struct cinfo = { 0 }; ErrorManager eman; if (setjmp(eman.jmp) == 0) { cinfo.err = jpeg_std_error(&eman.pub); cinfo.err->addon_message_table = vips__jpeg_message_table; cinfo.err->first_addon_message = 1000; cinfo.err->last_addon_message = 1001; eman.pub.error_exit = vips__new_error_exit; eman.pub.emit_message = rtiff_decompress_jpeg_emit_message; eman.pub.output_message = vips__new_output_message; eman.fp = NULL; jpeg_create_decompress(&cinfo); if (rtiff_decompress_jpeg_run(rtiff, &cinfo, data, data_len, out)) { jpeg_destroy_decompress(&cinfo); return -1; } } else { #ifdef DEBUG_VERBOSE printf("rtiff_decompress_jpeg: error return\n"); #endif /*DEBUG_VERBOSE*/ jpeg_destroy_decompress(&cinfo); return -1; } jpeg_destroy_decompress(&cinfo); return 0; } #endif /*HAVE_JPEG*/ static int rtiff_decompress_tile(Rtiff *rtiff, tdata_t *in, tsize_t size, tdata_t *out) { g_assert(rtiff->header.we_decompress); switch (rtiff->header.compression) { case JP2K_YCC: case JP2K_RGB: case JP2K_LOSSY: if (vips__foreign_load_jp2k_decompress( rtiff->out, rtiff->header.tile_width, rtiff->header.tile_height, TRUE, in, size, out, rtiff->header.tile_size)) return -1; break; #ifdef HAVE_JPEG case COMPRESSION_JPEG: if (rtiff_decompress_jpeg(rtiff, in, size, out)) return -1; break; #endif /*HAVE_JPEG*/ default: g_assert_not_reached(); break; } return 0; } /* Decompress a tile to RGBA */ static int rtiff_read_rgba_tile(Rtiff *rtiff, int x, int y, tdata_t *buf) { guint32 *u32_buf = (guint32 *) buf; if (!TIFFReadRGBATile(rtiff->tiff, x, y, u32_buf)) return -1; /* For some reason TIFFReadRGBATile decodes tiles upside down, * so we need to flip them. */ guint32 tile_width = rtiff->header.tile_width; guint32 tile_height = rtiff->header.tile_height; guint32 *up = u32_buf; guint32 *down = u32_buf + (tile_height - 1) * tile_width; for (int yy = 0; yy < tile_height / 2; yy++) { for (int xx = 0; xx < tile_width; xx++) VIPS_SWAP(guint32, up[xx], down[xx]); up += tile_width; down -= tile_width; } return 0; } /* Select a page and decompress a tile. This has to be a single operation, * since it changes the current page number in TIFF. */ static int rtiff_read_tile(RtiffSeq *seq, tdata_t *buf, int page, int x, int y) { Rtiff *rtiff = seq->rtiff; tsize_t size; #ifdef DEBUG_VERBOSE printf("rtiff_read_tile: page = %d, x = %d, y = %d, " "we_decompress = %d\n", page, x, y, rtiff->header.we_decompress); #endif /*DEBUG_VERBOSE*/ /* Compressed tiles load to compressed_buf. */ if (rtiff->header.we_decompress) { ttile_t tile_no; g_rec_mutex_lock(&rtiff->lock); if (rtiff_set_page(rtiff, page)) { g_rec_mutex_unlock(&rtiff->lock); return -1; } tile_no = TIFFComputeTile(rtiff->tiff, x, y, 0, 0); size = TIFFReadRawTile(rtiff->tiff, tile_no, seq->compressed_buf, seq->compressed_buf_length); if (size <= 0) { vips_foreign_load_invalidate(rtiff->out); g_rec_mutex_unlock(&rtiff->lock); return -1; } g_rec_mutex_unlock(&rtiff->lock); /* Decompress outside the lock, so we get parallelism. */ if (rtiff_decompress_tile(rtiff, seq->compressed_buf, size, buf)) { vips_error("tiff2vips", _("decompress error tile %d x %d"), x, y); return -1; } } else { g_rec_mutex_lock(&rtiff->lock); if (rtiff_set_page(rtiff, page)) { g_rec_mutex_unlock(&rtiff->lock); return -1; } int result; if (rtiff->header.read_as_rgba) result = rtiff_read_rgba_tile(rtiff, x, y, buf); else result = TIFFReadTile(rtiff->tiff, buf, x, y, 0, 0) < 0; if (result && rtiff->fail_on >= VIPS_FAIL_ON_WARNING) { vips_foreign_load_invalidate(rtiff->out); g_rec_mutex_unlock(&rtiff->lock); return -1; } g_rec_mutex_unlock(&rtiff->lock); } return 0; } /* Paint a tile from the file. This is a * special-case for when a region is exactly a tiff tile, and pixels need no * conversion. In this case, libtiff can read tiles directly to our output * region. */ static int rtiff_fill_region_aligned(VipsRegion *out, void *vseq, void *a, void *b, gboolean *stop) { RtiffSeq *seq = (RtiffSeq *) vseq; Rtiff *rtiff = (Rtiff *) a; VipsRect *r = &out->valid; int page_height = rtiff->header.height; int page_no = r->top / page_height; int page_y = r->top % page_height; g_assert((r->left % rtiff->header.tile_width) == 0); g_assert((r->top % rtiff->header.tile_height) == 0); g_assert(r->width == rtiff->header.tile_width); g_assert(r->height == rtiff->header.tile_height); g_assert(VIPS_REGION_LSKIP(out) == VIPS_REGION_SIZEOF_LINE(out)); #ifdef DEBUG_VERBOSE printf("rtiff_fill_region_aligned:\n"); #endif /*DEBUG_VERBOSE*/ /* Read that tile directly into the vips tile. */ if (rtiff_read_tile(seq, (tdata_t *) VIPS_REGION_ADDR(out, r->left, r->top), rtiff->page + page_no, r->left, page_y)) return -1; return 0; } /* Loop over the output region, painting in tiles from the file. */ static int rtiff_fill_region_unaligned(VipsRegion *out, void *vseq, void *a, void *b, gboolean *stop) { RtiffSeq *seq = (RtiffSeq *) vseq; Rtiff *rtiff = (Rtiff *) a; int tile_width = rtiff->header.tile_width; int tile_height = rtiff->header.tile_height; int page_height = rtiff->header.height; int tile_row_size = rtiff->header.tile_row_size; VipsRect *r = &out->valid; int x, y, z; #ifdef DEBUG_VERBOSE printf("rtiff_fill_region_unaligned:\n"); #endif /*DEBUG_VERBOSE*/ y = 0; while (y < r->height) { VipsRect tile, page, hit; /* Not necessary, but it stops static analyzers complaining * about a used-before-set. */ hit.height = 0; x = 0; while (x < r->width) { /* page_no is within this toilet roll image, not tiff * file page number ... add the number of the start * page to get that. */ int page_no = (r->top + y) / page_height; int page_y = (r->top + y) % page_height; /* Coordinate of the tile on this page that xy falls in. */ int xs = ((r->left + x) / tile_width) * tile_width; int ys = (page_y / tile_height) * tile_height; if (rtiff_read_tile(seq, seq->buf, rtiff->page + page_no, xs, ys)) return -1; /* Position of tile on the page. */ tile.left = xs; tile.top = ys; tile.width = tile_width; tile.height = tile_height; /* It'll be clipped by this page. */ page.left = 0; page.top = 0; page.width = rtiff->header.width; page.height = rtiff->header.height; vips_rect_intersectrect(&tile, &page, &tile); /* To image coordinates. */ tile.top += page_no * page_height; /* And clip again by this region. */ vips_rect_intersectrect(&tile, r, &hit); /* We are inside a tilecache, so requests will always * be aligned left-right to tile boundaries. * * this is not true vertically for toilet-roll images. */ g_assert(hit.left == tile.left); /* Unpack to VIPS format. * Just unpack the section of the tile we need. */ for (z = 0; z < hit.height; z++) { VipsPel *p = (VipsPel *) seq->buf + (hit.top - tile.top + z) * tile_row_size; VipsPel *q = VIPS_REGION_ADDR(out, hit.left, hit.top + z); rtiff->sfn(rtiff, q, p, hit.width, rtiff->client); } x += hit.width; } /* This will be the same for all tiles in the row we've just * done. */ y += hit.height; } return 0; } /* Loop over the output region, painting in tiles from the file. */ static int rtiff_fill_region(VipsRegion *out, void *vseq, void *a, void *b, gboolean *stop) { Rtiff *rtiff = (Rtiff *) a; int tile_width = rtiff->header.tile_width; int tile_height = rtiff->header.tile_height; int page_width = rtiff->header.width; int page_height = rtiff->header.height; VipsRect *r = &out->valid; int page_no = r->top / page_height; int page_y = r->top % page_height; VipsGenerateFn generate; #ifdef DEBUG_VERBOSE printf("rtiff_fill_region: left = %d, top = %d, " "width = %d, height = %d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG_VERBOSE*/ /* Special case: we are filling a single cache tile exactly sized to * match the tiff tile, and we have no repacking to do for this format. * * If we are not on the first page, pages must be a multiple of the * tile size of we'll miss alignment. */ if ((page_no == 0 || page_height % tile_height == 0) && r->left % tile_width == 0 && r->top % tile_height == 0 && r->width == tile_width && r->height == tile_height && r->left + tile_width <= page_width && page_y + tile_height <= page_height && VIPS_REGION_LSKIP(out) == VIPS_REGION_SIZEOF_LINE(out) && rtiff->memcpy) generate = rtiff_fill_region_aligned; else generate = rtiff_fill_region_unaligned; VIPS_GATE_START("rtiff_fill_region: work"); if (generate(out, vseq, a, b, stop)) { VIPS_GATE_STOP("rtiff_fill_region: work"); return -1; } VIPS_GATE_STOP("rtiff_fill_region: work"); return 0; } static int rtiff_seq_stop(void *vseq, void *a, void *b) { RtiffSeq *seq = (RtiffSeq *) vseq; VIPS_FREE(seq->buf); VIPS_FREE(seq->compressed_buf); return 0; } /* Unpremultiply associative alpha, if any. */ static int rtiff_unpremultiply(Rtiff *rtiff, VipsImage *in, VipsImage **out) { if (rtiff->header.alpha_band != -1) { VipsImage *x; if ( vips_unpremultiply(in, &x, "alpha_band", rtiff->header.alpha_band, NULL) || vips_cast(x, out, in->BandFmt, NULL)) { g_object_unref(x); return -1; } g_object_unref(x); } else { *out = in; g_object_ref(in); } return 0; } /* Tile-type TIFF reader core - pass in a per-tile transform. Generate into * the im and do it all partially. */ static int rtiff_read_tilewise(Rtiff *rtiff, VipsImage *out) { int tile_width = rtiff->header.tile_width; int tile_height = rtiff->header.tile_height; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 4); VipsImage *in; #ifdef DEBUG printf("tiff2vips: rtiff_read_tilewise\n"); #endif /*DEBUG*/ /* I don't have a sample images for tiled + separate, ban it for now. */ if (rtiff->header.separate) { vips_error("tiff2vips", "%s", _("tiled separate planes not supported")); return -1; } /* Read to this image, then cache to out, see below. */ t[0] = vips_image_new(); if (rtiff_set_header(rtiff, t[0])) return -1; /* Double check: in memcpy mode, the vips tilesize should exactly * match the tifftile size. */ if (rtiff->memcpy) { size_t vips_tile_size = VIPS_IMAGE_SIZEOF_PEL(t[0]) * tile_width * tile_height; if (rtiff->header.tile_size != vips_tile_size) { vips_error("tiff2vips", "%s", _("unsupported tiff image type")); return -1; } } /* Generate to out, adding a cache. Enough tiles for two complete rows. * Set "threaded", so we allow many tiles to be read at once. We lock * around each tile read. */ if ( vips_image_generate(t[0], rtiff_seq_start, rtiff_fill_region, rtiff_seq_stop, rtiff, NULL) || vips_tilecache(t[0], &t[1], "tile_width", tile_width, "tile_height", tile_height, "max_tiles", 2 * (1 + t[0]->Xsize / tile_width), "threaded", TRUE, NULL) || rtiff_unpremultiply(rtiff, t[1], &t[2])) return -1; in = t[2]; /* Only do this if we have to. */ if (rtiff->autorotate && vips_image_get_orientation(in) != 1) { if (vips_autorot(in, &t[3], NULL)) return -1; in = t[3]; } if (vips_image_write(in, out)) return -1; return 0; } /* Read a strip from a page. If the image is in separate planes, read each * plane and interleave to the output. * * No need to lock -- this is inside a sequential. */ static int rtiff_strip_read_interleaved(Rtiff *rtiff, int page, tstrip_t strip, tdata_t buf) { int samples_per_pixel = rtiff->header.samples_per_pixel; int read_height = rtiff->header.read_height; int bits_per_sample = rtiff->header.bits_per_sample; int read_as_rgba = rtiff->header.read_as_rgba; int strip_y = strip * read_height; if (rtiff_set_page(rtiff, page)) return -1; if (read_as_rgba) { if (rtiff_rgba_strip_read(rtiff, strip, buf)) return -1; } else if (rtiff->header.separate) { int page_width = rtiff->header.width; int page_height = rtiff->header.height; int strips_per_plane = 1 + (page_height - 1) / read_height; int strip_height = VIPS_MIN(read_height, page_height - strip_y); int pels_per_strip = page_width * strip_height; int bytes_per_sample = bits_per_sample >> 3; int i, j, k; for (i = 0; i < samples_per_pixel; i++) { VipsPel *p; VipsPel *q; if (rtiff_strip_read(rtiff, strips_per_plane * i + strip, rtiff->plane_buf)) return -1; p = (VipsPel *) rtiff->plane_buf; q = i * bytes_per_sample + (VipsPel *) buf; for (j = 0; j < pels_per_strip; j++) { for (k = 0; k < bytes_per_sample; k++) q[k] = p[k]; p += bytes_per_sample; q += bytes_per_sample * samples_per_pixel; } } } else { if (rtiff_strip_read(rtiff, strip, buf)) return -1; } return 0; } static int rtiff_stripwise_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsImage *out = out_region->im; Rtiff *rtiff = (Rtiff *) a; int read_height = rtiff->header.read_height; int page_height = rtiff->header.height; tsize_t scanline_size = rtiff->header.scanline_size; VipsRect *r = &out_region->valid; int y; #ifdef DEBUG_VERBOSE printf("rtiff_stripwise_generate: top = %d, height = %d\n", r->top, r->height); printf("rtiff_stripwise_generate: y_top = %d\n", rtiff->y_pos); #endif /*DEBUG_VERBOSE*/ /* We're inside a tilecache where tiles are the full image width, so * this should always be true. */ g_assert(r->left == 0); g_assert(r->width == out_region->im->Xsize); g_assert(VIPS_RECT_BOTTOM(r) <= out_region->im->Ysize); /* If we're reading more than one page, tiles won't fall on strip * boundaries. Tiles may be contain several strips. */ /* Check that y_pos is correct. It should be, since we are inside * a vips_sequential(). */ if (r->top != rtiff->y_pos) { vips_error("tiff2vips", _("out of order read -- at line %d, but line %d requested"), rtiff->y_pos, r->top); return -1; } VIPS_GATE_START("rtiff_stripwise_generate: work"); y = 0; while (y < r->height) { /* page_no is within this toilet roll image, not tiff * file page number ... add the number of the start * page to get that. */ int page_no = (r->top + y) / page_height; int y_page = (r->top + y) % page_height; /* Strip number. */ tstrip_t strip_no = y_page / read_height; VipsRect image, page, strip, hit; /* Our four (including the output region) rects, all in * output image coordinates. */ image.left = 0; image.top = 0; image.width = out->Xsize; image.height = out->Ysize; page.left = 0; page.top = page_height * ((r->top + y) / page_height); page.width = out->Xsize; page.height = page_height; strip.left = 0; strip.top = page.top + strip_no * read_height; strip.width = out->Xsize; strip.height = read_height; /* Clip strip against page and image ... the final strip will * be smaller. */ vips_rect_intersectrect(&strip, &image, &strip); vips_rect_intersectrect(&strip, &page, &strip); /* Now the bit that overlaps with the region we are filling. */ vips_rect_intersectrect(&strip, r, &hit); g_assert(hit.height > 0); /* Read directly into the image if we can. Otherwise, we must * read to a temp buffer then unpack into the image. * * We need to read via a buffer if we need to reformat pixels, * or if this strip is not aligned on a tile boundary. */ if (rtiff->memcpy && hit.top == strip.top && hit.height == strip.height) { if (rtiff_strip_read_interleaved(rtiff, rtiff->page + page_no, strip_no, VIPS_REGION_ADDR(out_region, 0, r->top + y))) { VIPS_GATE_STOP( "rtiff_stripwise_generate: work"); return -1; } } else { VipsPel *p; VipsPel *q; int z; /* Read and interleave the entire strip. */ if (rtiff_strip_read_interleaved(rtiff, rtiff->page + page_no, strip_no, rtiff->contig_buf)) { VIPS_GATE_STOP( "rtiff_stripwise_generate: work"); return -1; } /* Do any repacking to generate pixels in vips layout. */ p = (VipsPel *) rtiff->contig_buf + (hit.top - strip.top) * scanline_size; q = VIPS_REGION_ADDR(out_region, 0, r->top + y); for (z = 0; z < hit.height; z++) { rtiff->sfn(rtiff, q, p, out_region->im->Xsize, rtiff->client); p += scanline_size; q += VIPS_REGION_LSKIP(out_region); } } y += hit.height; rtiff->y_pos += hit.height; } VIPS_GATE_STOP("rtiff_stripwise_generate: work"); return 0; } /* Stripwise reading. * * We could potentially read strips in any order, but this would give * catastrophic performance for operations like 90 degrees rotate on a * large image. Only offer sequential read. */ static int rtiff_read_stripwise(Rtiff *rtiff, VipsImage *out) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 4); VipsImage *in; int tile_height; #ifdef DEBUG printf("tiff2vips: rtiff_read_stripwise\n"); #endif /*DEBUG*/ t[0] = vips_image_new(); if (rtiff_set_header(rtiff, t[0])) return -1; /* Double check: in memcpy mode, the vips linesize should exactly * match the tiff line size. */ if (rtiff->memcpy) { size_t vips_line_size; /* Lines are smaller in plane-separated mode. */ if (rtiff->header.separate) vips_line_size = VIPS_IMAGE_SIZEOF_ELEMENT(t[0]) * t[0]->Xsize; else vips_line_size = VIPS_IMAGE_SIZEOF_LINE(t[0]); if (rtiff->header.bits_per_sample == 16 && rtiff->header.sample_format == SAMPLEFORMAT_IEEEFP) vips_line_size /= 2; if (vips_line_size != rtiff->header.scanline_size) { vips_error("tiff2vips", "%s", _("unsupported tiff image type")); return -1; } } /* If we have separate image planes, we must read to a plane buffer, * then interleave to the output. * * We don't need a separate buffer per thread since the _generate() * function runs inside the cache lock. */ if (rtiff->header.separate) { if (!(rtiff->plane_buf = VIPS_MALLOC(out, rtiff->header.read_size))) return -1; } /* If we need to manipulate pixels, we must read to an interleaved * plane buffer before repacking to the output. * * If we are doing a multi-page read, we need a strip buffer, since * strips may not be aligned on tile boundaries. * * We don't need a separate buffer per thread since the _generate() * function runs inside the cache lock. */ if (!rtiff->memcpy || rtiff->n > 1) { tsize_t size; size = rtiff->header.read_size; if (rtiff->header.separate) size *= rtiff->header.samples_per_pixel; if (!(rtiff->contig_buf = VIPS_MALLOC(out, size))) return -1; } /* rows_per_strip can be very large if this is a separate plane image, * beware. * * Some images have very small rowsperstrip which will cause a lot of * work for the tilecache -- set a min size for tiles which is a * multiple of rowsperstrip. */ tile_height = VIPS_MAX( VIPS_ROUND_DOWN(16, rtiff->header.read_height), rtiff->header.read_height); if ( vips_image_generate(t[0], NULL, rtiff_stripwise_generate, NULL, rtiff, NULL) || vips_sequential(t[0], &t[1], "tile_height", tile_height, NULL) || rtiff_unpremultiply(rtiff, t[1], &t[2])) return -1; in = t[2]; /* Only do this if we have to. */ if (rtiff->autorotate && vips_image_get_orientation(in) != 1) { if (vips_autorot(in, &t[3], NULL)) return -1; in = t[3]; } if (vips_image_write(in, out)) return -1; return 0; } /* Load from a tiff dir into one of our tiff header structs. */ static int rtiff_header_read(Rtiff *rtiff, RtiffHeader *header) { int i; guint16 extra_samples_count; guint16 *extra_samples_types; guint16 subifd_count; toff_t *subifd_offsets; char *image_description; guint32 max_tile_dimension; gboolean can_read_as_rgba; if (!tfget32(rtiff->tiff, TIFFTAG_IMAGEWIDTH, &header->width) || !tfget32(rtiff->tiff, TIFFTAG_IMAGELENGTH, &header->height) || !tfget16(rtiff->tiff, TIFFTAG_SAMPLESPERPIXEL, &header->samples_per_pixel) || !tfget16(rtiff->tiff, TIFFTAG_BITSPERSAMPLE, &header->bits_per_sample) || !tfget16(rtiff->tiff, TIFFTAG_PHOTOMETRIC, &header->photometric_interpretation) || !tfget16(rtiff->tiff, TIFFTAG_INKSET, &header->inkset)) return -1; header->read_as_rgba = FALSE; /* TIFF images which can be read by TIFFRGBAImage or TIFFReadRGBATile. */ can_read_as_rgba = (header->samples_per_pixel == 1 || header->samples_per_pixel == 3 || header->samples_per_pixel == 4) && (header->bits_per_sample == 1 || header->bits_per_sample == 2 || header->bits_per_sample == 4 || header->bits_per_sample == 8 || header->bits_per_sample == 16); TIFFGetFieldDefaulted(rtiff->tiff, TIFFTAG_COMPRESSION, &header->compression); /* We'll decode old-style JPEG using the libtiff RGBA path. */ if (header->compression == COMPRESSION_OJPEG) { if (!can_read_as_rgba) { vips_error("tiff2vips", "%s", _("unsupported tiff image type")); return -1; } header->read_as_rgba = TRUE; } /* One of the types we decompress? */ for (i = 0; i < VIPS_NUMBER(rtiff_we_decompress); i++) if (header->compression == rtiff_we_decompress[i]) { #ifdef DEBUG printf("rtiff_header_read: compression %d handled by us\n", header->compression); #endif /*DEBUG*/ header->we_decompress = TRUE; break; } /* We must set this here since it'll change the value of scanline_size. */ rtiff_set_decode_format(rtiff); /* If there's YCbCr chroma subsampling and we're not already using one of * the JPEG decompressors, use the libtiff RGBA path. */ if (!header->read_as_rgba && header->compression != COMPRESSION_JPEG && header->photometric_interpretation == PHOTOMETRIC_YCBCR) { guint16 hsub, vsub; TIFFGetFieldDefaulted(rtiff->tiff, TIFFTAG_YCBCRSUBSAMPLING, &hsub, &vsub); if (hsub != 1 || vsub != 1) { if (!can_read_as_rgba) { vips_error("tiff2vips", "%s", _("subsampled images not supported")); return -1; } header->read_as_rgba = TRUE; } } if (header->photometric_interpretation == PHOTOMETRIC_LOGLUV) { if (header->compression != COMPRESSION_SGILOG && header->compression != COMPRESSION_SGILOG24) { vips_error("tiff2vips", "%s", _("not SGI-compressed LOGLUV")); return -1; } } /* For logluv, the calibration factor to get to absolute luminance. */ if (!TIFFGetField(rtiff->tiff, TIFFTAG_STONITS, &header->stonits)) header->stonits = 1.0; /* Arbitrary sanity-checking limits. */ if (header->width <= 0 || header->width >= VIPS_MAX_COORD || header->height <= 0 || header->height >= VIPS_MAX_COORD) { vips_error("tiff2vips", "%s", _("width/height out of range")); return -1; } if (header->samples_per_pixel <= 0 || header->samples_per_pixel > 10000 || header->bits_per_sample <= 0 || header->bits_per_sample > 32) { vips_error("tiff2vips", "%s", _("samples out of range")); return -1; } header->sample_format = get_sample_format(rtiff->tiff); header->orientation = get_orientation(rtiff->tiff); header->separate = FALSE; if (tfexists(rtiff->tiff, TIFFTAG_PLANARCONFIG)) { int v; if (!tfget16(rtiff->tiff, TIFFTAG_PLANARCONFIG, &v)) return -1; if (v == PLANARCONFIG_SEPARATE) header->separate = TRUE; } /* TIFFGetField needs a guint16 to write count to. */ if (TIFFGetField(rtiff->tiff, TIFFTAG_SUBIFD, &subifd_count, &subifd_offsets)) header->subifd_count = subifd_count; /* IMAGEDESCRIPTION often has useful metadata. libtiff makes sure * that data is null-terminated and contains no embedded null * characters. */ if (TIFFGetField(rtiff->tiff, TIFFTAG_IMAGEDESCRIPTION, &image_description)) header->image_description = vips_strdup(VIPS_OBJECT(rtiff->out), image_description); /* Tiles and strip images have slightly different fields. */ header->tiled = TIFFIsTiled(rtiff->tiff); if (header->read_as_rgba) { header->we_decompress = FALSE; header->photometric_interpretation = PHOTOMETRIC_RGB; header->samples_per_pixel = 4; header->bits_per_sample = 8; header->sample_format = SAMPLEFORMAT_UINT; header->separate = FALSE; } #ifdef DEBUG printf("rtiff_header_read: header.read_as_rgba = %d\n", header->read_as_rgba); printf("rtiff_header_read: header.width = %d\n", header->width); printf("rtiff_header_read: header.height = %d\n", header->height); printf("rtiff_header_read: header.samples_per_pixel = %d\n", header->samples_per_pixel); printf("rtiff_header_read: header.bits_per_sample = %d\n", header->bits_per_sample); printf("rtiff_header_read: header.sample_format = %d\n", header->sample_format); printf("rtiff_header_read: header.orientation = %d\n", header->orientation); printf("rtiff_header_read: header.tiled = %d\n", header->tiled); #endif /*DEBUG*/ if (header->tiled) { if (!tfget32(rtiff->tiff, TIFFTAG_TILEWIDTH, &header->tile_width) || !tfget32(rtiff->tiff, TIFFTAG_TILELENGTH, &header->tile_height)) return -1; #ifdef DEBUG printf("rtiff_header_read: header.tile_width = %d\n", header->tile_width); printf("rtiff_header_read: header.tile_height = %d\n", header->tile_height); #endif /*DEBUG*/ /* Arbitrary sanity-checking limits. */ max_tile_dimension = VIPS_MIN(8192, VIPS_ROUND_UP(2 * VIPS_MAX(header->width, header->height), 256)); if (header->tile_width <= 0 || header->tile_width > max_tile_dimension || header->tile_width % 16 != 0 || header->tile_height <= 0 || header->tile_height > max_tile_dimension || header->tile_height % 16 != 0) { vips_error("tiff2vips", "%s", _("tile size out of range")); return -1; } if (header->read_as_rgba) { header->tile_row_size = header->tile_width * 4; header->tile_size = header->tile_row_size * header->tile_height; } else { header->tile_size = TIFFTileSize(rtiff->tiff); header->tile_row_size = TIFFTileRowSize(rtiff->tiff); } #ifdef DEBUG printf("rtiff_header_read: header.tile_size = %zd\n", header->tile_size); printf("rtiff_header_read: header.tile_row_size = %zd\n", header->tile_row_size); #endif /*DEBUG*/ /* Fuzzed TIFFs can give crazy values for tile_size. Sanity * check at 100mb per tile. */ if (header->tile_size <= 0 || header->tile_size > 100 * 1000 * 1000 || header->tile_row_size <= 0 || header->tile_row_size > 100 * 1000 * 1000) { vips_error("tiff2vips", "%s", _("tile size out of range")); return -1; } /* Stop some compiler warnings. */ header->rows_per_strip = 0; header->strip_size = 0; header->number_of_strips = 0; header->read_height = 0; header->read_size = 0; } else { if (!tfget32(rtiff->tiff, TIFFTAG_ROWSPERSTRIP, &header->rows_per_strip)) return -1; /* rows_per_strip can be 2 ** 32 - 1, meaning the * whole image. Clip this down to height to avoid * confusing vips. * * And it mustn't be zero. */ header->rows_per_strip = VIPS_CLIP(1, header->rows_per_strip, header->height); header->number_of_strips = TIFFNumberOfStrips(rtiff->tiff); if (header->read_as_rgba) { header->scanline_size = header->width * 4; header->strip_size = header->scanline_size * header->rows_per_strip; } else { header->scanline_size = TIFFScanlineSize(rtiff->tiff); header->strip_size = TIFFStripSize(rtiff->tiff); } #ifdef DEBUG printf("rtiff_header_read: header.rows_per_strip = %d\n", header->rows_per_strip); printf("rtiff_header_read: header.strip_size = %zd\n", header->strip_size); printf("rtiff_header_read: header.scanline_size = %zd\n", header->scanline_size); printf("rtiff_header_read: header.number_of_strips = %d\n", header->number_of_strips); #endif /*DEBUG*/ /* libtiff has two strip-wise readers. TIFFReadEncodedStrip() * decompresses an entire strip to memory. It's fast, but it * will need a lot of ram if the strip is large. * TIFFReadScanline() reads a single scanline. It's slower, but * will save a lot of memory if strips are large. * * If this image has a strip size of over 128 lines, fall back * to TIFFReadScanline(), otherwise use TIFFReadEncodedStrip(). * * Don't do this in plane-separate mode. TIFFReadScanline() is * too fiddly to use in this case. * * Don't try scanline reading for YCbCr images. * TIFFScanlineSize() will not work in this case due to * chroma subsampling. * * Don't use scanline reading if we're going to use TIFFRGBAImage */ if (header->rows_per_strip > 128 && !header->separate && header->photometric_interpretation != PHOTOMETRIC_YCBCR && !header->read_as_rgba) { header->read_scanlinewise = TRUE; header->read_height = 1; header->read_size = rtiff->header.scanline_size; } else { header->read_scanlinewise = FALSE; header->read_height = header->rows_per_strip; header->read_size = header->strip_size; } #ifdef DEBUG printf("rtiff_header_read: header.read_scanlinewise = %d\n", header->read_scanlinewise); printf("rtiff_header_read: header.read_height = %d\n", header->read_height); printf("rtiff_header_read: header.read_size = %zd\n", header->read_size); #endif /*DEBUG*/ /* Stop some compiler warnings. */ header->tile_width = 0; header->tile_height = 0; header->tile_size = 0; header->tile_row_size = 0; } TIFFGetFieldDefaulted(rtiff->tiff, TIFFTAG_EXTRASAMPLES, &extra_samples_count, &extra_samples_types); header->alpha_band = -1; if (extra_samples_count > 0) { /* There must be exactly one band which is * EXTRASAMPLE_ASSOCALPHA. Note which one it is so we can * unpremultiply with the right channel. */ int i; for (i = 0; i < extra_samples_count; i++) if (extra_samples_types[i] == EXTRASAMPLE_ASSOCALPHA) { if (header->alpha_band != -1) g_warning("more than one alpha -- ignoring"); header->alpha_band = header->samples_per_pixel - extra_samples_count + i; } } return 0; } static int rtiff_header_equal(RtiffHeader *h1, RtiffHeader *h2) { if (h1->width != h2->width || h1->height != h2->height || h1->samples_per_pixel != h2->samples_per_pixel || h1->bits_per_sample != h2->bits_per_sample || h1->photometric_interpretation != h2->photometric_interpretation || h1->sample_format != h2->sample_format || h1->compression != h2->compression || h1->separate != h2->separate || h1->tiled != h2->tiled || h1->orientation != h2->orientation) return 0; if (h1->tiled) { if (h1->tile_width != h2->tile_width || h1->tile_height != h2->tile_height) return 0; } else { if (h1->read_height != h2->read_height || h1->read_size != h2->read_size || h1->number_of_strips != h2->number_of_strips) return 0; } return 1; } static int rtiff_header_read_all(Rtiff *rtiff) { #ifdef DEBUG printf("rtiff_header_read_all: reading header for page %d ...\n", rtiff->page); #endif /*DEBUG*/ /* -1 means "to the end". * * We must count pages before selecting and reading the header of the * first page, since scanning a TIFF can change the value of libtiff's * internal header fields in strange ways, especially if the TIFF is * corrupt. */ rtiff->n_pages = rtiff_n_pages(rtiff); if (rtiff_set_page(rtiff, rtiff->page) || rtiff_header_read(rtiff, &rtiff->header)) return -1; /* If we're to read many pages, verify that they are all identical. */ if (rtiff->n == -1) rtiff->n = rtiff->n_pages - rtiff->page; if (rtiff->n > 1) { int i; for (i = 1; i < rtiff->n; i++) { RtiffHeader header; #ifdef DEBUG printf("rtiff_header_read_all: verifying header for page %d ...\n", rtiff->page + i); #endif /*DEBUG*/ if (rtiff_set_page(rtiff, rtiff->page + i) || rtiff_header_read(rtiff, &header)) return -1; if (!rtiff_header_equal(&rtiff->header, &header)) { vips_error("tiff2vips", _("page %d differs from page %d"), rtiff->page + i, rtiff->page); return -1; } } /* Make sure the next set_page() will reread the directory. */ rtiff->current_page = -1; } return 0; } typedef gboolean (*TiffPropertyFn)(TIFF *tif); static gboolean vips__testtiff_source(VipsSource *source, TiffPropertyFn fn) { TIFF *tif; gboolean property; vips__tiff_init(); if (!(tif = vips__tiff_openin_source(source, rtiff_handler_error, rtiff_handler_warning, NULL, FALSE))) { vips_error_clear(); return FALSE; } property = fn ? fn(tif) : TRUE; TIFFClose(tif); return property; } gboolean vips__istiff_source(VipsSource *source) { return vips__testtiff_source(source, NULL); } gboolean vips__istifftiled_source(VipsSource *source) { return vips__testtiff_source(source, TIFFIsTiled); } int vips__tiff_read_header_source(VipsSource *source, VipsImage *out, int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on, gboolean unlimited) { Rtiff *rtiff; vips__tiff_init(); if (!(rtiff = rtiff_new(source, out, page, n, autorotate, subifd, fail_on, unlimited)) || rtiff_header_read_all(rtiff)) return -1; if (rtiff_set_header(rtiff, out)) return -1; if (rtiff->autorotate && vips_image_get_orientation_swap(out)) { VIPS_SWAP(int, out->Xsize, out->Ysize); vips_autorot_remove_angle(out); } /* We never call vips_source_decode() since we need to be able to * seek() the whole way through the file. Just minimise instead, */ vips_source_minimise(source); return 0; } int vips__tiff_read_source(VipsSource *source, VipsImage *out, int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on, gboolean unlimited) { Rtiff *rtiff; #ifdef DEBUG printf("tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion()); #endif /*DEBUG*/ vips__tiff_init(); if (!(rtiff = rtiff_new(source, out, page, n, autorotate, subifd, fail_on, unlimited)) || rtiff_header_read_all(rtiff)) return -1; if (rtiff->header.tiled) { if (rtiff_read_tilewise(rtiff, out)) return -1; } else { if (rtiff_read_stripwise(rtiff, out)) return -1; } /* We never call vips_source_decode() since we need to be able to * seek() the whole way through the file. Just minimise instead, */ vips_source_minimise(source); return 0; } #endif /*HAVE_TIFF*/ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/tiffload.c�����������������������������������������������������������0000664�0000000�0000000�00000041002�15163036615�0020322�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* load tiff from a file * * 5/12/11 * - from tiffload.c * 27/1/17 * - add get_flags for buffer loader */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_TIFF typedef struct _VipsForeignLoadTiff { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Load this page. */ int page; /* Load this many pages. */ int n; /* Select subifd index. -1 for main image. */ int subifd; /* Autorotate using orientation tag. */ gboolean autorotate; /* Remove denial of service limits. */ gboolean unlimited; } VipsForeignLoadTiff; typedef VipsForeignLoadClass VipsForeignLoadTiffClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadTiff, vips_foreign_load_tiff, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_tiff_dispose(GObject *gobject) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) gobject; VIPS_UNREF(tiff->source); G_OBJECT_CLASS(vips_foreign_load_tiff_parent_class)->dispose(gobject); } static VipsForeignFlags vips_foreign_load_tiff_get_flags_source(VipsSource *source) { VipsForeignFlags flags; flags = 0; if (vips__istifftiled_source(source)) flags |= VIPS_FOREIGN_PARTIAL; else flags |= VIPS_FOREIGN_SEQUENTIAL; return flags; } static VipsForeignFlags vips_foreign_load_tiff_get_flags_filename(const char *filename) { VipsSource *source; VipsForeignFlags flags; if (!(source = vips_source_new_from_file(filename))) return 0; flags = vips_foreign_load_tiff_get_flags_source(source); VIPS_UNREF(source); return flags; } static VipsForeignFlags vips_foreign_load_tiff_get_flags(VipsForeignLoad *load) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; return vips_foreign_load_tiff_get_flags_source(tiff->source); } static int vips_foreign_load_tiff_header(VipsForeignLoad *load) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; if (vips__tiff_read_header_source(tiff->source, load->out, tiff->page, tiff->n, tiff->autorotate, tiff->subifd, load->fail_on, tiff->unlimited)) return -1; return 0; } static int vips_foreign_load_tiff_load(VipsForeignLoad *load) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load; if (vips__tiff_read_source(tiff->source, load->real, tiff->page, tiff->n, tiff->autorotate, tiff->subifd, load->fail_on, tiff->unlimited)) return -1; return 0; } static void vips_foreign_load_tiff_class_init(VipsForeignLoadTiffClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; /* Other libraries may be using libtiff, we want to capture tiff * warning and error as soon as we can. * * This class init will be triggered during startup. */ vips__tiff_init(); gobject_class->dispose = vips_foreign_load_tiff_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffload_base"; object_class->description = _("load tiff"); /* We are fast, but must test after openslideload. */ foreign_class->priority = 50; load_class->get_flags_filename = vips_foreign_load_tiff_get_flags_filename; load_class->get_flags = vips_foreign_load_tiff_get_flags; load_class->header = vips_foreign_load_tiff_header; load_class->load = vips_foreign_load_tiff_load; VIPS_ARG_INT(class, "page", 20, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiff, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 21, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiff, n), -1, 100000, 1); VIPS_ARG_BOOL(class, "autorotate", 22, _("Autorotate"), _("Rotate image using orientation tag"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiff, autorotate), FALSE); VIPS_ARG_INT(class, "subifd", 23, _("subifd"), _("Subifd index"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiff, subifd), -1, 100000, -1); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION VIPS_ARG_BOOL(class, "unlimited", 24, _("Unlimited"), _("Remove all denial of service limits"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiff, unlimited), FALSE); #endif } static void vips_foreign_load_tiff_init(VipsForeignLoadTiff *tiff) { tiff->page = 0; tiff->n = 1; tiff->subifd = -1; tiff->unlimited = FALSE; } typedef struct _VipsForeignLoadTiffSource { VipsForeignLoadTiff parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadTiffSource; typedef VipsForeignLoadTiffClass VipsForeignLoadTiffSourceClass; G_DEFINE_TYPE(VipsForeignLoadTiffSource, vips_foreign_load_tiff_source, vips_foreign_load_tiff_get_type()); static int vips_foreign_load_tiff_source_build(VipsObject *object) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) object; VipsForeignLoadTiffSource *source = (VipsForeignLoadTiffSource *) object; if (source->source) { tiff->source = source->source; g_object_ref(tiff->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_tiff_source_parent_class) ->build(object); } static gboolean vips_foreign_load_tiff_source_is_a_source(VipsSource *source) { return vips__istiff_source(source); } static void vips_foreign_load_tiff_source_class_init( VipsForeignLoadTiffSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffload_source"; object_class->description = _("load tiff from source"); object_class->build = vips_foreign_load_tiff_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_tiff_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiffSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_tiff_source_init(VipsForeignLoadTiffSource *source) { } typedef struct _VipsForeignLoadTiffFile { VipsForeignLoadTiff parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadTiffFile; typedef VipsForeignLoadTiffClass VipsForeignLoadTiffFileClass; G_DEFINE_TYPE(VipsForeignLoadTiffFile, vips_foreign_load_tiff_file, vips_foreign_load_tiff_get_type()); static int vips_foreign_load_tiff_file_build(VipsObject *object) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) object; VipsForeignLoadTiffFile *file = (VipsForeignLoadTiffFile *) object; if (file->filename && !(tiff->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_tiff_file_parent_class) ->build(object); } static gboolean vips_foreign_load_tiff_file_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips_foreign_load_tiff_source_is_a_source(source); VIPS_UNREF(source); return result; } const char *vips__foreign_tiff_suffs[] = { ".tif", ".tiff", NULL }; static void vips_foreign_load_tiff_file_class_init(VipsForeignLoadTiffFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffload"; object_class->description = _("load tiff from file"); object_class->build = vips_foreign_load_tiff_file_build; foreign_class->suffs = vips__foreign_tiff_suffs; load_class->is_a = vips_foreign_load_tiff_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiffFile, filename), NULL); } static void vips_foreign_load_tiff_file_init(VipsForeignLoadTiffFile *file) { } typedef struct _VipsForeignLoadTiffBuffer { VipsForeignLoadTiff parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadTiffBuffer; typedef VipsForeignLoadTiffClass VipsForeignLoadTiffBufferClass; G_DEFINE_TYPE(VipsForeignLoadTiffBuffer, vips_foreign_load_tiff_buffer, vips_foreign_load_tiff_get_type()); static int vips_foreign_load_tiff_buffer_build(VipsObject *object) { VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) object; VipsForeignLoadTiffBuffer *buffer = (VipsForeignLoadTiffBuffer *) object; if (buffer->blob && !(tiff->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_tiff_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_tiff_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips_foreign_load_tiff_source_is_a_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_tiff_buffer_class_init( VipsForeignLoadTiffBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffload_buffer"; object_class->description = _("load tiff from buffer"); object_class->build = vips_foreign_load_tiff_buffer_build; load_class->is_a_buffer = vips_foreign_load_tiff_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadTiffBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_tiff_buffer_init(VipsForeignLoadTiffBuffer *buffer) { } #endif /*HAVE_TIFF*/ /** * vips_tiffload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a TIFF file into a VIPS image. * * It is a full baseline TIFF 6 reader, * with extensions for tiled images, multipage images, XYZ and LAB colour * space, pyramidal images and JPEG compression, including CMYK and YCbCr. * * @page means load this page from the file. By default the first page (page * 0) is read. * * @n means load this many pages. By default a single page is read. All the * pages must have the same dimensions, and they are loaded as a tall, thin * "toilet roll" image. The [const@META_PAGE_HEIGHT] metadata * tag gives the height in pixels of each page. Use -1 to load all pages. * * Setting @autorotate to `TRUE` will make the loader interpret the * orientation tag and automatically rotate the image appropriately during * load. * * If @autorotate is `FALSE`, the metadata field [const@META_ORIENTATION] is set * to the value of the orientation tag. Applications may read and interpret * this field * as they wish later in processing. See [method@Image.autorot]. Save * operations will use [const@META_ORIENTATION], if present, to set the * orientation of output images. * * If @autorotate is `TRUE`, the image will be rotated upright during load and * no metadata attached. This can be very slow. * * If @subifd is -1 (the default), the main image is selected for each page. * If it is 0 or greater and there is a SUBIFD tag, the indexed SUBIFD is * selected. This can be used to read lower resolution layers from * bioformats-style image pyramids. * * Use @fail_on to set the type of error that will cause load to fail. By * default, loaders are permissive, that is, [enum@Vips.FailOn.NONE]. * * When using libtiff 4.7.0+, the TIFF loader will limit memory allocation * for decoding each input file to 50MB to prevent denial of service attacks. * Set @unlimited to remove this limit. * * Any ICC profile is read and attached to the VIPS image as * [const@META_ICC_NAME]. Any XMP metadata is read and attached to the image * as [const@META_XMP_NAME]. Any IPTC is attached as [const@META_IPTC_NAME]. The * image description is * attached as [const@META_IMAGEDESCRIPTION]. Data in the photoshop tag is * attached as [const@META_PHOTOSHOP_NAME]. * * ::: tip "Optional arguments" * * @page: `gint`, load this page * * @n: `gint`, load this many pages * * @autorotate: `gboolean`, use orientation tag to rotate the image * during load * * @subifd: `gint`, select this subifd index * * @fail_on: [enum@FailOn], types of read error to fail on * * @unlimited: `gboolean`, remove all denial of service limits * * ::: seealso * [ctor@Image.new_from_file], [method@Image.autorot]. * * Returns: 0 on success, -1 on error. */ int vips_tiffload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("tiffload", ap, filename, out); va_end(ap); return result; } /** * vips_tiffload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a TIFF-formatted memory block into a VIPS image. Exactly as * [ctor@Image.tiffload], but read from a memory source. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, load this page * * @n: `gint`, load this many pages * * @autorotate: `gboolean`, use orientation tag to rotate the image * during load * * @subifd: `gint`, select this subifd index * * @fail_on: [enum@FailOn], types of read error to fail on * * @unlimited: `gboolean`, remove all denial of service limits * * ::: seealso * [ctor@Image.tiffload]. * * Returns: 0 on success, -1 on error. */ int vips_tiffload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("tiffload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_tiffload_source: * @source: source to load * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.tiffload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, load this page * * @n: `gint`, load this many pages * * @autorotate: `gboolean`, use orientation tag to rotate the image * during load * * @subifd: `gint`, select this subifd index * * @fail_on: [enum@FailOn], types of read error to fail on * * @unlimited: `gboolean`, remove all denial of service limits * * ::: seealso * [ctor@Image.tiffload]. * * Returns: 0 on success, -1 on error. */ int vips_tiffload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("tiffload_source", ap, source, out); va_end(ap); return result; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/tiffsave.c�����������������������������������������������������������0000664�0000000�0000000�00000062117�15163036615�0020353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* save to tiff * * 2/12/11 * - wrap a class around the tiff writer * 17/3/12 * - argh xres/yres macro was wrong * 26/1/14 * - add rgbjpeg flag * 21/12/15 * - add properties flag * 31/5/16 * - convert for jpg if jpg compression is on * 19/10/17 * - predictor defaults to horizontal, reducing file size, usually * 13/6/18 * - add region_shrink * 8/7/19 * - add webp and zstd support * - add @level and @lossless * 4/9/18 [f--f] * - xres/yres params were in pixels/cm * 26/1/20 * - add "depth" to set pyr depth * 12/5/20 * - add "subifd" to create pyr layers as sub-directories * 8/6/20 * - add bitdepth support for 2 and 4 bit greyscale images * - deprecate "squash" * 1/5/21 * - add "premultiply" flag * 10/5/22 * - add vips_tiffsave_target() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_TIFF #include "tiff.h" typedef struct _VipsForeignSaveTiff { VipsForeignSave parent_object; /* Set by subclasses. */ VipsTarget *target; /* Many options argh. */ VipsForeignTiffCompression compression; int Q; VipsForeignTiffPredictor predictor; gboolean tile; int tile_width; int tile_height; gboolean pyramid; gboolean squash; int bitdepth; gboolean miniswhite; VipsForeignTiffResunit resunit; double xres; double yres; gboolean bigtiff; gboolean rgbjpeg; gboolean properties; VipsRegionShrink region_shrink; int level; gboolean lossless; VipsForeignDzDepth depth; gboolean subifd; gboolean premultiply; } VipsForeignSaveTiff; typedef VipsForeignSaveClass VipsForeignSaveTiffClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveTiff, vips_foreign_save_tiff, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_tiff_dispose(GObject *gobject) { VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) gobject; VIPS_UNREF(tiff->target); G_OBJECT_CLASS(vips_foreign_save_tiff_parent_class)->dispose(gobject); } #define UC VIPS_FORMAT_UCHAR /* Type promotion for jpeg-in-tiff save ... just always go to uchar. */ static VipsBandFormat bandfmt_jpeg[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static int vips_foreign_save_tiff_build(VipsObject *object) { VipsForeignSaveClass *class = VIPS_FOREIGN_SAVE_GET_CLASS(object); VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) object; if (VIPS_OBJECT_CLASS(vips_foreign_save_tiff_parent_class)->build(object)) return -1; VipsImage *ready = save->ready; g_object_ref(ready); /* If we are saving jpeg-in-tiff, we need a different convert_saveable * path. The regular tiff one will let through things like float and * 16-bit and alpha for example, which will make the jpeg saver choke. */ if (tiff->compression == VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) { VipsImage *x; /* See also vips_foreign_save_jpeg_class_init(). */ if (vips__foreign_convert_saveable(ready, &x, VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_CMYK, bandfmt_jpeg, class->coding, save->background)) { VIPS_UNREF(ready); return -1; } VIPS_UNREF(ready); ready = x; } /* resunit param overrides resunit metadata. */ VipsForeignTiffResunit resunit = tiff->resunit; const char *p; if (!vips_object_argument_isset(object, "resunit") && vips_image_get_typeof(ready, VIPS_META_RESOLUTION_UNIT) && !vips_image_get_string(ready, VIPS_META_RESOLUTION_UNIT, &p) && vips_isprefix("in", p)) resunit = VIPS_FOREIGN_TIFF_RESUNIT_INCH; double xres = vips_object_argument_isset(object, "xres") ? tiff->xres : ready->Xres; double yres = vips_object_argument_isset(object, "yres") ? tiff->yres : ready->Yres; if (resunit == VIPS_FOREIGN_TIFF_RESUNIT_INCH) { xres *= 25.4; yres *= 25.4; } else { xres *= 10.0; yres *= 10.0; } if (vips__tiff_write_target(ready, tiff->target, tiff->compression, tiff->Q, tiff->predictor, save->profile, tiff->tile, tiff->tile_width, tiff->tile_height, tiff->pyramid, // deprecated "squash" param tiff->squash ? 1 : tiff->bitdepth, tiff->miniswhite, resunit, xres, yres, tiff->bigtiff, tiff->rgbjpeg, tiff->properties, tiff->region_shrink, tiff->level, tiff->lossless, tiff->depth, tiff->subifd, tiff->premultiply, save->page_height)) { VIPS_UNREF(ready); return -1; } VIPS_UNREF(ready); if (vips_target_end(tiff->target)) return -1; return 0; } static void vips_foreign_save_tiff_class_init(VipsForeignSaveTiffClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_tiff_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffsave_base"; object_class->description = _("save image as tiff"); object_class->build = vips_foreign_save_tiff_build; foreign_class->suffs = vips__foreign_tiff_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->coding |= VIPS_FOREIGN_CODING_LABQ; VIPS_ARG_ENUM(class, "compression", 6, _("Compression"), _("Compression for this file"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, compression), VIPS_TYPE_FOREIGN_TIFF_COMPRESSION, VIPS_FOREIGN_TIFF_COMPRESSION_NONE); VIPS_ARG_INT(class, "Q", 7, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, Q), 1, 100, 75); VIPS_ARG_ENUM(class, "predictor", 8, _("Predictor"), _("Compression prediction"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, predictor), VIPS_TYPE_FOREIGN_TIFF_PREDICTOR, VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL); VIPS_ARG_BOOL(class, "tile", 10, _("Tile"), _("Write a tiled tiff"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, tile), FALSE); VIPS_ARG_INT(class, "tile_width", 11, _("Tile width"), _("Tile width in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, tile_width), 1, 32768, 128); VIPS_ARG_INT(class, "tile_height", 12, _("Tile height"), _("Tile height in pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, tile_height), 1, 32768, 128); VIPS_ARG_BOOL(class, "pyramid", 13, _("Pyramid"), _("Write a pyramidal tiff"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, pyramid), FALSE); VIPS_ARG_BOOL(class, "miniswhite", 14, _("Miniswhite"), _("Use 0 for white in 1-bit images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, miniswhite), FALSE); VIPS_ARG_INT(class, "bitdepth", 15, _("Bit depth"), _("Write as a 1, 2, 4 or 8 bit image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, bitdepth), 0, 8, 0); VIPS_ARG_ENUM(class, "resunit", 16, _("Resolution unit"), _("Resolution unit"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, resunit), VIPS_TYPE_FOREIGN_TIFF_RESUNIT, VIPS_FOREIGN_TIFF_RESUNIT_CM); VIPS_ARG_DOUBLE(class, "xres", 17, _("Xres"), _("Horizontal resolution in pixels/mm"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, xres), 0.001, 1000000, 1); VIPS_ARG_DOUBLE(class, "yres", 18, _("Yres"), _("Vertical resolution in pixels/mm"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, yres), 0.001, 1000000, 1); VIPS_ARG_BOOL(class, "bigtiff", 19, _("Bigtiff"), _("Write a bigtiff image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, bigtiff), FALSE); VIPS_ARG_BOOL(class, "properties", 21, _("Properties"), _("Write a properties document to IMAGEDESCRIPTION"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, properties), FALSE); VIPS_ARG_ENUM(class, "region_shrink", 22, _("Region shrink"), _("Method to shrink regions"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, region_shrink), VIPS_TYPE_REGION_SHRINK, VIPS_REGION_SHRINK_MEAN); VIPS_ARG_INT(class, "level", 23, _("Level"), _("Deflate (1-9, default 6) or ZSTD (1-22, default 9) compression level"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, level), 0, 22, 0); VIPS_ARG_BOOL(class, "lossless", 24, _("Lossless"), _("Enable WEBP lossless mode"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, lossless), FALSE); VIPS_ARG_ENUM(class, "depth", 25, _("Depth"), _("Pyramid depth"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, depth), VIPS_TYPE_FOREIGN_DZ_DEPTH, VIPS_FOREIGN_DZ_DEPTH_ONETILE); VIPS_ARG_BOOL(class, "subifd", 26, _("Sub-IFD"), _("Save pyr layers as sub-IFDs"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, subifd), FALSE); VIPS_ARG_BOOL(class, "premultiply", 27, _("Premultiply"), _("Save with premultiplied alpha"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiff, premultiply), FALSE); VIPS_ARG_BOOL(class, "rgbjpeg", 28, _("RGB JPEG"), _("Output RGB JPEG rather than YCbCr"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveTiff, rgbjpeg), FALSE); VIPS_ARG_BOOL(class, "squash", 29, _("Squash"), _("Squash images down to 1 bit"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveTiff, squash), FALSE); } static void vips_foreign_save_tiff_init(VipsForeignSaveTiff *tiff) { tiff->compression = VIPS_FOREIGN_TIFF_COMPRESSION_NONE; tiff->Q = 75; tiff->predictor = VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL; tiff->tile_width = 128; tiff->tile_height = 128; tiff->resunit = VIPS_FOREIGN_TIFF_RESUNIT_CM; tiff->xres = 1.0; tiff->yres = 1.0; tiff->region_shrink = VIPS_REGION_SHRINK_MEAN; tiff->level = 0; tiff->lossless = FALSE; tiff->depth = VIPS_FOREIGN_DZ_DEPTH_ONETILE; tiff->bitdepth = 0; } typedef struct _VipsForeignSaveTiffTarget { VipsForeignSaveTiff parent_object; VipsTarget *target; } VipsForeignSaveTiffTarget; typedef VipsForeignSaveTiffClass VipsForeignSaveTiffTargetClass; G_DEFINE_TYPE(VipsForeignSaveTiffTarget, vips_foreign_save_tiff_target, vips_foreign_save_tiff_get_type()); static int vips_foreign_save_tiff_target_build(VipsObject *object) { VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) object; VipsForeignSaveTiffTarget *target = (VipsForeignSaveTiffTarget *) object; tiff->target = target->target; g_object_ref(tiff->target); return VIPS_OBJECT_CLASS(vips_foreign_save_tiff_target_parent_class) ->build(object); } static void vips_foreign_save_tiff_target_class_init( VipsForeignSaveTiffTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffsave_target"; object_class->description = _("save image to tiff target"); object_class->build = vips_foreign_save_tiff_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiffTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_tiff_target_init(VipsForeignSaveTiffTarget *target) { } typedef struct _VipsForeignSaveTiffFile { VipsForeignSaveTiff parent_object; char *filename; } VipsForeignSaveTiffFile; typedef VipsForeignSaveTiffClass VipsForeignSaveTiffFileClass; G_DEFINE_TYPE(VipsForeignSaveTiffFile, vips_foreign_save_tiff_file, vips_foreign_save_tiff_get_type()); static int vips_foreign_save_tiff_file_build(VipsObject *object) { VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) object; VipsForeignSaveTiffFile *file = (VipsForeignSaveTiffFile *) object; if (!(tiff->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_tiff_file_parent_class) ->build(object); } static void vips_foreign_save_tiff_file_class_init(VipsForeignSaveTiffFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffsave"; object_class->description = _("save image to tiff file"); object_class->build = vips_foreign_save_tiff_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveTiffFile, filename), NULL); } static void vips_foreign_save_tiff_file_init(VipsForeignSaveTiffFile *file) { } typedef struct _VipsForeignSaveTiffBuffer { VipsForeignSaveTiff parent_object; VipsArea *buf; } VipsForeignSaveTiffBuffer; typedef VipsForeignSaveTiffClass VipsForeignSaveTiffBufferClass; G_DEFINE_TYPE(VipsForeignSaveTiffBuffer, vips_foreign_save_tiff_buffer, vips_foreign_save_tiff_get_type()); static int vips_foreign_save_tiff_buffer_build(VipsObject *object) { VipsForeignSaveTiff *tiff = (VipsForeignSaveTiff *) object; VipsForeignSaveTiffBuffer *buffer = (VipsForeignSaveTiffBuffer *) object; VipsBlob *blob; if (!(tiff->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_tiff_buffer_parent_class) ->build(object)) return -1; g_object_get(tiff->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_tiff_buffer_class_init( VipsForeignSaveTiffBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "tiffsave_buffer"; object_class->description = _("save image to tiff buffer"); object_class->build = vips_foreign_save_tiff_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveTiffBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_tiff_buffer_init(VipsForeignSaveTiffBuffer *buffer) { } #endif /*HAVE_TIFF*/ /** * vips_tiffsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write a VIPS image to a file as TIFF. * * If @in has the [const@META_PAGE_HEIGHT] metadata item, this is assumed to * be a "toilet roll" image. It will be written as series of pages, each * [const@META_PAGE_HEIGHT] pixels high. * * Use @compression to set the tiff compression. Currently jpeg, packbits, * fax4, lzw, none, deflate, webp and zstd are supported. The default is no * compression. JPEG compression is a good lossy compressor for photographs, * packbits is good for 1-bit images, and deflate is the best lossless * compression TIFF can do. * * XYZ images are automatically saved as libtiff LOGLUV with SGILOG compression. * Float LAB images are saved as float CIELAB. Set @bitdepth to save as 8-bit * CIELAB. * * Use @Q to set the JPEG compression factor. Default 75. * * User @level to set the ZSTD (1-22) or Deflate (1-9) compression level. * Use @lossless to set WEBP lossless mode on. Use @Q to set the WEBP * compression level. * * Use @predictor to set the predictor for lzw, deflate and zstd compression. * It defaults to [enum@Vips.ForeignTiffPredictor.HORIZONTAL], meaning horizontal * differencing. Please refer to the libtiff * specifications for further discussion of various predictors. * * Set @tile to `TRUE` to write a tiled tiff. By default tiff are written in * strips. Use @tile_width and @tile_height to set the tile size. The defaiult * is 128 by 128. * * Set @pyramid to write the image as a set of images, one per page, of * decreasing size. Use @region_shrink to set how images will be shrunk: by * default each 2x2 block is just averaged, but you can set MODE or MEDIAN as * well. * * By default, the pyramid stops when the image is small enough to fit in one * tile. Use @depth to stop when the image fits in one pixel, or to only write * a single layer. * * Set @bitdepth to save 8-bit uchar images as 1, 2 or 4-bit TIFFs. * * In case of depth 1: Values >128 are written as white, values <=128 as black. * Normally vips will write MINISBLACK TIFFs where black is a 0 bit, but if you * set @miniswhite, it will use 0 for a white bit. Many pre-press applications * only work with images which use this sense. @miniswhite only affects one-bit * images, it does nothing for greyscale images. * * In case of depth 2: The same holds but values < 64 are written as black. * For 64 <= values < 128 they are written as dark grey, for 128 <= values < 192 * they are written as light gray and values above are written as white. * In case @miniswhite is set to true this behavior is inverted. * In case of depth 4: values < 16 are written as black, and so on for the * lighter shades. In case @miniswhite is set to true this behavior is inverted. * * Use @resunit to override the default resolution unit. The default * resolution unit is taken from the header field [const@META_RESOLUTION_UNIT]. * If this field is not set, then VIPS defaults to cm. * * Use @xres and @yres to override the default horizontal and vertical * resolutions. By default these values are taken from the VIPS image header. * libvips resolution is always in pixels per millimetre. * * Set @bigtiff to attempt to write a bigtiff. Bigtiff is a variant of the TIFF * format that allows more than 4GB in a file. * * Set @properties to write all vips metadata to the IMAGEDESCRIPTION tag as * xml. If @properties is not set, the value of [const@META_IMAGEDESCRIPTION] is * used instead. * * The value of [const@META_XMP_NAME] is written to the XMP tag. * [const@META_ORIENTATION] (if set) is used to set the value of the * orientation tag. [const@META_IPTC_NAME] (if set) is used to set the * value of the IPTC tag. [const@META_PHOTOSHOP_NAME] (if set) is used to * set the value of the PHOTOSHOP tag. * * By default, pyramid layers are saved as consecutive pages. * Set @subifd to save pyramid layers as sub-directories of the main image. * Setting this option can improve compatibility with formats like OME. * * Set @premultiply to save with premultiplied alpha. Some programs, such as * InDesign, will only work with premultiplied alpha. * * ::: tip "Optional arguments" * * @compression: [enum@ForeignTiffCompression], write with this * compression * * @Q: `gint`, quality factor * * @predictor: [enum@ForeignTiffPredictor], use this predictor * * @tile: `gboolean`, set `TRUE` to write a tiled tiff * * @tile_width: `gint`, for tile size * * @tile_height: `gint`, for tile size * * @pyramid: `gboolean`, write an image pyramid * * @bitdepth: `gint`, change bit depth to 1,2, or 4 bit * * @miniswhite: `gboolean`, write 1-bit images as MINISWHITE * * @resunit: [enum@ForeignTiffResunit] for resolution unit * * @xres: `gdouble`, horizontal resolution in pixels/mm * * @yres: `gdouble`, vertical resolution in pixels/mm * * @bigtiff: `gboolean`, write a BigTiff file * * @properties: `gboolean`, set `TRUE` to write an IMAGEDESCRIPTION tag * * @region_shrink: [enum@RegionShrink] How to shrink each 2x2 region. * * @level: `gint`, Zstd or Deflate (zlib) compression level * * @lossless: `gboolean`, WebP lossless mode * * @depth: [enum@ForeignDzDepth] how deep to make the pyramid * * @subifd: `gboolean`, write pyr layers as sub-ifds * * @premultiply: `gboolean`, write premultiplied alpha * * ::: seealso * [ctor@Image.tiffload], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_tiffsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("tiffsave", ap, in, filename); va_end(ap); return result; } /** * vips_tiffsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.tiffsave], but save to a memory buffer. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: tip "Optional arguments" * * @compression: [enum@ForeignTiffCompression], write with this * compression * * @Q: `gint`, quality factor * * @predictor: [enum@ForeignTiffPredictor], use this predictor * * @tile: `gboolean`, set `TRUE` to write a tiled tiff * * @tile_width: `gint`, for tile size * * @tile_height: `gint`, for tile size * * @pyramid: `gboolean`, write an image pyramid * * @bitdepth: `gint`, change bit depth to 1,2, or 4 bit * * @miniswhite: `gboolean`, write 1-bit images as MINISWHITE * * @resunit: [enum@ForeignTiffResunit] for resolution unit * * @xres: `gdouble`, horizontal resolution in pixels/mm * * @yres: `gdouble`, vertical resolution in pixels/mm * * @bigtiff: `gboolean`, write a BigTiff file * * @properties: `gboolean`, set `TRUE` to write an IMAGEDESCRIPTION tag * * @region_shrink: [enum@RegionShrink] How to shrink each 2x2 region. * * @level: `gint`, Zstd or Deflate (zlib) compression level * * @lossless: `gboolean`, WebP lossless mode * * @depth: [enum@ForeignDzDepth] how deep to make the pyramid * * @subifd: `gboolean`, write pyr layers as sub-ifds * * @premultiply: `gboolean`, write premultiplied alpha * * ::: seealso * [method@Image.tiffsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_tiffsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("tiffsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_tiffsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.tiffsave], but save to a target. * * ::: tip "Optional arguments" * * @compression: [enum@ForeignTiffCompression], write with this * compression * * @Q: `gint`, quality factor * * @predictor: [enum@ForeignTiffPredictor], use this predictor * * @tile: `gboolean`, set `TRUE` to write a tiled tiff * * @tile_width: `gint`, for tile size * * @tile_height: `gint`, for tile size * * @pyramid: `gboolean`, write an image pyramid * * @bitdepth: `gint`, change bit depth to 1,2, or 4 bit * * @miniswhite: `gboolean`, write 1-bit images as MINISWHITE * * @resunit: [enum@ForeignTiffResunit] for resolution unit * * @xres: `gdouble`, horizontal resolution in pixels/mm * * @yres: `gdouble`, vertical resolution in pixels/mm * * @bigtiff: `gboolean`, write a BigTiff file * * @properties: `gboolean`, set `TRUE` to write an IMAGEDESCRIPTION tag * * @region_shrink: [enum@RegionShrink] How to shrink each 2x2 region. * * @level: `gint`, Zstd or Deflate (zlib) compression level * * @lossless: `gboolean`, WebP lossless mode * * @depth: [enum@ForeignDzDepth] how deep to make the pyramid * * @subifd: `gboolean`, write pyr layers as sub-ifds * * @premultiply: `gboolean`, write premultiplied alpha * * ::: seealso * [method@Image.tiffsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_tiffsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("tiffsave_target", ap, in, target); va_end(ap); return result; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/uhdrload.c�����������������������������������������������������������0000664�0000000�0000000�00000055476�15163036615�0020360�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* load UltraHDR images with libuhdr * * 23/8/25 * - from heifload.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_UHDR #include "pforeign.h" #include "jpeg.h" #include #define VIPS_TYPE_FOREIGN_LOAD_UHDR (vips_foreign_load_uhdr_get_type()) #define VIPS_FOREIGN_LOAD_UHDR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_LOAD_UHDR, VipsForeignLoadUhdr)) #define VIPS_FOREIGN_LOAD_UHDR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN_LOAD_UHDR, VipsForeignLoadUhdrClass)) #define VIPS_IS_FOREIGN_LOAD_UHDR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN_LOAD_UHDR)) #define VIPS_IS_FOREIGN_LOAD_UHDR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN_LOAD_UHDR)) #define VIPS_FOREIGN_LOAD_UHDR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN_LOAD_UHDR, VipsForeignLoadUhdrClass)) typedef struct _VipsForeignLoadUhdr { VipsForeignLoad parent_object; /* Set from subclasses. */ VipsSource *source; int shrink; // decoder uhdr_codec_private_t *dec; uhdr_raw_image_t *raw_image; uhdr_raw_image_t *gainmap_image; } VipsForeignLoadUhdr; typedef struct _VipsForeignLoadUhdrClass { VipsForeignLoadClass parent_class; } VipsForeignLoadUhdrClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadUhdr, vips_foreign_load_uhdr, VIPS_TYPE_FOREIGN_LOAD); /* A fast uhdr detector. We just check the header for an MPF APP2 block * (quick) and only call is_uhdr_image() if we find it. */ static int vips_foreign_load_uhdr_is_a(VipsSource *source) { if (!vips__isjpeg_source(source)) return 0; VipsImage *context = vips_image_new(); ReadJpeg *jpeg; if (!(jpeg = vips__readjpeg_new(source, context, 1, VIPS_FAIL_ON_NONE, FALSE, FALSE))) { VIPS_UNREF(context); return 0; } /* Here for longjmp() from vips__new_error_exit() during * cinfo->mem->alloc_small() or jpeg_read_header(). */ if (setjmp(jpeg->eman.jmp)) { VIPS_UNREF(context); return 0; } if (vips__readjpeg_open_input(jpeg)) { VIPS_UNREF(context); return 0; } struct jpeg_decompress_struct *cinfo = &jpeg->cinfo; /* Read JPEG header. */ jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xffff); jpeg_read_header(cinfo, TRUE); gboolean found; found = FALSE; for (jpeg_saved_marker_ptr p = cinfo->marker_list; p; p = p->next) switch (p->marker) { case JPEG_APP0 + 2: if (p->data_length > 4 && vips_isprefix("MPF", (char *) p->data)) found = TRUE; break; default: break; } VIPS_UNREF(context); /* If we found an MPF block, also call is_uhdr_image(). This is very slow * and will force the whole image into memory, but it will only happen for * JPEGs with an MPF block, so hopefully not too often. */ if (found) { const void *data; size_t length; g_info("forcing JPEG into memory for uhdr detection"); if (!(data = vips_source_map(source, &length))) return -1; found = is_uhdr_image((void *) data, length); } return found; } const char * vips__uhdr_error_str(uhdr_codec_err_t err) { switch (err) { case UHDR_CODEC_OK: return "UHDR_CODEC_OK"; case UHDR_CODEC_ERROR: return "UHDR_CODEC_ERROR"; case UHDR_CODEC_UNKNOWN_ERROR: return "UHDR_CODEC_UNKNOWN_ERROR"; case UHDR_CODEC_INVALID_PARAM: return "UHDR_CODEC_INVALID_PARAM"; case UHDR_CODEC_MEM_ERROR: return "UHDR_CODEC_MEM_ERROR"; case UHDR_CODEC_INVALID_OPERATION: return "UHDR_CODEC_INVALID_OPERATION"; case UHDR_CODEC_UNSUPPORTED_FEATURE: return "UHDR_CODEC_UNSUPPORTED_FEATURE"; default: return ""; } } void vips__uhdr_error(uhdr_error_info_t *error) { if (error && error->has_detail) vips_error("uhdr", "%s (%s, %d)", error->detail, vips__uhdr_error_str(error->error_code), error->error_code); else if (error) vips_error("uhdr", "%s, %d", vips__uhdr_error_str(error->error_code), error->error_code); else vips_error("uhdr", "error"); } static void vips_foreign_load_uhdr_dispose(GObject *gobject) { VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) gobject; VIPS_FREEF(uhdr_release_decoder, uhdr->dec); VIPS_UNREF(uhdr->source); G_OBJECT_CLASS(vips_foreign_load_uhdr_parent_class)->dispose(gobject); } static int vips_foreign_load_uhdr_build(VipsObject *object) { VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) object; #ifdef DEBUG printf("vips_foreign_load_uhdr_build:\n"); #endif /*DEBUG*/ if (uhdr->source && vips_source_rewind(uhdr->source)) return -1; if (!uhdr->dec && !(uhdr->dec = uhdr_create_decoder())) { vips__uhdr_error(NULL); return -1; } return VIPS_OBJECT_CLASS(vips_foreign_load_uhdr_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_uhdr_get_flags(VipsForeignLoad *load) { // since we always decode the whole thing to memory return VIPS_FOREIGN_PARTIAL; } #ifdef DEBUG const char * vips__img_fmt_str(uhdr_img_fmt_t fmt) { switch (fmt) { case UHDR_IMG_FMT_UNSPECIFIED: return "UHDR_IMG_FMT_UNSPECIFIED"; case UHDR_IMG_FMT_24bppYCbCrP010: return "UHDR_IMG_FMT_24bppYCbCrP010"; case UHDR_IMG_FMT_12bppYCbCr420: return "UHDR_IMG_FMT_12bppYCbCr420"; case UHDR_IMG_FMT_8bppYCbCr400: return "UHDR_IMG_FMT_8bppYCbCr400"; case UHDR_IMG_FMT_32bppRGBA8888: return "UHDR_IMG_FMT_32bppRGBA8888"; case UHDR_IMG_FMT_64bppRGBAHalfFloat: return "UHDR_IMG_FMT_64bppRGBAHalfFloat"; case UHDR_IMG_FMT_32bppRGBA1010102: return "UHDR_IMG_FMT_32bppRGBA1010102"; case UHDR_IMG_FMT_24bppYCbCr444: return "UHDR_IMG_FMT_24bppYCbCr444"; case UHDR_IMG_FMT_16bppYCbCr422: return "UHDR_IMG_FMT_16bppYCbCr422"; case UHDR_IMG_FMT_16bppYCbCr440: return "UHDR_IMG_FMT_16bppYCbCr440"; case UHDR_IMG_FMT_12bppYCbCr411: return "UHDR_IMG_FMT_12bppYCbCr411"; case UHDR_IMG_FMT_10bppYCbCr410: return "UHDR_IMG_FMT_10bppYCbCr410"; case UHDR_IMG_FMT_24bppRGB888: return "UHDR_IMG_FMT_24bppRGB888"; case UHDR_IMG_FMT_30bppYCbCr444: return "UHDR_IMG_FMT_30bppYCbCr444"; default: return ""; } } const char * vips__color_gamut_str(uhdr_color_gamut_t cg) { switch (cg) { case UHDR_CG_UNSPECIFIED: return "UHDR_CG_UNSPECIFIED"; case UHDR_CG_BT_709: return "UHDR_CG_BT_709"; case UHDR_CG_DISPLAY_P3: return "UHDR_CG_DISPLAY_P3"; case UHDR_CG_BT_2100: return "UHDR_CG_BT_2100"; default: return ""; } } const char * vips__color_transfer_str(uhdr_color_transfer_t ct) { switch (ct) { case UHDR_CT_UNSPECIFIED: return "UHDR_CT_UNSPECIFIED"; case UHDR_CT_LINEAR: return "UHDR_CT_LINEAR"; case UHDR_CT_HLG: return "UHDR_CT_HLG"; case UHDR_CT_PQ: return "UHDR_CT_PQ"; case UHDR_CT_SRGB: return "UHDR_CT_SRGB"; default: return ""; } } const char * vips__color_range_str(uhdr_color_range_t range) { switch (range) { case UHDR_CR_UNSPECIFIED: return "UHDR_CR_UNSPECIFIED"; case UHDR_CR_LIMITED_RANGE: return "UHDR_CR_LIMITED_RANGE"; case UHDR_CR_FULL_RANGE: return "UHDR_CR_FULL_RANGE"; default: return ""; } } void vips__print_raw(uhdr_raw_image_t *raw) { printf("\traw->fmt = %s\n", vips__img_fmt_str(raw->fmt)); printf("\traw->cg = %s\n", vips__color_gamut_str(raw->cg)); printf("\traw->ct = %s\n", vips__color_transfer_str(raw->ct)); printf("\traw->range = %s\n", vips__color_range_str(raw->range)); printf("\traw->w = %d\n", raw->w); printf("\traw->h = %d\n", raw->h); printf("\traw->planes[0] = %p\n", raw->planes[0]); printf("\traw->planes[1] = %p\n", raw->planes[1]); printf("\traw->planes[2] = %p\n", raw->planes[2]); printf("\traw->stride[0] = %d\n", raw->stride[0]); printf("\traw->stride[1] = %d\n", raw->stride[1]); printf("\traw->stride[2] = %d\n", raw->stride[2]); } #endif /*DEBUG*/ static int vips_foreign_load_uhdr_set_metadata(VipsForeignLoadUhdr *uhdr, VipsImage *out) { uhdr_mem_block_t *mem_block; if ((mem_block = uhdr_dec_get_exif(uhdr->dec))) { g_info("attaching libuhdr exif"); vips_image_set_blob_copy(out, VIPS_META_EXIF_NAME, mem_block->data, mem_block->data_sz); } if ((mem_block = uhdr_dec_get_icc(uhdr->dec))) { const char *prefix = "ICC_PROFILE"; void *data = mem_block->data; size_t length = mem_block->data_sz; size_t prefix_len = strlen(prefix); // libuhdr profiles sometimes start with "ICC_PROFILE" and three bytes if (length > prefix_len + 3 && vips_isprefix(prefix, data)) { data = (void *) ((char *) data + prefix_len + 3); length -= prefix_len + 3; } g_info("attaching libuhdr profile"); vips_image_set_blob_copy(out, VIPS_META_ICC_NAME, data, length); } if ((mem_block = uhdr_dec_get_gainmap_image(uhdr->dec))) { // attach as a compressed JPG vips_image_set_blob_copy(out, "gainmap-data", mem_block->data, mem_block->data_sz); // if the shrink is not 1, load and attach the gainmap with the same // shrink if (uhdr->shrink != 1) { VipsImage *gainmap; if (vips_jpegload_buffer(mem_block->data, mem_block->data_sz, &gainmap, "shrink", uhdr->shrink, NULL)) return -1; vips_image_set_image(out, "gainmap", gainmap); VIPS_UNREF(gainmap); } } VIPS_SETSTR(out->filename, vips_connection_filename(VIPS_CONNECTION(uhdr->source))); uhdr_gainmap_metadata_t *gainmap_metadata = uhdr_dec_get_gainmap_metadata(uhdr->dec); if (gainmap_metadata) { double arr[3]; g_info("attaching gainmap metadata"); for (int i = 0; i < 3; i++) arr[i] = gainmap_metadata->max_content_boost[i]; vips_image_set_array_double(out, "gainmap-max-content-boost", arr, 3); for (int i = 0; i < 3; i++) arr[i] = gainmap_metadata->min_content_boost[i]; vips_image_set_array_double(out, "gainmap-min-content-boost", arr, 3); for (int i = 0; i < 3; i++) arr[i] = gainmap_metadata->gamma[i]; vips_image_set_array_double(out, "gainmap-gamma", arr, 3); for (int i = 0; i < 3; i++) arr[i] = gainmap_metadata->offset_sdr[i]; vips_image_set_array_double(out, "gainmap-offset-sdr", arr, 3); for (int i = 0; i < 3; i++) arr[i] = gainmap_metadata->offset_hdr[i]; vips_image_set_array_double(out, "gainmap-offset-hdr", arr, 3); vips_image_set_double(out, "gainmap-hdr-capacity-min", gainmap_metadata->hdr_capacity_min); vips_image_set_double(out, "gainmap-hdr-capacity-max", gainmap_metadata->hdr_capacity_max); vips_image_set_int(out, "gainmap-use-base-cg", gainmap_metadata->use_base_cg); } const int gainmap_width = uhdr_dec_get_gainmap_width(uhdr->dec); if (gainmap_width > 0) { vips_image_set_int(out, "gainmap-scale-factor", VIPS_MAX(1, uhdr_dec_get_image_width(uhdr->dec) / gainmap_width)); } return 0; } static int vips_foreign_load_uhdr_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) load; uhdr_error_info_t error_info; #ifdef DEBUG printf("vips_foreign_load_uhdr_header:\n"); #endif /*DEBUG*/ const void *data; size_t size; if (!(data = vips_source_map(uhdr->source, &size))) return -1; if (!is_uhdr_image((void *) data, size)) { vips_error(class->nickname, "%s", _("not an UltraHDR image")); return -1; } uhdr_compressed_image_t compressed_image = { (void *) data, size, .capacity = size, .cg = UHDR_CG_UNSPECIFIED, .ct = UHDR_CT_UNSPECIFIED, .range = UHDR_CR_UNSPECIFIED, }; error_info = uhdr_dec_set_image(uhdr->dec, &compressed_image); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } // only used if we use libuhdr to decode ... ignored if we decode to SDR // ourselves error_info = uhdr_dec_set_out_img_format(uhdr->dec, UHDR_IMG_FMT_64bppRGBAHalfFloat); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } error_info = uhdr_dec_set_out_color_transfer(uhdr->dec, UHDR_CT_LINEAR); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } error_info = uhdr_dec_probe(uhdr->dec); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } int image_width = uhdr_dec_get_image_width(uhdr->dec); int image_height = uhdr_dec_get_image_height(uhdr->dec); int width = image_width / uhdr->shrink; int height = image_height / uhdr->shrink; vips_image_init_fields(load->out, width, height, 3, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); if (vips_foreign_load_uhdr_set_metadata(uhdr, load->out)) return -1; return 0; } static int vips_foreign_load_uhdr_load(VipsForeignLoad *load) { VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) load; #ifdef DEBUG printf("vips_foreign_load_uhdr_load:\n"); #endif /*DEBUG*/ g_info("decoding UltraHDR to sRGB"); // decode as SDR with our libjpeg decoder ... downstream can // reconstruct HDR from the gainmap uhdr_mem_block_t *base_image = uhdr_dec_get_base_image(uhdr->dec); if (!base_image) { vips__uhdr_error(NULL); return -1; } VipsImage *out; if (vips_jpegload_buffer(base_image->data, base_image->data_sz, &out, "shrink", uhdr->shrink, NULL)) return -1; if (vips_image_write(out, load->real)) { VIPS_UNREF(out); return -1; } VIPS_UNREF(out); return 0; } static void vips_foreign_load_uhdr_class_init(VipsForeignLoadUhdrClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_uhdr_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrload_base"; object_class->description = _("load a UHDR image"); object_class->build = vips_foreign_load_uhdr_build; /* We need to be higher priority than jpegload. */ foreign_class->priority = 100; load_class->get_flags = vips_foreign_load_uhdr_get_flags; load_class->header = vips_foreign_load_uhdr_header; load_class->load = vips_foreign_load_uhdr_load; VIPS_ARG_INT(class, "shrink", 11, _("Shrink"), _("Shrink factor on load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadUhdr, shrink), 1, 8, 1); } static void vips_foreign_load_uhdr_init(VipsForeignLoadUhdr *uhdr) { uhdr->shrink = 1; } typedef struct _VipsForeignLoadUhdrFile { VipsForeignLoadUhdr parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadUhdrFile; typedef VipsForeignLoadUhdrClass VipsForeignLoadUhdrFileClass; G_DEFINE_TYPE(VipsForeignLoadUhdrFile, vips_foreign_load_uhdr_file, vips_foreign_load_uhdr_get_type()); static int vips_foreign_load_uhdr_file_build(VipsObject *object) { VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) object; VipsForeignLoadUhdrFile *file = (VipsForeignLoadUhdrFile *) object; if (file->filename && !(uhdr->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_uhdr_file_parent_class) ->build(object); } static gboolean vips_foreign_load_uhdr_file_is_a(const char *filename) { VipsSource *source; if (!(source = vips_source_new_from_file(filename))) return FALSE; gboolean is_a = vips_foreign_load_uhdr_is_a(source); VIPS_UNREF(source); return is_a; } static void vips_foreign_load_uhdr_file_class_init(VipsForeignLoadUhdrFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrload"; object_class->build = vips_foreign_load_uhdr_file_build; foreign_class->suffs = vips__jpeg_suffs; load_class->is_a = vips_foreign_load_uhdr_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadUhdrFile, filename), NULL); } static void vips_foreign_load_uhdr_file_init(VipsForeignLoadUhdrFile *file) { } typedef struct _VipsForeignLoadUhdrBuffer { VipsForeignLoadUhdr parent_object; /* Load from a buffer. */ VipsArea *buf; } VipsForeignLoadUhdrBuffer; typedef VipsForeignLoadUhdrClass VipsForeignLoadUhdrBufferClass; G_DEFINE_TYPE(VipsForeignLoadUhdrBuffer, vips_foreign_load_uhdr_buffer, vips_foreign_load_uhdr_get_type()); static int vips_foreign_load_uhdr_buffer_build(VipsObject *object) { VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) object; VipsForeignLoadUhdrBuffer *buffer = (VipsForeignLoadUhdrBuffer *) object; if (buffer->buf && !(uhdr->source = vips_source_new_from_memory( VIPS_AREA(buffer->buf)->data, VIPS_AREA(buffer->buf)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_uhdr_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_uhdr_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; gboolean is_a = vips_foreign_load_uhdr_is_a(source); VIPS_UNREF(source); return is_a; } static void vips_foreign_load_uhdr_buffer_class_init( VipsForeignLoadUhdrBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrload_buffer"; object_class->build = vips_foreign_load_uhdr_buffer_build; load_class->is_a_buffer = vips_foreign_load_uhdr_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadUhdrBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_load_uhdr_buffer_init(VipsForeignLoadUhdrBuffer *buffer) { } typedef struct _VipsForeignLoadUhdrSource { VipsForeignLoadUhdr parent_object; /* Load from a source. */ VipsSource *source; } VipsForeignLoadUhdrSource; typedef VipsForeignLoadUhdrClass VipsForeignLoadUhdrSourceClass; G_DEFINE_TYPE(VipsForeignLoadUhdrSource, vips_foreign_load_uhdr_source, vips_foreign_load_uhdr_get_type()); static int vips_foreign_load_uhdr_source_build(VipsObject *object) { VipsForeignLoadUhdr *uhdr = (VipsForeignLoadUhdr *) object; VipsForeignLoadUhdrSource *source = (VipsForeignLoadUhdrSource *) object; if (source->source) { uhdr->source = source->source; g_object_ref(uhdr->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_uhdr_source_parent_class) ->build(object); } static gboolean vips_foreign_load_uhdr_source_is_a_source(VipsSource *source) { return vips_foreign_load_uhdr_is_a(source); } static void vips_foreign_load_uhdr_source_class_init( VipsForeignLoadUhdrSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrload_source"; object_class->build = vips_foreign_load_uhdr_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_uhdr_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadUhdrSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_uhdr_source_init(VipsForeignLoadUhdrSource *source) { } #endif /*HAVE_UHDR*/ /** * vips_uhdrload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read an UltraHDR image. * * The UltraHDR image is decoded as a tone-mapped SDR base image * plus a gainmap attached as image metadata. * * Either process the SDR image and update the gainmap if necessary, or use * [method@Image.uhdr2scRGB] to convert the SDR + gainmap image to full scRGB * HDR. * * [method@Image.uhdrsave] can write both scRGB HDR and SDR plus gainmap * images. * * Set @shrink to shrink the returned image by an integer factor during load. * * ::: tip "Optional arguments" * * @shrink: `gint`, shrink by this factor on load * * ::: seealso * [ctor@Image.new_from_file], [method@Image.uhdr2scRGB]. * * Returns: 0 on success, -1 on error. */ int vips_uhdrload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("uhdrload", ap, filename, out); va_end(ap); return result; } /** * vips_uhdrload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.uhdrload], but read from a buffer. * * ::: tip "Optional arguments" * * @shrink: `gint`, shrink by this factor on load * * Returns: 0 on success, -1 on error. */ int vips_uhdrload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("uhdrload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_uhdrload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.uhdrload], but read from a source. * * ::: tip "Optional arguments" * * @shrink: `gint`, shrink by this factor on load * * Returns: 0 on success, -1 on error. */ int vips_uhdrload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("uhdrload_source", ap, source, out); va_end(ap); return result; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/uhdrsave.c�����������������������������������������������������������0000664�0000000�0000000�00000051170�15163036615�0020362�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* save with libuhdr * * 25/8/25 * - from heifsave.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #ifdef HAVE_UHDR #include "pforeign.h" #include // no suffs, we don't want to trigger directly for jpeg save const char *vips__uhdr_suffs[] = { NULL }; const char *vips__uhdr_error_str(uhdr_codec_err_t err); void vips__uhdr_error(uhdr_error_info_t *error); #ifdef DEBUG const char *vips__img_fmt_str(uhdr_img_fmt_t fmt); const char *vips__color_gamut_str(uhdr_color_gamut_t cg); const char *vips__color_transfer_str(uhdr_color_transfer_t ct); const char *vips__color_range_str(uhdr_color_range_t range); void vips__print_raw(uhdr_raw_image_t *raw); #endif /*DEBUG*/ typedef struct _VipsForeignSaveUhdr { VipsForeignSave parent_object; /* Where to write (set by subclasses). */ VipsTarget *target; int Q; int gainmap_scale_factor; uhdr_codec_private_t *enc; } VipsForeignSaveUhdr; typedef VipsForeignSaveClass VipsForeignSaveUhdrClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveUhdr, vips_foreign_save_uhdr, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_uhdr_dispose(GObject *gobject) { VipsForeignSaveUhdr *uhdr = (VipsForeignSaveUhdr *) gobject; VIPS_UNREF(uhdr->target); VIPS_FREEF(uhdr_release_encoder, uhdr->enc); G_OBJECT_CLASS(vips_foreign_save_uhdr_parent_class)->dispose(gobject); } typedef guint16 half; // from BSD-licenced code by njuff on SO static half vips__float_to_half(guint32 ia) { guint16 ir; ir = (ia >> 16) & 0x8000; if ((ia & 0x7f800000) == 0x7f800000) { if ((ia & 0x7fffffff) == 0x7f800000) ir |= 0x7c00; /* infinity */ else ir |= 0x7e00 | ((ia >> (24 - 11)) & 0x1ff); /* NaN, quietened */ } else if ((ia & 0x7f800000) >= 0x33000000) { int shift = (int) ((ia >> 23) & 0xff) - 127; if (shift > 15) ir |= 0x7c00; /* infinity */ else { ia = (ia & 0x007fffff) | 0x00800000; /* extract mantissa */ if (shift < -14) { /* denormal */ ir |= ia >> (-1 - shift); ia = ia << (32 - (-1 - shift)); } else { /* normal */ ir |= ia >> (24 - 11); ia = ia << (32 - (24 - 11)); ir = ir + ((14 + shift) << 10); } /* IEEE-754 round to nearest of even */ if ((ia > 0x80000000) || ((ia == 0x80000000) && (ir & 1))) ir++; } } return ir; } static int vips_foreign_save_uhdr_generate(VipsRegion *region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = ®ion->valid; uhdr_raw_image_t *raw = (uhdr_raw_image_t *) a; half *base = (half *) raw->planes[0]; int stride = 4 * raw->stride[0]; for (int y = 0; y < r->height; y++) { unsigned int *p = (unsigned int *) VIPS_REGION_ADDR(region, r->left, r->top + y); half *q = base + stride * (r->top + y) + 4 * r->left; for (int x = 0; x < r->width; x++) { q[0] = vips__float_to_half(p[0]); q[1] = vips__float_to_half(p[1]); q[2] = vips__float_to_half(p[2]); q[3] = vips__float_to_half(p[3]); p += 4; q += 4; } } return 0; } static int vips_foreign_save_uhdr_set_raw_hdr(VipsForeignSaveUhdr *uhdr, VipsImage *image) { uhdr_error_info_t error_info; g_info("attaching raw HDR image"); g_assert(image->Bands == 4); g_assert(image->BandFmt == VIPS_FORMAT_FLOAT); g_assert(image->Coding == VIPS_CODING_NONE); uhdr_raw_image_t hdr_image = { .fmt = UHDR_IMG_FMT_64bppRGBAHalfFloat, .cg = UHDR_CG_BT_709, .ct = UHDR_CT_LINEAR, .range = UHDR_CR_FULL_RANGE, .w = image->Xsize, .h = image->Ysize, .planes[0] = (void *) VIPS_ARRAY(uhdr, image->Xsize * image->Ysize * 8, VipsPel), .stride[0] = image->Xsize, }; if (!hdr_image.planes[0]) return -1; if (vips_image_pio_input(image)) return -1; if (vips_sink(image, NULL, vips_foreign_save_uhdr_generate, NULL, &hdr_image, NULL)) return -1; error_info = uhdr_enc_set_raw_image(uhdr->enc, &hdr_image, UHDR_HDR_IMG); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } return 0; } static int image_get_float(VipsImage *image, const char *name, float *f) { double d; if (vips_image_get_double(image, name, &d)) return -1; *f = d; return 0; } // pass in the array to fill, size must match static int image_get_array_float(VipsImage *image, const char *name, float *out, int n_out) { double *d; int n; if (vips_image_get_array_double(image, name, &d, &n)) return -1; if (n != n_out) { vips_error("image_get_array_float", _("bad size")); return -1; } for (int i = 0; i < n; i++) out[i] = d[i]; return 0; } static int vips_foreign_save_uhdr_set_compressed_gainmap(VipsForeignSaveUhdr *uhdr, VipsImage *image) { g_info("attaching compressed gainmap"); uhdr_gainmap_metadata_t metadata; if (image_get_array_float(image, "gainmap-max-content-boost", &metadata.max_content_boost[0], 3) || image_get_array_float(image, "gainmap-min-content-boost", &metadata.min_content_boost[0], 3) || image_get_array_float(image, "gainmap-gamma", &metadata.gamma[0], 3) || image_get_array_float(image, "gainmap-offset-sdr", &metadata.offset_sdr[0], 3) || image_get_array_float(image, "gainmap-offset-hdr", &metadata.offset_hdr[0], 3) || image_get_float(image, "gainmap-hdr-capacity-min", &metadata.hdr_capacity_min) || image_get_float(image, "gainmap-hdr-capacity-max", &metadata.hdr_capacity_max) || vips_image_get_int(image, "gainmap-use-base-cg", &metadata.use_base_cg)) return -1; /* If there's a processed gainmap, compress and attach that. Otherwise * attach the compressed gainmap from the input image. */ const void *data; size_t length; void *to_free; data = NULL; to_free = NULL; if (vips_image_get_typeof(image, "gainmap")) { VipsImage *gainmap; if (vips_image_get_image(image, "gainmap", &gainmap)) return -1; /* Never chroma subsample gainmaps, they are exponents, not RGB images. */ if (vips_jpegsave_buffer(gainmap, &to_free, &length, "subsample-mode", VIPS_FOREIGN_SUBSAMPLE_OFF, "Q", uhdr->Q, NULL)) { VIPS_UNREF(gainmap); return -1; } VIPS_UNREF(gainmap); data = to_free; } else if (vips_image_get_typeof(image, "gainmap-data") && vips_image_get_blob(image, "gainmap-data", &data, &length)) return -1; if (data) { uhdr_error_info_t error_info; uhdr_compressed_image_t gainmap_image = { .data = (void *) data, .data_sz = length, .capacity = length, }; error_info = uhdr_enc_set_gainmap_image(uhdr->enc, &gainmap_image, &metadata); if (error_info.error_code) { vips__uhdr_error(&error_info); VIPS_FREE(to_free); return -1; } } VIPS_FREE(to_free); return 0; } static int vips_foreign_save_uhdr_set_compressed_base(VipsForeignSaveUhdr *uhdr, VipsImage *image) { VipsObject **t = vips_object_local_array(VIPS_OBJECT(uhdr), 4); VipsTarget *temp; VipsSource *base; g_info("attaching compressed base"); if (!(temp = vips_target_new_temp(uhdr->target))) return -1; t[0] = VIPS_OBJECT(temp); // we don't want jpegsave to think this is a uhdr image it should pass // back to us: remove any gainmap to stop confusion if (vips_copy(image, (VipsImage **) &t[1], NULL)) return -1; image = VIPS_IMAGE(t[1]); vips_image_remove(image, "gainmap"); vips_image_remove(image, "gainmap-data"); if (vips_jpegsave_target(image, temp, "Q", uhdr->Q, NULL)) return -1; if (!(base = vips_source_new_from_target(temp))) return -1; t[2] = VIPS_OBJECT(base); const void *data; size_t length; if (!(data = vips_source_map(base, &length))) return -1; uhdr_compressed_image_t base_image = { .data = (void *) data, .data_sz = length, .capacity = length, }; uhdr_error_info_t error_info = uhdr_enc_set_compressed_image(uhdr->enc, &base_image, UHDR_BASE_IMG); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } return 0; } // save hdr static int vips_foreign_save_uhdr_hdr(VipsForeignSaveUhdr *uhdr, VipsImage *image) { uhdr_error_info_t error_info; g_info("saving scRGB as UltraHDR"); uhdr_enc_set_output_format(uhdr->enc, UHDR_CODEC_JPG); uhdr_enc_set_gainmap_scale_factor(uhdr->enc, uhdr->gainmap_scale_factor); uhdr_enc_set_using_multi_channel_gainmap(uhdr->enc, 0); // attach the gainmap, if we have one if (vips_image_get_typeof(image, "gainmap-data") && vips_foreign_save_uhdr_set_compressed_gainmap(uhdr, image)) return -1; if (vips_foreign_save_uhdr_set_raw_hdr(uhdr, image)) return -1; error_info = uhdr_encode(uhdr->enc); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } return 0; } // save sdr + gainmap static int vips_foreign_save_uhdr_sdr(VipsForeignSaveUhdr *uhdr, VipsImage *image) { uhdr_error_info_t error_info; g_info("saving base and gainmap as UltraHDR"); if (vips_foreign_save_uhdr_set_compressed_gainmap(uhdr, image) || vips_foreign_save_uhdr_set_compressed_base(uhdr, image)) return -1; error_info = uhdr_encode(uhdr->enc); if (error_info.error_code) { vips__uhdr_error(&error_info); return -1; } return 0; } static int vips_foreign_save_uhdr_build(VipsObject *object) { VipsForeignSave *save = VIPS_FOREIGN_SAVE(object); VipsForeignSaveUhdr *uhdr = (VipsForeignSaveUhdr *) object; uhdr_error_info_t error_info; if (VIPS_OBJECT_CLASS(vips_foreign_save_uhdr_parent_class)->build(object)) return -1; VipsImage *image = save->ready; g_object_ref(image); uhdr->enc = uhdr_create_encoder(); if (vips_image_get_typeof(image, VIPS_META_EXIF_NAME)) { const void *data; size_t length; if (vips_image_get_blob(image, VIPS_META_EXIF_NAME, &data, &length)) { VIPS_UNREF(image); return -1; } uhdr_mem_block_t exif = { .data = (void *) data, .data_sz = length, .capacity = length, }; error_info = uhdr_enc_set_exif_data(uhdr->enc, &exif); if (error_info.error_code) { vips__uhdr_error(&error_info); VIPS_UNREF(image); return -1; } } // libuhdr has no set_icc API, that's done for us from the gainmap metadata error_info = uhdr_enc_set_quality(uhdr->enc, uhdr->Q, UHDR_BASE_IMG); if (error_info.error_code) { vips__uhdr_error(&error_info); VIPS_UNREF(image); return -1; } error_info = uhdr_enc_set_quality(uhdr->enc, uhdr->Q, UHDR_GAIN_MAP_IMG); if (error_info.error_code) { vips__uhdr_error(&error_info); VIPS_UNREF(image); return -1; } if (image->Type == VIPS_INTERPRETATION_scRGB) { VipsImage *x; // fix bands, format, etc. if (vips_colourspace(image, &x, VIPS_INTERPRETATION_scRGB, NULL)) { VIPS_UNREF(image); return -1; } VIPS_UNREF(image); image = x; // libuhdr needs RGBA if (!vips_image_hasalpha(image)) { if (vips_addalpha(image, &x, NULL)) { VIPS_UNREF(image); return -1; } VIPS_UNREF(image); image = x; } if (vips_foreign_save_uhdr_hdr(uhdr, image)) { VIPS_UNREF(image); return -1; } } else { // we can rely on jpegsave to transform for save for us if (vips_foreign_save_uhdr_sdr(uhdr, image)) { VIPS_UNREF(image); return -1; } } VIPS_UNREF(image); uhdr_compressed_image_t *output = uhdr_get_encoded_stream(uhdr->enc); if (!output) { vips__uhdr_error(NULL); return -1; } if (vips_target_write(uhdr->target, output->data, output->data_sz)) return -1; if (vips_target_end(uhdr->target)) return -1; VIPS_FREEF(uhdr_release_encoder, uhdr->enc); return 0; } static void vips_foreign_save_uhdr_class_init(VipsForeignSaveUhdrClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_uhdr_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrsave_base"; object_class->description = _("save image in UltraHDR format"); object_class->build = vips_foreign_save_uhdr_build; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; VIPS_ARG_INT(class, "Q", 10, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveUhdr, Q), 1, 100, 75); VIPS_ARG_INT(class, "gainmap_scale_factor", 11, _("Gainmap scale factor"), _("The scale factor of base image to gainmap image"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveUhdr, gainmap_scale_factor), 1, 128, 2); } static void vips_foreign_save_uhdr_init(VipsForeignSaveUhdr *uhdr) { uhdr->Q = 75; uhdr->gainmap_scale_factor = 2; } typedef struct _VipsForeignSaveUhdrFile { VipsForeignSaveUhdr parent_object; /* Filename for save. */ char *filename; } VipsForeignSaveUhdrFile; typedef VipsForeignSaveUhdrClass VipsForeignSaveUhdrFileClass; G_DEFINE_TYPE(VipsForeignSaveUhdrFile, vips_foreign_save_uhdr_file, vips_foreign_save_uhdr_get_type()); static int vips_foreign_save_uhdr_file_build(VipsObject *object) { VipsForeignSaveUhdr *uhdr = (VipsForeignSaveUhdr *) object; VipsForeignSaveUhdrFile *file = (VipsForeignSaveUhdrFile *) object; if (file->filename && !(uhdr->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_uhdr_file_parent_class) ->build(object); } static void vips_foreign_save_uhdr_file_class_init(VipsForeignSaveUhdrFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrsave"; object_class->build = vips_foreign_save_uhdr_file_build; foreign_class->suffs = vips__uhdr_suffs; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveUhdrFile, filename), NULL); } static void vips_foreign_save_uhdr_file_init(VipsForeignSaveUhdrFile *file) { } typedef struct _VipsForeignSaveUhdrBuffer { VipsForeignSaveUhdr parent_object; /* Save to a buffer. */ VipsArea *buf; } VipsForeignSaveUhdrBuffer; typedef VipsForeignSaveUhdrClass VipsForeignSaveUhdrBufferClass; G_DEFINE_TYPE(VipsForeignSaveUhdrBuffer, vips_foreign_save_uhdr_buffer, vips_foreign_save_uhdr_get_type()); static int vips_foreign_save_uhdr_buffer_build(VipsObject *object) { VipsForeignSaveUhdr *uhdr = (VipsForeignSaveUhdr *) object; VipsForeignSaveUhdrBuffer *buffer = (VipsForeignSaveUhdrBuffer *) object; VipsBlob *blob; if (!(uhdr->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_uhdr_buffer_parent_class) ->build(object)) return -1; g_object_get(uhdr->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_uhdr_buffer_class_init( VipsForeignSaveUhdrBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrsave_buffer"; object_class->build = vips_foreign_save_uhdr_buffer_build; foreign_class->suffs = vips__uhdr_suffs; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveUhdrBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_uhdr_buffer_init(VipsForeignSaveUhdrBuffer *buffer) { } typedef struct _VipsForeignSaveUhdrTarget { VipsForeignSaveUhdr parent_object; VipsTarget *target; } VipsForeignSaveUhdrTarget; typedef VipsForeignSaveUhdrClass VipsForeignSaveUhdrTargetClass; G_DEFINE_TYPE(VipsForeignSaveUhdrTarget, vips_foreign_save_uhdr_target, vips_foreign_save_uhdr_get_type()); static int vips_foreign_save_uhdr_target_build(VipsObject *object) { VipsForeignSaveUhdr *uhdr = (VipsForeignSaveUhdr *) object; VipsForeignSaveUhdrTarget *target = (VipsForeignSaveUhdrTarget *) object; if (target->target) { uhdr->target = target->target; g_object_ref(uhdr->target); } return VIPS_OBJECT_CLASS(vips_foreign_save_uhdr_target_parent_class) ->build(object); } static void vips_foreign_save_uhdr_target_class_init( VipsForeignSaveUhdrTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "uhdrsave_target"; object_class->build = vips_foreign_save_uhdr_target_build; foreign_class->suffs = vips__uhdr_suffs; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveUhdrTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_uhdr_target_init(VipsForeignSaveUhdrTarget *target) { } #endif /*HAVE_UHDR*/ /** * vips_uhdrsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Save an image as UltraHDR. * * If an image is sRGB and has a gainmap, it will be saved as UltraHDR with no * gainmap recomputation. * * If the image is scRGB and has a gainmap, a base image will be computed * and it will be saved as UltraHDR. * * If the image is scRGB and has no gainmap, one will be computed at a * @gainmap_scale_factor of the base image. * This is slow and takes a lot of memory. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @gainmap_scale_factor: `gint`, scale factor of base image to gainmap * * ::: seealso * [method@Image.write_to_file], [ctor@Image.uhdrload]. * * Returns: 0 on success, -1 on error. */ int vips_uhdrsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("uhdrsave", ap, in, filename); va_end(ap); return result; } /** * vips_uhdrsave_buffer: (method) * @in: image to save * @buf: (array length=len) (element-type guint8): return output buffer here * @len: (type gsize): return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.uhdrsave], but save to a memory buffer. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @gainmap_scale_factor: `gint`, scale factor of base image to gainmap * * ::: seealso * [method@Image.uhdrsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_uhdrsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("uhdrsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_uhdrsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.uhdrsave], but save to a target. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @gainmap_scale_factor: `gint`, scale factor of base image to gainmap * * ::: seealso * [method@Image.uhdrsave], [method@Image.write_to_target]. * * Returns: 0 on success, -1 on error. */ int vips_uhdrsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("uhdrsave_target", ap, in, target); va_end(ap); return result; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������libvips-8.18.2/libvips/foreign/vips2jpeg.c����������������������������������������������������������0000664�0000000�0000000�00000062457�15163036615�0020464�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* wrap jpeg library for write * * 28/11/03 JC * - better no-overshoot on tile loop * 12/11/04 * - better demand size choice for eval * 30/6/05 JC * - update im_error()/im_warn() * - now loads and saves exif data * 30/7/05 * - now loads ICC profiles * - now saves ICC profiles from the VIPS header * 24/8/05 * - jpeg load sets vips xres/yres from exif, if possible * - jpeg save sets exif xres/yres from vips, if possible * 29/8/05 * - cut from old vips_jpeg.c * 20/4/06 * - auto convert to sRGB/mono for save * 13/10/06 * - add = 90 * 7/11/16 * - move exif handling out to exif.c * 27/2/17 * - use dbuf for memory output * 19/12/17 Lovell * - fix a leak with an error during buffer output * 19/4/19 * - fix another leak with error during buffer output * 19/7/19 * - ignore large XMP * 14/10/19 * - revise for target IO * 18/2/20 Elad-Laufer * - add subsample_mode, deprecate no_subsample * 13/9/20 * - only write JFIF resolution if we don't have EXIF * 7/10/21 Manthey * - add restart_interval * 21/10/21 usualuse * - raise single-chunk limit on APP to 65533 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_JPEG #include "jpeg.h" #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ #define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) const char *vips__jpeg_message_table[] = { "premature end of JPEG image", "unable to write to target", NULL }; /* New output message method - send to VIPS. */ void vips__new_output_message(j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; (*cinfo->err->format_message)(cinfo, buffer); vips_error("VipsJpeg", _("%s"), buffer); #ifdef DEBUG printf("vips__new_output_message: \"%s\"\n", buffer); #endif /*DEBUG*/ } /* New error_exit handler. */ void vips__new_error_exit(j_common_ptr cinfo) { ErrorManager *eman = (ErrorManager *) cinfo->err; #ifdef DEBUG printf("vips__new_error_exit:\n"); #endif /*DEBUG*/ /* Close the fp if necessary. */ if (eman->fp) { (void) fclose(eman->fp); eman->fp = NULL; } /* Send the error message to VIPS. This method is overridden above. */ (*cinfo->err->output_message)(cinfo); /* Jump back. */ longjmp(eman->jmp, 1); } /* What we track during a JPEG write. */ typedef struct { struct jpeg_compress_struct cinfo; ErrorManager eman; JSAMPROW *row_pointer; gboolean invert; } Write; static void write_destroy(Write *write) { jpeg_destroy_compress(&write->cinfo); VIPS_FREE(write->row_pointer); g_free(write); } static Write * write_new(void) { Write *write; if (!(write = g_new0(Write, 1))) return NULL; write->row_pointer = NULL; write->cinfo.err = jpeg_std_error(&write->eman.pub); write->cinfo.err->addon_message_table = vips__jpeg_message_table; write->cinfo.err->first_addon_message = 1000; write->cinfo.err->last_addon_message = 1001; write->cinfo.dest = NULL; write->eman.pub.error_exit = vips__new_error_exit; write->eman.pub.output_message = vips__new_output_message; write->eman.fp = NULL; write->invert = FALSE; return write; } static int write_blob(Write *write, VipsImage *image, const char *field, int app) { unsigned char *data; size_t data_length; if (!vips_image_get_typeof(image, field)) return 0; if (vips_image_get_blob(image, field, (void *) &data, &data_length)) return -1; /* Single jpeg markers can only hold 64kb, large objects must * be split into multiple markers. * * Unfortunately, how this splitting is done depends on the * data type. For example, ICC and XMP have completely * different ways of doing this. * * For now, just ignore oversize objects and warn. */ if (data_length > MAX_BYTES_IN_MARKER) g_warning("field \"%s\" is too large " "for a single JPEG marker, ignoring", field); else { #ifdef DEBUG printf("write_blob: attaching %zd bytes of %s\n", data_length, field); #endif /*DEBUG*/ jpeg_write_marker(&write->cinfo, app, data, data_length); } return 0; } #define XML_URL "http://ns.adobe.com/xap/1.0/" static int write_xmp(Write *write, VipsImage *in) { unsigned char *data; size_t data_length; char *p; if (!vips_image_get_typeof(in, VIPS_META_XMP_NAME)) return 0; if (vips_image_get_blob(in, VIPS_META_XMP_NAME, (void *) &data, &data_length)) return -1; /* To write >64kb XMP it you need to parse the whole XMP object, * pull out the most important fields, code just them into the main * XMP block, then write any remaining XMP objects into a set of * extended XMP markers. * * http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/ \ * XMPSpecificationPart3.pdf * * jpeg_write_marker() with some libjpeg versions will throw a fatal * error with large chunks. */ if (data_length > 60000) { g_warning("large XMP not saved"); return 0; } /* We need to add the magic XML URL to the start, then a null * character, then the data. */ p = g_malloc(data_length + strlen(XML_URL) + 1); strcpy(p, XML_URL); memcpy(p + strlen(XML_URL) + 1, data, data_length); jpeg_write_marker(&write->cinfo, JPEG_APP0 + 1, (unsigned char *) p, data_length + strlen(XML_URL) + 1); g_free(p); return 0; } static int write_exif(Write *write, VipsImage *image) { if (write_blob(write, image, VIPS_META_EXIF_NAME, JPEG_APP0 + 1)) return -1; return 0; } /* ICC writer from lcms, slight tweaks. */ /* * This routine writes the given ICC profile data into a JPEG file. * It *must* be called AFTER calling jpeg_start_compress() and BEFORE * the first call to jpeg_write_scanlines(). * (This ordering ensures that the APP2 marker(s) will appear after the * SOI and JFIF or Adobe markers, but before all else.) */ static void write_profile_data(j_compress_ptr cinfo, const JOCTET *icc_data_ptr, unsigned int icc_data_len) { unsigned int num_markers; /* total number of markers we'll write */ int cur_marker = 1; /* per spec, counting starts at 1 */ unsigned int length; /* number of bytes to write in this marker */ /* rounding up will fail for length == 0 */ g_assert(icc_data_len > 0); /* Calculate the number of markers we'll need, rounding up of course */ num_markers = (icc_data_len + MAX_DATA_BYTES_IN_MARKER - 1) / MAX_DATA_BYTES_IN_MARKER; while (icc_data_len > 0) { /* length of profile to put in this marker */ length = icc_data_len; if (length > MAX_DATA_BYTES_IN_MARKER) length = MAX_DATA_BYTES_IN_MARKER; icc_data_len -= length; /* Write the JPEG marker header (APP2 code and marker length) */ jpeg_write_m_header(cinfo, ICC_MARKER, (unsigned int) (length + ICC_OVERHEAD_LEN)); /* Write the marker identifying string "ICC_PROFILE" (null-terminated). * We code it in this less-than-transparent way so that the code works * even if the local character set is not ASCII. */ jpeg_write_m_byte(cinfo, 0x49); jpeg_write_m_byte(cinfo, 0x43); jpeg_write_m_byte(cinfo, 0x43); jpeg_write_m_byte(cinfo, 0x5F); jpeg_write_m_byte(cinfo, 0x50); jpeg_write_m_byte(cinfo, 0x52); jpeg_write_m_byte(cinfo, 0x4F); jpeg_write_m_byte(cinfo, 0x46); jpeg_write_m_byte(cinfo, 0x49); jpeg_write_m_byte(cinfo, 0x4C); jpeg_write_m_byte(cinfo, 0x45); jpeg_write_m_byte(cinfo, 0x0); /* Add the sequencing info */ jpeg_write_m_byte(cinfo, cur_marker); jpeg_write_m_byte(cinfo, (int) num_markers); /* Add the profile data */ while (length--) { jpeg_write_m_byte(cinfo, *icc_data_ptr); icc_data_ptr++; } cur_marker++; } } #ifndef HAVE_EXIF /* Set the JFIF resolution from the vips xres/yres tags. */ static void vips_jfif_resolution_from_image(struct jpeg_compress_struct *cinfo, VipsImage *image) { int xres, yres; const char *p; int unit; /* Default to inches, more progs support it. */ unit = 1; if (vips_image_get_typeof(image, VIPS_META_RESOLUTION_UNIT) && !vips_image_get_string(image, VIPS_META_RESOLUTION_UNIT, &p)) { if (vips_isprefix("cm", p)) unit = 2; else if (vips_isprefix("none", p)) unit = 0; } switch (unit) { case 0: xres = rint(image->Xres); yres = rint(image->Yres); break; case 1: xres = rint(image->Xres * 25.4); yres = rint(image->Yres * 25.4); break; case 2: xres = rint(image->Xres * 10.0); yres = rint(image->Yres * 10.0); break; default: g_assert_not_reached(); break; } VIPS_DEBUG_MSG("vips_jfif_resolution_from_image: " "setting xres = %d, yres = %d, unit = %d\n", xres, yres, unit); cinfo->density_unit = unit; cinfo->X_density = xres; cinfo->Y_density = yres; } #endif /*HAVE_EXIF*/ /* Write an ICC Profile from a file into the JPEG stream. */ static int write_profile_file(Write *write, const char *profile) { VipsBlob *blob; if (vips_profile_load(profile, &blob, NULL)) return -1; if (blob) { size_t length; const void *data = vips_blob_get(blob, &length); write_profile_data(&write->cinfo, (JOCTET *) data, length); #ifdef DEBUG printf("write_profile_file: attached profile \"%s\"\n", profile); #endif /*DEBUG*/ vips_area_unref((VipsArea *) blob); } return 0; } static int write_profile_meta(Write *write, VipsImage *in) { const void *data; size_t length; if (vips_image_get_blob(in, VIPS_META_ICC_NAME, &data, &length)) return -1; write_profile_data(&write->cinfo, data, length); #ifdef DEBUG printf("write_profile_meta: attached %zd byte profile from header\n", length); #endif /*DEBUG*/ return 0; } static int write_jpeg_block(VipsRegion *region, VipsRect *area, void *a) { Write *write = (Write *) a; for (int y = 0; y < area->height; y++) write->row_pointer[y] = (JSAMPROW) VIPS_REGION_ADDR(region, area->left, area->top + y); /* Catch any longjmp()s from jpeg_write_scanlines() here. */ if (setjmp(write->eman.jmp)) return -1; if (write->invert) { int n_elements = region->im->Bands * area->width; for (int y = 0; y < area->height; y++) { unsigned char *line = write->row_pointer[y]; for (int x = 0; x < n_elements; x++) line[x] = 255 - line[x]; } } jpeg_write_scanlines(&write->cinfo, write->row_pointer, area->height); return 0; } /* Set up cinfo. Pass width and height separately so we can be * used for region write. */ static void set_cinfo(struct jpeg_compress_struct *cinfo, VipsImage *in, int width, int height, int qfac, gboolean optimize_coding, gboolean progressive, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval) { J_COLOR_SPACE space; /* Set compression parameters. */ cinfo->image_width = width; cinfo->image_height = height; cinfo->input_components = in->Bands; if (in->Bands == 4 && in->Type == VIPS_INTERPRETATION_CMYK) { space = JCS_CMYK; } else if (in->Bands == 3) space = JCS_RGB; else if (in->Bands == 1) space = JCS_GRAYSCALE; else /* Use luminance compression for all channels. */ space = JCS_UNKNOWN; cinfo->in_color_space = space; #ifdef HAVE_JPEG_EXT_PARAMS /* Reset compression profile to libjpeg defaults */ if (jpeg_c_int_param_supported(cinfo, JINT_COMPRESS_PROFILE)) jpeg_c_set_int_param(cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST); #endif /* Reset to default. */ jpeg_set_defaults(cinfo); /* Compute optimal Huffman coding tables. */ cinfo->optimize_coding = optimize_coding; /* Use a restart interval. */ if (restart_interval > 0) cinfo->restart_interval = restart_interval; #ifdef HAVE_JPEG_EXT_PARAMS /* Apply trellis quantisation to each 8x8 block. Implies * "optimize_coding". */ if (trellis_quant) { if (jpeg_c_bool_param_supported(cinfo, JBOOLEAN_TRELLIS_QUANT)) { jpeg_c_set_bool_param(cinfo, JBOOLEAN_TRELLIS_QUANT, TRUE); cinfo->optimize_coding = TRUE; } else g_warning("trellis_quant unsupported"); } /* Apply overshooting to samples with extreme values e.g. 0 & 255 * for 8-bit. */ if (overshoot_deringing) { if (jpeg_c_bool_param_supported(cinfo, JBOOLEAN_OVERSHOOT_DERINGING)) jpeg_c_set_bool_param(cinfo, JBOOLEAN_OVERSHOOT_DERINGING, TRUE); else g_warning("overshoot_deringing unsupported"); } /* Split the spectrum of DCT coefficients into separate scans. * Requires progressive output. Must be set before * jpeg_simple_progression. */ if (optimize_scans) { if (progressive) { if (jpeg_c_bool_param_supported(cinfo, JBOOLEAN_OPTIMIZE_SCANS)) jpeg_c_set_bool_param(cinfo, JBOOLEAN_OPTIMIZE_SCANS, TRUE); else g_warning("ignoring optimize_scans"); } else g_warning("ignoring optimize_scans for baseline"); } /* Use predefined quantization table. */ if (quant_table > 0) { if (jpeg_c_int_param_supported(cinfo, JINT_BASE_QUANT_TBL_IDX)) jpeg_c_set_int_param(cinfo, JINT_BASE_QUANT_TBL_IDX, quant_table); else g_warning("setting quant_table unsupported"); } #else /* Using jpeglib.h without extension parameters, warn of ignored * options. */ if (trellis_quant) g_warning("ignoring trellis_quant"); if (overshoot_deringing) g_warning("ignoring overshoot_deringing"); if (optimize_scans) g_warning("ignoring optimize_scans"); if (quant_table > 0) g_warning("ignoring quant_table"); #endif /* Set compression quality. Must be called after setting params above. */ jpeg_set_quality(cinfo, qfac, TRUE); /* Enable progressive write. */ if (progressive) jpeg_simple_progression(cinfo); /* We must set chroma subsampling explicitly since some libjpegs do not * enable this by default. */ if (in->Bands == 3 && (subsample_mode == VIPS_FOREIGN_SUBSAMPLE_ON || (subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO && qfac < 90))) cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; else cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 1; /* Rest should have sampling factors 1,1. */ for (int i = 1; i < in->Bands; i++) cinfo->comp_info[i].h_samp_factor = cinfo->comp_info[i].v_samp_factor = 1; /* Only write the JFIF headers if we have no EXIF. * Some readers get confused if you set both. */ cinfo->write_JFIF_header = FALSE; #ifndef HAVE_EXIF vips_jfif_resolution_from_image(cinfo, in); cinfo->write_JFIF_header = TRUE; #endif /*HAVE_EXIF*/ } static int write_metadata(Write *write, VipsImage *in, const char *profile) { if (write_exif(write, in) || write_xmp(write, in) || write_blob(write, in, VIPS_META_IPTC_NAME, JPEG_APP0 + 13)) return -1; /* A profile supplied as an argument overrides an embedded * profile. */ if (profile) { if (write_profile_file(write, profile)) return -1; } else if (vips_image_get_typeof(in, VIPS_META_ICC_NAME)) { if (write_profile_meta(write, in)) return -1; } return 0; } /* Write a VIPS image to a JPEG compress struct. */ static int write_vips(Write *write, VipsImage *in, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval) { /* Should have been converted for save. */ g_assert(in->BandFmt == VIPS_FORMAT_UCHAR); g_assert(in->Coding == VIPS_CODING_NONE); /* Check input image. */ if (vips_image_pio_input(in)) return -1; set_cinfo(&write->cinfo, in, in->Xsize, in->Ysize, Q, optimize_coding, progressive, trellis_quant, overshoot_deringing, optimize_scans, quant_table, subsample_mode, restart_interval); if (in->Bands == 4 && in->Type == VIPS_INTERPRETATION_CMYK) /* IJG always sets an Adobe marker, so we should invert CMYK. */ write->invert = TRUE; /* Build VIPS output stuff now we know the image we'll be writing. */ if (!(write->row_pointer = VIPS_ARRAY(NULL, in->Ysize, JSAMPROW))) return -1; /* Write app0 and build compress tables. */ jpeg_start_compress(&write->cinfo, TRUE); /* All the other APP chunks come next. */ if (write_metadata(write, in, profile)) return -1; /* Write data. Note that the write function grabs the longjmp()! */ if (vips_sink_disc(in, write_jpeg_block, write)) return -1; /* We have to reinstate the setjmp() before we jpeg_finish_compress(). */ if (setjmp(write->eman.jmp)) return -1; /* This should only be called on a successful write. */ jpeg_finish_compress(&write->cinfo); return 0; } #define TARGET_BUFFER_SIZE (4096) typedef struct { /* Public jpeg fields. */ struct jpeg_destination_mgr pub; /* Private stuff during write. */ /* Build the output area here. */ VipsTarget *target; /* Our output buffer. */ unsigned char buf[TARGET_BUFFER_SIZE]; } Dest; /* Buffer full method. This is only called when the output area is exactly * full. */ static boolean empty_output_buffer(j_compress_ptr cinfo) { Dest *dest = (Dest *) cinfo->dest; if (vips_target_write(dest->target, dest->buf, TARGET_BUFFER_SIZE)) ERREXIT(cinfo, JERR_VIPS_TARGET_WRITE); dest->pub.next_output_byte = dest->buf; dest->pub.free_in_buffer = TARGET_BUFFER_SIZE; return TRUE; } /* Init dest method. */ static void init_destination(j_compress_ptr cinfo) { Dest *dest = (Dest *) cinfo->dest; dest->pub.next_output_byte = dest->buf; dest->pub.free_in_buffer = TARGET_BUFFER_SIZE; } /* Flush any remaining bytes to the output. */ static void term_destination(j_compress_ptr cinfo) { Dest *dest = (Dest *) cinfo->dest; if (vips_target_write(dest->target, dest->buf, TARGET_BUFFER_SIZE - dest->pub.free_in_buffer)) ERREXIT(cinfo, JERR_VIPS_TARGET_WRITE); } /* Set dest to one of our objects. */ void vips__jpeg_target_dest(j_compress_ptr cinfo, VipsTarget *target) { Dest *dest; if (!cinfo->dest) /* first time for this JPEG object? */ cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)( (j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(Dest)); dest = (Dest *) cinfo->dest; dest->pub.init_destination = init_destination; dest->pub.empty_output_buffer = empty_output_buffer; dest->pub.term_destination = term_destination; dest->target = target; } int vips__jpeg_write_target(VipsImage *in, VipsTarget *target, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval) { Write *write; if (!(write = write_new())) return -1; /* Make jpeg compression object. */ if (setjmp(write->eman.jmp)) { /* Here for longjmp() during write_vips(). */ write_destroy(write); return -1; } jpeg_create_compress(&write->cinfo); /* Attach output. */ vips__jpeg_target_dest(&write->cinfo, target); /* Convert! Write errors come back here as an error return. */ if (write_vips(write, in, Q, profile, optimize_coding, progressive, trellis_quant, overshoot_deringing, optimize_scans, quant_table, subsample_mode, restart_interval)) { write_destroy(write); return -1; } write_destroy(write); if (vips_target_end(target)) return -1; return 0; } /* Some people want to be able to save as xxx.jfif. libjpeg will write as * JFIF if it can, but if you use features like CMYK or YCCK, you'll get a * regular JPEG. So saving as .jfif won't (by itself) guarantee strict JFIF * conformance. */ const char *vips__jpeg_suffs[] = { ".jpg", ".jpeg", ".jpe", ".jfif", NULL }; /* Write a region to a JPEG compress struct. */ static int write_vips_region(Write *write, VipsRegion *region, VipsRect *rect, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, VipsForeignKeep keep, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval) { // the image we'll be writing VipsImage *in = region->im; VipsImage *x; set_cinfo(&write->cinfo, in, rect->width, rect->height, Q, optimize_coding, progressive, trellis_quant, overshoot_deringing, optimize_scans, quant_table, subsample_mode, restart_interval); /* Should have been converted for save. */ g_assert(in->BandFmt == VIPS_FORMAT_UCHAR); g_assert(in->Coding == VIPS_CODING_NONE); g_assert(in->Bands == 1 || in->Bands == 3 || in->Bands == 4); if (in->Bands == 4 && in->Type == VIPS_INTERPRETATION_CMYK) // FIXME ... need to invert on the fly as we send pixels to // libjpeg write->invert = TRUE; /* Build VIPS output stuff now we know the image we'll be writing. */ if (!(write->row_pointer = VIPS_ARRAY(NULL, rect->height, JSAMPROW))) return -1; /* Write app0 and build compress tables. */ jpeg_start_compress(&write->cinfo, TRUE); /* Updating metadata, need to copy the image. */ if (vips_copy(in, &x, NULL)) return -1; /* All the other APP chunks come next. */ if (vips__foreign_update_metadata(x, keep) || write_metadata(write, x, profile)) { g_object_unref(x); return -1; } g_object_unref(x); /* Write data. Note that the write function grabs the longjmp()! */ if (write_jpeg_block(region, rect, write)) return -1; /* We have to reinstate the setjmp() before we jpeg_finish_compress(). */ if (setjmp(write->eman.jmp)) return -1; /* This should only be called on a successful write. */ jpeg_finish_compress(&write->cinfo); return 0; } int vips__jpeg_region_write_target(VipsRegion *region, VipsRect *rect, VipsTarget *target, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, VipsForeignKeep keep, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval) { Write *write; if (!(write = write_new())) return -1; /* Make jpeg compression object. */ if (setjmp(write->eman.jmp)) { /* Here for longjmp() during write_vips(). */ write_destroy(write); return -1; } jpeg_create_compress(&write->cinfo); /* Attach output. */ vips__jpeg_target_dest(&write->cinfo, target); /* Convert! Write errors come back here as an error return. */ if (write_vips_region(write, region, rect, Q, profile, optimize_coding, progressive, keep, trellis_quant, overshoot_deringing, optimize_scans, quant_table, subsample_mode, restart_interval)) { write_destroy(write); return -1; } write_destroy(write); if (vips_target_end(target)) return -1; return 0; } #else /*!HAVE_JPEG*/ int vips__jpeg_region_write_target(VipsRegion *region, VipsRect *rect, VipsTarget *target, int Q, const char *profile, gboolean optimize_coding, gboolean progressive, VipsForeignKeep keep, gboolean trellis_quant, gboolean overshoot_deringing, gboolean optimize_scans, int quant_table, VipsForeignSubsample subsample_mode, int restart_interval) { vips_error("vips2jpeg", "%s", _("libvips built without JPEG support")); return -1; } #endif /*HAVE_JPEG*/ libvips-8.18.2/libvips/foreign/vips2magick.c000066400000000000000000000514251516303661500207630ustar00rootroot00000000000000/* save with libMagick * * 22/12/17 dlemstra * 6/2/19 DarthSim * - fix GraphicsMagick support * 17/2/19 * - support ICC, XMP, EXIF, IPTC metadata * - write with a single call to vips_sink_disc() * 29/6/19 * - support "strip" option * 6/7/19 [deftomat] * - support array of delays * 5/8/19 DarthSim * - support GIF optimization * 21/4/21 kleisauke * - include GObject part from magicksave.c * 9/12/21 [erik-frontify] * - add gif save subclass */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef ENABLE_MAGICKSAVE #include "pforeign.h" #include "magick.h" typedef struct _VipsForeignSaveMagick { VipsForeignSave parent_object; /* Parameters. */ char *filename; /* NULL during buffer output */ char *format; int quality; int bitdepth; gboolean optimize_gif_frames; gboolean optimize_gif_transparency; ImageInfo *image_info; ExceptionInfo *exception; char *map; StorageType storage_type; Image *images; Image *current_image; int page_height; GValue delay_gvalue; int *delays; int delays_length; /* The position of current_image in the output. */ VipsRect position; } VipsForeignSaveMagick; typedef VipsForeignSaveClass VipsForeignSaveMagickClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveMagick, vips_foreign_save_magick, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_magick_dispose(GObject *gobject) { VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) gobject; #ifdef DEBUG printf("vips_foreign_save_magick_dispose: %p\n", gobject); #endif /*DEBUG*/ VIPS_FREE(magick->filename); VIPS_FREE(magick->map); VIPS_FREEF(DestroyImageList, magick->images); VIPS_FREEF(DestroyImageInfo, magick->image_info); VIPS_FREEF(magick_destroy_exception, magick->exception); g_value_unset(&magick->delay_gvalue); G_OBJECT_CLASS(vips_foreign_save_magick_parent_class)->dispose(gobject); } /* Move current_image on to the next image we will write. */ static int vips_foreign_save_magick_next_image(VipsForeignSaveMagick *magick) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); VipsForeignSave *save = (VipsForeignSave *) magick; VipsImage *im = save->ready; Image *image; int number; const char *str; int page_index; g_assert(!magick->current_image); if (magick->images == NULL) { if (!(image = magick_acquire_image(magick->image_info, magick->exception))) return -1; magick->images = image; magick->position.top = 0; magick->position.left = 0; magick->position.width = im->Xsize; magick->position.height = magick->page_height; } else { image = GetLastImageInList(magick->images); magick_acquire_next_image(magick->image_info, image, magick->exception); if (GetNextImageInList(image) == NULL) return -1; image = SyncNextImageInList(image); magick->position.top += magick->page_height; } if (!magick_set_image_size(image, im->Xsize, magick->page_height, magick->exception)) { magick_vips_error(class->nickname, magick->exception); return -1; } /* Delay must be converted from milliseconds into centiseconds * as GIF image requires centiseconds. */ if (magick->delays) { page_index = magick->position.top / magick->page_height; if (page_index < magick->delays_length) image->delay = rint(magick->delays[page_index] / 10.0); } /* ImageMagick uses iterations like this (at least in gif save): * 0 - set 0 loops (infinite) * 1 - don't write the netscape extension block * 2 - loop once * 3 - loop twice etc. */ if (vips_image_get_typeof(im, "loop") && !vips_image_get_int(im, "loop", &number)) { image->iterations = (size_t) number; } else { /* DEPRECATED "gif-loop" * * We have the simple gif meaning, so we must add one unless * it's zero. */ if (vips_image_get_typeof(im, "gif-loop") && !vips_image_get_int(im, "gif-loop", &number)) image->iterations = (size_t) (number ? number + 1 : 0); } if (vips_image_get_typeof(im, "gif-comment") && !vips_image_get_string(im, "gif-comment", &str)) magick_set_property(image, "comment", str, magick->exception); /* libvips keeps animations as a set of independent frames, so we want * to clear to the background between each one. */ image->dispose = BackgroundDispose; if (magick_set_magick_profile(image, im, magick->exception)) { magick_vips_error(class->nickname, magick->exception); return -1; } magick->current_image = image; return 0; } /* We've written all the pixels to current_image ... finish it off ready to * move on. */ static void vips_foreign_save_magick_end_image(VipsForeignSaveMagick *magick) { if (magick->current_image) { magick_inherit_exception(magick->exception, magick->current_image); magick->current_image = NULL; } } /* Another block of pixels have arrived from libvips. */ static int vips_foreign_save_magick_write_block(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) a; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick); VipsRect pixels; pixels = region->valid; do { VipsRect hit; void *p; if (!magick->current_image && vips_foreign_save_magick_next_image(magick)) return -1; vips_rect_intersectrect(&pixels, &magick->position, &hit); p = VIPS_REGION_ADDR(region, hit.left, hit.top); if (!magick_import_pixels(magick->current_image, hit.left, hit.top - magick->position.top, hit.width, hit.height, magick->map, magick->storage_type, p, magick->exception)) { magick_vips_error(class->nickname, magick->exception); return -1; } /* Have we filled the page. */ if (VIPS_RECT_BOTTOM(&hit) == VIPS_RECT_BOTTOM(&magick->position)) vips_foreign_save_magick_end_image(magick); pixels.top += hit.height; pixels.height -= hit.height; } while (pixels.height > 0); return 0; } static int vips_foreign_save_magick_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) object; VipsImage *im; #ifdef DEBUG printf("vips_foreign_save_magick_build: %p\n", object); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_foreign_save_magick_parent_class)->build(object)) return -1; magick_genesis(); /* The image to save. */ im = save->ready; magick->exception = magick_acquire_exception(); magick->image_info = CloneImageInfo(NULL); switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: magick->storage_type = CharPixel; break; case VIPS_FORMAT_USHORT: magick->storage_type = ShortPixel; break; case VIPS_FORMAT_UINT: magick->storage_type = LongPixel; break; case VIPS_FORMAT_FLOAT: magick->storage_type = FloatPixel; break; case VIPS_FORMAT_DOUBLE: magick->storage_type = DoublePixel; break; default: vips_error(class->nickname, "%s", _("unsupported image format")); return -1; } switch (im->Bands) { case 1: magick->map = g_strdup("I"); break; case 2: magick->map = g_strdup("IA"); break; case 3: magick->map = g_strdup("RGB"); break; case 4: if (im->Type == VIPS_INTERPRETATION_CMYK) magick->map = g_strdup("CMYK"); else magick->map = g_strdup("RGBA"); break; case 5: magick->map = g_strdup("CMYKA"); break; default: vips_error(class->nickname, "%s", _("unsupported number of image bands")); return -1; } if (magick->format) { g_strlcpy(magick->image_info->magick, magick->format, MaxPathExtent); if (magick->filename) (void) g_snprintf(magick->image_info->filename, MaxPathExtent, "%s:%s", magick->format, magick->filename); } else if (magick->filename) { g_strlcpy(magick->image_info->filename, magick->filename, MaxPathExtent); } if (magick->quality > 0) magick->image_info->quality = magick->quality; magick->page_height = vips_image_get_page_height(im); /* Get as a gvalue so we can keep a ref to the delay array while we * need it. */ if (vips_image_get_typeof(im, "delay")) { g_value_unset(&magick->delay_gvalue); if (vips_image_get(im, "delay", &magick->delay_gvalue)) return -1; magick->delays = vips_value_get_array_int( &magick->delay_gvalue, &magick->delays_length); } if (vips_sink_disc(im, vips_foreign_save_magick_write_block, magick)) return -1; if (magick->optimize_gif_frames) { if (!magick_optimize_image_layers(&magick->images, magick->exception)) { magick_inherit_exception(magick->exception, magick->images); magick_vips_error(class->nickname, magick->exception); return -1; } } if (magick->optimize_gif_transparency) { if (!magick_optimize_image_transparency(magick->images, magick->exception)) { magick_inherit_exception(magick->exception, magick->images); magick_vips_error(class->nickname, magick->exception); return -1; } } /* Bitdepth <= 8 requested? Quantize/Dither images. * ImageMagick then selects the appropriate bit depth when writing * the actual image (e.g. BMP or GIF). */ if (magick->bitdepth) { if (!magick_quantize_images(magick->images, magick->bitdepth, magick->exception)) { magick_inherit_exception(magick->exception, magick->images); magick_vips_error(class->nickname, magick->exception); return -1; } } return 0; } /* We could call into libMagick and discover what save formats it supports, but * that would mean starting up libMagick on libvips init, and that would add a * lot of time. * * Instead, just list the commonly-used formats that all libMagicks support and * that libvips does not. */ static const char *vips__save_magick_suffs[] = { NULL }; static const char *vips__save_magick_bmp_suffs[] = { ".bmp", NULL }; static const char *vips__save_magick_gif_suffs[] = { ".gif", NULL }; /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT #define UI VIPS_FORMAT_UINT #define F VIPS_FORMAT_FLOAT #define D VIPS_FORMAT_DOUBLE static VipsBandFormat bandfmt_magick[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, UI, UI, F, F, D, D }; static void vips_foreign_save_magick_class_init(VipsForeignSaveMagickClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_magick_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magicksave_base"; object_class->description = _("save with ImageMagick"); object_class->build = vips_foreign_save_magick_build; /* *magick is fuzzed, but it's such a huge thing it's safer to * disable it. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* We need to be well to the back of the queue since vips's * dedicated savers are usually preferable. */ foreign_class->priority = -100; foreign_class->suffs = vips__save_magick_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->format_table = bandfmt_magick; VIPS_ARG_STRING(class, "format", 2, _("Format"), _("Format to save in"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMagick, format), NULL); VIPS_ARG_INT(class, "quality", 3, _("Quality"), _("Quality to use"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMagick, quality), 0, 100, 0); VIPS_ARG_BOOL(class, "optimize_gif_frames", 4, _("Optimize_gif_frames"), _("Apply GIF frames optimization"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMagick, optimize_gif_frames), FALSE); VIPS_ARG_BOOL(class, "optimize_gif_transparency", 5, _("Optimize_gif_transparency"), _("Apply GIF transparency optimization"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMagick, optimize_gif_transparency), FALSE); VIPS_ARG_INT(class, "bitdepth", 6, _("Bit depth"), _("Number of bits per pixel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMagick, bitdepth), 0, 8, 0); } static void vips_foreign_save_magick_init(VipsForeignSaveMagick *magick) { /* Init to an int just to have something there. It is swapped for an * int array later. */ g_value_init(&magick->delay_gvalue, G_TYPE_INT); magick->bitdepth = 0; } typedef struct _VipsForeignSaveMagickFile { VipsForeignSaveMagick parent_object; char *filename; } VipsForeignSaveMagickFile; typedef VipsForeignSaveMagickClass VipsForeignSaveMagickFileClass; G_DEFINE_TYPE(VipsForeignSaveMagickFile, vips_foreign_save_magick_file, vips_foreign_save_magick_get_type()); static int vips_foreign_save_magick_file_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) object; VipsForeignSaveMagickFile *file = (VipsForeignSaveMagickFile *) object; magick->filename = g_strdup(file->filename); if (VIPS_OBJECT_CLASS(vips_foreign_save_magick_file_parent_class) ->build(object)) return -1; if (!WriteImages(magick->image_info, magick->images, magick->image_info->filename, magick->exception)) { magick_inherit_exception(magick->exception, magick->images); magick_vips_error(class->nickname, magick->exception); return -1; } return 0; } static void vips_foreign_save_magick_file_class_init( VipsForeignSaveMagickFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magicksave"; object_class->description = _("save file with ImageMagick"); object_class->build = vips_foreign_save_magick_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveMagickFile, filename), NULL); } static void vips_foreign_save_magick_file_init(VipsForeignSaveMagickFile *file) { } typedef struct _VipsForeignSaveMagickBuffer { VipsForeignSaveMagick parent_object; /* Save to a buffer. */ VipsArea *buf; } VipsForeignSaveMagickBuffer; typedef VipsForeignSaveMagickClass VipsForeignSaveMagickBufferClass; G_DEFINE_TYPE(VipsForeignSaveMagickBuffer, vips_foreign_save_magick_buffer, vips_foreign_save_magick_get_type()); static int vips_foreign_save_magick_buffer_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) object; VipsForeignSaveMagickBuffer *buffer = (VipsForeignSaveMagickBuffer *) object; void *obuf; size_t olen; VipsBlob *blob; if (VIPS_OBJECT_CLASS(vips_foreign_save_magick_buffer_parent_class) ->build(object)) return -1; if (!(obuf = magick_images_to_blob(magick->image_info, magick->images, &olen, magick->exception))) { magick_inherit_exception(magick->exception, magick->images); magick_vips_error(class->nickname, magick->exception); return -1; } blob = vips_blob_new((VipsCallbackFn) vips_area_free_cb, obuf, olen); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_magick_buffer_class_init( VipsForeignSaveMagickBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "magicksave_buffer"; object_class->description = _("save image to magick buffer"); object_class->build = vips_foreign_save_magick_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveMagickBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_magick_buffer_init(VipsForeignSaveMagickBuffer *buffer) { } typedef VipsForeignSaveMagickFile VipsForeignSaveMagickBmpFile; typedef VipsForeignSaveMagickFileClass VipsForeignSaveMagickBmpFileClass; G_DEFINE_TYPE(VipsForeignSaveMagickBmpFile, vips_foreign_save_magick_bmp_file, vips_foreign_save_magick_file_get_type()); static void vips_foreign_save_magick_bmp_file_class_init( VipsForeignSaveMagickBmpFileClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "magicksave_bmp"; object_class->description = _("save bmp image with ImageMagick"); foreign_class->suffs = vips__save_magick_bmp_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_magick_bmp_file_init(VipsForeignSaveMagickBmpFile *file) { VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) file; VIPS_SETSTR(magick->format, "bmp"); } typedef VipsForeignSaveMagickBuffer VipsForeignSaveMagickBmpBuffer; typedef VipsForeignSaveMagickBufferClass VipsForeignSaveMagickBmpBufferClass; G_DEFINE_TYPE(VipsForeignSaveMagickBmpBuffer, vips_foreign_save_magick_bmp_buffer, vips_foreign_save_magick_buffer_get_type()); static void vips_foreign_save_magick_bmp_buffer_class_init( VipsForeignSaveMagickBmpBufferClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "magicksave_bmp_buffer"; object_class->description = _("save bmp image to magick buffer"); foreign_class->suffs = vips__save_magick_bmp_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_magick_bmp_buffer_init( VipsForeignSaveMagickBmpBuffer *buffer) { VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) buffer; VIPS_SETSTR(magick->format, "bmp"); } typedef VipsForeignSaveMagickFile VipsForeignSaveMagickGifFile; typedef VipsForeignSaveMagickFileClass VipsForeignSaveMagickGifFileClass; G_DEFINE_TYPE(VipsForeignSaveMagickGifFile, vips_foreign_save_magick_gif_file, vips_foreign_save_magick_file_get_type()); static void vips_foreign_save_magick_gif_file_class_init( VipsForeignSaveMagickGifFileClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "magicksave_gif"; object_class->description = _("save gif image with ImageMagick"); foreign_class->suffs = vips__save_magick_gif_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_magick_gif_file_init(VipsForeignSaveMagickGifFile *file) { VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) file; VIPS_SETSTR(magick->format, "gif"); } typedef VipsForeignSaveMagickBuffer VipsForeignSaveMagickGifBuffer; typedef VipsForeignSaveMagickBufferClass VipsForeignSaveMagickGifBufferClass; G_DEFINE_TYPE(VipsForeignSaveMagickGifBuffer, vips_foreign_save_magick_gif_buffer, vips_foreign_save_magick_buffer_get_type()); static void vips_foreign_save_magick_gif_buffer_class_init( VipsForeignSaveMagickGifBufferClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsOperationClass *operation_class = (VipsOperationClass *) class; object_class->nickname = "magicksave_gif_buffer"; object_class->description = _("save gif image to magick buffer"); foreign_class->suffs = vips__save_magick_gif_suffs; /* Hide from UI. */ operation_class->flags |= VIPS_OPERATION_DEPRECATED; } static void vips_foreign_save_magick_gif_buffer_init( VipsForeignSaveMagickGifBuffer *buffer) { VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) buffer; VIPS_SETSTR(magick->format, "gif"); } #endif /*ENABLE_MAGICKSAVE*/ libvips-8.18.2/libvips/foreign/vips2tiff.c000066400000000000000000001771141516303661500204640ustar00rootroot00000000000000/* TIFF PARTS: * Copyright (c) 1988, 1990 by Sam Leffler. * All rights reserved. * * This file is provided for unrestricted use provided that this * legend is included on all tape media and as a part of the * software program in whole or part. Users may copy, modify or * distribute this file at will. * * MODIFICATION FOR VIPS Copyright 1991, K.Martinez * * software may be distributed FREE, with these copyright notices * no responsibility/warrantee is implied or given * * * Modified and added im_LabQ2LabC() function. It can write IM_TYPE_LABQ image * in vips format to LAB in tiff format. * Copyright 1994 Ahmed Abbood. * * 19/9/95 JC * - calls TIFFClose() more reliably * - tidied up * 12/4/97 JC * - thrown away and rewritten for TIFF 6 lib * 22/4/97 JC * - writes a pyramid! * - to separate TIFF files tho' * 23/4/97 JC * - does 2nd gather pass to put pyramid into a single TIFF file * - ... and shrinks IM_CODING_LABQ too * 26/10/98 JC * - binary open for stupid systems * 7/6/99 JC * - 16bit TIFF write too * 9/7/99 JC * - ZIP tiff added * 11/5/00 JC * - removed TIFFmalloc/TIFFfree * 5/8/00 JC * - mode string now part of filename * 23/4/01 JC * - HAVE_TIFF turns on TIFFness * 19/3/02 ruven * - pyramid stops at tile size, not 64x64 * 29/4/02 JC * - write any number of bands (but still with photometric RGB, so not * very useful) * 10/9/02 JC * - oops, handle TIFF errors better * - now writes CMYK correctly * 13/2/03 JC * - tries not to write mad resolutions * 7/5/03 JC * - only write CMYK if Type == CMYK * - writes EXTRASAMPLES ALPHA for bands == 2 or 4 (if we're writing RGB) * 17/11/03 JC * - write float too * 28/11/03 JC * - read via a "p" so we work from mmap window images * - uses threadgroups for speedup * 9/3/04 JC * - 1 bit write mode added * 5/4/04 * - better handling of edge tiles (thanks Ruven) * 18/5/04 Andrey Kiselev * - added res_inch/res_cm option * 20/5/04 JC * - allow single res number too * 19/7/04 * - write several scanlines at once, good speed up for some cases * 22/9/04 * - got rid of wrapper image so nip gets progress feedback * - fixed tiny read-beyond-buffer issue for edge tiles * 7/10/04 * - added ICC profile embedding * 13/12/04 * - can now pyramid any non-complex type (thanks Ruven) * 27/1/05 * - added ccittfax4 as a compression option * 9/3/05 * - set PHOTOMETRIC_CIELAB for vips TYPE_LAB images ... so we can write * float LAB as well as float RGB * - also LABS images * 22/6/05 * - 16 bit LAB write was broken * 9/9/05 * - write any icc profile from meta * 3/3/06 * - raise tile buffer limit (thanks Ruven) * 11/11/06 * - set ORIENTATION_TOPLEFT (thanks Josef) * 18/7/07 Andrey Kiselev * - remove "b" option on TIFFOpen() * - support TIFFTAG_PREDICTOR types for lzw and deflate compression * 3/11/07 * - use im_wbuffer() for background writes * 15/2/08 * - set TIFFTAG_JPEGQUALITY explicitly when we copy TIFF files, since * libtiff doesn't keep this in the header (thanks Joe) * 20/2/08 * - use tiff error handler from im_tiff2vips.c * 27/2/08 * - don't try to copy icc profiles when building pyramids (thanks Joe) * 9/4/08 * - use IM_META_RESOLUTION_UNIT to set default resunit * 17/4/08 * - allow CMYKA (thanks Doron) * 5/9/08 * - trigger eval callbacks during tile write * 4/2/10 * - gtkdoc * 26/2/10 * - option to turn on bigtiff output * 16/4/10 * - use vips_sink_*() instead of threadgroup and friends * 22/6/10 * - make no-owner regions for the tile cache, since we share these * between threads * 12/7/11 * - use im__temp_name() for intermediates rather than polluting the * output directory * 5/9/11 * - enable YCbCr compression for jpeg write * 23/11/11 * - set reduced-resolution subfile type on pyramid layers * 2/12/11 * - make into a simple function call ready to be wrapped as a new-style * VipsForeign class * 21/3/12 * - bump max layer buffer up * 2/6/12 * - copy jpeg pyramid in gather in RGB mode ... tiff4 doesn't do ycbcr * mode * 7/8/12 * - be more cautious enabling YCbCr mode * 24/9/13 * - support many more vips formats, eg. complex, 32-bit int, any number * of bands, etc., see the tiff loader * 26/1/14 * - add RGB as well as YCbCr write * 20/11/14 * - cache input in tile write mode to keep us sequential * 3/12/14 * - embed XMP in output * 10/12/14 * - zero out edge tile buffers before jpeg wtiff, thanks iwbh15 * 19/1/15 * - disable chroma subsample if Q >= 90 * 13/2/15 * - append later layers, don't copy the base image * - use the nice dzsave pyramid code, much faster and simpler * - we now allow strip pyramids * 27/3/15 * - squash >128 rather than >0, nicer results for shrink * - add miniswhite option * 29/9/15 * - try to write IPTC metadata * - try to write photoshop metadata * 11/11/15 * - better alpha handling, thanks sadaqatullahn * 21/12/15 * - write TIFFTAG_IMAGEDESCRIPTION * 2/6/16 * - support strip option * 4/7/16 * - tag alpha as UNASSALPHA since it's not pre-multiplied, thanks Peter * 17/8/16 * - use wchar_t TIFFOpen on Windows * 14/10/16 * - add buffer output * 29/1/17 * - enable bigtiff automatically for large, uncompressed writes, thanks * AndreasSchmid1 * 26/8/17 * - support pyramid creation to buffer, thanks bubba * 24/10/17 * - no error on page-height not a factor of image height, just don't * write multipage * 13/6/18 * - add region_shrink * 2/7/18 * - copy EXTRASAMPLES to pyramid layers * 21/12/18 * - stop pyr layers if width or height drop to 1 * 8/7/19 * - add webp and zstd support * - add @level and @lossless * 18/12/19 * - "squash" now squashes 3-band float LAB down to LABQ * 26/1/20 * - add "depth" to set pyr depth * 27/1/20 * - write XYZ images as logluv * 7/2/20 [jclavoie-jive] * - add PAGENUMBER support * 23/5/20 * - add support for subifd pyramid layers * 6/6/20 MathemanFlo * - add bitdepth support for 2 and 4 bit greyscale images * 29/9/21 LionelArn2 * - loop for the whole output image, rather than per page * 20/10/21 [jacopoabramo] * - subifd enables pyramid * - add support for page_height param * 11/5/22 * - switch to terget API for output * 24/9/23 * - add threaded write of tiled JPEG and JP2K */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_TIFF #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include "pforeign.h" #include "tiff.h" /* We do jpeg compress ourselves, if we can. */ #ifdef HAVE_JPEG #include "jpeg.h" #endif /*HAVE_JPEG*/ /* TODO: * * - add a flag for plane-separate write * * At the moment, we write bioformats-style TIFFs by splitting bands up, * making a toilet-roll image and writing out in pages. The TIFFs we make * are not tagged as plane-separate and do not have (eg.) RGB photometric * interpretation. Moreover, when working from an RGB source, we'll end * up reading the input three times. * * A write-plane-separate flag to the TIFF writer could let us set the * photometric interpretation correctly, and save all planes in a single * pass before doing a final gather sweep. */ /* Max number of alpha channels we allow. */ #define MAX_ALPHA (64) /* Compression types we handle ourselves. */ static int wtiff_we_compress[] = { #ifdef HAVE_JPEG COMPRESSION_JPEG, #endif /*HAVE_JPEG*/ JP2K_LOSSY }; typedef struct _Layer Layer; typedef struct _Wtiff Wtiff; /* A layer in the pyramid. */ struct _Layer { Wtiff *wtiff; /* Main wtiff struct */ /* The temp target for this layer. */ VipsTarget *target; int width, height; /* Layer size */ int sub; /* Subsample factor for this layer */ TIFF *tif; /* TIFF file we write this layer to */ /* The image we build. We only keep a few scanlines of this around in * strip. */ VipsImage *image; /* The y position of strip in image. */ int y; /* The next line we write to in strip. */ int write_y; VipsRegion *strip; /* The current strip of pixels */ VipsRegion *copy; /* Pixels we copy to the next strip */ Layer *below; /* The smaller layer below us */ Layer *above; /* The larger layer above */ }; /* A TIFF image in the process of being written. */ struct _Wtiff { VipsImage *input; /* Original input image */ /* Image transformed ready for write. */ VipsImage *ready; /* Target to write to. */ VipsTarget *target; Layer *layer; /* Top of pyramid */ VipsPel *tbuf; /* TIFF output buffer */ int tls; /* Tile line size */ int compression; /* libtiff compression type */ int Q; /* JPEG q-factor, webp level */ int predictor; /* libtiff predictor type */ int tile; /* Tile or not */ int tilew, tileh; /* Tile size */ int pyramid; /* Wtiff pyramid */ int bitdepth; /* Write as 1, 2 or 4 bit */ int miniswhite; /* Wtiff as 0 == white */ int resunit; /* Resolution unit (inches or cm) */ double xres; /* Resolution in X */ double yres; /* Resolution in Y */ const char *profile; /* Profile to embed */ int bigtiff; /* True for bigtiff write */ int rgbjpeg; /* True for RGB not YCbCr */ int properties; /* Set to save XML props */ VipsRegionShrink region_shrink; /* How to shrink regions */ int level; /* Deflate (zlib) / zstd compression level */ gboolean lossless; /* lossless mode */ VipsForeignDzDepth depth; /* Pyr depth */ gboolean subifd; /* Write pyr layers into subifds */ gboolean premultiply; /* Premultiply alpha */ /* True if we've detected a toilet-roll image, plus the page height, * which has been checked to be a factor of im->Ysize. page_number * starts at zero and ticks up as we write each page. */ gboolean toilet_roll; int page_height; int page_number; int n_pages; /* The height of the TIFF we write. Equal to page_height in toilet * roll mode. */ int image_height; /* TRUE if we compress ourselves outside the libtiff lock. */ gboolean we_compress; /* Lock thread calls into libtiff with this. */ GMutex lock; }; /* libvips uses size_t for the length of binary data items, but libtiff wants * uint32. */ static void set_data64(TIFF *tif, guint32 tag, size_t length, const void *data) { if (length <= UINT_MAX) TIFFSetField(tif, tag, (guint32) length, data); } /* Write an ICC Profile from a file into the JPEG stream. */ static int embed_profile_file(TIFF *tif, const char *profile) { VipsBlob *blob; if (vips_profile_load(profile, &blob, NULL)) return -1; if (blob) { size_t length; const void *data = vips_blob_get(blob, &length); set_data64(tif, TIFFTAG_ICCPROFILE, length, data); #ifdef DEBUG printf("vips2tiff: attached profile \"%s\"\n", profile); #endif /*DEBUG*/ vips_area_unref((VipsArea *) blob); } return 0; } /* Embed an ICC profile from VipsImage metadata. */ static int embed_profile_meta(TIFF *tif, VipsImage *im) { const void *data; size_t length; if (vips_image_get_blob(im, VIPS_META_ICC_NAME, &data, &length)) return -1; set_data64(tif, TIFFTAG_ICCPROFILE, length, data); #ifdef DEBUG printf("vips2tiff: attached profile from meta\n"); #endif /*DEBUG*/ return 0; } static int wtiff_handler_error(TIFF *tiff, void *user_data, const char *module, const char *fmt, va_list ap) { vips_verror("vips2tiff", fmt, ap); return 1; } static int wtiff_handler_warning(TIFF *tiff, void *user_data, const char *module, const char *fmt, va_list ap) { g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap); return 1; } static void wtiff_layer_init(Wtiff *wtiff, Layer **layer, Layer *above, int width, int height) { if (!*layer) { *layer = VIPS_NEW(wtiff->ready, Layer); (*layer)->wtiff = wtiff; (*layer)->width = width; (*layer)->height = height; if (!above) /* Top of pyramid. */ (*layer)->sub = 1; else (*layer)->sub = above->sub * 2; (*layer)->tif = NULL; (*layer)->image = NULL; (*layer)->write_y = 0; (*layer)->y = 0; (*layer)->strip = NULL; (*layer)->copy = NULL; (*layer)->below = NULL; (*layer)->above = above; /* The target we write to. The base layer writes to the main * output, each layer smaller writes to a memory temp. */ if (!above) { (*layer)->target = wtiff->target; g_object_ref((*layer)->target); } else { const guint64 disc_threshold = vips_get_disc_threshold(); const guint64 layer_size = VIPS_IMAGE_SIZEOF_PEL(wtiff->ready) * width * height; if (layer_size > disc_threshold) (*layer)->target = vips_target_new_temp(wtiff->target); else (*layer)->target = vips_target_new_to_memory(); } /* printf("wtiff_layer_init: sub = %d, width = %d, height = %d\n", (*layer)->sub, width, height); */ } if (wtiff->pyramid) { int limitw, limith; switch (wtiff->depth) { case VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL: limitw = limith = 1; break; case VIPS_FOREIGN_DZ_DEPTH_ONETILE: limitw = wtiff->tilew; limith = wtiff->tileh; break; case VIPS_FOREIGN_DZ_DEPTH_ONE: limitw = wtiff->ready->Xsize; limith = wtiff->ready->Ysize; break; default: // stop a compiler warning limitw = 128; limith = 128; g_assert_not_reached(); } /* We make another layer if the image is too large to fit in a * single tile, and if neither axis is greater than 1. * * Very tall or wide images might end up with a smallest layer * larger than one tile. */ if (((*layer)->width > limitw || (*layer)->height > limith) && (*layer)->width > 1 && (*layer)->height > 1) wtiff_layer_init(wtiff, &(*layer)->below, *layer, width / 2, height / 2); } } static int wtiff_embed_profile(Wtiff *wtiff, TIFF *tif) { /* A profile supplied as an argument overrides an embedded * profile. */ if (wtiff->profile) { if (embed_profile_file(tif, wtiff->profile)) return -1; } else if (vips_image_get_typeof(wtiff->ready, VIPS_META_ICC_NAME)) { if (embed_profile_meta(tif, wtiff->ready)) return -1; } return 0; } static int wtiff_embed_xmp(Wtiff *wtiff, TIFF *tif) { const void *data; size_t size; if (!vips_image_get_typeof(wtiff->ready, VIPS_META_XMP_NAME)) return 0; if (vips_image_get_blob(wtiff->ready, VIPS_META_XMP_NAME, &data, &size)) return -1; set_data64(tif, TIFFTAG_XMLPACKET, size, data); #ifdef DEBUG printf("vips2tiff: attached XMP from meta\n"); #endif /*DEBUG*/ return 0; } static int wtiff_embed_iptc(Wtiff *wtiff, TIFF *tif) { const void *data; size_t size; if (!vips_image_get_typeof(wtiff->ready, VIPS_META_IPTC_NAME)) return 0; if (vips_image_get_blob(wtiff->ready, VIPS_META_IPTC_NAME, &data, &size)) return -1; /* For no very good reason, libtiff stores IPTC as an array of * long, not byte. */ if (size & 3) { g_warning("rounding up IPTC data length"); size /= 4; size += 1; } else size /= 4; set_data64(tif, TIFFTAG_RICHTIFFIPTC, size, data); #ifdef DEBUG printf("vips2tiff: attached IPTC from meta\n"); #endif /*DEBUG*/ return 0; } static int wtiff_embed_photoshop(Wtiff *wtiff, TIFF *tif) { const void *data; size_t size; if (vips_image_get_typeof(wtiff->ready, VIPS_META_PHOTOSHOP_NAME)) { if (vips_image_get_blob(wtiff->ready, VIPS_META_PHOTOSHOP_NAME, &data, &size)) return -1; set_data64(tif, TIFFTAG_PHOTOSHOP, size, data); #ifdef DEBUG printf("vips2tiff: attached %zd bytes of photoshop data\n", size); #endif /*DEBUG*/ } return 0; } /* Set IMAGEDESCRIPTION, if it's there. If @properties is TRUE, set from * vips' metadata. */ static int wtiff_embed_imagedescription(Wtiff *wtiff, TIFF *tif) { if (wtiff->properties) { char *doc; if (!(doc = vips__xml_properties(wtiff->ready))) return -1; TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, doc); g_free(doc); } else { const char *imagedescription; if (!vips_image_get_typeof(wtiff->ready, VIPS_META_IMAGEDESCRIPTION)) return 0; if (vips_image_get_string(wtiff->ready, VIPS_META_IMAGEDESCRIPTION, &imagedescription)) return -1; TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, imagedescription); } #ifdef DEBUG printf("vips2tiff: attached imagedescription from meta\n"); #endif /*DEBUG*/ return 0; } #ifdef HAVE_JPEG // in vips2jpeg.c void vips__jpeg_target_dest(j_compress_ptr cinfo, VipsTarget *target); static void wtiff_compress_jpeg_header(Wtiff *wtiff, struct jpeg_compress_struct *cinfo, VipsImage *image) { J_COLOR_SPACE space; cinfo->image_width = wtiff->tilew; cinfo->image_height = wtiff->tileh; cinfo->input_components = image->Bands; if (image->Bands == 4 && image->Type == VIPS_INTERPRETATION_CMYK) space = JCS_CMYK; else if (image->Bands == 3) space = JCS_RGB; else if (image->Bands == 1) space = JCS_GRAYSCALE; else /* Use luminance compression for all channels. */ space = JCS_UNKNOWN; cinfo->in_color_space = space; #ifdef HAVE_JPEG_EXT_PARAMS /* Reset compression profile to libjpeg defaults */ if (jpeg_c_int_param_supported(cinfo, JINT_COMPRESS_PROFILE)) jpeg_c_set_int_param(cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST); #endif jpeg_set_defaults(cinfo); /* Set compression quality. */ jpeg_set_quality(cinfo, wtiff->Q, TRUE); /* We must set chroma subsampling explicitly since some libjpegs do not * enable this by default. */ if (image->Bands == 3 && wtiff->Q < 90) cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; else cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 1; /* Rest should have sampling factors 1,1. */ for (int i = 1; i < image->Bands; i++) cinfo->comp_info[i].h_samp_factor = cinfo->comp_info[i].v_samp_factor = 1; /* For low Q, we write YCbCr, for high Q, RGB. The jpeg coeffs don't * encode the photometric interpretation, the tiff header does that, * so this code must be kept synced with wtiff_write_header(). */ if (image->Bands == 3 && wtiff->Q >= 90) jpeg_set_colorspace(cinfo, JCS_RGB); // Avoid writing the JFIF APP0 marker. cinfo->write_JFIF_header = FALSE; } static int wtiff_compress_jpeg(Wtiff *wtiff, VipsRegion *strip, VipsRect *tile, VipsTarget *target) { size_t sizeof_pel = VIPS_REGION_SIZEOF_PEL(strip); struct jpeg_compress_struct cinfo; ErrorManager eman; VipsPel *line; #ifdef DEBUG printf("wtiff_compress_jpeg: " "left = %d, top = %d, width = %d, height = %d\n", tile->left, tile->top, tile->width, tile->height); #endif /*DEBUG*/ // we could have one of these per thread and reuse it for a small speedup cinfo.err = jpeg_std_error(&eman.pub); cinfo.err->addon_message_table = vips__jpeg_message_table; cinfo.err->first_addon_message = 1000; cinfo.err->last_addon_message = 1001; cinfo.dest = NULL; eman.pub.error_exit = vips__new_error_exit; eman.pub.output_message = vips__new_output_message; eman.fp = NULL; // we need a line buffer to pad edge tiles line = VIPS_MALLOC(NULL, wtiff->tilew * sizeof_pel); /* Error handling. The error message will have been set by our handlers. */ if (setjmp(eman.jmp)) { jpeg_destroy_compress(&cinfo); VIPS_FREE(line); return -1; } /* Make jpeg compression object. */ jpeg_create_compress(&cinfo); /* Attach output. */ vips__jpeg_target_dest(&cinfo, target); wtiff_compress_jpeg_header(wtiff, &cinfo, strip->im); // don't output tables, just coefficients jpeg_suppress_tables(&cinfo, TRUE); // FALSE means we are outputting an abbreviated (no tables) datastream jpeg_start_compress(&cinfo, FALSE); if (tile->width < wtiff->tilew || tile->height < wtiff->tileh) { JSAMPROW row_pointer[1] = { line }; for (int y = 0; y < tile->height; y++) { memcpy(line, VIPS_REGION_ADDR(strip, tile->left, tile->top + y), tile->width * sizeof_pel); jpeg_write_scanlines(&cinfo, row_pointer, 1); } memset(line, 0, wtiff->tilew * sizeof_pel); for (int y = tile->height; y < wtiff->tileh; y++) { jpeg_write_scanlines(&cinfo, row_pointer, 1); } } else { for (int y = 0; y < tile->height; y++) { JSAMPROW row_pointer[1]; row_pointer[0] = VIPS_REGION_ADDR(strip, tile->left, tile->top + y); jpeg_write_scanlines(&cinfo, row_pointer, 1); } } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); VIPS_FREE(line); return 0; } static int wtiff_compress_jpeg_tables(Wtiff *wtiff, VipsImage *image, int width, int height, VipsTarget *target) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); cinfo.err->addon_message_table = vips__jpeg_message_table; cinfo.err->first_addon_message = 1000; cinfo.err->last_addon_message = 1001; jpeg_create_compress(&cinfo); /* Attach output. */ vips__jpeg_target_dest(&cinfo, target); wtiff_compress_jpeg_header(wtiff, &cinfo, image); // write just the header tables jpeg_write_tables(&cinfo); jpeg_destroy_compress(&cinfo); return 0; } #endif /*HAVE_JPEG*/ /* Write a TIFF header for this layer. */ static int wtiff_write_header(Wtiff *wtiff, Layer *layer) { TIFF *tif = layer->tif; int i; int orientation; #ifdef DEBUG printf("wtiff_write_header: sub %d, width %d, height %d\n", layer->sub, layer->width, layer->height); #endif /*DEBUG*/ /* Output base header fields. */ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, layer->width); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, layer->height); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_COMPRESSION, wtiff->compression); if (wtiff->compression == COMPRESSION_JPEG) TIFFSetField(tif, TIFFTAG_JPEGQUALITY, wtiff->Q); #ifdef HAVE_TIFF_COMPRESSION_WEBP if (wtiff->compression == COMPRESSION_WEBP) { TIFFSetField(tif, TIFFTAG_WEBP_LEVEL, wtiff->Q); TIFFSetField(tif, TIFFTAG_WEBP_LOSSLESS, wtiff->lossless); } if (wtiff->compression == COMPRESSION_ZSTD) { // Set zstd compression level - only accept valid values (1-22) if (wtiff->level) TIFFSetField(tif, TIFFTAG_ZSTD_LEVEL, VIPS_CLIP(1, wtiff->level, 22)); if (wtiff->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE) TIFFSetField(tif, TIFFTAG_PREDICTOR, wtiff->predictor); } #endif /*HAVE_TIFF_COMPRESSION_WEBP*/ // Set deflate (zlib) compression level - only accept valid values (1-9) if (wtiff->compression == COMPRESSION_ADOBE_DEFLATE && wtiff->level) TIFFSetField(tif, TIFFTAG_ZIPQUALITY, VIPS_CLIP(1, wtiff->level, 9)); if ((wtiff->compression == COMPRESSION_ADOBE_DEFLATE || wtiff->compression == COMPRESSION_LZW) && wtiff->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE) TIFFSetField(tif, TIFFTAG_PREDICTOR, wtiff->predictor); for (i = 0; i < VIPS_NUMBER(wtiff_we_compress); i++) if (wtiff->compression == wtiff_we_compress[i]) { wtiff->we_compress = TRUE; break; } /* Special case: we don't compress JPEG strip images, they are best left * to libtiff. */ if (wtiff->compression == COMPRESSION_JPEG && !wtiff->tile) wtiff->we_compress = FALSE; /* Don't write mad resolutions (eg. zero), it confuses some programs. */ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, wtiff->resunit); TIFFSetField(tif, TIFFTAG_XRESOLUTION, VIPS_FCLIP(0.01, wtiff->xres, 1000000)); TIFFSetField(tif, TIFFTAG_YRESOLUTION, VIPS_FCLIP(0.01, wtiff->yres, 1000000)); if (wtiff_embed_xmp(wtiff, tif) || wtiff_embed_iptc(wtiff, tif) || wtiff_embed_photoshop(wtiff, tif) || wtiff_embed_imagedescription(wtiff, tif) || wtiff_embed_profile(wtiff, tif)) return -1; if (vips_image_get_typeof(wtiff->ready, VIPS_META_ORIENTATION) && !vips_image_get_int(wtiff->ready, VIPS_META_ORIENTATION, &orientation)) TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation); /* And colour fields. */ if (wtiff->ready->Coding == VIPS_CODING_LABQ) { TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB); } else if (wtiff->bitdepth == 1 || wtiff->bitdepth == 2 || wtiff->bitdepth == 4) { TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, wtiff->bitdepth); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, wtiff->miniswhite ? PHOTOMETRIC_MINISWHITE : PHOTOMETRIC_MINISBLACK); } else { int photometric; /* Number of bands that have colour in .. other bands are saved * as alpha. */ int colour_bands; int alpha_bands; TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, wtiff->ready->Bands); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, vips_format_sizeof(wtiff->ready->BandFmt) << 3); if (wtiff->ready->Type == VIPS_INTERPRETATION_B_W || wtiff->ready->Type == VIPS_INTERPRETATION_GREY16 || wtiff->ready->Bands < 3) { /* Mono or mono + alpha. */ photometric = wtiff->miniswhite ? PHOTOMETRIC_MINISWHITE : PHOTOMETRIC_MINISBLACK; colour_bands = 1; } else if (wtiff->ready->Type == VIPS_INTERPRETATION_LAB || wtiff->ready->Type == VIPS_INTERPRETATION_LABS) { photometric = PHOTOMETRIC_CIELAB; colour_bands = 3; } else if (wtiff->input->Type == VIPS_INTERPRETATION_XYZ) { double stonits; photometric = PHOTOMETRIC_LOGLUV; /* Tell libtiff we will write as float XYZ. */ TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT); stonits = 1.0; if (vips_image_get_typeof(wtiff->ready, "stonits")) vips_image_get_double(wtiff->ready, "stonits", &stonits); TIFFSetField(tif, TIFFTAG_STONITS, stonits); colour_bands = 3; } else if (wtiff->ready->Type == VIPS_INTERPRETATION_CMYK && wtiff->ready->Bands >= 4) { photometric = PHOTOMETRIC_SEPARATED; TIFFSetField(tif, TIFFTAG_INKSET, INKSET_CMYK); colour_bands = 4; } else if (wtiff->compression == COMPRESSION_JPEG && wtiff->ready->Bands == 3 && wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR && (!wtiff->rgbjpeg && wtiff->Q < 90)) { /* This signals to libjpeg that it can do * YCbCr chrominance subsampling from RGB, not * that we will supply the image as YCbCr. */ photometric = PHOTOMETRIC_YCBCR; TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); colour_bands = 3; } else { /* Some kind of generic multi-band image with three or * more bands ... save the first three bands as RGB, * the rest as alpha. */ photometric = PHOTOMETRIC_RGB; colour_bands = 3; } alpha_bands = VIPS_CLIP(0, wtiff->ready->Bands - colour_bands, MAX_ALPHA); if (alpha_bands > 0) { guint16 v[MAX_ALPHA]; int i; /* EXTRASAMPLE_UNASSALPHA means generic extra * alpha-like channels. ASSOCALPHA means pre-multipled * alpha only. * * Make the first channel the premultiplied alpha, if * we are premultiplying. */ for (i = 0; i < alpha_bands; i++) v[i] = i == 0 && wtiff->premultiply ? EXTRASAMPLE_ASSOCALPHA : EXTRASAMPLE_UNASSALPHA; TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, alpha_bands, v); } TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric); } /* Layout. */ if (wtiff->tile) { TIFFSetField(tif, TIFFTAG_TILEWIDTH, wtiff->tilew); TIFFSetField(tif, TIFFTAG_TILELENGTH, wtiff->tileh); } else TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, wtiff->tileh); if (layer->above) /* Pyramid layer. */ TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE); else if (wtiff->toilet_roll) { /* One page of many. */ TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); TIFFSetField(tif, TIFFTAG_PAGENUMBER, wtiff->page_number, wtiff->n_pages); } /* Sample format. * * Don't set for logluv: libtiff does this for us. */ if (wtiff->input->Type != VIPS_INTERPRETATION_XYZ) { int format; format = SAMPLEFORMAT_UINT; if (vips_band_format_isuint(wtiff->ready->BandFmt)) format = SAMPLEFORMAT_UINT; else if (vips_band_format_isint(wtiff->ready->BandFmt)) format = SAMPLEFORMAT_INT; else if (vips_band_format_isfloat(wtiff->ready->BandFmt)) format = SAMPLEFORMAT_IEEEFP; else if (vips_band_format_iscomplex(wtiff->ready->BandFmt)) format = SAMPLEFORMAT_COMPLEXIEEEFP; TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, format); } #ifdef HAVE_JPEG // we have to write the tables ourselves for JPEG we_compress if (wtiff->we_compress && wtiff->compression == COMPRESSION_JPEG) { VipsTarget *target; int result; unsigned char *buffer; size_t length; target = vips_target_new_to_memory(); result = wtiff_compress_jpeg_tables(wtiff, wtiff->input, wtiff->input->Xsize, wtiff->input->Ysize, target); if (result) { g_object_unref(target); return -1; } buffer = vips_target_steal(target, &length); g_object_unref(target); #ifdef DEBUG printf("setting %zd bytes of table data\n", length); #endif /*DEBUG*/ set_data64(tif, TIFFTAG_JPEGTABLES, length, buffer); g_free(buffer); } #endif /*HAVE_JPEG*/ return 0; } static int wtiff_layer_rewind(Wtiff *wtiff, Layer *layer) { VipsRect strip_size; /* Build a line of tiles here. * * Expand the strip if necessary to make sure we have an even * number of lines. */ strip_size.left = 0; strip_size.top = 0; strip_size.width = layer->image->Xsize; strip_size.height = wtiff->tileh; if ((strip_size.height & 1) == 1) strip_size.height += 1; if (vips_region_buffer(layer->strip, &strip_size)) return -1; layer->y = 0; layer->write_y = 0; return 0; } static int wtiff_allocate_layers(Wtiff *wtiff) { Layer *layer; g_assert(wtiff->layer); for (layer = wtiff->layer; layer; layer = layer->below) { if (!layer->image) { layer->image = vips_image_new(); if (vips_image_pipelinev(layer->image, VIPS_DEMAND_STYLE_ANY, wtiff->ready, NULL)) return -1; layer->image->Xsize = layer->width; layer->image->Ysize = layer->height; layer->strip = vips_region_new(layer->image); layer->copy = vips_region_new(layer->image); /* The regions will get used in the bg thread callback, * so make sure we don't own them. */ vips__region_no_ownership(layer->strip); vips__region_no_ownership(layer->copy); layer->tif = vips__tiff_openout_target(layer->target, wtiff->bigtiff, wtiff_handler_error, wtiff_handler_warning, wtiff); if (!layer->tif) return -1; } if (wtiff_layer_rewind(wtiff, layer)) return -1; if (wtiff_write_header(wtiff, layer)) return -1; } if (!wtiff->tbuf) { if (wtiff->tile) wtiff->tbuf = vips_malloc(NULL, TIFFTileSize(wtiff->layer->tif)); else wtiff->tbuf = vips_malloc(NULL, TIFFScanlineSize(wtiff->layer->tif)); if (!wtiff->tbuf) return -1; } return 0; } /* Free a single pyramid layer. */ static void layer_free(Layer *layer) { /* Don't unref the target for this layer -- we'll need it for gather. */ VIPS_FREEF(TIFFClose, layer->tif); VIPS_UNREF(layer->strip); VIPS_UNREF(layer->copy); VIPS_UNREF(layer->image); } static void wtiff_free(Wtiff *wtiff) { Layer *layer; /* Free all pyramid resources. */ for (layer = wtiff->layer; layer; layer = layer->below) { layer_free(layer); VIPS_UNREF(layer->target); } VIPS_UNREF(wtiff->ready); VIPS_FREE(wtiff->tbuf); g_mutex_clear(&wtiff->lock); VIPS_FREE(wtiff); } static int get_compression(VipsForeignTiffCompression compression) { switch (compression) { case VIPS_FOREIGN_TIFF_COMPRESSION_NONE: return COMPRESSION_NONE; case VIPS_FOREIGN_TIFF_COMPRESSION_JPEG: return COMPRESSION_JPEG; case VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE: return COMPRESSION_ADOBE_DEFLATE; case VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS: return COMPRESSION_PACKBITS; case VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4: return COMPRESSION_CCITTFAX4; case VIPS_FOREIGN_TIFF_COMPRESSION_LZW: return COMPRESSION_LZW; #ifdef HAVE_TIFF_COMPRESSION_WEBP case VIPS_FOREIGN_TIFF_COMPRESSION_WEBP: return COMPRESSION_WEBP; case VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD: return COMPRESSION_ZSTD; #endif /*HAVE_TIFF_COMPRESSION_WEBP*/ case VIPS_FOREIGN_TIFF_COMPRESSION_JP2K: return JP2K_LOSSY; default: return COMPRESSION_NONE; } } static int get_resunit(VipsForeignTiffResunit resunit) { switch (resunit) { case VIPS_FOREIGN_TIFF_RESUNIT_CM: return RESUNIT_CENTIMETER; case VIPS_FOREIGN_TIFF_RESUNIT_INCH: return RESUNIT_INCH; default: g_assert_not_reached(); } /* Keep -Wall happy. */ return -1; } /* Get the image ready to be written. */ static int ready_to_write(Wtiff *wtiff) { VipsImage *input; VipsImage *x; input = wtiff->input; g_object_ref(input); if (vips_check_coding_known("vips2tiff", input)) { VIPS_UNREF(input); return -1; } /* Premultiply any alpha, if necessary. */ if (wtiff->premultiply && vips_image_hasalpha(input)) { VipsBandFormat start_format = input->BandFmt; if (vips_premultiply(input, &x, NULL)) { VIPS_UNREF(input); return -1; } VIPS_UNREF(input); input = x; /* Premultiply always makes a float -- cast back again. */ if (vips_cast(input, &x, start_format, NULL)) { VIPS_UNREF(input); return -1; } VIPS_UNREF(input); input = x; } /* "squash" float LAB down to LABQ. */ if (wtiff->bitdepth && input->Bands == 3 && input->BandFmt == VIPS_FORMAT_FLOAT && input->Type == VIPS_INTERPRETATION_LAB) { if (vips_Lab2LabQ(input, &x, NULL)) { VIPS_UNREF(input); return -1; } VIPS_UNREF(input); input = x; } wtiff->ready = input; return 0; } static Wtiff * wtiff_new(VipsImage *input, VipsTarget *target, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, gboolean miniswhite, VipsForeignTiffResunit resunit, double xres, double yres, gboolean bigtiff, gboolean rgbjpeg, gboolean properties, VipsRegionShrink region_shrink, int level, gboolean lossless, VipsForeignDzDepth depth, gboolean subifd, gboolean premultiply, int page_height) { Wtiff *wtiff; if (!(wtiff = VIPS_NEW(NULL, Wtiff))) return NULL; wtiff->input = input; wtiff->ready = NULL; wtiff->target = target; wtiff->layer = NULL; wtiff->tbuf = NULL; wtiff->compression = get_compression(compression); wtiff->Q = Q; wtiff->predictor = predictor; wtiff->tile = tile; wtiff->tilew = tile_width; wtiff->tileh = tile_height; wtiff->pyramid = pyramid; wtiff->bitdepth = bitdepth; wtiff->miniswhite = miniswhite; wtiff->resunit = get_resunit(resunit); wtiff->xres = xres; wtiff->yres = yres; wtiff->profile = profile; wtiff->bigtiff = bigtiff; wtiff->rgbjpeg = rgbjpeg; wtiff->properties = properties; wtiff->region_shrink = region_shrink; wtiff->level = level; wtiff->lossless = lossless; wtiff->depth = depth; wtiff->subifd = subifd; wtiff->premultiply = premultiply; wtiff->toilet_roll = FALSE; wtiff->page_height = page_height; wtiff->page_number = 0; wtiff->n_pages = 1; wtiff->image_height = input->Ysize; g_mutex_init(&wtiff->lock); /* Any pre-processing on the image. */ if (ready_to_write(wtiff)) { wtiff_free(wtiff); return NULL; } /* XYZ images are written as libtiff LOGLUV. */ if (wtiff->ready->Type == VIPS_INTERPRETATION_XYZ) wtiff->compression = COMPRESSION_SGILOG; /* Multipage image? 0 is the default for this argument. */ if (wtiff->page_height == 0) wtiff->page_height = vips_image_get_page_height(input); if (wtiff->page_height > 0 && wtiff->page_height < wtiff->ready->Ysize && wtiff->ready->Ysize % wtiff->page_height == 0) { #ifdef DEBUG printf("wtiff_new: detected toilet roll image, page-height=%d\n", wtiff->page_height); printf("wtiff_new: pages=%d\n", wtiff->ready->Ysize / wtiff->page_height); #endif /*DEBUG*/ wtiff->toilet_roll = TRUE; wtiff->image_height = wtiff->page_height; wtiff->n_pages = wtiff->ready->Ysize / wtiff->page_height; } /* subifd turns on pyramid mode. */ if (wtiff->subifd) wtiff->pyramid = TRUE; /* Pyramid images must be tiled. */ if (wtiff->pyramid) wtiff->tile = TRUE; /* Multi-page pyramids must be in subifd mode. */ if (wtiff->pyramid && wtiff->toilet_roll) wtiff->subifd = TRUE; /* We can only pyramid LABQ and non-complex images. */ if (wtiff->pyramid) { if (wtiff->ready->Coding == VIPS_CODING_NONE && vips_band_format_iscomplex(wtiff->ready->BandFmt)) { wtiff_free(wtiff); vips_error("vips2tiff", "%s", _("can only pyramid LABQ and non-complex images")); return NULL; } } /* If compression is off and we're writing a >4gb image, automatically * enable bigtiff. * * This won't always work. If the image data is just under 4gb but * there's a lot of metadata, we could be pushed over the 4gb limit. */ if (wtiff->compression == COMPRESSION_NONE && VIPS_IMAGE_SIZEOF_IMAGE(wtiff->ready) > UINT_MAX) wtiff->bigtiff = TRUE; /* In strip mode we use tileh to set rowsperstrip, and that does not * have the multiple-of-16 restriction. */ if (wtiff->tile) { if ((wtiff->tilew & 0xf) != 0 || (wtiff->tileh & 0xf) != 0) { wtiff_free(wtiff); vips_error("vips2tiff", "%s", _("tile size not a multiple of 16")); return NULL; } } /* Depth 8 is handled above. */ if (wtiff->bitdepth && !(wtiff->bitdepth == 1 || wtiff->bitdepth == 2 || wtiff->bitdepth == 4)) { g_warning("bitdepth 1, 2 or 4 only -- disabling bitdepth"); wtiff->bitdepth = 0; } /* Can only have byte fractional bit depths for 8 bit mono. * 3-band float should have been packed above. */ if (wtiff->bitdepth && !(wtiff->ready->Coding == VIPS_CODING_NONE && wtiff->ready->BandFmt == VIPS_FORMAT_UCHAR && wtiff->ready->Bands == 1)) { g_warning("can only set bitdepth for 1-band uchar and " "3-band float lab -- disabling bitdepth"); wtiff->bitdepth = 0; } if (wtiff->bitdepth && wtiff->compression == COMPRESSION_JPEG) { g_warning("can't have <8 bit JPEG -- disabling JPEG"); wtiff->compression = COMPRESSION_NONE; } /* We can only MINISWHITE non-complex images of 1 or 2 bands. */ if (wtiff->miniswhite && (wtiff->ready->Coding != VIPS_CODING_NONE || vips_band_format_iscomplex(wtiff->ready->BandFmt) || wtiff->ready->Bands > 2)) { g_warning("can only save non-complex greyscale images " "as miniswhite -- disabling miniswhite"); wtiff->miniswhite = FALSE; } /* Sizeof a line of bytes in the TIFF tile. */ if (wtiff->ready->Coding == VIPS_CODING_LABQ) wtiff->tls = wtiff->tilew * 3; else if (wtiff->bitdepth == 1) wtiff->tls = VIPS_ROUND_UP(wtiff->tilew, 8) / 8; else if (wtiff->bitdepth == 2) wtiff->tls = VIPS_ROUND_UP(wtiff->tilew, 4) / 4; else if (wtiff->bitdepth == 4) wtiff->tls = VIPS_ROUND_UP(wtiff->tilew, 2) / 2; else wtiff->tls = VIPS_IMAGE_SIZEOF_PEL(wtiff->ready) * wtiff->tilew; return wtiff; } /* Convert VIPS LabQ to TIFF LAB. Just take the first three bands. */ static void LabQ2LabC(VipsPel *q, VipsPel *p, int n) { int x; for (x = 0; x < n; x++) { /* Get most significant 8 bits of lab. */ q[0] = p[0]; q[1] = p[1]; q[2] = p[2]; p += 4; q += 3; } } /* Pack 8 bit VIPS to N bit TIFF. */ static void eightbit2nbit(Wtiff *wtiff, VipsPel *q, VipsPel *p, int n) { /* Invert in miniswhite mode. */ VipsPel mask = wtiff->miniswhite ? 255 : 0; int pixel_mask = 8 / wtiff->bitdepth - 1; int shift = 8 - wtiff->bitdepth; VipsPel bits; int x; bits = 0; for (x = 0; x < n; x++) { bits <<= wtiff->bitdepth; bits |= p[x] >> shift; if ((x & pixel_mask) == pixel_mask) *q++ = bits ^ mask; } /* Any left-over bits? Need to be left-aligned. */ if ((x & pixel_mask) != 0) { /* The number of bits we've collected in bits and must * left-align and flush. */ int collected_bits = (x & pixel_mask) << (wtiff->bitdepth - 1); *q++ = (bits ^ mask) << (8 - collected_bits); } } /* Swap the sense of the first channel, if necessary. */ #define GREY_LOOP(TYPE, MAX) \ { \ TYPE *p1; \ TYPE *q1; \ \ p1 = (TYPE *) p; \ q1 = (TYPE *) q; \ for (x = 0; x < n; x++) { \ if (invert) \ q1[0] = MAX - p1[0]; \ else \ q1[0] = p1[0]; \ \ for (i = 1; i < im->Bands; i++) \ q1[i] = p1[i]; \ \ q1 += im->Bands; \ p1 += im->Bands; \ } \ } /* If we're writing a 1 or 2 band image as a greyscale and MINISWHITE, we need * to swap the sense of the first band. See tiff2vips.c, greyscale_line() for * the opposite conversion. */ static void invert_band0(Wtiff *wtiff, VipsPel *q, VipsPel *p, int n) { VipsImage *im = wtiff->ready; gboolean invert = wtiff->miniswhite; int x, i; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_CHAR: GREY_LOOP(guchar, UCHAR_MAX); break; case VIPS_FORMAT_SHORT: GREY_LOOP(gshort, SHRT_MAX); break; case VIPS_FORMAT_USHORT: GREY_LOOP(gushort, USHRT_MAX); break; case VIPS_FORMAT_INT: GREY_LOOP(gint, INT_MAX); break; case VIPS_FORMAT_UINT: GREY_LOOP(guint, UINT_MAX); break; case VIPS_FORMAT_FLOAT: GREY_LOOP(float, 1.0); break; case VIPS_FORMAT_DOUBLE: GREY_LOOP(double, 1.0); break; default: g_assert_not_reached(); } } /* Convert VIPS LABS to TIFF 16 bit LAB. */ static void LabS2Lab16(VipsPel *q, VipsPel *p, int n, int samples_per_pixel) { short *p1 = (short *) p; unsigned short *q1 = (unsigned short *) q; int x; for (x = 0; x < n; x++) { int i; /* LABS L can be negative. */ q1[0] = VIPS_LSHIFT_INT(VIPS_MAX(0, p1[0]), 1); for (i = 1; i < samples_per_pixel; i++) q1[i] = p1[i]; q1 += samples_per_pixel; p1 += samples_per_pixel; } } /* Convert VIPS D65 XYZ to TIFF scaled float illuminant-free xyz. */ static void XYZ2tiffxyz(VipsPel *q, VipsPel *p, int n, int samples_per_pixel) { float *p1 = (float *) p; float *q1 = (float *) q; int x; for (x = 0; x < n; x++) { int i; q1[0] = p1[0] / VIPS_D65_X0; q1[1] = p1[1] / VIPS_D65_Y0; q1[2] = p1[2] / VIPS_D65_Z0; for (i = 3; i < samples_per_pixel; i++) q1[i] = p1[i]; q1 += samples_per_pixel; p1 += samples_per_pixel; } } /* Pack the pixels in @area from @in into a TIFF tile buffer. */ static void wtiff_pack2tiff(Wtiff *wtiff, Layer *layer, VipsRegion *in, VipsRect *area, VipsPel *q) { int y; /* JPEG compression can read outside the pixel area for edge tiles. It * always compresses 8x8 blocks, so if the image width or height is * not a multiple of 8, it can look beyond the pixels we will write. * * Black out the tile first to make sure these edge pixels are always * zero. */ if (wtiff->compression == COMPRESSION_JPEG && (area->width < wtiff->tilew || area->height < wtiff->tileh)) memset(q, 0, TIFFTileSize(layer->tif)); for (y = area->top; y < VIPS_RECT_BOTTOM(area); y++) { VipsPel *p = (VipsPel *) VIPS_REGION_ADDR(in, area->left, y); if (wtiff->ready->Coding == VIPS_CODING_LABQ) LabQ2LabC(q, p, area->width); else if (wtiff->bitdepth > 0) eightbit2nbit(wtiff, q, p, area->width); else if (wtiff->input->Type == VIPS_INTERPRETATION_XYZ) XYZ2tiffxyz(q, p, area->width, in->im->Bands); else if ((in->im->Bands == 1 || in->im->Bands == 2) && wtiff->miniswhite) invert_band0(wtiff, q, p, area->width); else if (wtiff->ready->BandFmt == VIPS_FORMAT_SHORT && wtiff->ready->Type == VIPS_INTERPRETATION_LABS) LabS2Lab16(q, p, area->width, in->im->Bands); else memcpy(q, p, area->width * VIPS_IMAGE_SIZEOF_PEL(wtiff->ready)); q += wtiff->tls; } } // a compressed (raw) tile waiting to be written typedef struct _WtiffTile { // x position (sort by this) int x; int y; // compressed data unsigned char *buffer; size_t length; } WtiffTile; // the state for a row of tiles being compressed in parallel typedef struct _WtiffRow { Wtiff *wtiff; VipsRegion *strip; Layer *layer; int x; // set of compressed tiles we have accumulated GSList *tiles; } WtiffRow; static int wtiff_row_add_tile(WtiffRow *row, int x, int y, unsigned char *buffer, size_t length) { WtiffTile *tile; if (!(tile = VIPS_NEW(NULL, WtiffTile))) return -1; tile->x = x; tile->y = y; tile->buffer = buffer; tile->length = length; g_mutex_lock(&row->wtiff->lock); row->tiles = g_slist_prepend(row->tiles, tile); g_mutex_unlock(&row->wtiff->lock); return 0; } static void wtiff_row_free(WtiffRow *row) { GSList *p; for (p = row->tiles; p; p = p->next) { WtiffTile *tile = (WtiffTile *) p->data; VIPS_FREE(tile->buffer); VIPS_FREE(tile); } VIPS_FREEF(g_slist_free, row->tiles); } static int wtiff_tile_compare(WtiffTile *a, WtiffTile *b, void *user_data) { return b->x - a->x; } static int wtiff_row_write(WtiffRow *row, TIFF *tif) { GSList *p; row->tiles = g_slist_sort(row->tiles, (GCompareFunc) wtiff_tile_compare); for (p = row->tiles; p; p = p->next) { WtiffTile *tile = (WtiffTile *) p->data; ttile_t tile_no = TIFFComputeTile(tif, tile->x, tile->y, 0, 0); if (TIFFWriteRawTile(tif, tile_no, tile->buffer, tile->length) == -1) { vips_error("vips2tiff", "%s", _("TIFF write tile failed")); return -1; } } return 0; } static int wtiff_layer_row_allocate(VipsThreadState *state, void *a, gboolean *stop) { WtiffRow *row = (WtiffRow *) a; Wtiff *wtiff = row->wtiff; VipsImage *im = row->layer->image; VipsRegion *strip = row->strip; VipsRect *valid = &strip->valid; #ifdef DEBUG_VERBOSE printf("wtiff_layer_row_allocate:\n"); #endif /*DEBUG_VERBOSE*/ if (row->x >= im->Xsize) { *stop = TRUE; #ifdef DEBUG_VERBOSE printf("wtiff_layer_row_allocate: done\n"); #endif /*DEBUG_VERBOSE*/ return 0; } state->x = row->x; state->y = valid->top; row->x += wtiff->tilew; return 0; } /* Compress a tile from a threadpool. */ static int wtiff_layer_row_work(VipsThreadState *state, void *a) { WtiffRow *row = (WtiffRow *) a; Wtiff *wtiff = row->wtiff; Layer *layer = row->layer; VipsImage *im = layer->image; VipsRegion *strip = row->strip; VipsRect *valid = &strip->valid; VipsRect image; VipsRect tile; VipsTarget *target; int result; unsigned char *buffer; size_t length; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; tile.left = state->x; tile.top = valid->top; tile.width = wtiff->tilew; tile.height = wtiff->tileh; vips_rect_intersectrect(&tile, &image, &tile); #ifdef DEBUG_VERBOSE printf("Compressing %dx%d tile at position %dx%d\n", tile.width, tile.height, tile.left, tile.top); #endif /*DEBUG_VERBOSE*/ target = vips_target_new_to_memory(); switch (wtiff->compression) { case JP2K_LOSSY: /* Sadly, chroma subsample seems not to work for edge tiles in tiff * with jp2k compression, so we always pass FALSE instead of: * * !wtiff->rgbjpeg && wtiff->Q < 90, * * I've verified that the libvips jp2k encode and decode subsample * operations fill the comps[i].data arrays correctly, so it * seems to be a openjpeg bug. * * FIXME ... try again with openjpeg 2.5, when that comes. */ result = vips__foreign_save_jp2k_compress( strip, &tile, target, wtiff->tilew, wtiff->tileh, !wtiff->rgbjpeg, // !wtiff->rgbjpeg && wtiff->Q < 90, FALSE, wtiff->lossless, wtiff->Q); break; #ifdef HAVE_JPEG case COMPRESSION_JPEG: result = wtiff_compress_jpeg(wtiff, strip, &tile, target); break; #endif /*HAVE_JPEG*/ default: result = -1; g_assert_not_reached(); break; } if (result) { g_object_unref(target); return -1; } buffer = vips_target_steal(target, &length); if (wtiff_row_add_tile(row, tile.left, tile.top, buffer, length)) { g_object_unref(target); g_free(buffer); return -1; } g_object_unref(target); return 0; } /* Write a set of tiles across the strip. */ static int wtiff_layer_write_tiles(Wtiff *wtiff, Layer *layer, VipsRegion *strip) { VipsImage *im = layer->image; VipsRect *area = &strip->valid; VipsRect image; int x; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; if (wtiff->we_compress) { /* If we're compressing ourselves, we can do the whole strip in * parallel. */ WtiffRow row = { wtiff, strip, layer, 0 }; VipsImage *x; if (vips_copy(im, &x, NULL)) return -1; /* We don't want threadpool_run to minimise on completion -- we need to * keep the cache on the pipeline before us. */ vips_image_set_int(x, "vips-no-minimise", 1); if (vips_threadpool_run(x, vips_thread_state_new, wtiff_layer_row_allocate, wtiff_layer_row_work, NULL, &row)) { VIPS_UNREF(x); wtiff_row_free(&row); return -1; } VIPS_UNREF(x); if (wtiff_row_write(&row, layer->tif)) { wtiff_row_free(&row); return -1; } wtiff_row_free(&row); } else { /* If we're using libtiff compression, we have to be serial. */ for (x = 0; x < im->Xsize; x += wtiff->tilew) { VipsRect tile; tile.left = x; tile.top = area->top; tile.width = wtiff->tilew; tile.height = wtiff->tileh; vips_rect_intersectrect(&tile, &image, &tile); /* Have to repack pixels for libtiff. */ wtiff_pack2tiff(wtiff, layer, strip, &tile, wtiff->tbuf); if (TIFFWriteTile(layer->tif, wtiff->tbuf, tile.left, tile.top, 0, 0) < 0) { vips_error("vips2tiff", "%s", _("TIFF write tile failed")); return -1; } } } return 0; } /* Write tileh scanlines, less for the last strip. */ static int wtiff_layer_write_strip(Wtiff *wtiff, Layer *layer, VipsRegion *strip) { VipsImage *im = layer->image; VipsRect *area = &strip->valid; int height = VIPS_MIN(wtiff->tileh, area->height); int y; #ifdef DEBUG_VERBOSE printf("wtiff_layer_write_strip: top %d, height %d, file %s\n", area->top, height, TIFFFileName(layer->tif)); #endif /*DEBUG_VERBOSE*/ for (y = 0; y < height; y++) { VipsPel *p = VIPS_REGION_ADDR(strip, 0, area->top + y); /* Any repacking necessary. */ if (im->Coding == VIPS_CODING_LABQ) { LabQ2LabC(wtiff->tbuf, p, im->Xsize); p = wtiff->tbuf; } else if (im->BandFmt == VIPS_FORMAT_SHORT && im->Type == VIPS_INTERPRETATION_LABS) { LabS2Lab16(wtiff->tbuf, p, im->Xsize, im->Bands); p = wtiff->tbuf; } else if (wtiff->input->Type == VIPS_INTERPRETATION_XYZ) { XYZ2tiffxyz(wtiff->tbuf, p, im->Xsize, im->Bands); p = wtiff->tbuf; } else if (wtiff->bitdepth > 0) { eightbit2nbit(wtiff, wtiff->tbuf, p, im->Xsize); p = wtiff->tbuf; } else if ((im->Bands == 1 || im->Bands == 2) && wtiff->miniswhite) { invert_band0(wtiff, wtiff->tbuf, p, im->Xsize); p = wtiff->tbuf; } if (TIFFWriteScanline(layer->tif, p, area->top + y, 0) < 0) return -1; } return 0; } static int layer_strip_arrived(Layer *layer); /* Shrink what pixels we can from this strip into the layer below. If the * strip below fills, recurse. */ static int layer_strip_shrink(Layer *layer) { Layer *below = layer->below; VipsRegion *from = layer->strip; VipsRegion *to = below->strip; VipsRect target; VipsRect source; /* Our pixels might cross a strip boundary in the layer below, so we * have to write repeatedly until we run out of pixels. */ for (;;) { /* The pixels the layer below needs. */ target.left = 0; target.top = below->write_y; target.width = below->image->Xsize; target.height = to->valid.height; vips_rect_intersectrect(&target, &to->valid, &target); /* Those pixels need this area of this layer. */ source.left = target.left * 2; source.top = target.top * 2; source.width = target.width * 2; source.height = target.height * 2; /* Of which we have these available. */ vips_rect_intersectrect(&source, &from->valid, &source); /* So these are the pixels in the layer below we can provide. */ target.left = source.left / 2; target.top = source.top / 2; target.width = source.width / 2; target.height = source.height / 2; /* None? All done. */ if (vips_rect_isempty(&target)) break; (void) vips_region_shrink_method(from, to, &target, layer->wtiff->region_shrink); below->write_y += target.height; /* If we've filled the strip below, let it know. * We can either fill the region, if it's somewhere half-way * down the image, or, if it's at the bottom, get to the last * real line of pixels. */ if (below->write_y == VIPS_RECT_BOTTOM(&to->valid) || below->write_y == below->height) { if (layer_strip_arrived(below)) return -1; } } return 0; } /* A new strip has arrived! The strip has at least enough pixels in to * write a line of tiles or a set of scanlines. * * - write a line of tiles / set of scanlines * - shrink what we can to the layer below * - move our strip down by the tile height * - copy the overlap with the previous strip */ static int layer_strip_arrived(Layer *layer) { Wtiff *wtiff = layer->wtiff; int result; VipsRect new_strip; VipsRect overlap; VipsRect image_area; if (wtiff->tile) result = wtiff_layer_write_tiles(wtiff, layer, layer->strip); else result = wtiff_layer_write_strip(wtiff, layer, layer->strip); if (result) return -1; if (layer->below && layer_strip_shrink(layer)) return -1; /* Position our strip down the image. * * Expand the strip if necessary to make sure we have an even * number of lines. */ layer->y += wtiff->tileh; new_strip.left = 0; new_strip.top = layer->y; new_strip.width = layer->image->Xsize; new_strip.height = wtiff->tileh; image_area.left = 0; image_area.top = 0; image_area.width = layer->image->Xsize; image_area.height = layer->image->Ysize; vips_rect_intersectrect(&new_strip, &image_area, &new_strip); if ((new_strip.height & 1) == 1) new_strip.height += 1; /* What pixels that we will need do we already have? Save them in * overlap. */ vips_rect_intersectrect(&new_strip, &layer->strip->valid, &overlap); if (!vips_rect_isempty(&overlap)) { if (vips_region_buffer(layer->copy, &overlap)) return -1; vips_region_copy(layer->strip, layer->copy, &overlap, overlap.left, overlap.top); } if (!vips_rect_isempty(&new_strip)) { if (vips_region_buffer(layer->strip, &new_strip)) return -1; /* And copy back again. */ if (!vips_rect_isempty(&overlap)) vips_region_copy(layer->copy, layer->strip, &overlap, overlap.left, overlap.top); } return 0; } /* Another few scanlines of pixels. We know the scanlines are all within the * current page. */ static int wtiff_write_lines(Wtiff *wtiff, VipsRegion *region, VipsRect *lines) { Layer *layer = wtiff->layer; int page_top = wtiff->page_number * wtiff->page_height; #ifdef DEBUG_VERBOSE printf("wtiff_write_lines: top %d, height %d\n", lines->top, lines->height); #endif /*DEBUG_VERBOSE*/ /* Keep filling the current strip of the top layer. Each time it * fills, write a chunk of pyramid. * * lines is in */ for (;;) { VipsRect *to = &layer->strip->valid; VipsRect target; VipsRect page_lines; /* The bit of strip that needs filling. */ target.left = 0; target.top = layer->write_y; target.width = layer->image->Xsize; target.height = to->height; vips_rect_intersectrect(&target, to, &target); /* region and lines are in world coordinates, we must subtract * the top of the current page to get layer coordinates. */ page_lines = *lines; page_lines.top -= page_top; /* Clip against the lines we've been given. */ vips_rect_intersectrect(&target, &page_lines, &target); /* Are we empty? All done. */ if (vips_rect_isempty(&target)) break; /* And copy those pixels in. * * FIXME: If the strip fits inside the region we've just * received, we could skip the copy. Will this happen very * often? Unclear. */ target.top += page_top; vips_region_copy(region, layer->strip, &target, target.left, target.top - page_top); layer->write_y += target.height; /* We can either fill the strip, if it's somewhere half-way * down the image, or, if it's at the bottom, get to the last * real line of pixels. */ if (layer->write_y == VIPS_RECT_BOTTOM(to) || layer->write_y == layer->height) { if (layer_strip_arrived(layer)) return -1; } } return 0; } /* Copy fields. */ #define CopyField(tag, v) \ if (TIFFGetField(in, tag, &v)) \ TIFFSetField(out, tag, v) static int wtiff_copy_tiles(Wtiff *wtiff, TIFF *out, TIFF *in) { const ttile_t n_tiles = TIFFNumberOfTiles(in); tsize_t tile_size; tdata_t buf; ttile_t i; /* If we will be copying raw tiles we need a buffer large * enough to hold the largest compressed tile in any page. * * Allocate a buffer 2x the uncompressed tile size ... much * simpler than searching every page for the largest tile with * TIFFTAG_TILEBYTECOUNTS. */ tile_size = (tsize_t) 2 * wtiff->tls * wtiff->tileh; buf = vips_malloc(NULL, tile_size); for (i = 0; i < n_tiles; i++) { tsize_t len = TIFFReadRawTile(in, i, buf, tile_size); if (len <= 0 || TIFFWriteRawTile(out, i, buf, len) < 0) { g_free(buf); return -1; } } g_free(buf); return 0; } /* Copy a TIFF file ... we know we wrote it, so just copy the tags we know * we might have set. */ static int wtiff_copy_tiff(Wtiff *wtiff, TIFF *out, TIFF *in) { guint32 ui32; guint16 ui16; guint16 ui16_2; float f; guint16 *a; /* All the fields we might have set. */ CopyField(TIFFTAG_IMAGEWIDTH, ui32); CopyField(TIFFTAG_IMAGELENGTH, ui32); CopyField(TIFFTAG_PLANARCONFIG, ui16); CopyField(TIFFTAG_ORIENTATION, ui16); CopyField(TIFFTAG_XRESOLUTION, f); CopyField(TIFFTAG_YRESOLUTION, f); CopyField(TIFFTAG_RESOLUTIONUNIT, ui16); CopyField(TIFFTAG_COMPRESSION, ui16); CopyField(TIFFTAG_SAMPLESPERPIXEL, ui16); CopyField(TIFFTAG_BITSPERSAMPLE, ui16); CopyField(TIFFTAG_PHOTOMETRIC, ui16); CopyField(TIFFTAG_ORIENTATION, ui16); CopyField(TIFFTAG_TILEWIDTH, ui32); CopyField(TIFFTAG_TILELENGTH, ui32); CopyField(TIFFTAG_ROWSPERSTRIP, ui32); CopyField(TIFFTAG_SUBFILETYPE, ui32); CopyField(TIFFTAG_PREDICTOR, ui16); CopyField(TIFFTAG_SAMPLEFORMAT, ui16); if (TIFFGetField(in, TIFFTAG_EXTRASAMPLES, &ui16, &a)) TIFFSetField(out, TIFFTAG_EXTRASAMPLES, ui16, a); if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &ui16, &ui16_2)) TIFFSetField(out, TIFFTAG_PAGENUMBER, ui16, ui16_2); unsigned char *buffer; guint32 length; if (TIFFGetField(in, TIFFTAG_JPEGTABLES, &length, &buffer)) TIFFSetField(out, TIFFTAG_JPEGTABLES, length, buffer); /* Other compression tags are just pseudotags and don't need to be set * because we copy raw tiles. */ /* We can't copy profiles or xmp :( Set again from wtiff. */ if (wtiff_embed_xmp(wtiff, out) || wtiff_embed_iptc(wtiff, out) || wtiff_embed_photoshop(wtiff, out) || wtiff_embed_imagedescription(wtiff, out) || wtiff_embed_profile(wtiff, out)) return -1; if (wtiff_copy_tiles(wtiff, out, in)) return -1; return 0; } /* Append all of the layers we wrote to the output. */ static int wtiff_gather(Wtiff *wtiff) { Layer *layer; #ifdef DEBUG printf("wtiff_gather:\n"); #endif /*DEBUG*/ if (wtiff->layer && wtiff->layer->below) for (layer = wtiff->layer->below; layer; layer = layer->below) { VipsSource *source; TIFF *in; #ifdef DEBUG printf("appending layer sub = %d ...\n", layer->sub); #endif /*DEBUG*/ if (!(source = vips_source_new_from_target(layer->target))) return -1; if (!(in = vips__tiff_openin_source(source, wtiff_handler_error, wtiff_handler_warning, NULL, FALSE))) { VIPS_UNREF(source); return -1; } VIPS_UNREF(source); if (wtiff_copy_tiff(wtiff, wtiff->layer->tif, in)) { TIFFClose(in); return -1; } TIFFClose(in); if (!TIFFWriteDirectory(wtiff->layer->tif)) return -1; } return 0; } static int wtiff_page_start(Wtiff *wtiff) { #ifdef DEBUG printf("wtiff_page_start: page %d\n", wtiff->page_number); #endif /*DEBUG*/ /* Init the pyramid framework for this page. This will just make a * single layer if we're not pyramiding. */ wtiff_layer_init(wtiff, &wtiff->layer, NULL, wtiff->ready->Xsize, wtiff->page_height); /* Fill all the layers and write the TIFF headers. */ if (wtiff_allocate_layers(wtiff)) return -1; /* In ifd mode, we write the pyramid layers as subdirectories of this * page. */ if (wtiff->subifd) { int n_layers; Layer *p; #ifdef DEBUG printf("wtiff_write_page: OME pyr mode\n"); #endif /*DEBUG*/ for (n_layers = 0, p = wtiff->layer->below; p; p = p->below) n_layers += 1; if (n_layers > 0) { toff_t *subifd_offsets; /* This magic tag makes the n_layers directories we * write after this one into subdirectories. We set * the offsets to 0 and libtiff will fill them in * automatically. */ subifd_offsets = VIPS_ARRAY(NULL, n_layers, toff_t); memset(subifd_offsets, 0, n_layers * sizeof(toff_t)); TIFFSetField(wtiff->layer->tif, TIFFTAG_SUBIFD, n_layers, subifd_offsets); g_free(subifd_offsets); } } return 0; } static int wtiff_page_end(Wtiff *wtiff) { #ifdef DEBUG printf("wtiff_page_end: page %d\n", wtiff->page_number); #endif /*DEBUG*/ if (!TIFFWriteDirectory(wtiff->layer->tif)) return -1; /* Append any pyr layers, if necessary. */ if (wtiff->layer->below) { Layer *layer; /* Free any lower pyramid resources ... this will * TIFFClose() (but not delete) the smaller layers * ready for us to read from them again. */ for (layer = wtiff->layer->below; layer; layer = layer->below) layer_free(layer); /* Append smaller layers to the main file. */ if (wtiff_gather(wtiff)) return -1; /* unref all the lower targets. */ for (layer = wtiff->layer->below; layer; layer = layer->below) VIPS_UNREF(layer->target); /* ... ready for the next page. */ wtiff->layer->below = NULL; } wtiff->page_number += 1; return 0; } /* A strip of pixels has come in from libvips. Split these strips into pages, * and run the page start / end code. */ static int wtiff_sink_disc_strip(VipsRegion *region, VipsRect *area, void *a) { Wtiff *wtiff = (Wtiff *) a; VipsRect pixels; #ifdef DEBUG_VERBOSE printf("wtiff_sink_disc_strip: top %d, height %d\n", area->top, area->height); #endif /*DEBUG_VERBOSE*/ g_assert(area->width == wtiff->ready->Xsize); /* Loop down this as we write scanlines into pages. */ pixels = *area; do { VipsRect page; VipsRect lines; /* The rect for the current page. */ page.left = 0; page.top = wtiff->page_height * wtiff->page_number; page.width = wtiff->ready->Xsize; page.height = wtiff->page_height; /* The scanlines we have for this page. */ vips_rect_intersectrect(&page, &pixels, &lines); /* At the top of the page? Run the page start code. */ if (lines.top == page.top && wtiff_page_start(wtiff)) return -1; /* Write the scanlines into the page. */ if (wtiff_write_lines(wtiff, region, &lines)) return -1; /* Hit the end of the page? Run the page end code. */ if (VIPS_RECT_BOTTOM(&page) == VIPS_RECT_BOTTOM(&lines) && wtiff_page_end(wtiff)) return -1; /* Remove the pixels we've written and loop if we have some * still to write. */ pixels.top += lines.height; pixels.height -= lines.height; } while (!vips_rect_isempty(&pixels)); return 0; } int vips__tiff_write_target(VipsImage *input, VipsTarget *target, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, const char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, int bitdepth, gboolean miniswhite, VipsForeignTiffResunit resunit, double xres, double yres, gboolean bigtiff, gboolean rgbjpeg, gboolean properties, VipsRegionShrink region_shrink, int level, gboolean lossless, VipsForeignDzDepth depth, gboolean subifd, gboolean premultiply, int page_height) { Wtiff *wtiff; vips__tiff_init(); if (!(wtiff = wtiff_new(input, target, compression, Q, predictor, profile, tile, tile_width, tile_height, pyramid, bitdepth, miniswhite, resunit, xres, yres, bigtiff, rgbjpeg, properties, region_shrink, level, lossless, depth, subifd, premultiply, page_height))) return -1; if (vips_sink_disc(wtiff->ready, wtiff_sink_disc_strip, wtiff)) { wtiff_free(wtiff); return -1; } wtiff_free(wtiff); return 0; } #endif /*HAVE_TIFF*/ libvips-8.18.2/libvips/foreign/vipsload.c000066400000000000000000000216451516303661500203660ustar00rootroot00000000000000/* load vips from a file * * 24/11/11 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* For vips_image_new_mode() */ #define VIPS_DISABLE_DEPRECATION_WARNINGS #include #include typedef struct _VipsForeignLoadVips { VipsForeignLoad parent_object; /* Source to load from (set by subclasses). */ VipsSource *source; } VipsForeignLoadVips; typedef VipsForeignLoadClass VipsForeignLoadVipsClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadVips, vips_foreign_load_vips, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_vips_dispose(GObject *gobject) { VipsForeignLoadVips *vips = (VipsForeignLoadVips *) gobject; VIPS_UNREF(vips->source); G_OBJECT_CLASS(vips_foreign_load_vips_parent_class)->dispose(gobject); } static VipsForeignFlags vips_foreign_load_vips_get_flags_source(VipsSource *source) { unsigned char *data; VipsForeignFlags flags; flags = VIPS_FOREIGN_PARTIAL; if (vips_source_sniff_at_most(source, &data, 4) == 4 && *((guint32 *) data) == VIPS_MAGIC_SPARC) flags |= VIPS_FOREIGN_BIGENDIAN; return flags; } static VipsForeignFlags vips_foreign_load_vips_get_flags(VipsForeignLoad *load) { VipsForeignLoadVips *vips = (VipsForeignLoadVips *) load; return vips_foreign_load_vips_get_flags_source(vips->source); } static VipsForeignFlags vips_foreign_load_vips_get_flags_filename(const char *filename) { VipsSource *source; VipsForeignFlags flags; if (!(source = vips_source_new_from_file(filename))) return 0; flags = vips_foreign_load_vips_get_flags_source(source); VIPS_UNREF(source); return flags; } static int vips_foreign_load_vips_header(VipsForeignLoad *load) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(load); VipsForeignLoadVips *vips = (VipsForeignLoadVips *) load; VipsConnection *connection = VIPS_CONNECTION(vips->source); const char *filename; VipsImage *image; VipsImage *x; if (!vips_source_is_file(vips->source) || !(filename = vips_connection_filename(connection))) { vips_error(class->nickname, "%s", _("no filename associated with source")); return -1; } if (!(image = vips_image_new_mode(filename, "r"))) return -1; /* What a hack. Remove the @out that's there now and replace it with * our image. */ g_object_get(load, "out", &x, NULL); g_object_unref(x); g_object_unref(x); g_object_set(load, "out", image, NULL); return 0; } static void vips_foreign_load_vips_class_init(VipsForeignLoadVipsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_vips_dispose; object_class->nickname = "vipsload_base"; object_class->description = _("load vips base class"); /* You're unlikely to want to use this on untrusted files. */ operation_class->flags |= VIPS_OPERATION_UNTRUSTED; /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; load_class->get_flags = vips_foreign_load_vips_get_flags; load_class->get_flags_filename = vips_foreign_load_vips_get_flags_filename; load_class->header = vips_foreign_load_vips_header; load_class->load = NULL; } static void vips_foreign_load_vips_init(VipsForeignLoadVips *vips) { } typedef struct _VipsForeignLoadVipsFile { VipsForeignLoadVips parent_object; char *filename; } VipsForeignLoadVipsFile; typedef VipsForeignLoadVipsClass VipsForeignLoadVipsFileClass; G_DEFINE_TYPE(VipsForeignLoadVipsFile, vips_foreign_load_vips_file, vips_foreign_load_vips_get_type()); static int vips_foreign_load_vips_file_build(VipsObject *object) { VipsForeignLoadVips *vips = (VipsForeignLoadVips *) object; VipsForeignLoadVipsFile *file = (VipsForeignLoadVipsFile *) object; if (file->filename && !(vips->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_vips_file_parent_class) ->build(object); } const char *vips__suffs[] = { ".v", ".vips", NULL }; static gboolean vips_foreign_load_vips_file_is_a(const char *filename) { return vips__file_magic(filename); } static void vips_foreign_load_vips_file_class_init(VipsForeignLoadVipsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "vipsload"; object_class->description = _("load vips from file"); object_class->build = vips_foreign_load_vips_file_build; foreign_class->suffs = vips__suffs; load_class->is_a = vips_foreign_load_vips_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadVipsFile, filename), NULL); } static void vips_foreign_load_vips_file_init(VipsForeignLoadVipsFile *file) { } typedef struct _VipsForeignLoadVipsSource { VipsForeignLoadVips parent_object; VipsSource *source; } VipsForeignLoadVipsSource; typedef VipsForeignLoadVipsClass VipsForeignLoadVipsSourceClass; G_DEFINE_TYPE(VipsForeignLoadVipsSource, vips_foreign_load_vips_source, vips_foreign_load_vips_get_type()); static int vips_foreign_load_vips_source_build(VipsObject *object) { VipsForeignLoadVips *vips = (VipsForeignLoadVips *) object; VipsForeignLoadVipsSource *source = (VipsForeignLoadVipsSource *) object; if (source->source) { vips->source = source->source; g_object_ref(vips->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_vips_source_parent_class) ->build(object); } static gboolean vips_foreign_load_vips_source_is_a_source(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); const char *filename; return vips_source_is_file(source) && (filename = vips_connection_filename(connection)) && vips__file_magic(filename); } static void vips_foreign_load_vips_source_class_init(VipsForeignLoadVipsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "vipsload_source"; object_class->description = _("load vips from source"); object_class->build = vips_foreign_load_vips_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips_foreign_load_vips_source_is_a_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadVipsSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_vips_source_init(VipsForeignLoadVipsSource *source) { } /** * vips_vipsload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read in a vips image. * * ::: seealso * [method@Image.vipssave]. * * Returns: 0 on success, -1 on error. */ int vips_vipsload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("vipsload", ap, filename, out); va_end(ap); return result; } /** * vips_vipsload_source: * @source: source to load from * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.vipsload], but read from a source. * * Returns: 0 on success, -1 on error. */ int vips_vipsload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("vipsload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/vipspng.c000066400000000000000000000753611516303661500202370ustar00rootroot00000000000000/* Load/save png image with libpng * * 28/11/03 JC * - better no-overshoot on tile loop * 22/2/05 * - read non-interlaced PNG with a line buffer (thanks Michel Brabants) * 11/1/06 * - read RGBA palette-ized images more robustly (thanks Tom) * 20/4/06 * - auto convert to sRGB/mono (with optional alpha) for save * 1/5/06 * - from vips_png.c * 8/5/06 * - set RGB16/GREY16 if appropriate * 2/11/07 * - use im_wbuffer() API for BG writes * 28/2/09 * - small cleanups * 4/2/10 * - gtkdoc * - fixed 16-bit save * 12/5/10 * - lololo but broke 8-bit save, fixed again * 20/7/10 Tim Elliott * - added im_vips2bufpng() * 8/1/11 * - get set png resolution (thanks Zhiyu Wu) * 17/3/11 * - update for libpng-1.5 API changes * - better handling of palette and 1-bit images * - ... but we are now png 1.2.9 and later only :-( argh * 28/3/11 * - argh gamma was wrong when viewed in firefox * 19/12/11 * - rework as a set of fns ready for wrapping as a class * 7/2/12 * - mild refactoring * - add support for sequential reads * 23/2/12 * - add a longjmp() to our error handler to stop the default one running * 13/3/12 * - add ICC profile read/write * 15/3/12 * - better alpha handling * - sanity check pixel geometry before allowing read * 17/6/12 * - more alpha fixes ... some images have no transparency chunk but * still set color_type to alpha * 16/7/13 * - more robust error handling from libpng * 9/8/14 * - don't check profiles, helps with libpng >=1.6.11 * 27/10/14 Lovell * - add @filter option * 26/2/15 * - close the read down early for a header read ... this saves an * fd during file read, handy for large numbers of input images * 31/7/16 * - support --strip option * 17/1/17 * - invalidate operation on read error * 27/2/17 * - use dbuf for buffer output * 30/3/17 * - better behaviour for truncated png files, thanks Yury * 26/4/17 * - better @fail handling with truncated PNGs * 9/4/18 * - set interlaced=1 for interlaced images * 20/6/18 [felixbuenemann] * - support png8 palette write with palette, colours, Q, dither * 25/8/18 * - support xmp read/write * 20/4/19 * - allow huge xmp metadata * 7/10/19 * - restart after minimise * 14/10/19 * - revise for connection IO * 11/5/20 * - only warn for saving bad profiles, don't fail * 19/2/21 781545872 * - read out background, if we can * 29/8/21 joshuamsager * - add "unlimited" flag to png load * 13/1/22 * - raise libpng pixel size limit to VIPS_MAX_COORD * 17/11/22 * - add exif read/write * 3/2/23 MathemanFlo * - add bits per sample metadata */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pforeign.h" #include "quantise.h" /* Shared with spng load/save. */ const char *vips__png_suffs[] = { ".png", NULL }; #ifdef HAVE_PNG #include #if PNG_LIBPNG_VER < 10003 #error "PNG library too old." #endif static void user_error_function(png_structp png_ptr, png_const_charp error_msg) { #ifdef DEBUG printf("user_error_function: %s\n", error_msg); #endif /*DEBUG*/ g_warning("%s", error_msg); /* This function must not return or the default error handler will be * invoked. */ longjmp(png_jmpbuf(png_ptr), -1); } static void user_warning_function(png_structp png_ptr, png_const_charp warning_msg) { #ifdef DEBUG printf("user_warning_function: %s\n", warning_msg); #endif /*DEBUG*/ g_warning("%s", warning_msg); } #define INPUT_BUFFER_SIZE (4096) /* What we track during a PNG read. */ typedef struct { char *name; VipsImage *out; VipsFailOn fail_on; gboolean unlimited; int y_pos; png_structp pPng; png_infop pInfo; png_bytep *row_pointer; VipsSource *source; /* read() to this buffer, copy to png as required. libpng does many * very small reads and we want to avoid a syscall for each one. */ unsigned char input_buffer[INPUT_BUFFER_SIZE]; unsigned char *next_byte; gint64 bytes_in_buffer; } Read; /* Can be called many times. */ static void read_destroy(Read *read) { /* We never call png_read_end(), perhaps we should. It can fail on * truncated files, so we'd need a setjmp(). */ if (read->pPng) png_destroy_read_struct(&read->pPng, &read->pInfo, NULL); VIPS_UNREF(read->source); VIPS_FREE(read->row_pointer); } static void read_close_cb(VipsImage *out, Read *read) { read_destroy(read); } static void read_minimise_cb(VipsImage *image, Read *read) { if (read->source) vips_source_minimise(read->source); } static void vips_png_read_source(png_structp pPng, png_bytep data, png_size_t length) { Read *read = png_get_io_ptr(pPng); #ifdef DEBUG printf("vips_png_read_source: read %zd bytes\n", length); #endif /*DEBUG*/ /* libpng makes many small reads, which hurts performance if you do a * syscall for each one. Read via our own buffer. */ while (length > 0) { gint64 bytes_available; if (read->bytes_in_buffer <= 0) { gint64 bytes_read; bytes_read = vips_source_read(read->source, read->input_buffer, INPUT_BUFFER_SIZE); if (bytes_read <= 0) png_error(pPng, "not enough data"); read->next_byte = read->input_buffer; read->bytes_in_buffer = bytes_read; } bytes_available = VIPS_MIN(read->bytes_in_buffer, length); memcpy(data, read->next_byte, bytes_available); data += bytes_available; length -= bytes_available; read->next_byte += bytes_available; read->bytes_in_buffer -= bytes_available; } } static Read * read_new(VipsSource *source, VipsImage *out, VipsFailOn fail_on, gboolean unlimited) { Read *read; if (!(read = VIPS_NEW(out, Read))) return NULL; read->name = NULL; read->fail_on = fail_on; read->out = out; read->y_pos = 0; read->pPng = NULL; read->pInfo = NULL; read->row_pointer = NULL; read->source = source; read->unlimited = unlimited; g_object_ref(source); g_signal_connect(out, "close", G_CALLBACK(read_close_cb), read); g_signal_connect(out, "minimise", G_CALLBACK(read_minimise_cb), read); if (!(read->pPng = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, user_error_function, user_warning_function))) return NULL; /* Prevent libpng (>=1.6.11) verifying sRGB profiles. Many PNGs have * broken profiles, but we still want to be able to open them. */ #ifdef PNG_SKIP_sRGB_CHECK_PROFILE png_set_option(read->pPng, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON); #endif /*PNG_SKIP_sRGB_CHECK_PROFILE*/ /* In non-fail mode, ignore CRC errors. */ if (read->fail_on < VIPS_FAIL_ON_ERROR) { #ifdef PNG_IGNORE_ADLER32 png_set_option(read->pPng, PNG_IGNORE_ADLER32, PNG_OPTION_ON); #endif /*PNG_IGNORE_ADLER32*/ /* Ignore and don't calculate checksums. */ png_set_crc_action(read->pPng, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); } /* libpng has a default soft limit of 1m pixels per axis. */ png_set_user_limits(read->pPng, VIPS_MAX_COORD, VIPS_MAX_COORD); if (vips_source_rewind(source)) return NULL; png_set_read_fn(read->pPng, read, vips_png_read_source); /* Catch PNG errors from png_read_info() etc. */ if (setjmp(png_jmpbuf(read->pPng))) return NULL; if (!(read->pInfo = png_create_info_struct(read->pPng))) return NULL; #ifdef HAVE_PNG_SET_CHUNK_MALLOC_MAX /* By default, libpng refuses to open files with a metadata chunk * larger than 8mb. We've seen real files with 20mb, so set 50mb. */ png_set_chunk_malloc_max(read->pPng, 50 * 1024 * 1024); /* This limits the number of chunks. The limit from * png_set_chunk_malloc_max() times this value is the maximum * memory use. * * libnpng defaults to 1000, which is rather high. */ png_set_chunk_cache_max(read->pPng, 100); #endif /*HAVE_PNG_SET_CHUNK_MALLOC_MAX*/ png_read_info(read->pPng, read->pInfo); return read; } /* Set the png text data as metadata on the vips image. These are always * null-terminated strings. */ static int vips__set_text(VipsImage *out, int i, const char *key, const char *text) { char name[256]; if (strcmp(key, "XML:com.adobe.xmp") == 0) { /* Save as an XMP tag. This must be a BLOB, for compatibility * for things like the XMP blob that the tiff loader adds. * * Note that this will remove the null-termination from the * string. We must carefully reattach this. */ vips_image_set_blob_copy(out, VIPS_META_XMP_NAME, text, strlen(text)); } else { /* Save as a string comment. Some PNGs have EXIF data as * text segments, but the correct way to support this is with * png_get_eXIf_1(). */ g_snprintf(name, 256, "png-comment-%d-%s", i, key); vips_image_set_string(out, name, text); } return 0; } /* Read a png header. */ static int png2vips_header(Read *read, VipsImage *out, gboolean header_only) { png_uint_32 width, height; int bitdepth, color_type; int interlace_type; png_uint_32 res_x, res_y; int unit_type; png_charp name; int compression_type; png_textp text_ptr; int num_text; /* Well thank you, libpng. */ #if PNG_LIBPNG_VER < 10400 png_charp profile; #else png_bytep profile; #endif png_uint_32 proflen; int bands; VipsInterpretation interpretation; double Xres, Yres; if (setjmp(png_jmpbuf(read->pPng))) return -1; png_get_IHDR(read->pPng, read->pInfo, &width, &height, &bitdepth, &color_type, &interlace_type, NULL, NULL); /* png_get_channels() gives us 1 band for palette images ... so look * at colour_type for output bands. * * Ignore alpha, we detect that separately below. */ switch (color_type) { case PNG_COLOR_TYPE_PALETTE: bands = 3; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_GRAY: bands = 1; break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: bands = 3; break; default: vips_error("png2vips", "%s", _("unsupported color type")); return -1; } if (bitdepth > 8) { if (bands < 3) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_RGB16; } else { if (bands < 3) interpretation = VIPS_INTERPRETATION_B_W; else interpretation = VIPS_INTERPRETATION_sRGB; } /* Expand palette images. */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(read->pPng); /* Expand transparency. */ if (png_get_valid(read->pPng, read->pInfo, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(read->pPng); bands += 1; } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { /* Some images have no transparency chunk, but still set * color_type to alpha. */ bands += 1; } /* Expand <8 bit images to full bytes. */ if (color_type == PNG_COLOR_TYPE_GRAY && bitdepth < 8) png_set_expand_gray_1_2_4_to_8(read->pPng); /* If we're an INTEL byte order machine and this is 16bits, we need * to swap bytes. */ if (bitdepth > 8 && !vips_amiMSBfirst()) png_set_swap(read->pPng); /* Get resolution. Default to 72 pixels per inch, the usual png value. */ unit_type = PNG_RESOLUTION_METER; res_x = 72.0 / 2.54 * 100.0; res_y = 72.0 / 2.54 * 100.0; png_get_pHYs(read->pPng, read->pInfo, &res_x, &res_y, &unit_type); switch (unit_type) { case PNG_RESOLUTION_METER: Xres = res_x / 1000.0; Yres = res_y / 1000.0; break; default: Xres = res_x; Yres = res_y; break; } /* Set VIPS header. */ vips_image_init_fields(out, width, height, bands, bitdepth > 8 ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, interpretation, Xres, Yres); VIPS_SETSTR(out->filename, vips_connection_filename(VIPS_CONNECTION(read->source))); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; /* Fetch the ICC profile. @name is useless, something like "icc" or * "ICC Profile" etc. Ignore it. * * @profile was png_charpp in libpngs < 1.5, png_bytepp is the * modern one. Ignore the warning, if any. */ if (png_get_iCCP(read->pPng, read->pInfo, &name, &compression_type, &profile, &proflen)) { #ifdef DEBUG printf("png2vips_header: attaching %d bytes of ICC profile\n", proflen); printf("png2vips_header: name = \"%s\"\n", name); #endif /*DEBUG*/ vips_image_set_blob_copy(out, VIPS_META_ICC_NAME, profile, proflen); } /* Some libpng warn you to call png_set_interlace_handling(); here, but * that can actually break interlace on older libpngs. * * Only set this for libpng 1.6+. */ #if PNG_LIBPNG_VER > 10600 (void) png_set_interlace_handling(read->pPng); #endif /* Sanity-check line size. * * Don't do this for header read, since we don't want to force a * malloc if all we are doing is looking at fields. */ if (!header_only) { png_read_update_info(read->pPng, read->pInfo); if (png_get_rowbytes(read->pPng, read->pInfo) != VIPS_IMAGE_SIZEOF_LINE(out)) { vips_error("vipspng", "%s", _("unable to read PNG header")); return -1; } } /* Let our caller know. These are very expensive to decode. */ if (interlace_type != PNG_INTERLACE_NONE) vips_image_set_int(out, "interlaced", 1); if (png_get_text(read->pPng, read->pInfo, &text_ptr, &num_text) > 0) { int i; /* Very large numbers of text chunks are used in DoS * attacks. */ if (!read->unlimited && num_text > MAX_PNG_TEXT_CHUNKS) { g_warning("%d text chunks, only %d text chunks will be loaded", num_text, MAX_PNG_TEXT_CHUNKS); num_text = MAX_PNG_TEXT_CHUNKS; } for (i = 0; i < num_text; i++) /* .text is always a null-terminated C string. */ if (vips__set_text(out, i, text_ptr[i].key, text_ptr[i].text)) return -1; } vips_image_set_int(out, VIPS_META_BITS_PER_SAMPLE, bitdepth); if (color_type == PNG_COLOR_TYPE_PALETTE) { /* Deprecated "palette-bit-depth" use "bits-per-sample" instead. */ vips_image_set_int(out, "palette-bit-depth", bitdepth); vips_image_set_int(out, VIPS_META_PALETTE, 1); } /* Note the PNG background colour, if any. */ #ifdef PNG_bKGD_SUPPORTED { png_color_16 *background; if (png_get_bKGD(read->pPng, read->pInfo, &background)) { const int scale = out->BandFmt == VIPS_FORMAT_UCHAR ? 1 : 256; double array[3]; int n; switch (color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: array[0] = background->gray / scale; n = 1; break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: array[0] = background->red / scale; array[1] = background->green / scale; array[2] = background->blue / scale; n = 3; break; case PNG_COLOR_TYPE_PALETTE: default: /* Not sure what to do here. I suppose we should read * the palette. */ n = 0; break; } if (n > 0) vips_image_set_array_double(out, "background", array, n); } } #endif /*PNG_bKGD_SUPPORTED*/ #ifdef PNG_eXIf_SUPPORTED { png_uint_32 num_exif; png_bytep exif; if (png_get_eXIf_1(read->pPng, read->pInfo, &num_exif, &exif)) vips_image_set_blob_copy(out, VIPS_META_EXIF_NAME, exif, num_exif); } #endif /*PNG_eXIf_SUPPORTED*/ return 0; } /* Out is a huge "t" buffer we decompress to. */ static int png2vips_interlace(Read *read, VipsImage *out) { int y; #ifdef DEBUG printf("png2vips_interlace: reading whole image\n"); #endif /*DEBUG*/ if (vips_image_write_prepare(out)) return -1; if (setjmp(png_jmpbuf(read->pPng))) return -1; if (!(read->row_pointer = VIPS_ARRAY(NULL, out->Ysize, png_bytep))) return -1; for (y = 0; y < out->Ysize; y++) read->row_pointer[y] = VIPS_IMAGE_ADDR(out, 0, y); png_read_image(read->pPng, read->row_pointer); read_destroy(read); return 0; } static int png2vips_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; Read *read = (Read *) a; int y; #ifdef DEBUG printf("png2vips_generate: line %d, %d rows\n", r->top, r->height); printf("png2vips_generate: y_top = %d\n", read->y_pos); #endif /*DEBUG*/ /* We're inside a tilecache where tiles are the full image width, so * this should always be true. */ g_assert(r->left == 0); g_assert(r->width == out_region->im->Xsize); g_assert(VIPS_RECT_BOTTOM(r) <= out_region->im->Ysize); /* Tiles should always be a strip in height, unless it's the final * strip. */ g_assert(r->height == VIPS_MIN(VIPS__FATSTRIP_HEIGHT, out_region->im->Ysize - r->top)); /* And check that y_pos is correct. It should be, since we are inside * a vips_sequential(). */ if (r->top != read->y_pos) { vips_error("vipspng", _("out of order read at line %d"), read->y_pos); return -1; } for (y = 0; y < r->height; y++) { png_bytep q = (png_bytep) VIPS_REGION_ADDR(out_region, 0, r->top + y); /* We need to catch errors from read_row(). */ if (!setjmp(png_jmpbuf(read->pPng))) png_read_row(read->pPng, q, NULL); else { /* We've failed to read some pixels. Knock this * operation out of cache. */ vips_foreign_load_invalidate(read->out); #ifdef DEBUG printf( "png2vips_generate: png_read_row() failed, " "line %d\n", r->top + y); printf("png2vips_generate: file %s\n", read->name); printf("png2vips_generate: thread %p\n", g_thread_self()); #endif /*DEBUG*/ /* And bail if fail is on. We have to add an error * message, since the handler we install just does * g_warning(). */ if (read->fail_on >= VIPS_FAIL_ON_TRUNCATED) { vips_error("vipspng", "%s", _("libpng read error")); return -1; } } read->y_pos += 1; } return 0; } static int png2vips_image(Read *read, VipsImage *out) { int interlace_type = png_get_interlace_type(read->pPng, read->pInfo); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 3); if (interlace_type != PNG_INTERLACE_NONE) { /* Arg awful interlaced image. We have to load to a huge mem * buffer, then copy to out. */ t[0] = vips_image_new_memory(); if (png2vips_header(read, t[0], FALSE) || png2vips_interlace(read, t[0]) || vips_image_write(t[0], out)) return -1; } else { t[0] = vips_image_new(); if (png2vips_header(read, t[0], FALSE) || vips_image_generate(t[0], NULL, png2vips_generate, NULL, read, NULL) || vips_sequential(t[0], &t[1], "tile_height", VIPS__FATSTRIP_HEIGHT, NULL) || vips_image_write(t[1], out)) return -1; } return 0; } gboolean vips__png_ispng_source(VipsSource *source) { const unsigned char *p; if ((p = vips_source_sniff(source, 8)) && !png_sig_cmp((png_bytep) p, 0, 8)) return TRUE; return FALSE; } int vips__png_header_source(VipsSource *source, VipsImage *out, gboolean unlimited) { Read *read; if (!(read = read_new(source, out, VIPS_FAIL_ON_NONE, unlimited)) || png2vips_header(read, out, TRUE)) return -1; vips_source_minimise(source); return 0; } int vips__png_read_source(VipsSource *source, VipsImage *out, VipsFailOn fail_on, gboolean unlimited) { Read *read; if (!(read = read_new(source, out, fail_on, unlimited)) || png2vips_image(read, out) || vips_source_decode(source)) return -1; return 0; } /* Interlaced PNGs need to be entirely decompressed into memory then can be * served partially from there. Non-interlaced PNGs may be read sequentially. */ gboolean vips__png_isinterlaced_source(VipsSource *source) { VipsImage *image; Read *read; int interlace_type; image = vips_image_new(); if (!(read = read_new(source, image, VIPS_FAIL_ON_NONE, FALSE))) { g_object_unref(image); return -1; } interlace_type = png_get_interlace_type(read->pPng, read->pInfo); g_object_unref(image); return interlace_type != PNG_INTERLACE_NONE; } /* What we track during a PNG write. */ typedef struct { VipsImage *in; VipsImage *memory; VipsTarget *target; png_structp pPng; png_infop pInfo; png_bytep *row_pointer; } Write; static void write_destroy(Write *write) { #ifdef DEBUG printf("write_destroy: %p\n", write); #endif /*DEBUG*/ VIPS_UNREF(write->memory); if (write->pPng) png_destroy_write_struct(&write->pPng, &write->pInfo); VIPS_FREE(write->row_pointer); VIPS_FREE(write); } static void user_write_data(png_structp pPng, png_bytep data, png_size_t length) { Write *write = (Write *) png_get_io_ptr(pPng); if (vips_target_write(write->target, data, length)) png_error(pPng, "not enough data"); } static Write * write_new(VipsImage *in, VipsTarget *target) { Write *write; if (!(write = VIPS_NEW(NULL, Write))) return NULL; write->in = in; write->target = target; #ifdef DEBUG printf("write_new: %p\n", write); #endif /*DEBUG*/ if (!(write->row_pointer = VIPS_ARRAY(NULL, in->Ysize, png_bytep))) return NULL; if (!(write->pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, user_error_function, user_warning_function))) { write_destroy(write); return NULL; } /* Prevent libpng (>=1.6.11) verifying sRGB profiles. We are often * asked to copy images containing bad profiles, and this check would * prevent that. */ #ifdef PNG_SKIP_sRGB_CHECK_PROFILE png_set_option(write->pPng, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON); #endif /*PNG_SKIP_sRGB_CHECK_PROFILE*/ png_set_write_fn(write->pPng, write, user_write_data, NULL); /* Catch PNG errors from png_create_info_struct(). */ if (setjmp(png_jmpbuf(write->pPng))) { write_destroy(write); return NULL; } if (!(write->pInfo = png_create_info_struct(write->pPng))) { write_destroy(write); return NULL; } return write; } static int write_png_block(VipsRegion *region, VipsRect *area, void *a) { Write *write = (Write *) a; int i; /* The area to write is always a set of complete scanlines. */ g_assert(area->left == 0); g_assert(area->width == region->im->Xsize); g_assert(area->top + area->height <= region->im->Ysize); /* Catch PNG errors. */ if (setjmp(png_jmpbuf(write->pPng))) return -1; for (i = 0; i < area->height; i++) write->row_pointer[i] = (png_bytep) VIPS_REGION_ADDR(region, 0, area->top + i); png_write_rows(write->pPng, write->row_pointer, area->height); return 0; } static void vips__png_set_text(png_structp pPng, png_infop pInfo, const char *key, const char *value) { png_text text; text.compression = 0; text.key = (char *) key; text.text = (char *) value; text.text_length = strlen(value); /* Before 1.4, these fields were only there if explicitly enabled. */ #if PNG_LIBPNG_VER > 10400 text.itxt_length = 0; text.lang = NULL; #endif png_set_text(pPng, pInfo, &text, 1); } static void * write_png_comment(VipsImage *image, const char *field, GValue *value, void *data) { Write *write = (Write *) data; if (vips_isprefix("png-comment-", field)) { const char *str; int i; char key[256]; if (vips_image_get_string(write->in, field, &str)) return image; if (strlen(field) > 256 || sscanf(field, "png-comment-%d-%80s", &i, key) != 2) { vips_error("vips2png", "%s", _("bad png comment key")); return image; } vips__png_set_text(write->pPng, write->pInfo, key, str); } return NULL; } static int vips_png_add_icc(Write *write, const void *data, size_t length) { if (setjmp(png_jmpbuf(write->pPng))) g_debug("bad ICC profile not saved"); else png_set_iCCP(write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, (void *) data, length); return 0; } static int vips_png_add_custom_icc(Write *write, const char *profile) { VipsBlob *blob; if (vips_profile_load(profile, &blob, NULL)) return -1; if (blob) { size_t length; const void *data = vips_blob_get(blob, &length); vips_png_add_icc(write, data, length); vips_area_unref((VipsArea *) blob); } return 0; } static int vips_png_add_original_icc(Write *write) { const void *data; size_t length; if (vips_image_get_blob(write->in, VIPS_META_ICC_NAME, &data, &length)) return -1; vips_png_add_icc(write, data, length); return 0; } /* Write a VIPS image to PNG. */ static int write_vips(Write *write, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean palette, int Q, double dither, int bitdepth, int effort) { VipsImage *in = write->in; int color_type; int interlace_type; int i, nb_passes; g_assert(in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT); g_assert(in->Coding == VIPS_CODING_NONE); g_assert(in->Bands > 0 && in->Bands < 5); /* Catch PNG errors. */ if (setjmp(png_jmpbuf(write->pPng))) return -1; /* Check input image. If we are writing interlaced, we need to make 7 * passes over the image. We advertise ourselves as seq, so to ensure * we only suck once from upstream, switch to WIO. */ if (interlace) { if (!(write->memory = vips_image_copy_memory(in))) return -1; in = write->memory; } else { if (vips_image_pio_input(in)) return -1; } if (compress < 0 || compress > 9) { vips_error("vips2png", "%s", _("compress should be in [0,9]")); return -1; } /* Set compression parameters. */ png_set_compression_level(write->pPng, compress); /* Set row filter. */ png_set_filter(write->pPng, 0, filter); switch (in->Bands) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: vips_error("vips2png", _("can't save %d band image as png"), in->Bands); return -1; } #ifdef HAVE_QUANTIZATION /* Enable image quantisation to paletted 8bpp PNG if palette is set. */ if (palette) color_type = PNG_COLOR_TYPE_PALETTE; #else if (palette) g_warning("ignoring palette (no quantisation support)"); #endif /*HAVE_QUANTIZATION*/ interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; /* libpng has a default soft limit of 1m pixels per axis. */ png_set_user_limits(write->pPng, VIPS_MAX_COORD, VIPS_MAX_COORD); png_set_IHDR(write->pPng, write->pInfo, in->Xsize, in->Ysize, bitdepth, color_type, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Set resolution. libpng uses pixels per meter. */ png_set_pHYs(write->pPng, write->pInfo, rint(in->Xres * 1000), rint(in->Yres * 1000), PNG_RESOLUTION_METER); /* Metadata */ if (vips_image_get_typeof(in, VIPS_META_XMP_NAME)) { const void *data; size_t length; char *str; /* XMP is attached as a BLOB with no null-termination. * We must re-add this. */ if (vips_image_get_blob(in, VIPS_META_XMP_NAME, &data, &length)) return -1; str = g_malloc(length + 1); g_strlcpy(str, data, length + 1); vips__png_set_text(write->pPng, write->pInfo, "XML:com.adobe.xmp", str); g_free(str); } #ifdef PNG_eXIf_SUPPORTED if (vips_image_get_typeof(in, VIPS_META_EXIF_NAME)) { const void *data; size_t length; if (vips_image_get_blob(in, VIPS_META_EXIF_NAME, &data, &length)) return -1; /* libpng does not want the JFIF "Exif\0\0" prefix. */ if (length >= 6 && vips_isprefix("Exif", (char *) data)) { data = (char *) data + 6; length -= 6; } png_set_eXIf_1(write->pPng, write->pInfo, length, (png_bytep) data); } #endif /*PNG_eXIf_SUPPORTED*/ if (vips_image_map(in, write_png_comment, write)) return -1; /* A profile supplied as an argument overrides an embedded * profile. */ if (profile) { if (vips_png_add_custom_icc(write, profile)) return -1; } else if (vips_image_get_typeof(in, VIPS_META_ICC_NAME)) { if (vips_png_add_original_icc(write)) return -1; } // the profile writers grab the setjmp, restore it if (setjmp(png_jmpbuf(write->pPng))) return -1; #ifdef HAVE_QUANTIZATION if (palette) { VipsImage *im_index; VipsImage *im_palette; int palette_count; png_color *png_palette; png_byte *png_trans; int trans_count; if (vips__quantise_image(in, &im_index, &im_palette, 1 << bitdepth, Q, dither, effort, FALSE)) return -1; palette_count = im_palette->Xsize; g_assert(palette_count <= PNG_MAX_PALETTE_LENGTH); png_palette = (png_color *) png_malloc(write->pPng, palette_count * sizeof(png_color)); png_trans = (png_byte *) png_malloc(write->pPng, palette_count * sizeof(png_byte)); trans_count = 0; for (i = 0; i < palette_count; i++) { VipsPel *p = (VipsPel *) VIPS_IMAGE_ADDR(im_palette, i, 0); png_color *col = &png_palette[i]; col->red = p[0]; col->green = p[1]; col->blue = p[2]; png_trans[i] = p[3]; if (p[3] != 255) trans_count = i + 1; #ifdef DEBUG printf("write_vips: palette[%d] %d %d %d %d\n", i + 1, p[0], p[1], p[2], p[3]); #endif /*DEBUG*/ } #ifdef DEBUG printf("write_vips: attaching %d color palette\n", palette_count); #endif /*DEBUG*/ png_set_PLTE(write->pPng, write->pInfo, png_palette, palette_count); if (trans_count) { #ifdef DEBUG printf("write_vips: attaching %d alpha values\n", trans_count); #endif /*DEBUG*/ png_set_tRNS(write->pPng, write->pInfo, png_trans, trans_count, NULL); } png_free(write->pPng, (void *) png_palette); png_free(write->pPng, (void *) png_trans); VIPS_UNREF(im_palette); VIPS_UNREF(write->memory); write->memory = im_index; in = write->memory; } #endif /*HAVE_QUANTIZATION*/ png_write_info(write->pPng, write->pInfo); /* If we're an intel byte order CPU and this is a 16bit image, we need * to swap bytes. */ if (bitdepth > 8 && !vips_amiMSBfirst()) png_set_swap(write->pPng); /* If bitdepth is 1/2/4, pack pixels into bytes. */ png_set_packing(write->pPng); if (interlace) nb_passes = png_set_interlace_handling(write->pPng); else nb_passes = 1; /* Write data. */ for (i = 0; i < nb_passes; i++) if (vips_sink_disc(in, write_png_block, write)) return -1; /* The setjmp() was held by our background writer: reset it. */ if (setjmp(png_jmpbuf(write->pPng))) return -1; png_write_end(write->pPng, write->pInfo); return 0; } int vips__png_write_target(VipsImage *in, VipsTarget *target, int compression, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean palette, int Q, double dither, int bitdepth, int effort) { Write *write; if (!(write = write_new(in, target))) return -1; if (write_vips(write, compression, interlace, profile, filter, palette, Q, dither, bitdepth, effort)) { write_destroy(write); vips_error("vips2png", _("unable to write to target %s"), vips_connection_nick(VIPS_CONNECTION(target))); return -1; } write_destroy(write); if (vips_target_end(target)) return -1; return 0; } #endif /*HAVE_PNG*/ libvips-8.18.2/libvips/foreign/vipssave.c000066400000000000000000000164701516303661500204050ustar00rootroot00000000000000/* save to vips * * 24/11/11 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* For vips_image_new_mode() */ #define VIPS_DISABLE_DEPRECATION_WARNINGS #include #include typedef struct _VipsForeignSaveVips { VipsForeignSave parent_object; VipsTarget *target; } VipsForeignSaveVips; typedef VipsForeignSaveClass VipsForeignSaveVipsClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveVips, vips_foreign_save_vips, VIPS_TYPE_FOREIGN_SAVE); static void vips_foreign_save_vips_dispose(GObject *gobject) { VipsForeignSaveVips *vips = (VipsForeignSaveVips *) gobject; VIPS_UNREF(vips->target); G_OBJECT_CLASS(vips_foreign_save_vips_parent_class)->dispose(gobject); } static int vips_foreign_save_vips_build(VipsObject *object) { VipsForeignSaveVips *vips = (VipsForeignSaveVips *) object; const char *filename; if (VIPS_OBJECT_CLASS(vips_foreign_save_vips_parent_class)->build(object)) return -1; if ((filename = vips_connection_filename(VIPS_CONNECTION(vips->target)))) { VipsForeignSave *save = (VipsForeignSave *) object; VipsImage *x; /* vips_image_build() has some magic for "w" * preventing recursion and sending this directly to the * saver built into iofuncs. */ if (!(x = vips_image_new_mode(filename, "w"))) return -1; if (vips_image_write(save->ready, x)) { g_object_unref(x); return -1; } g_object_unref(x); } else { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); /* We could add load vips from memory, fd, via mmap etc. here. * We should perhaps move iofuncs/vips.c into this file. * * For now, just fail unless there's a filename associated * with this source. */ vips_error(class->nickname, "%s", _("no filename associated with target")); return -1; } if (vips_target_end(vips->target)) return -1; return 0; } /* From vipsload.c. */ extern const char *vips__suffs[]; static void vips_foreign_save_vips_class_init(VipsForeignSaveVipsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_vips_dispose; object_class->nickname = "vipssave_base"; object_class->description = _("save vips base class"); object_class->build = vips_foreign_save_vips_build; foreign_class->suffs = vips__suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_ANY; save_class->coding = VIPS_FOREIGN_CODING_ALL; } static void vips_foreign_save_vips_init(VipsForeignSaveVips *vips) { } typedef struct _VipsForeignSaveVipsFile { VipsForeignSaveVips parent_object; char *filename; } VipsForeignSaveVipsFile; typedef VipsForeignSaveVipsClass VipsForeignSaveVipsFileClass; G_DEFINE_TYPE(VipsForeignSaveVipsFile, vips_foreign_save_vips_file, vips_foreign_save_vips_get_type()); static int vips_foreign_save_vips_file_build(VipsObject *object) { VipsForeignSaveVips *vips = (VipsForeignSaveVips *) object; VipsForeignSaveVipsFile *file = (VipsForeignSaveVipsFile *) object; if (!(vips->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_vips_file_parent_class) ->build(object); } static void vips_foreign_save_vips_file_class_init(VipsForeignSaveVipsFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "vipssave"; object_class->description = _("save image to file in vips format"); object_class->build = vips_foreign_save_vips_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveVipsFile, filename), NULL); } static void vips_foreign_save_vips_file_init(VipsForeignSaveVipsFile *file) { } typedef struct _VipsForeignSaveVipsTarget { VipsForeignSaveVips parent_object; VipsTarget *target; } VipsForeignSaveVipsTarget; typedef VipsForeignSaveVipsClass VipsForeignSaveVipsTargetClass; G_DEFINE_TYPE(VipsForeignSaveVipsTarget, vips_foreign_save_vips_target, vips_foreign_save_vips_get_type()); static int vips_foreign_save_vips_target_build(VipsObject *object) { VipsForeignSaveVips *vips = (VipsForeignSaveVips *) object; VipsForeignSaveVipsTarget *target = (VipsForeignSaveVipsTarget *) object; vips->target = target->target; g_object_ref(vips->target); return VIPS_OBJECT_CLASS(vips_foreign_save_vips_target_parent_class) ->build(object); } static void vips_foreign_save_vips_target_class_init( VipsForeignSaveVipsTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "vipssave_target"; object_class->description = _("save image to target in vips format"); object_class->build = vips_foreign_save_vips_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveVipsTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_vips_target_init(VipsForeignSaveVipsTarget *target) { } /** * vips_vipssave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write @in to @filename in VIPS format. * * ::: seealso * [ctor@Image.vipsload]. * * Returns: 0 on success, -1 on error. */ int vips_vipssave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("vipssave", ap, in, filename); va_end(ap); return result; } /** * vips_vipssave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.vipssave], but save to a target. * * Returns: 0 on success, -1 on error. */ int vips_vipssave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("vipssave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/webp2vips.c000066400000000000000000000463111516303661500204630ustar00rootroot00000000000000/* read with libwebp * * 6/8/13 * - from png2vips.c * 24/2/14 * - oops, buffer path was broken, thanks Lovell * 28/2/16 * - add @shrink * 7/11/16 * - support XMP/ICC/EXIF metadata * 18/10/17 * - sniff file type from magic number * 2/11/18 * - rework for demux API * - add animated read * 19/4/19 * - could memleak on some read errors * 24/4/19 * - fix bg handling in animations * 30/4/19 * - deprecate shrink, use scale instead, and make it a double ... this * lets us do faster and more accurate thumbnailing * 27/6/19 * - disable alpha output if all frame fill the canvas and are solid * 6/7/19 [deftomat] * - support array of delays * 14/10/19 * - revise for source IO * 27/10/21 * - disable shrink-on-load if we need subpixel accuracy in animations */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_LIBWEBP #include #include #include #include #include #include #include "pforeign.h" /* What we track during a read. */ typedef struct { VipsImage *out; VipsSource *source; /* The data we load, as a webp object. */ WebPData data; /* Load this page (frame number). */ int page; /* Load this many pages. */ int n; /* Scale-on-load factor. Use this to set frame_width. */ double scale; /* Size of each frame in input image coordinates. */ int canvas_width; int canvas_height; /* Size of each frame, in scaled output image coordinates, */ int frame_width; int frame_height; /* Size of final output image. */ int width; int height; /* TRUE if we will save the final image as RGBA. */ int alpha; /* Number of frames in file. */ int frame_count; /* Delays between frames (in milliseconds). */ int *delays; /* Parse with this. */ WebPDemuxer *demux; /* Decoder config. */ WebPDecoderConfig config; /* The current accumulated frame as a VipsImage. These are the pixels * we send to the output. It's a frame_width * frame_height memory * image. */ VipsImage *frame; /* The frame number currently in @frame. Numbered from 1, so 0 means * before the first frame. */ int frame_no; /* Iterate through the frames with this. iter.frame_num is the number * of the currently loaded frame. */ WebPIterator iter; /* How to junk the current frame when we move on. */ WebPMuxAnimDispose dispose_method; VipsRect dispose_rect; } Read; const char * vips__error_webp(VP8StatusCode code) { switch (code) { case VP8_STATUS_OK: return "VP8_STATUS_OK"; case VP8_STATUS_OUT_OF_MEMORY: return "VP8_STATUS_OUT_OF_MEMORY"; case VP8_STATUS_INVALID_PARAM: return "VP8_STATUS_INVALID_PARAM"; case VP8_STATUS_BITSTREAM_ERROR: return "VP8_STATUS_BITSTREAM_ERROR"; case VP8_STATUS_UNSUPPORTED_FEATURE: return "VP8_STATUS_UNSUPPORTED_FEATURE"; case VP8_STATUS_SUSPENDED: return "VP8_STATUS_SUSPENDED"; case VP8_STATUS_USER_ABORT: return "VP8_STATUS_USER_ABORT"; case VP8_STATUS_NOT_ENOUGH_DATA: return "VP8_STATUS_NOT_ENOUGH_DATA"; default: return ""; } } static void vips_image_paint_area(VipsImage *image, const VipsRect *r, const VipsPel *ink) { VipsRect valid = { 0, 0, image->Xsize, image->Ysize }; VipsRect ovl; vips_rect_intersectrect(r, &valid, &ovl); if (!vips_rect_isempty(&ovl)) { int ps = VIPS_IMAGE_SIZEOF_PEL(image); int ls = VIPS_IMAGE_SIZEOF_LINE(image); int ws = ovl.width * ps; VipsPel *to, *q; int x, y, z; /* We plot the first line pointwise, then memcpy() it for the * subsequent lines. We need to work for RGB and RGBA, so we * can't just write uint32s. */ to = VIPS_IMAGE_ADDR(image, ovl.left, ovl.top); q = to; for (x = 0; x < ovl.width; x++) { /* Faster than memcpy() for about ps < 20. */ for (z = 0; z < ps; z++) q[z] = ink[z]; q += ps; } q = to + ls; for (y = 1; y < ovl.height; y++) { memcpy(q, to, ws); q += ls; } } } /* Blend two guint8. */ #define BLEND(X, aX, Y, aY, scale) \ (((X * aX + Y * aY) * scale + (1 << 12)) >> 24) /* Extract R, G, B, A, assuming little-endian. */ #define getR(V) (V & 0xff) #define getG(V) ((V >> 8) & 0xff) #define getB(V) ((V >> 16) & 0xff) #define getA(V) ((V >> 24) & 0xff) /* Rebuild RGBA, assuming little-endian. */ #define setRGBA(R, G, B, A) \ (R | (G << 8) | (B << 16) | ((guint32) A << 24)) /* OVER blend of two unpremultiplied RGBA guint32 * * We assume little-endian (x86), add a byteswap before this if necessary. */ static guint32 blend_pixel(guint32 A, guint32 B) { guint8 aA = getA(A); if (aA == 0) return B; guint8 aB = getA(B); guint8 fac = (aB * (255 - aA) + 127) >> 8; guint8 aR = aA + fac; int scale = aR == 0 ? 0 : (1 << 24) / aR; guint8 rR = BLEND(getR(A), aA, getR(B), fac, scale); guint8 gR = BLEND(getG(A), aA, getG(B), fac, scale); guint8 bR = BLEND(getB(A), aA, getB(B), fac, scale); return setRGBA(rR, gR, bR, aR); } /* Blend sub into frame at left, top. */ static void vips_image_paint_image(VipsImage *frame, VipsImage *sub, int left, int top, gboolean blend) { VipsRect frame_rect = { 0, 0, frame->Xsize, frame->Ysize }; VipsRect sub_rect = { left, top, sub->Xsize, sub->Ysize }; int ps = VIPS_IMAGE_SIZEOF_PEL(frame); VipsRect ovl; g_assert(VIPS_IMAGE_SIZEOF_PEL(sub) == ps); vips_rect_intersectrect(&frame_rect, &sub_rect, &ovl); if (!vips_rect_isempty(&ovl)) { VipsPel *p, *q; int x, y; p = VIPS_IMAGE_ADDR(sub, ovl.left - left, ovl.top - top); q = VIPS_IMAGE_ADDR(frame, ovl.left, ovl.top); for (y = 0; y < ovl.height; y++) { if (blend) { guint32 *A = (guint32 *) p; guint32 *B = (guint32 *) q; for (x = 0; x < ovl.width; x++) B[x] = blend_pixel(A[x], B[x]); } else memcpy((char *) q, (char *) p, (size_t) ovl.width * ps); p += VIPS_IMAGE_SIZEOF_LINE(sub); q += VIPS_IMAGE_SIZEOF_LINE(frame); } } } int vips__iswebp_source(VipsSource *source) { const unsigned char *p; /* WebP is "RIFF xxxx WEBP" at the start, so we need 12 bytes. */ if ((p = vips_source_sniff(source, 12)) && vips_isprefix("RIFF", (char *) p) && vips_isprefix("WEBP", (char *) p + 8)) return 1; return 0; } static int read_free(Read *read) { WebPDemuxReleaseIterator(&read->iter); VIPS_UNREF(read->frame); VIPS_FREEF(WebPDemuxDelete, read->demux); WebPFreeDecBuffer(&read->config.output); VIPS_UNREF(read->source); VIPS_FREE(read->delays); VIPS_FREE(read); return 0; } static void read_close_cb(VipsImage *image, Read *read) { read_free(read); } static Read * read_new(VipsImage *out, VipsSource *source, int page, int n, double scale) { Read *read; if (!(read = VIPS_NEW(NULL, Read))) return NULL; read->out = out; read->source = source; g_object_ref(source); read->page = page; read->n = n; read->scale = scale; read->delays = NULL; read->demux = NULL; read->frame = NULL; read->dispose_method = WEBP_MUX_DISPOSE_NONE; read->frame_no = 0; /* Everything has to stay open until read has finished, unfortunately, * since webp relies on us mapping the whole source. */ g_signal_connect(out, "close", G_CALLBACK(read_close_cb), read); WebPInitDecoderConfig(&read->config); read->config.options.use_threads = 1; read->config.output.is_external_memory = 1; /* Map the whole source into memory. */ if (!(read->data.bytes = vips_source_map(source, &read->data.size))) return NULL; return read; } /* Map vips metadata names to webp names. */ const VipsWebPNames vips__webp_names[] = { { VIPS_META_ICC_NAME, "ICCP", ICCP_FLAG }, { VIPS_META_EXIF_NAME, "EXIF", EXIF_FLAG }, { VIPS_META_XMP_NAME, "XMP ", XMP_FLAG } }; const int vips__n_webp_names = VIPS_NUMBER(vips__webp_names); static int read_header(Read *read, VipsImage *out) { int flags; int i; if (!(read->demux = WebPDemux(&read->data))) { vips_error("webp", "%s", _("unable to parse image")); return -1; } flags = WebPDemuxGetI(read->demux, WEBP_FF_FORMAT_FLAGS); read->alpha = flags & ALPHA_FLAG; /* We do everything as RGBA and then, if we can, drop the alpha on * save. */ read->config.output.colorspace = MODE_RGBA; read->canvas_width = WebPDemuxGetI(read->demux, WEBP_FF_CANVAS_WIDTH); read->canvas_height = WebPDemuxGetI(read->demux, WEBP_FF_CANVAS_HEIGHT); if (flags & ANIMATION_FLAG) { int loop_count; WebPIterator iter; loop_count = WebPDemuxGetI(read->demux, WEBP_FF_LOOP_COUNT); read->frame_count = WebPDemuxGetI(read->demux, WEBP_FF_FRAME_COUNT); #ifdef DEBUG printf("webp2vips: animation\n"); printf("webp2vips: loop_count = %d\n", loop_count); printf("webp2vips: frame_count = %d\n", read->frame_count); #endif /*DEBUG*/ vips_image_set_int(out, "loop", loop_count); /* DEPRECATED "gif-loop" * * Not the correct behavior as loop=1 became gif-loop=0 * but we want to keep the old behavior untouched! */ vips_image_set_int(out, "gif-loop", loop_count == 0 ? 0 : loop_count - 1); if (WebPDemuxGetFrame(read->demux, 1, &iter)) { int i; read->delays = (int *) g_malloc0(read->frame_count * sizeof(int)); for (i = 0; i < read->frame_count; i++) read->delays[i] = 40; do { g_assert(iter.frame_num >= 1 && iter.frame_num <= read->frame_count); read->delays[iter.frame_num - 1] = iter.duration; /* We need the alpha in an animation if: * - any frame has transparent pixels * - any frame doesn't fill the whole canvas. */ if (iter.has_alpha || iter.width != read->canvas_width || iter.height != read->canvas_height) read->alpha = TRUE; /* We must disable shrink-on-load if any frame * does not fill the whole canvas. We won't be * able to shrink-on-load it to the exact * position in a downsized canvas. */ if (iter.width != read->canvas_width || iter.height != read->canvas_height) read->scale = 1.0; } while (WebPDemuxNextFrame(&iter)); vips_image_set_array_int(out, "delay", read->delays, read->frame_count); /* webp uses ms for delays, gif uses centiseconds. */ vips_image_set_int(out, "gif-delay", rint(read->delays[0] / 10.0)); } WebPDemuxReleaseIterator(&iter); if (read->n == -1) read->n = read->frame_count - read->page; if (read->page < 0 || read->n <= 0 || read->page + read->n > read->frame_count) { vips_error("webp", "%s", _("bad page number")); return -1; } /* Note that n-pages is the number of pages in the original, * not the number of pages in the image we are writing. */ vips_image_set_int(out, VIPS_META_N_PAGES, read->frame_count); } /* We round-to-nearest cf. pdfload etc. */ read->frame_width = rint(read->canvas_width * read->scale); read->frame_height = rint(read->canvas_height * read->scale); #ifdef DEBUG printf("webp2vips: canvas_width = %d\n", read->canvas_width); printf("webp2vips: canvas_height = %d\n", read->canvas_height); printf("webp2vips: frame_width = %d\n", read->frame_width); printf("webp2vips: frame_height = %d\n", read->frame_height); #endif /*DEBUG*/ if (flags & ANIMATION_FLAG) { /* Only set page-height if we have more than one page, or * this could accidentally turn into an animated image later. */ if (read->n > 1) vips_image_set_int(out, VIPS_META_PAGE_HEIGHT, read->frame_height); read->width = read->frame_width; read->height = read->n * read->frame_height; } else { read->width = read->frame_width; read->height = read->frame_height; read->frame_count = 1; } /* height can be huge if this is an animated webp image. */ if (read->width <= 0 || read->height <= 0 || read->width > 0x3FFF || read->height >= VIPS_MAX_COORD || read->frame_width <= 0 || read->frame_height <= 0 || read->frame_width > 0x3FFF || read->frame_height > 0x3FFF) { vips_error("webp", "%s", _("bad image dimensions")); return -1; } for (i = 0; i < vips__n_webp_names; i++) { const char *vips = vips__webp_names[i].vips; const char *webp = vips__webp_names[i].webp; if (flags & vips__webp_names[i].flags) { WebPChunkIterator iter; WebPDemuxGetChunk(read->demux, webp, 1, &iter); vips_image_set_blob_copy(out, vips, iter.chunk.bytes, iter.chunk.size); WebPDemuxReleaseChunkIterator(&iter); } } /* The canvas is always RGBA, we drop alpha to RGB on output if we * can. */ read->frame = vips_image_new_memory(); vips_image_init_fields(read->frame, read->frame_width, read->frame_height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); if (vips_image_pipelinev(read->frame, VIPS_DEMAND_STYLE_THINSTRIP, NULL) || vips_image_write_prepare(read->frame)) return -1; vips_image_init_fields(out, read->width, read->height, read->alpha ? 4 : 3, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, NULL)) return -1; VIPS_SETSTR(out->filename, vips_connection_filename(VIPS_CONNECTION(read->source))); if (!WebPDemuxGetFrame(read->demux, 1, &read->iter)) { vips_error("webp", "%s", _("unable to loop through frames")); return -1; } return 0; } /* Read a single frame -- a width * height block of pixels. This will get * blended into the accumulator at some offset. */ static VipsImage * read_frame(Read *read, int width, int height, const guint8 *data, size_t length) { VipsImage *frame; #ifdef DEBUG printf("read_frame:\n"); #endif /*DEBUG*/ frame = vips_image_new_memory(); vips_image_init_fields(frame, width, height, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0); if (vips_image_pipelinev(frame, VIPS_DEMAND_STYLE_THINSTRIP, NULL) || vips_image_write_prepare(frame)) { g_object_unref(frame); return NULL; } read->config.output.u.RGBA.rgba = VIPS_IMAGE_ADDR(frame, 0, 0); read->config.output.u.RGBA.stride = VIPS_IMAGE_SIZEOF_LINE(frame); read->config.output.u.RGBA.size = VIPS_IMAGE_SIZEOF_IMAGE(frame); if (read->scale != 1.0) { read->config.options.use_scaling = 1; read->config.options.scaled_width = width; read->config.options.scaled_height = height; } if (WebPDecode(data, length, &read->config) != VP8_STATUS_OK) { g_object_unref(frame); vips_error("webp2vips", "%s", _("unable to read pixels")); return NULL; } return frame; } static int read_next_frame(Read *read) { VipsImage *frame; VipsRect area; #ifdef DEBUG printf("read_next_frame:\n"); #endif /*DEBUG*/ /* Area of this frame, in output image coordinates. We must rint(), * since we need the same rules as the overall image scale, or we'll * sometimes have missing pixels on edges. */ area.left = rint(read->iter.x_offset * read->scale); area.top = rint(read->iter.y_offset * read->scale); area.width = rint(read->iter.width * read->scale); area.height = rint(read->iter.height * read->scale); /* Dispose from the previous frame. */ if (read->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { /* We must clear the pixels occupied by the previous webp * frame (not the whole of the read frame) to 0 (transparent). * * We do not clear to WEBP_FF_BACKGROUND_COLOR. That's only * used to composite down to RGB. Perhaps we * should attach background as metadata. */ guint32 zero = 0; vips_image_paint_area(read->frame, &read->dispose_rect, (VipsPel *) &zero); } /* Note this frame's dispose for next time. */ read->dispose_method = read->iter.dispose_method; read->dispose_rect = area; #ifdef DEBUG printf("webp2vips: frame_num = %d\n", read->iter.frame_num); printf(" left = %d\n", area.left); printf(" top = %d\n", area.top); printf(" width = %d\n", area.width); printf(" height = %d\n", area.height); printf(" duration = %d\n", read->iter.duration); printf(" dispose = "); if (read->iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) printf("clear to background\n"); else printf("none\n"); printf(" has_alpha = %d\n", read->iter.has_alpha); printf(" blend_method = "); if (read->iter.blend_method == WEBP_MUX_BLEND) printf("blend with previous\n"); else printf("don't blend\n"); #endif /*DEBUG*/ if (!(frame = read_frame(read, area.width, area.height, read->iter.fragment.bytes, read->iter.fragment.size))) return -1; /* Now blend or copy the new pixels into our accumulator. */ vips_image_paint_image(read->frame, frame, area.left, area.top, read->iter.frame_num > 1 && read->iter.blend_method == WEBP_MUX_BLEND); g_object_unref(frame); /* If there's another frame, move on. */ if (read->iter.frame_num < read->frame_count) { if (!WebPDemuxNextFrame(&read->iter)) { vips_error("webp2vips", "%s", _("not enough frames")); return -1; } } return 0; } static int read_webp_generate(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; Read *read = (Read *) a; /* iter.frame_num numbers from 1. */ int frame = 1 + r->top / read->frame_height + read->page; int line = r->top % read->frame_height; #ifdef DEBUG_VERBOSE printf("read_webp_generate: line %d\n", r->top); #endif /*DEBUG_VERBOSE*/ g_assert(r->height == 1); while (read->frame_no < frame) { if (read_next_frame(read)) return -1; read->frame_no += 1; } if (out_region->im->Bands == 4) memcpy(VIPS_REGION_ADDR(out_region, 0, r->top), VIPS_IMAGE_ADDR(read->frame, 0, line), VIPS_IMAGE_SIZEOF_LINE(read->frame)); else { int x; VipsPel *p; VipsPel *q; /* We know that alpha is solid, so we can just drop the 4th * band. */ p = VIPS_IMAGE_ADDR(read->frame, 0, line); q = VIPS_REGION_ADDR(out_region, 0, r->top); for (x = 0; x < r->width; x++) { q[0] = p[0]; q[1] = p[1]; q[2] = p[2]; q += 3; p += 4; } } return 0; } static int read_image(Read *read, VipsImage *out) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 2); /* Make the output pipeline. */ t[0] = vips_image_new(); if (read_header(read, t[0])) return -1; if (vips_image_generate(t[0], NULL, read_webp_generate, NULL, read, NULL) || vips_sequential(t[0], &t[1], NULL) || vips_image_write(t[1], out)) return -1; return 0; } int vips__webp_read_header_source(VipsSource *source, VipsImage *out, int page, int n, double scale) { Read *read; if (!(read = read_new(out, source, page, n, scale)) || read_header(read, out)) return -1; return 0; } int vips__webp_read_source(VipsSource *source, VipsImage *out, int page, int n, double scale) { Read *read; if (!(read = read_new(out, source, page, n, scale)) || read_image(read, out)) return -1; return 0; } #endif /*HAVE_LIBWEBP*/ libvips-8.18.2/libvips/foreign/webpload.c000066400000000000000000000326001516303661500203330ustar00rootroot00000000000000/* load webp images * * 6/8/13 * - from pngload.c * 28/2/16 * - add @shrink * 1/11/18 * - add @page, @n * 30/4/19 * - deprecate @shrink, use @scale instead */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pforeign.h" #ifdef HAVE_LIBWEBP typedef struct _VipsForeignLoadWebp { VipsForeignLoad parent_object; /* Set by subclasses. */ VipsSource *source; /* Load this page (frame number). */ int page; /* Load this many pages. */ int n; /* Scale by this much during load. */ double scale; /* Old and deprecated scaling path. */ int shrink; } VipsForeignLoadWebp; typedef VipsForeignLoadClass VipsForeignLoadWebpClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignLoadWebp, vips_foreign_load_webp, VIPS_TYPE_FOREIGN_LOAD); static void vips_foreign_load_webp_dispose(GObject *gobject) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) gobject; VIPS_UNREF(webp->source); G_OBJECT_CLASS(vips_foreign_load_webp_parent_class)->dispose(gobject); } static int vips_foreign_load_webp_build(VipsObject *object) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) object; /* BC for the old API. */ if (!vips_object_argument_isset(VIPS_OBJECT(webp), "scale") && vips_object_argument_isset(VIPS_OBJECT(webp), "shrink") && webp->shrink != 0) webp->scale = 1.0 / webp->shrink; // FIXME: Invalidates operation cache return VIPS_OBJECT_CLASS(vips_foreign_load_webp_parent_class) ->build(object); } static VipsForeignFlags vips_foreign_load_webp_get_flags(VipsForeignLoad *load) { return 0; } static VipsForeignFlags vips_foreign_load_webp_get_flags_filename(const char *filename) { return 0; } static int vips_foreign_load_webp_header(VipsForeignLoad *load) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load; if (vips__webp_read_header_source(webp->source, load->out, webp->page, webp->n, webp->scale)) return -1; return 0; } static int vips_foreign_load_webp_load(VipsForeignLoad *load) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) load; if (vips__webp_read_source(webp->source, load->real, webp->page, webp->n, webp->scale)) return -1; return 0; } static void vips_foreign_load_webp_class_init(VipsForeignLoadWebpClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->dispose = vips_foreign_load_webp_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpload_base"; object_class->description = _("load webp"); object_class->build = vips_foreign_load_webp_build; /* We are fast at is_a(), so high priority. */ foreign_class->priority = 200; load_class->get_flags_filename = vips_foreign_load_webp_get_flags_filename; load_class->get_flags = vips_foreign_load_webp_get_flags; load_class->header = vips_foreign_load_webp_header; load_class->load = vips_foreign_load_webp_load; VIPS_ARG_INT(class, "page", 20, _("Page"), _("First page to load"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadWebp, page), 0, 100000, 0); VIPS_ARG_INT(class, "n", 21, _("n"), _("Number of pages to load, -1 for all"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadWebp, n), -1, 100000, 1); VIPS_ARG_DOUBLE(class, "scale", 22, _("Scale"), _("Factor to scale by"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignLoadWebp, scale), 0.0, 1024.0, 1.0); VIPS_ARG_INT(class, "shrink", 23, _("Shrink"), _("Shrink factor on load"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignLoadWebp, shrink), 1, 1024, 1); } static void vips_foreign_load_webp_init(VipsForeignLoadWebp *webp) { webp->n = 1; webp->shrink = 1; webp->scale = 1.0; } typedef struct _VipsForeignLoadWebpSource { VipsForeignLoadWebp parent_object; VipsSource *source; } VipsForeignLoadWebpSource; typedef VipsForeignLoadWebpClass VipsForeignLoadWebpSourceClass; G_DEFINE_TYPE(VipsForeignLoadWebpSource, vips_foreign_load_webp_source, vips_foreign_load_webp_get_type()); static int vips_foreign_load_webp_source_build(VipsObject *object) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) object; VipsForeignLoadWebpSource *source = (VipsForeignLoadWebpSource *) object; if (source->source) { webp->source = source->source; g_object_ref(webp->source); } return VIPS_OBJECT_CLASS(vips_foreign_load_webp_source_parent_class) ->build(object); } static void vips_foreign_load_webp_source_class_init( VipsForeignLoadWebpSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpload_source"; object_class->description = _("load webp from source"); object_class->build = vips_foreign_load_webp_source_build; operation_class->flags |= VIPS_OPERATION_NOCACHE; load_class->is_a_source = vips__iswebp_source; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadWebpSource, source), VIPS_TYPE_SOURCE); } static void vips_foreign_load_webp_source_init(VipsForeignLoadWebpSource *buffer) { } typedef struct _VipsForeignLoadWebpFile { VipsForeignLoadWebp parent_object; /* Filename for load. */ char *filename; } VipsForeignLoadWebpFile; typedef VipsForeignLoadWebpClass VipsForeignLoadWebpFileClass; G_DEFINE_TYPE(VipsForeignLoadWebpFile, vips_foreign_load_webp_file, vips_foreign_load_webp_get_type()); static int vips_foreign_load_webp_file_build(VipsObject *object) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) object; VipsForeignLoadWebpFile *file = (VipsForeignLoadWebpFile *) object; if (file->filename && !(webp->source = vips_source_new_from_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_webp_file_parent_class) ->build(object); } static gboolean vips_foreign_load_webp_file_is_a(const char *filename) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_file(filename))) return FALSE; result = vips__iswebp_source(source); VIPS_UNREF(source); return result; } const char *vips__webp_suffs[] = { ".webp", NULL }; static void vips_foreign_load_webp_file_class_init(VipsForeignLoadWebpFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpload"; object_class->description = _("load webp from file"); object_class->build = vips_foreign_load_webp_file_build; foreign_class->suffs = vips__webp_suffs; load_class->is_a = vips_foreign_load_webp_file_is_a; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadWebpFile, filename), NULL); } static void vips_foreign_load_webp_file_init(VipsForeignLoadWebpFile *file) { } typedef struct _VipsForeignLoadWebpBuffer { VipsForeignLoadWebp parent_object; /* Load from a buffer. */ VipsBlob *blob; } VipsForeignLoadWebpBuffer; typedef VipsForeignLoadWebpClass VipsForeignLoadWebpBufferClass; G_DEFINE_TYPE(VipsForeignLoadWebpBuffer, vips_foreign_load_webp_buffer, vips_foreign_load_webp_get_type()); static int vips_foreign_load_webp_buffer_build(VipsObject *object) { VipsForeignLoadWebp *webp = (VipsForeignLoadWebp *) object; VipsForeignLoadWebpBuffer *buffer = (VipsForeignLoadWebpBuffer *) object; if (buffer->blob && !(webp->source = vips_source_new_from_memory( VIPS_AREA(buffer->blob)->data, VIPS_AREA(buffer->blob)->length))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_load_webp_buffer_parent_class) ->build(object); } static gboolean vips_foreign_load_webp_buffer_is_a_buffer(const void *buf, size_t len) { VipsSource *source; gboolean result; if (!(source = vips_source_new_from_memory(buf, len))) return FALSE; result = vips__iswebp_source(source); VIPS_UNREF(source); return result; } static void vips_foreign_load_webp_buffer_class_init( VipsForeignLoadWebpBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpload_buffer"; object_class->description = _("load webp from buffer"); object_class->build = vips_foreign_load_webp_buffer_build; load_class->is_a_buffer = vips_foreign_load_webp_buffer_is_a_buffer; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignLoadWebpBuffer, blob), VIPS_TYPE_BLOB); } static void vips_foreign_load_webp_buffer_init(VipsForeignLoadWebpBuffer *buffer) { } #endif /*HAVE_LIBWEBP*/ /** * vips_webpload: * @filename: file to load * @out: (out): decompressed image * @...: `NULL`-terminated list of optional named arguments * * Read a WebP file into a VIPS image. * * Use @page to select a page to render, numbering from zero. * * Use @n to select the number of pages to render. The default is 1. Pages are * rendered in a vertical column, with each individual page aligned to the * left. Set to -1 to mean "until the end of the document". Use [method@Image.grid] * to change page layout. * * Use @scale to specify a scale-on-load factor. For example, 2.0 to double * the size on load. Animated webp images don't support shrink-on-load, so a * further resize may be necessary. * * The loader supports ICC, EXIF and XMP metadata. * * ::: tip "Optional arguments" * * @page: `gint`, page (frame) to read * * @n: `gint`, load this many pages * * @scale: `gdouble`, scale by this much on load * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, -1 on error. */ int vips_webpload(const char *filename, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("webpload", ap, filename, out); va_end(ap); return result; } /** * vips_webpload_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Read a WebP-formatted memory block into a VIPS image. Exactly as * [ctor@Image.webpload], but read from a memory buffer. * * You must not free the buffer while @out is active. The * [signal@Object::postclose] signal on @out is a good place to free. * * ::: tip "Optional arguments" * * @page: `gint`, page (frame) to read * * @n: `gint`, load this many pages * * @scale: `gdouble`, scale by this much on load * * ::: seealso * [ctor@Image.webpload] * * Returns: 0 on success, -1 on error. */ int vips_webpload_buffer(void *buf, size_t len, VipsImage **out, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, out); result = vips_call_split("webpload_buffer", ap, blob, out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } /** * vips_webpload_source: * @source: source to load from * @out: (out): image to write * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.webpload], but read from a source. * * ::: tip "Optional arguments" * * @page: `gint`, page (frame) to read * * @n: `gint`, load this many pages * * @scale: `gdouble`, scale by this much on load * * ::: seealso * [ctor@Image.webpload] * * Returns: 0 on success, -1 on error. */ int vips_webpload_source(VipsSource *source, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("webpload_source", ap, source, out); va_end(ap); return result; } libvips-8.18.2/libvips/foreign/webpsave.c000066400000000000000000001114141516303661500203530ustar00rootroot00000000000000/* save to webp * * 24/11/11 * - wrap a class around the webp writer * 6/8/13 * - from vips2jpeg.c * 31/5/16 * - buffer write ignored lossless, thanks aaron42net * 2/5/16 Felix Bünemann * - used advanced encoding API, expose controls * 8/11/16 * - add metadata write * 29/10/18 * - add animated webp support * 29/10/18 * - target libwebp 0.5+ and remove some ifdefs * - add animated webp write * - use libwebpmux instead of our own thing, phew * 15/1/19 lovell * - add @effort * 6/7/19 [deftomat] * - support array of delays * 8/7/19 * - set loop even if we strip * 14/10/19 * - revise for target IO * 18/7/20 * - add @profile param to match tiff, jpg, etc. * 30/7/21 * - rename "reduction_effort" as "effort" * 7/9/22 dloebl * - switch to sink_disc */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pforeign.h" #ifdef HAVE_LIBWEBP #include #include #include typedef int (*webp_import)(WebPPicture *picture, const uint8_t *rgb, int stride); typedef enum _VipsForeignSaveWebpMode { VIPS_FOREIGN_SAVE_WEBP_MODE_SINGLE, VIPS_FOREIGN_SAVE_WEBP_MODE_ANIM } VipsForeignSaveWebpMode; typedef struct _VipsForeignSaveWebp { VipsForeignSave parent_object; VipsTarget *target; /* Animated or single image write mode? * Important, because we use a different API * for animated WebP write. */ VipsForeignSaveWebpMode mode; int timestamp_ms; /* Quality factor. */ int Q; /* Turn on lossless encode. */ gboolean lossless; /* Preserve color values from transparent pixels. */ gboolean exact; /* Lossy compression preset. */ VipsForeignWebpPreset preset; /* Enable smart chroma subsampling. */ gboolean smart_subsample; /* Enable smart deblock filter adjusting. */ gboolean smart_deblock; /* Use preprocessing in lossless mode. */ gboolean near_lossless; /* Alpha quality. */ int alpha_q; /* Level of CPU effort to reduce file size. */ int effort; /* If non-zero, set the desired target size in bytes. * Takes precedence over the 'Q' parameter. */ int target_size; /* Number of entropy-analysis passes (in [1..10]). * The default value of 1 is appropriate for most cases. * If target_size is set, this must be set to a suitably large value. */ int passes; /* Animated webp options. */ int gif_delay; int *delay; int delay_length; /* Attempt to minimise size */ gboolean min_size; /* Allow mixed encoding (might reduce file size) */ gboolean mixed; /* Min between key frames. */ int kmin; /* Max between keyframes. */ int kmax; WebPConfig config; /* Output is written here. We can only support memory write, since we * handle metadata. */ WebPMemoryWriter memory_writer; /* Write animated webp here. */ WebPAnimEncoder *enc; /* Add metadata with this. */ WebPMux *mux; /* The current y position in the frame and the current page index. */ int write_y; int page_number; /* VipsRegion is not always contiguous, but we need contiguous RGB(A) * for libwebp. We need to copy each frame to a local buffer. */ VipsPel *frame_bytes; } VipsForeignSaveWebp; typedef VipsForeignSaveClass VipsForeignSaveWebpClass; G_DEFINE_ABSTRACT_TYPE(VipsForeignSaveWebp, vips_foreign_save_webp, VIPS_TYPE_FOREIGN_SAVE); static int vips_foreign_save_webp_progress_hook(int percent, const WebPPicture *picture) { VipsImage *in = (VipsImage *) picture->user_data; /* Trigger any eval callbacks on the image and check if we need to abort * the WebP encoding. */ vips_image_eval(in, VIPS_IMAGE_N_PELS(in)); /* Abort WebP encoding if requested. */ if (vips_image_iskilled(in)) return 0; return 1; } static void vips_foreign_save_webp_unset(VipsForeignSaveWebp *webp) { WebPMemoryWriterClear(&webp->memory_writer); VIPS_FREEF(WebPAnimEncoderDelete, webp->enc); VIPS_FREEF(WebPMuxDelete, webp->mux); } static void vips_foreign_save_webp_dispose(GObject *gobject) { VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) gobject; vips_foreign_save_webp_unset(webp); VIPS_UNREF(webp->target); VIPS_FREE(webp->frame_bytes); G_OBJECT_CLASS(vips_foreign_save_webp_parent_class)->dispose(gobject); } static gboolean vips_foreign_save_webp_pic_init(VipsForeignSaveWebp *webp, WebPPicture *pic) { VipsForeignSave *save = (VipsForeignSave *) webp; if (!WebPPictureInit(pic)) { vips_error("webpsave", "%s", _("picture version error")); return FALSE; } pic->writer = WebPMemoryWrite; pic->custom_ptr = (void *) &webp->memory_writer; pic->progress_hook = vips_foreign_save_webp_progress_hook; pic->user_data = (void *) save->in; /* Smart subsampling needs use_argb because it is applied during * RGB to YUV conversion. */ pic->use_argb = webp->lossless || webp->near_lossless || webp->smart_subsample; return TRUE; } /* Write a VipsImage into an uninitialised pic. */ static int vips_foreign_save_webp_write_webp_image(VipsForeignSaveWebp *webp, const VipsPel *imagedata, WebPPicture *pic) { VipsForeignSave *save = (VipsForeignSave *) webp; int page_height = vips_image_get_page_height(save->ready); webp_import import; if (!vips_foreign_save_webp_pic_init(webp, pic)) return -1; pic->width = save->ready->Xsize; pic->height = page_height; if (save->ready->Bands == 4) import = WebPPictureImportRGBA; else import = WebPPictureImportRGB; if (!import(pic, imagedata, save->ready->Xsize * save->ready->Bands)) { WebPPictureFree(pic); vips_error("webpsave", "%s", _("picture memory error")); return -1; } return 0; } static int vips_foreign_save_webp_get_delay(VipsForeignSaveWebp *webp, int page_number) { int delay; if (webp->delay && page_number < webp->delay_length) delay = webp->delay[page_number]; else // the old gif delay field was in centiseconds, so convert to ms delay = webp->gif_delay * 10; /* Force frames with a small or no duration to 100ms for consistency * with web browsers and other transcoding tools. */ return delay <= 10 ? 100 : delay; } /* We have a complete frame -- write! */ static int vips_foreign_save_webp_write_frame(VipsForeignSaveWebp *webp) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(webp); WebPPicture pic; if (vips_foreign_save_webp_write_webp_image(webp, webp->frame_bytes, &pic)) return -1; /* Animated write */ if (webp->mode == VIPS_FOREIGN_SAVE_WEBP_MODE_ANIM) { if (!WebPAnimEncoderAdd(webp->enc, &pic, webp->timestamp_ms, &webp->config)) { WebPPictureFree(&pic); vips_error(class->nickname, "%s", _("anim add error")); return -1; } /* Adjust current timestamp */ webp->timestamp_ms += vips_foreign_save_webp_get_delay(webp, webp->page_number); } else { /* Single image write */ if (!WebPEncode(&webp->config, &pic)) { WebPPictureFree(&pic); vips_error("webpsave", "%s", _("unable to encode")); return -1; } } WebPPictureFree(&pic); return 0; } /* Another chunk of pixels have arrived from the pipeline. Add to frame, and * if the frame completes, compress and write to the target. */ static int vips_foreign_save_webp_sink_disc(VipsRegion *region, VipsRect *area, void *a) { VipsForeignSave *save = (VipsForeignSave *) a; VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) a; int page_height = vips_image_get_page_height(save->ready); /* Write the new pixels into the frame. */ for (int i = 0; i < area->height; i++) { memcpy(webp->frame_bytes + area->width * webp->write_y * save->ready->Bands, VIPS_REGION_ADDR(region, 0, area->top + i), (size_t) area->width * save->ready->Bands); webp->write_y += 1; /* If we've filled the frame, write and move it down. */ if (webp->write_y == page_height) { if (vips_foreign_save_webp_write_frame(webp)) return -1; webp->write_y = 0; webp->page_number += 1; } } return 0; } static WebPPreset get_preset(VipsForeignWebpPreset preset) { switch (preset) { case VIPS_FOREIGN_WEBP_PRESET_DEFAULT: return WEBP_PRESET_DEFAULT; case VIPS_FOREIGN_WEBP_PRESET_PICTURE: return WEBP_PRESET_PICTURE; case VIPS_FOREIGN_WEBP_PRESET_PHOTO: return WEBP_PRESET_PHOTO; case VIPS_FOREIGN_WEBP_PRESET_DRAWING: return WEBP_PRESET_DRAWING; case VIPS_FOREIGN_WEBP_PRESET_ICON: return WEBP_PRESET_ICON; case VIPS_FOREIGN_WEBP_PRESET_TEXT: return WEBP_PRESET_TEXT; default: g_assert_not_reached(); } /* Keep -Wall happy. */ return -1; } static void vips_webp_set_count(VipsForeignSaveWebp *webp, int loop_count) { uint32_t features; if (WebPMuxGetFeatures(webp->mux, &features) == WEBP_MUX_OK && (features & ANIMATION_FLAG)) { WebPMuxAnimParams params; if (WebPMuxGetAnimationParams(webp->mux, ¶ms) == WEBP_MUX_OK) { params.loop_count = loop_count; WebPMuxSetAnimationParams(webp->mux, ¶ms); } } } static int vips_webp_set_chunk(VipsForeignSaveWebp *webp, const char *webp_name, const void *data, size_t length) { WebPData chunk; chunk.bytes = data; chunk.size = length; if (WebPMuxSetChunk(webp->mux, webp_name, &chunk, 1) != WEBP_MUX_OK) { vips_error("webpsave", "%s", _("chunk add error")); return -1; } return 0; } static int vips_webp_add_original_meta(VipsForeignSaveWebp *webp) { VipsForeignSave *save = (VipsForeignSave *) webp; for (int i = 0; i < vips__n_webp_names; i++) { const char *vips_name = vips__webp_names[i].vips; const char *webp_name = vips__webp_names[i].webp; if (g_str_equal(vips_name, VIPS_META_ICC_NAME)) continue; if (vips_image_get_typeof(save->ready, vips_name)) { const void *data; size_t length; if (vips_image_get_blob(save->ready, vips_name, &data, &length) || vips_webp_set_chunk(webp, webp_name, data, length)) return -1; } } return 0; } static const char * vips_webp_get_webp_name(const char *vips_name) { for (int i = 0; i < vips__n_webp_names; i++) if (g_str_equal(vips_name, vips__webp_names[i].vips)) return vips__webp_names[i].webp; return ""; } static int vips_webp_add_icc(VipsForeignSaveWebp *webp, const void *profile, size_t length) { const char *webp_name = vips_webp_get_webp_name(VIPS_META_ICC_NAME); if (vips_webp_set_chunk(webp, webp_name, profile, length)) return -1; return 0; } static int vips_webp_add_custom_icc(VipsForeignSaveWebp *webp, const char *profile) { VipsBlob *blob; if (vips_profile_load(profile, &blob, NULL)) return -1; if (blob) { size_t length; const void *data = vips_blob_get(blob, &length); if (vips_webp_add_icc(webp, data, length)) { vips_area_unref((VipsArea *) blob); return -1; } vips_area_unref((VipsArea *) blob); } return 0; } static int vips_webp_add_original_icc(VipsForeignSaveWebp *webp) { VipsForeignSave *save = (VipsForeignSave *) webp; const void *data; size_t length; if (vips_image_get_blob(save->ready, VIPS_META_ICC_NAME, &data, &length)) return -1; vips_webp_add_icc(webp, data, length); return 0; } static int vips_webp_add_metadata(VipsForeignSaveWebp *webp) { VipsForeignSave *save = (VipsForeignSave *) webp; WebPData data; data.bytes = webp->memory_writer.mem; data.size = webp->memory_writer.size; /* Parse what we have. */ if (!(webp->mux = WebPMuxCreate(&data, 1))) { vips_error("webpsave", "%s", _("mux error")); return -1; } if (vips_image_get_typeof(save->ready, "loop")) { int loop; if (vips_image_get_int(save->ready, "loop", &loop)) return -1; vips_webp_set_count(webp, loop); } else if (vips_image_get_typeof(save->ready, "gif-loop")) { /* DEPRECATED "gif-loop" */ int gif_loop; if (vips_image_get_int(save->ready, "gif-loop", &gif_loop)) return -1; vips_webp_set_count(webp, gif_loop == 0 ? 0 : gif_loop + 1); } /* Metadata */ if (vips_webp_add_original_meta(webp)) return -1; /* A profile supplied as an argument overrides an embedded * profile. */ if (save->profile) { if (vips_webp_add_custom_icc(webp, save->profile)) return -1; } else if (vips_image_get_typeof(save->ready, VIPS_META_ICC_NAME)) { if (vips_webp_add_original_icc(webp)) return -1; } if (WebPMuxAssemble(webp->mux, &data) != WEBP_MUX_OK) { vips_error("webpsave", "%s", _("mux error")); return -1; } /* Free old stuff, reinit with new stuff. */ WebPMemoryWriterClear(&webp->memory_writer); webp->memory_writer.mem = (uint8_t *) data.bytes; webp->memory_writer.size = data.size; return 0; } static int vips_foreign_save_webp_init_config(VipsForeignSaveWebp *webp) { /* Init WebP config. */ WebPMemoryWriterInit(&webp->memory_writer); if (!WebPConfigInit(&webp->config)) { vips_error("webpsave", "%s", _("config version error")); return -1; } /* These presets are only for lossy compression. There seems to be * separate API for lossless or near-lossless, see * WebPConfigLosslessPreset(). */ if (!(webp->lossless || webp->near_lossless) && !WebPConfigPreset(&webp->config, get_preset(webp->preset), webp->Q)) { vips_error("webpsave", "%s", _("config version error")); return -1; } webp->config.lossless = webp->lossless || webp->near_lossless; webp->config.exact = webp->exact; webp->config.alpha_quality = webp->alpha_q; webp->config.method = webp->effort; webp->config.target_size = webp->target_size; webp->config.pass = webp->passes; if (webp->lossless) webp->config.quality = webp->Q; if (webp->near_lossless) webp->config.near_lossless = webp->Q; if (webp->smart_subsample) webp->config.use_sharp_yuv = 1; if (webp->smart_deblock) webp->config.autofilter = 1; if (!WebPValidateConfig(&webp->config)) { vips_error("webpsave", "%s", _("invalid configuration")); return -1; } return 0; } static int vips_foreign_save_webp_init_anim_enc(VipsForeignSaveWebp *webp) { VipsForeignSave *save = (VipsForeignSave *) webp; int page_height = vips_image_get_page_height(save->ready); WebPAnimEncoderOptions anim_config; /* Init config for animated write */ if (!WebPAnimEncoderOptionsInit(&anim_config)) { vips_error("webpsave", "%s", _("config version error")); return -1; } anim_config.minimize_size = webp->min_size; anim_config.allow_mixed = webp->mixed; anim_config.kmin = webp->kmin; anim_config.kmax = webp->kmax; webp->enc = WebPAnimEncoderNew(save->ready->Xsize, page_height, &anim_config); if (!webp->enc) { vips_error("webpsave", "%s", _("unable to init animation")); return -1; } /* Get delay array * * There might just be the old gif-delay field. This is centiseconds. * New images have an array of ints giving millisecond durations. */ webp->gif_delay = 10; if (vips_image_get_typeof(save->ready, "gif-delay") && vips_image_get_int(save->ready, "gif-delay", &webp->gif_delay)) return -1; webp->delay = NULL; if (vips_image_get_typeof(save->ready, "delay") && vips_image_get_array_int(save->ready, "delay", &webp->delay, &webp->delay_length)) return -1; return 0; } static int vips_foreign_save_webp_finish_anim(VipsForeignSaveWebp *webp) { WebPData webp_data; /* Closes animated encoder and adds last frame delay. */ if (!WebPAnimEncoderAdd(webp->enc, NULL, webp->timestamp_ms, NULL)) { vips_error("webpsave", "%s", _("anim close error")); return -1; } if (!WebPAnimEncoderAssemble(webp->enc, &webp_data)) { vips_error("webpsave", "%s", _("anim build error")); return -1; } /* Terrible. This will only work if the output buffer is currently * empty. */ if (webp->memory_writer.mem != NULL) { vips_error("webpsave", "%s", _("internal error")); return -1; } webp->memory_writer.mem = (uint8_t *) webp_data.bytes; webp->memory_writer.size = webp_data.size; return 0; } static int vips_foreign_save_webp_build(VipsObject *object) { VipsForeignSave *save = (VipsForeignSave *) object; VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object; int page_height; if (VIPS_OBJECT_CLASS(vips_foreign_save_webp_parent_class)->build(object)) return -1; page_height = vips_image_get_page_height(save->ready); if (save->ready->Xsize > 16383 || page_height > 16383) { vips_error("webpsave", _("image too large")); return -1; } /* RGB(A) frame as a contiguous buffer. */ size_t frame_size = (size_t) save->ready->Bands * save->ready->Xsize * page_height; webp->frame_bytes = g_try_malloc(frame_size); if (webp->frame_bytes == NULL) { vips_error("webpsave", _("failed to allocate %zu bytes"), frame_size); return -1; } if (!vips_object_argument_isset(object, "passes") && vips_object_argument_isset(object, "target_size")) webp->passes = 3; /* Init generic WebP config */ if (vips_foreign_save_webp_init_config(webp)) return -1; /* Determine the write mode (single image or animated write) */ webp->mode = VIPS_FOREIGN_SAVE_WEBP_MODE_SINGLE; if (page_height != save->ready->Ysize) webp->mode = VIPS_FOREIGN_SAVE_WEBP_MODE_ANIM; /* Init config for animated write (if necessary) */ if (webp->mode == VIPS_FOREIGN_SAVE_WEBP_MODE_ANIM) if (vips_foreign_save_webp_init_anim_enc(webp)) return -1; if (vips_sink_disc(save->ready, vips_foreign_save_webp_sink_disc, webp)) return -1; /* Finish animated write */ if (webp->mode == VIPS_FOREIGN_SAVE_WEBP_MODE_ANIM) if (vips_foreign_save_webp_finish_anim(webp)) return -1; if (vips_webp_add_metadata(webp)) return -1; if (vips_target_write(webp->target, webp->memory_writer.mem, webp->memory_writer.size)) return -1; if (vips_target_end(webp->target)) return -1; vips_foreign_save_webp_unset(webp); return 0; } static const char *vips__save_webp_suffs[] = { ".webp", NULL }; #define UC VIPS_FORMAT_UCHAR /* Type promotion for save ... just always go to uchar. */ static VipsBandFormat bandfmt_webp[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC }; static void vips_foreign_save_webp_class_init(VipsForeignSaveWebpClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsForeignClass *foreign_class = (VipsForeignClass *) class; VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class; gobject_class->dispose = vips_foreign_save_webp_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpsave_base"; object_class->description = _("save as WebP"); object_class->build = vips_foreign_save_webp_build; foreign_class->suffs = vips__save_webp_suffs; save_class->saveable = VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA; save_class->format_table = bandfmt_webp; VIPS_ARG_INT(class, "Q", 10, _("Q"), _("Q factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, Q), 0, 100, 75); VIPS_ARG_BOOL(class, "lossless", 11, _("Lossless"), _("Enable lossless compression"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, lossless), FALSE); VIPS_ARG_BOOL(class, "exact", 12, _("Exact"), _("Preserve color values from transparent pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, exact), FALSE); VIPS_ARG_ENUM(class, "preset", 13, _("Preset"), _("Preset for lossy compression"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, preset), VIPS_TYPE_FOREIGN_WEBP_PRESET, VIPS_FOREIGN_WEBP_PRESET_DEFAULT); VIPS_ARG_BOOL(class, "smart_subsample", 14, _("Smart subsampling"), _("Enable high quality chroma subsampling"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, smart_subsample), FALSE); VIPS_ARG_BOOL(class, "near_lossless", 15, _("Near lossless"), _("Enable preprocessing in lossless mode (uses Q)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, near_lossless), FALSE); VIPS_ARG_INT(class, "alpha_q", 16, _("Alpha quality"), _("Change alpha plane fidelity for lossy compression"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, alpha_q), 0, 100, 100); VIPS_ARG_BOOL(class, "min_size", 17, _("Minimise size"), _("Optimise for minimum size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, min_size), FALSE); VIPS_ARG_INT(class, "kmin", 18, _("Minimum keyframe spacing"), _("Minimum number of frames between key frames"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, kmin), 0, INT_MAX, INT_MAX - 1); VIPS_ARG_INT(class, "kmax", 19, _("Maximum keyframe spacing"), _("Maximum number of frames between key frames"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, kmax), 0, INT_MAX, INT_MAX); VIPS_ARG_INT(class, "effort", 20, _("Effort"), _("Level of CPU effort to reduce file size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, effort), 0, 6, 4); VIPS_ARG_INT(class, "target_size", 21, _("Target size"), _("Desired target size in bytes"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, target_size), 0, INT_MAX, 0); VIPS_ARG_INT(class, "reduction_effort", 22, _("Reduction effort"), _("Level of CPU effort to reduce file size"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsForeignSaveWebp, effort), 0, 6, 4); VIPS_ARG_BOOL(class, "mixed", 23, _("Mixed encoding"), _("Allow mixed encoding (might reduce file size)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, mixed), FALSE); VIPS_ARG_BOOL(class, "smart_deblock", 24, _("Smart deblocking"), _("Enable auto-adjusting of the deblocking filter"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, smart_deblock), FALSE); VIPS_ARG_INT(class, "passes", 25, _("Passes"), _("Number of entropy-analysis passes (in [1..10])"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebp, passes), 1, 10, 1); } static void vips_foreign_save_webp_init(VipsForeignSaveWebp *webp) { webp->Q = 75; webp->alpha_q = 100; webp->effort = 4; webp->passes = 1; /* ie. keyframes disabled by default. */ webp->kmin = INT_MAX - 1; webp->kmax = INT_MAX; } typedef struct _VipsForeignSaveWebpTarget { VipsForeignSaveWebp parent_object; VipsTarget *target; } VipsForeignSaveWebpTarget; typedef VipsForeignSaveWebpClass VipsForeignSaveWebpTargetClass; G_DEFINE_TYPE(VipsForeignSaveWebpTarget, vips_foreign_save_webp_target, vips_foreign_save_webp_get_type()); static int vips_foreign_save_webp_target_build(VipsObject *object) { VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object; VipsForeignSaveWebpTarget *target = (VipsForeignSaveWebpTarget *) object; webp->target = target->target; g_object_ref(webp->target); return VIPS_OBJECT_CLASS(vips_foreign_save_webp_target_parent_class) ->build(object); } static void vips_foreign_save_webp_target_class_init( VipsForeignSaveWebpTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpsave_target"; object_class->build = vips_foreign_save_webp_target_build; VIPS_ARG_OBJECT(class, "target", 1, _("Target"), _("Target to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebpTarget, target), VIPS_TYPE_TARGET); } static void vips_foreign_save_webp_target_init(VipsForeignSaveWebpTarget *target) { } typedef struct _VipsForeignSaveWebpFile { VipsForeignSaveWebp parent_object; char *filename; } VipsForeignSaveWebpFile; typedef VipsForeignSaveWebpClass VipsForeignSaveWebpFileClass; G_DEFINE_TYPE(VipsForeignSaveWebpFile, vips_foreign_save_webp_file, vips_foreign_save_webp_get_type()); static int vips_foreign_save_webp_file_build(VipsObject *object) { VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object; VipsForeignSaveWebpFile *file = (VipsForeignSaveWebpFile *) object; if (!(webp->target = vips_target_new_to_file(file->filename))) return -1; return VIPS_OBJECT_CLASS(vips_foreign_save_webp_file_parent_class) ->build(object); } static void vips_foreign_save_webp_file_class_init(VipsForeignSaveWebpFileClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpsave"; object_class->build = vips_foreign_save_webp_file_build; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to save to"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsForeignSaveWebpFile, filename), NULL); } static void vips_foreign_save_webp_file_init(VipsForeignSaveWebpFile *file) { } typedef struct _VipsForeignSaveWebpBuffer { VipsForeignSaveWebp parent_object; VipsArea *buf; } VipsForeignSaveWebpBuffer; typedef VipsForeignSaveWebpClass VipsForeignSaveWebpBufferClass; G_DEFINE_TYPE(VipsForeignSaveWebpBuffer, vips_foreign_save_webp_buffer, vips_foreign_save_webp_get_type()); static int vips_foreign_save_webp_buffer_build(VipsObject *object) { VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object; VipsForeignSaveWebpBuffer *buffer = (VipsForeignSaveWebpBuffer *) object; if (!(webp->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_webp_buffer_parent_class) ->build(object)) return -1; VipsBlob *blob; g_object_get(webp->target, "blob", &blob, NULL); g_object_set(buffer, "buffer", blob, NULL); vips_area_unref(VIPS_AREA(blob)); return 0; } static void vips_foreign_save_webp_buffer_class_init( VipsForeignSaveWebpBufferClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "webpsave_buffer"; object_class->build = vips_foreign_save_webp_buffer_build; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to save to"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsForeignSaveWebpBuffer, buf), VIPS_TYPE_BLOB); } static void vips_foreign_save_webp_buffer_init(VipsForeignSaveWebpBuffer *buffer) { } typedef struct _VipsForeignSaveWebpMime { VipsForeignSaveWebp parent_object; } VipsForeignSaveWebpMime; typedef VipsForeignSaveWebpClass VipsForeignSaveWebpMimeClass; G_DEFINE_TYPE(VipsForeignSaveWebpMime, vips_foreign_save_webp_mime, vips_foreign_save_webp_get_type()); static int vips_foreign_save_webp_mime_build(VipsObject *object) { VipsForeignSaveWebp *webp = (VipsForeignSaveWebp *) object; VipsBlob *blob; void *data; size_t len; if (!(webp->target = vips_target_new_to_memory())) return -1; if (VIPS_OBJECT_CLASS(vips_foreign_save_webp_mime_parent_class) ->build(object)) return -1; g_object_get(webp->target, "blob", &blob, NULL); data = VIPS_AREA(blob)->data; len = VIPS_AREA(blob)->length; vips_area_unref(VIPS_AREA(blob)); printf("Content-length: %zu\r\n", len); printf("Content-type: image/webp\r\n"); printf("\r\n"); (void) fwrite(data, sizeof(char), len, stdout); fflush(stdout); VIPS_UNREF(webp->target); return 0; } static void vips_foreign_save_webp_mime_class_init(VipsForeignSaveWebpMimeClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; object_class->nickname = "webpsave_mime"; object_class->description = _("save image to webp mime"); object_class->build = vips_foreign_save_webp_mime_build; } static void vips_foreign_save_webp_mime_init(VipsForeignSaveWebpMime *mime) { } #endif /*HAVE_LIBWEBP*/ /** * vips_webpsave: (method) * @in: image to save * @filename: file to write to * @...: `NULL`-terminated list of optional named arguments * * Write an image to a file in WebP format. * * By default, images are saved in lossy format, with * @Q giving the WebP quality factor. It has the range 0 - 100, with the * default 75. * * Use @preset to hint the image type to the lossy compressor. The default is * [enum@Vips.ForeignWebpPreset.DEFAULT]. * * Set @smart_subsample to enable high quality chroma subsampling. * * Set @smart_deblock to enable auto-adjusting of the deblocking filter. This * can improve image quality, especially on low-contrast edges, but encoding * can take significantly longer. * * Use @alpha_q to set the quality for the alpha channel in lossy mode. It has * the range 1 - 100, with the default 100. * * Use @effort to control how much CPU time to spend attempting to * reduce file size. A higher value means more effort and therefore CPU time * should be spent. It has the range 0-6 and a default value of 4. * * Use @target_size to set the desired target size in bytes. * * Use @passes to set the number of entropy-analysis passes, by default 1, * unless @target_size is set, in which case the default is 3. It is not * recommended to set @passes unless you set @target_size. Doing so will * result in longer encoding times for no benefit. * * Set @lossless to use lossless compression, or combine @near_lossless * with @Q 80, 60, 40 or 20 to apply increasing amounts of preprocessing * which improves the near-lossless compression ratio by up to 50%. * * Set @exact to preserve the color data in transparent pixels. This can * reduce compression efficiency, but is generally required when working with * images as data. * * For animated webp output, @min_size will try to optimize for minimum size. * * For animated webp output, @kmax sets the maximum number of frames between * keyframes. Setting 0 means only keyframes. @kmin sets the minimum number of * frames between frames. Setting 0 means no keyframes. By default, keyframes * are disabled. * * For animated webp output, @mixed tries to improve the file size by mixing * both lossy and lossless encoding. * * Use the metadata items `loop` and `delay` to set the number of * loops for the animation and the frame delays. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @exact: `gboolean`, preserves color values from transparent pixels * * @preset: [enum@ForeignWebpPreset], choose lossy compression preset * * @smart_subsample: `gboolean`, enables high quality chroma subsampling * * @smart_deblock: `gboolean`, enables auto-adjusting of the deblocking * filter * * @near_lossless: `gboolean`, preprocess in lossless mode (controlled * by Q) * * @alpha_q: `gint`, set alpha quality in lossless mode * * @effort: `gint`, level of CPU effort to reduce file size * * @target_size: `gint`, desired target size in bytes * * @passes: `gint`, number of entropy-analysis passes * * @min_size: `gboolean`, minimise size * * @mixed: `gboolean`, allow both lossy and lossless encoding * * @kmin: `gint`, minimum number of frames between keyframes * * @kmax: `gint`, maximum number of frames between keyframes * * ::: seealso * [ctor@Image.webpload], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_webpsave(VipsImage *in, const char *filename, ...) { va_list ap; int result; va_start(ap, filename); result = vips_call_split("webpsave", ap, in, filename); va_end(ap); return result; } /** * vips_webpsave_buffer: (method) * @in: image to save * @buf: (out) (array length=len) (element-type guint8): return output buffer here * @len: return output length here * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.webpsave], but save to a memory buffer. * * The address of the buffer is returned in @buf, the length of the buffer in * @len. You are responsible for freeing the buffer with [func@GLib.free] when you * are done with it. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @preset: [enum@ForeignWebpPreset], choose lossy compression preset * * @exact: `gboolean`, preserves color values from transparent pixels * * @smart_subsample: `gboolean`, enables high quality chroma subsampling * * @smart_deblock: `gboolean`, enables auto-adjusting of the deblocking * filter * * @near_lossless: `gboolean`, preprocess in lossless mode (controlled * by Q) * * @alpha_q: `gint`, set alpha quality in lossless mode * * @effort: `gint`, level of CPU effort to reduce file size * * @target_size: `gint`, desired target size in bytes * * @passes: `gint`, number of entropy-analysis passes * * @min_size: `gboolean`, minimise size * * @mixed: `gboolean`, allow both lossy and lossless encoding * * @kmin: `gint`, minimum number of frames between keyframes * * @kmax: `gint`, maximum number of frames between keyframes * * ::: seealso * [method@Image.webpsave]. * * Returns: 0 on success, -1 on error. */ int vips_webpsave_buffer(VipsImage *in, void **buf, size_t *len, ...) { va_list ap; VipsArea *area; int result; area = NULL; va_start(ap, len); result = vips_call_split("webpsave_buffer", ap, in, &area); va_end(ap); if (!result && area) { if (buf) { *buf = area->data; area->free_fn = NULL; } if (len) *len = area->length; vips_area_unref(area); } return result; } /** * vips_webpsave_mime: (method) * @in: image to save * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.webpsave], but save as a mime webp on stdout. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @exact: `gboolean`, preserves color values from transparent pixels * * @preset: [enum@ForeignWebpPreset], choose lossy compression preset * * @smart_subsample: `gboolean`, enables high quality chroma subsampling * * @smart_deblock: `gboolean`, enables auto-adjusting of the deblocking * filter * * @near_lossless: `gboolean`, preprocess in lossless mode (controlled * by Q) * * @alpha_q: `gint`, set alpha quality in lossless mode * * @effort: `gint`, level of CPU effort to reduce file size * * @target_size: `gint`, desired target size in bytes * * @passes: `gint`, number of entropy-analysis passes * * @min_size: `gboolean`, minimise size * * @mixed: `gboolean`, allow both lossy and lossless encoding * * @kmin: `gint`, minimum number of frames between keyframes * * @kmax: `gint`, maximum number of frames between keyframes * * ::: seealso * [method@Image.webpsave], [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error. */ int vips_webpsave_mime(VipsImage *in, ...) { va_list ap; int result; va_start(ap, in); result = vips_call_split("webpsave_mime", ap, in); va_end(ap); return result; } /** * vips_webpsave_target: (method) * @in: image to save * @target: save image to this target * @...: `NULL`-terminated list of optional named arguments * * As [method@Image.webpsave], but save to a target. * * ::: tip "Optional arguments" * * @Q: `gint`, quality factor * * @lossless: `gboolean`, enables lossless compression * * @preset: [enum@ForeignWebpPreset], choose lossy compression preset * * @smart_subsample: `gboolean`, enables high quality chroma subsampling * * @smart_deblock: `gboolean`, enables auto-adjusting of the deblocking * filter * * @near_lossless: `gboolean`, preprocess in lossless mode (controlled * by Q) * * @alpha_q: `gint`, set alpha quality in lossless mode * * @effort: `gint`, level of CPU effort to reduce file size * * @target_size: `gint`, desired target size in bytes * * @passes: `gint`, number of entropy-analysis passes * * @min_size: `gboolean`, minimise size * * @mixed: `gboolean`, allow both lossy and lossless encoding * * @kmin: `gint`, minimum number of frames between keyframes * * @kmax: `gint`, maximum number of frames between keyframes * * ::: seealso * [method@Image.webpsave]. * * Returns: 0 on success, -1 on error. */ int vips_webpsave_target(VipsImage *in, VipsTarget *target, ...) { va_list ap; int result; va_start(ap, target); result = vips_call_split("webpsave_target", ap, in, target); va_end(ap); return result; } libvips-8.18.2/libvips/freqfilt/000077500000000000000000000000001516303661500165545ustar00rootroot00000000000000libvips-8.18.2/libvips/freqfilt/freqfilt.c000066400000000000000000000101341516303661500205330ustar00rootroot00000000000000/* base class for all Fourier stuff * * properties: * - single output image */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pfreqfilt.h" G_DEFINE_ABSTRACT_TYPE(VipsFreqfilt, vips_freqfilt, VIPS_TYPE_OPERATION); static int vips_freqfilt_build(VipsObject *object) { VipsFreqfilt *freqfilt = VIPS_FREQFILT(object); #ifdef DEBUG printf("vips_freqfilt_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_object_set(freqfilt, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_freqfilt_parent_class)->build(object)) return -1; return 0; } static void vips_freqfilt_class_init(VipsFreqfiltClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "freqfilt"; vobject_class->description = _("frequency-domain filter operations"); vobject_class->build = vips_freqfilt_build; VIPS_ARG_IMAGE(class, "in", -1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFreqfilt, in)); VIPS_ARG_IMAGE(class, "out", 1, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsFreqfilt, out)); } static void vips_freqfilt_init(VipsFreqfilt *freqfilt) { } /* Transform an n-band image with a 1-band processing function. * * Memory strategy: we need memory buffers for the input and the output of * fftw. In some modes fftw generates only half the output and we construct * the rest. * * input pipeline -> * bandsplit -> * full memory image, freed when im_*fft*() exits -> * fftw -> * half memory image, freed when im_*fft*() exits -> * full memory image, freed when @out is freed -> * partial bandjoin -> * output pipeline * * vips__fftproc() needs to just call VipsFftProcessFn directly for 1 band * images, so we can't cache the output in this fn. */ int vips__fftproc(VipsObject *context, VipsImage *in, VipsImage **out, VipsFftProcessFn fn) { VipsImage **bands = (VipsImage **) vips_object_local_array(context, in->Bands); VipsImage **fft = (VipsImage **) vips_object_local_array(context, in->Bands); int b; if (in->Bands == 1) return fn(context, in, out); for (b = 0; b < in->Bands; b++) if (vips_extract_band(in, &bands[b], b, NULL) || fn(context, bands[b], &fft[b])) return -1; if (vips_bandjoin(fft, out, in->Bands, NULL)) return -1; return 0; } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_freqfilt_operation_init(void) { #ifdef HAVE_FFTW extern GType vips_fwfft_get_type(void); extern GType vips_invfft_get_type(void); #endif /*HAVE_FFTW*/ extern GType vips_freqmult_get_type(void); extern GType vips_spectrum_get_type(void); extern GType vips_phasecor_get_type(void); #ifdef HAVE_FFTW vips_fwfft_get_type(); vips_invfft_get_type(); #endif /*HAVE_FFTW*/ vips_freqmult_get_type(); vips_spectrum_get_type(); vips_phasecor_get_type(); } libvips-8.18.2/libvips/freqfilt/freqmult.c000066400000000000000000000102311516303661500205540ustar00rootroot00000000000000/* frequency-domain filter an image * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on : 08/03/1991 * 16/6/93 J.Cupitt * - im_multiply() called, rather than im_cmultim() * 27/10/93 JC * - im_clip2*() called, rather than im_any2*() * 20/9/95 JC * - rewritten * 10/9/98 JC * - frees memory more quickly * 4/3/03 JC * - use im_invfftr() to get real back for speedup * 3/1/14 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pfreqfilt.h" typedef struct _VipsFreqmult { VipsFreqfilt parent_instance; VipsImage *mask; } VipsFreqmult; typedef VipsFreqfiltClass VipsFreqmultClass; G_DEFINE_TYPE(VipsFreqmult, vips_freqmult, VIPS_TYPE_FREQFILT); static int vips_freqmult_build(VipsObject *object) { VipsFreqfilt *freqfilt = VIPS_FREQFILT(object); VipsFreqmult *freqmult = (VipsFreqmult *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_freqmult_parent_class)->build(object)) return -1; in = freqfilt->in; if (vips_band_format_iscomplex(in->BandFmt)) { if (vips_multiply(in, freqmult->mask, &t[0], NULL) || vips_invfft(t[0], &t[1], "real", TRUE, NULL)) return -1; in = t[1]; } else { /* Optimisation: output of vips_invfft() is double, we * will usually cast to char, so rather than keeping a * large double buffer and partial to char from that, * cast to a memory buffer and copy to out from that. * * FIXME does this actually work now we're a class? test * perhaps we need a temporary object */ t[4] = vips_image_new_memory(); if (vips_fwfft(in, &t[0], NULL) || vips_multiply(t[0], freqmult->mask, &t[1], NULL) || vips_invfft(t[1], &t[2], "real", TRUE, NULL) || vips_cast(t[2], &t[3], in->BandFmt, NULL) || vips_image_write(t[3], t[4])) return -1; in = t[4]; } if (vips_image_write(in, freqfilt->out)) return -1; return 0; } static void vips_freqmult_class_init(VipsFreqmultClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "freqmult"; vobject_class->description = _("frequency-domain filtering"); vobject_class->build = vips_freqmult_build; VIPS_ARG_IMAGE(class, "mask", 0, _("Mask"), _("Input mask image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsFreqmult, mask)); } static void vips_freqmult_init(VipsFreqmult *freqmult) { } /** * vips_freqmult: (method) * @in: input image * @mask: mask image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Multiply @in by @mask in Fourier space. * * @in is transformed to Fourier space, multiplied with @mask, then * transformed back to real space. If @in is already a complex image, just * multiply then inverse transform. * * ::: seealso * [method@Image.invfft], [ctor@Image.mask_ideal]. * * Returns: 0 on success, -1 on error. */ int vips_freqmult(VipsImage *in, VipsImage *mask, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("freqmult", ap, in, mask, out); va_end(ap); return result; } libvips-8.18.2/libvips/freqfilt/fwfft.c000066400000000000000000000220561516303661500200410ustar00rootroot00000000000000/* forward FFT * * Author: Nicos Dessipris * Written on: 12/04/1990 * Modified on : 09/05/1990 to cope with float input * Modified on : 08/03/1991 history removed * Modified on : 03/04/1991 to cope with any input * * 28/6/95 JC * - rewritten to use im_clip2f() rather than own code * - memory leaks fixed * 10/9/98 JC * - frees memory more quickly * 2/4/02 JC * - fftw code added * 13/7/02 JC * - output Type set to IM_TYPE_FOURIER to help nip * 27/2/03 JC * - exploits real_to_complex() path in libfftw for real input (thanks * Matt) for a 2x speed-up * 17/11/03 JC * - fix a segv for wider than high images in the real_to_complex() path * (thanks Andrey) * - fixes to real_to_complex() path to give the correct result for * non-square images, including odd widths and heights * 3/11/04 * - added fftw3 support * 7/2/10 * - cleanups * - gtkdoc * 25/3/10 * - have a "t" image linked to out to keep the image alive for longer * 27/1/12 * - better setting of interpretation * - remove own fft fallback code * - remove fftw2 path * - reduce memuse * 3/1/14 * - redone as a class * 15/12/23 [akash-akya] * - add locks */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pfreqfilt.h" #ifdef HAVE_FFTW #include typedef struct _VipsFwfft { VipsFreqfilt parent_instance; } VipsFwfft; typedef VipsFreqfiltClass VipsFwfftClass; G_DEFINE_TYPE(VipsFwfft, vips_fwfft, VIPS_TYPE_FREQFILT); /* Everything in fftw3 except execute has to be behind a mutex. */ GMutex vips__fft_lock; /* Real to complex forward transform. */ static int rfwfft1(VipsObject *object, VipsImage *in, VipsImage **out) { VipsFwfft *fwfft = (VipsFwfft *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(fwfft); const guint64 size = VIPS_IMAGE_N_PELS(in); const int half_width = in->Xsize / 2 + 1; double *half_complex; double *planner_scratch; fftw_plan plan; double *buf, *q, *p; int x, y; if (vips_check_mono(class->nickname, in) || vips_check_uncoded(class->nickname, in)) return -1; /* Convert input to a real double membuffer. */ t[1] = vips_image_new_memory(); if (vips_cast_double(in, &t[0], NULL) || vips_image_write(t[0], t[1])) return -1; /* Make the plan for the transform. Yes, they really do use nx for * height and ny for width. Use a separate scratch buffer for the * planner, we can't overwrite real->data */ if (!(planner_scratch = VIPS_ARRAY(fwfft, VIPS_IMAGE_N_PELS(in), double))) return -1; if (!(half_complex = VIPS_ARRAY(fwfft, in->Ysize * half_width * 2, double))) return -1; g_mutex_lock(&vips__fft_lock); if (!(plan = fftw_plan_dft_r2c_2d(in->Ysize, in->Xsize, planner_scratch, (fftw_complex *) half_complex, 0))) { g_mutex_unlock(&vips__fft_lock); vips_error(class->nickname, "%s", _("unable to create transform plan")); return -1; } g_mutex_unlock(&vips__fft_lock); fftw_execute_dft_r2c(plan, (double *) t[1]->data, (fftw_complex *) half_complex); g_mutex_lock(&vips__fft_lock); fftw_destroy_plan(plan); g_mutex_unlock(&vips__fft_lock); /* Write to out as another memory buffer. */ *out = vips_image_new_memory(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_ANY, in, NULL)) return -1; (*out)->BandFmt = VIPS_FORMAT_DPCOMPLEX; (*out)->Type = VIPS_INTERPRETATION_FOURIER; if (!(buf = VIPS_ARRAY(fwfft, (*out)->Xsize * 2, double))) return -1; /* Copy and normalise. The right half is the up/down and * left/right flip of the left, but conjugated. Do the first * row separately, then mirror around the centre row. */ p = half_complex; q = buf; for (x = 0; x < half_width; x++) { q[0] = p[0] / size; q[1] = p[1] / size; p += 2; q += 2; } p = half_complex + ((in->Xsize + 1) / 2 - 1) * 2; for (x = half_width; x < (*out)->Xsize; x++) { q[0] = p[0] / size; q[1] = -1.0 * p[1] / size; p -= 2; q += 2; } if (vips_image_write_line(*out, 0, (VipsPel *) buf)) return -1; for (y = 1; y < (*out)->Ysize; y++) { p = half_complex + y * half_width * 2; q = buf; for (x = 0; x < half_width; x++) { q[0] = p[0] / size; q[1] = p[1] / size; p += 2; q += 2; } /* Good grief. */ p = half_complex + 2 * /* clang-format off */ (((*out)->Ysize - y + 1) * half_width - 2 + (in->Xsize & 1)); /* clang-format on */ for (x = half_width; x < (*out)->Xsize; x++) { q[0] = p[0] / size; q[1] = -1.0 * p[1] / size; p -= 2; q += 2; } if (vips_image_write_line(*out, y, (VipsPel *) buf)) return -1; } return 0; } /* Complex to complex forward transform. */ static int cfwfft1(VipsObject *object, VipsImage *in, VipsImage **out) { VipsFwfft *fwfft = (VipsFwfft *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(fwfft); fftw_plan plan; double *planner_scratch; double *buf, *q, *p; int x, y; if (vips_check_mono(class->nickname, in) || vips_check_uncoded(class->nickname, in)) return -1; /* Convert input to a complex double membuffer. */ t[1] = vips_image_new_memory(); if (vips_cast_dpcomplex(in, &t[0], NULL) || vips_image_write(t[0], t[1])) return -1; /* We have to have a separate buffer for the planner to work on. */ if (!(planner_scratch = VIPS_ARRAY(fwfft, VIPS_IMAGE_N_PELS(in) * 2, double))) return -1; /* Make the plan for the transform. */ g_mutex_lock(&vips__fft_lock); if (!(plan = fftw_plan_dft_2d(in->Ysize, in->Xsize, (fftw_complex *) planner_scratch, (fftw_complex *) planner_scratch, FFTW_FORWARD, 0))) { g_mutex_unlock(&vips__fft_lock); vips_error(class->nickname, "%s", _("unable to create transform plan")); return -1; } g_mutex_unlock(&vips__fft_lock); fftw_execute_dft(plan, (fftw_complex *) t[1]->data, (fftw_complex *) t[1]->data); g_mutex_lock(&vips__fft_lock); fftw_destroy_plan(plan); g_mutex_unlock(&vips__fft_lock); /* Write to out as another memory buffer. */ *out = vips_image_new_memory(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_ANY, in, NULL)) return -1; (*out)->BandFmt = VIPS_FORMAT_DPCOMPLEX; (*out)->Type = VIPS_INTERPRETATION_FOURIER; if (!(buf = VIPS_ARRAY(fwfft, (*out)->Xsize * 2, double))) return -1; /* Copy to out, normalise. */ p = (double *) t[1]->data; for (y = 0; y < (*out)->Ysize; y++) { guint64 size = VIPS_IMAGE_N_PELS(*out); q = buf; for (x = 0; x < (*out)->Xsize; x++) { q[0] = p[0] / size; q[1] = p[1] / size; p += 2; q += 2; } if (vips_image_write_line(*out, y, (VipsPel *) buf)) return -1; } return 0; } static int vips_fwfft_build(VipsObject *object) { VipsFreqfilt *freqfilt = VIPS_FREQFILT(object); VipsFwfft *fwfft = (VipsFwfft *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_fwfft_parent_class)->build(object)) return -1; in = freqfilt->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (vips_band_format_iscomplex(in->BandFmt)) { if (vips__fftproc(VIPS_OBJECT(fwfft), in, &t[1], cfwfft1)) return -1; } else { if (vips__fftproc(VIPS_OBJECT(fwfft), in, &t[1], rfwfft1)) return -1; } if (vips_image_write(t[1], freqfilt->out)) return -1; return 0; } static void vips_fwfft_class_init(VipsFwfftClass *class) { VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); vobject_class->nickname = "fwfft"; vobject_class->description = _("forward FFT"); vobject_class->build = vips_fwfft_build; } static void vips_fwfft_init(VipsFwfft *fwfft) { } #endif /*HAVE_FFTW*/ /** * vips_fwfft: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Transform an image to Fourier space. * * VIPS uses the fftw Fourier Transform library. If this library was not * available when VIPS was configured, these functions will fail. * * ::: seealso * [method@Image.invfft]. * * Returns: 0 on success, -1 on error. */ int vips_fwfft(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("fwfft", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/freqfilt/invfft.c000066400000000000000000000164351516303661500202250ustar00rootroot00000000000000/* Inverse FFT * * Author: Nicos Dessipris * Written on: 12/04/1990 * Modified on : * 28/6/95 JC * - rewritten, based on new im_invfft() code * 10/9/98 JC * - frees memory more quickly * 2/4/02 JC * - fftw code added * 13/7/02 JC * - Type reset * 27/2/03 JC * - tiny speed-up ... save 1 copy on write * 22/1/04 JC * - oops, fix for segv on wider than high fftw transforms * 3/11/04 * - added fftw3 support * 7/2/10 * - gtkdoc * 27/1/12 * - better setting of interpretation * - remove own fft fallback code * - remove fftw2 path * - reduce memuse * 3/1/14 * - redone as a class * 15/12/23 [akash-akya] * - add locks */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pfreqfilt.h" #ifdef HAVE_FFTW #include typedef struct _VipsInvfft { VipsFreqfilt parent_instance; gboolean real; } VipsInvfft; typedef VipsFreqfiltClass VipsInvfftClass; G_DEFINE_TYPE(VipsInvfft, vips_invfft, VIPS_TYPE_FREQFILT); /* Complex to complex inverse transform. */ static int cinvfft1(VipsObject *object, VipsImage *in, VipsImage **out) { VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsInvfft *invfft = (VipsInvfft *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(invfft); fftw_plan plan; double *planner_scratch; if (vips_check_mono(class->nickname, in) || vips_check_uncoded(class->nickname, in)) return -1; /* Convert input to a complex double membuffer. */ *out = vips_image_new_memory(); if (vips_cast_dpcomplex(in, &t[0], NULL) || vips_image_write(t[0], *out)) return -1; /* Make the plan for the transform. Yes, they really do use nx for * height and ny for width. */ if (!(planner_scratch = VIPS_ARRAY(invfft, VIPS_IMAGE_N_PELS(in) * 2, double))) return -1; g_mutex_lock(&vips__fft_lock); if (!(plan = fftw_plan_dft_2d(in->Ysize, in->Xsize, (fftw_complex *) planner_scratch, (fftw_complex *) planner_scratch, FFTW_BACKWARD, 0))) { g_mutex_unlock(&vips__fft_lock); vips_error(class->nickname, "%s", _("unable to create transform plan")); return -1; } g_mutex_unlock(&vips__fft_lock); fftw_execute_dft(plan, (fftw_complex *) (*out)->data, (fftw_complex *) (*out)->data); g_mutex_lock(&vips__fft_lock); fftw_destroy_plan(plan); g_mutex_unlock(&vips__fft_lock); (*out)->Type = VIPS_INTERPRETATION_B_W; return 0; } /* Complex to real inverse transform. */ static int rinvfft1(VipsObject *object, VipsImage *in, VipsImage **out) { VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsInvfft *invfft = (VipsInvfft *) object; VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(invfft); const int half_width = in->Xsize / 2 + 1; double *half_complex; double *planner_scratch; fftw_plan plan; int x, y; double *q, *p; /* Convert input to a complex double membuffer. */ t[1] = vips_image_new_memory(); if (vips_cast_dpcomplex(in, &t[0], NULL) || vips_image_write(t[0], t[1])) return -1; /* Build half-complex image. */ if (!(half_complex = VIPS_ARRAY(invfft, t[1]->Ysize * half_width * 2, double))) return -1; q = half_complex; for (y = 0; y < t[1]->Ysize; y++) { p = ((double *) t[1]->data) + (guint64) y * t[1]->Xsize * 2; for (x = 0; x < half_width; x++) { q[0] = p[0]; q[1] = p[1]; p += 2; q += 2; } } /* Make mem buffer real image for output. */ *out = vips_image_new_memory(); if (vips_image_pipelinev(*out, VIPS_DEMAND_STYLE_ANY, t[1], NULL)) return -1; (*out)->BandFmt = VIPS_FORMAT_DOUBLE; (*out)->Type = VIPS_INTERPRETATION_B_W; if (vips_image_write_prepare(*out)) return -1; /* Make the plan for the transform. Yes, they really do use nx for * height and ny for width. */ if (!(planner_scratch = VIPS_ARRAY(invfft, t[1]->Ysize * half_width * 2, double))) return -1; g_mutex_lock(&vips__fft_lock); if (!(plan = fftw_plan_dft_c2r_2d(t[1]->Ysize, t[1]->Xsize, (fftw_complex *) planner_scratch, (double *) (*out)->data, 0))) { g_mutex_unlock(&vips__fft_lock); vips_error(class->nickname, "%s", _("unable to create transform plan")); return -1; } g_mutex_unlock(&vips__fft_lock); fftw_execute_dft_c2r(plan, (fftw_complex *) half_complex, (double *) (*out)->data); g_mutex_lock(&vips__fft_lock); fftw_destroy_plan(plan); g_mutex_unlock(&vips__fft_lock); return 0; } static int vips_invfft_build(VipsObject *object) { VipsFreqfilt *freqfilt = VIPS_FREQFILT(object); VipsInvfft *invfft = (VipsInvfft *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_invfft_parent_class)->build(object)) return -1; in = freqfilt->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (invfft->real) { if (vips__fftproc(VIPS_OBJECT(invfft), in, &t[1], rinvfft1)) return -1; } else { if (vips__fftproc(VIPS_OBJECT(invfft), in, &t[1], cinvfft1)) return -1; } if (vips_image_write(t[1], freqfilt->out)) return -1; return 0; } static void vips_invfft_class_init(VipsInvfftClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "invfft"; vobject_class->description = _("inverse FFT"); vobject_class->build = vips_invfft_build; VIPS_ARG_BOOL(class, "real", 4, _("Real"), _("Output only the real part of the transform"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsInvfft, real), FALSE); } static void vips_invfft_init(VipsInvfft *invfft) { } #endif /*HAVE_FFTW*/ /** * vips_invfft: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Transform an image from Fourier space to real space. * * The result is complex. If you are OK with a real result, set @real, * it's quicker. * * VIPS uses the fftw Fourier Transform library. If this library was not * available when VIPS was configured, these functions will fail. * * ::: tip "Optional arguments" * * @real: `gboolean`, only output the real part * * ::: seealso * [method@Image.fwfft]. * * Returns: 0 on success, -1 on error. */ int vips_invfft(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("invfft", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/freqfilt/meson.build000066400000000000000000000006321516303661500207170ustar00rootroot00000000000000freqfilt_sources = files( 'freqfilt.c', 'fwfft.c', 'invfft.c', 'freqmult.c', 'spectrum.c', 'phasecor.c', ) freqfilt_headers = files( 'pfreqfilt.h', ) libvips_sources += freqfilt_sources freqfilt_lib = static_library('freqfilt', freqfilt_sources, freqfilt_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += freqfilt_lib libvips-8.18.2/libvips/freqfilt/pfreqfilt.h000066400000000000000000000041651516303661500207270ustar00rootroot00000000000000/* base class for all freqfilt operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PFREQFILT_H #define VIPS_PFREQFILT_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* All fftw3 calls except execute() need to be locked. */ extern GMutex vips__fft_lock; #define VIPS_TYPE_FREQFILT (vips_freqfilt_get_type()) #define VIPS_FREQFILT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FREQFILT, VipsFreqfilt)) #define VIPS_FREQFILT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FREQFILT, VipsFreqfiltClass)) #define VIPS_IS_FREQFILT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FREQFILT)) #define VIPS_IS_FREQFILT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FREQFILT)) #define VIPS_FREQFILT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FREQFILT, VipsFreqfiltClass)) typedef struct _VipsFreqfilt { VipsOperation parent_instance; VipsImage *in; VipsImage *out; } VipsFreqfilt; typedef struct _VipsFreqfiltClass { VipsOperationClass parent_class; } VipsFreqfiltClass; GType vips_freqfilt_get_type(void); typedef int (*VipsFftProcessFn)(VipsObject *, VipsImage *, VipsImage **); int vips__fftproc(VipsObject *context, VipsImage *in, VipsImage **out, VipsFftProcessFn fn); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PFREQFILT_H*/ libvips-8.18.2/libvips/freqfilt/phasecor.c000066400000000000000000000066451516303661500205370ustar00rootroot00000000000000/* Like spcor, but calculates phase correlation in the Fourier domain. * * Copyright: 2008, Nottingham Trent University * * Author: Tom Vajzovic * Written on: 2008-01-16 * 7/2/10 * - cleanups * - gtkdoc * 3/1/14 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pfreqfilt.h" typedef struct _VipsPhasecor { VipsFreqfilt parent_instance; VipsImage *in2; } VipsPhasecor; typedef VipsFreqfiltClass VipsPhasecorClass; G_DEFINE_TYPE(VipsPhasecor, vips_phasecor, VIPS_TYPE_FREQFILT); static int vips_phasecor_build(VipsObject *object) { VipsFreqfilt *freqfilt = VIPS_FREQFILT(object); VipsPhasecor *phasecor = (VipsPhasecor *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); VipsImage *in1, *in2; if (VIPS_OBJECT_CLASS(vips_phasecor_parent_class)->build(object)) return -1; in1 = freqfilt->in; in2 = phasecor->in2; if (in1->BandFmt != VIPS_FORMAT_COMPLEX) { if (vips_fwfft(in1, &t[0], NULL)) return -1; in1 = t[0]; } if (in2->BandFmt != VIPS_FORMAT_COMPLEX) { if (vips_fwfft(in2, &t[1], NULL)) return -1; in2 = t[1]; } if (vips_cross_phase(in1, in2, &t[2], NULL) || vips_invfft(t[2], &t[3], "real", TRUE, NULL) || vips_image_write(t[3], freqfilt->out)) return -1; return 0; } static void vips_phasecor_class_init(VipsPhasecorClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "phasecor"; vobject_class->description = _("calculate phase correlation"); vobject_class->build = vips_phasecor_build; VIPS_ARG_IMAGE(class, "in2", 0, _("in2"), _("Second input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPhasecor, in2)); } static void vips_phasecor_init(VipsPhasecor *phasecor) { } /** * vips_phasecor: (method) * @in1: first input image * @in2: second input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Convert the two input images to Fourier space, calculate phase-correlation, * back to real space. * * ::: seealso * [method@Image.fwfft], [method@Image.cross_phase], * * Returns: 0 on success, -1 on error. */ int vips_phasecor(VipsImage *in1, VipsImage *in2, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("phasecor", ap, in1, in2, out); va_end(ap); return result; } libvips-8.18.2/libvips/freqfilt/spectrum.c000066400000000000000000000061571516303661500205730ustar00rootroot00000000000000/* make a displayable power spectrum for an image * * Author: Nicos Dessipris * Written on: 27/03/1991 * Modified on : * 16/6/93 J.Cupitt * - im_ioflag() changed to im_iocheck() * 23/2/95 JC * - rewritten for partials * 10/9/98 JC * - frees memory more quickly * 2/4/02 JC * - any number of bands * 7/2/10 * - gtkdoc * - cleanups * 3/1/14 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pfreqfilt.h" typedef VipsFreqfilt VipsSpectrum; typedef VipsFreqfiltClass VipsSpectrumClass; G_DEFINE_TYPE(VipsSpectrum, vips_spectrum, VIPS_TYPE_FREQFILT); static int vips_spectrum_build(VipsObject *object) { VipsFreqfilt *freqfilt = VIPS_FREQFILT(object); VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_spectrum_parent_class)->build(object)) return -1; in = freqfilt->in; if (in->BandFmt != VIPS_FORMAT_COMPLEX) { if (vips_fwfft(in, &t[0], NULL)) return -1; in = t[0]; } if (vips_abs(in, &t[1], NULL) || vips_scale(t[1], &t[2], "log", TRUE, NULL) || vips_wrap(t[2], &t[3], NULL)) return -1; if (vips_image_write(t[3], freqfilt->out)) return -1; return 0; } static void vips_spectrum_class_init(VipsSpectrumClass *class) { VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); vobject_class->nickname = "spectrum"; vobject_class->description = _("make displayable power spectrum"); vobject_class->build = vips_spectrum_build; } static void vips_spectrum_init(VipsSpectrum *spectrum) { } /** * vips_spectrum: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Make a displayable (ie. 8-bit unsigned int) power spectrum. * * If @in is non-complex, it is transformed to Fourier space. Then the * absolute value is passed through [method@Image.scale] in log mode, and * [method@Image.wrap]. * * ::: seealso * [method@Image.fwfft], [method@Image.scale], [method@Image.wrap]. * * Returns: 0 on success, -1 on error. */ int vips_spectrum(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("spectrum", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/000077500000000000000000000000001516303661500167355ustar00rootroot00000000000000libvips-8.18.2/libvips/histogram/case.c000066400000000000000000000166471516303661500200320ustar00rootroot00000000000000/* use pixel values to pick cases from an array of images * * 28/7/19 * - from maplut.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include typedef struct _VipsCase { VipsOperation parent_instance; VipsImage *index; VipsArrayImage *cases; VipsImage *out; int n; } VipsCase; typedef VipsOperationClass VipsCaseClass; G_DEFINE_TYPE(VipsCase, vips_case, VIPS_TYPE_OPERATION); static int vips_case_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion **ar = (VipsRegion **) seq; VipsCase *cas = (VipsCase *) b; VipsRect *r = &out_region->valid; VipsRegion *index = ar[cas->n]; int x, y, i; VipsPel *restrict ip; VipsPel *restrict q; size_t ils; size_t qls; int hist[256]; VipsPel *restrict p[256]; size_t ls[256]; size_t ps; if (vips_region_prepare(index, r)) return -1; g_assert(index->im->BandFmt == VIPS_FORMAT_UCHAR); g_assert(index->im->Bands == 1); /* Histogram of index region, so we know which of our inputs we will * need to prepare. */ memset(hist, 0, cas->n * sizeof(int)); ip = VIPS_REGION_ADDR(index, r->left, r->top); ils = VIPS_REGION_LSKIP(index); for (y = 0; y < r->height; y++) { for (x = 0; x < r->width; x++) { int v = VIPS_MIN(ip[x], cas->n - 1); hist[v] += 1; } ip += ils; } for (i = 0; i < cas->n; i++) if (hist[i]) { if (vips_region_prepare(ar[i], r)) return -1; p[i] = VIPS_REGION_ADDR(ar[i], r->left, r->top); ls[i] = VIPS_REGION_LSKIP(ar[i]); } ip = VIPS_REGION_ADDR(index, r->left, r->top); q = VIPS_REGION_ADDR(out_region, r->left, r->top); qls = VIPS_REGION_LSKIP(out_region); ps = VIPS_IMAGE_SIZEOF_PEL(out_region->im); for (y = 0; y < r->height; y++) { int k; k = 0; for (x = 0; x < r->width; x++) { int v = VIPS_MIN(ip[x], cas->n - 1); VipsPel *restrict pv = p[v]; int j; for (j = 0; j < ps; j++) { q[k] = pv[k]; k += 1; } } ip += ils; q += qls; for (i = 0; i < cas->n; i++) if (hist[i]) p[i] += ls[i]; } return 0; } static int vips_case_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsCase *cas = (VipsCase *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *index; VipsImage **cases; VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; int i; g_object_set(object, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_case_parent_class)->build(object)) return -1; index = cas->index; cases = vips_area_get_data(&cas->cases->area, NULL, &cas->n, NULL, NULL); if (cas->n > 256 || cas->n < 1) { vips_error(class->nickname, "%s", _("bad number of cases")); return -1; } if (index->Bands > 1) { vips_error(class->nickname, "%s", _("index image not 1-band")); return -1; } /* Cast @index to u8 to make the index image. */ if (vips_cast(index, &t[0], VIPS_FORMAT_UCHAR, NULL)) return -1; index = t[0]; decode = (VipsImage **) vips_object_local_array(object, cas->n); format = (VipsImage **) vips_object_local_array(object, cas->n); band = (VipsImage **) vips_object_local_array(object, cas->n + 1); size = (VipsImage **) vips_object_local_array(object, cas->n + 1); /* Decode RAD/LABQ etc. */ for (i = 0; i < cas->n; i++) if (vips_image_decode(cases[i], &decode[i])) return -1; cases = decode; /* case images must match in format, size and bands. * * We want everything sized up to the size of the index image, so add * that to the end of the set of images for sizealike. */ band[cas->n] = index; g_object_ref(index); if (vips__formatalike_vec(cases, format, cas->n) || vips__bandalike_vec(class->nickname, format, band, cas->n, 1) || vips__sizealike_vec(band, size, cas->n + 1)) return -1; cases = size; if (vips_image_pipeline_array(cas->out, VIPS_DEMAND_STYLE_THINSTRIP, cases)) return -1; cas->out->BandFmt = cases[0]->BandFmt; cas->out->Bands = cases[0]->Bands; cas->out->Type = cases[0]->Type; if (vips_image_generate(cas->out, vips_start_many, vips_case_gen, vips_stop_many, cases, cas)) return -1; return 0; } static void vips_case_class_init(VipsCaseClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "case"; object_class->description = _("use pixel values to pick cases from an array of images"); object_class->build = vips_case_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "index", 1, _("Index"), _("Index image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCase, index)); VIPS_ARG_BOXED(class, "cases", 2, _("Cases"), _("Array of case images"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCase, cases), VIPS_TYPE_ARRAY_IMAGE); VIPS_ARG_IMAGE(class, "out", 3, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsCase, out)); } static void vips_case_init(VipsCase *cas) { } static int vips_casev(VipsImage *index, VipsImage **cases, VipsImage **out, int n, va_list ap) { VipsArrayImage *array; int result; array = vips_array_image_new(cases, n); result = vips_call_split("case", ap, index, array, out); vips_area_unref(VIPS_AREA(array)); return result; } /** * vips_case: (method) * @index: index image * @cases: (array length=n): array of case images * @out: (out): output image * @n: number of case images * @...: `NULL`-terminated list of optional named arguments * * Use values in @index to select pixels from @cases. * * @index must have one band. @cases can have up to 256 elements. Values in * @index greater than or equal to @n use the final image in @cases. The * images in @cases must have either one band or the same number of bands. * The output image is the same size as @index. Images in @cases are * expanded to the smallest common format and number of bands. * * Combine this with [func@Image.switch] to make something like a case * statement or a multi-way [method@Image.ifthenelse]. * * ::: seealso * [method@Image.maplut], [func@Image.switch], [method@Image.ifthenelse]. * * Returns: 0 on success, -1 on error */ int vips_case(VipsImage *index, VipsImage **cases, VipsImage **out, int n, ...) { va_list ap; int result; va_start(ap, n); result = vips_casev(index, cases, out, n, ap); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_cum.c000066400000000000000000000113311516303661500207130ustar00rootroot00000000000000/* histogram cumulativisation * * Author: N. Dessipris * Written on: 02/08/1990 * 24/5/95 JC * - tidied up and ANSIfied * 20/7/95 JC * - smartened up again * - now works for hists >256 elements * 3/3/01 JC * - broken into cum and norm ... helps im_histspec() * - better behaviour for >8 bit hists * 31/10/05 JC * - was broken for vertical histograms, gah * - neater im_histnorm() * 23/7/07 * - eek, off by 1 for more than 1 band hists * 12/5/08 * - histcum works for signed hists now as well * 24/3/10 * - gtkdoc * - small cleanups * 12/8/13 * - redone im_histcum() as a class, vips_hist_cum() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "phistogram.h" #include "hist_unary.h" typedef VipsHistUnary VipsHistCum; typedef VipsHistUnaryClass VipsHistCumClass; G_DEFINE_TYPE(VipsHistCum, vips_hist_cum, VIPS_TYPE_HIST_UNARY); #define ACCUMULATE(ITYPE, OTYPE) \ { \ for (b = 0; b < nb; b++) { \ ITYPE *p = (ITYPE *) in[0]; \ OTYPE *q = (OTYPE *) out; \ OTYPE total; \ \ total = 0; \ for (x = b; x < mx; x += nb) { \ total += p[x]; \ q[x] = total; \ } \ } \ } /* Special case for VIPS_FORMAT_INT, to prevent UB. */ #define ACCUMULATE_INT64(ITYPE, OTYPE) \ { \ for (b = 0; b < nb; b++) { \ ITYPE *p = (ITYPE *) in[0]; \ OTYPE *q = (OTYPE *) out; \ int64_t total; \ \ total = 0; \ for (x = b; x < mx; x += nb) { \ total += p[x]; \ q[x] = total; \ } \ } \ } static void vips_hist_cum_process(VipsHistogram *histogram, VipsPel *out, VipsPel **in, int width) { const int bands = vips_image_get_bands(histogram->ready[0]); const int nb = vips_band_format_iscomplex(histogram->ready[0]->BandFmt) ? bands * 2 : bands; int mx = width * nb; int x, b; switch (vips_image_get_format(histogram->ready[0])) { case VIPS_FORMAT_CHAR: ACCUMULATE(signed char, signed int); break; case VIPS_FORMAT_UCHAR: ACCUMULATE(unsigned char, unsigned int); break; case VIPS_FORMAT_SHORT: ACCUMULATE(signed short, signed int); break; case VIPS_FORMAT_USHORT: ACCUMULATE(unsigned short, unsigned int); break; case VIPS_FORMAT_INT: ACCUMULATE_INT64(signed int, signed int); break; case VIPS_FORMAT_UINT: ACCUMULATE(unsigned int, unsigned int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: ACCUMULATE(float, float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: ACCUMULATE(double, double); break; default: g_assert_not_reached(); } } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define C VIPS_FORMAT_CHAR #define US VIPS_FORMAT_USHORT #define S VIPS_FORMAT_SHORT #define UI VIPS_FORMAT_UINT #define I VIPS_FORMAT_INT #define F VIPS_FORMAT_FLOAT #define X VIPS_FORMAT_COMPLEX #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX static const VipsBandFormat vips_hist_cum_format_table[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UI, I, UI, I, UI, I, F, F, D, D }; static void vips_hist_cum_class_init(VipsHistCumClass *class) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsHistogramClass *hclass = VIPS_HISTOGRAM_CLASS(class); object_class->nickname = "hist_cum"; object_class->description = _("form cumulative histogram"); hclass->format_table = vips_hist_cum_format_table; hclass->process = vips_hist_cum_process; } static void vips_hist_cum_init(VipsHistCum *hist_cum) { } /** * vips_hist_cum: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Form cumulative histogram. * * ::: seealso * [method@Image.hist_norm]. * * Returns: 0 on success, -1 on error */ int vips_hist_cum(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_cum", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_entropy.c000066400000000000000000000072711516303661500216370ustar00rootroot00000000000000/* estimate entropy * * Author: John Cupitt * 11/8/15 * - from hist_ismonotonic.c * 6/3/16 * - vips_log() call was mangled, thanks Lovell */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include typedef struct _VipsHistEntropy { VipsOperation parent_instance; VipsImage *in; double out; } VipsHistEntropy; typedef VipsOperationClass VipsHistEntropyClass; G_DEFINE_TYPE(VipsHistEntropy, vips_hist_entropy, VIPS_TYPE_OPERATION); static int vips_hist_entropy_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsHistEntropy *entropy = (VipsHistEntropy *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); double avg; double sum; if (VIPS_OBJECT_CLASS(vips_hist_entropy_parent_class)->build(object)) return -1; if (vips_check_hist(class->nickname, entropy->in)) return -1; /* Compute: * norm_hist = hist / sum(hist) * entropy = -sum(norm_hist * log2(norm_hist)) */ if (vips_avg(entropy->in, &avg, NULL)) return -1; sum = avg * VIPS_IMAGE_N_PELS(entropy->in) * entropy->in->Bands; if (vips_linear1(entropy->in, &t[0], 1.0 / sum, 0, NULL) || vips_log(t[0], &t[1], NULL) || vips_linear1(t[1], &t[2], 1.0 / log(2.0), 0, NULL) || vips_multiply(t[0], t[2], &t[3], NULL) || vips_avg(t[3], &avg, NULL)) return -1; g_object_set(entropy, "out", -avg * VIPS_IMAGE_N_PELS(entropy->in) * entropy->in->Bands, NULL); return 0; } static void vips_hist_entropy_class_init(VipsHistEntropyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_entropy"; object_class->description = _("estimate image entropy"); object_class->build = vips_hist_entropy_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input histogram image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistEntropy, in)); VIPS_ARG_DOUBLE(class, "out", 2, _("Output"), _("Output value"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistEntropy, out), -INFINITY, INFINITY, 0.0); } static void vips_hist_entropy_init(VipsHistEntropy *entropy) { } /** * vips_hist_entropy: (method) * @in: input histogram * @out: (out): image entropy * @...: `NULL`-terminated list of optional named arguments * * Estimate image entropy from a histogram. Entropy is calculated as: * * ``` * -sum(p * log2(p)) * ``` * * where p is histogram-value / sum-of-histogram-values. * * Returns: 0 on success, -1 on error */ int vips_hist_entropy(VipsImage *in, double *out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_entropy", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_equal.c000066400000000000000000000077251516303661500212520ustar00rootroot00000000000000/* Histogram-equalise an image. * * Copyright: 1991, N. Dessipris. * * Author: Nicos Dessipris * Written on: 27/03/1991 * Modified on : * 16/6/93 J.Cupitt * - im_ioflag() changed to im_iocheck() * 24/5/95 JC * - ANSIfied and tidied up * 3/3/01 JC * - more cleanup * 23/3/10 * - gtkdoc * 12/8/13 * - redone as a class * 19/6/17 * - make output format always == input format, thanks Simon */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include typedef struct _VipsHistEqual { VipsOperation parent_instance; VipsImage *in; VipsImage *out; /* -1 for all bands, or the band we scan. */ int which; } VipsHistEqual; typedef VipsOperationClass VipsHistEqualClass; G_DEFINE_TYPE(VipsHistEqual, vips_hist_equal, VIPS_TYPE_OPERATION); static int vips_hist_equal_build(VipsObject *object) { VipsHistEqual *equal = (VipsHistEqual *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); g_object_set(equal, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_hist_equal_parent_class)->build(object)) return -1; /* norm can return a uchar output for a ushort input if the range is * small, so make sure we cast back to the input type again. */ if (vips_hist_find(equal->in, &t[0], "band", equal->which, NULL) || vips_hist_cum(t[0], &t[1], NULL) || vips_hist_norm(t[1], &t[2], NULL) || vips_cast(t[2], &t[3], equal->in->BandFmt, NULL) || vips_maplut(equal->in, &t[4], t[3], NULL) || vips_image_write(t[4], equal->out)) return -1; return 0; } static void vips_hist_equal_class_init(VipsHistEqualClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_equal"; object_class->description = _("histogram equalisation"); object_class->build = vips_hist_equal_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistEqual, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistEqual, out)); VIPS_ARG_INT(class, "band", 110, _("Band"), _("Equalise with this band"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHistEqual, which), -1, 100000, -1); } static void vips_hist_equal_init(VipsHistEqual *equal) { equal->which = -1; } /** * vips_hist_equal: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Histogram-equalise @in. * * Equalise using band @bandno, or if @bandno is -1, * equalise bands independently. The output format is always the same as the * input format. * * ::: tip "Optional arguments" * * @band: `gint`, band to equalise * * Returns: 0 on success, -1 on error */ int vips_hist_equal(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_equal", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_ismonotonic.c000066400000000000000000000075741516303661500225060ustar00rootroot00000000000000/* test for monotonicity * * Author: John Cupitt * Written on: 18/7/1995 * 17/9/96 JC * - restrictions on Ps, Pm, Ph relaxed * - restrictions on S, M, H relaxed * 25/7/01 JC * - patched for im_extract_band() change * 11/7/04 * - generalised to im_tone_build_range() ... so you can use it for any * image, not just LabS * 26/3/10 * - cleanups * - gtkdoc * 20/9/13 * - redone as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include typedef struct _VipsHistIsmonotonic { VipsOperation parent_instance; VipsImage *in; gboolean monotonic; } VipsHistIsmonotonic; typedef VipsOperationClass VipsHistIsmonotonicClass; G_DEFINE_TYPE(VipsHistIsmonotonic, vips_hist_ismonotonic, VIPS_TYPE_OPERATION); static int vips_hist_ismonotonic_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsHistIsmonotonic *ismonotonic = (VipsHistIsmonotonic *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); double m; if (VIPS_OBJECT_CLASS(vips_hist_ismonotonic_parent_class)->build(object)) return -1; if (vips_check_hist(class->nickname, ismonotonic->in)) return -1; if (ismonotonic->in->Xsize == 1) t[0] = vips_image_new_matrixv(1, 2, -1.0, 1.0); else t[0] = vips_image_new_matrixv(2, 1, -1.0, 1.0); vips_image_set_double(t[0], "offset", 128); /* We want >=128 everywhere, ie. no -ve transitions. */ if (vips_conv(ismonotonic->in, &t[1], t[0], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_moreeq_const1(t[1], &t[2], 128, NULL) || vips_min(t[2], &m, NULL)) return -1; g_object_set(ismonotonic, "monotonic", (int) m == 255, NULL); return 0; } static void vips_hist_ismonotonic_class_init(VipsHistIsmonotonicClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_ismonotonic"; object_class->description = _("test for monotonicity"); object_class->build = vips_hist_ismonotonic_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input histogram image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistIsmonotonic, in)); VIPS_ARG_BOOL(class, "monotonic", 2, _("Monotonic"), _("true if in is monotonic"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistIsmonotonic, monotonic), FALSE); } static void vips_hist_ismonotonic_init(VipsHistIsmonotonic *ismonotonic) { } /** * vips_hist_ismonotonic: (method) * @in: lookup-table to test * @out: (out): set non-zero if @in is monotonic * @...: `NULL`-terminated list of optional named arguments * * Test @in for monotonicity. @out is set non-zero if @in is monotonic. * * Returns: 0 on success, -1 on error */ int vips_hist_ismonotonic(VipsImage *in, gboolean *out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_ismonotonic", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_local.c000066400000000000000000000242271516303661500212310ustar00rootroot00000000000000/* local histogram equalisation * * Copyright: 1991, N. Dessipris * * Author: N. Dessipris * Written on: 24/10/1991 * Modified on : * 25/1/96 JC * - rewritten, adapting im_spcor() * - correct result, 2x faster, partial, simpler, better arg checking * 8/7/04 * - expand input rather than output with new im_embed() mode * - _raw() output is one pixel larger * - sets Xoffset/Yoffset * 23/6/08 * - check for window too small as well * 25/3/10 * - gtkdoc * - small cleanups * 5/9/13 * - redo as a class * 9/9/13 * - any number of bands * 20/1/17 * - add contrast limit * - sum to <= target, not < target, since cumulative hists include the * current value * - scale result by 255, not 256, to avoid overflow * - off by 1 fix for odd window widths */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include typedef struct _VipsHistLocal { VipsOperation parent_instance; VipsImage *in; VipsImage *out; int width; int height; int max_slope; } VipsHistLocal; typedef VipsOperationClass VipsHistLocalClass; G_DEFINE_TYPE(VipsHistLocal, vips_hist_local, VIPS_TYPE_OPERATION); /* Our sequence value: the region this sequence is using, and local stats. */ typedef struct { VipsRegion *ir; /* Input region */ /* A 256-element hist for every band. */ unsigned int **hist; } VipsHistLocalSequence; static int vips_hist_local_stop(void *vseq, void *a, void *b) { VipsHistLocalSequence *seq = (VipsHistLocalSequence *) vseq; VipsImage *in = (VipsImage *) a; VIPS_UNREF(seq->ir); if (seq->hist && in) { int i; for (i = 0; i < in->Bands; i++) VIPS_FREE(seq->hist[i]); } VIPS_FREE(seq->hist); VIPS_FREE(seq); return 0; } static void * vips_hist_local_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsHistLocalSequence *seq; int i; if (!(seq = VIPS_NEW(NULL, VipsHistLocalSequence))) return NULL; seq->ir = NULL; seq->hist = NULL; if (!(seq->ir = vips_region_new(in)) || !(seq->hist = VIPS_ARRAY(NULL, in->Bands, unsigned int *))) { vips_hist_local_stop(seq, NULL, NULL); return NULL; } for (i = 0; i < in->Bands; i++) if (!(seq->hist[i] = VIPS_ARRAY(NULL, 256, unsigned int))) { vips_hist_local_stop(seq, NULL, NULL); return NULL; } return seq; } static int vips_hist_local_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsHistLocalSequence *seq = (VipsHistLocalSequence *) vseq; VipsImage *in = (VipsImage *) a; const VipsHistLocal *local = (VipsHistLocal *) b; VipsRect *r = &out_region->valid; const int bands = in->Bands; const int max_slope = local->max_slope; VipsRect irect; int y; int lsk; int centre; /* Offset to move to centre of window */ /* What part of ir do we need? */ irect.left = r->left; irect.top = r->top; irect.width = r->width + local->width; irect.height = r->height + local->height; if (vips_region_prepare(seq->ir, &irect)) return -1; lsk = VIPS_REGION_LSKIP(seq->ir); centre = lsk * (local->height / 2) + bands * (local->width / 2); for (y = 0; y < r->height; y++) { /* Get input and output pointers for this line. */ VipsPel *restrict p = VIPS_REGION_ADDR(seq->ir, r->left, r->top + y); VipsPel *restrict q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); VipsPel *restrict p1; int x, i, j, b; /* Find histogram for the start of this line. */ for (b = 0; b < bands; b++) memset(seq->hist[b], 0, 256 * sizeof(unsigned int)); p1 = p; for (j = 0; j < local->height; j++) { for (i = 0, x = 0; x < local->width; x++) for (b = 0; b < bands; b++, i++) seq->hist[b][p1[i]] += 1; p1 += lsk; } /* Loop for output pels. */ for (x = 0; x < r->width; x++) { for (b = 0; b < bands; b++) { /* Sum histogram up to current pel. */ unsigned int *restrict hist = seq->hist[b]; const int target = p[centre + b]; int sum; sum = 0; /* For CLAHE we need to limit the height of the * hist to limit the amount we boost the * contrast by. */ if (max_slope > 0) { int sum_over; sum_over = 0; /* Must be <= target, since a cum hist * always includes the current element. */ for (i = 0; i <= target; i++) { if (hist[i] > max_slope) { sum_over += hist[i] - max_slope; sum += max_slope; } else sum += hist[i]; } for (; i < 256; i++) { if (hist[i] > max_slope) sum_over += hist[i] - max_slope; } /* The extra clipped off bit from the * top of the hist is spread over all * bins equally, then summed to target. */ sum += (target + 1) * sum_over / 256; } else { sum = 0; for (i = 0; i <= target; i++) sum += hist[i]; } /* This can't overflow, even in * contrast-limited mode. * * Scale by 255, not 256, or we'll get * overflow. */ q[b] = 255 * sum / (local->width * local->height); /* Adapt histogram -- remove the pels from * the left hand column, add in pels for a * new right-hand column. */ p1 = p + b; for (j = 0; j < local->height; j++) { hist[p1[0]] -= 1; hist[p1[bands * local->width]] += 1; p1 += lsk; } } p += bands; q += bands; } } return 0; } static int vips_hist_local_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsHistLocal *local = (VipsHistLocal *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_hist_local_parent_class)->build(object)) return -1; in = local->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (vips_check_format(class->nickname, in, VIPS_FORMAT_UCHAR)) return -1; if (local->width > in->Xsize || local->height > in->Ysize) { vips_error(class->nickname, "%s", _("window too large")); return -1; } /* Expand the input. */ if (vips_embed(in, &t[1], local->width / 2, local->height / 2, in->Xsize + local->width - 1, in->Ysize + local->height - 1, "extend", VIPS_EXTEND_MIRROR, NULL)) return -1; in = t[1]; g_object_set(object, "out", vips_image_new(), NULL); /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause * too many recalculations on overlaps. */ if (vips_image_pipelinev(local->out, VIPS_DEMAND_STYLE_FATSTRIP, in, NULL)) return -1; local->out->Xsize -= local->width - 1; local->out->Ysize -= local->height - 1; if (vips_image_generate(local->out, vips_hist_local_start, vips_hist_local_generate, vips_hist_local_stop, in, local)) return -1; local->out->Xoffset = 0; local->out->Yoffset = 0; vips_reorder_margin_hint(local->out, local->width * local->height); return 0; } static void vips_hist_local_class_init(VipsHistLocalClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_local"; object_class->description = _("local histogram equalisation"); object_class->build = vips_hist_local_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistLocal, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistLocal, out)); VIPS_ARG_INT(class, "width", 4, _("Width"), _("Window width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistLocal, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Window height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistLocal, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "max_slope", 6, _("Max slope"), _("Maximum slope (CLAHE)"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsHistLocal, max_slope), 0, 100, 0); } static void vips_hist_local_init(VipsHistLocal *local) { } /** * vips_hist_local: (method) * @in: input image * @out: (out): output image * @width: width of region * @height: height of region * @...: `NULL`-terminated list of optional named arguments * * Performs local histogram equalisation on @in using a * window of size @width by @height centered on the input pixel. * * The output image is the same size as the input image. The edge pixels are * created by mirroring the input image outwards. * * If @max_slope is greater than 0, it sets the maximum value for the slope of * the cumulative histogram, that is, the maximum brightening that is * performed. A value of 3 is often used. Local histogram equalization with * contrast limiting is usually called CLAHE. * * ::: tip "Optional arguments" * * @max_slope: `gint`, maximum brightening * * ::: seealso * [method@Image.hist_equal]. * * Returns: 0 on success, -1 on error */ int vips_hist_local(VipsImage *in, VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("hist_local", ap, in, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_match.c000066400000000000000000000113621516303661500212270ustar00rootroot00000000000000/* Match two normalised, cumulative histograms. * * Copyright: 1991, N. Dessipris. * * Author: Nicos Dessipris * Written on: 19/07/1990 * Modified on: 26/03/1991 * * 1/3/01 JC * - bleurg! rewritten, now does 16 bits as well, bugs removed, faster, * smaller * 24/3/10 * - gtkdoc * - small cleanups * 12/8/13 * - redone im_histspec() as a class, vips_hist_match() * 19/12/13 * - oop, upcast input */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "phistogram.h" /* #define DEBUG */ typedef struct _VipsHistMatch { VipsHistogram parent_instance; VipsImage *in; VipsImage *ref; } VipsHistMatch; typedef VipsHistogramClass VipsHistMatchClass; G_DEFINE_TYPE(VipsHistMatch, vips_hist_match, VIPS_TYPE_HISTOGRAM); static void vips_hist_match_process(VipsHistogram *histogram, VipsPel *out, VipsPel **in, int width) { VipsHistMatch *match = (VipsHistMatch *) histogram; const int bands = match->in->Bands; const int max = width * bands; unsigned int *inbuf = (unsigned int *) in[0]; unsigned int *refbuf = (unsigned int *) in[1]; unsigned int *outbuf = (unsigned int *) out; int i, j; for (j = 0; j < bands; j++) { /* Track up refbuf[] with this. */ int ri = j; int limit = max - bands; for (i = j; i < max; i += bands) { unsigned int inv = inbuf[i]; for (; ri < limit; ri += bands) if (inv <= refbuf[ri]) break; if (ri < limit) { /* Simple rounding. */ double mid = refbuf[ri] + refbuf[ri + bands] / 2.0; if (inv < mid) outbuf[i] = ri / bands; else outbuf[i] = ri / bands + 1; } else outbuf[i] = refbuf[ri]; } } } static int vips_hist_match_build(VipsObject *object) { VipsHistogram *histogram = VIPS_HISTOGRAM(object); VipsHistMatch *match = (VipsHistMatch *) object; histogram->n = 2; histogram->in = (VipsImage **) vips_object_local_array(object, 2); histogram->in[0] = match->in; histogram->in[1] = match->ref; if (histogram->in[0]) g_object_ref(histogram->in[0]); if (histogram->in[1]) g_object_ref(histogram->in[1]); if (VIPS_OBJECT_CLASS(vips_hist_match_parent_class)->build(object)) return -1; return 0; } static void vips_hist_match_class_init(VipsHistMatchClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsHistogramClass *hclass = VIPS_HISTOGRAM_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "hist_match"; vobject_class->description = _("match two histograms"); vobject_class->build = vips_hist_match_build; hclass->input_format = VIPS_FORMAT_UINT; hclass->process = vips_hist_match_process; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input histogram"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistMatch, in)); VIPS_ARG_IMAGE(class, "ref", 2, _("Reference"), _("Reference histogram"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistMatch, ref)); } static void vips_hist_match_init(VipsHistMatch *match) { } /** * vips_hist_match: (method) * @in: input histogram * @ref: reference histogram * @out: (out): output histogram * @...: `NULL`-terminated list of optional named arguments * * Adjust @in to match @ref. If @in and @ref are normalised * cumulative histograms, @out will be a LUT that adjusts the PDF of the image * from which @in was made to match the PDF of @ref's image. * * ::: seealso * [method@Image.maplut], [method@Image.hist_find], [method@Image.hist_norm], * [method@Image.hist_cum]. * * Returns: 0 on success, -1 on error */ int vips_hist_match(VipsImage *in, VipsImage *ref, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_match", ap, in, ref, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_norm.c000066400000000000000000000104121516303661500211010ustar00rootroot00000000000000/* histogram normalisation * * Author: N. Dessipris * Written on: 02/08/1990 * 24/5/95 JC * - tidied up and ANSIfied * 20/7/95 JC * - smartened up again * - now works for hists >256 elements * 3/3/01 JC * - broken into norm and norm ... helps im_histspec() * - better behaviour for >8 bit hists * 31/10/05 JC * - was broken for vertical histograms, gah * - neater im_histnorm() * 23/7/07 * - eek, off by 1 for more than 1 band hists * 12/5/08 * - histnorm works for signed hists now as well * 24/3/10 * - gtkdoc * - small cleanups * 12/8/13 * - redone im_histnorm() as a class, vips_hist_norm() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include typedef struct _VipsHistNorm { VipsOperation parent_instance; VipsImage *in; VipsImage *out; } VipsHistNorm; typedef VipsOperationClass VipsHistNormClass; G_DEFINE_TYPE(VipsHistNorm, vips_hist_norm, VIPS_TYPE_OPERATION); static int vips_hist_norm_build(VipsObject *object) { VipsHistNorm *norm = (VipsHistNorm *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); guint64 new_max; int bands; double *a, *b; int y; VipsBandFormat fmt; g_object_set(object, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_hist_norm_parent_class)->build(object)) return -1; /* Need max for each channel. */ if (vips_stats(norm->in, &t[0], NULL)) return -1; /* Scale each channel by px / channel max */ new_max = VIPS_IMAGE_N_PELS(norm->in) - 1; bands = norm->in->Bands; if (!(a = VIPS_ARRAY(object, bands, double)) || !(b = VIPS_ARRAY(object, bands, double))) return -1; for (y = 0; y < bands; y++) { a[y] = new_max / *VIPS_MATRIX(t[0], 1, y + 1); b[y] = 0; } if (vips_linear(norm->in, &t[1], a, b, bands, NULL)) return -1; /* Make output format as small as we can. */ if (new_max <= 255) fmt = VIPS_FORMAT_UCHAR; else if (new_max <= 65535) fmt = VIPS_FORMAT_USHORT; else fmt = VIPS_FORMAT_UINT; if (vips_cast(t[1], &t[2], fmt, NULL) || vips_image_write(t[2], norm->out)) return -1; return 0; } static void vips_hist_norm_class_init(VipsHistNormClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_norm"; object_class->description = _("normalise histogram"); object_class->build = vips_hist_norm_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistNorm, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistNorm, out)); } static void vips_hist_norm_init(VipsHistNorm *hist_norm) { } /** * vips_hist_norm: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Normalise histogram. The maximum of each band becomes equal to the maximum * index, so for example the max for a uchar image becomes 255. * Normalise each band separately. * * ::: seealso * [method@Image.hist_cum]. * * Returns: 0 on success, -1 on error */ int vips_hist_norm(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_norm", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_plot.c000066400000000000000000000203651516303661500211140ustar00rootroot00000000000000/* draw a histogram * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris. * Written on: 09/07/1990 * Modified on : 12/03/1991 * 20/6/95 JC * - rules rationalised * - im_lineprof removed * - rewritten * 13/8/99 JC * - rewritten again for partial, rules redone * 19/9/99 JC * - oooops, broken for >1 band * 26/9/99 JC * - oooops, graph float was wrong * 17/11/99 JC * - oops, failed for all 0's histogram * 14/12/05 * - redone plot function in C, also use incheck() to cache calcs * - much, much faster! * 12/5/09 * - fix signed/unsigned warning * 24/3/10 * - gtkdoc * - small cleanups * - oop, would fail for signed int histograms * 19/8/13 * - wrap as a class, left a rewrite for now */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "phistogram.h" typedef struct _VipsHistPlot { VipsOperation parent_instance; VipsImage *in; VipsImage *out; } VipsHistPlot; typedef VipsOperationClass VipsHistPlotClass; G_DEFINE_TYPE(VipsHistPlot, vips_hist_plot, VIPS_TYPE_OPERATION); #define VERT(TYPE) \ { \ TYPE *p1 = (TYPE *) p; \ \ for (x = le; x < ri; x++) { \ for (z = 0; z < nb; z++) \ q[z] = p1[z] < x ? 0 : 255; \ \ q += nb; \ } \ } /* Generate function. */ static int vips_hist_plot_vert_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int ri = VIPS_RECT_RIGHT(r); int bo = VIPS_RECT_BOTTOM(r); int nb = in->Bands; int x, y, z; for (y = to; y < bo; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); VipsPel *p = VIPS_IMAGE_ADDR(in, 0, y); switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: VERT(unsigned char); break; case VIPS_FORMAT_CHAR: VERT(signed char); break; case VIPS_FORMAT_USHORT: VERT(unsigned short); break; case VIPS_FORMAT_SHORT: VERT(signed short); break; case VIPS_FORMAT_UINT: VERT(unsigned int); break; case VIPS_FORMAT_INT: VERT(signed int); break; case VIPS_FORMAT_FLOAT: VERT(float); break; case VIPS_FORMAT_DOUBLE: VERT(double); break; default: g_assert_not_reached(); } } return 0; } #define HORZ(TYPE) \ { \ TYPE *p1 = (TYPE *) p; \ \ for (y = to; y < bo; y++) { \ for (z = 0; z < nb; z++) \ q[z] = p1[z] < ht - y ? 0 : 255; \ \ q += lsk; \ } \ } /* Generate function. */ static int vips_hist_plot_horz_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int ri = VIPS_RECT_RIGHT(r); int bo = VIPS_RECT_BOTTOM(r); int nb = in->Bands; int lsk = VIPS_REGION_LSKIP(out_region); int ht = out_region->im->Ysize; int x, y, z; for (x = le; x < ri; x++) { VipsPel *q = VIPS_REGION_ADDR(out_region, x, to); VipsPel *p = VIPS_IMAGE_ADDR(in, x, 0); switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: HORZ(unsigned char); break; case VIPS_FORMAT_CHAR: HORZ(signed char); break; case VIPS_FORMAT_USHORT: HORZ(unsigned short); break; case VIPS_FORMAT_SHORT: HORZ(signed short); break; case VIPS_FORMAT_UINT: HORZ(unsigned int); break; case VIPS_FORMAT_INT: HORZ(signed int); break; case VIPS_FORMAT_FLOAT: HORZ(float); break; case VIPS_FORMAT_DOUBLE: HORZ(double); break; default: g_assert_not_reached(); } } return 0; } static int vips_hist_plot_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsHistPlot *plot = (VipsHistPlot *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; double min, max; int width, height, tsize; VipsGenerateFn generate_fn; g_object_set(plot, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_hist_plot_parent_class)->build(object)) return -1; in = plot->in; if (vips_check_uncoded(class->nickname, in) || vips_check_noncomplex(class->nickname, in) || vips_check_hist(class->nickname, in)) return -1; if (!vips_band_format_isuint(in->BandFmt) && vips_band_format_isint(in->BandFmt)) { /* A signed int type. Move min up to 0. */ double min; if (vips_min(in, &min, NULL) || vips_linear1(in, &t[0], 1.0, -min, NULL)) return -1; in = t[0]; } else if (vips_band_format_isfloat(in->BandFmt)) { /* Float image: scale min--max to 0--any. Output square * graph. */ int any = in->Xsize * in->Ysize; if (vips_stats(in, &t[0], NULL)) return -1; min = *VIPS_MATRIX(t[0], 0, 0); max = *VIPS_MATRIX(t[0], 1, 0); /* For float-style images, we need to check for near zero range, * or we'll get +/- Inf in vips_max() below. */ if (fabs(max - min) > 0.01) { if (vips_linear1(in, &t[1], any / (max - min), -min * any / (max - min), NULL)) return -1; } else /* Range effectively zero: just return black. */ if (vips_black(&t[1], in->Xsize, in->Ysize, "bands", in->Bands, NULL)) return -1; in = t[1]; } if (vips_image_wio_input(in)) return -1; /* Find range we will plot. */ if (vips_max(in, &max, NULL)) return -1; g_assert(max >= 0); if (in->BandFmt == VIPS_FORMAT_UCHAR) tsize = 256; else tsize = ceil(max); /* Make sure we don't make a zero height image. */ if (tsize == 0) tsize = 1; if (in->Xsize == 1) { /* Vertical graph. */ width = tsize; height = in->Ysize; generate_fn = vips_hist_plot_vert_gen; } else { /* Horizontal graph. */ width = in->Xsize; height = tsize; generate_fn = vips_hist_plot_horz_gen; } /* Set image. */ vips_image_init_fields(plot->out, width, height, in->Bands, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0); if (vips_image_pipelinev(plot->out, VIPS_DEMAND_STYLE_ANY, NULL) || vips_image_generate(plot->out, NULL, generate_fn, NULL, in, NULL)) return -1; return 0; } static void vips_hist_plot_class_init(VipsHistPlotClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_plot"; object_class->description = _("plot histogram"); object_class->build = vips_hist_plot_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistPlot, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistPlot, out)); } static void vips_hist_plot_init(VipsHistPlot *hist_plot) { } /** * vips_hist_plot: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * Plot a 1 by any or any by 1 image file as a max by any or * any by max image using these rules: * * *unsigned char* max is always 256 * * *other unsigned integer types* output 0 - maximum * value of @in. * * *signed int types* min moved to 0, max moved to max + min. * * *float types* min moved to 0, max moved to any * (square output) * * Returns: 0 on success, -1 on error */ int vips_hist_plot(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("hist_plot", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/hist_unary.c000066400000000000000000000045351516303661500212750ustar00rootroot00000000000000/* a hist operation implemented as a unary processor * * properties: * - single hist to single hist */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "phistogram.h" #include "hist_unary.h" G_DEFINE_ABSTRACT_TYPE(VipsHistUnary, vips_hist_unary, VIPS_TYPE_HISTOGRAM); static int vips_hist_unary_build(VipsObject *object) { VipsHistogram *histogram = VIPS_HISTOGRAM(object); VipsHistUnary *unary = VIPS_HIST_UNARY(object); histogram->n = 1; histogram->in = (VipsImage **) vips_object_local_array(object, 1); histogram->in[0] = unary->in; if (histogram->in[0]) g_object_ref(histogram->in[0]); if (VIPS_OBJECT_CLASS(vips_hist_unary_parent_class)->build(object)) return -1; return 0; } static void vips_hist_unary_class_init(VipsHistUnaryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "hist_unary"; vobject_class->description = _("hist_unary operations"); vobject_class->build = vips_hist_unary_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsHistUnary, in)); } static void vips_hist_unary_init(VipsHistUnary *hist_unary) { } libvips-8.18.2/libvips/histogram/hist_unary.h000066400000000000000000000036111516303661500212740ustar00rootroot00000000000000/* base class for all hist_unary operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PHIST_UNARY_H #define VIPS_PHIST_UNARY_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_HIST_UNARY (vips_hist_unary_get_type()) #define VIPS_HIST_UNARY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_HIST_UNARY, VipsHistUnary)) #define VIPS_HIST_UNARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_HIST_UNARY, VipsHistUnaryClass)) #define VIPS_IS_HIST_UNARY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_HIST_UNARY)) #define VIPS_IS_HIST_UNARY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_HIST_UNARY)) #define VIPS_HIST_UNARY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_HIST_UNARY, VipsHistUnaryClass)) typedef struct _VipsHistUnary { VipsHistogram parent_instance; VipsImage *in; } VipsHistUnary; typedef struct _VipsHistUnaryClass { VipsHistogramClass parent_class; } VipsHistUnaryClass; GType vips_hist_unary_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PHIST_UNARY_H*/ libvips-8.18.2/libvips/histogram/histogram.c000066400000000000000000000145261516303661500211060ustar00rootroot00000000000000/* base class for all histogram operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "phistogram.h" G_DEFINE_ABSTRACT_TYPE(VipsHistogram, vips_histogram, VIPS_TYPE_OPERATION); /* sizealike by expanding in just one dimension and copying the final element. */ static int vips__hist_sizealike_vec(VipsImage **in, VipsImage **out, int n) { int i; int max_size; g_assert(n >= 1); max_size = VIPS_MAX(in[0]->Xsize, in[0]->Ysize); for (i = 1; i < n; i++) max_size = VIPS_MAX(max_size, VIPS_MAX(in[0]->Xsize, in[0]->Ysize)); for (i = 0; i < n; i++) if (in[i]->Ysize == 1) { if (vips_embed(in[i], &out[i], 0, 0, max_size, 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; } else { if (vips_embed(in[i], &out[i], 0, 0, 1, max_size, "extend", VIPS_EXTEND_COPY, NULL)) return -1; } return 0; } static int vips_histogram_build(VipsObject *object) { VipsHistogram *histogram = VIPS_HISTOGRAM(object); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS(histogram); VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; VipsImage **memory; VipsPel *outbuf; VipsPel **inbuf; int i; #ifdef DEBUG printf("vips_histogram_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_histogram_parent_class)->build(object)) return -1; g_assert(histogram->n > 0); /* Must be NULL-terminated. */ g_assert(!histogram->in[histogram->n]); decode = (VipsImage **) vips_object_local_array(object, histogram->n); format = (VipsImage **) vips_object_local_array(object, histogram->n); band = (VipsImage **) vips_object_local_array(object, histogram->n); size = (VipsImage **) vips_object_local_array(object, histogram->n); memory = (VipsImage **) vips_object_local_array(object, histogram->n); g_object_set(histogram, "out", vips_image_new(), NULL); for (i = 0; i < histogram->n; i++) if (vips_image_decode(histogram->in[i], &decode[i]) || vips_check_hist(class->nickname, decode[i])) return -1; /* Cast our input images up to a common format, bands and size. If * input_format is set, cast to a fixed input type. */ if (hclass->input_format != VIPS_FORMAT_NOTSET) { for (i = 0; i < histogram->n; i++) if (vips_cast(decode[i], &format[i], hclass->input_format, NULL)) return -1; } else { if (vips__formatalike_vec(decode, format, histogram->n)) return -1; } if (vips__bandalike_vec(class->nickname, format, band, histogram->n, 1) || vips__hist_sizealike_vec(band, size, histogram->n)) return -1; if (vips_image_pipeline_array(histogram->out, VIPS_DEMAND_STYLE_THINSTRIP, size)) return -1; /* Need a copy of the inputs in memory. */ if (!(inbuf = VIPS_ARRAY(object, histogram->n + 1, VipsPel *))) return -1; for (i = 0; i < histogram->n; i++) { if (!(memory[i] = vips_image_copy_memory(size[i]))) return -1; inbuf[i] = VIPS_IMAGE_ADDR(memory[i], 0, 0); } inbuf[i] = NULL; /* Keep a copy of the memory images here for subclasses. */ histogram->ready = memory; histogram->out->Xsize = VIPS_IMAGE_N_PELS(histogram->ready[0]); histogram->out->Ysize = 1; if (hclass->format_table) histogram->out->BandFmt = hclass->format_table[histogram->ready[0]->BandFmt]; histogram->out->Type = VIPS_INTERPRETATION_HISTOGRAM; if (!(outbuf = vips_malloc(object, VIPS_IMAGE_SIZEOF_LINE(histogram->out)))) return -1; hclass->process(histogram, outbuf, inbuf, histogram->ready[0]->Xsize); if (vips_image_write_line(histogram->out, 0, outbuf)) return -1; return 0; } static void vips_histogram_class_init(VipsHistogramClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "histogram"; vobject_class->description = _("histogram operations"); vobject_class->build = vips_histogram_build; class->input_format = VIPS_FORMAT_NOTSET; /* Inputs set by subclassess. */ VIPS_ARG_IMAGE(class, "out", 10, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsHistogram, out)); } static void vips_histogram_init(VipsHistogram *histogram) { /* Sanity check this above. */ histogram->n = -1; } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_histogram_operation_init(void) { extern GType vips_maplut_get_type(void); extern GType vips_case_get_type(void); extern GType vips_percent_get_type(void); extern GType vips_hist_cum_get_type(void); extern GType vips_hist_norm_get_type(void); extern GType vips_hist_equal_get_type(void); extern GType vips_hist_plot_get_type(void); extern GType vips_hist_match_get_type(void); extern GType vips_hist_local_get_type(void); extern GType vips_hist_ismonotonic_get_type(void); extern GType vips_hist_entropy_get_type(void); extern GType vips_stdif_get_type(void); vips_maplut_get_type(); vips_case_get_type(); vips_percent_get_type(); vips_stdif_get_type(); vips_hist_cum_get_type(); vips_hist_norm_get_type(); vips_hist_equal_get_type(); vips_hist_plot_get_type(); vips_hist_match_get_type(); vips_hist_local_get_type(); vips_hist_ismonotonic_get_type(); vips_hist_entropy_get_type(); } libvips-8.18.2/libvips/histogram/maplut.c000066400000000000000000000466031516303661500204140ustar00rootroot00000000000000/* map though a LUT * * Modified: * 18/6/93 JC * - oops! im_incheck() added for LUT image * - some ANSIfication * 15/7/93 JC * - adapted for partial v2 * - ANSIfied * - now does complex LUTs too * 10/3/94 JC * - more helpful error messages, slight reformatting * 24/8/94 JC * - now allows non-uchar image input * 7/10/94 JC * - uses im_malloc(), IM_NEW() etc. * 13/3/95 JC * - now takes a private copy of LUT, so user can im_close() LUT image * after im_maplut() without fear of coredumps * 23/6/95 JC * - lut may now have many bands if image has just one band * 3/3/01 JC * - small speed ups * 30/6/04 * - heh, 1 band image + 3 band lut + >8bit output has been broken for 9 * years :-) * 7/11/07 * - new eval start/end system * 25/3/10 * - gtkdoc * - small cleanups * 5/7/13 * - convert to a class * 2/10/13 * - add --band arg, replacing im_tone_map() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include typedef struct _VipsMaplut { VipsOperation parent_instance; VipsImage *in; VipsImage *out; VipsImage *lut; int band; int fmt; /* LUT image BandFmt */ int nb; /* Number of bands in lut */ int es; /* VIPS_IMAGE_SIZEOF_ELEMENT() for lut image */ int sz; /* Number of elements in minor dimension */ int clp; /* Value we clip against */ VipsPel **table; /* Lut converted to 2d array */ int overflow; /* Number of overflows for non-uchar lut */ } VipsMaplut; typedef VipsOperationClass VipsMaplutClass; G_DEFINE_TYPE(VipsMaplut, vips_maplut, VIPS_TYPE_OPERATION); static void vips_maplut_preeval(VipsImage *image, VipsProgress *progress, VipsMaplut *maplut) { maplut->overflow = 0; } static void vips_maplut_posteval(VipsImage *image, VipsProgress *progress, VipsMaplut *maplut) { if (maplut->overflow) g_warning("%d overflows detected", maplut->overflow); } /* Our sequence value: the region this sequence is using, and local stats. */ typedef struct { VipsRegion *ir; /* Input region */ int overflow; /* Number of overflows */ } VipsMaplutSequence; /* Our start function. */ static void * vips_maplut_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsMaplutSequence *seq; if (!(seq = VIPS_NEW(out, VipsMaplutSequence))) return NULL; /* Init! */ seq->ir = NULL; seq->overflow = 0; if (!(seq->ir = vips_region_new(in))) return NULL; return seq; } /* Map through n non-complex luts. */ #define loop(OUT) \ { \ int b = maplut->nb; \ \ for (y = to; y < bo; y++) { \ for (z = 0; z < b; z++) { \ VipsPel *p = VIPS_REGION_ADDR(ir, le, y); \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ OUT *tlut = (OUT *) maplut->table[z]; \ \ for (x = z; x < ne; x += b) { \ unsigned int index = p[x]; \ \ if (index > maplut->clp) { \ index = maplut->clp; \ seq->overflow++; \ } \ \ q[x] = tlut[index]; \ } \ } \ } \ } /* Map through n complex luts. */ #define loopc(OUT) \ { \ int b = in->Bands; \ \ for (y = to; y < bo; y++) { \ for (z = 0; z < b; z++) { \ VipsPel *p = VIPS_REGION_ADDR(ir, le, y) + z; \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y) + z * 2; \ OUT *tlut = (OUT *) maplut->table[z]; \ \ for (x = 0; x < ne; x += b) { \ int n = p[x] * 2; \ \ q[0] = tlut[n]; \ q[1] = tlut[n + 1]; \ q += b * 2; \ } \ } \ } \ } #define loopg(IN, OUT) \ { \ int b = maplut->nb; \ \ for (y = to; y < bo; y++) { \ for (z = 0; z < b; z++) { \ IN *p = (IN *) VIPS_REGION_ADDR(ir, le, y); \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ OUT *tlut = (OUT *) maplut->table[z]; \ \ for (x = z; x < ne; x += b) { \ unsigned int index = p[x]; \ \ if (index > maplut->clp) { \ index = maplut->clp; \ seq->overflow++; \ } \ \ q[x] = tlut[index]; \ } \ } \ } \ } #define loopcg(IN, OUT) \ { \ int b = in->Bands; \ \ for (y = to; y < bo; y++) { \ for (z = 0; z < b; z++) { \ IN *p = (IN *) VIPS_REGION_ADDR(ir, le, y) + z; \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y) + z * 2; \ OUT *tlut = (OUT *) maplut->table[z]; \ \ for (x = 0; x < ne; x += b) { \ unsigned int index = p[x]; \ \ if (index > maplut->clp) { \ index = maplut->clp; \ seq->overflow++; \ } \ \ q[0] = tlut[index * 2]; \ q[1] = tlut[index * 2 + 1]; \ \ q += b * 2; \ } \ } \ } \ } /* Map image through one non-complex lut. */ #define loop1(OUT) \ { \ OUT *tlut = (OUT *) maplut->table[0]; \ \ for (y = to; y < bo; y++) { \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ VipsPel *p = VIPS_REGION_ADDR(ir, le, y); \ \ for (x = 0; x < ne; x++) { \ unsigned int index = p[x]; \ \ if (index > maplut->clp) { \ index = maplut->clp; \ seq->overflow++; \ } \ \ q[x] = tlut[index]; \ } \ } \ } /* Map image through one complex lut. */ #define loop1c(OUT) \ { \ OUT *tlut = (OUT *) maplut->table[0]; \ \ for (y = to; y < bo; y++) { \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ VipsPel *p = VIPS_REGION_ADDR(ir, le, y); \ \ for (x = 0; x < ne; x++) { \ int n = p[x] * 2; \ \ q[0] = tlut[n]; \ q[1] = tlut[n + 1]; \ q += 2; \ } \ } \ } /* As above, but the input image may be any unsigned integer type. We have to * index the lut carefully, and record the number of overflows we detect. */ #define loop1g(IN, OUT) \ { \ OUT *tlut = (OUT *) maplut->table[0]; \ \ for (y = to; y < bo; y++) { \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ IN *p = (IN *) VIPS_REGION_ADDR(ir, le, y); \ \ for (x = 0; x < ne; x++) { \ unsigned int index = p[x]; \ \ if (index > maplut->clp) { \ index = maplut->clp; \ seq->overflow++; \ } \ \ q[x] = tlut[index]; \ } \ } \ } #define loop1cg(IN, OUT) \ { \ OUT *tlut = (OUT *) maplut->table[0]; \ \ for (y = to; y < bo; y++) { \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ IN *p = (IN *) VIPS_REGION_ADDR(ir, le, y); \ \ for (x = 0; x < ne; x++) { \ unsigned int index = p[x]; \ \ if (index > maplut->clp) { \ index = maplut->clp; \ seq->overflow++; \ } \ \ q[0] = tlut[index * 2]; \ q[1] = tlut[index * 2 + 1]; \ q += 2; \ } \ } \ } /* Map 1-band image through a many-band non-complex lut. */ #define loop1m(OUT) \ { \ OUT **tlut = (OUT **) maplut->table; \ \ for (y = to; y < bo; y++) { \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ VipsPel *p = VIPS_REGION_ADDR(ir, le, y); \ \ for (i = 0, x = 0; x < np; x++) { \ unsigned int n = p[x]; \ \ if (n > maplut->clp) { \ n = maplut->clp; \ seq->overflow++; \ } \ \ for (z = 0; z < maplut->nb; z++, i++) \ q[i] = tlut[z][n]; \ } \ } \ } /* Map 1-band image through many-band complex lut. */ #define loop1cm(OUT) \ { \ OUT **tlut = (OUT **) maplut->table; \ \ for (y = to; y < bo; y++) { \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ VipsPel *p = VIPS_REGION_ADDR(ir, le, y); \ \ for (x = 0; x < np; x++) { \ int n = p[x] * 2; \ \ for (z = 0; z < maplut->nb; z++) { \ q[0] = tlut[z][n]; \ q[1] = tlut[z][n + 1]; \ q += 2; \ } \ } \ } \ } /* Map 1-band uint or ushort image through a many-band non-complex LUT. */ #define loop1gm(IN, OUT) \ { \ OUT **tlut = (OUT **) maplut->table; \ \ for (y = to; y < bo; y++) { \ IN *p = (IN *) VIPS_REGION_ADDR(ir, le, y); \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ \ for (i = 0, x = 0; x < np; x++) { \ unsigned int n = p[x]; \ \ if (n > maplut->clp) { \ n = maplut->clp; \ seq->overflow++; \ } \ \ for (z = 0; z < maplut->nb; z++, i++) \ q[i] = tlut[z][n]; \ } \ } \ } /* Map 1-band uint or ushort image through a many-band complex LUT. */ #define loop1cgm(IN, OUT) \ { \ OUT **tlut = (OUT **) maplut->table; \ \ for (y = to; y < bo; y++) { \ IN *p = (IN *) VIPS_REGION_ADDR(ir, le, y); \ OUT *q = (OUT *) VIPS_REGION_ADDR(out_region, le, y); \ \ for (x = 0; x < np; x++) { \ unsigned int n = p[x]; \ \ if (n > maplut->clp) { \ n = maplut->clp; \ seq->overflow++; \ } \ \ for (z = 0; z < maplut->nb; z++) { \ q[0] = tlut[z][n * 2]; \ q[1] = tlut[z][n * 2 + 1]; \ q += 2; \ } \ } \ } \ } /* Switch for input types. Has to be uint type! */ #define inner_switch(UCHAR, GEN, OUT) \ switch (ir->im->BandFmt) { \ case VIPS_FORMAT_UCHAR: \ UCHAR(OUT); \ break; \ case VIPS_FORMAT_USHORT: \ GEN(unsigned short, OUT); \ break; \ case VIPS_FORMAT_UINT: \ GEN(unsigned int, OUT); \ break; \ default: \ g_assert_not_reached(); \ } /* Switch for LUT types. One function for non-complex images, a * variant for complex ones. Another pair as well, in case the input is not * uchar. */ #define outer_switch(UCHAR_F, UCHAR_FC, GEN_F, GEN_FC) \ switch (maplut->fmt) { \ case VIPS_FORMAT_UCHAR: \ inner_switch(UCHAR_F, GEN_F, unsigned char); \ break; \ case VIPS_FORMAT_CHAR: \ inner_switch(UCHAR_F, GEN_F, char); \ break; \ case VIPS_FORMAT_USHORT: \ inner_switch(UCHAR_F, GEN_F, unsigned short); \ break; \ case VIPS_FORMAT_SHORT: \ inner_switch(UCHAR_F, GEN_F, short); \ break; \ case VIPS_FORMAT_UINT: \ inner_switch(UCHAR_F, GEN_F, unsigned int); \ break; \ case VIPS_FORMAT_INT: \ inner_switch(UCHAR_F, GEN_F, int); \ break; \ case VIPS_FORMAT_FLOAT: \ inner_switch(UCHAR_F, GEN_F, float); \ break; \ case VIPS_FORMAT_DOUBLE: \ inner_switch(UCHAR_F, GEN_F, double); \ break; \ case VIPS_FORMAT_COMPLEX: \ inner_switch(UCHAR_FC, GEN_FC, float); \ break; \ case VIPS_FORMAT_DPCOMPLEX: \ inner_switch(UCHAR_FC, GEN_FC, double); \ break; \ default: \ g_assert_not_reached(); \ } /* Do a map. */ static int vips_maplut_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsMaplutSequence *seq = (VipsMaplutSequence *) vseq; VipsImage *in = (VipsImage *) a; VipsMaplut *maplut = (VipsMaplut *) b; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int np = r->width; /* Pels across region */ int ne = VIPS_REGION_N_ELEMENTS(out_region); /* Number of elements */ int x, y, z, i; if (vips_region_prepare(ir, r)) return -1; /* clang-format off */ if (maplut->nb == 1) /* One band lut. */ outer_switch(loop1, loop1c, loop1g, loop1cg) else /* Many band lut. */ if (in->Bands == 1) /* ... but 1 band input. */ outer_switch(loop1m, loop1cm, loop1gm, loop1cgm) else outer_switch(loop, loopc, loopg, loopcg) return 0; /* clang-format on */ } /* Destroy a sequence value. */ static int vips_maplut_stop(void *vseq, void *a, void *b) { VipsMaplutSequence *seq = (VipsMaplutSequence *) vseq; VipsMaplut *maplut = (VipsMaplut *) b; /* Add to global stats. */ maplut->overflow += seq->overflow; VIPS_UNREF(seq->ir); return 0; } /* Save a bit of typing. */ #define UC VIPS_FORMAT_UCHAR #define US VIPS_FORMAT_USHORT #define UI VIPS_FORMAT_UINT /* Type mapping: go to uchar / ushort / uint to make an index. */ static const VipsBandFormat bandfmt_maplut[10] = { /* Band format: UC C US S UI I F X D DX */ /* Promotion: */ UC, UC, US, US, UI, UI, UI, UI, UI, UI }; /* Repack lut into a set of band arrays. If we're just passing one band of the * image through the lut, put the identity function in the other bands. */ #define PACK_TABLE(TYPE) \ { \ TYPE *data = (TYPE *) lut->data; \ int x, b; \ \ for (x = 0; x < maplut->sz; x++) \ for (b = 0; b < maplut->nb; b++) { \ TYPE *q = (TYPE *) maplut->table[b]; \ \ if (maplut->band >= 0 && \ lut->Bands == 1) { \ if (b == maplut->band) \ q[x] = data[x]; \ else \ q[x] = x; \ } \ else \ q[x] = data[x * lut->Bands + b]; \ } \ } #define PACK_TABLEC(TYPE) \ { \ TYPE *data = (TYPE *) lut->data; \ int x, b; \ \ for (x = 0; x < maplut->sz; x++) \ for (b = 0; b < maplut->nb; b++) { \ TYPE *q = (TYPE *) maplut->table[b]; \ \ if (maplut->band >= 0 && \ lut->Bands == 1) { \ if (b == maplut->band) { \ q[2 * x] = data[2 * x]; \ q[2 * x + 1] = data[2 * x + 1]; \ } \ else { \ q[2 * x] = x; \ q[2 * x + 1] = 0; \ } \ } \ else { \ q[2 * x] = data[2 * (x * lut->Bands + b)]; \ q[2 * x + 1] = \ data[2 * (x * lut->Bands + b) + 1]; \ } \ } \ } static int vips_maplut_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsMaplut *maplut = (VipsMaplut *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; VipsImage *lut; int i; g_object_set(object, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_maplut_parent_class)->build(object)) return -1; in = maplut->in; lut = maplut->lut; if (vips_check_hist(class->nickname, lut) || vips_check_uncoded(class->nickname, lut)) return -1; /* Cast @in to u8/u16/u32 to make the index image. */ if (vips_cast(in, &t[0], bandfmt_maplut[in->BandFmt], NULL)) return -1; in = t[0]; if (vips_check_uncoded(class->nickname, in) || vips_check_bands_1orn(class->nickname, in, lut) || vips_image_pio_input(in)) return -1; if (vips_image_pipelinev(maplut->out, VIPS_DEMAND_STYLE_THINSTRIP, in, lut, NULL)) return -1; maplut->out->BandFmt = lut->BandFmt; /* Output has same number of bands as LUT, unless LUT has 1 band, in * which case output has same number of bands as input. */ if (lut->Bands != 1) maplut->out->Bands = lut->Bands; /* The Type comes from the image with many bands. A B_W index image, * for example, needs to become an RGB image when it goes through a * three-band LUT. */ if (lut->Bands != 1) maplut->out->Type = lut->Type; /* We can still set crazy interpretations -- for example, a many-band LUT * made with identity will be a histogram, but we don't want that for the * output image. * * Replace any crazy interpretations with the default. */ maplut->out->Type = vips_image_guess_interpretation(maplut->out); g_signal_connect(in, "preeval", G_CALLBACK(vips_maplut_preeval), maplut); g_signal_connect(in, "posteval", G_CALLBACK(vips_maplut_posteval), maplut); /* Make luts. We unpack the LUT image into a 2D C array to speed * processing. */ if (!(t[1] = vips_image_copy_memory(lut))) return -1; lut = t[1]; maplut->fmt = lut->BandFmt; maplut->es = VIPS_IMAGE_SIZEOF_ELEMENT(lut); maplut->sz = lut->Xsize * lut->Ysize; maplut->clp = maplut->sz - 1; /* If @bands is >= 0, we need to expand the lut to the number of bands * in the input image. */ if (maplut->band >= 0 && lut->Bands == 1) maplut->nb = in->Bands; else maplut->nb = lut->Bands; /* Attach tables. */ if (!(maplut->table = VIPS_ARRAY(maplut, maplut->nb, VipsPel *))) return -1; for (i = 0; i < maplut->nb; i++) if (!(maplut->table[i] = VIPS_ARRAY(maplut, maplut->sz * maplut->es, VipsPel))) return -1; /* Scan LUT and fill table. */ switch (lut->BandFmt) { case VIPS_FORMAT_UCHAR: PACK_TABLE(unsigned char); break; case VIPS_FORMAT_CHAR: PACK_TABLE(char); break; case VIPS_FORMAT_USHORT: PACK_TABLE(unsigned short); break; case VIPS_FORMAT_SHORT: PACK_TABLE(short); break; case VIPS_FORMAT_UINT: PACK_TABLE(unsigned int); break; case VIPS_FORMAT_INT: PACK_TABLE(int); break; case VIPS_FORMAT_FLOAT: PACK_TABLE(float); break; case VIPS_FORMAT_DOUBLE: PACK_TABLE(double); break; case VIPS_FORMAT_COMPLEX: PACK_TABLEC(float); break; case VIPS_FORMAT_DPCOMPLEX: PACK_TABLEC(double); break; default: g_assert_not_reached(); } if (vips_image_generate(maplut->out, vips_maplut_start, vips_maplut_gen, vips_maplut_stop, in, maplut)) return -1; return 0; } static void vips_maplut_class_init(VipsMaplutClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "maplut"; object_class->description = _("map an image though a lut"); object_class->build = vips_maplut_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaplut, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMaplut, out)); VIPS_ARG_IMAGE(class, "lut", 3, _("LUT"), _("Look-up table image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMaplut, lut)); VIPS_ARG_INT(class, "band", 4, _("Band"), _("Apply one-band lut to this band of in"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMaplut, band), -1, 10000, -1); } static void vips_maplut_init(VipsMaplut *maplut) { maplut->band = -1; } /** * vips_maplut: (method) * @in: input image * @out: (out): output image * @lut: look-up table * @...: `NULL`-terminated list of optional named arguments * * Map an image through another image acting as a LUT (Look Up Table). * The lut may have any type and the output image will be that type. * * The input image will be cast to one of the unsigned integer types, that is, * [enum@Vips.BandFormat.UCHAR], [enum@Vips.BandFormat.USHORT] or [enum@Vips.BandFormat.UINT]. * * If @lut is too small for the input type (for example, if @in is * [enum@Vips.BandFormat.UCHAR] but @lut only has 100 elements), the lut is padded out * by copying the last element. Overflows are reported at the end of * computation. * If @lut is too large, extra values are ignored. * * If @lut has one band and @band is -1 (the default), then all bands of @in * pass through @lut. If @band is >= 0, then just that band of @in passes * through @lut and other bands are just copied. * * If @lut * has same number of bands as @in, then each band is mapped * separately. If @in has one band, then @lut may have many bands and * the output will have the same number of bands as @lut. * * ::: tip "Optional arguments" * * @band: `gint`, apply one-band @lut to this band of @in * * ::: seealso * [method@Image.hist_find], [ctor@Image.identity]. * * Returns: 0 on success, -1 on error */ int vips_maplut(VipsImage *in, VipsImage **out, VipsImage *lut, ...) { va_list ap; int result; va_start(ap, lut); result = vips_call_split("maplut", ap, in, out, lut); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/meson.build000066400000000000000000000011311516303661500210730ustar00rootroot00000000000000histogram_sources = files( 'histogram.c', 'maplut.c', 'case.c', 'hist_unary.c', 'hist_cum.c', 'hist_norm.c', 'hist_equal.c', 'hist_plot.c', 'hist_match.c', 'hist_local.c', 'percent.c', 'hist_ismonotonic.c', 'hist_entropy.c', 'stdif.c', ) histogram_headers = files( 'phistogram.h', 'hist_unary.h', ) libvips_sources += histogram_sources histogram_lib = static_library('histogram', histogram_sources, histogram_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += histogram_lib libvips-8.18.2/libvips/histogram/percent.c000066400000000000000000000101511516303661500205370ustar00rootroot00000000000000/* find percent of pixels * * Copyright: 1990, N. Dessipris * * Author: N. Dessipris * Written on: 02/08/1990 * Modified on : 29/4/93 K.Martinez for Sys5 * 20/2/95 JC * - now returns result through parameter * - ANSIfied a little * 19/1/07 * - redone with the vips hist operators * 25/3/10 * - gtkdoc * 20/9/13 * - wrap as a class * - more accurate */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include typedef struct _VipsPercent { VipsOperation parent_instance; VipsImage *in; double percent; int threshold; } VipsPercent; typedef VipsOperationClass VipsPercentClass; G_DEFINE_TYPE(VipsPercent, vips_percent, VIPS_TYPE_OPERATION); static int vips_percent_build(VipsObject *object) { VipsPercent *percent = (VipsPercent *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); double threshold; if (VIPS_OBJECT_CLASS(vips_percent_parent_class)->build(object)) return -1; if (vips_hist_find(percent->in, &t[0], NULL) || vips_hist_cum(t[0], &t[1], NULL) || vips_hist_norm(t[1], &t[2], NULL) || vips_more_const1(t[2], &t[3], (percent->percent / 100.0) * t[2]->Xsize, NULL) || vips_profile(t[3], &t[5], &t[6], NULL) || vips_avg(t[6], &threshold, NULL)) return -1; g_object_set(object, "threshold", (int) threshold, NULL); return 0; } static void vips_percent_class_init(VipsPercentClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "percent"; object_class->description = _("find threshold for percent of pixels"); object_class->build = vips_percent_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPercent, in)); VIPS_ARG_DOUBLE(class, "percent", 2, _("Percent"), _("Percent of pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsPercent, percent), 0, 100, 50); VIPS_ARG_INT(class, "threshold", 3, _("Threshold"), _("Threshold above which lie percent of pixels"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsPercent, threshold), 0, 65535, 0); } static void vips_percent_init(VipsPercent *percent) { } /** * vips_percent: (method) * @in: input image * @percent: threshold percentage * @threshold: (out): output threshold value * @...: `NULL`-terminated list of optional named arguments * * [method@Image.percent] returns (through the @threshold parameter) the threshold * below which there are @percent values of @in. For example: * * ```bash * $ vips percent k2.jpg 90 * 214 * ``` * * Means that 90% of pixels in `k2.jpg` have a value less than 214. * * The function works for uchar and ushort images only. It can be used * to threshold the scaled result of a filtering operation. * * ::: seealso * [method@Image.hist_find], [method@Image.profile]. * * Returns: 0 on success, -1 on error */ int vips_percent(VipsImage *in, double percent, int *threshold, ...) { va_list ap; int result; va_start(ap, threshold); result = vips_call_split("percent", ap, in, percent, threshold); va_end(ap); return result; } libvips-8.18.2/libvips/histogram/phistogram.h000066400000000000000000000046611516303661500212720ustar00rootroot00000000000000/* base class for all histogram operations * * many hists in, one hist out, a buffer processing function in the class */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PHISTOGRAM_H #define VIPS_PHISTOGRAM_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_HISTOGRAM (vips_histogram_get_type()) #define VIPS_HISTOGRAM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_HISTOGRAM, VipsHistogram)) #define VIPS_HISTOGRAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_HISTOGRAM, VipsHistogramClass)) #define VIPS_IS_HISTOGRAM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_HISTOGRAM)) #define VIPS_IS_HISTOGRAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_HISTOGRAM)) #define VIPS_HISTOGRAM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_HISTOGRAM, VipsHistogramClass)) typedef struct _VipsHistogram VipsHistogram; typedef void (*VipsHistogramProcessFn)(VipsHistogram *histogram, VipsPel *out, VipsPel **in, int width); struct _VipsHistogram { VipsOperation parent_instance; VipsImage *out; /* NULL-terminated array of input images. */ VipsImage **in; int n; /* ... and transformed ready for processing. */ VipsImage **ready; }; typedef struct _VipsHistogramClass { VipsOperationClass parent_class; /* For each input format, what output format. */ const VipsBandFormat *format_table; /* If not VIPS_FORMAT_NOTSET, upcast all ins to this. */ VipsBandFormat input_format; VipsHistogramProcessFn process; } VipsHistogramClass; GType vips_histogram_get_type(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PHISTOGRAM_H*/ libvips-8.18.2/libvips/histogram/stdif.c000066400000000000000000000232761516303661500202240ustar00rootroot00000000000000/* statistical difference * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on : * 6/8/93 JC * - now works for odd window sizes * - ANSIfication * 25/5/95 JC * - new IM_ARRAY() macro * 25/1/96 JC * - im_lhisteq() adapted to make new im_stdif() * - now partial, plus rolling window * - 5x faster, amazingly * - works * 7/4/04 * - now uses im_embed() with edge stretching on the input, not * the output * 25/3/10 * - gtkdoc * - small cleanups * 10/8/13 * - wrapped as a class using hist_local.c * - many bands */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include typedef struct _VipsStdif { VipsOperation parent_instance; VipsImage *in; VipsImage *out; int width; int height; double a; double m0; double b; double s0; } VipsStdif; typedef VipsOperationClass VipsStdifClass; G_DEFINE_TYPE(VipsStdif, vips_stdif, VIPS_TYPE_OPERATION); /* How ugly and stupid. */ #define MAX_BANDS (100) static int vips_stdif_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsRegion *ir = (VipsRegion *) vseq; VipsImage *in = (VipsImage *) a; VipsStdif *stdif = (VipsStdif *) b; int bands = in->Bands; int npel = stdif->width * stdif->width; VipsRect irect; int y; int lsk; int centre; /* Offset to move to centre of window */ /* What part of ir do we need? */ irect.left = out_region->valid.left; irect.top = out_region->valid.top; irect.width = out_region->valid.width + stdif->width; irect.height = out_region->valid.height + stdif->height; if (vips_region_prepare(ir, &irect)) return -1; lsk = VIPS_REGION_LSKIP(ir); centre = lsk * (stdif->height / 2) + stdif->width / 2; for (y = 0; y < r->height; y++) { /* Get input and output pointers for this line. */ VipsPel *p = VIPS_REGION_ADDR(ir, r->left, r->top + y); VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); double f1 = stdif->a * stdif->m0; double f2 = 1.0 - stdif->a; double f3 = stdif->b * stdif->s0; VipsPel *p1; int x, i, j, b; /* We will get int overflow for windows larger than about 256 * x 256, sadly. */ unsigned int sum[MAX_BANDS]; unsigned int sum2[MAX_BANDS]; /* Find sum, sum of squares for the start of this line. */ for (b = 0; b < bands; b++) { memset(sum, 0, bands * sizeof(unsigned int)); memset(sum2, 0, bands * sizeof(unsigned int)); } p1 = p; for (j = 0; j < stdif->height; j++) { i = 0; for (x = 0; x < stdif->width; x++) { for (b = 0; b < bands; b++) { int t = p1[i++]; sum[b] += t; sum2[b] += t * t; } } p1 += lsk; } /* Loop for output pels. */ for (x = 0; x < r->width; x++) { for (b = 0; b < bands; b++) { /* Find stats. */ double mean = (double) sum[b] / npel; double var = (double) sum2[b] / npel - (mean * mean); double sig = sqrt(var); /* Transform. */ double res = f1 + f2 * mean + ((double) p[centre] - mean) * (f3 / (stdif->s0 + stdif->b * sig)); /* And write. */ if (res < 0.0) *q++ = 0; else if (res >= 256.0) *q++ = 255; else *q++ = res + 0.5; /* Adapt sums - remove the pels from the left * hand column, add in pels for a new * right-hand column. */ p1 = p; for (j = 0; j < stdif->height; j++) { int t1 = p1[0]; int t2 = p1[bands * stdif->width]; sum[b] -= t1; sum2[b] -= t1 * t1; sum[b] += t2; sum2[b] += t2 * t2; p1 += lsk; } p += 1; } } } return 0; } static int vips_stdif_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsStdif *stdif = (VipsStdif *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_stdif_parent_class)->build(object)) return -1; in = stdif->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (vips_check_format(class->nickname, in, VIPS_FORMAT_UCHAR)) return -1; if (stdif->width > in->Xsize || stdif->height > in->Ysize) { vips_error(class->nickname, "%s", _("window too large")); return -1; } if (in->Bands > MAX_BANDS) { vips_error(class->nickname, "%s", _("too many bands")); return -1; } /* Expand the input. */ if (vips_embed(in, &t[1], stdif->width / 2, stdif->height / 2, in->Xsize + stdif->width - 1, in->Ysize + stdif->height - 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[1]; g_object_set(object, "out", vips_image_new(), NULL); /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause * too many recalculations on overlaps. */ if (vips_image_pipelinev(stdif->out, VIPS_DEMAND_STYLE_FATSTRIP, in, NULL)) return -1; stdif->out->Xsize -= stdif->width - 1; stdif->out->Ysize -= stdif->height - 1; if (vips_image_generate(stdif->out, vips_start_one, vips_stdif_generate, vips_stop_one, in, stdif)) return -1; stdif->out->Xoffset = 0; stdif->out->Yoffset = 0; vips_reorder_margin_hint(stdif->out, stdif->width * stdif->height); return 0; } static void vips_stdif_class_init(VipsStdifClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "stdif"; object_class->description = _("statistical difference"); object_class->build = vips_stdif_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsStdif, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsStdif, out)); /* Windows larger than 256x256 will overflow sum2, see above. */ VIPS_ARG_INT(class, "width", 4, _("Width"), _("Window width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsStdif, width), 1, 256, 11); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Window height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsStdif, height), 1, 256, 11); VIPS_ARG_DOUBLE(class, "a", 2, _("Mean weight"), _("Weight of new mean"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsStdif, a), 0.0, 1.0, 0.5); VIPS_ARG_DOUBLE(class, "m0", 2, _("Mean"), _("New mean"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsStdif, m0), -INFINITY, INFINITY, 128); VIPS_ARG_DOUBLE(class, "b", 2, _("Deviation weight"), _("Weight of new deviation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsStdif, b), 0.0, 2.0, 0.5); VIPS_ARG_DOUBLE(class, "s0", 2, _("Deviation"), _("New deviation"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsStdif, s0), -INFINITY, INFINITY, 50); } static void vips_stdif_init(VipsStdif *stdif) { stdif->width = 11; stdif->height = 11; stdif->a = 0.5; stdif->m0 = 128.0; stdif->b = 0.5; stdif->s0 = 50.0; } /** * vips_stdif: (method) * @in: input image * @out: (out): output image * @width: width of region * @height: height of region * @...: `NULL`-terminated list of optional named arguments * * [method@Image.stdif] performs statistical differencing according to the * formula given in page 45 of the book "An Introduction to Digital Image * Processing" by Wayne Niblack. * * This transformation emphasises the way in * which a pel differs statistically from its neighbours. It is useful for * enhancing low-contrast images with lots of detail, such as X-ray plates. * * At point (i,j) the output is given by the equation: * * ``` * vout(i,j) = @a * @m0 + (1 - @a) * meanv + * (vin(i,j) - meanv) * (@b * @s0) / (@s0 + @b * stdv) * ``` * * Values @a, @m0, @b and @s0 are entered, while meanv and stdv are the values * calculated over a moving window of size @width, @height centred on pixel * (i,j). @m0 is the new mean, @a is the weight given to it. @s0 is the new * standard deviation, @b is the weight given to it. * * Try: * * ``` * vips stdif $VIPSHOME/pics/huysum.v fred.v 0.5 128 0.5 50 11 11 * ``` * * The operation works on one-band uchar images only, and writes a one-band * uchar image as its result. The output image has the same size as the * input. * * ::: tip "Optional arguments" * * @a: `gdouble`, weight of new mean * * @m0: `gdouble`, target mean * * @b: `gdouble`, weight of new deviation * * @s0: `gdouble`, target deviation * * ::: seealso * [method@Image.hist_local]. * * Returns: 0 on success, -1 on error */ int vips_stdif(VipsImage *in, VipsImage **out, int width, int height, ...) { va_list ap; int result; va_start(ap, height); result = vips_call_split("stdif", ap, in, out, width, height); va_end(ap); return result; } libvips-8.18.2/libvips/include/000077500000000000000000000000001516303661500163635ustar00rootroot00000000000000libvips-8.18.2/libvips/include/vips/000077500000000000000000000000001516303661500173445ustar00rootroot00000000000000libvips-8.18.2/libvips/include/vips/almostdeprecated.h000066400000000000000000000362331516303661500230440ustar00rootroot00000000000000/* Old and broken stuff that we still enable by default, but don't document * and certainly don't recommend. * * 30/6/09 * - from vips.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IM_ALMOSTDEPRECATED_H #define IM_ALMOSTDEPRECATED_H #ifndef VIPS_VIPS7COMPAT_H #error Should not be included directly use vips7compat.h instead #endif #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Was public, now deprecated. */ typedef enum /*< skip >*/ { IM_BBITS_BYTE = 8, IM_BBITS_SHORT = 16, IM_BBITS_INT = 32, IM_BBITS_FLOAT = 32, IM_BBITS_COMPLEX = 64, IM_BBITS_DOUBLE = 64, IM_BBITS_DPCOMPLEX = 128 } VipsBBits; /* Used to define a region of interest for im_extract() etc. Too boring to be * public API, see im_extract_area() etc. */ typedef struct { int xstart; int ystart; int xsize; int ysize; int chsel; /* 1 2 3 or 0, for r g b or all respectively *(channel select) */ } IMAGE_BOX; VIPS_DEPRECATED int im_extract(IMAGE *, IMAGE *, IMAGE_BOX *); VIPS_DEPRECATED DOUBLEMASK *im_measure(IMAGE *im, IMAGE_BOX *box, int h, int v, int *sel, int nsel, const char *name); VIPS_DEPRECATED gboolean im_isuint(IMAGE *im); VIPS_DEPRECATED gboolean im_isint(IMAGE *im); VIPS_DEPRECATED gboolean im_isfloat(IMAGE *im); VIPS_DEPRECATED gboolean im_isscalar(IMAGE *im); VIPS_DEPRECATED gboolean im_iscomplex(IMAGE *im); VIPS_DEPRECATED int im_c2ps(IMAGE *in, IMAGE *out); VIPS_DEPRECATED int im_clip(IMAGE *in, IMAGE *out); #define MASK_IDEAL_HIGHPASS IM_MASK_IDEAL_HIGHPASS #define MASK_IDEAL_LOWPASS IM_MASK_IDEAL_LOWPASS #define MASK_BUTTERWORTH_HIGHPASS IM_MASK_BUTTERWORTH_HIGHPASS #define MASK_BUTTERWORTH_LOWPASS IM_MASK_BUTTERWORTH_LOWPASS #define MASK_GAUSS_HIGHPASS IM_MASK_GAUSS_HIGHPASS #define MASK_GAUSS_LOWPASS IM_MASK_GAUSS_LOWPASS #define MASK_IDEAL_RINGPASS IM_MASK_IDEAL_RINGPASS #define MASK_IDEAL_RINGREJECT IM_MASK_IDEAL_RINGREJECT #define MASK_BUTTERWORTH_RINGPASS IM_MASK_BUTTERWORTH_RINGPASS #define MASK_BUTTERWORTH_RINGREJECT IM_MASK_BUTTERWORTH_RINGREJECT #define MASK_GAUSS_RINGPASS IM_MASK_GAUSS_RINGPASS #define MASK_GAUSS_RINGREJECT IM_MASK_GAUSS_RINGREJECT #define MASK_IDEAL_BANDPASS IM_MASK_IDEAL_BANDPASS #define MASK_IDEAL_BANDREJECT IM_MASK_IDEAL_BANDREJECT #define MASK_BUTTERWORTH_BANDPASS IM_MASK_BUTTERWORTH_BANDPASS #define MASK_BUTTERWORTH_BANDREJECT IM_MASK_BUTTERWORTH_BANDREJECT #define MASK_GAUSS_BANDPASS IM_MASK_GAUSS_BANDPASS #define MASK_GAUSS_BANDREJECT IM_MASK_GAUSS_BANDREJECT #define MASK_FRACTAL_FLT IM_MASK_FRACTAL_FLT #define MaskType ImMaskType /* Copy and swap types. */ typedef enum /*< skip >*/ { IM_ARCH_NATIVE, IM_ARCH_BYTE_SWAPPED, IM_ARCH_LSB_FIRST, IM_ARCH_MSB_FIRST } im_arch_type; VIPS_DEPRECATED gboolean im_isnative(im_arch_type arch); VIPS_DEPRECATED int im_copy_from(IMAGE *in, IMAGE *out, im_arch_type architecture); /* Backwards compatibility macros. */ #define im_clear_error_string() im_error_clear() #define im_errorstring() im_error_buffer() /* Deprecated API. */ VIPS_DEPRECATED_FOR(vips_error) void im_errormsg(const char *fmt, ...) G_GNUC_PRINTF(1, 2); VIPS_DEPRECATED_FOR(vips_verror) void im_verrormsg(const char *fmt, va_list ap); VIPS_DEPRECATED_FOR(vips_error_system) void im_errormsg_system(int err, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_DEPRECATED_FOR(g_info) void im_diagnostics(const char *fmt, ...) G_GNUC_PRINTF(1, 2); VIPS_DEPRECATED_FOR(g_warning) void im_warning(const char *fmt, ...) G_GNUC_PRINTF(1, 2); VIPS_DEPRECATED_FOR(g_mutex_init) GMutex *vips_g_mutex_new(void); VIPS_DEPRECATED_FOR(g_mutex_clear) void vips_g_mutex_free(GMutex *); VIPS_DEPRECATED_FOR(g_cond_init) GCond *vips_g_cond_new(void); VIPS_DEPRECATED_FOR(g_cond_clear) void vips_g_cond_free(GCond *); VIPS_DEPRECATED_FOR(g_thread_join) void *vips_g_thread_join(GThread *thread); VIPS_DEPRECATED int im_iterate(VipsImage *im, VipsStartFn start, im_generate_fn generate, VipsStopFn stop, void *a, void *b); /* Async rendering. */ VIPS_DEPRECATED_FOR(vips_sink_screen) int im_render_priority(VipsImage *in, VipsImage *out, VipsImage *mask, int width, int height, int max, int priority, void (*notify)(VipsImage *, VipsRect *, void *), void *client); VIPS_DEPRECATED_FOR(vips_sink_screen) int im_cache(VipsImage *in, VipsImage *out, int width, int height, int max); /* Deprecated operations. */ VIPS_DEPRECATED int im_cmulnorm(IMAGE *in1, IMAGE *in2, IMAGE *out); VIPS_DEPRECATED int im_fav4(IMAGE **, IMAGE *); VIPS_DEPRECATED int im_gadd(double, IMAGE *, double, IMAGE *, double, IMAGE *); VIPS_DEPRECATED int im_litecor(IMAGE *, IMAGE *, IMAGE *, int, double); VIPS_DEPRECATED_FOR(vips_sink_screen) int im_render_fade(IMAGE *in, IMAGE *out, IMAGE *mask, int width, int height, int max, int fps, int steps, int priority, void (*notify)(IMAGE *, VipsRect *, void *), void *client); VIPS_DEPRECATED_FOR(vips_sink_screen) int im_render(IMAGE *in, IMAGE *out, IMAGE *mask, int width, int height, int max, void (*notify)(IMAGE *, VipsRect *, void *), void *client); VIPS_DEPRECATED int im_cooc_matrix(IMAGE *im, IMAGE *m, int xp, int yp, int xs, int ys, int dx, int dy, int flag); VIPS_DEPRECATED int im_cooc_asm(IMAGE *m, double *asmoment); VIPS_DEPRECATED int im_cooc_contrast(IMAGE *m, double *contrast); VIPS_DEPRECATED int im_cooc_correlation(IMAGE *m, double *correlation); VIPS_DEPRECATED int im_cooc_entropy(IMAGE *m, double *entropy); VIPS_DEPRECATED int im_glds_matrix(IMAGE *im, IMAGE *m, int xpos, int ypos, int xsize, int ysize, int dx, int dy); VIPS_DEPRECATED int im_glds_asm(IMAGE *m, double *asmoment); VIPS_DEPRECATED int im_glds_contrast(IMAGE *m, double *contrast); VIPS_DEPRECATED int im_glds_entropy(IMAGE *m, double *entropy); VIPS_DEPRECATED int im_glds_mean(IMAGE *m, double *mean); VIPS_DEPRECATED int im_dif_std(IMAGE *im, int xpos, int ypos, int xsize, int ysize, int dx, int dy, double *pmean, double *pstd); VIPS_DEPRECATED int im_simcontr(IMAGE *out, int xsize, int ysize); VIPS_DEPRECATED int im_spatres(IMAGE *in, IMAGE *out, int step); VIPS_DEPRECATED int im_stretch3(IMAGE *in, IMAGE *out, double dx, double dy); /* Renamed operations. */ /* arithmetic */ VIPS_DEPRECATED_FOR(vips_remainder_const) int im_remainderconst_vec(IMAGE *in, IMAGE *out, int n, double *c); /* boolean */ VIPS_DEPRECATED_FOR(vips_andimage_const1) int im_andconst(IMAGE *, IMAGE *, double); VIPS_DEPRECATED_FOR(vips_andimage_const) int im_and_vec(IMAGE *, IMAGE *, int, double *); VIPS_DEPRECATED_FOR(vips_orimage_const1) int im_orconst(IMAGE *, IMAGE *, double); VIPS_DEPRECATED_FOR(vips_orimage_const) int im_or_vec(IMAGE *, IMAGE *, int, double *); VIPS_DEPRECATED_FOR(vips_eorimage_const1) int im_eorconst(IMAGE *, IMAGE *, double); VIPS_DEPRECATED_FOR(vips_eorimage_const) int im_eor_vec(IMAGE *, IMAGE *, int, double *); /* mosaicing */ VIPS_DEPRECATED_FOR(vips_affine) int im_affine(IMAGE *in, IMAGE *out, double a, double b, double c, double d, double dx, double dy, int ox, int oy, int ow, int oh); VIPS_DEPRECATED_FOR(vips_similarity) int im_similarity(IMAGE *in, IMAGE *out, double a, double b, double dx, double dy); VIPS_DEPRECATED_FOR(vips_similarity) int im_similarity_area(IMAGE *in, IMAGE *out, double a, double b, double dx, double dy, int ox, int oy, int ow, int oh); /* colour */ VIPS_DEPRECATED_FOR(vips_icc_export) int im_icc_export(IMAGE *in, IMAGE *out, const char *output_profile_filename, int intent); /* conversion */ VIPS_DEPRECATED_FOR(vips_cast) int im_clip2dcm(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2cm(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2us(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2ui(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2s(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2i(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2d(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2f(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2c(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_tilecache) int vips_cache(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_DEPRECATED int im_slice(IMAGE *in, IMAGE *out, double, double); VIPS_DEPRECATED int im_thresh(IMAGE *in, IMAGE *out, double); VIPS_DEPRECATED_FOR(printf) int im_print(const char *message); VIPS_DEPRECATED int im_convsub(IMAGE *in, IMAGE *out, INTMASK *mask, int xskip, int yskip); VIPS_DEPRECATED int im_bernd(const char *tiffname, int x, int y, int w, int h); VIPS_DEPRECATED int im_resize_linear(IMAGE *, IMAGE *, int, int); VIPS_DEPRECATED_FOR(vips_convf) int im_convf(IMAGE *in, IMAGE *out, DOUBLEMASK *mask); VIPS_DEPRECATED_FOR(vips_convsep) int im_convsepf(IMAGE *in, IMAGE *out, DOUBLEMASK *mask); VIPS_DEPRECATED int im_conv_raw(IMAGE *in, IMAGE *out, INTMASK *mask); VIPS_DEPRECATED int im_convf_raw(IMAGE *in, IMAGE *out, DOUBLEMASK *mask); VIPS_DEPRECATED int im_convsep_raw(IMAGE *in, IMAGE *out, INTMASK *mask); VIPS_DEPRECATED int im_convsepf_raw(IMAGE *in, IMAGE *out, DOUBLEMASK *mask); VIPS_DEPRECATED int im_fastcor_raw(IMAGE *in, IMAGE *ref, IMAGE *out); VIPS_DEPRECATED int im_spcor_raw(IMAGE *in, IMAGE *ref, IMAGE *out); VIPS_DEPRECATED int im_gradcor_raw(IMAGE *in, IMAGE *ref, IMAGE *out); VIPS_DEPRECATED int im_contrast_surface_raw(IMAGE *in, IMAGE *out, int half_win_size, int spacing); VIPS_DEPRECATED_FOR(vips_stdif) int im_stdif_raw(IMAGE *in, IMAGE *out, double a, double m0, double b, double s0, int xwin, int ywin); VIPS_DEPRECATED_FOR(vips_hist_local) int im_lhisteq_raw(IMAGE *in, IMAGE *out, int xwin, int ywin); VIPS_DEPRECATED_FOR(vips_morph) int im_erode_raw(IMAGE *in, IMAGE *out, INTMASK *m); VIPS_DEPRECATED_FOR(vips_morph) int im_dilate_raw(IMAGE *in, IMAGE *out, INTMASK *m); VIPS_DEPRECATED int im_rank_raw(IMAGE *in, IMAGE *out, int xsize, int ysize, int order); /* foreign */ /** * VipsForeignJpegSubsample: * @VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO: default preset * @VIPS_FOREIGN_JPEG_SUBSAMPLE_ON: always perform subsampling * @VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF: never perform subsampling * * Set jpeg subsampling mode. * * DEPRECATED: use [enum@ForeignSubsample] */ typedef enum { VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO, VIPS_FOREIGN_JPEG_SUBSAMPLE_ON, VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF, VIPS_FOREIGN_JPEG_SUBSAMPLE_LAST /*< skip >*/ } VipsForeignJpegSubsample; VIPS_DEPRECATED_FOR(vips_rawsave_target) int vips_rawsave_fd(VipsImage *in, int fd, ...) G_GNUC_NULL_TERMINATED; /* inplace */ VIPS_DEPRECATED_FOR(vips_draw_circle) int im_circle(IMAGE *im, int cx, int cy, int radius, int intensity); VIPS_DEPRECATED_FOR(vips_draw_line1) int im_line(IMAGE *, int, int, int, int, int); VIPS_DEPRECATED_FOR(vips_labelregions) int im_segment(IMAGE *test, IMAGE *mask, int *segments); VIPS_DEPRECATED_FOR(vips_draw_rect) int im_paintrect(IMAGE *im, VipsRect *r, PEL *ink); VIPS_DEPRECATED_FOR(vips_draw_image) int im_insertplace(IMAGE *main, IMAGE *sub, int x, int y); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_flood_copy(IMAGE *in, IMAGE *out, int x, int y, PEL *ink); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_flood_blob_copy(IMAGE *in, IMAGE *out, int x, int y, PEL *ink); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_flood_other_copy(IMAGE *test, IMAGE *mark, IMAGE *out, int x, int y, int serial); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_flood(IMAGE *im, int x, int y, PEL *ink, VipsRect *dout); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_flood_blob(IMAGE *im, int x, int y, PEL *ink, VipsRect *dout); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_flood_other(IMAGE *test, IMAGE *mark, int x, int y, int serial, VipsRect *dout); VIPS_DEPRECATED_FOR(vips_draw_line) int im_fastline(IMAGE *im, int x1, int y1, int x2, int y2, PEL *pel); VIPS_DEPRECATED_FOR(vips_draw_line) int im_fastlineuser(IMAGE *im, int x1, int y1, int x2, int y2, VipsPlotFn fn, void *client1, void *client2, void *client3); VIPS_DEPRECATED_FOR(vips_draw_mask) int im_plotmask(IMAGE *im, int ix, int iy, PEL *ink, PEL *mask, VipsRect *r); VIPS_DEPRECATED_FOR(vips_getpoint) int im_readpoint(IMAGE *im, int x, int y, PEL *pel); VIPS_DEPRECATED_FOR(vips_draw_point) int im_plotpoint(IMAGE *im, int x, int y, PEL *pel); VIPS_DEPRECATED_FOR(vips_draw_smudge) int im_smudge(IMAGE *image, int ix, int iy, VipsRect *r); VIPS_DEPRECATED int im_smear(IMAGE *im, int ix, int iy, VipsRect *r); VIPS_DEPRECATED_FOR(g_warning) void vips_warn(const char *domain, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_DEPRECATED_FOR(g_warning) void vips_vwarn(const char *domain, const char *fmt, va_list ap); VIPS_DEPRECATED void vips_info_set(gboolean info); VIPS_DEPRECATED_FOR(g_info) void vips_info(const char *domain, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_DEPRECATED_FOR(g_info) void vips_vinfo(const char *domain, const char *fmt, va_list ap); VIPS_DEPRECATED_FOR(vips_autorot) VipsAngle vips_autorot_get_angle(VipsImage *image); VIPS_DEPRECATED_FOR(vips_thread_isvips) gboolean vips_thread_isworker(void); /* iofuncs */ VIPS_DEPRECATED_FOR(g_free) int vips_free(void *buf); VIPS_DEPRECATED_FOR(vips_target_end) void vips_target_finish(VipsTarget *target); VIPS_DEPRECATED_FOR(vips_cache_operation_buildp) VipsOperation *vips_cache_operation_lookup(VipsOperation *operation); VIPS_DEPRECATED_FOR(vips_cache_operation_buildp) void vips_cache_operation_add(VipsOperation *operation); VIPS_DEPRECATED_FOR(g_strlcpy) char *vips_strncpy(char *dest, const char *src, int n); VIPS_DEPRECATED_FOR(g_strrstr) char *vips_strrstr(const char *haystack, const char *needle); VIPS_DEPRECATED_FOR(g_str_has_suffix) gboolean vips_ispostfix(const char *a, const char *b); VIPS_DEPRECATED_FOR(g_vsnprintf) int vips_vsnprintf(char *str, size_t size, const char *format, va_list ap); VIPS_DEPRECATED_FOR(g_snprintf) int vips_snprintf(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4); /* This has been deprecated and replaced by VipsForeignSaveable. Implement * this with macros to stop C++ enum assignment errors. */ #define VipsSaveable VipsForeignSaveable #define VIPS_SAVEABLE_ANY VIPS_FOREIGN_SAVEABLE_ANY #define VIPS_SAVEABLE_MONO VIPS_FOREIGN_SAVEABLE_MONO #define VIPS_SAVEABLE_RGB \ (VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB) #define VIPS_SAVEABLE_RGBA \ (VIPS_FOREIGN_SAVEABLE_MONO | \ VIPS_FOREIGN_SAVEABLE_RGB | \ VIPS_FOREIGN_SAVEABLE_ALPHA) #define VIPS_SAVEABLE_RGBA_ONLY \ (VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_ALPHA) #define VIPS_SAVEABLE_RGB_CMYK \ (VIPS_FOREIGN_SAVEABLE_MONO | \ VIPS_FOREIGN_SAVEABLE_RGB | \ VIPS_FOREIGN_SAVEABLE_CMYK) #define VIPS_SAVEABLE_LAST (99) #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*IM_ALMOSTDEPRECATED_H*/ libvips-8.18.2/libvips/include/vips/arithmetic.h000066400000000000000000000417751516303661500216640ustar00rootroot00000000000000/* Headers for arithmetic * * 30/6/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_ARITHMETIC_H #define VIPS_ARITHMETIC_H #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /** * VipsOperationMath: * @VIPS_OPERATION_MATH_SIN: `sin()`, angles in degrees * @VIPS_OPERATION_MATH_COS: `cos()`, angles in degrees * @VIPS_OPERATION_MATH_TAN: `tan()`, angles in degrees * @VIPS_OPERATION_MATH_ASIN: `asin()`, angles in degrees * @VIPS_OPERATION_MATH_ACOS: `acos()`, angles in degrees * @VIPS_OPERATION_MATH_ATAN: `atan()`, angles in degrees * @VIPS_OPERATION_MATH_LOG: log base e * @VIPS_OPERATION_MATH_LOG10: log base 10 * @VIPS_OPERATION_MATH_EXP: e to the something * @VIPS_OPERATION_MATH_EXP10: 10 to the something * @VIPS_OPERATION_MATH_SINH: `sinh()`, angles in radians * @VIPS_OPERATION_MATH_COSH: `cosh()`, angles in radians * @VIPS_OPERATION_MATH_TANH: `tanh()`, angles in radians * @VIPS_OPERATION_MATH_ASINH: `asinh()`, angles in radians * @VIPS_OPERATION_MATH_ACOSH: `acosh()`, angles in radians * @VIPS_OPERATION_MATH_ATANH: `atanh()`, angles in radians * * See also: [method@Image.math]. */ typedef enum { VIPS_OPERATION_MATH_SIN, VIPS_OPERATION_MATH_COS, VIPS_OPERATION_MATH_TAN, VIPS_OPERATION_MATH_ASIN, VIPS_OPERATION_MATH_ACOS, VIPS_OPERATION_MATH_ATAN, VIPS_OPERATION_MATH_LOG, VIPS_OPERATION_MATH_LOG10, VIPS_OPERATION_MATH_EXP, VIPS_OPERATION_MATH_EXP10, VIPS_OPERATION_MATH_SINH, VIPS_OPERATION_MATH_COSH, VIPS_OPERATION_MATH_TANH, VIPS_OPERATION_MATH_ASINH, VIPS_OPERATION_MATH_ACOSH, VIPS_OPERATION_MATH_ATANH, VIPS_OPERATION_MATH_LAST /*< skip >*/ } VipsOperationMath; /** * VipsOperationMath2: * @VIPS_OPERATION_MATH2_POW: `pow(left, right)` * @VIPS_OPERATION_MATH2_WOP: `pow(right, left)` * @VIPS_OPERATION_MATH2_ATAN2: `atan2(left, right)` * * See also: [method@Image.math]. */ typedef enum { VIPS_OPERATION_MATH2_POW, VIPS_OPERATION_MATH2_WOP, VIPS_OPERATION_MATH2_ATAN2, VIPS_OPERATION_MATH2_LAST /*< skip >*/ } VipsOperationMath2; /** * VipsOperationRound: * @VIPS_OPERATION_ROUND_RINT: round to nearest * @VIPS_OPERATION_ROUND_FLOOR: largest integral value not greater than * @VIPS_OPERATION_ROUND_CEIL: the smallest integral value not less than * * See also: [method@Image.round]. */ typedef enum { VIPS_OPERATION_ROUND_RINT, VIPS_OPERATION_ROUND_CEIL, VIPS_OPERATION_ROUND_FLOOR, VIPS_OPERATION_ROUND_LAST /*< skip >*/ } VipsOperationRound; /** * VipsOperationRelational: * @VIPS_OPERATION_RELATIONAL_EQUAL: `==` * @VIPS_OPERATION_RELATIONAL_NOTEQ: `!=` * @VIPS_OPERATION_RELATIONAL_LESS: `<` * @VIPS_OPERATION_RELATIONAL_LESSEQ: `<=` * @VIPS_OPERATION_RELATIONAL_MORE: `>` * @VIPS_OPERATION_RELATIONAL_MOREEQ: `>=` * * See also: [method@Image.relational]. */ typedef enum { VIPS_OPERATION_RELATIONAL_EQUAL, VIPS_OPERATION_RELATIONAL_NOTEQ, VIPS_OPERATION_RELATIONAL_LESS, VIPS_OPERATION_RELATIONAL_LESSEQ, VIPS_OPERATION_RELATIONAL_MORE, VIPS_OPERATION_RELATIONAL_MOREEQ, VIPS_OPERATION_RELATIONAL_LAST /*< skip >*/ } VipsOperationRelational; /** * VipsOperationBoolean: * @VIPS_OPERATION_BOOLEAN_AND: `&` * @VIPS_OPERATION_BOOLEAN_OR: `|` * @VIPS_OPERATION_BOOLEAN_EOR: `^` * @VIPS_OPERATION_BOOLEAN_LSHIFT: `>>` * @VIPS_OPERATION_BOOLEAN_RSHIFT: `<<` * * See also: [method@Image.boolean]. */ typedef enum { VIPS_OPERATION_BOOLEAN_AND, VIPS_OPERATION_BOOLEAN_OR, VIPS_OPERATION_BOOLEAN_EOR, VIPS_OPERATION_BOOLEAN_LSHIFT, VIPS_OPERATION_BOOLEAN_RSHIFT, VIPS_OPERATION_BOOLEAN_LAST /*< skip >*/ } VipsOperationBoolean; /** * VipsOperationComplex: * @VIPS_OPERATION_COMPLEX_POLAR: convert to polar coordinates * @VIPS_OPERATION_COMPLEX_RECT: convert to rectangular coordinates * @VIPS_OPERATION_COMPLEX_CONJ: complex conjugate * * See also: [method@Image.complex]. */ typedef enum { VIPS_OPERATION_COMPLEX_POLAR, VIPS_OPERATION_COMPLEX_RECT, VIPS_OPERATION_COMPLEX_CONJ, VIPS_OPERATION_COMPLEX_LAST /*< skip >*/ } VipsOperationComplex; /** * VipsOperationComplex2: * @VIPS_OPERATION_COMPLEX2_CROSS_PHASE: convert to polar coordinates * * See also: [method@Image.complex2]. */ typedef enum { VIPS_OPERATION_COMPLEX2_CROSS_PHASE, /*< nick=cross-phase >*/ VIPS_OPERATION_COMPLEX2_LAST /*< skip >*/ } VipsOperationComplex2; /** * VipsOperationComplexget: * @VIPS_OPERATION_COMPLEXGET_REAL: get real component * @VIPS_OPERATION_COMPLEXGET_IMAG: get imaginary component * * See also: [method@Image.complexget]. */ typedef enum { VIPS_OPERATION_COMPLEXGET_REAL, VIPS_OPERATION_COMPLEXGET_IMAG, VIPS_OPERATION_COMPLEXGET_LAST /*< skip >*/ } VipsOperationComplexget; VIPS_API int vips_add(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sum(VipsImage **in, VipsImage **out, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_subtract(VipsImage *in1, VipsImage *in2, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_multiply(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_divide(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_linear(VipsImage *in, VipsImage **out, const double *a, const double *b, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_linear1(VipsImage *in, VipsImage **out, double a, double b, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_remainder(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_remainder_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_remainder_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_invert(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_abs(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sign(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_clamp(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_maxpair(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_minpair(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_round(VipsImage *in, VipsImage **out, VipsOperationRound round, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_floor(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_ceil(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rint(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_math(VipsImage *in, VipsImage **out, VipsOperationMath math, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sin(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cos(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tan(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_asin(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_acos(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_atan(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_exp(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_exp10(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_log(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_log10(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sinh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cosh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tanh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_asinh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_acosh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_atanh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_complex(VipsImage *in, VipsImage **out, VipsOperationComplex cmplx, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_polar(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rect(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_conj(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_complex2(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationComplex2 cmplx, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cross_phase(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_complexget(VipsImage *in, VipsImage **out, VipsOperationComplexget get, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_real(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_imag(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_complexform(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_relational(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationRelational relational, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_equal(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_notequal(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_less(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_lesseq(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_more(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_moreeq(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_relational_const(VipsImage *in, VipsImage **out, VipsOperationRelational relational, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_equal_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_notequal_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_less_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_lesseq_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_more_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_moreeq_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_relational_const1(VipsImage *in, VipsImage **out, VipsOperationRelational relational, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_equal_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_notequal_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_less_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_lesseq_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_more_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_moreeq_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_boolean(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationBoolean boolean, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_andimage(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_orimage(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_eorimage(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_lshift(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rshift(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_boolean_const(VipsImage *in, VipsImage **out, VipsOperationBoolean boolean, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_andimage_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_orimage_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_eorimage_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_lshift_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rshift_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_boolean_const1(VipsImage *in, VipsImage **out, VipsOperationBoolean boolean, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_andimage_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_orimage_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_eorimage_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_lshift_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rshift_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_math2(VipsImage *left, VipsImage *right, VipsImage **out, VipsOperationMath2 math2, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pow(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_wop(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_atan2(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_math2_const(VipsImage *in, VipsImage **out, VipsOperationMath2 math2, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pow_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_wop_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_atan2_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_math2_const1(VipsImage *in, VipsImage **out, VipsOperationMath2 math2, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pow_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_wop_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_atan2_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_avg(VipsImage *in, double *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_deviate(VipsImage *in, double *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_min(VipsImage *in, double *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_max(VipsImage *in, double *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_stats(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_measure(VipsImage *in, VipsImage **out, int h, int v, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_find_trim(VipsImage *in, int *left, int *top, int *width, int *height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_getpoint(VipsImage *in, double **vector, int *n, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_find(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_find_ndim(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_find_indexed(VipsImage *in, VipsImage *index, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hough_line(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hough_circle(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_project(VipsImage *in, VipsImage **columns, VipsImage **rows, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_profile(VipsImage *in, VipsImage **columns, VipsImage **rows, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_ARITHMETIC_H*/ libvips-8.18.2/libvips/include/vips/basic.h000066400000000000000000000072251516303661500206040ustar00rootroot00000000000000/* A few basic types needed everywhere. * * 27/10/11 * - from type.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_BASIC_H #define VIPS_BASIC_H /* Defined in config.h */ #ifndef _VIPS_PUBLIC #define _VIPS_PUBLIC #endif #define VIPS_API _VIPS_PUBLIC extern /* VIPS_DISABLE_DEPRECATION_WARNINGS: * * Disable deprecation warnings from VIPS API. * * Must be defined before including `vips/vips.h`. */ #ifdef VIPS_DISABLE_DEPRECATION_WARNINGS #define VIPS_DEPRECATED VIPS_API #define VIPS_DEPRECATED_FOR(f) VIPS_API #else #define VIPS_DEPRECATED G_DEPRECATED VIPS_API #define VIPS_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) VIPS_API #endif #if !defined(VIPS_DISABLE_DEPRECATION_WARNINGS) && \ (G_GNUC_CHECK_VERSION(4, 6) || \ __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 4)) #define _VIPS_GNUC_DO_PRAGMA(x) _Pragma(G_STRINGIFY(x)) #define VIPS_DEPRECATED_MACRO _VIPS_GNUC_DO_PRAGMA(GCC warning "Deprecated pre-processor symbol") #define VIPS_DEPRECATED_MACRO_FOR(f) \ _VIPS_GNUC_DO_PRAGMA(GCC warning G_STRINGIFY(Deprecated pre-processor symbol: replace with #f)) #else #define VIPS_DEPRECATED_MACRO #define VIPS_DEPRECATED_MACRO_FOR(f) #endif #if !defined(VIPS_DISABLE_DEPRECATION_WARNINGS) && \ (G_GNUC_CHECK_VERSION(6, 1) || \ __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 0)) #define VIPS_DEPRECATED_ENUMERATOR G_DEPRECATED #define VIPS_DEPRECATED_ENUMERATOR_FOR(f) G_DEPRECATED_FOR(f) #else #define VIPS_DEPRECATED_ENUMERATOR #define VIPS_DEPRECATED_ENUMERATOR_FOR(f) #endif #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /** * VipsPel: * * A picture element. Cast this to whatever the associated VipsBandFormat says * to get the value. */ typedef unsigned char VipsPel; /* Also used for eg. vips_local() and friends. */ typedef int (*VipsCallbackFn)(void *a, void *b); /* Like GFunc, but return a value. */ typedef void *(*VipsSListMap2Fn)(void *item, void *a, void *b); typedef void *(*VipsSListMap4Fn)(void *item, void *a, void *b, void *c, void *d); typedef void *(*VipsSListFold2Fn)(void *item, void *a, void *b, void *c); typedef enum { VIPS_PRECISION_INTEGER, VIPS_PRECISION_FLOAT, VIPS_PRECISION_APPROXIMATE, VIPS_PRECISION_LAST /*< skip >*/ } VipsPrecision; #ifndef __GI_SCANNER__ /* Just for testing. */ VIPS_API char *vips_path_filename7(const char *path); VIPS_API char *vips_path_mode7(const char *path); #endif /* !__GI_SCANNER__ */ struct _VipsImage; typedef struct _VipsImage VipsImage; struct _VipsRegion; typedef struct _VipsRegion VipsRegion; struct _VipsBuf; typedef struct _VipsBuf VipsBuf; struct _VipsSource; typedef struct _VipsSource VipsSource; struct _VipsTarget; typedef struct _VipsTarget VipsTarget; struct _VipsInterpolate; typedef struct _VipsInterpolate VipsInterpolate; struct _VipsOperation; typedef struct _VipsOperation VipsOperation; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_BASIC_H*/ libvips-8.18.2/libvips/include/vips/buf.h000066400000000000000000000056341516303661500203010ustar00rootroot00000000000000/* A static string buffer, with overflow protection. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_BUF_H #define VIPS_BUF_H #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ struct _VipsBuf { /* All fields are private. */ /*< private >*/ char *base; /* String base */ int mx; /* Maximum length */ int i; /* Current write point */ gboolean full; /* String has filled, block writes */ int lasti; /* For read-recent */ gboolean dynamic; /* We own the string with malloc() */ }; #define VIPS_BUF_STATIC(TEXT) \ { \ &TEXT[0], sizeof(TEXT), 0, FALSE, 0, FALSE \ } /* Init and append to one of the above. */ VIPS_API void vips_buf_rewind(VipsBuf *buf); VIPS_API void vips_buf_destroy(VipsBuf *buf); VIPS_API void vips_buf_init(VipsBuf *buf); VIPS_API void vips_buf_set_static(VipsBuf *buf, char *base, int mx); VIPS_API void vips_buf_set_dynamic(VipsBuf *buf, int mx); VIPS_API void vips_buf_init_static(VipsBuf *buf, char *base, int mx); VIPS_API void vips_buf_init_dynamic(VipsBuf *buf, int mx); VIPS_API gboolean vips_buf_appendns(VipsBuf *buf, const char *str, int sz); VIPS_API gboolean vips_buf_appends(VipsBuf *buf, const char *str); VIPS_API gboolean vips_buf_appendf(VipsBuf *buf, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_API gboolean vips_buf_vappendf(VipsBuf *buf, const char *fmt, va_list ap); VIPS_API gboolean vips_buf_appendc(VipsBuf *buf, char ch); VIPS_API gboolean vips_buf_appendgv(VipsBuf *buf, GValue *value); VIPS_API gboolean vips_buf_append_size(VipsBuf *buf, size_t n); VIPS_API gboolean vips_buf_removec(VipsBuf *buf, char ch); VIPS_API gboolean vips_buf_change(VipsBuf *buf, const char *o, const char *n); VIPS_API gboolean vips_buf_is_empty(VipsBuf *buf); VIPS_API gboolean vips_buf_is_full(VipsBuf *buf); VIPS_API const char *vips_buf_all(VipsBuf *buf); VIPS_API const char *vips_buf_firstline(VipsBuf *buf); VIPS_API gboolean vips_buf_appendg(VipsBuf *buf, double g); VIPS_API gboolean vips_buf_appendd(VipsBuf *buf, int d); VIPS_API int vips_buf_len(VipsBuf *buf); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_BUF_H*/ libvips-8.18.2/libvips/include/vips/colour.h000066400000000000000000000203201516303661500210150ustar00rootroot00000000000000/* Definitions for VIPS colour package. * * J.Cupitt, 8/4/93 * 15/7/96 JC * - C++ stuff added * 20/2/98 JC * - new display calibration added * 26/9/05 * - added IM_ prefix to colour temps */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_COLOUR_H #define VIPS_COLOUR_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Areas under curves for Dxx. 2 degree observer. */ #define VIPS_D93_X0 (89.7400) #define VIPS_D93_Y0 (100.0) #define VIPS_D93_Z0 (130.7700) #define VIPS_D75_X0 (94.9682) #define VIPS_D75_Y0 (100.0) #define VIPS_D75_Z0 (122.5710) /* D65 temp 6504. */ #define VIPS_D65_X0 (95.0470) #define VIPS_D65_Y0 (100.0) #define VIPS_D65_Z0 (108.8827) #define VIPS_D55_X0 (95.6831) #define VIPS_D55_Y0 (100.0) #define VIPS_D55_Z0 (92.0871) #define VIPS_D50_X0 (96.4250) #define VIPS_D50_Y0 (100.0) #define VIPS_D50_Z0 (82.4680) /* A temp 2856k. */ #define VIPS_A_X0 (109.8503) #define VIPS_A_Y0 (100.0) #define VIPS_A_Z0 (35.5849) /* B temp 4874k. */ #define VIPS_B_X0 (99.0720) #define VIPS_B_Y0 (100.0) #define VIPS_B_Z0 (85.2230) /* C temp 6774k. */ #define VIPS_C_X0 (98.0700) #define VIPS_C_Y0 (100.0) #define VIPS_C_Z0 (118.2300) #define VIPS_E_X0 (100.0) #define VIPS_E_Y0 (100.0) #define VIPS_E_Z0 (100.0) #define VIPS_D3250_X0 (105.6590) #define VIPS_D3250_Y0 (100.0) #define VIPS_D3250_Z0 (45.8501) /* Note: constants align with those defined in lcms2.h, except for * VIPS_INTENT_AUTO, which is libvips-specific. */ typedef enum { VIPS_INTENT_PERCEPTUAL = 0, VIPS_INTENT_RELATIVE, VIPS_INTENT_SATURATION, VIPS_INTENT_ABSOLUTE, /* Leave room for possible new rendering intents beyond the * four standard ones. */ VIPS_INTENT_AUTO = 32, VIPS_INTENT_LAST /*< skip >*/ } VipsIntent; typedef enum { VIPS_PCS_LAB, VIPS_PCS_XYZ, VIPS_PCS_LAST /*< skip >*/ } VipsPCS; VIPS_API gboolean vips_colourspace_issupported(const VipsImage *image); VIPS_API int vips_colourspace(VipsImage *in, VipsImage **out, VipsInterpretation space, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LabQ2sRGB(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rad2float(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_float2rad(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LabS2LabQ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LabQ2LabS(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LabQ2Lab(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Lab2LabQ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LCh2Lab(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Lab2LCh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Lab2XYZ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_XYZ2Lab(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_XYZ2scRGB(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_scRGB2sRGB(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_scRGB2BW(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sRGB2scRGB(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_scRGB2XYZ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_HSV2sRGB(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sRGB2HSV(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LCh2CMC(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_CMC2LCh(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_XYZ2Yxy(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Yxy2XYZ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_LabS2Lab(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Lab2LabS(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_CMYK2XYZ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_XYZ2CMYK(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Oklab2XYZ(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_XYZ2Oklab(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Oklch2Oklab(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_Oklab2Oklch(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdr2scRGB(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_profile_load(const char *name, VipsBlob **profile, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_icc_present(void); VIPS_API int vips_icc_transform(VipsImage *in, VipsImage **out, const char *output_profile, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_icc_import(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_icc_export(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_icc_ac2rc(VipsImage *in, VipsImage **out, const char *profile_filename); VIPS_API gboolean vips_icc_is_compatible_profile(VipsImage *image, const void *data, size_t data_length); VIPS_API int vips_dE76(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dE00(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dECMC(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API void vips_col_Lab2XYZ(float L, float a, float b, float *X, float *Y, float *Z); VIPS_API void vips_col_XYZ2Lab(float X, float Y, float Z, float *L, float *a, float *b); VIPS_API double vips_col_ab2h(double a, double b); VIPS_API void vips_col_ab2Ch(float a, float b, float *C, float *h); VIPS_API void vips_col_Ch2ab(float C, float h, float *a, float *b); VIPS_API float vips_col_L2Lcmc(float L); VIPS_API float vips_col_C2Ccmc(float C); VIPS_API float vips_col_Ch2hcmc(float C, float h); VIPS_API void vips_col_make_tables_CMC(void); VIPS_API float vips_col_Lcmc2L(float Lcmc); VIPS_API float vips_col_Ccmc2C(float Ccmc); VIPS_API float vips_col_Chcmc2h(float C, float hcmc); VIPS_API int vips_col_sRGB2scRGB_8(int r, int g, int b, float *R, float *G, float *B); VIPS_API int vips_col_sRGB2scRGB_16(int r, int g, int b, float *R, float *G, float *B); VIPS_API int vips_col_sRGB2scRGB_8_noclip(int r, int g, int b, float *R, float *G, float *B); VIPS_API int vips_col_sRGB2scRGB_16_noclip(int r, int g, int b, float *R, float *G, float *B); VIPS_API int vips_col_scRGB2XYZ(float R, float G, float B, float *X, float *Y, float *Z); VIPS_API int vips_col_XYZ2scRGB(float X, float Y, float Z, float *R, float *G, float *B); VIPS_API int vips_col_scRGB2sRGB_8(float R, float G, float B, int *r, int *g, int *b, int *og); VIPS_API int vips_col_scRGB2sRGB_16(float R, float G, float B, int *r, int *g, int *b, int *og); VIPS_API int vips_col_scRGB2BW_16(float R, float G, float B, int *g, int *og); VIPS_API int vips_col_scRGB2BW_8(float R, float G, float B, int *g, int *og); VIPS_API float vips_pythagoras(float L1, float a1, float b1, float L2, float a2, float b2); VIPS_API float vips_col_dE00( float L1, float a1, float b1, float L2, float a2, float b2); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_COLOUR_H*/ libvips-8.18.2/libvips/include/vips/connection.h000066400000000000000000000376461516303661500216740ustar00rootroot00000000000000/* A byte source/sink .. it can be a pipe, socket, or perhaps a node.js stream. * * J.Cupitt, 19/6/14 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_CONNECTION_H #define VIPS_CONNECTION_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_CONNECTION (vips_connection_get_type()) #define VIPS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_CONNECTION, VipsConnection)) #define VIPS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_CONNECTION, VipsConnectionClass)) #define VIPS_IS_CONNECTION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_CONNECTION)) #define VIPS_IS_CONNECTION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_CONNECTION)) #define VIPS_CONNECTION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_CONNECTION, VipsConnectionClass)) typedef struct _VipsConnection { VipsObject parent_object; /*< private >*/ /* Read/write this fd if connected to a system pipe/socket. Override * ::read() and ::write() to do something else. */ int descriptor; /* A descriptor we close with vips_tracked_close(). */ int tracked_descriptor; /* A descriptor we close with close(). */ int close_descriptor; /* If descriptor is a file, the filename we opened. Handy for error * messages. */ char *filename; } VipsConnection; typedef struct _VipsConnectionClass { VipsObjectClass parent_class; } VipsConnectionClass; VIPS_API GType vips_connection_get_type(void); VIPS_API const char *vips_connection_filename(VipsConnection *connection); VIPS_API const char *vips_connection_nick(VipsConnection *connection); VIPS_API void vips_pipe_read_limit_set(gint64 limit); #define VIPS_TYPE_SOURCE (vips_source_get_type()) #define VIPS_SOURCE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_SOURCE, VipsSource)) #define VIPS_SOURCE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_SOURCE, VipsSourceClass)) #define VIPS_IS_SOURCE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_SOURCE)) #define VIPS_IS_SOURCE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_SOURCE)) #define VIPS_SOURCE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_SOURCE, VipsSourceClass)) struct _VipsSource { VipsConnection parent_object; /* We have two phases: * * During the header phase, we save bytes read from the input (if this * is an unseekable source) so that we can rewind and try again, if * necessary. * * Once we reach decode phase, we no longer support rewind and the * buffer of saved data is discarded. */ gboolean decode; /* TRUE if this input is something like a pipe. These don't support * seek or map -- all you can do is read() bytes sequentially. * * If you attempt to map or get the size of a pipe-style input, it'll * get read entirely into memory. Seeks will cause read up to the seek * point. */ gboolean have_tested_seek; gboolean is_pipe; /* The current read point and length. * * length is -1 for is_pipe sources. * * off_t can be 32 bits on some platforms, so make sure we have a * full 64. */ gint64 read_position; gint64 length; /*< private >*/ /* For sources where we have the whole image in memory (from a memory * buffer, from mmaping the file, from reading the pipe into memory), * a pointer to the start. */ const void *data; /* For is_pipe sources, save data read during header phase here. If * we rewind and try again, serve data from this until it runs out. * * If we need to force the whole pipe into memory, read everything to * this and put a copy of the pointer in data. */ GByteArray *header_bytes; /* Save the first few bytes here for file type sniffing. */ GByteArray *sniff; /* For a memory source, the blob we read from. */ VipsBlob *blob; /* If we mmaped the file, what we need to unmmap on finalize. */ void *mmap_baseaddr; size_t mmap_length; }; typedef struct _VipsSourceClass { VipsConnectionClass parent_class; /* Subclasses can define these to implement other source methods. */ /* Read from the source into the supplied buffer, args exactly as * [`read()`](man:read(2)). Set errno on error. * * We must return gint64, since ssize_t is often defined as unsigned * on Windows. */ gint64 (*read)(VipsSource *source, void *buffer, size_t length); /* Seek to a certain position, args exactly as [`lseek()`](man:lseek(2)). Set errno on * error. * * Unseekable sources should always return -1. VipsSource will then * seek by _read()ing bytes into memory as required. * * We have to use int64 rather than off_t, since we must work on * Windows, where off_t can be 32-bits. */ gint64 (*seek)(VipsSource *source, gint64 offset, int whence); } VipsSourceClass; VIPS_API GType vips_source_get_type(void); VIPS_API VipsSource *vips_source_new_from_descriptor(int descriptor); VIPS_API VipsSource *vips_source_new_from_file(const char *filename); VIPS_API VipsSource *vips_source_new_from_blob(VipsBlob *blob); VIPS_API VipsSource *vips_source_new_from_target(VipsTarget *target); VIPS_API VipsSource *vips_source_new_from_memory(const void *data, size_t length); VIPS_API VipsSource *vips_source_new_from_options(const char *options); VIPS_API void vips_source_minimise(VipsSource *source); VIPS_API int vips_source_unminimise(VipsSource *source); VIPS_API int vips_source_decode(VipsSource *source); VIPS_API gint64 vips_source_read(VipsSource *source, void *buffer, size_t length); VIPS_API gboolean vips_source_is_mappable(VipsSource *source); VIPS_API gboolean vips_source_is_file(VipsSource *source); VIPS_API const void *vips_source_map(VipsSource *source, size_t *length); VIPS_API VipsBlob *vips_source_map_blob(VipsSource *source); VIPS_API gint64 vips_source_seek(VipsSource *source, gint64 offset, int whence); VIPS_API int vips_source_rewind(VipsSource *source); VIPS_API gint64 vips_source_sniff_at_most(VipsSource *source, unsigned char **data, size_t length); VIPS_API unsigned char *vips_source_sniff(VipsSource *source, size_t length); VIPS_API gint64 vips_source_length(VipsSource *source); #define VIPS_TYPE_SOURCE_CUSTOM (vips_source_custom_get_type()) #define VIPS_SOURCE_CUSTOM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_SOURCE_CUSTOM, VipsSourceCustom)) #define VIPS_SOURCE_CUSTOM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_SOURCE_CUSTOM, VipsSourceCustomClass)) #define VIPS_IS_SOURCE_CUSTOM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_SOURCE_CUSTOM)) #define VIPS_IS_SOURCE_CUSTOM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_SOURCE_CUSTOM)) #define VIPS_SOURCE_CUSTOM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_SOURCE_CUSTOM, VipsSourceCustomClass)) typedef struct _VipsSourceCustom { VipsSource parent_object; } VipsSourceCustom; typedef struct _VipsSourceCustomClass { VipsSourceClass parent_class; /* The action signals clients can use to implement read and seek. * We must use gint64 everywhere since there's no G_TYPE_SIZE. */ gint64 (*read)(VipsSourceCustom *source, void *buffer, gint64 length); gint64 (*seek)(VipsSourceCustom *source, gint64 offset, int whence); } VipsSourceCustomClass; VIPS_API GType vips_source_custom_get_type(void); VIPS_API VipsSourceCustom *vips_source_custom_new(void); /* A GInputStream that wraps a VipsSource. This lets us eg. * hook librsvg up to libvips using their GInputStream interface. */ #define VIPS_TYPE_G_INPUT_STREAM (vips_g_input_stream_get_type()) #define VIPS_G_INPUT_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_G_INPUT_STREAM, VipsGInputStream)) #define VIPS_G_INPUT_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_G_INPUT_STREAM, VipsGInputStreamClass)) #define VIPS_IS_G_INPUT_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_G_INPUT_STREAM)) #define VIPS_IS_G_INPUT_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_G_INPUT_STREAM)) #define VIPS_G_INPUT_STREAM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_G_INPUT_STREAM, VipsGInputStreamClass)) typedef struct _VipsGInputStream { GInputStream parent_instance; /*< private >*/ /* The VipsSource we wrap. */ VipsSource *source; } VipsGInputStream; typedef struct _VipsGInputStreamClass { GInputStreamClass parent_class; } VipsGInputStreamClass; VIPS_API GType vips_g_input_stream_get_type(void); VIPS_API GInputStream *vips_g_input_stream_new_from_source(VipsSource *source); /* A VipsSource that wraps a GInputStream. This lets us eg. load PNGs from * GFile objects. */ #define VIPS_TYPE_SOURCE_G_INPUT_STREAM (vips_source_g_input_stream_get_type()) #define VIPS_SOURCE_G_INPUT_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_SOURCE_G_INPUT_STREAM, VipsSourceGInputStream)) #define VIPS_SOURCE_G_INPUT_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_SOURCE_G_INPUT_STREAM, VipsSourceGInputStreamClass)) #define VIPS_IS_SOURCE_G_INPUT_STREAM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_SOURCE_G_INPUT_STREAM)) #define VIPS_IS_SOURCE_G_INPUT_STREAM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_SOURCE_G_INPUT_STREAM)) #define VIPS_SOURCE_G_INPUT_STREAM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_SOURCE_G_INPUT_STREAM, VipsSourceGInputStreamClass)) typedef struct _VipsSourceGInputStream { VipsSource parent_instance; /*< private >*/ /* The GInputStream we wrap. */ GInputStream *stream; GSeekable *seekable; GFileInfo *info; } VipsSourceGInputStream; typedef struct _VipsSourceGInputStreamClass { VipsSourceClass parent_class; } VipsSourceGInputStreamClass; VIPS_API GType vips_source_g_input_stream_get_type(void); VIPS_API VipsSourceGInputStream *vips_source_g_input_stream_new(GInputStream *stream); #define VIPS_TYPE_TARGET (vips_target_get_type()) #define VIPS_TARGET(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_TARGET, VipsTarget)) #define VIPS_TARGET_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_TARGET, VipsTargetClass)) #define VIPS_IS_TARGET(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_TARGET)) #define VIPS_IS_TARGET_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_TARGET)) #define VIPS_TARGET_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_TARGET, VipsTargetClass)) /* PNG writes in 8kb chunks, so we need to be a little larger than that. */ #define VIPS_TARGET_BUFFER_SIZE (8500) struct _VipsTarget { VipsConnection parent_object; /*< private >*/ /* This target should write to memory. */ gboolean memory; /* The target has been ended and can no longer be written. */ gboolean ended; /* Write memory output here. We use a GString rather than a * GByteArray since we need eg. g_string_overwrite_len(). * @position tracks the current write position in this. */ GString *memory_buffer; /* And return memory via this blob. */ VipsBlob *blob; /* Buffer small writes here. write_point is the index of the next * character to write. */ unsigned char output_buffer[VIPS_TARGET_BUFFER_SIZE]; int write_point; /* Write position in memory_buffer. * * off_t can be 32 bits on some platforms, so make sure we have a * full 64. */ gint64 position; /* Temp targets on the filesystem need deleting, sometimes. */ gboolean delete_on_close; char *delete_on_close_filename; }; typedef struct _VipsTargetClass { VipsConnectionClass parent_class; /* Write to output. Args exactly as write(2). * * We must return gint64, since ssize_t is often defined as unsigned * on Windows. */ gint64 (*write)(VipsTarget *target, const void *data, size_t length); /* Deprecated in favour of ::end. */ void (*finish)(VipsTarget *target); /* libtiff needs to be able to seek and read on targets, * unfortunately. * * This will not work for eg. pipes, of course. */ /* Read from the target into the supplied buffer, args exactly as * [`read()`](man:read(2)). Set errno on error. * * We must return gint64, since ssize_t is often defined as unsigned * on Windows. */ gint64 (*read)(VipsTarget *target, void *buffer, size_t length); /* Seek output. Args exactly as [`lseek()`](man:lseek(2)). * * We have to use int64 rather than off_t, since we must work on * Windows, where off_t can be 32-bits. */ gint64 (*seek)(VipsTarget *target, gint64 offset, int whence); /* Output has been generated, so do any clearing up, * eg. copy the bytes we saved in memory to the target blob. */ int (*end)(VipsTarget *target); } VipsTargetClass; VIPS_API GType vips_target_get_type(void); VIPS_API VipsTarget *vips_target_new_to_descriptor(int descriptor); VIPS_API VipsTarget *vips_target_new_to_file(const char *filename); VIPS_API VipsTarget *vips_target_new_to_memory(void); VIPS_API VipsTarget *vips_target_new_temp(VipsTarget *based_on); VIPS_API int vips_target_write(VipsTarget *target, const void *data, size_t length); VIPS_API gint64 vips_target_read(VipsTarget *target, void *buffer, size_t length); VIPS_API gint64 vips_target_seek(VipsTarget *target, gint64 offset, int whence); VIPS_API int vips_target_end(VipsTarget *target); VIPS_API unsigned char *vips_target_steal(VipsTarget *target, size_t *length); VIPS_API char *vips_target_steal_text(VipsTarget *target); VIPS_API int vips_target_putc(VipsTarget *target, int ch); #define VIPS_TARGET_PUTC(S, C) ( \ (S)->write_point < VIPS_TARGET_BUFFER_SIZE \ ? ((S)->output_buffer[(S)->write_point++] = (C), 0) \ : vips_target_putc((S), (C))) VIPS_API int vips_target_writes(VipsTarget *target, const char *str); VIPS_API int vips_target_writef(VipsTarget *target, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_API int vips_target_write_amp(VipsTarget *target, const char *str); #define VIPS_TYPE_TARGET_CUSTOM (vips_target_custom_get_type()) #define VIPS_TARGET_CUSTOM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_TARGET_CUSTOM, VipsTargetCustom)) #define VIPS_TARGET_CUSTOM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_TARGET_CUSTOM, VipsTargetCustomClass)) #define VIPS_IS_TARGET_CUSTOM(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_TARGET_CUSTOM)) #define VIPS_IS_TARGET_CUSTOM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_TARGET_CUSTOM)) #define VIPS_TARGET_CUSTOM_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_TARGET_CUSTOM, VipsTargetCustomClass)) #define VIPS_TARGET_CUSTOM_BUFFER_SIZE (4096) typedef struct _VipsTargetCustom { VipsTarget parent_object; } VipsTargetCustom; typedef struct _VipsTargetCustomClass { VipsTargetClass parent_class; /* The action signals clients can use to implement write and finish. * We must use gint64 everywhere since there's no G_TYPE_SIZE. */ gint64 (*write)(VipsTargetCustom *target, const void *data, gint64 length); void (*finish)(VipsTargetCustom *target); gint64 (*read)(VipsTargetCustom *target, void *buffer, gint64 length); gint64 (*seek)(VipsTargetCustom *target, gint64 offset, int whence); int (*end)(VipsTargetCustom *target); } VipsTargetCustomClass; VIPS_API GType vips_target_custom_get_type(void); VIPS_API VipsTargetCustom *vips_target_custom_new(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_CONNECTION_H*/ libvips-8.18.2/libvips/include/vips/conversion.h000066400000000000000000000226221516303661500217060ustar00rootroot00000000000000/* conversion.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_CONVERSION_H #define VIPS_CONVERSION_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum { VIPS_EXTEND_BLACK, VIPS_EXTEND_COPY, VIPS_EXTEND_REPEAT, VIPS_EXTEND_MIRROR, VIPS_EXTEND_WHITE, VIPS_EXTEND_BACKGROUND, VIPS_EXTEND_LAST /*< skip >*/ } VipsExtend; typedef enum { VIPS_COMPASS_DIRECTION_CENTRE, VIPS_COMPASS_DIRECTION_NORTH, VIPS_COMPASS_DIRECTION_EAST, VIPS_COMPASS_DIRECTION_SOUTH, VIPS_COMPASS_DIRECTION_WEST, VIPS_COMPASS_DIRECTION_NORTH_EAST, VIPS_COMPASS_DIRECTION_SOUTH_EAST, VIPS_COMPASS_DIRECTION_SOUTH_WEST, VIPS_COMPASS_DIRECTION_NORTH_WEST, VIPS_COMPASS_DIRECTION_LAST /*< skip >*/ } VipsCompassDirection; typedef enum { VIPS_DIRECTION_HORIZONTAL, VIPS_DIRECTION_VERTICAL, VIPS_DIRECTION_LAST /*< skip >*/ } VipsDirection; typedef enum { VIPS_ALIGN_LOW, VIPS_ALIGN_CENTRE, VIPS_ALIGN_HIGH, VIPS_ALIGN_LAST /*< skip >*/ } VipsAlign; typedef enum { VIPS_ANGLE_D0, VIPS_ANGLE_D90, VIPS_ANGLE_D180, VIPS_ANGLE_D270, VIPS_ANGLE_LAST /*< skip >*/ } VipsAngle; typedef enum { VIPS_ANGLE45_D0, VIPS_ANGLE45_D45, VIPS_ANGLE45_D90, VIPS_ANGLE45_D135, VIPS_ANGLE45_D180, VIPS_ANGLE45_D225, VIPS_ANGLE45_D270, VIPS_ANGLE45_D315, VIPS_ANGLE45_LAST /*< skip >*/ } VipsAngle45; typedef enum { VIPS_INTERESTING_NONE, VIPS_INTERESTING_CENTRE, VIPS_INTERESTING_ENTROPY, VIPS_INTERESTING_ATTENTION, VIPS_INTERESTING_LOW, VIPS_INTERESTING_HIGH, VIPS_INTERESTING_ALL, VIPS_INTERESTING_LAST /*< skip >*/ } VipsInteresting; typedef enum { VIPS_BLEND_MODE_CLEAR, VIPS_BLEND_MODE_SOURCE, VIPS_BLEND_MODE_OVER, VIPS_BLEND_MODE_IN, VIPS_BLEND_MODE_OUT, VIPS_BLEND_MODE_ATOP, VIPS_BLEND_MODE_DEST, VIPS_BLEND_MODE_DEST_OVER, VIPS_BLEND_MODE_DEST_IN, VIPS_BLEND_MODE_DEST_OUT, VIPS_BLEND_MODE_DEST_ATOP, VIPS_BLEND_MODE_XOR, VIPS_BLEND_MODE_ADD, VIPS_BLEND_MODE_SATURATE, VIPS_BLEND_MODE_MULTIPLY, VIPS_BLEND_MODE_SCREEN, VIPS_BLEND_MODE_OVERLAY, VIPS_BLEND_MODE_DARKEN, VIPS_BLEND_MODE_LIGHTEN, VIPS_BLEND_MODE_COLOUR_DODGE, VIPS_BLEND_MODE_COLOUR_BURN, VIPS_BLEND_MODE_HARD_LIGHT, VIPS_BLEND_MODE_SOFT_LIGHT, VIPS_BLEND_MODE_DIFFERENCE, VIPS_BLEND_MODE_EXCLUSION, VIPS_BLEND_MODE_LAST /*< skip >*/ } VipsBlendMode; VIPS_API int vips_copy(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tilecache(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_linecache(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sequential(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_copy_file(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_embed(VipsImage *in, VipsImage **out, int x, int y, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gravity(VipsImage *in, VipsImage **out, VipsCompassDirection direction, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_flip(VipsImage *in, VipsImage **out, VipsDirection direction, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_insert(VipsImage *main, VipsImage *sub, VipsImage **out, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_join(VipsImage *in1, VipsImage *in2, VipsImage **out, VipsDirection direction, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_arrayjoin(VipsImage **in, VipsImage **out, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_extract_area(VipsImage *in, VipsImage **out, int left, int top, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_crop(VipsImage *in, VipsImage **out, int left, int top, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_smartcrop(VipsImage *in, VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_extract_band(VipsImage *in, VipsImage **out, int band, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_replicate(VipsImage *in, VipsImage **out, int across, int down, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_grid(VipsImage *in, VipsImage **out, int tile_height, int across, int down, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_transpose3d(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_wrap(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rot(VipsImage *in, VipsImage **out, VipsAngle angle, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rot90(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rot180(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rot270(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rot45(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API void vips_autorot_remove_angle(VipsImage *image); VIPS_API int vips_autorot(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_zoom(VipsImage *in, VipsImage **out, int xfac, int yfac, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_subsample(VipsImage *in, VipsImage **out, int xfac, int yfac, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast(VipsImage *in, VipsImage **out, VipsBandFormat format, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_uchar(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_char(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_ushort(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_short(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_uint(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_int(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_float(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_double(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_complex(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_cast_dpcomplex(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_scale(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_msb(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_byteswap(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandjoin(VipsImage **in, VipsImage **out, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandjoin2(VipsImage *in1, VipsImage *in2, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandjoin_const(VipsImage *in, VipsImage **out, double *c, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandjoin_const1(VipsImage *in, VipsImage **out, double c, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandrank(VipsImage **in, VipsImage **out, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandfold(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandunfold(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandbool(VipsImage *in, VipsImage **out, VipsOperationBoolean boolean, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandand(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandor(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandeor(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_bandmean(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_recomb(VipsImage *in, VipsImage **out, VipsImage *m, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_ifthenelse(VipsImage *cond, VipsImage *in1, VipsImage *in2, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_switch(VipsImage **tests, VipsImage **out, int n, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_flatten(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_addalpha(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_premultiply(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_unpremultiply(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_composite(VipsImage **in, VipsImage **out, int n, int *mode, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_composite2(VipsImage *base, VipsImage *overlay, VipsImage **out, VipsBlendMode mode, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_falsecolour(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gamma(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_CONVERSION_H*/ libvips-8.18.2/libvips/include/vips/convolution.h000066400000000000000000000051501516303661500220750ustar00rootroot00000000000000/* convolution.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_CONVOLUTION_H #define VIPS_CONVOLUTION_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum { VIPS_COMBINE_MAX, VIPS_COMBINE_SUM, VIPS_COMBINE_MIN, VIPS_COMBINE_LAST /*< skip >*/ } VipsCombine; VIPS_API int vips_conv(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_convf(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_convi(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_conva(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_convsep(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_convasep(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_compass(VipsImage *in, VipsImage **out, VipsImage *mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gaussblur(VipsImage *in, VipsImage **out, double sigma, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sharpen(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_spcor(VipsImage *in, VipsImage *ref, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_fastcor(VipsImage *in, VipsImage *ref, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sobel(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_scharr(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_prewitt(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_canny(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_CONVOLUTION_H*/ libvips-8.18.2/libvips/include/vips/create.h000066400000000000000000000112631516303661500207630ustar00rootroot00000000000000/* create.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_CREATE_H #define VIPS_CREATE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum { VIPS_TEXT_WRAP_WORD = 0, VIPS_TEXT_WRAP_CHAR, VIPS_TEXT_WRAP_WORD_CHAR, VIPS_TEXT_WRAP_NONE, VIPS_TEXT_WRAP_LAST /*< skip >*/ } VipsTextWrap; typedef enum { VIPS_SDF_SHAPE_CIRCLE = 0, VIPS_SDF_SHAPE_BOX, VIPS_SDF_SHAPE_ROUNDED_BOX, VIPS_SDF_SHAPE_LINE, VIPS_SDF_SHAPE_LAST /*< skip >*/ } VipsSdfShape; VIPS_API int vips_black(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_xyz(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_grey(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gaussmat(VipsImage **out, double sigma, double min_ampl, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_logmat(VipsImage **out, double sigma, double min_ampl, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_text(VipsImage **out, const char *text, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gaussnoise(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_eye(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sines(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_zone(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_sdf(VipsImage **out, int width, int height, VipsSdfShape shape, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_identity(VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_buildlut(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_invertlut(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tonelut(VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_ideal(VipsImage **out, int width, int height, double frequency_cutoff, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_ideal_ring(VipsImage **out, int width, int height, double frequency_cutoff, double ringwidth, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_ideal_band(VipsImage **out, int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_butterworth(VipsImage **out, int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_butterworth_ring(VipsImage **out, int width, int height, double order, double frequency_cutoff, double amplitude_cutoff, double ringwidth, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_butterworth_band(VipsImage **out, int width, int height, double order, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_gaussian(VipsImage **out, int width, int height, double frequency_cutoff, double amplitude_cutoff, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_gaussian_ring(VipsImage **out, int width, int height, double frequency_cutoff, double amplitude_cutoff, double ringwidth, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_gaussian_band(VipsImage **out, int width, int height, double frequency_cutoff_x, double frequency_cutoff_y, double radius, double amplitude_cutoff, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mask_fractal(VipsImage **out, int width, int height, double fractal_dimension, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_fractsurf(VipsImage **out, int width, int height, double fractal_dimension, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_worley(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_perlin(VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_CREATE_H*/ libvips-8.18.2/libvips/include/vips/dbuf.h000066400000000000000000000047621516303661500204460ustar00rootroot00000000000000/* A dynamic memory buffer that expands as you write. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_DBUF_H #define VIPS_DBUF_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include /* A buffer in the process of being written to. */ typedef struct _VipsDbuf { /* All fields are private. */ /*< private >*/ /* The current base, and the size of the allocated memory area. */ unsigned char *data; size_t allocated_size; /* The size of the actual data that's been written. This will usually * be <= allocated_size, but always >= write_point. */ size_t data_size; /* The write point. */ size_t write_point; } VipsDbuf; VIPS_API void vips_dbuf_init(VipsDbuf *dbuf); VIPS_API gboolean vips_dbuf_minimum_size(VipsDbuf *dbuf, size_t size); VIPS_API gboolean vips_dbuf_allocate(VipsDbuf *dbuf, size_t size); VIPS_API size_t vips_dbuf_read(VipsDbuf *dbuf, unsigned char *data, size_t size); VIPS_API unsigned char *vips_dbuf_get_write(VipsDbuf *dbuf, size_t *size); VIPS_API gboolean vips_dbuf_write(VipsDbuf *dbuf, const unsigned char *data, size_t size); VIPS_API gboolean vips_dbuf_writef(VipsDbuf *dbuf, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_API gboolean vips_dbuf_write_amp(VipsDbuf *dbuf, const char *str); VIPS_API void vips_dbuf_reset(VipsDbuf *dbuf); VIPS_API void vips_dbuf_destroy(VipsDbuf *dbuf); VIPS_API gboolean vips_dbuf_seek(VipsDbuf *dbuf, off_t offset, int whence); VIPS_API void vips_dbuf_truncate(VipsDbuf *dbuf); VIPS_API off_t vips_dbuf_tell(VipsDbuf *dbuf); VIPS_API unsigned char *vips_dbuf_string(VipsDbuf *dbuf, size_t *size); VIPS_API unsigned char *vips_dbuf_steal(VipsDbuf *dbuf, size_t *size); #endif /*VIPS_DBUF_H*/ #ifdef __cplusplus } #endif /*__cplusplus*/ libvips-8.18.2/libvips/include/vips/debug.h000066400000000000000000000037011516303661500206040ustar00rootroot00000000000000/* Support for debug.c in iofuncs. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_DEBUG_H #define VIPS_DEBUG_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #ifdef VIPS_DEBUG #define VIPS_DEBUG_MSG(...) \ G_STMT_START \ { \ printf(__VA_ARGS__); \ } \ G_STMT_END #else #define VIPS_DEBUG_MSG(...) \ G_STMT_START \ { \ ; \ } \ G_STMT_END #endif /*VIPS_DEBUG*/ #ifdef VIPS_DEBUG_RED #define VIPS_DEBUG_MSG_RED(...) \ G_STMT_START \ { \ printf("red: " __VA_ARGS__); \ } \ G_STMT_END #else #define VIPS_DEBUG_MSG_RED(...) \ G_STMT_START \ { \ ; \ } \ G_STMT_END #endif /*VIPS_DEBUG_RED*/ #ifdef VIPS_DEBUG_AMBER #define VIPS_DEBUG_MSG_AMBER(...) \ G_STMT_START \ { \ printf("amber: " __VA_ARGS__); \ } \ G_STMT_END #else #define VIPS_DEBUG_MSG_AMBER(...) \ G_STMT_START \ { \ ; \ } \ G_STMT_END #endif /*VIPS_DEBUG_AMBER*/ #ifdef VIPS_DEBUG_GREEN #define VIPS_DEBUG_MSG_GREEN(...) \ G_STMT_START \ { \ printf("green: " __VA_ARGS__); \ } \ G_STMT_END #else #define VIPS_DEBUG_MSG_GREEN(...) \ G_STMT_START \ { \ ; \ } \ G_STMT_END #endif /*VIPS_DEBUG_GREEN*/ #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /* VIPS_DEBUG_H */ libvips-8.18.2/libvips/include/vips/deprecated.h000066400000000000000000000074231516303661500216230ustar00rootroot00000000000000/* Old and broken stuff we do not enable by default * * 30/6/09 * - from vips.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IM_DEPRECATED_H #define IM_DEPRECATED_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* On win32, need to override the wingdi defs for these. Yuk! */ #ifdef G_OS_WIN32 #ifdef RGB #undef RGB #endif #ifdef CMYK #undef CMYK #endif #endif /*G_OS_WIN32*/ /* Bits per Band */ #define BBBYTE 8 #define BBSHORT 16 #define BBINT 32 #define BBFLOAT 32 #define BBCOMPLEX 64 /* complex consisting of two floats */ #define BBDOUBLE 64 #define BBDPCOMPLEX 128 /* complex consisting of two doubles */ /* picture Type */ #define MULTIBAND 0 #define B_W 1 #define LUMINACE 2 #define XRAY 3 #define IR 4 #define YUV 5 #define RED_ONLY 6 /* red channel only */ #define GREEN_ONLY 7 /* green channel only */ #define BLUE_ONLY 8 /* blue channel only */ #define POWER_SPECTRUM 9 #define HISTOGRAM 10 #define FOURIER 24 /* Colour spaces. */ #define LUT 11 #define XYZ 12 #define LAB 13 #define CMC 14 #define CMYK 15 #define LABQ 16 #define RGB 17 #define UCS 18 #define LCH 19 #define LABS 21 #define sRGB 22 #define YXY 23 /* BandFmt */ #define FMTNOTSET -1 #define FMTUCHAR 0 /* pels interpreted as unsigned chars */ #define FMTCHAR 1 /* pels interpreted as signed chars */ #define FMTUSHORT 2 /* pels interpreted as unsigned shorts */ #define FMTSHORT 3 /* pels interpreted as signed shorts */ #define FMTUINT 4 /* pels interpreted as unsigned ints */ #define FMTINT 5 /* pels interpreted as signed ints */ #define FMTFLOAT 6 /* pels interpreted as floats */ #define FMTCOMPLEX 7 /* pels interpreted as complex (2 float each) */ #define FMTDOUBLE 8 /* pels interpreted as unsigned double */ #define FMTDPCOMPLEX 9 /* pels interpreted as complex (2 double each)*/ /* Coding type */ #define NOCODING 0 #define COLQUANT 1 #define LABPACK 2 #define LABPACK_COMPRESSED 3 #define RGB_COMPRESSED 4 #define LUM_COMPRESSED 5 /* Compression type */ #define NO_COMPRESSION 0 #define TCSF_COMPRESSION 1 #define JPEG_COMPRESSION 2 #define esize(I) IM_IMAGE_SIZEOF_ELEMENT(I) #define psize(I) IM_IMAGE_SIZEOF_PEL(I) #define lsize(I) IM_IMAGE_SIZEOF_LINE(I) #define niele(I) IM_IMAGE_N_ELEMENTS(I) #define lskip(B) IM_REGION_LSKIP(B) #define nele(B) IM_REGION_N_ELEMENTS(B) #define rsize(B) IM_REGION_SIZEOF_LINE(B) #define addr(B, X, Y) IM_REGION_ADDR(B, X, Y) #ifndef MAX #define MAX(A, B) IM_MAX(A, B) #define MIN(A, B) IM_MIN(A, B) #endif /*MAX*/ #define CLIP(A, V, B) IM_CLIP(A, V, B) #define NEW(IM, A) IM_NEW(IM, A) #define NUMBER(R) IM_NUMBER(R) #define ARRAY(IM, N, T) IM_ARRAY(IM, N, T) #define RINT(R) IM_RINT(R) #define CLIP_UCHAR(V, SEQ) IM_CLIP_UCHAR(V, SEQ) #define CLIP_USHORT(V, SEQ) IM_CLIP_USHORT(V, SEQ) #define CLIP_CHAR(V, SEQ) IM_CLIP_CHAR(V, SEQ) #define CLIP_SHORT(V, SEQ) IM_CLIP_SHORT(V, SEQ) #define CLIP_NONE(V, SEQ) IM_CLIP_NONE(V, SEQ) #define right(R) IM_RECT_RIGHT(R) #define bottom(R) IM_RECT_BOTTOM(R) #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*IM_DEPRECATED_H*/ libvips-8.18.2/libvips/include/vips/dispatch.h000066400000000000000000000242771516303661500213300ustar00rootroot00000000000000/* VIPS function dispatch. * * J. Cupitt, 8/4/93. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IM_DISPATCH_H #define IM_DISPATCH_H #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include #include /* Type names. You may define your own, but if you use one of these, then * you should use the built-in VIPS type converters. */ #define IM_TYPE_IMAGEVEC "imagevec" /* im_object is ptr to IMAGE[] */ #define IM_TYPE_DOUBLEVEC "doublevec" /* im_object is ptr to double[] */ #define IM_TYPE_INTVEC "intvec" /* im_object is ptr to int[] */ #define IM_TYPE_DOUBLE "double" /* im_object is ptr to double */ #define IM_TYPE_INT "integer" /* 32-bit integer */ #define IM_TYPE_COMPLEX "complex" /* Pair of doubles */ #define IM_TYPE_STRING "string" /* Zero-terminated char array */ #define IM_TYPE_IMASK "intmask" /* Integer mask type */ #define IM_TYPE_DMASK "doublemask" /* Double mask type */ #define IM_TYPE_IMAGE "image" /* IMAGE descriptor */ #define IM_TYPE_DISPLAY "display" /* Display descriptor */ #define IM_TYPE_GVALUE "gvalue" /* GValue wrapper */ #define IM_TYPE_INTERPOLATE "interpolate" /* A subclass of VipsInterpolate */ typedef char *im_arg_type; /* Type of argument id */ /* Internal representation of an argument to an image processing function. */ typedef void *im_object; /* These bits are ored together to make the flags in a type descriptor. * * IM_TYPE_OUTPUT: set to indicate output, otherwise input. If the IM_TYPE_RW * bit is set and IM_TYPE_OUTPUT is not set, both input and output (ie. the * operation side-effects this argument). * * IM_TYPE_ARG: Two ways of making an im_object --- with and without a * command-line string to help you along. Arguments with a string are thing * like IMAGE descriptors, which require a filename to initialise. * Arguments without are things like output numbers, where making the object * simply involves allocating storage. */ typedef enum { IM_TYPE_NONE = 0, /* No flags */ IM_TYPE_OUTPUT = 0x1, /* Output/input object */ IM_TYPE_ARG = 0x2, /* Uses a str arg in construction */ IM_TYPE_RW = 0x4 /* Read-write */ } im_type_flags; /* Initialise, destroy and write objects. The "str" argument to the * init function will not be supplied if this is not an ARG type. The * write function writes to the GString. */ typedef int (*im_init_obj_fn)(im_object *obj, char *str); typedef int (*im_dest_obj_fn)(im_object obj); /* Describe a VIPS type. */ typedef struct { im_arg_type type; /* Type of argument */ int size; /* sizeof(im_object repres.) */ im_type_flags flags; /* Flags */ im_init_obj_fn init; /* Operation functions */ im_dest_obj_fn dest; /* Destroy object */ } im_type_desc; /* Success on an argument. This is called if the image processing function * succeeds and should be used to (for example) print output. */ typedef int (*im_print_obj_fn)(im_object obj); /* Describe a VIPS command argument. */ typedef struct { char *name; /* eg. "width" */ im_type_desc *desc; /* Type description */ im_print_obj_fn print; /* Print some output objects */ } im_arg_desc; /* Type of VIPS dispatch function. */ typedef int (*im_dispatch_fn)(im_object *argv); /* Maximum size of arg table. */ #define IM_MAX_ARGS (1000) /* Flags for functions. These are for information only, and more may be * added. */ typedef enum { IM_FN_NONE = 0, /* No flags set */ IM_FN_PIO = 0x1, /* Is a partial function */ IM_FN_TRANSFORM = 0x2, /* Performs coordinate transformations */ IM_FN_PTOP = 0x4, /* Point-to-point ... can be done with a LUT */ IM_FN_NOCACHE = 0x8 /* Result should not be cached */ } im_fn_flags; /* Describe a VIPS function. */ typedef struct { char *name; /* eg "im_invert" */ char *desc; /* Description - eg "photographic negative" */ im_fn_flags flags; /* Flags for this function */ im_dispatch_fn disp; /* Dispatch */ int argc; /* Number of args */ im_arg_desc *argv; /* Arg table */ } im_function; /* A set of VIPS functions forming a package. */ typedef struct { char *name; /* Package name (eg "arithmetic") */ int nfuncs; /* Number of functions in package */ im_function **table; /* Array of function descriptors */ } im_package; /* Externs for dispatch. */ /* Struct for mask IO to a file. */ typedef struct { char *name; /* Command-line name in */ void *mask; /* Mask --- DOUBLE or INT */ } im_mask_object; /* Struct for doublevec IO */ typedef struct { int n; /* Vector length */ double *vec; /* Vector */ } im_doublevec_object; /* Struct for intvec IO */ typedef struct { int n; /* Vector length */ int *vec; /* Vector */ } im_intvec_object; /* Struct for imagevec IO */ typedef struct { int n; /* Vector length */ IMAGE **vec; /* Vector */ } im_imagevec_object; /* Built-in VIPS types. */ VIPS_DEPRECATED im_type_desc im__input_int; VIPS_DEPRECATED im_type_desc im__input_intvec; VIPS_DEPRECATED im_type_desc im__input_imask; VIPS_DEPRECATED im_type_desc im__output_int; VIPS_DEPRECATED im_type_desc im__output_intvec; VIPS_DEPRECATED im_type_desc im__output_imask; VIPS_DEPRECATED im_type_desc im__input_double; VIPS_DEPRECATED im_type_desc im__input_doublevec; VIPS_DEPRECATED im_type_desc im__input_dmask; VIPS_DEPRECATED im_type_desc im__output_double; VIPS_DEPRECATED im_type_desc im__output_doublevec; VIPS_DEPRECATED im_type_desc im__output_dmask; VIPS_DEPRECATED im_type_desc im__output_dmask_screen; VIPS_DEPRECATED im_type_desc im__output_complex; VIPS_DEPRECATED im_type_desc im__input_string; VIPS_DEPRECATED im_type_desc im__output_string; VIPS_DEPRECATED im_type_desc im__input_imagevec; VIPS_DEPRECATED im_type_desc im__input_image; VIPS_DEPRECATED im_type_desc im__output_image; VIPS_DEPRECATED im_type_desc im__rw_image; VIPS_DEPRECATED im_type_desc im__input_display; VIPS_DEPRECATED im_type_desc im__output_display; VIPS_DEPRECATED im_type_desc im__input_gvalue; VIPS_DEPRECATED im_type_desc im__output_gvalue; VIPS_DEPRECATED im_type_desc im__input_interpolate; /* VIPS print functions. */ VIPS_DEPRECATED int im__iprint(im_object obj); /* int */ VIPS_DEPRECATED int im__ivprint(im_object obj); /* intvec */ VIPS_DEPRECATED int im__dprint(im_object obj); /* double */ VIPS_DEPRECATED int im__dvprint(im_object obj); /* doublevec */ VIPS_DEPRECATED int im__dmsprint(im_object obj); /* DOUBLEMASK as stats */ VIPS_DEPRECATED int im__cprint(im_object obj); /* complex */ VIPS_DEPRECATED int im__sprint(im_object obj); /* string */ VIPS_DEPRECATED int im__displayprint(im_object obj);/* im_col_display */ VIPS_DEPRECATED int im__gprint(im_object obj); /* GValue */ /* Macros for convenient creation. */ #define IM_INPUT_INT(S) \ { \ S, &im__input_int, NULL \ } #define IM_INPUT_INTVEC(S) \ { \ S, &im__input_intvec, NULL \ } #define IM_INPUT_IMASK(S) \ { \ S, &im__input_imask, NULL \ } #define IM_OUTPUT_INT(S) \ { \ S, &im__output_int, im__iprint \ } #define IM_OUTPUT_INTVEC(S) \ { \ S, &im__output_intvec, im__ivprint \ } #define IM_OUTPUT_IMASK(S) \ { \ S, &im__output_imask, NULL \ } #define IM_INPUT_DOUBLE(S) \ { \ S, &im__input_double, NULL \ } #define IM_INPUT_DOUBLEVEC(S) \ { \ S, &im__input_doublevec, NULL \ } #define IM_INPUT_DMASK(S) \ { \ S, &im__input_dmask, NULL \ } #define IM_OUTPUT_DOUBLE(S) \ { \ S, &im__output_double, im__dprint \ } #define IM_OUTPUT_DOUBLEVEC(S) \ { \ S, &im__output_doublevec, im__dvprint \ } #define IM_OUTPUT_DMASK(S) \ { \ S, &im__output_dmask, NULL \ } #define IM_OUTPUT_DMASK_STATS(S) \ { \ S, &im__output_dmask_screen, im__dmsprint \ } #define IM_OUTPUT_COMPLEX(S) \ { \ S, &im__output_complex, im__cprint \ } #define IM_INPUT_STRING(S) \ { \ S, &im__input_string, NULL \ } #define IM_OUTPUT_STRING(S) \ { \ S, &im__output_string, im__sprint \ } #define IM_INPUT_IMAGE(S) \ { \ S, &im__input_image, NULL \ } #define IM_INPUT_IMAGEVEC(S) \ { \ S, &im__input_imagevec, NULL \ } #define IM_OUTPUT_IMAGE(S) \ { \ S, &im__output_image, NULL \ } #define IM_RW_IMAGE(S) \ { \ S, &im__rw_image, NULL \ } #define IM_INPUT_DISPLAY(S) \ { \ S, &im__input_display, NULL \ } #define IM_OUTPUT_DISPLAY(S) \ { \ S, &im__output_display, im__displayprint \ } #define IM_INPUT_GVALUE(S) \ { \ S, &im__input_gvalue, NULL \ } #define IM_OUTPUT_GVALUE(S) \ { \ S, &im__output_gvalue, im__gprint \ } #define IM_INPUT_INTERPOLATE(S) \ { \ S, &im__input_interpolate, NULL \ } /* Add a plug-in package. */ VIPS_DEPRECATED im_package *im_load_plugin(const char *name); VIPS_DEPRECATED int im_load_plugins(const char *fmt, ...) G_GNUC_PRINTF(1, 2); /* Close all plug-ins. */ VIPS_DEPRECATED int im_close_plugins(void); /* Loop over all loaded packages. */ VIPS_DEPRECATED void *im_map_packages(VipsSListMap2Fn fn, void *a); /* Convenience functions for finding packages, functions, etc. */ VIPS_DEPRECATED im_function *im_find_function(const char *name); VIPS_DEPRECATED im_package *im_find_package(const char *name); VIPS_DEPRECATED im_package *im_package_of_function(const char *name); /* Allocate space for, and free im_object argument lists. */ VIPS_DEPRECATED int im_free_vargv(im_function *fn, im_object *vargv); VIPS_DEPRECATED int im_allocate_vargv(im_function *fn, im_object *vargv); /* Run a VIPS command by name. */ VIPS_DEPRECATED int im_run_command(char *name, int argc, char **argv); VIPS_DEPRECATED int vips__input_interpolate_init(im_object *obj, char *str); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*IM_DISPATCH_H*/ libvips-8.18.2/libvips/include/vips/draw.h000066400000000000000000000055401516303661500204560ustar00rootroot00000000000000/* draw.h * * 3/11/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_DRAW_H #define VIPS_DRAW_H #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum { VIPS_COMBINE_MODE_SET, VIPS_COMBINE_MODE_ADD, VIPS_COMBINE_MODE_LAST /*< skip >*/ } VipsCombineMode; VIPS_API int vips_draw_rect(VipsImage *image, double *ink, int n, int left, int top, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_rect1(VipsImage *image, double ink, int left, int top, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_point(VipsImage *image, double *ink, int n, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_point1(VipsImage *image, double ink, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_image(VipsImage *image, VipsImage *sub, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_mask(VipsImage *image, double *ink, int n, VipsImage *mask, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_mask1(VipsImage *image, double ink, VipsImage *mask, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_line(VipsImage *image, double *ink, int n, int x1, int y1, int x2, int y2, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_line1(VipsImage *image, double ink, int x1, int y1, int x2, int y2, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_circle(VipsImage *image, double *ink, int n, int cx, int cy, int radius, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_circle1(VipsImage *image, double ink, int cx, int cy, int radius, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_flood(VipsImage *image, double *ink, int n, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_flood1(VipsImage *image, double ink, int x, int y, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_draw_smudge(VipsImage *image, int left, int top, int width, int height, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_DRAW_H*/ libvips-8.18.2/libvips/include/vips/enumtypes.c.in000066400000000000000000000020441516303661500221460ustar00rootroot00000000000000/*** BEGIN file-header ***/ /* auto-generated enums for vips introspection */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #define VIPS_DISABLE_DEPRECATION_WARNINGS #include /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@basename@" */ /*** END file-production ***/ /*** BEGIN value-header ***/ GType @enum_name@_get_type(void) { static gsize gtype_id = 0; if (g_once_init_enter(>ype_id)) { static const G@Type@Value values[] = { /*** END value-header ***/ /*** BEGIN value-production ***/ { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, /*** END value-production ***/ /*** BEGIN value-tail ***/ { 0, NULL, NULL } }; GType new_type = g_@type@_register_static(g_intern_static_string("@EnumName@"), values); g_once_init_leave(>ype_id, new_type); } return (GType) gtype_id; } /*** END value-tail ***/ /*** BEGIN file-tail ***/ /* Deprecated enumerations */ GType vips_saveable_get_type(void) { return vips_foreign_saveable_get_type(); } /*** END file-tail ***/ libvips-8.18.2/libvips/include/vips/enumtypes.h.in000066400000000000000000000012421516303661500221520ustar00rootroot00000000000000/*** BEGIN file-header ***/ #ifndef VIPS_ENUM_TYPES_H #define VIPS_ENUM_TYPES_H G_BEGIN_DECLS /*** END file-header ***/ /*** BEGIN file-production ***/ /* enumerations from "@basename@" */ /*** END file-production ***/ /*** BEGIN value-header ***/ VIPS_API GType @enum_name@_get_type(void) G_GNUC_CONST; #define VIPS_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) /*** END value-header ***/ /*** BEGIN file-tail ***/ /* Deprecated enumerations */ #ifndef __GI_SCANNER__ VIPS_API GType vips_saveable_get_type(void) G_GNUC_CONST; #define VIPS_TYPE_SAVEABLE (vips_saveable_get_type()) #endif /*__GI_SCANNER__*/ G_END_DECLS #endif /*VIPS_ENUM_TYPES_H*/ /*** END file-tail ***/ libvips-8.18.2/libvips/include/vips/error.h000066400000000000000000000102131516303661500206430ustar00rootroot00000000000000/* Error handling. */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_ERROR_H #define VIPS_ERROR_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_API const char *vips_error_buffer(void); VIPS_API char *vips_error_buffer_copy(void); VIPS_API void vips_error_clear(void); VIPS_API void vips_error_freeze(void); VIPS_API void vips_error_thaw(void); VIPS_API void vips_error(const char *domain, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_API void vips_verror(const char *domain, const char *fmt, va_list ap); VIPS_API void vips_error_system(int err, const char *domain, const char *fmt, ...) G_GNUC_PRINTF(3, 4); VIPS_API void vips_verror_system(int err, const char *domain, const char *fmt, va_list ap); VIPS_API void vips_error_g(GError **error); VIPS_API void vips_g_error(GError **error); VIPS_API void vips_error_exit(const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF(1, 2); VIPS_API int vips_check_uncoded(const char *domain, VipsImage *im); VIPS_API int vips_check_coding(const char *domain, VipsImage *im, VipsCoding coding); VIPS_API int vips_check_coding_known(const char *domain, VipsImage *im); VIPS_API int vips_check_coding_noneorlabq(const char *domain, VipsImage *im); VIPS_API int vips_check_coding_same(const char *domain, VipsImage *im1, VipsImage *im2); VIPS_API int vips_check_mono(const char *domain, VipsImage *im); VIPS_API int vips_check_bands(const char *domain, VipsImage *im, int bands); VIPS_API int vips_check_bands_1or3(const char *domain, VipsImage *im); VIPS_API int vips_check_bands_atleast(const char *domain, VipsImage *im, int bands); VIPS_API int vips_check_bands_1orn(const char *domain, VipsImage *im1, VipsImage *im2); VIPS_API int vips_check_bands_1orn_unary(const char *domain, VipsImage *im, int n); VIPS_API int vips_check_bands_same(const char *domain, VipsImage *im1, VipsImage *im2); VIPS_API int vips_check_bandno(const char *domain, VipsImage *im, int bandno); VIPS_API int vips_check_int(const char *domain, VipsImage *im); VIPS_API int vips_check_uint(const char *domain, VipsImage *im); VIPS_API int vips_check_uintorf(const char *domain, VipsImage *im); VIPS_API int vips_check_noncomplex(const char *domain, VipsImage *im); VIPS_API int vips_check_complex(const char *domain, VipsImage *im); VIPS_API int vips_check_twocomponents(const char *domain, VipsImage *im); VIPS_API int vips_check_format(const char *domain, VipsImage *im, VipsBandFormat fmt); VIPS_API int vips_check_u8or16(const char *domain, VipsImage *im); VIPS_API int vips_check_8or16(const char *domain, VipsImage *im); VIPS_API int vips_check_u8or16orf(const char *domain, VipsImage *im); VIPS_API int vips_check_format_same(const char *domain, VipsImage *im1, VipsImage *im2); VIPS_API int vips_check_size_same(const char *domain, VipsImage *im1, VipsImage *im2); VIPS_API int vips_check_oddsquare(const char *domain, VipsImage *im); VIPS_API int vips_check_vector_length(const char *domain, int n, int len); VIPS_API int vips_check_vector(const char *domain, int n, VipsImage *im); VIPS_API int vips_check_hist(const char *domain, VipsImage *im); VIPS_API int vips_check_matrix(const char *domain, VipsImage *im, VipsImage **out); VIPS_API int vips_check_separable(const char *domain, VipsImage *im); VIPS_API int vips_check_precision_intfloat(const char *domain, VipsPrecision precision); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_ERROR_H*/ libvips-8.18.2/libvips/include/vips/foreign.h000066400000000000000000001005331516303661500211500ustar00rootroot00000000000000/* Base type for supported image formats. Subclass this to add a new * format. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_FOREIGN_H #define VIPS_FOREIGN_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_FOREIGN (vips_foreign_get_type()) #define VIPS_FOREIGN(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN, VipsForeign)) #define VIPS_FOREIGN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN, VipsForeignClass)) #define VIPS_IS_FOREIGN(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN)) #define VIPS_IS_FOREIGN_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN)) #define VIPS_FOREIGN_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN, VipsForeignClass)) typedef struct _VipsForeign { VipsOperation parent_object; /*< public >*/ } VipsForeign; typedef struct _VipsForeignClass { VipsOperationClass parent_class; /*< public >*/ /* Loop over formats in this order, default 0. We need this because * some formats can be read by several loaders (eg. tiff can be read * by the libMagick loader as well as by the tiff loader), and we want * to make sure the better loader comes first. */ int priority; /* Null-terminated list of recommended suffixes, eg. ".tif", ".tiff". * This can be used by both load and save, so it's in the base class. */ const char **suffs; } VipsForeignClass; VIPS_API GType vips_foreign_get_type(void); /* Map over and find formats. This uses type introspection to loop over * subclasses of VipsForeign. */ VIPS_API void *vips_foreign_map(const char *base, VipsSListMap2Fn fn, void *a, void *b); /* Image file load properties. * * Keep in sync with the deprecated VipsFormatFlags, we need to be able to * cast between them. */ typedef enum /*< flags >*/ { VIPS_FOREIGN_NONE = 0, /* No flags set */ VIPS_FOREIGN_PARTIAL = 1, /* Lazy read OK (eg. tiled tiff) */ VIPS_FOREIGN_BIGENDIAN = 2, /* Most-significant byte first */ VIPS_FOREIGN_SEQUENTIAL = 4, /* Top-to-bottom lazy read OK */ VIPS_FOREIGN_ALL = 7 /* All flags set */ } VipsForeignFlags; /** * VipsFailOn: * @VIPS_FAIL_ON_NONE: never stop * @VIPS_FAIL_ON_TRUNCATED: stop on image truncated, nothing else * @VIPS_FAIL_ON_ERROR: stop on serious error or truncation * @VIPS_FAIL_ON_WARNING: stop on anything, even warnings * * How sensitive loaders are to errors, from never stop (very insensitive), to * stop on the smallest warning (very sensitive). * * Each one implies the ones before it, so [enum@Vips.FailOn.ERROR] implies * [enum@Vips.FailOn.TRUNCATED]. */ typedef enum { VIPS_FAIL_ON_NONE, VIPS_FAIL_ON_TRUNCATED, VIPS_FAIL_ON_ERROR, VIPS_FAIL_ON_WARNING, VIPS_FAIL_ON_LAST /*< skip >*/ } VipsFailOn; #define VIPS_TYPE_FOREIGN_LOAD (vips_foreign_load_get_type()) #define VIPS_FOREIGN_LOAD(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_LOAD, VipsForeignLoad)) #define VIPS_FOREIGN_LOAD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN_LOAD, VipsForeignLoadClass)) #define VIPS_IS_FOREIGN_LOAD(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN_LOAD)) #define VIPS_IS_FOREIGN_LOAD_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN_LOAD)) #define VIPS_FOREIGN_LOAD_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN_LOAD, VipsForeignLoadClass)) typedef struct _VipsForeignLoad { VipsForeign parent_object; /*< private >*/ /* Set TRUE to force open via memory. */ gboolean memory; /* Type of access upstream wants and the loader must supply. */ VipsAccess access; /* Flags for this load operation. */ VipsForeignFlags flags; /* Behaviour on error. */ VipsFailOn fail_on; /* Deprecated and unused. Just here for compat. */ gboolean fail; gboolean sequential; /*< public >*/ /* The image we generate. This must be set by ->header(). */ VipsImage *out; /* The behind-the-scenes real image we decompress to. This can be a * disc file or a memory buffer. This must be set by ->load(). */ VipsImage *real; /* Set this to tag the operation as nocache. */ gboolean nocache; /* Deprecated: the memory option used to be called disc and default * TRUE. */ gboolean disc; /* Set if a start function fails. We want to prevent the other starts * from also triggering the load. */ gboolean error; /* Set by "revalidate": set the REVALIDATE flag for this operation to * force it to execute. */ gboolean revalidate; } VipsForeignLoad; typedef struct _VipsForeignLoadClass { VipsForeignClass parent_class; /*< public >*/ /* Is a file in this format. * * This function should return `TRUE` if the file contains an image of * this type. If you don't define this function, #VipsForeignLoad * will use @suffs instead. */ gboolean (*is_a)(const char *filename); /* Is a buffer in this format. * * This function should return `TRUE` if the buffer contains an image of * this type. */ gboolean (*is_a_buffer)(const void *data, size_t size); /* Is a stream in this format. * * This function should return `TRUE` if the stream contains an image of * this type. */ gboolean (*is_a_source)(VipsSource *source); /* Get the flags from a filename. * * This function should examine the file and return a set * of flags. If you don't define it, vips will default to 0 (no flags * set). * * This method is necessary for vips7 compatibility. Don't define * it if you don't need vips7. */ VipsForeignFlags (*get_flags_filename)(const char *filename); /* Get the flags for this load operation. Images can be loaded from * (for example) memory areas rather than files, so you can't just use * @get_flags_filename(). */ VipsForeignFlags (*get_flags)(VipsForeignLoad *load); /* Do the minimum read we can. * * Set the header fields in @out from @filename. If you can read the * whole image as well with no performance cost (as with vipsload), * or if your loader does not support reading only the header, read * the entire image in this method and leave @load() NULL. * * @header() needs to set the dhint on the image .. otherwise you get * the default SMALLTILE. * * Return 0 for success, -1 for error, setting vips_error(). */ int (*header)(VipsForeignLoad *load); /* Read the whole image into @real. The pixels will get copied to @out * later. * * You can omit this method if you define a @header() method which * loads the whole file. * * Return 0 for success, -1 for error, setting * vips_error(). */ int (*load)(VipsForeignLoad *load); } VipsForeignLoadClass; VIPS_API GType vips_foreign_load_get_type(void); VIPS_API const char *vips_foreign_find_load(const char *filename); VIPS_API const char *vips_foreign_find_load_buffer(const void *data, size_t size); VIPS_API const char *vips_foreign_find_load_source(VipsSource *source); VIPS_API VipsForeignFlags vips_foreign_flags(const char *loader, const char *filename); VIPS_API gboolean vips_foreign_is_a(const char *loader, const char *filename); VIPS_API gboolean vips_foreign_is_a_buffer(const char *loader, const void *data, size_t size); VIPS_API gboolean vips_foreign_is_a_source(const char *loader, VipsSource *source); VIPS_API void vips_foreign_load_invalidate(VipsImage *image); #define VIPS_TYPE_FOREIGN_SAVE (vips_foreign_save_get_type()) #define VIPS_FOREIGN_SAVE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FOREIGN_SAVE, VipsForeignSave)) #define VIPS_FOREIGN_SAVE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FOREIGN_SAVE, VipsForeignSaveClass)) #define VIPS_IS_FOREIGN_SAVE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FOREIGN_SAVE)) #define VIPS_IS_FOREIGN_SAVE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FOREIGN_SAVE)) #define VIPS_FOREIGN_SAVE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FOREIGN_SAVE, VipsForeignSaveClass)) /** * VipsForeignSaveable: * @VIPS_FOREIGN_SAVEABLE_ANY: saver supports everything (eg. TIFF) * @VIPS_FOREIGN_SAVEABLE_MONO: 1 band * @VIPS_FOREIGN_SAVEABLE_RGB: 3 bands * @VIPS_FOREIGN_SAVEABLE_CMYK: 4 bands * @VIPS_FOREIGN_SAVEABLE_ALPHA: an extra band * * The set of image types supported by a saver. * * ::: seealso * [class@ForeignSave]. */ typedef enum /*< flags >*/ { VIPS_FOREIGN_SAVEABLE_ANY = 0, VIPS_FOREIGN_SAVEABLE_MONO = 1, VIPS_FOREIGN_SAVEABLE_RGB = 2, VIPS_FOREIGN_SAVEABLE_CMYK = 4, VIPS_FOREIGN_SAVEABLE_ALPHA = 8, VIPS_FOREIGN_SAVEABLE_ALL = (VIPS_FOREIGN_SAVEABLE_MONO | VIPS_FOREIGN_SAVEABLE_RGB | VIPS_FOREIGN_SAVEABLE_CMYK | VIPS_FOREIGN_SAVEABLE_ALPHA) } VipsForeignSaveable; /** * VipsForeignCoding: * @VIPS_FOREIGN_CODING_NONE: saver supports [enum@Vips.Coding.NONE] * @VIPS_FOREIGN_CODING_LABQ: saver supports [enum@Vips.Coding.LABQ] * @VIPS_FOREIGN_CODING_RAD: saver supports [enum@Vips.Coding.RAD] * @VIPS_FOREIGN_CODING_ALL: saver supports all coding types * * The set of coding types supported by a saver. * * ::: seealso * [enum@Coding]. */ typedef enum /*< flags >*/ { VIPS_FOREIGN_CODING_NONE = 1 << 0, VIPS_FOREIGN_CODING_LABQ = 1 << 1, VIPS_FOREIGN_CODING_RAD = 1 << 2, VIPS_FOREIGN_CODING_ALL = (VIPS_FOREIGN_CODING_NONE | VIPS_FOREIGN_CODING_LABQ | VIPS_FOREIGN_CODING_RAD) } VipsForeignCoding; /** * VipsForeignKeep: * @VIPS_FOREIGN_KEEP_NONE: don't attach metadata * @VIPS_FOREIGN_KEEP_EXIF: keep Exif metadata * @VIPS_FOREIGN_KEEP_XMP: keep XMP metadata * @VIPS_FOREIGN_KEEP_IPTC: keep IPTC metadata * @VIPS_FOREIGN_KEEP_ICC: keep ICC metadata * @VIPS_FOREIGN_KEEP_OTHER: keep other metadata (e.g. PNG comments) * @VIPS_FOREIGN_KEEP_GAINMAP: keep the gainmap metadata * @VIPS_FOREIGN_KEEP_ALL: keep all metadata * * Which metadata to retain. */ typedef enum /*< flags >*/ { VIPS_FOREIGN_KEEP_NONE = 0, VIPS_FOREIGN_KEEP_EXIF = 1 << 0, VIPS_FOREIGN_KEEP_XMP = 1 << 1, VIPS_FOREIGN_KEEP_IPTC = 1 << 2, VIPS_FOREIGN_KEEP_ICC = 1 << 3, VIPS_FOREIGN_KEEP_OTHER = 1 << 4, VIPS_FOREIGN_KEEP_GAINMAP = 1 << 5, VIPS_FOREIGN_KEEP_ALL = (VIPS_FOREIGN_KEEP_EXIF | VIPS_FOREIGN_KEEP_XMP | VIPS_FOREIGN_KEEP_IPTC | VIPS_FOREIGN_KEEP_ICC | VIPS_FOREIGN_KEEP_OTHER | VIPS_FOREIGN_KEEP_GAINMAP) } VipsForeignKeep; typedef struct _VipsForeignSave { VipsForeign parent_object; /* Deprecated in favor of [keep=none] */ gboolean strip; /* Which metadata to retain. */ VipsForeignKeep keep; /* Filename of profile to embed. */ char *profile; /* If flattening out alpha, the background colour to use. Default to * 0 (black). */ VipsArrayDouble *background; /* Set to non-zero to set the page size for multi-page save. */ int page_height; /*< public >*/ /* The image we are to save, as supplied by our caller. */ VipsImage *in; /* @in converted to a saveable format (eg. 8-bit RGB) according to the * instructions you give in the class fields below. * * This is the image you should actually write to the output. */ VipsImage *ready; } VipsForeignSave; typedef struct _VipsForeignSaveClass { VipsForeignClass parent_class; /*< public >*/ /* How this format treats bands. * * @saveable describes the image types that your saver can handle. For * example, PPM images can have 1 or 3 bands (mono or RGB), so it * uses [flags@Vips.ForeignSaveable.MONO] | [flags@Vips.ForeignSaveable.RGB]. */ VipsForeignSaveable saveable; /* How this format treats band formats. * * @format_table describes the band formats that your saver can * handle. For each of the 10 #VipsBandFormat values, the array * should give the format your saver will accept. */ VipsBandFormat *format_table; /* The set of coding types this format can save. For example, * [method@Image.vipssave] can save all coding types, so it * uses [flags@Vips.ForeignCoding.ALL] * * Default to [flags@Vips.ForeignCoding.NONE]. */ VipsForeignCoding coding; } VipsForeignSaveClass; VIPS_API GType vips_foreign_save_get_type(void); VIPS_API const char *vips_foreign_find_save(const char *filename); VIPS_API gchar **vips_foreign_get_suffixes(void); VIPS_API const char *vips_foreign_find_save_buffer(const char *suffix); VIPS_API const char *vips_foreign_find_save_target(const char *suffix); VIPS_API int vips_vipsload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_vipsload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_vipssave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_vipssave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_openslideload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_openslideload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignSubsample: * @VIPS_FOREIGN_SUBSAMPLE_AUTO: prevent subsampling when quality >= 90 * @VIPS_FOREIGN_SUBSAMPLE_ON: always perform subsampling * @VIPS_FOREIGN_SUBSAMPLE_OFF: never perform subsampling * * Set subsampling mode. */ typedef enum { VIPS_FOREIGN_SUBSAMPLE_AUTO, VIPS_FOREIGN_SUBSAMPLE_ON, VIPS_FOREIGN_SUBSAMPLE_OFF, VIPS_FOREIGN_SUBSAMPLE_LAST /*< skip >*/ } VipsForeignSubsample; VIPS_API int vips_jpegload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jpegload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jpegload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jpegsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jpegsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jpegsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jpegsave_mime(VipsImage *in, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignWebpPreset: * @VIPS_FOREIGN_WEBP_PRESET_DEFAULT: default preset * @VIPS_FOREIGN_WEBP_PRESET_PICTURE: digital picture, like portrait, inner shot * @VIPS_FOREIGN_WEBP_PRESET_PHOTO: outdoor photograph, with natural lighting * @VIPS_FOREIGN_WEBP_PRESET_DRAWING: hand or line drawing, with high-contrast details * @VIPS_FOREIGN_WEBP_PRESET_ICON: small-sized colorful images * @VIPS_FOREIGN_WEBP_PRESET_TEXT: text-like * * Tune lossy encoder settings for different image types. */ typedef enum { VIPS_FOREIGN_WEBP_PRESET_DEFAULT, VIPS_FOREIGN_WEBP_PRESET_PICTURE, VIPS_FOREIGN_WEBP_PRESET_PHOTO, VIPS_FOREIGN_WEBP_PRESET_DRAWING, VIPS_FOREIGN_WEBP_PRESET_ICON, VIPS_FOREIGN_WEBP_PRESET_TEXT, VIPS_FOREIGN_WEBP_PRESET_LAST /*< skip >*/ } VipsForeignWebpPreset; VIPS_API int vips_webpload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_webpload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_webpload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_webpsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_webpsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_webpsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_webpsave_mime(VipsImage *in, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignTiffCompression: * @VIPS_FOREIGN_TIFF_COMPRESSION_NONE: no compression * @VIPS_FOREIGN_TIFF_COMPRESSION_JPEG: jpeg compression * @VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE: deflate (zip) compression * @VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS: packbits compression * @VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4: fax4 compression * @VIPS_FOREIGN_TIFF_COMPRESSION_LZW: LZW compression * @VIPS_FOREIGN_TIFF_COMPRESSION_WEBP: WEBP compression * @VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD: ZSTD compression * @VIPS_FOREIGN_TIFF_COMPRESSION_JP2K: JP2K compression * * The compression types supported by the tiff writer. * * Use @Q to set the jpeg compression level, default 75. * * Use @predictor to set the lzw or deflate prediction, default horizontal. * * Use @lossless to set WEBP lossless compression. * * Use @level to set webp and zstd compression level. */ typedef enum { VIPS_FOREIGN_TIFF_COMPRESSION_NONE, VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE, VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS, VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4, VIPS_FOREIGN_TIFF_COMPRESSION_LZW, VIPS_FOREIGN_TIFF_COMPRESSION_WEBP, VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD, VIPS_FOREIGN_TIFF_COMPRESSION_JP2K, VIPS_FOREIGN_TIFF_COMPRESSION_LAST /*< skip >*/ } VipsForeignTiffCompression; /** * VipsForeignTiffPredictor: * @VIPS_FOREIGN_TIFF_PREDICTOR_NONE: no prediction * @VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL: horizontal differencing * @VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT: float predictor * * The predictor can help deflate and lzw compression. The values are fixed by * the tiff library. */ typedef enum { VIPS_FOREIGN_TIFF_PREDICTOR_NONE = 1, VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL = 2, VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT = 3, VIPS_FOREIGN_TIFF_PREDICTOR_LAST /*< skip >*/ } VipsForeignTiffPredictor; /** * VipsForeignTiffResunit: * @VIPS_FOREIGN_TIFF_RESUNIT_CM: use centimeters * @VIPS_FOREIGN_TIFF_RESUNIT_INCH: use inches * * Use inches or centimeters as the resolution unit for a tiff file. */ typedef enum { VIPS_FOREIGN_TIFF_RESUNIT_CM, VIPS_FOREIGN_TIFF_RESUNIT_INCH, VIPS_FOREIGN_TIFF_RESUNIT_LAST /*< skip >*/ } VipsForeignTiffResunit; VIPS_API int vips_tiffload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tiffload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tiffload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tiffsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tiffsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_tiffsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_openexrload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_fitsload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_fitsload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_fitssave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_analyzeload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rawload(const char *filename, VipsImage **out, int width, int height, int bands, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rawsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rawsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rawsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_csvload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_csvload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_csvsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_csvsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixprint(VipsImage *in, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_magickload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_magickload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_magickload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_magicksave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_magicksave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignPngFilter: * @VIPS_FOREIGN_PNG_FILTER_NONE: no filtering * @VIPS_FOREIGN_PNG_FILTER_SUB: difference to the left * @VIPS_FOREIGN_PNG_FILTER_UP: difference up * @VIPS_FOREIGN_PNG_FILTER_AVG: average of left and up * @VIPS_FOREIGN_PNG_FILTER_PAETH: pick best neighbor predictor automatically * @VIPS_FOREIGN_PNG_FILTER_ALL: adaptive * * http://www.w3.org/TR/PNG-Filters.html * The values mirror those of png.h in libpng. */ typedef enum /*< flags >*/ { VIPS_FOREIGN_PNG_FILTER_NONE = 0x08, VIPS_FOREIGN_PNG_FILTER_SUB = 0x10, VIPS_FOREIGN_PNG_FILTER_UP = 0x20, VIPS_FOREIGN_PNG_FILTER_AVG = 0x40, VIPS_FOREIGN_PNG_FILTER_PAETH = 0x80, VIPS_FOREIGN_PNG_FILTER_ALL = 0xF8 } VipsForeignPngFilter; VIPS_API int vips_pngload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pngload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pngload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pngsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pngsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pngsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignPpmFormat: * @VIPS_FOREIGN_PPM_FORMAT_PBM: portable bitmap * @VIPS_FOREIGN_PPM_FORMAT_PGM: portable greymap * @VIPS_FOREIGN_PPM_FORMAT_PPM: portable pixmap * @VIPS_FOREIGN_PPM_FORMAT_PFM: portable float map * @VIPS_FOREIGN_PPM_FORMAT_PNM: portable anymap * * The netpbm file format to save as. * * [enum@Vips.ForeignPpmFormat.PBM] images are single bit. * * [enum@Vips.ForeignPpmFormat.PGM] images are 8, 16, or 32-bits, one band. * * [enum@Vips.ForeignPpmFormat.PPM] images are 8, 16, or 32-bits, three bands. * * [enum@Vips.ForeignPpmFormat.PFM] images are 32-bit float pixels. * * [enum@Vips.ForeignPpmFormat.PNM] images are anymap images -- the image format * is used to pick the saver. * */ typedef enum { VIPS_FOREIGN_PPM_FORMAT_PBM, VIPS_FOREIGN_PPM_FORMAT_PGM, VIPS_FOREIGN_PPM_FORMAT_PPM, VIPS_FOREIGN_PPM_FORMAT_PFM, VIPS_FOREIGN_PPM_FORMAT_PNM, VIPS_FOREIGN_PPM_FORMAT_LAST /*< skip >*/ } VipsForeignPpmFormat; VIPS_API int vips_ppmload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_ppmload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_ppmload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_ppmsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_ppmsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_radload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_radload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_radload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_radsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_radsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_radsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignPdfPageBox: * @VIPS_FOREIGN_PDF_PAGE_BOX_MEDIA: media box * @VIPS_FOREIGN_PDF_PAGE_BOX_CROP: crop box * @VIPS_FOREIGN_PDF_PAGE_BOX_TRIM: trim box * @VIPS_FOREIGN_PDF_PAGE_BOX_BLEED: bleed box * @VIPS_FOREIGN_PDF_PAGE_BOX_ART: art box * * Each page of a PDF document can contain multiple page boxes, * also known as boundary boxes or print marks. * * Each page box defines a region of the complete page that * should be rendered. The default region is the crop box. */ typedef enum { VIPS_FOREIGN_PDF_PAGE_BOX_MEDIA, VIPS_FOREIGN_PDF_PAGE_BOX_CROP, VIPS_FOREIGN_PDF_PAGE_BOX_TRIM, VIPS_FOREIGN_PDF_PAGE_BOX_BLEED, VIPS_FOREIGN_PDF_PAGE_BOX_ART, VIPS_FOREIGN_PDF_PAGE_BOX_LAST /*< skip >*/ } VipsForeignPdfPageBox; VIPS_API int vips_pdfload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pdfload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_pdfload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_svgload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_svgload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_svgload_string(const char *str, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_svgload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gifload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gifload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gifload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gifsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gifsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_gifsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dcrawload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dcrawload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dcrawload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdrload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdrload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdrload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdrsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdrsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_uhdrsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_heifload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_heifload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_heifload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_heifsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_heifsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_heifsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_niftiload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_niftiload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_niftisave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jp2kload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jp2kload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jp2kload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jp2ksave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jp2ksave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jp2ksave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jxlload_source(VipsSource *source, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jxlload_buffer(void *buf, size_t len, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jxlload(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jxlsave(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jxlsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_jxlsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignDzLayout: * @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout * @VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY: use Zoomify directory layout * @VIPS_FOREIGN_DZ_LAYOUT_GOOGLE: use Google maps directory layout * @VIPS_FOREIGN_DZ_LAYOUT_IIIF: use IIIF v2 directory layout * @VIPS_FOREIGN_DZ_LAYOUT_IIIF3: use IIIF v3 directory layout * * What directory layout and metadata standard to use. */ typedef enum { VIPS_FOREIGN_DZ_LAYOUT_DZ, VIPS_FOREIGN_DZ_LAYOUT_ZOOMIFY, VIPS_FOREIGN_DZ_LAYOUT_GOOGLE, VIPS_FOREIGN_DZ_LAYOUT_IIIF, VIPS_FOREIGN_DZ_LAYOUT_IIIF3, VIPS_FOREIGN_DZ_LAYOUT_LAST /*< skip >*/ } VipsForeignDzLayout; /** * VipsForeignDzDepth: * @VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL: create layers down to 1x1 pixel * @VIPS_FOREIGN_DZ_DEPTH_ONETILE: create layers down to 1x1 tile * @VIPS_FOREIGN_DZ_DEPTH_ONE: only create a single layer * * How many pyramid layers to create. */ typedef enum { VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL, VIPS_FOREIGN_DZ_DEPTH_ONETILE, VIPS_FOREIGN_DZ_DEPTH_ONE, VIPS_FOREIGN_DZ_DEPTH_LAST /*< skip >*/ } VipsForeignDzDepth; /** * VipsForeignDzContainer: * @VIPS_FOREIGN_DZ_CONTAINER_FS: write tiles to the filesystem * @VIPS_FOREIGN_DZ_CONTAINER_ZIP: write tiles to a zip file * @VIPS_FOREIGN_DZ_CONTAINER_SZI: write to a szi file * * What container format to use. */ typedef enum { VIPS_FOREIGN_DZ_CONTAINER_FS, VIPS_FOREIGN_DZ_CONTAINER_ZIP, VIPS_FOREIGN_DZ_CONTAINER_SZI, VIPS_FOREIGN_DZ_CONTAINER_LAST /*< skip >*/ } VipsForeignDzContainer; VIPS_API int vips_dzsave(VipsImage *in, const char *name, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dzsave_buffer(VipsImage *in, void **buf, size_t *len, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_dzsave_target(VipsImage *in, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; /** * VipsForeignHeifCompression: * @VIPS_FOREIGN_HEIF_COMPRESSION_HEVC: x265 * @VIPS_FOREIGN_HEIF_COMPRESSION_AVC: x264 * @VIPS_FOREIGN_HEIF_COMPRESSION_JPEG: jpeg * @VIPS_FOREIGN_HEIF_COMPRESSION_AV1: aom * * The compression format to use inside a HEIF container. * * This is assumed to use the same numbering as `heif_compression_format`. */ typedef enum { VIPS_FOREIGN_HEIF_COMPRESSION_HEVC = 1, VIPS_FOREIGN_HEIF_COMPRESSION_AVC = 2, VIPS_FOREIGN_HEIF_COMPRESSION_JPEG = 3, VIPS_FOREIGN_HEIF_COMPRESSION_AV1 = 4, VIPS_FOREIGN_HEIF_COMPRESSION_LAST /*< skip >*/ } VipsForeignHeifCompression; /** * VipsForeignHeifEncoder: * @VIPS_FOREIGN_HEIF_ENCODER_AUTO: auto * @VIPS_FOREIGN_HEIF_ENCODER_AOM: aom * @VIPS_FOREIGN_HEIF_ENCODER_RAV1E: RAV1E * @VIPS_FOREIGN_HEIF_ENCODER_SVT: SVT-AV1 * @VIPS_FOREIGN_HEIF_ENCODER_X265: x265 * * The selected encoder to use. * If libheif hasn't been compiled with the selected encoder, * we will fallback to the default encoder for the compression format. * */ typedef enum { VIPS_FOREIGN_HEIF_ENCODER_AUTO, VIPS_FOREIGN_HEIF_ENCODER_AOM, VIPS_FOREIGN_HEIF_ENCODER_RAV1E, VIPS_FOREIGN_HEIF_ENCODER_SVT, VIPS_FOREIGN_HEIF_ENCODER_X265, VIPS_FOREIGN_HEIF_ENCODER_LAST /*< skip >*/ } VipsForeignHeifEncoder; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_FOREIGN_H*/ libvips-8.18.2/libvips/include/vips/format.h000066400000000000000000000070561516303661500210150ustar00rootroot00000000000000/* Base type for supported image formats. Subclass this to add a new * format. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_FORMAT_H #define VIPS_FORMAT_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_FORMAT (vips_format_get_type()) #define VIPS_FORMAT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_FORMAT, VipsFormat)) #define VIPS_FORMAT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_FORMAT, VipsFormatClass)) #define VIPS_IS_FORMAT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_FORMAT)) #define VIPS_IS_FORMAT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_FORMAT)) #define VIPS_FORMAT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_FORMAT, VipsFormatClass)) /* Image file properties. */ typedef enum { VIPS_FORMAT_NONE = 0, /* No flags set */ VIPS_FORMAT_PARTIAL = 1, /* Lazy read OK (eg. tiled tiff) */ VIPS_FORMAT_BIGENDIAN = 2 /* Most-significant byte first */ } VipsFormatFlags; /* Don't instantiate these things, just use the class stuff. */ typedef struct _VipsFormat { VipsObject parent_object; /*< public >*/ } VipsFormat; typedef struct _VipsFormatClass { VipsObjectClass parent_class; /*< public >*/ /* Is a file in this format. */ gboolean (*is_a)(const char *filename); /* Read just the header into the VipsImage. */ int (*header)(const char *filename, VipsImage *image); /* Load the whole image. */ int (*load)(const char *filename, VipsImage *image); /* Write the VipsImage to the file in this format. */ int (*save)(VipsImage *image, const char *filename); /* Get the flags for this file in this format. */ VipsFormatFlags (*get_flags)(const char *filename); /* Loop over formats in this order, default 0. We need this because * some formats can be read by several loaders (eg. tiff can be read * by the libMagick loader as well as by the tiff loader), and we want * to make sure the better loader comes first. */ int priority; /* Null-terminated list of allowed suffixes, eg. ".tif", ".tiff". */ const char **suffs; } VipsFormatClass; VIPS_API GType vips_format_get_type(void); /* Map over and find formats. This uses type introspection to loop over * subclasses of VipsFormat. */ VIPS_API void *vips_format_map(VipsSListMap2Fn fn, void *a, void *b); VIPS_API VipsFormatClass *vips_format_for_file(const char *filename); VIPS_API VipsFormatClass *vips_format_for_name(const char *filename); VIPS_API VipsFormatFlags vips_format_get_flags(VipsFormatClass *format, const char *filename); /* Read/write an image convenience functions. */ VIPS_API int vips_format_read(const char *filename, VipsImage *out); VIPS_API int vips_format_write(VipsImage *in, const char *filename); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_FORMAT_H*/ libvips-8.18.2/libvips/include/vips/freqfilt.h000066400000000000000000000027771516303661500213460ustar00rootroot00000000000000/* freq_filt.h * * 2/11/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_FREQFILT_H #define VIPS_FREQFILT_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_API int vips_fwfft(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_invfft(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_freqmult(VipsImage *in, VipsImage *mask, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_spectrum(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_phasecor(VipsImage *in1, VipsImage *in2, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_FREQFILT_H*/ libvips-8.18.2/libvips/include/vips/gate.h000066400000000000000000000032021516303661500204320ustar00rootroot00000000000000/* Thread profiling. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_GATE_H #define VIPS_GATE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include #define VIPS_GATE_START(NAME) \ G_STMT_START \ { \ if (vips__thread_profile) \ vips__thread_gate_start(NAME); \ } \ G_STMT_END #define VIPS_GATE_STOP(NAME) \ G_STMT_START \ { \ if (vips__thread_profile) \ vips__thread_gate_stop(NAME); \ } \ G_STMT_END #define VIPS_GATE_MALLOC(SIZE) \ G_STMT_START \ { \ if (vips__thread_profile) \ vips__thread_malloc_free((gint64) (SIZE)); \ } \ G_STMT_END #define VIPS_GATE_FREE(SIZE) \ G_STMT_START \ { \ if (vips__thread_profile) \ vips__thread_malloc_free(-((gint64) (SIZE))); \ } \ G_STMT_END VIPS_API void vips_profile_set(gboolean profile); #endif /*VIPS_GATE_H*/ #ifdef __cplusplus } #endif /*__cplusplus*/ libvips-8.18.2/libvips/include/vips/generate.h000066400000000000000000000046731516303661500213210ustar00rootroot00000000000000/* Generate pixels. * * J.Cupitt, 8/4/93 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_GENERATE_H #define VIPS_GENERATE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef int (*VipsRegionWrite)(VipsRegion *region, VipsRect *area, void *a); VIPS_API int vips_sink_disc(VipsImage *im, VipsRegionWrite write_fn, void *a); VIPS_API int vips_sink(VipsImage *im, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b); VIPS_API int vips_sink_tile(VipsImage *im, int tile_width, int tile_height, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b); typedef void (*VipsSinkNotify)(VipsImage *im, VipsRect *rect, void *a); VIPS_API int vips_sink_screen(VipsImage *in, VipsImage *out, VipsImage *mask, int tile_width, int tile_height, int max_tiles, int priority, VipsSinkNotify notify_fn, void *a); VIPS_API int vips_sink_memory(VipsImage *im); VIPS_API void *vips_start_one(VipsImage *out, void *a, void *b); VIPS_API int vips_stop_one(void *seq, void *a, void *b); VIPS_API void *vips_start_many(VipsImage *out, void *a, void *b); VIPS_API int vips_stop_many(void *seq, void *a, void *b); VIPS_API VipsImage **vips_allocate_input_array(VipsImage *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_image_generate(VipsImage *image, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b); VIPS_API int vips_image_pipeline_array(VipsImage *image, VipsDemandStyle hint, VipsImage **in); VIPS_API int vips_image_pipelinev(VipsImage *image, VipsDemandStyle hint, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_GENERATE_H*/ libvips-8.18.2/libvips/include/vips/header.h000066400000000000000000000235551516303661500207570ustar00rootroot00000000000000/* image header funcs * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_HEADER_H #define VIPS_HEADER_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /** * VIPS_META_EXIF_NAME: * * The name that read and write operations use for the image's EXIF data. */ #define VIPS_META_EXIF_NAME "exif-data" /** * VIPS_META_XMP_NAME: * * The name that read and write operations use for the image's XMP data. */ #define VIPS_META_XMP_NAME "xmp-data" /** * VIPS_META_IPTC_NAME: * * The name that read and write operations use for the image's IPTC data. */ #define VIPS_META_IPTC_NAME "iptc-data" /** * VIPS_META_PHOTOSHOP_NAME: * * The name that TIFF read and write operations use for the image's * TIFFTAG_PHOTOSHOP data. */ #define VIPS_META_PHOTOSHOP_NAME "photoshop-data" /** * VIPS_META_ICC_NAME: * * The name we use to attach an ICC profile. The file read and write * operations for TIFF, JPEG, PNG and others use this item of metadata to * attach and save ICC profiles. The profile is updated by the * [method@Image.icc_transform] operations. */ #define VIPS_META_ICC_NAME "icc-profile-data" /** * VIPS_META_IMAGEDESCRIPTION: * * The IMAGEDESCRIPTION tag. Often has useful metadata. */ #define VIPS_META_IMAGEDESCRIPTION "image-description" /** * VIPS_META_RESOLUTION_UNIT: * * The JPEG and TIFF read and write operations use this to record the * file's preferred unit for resolution. */ #define VIPS_META_RESOLUTION_UNIT "resolution-unit" /** * VIPS_META_BITS_PER_SAMPLE: * * The bits per sample for each channel. */ #define VIPS_META_BITS_PER_SAMPLE "bits-per-sample" /** * VIPS_META_PALETTE: * * Does this image have a palette? */ #define VIPS_META_PALETTE "palette" /** * VIPS_META_LOADER: * * Record the name of the original loader here. Handy for hinting file formats * and for debugging. */ #define VIPS_META_LOADER "vips-loader" /** * VIPS_META_SEQUENTIAL: * * Images loaded via [method@Image.sequential] have this int field defined. Some * operations (eg. [method@Image.shrinkv]) add extra caches if they see it on their * input. */ #define VIPS_META_SEQUENTIAL "vips-sequential" /** * VIPS_META_ORIENTATION: * * The orientation tag for this image. An int from 1 - 8 using the standard * exif/tiff meanings. * * - 1 - The 0th row represents the visual top of the image, and the 0th column * represents the visual left-hand side. * - 2 - The 0th row represents the visual top of the image, and the 0th column * represents the visual right-hand side. * - 3 - The 0th row represents the visual bottom of the image, and the 0th * column represents the visual right-hand side. * - 4 - The 0th row represents the visual bottom of the image, and the 0th * column represents the visual left-hand side. * - 5 - The 0th row represents the visual left-hand side of the image, and the * 0th column represents the visual top. * - 6 - The 0th row represents the visual right-hand side of the image, and the * 0th column represents the visual top. * - 7 - The 0th row represents the visual right-hand side of the image, and the * 0th column represents the visual bottom. * - 8 - The 0th row represents the visual left-hand side of the image, and the * 0th column represents the visual bottom. */ #define VIPS_META_ORIENTATION "orientation" /** * VIPS_META_PAGE_HEIGHT: * * If set, the height of each page when this image was loaded. If you save an * image with "page-height" set to a format that supports multiple pages, such * as tiff, the image will be saved as a series of pages. */ #define VIPS_META_PAGE_HEIGHT "page-height" /** * VIPS_META_N_PAGES: * * If set, the number of pages in the original file. */ #define VIPS_META_N_PAGES "n-pages" /** * VIPS_META_N_SUBIFDS: * * If set, the number of subifds in the first page of the file. */ #define VIPS_META_N_SUBIFDS "n-subifds" /** * VIPS_META_CONCURRENCY: * * If set, the suggested concurrency for this image. */ #define VIPS_META_CONCURRENCY "concurrency" /** * VIPS_META_TILE_WIDTH * * If set, the width of the tiles for this image. */ #define VIPS_META_TILE_WIDTH "tile-width" /** * VIPS_META_TILE_HEIGHT * * If set, the height of the tiles for this image. */ #define VIPS_META_TILE_HEIGHT "tile-height" VIPS_API guint64 vips_format_sizeof(VipsBandFormat format); VIPS_API guint64 vips_format_sizeof_unsafe(VipsBandFormat format); VIPS_API double vips_interpretation_max_alpha(VipsInterpretation interpretation); VIPS_API int vips_interpretation_bands(VipsInterpretation interpretation); VIPS_API int vips_image_get_width(const VipsImage *image); VIPS_API int vips_image_get_height(const VipsImage *image); VIPS_API int vips_image_get_bands(const VipsImage *image); VIPS_API VipsBandFormat vips_image_get_format(const VipsImage *image); VIPS_API double vips_image_get_format_max(VipsBandFormat format); VIPS_API VipsBandFormat vips_image_guess_format(const VipsImage *image); VIPS_API VipsCoding vips_image_get_coding(const VipsImage *image); VIPS_API VipsInterpretation vips_image_get_interpretation(const VipsImage *image); VIPS_API VipsInterpretation vips_image_guess_interpretation(const VipsImage *image); VIPS_API double vips_image_get_xres(const VipsImage *image); VIPS_API double vips_image_get_yres(const VipsImage *image); VIPS_API int vips_image_get_xoffset(const VipsImage *image); VIPS_API int vips_image_get_yoffset(const VipsImage *image); VIPS_API const char *vips_image_get_filename(const VipsImage *image); VIPS_API const char *vips_image_get_mode(const VipsImage *image); VIPS_API double vips_image_get_scale(const VipsImage *image); VIPS_API double vips_image_get_offset(const VipsImage *image); VIPS_API int vips_image_get_page_height(VipsImage *image); VIPS_API int vips_image_get_n_pages(VipsImage *image); VIPS_API int vips_image_get_n_subifds(VipsImage *image); VIPS_API int vips_image_get_orientation(VipsImage *image); VIPS_API gboolean vips_image_get_orientation_swap(VipsImage *image); VIPS_API int vips_image_get_concurrency(VipsImage *image, int default_concurrency); VIPS_API int vips_image_get_tile_width(VipsImage *image); VIPS_API int vips_image_get_tile_height(VipsImage *image); VIPS_API VipsImage *vips_image_get_gainmap(VipsImage *image); VIPS_API const void *vips_image_get_data(VipsImage *image); VIPS_API void vips_image_init_fields(VipsImage *image, int xsize, int ysize, int bands, VipsBandFormat format, VipsCoding coding, VipsInterpretation interpretation, double xres, double yres); VIPS_API void vips_image_set(VipsImage *image, const char *name, GValue *value); VIPS_API int vips_image_get(const VipsImage *image, const char *name, GValue *value_copy); VIPS_API int vips_image_get_as_string(const VipsImage *image, const char *name, char **out); VIPS_API GType vips_image_get_typeof(const VipsImage *image, const char *name); VIPS_API gboolean vips_image_remove(VipsImage *image, const char *name); typedef void *(*VipsImageMapFn)(VipsImage *image, const char *name, GValue *value, void *a); VIPS_API void *vips_image_map(VipsImage *image, VipsImageMapFn fn, void *a); VIPS_API gchar **vips_image_get_fields(VipsImage *image); VIPS_API void vips_image_set_area(VipsImage *image, const char *name, VipsCallbackFn free_fn, void *data); VIPS_API int vips_image_get_area(const VipsImage *image, const char *name, const void **data); VIPS_API void vips_image_set_blob(VipsImage *image, const char *name, VipsCallbackFn free_fn, const void *data, size_t length); VIPS_API void vips_image_set_blob_copy(VipsImage *image, const char *name, const void *data, size_t length); VIPS_API int vips_image_get_blob(const VipsImage *image, const char *name, const void **data, size_t *length); VIPS_API int vips_image_get_int(const VipsImage *image, const char *name, int *out); VIPS_API void vips_image_set_int(VipsImage *image, const char *name, int i); VIPS_API int vips_image_get_double(const VipsImage *image, const char *name, double *out); VIPS_API void vips_image_set_double(VipsImage *image, const char *name, double d); VIPS_API int vips_image_get_string(const VipsImage *image, const char *name, const char **out); VIPS_API void vips_image_set_string(VipsImage *image, const char *name, const char *str); VIPS_API void vips_image_print_field(const VipsImage *image, const char *name); VIPS_API int vips_image_get_image(const VipsImage *image, const char *name, VipsImage **out); VIPS_API void vips_image_set_image(VipsImage *image, const char *name, VipsImage *im); VIPS_API void vips_image_set_array_int(VipsImage *image, const char *name, const int *array, int n); VIPS_API int vips_image_get_array_int(VipsImage *image, const char *name, int **out, int *n); VIPS_API int vips_image_get_array_double(VipsImage *image, const char *name, double **out, int *n); VIPS_API void vips_image_set_array_double(VipsImage *image, const char *name, const double *array, int n); VIPS_API int vips_image_history_printf(VipsImage *image, const char *format, ...) G_GNUC_PRINTF(2, 3); VIPS_API int vips_image_history_args(VipsImage *image, const char *name, int argc, char *argv[]); VIPS_API const char *vips_image_get_history(VipsImage *image); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_HEADER_H*/ libvips-8.18.2/libvips/include/vips/histogram.h000066400000000000000000000043271516303661500215200ustar00rootroot00000000000000/* histograms_lut.h * * 3/11/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_HISTOGRAM_H #define VIPS_HISTOGRAM_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_API int vips_maplut(VipsImage *in, VipsImage **out, VipsImage *lut, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_percent(VipsImage *in, double percent, int *threshold, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_stdif(VipsImage *in, VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_cum(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_norm(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_equal(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_plot(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_match(VipsImage *in, VipsImage *ref, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_local(VipsImage *in, VipsImage **out, int width, int height, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_ismonotonic(VipsImage *in, gboolean *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_hist_entropy(VipsImage *in, double *out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_case(VipsImage *index, VipsImage **cases, VipsImage **out, int n, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_HISTOGRAM_H*/ libvips-8.18.2/libvips/include/vips/image.h000066400000000000000000000433201516303661500206010ustar00rootroot00000000000000/* VIPS image class. * * 7/7/09 * - from vips.h * 2/3/11 * - move to GObject */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_IMAGE_H #define VIPS_IMAGE_H #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* If you read MSB first, you get these two values. * intel order: byte 0 = b6 * SPARC order: byte 0 = 08 */ #define VIPS_MAGIC_INTEL (0xb6a6f208U) #define VIPS_MAGIC_SPARC (0x08f2a6b6U) /* We have a maximum value for a coordinate at various points for sanity * checking. For example, vips_black() has a max with and height. We use int * for width/height so we could go up to 2bn, but it's good to have a lower * value set so we can see crazy numbers early. * * This can be overridden with the `VIPS_MAX_COORD` env var, or the * `--vips-max-coord` CLI arg. */ #define VIPS_DEFAULT_MAX_COORD (100000000) /* Fetch the overridden value. */ #define VIPS_MAX_COORD (vips_max_coord_get()) typedef enum { VIPS_DEMAND_STYLE_ERROR = -1, VIPS_DEMAND_STYLE_SMALLTILE, VIPS_DEMAND_STYLE_FATSTRIP, VIPS_DEMAND_STYLE_THINSTRIP, VIPS_DEMAND_STYLE_ANY } VipsDemandStyle; /* Types of image descriptor we may have. The type field is advisory only: it * does not imply that any fields in IMAGE have valid data. */ typedef enum { VIPS_IMAGE_ERROR = -1, VIPS_IMAGE_NONE, /* no type set */ VIPS_IMAGE_SETBUF, /* malloced memory array */ VIPS_IMAGE_SETBUF_FOREIGN, /* memory array, don't free on close */ VIPS_IMAGE_OPENIN, /* input from fd with a window */ VIPS_IMAGE_MMAPIN, /* memory mapped input file */ VIPS_IMAGE_MMAPINRW, /* memory mapped read/write file */ VIPS_IMAGE_OPENOUT, /* output to fd */ VIPS_IMAGE_PARTIAL /* partial image */ } VipsImageType; typedef enum { VIPS_INTERPRETATION_ERROR = -1, VIPS_INTERPRETATION_MULTIBAND = 0, VIPS_INTERPRETATION_B_W = 1, VIPS_INTERPRETATION_HISTOGRAM = 10, VIPS_INTERPRETATION_XYZ = 12, VIPS_INTERPRETATION_LAB = 13, VIPS_INTERPRETATION_CMYK = 15, VIPS_INTERPRETATION_LABQ = 16, VIPS_INTERPRETATION_RGB = 17, VIPS_INTERPRETATION_CMC = 18, VIPS_INTERPRETATION_LCH = 19, VIPS_INTERPRETATION_LABS = 21, VIPS_INTERPRETATION_sRGB = 22, VIPS_INTERPRETATION_YXY = 23, VIPS_INTERPRETATION_FOURIER = 24, VIPS_INTERPRETATION_RGB16 = 25, VIPS_INTERPRETATION_GREY16 = 26, VIPS_INTERPRETATION_MATRIX = 27, VIPS_INTERPRETATION_scRGB = 28, VIPS_INTERPRETATION_HSV = 29, VIPS_INTERPRETATION_OKLAB = 30, VIPS_INTERPRETATION_OKLCH = 31, VIPS_INTERPRETATION_LAST = 32 /*< skip >*/ } VipsInterpretation; typedef enum { VIPS_FORMAT_NOTSET = -1, VIPS_FORMAT_UCHAR = 0, VIPS_FORMAT_CHAR = 1, VIPS_FORMAT_USHORT = 2, VIPS_FORMAT_SHORT = 3, VIPS_FORMAT_UINT = 4, VIPS_FORMAT_INT = 5, VIPS_FORMAT_FLOAT = 6, VIPS_FORMAT_COMPLEX = 7, VIPS_FORMAT_DOUBLE = 8, VIPS_FORMAT_DPCOMPLEX = 9, VIPS_FORMAT_LAST = 10 /*< skip >*/ } VipsBandFormat; typedef enum { VIPS_CODING_ERROR = -1, VIPS_CODING_NONE = 0, VIPS_CODING_LABQ = 2, VIPS_CODING_RAD = 6, VIPS_CODING_LAST = 7 /*< skip >*/ } VipsCoding; typedef enum { VIPS_ACCESS_RANDOM, VIPS_ACCESS_SEQUENTIAL, VIPS_ACCESS_SEQUENTIAL_UNBUFFERED VIPS_DEPRECATED_ENUMERATOR_FOR(VIPS_ACCESS_SEQUENTIAL), VIPS_ACCESS_LAST /*< skip >*/ } VipsAccess; typedef void *(*VipsStartFn)(VipsImage *out, void *a, void *b); typedef int (*VipsGenerateFn)(VipsRegion *out, void *seq, void *a, void *b, gboolean *stop); typedef int (*VipsStopFn)(void *seq, void *a, void *b); /* Struct we keep a record of execution time in. Passed to eval signal so * it can assess progress. */ typedef struct _VipsProgress { /*< private >*/ VipsImage *im; /* Image we are part of */ /*< public >*/ int run; /* Time we have been running */ int eta; /* Estimated seconds of computation left */ gint64 tpels; /* Number of pels we expect to calculate */ gint64 npels; /* Number of pels calculated so far */ int percent; /* Percent complete */ GTimer *start; /* Start time */ } VipsProgress; #define VIPS_TYPE_IMAGE (vips_image_get_type()) #define VIPS_IMAGE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_IMAGE, VipsImage)) #define VIPS_IMAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_IMAGE, VipsImageClass)) #define VIPS_IS_IMAGE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_IMAGE)) #define VIPS_IS_IMAGE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_IMAGE)) #define VIPS_IMAGE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_IMAGE, VipsImageClass)) /* Matching typedef in basic.h. */ struct _VipsImage { VipsObject parent_instance; /*< private >*/ /* We have to keep these names for compatibility with the old API. * Don't use them though, use vips_image_get_width() and friends. */ int Xsize; /* image width, in pixels */ int Ysize; /* image height, in pixels */ int Bands; /* number of image bands */ VipsBandFormat BandFmt; /* pixel format */ VipsCoding Coding; /* pixel coding */ VipsInterpretation Type; /* pixel interpretation */ double Xres; /* horizontal pixels per millimetre */ double Yres; /* vertical pixels per millimetre */ int Xoffset; /* image origin hint */ int Yoffset; /* image origin hint */ /* No longer used, the names are here for compat with very, very old * code. */ int Length; short Compression; short Level; int Bbits; /* was number of bits in this format */ /* Old code expects to see this member, newer code has a param on * eval(). */ VipsProgress *time; /* Derived fields that some code can fiddle with. New code should use * vips_image_get_history() and friends. */ char *Hist; /* don't use, see vips_image_get_history() */ char *filename; /* pointer to copy of filename */ VipsPel *data; /* start of image data for WIO */ int kill; /* set to non-zero to block eval */ /* Everything below this private and only used internally by * VipsImage. */ /* During vips image read and write we need temporary float-sized * fields in the struct for staging xres/yres. Don't use these any * other time. */ float Xres_float; float Yres_float; char *mode; /* mode string passed to _new() */ VipsImageType dtype; /* descriptor type */ int fd; /* file descriptor */ void *baseaddr; /* pointer to the start of an mmap file */ size_t length; /* size of mmap area */ guint32 magic; /* magic from header, endian-ness of image */ /* Partial image stuff. All these fields are initialised * to NULL and ignored unless set by vips_image_generate() etc. */ VipsStartFn start_fn; VipsGenerateFn generate_fn; VipsStopFn stop_fn; void *client1; /* user arguments */ void *client2; GMutex sslock; /* start-stop lock */ GSList *regions; /* list of regions current for this image */ VipsDemandStyle dhint; /* demand style hint */ /* Extra user-defined fields ... see vips_image_get() etc. */ GHashTable *meta; /* GhashTable of GValue */ GSList *meta_traverse; /* traverse order for Meta */ /* Part of mmap() read ... the sizeof() the header we skip from the * file start. Usually VIPS_SIZEOF_HEADER, but can be something else * for binary file read. * * guint64 so that we can guarantee to work even on systems with * strange ideas about large files. */ gint64 sizeof_header; /* If this is a large disc image, don't map the whole thing, instead * have a set of windows shared between the regions active on the * image. List of VipsWindow. */ GSList *windows; /* Upstream/downstream relationships, built from args to * vips_demand_hint(). * * We use these to invalidate downstream pixel buffers. * Use 'serial' to spot circular dependencies. * * See also hint_set below. */ GSList *upstream; GSList *downstream; int serial; /* Keep a list of recounted GValue strings so we can share hist * efficiently. */ GSList *history_list; /* The VipsImage (if any) we should signal eval progress on. */ VipsImage *progress_signal; /* Record the file length here. We use this to stop ourselves mapping * things beyond the end of the file in the case that the file has * been truncated. * * gint64 so that we can guarantee to work even on systems with * strange ideas about large files. */ gint64 file_length; /* Set this when vips_demand_hint_array() is called, and check in any * operation that will demand pixels from the image. * * We use vips_demand_hint_array() to build the tree of * upstream/downstream relationships, so it's a mandatory thing. */ gboolean hint_set; /* Delete-on-close is hard to do with signals and callbacks since we * really need to do this in finalize after the fd has been closed, * but you can't emit signals then. * * Also keep a private copy of the filename string to be deleted, * since image->filename will be freed in _dispose(). */ gboolean delete_on_close; char *delete_on_close_filename; }; typedef struct _VipsImageClass { VipsObjectClass parent_class; /* Signals we emit. */ /* Evaluation is starting. */ void (*preeval)(VipsImage *image, VipsProgress *progress, void *data); /* Evaluation progress. */ void (*eval)(VipsImage *image, VipsProgress *progress, void *data); /* Evaluation is ending. */ void (*posteval)(VipsImage *image, VipsProgress *progress, void *data); /* An image has been written to. * Used by eg. vips_image_new_mode("x.jpg", "w") to do the * final write to jpeg. * Set *result to non-zero to indicate an error on write. */ void (*written)(VipsImage *image, int *result, void *data); /* An image has been modified in some way and all caches * need dropping. */ void (*invalidate)(VipsImage *image, void *data); /* Minimise this pipeline. * * This is triggered (sometimes) at the end of eval to signal that * we're probably done and that operations involved should try to * minimise memory use by, for example, dropping caches. * * See vips_tilecache(). */ void (*minimise)(VipsImage *image, void *data); } VipsImageClass; VIPS_API GType vips_image_get_type(void); /* Has to be guint64 and not size_t/off_t since we have to be able to address * huge images on platforms with 32-bit files. */ /* Pixel address calculation macros. */ #define VIPS_IMAGE_SIZEOF_ELEMENT(I) \ (vips_format_sizeof_unsafe((I)->BandFmt)) #define VIPS_IMAGE_SIZEOF_PEL(I) \ (VIPS_IMAGE_SIZEOF_ELEMENT(I) * (I)->Bands) #define VIPS_IMAGE_SIZEOF_LINE(I) \ (VIPS_IMAGE_SIZEOF_PEL(I) * (I)->Xsize) #define VIPS_IMAGE_SIZEOF_IMAGE(I) \ (VIPS_IMAGE_SIZEOF_LINE(I) * (I)->Ysize) #define VIPS_IMAGE_N_ELEMENTS(I) \ ((I)->Bands * (I)->Xsize) #define VIPS_IMAGE_N_PELS(I) \ ((guint64) (I)->Xsize * (I)->Ysize) /* If VIPS_DEBUG is defined, add bounds checking. */ #ifdef VIPS_DEBUG #define VIPS_IMAGE_ADDR(I, X, Y) \ (((X) >= 0 && (X) < VIPS_IMAGE(I)->Xsize && \ (Y) >= 0 && (Y) < VIPS_IMAGE(I)->Ysize && \ VIPS_IMAGE(I)->data) \ ? (VIPS_IMAGE(I)->data + \ (Y) *VIPS_IMAGE_SIZEOF_LINE(I) + \ (X) *VIPS_IMAGE_SIZEOF_PEL(I)) \ : (fprintf(stderr, \ "VIPS_IMAGE_ADDR: point out of bounds, " \ "file \"%s\", line %d\n" \ "(point x=%d, y=%d\n" \ " should have been within VipsRect left=%d, top=%d, " \ "width=%d, height=%d)\n", \ __FILE__, __LINE__, \ (X), (Y), \ 0, 0, \ VIPS_IMAGE(I)->Xsize, \ VIPS_IMAGE(I)->Ysize), \ (VipsPel *) NULL)) #else /*!VIPS_DEBUG*/ #define VIPS_IMAGE_ADDR(I, X, Y) \ ((I)->data + \ (Y) *VIPS_IMAGE_SIZEOF_LINE(I) + \ (X) *VIPS_IMAGE_SIZEOF_PEL(I)) #endif /*VIPS_DEBUG*/ #ifdef VIPS_DEBUG #define VIPS_MATRIX(I, X, Y) \ ((VIPS_IMAGE(I)->BandFmt == VIPS_FORMAT_DOUBLE && \ VIPS_IMAGE(I)->Bands == 1) \ ? ((double *) VIPS_IMAGE_ADDR(I, X, Y)) \ : (fprintf(stderr, "VIPS_MATRIX: not a matrix image\n"), \ (double *) NULL)) #else /*!VIPS_DEBUG*/ #define VIPS_MATRIX(I, X, Y) \ ((double *) VIPS_IMAGE_ADDR(I, X, Y)) #endif /*VIPS_DEBUG*/ VIPS_API void vips_progress_set(gboolean progress); VIPS_API void vips_image_invalidate_all(VipsImage *image); VIPS_API void vips_image_minimise_all(VipsImage *image); VIPS_API gboolean vips_image_is_sequential(VipsImage *image); VIPS_API void vips_image_preeval(VipsImage *image); VIPS_API void vips_image_eval(VipsImage *image, guint64 processed); VIPS_API void vips_image_posteval(VipsImage *image); VIPS_API void vips_image_set_progress(VipsImage *image, gboolean progress); VIPS_API gboolean vips_image_iskilled(VipsImage *image); VIPS_API void vips_image_set_kill(VipsImage *image, gboolean kill); VIPS_API char *vips_filename_get_filename(const char *vips_filename); VIPS_API char *vips_filename_get_options(const char *vips_filename); VIPS_API VipsImage *vips_image_new(void); VIPS_API VipsImage *vips_image_new_memory(void); VIPS_API VipsImage *vips_image_memory(void); VIPS_API VipsImage *vips_image_new_from_file(const char *name, ...) G_GNUC_NULL_TERMINATED; VIPS_API VipsImage *vips_image_new_from_file_RW(const char *filename); VIPS_API VipsImage *vips_image_new_from_file_raw(const char *filename, int xsize, int ysize, int bands, guint64 offset); VIPS_API VipsImage *vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format); VIPS_API VipsImage *vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format); VIPS_API VipsImage *vips_image_new_from_buffer(const void *buf, size_t len, const char *option_string, ...) G_GNUC_NULL_TERMINATED; VIPS_API VipsImage *vips_image_new_from_source(VipsSource *source, const char *option_string, ...) G_GNUC_NULL_TERMINATED; VIPS_API VipsImage *vips_image_new_matrix(int width, int height); VIPS_API VipsImage *vips_image_new_matrixv(int width, int height, ...); VIPS_API VipsImage *vips_image_new_matrix_from_array(int width, int height, const double *array, int size); VIPS_API VipsImage *vips_image_matrix_from_array(int width, int height, const double *array, int size); VIPS_API VipsImage *vips_image_new_from_image(VipsImage *image, const double *c, int n); VIPS_API VipsImage *vips_image_new_from_image1(VipsImage *image, double c); VIPS_API void vips_image_set_delete_on_close(VipsImage *image, gboolean delete_on_close); VIPS_API guint64 vips_get_disc_threshold(void); VIPS_API VipsImage *vips_image_new_temp_file(const char *format); VIPS_API int vips_image_write(VipsImage *image, VipsImage *out); VIPS_API int vips_image_write_to_file(VipsImage *image, const char *name, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_image_write_to_buffer(VipsImage *in, const char *suffix, void **buf, size_t *size, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_image_write_to_target(VipsImage *in, const char *suffix, VipsTarget *target, ...) G_GNUC_NULL_TERMINATED; VIPS_API void *vips_image_write_to_memory(VipsImage *in, size_t *size); VIPS_API int vips_image_decode_predict(VipsImage *in, int *bands, VipsBandFormat *format); VIPS_API int vips_image_decode(VipsImage *in, VipsImage **out); VIPS_API int vips_image_encode(VipsImage *in, VipsImage **out, VipsCoding coding); VIPS_API gboolean vips_image_isMSBfirst(VipsImage *image); VIPS_API gboolean vips_image_isfile(VipsImage *image); VIPS_API gboolean vips_image_ispartial(VipsImage *image); VIPS_API gboolean vips_image_hasalpha(VipsImage *image); VIPS_API VipsImage *vips_image_copy_memory(VipsImage *image); VIPS_API int vips_image_wio_input(VipsImage *image); VIPS_API int vips_image_pio_input(VipsImage *image); VIPS_API int vips_image_pio_output(VipsImage *image); VIPS_API int vips_image_inplace(VipsImage *image); VIPS_API int vips_image_write_prepare(VipsImage *image); VIPS_API int vips_image_write_line(VipsImage *image, int ypos, VipsPel *linebuffer); VIPS_API gboolean vips_band_format_isint(VipsBandFormat format); VIPS_API gboolean vips_band_format_isuint(VipsBandFormat format); VIPS_API gboolean vips_band_format_is8bit(VipsBandFormat format); VIPS_API gboolean vips_band_format_isfloat(VipsBandFormat format); VIPS_API gboolean vips_band_format_iscomplex(VipsBandFormat format); VIPS_API int vips_system(const char *cmd_format, ...) G_GNUC_NULL_TERMINATED; /* Defined in type.c but declared here, since they use VipsImage. */ VIPS_API VipsArrayImage *vips_array_image_new(VipsImage **array, int n); VIPS_API VipsArrayImage *vips_array_image_newv(int n, ...); VIPS_API VipsArrayImage *vips_array_image_new_from_string(const char *string, VipsAccess flags); VIPS_API VipsArrayImage *vips_array_image_empty(void); VIPS_API VipsArrayImage *vips_array_image_append(VipsArrayImage *array, VipsImage *image); VIPS_API VipsImage **vips_array_image_get(VipsArrayImage *array, int *n); VIPS_API VipsImage **vips_value_get_array_image(const GValue *value, int *n); VIPS_API void vips_value_set_array_image(GValue *value, int n); /* Defined in reorder.c, but really a function on image. */ VIPS_API int vips_reorder_prepare_many(VipsImage *image, VipsRegion **regions, VipsRect *r); VIPS_API void vips_reorder_margin_hint(VipsImage *image, int margin); VIPS_API void vips_image_free_buffer(VipsImage *image, void *buffer); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_IMAGE_H*/ libvips-8.18.2/libvips/include/vips/internal.h000066400000000000000000000321001516303661500213250ustar00rootroot00000000000000/* Declarations only used internally to vips. See private.h for declarations * which are not public, but which have to be publicly visible. * * 11/9/06 * - cut from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_INTERNAL_H #define VIPS_INTERNAL_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Try to make an O_BINARY and O_NOINHERIT ... sometimes need the leading '_'. */ #if defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN) #ifndef O_BINARY #ifdef _O_BINARY #define O_BINARY _O_BINARY #endif /*_O_BINARY*/ #endif /*!O_BINARY*/ #ifndef O_NOINHERIT #ifdef _O_NOINHERIT #define O_NOINHERIT _O_NOINHERIT #endif /*_O_NOINHERIT*/ #endif /*!O_NOINHERIT*/ #endif /*defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN)*/ /* If we have O_BINARY, add it to a mode flags set. */ #ifdef O_BINARY #define BINARYIZE(M) ((M) | O_BINARY) #else /*!O_BINARY*/ #define BINARYIZE(M) (M) #endif /*O_BINARY*/ /* If we have O_CLOEXEC or O_NOINHERIT, add it to a mode flags set. */ #ifdef O_CLOEXEC #define CLOEXEC(M) ((M) | O_CLOEXEC) #elif defined(O_NOINHERIT) #define CLOEXEC(M) ((M) | O_NOINHERIT) #else /*!O_CLOEXEC && !O_NOINHERIT*/ #define CLOEXEC(M) (M) #endif /*O_CLOEXEC*/ /* C99 restrict keyword */ #ifdef __cplusplus #define restrict __restrict #endif /* << on an int is undefined in C if the int is negative. Imagine a machine * that uses 1s complement, for example. * * Fuzzers find and warn about this, so we must use this macro instead. Cast * to uint, shift, and cast back. */ #define VIPS_LSHIFT_INT(I, N) ((int) ((unsigned int) (I) << (N))) /* What we store in the Meta hash table. We can't just use GHashTable's * key/value pairs, since we need to iterate over meta in Meta_traverse order. * * We don't refcount at this level ... large meta values are refcounted by * their GValue implementation, see eg. MetaArea. */ typedef struct _VipsMeta { VipsImage *im; char *name; /* strdup() of field name */ GValue value; /* copy of value */ } VipsMeta; /* TODO(kleisauke): VIPS_API is required by the magick module. */ VIPS_API int vips__exif_parse(VipsImage *image); int vips__exif_update(VipsImage *image); void vips_check_init(void); /* Set from the command-line. */ extern gboolean vips__vector_enabled; void vips__vector_init(void); void vips__meta_init_types(void); void vips__meta_destroy(VipsImage *im); int vips__meta_cp(VipsImage *, const VipsImage *); /* Default tile geometry. */ extern int vips__tile_width; extern int vips__tile_height; extern int vips__fatstrip_height; extern int vips__thinstrip_height; /* Default n threads. */ extern int vips__concurrency; /* abort() on any error. */ extern int vips__fatal; /* Enable leak check. */ extern int vips__leak; /* Give progress feedback. */ extern int vips__progress; /* Show info messages. Handy for debugging. */ extern int vips__info; /* A string giving the image size (in bytes of uncompressed image) above which * we decompress to disc on open. */ extern char *vips__disc_threshold; extern gboolean vips__cache_dump; extern gboolean vips__cache_trace; extern float vips_v2Y_16[65536]; void vips__thread_init(void); void vips__threadpool_init(void); void vips__threadpool_shutdown(void); typedef struct _VipsThreadset VipsThreadset; VipsThreadset *vips_threadset_new(int max_threads); int vips_threadset_run(VipsThreadset *set, const char *domain, GFunc func, gpointer data); void vips_threadset_free(VipsThreadset *set); VIPS_API void vips__worker_lock(GMutex *mutex); VIPS_API void vips__worker_cond_wait(GCond *cond, GMutex *mutex); gboolean vips__worker_exit(void); void vips__cache_init(void); int vips__print_renders(void); int vips__type_leak(void); int vips__object_leak(void); #ifdef HAVE_OPENSLIDE int vips__openslideconnection_leak(void); #endif /*HAVE_OPENSLIDE*/ /* iofuncs */ int vips__open_image_read(const char *filename); int vips__open_image_write(const char *filename, gboolean temp); /* Defined in `vips.h`, unless building with `-Ddeprecated=false` */ #if !VIPS_ENABLE_DEPRECATED int vips_image_open_input(VipsImage *image); int vips_image_open_output(VipsImage *image); #endif void vips__link_break_all(VipsImage *im); void *vips__link_map(VipsImage *image, gboolean upstream, VipsSListMap2Fn fn, void *a, void *b); gboolean vips__mmap_supported(int fd); void *vips__mmap(int fd, int writeable, size_t length, gint64 offset); int vips__munmap(const void *start, size_t length); /* Defined in `vips.h`, unless building with `-Ddeprecated=false` */ #if !VIPS_ENABLE_DEPRECATED int vips_mapfile(VipsImage *image); int vips_mapfilerw(VipsImage *image); int vips_remapfilerw(VipsImage *image); #endif void vips__buffer_init(void); void vips__buffer_shutdown(void); void vips__copy_4byte(int swap, unsigned char *to, unsigned char *from); void vips__copy_2byte(gboolean swap, unsigned char *to, unsigned char *from); guint32 vips__file_magic(const char *filename); /* TODO(kleisauke): VIPS_API is required by vipsheader. */ VIPS_API int vips__has_extension_block(VipsImage *im); /* TODO(kleisauke): VIPS_API is required by vipsheader. */ VIPS_API void *vips__read_extension_block(VipsImage *im, size_t *size); /* TODO(kleisauke): VIPS_API is required by vipsedit. */ VIPS_API int vips__write_extension_block(VipsImage *im, void *buf, size_t size); int vips__writehist(VipsImage *image); /* TODO(kleisauke): VIPS_API is required by vipsedit. */ VIPS_API int vips__read_header_bytes(VipsImage *im, unsigned char *from); /* TODO(kleisauke): VIPS_API is required by vipsedit. */ VIPS_API int vips__write_header_bytes(VipsImage *im, unsigned char *to); int vips__image_meta_copy(VipsImage *dst, const VipsImage *src); extern GMutex vips__global_lock; int vips_image_written(VipsImage *image); /* Defined in `vips.h`, unless building with `-Ddeprecated=false` */ #if !VIPS_ENABLE_DEPRECATED VipsImage *vips_image_new_mode(const char *filename, const char *mode); #endif int vips__formatalike_vec(VipsImage **in, VipsImage **out, int n); int vips__sizealike_vec(VipsImage **in, VipsImage **out, int n); int vips__bandup(const char *domain, VipsImage *in, VipsImage **out, int n); int vips__bandalike_vec(const char *domain, VipsImage **in, VipsImage **out, int n, int base_bands); int vips__formatalike(VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2); int vips__sizealike(VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2); int vips__bandalike(const char *domain, VipsImage *in1, VipsImage *in2, VipsImage **out1, VipsImage **out2); /* draw */ VipsPel *vips__vector_to_pels(const char *domain, int bands, VipsBandFormat format, VipsCoding coding, double *real, double *imag, int n); /* TODO(kleisauke): VIPS_API is required by the poppler module. */ VIPS_API VipsPel *vips__vector_to_ink(const char *domain, VipsImage *im, double *real, double *imag, int n); int vips__draw_flood_direct(VipsImage *image, VipsImage *test, int serial, int x, int y); int vips__draw_mask_direct(VipsImage *image, VipsImage *mask, VipsPel *ink, int x, int y); typedef void (*VipsDrawPoint)(VipsImage *image, int x, int y, void *client); typedef void (*VipsDrawScanline)(VipsImage *image, int y, int x1, int x2, int quadrant, void *client); void vips__draw_line_direct(VipsImage *image, int x1, int y1, int x2, int y2, VipsDrawPoint draw_point, void *client); void vips__draw_circle_direct(VipsImage *image, int cx, int cy, int r, VipsDrawScanline draw_scanline, void *client); int vips__insert_paste_region(VipsRegion *out, VipsRegion *in, VipsRect *pos); /* Register base vips interpolators, called during startup. */ void vips__interpolate_init(void); /* Start up various packages. */ void vips_arithmetic_operation_init(void); void vips_conversion_operation_init(void); void vips_resample_operation_init(void); void vips_foreign_operation_init(void); void vips_colour_operation_init(void); void vips_histogram_operation_init(void); void vips_freqfilt_operation_init(void); void vips_create_operation_init(void); void vips_morphology_operation_init(void); void vips_convolution_operation_init(void); void vips_draw_operation_init(void); void vips_mosaicing_operation_init(void); void vips_cimg_operation_init(void); guint64 vips__parse_size(const char *size_string); /* TODO(kleisauke): VIPS_API is required by vipsthumbnail. */ VIPS_API int vips__substitutec(char *buf, size_t len, char c, char *sub); VIPS_API int vips__substitute(char *buf, size_t len, char *sub); int vips_check_coding_labq(const char *domain, VipsImage *im); int vips_check_coding_rad(const char *domain, VipsImage *im); int vips_check_bands_3ormore(const char *domain, VipsImage *im); int vips__byteswap_bool(VipsImage *in, VipsImage **out, gboolean swap); char *vips__xml_properties(VipsImage *image); /* TODO(kleisauke): VIPS_API is required by the poppler module. */ VIPS_API void vips__premultiplied_bgra2rgba(guint32 *restrict p, int n); VIPS_API void vips__rgba2bgra_premultiplied(guint32 *restrict p, int n); void vips__premultiplied_rgb1282scrgba(float *p, int n); void vips__bgra2rgba(guint32 *restrict p, int n); void vips__Lab2LabQ_vec(VipsPel *out, float *in, int width); void vips__LabQ2Lab_vec(float *out, VipsPel *in, int width); void vips_col_make_tables_RGB_16(void); #ifdef DEBUG_LEAK extern GQuark vips__image_pixels_quark; #endif /*DEBUG_LEAK*/ /* With DEBUG_LEAK, hang one of these off each image and count pixels * calculated. */ typedef struct _VipsImagePixels { const char *nickname; gint64 tpels; /* Number of pels we expect to calculate */ gint64 npels; /* Number of pels calculated so far */ } VipsImagePixels; int vips__foreign_convert_saveable(VipsImage *in, VipsImage **ready, VipsForeignSaveable saveable, VipsBandFormat *format, VipsForeignCoding coding, VipsArrayDouble *background); int vips_foreign_load(const char *filename, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; int vips_foreign_save(VipsImage *in, const char *filename, ...) G_GNUC_NULL_TERMINATED; int vips__image_intize(VipsImage *in, VipsImage **out); void vips__reorder_init(void); int vips__reorder_set_input(VipsImage *image, VipsImage **in); void vips__reorder_clear(VipsImage *image); /* Window manager API. */ VipsWindow *vips_window_take(VipsWindow *window, VipsImage *im, int top, int height); int vips__profile_set(VipsImage *image, const char *name); void vips__thread_profile_attach(const char *thread_name); void vips__thread_profile_detach(void); void vips__thread_profile_stop(void); int vips__lrmosaic(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int mwidth); int vips__tbmosaic(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int mwidth); int vips__correl(VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y); unsigned int vips_operation_hash(VipsOperation *operation); int vips__open_read(const char *filename); FILE *vips__fopen(const char *filename, const char *mode); char *vips__file_read_name(const char *name, const char *fallback_dir, size_t *length_out); int vips__file_write(void *data, size_t size, size_t nmemb, FILE *stream); int vips__fgetc(FILE *fp); GValue *vips__gvalue_ref_string_new(const char *text); void vips__gslist_gvalue_free(GSList *list); GSList *vips__gslist_gvalue_copy(const GSList *list); GSList *vips__gslist_gvalue_merge(GSList *a, const GSList *b); char *vips__gslist_gvalue_get(const GSList *list); gint64 vips__seek_no_error(int fd, gint64 pos, int whence); int vips__ftruncate(int fd, gint64 pos); const char *vips__token_must(const char *buffer, VipsToken *token, char *string, int size); const char *vips__token_need(const char *buffer, VipsToken need_token, char *string, int size); const char *vips__token_segment(const char *p, VipsToken *token, char *string, int size); const char *vips__token_segment_need(const char *p, VipsToken need_token, char *string, int size); const char *vips__find_rightmost_brackets(const char *p); void vips__change_suffix(const char *name, char *out, int mx, const char *new_suff, const char **olds, int nolds); guint32 vips__random(guint32 seed); guint32 vips__random_add(guint32 seed, int value); const char *vips__icc_dir(void); const char *vips__windows_prefix(void); char *vips__get_iso8601(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_INTERNAL_H*/ libvips-8.18.2/libvips/include/vips/interpolate.h000066400000000000000000000100721516303661500220430ustar00rootroot00000000000000/* Various interpolators. * * J.Cupitt, 15/10/08 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_INTERPOLATE_H #define VIPS_INTERPOLATE_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_INTERPOLATE (vips_interpolate_get_type()) #define VIPS_INTERPOLATE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE, VipsInterpolate)) #define VIPS_INTERPOLATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE, VipsInterpolateClass)) #define VIPS_IS_INTERPOLATE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE)) #define VIPS_IS_INTERPOLATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE)) #define VIPS_INTERPOLATE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE, VipsInterpolateClass)) struct _VipsInterpolate { VipsObject parent_object; }; /* An interpolation function. This is a class method, but we have a lookup * function for it to speed up dispatch. Write to the memory at "out", * interpolate the value at position (x, y) in "in". */ typedef void (*VipsInterpolateMethod)(VipsInterpolate *interpolate, void *out, VipsRegion *in, double x, double y); typedef struct _VipsInterpolateClass { VipsObjectClass parent_class; /* Write to pixel out(x,y), interpolating from in(x,y). The caller has * to set the regions up. */ VipsInterpolateMethod interpolate; /* This interpolator needs a window this many pixels across and down. */ int (*get_window_size)(VipsInterpolate *interpolate); /* Or just set this if you want a constant. */ int window_size; /* Stencils are offset by this much. Default to window_size / 2 - 1 * (centering) if get_window_offset is NULL and window_offset is -1. */ int (*get_window_offset)(VipsInterpolate *interpolate); int window_offset; } VipsInterpolateClass; VIPS_API GType vips_interpolate_get_type(void); VIPS_API void vips_interpolate(VipsInterpolate *interpolate, void *out, VipsRegion *in, double x, double y); VIPS_API VipsInterpolateMethod vips_interpolate_get_method(VipsInterpolate *interpolate); VIPS_API int vips_interpolate_get_window_size(VipsInterpolate *interpolate); VIPS_API int vips_interpolate_get_window_offset(VipsInterpolate *interpolate); /* How many bits of precision we keep for transformations, ie. how many * pre-computed matrices we have. */ #define VIPS_TRANSFORM_SHIFT (6) #define VIPS_TRANSFORM_SCALE (1 << VIPS_TRANSFORM_SHIFT) /* How many bits of precision we keep for interpolation, ie. where the decimal * is in the fixed-point tables. For 16-bit pixels, we need 16 bits for the * data and 4 bits to add 16 values together. That leaves 12 bits for the * fractional part. */ #define VIPS_INTERPOLATE_SHIFT (12) #define VIPS_INTERPOLATE_SCALE (1 << VIPS_INTERPOLATE_SHIFT) /* Convenience: return static interpolators, no need to unref. */ VIPS_API VipsInterpolate *vips_interpolate_nearest_static(void); VIPS_API VipsInterpolate *vips_interpolate_bilinear_static(void); /* Convenience: make an interpolator from a nickname. g_object_unref() when * you're done with it. */ VIPS_API VipsInterpolate *vips_interpolate_new(const char *nickname); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_INTERPOLATE_H*/ libvips-8.18.2/libvips/include/vips/intl.h000066400000000000000000000004311516303661500204610ustar00rootroot00000000000000/* i18n stuff for vips. Deprecated in favour of glib/gi18n.h. */ #ifndef VIPS_INTL_H #define VIPS_INTL_H #ifdef ENABLE_NLS #include #else /*!ENABLE_NLS*/ #define _(String) (String) #define N_(String) (String) #endif /* ENABLE_NLS */ #endif /* VIPS_INTL_H */ libvips-8.18.2/libvips/include/vips/mask.h000066400000000000000000000105051516303661500204510ustar00rootroot00000000000000/* mask.h * * 20/9/09 * - from proto.h */ /* All deprecated. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IM_MASK_H #define IM_MASK_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef struct im__INTMASK { int xsize; int ysize; int scale; int offset; int *coeff; char *filename; } INTMASK; typedef struct im__DOUBLEMASK { int xsize; int ysize; double scale; double offset; double *coeff; char *filename; } DOUBLEMASK; #define IM_MASK(M, X, Y) ((M)->coeff[(X) + (Y) * (M)->xsize]) VIPS_DEPRECATED INTMASK *im_create_imask(const char *filename, int xsize, int ysize); VIPS_DEPRECATED INTMASK *im_create_imaskv(const char *filename, int xsize, int ysize, ...); VIPS_DEPRECATED DOUBLEMASK *im_create_dmask(const char *filename, int xsize, int ysize); VIPS_DEPRECATED DOUBLEMASK *im_create_dmaskv(const char *filename, int xsize, int ysize, ...); VIPS_DEPRECATED INTMASK *im_read_imask(const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_read_dmask(const char *filename); VIPS_DEPRECATED void im_print_imask(INTMASK *in); VIPS_DEPRECATED void im_print_dmask(DOUBLEMASK *in); VIPS_DEPRECATED int im_write_imask(INTMASK *in); VIPS_DEPRECATED int im_write_dmask(DOUBLEMASK *in); VIPS_DEPRECATED int im_write_imask_name(INTMASK *in, const char *filename); VIPS_DEPRECATED int im_write_dmask_name(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED int im_free_imask(INTMASK *in); VIPS_DEPRECATED int im_free_dmask(DOUBLEMASK *in); VIPS_DEPRECATED INTMASK *im_log_imask(const char *filename, double sigma, double min_ampl); VIPS_DEPRECATED DOUBLEMASK *im_log_dmask(const char *filename, double sigma, double min_ampl); VIPS_DEPRECATED INTMASK *im_gauss_imask(const char *filename, double sigma, double min_ampl); VIPS_DEPRECATED INTMASK *im_gauss_imask_sep(const char *filename, double sigma, double min_ampl); VIPS_DEPRECATED DOUBLEMASK *im_gauss_dmask(const char *filename, double sigma, double min_ampl); VIPS_DEPRECATED DOUBLEMASK *im_gauss_dmask_sep(const char *filename, double sigma, double min_ampl); VIPS_DEPRECATED INTMASK *im_dup_imask(INTMASK *in, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_dup_dmask(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED INTMASK *im_scale_dmask(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED void im_norm_dmask(DOUBLEMASK *mask); VIPS_DEPRECATED DOUBLEMASK *im_imask2dmask(INTMASK *in, const char *filename); VIPS_DEPRECATED INTMASK *im_dmask2imask(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED INTMASK *im_rotate_imask90(INTMASK *in, const char *filename); VIPS_DEPRECATED INTMASK *im_rotate_imask45(INTMASK *in, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_rotate_dmask90(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_rotate_dmask45(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_mattrn(DOUBLEMASK *in, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_matcat(DOUBLEMASK *top, DOUBLEMASK *bottom, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_matmul(DOUBLEMASK *in1, DOUBLEMASK *in2, const char *filename); VIPS_DEPRECATED DOUBLEMASK *im_lu_decomp(const DOUBLEMASK *mat, const char *filename); VIPS_DEPRECATED int im_lu_solve(const DOUBLEMASK *lu, double *vec); VIPS_DEPRECATED DOUBLEMASK *im_matinv(const DOUBLEMASK *mat, const char *filename); VIPS_DEPRECATED int im_matinv_inplace(DOUBLEMASK *mat); VIPS_DEPRECATED DOUBLEMASK *im_local_dmask(struct _VipsImage *out, DOUBLEMASK *mask); VIPS_DEPRECATED INTMASK *im_local_imask(struct _VipsImage *out, INTMASK *mask); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*IM_MASK_H*/ libvips-8.18.2/libvips/include/vips/memory.h000066400000000000000000000063761516303661500210410ustar00rootroot00000000000000/* memory utilities * * J.Cupitt, 8/4/93 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_MEMORY_H #define VIPS_MEMORY_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_FREEF(F, S) \ G_STMT_START \ { \ if (S) { \ (void) (F((S))); \ (S) = 0; \ } \ } \ G_STMT_END #define VIPS_FREE(S) VIPS_FREEF(g_free, (S)); #define VIPS_SETSTR(S, V) \ G_STMT_START \ { \ const char *sst = (V); \ \ if ((S) != sst) { \ if (!(S) || !sst || strcmp((S), sst) != 0) { \ VIPS_FREE(S); \ if (sst) \ (S) = g_strdup(sst); \ } \ } \ } \ G_STMT_END #define VIPS_MALLOC(OBJ, S) \ (vips_malloc(VIPS_OBJECT(OBJ), S)) #define VIPS_NEW(OBJ, T) \ ((T *) VIPS_MALLOC(OBJ, sizeof(T))) #define VIPS_ARRAY(OBJ, N, T) \ ((T *) VIPS_MALLOC(OBJ, (N) * sizeof(T))) #ifndef __GI_SCANNER__ G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsImage, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsObject, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsRegion, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsConnection, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsSource, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsSourceCustom, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsGInputStream, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsSourceGInputStream, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsTarget, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsTargetCustom, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsSbuf, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsInterpolate, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsOperation, g_object_unref) // FIXME ... need more of these G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsArrayDouble, VipsArrayDouble_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(VipsArrayImage, VipsArrayImage_unref) #endif /* !__GI_SCANNER__ */ VIPS_API void *vips_malloc(VipsObject *object, size_t size); VIPS_API char *vips_strdup(VipsObject *object, const char *str); VIPS_API void vips_tracked_free(void *s); VIPS_API void vips_tracked_aligned_free(void *s); VIPS_API void *vips_tracked_malloc(size_t size); VIPS_API void *vips_tracked_aligned_alloc(size_t size, size_t align); VIPS_API size_t vips_tracked_get_mem(void); VIPS_API size_t vips_tracked_get_mem_highwater(void); VIPS_API int vips_tracked_get_allocs(void); VIPS_API int vips_tracked_open(const char *pathname, int flags, int mode); VIPS_API int vips_tracked_close(int fd); VIPS_API int vips_tracked_get_files(void); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_MEMORY_H*/ libvips-8.18.2/libvips/include/vips/meson.build000066400000000000000000000072571516303661500215210ustar00rootroot00000000000000# Headers that we install but neither introspect nor document. public_other_headers = files( 'debug.h', 'format.h', 'private.h', 'transform.h', ) public_deprecated_headers = files( 'almostdeprecated.h', 'deprecated.h', 'dispatch.h', 'intl.h', 'mask.h', 'video.h', 'vips7compat.h', ) if get_option('deprecated') public_other_headers += public_deprecated_headers endif public_headers = files( 'arithmetic.h', 'basic.h', 'buf.h', 'colour.h', 'connection.h', 'conversion.h', 'convolution.h', 'create.h', 'dbuf.h', 'draw.h', 'error.h', 'foreign.h', 'freqfilt.h', 'gate.h', 'generate.h', 'header.h', 'histogram.h', 'image.h', 'interpolate.h', 'memory.h', 'morphology.h', 'mosaicing.h', 'object.h', 'operation.h', 'rect.h', 'region.h', 'resample.h', 'sbuf.h', 'semaphore.h', 'thread.h', 'threadpool.h', 'type.h', 'util.h', 'vector.h', 'vips.h', ) enum_headers = files( 'resample.h', 'memory.h', 'create.h', 'foreign.h', 'arithmetic.h', 'conversion.h', 'util.h', 'image.h', 'colour.h', 'operation.h', 'convolution.h', 'morphology.h', 'draw.h', 'basic.h', 'object.h', 'region.h' ) if get_option('deprecated') enum_headers += files( 'almostdeprecated.h', ) endif enumtypes = gnome.mkenums( 'enumtypes', sources: enum_headers, h_template: 'enumtypes.h.in', c_template: 'enumtypes.c.in', install_header: true, install_dir: get_option('prefix') / get_option('includedir') / 'vips' ) vips_verbose_config = [] foreach _, section : build_summary foreach key, arr : section if key.contains('docs') or \ key.contains('cpp-docs') or \ key.contains('introspection') or \ key.contains('examples') continue endif vips_verbose_config += '@0@: @1@'.format(key, arr[0]) endforeach endforeach foreach _, section : build_features foreach key, arr : section dep_name = arr[0] found = arr[1].found() if found and arr[1].type_name() != 'internal' dep_name = arr[1].name() endif dynamic_module = arr.length() > 2 ? ' (dynamic module: @0@)'.format(arr[2]) : '' vips_verbose_config += '@0@ with @1@: @2@@3@'.format(key, dep_name, found, dynamic_module) endforeach endforeach version_data = configuration_data() version_data.set('VIPS_VERSION', meson.project_version()) version_data.set('VIPS_VERSION_STRING', meson.project_version()) version_data.set('VIPS_MAJOR_VERSION', version_major) version_data.set('VIPS_MINOR_VERSION', version_minor) version_data.set('VIPS_MICRO_VERSION', version_patch) version_data.set('LIBRARY_CURRENT', library_current) version_data.set('LIBRARY_REVISION', library_revision) version_data.set('LIBRARY_AGE', library_age) version_data.set('VIPS_CONFIG', '\\n'.join(vips_verbose_config)) version_data.set10('VIPS_ENABLE_DEPRECATED', get_option('deprecated')) version_header = configure_file( input: 'version.h.in', output: 'version.h', configuration: version_data, install: true, install_dir: get_option('prefix') / get_option('includedir') / 'vips' ) libvips_sources += public_headers libvips_sources += enumtypes libvips_sources += version_header install_headers( public_other_headers, public_headers, subdir: 'vips' ) libvips_includedir = include_directories('..') libvips_headers_dep = declare_dependency( sources: [ public_headers, enumtypes[1], version_header, ], include_directories: libvips_includedir ) libvips_deps += libvips_headers_dep libvips-8.18.2/libvips/include/vips/morphology.h000066400000000000000000000035261516303661500217220ustar00rootroot00000000000000/* morphology.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_MORPHOLOGY_H #define VIPS_MORPHOLOGY_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum { VIPS_OPERATION_MORPHOLOGY_ERODE, VIPS_OPERATION_MORPHOLOGY_DILATE, VIPS_OPERATION_MORPHOLOGY_LAST /*< skip >*/ } VipsOperationMorphology; VIPS_API int vips_morph(VipsImage *in, VipsImage **out, VipsImage *mask, VipsOperationMorphology morph, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rank(VipsImage *in, VipsImage **out, int width, int height, int index, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_median(VipsImage *in, VipsImage **out, int size, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_countlines(VipsImage *in, double *nolines, VipsDirection direction, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_labelregions(VipsImage *in, VipsImage **mask, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_fill_nearest(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_MORPHOLOGY_H*/ libvips-8.18.2/libvips/include/vips/mosaicing.h000066400000000000000000000042241516303661500214700ustar00rootroot00000000000000/* mosaicing.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_MOSAICING_H #define VIPS_MOSAICING_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_API int vips_merge(VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int dx, int dy, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mosaic(VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int xref, int yref, int xsec, int ysec, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mosaic1(VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_match(VipsImage *ref, VipsImage *sec, VipsImage **out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_globalbalance(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_remosaic(VipsImage *in, VipsImage **out, const char *old_str, const char *new_str, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixinvert(VipsImage *m, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_matrixmultiply(VipsImage *left, VipsImage *right, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_MOSAICING_H*/ libvips-8.18.2/libvips/include/vips/object.h000066400000000000000000000514561516303661500207760ustar00rootroot00000000000000/* abstract base class for all vips objects */ /* Copyright (C) 1991-2003 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_OBJECT_H #define VIPS_OBJECT_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Handy! */ #ifdef VIPS_DEBUG #define VIPS_UNREF(X) \ G_STMT_START \ { \ if (X) { \ g_assert(G_OBJECT(X)->ref_count > 0); \ g_object_unref(X); \ (X) = 0; \ } \ } \ G_STMT_END #else /*!VIPS_DEBUG*/ #define VIPS_UNREF(X) VIPS_FREEF(g_object_unref, (X)) #endif /*VIPS_DEBUG*/ typedef struct _VipsObject VipsObject; typedef struct _VipsObjectClass VipsObjectClass; /* Track extra stuff for arguments to objects */ typedef enum /*< flags >*/ { VIPS_ARGUMENT_NONE = 0, VIPS_ARGUMENT_REQUIRED = 1, VIPS_ARGUMENT_CONSTRUCT = 2, VIPS_ARGUMENT_SET_ONCE = 4, VIPS_ARGUMENT_SET_ALWAYS = 8, VIPS_ARGUMENT_INPUT = 16, VIPS_ARGUMENT_OUTPUT = 32, VIPS_ARGUMENT_DEPRECATED = 64, VIPS_ARGUMENT_MODIFY = 128, VIPS_ARGUMENT_NON_HASHABLE = 256 } VipsArgumentFlags; /* Useful flag combinations. User-visible ones are: * * VIPS_ARGUMENT_REQUIRED_INPUT Eg. the "left" argument for an add operation * * VIPS_ARGUMENT_OPTIONAL_INPUT Eg. the "caption" for an object * * VIPS_ARGUMENT_REQUIRED_OUTPUT Eg. the "result" of an add operation * * VIPS_ARGUMENT_OPTIONAL_OUTPUT Eg. the x pos of the image minimum * * Other combinations are used internally, eg. supplying the cast-table for an * arithmetic operation */ #define VIPS_ARGUMENT_REQUIRED_INPUT \ (VIPS_ARGUMENT_INPUT | \ VIPS_ARGUMENT_REQUIRED | \ VIPS_ARGUMENT_CONSTRUCT) #define VIPS_ARGUMENT_OPTIONAL_INPUT \ (VIPS_ARGUMENT_INPUT | \ VIPS_ARGUMENT_CONSTRUCT) #define VIPS_ARGUMENT_REQUIRED_OUTPUT \ (VIPS_ARGUMENT_OUTPUT | \ VIPS_ARGUMENT_REQUIRED | \ VIPS_ARGUMENT_CONSTRUCT) #define VIPS_ARGUMENT_OPTIONAL_OUTPUT \ (VIPS_ARGUMENT_OUTPUT | \ VIPS_ARGUMENT_CONSTRUCT) #define VIPS_ARG_IMAGE(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_object((NAME), (LONG), (DESC), \ VIPS_TYPE_IMAGE, \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_OBJECT(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, TYPE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_object((NAME), (LONG), (DESC), \ TYPE, \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_INTERPOLATE(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET) \ VIPS_ARG_OBJECT(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, VIPS_TYPE_INTERPOLATE) #define VIPS_ARG_BOOL(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_boolean((NAME), (LONG), (DESC), \ (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_DOUBLE(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, MIN, MAX, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_double((NAME), (LONG), (DESC), \ (MIN), (MAX), (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_BOXED(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, TYPE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_boxed((NAME), (LONG), (DESC), \ (TYPE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_INT(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, MIN, MAX, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_int((NAME), (LONG), (DESC), \ (MIN), (MAX), (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_UINT64(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, MIN, MAX, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_uint64((NAME), (LONG), (DESC), \ (MIN), (MAX), (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_ENUM(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, TYPE, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_enum((NAME), (LONG), (DESC), \ (TYPE), (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_FLAGS(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, TYPE, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_flags((NAME), (LONG), (DESC), \ (TYPE), (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_STRING(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET, VALUE) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_string((NAME), (LONG), (DESC), \ (VALUE), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } #define VIPS_ARG_POINTER(CLASS, NAME, PRIORITY, LONG, DESC, FLAGS, OFFSET) \ { \ GParamSpec *pspec; \ \ pspec = g_param_spec_pointer((NAME), (LONG), (DESC), \ (GParamFlags) (G_PARAM_READWRITE)); \ g_object_class_install_property(G_OBJECT_CLASS(CLASS), \ vips_argument_get_id(), pspec); \ vips_object_class_install_argument(VIPS_OBJECT_CLASS(CLASS), \ pspec, (VipsArgumentFlags) (FLAGS), (PRIORITY), (OFFSET)); \ } /* Keep one of these for every argument. */ typedef struct _VipsArgument { GParamSpec *pspec; /* pspec for this argument */ /* More stuff, see below */ } VipsArgument; /* Keep one of these in the class struct for every argument. */ typedef struct _VipsArgumentClass { VipsArgument parent; /* The class of the object we are an arg for. */ VipsObjectClass *object_class; VipsArgumentFlags flags; int priority; /* Order args by this */ guint offset; /* G_STRUCT_OFFSET of member in object */ } VipsArgumentClass; /* Keep one of these in the object struct for every argument instance. */ typedef struct _VipsArgumentInstance { VipsArgument parent; /* The class we are part of. */ VipsArgumentClass *argument_class; /* The object we are attached to. */ VipsObject *object; /* Has been set. */ gboolean assigned; /* If this is an output argument, keep the id of our "close" handler * here. */ gulong close_id; /* We need to listen for "invalidate" on input images and send our own * "invalidate" out. If we go, we need to disconnect. */ gulong invalidate_id; } VipsArgumentInstance; /* Need to look up our VipsArgument structs from a pspec. Just hash the * pointer (ie. we assume pspecs are never shared, is this correct?) */ typedef GHashTable VipsArgumentTable; VIPS_API int vips_argument_get_id(void); #ifndef __GI_SCANNER__ void vips__object_set_member(VipsObject *object, GParamSpec *pspec, GObject **member, GObject *argument); #endif /* !__GI_SCANNER__ */ typedef void *(*VipsArgumentMapFn)(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b); VIPS_API void *vips_argument_map(VipsObject *object, VipsArgumentMapFn fn, void *a, void *b); VIPS_API int vips_object_get_args(VipsObject *object, const char ***names, int **flags, int *n_args); typedef void *(*VipsArgumentClassMapFn)(VipsObjectClass *object_class, GParamSpec *pspec, VipsArgumentClass *argument_class, void *a, void *b); VIPS_API void *vips_argument_class_map(VipsObjectClass *object_class, VipsArgumentClassMapFn fn, void *a, void *b); VIPS_API gboolean vips_argument_class_needsstring(VipsArgumentClass *argument_class); VIPS_API int vips_object_get_argument(VipsObject *object, const char *name, GParamSpec **pspec, VipsArgumentClass **argument_class, VipsArgumentInstance **argument_instance); VIPS_API gboolean vips_object_argument_isset(VipsObject *object, const char *name); VIPS_API VipsArgumentFlags vips_object_get_argument_flags(VipsObject *object, const char *name); VIPS_API int vips_object_get_argument_priority(VipsObject *object, const char *name); /* We have to loop over an objects args in several places, and we can't always * use vips_argument_map(), the preferred looper. Have the loop code as a * macro as well for these odd cases. */ #define VIPS_ARGUMENT_FOR_ALL(OBJECT, PSPEC, ARG_CLASS, ARG_INSTANCE) \ { \ VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(OBJECT); \ GSList *p; \ \ for (p = object_class->argument_table_traverse; p; p = p->next) { \ VipsArgumentClass *ARG_CLASS = \ (VipsArgumentClass *) p->data; \ VipsArgument *argument = (VipsArgument *) argument_class; \ GParamSpec *PSPEC = argument->pspec; \ VipsArgumentInstance *ARG_INSTANCE G_GNUC_UNUSED = \ vips__argument_get_instance(argument_class, \ VIPS_OBJECT(OBJECT)); #define VIPS_ARGUMENT_FOR_ALL_END \ } \ } /* And some macros to collect args from a va list. * * Use something like this: * * GParamSpec *pspec; * VipsArgumentClass *argument_class; * VipsArgumentInstance *argument_instance; * * if (vips_object_get_argument(VIPS_OBJECT(operation), name, * &pspec, &argument_class, &argument_instance)) * return -1; * * VIPS_ARGUMENT_COLLECT_SET(pspec, argument_class, ap); * * GValue value holds the value of an input argument, do * something with it * * VIPS_ARGUMENT_COLLECT_GET(pspec, argument_class, ap); * * void **arg points to where to write an output argument * * VIPS_ARGUMENT_COLLECT_END */ #define VIPS_ARGUMENT_COLLECT_SET(PSPEC, ARG_CLASS, AP) \ if ((ARG_CLASS->flags & VIPS_ARGUMENT_INPUT)) { \ GValue value = G_VALUE_INIT; \ gchar *error = NULL; \ \ /* Input args are given inline, eg. ("factor", 12.0) \ * and must be collected. \ */ \ G_VALUE_COLLECT_INIT(&value, \ G_PARAM_SPEC_VALUE_TYPE(PSPEC), AP, 0, &error); \ \ /* Don't bother with the error message. \ */ \ if (error) { \ VIPS_DEBUG_MSG("VIPS_OBJECT_COLLECT_SET: err\n"); \ g_free(error); \ } #define VIPS_ARGUMENT_COLLECT_GET(PSPEC, ARG_CLASS, AP) \ g_value_unset(&value); \ } \ else if ((ARG_CLASS->flags & VIPS_ARGUMENT_OUTPUT)) \ { \ void **arg G_GNUC_UNUSED; \ \ /* Output args are a pointer to where to send the \ * result. \ */ \ arg = va_arg(AP, void **); #define VIPS_ARGUMENT_COLLECT_END \ } #define VIPS_TYPE_OBJECT (vips_object_get_type()) #define VIPS_OBJECT(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), VIPS_TYPE_OBJECT, VipsObject)) #define VIPS_OBJECT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), VIPS_TYPE_OBJECT, VipsObjectClass)) #define VIPS_IS_OBJECT(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_OBJECT)) #define VIPS_IS_OBJECT_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_OBJECT)) #define VIPS_OBJECT_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), VIPS_TYPE_OBJECT, VipsObjectClass)) struct _VipsObject { GObject parent_instance; /* Set after ->build() has run successfully: construct is fully done * and checked. */ gboolean constructed; /* Set for static objects which are allocated at startup and never * freed. These objects are omitted from leak reports. */ gboolean static_object; /* Table of argument instances for this class and any derived classes. */ VipsArgumentTable *argument_table; /* Class properties (see below), duplicated in the instance so we can * get at them easily via the property system. */ char *nickname; char *description; /* The pre/post/close callbacks are all fire-once. */ gboolean preclose; gboolean close; gboolean postclose; /* Total memory allocated relative to this object, handy for * profiling. */ size_t local_memory; }; struct _VipsObjectClass { GObjectClass parent_class; /* Build the object ... all argument properties have been set, * now build the thing. */ int (*build)(VipsObject *object); /* Just after build ... the object is fully ready for work. */ int (*postbuild)(VipsObject *object, void *data); /* Try to print something about the class, handy for help displays. * Keep to one line. */ void (*summary_class)(struct _VipsObjectClass *cls, VipsBuf *buf); /* Try to print a one-line summary for the object, the user can see * this output via things like "header fred.tif", --vips-cache-trace, * etc. */ void (*summary)(VipsObject *object, VipsBuf *buf); /* Try to print everything about the object, handy for debugging. */ void (*dump)(VipsObject *object, VipsBuf *buf); /* Sanity-check the object. Print messages and stuff. * Handy for debugging. */ void (*sanity)(VipsObject *object, VipsBuf *buf); /* Rewind. Save and restore any stuff that needs to survive a * dispose(). */ void (*rewind)(VipsObject *object); /* Just before close, everything is still alive. */ void (*preclose)(VipsObject *object); /* Close, time to free stuff. */ void (*close)(VipsObject *object); /* Post-close, everything is dead, except the VipsObject pointer. * Useful for eg. deleting the file associated with a temp image. */ void (*postclose)(VipsObject *object); /* The CLI interface. Implement these four to get CLI input and output * for your object. */ /* Given a command-line arg (eg. a filename), make an instance of the * object. Just do the g_object_new(), don't call _build(). * * Don't call this directly, see vips_object_new_from_string(). */ VipsObject *(*new_from_string)(const char *string); /* The inverse of ^^. Given an object, output what ->new_from_string() * would have been given to make that object. */ void (*to_string)(VipsObject *object, VipsBuf *buf); /* Does this output arg need an arg from the command line? Image * output, for example, needs a filename to write to. */ gboolean output_needs_arg; /* Write the object to the string. Return 0 for success, or -1 on * error, setting vips_error(). string is NULL if output_needs_arg() * was FALSE. */ int (*output_to_arg)(VipsObject *object, const char *string); /* Class nickname, eg. "VipsInterpolateBicubic" has "bicubic" as a * nickname. Not internationalised. */ const char *nickname; /* Class description. Used for help messages, so internationalised. */ const char *description; /* Hash from pspec to VipsArgumentClass. * * This records the VipsArgumentClass for every pspec used in * VipsObject and any subclass (ie. everywhere), so it's huge. Don't * loop over this hash! Fine for lookups though. */ VipsArgumentTable *argument_table; /* A sorted (by priority) list of the VipsArgumentClass for this class * and any superclasses. This is small and specific to this class. * * Use the stored GType to work out when to restart the list for a * subclass. */ GSList *argument_table_traverse; GType argument_table_traverse_gtype; /* This class is deprecated and therefore hidden from various UI bits. * * VipsOperation has a deprecated flag, use that in preference to this * if you can. */ gboolean deprecated; /* Reserved for future expansion. */ void (*_vips_reserved1)(void); void (*_vips_reserved2)(void); void (*_vips_reserved3)(void); void (*_vips_reserved4)(void); }; VIPS_API gboolean vips_value_is_null(GParamSpec *psoec, const GValue *value); VIPS_API void vips_object_set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec); VIPS_API void vips_object_get_property(GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec); VIPS_API void vips_object_preclose(VipsObject *object); VIPS_API int vips_object_build(VipsObject *object); VIPS_API void vips_object_summary_class(VipsObjectClass *klass, VipsBuf *buf); VIPS_API void vips_object_summary(VipsObject *object, VipsBuf *buf); VIPS_API void vips_object_dump(VipsObject *object, VipsBuf *buf); VIPS_API void vips_object_print_summary_class(VipsObjectClass *klass); VIPS_API void vips_object_print_summary(VipsObject *object); VIPS_API void vips_object_print_dump(VipsObject *object); VIPS_API void vips_object_print_name(VipsObject *object); VIPS_API gboolean vips_object_sanity(VipsObject *object); VIPS_API GType vips_object_get_type(void); VIPS_API void vips_object_class_install_argument(VipsObjectClass *cls, GParamSpec *pspec, VipsArgumentFlags flags, int priority, guint offset); VIPS_API int vips_object_set_argument_from_string(VipsObject *object, const char *name, const char *value); VIPS_API gboolean vips_object_argument_needsstring(VipsObject *object, const char *name); VIPS_API int vips_object_get_argument_to_string(VipsObject *object, const char *name, const char *arg); VIPS_API int vips_object_set_required(VipsObject *object, const char *value); typedef void *(*VipsObjectSetArguments)(VipsObject *object, void *a, void *b); VIPS_API VipsObject *vips_object_new(GType type, VipsObjectSetArguments set, void *a, void *b); VIPS_API int vips_object_set_valist(VipsObject *object, va_list ap); VIPS_API int vips_object_set(VipsObject *object, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_object_set_from_string(VipsObject *object, const char *string); VIPS_API VipsObject *vips_object_new_from_string(VipsObjectClass *object_class, const char *p); VIPS_API void vips_object_to_string(VipsObject *object, VipsBuf *buf); VIPS_API void *vips_object_map(VipsSListMap2Fn fn, void *a, void *b); typedef void *(*VipsTypeMapFn)(GType type, void *a); typedef void *(*VipsTypeMap2Fn)(GType type, void *a, void *b); typedef void *(*VipsClassMapFn)(VipsObjectClass *cls, void *a); VIPS_API void *vips_type_map(GType base, VipsTypeMap2Fn fn, void *a, void *b); VIPS_API void *vips_type_map_all(GType base, VipsTypeMapFn fn, void *a); VIPS_API int vips_type_depth(GType type); VIPS_API GType vips_type_find(const char *basename, const char *nickname); VIPS_API const char *vips_nickname_find(GType type); VIPS_API void *vips_class_map_all(GType type, VipsClassMapFn fn, void *a); VIPS_API const VipsObjectClass *vips_class_find(const char *basename, const char *nickname); VIPS_API VipsObject **vips_object_local_array(VipsObject *parent, int n); VIPS_API void vips_object_local_cb(VipsObject *vobject, GObject *gobject); #define vips_object_local(V, G) \ (g_signal_connect(V, "close", G_CALLBACK(vips_object_local_cb), G)) VIPS_API void vips_object_set_static(VipsObject *object, gboolean static_object); VIPS_API void vips_object_print_all(void); VIPS_API void vips_object_sanity_all(void); VIPS_API void vips_object_rewind(VipsObject *object); VIPS_API void vips_object_unref_outputs(VipsObject *object); VIPS_API const char *vips_object_get_description(VipsObject *object); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_OBJECT_H*/ libvips-8.18.2/libvips/include/vips/operation.h000066400000000000000000000113121516303661500215130ustar00rootroot00000000000000/* base class for all vips operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_OPERATION_H #define VIPS_OPERATION_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum /*< flags >*/ { VIPS_OPERATION_NONE = 0, VIPS_OPERATION_SEQUENTIAL = 1, VIPS_OPERATION_SEQUENTIAL_UNBUFFERED VIPS_DEPRECATED_ENUMERATOR_FOR(VIPS_OPERATION_SEQUENTIAL) = 2, VIPS_OPERATION_NOCACHE = 4, VIPS_OPERATION_DEPRECATED = 8, VIPS_OPERATION_UNTRUSTED = 16, VIPS_OPERATION_BLOCKED = 32, VIPS_OPERATION_REVALIDATE = 64 } VipsOperationFlags; #define VIPS_TYPE_OPERATION (vips_operation_get_type()) #define VIPS_OPERATION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_OPERATION, VipsOperation)) #define VIPS_OPERATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_OPERATION, VipsOperationClass)) #define VIPS_IS_OPERATION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_OPERATION)) #define VIPS_IS_OPERATION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_OPERATION)) #define VIPS_OPERATION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_OPERATION, VipsOperationClass)) typedef gboolean (*VipsOperationBuildFn)(VipsObject *object); struct _VipsOperation { VipsObject parent_instance; /* Keep the hash here. */ guint hash; gboolean found_hash; /* Pixels calculated ... handy for measuring over-calculation. */ int pixels; }; typedef struct _VipsOperationClass { VipsObjectClass parent_class; /* Print the usage message. */ void (*usage)(struct _VipsOperationClass *cls, VipsBuf *buf); /* Return a set of operation flags. */ VipsOperationFlags (*get_flags)(VipsOperation *operation); VipsOperationFlags flags; /* One of our input images has signalled "invalidate". The cache uses * VipsOperation::invalidate to drop dirty ops. */ void (*invalidate)(VipsOperation *operation); } VipsOperationClass; VIPS_API GType vips_operation_get_type(void); VIPS_API VipsOperationFlags vips_operation_get_flags(VipsOperation *operation); VIPS_API void vips_operation_class_print_usage(VipsOperationClass *operation_class); VIPS_API void vips_operation_invalidate(VipsOperation *operation); VIPS_API int vips_operation_call_valist(VipsOperation *operation, va_list ap); VIPS_API VipsOperation *vips_operation_new(const char *name); VIPS_API int vips_call_required_optional(VipsOperation **operation, va_list required, va_list optional); VIPS_API int vips_call(const char *operation_name, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_call_split(const char *operation_name, va_list optional, ...); VIPS_API int vips_call_split_option_string(const char *operation_name, const char *option_string, va_list optional, ...); VIPS_API void vips_call_options(GOptionGroup *group, VipsOperation *operation); VIPS_API int vips_call_argv(VipsOperation *operation, int argc, char **argv); VIPS_API void vips_cache_drop_all(void); VIPS_API int vips_cache_operation_buildp(VipsOperation **operation); VIPS_API VipsOperation *vips_cache_operation_build(VipsOperation *operation); VIPS_API void vips_cache_print(void); VIPS_API void vips_cache_set_max(int max); VIPS_API void vips_cache_set_max_mem(size_t max_mem); VIPS_API int vips_cache_get_max(void); VIPS_API int vips_cache_get_size(void); VIPS_API size_t vips_cache_get_max_mem(void); VIPS_API int vips_cache_get_max_files(void); VIPS_API void vips_cache_set_max_files(int max_files); VIPS_API void vips_cache_set_dump(gboolean dump); VIPS_API void vips_cache_set_trace(gboolean trace); /* Part of threadpool, really, but we want these in a header that gets scanned * for our typelib. */ VIPS_API void vips_concurrency_set(int concurrency); VIPS_API int vips_concurrency_get(void); VIPS_API void vips_operation_block_set(const char *name, gboolean state); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_OPERATION_H*/ libvips-8.18.2/libvips/include/vips/private.h000066400000000000000000000172031516303661500211720ustar00rootroot00000000000000/* Declarations which are public-facing, but private. See internal.h for * declarations which are only used internally by vips and which are not * externally visible. * * 6/7/09 * - from vips.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PRIVATE_H #define VIPS_PRIVATE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include #define VIPS_SPARE (8) /* sizeof() a VIPS header on disc. */ #define VIPS_SIZEOF_HEADER (64) /* What we track for each mmap window. Have a list of these on an openin * VipsImage. */ typedef struct { int ref_count; /* # of regions referencing us */ struct _VipsImage *im; /* VipsImage we are attached to */ int top; /* Area of image we have mapped, in pixels */ int height; VipsPel *data; /* First pixel of line 'top' */ void *baseaddr; /* Base of window */ size_t length; /* Size of window */ } VipsWindow; VIPS_API int vips_window_unref(VipsWindow *window); VIPS_API void vips_window_print(VipsWindow *window); /* Per-thread buffer state. Held in a GPrivate. */ typedef struct { GHashTable *hash; /* VipsImage -> VipsBufferCache* */ GThread *thread; /* Just for sanity checking */ } VipsBufferThread; /* Per-image buffer cache. This keeps a list of "done" VipsBuffer that this * worker has generated. We use this to reuse results within a thread. * * Hash to this from VipsBufferThread::hash. * We can't store the GSList directly in the hash table as GHashTable lacks an * update operation and we'd need to _remove() and _insert() on every list * operation. */ typedef struct _VipsBufferCache { GSList *buffers; /* GSList of "done" VipsBuffer* */ GThread *thread; /* Just for sanity checking */ struct _VipsImage *im; VipsBufferThread *buffer_thread; GSList *reserve; /* VipsBuffer kept in reserve */ int n_reserve; /* Number in reserve */ } VipsBufferCache; /* What we track for each pixel buffer. These can move between caches and * between threads, but not between images. * * Moving between threads is difficult, use region ownership stuff. */ typedef struct _VipsBuffer { int ref_count; /* # of regions referencing us */ struct _VipsImage *im; /* VipsImage we are attached to */ VipsRect area; /* Area this pixel buffer covers */ gboolean done; /* Calculated and in a cache */ VipsBufferCache *cache; /* The cache this buffer is published on */ VipsPel *buf; /* Private malloc() area */ size_t bsize; /* Size of private malloc() */ } VipsBuffer; VIPS_API void vips_buffer_dump_all(void); VIPS_API void vips_buffer_done(VipsBuffer *buffer); VIPS_API void vips_buffer_undone(VipsBuffer *buffer); VIPS_API void vips_buffer_unref(VipsBuffer *buffer); VIPS_API VipsBuffer *vips_buffer_new(struct _VipsImage *im, VipsRect *area); VIPS_API VipsBuffer *vips_buffer_ref(struct _VipsImage *im, VipsRect *area); VIPS_API VipsBuffer *vips_buffer_unref_ref(VipsBuffer *buffer, struct _VipsImage *im, VipsRect *area); VIPS_API void vips_buffer_print(VipsBuffer *buffer); void vips__render_shutdown(void); /* Sections of region.h that are private to VIPS. */ /* Region types. */ typedef enum _RegionType { VIPS_REGION_NONE, VIPS_REGION_BUFFER, /* A VipsBuffer */ VIPS_REGION_OTHER_REGION, /* Memory on another region */ VIPS_REGION_OTHER_IMAGE, /* Memory on another image */ VIPS_REGION_WINDOW /* A VipsWindow on fd */ } RegionType; /* Private to iofuncs: the size of the `tiles' requested by * vips_image_generate() when acting as a data sink. */ #define VIPS__TILE_WIDTH (128) #define VIPS__TILE_HEIGHT (128) /* The height of the strips for the other two request styles. */ #define VIPS__THINSTRIP_HEIGHT (1) #define VIPS__FATSTRIP_HEIGHT (16) /* Functions on regions. */ struct _VipsRegion; void vips__region_take_ownership(struct _VipsRegion *reg); void vips__region_check_ownership(struct _VipsRegion *reg); /* TODO(kleisauke): VIPS_API is required by vipsdisp. */ VIPS_API void vips__region_no_ownership(struct _VipsRegion *reg); typedef int (*VipsRegionFillFn)(struct _VipsRegion *, void *); VIPS_API int vips_region_fill(struct _VipsRegion *reg, const VipsRect *r, VipsRegionFillFn fn, void *a); int vips__image_wio_output(struct _VipsImage *image); int vips__image_pio_output(struct _VipsImage *image); /* VIPS_ARGUMENT_FOR_ALL() needs to have this visible. */ VIPS_API VipsArgumentInstance *vips__argument_get_instance( VipsArgumentClass *argument_class, VipsObject *object); VipsArgument *vips__argument_table_lookup(VipsArgumentTable *table, GParamSpec *pspec); /* im_demand_hint_array() needs to have this visible. */ #if VIPS_ENABLE_DEPRECATED VIPS_API #endif void vips__demand_hint_array(struct _VipsImage *image, int hint, struct _VipsImage **in); /* im_cp_desc_array() needs to have this visible. */ #if VIPS_ENABLE_DEPRECATED VIPS_API #endif int vips__image_copy_fields_array(struct _VipsImage *out, struct _VipsImage *in[]); void vips__region_count_pixels(struct _VipsRegion *region, const char *nickname); VIPS_API void vips_region_dump_all(void); VIPS_API int vips_region_prepare_many(struct _VipsRegion **reg, const VipsRect *r); /* Handy for debugging. */ int vips__view_image(struct _VipsImage *image); /* Pre 8.7 libvipses used this for allocating argument ids. */ VIPS_API int _vips__argument_id; // autoptr needs typed functions for autofree ... this needs to be in the // public API since downstream projects can use our auto defs VIPS_API void VipsArrayDouble_unref(VipsArrayDouble *array); VIPS_API void VipsArrayImage_unref(VipsArrayImage *array); extern gboolean vips__thread_profile; void vips__thread_gate_start(const char *gate_name); void vips__thread_gate_stop(const char *gate_name); void vips__thread_malloc_free(gint64 size); FILE *vips__file_open_read(const char *filename, const char *fallback_dir, gboolean text_mode); FILE *vips__file_open_write(const char *filename, gboolean text_mode); /* TODO(kleisauke): VIPS_API is required by vipsedit. */ VIPS_API int vips__write(int fd, const void *buf, size_t count); /* TODO(kleisauke): VIPS_API is required by test_connections. */ VIPS_API int vips__open(const char *filename, int flags, int mode); /* TODO(kleisauke): VIPS_API is required by vipsedit. */ VIPS_API char *vips__file_read(FILE *fp, const char *name, size_t *length_out); /* TODO(kleisauke): VIPS_API is required by the magick module. */ VIPS_API gint64 vips__get_bytes(const char *filename, unsigned char buf[], gint64 len); /* TODO(kleisauke): VIPS_API is required by vipsedit. */ VIPS_API gint64 vips__seek(int fd, gint64 pos, int whence); /* TODO(kleisauke): VIPS_API is required by libvips-cpp and vipsheader. */ VIPS_API void vips__filename_split8(const char *name, char *filename, char *option_string); /* TODO(kleisauke): VIPS_API is required by jpegsave_file_fuzzer. */ VIPS_API char *vips__temp_name(const char *format); /* Used by libvips tools. */ VIPS_API void vips__win32_terminate(int ret); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PRIVATE_H*/ libvips-8.18.2/libvips/include/vips/rect.h000066400000000000000000000040531516303661500204540ustar00rootroot00000000000000/* Simple rectangle algebra. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_RECT_H #define VIPS_RECT_H #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef struct _VipsRect { /*< public >*/ int left; int top; int width; int height; } VipsRect; #define VIPS_RECT_RIGHT(R) ((R)->left + (R)->width) #define VIPS_RECT_BOTTOM(R) ((R)->top + (R)->height) #define VIPS_RECT_HCENTRE(R) ((R)->left + (R)->width / 2) #define VIPS_RECT_VCENTRE(R) ((R)->top + (R)->height / 2) VIPS_API gboolean vips_rect_isempty(const VipsRect *r); VIPS_API gboolean vips_rect_includespoint(const VipsRect *r, int x, int y); VIPS_API gboolean vips_rect_includesrect(const VipsRect *r1, const VipsRect *r2); VIPS_API gboolean vips_rect_equalsrect(const VipsRect *r1, const VipsRect *r2); VIPS_API gboolean vips_rect_overlapsrect(const VipsRect *r1, const VipsRect *r2); VIPS_API void vips_rect_marginadjust(VipsRect *r, int n); VIPS_API void vips_rect_intersectrect(const VipsRect *r1, const VipsRect *r2, VipsRect *out); VIPS_API void vips_rect_unionrect(const VipsRect *r1, const VipsRect *r2, VipsRect *out); VIPS_API VipsRect *vips_rect_dup(const VipsRect *r); VIPS_API void vips_rect_normalise(VipsRect *r); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_RECT_H*/ libvips-8.18.2/libvips/include/vips/region.h000066400000000000000000000151261516303661500210050ustar00rootroot00000000000000/* Definitions for partial image regions. * * J.Cupitt, 8/4/93 * * 2/3/11 * - move to GObject */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_REGION_H #define VIPS_REGION_H #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_REGION (vips_region_get_type()) #define VIPS_REGION(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_REGION, VipsRegion)) #define VIPS_REGION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_REGION, VipsRegionClass)) #define VIPS_IS_REGION(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_REGION)) #define VIPS_IS_REGION_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_REGION)) #define VIPS_REGION_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_REGION, VipsRegionClass)) /** * VipsRegionShrink: * @VIPS_REGION_SHRINK_MEAN: use the average * @VIPS_REGION_SHRINK_MEDIAN: use the median * @VIPS_REGION_SHRINK_MODE: use the mode * @VIPS_REGION_SHRINK_MAX: use the maximum * @VIPS_REGION_SHRINK_MIN: use the minimum * @VIPS_REGION_SHRINK_NEAREST: use the top-left pixel * * How to calculate the output pixels when shrinking a 2x2 region. * * Images with alpha (see [method@Image.hasalpha]) always shrink with * [enum@Vips.RegionShrink.MEAN] and pixels scaled by alpha to avoid fringing. * * Set the image interpretation to [enum@Vips.Interpretation.MULTIBAND] to * treat all bands equally. */ typedef enum { VIPS_REGION_SHRINK_MEAN, VIPS_REGION_SHRINK_MEDIAN, VIPS_REGION_SHRINK_MODE, VIPS_REGION_SHRINK_MAX, VIPS_REGION_SHRINK_MIN, VIPS_REGION_SHRINK_NEAREST, VIPS_REGION_SHRINK_LAST /*< skip >*/ } VipsRegionShrink; /* Sub-area of image. * * Matching typedef in basic.h. */ struct _VipsRegion { VipsObject parent_object; /* Users may read these two fields. */ /*< public >*/ VipsImage *im; /* Link back to parent image */ VipsRect valid; /* Area of parent we can see */ /* The rest of VipsRegion is private. */ /*< private >*/ RegionType type; /* What kind of attachment */ VipsPel *data; /* Off here to get data */ int bpl; /* Bytes-per-line for data */ void *seq; /* Sequence we are using to fill region */ /* The thread that made this region. Used to assert() test that * regions are not being shared between threads. */ GThread *thread; /* Ref to the window we use for this region, if any. */ VipsWindow *window; /* Ref to the buffer we use for this region, if any. */ VipsBuffer *buffer; /* The image this region is on has changed and caches need to be * dropped. */ gboolean invalid; }; typedef struct _VipsRegionClass { VipsObjectClass parent_class; } VipsRegionClass; VIPS_API GType vips_region_get_type(void); VIPS_API VipsRegion *vips_region_new(VipsImage *image); VIPS_API int vips_region_buffer(VipsRegion *reg, const VipsRect *r); VIPS_API int vips_region_image(VipsRegion *reg, const VipsRect *r); VIPS_API int vips_region_region(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y); VIPS_API int vips_region_equalsregion(VipsRegion *reg1, VipsRegion *reg2); VIPS_API int vips_region_position(VipsRegion *reg, int x, int y); VIPS_API void vips_region_paint(VipsRegion *reg, const VipsRect *r, int value); VIPS_API void vips_region_paint_pel(VipsRegion *reg, const VipsRect *r, const VipsPel *ink); VIPS_API void vips_region_black(VipsRegion *reg); VIPS_API void vips_region_copy(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y); VIPS_API int vips_region_shrink_method(VipsRegion *from, VipsRegion *to, const VipsRect *target, VipsRegionShrink method); VIPS_API int vips_region_shrink(VipsRegion *from, VipsRegion *to, const VipsRect *target); VIPS_API int vips_region_prepare(VipsRegion *reg, const VipsRect *r); VIPS_API int vips_region_prepare_to(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y); VIPS_API VipsPel *vips_region_fetch(VipsRegion *region, int left, int top, int width, int height, size_t *len); VIPS_API int vips_region_width(VipsRegion *region); VIPS_API int vips_region_height(VipsRegion *region); VIPS_API void vips_region_invalidate(VipsRegion *reg); /* Use this to count pixels passing through key points. Handy for spotting bad * overcomputation. */ #ifdef DEBUG_LEAK #define VIPS_COUNT_PIXELS(R, N) vips__region_count_pixels(R, N) #else /*!DEBUG_LEAK*/ #define VIPS_COUNT_PIXELS(R, N) #endif /*DEBUG_LEAK*/ #define VIPS_REGION_LSKIP(R) \ ((size_t) ((R)->bpl)) #define VIPS_REGION_N_ELEMENTS(R) \ ((size_t) ((R)->valid.width * (R)->im->Bands)) #define VIPS_REGION_SIZEOF_ELEMENT(R) \ (VIPS_IMAGE_SIZEOF_ELEMENT((R)->im)) #define VIPS_REGION_SIZEOF_PEL(R) \ (VIPS_IMAGE_SIZEOF_PEL((R)->im)) #define VIPS_REGION_SIZEOF_LINE(R) \ ((size_t) ((R)->valid.width * VIPS_REGION_SIZEOF_PEL(R))) /* If DEBUG is defined, add bounds checking. */ #ifdef DEBUG #define VIPS_REGION_ADDR(R, X, Y) \ ((vips_rect_includespoint(&(R)->valid, (X), (Y))) \ ? ((R)->data + ((Y) - (R)->valid.top) * VIPS_REGION_LSKIP(R) + \ ((X) - (R)->valid.left) * VIPS_REGION_SIZEOF_PEL(R)) \ : (fprintf(stderr, \ "VIPS_REGION_ADDR: point out of bounds, " \ "file \"%s\", line %d\n" \ "(point x=%d, y=%d\n" \ " should have been within VipsRect left=%d, top=%d, " \ "width=%d, height=%d)\n", \ __FILE__, __LINE__, \ (X), (Y), \ (R)->valid.left, \ (R)->valid.top, \ (R)->valid.width, \ (R)->valid.height), \ abort(), (VipsPel *) NULL)) #else /*DEBUG*/ #define VIPS_REGION_ADDR(R, X, Y) \ ((R)->data + \ ((Y) - (R)->valid.top) * VIPS_REGION_LSKIP(R) + \ ((X) - (R)->valid.left) * VIPS_REGION_SIZEOF_PEL(R)) #endif /*DEBUG*/ #define VIPS_REGION_ADDR_TOPLEFT(R) ((R)->data) #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_REGION_H*/ libvips-8.18.2/libvips/include/vips/resample.h000066400000000000000000000061211516303661500213250ustar00rootroot00000000000000/* resample.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_RESAMPLE_H #define VIPS_RESAMPLE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ typedef enum { VIPS_KERNEL_NEAREST, VIPS_KERNEL_LINEAR, VIPS_KERNEL_CUBIC, VIPS_KERNEL_MITCHELL, VIPS_KERNEL_LANCZOS2, VIPS_KERNEL_LANCZOS3, VIPS_KERNEL_MKS2013, VIPS_KERNEL_MKS2021, VIPS_KERNEL_LAST /*< skip >*/ } VipsKernel; typedef enum { VIPS_SIZE_BOTH, VIPS_SIZE_UP, VIPS_SIZE_DOWN, VIPS_SIZE_FORCE, VIPS_SIZE_LAST /*< skip >*/ } VipsSize; VIPS_API int vips_shrink(VipsImage *in, VipsImage **out, double hshrink, double vshrink, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_shrinkh(VipsImage *in, VipsImage **out, int hshrink, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_shrinkv(VipsImage *in, VipsImage **out, int vshrink, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_reduce(VipsImage *in, VipsImage **out, double hshrink, double vshrink, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_reduceh(VipsImage *in, VipsImage **out, double hshrink, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_reducev(VipsImage *in, VipsImage **out, double vshrink, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_thumbnail(const char *filename, VipsImage **out, int width, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_thumbnail_buffer(void *buf, size_t len, VipsImage **out, int width, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_thumbnail_image(VipsImage *in, VipsImage **out, int width, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_thumbnail_source(VipsSource *source, VipsImage **out, int width, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_similarity(VipsImage *in, VipsImage **out, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_rotate(VipsImage *in, VipsImage **out, double angle, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_affine(VipsImage *in, VipsImage **out, double a, double b, double c, double d, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_resize(VipsImage *in, VipsImage **out, double scale, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_mapim(VipsImage *in, VipsImage **out, VipsImage *index, ...) G_GNUC_NULL_TERMINATED; VIPS_API int vips_quadratic(VipsImage *in, VipsImage **out, VipsImage *coeff, ...) G_GNUC_NULL_TERMINATED; #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_RESAMPLE_H*/ libvips-8.18.2/libvips/include/vips/sbuf.h000066400000000000000000000070361516303661500204620ustar00rootroot00000000000000/* Buffered inputput from a VipsSource * * J.Cupitt, 18/11/19 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_SBUF_H #define VIPS_SBUF_H #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_SBUF (vips_sbuf_get_type()) #define VIPS_SBUF(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_SBUF, VipsSbuf)) #define VIPS_SBUF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_SBUF, VipsSbufClass)) #define VIPS_IS_SBUF(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_SBUF)) #define VIPS_IS_SBUF_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_SBUF)) #define VIPS_SBUF_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_SBUF, VipsSbufClass)) #define VIPS_SBUF_BUFFER_SIZE (4096) /* Layer over source: read with an input buffer. * * Libraries like libjpeg do their own input buffering and need raw IO, but * others, like radiance, need to parse the input into lines. A buffered read * class is very convenient. */ typedef struct _VipsSbuf { VipsObject parent_object; /*< private >*/ /* The VipsSource we wrap. */ VipsSource *source; /* The +1 means there's always a \0 byte at the end. * * Unsigned char, since we don't want >127 to be -ve. * * chars_in_buffer is how many chars we have in input_buffer, * read_point is the current read position in that buffer. */ unsigned char input_buffer[VIPS_SBUF_BUFFER_SIZE + 1]; int chars_in_buffer; int read_point; /* Build lines of text here. */ unsigned char line[VIPS_SBUF_BUFFER_SIZE + 1]; } VipsSbuf; typedef struct _VipsSbufClass { VipsObjectClass parent_class; } VipsSbufClass; VIPS_API GType vips_sbuf_get_type(void); VIPS_API VipsSbuf *vips_sbuf_new_from_source(VipsSource *source); VIPS_API void vips_sbuf_unbuffer(VipsSbuf *sbuf); VIPS_API int vips_sbuf_getc(VipsSbuf *sbuf); #define VIPS_SBUF_GETC(S) ( \ (S)->read_point < (S)->chars_in_buffer \ ? (S)->input_buffer[(S)->read_point++] \ : vips_sbuf_getc(S)) VIPS_API void vips_sbuf_ungetc(VipsSbuf *sbuf); #define VIPS_SBUF_UNGETC(S) \ { \ if ((S)->read_point > 0) \ (S)->read_point -= 1; \ } VIPS_API int vips_sbuf_require(VipsSbuf *sbuf, int require); #define VIPS_SBUF_REQUIRE(S, R) ( \ (S)->read_point + (R) <= (S)->chars_in_buffer \ ? 0 \ : vips_sbuf_require((S), (R))) #define VIPS_SBUF_PEEK(S) ((S)->input_buffer + (S)->read_point) #define VIPS_SBUF_FETCH(S) ((S)->input_buffer[(S)->read_point++]) VIPS_API const char *vips_sbuf_get_line(VipsSbuf *sbuf); VIPS_API char *vips_sbuf_get_line_copy(VipsSbuf *sbuf); VIPS_API const char *vips_sbuf_get_non_whitespace(VipsSbuf *sbuf); VIPS_API int vips_sbuf_skip_whitespace(VipsSbuf *sbuf); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_SBUF_H*/ libvips-8.18.2/libvips/include/vips/semaphore.h000066400000000000000000000034031516303661500215000ustar00rootroot00000000000000/* Definitions for thread support. * * JC, 9/5/94 * 30/7/99 RP, JC * - reworked for posix/solaris threads * 28/9/99 JC * - restructured, made part of public API */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_SEMAPHORE_H #define VIPS_SEMAPHORE_H #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Implement our own semaphores. */ typedef struct { /* All fields are private. */ /*< private >*/ char *name; int v; GMutex mutex; GCond cond; } VipsSemaphore; VIPS_API int vips_semaphore_up(VipsSemaphore *s); VIPS_API int vips_semaphore_upn(VipsSemaphore *s, int n); VIPS_API int vips_semaphore_down(VipsSemaphore *s); VIPS_API int vips_semaphore_downn(VipsSemaphore *s, int n); VIPS_API int vips_semaphore_down_timeout(VipsSemaphore *s, gint64 timeout); VIPS_API void vips_semaphore_destroy(VipsSemaphore *s); VIPS_API void vips_semaphore_init(VipsSemaphore *s, int v, char *name); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_SEMAPHORE_H*/ libvips-8.18.2/libvips/include/vips/thread.h000066400000000000000000000025341516303661500207700ustar00rootroot00000000000000/* Private include file ... if we've been configured without gthread, we need * to point the g_thread_*() and g_mutex_*() functions at our own stubs. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_THREAD_H #define VIPS_THREAD_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_API GThread *vips_g_thread_new(const char *domain, GThreadFunc func, gpointer data); VIPS_API gboolean vips_thread_isvips(void); VIPS_API int vips_thread_execute(const char *domain, GFunc func, gpointer data); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_THREAD_H*/ libvips-8.18.2/libvips/include/vips/threadpool.h000066400000000000000000000076441516303661500216710ustar00rootroot00000000000000/* Thread eval for VIPS. * * 29/9/99 JC * - from thread.h * 17/3/10 * - from threadgroup * - rework with a simpler distributed work allocation model * 02/02/20 kleisauke * - reuse threads by using GLib's threadpool */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_THREADPOOL_H #define VIPS_THREADPOOL_H #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_THREAD_STATE (vips_thread_state_get_type()) #define VIPS_THREAD_STATE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_THREAD_STATE, VipsThreadState)) #define VIPS_THREAD_STATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_THREAD_STATE, VipsThreadStateClass)) #define VIPS_IS_THREAD_STATE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_THREAD_STATE)) #define VIPS_IS_THREAD_STATE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_THREAD_STATE)) #define VIPS_THREAD_STATE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_THREAD_STATE, VipsThreadStateClass)) typedef struct _VipsThreadState { VipsObject parent_object; /*< public >*/ /* Image we run on. */ VipsImage *im; /* This region is created and destroyed by the threadpool for the * use of the worker. */ VipsRegion *reg; /* Neither used nor set, do what you like with them. */ VipsRect pos; int x, y; /* Set in work to get the allocate to signal stop. */ gboolean stop; /* The client data passed to the enclosing vips_threadpool_run(). */ void *a; /* Set in allocate to stall this thread for a moment. Handy for * debugging race conditions. */ gboolean stall; } VipsThreadState; typedef struct _VipsThreadStateClass { VipsObjectClass parent_class; /*< public >*/ } VipsThreadStateClass; VIPS_API void *vips_thread_state_set(VipsObject *object, void *a, void *b); VIPS_API GType vips_thread_state_get_type(void); VIPS_API VipsThreadState *vips_thread_state_new(VipsImage *im, void *a); /* Constructor for per-thread state. */ typedef VipsThreadState *(*VipsThreadStartFn)(VipsImage *im, void *a); /* A work allocate function. This is run single-threaded by a worker to * set up a new work unit. * Return non-zero for errors. Set *stop for "no more work to do" */ typedef int (*VipsThreadpoolAllocateFn)(VipsThreadState *state, void *a, gboolean *stop); /* A work function. This does a unit of work (eg. processing a tile or * whatever). Return non-zero for errors. */ typedef int (*VipsThreadpoolWorkFn)(VipsThreadState *state, void *a); /* A progress function. This is run by the main thread once for every * allocation. Return an error to kill computation early. */ typedef int (*VipsThreadpoolProgressFn)(void *a); VIPS_API int vips_threadpool_run(VipsImage *im, VipsThreadStartFn start, VipsThreadpoolAllocateFn allocate, VipsThreadpoolWorkFn work, VipsThreadpoolProgressFn progress, void *a); VIPS_API void vips_get_tile_size(VipsImage *im, int *tile_width, int *tile_height, int *n_lines); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_THREADPOOL_H*/ libvips-8.18.2/libvips/include/vips/transform.h000066400000000000000000000047611516303661500215400ustar00rootroot00000000000000/* Affine transforms. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_TRANSFORM_H #define VIPS_TRANSFORM_H #include #include #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Params for an affine transformation. */ typedef struct { /* Area of input we can use. This can be smaller than the real input * image: we expand the input to add extra pixels for interpolation. */ VipsRect iarea; /* The area of the output we've been asked to generate. left/top can * be negative. */ VipsRect oarea; /* The transform. */ double a, b, c, d; double idx, idy; double odx, ody; double ia, ib, ic, id; /* Inverse of matrix abcd */ } VipsTransformation; void vips__transform_init(VipsTransformation *trn); int vips__transform_calc_inverse(VipsTransformation *trn); int vips__transform_isidentity(const VipsTransformation *trn); int vips__transform_add(const VipsTransformation *in1, const VipsTransformation *in2, VipsTransformation *out); void vips__transform_print(const VipsTransformation *trn); void vips__transform_forward_point(const VipsTransformation *trn, const double x, const double y, double *ox, double *oy); void vips__transform_invert_point(const VipsTransformation *trn, const double x, const double y, double *ox, double *oy); void vips__transform_forward_rect(const VipsTransformation *trn, const VipsRect *in, VipsRect *out); void vips__transform_invert_rect(const VipsTransformation *trn, const VipsRect *in, VipsRect *out); void vips__transform_set_area(VipsTransformation *); int vips__affine(VipsImage *in, VipsImage *out, VipsTransformation *trn); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_TRANSFORM_H*/ libvips-8.18.2/libvips/include/vips/type.h000066400000000000000000000171701516303661500205040ustar00rootroot00000000000000/* the GTypes we define * * 27/10/11 * - from header.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_TYPE_H #define VIPS_TYPE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #ifndef __GI_SCANNER__ /* A very simple boxed type for testing. Just holds an int. */ typedef struct _VipsThing { int i; } VipsThing; /** * VIPS_TYPE_THING: * * The [alias@GObject.Type] for a #VipsThing. */ #define VIPS_TYPE_THING (vips_thing_get_type()) VIPS_API GType vips_thing_get_type(void); VIPS_API VipsThing *vips_thing_new(int i); #endif /* !__GI_SCANNER__ */ /* A ref-counted area of memory. Can hold arrays of things as well. */ typedef struct _VipsArea { void *data; size_t length; /* 0 if not known */ /* If this area represents an array, the number of elements in the * array. Equal to length / sizeof(element). */ int n; /*< private >*/ /* Reference count and lock. * * We could use an atomic int, but this is not a high-traffic data * structure, so a simple GMutex is OK. */ int count; GMutex lock; /* Things like ICC profiles need their own free functions. * * Set client to anything you like -- VipsArea doesn't use this. */ VipsCallbackFn free_fn; void *client; /* If we are holding an array (for example, an array of double), the * GType of the elements and their size. 0 for not known. * * n is always length / sizeof_type, we keep it as a member for * convenience. */ GType type; size_t sizeof_type; } VipsArea; VIPS_API VipsArea *vips_area_copy(VipsArea *area); VIPS_API int vips_area_free_cb(void *mem, VipsArea *area); VIPS_API void vips_area_unref(VipsArea *area); VIPS_API VipsArea *vips_area_new(VipsCallbackFn free_fn, void *data); VIPS_API VipsArea *vips_area_new_array(GType type, size_t sizeof_type, int n); VIPS_API VipsArea *vips_area_new_array_object(int n); VIPS_API void *vips_area_get_data(VipsArea *area, size_t *length, int *n, GType *type, size_t *sizeof_type); #ifdef VIPS_DEBUG #define VIPS_ARRAY_ADDR(X, I) \ (((I) >= 0 && (I) < VIPS_AREA(X)->n) \ ? (void *) ((VipsPel *) VIPS_AREA(X)->data + \ VIPS_AREA(X)->sizeof_type * (I)) \ : (fprintf(stderr, \ "VIPS_ARRAY_ADDR: index out of bounds, " \ "file \"%s\", line %d\n" \ "(index %d should have been within [0,%d])\n", \ __FILE__, __LINE__, \ (I), VIPS_AREA(X)->n), \ NULL)) #else /*!VIPS_DEBUG*/ #define VIPS_ARRAY_ADDR(X, I) \ ((void *) ((VipsPel *) VIPS_AREA(X)->data + \ VIPS_AREA(X)->sizeof_type * (I))) #endif /*VIPS_DEBUG*/ /** * VIPS_TYPE_AREA: * * The [alias@GObject.Type] for a [struct@Area]. */ #define VIPS_TYPE_AREA (vips_area_get_type()) #define VIPS_AREA(X) ((VipsArea *) (X)) VIPS_API GType vips_area_get_type(void); /** * VIPS_TYPE_SAVE_STRING: * * The [alias@GObject.Type] for a [struct@SaveString]. */ #define VIPS_TYPE_SAVE_STRING (vips_save_string_get_type()) VIPS_API GType vips_save_string_get_type(void); typedef struct _VipsSaveString { char *s; } VipsSaveString; /** * VIPS_TYPE_REF_STRING: * * The [alias@GObject.Type] for a [struct@RefString]. */ #define VIPS_TYPE_REF_STRING (vips_ref_string_get_type()) typedef struct _VipsRefString { VipsArea area; } VipsRefString; VIPS_API VipsRefString *vips_ref_string_new(const char *str); VIPS_API const char *vips_ref_string_get(VipsRefString *refstr, size_t *length); VIPS_API GType vips_ref_string_get_type(void); /** * VIPS_TYPE_BLOB: * * The [alias@GObject.Type] for a [struct@Blob]. */ #define VIPS_TYPE_BLOB (vips_blob_get_type()) typedef struct _VipsBlob { VipsArea area; } VipsBlob; VIPS_API VipsBlob *vips_blob_new(VipsCallbackFn free_fn, const void *data, size_t length); VIPS_API VipsBlob *vips_blob_copy(const void *data, size_t length); VIPS_API const void *vips_blob_get(VipsBlob *blob, size_t *length); VIPS_API void vips_blob_set(VipsBlob *blob, VipsCallbackFn free_fn, const void *data, size_t length); VIPS_API GType vips_blob_get_type(void); /** * VIPS_TYPE_ARRAY_DOUBLE: * * The [alias@GObject.Type] for a [struct@ArrayDouble]. */ #define VIPS_TYPE_ARRAY_DOUBLE (vips_array_double_get_type()) typedef struct _VipsArrayDouble { VipsArea area; } VipsArrayDouble; VIPS_API VipsArrayDouble *vips_array_double_new(const double *array, int n); VIPS_API VipsArrayDouble *vips_array_double_newv(int n, ...); VIPS_API double *vips_array_double_get(VipsArrayDouble *array, int *n); VIPS_API GType vips_array_double_get_type(void); /** * VIPS_TYPE_ARRAY_INT: * * The [alias@GObject.Type] for a [struct@ArrayInt]. */ #define VIPS_TYPE_ARRAY_INT (vips_array_int_get_type()) typedef struct _VipsArrayInt { VipsArea area; } VipsArrayInt; VIPS_API VipsArrayInt *vips_array_int_new(const int *array, int n); VIPS_API VipsArrayInt *vips_array_int_newv(int n, ...); VIPS_API int *vips_array_int_get(VipsArrayInt *array, int *n); VIPS_API GType vips_array_int_get_type(void); /** * VIPS_TYPE_ARRAY_IMAGE: * * The [alias@GObject.Type] for a [struct@ArrayImage]. */ #define VIPS_TYPE_ARRAY_IMAGE (vips_array_image_get_type()) typedef struct _VipsArrayImage { VipsArea area; } VipsArrayImage; /* See image.h for vips_array_image_new() etc., they need to be declared after * VipsImage. */ VIPS_API GType vips_array_image_get_type(void); VIPS_API void vips_value_set_area(GValue *value, VipsCallbackFn free_fn, void *data); VIPS_API void *vips_value_get_area(const GValue *value, size_t *length); VIPS_API const char *vips_value_get_save_string(const GValue *value); VIPS_API void vips_value_set_save_string(GValue *value, const char *str); VIPS_API void vips_value_set_save_stringf(GValue *value, const char *fmt, ...) G_GNUC_PRINTF(2, 3); VIPS_API const char *vips_value_get_ref_string(const GValue *value, size_t *length); VIPS_API void vips_value_set_ref_string(GValue *value, const char *str); VIPS_API void *vips_value_get_blob(const GValue *value, size_t *length); VIPS_API void vips_value_set_blob(GValue *value, VipsCallbackFn free_fn, const void *data, size_t length); VIPS_API void vips_value_set_blob_free(GValue *value, void *data, size_t length); VIPS_API void vips_value_set_array(GValue *value, int n, GType type, size_t sizeof_type); VIPS_API void *vips_value_get_array(const GValue *value, int *n, GType *type, size_t *sizeof_type); VIPS_API double *vips_value_get_array_double(const GValue *value, int *n); VIPS_API void vips_value_set_array_double(GValue *value, const double *array, int n); VIPS_API int *vips_value_get_array_int(const GValue *value, int *n); VIPS_API void vips_value_set_array_int(GValue *value, const int *array, int n); VIPS_API GObject **vips_value_get_array_object(const GValue *value, int *n); VIPS_API void vips_value_set_array_object(GValue *value, int n); /* See also image.h, that has vips_array_image_get(), vips_array_image_new(), * vips_value_get_array_image() and vips_value_set_array_image(). They need * to be declared after VipsImage. */ #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_TYPE_H*/ libvips-8.18.2/libvips/include/vips/util.h000066400000000000000000000200071516303661500204710ustar00rootroot00000000000000/* Various useful definitions. * * J.Cupitt, 8/4/93 * 15/7/96 JC * - C++ stuff added */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_UTIL_H #define VIPS_UTIL_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include /* Some platforms don't have M_PI :-( */ #define VIPS_PI (3.14159265358979323846) /* Convert degrees->rads and vice-versa. */ #define VIPS_RAD(R) (((R) / 360.0) * 2.0 * VIPS_PI) #define VIPS_DEG(A) (((A) / (2.0 * VIPS_PI)) * 360.0) #define VIPS_MAX(A, B) ((A) > (B) ? (A) : (B)) #define VIPS_MIN(A, B) ((A) < (B) ? (A) : (B)) #define VIPS_FMAX(A, B) fmax((A), (B)) VIPS_DEPRECATED_MACRO_FOR(fmax) #define VIPS_FMIN(A, B) fmin((A), (B)) VIPS_DEPRECATED_MACRO_FOR(fmin) #define VIPS_CLIP(A, V, B) VIPS_MAX((A), VIPS_MIN((B), (V))) #define VIPS_FCLIP(A, V, B) fmax((A), fmin((B), (V))) #define VIPS_NUMBER(R) ((int) (sizeof(R) / sizeof(R[0]))) #define VIPS_ABS(V) (((V) >= 0) ? (V) : -(V)) #define VIPS_FABS(V) fabs((V)) VIPS_DEPRECATED_MACRO_FOR(fabs) // is something (eg. a pointer) N aligned #define VIPS_ALIGNED(P, N) ((((guint64) (P)) & ((N) - 1)) == 0) #define VIPS_ISNAN(V) isnan(V) VIPS_DEPRECATED_MACRO_FOR(isnan) #define VIPS_FLOOR(V) floor(V) VIPS_DEPRECATED_MACRO_FOR(floor) #define VIPS_CEIL(V) ceil(V) VIPS_DEPRECATED_MACRO_FOR(ceil) #define VIPS_RINT(V) rint(V) VIPS_DEPRECATED_MACRO_FOR(rint) #define VIPS_ROUND(V) round(V) VIPS_DEPRECATED_MACRO_FOR(round) /* Testing status before the function call saves a lot of time. */ #define VIPS_ONCE(ONCE, FUNC, CLIENT) \ G_STMT_START \ { \ if (G_UNLIKELY((ONCE)->status != G_ONCE_STATUS_READY)) \ (void) g_once(ONCE, FUNC, CLIENT); \ } \ G_STMT_END /* rint() does "bankers rounding", it rounds to the nearest even integer. * For things like image geometry, we want strict nearest int. * * If you know it's unsigned, _UINT is a little faster. */ #define VIPS_ROUND_INT(R) ((int) ((R) > 0 ? ((R) + 0.5) : ((R) -0.5))) #define VIPS_ROUND_UINT(R) ((int) ((R) + 0.5)) /* Round N down and up to the nearest multiple of P. */ #define VIPS_ROUND_DOWN(N, P) ((N) - ((N) % (P))) #define VIPS_ROUND_UP(N, P) (VIPS_ROUND_DOWN((N) + (P) -1, (P))) #define VIPS_SWAP(TYPE, A, B) \ G_STMT_START \ { \ TYPE t = (A); \ (A) = (B); \ (B) = t; \ } \ G_STMT_END /* Duff's device. Do OPERation N times in a 16-way unrolled loop. */ #define VIPS_UNROLL(N, OPER) \ G_STMT_START \ { \ if ((N)) { \ int duff_count = ((N) + 15) / 16; \ \ switch ((N) % 16) { \ case 0: \ do { \ OPER; \ case 15: \ OPER; \ case 14: \ OPER; \ case 13: \ OPER; \ case 12: \ OPER; \ case 11: \ OPER; \ case 10: \ OPER; \ case 9: \ OPER; \ case 8: \ OPER; \ case 7: \ OPER; \ case 6: \ OPER; \ case 5: \ OPER; \ case 4: \ OPER; \ case 3: \ OPER; \ case 2: \ OPER; \ case 1: \ OPER; \ } while (--duff_count > 0); \ } \ } \ } \ G_STMT_END /* Various integer range clips. Record over/under flows. */ #define VIPS_CLIP_UCHAR(V, SEQ) \ G_STMT_START \ { \ if ((V) < 0) { \ (SEQ)->underflow++; \ (V) = 0; \ } \ else if ((V) > UCHAR_MAX) { \ (SEQ)->overflow++; \ (V) = UCHAR_MAX; \ } \ } \ G_STMT_END #define VIPS_CLIP_CHAR(V, SEQ) \ G_STMT_START \ { \ if ((V) < SCHAR_MIN) { \ (SEQ)->underflow++; \ (V) = SCHAR_MIN; \ } \ else if ((V) > SCHAR_MAX) { \ (SEQ)->overflow++; \ (V) = SCHAR_MAX; \ } \ } \ G_STMT_END #define VIPS_CLIP_USHORT(V, SEQ) \ G_STMT_START \ { \ if ((V) < 0) { \ (SEQ)->underflow++; \ (V) = 0; \ } \ else if ((V) > USHRT_MAX) { \ (SEQ)->overflow++; \ (V) = USHRT_MAX; \ } \ } \ G_STMT_END #define VIPS_CLIP_SHORT(V, SEQ) \ G_STMT_START \ { \ if ((V) < SHRT_MIN) { \ (SEQ)->underflow++; \ (V) = SHRT_MIN; \ } \ else if ((V) > SHRT_MAX) { \ (SEQ)->overflow++; \ (V) = SHRT_MAX; \ } \ } \ G_STMT_END #define VIPS_CLIP_UINT(V, SEQ) \ G_STMT_START \ { \ if ((V) < 0) { \ (SEQ)->underflow++; \ (V) = 0; \ } \ } \ G_STMT_END #define VIPS_CLIP_NONE(V, SEQ) \ { \ } /* Not all platforms have PATH_MAX (eg. Hurd) and we don't need a platform one * anyway, just a static buffer big enough for almost any path. */ #define VIPS_PATH_MAX (4096) /* Create multiple copies of a function targeted at groups of SIMD intrinsics, * with the most suitable selected at runtime via dynamic dispatch. */ #ifdef HAVE_TARGET_CLONES #define VIPS_TARGET_CLONES(TARGETS) \ __attribute__((target_clones(TARGETS))) #else #define VIPS_TARGET_CLONES(TARGETS) #endif VIPS_API const char *vips_enum_string(GType enm, int value); VIPS_API const char *vips_enum_nick(GType enm, int value); VIPS_API int vips_enum_from_nick(const char *domain, GType type, const char *str); VIPS_API int vips_flags_from_nick(const char *domain, GType type, const char *nick); VIPS_API gboolean vips_slist_equal(GSList *l1, GSList *l2); VIPS_API void *vips_slist_map2(GSList *list, VipsSListMap2Fn fn, void *a, void *b); VIPS_API void *vips_slist_map2_rev(GSList *list, VipsSListMap2Fn fn, void *a, void *b); VIPS_API void *vips_slist_map4(GSList *list, VipsSListMap4Fn fn, void *a, void *b, void *c, void *d); VIPS_API void *vips_slist_fold2(GSList *list, void *start, VipsSListFold2Fn fn, void *a, void *b); VIPS_API GSList *vips_slist_filter(GSList *list, VipsSListMap2Fn fn, void *a, void *b); VIPS_API void vips_slist_free_all(GSList *list); VIPS_API void *vips_map_equal(void *a, void *b); VIPS_API void *vips_hash_table_map(GHashTable *hash, VipsSListMap2Fn fn, void *a, void *b); VIPS_API gboolean vips_iscasepostfix(const char *a, const char *b); VIPS_API gboolean vips_isprefix(const char *a, const char *b); VIPS_API char *vips_break_token(char *str, const char *brk); VIPS_API int vips_filename_suffix_match(const char *path, const char *suffixes[]); VIPS_API gint64 vips_file_length(int fd); VIPS_API int vips_existsf(const char *name, ...) G_GNUC_PRINTF(1, 2); VIPS_API int vips_isdirf(const char *name, ...) G_GNUC_PRINTF(1, 2); VIPS_API int vips_mkdirf(const char *name, ...) G_GNUC_PRINTF(1, 2); VIPS_API int vips_rmdirf(const char *name, ...) G_GNUC_PRINTF(1, 2); VIPS_API int vips_rename(const char *old_name, const char *new_name); /** * VipsToken: (skip) * @VIPS_TOKEN_LEFT: left bracket * @VIPS_TOKEN_RIGHT: right bracket * @VIPS_TOKEN_STRING: string constant * @VIPS_TOKEN_EQUALS: equals sign * @VIPS_TOKEN_COMMA: comma * * Tokens returned by the vips lexical analyzer, see vips__token_get(). This * is used to parse option strings for arguments. * * Left and right brackets can be any of (, {, [, <. * * Strings may be in double quotes, and may contain escaped quote characters, * for example string, "string" and "str\"ing". */ typedef enum { VIPS_TOKEN_LEFT = 1, VIPS_TOKEN_RIGHT, VIPS_TOKEN_STRING, VIPS_TOKEN_EQUALS, VIPS_TOKEN_COMMA } VipsToken; #ifndef __GI_SCANNER__ // we expose this one in the API for testing VIPS_API const char *vips__token_get(const char *buffer, VipsToken *token, char *string, int size); #endif /* !__GI_SCANNER__ */ VIPS_API int vips_ispoweroftwo(int p); VIPS_API int vips_amiMSBfirst(void); VIPS_API char *vips_realpath(const char *path); VIPS_API int vips_strtod(const char *str, double *out); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_UTIL_H*/ libvips-8.18.2/libvips/include/vips/vector.h000066400000000000000000000026161516303661500210240ustar00rootroot00000000000000/* helper stuff for Highway * * 16/03/21 kleisauke * - from vector.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VECTOR_H #define VIPS_VECTOR_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_API gboolean vips_vector_isenabled(void); VIPS_API void vips_vector_set_enabled(gboolean enabled); VIPS_API gint64 vips_vector_get_builtin_targets(void); VIPS_API gint64 vips_vector_get_supported_targets(void); VIPS_API const char *vips_vector_target_name(gint64 target); VIPS_API void vips_vector_disable_targets(gint64 disabled_targets); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_VECTOR_H*/ libvips-8.18.2/libvips/include/vips/version.h.in000066400000000000000000000013351516303661500216110ustar00rootroot00000000000000/* Macros for the header version. */ #ifndef VIPS_VERSION_H #define VIPS_VERSION_H #define VIPS_VERSION "@VIPS_VERSION@" #define VIPS_VERSION_STRING "@VIPS_VERSION_STRING@" #define VIPS_MAJOR_VERSION (@VIPS_MAJOR_VERSION@) #define VIPS_MINOR_VERSION (@VIPS_MINOR_VERSION@) #define VIPS_MICRO_VERSION (@VIPS_MICRO_VERSION@) /* The ABI version, as used for library versioning. */ #define VIPS_LIBRARY_CURRENT (@LIBRARY_CURRENT@) #define VIPS_LIBRARY_REVISION (@LIBRARY_REVISION@) #define VIPS_LIBRARY_AGE (@LIBRARY_AGE@) #define VIPS_CONFIG "@VIPS_CONFIG@" /* Not really anything to do with versions, but this is a handy place to put * it. */ #define VIPS_ENABLE_DEPRECATED @VIPS_ENABLE_DEPRECATED@ #endif /*VIPS_VERSION_H*/ libvips-8.18.2/libvips/include/vips/video.h000066400000000000000000000023601516303661500206240ustar00rootroot00000000000000/* video.h * * 20/9/09 * - from proto.h */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IM_VIDEO_H #define IM_VIDEO_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ VIPS_DEPRECATED int im_video_v4l1(VipsImage *im, const char *device, int channel, int brightness, int colour, int contrast, int hue, int ngrabs); VIPS_DEPRECATED int im_video_test(VipsImage *im, int brightness, int error); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*IM_VIDEO_H*/ libvips-8.18.2/libvips/include/vips/vips.h000066400000000000000000000115071516303661500205020ustar00rootroot00000000000000/* @(#) Header file for Birkbeck/VIPS Image Processing Library * Authors: N. Dessipris, K. Martinez, Birkbeck College, London. * Sept 94 * * 15/7/96 JC * - now does C++ extern stuff * - many more protos * 15/4/97 JC * - protos split out * 4/3/98 JC * - IM_ANY added * - sRGB colourspace added * 28/10/98 JC * - VASARI_MAGIC_INTEL and VASARI_MAGIC_SPARC added * 29/9/99 JC * - new locks for threading, no more threadgroup stuff in IMAGE * 30/11/00 JC * - override RGB/CMYK macros on cygwin * 21/9/02 JC * - new Xoffset/Yoffset fields * - rationalized macro names * 6/6/05 Markus Wollgarten * - added Meta header field * 31/7/05 * - added meta.h for new metadata API * 22/8/05 * - scrapped stupid VAS_HD * 30/9/05 * - added sizeof_header field for mmap window read of RAW files * 4/10/05 * - now you have to define IM_ENABLE_DEPRECATED to get broken #defined * 5/10/05 * - added GNUC attributes * 8/5/06 * - added RGB16, GREY16 * 30/10/06 * - added im_window_t * 7/11/07 * - added preclose and evalstart callbacks * - brought time struct in here * 7/3/08 * - MAGIC values should be unsigned * 2/7/08 * - added invalidate callbacks * 7/8/08 * - include , thanks nicola * 30/6/09 * - move deprecated stuff to its own header * 16/5/18 * - remove old vips7 stuff, you must explicitly include it now */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VIPS_H #define VIPS_VIPS_H #include #include #include #include /* Needed for VipsGInputStream. */ #include #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* VIPS_DISABLE_COMPAT: * * Disable automatically inclusion of `vips7compat.h`. * * This has no effect when building with `-Ddeprecated=false`. */ #if VIPS_ENABLE_DEPRECATED && !defined(VIPS_DISABLE_COMPAT) #include #endif /* We can't use _ here since this will be compiled by our clients and they may * not have _(). */ #define VIPS_INIT(ARGV0) \ (vips_version(3) - vips_version(5) != \ VIPS_LIBRARY_CURRENT - VIPS_LIBRARY_AGE \ ? ( \ g_warning("ABI mismatch"), \ g_warning("library has ABI version %d", \ vips_version(3) - vips_version(5)), \ g_warning("application needs ABI version %d", \ VIPS_LIBRARY_CURRENT - VIPS_LIBRARY_AGE), \ vips_error("vips_init", "ABI mismatch"), \ -1) \ : vips_init(ARGV0)) VIPS_API int vips_max_coord_get(void); VIPS_API int vips_init(const char *argv0); VIPS_API const char *vips_get_argv0(void); VIPS_API const char *vips_get_prgname(void); VIPS_API void vips_shutdown(void); VIPS_API void vips_thread_shutdown(void); VIPS_API void vips_add_option_entries(GOptionGroup *option_group); VIPS_API void vips_leak_set(gboolean leak); VIPS_API void vips_block_untrusted_set(gboolean state); VIPS_API const char *vips_version_string(void); VIPS_API int vips_version(int flag); VIPS_API const char *vips_guess_prefix(const char *argv0, const char *env_name); VIPS_API const char *vips_guess_libdir(const char *argv0, const char *env_name); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_VIPS_H*/ libvips-8.18.2/libvips/include/vips/vips7compat.h000066400000000000000000001706141516303661500220020ustar00rootroot00000000000000/* compat with the vips7 API * * 4/3/11 * - hacked up */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_VIPS7COMPAT_H #define VIPS_VIPS7COMPAT_H #include #ifdef HAVE_ORC #include #endif /* HAVE_ORC */ #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ /* Renamed types. */ /* We have this misspelt in earlier versions :( */ #define VIPS_META_IPCT_NAME VIPS_META_IPTC_NAME #define IM_D93_X0 VIPS_D93_X0 #define IM_D93_Y0 VIPS_D93_Y0 #define IM_D93_Z0 VIPS_D93_Z0 #define IM_D75_X0 VIPS_D75_X0 #define IM_D75_Y0 VIPS_D75_Y0 #define IM_D75_Z0 VIPS_D75_Z0 #define IM_D65_X0 VIPS_D65_X0 #define IM_D65_Y0 VIPS_D65_Y0 #define IM_D65_Z0 VIPS_D65_Z0 #define IM_D55_X0 VIPS_D55_X0 #define IM_D55_Y0 VIPS_D55_Y0 #define IM_D55_Z0 VIPS_D55_Z0 #define IM_D50_X0 VIPS_D50_X0 #define IM_D50_Y0 VIPS_D50_Y0 #define IM_D50_Z0 VIPS_D50_Z0 #define IM_A_X0 VIPS_A_X0 #define IM_A_Y0 VIPS_A_Y0 #define IM_A_Z0 VIPS_A_Z0 #define IM_B_X0 VIPS_B_X0 #define IM_B_Y0 VIPS_B_Y0 #define IM_B_Z0 VIPS_B_Z0 #define IM_C_X0 VIPS_C_X0 #define IM_C_Y0 VIPS_C_Y0 #define IM_C_Z0 VIPS_C_Z0 #define IM_E_X0 VIPS_E_X0 #define IM_E_Y0 VIPS_E_Y0 #define IM_E_Z0 VIPS_E_Z0 #define IM_D3250_X0 VIPS_D3250_X0 #define IM_D3250_Y0 VIPS_D3250_Y0 #define IM_D3250_Z0 VIPS_D3250_Z0 #define im_col_Lab2XYZ vips_col_Lab2XYZ #define im_col_XYZ2Lab vips_col_XYZ2Lab #define im_col_ab2h vips_col_ab2h #define im_col_ab2Ch vips_col_ab2Ch #define im_col_Ch2ab vips_col_Ch2ab #define im_col_L2Lucs vips_col_L2Lcmc #define im_col_C2Cucs vips_col_C2Ccmc #define im_col_Ch2hucs vips_col_Ch2hcmc #define im_col_pythagoras vips_pythagoras #define im_col_make_tables_UCS vips_col_make_tables_CMC #define im_col_Lucs2L vips_col_Lcmc2L #define im_col_Cucs2C vips_col_Ccmc2C #define im_col_Chucs2h vips_col_Chcmc2h #define PEL VipsPel #define IM_BANDFMT_NOTSET VIPS_FORMAT_NOTSET #define IM_BANDFMT_UCHAR VIPS_FORMAT_UCHAR #define IM_BANDFMT_CHAR VIPS_FORMAT_CHAR #define IM_BANDFMT_USHORT VIPS_FORMAT_USHORT #define IM_BANDFMT_SHORT VIPS_FORMAT_SHORT #define IM_BANDFMT_UINT VIPS_FORMAT_UINT #define IM_BANDFMT_INT VIPS_FORMAT_INT #define IM_BANDFMT_FLOAT VIPS_FORMAT_FLOAT #define IM_BANDFMT_COMPLEX VIPS_FORMAT_COMPLEX #define IM_BANDFMT_DOUBLE VIPS_FORMAT_DOUBLE #define IM_BANDFMT_DPCOMPLEX VIPS_FORMAT_DPCOMPLEX #define IM_BANDFMT_LAST VIPS_FORMAT_LAST #define VipsBandFmt VipsBandFormat #define IM_SMALLTILE VIPS_DEMAND_STYLE_SMALLTILE #define IM_FATSTRIP VIPS_DEMAND_STYLE_FATSTRIP #define IM_THINSTRIP VIPS_DEMAND_STYLE_THINSTRIP #define IM_ANY VIPS_DEMAND_STYLE_ANY #define IM_CODING_NONE VIPS_CODING_NONE #define IM_CODING_LABQ VIPS_CODING_LABQ #define IM_CODING_RAD VIPS_CODING_RAD #define IM_TYPE_MULTIBAND VIPS_INTERPRETATION_MULTIBAND #define IM_TYPE_B_W VIPS_INTERPRETATION_B_W #define IM_TYPE_HISTOGRAM VIPS_INTERPRETATION_HISTOGRAM #define IM_TYPE_FOURIER VIPS_INTERPRETATION_FOURIER #define IM_TYPE_XYZ VIPS_INTERPRETATION_XYZ #define IM_TYPE_LAB VIPS_INTERPRETATION_LAB #define IM_TYPE_CMYK VIPS_INTERPRETATION_CMYK #define IM_TYPE_LABQ VIPS_INTERPRETATION_LABQ #define IM_TYPE_RGB VIPS_INTERPRETATION_RGB #define IM_TYPE_UCS VIPS_INTERPRETATION_CMC #define IM_TYPE_LCH VIPS_INTERPRETATION_LCH #define IM_TYPE_LABS VIPS_INTERPRETATION_LABS #define IM_TYPE_sRGB VIPS_INTERPRETATION_sRGB #define IM_TYPE_YXY VIPS_INTERPRETATION_YXY #define IM_TYPE_RGB16 VIPS_INTERPRETATION_RGB16 #define IM_TYPE_GREY16 VIPS_INTERPRETATION_GREY16 #define VipsType VipsInterpretation #define IMAGE VipsImage #define REGION VipsRegion #define IM_INTENT_PERCEPTUAL VIPS_INTENT_PERCEPTUAL #define IM_INTENT_RELATIVE_COLORIMETRIC VIPS_INTENT_RELATIVE #define IM_INTENT_SATURATION VIPS_INTENT_SATURATION #define IM_INTENT_ABSOLUTE_COLORIMETRIC VIPS_INTENT_ABSOLUTE /* Renamed macros. */ #define IM_MAX VIPS_MAX #define IM_MIN VIPS_MIN #define IM_RAD VIPS_RAD #define IM_DEG VIPS_DEG #define IM_PI VIPS_PI #define IM_RINT VIPS_RINT #define IM_ABS VIPS_ABS #define IM_NUMBER VIPS_NUMBER #define IM_CLIP VIPS_CLIP #define IM_CLIP_UCHAR VIPS_CLIP_UCHAR #define IM_CLIP_CHAR VIPS_CLIP_CHAR #define IM_CLIP_USHORT VIPS_CLIP_USHORT #define IM_CLIP_SHORT VIPS_CLIP_SHORT #define IM_CLIP_NONE VIPS_CLIP_NONE #define IM_SWAP VIPS_SWAP #define IM_IMAGE_ADDR VIPS_IMAGE_ADDR #define IM_IMAGE_N_ELEMENTS VIPS_IMAGE_N_ELEMENTS #define IM_IMAGE_SIZEOF_ELEMENT VIPS_IMAGE_SIZEOF_ELEMENT #define IM_IMAGE_SIZEOF_PEL VIPS_IMAGE_SIZEOF_PEL #define IM_IMAGE_SIZEOF_LINE VIPS_IMAGE_SIZEOF_LINE #define IM_REGION_LSKIP VIPS_REGION_LSKIP #define IM_REGION_ADDR VIPS_REGION_ADDR #define IM_REGION_ADDR_TOPLEFT VIPS_REGION_ADDR_TOPLEFT #define IM_REGION_N_ELEMENTS VIPS_REGION_N_ELEMENTS #define IM_REGION_SIZEOF_LINE VIPS_REGION_SIZEOF_LINE /* Renamed externs. */ VIPS_DEPRECATED_FOR(vips_format_sizeof_unsafe) const guint64 vips__image_sizeof_bandformat[]; #define im__sizeof_bandfmt vips__image_sizeof_bandformat /* Renamed functions. */ #define im_error vips_error #define im_verror vips_verror #define im_verror_system vips_verror_system #define im_error_system vips_error_system #define im_error_buffer vips_error_buffer #define im_error_clear vips_error_clear #define im_warn vips_warn #define im_vwarn vips_vwarn #define im_diag vips_info #define im_vdiag vips_vinfo #define error_exit vips_error_exit #define im_get_argv0 vips_get_argv0 #define im_version_string vips_version_string #define im_version vips_version #define im_get_option_group vips_get_option_group #define im_guess_prefix vips_guess_prefix #define im_guess_libdir vips_guess_libdir #define im__global_lock vips__global_lock VIPS_DEPRECATED int im_cp_desc(IMAGE *out, IMAGE *in); VIPS_DEPRECATED int im_cp_descv(IMAGE *im, ...); #define im_cp_desc_array(I, A) vips__image_copy_fields_array(I, A) VIPS_DEPRECATED int im_demand_hint(IMAGE *im, VipsDemandStyle hint, ...); #define im_demand_hint_array(A, B, C) (vips__demand_hint_array(A, B, C), 0) #define im_image(P, W, H, B, F) \ vips_image_new_from_memory((P), 0, (W), (H), (B), (F)) #define im_binfile vips_image_new_from_file_raw #define im__open_temp vips_image_new_temp_file #define im__test_kill(I) (vips_image_iskilled(I)) #define im__start_eval(I) (vips_image_preeval(I), vips_image_iskilled(I)) #define im__handle_eval(I, W, H) \ (vips_image_eval(I, W, H), vips_image_iskilled(I)) #define im__end_eval vips_image_posteval #define im_invalidate vips_image_invalidate_all #define im_isfile vips_image_isfile #define im_printdesc(I) vips_object_print_dump(VIPS_OBJECT(I)) /* im_openout() needs to have this visible. */ VIPS_DEPRECATED VipsImage *vips_image_new_mode(const char *filename, const char *mode); /* im_image_open_input() needs to have this visible. */ VIPS_DEPRECATED int vips_image_open_input(VipsImage *image); /* im_image_open_output() needs to have this visible. */ VIPS_DEPRECATED int vips_image_open_output(VipsImage *image); /* im_mapfile() needs to have this visible. */ VIPS_DEPRECATED int vips_mapfile(VipsImage *image); /* im_mapfilerw() needs to have this visible. */ VIPS_DEPRECATED int vips_mapfilerw(VipsImage *image); /* im_remapfilerw() needs to have this visible. */ VIPS_DEPRECATED int vips_remapfilerw(VipsImage *image); #define im_openout(F) vips_image_new_mode(F, "w") #define im_setbuf(F) vips_image_new("t") #define im_initdesc(image, \ xsize, ysize, bands, bandbits, bandfmt, coding, \ type, xres, yres, xo, yo) \ vips_image_init_fields(image, \ xsize, ysize, bands, bandfmt, coding, \ type, xres, yres) #define im__open_image_file vips__open_image_read #define im_setupout vips_image_write_prepare #define im_writeline(Y, IM, P) vips_image_write_line(IM, Y, P) #define im_prepare vips_region_prepare #define im_prepare_to vips_region_prepare_to #define im_region_create vips_region_new #define im_region_free g_object_unref #define im_region_region vips_region_region #define im_region_buffer vips_region_buffer #define im_region_black vips_region_black #define im_region_paint vips_region_paint #define im_prepare_many vips_region_prepare_many #define im__region_no_ownership vips__region_no_ownership #define im_image_sanity(I) (!vips_object_sanity(VIPS_OBJECT(I))) #define im_image_sanity_all vips_object_sanity_all #define im__print_all vips_object_print_all /* Compat functions. */ VIPS_DEPRECATED_FOR(vips_init) int im_init_world(const char *argv0); VIPS_DEPRECATED_FOR(vips_image_new_mode) VipsImage *im_open(const char *filename, const char *mode); VIPS_DEPRECATED VipsImage *im_open_local(VipsImage *parent, const char *filename, const char *mode); VIPS_DEPRECATED int im_open_local_array(VipsImage *parent, VipsImage **images, int n, const char *filename, const char *mode); #define im_callback_fn VipsCallbackFn VIPS_DEPRECATED_FOR(g_signal_connect) int im_add_callback(VipsImage *im, const char *callback, im_callback_fn fn, void *a, void *b); VIPS_DEPRECATED_FOR(g_signal_connect) int im_add_callback1(VipsImage *im, const char *callback, im_callback_fn fn, void *a, void *b); #define im_add_close_callback(IM, FN, A, B) \ im_add_callback(IM, "close", FN, A, B) #define im_add_postclose_callback(IM, FN, A, B) \ im_add_callback(IM, "postclose", FN, A, B) #define im_add_preclose_callback(IM, FN, A, B) \ im_add_callback(IM, "preclose", FN, A, B) #define im_add_evalstart_callback(IM, FN, A, B) \ im_add_callback1(IM, "preeval", FN, A, B) #define im_add_evalend_callback(IM, FN, A, B) \ im_add_callback1(IM, "posteval", FN, A, B) #define im_add_eval_callback(IM, FN, A, B) \ (vips_image_set_progress(IM, TRUE), \ im_add_callback1(IM, "eval", FN, A, B)) #define im_add_invalidate_callback(IM, FN, A, B) \ im_add_callback(IM, "invalidate", FN, A, B) #define im_bits_of_fmt(fmt) (vips_format_sizeof(fmt) << 3) typedef void *(*im_construct_fn)(void *, void *, void *); VIPS_DEPRECATED_FOR(vips_object_local) void *im_local(VipsImage *im, im_construct_fn cons, im_callback_fn dest, void *a, void *b, void *c); VIPS_DEPRECATED_FOR(vips_object_local_array) int im_local_array(VipsImage *im, void **out, int n, im_construct_fn cons, im_callback_fn dest, void *a, void *b, void *c); VIPS_DEPRECATED_FOR(g_object_unref) int im_close(VipsImage *im); VIPS_DEPRECATED_FOR(vips_image_new_from_file) VipsImage *im_init(const char *filename); VIPS_DEPRECATED_FOR(vips_enum_string) const char *im_Type2char(VipsInterpretation type); VIPS_DEPRECATED_FOR(vips_enum_string) const char *im_BandFmt2char(VipsBandFormat fmt); VIPS_DEPRECATED_FOR(vips_enum_string) const char *im_Coding2char(VipsCoding coding); VIPS_DEPRECATED_FOR(vips_enum_string) const char *im_Compression2char(int n); VIPS_DEPRECATED_FOR(vips_enum_string) const char *im_dtype2char(VipsImageType n); VIPS_DEPRECATED_FOR(vips_enum_string) const char *im_dhint2char(VipsDemandStyle style); VIPS_DEPRECATED_FOR(vips_enum_from_nick) VipsInterpretation im_char2Type(const char *str); VIPS_DEPRECATED_FOR(vips_enum_from_nick) VipsBandFormat im_char2BandFmt(const char *str); VIPS_DEPRECATED_FOR(vips_enum_from_nick) VipsCoding im_char2Coding(const char *str); VIPS_DEPRECATED_FOR(vips_enum_from_nick) VipsImageType im_char2dtype(const char *str); VIPS_DEPRECATED_FOR(vips_enum_from_nick) VipsDemandStyle im_char2dhint(const char *str); #define Rect VipsRect #define IM_RECT_RIGHT VIPS_RECT_RIGHT #define IM_RECT_BOTTOM VIPS_RECT_BOTTOM #define IM_RECT_HCENTRE VIPS_RECT_HCENTRE #define IM_RECT_VCENTRE VIPS_RECT_VCENTRE #define im_rect_marginadjust vips_rect_marginadjust #define im_rect_includespoint vips_rect_includespoint #define im_rect_includesrect vips_rect_includesrect #define im_rect_intersectrect vips_rect_intersectrect #define im_rect_isempty vips_rect_isempty #define im_rect_unionrect vips_rect_unionrect #define im_rect_equalsrect vips_rect_equalsrect #define im_rect_dup vips_rect_dup #define im_rect_normalise vips_rect_normalise #define im_start_one vips_start_one #define im_stop_one vips_stop_one #define im_start_many vips_start_many #define im_stop_many vips_stop_many #define im_allocate_input_array vips_allocate_input_array #define im_start_fn VipsStartFn typedef int (*im_generate_fn)(VipsRegion *out, void *seq, void *a, void *b); #define im_stop_fn VipsStopFn VIPS_DEPRECATED_FOR(vips_image_generate) int im_generate(VipsImage *im, im_start_fn start, im_generate_fn generate, im_stop_fn stop, void *a, void *b); #define im__mmap vips__mmap #define im__munmap vips__munmap #define im_mapfile vips_mapfile #define im_mapfilerw vips_mapfilerw #define im_remapfilerw vips_remapfilerw #define im__print_renders vips__print_renders VIPS_DEPRECATED_FOR(vips_sink_screen) int im_cache(IMAGE *in, IMAGE *out, int width, int height, int max); #define IM_FREEF(F, S) \ G_STMT_START \ { \ if (S) { \ (void) F((S)); \ (S) = 0; \ } \ } \ G_STMT_END /* Can't just use VIPS_FREEF(), we want the extra cast to void on the argument * to vips_free() to make sure we can work for "const char *" variables. */ #define IM_FREE(S) \ G_STMT_START \ { \ if (S) { \ (void) im_free((void *) (S)); \ (S) = 0; \ } \ } \ G_STMT_END #define IM_SETSTR(S, V) \ G_STMT_START \ { \ const char *sst = (V); \ \ if ((S) != sst) { \ if (!(S) || !sst || strcmp((S), sst) != 0) { \ IM_FREE(S); \ if (sst) \ (S) = im_strdup(NULL, sst); \ } \ } \ } \ G_STMT_END #define im_malloc(IM, SZ) \ (vips_malloc(VIPS_OBJECT(IM), (SZ))) #define im_free vips_free #define im_strdup(IM, STR) \ (vips_strdup(VIPS_OBJECT(IM), (STR))) #define IM_NEW(IM, T) ((T *) im_malloc((IM), sizeof(T))) #define IM_ARRAY(IM, N, T) ((T *) im_malloc((IM), (N) * sizeof(T))) #define im_incheck vips_image_wio_input #define im_outcheck(I) (0) #define im_rwcheck vips_image_inplace #define im_pincheck vips_image_pio_input #define im_poutcheck(I) (0) #define im_iocheck(I, O) im_incheck(I) #define im_piocheck(I, O) im_pincheck(I) #define im_check_uncoded vips_check_uncoded #define im_check_coding_known vips_check_coding_known #define im_check_coding_labq vips_check_coding_labq #define im_check_coding_rad vips_check_coding_rad #define im_check_coding_noneorlabq vips_check_coding_noneorlabq #define im_check_coding_same vips_check_coding_same #define im_check_mono vips_check_mono #define im_check_bands_1or3 vips_check_bands_1or3 #define im_check_bands vips_check_bands #define im_check_bands_1orn vips_check_bands_1orn #define im_check_bands_1orn_unary vips_check_bands_1orn_unary #define im_check_bands_same vips_check_bands_same #define im_check_bandno vips_check_bandno #define im_check_int vips_check_int #define im_check_uint vips_check_uint #define im_check_uintorf vips_check_uintorf #define im_check_noncomplex vips_check_noncomplex #define im_check_complex vips_check_complex #define im_check_format vips_check_format #define im_check_u8or16 vips_check_u8or16 #define im_check_8or16 vips_check_8or16 #define im_check_u8or16orf vips_check_u8or16orf #define im_check_format_same vips_check_format_same #define im_check_size_same vips_check_size_same #define im_check_vector vips_check_vector #define im_check_hist vips_check_hist #define im_check_imask vips_check_imask #define im_check_dmask vips_check_dmask #define vips_bandfmt_isint vips_band_format_isint #define vips_bandfmt_isuint vips_band_format_isuint #define vips_bandfmt_isfloat vips_band_format_isfloat #define vips_bandfmt_iscomplex vips_band_format_iscomplex #define im__change_suffix vips__change_suffix /* Buffer processing. */ typedef void (*im_wrapone_fn)(void *in, void *out, int width, void *a, void *b); VIPS_DEPRECATED int im_wrapone(VipsImage *in, VipsImage *out, im_wrapone_fn fn, void *a, void *b); typedef void (*im_wraptwo_fn)(void *in1, void *in2, void *out, int width, void *a, void *b); VIPS_DEPRECATED int im_wraptwo(VipsImage *in1, VipsImage *in2, VipsImage *out, im_wraptwo_fn fn, void *a, void *b); typedef void (*im_wrapmany_fn)(void **in, void *out, int width, void *a, void *b); VIPS_DEPRECATED int im_wrapmany(VipsImage **in, VipsImage *out, im_wrapmany_fn fn, void *a, void *b); #define IM_META_EXIF_NAME VIPS_META_EXIF_NAME #define IM_META_ICC_NAME VIPS_META_ICC_NAME #define IM_META_RESOLUTION_UNIT VIPS_META_RESOLUTION_UNIT #define IM_TYPE_SAVE_STRING VIPS_TYPE_SAVE_STRING #define IM_TYPE_BLOB VIPS_TYPE_BLOB #define IM_TYPE_AREA VIPS_TYPE_AREA #define IM_TYPE_REF_STRING VIPS_TYPE_REF_STRING #define im_header_map_fn VipsImageMapFn #define im_header_map vips_image_map #define im_header_int vips_image_get_int #define im_header_double vips_image_get_double #define im_header_string(IMAGE, FIELD, STRING) \ vips_image_get_string(IMAGE, FIELD, (const char **) STRING) #define im_header_as_string vips_image_get_as_string #define im_header_get_typeof vips_image_get_typeof #define im_header_get vips_image_get #define im_histlin vips_image_history_printf #define im_updatehist vips_image_history_args #define im_history_get vips_image_get_history #define im_save_string_get vips_value_get_save_string #define im_save_string_set vips_value_set_save_string #define im_save_string_setf vips_value_set_save_stringf #define im_ref_string_set vips_value_set_ref_string #define im_ref_string_get(V) vips_value_get_ref_string(V, NULL) VIPS_DEPRECATED_FOR(vips_value_get_ref_string) size_t im_ref_string_get_length(const GValue *value); #define im_blob_get vips_value_get_blob #define im_blob_set vips_value_set_blob #define im_meta_set(A, B, C) (vips_image_set(A, B, C), 0) #define im_meta_remove vips_image_remove #define im_meta_get vips_image_get #define im_meta_get_typeof vips_image_get_typeof #define im_meta_set_int(A, B, C) (vips_image_set_int(A, B, C), 0) #define im_meta_get_int vips_image_get_int #define im_meta_set_double(A, B, C) (vips_image_set_double(A, B, C), 0) #define im_meta_get_double vips_image_get_double #define im_meta_set_area(A, B, C, D) (vips_image_set_area(A, B, C, D), 0) #define im_meta_get_area vips_image_get_area #define im_meta_set_string(A, B, C) (vips_image_set_string(A, B, C), 0) #define im_meta_get_string vips_image_get_string #define im_meta_set_blob(A, B, C, D, E) \ (vips_image_set_blob(A, B, C, D, E), 0) #define im_meta_get_blob vips_image_get_blob #define im_semaphore_t VipsSemaphore #define im_semaphore_up vips_semaphore_up #define im_semaphore_down vips_semaphore_down #define im_semaphore_upn vips_semaphore_upn #define im_semaphore_downn vips_semaphore_downn #define im_semaphore_destroy vips_semaphore_destroy #define im_semaphore_init vips_semaphore_init #define im__open_image_read vips__open_image_read #define im_image_open_input vips_image_open_input #define im_image_open_output vips_image_open_output #define im__has_extension_block vips__has_extension_block #define im__read_extension_block vips__read_extension_block #define im__write_extension_block vips__write_extension_block #define im__writehist vips__writehist #define im__read_header_bytes vips__read_header_bytes #define im__write_header_bytes vips__write_header_bytes #define VSListMap2Fn VipsSListMap2Fn #define VSListMap4Fn VipsSListMap4Fn #define VSListFold2Fn VipsSListFold2Fn #define im_slist_equal vips_slist_equal #define im_slist_map2 vips_slist_map2 #define im_slist_map2_rev vips_slist_map2_rev #define im_slist_map4 vips_slist_map4 #define im_slist_fold2 vips_slist_fold2 #define im_slist_filter vips_slist_filter #define im_slist_free_all vips_slist_free_all #define im_map_equal vips_map_equal #define im_hash_table_map vips_hash_table_map #define im_strncpy vips_strncpy #define im_strrstr vips_strrstr #define im_ispostfix vips_ispostfix #define im_isprefix vips_isprefix #define im_break_token vips_break_token #define im_vsnprintf vips_vsnprintf #define im_snprintf vips_snprintf #define im_file_length vips_file_length #define im__write vips__write #define im__file_open_read vips__file_open_read #define im__file_open_write vips__file_open_write #define im__file_read vips__file_read #define im__file_read_name vips__file_read_name #define im__file_write vips__file_write #define im__get_bytes vips__get_bytes #define im__gvalue_ref_string_new vips__gvalue_ref_string_new #define im__gslist_gvalue_free vips__gslist_gvalue_free #define im__gslist_gvalue_copy vips__gslist_gvalue_copy #define im__gslist_gvalue_merge vips__gslist_gvalue_merge #define im__gslist_gvalue_get vips__gslist_gvalue_get #define im__seek vips__seek #define im__ftruncate vips__ftruncate #define im_existsf vips_existsf #define im_popenf vips_popenf #define im_ispoweroftwo vips_ispoweroftwo #define im_amiMSBfirst vips_amiMSBfirst #define im__temp_name vips__temp_name #define IM_VERSION_STRING VIPS_VERSION_STRING #define IM_MAJOR_VERSION VIPS_MAJOR_VERSION #define IM_MINOR_VERSION VIPS_MINOR_VERSION #define IM_MICRO_VERSION VIPS_MICRO_VERSION #if defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN) #define VIPS_EXEEXT ".exe" #else /* !defined(G_PLATFORM_WIN32) && !defined(G_WITH_CYGWIN) */ #define VIPS_EXEEXT "" #endif /* defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN) */ #define IM_EXEEXT VIPS_EXEEXT #define IM_SIZEOF_HEADER VIPS_SIZEOF_HEADER #define im_concurrency_set vips_concurrency_set #define im_concurrency_get vips_concurrency_get VIPS_DEPRECATED_FOR(vips_add) int im_add(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_subtract) int im_subtract(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_multiply) int im_multiply(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_divide) int im_divide(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_min) int im_min(VipsImage *in, double *out); VIPS_DEPRECATED_FOR(vips_min) int im_minpos(VipsImage *in, int *xpos, int *ypos, double *out); VIPS_DEPRECATED_FOR(vips_max) int im_max(VipsImage *in, double *out); VIPS_DEPRECATED_FOR(vips_max) int im_maxpos(VipsImage *in, int *xpos, int *ypos, double *out); VIPS_DEPRECATED_FOR(vips_avg) int im_avg(VipsImage *in, double *out); VIPS_DEPRECATED_FOR(vips_deviate) int im_deviate(VipsImage *in, double *out); VIPS_DEPRECATED_FOR(vips_invert) int im_invert(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_linear1) int im_lintra(double a, VipsImage *in, double b, VipsImage *out); VIPS_DEPRECATED_FOR(vips_linear) int im_lintra_vec(int n, double *a, VipsImage *in, double *b, VipsImage *out); VIPS_DEPRECATED_FOR(vips_abs) int im_abs(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_sign) int im_sign(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_stats) DOUBLEMASK *im_stats(VipsImage *in); VIPS_DEPRECATED_FOR(vips_measure) DOUBLEMASK *im_measure_area(VipsImage *im, int left, int top, int width, int height, int h, int v, int *sel, int nsel, const char *name); VIPS_DEPRECATED_FOR(vips_sin) int im_sintra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_cos) int im_costra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_tan) int im_tantra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_asin) int im_asintra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_acos) int im_acostra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_atan) int im_atantra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_log) int im_logtra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_log10) int im_log10tra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_exp) int im_exptra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_exp10) int im_exp10tra(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_floor) int im_floor(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_rint) int im_rint(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_ceil) int im_ceil(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_equal) int im_equal(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_notequal) int im_notequal(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_less) int im_less(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_lesseq) int im_lesseq(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_more) int im_more(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_moreeq) int im_moreeq(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_andimage) int im_andimage(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_orimage) int im_orimage(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_eorimage) int im_eorimage(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_andimage_const) int im_andimage_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_orimage_const) int im_orimage_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_eorimage_const) int im_eorimage_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_andimage_const1) int im_andimageconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_orimage_const1) int im_orimageconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_eorimage_const1) int im_eorimageconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_lshift_const) int im_shiftleft_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_lshift) int im_shiftleft(VipsImage *in, VipsImage *out, int n); VIPS_DEPRECATED_FOR(vips_rshift_const) int im_shiftright_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_rshift) int im_shiftright(VipsImage *in, VipsImage *out, int n); VIPS_DEPRECATED_FOR(vips_remainder) int im_remainder(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_remainder_const) int im_remainder_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_remainder_const1) int im_remainderconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_pow) int im_powtra(VipsImage *in, VipsImage *out, double e); VIPS_DEPRECATED_FOR(vips_pow_const) int im_powtra_vec(VipsImage *in, VipsImage *out, int n, double *e); VIPS_DEPRECATED_FOR(vips_exp) int im_expntra(VipsImage *in, VipsImage *out, double e); VIPS_DEPRECATED_FOR(vips_exp_const) int im_expntra_vec(VipsImage *in, VipsImage *out, int n, double *e); VIPS_DEPRECATED_FOR(vips_equal_const) int im_equal_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_notequal_const) int im_notequal_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_less_const) int im_less_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_lesseq_const) int im_lesseq_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_more_const) int im_more_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_moreeq_const) int im_moreeq_vec(VipsImage *in, VipsImage *out, int n, double *c); VIPS_DEPRECATED_FOR(vips_equal_const1) int im_equalconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_notequal_const1) int im_notequalconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_less_const1) int im_lessconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_lesseq_const1) int im_lesseqconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_more_const1) int im_moreconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_moreeq_const1) int im_moreeqconst(VipsImage *in, VipsImage *out, double c); VIPS_DEPRECATED_FOR(vips_max) int im_maxpos_vec(VipsImage *im, int *xpos, int *ypos, double *maxima, int n); VIPS_DEPRECATED_FOR(vips_min) int im_minpos_vec(VipsImage *im, int *xpos, int *ypos, double *minima, int n); VIPS_DEPRECATED int im_maxpos_avg(VipsImage *im, double *xpos, double *ypos, double *out); VIPS_DEPRECATED int im_linreg(VipsImage **ins, VipsImage *out, double *xs); VIPS_DEPRECATED_FOR(vips_cross_phase) int im_cross_phase(VipsImage *a, VipsImage *b, VipsImage *out); VIPS_DEPRECATED int im_point(VipsImage *im, VipsInterpolate *interpolate, double x, double y, int band, double *out); VIPS_DEPRECATED int im_point_bilinear(VipsImage *im, double x, double y, int band, double *out); VIPS_DEPRECATED_FOR(vips_image_write) int im_copy(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_copy) int im_copy_set(VipsImage *in, VipsImage *out, VipsInterpretation interpretation, float xres, float yres, int xoffset, int yoffset); VIPS_DEPRECATED int im_copy_set_meta(VipsImage *in, VipsImage *out, const char *field, GValue *value); VIPS_DEPRECATED_FOR(vips_copy) int im_copy_morph(VipsImage *in, VipsImage *out, int bands, VipsBandFormat format, VipsCoding coding); VIPS_DEPRECATED_FOR(vips_byteswap) int im_copy_swap(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_copy_file) int im_copy_file(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_copy_native(VipsImage *in, VipsImage *out, gboolean is_msb_first); VIPS_DEPRECATED_FOR(vips_embed) int im_embed(VipsImage *in, VipsImage *out, int type, int x, int y, int width, int height); VIPS_DEPRECATED_FOR(vips_flip) int im_fliphor(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_flip) int im_flipver(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_insert) int im_insert(VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y); VIPS_DEPRECATED_FOR(vips_insert) int im_insert_noexpand(VipsImage *main, VipsImage *sub, VipsImage *out, int x, int y); VIPS_DEPRECATED_FOR(vips_join) int im_lrjoin(VipsImage *left, VipsImage *right, VipsImage *out); VIPS_DEPRECATED_FOR(vips_join) int im_tbjoin(VipsImage *top, VipsImage *bottom, VipsImage *out); VIPS_DEPRECATED_FOR(vips_extract_area) int im_extract_area(VipsImage *in, VipsImage *out, int left, int top, int width, int height); VIPS_DEPRECATED_FOR(vips_extract_band) int im_extract_band(VipsImage *in, VipsImage *out, int band); VIPS_DEPRECATED_FOR(vips_extract_band) int im_extract_bands(VipsImage *in, VipsImage *out, int band, int nbands); VIPS_DEPRECATED int im_extract_areabands(VipsImage *in, VipsImage *out, int left, int top, int width, int height, int band, int nbands); VIPS_DEPRECATED_FOR(vips_replicate) int im_replicate(VipsImage *in, VipsImage *out, int across, int down); VIPS_DEPRECATED_FOR(vips_wrap) int im_wrap(VipsImage *in, VipsImage *out, int x, int y); VIPS_DEPRECATED_FOR(vips_wrap) int im_rotquad(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_cast) int im_clip2fmt(VipsImage *in, VipsImage *out, VipsBandFormat fmt); VIPS_DEPRECATED_FOR(vips_bandjoin2) int im_bandjoin(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_bandjoin) int im_gbandjoin(VipsImage **in, VipsImage *out, int n); VIPS_DEPRECATED_FOR(vips_bandrank) int im_rank_image(VipsImage **in, VipsImage *out, int n, int index); VIPS_DEPRECATED_FOR(vips_bandrank) int im_maxvalue(VipsImage **in, VipsImage *out, int n); VIPS_DEPRECATED_FOR(vips_grid) int im_grid(VipsImage *in, VipsImage *out, int tile_height, int across, int down); VIPS_DEPRECATED_FOR(vips_scale) int im_scale(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_scale) int im_scaleps(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_msb) int im_msb(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_msb) int im_msb_band(VipsImage *in, VipsImage *out, int band); VIPS_DEPRECATED_FOR(vips_zoom) int im_zoom(VipsImage *in, VipsImage *out, int xfac, int yfac); VIPS_DEPRECATED_FOR(vips_subsample) int im_subsample(VipsImage *in, VipsImage *out, int xshrink, int yshrink); VIPS_DEPRECATED_FOR(vips_gaussnoise) int im_gaussnoise(VipsImage *out, int x, int y, double mean, double sigma); VIPS_DEPRECATED_FOR(vips_text) int im_text(VipsImage *out, const char *text, const char *font, int width, int alignment, int dpi); VIPS_DEPRECATED_FOR(vips_black) int im_black(VipsImage *out, int x, int y, int bands); VIPS_DEPRECATED_FOR(vips_xyz) int im_make_xy(VipsImage *out, const int xsize, const int ysize); VIPS_DEPRECATED_FOR(vips_zone) int im_zone(VipsImage *out, int size); VIPS_DEPRECATED_FOR(vips_zone) int im_fzone(VipsImage *out, int size); VIPS_DEPRECATED_FOR(vips_eye) int im_feye(VipsImage *out, const int xsize, const int ysize, const double factor); VIPS_DEPRECATED_FOR(vips_eye) int im_eye(VipsImage *out, const int xsize, const int ysize, const double factor); VIPS_DEPRECATED_FOR(vips_grey) int im_grey(VipsImage *out, const int xsize, const int ysize); VIPS_DEPRECATED_FOR(vips_grey) int im_fgrey(VipsImage *out, const int xsize, const int ysize); VIPS_DEPRECATED_FOR(vips_sines) int im_sines(VipsImage *out, int xsize, int ysize, double horfreq, double verfreq); VIPS_DEPRECATED_FOR(vips_buildlut) int im_buildlut(DOUBLEMASK *input, VipsImage *output); VIPS_DEPRECATED_FOR(vips_invertlut) int im_invertlut(DOUBLEMASK *input, VipsImage *output, int lut_size); VIPS_DEPRECATED_FOR(vips_identity) int im_identity(VipsImage *lut, int bands); VIPS_DEPRECATED_FOR(vips_identity) int im_identity_ushort(VipsImage *lut, int bands, int sz); VIPS_DEPRECATED_FOR(vips_tonelut) int im_tone_build_range(VipsImage *out, int in_max, int out_max, double Lb, double Lw, double Ps, double Pm, double Ph, double S, double M, double H); VIPS_DEPRECATED_FOR(vips_tonelut) int im_tone_build(VipsImage *out, double Lb, double Lw, double Ps, double Pm, double Ph, double S, double M, double H); VIPS_DEPRECATED_FOR(vips_system) int im_system(VipsImage *im, const char *cmd, char **out); VIPS_DEPRECATED_FOR(vips_system) VipsImage *im_system_image(VipsImage *im, const char *in_format, const char *out_format, const char *cmd_format, char **log); VIPS_DEPRECATED_FOR(vips_complex) int im_c2amph(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_complex) int im_c2rect(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_imag) int im_c2imag(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_real) int im_c2real(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_complexform) int im_ri2c(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_rot90) int im_rot90(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_rot180) int im_rot180(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_rot270) int im_rot270(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_ifthenelse) int im_ifthenelse(VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out); VIPS_DEPRECATED_FOR(vips_ifthenelse) int im_blend(VipsImage *c, VipsImage *a, VipsImage *b, VipsImage *out); VIPS_DEPRECATED DOUBLEMASK *im_vips2mask(VipsImage *in, const char *filename); VIPS_DEPRECATED INTMASK *im_vips2imask(IMAGE *in, const char *filename); VIPS_DEPRECATED int im_mask2vips(DOUBLEMASK *in, VipsImage *out); VIPS_DEPRECATED int im_imask2vips(INTMASK *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_bandmean) int im_bandmean(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_recomb) int im_recomb(VipsImage *in, VipsImage *out, DOUBLEMASK *recomb); VIPS_DEPRECATED int im_argb2rgba(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_falsecolour) int im_falsecolour(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_gamma) int im_gammacorrect(VipsImage *in, VipsImage *out, double exponent); VIPS_DEPRECATED_FOR(vips_tilecache) int im_tile_cache_random(IMAGE *in, IMAGE *out, int tile_width, int tile_height, int max_tiles); VIPS_DEPRECATED_FOR(vips_shrink) int im_shrink(VipsImage *in, VipsImage *out, double xshrink, double yshrink); VIPS_DEPRECATED_FOR(vips_affine) int im_affinei(VipsImage *in, VipsImage *out, VipsInterpolate *interpolate, double a, double b, double c, double d, double dx, double dy, int ox, int oy, int ow, int oh); VIPS_DEPRECATED_FOR(vips_affine) int im_affinei_all(VipsImage *in, VipsImage *out, VipsInterpolate *interpolate, double a, double b, double c, double d, double dx, double dy); VIPS_DEPRECATED_FOR(vips_shrink) int im_rightshift_size(VipsImage *in, VipsImage *out, int xshift, int yshift, int band_fmt); VIPS_DEPRECATED_FOR(vips_Lab2XYZ) int im_Lab2XYZ_temp(IMAGE *in, IMAGE *out, double X0, double Y0, double Z0); VIPS_DEPRECATED_FOR(vips_Lab2XYZ) int im_Lab2XYZ(IMAGE *in, IMAGE *out); VIPS_DEPRECATED_FOR(vips_XYZ2Lab) int im_XYZ2Lab(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_XYZ2Lab) int im_XYZ2Lab_temp(VipsImage *in, VipsImage *out, double X0, double Y0, double Z0); VIPS_DEPRECATED_FOR(vips_Lab2LCh) int im_Lab2LCh(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LCh2Lab) int im_LCh2Lab(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LCh2CMC) int im_LCh2UCS(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_CMC2LCh) int im_UCS2LCh(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_XYZ2Yxy) int im_XYZ2Yxy(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_Yxy2XYZ) int im_Yxy2XYZ(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_float2rad) int im_float2rad(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_rad2float) int im_rad2float(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_Lab2LabQ) int im_Lab2LabQ(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LabQ2Lab) int im_LabQ2Lab(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_Lab2LabS) int im_Lab2LabS(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LabS2Lab) int im_LabS2Lab(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LabQ2LabS) int im_LabQ2LabS(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LabS2LabQ) int im_LabS2LabQ(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_LabQ2sRGB) int im_LabQ2sRGB(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_XYZ2sRGB(IMAGE *in, IMAGE *out); VIPS_DEPRECATED int im_sRGB2XYZ(IMAGE *in, IMAGE *out); struct im_col_display; #define im_col_displays(S) (NULL) #define im_LabQ2disp_build_table(A, B) (NULL) #define im_LabQ2disp_table(A, B, C) (im_LabQ2disp(A, B, C)) VIPS_DEPRECATED int im_Lab2disp(IMAGE *in, IMAGE *out, struct im_col_display *disp); VIPS_DEPRECATED int im_disp2Lab(IMAGE *in, IMAGE *out, struct im_col_display *disp); VIPS_DEPRECATED int im_dE_fromdisp(IMAGE *, IMAGE *, IMAGE *, struct im_col_display *); VIPS_DEPRECATED int im_dECMC_fromdisp(IMAGE *, IMAGE *, IMAGE *, struct im_col_display *); #define im_disp2XYZ(A, B, C) (im_sRGB2XYZ(A, B)) #define im_XYZ2disp(A, B, C) (im_XYZ2sRGB(A, B)) #define im_LabQ2disp(A, B, C) (im_LabQ2sRGB(A, B)) VIPS_DEPRECATED_FOR(vips_icc_transform) int im_icc_transform(VipsImage *in, VipsImage *out, const char *input_profile_filename, const char *output_profile_filename, VipsIntent intent); #define im_icc_present vips_icc_present VIPS_DEPRECATED_FOR(vips_icc_import) int im_icc_import(VipsImage *in, VipsImage *out, const char *input_profile_filename, VipsIntent intent); VIPS_DEPRECATED_FOR(vips_icc_import) int im_icc_import_embedded(VipsImage *in, VipsImage *out, VipsIntent intent); VIPS_DEPRECATED_FOR(vips_icc_export) int im_icc_export_depth(VipsImage *in, VipsImage *out, int depth, const char *output_profile_filename, VipsIntent intent); VIPS_DEPRECATED_FOR(vips_icc_ac2rc) int im_icc_ac2rc(VipsImage *in, VipsImage *out, const char *profile_filename); VIPS_DEPRECATED int im_LabQ2XYZ(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_UCS2XYZ(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_UCS2Lab(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_Lab2UCS(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_XYZ2UCS(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_dE76) int im_dE_fromLab(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_dECMC) int im_dECMC_fromLab(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED int im_dE_fromXYZ(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_dE00) int im_dE00_fromLab(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED int im_lab_morph(VipsImage *in, VipsImage *out, DOUBLEMASK *mask, double L_offset, double L_scale, double a_scale, double b_scale); #define im_col_dE00 vips_col_dE00 VIPS_DEPRECATED_FOR(vips_quadratic) int im_quadratic(IMAGE *in, IMAGE *out, IMAGE *coeff); VIPS_DEPRECATED_FOR(vips_maplut) int im_maplut(VipsImage *in, VipsImage *out, VipsImage *lut); VIPS_DEPRECATED int im_hist(VipsImage *in, VipsImage *out, int bandno); VIPS_DEPRECATED_FOR(vips_hist_find) int im_histgr(VipsImage *in, VipsImage *out, int bandno); VIPS_DEPRECATED_FOR(vips_hist_cum) int im_histcum(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_hist_norm) int im_histnorm(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_histeq(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_hist_equal) int im_heq(VipsImage *in, VipsImage *out, int bandno); VIPS_DEPRECATED_FOR(vips_hist_find_ndim) int im_histnD(VipsImage *in, VipsImage *out, int bins); VIPS_DEPRECATED_FOR(vips_hist_find_indexed) int im_hist_indexed(VipsImage *index, VipsImage *value, VipsImage *out); VIPS_DEPRECATED_FOR(vips_hist_plot) int im_histplot(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_project) int im_project(VipsImage *in, VipsImage *hout, VipsImage *vout); VIPS_DEPRECATED_FOR(vips_profile) int im_profile(IMAGE *in, IMAGE *out, int dir); VIPS_DEPRECATED int im_hsp(VipsImage *in, VipsImage *ref, VipsImage *out); VIPS_DEPRECATED int im_histspec(VipsImage *in, VipsImage *ref, VipsImage *out); VIPS_DEPRECATED_FOR(vips_hist_local) int im_lhisteq(VipsImage *in, VipsImage *out, int xwin, int ywin); VIPS_DEPRECATED_FOR(vips_stdif) int im_stdif(VipsImage *in, VipsImage *out, double a, double m0, double b, double s0, int xwin, int ywin); VIPS_DEPRECATED_FOR(vips_percent) int im_mpercent(VipsImage *in, double percent, int *out); VIPS_DEPRECATED int im_mpercent_hist(VipsImage *hist, double percent, int *out); VIPS_DEPRECATED_FOR(vips_hist_ismonotonic) int im_ismonotonic(VipsImage *lut, int *out); VIPS_DEPRECATED int im_tone_analyse(VipsImage *in, VipsImage *out, double Ps, double Pm, double Ph, double S, double M, double H); VIPS_DEPRECATED int im_tone_map(VipsImage *in, VipsImage *out, VipsImage *lut); /* Not really correct, but who uses these. */ #define im_lhisteq_raw im_lhisteq #define im_stdif_raw im_stdif /* ruby-vips uses this */ #define vips_class_map_concrete_all vips_class_map_all VIPS_DEPRECATED_FOR(vips_morph) int im_dilate(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED_FOR(vips_morph) int im_erode(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED_FOR(vips_conva) int im_aconv(VipsImage *in, VipsImage *out, DOUBLEMASK *mask, int n_layers, int cluster); VIPS_DEPRECATED_FOR(vips_convi) int im_conv(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED_FOR(vips_convf) int im_conv_f(VipsImage *in, VipsImage *out, DOUBLEMASK *mask); VIPS_DEPRECATED_FOR(vips_convasep) int im_aconvsep(VipsImage *in, VipsImage *out, DOUBLEMASK *mask, int n_layers); VIPS_DEPRECATED_FOR(vips_convsep) int im_convsep(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED_FOR(vips_convsep) int im_convsep_f(VipsImage *in, VipsImage *out, DOUBLEMASK *mask); VIPS_DEPRECATED_FOR(vips_compass) int im_compass(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED_FOR(vips_compass) int im_gradient(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED_FOR(vips_compass) int im_lindetect(VipsImage *in, VipsImage *out, INTMASK *mask); VIPS_DEPRECATED int im_addgnoise(VipsImage *in, VipsImage *out, double sigma); VIPS_DEPRECATED int im_contrast_surface_raw(IMAGE *in, IMAGE *out, int half_win_size, int spacing); VIPS_DEPRECATED int im_contrast_surface(VipsImage *in, VipsImage *out, int half_win_size, int spacing); VIPS_DEPRECATED int im_grad_x(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_grad_y(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_fastcor) int im_fastcor(VipsImage *in, VipsImage *ref, VipsImage *out); VIPS_DEPRECATED_FOR(vips_spcor) int im_spcor(VipsImage *in, VipsImage *ref, VipsImage *out); VIPS_DEPRECATED int im_gradcor(VipsImage *in, VipsImage *ref, VipsImage *out); VIPS_DEPRECATED_FOR(vips_sharpen) int im_sharpen(VipsImage *in, VipsImage *out, int mask_size, double x1, double y2, double y3, double m1, double m2); typedef enum { IM_MASK_IDEAL_HIGHPASS = 0, IM_MASK_IDEAL_LOWPASS = 1, IM_MASK_BUTTERWORTH_HIGHPASS = 2, IM_MASK_BUTTERWORTH_LOWPASS = 3, IM_MASK_GAUSS_HIGHPASS = 4, IM_MASK_GAUSS_LOWPASS = 5, IM_MASK_IDEAL_RINGPASS = 6, IM_MASK_IDEAL_RINGREJECT = 7, IM_MASK_BUTTERWORTH_RINGPASS = 8, IM_MASK_BUTTERWORTH_RINGREJECT = 9, IM_MASK_GAUSS_RINGPASS = 10, IM_MASK_GAUSS_RINGREJECT = 11, IM_MASK_IDEAL_BANDPASS = 12, IM_MASK_IDEAL_BANDREJECT = 13, IM_MASK_BUTTERWORTH_BANDPASS = 14, IM_MASK_BUTTERWORTH_BANDREJECT = 15, IM_MASK_GAUSS_BANDPASS = 16, IM_MASK_GAUSS_BANDREJECT = 17, IM_MASK_FRACTAL_FLT = 18 } ImMaskType; /* We had them in the VIPS namespace for a while before deprecating them. */ #define VIPS_MASK_IDEAL_HIGHPASS IM_MASK_IDEAL_HIGHPASS #define VIPS_MASK_IDEAL_LOWPASS IM_MASK_IDEAL_LOWPASS #define VIPS_MASK_BUTTERWORTH_HIGHPASS IM_MASK_BUTTERWORTH_HIGHPASS #define VIPS_MASK_BUTTERWORTH_LOWPASS IM_MASK_BUTTERWORTH_LOWPASS #define VIPS_MASK_GAUSS_HIGHPASS IM_MASK_GAUSS_HIGHPASS #define VIPS_MASK_GAUSS_LOWPASS IM_MASK_GAUSS_LOWPASS #define VIPS_MASK_IDEAL_RINGPASS IM_MASK_IDEAL_RINGPASS #define VIPS_MASK_IDEAL_RINGREJECT IM_MASK_IDEAL_RINGREJECT #define VIPS_MASK_BUTTERWORTH_RINGPASS IM_MASK_BUTTERWORTH_RINGPASS #define VIPS_MASK_BUTTERWORTH_RINGREJECT IM_MASK_BUTTERWORTH_RINGREJECT #define VIPS_MASK_GAUSS_RINGPASS IM_MASK_GAUSS_RINGPASS #define VIPS_MASK_GAUSS_RINGREJECT IM_MASK_GAUSS_RINGREJECT #define VIPS_MASK_IDEAL_BANDPASS IM_MASK_IDEAL_BANDPASS #define VIPS_MASK_IDEAL_BANDREJECT IM_MASK_IDEAL_BANDREJECT #define VIPS_MASK_BUTTERWORTH_BANDPASS IM_MASK_BUTTERWORTH_BANDPASS #define VIPS_MASK_BUTTERWORTH_BANDREJECT IM_MASK_BUTTERWORTH_BANDREJECT #define VIPS_MASK_GAUSS_BANDPASS IM_MASK_GAUSS_BANDPASS #define VIPS_MASK_GAUSS_BANDREJECT IM_MASK_GAUSS_BANDREJECT #define VIPS_MASK_FRACTAL_FLT IM_MASK_FRACTAL_FLT #define VIPS_MASK IM_MASK VIPS_DEPRECATED int im_flt_image_freq(VipsImage *in, VipsImage *out, ImMaskType flag, ...); VIPS_DEPRECATED int im_create_fmask(VipsImage *out, int xsize, int ysize, ImMaskType flag, ...); VIPS_DEPRECATED_FOR(vips_fwfft) int im_fwfft(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_invfft) int im_invfft(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_invfft) int im_invfftr(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_freqmult) int im_freqflt(VipsImage *in, VipsImage *mask, VipsImage *out); VIPS_DEPRECATED_FOR(vips_spectrum) int im_disp_ps(VipsImage *in, VipsImage *out); VIPS_DEPRECATED_FOR(vips_fractsurf) int im_fractsurf(VipsImage *out, int size, double frd); VIPS_DEPRECATED_FOR(vips_phasecor) int im_phasecor_fft(VipsImage *in1, VipsImage *in2, VipsImage *out); VIPS_DEPRECATED_FOR(vips_countlines) int im_cntlines(VipsImage *im, double *nolines, int flag); VIPS_DEPRECATED_FOR(vips_labelregions) int im_label_regions(VipsImage *test, VipsImage *mask, int *segments); VIPS_DEPRECATED_FOR(vips_rank) int im_rank(VipsImage *in, VipsImage *out, int width, int height, int index); VIPS_DEPRECATED int im_zerox(VipsImage *in, VipsImage *out, int sign); VIPS_DEPRECATED int im_benchmarkn(VipsImage *in, VipsImage *out, int n); VIPS_DEPRECATED int im_benchmark2(VipsImage *in, double *out); VIPS_DEPRECATED_FOR(vips_draw_circle) int im_draw_circle(VipsImage *image, int x, int y, int radius, gboolean fill, VipsPel *ink); VIPS_DEPRECATED_FOR(vips_draw_mask) int im_draw_mask(VipsImage *image, VipsImage *mask_im, int x, int y, VipsPel *ink); VIPS_DEPRECATED_FOR(vips_draw_image) int im_draw_image(VipsImage *image, VipsImage *sub, int x, int y); VIPS_DEPRECATED_FOR(vips_draw_rect) int im_draw_rect(VipsImage *image, int left, int top, int width, int height, int fill, VipsPel *ink); typedef int (*VipsPlotFn)(VipsImage *image, int x, int y, void *a, void *b, void *c); VIPS_DEPRECATED_FOR(vips_draw_line) int im_draw_line_user(VipsImage *image, int x1, int y1, int x2, int y2, VipsPlotFn plot, void *a, void *b, void *c); VIPS_DEPRECATED_FOR(vips_draw_line) int im_draw_line(VipsImage *image, int x1, int y1, int x2, int y2, VipsPel *ink); VIPS_DEPRECATED int im_lineset(VipsImage *in, VipsImage *out, VipsImage *mask, VipsImage *ink, int n, int *x1v, int *y1v, int *x2v, int *y2v); VIPS_DEPRECATED int im_insertset(VipsImage *main, VipsImage *sub, VipsImage *out, int n, int *x, int *y); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_draw_flood(VipsImage *image, int x, int y, VipsPel *ink, VipsRect *dout); VIPS_DEPRECATED_FOR(vips_draw_flood) int im_draw_flood_blob(VipsImage *image, int x, int y, VipsPel *ink, VipsRect *dout); VIPS_DEPRECATED_FOR(vips_draw_flood1) int im_draw_flood_other(VipsImage *image, VipsImage *test, int x, int y, int serial, VipsRect *dout); VIPS_DEPRECATED_FOR(vips_draw_point) int im_draw_point(VipsImage *image, int x, int y, VipsPel *ink); VIPS_DEPRECATED_FOR(vips_getpoint) int im_read_point(VipsImage *image, int x, int y, VipsPel *ink); VIPS_DEPRECATED_FOR(vips_draw_smudge) int im_draw_smudge(VipsImage *image, int left, int top, int width, int height); VIPS_DEPRECATED void im_filename_split(const char *path, char *name, char *mode); VIPS_DEPRECATED_FOR(g_path_get_basename) const char *im_skip_dir(const char *filename); VIPS_DEPRECATED void im_filename_suffix(const char *path, char *suffix); VIPS_DEPRECATED int im_filename_suffix_match(const char *path, const char *suffixes[]); VIPS_DEPRECATED char *im_getnextoption(char **in); VIPS_DEPRECATED char *im_getsuboption(const char *buf); VIPS_DEPRECATED_FOR(vips_match) int im_match_linear(VipsImage *ref, VipsImage *sec, VipsImage *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2); VIPS_DEPRECATED_FOR(vips_match) int im_match_linear_search(VipsImage *ref, VipsImage *sec, VipsImage *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int hwindowsize, int hsearchsize); VIPS_DEPRECATED_FOR(vips_globalbalance) int im_global_balance(VipsImage *in, VipsImage *out, double gamma); VIPS_DEPRECATED_FOR(vips_globalbalance) int im_global_balancef(VipsImage *in, VipsImage *out, double gamma); VIPS_DEPRECATED_FOR(vips_remosaic) int im_remosaic(VipsImage *in, VipsImage *out, const char *old_str, const char *new_str); VIPS_DEPRECATED_FOR(vips_merge) int im_lrmerge(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth); VIPS_DEPRECATED_FOR(vips_mosaic1) int im_lrmerge1(VipsImage *ref, VipsImage *sec, VipsImage *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int mwidth); VIPS_DEPRECATED_FOR(vips_merge) int im_tbmerge(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth); VIPS_DEPRECATED_FOR(vips_mosaic1) int im_tbmerge1(VipsImage *ref, VipsImage *sec, VipsImage *out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int mwidth); VIPS_DEPRECATED_FOR(vips_mosaic) int im_lrmosaic(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int balancetype, int mwidth); VIPS_DEPRECATED_FOR(vips_mosaic1) int im_lrmosaic1(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int hwindowsize, int hsearchsize, int balancetype, int mwidth); VIPS_DEPRECATED_FOR(vips_mosaic) int im_tbmosaic(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int balancetype, int mwidth); VIPS_DEPRECATED_FOR(vips_mosaic1) int im_tbmosaic1(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int hwindowsize, int hsearchsize, int balancetype, int mwidth); VIPS_DEPRECATED int im_correl(VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y); VIPS_DEPRECATED int im_align_bands(VipsImage *in, VipsImage *out); VIPS_DEPRECATED int im_maxpos_subpel(VipsImage *in, double *x, double *y); VipsImage *vips__deprecated_open_read(const char *filename, gboolean sequential); VipsImage *vips__deprecated_open_write(const char *filename); void im__format_init(void); /* Low-level read/write operations. */ VIPS_DEPRECATED int im_jpeg2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_bufjpeg2vips(void *buf, size_t len, VipsImage *out, gboolean header_only); VIPS_DEPRECATED int im_vips2jpeg(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_vips2mimejpeg(VipsImage *in, int qfac); VIPS_DEPRECATED int im_vips2bufjpeg(VipsImage *in, VipsImage *out, int qfac, char **obuf, int *olen); VIPS_DEPRECATED int im_tiff2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2tiff(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_tile_cache(VipsImage *in, VipsImage *out, int tile_width, int tile_height, int max_tiles); VIPS_DEPRECATED int im_magick2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_bufmagick2vips(void *buf, size_t len, VipsImage *out, gboolean header_only); VIPS_DEPRECATED int im_exr2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_ppm2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2ppm(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_analyze2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_csv2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2csv(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_png2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2png(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_vips2bufpng(VipsImage *in, VipsImage *out, int compression, int interlace, char **obuf, size_t *olen); VIPS_DEPRECATED int im_webp2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2webp(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_raw2vips(const char *filename, VipsImage *out, int width, int height, int bpp, int offset); VIPS_DEPRECATED int im_vips2raw(VipsImage *in, int fd); VIPS_DEPRECATED int im_mat2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_rad2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2rad(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_fits2vips(const char *filename, VipsImage *out); VIPS_DEPRECATED int im_vips2fits(VipsImage *in, const char *filename); VIPS_DEPRECATED int im_vips2dz(VipsImage *in, const char *filename); int im__bandup(const char *domain, VipsImage *in, VipsImage *out, int n); int im__bandalike_vec(const char *domain, VipsImage **in, VipsImage **out, int n); int im__bandalike(const char *domain, VipsImage *in1, VipsImage *in2, VipsImage *out1, VipsImage *out2); int im__formatalike_vec(VipsImage **in, VipsImage **out, int n); int im__formatalike(VipsImage *in1, VipsImage *in2, VipsImage *out1, VipsImage *out2); int im__colour_unary(const char *domain, VipsImage *in, VipsImage *out, VipsInterpretation interpretation, im_wrapone_fn buffer_fn, void *a, void *b); VipsImage **im__insert_base(const char *domain, VipsImage *in1, VipsImage *in2, VipsImage *out); /* TODO(kleisauke): These are also defined in pmosaicing.h */ int vips__find_lroverlap(VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1); int vips__find_tboverlap(VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1); /* A colour temperature. */ typedef struct { double X0, Y0, Z0; } im_colour_temperature; VIPS_DEPRECATED void im_copy_dmask_matrix(DOUBLEMASK *mask, double **matrix); VIPS_DEPRECATED void im_copy_matrix_dmask(double **matrix, DOUBLEMASK *mask); VIPS_DEPRECATED int *im_ivector(int nl, int nh); VIPS_DEPRECATED float *im_fvector(int nl, int nh); VIPS_DEPRECATED double *im_dvector(int nl, int nh); VIPS_DEPRECATED void im_free_ivector(int *v, int nl, int nh); VIPS_DEPRECATED void im_free_fvector(float *v, int nl, int nh); VIPS_DEPRECATED void im_free_dvector(double *v, int nl, int nh); VIPS_DEPRECATED int **im_imat_alloc(int nrl, int nrh, int ncl, int nch); VIPS_DEPRECATED void im_free_imat(int **m, int nrl, int nrh, int ncl, int nch); VIPS_DEPRECATED float **im_fmat_alloc(int nrl, int nrh, int ncl, int nch); VIPS_DEPRECATED void im_free_fmat(float **m, int nrl, int nrh, int ncl, int nch); VIPS_DEPRECATED double **im_dmat_alloc(int nrl, int nrh, int ncl, int nch); VIPS_DEPRECATED void im_free_dmat(double **m, int nrl, int nrh, int ncl, int nch); VIPS_DEPRECATED int im_invmat(double **, int); VIPS_DEPRECATED int im_conv_f_raw(VipsImage *in, VipsImage *out, DOUBLEMASK *mask); VIPS_DEPRECATED int im_convsep_f_raw(VipsImage *in, VipsImage *out, DOUBLEMASK *mask); VIPS_DEPRECATED int im_greyc_mask(VipsImage *in, VipsImage *out, VipsImage *mask, int iterations, float amplitude, float sharpness, float anisotropy, float alpha, float sigma, float dl, float da, float gauss_prec, int interpolation, int fast_approx); VIPS_DEPRECATED int vips_check_imask(const char *domain, INTMASK *mask); VIPS_DEPRECATED int vips_check_dmask(const char *domain, DOUBLEMASK *mask); VIPS_DEPRECATED int vips_check_dmask_1d(const char *domain, DOUBLEMASK *mask); VIPS_DEPRECATED GOptionGroup *vips_get_option_group(void); /* old window manager API */ VIPS_DEPRECATED VipsWindow *vips_window_ref(VipsImage *im, int top, int height); VIPS_DEPRECATED FILE *vips_popenf(const char *fmt, const char *mode, ...) G_GNUC_PRINTF(1, 3); double *vips__ink_to_vector(const char *domain, VipsImage *im, VipsPel *ink, int *n); VipsPel *im__vector_to_ink(const char *domain, VipsImage *im, int n, double *vec); int vips__init(const char *argv0); size_t vips__get_sizeof_vipsobject(void); /* This is deprecated to make room for highway. */ #define VIPS_VECTOR_SOURCE_MAX (10) typedef struct { const char *name; char *unique_name; int n_temp; int n_scanline; int n_source; int n_destination; int n_constant; int n_parameter; int n_instruction; int sl[VIPS_VECTOR_SOURCE_MAX]; int line[VIPS_VECTOR_SOURCE_MAX]; int s[VIPS_VECTOR_SOURCE_MAX]; int d1; #ifdef HAVE_ORC OrcProgram *program; #endif /*HAVE_ORC*/ gboolean compiled; } VipsVector; typedef struct { #ifdef HAVE_ORC OrcExecutor executor; #endif /*HAVE_ORC*/ VipsVector *vector; } VipsExecutor; VIPS_DEPRECATED void vips_vector_init(void); VIPS_DEPRECATED void vips_vector_free(VipsVector *vector); VIPS_DEPRECATED VipsVector *vips_vector_new(const char *name, int dsize); VIPS_DEPRECATED void vips_vector_constant(VipsVector *vector, char *name, int value, int size); VIPS_DEPRECATED void vips_vector_source_scanline(VipsVector *vector, char *name, int line, int size); VIPS_DEPRECATED int vips_vector_source_name(VipsVector *vector, const char *name, int size); VIPS_DEPRECATED void vips_vector_temporary(VipsVector *vector, const char *name, int size); VIPS_DEPRECATED int vips_vector_parameter(VipsVector *vector, const char *name, int size); VIPS_DEPRECATED int vips_vector_destination(VipsVector *vector, const char *name, int size); VIPS_DEPRECATED void vips_vector_asm2(VipsVector *vector, const char *op, const char *a, const char *b); VIPS_DEPRECATED void vips_vector_asm3(VipsVector *vector, const char *op, const char *a, const char *b, const char *c); VIPS_DEPRECATED gboolean vips_vector_full(VipsVector *vector); VIPS_DEPRECATED gboolean vips_vector_compile(VipsVector *vector); VIPS_DEPRECATED void vips_vector_print(VipsVector *vector); VIPS_DEPRECATED void vips_executor_set_program(VipsExecutor *executor, VipsVector *vector, int n); VIPS_DEPRECATED void vips_executor_set_scanline(VipsExecutor *executor, VipsRegion *ir, int x, int y); VIPS_DEPRECATED void vips_executor_set_destination(VipsExecutor *executor, void *value); VIPS_DEPRECATED void vips_executor_set_parameter(VipsExecutor *executor, int var, int value); VIPS_DEPRECATED void vips_executor_set_array(VipsExecutor *executor, int var, void *value); VIPS_DEPRECATED void vips_executor_run(VipsExecutor *executor); VIPS_DEPRECATED void vips_vector_to_fixed_point(double *in, int *out, int n, int scale); /* This stuff is very, very old and should not be used by anyone now. */ #ifdef VIPS_ENABLE_ANCIENT #include #endif /*VIPS_ENABLE_ANCIENT*/ #include #include #include #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_VIPS7COMPAT_H*/ libvips-8.18.2/libvips/iofuncs/000077500000000000000000000000001516303661500164065ustar00rootroot00000000000000libvips-8.18.2/libvips/iofuncs/buf.c000066400000000000000000000355561516303661500173440ustar00rootroot00000000000000/* string buffers */ /* Copyright (C) 1991-2003 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include /** * VipsBuf: * * A message buffer you can append stuff to safely and quickly. If the message * gets too long, you get "..." and truncation. Message buffers can be on the * stack or heap. * * For example: * * ```c * char txt[256]; * VipsBuf buf = VIPS_BUF_STATIC(txt); * int i; * * vips_buf_appends(&buf, "Numbers are: "); * for (i = 0; i < array_length; i++) { * if (i > 0) * vips_buf_appends(&buf, ", "); * vips_buf_appendg(&buf, array[i]); * } * printf("%s", vips_buf_all(&buf)); * ``` */ /** * VIPS_BUF_STATIC: * @TEXT: the storage area to use * * Initialize a heap buffer. For example: * * ```c * char txt[256]; * VipsBuf buf = VIPS_BUF_STATIC(txt); * ``` */ /** * vips_buf_rewind: * @buf: the buffer * * Reset the buffer to the empty string. */ void vips_buf_rewind(VipsBuf *buf) { buf->i = 0; buf->lasti = 0; buf->full = FALSE; if (buf->base) buf->base[0] = '\0'; } /** * vips_buf_init: * @buf: the buffer * * Initialize a buffer. */ void vips_buf_init(VipsBuf *buf) { buf->base = NULL; buf->mx = 0; buf->dynamic = FALSE; vips_buf_rewind(buf); } /** * vips_buf_destroy: * @buf: the buffer * * Destroy a buffer. Only needed for heap buffers. Leaves the buffer in the * _init state. */ void vips_buf_destroy(VipsBuf *buf) { if (buf->dynamic) { VIPS_FREE(buf->base); } vips_buf_init(buf); } /** * vips_buf_set_static: * @buf: the buffer * @base: the start of the memory area to use for storage * @mx: the size of the storage area * * Attach the buffer to a static memory area. The buffer needs to have been * initialised. The memory area needs to be at least 4 bytes long. */ void vips_buf_set_static(VipsBuf *buf, char *base, int mx) { g_assert(mx >= 4); vips_buf_destroy(buf); buf->base = base; buf->mx = mx; buf->dynamic = FALSE; vips_buf_rewind(buf); } /** * vips_buf_init_static: * @buf: the buffer * @base: the start of the memory area to use for storage * @mx: the size of the storage area * * Initialise and attach to a static memory area. [func@BUF_STATIC] is usually * more convenient. * * For example: * * ```c * char txt[256]; * VipsBuf buf; * * vips_buf_init_static(&buf, txt, 256); * ``` * * Static buffers don't need to be freed when they go out of scope, but their * size must be set at compile-time. */ void vips_buf_init_static(VipsBuf *buf, char *base, int mx) { vips_buf_init(buf); vips_buf_set_static(buf, base, mx); } /** * vips_buf_set_dynamic: * @buf: the buffer * @mx: the size of the storage area * * Attach the buffer to a heap memory area. The buffer needs to have been * initialised. The memory area needs to be at least 4 bytes long. */ void vips_buf_set_dynamic(VipsBuf *buf, int mx) { g_assert(mx >= 4); if (buf->mx == mx && buf->dynamic) /* No change? */ vips_buf_rewind(buf); else { vips_buf_destroy(buf); if (!(buf->base = VIPS_ARRAY(NULL, mx, char))) /* No error return, so just block writes. */ buf->full = TRUE; else { buf->mx = mx; buf->dynamic = TRUE; vips_buf_rewind(buf); } } } /** * vips_buf_init_dynamic: * @buf: the buffer * @mx: the size of the storage area * * Initialise and attach to a heap memory area. * The memory area needs to be at least 4 bytes long. * * ```c * VipsBuf buf; * * vips_buf_init_dynamic(&buf, 256); * ``` * * Dynamic buffers must be freed with [method@Buf.destroy], but their size can * be set at runtime. */ void vips_buf_init_dynamic(VipsBuf *buf, int mx) { vips_buf_init(buf); vips_buf_set_dynamic(buf, mx); } /** * vips_buf_appendns: * @buf: the buffer * @str: the string to append to the buffer * @sz: the size of the string to append * * Append at most @sz chars from @str to @buf. @sz < 0 means unlimited. This * is the low-level append operation: functions like [method@Buf.appendf] build * on top of this. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appendns(VipsBuf *buf, const char *str, int sz) { int len; int n; int avail; int cpy; if (buf->full) return FALSE; if (!str) return TRUE; /* Amount we want to copy. */ len = strlen(str); if (sz >= 0) n = VIPS_MIN(sz, len); else n = len; /* Space available. */ avail = buf->mx - buf->i - 4; cpy = VIPS_MIN(n, avail); /* Can't use g_strlcpy() here, we don't want to drop the end of the * string. * * gcc10.3 (I think?) issues a false-positive warning about this. */ strncpy(buf->base + buf->i, str, cpy); buf->i += cpy; if (buf->i >= buf->mx - 4) { buf->full = TRUE; strcpy(buf->base + buf->mx - 4, "..."); buf->i = buf->mx - 1; return FALSE; } return TRUE; } /** * vips_buf_appends: * @buf: the buffer * @str: the string to append to the buffer * * Append the whole of @str to @buf. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appends(VipsBuf *buf, const char *str) { return vips_buf_appendns(buf, str, -1); } /** * vips_buf_appendc: * @buf: the buffer * @ch: the character to append to the buffer * * Append a single character @ch to @buf. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appendc(VipsBuf *buf, char ch) { char tiny[2]; tiny[0] = ch; tiny[1] = '\0'; return vips_buf_appendns(buf, tiny, 1); } /** * vips_buf_change: * @buf: the buffer * @o: the string to search for * @n: the string to substitute * * Swap the rightmost occurrence of @o for @n. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_change(VipsBuf *buf, const char *old, const char *new) { int olen = strlen(old); int nlen = strlen(new); int i; if (buf->full) return FALSE; if (buf->i - olen + nlen > buf->mx - 4) { buf->full = TRUE; return FALSE; } /* Find pos of old. */ for (i = buf->i - olen; i > 0; i--) if (vips_isprefix(old, buf->base + i)) break; g_assert(i >= 0); /* Move tail of buffer to make right-size space for new. */ memmove(buf->base + i + nlen, buf->base + i + olen, buf->i - i - olen); /* Copy new in. */ memcpy(buf->base + i, new, nlen); buf->i = i + nlen + (buf->i - i - olen); return TRUE; } /** * vips_buf_removec: * @buf: the buffer * @ch: the character to remove * * Remove the last character, if it's @ch. * * Returns: `TRUE` if a character was removed, `FALSE` otherwise. */ gboolean vips_buf_removec(VipsBuf *buf, char ch) { if (buf->i > 0 && buf->base[buf->i - 1] == ch) { buf->i -= 1; return TRUE; } else return FALSE; } /** * vips_buf_vappendf: * @buf: the buffer * @fmt: `printf()`-style format string * @ap: arguments to format string * * Append to @buf, args as [`vprintf()`](man:vprintf(3)). * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_vappendf(VipsBuf *buf, const char *fmt, va_list ap) { int avail; char *p; if (buf->full) return FALSE; // -3 to leave space for "..." // not -4, since the terminating \0 will already be on the string written // by g_vsnprintf() avail = buf->mx - buf->i - 3; p = buf->base + buf->i; (void) g_vsnprintf(p, avail, fmt, ap); buf->i += strlen(p); if (buf->i >= buf->mx - 4) { buf->full = TRUE; strcpy(buf->base + buf->mx - 4, "..."); buf->i = buf->mx - 1; return FALSE; } return TRUE; } /** * vips_buf_appendf: * @buf: the buffer * @fmt: `printf()`-style format string * @...: arguments to format string * * Format the string and append to @buf. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appendf(VipsBuf *buf, const char *fmt, ...) { va_list ap; gboolean result; va_start(ap, fmt); result = vips_buf_vappendf(buf, fmt, ap); va_end(ap); return result; } /** * vips_buf_appendg: * @buf: the buffer * @g: value to format and append * * Append a double, non-localised. Useful for config files etc. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appendg(VipsBuf *buf, double g) { char text[G_ASCII_DTOSTR_BUF_SIZE]; g_ascii_dtostr(text, sizeof(text), g); return vips_buf_appends(buf, text); } /** * vips_buf_appendd: * @buf: the buffer * @d: value to format and append * * Append a number. If the number is -ve, add brackets. Needed for * building function arguments. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appendd(VipsBuf *buf, int d) { if (d < 0) return vips_buf_appendf(buf, " (%d)", d); else return vips_buf_appendf(buf, " %d", d); } /** * vips_buf_appendgv: * @buf: the buffer * @value: [struct@GObject.Value] to format and append * * Format and append a [struct@GObject.Value] as a printable thing. * We display text like "3144 bytes of binary data" for BLOBs like icc-profile-data. * * Use [method@Image.get_as_string] to make a text representation of a field. * That will base64-encode blobs, for example. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_appendgv(VipsBuf *buf, GValue *value) { GType type = G_VALUE_TYPE(value); GType fundamental = g_type_fundamental(type); gboolean handled; gboolean result; result = FALSE; handled = FALSE; switch (fundamental) { case G_TYPE_STRING: { const char *str; /* These are GStrings (gchararray). vips refstrings are * handled by boxed, see below. */ str = g_value_get_string(value); result = vips_buf_appends(buf, str); handled = TRUE; } break; case G_TYPE_OBJECT: { GObject *object; object = g_value_get_object(value); if (VIPS_IS_OBJECT(object)) { vips_object_summary(VIPS_OBJECT(object), buf); result = TRUE; handled = TRUE; } } break; case G_TYPE_INT: result = vips_buf_appendf(buf, "%d", g_value_get_int(value)); handled = TRUE; break; case G_TYPE_UINT64: result = vips_buf_appendf(buf, "%" G_GINT64_FORMAT, g_value_get_uint64(value)); handled = TRUE; break; case G_TYPE_DOUBLE: result = vips_buf_appendf(buf, "%g", g_value_get_double(value)); handled = TRUE; break; case G_TYPE_BOOLEAN: result = vips_buf_appends(buf, g_value_get_boolean(value) ? "true" : "false"); handled = TRUE; break; case G_TYPE_ENUM: result = vips_buf_appends(buf, vips_enum_nick(type, g_value_get_enum(value))); handled = TRUE; break; case G_TYPE_FLAGS: { GFlagsClass *flags_class = g_type_class_ref(type); GFlagsValue *v; int flags; flags = g_value_get_flags(value); while (flags && (v = g_flags_get_first_value(flags_class, flags))) { result = vips_buf_appendf(buf, "%s ", v->value_nick); flags &= ~v->value; } handled = TRUE; } break; case G_TYPE_BOXED: if (type == VIPS_TYPE_REF_STRING) { const char *str; size_t str_len; /* These should be printable. */ str = vips_value_get_ref_string(value, &str_len); result = vips_buf_appends(buf, str); handled = TRUE; } else if (type == VIPS_TYPE_BLOB) { size_t str_len; /* Binary data and not printable. */ (void) vips_value_get_ref_string(value, &str_len); result = vips_buf_appendf(buf, _("%zd bytes of binary data"), str_len); handled = TRUE; } else if (type == VIPS_TYPE_ARRAY_DOUBLE) { double *arr; int n; int i; arr = vips_value_get_array_double(value, &n); for (i = 0; i < n; i++) result = vips_buf_appendf(buf, "%g ", arr[i]); handled = TRUE; } else if (type == VIPS_TYPE_ARRAY_INT) { int *arr; int n; int i; arr = vips_value_get_array_int(value, &n); for (i = 0; i < n; i++) result = vips_buf_appendf(buf, "%d ", arr[i]); handled = TRUE; } else if (type == VIPS_TYPE_ARRAY_IMAGE) { VipsImage **arr; int n; int i; arr = vips_value_get_array_image(value, &n); for (i = 0; i < n; i++) { vips_object_summary(VIPS_OBJECT(arr[i]), buf); result = vips_buf_appends(buf, " "); } handled = TRUE; } break; default: break; } if (!handled) { char *str_value; str_value = g_strdup_value_contents(value); result = vips_buf_appends(buf, str_value); g_free(str_value); } return result; } /** * vips_buf_append_size: * @buf: the buffer * @n: the number of bytes * * Turn a number of bytes into a sensible string ... eg "12", "12KB", "12MB", * "12GB" etc. * * Returns: `FALSE` on overflow, `TRUE` otherwise. */ gboolean vips_buf_append_size(VipsBuf *buf, size_t n) { const static char *names[] = { /* File length unit. */ N_("bytes"), /* Kilobyte unit. */ N_("KB"), /* Megabyte unit. */ N_("MB"), /* Gigabyte unit. */ N_("GB"), /* Terabyte unit. */ N_("TB") }; double sz = n; int i; /* -1, since we want to stop at TB, not run off the end. */ for (i = 0; sz > 1024 && i < VIPS_NUMBER(names) - 1; sz /= 1024, i++) ; if (i == 0) /* No decimal places for bytes. */ return vips_buf_appendf(buf, "%g %s", sz, _(names[i])); else return vips_buf_appendf(buf, "%.2f %s", sz, _(names[i])); } /** * vips_buf_all: * @buf: the buffer * * Return the contents of the buffer as a C string. * * Returns: the `NULL`-terminated contents of the buffer. This is a pointer to * the memory managed by the buffer and must not be freed. */ const char * vips_buf_all(VipsBuf *buf) { buf->base[buf->i] = '\0'; return buf->base; } /** * vips_buf_firstline: * @buf: the buffer * * Trim to just the first line (excluding "\n"). * * Returns: the `NULL`-terminated contents of the buffer. This is a pointer to * the memory managed by the buffer and must not be freed. */ const char * vips_buf_firstline(VipsBuf *buf) { char *p; if ((p = strchr(vips_buf_all(buf), '\n'))) *p = '\0'; return vips_buf_all(buf); } /** * vips_buf_is_empty: * @buf: the buffer * * Returns: `TRUE` if the buffer is empty. */ gboolean vips_buf_is_empty(VipsBuf *buf) { return buf->i == 0; } /** * vips_buf_is_full: * @buf: the buffer * * Returns: `TRUE` if the buffer is full. */ gboolean vips_buf_is_full(VipsBuf *buf) { return buf->full; } /** * vips_buf_len: * @buf: the buffer * * Returns: the number of characters currently in the buffer. */ int vips_buf_len(VipsBuf *buf) { return buf->i; } libvips-8.18.2/libvips/iofuncs/buffer.c000066400000000000000000000401401516303661500200220ustar00rootroot00000000000000/* Manage sets of pixel buffers on an image. * * 30/10/06 * - from window.c * 2/2/07 * - speed up the search, use our own lock (thanks Christian) * 5/2/07 * - split to many buffer lists per image * 11/2/07 * - split to a buffer hash per thread * - reuse buffer mallocs when we can * 20/2/07 * - add VipsBufferCacheList and we can avoid some hash ops on * done/undone * 5/3/10 * - move invalid stuff to region * - move link maintenance to im_demand_hint * 21/9/11 * - switch to vips_tracked_malloc() * 18/12/13 * - keep a few buffers in reserve per image, stops malloc/free * cycling when sharing is repeatedly discovered * 6/6/16 * - free buffers on image close as well as thread exit, so main thread * buffers don't clog up the system * 13/10/16 * - better solution: don't keep a buffercache for non-workers */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG_CREATE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef DEBUG /* Track all buffers here for debugging. */ static GSList *vips__buffer_all = NULL; #endif /*DEBUG*/ #ifdef DEBUG_CREATE static GSList *vips__buffer_cache_all = NULL; #endif /*DEBUG_CREATE*/ /* The maximum numbers of buffers we hold in reserve per image. */ static const int buffer_cache_max_reserve = 2; /* Workers have a BufferThread (and BufferCache) in a GPrivate they have * exclusive access to. */ static void buffer_thread_destroy_notify(gpointer data); static GPrivate buffer_thread_key = G_PRIVATE_INIT(buffer_thread_destroy_notify); void vips_buffer_print(VipsBuffer *buffer) { printf("VipsBuffer: %p ref_count = %d, ", buffer, buffer->ref_count); printf("im = %p, ", buffer->im); printf("area.left = %d, ", buffer->area.left); printf("area.top = %d, ", buffer->area.top); printf("area.width = %d, ", buffer->area.width); printf("area.height = %d, ", buffer->area.height); printf("done = %d, ", buffer->done); printf("cache = %p, ", buffer->cache); printf("buf = %p, ", buffer->buf); printf("bsize = %zd\n", buffer->bsize); } #ifdef DEBUG static void * vips_buffer_dump(VipsBuffer *buffer, size_t *reserve, size_t *alive) { vips_buffer_print(buffer); g_assert(buffer->im); g_assert(buffer->buf); if (!buffer->cache && !buffer->done) { /* Global buffer, not linked to any cache. */ printf("global buffer %p, %.3g MB\n", buffer, buffer->bsize / (1024 * 1024.0)); *alive += buffer->bsize; } else if (buffer->cache && buffer->done && !vips_rect_isempty(&buffer->area) && g_slist_find(buffer->cache->buffers, buffer)) { /* Published on a thread. */ printf("thread buffer %p, %.3g MB\n", buffer, buffer->bsize / (1024 * 1024.0)); *alive += buffer->bsize; } else if (buffer->ref_count == 0 && buffer->cache && !buffer->done && vips_rect_isempty(&buffer->area) && g_slist_find(buffer->cache->reserve, buffer)) /* Held in reserve. */ *reserve += buffer->bsize; else printf("buffer craziness!\n"); return NULL; } #endif /*DEBUG*/ #ifdef DEBUG_CREATE static void * vips_buffer_cache_dump(VipsBufferCache *cache, void *a, void *b) { printf("VipsBufferCache: %p\n", cache); printf("\t%d buffers\n", g_slist_length(cache->buffers)); printf("\tthread %p\n", cache->thread); printf("\timage %p\n", cache->im); printf("\tbuffer_thread %p\n", cache->buffer_thread); printf("\t%d in reserve\n", g_slist_length(cache->reserve)); return NULL; } #endif /*DEBUG_CREATE*/ void vips_buffer_dump_all(void) { #ifdef DEBUG if (vips__buffer_all) { size_t reserve; size_t alive; printf("buffers:\n"); reserve = 0; alive = 0; vips_slist_map2(vips__buffer_all, (VipsSListMap2Fn) vips_buffer_dump, &reserve, &alive); printf("%.3g MB alive\n", alive / (1024 * 1024.0)); printf("%.3g MB in reserve\n", reserve / (1024 * 1024.0)); } #ifdef DEBUG_CREATE if (vips__buffer_cache_all) { printf("buffers: %d buffer cache still alive\n", g_slist_length(vips__buffer_cache_all)); vips_slist_map2(vips__buffer_cache_all, (VipsSListMap2Fn) vips_buffer_cache_dump, NULL, NULL); printf("g_thread_self() == %p\n", g_thread_self()); } #endif /*DEBUG_CREATE*/ #endif /*DEBUG*/ } static void vips_buffer_free(VipsBuffer *buffer) { VIPS_FREEF(vips_tracked_aligned_free, buffer->buf); buffer->bsize = 0; g_free(buffer); #ifdef DEBUG g_mutex_lock(&vips__global_lock); g_assert(g_slist_find(vips__buffer_all, buffer)); vips__buffer_all = g_slist_remove(vips__buffer_all, buffer); g_mutex_unlock(&vips__global_lock); #endif /*DEBUG*/ #ifdef DEBUG_VERBOSE printf("vips_buffer_free: freeing buffer %p\n", buffer); #endif /*DEBUG_VERBOSE*/ } static void buffer_thread_free(VipsBufferThread *buffer_thread) { VIPS_FREEF(g_hash_table_destroy, buffer_thread->hash); VIPS_FREE(buffer_thread); } /* Run for GDestroyNotify on the VipsBufferThread hash. */ static void buffer_cache_free(VipsBufferCache *cache) { GSList *p; #ifdef DEBUG_CREATE g_mutex_lock(&vips__global_lock); vips__buffer_cache_all = g_slist_remove(vips__buffer_cache_all, cache); g_mutex_unlock(&vips__global_lock); printf("buffer_cache_free: freeing cache %p on thread %p\n", cache, g_thread_self()); printf("\t(%d caches left)\n", g_slist_length(vips__buffer_cache_all)); #endif /*DEBUG_CREATE*/ /* Need to mark undone so we don't try and take them off this cache on * unref. */ for (p = cache->buffers; p; p = p->next) { VipsBuffer *buffer = (VipsBuffer *) p->data; g_assert(buffer->done); g_assert(buffer->cache == cache); buffer->done = FALSE; buffer->cache = NULL; } VIPS_FREEF(g_slist_free, cache->buffers); for (p = cache->reserve; p; p = p->next) { VipsBuffer *buffer = (VipsBuffer *) p->data; vips_buffer_free(buffer); } VIPS_FREEF(g_slist_free, cache->reserve); g_free(cache); } static VipsBufferCache * buffer_cache_new(VipsBufferThread *buffer_thread, VipsImage *im) { VipsBufferCache *cache; cache = g_new(VipsBufferCache, 1); cache->buffers = NULL; cache->thread = g_thread_self(); cache->im = im; cache->buffer_thread = buffer_thread; cache->reserve = NULL; cache->n_reserve = 0; #ifdef DEBUG_CREATE g_mutex_lock(&vips__global_lock); vips__buffer_cache_all = g_slist_prepend(vips__buffer_cache_all, cache); g_mutex_unlock(&vips__global_lock); printf("buffer_cache_new: new cache %p for thread %p on image %p\n", cache, g_thread_self(), im); printf("\t(%d caches now)\n", g_slist_length(vips__buffer_cache_all)); #endif /*DEBUG_CREATE*/ return cache; } static VipsBufferThread * buffer_thread_new(void) { VipsBufferThread *buffer_thread; buffer_thread = g_new(VipsBufferThread, 1); buffer_thread->hash = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) buffer_cache_free); buffer_thread->thread = g_thread_self(); return buffer_thread; } /* Get our private VipsBufferThread. NULL for non-worker threads. */ static VipsBufferThread * buffer_thread_get(void) { VipsBufferThread *buffer_thread; if (vips_thread_isvips()) { /* Our threads get a set of private buffers, since we know we * will be calling vips_thread_shutdown() on thread * termination. */ if (!(buffer_thread = g_private_get(&buffer_thread_key))) { buffer_thread = buffer_thread_new(); g_private_set(&buffer_thread_key, buffer_thread); } g_assert(buffer_thread->thread == g_thread_self()); } else /* Non-vips threads don't have one. */ buffer_thread = NULL; return buffer_thread; } /* Get the VipsBufferCache for this image, or NULL for a non-worker. */ static VipsBufferCache * buffer_cache_get(VipsImage *im) { VipsBufferThread *buffer_thread; VipsBufferCache *cache; if ((buffer_thread = buffer_thread_get())) { if (!(cache = (VipsBufferCache *) g_hash_table_lookup(buffer_thread->hash, im))) { cache = buffer_cache_new(buffer_thread, im); g_hash_table_insert(buffer_thread->hash, im, cache); } g_assert(cache->thread == g_thread_self()); } else cache = NULL; return cache; } /* Pixels have been calculated: publish for other parts of this thread to see. */ void vips_buffer_done(VipsBuffer *buffer) { VipsImage *im = buffer->im; VipsBufferCache *cache; if (!buffer->done && (cache = buffer_cache_get(im))) { g_assert(!g_slist_find(cache->buffers, buffer)); g_assert(!buffer->cache); buffer->done = TRUE; buffer->cache = cache; cache->buffers = g_slist_prepend(cache->buffers, buffer); #ifdef DEBUG_VERBOSE printf("vips_buffer_done: thread %p adding buffer %p to cache %p\n", g_thread_self(), buffer, cache); vips_buffer_print(buffer); #endif /*DEBUG_VERBOSE*/ } } /* Take off the public 'done' list. Make sure it has no calculated pixels in. */ void vips_buffer_undone(VipsBuffer *buffer) { if (buffer->done) { VipsBufferCache *cache = buffer->cache; #ifdef DEBUG_VERBOSE printf("vips_buffer_undone: thread %p removing " "buffer %p from cache %p\n", g_thread_self(), buffer, cache); #endif /*DEBUG_VERBOSE*/ g_assert(cache->thread == g_thread_self()); g_assert(cache->buffer_thread->thread == cache->thread); g_assert(g_slist_find(cache->buffers, buffer)); g_assert(buffer_thread_get()); g_assert(cache->buffer_thread == buffer_thread_get()); cache->buffers = g_slist_remove(cache->buffers, buffer); buffer->done = FALSE; #ifdef DEBUG_VERBOSE printf("vips_buffer_undone: %d buffers left\n", g_slist_length(cache->buffers)); #endif /*DEBUG_VERBOSE*/ } buffer->cache = NULL; buffer->area.width = 0; buffer->area.height = 0; } void vips_buffer_unref(VipsBuffer *buffer) { #ifdef DEBUG_VERBOSE printf("** vips_buffer_unref: left = %d, top = %d, " "width = %d, height = %d (%p)\n", buffer->area.left, buffer->area.top, buffer->area.width, buffer->area.height, buffer); #endif /*DEBUG_VERBOSE*/ g_assert(buffer->ref_count > 0); buffer->ref_count -= 1; if (buffer->ref_count == 0) { VipsBufferCache *cache; #ifdef DEBUG_VERBOSE if (!buffer->done) printf("vips_buffer_unref: buffer was not done\n"); #endif /*DEBUG_VERBOSE*/ vips_buffer_undone(buffer); /* Place on this thread's reserve list for reuse. */ if ((cache = buffer_cache_get(buffer->im)) && cache->n_reserve < buffer_cache_max_reserve) { g_assert(!buffer->cache); cache->reserve = g_slist_prepend(cache->reserve, buffer); cache->n_reserve += 1; buffer->cache = cache; buffer->area.width = 0; buffer->area.height = 0; } else vips_buffer_free(buffer); } } static int buffer_move(VipsBuffer *buffer, VipsRect *area) { VipsImage *im = buffer->im; size_t new_bsize; size_t align; g_assert(buffer->ref_count == 1); vips_buffer_undone(buffer); g_assert(!buffer->done); buffer->area = *area; new_bsize = (size_t) VIPS_IMAGE_SIZEOF_PEL(im) * area->width * area->height; /* Need to pad buffer size to be aligned-up to * 64 bytes for the highway paths. */ #ifdef HAVE_HWY if (im->BandFmt == VIPS_FORMAT_UCHAR) { new_bsize += /*HWY_ALIGNMENT*/ 64 - 1; align = /*HWY_ALIGNMENT*/ 64; } else #endif /*HAVE_HWY*/ align = 16; if (buffer->bsize < new_bsize || !buffer->buf) { buffer->bsize = new_bsize; VIPS_FREEF(vips_tracked_aligned_free, buffer->buf); if (!(buffer->buf = vips_tracked_aligned_alloc(buffer->bsize, align))) return -1; } return 0; } /* Make a new buffer. */ VipsBuffer * vips_buffer_new(VipsImage *im, VipsRect *area) { VipsBufferCache *cache; VipsBuffer *buffer; if ((cache = buffer_cache_get(im)) && cache->reserve) { buffer = (VipsBuffer *) cache->reserve->data; cache->reserve = g_slist_remove(cache->reserve, buffer); cache->n_reserve -= 1; g_assert(buffer->im == im); g_assert(buffer->done == FALSE); g_assert(buffer->cache); buffer->ref_count = 1; buffer->done = FALSE; buffer->cache = NULL; } else { buffer = g_new0(VipsBuffer, 1); buffer->ref_count = 1; buffer->im = im; buffer->done = FALSE; buffer->cache = NULL; buffer->buf = NULL; buffer->bsize = 0; #ifdef DEBUG g_mutex_lock(&vips__global_lock); vips__buffer_all = g_slist_prepend(vips__buffer_all, buffer); g_mutex_unlock(&vips__global_lock); #endif /*DEBUG*/ } if (buffer_move(buffer, area)) { vips_buffer_free(buffer); return NULL; } return buffer; } /* Find an existing buffer that encloses area and return a ref. Or NULL for no * existing buffer. */ static VipsBuffer * buffer_find(VipsImage *im, VipsRect *r) { VipsBufferCache *cache; VipsBuffer *buffer; GSList *p; VipsRect *area; if (!(cache = buffer_cache_get(im))) return NULL; /* This needs to be quick :-( don't use * vips_slist_map2()/vips_rect_includesrect(), do the search * inline. * * FIXME we return the first enclosing buffer, perhaps we should * search for the largest? */ for (p = cache->buffers; p; p = p->next) { buffer = (VipsBuffer *) p->data; area = &buffer->area; if (area->left <= r->left && area->top <= r->top && area->left + area->width >= r->left + r->width && area->top + area->height >= r->top + r->height) { buffer->ref_count += 1; #ifdef DEBUG_VERBOSE printf("buffer_find: left = %d, top = %d, " "width = %d, height = %d, count = %d (%p)\n", buffer->area.left, buffer->area.top, buffer->area.width, buffer->area.height, buffer->ref_count, buffer); #endif /*DEBUG_VERBOSE*/ return buffer; } } return NULL; } /* Return a ref to a buffer that encloses area. The buffer we return might be * done. */ VipsBuffer * vips_buffer_ref(VipsImage *im, VipsRect *area) { VipsBuffer *buffer; if ((buffer = buffer_find(im, area))) return buffer; else return vips_buffer_new(im, area); } /* Unref old, ref new, in a single operation. Reuse stuff if we can. The * buffer we return might or might not be done. */ VipsBuffer * vips_buffer_unref_ref(VipsBuffer *old_buffer, VipsImage *im, VipsRect *area) { VipsBuffer *buffer; g_assert(!old_buffer || old_buffer->im == im); /* Is the current buffer OK? */ if (old_buffer && vips_rect_includesrect(&old_buffer->area, area)) return old_buffer; /* Does the new area already have a buffer? */ if ((buffer = buffer_find(im, area))) { VIPS_FREEF(vips_buffer_unref, old_buffer); return buffer; } /* Is the current buffer unshared? We can just move it. */ if (old_buffer && old_buffer->ref_count == 1) { if (buffer_move(old_buffer, area)) { vips_buffer_unref(old_buffer); return NULL; } return old_buffer; } /* Fallback ... unref the old one, make a new one. */ VIPS_FREEF(vips_buffer_unref, old_buffer); if (!(buffer = vips_buffer_new(im, area))) return NULL; return buffer; } static void buffer_thread_destroy_notify(gpointer data) { /* We only come here if vips_thread_shutdown() was not called for this * thread. Do our best to clean up. * * GPrivate has stopped working by this point in destruction, be * careful not to touch that. */ buffer_thread_free(data); } /* Init the buffer cache system. This is called during vips_init. */ void vips__buffer_init(void) { if (buffer_cache_max_reserve < 1) printf("vips__buffer_init: buffer reserve disabled\n"); #ifdef DEBUG printf("vips__buffer_init: DEBUG enabled\n"); #endif /*DEBUG*/ #ifdef DEBUG_CREATE printf("vips__buffer_init: DEBUG_CREATE enabled\n"); #endif /*DEBUG_CREATE*/ } void vips__buffer_shutdown(void) { VipsBufferThread *buffer_thread; if ((buffer_thread = g_private_get(&buffer_thread_key))) { buffer_thread_free(buffer_thread); g_private_set(&buffer_thread_key, NULL); } } libvips-8.18.2/libvips/iofuncs/cache.c000066400000000000000000000766501516303661500176330ustar00rootroot00000000000000/* cache vips operations * * 20/6/12 * - try to make it compile on centos5 * 7/7/12 * - add a lock so we can run operations from many threads * 28/11/19 [MaxKellermann] * - make invalidate advisory rather than immediate */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* TODO what about delayed writes ... do we ever write in close? we shouldn't, should do in evalend or written or somesuch use g_param_values_cmp() instead of value_equal()? */ /* #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include /* Set by GOption from the command line, eg. "12m". */ gboolean vips__cache_dump = FALSE; gboolean vips__cache_trace = FALSE; /* Max number of cached operations. * * It was 10,000, but this was too high for batch-style applications with * little reuse. */ static int vips_cache_max = 100; /* How many tracked open files we allow before we start dropping cache. */ static int vips_cache_max_files = 100; /* How much RAM we spend on caches before we start dropping cached operations * ... default 100mb. * * It was 1gb, but that's a lot of memory for things like vipsthumbnail where * there will be (almost) no reuse. Default low and let apps raise it if it'd * be useful. */ static size_t vips_cache_max_mem = 100 * 1024 * 1024; /* Hold a ref to all "recent" operations. */ static GHashTable *vips_cache_table = NULL; /* A 'time' counter: increment on all cache ops. Use this to detect LRU. */ static int vips_cache_time = 0; /* Protect cache access with this. */ static GMutex vips_cache_lock; /* A cache entry. */ typedef struct _VipsOperationCacheEntry { VipsOperation *operation; /* When we added this operation to cache .. used to find LRU for * flush. */ int time; /* We listen for "invalidate" from the operation. Track the id here so * we can disconnect when we drop an operation. */ gulong invalidate_id; /* Set if someone thinks this cache entry should be dropped. */ gboolean invalid; } VipsOperationCacheEntry; /* Pass in the pspec so we can get the generic type. For example, a * held in a GParamSpec allowing OBJECT, but the value could be of type * VipsImage. generics are much faster to compare. */ static unsigned int vips_value_hash(GParamSpec *pspec, const GValue *value) { GType generic = G_PARAM_SPEC_TYPE(pspec); /* Not compile-time constants, so we have to use a set of if()s. Could * make a table at run time I guess. */ if (generic == G_TYPE_PARAM_BOOLEAN) return (unsigned int) g_value_get_boolean(value); else if (generic == G_TYPE_PARAM_CHAR) return (unsigned int) g_value_get_schar(value); else if (generic == G_TYPE_PARAM_UCHAR) return (unsigned int) g_value_get_uchar(value); else if (generic == G_TYPE_PARAM_INT) return (unsigned int) g_value_get_int(value); else if (generic == G_TYPE_PARAM_UINT) return (unsigned int) g_value_get_uint(value); else if (generic == G_TYPE_PARAM_LONG) return (unsigned int) g_value_get_long(value); else if (generic == G_TYPE_PARAM_ULONG) return (unsigned int) g_value_get_ulong(value); else if (generic == G_TYPE_PARAM_ENUM) return (unsigned int) g_value_get_enum(value); else if (generic == G_TYPE_PARAM_FLAGS) return (unsigned int) g_value_get_flags(value); else if (generic == G_TYPE_PARAM_UINT64) { guint64 i = g_value_get_uint64(value); return g_int64_hash((gint64 *) &i); } else if (generic == G_TYPE_PARAM_INT64) { gint64 i = g_value_get_int64(value); return g_int64_hash(&i); } else if (generic == G_TYPE_PARAM_FLOAT) { float f = g_value_get_float(value); return g_direct_hash((void *) &f); } else if (generic == G_TYPE_PARAM_DOUBLE) { double d = g_value_get_double(value); return g_double_hash(&d); } else if (generic == G_TYPE_PARAM_STRING) { const char *s = g_value_get_string(value); return s ? g_str_hash(s) : 0; } else if (generic == G_TYPE_PARAM_BOXED) { void *p = g_value_get_boxed(value); // array_object is an internal type, don't have a case for this if (!p) return 0; else if (G_VALUE_TYPE(value) == VIPS_TYPE_ARRAY_INT) { int n; int *array = (int *) vips_area_get_data(VIPS_AREA(p), NULL, &n, NULL, NULL); guint hash = 0; for (int i = 0; i < n; i++) hash = (hash << 1) ^ g_int_hash(&array[i]); return hash; } else if (G_VALUE_TYPE(value) == VIPS_TYPE_ARRAY_DOUBLE) { int n; double *array = (double *) vips_area_get_data(VIPS_AREA(p), NULL, &n, NULL, NULL); guint hash = 0; for (int i = 0; i < n; i++) hash = (hash << 1) ^ g_double_hash(&array[i]); return hash; } else if (G_VALUE_TYPE(value) == VIPS_TYPE_ARRAY_IMAGE) { int n; void **array = (void **) vips_area_get_data(VIPS_AREA(p), NULL, &n, NULL, NULL); guint hash = 0; for (int i = 0; i < n; i++) hash = (hash << 1) ^ g_direct_hash(array[i]); return hash; } else return g_direct_hash(p); } else if (generic == G_TYPE_PARAM_POINTER) { void *p = g_value_get_pointer(value); return p ? g_direct_hash(p) : 0; } else if (generic == G_TYPE_PARAM_OBJECT) { void *p = g_value_get_object(value); return p ? g_direct_hash(p) : 0; } else { /* Fallback: convert to a string and hash that. * This is very slow, print a warning if we use it * so we can add another case. */ char *s; unsigned int hash; s = g_strdup_value_contents(value); hash = g_str_hash(s); printf("vips_value_hash: no case for %s\n", s); printf("\ttype %d, %s\n", (int) G_VALUE_TYPE(value), g_type_name(G_VALUE_TYPE(value))); printf("\tgeneric %d, %s\n", (int) G_VALUE_TYPE(generic), g_type_name(generic)); g_free(s); return hash; } } /* Pass in the pspec so we can get the generic type. For example, a * value could be held in a GParamSpec allowing OBJECT, but the value * could be of type VipsImage. generics are much faster to compare. */ static gboolean vips_value_equal(GParamSpec *pspec, const GValue *v1, const GValue *v2) { GType generic = G_PARAM_SPEC_TYPE(pspec); GType t1 = G_VALUE_TYPE(v1); GType t2 = G_VALUE_TYPE(v2); if (t1 != t2) return FALSE; /* Not compile-time constants, so we have to use a set of if()s. Could * make a table at run time I guess. */ if (generic == G_TYPE_PARAM_BOOLEAN) return g_value_get_boolean(v1) == g_value_get_boolean(v2); else if (generic == G_TYPE_PARAM_CHAR) return g_value_get_schar(v1) == g_value_get_schar(v2); if (generic == G_TYPE_PARAM_UCHAR) return g_value_get_uchar(v1) == g_value_get_uchar(v2); if (generic == G_TYPE_PARAM_INT) return g_value_get_int(v1) == g_value_get_int(v2); if (generic == G_TYPE_PARAM_UINT) return g_value_get_uint(v1) == g_value_get_uint(v2); if (generic == G_TYPE_PARAM_LONG) return g_value_get_long(v1) == g_value_get_long(v2); if (generic == G_TYPE_PARAM_ULONG) return g_value_get_ulong(v1) == g_value_get_ulong(v2); if (generic == G_TYPE_PARAM_ENUM) return g_value_get_enum(v1) == g_value_get_enum(v2); if (generic == G_TYPE_PARAM_FLAGS) return g_value_get_flags(v1) == g_value_get_flags(v2); if (generic == G_TYPE_PARAM_UINT64) return g_value_get_uint64(v1) == g_value_get_uint64(v2); if (generic == G_TYPE_PARAM_INT64) return g_value_get_int64(v1) == g_value_get_int64(v2); if (generic == G_TYPE_PARAM_FLOAT) return g_value_get_float(v1) == g_value_get_float(v2); if (generic == G_TYPE_PARAM_DOUBLE) return g_value_get_double(v1) == g_value_get_double(v2); if (generic == G_TYPE_PARAM_STRING) { const char *s1 = g_value_get_string(v1); const char *s2 = g_value_get_string(v2); if (s1 == s2) return TRUE; else return s1 && s2 && strcmp(s1, s2) == 0; } if (generic == G_TYPE_PARAM_BOXED) { void *p1 = g_value_get_boxed(v1); void *p2 = g_value_get_boxed(v2); if (p1 == p2) return TRUE; else if (!p1 || !p2) return FALSE; else if (t1 == VIPS_TYPE_ARRAY_INT) { int n1; int *array1 = (int *) vips_area_get_data(VIPS_AREA(p1), NULL, &n1, NULL, NULL); int n2; int *array2 = (int *) vips_area_get_data(VIPS_AREA(p2), NULL, &n2, NULL, NULL); if (n1 != n2) return FALSE; else if (array1 == array2) return TRUE; else { for (int i = 0; i < n1; i++) if (array1[i] != array2[i]) return FALSE; return TRUE; } } else if (t1 == VIPS_TYPE_ARRAY_DOUBLE) { int n1; double *array1 = (double *) vips_area_get_data(VIPS_AREA(p1), NULL, &n1, NULL, NULL); int n2; double *array2 = (double *) vips_area_get_data(VIPS_AREA(p2), NULL, &n2, NULL, NULL); if (n1 != n2) return FALSE; else if (array1 == array2) return TRUE; else { for (int i = 0; i < n1; i++) if (array1[i] != array2[i]) return FALSE; return TRUE; } } else if (t1 == VIPS_TYPE_ARRAY_IMAGE) { int n1; void **array1 = (void **) vips_area_get_data(VIPS_AREA(p1), NULL, &n1, NULL, NULL); int n2; void **array2 = (void **) vips_area_get_data(VIPS_AREA(p2), NULL, &n2, NULL, NULL); if (n1 != n2) return FALSE; else if (array1 == array2) return TRUE; else { for (int i = 0; i < n1; i++) if (array1[i] != array2[i]) return FALSE; return TRUE; } } else return p1 == p2; } if (generic == G_TYPE_PARAM_POINTER) return g_value_get_pointer(v1) == g_value_get_pointer(v2); if (generic == G_TYPE_PARAM_OBJECT) return g_value_get_object(v1) == g_value_get_object(v2); else { /* Fallback: convert to a string and compare that. * This is very slow, print a warning if we use it * so we can add another case. */ char *s1; char *s2; gboolean equal; s1 = g_strdup_value_contents(v1); s2 = g_strdup_value_contents(v2); equal = strcmp(s1, s2) == 0; printf("vips_value_equal: no case for %s, %s\n", s1, s2); printf("\tt1 %d, %s\n", (int) t1, g_type_name(t1)); printf("\tt2 %d, %s\n", (int) t2, g_type_name(t2)); printf("\tgeneric %d, %s\n", (int) G_VALUE_TYPE(generic), g_type_name(generic)); g_free(s1); g_free(s2); return equal; } } static void * vips_object_hash_arg(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { unsigned int *hash = (unsigned int *) a; if ((argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && !(argument_class->flags & VIPS_ARGUMENT_NON_HASHABLE) && argument_instance->assigned) { const char *name = g_param_spec_get_name(pspec); GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); GValue value = G_VALUE_INIT; g_value_init(&value, type); g_object_get_property(G_OBJECT(object), name, &value); *hash = (*hash << 1) ^ vips_value_hash(pspec, &value); g_value_unset(&value); } return NULL; } /* Find a hash from the input arguments to a VipsOperation. */ unsigned int vips_operation_hash(VipsOperation *operation) { guint hash; if (operation->found_hash) hash = operation->hash; else { /* Include the operation type in the hash. */ hash = (guint) G_OBJECT_TYPE(operation); (void) vips_argument_map(VIPS_OBJECT(operation), vips_object_hash_arg, &hash, NULL); /* Make sure we can't have a zero hash value. */ hash |= 1; /* The hash can change up to the moment of construction. After that, * it should be fixed. */ if (VIPS_OBJECT(operation)->constructed) { operation->hash = hash; operation->found_hash = TRUE; } } return hash; } static void * vips_object_equal_arg(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsObject *other = (VipsObject *) a; const char *name = g_param_spec_get_name(pspec); GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); GValue v1 = G_VALUE_INIT; GValue v2 = G_VALUE_INIT; gboolean equal; /* Only test assigned input constructor args. Avoid the nohash args as * well. */ if (!(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) || !(argument_class->flags & VIPS_ARGUMENT_INPUT) || (argument_class->flags & VIPS_ARGUMENT_NON_HASHABLE) || !argument_instance->assigned) return NULL; /* If this is an optional arg, we need to check that this was * assigned on @other as well. */ if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED) && !vips_object_argument_isset(other, name)) /* Optional and was not set on other ... we've found a * difference! */ return (void *) name; g_value_init(&v1, type); g_value_init(&v2, type); g_object_get_property(G_OBJECT(object), name, &v1); g_object_get_property(G_OBJECT(other), name, &v2); equal = vips_value_equal(pspec, &v1, &v2); g_value_unset(&v1); g_value_unset(&v2); /* Stop (return non-NULL) if we've found a difference. */ return !equal ? (void *) name : NULL; } /* Are two objects equal, ie. have the same inputs. */ static gboolean vips_operation_equal(VipsOperation *a, VipsOperation *b) { if (a == b) return TRUE; if (G_OBJECT_TYPE(a) == G_OBJECT_TYPE(b) && vips_operation_hash(a) == vips_operation_hash(b) && !vips_argument_map(VIPS_OBJECT(a), vips_object_equal_arg, b, NULL)) return TRUE; return FALSE; } #ifdef DEBUG_LEAK static void * vips_operation_copy_argument(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsOperation *new = VIPS_OPERATION(a); if ((argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && argument_instance->assigned) { const char *name = g_param_spec_get_name(pspec); GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); GValue value = G_VALUE_INIT; g_value_init(&value, type); g_object_get_property(G_OBJECT(object), name, &value); g_object_set_property(G_OBJECT(new), name, &value); g_value_unset(&value); } return NULL; } static VipsOperation * vips_operation_copy(VipsOperation *operation) { VipsObject *object = VIPS_OBJECT(operation); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsOperation *new = vips_operation_new(class->nickname); (void) vips_argument_map(object, vips_operation_copy_argument, new, NULL); return new; } #endif /*DEBUG_LEAK*/ static void * vips_object_unref_arg(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { if ((argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_OUTPUT) && argument_instance->assigned && G_IS_PARAM_SPEC_OBJECT(pspec)) { GObject *value; /* This will up the ref count for us. */ g_object_get(G_OBJECT(object), g_param_spec_get_name(pspec), &value, NULL); /* This operation is probably going, so we must wipe the cache * entry pointer on the object. */ g_object_set_data(value, "libvips-cache-entry", NULL); /* Drop the ref we just got, then drop the ref we make when we * added to the cache. */ g_object_unref(value); g_object_unref(value); } return NULL; } static void vips_cache_free_cb(VipsOperationCacheEntry *entry) { #ifdef DEBUG printf("vips_cache_free_cb: "); vips_object_print_summary(VIPS_OBJECT(entry->operation)); #endif /*DEBUG*/ if (entry->invalidate_id) { g_signal_handler_disconnect(entry->operation, entry->invalidate_id); entry->invalidate_id = 0; } (void) vips_argument_map(VIPS_OBJECT(entry->operation), vips_object_unref_arg, NULL, NULL); g_object_unref(entry->operation); g_free(entry); } void * vips__cache_once_init(void *data) { vips_cache_table = g_hash_table_new_full( (GHashFunc) vips_operation_hash, (GEqualFunc) vips_operation_equal, NULL, (GDestroyNotify) vips_cache_free_cb); return NULL; } void vips__cache_init(void) { static GOnce once = G_ONCE_INIT; VIPS_ONCE(&once, vips__cache_once_init, NULL); } static void * vips_cache_print_fn(void *value, void *a, void *b) { VipsOperationCacheEntry *entry = value; char str[32768]; VipsBuf buf = VIPS_BUF_STATIC(str); vips_object_to_string(VIPS_OBJECT(entry->operation), &buf); printf("%p - %s\n", value, vips_buf_all(&buf)); return NULL; } static void vips_cache_print_nolock(void) { if (vips_cache_table) { printf("Operation cache:\n"); vips_hash_table_map(vips_cache_table, vips_cache_print_fn, NULL, NULL); } } /** * vips_cache_print: * * Print the whole operation cache to stdout. Handy for debugging. */ void vips_cache_print(void) { g_mutex_lock(&vips_cache_lock); vips_cache_print_nolock(); g_mutex_unlock(&vips_cache_lock); } static VipsOperationCacheEntry * vips_cache_operation_get(VipsOperation *operation) { return g_hash_table_lookup(vips_cache_table, operation); } /* Remove an operation from the cache. */ static void vips_cache_remove(VipsOperation *operation) { g_hash_table_remove(vips_cache_table, operation); } static void * vips_object_ref_arg(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsOperationCacheEntry *entry = a; if ((argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_OUTPUT) && argument_instance->assigned && G_IS_PARAM_SPEC_OBJECT(pspec)) { GObject *value; /* This will up the ref count for us. */ g_object_get(G_OBJECT(object), g_param_spec_get_name(pspec), &value, NULL); /* This object has been made by this cache entry. */ g_object_set_data(value, "libvips-cache-entry", entry); } return NULL; } static void vips_entry_touch(VipsOperationCacheEntry *entry) { /* Don't up the time for invalid items -- we want them to fall out of * cache. */ if (!entry->invalid) entry->time = vips_cache_time; } static void * vips_image_touch_cb(VipsImage *image, void *a, void *b) { VipsOperationCacheEntry *entry = g_object_get_data(G_OBJECT(image), "libvips-cache-entry"); if (entry) vips_entry_touch(entry); return NULL; } static void * vips_object_touch_arg(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { if ((argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && argument_instance->assigned && g_type_is_a(G_PARAM_SPEC_VALUE_TYPE(pspec), VIPS_TYPE_IMAGE)) { VipsImage *image; g_object_get(G_OBJECT(object), g_param_spec_get_name(pspec), &image, NULL); (void) vips__link_map(image, TRUE, (VipsSListMap2Fn) vips_image_touch_cb, NULL, NULL); VIPS_UNREF(image); } return NULL; } /* Ref an operation for the cache. The operation itself, plus all the output * objects it makes. */ static void vips_entry_ref(VipsOperationCacheEntry *entry) { #ifdef DEBUG printf("vips_cache_ref: "); vips_object_print_summary(VIPS_OBJECT(entry->operation)); #endif /*DEBUG*/ g_object_ref(entry->operation); (void) vips_argument_map(VIPS_OBJECT(entry->operation), vips_object_ref_arg, entry, NULL); vips_cache_time += 1; /* Touch the cache entries on the upstream trees on all input images. */ (void) vips_argument_map(VIPS_OBJECT(entry->operation), vips_object_touch_arg, NULL, NULL); /* And this entry. */ vips_entry_touch(entry); } static void vips_cache_invalidate_cb(VipsOperation *operation, VipsOperationCacheEntry *entry) { #ifdef DEBUG printf("vips_cache_invalidate_cb: "); vips_object_print_summary(VIPS_OBJECT(operation)); #endif /*DEBUG*/ entry->invalid = TRUE; } static void vips_cache_insert(VipsOperation *operation) { VipsOperationCacheEntry *entry = g_new(VipsOperationCacheEntry, 1); #ifdef VIPS_DEBUG printf("vips_cache_insert: adding to cache"); vips_object_print_dump(VIPS_OBJECT(operation)); #endif /*VIPS_DEBUG*/ entry->operation = operation; entry->time = 0; entry->invalidate_id = 0; entry->invalid = FALSE; g_hash_table_insert(vips_cache_table, operation, entry); vips_entry_ref(entry); /* If the operation signals "invalidate", we must tag this cache entry * for removal. */ entry->invalidate_id = g_signal_connect(operation, "invalidate", G_CALLBACK(vips_cache_invalidate_cb), entry); } /** * vips_cache_drop_all: * * Drop the whole operation cache, handy for leak tracking. Also called * automatically on [func@shutdown]. */ void vips_cache_drop_all(void) { #ifdef VIPS_DEBUG printf("vips_cache_drop_all:\n"); #endif /*VIPS_DEBUG*/ g_mutex_lock(&vips_cache_lock); if (vips_cache_table) { if (vips__cache_dump) vips_cache_print_nolock(); g_hash_table_remove_all(vips_cache_table); VIPS_FREEF(g_hash_table_unref, vips_cache_table); } g_mutex_unlock(&vips_cache_lock); } static void vips_cache_get_lru_cb(VipsOperation *key, VipsOperationCacheEntry *value, VipsOperationCacheEntry **best) { if (!*best || (*best)->time > value->time) *best = value; } /* Get the least-recently-used cache item. * * TODO ... will this be too expensive? probably not */ static VipsOperation * vips_cache_get_lru(void) { VipsOperationCacheEntry *entry; entry = NULL; g_hash_table_foreach(vips_cache_table, (GHFunc) vips_cache_get_lru_cb, &entry); if (entry) return entry->operation; return NULL; } /* Is the cache full? Drop until it's not. */ static void vips_cache_trim(void) { VipsOperation *operation; g_mutex_lock(&vips_cache_lock); while (vips_cache_table && (g_hash_table_size(vips_cache_table) > vips_cache_max || vips_tracked_get_files() > vips_cache_max_files || vips_tracked_get_mem() > vips_cache_max_mem) && (operation = vips_cache_get_lru())) { #ifdef DEBUG printf("vips_cache_trim: trimming "); vips_object_print_summary(VIPS_OBJECT(operation)); #endif /*DEBUG*/ vips_cache_remove(operation); } g_mutex_unlock(&vips_cache_lock); } #ifdef DEBUG_LEAK static void * vips_cache_find_differences(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsOperation *operation_before = VIPS_OPERATION(a); if ((argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && argument_instance->assigned) { const char *name = g_param_spec_get_name(pspec); GValue value_before = G_VALUE_INIT; g_object_get_property(G_OBJECT(operation_before), name, &value_before); unsigned int hash_before = vips_value_hash(pspec, &value_before); GValue value_after = G_VALUE_INIT; g_object_get_property(G_OBJECT(object), name, &value_after); unsigned int hash_after = vips_value_hash(pspec, &value_after); if (hash_before != hash_after) { g_warning("arg \"%s\" has changed value during build", name); char *str_before = g_strdup_value_contents(&value_before); g_warning("\tvalue before: %s", str_before); g_free(str_before); char *str_after = g_strdup_value_contents(&value_after); g_warning("\tvalue after: %s", str_after); g_free(str_after); } g_value_unset(&value_before); g_value_unset(&value_after); } return NULL; } #endif /*DEBUG_LEAK*/ /** * vips_cache_operation_buildp: (skip) * @operation: pointer to operation to lookup * * Look up @operation in the cache. If we get a hit, unref @operation, ref the * old one and return that through the argument pointer. * * If we miss, build and add @operation. * * Operators that have been tagged as invalid by [signal@Image::invalidate] are * removed from cache. * * Operators with the [flags@Vips.OperationFlags.BLOCKED] flag are never * executed. * * Operators with the [flags@Vips.OperationFlags.REVALIDATE] flag are always * executed and any old cache value is replaced. * * Operators with the [flags@Vips.OperationFlags.NOCACHE] flag are never cached. * * Returns: 0 on success, or -1 on error. */ int vips_cache_operation_buildp(VipsOperation **operation) { /* Any flags for this new operation we are building. */ VipsOperationFlags flags = vips_operation_get_flags(*operation); VipsOperationCacheEntry *hit; g_assert(VIPS_IS_OPERATION(*operation)); #ifdef VIPS_DEBUG printf("vips_cache_operation_buildp: %p %s\n", *operation, VIPS_OBJECT_GET_CLASS(*operation)->nickname); vips_object_print_dump(VIPS_OBJECT(*operation)); #endif /*VIPS_DEBUG*/ g_mutex_lock(&vips_cache_lock); hit = vips_cache_operation_get(*operation); /* We need to remove the existing cache entry if it's been tagged * as invalid, if it's been blocked, or someone has requested * revalidation. */ if (hit) { if (hit->invalid || (flags & VIPS_OPERATION_BLOCKED) || (flags & VIPS_OPERATION_REVALIDATE)) { vips_cache_remove(hit->operation); hit = NULL; } } /* If we still have a hit, return that and junk the operation we were * passed. */ if (hit) { vips_entry_ref(hit); g_object_unref(*operation); *operation = hit->operation; if (vips__cache_trace) { printf("vips cache*: "); vips_object_print_summary(VIPS_OBJECT(*operation)); } } g_mutex_unlock(&vips_cache_lock); /* If there was a miss, we need to build this operation and add * it to the cache, if appropriate. */ if (!hit) { #ifdef DEBUG_LEAK unsigned int hash_before = 0; VipsOperation *operation_before = NULL; /* The _build method must not change the object hash. If it does, the * finished operation won't detect hits with next identical call. */ if (vips__leak) { hash_before = vips_operation_hash(*operation); /* This isn't a deep copy, so it won't detect eg. * operations modifying compound objects like VipsArrayInt. * However, the hash_before value we save will. */ operation_before = vips_operation_copy(*operation); } #endif /*DEBUG_LEAK*/ if (vips_object_build(VIPS_OBJECT(*operation))) return -1; #ifdef DEBUG_LEAK if (vips__leak && !(flags & VIPS_OPERATION_NOCACHE) && hash_before != vips_operation_hash(*operation)) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC(txt); vips_object_summary(VIPS_OBJECT(operation_before), &buf); g_warning("vips_cache_operation_buildp: " "arg mismatch on build of: %s", vips_buf_all(&buf)); vips_argument_map(VIPS_OBJECT(*operation), vips_cache_find_differences, operation_before, NULL); } VIPS_UNREF(operation_before); #endif /*DEBUG_LEAK*/ /* Retrieve the flags again, as vips_foreign_load_build() may * set load->nocache. */ flags = vips_operation_get_flags(*operation); g_mutex_lock(&vips_cache_lock); /* If two threads build the same operation at the same time, * we can get multiple adds. Let the first one win. See * https://github.com/libvips/libvips/pull/181 */ if (!vips_cache_operation_get(*operation)) { /* Has to be after _build() so we can see output args. */ if (vips__cache_trace) { if (flags & VIPS_OPERATION_NOCACHE) printf("vips cache : "); else printf("vips cache+: "); vips_object_print_summary(VIPS_OBJECT(*operation)); } if (!(flags & VIPS_OPERATION_NOCACHE)) vips_cache_insert(*operation); } g_mutex_unlock(&vips_cache_lock); } vips_cache_trim(); return 0; } /** * vips_cache_operation_build: * @operation: (transfer none): operation to lookup * * A binding-friendly version of [func@cache_operation_buildp]. * * After calling this, @operation has the same ref count as when it went in, * and the result must be freed with [method@Object.unref_outputs] and * [method@GObject.Object.unref]. * * Returns: (transfer full): The built operation. */ VipsOperation * vips_cache_operation_build(VipsOperation *operation) { VipsOperation *orig_operation = operation; /* Stop it being unreffed for us on hit. */ g_object_ref(orig_operation); if (vips_cache_operation_buildp(&operation)) { g_object_unref(orig_operation); return NULL; } return operation; } /** * vips_cache_set_max: * @max: maximum number of operation to cache * * Set the maximum number of operations we keep in cache. */ void vips_cache_set_max(int max) { vips_cache_max = max; vips_cache_trim(); } /** * vips_cache_set_max_mem: * @max_mem: maximum amount of tracked memory we use * * Set the maximum amount of tracked memory we allow before we start dropping * cached operations. See [func@tracked_get_mem]. * * libvips only tracks memory it allocates, it can't track memory allocated by * external libraries. If you use an operation like [ctor@Image.magickload], * most of the memory it uses won't be included. * * ::: seealso * [func@tracked_get_mem]. */ void vips_cache_set_max_mem(size_t max_mem) { vips_cache_max_mem = max_mem; vips_cache_trim(); } /** * vips_cache_get_max: * * Get the maximum number of operations we keep in cache. * * Returns: the maximum number of operations we keep in cache */ int vips_cache_get_max(void) { return vips_cache_max; } /** * vips_cache_get_size: * * Get the current number of operations in cache. * * Returns: get the current number of operations in cache. */ int vips_cache_get_size(void) { guint size; g_mutex_lock(&vips_cache_lock); size = 0; if (vips_cache_table) size = g_hash_table_size(vips_cache_table); g_mutex_unlock(&vips_cache_lock); return size; } /** * vips_cache_get_max_mem: * * Get the maximum amount of tracked memory we allow before we start dropping * cached operations. See [func@tracked_get_mem]. * * ::: seealso * [func@tracked_get_mem]. * * Returns: the maximum amount of tracked memory we allow */ size_t vips_cache_get_max_mem(void) { return vips_cache_max_mem; } /** * vips_cache_get_max_files: * * Get the maximum number of tracked files we allow before we start dropping * cached operations. See [func@tracked_get_files]. * * libvips only tracks file descriptors it allocates, it can't track ones * allocated by external libraries. If you use an operation like * [ctor@Image.magickload], most of the descriptors it uses won't be included. * * ::: seealso * [func@tracked_get_files]. * * Returns: the maximum number of tracked files we allow */ int vips_cache_get_max_files(void) { return vips_cache_max_files; } /** * vips_cache_set_max_files: * @max_files: max open files we allow * * Set the maximum number of tracked files we allow before we start dropping * cached operations. See [func@tracked_get_files]. * * ::: seealso * [func@tracked_get_files]. */ void vips_cache_set_max_files(int max_files) { vips_cache_max_files = max_files; vips_cache_trim(); } /** * vips_cache_set_dump: * @dump: if `TRUE`, dump the operation cache on exit * * Handy for debugging. Print the operation cache to stdout just before exit. * * ::: seealso * [func@cache_set_trace]. */ void vips_cache_set_dump(gboolean dump) { vips__cache_dump = dump; } /** * vips_cache_set_trace: * @trace: if `TRUE`, trace the operation cache * * Handy for debugging. Print operation cache actions to stdout as we run. * * You can set the environment variable `VIPS_TRACE` to turn this option on, or * use the command-line flag `--vips-cache-trace`. * * ::: seealso * [func@cache_set_dump]. */ void vips_cache_set_trace(gboolean trace) { vips__cache_trace = trace; } libvips-8.18.2/libvips/iofuncs/connection.c000066400000000000000000000104141516303661500207110ustar00rootroot00000000000000/* A byte source/sink .. it can be a pipe, file descriptor, memory area, * socket, node.js stream, etc. * * J.Cupitt, 19/6/14 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #include #include /** * VipsConnection: * * An abstract base class representing a source or sink of bytes. * * It can be connected to a network socket, for example, or perhaps * a Node.js stream, or to an area of memory. This allows it to support * operations like JPEG loading, see for example [ctor@Image.jpegload_source]. * * Subclass to add other input sources. Use [class@SourceCustom] and * [class@TargetCustom] to make a source or target with action signals. * These classes provide action signals such as: * * - [signal@SourceCustom::read] for reading data from a custom source. * - [signal@SourceCustom::seek] for seeking within a data stream. * - [signal@TargetCustom::write] for writing data to a custom target. */ G_DEFINE_ABSTRACT_TYPE(VipsConnection, vips_connection, VIPS_TYPE_OBJECT); static void vips_connection_finalize(GObject *gobject) { VipsConnection *connection = (VipsConnection *) gobject; #ifdef VIPS_DEBUG VIPS_DEBUG_MSG("vips_connection_finalize: "); vips_object_print_name(VIPS_OBJECT(gobject)); VIPS_DEBUG_MSG("\n"); #endif /*VIPS_DEBUG*/ if (connection->tracked_descriptor >= 0) { VIPS_DEBUG_MSG(" tracked_close()\n"); vips_tracked_close(connection->tracked_descriptor); connection->tracked_descriptor = -1; connection->descriptor = -1; } if (connection->close_descriptor >= 0) { VIPS_DEBUG_MSG(" close()\n"); close(connection->close_descriptor); connection->close_descriptor = -1; connection->descriptor = -1; } VIPS_FREE(connection->filename); G_OBJECT_CLASS(vips_connection_parent_class)->finalize(gobject); } static void vips_connection_class_init(VipsConnectionClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); gobject_class->finalize = vips_connection_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; VIPS_ARG_INT(class, "descriptor", 1, _("Descriptor"), _("File descriptor for read or write"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConnection, descriptor), -1, 1000000000, 0); VIPS_ARG_STRING(class, "filename", 2, _("Filename"), _("Name of file to open"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsConnection, filename), NULL); } static void vips_connection_init(VipsConnection *connection) { connection->descriptor = -1; connection->tracked_descriptor = -1; connection->close_descriptor = -1; } /** * vips_connection_filename: * @connection: connection to operate on * * Returns: any filename associated with this connection, or `NULL`. */ const char * vips_connection_filename(VipsConnection *connection) { return connection->filename; } /** * vips_connection_nick: * @connection: connection to operate on * * Returns: a string describing this connection which could be displayed to a * user. */ const char * vips_connection_nick(VipsConnection *connection) { return connection->filename ? connection->filename : VIPS_OBJECT(connection)->nickname; } libvips-8.18.2/libvips/iofuncs/dbuf.c000066400000000000000000000230021516303661500174670ustar00rootroot00000000000000/* A dynamic memory buffer that expands as you write. */ /* Copyright (C) 1991-2003 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /** * vips_dbuf_init: * @dbuf: the buffer * * Initialize @dbuf. You can also just init to zero, eg. * `VipsDbuf buf = {0};`. * * Destroy with [method@Dbuf.destroy]. */ void vips_dbuf_init(VipsDbuf *dbuf) { dbuf->data = NULL; dbuf->allocated_size = 0; dbuf->data_size = 0; dbuf->write_point = 0; } /** * vips_dbuf_minimum_size: * @dbuf: the buffer * @size: the minimum size * * Make sure @dbuf is at least @size bytes. * * Returns: `FALSE` on out of memory, `TRUE` otherwise. */ gboolean vips_dbuf_minimum_size(VipsDbuf *dbuf, size_t size) { if (size > dbuf->allocated_size) { const size_t new_allocated_size = 3 * (16 + size) / 2; unsigned char *new_data; if (!(new_data = g_try_realloc(dbuf->data, new_allocated_size))) { vips_error("VipsDbuf", "%s", _("out of memory")); return FALSE; } dbuf->data = new_data; dbuf->allocated_size = new_allocated_size; } return TRUE; } /** * vips_dbuf_allocate: * @dbuf: the buffer * @size: the size to allocate * * Make sure @dbuf has at least @size bytes available after the write point. * * Returns: `FALSE` on out of memory, `TRUE` otherwise. */ gboolean vips_dbuf_allocate(VipsDbuf *dbuf, size_t size) { return vips_dbuf_minimum_size(dbuf, dbuf->write_point + size); } /** * vips_dbuf_read: * @dbuf: the buffer * @data: read to this area * @size: read up to this many bytes * * Up to @size bytes are read from the buffer and copied to @data. The number * of bytes transferred is returned. * * Returns: the number of bytes transferred. */ size_t vips_dbuf_read(VipsDbuf *dbuf, unsigned char *data, size_t size) { const size_t available = dbuf->data_size - dbuf->write_point; const size_t copied = VIPS_MIN(size, available); memcpy(data, dbuf->data + dbuf->write_point, copied); dbuf->write_point += copied; return copied; } /** * vips_dbuf_get_write: * @dbuf: the buffer * @size: (allow-none): optionally return length in bytes here * * Return a pointer to an area you can write to, return length of area in * @size. Use [method@Dbuf.allocate] before this call to set a minimum amount of * space to have available. * * The write point moves to just beyond the returned block. Use * [method@Dbuf.seek] to move it back again. * * Returns: (transfer none): start of write area. */ unsigned char * vips_dbuf_get_write(VipsDbuf *dbuf, size_t *size) { unsigned char *write = dbuf->data + dbuf->write_point; const size_t available = dbuf->allocated_size - dbuf->write_point; memset(write, 0, available); dbuf->write_point = dbuf->allocated_size; dbuf->data_size = dbuf->allocated_size; if (size) *size = available; return write; } /** * vips_dbuf_write: * @dbuf: the buffer * @data: the data to write to the buffer * @size: the size of the len to write * * Append @size bytes from @data. @dbuf expands if necessary. * * Returns: `FALSE` on out of memory, `TRUE` otherwise. */ gboolean vips_dbuf_write(VipsDbuf *dbuf, const unsigned char *data, size_t size) { if (!vips_dbuf_allocate(dbuf, size)) return FALSE; memcpy(dbuf->data + dbuf->write_point, data, size); dbuf->write_point += size; dbuf->data_size = VIPS_MAX(dbuf->data_size, dbuf->write_point); return TRUE; } /** * vips_dbuf_writef: * @dbuf: the buffer * @fmt: `printf()`-style format string * @...: arguments to format string * * Format the string and write to @dbuf. * * Returns: `FALSE` on out of memory, `TRUE` otherwise. */ gboolean vips_dbuf_writef(VipsDbuf *dbuf, const char *fmt, ...) { va_list ap; va_start(ap, fmt); char *line = g_strdup_vprintf(fmt, ap); va_end(ap); if (vips_dbuf_write(dbuf, (unsigned char *) line, strlen(line))) { g_free(line); return FALSE; } g_free(line); return TRUE; } /** * vips_dbuf_write_amp: * @dbuf: the buffer * @str: string to write * * Write @str to @dbuf, but escape stuff that xml hates in text. Our * argument string is utf-8. * * XML rules: * * - We must escape &<> * - Don't escape \n, \t, \r * - Do escape the other ASCII codes. * * Returns: `FALSE` on out of memory, `TRUE` otherwise. */ gboolean vips_dbuf_write_amp(VipsDbuf *dbuf, const char *str) { const char *p; for (p = str; *p; p++) if (*p < 32 && *p != '\n' && *p != '\t' && *p != '\r') { /* You'd think we could output "%x;", but xml * 1.0 parsers barf on that. xml 1.1 allows this, but * there are almost no parsers. * * U+2400 onwards are unicode glyphs for the ASCII * control characters, so we can use them -- thanks * electroly. */ if (!vips_dbuf_writef(dbuf, "&#x%04x;", 0x2400 + *p)) return FALSE; } else if (*p == '<') { if (!vips_dbuf_write(dbuf, (guchar *) "<", 4)) return FALSE; } else if (*p == '>') { if (!vips_dbuf_write(dbuf, (guchar *) ">", 4)) return FALSE; } else if (*p == '&') { if (!vips_dbuf_write(dbuf, (guchar *) "&", 5)) return FALSE; } else { if (!vips_dbuf_write(dbuf, (guchar *) p, 1)) return FALSE; } return TRUE; } /** * vips_dbuf_reset: * @dbuf: the buffer * * Reset the buffer to empty. No memory is freed, just the data size and * write point are reset. */ void vips_dbuf_reset(VipsDbuf *dbuf) { dbuf->write_point = 0; dbuf->data_size = 0; } /** * vips_dbuf_destroy: * @dbuf: the buffer * * Destroy @dbuf. This frees any allocated memory. Useful for dbufs on the * stack. */ void vips_dbuf_destroy(VipsDbuf *dbuf) { vips_dbuf_reset(dbuf); VIPS_FREE(dbuf->data); dbuf->allocated_size = 0; } /** * vips_dbuf_seek: * @dbuf: the buffer * @offset: how to move the write point * @whence: from start, from end, from current * * Move the write point. @whence can be `SEEK_SET`, `SEEK_CUR`, `SEEK_END`, with * the usual meaning. */ gboolean vips_dbuf_seek(VipsDbuf *dbuf, off_t offset, int whence) { off_t new_write_point; switch (whence) { case SEEK_SET: new_write_point = offset; break; case SEEK_END: new_write_point = dbuf->data_size + offset; break; case SEEK_CUR: new_write_point = dbuf->write_point + offset; break; default: g_assert(0); new_write_point = dbuf->write_point; break; } if (new_write_point < 0) { vips_error("VipsDbuf", "%s", "negative seek"); return FALSE; } /* Possibly need to grow the buffer */ if (!vips_dbuf_minimum_size(dbuf, new_write_point)) return FALSE; dbuf->write_point = new_write_point; if (dbuf->data_size < dbuf->write_point) { memset(dbuf->data + dbuf->data_size, 0, dbuf->write_point - dbuf->data_size); dbuf->data_size = dbuf->write_point; } return TRUE; } /** * vips_dbuf_truncate: * @dbuf: the buffer * * Truncate the data so that it ends at the write point. No memory is freed. */ void vips_dbuf_truncate(VipsDbuf *dbuf) { dbuf->data_size = dbuf->write_point; } /** * vips_dbuf_tell: * @dbuf: the buffer * * Returns: the current write point */ off_t vips_dbuf_tell(VipsDbuf *dbuf) { return dbuf->write_point; } /** * vips_dbuf_null_terminate: * @dbuf: the buffer * * Make sure the byte after the last data byte is `\0`. This extra byte is not * included in the data size and the write point is not moved. * * This makes it safe to treat the dbuf contents as a C string. * * Returns: `FALSE` on out of memory, `TRUE` otherwise. */ static gboolean vips_dbuf_null_terminate(VipsDbuf *dbuf) { if (!vips_dbuf_minimum_size(dbuf, dbuf->data_size + 1)) return FALSE; dbuf->data[dbuf->data_size] = 0; return TRUE; } /** * vips_dbuf_steal: * @dbuf: the buffer * @size: (allow-none): optionally return length in bytes here * * Destroy a buffer, but rather than freeing memory, a pointer is returned. * This must be freed with [func@GLib.free]. * * A `\0` is appended, but not included in the character count. This is so the * pointer can be safely treated as a C string. * * Returns: (transfer full): The pointer held by @dbuf. */ unsigned char * vips_dbuf_steal(VipsDbuf *dbuf, size_t *size) { unsigned char *data; vips_dbuf_null_terminate(dbuf); data = dbuf->data; if (size) *size = dbuf->data_size; dbuf->data = NULL; vips_dbuf_destroy(dbuf); return data; } /** * vips_dbuf_string: * @dbuf: the buffer * @size: (allow-none): optionally return length in bytes here * * Return a pointer to @dbuf's internal data. * * A `\0` is appended, but not included in the character count. This is so the * pointer can be safely treated as a C string. * * Returns: (transfer none): The pointer held by @dbuf. */ unsigned char * vips_dbuf_string(VipsDbuf *dbuf, size_t *size) { vips_dbuf_null_terminate(dbuf); if (size) *size = dbuf->data_size; return dbuf->data; } libvips-8.18.2/libvips/iofuncs/error.c000066400000000000000000000651331516303661500177130ustar00rootroot00000000000000/* error.c -- error message handling * * Copyright: N. Dessipris * Written on: 18/03/1991 * Updated on: 9/7/92 KM * 20/12/2003 JC * - i18n added, domain now separate arg * 14/2/07 * - lock around error buffer changes * 20/2/08 * - lock around warnings and diagnostics too, why not * 2/10/09 * - error_exit() moved here * - gtkdoc comments * 24/6/10 * - fmt to error_exit() may be NULL * 12/9/19 [dineshkannaa] * - add vips_error_buffer_copy() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #ifdef G_OS_WIN32 #include #include #endif /*G_OS_WIN32*/ /* Make global array to keep the error message buffer. */ #define VIPS_MAX_ERROR (10240) static char vips_error_text[VIPS_MAX_ERROR] = ""; static VipsBuf vips_error_buf = VIPS_BUF_STATIC(vips_error_text); static int vips_error_freeze_count = 0; /** * vips_error_freeze: * * Stop errors being logged. Use [func@error_thaw] to unfreeze. You can * nest freeze/thaw pairs. */ void vips_error_freeze(void) { g_mutex_lock(&vips__global_lock); g_assert(vips_error_freeze_count >= 0); vips_error_freeze_count += 1; g_mutex_unlock(&vips__global_lock); } /** * vips_error_thaw: * * Re-enable error logging. */ void vips_error_thaw(void) { g_mutex_lock(&vips__global_lock); vips_error_freeze_count -= 1; g_assert(vips_error_freeze_count >= 0); g_mutex_unlock(&vips__global_lock); } /** * vips_error_buffer: * * Get a pointer to the start of the error buffer as a C string. * The string is owned by the error system and must not be freed. * * ::: seealso * [func@error_clear]. * * Returns: the error buffer as a C string which must not be freed */ const char * vips_error_buffer(void) { const char *msg; g_mutex_lock(&vips__global_lock); msg = vips_buf_all(&vips_error_buf); g_mutex_unlock(&vips__global_lock); return msg; } /** * vips_error_buffer_copy: * * Return a copy of the vips error buffer, and clear it. * * Returns: a copy of the libvips error buffer */ char * vips_error_buffer_copy(void) { char *msg; g_mutex_lock(&vips__global_lock); msg = g_strdup(vips_buf_all(&vips_error_buf)); vips_buf_rewind(&vips_error_buf); g_mutex_unlock(&vips__global_lock); return msg; } /* Some systems do not have va_copy() ... this might work (it does on MSVC, * apparently). * * FIXME ... this should be in configure.in */ #ifndef va_copy #define va_copy(d, s) ((d) = (s)) #endif /** * vips_verror: * @domain: the source of the error * @fmt: `printf()`-style format string for the error * @ap: arguments to the format string * * Append a message to the error buffer. * * ::: seealso * [func@error]. */ void vips_verror(const char *domain, const char *fmt, va_list ap) { #ifdef VIPS_DEBUG { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC(txt); va_list ap2; vips_buf_appendf(&buf, "%s: ", domain); va_copy(ap2, ap); vips_buf_vappendf(&buf, fmt, ap2); vips_buf_appends(&buf, "\n"); VIPS_DEBUG_MSG("vips_verror: %s", vips_buf_all(&buf)); } #endif /*VIPS_DEBUG*/ g_mutex_lock(&vips__global_lock); g_assert(vips_error_freeze_count >= 0); if (!vips_error_freeze_count) { if (domain) vips_buf_appendf(&vips_error_buf, "%s: ", domain); vips_buf_vappendf(&vips_error_buf, fmt, ap); vips_buf_appends(&vips_error_buf, "\n"); } g_mutex_unlock(&vips__global_lock); if (vips__fatal) vips_error_exit("vips__fatal"); } /** * vips_error: * @domain: the source of the error * @fmt: `printf()`-style format string for the error * @...: arguments to the format string * * Format the string in the style of [`printf()`](man:printf(3)) and append to the error buffer. * * ::: seealso * [func@error_system], [func@verror]. */ void vips_error(const char *domain, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vips_verror(domain, fmt, ap); va_end(ap); } /** * vips_verror_system: * @err: the system error code * @domain: the source of the error * @fmt: `printf()`-style format string for the error * @ap: arguments to the format string * * Format the string in the style of [`printf()`](man:printf(3)) and append to the error buffer. * Then create and append a localised message based on the system error code, * usually the value of errno. * * ::: seealso * [func@error_system]. */ void vips_verror_system(int err, const char *domain, const char *fmt, va_list ap) { vips_verror(domain, fmt, ap); vips_error(_("system error"), "%s", g_strerror(err)); } /** * vips_error_system: * @err: the system error code * @domain: the source of the error * @fmt: `printf()`-style format string for the error * @...: arguments to the format string * * Format the string in the style of [`printf()`](man:printf(3)) and append to the error buffer. * Then create and append a localised message based on the system error code, * usually the value of errno. * * ::: seealso * [func@verror_system]. */ void vips_error_system(int err, const char *domain, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vips_verror_system(err, domain, fmt, ap); va_end(ap); } /** * vips_error_g: * @error: (out): glib error pointer * * This function sets the glib error pointer from the vips error buffer and * clears it. It's handy for returning errors to glib functions from vips. * * See [func@g_error] for the inverse operation. * * ::: seealso * [func@GLib.set_error], [func@g_error]. */ void vips_error_g(GError **error) { static GQuark vips_domain = 0; if (!vips_domain) vips_domain = g_quark_from_string("libvips"); /* glib does not expect a trailing '\n' and vips always has one. */ g_mutex_lock(&vips__global_lock); vips_buf_removec(&vips_error_buf, '\n'); g_mutex_unlock(&vips__global_lock); g_set_error(error, vips_domain, -1, "%s", vips_error_buffer()); vips_error_clear(); } /** * vips_g_error: * @error: glib error pointer * * This function adds the [struct@GLib.Error] to the vips error buffer and clears it. It's * the opposite of [func@error_g]. * * ::: seealso * [func@error_g]. */ void vips_g_error(GError **error) { if (error && *error) { vips_error("glib", "%s\n", (*error)->message); g_error_free(*error); *error = NULL; } } /** * vips_error_clear: * * Clear and reset the error buffer. This is typically called after presenting * an error to the user. * * ::: seealso * [func@error_buffer]. */ void vips_error_clear(void) { g_mutex_lock(&vips__global_lock); vips_buf_rewind(&vips_error_buf); g_mutex_unlock(&vips__global_lock); } /** * vips_error_exit: * @fmt: `printf()`-style format string for the message * @...: arguments to the format string * * Sends a formatted error message to stderr, then sends the contents of the * error buffer, if any, then shuts down vips and terminates the program with * an error code. * * @fmt may be `NULL`, in which case only the error buffer is printed before * exiting. * * ::: seealso * [func@error]. */ void vips_error_exit(const char *fmt, ...) { if (fmt) { va_list ap; fprintf(stderr, "%s: ", vips_get_prgname()); va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } fprintf(stderr, "%s", vips_error_buffer()); vips_shutdown(); if (vips__fatal) abort(); else exit(1); } /** * vips_check_uncoded: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is not coded. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_uncoded(const char *domain, VipsImage *im) { if (im->Coding != VIPS_CODING_NONE) { vips_error(domain, "%s", _("image must be uncoded")); return -1; } return 0; } /** * vips_check_coding_noneorlabq: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is uncoded or LABQ coded. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_coding_noneorlabq(const char *domain, VipsImage *im) { /* These all have codings that extract/ifthenelse/etc can ignore. */ if (im->Coding != VIPS_CODING_NONE && im->Coding != VIPS_CODING_LABQ) { vips_error(domain, "%s", _("image coding must be 'none' or 'labq'")); return -1; } return 0; } /** * vips_check_coding_known: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is uncoded, LABQ coded or RAD coded. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_coding_known(const char *domain, VipsImage *im) { /* These all have codings that extract/ifthenelse/etc can ignore. */ if (im->Coding != VIPS_CODING_NONE && im->Coding != VIPS_CODING_LABQ && im->Coding != VIPS_CODING_RAD) { vips_error(domain, "%s", _("unknown image coding")); return -1; } return 0; } /** * vips_check_coding: * @domain: the originating domain for the error message * @im: image to check * @coding: required coding * * Check that the image has the required @coding. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_coding(const char *domain, VipsImage *im, VipsCoding coding) { if (im->Coding != coding) { vips_error(domain, _("coding '%s' only"), vips_enum_nick(VIPS_TYPE_CODING, coding)); return -1; } return 0; } /** * vips_check_mono: * @domain: the originating domain for the error message * @im: image to check * * Check that the image has exactly one band. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_mono(const char *domain, VipsImage *im) { if (im->Bands != 1) { vips_error(domain, "%s", _("image must one band")); return -1; } return 0; } /** * vips_check_bands: * @domain: the originating domain for the error message * @im: image to check * @bands: must have this many bands * * Check that the image has @bands bands. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_bands(const char *domain, VipsImage *im, int bands) { if (im->Bands != bands) { vips_error(domain, _("image must have %d bands"), bands); return -1; } return 0; } /** * vips_check_bands_1or3: * @domain: the originating domain for the error message * @im: image to check * * Check that the image has either one or three bands. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_bands_1or3(const char *domain, VipsImage *im) { if (im->Bands != 1 && im->Bands != 3) { vips_error(domain, "%s", _("image must have one or three bands")); return -1; } return 0; } /** * vips_check_bands_atleast: * @domain: the originating domain for the error message * @im: image to check * @bands: at least this many bands * * Check that the image has at least @bands bands. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_bands_atleast(const char *domain, VipsImage *im, int bands) { if (im->Bands < bands) { vips_error(domain, _("image must have at least %d bands"), bands); return -1; } return 0; } /** * vips_check_bands_1orn: * @domain: the originating domain for the error message * @im1: first image to check * @im2: second image to check * * Check that the images have the same number of bands, or that one of the * images has just 1 band. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_bands_1orn(const char *domain, VipsImage *im1, VipsImage *im2) { if (im1->Bands != im2->Bands && (im1->Bands != 1 && im2->Bands != 1)) { vips_error(domain, "%s", _("images must have the same number of bands, " "or one must be single-band")); return -1; } return 0; } /** * vips_check_bands_1orn_unary: * @domain: the originating domain for the error message * @im: image to check * @n: number of bands, or 1 * * Check that an image has 1 or @n bands. Handy for unary operations, cf. * [func@check_bands_1orn]. * If not, set an error message * and return non-zero. * * ::: seealso * [func@check_bands_1orn]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_bands_1orn_unary(const char *domain, VipsImage *im, int n) { if (im->Bands != 1 && im->Bands != n) { vips_error(domain, _("image must have 1 or %d bands"), n); return -1; } return 0; } /** * vips_check_noncomplex: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is not complex. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_noncomplex(const char *domain, VipsImage *im) { if (vips_band_format_iscomplex(im->BandFmt)) { vips_error(domain, "%s", _("image must be non-complex")); return -1; } return 0; } /** * vips_check_complex: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is complex. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_complex(const char *domain, VipsImage *im) { if (!vips_band_format_iscomplex(im->BandFmt)) { vips_error(domain, "%s", _("image must be complex")); return -1; } return 0; } /** * vips_check_twocomponents: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is has two "components", ie. is a one-band complex or * a two-band non-complex. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_twocomponents(const char *domain, VipsImage *im) { if (!vips_band_format_iscomplex(im->BandFmt) && im->Bands != 2) { vips_error(domain, "%s", _("image must be two-band or complex")); return -1; } return 0; } /** * vips_check_format: * @domain: the originating domain for the error message * @im: image to check * @fmt: format to test for * * Check that the image has the specified format. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_format(const char *domain, VipsImage *im, VipsBandFormat fmt) { if (im->BandFmt != fmt) { vips_error(domain, _("image must be %s"), vips_enum_string(VIPS_TYPE_BAND_FORMAT, fmt)); return -1; } return 0; } /** * vips_check_int: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is in one of the integer formats. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_int(const char *domain, VipsImage *im) { if (!vips_band_format_isint(im->BandFmt)) { vips_error(domain, "%s", _("image must be integer")); return -1; } return 0; } /** * vips_check_uint: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is in one of the unsigned integer formats. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_uint(const char *domain, VipsImage *im) { if (!vips_band_format_isuint(im->BandFmt)) { vips_error(domain, "%s", _("image must be unsigned integer")); return -1; } return 0; } /** * vips_check_8or16: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is 8 or 16-bit integer, signed or unsigned. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_8or16(const char *domain, VipsImage *im) { if (im->BandFmt != VIPS_FORMAT_UCHAR && im->BandFmt != VIPS_FORMAT_USHORT && im->BandFmt != VIPS_FORMAT_CHAR && im->BandFmt != VIPS_FORMAT_SHORT) { vips_error(domain, "%s", _("image must be 8- or 16-bit integer, signed or unsigned")); return -1; } return 0; } /** * vips_check_u8or16: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is 8 or 16-bit unsigned integer. * Otherwise set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_u8or16(const char *domain, VipsImage *im) { if (im->BandFmt != VIPS_FORMAT_UCHAR && im->BandFmt != VIPS_FORMAT_USHORT) { vips_error(domain, "%s", _("image must be 8- or 16-bit unsigned integer")); return -1; } return 0; } /** * vips_check_u8or16orf: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is 8 or 16-bit unsigned integer, or float. * Otherwise set an error message and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_u8or16orf(const char *domain, VipsImage *im) { if (im->BandFmt != VIPS_FORMAT_UCHAR && im->BandFmt != VIPS_FORMAT_USHORT && im->BandFmt != VIPS_FORMAT_FLOAT) { vips_error(domain, "%s", _("image must be 8- or 16-bit unsigned integer, or float")); return -1; } return 0; } /** * vips_check_uintorf: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is unsigned int or float. * Otherwise set an error message and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_uintorf(const char *domain, VipsImage *im) { if (im->BandFmt != VIPS_FORMAT_UCHAR && im->BandFmt != VIPS_FORMAT_USHORT && im->BandFmt != VIPS_FORMAT_UINT && im->BandFmt != VIPS_FORMAT_FLOAT) { vips_error(domain, "%s", _("image must be unsigned int or float")); return -1; } return 0; } /** * vips_check_size_same: * @domain: the originating domain for the error message * @im1: first image to check * @im2: second image to check * * Check that the images have the same size. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_size_same(const char *domain, VipsImage *im1, VipsImage *im2) { if (im1->Xsize != im2->Xsize || im1->Ysize != im2->Ysize) { vips_error(domain, "%s", _("images must match in size")); return -1; } return 0; } /** * vips_check_oddsquare: * @domain: the originating domain for the error message * @im: image to check * * Check that the image is square and that the sides are odd. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_oddsquare(const char *domain, VipsImage *im) { if (im->Xsize != im->Ysize || im->Xsize % 2 == 0) { vips_error(domain, "%s", _("images must be odd and square")); return -1; } return 0; } /** * vips_check_bands_same: * @domain: the originating domain for the error message * @im1: first image to check * @im2: second image to check * * Check that the images have the same number of bands. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_bands_same(const char *domain, VipsImage *im1, VipsImage *im2) { if (im1->Bands != im2->Bands) { vips_error(domain, "%s", _("images must have the same number of bands")); return -1; } return 0; } /** * vips_check_bandno: * @domain: the originating domain for the error message * @im: image to check * @bandno: band number * * @bandno should be a valid band number (ie. 0 to im->Bands - 1), or can be * -1, meaning all bands. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_bandno(const char *domain, VipsImage *im, int bandno) { if (bandno < -1 || bandno > im->Bands - 1) { vips_error(domain, "bandno must be -1, or less than %d", im->Bands); return -1; } return 0; } /** * vips_check_format_same: * @domain: the originating domain for the error message * @im1: first image to check * @im2: second image to check * * Check that the images have the same format. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_format_same(const char *domain, VipsImage *im1, VipsImage *im2) { if (im1->BandFmt != im2->BandFmt) { vips_error(domain, "%s", _("images must have the same band format")); return -1; } return 0; } /** * vips_check_coding_same: * @domain: the originating domain for the error message * @im1: first image to check * @im2: second image to check * * Check that the images have the same coding. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_coding_same(const char *domain, VipsImage *im1, VipsImage *im2) { if (im1->Coding != im2->Coding) { vips_error(domain, "%s", _("images must have the same coding")); return -1; } return 0; } /** * vips_check_vector_length: * @domain: the originating domain for the error message * @n: number of elements in vector * @len: number of elements vector should have * * Check that @n == @len. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_vector_length(const char *domain, int n, int len) { if (n != len) { vips_error(domain, _("vector must have %d elements"), len); return -1; } return 0; } /** * vips_check_vector: * @domain: the originating domain for the error message * @n: number of elements in vector * @im: image to check against * * Operations with a vector constant need a 1-element vector, or a vector with * the same number of elements as there are bands in the image, or a 1-band * image and a many-element vector. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_vector(const char *domain, int n, VipsImage *im) { /* Here it's clearer to list the cases that are OK. */ if (n == im->Bands) return 0; if (n == 1) return 0; if (im->Bands == 1 && n > 1) return 0; if (im->Bands == 1) vips_error(domain, "%s", _("vector must have 1 element")); else vips_error(domain, _("vector must have 1 or %d elements"), im->Bands); return -1; } /** * vips_check_hist: * @domain: the originating domain for the error message * @im: image to check * * Histogram images must have width or height 1, and must not have more than * 65536 elements. Return 0 if the image will pass as a histogram, or -1 and * set an error message otherwise. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_hist(const char *domain, VipsImage *im) { if (im->Xsize != 1 && im->Ysize != 1) { vips_error(domain, "%s", _("histograms must have width or height 1")); return -1; } if (VIPS_IMAGE_N_PELS(im) > 65536) { vips_error(domain, "%s", _("histograms must have not have more than 65536 elements")); return -1; } return 0; } /** * vips_check_matrix: * @domain: the originating domain for the error message * @im: image to check * @out: (out): put image as in-memory doubles here * * Matrix images must have width and height less than 100000 and have 1 band. * * Return 0 if the image will pass as a matrix, or -1 and set an error * message otherwise. * * @out is set to be @im cast to double and stored in memory. Use * [func@MATRIX] to address values in @out. * * You must unref @out when you are done with it. * * ::: seealso * [func@MATRIX]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_matrix(const char *domain, VipsImage *im, VipsImage **out) { VipsImage *t; *out = NULL; if (im->Xsize > 100000 || im->Ysize > 100000) { vips_error(domain, "%s", _("matrix image too large")); return -1; } if (im->Bands != 1) { vips_error(domain, "%s", _("matrix image must have one band")); return -1; } if (vips_cast(im, &t, VIPS_FORMAT_DOUBLE, NULL)) return -1; if (!(*out = vips_image_copy_memory(t))) { VIPS_UNREF(t); return -1; } VIPS_UNREF(t); return 0; } /** * vips_check_separable: * @domain: the originating domain for the error message * @im: image to check * * Separable matrix images must have width or height 1. * Return 0 if the image will pass, or -1 and * set an error message otherwise. * * ::: seealso * [func@error]. * * Returns: 0 if OK, -1 otherwise. */ int vips_check_separable(const char *domain, VipsImage *im) { if (im->Xsize != 1 && im->Ysize != 1) { vips_error(domain, "%s", _("separable matrix images must have width or height 1")); return -1; } return 0; } /** * vips_check_precision_intfloat: * @domain: the originating domain for the error message * @precision: precision to check * * Check that @prec image is either float or int. * If not, set an error message * and return non-zero. * * ::: seealso * [func@error]. * * Returns: 0 on OK, or -1 on error. */ int vips_check_precision_intfloat(const char *domain, VipsPrecision precision) { if (precision != VIPS_PRECISION_INTEGER && precision != VIPS_PRECISION_FLOAT) { vips_error(domain, "%s", _("precision must be int or float")); return -1; } return 0; } libvips-8.18.2/libvips/iofuncs/gate.c000066400000000000000000000207171516303661500175010ustar00rootroot00000000000000/* gate.c -- thread profiling * * Written on: 18 nov 13 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Very verbose. #define VIPS_DEBUG_RED */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #define VIPS_GATE_SIZE (1000) /* A set of timing records. i is the index of the next slot we fill. */ typedef struct _VipsThreadGateBlock { struct _VipsThreadGateBlock *prev; gint64 time[VIPS_GATE_SIZE]; int i; } VipsThreadGateBlock; /* What we track for each gate-name. */ typedef struct _VipsThreadGate { const char *name; VipsThreadGateBlock *start; VipsThreadGateBlock *stop; } VipsThreadGate; /* One of these in per-thread private storage. */ typedef struct _VipsThreadProfile { const char *name; GThread *thread; GHashTable *gates; VipsThreadGate *memory; } VipsThreadProfile; gboolean vips__thread_profile = FALSE; static void thread_profile_destroy_notify(gpointer data); static GPrivate vips_thread_profile_key = G_PRIVATE_INIT(thread_profile_destroy_notify); static FILE *vips__thread_fp = NULL; /** * vips_profile_set: * @profile: `TRUE` to enable profile recording * * If set, vips will record profiling information, and dump it on program * exit. These profiles can be analysed with the `vipsprofile` program. */ void vips_profile_set(gboolean profile) { vips__thread_profile = profile; } static void vips_thread_gate_block_save(VipsThreadGateBlock *block, FILE *fp) { int i; for (i = block->i - 1; i >= 0; i--) fprintf(fp, "%" G_GINT64_FORMAT " ", block->time[i]); fprintf(fp, "\n"); if (block->prev) vips_thread_gate_block_save(block->prev, fp); } static void vips_thread_profile_save_gate(VipsThreadGate *gate, FILE *fp) { if (gate->start->i || gate->start->prev) { fprintf(fp, "gate: %s\n", gate->name); fprintf(fp, "start:\n"); vips_thread_gate_block_save(gate->start, fp); fprintf(fp, "stop:\n"); vips_thread_gate_block_save(gate->stop, fp); } } static void vips_thread_profile_save_cb(gpointer key, gpointer value, gpointer data) { VipsThreadGate *gate = (VipsThreadGate *) value; FILE *fp = (FILE *) data; vips_thread_profile_save_gate(gate, fp); } static void vips_thread_profile_save(VipsThreadProfile *profile) { g_mutex_lock(&vips__global_lock); VIPS_DEBUG_MSG("vips_thread_profile_save: %s\n", profile->name); if (!vips__thread_fp) { vips__thread_fp = vips__file_open_write("vips-profile.txt", TRUE); if (!vips__thread_fp) { g_mutex_unlock(&vips__global_lock); g_warning("unable to create profile log"); return; } printf("recording profile in vips-profile.txt\n"); } fprintf(vips__thread_fp, "thread: %s (%p)\n", profile->name, profile); g_hash_table_foreach(profile->gates, vips_thread_profile_save_cb, vips__thread_fp); vips_thread_profile_save_gate(profile->memory, vips__thread_fp); g_mutex_unlock(&vips__global_lock); } static void vips_thread_gate_block_free(VipsThreadGateBlock *block) { VIPS_FREEF(vips_thread_gate_block_free, block->prev); VIPS_FREE(block); } static void vips_thread_gate_free(VipsThreadGate *gate) { VIPS_FREEF(vips_thread_gate_block_free, gate->start); VIPS_FREEF(vips_thread_gate_block_free, gate->stop); VIPS_FREE(gate); } static void vips_thread_profile_free(VipsThreadProfile *profile) { VIPS_DEBUG_MSG("vips_thread_profile_free: %s\n", profile->name); VIPS_FREEF(g_hash_table_destroy, profile->gates); VIPS_FREEF(vips_thread_gate_free, profile->memory); VIPS_FREE(profile); } void vips__thread_profile_stop(void) { if (vips__thread_profile) VIPS_FREEF(fclose, vips__thread_fp); } static void thread_profile_destroy_notify(gpointer data) { VipsThreadProfile *profile = data; /* We only come here if vips_thread_shutdown() was not called for this * thread. Do our best to clean up. * * GPrivate has stopped working, be careful not to touch that. * * Don't try to save: we must free all mem before saving and we * probably haven't done that because vips_thread_shutdown() has not * been called. */ if (vips__thread_profile) g_warning("discarding unsaved state for thread %p -- " "call vips_thread_shutdown() for this thread", profile->thread); vips_thread_profile_free(profile); } static VipsThreadGate * vips_thread_gate_new(const char *gate_name) { VipsThreadGate *gate; gate = g_new(VipsThreadGate, 1); gate->name = gate_name; gate->start = g_new0(VipsThreadGateBlock, 1); gate->stop = g_new0(VipsThreadGateBlock, 1); return gate; } void vips__thread_profile_attach(const char *thread_name) { VipsThreadProfile *profile; VIPS_DEBUG_MSG("vips__thread_profile_attach: %s\n", thread_name); profile = g_new(VipsThreadProfile, 1); profile->name = thread_name; profile->gates = g_hash_table_new_full( g_direct_hash, g_str_equal, NULL, (GDestroyNotify) vips_thread_gate_free); profile->memory = vips_thread_gate_new("memory"); g_private_replace(&vips_thread_profile_key, profile); } static VipsThreadProfile * vips_thread_profile_get(void) { return g_private_get(&vips_thread_profile_key); } /* This usually happens automatically when a thread shuts down, but that will * not happen for the main thread. * * Shut down any stats on the main thread with this, see vips_shutdown(). */ void vips__thread_profile_detach(void) { VipsThreadProfile *profile; VIPS_DEBUG_MSG("vips__thread_profile_detach:\n"); if ((profile = vips_thread_profile_get())) { if (vips__thread_profile) vips_thread_profile_save(profile); vips_thread_profile_free(profile); g_private_set(&vips_thread_profile_key, NULL); } } static void vips_thread_gate_block_add(VipsThreadGateBlock **block) { VipsThreadGateBlock *new_block; new_block = g_new0(VipsThreadGateBlock, 1); new_block->prev = *block; *block = new_block; } void vips__thread_gate_start(const char *gate_name) { VipsThreadProfile *profile; VIPS_DEBUG_MSG_RED("vips__thread_gate_start: %s\n", gate_name); if ((profile = vips_thread_profile_get())) { gint64 time = g_get_monotonic_time(); VipsThreadGate *gate; if (!(gate = g_hash_table_lookup(profile->gates, gate_name))) { gate = vips_thread_gate_new(gate_name); g_hash_table_insert(profile->gates, (char *) gate_name, gate); } if (gate->start->i >= VIPS_GATE_SIZE) vips_thread_gate_block_add(&gate->start); gate->start->time[gate->start->i++] = time; VIPS_DEBUG_MSG_RED("\t %" G_GINT64_FORMAT "\n", time); } } void vips__thread_gate_stop(const char *gate_name) { VipsThreadProfile *profile; VIPS_DEBUG_MSG_RED("vips__thread_gate_stop: %s\n", gate_name); if ((profile = vips_thread_profile_get())) { gint64 time = g_get_monotonic_time(); VipsThreadGate *gate; if (!(gate = g_hash_table_lookup(profile->gates, gate_name))) { gate = vips_thread_gate_new(gate_name); g_hash_table_insert(profile->gates, (char *) gate_name, gate); } if (gate->stop->i >= VIPS_GATE_SIZE) vips_thread_gate_block_add(&gate->stop); gate->stop->time[gate->stop->i++] = time; VIPS_DEBUG_MSG_RED("\t %" G_GINT64_FORMAT "\n", time); } } /* Record a malloc() or free(). Use -ve numbers for free. */ void vips__thread_malloc_free(gint64 size) { VipsThreadProfile *profile; VIPS_DEBUG_MSG_RED("vips__thread_malloc_free: %zd\n", size); #ifdef VIPS_DEBUG if (!(profile = vips_thread_profile_get())) printf("argh no block to record free() in!\n"); #endif /*VIPS_DEBUG*/ if ((profile = vips_thread_profile_get())) { gint64 time = g_get_monotonic_time(); VipsThreadGate *gate = profile->memory; if (gate->start->i >= VIPS_GATE_SIZE) { vips_thread_gate_block_add(&gate->start); vips_thread_gate_block_add(&gate->stop); } gate->start->time[gate->start->i++] = time; gate->stop->time[gate->stop->i++] = size; } } libvips-8.18.2/libvips/iofuncs/generate.c000066400000000000000000000440161516303661500203510ustar00rootroot00000000000000/* Manage pipelines of partial images. * * J.Cupitt, 17/4/93. * 1/7/93 JC * - adapted for partial v2 * - ANSIfied * 6/7/93 JC * - im_setupout() conventions clarified - see autorewind in * im_iocheck(). * 20/7/93 JC * - eval callbacks added * 7/9/93 JC * - demand hint mechanism added * 25/10/93 * - asynchronous output mechanisms removed, as no observable speed-up * 9/5/94 * - new thread stuff added, with a define to turn it off * 15/8/94 * - start & stop functions can now be NULL for no-op * 7/10/94 JC * - evalend callback system added * 23/12/94 JC * - IM_ARRAY uses added * 22/2/95 JC * - im_fill_copy() added * - im_region_region() uses modified * 24/4/95 JC & KM * - im_fill_lines() bug removed * 30/8/96 JC * - revised and simplified ... some code shared with im_iterate() * - new im_generate_region() added * 2/3/98 JC * - IM_ANY added * 20/7/99 JC * - tile geometry made into ints for easy tuning * 30/7/99 RP JC * - threads reorganised for POSIX * 29/9/99 JC * - threadgroup stuff added * 15/4/04 * - better how-many-pixels-calculated * 27/11/06 * - merge background write stuff * 7/11/07 * - new start/end eval callbacks * 7/10/09 * - gtkdoc comments * 16/4/10 * - remove threadgroup stuff * 24/3/11 * - move demand_hint stuff in here * - move to vips_ namespace * 7/7/12 * - lock around link make/break so we can process an image from many * threads */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #ifdef HAVE_IO_H #include #endif /*HAVE_IO_H*/ #include #include #include /* Max number of images we can handle. */ #define MAX_IMAGES (1000) /* Make an upstream/downstream link. upstream is one of downstream's inputs. */ static void vips__link_make(VipsImage *image_up, VipsImage *image_down) { g_assert(image_up); g_assert(image_down); image_up->downstream = g_slist_prepend(image_up->downstream, image_down); image_down->upstream = g_slist_prepend(image_down->upstream, image_up); /* Propagate the progress indicator. */ if (image_up->progress_signal && !image_down->progress_signal) image_down->progress_signal = image_up->progress_signal; } static void * vips__link_break(VipsImage *image_up, VipsImage *image_down, void *b) { g_assert(image_up); g_assert(image_down); g_assert(g_slist_find(image_up->downstream, image_down)); g_assert(g_slist_find(image_down->upstream, image_up)); image_up->downstream = g_slist_remove(image_up->downstream, image_down); image_down->upstream = g_slist_remove(image_down->upstream, image_up); /* Unlink the progress chain. */ if (image_down->progress_signal && image_down->progress_signal == image_up->progress_signal) image_down->progress_signal = NULL; return NULL; } static void * vips__link_break_rev(VipsImage *image_down, VipsImage *image_up, void *b) { return vips__link_break(image_up, image_down, b); } /* A VipsImage is going ... break all links. */ void vips__link_break_all(VipsImage *image) { g_mutex_lock(&vips__global_lock); vips_slist_map2(image->upstream, (VipsSListMap2Fn) vips__link_break, image, NULL); vips_slist_map2(image->downstream, (VipsSListMap2Fn) vips__link_break_rev, image, NULL); g_assert(!image->upstream); g_assert(!image->downstream); g_mutex_unlock(&vips__global_lock); } typedef struct _LinkMap { gboolean upstream; int serial; VipsSListMap2Fn fn; void *a; void *b; } LinkMap; static void * vips__link_mapp(VipsImage *image, LinkMap *map, void *b) { void *res; /* Loop? */ if (image->serial == map->serial) return NULL; image->serial = map->serial; if ((res = map->fn(image, map->a, map->b))) return res; return vips_slist_map2(map->upstream ? image->upstream : image->downstream, (VipsSListMap2Fn) vips__link_mapp, map, NULL); } static void * vips__link_map_cb(VipsImage *image, GSList **images, void *b) { *images = g_slist_prepend(*images, image); return NULL; } /* Apply a function to an image and all upstream or downstream images, * direct and indirect. */ void * vips__link_map(VipsImage *image, gboolean upstream, VipsSListMap2Fn fn, void *a, void *b) { static int serial = 0; LinkMap map; GSList *images; GSList *p; void *result; images = NULL; /* The function might do anything, including removing images * or invalidating other images, so we can't trigger them from within * the image loop. Instead we collect a list of images, ref them, * run the functions, and unref. */ map.upstream = upstream; map.fn = (VipsSListMap2Fn) vips__link_map_cb; map.a = (void *) &images; map.b = NULL; /* We will be walking the tree of images and updating the ->serial * member. There will be intense confusion if two threads try to do * this at the same time. */ g_mutex_lock(&vips__global_lock); serial += 1; map.serial = serial; vips__link_mapp(image, &map, NULL); for (p = images; p; p = p->next) g_object_ref(p->data); g_mutex_unlock(&vips__global_lock); result = vips_slist_map2(images, fn, a, b); for (p = images; p; p = p->next) g_object_unref(p->data); g_slist_free(images); return result; } /* We have to have this as a separate entry point so we can support the old * vips7 API. */ void vips__demand_hint_array(VipsImage *image, int int_hint, VipsImage **in) { VipsDemandStyle hint = (VipsDemandStyle) int_hint; int i, len, nany; VipsDemandStyle set_hint; /* How many input images are there? And how many are ANY? */ for (i = 0, len = 0, nany = 0; in[i]; i++, len++) if (in[i]->dhint == VIPS_DEMAND_STYLE_ANY) nany++; /* Find the most restrictive of all the hints available to us. * * We have tried to be smarter about this in the past -- for example, * detecting all ANY inputs and ignoring the hint in this case, but * there are inevitably odd cases which cause problems. For example, * new_from_memory, resize, affine, write_to_memory would run with * FATSTRIP. */ set_hint = hint; for (i = 0; i < len; i++) set_hint = (VipsDemandStyle) VIPS_MIN((int) set_hint, (int) in[i]->dhint); image->dhint = set_hint; #ifdef DEBUG printf("vips_image_pipeline_array: set dhint for \"%s\" to %s\n", image->filename, vips_enum_nick(VIPS_TYPE_DEMAND_STYLE, image->dhint)); printf("\toperation requested %s\n", vips_enum_nick(VIPS_TYPE_DEMAND_STYLE, hint)); printf("\tinputs were:\n"); printf("\t"); for (i = 0; in[i]; i++) printf("%s ", vips_enum_nick(VIPS_TYPE_DEMAND_STYLE, in[i]->dhint)); printf("\n"); #endif /*DEBUG*/ /* im depends on all these ims. */ g_mutex_lock(&vips__global_lock); for (i = 0; i < len; i++) vips__link_make(in[i], image); g_mutex_unlock(&vips__global_lock); /* Set a flag on the image to say we remembered to call this thing. * vips_image_generate() and friends check this. */ image->hint_set = TRUE; } /** * vips_image_pipeline_array: * @image: (out): output image * @hint: demand hint for @image * @in: (array zero-terminated=1): `NULL`-terminated array of input images * * Add an image to a pipeline. @image depends on all of the images in @in, * @image prefers to supply pixels according to @hint. * * Operations can set demand hints, that is, hints to the VIPS IO system about * the type of region geometry they work best with. For example, * operations which transform coordinates will usually work best with * [enum@Vips.DemandStyle.SMALLTILE], operations which work on local windows of * pixels will like [enum@Vips.DemandStyle.FATSTRIP]. * * Header fields in @image are set from the fields in @in, with lower-numbered * images in @in taking priority. * For example, if @in[0] and @in[1] both have an item * called "icc-profile", it's the profile attached to @in[0] that will end up * on @image. * Image history is completely copied from all @in. @image will have the history * of all the input images. * The array of input images can be empty, meaning @image is at the start of a * pipeline. * * VIPS uses the list of input images to build the tree of operations it needs * for the cache invalidation system. * * ::: seealso * [method@Image.pipelinev], [method@Image.generate]. * * Returns: 0 on success, -1 on error. */ int vips_image_pipeline_array(VipsImage *image, VipsDemandStyle hint, VipsImage **in) { if (!vips_object_sanity(VIPS_OBJECT(image))) return -1; /* This function can be called more than once per output image. For * example, jpeg header load will call this once on ->out to set the * default hint, then later call it again to connect the output image * up to the real image. * * It's only ever called first time with in[0] == NULL and second time * with a real value for @in. */ vips__demand_hint_array(image, hint, in); if (in[0] && vips__image_copy_fields_array(image, in)) return -1; if (vips__reorder_set_input(image, in)) return -1; return 0; } /** * vips_image_pipelinev: * @image: output image of pipeline * @hint: hint for this image * @...: `NULL`-terminated list of input images * * Build an array and call [func@Image.pipeline_array]. * * ::: seealso * [method@Image.generate]. */ int vips_image_pipelinev(VipsImage *image, VipsDemandStyle hint, ...) { va_list ap; int i; VipsImage *ar[MAX_IMAGES]; va_start(ap, hint); for (i = 0; i < MAX_IMAGES && (ar[i] = va_arg(ap, VipsImage *)); i++) ; va_end(ap); if (i == MAX_IMAGES) { g_warning("too many images"); /* Make sure we have a sentinel there. */ ar[i - 1] = NULL; } return vips_image_pipeline_array(image, hint, ar); } /** * vips_start_one: * @out: image to generate * @a: user data * @b: user data * * Start function for one image in. Input image is @a. * * ::: seealso * [method@Image.generate]. */ void * vips_start_one(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; return vips_region_new(in); } /** * vips_stop_one: * @seq: sequence value * @a: user data * @b: user data * * Stop function for one image in. Input image is @a. * * ::: seealso * [method@Image.generate]. */ int vips_stop_one(void *seq, void *a, void *b) { VipsRegion *reg = (VipsRegion *) seq; g_object_unref(reg); return 0; } /** * vips_stop_many: * @seq: sequence value * @a: user data * @b: user data * * Stop function for many images in. @a is a pointer to * a `NULL`-terminated array of input images. * * ::: seealso * [method@Image.generate]. */ int vips_stop_many(void *seq, void *a, void *b) { VipsRegion **ar = (VipsRegion **) seq; if (ar) { int i; for (i = 0; ar[i]; i++) g_object_unref(ar[i]); g_free((char *) ar); } return 0; } /** * vips_start_many: * @out: image to generate * @a: user data * @b: user data * * Start function for many images in. @a is a pointer to * a `NULL`-terminated array of input images. * * ::: seealso * [method@Image.generate], [func@allocate_input_array] */ void * vips_start_many(VipsImage *out, void *a, void *b) { VipsImage **in = (VipsImage **) a; int i, n; VipsRegion **ar; /* How many images? */ for (n = 0; in[n]; n++) ; /* Allocate space for region array. */ if (!(ar = VIPS_ARRAY(NULL, n + 1, VipsRegion *))) return NULL; /* Create a set of regions. */ for (i = 0; i < n; i++) if (!(ar[i] = vips_region_new(in[i]))) { vips_stop_many(ar, NULL, NULL); return NULL; } ar[n] = NULL; return ar; } /** * vips_allocate_input_array: * @out: free array when this image closes * @...: `NULL`-terminated list of input images * * Convenience function -- make a `NULL`-terminated array of input images. * Use with [func@start_many]. * * ::: seealso * [method@Image.generate], [func@start_many]. * * Returns: (transfer none) (nullable): `NULL`-terminated array of images. * Do not free the result. */ VipsImage ** vips_allocate_input_array(VipsImage *out, ...) { va_list ap; VipsImage **ar; int i, n; /* Count input images. */ va_start(ap, out); for (n = 0; va_arg(ap, VipsImage *); n++) ; va_end(ap); /* Allocate array. */ if (!(ar = VIPS_ARRAY(out, n + 1, VipsImage *))) return NULL; /* Fill array. */ va_start(ap, out); for (i = 0; i < n; i++) ar[i] = va_arg(ap, VipsImage *); va_end(ap); ar[n] = NULL; return ar; } /** * VipsStartFn: * @out: image being calculated * @a: user data * @b: user data * * Start a new processing sequence for this generate function. This allocates * per-thread state, such as an input region. * * ::: seealso * [func@start_one], [func@start_many]. * * Returns: a new sequence value */ /** * VipsGenerateFn: * @out: [class@Region] to fill * @seq: sequence value * @a: user data * @b: user data * @stop: set this to stop processing * * Fill @out->valid with pixels. @seq contains per-thread state, such as the * input regions. Set @stop to `TRUE` to stop processing. * * ::: seealso * [method@Image.generate], [func@stop_many]. * * Returns: 0 on success, -1 on error. */ /** * VipsStopFn: * @seq: sequence value * @a: user data * @b: user data * * Stop a processing sequence. This frees * per-thread state, such as an input region. * * ::: seealso * [func@stop_one], [func@stop_many]. * * Returns: 0 on success, -1 on error. */ /* A write function for VIPS images. Just write() the pixel data. */ static int write_vips(VipsRegion *region, VipsRect *area, void *a) { size_t count; void *buf; count = (size_t) region->bpl * area->height; buf = VIPS_REGION_ADDR(region, 0, area->top); do { // write() uses int not size_t on windows, so we need to chunk // ... max 1gb, why not int chunk_size = VIPS_MIN(1024 * 1024 * 1024, count); gint64 nwritten = write(region->im->fd, buf, chunk_size); /* n == 0 isn't strictly an error, but we treat it as * one to make sure we don't get stuck in this loop. */ if (nwritten <= 0) return errno; buf = (void *) ((char *) buf + nwritten); count -= nwritten; } while (count > 0); return 0; } /** * vips_image_generate: * @image: generate this image * @start_fn: (scope async): start sequences with this function * @generate_fn: (scope async): generate pixels with this function * @stop_fn: (scope async): stop sequences with this function * @a: user data * @b: user data * * Generates an image. The action depends on the image type. * * For images created with [ctor@Image.new], [method@Image.generate] just * attaches the start/generate/stop callbacks and returns. * * For images created with [ctor@Image.new_memory], memory is allocated for * the whole image and it is entirely generated using [func@sink_memory]. * * For images created with [ctor@Image.new_temp_file] and friends, memory for * a few scanlines is allocated and * [method@Image.sink_disc] used to generate the image in small chunks. As each * chunk is generated, it is written to disc. * * ::: seealso * [func@sink_memory], [ctor@Image.new], [method@Region.prepare]. * * Returns: 0 on success, or -1 on error. */ int vips_image_generate(VipsImage *image, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b) { int res; VIPS_DEBUG_MSG("vips_image_generate: %p\n", image); g_assert(generate_fn); if (!vips_object_sanity(VIPS_OBJECT(image))) return -1; if (!image->hint_set) { vips_error("vips_image_generate", "%s", _("demand hint not set")); return -1; } /* We don't use this, but make sure it's set in case any old binaries * are expecting it. */ image->Bbits = vips_format_sizeof(image->BandFmt) << 3; /* Look at output type to decide our action. */ switch (image->dtype) { case VIPS_IMAGE_PARTIAL: /* Output to partial image. Just attach functions and return. */ if (image->generate_fn || image->start_fn || image->stop_fn) { vips_error("VipsImage", "%s", _("generate() called twice")); return -1; } image->start_fn = start_fn; image->generate_fn = generate_fn; image->stop_fn = stop_fn; image->client1 = a; image->client2 = b; VIPS_DEBUG_MSG("vips_image_generate: " "attaching partial callbacks\n"); if (vips_image_written(image)) return -1; break; case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: case VIPS_IMAGE_MMAPINRW: case VIPS_IMAGE_OPENOUT: /* Eval now .. sanity check. */ if (image->generate_fn || image->start_fn || image->stop_fn) { vips_error("VipsImage", "%s", _("generate() called twice")); return -1; } /* Attach callbacks. */ image->start_fn = start_fn; image->generate_fn = generate_fn; image->stop_fn = stop_fn; image->client1 = a; image->client2 = b; if (vips_image_write_prepare(image)) return -1; if (image->dtype == VIPS_IMAGE_OPENOUT) res = vips_sink_disc(image, write_vips, NULL); else res = vips_sink_memory(image); /* Error? */ if (res) return -1; /* Must come before we rewind. */ if (vips_image_written(image)) return -1; /* We've written to image ... rewind it ready for reading. */ if (vips_image_pio_input(image)) return -1; break; default: /* Not a known output style. */ vips_error("VipsImage", _("unable to output to a %s image"), vips_enum_nick(VIPS_TYPE_IMAGE_TYPE, image->dtype)); return -1; } return 0; } libvips-8.18.2/libvips/iofuncs/ginputsource.c000066400000000000000000000156611516303661500213120ustar00rootroot00000000000000/* A GInputStream that links to a VipsSource under the hood. * * 10/11/19 kleisauke */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include static void vips_g_input_stream_seekable_iface_init(GSeekableIface *iface); G_DEFINE_TYPE_WITH_CODE(VipsGInputStream, vips_g_input_stream, G_TYPE_INPUT_STREAM, G_IMPLEMENT_INTERFACE(G_TYPE_SEEKABLE, vips_g_input_stream_seekable_iface_init)) enum { PROP_0, PROP_STREAM }; static void vips_g_input_stream_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(object); switch (prop_id) { case PROP_STREAM: g_value_set_object(value, gstream->source); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } } static void vips_g_input_stream_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(object); switch (prop_id) { case PROP_STREAM: gstream->source = g_value_dup_object(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } } static void vips_g_input_stream_finalize(GObject *object) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(object); VIPS_UNREF(gstream->source); G_OBJECT_CLASS(vips_g_input_stream_parent_class)->finalize(object); } static goffset vips_g_input_stream_tell(GSeekable *seekable) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(seekable); goffset pos; VIPS_DEBUG_MSG("vips_g_input_stream_tell:\n"); pos = vips_source_seek(gstream->source, 0, SEEK_CUR); if (pos == -1) return 0; return pos; } static gboolean vips_g_input_stream_can_seek(GSeekable *seekable) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(seekable); VIPS_DEBUG_MSG("vips_g_input_stream_can_seek: %d\n", !gstream->source->is_pipe); return !gstream->source->is_pipe; } static int seek_type_to_lseek(GSeekType type) { switch (type) { default: case G_SEEK_CUR: return SEEK_CUR; case G_SEEK_SET: return SEEK_SET; case G_SEEK_END: return SEEK_END; } } static gboolean vips_g_input_stream_seek(GSeekable *seekable, goffset offset, GSeekType type, GCancellable *cancellable, GError **error) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(seekable); VIPS_DEBUG_MSG( "vips_g_input_stream_seek: offset = %" G_GINT64_FORMAT ", type = %d\n", offset, type); if (vips_source_seek(gstream->source, offset, seek_type_to_lseek(type)) == -1) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Error while seeking: %s"), vips_error_buffer()); return FALSE; } return TRUE; } static gboolean vips_g_input_stream_can_truncate(GSeekable *seekable) { return FALSE; } static gboolean vips_g_input_stream_truncate(GSeekable *seekable, goffset offset, GCancellable *cancellable, GError **error) { g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Cannot truncate VipsGInputStream")); return FALSE; } static gssize vips_g_input_stream_read(GInputStream *stream, void *buffer, gsize count, GCancellable *cancellable, GError **error) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(stream); gssize res; VIPS_DEBUG_MSG("vips_g_input_stream_read: count: %zd\n", count); if (g_cancellable_set_error_if_cancelled(cancellable, error)) return -1; if ((res = vips_source_read(gstream->source, buffer, count)) == -1) g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Error while reading: %s"), vips_error_buffer()); return res; } static gssize vips_g_input_stream_skip(GInputStream *stream, gsize count, GCancellable *cancellable, GError **error) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(stream); gssize position; VIPS_DEBUG_MSG("vips_g_input_stream_skip: count: %zd\n", count); if (g_cancellable_set_error_if_cancelled(cancellable, error)) return -1; position = vips_source_seek(gstream->source, count, SEEK_CUR); if (position == -1) { g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Error while seeking: %s"), vips_error_buffer()); return -1; } return position; } static gboolean vips_g_input_stream_close(GInputStream *stream, GCancellable *cancellable, GError **error) { VipsGInputStream *gstream = VIPS_G_INPUT_STREAM(stream); vips_source_minimise(gstream->source); return TRUE; } static void vips_g_input_stream_seekable_iface_init(GSeekableIface *iface) { iface->tell = vips_g_input_stream_tell; iface->can_seek = vips_g_input_stream_can_seek; iface->seek = vips_g_input_stream_seek; iface->can_truncate = vips_g_input_stream_can_truncate; iface->truncate_fn = vips_g_input_stream_truncate; } static void vips_g_input_stream_class_init(VipsGInputStreamClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS(class); gobject_class->finalize = vips_g_input_stream_finalize; gobject_class->get_property = vips_g_input_stream_get_property; gobject_class->set_property = vips_g_input_stream_set_property; istream_class->read_fn = vips_g_input_stream_read; istream_class->skip = vips_g_input_stream_skip; istream_class->close_fn = vips_g_input_stream_close; g_object_class_install_property(gobject_class, PROP_STREAM, g_param_spec_object("input", _("Input"), _("Stream to wrap"), VIPS_TYPE_SOURCE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void vips_g_input_stream_init(VipsGInputStream *gstream) { } /** * vips_g_input_stream_new_from_source: * @source: vips source to wrap * * Create a new [class@Gio.InputStream] wrapping a [class@Source]. This is * useful for loaders like SVG and PDF which support [class@Gio.InputStream] * methods. * * ::: seealso * [ctor@SourceGInputStream.new] * * Returns: (transfer full): a new [class@Gio.InputStream] */ GInputStream * vips_g_input_stream_new_from_source(VipsSource *source) { return g_object_new(VIPS_TYPE_G_INPUT_STREAM, "input", source, NULL); } libvips-8.18.2/libvips/iofuncs/header.c000066400000000000000000001567111516303661500200150ustar00rootroot00000000000000/* get, set and copy image header fields * * 9/7/02 JC * - first version * 7/6/05 * - now reads meta fields too * - cleaned up * - added im_header_exists(), im_header_map() * 1/8/05 * - now im_header_get_type() and im_header_get() rather than * im_header_exists() * 4/1/07 * - removed Hist from standard fields ... now a separate function * 29/8/09 * - im_header_get_type() renamed as im_header_get_typeof() to prevent * confusion with GObject-style type definers * 1/10/09 * - rename as header.c * - gtkdoc comments * 22/3/11 * - rename fields for vips8 * - move to vips_ prefix * 16/7/15 * - auto wrap GString as RefString * 20/10/16 * - return header enums as enums, not ints * - vips_image_get_*() all convert everything to target type if they can * - rename "field" as "name" in docs * 21/11/18 * - get_string will allow G_STRING and REF_STRING * 28/12/18 * - hide deprecated header fields from _map * 17/2/19 * - add vips_image_get_page_height() * 19/6/19 * - add vips_image_get_n_pages() * 20/6/19 * - add vips_image_get/set_array_int() * 31/1/19 * - lock for metadata changes */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #define VIPS_DISABLE_DEPRECATION_WARNINGS #include #include #include /* Use in various small places where we need a mutex and it's not worth * making a private one. */ static GMutex vips__meta_lock; /* We have to keep the gtype as a string, since we statically init this. */ typedef struct _HeaderField { const char *name; const char *type; glong offset; } HeaderField; /* Built in fields and struct offsets. */ static HeaderField vips_header_fields[] = { { "width", "gint", G_STRUCT_OFFSET(VipsImage, Xsize) }, { "height", "gint", G_STRUCT_OFFSET(VipsImage, Ysize) }, { "bands", "gint", G_STRUCT_OFFSET(VipsImage, Bands) }, { "format", "VipsBandFormat", G_STRUCT_OFFSET(VipsImage, BandFmt) }, { "coding", "VipsCoding", G_STRUCT_OFFSET(VipsImage, Coding) }, { "interpretation", "VipsInterpretation", G_STRUCT_OFFSET(VipsImage, Type) }, { "xoffset", "gint", G_STRUCT_OFFSET(VipsImage, Xoffset) }, { "yoffset", "gint", G_STRUCT_OFFSET(VipsImage, Yoffset) }, { "xres", "gdouble", G_STRUCT_OFFSET(VipsImage, Xres) }, { "yres", "gdouble", G_STRUCT_OFFSET(VipsImage, Yres) }, { "filename", "gchararray", G_STRUCT_OFFSET(VipsImage, filename) } }; /* Old names we keep around for back-compat. We never loop over these with * map, but we do check them when we look up fields by name. */ static HeaderField vips_header_fields_old[] = { { "Xsize", "gint", G_STRUCT_OFFSET(VipsImage, Xsize) }, { "Ysize", "gint", G_STRUCT_OFFSET(VipsImage, Ysize) }, { "Bands", "gint", G_STRUCT_OFFSET(VipsImage, Bands) }, { "Bbits", "gint", G_STRUCT_OFFSET(VipsImage, Bbits) }, { "BandFmt", "gint", G_STRUCT_OFFSET(VipsImage, BandFmt) }, { "Coding", "gint", G_STRUCT_OFFSET(VipsImage, Coding) }, { "Type", "gint", G_STRUCT_OFFSET(VipsImage, Type) }, { "Xoffset", "gint", G_STRUCT_OFFSET(VipsImage, Xoffset) }, { "Yoffset", "gint", G_STRUCT_OFFSET(VipsImage, Yoffset) }, { "Xres", "gdouble", G_STRUCT_OFFSET(VipsImage, Xres) }, { "Yres", "gdouble", G_STRUCT_OFFSET(VipsImage, Yres) } }; /* This is used by (eg.) VIPS_IMAGE_SIZEOF_ELEMENT() to calculate object * size via vips_format_sizeof(). * * It needs to be guint64 and not size_t since we use this as the basis for * image address calcs and they have to be 64-bit, even on 32-bit machines. * * Can't be static, we need this to be visible for vips7 compat. */ const guint64 vips__image_sizeof_bandformat[] = { sizeof(unsigned char), /* VIPS_FORMAT_UCHAR */ sizeof(signed char), /* VIPS_FORMAT_CHAR */ sizeof(unsigned short), /* VIPS_FORMAT_USHORT */ sizeof(unsigned short), /* VIPS_FORMAT_SHORT */ sizeof(unsigned int), /* VIPS_FORMAT_UINT */ sizeof(unsigned int), /* VIPS_FORMAT_INT */ sizeof(float), /* VIPS_FORMAT_FLOAT */ 2 * sizeof(float), /* VIPS_FORMAT_COMPLEX */ sizeof(double), /* VIPS_FORMAT_DOUBLE */ 2 * sizeof(double) /* VIPS_FORMAT_DPCOMPLEX */ }; /** * vips_format_sizeof: * @format: format type * * Returns: number of bytes for a band format. */ guint64 vips_format_sizeof(VipsBandFormat format) { format = VIPS_CLIP(0, format, VIPS_FORMAT_DPCOMPLEX); return vips__image_sizeof_bandformat[format]; } /** * vips_format_sizeof_unsafe: (skip) * @format: format type * * A fast but dangerous version of [func@format_sizeof]. You must have * previously range-checked @format or you'll crash. * * Returns: number of bytes for a band format. */ guint64 vips_format_sizeof_unsafe(VipsBandFormat format) { g_assert(0 <= format && format <= VIPS_FORMAT_DPCOMPLEX); return vips__image_sizeof_bandformat[format]; } /** * vips_interpretation_max_alpha: * @interpretation: image interpretation * * Returns: the maximum alpha value for an interpretation. */ double vips_interpretation_max_alpha(VipsInterpretation interpretation) { switch (interpretation) { case VIPS_INTERPRETATION_GREY16: case VIPS_INTERPRETATION_RGB16: return 65535.0; case VIPS_INTERPRETATION_scRGB: return 1.0; default: return 255.0; } } /** * vips_interpretation_bands: * @interpretation: image to check * * The number of "real" bands we expect for this interpretation. If we've no * idea (eg. MULTIBAND), return 0. * * Returns: the number of bands implied by this interpretation, or 0. */ int vips_interpretation_bands(VipsInterpretation interpretation) { switch (interpretation) { case VIPS_INTERPRETATION_B_W: case VIPS_INTERPRETATION_GREY16: return 1; case VIPS_INTERPRETATION_RGB: case VIPS_INTERPRETATION_CMC: case VIPS_INTERPRETATION_LCH: case VIPS_INTERPRETATION_LABS: case VIPS_INTERPRETATION_sRGB: case VIPS_INTERPRETATION_YXY: case VIPS_INTERPRETATION_XYZ: case VIPS_INTERPRETATION_LAB: case VIPS_INTERPRETATION_RGB16: case VIPS_INTERPRETATION_scRGB: case VIPS_INTERPRETATION_HSV: case VIPS_INTERPRETATION_OKLAB: case VIPS_INTERPRETATION_OKLCH: return 3; case VIPS_INTERPRETATION_CMYK: return 4; default: /* We can't really guess bands for things like HISTOGRAM or FOURIER or * MULTIBAND. */ return 0; } } #ifdef DEBUG /* Check that this meta is on the hash table. */ static void * meta_sanity_on_hash(VipsMeta *meta, VipsImage *im, void *b) { VipsMeta *found; if (meta->im != im) printf("*** field \"%s\" has incorrect im\n", meta->name); if (!(found = g_hash_table_lookup(im->meta, meta->name))) printf("*** field \"%s\" is on traverse but not in hash\n", meta->name); if (found != meta) printf("*** meta \"%s\" on traverse and hash do not match\n", meta->name); return NULL; } static void meta_sanity_on_traverse(const char *name, VipsMeta *meta, VipsImage *im) { if (meta->name != name) printf("*** field \"%s\" has incorrect name\n", meta->name); if (meta->im != im) printf("*** field \"%s\" has incorrect im\n", meta->name); if (!g_slist_find(im->meta_traverse, meta)) printf("*** field \"%s\" is in hash but not on traverse\n", meta->name); } static void meta_sanity(const VipsImage *im) { if (im->meta) g_hash_table_foreach(im->meta, (GHFunc) meta_sanity_on_traverse, (void *) im); vips_slist_map2(im->meta_traverse, (VipsSListMap2Fn) meta_sanity_on_hash, (void *) im, NULL); } #endif /*DEBUG*/ static void meta_free(VipsMeta *meta) { #ifdef DEBUG { char *str_value; str_value = g_strdup_value_contents(&meta->value); printf("meta_free: name %s, value = %s\n", meta->name, str_value); g_free(str_value); } #endif /*DEBUG*/ if (meta->im) meta->im->meta_traverse = g_slist_remove(meta->im->meta_traverse, meta); g_value_unset(&meta->value); g_free(meta->name); g_free(meta); } static VipsMeta * meta_new(VipsImage *image, const char *name, GValue *value) { VipsMeta *meta; meta = g_new(VipsMeta, 1); meta->im = image; meta->name = NULL; memset(&meta->value, 0, sizeof(GValue)); meta->name = g_strdup(name); /* Special case: we don't want to have G_STRING on meta. They will be * copied down pipelines, plus some of our API (like * vips_image_get_string()) assumes that the GValue is a refstring and * that read-only pointers can be handed out. * * Turn G_TYPE_STRING into VIPS_TYPE_REF_STRING. */ if (G_VALUE_TYPE(value) == G_TYPE_STRING) g_value_init(&meta->value, VIPS_TYPE_REF_STRING); else g_value_init(&meta->value, G_VALUE_TYPE(value)); /* We don't do any conversions that can fail. */ (void) g_value_transform(value, &meta->value); image->meta_traverse = g_slist_append(image->meta_traverse, meta); g_hash_table_replace(image->meta, meta->name, meta); #ifdef DEBUG { char *str_value; str_value = g_strdup_value_contents(value); printf("meta_new: name %s, value = %s\n", name, str_value); g_free(str_value); } #endif /*DEBUG*/ return meta; } /* Destroy all the meta on an image. */ void vips__meta_destroy(VipsImage *image) { VIPS_FREEF(g_hash_table_destroy, image->meta); g_assert(!image->meta_traverse); } static void meta_init(VipsImage *im) { if (!im->meta) { g_assert(!im->meta_traverse); im->meta = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) meta_free); } } /** * vips_image_get_width: * @image: image to get from * * Returns: the number of pixels across the image. */ int vips_image_get_width(const VipsImage *image) { return image->Xsize; } /** * vips_image_get_height: * @image: image to get from * * Returns: the number of pixels down the image. */ int vips_image_get_height(const VipsImage *image) { return image->Ysize; } /** * vips_image_get_bands: * @image: image to get from * * Returns: the number of bands (channels) in the image. */ int vips_image_get_bands(const VipsImage *image) { return image->Bands; } /** * vips_image_get_format: * @image: image to get from * * Returns: the format of each band element. */ VipsBandFormat vips_image_get_format(const VipsImage *image) { return image->BandFmt; } /** * vips_image_get_format_max: * @format: the format * * Returns: the maximum numeric value possible for this format. */ double vips_image_get_format_max(VipsBandFormat format) { switch (format) { case VIPS_FORMAT_UCHAR: return UCHAR_MAX; case VIPS_FORMAT_CHAR: return SCHAR_MAX; case VIPS_FORMAT_USHORT: return USHRT_MAX; case VIPS_FORMAT_SHORT: return SHRT_MAX; case VIPS_FORMAT_UINT: return UINT_MAX; case VIPS_FORMAT_INT: return INT_MAX; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: return FLT_MAX; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: return DBL_MAX; default: return -1; } } /** * vips_image_guess_format: * @image: image to guess for * * Return the [enum@BandFormat] for an image, guessing a sane value if * the set value looks crazy. * * For example, for a float image tagged as rgb16, we'd return ushort. * * Returns: a sensible [enum@BandFormat] for the image. */ VipsBandFormat vips_image_guess_format(const VipsImage *image) { VipsBandFormat format; /* Stop a compiler warning. */ format = VIPS_FORMAT_UCHAR; switch (image->Type) { case VIPS_INTERPRETATION_FOURIER: if (image->BandFmt == VIPS_FORMAT_DOUBLE || image->BandFmt == VIPS_FORMAT_DPCOMPLEX) format = VIPS_FORMAT_DPCOMPLEX; else format = VIPS_FORMAT_COMPLEX; break; case VIPS_INTERPRETATION_sRGB: case VIPS_INTERPRETATION_RGB: format = VIPS_FORMAT_UCHAR; break; case VIPS_INTERPRETATION_XYZ: case VIPS_INTERPRETATION_LAB: case VIPS_INTERPRETATION_CMC: case VIPS_INTERPRETATION_LCH: case VIPS_INTERPRETATION_HSV: case VIPS_INTERPRETATION_scRGB: case VIPS_INTERPRETATION_YXY: case VIPS_INTERPRETATION_OKLAB: case VIPS_INTERPRETATION_OKLCH: format = VIPS_FORMAT_FLOAT; break; case VIPS_INTERPRETATION_CMYK: if (image->BandFmt == VIPS_FORMAT_USHORT) format = VIPS_FORMAT_USHORT; else format = VIPS_FORMAT_UCHAR; break; case VIPS_INTERPRETATION_LABQ: format = VIPS_FORMAT_UCHAR; break; case VIPS_INTERPRETATION_LABS: format = VIPS_FORMAT_SHORT; break; case VIPS_INTERPRETATION_GREY16: case VIPS_INTERPRETATION_RGB16: format = VIPS_FORMAT_USHORT; break; case VIPS_INTERPRETATION_MATRIX: if (image->BandFmt == VIPS_FORMAT_DOUBLE) format = VIPS_FORMAT_DOUBLE; else format = VIPS_FORMAT_FLOAT; break; case VIPS_INTERPRETATION_B_W: case VIPS_INTERPRETATION_HISTOGRAM: case VIPS_INTERPRETATION_MULTIBAND: default: // for eg. INTERPRETATION_ERROR, stick with the format we have format = image->BandFmt; break; } return format; } /** * vips_image_get_coding: * @image: image to get from * * Returns: the [enum@Coding] from the image header. */ VipsCoding vips_image_get_coding(const VipsImage *image) { return image->Coding; } /** * vips_image_get_interpretation: * @image: image to get from * * Return the [enum@Interpretation] set in the image header. * Use [method@Image.guess_format] if you want a sanity-checked value. * * Returns: the [enum@Interpretation] from the image header. */ VipsInterpretation vips_image_get_interpretation(const VipsImage *image) { return image->Type; } /* Try to guess a sane value for interpretation. */ static VipsInterpretation vips_image_default_interpretation(const VipsImage *image) { switch (image->Coding) { case VIPS_CODING_LABQ: return VIPS_INTERPRETATION_LABQ; case VIPS_CODING_RAD: return VIPS_INTERPRETATION_sRGB; default: break; } switch (image->BandFmt) { case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_SHORT: case VIPS_FORMAT_UINT: case VIPS_FORMAT_INT: case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_DOUBLE: switch (image->Bands) { case 1: case 2: return VIPS_INTERPRETATION_B_W; case 3: case 4: // we don't send float/double to scrgb, that's very likely to // cause much more confusion, since "linear" makes float rgg all // the time // // we do send u16 to rgb16/grey16 since that's a common case, // see below return VIPS_INTERPRETATION_sRGB; default: return VIPS_INTERPRETATION_MULTIBAND; } case VIPS_FORMAT_CHAR: switch (image->Bands) { case 1: return VIPS_INTERPRETATION_MATRIX; default: return VIPS_INTERPRETATION_MULTIBAND; } case VIPS_FORMAT_USHORT: switch (image->Bands) { case 1: case 2: return VIPS_INTERPRETATION_GREY16; case 3: case 4: return VIPS_INTERPRETATION_RGB16; default: return VIPS_INTERPRETATION_MULTIBAND; } case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: return VIPS_INTERPRETATION_FOURIER; default: return VIPS_INTERPRETATION_MULTIBAND; } } /** * vips_image_guess_interpretation: * @image: image to guess for * * Return the [enum@Interpretation] for an image, guessing a sane value if * the set value looks crazy. * * Returns: a sensible [enum@Interpretation] for the image. */ VipsInterpretation vips_image_guess_interpretation(const VipsImage *image) { gboolean sane; sane = TRUE; /* Coding overrides interpretation. */ switch (image->Coding) { case VIPS_CODING_ERROR: sane = FALSE; break; case VIPS_CODING_LABQ: if (image->Type != VIPS_INTERPRETATION_LABQ) sane = FALSE; break; case VIPS_CODING_RAD: if (image->Type != VIPS_INTERPRETATION_sRGB) sane = FALSE; break; default: break; } /* If we have eg. a two-band sRGB, we are crazy. */ if (image->Bands < vips_interpretation_bands(image->Type)) sane = FALSE; switch (image->Type) { case VIPS_INTERPRETATION_ERROR: sane = FALSE; break; case VIPS_INTERPRETATION_MULTIBAND: /* This is a pretty useless generic tag. Always reset it. */ sane = FALSE; break; case VIPS_INTERPRETATION_HISTOGRAM: if (image->Xsize > 1 && image->Ysize > 1) sane = FALSE; break; case VIPS_INTERPRETATION_FOURIER: if (!vips_band_format_iscomplex(image->BandFmt)) sane = FALSE; break; case VIPS_INTERPRETATION_scRGB: case VIPS_INTERPRETATION_YXY: case VIPS_INTERPRETATION_OKLAB: case VIPS_INTERPRETATION_OKLCH: /* Need float values in 0 - 1. */ if (!vips_band_format_isfloat(image->BandFmt)) sane = FALSE; break; case VIPS_INTERPRETATION_LABQ: if (image->Coding != VIPS_CODING_LABQ) sane = FALSE; break; case VIPS_INTERPRETATION_LABS: /* Needs to be able to express +/- 32767 */ if (vips_band_format_isuint(image->BandFmt) || vips_band_format_is8bit(image->BandFmt)) sane = FALSE; break; case VIPS_INTERPRETATION_RGB16: case VIPS_INTERPRETATION_GREY16: if (vips_band_format_is8bit(image->BandFmt)) sane = FALSE; break; default: break; } if (sane) return vips_image_get_interpretation(image); else return vips_image_default_interpretation(image); } /** * vips_image_get_xres: * @image: image to get from * * Returns: the horizontal image resolution in pixels per millimeter. */ double vips_image_get_xres(const VipsImage *image) { return image->Xres; } /** * vips_image_get_yres: * @image: image to get from * * Returns: the vertical image resolution in pixels per millimeter. */ double vips_image_get_yres(const VipsImage *image) { return image->Yres; } /** * vips_image_get_xoffset: * @image: image to get from * * Returns: the horizontal position of the image origin, in pixels. */ int vips_image_get_xoffset(const VipsImage *image) { return image->Xoffset; } /** * vips_image_get_yoffset: * @image: image to get from * * Returns: the vertical position of the image origin, in pixels. */ int vips_image_get_yoffset(const VipsImage *image) { return image->Yoffset; } /** * vips_image_get_filename: * @image: image to get from * * Returns: the name of the file the image was loaded from, or `NULL` if * there is no filename. */ const char * vips_image_get_filename(const VipsImage *image) { return image->filename; } /** * vips_image_get_mode: * @image: image to get from * * Image modes are things like `"t"`, meaning a memory buffer, and `"p"` * meaning a delayed computation. * * Returns: the image mode. */ const char * vips_image_get_mode(const VipsImage *image) { return image->mode; } /** * vips_image_get_scale: * @image: image to get from * * Matrix images can have an optional `scale` field for use by integer * convolution. * * Returns: the scale. */ double vips_image_get_scale(const VipsImage *image) { double scale; scale = 1.0; if (vips_image_get_typeof(image, "scale")) vips_image_get_double(image, "scale", &scale); return scale; } /** * vips_image_get_offset: * @image: image to get from * * Matrix images can have an optional `offset` field for use by integer * convolution. * * Returns: the offset. */ double vips_image_get_offset(const VipsImage *image) { double offset; offset = 0.0; if (vips_image_get_typeof(image, "offset")) vips_image_get_double(image, "offset", &offset); return offset; } /** * vips_image_get_page_height: * @image: image to get from * * Multi-page images can have a page height. Fetch it, and sanity check it. If * page-height is not set, it defaults to the image height. * * Returns: the page height. */ int vips_image_get_page_height(VipsImage *image) { int page_height; if (vips_image_get_typeof(image, VIPS_META_PAGE_HEIGHT) && !vips_image_get_int(image, VIPS_META_PAGE_HEIGHT, &page_height) && page_height > 0 && page_height < image->Ysize && image->Ysize % page_height == 0) return page_height; return image->Ysize; } /** * vips_image_get_n_pages: * @image: image to get from * * Fetch and sanity-check [const@META_N_PAGES]. Default to 1 if not present * or crazy. * * This is the number of pages in the image file, not the number of pages that * have been loaded into @image. * * Returns: the number of pages in the image file */ int vips_image_get_n_pages(VipsImage *image) { int n_pages; if (vips_image_get_typeof(image, VIPS_META_N_PAGES) && !vips_image_get_int(image, VIPS_META_N_PAGES, &n_pages) && n_pages > 1 && n_pages < 10000) return n_pages; return 1; } /** * vips_image_get_concurrency: * @image: image to get from * * Fetch and sanity-check [const@META_CONCURRENCY]. Default to 1 if not * present or crazy. * * Returns: the suggested concurrency for this image */ int vips_image_get_concurrency(VipsImage *image, int default_concurrency) { int concurrency; if (vips_image_get_typeof(image, VIPS_META_CONCURRENCY) && !vips_image_get_int(image, VIPS_META_CONCURRENCY, &concurrency) && concurrency >= 1 && concurrency < 100) return concurrency; return default_concurrency; } /** * vips_image_get_n_subifds: * @image: image to get from * * Fetch and sanity-check [const@META_N_SUBIFDS]. Default to 0 if not * present or crazy. * * Returns: the number of subifds in the image file */ int vips_image_get_n_subifds(VipsImage *image) { int n_subifds; if (vips_image_get_typeof(image, VIPS_META_N_SUBIFDS) && !vips_image_get_int(image, VIPS_META_N_SUBIFDS, &n_subifds) && n_subifds > 1 && n_subifds < 1000) return n_subifds; return 0; } /** * vips_image_get_orientation: * @image: image to get from * * Fetch and sanity-check [const@META_ORIENTATION]. Default to 1 (no rotate, * no flip) if not present or crazy. * * Returns: the image orientation. */ int vips_image_get_orientation(VipsImage *image) { int orientation; if (vips_image_get_typeof(image, VIPS_META_ORIENTATION) && !vips_image_get_int(image, VIPS_META_ORIENTATION, &orientation) && orientation > 0 && orientation < 9) return orientation; return 1; } /** * vips_image_get_orientation_swap: * @image: image to get from * * Return `TRUE` if applying the orientation would swap width and height. * * Returns: if width/height will swap */ gboolean vips_image_get_orientation_swap(VipsImage *image) { int orientation = vips_image_get_orientation(image); return orientation >= 5 && orientation <= 8; } /** * vips_image_get_tile_width: * @image: image to get from * * Fetch and sanity-check [const@META_TILE_WIDTH]. Default to -1 (no tiling) * if not present or crazy. * * Returns: the width of the tiles encoded in the image. */ int vips_image_get_tile_width(VipsImage *image) { int tile_width; if (vips_image_get_typeof(image, VIPS_META_TILE_WIDTH) && !vips_image_get_int(image, VIPS_META_TILE_WIDTH, &tile_width) && tile_width > 0 && tile_width <= vips_image_get_width(image)) return tile_width; return -1; } /** * vips_image_get_tile_height: * @image: image to get from * * Fetch and sanity-check [const@META_TILE_HEIGHT]. Default to -1 (no tiling) * if not present or crazy. * * Returns: the height of the tiles encoded in the image. */ int vips_image_get_tile_height(VipsImage *image) { int tile_height; if (vips_image_get_typeof(image, VIPS_META_TILE_HEIGHT) && !vips_image_get_int(image, VIPS_META_TILE_HEIGHT, &tile_height) && tile_height > 0 && tile_height <= vips_image_get_height(image)) return tile_height; return -1; } /** * vips_image_get_gainmap: * @image: image to get the gainmap from * * If the image has an attached `"gainmap"`, return that. If there's a * compressed `"gainmap-data"`, decompress, and return it. * * You need to free the result with [method@GObject.Object.unref] when * you're done with it. * * Returns: (nullable) (transfer full): the gainmap image, if present, or NULL. */ VipsImage * vips_image_get_gainmap(VipsImage *image) { VipsImage *gainmap; gainmap = NULL; if (vips_image_get_typeof(image, "gainmap")) { if (vips_image_get_image(image, "gainmap", &gainmap)) return NULL; } else if (vips_image_get_typeof(image, "gainmap-data")) { const void *data; size_t length; if (vips_image_get_blob(image, "gainmap-data", &data, &length) || vips_jpegload_buffer((void *) data, length, &gainmap, NULL)) return NULL; } return gainmap; } /** * vips_image_get_data: * @image: image to get data for * * Return a pointer to the image's pixel data, if possible. This can involve * allocating large amounts of memory and performing a long computation. Image * pixels are laid out in band-packed rows. * * Since this function modifies @image, it is not threadsafe. Only call it on * images which you are sure have not been shared with another thread. * * ::: seealso * [method@Image.wio_input], [method@Image.copy_memory]. * * Returns: (nullable) (transfer none): a pointer to pixel data, if possible. */ const void * vips_image_get_data(VipsImage *image) { if (vips_image_wio_input(image)) return NULL; return image->data; } /** * vips_image_init_fields: * @image: image to init * @xsize: image width * @ysize: image height * @bands: image bands * @format: band format * @coding: image coding * @interpretation: image type * @xres: horizontal resolution, pixels per millimetre * @yres: vertical resolution, pixels per millimetre * * A convenience function to set the header fields after creating an image. * Normally you copy the fields from your input images with * [method.Image.pipelinev] and then make any adjustments you need, * but if you are creating an image from scratch, for example * [ctor@Image.black] or [ctor@Image.jpegload], you do need to set all the * fields yourself. * * ::: seealso * [method.Image.pipelinev]. */ void vips_image_init_fields(VipsImage *image, int xsize, int ysize, int bands, VipsBandFormat format, VipsCoding coding, VipsInterpretation interpretation, double xres, double yres) { g_object_set(image, "width", xsize, "height", ysize, "bands", bands, "format", format, NULL); image->Coding = coding; image->Type = interpretation; image->Xres = VIPS_MAX(0, xres); image->Yres = VIPS_MAX(0, yres); } static void * meta_cp_field(VipsMeta *meta, VipsImage *dst, void *b) { #ifdef DEBUG { char *str_value; str_value = g_strdup_value_contents(&meta->value); printf("vips__meta_cp: copying name %s, value = %s\n", meta->name, str_value); g_free(str_value); } #endif /*DEBUG*/ (void) meta_new(dst, meta->name, &meta->value); #ifdef DEBUG meta_sanity(dst); #endif /*DEBUG*/ return NULL; } /* Copy meta on to dst. */ int vips__image_meta_copy(VipsImage *dst, const VipsImage *src) { if (src->meta) { /* We lock with vips_image_set() to stop races in highly- * threaded applications. */ g_mutex_lock(&vips__meta_lock); meta_init(dst); vips_slist_map2(src->meta_traverse, (VipsSListMap2Fn) meta_cp_field, dst, NULL); g_mutex_unlock(&vips__meta_lock); } return 0; } /* We have to have this as a separate entry point so we can support the old * vips7 API. */ int vips__image_copy_fields_array(VipsImage *out, VipsImage *in[]) { int i; int ni; g_assert(in[0]); /* Copy magic too, handy for knowing the original image's byte order. */ out->magic = in[0]->magic; out->Xsize = in[0]->Xsize; out->Ysize = in[0]->Ysize; out->Bands = in[0]->Bands; out->Bbits = in[0]->Bbits; out->BandFmt = in[0]->BandFmt; out->Type = in[0]->Type; out->Coding = in[0]->Coding; out->Xres = in[0]->Xres; out->Yres = in[0]->Yres; out->Xoffset = in[0]->Xoffset; out->Yoffset = in[0]->Yoffset; /* Count number of images. */ for (ni = 0; in[ni]; ni++) ; /* Need to copy last-to-first so that in0 meta will override any * earlier meta. * * Don't destroy the meta on out. Things like foreign.c like setting * image properties before calling a subclass loader, and those * subclass loaders will sometimes write to an image. */ for (i = ni - 1; i >= 0; i--) if (vips__image_meta_copy(out, in[i])) return -1; /* Merge hists first to last. */ for (i = 0; in[i]; i++) out->history_list = vips__gslist_gvalue_merge( out->history_list, in[i]->history_list); return 0; } /** * vips_image_set: * @image: image to set the metadata on * @name: the name to give the metadata * @value: the [struct@GObject.Value] to copy into the image * * Set a piece of metadata on @image. Any old metadata with that name is * destroyed. The [struct@GObject.Value] is copied into the image, so you need to unset the * value when you're done with it. * * For example, to set an integer on an image (though you would use the * convenience function [method@Image.set_int] in practice), you would do: * * ```c * GValue value = G_VALUE_INIT; * * g_value_init(&value, G_TYPE_INT); * g_value_set_int(&value, 42); * vips_image_set(image, name, &value); * g_value_unset(&value); * ``` * * ::: seealso * [method@Image.get]. */ void vips_image_set(VipsImage *image, const char *name, GValue *value) { g_assert(name); g_assert(value); #ifdef DEBUG_LEAK /* Warn if metadata is being set on a shared image. */ if (vips__leak && G_OBJECT(image)->ref_count > 2) printf("vips_image_set: set \"%s\" on shared image\n", name); #endif /*DEBUG_LEAK*/ /* We lock between modifying metadata and copying metadata between * images, see vips__image_meta_copy(). * * This prevents modification of metadata by one thread racing with * metadata copy on another -- this can lead to crashes in * highly-threaded applications. */ g_mutex_lock(&vips__meta_lock); meta_init(image); (void) meta_new(image, name, value); g_mutex_unlock(&vips__meta_lock); /* If we're setting an EXIF data block, we need to automatically expand * out all the tags. This will set things like xres/yres too. * * We do this here rather than in meta_new() since we don't want to * trigger on copy_fields. */ if (strcmp(name, VIPS_META_EXIF_NAME) == 0) if (vips__exif_parse(image)) g_warning("image_set: bad exif data"); #ifdef DEBUG meta_sanity(image); #endif /*DEBUG*/ } /* Unfortunately gvalue seems to have no way of doing this. Just handle the vips * built-in types. */ static void vips_set_value_from_pointer(GValue *value, void *data) { GType type = G_VALUE_TYPE(value); /* The fundamental type ... eg. G_TYPE_ENUM for a VIPS_TYPE_KERNEL, * or G_TYPE_OBJECT for VIPS_TYPE_IMAGE(). */ GType fundamental = G_TYPE_FUNDAMENTAL(type); if (fundamental == G_TYPE_INT) g_value_set_int(value, *((int *) data)); else if (fundamental == G_TYPE_DOUBLE) g_value_set_double(value, *((double *) data)); else if (fundamental == G_TYPE_ENUM) g_value_set_enum(value, *((int *) data)); else if (fundamental == G_TYPE_STRING) // we don't want to copy the string (ie. the filename, usually) since // it'll then be freed when the value is unset ... instead we must // directly use the pointer owned by the VipsImage g_value_set_static_string(value, *((char **) data)); else g_warning("%s: unimplemented vips_set_value_from_pointer() type %s", G_STRLOC, g_type_name(type)); } /** * vips_image_get: * @image: image to get the field from * @name: the name to fetch * @value_copy: (transfer full) (out caller-allocates): the * [struct@GObject.Value] is copied into this * * Fill @value_copy with a copy of the header field. @value_copy must be zeroed * but uninitialised. * * This will return -1 and add a message to the error buffer if the field * does not exist. Use [method@Image.get_typeof] to test for the * existence of a field first if you are not certain it will be there. * * For example, to read a double from an image (though of course you would use * [method@Image.get_double] in practice): * * ```c * GValue value = G_VALUE_INIT; * double d; * * if (vips_image_get(image, name, &value)) * return -1; * * if (G_VALUE_TYPE(&value) != G_TYPE_DOUBLE) { * vips_error("mydomain", * _("field \"%s\" is of type %s, not double"), * name, * g_type_name(G_VALUE_TYPE(&value))); * g_value_unset(&value); * return -1; * } * * d = g_value_get_double(&value); * g_value_unset(&value); * ``` * * ::: seealso * [method@Image.get_typeof], [method@Image.get_double]. * * Returns: (skip): 0 on success, -1 otherwise. */ int vips_image_get(const VipsImage *image, const char *name, GValue *value_copy) { int i; VipsMeta *meta; g_assert(name); g_assert(value_copy); for (i = 0; i < VIPS_NUMBER(vips_header_fields); i++) { HeaderField *field = &vips_header_fields[i]; if (strcmp(field->name, name) == 0) { GType gtype = g_type_from_name(field->type); g_value_init(value_copy, gtype); vips_set_value_from_pointer(value_copy, G_STRUCT_MEMBER_P(image, field->offset)); return 0; } } for (i = 0; i < VIPS_NUMBER(vips_header_fields_old); i++) { HeaderField *field = &vips_header_fields_old[i]; if (strcmp(field->name, name) == 0) { GType gtype = g_type_from_name(field->type); g_value_init(value_copy, gtype); vips_set_value_from_pointer(value_copy, G_STRUCT_MEMBER_P(image, field->offset)); return 0; } } if (image->meta && (meta = g_hash_table_lookup(image->meta, name))) { g_value_init(value_copy, G_VALUE_TYPE(&meta->value)); g_value_copy(&meta->value, value_copy); return 0; } vips_error("vips_image_get", _("field \"%s\" not found"), name); return -1; } /** * vips_image_get_typeof: * @image: image to test * @name: the name to search for * * Read the [alias@GObject.Type] for a header field. Returns zero if there * is no field of that name. * * ::: seealso * [method@Image.get]. * * Returns: the [alias@GObject.Type] of the field, or zero if there is no * field of that name. */ GType vips_image_get_typeof(const VipsImage *image, const char *name) { int i; VipsMeta *meta; g_assert(name); for (i = 0; i < VIPS_NUMBER(vips_header_fields); i++) { HeaderField *field = &vips_header_fields[i]; if (strcmp(field->name, name) == 0) return g_type_from_name(field->type); } for (i = 0; i < VIPS_NUMBER(vips_header_fields_old); i++) { HeaderField *field = &vips_header_fields_old[i]; if (strcmp(field->name, name) == 0) return g_type_from_name(field->type); } if (image->meta && (meta = g_hash_table_lookup(image->meta, name))) return G_VALUE_TYPE(&meta->value); VIPS_DEBUG_MSG("vips_image_get_typeof: unknown field %s\n", name); return 0; } /** * vips_image_remove: * @image: image to test * @name: the name to search for * * Find and remove an item of metadata. Return `FALSE` if no metadata of that * name was found. * * ::: seealso * [method@Image.set], [method@Image.get_typeof]. * * Returns: `TRUE` if an item of metadata of that name was found and removed */ gboolean vips_image_remove(VipsImage *image, const char *name) { gboolean result; result = FALSE; #ifdef DEBUG_LEAK /* Warn if metadata is being removed from a shared image. */ if (vips__leak && G_OBJECT(image)->ref_count > 2) printf("vips_image_remove: remove \"%s\" on shared image\n", name); #endif /*DEBUG_LEAK*/ if (image->meta) { /* We lock between modifying metadata and copying metadata * between images, see vips__image_meta_copy(). * * This prevents modification of metadata by one thread * racing with metadata copy on another -- this can lead to * crashes in highly-threaded applications. */ g_mutex_lock(&vips__meta_lock); result = g_hash_table_remove(image->meta, name); g_mutex_unlock(&vips__meta_lock); } return result; } /* Deprecated header fields we hide from _map. */ static const char *vips_image_header_deprecated[] = { "ipct-data", "gif-delay", "gif-loop", "palette-bit-depth", "heif-bitdepth" }; static void * vips_image_map_fn(VipsMeta *meta, VipsImageMapFn fn, void *a) { /* Hide deprecated fields. */ for (int i = 0; i < VIPS_NUMBER(vips_image_header_deprecated); i++) if (strcmp(meta->name, vips_image_header_deprecated[i]) == 0) return NULL; return fn(meta->im, meta->name, &meta->value, a); } /** * vips_image_map: * @image: image to map over * @fn: (scope call) (closure a): function to call for each header field * @a: user data for @fn * * This function calls @fn for every header field, including every item of * metadata. * * Like all _map functions, the user function should return `NULL` to continue * iteration, or a non-`NULL` pointer to indicate early termination. * * ::: seealso * [method@Image.get_typeof], [method@Image.get]. * * Returns: (nullable) (transfer none): `NULL` on success, the failing * pointer otherwise. */ void * vips_image_map(VipsImage *image, VipsImageMapFn fn, void *a) { void *result; for (int i = 0; i < VIPS_NUMBER(vips_header_fields); i++) { HeaderField *field = &vips_header_fields[i]; GValue value = G_VALUE_INIT; (void) vips_image_get(image, field->name, &value); result = fn(image, field->name, &value, a); g_value_unset(&value); if (result) return result; } if (image->meta_traverse && (result = vips_slist_map2(image->meta_traverse, (VipsSListMap2Fn) vips_image_map_fn, fn, a))) return result; return NULL; } static void * count_fields(VipsImage *image, const char *field, GValue *value, void *a) { int *n_fields = (int *) a; *n_fields += 1; return NULL; } static void * add_fields(VipsImage *image, const char *field, GValue *value, void *a) { gchar ***p = (gchar ***) a; **p = g_strdup(field); *p += 1; return NULL; } /** * vips_image_get_fields: * @image: image to get fields from * * Get a `NULL`-terminated array listing all the metadata field names on @image. * Free the return result with [func@GLib.strfreev]. * * This is handy for language bindings. From C, it's usually more convenient to * use [method@Image.map]. * * Returns: (transfer full): metadata fields in image, as a `NULL`-terminated * array. */ gchar ** vips_image_get_fields(VipsImage *image) { int n_fields; gchar **fields; gchar **p; n_fields = 0; (void) vips_image_map(image, count_fields, &n_fields); fields = g_new0(gchar *, n_fields + 1); p = fields; (void) vips_image_map(image, add_fields, &p); return fields; } /** * vips_image_set_area: * @image: image to attach the metadata to * @name: metadata name * @free_fn: (scope async) (nullable): free function for @data * @data: (transfer full): pointer to area of memory * * Attaches @data as a metadata item on @image under the name @name. When * VIPS no longer needs the metadata, it will be freed with @free_fn. * * ::: seealso * [method@Image.get_double], [method@Image.set]. */ void vips_image_set_area(VipsImage *image, const char *name, VipsCallbackFn free_fn, void *data) { GValue value = G_VALUE_INIT; vips_value_set_area(&value, free_fn, data); vips_image_set(image, name, &value); g_value_unset(&value); } static int meta_get_value(const VipsImage *image, const char *name, GType type, GValue *value_copy) { GValue value = G_VALUE_INIT; if (vips_image_get(image, name, &value)) return -1; g_value_init(value_copy, type); if (!g_value_transform(&value, value_copy)) { vips_error("VipsImage", _("field \"%s\" is of type %s, not %s"), name, g_type_name(G_VALUE_TYPE(&value)), g_type_name(type)); g_value_unset(&value); return -1; } g_value_unset(&value); return 0; } /** * vips_image_get_area: * @image: image to get the metadata from * @name: metadata name * @data: (out): return metadata value * * Gets @data from @image under the name @name. A convenience * function over [method@Image.get]. Use [method@Image.get_typeof] to * test for the existence of a piece of metadata. * * ::: seealso * [method@Image.set_area], [method@Image.get], * [method@Image.get_typeof]. * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_area(const VipsImage *image, const char *name, const void **data) { GValue value_copy = G_VALUE_INIT; if (!meta_get_value(image, name, VIPS_TYPE_AREA, &value_copy)) { *data = vips_value_get_area(&value_copy, NULL); g_value_unset(&value_copy); return 0; } return -1; } /** * vips_image_set_blob: * @image: image to attach the metadata to * @name: metadata name * @free_fn: (scope async) (nullable): free function for @data * @data: (array length=length) (element-type guint8) (transfer full): pointer to area of * memory * @length: length of memory area * * Attaches @data as a metadata item on @image under the name @name. * * ::: seealso * [method@Image.get_blob], [method@Image.set]. */ void vips_image_set_blob(VipsImage *image, const char *name, VipsCallbackFn free_fn, const void *data, size_t size) { GValue value = G_VALUE_INIT; g_value_init(&value, VIPS_TYPE_BLOB); vips_value_set_blob(&value, free_fn, data, size); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_set_blob_copy: * @image: image to attach the metadata to * @name: metadata name * @data: (array length=length) (element-type guint8): pointer to area of memory * @length: length of memory area * * Attaches @data as a metadata item on @image under the name @name, taking * a copy of the memory area. * * ::: seealso * [method@Image.get_blob], [method@Image.set]. */ void vips_image_set_blob_copy(VipsImage *image, const char *name, const void *data, size_t length) { void *data_copy; /* Cap at 100mb for sanity. */ if (!data || length == 0 || length > 100 * 1024 * 1024) return; /* We add an extra, secret null byte at the end, just in case this blob * is read as a C string. The libtiff reader attaches * XMP XML as a blob, for example. */ if (!(data_copy = vips_malloc(NULL, length + 1))) return; memcpy(data_copy, data, length); ((unsigned char *) data_copy)[length] = '\0'; vips_image_set_blob(image, name, (VipsCallbackFn) vips_area_free_cb, data_copy, length); } /** * vips_image_get_blob: * @image: image to get the metadata from * @name: metadata name * @data: (out) (array length=length) (element-type guint8): pointer to area * of memory * @length: (out): return the blob length here, optionally * * Gets @data from @image under the name @name, optionally returns its * length in @length. Use [method@Image.get_typeof] to test for the existence * of a piece of metadata. * * ::: seealso * [method@Image.get], [method@Image.get_typeof], * [method@Blob.get]. * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_blob(const VipsImage *image, const char *name, const void **data, size_t *length) { GValue value_copy = G_VALUE_INIT; if (!meta_get_value(image, name, VIPS_TYPE_BLOB, &value_copy)) { *data = vips_value_get_blob(&value_copy, length); g_value_unset(&value_copy); return 0; } return -1; } /** * vips_image_get_int: * @image: image to get the header field from * @name: field name * @out: (out): return field value * * Gets @out from @im under the name @name. * The value will be transformed into an int, if possible. * * ::: seealso * [method@Image.get], [method@Image.get_typeof]. * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_int(const VipsImage *image, const char *name, int *out) { GValue value = G_VALUE_INIT; if (meta_get_value(image, name, G_TYPE_INT, &value)) return -1; *out = g_value_get_int(&value); g_value_unset(&value); return 0; } /** * vips_image_set_int: * @image: image to attach the metadata to * @name: metadata name * @i: metadata value * * Attaches @i as a metadata item on @image under the name @name. A * convenience function over [method@Image.set]. * * ::: seealso * [method@Image.get_int], [method@Image.set]. */ void vips_image_set_int(VipsImage *image, const char *name, int i) { GValue value = G_VALUE_INIT; g_value_init(&value, G_TYPE_INT); g_value_set_int(&value, i); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_get_double: * @image: image to get the header field from * @name: field name * @out: (out): return field value * * Gets @out from @im under the name @name. * The value will be transformed into a double, if possible. * * ::: seealso * [method@Image.get], [method@Image.get_typeof]. * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_double(const VipsImage *image, const char *name, double *out) { GValue value = G_VALUE_INIT; if (meta_get_value(image, name, G_TYPE_DOUBLE, &value)) return -1; *out = g_value_get_double(&value); g_value_unset(&value); return 0; } /** * vips_image_set_double: * @image: image to attach the metadata to * @name: metadata name * @d: metadata value * * Attaches @d as a metadata item on @image as @name. A * convenience function over [method@Image.set]. * * ::: seealso * [method@Image.get_double], [method@Image.set]. */ void vips_image_set_double(VipsImage *image, const char *name, double d) { GValue value = G_VALUE_INIT; g_value_init(&value, G_TYPE_DOUBLE); g_value_set_double(&value, d); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_get_string: * @image: image to get the header field from * @name: field name * @out: (out) (transfer none): return field value * * Gets @out from @im under the name @name. * The field must be of type `G_TYPE_STRING` or `VIPS_TYPE_REF_STRING`. * * Do not free @out. * * Use [method@Image.get_as_string] to fetch any field as a string. * * ::: seealso * [method@Image.get], [method@Image.get_typeof]. * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_string(const VipsImage *image, const char *name, const char **out) { GValue value = G_VALUE_INIT; if (vips_image_get(image, name, &value)) return -1; if (G_VALUE_TYPE(&value) == VIPS_TYPE_REF_STRING) { VipsArea *area; area = g_value_get_boxed(&value); *out = area->data; } else if (G_VALUE_TYPE(&value) == G_TYPE_STRING) { *out = g_value_get_string(&value); } else { vips_error("VipsImage", _("field \"%s\" is of type %s, not VipsRefString"), name, g_type_name(G_VALUE_TYPE(&value))); g_value_unset(&value); return -1; } g_value_unset(&value); return 0; } /** * vips_image_set_string: * @image: image to attach the metadata to * @name: metadata name * @str: metadata value * * Attaches @str as a metadata item on @image as @name. * A convenience * function over [method@Image.set] using `VIPS_TYPE_REF_STRING`. * * ::: seealso * [method@Image.get_double], [method@Image.set]. */ void vips_image_set_string(VipsImage *image, const char *name, const char *str) { GValue value = G_VALUE_INIT; g_value_init(&value, VIPS_TYPE_REF_STRING); vips_value_set_ref_string(&value, str); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_get_as_string: * @image: image to get the header field from * @name: field name * @out: (out) (transfer full): return field value as string * * Returns @name from @image in @out. * This function will read any field, returning it as a printable string. * You need to free the string with [func@GLib.free] when you are done with it. * * This will base64-encode BLOBs, for example. Use [method@Buf.appendg] to * make a string that's for humans. * * ::: seealso * [method@Image.get], [method@Image.get_typeof], * [method@Buf.appendg]. * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_as_string(const VipsImage *image, const char *name, char **out) { GValue value = G_VALUE_INIT; GType type; if (vips_image_get(image, name, &value)) return -1; /* Display the save form, if there is one. This way we display * something useful for ICC profiles, xml fields, etc. */ type = G_VALUE_TYPE(&value); if (g_value_type_transformable(type, VIPS_TYPE_SAVE_STRING)) { GValue save_value = G_VALUE_INIT; g_value_init(&save_value, VIPS_TYPE_SAVE_STRING); if (!g_value_transform(&value, &save_value)) return -1; *out = g_strdup(vips_value_get_save_string(&save_value)); g_value_unset(&save_value); } else *out = g_strdup_value_contents(&value); g_value_unset(&value); return 0; } /** * vips_image_print_field: * @image: image to get the header field from * @name: field name * * Prints field @name to stdout as ASCII. Handy for debugging. */ void vips_image_print_field(const VipsImage *image, const char *name) { char *str; if (vips_image_get_as_string(image, name, &str)) { printf("vips_image_print_field: unable to read field\n"); return; } printf(".%s: %s\n", name, str); g_free(str); } /** * vips_image_get_image: * @image: image to get the metadata from * @name: metadata name * @out: (out) (transfer full): return metadata value * * Gets @out from @im under the name @name. * The field must be of type `VIPS_TYPE_IMAGE`. * You must unref @out with [method@GObject.Object.unref]. * * Use [method@Image.get_typeof] to test for the * existence of a piece of metadata. * * ::: seealso * [method@Image.get], [method@Image.set_image] * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_image(const VipsImage *image, const char *name, VipsImage **out) { GValue value = G_VALUE_INIT; if (meta_get_value(image, name, VIPS_TYPE_IMAGE, &value)) return -1; *out = g_value_dup_object(&value); g_value_unset(&value); return 0; } /** * vips_image_set_image: * @image: image to attach the metadata to * @name: metadata name * @im: metadata value * * Attaches @im as a metadata item on @image as @name. * A convenience function over [method@Image.set]. * * ::: seealso * [method@Image.get_image], [method@Image.set]. */ void vips_image_set_image(VipsImage *image, const char *name, VipsImage *im) { GValue value = G_VALUE_INIT; g_value_init(&value, VIPS_TYPE_IMAGE); g_value_set_object(&value, im); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_get_array_int: * @image: image to get the metadata from * @name: metadata name * @out: (out) (array length=n) (transfer none): return pointer to array * @n: (out) (optional): return the number of elements here, optionally * * Gets @out from @im under the name @name. * The field must be of type `VIPS_TYPE_ARRAY_INT`. * * Do not free @out. @out is valid as long as @image is valid. * * Use [method@Image.get_typeof] to test for the * existence of a piece of metadata. * * ::: seealso * [method@Image.get], [method@Image.set_image] * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_array_int(VipsImage *image, const char *name, int **out, int *n) { GValue value = G_VALUE_INIT; if (meta_get_value(image, name, VIPS_TYPE_ARRAY_INT, &value)) return -1; *out = vips_value_get_array_int(&value, n); g_value_unset(&value); return 0; } /** * vips_image_set_array_int: * @image: image to attach the metadata to * @name: metadata name * @array: (array length=n) (allow-none): array of ints * @n: the number of elements * * Attaches @array as a metadata item on @image as @name. * A convenience function over [method@Image.set]. * * ::: seealso * [method@Image.get_image], [method@Image.set]. */ void vips_image_set_array_int(VipsImage *image, const char *name, const int *array, int n) { GValue value = G_VALUE_INIT; g_value_init(&value, VIPS_TYPE_ARRAY_INT); vips_value_set_array_int(&value, array, n); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_get_array_double: * @image: image to get the metadata from * @name: metadata name * @out: (out) (array length=n) (transfer none): return pointer to array * @n: (out) (optional): return the number of elements here, optionally * * Gets @out from @im under the name @name. * The field must be of type `VIPS_TYPE_ARRAY_INT`. * * Do not free @out. @out is valid as long as @image is valid. * * Use [method@Image.get_typeof] to test for the * existence of a piece of metadata. * * ::: seealso * [method@Image.get], [method@Image.set_image] * * Returns: 0 on success, -1 otherwise. */ int vips_image_get_array_double(VipsImage *image, const char *name, double **out, int *n) { GValue value = G_VALUE_INIT; if (meta_get_value(image, name, VIPS_TYPE_ARRAY_DOUBLE, &value)) return -1; *out = vips_value_get_array_double(&value, n); g_value_unset(&value); return 0; } /** * vips_image_set_array_double: * @image: image to attach the metadata to * @name: metadata name * @array: (array length=n) (allow-none): array of doubles * @n: the number of elements * * Attaches @array as a metadata item on @image as @name. * A convenience function over [method@Image.set]. * * ::: seealso * [method@Image.get_image], [method@Image.set]. */ void vips_image_set_array_double(VipsImage *image, const char *name, const double *array, int n) { GValue value = G_VALUE_INIT; g_value_init(&value, VIPS_TYPE_ARRAY_DOUBLE); vips_value_set_array_double(&value, array, n); vips_image_set(image, name, &value); g_value_unset(&value); } /** * vips_image_history_printf: * @image: add history line to this image * @format: `printf()`-style format string * @...: arguments to format string * * Add a line to the image history. The @format and arguments are expanded, the * date and time is appended prefixed with a hash character, and the whole * string is appended to the image history and terminated with a newline. * * For example: * * ```c * vips_image_history_printf(image, "vips invert %s %s", * in->filename, out->filename); * ``` * * Might add the string * * ```bash * "vips invert /home/john/fred.v /home/john/jim.v # Fri Apr 3 23:30:35 2009\n" * ``` * * VIPS operations don't add history lines for you because a single action at * the application level might involve many VIPS operations. History must be * recorded by the application. * * Returns: 0 on success, -1 on error. */ int vips_image_history_printf(VipsImage *image, const char *fmt, ...) { va_list args; char str[VIPS_PATH_MAX]; VipsBuf buf = VIPS_BUF_STATIC(str); time_t timebuf; va_start(args, fmt); (void) vips_buf_vappendf(&buf, fmt, args); va_end(args); vips_buf_appends(&buf, " # "); /* Add the date. ctime always attaches a '\n', gah. */ time(&timebuf); vips_buf_appends(&buf, ctime(&timebuf)); vips_buf_removec(&buf, '\n'); #ifdef DEBUG printf("vips_image_history_printf: " "adding:\n\t%s\nto history on image %p\n", vips_buf_all(&buf), image); #endif /*DEBUG*/ image->history_list = g_slist_append(image->history_list, vips__gvalue_ref_string_new(vips_buf_all(&buf))); return 0; } /** * vips_image_history_args: * @image: image to attach history line to * @name: program name * @argc: number of program arguments * @argv: (array length=argc) (element-type char*): program arguments * * Formats the name/argv as a single string and calls * [method@Image.history_printf]. A convenience function for * command-line programs. * * ::: seealso * [method@Image.get_history]. * * Returns: 0 on success, -1 on error. */ int vips_image_history_args(VipsImage *image, const char *name, int argc, char *argv[]) { int i; char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC(txt); vips_buf_appends(&buf, name); for (i = 0; i < argc; i++) { vips_buf_appends(&buf, " "); vips_buf_appends(&buf, argv[i]); } if (vips_image_history_printf(image, "%s", vips_buf_all(&buf))) return -1; return 0; } /** * vips_image_get_history: * @image: get history from here * * This function reads the image history as a C string. The string is owned * by VIPS and must not be freed. * * VIPS tracks the history of each image, that is, the sequence of operations * that generated that image. Applications built on VIPS need to call * [method@Image.history_printf] for each action they perform, setting the * command-line equivalent for the action. * * ::: seealso * [method@Image.history_printf]. * * Returns: (transfer none): The history of @image as a C string. Do not free! */ const char * vips_image_get_history(VipsImage *image) { if (!image->Hist) image->Hist = vips__gslist_gvalue_get(image->history_list); return image->Hist ? image->Hist : ""; } libvips-8.18.2/libvips/iofuncs/image.c000066400000000000000000003014141516303661500176370ustar00rootroot00000000000000/* vips image class * * 4/2/11 * - hacked up from various places * 6/6/13 * - vips_image_write() didn't ref non-partial sources * 18/4/15 * - add vips_image_copy_memory() * 25/11/15 * - add vips_image_new_from_memory_copy() * 10/6/16 * - vips_image_write() does not ref input for non-partial images * 29/10/16 * - add vips_image_hasalpha() * 11/10/17 * - more severing for vips_image_write() * 3/4/18 * - better rules for hasalpha * 9/10/18 * - fix up vips_image_dump(), it was still using ints not enums * 10/12/19 * - add vips_image_new_from_source / vips_image_write_to_target() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #define VIPS_DISABLE_DEPRECATION_WARNINGS #include #include #include /** * VipsImage: * * The [class@Image] class and associated types and macros. * * Images can be created from formatted files on disc, from C-style arrays on * disc, from formatted areas of memory, or from C-style arrays in memory. See * [ctor@Image.new_from_file] and friends. * Creating an image is fast. libvips reads just enough of * the image to be able to get the various properties, such as width in * pixels. It delays reading any pixels until they are really needed. * * Once you have an image, you can get properties from it in the usual way. * You can use projection functions, like [method@Image.get_width] or * [method@GObject.Object.get], to get [class@GObject.Object] properties. * * `.v` images are three-dimensional arrays, the dimensions being width, * height and bands. Each dimension can be up to 2 ** 31 pixels (or band * elements). An image has a format, meaning the machine number type used * to represent each value. libvips supports 10 formats, from 8-bit unsigned * integer up to 128-bit double complex, see [method@Image.get_format]. * * In libvips, images are uninterpreted arrays, meaning that from the point * of view of most operations, they are just large collections of numbers. * There's no difference between an RGBA (RGB with alpha) image and a CMYK * image, for example, they are both just four-band images. It's up to the * user of the library to pass the right sort of image to each operation. * * To take an example, libvips has [method@Image.Lab2XYZ], an operation to * transform an image from CIE LAB colour space to CIE XYZ space. It assumes * the first three bands represent pixels in LAB colour space and returns an * image where the first three bands are transformed to XYZ and any * remaining bands are just copied. Pass it an RGB image by mistake and * you'll just get nonsense. * * libvips has a feature to help (a little) with this: it sets a * [enum@Interpretation] hint for each image (see * [method@Image.get_interpretation]); a hint which says how pixels should * be interpreted. For example, [method@Image.Lab2XYZ] will set the * interpretation of the output image to [enum@Vips.Interpretation.XYZ]. * A few utility operations will also use interpretation as a guide. For * example, you can give [method@Image.colourspace] an input image and a * desired colourspace and it will use the input's interpretation hint to * apply the best sequence of colourspace transforms to get to the desired * space. * * Use things like [method@Image.invert] to manipulate your images. When you * are done, you can write images to disc files (with * [method@Image.write_to_file]), to formatted memory buffers (with * [method@Image.write_to_buffer]) and to C-style memory arrays (with * [method@Image.write_to_memory]). * * You can also write images to other images. Create, for example, a temporary * disc image with [ctor@Image.new_temp_file], then write your image to that * with [method@Image.write]. You can create several other types of image and * write to them, see [ctor@Image.new_memory], for example. * * See [class@Operation] for an introduction to running operations on images, * see [Image headers](libvips-header.html) for getting and setting image * metadata. See [class@Object] for a discussion of the lower levels. */ /** * VIPS_MAGIC_INTEL: * * The first four bytes of a VIPS file in Intel byte ordering. */ /** * VIPS_MAGIC_SPARC: * * The first four bytes of a VIPS file in SPARC byte ordering. */ /** * VipsAccess: * @VIPS_ACCESS_RANDOM: can read anywhere * @VIPS_ACCESS_SEQUENTIAL: top-to-bottom reading only, but with a small buffer * @VIPS_ACCESS_SEQUENTIAL_UNBUFFERED: deprecated, use [enum@Vips.Access.SEQUENTIAL] instead * * The type of access an operation has to supply. See [method@Image.tilecache] * and [class@Foreign]. * * [enum@Vips.Access.RANDOM] means requests can come in any order. * * [enum@Vips.Access.SEQUENTIAL] means requests will be top-to-bottom, but with some * amount of buffering behind the read point for small non-local accesses. */ /** * VipsDemandStyle: * @VIPS_DEMAND_STYLE_SMALLTILE: demand in small (typically 128x128 pixel) tiles * @VIPS_DEMAND_STYLE_FATSTRIP: demand in fat (typically 16 pixel high) strips * @VIPS_DEMAND_STYLE_THINSTRIP: demand in thin (typically 1 pixel high) strips * @VIPS_DEMAND_STYLE_ANY: demand geometry does not matter * * See [method@Image.pipelinev]. Operations can hint * the kind of demand geometry they prefer * to the VIPS image IO system. * * These demand styles are given below in order of increasing * specialisation. When demanding output from a pipeline, * [method@Image.generate] * will use the most general style requested by the operations * in the pipeline. * * [enum@Vips.DemandStyle.SMALLTILE] -- This is the most general demand format. * Output is demanded in small (around 100x100 pel) sections. This style works * reasonably efficiently, even for bizarre operations like 45 degree rotate. * * [enum@Vips.DemandStyle.FATSTRIP] -- This operation would like to output strips * the width of the image and as high as possible. This option is suitable * for area operations which do not violently transform coordinates, such * as [method@Image.conv]. * * [enum@Vips.DemandStyle.THINSTRIP] -- This operation would like to output strips * the width of the image and a few pels high. This option is suitable for * point-to-point operations, such as those in the arithmetic package. * * [enum@Vips.DemandStyle.ANY] -- This image is not being demand-read from a disc * file (even indirectly) so any demand style is OK. It's used for things like * [ctor@Image.black] where the pixels are calculated. * * ::: seealso * [method@Image.pipelinev]. */ /** * VipsInterpretation: * @VIPS_INTERPRETATION_MULTIBAND: generic many-band image * @VIPS_INTERPRETATION_B_W: some kind of single-band image * @VIPS_INTERPRETATION_HISTOGRAM: a 1D image, eg. histogram or lookup table * @VIPS_INTERPRETATION_FOURIER: image is in fourier space * @VIPS_INTERPRETATION_XYZ: the first three bands are CIE XYZ * @VIPS_INTERPRETATION_LAB: pixels are in CIE Lab space * @VIPS_INTERPRETATION_OKLAB: pixels are in Oklab colourspace * @VIPS_INTERPRETATION_OKLCH: pixels are in Oklch colourspace * @VIPS_INTERPRETATION_CMYK: the first four bands are in CMYK space * @VIPS_INTERPRETATION_LABQ: implies [enum@Vips.Coding.LABQ] * @VIPS_INTERPRETATION_RGB: generic RGB space * @VIPS_INTERPRETATION_CMC: a uniform colourspace based on CMC(1:1) * @VIPS_INTERPRETATION_LCH: pixels are in CIE LCh space * @VIPS_INTERPRETATION_LABS: CIE LAB coded as three signed 16-bit values * @VIPS_INTERPRETATION_sRGB: pixels are sRGB * @VIPS_INTERPRETATION_HSV: pixels are HSV * @VIPS_INTERPRETATION_scRGB: pixels are scRGB * @VIPS_INTERPRETATION_YXY: pixels are CIE Yxy * @VIPS_INTERPRETATION_RGB16: generic 16-bit RGB * @VIPS_INTERPRETATION_GREY16: generic 16-bit mono * @VIPS_INTERPRETATION_MATRIX: a matrix * * How the values in an image should be interpreted. For example, a * three-band float image of type [enum@Vips.Interpretation.LAB] should have its * pixels interpreted as coordinates in CIE Lab space. * * RGB and sRGB are treated in the same way. Use the colourspace functions if * you want some other behaviour. * * The gaps in numbering are historical and must be maintained. Allocate * new numbers from the end. */ /** * VipsBandFormat: * @VIPS_FORMAT_NOTSET: invalid setting * @VIPS_FORMAT_UCHAR: unsigned char format * @VIPS_FORMAT_CHAR: char format * @VIPS_FORMAT_USHORT: unsigned short format * @VIPS_FORMAT_SHORT: short format * @VIPS_FORMAT_UINT: unsigned int format * @VIPS_FORMAT_INT: int format * @VIPS_FORMAT_FLOAT: float format * @VIPS_FORMAT_COMPLEX: complex (two floats) format * @VIPS_FORMAT_DOUBLE: double float format * @VIPS_FORMAT_DPCOMPLEX: double complex (two double) format * * The format used for each band element. * * Each corresponds to a native C type for the current machine. For example, * [enum@Vips.BandFormat.USHORT] is `unsigned short`. */ /** * VipsCoding: * @VIPS_CODING_NONE: pixels are not coded * @VIPS_CODING_LABQ: pixels encode 3 float CIELAB values as 4 uchar * @VIPS_CODING_RAD: pixels encode 3 float RGB as 4 uchar (Radiance coding) * * How pixels are coded. * * Normally, pixels are uncoded and can be manipulated as you would expect. * However some file formats code pixels for compression, and sometimes it's * useful to be able to manipulate images in the coded format. * * The gaps in the numbering are historical and must be maintained. Allocate * new numbers from the end. */ /** * VipsProgress: * @run: Time we have been running * @eta: Estimated seconds of computation left * @tpels: Number of pels we expect to calculate * @npels: Number of pels calculated so far * @percent: Percent complete * @start: Start time * * A structure available to eval callbacks giving information on evaluation * progress. See [signal@Image::eval]. */ /** * VIPS_IMAGE_SIZEOF_ELEMENT: * @I: a [class@Image] * * Returns: `sizeof()` a band element. */ /** * VIPS_IMAGE_SIZEOF_PEL: * @I: a [class@Image] * * Returns: `sizeof()` a pixel. */ /** * VIPS_IMAGE_SIZEOF_LINE: * @I: a [class@Image] * * Returns: `sizeof()` a scanline of pixels. */ /** * VIPS_IMAGE_N_ELEMENTS: * @I: a [class@Image] * * Returns: The number of band elements in a scanline. */ /** * VIPS_IMAGE_N_PELS: * @I: a [class@Image] * * Returns: The number of pels in an image. A 64-bit unsigned int. */ /** * VIPS_IMAGE_ADDR: * @I: a [class@Image] * @X: x coordinate * @Y: y coordinate * * This macro returns a pointer to a pixel in an image, cast to a [alias@Pel] \*. * It only works for images which are fully available in memory, so memory * buffers and small mapped images only. * * If `VIPS_DEBUG` is defined, you get a version that checks bounds for you. * * ::: seealso * [method@Image.wio_input], [method@Image.inplace], [func@REGION_ADDR]. * * Returns: The address of pixel (@X,@Y) in @I. */ /** * VIPS_MATRIX: * @I: a [class@Image] * @X: x coordinate * @Y: y coordinate * * This macro returns a pointer to a pixel in an image, cast to a double*. The * image must have a single band, be [enum@Vips.BandFormat.DOUBLE] and be * fully available in memory, so memory buffers and small * mapped images only. * * If `VIPS_DEBUG` is defined, you get a version that checks bounds and image * type for you. * * ::: seealso * [method@Image.wio_input], [method@Image.inplace], [func@check_matrix]. * * Returns: The address of pixel (@X,@Y) in @I. */ /* Our signals. */ enum { SIG_PREEVAL, SIG_EVAL, SIG_POSTEVAL, SIG_WRITTEN, SIG_INVALIDATE, SIG_MINIMISE, SIG_LAST }; /* Progress feedback. Only really useful for testing, tbh. */ int vips__progress = 0; /* A string giving the image size (in bytes of uncompressed image) above which * we decompress to disc on open. Can be eg. "12m" for 12 megabytes. */ char *vips__disc_threshold = NULL; /* Minimise needs a lock. */ static GMutex vips__minimise_lock; static guint vips_image_signals[SIG_LAST] = { 0 }; G_DEFINE_TYPE(VipsImage, vips_image, VIPS_TYPE_OBJECT); /** * vips_progress_set: * @progress: `TRUE` to enable progress messages * * If set, vips will print messages about the progress of computation to * stdout. This can also be enabled with the `--vips-progress` option, or by * setting the environment variable `VIPS_PROGRESS`. */ void vips_progress_set(gboolean progress) { vips__progress = progress; } static void vips_image_delete(VipsImage *image) { if (image->delete_on_close) { g_assert(image->delete_on_close_filename); VIPS_DEBUG_MSG("vips_image_delete: removing temp %s\n", image->delete_on_close_filename); g_unlink(image->delete_on_close_filename); VIPS_FREE(image->delete_on_close_filename); image->delete_on_close = FALSE; } } static void vips_image_finalize(GObject *gobject) { VipsImage *image = VIPS_IMAGE(gobject); VIPS_DEBUG_MSG("vips_image_finalize: %p\n", gobject); /* Should be no regions defined on the image, since they all hold a * ref to their host image. */ g_assert(!image->regions); /* Therefore there should be no windows. */ g_assert(!image->windows); /* Junk generate functions. */ image->start_fn = NULL; image->generate_fn = NULL; image->stop_fn = NULL; image->client1 = NULL; image->client2 = NULL; /* No more upstream/downstream links. */ vips__link_break_all(image); if (image->time) { VIPS_FREEF(g_timer_destroy, image->time->start); VIPS_FREE(image->time); } /* Free attached memory. */ if (image->data) { if (image->dtype == VIPS_IMAGE_SETBUF) { VIPS_DEBUG_MSG("vips_image_finalize: freeing buffer\n"); vips_tracked_free(image->data); image->dtype = VIPS_IMAGE_NONE; } image->data = NULL; } /* Delete associated files. */ vips_image_delete(image); g_mutex_clear(&image->sslock); VIPS_FREE(image->Hist); VIPS_FREEF(vips__gslist_gvalue_free, image->history_list); vips__meta_destroy(image); G_OBJECT_CLASS(vips_image_parent_class)->finalize(gobject); } static void vips_image_dispose(GObject *gobject) { VipsImage *image = VIPS_IMAGE(gobject); VIPS_DEBUG_MSG("vips_image_dispose: %p\n", gobject); #ifdef DEBUG_LEAK { VipsImagePixels *pixels = g_object_get_qdata(G_OBJECT(image), vips__image_pixels_quark); if (pixels && pixels->tpels) { int compute_percent = 100.0 * pixels->npels / pixels->tpels; if (compute_percent > 100) printf("vips_image_dispose: %s %s computed %d%%\n", image->filename, pixels->nickname, compute_percent); } } #endif /*DEBUG_LEAK*/ vips_object_preclose(VIPS_OBJECT(gobject)); /* We have to junk the fd in dispose, since we run this for rewind and * we must close and reopen the file when we switch from write to * read. */ /* Any file mapping? */ if (image->baseaddr) { /* MMAP file. */ VIPS_DEBUG_MSG("vips_image_dispose: unmapping file\n"); vips__munmap(image->baseaddr, image->length); image->baseaddr = NULL; image->length = 0; /* This must have been a pointer to the mmap region, rather * than a setbuf. */ image->data = NULL; } /* Is there a file descriptor? */ if (image->fd != -1) { VIPS_DEBUG_MSG("vips_image_dispose: closing output file\n"); if (vips_tracked_close(image->fd) == -1) vips_error("VipsImage", "%s", _("unable to close fd")); image->fd = -1; } G_OBJECT_CLASS(vips_image_parent_class)->dispose(gobject); } static VipsObject * vips_image_new_from_file_object(const char *string) { VipsImage *image; vips_check_init(); /* We mustn't _build() the object here, so we can't just call * vips_image_new_from_file(). */ image = VIPS_IMAGE(g_object_new(VIPS_TYPE_IMAGE, NULL)); g_object_set(image, "filename", string, "mode", "r", NULL); return VIPS_OBJECT(image); } static void vips_image_to_string(VipsObject *object, VipsBuf *buf) { VipsImage *image = VIPS_IMAGE(object); vips_buf_appends(buf, image->filename); } static int vips_image_write_object(VipsObject *object, const char *string) { return vips_image_write_to_file(VIPS_IMAGE(object), string, NULL); } static void * print_field_fn(VipsImage *image, const char *field, GValue *value, void *a) { VipsBuf *buf = (VipsBuf *) a; vips_buf_appendf(buf, "%s: ", field); vips_buf_appendgv(buf, value); vips_buf_appendf(buf, "\n"); return NULL; } static void vips_image_dump(VipsObject *object, VipsBuf *buf) { VipsImage *image = VIPS_IMAGE(object); vips_buf_appendf(buf, g_dngettext(GETTEXT_PACKAGE, "%dx%d %s, %d band, %s", "%dx%d %s, %d bands, %s", vips_image_get_bands(image)), vips_image_get_width(image), vips_image_get_height(image), vips_enum_nick(VIPS_TYPE_BAND_FORMAT, vips_image_get_format(image)), vips_image_get_bands(image), vips_enum_nick(VIPS_TYPE_INTERPRETATION, vips_image_get_interpretation(image))); vips_buf_appendf(buf, ", %s", vips_enum_nick(VIPS_TYPE_IMAGE_TYPE, image->dtype)); VIPS_OBJECT_CLASS(vips_image_parent_class)->dump(object, buf); vips_buf_appendf(buf, "\n"); (void) vips_image_map(image, print_field_fn, (void *) buf); vips_buf_appendf(buf, "Hist: %s", vips_image_get_history(image)); } static void vips_image_summary(VipsObject *object, VipsBuf *buf) { VipsImage *image = VIPS_IMAGE(object); const char *p; vips_buf_appendf(buf, "%dx%d", vips_image_get_width(image), vips_image_get_height(image)); if (vips_image_get_coding(image) == VIPS_CODING_NONE) { vips_buf_appendf(buf, g_dngettext(GETTEXT_PACKAGE, " %s, %d band, %s", " %s, %d bands, %s", vips_image_get_bands(image)), vips_enum_nick(VIPS_TYPE_BAND_FORMAT, vips_image_get_format(image)), vips_image_get_bands(image), vips_enum_nick(VIPS_TYPE_INTERPRETATION, vips_image_get_interpretation(image))); } else { vips_buf_appendf(buf, ", %s", vips_enum_nick(VIPS_TYPE_CODING, vips_image_get_coding(image))); } if (vips_image_get_typeof(image, VIPS_META_LOADER) && !vips_image_get_string(image, VIPS_META_LOADER, &p)) vips_buf_appendf(buf, ", %s", p); VIPS_OBJECT_CLASS(vips_image_parent_class)->summary(object, buf); } static void * vips_image_sanity_upstream(VipsImage *up, VipsImage *down, void *b) { if (!g_slist_find(up->downstream, down) || !g_slist_find(down->upstream, up)) return up; return NULL; } static void * vips_image_sanity_downstream(VipsImage *down, VipsImage *up, void *b) { return vips_image_sanity_upstream(up, down, b); } static void vips_image_sanity(VipsObject *object, VipsBuf *buf) { VipsImage *image = VIPS_IMAGE(object); guint64 es, ps, ls, sizeof_image; if (image->Xsize <= 0 || image->Ysize <= 0 || image->Bands <= 0) vips_buf_appends(buf, "bad dimensions\n"); if (image->BandFmt < -1 || image->BandFmt > VIPS_FORMAT_DPCOMPLEX || (image->Coding != -1 && image->Coding != VIPS_CODING_NONE && image->Coding != VIPS_CODING_LABQ && image->Coding != VIPS_CODING_RAD) || image->Type >= VIPS_INTERPRETATION_LAST || image->dtype > VIPS_IMAGE_PARTIAL || image->dhint > VIPS_DEMAND_STYLE_ANY) vips_buf_appends(buf, "bad enum\n"); if (image->Xres < 0 || image->Yres < 0) vips_buf_appends(buf, "bad resolution\n"); es = VIPS_IMAGE_SIZEOF_ELEMENT(image); /* Guard for `es * bands * width * height <= UINT64_MAX`, i.e. check * whether the VIPS_IMAGE_SIZEOF_PEL(), VIPS_IMAGE_SIZEOF_LINE() * and VIPS_IMAGE_SIZEOF_IMAGE() macros can be safely used. * * Also ensure that vips_tracked_malloc(VIPS_IMAGE_SIZEOF_IMAGE(image)) * can be called safely for setbuf types. */ if (!g_uint64_checked_mul(&ps, es, image->Bands) || !g_uint64_checked_mul(&ls, ps, image->Xsize) || !g_uint64_checked_mul(&sizeof_image, ls, image->Ysize) || (image->dtype == VIPS_IMAGE_SETBUF && sizeof_image > G_MAXSIZE - 16)) vips_buf_appends(buf, "dimension overflow\n"); /* These checks are expensive -- only do in leakcheck mode. */ if (vips__leak) { /* Must lock around inter-image links. */ g_mutex_lock(&vips__global_lock); if (vips_slist_map2(image->upstream, (VipsSListMap2Fn) vips_image_sanity_upstream, image, NULL)) vips_buf_appends(buf, "upstream broken\n"); if (vips_slist_map2(image->downstream, (VipsSListMap2Fn) vips_image_sanity_downstream, image, NULL)) vips_buf_appends(buf, "downstream broken\n"); g_mutex_unlock(&vips__global_lock); } VIPS_OBJECT_CLASS(vips_image_parent_class)->sanity(object, buf); } static void vips_image_rewind(VipsObject *object) { VipsImage *image = VIPS_IMAGE(object); char *filename; char *mode; /* This triggers a dispose. Copy filename/mode across the dispose. */ filename = g_strdup(vips_image_get_filename(image)); mode = g_strdup(vips_image_get_mode(image)); VIPS_OBJECT_CLASS(vips_image_parent_class)->rewind(object); g_assert(image->filename == NULL); g_assert(image->mode == NULL); image->filename = filename; image->mode = mode; } /* Delayed save. */ /* From "written" callback: save to image->filename using VipsForeign. */ static void vips_image_save_cb(VipsImage *image, int *result, void *data) { if (vips_foreign_save(image, image->filename, NULL)) *result = -1; } /* Progress feedback. */ static void vips_image_preeval_cb(VipsImage *image, VipsProgress *progress, int *last) { int tile_width; int tile_height; int n_lines; *last = -1; vips_get_tile_size(image, &tile_width, &tile_height, &n_lines); printf(_("%s %s: %d x %d pixels, %d threads, %d x %d tiles, " "%d lines in buffer"), vips_get_prgname(), image->filename, image->Xsize, image->Ysize, vips_concurrency_get(), tile_width, tile_height, n_lines); printf("\n"); } static void vips_image_eval_cb(VipsImage *image, VipsProgress *progress, int *last) { if (progress->percent != *last) { printf(_("%s %s: %d%% complete"), vips_get_prgname(), image->filename, progress->percent); printf("\r"); fflush(stdout); *last = progress->percent; /* Needs DEBUG in region.c vips_region_dump_all(); */ } } static void vips_image_posteval_cb(VipsImage *image, VipsProgress *progress, void *data) { /* Spaces at end help to erase the %complete message we overwrite. */ printf(_("%s %s: done in %.3gs \n"), vips_get_prgname(), image->filename, g_timer_elapsed(progress->start, NULL)); } /* Attach progress feedback, if required. */ static void vips_image_add_progress(VipsImage *image) { if (vips__progress || g_getenv("VIPS_PROGRESS") #ifdef ENABLE_DEPRECATED || g_getenv("IM_PROGRESS") #endif ) { /* Keep the %complete we displayed last time here. */ int *last = VIPS_NEW(image, int); g_signal_connect(image, "preeval", G_CALLBACK(vips_image_preeval_cb), last); g_signal_connect(image, "eval", G_CALLBACK(vips_image_eval_cb), last); g_signal_connect(image, "posteval", G_CALLBACK(vips_image_posteval_cb), NULL); vips_image_set_progress(image, TRUE); } } /* We have to do a lot of work in _build() so we can work with the stuff in * /deprecated to support the vips7 API. We could get rid of most of this * stuff if we were vips8-only. */ static int vips_image_build(VipsObject *object) { VipsImage *image = VIPS_IMAGE(object); const char *filename = image->filename; const char *mode = image->mode; guint32 magic; guint64 sizeof_image; VIPS_DEBUG_MSG("vips_image_build: %p\n", image); if (VIPS_OBJECT_CLASS(vips_image_parent_class)->build(object)) return -1; /* Parse the mode string. */ switch (mode[0]) { case 'v': if (vips_image_open_input(image)) return -1; break; case 'r': if ((magic = vips__file_magic(filename))) { /* We may need to byteswap. */ if (GUINT_FROM_BE(magic) == image->magic) { /* Native open. */ if (vips_image_open_input(image)) return -1; } else { VipsImage *t; VipsImage *t2; /* Open the image in t, then byteswap to this * image. */ if (!(t = vips_image_new_mode(filename, "v"))) return -1; if (vips_byteswap(t, &t2, NULL)) { g_object_unref(t); return -1; } g_object_unref(t); image->dtype = VIPS_IMAGE_PARTIAL; if (vips_image_write(t2, image)) { g_object_unref(t2); return -1; } g_object_unref(t2); } } else { VipsImage *t; if (mode[1] == 's') { if (vips_foreign_load(filename, &t, "access", VIPS_ACCESS_SEQUENTIAL, NULL)) return -1; } else { if (vips_foreign_load(filename, &t, NULL)) return -1; } image->dtype = VIPS_IMAGE_PARTIAL; if (vips_image_write(t, image)) { g_object_unref(t); return -1; } g_object_unref(t); } break; case 'w': { const char *file_op; /* Make sure the vips saver is there ... strange things will * happen if this type is renamed or removed. */ g_assert(g_type_from_name("VipsForeignSaveVips")); if (!(file_op = vips_foreign_find_save(filename))) return -1; /* If this is the vips saver, just save directly ourselves. * Otherwise save with VipsForeign when the image has been * written to. */ if (vips_isprefix("VipsForeignSaveVips", file_op)) image->dtype = VIPS_IMAGE_OPENOUT; else { image->dtype = VIPS_IMAGE_PARTIAL; g_signal_connect(image, "written", G_CALLBACK(vips_image_save_cb), NULL); } } break; case 't': image->dtype = VIPS_IMAGE_SETBUF; image->dhint = VIPS_DEMAND_STYLE_ANY; break; case 'p': image->dtype = VIPS_IMAGE_PARTIAL; break; case 'a': if ((image->fd = vips__open_image_read(filename)) == -1) return -1; image->dtype = VIPS_IMAGE_OPENIN; image->dhint = VIPS_DEMAND_STYLE_THINSTRIP; if (image->Bands == 1) image->Type = VIPS_INTERPRETATION_B_W; else if (image->Bands == 3) image->Type = VIPS_INTERPRETATION_sRGB; else image->Type = VIPS_INTERPRETATION_MULTIBAND; /* Read the real file length and check against what we think * the size should be. */ if ((image->file_length = vips_file_length(image->fd)) == -1) return -1; /* Very common, so a special message. */ sizeof_image = VIPS_IMAGE_SIZEOF_IMAGE(image); if (image->file_length - image->sizeof_header < sizeof_image) { vips_error("VipsImage", _("unable to open \"%s\", file too short"), image->filename); return -1; } /* Just weird. Only print a warning for this, since we should * still be able to process it without coredumps. */ if (image->file_length - image->sizeof_header > sizeof_image) g_warning("%s is longer than expected", image->filename); break; case 'm': if (image->Bands == 1) image->Type = VIPS_INTERPRETATION_B_W; else if (image->Bands == 3) image->Type = VIPS_INTERPRETATION_sRGB; else image->Type = VIPS_INTERPRETATION_MULTIBAND; image->dtype = VIPS_IMAGE_SETBUF_FOREIGN; image->dhint = VIPS_DEMAND_STYLE_ANY; break; default: vips_error("VipsImage", _("bad mode \"%s\""), mode); return -1; } vips_image_add_progress(image); return 0; } static void * vips_image_real_invalidate_cb(VipsRegion *reg, void *a, void *b) { vips_region_invalidate(reg); return NULL; } static void vips_image_real_invalidate(VipsImage *image, void *data) { VIPS_DEBUG_MSG("vips_image_real_invalidate: %p\n", image); VIPS_GATE_START("vips_image_real_invalidate: wait"); g_mutex_lock(&image->sslock); VIPS_GATE_STOP("vips_image_real_invalidate: wait"); (void) vips_slist_map2(image->regions, (VipsSListMap2Fn) vips_image_real_invalidate_cb, NULL, NULL); g_mutex_unlock(&image->sslock); } static void vips_image_real_minimise(VipsImage *image, void *data) { VIPS_DEBUG_MSG("vips_image_real_minimise: %p\n", image); } static void vips_image_real_written(VipsImage *image, int *result, void *data) { VIPS_DEBUG_MSG("vips_image_real_written: %p\n", image); /* For vips image write, append the xml after the data. */ if (image->dtype == VIPS_IMAGE_OPENOUT && vips__writehist(image)) *result = -1; } static void vips_image_class_init(VipsImageClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_image_class_init:\n"); gobject_class->finalize = vips_image_finalize; gobject_class->dispose = vips_image_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->new_from_string = vips_image_new_from_file_object; vobject_class->to_string = vips_image_to_string; vobject_class->output_needs_arg = TRUE; vobject_class->output_to_arg = vips_image_write_object; vobject_class->nickname = "image"; vobject_class->description = _("image class"); vobject_class->dump = vips_image_dump; vobject_class->summary = vips_image_summary; vobject_class->sanity = vips_image_sanity; vobject_class->rewind = vips_image_rewind; vobject_class->build = vips_image_build; class->invalidate = vips_image_real_invalidate; class->written = vips_image_real_written; class->minimise = vips_image_real_minimise; /* Create properties. */ /* It'd be good to have these as set once at construct time, but we * can't :-( * * For example, a "p" image might be made with vips_image_new() and * constructed, then passed to vips_copy() of whatever to be written to. * That operation will then need to set width/height etc. * * We can't set_once either, since vips_copy() etc. need to update * xoffset and friends on the way through. */ VIPS_ARG_INT(class, "width", 2, _("Width"), _("Image width in pixels"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Xsize), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 3, _("Height"), _("Image height in pixels"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Ysize), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "bands", 4, _("Bands"), _("Number of bands in image"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Bands), 1, VIPS_MAX_COORD, 1); VIPS_ARG_ENUM(class, "format", 5, _("Format"), _("Pixel format in image"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, BandFmt), VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR); VIPS_ARG_ENUM(class, "coding", 6, _("Coding"), _("Pixel coding"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Coding), VIPS_TYPE_CODING, VIPS_CODING_NONE); VIPS_ARG_ENUM(class, "interpretation", 7, _("Interpretation"), _("Pixel interpretation"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Type), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_MULTIBAND); VIPS_ARG_DOUBLE(class, "xres", 8, _("Xres"), _("Horizontal resolution in pixels/mm"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Xres), -0.0, 1000000, 0); VIPS_ARG_DOUBLE(class, "yres", 9, _("Yres"), _("Vertical resolution in pixels/mm"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Yres), -0.0, 1000000, 0); VIPS_ARG_INT(class, "xoffset", 10, _("Xoffset"), _("Horizontal offset of origin"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Xoffset), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_INT(class, "yoffset", 11, _("Yoffset"), _("Vertical offset of origin"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, Yoffset), -VIPS_MAX_COORD, VIPS_MAX_COORD, 0); VIPS_ARG_STRING(class, "filename", 12, _("Filename"), _("Image filename"), VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET(VipsImage, filename), NULL); VIPS_ARG_STRING(class, "mode", 13, _("Mode"), _("Open mode"), VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET(VipsImage, mode), "p"); VIPS_ARG_BOOL(class, "kill", 14, _("Kill"), _("Block evaluation on this image"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsImage, kill), FALSE); VIPS_ARG_ENUM(class, "demand", 15, _("Demand style"), _("Preferred demand style for this image"), VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET(VipsImage, dhint), VIPS_TYPE_DEMAND_STYLE, VIPS_DEMAND_STYLE_SMALLTILE); VIPS_ARG_UINT64(class, "sizeof_header", 16, _("Size of header"), _("Offset in bytes from start of file"), VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET(VipsImage, sizeof_header), 0, 1000000000, VIPS_SIZEOF_HEADER); VIPS_ARG_POINTER(class, "foreign_buffer", 17, _("Foreign buffer"), _("Pointer to foreign pixels"), VIPS_ARGUMENT_SET_ONCE | VIPS_ARGUMENT_CONSTRUCT, G_STRUCT_OFFSET(VipsImage, data)); /* Create signals. */ /** * VipsImage::preeval: * @image: the image to be calculated * @progress: (type VipsProgress): [struct@Progress] for this image * * This signal is emitted once before computation of @image * starts. It's a good place to set up evaluation feedback. * * Use [method@Image.set_progress] to turn on progress reporting for an * image. */ vips_image_signals[SIG_PREEVAL] = g_signal_new("preeval", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsImageClass, preeval), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * VipsImage::eval: * @image: the image being calculated * @progress: (type VipsProgress): [struct@Progress] for this image * * This signal is emitted once per work unit (typically a 128 x * 128 area of pixels) during image computation. * * You can use this signal to update user-interfaces with progress * feedback. Beware of updating too frequently: you will usually * need some throttling mechanism. * * Use [method@Image.set_progress] to turn on progress reporting for an * image. */ vips_image_signals[SIG_EVAL] = g_signal_new("eval", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsImageClass, eval), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * VipsImage::posteval: * @image: the image that was calculated * @progress: (type VipsProgress): [struct@Progress] for this image * * This signal is emitted once at the end of the computation * of @image. It's a good place to shut down evaluation feedback. * * Use [method@Image.set_progress] to turn on progress reporting for an * image. */ vips_image_signals[SIG_POSTEVAL] = g_signal_new("posteval", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsImageClass, posteval), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * VipsImage::written: * @image: the image that was calculated * @result: (out) (type gint): set to non-zero to indicate error * * This signal is emitted just after an image has been * written to. It is * used by vips to implement things like write to foreign file * formats. */ vips_image_signals[SIG_WRITTEN] = g_signal_new("written", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsImageClass, written), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * VipsImage::invalidate: * @image: the image that has changed * * This signal is emitted when an image or one of it's * upstream data sources has been destructively modified. See * [method@Image.invalidate_all]. */ vips_image_signals[SIG_INVALIDATE] = g_signal_new("invalidate", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsImageClass, invalidate), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VipsImage::minimise: * @image: the image that is being minimised * * This signal is emitted when an image has been asked to * minimise memory usage. All non-essential caches are dropped. * See [method@Image.minimise_all]. */ vips_image_signals[SIG_MINIMISE] = g_signal_new("minimise", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsImageClass, minimise), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void vips_image_init(VipsImage *image) { VIPS_DEBUG_MSG("vips_image_init: %p\n", image); /* Default to native order. */ image->magic = vips_amiMSBfirst() ? VIPS_MAGIC_SPARC : VIPS_MAGIC_INTEL; image->Xsize = 1; image->Ysize = 1; image->Bands = 1; image->Xres = 1.0; image->Yres = 1.0; image->fd = -1; /* since 0 is stdout */ g_mutex_init(&image->sslock); image->sizeof_header = VIPS_SIZEOF_HEADER; image->mode = g_strdup("p"); #ifdef DEBUG_LEAK g_object_set_qdata_full(G_OBJECT(image), vips__image_pixels_quark, g_new0(VipsImagePixels, 1), (GDestroyNotify) g_free); #endif /*DEBUG_LEAK*/ } int vips_image_written(VipsImage *image) { int result; VIPS_DEBUG_MSG("vips_image_written: %p\n", image); result = 0; g_signal_emit(image, vips_image_signals[SIG_WRITTEN], 0, &result); return result; } static void vips_image_invalidate(VipsImage *image) { VIPS_DEBUG_MSG("vips_image_invalidate: %p\n", image); g_signal_emit(image, vips_image_signals[SIG_INVALIDATE], 0); } static void * vips_image_invalidate_all_cb(VipsImage *image, void *a, void *b) { vips_image_invalidate(image); return NULL; } /** * vips_image_invalidate_all: * @image: [class@Image] to invalidate * * Invalidate all pixel caches on @image and any downstream images, that * is, images which depend on this image. Additionally, all operations which * depend upon this image are dropped from the VIPS operation cache. * * You should call this function after destructively modifying an image with * something like [method@Image.draw_circle]. * * The [signal@Image::invalidate] signal is emitted for all invalidated images. * * ::: seealso * [method@Region.invalidate]. */ void vips_image_invalidate_all(VipsImage *image) { VIPS_DEBUG_MSG("vips_image_invalidate_all: %p\n", image); (void) vips__link_map(image, FALSE, (VipsSListMap2Fn) vips_image_invalidate_all_cb, NULL, NULL); } static void vips_image_minimise(VipsImage *image) { VIPS_DEBUG_MSG("vips_image_minimise: %p\n", image); g_signal_emit(image, vips_image_signals[SIG_MINIMISE], 0); } static void * vips_image_minimise_all_cb(VipsImage *image, void *a, void *b) { vips_image_minimise(image); return NULL; } /** * vips_image_minimise_all: * @image: [class@Image] to minimise * * Minimise memory use on this image and any upstream images, that is, images * which this image depends upon. This function is called automatically at the * end of a computation, but it might be useful to call at other times. * * The [signal@Image::minimise] signal is emitted for all minimised images. */ void vips_image_minimise_all(VipsImage *image) { /* Just like the eval callbacks, don't minimise for sub-evaluations. */ if (vips_image_get_typeof(image, "hide-progress")) return; /* Minimisation will modify things like sources, so we can't run it * from many threads. */ g_mutex_lock(&vips__minimise_lock); (void) vips__link_map(image, TRUE, (VipsSListMap2Fn) vips_image_minimise_all_cb, NULL, NULL); g_mutex_unlock(&vips__minimise_lock); } /** * vips_image_is_sequential: * @image: [class@Image] to minimise * * `TRUE` if any of the images upstream from @image were opened in sequential * mode. Some operations change behaviour slightly in sequential mode to * optimize memory behaviour. * * Returns: `TRUE` if @image is in sequential mode. */ gboolean vips_image_is_sequential(VipsImage *image) { return vips_image_get_typeof(image, VIPS_META_SEQUENTIAL); } /* Attach a new time struct, if necessary, and reset it. */ static int vips_progress_add(VipsImage *image) { VipsProgress *progress; VIPS_DEBUG_MSG("vips_progress_add: %p\n", image); if (!(progress = image->time)) { if (!(image->time = VIPS_NEW(NULL, VipsProgress))) return -1; progress = image->time; progress->im = image; progress->start = NULL; } if (!progress->start) progress->start = g_timer_new(); g_timer_start(progress->start); progress->run = 0; progress->eta = 0; progress->tpels = VIPS_IMAGE_N_PELS(image); progress->npels = 0; progress->percent = 0; return 0; } static void vips_progress_update(VipsProgress *progress, guint64 processed) { float prop; VIPS_DEBUG_MSG("vips_progress_update: %p\n", progress); g_assert(progress); progress->run = g_timer_elapsed(progress->start, NULL); progress->npels = processed; prop = (float) progress->npels / (float) progress->tpels; progress->percent = 100 * prop; /* Don't estimate eta until we are 10% in. */ if (prop > 0.1) progress->eta = (1.0 / prop) * progress->run - progress->run; } void vips_image_preeval(VipsImage *image) { if (image->progress_signal) { VIPS_DEBUG_MSG("vips_image_preeval: %p\n", image); g_assert(vips_object_sanity(VIPS_OBJECT(image->progress_signal))); (void) vips_progress_add(image); /* For vips7 compat, we also have to make sure ->time on the * image that was originally marked with * vips_image_set_progress() is valid. */ (void) vips_progress_add(image->progress_signal); if (!vips_image_get_typeof(image, "hide-progress")) g_signal_emit(image->progress_signal, vips_image_signals[SIG_PREEVAL], 0, image->time); } } /* Updated the number of pixels that have been processed. */ void vips_image_eval(VipsImage *image, guint64 processed) { if (image->progress_signal && image->time) { VIPS_DEBUG_MSG("vips_image_eval: %p\n", image); g_assert(vips_object_sanity(VIPS_OBJECT(image->progress_signal))); vips_progress_update(image->time, processed); /* For vips7 compat, update the ->time on the signalling image * too, even though it may have a different width/height to * the image we are actually generating. */ if (image->progress_signal->time != image->time) vips_progress_update(image->progress_signal->time, processed); if (!vips_image_get_typeof(image, "hide-progress")) g_signal_emit(image->progress_signal, vips_image_signals[SIG_EVAL], 0, image->time); } } void vips_image_posteval(VipsImage *image) { if (image->progress_signal && image->progress_signal->time) { gint64 processed; VIPS_DEBUG_MSG("vips_image_posteval: %p\n", image); g_assert(vips_object_sanity( VIPS_OBJECT(image->progress_signal))); /* Make sure posteval sees a finished progress. */ processed = image->time->tpels; vips_progress_update(image->time, processed); /* For vips7 compat, update the ->time on the signalling image * too, even though it may have a different width/height to * the image we are actually generating. */ if (image->progress_signal->time != image->time) vips_progress_update(image->progress_signal->time, processed); if (!vips_image_get_typeof(image, "hide-progress")) g_signal_emit(image->progress_signal, vips_image_signals[SIG_POSTEVAL], 0, image->time); } } /** * vips_image_set_progress: * @image: image to signal progress on * @progress: turn progress reporting on or off * * vips signals evaluation progress via the [signal@Image::preeval], * [signal@Image::eval] and [signal@Image::posteval] * signals. Progress is signalled on the most-downstream image for which * [method@Image.set_progress] was called. */ void vips_image_set_progress(VipsImage *image, gboolean progress) { if (progress && !image->progress_signal) { VIPS_DEBUG_MSG("vips_image_set_progress: %p %s\n", image, image->filename); image->progress_signal = image; } else if (!progress) image->progress_signal = NULL; } /** * vips_image_iskilled: * @image: image to test * * If @image has been killed (see [method@Image.set_kill]), set an error * message, clear the [class@Image].kill flag and return `TRUE`. Otherwise * return `FALSE`. * * Handy for loops which need to run sets of threads which can fail. * * ::: seealso * [method@Image.set_kill]. * * Returns: `TRUE` if @image has been killed. */ gboolean vips_image_iskilled(VipsImage *image) { gboolean kill; kill = image->kill; // check the image we are signalling progress on too if (image->progress_signal) kill |= image->progress_signal->kill; /* Has kill been set for this image? If yes, abort evaluation. */ if (kill) { #ifdef VIPS_DEBUG printf("vips_image_iskilled: %s (%p) killed\n", image->filename, image); #endif /*VIPS_DEBUG*/ vips_error("VipsImage", _("killed for image \"%s\""), image->filename); /* We've picked up the kill message, it's now our caller's * responsibility to pass the message up the chain. */ vips_image_set_kill(image, FALSE); } return kill; } /** * vips_image_set_kill: * @image: image to test * @kill: the kill state * * Set the [class@Image].kill flag on an image. Handy for stopping sets of * threads. * * ::: seealso * [method@Image.iskilled]. */ void vips_image_set_kill(VipsImage *image, gboolean kill) { if (image->kill != kill) VIPS_DEBUG_MSG("vips_image_set_kill: %s (%p) %d\n", image->filename, image, kill); image->kill = kill; // set here too if (image->progress_signal) image->progress_signal->kill = kill; } /* Fills the given buffer with a temporary filename. * Assuming that "int" might be 64 Bit wide a buffer size of 26 suffices. */ static void vips_image_temp_name(char *name, int size) { static int global_serial = 0; int serial = g_atomic_int_add(&global_serial, 1); g_snprintf(name, size, "temp-%d", serial); } /** * vips_image_new: (constructor) * * [ctor@Image.new] creates a new, empty [class@Image]. * If you write to one of these images, vips will just attach some callbacks, * no pixels will be generated. * * Write pixels to an image with [method@Image.generate] or * [method@Image.write_line]. Write a whole image to another image with * [method@Image.write]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new(void) { VipsImage *image; char filename[26]; vips_check_init(); vips_image_temp_name(filename, sizeof(filename)); image = VIPS_IMAGE(g_object_new(VIPS_TYPE_IMAGE, NULL)); g_object_set(image, "filename", filename, "mode", "p", NULL); if (vips_object_build(VIPS_OBJECT(image))) { VIPS_UNREF(image); return NULL; } return image; } VipsImage * vips_image_new_mode(const char *filename, const char *mode) { VipsImage *image; g_assert(filename); g_assert(mode); vips_check_init(); image = VIPS_IMAGE(g_object_new(VIPS_TYPE_IMAGE, NULL)); g_object_set(image, "filename", filename, "mode", mode, NULL); if (vips_object_build(VIPS_OBJECT(image))) { VIPS_UNREF(image); return NULL; } return image; } /** * vips_image_new_memory: (skip) * * [ctor@Image.new_memory] creates a new [class@Image] which, when written to, * will create a memory image. * * ::: seealso * [ctor@Image.new]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_memory(void) { char filename[26]; vips_image_temp_name(filename, sizeof(filename)); return vips_image_new_mode(filename, "t"); } /** * vips_image_memory: (constructor) * * A renamed [ctor@Image.new_memory] ... Some gobject binding systems do not * like more than one `_new()` method. * * ::: seealso * [ctor@Image.new_memory]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_memory(void) { return vips_image_new_memory(); } /** * vips_filename_get_filename: * @vips_filename: a filename including a set of options * * Given a vips filename like "fred.jpg[Q=90]", return a new string of * just the filename part, "fred.jpg" in this case. * * Useful for language bindings. * * ::: seealso * [func@filename_get_options]. * * Returns: transfer full: just the filename component. */ char * vips_filename_get_filename(const char *vips_filename) { char filename[VIPS_PATH_MAX]; char options[VIPS_PATH_MAX]; vips__filename_split8(vips_filename, filename, options); return g_strdup(filename); } /** * vips_filename_get_options: * @vips_filename: a filename including a set of options * * Given a vips filename like "fred.jpg[Q=90]", return a new string of * just the options part, "[Q=90]" in this case. * * Useful for language bindings. * * ::: seealso * [func@filename_get_filename]. * * Returns: transfer full: just the options component. */ char * vips_filename_get_options(const char *vips_filename) { char filename[VIPS_PATH_MAX]; char options[VIPS_PATH_MAX]; vips__filename_split8(vips_filename, filename, options); return g_strdup(options); } /** * vips_image_new_from_file: (constructor) * @name: file to open * @...: `NULL`-terminated list of optional named arguments * * [ctor@Image.new_from_file] opens @name for reading. It can load files * in many image formats, including VIPS, TIFF, PNG, JPEG, FITS, Matlab, * OpenEXR, CSV, WebP, Radiance, RAW, PPM and others. * * Load options may be appended to @filename as `[name=value,...]` or given as * a `NULL`-terminated list of name-value pairs at the end of the arguments. * Options given in the function call override options given in the filename. * Many loaders add extra options, see [ctor@Image.jpegload], for example. * * [ctor@Image.new_from_file] always returns immediately with the header * fields filled in. No pixels are actually read until you first access them. * * @access lets you set a [enum@Access] hint giving the expected access pattern * for this file. * [enum@Vips.Access.RANDOM] means you can fetch pixels randomly from the image. * This is the default mode. [enum@Vips.Access.SEQUENTIAL] means you will * read the whole image exactly once, top-to-bottom. In this mode, libvips * can avoid converting the whole image in one go, for a large memory saving. * You are allowed to make small non-local references, so area operations like * convolution will work. * * In [enum@Vips.Access.RANDOM] mode, small images are decompressed to memory * and then processed from there. Large images are decompressed to temporary * random-access files on disc and then processed from there. * * Set @memory to `TRUE` to force loading via memory. The default is to load * large random access images via temporary disc files. See * [ctor@Image.new_temp_file] for an * explanation of how VIPS selects a location for the temporary file. * * The disc threshold can be set with the `--vips-disc-threshold` * command-line argument, or the `VIPS_DISC_THRESHOLD` environment variable. * The value is a simple integer, but can take a unit postfix of "k", * "m" or "g" to indicate kilobytes, megabytes or gigabytes. * The default threshold is 100 MB. * * For example: * * ```c * VipsImage *image = vips_image_new_from_file("fred.tif", * "page", 12, * NULL); * ``` * * Will open "fred.tif", reading page 12. * * ```c * VipsImage *image = vips_image_new_from_file("fred.jpg[shrink=2]", NULL); * ``` * * Will open `fred.jpg`, downsampling by a factor of two. * * Use [func@Foreign.find_load] or [func@Foreign.is_a] to see what format a * file is in and therefore what options are available. If you need more * control over the loading process, you can call loaders directly, see * [ctor@Image.jpegload], for example. * * ::: tip "Optional arguments" * * @access: [enum@Access], hint expected access pattern * * @memory: `gboolean`, force load via memory * * ::: seealso * [func@Foreign.find_load], [func@Foreign.is_a], * [method@Image.write_to_file]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_file(const char *name, ...) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; va_list ap; int result; VipsImage *out; vips_check_init(); vips__filename_split8(name, filename, option_string); if (!(operation_name = vips_foreign_find_load(filename))) return NULL; va_start(ap, name); result = vips_call_split_option_string(operation_name, option_string, ap, filename, &out); va_end(ap); if (result) return NULL; return out; } /** * vips_image_new_from_file_RW: (constructor) * @filename: filename to open * * Opens the named file for simultaneous reading and writing. This will only * work for VIPS files in a format native to your machine. It is only for * paintbox-type applications. * * ::: seealso * [method@Image.draw_circle]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_file_RW(const char *filename) { return vips_image_new_mode(filename, "rw"); } /** * vips_image_new_from_file_raw: (constructor) * @filename: filename to open * @xsize: image width * @ysize: image height * @bands: image bands (or bytes per pixel) * @offset: bytes to skip at start of file * * This function maps the named file and returns a [class@Image] you can use to * read it. * * It returns an 8-bit image with @bands bands. If the image is not 8-bit, use * [method@Image.copy] to transform the descriptor after loading it. * * ::: seealso * [method@Image.copy], [ctor@Image.rawload], [ctor@Image.new_from_file]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_file_raw(const char *filename, int xsize, int ysize, int bands, guint64 offset) { VipsImage *image; vips_check_init(); image = VIPS_IMAGE(g_object_new(VIPS_TYPE_IMAGE, NULL)); g_object_set(image, "filename", filename, "mode", "a", "width", xsize, "height", ysize, "bands", bands, "sizeof_header", offset, NULL); if (vips_object_build(VIPS_OBJECT(image))) { VIPS_UNREF(image); return NULL; } return image; } /** * vips_image_new_from_memory: (constructor) * @data: (array length=size) (element-type guint8) (transfer none): start of memory area * @size: (type gsize): length of memory area * @width: image width * @height: image height * @bands: image bands (or bytes per pixel) * @format: image format * * This function wraps a [class@Image] around a memory area. The memory area * must be a simple array, for example RGBRGBRGB, left-to-right, * top-to-bottom. Use [ctor@Image.new_from_buffer] to load an area of memory * containing an image in a format. * * VIPS does not take * responsibility for the area of memory, it's up to you to make sure it's * freed when the image is closed. See for example [signal@Object::close]. * * Because VIPS is "borrowing" @data from the caller, this function is * extremely dangerous. Unless you are very careful, you will get crashes or * memory corruption. Use [ctor@Image.new_from_memory_copy] instead if you are * at all unsure. * * Use [method@Image.copy] to set other image properties. * * ::: seealso * [ctor@Image.new], [method@Image.write_to_memory], * [ctor@Image.new_from_memory_copy]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format) { VipsImage *image; char filename[26]; vips_check_init(); vips_image_temp_name(filename, sizeof(filename)); image = VIPS_IMAGE(g_object_new(VIPS_TYPE_IMAGE, NULL)); g_object_set(image, "filename", filename, "mode", "m", "foreign_buffer", data, "width", width, "height", height, "bands", bands, "format", format, NULL); if (vips_object_build(VIPS_OBJECT(image))) { VIPS_UNREF(image); return NULL; } if (size < VIPS_IMAGE_SIZEOF_IMAGE(image)) { vips_error("VipsImage", _("memory area too small -- " "should be %" G_GUINT64_FORMAT " bytes, you passed %zd"), VIPS_IMAGE_SIZEOF_IMAGE(image), size); VIPS_UNREF(image); return NULL; } return image; } static void vips_image_new_from_memory_copy_cb(VipsImage *image, void *data_copy) { vips_tracked_free(data_copy); } /** * vips_image_new_from_memory_copy: (constructor) * @data: (array length=size) (element-type guint8) (transfer none): start of memory area * @size: (type gsize): length of memory area * @width: image width * @height: image height * @bands: image bands (or bytes per pixel) * @format: image format * * Like [ctor@Image.new_from_memory], but VIPS will make a copy of the memory * area. This means more memory use and an extra copy operation, but is much * simpler and safer. * * ::: seealso * [ctor@Image.new_from_memory]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format) { void *data_copy; VipsImage *image; vips_check_init(); if (!(data_copy = vips_tracked_malloc(size))) return NULL; memcpy(data_copy, data, size); if (!(image = vips_image_new_from_memory(data_copy, size, width, height, bands, format))) { vips_tracked_free(data_copy); return NULL; } g_signal_connect(image, "close", G_CALLBACK(vips_image_new_from_memory_copy_cb), data_copy); return image; } /** * vips_image_new_from_buffer: (constructor) * @buf: (array length=len) (element-type guint8) (transfer none): image data * @len: (type gsize): length of memory buffer * @option_string: set of extra options as a string * @...: `NULL`-terminated list of optional named arguments * * Loads an image from the formatted area of memory @buf, @len using the * loader recommended by [func@Foreign.find_load_buffer]. * To load an unformatted area of memory, use * [ctor@Image.new_from_memory]. * * VIPS does not take * responsibility for the area of memory, it's up to you to make sure it's * freed when the image is closed. See for example [signal@Object::close]. * * Load options may be given in @option_string as `[name=value,...]` or given as * a `NULL`-terminated list of name-value pairs at the end of the arguments. * Options given in the function call override options given in the filename. * * ::: seealso * [method@Image.write_to_buffer]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_buffer(const void *buf, size_t len, const char *option_string, ...) { const char *operation_name; va_list ap; int result; VipsImage *out; VipsBlob *blob; vips_check_init(); if (!(operation_name = vips_foreign_find_load_buffer(buf, len))) return NULL; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, option_string); result = vips_call_split_option_string(operation_name, option_string, ap, blob, &out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); if (result) return NULL; return out; } /** * vips_image_new_from_source: (constructor) * @source: (transfer none): source to fetch image from * @option_string: set of extra options as a string * @...: `NULL`-terminated list of optional named arguments * * Loads an image from the formatted source @input, * loader recommended by [func@Foreign.find_load_source]. * * Load options may be given in @option_string as `[name=value,...]` or given as * a `NULL`-terminated list of name-value pairs at the end of the arguments. * Options given in the function call override options given in the string. * * ::: seealso * [method@Image.write_to_target]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_source(VipsSource *source, const char *option_string, ...) { const char *filename = vips_connection_filename(VIPS_CONNECTION(source)); const char *operation_name; va_list ap; int result; VipsImage *out; vips_check_init(); vips_error_freeze(); operation_name = vips_foreign_find_load_source(source); vips_error_thaw(); if (operation_name) { va_start(ap, option_string); result = vips_call_split_option_string(operation_name, option_string, ap, source, &out); va_end(ap); } else if (filename) { /* Try with the old file-based loaders. */ if (!(operation_name = vips_foreign_find_load(filename))) return NULL; va_start(ap, option_string); result = vips_call_split_option_string(operation_name, option_string, ap, filename, &out); va_end(ap); } else if (vips_source_is_mappable(source)) { /* Try with the old buffer-based loaders. */ VipsBlob *blob; const void *buf; size_t len; if (!(blob = vips_source_map_blob(source))) return NULL; buf = vips_blob_get(blob, &len); if (!(operation_name = vips_foreign_find_load_buffer(buf, len))) { vips_area_unref(VIPS_AREA(blob)); return NULL; } va_start(ap, option_string); result = vips_call_split_option_string(operation_name, option_string, ap, blob, &out); va_end(ap); vips_area_unref(VIPS_AREA(blob)); } else { vips_error("VipsImage", "%s", _("unable to load source")); result = -1; } if (result) return NULL; return out; } /** * vips_image_new_matrix: (constructor) * @width: image width * @height: image height * * This convenience function makes an image which is a matrix: a one-band * [enum@Vips.BandFormat.DOUBLE] image held in memory. * * Use [func@IMAGE_ADDR], or [func@MATRIX] to address pixels in the image. * * Use [method@Image.set_double] to set "scale" and "offset", if required. * * ::: seealso * [ctor@Image.new_matrixv] * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_matrix(int width, int height) { VipsImage *image; vips_check_init(); image = VIPS_IMAGE(g_object_new(VIPS_TYPE_IMAGE, NULL)); g_object_set(image, "filename", "vips_image_new_matrix", "mode", "t", "width", width, "height", height, "bands", 1, "format", VIPS_FORMAT_DOUBLE, "interpretation", VIPS_INTERPRETATION_MATRIX, NULL); if (vips_object_build(VIPS_OBJECT(image))) { VIPS_UNREF(image); return NULL; } if (vips_image_write_prepare(image)) { g_object_unref(image); return NULL; } return image; } /** * vips_image_new_matrixv: (constructor) * @width: image width * @height: image height * @...: matrix coefficients * * As [ctor@Image.new_matrix], but initialise the matrix from the argument * list. After @height should be @width * @height double constants which are * used to set the matrix elements. * * ::: seealso * [ctor@Image.new_matrix] * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_matrixv(int width, int height, ...) { va_list ap; VipsImage *matrix; int x, y; vips_check_init(); matrix = vips_image_new_matrix(width, height); va_start(ap, height); for (y = 0; y < height; y++) for (x = 0; x < width; x++) *VIPS_MATRIX(matrix, x, y) = va_arg(ap, double); va_end(ap); return matrix; } /** * vips_image_new_matrix_from_array: (constructor) * @width: image width * @height: image height * @array: (array length=size) (transfer none): array of elements * @size: (type gsize): number of elements * * A binding-friendly version of [ctor@Image.new_matrixv]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_matrix_from_array(int width, int height, const double *array, int size) { VipsImage *matrix; int x, y; int i; if (size != width * height) { vips_error("VipsImage", _("bad array length -- should be %d, you passed %d"), width * height, size); return NULL; } vips_check_init(); matrix = vips_image_new_matrix(width, height); i = 0; for (y = 0; y < height; y++) for (x = 0; x < width; x++) *VIPS_MATRIX(matrix, x, y) = array[i++]; return matrix; } /** * vips_image_matrix_from_array: (skip) * @width: image width * @height: image height * @array: (array length=size) (transfer none): array of elements * @size: (type gsize): number of elements * * A renamed [ctor@Image.new_matrix_from_array]. Some gobject bindings do not * like more than one _new method. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_matrix_from_array(int width, int height, const double *array, int size) { return vips_image_new_matrix_from_array(width, height, array, size); } /** * vips_image_new_from_image: (constructor) * @image: image to copy * @c: (array length=n) (transfer none): array of constants * @n: number of constants * * Creates a new image with width, height, format, interpretation, resolution * and offset taken from @image, but with number of bands taken from @n and the * value of each band element set from @c. * * ::: seealso * [ctor@Image.new_from_image1] * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_image(VipsImage *image, const double *c, int n) { VipsObject *scope = (VipsObject *) vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array(scope, 5); double *ones; int i; VipsImage *result; if (!(ones = VIPS_ARRAY(scope, n, double))) { g_object_unref(scope); return NULL; } for (i = 0; i < n; i++) ones[i] = 1.0; if (vips_black(&t[0], 1, 1, NULL) || vips_linear(t[0], &t[1], ones, (double *) c, n, NULL) || vips_cast(t[1], &t[2], image->BandFmt, NULL) || vips_embed(t[2], &t[3], 0, 0, image->Xsize, image->Ysize, "extend", VIPS_EXTEND_COPY, NULL) || vips_copy(t[3], &t[4], "interpretation", image->Type, "xres", image->Xres, "yres", image->Yres, "xoffset", image->Xoffset, "yoffset", image->Yoffset, NULL)) { g_object_unref(scope); return NULL; } result = t[4]; g_object_ref(result); g_object_unref(scope); return result; } /** * vips_image_new_from_image1: (constructor) * @image: image to copy * @c: constants * * Creates a new image with width, height, format, interpretation, resolution * and offset taken from @image, but with one band and each pixel having the * value @c. * * ::: seealso * [ctor@Image.new_from_image] * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_from_image1(VipsImage *image, double c) { return vips_image_new_from_image(image, (const double *) &c, 1); } /** * vips_image_set_delete_on_close: * @image: image to set * @delete_on_close: format of file * * Sets the delete_on_close flag for the image. If this flag is set, when * @image is finalized, the filename held in @image->filename at the time of * this call is deleted. * * This function is clearly extremely dangerous, use with great caution. * * ::: seealso * [ctor@Image.new_temp_file]. */ void vips_image_set_delete_on_close(VipsImage *image, gboolean delete_on_close) { VIPS_DEBUG_MSG("vips_image_set_delete_on_close: %d %s\n", delete_on_close, image->filename); image->delete_on_close = delete_on_close; VIPS_FREE(image->delete_on_close_filename); if (delete_on_close) VIPS_SETSTR(image->delete_on_close_filename, image->filename); } /** * vips_get_disc_threshold: * * Return the number of bytes at which we flip between open via memory and * open via disc. This defaults to 100mb, but can be changed with the * `VIPS_DISC_THRESHOLD` environment variable or the `--vips-disc-threshold` * command-line flag. See [ctor@Image.new_from_file]. * * Returns: disc threshold in bytes. */ guint64 vips_get_disc_threshold(void) { static gboolean done = FALSE; static guint64 threshold; if (!done) { const char *env; done = TRUE; /* 100mb default. */ threshold = 100 * 1024 * 1024; if ((env = g_getenv("VIPS_DISC_THRESHOLD")) #ifdef ENABLE_DEPRECATED || (env = g_getenv("IM_DISC_THRESHOLD")) #endif ) threshold = vips__parse_size(env); if (vips__disc_threshold) threshold = vips__parse_size(vips__disc_threshold); #ifdef DEBUG printf("vips_get_disc_threshold: %zd bytes\n", threshold); #endif /*DEBUG*/ } return threshold; } /** * vips_image_new_temp_file: (constructor) * @format: format of file * * Make a [class@Image] which, when written to, will create a temporary file on * disc. The file will be automatically deleted when the image is destroyed. * @format is something like "%s.v" for a vips file. * * The file is created in the temporary directory. This is set with the * environment variable TMPDIR. If this is not set, then on Unix systems, vips * will default to /tmp. On Windows, vips uses `GetTempPath()` to find the * temporary directory. * * ::: seealso * [ctor@Image.new]. * * Returns: the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_new_temp_file(const char *format) { char *name; VipsImage *image; vips_check_init(); if (!(name = vips__temp_name(format))) return NULL; if (!(image = vips_image_new_mode(name, "w"))) { g_free(name); return NULL; } g_free(name); vips_image_set_delete_on_close(image, TRUE); return image; } static int vips_image_write_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; /* printf("vips_image_write_gen: %p " "left = %d, top = %d, width = %d, height = %d\n", out_region->im, r->left, r->top, r->width, r->height); */ /* Copy with pointers. */ if (vips_region_prepare(ir, r) || vips_region_region(out_region, ir, r, r->left, r->top)) return -1; return 0; } /** * vips_image_write: * @image: image to write * @out: (out): write to this image * * Write @image to @out. Use [ctor@Image.new] and friends to create the * [class@Image] you want to write to. * * ::: seealso * [ctor@Image.new], [method@Image.copy], [method@Image.write_to_file]. * * Returns: 0 on success, or -1 on error. */ int vips_image_write(VipsImage *image, VipsImage *out) { /* image needs to stay alive for this call. It can be unreffed during * the generate. */ g_object_ref(image); if (vips_image_pio_input(image) || vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, image, NULL)) { g_object_unref(image); return -1; } if (vips_image_generate(out, vips_start_one, vips_image_write_gen, vips_stop_one, image, NULL)) { g_object_unref(image); return -1; } /* If @out is a partial image, we need to unref @image when out is * unreffed. * * If it's not partial, perhaps a file we write to or a memory image, * we need to break any links between @image and @out created by * vips_image_pipelinev(). */ if (vips_image_ispartial(out)) { vips_object_local(out, image); } else { vips__reorder_clear(out); vips__link_break_all(out); g_object_unref(image); } return 0; } /** * vips_image_write_to_file: * @image: image to write * @name: write to this file * @...: `NULL`-terminated list of optional named arguments * * Writes @in to @name using the saver recommended by * [func@Foreign.find_save]. * * Save options may be appended to @filename as `[name=value,...]` or given as * a `NULL`-terminated list of name-value pairs at the end of the arguments. * Options given in the function call override options given in the filename. * * ::: seealso * [ctor@Image.new_from_file]. * * Returns: 0 on success, or -1 on error. */ int vips_image_write_to_file(VipsImage *image, const char *name, ...) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; va_list ap; int result; /* Save with the new target API if we can. Fall back to the older * mechanism in case the saver we need has not been converted yet. * * We need to hide any errors from this first phase. */ vips__filename_split8(name, filename, option_string); vips_error_freeze(); operation_name = vips_foreign_find_save_target(filename); vips_error_thaw(); if (operation_name) { VipsTarget *target; if (!(target = vips_target_new_to_file(filename))) return -1; va_start(ap, name); result = vips_call_split_option_string(operation_name, option_string, ap, image, target); va_end(ap); VIPS_UNREF(target); } else if ((operation_name = vips_foreign_find_save(filename))) { va_start(ap, name); result = vips_call_split_option_string(operation_name, option_string, ap, image, filename); va_end(ap); } else return -1; return result; } /** * vips_image_write_to_buffer: * @in: image to write * @suffix: format to write * @buf: (array length=size) (element-type guint8) (transfer full): return buffer start here * @size: (type gsize): return buffer length here * @...: `NULL`-terminated list of optional named arguments * * Writes @in to a memory buffer in a format specified by @suffix. * * Save options may be appended to @suffix as `[name=value,...]` or given as * a `NULL`-terminated list of name-value pairs at the end of the arguments. * Options given in the function call override options given in the filename. * * Currently only TIFF, JPEG and PNG formats are supported. * * You can call the various save operations directly if you wish, see * [method@Image.jpegsave_buffer], for example. * * ::: seealso * [method@Image.write_to_memory], [ctor@Image.new_from_buffer]. * * Returns: 0 on success, -1 on error */ int vips_image_write_to_buffer(VipsImage *in, const char *suffix, void **buf, size_t *size, ...) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; VipsBlob *blob; va_list ap; int result; vips__filename_split8(suffix, filename, option_string); vips_error_freeze(); operation_name = vips_foreign_find_save_target(filename); vips_error_thaw(); if (operation_name) { VipsTarget *target; if (!(target = vips_target_new_to_memory())) return -1; va_start(ap, size); result = vips_call_split_option_string(operation_name, option_string, ap, in, target); va_end(ap); if (result) { VIPS_UNREF(target); return -1; } g_object_get(target, "blob", &blob, NULL); VIPS_UNREF(target); } else if ((operation_name = vips_foreign_find_save_buffer(filename))) { va_start(ap, size); result = vips_call_split_option_string(operation_name, option_string, ap, in, &blob); va_end(ap); if (result) return -1; } else return -1; *buf = NULL; if (size) *size = 0; if (blob) { if (buf) { *buf = VIPS_AREA(blob)->data; VIPS_AREA(blob)->free_fn = NULL; } if (size) *size = VIPS_AREA(blob)->length; vips_area_unref(VIPS_AREA(blob)); } return 0; } /** * vips_image_write_to_target: * @in: image to write * @suffix: format to write * @target: target to write to * @...: `NULL`-terminated list of optional named arguments * * Writes @in to @output in format @suffix. * * Save options may be appended to @suffix as `[name=value,...]` or given as * a `NULL`-terminated list of name-value pairs at the end of the arguments. * Options given in the function call override options given in the filename. * * You can call the various save operations directly if you wish, see * [method@Image.jpegsave_target], for example. * * ::: seealso * [method@Image.write_to_file]. * * Returns: 0 on success, -1 on error */ int vips_image_write_to_target(VipsImage *in, const char *suffix, VipsTarget *target, ...) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; const char *operation_name; va_list ap; int result; vips__filename_split8(suffix, filename, option_string); if (!(operation_name = vips_foreign_find_save_target(filename))) return -1; va_start(ap, target); result = vips_call_split_option_string(operation_name, option_string, ap, in, target); va_end(ap); if (result) return -1; return 0; } /** * vips_image_write_to_memory: * @in: image to write * @size: return buffer length here * * Writes @in to memory as a simple, unformatted C-style array. * * The caller is responsible for freeing this memory with [func@GLib.free]. * * ::: seealso * [method@Image.write_to_buffer]. * * Returns: (array length=size) (element-type guint8) (transfer full): return buffer start here */ void * vips_image_write_to_memory(VipsImage *in, size_t *size_out) { void *buf; size_t size; VipsImage *x; size = VIPS_IMAGE_SIZEOF_IMAGE(in); if (!(buf = g_try_malloc(size))) { vips_error("vips_image_write_to_memory", _("out of memory -- size == %dMB"), (int) (size / (1024.0 * 1024.0))); g_warning("out of memory -- size == %dMB", (int) (size / (1024.0 * 1024.0))); return NULL; } x = vips_image_new_from_memory(buf, size, in->Xsize, in->Ysize, in->Bands, in->BandFmt); if (vips_image_write(in, x)) { g_object_unref(x); g_free(buf); return NULL; } g_object_unref(x); if (size_out) *size_out = size; return buf; } /** * vips_image_decode: * @in: image to decode * @out: (out): write to this image * * A convenience function to unpack to a format that we can compute with. * @out.coding is always [enum@Vips.Coding.NONE]. * * This unpacks LABQ to plain LAB. Use [method@Image.LabQ2LabS] for a bit * more speed if you need it. * * ::: seealso * [method@Image.encode], [method@Image.LabQ2Lab], [method@Image.rad2float]. * * Returns: 0 on success, or -1 on error. */ int vips_image_decode(VipsImage *in, VipsImage **out) { /* Keep in sync with vips__vector_to_ink(). */ if (in->Coding == VIPS_CODING_LABQ) { if (vips_LabQ2Lab(in, out, NULL)) return -1; } else if (in->Coding == VIPS_CODING_RAD) { if (vips_rad2float(in, out, NULL)) return -1; } else { if (vips_copy(in, out, NULL)) return -1; } return 0; } /** * vips_image_decode_predict: * @in: image to decode * @bands: (out): predict bands here * @format: (out): predict format here * * We often need to know what an image will decode to without actually * decoding it, for example, in arg checking. * * ::: seealso * [method@Image.decode]. */ int vips_image_decode_predict(VipsImage *in, int *out_bands, VipsBandFormat *out_format) { VipsBandFormat format; int bands; if (in->Coding == VIPS_CODING_LABQ) { bands = 3; format = VIPS_FORMAT_FLOAT; } else if (in->Coding == VIPS_CODING_RAD) { bands = 3; format = VIPS_FORMAT_FLOAT; } else { bands = in->Bands; format = in->BandFmt; } if (out_bands) *out_bands = bands; if (out_format) *out_format = format; return 0; } /** * vips_image_encode: * @in: image to encode * @out: (out): write to this image * @coding: coding to apply * * A convenience function to pack to a coding. The inverse of * [method@Image.decode]. * * ::: seealso * [method@Image.decode]. * * Returns: 0 on success, or -1 on error. */ int vips_image_encode(VipsImage *in, VipsImage **out, VipsCoding coding) { if (coding == VIPS_CODING_LABQ) { if (vips_Lab2LabQ(in, out, NULL)) return -1; } else if (coding == VIPS_CODING_RAD) { if (vips_float2rad(in, out, NULL)) return -1; } else { if (vips_copy(in, out, NULL)) return -1; } return 0; } /** * vips_image_isMSBfirst: * @image: image to test * * Return `TRUE` if @image is in most-significant- * byte first form. This is the byte order used on the SPARC * architecture and others. */ gboolean vips_image_isMSBfirst(VipsImage *image) { if (image->magic == VIPS_MAGIC_SPARC) return 1; else return 0; } /** * vips_image_isfile: * @image: image to test * * Return `TRUE` if @image represents a file on disc in some way. */ gboolean vips_image_isfile(VipsImage *image) { switch (image->dtype) { case VIPS_IMAGE_MMAPIN: case VIPS_IMAGE_MMAPINRW: case VIPS_IMAGE_OPENOUT: case VIPS_IMAGE_OPENIN: return 1; case VIPS_IMAGE_PARTIAL: case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: case VIPS_IMAGE_NONE: return 0; default: g_assert(FALSE); return 0; } } /** * vips_image_ispartial: * @image: image to test * * Return `TRUE` if @im represents a partial image (a delayed calculation). */ gboolean vips_image_ispartial(VipsImage *image) { if (image->dtype == VIPS_IMAGE_PARTIAL) return 1; else return 0; } /** * vips_image_hasalpha: * @image: image to check * * Look at an image's interpretation and see if it has extra alpha bands. For * example, a 4-band [enum@Vips.Interpretation.sRGB] would, but a six-band * [enum@Vips.Interpretation.MULTIBAND] would not. * * Return `TRUE` if @image has an alpha channel. */ gboolean vips_image_hasalpha(VipsImage *image) { int bands = vips_interpretation_bands(image->Type); return bands > 0 && image->Bands > bands; } /** * vips_image_write_prepare: * @image: image to prepare * * Call this after setting header fields (width, height, and so on) to * allocate resources ready for writing. * * Normally this function is called for you by [method@Image.generate] or * [method@Image.write_line]. You will need to call it yourself if you plan to * write directly to the ->data member of a memory image. * * Returns: 0 on success, or -1 on error. */ int vips_image_write_prepare(VipsImage *image) { if (image->dtype == VIPS_IMAGE_PARTIAL) { VIPS_DEBUG_MSG("vips_image_write_prepare: old-style output for %s\n", image->filename); image->dtype = VIPS_IMAGE_SETBUF; } if (!vips_object_sanity(VIPS_OBJECT(image))) return -1; if (image->Xsize <= 0 || image->Ysize <= 0 || image->Bands <= 0) { vips_error("VipsImage", "%s", _("bad dimensions")); return -1; } /* We don't use this, but make sure it's set in case any old programs * are expecting it. */ image->Bbits = vips_format_sizeof(image->BandFmt) << 3; switch (image->dtype) { case VIPS_IMAGE_MMAPINRW: case VIPS_IMAGE_SETBUF_FOREIGN: break; case VIPS_IMAGE_SETBUF: if (!image->data && !(image->data = vips_tracked_malloc( VIPS_IMAGE_SIZEOF_IMAGE(image)))) return -1; break; case VIPS_IMAGE_OPENOUT: if (vips_image_open_output(image)) return -1; break; default: vips_error("VipsImage", "%s", _("bad image descriptor")); return -1; } return 0; } /** * vips_image_write_line: * @image: image to write to * @ypos: vertical position of scan-line to write * @linebuffer: scanline of pixels * * Write a line of pixels to an image. This function must be called repeatedly * with @ypos increasing from 0 to [property@Image:height]. * @linebuffer must be [func@IMAGE_SIZEOF_LINE] bytes long. * * ::: seealso * [method@Image.generate]. * * Returns: 0 on success, or -1 on error. */ int vips_image_write_line(VipsImage *image, int ypos, VipsPel *linebuffer) { guint64 linesize = VIPS_IMAGE_SIZEOF_LINE(image); /* Is this the start of eval? */ if (ypos == 0) { if (vips__image_wio_output(image)) return -1; /* Always clear kill before we start looping. See the * call to vips_image_iskilled() below. */ vips_image_set_kill(image, FALSE); vips_image_write_prepare(image); vips_image_preeval(image); } /* Possible cases for output: FILE or SETBUF. */ switch (image->dtype) { case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: memcpy(VIPS_IMAGE_ADDR(image, 0, ypos), linebuffer, linesize); break; case VIPS_IMAGE_OPENOUT: /* Don't use ypos for this. */ if (vips__write(image->fd, linebuffer, linesize)) return -1; break; default: vips_error("VipsImage", _("unable to output to a %s image"), vips_enum_string(VIPS_TYPE_IMAGE_TYPE, image->dtype)); return -1; } /* Trigger evaluation callbacks for this image. */ vips_image_eval(image, (guint64) ypos * image->Xsize); if (vips_image_iskilled(image)) return -1; /* Is this the end of eval? */ if (ypos == image->Ysize - 1) { vips_image_posteval(image); if (vips_image_written(image)) return -1; } return 0; } /* Rewind an output file. VIPS images only. */ static int vips_image_rewind_output(VipsImage *image) { int fd; g_assert(image->dtype == VIPS_IMAGE_OPENOUT); #ifdef DEBUG_IO printf("vips_image_rewind_output: %s\n", image->filename); #endif /*DEBUG_IO*/ /* We want to keep the fd across rewind. * * On Windows, we open temp files with _O_TEMPORARY. We mustn't close * the file since this will delete it. * * We could open the file again to keep a reference to it alive, but * this is also problematic on Windows. */ fd = image->fd; image->fd = -1; /* Free any resources the image holds and reset to a base * state. */ vips_object_rewind(VIPS_OBJECT(image)); /* And reopen ... recurse to get a mmaped image. * * We use "v" mode to get it opened as a vips image, bypassing the * file type checks. They will fail on Windows because you can't open * fds more than once. */ image->fd = fd; g_object_set(image, "mode", "v", NULL); if (vips_object_build(VIPS_OBJECT(image))) { vips_error("VipsImage", _("auto-rewind for %s failed"), image->filename); return -1; } /* Now we've finished writing and reopened as read, we can * delete-on-close. * * On *nix-like systems, this will unlink the file from the * filesystem and when we exit, for whatever reason, the file * we be reclaimed. * * On Windows this will fail because the file is open and you can't * delete open files. However, on Windows we set _O_TEMPORARY, so the * file will be deleted when the fd is finally closed. */ vips_image_delete(image); return 0; } /** * vips_image_copy_memory: * @image: image to copy to a memory buffer * * This function allocates memory, renders @image into it, builds a new * image around the memory area, and returns that. * * If the image is already a simple area of memory, it just refs @image and * returns it. * * Call this before using the draw operations to make sure you have a * memory image that can be modified. * * [method@Image.copy] adds a null "copy" node to a pipeline. Use that * instead if you want to change metadata and not pixels. * * This operation is thread-safe, unlike [method@Image.wio_input]. * * If you are sure that @image is not shared with another thread (perhaps you * have made it yourself), use [method@Image.wio_input] instead. * * ::: seealso * [method@Image.wio_input]. * * Returns: (transfer full): the new [class@Image], or `NULL` on error. */ VipsImage * vips_image_copy_memory(VipsImage *image) { VipsImage *new; switch (image->dtype) { case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: case VIPS_IMAGE_MMAPIN: case VIPS_IMAGE_MMAPINRW: /* Can read from all these, in principle anyway. */ new = image; g_object_ref(new); break; case VIPS_IMAGE_OPENOUT: case VIPS_IMAGE_OPENIN: case VIPS_IMAGE_PARTIAL: new = vips_image_new_memory(); if (vips_image_write(image, new)) { g_object_unref(new); return NULL; } break; default: vips_error("vips_image_copy_memory", "%s", _("image not readable")); return NULL; } return new; } /** * vips_image_wio_input: * @image: image to transform * * Check that an image is readable via the [func@IMAGE_ADDR] macro, that is, * that the entire image is in memory and all pixels can be read with * [func@IMAGE_ADDR]. If it * isn't, try to transform it so that [func@IMAGE_ADDR] can work. * * Since this function modifies @image, it is not thread-safe. Only call it on * images which you are sure have not been shared with another thread. If the * image might have been shared, use the less efficient * [method@Image.copy_memory] instead. * * ::: seealso * [method@Image.copy_memory], [method@Image.pio_input], * [method@Image.inplace], [func@IMAGE_ADDR]. * * Returns: 0 on success, or -1 on error. */ int vips_image_wio_input(VipsImage *image) { VipsImage *t1; if (!vips_object_sanity(VIPS_OBJECT(image))) return -1; #ifdef DEBUG_IO printf("vips_image_wio_input: wio input for %s\n", image->filename); #endif /*DEBUG_IO*/ switch (image->dtype) { case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: /* Should have been written to. */ if (!image->data) { vips_error("vips_image_wio_input", "%s", _("no image data")); return -1; } break; case VIPS_IMAGE_MMAPIN: case VIPS_IMAGE_MMAPINRW: /* Can read from all these, in principle anyway. */ break; case VIPS_IMAGE_PARTIAL: #ifdef DEBUG_IO printf("vips_image_wio_input: converting partial image to WIO\n"); #endif /*DEBUG_IO*/ /* Change to VIPS_IMAGE_SETBUF. First, make a memory * buffer and copy into that. */ t1 = vips_image_new_memory(); if (vips_image_write(image, t1)) { g_object_unref(t1); return -1; } /* Copy new stuff in. We can't unref and free stuff, as this * would kill of lots of regions and cause dangling pointers * elsewhere. */ image->dtype = VIPS_IMAGE_SETBUF; image->data = t1->data; t1->data = NULL; /* Close temp image. */ g_object_unref(t1); /* We need to zap any start/gen/stop callbacks. If we don't, * calling vips_region_prepare_to() later to read from this * image will fail, since it will think it needs to create the * image, not read from it. */ image->start_fn = NULL; image->generate_fn = NULL; image->stop_fn = NULL; image->client1 = NULL; image->client2 = NULL; /* ... and that may confuse any regions which are trying to * generate from this image. */ if (image->regions) g_warning("rewinding image with active regions"); break; case VIPS_IMAGE_OPENIN: #ifdef DEBUG_IO printf("vips_image_wio_input: " "converting openin image for wio input\n"); #endif /*DEBUG_IO*/ /* just mmap() the whole thing. */ if (vips_mapfile(image)) return -1; image->data = (VipsPel *) image->baseaddr + image->sizeof_header; image->dtype = VIPS_IMAGE_MMAPIN; break; case VIPS_IMAGE_OPENOUT: /* Close file down and reopen as input. I guess this will only * work for vips files? */ if (vips_image_rewind_output(image) || vips_image_wio_input(image)) return -1; break; default: vips_error("vips_image_wio_input", "%s", _("image not readable")); return -1; } return 0; } int vips__image_wio_output(VipsImage *image) { #ifdef DEBUG_IO printf("vips__image_wio_output: WIO output for %s\n", image->filename); #endif /*DEBUG_IO*/ switch (image->dtype) { case VIPS_IMAGE_PARTIAL: /* Make sure nothing is attached. */ if (image->generate_fn) { vips_error("vips__image_wio_output", "%s", _("image already written")); return -1; } /* Cannot do old-style write to PARTIAL. Turn to SETBUF. */ image->dtype = VIPS_IMAGE_SETBUF; break; case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_OPENOUT: case VIPS_IMAGE_SETBUF_FOREIGN: /* Can write to this ok. * * We used to check that ->data was null and warn about * writing twice, but we no longer insist that this is called * before vips_image_write_prepare(), so we can't do that any * more. */ break; default: vips_error("vips__image_wio_output", "%s", _("image not writeable")); return -1; } return 0; } /** * vips_image_inplace: * @image: image to make read-write * * Gets @image ready for an in-place operation, such as * [method@Image.draw_circle]. After calling this function you can both read * and write the image with [func@IMAGE_ADDR]. * * This method is called for you by the base class of the draw operations, * there's no need to call it yourself. * * Since this function modifies @image, it is not thread-safe. Only call it on * images which you are sure have not been shared with another thread. * All in-place operations are inherently not thread-safe, so you need to take * great care in any case. * * ::: seealso * [method@Image.draw_circle], [method@Image.wio_input]. * * Returns: 0 on success, or -1 on error. */ int vips_image_inplace(VipsImage *image) { /* Do an vips_image_wio_input(). This will rewind, generate, etc. */ if (vips_image_wio_input(image)) return -1; /* Look at the type. */ switch (image->dtype) { case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: case VIPS_IMAGE_MMAPINRW: /* No action necessary. */ break; case VIPS_IMAGE_MMAPIN: /* Try to remap read-write. */ if (vips_remapfilerw(image)) return -1; break; default: vips_error("vips_image_inplace", "%s", _("bad file type")); return -1; } /* This image is about to be changed (probably). Make sure it's not * in cache. */ vips_image_invalidate_all(image); return 0; } /** * vips_image_pio_input: * @image: image to check * * Check that an image is readable with [method@Region.prepare] and friends. * If it isn't, try to transform the image so that [method@Region.prepare] can * work. * * ::: seealso * [method@Image.pio_output], [method@Region.prepare]. * * Returns: 0 on success, or -1 on error. */ int vips_image_pio_input(VipsImage *image) { if (!vips_object_sanity(VIPS_OBJECT(image))) return -1; #ifdef DEBUG_IO printf("vips_image_pio_input: enabling partial input for %s\n", image->filename); #endif /*DEBUG_IO*/ switch (image->dtype) { case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: /* Should have been written to. */ if (!image->data) { vips_error("vips_image_pio_input", "%s", _("no image data")); return -1; } /* Should be no generate functions now. */ image->start_fn = NULL; image->generate_fn = NULL; image->stop_fn = NULL; break; case VIPS_IMAGE_PARTIAL: /* We can sometimes want to copy images with no generate func, * eg. if we are going to be manipulating metadata, so we * can't check for gen funcs. See dzsave direct mode. */ break; case VIPS_IMAGE_MMAPIN: case VIPS_IMAGE_MMAPINRW: case VIPS_IMAGE_OPENIN: break; case VIPS_IMAGE_OPENOUT: /* Free any resources the image holds and reset to a base * state. */ if (vips_image_rewind_output(image)) return -1; break; default: vips_error("vips_image_pio_input", "%s", _("image not readable")); return -1; } return 0; } /** * vips_image_pio_output: * @image: image to check * * Check that an image is writeable with [method@Image.generate]. If it isn't, * try to transform the image so that [method@Image.generate] can work. * * ::: seealso * [method@Image.pio_input]. * * Returns: 0 on success, or -1 on error. */ int vips_image_pio_output(VipsImage *image) { #ifdef DEBUG_IO printf("vips_image_pio_output: enabling partial output for %s\n", image->filename); #endif /*DEBUG_IO*/ switch (image->dtype) { case VIPS_IMAGE_SETBUF: if (image->data) { vips_error("vips_image_pio_output", "%s", _("image already written")); return -1; } break; case VIPS_IMAGE_PARTIAL: if (image->generate_fn) { vips_error("vips_image_pio_output", "%s", _("image already written")); return -1; } break; case VIPS_IMAGE_OPENOUT: case VIPS_IMAGE_SETBUF_FOREIGN: break; default: vips_error("vips_image_pio_output", "%s", _("image not writeable")); return -1; } return 0; } /** * vips_band_format_isint: * @format: format to test * * Return `TRUE` if @format is one of the integer types. */ gboolean vips_band_format_isint(VipsBandFormat format) { switch (format) { case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_CHAR: case VIPS_FORMAT_USHORT: case VIPS_FORMAT_SHORT: case VIPS_FORMAT_UINT: case VIPS_FORMAT_INT: return TRUE; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: return FALSE; default: g_assert_not_reached(); return FALSE; } } /** * vips_band_format_isuint: * @format: format to test * * Return `TRUE` if @format is one of the unsigned integer types. */ gboolean vips_band_format_isuint(VipsBandFormat format) { switch (format) { case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_USHORT: case VIPS_FORMAT_UINT: return TRUE; case VIPS_FORMAT_INT: case VIPS_FORMAT_SHORT: case VIPS_FORMAT_CHAR: case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: return FALSE; default: g_assert_not_reached(); return FALSE; } } /** * vips_band_format_is8bit: * @format: format to test * * Return `TRUE` if @format is uchar or schar. */ gboolean vips_band_format_is8bit(VipsBandFormat format) { switch (format) { case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_CHAR: return TRUE; case VIPS_FORMAT_USHORT: case VIPS_FORMAT_SHORT: case VIPS_FORMAT_UINT: case VIPS_FORMAT_INT: case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: return FALSE; default: g_assert_not_reached(); return FALSE; } } /** * vips_band_format_isfloat: * @format: format to test * * Return `TRUE` if @format is one of the float types. */ gboolean vips_band_format_isfloat(VipsBandFormat format) { switch (format) { case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_DOUBLE: return TRUE; case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_CHAR: case VIPS_FORMAT_USHORT: case VIPS_FORMAT_SHORT: case VIPS_FORMAT_UINT: case VIPS_FORMAT_INT: case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: return FALSE; default: g_assert_not_reached(); return FALSE; } } /** * vips_band_format_iscomplex: * @format: format to test * * Return `TRUE` if @fmt is one of the complex types. */ gboolean vips_band_format_iscomplex(VipsBandFormat format) { switch (format) { case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DPCOMPLEX: return TRUE; case VIPS_FORMAT_UCHAR: case VIPS_FORMAT_CHAR: case VIPS_FORMAT_USHORT: case VIPS_FORMAT_SHORT: case VIPS_FORMAT_UINT: case VIPS_FORMAT_INT: case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_DOUBLE: return FALSE; default: g_assert_not_reached(); return FALSE; } } /** * vips_image_free_buffer: * @image: the image that contains the buffer * @buffer: the original buffer that was stolen * * Free the externally allocated buffer found in the input image. This function * is intended to be used with g_signal_connect. */ void vips_image_free_buffer(VipsImage *image, void *buffer) { free(buffer); } /* Handy for debugging: view an image in nip2. */ int vips__view_image(VipsImage *image) { VipsArrayImage *array; int result; array = vips_array_image_new(&image, 1); result = vips_system("nip2 %s", "in", array, "in-format", "%s.v", NULL); vips_area_unref(VIPS_AREA(array)); return result; } libvips-8.18.2/libvips/iofuncs/init.c000066400000000000000000001037251516303661500175250ustar00rootroot00000000000000/* Start up the world of vips. * * 7/1/04 JC * - 1st version * 7/6/05 * - g_type_init() too, so we can use gobject * 2/9/06 * - also set g_prg_name() and load plugins * 8/12/06 * - add liboil support * 5/2/07 * - stop a loop if we're called recursively during VIPS startup ... it * can happen if (for example) vips_guess_prefix() fails and tries to * i18n an error message (thanks Christian) * 8/6/07 * - just warn if plugins fail to load correctly: too annoying to have * VIPS refuse to start because of a dodgy plugin * 7/11/07 * - progress feedback option * 5/8/08 * - load plugins from libdir/vips-x.x * 5/10/09 * - gtkdoc comments * 14/3/10 * - init image and region before we start, we need all types to be fully * constructed before we go parallel * 18/9/16 * - call _setmaxstdio() on win32 * 4/8/17 * - hide warnings is VIPS_WARNING is set * 20/4/19 * - set the min stack, if we can * 17/9/21 * - don't use atexit for cleanup, it's too unreliable ... users should * call vips_shutdown explicitly if they want a clean exit, though a * dirty exit is fine */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* pthread_setattr_default_np() is a non-portable GNU extension. */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #ifdef HAVE_PTHREAD_DEFAULT_NP #include #endif /*HAVE_PTHREAD_DEFAULT_NP*/ #include #include #ifdef HAVE_SYS_PARAM_H #include #endif /*HAVE_SYS_PARAM_H*/ #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #ifdef HAVE_DIRECT_H #include #endif /*HAVE_DIRECT_H*/ #include #include /* For vips__win32_terminate(). */ #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ #define VIPS_DISABLE_DEPRECATION_WARNINGS #include #include #include /* abort() on the first warning or error. */ int vips__fatal = 0; /* Use in various small places where we need a mutex and it's not worth * making a private one. */ GMutex vips__global_lock; /* A debugging timer, zero at library init. */ GTimer *vips__global_timer = NULL; /* Keep a copy of the argv0 here. */ static char *vips__argv0 = NULL; /* Keep a copy of the last component of argv0 here. */ static char *vips__prgname = NULL; /* Leak check on exit. */ int vips__leak = 0; #ifdef DEBUG_LEAK /* Count pixels processed per image here. */ GQuark vips__image_pixels_quark = 0; #endif /*DEBUG_LEAK*/ /* The maximum coordinate (ie. dimension) value we allow. This can be * overridden with the `--vips-max-coord` CLI arg, or the `VIPS_MAX_COORD` env * var. */ static char *vips__max_coord_arg = NULL; /** * vips_max_coord_get: * * Return the maximum coordinate value. This can be the default, a value set * set by the `--vips-max-coord` CLI arg, or a value set in the `VIPS_MAX_COORD` * environment variable. * * These strings can include unit specifiers, eg. "10m" for 10 million pixels. * Values above INT_MAX are not supported. * * Returns: The maximum value a coordinate, or image dimension, can have. */ int vips_max_coord_get(void) { // CLI overrides env var const char *as_str = vips__max_coord_arg ? vips__max_coord_arg : g_getenv("VIPS_MAX_COORD"); if (as_str) { guint64 size = vips__parse_size(as_str); return VIPS_CLIP(100, size, INT_MAX); } else return VIPS_DEFAULT_MAX_COORD; } /** * vips_get_argv0: * * ::: seealso * [func@INIT]. * * Returns: (transfer none): a pointer to an internal copy of the * argv0 string passed to [func@INIT]. Do not free this value */ const char * vips_get_argv0(void) { return vips__argv0; } /** * vips_get_prgname: * * Return the program name. * * ::: seealso * [func@INIT]. * * Returns: (transfer none): a pointer to an internal copy of the program * name. Do not free this value */ const char * vips_get_prgname(void) { const char *prgname; if ((prgname = g_get_prgname())) return prgname; else return vips__prgname; } /** * VIPS_INIT: * @ARGV0: name of application * * [func@INIT] starts up the world of VIPS. You should call this on * program startup before using any other VIPS operations. If you do not call * [func@INIT], VIPS will call it for you when you use your first VIPS * operation, but it may not be able to get hold of @ARGV0 and VIPS may * therefore be unable to find its data files. It is much better to call * this macro yourself. * * @ARGV0 is used to help discover message catalogues if libvips has been * relocated. If you don't need a relocatable package, you can just pass `""` * and it'll be fine. * * Additionally, [func@INIT] can be run from any thread, but it must not be * called from more than one thread at the same time. This is much easier to * guarantee if you call it yourself. * * [func@INIT] is a macro, since it tries to check ABI compatibility * between the caller and the library. You can also call [func@init], the * non-macro version, if macros are not available to you. * * You may call [func@INIT] many times and [func@shutdown] many times, but you * must not call [func@INIT] after [func@shutdown]. In other words, you cannot * stop and restart vips. * * Use the environment variable `VIPS_MIN_STACK_SIZE` to set the minimum stack * size. For example, `2m` for a minimum of two megabytes of stack. This can * be important for systems like musl where the default stack is very small. * * [func@INIT] does approximately the following: * * - checks that the libvips your program is expecting is * binary-compatible with the vips library you're running against * * - sets a minimum stack size, see above * * - initialises any libraries that VIPS is using, including GObject * and the threading system, if necessary * * - guesses where the VIPS data files are and sets up * internationalisation -- see [func@guess_prefix] * * - creates the main vips types, including [class@Image] and friends * * - loads any plugins from $libdir/vips-x.y/, where x and y are the * major and minor version numbers for this VIPS. * * Example: * * ```c * int main(int argc, char **argv) * { * if (VIPS_INIT(argv[0])) * vips_error_exit("unable to start VIPS"); * * vips_shutdown(); * * return 0; * } * ``` * * ::: seealso * [func@shutdown], [func@add_option_entries], [func@version], * [func@guess_prefix], [func@guess_libdir]. * * Returns: 0 on success, -1 otherwise */ #ifdef ENABLE_MODULES /* Load all plugins in a directory. */ static void vips_load_plugins(const char *fmt, ...) { va_list ap; char dir_name[VIPS_PATH_MAX]; GDir *dir; const char *name; /* Do nothing if modules aren't supported. */ if (!g_module_supported()) return; va_start(ap, fmt); (void) g_vsnprintf(dir_name, VIPS_PATH_MAX, fmt, ap); va_end(ap); g_info("searching \"%s\"", dir_name); /* Do nothing if directory is not present. */ if (!(dir = g_dir_open(dir_name, 0, NULL))) return; while ((name = g_dir_read_name(dir))) { char path[VIPS_PATH_MAX]; GModule *module; g_snprintf(path, VIPS_PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", dir_name, name); g_info("loading \"%s\"", path); module = g_module_open(path, G_MODULE_BIND_LAZY); if (module) /* Modules will almost certainly create new * types, so they can't be unloaded. */ g_module_make_resident(module); else g_warning("unable to load \"%s\" -- %s", path, g_module_error()); } g_dir_close(dir); } #endif /*ENABLE_MODULES*/ /* Install this log handler to hide warning messages. */ static void empty_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { } /* Attempt to set a minimum stacksize. This can be important on systems with a * very low default, like musl. */ static void set_stacksize(guint64 size) { #ifdef HAVE_PTHREAD_DEFAULT_NP pthread_attr_t attr; size_t cur_stack_size; /* Don't allow stacks less than 2mb. */ size = VIPS_MAX(size, 2 * 1024 * 1024); if (pthread_attr_init(&attr) || pthread_attr_getstacksize(&attr, &cur_stack_size)) { g_warning("set_stacksize: unable to get stack size"); pthread_attr_destroy(&attr); return; } if (cur_stack_size < size) { if (pthread_attr_setstacksize(&attr, size) || pthread_setattr_default_np(&attr)) g_warning("set_stacksize: unable to set stack size"); else g_info("set stack size to %" G_GUINT64_FORMAT "k", size / (guint64) 1024); } pthread_attr_destroy(&attr); #endif /*HAVE_PTHREAD_DEFAULT_NP*/ } /* Equivalent to setting the `G_MESSAGES_DEBUG=VIPS` environment variable. */ static void vips_verbose(void) { #if GLIB_CHECK_VERSION(2, 80, 0) const char *domains[] = { G_LOG_DOMAIN, NULL }; g_log_writer_default_set_debug_domains(domains); #else g_setenv("G_MESSAGES_DEBUG", G_LOG_DOMAIN, TRUE); #endif } static int vips_leak(void) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC(txt); int n_leaks; n_leaks = 0; n_leaks += vips__object_leak(); n_leaks += vips__type_leak(); n_leaks += vips_tracked_get_allocs(); n_leaks += vips_tracked_get_mem(); n_leaks += vips_tracked_get_files(); #if defined(HAVE_OPENSLIDE) && !defined(OPENSLIDE_MODULE) n_leaks += vips__openslideconnection_leak(); #endif /*defined(HAVE_OPENSLIDE) && !defined(OPENSLIDE_MODULE)*/ if (vips_tracked_get_allocs() || vips_tracked_get_mem() || vips_tracked_get_files()) { vips_buf_appendf(&buf, "memory: %d allocations, %zd bytes\n", vips_tracked_get_allocs(), vips_tracked_get_mem()); vips_buf_appendf(&buf, "files: %d open\n", vips_tracked_get_files()); } vips_buf_appendf(&buf, "memory: high-water mark "); vips_buf_append_size(&buf, vips_tracked_get_mem_highwater()); vips_buf_appends(&buf, "\n"); if (strlen(vips_error_buffer()) > 0) { vips_buf_appendf(&buf, "error buffer: %s", vips_error_buffer()); n_leaks += strlen(vips_error_buffer()); } fprintf(stderr, "%s", vips_buf_all(&buf)); n_leaks += vips__print_renders(); #ifdef DEBUG vips_buffer_dump_all(); #endif /*DEBUG*/ return n_leaks; } /** * vips_init: * @argv0: name of application * * This function starts up libvips, see [func@INIT]. * * This function is for bindings which need to start up vips. C programs * should use the [func@INIT] macro, which does some extra checks. * * ::: seealso * [func@INIT]. * * Returns: 0 on success, -1 otherwise */ int vips_init(const char *argv0) { extern GType vips_system_get_type(void); extern GType write_thread_state_get_type(void); extern GType sink_memory_thread_state_get_type(void); extern GType render_thread_state_get_type(void); extern GType vips_source_get_type(void); extern GType vips_source_custom_get_type(void); extern GType vips_target_get_type(void); extern GType vips_target_custom_get_type(void); extern GType vips_g_input_stream_get_type(void); static gboolean started = FALSE; static gboolean done = FALSE; const char *vips_min_stack_size; gint64 min_stack_size; const char *prefix; const char *libdir; #ifdef ENABLE_NLS char *locale; #endif /* ENABLE_NLS */ /* Two stage done handling: 'done' means we've completed, 'started' * means we're currently initialising. Use this to prevent recursive * invocation. */ if (done) /* Called more than once, we succeeded, just return OK. */ return 0; if (started) /* Recursive invocation, something has broken horribly. * Hopefully the first init will handle it. */ return 0; started = TRUE; /* Try to set a minimum stacksize, default 2mb. We need to do this * before any threads start. */ min_stack_size = 2 * 1024 * 1024; if ((vips_min_stack_size = g_getenv("VIPS_MIN_STACK_SIZE"))) min_stack_size = vips__parse_size(vips_min_stack_size); (void) set_stacksize(min_stack_size); if (g_getenv("VIPS_INFO") #ifdef ENABLE_DEPRECATED || g_getenv("IM_INFO") #endif ) vips_verbose(); if (g_getenv("VIPS_PROFILE")) vips_profile_set(TRUE); if (g_getenv("VIPS_LEAK")) vips_leak_set(TRUE); if (g_getenv("VIPS_TRACE")) vips_cache_set_trace(TRUE); const char *pipe_read_limit; if ((pipe_read_limit = g_getenv("VIPS_PIPE_READ_LIMIT"))) vips_pipe_read_limit_set(vips__parse_size(pipe_read_limit)); #ifdef G_OS_WIN32 /* Windows has a limit of 512 files open at once for the fopen() family * of functions, and 2048 for the _open() family. This raises the limit * of fopen() to the same level as _open(). * * It will not go any higher than this, unfortunately. */ (void) _setmaxstdio(2048); #endif /*G_OS_WIN32*/ vips__thread_init(); vips__threadpool_init(); vips__buffer_init(); if (!vips__global_timer) vips__global_timer = g_timer_new(); VIPS_SETSTR(vips__argv0, argv0); vips__prgname = g_path_get_basename(argv0); vips__thread_profile_attach("main"); /* We can't do VIPS_GATE_START() until command-line processing * happens, since vips__thread_profile may not be set yet. Call * directly. */ vips__thread_gate_start("init: main"); vips__thread_gate_start("init: startup"); /* Try to discover our prefix. */ if ((prefix = g_getenv("VIPSHOME"))) g_info("VIPSHOME = %s", prefix); if (!(prefix = vips_guess_prefix(argv0, "VIPSHOME")) || !(libdir = vips_guess_libdir(argv0, "VIPSHOME"))) return -1; g_info("VIPS_PREFIX = %s", VIPS_PREFIX); g_info("VIPS_LIBDIR = %s", VIPS_LIBDIR); g_info("prefix = %s", prefix); g_info("libdir = %s", libdir); /* Get i18n .mo files from $VIPSHOME/share/locale/. */ #ifdef ENABLE_NLS locale = g_build_filename(prefix, "share", "locale", NULL); bindtextdomain(GETTEXT_PACKAGE, locale); g_free(locale); #ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); #endif /* HAVE_BIND_TEXTDOMAIN_CODESET */ #endif /* ENABLE_NLS */ /* Register base vips types. */ (void) vips_image_get_type(); (void) vips_region_get_type(); (void) write_thread_state_get_type(); (void) sink_memory_thread_state_get_type(); (void) render_thread_state_get_type(); (void) vips_source_get_type(); (void) vips_source_custom_get_type(); (void) vips_target_get_type(); (void) vips_target_custom_get_type(); vips__meta_init_types(); vips__interpolate_init(); #ifdef ENABLE_DEPRECATED im__format_init(); #endif /* Start up operator cache. */ vips__cache_init(); /* Recomp reordering system. */ vips__reorder_init(); /* Start up packages. */ vips_system_get_type(); vips_arithmetic_operation_init(); vips_conversion_operation_init(); vips_create_operation_init(); vips_foreign_operation_init(); vips_resample_operation_init(); vips_colour_operation_init(); vips_histogram_operation_init(); vips_convolution_operation_init(); vips_freqfilt_operation_init(); vips_morphology_operation_init(); vips_draw_operation_init(); vips_mosaicing_operation_init(); vips_g_input_stream_get_type(); #ifdef ENABLE_MODULES /* Load any vips8 modules from the vips libdir. Keep going, even if * some modules fail to load. * * Only do this if we have been built as a set of loadable * modules, or we might try loading an operation into a library that * already has that operation built in. */ vips_load_plugins("%s/vips-modules-%d.%d", libdir, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION); #ifdef ENABLE_DEPRECATED /* We had vips8 plugins for a while. */ vips_load_plugins("%s/vips-plugins-%d.%d", libdir, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION); /* Load up any vips7 plugins. We don't error on * failure, it's too annoying to have VIPS refuse to start because of * a broken plugin. */ if (im_load_plugins("%s/vips-%d.%d", libdir, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION)) { g_warning("%s", vips_error_buffer()); vips_error_clear(); } /* Also load from libdir :-( kept for back compat convenience. */ if (im_load_plugins("%s", libdir)) { g_warning("%s", vips_error_buffer()); vips_error_clear(); } #endif /*ENABLE_DEPRECATED*/ #endif /*ENABLE_MODULES*/ /* Detect SIMD features. */ vips__vector_init(); #ifdef DEBUG_LEAK vips__image_pixels_quark = g_quark_from_static_string("vips-image-pixels"); #endif /*DEBUG_LEAK*/ /* If VIPS_WARNING is defined, suppress all warning messages from vips. * * Libraries should not call g_log_set_handler(), it is * supposed to be for the application layer, but this can be awkward to * set up if you are using libvips from something like Ruby. Allow this * env var hack as a workaround. */ if (g_getenv("VIPS_WARNING") #ifdef ENABLE_DEPRECATED || g_getenv("IM_WARNING") #endif ) g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, empty_log_handler, NULL); /* Block any untrusted operations. This must come after plugin load. */ if (g_getenv("VIPS_BLOCK_UNTRUSTED")) vips_block_untrusted_set(TRUE); done = TRUE; vips__thread_gate_stop("init: startup"); return 0; } /* Call this before vips stuff that uses stuff we need to have inited. */ void vips_check_init(void) { /* Pass in a nonsense name for argv0 ... this init path is only here * for old programs which are missing an vips_init() call. We need * i18n set up before we can translate. */ if (vips_init("vips")) vips_error_clear(); } /** * vips_thread_shutdown: * * Free any thread-private data and flush any profiling information. * * This function needs to be called when a thread that has been using vips * exits. It is called for you by [func@shutdown] and for any threads created * within the thread pool. * * You will need to call it from threads created in * other ways or there will be memory leaks. If you do not call it, vips * will generate a warning message. * * It may be called many times, and you can continue using vips after * calling it. Calling it too often will reduce performance. */ void vips_thread_shutdown(void) { vips__thread_profile_detach(); vips__buffer_shutdown(); } /** * vips_shutdown: * * Call this to drop caches, close plugins, terminate background threads, and * finalize any internal library testing. * * [func@shutdown] is optional. If you don't call it, your platform will * clean up for you. The only negative consequences are that the leak checker * and the profiler will not work. * * You may call [func@INIT] many times and [func@shutdown] many times, but you * must not call [func@INIT] after [func@shutdown]. In other words, you cannot * stop and restart libvips. * * ::: seealso * [func@profile_set], [func@leak_set]. */ void vips_shutdown(void) { #ifdef DEBUG printf("vips_shutdown:\n"); #endif /*DEBUG*/ vips_cache_drop_all(); #ifdef ENABLE_DEPRECATED im_close_plugins(); #endif /* Mustn't run this more than once. Don't use the VIPS_GATE macro, * since we don't for gate start. */ { static gboolean done = FALSE; if (!done) vips__thread_gate_stop("init: main"); } vips__render_shutdown(); vips_thread_shutdown(); vips__thread_profile_stop(); vips__threadpool_shutdown(); VIPS_FREE(vips__argv0); VIPS_FREE(vips__prgname); VIPS_FREEF(g_timer_destroy, vips__global_timer); /* In dev releases, always show leaks. But not more than once, it's * annoying. */ #ifndef DEBUG_LEAK if (vips__leak) #endif /*DEBUG_LEAK*/ { static gboolean done = FALSE; if (!done) { done = TRUE; vips_leak(); } } } static gboolean vips_lib_info_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vips_verbose(); return TRUE; } static gboolean vips_set_fatal_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vips__fatal = 1; /* Set masks for debugging ... stop on any problem. */ g_log_set_always_fatal( G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); return TRUE; } static gboolean vips_lib_version_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { printf("libvips %s\n", VIPS_VERSION_STRING); vips_shutdown(); exit(0); } static gboolean vips_lib_config_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { printf("%s\n", VIPS_CONFIG); vips_shutdown(); exit(0); } static gboolean vips_cache_max_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vips_cache_set_max(vips__parse_size(value)); return TRUE; } static gboolean vips_cache_max_memory_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vips_cache_set_max_mem(vips__parse_size(value)); return TRUE; } static gboolean vips_cache_max_files_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vips_cache_set_max_files(vips__parse_size(value)); return TRUE; } static gboolean vips_pipe_read_limit_cb(const gchar *option_name, const gchar *value, gpointer data, GError **error) { vips_pipe_read_limit_set(vips__parse_size(value)); return TRUE; } static GOptionEntry option_entries[] = { { "vips-info", 0, G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &vips_lib_info_cb, N_("show informative messages"), NULL }, { "vips-fatal", 0, G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &vips_set_fatal_cb, N_("abort on first error or warning"), NULL }, { "vips-concurrency", 0, 0, G_OPTION_ARG_INT, &vips__concurrency, N_("evaluate with N concurrent threads"), "N" }, { "vips-max-coord", 0, 0, G_OPTION_ARG_STRING, &vips__max_coord_arg, N_("maximum coordinate"), NULL }, { "vips-tile-width", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &vips__tile_width, N_("set tile width to N (DEBUG)"), "N" }, { "vips-tile-height", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &vips__tile_height, N_("set tile height to N (DEBUG)"), "N" }, { "vips-thinstrip-height", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &vips__thinstrip_height, N_("set thinstrip height to N (DEBUG)"), "N" }, { "vips-fatstrip-height", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &vips__fatstrip_height, N_("set fatstrip height to N (DEBUG)"), "N" }, { "vips-progress", 0, 0, G_OPTION_ARG_NONE, &vips__progress, N_("show progress feedback"), NULL }, { "vips-leak", 0, 0, G_OPTION_ARG_NONE, &vips__leak, N_("leak-check on exit"), NULL }, { "vips-profile", 0, 0, G_OPTION_ARG_NONE, &vips__thread_profile, N_("profile and dump timing on exit"), NULL }, { "vips-disc-threshold", 0, 0, G_OPTION_ARG_STRING, &vips__disc_threshold, N_("images larger than N are decompressed to disc"), "N" }, { "vips-novector", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &vips__vector_enabled, N_("disable vectorised versions of operations"), NULL }, { "vips-cache-max", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &vips_cache_max_cb, N_("cache at most N operations"), "N" }, { "vips-cache-max-memory", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &vips_cache_max_memory_cb, N_("cache at most N bytes in memory"), "N" }, { "vips-cache-max-files", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &vips_cache_max_files_cb, N_("allow at most N open files"), "N" }, { "vips-cache-trace", 0, 0, G_OPTION_ARG_NONE, &vips__cache_trace, N_("trace operation cache"), NULL }, { "vips-cache-dump", 0, 0, G_OPTION_ARG_NONE, &vips__cache_dump, N_("dump operation cache on exit"), NULL }, { "vips-version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &vips_lib_version_cb, N_("print libvips version"), NULL }, { "vips-config", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &vips_lib_config_cb, N_("print libvips config"), NULL }, { "vips-pipe-read-limit", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &vips_pipe_read_limit_cb, N_("read at most this many bytes from a pipe"), NULL }, { NULL } }; /** * vips_add_option_entries: * @option_group: group to add to * * Add the standard vips [struct@GLib.OptionEntry] to a * [struct@GLib.OptionGroup]. * * ::: seealso * [ctor@GLib.OptionGroup.new]. */ void vips_add_option_entries(GOptionGroup *option_group) { g_option_group_add_entries(option_group, option_entries); } /* Find the prefix part of a dir ... name is the name of this prog from argv0. * * dir name guess prefix * * /home/john/vips-7.6.4/bin/vips-7.6 vips-7.6 /home/john/vips-7.6.4 * /usr/local/bin/ip ip /usr/local * * all other forms ... return NULL. */ static char * extract_prefix(const char *dir, const char *name) { char edir[VIPS_PATH_MAX]; static char vname[VIPS_PATH_MAX]; int i; g_info("trying for dir = \"%s\", name = \"%s\"", dir, name); /* Is dir relative? Prefix with cwd. */ if (!g_path_is_absolute(dir)) { char *cwd; cwd = g_get_current_dir(); g_snprintf(edir, VIPS_PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", cwd, dir); g_free(cwd); } else { g_strlcpy(edir, dir, VIPS_PATH_MAX); } /* Chop off the trailing prog name, plus the trailing * G_DIR_SEPARATOR_S. */ if (!g_str_has_suffix(edir, name)) return NULL; g_strlcpy(vname, edir, VIPS_PATH_MAX); vname[strlen(edir) - strlen(name) - 1] = '\0'; /* Remove any "/./", any trailing "/.", any trailing "/". */ for (i = 0; i < (int) strlen(vname); i++) if (vips_isprefix(G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S, vname + i)) memmove(vname + i, vname + i + 2, strlen(vname + i + 2) + 1); if (g_str_has_suffix(vname, G_DIR_SEPARATOR_S ".")) vname[strlen(vname) - 2] = '\0'; if (g_str_has_suffix(vname, G_DIR_SEPARATOR_S)) vname[strlen(vname) - 1] = '\0'; g_info("canonicalised path = \"%s\"", vname); /* Ought to be a "/bin" at the end now. */ if (!g_str_has_suffix(vname, G_DIR_SEPARATOR_S "bin")) return NULL; vname[strlen(vname) - strlen(G_DIR_SEPARATOR_S "bin")] = '\0'; g_info("found \"%s\"", vname); return vname; } /* Search a path for a file ... we overwrite the PATH string passed in. */ static char * scan_path(char *path, const char *name) { char *p, *q; char *prefix; for (p = path; (q = vips_break_token(p, G_SEARCHPATH_SEPARATOR_S)); p = q) { char str[VIPS_PATH_MAX]; /* Form complete path. */ g_snprintf(str, VIPS_PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", p, name); g_info("looking in \"%s\" for \"%s\"", p, name); if (vips_existsf("%s", str) && (prefix = extract_prefix(str, name))) { return prefix; } } return NULL; } /* Look for a file along PATH. If we find it, look for an enclosing prefix. */ static char * find_file(const char *name) { const char *path = g_getenv("PATH"); char *prefix; char full_path[VIPS_PATH_MAX]; if (!path) return NULL; g_info("g_getenv(\"PATH\") == \"%s\"", path); #ifdef G_OS_WIN32 { char *dir; /* Windows always searches '.' first, so prepend cwd to path. */ dir = g_get_current_dir(); g_snprintf(full_path, VIPS_PATH_MAX, "%s" G_SEARCHPATH_SEPARATOR_S "%s", dir, path); g_free(dir); } #else /*!G_OS_WIN32*/ g_strlcpy(full_path, path, VIPS_PATH_MAX); #endif /*G_OS_WIN32*/ if ((prefix = scan_path(full_path, name))) return prefix; return NULL; } /* Guess a value for the install PREFIX. */ static const char * guess_prefix(const char *argv0, const char *name) { char *prefix; /* We've already checked for VIPSHOME. If the configure-time * library prefix looks OK, use the configure-time prefix. */ if (vips_existsf("%s/vips-modules-%d.%d", VIPS_LIBDIR, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION)) { g_info("found %s/vips-modules-%d.%d", VIPS_LIBDIR, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION); g_info("using configure-time prefix"); return VIPS_PREFIX; } /* Try to guess from argv0. */ if (argv0) { if (g_path_is_absolute(argv0)) { /* Must point to our executable. */ if ((prefix = extract_prefix(argv0, name))) { g_info("found \"%s\" from argv0", prefix); return prefix; } } /* Look along path for name. */ if ((prefix = find_file(name))) { g_info("found \"%s\" from PATH", prefix); return prefix; } } /* Try to guess from cwd. Only if this is a relative path, though. */ if (argv0 && !g_path_is_absolute(argv0)) { char *dir; char full_path[VIPS_PATH_MAX]; char *resolved; dir = g_get_current_dir(); g_snprintf(full_path, VIPS_PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", dir, argv0); g_free(dir); if ((resolved = vips_realpath(full_path))) { prefix = extract_prefix(resolved, name); g_free(resolved); if (prefix) { g_info("found \"%s\" from cwd", prefix); return prefix; } } } /* Fall back to the configure-time prefix. */ return VIPS_PREFIX; } /** * vips_guess_prefix: * @argv0: program name (typically argv[0]) * @env_name: save prefix in this environment variable * * [func@guess_prefix] tries to guess the install directory. You should pass * in the value of argv[0] (the name your program was run as) as a clue to * help it out, plus the name of the environment variable you let the user * override your package install area with (eg. "VIPSHOME"). * * On success, [func@guess_prefix] returns the prefix it discovered, and as a * side effect, sets the environment variable (if it's not set). * * Don't free the return string! * * ::: seealso * [func@guess_libdir]. * * Returns: (transfer none): the install prefix as a static string, do not free. */ const char * vips_guess_prefix(const char *argv0, const char *env_name) { const char *prefix; /* Already set? */ if ((prefix = g_getenv(env_name))) return prefix; #ifdef G_OS_WIN32 prefix = vips__windows_prefix(); #else /*!G_OS_WIN32*/ { char *basename; basename = g_path_get_basename(argv0); prefix = guess_prefix(argv0, basename); g_free(basename); } #endif /*G_OS_WIN32*/ g_setenv(env_name, prefix, TRUE); return prefix; } /** * vips_guess_libdir: * @argv0: program name (typically argv[0]) * @env_name: save prefix in this environment variable * * [func@guess_libdir] tries to guess the install directory (usually the * configure libdir, or $prefix/lib). You should pass * in the value of argv[0] (the name your program was run as) as a clue to * help it out, plus the name of the environment variable you let the user * override your package install area with (eg. "VIPSHOME"). * * On success, [func@guess_libdir] returns the libdir it discovered, and as a * side effect, sets the prefix environment variable (if it's not set). * * Don't free the return string! * * ::: seealso * [func@guess_prefix]. * * Returns: (transfer none): the libdir as a static string, do not free. */ const char * vips_guess_libdir(const char *argv0, const char *env_name) { const char *prefix = vips_guess_prefix(argv0, env_name); static char *libdir = NULL; char *suffix; if (libdir) return libdir; /* Have we been moved since configure? If not, use the configure-time * libdir. * * The lib directory name can be eg. "lib", "lib64" etc. depending on * the platform, so copy that from the configure-time libdir if we can. * The configure-time LIBDIR is generated by autotools and always uses * '/', even on Windows. */ if (strcmp(prefix, VIPS_PREFIX) == 0) libdir = VIPS_LIBDIR; else if ((suffix = strrchr(VIPS_LIBDIR, '/'))) libdir = g_strdup_printf("%s%s", prefix, suffix); else libdir = g_strdup_printf("%s/lib", prefix); return libdir; } /** * vips_version_string: * * Get the VIPS version as a static string, including a build date and time. * Do not free. * * Returns: (transfer none): a static version string */ const char * vips_version_string(void) { return VIPS_VERSION_STRING; } /** * vips_version: * @flag: which field of the version to get * * Get the major, minor or micro library version, with @flag values 0, 1 and * 2. * * Get the ABI current, revision and age (as used by Meson) with @flag * values 3, 4, 5. * * Returns: library version number */ int vips_version(int flag) { switch (flag) { case 0: return VIPS_MAJOR_VERSION; case 1: return VIPS_MINOR_VERSION; case 2: return VIPS_MICRO_VERSION; case 3: return VIPS_LIBRARY_CURRENT; case 4: return VIPS_LIBRARY_REVISION; case 5: return VIPS_LIBRARY_AGE; default: vips_error("vips_version", "%s", _("flag not in [0, 5]")); return -1; } } /** * vips_leak_set: * @leak: turn leak checking on or off * * Turn on or off vips leak checking. See also `--vips-leak`, * [func@add_option_entries] and the `VIPS_LEAK` environment variable. * * You should call this very early in your program. */ void vips_leak_set(gboolean leak) { vips__leak = leak; } static void * vips_block_untrusted_set_operation(VipsOperationClass *class, gboolean *state) { g_assert(VIPS_IS_OPERATION_CLASS(class)); if (class->flags & VIPS_OPERATION_UNTRUSTED) vips_operation_block_set(G_OBJECT_CLASS_NAME(class), *state); return NULL; } /** * vips_block_untrusted_set: * @state: the block state to set * * Set the block state on all untrusted operations. * * ```c * vips_block_untrusted_set(TRUE); * ``` * * Will block all untrusted operations from running. * * Use `vips -l` at the command-line to see the class hierarchy and which * operations are marked as untrusted. * * Set the environment variable `VIPS_BLOCK_UNTRUSTED` to block all untrusted * operations on [func@init]. */ void vips_block_untrusted_set(gboolean state) { vips_class_map_all(g_type_from_name("VipsOperation"), (VipsClassMapFn) vips_block_untrusted_set_operation, &state); } /* win32 can occasionally deadlock on main() return for exes built with clang, * see: https://github.com/libvips/libvips/discussions/4690 * * This function will terminate the process prematurely on win32, bypassing * normal process exit, but does nothing on other platforms. */ void vips__win32_terminate(int ret) { #ifdef G_OS_WIN32 /* These won't be flushed on a disorderly exit. */ fflush(stdout); fflush(stderr); /* Maybe add some other stuff! */ TerminateProcess(GetCurrentProcess(), ret); #endif /*G_OS_WIN32*/ } libvips-8.18.2/libvips/iofuncs/mapfile.c000066400000000000000000000217761516303661500202040ustar00rootroot00000000000000/* map and unmap files in various ways * * Copyright: Nicos Dessipris * Wriiten on: 13/02/1990 * Updated on: * 10/5/93 J.Cupitt * - im_mapfilerw() added * 13/12/94 JC * - ANSIfied * 5/7/99 JC * - better error if unable to map rw * 31/3/02 JC * - better mmap() fails error * 19/9/02 JC * - added im__mmap()/im__munmap() with windows versions * 5/1/04 Lev Serebryakov * - patched for freebsd compatibility * 5/2/04 JC * - now records length as well as base, so we unmap the right amount of * memory even if files change behind our back * 1/1/10 * - set NOCACHE if we can ... helps OS X performance a lot * 25/3/11 * - move to vips_ namespace */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_SYS_MMAN_H #include #endif /*HAVE_SYS_MMAN_H*/ #ifdef HAVE_SYS_FILE_H #include #endif /*HAVE_SYS_FILE_H*/ #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #ifdef G_OS_WIN32 #ifndef S_ISREG #define S_ISREG(m) (!!(m & _S_IFREG)) #endif #include #include #endif /*G_OS_WIN32*/ #ifdef _MSC_VER #define mode_t guint16 #endif /* Does this fd support mmap. Pipes won't, for example. * FIXME unused internal function */ gboolean vips__mmap_supported(int fd) { void *baseaddr; size_t length = 4096; off_t offset = 0; #ifdef G_OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle(fd); DWORD flProtect; HANDLE hMMFile; DWORD dwDesiredAccess; ULARGE_INTEGER quad; DWORD dwFileOffsetHigh; DWORD dwFileOffsetLow; flProtect = PAGE_READONLY; if (!(hMMFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL))) return FALSE; dwDesiredAccess = FILE_MAP_READ; quad.QuadPart = offset; dwFileOffsetLow = quad.LowPart; dwFileOffsetHigh = quad.HighPart; if (!(baseaddr = (char *) MapViewOfFile(hMMFile, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, length))) { CloseHandle(hMMFile); return FALSE; } CloseHandle(hMMFile); UnmapViewOfFile(baseaddr); } #else /*!G_OS_WIN32*/ { int prot = PROT_READ; int flags = MAP_SHARED; baseaddr = mmap(0, length, prot, flags, fd, (off_t) offset); if (baseaddr == MAP_FAILED) return FALSE; munmap(baseaddr, length); } #endif /*G_OS_WIN32*/ return TRUE; } void * vips__mmap(int fd, int writeable, size_t length, gint64 offset) { void *baseaddr; #ifdef DEBUG printf("vips__mmap: length = 0x%zx, offset = 0x%lx\n", length, offset); #endif /*DEBUG*/ #ifdef G_OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle(fd); DWORD flProtect; DWORD dwDesiredAccess; HANDLE hMMFile; ULARGE_INTEGER quad; DWORD dwFileOffsetHigh; DWORD dwFileOffsetLow; if (writeable) { flProtect = PAGE_READWRITE; dwDesiredAccess = FILE_MAP_WRITE; } else { flProtect = PAGE_READONLY; dwDesiredAccess = FILE_MAP_READ; } quad.QuadPart = offset; dwFileOffsetLow = quad.LowPart; dwFileOffsetHigh = quad.HighPart; if (!(hMMFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL))) { vips_error_system(GetLastError(), "vips_mapfile", "%s", _("unable to CreateFileMapping")); return NULL; } if (!(baseaddr = (char *) MapViewOfFile(hMMFile, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, length))) { vips_error_system(GetLastError(), "vips_mapfile", "%s", _("unable to MapViewOfFile")); CloseHandle(hMMFile); return NULL; } /* Can close mapping now ... view stays until UnmapViewOfFile(). FIXME ... is this a performance problem? see https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga We should probably have a small cache from hFile -> hMMFile and reuse mappings between vips__mmap calls keep a ref count for each mapping and kick the hMMFile out of cache on the final munmap */ CloseHandle(hMMFile); } #else /*!G_OS_WIN32*/ { int prot; int flags; if (writeable) prot = PROT_WRITE; else prot = PROT_READ; flags = MAP_SHARED; /* OS X caches mmapped files very aggressively if this flags is not * set. Scanning a large file without this flag will cause every other * process to get swapped out and kill performance. */ #ifdef MAP_NOCACHE flags |= MAP_NOCACHE; #endif /*MAP_NOCACHE*/ /* Casting gint64 to off_t should be safe, even on *nixes without * LARGEFILE. */ baseaddr = mmap(0, length, prot, flags, fd, (off_t) offset); if (baseaddr == MAP_FAILED) { vips_error_system(errno, "vips_mapfile", "%s", _("unable to mmap")); return NULL; } } #endif /*G_OS_WIN32*/ return baseaddr; } int vips__munmap(const void *start, size_t length) { #ifdef G_OS_WIN32 if (!UnmapViewOfFile((void *) start)) { vips_error_system(GetLastError(), "vips_mapfile", "%s", _("unable to UnmapViewOfFile")); return -1; } #else /*!G_OS_WIN32*/ if (munmap((void *) start, length) < 0) { vips_error_system(errno, "vips_mapfile", "%s", _("unable to munmap file")); return -1; } #endif /*G_OS_WIN32*/ return 0; } int vips_mapfile(VipsImage *im) { struct stat st; mode_t m; assert(!im->baseaddr); /* Check the size of the file; if it is less than 64 bytes, then flag * an error, we won't be able to read the vips header without a segv. */ g_assert(im->file_length > 0); if (im->file_length < 64) { vips_error("vips_mapfile", "%s", _("file is less than 64 bytes")); return -1; } if (fstat(im->fd, &st) == -1) { vips_error("vips_mapfile", "%s", _("unable to get file status")); return -1; } m = (mode_t) st.st_mode; if (!S_ISREG(m)) { vips_error("vips_mapfile", "%s", _("not a regular file")); return -1; } if (!(im->baseaddr = vips__mmap(im->fd, 0, im->file_length, 0))) return -1; im->length = im->file_length; return 0; } /* As above, but map read/write. */ int vips_mapfilerw(VipsImage *im) { struct stat st; mode_t m; assert(!im->baseaddr); /* Check the size of the file if it is less than 64 bytes return * make also sure that it is a regular file */ g_assert(im->file_length > 0); if (fstat(im->fd, &st) == -1) { vips_error("vips_mapfilerw", "%s", _("unable to get file status")); return -1; } m = (mode_t) st.st_mode; if (im->file_length < 64 || !S_ISREG(m)) { vips_error("vips_mapfile", "%s", _("unable to read data")); return -1; } if (!(im->baseaddr = vips__mmap(im->fd, 1, im->file_length, 0))) return -1; im->length = im->file_length; return 0; } /* From im_rwcheck() ... image needs to be a completely mapped read-only file, * we try to remap it read-write. */ int vips_remapfilerw(VipsImage *image) { void *baseaddr; #ifdef DEBUG printf("vips_remapfilerw:\n"); #endif /*DEBUG*/ #ifdef G_OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle(image->fd); HANDLE hMMFile; if (!(hMMFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL))) { vips_error_system(GetLastError(), "vips_mapfile", "%s", _("unable to CreateFileMapping")); return -1; } if (!UnmapViewOfFile(image->baseaddr)) { vips_error_system(GetLastError(), "vips_mapfile", "%s", _("unable to UnmapViewOfFile")); return -1; } if (!(baseaddr = (char *) MapViewOfFileEx(hMMFile, FILE_MAP_WRITE, 0, 0, 0, image->baseaddr))) { vips_error_system(GetLastError(), "vips_mapfile", "%s", _("unable to MapViewOfFile")); CloseHandle(hMMFile); return -1; } /* Can close mapping now ... view stays until UnmapViewOfFile(). FIXME ... is this a performance problem? */ CloseHandle(hMMFile); } #else /*!G_OS_WIN32*/ { assert(image->dtype == VIPS_IMAGE_MMAPIN); baseaddr = mmap(image->baseaddr, image->length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, image->fd, 0); if (baseaddr == (void *) -1) { vips_error("vips_mapfile", _("unable to mmap: \"%s\" - %s"), image->filename, g_strerror(errno)); return -1; } } #endif /*G_OS_WIN32*/ image->dtype = VIPS_IMAGE_MMAPINRW; if (baseaddr != image->baseaddr) { vips_error("vips_mapfile", _("unable to mmap \"%s\" to same address"), image->filename); image->baseaddr = baseaddr; return -1; } return 0; } libvips-8.18.2/libvips/iofuncs/memory.c000066400000000000000000000317161516303661500200720ustar00rootroot00000000000000/* tracked memory * * 2/11/99 JC * - from im_open.c and callback.c * - malloc tracking stuff added * 11/3/01 JC * - im_strncpy() added * 20/4/01 JC * - im_(v)snprintf() added * 6/7/05 * - more tracking for DEBUGM * 20/10/06 * - return NULL for size <= 0 * 11/5/06 * - abort() on malloc() failure with DEBUG * 20/10/09 * - gtkdoc comment * 6/11/09 * - im_malloc()/im_free() now call g_try_malloc/g_free() ... removes * confusion over whether to use im_free() or g_free() for things like * im_header_string() * 21/9/11 * - rename as vips_tracked_malloc() to emphasise difference from * g_malloc()/g_free() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_IO_H #include #endif /*HAVE_IO_H*/ #include #include #include #include #if defined(HAVE__ALIGNED_MALLOC) || defined(HAVE_MEMALIGN) #include #endif #include /* g_assert_not_reached() on memory errors. #define DEBUG */ /* Track malloc/free and open/close. #define DEBUG_VERBOSE_MEM #define DEBUG_VERBOSE_FD */ #ifdef DEBUG #warning DEBUG on in libsrc/iofuncs/memory.c #endif /*DEBUG*/ static int vips_tracked_allocs = 0; static size_t vips_tracked_mem = 0; static int vips_tracked_files = 0; static size_t vips_tracked_mem_highwater = 0; static GMutex vips_tracked_mutex; /** * VIPS_NEW: * @OBJ: allocate memory local to @OBJ, or `NULL` for no auto-free * @T: type of thing to allocate * * Allocate memory for a thing of type @T. The memory is not * cleared. * * This macro cannot fail. See [func@tracked_malloc] if you are * allocating large amounts of memory. * * ::: seealso * [func@malloc]. * * Returns: A pointer of type @T *. */ /** * VIPS_ARRAY: * @OBJ: allocate memory local to @OBJ, or `NULL` for no auto-free * @N: number of @T 's to allocate * @T: type of thing to allocate * * Allocate memory for an array of objects of type @T. The memory is not * cleared. * * This macro cannot fail. See [func@tracked_malloc] if you are * allocating large amounts of memory. * * ::: seealso * [func@malloc]. * * Returns: A pointer of type @T *. */ static void vips_malloc_cb(VipsObject *object, char *buf) { g_free(buf); } /** * vips_malloc: * @object: (nullable): allocate memory local to this [class@Object], or `NULL` * @size: number of bytes to allocate * * [func@GLib.malloc] local to @object, that is, the memory will be automatically * freed for you when the object is closed. If @object is `NULL`, you need to * free the memory explicitly with [func@GLib.free]. * * This function cannot fail. See [func@tracked_malloc] if you are * allocating large amounts of memory. * * ::: seealso * [func@tracked_malloc]. * * Returns: (transfer full): a pointer to the allocated memory. */ void * vips_malloc(VipsObject *object, size_t size) { void *buf; buf = g_malloc0(size); if (object) { g_signal_connect(object, "postclose", G_CALLBACK(vips_malloc_cb), buf); object->local_memory += size; } return buf; } /** * vips_strdup: * @object: (nullable): allocate memory local to this [class@Object], or `NULL` * @str: string to copy * * [func@GLib.strdup] a string. When @object is freed, the string will be freed for * you. If @object is `NULL`, you need to * free the memory yourself with [func@GLib.free]. * * This function cannot fail. * * ::: seealso * [func@malloc]. * * Returns: (transfer full): a pointer to the allocated memory */ char * vips_strdup(VipsObject *object, const char *str) { char *str_dup; str_dup = g_strdup(str); if (object) { g_signal_connect(object, "postclose", G_CALLBACK(vips_malloc_cb), str_dup); object->local_memory += strlen(str); } return str_dup; } /** * vips_tracked_free: * @s: (transfer full): memory to free * * Only use it to free memory that was * previously allocated with [func@tracked_malloc] * with a `NULL` first argument. * * ::: seealso * [func@tracked_malloc]. */ void vips_tracked_free(void *s) { /* Keep the size of the alloc in the previous 16 bytes. Ensures * alignment rules are kept. */ void *start = (void *) ((char *) s - 16); size_t size = *((size_t *) start); g_mutex_lock(&vips_tracked_mutex); #ifdef DEBUG_VERBOSE_MEM printf("vips_tracked_free: %p, %zd bytes\n", s, size); #endif /*DEBUG_VERBOSE_MEM*/ if (vips_tracked_allocs <= 0) g_warning("vips_free: too many frees"); if (vips_tracked_mem < size) g_warning("vips_free: too much free"); vips_tracked_mem -= size; vips_tracked_allocs -= 1; g_mutex_unlock(&vips_tracked_mutex); g_free(start); VIPS_GATE_FREE(size); } /** * vips_tracked_aligned_free: * @s: (transfer full): memory to free * * Only use it to free memory that was * previously allocated with [func@tracked_aligned_alloc] * with a `NULL` first argument. * * ::: seealso * [func@tracked_aligned_alloc]. */ void vips_tracked_aligned_free(void *s) { void *start = (size_t *) s - 1; size_t size = *((size_t *) start); g_mutex_lock(&vips_tracked_mutex); #ifdef DEBUG_VERBOSE printf("vips_tracked_aligned_free: %p, %zd bytes\n", s, size); #endif /*DEBUG_VERBOSE*/ if (vips_tracked_allocs <= 0) g_warning("vips_free: too many frees"); if (vips_tracked_mem < size) g_warning("vips_free: too much free"); vips_tracked_mem -= size; vips_tracked_allocs -= 1; g_mutex_unlock(&vips_tracked_mutex); #ifdef HAVE__ALIGNED_MALLOC _aligned_free(start); #else /*defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN)*/ free(start); #endif VIPS_GATE_FREE(size); } /** * vips_tracked_malloc: * @size: number of bytes to allocate * * Allocate an area of memory that will be tracked by [func@tracked_get_mem] * and friends. * * If allocation fails, [func@tracked_malloc] returns `NULL` and * sets an error message. * * You must only free the memory returned with [func@tracked_free]. * * ::: seealso * [func@tracked_free], [func@malloc]. * * Returns: (transfer full): a pointer to the allocated memory, or `NULL` on error. */ void * vips_tracked_malloc(size_t size) { void *buf; /* Need an extra sizeof(size_t) bytes to track * size of this block. Ask for an extra 16 to make sure we don't break * alignment rules. */ size += 16; if (!(buf = g_try_malloc0(size))) { #ifdef DEBUG g_assert_not_reached(); #endif /*DEBUG*/ vips_error("vips_tracked", _("out of memory -- size == %dMB"), (int) (size / (1024.0 * 1024.0))); g_warning("out of memory -- size == %dMB", (int) (size / (1024.0 * 1024.0))); return NULL; } g_mutex_lock(&vips_tracked_mutex); *((size_t *) buf) = size; buf = (void *) ((char *) buf + 16); vips_tracked_mem += size; if (vips_tracked_mem > vips_tracked_mem_highwater) vips_tracked_mem_highwater = vips_tracked_mem; vips_tracked_allocs += 1; #ifdef DEBUG_VERBOSE_MEM printf("vips_tracked_malloc: %p, %zd bytes\n", buf, size); #endif /*DEBUG_VERBOSE_MEM*/ g_mutex_unlock(&vips_tracked_mutex); VIPS_GATE_MALLOC(size); return buf; } /** * vips_tracked_aligned_alloc: * @size: number of bytes to allocate * @align: specifies the alignment * * Allocate an area of memory aligned on a boundary specified * by @align that will be tracked by [func@tracked_get_mem] * and friends. * * If allocation fails, [func@tracked_aligned_alloc] returns `NULL` * and sets an error message. * * You must only free the memory returned with [func@tracked_aligned_free]. * * ::: seealso * [func@tracked_malloc], [func@tracked_aligned_free], [func@malloc]. * * Returns: (transfer full): a pointer to the allocated memory, or `NULL` on error. */ void * vips_tracked_aligned_alloc(size_t size, size_t align) { void *buf; g_assert(!(align & (align - 1))); /* Need an extra sizeof(size_t) bytes to track * size of this block. */ size += sizeof(size_t); #ifdef HAVE__ALIGNED_MALLOC if (!(buf = _aligned_malloc(size, align))) { #elif defined(HAVE_POSIX_MEMALIGN) if (posix_memalign(&buf, align, size)) { #elif defined(HAVE_MEMALIGN) if (!(buf = memalign(align, size))) { #else #error Missing aligned alloc implementation #endif #ifdef DEBUG g_assert_not_reached(); #endif /*DEBUG*/ vips_error("vips_tracked", _("out of memory -- size == %dMB"), (int) (size / (1024.0 * 1024.0))); g_warning("out of memory -- size == %dMB", (int) (size / (1024.0 * 1024.0))); return NULL; } memset(buf, 0, size); g_mutex_lock(&vips_tracked_mutex); *((size_t *) buf) = size; vips_tracked_mem += size; if (vips_tracked_mem > vips_tracked_mem_highwater) vips_tracked_mem_highwater = vips_tracked_mem; vips_tracked_allocs += 1; #ifdef DEBUG_VERBOSE printf("vips_tracked_aligned_alloc: %p, %zd bytes\n", buf, size); #endif /*DEBUG_VERBOSE*/ g_mutex_unlock(&vips_tracked_mutex); VIPS_GATE_MALLOC(size); return (void *) ((size_t *) buf + 1); } /** * vips_tracked_open: * @pathname: name of file to open * @flags: flags for `open()` * @mode: open mode * * Exactly as [`open()`](man:open(2)), but the number of files currently open via * [func@tracked_open] is available via [func@tracked_get_files]. This is used * by the vips operation cache to drop cache when the number of files * available is low. * * You must only close the file descriptor with [func@tracked_close]. * * @pathname should be utf8. * * ::: seealso * [func@tracked_close], [func@tracked_get_files]. * * Returns: a file descriptor, or -1 on error. */ int vips_tracked_open(const char *pathname, int flags, int mode) { int fd; if ((fd = vips__open(pathname, flags, mode)) == -1) return -1; g_mutex_lock(&vips_tracked_mutex); vips_tracked_files += 1; #ifdef DEBUG_VERBOSE_FD printf("vips_tracked_open: %s = %d (%d)\n", pathname, fd, vips_tracked_files); #endif /*DEBUG_VERBOSE_FD*/ g_mutex_unlock(&vips_tracked_mutex); return fd; } /** * vips_tracked_close: * @fd: file to `close()` * * Exactly as [`close()`](man:close(2)), but update the number of files currently open via * [func@tracked_get_files]. This is used * by the vips operation cache to drop cache when the number of files * available is low. * * You must only close file descriptors opened with [func@tracked_open]. * * ::: seealso * [func@tracked_open], [func@tracked_get_files]. * * Returns: a file descriptor, or -1 on error. */ int vips_tracked_close(int fd) { int result; g_mutex_lock(&vips_tracked_mutex); /* libvips uses fd -1 to mean invalid descriptor. */ g_assert(fd != -1); g_assert(vips_tracked_files > 0); vips_tracked_files -= 1; #ifdef DEBUG_VERBOSE_FD printf("vips_tracked_close: %d (%d)\n", fd, vips_tracked_files); printf(" from thread %p\n", g_thread_self()); #endif /*DEBUG_VERBOSE_FD*/ g_mutex_unlock(&vips_tracked_mutex); result = close(fd); return result; } /** * vips_tracked_get_mem: * * Returns the number of bytes currently allocated via [func@malloc] and * friends. vips uses this figure to decide when to start dropping cache, see * [class@Operation]. * * Returns: the number of currently allocated bytes */ size_t vips_tracked_get_mem(void) { size_t mem; g_mutex_lock(&vips_tracked_mutex); mem = vips_tracked_mem; g_mutex_unlock(&vips_tracked_mutex); return mem; } /** * vips_tracked_get_mem_highwater: * * Returns the largest number of bytes simultaneously allocated via * [func@tracked_malloc]. Handy for estimating max memory requirements for a * program. * * Returns: the largest number of currently allocated bytes */ size_t vips_tracked_get_mem_highwater(void) { size_t mx; g_mutex_lock(&vips_tracked_mutex); mx = vips_tracked_mem_highwater; g_mutex_unlock(&vips_tracked_mutex); return mx; } /** * vips_tracked_get_allocs: * * Returns the number of active allocations. * * Returns: the number of active allocations */ int vips_tracked_get_allocs(void) { int n; g_mutex_lock(&vips_tracked_mutex); n = vips_tracked_allocs; g_mutex_unlock(&vips_tracked_mutex); return n; } /** * vips_tracked_get_files: * * Returns the number of open files. * * Returns: the number of open files */ int vips_tracked_get_files(void) { int n; g_mutex_lock(&vips_tracked_mutex); n = vips_tracked_files; g_mutex_unlock(&vips_tracked_mutex); return n; } libvips-8.18.2/libvips/iofuncs/meson.build000066400000000000000000000020631516303661500205510ustar00rootroot00000000000000iofuncs_sources = files( 'thread.c', 'threadset.c', 'threadpool.c', 'ginputsource.c', 'connection.c', 'source.c', 'sourcecustom.c', 'sourceginput.c', 'target.c', 'targetcustom.c', 'sbuf.c', 'dbuf.c', 'reorder.c', 'type.c', 'gate.c', 'object.c', 'error.c', 'image.c', 'vips.c', 'generate.c', 'mapfile.c', 'cache.c', 'sink.c', 'sinkmemory.c', 'sinkdisc.c', 'sinkscreen.c', 'memory.c', 'header.c', 'operation.c', 'region.c', 'rect.c', 'semaphore.c', 'util.c', 'init.c', 'buf.c', 'window.c', 'vector.cpp', 'system.c', 'buffer.c', ) iofuncs_headers = files( 'sink.h', ) vipsmarshal = gnome.genmarshal( 'vipsmarshal', prefix: 'vips', sources: 'vipsmarshal.list', ) libvips_sources += iofuncs_sources iofuncs_lib = static_library('iofuncs', iofuncs_sources, iofuncs_headers, vipsmarshal, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += iofuncs_lib libvips-8.18.2/libvips/iofuncs/object.c000066400000000000000000002402651516303661500200310ustar00rootroot00000000000000/* abstract base class for all vips objects * * Edited from nip's base class, 15/10/08 * * 29/5/18 * - added vips_argument_get_id() */ /* Copyright (C) 1991-2003 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define VIPS_DEBUG #define DEBUG_REF */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /* For VIPS_OPERATION_SEQUENTIAL_UNBUFFERED */ #define VIPS_DISABLE_DEPRECATION_WARNINGS #include #include #include #include #include "vipsmarshal.h" /** * VipsObject: * * An abstract base class for all objects in libvips. * * It has the following major features: * * - **Functional class creation**: libvips objects have a very regular * lifecycle: initialise, build, use, destroy. They behave rather like * function calls and are free of side-effects. * * - **Run-time introspection**: libvips objects can be fully introspected * at run-time. There is no need for separate source-code analysis. * * - **Command-line interface**: Any vips object can be run from the * command-line with the `vips` driver program. * * ## The [class@Object] lifecycle * * [class@Object]'s have a strictly defined lifecycle, split broadly as * construct and then use. In detail, the stages are: * * 1. [ctor@GObject.Object.new]. The [class@Object] is created with * [ctor@GObject.Object.new]. Objects in this state are blank slates and * need to have their various parameters set. * * 2. [method@GObject.Object.set]. You loop over the [struct@Argument] that * the object has defined with [func@Argument.map]. Arguments have a set of * flags attached to them for required, optional, input, output, type, and * so on. You must set all required arguments. * * 3. [method@Object.build]. Call this to construct the object and get it * ready for use. Building an object happens in four stages, see below. * * 4. [method@GObject.Object.get]. The object has now been built. You can * read out any computed values. * * 5. [method@GObject.Object.unref]. When you are done with an object, you * can unref it. See the section on reference counting for an explanation * of the convention that [class@Object] uses. When the last ref to an * object is released, the object is closed. Objects close in three stages, * see below. * * The stages inside [method@Object.build] are: * * 1. Chain up through the object's `build` class methods. At each stage, * each class does any initial setup and checking, then chains up to its * superclass. * * 2. The innermost `build` method inside [class@Object] itself checks that * all input arguments have been set and then returns. * * 3. All object `build` methods now finish executing, from innermost to * outermost. They know all input arguments have been checked and supplied, * so now they set all output arguments. * * 4. [method@Object.build] finishes the process by checking that all output * objects have been set, and then triggering the [signal@Object::postbuild] * signal. [signal@Object::postbuild] only runs if the object has constructed * successfully. * * [class@Operation] has a cache of recent operation objects, see that class for * an explanation of [func@cache_operation_build]. * * Finally, the stages inside close are: * * 1. [signal@Object::preclose]. This is emitted at the start of the * [class@Object] dispose. The object is still functioning. * * 2. [signal@Object::close]. This runs just after all [struct@Argument] held * by the object have been released. * * 3. [signal@Object::postclose]. This runs right at the end. The object * pointer is still valid, but nothing else is. * * ## The [class@Object] reference counting convention * * [class@Object] has a set of conventions to simplify reference counting. * * 1. All input [class@GObject.Object] have a ref added to them, owned by the * object. When a [class@Object] is unreffed, all of these refs to input * objects are automatically dropped. * * 2. All output [class@GObject.Object] hold a ref to the object. When a * [class@GObject.Object] which is an output of a [class@Object] is * disposed, it must drop this reference. [class@Object] which are outputs * of other [class@Object]'s will do this automatically. * * See [class@Operation] for an example of [class@Object] reference counting. */ /** * VipsArgument: * * libvips has a simple mechanism for automating at least some aspects of * [class@GObject.Object] properties. You add a set of macros to your * `_class_init()` which describe the arguments, and set the get and set * functions to the libvips ones. * * See [extending](extending.html) for a complete example. */ /** * VipsArgumentFlags: * @VIPS_ARGUMENT_NONE: no flags * @VIPS_ARGUMENT_REQUIRED: must be set in the constructor * @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor * @VIPS_ARGUMENT_SET_ONCE: can only be set once * @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on) * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us) * @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide * @VIPS_ARGUMENT_MODIFY: the input argument will be modified * @VIPS_ARGUMENT_NON_HASHABLE: the argument is non-hashable * * Flags we associate with each object argument. * * Have separate input & output flags. Both set is an error; neither set is OK. * * Input gobjects are automatically reffed, output gobjects automatically ref * us. We also automatically watch for "destroy" and unlink. * * [flags@Vips.ArgumentFlags.SET_ALWAYS] is handy for arguments which are set * from C. For example, [property@Image:width] is a property that gives * access to the Xsize member of struct _VipsImage. We default its * 'assigned' to `TRUE` since the field is always set directly by C. * * [flags@Vips.ArgumentFlags.DEPRECATED] arguments are not shown in help text, * are not looked for if required, are not checked for "have-been-set". You can * deprecate a required argument, but you must obviously add a new required * argument if you do. * * Input args with [flags@Vips.ArgumentFlags.MODIFY] will be modified by the * operation. This is used for things like the in-place drawing operations. * * [flags@Vips.ArgumentFlags.NON_HASHABLE] stops the argument being used in * hash and equality tests. It's useful for arguments like `revalidate` which * control the behaviour of the operator cache. */ /* Our signals. */ enum { SIG_POSTBUILD, SIG_PRECLOSE, SIG_CLOSE, SIG_POSTCLOSE, SIG_LAST }; /* Table of all objects, handy for debugging. */ static GHashTable *vips__object_all = NULL; static GMutex vips__object_all_lock; static guint vips_object_signals[SIG_LAST] = { 0 }; /* This has to be externally visible for compatibility with older libvipses. */ int _vips__argument_id = 1; /* Keep a cache of nickname -> GType lookups. */ static GHashTable *vips__object_nickname_table = NULL; G_DEFINE_ABSTRACT_TYPE(VipsObject, vips_object, G_TYPE_OBJECT); /** * vips_argument_get_id: (skip) * * Allocate a new property id. See * [method@GObject.ObjectClass.install_property]. * * Returns: a new property id > 0 */ int vips_argument_get_id(void) { int id; /* We probably don't need to lock: glib seems to single-thread class * creation. */ id = _vips__argument_id++; return id; } /* Don't call this directly, see vips_object_build(). */ static int vips_object_postbuild(VipsObject *object) { int result; #ifdef DEBUG printf("vips_object_postbuild: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_signal_emit(object, vips_object_signals[SIG_POSTBUILD], 0, &result); return result; } void vips_object_preclose(VipsObject *object) { if (!object->preclose) { object->preclose = TRUE; #ifdef DEBUG printf("vips_object_preclose: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_signal_emit(object, vips_object_signals[SIG_PRECLOSE], 0); } } static void vips_object_close(VipsObject *object) { if (!object->close) { object->close = TRUE; #ifdef DEBUG printf("vips_object_close: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_signal_emit(object, vips_object_signals[SIG_CLOSE], 0); } } static void vips_object_postclose(VipsObject *object) { if (!object->postclose) { object->postclose = TRUE; #ifdef DEBUG printf("vips_object_postclose: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_signal_emit(object, vips_object_signals[SIG_POSTCLOSE], 0); } } static void * vips_object_check_required(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); int *result = (int *) a; VipsArgumentFlags *iomask = (VipsArgumentFlags *) b; VIPS_DEBUG_MSG("vips_object_check_required: %s\n", g_param_spec_get_name(pspec)); VIPS_DEBUG_MSG("\trequired: %d\n", argument_class->flags & VIPS_ARGUMENT_REQUIRED); VIPS_DEBUG_MSG("\tconstruct: %d\n", argument_class->flags & VIPS_ARGUMENT_CONSTRUCT); VIPS_DEBUG_MSG("\tinput: %d\n", argument_class->flags & VIPS_ARGUMENT_INPUT); VIPS_DEBUG_MSG("\toutput: %d\n", argument_class->flags & VIPS_ARGUMENT_OUTPUT); VIPS_DEBUG_MSG("\tassigned: %d\n", argument_instance->assigned); if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) && (argument_class->flags & *iomask) && !argument_instance->assigned) { vips_error(class->nickname, _("parameter %s not set"), g_param_spec_get_name(pspec)); *result = -1; } return NULL; } int vips_object_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); /* Input and output args must both be set. */ VipsArgumentFlags iomask = VIPS_ARGUMENT_INPUT | VIPS_ARGUMENT_OUTPUT; int result; #ifdef DEBUG printf("vips_object_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (class->build(object)) return -1; /* Check all required arguments have been supplied, don't stop on 1st * error. */ result = 0; (void) vips_argument_map(object, vips_object_check_required, &result, &iomask); /* ... more checks go here. */ object->constructed = TRUE; /* Only postbuild on success. */ if (!result) result = vips_object_postbuild(object); return result; } /** * vips_object_summary_class: (skip) * @klass: class to summarise * @buf: write summary here * * Generate a human-readable summary for a class. */ void vips_object_summary_class(VipsObjectClass *klass, VipsBuf *buf) { klass->summary_class(klass, buf); } /** * vips_object_summary: (skip) * @object: object to summarise * @buf: write summary here * * Generate a human-readable summary for an object. */ void vips_object_summary(VipsObject *object, VipsBuf *buf) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); class->summary(object, buf); } /** * vips_object_dump: (skip) * @object: object to dump * @buf: write dump here * * Dump everything that vips knows about an object to a string. */ void vips_object_dump(VipsObject *object, VipsBuf *buf) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); class->dump(object, buf); } void vips_object_print_summary_class(VipsObjectClass *klass) { char str[2048]; VipsBuf buf = VIPS_BUF_STATIC(str); vips_object_summary_class(klass, &buf); printf("%s\n", vips_buf_all(&buf)); } void vips_object_print_summary(VipsObject *object) { char str[2048]; VipsBuf buf = VIPS_BUF_STATIC(str); vips_object_summary(object, &buf); printf("%s\n", vips_buf_all(&buf)); } void vips_object_print_dump(VipsObject *object) { char str[32768]; VipsBuf buf = VIPS_BUF_STATIC(str); vips_object_dump(object, &buf); printf("%s\n", vips_buf_all(&buf)); } void vips_object_print_name(VipsObject *object) { printf("%s (%p)", G_OBJECT_TYPE_NAME(object), object); } gboolean vips_object_sanity(VipsObject *object) { if (!object) { vips_error("vips_object_sanity", _("null object")); return FALSE; } VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); char str[1000]; VipsBuf buf = VIPS_BUF_STATIC(str); class->sanity(object, &buf); if (!vips_buf_is_empty(&buf)) { vips_error(class->nickname, "%s", vips_buf_all(&buf)); return FALSE; } return TRUE; } /* On a rewind, we dispose the old contents of the object and * reconstruct. This is used in things like im_pincheck() where a "w" * image has to be rewound and become a "p" image. * * Override in subclasses if you want to preserve some fields, see image.c. */ void vips_object_rewind(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); class->rewind(object); } /* Extra stuff we track for properties to do our argument handling. */ static void vips_argument_instance_detach(VipsArgumentInstance *argument_instance) { VipsObject *object = argument_instance->object; VipsArgumentClass *argument_class = argument_instance->argument_class; if (argument_instance->close_id) { /* If close_id is set, the argument must be a gobject of some * sort, so we can fetch it. */ GObject *member = G_STRUCT_MEMBER(GObject *, object, argument_class->offset); if (g_signal_handler_is_connected(member, argument_instance->close_id)) g_signal_handler_disconnect(member, argument_instance->close_id); argument_instance->close_id = 0; } if (argument_instance->invalidate_id) { GObject *member = G_STRUCT_MEMBER(GObject *, object, argument_class->offset); if (g_signal_handler_is_connected(member, argument_instance->invalidate_id)) g_signal_handler_disconnect(member, argument_instance->invalidate_id); argument_instance->invalidate_id = 0; } } /* Free a VipsArgumentInstance ... VipsArgumentClass can just be g_free()d. */ static void vips_argument_instance_free(VipsArgumentInstance *argument_instance) { vips_argument_instance_detach(argument_instance); g_free(argument_instance); } VipsArgument * vips__argument_table_lookup(VipsArgumentTable *table, GParamSpec *pspec) { VipsArgument *argument; g_mutex_lock(&vips__global_lock); argument = (VipsArgument *) g_hash_table_lookup(table, pspec); g_mutex_unlock(&vips__global_lock); return argument; } static void vips_argument_table_replace(VipsArgumentTable *table, VipsArgument *argument) { g_hash_table_replace(table, argument->pspec, argument); } static void vips_argument_table_destroy(VipsArgumentTable *table) { g_hash_table_destroy(table); } /** * vips_argument_map: * @object: object whose args should be enumerated * @fn: (scope call) (closure a): call this function for every argument * @a: client data * @b: client data * * Loop over the [struct@Argument] of an object. Stop when @fn returns non-`NULL` * and return that value. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_argument_map(VipsObject *object, VipsArgumentMapFn fn, void *a, void *b) { /* Make sure we can't go during the loop. This can happen if eg. we * flush an arg that refs us. */ g_object_ref(object); VIPS_ARGUMENT_FOR_ALL(object, pspec, argument_class, argument_instance) { void *result; /* argument_instance should not be NULL. */ g_assert(argument_instance); if ((result = fn(object, pspec, argument_class, argument_instance, a, b))) { g_object_unref(object); return result; } } VIPS_ARGUMENT_FOR_ALL_END g_object_unref(object); return NULL; } /** * vips_argument_class_map: (skip) * * And loop over a class. Same as ^^, but with no VipsArgumentInstance. */ void * vips_argument_class_map(VipsObjectClass *object_class, VipsArgumentClassMapFn fn, void *a, void *b) { GSList *p; for (p = object_class->argument_table_traverse; p; p = p->next) { VipsArgumentClass *arg_class = (VipsArgumentClass *) p->data; VipsArgument *argument = (VipsArgument *) arg_class; GParamSpec *pspec = argument->pspec; void *result; if ((result = fn(object_class, pspec, arg_class, a, b))) return result; } return NULL; } /* Does an vipsargument need an argument to write to? For example, an image * output needs a filename, a double output just prints. */ gboolean vips_argument_class_needsstring(VipsArgumentClass *argument_class) { GParamSpec *pspec = ((VipsArgument *) argument_class)->pspec; GType otype; VipsObjectClass *oclass; if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) /* Bools, input or output, don't need args. */ return FALSE; if (argument_class->flags & VIPS_ARGUMENT_INPUT) /* All other inputs need something. */ return TRUE; /* Just output objects. */ if ((otype = G_PARAM_SPEC_VALUE_TYPE(pspec)) && g_type_is_a(otype, VIPS_TYPE_OBJECT) && (oclass = g_type_class_ref(otype))) /* For now, only vipsobject subclasses can ask for args. */ return oclass->output_needs_arg; else return FALSE; } /* Create a VipsArgumentInstance for each installed argument property. Ideally * we'd do this during _init() but g_object_class_find_property() does not seem * to work then :-( so we have to delay it until first access. See * vips__argument_get_instance(). */ static void vips_argument_init(VipsObject *object) { if (!object->argument_table) { #ifdef DEBUG printf("vips_argument_init: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ object->argument_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) vips_argument_instance_free); /* Make a VipsArgumentInstance for each installed argument * property. We can't use vips_argument_map() since that does * some sanity checks that won't pass until all arg instance * are built. */ VIPS_ARGUMENT_FOR_ALL(object, pspec, argument_class, argument_instance) { #ifdef DEBUG printf("vips_argument_init: adding instance argument for %s\n", g_param_spec_get_name(pspec)); #endif /*DEBUG*/ /* argument_instance should be NULL since we've not * set it yet. */ g_assert(argument_instance == NULL); argument_instance = g_new(VipsArgumentInstance, 1); ((VipsArgument *) argument_instance)->pspec = pspec; argument_instance->argument_class = argument_class; argument_instance->object = object; /* SET_ALWAYS args default to assigned. */ argument_instance->assigned = argument_class->flags & VIPS_ARGUMENT_SET_ALWAYS; argument_instance->close_id = 0; argument_instance->invalidate_id = 0; vips_argument_table_replace(object->argument_table, (VipsArgument *) argument_instance); } VIPS_ARGUMENT_FOR_ALL_END } } /** * vips__argument_get_instance: (skip) * * Convenience ... given the VipsArgumentClass, get the VipsArgumentInstance. */ VipsArgumentInstance * vips__argument_get_instance(VipsArgumentClass *argument_class, VipsObject *object) { /* Make sure the instance args are built. */ vips_argument_init(object); return (VipsArgumentInstance *) vips__argument_table_lookup(object->argument_table, ((VipsArgument *) argument_class)->pspec); } /** * vips_object_get_argument: (skip) * @object: the object to fetch the args from * @name: arg to fetch * @pspec: (transfer none): the pspec for this arg * @argument_class: (transfer none): the argument_class for this arg * @argument_instance: (transfer none): the argument_instance for this arg * * Look up the three things you need to work with a vips argument. * * Returns: 0 on success, or -1 on error. */ int vips_object_get_argument(VipsObject *object, const char *name, GParamSpec **pspec, VipsArgumentClass **argument_class, VipsArgumentInstance **argument_instance) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); if (!(*pspec = g_object_class_find_property(G_OBJECT_CLASS(class), name))) { vips_error(class->nickname, _("no property named `%s'"), name); return -1; } if (!(*argument_class = (VipsArgumentClass *) vips__argument_table_lookup(class->argument_table, *pspec))) { vips_error(class->nickname, _("no vips argument named `%s'"), name); return -1; } if (!(*argument_instance = vips__argument_get_instance( *argument_class, object))) { vips_error(class->nickname, _("argument `%s' has no instance"), name); return -1; } return 0; } /** * vips_object_argument_isset: * @object: the object to fetch the args from * @name: arg to fetch * * Convenience: has an argument been assigned. Useful for bindings. * * Returns: `TRUE` if the argument has been assigned. */ gboolean vips_object_argument_isset(VipsObject *object, const char *name) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return FALSE; return argument_instance->assigned; } /** * vips_object_get_argument_flags: * @object: the object to fetch the args from * @name: arg to fetch * * Convenience: get the flags for an argument. Useful for bindings. * * Returns: The [flags@ArgumentFlags] for this argument. */ VipsArgumentFlags vips_object_get_argument_flags(VipsObject *object, const char *name) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return 0; return argument_class->flags; } /** * vips_object_get_argument_priority: * @object: the object to fetch the args from * @name: arg to fetch * * Convenience: get the priority for an argument. Useful for bindings. * * Returns: The priority of this argument. */ int vips_object_get_argument_priority(VipsObject *object, const char *name) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return 0; return argument_class->priority; } static void vips_object_clear_member(VipsArgumentInstance *argument_instance) { VipsObject *object = argument_instance->object; VipsArgumentClass *argument_class = argument_instance->argument_class; GObject **member = &G_STRUCT_MEMBER(GObject *, object, argument_class->offset); vips_argument_instance_detach(argument_instance); if (*member) { if (argument_class->flags & VIPS_ARGUMENT_INPUT) { #ifdef DEBUG_REF printf("vips_object_clear_member: vips object: "); vips_object_print_name(object); printf(" no longer refers to gobject %s (%p)\n", G_OBJECT_TYPE_NAME(*member), *member); printf(" count down to %d\n", G_OBJECT(*member)->ref_count - 1); #endif /*DEBUG_REF*/ /* We reffed the object. */ g_object_unref(*member); } else if (argument_class->flags & VIPS_ARGUMENT_OUTPUT) { #ifdef DEBUG_REF printf("vips_object_clear_member: gobject %s (%p)\n", G_OBJECT_TYPE_NAME(*member), *member); printf(" no longer refers to vips object: "); vips_object_print_name(object); printf(" count down to %d\n", G_OBJECT(object)->ref_count - 1); #endif /*DEBUG_REF*/ g_object_unref(object); } *member = NULL; } } /* Free any args which are holding resources. */ static void * vips_object_dispose_argument(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { g_assert(((VipsArgument *) argument_class)->pspec == pspec); g_assert(((VipsArgument *) argument_instance)->pspec == pspec); if (G_IS_PARAM_SPEC_OBJECT(pspec) || G_IS_PARAM_SPEC_BOXED(pspec)) { #ifdef DEBUG printf("vips_object_dispose_argument: "); vips_object_print_name(object); printf(".%s\n", g_param_spec_get_name(pspec)); #endif /*DEBUG*/ g_object_set(object, g_param_spec_get_name(pspec), NULL, NULL); } return NULL; } /* Free all args on this object which may be holding resources. * * Note that this is not the same as vips_object_unref_outputs(). That * looks for output objects which may have been created during _build() which * hold refs to this object and unrefs them. * * This function looks for objects which this object holds refs to and which * may be holding sub-resources and zaps them. */ static void vips_argument_dispose_all(VipsObject *object) { #ifdef DEBUG printf("vips_argument_dispose_all: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ vips_argument_map(object, vips_object_dispose_argument, NULL, NULL); } /* Free any args which are holding memory. */ static void * vips_object_free_argument(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { g_assert(((VipsArgument *) argument_class)->pspec == pspec); g_assert(((VipsArgument *) argument_instance)->pspec == pspec); if (G_IS_PARAM_SPEC_STRING(pspec)) { #ifdef DEBUG printf("vips_object_free_argument: "); vips_object_print_name(object); printf(".%s\n", g_param_spec_get_name(pspec)); #endif /*DEBUG*/ g_object_set(object, g_param_spec_get_name(pspec), NULL, NULL); } return NULL; } /* Free args which hold memory. Things like strings need to be freed right at * the end in case anyone is still using them. */ static void vips_argument_free_all(VipsObject *object) { #ifdef DEBUG printf("vips_argument_free_all: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ vips_argument_map(object, vips_object_free_argument, NULL, NULL); } static void vips_object_dispose(GObject *gobject) { VipsObject *object = VIPS_OBJECT(gobject); #ifdef DEBUG printf("vips_object_dispose: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ /* Our subclasses should have already called this. Run it again, just * in case. */ #ifdef DEBUG if (!object->preclose) printf("vips_object_dispose: pre-close missing!\n"); #endif /*DEBUG*/ vips_object_preclose(object); /* Clear all our arguments: they may be holding resources we should * drop. */ vips_argument_dispose_all(object); vips_object_close(object); vips_object_postclose(object); vips_argument_free_all(object); VIPS_FREEF(vips_argument_table_destroy, object->argument_table); G_OBJECT_CLASS(vips_object_parent_class)->dispose(gobject); } static void vips_object_finalize(GObject *gobject) { VipsObject *object = VIPS_OBJECT(gobject); #ifdef DEBUG printf("vips_object_finalize: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ /* I'd like to have post-close in here, but you can't emit signals * from finalize, sadly. */ g_mutex_lock(&vips__object_all_lock); g_hash_table_remove(vips__object_all, object); g_mutex_unlock(&vips__object_all_lock); G_OBJECT_CLASS(vips_object_parent_class)->finalize(gobject); } static void vips_object_arg_invalidate(GObject *argument, VipsArgumentInstance *argument_instance) { /* Image @argument has signalled "invalidate" ... resignal on our * operation. */ if (VIPS_IS_OPERATION(argument_instance->object)) vips_operation_invalidate(VIPS_OPERATION(argument_instance->object)); } static void vips_object_arg_close(GObject *argument, VipsArgumentInstance *argument_instance) { VipsObject *object = argument_instance->object; GParamSpec *pspec = ((VipsArgument *) argument_instance)->pspec; /* Argument had reffed us ... now it's being closed, so we NULL out * the pointer to unref. */ g_object_set(object, g_param_spec_get_name(pspec), NULL, NULL); } /* Set a member to an object. Handle the ref counts and signal * connect/disconnect. */ void vips__object_set_member(VipsObject *object, GParamSpec *pspec, GObject **member, GObject *argument) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsArgumentClass *argument_class = (VipsArgumentClass *) vips__argument_table_lookup(class->argument_table, pspec); VipsArgumentInstance *argument_instance = vips__argument_get_instance(argument_class, object); GType otype = G_PARAM_SPEC_VALUE_TYPE(pspec); g_assert(argument_instance); vips_object_clear_member(argument_instance); g_assert(!*member); *member = argument; if (*member) { if (argument_class->flags & VIPS_ARGUMENT_INPUT) { #ifdef DEBUG_REF printf("vips__object_set_member: vips object: "); vips_object_print_name(object); printf(" refers to gobject %s (%p)\n", G_OBJECT_TYPE_NAME(*member), *member); printf(" count up to %d\n", G_OBJECT(*member)->ref_count); #endif /*DEBUG_REF*/ /* Ref the argument. */ g_object_ref(*member); } else if (argument_class->flags & VIPS_ARGUMENT_OUTPUT) { #ifdef DEBUG_REF printf("vips__object_set_member: gobject %s (%p)\n", G_OBJECT_TYPE_NAME(*member), *member); printf(" refers to vips object: "); vips_object_print_name(object); printf(" count up to %d\n", G_OBJECT(object)->ref_count); #endif /*DEBUG_REF*/ /* The argument reffs us. */ g_object_ref(object); } } if (*member && g_type_is_a(otype, VIPS_TYPE_IMAGE)) { if (argument_class->flags & VIPS_ARGUMENT_INPUT) { g_assert(!argument_instance->invalidate_id); argument_instance->invalidate_id = g_signal_connect(*member, "invalidate", G_CALLBACK(vips_object_arg_invalidate), argument_instance); } else if (argument_class->flags & VIPS_ARGUMENT_OUTPUT) { g_assert(!argument_instance->close_id); argument_instance->close_id = g_signal_connect(*member, "close", G_CALLBACK(vips_object_arg_close), argument_instance); } } } /* Is a value NULL? We allow multiple sets of NULL so props can be cleared. * The pspec gives the value type, for consistency with the way value types * are detected in set and get. */ gboolean vips_value_is_null(GParamSpec *pspec, const GValue *value) { if (G_IS_PARAM_SPEC_STRING(pspec) && !g_value_get_string(value)) return TRUE; if (G_IS_PARAM_SPEC_OBJECT(pspec) && !g_value_get_object(value)) return TRUE; if (G_IS_PARAM_SPEC_POINTER(pspec) && !g_value_get_pointer(value)) return TRUE; if (G_IS_PARAM_SPEC_BOXED(pspec) && !g_value_get_boxed(value)) return TRUE; return FALSE; } /* Also used by subclasses, so not static. */ void vips_object_set_property(GObject *gobject, guint property_id, const GValue *value, GParamSpec *pspec) { VipsObject *object = VIPS_OBJECT(gobject); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(gobject); VipsArgumentClass *argument_class = (VipsArgumentClass *) vips__argument_table_lookup(class->argument_table, pspec); VipsArgumentInstance *argument_instance = vips__argument_get_instance(argument_class, object); g_assert(argument_instance); #ifdef DEBUG printf("vips_object_set_property: "); vips_object_print_name(object); printf(".%s\n", g_param_spec_get_name(pspec)); /* This can crash horribly with some values, have it as a separate * chunk so we can easily comment it out. */ { char *str_value; str_value = g_strdup_value_contents(value); printf("\t%s\n", str_value); g_free(str_value); } #endif /*DEBUG*/ g_assert(((VipsArgument *) argument_class)->pspec == pspec); g_assert(((VipsArgument *) argument_instance)->pspec == pspec); /* If this is a construct-only argument, we can only set before we've * built. */ if (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT && object->constructed && !vips_value_is_null(pspec, value)) { g_warning("%s: %s can't assign '%s' after construct", G_STRLOC, G_OBJECT_TYPE_NAME(gobject), g_param_spec_get_name(pspec)); return; } /* If this is a set-once argument, check we've not set it before. */ if (argument_class->flags & VIPS_ARGUMENT_SET_ONCE && argument_instance->assigned && !vips_value_is_null(pspec, value)) { g_warning("%s: %s can only assign '%s' once", G_STRLOC, G_OBJECT_TYPE_NAME(gobject), g_param_spec_get_name(pspec)); return; } /* We can't use a switch since some param specs don't have fundamental * types and are hence not compile-time constants, argh. */ if (G_IS_PARAM_SPEC_STRING(pspec)) { char **member = &G_STRUCT_MEMBER(char *, object, argument_class->offset); if (*member) g_free(*member); *member = g_value_dup_string(value); } else if (G_IS_PARAM_SPEC_OBJECT(pspec)) { GObject **member = &G_STRUCT_MEMBER(GObject *, object, argument_class->offset); vips__object_set_member(object, pspec, member, g_value_get_object(value)); } else if (G_IS_PARAM_SPEC_INT(pspec)) { int *member = &G_STRUCT_MEMBER(int, object, argument_class->offset); *member = g_value_get_int(value); } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { guint64 *member = &G_STRUCT_MEMBER(guint64, object, argument_class->offset); *member = g_value_get_uint64(value); } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { gboolean *member = &G_STRUCT_MEMBER(gboolean, object, argument_class->offset); *member = g_value_get_boolean(value); } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { int *member = &G_STRUCT_MEMBER(int, object, argument_class->offset); *member = g_value_get_enum(value); } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { int *member = &G_STRUCT_MEMBER(int, object, argument_class->offset); *member = g_value_get_flags(value); } else if (G_IS_PARAM_SPEC_POINTER(pspec)) { gpointer *member = &G_STRUCT_MEMBER(gpointer, object, argument_class->offset); *member = g_value_get_pointer(value); } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { double *member = &G_STRUCT_MEMBER(double, object, argument_class->offset); *member = g_value_get_double(value); } else if (G_IS_PARAM_SPEC_BOXED(pspec)) { gpointer *member = &G_STRUCT_MEMBER(gpointer, object, argument_class->offset); if (*member) { g_boxed_free(G_PARAM_SPEC_VALUE_TYPE(pspec), *member); *member = NULL; } /* Copy the boxed into our pointer (will use eg. * vips__object_vector_dup()). */ *member = g_value_dup_boxed(value); } else { g_warning("%s: %s.%s unimplemented property type %s", G_STRLOC, G_OBJECT_TYPE_NAME(gobject), g_param_spec_get_name(pspec), g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); } /* Note that it's now been set. */ argument_instance->assigned = TRUE; } /* Also used by subclasses, so not static. */ void vips_object_get_property(GObject *gobject, guint property_id, GValue *value, GParamSpec *pspec) { VipsObject *object = VIPS_OBJECT(gobject); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(gobject); VipsArgumentClass *argument_class = (VipsArgumentClass *) vips__argument_table_lookup(class->argument_table, pspec); VipsArgumentInstance *argument_instance = vips__argument_get_instance(argument_class, object); g_assert(((VipsArgument *) argument_class)->pspec == pspec); if (!argument_instance->assigned) { /* Set the value to the default. Things like Ruby * gobject-introspection will walk objects during GC, and we * can find ourselves fetching object values between init and * build. */ g_param_value_set_default(pspec, value); return; } if (G_IS_PARAM_SPEC_STRING(pspec)) { char *member = G_STRUCT_MEMBER(char *, object, argument_class->offset); g_value_set_string(value, member); } else if (G_IS_PARAM_SPEC_OBJECT(pspec)) { GObject **member = &G_STRUCT_MEMBER(GObject *, object, argument_class->offset); g_value_set_object(value, *member); } else if (G_IS_PARAM_SPEC_INT(pspec)) { int *member = &G_STRUCT_MEMBER(int, object, argument_class->offset); g_value_set_int(value, *member); } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { guint64 *member = &G_STRUCT_MEMBER(guint64, object, argument_class->offset); g_value_set_uint64(value, *member); } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { gboolean *member = &G_STRUCT_MEMBER(gboolean, object, argument_class->offset); g_value_set_boolean(value, *member); } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { int *member = &G_STRUCT_MEMBER(int, object, argument_class->offset); g_value_set_enum(value, *member); } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { int *member = &G_STRUCT_MEMBER(int, object, argument_class->offset); g_value_set_flags(value, *member); } else if (G_IS_PARAM_SPEC_POINTER(pspec)) { gpointer *member = &G_STRUCT_MEMBER(gpointer, object, argument_class->offset); g_value_set_pointer(value, *member); } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { double *member = &G_STRUCT_MEMBER(double, object, argument_class->offset); g_value_set_double(value, *member); } else if (G_IS_PARAM_SPEC_BOXED(pspec)) { gpointer *member = &G_STRUCT_MEMBER(gpointer, object, argument_class->offset); /* Copy the boxed into our pointer (will use eg. * vips__object_vector_dup()). */ g_value_set_boxed(value, *member); } else { g_warning("%s: %s.%s unimplemented property type %s", G_STRLOC, G_OBJECT_TYPE_NAME(gobject), g_param_spec_get_name(pspec), g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); } } static int vips_object_real_build(VipsObject *object) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); /* Only test input args, output ones can be set by our subclasses as * they build. See vips_object_build() above. */ VipsArgumentFlags iomask = VIPS_ARGUMENT_INPUT; int result; #ifdef DEBUG printf("vips_object_real_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_assert(!object->constructed); /* It'd be nice if this just copied a pointer rather than did a * strdup(). Set these here rather than in object_init, so that the * class gets a chance to set them. */ g_object_set(object, "nickname", object_class->nickname, "description", object_class->description, NULL); /* Check all required input arguments have been supplied, don't stop * on 1st error. */ result = 0; (void) vips_argument_map(object, vips_object_check_required, &result, &iomask); if (!vips_object_sanity(object)) return -1; return result; } static int vips_object_real_postbuild(VipsObject *object, void *data) { #ifdef DEBUG printf("vips_object_real_postbuild: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_assert(object->constructed); return 0; } static void vips_object_real_summary_class(VipsObjectClass *class, VipsBuf *buf) { vips_buf_appendf(buf, "%s", G_OBJECT_CLASS_NAME(class)); if (class->nickname) vips_buf_appendf(buf, " (%s)", class->nickname); if (class->description) vips_buf_appendf(buf, ", %s", class->description); } static void vips_object_real_summary(VipsObject *object, VipsBuf *buf) { } static void vips_object_real_dump(VipsObject *object, VipsBuf *buf) { vips_buf_appendf(buf, " %s (%p) count=%d", G_OBJECT_TYPE_NAME(object), object, G_OBJECT(object)->ref_count); if (object->local_memory) vips_buf_appendf(buf, " %zd bytes", object->local_memory); } static void vips_object_real_sanity(VipsObject *object, VipsBuf *buf) { } static void vips_object_real_rewind(VipsObject *object) { #ifdef DEBUG printf("vips_object_real_rewind\n"); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_object_run_dispose(G_OBJECT(object)); object->constructed = FALSE; object->preclose = FALSE; object->close = FALSE; object->postclose = FALSE; } static VipsObject * vips_object_real_new_from_string(const char *string) { GType type; vips_check_init(); /* The main arg selects the subclass. */ if (!(type = vips_type_find(NULL, string))) { vips_error("VipsObject", _("class \"%s\" not found"), string); return NULL; } return VIPS_OBJECT(g_object_new(type, NULL)); } static void vips_object_real_to_string(VipsObject *object, VipsBuf *buf) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); /* Just "bicubic" or whatever. */ vips_buf_appends(buf, class->nickname); } static void transform_string_double(const GValue *src_value, GValue *dest_value) { g_value_set_double(dest_value, g_ascii_strtod(g_value_get_string(src_value), NULL)); } static void vips_object_class_init(VipsObjectClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); /* We must have threads set up before we can process. */ vips_check_init(); if (!vips__object_all) vips__object_all = g_hash_table_new(g_direct_hash, g_direct_equal); gobject_class->dispose = vips_object_dispose; gobject_class->finalize = vips_object_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; class->build = vips_object_real_build; class->postbuild = vips_object_real_postbuild; class->summary_class = vips_object_real_summary_class; class->summary = vips_object_real_summary; class->dump = vips_object_real_dump; class->sanity = vips_object_real_sanity; class->rewind = vips_object_real_rewind; class->new_from_string = vips_object_real_new_from_string; class->to_string = vips_object_real_to_string; class->nickname = "object"; class->description = _("base class"); /* Table of VipsArgumentClass ... we can just g_free() them. */ class->argument_table = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free); class->argument_table_traverse = NULL; /* For setting double arguments from the command-line. */ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_DOUBLE, transform_string_double); VIPS_ARG_STRING(class, "nickname", 1, _("Nickname"), _("Class nickname"), VIPS_ARGUMENT_SET_ONCE, G_STRUCT_OFFSET(VipsObject, nickname), ""); VIPS_ARG_STRING(class, "description", 2, _("Description"), _("Class description"), VIPS_ARGUMENT_SET_ONCE, G_STRUCT_OFFSET(VipsObject, description), ""); /** * VipsObject::postbuild: * @object: the object that has been built * * The ::postbuild signal is emitted once just after successful object * construction. Return non-zero to cause object construction to fail. */ vips_object_signals[SIG_POSTBUILD] = g_signal_new("postbuild", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsObjectClass, postbuild), NULL, NULL, vips_INT__VOID, G_TYPE_INT, 0); /** * VipsObject::preclose: * @object: the object that is to close * * The ::preclose signal is emitted once just before object close * starts. The object is still alive. */ vips_object_signals[SIG_PRECLOSE] = g_signal_new("preclose", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsObjectClass, preclose), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VipsObject::close: * @object: the object that is closing * * The ::close signal is emitted once during object close. The object * is dying and may not work. */ vips_object_signals[SIG_CLOSE] = g_signal_new("close", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsObjectClass, close), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * VipsObject::postclose: * @object: the object that has closed * * The ::postclose signal is emitted once after object close. The * object pointer is still valid, but nothing else. */ vips_object_signals[SIG_POSTCLOSE] = g_signal_new("postclose", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsObjectClass, postclose), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void vips_object_init(VipsObject *object) { #ifdef DEBUG printf("vips_object_init: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_mutex_lock(&vips__object_all_lock); g_hash_table_insert(vips__object_all, object, object); g_mutex_unlock(&vips__object_all_lock); } static void * traverse_find_required_priority(void *data, void *a, void *b) { VipsArgumentClass *argument_class = (VipsArgumentClass *) data; int priority = GPOINTER_TO_INT(a); if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) && !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) && argument_class->priority == priority) return argument_class; return NULL; } static int traverse_sort(VipsArgumentClass *class1, VipsArgumentClass *class2, void *user_data) { return class1->priority - class2->priority; } /* Add a vipsargument ... automate some stuff with this. */ void vips_object_class_install_argument(VipsObjectClass *object_class, GParamSpec *pspec, VipsArgumentFlags flags, int priority, guint offset) { VipsArgumentClass *argument_class = g_new(VipsArgumentClass, 1); GSList *argument_table_traverse; VipsArgumentClass *ac; #ifdef DEBUG printf("vips_object_class_install_argument: %p %s %s\n", object_class, g_type_name(G_TYPE_FROM_CLASS(object_class)), g_param_spec_get_name(pspec)); #endif /*DEBUG*/ /* object_class->argument* is shared, so we must lock. */ g_mutex_lock(&vips__global_lock); /* Must be a new one. */ g_assert(!g_hash_table_lookup(object_class->argument_table, pspec)); /* Mustn't have INPUT and OUTPUT both set. */ g_assert(!( (flags & VIPS_ARGUMENT_INPUT) && (flags & VIPS_ARGUMENT_OUTPUT))); ((VipsArgument *) argument_class)->pspec = pspec; argument_class->object_class = object_class; argument_class->flags = flags; argument_class->priority = priority; argument_class->offset = offset; vips_argument_table_replace(object_class->argument_table, (VipsArgument *) argument_class); /* If this is the first argument for a new subclass, we need to clone * the traverse list we inherit. */ if (object_class->argument_table_traverse_gtype != G_TYPE_FROM_CLASS(object_class)) { #ifdef DEBUG printf("vips_object_class_install_argument: cloning traverse\n"); #endif /*DEBUG*/ object_class->argument_table_traverse = g_slist_copy(object_class->argument_table_traverse); object_class->argument_table_traverse_gtype = G_TYPE_FROM_CLASS(object_class); } /* We read argument_table_traverse without a lock (eg. see * vips_argument_map()), so we must be very careful updating it. */ argument_table_traverse = g_slist_copy(object_class->argument_table_traverse); /* We keep traverse sorted by priority, so we mustn't have duplicate * priority values in required args. */ if ((flags & VIPS_ARGUMENT_REQUIRED) && !(flags & VIPS_ARGUMENT_DEPRECATED) && (ac = vips_slist_map2(argument_table_traverse, traverse_find_required_priority, GINT_TO_POINTER(priority), NULL))) g_warning("vips_object_class_install_argument: " "%s.%s, %s.%s duplicate priority", g_type_name(G_TYPE_FROM_CLASS(object_class)), g_param_spec_get_name(pspec), g_type_name(G_TYPE_FROM_CLASS(ac->object_class)), g_param_spec_get_name(((VipsArgument *) ac)->pspec)); /* Warn about optional boolean args which default TRUE. These won't * work from the CLI, since simple GOption switches don't allow * `=false`. */ if (!(flags & VIPS_ARGUMENT_REQUIRED) && !(flags & VIPS_ARGUMENT_DEPRECATED) && G_IS_PARAM_SPEC_BOOLEAN(pspec) && G_PARAM_SPEC_BOOLEAN(pspec)->default_value) g_warning("vips_object_class_install_argument: " "default TRUE BOOL arg %s.%s", g_type_name(G_TYPE_FROM_CLASS(object_class)), g_param_spec_get_name(pspec)); argument_table_traverse = g_slist_prepend( argument_table_traverse, argument_class); argument_table_traverse = g_slist_sort( argument_table_traverse, (GCompareFunc) traverse_sort); VIPS_SWAP(GSList *, argument_table_traverse, object_class->argument_table_traverse); g_slist_free(argument_table_traverse); #ifdef DEBUG { GSList *p; printf("%d items on traverse %p\n", g_slist_length(object_class->argument_table_traverse), &object_class->argument_table_traverse); for (p = object_class->argument_table_traverse; p; p = p->next) { VipsArgumentClass *argument_class = (VipsArgumentClass *) p->data; printf("\t%p %s\n", argument_class, g_param_spec_get_name( ((VipsArgument *) argument_class)->pspec)); } } #endif /*DEBUG*/ g_mutex_unlock(&vips__global_lock); } static void vips_object_no_value(VipsObject *object, const char *name) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) g_assert_not_reached(); if (strcmp(name, g_param_spec_get_name(pspec)) == 0) vips_error(class->nickname, _("no value supplied for argument '%s'"), name); else vips_error(class->nickname, _("no value supplied for argument '%s' ('%s')"), name, g_param_spec_get_name(pspec)); } /* Set a named arg from a string. */ int vips_object_set_argument_from_string(VipsObject *object, const char *name, const char *value) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; VipsObjectClass *oclass; GType otype; GValue gvalue = G_VALUE_INIT; VIPS_DEBUG_MSG("vips_object_set_argument_from_string: %s = %s\n", name, value); if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return -1; otype = G_PARAM_SPEC_VALUE_TYPE(pspec); g_assert(argument_class->flags & VIPS_ARGUMENT_INPUT); if (g_type_is_a(otype, VIPS_TYPE_IMAGE)) { VipsImage *out; VipsOperationFlags flags; VipsAccess access; char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; flags = 0; if (VIPS_IS_OPERATION(object)) flags = vips_operation_get_flags(VIPS_OPERATION(object)); if (flags & (VIPS_OPERATION_SEQUENTIAL_UNBUFFERED | VIPS_OPERATION_SEQUENTIAL)) access = VIPS_ACCESS_SEQUENTIAL; else access = VIPS_ACCESS_RANDOM; if (!value) { vips_object_no_value(object, name); return -1; } vips__filename_split8(value, filename, option_string); if (strcmp("stdin", filename) == 0) { VipsSource *source; if (!(source = vips_source_new_from_descriptor(0))) return -1; if (!(out = vips_image_new_from_source(source, option_string, "access", access, NULL))) { VIPS_UNREF(source); return -1; } VIPS_UNREF(source); } else { if (!(out = vips_image_new_from_file(value, "access", access, NULL))) return -1; } g_value_init(&gvalue, VIPS_TYPE_IMAGE); g_value_set_object(&gvalue, out); /* Setting gvalue will have upped @out's count again, * go back to 1 so that gvalue has the only ref. */ g_object_unref(out); } else if (g_type_is_a(otype, VIPS_TYPE_SOURCE)) { VipsSource *source; if (!value) { vips_object_no_value(object, name); return -1; } if (!(source = vips_source_new_from_options(value))) return -1; g_value_init(&gvalue, VIPS_TYPE_SOURCE); g_value_set_object(&gvalue, source); /* Setting gvalue will have upped @out's count again, * go back to 1 so that gvalue has the only ref. */ g_object_unref(source); } else if (g_type_is_a(otype, VIPS_TYPE_ARRAY_IMAGE)) { /* We have to have a special case for this, we can't just rely * on transform_g_string_array_image(), since we need to be * able to set the access hint on the image. */ VipsArrayImage *array_image; VipsOperationFlags flags; VipsAccess access; if (!value) { vips_object_no_value(object, name); return -1; } flags = 0; if (VIPS_IS_OPERATION(object)) flags = vips_operation_get_flags( VIPS_OPERATION(object)); if (flags & (VIPS_OPERATION_SEQUENTIAL_UNBUFFERED | VIPS_OPERATION_SEQUENTIAL)) access = VIPS_ACCESS_SEQUENTIAL; else access = VIPS_ACCESS_RANDOM; if (!(array_image = vips_array_image_new_from_string(value, access))) return -1; g_value_init(&gvalue, VIPS_TYPE_ARRAY_IMAGE); g_value_set_boxed(&gvalue, array_image); /* Setting gvalue will have upped @array_image's count again, * go back to 1 so that gvalue has the only ref. */ vips_area_unref(VIPS_AREA(array_image)); } else if (g_type_is_a(otype, VIPS_TYPE_OBJECT) && (oclass = g_type_class_ref(otype))) { VipsObject *new_object; if (!value) { vips_object_no_value(object, name); return -1; } if (!(new_object = vips_object_new_from_string(oclass, value))) return -1; /* Not necessarily a VipsOperation subclass so we don't use * the cache. We could have a separate case for this. */ if (vips_object_build(new_object)) { g_object_unref(new_object); return -1; } g_value_init(&gvalue, G_TYPE_OBJECT); g_value_set_object(&gvalue, new_object); /* The GValue now has a ref, we can drop ours. */ g_object_unref(new_object); } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { gboolean b; b = TRUE; if (value && (g_ascii_strcasecmp(value, "false") == 0 || g_ascii_strcasecmp(value, "no") == 0 || strcmp(value, "0") == 0)) b = FALSE; g_value_init(&gvalue, G_TYPE_BOOLEAN); g_value_set_boolean(&gvalue, b); } else if (G_IS_PARAM_SPEC_INT(pspec)) { int i; if (!value) { vips_object_no_value(object, name); return -1; } if (sscanf(value, "%d", &i) != 1) { vips_error(class->nickname, _("'%s' is not an integer"), value); return -1; } g_value_init(&gvalue, G_TYPE_INT); g_value_set_int(&gvalue, i); } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { /* Not always the same as guint64 :-( argh. */ long long l; if (!value) { vips_object_no_value(object, name); return -1; } if (sscanf(value, "%lld", &l) != 1) { vips_error(class->nickname, _("'%s' is not an integer"), value); return -1; } g_value_init(&gvalue, G_TYPE_UINT64); g_value_set_uint64(&gvalue, l); } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { double d; if (!value) { vips_object_no_value(object, name); return -1; } if (vips_strtod(value, &d)) return -1; g_value_init(&gvalue, G_TYPE_DOUBLE); g_value_set_double(&gvalue, d); } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { int i; if (!value) { vips_object_no_value(object, name); return -1; } if ((i = vips_enum_from_nick(class->nickname, otype, value)) < 0) return -1; g_value_init(&gvalue, otype); g_value_set_enum(&gvalue, i); } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { int i; if (!value) { vips_object_no_value(object, name); return -1; } if ((i = vips_flags_from_nick(class->nickname, otype, value)) < 0) return -1; g_value_init(&gvalue, otype); g_value_set_flags(&gvalue, i); } else { if (!value) { vips_object_no_value(object, name); return -1; } g_value_init(&gvalue, G_TYPE_STRING); g_value_set_string(&gvalue, value); } g_object_set_property(G_OBJECT(object), name, &gvalue); g_value_unset(&gvalue); return 0; } /* Does an vipsargument need an argument to write to? For example, an image * output needs a filename, a double output just prints. */ gboolean vips_object_argument_needsstring(VipsObject *object, const char *name) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; #ifdef DEBUG printf("vips_object_argument_needsstring: %s\n", name); #endif /*DEBUG*/ if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return -1; return vips_argument_class_needsstring(argument_class); } static void vips_object_print_arg(VipsObject *object, GParamSpec *pspec, VipsBuf *buf) { GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); const char *name = g_param_spec_get_name(pspec); GValue value = G_VALUE_INIT; char *str_value; g_value_init(&value, type); g_object_get_property(G_OBJECT(object), name, &value); str_value = g_strdup_value_contents(&value); vips_buf_appends(buf, str_value); g_free(str_value); g_value_unset(&value); } /* Is a filename a target, ie. it is of the form ".jpg". Any trailing options * have already been stripped. Watch out for cases like "./x.jpg". */ static gboolean vips_filename_istarget(const char *filename) { const char *p; return (p = strrchr(filename, '.')) && p == filename; } /* Write a named arg to the string. If the arg does not need a string (see * above), arg will be NULL. */ int vips_object_get_argument_to_string(VipsObject *object, const char *name, const char *arg) { GParamSpec *pspec; GType otype; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; VipsObjectClass *oclass; #ifdef DEBUG printf("vips_object_get_argument_to_string: %s -> %s\n", name, arg); #endif /*DEBUG*/ if (vips_object_get_argument(object, name, &pspec, &argument_class, &argument_instance)) return -1; otype = G_PARAM_SPEC_VALUE_TYPE(pspec); g_assert(argument_class->flags & VIPS_ARGUMENT_OUTPUT); if (g_type_is_a(otype, VIPS_TYPE_IMAGE)) { VipsImage *in; char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; vips__filename_split8(arg, filename, option_string); if (vips_filename_istarget(filename)) { VipsTarget *target; if (!(target = vips_target_new_to_descriptor(1))) return -1; g_object_get(object, name, &in, NULL); if (vips_image_write_to_target(in, arg, target, NULL)) { VIPS_UNREF(in); VIPS_UNREF(target); return -1; } VIPS_UNREF(in); VIPS_UNREF(target); } else { /* Pull out the image and write it. */ g_object_get(object, name, &in, NULL); if (vips_image_write_to_file(in, arg, NULL)) { VIPS_UNREF(in); return -1; } VIPS_UNREF(in); } } else if (g_type_is_a(otype, VIPS_TYPE_OBJECT) && (oclass = g_type_class_ref(otype)) && oclass->output_to_arg) { VipsObject *value; g_object_get(object, name, &value, NULL); if (oclass->output_to_arg(value, arg)) { g_object_unref(value); return -1; } g_object_unref(value); } else { char str[1000]; VipsBuf buf = VIPS_BUF_STATIC(str); vips_object_print_arg(object, pspec, &buf); printf("%s\n", vips_buf_all(&buf)); } return 0; } static void * vips_argument_is_required(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && !argument_instance->assigned) return pspec; return NULL; } /* Find the first unassigned required input arg. */ static GParamSpec * vips_object_find_required(VipsObject *object) { return (GParamSpec *) vips_argument_map(object, vips_argument_is_required, NULL, NULL); } typedef struct _VipsNameFlagsPair { const char **names; int *flags; } VipsNameFlagsPair; static void * vips_object_find_args(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsNameFlagsPair *pair = (VipsNameFlagsPair *) a; int *i = (int *) b; pair->names[*i] = g_param_spec_get_name(pspec); pair->flags[*i] = (int) argument_class->flags; *i += 1; return NULL; } /** * vips_object_get_args: (skip) * @object: object whose args should be retrieved * @names: (transfer none) (array length=n_args) (allow-none): output array of [class@GObject.ParamSpec] names * @flags: (transfer none) (array length=n_args) (allow-none): output array of [flags@ArgumentFlags] * @n_args: (allow-none): length of output arrays * * Get all [class@GObject.ParamSpec] names and [flags@ArgumentFlags] for an object. * * This is handy for language bindings. From C, it's usually more convenient to * use [func@Argument.map]. * * Returns: 0 on success, -1 on error */ int vips_object_get_args(VipsObject *object, const char ***names, int **flags, int *n_args) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); int n = g_slist_length(object_class->argument_table_traverse); VipsNameFlagsPair pair; int i; pair.names = VIPS_ARRAY(object, n, const char *); pair.flags = VIPS_ARRAY(object, n, int); if (!pair.names || !pair.flags) return -1; i = 0; (void) vips_argument_map(object, vips_object_find_args, &pair, &i); if (names) *names = pair.names; if (flags) *flags = pair.flags; if (n_args) *n_args = n; return 0; } /** * vips_object_new: (skip) * @type: object to create * @set: set arguments with this * @a: client data * @b: client data * * [ctor@GObject.Object.new] the object, set any arguments with @set, call * [method@Object.build] and return the complete object. * * Returns: the new object */ VipsObject * vips_object_new(GType type, VipsObjectSetArguments set, void *a, void *b) { VipsObject *object; vips_check_init(); object = VIPS_OBJECT(g_object_new(type, NULL)); if (set && set(object, a, b)) { g_object_unref(object); return NULL; } if (vips_object_build(object)) { g_object_unref(object); return NULL; } return object; } /** * vips_object_set_valist: * @object: object to set arguments on * @ap: `NULL`-terminated list of argument/value pairs * * See [method@Object.set]. * * Returns: 0 on success, -1 on error */ int vips_object_set_valist(VipsObject *object, va_list ap) { char *name; VIPS_DEBUG_MSG("vips_object_set_valist:\n"); for (name = va_arg(ap, char *); name; name = va_arg(ap, char *)) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; VIPS_DEBUG_MSG("\tname = '%s' (%p)\n", name, name); if (vips_object_get_argument(VIPS_OBJECT(object), name, &pspec, &argument_class, &argument_instance)) return -1; VIPS_ARGUMENT_COLLECT_SET(pspec, argument_class, ap); g_object_set_property(G_OBJECT(object), name, &value); VIPS_ARGUMENT_COLLECT_GET(pspec, argument_class, ap); VIPS_ARGUMENT_COLLECT_END } return 0; } /** * vips_object_set: * @object: object to set arguments on * @...: `NULL`-terminated list of argument/value pairs * * Set a list of vips object arguments. For example: * * ```c * vips_object_set(operation, * "input", in, * "output", &out, * NULL); * ``` * * Input arguments are given in-line, output arguments are given as pointers * to where the output value should be written. * * ::: seealso * [method@Object.set_valist], [method@Object.set_from_string]. * * Returns: 0 on success, -1 on error */ int vips_object_set(VipsObject *object, ...) { va_list ap; int result; va_start(ap, object); result = vips_object_set_valist(object, ap); va_end(ap); return result; } /* Set object args from a string. @p should be the initial left bracket and * there should be no tokens after the matching right bracket. @p is modified. */ static int vips_object_set_args(VipsObject *object, const char *p) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsToken token; char string[VIPS_PATH_MAX]; char string2[VIPS_PATH_MAX]; GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if (!(p = vips__token_need(p, VIPS_TOKEN_LEFT, string, VIPS_PATH_MAX))) return -1; if (!(p = vips__token_segment(p, &token, string, VIPS_PATH_MAX))) return -1; for (;;) { if (token == VIPS_TOKEN_RIGHT) break; if (token != VIPS_TOKEN_STRING) { vips_error(class->nickname, _("expected string or ), saw %s"), vips_enum_nick(VIPS_TYPE_TOKEN, token)); return -1; } /* We have to look for a '=', ']' or a ',' to see if string is * a param name or a value. */ if (!(p = vips__token_segment(p, &token, string2, VIPS_PATH_MAX))) return -1; if (token == VIPS_TOKEN_EQUALS) { if (!(p = vips__token_segment_need(p, VIPS_TOKEN_STRING, string2, VIPS_PATH_MAX))) return -1; if (vips_object_set_argument_from_string(object, string, string2)) return -1; if (!(p = vips__token_must(p, &token, string2, VIPS_PATH_MAX))) return -1; } else if (g_object_class_find_property( G_OBJECT_GET_CLASS(object), string) && !vips_object_get_argument(object, string, &pspec, &argument_class, &argument_instance) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && G_IS_PARAM_SPEC_BOOLEAN(pspec)) { /* The string is the name of an optional * input boolean ... set it! */ if (!argument_instance->assigned) g_object_set(object, string, TRUE, NULL); } else if ((pspec = vips_object_find_required(object))) { if (vips_object_set_argument_from_string(object, g_param_spec_get_name(pspec), string)) return -1; } else { vips_error(class->nickname, _("unable to set '%s'"), string); return -1; } /* Now must be a , or a ). */ if (token == VIPS_TOKEN_COMMA) { if (!(p = vips__token_must(p, &token, string, VIPS_PATH_MAX))) return -1; } else if (token != VIPS_TOKEN_RIGHT) { vips_error(class->nickname, "%s", _("not , or ) after parameter")); return -1; } } if ((p = vips__token_get(p, &token, string, VIPS_PATH_MAX))) { vips_error(class->nickname, "%s", _("extra tokens after ')'")); return -1; } return 0; } /** * vips_object_set_from_string: * @object: object to set arguments on * @string: arguments as a string * * Set object arguments from a string. The string can be something like * "a=12", or "a = 12, b = 13", or "fred". The string can optionally be * enclosed in brackets. * * You'd typically use this between creating the object and building it. * * ::: seealso * [method@Object.set], [method@Object.build], * [func@cache_operation_buildp]. * * Returns: 0 on success, -1 on error */ int vips_object_set_from_string(VipsObject *object, const char *string) { const char *q; VipsToken token; char buffer[VIPS_PATH_MAX]; char str[VIPS_PATH_MAX]; g_strlcpy(buffer, string, VIPS_PATH_MAX); /* Does string start with a bracket? If it doesn't, enclose the whole * thing in []. */ if (!(q = vips__token_get(buffer, &token, str, VIPS_PATH_MAX)) || token != VIPS_TOKEN_LEFT) g_snprintf(buffer, VIPS_PATH_MAX, "[%s]", string); else g_strlcpy(buffer, string, VIPS_PATH_MAX); return vips_object_set_args(object, buffer); } VipsObject * vips_object_new_from_string(VipsObjectClass *object_class, const char *p) { const char *q; char str[VIPS_PATH_MAX]; VipsObject *object; g_assert(object_class); g_assert(object_class->new_from_string); /* Find the start of the optional args on the end of the string, take * everything before that as the principal arg for the constructor. */ if ((q = vips__find_rightmost_brackets(p))) g_strlcpy(str, p, VIPS_MIN(VIPS_PATH_MAX, q - p + 1)); else g_strlcpy(str, p, VIPS_PATH_MAX); if (!(object = object_class->new_from_string(str))) return NULL; /* More tokens there? Set any other args. */ if (q && vips_object_set_from_string(object, q)) { g_object_unref(object); return NULL; } return object; } static void * vips_object_to_string_required(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsBuf *buf = (VipsBuf *) a; gboolean *first = (gboolean *) b; if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED)) { if (*first) { vips_buf_appends(buf, "("); *first = FALSE; } else { vips_buf_appends(buf, ","); } vips_object_print_arg(object, pspec, buf); } return NULL; } static void * vips_object_to_string_optional(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsBuf *buf = (VipsBuf *) a; gboolean *first = (gboolean *) b; if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED) && argument_instance->assigned) { if (*first) { vips_buf_appends(buf, "("); *first = FALSE; } else { vips_buf_appends(buf, ","); } vips_buf_appends(buf, g_param_spec_get_name(pspec)); vips_buf_appends(buf, "="); vips_object_print_arg(object, pspec, buf); } return NULL; } /** * vips_object_to_string: * @object: object to stringify * @buf: write string here * * The inverse of [ctor@Object.new_from_string]: turn @object into eg. * `"VipsInterpolateSnohalo1(blur=.333333)"`. */ void vips_object_to_string(VipsObject *object, VipsBuf *buf) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); gboolean first; g_assert(object_class->to_string); /* Nicknames are not guaranteed to be unique, so use the full type * name. */ object_class->to_string(object, buf); first = TRUE; (void) vips_argument_map(object, vips_object_to_string_required, buf, &first); (void) vips_argument_map(object, vips_object_to_string_optional, buf, &first); if (!first) vips_buf_appends(buf, ")"); } typedef struct { VipsSListMap2Fn fn; void *a; void *b; void *result; } VipsObjectMapArgs; static void vips_object_map_sub(VipsObject *key, VipsObject *value, VipsObjectMapArgs *args) { if (!args->result) args->result = args->fn(key, args->a, args->b); } /** * vips_object_map: (skip) * @fn: function to call for all objects * @a: client data * @b: client data * * Call a function for all alive objects. * Stop when @fn returns non-`NULL` and return that value. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_object_map(VipsSListMap2Fn fn, void *a, void *b) { VipsObjectMapArgs args; args.fn = fn; args.a = a; args.b = b; args.result = NULL; /* We must test vips__object_all before we lock because the lock is * only created when the first object is created. */ if (vips__object_all) { g_mutex_lock(&vips__object_all_lock); g_hash_table_foreach(vips__object_all, (GHFunc) vips_object_map_sub, &args); g_mutex_unlock(&vips__object_all_lock); } return args.result; } /** * vips_type_map: (skip) * @base: base type * @fn: call this function for every type * @a: client data * @b: client data * * Map over a type's children. Stop when @fn returns non-`NULL` * and return that value. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_type_map(GType base, VipsTypeMap2Fn fn, void *a, void *b) { GType *child; guint n_children; unsigned int i; void *result; child = g_type_children(base, &n_children); result = NULL; for (i = 0; i < n_children && !result; i++) result = fn(child[i], a, b); g_free(child); return result; } /** * vips_type_map_all: (skip) * @base: base type * @fn: call this function for every type * @a: client data * * Map over a type's children, direct and indirect. Stop when @fn returns * non-`NULL` and return that value. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_type_map_all(GType base, VipsTypeMapFn fn, void *a) { void *result; if (!(result = fn(base, a))) result = vips_type_map(base, (VipsTypeMap2Fn) vips_type_map_all, fn, a); return result; } /** * vips_class_map_all: (skip) * @type: base type * @fn: call this function for every type * @a: client data * * Loop over all the subclasses of @type. Non-abstract classes only. * Stop when @fn returns * non-`NULL` and return that value. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_class_map_all(GType type, VipsClassMapFn fn, void *a) { void *result; /* Avoid abstract classes. Use type_map_all for them. */ if (!G_TYPE_IS_ABSTRACT(type)) { /* We never unref this ref, but we never unload classes * anyway, so so what. */ if ((result = fn( VIPS_OBJECT_CLASS(g_type_class_ref(type)), a))) return result; } if ((result = vips_type_map(type, (VipsTypeMap2Fn) vips_class_map_all, fn, a))) return result; return NULL; } /* How deeply nested is a class ... used to indent class lists. */ int vips_type_depth(GType type) { int depth; depth = 0; while (type != VIPS_TYPE_OBJECT && (type = g_type_parent(type))) depth += 1; return depth; } static void * test_name(VipsObjectClass *class, const char *nickname) { if (g_ascii_strcasecmp(class->nickname, nickname) == 0) return class; /* Check the class name too, why not. */ if (g_ascii_strcasecmp(G_OBJECT_CLASS_NAME(class), nickname) == 0) return class; return NULL; } /** * vips_class_find: * @basename: name of base class * @nickname: search for a class with this nickname * * Search below @basename, return the first class whose name or @nickname * matches. * * ::: seealso * [func@type_find] * * Returns: (transfer none): the found class. */ const VipsObjectClass * vips_class_find(const char *basename, const char *nickname) { const char *classname = basename ? basename : "VipsObject"; VipsObjectClass *class; GType base; if (!(base = g_type_from_name(classname))) return NULL; class = vips_class_map_all(base, (VipsClassMapFn) test_name, (void *) nickname); return class; } /* What we store for each nickname. We can't just store the type with * GINT_TO_POINTER() since GType is 64 bits on some platforms. */ typedef struct _NicknameGType { const char *nickname; GType type; gboolean duplicate; } NicknameGType; static void * vips_class_add_hash(VipsObjectClass *class, GHashTable *table) { GType type = G_OBJECT_CLASS_TYPE(class); NicknameGType *hit; hit = (NicknameGType *) g_hash_table_lookup(table, (void *) class->nickname); /* If this is not a unique name, mark as a duplicate. In this case * we'll need to fall back to a search. */ if (hit) hit->duplicate = TRUE; else { hit = g_new(NicknameGType, 1); hit->nickname = class->nickname; hit->type = type; hit->duplicate = FALSE; g_hash_table_insert(table, (void *) hit->nickname, hit); } return NULL; } static void * vips_class_build_hash_cb(void *dummy) { GType base; vips__object_nickname_table = g_hash_table_new(g_str_hash, g_str_equal); base = g_type_from_name("VipsObject"); g_assert(base); vips_class_map_all(base, (VipsClassMapFn) vips_class_add_hash, (void *) vips__object_nickname_table); return NULL; } /** * vips_type_find: * @basename: name of base class * @nickname: search for a class with this nickname * * Search below @basename, return the [alias@GObject.Type] of the class * whose name or @nickname matches, or 0 for not found. * If @basename is `NULL`, the whole of [class@Object] is searched. * * This function uses a cache, so it should be quick. * * ::: seealso * [func@class_find] * * Returns: the [alias@GObject.Type] of the class, or 0 if the class is not found. */ GType vips_type_find(const char *basename, const char *nickname) { static GOnce once = G_ONCE_INIT; const char *classname = basename ? basename : "VipsObject"; NicknameGType *hit; GType base; GType type; VIPS_ONCE(&once, vips_class_build_hash_cb, NULL); hit = (NicknameGType *) g_hash_table_lookup(vips__object_nickname_table, (void *) nickname); /* We must only search below basename ... check that the cache hit is * in the right part of the tree. */ if (!(base = g_type_from_name(classname))) return 0; if (hit && !hit->duplicate && g_type_is_a(hit->type, base)) type = hit->type; else { const VipsObjectClass *class; if (!(class = vips_class_find(basename, nickname))) return 0; type = G_OBJECT_CLASS_TYPE(class); } return type; } /** * vips_nickname_find: * @type: [alias@GObject.Type] to search for * * Return the VIPS nickname for a [alias@GObject.Type]. Handy for language bindings. * * Returns: (transfer none): the class nickname. */ const char * vips_nickname_find(GType type) { gpointer p; VipsObjectClass *class; if (type && (p = g_type_class_ref(type)) && VIPS_IS_OBJECT_CLASS(p) && (class = VIPS_OBJECT_CLASS(p))) return class->nickname; return NULL; } /* The vips_object_local_array() macro uses this as its callback. */ void vips_object_local_cb(VipsObject *vobject, GObject *gobject) { VIPS_FREEF(g_object_unref, gobject); } typedef struct { VipsObject **array; int n; } VipsObjectLocal; static void vips_object_local_array_cb(VipsObject *parent, VipsObjectLocal *local) { int i; for (i = 0; i < local->n; i++) VIPS_FREEF(g_object_unref, local->array[i]); VIPS_FREEF(g_free, local->array); VIPS_FREEF(g_free, local); } /** * vips_object_local_array: (skip) * @parent: objects unref when this object unrefs * @n: array size * * Make an array of `NULL` [class@Object] pointers. When @parent closes, every * non-`NULL` pointer in the array will be unreffed and the array will be * freed. Handy for creating a set of temporary images for a function. * * The array is `NULL`-terminated, ie. contains an extra `NULL` element at the * end. * * Example: * * ```c * VipsObject **t; * * t = vips_object_local_array(parent, 5); * if (vips_add(a, b, &t[0], NULL) || * vips_invert(t[0], &t[1], NULL) || * vips_add(t[1], t[0], &t[2], NULL) || * vips_costra(t[2], out, NULL)) * return -1; * ``` * * Returns: an array of `NULL` pointers of length @n */ VipsObject ** vips_object_local_array(VipsObject *parent, int n) { VipsObjectLocal *local; local = g_new(VipsObjectLocal, 1); local->n = n; /* Make the array 1 too long so we can be sure there's a NULL * terminator. */ local->array = g_new0(VipsObject *, n + 1); g_signal_connect(parent, "close", G_CALLBACK(vips_object_local_array_cb), local); return local->array; } void vips_object_set_static(VipsObject *object, gboolean static_object) { object->static_object = static_object; } static void * vips_object_n_static_cb(VipsObject *object, int *n, void *b) { if (object->static_object) *n += 1; return NULL; } static int vips_object_n_static(void) { int n; n = 0; vips_object_map( (VipsSListMap2Fn) vips_object_n_static_cb, &n, NULL); return n; } static void * vips_object_print_all_cb(VipsObject *object, int *n, void *b) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); char str[32768]; VipsBuf buf = VIPS_BUF_STATIC(str); fprintf(stderr, "%d) %s (%p)", *n, G_OBJECT_TYPE_NAME(object), object); if (object->local_memory) fprintf(stderr, " %zd bytes", object->local_memory); fprintf(stderr, ", count=%d", G_OBJECT(object)->ref_count); fprintf(stderr, "\n"); vips_object_summary_class(class, &buf); vips_buf_appends(&buf, ", "); vips_object_summary(object, &buf); fprintf(stderr, "%s\n", vips_buf_all(&buf)); *n += 1; return NULL; } int vips__object_leak(void) { int n_leaks; n_leaks = 0; /* Don't count static objects. */ if (vips__object_all && g_hash_table_size(vips__object_all) > vips_object_n_static()) { fprintf(stderr, "%d objects alive:\n", g_hash_table_size(vips__object_all)); vips_object_map( (VipsSListMap2Fn) vips_object_print_all_cb, &n_leaks, NULL); } return n_leaks; } void vips_object_print_all(void) { (void) vips__object_leak(); (void) vips__type_leak(); } static void * vips_object_sanity_all_cb(VipsObject *object, void *a, void *b) { (void) vips_object_sanity(object); return NULL; } void vips_object_sanity_all(void) { vips_object_map( (VipsSListMap2Fn) vips_object_sanity_all_cb, NULL, NULL); } static void * vips_object_unref_outputs_sub(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { if ((argument_class->flags & VIPS_ARGUMENT_OUTPUT) && G_IS_PARAM_SPEC_OBJECT(pspec) && argument_instance->assigned) { GObject *value; g_object_get(object, g_param_spec_get_name(pspec), &value, NULL); /* Doing the get refs the object, so unref the get, then unref * again since this an an output object of the operation. */ g_object_unref(value); g_object_unref(value); } return NULL; } /** * vips_object_unref_outputs: * @object: object to drop output refs from * * Unref all assigned output objects. Useful for language bindings. * * After an object is built, all output args are owned by the caller. If * something goes wrong before then, we have to unref the outputs that have * been made so far. This function can also be useful for callers when * they've finished processing outputs themselves. * * ::: seealso * [func@cache_operation_build]. */ void vips_object_unref_outputs(VipsObject *object) { (void) vips_argument_map(object, vips_object_unref_outputs_sub, NULL, NULL); } /** * vips_object_get_description: * @object: object to fetch description from * * Fetch the object description. Useful for language bindings. * * [property@Object:description] is only available after `_build()`, which can be too * late. This function fetches from the instance, if possible, but falls back * to the class description if we are too early. * * Returns: the object description */ const char * vips_object_get_description(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); if (object->description) return object->description; else return class->description; } libvips-8.18.2/libvips/iofuncs/operation.c000066400000000000000000001204241516303661500205550ustar00rootroot00000000000000/* base class for all vips operations * * 30/12/14 * - display default/min/max for pspec in usage */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include /** * VipsOperation: * * An abstract base class for all operations in libvips. * * It builds on [class@Object] to provide the introspection and * command-line interface to libvips. * * It also maintains a cache of recent operations. See below. * * [func@call], [func@call_split] and [func@call_split_option_string] are used * by vips to implement the C API. They can execute any [class@Operation], * passing in a set of required and optional arguments. Normally you would not * use these functions directly: every operation has a tiny wrapper function * which provides type-safety for the required arguments. For example, * [method@Image.embed] is defined as: * * ```c * int * vips_embed(VipsImage *in, VipsImage **out, * int x, int y, int width, int height, ...) * { * va_list ap; * int result; * * va_start(ap, height); * result = vips_call_split("embed", ap, in, out, x, y, width, height); * va_end(ap); * * return result; * } * ``` * * Use [func@call_argv] to run any libvips operation from a command-line style * argc/argv array. This is the thing used by the `vips` main program to * implement the command-line interface. * * ## [class@Operation] and reference counting * * After calling a [class@Operation] you are responsible for unreffing any * output objects. For example, consider: * * ```c * VipsImage *im = ...; * VipsImage *t1; * * if (vips_invert(im, &t1, NULL)) * error .. * ``` * * This will invert `im` and return a new [class@Image], `t1`. As the caller * of [method@Image.invert], you are responsible for `t1` and must unref it * when you no longer need it. If [method@Image.invert] fails, no `t1` is * returned and you don't need to do anything. * * If you don't need to use `im` for another operation, you can unref `im` * immediately after the call. If `im` is needed to calculate `t1`, * [method@Image.invert] will add a ref to `im` and automatically drop it when * `t1` is unreffed. * * Consider running two operations, one after the other. You could write: * * ```c * VipsImage *im = ...; * VipsImage *t1, *t2; * * if (vips_invert(im, &t1, NULL)) { * g_object_unref(im); * return -1; * } * g_object_unref(im); * * if (vips_flip(t1, &t2, VIPS_DIRECTION_HORIZONTAL, NULL)) { * g_object_unref(t1); * return -1; * } * g_object_unref(t1); * ``` * * This is correct, but rather long-winded. libvips provides a handy thing to * make a vector of auto-freeing object references. You can write this as: * * ```c * VipsObject *parent = ...; * VipsImage *im = ...; * VipsImage *t = (VipsImage **) vips_object_local_array(parent, 2); * * if (vips_invert(im, &t[0], NULL) || * vips_flip(t[0], &t[1], VIPS_DIRECTION_HORIZONTAL, NULL)) * return -1; * ``` * * where `parent` is some enclosing object which will be unreffed when this * task is complete. [method@Object.local_array] makes an array of * [class@Object] (or [class@Image], in this case) where when `parent` is * freed, all non-`NULL` [class@Object] in the array are also unreffed. * * ## The [class@Operation] cache * * Because all [class@Object] are immutable, they can be cached. The cache is * very simple to use: instead of calling [method@Object.build], call * [func@cache_operation_build]. This function calculates a hash from the * operations' input arguments and looks it up in table of all recent * operations. If there's a hit, the new operation is unreffed, the old * operation reffed, and the old operation returned in place of the new one. * * The cache size is controlled with [func@cache_set_max] and friends. */ /** * VipsOperationFlags: * @VIPS_OPERATION_NONE: no flags * @VIPS_OPERATION_SEQUENTIAL: can work sequentially with a small buffer * @VIPS_OPERATION_SEQUENTIAL_UNBUFFERED: deprecated, use [flags@Vips.OperationFlags.SEQUENTIAL] instead * @VIPS_OPERATION_NOCACHE: must not be cached * @VIPS_OPERATION_DEPRECATED: a compatibility thing * @VIPS_OPERATION_UNTRUSTED: not hardened for untrusted input * @VIPS_OPERATION_BLOCKED: prevent this operation from running * @VIPS_OPERATION_REVALIDATE: force the operation to run * * Flags we associate with an operation. * * [flags@Vips.OperationFlags.SEQUENTIAL] means that the operation works like * [method@Image.conv]: it can process images top-to-bottom with only small * non-local references. * * Every scan-line must be requested, you are not allowed to skip * ahead, but as a special case, the very first request can be for a region * not at the top of the image. In this case, the first part of the image will * be read and discarded * * Every scan-line must be requested, you are not allowed to skip * ahead, but as a special case, the very first request can be for a region * not at the top of the image. In this case, the first part of the image will * be read and discarded * * [flags@Vips.OperationFlags.NOCACHE] means that the operation must not be * cached by vips. * * [flags@Vips.OperationFlags.DEPRECATED] means this is an old operation kept * in vips for compatibility only and should be hidden from users. * * [flags@Vips.OperationFlags.UNTRUSTED] means the operation depends on * external libraries which have not been hardened against attack. It should * probably not be used on untrusted input. Use [func@block_untrusted_set] * to block all untrusted operations. * * [flags@Vips.OperationFlags.BLOCKED] means the operation is prevented from * executing. Use [func@Operation.block_set] to enable and disable groups of * operations. * * [flags@Vips.OperationFlags.REVALIDATE] force the operation to run, updating * the cache with the new value. This is used by eg. VipsForeignLoad to * implement the "revalidate" argument. */ /* Abstract base class for operations. */ /* Our signals. */ enum { SIG_INVALIDATE, SIG_LAST }; static guint vips_operation_signals[SIG_LAST] = { 0 }; G_DEFINE_ABSTRACT_TYPE(VipsOperation, vips_operation, VIPS_TYPE_OBJECT); static void vips_operation_finalize(GObject *gobject) { VipsOperation *operation = VIPS_OPERATION(gobject); VIPS_DEBUG_MSG("vips_operation_finalize: %p\n", gobject); if (operation->pixels) g_info(_("%d pixels calculated"), operation->pixels); G_OBJECT_CLASS(vips_operation_parent_class)->finalize(gobject); } static void vips_operation_dispose(GObject *gobject) { VIPS_DEBUG_MSG("vips_operation_dispose: %p\n", gobject); G_OBJECT_CLASS(vips_operation_parent_class)->dispose(gobject); } /* Three basic types of command-line argument. * * INPUTS: things like an input image, there is a filename argument on the * command-line which is used to construct the operation argument. * * NOARG_OUTPUT: things like the result of VipsMax, there's no correspondiong * command-line argument, we just print the value. * * OPTIONS: optional arguments. * * NONE: hide this thing. */ typedef enum { USAGE_INPUTS, USAGE_NOARG_OUTPUT, USAGE_OPTIONS, USAGE_NONE } UsageType; typedef struct { char *message; /* header message on first print */ UsageType type; /* Type of arg to select */ gboolean oftype; /* Show as "of type" */ int n; /* Arg number */ } VipsOperationClassUsage; /* Put an arg into one the categories above. */ static UsageType vips_operation_class_usage_classify(VipsArgumentClass *argument_class) { if (!(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) || (argument_class->flags & VIPS_ARGUMENT_DEPRECATED)) return USAGE_NONE; if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED)) return USAGE_OPTIONS; if (vips_argument_class_needsstring(argument_class)) return USAGE_INPUTS; if ((argument_class->flags & VIPS_ARGUMENT_OUTPUT) && !vips_argument_class_needsstring(argument_class)) return USAGE_NOARG_OUTPUT; return USAGE_NONE; } /* Display a set of flags as "a:b:c" */ static void vips__flags_to_str(VipsBuf *buf, GFlagsClass *flags, guint value) { gboolean first = TRUE; for (int i = 0; i < flags->n_values; i++) // can't be 0 (would match everything), and all bits // should match all bits in the value, or "all" would always match // everything if (flags->values[i].value && (value & flags->values[i].value) == flags->values[i].value) { if (!first) vips_buf_appends(buf, ":"); first = FALSE; vips_buf_appends(buf, flags->values[i].value_nick); } } static void vips_operation_pspec_usage(VipsBuf *buf, GParamSpec *pspec) { GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); /* These are the pspecs that vips uses that have interesting values. */ if (G_IS_PARAM_SPEC_ENUM(pspec)) { /* GParamSpecEnum holds a ref on the class so we just peek. */ GEnumClass *genum = g_type_class_peek(type); GParamSpecEnum *pspec_enum = (GParamSpecEnum *) pspec; int i; g_assert(genum); vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("default enum")); vips_buf_appendf(buf, ": %s\n", vips_enum_nick(type, pspec_enum->default_value)); vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("allowed enums")); vips_buf_appendf(buf, ": "); for (i = 0; i < genum->n_values; i++) { if (i > 0) vips_buf_appends(buf, ", "); vips_buf_appends(buf, genum->values[i].value_nick); } vips_buf_appendf(buf, "\n"); } if (G_IS_PARAM_SPEC_FLAGS(pspec)) { /* GParamSpecFlags holds a ref on the class so we just peek. */ GFlagsClass *gflags = g_type_class_peek(type); GParamSpecFlags *pspec_flags = (GParamSpecFlags *) pspec; int i; g_assert(gflags); vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("default flags")); vips_buf_appendf(buf, ": "); vips__flags_to_str(buf, gflags, pspec_flags->default_value); vips_buf_appendf(buf, "\n"); vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("allowed flags")); vips_buf_appendf(buf, ": "); for (i = 0; i < gflags->n_values; i++) { if (i > 0) vips_buf_appends(buf, ", "); vips_buf_appends(buf, gflags->values[i].value_nick); } vips_buf_appendf(buf, "\n"); } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { GParamSpecBoolean *pspec_boolean = (GParamSpecBoolean *) pspec; vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("default")); vips_buf_appendf(buf, ": %s\n", pspec_boolean->default_value ? "true" : "false"); } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { GParamSpecDouble *pspec_double = (GParamSpecDouble *) pspec; vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("default")); vips_buf_appendf(buf, ": %g\n", pspec_double->default_value); vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("min")); vips_buf_appendf(buf, ": %g, ", pspec_double->minimum); vips_buf_appendf(buf, "%s", _("max")); vips_buf_appendf(buf, ": %g\n", pspec_double->maximum); } else if (G_IS_PARAM_SPEC_INT(pspec)) { GParamSpecInt *pspec_int = (GParamSpecInt *) pspec; vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("default")); vips_buf_appendf(buf, ": %d\n", pspec_int->default_value); vips_buf_appendf(buf, "\t\t\t"); vips_buf_appendf(buf, "%s", _("min")); vips_buf_appendf(buf, ": %d, ", pspec_int->minimum); vips_buf_appendf(buf, "%s", _("max")); vips_buf_appendf(buf, ": %d\n", pspec_int->maximum); } } static void * vips_operation_class_usage_arg(VipsObjectClass *object_class, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsBuf *buf, VipsOperationClassUsage *usage) { if (usage->type == vips_operation_class_usage_classify(argument_class)) { if (usage->message && usage->n == 0) vips_buf_appendf(buf, "%s\n", usage->message); if (usage->oftype) { vips_buf_appendf(buf, " %-12s - %s, %s %s\n", g_param_spec_get_name(pspec), g_param_spec_get_blurb(pspec), (argument_class->flags & VIPS_ARGUMENT_INPUT) ? _("input") : _("output"), g_type_name( G_PARAM_SPEC_VALUE_TYPE(pspec))); vips_operation_pspec_usage(buf, pspec); } else { if (usage->n > 0) vips_buf_appends(buf, " "); vips_buf_appends(buf, g_param_spec_get_name(pspec)); } usage->n += 1; } return NULL; } static void vips_operation_usage(VipsOperationClass *class, VipsBuf *buf) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsOperationClassUsage usage; vips_buf_appendf(buf, "%s\n", object_class->description); vips_buf_appendf(buf, "usage:\n"); /* First pass through args: show the required names. */ vips_buf_appendf(buf, " %s ", object_class->nickname); usage.message = NULL; usage.type = USAGE_INPUTS; usage.oftype = FALSE; usage.n = 0; vips_argument_class_map(object_class, (VipsArgumentClassMapFn) vips_operation_class_usage_arg, buf, &usage); vips_buf_appends(buf, " [--option-name option-value ...]\n"); /* Show required types. */ usage.message = "where:"; usage.type = USAGE_INPUTS; usage.oftype = TRUE; usage.n = 0; vips_argument_class_map(object_class, (VipsArgumentClassMapFn) vips_operation_class_usage_arg, buf, &usage); /* Show outputs with no input arg (eg. output maximum value for * vips_max()). */ usage.message = "outputs:"; usage.type = USAGE_NOARG_OUTPUT; usage.oftype = TRUE; usage.n = 0; vips_argument_class_map(object_class, (VipsArgumentClassMapFn) vips_operation_class_usage_arg, buf, &usage); /* Show optional args. */ usage.message = "optional arguments:"; usage.type = USAGE_OPTIONS; usage.oftype = TRUE; usage.n = 0; vips_argument_class_map(object_class, (VipsArgumentClassMapFn) vips_operation_class_usage_arg, buf, &usage); /* Show flags. */ if (class->flags) { GFlagsValue *value; VipsOperationFlags flags; GFlagsClass *flags_class = g_type_class_ref(VIPS_TYPE_OPERATION_FLAGS); vips_buf_appendf(buf, "operation flags: "); flags = class->flags; while (flags && (value = g_flags_get_first_value(flags_class, flags))) { vips_buf_appendf(buf, "%s ", value->value_nick); flags &= ~value->value; } vips_buf_appends(buf, "\n"); } } static void * vips_operation_call_argument(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsArgument *argument = (VipsArgument *) argument_class; printf(" %s: offset = %d ", g_param_spec_get_name(argument->pspec), argument_class->offset); if (argument_class->flags & VIPS_ARGUMENT_REQUIRED) printf("required "); if (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) printf("construct "); if (argument_class->flags & VIPS_ARGUMENT_SET_ONCE) printf("set-once "); if (argument_instance->assigned) printf("assigned "); printf("\n"); return NULL; } static void vips_operation_dump(VipsObject *object, VipsBuf *buf) { VipsOperation *operation = VIPS_OPERATION(object); VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); if (operation->found_hash) printf("hash = %x\n", operation->hash); printf("%s args:\n", object_class->nickname); vips_argument_map(VIPS_OBJECT(operation), vips_operation_call_argument, NULL, NULL); VIPS_OBJECT_CLASS(vips_operation_parent_class)->dump(object, buf); } static void * vips_operation_vips_operation_print_summary_arg(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsBuf *buf = (VipsBuf *) a; /* Just assigned input and output construct args. _summary() is used * for things like cache tracing, so it's useful to show output args. */ if (((argument_class->flags & VIPS_ARGUMENT_INPUT) || (argument_class->flags & VIPS_ARGUMENT_OUTPUT)) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && argument_instance->assigned) { const char *name = g_param_spec_get_name(pspec); GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); GValue gvalue = G_VALUE_INIT; char *str; g_value_init(&gvalue, type); g_object_get_property(G_OBJECT(object), name, &gvalue); str = g_strdup_value_contents(&gvalue); vips_buf_appendf(buf, " %s=%s", name, str); g_free(str); g_value_unset(&gvalue); } return NULL; } static int vips_operation_build(VipsObject *object) { VipsOperationClass *class = VIPS_OPERATION_GET_CLASS(object); #ifdef VIPS_DEBUG printf("vips_operation_build: "); vips_object_print_name(object); printf("\n"); #endif /*VIPS_DEBUG*/ if (class->flags & VIPS_OPERATION_BLOCKED) { vips_error(VIPS_OBJECT_CLASS(class)->nickname, "%s", _("operation is blocked")); return -1; } if (VIPS_OBJECT_CLASS(vips_operation_parent_class)->build(object)) return -1; return 0; } static void vips_operation_summary_class(VipsObjectClass *object_class, VipsBuf *buf) { VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(object_class); VIPS_OBJECT_CLASS(vips_operation_parent_class) ->summary_class(object_class, buf); GType gtype = G_OBJECT_CLASS_TYPE(operation_class); if (!G_TYPE_IS_ABSTRACT(gtype) && operation_class->flags & VIPS_OPERATION_NOCACHE) vips_buf_appendf(buf, ", nocache"); } static void vips_operation_summary(VipsObject *object, VipsBuf *buf) { VipsOperation *operation = VIPS_OPERATION(object); VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); vips_buf_appendf(buf, "%s", object_class->nickname); vips_argument_map(VIPS_OBJECT(operation), vips_operation_vips_operation_print_summary_arg, buf, NULL); vips_buf_appends(buf, " -"); VIPS_OBJECT_CLASS(vips_operation_parent_class)->summary(object, buf); } static VipsOperationFlags vips_operation_real_get_flags(VipsOperation *operation) { VipsOperationClass *class = VIPS_OPERATION_GET_CLASS(operation); return class->flags; } static void vips_operation_class_init(VipsOperationClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->finalize = vips_operation_finalize; gobject_class->dispose = vips_operation_dispose; vobject_class->build = vips_operation_build; vobject_class->summary_class = vips_operation_summary_class; vobject_class->summary = vips_operation_summary; vobject_class->dump = vips_operation_dump; vobject_class->nickname = "operation"; vobject_class->description = _("operations"); class->usage = vips_operation_usage; class->get_flags = vips_operation_real_get_flags; vips_operation_signals[SIG_INVALIDATE] = g_signal_new("invalidate", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(VipsOperationClass, invalidate), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void vips_operation_init(VipsOperation *operation) { } /** * vips_operation_get_flags: * @operation: operation to fetch flags from * * Returns the set of flags for this operation. * * Returns: 0 on success, or -1 on error. */ VipsOperationFlags vips_operation_get_flags(VipsOperation *operation) { VipsOperationClass *class = VIPS_OPERATION_GET_CLASS(operation); return class->get_flags(operation); } /** * vips_operation_class_print_usage: (skip) * @operation_class: class to print usage for * * Print a usage message for the operation to stdout. */ void vips_operation_class_print_usage(VipsOperationClass *operation_class) { char str[4096]; VipsBuf buf = VIPS_BUF_STATIC(str); operation_class->usage(operation_class, &buf); printf("%s", vips_buf_all(&buf)); } void vips_operation_invalidate(VipsOperation *operation) { #ifdef VIPS_DEBUG printf("vips_operation_invalidate: %p\n", operation); vips_object_print_summary(VIPS_OBJECT(operation)); #endif /*VIPS_DEBUG*/ g_signal_emit(operation, vips_operation_signals[SIG_INVALIDATE], 0); } /** * vips_operation_new: (constructor) * @name: nickname of operation to create * * Return a new [class@Operation] with the specified nickname. Useful for * language bindings. * * You'll need to set any arguments and build the operation before you can use * it. See [func@call] for a higher-level way to make new operations. * * Returns: (transfer full): the new operation. */ VipsOperation * vips_operation_new(const char *name) { GType type; VipsObject *object; VipsOperation *operation; vips_check_init(); if (!(type = vips_type_find("VipsOperation", name))) { vips_error("VipsOperation", _("class \"%s\" not found"), name); return NULL; } if (!(object = g_object_new(type, NULL))) { vips_error("VipsOperation", _("\"%s\" is not an instantiable class"), name); return NULL; } operation = VIPS_OPERATION(object); VIPS_DEBUG_MSG("vips_operation_new: %s (%p)\n", name, operation); return operation; } /* Some systems do not have va_copy() ... this might work (it does on MSVC, * apparently). * * FIXME ... this should be in configure.in */ #ifndef va_copy #define va_copy(d, s) ((d) = (s)) #endif static int vips_operation_set_valist_required(VipsOperation *operation, va_list ap) { VIPS_DEBUG_MSG("vips_operation_set_valist_required:\n"); /* Set required input arguments. Can't use vips_argument_map here * :-( because passing va_list by reference is not portable. */ VIPS_ARGUMENT_FOR_ALL(operation, pspec, argument_class, argument_instance) { g_assert(argument_instance); /* We skip deprecated required args. There will be a new, * renamed arg in the same place. */ if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) && !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED)) { VIPS_ARGUMENT_COLLECT_SET(pspec, argument_class, ap); #ifdef VIPS_DEBUG { char *str; str = g_strdup_value_contents(&value); VIPS_DEBUG_MSG("\t%s = %s\n", g_param_spec_get_name(pspec), str); g_free(str); } #endif /*VIPS_DEBUG */ g_object_set_property(G_OBJECT(operation), g_param_spec_get_name(pspec), &value); VIPS_ARGUMENT_COLLECT_GET(pspec, argument_class, ap); #ifdef VIPS_DEBUG printf("\tskipping arg %p for %s\n", arg, g_param_spec_get_name(pspec)); #endif /*VIPS_DEBUG */ VIPS_ARGUMENT_COLLECT_END } } VIPS_ARGUMENT_FOR_ALL_END return 0; } static int vips_operation_get_valist_required(VipsOperation *operation, va_list ap) { VIPS_DEBUG_MSG("vips_operation_get_valist_required:\n"); /* Extract output arguments. Can't use vips_argument_map here * :-( because passing va_list by reference is not portable. */ VIPS_ARGUMENT_FOR_ALL(operation, pspec, argument_class, argument_instance) { if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED)) { VIPS_ARGUMENT_COLLECT_SET(pspec, argument_class, ap); VIPS_ARGUMENT_COLLECT_GET(pspec, argument_class, ap); if (!argument_instance->assigned) continue; #ifdef VIPS_DEBUG printf("\twriting %s to %p\n", g_param_spec_get_name(pspec), arg); #endif /*VIPS_DEBUG */ /* It'd be nice to be able to test for arg being a * valid gobject pointer, since passing in a valid * pointer (and having us destroy it) is a common * error and a cause of hard-to-find leaks. * * Unfortunately, G_IS_OBJECT() can't be given an * arbitrary pointer for testing -- you're very likely * to get coredumps. */ g_object_get(G_OBJECT(operation), g_param_spec_get_name(pspec), arg, NULL); /* If the pspec is an object, that will up the ref * count. We want to hand over the ref, so we have to * knock it down again. */ if (G_IS_PARAM_SPEC_OBJECT(pspec)) { GObject *object; object = *((GObject **) arg); g_object_unref(object); } VIPS_ARGUMENT_COLLECT_END } } VIPS_ARGUMENT_FOR_ALL_END return 0; } static int vips_operation_get_valist_optional(VipsOperation *operation, va_list ap) { char *name; VIPS_DEBUG_MSG("vips_operation_get_valist_optional:\n"); for (name = va_arg(ap, char *); name; name = va_arg(ap, char *)) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; VIPS_DEBUG_MSG("\tname = '%s' (%p)\n", name, name); if (vips_object_get_argument(VIPS_OBJECT(operation), name, &pspec, &argument_class, &argument_instance)) return -1; VIPS_ARGUMENT_COLLECT_SET(pspec, argument_class, ap); /* We must collect input args as we walk the name/value list, * but we don't do anything with them. */ VIPS_ARGUMENT_COLLECT_GET(pspec, argument_class, ap); /* Here's an output arg. */ #ifdef VIPS_DEBUG printf("\twriting %s to %p\n", g_param_spec_get_name(pspec), arg); #endif /*VIPS_DEBUG */ /* If the dest pointer is NULL, skip the read. */ if (arg) { g_object_get(G_OBJECT(operation), g_param_spec_get_name(pspec), arg, NULL); /* If the pspec is an object, that will up * the ref count. We want to hand over the * ref, so we have to knock it down again. */ if (G_IS_PARAM_SPEC_OBJECT(pspec)) { GObject *object; object = *((GObject **) arg); g_object_unref(object); } } VIPS_ARGUMENT_COLLECT_END } return 0; } /** * vips_call_required_optional: * @operation: the operation to execute * @required: `va_list` of required arguments * @optional: `NULL`-terminated `va_list` of name / value pairs * * This is the main entry point for the C and C++ varargs APIs. @operation * is executed, supplying @required and @optional arguments. * * Beware, this can change @operation to point at an old, cached one. * * Returns: 0 on success, -1 on error */ int vips_call_required_optional(VipsOperation **operation, va_list required, va_list optional) { int result; va_list a; va_list b; /* We need to be able to walk required and optional twice. On x64 gcc, * vips_operation_set_valist_required() etc. will destructively alter * the passed-in va_list. We make a copy and walk that instead. */ va_copy(a, required); va_copy(b, optional); result = vips_operation_set_valist_required(*operation, a) || vips_object_set_valist(VIPS_OBJECT(*operation), b); va_end(a); va_end(b); if (result) return -1; /* Build from cache. */ if (vips_cache_operation_buildp(operation)) return -1; /* Walk args again, writing output. */ va_copy(a, required); va_copy(b, optional); result = vips_operation_get_valist_required(*operation, required) || vips_operation_get_valist_optional(*operation, optional); va_end(a); va_end(b); return result; } static int vips_call_by_name(const char *operation_name, const char *option_string, va_list required, va_list optional) { VipsOperation *operation; int result; VIPS_DEBUG_MSG("vips_call_by_name: starting for %s ...\n", operation_name); if (!(operation = vips_operation_new(operation_name))) return -1; /* Set str options before vargs options, so the user can't override * things we set deliberately. */ if (option_string && vips_object_set_from_string(VIPS_OBJECT(operation), option_string)) { vips_object_unref_outputs(VIPS_OBJECT(operation)); g_object_unref(operation); return -1; } result = vips_call_required_optional(&operation, required, optional); /* Build failed: junk args and back out. */ if (result) { vips_object_unref_outputs(VIPS_OBJECT(operation)); g_object_unref(operation); return -1; } /* The operation we have built should now have been reffed by one of * its arguments or have finished its work. Either way, we can unref. */ g_object_unref(operation); return result; } /** * vips_call: * @operation_name: name of operation to call * @...: required args, then a `NULL`-terminated list of argument/value pairs * * [func@call] calls the named operation, passing in required arguments and * then setting any optional ones from the remainder of the arguments as a set * of name/value pairs. * * For example, [method@Image.embed] takes six required arguments, @in, @out, * @x, @y, @width, @height, and has two optional arguments, @extend and * @background. You can run it with [func@call] like this: * * ```c * VipsImage *in = ... * VipsImage *out; * * if (vips_call("embed", in, &out, 10, 10, 100, 100, * "extend", VIPS_EXTEND_COPY, * NULL)) * ... error * ``` * * Normally of course you'd just use the [method@Image.embed] wrapper function and get * type-safety for the required arguments. * * ::: seealso * [func@call_split], [func@call_options]. * * Returns: 0 on success, -1 on error */ int vips_call(const char *operation_name, ...) { VipsOperation *operation; int result; va_list required; va_list optional; if (!(operation = vips_operation_new(operation_name))) return -1; /* We have to break the va_list into separate required and optional * components. * * Note the start, grab the required, then copy and reuse. */ va_start(required, operation_name); va_copy(optional, required); VIPS_ARGUMENT_FOR_ALL(operation, pspec, argument_class, argument_instance) { g_assert(argument_instance); if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED)) { VIPS_ARGUMENT_COLLECT_SET(pspec, argument_class, optional); VIPS_ARGUMENT_COLLECT_GET(pspec, argument_class, optional); VIPS_ARGUMENT_COLLECT_END } } VIPS_ARGUMENT_FOR_ALL_END /* We just needed this operation for the arg loop. */ g_object_unref(operation); result = vips_call_by_name(operation_name, NULL, required, optional); va_end(required); va_end(optional); return result; } int vips_call_split(const char *operation_name, va_list optional, ...) { int result; va_list required; va_start(required, optional); result = vips_call_by_name(operation_name, NULL, required, optional); va_end(required); return result; } int vips_call_split_option_string(const char *operation_name, const char *option_string, va_list optional, ...) { int result; va_list required; va_start(required, optional); result = vips_call_by_name(operation_name, option_string, required, optional); va_end(required); return result; } static void * vips_call_find_pspec(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { const char *name = (const char *) a; /* One char names we assume are "-x" style abbreviations, longer names * we match the whole string. */ if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && !argument_instance->assigned) if ((strlen(name) == 1 && g_param_spec_get_name(pspec)[0] == name[0]) || strcmp(g_param_spec_get_name(pspec), name) == 0) return argument_instance; return NULL; } /* Keep this stuff around for output args. */ typedef struct _VipsCallOptionOutput { VipsArgumentInstance *argument_instance; char *value; } VipsCallOptionOutput; static int vips_call_option_output(VipsObject *object, VipsCallOptionOutput *output) { VipsArgumentInstance *argument_instance = output->argument_instance; GParamSpec *pspec = ((VipsArgument *) argument_instance)->pspec; int result; /* Don't look at the output arg if _build() hasn't run successfully, it * probably won't have been set. */ result = 0; if (object->constructed) result = vips_object_get_argument_to_string(object, g_param_spec_get_name(pspec), output->value); return result; } static void vips_call_option_output_free(VipsObject *object, VipsCallOptionOutput *output) { VIPS_FREE(output->value); g_free(output); } static gboolean vips_call_options_set(const gchar *option_name, const gchar *value, gpointer data, GError **error) { VipsOperation *operation = (VipsOperation *) data; const char *name; VipsArgumentInstance *argument_instance; VipsArgumentClass *argument_class; GParamSpec *pspec; VIPS_DEBUG_MSG("vips_call_options_set: %s = %s\n", option_name, value); /* Remove any leading "--" from the option name. */ for (name = option_name; *name == '-'; name++) ; if (!(argument_instance = (VipsArgumentInstance *) vips_argument_map( VIPS_OBJECT(operation), vips_call_find_pspec, (void *) name, NULL))) { vips_error(VIPS_OBJECT_GET_CLASS(operation)->nickname, _("unknown argument '%s'"), name); vips_error_g(error); return FALSE; } argument_class = argument_instance->argument_class; pspec = ((VipsArgument *) argument_instance)->pspec; if ((argument_class->flags & VIPS_ARGUMENT_INPUT)) { if (vips_object_set_argument_from_string( VIPS_OBJECT(operation), g_param_spec_get_name(pspec), value)) { vips_error_g(error); return FALSE; } #ifdef VIPS_DEBUG { GType type = G_PARAM_SPEC_VALUE_TYPE(pspec); GValue gvalue = G_VALUE_INIT; char *str; g_value_init(&gvalue, type); g_object_get_property(G_OBJECT(operation), g_param_spec_get_name(pspec), &gvalue); str = g_strdup_value_contents(&gvalue); VIPS_DEBUG_MSG("\tGValue %s = %s\n", g_param_spec_get_name(pspec), str); g_free(str); g_value_unset(&gvalue); } #endif /*VIPS_DEBUG*/ } else if ((argument_class->flags & VIPS_ARGUMENT_OUTPUT)) { VipsCallOptionOutput *output; /* We can't do output now, we have to attach a callback to do * the processing after the operation has run. */ output = g_new(VipsCallOptionOutput, 1); output->argument_instance = argument_instance; output->value = g_strdup(value); g_signal_connect(operation, "postbuild", G_CALLBACK(vips_call_option_output), output); g_signal_connect(operation, "close", G_CALLBACK(vips_call_option_output_free), output); } return TRUE; } static void * vips_call_options_add(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { GOptionGroup *group = (GOptionGroup *) a; if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && !argument_instance->assigned) { const char *name = g_param_spec_get_name(pspec); gboolean needs_string = vips_object_argument_needsstring(object, name); GOptionEntry entry[2]; entry[0].long_name = name; entry[0].description = g_param_spec_get_blurb(pspec); /* Don't set short names for deprecated args. */ if (argument_class->flags & VIPS_ARGUMENT_DEPRECATED) entry[0].short_name = '\0'; else entry[0].short_name = name[0]; entry[0].flags = 0; if (!needs_string) entry[0].flags |= G_OPTION_FLAG_NO_ARG; if (argument_class->flags & VIPS_ARGUMENT_DEPRECATED) entry[0].flags |= G_OPTION_FLAG_HIDDEN; entry[0].arg = G_OPTION_ARG_CALLBACK; entry[0].arg_data = (gpointer) vips_call_options_set; if (needs_string) entry[0].arg_description = g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)); else entry[0].arg_description = NULL; entry[1].long_name = NULL; VIPS_DEBUG_MSG("vips_call_options_add: adding %s\n", name); g_option_group_add_entries(group, &entry[0]); } return NULL; } void vips_call_options(GOptionGroup *group, VipsOperation *operation) { (void) vips_argument_map(VIPS_OBJECT(operation), vips_call_options_add, group, NULL); } /* What we track during an argv call. */ typedef struct _VipsCall { VipsOperation *operation; int argc; char **argv; int i; } VipsCall; static const char * vips_call_get_arg(VipsCall *call, int i) { if (i < 0 || i >= call->argc) { vips_error(VIPS_OBJECT_GET_CLASS(call->operation)->nickname, "%s", _("too few arguments")); return NULL; } return call->argv[i]; } static void * vips_call_argv_input(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsCall *call = (VipsCall *) a; /* Loop over all required construct args. */ if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED)) { const char *name = g_param_spec_get_name(pspec); if ((argument_class->flags & VIPS_ARGUMENT_INPUT)) { const char *arg; if (!(arg = vips_call_get_arg(call, call->i)) || vips_object_set_argument_from_string(object, name, arg)) return pspec; call->i += 1; } else if ((argument_class->flags & VIPS_ARGUMENT_OUTPUT)) { if (vips_object_argument_needsstring(object, name)) call->i += 1; } } return NULL; } static void * vips_call_argv_output(VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, void *a, void *b) { VipsCall *call = (VipsCall *) a; /* Loop over all required construct args. */ if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED)) { if ((argument_class->flags & VIPS_ARGUMENT_INPUT)) call->i += 1; else if ((argument_class->flags & VIPS_ARGUMENT_OUTPUT)) { const char *name = g_param_spec_get_name(pspec); const char *arg; arg = NULL; if (vips_object_argument_needsstring(object, name)) { arg = vips_call_get_arg(call, call->i); if (!arg) return pspec; call->i += 1; } if (vips_object_get_argument_to_string(object, name, arg)) return pspec; } } return NULL; } /* Our main command-line entry point. Optional args should have been set by * the GOption parser already, see above. * * We don't create the operation, so we must not unref it. The caller must * unref on error too. The caller must also call vips_object_unref_outputs() on * all code paths. */ int vips_call_argv(VipsOperation *operation, int argc, char **argv) { VipsCall call; g_assert(argc >= 0); #ifdef VIPS_DEBUG printf("vips_call_argv: "); vips_object_print_name(VIPS_OBJECT(operation)); printf("\n"); { int i; for (i = 0; i < argc; i++) printf("%d) %s\n", i, argv[i]); } #endif /*VIPS_DEBUG*/ call.operation = operation; call.argc = argc; call.argv = argv; call.i = 0; if (vips_argument_map(VIPS_OBJECT(operation), vips_call_argv_input, &call, NULL)) return -1; /* Any unused arguments? We must fail. Consider eg. "vips bandjoin a b * c". This would overwrite b with a and ignore c, potentially * disastrous. */ if (argc > call.i) { vips_error(VIPS_OBJECT_GET_CLASS(operation)->nickname, "%s", _("too many arguments")); return -1; } /* We can't use the operation cache, we need to be able to change the * operation pointer. The cache probably wouldn't help anyway. */ if (vips_object_build(VIPS_OBJECT(operation))) return -1; /* We're not using the cache, so we need to print the trace line. */ if (vips__cache_trace) { printf("vips cache : "); vips_object_print_summary(VIPS_OBJECT(operation)); } call.i = 0; if (vips_argument_map(VIPS_OBJECT(operation), vips_call_argv_output, &call, NULL)) return -1; return 0; } static void * vips_operation_block_set_operation(VipsOperationClass *class, gboolean *state) { g_assert(VIPS_IS_OPERATION_CLASS(class)); #ifdef VIPS_DEBUG if (((class->flags & VIPS_OPERATION_BLOCKED) != 0) != *state) VIPS_DEBUG_MSG("vips_operation_block_set_operation: " "setting block state on %s = %d\n", VIPS_OBJECT_CLASS(class)->nickname, *state); #endif if (*state) class->flags |= VIPS_OPERATION_BLOCKED; else class->flags &= ~VIPS_OPERATION_BLOCKED; return NULL; } /** * vips_operation_block_set: * @name: set block state at this point and below * @state: the block state to set * * Set the block state on all operations in the libvips class hierarchy at * @name and below. * * For example: * * ```c * vips_operation_block_set("VipsForeignLoad", TRUE); * vips_operation_block_set("VipsForeignLoadJpeg", FALSE); * ``` * * Will block all load operations, except JPEG. * * Use `vips -l` at the command-line to see the class hierarchy. * * This call does nothing if the named operation is not found. * * ::: seealso * [func@block_untrusted_set]. */ void vips_operation_block_set(const char *name, gboolean state) { GType base; if ((base = g_type_from_name(name)) && g_type_is_a(base, VIPS_TYPE_OPERATION)) vips_class_map_all(base, (VipsClassMapFn) vips_operation_block_set_operation, &state); } libvips-8.18.2/libvips/iofuncs/rect.c000066400000000000000000000125161516303661500175140ustar00rootroot00000000000000/* Simple rectangle algebra. Should build rectangle list algebra on top of * this. * * J. Cupitt, 8/4/93. * * 17/3/11 * - move to vips_ prefix * - gtk-doc comments */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /** * VipsRect: * @left: left edge of rectangle * @top: top edge of rectangle * @width: width of rectangle * @height: height of rectangle * * A [struct@Rect] is a rectangular area of pixels. This is a struct for * performing simple rectangle algebra. */ /** * vips_rect_includespoint: * @r: rectangle to test * @x: position to test for * @y: position to test for * * Does @r contain point (@x, @y)? * * Returns: `TRUE` if @r contains (@x, @y). */ gboolean vips_rect_includespoint(const VipsRect *r, int x, int y) { return r->left <= x && r->top <= y && r->left + r->width > x && r->top + r->height > y; } /** * vips_rect_isempty: * @r: rectangle to test * * Is @r empty? ie. zero width or height. * * Returns: `TRUE` if @r contains no pixels. */ gboolean vips_rect_isempty(const VipsRect *r) { return r->width <= 0 || r->height <= 0; } /** * vips_rect_includesrect: * @r1: outer rectangle * @r2: inner rectangle * * Is @r2 a subset of @r1? * * Returns: `TRUE` if @r2 is a subset of @r1. */ gboolean vips_rect_includesrect(const VipsRect *r1, const VipsRect *r2) { return r1->left <= r2->left && r1->top <= r2->top && r1->left + r1->width >= r2->left + r2->width && r1->top + r1->height >= r2->top + r2->height; } /** * vips_rect_equalsrect: * @r1: first rectangle * @r2: second rectangle * * Is @r1 equal to @r2? * * Returns: `TRUE` if @r1 is equal to @r2. */ gboolean vips_rect_equalsrect(const VipsRect *r1, const VipsRect *r2) { return r1->left == r2->left && r1->top == r2->top && r1->width == r2->width && r1->height == r2->height; } /** * vips_rect_overlapsrect: * @r1: first rectangle * @r2: second rectangle * * Do @r1 and @r2 have a non-empty intersection? * * Returns: `TRUE` if @r2 and @r1 overlap. */ gboolean vips_rect_overlapsrect(const VipsRect *r1, const VipsRect *r2) { VipsRect intersection; vips_rect_intersectrect(r1, r2, &intersection); return !vips_rect_isempty(&intersection); } /** * vips_rect_marginadjust: * @r: rectangle to adjust * @n: enlarge by * * Enlarge @r by @n. +1 means out one pixel. */ void vips_rect_marginadjust(VipsRect *r, int n) { r->left -= n; r->top -= n; r->width += 2 * n; r->height += 2 * n; } /** * vips_rect_intersectrect: * @r1: input rectangle 1 * @r2: input rectangle 2 * @out: (out): output rectangle * * Fill @out with the intersection of @r1 and @r2. @out can equal @r1 or @r2. */ void vips_rect_intersectrect(const VipsRect *r1, const VipsRect *r2, VipsRect *out) { int left = VIPS_MAX(r1->left, r2->left); int top = VIPS_MAX(r1->top, r2->top); int right = VIPS_MIN(VIPS_RECT_RIGHT(r1), VIPS_RECT_RIGHT(r2)); int bottom = VIPS_MIN(VIPS_RECT_BOTTOM(r1), VIPS_RECT_BOTTOM(r2)); int width = VIPS_MAX(0, right - left); int height = VIPS_MAX(0, bottom - top); out->left = left; out->top = top; out->width = width; out->height = height; } /** * vips_rect_unionrect: * @r1: input rectangle 1 * @r2: input rectangle 2 * @out: (out): output rectangle * * Fill @out with the bounding box of @r1 and @r2. @out can equal @r1 or @r2. */ void vips_rect_unionrect(const VipsRect *r1, const VipsRect *r2, VipsRect *out) { if (vips_rect_isempty(r1)) *out = *r2; else if (vips_rect_isempty(r2)) *out = *r1; else { int left = VIPS_MIN(r1->left, r2->left); int top = VIPS_MIN(r1->top, r2->top); int width = VIPS_MAX(VIPS_RECT_RIGHT(r1), VIPS_RECT_RIGHT(r2)) - left; int height = VIPS_MAX(VIPS_RECT_BOTTOM(r1), VIPS_RECT_BOTTOM(r2)) - top; out->left = left; out->top = top; out->width = width; out->height = height; } } /** * vips_rect_dup: (skip) * @r: rectangle to duplicate * * Duplicate a rect to the heap. You need to free the result with [func@GLib.free]. * * Returns: (transfer full): a pointer to copy of @r allocated on the heap. */ VipsRect * vips_rect_dup(const VipsRect *r) { VipsRect *out; if (!(out = VIPS_NEW(NULL, VipsRect))) return NULL; *out = *r; return out; } /** * vips_rect_normalise: * @r: rect to normalise * * Make sure width and height are >0 by moving the origin and flipping the * rect. */ void vips_rect_normalise(VipsRect *r) { if (r->width < 0) { r->left += r->width; r->width *= -1; } if (r->height < 0) { r->top += r->height; r->height *= -1; } } libvips-8.18.2/libvips/iofuncs/region.c000066400000000000000000001411051516303661500200370ustar00rootroot00000000000000/* Make and destroy partial image regions. * * J.Cupitt, 8/4/93. * 1/7/93 JC * - adapted for partial v2 * - ANSIfied * 15/8/94 JC * - start & stop can now be NULL for no-op * 12/5/94 JC * - threads v2.0 added * 22/2/95 JC * - im_region_region() args changed * 22/6/95 JC * - im_region_local() did not always reset the data pointer * 18/11/98 JC * - init a, b, c also now, to help rtc avoid spurious checks * 29/6/01 JC * - im_region_free() now frees immediately * 6/8/02 JC * - new mmap() window regions * 5/11/02 JC * - fix for mmap a local region * 28/2/05 * - shrink local region memory if required much-greater-than allocated * 3/6/05 * - im_region_region() allows Bands and BandFmt to differ, provided * sizeof( pel ) is the same ... makes im_copy_morph() work * 30/10/06 * - switch to im_window_t for mmap window stuff * 29/11/06 * - switch to im_buffer_t for local mem buffer stuff * 19/1/07 * - im_region_image() only sets r, not whole image * 1'2'07 * - gah, im_region_image() could still break (thanks Mikkel) * 23/7/08 * - added im_region_print() * 7/10/09 * - gtkdoc comments * 5/3/10 * - move invalid stuff to region * 3/3/11 * - move on top of VipsObject, rename as VipsRegion * 23/2/17 * - multiply transparent images through alpha in vips_region_shrink() * 13/6/18 harukizaemon * - add VipsRegionShrink parameter to vips_region_shrink() * 9/6/19 * - saner behaviour for vips_region_fetch() if the request is partly * outside the image * 22/2/21 f1ac * - fix int overflow in vips_region_copy(), could cause crashes with * very wide images */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_MOVE #define DEBUG_ENVIRONMENT 1 #define DEBUG_CREATE #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include /** * VipsRegion: * * A [class@Region] represents a small, rectangular part of an image. * * You use regions to read pixels out of images without having to have the * whole image in memory at once. * * A region can be a memory buffer, part of a memory-mapped file, part of some * other image, or part of some other region. * * Regions must be created, used and freed all within the same thread, since * they can reference private per-thread caches. libvips sanity-checks region * ownership in various places, so you are likely to see [func@GLib.assert] * errors if you don't follow this rule. * * There is API to transfer ownership of regions between threads, but * (hopefully) this is only needed within libvips, so we don't expose it. */ /** * VIPS_REGION_LSKIP: * @R: a [class@Region] * * Returns: The number of bytes to add to move down a scanline. */ /** * VIPS_REGION_N_ELEMENTS: * @R: a [class@Region] * * Returns: The number of band elements across a region. */ /** * VIPS_REGION_SIZEOF_LINE: * @R: a [class@Region] * * Returns: The number of bytes across a region. */ /** * VIPS_REGION_ADDR: * @R: a [class@Region] * @X: x coordinate * @Y: y coordinate * * This macro returns a pointer to a pixel in a region. The (@X, @Y) * coordinates need to be within the [struct@Rect] (@R->valid). * * If DEBUG is defined, you get a version that checks bounds for you. * * ::: seealso * [method@Region.prepare]. * * Returns: The address of pixel (@X,@Y) in @R. */ /** * VIPS_REGION_ADDR_TOPLEFT: * @R: a [class@Region] * * This macro returns a pointer to the top-left pixel in the [class@Region], that * is, the pixel at (@R->valid.left, @R->valid.top). * * ::: seealso * [method@Region.prepare]. * * Returns: The address of the top-left pixel in the region. */ /* Properties. */ enum { PROP_IMAGE = 1, PROP_LAST }; G_DEFINE_TYPE(VipsRegion, vips_region, VIPS_TYPE_OBJECT); #ifdef VIPS_DEBUG static GSList *vips__regions_all = NULL; #endif /*VIPS_DEBUG*/ static void vips_region_finalize(GObject *gobject) { #ifdef VIPS_DEBUG VIPS_DEBUG_MSG("vips_region_finalize: "); vips_object_print_name(VIPS_OBJECT(gobject)); VIPS_DEBUG_MSG("\n"); #endif /*VIPS_DEBUG*/ #ifdef VIPS_DEBUG g_mutex_lock(&vips__global_lock); vips__regions_all = g_slist_remove(vips__regions_all, gobject); g_mutex_unlock(&vips__global_lock); #endif /*VIPS_DEBUG*/ G_OBJECT_CLASS(vips_region_parent_class)->finalize(gobject); } /* Call a start function if no sequence is running on this VipsRegion. */ int vips__region_start(VipsRegion *region) { VipsImage *image = region->im; if (!region->seq && image->start_fn) { VIPS_GATE_START("vips__region_start: wait"); g_mutex_lock(&image->sslock); VIPS_GATE_STOP("vips__region_start: wait"); region->seq = image->start_fn(image, image->client1, image->client2); g_mutex_unlock(&image->sslock); if (!region->seq) { #ifdef DEBUG printf("vips__region_start: start function failed for image %s", image->filename); #endif /*DEBUG*/ return -1; } } return 0; } /* Call a stop function if a sequence is running in this VipsRegion. */ void vips__region_stop(VipsRegion *region) { VipsImage *image = region->im; if (region->seq && image->stop_fn) { int result; VIPS_GATE_START("vips__region_stop: wait"); g_mutex_lock(&image->sslock); VIPS_GATE_STOP("vips__region_stop: wait"); result = image->stop_fn(region->seq, image->client1, image->client2); g_mutex_unlock(&image->sslock); /* stop function can return an error, but we have nothing we * can really do with it, sadly. */ if (result) g_warning("stop callback failed for image %s", image->filename); region->seq = NULL; } } static void vips_region_dispose(GObject *gobject) { VipsRegion *region = VIPS_REGION(gobject); VipsImage *image = region->im; #ifdef VIPS_DEBUG VIPS_DEBUG_MSG("vips_region_dispose: "); vips_object_print_name(VIPS_OBJECT(gobject)); VIPS_DEBUG_MSG("\n"); #endif /*VIPS_DEBUG*/ vips_object_preclose(VIPS_OBJECT(gobject)); /* Stop this sequence. */ vips__region_stop(region); /* Free any attached memory. */ VIPS_FREEF(vips_window_unref, region->window); VIPS_FREEF(vips_buffer_unref, region->buffer); /* Detach from image. */ VIPS_GATE_START("vips_region_dispose: wait"); g_mutex_lock(&image->sslock); VIPS_GATE_STOP("vips_region_dispose: wait"); image->regions = g_slist_remove(image->regions, region); g_mutex_unlock(&image->sslock); region->im = NULL; g_object_unref(image); G_OBJECT_CLASS(vips_region_parent_class)->dispose(gobject); } static void vips_region_dump(VipsObject *object, VipsBuf *buf) { VipsRegion *region = VIPS_REGION(object); vips_buf_appendf(buf, "VipsRegion: %p, ", region); vips_buf_appendf(buf, "im = %p, ", region->im); vips_buf_appendf(buf, "valid.left = %d, ", region->valid.left); vips_buf_appendf(buf, "valid.top = %d, ", region->valid.top); vips_buf_appendf(buf, "valid.width = %d, ", region->valid.width); vips_buf_appendf(buf, "valid.height = %d, ", region->valid.height); vips_buf_appendf(buf, "type = %d, ", region->type); vips_buf_appendf(buf, "data = %p, ", region->data); vips_buf_appendf(buf, "bpl = %d, ", region->bpl); vips_buf_appendf(buf, "seq = %p, ", region->seq); vips_buf_appendf(buf, "thread = %p, ", region->thread); vips_buf_appendf(buf, "window = %p, ", region->window); vips_buf_appendf(buf, "buffer = %p, ", region->buffer); vips_buf_appendf(buf, "invalid = %d", region->invalid); VIPS_OBJECT_CLASS(vips_region_parent_class)->dump(object, buf); } static void vips_region_summary(VipsObject *object, VipsBuf *buf) { VipsRegion *region = VIPS_REGION(object); vips_buf_appendf(buf, "VipsRegion: %p, ", region); vips_buf_appendf(buf, "im = %p, ", region->im); vips_buf_appendf(buf, "left = %d, ", region->valid.left); vips_buf_appendf(buf, "top = %d, ", region->valid.top); vips_buf_appendf(buf, "width = %d, ", region->valid.width); vips_buf_appendf(buf, "height = %d", region->valid.height); if (region->buffer && region->buffer->buf) vips_buf_appendf(buf, ", %.3gMB", region->buffer->bsize / (1024 * 1024.0)); VIPS_OBJECT_CLASS(vips_region_parent_class)->summary(object, buf); } /* If a region is being created in one thread (eg. the main thread) and then * used in another (eg. a worker thread), the new thread needs to tell VIPS * to stop sanity g_assert() fails. The previous owner needs to * vips__region_no_ownership() before we can call this. */ void vips__region_take_ownership(VipsRegion *region) { /* Lock so that there's a memory barrier with the thread doing the * vips__region_no_ownership() before us. */ VIPS_GATE_START("vips__region_take_ownership: wait"); g_mutex_lock(®ion->im->sslock); VIPS_GATE_STOP("vips__region_take_ownership: wait"); if (region->thread != g_thread_self()) { g_assert(region->thread == NULL); /* We don't want to move shared buffers: the other region * using this buffer will still be on the other thread. * Not sure if this will ever happen: if it does, we'll * need to dup the buffer. */ g_assert(!region->buffer || region->buffer->ref_count == 1); region->thread = g_thread_self(); } g_mutex_unlock(®ion->im->sslock); } void vips__region_check_ownership(VipsRegion *region) { if (region->thread) { g_assert(region->thread == g_thread_self()); if (region->buffer && region->buffer->cache) g_assert(region->thread == region->buffer->cache->thread); } } /* Call this from the relinquishing thread. Removes the buffer (if any) from * this thread's buffer cache. */ void vips__region_no_ownership(VipsRegion *region) { VIPS_GATE_START("vips__region_no_ownership: wait"); g_mutex_lock(®ion->im->sslock); VIPS_GATE_STOP("vips__region_no_ownership: wait"); vips__region_check_ownership(region); region->thread = NULL; if (region->buffer) vips_buffer_undone(region->buffer); g_mutex_unlock(®ion->im->sslock); } static int vips_region_build(VipsObject *object) { VipsRegion *region = VIPS_REGION(object); VipsImage *image = region->im; VIPS_DEBUG_MSG("vips_region_build: %p\n", region); if (VIPS_OBJECT_CLASS(vips_region_parent_class)->build(object)) return -1; vips__region_take_ownership(region); /* We're usually inside the ss lock anyway. But be safe ... */ VIPS_GATE_START("vips_region_build: wait"); g_mutex_lock(&image->sslock); VIPS_GATE_STOP("vips_region_build: wait"); image->regions = g_slist_prepend(image->regions, region); g_mutex_unlock(&image->sslock); return 0; } static void vips_region_class_init(VipsRegionClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->finalize = vips_region_finalize; gobject_class->dispose = vips_region_dispose; vobject_class->summary = vips_region_summary; vobject_class->dump = vips_region_dump; vobject_class->build = vips_region_build; } static void vips_region_init(VipsRegion *region) { region->type = VIPS_REGION_NONE; #ifdef VIPS_DEBUG g_mutex_lock(&vips__global_lock); vips__regions_all = g_slist_prepend(vips__regions_all, region); printf("vips_region_init: %d regions in vips\n", g_slist_length(vips__regions_all)); g_mutex_unlock(&vips__global_lock); #endif /*VIPS_DEBUG*/ } /** * vips_region_new: (constructor) * @image: image to create this region on * * Create a region. [class@Region] start out empty, you need to call * [method@Region.prepare] to fill them with pixels. * * ::: seealso * [method@Region.prepare]. */ VipsRegion * vips_region_new(VipsImage *image) { VipsRegion *region; /* Ref quickly, we want to make sure we keep the image around. * We can't use the property system, we need to be very threaded. */ g_object_ref(image); g_assert(G_OBJECT(image)->ref_count > 1); g_assert(vips_object_sanity(VIPS_OBJECT(image))); region = VIPS_REGION(g_object_new(VIPS_TYPE_REGION, NULL)); region->im = image; if (vips_object_build(VIPS_OBJECT(region))) { VIPS_UNREF(region); return NULL; } g_assert(vips_object_sanity(VIPS_OBJECT(region))); return region; } /* Region should be a pixel buffer. On return, check * reg->buffer->done to see if there are pixels there already. Otherwise, you * need to calculate. */ /** * vips_region_buffer: * @reg: region to operate upon * @r: [struct@Rect] of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available as a * memory buffer that can be written to. * * Returns: 0 on success, or -1 for error. */ int vips_region_buffer(VipsRegion *reg, const VipsRect *r) { VipsImage *im = reg->im; VipsRect image; VipsRect clipped; vips__region_check_ownership(reg); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; vips_rect_intersectrect(r, &image, &clipped); /* Test for empty. */ if (vips_rect_isempty(&clipped)) { vips_error("VipsRegion", "%s", _("valid clipped to nothing")); return -1; } VIPS_FREEF(vips_window_unref, reg->window); /* Have we been asked to drop caches? We want to throw everything * away. * * If not, try to reuse the current buffer. */ if (reg->invalid) { VIPS_FREEF(vips_buffer_unref, reg->buffer); reg->invalid = FALSE; if (!(reg->buffer = vips_buffer_new(im, &clipped))) return -1; } else { /* We combine buffer unref and new buffer ref in one call * to reduce malloc/free cycling. */ if (!(reg->buffer = vips_buffer_unref_ref(reg->buffer, im, &clipped))) return -1; } /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = VIPS_IMAGE_SIZEOF_PEL(im) * reg->buffer->area.width; reg->type = VIPS_REGION_BUFFER; reg->data = reg->buffer->buf; return 0; } /** * vips_region_image: * @reg: region to operate upon * @r: [struct@Rect] of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available to be * read from the image. The image needs to be a memory buffer or represent a * file on disc that has been mapped or can be mapped. * * Returns: 0 on success, or -1 for error. */ int vips_region_image(VipsRegion *reg, const VipsRect *r) { VipsImage *image = reg->im; VipsRect all; VipsRect clipped; /* Sanity check. */ vips__region_check_ownership(reg); /* Clip against image. */ all.top = 0; all.left = 0; all.width = image->Xsize; all.height = image->Ysize; vips_rect_intersectrect(r, &all, &clipped); if (vips_rect_isempty(&clipped)) { vips_error("VipsRegion", "%s", _("valid clipped to nothing")); return -1; } reg->invalid = FALSE; VIPS_FREEF(vips_buffer_unref, reg->buffer); if (image->data) { /* We have the whole image available ... easy! */ VIPS_FREEF(vips_window_unref, reg->window); /* We can't just set valid = whole image, since this may be an * incompletely calculated memory buffer. Just set valid to r. */ reg->valid = clipped; reg->bpl = VIPS_IMAGE_SIZEOF_LINE(image); reg->data = VIPS_IMAGE_ADDR(image, clipped.left, clipped.top); reg->type = VIPS_REGION_OTHER_IMAGE; } else if (image->dtype == VIPS_IMAGE_OPENIN) { /* No complete image data ... but we can use a rolling window. */ reg->type = VIPS_REGION_WINDOW; if (!(reg->window = vips_window_take(reg->window, image, clipped.top, clipped.height))) return -1; /* Note the area the window actually represents. */ reg->valid.left = 0; reg->valid.top = reg->window->top; reg->valid.width = image->Xsize; reg->valid.height = reg->window->height; reg->bpl = VIPS_IMAGE_SIZEOF_LINE(image); reg->data = reg->window->data; } else { VIPS_FREEF(vips_window_unref, reg->window); vips_error("VipsRegion", "%s", _("bad image type")); return -1; } return 0; } /** * vips_region_region: * @reg: region to operate upon * @dest: region to connect to * @r: [struct@Rect] of pixels you need to be able to address * @x: position of @r in @dest * @y: position of @r in @dest * * Make [func@REGION_ADDR] on @reg go to @dest instead. * * @r is the part of @reg which you want to be able to address (this * effectively becomes the valid field), (@x, @y) is the top LH corner of the * corresponding area in @dest. * * Performs all clipping necessary to ensure that @reg->valid is indeed * valid. * * If the region we attach to is moved or destroyed, we can be left with * dangling pointers! If the region we attach to is on another image, the * two images must have the same sizeof(pel). * * Returns: 0 on success, or -1 for error. */ int vips_region_region(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y) { VipsRect image; VipsRect wanted; VipsRect clipped; VipsRect clipped2; VipsRect final; /* Sanity check. */ if (!dest->data) { vips_error("VipsRegion", "%s", _("no pixel data on attached image")); return -1; } if (VIPS_IMAGE_SIZEOF_PEL(dest->im) != VIPS_IMAGE_SIZEOF_PEL(reg->im)) { vips_error("VipsRegion", "%s", _("images do not match in pixel size")); return -1; } vips__region_check_ownership(reg); /* We can't test g_assert(dest->thread == g_thread_self()); * since we can have several threads writing to the same region in * threadgroup. */ /* Clip r against size of the image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; vips_rect_intersectrect(r, &image, &clipped); /* Translate to dest's coordinate space and clip against the available * pixels. */ wanted.left = x + (clipped.left - r->left); wanted.top = y + (clipped.top - r->top); wanted.width = clipped.width; wanted.height = clipped.height; /* Test that dest->valid is large enough. */ if (!vips_rect_includesrect(&dest->valid, &wanted)) { vips_error("VipsRegion", "%s", _("dest too small")); return -1; } /* Clip against the available pixels. */ vips_rect_intersectrect(&wanted, &dest->valid, &clipped2); /* Translate back to reg's coordinate space and set as valid. */ final.left = r->left + (clipped2.left - wanted.left); final.top = r->top + (clipped2.top - wanted.top); final.width = clipped2.width; final.height = clipped2.height; /* Test for empty. */ if (vips_rect_isempty(&final)) { vips_error("VipsRegion", "%s", _("valid clipped to nothing")); return -1; } /* Init new stuff. */ VIPS_FREEF(vips_buffer_unref, reg->buffer); VIPS_FREEF(vips_window_unref, reg->window); reg->invalid = FALSE; reg->valid = final; reg->bpl = dest->bpl; reg->data = VIPS_REGION_ADDR(dest, clipped2.left, clipped2.top); reg->type = VIPS_REGION_OTHER_REGION; return 0; } /** * vips_region_equalsregion: * @reg1: region to test * @reg2: region to test * * Do two regions point to the same piece of image? ie. * * ```c * VIPS_REGION_ADDR(reg1, x, y) == VIPS_REGION_ADDR(reg2, x, y) && * *VIPS_REGION_ADDR(reg1, x, y) == * *VIPS_REGION_ADDR(reg2, x, y) for all x, y, reg1, reg2. * ``` * * Returns: non-zero on equality. */ int vips_region_equalsregion(VipsRegion *reg1, VipsRegion *reg2) { return reg1->im == reg2->im && vips_rect_equalsrect(®1->valid, ®2->valid) && reg1->data == reg2->data; } /** * vips_region_position: * @reg: region to operate upon * @x: position to move to * @y: position to move to * * Set the position of a region. This only affects reg->valid, ie. the way * pixels are addressed, not reg->data, the pixels which are addressed. Clip * against the size of the image. Do not allow negative positions, or * positions outside the image. * * Returns: 0 on success, or -1 for error. */ int vips_region_position(VipsRegion *reg, int x, int y) { VipsRect req, image, clipped; /* Clip! */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; req.top = y; req.left = x; req.width = reg->valid.width; req.height = reg->valid.height; vips_rect_intersectrect(&image, &req, &clipped); if (x < 0 || y < 0 || vips_rect_isempty(&clipped)) { vips_error("VipsRegion", "%s", _("bad position")); return -1; } reg->valid = clipped; reg->invalid = FALSE; return 0; } int vips_region_fill(VipsRegion *reg, const VipsRect *r, VipsRegionFillFn fn, void *a) { g_assert(reg->im->dtype == VIPS_IMAGE_PARTIAL); g_assert(reg->im->generate_fn); /* You'd think we could check reg and see if it already has some of * the pixels we need. If it does, we could copy them and only * generate the new ones. * * However, we usually have neighbouring regions on different threads, * so from the point of view of this thread, we will get no overlaps * on successive prepare requests. */ /* Should have local memory. */ if (vips_region_buffer(reg, r)) return -1; /* Evaluate into out_region, if we've not got calculated pixels. */ if (!reg->buffer->done) { if (fn(reg, a)) return -1; /* Publish our results. */ if (reg->buffer) vips_buffer_done(reg->buffer); } return 0; } #define FILL_LINE(TYPE, Q, N, V) \ { \ int x; \ TYPE *QT = (TYPE *) Q; \ \ for (x = 0; x < (N); x++) \ QT[x] = (V); \ } /** * vips_region_paint: * @reg: region to operate upon * @r: area to paint * @value: value to paint * * Paints @value into @reg covering rectangle @r. * @r is clipped against * @reg->valid. * * For int images, @value is * passed to [`memset()`](man:memset(3)), so it usually needs to be 0 or 255. For float images, * value is cast to a float and copied in to each band element. * * @r is clipped against * @reg->valid. * * ::: seealso * [method@Region.black]. */ void vips_region_paint(VipsRegion *reg, const VipsRect *r, int value) { VipsRect clipped; vips_rect_intersectrect(r, ®->valid, &clipped); if (!vips_rect_isempty(&clipped)) { VipsPel *q = VIPS_REGION_ADDR(reg, clipped.left, clipped.top); size_t ls = VIPS_REGION_LSKIP(reg); size_t wd = clipped.width * VIPS_IMAGE_SIZEOF_PEL(reg->im); int y; if (vips_band_format_isint(reg->im->BandFmt)) { for (y = 0; y < clipped.height; y++) { memset((char *) q, value, wd); q += ls; } } else { gboolean iscomplex = vips_band_format_iscomplex(reg->im->BandFmt); int nele = clipped.width * reg->im->Bands * (iscomplex ? 2 : 1); VipsPel *q1; switch (reg->im->BandFmt) { case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: FILL_LINE(float, q, nele, value); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: FILL_LINE(double, q, nele, value); break; default: g_assert_not_reached(); } q1 = q + ls; for (y = 1; y < clipped.height; y++) { memcpy((char *) q1, (char *) q, wd); q1 += ls; } } } } /** * vips_region_paint_pel: * @reg: region to operate upon * @r: area to paint * @ink: value to paint * * Paints @ink into @reg covering rectangle @r. @r is clipped against * @reg->valid. * * @ink should be a byte array of the same size as an image pixel containing * the binary value to write into the pixels. * * ::: seealso * [method@Region.paint]. */ void vips_region_paint_pel(VipsRegion *reg, const VipsRect *r, const VipsPel *ink) { VipsRect ovl; vips_rect_intersectrect(r, ®->valid, &ovl); if (!vips_rect_isempty(&ovl)) { int ps = VIPS_IMAGE_SIZEOF_PEL(reg->im); int ws = ovl.width * ps; int ls = VIPS_REGION_LSKIP(reg); VipsPel *to, *q; int x, y, z; /* We plot the first line pointwise, then memcpy() it for the * subsequent lines. */ to = VIPS_REGION_ADDR(reg, ovl.left, ovl.top); q = to; for (x = 0; x < ovl.width; x++) { /* Faster than memcpy() for about n<20. */ for (z = 0; z < ps; z++) q[z] = ink[z]; q += ps; } q = to + ls; for (y = 1; y < ovl.height; y++) { memcpy(q, to, ws); q += ls; } } } /** * vips_region_black: * @reg: region to operate upon * * Paints 0 into the valid part of @reg. * * ::: seealso * [method@Region.paint]. */ void vips_region_black(VipsRegion *reg) { vips_region_paint(reg, ®->valid, 0); } /** * vips_region_copy: * @reg: source region * @dest: (inout): destination region * @r: [struct@Rect] of pixels you need to copy * @x: position of @r in @dest * @y: position of @r in @dest * * Copy from one region to another. Copy area @r from inside @reg to @dest, * positioning the area of pixels at @x, @y. The two regions must have pixels * which are the same size. * * ::: seealso * [method@Region.paint]. */ void vips_region_copy(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y) { size_t len = VIPS_IMAGE_SIZEOF_PEL(reg->im) * r->width; VipsPel *p = VIPS_REGION_ADDR(reg, r->left, r->top); VipsPel *q = VIPS_REGION_ADDR(dest, x, y); size_t plsk = VIPS_REGION_LSKIP(reg); size_t qlsk = VIPS_REGION_LSKIP(dest); int z; #ifdef DEBUG /* Find the area we will write to in dest. */ VipsRect output; printf("vips_region_copy: sanity check\n"); output.left = x; output.top = y; output.width = r->width; output.height = r->height; /* Must be inside dest->valid. */ g_assert(vips_rect_includesrect(&dest->valid, &output)); /* Check the area we are reading from in reg. */ g_assert(vips_rect_includesrect(®->valid, r)); /* VipsPel size must be the same. */ g_assert(VIPS_IMAGE_SIZEOF_PEL(reg->im) == VIPS_IMAGE_SIZEOF_PEL(dest->im)); #endif /*DEBUG*/ /* Copy the scanlines. * * Special case: if the two sets of scanlines are end-to-end (this * happens if we are copying complete regions) we can do a single * memcpy() for the whole thing. This is a little faster since we * won't have to do unaligned copies. */ if (len == plsk && len == qlsk) memcpy(q, p, len * r->height); else for (z = 0; z < r->height; z++) { memcpy(q, p, len); p += plsk; q += qlsk; } } /* Generate area @target in @to using pixels in @from. * * VIPS_CODING_LABQ only. */ static void vips_region_shrink_labpack(VipsRegion *from, VipsRegion *to, const VipsRect *target) { int ls = VIPS_REGION_LSKIP(from); int x, y; for (y = 0; y < target->height; y++) { VipsPel *p = VIPS_REGION_ADDR(from, target->left * 2, (target->top + y) * 2); VipsPel *q = VIPS_REGION_ADDR(to, target->left, target->top + y); /* Ignore the extra bits for speed. */ for (x = 0; x < target->width; x++) { signed char *sp = (signed char *) p; unsigned char *up = (unsigned char *) p; int l = up[0] + up[4] + up[ls] + up[ls + 4]; int a = sp[1] + sp[5] + sp[ls + 1] + sp[ls + 5]; int b = sp[2] + sp[6] + sp[ls + 2] + sp[ls + 6]; q[0] = (l + 2) >> 2; q[1] = a >> 2; q[2] = b >> 2; q[3] = 0; q += 4; p += 8; } } } #define SHRINK_TYPE_MEAN_INT(TYPE) \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) { \ int tot = tp[z] + tp[z + nb] + \ tp1[z] + tp1[z + nb]; \ \ tq[z] = (tot + 2) >> 2; \ } \ \ /* Move on two pels in input. \ */ \ p += ps << 1; \ q += ps; \ } #define SHRINK_TYPE_MEAN_FLOAT(TYPE) \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) { \ double tot = tp[z] + tp[z + nb] + \ tp1[z] + tp1[z + nb]; \ \ tq[z] = tot / 4; \ } \ \ /* Move on two pels in input. \ */ \ p += ps << 1; \ q += ps; \ } /* Generate area @target in @to using pixels in @from. Non-complex. */ static void vips_region_shrink_uncoded_mean(VipsRegion *from, VipsRegion *to, const VipsRect *target) { int ls = VIPS_REGION_LSKIP(from); int ps = VIPS_IMAGE_SIZEOF_PEL(from->im); int nb = from->im->Bands; int x, y, z; for (y = 0; y < target->height; y++) { VipsPel *p = VIPS_REGION_ADDR(from, target->left * 2, (target->top + y) * 2); VipsPel *q = VIPS_REGION_ADDR(to, target->left, target->top + y); /* Process this line of pels. */ switch (from->im->BandFmt) { case VIPS_FORMAT_UCHAR: SHRINK_TYPE_MEAN_INT(unsigned char); break; case VIPS_FORMAT_CHAR: SHRINK_TYPE_MEAN_INT(signed char); break; case VIPS_FORMAT_USHORT: SHRINK_TYPE_MEAN_INT(unsigned short); break; case VIPS_FORMAT_SHORT: SHRINK_TYPE_MEAN_INT(signed short); break; case VIPS_FORMAT_UINT: SHRINK_TYPE_MEAN_INT(unsigned int); break; case VIPS_FORMAT_INT: SHRINK_TYPE_MEAN_INT(signed int); break; case VIPS_FORMAT_FLOAT: SHRINK_TYPE_MEAN_FLOAT(float); break; case VIPS_FORMAT_DOUBLE: SHRINK_TYPE_MEAN_FLOAT(double); break; default: g_assert_not_reached(); } } } /* This method is implemented so as to perform well and to always select an * output pixel from one of the input pixels. As such we make only the * following guarantees: * * ONLY works for non-complex uncoded images pixel types * ALWAYS draws from the input values * NEVER interpolates * NOT stable with respect to the ordered set of input values * IS stable with respect to the initial arrangement of input values */ #define SHRINK_TYPE_MEDIAN(TYPE) \ { \ int ls = VIPS_REGION_LSKIP(from); \ \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) { \ tq[z] = VIPS_MIN( \ VIPS_MAX(tp[z], tp[z + nb]), \ VIPS_MAX(tp1[z], tp1[z + nb])); \ } \ \ /* Move on two pels in input. \ */ \ p += ps << 1; \ q += ps; \ } \ } /* This method is implemented so as to perform well and to always select an * output pixel from one of the input pixels. As such we make only the * following guarantees: * * ONLY works for non-complex uncoded images pixel types * ALWAYS draws from the input values * NEVER interpolates * NOT stable with respect to the ordered set of input values * IS stable with respect to the initial arrangement of input values */ #define SHRINK_TYPE_MODE(TYPE) \ { \ int ls = VIPS_REGION_LSKIP(from); \ \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) { \ TYPE v[] = { tp[z], tp[z + nb], tp1[z], tp1[z + nb] }; \ int b0 = (v[0] == v[1]) | \ (v[0] == v[2]) | \ (v[0] == v[3]); \ int b1 = (v[1] == v[0]) | \ (v[1] == v[2]) | \ (v[1] == v[3]); \ int index = ((~b0) & 0x1) + (~(b0 ^ b1) & 0x1); \ \ tq[z] = v[index]; \ } \ \ p += ps << 1; \ q += ps; \ } \ } #define SHRINK_TYPE_MAX(TYPE) \ { \ int ls = VIPS_REGION_LSKIP(from); \ \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) { \ tq[z] = VIPS_MAX( \ VIPS_MAX(tp[z], tp[z + nb]), \ VIPS_MAX(tp1[z], tp1[z + nb])); \ } \ \ p += ps << 1; \ q += ps; \ } \ } #define SHRINK_TYPE_MIN(TYPE) \ { \ int ls = VIPS_REGION_LSKIP(from); \ \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) { \ tq[z] = VIPS_MIN( \ VIPS_MIN(tp[z], tp[z + nb]), \ VIPS_MIN(tp1[z], tp1[z + nb])); \ } \ \ p += ps << 1; \ q += ps; \ } \ } #define SHRINK_TYPE_NEAREST(TYPE) \ { \ for (x = 0; x < target->width; x++) { \ TYPE *tp = (TYPE *) p; \ TYPE *tq = (TYPE *) q; \ \ for (z = 0; z < nb; z++) \ tq[z] = tp[z]; \ \ p += ps << 1; \ q += ps; \ } \ } #define VIPS_REGION_SHRINK(OP) \ static void \ vips_region_shrink_uncoded_##OP(VipsRegion *from, \ VipsRegion *to, const VipsRect *target) \ { \ int ps = VIPS_IMAGE_SIZEOF_PEL(from->im); \ int nb = from->im->Bands; \ \ int x, y, z; \ \ for (y = 0; y < target->height; y++) { \ VipsPel *p = VIPS_REGION_ADDR(from, \ target->left * 2, (target->top + y) * 2); \ VipsPel *q = VIPS_REGION_ADDR(to, \ target->left, target->top + y); \ \ /* Process this line of pels. \ */ \ switch (from->im->BandFmt) { \ case VIPS_FORMAT_UCHAR: \ SHRINK_TYPE_##OP(unsigned char); \ break; \ case VIPS_FORMAT_CHAR: \ SHRINK_TYPE_##OP(signed char); \ break; \ case VIPS_FORMAT_USHORT: \ SHRINK_TYPE_##OP(unsigned short); \ break; \ case VIPS_FORMAT_SHORT: \ SHRINK_TYPE_##OP(signed short); \ break; \ case VIPS_FORMAT_UINT: \ SHRINK_TYPE_##OP(unsigned int); \ break; \ case VIPS_FORMAT_INT: \ SHRINK_TYPE_##OP(signed int); \ break; \ case VIPS_FORMAT_FLOAT: \ SHRINK_TYPE_##OP(float); \ break; \ case VIPS_FORMAT_DOUBLE: \ SHRINK_TYPE_##OP(double); \ break; \ \ default: \ g_assert_not_reached(); \ } \ } \ } VIPS_REGION_SHRINK(MAX); VIPS_REGION_SHRINK(MIN); VIPS_REGION_SHRINK(MODE); VIPS_REGION_SHRINK(MEDIAN); VIPS_REGION_SHRINK(NEAREST); /* Generate area @target in @to using pixels in @from. Non-complex. */ static void vips_region_shrink_uncoded(VipsRegion *from, VipsRegion *to, const VipsRect *target, VipsRegionShrink method) { switch (method) { case VIPS_REGION_SHRINK_MEAN: vips_region_shrink_uncoded_mean(from, to, target); break; case VIPS_REGION_SHRINK_MEDIAN: vips_region_shrink_uncoded_MEDIAN(from, to, target); break; case VIPS_REGION_SHRINK_MODE: vips_region_shrink_uncoded_MODE(from, to, target); break; case VIPS_REGION_SHRINK_MAX: vips_region_shrink_uncoded_MAX(from, to, target); break; case VIPS_REGION_SHRINK_MIN: vips_region_shrink_uncoded_MIN(from, to, target); break; case VIPS_REGION_SHRINK_NEAREST: vips_region_shrink_uncoded_NEAREST(from, to, target); break; default: g_assert_not_reached(); } } /* No point having an int path, this will always be horribly slow. */ #define SHRINK_ALPHA_TYPE(TYPE) \ { \ TYPE *tp = (TYPE *) p; \ TYPE *tp1 = (TYPE *) (p + ls); \ TYPE *tq = (TYPE *) q; \ \ for (x = 0; x < target->width; x++) { \ /* Make the input alphas. \ */ \ double a1 = tp[nb - 1]; \ double a2 = tp[nb + nb - 1]; \ double a3 = tp1[nb - 1]; \ double a4 = tp1[nb + nb - 1]; \ \ /* Output alpha. \ */ \ double a = (a1 + a2 + a3 + a4) / 4.0; \ \ if (a == 0) { \ for (z = 0; z < nb; z++) \ tq[z] = 0; \ } \ else { \ for (z = 0; z < nb - 1; z++) \ tq[z] = (a1 * tp[z] + a2 * tp[z + nb] + \ a3 * tp1[z] + a4 * tp1[z + nb]) / \ (4.0 * a); \ tq[z] = a; \ } \ \ /* Move on two pels in input. \ */ \ tp += nb << 1; \ tp1 += nb << 1; \ tq += nb; \ } \ } /* Generate area @target in @to using pixels in @from. Non-complex. Use the * last band as alpha. */ static void vips_region_shrink_alpha(VipsRegion *from, VipsRegion *to, const VipsRect *target) { int ls = VIPS_REGION_LSKIP(from); int nb = from->im->Bands; int x, y, z; for (y = 0; y < target->height; y++) { VipsPel *p = VIPS_REGION_ADDR(from, target->left * 2, (target->top + y) * 2); VipsPel *q = VIPS_REGION_ADDR(to, target->left, target->top + y); /* Process this line of pels. */ switch (from->im->BandFmt) { case VIPS_FORMAT_UCHAR: SHRINK_ALPHA_TYPE(unsigned char); break; case VIPS_FORMAT_CHAR: SHRINK_ALPHA_TYPE(signed char); break; case VIPS_FORMAT_USHORT: SHRINK_ALPHA_TYPE(unsigned short); break; case VIPS_FORMAT_SHORT: SHRINK_ALPHA_TYPE(signed short); break; case VIPS_FORMAT_UINT: SHRINK_ALPHA_TYPE(unsigned int); break; case VIPS_FORMAT_INT: SHRINK_ALPHA_TYPE(signed int); break; case VIPS_FORMAT_FLOAT: SHRINK_ALPHA_TYPE(float); break; case VIPS_FORMAT_DOUBLE: SHRINK_ALPHA_TYPE(double); break; default: g_assert_not_reached(); } } } /** * vips_region_shrink_method: * @from: source region * @to: (inout): destination region * @target: [struct@Rect] of pixels you need to copy * @method: method to use when generating target pixels * * Write the pixels @target in @to from the x2 larger area in @from. * Non-complex uncoded images and LABQ only. * * @method selects the method used to do the 2x2 shrink. * * ::: seealso * [method@Region.copy]. */ int vips_region_shrink_method(VipsRegion *from, VipsRegion *to, const VipsRect *target, VipsRegionShrink method) { VipsImage *image = from->im; if (vips_check_coding_noneorlabq("vips_region_shrink_method", image)) return -1; if (from->im->Coding == VIPS_CODING_NONE) { if (vips_check_noncomplex("vips_region_shrink_method", image)) return -1; if (vips_image_hasalpha(image)) vips_region_shrink_alpha(from, to, target); else vips_region_shrink_uncoded(from, to, target, method); } else vips_region_shrink_labpack(from, to, target); return 0; } /** * vips_region_shrink: (skip) * @from: source region * @to: (inout): destination region * @target: [struct@Rect] of pixels you need to copy * * Write the pixels @target in @to from the x2 larger area in @from. * Non-complex uncoded images and LABQ only. Images with alpha (see * [method@Image.hasalpha]) shrink with pixels scaled by alpha to avoid fringing. * * This is a compatibility stub that just calls [method@Region.shrink_method]. * * ::: seealso * [method@Region.shrink_method]. */ int vips_region_shrink(VipsRegion *from, VipsRegion *to, const VipsRect *target) { return vips_region_shrink_method(from, to, target, VIPS_REGION_SHRINK_MEAN); } /* Generate into a region. */ static int vips_region_generate(VipsRegion *reg, void *a) { VipsImage *im = reg->im; gboolean stop; /* Start new sequence, if necessary. */ if (vips__region_start(reg)) return -1; /* Ask for evaluation. */ stop = FALSE; if (im->generate_fn(reg, reg->seq, im->client1, im->client2, &stop)) return -1; if (stop) { vips_error("vips_region_generate", "%s", _("stop requested")); return -1; } return 0; } /** * vips_region_prepare: * @reg: region to prepare * @r: [struct@Rect] of pixels you need to be able to address * * [method@Region.prepare] fills @reg with pixels. After calling, * you can address at least the area @r with [func@REGION_ADDR] and get * valid pixels. * * [method@Region.prepare] runs in-line, that is, computation is done by * the calling thread, no new threads are involved, and computation * blocks until the pixels are ready. * * Use [method@Image.sink_screen] to calculate an area of pixels in the * background. * * ::: seealso * [method@Image.sink_screen], [method@Region.prepare_to]. * * Returns: 0 on success, or -1 on error. */ int vips_region_prepare(VipsRegion *reg, const VipsRect *r) { VipsImage *im = reg->im; VipsRect save = *r; vips__region_check_ownership(reg); if (vips_image_iskilled(im)) return -1; /* We use save for sanity checking valid: we test at the end that the * pixels we have generated are indeed all the ones that were asked * for. * * However, r may be clipped by the image size, so we need to clip * save as well to make sure we don't fail the assert due to that. */ { VipsRect image; image.left = 0; image.top = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; vips_rect_intersectrect(&save, &image, &save); } #ifdef DEBUG printf("vips_region_prepare: " "left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG*/ switch (im->dtype) { case VIPS_IMAGE_PARTIAL: if (vips_region_fill(reg, r, vips_region_generate, NULL)) return -1; break; case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: case VIPS_IMAGE_MMAPIN: case VIPS_IMAGE_MMAPINRW: case VIPS_IMAGE_OPENIN: /* Attach to existing buffer. */ if (vips_region_image(reg, r)) return -1; break; default: vips_error("vips_region_prepare", _("unable to input from a %s image"), vips_enum_string(VIPS_TYPE_IMAGE_TYPE, im->dtype)); return -1; } /* valid should now include all the pixels that were asked for. */ g_assert(vips_rect_includesrect(®->valid, &save)); return 0; } /* We need to make pixels using reg's generate function, and write the result * to dest. */ static int vips_region_prepare_to_generate(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y) { VipsImage *im = reg->im; VipsPel *p; if (!im->generate_fn) { vips_error("vips_region_prepare_to", "%s", _("incomplete header")); return -1; } if (vips_region_region(reg, dest, r, x, y)) return -1; /* Remember where reg is pointing now. */ p = VIPS_REGION_ADDR(reg, reg->valid.left, reg->valid.top); /* Run sequence into reg. */ if (vips_region_generate(reg, NULL)) return -1; /* The generate function may not have actually made any pixels ... it * might just have redirected reg to point somewhere else. If it has, * we need an extra copy operation. */ if (VIPS_REGION_ADDR(reg, reg->valid.left, reg->valid.top) != p) vips_region_copy(reg, dest, r, x, y); return 0; } /** * vips_region_prepare_to: * @reg: region to prepare * @dest: region to write to * @r: [struct@Rect] of pixels you need to be able to address * @x: position of @r in @dest * @y: position of @r in @dest * * Like [method@Region.prepare]: fill @reg with the pixels in area @r. * * Unlike [method@Region.prepare], rather than writing the result to @reg, the * pixels are written into @dest at offset @x, @y. * * Also unlike [method@Region.prepare], @dest is not set up for writing for * you with [method@Region.buffer]. You can * point @dest at anything, and pixels really will be written there. * This makes [method@Region.prepare_to] useful for making the ends of * pipelines. * * ::: seealso * [method@Region.prepare], [method@Image.sink_disc]. * * Returns: 0 on success, or -1 on error */ int vips_region_prepare_to(VipsRegion *reg, VipsRegion *dest, const VipsRect *r, int x, int y) { VipsImage *im = reg->im; VipsRect image; VipsRect wanted; VipsRect clipped; VipsRect clipped2; VipsRect final; if (vips_image_iskilled(im)) return -1; /* Sanity check. */ if (!dest->data || dest->im->BandFmt != reg->im->BandFmt || dest->im->Bands != reg->im->Bands) { vips_error("vips_region_prepare_to", "%s", _("inappropriate region type")); return -1; } /* clip r first against the size of reg->im, then again against the * memory we have available to write to on dest. Just like * vips_region_region() */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; vips_rect_intersectrect(r, &image, &clipped); g_assert(clipped.left == r->left); g_assert(clipped.top == r->top); wanted.left = x + (clipped.left - r->left); wanted.top = y + (clipped.top - r->top); wanted.width = clipped.width; wanted.height = clipped.height; /* Test that dest->valid is large enough. */ if (!vips_rect_includesrect(&dest->valid, &wanted)) { vips_error("vips_region_prepare_to", "%s", _("dest too small")); return -1; } vips_rect_intersectrect(&wanted, &dest->valid, &clipped2); /* Translate back to reg's coordinate space and set as valid. */ final.left = r->left + (clipped2.left - wanted.left); final.top = r->top + (clipped2.top - wanted.top); final.width = clipped2.width; final.height = clipped2.height; x = clipped2.left; y = clipped2.top; if (vips_rect_isempty(&final)) { vips_error("vips_region_prepare_to", "%s", _("valid clipped to nothing")); return -1; } #ifdef DEBUG printf("vips_region_prepare_to: " "left = %d, top = %d, width = %d, height = %d\n", final.left, final.top, final.width, final.height); #endif /*DEBUG*/ /* Input or output image type? */ switch (im->dtype) { case VIPS_IMAGE_OPENOUT: case VIPS_IMAGE_PARTIAL: /* We are generating with a sequence. */ if (vips_region_prepare_to_generate(reg, dest, &final, x, y)) return -1; break; case VIPS_IMAGE_MMAPIN: case VIPS_IMAGE_MMAPINRW: case VIPS_IMAGE_OPENIN: /* Attach to existing buffer and copy to dest. */ if (vips_region_image(reg, &final)) return -1; vips_region_copy(reg, dest, &final, x, y); break; case VIPS_IMAGE_SETBUF: case VIPS_IMAGE_SETBUF_FOREIGN: /* Could be either input or output. If there is a generate * function, we are outputting. */ if (im->generate_fn) { if (vips_region_prepare_to_generate(reg, dest, &final, x, y)) return -1; } else { if (vips_region_image(reg, &final)) return -1; vips_region_copy(reg, dest, &final, x, y); } break; default: vips_error("vips_region_prepare_to", _("unable to input from a %s image"), vips_enum_nick(VIPS_TYPE_IMAGE_TYPE, im->dtype)); return -1; } /* We've written fresh pixels to dest, it's no longer invalid (if it * was). * * We need this extra thing here because, unlike * vips_region_prepare(), we don't vips_region_buffer() dest before * writing it. */ dest->invalid = FALSE; return 0; } /* Don't use this, use vips_reorder_prepare_many() instead. */ int vips_region_prepare_many(VipsRegion **reg, const VipsRect *r) { for (; *reg; ++reg) if (vips_region_prepare(*reg, r)) return -1; return 0; } /** * vips_region_fetch: * @region: region to fetch pixels from * @left: area of pixels to fetch * @top: area of pixels to fetch * @width: area of pixels to fetch * @height: area of pixels to fetch * * Generate an area of pixels and return a copy. The result must be freed * with [func@GLib.free]. The requested area must be completely inside the * image. * * This is equivalent to [method@Region.prepare], followed by a memcpy. It is * convenient for language bindings. * * Returns: A copy of the pixel data. */ VipsPel * vips_region_fetch(VipsRegion *region, int left, int top, int width, int height, size_t *len) { VipsRect request; VipsRect image; int y; VipsPel *result; VipsPel *p, *q; size_t skip; size_t line; g_assert(width > 0); g_assert(height > 0); image.left = 0; image.top = 0; image.width = region->im->Xsize; image.height = region->im->Ysize; request.left = left; request.top = top; request.width = width; request.height = height; if (!vips_rect_includesrect(&image, &request)) return NULL; if (vips_region_prepare(region, &request)) return NULL; skip = VIPS_REGION_LSKIP(region); line = VIPS_IMAGE_SIZEOF_PEL(region->im) * request.width; if (!(result = (VipsPel *) vips_malloc(NULL, line * request.height))) return NULL; p = VIPS_REGION_ADDR(region, request.left, request.top); q = result; for (y = 0; y < request.height; y++) { memcpy(q, p, line); p += skip; q += line; } if (len) *len = request.height * line; return result; } /** * vips_region_width: * @region: fetch width from this * * Returns: Width of the pixels held in region. */ int vips_region_width(VipsRegion *region) { return region->valid.width; } /** * vips_region_height: * @region: fetch height from this * * Returns: Height of the pixels held in region. */ int vips_region_height(VipsRegion *region) { return region->valid.height; } /** * vips_region_invalidate: * @reg: region to invalidate * * Mark a region as containing invalid pixels. Calling this function means * that the next time [method@Region.prepare] is called, the region will be * recalculated. * * This is faster than calling [method@Image.invalidate_all], but obviously only * affects a single region. * * ::: seealso * [method@Image.invalidate_all], [method@Region.prepare]. */ void vips_region_invalidate(VipsRegion *reg) { reg->invalid = TRUE; } #ifdef VIPS_DEBUG static void * vips_region_dump_all_cb(VipsRegion *region, size_t *alive, void *b) { char str[2048]; VipsBuf buf = VIPS_BUF_STATIC(str); vips_object_summary(VIPS_OBJECT(region), &buf); printf("%s\n", vips_buf_all(&buf)); if (region->buffer && region->buffer->buf) *alive += region->buffer->bsize; return NULL; } void vips_region_dump_all(void) { size_t alive; g_mutex_lock(&vips__global_lock); alive = 0; printf("%d regions in vips\n", g_slist_length(vips__regions_all)); vips_slist_map2(vips__regions_all, (VipsSListMap2Fn) vips_region_dump_all_cb, &alive, NULL); printf("%gMB alive\n", alive / (1024 * 1024.0)); g_mutex_unlock(&vips__global_lock); } #endif /*VIPS_DEBUG*/ #ifdef DEBUG_LEAK void vips__region_count_pixels(VipsRegion *region, const char *nickname) { VipsImage *image = region->im; VipsImagePixels *pixels = g_object_get_qdata(G_OBJECT(image), vips__image_pixels_quark); g_mutex_lock(&vips__global_lock); if (!pixels->tpels) pixels->tpels = VIPS_IMAGE_N_PELS(image); if (!pixels->nickname) pixels->nickname = nickname; pixels->npels += region->valid.width * region->valid.height; g_mutex_unlock(&vips__global_lock); } #endif /*DEBUG_LEAK*/ libvips-8.18.2/libvips/iofuncs/reorder.c000066400000000000000000000230301516303661500202120ustar00rootroot00000000000000/* reorder.c ... manage reorder reordering * * 11/1/17 * - first version */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include /* Have one of these on every image, identified by a quark. */ typedef struct _VipsReorder { /* The image we are attached to. */ VipsImage *image; /* The direct inputs to this image, so a copy of the array that is * passed to vips_image_pipeline_array(), and in the same order. * NULL-terminated. * * Score is the priority we give to the inputs as we de-dupe the source * arrays. * * The recomp order is the order we prepare regions in ... just make a * range then sort by score. */ int n_inputs; VipsImage **input; int *score; int *recomp_order; /* Source images are images with no input images, so file load, * vips_black(), etc. NULL-terminated array. * * The cumulative margin is the total margin that has been added to * each source image up to this point in the pipeline. */ int n_sources; VipsImage **source; int *cumulative_margin; } VipsReorder; GQuark vips__image_reorder_quark = 0; #ifdef DEBUG static void vips_reorder_print(VipsReorder *reorder) { int i; printf("vips_reorder_print: "); vips_object_print_name(VIPS_OBJECT(reorder->image)); printf("\n"); printf("n_inputs = %d\n", reorder->n_inputs); printf(" n score order\n"); for (i = 0; i < reorder->n_inputs; i++) { printf("%2d - %8d, %8d, ", i, reorder->score[i], reorder->recomp_order[i]); vips_object_print_name(VIPS_OBJECT(reorder->input[i])); printf("\n"); } printf("n_sources = %d\n", reorder->n_sources); printf(" n margin\n"); for (i = 0; i < reorder->n_sources; i++) { printf("%2d - %8d, ", i, reorder->cumulative_margin[i]); vips_object_print_name(VIPS_OBJECT(reorder->source[i])); printf("\n"); } } #endif /*DEBUG*/ static void vips_reorder_free(VipsReorder *reorder) { /* We free explicitly, rather than using VIPS_ARRAY(image, ...), since * we need to make sure these pointers are valid to this point in the * close cycle. */ VIPS_FREE(reorder->input); VIPS_FREE(reorder->score); VIPS_FREE(reorder->recomp_order); VIPS_FREE(reorder->source); VIPS_FREE(reorder->cumulative_margin); } static void vips_reorder_destroy(VipsReorder *reorder) { vips_reorder_free(reorder); VIPS_FREE(reorder); } static VipsReorder * vips_reorder_get(VipsImage *image) { VipsReorder *reorder; if ((reorder = g_object_get_qdata(G_OBJECT(image), vips__image_reorder_quark))) return reorder; reorder = VIPS_NEW(NULL, VipsReorder); reorder->image = image; reorder->n_inputs = 0; reorder->input = NULL; reorder->score = NULL; reorder->recomp_order = NULL; reorder->n_sources = 0; reorder->source = NULL; reorder->cumulative_margin = NULL; g_object_set_qdata_full(G_OBJECT(image), vips__image_reorder_quark, reorder, (GDestroyNotify) vips_reorder_destroy); return reorder; } static int vips_reorder_compare_score(const void *a, const void *b, void *arg) { int i1 = *((int *) a); int i2 = *((int *) b); VipsReorder *reorder = (VipsReorder *) arg; return reorder->score[i2] - reorder->score[i1]; } int vips__reorder_set_input(VipsImage *image, VipsImage **in) { VipsReorder *reorder = vips_reorder_get(image); int i; int total; /* We have to support being called more than once on the same image. * Two cases: * * 1. in the first call, no images were set ... we throw away * everything from the first call and try again. foreign can do this. * * 2. warn if the args were different and do nothing. */ if (reorder->source) { if (reorder->n_inputs == 0) { reorder->n_sources = 0; vips_reorder_free(reorder); } else { for (i = 0; in[i]; i++) if (i >= reorder->n_inputs || in[i] != reorder->input[i]) { /* Should never happen. */ g_warning("vips__reorder_set_input: args differ\n"); break; } return 0; } } /* Make a copy of the input array. */ for (i = 0; in[i]; i++) ; reorder->n_inputs = i; reorder->input = VIPS_ARRAY(NULL, reorder->n_inputs + 1, VipsImage *); reorder->score = VIPS_ARRAY(NULL, reorder->n_inputs, int); reorder->recomp_order = VIPS_ARRAY(NULL, reorder->n_inputs, int); if (!reorder->input) return -1; if (reorder->n_inputs && (!reorder->score || !reorder->recomp_order)) return -1; for (i = 0; i < reorder->n_inputs; i++) { reorder->input[i] = in[i]; reorder->score[i] = 0; reorder->recomp_order[i] = i; } reorder->input[i] = NULL; /* Find the total number of source images -- this gives an upper bound * to the size of the unique source image array we will need. */ total = 0; for (i = 0; i < reorder->n_inputs; i++) total += vips_reorder_get(reorder->input[i])->n_sources; /* No source images means this must itself be a source image, so it has * a source image of itself. */ total = VIPS_MAX(1, total); reorder->source = VIPS_ARRAY(NULL, total + 1, VipsImage *); reorder->cumulative_margin = VIPS_ARRAY(NULL, total, int); if (!reorder->source || !reorder->cumulative_margin) return -1; /* Copy source images over, removing duplicates. If we find a * duplicate, we have a reordering opportunity, and we adjust the * scores of the two images containing the dupe. */ for (i = 0; i < reorder->n_inputs; i++) { VipsReorder *input = vips_reorder_get(reorder->input[i]); int j; for (j = 0; j < input->n_sources; j++) { int k; /* Search for dupe. */ for (k = 0; k < reorder->n_sources; k++) if (reorder->source[k] == input->source[j]) break; if (k < reorder->n_sources) { /* Found a dupe. Does this new use of * input->source[j] have a larger or smaller * margin? Adjust the score to reflect the * change, note the new max. */ reorder->score[i] += input->cumulative_margin[j] - reorder->cumulative_margin[k]; reorder->cumulative_margin[k] = VIPS_MAX( reorder->cumulative_margin[k], input->cumulative_margin[j]); } else { /* No dupe, just add to the table. */ reorder->source[reorder->n_sources] = input->source[j]; reorder->cumulative_margin[reorder->n_sources] = input->cumulative_margin[j]; reorder->n_sources += 1; } } } /* Sort recomp_order by score. qsort_r() is a GNU libc thing, don't use * it. */ if (reorder->n_inputs > 1) #if GLIB_CHECK_VERSION(2, 82, 0) g_sort_array #else g_qsort_with_data #endif (reorder->recomp_order, reorder->n_inputs, sizeof(int), vips_reorder_compare_score, reorder); /* No sources ... make one, us! */ if (reorder->n_inputs == 0) { reorder->source[0] = image; reorder->cumulative_margin[0] = 0; reorder->n_sources = 1; } #ifdef DEBUG vips_reorder_print(reorder); #endif /*DEBUG*/ return 0; } /** * vips_reorder_prepare_many: (method) * @image: the image that's being written * @regions: (array): the set of regions to prepare * @r: the [struct@Rect] to prepare on each region * * [method@Image.reorder_prepare_many] runs [method@Region.prepare] on each * region in @regions, requesting the pixels in @r. * * It tries to request the regions in the order which will cause least * recomputation. This can give a large speedup, in some cases. * * ::: seealso * [method@Region.prepare], [method@Image.reorder_margin_hint]. * * Returns: 0 on success, or -1 on error. */ int vips_reorder_prepare_many(VipsImage *image, VipsRegion **regions, VipsRect *r) { VipsReorder *reorder = vips_reorder_get(image); int i; for (i = 0; i < reorder->n_inputs; i++) { g_assert(regions[i]); if (vips_region_prepare( regions[reorder->recomp_order[i]], r)) return -1; } return 0; } /** * vips_reorder_margin_hint: (method) * @image: the image to hint on * @margin: the size of the margin this operation has added * * [method@Image.reorder_margin_hint] sets a hint that @image contains a * margin, that is, that each [method@Region.prepare] on @image will request * a slightly larger region from it's inputs. A good value for @margin is * (width * height) for the window the operation uses. * * This information is used by [method@Image.reorder_prepare_many] to attempt to * reorder computations to minimise recomputation. * * ::: seealso * [method@Image.reorder_prepare_many]. */ void vips_reorder_margin_hint(VipsImage *image, int margin) { VipsReorder *reorder = vips_reorder_get(image); int i; for (i = 0; i < reorder->n_sources; i++) reorder->cumulative_margin[i] += margin; } void vips__reorder_clear(VipsImage *image) { g_object_set_qdata(G_OBJECT(image), vips__image_reorder_quark, NULL); } void vips__reorder_init(void) { if (!vips__image_reorder_quark) vips__image_reorder_quark = g_quark_from_static_string("vips-image-reorder"); } libvips-8.18.2/libvips/iofuncs/sbuf.c000066400000000000000000000277661516303661500175330ustar00rootroot00000000000000/* Buffered input from a source. * * J.Cupitt, 18/11/19 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #include #include /** * VipsSbuf: * * A [class@Sbuf] provides a buffered reading interface for a [class@Source]. * * You can fetch lines of text, skip whitespace, and so on. * * It is useful for implementing things like CSV readers, for example. */ G_DEFINE_TYPE(VipsSbuf, vips_sbuf, VIPS_TYPE_OBJECT); static void vips_sbuf_class_init(VipsSbufClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); GObjectClass *gobject_class = G_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "sbuf"; object_class->description = _("buffered source"); VIPS_ARG_OBJECT(class, "input", 1, _("Input"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSbuf, source), VIPS_TYPE_SOURCE); } static void vips_sbuf_init(VipsSbuf *sbuf) { sbuf->read_point = 0; sbuf->chars_in_buffer = 0; sbuf->input_buffer[0] = '\0'; } /** * vips_sbuf_new_from_source: * @source: source to operate on * * Create a [class@Sbuf] wrapping a source. * * Returns: a new [class@Sbuf] */ VipsSbuf * vips_sbuf_new_from_source(VipsSource *source) { VipsSbuf *sbuf; g_assert(source); sbuf = VIPS_SBUF(g_object_new(VIPS_TYPE_SBUF, "input", source, NULL)); if (vips_object_build(VIPS_OBJECT(sbuf))) { VIPS_UNREF(sbuf); return NULL; } return sbuf; } /** * vips_sbuf_unbuffer: * @sbuf: source to operate on * * Discard the input buffer and reset the read point. You must call this * before using read or seek on the underlying [class@Source] class. */ void vips_sbuf_unbuffer(VipsSbuf *sbuf) { /* We'd read ahead a little way -- seek backwards by that amount. */ vips_source_seek(sbuf->source, sbuf->read_point - sbuf->chars_in_buffer, SEEK_CUR); sbuf->read_point = 0; sbuf->chars_in_buffer = 0; } /* Returns -1 on error, 0 on EOF, otherwise bytes read. */ static gint64 vips_sbuf_refill(VipsSbuf *sbuf) { gint64 bytes_read; VIPS_DEBUG_MSG("vips_sbuf_refill:\n"); /* We should not discard any unread bytes. */ g_assert(sbuf->read_point == sbuf->chars_in_buffer); bytes_read = vips_source_read(sbuf->source, sbuf->input_buffer, VIPS_SBUF_BUFFER_SIZE); if (bytes_read == -1) return -1; sbuf->read_point = 0; sbuf->chars_in_buffer = bytes_read; /* Always add a null byte so we can use strchr() etc. on lines. This is * safe because input_buffer is VIPS_SBUF_BUFFER_SIZE + 1 bytes. */ sbuf->input_buffer[bytes_read] = '\0'; return bytes_read; } /** * vips_sbuf_getc: * @sbuf: source to operate on * * Fetch the next character from the source. * * If you can, use the macro [func@SBUF_GETC] instead for speed. * * Returns: the next char from @sbuf, -1 on read error or EOF. */ int vips_sbuf_getc(VipsSbuf *sbuf) { if (sbuf->read_point == sbuf->chars_in_buffer && vips_sbuf_refill(sbuf) <= 0) return -1; g_assert(sbuf->read_point < sbuf->chars_in_buffer); return sbuf->input_buffer[sbuf->read_point++]; } /** * VIPS_SBUF_GETC: * @sbuf: source to operate on * * Fetch the next character from the source. * * Returns: the next char from @sbuf, -1 on read error or EOF. */ /** * vips_sbuf_ungetc: * @sbuf: source to operate on * * The opposite of [method@Sbuf.getc]: undo the previous getc. * * unget more than one character is undefined. Unget at the start of the file * does nothing. * * If you can, use the macro [func@SBUF_UNGETC] instead for speed. */ void vips_sbuf_ungetc(VipsSbuf *sbuf) { if (sbuf->read_point > 0) sbuf->read_point -= 1; } /** * VIPS_SBUF_UNGETC: * @sbuf: source to operate on * * The opposite of [method@Sbuf.getc]: undo the previous getc. * * unget more than one character is undefined. Unget at the start of the file * does nothing. */ /** * vips_sbuf_require: * @sbuf: source to operate on * @require: make sure we have at least this many chars available * * Make sure there are at least @require bytes of readahead available. * * Returns: 0 on success, -1 on error or EOF. */ int vips_sbuf_require(VipsSbuf *sbuf, int require) { g_assert(require < VIPS_SBUF_BUFFER_SIZE); g_assert(sbuf->chars_in_buffer >= 0); g_assert(sbuf->chars_in_buffer <= VIPS_SBUF_BUFFER_SIZE); g_assert(sbuf->read_point >= 0); g_assert(sbuf->read_point <= sbuf->chars_in_buffer); VIPS_DEBUG_MSG("vips_sbuf_require: %d\n", require); if (sbuf->read_point + require > sbuf->chars_in_buffer) { /* Areas can overlap, so we must memmove(). */ memmove(sbuf->input_buffer, sbuf->input_buffer + sbuf->read_point, sbuf->chars_in_buffer - sbuf->read_point); sbuf->chars_in_buffer -= sbuf->read_point; sbuf->read_point = 0; while (require > sbuf->chars_in_buffer) { unsigned char *to = sbuf->input_buffer + sbuf->chars_in_buffer; int space_available = VIPS_SBUF_BUFFER_SIZE - sbuf->chars_in_buffer; gint64 bytes_read; if ((bytes_read = vips_source_read(sbuf->source, to, space_available)) < 0) return -1; if (bytes_read == 0) { vips_error( vips_connection_nick(VIPS_CONNECTION( sbuf->source)), "%s", _("end of file")); return -1; } to[bytes_read] = '\0'; sbuf->chars_in_buffer += bytes_read; } } return 0; } /** * VIPS_SBUF_REQUIRE: * @sbuf: source to operate on * @require: need this many characters * * Make sure at least @require characters are available for * [func@SBUF_PEEK] and [func@SBUF_FETCH]. * * Returns: 0 on success, -1 on read error or EOF. */ /** * VIPS_SBUF_PEEK: * @sbuf: source to operate on * * After a successful [func@SBUF_REQUIRE], you can index this to get * require characters of input. * * Returns: a pointer to the next require characters of input. */ /** * VIPS_SBUF_FETCH: * @sbuf: source to operate on * * After a successful [func@SBUF_REQUIRE], you can use this require times * to fetch characters of input. * * Returns: the next input character. */ /** * vips_sbuf_get_line: * @sbuf: source to operate on * * Fetch the next line of text from @sbuf and return it. The end of * line character (or characters, for DOS files) are removed, and the string * is terminated with a null (`\0` character). * * Returns `NULL` on end of file or read error. * * If the line is longer than some arbitrary (but large) limit, it is * truncated. If you need to be able to read very long lines, use the * slower [method@Sbuf.get_line_copy]. * * The return value is owned by @sbuf and must not be freed. It * is valid until the next get call to @sbuf. * * Returns: the next line of text, or `NULL` on EOF or read error. */ const char * vips_sbuf_get_line(VipsSbuf *sbuf) { int write_point; int space_remaining; int ch; VIPS_DEBUG_MSG("vips_sbuf_get_line:\n"); write_point = 0; space_remaining = VIPS_SBUF_BUFFER_SIZE; while ((ch = VIPS_SBUF_GETC(sbuf)) != -1 && ch != '\n' && space_remaining > 0) { sbuf->line[write_point] = ch; write_point += 1; space_remaining -= 1; } sbuf->line[write_point] = '\0'; /* If we hit EOF immediately, return EOF. */ if (ch == -1 && write_point == 0) return NULL; /* If the final char in the buffer is \r, this is probably a DOS file * and we should remove that too. * * There's a chance this could incorrectly remove \r in very long * lines, but ignore this. */ if (write_point > 0 && sbuf->line[write_point - 1] == '\r') sbuf->line[write_point - 1] = '\0'; /* If we filled the output line without seeing \n, keep going to the * next \n. */ if (ch != '\n' && space_remaining == 0) { while ((ch = VIPS_SBUF_GETC(sbuf)) != -1 && ch != '\n') ; } VIPS_DEBUG_MSG(" %s\n", sbuf->line); return (const char *) sbuf->line; } /** * vips_sbuf_get_line_copy: * @sbuf: source to operate on * * Fetch the next line of text from @sbuf and return it. The end of * line character (or characters, for DOS files) are removed, and the string * is terminated with a null (`\0` character). * * The return result must be freed with [func@GLib.free]. * * This is slower than [method@Sbuf.get_line], but can work with lines of * any length. * * Returns: the next line of text, or `NULL` on EOF or read error. */ char * vips_sbuf_get_line_copy(VipsSbuf *sbuf) { static const unsigned char null = '\0'; VIPS_DEBUG_MSG("vips_sbuf_get_line_copy:\n"); GByteArray *buffer; int ch; char *result; buffer = g_byte_array_new(); while ((ch = VIPS_SBUF_GETC(sbuf)) != -1 && ch != '\n') { unsigned char c = ch; g_byte_array_append(buffer, &c, 1); } /* Immediate EOF. */ if (ch == -1 && buffer->len == 0) { VIPS_FREEF(g_byte_array_unref, buffer); return NULL; } /* If the character before the \n was \r, this is probably a DOS file * and we should remove the \r. */ if (ch == '\n' && buffer->len > 0 && buffer->data[buffer->len - 1] == '\r') g_byte_array_set_size(buffer, buffer->len - 1); g_byte_array_append(buffer, &null, 1); result = (char *) g_byte_array_free(buffer, FALSE); VIPS_DEBUG_MSG(" %s\n", result); return result; } /** * vips_sbuf_get_non_whitespace: * @sbuf: source to operate on * * Fetch the next chunk of non-whitespace text from the source, and * null-terminate it. * * After this, the next getc will be the first char of the next block of * whitespace (or EOF). * * If the first getc is whitespace, stop instantly and return the empty * string. * * If the item is longer than some arbitrary (but large) limit, it is * truncated. * * The return value is owned by @sbuf and must not be freed. It * is valid until the next get call to @sbuf. * * Returns: the next block of non-whitespace, or `NULL` on EOF or read error. */ const char * vips_sbuf_get_non_whitespace(VipsSbuf *sbuf) { int ch; int i; for (i = 0; i < VIPS_SBUF_BUFFER_SIZE && !g_ascii_isspace(ch = VIPS_SBUF_GETC(sbuf)) && ch != EOF; i++) sbuf->line[i] = ch; sbuf->line[i] = '\0'; /* If we stopped before seeing any whitespace, skip to the end of the * block of non-whitespace. */ if (!g_ascii_isspace(ch)) while (!g_ascii_isspace(ch = VIPS_SBUF_GETC(sbuf)) && ch != EOF) ; /* If we finally stopped on whitespace, step back one so the next get * will be whitespace (or EOF). */ if (g_ascii_isspace(ch)) VIPS_SBUF_UNGETC(sbuf); return (const char *) sbuf->line; } /** * vips_sbuf_skip_whitespace: * @sbuf: source to operate on * * After this, the next getc will be the first char of the next block of * non-whitespace (or EOF). * * Also skip comments, ie. from any '#' character to the end of the line. * * Returns: 0 on success, or -1 on EOF. */ int vips_sbuf_skip_whitespace(VipsSbuf *sbuf) { int ch; do { ch = VIPS_SBUF_GETC(sbuf); /* # skip comments too. */ while (ch == '#') { /* Probably EOF. */ if (!vips_sbuf_get_line(sbuf)) return -1; ch = VIPS_SBUF_GETC(sbuf); } } while (g_ascii_isspace(ch)); VIPS_SBUF_UNGETC(sbuf); return 0; } libvips-8.18.2/libvips/iofuncs/semaphore.c000066400000000000000000000074441516303661500205460ustar00rootroot00000000000000/* Support for thread stuff. * * JC & KM 9/5/94 * Modified: * 28/11/94 JC * - return(0) missing from tidy_thread_info() * 4/8/99 RP JC * - reorganised for POSIX * 28/3/11 * - moved to vips_ namespace */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_IO */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include void vips_semaphore_init(VipsSemaphore *s, int v, char *name) { s->v = v; s->name = name; g_mutex_init(&s->mutex); g_cond_init(&s->cond); } void vips_semaphore_destroy(VipsSemaphore *s) { g_mutex_clear(&s->mutex); g_cond_clear(&s->cond); } /* Add n to the semaphore and signal any threads that are blocked waiting * a change. */ int vips_semaphore_upn(VipsSemaphore *s, int n) { int value_after_op; g_mutex_lock(&s->mutex); s->v += n; value_after_op = s->v; /* If we are only incrementing by one, we only need to wake a single * thread. If we are incrementing by a lot, we must wake all threads. */ if (n == 1) g_cond_signal(&s->cond); else g_cond_broadcast(&s->cond); g_mutex_unlock(&s->mutex); #ifdef DEBUG_IO printf("vips_semaphore_upn(\"%s\",%d) = %d\n", s->name, n, value_after_op); if (value_after_op > 1) vips_error("vips_semaphore_upn", "up over 1!"); #endif /*DEBUG_IO*/ return value_after_op; } /* Increment the semaphore. */ int vips_semaphore_up(VipsSemaphore *s) { return vips_semaphore_upn(s, 1); } /* Wait for sem > n, then subtract n. * Returns -1 when the monotonic time in @end_time was passed. */ static int vips__semaphore_downn_until(VipsSemaphore *s, int n, gint64 end_time) { int value_after_op; VIPS_GATE_START("vips__semaphore_downn_until: wait"); g_mutex_lock(&s->mutex); while (s->v < n) { if (end_time == -1) vips__worker_cond_wait(&s->cond, &s->mutex); else if (!g_cond_wait_until(&s->cond, &s->mutex, end_time)) { /* timeout has passed. */ g_mutex_unlock(&s->mutex); VIPS_GATE_STOP("vips__semaphore_downn_until: wait"); return -1; } } s->v -= n; value_after_op = s->v; g_mutex_unlock(&s->mutex); #ifdef DEBUG_IO printf("vips__semaphore_downn_until(\"%s\",%d): %d\n", s->name, n, value_after_op); #endif /*DEBUG_IO*/ VIPS_GATE_STOP("vips__semaphore_downn_until: wait"); return value_after_op; } /* Wait for sem>n, then subtract n. n must be >= 0. Returns the new semaphore * value. */ int vips_semaphore_downn(VipsSemaphore *s, int n) { g_assert(n >= 0); return vips__semaphore_downn_until(s, n, -1); } /* Wait for sem > 0, then decrement. Returns the new semaphore value. */ int vips_semaphore_down(VipsSemaphore *s) { return vips__semaphore_downn_until(s, 1, -1); } /* Wait for sem > 0, then decrement. * Returns -1 when @timeout (in microseconds) has passed, or the new * semaphore value. */ int vips_semaphore_down_timeout(VipsSemaphore *s, gint64 timeout) { gint64 end_time = g_get_monotonic_time() + timeout; return vips__semaphore_downn_until(s, 1, end_time); } libvips-8.18.2/libvips/iofuncs/sink.c000066400000000000000000000305241516303661500175220ustar00rootroot00000000000000/* A sink that's not attached to anything, eg. find image average, * * 28/3/10 * - from im_iterate(), reworked for threadpool */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "sink.h" /* A part of the image we are scanning. * * We can't let any threads fall too far behind as that would mess up seq * image sources. Keep track of two areas moving down the image, and stall if * the previous area still has active threads. */ typedef struct _SinkArea { struct _Sink *sink; VipsRect rect; /* Part of image this area covers */ VipsSemaphore n_thread; /* Number of threads scanning this area */ } SinkArea; /* Per-call state. */ typedef struct _Sink { SinkBase sink_base; /* We need a temp "p" image between the source image and us to * make sure we can't damage the original. */ VipsImage *t; /* Call params. */ VipsStartFn start_fn; VipsGenerateFn generate_fn; VipsStopFn stop_fn; void *a; void *b; /* We are current scanning area, we'll delay starting a new * area if old_area (the previous position) hasn't completed. */ SinkArea *area; SinkArea *old_area; } Sink; /* Our per-thread state. */ typedef struct _SinkThreadState { VipsThreadState parent_object; /* Sequence value for this thread. */ void *seq; /* The region we walk over sink->t copy. We can't use * parent_object->reg, it's defined on the outer image. */ VipsRegion *reg; /* The area we were allocated from. */ SinkArea *area; } SinkThreadState; typedef struct _SinkThreadStateClass { VipsThreadStateClass parent_class; } SinkThreadStateClass; G_DEFINE_TYPE(SinkThreadState, sink_thread_state, VIPS_TYPE_THREAD_STATE); static void sink_area_free(SinkArea *area) { vips_semaphore_destroy(&area->n_thread); g_free(area); } static SinkArea * sink_area_new(Sink *sink) { SinkArea *area; if (!(area = VIPS_NEW(NULL, SinkArea))) return NULL; area->sink = sink; vips_semaphore_init(&area->n_thread, 0, "n_thread"); return area; } /* Move an area to a position. */ static void sink_area_position(SinkArea *area, int top, int height) { Sink *sink = area->sink; VipsRect all, rect; all.left = 0; all.top = 0; all.width = sink->sink_base.im->Xsize; all.height = sink->sink_base.im->Ysize; rect.left = 0; rect.top = top; rect.width = sink->sink_base.im->Xsize; rect.height = height; vips_rect_intersectrect(&all, &rect, &area->rect); } /* Our VipsThreadpoolAllocate function ... move the thread to the next tile * that needs doing. If we fill the current area, we block until the previous * area is finished, then swap areas. * * If all tiles are done, we return FALSE to end iteration. */ static gboolean sink_area_allocate_fn(VipsThreadState *state, void *a, gboolean *stop) { SinkThreadState *sstate = (SinkThreadState *) state; Sink *sink = (Sink *) a; SinkBase *sink_base = (SinkBase *) sink; VipsRect image; VipsRect tile; VIPS_DEBUG_MSG("sink_area_allocate_fn: %p\n", g_thread_self()); /* Is the state x/y OK? New line or maybe new buffer or maybe even * all done. */ if (sink_base->x >= sink->area->rect.width) { sink_base->x = 0; sink_base->y += sink_base->tile_height; if (sink_base->y >= VIPS_RECT_BOTTOM(&sink->area->rect)) { /* Block until the previous area is done. */ if (sink->area->rect.top > 0) vips_semaphore_downn( &sink->old_area->n_thread, 0); /* End of image? */ if (sink_base->y >= sink_base->im->Ysize) { *stop = TRUE; return 0; } /* Swap buffers. */ VIPS_SWAP(SinkArea *, sink->area, sink->old_area); /* Position buf at the new y. */ sink_area_position(sink->area, sink_base->y, sink_base->n_lines); } } /* x, y and buf are good: save params for thread. */ image.left = 0; image.top = 0; image.width = sink_base->im->Xsize; image.height = sink_base->im->Ysize; tile.left = sink_base->x; tile.top = sink_base->y; tile.width = sink_base->tile_width; tile.height = sink_base->tile_height; vips_rect_intersectrect(&image, &tile, &state->pos); /* The thread needs to know which area it's writing to. */ sstate->area = sink->area; VIPS_DEBUG_MSG(" %p allocated %d x %d:\n", g_thread_self(), state->pos.left, state->pos.top); /* Add to the number of writers on the area. */ vips_semaphore_upn(&sink->area->n_thread, -1); /* Move state on. */ sink_base->x += sink_base->tile_width; /* Add the number of pixels we've just allocated to progress. */ sink_base->processed += (guint64) state->pos.width * state->pos.height; return 0; } /* Call a thread's stop function. */ static int sink_call_stop(Sink *sink, SinkThreadState *state) { if (state->seq && sink->stop_fn) { int result; VIPS_DEBUG_MSG("sink_call_stop: state = %p\n", state); result = sink->stop_fn(state->seq, sink->a, sink->b); if (result) { SinkBase *sink_base = (SinkBase *) sink; vips_error("vips_sink", _("stop function failed for image \"%s\""), sink_base->im->filename); return -1; } state->seq = NULL; } return 0; } static void sink_thread_state_dispose(GObject *gobject) { SinkThreadState *state = (SinkThreadState *) gobject; Sink *sink = (Sink *) ((VipsThreadState *) state)->a; sink_call_stop(sink, state); VIPS_UNREF(state->reg); G_OBJECT_CLASS(sink_thread_state_parent_class)->dispose(gobject); } /* Call the start function for this thread, if necessary. */ static int sink_call_start(Sink *sink, SinkThreadState *state) { if (!state->seq && sink->start_fn) { VIPS_DEBUG_MSG("sink_call_start: state = %p\n", state); state->seq = sink->start_fn(sink->t, sink->a, sink->b); if (!state->seq) { SinkBase *sink_base = (SinkBase *) sink; vips_error("vips_sink", _("start function failed for image \"%s\""), sink_base->im->filename); return -1; } } return 0; } static int sink_thread_state_build(VipsObject *object) { SinkThreadState *state = (SinkThreadState *) object; Sink *sink = (Sink *) ((VipsThreadState *) state)->a; if (!(state->reg = vips_region_new(sink->t)) || sink_call_start(sink, state)) return -1; return VIPS_OBJECT_CLASS(sink_thread_state_parent_class)->build(object); } static void sink_thread_state_class_init(SinkThreadStateClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = sink_thread_state_dispose; object_class->build = sink_thread_state_build; object_class->nickname = "sinkthreadstate"; object_class->description = _("per-thread state for sink"); } static void sink_thread_state_init(SinkThreadState *state) { state->seq = NULL; state->reg = NULL; } VipsThreadState * vips_sink_thread_state_new(VipsImage *im, void *a) { return VIPS_THREAD_STATE(vips_object_new( sink_thread_state_get_type(), vips_thread_state_set, im, a)); } static void sink_free(Sink *sink) { VIPS_FREEF(sink_area_free, sink->area); VIPS_FREEF(sink_area_free, sink->old_area); VIPS_FREEF(g_object_unref, sink->t); } void vips_sink_base_init(SinkBase *sink_base, VipsImage *image) { /* Always clear kill before we start looping. See the * call to vips_image_iskilled() below. */ vips_image_set_kill(image, FALSE); sink_base->im = image; sink_base->x = 0; sink_base->y = 0; vips_get_tile_size(image, &sink_base->tile_width, &sink_base->tile_height, &sink_base->n_lines); sink_base->processed = 0; } static int sink_init(Sink *sink, VipsImage *image, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b) { g_assert(generate_fn); vips_sink_base_init(&sink->sink_base, image); sink->t = NULL; sink->start_fn = start_fn; sink->generate_fn = generate_fn; sink->stop_fn = stop_fn; sink->a = a; sink->b = b; sink->area = NULL; sink->old_area = NULL; if (!(sink->t = vips_image_new()) || !(sink->area = sink_area_new(sink)) || !(sink->old_area = sink_area_new(sink)) || vips_image_write(sink->sink_base.im, sink->t)) { sink_free(sink); return -1; } return 0; } static int sink_work(VipsThreadState *state, void *a) { SinkThreadState *sstate = (SinkThreadState *) state; Sink *sink = (Sink *) a; SinkArea *area = sstate->area; int result; result = vips_region_prepare(sstate->reg, &state->pos); if (!result) result = sink->generate_fn(sstate->reg, sstate->seq, sink->a, sink->b, &state->stop); /* Tell the allocator we're done. */ vips_semaphore_upn(&area->n_thread, 1); return result; } int vips_sink_base_progress(void *a) { SinkBase *sink_base = (SinkBase *) a; VIPS_DEBUG_MSG("vips_sink_base_progress:\n"); /* Trigger any eval callbacks on our source image and * check for errors. */ vips_image_eval(sink_base->im, sink_base->processed); if (vips_image_iskilled(sink_base->im)) return -1; return 0; } /** * vips_sink_tile: (method) * @im: scan over this image * @tile_width: tile width * @tile_height: tile height * @start_fn: (scope async): start sequences with this function * @generate_fn: (scope async): generate pixels with this function * @stop_fn: (scope async): stop sequences with this function * @a: user data * @b: user data * * Loops over an image. @generate_fn is called for every * pixel in the image, with * the @reg argument being a region of calculated pixels. * * Each set of pixels is @tile_width by @tile_height pixels (less at the * image edges). This is handy for things like writing a tiled TIFF image, * where tiles have to be generated with a certain size. * * ::: seealso * [method@Image.sink], [method@Image.get_tile_size]. * * Returns: 0 on success, or -1 on error. */ int vips_sink_tile(VipsImage *im, int tile_width, int tile_height, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b) { Sink sink; int result; if (!vips_object_sanity(VIPS_OBJECT(im))) return -1; /* We don't use this, but make sure it's set in case any old binaries * are expecting it. */ im->Bbits = vips_format_sizeof(im->BandFmt) << 3; if (sink_init(&sink, im, start_fn, generate_fn, stop_fn, a, b)) return -1; if (tile_width > 0) { sink.sink_base.tile_width = tile_width; sink.sink_base.tile_height = tile_height; } /* vips_sink_base_progress() signals progress on im, so we have to do * pre/post on that too. */ vips_image_preeval(im); sink_area_position(sink.area, 0, sink.sink_base.n_lines); result = vips_threadpool_run(im, vips_sink_thread_state_new, sink_area_allocate_fn, sink_work, vips_sink_base_progress, &sink); vips_image_posteval(im); sink_free(&sink); vips_image_minimise_all(im); return result; } /** * vips_sink: (method) * @im: scan over this image * @start_fn: (scope async): start sequences with this function * @generate_fn: (scope async): generate pixels with this function * @stop_fn: (scope async): stop sequences with this function * @a: user data * @b: user data * * Loops over an image. @generate_fn is called for every pixel in * the image, with the @reg argument being a region of calculated pixels. * [method@Image.sink] is used to implement operations like * [method@Image.avg] which have no image output. * * Each set of pixels is sized according to the requirements of the image * pipeline that generated @im. * * ::: seealso * [method@Image.generate], [ctor@Image.new]. * * Returns: 0 on success, or -1 on error. */ int vips_sink(VipsImage *im, VipsStartFn start_fn, VipsGenerateFn generate_fn, VipsStopFn stop_fn, void *a, void *b) { return vips_sink_tile(im, -1, -1, start_fn, generate_fn, stop_fn, a, b); } libvips-8.18.2/libvips/iofuncs/sink.h000066400000000000000000000034011516303661500175210ustar00rootroot00000000000000/* A sink that's not attached to anything, eg. find image average, * * 28/3/10 * - from im_iterate(), reworked for threadpool */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_SINK_H #define VIPS_SINK_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #include /* Base for sink.c / sinkdisc.c / sinkmemory.c */ typedef struct _SinkBase { VipsImage *im; /* The position we're at in buf. */ int x; int y; /* The tilesize we've picked. */ int tile_width; int tile_height; int n_lines; /* The number of pixels allocate has allocated. Used for progress * feedback. */ guint64 processed; } SinkBase; /* Some function we can share. */ void vips_sink_base_init(SinkBase *sink_base, VipsImage *image); VipsThreadState *vips_sink_thread_state_new(VipsImage *im, void *a); int vips_sink_base_allocate(VipsThreadState *state, void *a, gboolean *stop); int vips_sink_base_progress(void *a); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_SINK_H*/ libvips-8.18.2/libvips/iofuncs/sinkdisc.c000066400000000000000000000321651516303661500203700ustar00rootroot00000000000000/* Write an image to a disc file. * * 19/3/10 * - from im_wbuffer.c * - move on top of VipsThreadpool, instead of im_threadgroup_t * 23/6/10 * - better buffer handling for single-line images * 17/7/10 * - we could get stuck if allocate failed (thanks Tim) * 23/2/12 * - we could deadlock if generate failed */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include "sink.h" /* A buffer we are going to write to disc in a background thread. */ typedef struct _WriteBuffer { struct _Write *write; VipsRegion *region; /* Pixels */ VipsRect area; /* Part of image this region covers */ VipsSemaphore go; /* Start bg thread loop */ VipsSemaphore nwrite; /* Number of threads writing to region */ VipsSemaphore done; /* Bg thread has done write */ VipsSemaphore finish; /* Bg thread has finished */ int write_errno; /* Save write errors here */ gboolean running; /* Whether the bg writer thread is running */ gboolean kill; /* Set to ask thread to exit */ } WriteBuffer; /* Per-call state. */ typedef struct _Write { SinkBase sink_base; /* We are current writing tiles to buf, buf_back is in the hands of * the bg write thread. */ WriteBuffer *buf; WriteBuffer *buf_back; /* The file format write operation. */ VipsRegionWrite write_fn; void *a; } Write; static int write_check_error(Write *write) { if (write->buf->write_errno || write->buf_back->write_errno) { vips_error_system(write->buf->write_errno ? write->buf->write_errno : write->buf_back->write_errno, "wbuffer_write", "%s", _("write failed")); return -1; } return 0; } /* Our per-thread state ... we need to also track the buffer that pos is * supposed to write to. */ typedef struct _WriteThreadState { VipsThreadState parent_object; WriteBuffer *buf; } WriteThreadState; typedef struct _WriteThreadStateClass { VipsThreadStateClass parent_class; } WriteThreadStateClass; G_DEFINE_TYPE(WriteThreadState, write_thread_state, VIPS_TYPE_THREAD_STATE); static void write_thread_state_class_init(WriteThreadStateClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); object_class->nickname = "writethreadstate"; object_class->description = _("per-thread state for sinkdisc"); } static void write_thread_state_init(WriteThreadState *state) { state->buf = NULL; } static VipsThreadState * write_thread_state_new(VipsImage *im, void *a) { return VIPS_THREAD_STATE(vips_object_new( write_thread_state_get_type(), vips_thread_state_set, im, a)); } static void wbuffer_free(WriteBuffer *wbuffer) { /* Is there a thread running this region? Kill it! */ if (wbuffer->running) { wbuffer->kill = TRUE; vips_semaphore_up(&wbuffer->go); vips_semaphore_down(&wbuffer->finish); VIPS_DEBUG_MSG("wbuffer_free:\n"); wbuffer->running = FALSE; } VIPS_UNREF(wbuffer->region); vips_semaphore_destroy(&wbuffer->go); vips_semaphore_destroy(&wbuffer->nwrite); vips_semaphore_destroy(&wbuffer->done); vips_semaphore_destroy(&wbuffer->finish); g_free(wbuffer); } static void wbuffer_write(WriteBuffer *wbuffer) { Write *write = wbuffer->write; VIPS_DEBUG_MSG("wbuffer_write: %d bytes from wbuffer %p\n", wbuffer->region->bpl * wbuffer->area.height, wbuffer); VIPS_GATE_START("wbuffer_write: work"); wbuffer->write_errno = write->write_fn(wbuffer->region, &wbuffer->area, write->a); VIPS_GATE_STOP("wbuffer_write: work"); } /* Run this as a thread to do a BG write. */ static void wbuffer_write_thread(void *data, void *user_data) { WriteBuffer *wbuffer = (WriteBuffer *) data; for (;;) { /* Wait to be told to write. */ vips_semaphore_down(&wbuffer->go); if (wbuffer->kill) break; /* Now block until the last worker finishes on this buffer. */ vips_semaphore_downn(&wbuffer->nwrite, 0); wbuffer_write(wbuffer); /* Signal write complete. */ vips_semaphore_up(&wbuffer->done); } /* We are exiting: tell the main thread. */ vips_semaphore_up(&wbuffer->finish); } static WriteBuffer * wbuffer_new(Write *write) { WriteBuffer *wbuffer; if (!(wbuffer = VIPS_NEW(NULL, WriteBuffer))) return NULL; wbuffer->write = write; wbuffer->region = NULL; vips_semaphore_init(&wbuffer->go, 0, "go"); vips_semaphore_init(&wbuffer->nwrite, 0, "nwrite"); vips_semaphore_init(&wbuffer->done, 0, "done"); vips_semaphore_init(&wbuffer->finish, 0, "finish"); wbuffer->write_errno = 0; wbuffer->running = FALSE; wbuffer->kill = FALSE; if (!(wbuffer->region = vips_region_new(write->sink_base.im))) { wbuffer_free(wbuffer); return NULL; } /* The worker threads need to be able to move the buffers around. */ vips__region_no_ownership(wbuffer->region); /* Make this last (picks up parts of wbuffer on startup). */ if (vips_thread_execute("wbuffer", wbuffer_write_thread, wbuffer)) { wbuffer_free(wbuffer); return NULL; } wbuffer->running = TRUE; return wbuffer; } /* Block until the previous write completes, then write the front buffer. */ static int wbuffer_flush(Write *write) { VIPS_DEBUG_MSG("wbuffer_flush:\n"); /* Block until the other buffer has been written. We have to do this * before we can set this buffer writing or we'll lose output ordering. */ if (write->buf->area.top > 0) { vips_semaphore_down(&write->buf_back->done); if (write_check_error(write)) return -1; } /* Set the background writer going for this buffer. */ vips_semaphore_up(&write->buf->go); return 0; } /* Move a wbuffer to a position. */ static int wbuffer_position(WriteBuffer *wbuffer, int top, int height) { VipsRect image, area; int result; image.left = 0; image.top = 0; image.width = wbuffer->write->sink_base.im->Xsize; image.height = wbuffer->write->sink_base.im->Ysize; area.left = 0; area.top = top; area.width = wbuffer->write->sink_base.im->Xsize; area.height = height; vips_rect_intersectrect(&area, &image, &wbuffer->area); /* The workers take turns to move the buffers. */ vips__region_take_ownership(wbuffer->region); result = vips_region_buffer(wbuffer->region, &wbuffer->area); vips__region_no_ownership(wbuffer->region); /* This should be an exclusive buffer, hopefully. */ if (!result) g_assert(!wbuffer->region->buffer->done); return result; } /* Our VipsThreadpoolAllocate function ... move the thread to the next tile * that needs doing. If no buffer is available (the bg writer hasn't yet * finished with it), we block. If all tiles are done, we return FALSE to end * iteration. */ static gboolean wbuffer_allocate_fn(VipsThreadState *state, void *a, gboolean *stop) { WriteThreadState *wstate = (WriteThreadState *) state; Write *write = (Write *) a; SinkBase *sink_base = (SinkBase *) write; VipsRect image; VipsRect tile; VIPS_DEBUG_MSG("wbuffer_allocate_fn:\n"); /* Is the state x/y OK? New line or maybe new buffer or maybe even * all done. */ if (sink_base->x >= write->buf->area.width) { sink_base->x = 0; sink_base->y += sink_base->tile_height; if (sink_base->y >= VIPS_RECT_BOTTOM(&write->buf->area)) { VIPS_DEBUG_MSG("wbuffer_allocate_fn: " "finished top = %d, height = %d\n", write->buf->area.top, write->buf->area.height); /* Block until the write of the previous buffer * is done, then set write of this buffer going. */ if (wbuffer_flush(write)) { *stop = TRUE; return -1; } /* End of image? */ if (sink_base->y >= sink_base->im->Ysize) { *stop = TRUE; return 0; } VIPS_DEBUG_MSG("wbuffer_allocate_fn: " "starting top = %d, height = %d\n", sink_base->y, sink_base->n_lines); /* Swap buffers. */ VIPS_SWAP(WriteBuffer *, write->buf, write->buf_back); /* Position buf at the new y. */ if (wbuffer_position(write->buf, sink_base->y, sink_base->n_lines)) { *stop = TRUE; return -1; } /* This will be the first tile of a new buffer ... mark this as a * good place to stall for a moment if we want to stress the * caching system. See threadpool.c. */ state->stall = TRUE; } } /* x, y and buf are good: save params for thread. */ image.left = 0; image.top = 0; image.width = sink_base->im->Xsize; image.height = sink_base->im->Ysize; tile.left = sink_base->x; tile.top = sink_base->y; tile.width = sink_base->tile_width; tile.height = sink_base->tile_height; vips_rect_intersectrect(&image, &tile, &state->pos); /* The thread needs to know which buffer it's writing to. */ wstate->buf = write->buf; VIPS_DEBUG_MSG(" thread %p allocated " "left = %d, top = %d, width = %d, height = %d\n", g_thread_self(), tile.left, tile.top, tile.width, tile.height); /* Add to the number of writers on the buffer. */ vips_semaphore_upn(&write->buf->nwrite, -1); /* Move state on. */ sink_base->x += sink_base->tile_width; /* Add the number of pixels we've just allocated to progress. */ sink_base->processed += (guint64) state->pos.width * state->pos.height; return 0; } /* Our VipsThreadpoolWork function ... generate a tile! */ static int wbuffer_work_fn(VipsThreadState *state, void *a) { WriteThreadState *wstate = (WriteThreadState *) state; int result; VIPS_DEBUG_MSG("wbuffer_work_fn: thread %p, %d x %d\n", g_thread_self(), state->pos.left, state->pos.top); result = vips_region_prepare_to(state->reg, wstate->buf->region, &state->pos, state->pos.left, state->pos.top); VIPS_DEBUG_MSG("wbuffer_work_fn: thread %p result = %d\n", g_thread_self(), result); /* Tell the bg write thread we've left. */ vips_semaphore_upn(&wstate->buf->nwrite, 1); return result; } static void write_init(Write *write, VipsImage *image, VipsRegionWrite write_fn, void *a) { vips_sink_base_init(&write->sink_base, image); write->buf = wbuffer_new(write); write->buf_back = wbuffer_new(write); write->write_fn = write_fn; write->a = a; } static void write_free(Write *write) { VIPS_FREEF(wbuffer_free, write->buf); VIPS_FREEF(wbuffer_free, write->buf_back); } /** * VipsRegionWrite: * @region: get pixels from here * @area: area to write * @a: client data * * The function should write the pixels in @area from @region. @a is the * value passed into [method@Image.sink_disc]. * * ::: seealso * [method@Image.sink_disc]. * * Returns: 0 on success, -1 on error. */ /** * vips_sink_disc: (method) * @im: image to process * @write_fn: (scope call) (closure a): called for every batch of pixels * @a: client data * * [method@Image.sink_disc] loops over @im, top-to-bottom, generating it in sections. * As each section is produced, @write_fn is called. * * @write_fn is always called single-threaded (though not always from the same * thread), it's always given image * sections in top-to-bottom order, and there are never any gaps. * * This operation is handy for making image sinks which output to things like * disc files. Things like [method@Image.jpegsave], for example, use this to write * images to files in JPEG format. * * ::: seealso * [func@concurrency_set]. * * Returns: 0 on success, -1 on error. */ int vips_sink_disc(VipsImage *im, VipsRegionWrite write_fn, void *a) { Write write; int result; vips_image_preeval(im); write_init(&write, im, write_fn, a); result = 0; if (!write.buf || !write.buf_back || wbuffer_position(write.buf, 0, write.sink_base.n_lines) || vips_threadpool_run(im, write_thread_state_new, wbuffer_allocate_fn, wbuffer_work_fn, vips_sink_base_progress, &write)) result = -1; /* Just before allocate signalled stop, it set write.buf writing. We * need to wait for this write to finish. * * We can't just free the buffers (which will wait for the bg threads * to finish), since the bg thread might see the kill before it gets a * chance to write. * * If the pool exited with an error, write.buf might not have been * started (if the allocate failed), and in any case, we don't care if * the final write went through or not. */ if (!result) vips_semaphore_down(&write.buf->done); vips_image_posteval(im); /* The final write might have failed, pick up any error code. */ result |= write_check_error(&write); write_free(&write); vips_image_minimise_all(im); return result; } libvips-8.18.2/libvips/iofuncs/sinkmemory.c000066400000000000000000000204341516303661500207520ustar00rootroot00000000000000/* SinkMemory an image to a memory buffer, keeping top-to-bottom ordering. * * For sequential operations we need to keep requests reasonably ordered: we * can't let some tiles get very delayed. So we need to stall starting new * threads if the last thread gets too far behind. * * 17/2/12 * - from sinkdisc.c * 23/2/12 * - we could deadlock if generate failed */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "sink.h" /* A part of the image we are writing. */ typedef struct _SinkMemoryArea { struct _SinkMemory *memory; VipsRect rect; /* Part of image this area covers */ VipsSemaphore nwrite; /* Number of threads writing to this area */ } SinkMemoryArea; /* Per-call state. */ typedef struct _SinkMemory { SinkBase sink_base; /* We are current writing tiles to area, we'll delay starting a new * area if old_area (the previous position) hasn't completed. */ SinkMemoryArea *area; SinkMemoryArea *old_area; /* A region covering the whole of the output image ... we write to * this from many workers with vips_region_prepare_to(). */ VipsRegion *region; } SinkMemory; /* Our per-thread state ... we need to also track the area that pos is * supposed to write to. */ typedef struct _SinkMemoryThreadState { VipsThreadState parent_object; SinkMemoryArea *area; } SinkMemoryThreadState; typedef struct _SinkMemoryThreadStateClass { VipsThreadStateClass parent_class; } SinkMemoryThreadStateClass; G_DEFINE_TYPE(SinkMemoryThreadState, sink_memory_thread_state, VIPS_TYPE_THREAD_STATE); static void sink_memory_thread_state_class_init(SinkMemoryThreadStateClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); object_class->nickname = "sinkmemorythreadstate"; object_class->description = _("per-thread state for sinkmemory"); } static void sink_memory_thread_state_init(SinkMemoryThreadState *smstate) { } static VipsThreadState * sink_memory_thread_state_new(VipsImage *image, void *a) { return VIPS_THREAD_STATE(vips_object_new( sink_memory_thread_state_get_type(), vips_thread_state_set, image, a)); } static void sink_memory_area_free(SinkMemoryArea *area) { vips_semaphore_destroy(&area->nwrite); g_free(area); } static SinkMemoryArea * sink_memory_area_new(SinkMemory *memory) { SinkMemoryArea *area; if (!(area = VIPS_NEW(NULL, SinkMemoryArea))) return NULL; area->memory = memory; vips_semaphore_init(&area->nwrite, 0, "nwrite"); return area; } /* Move an area to a position. */ static void sink_memory_area_position(SinkMemoryArea *area, int top, int height) { SinkMemory *memory = area->memory; VipsRect all, rect; all.left = 0; all.top = 0; all.width = memory->sink_base.im->Xsize; all.height = memory->sink_base.im->Ysize; rect.left = 0; rect.top = top; rect.width = memory->sink_base.im->Xsize; rect.height = height; vips_rect_intersectrect(&all, &rect, &area->rect); } /* Our VipsThreadpoolAllocate function ... move the thread to the next tile * that needs doing. If we fill the current area, we block until the previous * area is finished, then swap areas. * * If all tiles are done, we return FALSE to end iteration. */ static gboolean sink_memory_area_allocate_fn(VipsThreadState *state, void *a, gboolean *stop) { SinkMemoryThreadState *smstate = (SinkMemoryThreadState *) state; SinkMemory *memory = (SinkMemory *) a; SinkBase *sink_base = (SinkBase *) memory; VipsRect image; VipsRect tile; VIPS_DEBUG_MSG("sink_memory_area_allocate_fn: %p\n", g_thread_self()); /* Is the state x/y OK? New line or maybe new buffer or maybe even * all done. */ if (sink_base->x >= memory->area->rect.width) { sink_base->x = 0; sink_base->y += sink_base->tile_height; if (sink_base->y >= VIPS_RECT_BOTTOM(&memory->area->rect)) { /* Block until the previous area is done. */ if (memory->area->rect.top > 0) vips_semaphore_downn( &memory->old_area->nwrite, 0); /* End of image? */ if (sink_base->y >= sink_base->im->Ysize) { *stop = TRUE; return 0; } /* Swap buffers. */ VIPS_SWAP(SinkMemoryArea *, memory->area, memory->old_area); /* Position buf at the new y. */ sink_memory_area_position(memory->area, sink_base->y, sink_base->n_lines); } } /* x, y and buf are good: save params for thread. */ image.left = 0; image.top = 0; image.width = sink_base->im->Xsize; image.height = sink_base->im->Ysize; tile.left = sink_base->x; tile.top = sink_base->y; tile.width = sink_base->tile_width; tile.height = sink_base->tile_height; vips_rect_intersectrect(&image, &tile, &state->pos); /* The thread needs to know which area it's writing to. */ smstate->area = memory->area; VIPS_DEBUG_MSG(" %p allocated %d x %d:\n", g_thread_self(), state->pos.left, state->pos.top); /* Add to the number of writers on the area. */ vips_semaphore_upn(&memory->area->nwrite, -1); /* Move state on. */ sink_base->x += sink_base->tile_width; /* Add the number of pixels we've just allocated to progress. */ sink_base->processed += (guint64) state->pos.width * state->pos.height; return 0; } /* Our VipsThreadpoolWork function ... generate a tile! */ static int sink_memory_area_work_fn(VipsThreadState *state, void *a) { SinkMemory *memory = (SinkMemory *) a; SinkMemoryThreadState *smstate = (SinkMemoryThreadState *) state; SinkMemoryArea *area = smstate->area; int result; VIPS_DEBUG_MSG("sink_memory_area_work_fn: %p %d x %d\n", g_thread_self(), state->pos.left, state->pos.top); result = vips_region_prepare_to(state->reg, memory->region, &state->pos, state->pos.left, state->pos.top); VIPS_DEBUG_MSG("sink_memory_area_work_fn: %p result = %d\n", g_thread_self(), result); /* Tell the allocator we're done. */ vips_semaphore_upn(&area->nwrite, 1); return result; } static void sink_memory_free(SinkMemory *memory) { VIPS_FREEF(sink_memory_area_free, memory->area); VIPS_FREEF(sink_memory_area_free, memory->old_area); VIPS_UNREF(memory->region); } static int sink_memory_init(SinkMemory *memory, VipsImage *image) { VipsRect all; vips_sink_base_init(&memory->sink_base, image); memory->area = NULL; memory->old_area = NULL; all.left = 0; all.top = 0; all.width = image->Xsize; all.height = image->Ysize; if (!(memory->region = vips_region_new(image)) || vips_region_image(memory->region, &all) || !(memory->area = sink_memory_area_new(memory)) || !(memory->old_area = sink_memory_area_new(memory))) { sink_memory_free(memory); return -1; } return 0; } /** * vips_sink_memory: * @im: generate this image to memory * * Loops over @im, generating it to a memory buffer attached to @im. It is * used by vips to implement writing to a memory buffer. * * ::: seealso * [method@Image.sink], [method@Image.get_tile_size], * [ctor@Image.new_memory]. * * Returns: 0 on success, or -1 on error. */ int vips_sink_memory(VipsImage *image) { SinkMemory memory; int result; if (sink_memory_init(&memory, image)) return -1; vips_image_preeval(image); sink_memory_area_position(memory.area, 0, memory.sink_base.n_lines); result = vips_threadpool_run(image, sink_memory_thread_state_new, sink_memory_area_allocate_fn, sink_memory_area_work_fn, vips_sink_base_progress, &memory); vips_image_posteval(image); sink_memory_free(&memory); vips_image_minimise_all(image); VIPS_DEBUG_MSG("vips_sink_memory: done\n"); return result; } libvips-8.18.2/libvips/iofuncs/sinkscreen.c000066400000000000000000000731621516303661500207270ustar00rootroot00000000000000/* asynchronous screen sink * * 1/1/10 * - from im_render.c * 25/11/10 * - in synchronous mode, use a single region for input and save huge * mem use * 20/1/14 * - bg render thread quits on shutdown * 1/12/15 * - don't do anything to out or mask after they have closed * - only run the bg render thread when there's work to do */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Verbose debugging output. #define VIPS_DEBUG */ /* Trace allocate/free. #define VIPS_DEBUG_AMBER */ /* Trace reschedule #define VIPS_DEBUG_GREEN */ /* Trace serious problems. #define VIPS_DEBUG_RED */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #ifdef VIPS_DEBUG_AMBER static int render_num_renders = 0; #endif /*VIPS_DEBUG_AMBER*/ /* A tile in our cache. */ typedef struct { struct _Render *render; VipsRect area; /* Place here (unclipped) */ VipsRegion *region; /* VipsRegion with the pixels */ /* The tile contains calculated pixels. Though the region may have been * invalidated behind our backs: we have to check that too. */ gboolean painted; /* The tile is on the dirty list. This saves us having to search the * dirty list all the time. */ gboolean dirty; /* Time of last use, for LRU flush */ int ticks; } Tile; /* Per-call state. */ typedef struct _Render { /* Reference count this, since we use these things from several * threads. We can't easily use the gobject ref count system since we * need a lock around operations. */ #if GLIB_CHECK_VERSION(2, 58, 0) gatomicrefcount ref_count; #else int ref_count; GMutex ref_count_lock; #endif /* Parameters. */ VipsImage *in; /* Image we render */ VipsImage *out; /* Write tiles here on demand */ VipsImage *mask; /* Set valid pixels here */ int tile_width; /* Tile size */ int tile_height; int max_tiles; /* Maximum number of tiles */ int priority; /* Larger numbers done sooner */ VipsSinkNotify notify; /* Tell caller about paints here */ void *a; /* This render has it's own threadpool and is not on the shared list. * * This private threadpool needs a semaphore to wait on for dirty tiles * to arrive. */ gboolean private_threadpool; VipsSemaphore dirty_sem; /* Lock here before reading or modifying the tile structure. */ GMutex lock; /* Tile cache. */ GSList *all; /* All our tiles */ int ntiles; /* Number of tiles */ int ticks; /* Inc. on each access ... used for LRU */ /* List of dirty tiles. Most recent at the front. */ GSList *dirty; /* Hash of tiles with positions. Tiles can be dirty or painted. */ GHashTable *tiles; /* A shutdown flag. If ->out or ->mask close, we must no longer do * anything to them until we shut down too. */ gboolean shutdown; } Render; /* Our per-thread state. */ typedef struct _RenderThreadState { VipsThreadState parent_object; /* The tile that should be calculated. */ Tile *tile; } RenderThreadState; typedef struct _RenderThreadStateClass { VipsThreadStateClass parent_class; } RenderThreadStateClass; G_DEFINE_TYPE(RenderThreadState, render_thread_state, VIPS_TYPE_THREAD_STATE); /* The BG thread which sits waiting to do some calculations, and the semaphore * it waits on holding the number of renders with dirty tiles. */ static GThread *render_thread = NULL; /* Set this to ask the render thread to quit. */ static gboolean render_kill = FALSE; /* All the renders with dirty tiles, and a semaphore that the bg render thread * waits on. */ static GMutex render_dirty_lock; static GSList *render_dirty_all = NULL; static VipsSemaphore n_render_dirty_sem; /* Set this to make the bg thread stop and reschedule. */ static gboolean render_reschedule = FALSE; /* Set this GPrivate to link a thread back to its Render struct. */ static GPrivate render_worker_key; gboolean vips__worker_exit(void) { Render *render = (Render *) g_private_get(&render_worker_key); return render && render->shutdown; } static void render_thread_state_class_init(RenderThreadStateClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); object_class->nickname = "renderthreadstate"; object_class->description = _("per-thread state for render"); } static void render_thread_state_init(RenderThreadState *state) { state->tile = NULL; } static VipsThreadState * render_thread_state_new(VipsImage *im, void *a) { return VIPS_THREAD_STATE(vips_object_new(render_thread_state_get_type(), vips_thread_state_set, im, a)); } static void * tile_free(Tile *tile, void *a, void *b) { VIPS_DEBUG_MSG_AMBER("tile_free\n"); VIPS_UNREF(tile->region); g_free(tile); return NULL; } static int render_free(Render *render) { VIPS_DEBUG_MSG_AMBER("render_free: %p\n", render); #if GLIB_CHECK_VERSION(2, 58, 0) g_assert(g_atomic_ref_count_compare(&render->ref_count, 0)); #else g_assert(render->ref_count == 0); #endif g_mutex_lock(&render_dirty_lock); if (g_slist_find(render_dirty_all, render)) { render_dirty_all = g_slist_remove(render_dirty_all, render); /* We don't need to adjust the semaphore: if it's too high, * the render thread will just loop and decrement next time * render_dirty_all is NULL. */ } g_mutex_unlock(&render_dirty_lock); #if !GLIB_CHECK_VERSION(2, 58, 0) g_mutex_clear(&render->ref_count_lock); #endif g_mutex_clear(&render->lock); if (render->private_threadpool) vips_semaphore_destroy(&render->dirty_sem); vips_slist_map2(render->all, (VipsSListMap2Fn) tile_free, NULL, NULL); VIPS_FREEF(g_slist_free, render->all); render->ntiles = 0; VIPS_FREEF(g_slist_free, render->dirty); VIPS_FREEF(g_hash_table_destroy, render->tiles); VIPS_UNREF(render->in); g_free(render); #ifdef VIPS_DEBUG_AMBER render_num_renders -= 1; printf("%d active renders\n", render_num_renders); #endif /*VIPS_DEBUG_AMBER*/ return 0; } /* Ref and unref a Render ... free on last unref. */ static int render_ref(Render *render) { #if GLIB_CHECK_VERSION(2, 58, 0) g_assert(!g_atomic_ref_count_compare(&render->ref_count, 0)); g_atomic_ref_count_inc(&render->ref_count); #else g_mutex_lock(&render->ref_count_lock); g_assert(render->ref_count != 0); render->ref_count += 1; g_mutex_unlock(&render->ref_count_lock); #endif return 0; } static int render_unref(Render *render) { gboolean kill; #if GLIB_CHECK_VERSION(2, 58, 0) g_assert(!g_atomic_ref_count_compare(&render->ref_count, 0)); kill = g_atomic_ref_count_dec(&render->ref_count); #else g_mutex_lock(&render->ref_count_lock); g_assert(render->ref_count > 0); render->ref_count -= 1; kill = render->ref_count == 0; g_mutex_unlock(&render->ref_count_lock); #endif if (kill) render_free(render); return 0; } /* Get the next tile to paint off the dirty list. */ static Tile * render_tile_dirty_get(Render *render) { Tile *tile; if (!render->dirty) tile = NULL; else { tile = (Tile *) render->dirty->data; g_assert(tile->dirty); render->dirty = g_slist_remove(render->dirty, tile); tile->dirty = FALSE; } return tile; } /* Pick a dirty tile to reuse. We could potentially get the tile that * render_work() is working on in the background :-( but I don't think we'll * get a crash, just a mis-paint. It should be vanishingly impossible anyway. */ static Tile * render_tile_dirty_reuse(Render *render) { Tile *tile; if (!render->dirty) tile = NULL; else { tile = (Tile *) g_slist_last(render->dirty)->data; render->dirty = g_slist_remove(render->dirty, tile); g_assert(tile->dirty); tile->dirty = FALSE; VIPS_DEBUG_MSG("render_tile_get_dirty_reuse: reusing dirty %p\n", tile); } return tile; } /* Add a tile to the dirty list. */ static void tile_dirty_set(Tile *tile) { Render *render = tile->render; if (!tile->dirty) { g_assert(!g_slist_find(render->dirty, tile)); render->dirty = g_slist_prepend(render->dirty, tile); tile->dirty = TRUE; tile->painted = FALSE; } else g_assert(g_slist_find(render->dirty, tile)); } /* Bump a tile to the front of the dirty list, if it's there. */ static void tile_dirty_bump(Tile *tile) { Render *render = tile->render; if (tile->dirty) { g_assert(g_slist_find(render->dirty, tile)); render->dirty = g_slist_remove(render->dirty, tile); render->dirty = g_slist_prepend(render->dirty, tile); } else g_assert(!g_slist_find(render->dirty, tile)); } static int render_allocate(VipsThreadState *state, void *a, gboolean *stop) { Render *render = (Render *) a; RenderThreadState *rstate = (RenderThreadState *) state; Tile *tile; g_mutex_lock(&render->lock); if (render_reschedule || !(tile = render_tile_dirty_get(render))) { VIPS_DEBUG_MSG_GREEN("render_allocate: stopping\n"); *stop = TRUE; rstate->tile = NULL; } else rstate->tile = tile; g_mutex_unlock(&render->lock); return 0; } static int render_work(VipsThreadState *state, void *a) { Render *render = (Render *) a; RenderThreadState *rstate = (RenderThreadState *) state; Tile *tile = rstate->tile; g_assert(tile); VIPS_DEBUG_MSG("calculating tile %p %dx%d\n", tile, tile->area.left, tile->area.top); /* vips__worker_exit() uses this to find the render to check for * shutdown. */ g_private_set(&render_worker_key, render); if (vips_region_prepare_to(state->reg, tile->region, &tile->area, tile->area.left, tile->area.top)) { VIPS_DEBUG_MSG_RED("render_work: vips_region_prepare_to() failed: %s\n", vips_error_buffer()); g_private_set(&render_worker_key, NULL); return -1; } tile->painted = TRUE; if (!render->shutdown && render->notify) render->notify(render->out, &tile->area, render->a); g_private_set(&render_worker_key, NULL); return 0; } static void render_dirty_put(Render *render); /* Called from vips_shutdown(). */ void vips__render_shutdown(void) { /* We may come here without having inited. */ if (render_thread) { g_mutex_lock(&render_dirty_lock); GThread *thread; thread = render_thread; render_reschedule = TRUE; render_kill = TRUE; g_mutex_unlock(&render_dirty_lock); vips_semaphore_up(&n_render_dirty_sem); (void) g_thread_join(thread); vips_semaphore_destroy(&n_render_dirty_sem); } } static int render_dirty_sort(Render *a, Render *b, void *user_data) { return b->priority - a->priority; } /* Add to the jobs list, if it has work to be done. */ static void render_dirty_put(Render *render) { if (render->private_threadpool) // set our private renderer going vips_semaphore_up(&render->dirty_sem); else { // add to the worklist for thwe global renderer g_mutex_lock(&render_dirty_lock); if (render->dirty) { if (!g_slist_find(render_dirty_all, render)) { render_dirty_all = g_slist_prepend(render_dirty_all, render); render_dirty_all = g_slist_sort(render_dirty_all, (GCompareFunc) render_dirty_sort); /* Tell the bg render thread we have one more dirty * render on there. */ vips_semaphore_up(&n_render_dirty_sem); } } g_mutex_unlock(&render_dirty_lock); } } static guint tile_hash(gconstpointer key) { VipsRect *rect = (VipsRect *) key; int x = rect->left / rect->width; int y = rect->top / rect->height; return x << 16 ^ y; } static gboolean tile_equal(gconstpointer a, gconstpointer b) { VipsRect *rect1 = (VipsRect *) a; VipsRect *rect2 = (VipsRect *) b; return rect1->left == rect2->left && rect1->top == rect2->top; } static void render_close_cb(VipsImage *image, Render *render) { VIPS_DEBUG_MSG_AMBER("render_close_cb\n"); /* The output image or mask are closing. This render will stick * around for a while, since threads can still be running, but it * must no longer reference ->out or ->mask (for example, invalidating * them). */ render->shutdown = TRUE; if (render->private_threadpool) { /* Nudge the bg thread (if any) for this pool. */ VIPS_DEBUG_MSG_GREEN("render_close_cb: nudge private worker\n"); vips_semaphore_up(&render->dirty_sem); } else { /* If this render is being worked on, we want to jog the bg thread, * make it drop it's ref and think again. */ VIPS_DEBUG_MSG_GREEN("render_close_cb: reschedule\n"); render_reschedule = TRUE; } render_unref(render); } static Render * render_new(VipsImage *in, VipsImage *out, VipsImage *mask, int tile_width, int tile_height, int max_tiles, int priority, VipsSinkNotify notify, void *a) { Render *render; /* Don't use auto-free for render, we do our own lifetime management * with _ref() and _unref(). */ if (!(render = VIPS_NEW(NULL, Render))) return NULL; /* render must hold a ref to in. This is dropped in render_free(). */ g_object_ref(in); #if GLIB_CHECK_VERSION(2, 58, 0) g_atomic_ref_count_init(&render->ref_count); #else render->ref_count = 1; g_mutex_init(&render->ref_count_lock); #endif render->in = in; render->out = out; render->mask = mask; render->tile_width = tile_width; render->tile_height = tile_height; render->max_tiles = max_tiles; render->priority = priority; render->notify = notify; render->a = a; if (render->priority < 0) { render->private_threadpool = TRUE; vips_semaphore_init(&render->dirty_sem, 0, "dirty_sem"); } g_mutex_init(&render->lock); render->all = NULL; render->ntiles = 0; render->ticks = 0; render->tiles = g_hash_table_new(tile_hash, tile_equal); render->dirty = NULL; render->shutdown = FALSE; /* Both out and mask must close before we can free the render. */ g_signal_connect(out, "close", G_CALLBACK(render_close_cb), render); if (mask) { g_signal_connect(mask, "close", G_CALLBACK(render_close_cb), render); render_ref(render); } VIPS_DEBUG_MSG_AMBER("render_new: %p\n", render); #ifdef VIPS_DEBUG_AMBER render_num_renders += 1; printf("%d active renders\n", render_num_renders); #endif /*VIPS_DEBUG_AMBER*/ return render; } /* Make a Tile. */ static Tile * tile_new(Render *render) { Tile *tile; VIPS_DEBUG_MSG_AMBER("tile_new\n"); /* Don't use auto-free: we need to make sure we free the tile after * Render. */ if (!(tile = VIPS_NEW(NULL, Tile))) return NULL; tile->render = render; tile->area.left = 0; tile->area.top = 0; tile->area.width = render->tile_width; tile->area.height = render->tile_height; tile->region = NULL; tile->painted = FALSE; tile->dirty = FALSE; tile->ticks = render->ticks; if (!(tile->region = vips_region_new(render->in))) { (void) tile_free(tile, NULL, NULL); return NULL; } // tiles are shared between threads vips__region_no_ownership(tile->region); render->all = g_slist_prepend(render->all, tile); render->ntiles += 1; return tile; } /* Search the cache for a tile by position. */ static Tile * render_tile_lookup(Render *render, VipsRect *area) { return (Tile *) g_hash_table_lookup(render->tiles, area); } /* Add a new tile to the table. */ static void render_tile_add(Tile *tile, VipsRect *area) { Render *render = tile->render; g_assert(!render_tile_lookup(render, area)); tile->area = *area; tile->painted = FALSE; /* Ignore buffer allocate errors, there's not much we could do with * them. */ if (vips_region_buffer(tile->region, &tile->area)) VIPS_DEBUG_MSG_RED("render_tile_add: buffer allocate failed\n"); g_hash_table_insert(render->tiles, &tile->area, tile); } /* Move a tile to a new position. */ static void render_tile_move(Tile *tile, VipsRect *area) { Render *render = tile->render; g_assert(render_tile_lookup(render, &tile->area)); if (tile->area.left != area->left || tile->area.top != area->top) { g_assert(!render_tile_lookup(render, area)); g_hash_table_remove(render->tiles, &tile->area); render_tile_add(tile, area); } } /* We've looked at a tile ... bump to end of LRU and front of dirty. */ static void tile_touch(Tile *tile) { Render *render = tile->render; tile->ticks = render->ticks; render->ticks += 1; tile_dirty_bump(tile); } /* Queue a tile for calculation. */ static void tile_queue(Tile *tile, VipsRegion *reg) { Render *render = tile->render; VIPS_DEBUG_MSG("tile_queue: adding tile %p %dx%d to dirty\n", tile, tile->area.left, tile->area.top); tile->painted = FALSE; tile_touch(tile); if (render->notify) { /* Add to the list of renders with dirty tiles. The bg * thread will pick it up and paint it. It can be already on * the dirty list. */ tile_dirty_set(tile); render_dirty_put(render); } else { /* no notify ... paint the tile ourselves * synchronously. No need to notify the client since they'll * never see black tiles. */ VIPS_DEBUG_MSG("tile_queue: painting tile %p %dx%d synchronously\n", tile, tile->area.left, tile->area.top); /* While we're computing, let other threads use the cache. * This tile won't get pulled out from under us since it's not * marked as "painted", and it's not on the dirty list. */ g_mutex_unlock(&render->lock); if (vips_region_prepare_to(reg, tile->region, &tile->area, tile->area.left, tile->area.top)) VIPS_DEBUG_MSG_RED("tile_queue: prepare failed\n"); g_mutex_lock(&render->lock); tile->painted = TRUE; } } static void tile_test_clean_ticks(VipsRect *key, Tile *value, Tile **best) { if (value->painted) if (!*best || value->ticks < (*best)->ticks) *best = value; } /* Pick a painted tile to reuse. Search for LRU (slow!). */ static Tile * render_tile_get_painted(Render *render) { Tile *tile; tile = NULL; g_hash_table_foreach(render->tiles, (GHFunc) tile_test_clean_ticks, &tile); if (tile) VIPS_DEBUG_MSG("render_tile_get_painted: reusing painted %p\n", tile); return tile; } /* Ask for an area of calculated pixels. Get from cache, request calculation, * or if we've no threads or no notify, calculate immediately. */ static Tile * render_tile_request(Render *render, VipsRegion *reg, VipsRect *area) { Tile *tile; VIPS_DEBUG_MSG("render_tile_request: asking for %dx%d\n", area->left, area->top); if ((tile = render_tile_lookup(render, area))) { /* We already have a tile at this position. If it's invalid, * ask for a repaint. */ if (tile->region->invalid) tile_queue(tile, reg); else tile_touch(tile); } else if (render->ntiles < render->max_tiles || render->max_tiles == -1) { /* We have fewer tiles than the max. We can just make a new * tile. */ if (!(tile = tile_new(render))) return NULL; render_tile_add(tile, area); tile_queue(tile, reg); } else { /* Need to reuse a tile. Try for an old painted tile first, * then if that fails, reuse a dirty tile. */ if (!(tile = render_tile_get_painted(render)) && !(tile = render_tile_dirty_reuse(render))) { VIPS_DEBUG_MSG("render_tile_request: no tiles to reuse\n"); return NULL; } render_tile_move(tile, area); tile_queue(tile, reg); } return tile; } /* Copy what we can from the tile into the region. */ static void tile_copy(Tile *tile, VipsRegion *to) { VipsRect ovlap; /* Find common pixels. */ vips_rect_intersectrect(&tile->area, &to->valid, &ovlap); g_assert(!vips_rect_isempty(&ovlap)); /* If the tile is painted, copy over the pixels. Otherwise, fill with * zero. */ if (tile->painted && !tile->region->invalid) { int len = VIPS_IMAGE_SIZEOF_PEL(to->im) * ovlap.width; int y; VIPS_DEBUG_MSG("tile_copy: copying calculated pixels for %p %dx%d\n", tile, tile->area.left, tile->area.top); for (y = ovlap.top; y < VIPS_RECT_BOTTOM(&ovlap); y++) { VipsPel *p = VIPS_REGION_ADDR(tile->region, ovlap.left, y); VipsPel *q = VIPS_REGION_ADDR(to, ovlap.left, y); memcpy(q, p, len); } } else { VIPS_DEBUG_MSG("tile_copy: zero filling for %p %dx%d\n", tile, tile->area.left, tile->area.top); vips_region_paint(to, &ovlap, 0); } } /* Loop over the output region, filling with data from cache. */ static int image_fill(VipsRegion *out, void *seq, void *a, void *b, gboolean *stop) { Render *render = (Render *) b; int tile_width = render->tile_width; int tile_height = render->tile_height; VipsRegion *reg = (VipsRegion *) seq; VipsRect *r = &out->valid; int x, y; /* Find top left of tiles we need. */ int xs = (r->left / tile_width) * tile_width; int ys = (r->top / tile_height) * tile_height; VIPS_DEBUG_MSG("image_fill: left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); g_mutex_lock(&render->lock); /* FIXME ... if r fits inside a single tile, we could skip the copy. */ for (y = ys; y < VIPS_RECT_BOTTOM(r); y += tile_height) for (x = xs; x < VIPS_RECT_RIGHT(r); x += tile_width) { VipsRect area; Tile *tile; area.left = x; area.top = y; area.width = tile_width; area.height = tile_height; tile = render_tile_request(render, reg, &area); if (tile) tile_copy(tile, out); else VIPS_DEBUG_MSG_RED("image_fill: argh!\n"); } g_mutex_unlock(&render->lock); return 0; } /* The mask image is 255 / 0 for the state of painted for each tile. */ static int mask_fill(VipsRegion *out, void *seq, void *a, void *b, gboolean *stop) { Render *render = (Render *) a; int tile_width = render->tile_width; int tile_height = render->tile_height; VipsRect *r = &out->valid; int x, y; /* Find top left of tiles we need. */ int xs = (r->left / tile_width) * tile_width; int ys = (r->top / tile_height) * tile_height; VIPS_DEBUG_MSG("mask_fill: left = %d, top = %d, width = %d, height = %d\n", r->left, r->top, r->width, r->height); g_mutex_lock(&render->lock); for (y = ys; y < VIPS_RECT_BOTTOM(r); y += tile_height) for (x = xs; x < VIPS_RECT_RIGHT(r); x += tile_width) { VipsRect area; Tile *tile; int value; area.left = x; area.top = y; area.width = tile_width; area.height = tile_height; tile = render_tile_lookup(render, &area); value = (tile && tile->painted && !tile->region->invalid) ? 255 : 0; /* Only mark painted tiles containing valid pixels. */ vips_region_paint(out, &area, value); } g_mutex_unlock(&render->lock); return 0; } /* Get the first render with dirty tiles. */ static Render * render_dirty_get(void) { Render *render; /* Wait for a render with dirty tiles. */ vips_semaphore_down(&n_render_dirty_sem); g_mutex_lock(&render_dirty_lock); /* Just take the head of the jobs list ... we sort when we add. */ render = NULL; if (render_dirty_all) { render = (Render *) render_dirty_all->data; /* Ref the render to make sure it can't die while we're * working on it. */ render_ref(render); render_dirty_all = g_slist_remove(render_dirty_all, render); } g_mutex_unlock(&render_dirty_lock); return render; } /* Loop for the background render manager thread. */ static void * render_thread_main(void *client) { Render *render; while (!render_kill) { VIPS_DEBUG_MSG_GREEN("render_thread_main: threadpool start\n"); render_reschedule = FALSE; if ((render = render_dirty_get())) { if (vips_threadpool_run(render->in, render_thread_state_new, render_allocate, render_work, NULL, render)) VIPS_DEBUG_MSG_RED("render_thread_main: " "threadpool_run failed\n"); VIPS_DEBUG_MSG_GREEN("render_thread_main: threadpool return\n"); /* Add back to the jobs list, if we need to. */ render_dirty_put(render); /* _get() does a ref to make sure we keep the render * alive during processing ... unref before we loop. * This can kill off the render. */ render_unref(render); } } /* We are exiting, so render_thread must now be NULL. */ render_thread = NULL; return NULL; } static int render_allocate_private(VipsThreadState *state, void *a, gboolean *stop) { Render *render = (Render *) a; RenderThreadState *rstate = (RenderThreadState *) state; /* Wait for a dirty tile to arrive on this render. */ vips_semaphore_down(&render->dirty_sem); /* The mask or image is closing, we must exit. */ if (render->shutdown) { *stop = TRUE; rstate->tile = NULL; return 0; } /* Get the dirty tile, if any. */ g_mutex_lock(&render->lock); rstate->tile = render_tile_dirty_get(render); VIPS_DEBUG_MSG_AMBER("render_allocate_private: allocated tile %p\n", rstate->tile); g_mutex_unlock(&render->lock); return 0; } /* A worker for a private render. */ static void render_work_private(void *data, void *null) { VIPS_DEBUG_MSG_AMBER("render_work_private: start\n"); Render *render = (Render *) data; /* vips__worker_exit() uses this to find the render to check for * shutdown. */ g_private_set(&render_worker_key, render); // this will quit on ->shutdown == TRUE if (vips_threadpool_run(render->in, render_thread_state_new, render_allocate_private, render_work, NULL, render)) VIPS_DEBUG_MSG_RED("render_work_private: threadpool_run failed\n"); g_private_set(&render_worker_key, NULL); render_unref(render); VIPS_DEBUG_MSG_AMBER("render_work_private: stop\n"); } static void * vips__sink_screen_once(void *data) { g_assert(!render_thread); vips_semaphore_init(&n_render_dirty_sem, 0, "n_render_dirty"); /* Don't use vips_thread_execute(), since this thread will only be * ended by vips_shutdown, and that isn't always called. */ render_thread = vips_g_thread_new("sink_screen", render_thread_main, NULL); return NULL; } /** * vips_sink_screen: (method) * @in: input image * @out: (out): output image * @mask: mask image indicating valid pixels * @tile_width: tile width * @tile_height: tile height * @max_tiles: maximum tiles to cache * @priority: rendering priority * @notify_fn: (scope call) (closure a) (nullable): pixels are ready notification callback * @a: (nullable): client data for callback * * This operation renders @in in the background, making pixels available * on @out as they are calculated. The @notify_fn callback is run every * time a new set of pixels are available. Calculated pixels are kept in * a cache with tiles sized @tile_width by @tile_height pixels and with at * most @max_tiles tiles. If @max_tiles is -1, the cache is of unlimited * size (up to the maximum image * size). The @mask image is a one-band * uchar image and has 255 for pixels which are currently in cache and 0 * for uncalculated pixels. * * Renders with a positive priority are assumed to be large, high-priority, * foreground images. Although there can be many of these, only one is ever * active, to avoid overcommitting threads. * * Renders with a negative priority are assumed to be small, thumbnail images, * consisting of a single tile. Single tile images are effectively * single-threaded, so all these renders are evaluated together. * * Calls to [method@Region.prepare] on @out return immediately and hold * whatever is currently in cache for that [struct@Rect] (check @mask to see * which parts of the [struct@Rect] are valid). Any pixels in the [struct@Rect] * which are not in cache are added to a queue, and the @notify_fn * callback will trigger when those pixels are ready. * * The @notify_fn callback is run from one of the background threads. In the * callback you need to somehow send a message to the main thread that the * pixels are ready. In a glib-based application, this is easily done with * [func@GLib.idle_add]. * * If @notify_fn is `NULL` then [method@Image.sink_screen] runs synchronously. * [method@Region.prepare] on @out will always block until the pixels have been * calculated. * * ::: seealso * [method@Image.tilecache], [method@Region.prepare], * [method@Image.sink_disc], [method@Image.sink]. * * Returns: 0 on success, -1 on error. */ int vips_sink_screen(VipsImage *in, VipsImage *out, VipsImage *mask, int tile_width, int tile_height, int max_tiles, int priority, VipsSinkNotify notify_fn, void *a) { static GOnce once = G_ONCE_INIT; Render *render; VIPS_ONCE(&once, vips__sink_screen_once, NULL); if (tile_width <= 0 || tile_height <= 0 || max_tiles < -1) { vips_error("vips_sink_screen", "%s", _("bad parameters")); return -1; } if (vips_image_pio_input(in) || vips_image_pipelinev(out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; if (mask) { if (vips_image_pipelinev(mask, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; mask->Bands = 1; mask->BandFmt = VIPS_FORMAT_UCHAR; mask->Type = VIPS_INTERPRETATION_B_W; mask->Coding = VIPS_CODING_NONE; } if (!(render = render_new(in, out, mask, tile_width, tile_height, max_tiles, priority, notify_fn, a))) return -1; VIPS_DEBUG_MSG("vips_sink_screen: max = %d, %p\n", max_tiles, render); if (render->private_threadpool) { render_ref(render); vips_thread_execute("private threadpool", render_work_private, render); } if (vips_image_generate(out, vips_start_one, image_fill, vips_stop_one, in, render)) return -1; if (mask && vips_image_generate(mask, NULL, mask_fill, NULL, render, NULL)) return -1; return 0; } int vips__print_renders(void) { int n_leaks; n_leaks = 0; #ifdef VIPS_DEBUG_AMBER if (render_num_renders > 0) { printf("%d active renders\n", render_num_renders); n_leaks += render_num_renders; } #endif /*VIPS_DEBUG_AMBER*/ g_mutex_lock(&render_dirty_lock); n_leaks += g_slist_length(render_dirty_all); if (render_dirty_all) printf("dirty renders\n"); g_mutex_unlock(&render_dirty_lock); return n_leaks; } libvips-8.18.2/libvips/iofuncs/source.c000066400000000000000000001014261516303661500200560ustar00rootroot00000000000000/* A byte source/sink .. it can be a pipe, file descriptor, memory area, * socket, node.js stream, etc. * * 19/6/14 * * 3/2/20 * - add vips_pipe_read_limit_set() * 3/10/20 * - improve behaviour with read and seek on pipes * 26/11/20 * - use _setmode() on win to force binary read for previously opened * descriptors * 8/10/21 * - fix named pipes * 10/5/22 * - add vips_source_new_from_target() */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define TEST_SANITY #define VIPS_DEBUG #define DEBUG_MINIMISE */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ #include #include /** * VipsSource: * * A [class@Source] provides a unified interface for reading, seeking, and * mapping data, regardless of the underlying source type. * * This source can originate from something like a socket, file or memory * area. * * During the header phase, we save data from unseekable sources in a buffer * so readers can rewind and read again. We don't buffer data during the * decode stage. */ /** * VipsSourceCustom: * * Subclass of [class@Source] with action signals for handlers. * * This is supposed to be useful for language bindings. */ /** * VipsTarget: * * A [class@Target] provides a unified interface for writing data to various * output destinations. * * This target could be a socket, file, memory area, or any other destination * that accepts byte data. */ /** * VipsTargetCustom: * * Subclass of [class@Target] with action signals for handlers. * * This is supposed to be useful for language bindings. */ #define MODE_READ CLOEXEC(BINARYIZE(O_RDONLY)) /* -1 on a pipe isn't actually unbounded. Have a limit to prevent * huge sources accidentally filling memory. * * This can be configured with vips_pipe_read_limit_set(). */ static gint64 vips__pipe_read_limit = 1024 * 1024 * 1024; /** * vips_pipe_read_limit_set: * @limit: maximum number of bytes to buffer from a pipe * * If a source does not support mmap or seek and the source is * used with a loader that can only work from memory, then the data will be * automatically read into memory to EOF before the loader starts. This can * produce high memory use if the descriptor represents a large object. * * Use [func@pipe_read_limit_set] to limit the size of object that * will be read in this way. The default is 1GB. * * Set a value of -1 to mean no limit. * * ::: seealso * `--vips-pipe-read-limit` and the environment variable * `VIPS_PIPE_READ_LIMIT`. */ void vips_pipe_read_limit_set(gint64 limit) { vips__pipe_read_limit = limit; } G_DEFINE_TYPE(VipsSource, vips_source, VIPS_TYPE_CONNECTION); /* Does this source support seek. You must unminimise before calling this. */ static int vips_source_test_seek(VipsSource *source) { if (!source->have_tested_seek) { VipsSourceClass *class = VIPS_SOURCE_GET_CLASS(source); source->have_tested_seek = TRUE; VIPS_DEBUG_MSG("vips_source_can_seek: testing seek ..\n"); /* Can we seek this input? * * We need to call the method directly rather than via * vips_source_seek() etc. or we might trigger seek emulation. */ if (source->data || class->seek(source, 0, SEEK_CUR) != -1) { gint64 length; VIPS_DEBUG_MSG(" seekable source\n"); /* We should be able to get the length of seekable * objects. */ if ((length = vips_source_length(source)) == -1) return -1; source->length = length; /* If we can seek, we won't need to save header bytes. */ VIPS_FREEF(g_byte_array_unref, source->header_bytes); } else { /* Not seekable. This must be some kind of pipe. */ VIPS_DEBUG_MSG(" not seekable\n"); source->is_pipe = TRUE; } } return 0; } /* We can't test for seekability or length during _build, since the read and * seek signal handlers might not have been connected yet. Instead, we test * when we first need to know. */ static int vips_source_test_features(VipsSource *source) { if (vips_source_unminimise(source) || vips_source_test_seek(source)) return -1; return 0; } #ifdef TEST_SANITY static void vips_source_sanity(VipsSource *source) { if (source->data) { /* A memory buffer. Not a pipe (can map and seek). */ g_assert(!source->is_pipe); /* Read position must lie within the buffer. */ g_assert(source->read_position >= 0); g_assert(source->read_position <= source->length); /* After we're done with the header, the sniff buffer should * be gone. */ g_assert(!source->decode || !source->sniff); /* Have length. */ g_assert(source->length != -1); } else if (source->is_pipe) { /* Something like a descriptor we can't seek. It might not have * ->descriptor valid, that could be held in a subclass. */ if (source->decode) { /* Reading pixel data. */ g_assert(!source->header_bytes); g_assert(!source->sniff); } else { /* Reading header data. */ g_assert(source->header_bytes); g_assert(source->read_position >= 0); g_assert(source->read_position <= source->header_bytes->len); } /* No length available. */ g_assert(source->length == -1); } else { /* Something like a descriptor we can seek. It might not have * ->descriptor valid, that could be held in a subclass. */ /* After we're done with the header, the sniff buffer should * be gone. */ if (source->decode) g_assert(!source->sniff); /* Once we've tested seek, the read position must lie within * the file. */ if (source->have_tested_seek) { g_assert(source->length != -1); g_assert(source->read_position >= 0); g_assert(source->read_position <= source->length); } } } #endif /*TEST_SANITY*/ #ifdef TEST_SANITY #define SANITY(S) vips_source_sanity(S) #warning "sanity tests on in source.c" #else /*!TEST_SANITY*/ #define SANITY(S) #endif /*TEST_SANITY*/ static void vips_source_finalize(GObject *gobject) { VipsSource *source = VIPS_SOURCE(gobject); #ifdef DEBUG_MINIMISE printf("vips_source_finalize: %p\n", source); #endif /*DEBUG_MINIMISE*/ VIPS_FREEF(g_byte_array_unref, source->header_bytes); VIPS_FREEF(g_byte_array_unref, source->sniff); if (source->mmap_baseaddr) { vips__munmap(source->mmap_baseaddr, source->mmap_length); source->mmap_baseaddr = NULL; } G_OBJECT_CLASS(vips_source_parent_class)->finalize(gobject); } static int vips_source_build(VipsObject *object) { VipsConnection *connection = VIPS_CONNECTION(object); VipsSource *source = VIPS_SOURCE(object); VIPS_DEBUG_MSG("vips_source_build: %p\n", source); if (VIPS_OBJECT_CLASS(vips_source_parent_class)->build(object)) return -1; if (vips_object_argument_isset(object, "filename") && vips_object_argument_isset(object, "descriptor")) { vips_error(vips_connection_nick(connection), "%s", _("don't set 'filename' and 'descriptor'")); return -1; } /* unminimise will open the filename. */ if (vips_object_argument_isset(object, "filename") && vips_source_unminimise(source)) return -1; if (vips_object_argument_isset(object, "descriptor")) { connection->descriptor = dup(connection->descriptor); connection->close_descriptor = connection->descriptor; #ifdef G_OS_WIN32 /* Windows will create eg. stdin and stdout in text mode. * We always read in binary mode. */ _setmode(connection->descriptor, _O_BINARY); #endif /*G_OS_WIN32*/ } if (vips_object_argument_isset(object, "blob")) { size_t length; if (!(source->data = vips_blob_get(source->blob, &length))) return -1; source->length = VIPS_MIN(length, G_MAXSSIZE); } return 0; } static gint64 vips_source_read_real(VipsSource *source, void *data, size_t length) { VipsConnection *connection = VIPS_CONNECTION(source); gint64 bytes_read; VIPS_DEBUG_MSG("vips_source_read_real:\n"); do { bytes_read = read(connection->descriptor, data, length); } while (bytes_read < 0 && errno == EINTR); return bytes_read; } static gint64 vips_source_seek_real(VipsSource *source, gint64 offset, int whence) { VipsConnection *connection = VIPS_CONNECTION(source); VIPS_DEBUG_MSG("vips_source_seek_real:\n"); /* Like _read_real(), we must not set a vips_error. We need to use the * vips__seek wrapper so we can seek long files on Windows. */ if (connection->descriptor != -1) return vips__seek_no_error(connection->descriptor, offset, whence); return -1; } static void vips_source_class_init(VipsSourceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); gobject_class->finalize = vips_source_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "source"; object_class->description = _("input source"); object_class->build = vips_source_build; class->read = vips_source_read_real; class->seek = vips_source_seek_real; VIPS_ARG_BOXED(class, "blob", 3, _("Blob"), _("Blob to load from"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSource, blob), VIPS_TYPE_BLOB); } static void vips_source_init(VipsSource *source) { source->length = -1; source->sniff = g_byte_array_new(); source->header_bytes = g_byte_array_new(); } /** * vips_source_new_from_descriptor: * @descriptor: read from this file descriptor * * Create an source attached to a file descriptor. @descriptor is * closed with [`close()`](man:close(2)) when source is finalized. * * Returns: a new source. */ VipsSource * vips_source_new_from_descriptor(int descriptor) { VipsSource *source; VIPS_DEBUG_MSG("vips_source_new_from_descriptor: %d\n", descriptor); source = VIPS_SOURCE(g_object_new(VIPS_TYPE_SOURCE, "descriptor", descriptor, NULL)); if (vips_object_build(VIPS_OBJECT(source))) { VIPS_UNREF(source); return NULL; } SANITY(source); return source; } /** * vips_source_new_from_file: * @filename: read from this filename * * Create a source attached to a file. * * If this descriptor does not support mmap and the source is * used with a loader that can only work from memory, then the data will be * automatically read into memory to EOF before the loader starts. This can * produce high memory use if the descriptor represents a large object. * * Use [func@pipe_read_limit_set] to limit the size of object that * will be read in this way. The default is 1GB. * * Returns: a new source. */ VipsSource * vips_source_new_from_file(const char *filename) { VipsSource *source; VIPS_DEBUG_MSG("vips_source_new_from_file: %s\n", filename); source = VIPS_SOURCE(g_object_new(VIPS_TYPE_SOURCE, "filename", filename, NULL)); if (vips_object_build(VIPS_OBJECT(source))) { VIPS_UNREF(source); return NULL; } SANITY(source); return source; } /** * vips_source_new_from_blob: * @blob: memory area to load * * Create a source attached to an area of memory. * * Returns: a new source. */ VipsSource * vips_source_new_from_blob(VipsBlob *blob) { VipsSource *source; VIPS_DEBUG_MSG("vips_source_new_from_blob: %p\n", blob); source = VIPS_SOURCE(g_object_new(VIPS_TYPE_SOURCE, "blob", blob, NULL)); if (vips_object_build(VIPS_OBJECT(source))) { VIPS_UNREF(source); return NULL; } SANITY(source); return source; } /** * vips_source_new_from_target: * @target: build the source from this target * * Create a source from a temp target that has been written to. * * Returns: a new source. */ VipsSource * vips_source_new_from_target(VipsTarget *target) { VipsConnection *connection = VIPS_CONNECTION(target); VipsSource *source; VIPS_DEBUG_MSG("vips_source_new_from_target: %p\n", target); /* Flush output buffer, move memory into the blob, etc. */ if (vips_target_end(target)) return NULL; if (connection->descriptor > 0) source = vips_source_new_from_descriptor(connection->descriptor); else if (target->memory) { VipsBlob *blob; g_object_get(target, "blob", &blob, NULL); source = vips_source_new_from_blob(blob); vips_area_unref(VIPS_AREA(blob)); } else { vips_error(vips_connection_nick(connection), "%s", _("unimplemented target")); return NULL; } return source; } /** * vips_source_new_from_memory: * @data: memory area to load * @length: size of memory area * * Create a source attached to an area of memory. * * You must not free @data while the source is active. * * Returns: a new source. */ VipsSource * vips_source_new_from_memory(const void *data, size_t length) { VipsSource *source; VipsBlob *blob; VIPS_DEBUG_MSG("vips_source_new_from_buffer: %p, length = %zd\n", data, length); /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, data, length); source = vips_source_new_from_blob(blob); vips_area_unref(VIPS_AREA(blob)); SANITY(source); return source; } /** * vips_source_new_from_options: * @options: option string * * Create a source from an option string. * * Returns: a new source. */ VipsSource * vips_source_new_from_options(const char *options) { VipsSource *source; VIPS_DEBUG_MSG("vips_source_new_from_options: %s\n", options); source = VIPS_SOURCE(g_object_new(VIPS_TYPE_SOURCE, NULL)); if (vips_object_set_from_string(VIPS_OBJECT(source), options) || vips_object_build(VIPS_OBJECT(source))) { VIPS_UNREF(source); return NULL; } SANITY(source); return source; } /** * vips_source_minimise: * @source: source to operate on * * Minimise the source. As many resources as can be safely removed are * removed. Use [method@Source.unminimise] to restore the source if you wish to * use it again. * * Loaders should call this in response to the minimise signal on their output * image. */ void vips_source_minimise(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); SANITY(source); (void) vips_source_test_features(source); if (connection->filename && connection->descriptor != -1 && connection->tracked_descriptor == connection->descriptor && !source->is_pipe) { #ifdef DEBUG_MINIMISE printf("vips_source_minimise: %p %s\n", source, vips_connection_nick(VIPS_CONNECTION(source))); #endif /*DEBUG_MINIMISE*/ vips_tracked_close(connection->tracked_descriptor); connection->tracked_descriptor = -1; connection->descriptor = -1; } SANITY(source); } /** * vips_source_unminimise: * @source: source to operate on * * Restore the source after minimisation. This is called at the start * of every source method, so loaders should not usually need this. * * ::: seealso * [method@Source.minimise]. * * Returns: 0 on success, or -1 on error. */ int vips_source_unminimise(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); if (connection->descriptor == -1 && connection->tracked_descriptor == -1 && connection->filename) { int fd; #ifdef DEBUG_MINIMISE printf("vips_source_unminimise: %p %s\n", source, vips_connection_nick(VIPS_CONNECTION(source))); #endif /*DEBUG_MINIMISE*/ if ((fd = vips_tracked_open(connection->filename, MODE_READ, 0)) == -1) { vips_error_system(errno, vips_connection_nick(connection), "%s", _("unable to open for read")); return -1; } connection->tracked_descriptor = fd; connection->descriptor = fd; if (vips_source_test_seek(source)) return -1; /* It might be a named pipe. */ if (!source->is_pipe) { VIPS_DEBUG_MSG("vips_source_unminimise: restoring " "read position %" G_GINT64_FORMAT "\n", source->read_position); if (vips__seek(connection->descriptor, source->read_position, SEEK_SET) == -1) return -1; } } return 0; } /** * vips_source_decode: * @source: source to operate on * * Signal the end of header read and the start of the pixel decode phase. * After this, you can no longer seek on this source. * * Loaders should call this at the end of header read. * * ::: seealso * [method@Source.unminimise]. * * Returns: 0 on success, -1 on error. */ int vips_source_decode(VipsSource *source) { VIPS_DEBUG_MSG("vips_source_decode:\n"); SANITY(source); if (!source->decode) { source->decode = TRUE; VIPS_FREEF(g_byte_array_unref, source->sniff); /* Now decode is set, header_bytes will be freed once it's * exhausted, see vips_source_read(). */ } vips_source_minimise(source); SANITY(source); return 0; } #ifdef VIPS_DEBUG static void vips_source_print(VipsSource *source) { printf("vips_source_print: %p\n", source); printf(" source->read_position = %zd\n", source->read_position); printf(" source->is_pipe = %d\n", source->is_pipe); printf(" source->length = %zd\n", source->length); printf(" source->data = %p\n", source->data); printf(" source->header_bytes = %p\n", source->header_bytes); if (source->header_bytes) printf(" source->header_bytes->len = %d\n", source->header_bytes->len); printf(" source->sniff = %p\n", source->sniff); if (source->sniff) printf(" source->sniff->len = %d\n", source->sniff->len); } #endif /*VIPS_DEBUG*/ /** * vips_source_read: * @source: source to operate on * @buffer: store bytes here * @length: length of @buffer in bytes * * Read up to @length bytes from @source and store the bytes in @buffer. * Return the number of bytes actually read. If all bytes have been read from * the file, return 0. * * Arguments exactly as [`read()`](man:read(2)). * * Returns: the number of bytes read, 0 on end of file, -1 on error. */ gint64 vips_source_read(VipsSource *source, void *buffer, size_t length) { VipsSourceClass *class = VIPS_SOURCE_GET_CLASS(source); gint64 total_read; VIPS_DEBUG_MSG("vips_source_read:\n"); SANITY(source); if (vips_source_unminimise(source) || vips_source_test_features(source)) return -1; total_read = 0; if (source->data) { /* The whole thing is in memory somehow. */ gint64 available = VIPS_MIN(length, source->length - source->read_position); VIPS_DEBUG_MSG(" %zd bytes from memory\n", available); memcpy(buffer, (char *) source->data + source->read_position, available); source->read_position += available; total_read += available; } else { /* Some kind of filesystem or custom source. * * Get what we can from header_bytes. We may need to read * some more after this. */ if (source->header_bytes && source->read_position < source->header_bytes->len) { gint64 available = VIPS_MIN(length, source->header_bytes->len - source->read_position); VIPS_DEBUG_MSG(" %zd bytes from cache\n", available); memcpy(buffer, source->header_bytes->data + source->read_position, available); source->read_position += available; buffer = (char *) buffer + available; length -= available; total_read += available; } /* We're in pixel decode mode and we've exhausted the header * cache. We can safely junk it. */ if (source->decode && source->header_bytes && source->read_position >= source->header_bytes->len) VIPS_FREEF(g_byte_array_unref, source->header_bytes); /* Any more bytes requested? Call the read() vfunc. */ if (length > 0) { gint64 bytes_read; VIPS_DEBUG_MSG(" calling class->read()\n"); bytes_read = class->read(source, buffer, length); VIPS_DEBUG_MSG(" %zd bytes from read()\n", bytes_read); if (bytes_read == -1) { vips_error_system(errno, vips_connection_nick(VIPS_CONNECTION(source)), "%s", _("read error")); return -1; } /* We need to save bytes if we're in header mode and * we can't seek or map. */ if (source->header_bytes && source->is_pipe && !source->decode && bytes_read > 0) g_byte_array_append(source->header_bytes, buffer, bytes_read); source->read_position += bytes_read; total_read += bytes_read; } } VIPS_DEBUG_MSG(" %zd bytes total\n", total_read); SANITY(source); return total_read; } /* Read to a position. * * target == -1 means read to end of source -- useful for forcing a pipe into * memory, for example. This will always set length to the pipe length. * * If we hit EOF and we're buffering, set length on the pipe and turn it into * a memory source. * * read_position is left somewhere indeterminate. */ static int vips_source_pipe_read_to_position(VipsSource *source, gint64 target) { const char *nick = vips_connection_nick(VIPS_CONNECTION(source)); unsigned char buffer[4096]; /* This is only useful for pipes (sources where we don't know the * length). */ g_assert(source->length == -1); g_assert(source->is_pipe); while (target == -1 || source->read_position < target) { gint64 bytes_read; bytes_read = vips_source_read(source, buffer, 4096); if (bytes_read == -1) return -1; if (bytes_read == 0) { /* No more bytes available, we must be at EOF. */ source->length = source->read_position; /* Have we been buffering the whole thing? We can * become a memory source. */ if (source->header_bytes) { source->data = source->header_bytes->data; source->is_pipe = FALSE; /* TODO ... we could close more fds here. */ vips_source_minimise(source); } break; } if (vips__pipe_read_limit != -1 && source->read_position > vips__pipe_read_limit) { vips_error(nick, "%s", _("pipe too long")); return -1; } } return 0; } /* Convert a seekable source that can't be mapped (eg. a custom input with a * seek method) into a memory source. */ static int vips_source_read_to_memory(VipsSource *source) { GByteArray *byte_array; gint64 read_position; unsigned char *q; VIPS_DEBUG_MSG("vips_source_read_to_memory:\n"); g_assert(!source->is_pipe); g_assert(!source->blob); g_assert(!source->header_bytes); g_assert(source->length >= 0); if (G_UNLIKELY(source->length > UINT_MAX)) { vips_error(vips_connection_nick(VIPS_CONNECTION(source)), "%s", _("length overflow")); return -1; } if (vips_source_rewind(source)) return -1; /* We know the length, so we can size the buffer correctly and read * directly to it. */ byte_array = g_byte_array_new(); g_byte_array_set_size(byte_array, (guint) source->length); read_position = 0; q = byte_array->data; while (read_position < source->length) { gint64 bytes_read; bytes_read = vips_source_read(source, q, VIPS_MAX(4096, source->length - read_position)); if (bytes_read == -1) { VIPS_FREEF(g_byte_array_unref, byte_array); return -1; } if (bytes_read == 0) break; read_position += bytes_read; q += bytes_read; } /* Steal the byte_array pointer and turn into a memory source. * * We save byte_array in the header_bytes field to get it freed when * we are freed. */ source->data = byte_array->data; source->is_pipe = FALSE; source->header_bytes = byte_array; vips_source_minimise(source); return 0; } static int vips_source_descriptor_to_memory(VipsSource *source) { VipsConnection *connection = VIPS_CONNECTION(source); VIPS_DEBUG_MSG("vips_source_descriptor_to_memory:\n"); g_assert(!source->blob); g_assert(!source->mmap_baseaddr); if (!(source->mmap_baseaddr = vips__mmap(connection->descriptor, FALSE, source->length, 0))) return -1; /* And it's now a memory source. */ source->data = source->mmap_baseaddr; source->mmap_length = source->length; return 0; } /** * vips_source_is_mappable: * @source: source to operate on * * Some sources can be efficiently mapped into memory. * You can still use [method@Source.map] if this function returns `FALSE`, * but it will be slow. * * Returns: `TRUE` if the source can be efficiently mapped into memory. */ gboolean vips_source_is_mappable(VipsSource *source) { if (vips_source_unminimise(source) || vips_source_test_features(source)) return -1; /* Already a memory object, or there's a filename we can map, or * there's a seekable descriptor. */ return source->data || VIPS_CONNECTION(source)->filename || (!source->is_pipe && VIPS_CONNECTION(source)->descriptor != -1); } /** * vips_source_is_file: * @source: source to operate on * * Test if this source is a simple file with support for seek. Named pipes, * for example, will fail this test. If `TRUE`, you can use * [method@Connection.filename] to find the filename. * * Use this to add basic source support for older loaders which can only work * on files. * * Returns: `TRUE` if the source is a simple file. */ gboolean vips_source_is_file(VipsSource *source) { if (vips_source_unminimise(source) || vips_source_test_features(source)) return -1; /* There's a filename, and it supports seek. */ return VIPS_CONNECTION(source)->filename && !source->is_pipe; } /** * vips_source_map: * @source: source to operate on * @length: return the file length here, or `NULL` * * Map the source entirely into memory and return a pointer to the * start. If @length is non-NULL, the source size is written to it. * * This operation can take a long time. Use [method@Source.is_mappable] to * check if a source can be mapped efficiently. * * The pointer is valid for as long as @source is alive. * * Returns: a pointer to the start of the file contents, or `NULL` on error. */ const void * vips_source_map(VipsSource *source, size_t *length) { VIPS_DEBUG_MSG("vips_source_map:\n"); SANITY(source); if (vips_source_unminimise(source) || vips_source_test_features(source)) return NULL; /* Try to map the file into memory, if possible. Some filesystems have * mmap disabled, so we don't give up if this fails. */ if (!source->data && vips_source_is_mappable(source)) (void) vips_source_descriptor_to_memory(source); /* If it's not a pipe, we can rewind, get the length, and read the * whole thing. */ if (!source->data && !source->is_pipe && vips_source_read_to_memory(source)) return NULL; /* We don't know the length and must read and assemble in chunks. */ if (source->is_pipe && vips_source_pipe_read_to_position(source, -1)) return NULL; if (length) *length = source->length; SANITY(source); return source->data; } static int vips_source_map_cb(void *a, VipsArea *area) { GObject *gobject = G_OBJECT(area->client); VIPS_UNREF(gobject); return 0; } /** * vips_source_map_blob: * @source: source to operate on * * Just like [method@Source.map], but return a [struct@Blob] containing the * pointer. @source will stay alive as long as the result is alive. * * Returns: a new [struct@Blob] containing the data, or `NULL` on error. */ VipsBlob * vips_source_map_blob(VipsSource *source) { const void *buf; size_t len; VipsBlob *blob; if (!(buf = vips_source_map(source, &len)) || !(blob = vips_blob_new((VipsCallbackFn) vips_source_map_cb, buf, len))) return NULL; /* The source must stay alive until the blob is done. */ g_object_ref(source); VIPS_AREA(blob)->client = source; return blob; } /** * vips_source_seek: * @source: source to operate on * @offset: seek by this offset * @whence: seek relative to this point * * Move the file read position. You can't call this after pixel decode starts. * The arguments are exactly as [`lseek()`](man:lseek(2)). * * Returns: the new file position, or -1 on error. */ gint64 vips_source_seek(VipsSource *source, gint64 offset, int whence) { const char *nick = vips_connection_nick(VIPS_CONNECTION(source)); VipsSourceClass *class = VIPS_SOURCE_GET_CLASS(source); gint64 new_pos; VIPS_DEBUG_MSG( "vips_source_seek: offset = %" G_GINT64_FORMAT ", whence = %d\n", offset, whence); if (vips_source_unminimise(source) || vips_source_test_features(source)) return -1; if (source->data) { switch (whence) { case SEEK_SET: new_pos = offset; break; case SEEK_CUR: new_pos = source->read_position + offset; break; case SEEK_END: new_pos = source->length + offset; break; default: vips_error(nick, "%s", _("bad 'whence'")); return -1; } } else if (source->is_pipe) { switch (whence) { case SEEK_SET: new_pos = offset; break; case SEEK_CUR: new_pos = source->read_position + offset; break; case SEEK_END: /* We have to read the whole source into memory to get * the length. */ if (vips_source_pipe_read_to_position(source, -1)) return -1; new_pos = source->length + offset; break; default: vips_error(nick, "%s", _("bad 'whence'")); return -1; } } else { if ((new_pos = class->seek(source, offset, whence)) == -1) return -1; } /* For pipes, we have to fake seek by reading to that point. This * might hit EOF and turn the pipe into a memory source. */ if (source->is_pipe && vips_source_pipe_read_to_position(source, new_pos)) return -1; /* Don't allow out of range seeks. */ if (new_pos < 0 || (source->length != -1 && new_pos > source->length)) { vips_error(nick, _("bad seek to %" G_GINT64_FORMAT), new_pos); return -1; } source->read_position = new_pos; VIPS_DEBUG_MSG(" new_pos = %" G_GINT64_FORMAT "\n", new_pos); return new_pos; } /** * vips_source_rewind: * @source: source to operate on * * Rewind the source to the start. * * You can't always do this after the pixel decode phase starts -- for * example, pipe-like sources can't be rewound. * * Returns: 0 on success, or -1 on error. */ int vips_source_rewind(VipsSource *source) { VIPS_DEBUG_MSG("vips_source_rewind:\n"); SANITY(source); if (vips_source_test_features(source) || vips_source_seek(source, 0, SEEK_SET) != 0) return -1; /* Back into sniff + header decode state. */ source->decode = FALSE; if (!source->sniff) source->sniff = g_byte_array_new(); SANITY(source); return 0; } /** * vips_source_length: * @source: source to operate on * * Return the length in bytes of the source. Unseekable sources, for * example pipes, will have to be read entirely into memory before the length * can be found, so this operation can take a long time. * * Returns: number of bytes in source, or -1 on error. */ gint64 vips_source_length(VipsSource *source) { gint64 length; gint64 read_position; VIPS_DEBUG_MSG("vips_source_length:\n"); if (vips_source_test_features(source)) return -1; read_position = vips_source_seek(source, 0, SEEK_CUR); length = vips_source_seek(source, 0, SEEK_END); vips_source_seek(source, read_position, SEEK_SET); return length; } /** * vips_source_sniff_at_most: * @source: peek this source * @data: return a pointer to the bytes read here * @length: max number of bytes to read * * Attempt to sniff at most @length bytes from the start of the source. A * pointer to the bytes is returned in @data. The number of bytes actually * read is returned -- it may be less than @length if the file is shorter than * @length. A negative number indicates a read error. * * Do not use it if @length is greater than `UINT_MAX`. * [struct@GLib.ByteArray] stores the length of its data in `guint`, which * may be shorter than `size_t`. * * Returns: number of bytes read, or -1 on error. */ gint64 vips_source_sniff_at_most(VipsSource *source, unsigned char **data, size_t length) { unsigned char *q; gint64 read_position; VIPS_DEBUG_MSG("vips_source_sniff_at_most: %zd bytes\n", length); g_assert(length <= UINT_MAX); SANITY(source); if (vips_source_test_features(source) || vips_source_rewind(source)) return -1; g_byte_array_set_size(source->sniff, (guint) length); read_position = 0; q = source->sniff->data; while (read_position < length) { gint64 bytes_read; bytes_read = vips_source_read(source, q, length - read_position); if (bytes_read == -1) return -1; if (bytes_read == 0) break; read_position += bytes_read; q += bytes_read; } SANITY(source); *data = source->sniff->data; return read_position; } /** * vips_source_sniff: * @source: sniff this source * @length: number of bytes to sniff * * Return a pointer to the first few bytes of the file. If the file is too * short, return `NULL`. * * Returns: a pointer to the bytes at the start of the file, or `NULL` on error. */ unsigned char * vips_source_sniff(VipsSource *source, size_t length) { unsigned char *data; gint64 bytes_read; if (vips_source_test_features(source)) return NULL; bytes_read = vips_source_sniff_at_most(source, &data, length); if (bytes_read == -1) return NULL; if (bytes_read < length) return NULL; return data; } libvips-8.18.2/libvips/iofuncs/sourcecustom.c000066400000000000000000000141001516303661500213010ustar00rootroot00000000000000/* A Source subclass with signals you can easily hook up to other input * sources. * * J.Cupitt, 21/11/19 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG_RED #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #include #include #include "vipsmarshal.h" G_DEFINE_TYPE(VipsSourceCustom, vips_source_custom, VIPS_TYPE_SOURCE); /* Our signals. */ enum { SIG_SEEK, SIG_READ, SIG_LAST }; static guint vips_source_custom_signals[SIG_LAST] = { 0 }; static void vips_source_custom_dispose(GObject *gobject) { VIPS_DEBUG_MSG("vips_source_custom_dispose: %p\n", gobject); G_OBJECT_CLASS(vips_source_custom_parent_class)->dispose(gobject); } static gint64 vips_source_custom_read_real(VipsSource *source, void *buffer, size_t length) { gint64 bytes_read; VIPS_DEBUG_MSG_RED("vips_source_custom_read_real: %p\n", source); /* Return this value (error) if there's no attached handler. */ bytes_read = 0; g_signal_emit(source, vips_source_custom_signals[SIG_READ], 0, buffer, (gint64) length, &bytes_read); VIPS_DEBUG_MSG_RED(" vips_source_custom_read_real, seen %zd bytes\n", bytes_read); return bytes_read; } static gint64 vips_source_custom_seek_real(VipsSource *source, gint64 offset, int whence) { GValue args[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; GValue result = G_VALUE_INIT; gint64 new_position; VIPS_DEBUG_MSG("vips_source_custom_seek_real:\n"); /* Set the signal args. */ g_value_init(&args[0], G_TYPE_OBJECT); g_value_set_object(&args[0], source); g_value_init(&args[1], G_TYPE_INT64); g_value_set_int64(&args[1], offset); g_value_init(&args[2], G_TYPE_INT); g_value_set_int(&args[2], whence); /* Set the default value if no handlers are attached. */ g_value_init(&result, G_TYPE_INT64); g_value_set_int64(&result, -1); /* We need to use this signal interface since we want a default value * if no handlers are attached. */ g_signal_emitv((const GValue *) &args, vips_source_custom_signals[SIG_SEEK], 0, &result); new_position = g_value_get_int64(&result); g_value_unset(&args[0]); g_value_unset(&args[1]); g_value_unset(&args[2]); g_value_unset(&result); VIPS_DEBUG_MSG(" vips_source_custom_seek_real, seen new pos %zd\n", new_position); return new_position; } static gint64 vips_source_custom_read_signal_real(VipsSourceCustom *source_custom, void *data, gint64 length) { VIPS_DEBUG_MSG("vips_source_custom_read_signal_real: %p\n", source_custom); return 0; } static gint64 vips_source_custom_seek_signal_real(VipsSourceCustom *source_custom, gint64 offset, int whence) { VIPS_DEBUG_MSG("vips_source_custom_seek_signal_real:\n"); return -1; } static void vips_source_custom_class_init(VipsSourceCustomClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsSourceClass *source_class = VIPS_SOURCE_CLASS(class); gobject_class->dispose = vips_source_custom_dispose; object_class->nickname = "source_custom"; object_class->description = _("Custom source"); source_class->read = vips_source_custom_read_real; source_class->seek = vips_source_custom_seek_real; class->read = vips_source_custom_read_signal_real; class->seek = vips_source_custom_seek_signal_real; /** * VipsSourceCustom::read: * @source_custom: the source being operated on * @buffer: `gpointer`, buffer to fill * @size: `gint64`, size of buffer * * This signal is emitted to read bytes from the source into @buffer. * * Returns: the number of bytes read. Return 0 for EOF. */ vips_source_custom_signals[SIG_READ] = g_signal_new("read", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsSourceCustomClass, read), NULL, NULL, vips_INT64__POINTER_INT64, G_TYPE_INT64, 2, G_TYPE_POINTER, G_TYPE_INT64); /** * VipsSourceCustom::seek: * @source_custom: the source being operated on * @offset: `gint64`, seek offset * @whence: `gint`, seek origin * * This signal is emitted to seek the source. The handler should * change the source position appropriately. * * The handler for an unseekable source should always return -1. * * Returns: the new seek position. */ vips_source_custom_signals[SIG_SEEK] = g_signal_new("seek", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsSourceCustomClass, seek), NULL, NULL, vips_INT64__INT64_INT, G_TYPE_INT64, 2, G_TYPE_INT64, G_TYPE_INT); } static void vips_source_custom_init(VipsSourceCustom *source_custom) { VIPS_DEBUG_MSG("vips_source_custom_init: %p\n", source_custom); } /** * vips_source_custom_new: * * Create a [class@SourceCustom]. Attach signals to implement read and seek. * * Returns: a new [class@SourceCustom] */ VipsSourceCustom * vips_source_custom_new(void) { VipsSourceCustom *source_custom; VIPS_DEBUG_MSG("vips_source_custom_new:\n"); source_custom = VIPS_SOURCE_CUSTOM( g_object_new(VIPS_TYPE_SOURCE_CUSTOM, NULL)); if (vips_object_build(VIPS_OBJECT(source_custom))) { VIPS_UNREF(source_custom); return NULL; } return source_custom; } libvips-8.18.2/libvips/iofuncs/sourceginput.c000066400000000000000000000145301516303661500213040ustar00rootroot00000000000000/* A Source subclass which wraps a ginputstream. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #include #include G_DEFINE_TYPE(VipsSourceGInputStream, vips_source_g_input_stream, VIPS_TYPE_SOURCE); /* TODO: * - some more docs */ /* This will only be useful for memory and pipe-style streams. It's not * possible to get filename or filenos from GInputStream objects. * Without those two bits of information, important VipsSource features like * mmap and openslide load will not work. * * For sources which are files on local disc, you should use * vips_source_new_from_file() instead. */ static int vips_source_g_input_stream_build(VipsObject *object) { VipsSource *source = VIPS_SOURCE(object); VipsSourceGInputStream *source_ginput = VIPS_SOURCE_G_INPUT_STREAM(source); GError *error = NULL; VIPS_DEBUG_MSG("vips_source_g_input_stream_build: %p\n", source); if (VIPS_OBJECT_CLASS(vips_source_g_input_stream_parent_class)->build(object)) return -1; if (G_IS_FILE_INPUT_STREAM(source_ginput->stream)) { const char *name; /* It's unclear if this will ever produce useful output. */ if (!(source_ginput->info = g_file_input_stream_query_info( G_FILE_INPUT_STREAM(source_ginput->stream), G_FILE_ATTRIBUTE_STANDARD_NAME, NULL, &error))) { vips_g_error(&error); return -1; } #ifdef VIPS_DEBUG { char **attributes; int i; /* Swap G_FILE_ATTRIBUTE_STANDARD_NAME above for "*" to get a * list of all available attributes. */ attributes = g_file_info_list_attributes( source_ginput->info, NULL); printf("stream attributes:\n"); for (i = 0; attributes[i]; i++) { char *name = attributes[i]; char *value; value = g_file_info_get_attribute_as_string( source_ginput->info, name); printf("\t%s = %s\n", name, value); g_free(value); } g_strfreev(attributes); } #endif /*VIPS_DEBUG*/ if ((name = g_file_info_get_name(source_ginput->info))) g_object_set(object, "filename", name, NULL); } if (G_IS_SEEKABLE(source_ginput->stream) && g_seekable_can_seek(G_SEEKABLE(source_ginput->stream))) source_ginput->seekable = G_SEEKABLE(source_ginput->stream); return 0; } static gint64 vips_source_g_input_stream_read(VipsSource *source, void *buffer, size_t length) { VipsSourceGInputStream *source_ginput = VIPS_SOURCE_G_INPUT_STREAM(source); GError *error = NULL; gint64 bytes_read; VIPS_DEBUG_MSG("vips_source_g_input_stream_read: %zd bytes\n", length); /* Do we need to loop on this call? The docs are unclear. */ if ((bytes_read = g_input_stream_read(source_ginput->stream, buffer, length, NULL, &error)) < 0) { VIPS_DEBUG_MSG(" %s\n", error->message); vips_g_error(&error); return -1; } VIPS_DEBUG_MSG(" (returned %zd bytes)\n", bytes_read); return bytes_read; } static GSeekType lseek_to_seek_type(int whence) { switch (whence) { default: case SEEK_CUR: return G_SEEK_CUR; case SEEK_SET: return G_SEEK_SET; case SEEK_END: return G_SEEK_END; } } static gint64 vips_source_g_input_stream_seek(VipsSource *source, gint64 offset, int whence) { VipsSourceGInputStream *source_ginput = VIPS_SOURCE_G_INPUT_STREAM(source); GSeekType type = lseek_to_seek_type(whence); GError *error = NULL; gint64 new_position; VIPS_DEBUG_MSG("vips_source_g_input_stream_seek: " "offset = %zd, whence = %d\n", offset, whence); if (source_ginput->seekable) { if (!g_seekable_seek(source_ginput->seekable, offset, type, NULL, &error)) { vips_g_error(&error); return -1; } new_position = g_seekable_tell(source_ginput->seekable); } else new_position = -1; VIPS_DEBUG_MSG(" (new position = %zd)\n", new_position); return new_position; } static void vips_source_g_input_stream_class_init(VipsSourceGInputStreamClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsSourceClass *source_class = VIPS_SOURCE_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "source_g_input_stream"; object_class->description = _("GInputStream source"); object_class->build = vips_source_g_input_stream_build; source_class->read = vips_source_g_input_stream_read; source_class->seek = vips_source_g_input_stream_seek; VIPS_ARG_OBJECT(class, "stream", 3, _("Stream"), _("GInputStream to read from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSourceGInputStream, stream), G_TYPE_INPUT_STREAM); } static void vips_source_g_input_stream_init(VipsSourceGInputStream *source) { } /** * vips_source_g_input_stream_new: * @stream: read from this stream * * Create a [class@SourceGInputStream] which wraps @stream. * * ::: seealso * [ctor@GInputStream.new_from_source] * * Returns: (transfer full): the new source. */ VipsSourceGInputStream * vips_source_g_input_stream_new(GInputStream *stream) { VipsSourceGInputStream *source; VIPS_DEBUG_MSG("vips_source_g_input_stream_new:\n"); source = VIPS_SOURCE_G_INPUT_STREAM( g_object_new(VIPS_TYPE_SOURCE_G_INPUT_STREAM, "stream", stream, NULL)); if (vips_object_build(VIPS_OBJECT(source))) { VIPS_UNREF(source); return NULL; } return source; } libvips-8.18.2/libvips/iofuncs/system.c000066400000000000000000000253211516303661500201010ustar00rootroot00000000000000/* vips_system(): run a command on an image * * 7/3/00 JC * - hacked it in * 21/10/02 JC * - use mktemp() if mkstemp() is not available * 10/3/03 JC * - out can be NULL * 23/12/04 * - use g_mkstemp() * 8/9/09 * - add .v suffix (thanks Roland) * - use vipsbuf * - rewrite to make it simpler * 2/2/10 * - gtkdoc * 4/6/13 * - redo as a class * - input and output images are now optional * 3/5/14 * - switch to g_spawn_command_line_sync() from popen() ... helps stop * stray command-windows on Windows * 27/3/16 * - allow [options] in out_format * 20/8/25 * - add "cache" argument */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include typedef struct _VipsSystem { VipsOperation parent_instance; VipsArrayImage *in; VipsImage *out; char *cmd_format; char *in_format; char *out_format; char *log; gboolean cache; /* Array of names we wrote the input images to. */ char **in_name; /* Output name without any options, so /tmp/vips-weifh.svg, for * example. */ char *out_name; /* Output name with any options, so /tmp/vips-weifh.svg[scale=2], for * example. */ char *out_name_options; } VipsSystem; typedef VipsOperationClass VipsSystemClass; G_DEFINE_TYPE(VipsSystem, vips_system, VIPS_TYPE_OPERATION); static void vips_system_dispose(GObject *gobject) { VipsSystem *system = (VipsSystem *) gobject; if (system->in_name) { int i; for (i = 0; i < VIPS_AREA(system->in)->n; i++) { g_unlink(system->in_name[i]); VIPS_FREE(system->in_name[i]); } } VIPS_FREE(system->out_name); VIPS_FREE(system->out_name_options); G_OBJECT_CLASS(vips_system_parent_class)->dispose(gobject); } static int vips_system_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsSystem *system = (VipsSystem *) object; int i; char cmd[VIPS_PATH_MAX]; char *p; char *std_output; char *std_error; int result; GError *error = NULL; if (VIPS_OBJECT_CLASS(vips_system_parent_class)->build(object)) return -1; /* Write the input images to files. We must always make copies of the * files, even if this image is a disc file already, in case the * command needs a different format. */ if (system->in) { char *in_format = system->in_format ? system->in_format : "%s.tif"; int n; VipsImage **in = vips_array_image_get(system->in, &n); if (!(system->in_name = VIPS_ARRAY(object, n, char *))) return -1; memset(system->in_name, 0, n * sizeof(char *)); for (i = 0; i < n; i++) { if (!(system->in_name[i] = vips__temp_name(in_format))) return -1; if (vips_image_write_to_file(in[i], system->in_name[i], NULL)) return -1; } } /* Make the output filename. */ if (system->out_format) { char filename[VIPS_PATH_MAX]; char option_string[VIPS_PATH_MAX]; vips__filename_split8(system->out_format, filename, option_string); if (!(system->out_name = vips__temp_name(filename))) return -1; system->out_name_options = g_strconcat(system->out_name, option_string, NULL); } g_strlcpy(cmd, system->cmd_format, VIPS_PATH_MAX); if (system->in) for (i = 0; i < VIPS_AREA(system->in)->n; i++) if (vips__substitute(cmd, VIPS_PATH_MAX, system->in_name[i])) { vips_error(class->nickname, "%s", _("unable to substitute input filename")); return -1; } if (system->out_name && vips__substitute(cmd, VIPS_PATH_MAX, system->out_name)) { vips_error(class->nickname, "%s", _("unable to substitute output filename")); return -1; } /* Swap all "%%" in the string for a single "%". We need this for * compatibility with older printf-based vips_system()s which * needed a double %%. */ for (p = cmd; *p; p++) if (p[0] == '%' && p[1] == '%') memmove(p, p + 1, strlen(p)); #ifdef DEBUG printf("vips_system_build: spawn <<%s>> ...\n", cmd); #endif /*DEBUG*/ if (!g_spawn_command_line_sync(cmd, &std_output, &std_error, &result, &error) || result) { #ifdef DEBUG printf("\t... failed\n"); #endif /*DEBUG*/ if (error) { vips_error(class->nickname, "%s", error->message); g_error_free(error); } if (std_error) { g_strchomp(std_error); if (strcmp(std_error, "") != 0) vips_error(class->nickname, "error output: %s", std_error); VIPS_FREE(std_error); } if (std_output) { g_strchomp(std_output); if (strcmp(std_output, "") != 0) vips_error(class->nickname, "output: %s", std_output); VIPS_FREE(std_output); } vips_error_system(result, class->nickname, _("command \"%s\" failed"), cmd); return -1; } #ifdef DEBUG printf("\t... success\n"); #endif /*DEBUG*/ if (std_error) { g_strchomp(std_error); if (strcmp(std_error, "") != 0) g_warning("stderr output: %s", std_error); } if (std_output) { g_strchomp(std_output); g_object_set(system, "log", std_output, NULL); } VIPS_FREE(std_output); VIPS_FREE(std_error); if (system->out_name_options) { VipsImage *out; if (!(out = vips_image_new_from_file(system->out_name_options, NULL))) return -1; vips_image_set_delete_on_close(out, TRUE); g_object_set(system, "out", out, NULL); } return 0; } static VipsOperationFlags vips_system_get_flags(VipsOperation *operation) { VipsOperationFlags flags = VIPS_OPERATION_CLASS(vips_system_parent_class)->get_flags(operation); VipsSystem *system = (VipsSystem *) operation; if (system->cache) flags &= ~VIPS_OPERATION_NOCACHE; return flags; } static void vips_system_class_init(VipsSystemClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->dispose = vips_system_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "system"; vobject_class->description = _("run an external command"); vobject_class->build = vips_system_build; operation_class->get_flags = vips_system_get_flags; operation_class->flags = VIPS_OPERATION_NOCACHE; VIPS_ARG_BOXED(class, "in", 0, _("Input"), _("Array of input images"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSystem, in), VIPS_TYPE_ARRAY_IMAGE); VIPS_ARG_IMAGE(class, "out", 1, _("Output"), _("Output image"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsSystem, out)); VIPS_ARG_STRING(class, "cmd_format", 2, _("Command"), _("Command to run"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSystem, cmd_format), NULL); VIPS_ARG_STRING(class, "in_format", 3, _("Input format"), _("Format for input filename"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSystem, in_format), NULL); VIPS_ARG_STRING(class, "out_format", 4, _("Output format"), _("Format for output filename"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSystem, out_format), NULL); VIPS_ARG_BOOL(class, "cache", 5, _("Cache"), _("Cache this call"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSystem, cache), FALSE); VIPS_ARG_STRING(class, "log", 6, _("Log"), _("Command log"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsSystem, log), NULL); } static void vips_system_init(VipsSystem *system) { } /** * vips_system: * @cmd_format: command to run * @...: `NULL`-terminated list of optional named arguments * * [ctor@Image.system] runs a command, optionally passing a set of images in and * optionally getting an image back. The command's stdout is returned in @log. * * First, if @in is set, the array of images are written to files. See * [ctor@Image.new_temp_file] to see how temporary files are created. * If @in_format is something like `%s.png`, the file will be written in PNG * format. By default, @in_format is `%s.tif`. * * If @out_format is set, an output filename is formed in the same way. Any * trailing `[options]` are stripped from @out_format. * * The command string to run is made by substituting the first set of `%s` * in @cmd_format for the names of the input files, if @in is set, and then * the next `%s` for the output filename, if @out_format is set. * You can put a number between the `%` and the `s` to change the order * in which the substitution occurs. * * The command is executed with [`popen()`](man:popen(3)) and the output * captured in @log. * * After the command finishes, if @out_format is set, the output image is * opened and returned in @out. You can append `[options]` to @out_format to * control how this open happens. * * Closing @out image will automatically delete the output file. * * Finally the input images are deleted. * * If @cache is set, this call will be added to the libvips operation cache * and reused if possible. * * For example, this call will run the ImageMagick convert program on an * image, using JPEG files to pass images into and out of the convert command. * * ```c * VipsArrayImage *in; * VipsImage *out; * char *log; * * if (vips_system("convert %s -swirl 45 %s", * "in", in, * "out", &out, * "in_format", "%s.jpg", * "out_format", "%s.jpg", * "cache", TRUE, * "log", &log, * NULL)) * error ... * ``` * * ::: tip "Optional arguments" * * @in: [struct@ArrayImage], array of input images * * @out: [class@Image], output, image * * @in_format: `gchararray`, write input files like this * * @out_format: `gchararray`, write output filename like this * * @cache: `gboolean`, cache this call * * @log: `gchararray`, output, stdout of command is returned here * * Returns: 0 on success, -1 on failure. */ int vips_system(const char *cmd_format, ...) { va_list ap; int result; va_start(ap, cmd_format); result = vips_call_split("system", ap, cmd_format); va_end(ap); return result; } libvips-8.18.2/libvips/iofuncs/target.c000066400000000000000000000465121516303661500200500ustar00rootroot00000000000000/* A byte source/sink .. it can be a pipe, file descriptor, memory area, * socket, node.js stream, etc. * * J.Cupitt, 19/6/14 * * 26/11/20 * - use _setmode() on win to force binary write for previously opened * descriptors */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ #include #include /* libtiff needs to be able to seek and read back output files, unfortunately, * so we must open read-write. */ #define MODE_READWRITE CLOEXEC(BINARYIZE(O_RDWR | O_CREAT | O_TRUNC)) G_DEFINE_TYPE(VipsTarget, vips_target, VIPS_TYPE_CONNECTION); static void vips_target_finalize(GObject *gobject) { VipsTarget *target = VIPS_TARGET(gobject); VIPS_DEBUG_MSG("vips_target_finalize:\n"); if (target->memory_buffer) { g_string_free(target->memory_buffer, TRUE); target->memory_buffer = NULL; } if (target->blob) { vips_area_unref(VIPS_AREA(target->blob)); target->blob = NULL; } if (target->delete_on_close && target->delete_on_close_filename) g_unlink(target->delete_on_close_filename); VIPS_FREE(target->delete_on_close_filename); G_OBJECT_CLASS(vips_target_parent_class)->finalize(gobject); } static int vips_target_build(VipsObject *object) { VipsConnection *connection = VIPS_CONNECTION(object); VipsTarget *target = VIPS_TARGET(object); VIPS_DEBUG_MSG("vips_target_build: %p\n", connection); if (VIPS_OBJECT_CLASS(vips_target_parent_class)->build(object)) return -1; if (vips_object_argument_isset(object, "filename") && vips_object_argument_isset(object, "descriptor")) { vips_error(vips_connection_nick(connection), "%s", _("don't set 'filename' and 'descriptor'")); return -1; } // for filename targets, don't create the file we write on _build() -- // do it lazily on the first write or seek if (vips_object_argument_isset(object, "descriptor")) { connection->descriptor = dup(connection->descriptor); connection->close_descriptor = connection->descriptor; #ifdef G_OS_WIN32 /* Windows will create eg. stdin and stdout in text mode. * We always write in binary mode. */ _setmode(connection->descriptor, _O_BINARY); #endif /*G_OS_WIN32*/ } else if (target->memory) target->memory_buffer = g_string_sized_new(VIPS_TARGET_BUFFER_SIZE); return 0; } /* If necessary, create the file we write to from the filename. We do this * lazily on first write or seek, since eg. dzsave might not actually write * to this filename in some cases. */ static int vips_target_create_file(VipsTarget *target) { VipsConnection *connection = VIPS_CONNECTION(target); if (connection->filename && connection->tracked_descriptor == -1) { const char *filename = connection->filename; int fd; /* 0644 is rw user, r group and other. */ if ((fd = vips_tracked_open(filename, MODE_READWRITE, 0644)) == -1) { vips_error_system(errno, vips_connection_nick(connection), "%s", _("unable to open for write")); return -1; } connection->tracked_descriptor = fd; connection->descriptor = fd; } return 0; } static gint64 vips_target_write_real(VipsTarget *target, const void *data, size_t length) { VipsConnection *connection = VIPS_CONNECTION(target); gint64 result; VIPS_DEBUG_MSG("vips_target_write_real: %zd bytes\n", length); if (target->memory_buffer) { VIPS_DEBUG_MSG("vips_target_write_real: to position %zd\n", target->position); g_string_overwrite_len(target->memory_buffer, target->position, data, length); target->position += length; result = length; } else { if (vips_target_create_file(target)) result = -1; else result = write(connection->descriptor, data, length); } return result; } static gint64 vips_target_seek_real(VipsTarget *target, gint64 offset, int whence) { VipsConnection *connection = VIPS_CONNECTION(target); const char *nick = vips_connection_nick(connection); gint64 new_position; VIPS_DEBUG_MSG( "vips_target_seek_real: offset = %" G_GINT64_FORMAT ", whence = %d\n", offset, whence); if (target->memory_buffer) { switch (whence) { case SEEK_SET: new_position = offset; break; case SEEK_CUR: new_position = target->position + offset; break; case SEEK_END: new_position = target->memory_buffer->len + offset; break; default: vips_error(nick, "%s", _("bad 'whence'")); return -1; } if (new_position > target->memory_buffer->len) g_string_set_size(target->memory_buffer, new_position); target->position = new_position; } else if (vips_target_create_file(target)) new_position = -1; else /* We need to use the vips__seek() wrapper so we can seek long * files on Windows. */ new_position = vips__seek_no_error(connection->descriptor, offset, whence); return new_position; } static gint64 vips_target_read_real(VipsTarget *target, void *data, size_t length) { gint64 bytes_read; VIPS_DEBUG_MSG("vips_target_read_real: %zd bytes\n", length); if (target->memory_buffer) { bytes_read = VIPS_MIN(length, target->memory_buffer->len - target->position); VIPS_DEBUG_MSG(" %zd bytes from memory\n", bytes_read); memcpy(data, target->memory_buffer->str + target->position, bytes_read); target->position += bytes_read; } else { VipsConnection *connection = VIPS_CONNECTION(target); int fd = connection->descriptor; do { bytes_read = read(fd, data, length); } while (bytes_read < 0 && errno == EINTR); } VIPS_DEBUG_MSG(" read %zd bytes\n", bytes_read); return bytes_read; } static int vips_target_end_real(VipsTarget *target) { VIPS_DEBUG_MSG("vips_target_finish_real:\n"); return 0; } static void vips_target_finish_real(VipsTarget *target) { VIPS_DEBUG_MSG("vips_target_finish_real:\n"); } static void vips_target_class_init(VipsTargetClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); gobject_class->finalize = vips_target_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "target"; object_class->description = _("Target"); object_class->build = vips_target_build; class->write = vips_target_write_real; class->read = vips_target_read_real; class->seek = vips_target_seek_real; class->end = vips_target_end_real; class->finish = vips_target_finish_real; VIPS_ARG_BOOL(class, "memory", 3, _("Memory"), _("File descriptor should output to memory"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsTarget, memory), FALSE); /* SET_ALWAYS means that blob is set by C and the obj system is not * involved in creation or destruction. It can be read at any time. */ VIPS_ARG_BOXED(class, "blob", 4, _("Blob"), _("Blob to save to"), VIPS_ARGUMENT_SET_ALWAYS, G_STRUCT_OFFSET(VipsTarget, blob), VIPS_TYPE_BLOB); } static void vips_target_init(VipsTarget *target) { target->blob = vips_blob_new(NULL, NULL, 0); target->write_point = 0; } /** * vips_target_new_to_descriptor: (constructor) * @descriptor: write to this file descriptor * * Create a target attached to a file descriptor. * @descriptor is kept open until the target is finalized. * * ::: seealso * [ctor@Target.new_to_file]. * * Returns: a new target. */ VipsTarget * vips_target_new_to_descriptor(int descriptor) { VipsTarget *target; VIPS_DEBUG_MSG("vips_target_new_to_descriptor: %d\n", descriptor); target = VIPS_TARGET(g_object_new(VIPS_TYPE_TARGET, "descriptor", descriptor, NULL)); if (vips_object_build(VIPS_OBJECT(target))) { VIPS_UNREF(target); return NULL; } return target; } /** * vips_target_new_to_file: (constructor) * @filename: write to this file * * Create a target attached to a file. * * Returns: a new target. */ VipsTarget * vips_target_new_to_file(const char *filename) { VipsTarget *target; VIPS_DEBUG_MSG("vips_target_new_to_file: %s\n", filename); target = VIPS_TARGET(g_object_new(VIPS_TYPE_TARGET, "filename", filename, NULL)); if (vips_object_build(VIPS_OBJECT(target))) { VIPS_UNREF(target); return NULL; } return target; } /** * vips_target_new_to_memory: (constructor) * * Create a target which will write to a memory area. Read from @blob to get * memory. * * ::: seealso * [ctor@Target.new_to_file]. * * Returns: a new target. */ VipsTarget * vips_target_new_to_memory(void) { VipsTarget *target; VIPS_DEBUG_MSG("vips_target_new_to_memory:\n"); target = VIPS_TARGET(g_object_new(VIPS_TYPE_TARGET, "memory", TRUE, NULL)); if (vips_object_build(VIPS_OBJECT(target))) { VIPS_UNREF(target); return NULL; } return target; } /** * vips_target_new_temp: (constructor) * @based_on: base the temporary target on this target * * Create a temporary target -- either a temporary file on disc, or an area in * memory, depending on what sort of target @based_on is. * * ::: seealso * [ctor@Target.new_to_file]. * * Returns: a new target. */ VipsTarget * vips_target_new_temp(VipsTarget *based_on) { VipsTarget *target; VIPS_DEBUG_MSG("vips_target_new_temp: %p\n", based_on); if (vips_connection_filename(VIPS_CONNECTION(based_on))) { int descriptor; char *filename; if (!(filename = vips__temp_name("%s.target"))) return NULL; if ((descriptor = vips__open_image_write(filename, TRUE)) < 0) { g_free(filename); return NULL; } if (!(target = vips_target_new_to_descriptor(descriptor))) { g_free(filename); vips_tracked_close(descriptor); return NULL; } vips_tracked_close(descriptor); target->delete_on_close = TRUE; target->delete_on_close_filename = filename; } else target = vips_target_new_to_memory(); return target; } static int vips_target_write_unbuffered(VipsTarget *target, const void *data, size_t length) { VipsTargetClass *class = VIPS_TARGET_GET_CLASS(target); VIPS_DEBUG_MSG("vips_target_write_unbuffered:\n"); if (target->ended) return 0; while (length > 0) { // write() uses int not size_t on windows, so we need to chunk // ... max 1gb, why not int chunk_size = VIPS_MIN(1024 * 1024 * 1024, length); gint64 bytes_written = class->write(target, data, chunk_size); /* n == 0 isn't strictly an error, but we treat it as * one to make sure we don't get stuck in this loop. */ if (bytes_written <= 0) { vips_error_system(errno, vips_connection_nick( VIPS_CONNECTION(target)), "%s", _("write error")); return -1; } length -= bytes_written; data = (char *) data + bytes_written; } return 0; } static int vips_target_flush(VipsTarget *target) { g_assert(target->write_point >= 0); g_assert(target->write_point <= VIPS_TARGET_BUFFER_SIZE); VIPS_DEBUG_MSG("vips_target_flush:\n"); if (target->write_point > 0) { if (vips_target_write_unbuffered(target, target->output_buffer, target->write_point)) return -1; target->write_point = 0; } return 0; } /** * vips_target_write: * @target: target to operate on * @data: data to write * @length: length of @data in bytes * * Write @length bytes from @data to the output. * * Returns: 0 on success, -1 on error. */ int vips_target_write(VipsTarget *target, const void *data, size_t length) { VIPS_DEBUG_MSG("vips_target_write: %zd bytes\n", length); if (length > VIPS_TARGET_BUFFER_SIZE - target->write_point && vips_target_flush(target)) return -1; if (length > VIPS_TARGET_BUFFER_SIZE - target->write_point) { /* Still too large? Do an unbuffered write. */ if (vips_target_write_unbuffered(target, data, length)) return -1; } else { memcpy(target->output_buffer + target->write_point, data, length); target->write_point += length; } return 0; } /** * vips_target_read: * @target: target to operate on * @buffer: store bytes here * @length: length of @buffer in bytes * * Read up to @length bytes from @target and store the bytes in @buffer. * Return the number of bytes actually read. If all bytes have been read from * the file, return 0. * * Arguments exactly as [`read()`](man:read(2)). * * Reading from a target sounds weird, but libtiff needs this for * multi-page writes. This method will fail for targets like pipes. * * Returns: the number of bytes read, 0 on end of file, -1 on error. */ gint64 vips_target_read(VipsTarget *target, void *buffer, size_t length) { VipsTargetClass *class = VIPS_TARGET_GET_CLASS(target); VIPS_DEBUG_MSG("vips_target_read: %zd bytes\n", length); if (vips_target_flush(target)) return -1; return class->read(target, buffer, length); } /** * vips_target_seek: * @target: target to operate on * @offset: offset to seek to * @whence: seek relative to beginning, offset, or end * * Seek the target. This behaves exactly as [`lseek()`](man:lseek(2)). * * Seeking a target sounds weird, but libtiff needs this. This method will * fail for targets like pipes. * * Returns: the new offset, -1 on error. */ gint64 vips_target_seek(VipsTarget *target, gint64 offset, int whence) { VipsTargetClass *class = VIPS_TARGET_GET_CLASS(target); gint64 new_offset; VIPS_DEBUG_MSG( "vips_target_seek: offset = %" G_GINT64_FORMAT ", whence = %d\n", offset, whence); if (vips_target_flush(target)) return -1; new_offset = class->seek(target, offset, whence); VIPS_DEBUG_MSG("vips_target_seek: new_offset = %" G_GINT64_FORMAT "\n", new_offset); return new_offset; } /** * vips_target_end: * @target: target to operate on * * Call this at the end of write to make the target do any cleaning up. You * can call it many times. * * After a target has been ended, further writes will do nothing. * * Returns: 0 on success, -1 on error. */ int vips_target_end(VipsTarget *target) { VipsTargetClass *class = VIPS_TARGET_GET_CLASS(target); VIPS_DEBUG_MSG("vips_target_end:\n"); if (target->ended) return 0; if (vips_target_flush(target)) return -1; /* Move the target buffer into the blob so it can be read out. */ if (target->memory_buffer) { const char *data; size_t length; length = target->memory_buffer->len; data = g_string_free(target->memory_buffer, FALSE); target->memory_buffer = NULL; vips_blob_set(target->blob, (VipsCallbackFn) vips_area_free_cb, data, length); } else { if (class->end(target)) return -1; } target->ended = TRUE; return 0; } /** * vips_target_steal: * @target: target to operate on * @length: return number of bytes of data * * Memory targets only (see [ctor@Target.new_to_memory]). Steal all data * written to the target so far, and call [method@Target.end]. * * You must free the returned pointer with [func@GLib.free]. * * The data is NOT automatically null-terminated. Use [method@Target.putc] with * a '\0' before calling this to get a null-terminated string. * * You can't call this after [method@Target.end], since that moves the data to a * blob, and we can't steal from that in case the pointer has been shared. * * You can't call this function more than once. * * Returns: (array length=length) (element-type guint8) (transfer full): the * data */ unsigned char * vips_target_steal(VipsTarget *target, size_t *length) { const char *data; (void) vips_target_flush(target); data = NULL; if (target->memory_buffer) { if (length) *length = target->memory_buffer->len; data = g_string_free(target->memory_buffer, FALSE); target->memory_buffer = NULL; /* We must have a valid byte array, or end will fail. */ target->memory_buffer = g_string_sized_new(0); } if (vips_target_end(target)) return NULL; return (unsigned char *) data; } /** * vips_target_steal_text: * @target: target to operate on * * As [method@Target.steal], but return a null-terminated string. * * Returns: (transfer full): target contents as a null-terminated string. */ char * vips_target_steal_text(VipsTarget *target) { vips_target_putc(target, '\0'); return (char *) vips_target_steal(target, NULL); } /** * vips_target_putc: * @target: target to operate on * @ch: character to write * * Write a single character @ch to @target. See the macro [func@TARGET_PUTC] * for a faster way to do this. * * Returns: 0 on success, -1 on error. */ int vips_target_putc(VipsTarget *target, int ch) { VIPS_DEBUG_MSG("vips_target_putc: %d\n", ch); if (target->write_point >= VIPS_TARGET_BUFFER_SIZE && vips_target_flush(target)) return -1; target->output_buffer[target->write_point++] = ch; return 0; } /** * vips_target_writes: * @target: target to operate on * @str: string to write * * Write a null-terminated string to @target. * * Returns: 0 on success, and -1 on error. */ int vips_target_writes(VipsTarget *target, const char *str) { return vips_target_write(target, (unsigned char *) str, strlen(str)); } /** * vips_target_writef: * @target: target to operate on * @fmt: `printf()`-style format string * @...: arguments to format string * * Format the string and write to @target. * * Returns: 0 on success, and -1 on error. */ int vips_target_writef(VipsTarget *target, const char *fmt, ...) { va_list ap; char *line; int result; va_start(ap, fmt); line = g_strdup_vprintf(fmt, ap); va_end(ap); result = vips_target_writes(target, line); g_free(line); return result; } /** * vips_target_write_amp: * @target: target to operate on * @str: string to write * * Write @str to @target, but escape stuff that xml hates in text. Our * argument string is utf-8. * * XML rules: * * - We must escape &<> * - Don't escape \n, \t, \r * - Do escape the other ASCII codes. * * Returns: 0 on success, -1 on error. */ int vips_target_write_amp(VipsTarget *target, const char *str) { const char *p; for (p = str; *p; p++) if (*p < 32 && *p != '\n' && *p != '\t' && *p != '\r') { /* You'd think we could output "%x;", but xml * 1.0 parsers barf on that. xml 1.1 allows this, but * there are almost no parsers. * * U+2400 onwards are unicode glyphs for the ASCII * control characters, so we can use them -- thanks * electroly. */ if (vips_target_writef(target, "&#x%04x;", 0x2400 + *p)) return -1; } else if (*p == '<') { if (vips_target_writes(target, "<")) return -1; } else if (*p == '>') { if (vips_target_writes(target, ">")) return -1; } else if (*p == '&') { if (vips_target_writes(target, "&")) return -1; } else { if (VIPS_TARGET_PUTC(target, *p)) return -1; } return 0; } libvips-8.18.2/libvips/iofuncs/targetcustom.c000066400000000000000000000216361516303661500213030ustar00rootroot00000000000000/* A Target subclass with signals you can easily hook up to other output * sources. * * J.Cupitt, 21/11/19 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #include #include #include "vipsmarshal.h" G_DEFINE_TYPE(VipsTargetCustom, vips_target_custom, VIPS_TYPE_TARGET); /* Our signals. */ enum { SIG_WRITE, SIG_READ, SIG_SEEK, SIG_END, SIG_FINISH, SIG_LAST }; static guint vips_target_custom_signals[SIG_LAST] = { 0 }; static gint64 vips_target_custom_write_real(VipsTarget *target, const void *data, size_t length) { gint64 bytes_written; VIPS_DEBUG_MSG("vips_target_custom_write_real:\n"); /* Return value if no attached handler. */ bytes_written = 0; g_signal_emit(target, vips_target_custom_signals[SIG_WRITE], 0, data, (gint64) length, &bytes_written); VIPS_DEBUG_MSG(" %zd\n", bytes_written); return bytes_written; } static gint64 vips_target_custom_read_real(VipsTarget *target, void *buffer, size_t length) { gint64 bytes_read; VIPS_DEBUG_MSG("vips_target_custom_read_real:\n"); /* Return this value (error) if there's no attached handler. */ bytes_read = 0; g_signal_emit(target, vips_target_custom_signals[SIG_READ], 0, buffer, (gint64) length, &bytes_read); VIPS_DEBUG_MSG(" vips_target_custom_read_real, seen %zd bytes\n", bytes_read); return bytes_read; } static gint64 vips_target_custom_seek_real(VipsTarget *target, gint64 offset, int whence) { GValue args[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; GValue result = G_VALUE_INIT; gint64 new_position; VIPS_DEBUG_MSG("vips_target_custom_seek_real:\n"); /* Set the signal args. */ g_value_init(&args[0], G_TYPE_OBJECT); g_value_set_object(&args[0], target); g_value_init(&args[1], G_TYPE_INT64); g_value_set_int64(&args[1], offset); g_value_init(&args[2], G_TYPE_INT); g_value_set_int(&args[2], whence); /* Set the default value if no handlers are attached. */ g_value_init(&result, G_TYPE_INT64); g_value_set_int64(&result, -1); /* We need to use this signal interface since we want a default value * if no handlers are attached. */ g_signal_emitv((const GValue *) &args, vips_target_custom_signals[SIG_SEEK], 0, &result); new_position = g_value_get_int64(&result); g_value_unset(&args[0]); g_value_unset(&args[1]); g_value_unset(&args[2]); g_value_unset(&result); VIPS_DEBUG_MSG(" vips_target_custom_seek_real, seen new pos %zd\n", new_position); return new_position; } static int vips_target_custom_end_real(VipsTarget *target) { int result; VIPS_DEBUG_MSG("vips_target_custom_end_real:\n"); /* For compatibility with older libvipses, we have to emit "finish" * as well, eg. ruby-vips relies on this. */ g_signal_emit(target, vips_target_custom_signals[SIG_FINISH], 0); /* Return value if no attached handler. */ result = 0; g_signal_emit(target, vips_target_custom_signals[SIG_END], 0, &result); return result; } static void vips_target_custom_finish_real(VipsTarget *target) { VIPS_DEBUG_MSG("vips_target_custom_finish_real:\n"); g_signal_emit(target, vips_target_custom_signals[SIG_FINISH], 0); } static gint64 vips_target_custom_write_signal_real(VipsTargetCustom *target_custom, const void *data, gint64 length) { VIPS_DEBUG_MSG("vips_target_custom_write_signal_real:\n"); return 0; } static gint64 vips_target_custom_read_signal_real(VipsTargetCustom *target_custom, void *data, gint64 length) { VIPS_DEBUG_MSG("vips_target_custom_read_signal_real:\n"); return 0; } static gint64 vips_target_custom_seek_signal_real(VipsTargetCustom *target_custom, gint64 offset, int whence) { VIPS_DEBUG_MSG("vips_target_custom_seek_signal_real:\n"); return -1; } static int vips_target_custom_end_signal_real(VipsTargetCustom *target_custom) { VIPS_DEBUG_MSG("vips_target_custom_end_signal_real:\n"); return 0; } static void vips_target_custom_finish_signal_real(VipsTargetCustom *target_custom) { VIPS_DEBUG_MSG("vips_target_custom_finish_signal_real:\n"); } static void vips_target_custom_class_init(VipsTargetCustomClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsTargetClass *target_class = VIPS_TARGET_CLASS(class); object_class->nickname = "target_custom"; object_class->description = _("Custom target"); target_class->write = vips_target_custom_write_real; target_class->read = vips_target_custom_read_real; target_class->seek = vips_target_custom_seek_real; target_class->end = vips_target_custom_end_real; target_class->finish = vips_target_custom_finish_real; class->write = vips_target_custom_write_signal_real; class->read = vips_target_custom_read_signal_real; class->seek = vips_target_custom_seek_signal_real; class->end = vips_target_custom_end_signal_real; class->finish = vips_target_custom_finish_signal_real; /** * VipsTargetCustom::write: * @target_custom: the target being operated on * @data: `gpointer`, bytes to write * @length: `gint64`, number of bytes * * This signal is emitted to write bytes to the target. * * Returns: the number of bytes written. */ vips_target_custom_signals[SIG_WRITE] = g_signal_new("write", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsTargetCustomClass, write), NULL, NULL, vips_INT64__POINTER_INT64, G_TYPE_INT64, 2, G_TYPE_POINTER, G_TYPE_INT64); /** * VipsTargetCustom::read: * @target_custom: the target being operated on * @buffer: `gpointer`, buffer to fill * @size: `gint64`, size of buffer * * This signal is emitted to read bytes from the target into @buffer. * * The handler for an unreadable target should always return -1. * * Returns: the number of bytes read. Return 0 for EOF. */ vips_target_custom_signals[SIG_READ] = g_signal_new("read", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsTargetCustomClass, read), NULL, NULL, vips_INT64__POINTER_INT64, G_TYPE_INT64, 2, G_TYPE_POINTER, G_TYPE_INT64); /** * VipsTargetCustom::seek: * @target_custom: the target being operated on * @offset: `gint64`, seek offset * @whence: `gint`, seek origin * * This signal is emitted to seek the target. The handler should * change the target position appropriately. * * The handler for an unseekable target should always return -1. * * Returns: the new seek position. */ vips_target_custom_signals[SIG_SEEK] = g_signal_new("seek", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsTargetCustomClass, seek), NULL, NULL, vips_INT64__INT64_INT, G_TYPE_INT64, 2, G_TYPE_INT64, G_TYPE_INT); /** * VipsTargetCustom::end: * @target_custom: the target being operated on * * This signal is emitted at the end of write. The target should do * any finishing necessary. * * Returns: 0 on success, -1 on error. */ vips_target_custom_signals[SIG_END] = g_signal_new("end", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsTargetCustomClass, end), NULL, NULL, vips_INT__VOID, G_TYPE_INT, 0); /** * VipsTargetCustom::finish: * @target_custom: the target being operated on * * Deprecated for [signal@TargetCustom::end]. */ vips_target_custom_signals[SIG_FINISH] = g_signal_new("finish", G_TYPE_FROM_CLASS(class), G_SIGNAL_ACTION, G_STRUCT_OFFSET(VipsTargetCustomClass, finish), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void vips_target_custom_init(VipsTargetCustom *target_custom) { } /** * vips_target_custom_new: * * Create a [class@TargetCustom]. Attach signals to implement write and finish. * * Returns: a new [class@TargetCustom] */ VipsTargetCustom * vips_target_custom_new(void) { VipsTargetCustom *target_custom; VIPS_DEBUG_MSG("vips_target_custom_new:\n"); target_custom = VIPS_TARGET_CUSTOM( g_object_new(VIPS_TYPE_TARGET_CUSTOM, NULL)); if (vips_object_build(VIPS_OBJECT(target_custom))) { VIPS_UNREF(target_custom); return NULL; } return target_custom; } libvips-8.18.2/libvips/iofuncs/thread.c000066400000000000000000000206241516303661500200250ustar00rootroot00000000000000/* Basic functions to support threading. * * 29/9/22 * - from threadpool.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG #define VIPS_DEBUG_RED */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ /* Maximum value we allow for VIPS_CONCURRENCY. We need to stop huge values * killing the system. */ #define MAX_THREADS (1024) /* Default n threads ... 0 means get from environment. */ int vips__concurrency = 0; /* Default tile geometry ... can be set by vips_init(). */ int vips__tile_width = VIPS__TILE_WIDTH; int vips__tile_height = VIPS__TILE_HEIGHT; int vips__fatstrip_height = VIPS__FATSTRIP_HEIGHT; int vips__thinstrip_height = VIPS__THINSTRIP_HEIGHT; /* Set this GPrivate to indicate that is a libvips thread. */ static GPrivate is_vips_thread_key; /* TRUE if we are a vips thread. We sometimes manage resource allocation * differently for vips threads since we can cheaply free stuff on thread * termination. */ gboolean vips_thread_isvips(void) { return g_private_get(&is_vips_thread_key) != NULL; } typedef struct { const char *domain; GThreadFunc func; gpointer data; } VipsThreadInfo; static void * vips_thread_run(gpointer data) { VipsThreadInfo *info = (VipsThreadInfo *) data; void *result; /* Set this to something (anything) to tag this thread as a vips * worker. No need to call g_private_replace as there is no * GDestroyNotify handler associated with a worker. */ g_private_set(&is_vips_thread_key, info); result = info->func(info->data); g_free(info); vips_thread_shutdown(); return result; } /** * vips_g_thread_new: * @domain: (nullable): an (optional) name for the new thread * @func: (scope async) (closure data): a function to execute in the new thread * @data: (nullable): an argument to supply to the new thread * * Wrapper for [ctor@GLib.Thread.try_new]. * * Returns: (transfer full): the new [struct@GLib.Thread], or `NULL` if an * error occurred */ GThread * vips_g_thread_new(const char *domain, GThreadFunc func, gpointer data) { GThread *thread; VipsThreadInfo *info; GError *error = NULL; info = g_new(VipsThreadInfo, 1); info->domain = domain; info->func = func; info->data = data; thread = g_thread_try_new(domain, vips_thread_run, info, &error); VIPS_DEBUG_MSG_RED("vips_g_thread_new: g_thread_create(%s) = %p\n", domain, thread); if (!thread) { if (error) vips_g_error(&error); else vips_error(domain, "%s", _("unable to create thread")); } return thread; } /* The default concurrency, set by the environment variable VIPS_CONCURRENCY, * or if that is not set, the number of threads available on the host machine. */ static int vips__concurrency_get_default(void) { const char *str; int nthr; int x; /* Tell the threads system how much concurrency we expect. */ if (vips__concurrency > 0) nthr = vips__concurrency; else if ( ((str = g_getenv("VIPS_CONCURRENCY")) #ifdef ENABLE_DEPRECATED || (str = g_getenv("IM_CONCURRENCY")) #endif ) && (x = atoi(str)) > 0) nthr = x; else nthr = g_get_num_processors(); if (nthr < 1 || nthr > MAX_THREADS) { nthr = VIPS_CLIP(1, nthr, MAX_THREADS); g_warning("threads clipped to %d", nthr); } return nthr; } /** * vips_concurrency_set: * @concurrency: number of threads to run * * Sets the number of worker threads that vips should use when running * [func@threadpool_run]. * * The special value 0 means "default". In this case, the number of threads * is set by the environment variable `VIPS_CONCURRENCY`, or if that is not * set, the number of threads available on the host machine. * * ::: seealso * [func@concurrency_get]. */ void vips_concurrency_set(int concurrency) { /* Tell the threads system how much concurrency we expect. */ if (concurrency < 1) concurrency = vips__concurrency_get_default(); else if (concurrency > MAX_THREADS) { concurrency = MAX_THREADS; g_warning("threads clipped to %d", MAX_THREADS); } vips__concurrency = concurrency; } /** * vips_concurrency_get: * * Returns the number of worker threads that vips should use when running * [func@threadpool_run]. * * vips gets this values from these sources in turn: * * If [func@concurrency_set] has been called, this value is used. The special * value 0 means "default". You can also use the command-line argument * `--vips-concurrency` to set this value. * * If [func@concurrency_set] has not been called and no command-line argument * was used, vips uses the value of the environment variable `VIPS_CONCURRENCY`. * * If `VIPS_CONCURRENCY` has not been set, vips finds the number of hardware * threads that the host machine can run in parallel and uses that value. * * The final value is clipped to the range 1 - 1024. * * ::: seealso * [func@concurrency_get]. * * Returns: number of worker threads to use. */ int vips_concurrency_get(void) { return vips__concurrency; } /** * vips_get_tile_size: (method) * @im: image to guess for * @tile_width: (out): return selected tile width * @tile_height: (out): return selected tile height * @n_lines: (out): return buffer height in scanlines * * Pick a tile size and a buffer height for this image and the current * value of [func@concurrency_get]. The buffer height * will always be a multiple of tile_height. * * The buffer height is the height of each buffer we fill in sink disc. Since * we have two buffers, the largest range of input locality is twice the output * buffer size, plus whatever margin we add for things like convolution. */ void vips_get_tile_size(VipsImage *im, int *tile_width, int *tile_height, int *n_lines) { const int nthr = vips_concurrency_get(); const int typical_image_width = 1000; /* Compiler warnings. */ *tile_width = 1; *tile_height = 1; /* Pick a render geometry. */ switch (im->dhint) { case VIPS_DEMAND_STYLE_SMALLTILE: *tile_width = vips__tile_width; *tile_height = vips__tile_height; break; case VIPS_DEMAND_STYLE_ANY: case VIPS_DEMAND_STYLE_FATSTRIP: *tile_width = im->Xsize; *tile_height = vips__fatstrip_height; break; case VIPS_DEMAND_STYLE_THINSTRIP: *tile_width = im->Xsize; /* Only enable thinstrip height for very wide images -- the * overheads are too high to be worthwhile otherwise. */ *tile_height = im->Xsize > 10000 ? vips__thinstrip_height : vips__fatstrip_height; break; default: g_assert_not_reached(); } /* We can't set n_lines for the current demand style: a later bit of * the pipeline might see a different hint and we need to synchronise * buffer sizes everywhere. * * We also can't depend on the current image size, since that might * change down the pipeline too. Pick a typical image width. * * Pick the maximum buffer size we might possibly need, then round up * to a multiple of tileheight. */ *n_lines = vips__tile_height * VIPS_ROUND_UP(vips__tile_width * nthr, typical_image_width) / typical_image_width; *n_lines = VIPS_MAX(*n_lines, vips__fatstrip_height * nthr); *n_lines = VIPS_MAX(*n_lines, vips__thinstrip_height * nthr); *n_lines = VIPS_ROUND_UP(*n_lines, *tile_height); /* We make this assumption in several places. */ g_assert(*n_lines % *tile_height == 0); VIPS_DEBUG_MSG("vips_get_tile_size: %d by %d patches, " "groups of %d scanlines\n", *tile_width, *tile_height, *n_lines); } void vips__thread_init(void) { if (vips__concurrency == 0) vips__concurrency = vips__concurrency_get_default(); } libvips-8.18.2/libvips/iofuncs/threadpool.c000066400000000000000000000421571516303661500207240ustar00rootroot00000000000000/* Support for thread pools ... like threadgroups, but lighter. * * 18/3/10 * - from threadgroup.c * - distributed work allocation idea from Christian Blenia, thank you * very much * 21/3/10 * - progress feedback * - only expose VipsThreadState * 11/5/10 * - argh, stopping many threads could sometimes leave allocated work * undone * 17/7/10 * - set pool->error whenever we set thr->error, lets us catch allocate * errors (thanks Tim) * 25/7/14 * - limit nthr on tiny images * 6/3/17 * - remove single-thread-first-request thing, new seq system makes it * unnecessary * 23/4/17 * - add ->stall * - don't depend on image width when setting n_lines * 27/2/19 jtorresfabra * - free threadpool earlier */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG #define VIPS_DEBUG_RED */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ /** * VipsThreadState: * * A [class@ThreadState] represents a per-thread state. * * [callback@ThreadpoolAllocateFn] functions can use these members to * communicate with [callback@ThreadpoolWorkFn] functions. * * ::: seealso * [func@threadpool_run]. */ /* Set to stall threads for debugging. */ static gboolean vips__stall = FALSE; /* The global threadset we run workers in. */ static VipsThreadset *vips__threadset = NULL; /* Set this GPrivate to link a thread back to its VipsWorker struct. */ static GPrivate worker_key; /* Maximum value we allow for VIPS_CONCURRENCY. We need to stop huge values * killing the system. */ #define MAX_THREADS (1024) /* Start up threadpools. This is called during vips_init. */ void vips__threadpool_init(void) { /* 3 is the useful minimum, and huge values can crash the machine. */ const char *max_threads_env = g_getenv("VIPS_MAX_THREADS"); int max_threads = max_threads_env ? VIPS_CLIP(3, atoi(max_threads_env), MAX_THREADS) : 0; if (g_getenv("VIPS_STALL")) vips__stall = TRUE; /* max_threads > 0 will create a set of threads on startup. This is * necessary for wasm, but may break on systems that try to fork() * after init. */ vips__threadset = vips_threadset_new(max_threads); } void vips__threadpool_shutdown(void) { VIPS_FREEF(vips_threadset_free, vips__threadset); } /** * vips_thread_execute: * @domain: a name for the thread (useful for debugging) * @func: (scope async) (closure data): a function to execute in the libvips threadset * @data: (nullable): an argument to supply to @func * * A newly created or reused thread will execute @func with the * argument @data. * * Returns: 0 on success, -1 on error. */ int vips_thread_execute(const char *domain, GFunc func, gpointer data) { return vips_threadset_run(vips__threadset, domain, func, data); } G_DEFINE_TYPE(VipsThreadState, vips_thread_state, VIPS_TYPE_OBJECT); static void vips_thread_state_dispose(GObject *gobject) { VipsThreadState *state = (VipsThreadState *) gobject; VIPS_DEBUG_MSG("vips_thread_state_dispose:\n"); VIPS_UNREF(state->reg); G_OBJECT_CLASS(vips_thread_state_parent_class)->dispose(gobject); } static int vips_thread_state_build(VipsObject *object) { VipsThreadState *state = (VipsThreadState *) object; if (!(state->reg = vips_region_new(state->im))) return -1; return VIPS_OBJECT_CLASS(vips_thread_state_parent_class) ->build(object); } static void vips_thread_state_class_init(VipsThreadStateClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = vips_thread_state_dispose; object_class->build = vips_thread_state_build; object_class->nickname = "threadstate"; object_class->description = _("per-thread state for vipsthreadpool"); } static void vips_thread_state_init(VipsThreadState *state) { VIPS_DEBUG_MSG("vips_thread_state_init:\n"); state->reg = NULL; state->stop = FALSE; state->stall = FALSE; } void * vips_thread_state_set(VipsObject *object, void *a, void *b) { VipsThreadState *state = (VipsThreadState *) object; VipsImage *im = (VipsImage *) a; VIPS_DEBUG_MSG("vips_thread_state_set: image %p\n", im); state->im = im; state->a = b; return NULL; } VipsThreadState * vips_thread_state_new(VipsImage *im, void *a) { VIPS_DEBUG_MSG("vips_thread_state_new: image %p\n", im); return VIPS_THREAD_STATE(vips_object_new( VIPS_TYPE_THREAD_STATE, vips_thread_state_set, im, a)); } /* What we track for each thread in the pool. */ typedef struct _VipsWorker { struct _VipsThreadpool *pool; /* Pool we are part of */ VipsThreadState *state; gboolean stop; } VipsWorker; /* What we track for a group of threads working together. */ typedef struct _VipsThreadpool { VipsImage *im; /* Image we are calculating */ /* Start a thread, do a unit of work (runs in parallel) and allocate * a unit of work (serial). Plus the mutex we use to serialize work * allocation. */ VipsThreadStartFn start; VipsThreadpoolAllocateFn allocate; VipsThreadpoolWorkFn work; GMutex allocate_lock; void *a; /* User argument to start / allocate / etc. */ int max_workers; /* Max number of workers in pool */ /* The number of workers in the pool (as a negative number, so * -4 means 4 workers are running). */ VipsSemaphore n_workers; /* Workers up this for every loop to make the main thread tick. */ VipsSemaphore tick; /* The number of workers queueing up on allocate_lock. Use this to * grow and shrink the threadpool. */ int n_waiting; // (atomic) /* Increment this and the next worker will decrement and exit if needed * (used to downsize the threadpool). */ int exit; // (atomic) /* Set this to abort evaluation early with an error. */ gboolean error; /* Ask threads to exit, either set by allocate, or on free. */ gboolean stop; } VipsThreadpool; static int vips_worker_allocate(VipsWorker *worker) { VipsThreadpool *pool = worker->pool; g_assert(!pool->stop); if (!worker->state && !(worker->state = pool->start(pool->im, pool->a))) return -1; if (pool->allocate(worker->state, pool->a, &pool->stop)) return -1; return 0; } /* Run this once per main loop. Get some work (single-threaded), then do it * (many-threaded). */ static void vips_worker_work_unit(VipsWorker *worker) { VipsThreadpool *pool = worker->pool; VIPS_GATE_START("vips_worker_work_unit: wait"); vips__worker_lock(&pool->allocate_lock); VIPS_GATE_STOP("vips_worker_work_unit: wait"); /* Has another worker signaled stop while we've been waiting? */ if (pool->stop) { worker->stop = TRUE; g_mutex_unlock(&pool->allocate_lock); return; } /* Has a thread been asked to exit? Volunteer if yes. */ if (g_atomic_int_add(&pool->exit, -1) > 0) { /* A thread had been asked to exit, and we've grabbed the * flag. */ worker->stop = TRUE; g_mutex_unlock(&pool->allocate_lock); return; } else { /* No one had been asked to exit and we've mistakenly taken * the exit count below zero. Put it back up again. */ g_atomic_int_inc(&pool->exit); } if (vips_worker_allocate(worker)) { pool->error = TRUE; worker->stop = TRUE; g_mutex_unlock(&pool->allocate_lock); return; } /* Have we just signalled stop? */ if (pool->stop) { worker->stop = TRUE; g_mutex_unlock(&pool->allocate_lock); return; } g_mutex_unlock(&pool->allocate_lock); if (worker->state->stall && vips__stall) { /* Sleep for 0.5s. Handy for stressing the seq system. Stall * is set by allocate funcs in various places. */ g_usleep(500000); worker->state->stall = FALSE; printf("vips_worker_work_unit: stall done, releasing y = %d ...\n", worker->state->y); } /* Process a work unit. */ if (pool->work(worker->state, pool->a)) { worker->stop = TRUE; pool->error = TRUE; } } /* What runs as a thread ... loop, waiting to be told to do stuff. */ static void vips_thread_main_loop(void *a, void *b) { VipsWorker *worker = (VipsWorker *) a; VipsThreadpool *pool = worker->pool; VIPS_GATE_START("vips_thread_main_loop: thread"); g_private_set(&worker_key, worker); /* Process work units! Always tick, even if we are stopping, so the * main thread will wake up for exit. */ while (!pool->stop && !worker->stop && !pool->error) { VIPS_GATE_START("vips_worker_work_unit: u"); vips_worker_work_unit(worker); VIPS_GATE_STOP("vips_worker_work_unit: u"); vips_semaphore_up(&pool->tick); } VIPS_GATE_STOP("vips_thread_main_loop: thread"); /* unreffing the worker state will trigger stop in the threadstate, so * we need to single-thread. */ g_mutex_lock(&pool->allocate_lock); VIPS_FREEF(g_object_unref, worker->state); g_mutex_unlock(&pool->allocate_lock); VIPS_FREE(worker); g_private_set(&worker_key, NULL); /* We are done: tell the main thread. */ vips_semaphore_upn(&pool->n_workers, 1); } /* Attach another thread to a threadpool. */ static int vips_worker_new(VipsThreadpool *pool) { VipsWorker *worker; if (!(worker = VIPS_NEW(NULL, VipsWorker))) return -1; worker->pool = pool; worker->state = NULL; /* We can't build the state here, it has to be done by the worker * itself the first time that allocate runs so that any regions are * owned by the correct thread. */ if (vips_thread_execute("worker", vips_thread_main_loop, worker)) { g_free(worker); return -1; } /* One more worker in the pool. */ vips_semaphore_upn(&pool->n_workers, -1); return 0; } void vips__worker_lock(GMutex *mutex) { VipsWorker *worker = (VipsWorker *) g_private_get(&worker_key); if (worker) g_atomic_int_inc(&worker->pool->n_waiting); g_mutex_lock(mutex); if (worker) g_atomic_int_dec_and_test(&worker->pool->n_waiting); } void vips__worker_cond_wait(GCond *cond, GMutex *mutex) { VipsWorker *worker = (VipsWorker *) g_private_get(&worker_key); if (worker) g_atomic_int_inc(&worker->pool->n_waiting); g_cond_wait(cond, mutex); if (worker) g_atomic_int_dec_and_test(&worker->pool->n_waiting); } static void vips_threadpool_wait(VipsThreadpool *pool) { /* Wait for them all to exit. */ pool->stop = TRUE; vips_semaphore_downn(&pool->n_workers, 0); } static void vips_threadpool_free(VipsThreadpool *pool) { vips_threadpool_wait(pool); g_mutex_clear(&pool->allocate_lock); vips_semaphore_destroy(&pool->n_workers); vips_semaphore_destroy(&pool->tick); VIPS_FREE(pool); } static VipsThreadpool * vips_threadpool_new(VipsImage *im) { VipsThreadpool *pool; int tile_width; int tile_height; gint64 n_tiles; int n_lines; /* Allocate and init new thread block. */ if (!(pool = VIPS_NEW(NULL, VipsThreadpool))) return NULL; pool->im = im; pool->allocate = NULL; pool->work = NULL; g_mutex_init(&pool->allocate_lock); pool->max_workers = vips_concurrency_get(); vips_semaphore_init(&pool->n_workers, 0, "n_workers"); vips_semaphore_init(&pool->tick, 0, "tick"); pool->error = FALSE; pool->stop = FALSE; pool->exit = 0; /* If this is a tiny image, we won't need all max_workers threads. * Guess how * many tiles we might need to cover the image and use that to limit * the number of threads we create. */ vips_get_tile_size(im, &tile_width, &tile_height, &n_lines); n_tiles = (1 + (gint64) im->Xsize / tile_width) * (1 + (gint64) im->Ysize / tile_height); n_tiles = VIPS_CLIP(1, n_tiles, 1024); pool->max_workers = VIPS_MIN(pool->max_workers, n_tiles); /* VIPS_META_CONCURRENCY on the image can optionally override * concurrency. */ pool->max_workers = vips_image_get_concurrency(im, pool->max_workers); return pool; } /** * VipsThreadpoolStartFn: * @a: client data * @b: client data * @c: client data * * This function is called once by each worker just before the first time work * is allocated to it to build the per-thread state. Per-thread state is used * by [callback@ThreadpoolAllocateFn] and [callback@ThreadpoolWorkFn] to * communicate. * * [class@ThreadState] is a subclass of [class@Object]. Start functions are * called from allocate, that is, they are single-threaded. * * ::: seealso * [func@threadpool_run]. * * Returns: a new [class@ThreadState] object, or `NULL` on error */ /** * VipsThreadpoolAllocateFn: * @state: per-thread state * @a: client data * @stop: set this to signal end of computation * * This function is called to allocate a new work unit for the thread. It is * always single-threaded, so it can modify per-pool state (such as a * counter). * * It should set @stop to `TRUE` to indicate that no work could be allocated * because the job is done. * * ::: seealso * [func@threadpool_run]. * * Returns: 0 on success, or -1 on error */ /** * VipsThreadpoolWorkFn: * @state: per-thread state * @a: client data * * This function is called to process a work unit. Many copies of this can run * at once, so it should not write to the per-pool state. It can write to * per-thread state. * * ::: seealso * [func@threadpool_run]. * * Returns: 0 on success, or -1 on error */ /** * VipsThreadpoolProgressFn: * @a: client data * * This function is called by the main thread once for every work unit * processed. It can be used to give the user progress feedback. * * ::: seealso * [func@threadpool_run]. * * Returns: 0 on success, or -1 on error */ /** * vips_threadpool_run: * @im: image to loop over * @start: (scope async): allocate per-thread state * @allocate: (scope async): allocate a work unit * @work: (scope async): process a work unit * @progress: (scope async): give progress feedback about a work unit, or `NULL` * @a: client data * * This function runs a set of threads over an image. Each thread first calls * @start to create new per-thread state, then runs * @allocate to set up a new work unit (perhaps the next tile in an image, for * example), then @work to process that work unit. After each unit is * processed, @progress is called, so that the operation can give * progress feedback. @progress may be `NULL`. * * The object returned by @start must be an instance of a subclass of * [class@ThreadState]. Use this to communicate between @allocate and @work. * * @allocate and @start are always single-threaded (so they can write to the * per-pool state), whereas @work can be executed concurrently. @progress is * always called by * the main thread (ie. the thread which called [func@threadpool_run]). * * ::: seealso * [func@concurrency_set]. * * Returns: 0 on success, or -1 on error. */ int vips_threadpool_run(VipsImage *im, VipsThreadStartFn start, VipsThreadpoolAllocateFn allocate, VipsThreadpoolWorkFn work, VipsThreadpoolProgressFn progress, void *a) { VipsThreadpool *pool; int result; int n_waiting; int n_working; if (!(pool = vips_threadpool_new(im))) return -1; pool->start = start; pool->allocate = allocate; pool->work = work; pool->a = a; /* Start with half of the max number of threads, then let it drift up * and down with load. */ for (n_working = 0; n_working < 1 + pool->max_workers / 2; n_working++) if (vips_worker_new(pool)) { vips_threadpool_free(pool); return -1; } for (;;) { /* Wait for a tick from a worker. */ vips_semaphore_down(&pool->tick); VIPS_DEBUG_MSG("vips_threadpool_run: tick\n"); if (pool->stop || pool->error) break; if (progress && progress(pool->a)) pool->error = TRUE; if (pool->stop || pool->error) break; n_waiting = g_atomic_int_get(&pool->n_waiting); VIPS_DEBUG_MSG("n_waiting = %d\n", n_waiting); VIPS_DEBUG_MSG("n_working = %d\n", n_working); VIPS_DEBUG_MSG("exit = %d\n", pool->exit); if (n_waiting > 3 && n_working > 1) { VIPS_DEBUG_MSG("shrinking thread pool\n"); g_atomic_int_inc(&pool->exit); n_working -= 1; } else if (n_waiting < 2 && n_working < pool->max_workers) { VIPS_DEBUG_MSG("expanding thread pool\n"); if (vips_worker_new(pool)) { vips_threadpool_free(pool); return -1; } n_working += 1; } } /* This will block until the last worker completes. */ vips_threadpool_wait(pool); /* Return 0 for success. */ result = pool->error ? -1 : 0; vips_threadpool_free(pool); if (!vips_image_get_concurrency(im, 0)) g_info("threadpool completed with %d workers", n_working); /* "minimise" is only emitted for top-level threadpools. */ if (!vips_image_get_typeof(im, "vips-no-minimise")) vips_image_minimise_all(im); return result; } libvips-8.18.2/libvips/iofuncs/threadset.c000066400000000000000000000210031516303661500205310ustar00rootroot00000000000000/* A set of threads. * * Creating and destroying threads can be expensive on some platforms, so we * try to only create once, then reuse. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include /* #define VIPS_DEBUG */ #include #include #include typedef struct _VipsThreadExec { /* The source of this function. */ const char *domain; /* The function to execute within the thread. */ GFunc func; /* User data that is handed over to func when it is called. */ gpointer data; } VipsThreadExec; struct _VipsThreadset { /* An asynchronous queue of tasks. */ GAsyncQueue *queue; /* Idle threads wait on this semaphore. */ VipsSemaphore idle; /* The number of threads that haven't reached their entry point. */ int queue_guard; /* The current number of (idle-)threads, the highwater mark, * and the max we allow before blocking thread creation. */ int n_threads; int n_threads_highwater; int n_idle_threads; int max_threads; /* Set by our controller to request exit. */ gboolean exit; }; /* The maximum relative time (in microseconds) that a thread waits * for work before being stopped. */ static const gint64 max_idle_time = 15 * G_TIME_SPAN_SECOND; /* The maximum number of idle threads. */ static const int max_idle_threads = 8; static gboolean vips_threadset_reuse_wait(VipsThreadset *set) { int result; /* A superfluous thread? Leave this thread. */ if (++set->n_idle_threads > max_idle_threads) return FALSE; g_async_queue_unlock(set->queue); /* Wait for at least 15 seconds before leaving this thread. */ result = vips_semaphore_down_timeout(&set->idle, max_idle_time); g_async_queue_lock(set->queue); return result != -1; } static void vips_threadset_free_internal(VipsThreadset *set) { VIPS_FREEF(g_async_queue_unref, set->queue); vips_semaphore_destroy(&set->idle); VIPS_FREE(set); } /* The thread work function. */ static void * vips_threadset_work(void *pointer) { VipsThreadset *set = (VipsThreadset *) pointer; gboolean cleanup = FALSE; VIPS_DEBUG_MSG("vips_threadset_work: starting %p\n", g_thread_self()); g_async_queue_lock(set->queue); set->queue_guard--; for (;;) { /* Pop a task from the queue. If the number of threads is limited, * this will block until a task becomes available. Otherwise, it * waits for at least 1/2 second before being marked as idle. */ VipsThreadExec *task = set->max_threads > 0 ? g_async_queue_pop_unlocked(set->queue) : g_async_queue_timeout_pop_unlocked(set->queue, G_USEC_PER_SEC / 2); /* Request to exit? Leave this thread. */ if (set->exit) { /* The last thread should cleanup the set. */ cleanup = set->n_threads == 1; break; } /* No task available? Wait for being reused. */ if (task == NULL) { if (!vips_threadset_reuse_wait(set)) { set->n_idle_threads--; break; } continue; } /* A task was received and there was no request to exit. */ g_async_queue_unlock(set->queue); /* If we're profiling, attach a prof struct to this thread. */ if (vips__thread_profile) vips__thread_profile_attach(task->domain); /* Execute the task. */ task->func(task->data, NULL); /* Free any thread-private resources -- they will not be * useful for the next task to use this thread. */ vips_thread_shutdown(); VIPS_FREE(task); g_async_queue_lock(set->queue); } /* Timed-out or exit has been requested, decrement number of threads. */ set->n_threads--; VIPS_DEBUG_MSG( "vips_threadset_work: stopping %p (%d remaining, %d idle)\n", g_thread_self(), set->n_threads, set->n_idle_threads); g_async_queue_unlock(set->queue); if (cleanup) vips_threadset_free_internal(set); return NULL; } /* Add a new thread to the set. */ static gboolean vips_threadset_add_thread(VipsThreadset *set) { gboolean reused = FALSE; /* There are already sufficient threads running. */ if (set->max_threads > 0 && set->n_threads >= set->max_threads) return TRUE; if (set->n_idle_threads > 0) { vips_semaphore_up(&set->idle); set->n_idle_threads--; reused = TRUE; } if (!reused) { /* No idle thread was found, we have to start a new one. */ GThread *thread; if (!(thread = vips_g_thread_new("libvips worker", vips_threadset_work, set))) return FALSE; /* Ensure threads are freed on exit. */ g_thread_unref(thread); set->n_threads++; set->queue_guard++; set->n_threads_highwater = VIPS_MAX(set->n_threads_highwater, set->n_threads); } return TRUE; } /** * vips_threadset_new: (free-func vips_threadset_free) (skip) * @max_threads: maximum number of system threads * * Create a new threadset. * * If @max_threads is 0, new threads will be created when necessary by * [func@threadset_run], with no limit on the number of threads. * * If @max_threads is > 0, then that many threads will be created by * [ctor@Threadset.new] during startup and [func@threadset_run] will * not spawn any additional threads. * * Returns: the new threadset. */ VipsThreadset * vips_threadset_new(int max_threads) { VipsThreadset *set; set = g_new0(VipsThreadset, 1); set->queue = g_async_queue_new(); vips_semaphore_init(&set->idle, 0, "idle"); set->max_threads = max_threads; if (set->max_threads > 0) for (int i = 0; i < set->max_threads; i++) { if (!vips_threadset_add_thread(set)) { vips_threadset_free(set); return NULL; } } return set; } /** * vips_threadset_run: * @set: the threadset to run the task in * @domain: the name of the task (useful for debugging) * @func: (scope async) (closure data): the task to execute * @data: (nullable): the task's data * * Execute a task in a thread. If there are no idle threads and the maximum * thread limit specified by @max_threads has not been reached, a new thread * will be spawned. * * ::: seealso * [ctor@Threadset.new]. * * Returns: 0 on success, or -1 on error. */ int vips_threadset_run(VipsThreadset *set, const char *domain, GFunc func, gpointer data) { VipsThreadExec *task; g_async_queue_lock(set->queue); /* Create or reuse an idle thread if there are at least as many tasks * in the queue as waiting threads. The guard comparison prevents * oversubscription by threads that haven't started yet. */ if (g_async_queue_length_unlocked(set->queue) >= set->queue_guard) if (!vips_threadset_add_thread(set)) { g_async_queue_unlock(set->queue); /* Thread create has failed. */ return -1; } /* Allocate the task and push it into the queue. */ task = g_new0(VipsThreadExec, 1); task->domain = domain; task->func = func; task->data = data; g_async_queue_push_unlocked(set->queue, task); g_async_queue_unlock(set->queue); return 0; } /** * vips_threadset_free: * @set: the threadset to free * * Free a threadset. This call returns immediately. */ void vips_threadset_free(VipsThreadset *set) { VIPS_DEBUG_MSG("vips_threadset_free: %p\n", set); g_async_queue_lock(set->queue); if (vips__leak) printf("vips_threadset_free: peak of %d threads\n", set->n_threads_highwater); set->exit = TRUE; /* No threads left, we cleanup. */ if (set->n_threads == 0) { g_async_queue_unlock(set->queue); vips_threadset_free_internal(set); return; } /* Wake up idle threads, if any. */ if (set->n_idle_threads > 0) vips_semaphore_upn(&set->idle, set->n_idle_threads); /* Send dummy data to the queue, causing threads to wake up and check * the above set->exit condition. */ for (int i = 0; i < set->n_threads; i++) g_async_queue_push_unlocked(set->queue, GUINT_TO_POINTER(1)); g_async_queue_unlock(set->queue); } libvips-8.18.2/libvips/iofuncs/type.c000066400000000000000000001353551516303661500175470ustar00rootroot00000000000000/* array type * * Unlike GArray, this has fixed length, tracks a GType for elements, and has * a per-element free function. * * 27/10/11 * - from header.c * 16/7/13 * - leakcheck VipsArea * 16/8/17 * - validate strings as utf-8 on set */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include /* A very simple boxed type for testing. Just an int. * * You can manipulate this thing from Python (for example) with: * * from gi.repository import Vips * a = Vips.Thing.new(12) * print a.i * b = a * del a * print b.i * del b */ /** * vips_thing_new: * @i: * * Returns: (transfer full): a new [struct@Thing]. */ VipsThing * vips_thing_new(int i) { VipsThing *thing; thing = g_new(VipsThing, 1); thing->i = i; printf("vips_thing_new: %d %p\n", i, thing); return thing; } static VipsThing * vips_thing_copy(VipsThing *thing) { VipsThing *thing2; thing2 = vips_thing_new(thing->i); printf("vips_thing_copy: %d %p = %p\n", thing->i, thing2, thing); return thing2; } static void vips_thing_free(VipsThing *thing) { printf("vips_thing_free: %d %p\n", thing->i, thing); g_free(thing); } G_DEFINE_BOXED_TYPE(VipsThing, vips_thing, (GBoxedCopyFunc) vips_thing_copy, (GBoxedFreeFunc) vips_thing_free) static GSList *vips_area_all = NULL; VipsArea * vips_area_copy(VipsArea *area) { g_mutex_lock(&area->lock); g_assert(area->count > 0); area->count += 1; #ifdef DEBUG printf("vips_area_copy: %p count = %d\n", area, area->count); #endif /*DEBUG*/ g_mutex_unlock(&area->lock); return area; } int vips_area_free_cb(void *mem, VipsArea *area) { g_free(mem); return 0; } static void vips_area_free(VipsArea *area) { if (area->free_fn && area->data) { area->free_fn(area->data, area); area->free_fn = NULL; } area->data = NULL; } void vips_area_unref(VipsArea *area) { g_mutex_lock(&area->lock); g_assert(area->count > 0); area->count -= 1; #ifdef DEBUG printf("vips_area_unref: %p count = %d\n", area, area->count); #endif /*DEBUG*/ if (vips__leak) { g_mutex_lock(&vips__global_lock); g_assert(g_slist_find(vips_area_all, area)); g_mutex_unlock(&vips__global_lock); } if (area->count == 0) { vips_area_free(area); g_mutex_unlock(&area->lock); g_mutex_clear(&area->lock); if (vips__leak) { g_mutex_lock(&vips__global_lock); vips_area_all = g_slist_remove(vips_area_all, area); g_mutex_unlock(&vips__global_lock); } g_free(area); #ifdef DEBUG g_mutex_lock(&vips__global_lock); printf("vips_area_unref: free .. total = %d\n", g_slist_length(vips_area_all)); g_mutex_unlock(&vips__global_lock); #endif /*DEBUG*/ } else g_mutex_unlock(&area->lock); } /* autoptr needs typed versions of functions for free. */ void VipsArrayDouble_unref(VipsArrayDouble *array) { vips_area_unref(VIPS_AREA(array)); } void VipsArrayImage_unref(VipsArrayImage *array) { vips_area_unref(VIPS_AREA(array)); } /** * vips_area_new: * @free_fn: (scope async) (nullable): @data will be freed with this function * @data: (transfer full): data will be freed with this function * * A VipsArea wraps a chunk of memory. It adds reference counting and a free * function. It also keeps a count and a [alias@GObject.Type], so the area can * be an array. * * This type is used for things like passing an array of double or an array of * [class@Object] pointers to operations, and for reference-counted immutable * strings. * * Initial count == 1, so [method@Area.unref] after attaching somewhere. * * ::: seealso * [method@Area.unref]. * * Returns: (transfer full): the new [struct@Area]. */ VipsArea * vips_area_new(VipsCallbackFn free_fn, void *data) { VipsArea *area; area = g_new(VipsArea, 1); area->count = 1; g_mutex_init(&area->lock); area->length = 0; area->data = data; area->free_fn = free_fn; area->type = 0; area->sizeof_type = 0; if (vips__leak) { g_mutex_lock(&vips__global_lock); vips_area_all = g_slist_prepend(vips_area_all, area); g_mutex_unlock(&vips__global_lock); } #ifdef DEBUG g_mutex_lock(&vips__global_lock); printf("vips_area_new: %p count = %d (%d in total)\n", area, area->count, g_slist_length(vips_area_all)); g_mutex_unlock(&vips__global_lock); #endif /*DEBUG*/ return area; } int vips__type_leak(void) { int n_leaks; n_leaks = 0; if (vips_area_all) { GSList *p; fprintf(stderr, "%d VipsArea alive\n", g_slist_length(vips_area_all)); for (p = vips_area_all; p; p = p->next) { VipsArea *area = VIPS_AREA(p->data); fprintf(stderr, "\t%p count = %d, bytes = %zd\n", area, area->count, area->length); n_leaks += 1; } } return n_leaks; } /** * vips_area_new_array: * @type: [alias@GObject.Type] of elements to store * @sizeof_type: `sizeof()` an element in the array * @n: number of elements in the array * * An area which holds an array of elements of some [alias@GObject.Type]. * To set values for the elements, get the pointer and write. * * ::: seealso * [method@Area.unref]. * * Returns: (transfer full): the new [struct@Area]. */ VipsArea * vips_area_new_array(GType type, size_t sizeof_type, int n) { VipsArea *area; void *array; array = g_malloc(n * sizeof_type); area = vips_area_new((VipsCallbackFn) vips_area_free_cb, array); area->n = n; area->length = n * sizeof_type; area->type = type; area->sizeof_type = sizeof_type; return area; } static int vips_area_free_array_object(GObject **array, VipsArea *area) { int i; for (i = 0; i < area->n; i++) VIPS_FREEF(g_object_unref, array[i]); VIPS_FREE(array); area->n = 0; return 0; } /** * vips_area_new_array_object: (constructor) * @n: number of elements in the array * * An area which holds an array of [class@GObject.Object] s. See * [ctor@Area.new_array]. When the area is freed, each [class@GObject.Object] * will be unreffed. * * Add an extra `NULL` element at the end, handy for eg. * [func@Image.pipeline_array] etc. * * ::: seealso * [method@Area.unref]. * * Returns: (transfer full): the new [struct@Area]. */ VipsArea * vips_area_new_array_object(int n) { GObject **array; VipsArea *area; array = g_new0(GObject *, n + 1); area = vips_area_new((VipsCallbackFn) vips_area_free_array_object, array); area->n = n; area->length = n * sizeof(GObject *); area->type = G_TYPE_OBJECT; area->sizeof_type = sizeof(GObject *); return area; } /** * vips_area_get_data: * @area: [struct@Area] to fetch from * @length: (out) (optional): optionally return length in bytes here * @n: (out) (optional): optionally return number of elements here * @type: (out) (optional): optionally return element type here * @sizeof_type: (out) (optional): optionally return `sizeof()` element type here * * Return the data pointer plus optionally the length in bytes of an area, * the number of elements, the [alias@GObject.Type] of each element and the * `sizeof()` each element. * * Returns: (transfer none): The pointer held by @area. */ void * vips_area_get_data(VipsArea *area, size_t *length, int *n, GType *type, size_t *sizeof_type) { if (!area) return NULL; if (length) *length = area->length; if (n) *n = area->n; if (type) *type = area->type; if (sizeof_type) *sizeof_type = area->sizeof_type; return area->data; } /* Transform an area to a G_TYPE_STRING. */ static void transform_area_g_string(const GValue *src_value, GValue *dest_value) { VipsArea *area; char buf[256]; area = g_value_get_boxed(src_value); g_snprintf(buf, 256, "VIPS_TYPE_AREA, count = %d, data = %p", area->count, area->data); g_value_set_string(dest_value, buf); } G_DEFINE_BOXED_TYPE_WITH_CODE(VipsArea, vips_area, (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref, g_value_register_transform_func( g_define_type_id, G_TYPE_STRING, transform_area_g_string);) /* Transform funcs for builtin types to SAVE_STRING. */ static void transform_int_save_string(const GValue *src_value, GValue *dest_value) { vips_value_set_save_stringf(dest_value, "%d", g_value_get_int(src_value)); } static void transform_save_string_int(const GValue *src_value, GValue *dest_value) { g_value_set_int(dest_value, atoi(vips_value_get_save_string(src_value))); } static void transform_double_save_string(const GValue *src_value, GValue *dest_value) { char buf[G_ASCII_DTOSTR_BUF_SIZE]; /* Need to be locale independent. */ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, g_value_get_double(src_value)); vips_value_set_save_string(dest_value, buf); } static void transform_save_string_double(const GValue *src_value, GValue *dest_value) { g_value_set_double(dest_value, g_ascii_strtod(vips_value_get_save_string(src_value), NULL)); } static void transform_float_save_string(const GValue *src_value, GValue *dest_value) { char buf[G_ASCII_DTOSTR_BUF_SIZE]; /* Need to be locale independent. */ g_ascii_dtostr(buf, G_ASCII_DTOSTR_BUF_SIZE, g_value_get_float(src_value)); vips_value_set_save_string(dest_value, buf); } static void transform_save_string_float(const GValue *src_value, GValue *dest_value) { g_value_set_float(dest_value, g_ascii_strtod(vips_value_get_save_string(src_value), NULL)); } /* Save meta fields to the header. We have a new string type for header fields * to save to XML and define transform functions to go from our meta types to * this string type. */ G_DEFINE_BOXED_TYPE_WITH_CODE(VipsSaveString, vips_save_string, (GBoxedCopyFunc) g_strdup, (GBoxedFreeFunc) g_free, g_value_register_transform_func( G_TYPE_INT, g_define_type_id, transform_int_save_string); g_value_register_transform_func( g_define_type_id, G_TYPE_INT, transform_save_string_int); g_value_register_transform_func( G_TYPE_DOUBLE, g_define_type_id, transform_double_save_string); g_value_register_transform_func( g_define_type_id, G_TYPE_DOUBLE, transform_save_string_double); g_value_register_transform_func( G_TYPE_FLOAT, g_define_type_id, transform_float_save_string); g_value_register_transform_func( g_define_type_id, G_TYPE_FLOAT, transform_save_string_float); ) /* Transform a refstring to a G_TYPE_STRING and back. */ static void transform_ref_string_g_string(const GValue *src_value, GValue *dest_value) { g_value_set_string(dest_value, vips_value_get_ref_string(src_value, NULL)); } static void transform_g_string_ref_string(const GValue *src_value, GValue *dest_value) { vips_value_set_ref_string(dest_value, g_value_get_string(src_value)); } /* To a save string. */ static void transform_ref_string_save_string(const GValue *src_value, GValue *dest_value) { vips_value_set_save_stringf(dest_value, "%s", vips_value_get_ref_string(src_value, NULL)); } static void transform_save_string_ref_string(const GValue *src_value, GValue *dest_value) { vips_value_set_ref_string(dest_value, vips_value_get_save_string(src_value)); } /** * vips_ref_string_new: * @str: (transfer none): string to store * * Create a new refstring. These are reference-counted immutable strings, used * to store string data in vips image metadata. * * Strings must be valid utf-8; use blob for binary data. * * ::: seealso * [method@Area.unref]. * * Returns: (transfer full) (nullable): the new [struct@RefString], or `NULL` on * error. */ VipsRefString * vips_ref_string_new(const char *str) { VipsArea *area; char *utf8_str = g_utf8_make_valid(str, -1); area = vips_area_new((VipsCallbackFn) vips_area_free_cb, utf8_str); /* Handy place to cache this. */ area->length = strlen(utf8_str); return (VipsRefString *) area; } /** * vips_ref_string_get: * @refstr: the [struct@RefString] to fetch from * @length: (out) (optional): return length here, optionally * * Get a pointer to the private string inside a refstr. Handy for language * bindings. * * ::: seealso * [func@value_get_ref_string]. * * Returns: (transfer none): The C string held by @refstr. */ const char * vips_ref_string_get(VipsRefString *refstr, size_t *length) { VipsArea *area = VIPS_AREA(refstr); return vips_area_get_data(area, length, NULL, NULL, NULL); } G_DEFINE_BOXED_TYPE_WITH_CODE(VipsRefString, vips_ref_string, (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref, g_value_register_transform_func( g_define_type_id, G_TYPE_STRING, transform_ref_string_g_string); g_value_register_transform_func( G_TYPE_STRING, g_define_type_id, transform_g_string_ref_string); g_value_register_transform_func( g_define_type_id, VIPS_TYPE_SAVE_STRING, transform_ref_string_save_string); g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, g_define_type_id, transform_save_string_ref_string);) /** * vips_blob_new: * @free_fn: (scope async) (allow-none): @data will be freed with this function * @data: (array length=length) (element-type guint8) (transfer full): data to store * @length: number of bytes in @data * * Like [ctor@Area.new], but track a length as well. The returned [struct@Blob] * takes ownership of @data and will free it with @free_fn. Pass `NULL` for * @free_fn to not transfer ownership. * * An area of mem with a free func and a length (some sort of binary object, * like an ICC profile). * * ::: seealso * [method@Area.unref]. * * Returns: (transfer full): the new [struct@Blob]. */ VipsBlob * vips_blob_new(VipsCallbackFn free_fn, const void *data, size_t length) { VipsArea *area; area = vips_area_new(free_fn, (void *) data); area->length = length; return (VipsBlob *) area; } /** * vips_blob_copy: * @data: (array length=length) (element-type guint8) (transfer none): data to store * @length: number of bytes in @data * * Like [ctor@Blob.new], but take a copy of the data. Useful for bindings * which struggle with callbacks. * * ::: seealso * [ctor@Blob.new]. * * Returns: (transfer full): the new [struct@Blob]. */ VipsBlob * vips_blob_copy(const void *data, size_t length) { void *data_copy; VipsArea *area; data_copy = g_malloc(length); memcpy(data_copy, data, length); area = vips_area_new((VipsCallbackFn) vips_area_free_cb, data_copy); area->length = length; return (VipsBlob *) area; } /** * vips_blob_get: * @blob: [struct@Blob] to fetch from * @length: return number of bytes of data * * Get the data from a [struct@Blob]. * * ::: seealso * [ctor@Blob.new]. * * Returns: (array length=length) (element-type guint8) (transfer none): the * data */ const void * vips_blob_get(VipsBlob *blob, size_t *length) { return vips_area_get_data(VIPS_AREA(blob), length, NULL, NULL, NULL); } /** * vips_blob_set: * @blob: [struct@Blob] to set * @free_fn: (scope async) (allow-none): @data will be freed with this function * @data: (array length=length) (element-type guint8) (transfer full): data to store * @length: number of bytes in @data * * Any old data is freed and new data attached. * * It's sometimes useful to be able to create blobs as empty and then fill * them later. * * ::: seealso * [ctor@Blob.new]. */ void vips_blob_set(VipsBlob *blob, VipsCallbackFn free_fn, const void *data, size_t length) { VipsArea *area = VIPS_AREA(blob); g_mutex_lock(&area->lock); vips_area_free(area); area->free_fn = free_fn; area->length = length; area->data = (void *) data; g_mutex_unlock(&area->lock); } /* Transform a blob to a G_TYPE_STRING. */ static void transform_blob_g_string(const GValue *src_value, GValue *dest_value) { void *blob; size_t length; char buf[256]; blob = vips_value_get_blob(src_value, &length); g_snprintf(buf, 256, "VIPS_TYPE_BLOB, data = %p, length = %zd", blob, length); g_value_set_string(dest_value, buf); } /* Transform a blob to a save string and back. */ static void transform_blob_save_string(const GValue *src_value, GValue *dest_value) { void *blob; size_t length; char *b64; blob = vips_value_get_blob(src_value, &length); if ((b64 = g_base64_encode(blob, length))) { vips_value_set_save_string(dest_value, b64); g_free(b64); } else /* No error return from transform, but we should set it to * something. */ vips_value_set_save_string(dest_value, ""); } static void transform_save_string_blob(const GValue *src_value, GValue *dest_value) { const char *b64; void *blob; size_t length; b64 = vips_value_get_save_string(src_value); if ((blob = g_base64_decode(b64, &length))) vips_value_set_blob(dest_value, (VipsCallbackFn) vips_area_free_cb, blob, length); else /* No error return from transform, but we should set it to * something. */ vips_value_set_blob(dest_value, NULL, NULL, 0); } G_DEFINE_BOXED_TYPE_WITH_CODE(VipsBlob, vips_blob, (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref, g_value_register_transform_func( g_define_type_id, G_TYPE_STRING, transform_blob_g_string); g_value_register_transform_func( g_define_type_id, VIPS_TYPE_SAVE_STRING, transform_blob_save_string); g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, g_define_type_id, transform_save_string_blob);) /** * vips_array_int_new: * @array: (array length=n): array of int * @n: number of ints * * Allocate a new array of ints and copy @array into it. Free with * [method@Area.unref]. * * ::: seealso * [struct@Area]. * * Returns: (transfer full): A new [struct@ArrayInt]. */ VipsArrayInt * vips_array_int_new(const int *array, int n) { VipsArea *area; int *array_copy; area = vips_area_new_array(G_TYPE_INT, sizeof(int), n); array_copy = vips_area_get_data(area, NULL, NULL, NULL, NULL); memcpy(array_copy, array, n * sizeof(int)); return (VipsArrayInt *) area; } /** * vips_array_int_newv: * @n: number of ints * @...: list of int arguments * * Allocate a new array of @n ints and copy @... into it. Free with * [method@Area.unref]. * * ::: seealso * [ctor@ArrayInt.new] * * Returns: (transfer full): A new [struct@ArrayInt]. */ VipsArrayInt * vips_array_int_newv(int n, ...) { va_list ap; VipsArea *area; int *array; int i; area = vips_area_new_array(G_TYPE_INT, sizeof(int), n); array = vips_area_get_data(area, NULL, NULL, NULL, NULL); va_start(ap, n); for (i = 0; i < n; i++) array[i] = va_arg(ap, int); va_end(ap); return (VipsArrayInt *) area; } /** * vips_array_int_get: * @array: the [struct@ArrayInt] to fetch from * @n: length of array * * Fetch an int array from a [struct@ArrayInt]. Useful for language bindings. * * Returns: (array length=n) (transfer none): array of int */ int * vips_array_int_get(VipsArrayInt *array, int *n) { VipsArea *area = VIPS_AREA(array); g_assert(area->type == G_TYPE_INT); if (n) *n = area->n; return (int *) VIPS_ARRAY_ADDR(array, 0); } static void transform_array_int_g_string(const GValue *src_value, GValue *dest_value) { int n; int *array; char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC(txt); int i; if ((array = vips_value_get_array_int(src_value, &n))) for (i = 0; i < n; i++) /* Use space as a separator since ',' may be a * decimal point in this locale. */ vips_buf_appendf(&buf, "%d ", array[i]); g_value_set_string(dest_value, vips_buf_all(&buf)); } static void transform_array_int_save_string(const GValue *src_value, GValue *dest_value) { GValue intermediate = G_VALUE_INIT; g_value_init(&intermediate, G_TYPE_STRING); transform_array_int_g_string(src_value, &intermediate); vips_value_set_save_string(dest_value, g_value_get_string(&intermediate)); g_value_unset(&intermediate); } /* It'd be great to be able to write a generic string->array function, but * it doesn't seem possible. */ static void transform_g_string_array_int(const GValue *src_value, GValue *dest_value) { char *str; int n; char *p, *q; int i; int *array; /* Walk the string to get the number of elements. * We need a copy of the string, since we insert \0 during * scan. */ str = g_value_dup_string(src_value); n = 0; for (p = str; (q = vips_break_token(p, "\t;, ")); p = q) n += 1; g_free(str); vips_value_set_array_int(dest_value, NULL, n); array = vips_value_get_array_int(dest_value, NULL); str = g_value_dup_string(src_value); i = 0; for (p = str; (q = vips_break_token(p, "\t;, ")); p = q) { if (sscanf(p, "%d", &array[i]) != 1) { /* Set array to length zero to indicate an error. */ vips_error("vipstype", _("unable to convert \"%s\" to int"), p); vips_value_set_array(dest_value, 0, G_TYPE_INT, sizeof(int)); g_free(str); return; } i += 1; } g_free(str); } static void transform_save_string_array_int(const GValue *src_value, GValue *dest_value) { GValue intermediate = G_VALUE_INIT; g_value_init(&intermediate, G_TYPE_STRING); g_value_set_string(&intermediate, vips_value_get_save_string(src_value)); transform_g_string_array_int(&intermediate, dest_value); g_value_unset(&intermediate); } /* We need a arrayint, we have an int, make a one-element array. */ static void transform_int_array_int(const GValue *src_value, GValue *dest_value) { int *array; vips_value_set_array_int(dest_value, NULL, 1); array = vips_value_get_array_int(dest_value, NULL); array[0] = g_value_get_int(src_value); } static void transform_double_array_int(const GValue *src_value, GValue *dest_value) { int *array; vips_value_set_array_int(dest_value, NULL, 1); array = vips_value_get_array_int(dest_value, NULL); array[0] = g_value_get_double(src_value); } static void transform_array_double_array_int(const GValue *src_value, GValue *dest_value) { int n; double *array_double = vips_value_get_array_double(src_value, &n); int *array_int; int i; vips_value_set_array_int(dest_value, NULL, n); array_int = vips_value_get_array_int(dest_value, NULL); for (i = 0; i < n; i++) array_int[i] = array_double[i]; } G_DEFINE_BOXED_TYPE_WITH_CODE(VipsArrayInt, vips_array_int, (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref, g_value_register_transform_func( g_define_type_id, G_TYPE_STRING, transform_array_int_g_string); g_value_register_transform_func( G_TYPE_STRING, g_define_type_id, transform_g_string_array_int); g_value_register_transform_func( G_TYPE_INT, g_define_type_id, transform_int_array_int); g_value_register_transform_func( G_TYPE_DOUBLE, g_define_type_id, transform_double_array_int); g_value_register_transform_func( g_define_type_id, VIPS_TYPE_SAVE_STRING, transform_array_int_save_string); g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, g_define_type_id, transform_save_string_array_int);) /** * vips_array_double_new: * @array: (array length=n): array of double * @n: number of doubles * * Allocate a new array of doubles and copy @array into it. Free with * [method@Area.unref]. * * ::: seealso * [struct@Area]. * * Returns: (transfer full): A new [struct@ArrayDouble]. */ VipsArrayDouble * vips_array_double_new(const double *array, int n) { VipsArea *area; double *array_copy; area = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); array_copy = vips_area_get_data(area, NULL, NULL, NULL, NULL); memcpy(array_copy, array, n * sizeof(double)); return (VipsArrayDouble *) area; } /** * vips_array_double_newv: * @n: number of doubles * @...: list of double arguments * * Allocate a new array of @n doubles and copy @... into it. Free with * [method@Area.unref]. * * ::: seealso * [ctor@ArrayDouble.new] * * Returns: (transfer full): A new [struct@ArrayDouble]. */ VipsArrayDouble * vips_array_double_newv(int n, ...) { va_list ap; VipsArea *area; double *array; int i; area = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); array = vips_area_get_data(area, NULL, NULL, NULL, NULL); va_start(ap, n); for (i = 0; i < n; i++) array[i] = va_arg(ap, double); va_end(ap); return (VipsArrayDouble *) area; } /** * vips_array_double_get: * @array: the [struct@ArrayDouble] to fetch from * @n: length of array * * Fetch a double array from a [struct@ArrayDouble]. Useful for language bindings. * * Returns: (array length=n) (transfer none): array of double */ double * vips_array_double_get(VipsArrayDouble *array, int *n) { VipsArea *area = VIPS_AREA(array); g_assert(area->type == G_TYPE_DOUBLE); if (n) *n = area->n; return VIPS_ARRAY_ADDR(array, 0); } typedef void (*SetStringFn)(GValue *dest_value, const char *str); static void array_double_to_value(const GValue *src_value, GValue *dest_value, SetStringFn set) { int n; double *array; char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC(txt); int i; if ((array = vips_value_get_array_double(src_value, &n))) for (i = 0; i < n; i++) { // locale independent vips_buf_appendg(&buf, array[i]); vips_buf_appends(&buf, " "); } set(dest_value, vips_buf_all(&buf)); } static void transform_array_double_g_string(const GValue *src_value, GValue *dest_value) { array_double_to_value(src_value, dest_value, g_value_set_string); } static void transform_array_double_save_string(const GValue *src_value, GValue *dest_value) { array_double_to_value(src_value, dest_value, vips_value_set_save_string); } /* It'd be great to be able to write a generic string->array function, but * it doesn't seem to be possible. */ static void string_to_array_double(const char *input, GValue *dest_value) { char *str; int n; char *p, *q; int i; double *array; str = g_strdup(input); n = 0; for (p = str; (q = vips_break_token(p, "\t;, ")); p = q) n += 1; g_free(str); vips_value_set_array_double(dest_value, NULL, n); array = vips_value_get_array_double(dest_value, NULL); str = g_strdup(input); i = 0; for (p = str; (q = vips_break_token(p, "\t;, ")); p = q) { // this is locale-independent if (vips_strtod(p, &array[i])) { /* Set array to length zero to indicate an error. */ g_warning("bad argument: not a numeric value \"%s\"", p); vips_value_set_array_double(dest_value, NULL, 0); g_free(str); return; } i += 1; } g_free(str); } static void transform_g_string_array_double(const GValue *src_value, GValue *dest_value) { string_to_array_double(g_value_get_string(src_value), dest_value); } static void transform_save_string_array_double(const GValue *src_value, GValue *dest_value) { string_to_array_double(vips_value_get_save_string(src_value), dest_value); } /* We need an arraydouble, we have a double, make a one-element array. */ static void transform_double_array_double(const GValue *src_value, GValue *dest_value) { double *array; vips_value_set_array_double(dest_value, NULL, 1); array = vips_value_get_array_double(dest_value, NULL); array[0] = g_value_get_double(src_value); } static void transform_int_array_double(const GValue *src_value, GValue *dest_value) { double *array; vips_value_set_array_double(dest_value, NULL, 1); array = vips_value_get_array_double(dest_value, NULL); array[0] = g_value_get_int(src_value); } static void transform_array_int_array_double(const GValue *src_value, GValue *dest_value) { int n; int *array_int = vips_value_get_array_int(src_value, &n); double *array_double; int i; vips_value_set_array_double(dest_value, NULL, n); array_double = vips_value_get_array_double(dest_value, NULL); for (i = 0; i < n; i++) array_double[i] = array_int[i]; } /* You can set enums from ints, but not doubles. Add a double converter too. */ static void transform_double_enum(const GValue *src_value, GValue *dest_value) { g_value_set_enum(dest_value, g_value_get_double(src_value)); } G_DEFINE_BOXED_TYPE_WITH_CODE(VipsArrayDouble, vips_array_double, (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref, g_value_register_transform_func( g_define_type_id, G_TYPE_STRING, transform_array_double_g_string); g_value_register_transform_func( G_TYPE_STRING, g_define_type_id, transform_g_string_array_double); g_value_register_transform_func( g_define_type_id, VIPS_TYPE_SAVE_STRING, transform_array_double_save_string); g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, g_define_type_id, transform_save_string_array_double); g_value_register_transform_func( G_TYPE_DOUBLE, g_define_type_id, transform_double_array_double); g_value_register_transform_func( G_TYPE_INT, g_define_type_id, transform_int_array_double); g_value_register_transform_func( G_TYPE_DOUBLE, G_TYPE_ENUM, transform_double_enum); ) /** * vips_array_image_new: (constructor) * @array: (array length=n): array of [class@Image] * @n: number of images * * Allocate a new array of images and copy @array into it. Free with * [method@Area.unref]. * * The images will all be reffed by this function. They * will be automatically unreffed for you by * [method@Area.unref]. * * Add an extra `NULL` element at the end, handy for eg. * [func@Image.pipeline_array] etc. * * ::: seealso * [struct@Area]. * * Returns: (transfer full): A new [struct@ArrayImage]. */ VipsArrayImage * vips_array_image_new(VipsImage **array, int n) { VipsArea *area; VipsImage **array_copy; int i; area = vips_area_new_array_object(n); area->type = VIPS_TYPE_IMAGE; array_copy = vips_area_get_data(area, NULL, NULL, NULL, NULL); for (i = 0; i < n; i++) { array_copy[i] = (VipsImage *) array[i]; g_object_ref(array_copy[i]); } return (VipsArrayImage *) area; } /** * vips_array_image_newv: (constructor) * @n: number of images * @...: list of [class@Image] arguments * * Allocate a new array of @n [class@Image] and copy @... into it. Free with * [method@Area.unref]. * * The images will all be reffed by this function. They * will be automatically unreffed for you by * [method@Area.unref]. * * Add an extra `NULL` element at the end, handy for eg. * [func@Image.pipeline_array] etc. * * ::: seealso * [ctor@ArrayImage.new] * * Returns: (transfer full): A new [struct@ArrayImage]. */ VipsArrayImage * vips_array_image_newv(int n, ...) { va_list ap; VipsArea *area; VipsImage **array; int i; area = vips_area_new_array_object(n); area->type = VIPS_TYPE_IMAGE; array = vips_area_get_data(area, NULL, NULL, NULL, NULL); va_start(ap, n); for (i = 0; i < n; i++) { array[i] = va_arg(ap, VipsImage *); g_object_ref(array[i]); } va_end(ap); return (VipsArrayImage *) area; } VipsArrayImage * vips_array_image_new_from_string(const char *string, VipsAccess access) { char *str; int n; VipsArea *area; VipsImage **array; char *p, *q; int i; /* We need a copy of the string, since we insert \0 during * scan. */ str = g_strdup(string); n = 0; for (p = str; (q = vips_break_token(p, " \n\t\r")); p = q) n += 1; g_free(str); area = vips_area_new_array_object(n); area->type = VIPS_TYPE_IMAGE; array = vips_area_get_data(area, NULL, NULL, NULL, NULL); str = g_strdup(string); i = 0; for (p = str; (q = vips_break_token(p, " \n\t\r")); p = q) { if (!(array[i] = vips_image_new_from_file(p, "access", access, NULL))) { vips_area_unref(area); g_free(str); return NULL; } i += 1; } g_free(str); return (VipsArrayImage *) area; } /** * vips_array_image_empty: (constructor) * * Make an empty image array. * Handy with [method@ArrayImage.append] for bindings * which can't handle object array arguments. * * ::: seealso * [method@ArrayImage.append]. * * Returns: (transfer full): A new [struct@ArrayImage]. */ VipsArrayImage * vips_array_image_empty(void) { return vips_array_image_new(NULL, 0); } /** * vips_array_image_append: * @array: (transfer none): append to this * @image: add this * * Make a new [struct@ArrayImage], one larger than @array, with @image appended * to the end. * Handy with [ctor@ArrayImage.empty] for bindings * which can't handle object array arguments. * * ::: seealso * [ctor@ArrayImage.empty]. * * Returns: (transfer full): A new [struct@ArrayImage]. */ VipsArrayImage * vips_array_image_append(VipsArrayImage *array, VipsImage *image) { VipsArea *old_area = VIPS_AREA(array); int n = old_area->n; VipsArea *new_area; VipsImage **old_vector; VipsImage **new_vector; int i; new_area = vips_area_new_array_object(n + 1); new_area->type = VIPS_TYPE_IMAGE; old_vector = vips_area_get_data(old_area, NULL, NULL, NULL, NULL); new_vector = vips_area_get_data(new_area, NULL, NULL, NULL, NULL); for (i = 0; i < n; i++) { new_vector[i] = (VipsImage *) old_vector[i]; g_object_ref(new_vector[i]); } new_vector[i] = image; g_object_ref(new_vector[i]); return (VipsArrayImage *) new_area; } /** * vips_array_image_get: * @array: the [struct@ArrayImage] to fetch from * @n: length of array * * Fetch an image array from a [struct@ArrayImage]. Useful for language bindings. * * Returns: (array length=n) (transfer none): array of [class@Image] */ VipsImage ** vips_array_image_get(VipsArrayImage *array, int *n) { VipsArea *area = VIPS_AREA(array); g_assert(area->type == VIPS_TYPE_IMAGE); if (n) *n = area->n; return (VipsImage **) VIPS_ARRAY_ADDR(array, 0); } static void transform_g_string_array_image(const GValue *src_value, GValue *dest_value) { char *str; VipsArrayImage *array_image; str = g_value_dup_string(src_value); /* We can't get access here, just assume nothing. See the special case * in vips_object_new_from_string() for how we usually get this right. */ if (!(array_image = vips_array_image_new_from_string(str, 0))) { /* Set the dest to length zero to indicate error. */ vips_value_set_array_image(dest_value, 0); g_free(str); return; } g_free(str); g_value_set_boxed(dest_value, array_image); vips_area_unref(VIPS_AREA(array_image)); } G_DEFINE_BOXED_TYPE_WITH_CODE(VipsArrayImage, vips_array_image, (GBoxedCopyFunc) vips_area_copy, (GBoxedFreeFunc) vips_area_unref, g_value_register_transform_func( G_TYPE_STRING, g_define_type_id, transform_g_string_array_image);) /** * vips_value_set_area: * @value: set this value * @free_fn: (scope async) (nullable): data will be freed with this function * @data: (transfer full): set @value to track this pointer * * Set value to be a ref-counted area of memory with a free function. */ void vips_value_set_area(GValue *value, VipsCallbackFn free_fn, void *data) { VipsArea *area; area = vips_area_new(free_fn, data); g_value_init(value, VIPS_TYPE_AREA); g_value_set_boxed(value, area); vips_area_unref(area); } /** * vips_value_get_area: * @value: get from this value * @length: (out) (optional): optionally return length here * * Get the pointer from an area. Don't touch count (area is static). * * Returns: (transfer none): The pointer held by @value. */ void * vips_value_get_area(const GValue *value, size_t *length) { VipsArea *area; area = g_value_get_boxed(value); return vips_area_get_data(area, length, NULL, NULL, NULL); } /** * vips_value_get_save_string: * @value: GValue to get from * * Get the C string held internally by the GValue. * * Returns: (transfer none): The C string held by @value. */ const char * vips_value_get_save_string(const GValue *value) { return (char *) g_value_get_boxed(value); } /** * vips_value_set_save_string: * @value: (out): GValue to set * @str: C string to copy into the GValue * * Copies the C string into @value. * * @str should be a valid utf-8 string. */ void vips_value_set_save_string(GValue *value, const char *str) { g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_SAVE_STRING); if (!g_utf8_validate(str, -1, NULL)) str = ""; g_value_set_boxed(value, str); } /** * vips_value_set_save_stringf: * @value: (out): GValue to set * @fmt: `printf()`-style format string * @...: arguments to `printf()`-formatted @fmt * * Generates a string and copies it into @value. */ void vips_value_set_save_stringf(GValue *value, const char *fmt, ...) { va_list ap; char *str; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_SAVE_STRING); va_start(ap, fmt); str = g_strdup_vprintf(fmt, ap); va_end(ap); vips_value_set_save_string(value, str); g_free(str); } /** * vips_value_get_ref_string: * @value: [struct@GObject.Value] to get from * @length: (out) (optional): return length here, optionally * * Get the C string held internally by the [struct@GObject.Value]. * * Returns: (transfer none): The C string held by @value. */ const char * vips_value_get_ref_string(const GValue *value, size_t *length) { return vips_value_get_area(value, length); } /** * vips_value_set_ref_string: * @value: (out): [struct@GObject.Value] to set * @str: C string to copy into the GValue * * Copies the C string @str into @value. * * vips_ref_string are immutable C strings that are copied between images by * copying reference-counted pointers, making them much more efficient than * regular [struct@GObject.Value] strings. * * @str should be a valid utf-8 string. */ void vips_value_set_ref_string(GValue *value, const char *str) { VipsRefString *ref_str; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_REF_STRING); ref_str = vips_ref_string_new(str); g_value_set_boxed(value, ref_str); vips_area_unref(VIPS_AREA(ref_str)); } /** * vips_value_set_blob: * @value: (out): GValue to set * @free_fn: (scope async) (nullable): free function for @data * @data: (array length=length) (element-type guint8) (transfer full): pointer to area of * memory * @length: length of memory area * * Sets @value to hold a @data. When @value is freed, @data will be * freed with @free_fn. @value also holds a note of the size of the memory * area. * * blobs are things like ICC profiles or EXIF data. They are relocatable, and * are saved to VIPS files for you coded as base64 inside the XML. They are * copied by copying reference-counted pointers. * * ::: seealso * [func@value_get_blob] */ void vips_value_set_blob(GValue *value, VipsCallbackFn free_fn, const void *data, size_t length) { VipsBlob *blob; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_BLOB); blob = vips_blob_new(free_fn, data, length); g_value_set_boxed(value, blob); vips_area_unref(VIPS_AREA(blob)); } /** * vips_value_set_blob_free: * @value: GValue to set * @data: (transfer full) (array length=length) (element-type guint8) : pointer to area of * memory * @length: length of memory area * * Just like [func@value_set_blob], but when * @value is freed, @data will be * freed with [func@GLib.free]. * * This can be easier to call for language bindings. * * ::: seealso * [func@value_set_blob] */ void vips_value_set_blob_free(GValue *value, void *data, size_t length) { VipsBlob *blob; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_BLOB); blob = vips_blob_new((VipsCallbackFn) vips_area_free_cb, data, length); g_value_set_boxed(value, blob); vips_area_unref(VIPS_AREA(blob)); } /** * vips_value_get_blob: * @value: GValue to set * @length: (out) (optional): optionally return length of memory area * * Returns the data pointer from a blob. Optionally returns the length too. * * blobs are things like ICC profiles or EXIF data. They are relocatable, and * are saved to VIPS files for you coded as base64 inside the XML. They are * copied by copying reference-counted pointers. * * ::: seealso * [func@value_set_blob] * * Returns: (transfer none) (array length=length) (element-type guint8): The pointer held * by @value. */ void * vips_value_get_blob(const GValue *value, size_t *length) { return vips_value_get_area(value, length); } /** * vips_value_set_array: * @value: (out): [struct@GObject.Value] to set * @n: number of elements * @type: the type of each element * @sizeof_type: the sizeof each element * * Set @value to be an array of things. * * This allocates memory but does not * initialise the contents: get the pointer and write instead. */ void vips_value_set_array(GValue *value, int n, GType type, size_t sizeof_type) { VipsArea *area; area = vips_area_new_array(type, sizeof_type, n); g_value_set_boxed(value, area); vips_area_unref(area); } /** * vips_value_get_array: * @value: [struct@GObject.Value] to get from * @n: (out) (optional): return the number of elements here, optionally * @type: (out) (optional): return the type of each element here, optionally * @sizeof_type: (out) (optional): return the sizeof each element here, optionally * * Return the pointer to the array held by @value. * Optionally return the other properties of the array in @n, @type, * @sizeof_type. * * ::: seealso * [func@value_set_array]. * * Returns: (transfer none): The array address. */ void * vips_value_get_array(const GValue *value, int *n, GType *type, size_t *sizeof_type) { VipsArea *area; /* Can't check value type, because we may get called from * vips_*_get_type(). */ if (!(area = g_value_get_boxed(value))) return NULL; if (n) *n = area->n; if (type) *type = area->type; if (sizeof_type) *sizeof_type = area->sizeof_type; return area->data; } /** * vips_value_get_array_int: * @value: [struct@GObject.Value] to get from * @n: (out) (optional): return the number of elements here, optionally * * Return the start of the array of ints held by @value. * optionally return the number of elements in @n. * * ::: seealso * [ctor@ArrayInt.new]. * * Returns: (transfer none) (array length=n): The array address. */ int * vips_value_get_array_int(const GValue *value, int *n) { return vips_value_get_array(value, n, NULL, NULL); } /** * vips_value_set_array_int: * @value: [struct@GObject.Value] to get from * @array: (array length=n) (allow-none): array of ints * @n: the number of elements * * Set @value to hold a copy of @array. Pass in the array length in @n. * * ::: seealso * [method@ArrayInt.get]. */ void vips_value_set_array_int(GValue *value, const int *array, int n) { vips_value_set_array(value, n, G_TYPE_INT, sizeof(int)); if (array) { int *array_copy; array_copy = vips_value_get_array_int(value, NULL); memcpy(array_copy, array, n * sizeof(int)); } } /** * vips_value_get_array_double: * @value: [struct@GObject.Value] to get from * @n: (out) (optional): return the number of elements here, optionally * * Return the start of the array of doubles held by @value. * optionally return the number of elements in @n. * * ::: seealso * [ctor@ArrayDouble.new]. * * Returns: (transfer none) (array length=n): The array address. */ double * vips_value_get_array_double(const GValue *value, int *n) { return vips_value_get_array(value, n, NULL, NULL); } /** * vips_value_set_array_double: * @value: [struct@GObject.Value] to get from * @array: (array length=n) (allow-none): array of doubles * @n: the number of elements * * Set @value to hold a copy of @array. Pass in the array length in @n. * * ::: seealso * [method@ArrayDouble.get]. */ void vips_value_set_array_double(GValue *value, const double *array, int n) { vips_value_set_array(value, n, G_TYPE_DOUBLE, sizeof(double)); if (array) { double *array_copy; array_copy = vips_value_get_array_double(value, NULL); memcpy(array_copy, array, n * sizeof(double)); } } /** * vips_value_get_array_image: * @value: [struct@GObject.Value] to get from * @n: (out) (optional): return the number of elements here, optionally * * Return the start of the array of images held by @value. * optionally return the number of elements in @n. * * ::: seealso * [func@value_set_array_image]. * * Returns: (transfer none) (array length=n): The array address. */ VipsImage ** vips_value_get_array_image(const GValue *value, int *n) { return vips_value_get_array(value, n, NULL, NULL); } /** * vips_value_set_array_image: * @value: [struct@GObject.Value] to get from * @n: the number of elements * * Set @value to hold an array of images. Pass in the array length in @n. * * ::: seealso * [method@ArrayImage.get]. */ void vips_value_set_array_image(GValue *value, int n) { VipsArea *area; area = vips_area_new_array_object(n); area->type = VIPS_TYPE_IMAGE; g_value_set_boxed(value, area); vips_area_unref(area); } /** * vips_value_get_array_object: (skip) * @value: [struct@GObject.Value] to get from * @n: (out) (optional): return the number of elements here, optionally * * Return the start of the array of [class@GObject.Object] held by @value. * Optionally return the number of elements in @n. * * ::: seealso * [ctor@Area.new_array_object]. * * Returns: (transfer none) (array length=n): The array address. */ GObject ** vips_value_get_array_object(const GValue *value, int *n) { return vips_value_get_array(value, n, NULL, NULL); } /** * vips_value_set_array_object: * @value: (out): [struct@GObject.Value] to set * @n: the number of elements * * Set @value to hold an array of [class@GObject.Object]. Pass in the array * length in @n. * * ::: seealso * [func@value_get_array_object]. */ void vips_value_set_array_object(GValue *value, int n) { VipsArea *area; area = vips_area_new_array_object(n); g_value_set_boxed(value, area); vips_area_unref(area); } /* Make the types we need for basic functioning. Called from vips_init(). */ void vips__meta_init_types(void) { (void) vips_thing_get_type(); (void) vips_save_string_get_type(); (void) vips_area_get_type(); (void) vips_ref_string_get_type(); (void) vips_blob_get_type(); (void) vips_array_int_get_type(); (void) vips_array_double_get_type(); (void) vips_array_image_get_type(); /* Register transform functions to convert between an array of * integers and doubles. This is set here to prevent a recursive * call chain. */ g_value_register_transform_func(VIPS_TYPE_ARRAY_INT, VIPS_TYPE_ARRAY_DOUBLE, transform_array_int_array_double); g_value_register_transform_func(VIPS_TYPE_ARRAY_DOUBLE, VIPS_TYPE_ARRAY_INT, transform_array_double_array_int); } libvips-8.18.2/libvips/iofuncs/util.c000066400000000000000000001233301516303661500175310ustar00rootroot00000000000000/* Some basic util functions. */ /* Copyright (C) 1991-2003 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Enable linux extensions like O_TMPFILE, if available. */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #ifdef HAVE_IO_H #include #endif /*HAVE_IO_H*/ #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ #include #include /* Temp buffer for snprintf() layer on old systems. */ #define MAX_BUF (100000) #define MODE_READ CLOEXEC(BINARYIZE(O_RDONLY)) /** * vips_slist_equal: * @l1: (element-type guint8): a [struct@GLib.SList] * @l2: (element-type guint8): another [struct@GLib.SList] * * Test two lists for equality. * * Returns: `TRUE` if @l1 is equal to @l2. `FALSE` otherwise. */ gboolean vips_slist_equal(GSList *l1, GSList *l2) { while (l1 && l2) { if (l1->data != l2->data) return FALSE; l1 = l1->next; l2 = l2->next; } if (l1 || l2) return FALSE; return TRUE; } /** * vips_slist_map2: * @list: (element-type guint8): a [struct@GLib.SList] * @fn: (scope call): function to apply to each list element * @a: user data * @b: user data * * Map over a slist. _copy() the list in case the callback changes it. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_slist_map2(GSList *list, VipsSListMap2Fn fn, void *a, void *b) { GSList *copy; GSList *i; void *result; copy = g_slist_copy(list); result = NULL; for (i = copy; i && !(result = fn(i->data, a, b)); i = i->next) ; g_slist_free(copy); return result; } /** * vips_slist_map2_rev: * @list: (element-type guint8): a [struct@GLib.SList] * @fn: (scope call): function to apply to each list element * @a: user data * @b: user data * * Map backwards. We _reverse() rather than recurse and unwind to save stack. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_slist_map2_rev(GSList *list, VipsSListMap2Fn fn, void *a, void *b) { GSList *copy; GSList *i; void *result; copy = g_slist_copy(list); copy = g_slist_reverse(copy); result = NULL; for (i = copy; i && !(result = fn(i->data, a, b)); i = i->next) ; g_slist_free(copy); return result; } /** * vips_slist_map4: * @list: (element-type guint8): a [struct@GLib.SList] * @fn: (scope call): function to apply to each list element * @a: user data * @b: user data * @c: user data * @d: user data * * Map over a slist. _copy() the list in case the callback changes it. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_slist_map4(GSList *list, VipsSListMap4Fn fn, void *a, void *b, void *c, void *d) { GSList *copy; GSList *i; void *result; copy = g_slist_copy(list); result = NULL; for (i = copy; i && !(result = fn(i->data, a, b, c, d)); i = i->next) ; g_slist_free(copy); return result; } /** * vips_slist_fold2: * @list: (element-type guint8): a [struct@GLib.SList] * @start: initial value for the accumulator * @fn: (scope call): function to apply to each list element * @a: user data * @b: user data * * Fold over a slist, applying @fn to each element. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_slist_fold2(GSList *list, void *start, VipsSListFold2Fn fn, void *a, void *b) { void *c; GSList *this, *next; for (c = start, this = list; this; this = next) { next = this->next; if (!(c = fn(this->data, c, a, b))) return NULL; } return c; } /** * vips_slist_filter: * @list: (element-type guint8): a [struct@GLib.SList] * @fn: (scope call): function to call for each element. * @a: user data * @b: user data * * Remove all occurrences of an item from a list. * Returns the new head of the list. * * Returns: (element-type guint8) (transfer full): new head of @list */ GSList * vips_slist_filter(GSList *list, VipsSListMap2Fn fn, void *a, void *b) { GSList *tmp; GSList *prev; prev = NULL; tmp = list; while (tmp) { if (fn(tmp->data, a, b)) { GSList *next = tmp->next; if (prev) prev->next = next; if (list == tmp) list = next; tmp->next = NULL; g_slist_free(tmp); tmp = next; } else { prev = tmp; tmp = tmp->next; } } return list; } static void vips_slist_free_all_cb(void *thing, void *dummy) { g_free(thing); } /** * vips_slist_free_all: * @list: (element-type guint8): a [struct@GLib.SList] * * Free a [struct@GLib.SList] of things which need [func@GLib.free]ing. */ void vips_slist_free_all(GSList *list) { g_slist_foreach(list, vips_slist_free_all_cb, NULL); g_slist_free(list); } void * vips_map_equal(void *a, void *b) { if (a == b) return a; return NULL; } typedef struct { void *a; void *b; VipsSListMap2Fn fn; void *result; } Pair; static gboolean vips_hash_table_predicate(const char *key, void *value, Pair *pair) { return (pair->result = pair->fn(value, pair->a, pair->b)) != NULL; } /** * vips_hash_table_map: * @hash: a [struct@GLib.HashTable] * @fn: (scope call): function to apply to each hash value * @a: user data * @b: user data * * Like slist map, but for a hash table. * * Returns: `NULL` if @fn returns `NULL` for all arguments, otherwise the first * non-`NULL` value from @fn. */ void * vips_hash_table_map(GHashTable *hash, VipsSListMap2Fn fn, void *a, void *b) { Pair pair; pair.a = a; pair.b = b; pair.fn = fn; pair.result = NULL; g_hash_table_find(hash, (GHRFunc) vips_hash_table_predicate, &pair); return pair.result; } /* Case-insensitive test for string b ends string a. ASCII strings only. */ gboolean vips_iscasepostfix(const char *a, const char *b) { int m = strlen(a); int n = strlen(b); if (n > m) return FALSE; return g_ascii_strcasecmp(a + m - n, b) == 0; } /* Test for string a starts string b. a is a known-good string, b may be * random data. Use g_str_has_prefix() when both strings are non-NULL and * NULL-terminated. */ gboolean vips_isprefix(const char *a, const char *b) { int i; for (i = 0; a[i] && b[i]; i++) if (a[i] != b[i]) return FALSE; /* If there's stuff left in a but b has finished, we must have a * mismatch. */ if (a[i] && !b[i]) return FALSE; return TRUE; } /* Exactly like strcspn(), but allow \ as an escape character. * * strspne("hello world", " ") == 5 * strspne("hello\\ world", " ") == 12 */ static size_t strcspne(const char *s, const char *reject) { size_t skip; /* If \ is one of the reject chars, no need for any looping. */ if (strchr(reject, '\\')) return strcspn(s, reject); skip = 0; for (;;) { skip += strcspn(s + skip, reject); /* s[skip] is at the start of the string, or the end, or on a * break character. */ if (skip == 0 || !s[skip] || s[skip - 1] != '\\') break; /* So skip points at break char and we have a '\' in the char * before. Step over the break. */ skip += 1; } return skip; } /* Like strtok(). Give a string and a list of break characters. Then: * - skip initial break characters * - EOS? return NULL * - skip a series of non-break characters, allow `\` as a break escape * - write a '\0' over the next break character and return a pointer to the * char after that * * The idea is that this can be used in loops as the iterator. Example: * * char *p = " 1 2 3 "; // mutable * char *q; * int i; * int v[...]; * * for(i = 0; (q = vips_break_token(p, " ")); i++, p = q) * v[i] = atoi(p); * * will set * v[0] = 1; * v[1] = 2; * v[2] = 3; * * or with just one pointer, provided your atoi() is OK with trailing chars * and you know there is at least one item there * * char *p = " 1 2 3 "; // mutable * int i; * int v[...]; * * for(i = 0; p; p = vips_break_token(p, " ")) * v[i] = atoi(p); * * You can use \ to escape breaks, for example: * * vips_break_token("hello\ world", " ") will see a single token containing * a space. The \ characters are squashed out. */ char * vips_break_token(char *str, const char *brk) { char *p; char *q; /* Is the string empty? If yes, return NULL immediately. */ if (!str || !*str) return NULL; /* Skip initial break characters. */ p = str + strspn(str, brk); /* No item? */ if (!*p) return NULL; /* We have a token ... search for the first break character after the * token. strcspne() allows '\' to escape breaks, see above. */ p += strcspne(p, brk); /* Is there string left? */ if (*p) { /* Write in an end-of-string mark and return the start of the * next token. */ *p++ = '\0'; p += strspn(p, brk); } /* There may be escaped break characters in str. Loop, squashing them * out. */ for (q = strchr(str, '\\'); q && *q; q = strchr(q, '\\')) { memmove(q, q + 1, strlen(q)); /* If there's \\, we don't want to squash out the second \. */ q += 1; } return p; } /* Does a filename have one of a set of suffixes. Ignore case and any trailing * options. */ int vips_filename_suffix_match(const char *path, const char *suffixes[]) { char *basename; char *q; int result; const char **p; /* Drop any directory components. */ basename = g_path_get_basename(path); /* Zap any trailing [] options. */ if ((q = (char *) vips__find_rightmost_brackets(basename))) *q = '\0'; result = 0; for (p = suffixes; *p; p++) if (vips_iscasepostfix(basename, *p)) { result = 1; break; } g_free(basename); return result; } /* Get file length ... 64-bitally. -1 for error. */ gint64 vips_file_length(int fd) { #ifdef G_OS_WIN32 struct _stati64 st; if (_fstati64(fd, &st) == -1) { #else /*!G_OS_WIN32*/ struct stat st; if (fstat(fd, &st) == -1) { #endif /*G_OS_WIN32*/ vips_error_system(errno, "vips_file_length", "%s", _("unable to get file stats")); return -1; } return st.st_size; } /* Wrap write() up */ int vips__write(int fd, const void *buf, size_t count) { do { // write() uses int not size_t on windows, so we need to chunk // ... max 1gb, why not int chunk_size = VIPS_MIN(1024 * 1024 * 1024, count); gint64 nwritten = write(fd, buf, chunk_size); /* n == 0 isn't strictly an error, but we treat it as * one to make sure we don't get stuck in this loop. */ if (nwritten <= 0) { vips_error_system(errno, "vips__write", "%s", _("write failed")); return -1; } buf = (void *) ((char *) buf + nwritten); count -= nwritten; } while (count > 0); return 0; } #ifdef G_OS_WIN32 /* Set the create date on a file. On Windows, the create date may be copied * over from an existing file of the same name, unless you reset it. * * See https://devblogs.microsoft.com/oldnewthing/20050715-14/?p=34923 */ void vips__set_create_time(int fd) { HANDLE handle; SYSTEMTIME st; FILETIME ft; /* Create time cannot be set on invalid or stream * (stdin, stdout, stderr) file descriptors. */ if (fd < 3) return; if ((handle = (HANDLE) _get_osfhandle(fd)) == INVALID_HANDLE_VALUE) return; GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); SetFileTime(handle, &ft, &ft, &ft); } #endif /*G_OS_WIN32*/ /* open() with a utf8 filename, setting errno. */ int vips__open(const char *filename, int flags, int mode) { int fd; /* Various bad things happen if you accidentally open a directory as a * file. * * Except in O_TMPFILE mode, when you have to. */ if ( #ifdef O_TMPFILE !(flags & O_TMPFILE) && #endif /*O_TMPFILE*/ g_file_test(filename, G_FILE_TEST_IS_DIR)) { errno = EISDIR; return -1; } fd = g_open(filename, flags, mode); #ifdef G_OS_WIN32 if (fd != -1 && (mode & O_CREAT)) vips__set_create_time(fd); #endif /*G_OS_WIN32*/ return fd; } int vips__open_read(const char *filename) { return vips__open(filename, MODE_READ, 0); } /* fopen() with utf8 filename and mode, setting errno. */ FILE * vips__fopen(const char *filename, const char *mode) { FILE *fp; fp = g_fopen(filename, mode); #ifdef G_OS_WIN32 if (fp && mode[0] == 'w') vips__set_create_time(_fileno(fp)); #endif /*G_OS_WIN32*/ return fp; } /* Does a filename contain a directory separator? */ static gboolean filename_hasdir(const char *filename) { char *dirname; gboolean hasdir; dirname = g_path_get_dirname(filename); hasdir = (strcmp(dirname, ".") != 0); g_free(dirname); return hasdir; } /* Open a file. We take an optional fallback dir as well and will try opening * there if opening directly fails. * * This is used for things like finding ICC profiles. We try to open the file * directly first, and if that fails and the filename does not contain a * directory separator, we try looking in the fallback dir. */ FILE * vips__file_open_read(const char *filename, const char *fallback_dir, gboolean text_mode) { char *mode; FILE *fp; #if defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN) if (text_mode) mode = "rN"; else mode = "rbN"; #else /*!defined(G_PLATFORM_WIN32) && !defined(G_WITH_CYGWIN)*/ mode = "re"; #endif /*defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN)*/ if ((fp = vips__fopen(filename, mode))) return fp; if (fallback_dir && !filename_hasdir(filename)) { char *path; path = g_build_filename(fallback_dir, filename, NULL); fp = vips__fopen(path, mode); g_free(path); if (fp) return fp; } vips_error_system(errno, "vips__file_open_read", _("unable to open file \"%s\" for reading"), filename); return NULL; } FILE * vips__file_open_write(const char *filename, gboolean text_mode) { char *mode; FILE *fp; #if defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN) if (text_mode) mode = "wN"; else mode = "wbN"; #else /*!defined(G_PLATFORM_WIN32) && !defined(G_WITH_CYGWIN)*/ mode = "we"; #endif /*defined(G_PLATFORM_WIN32) || defined(G_WITH_CYGWIN)*/ if (!(fp = vips__fopen(filename, mode))) { vips_error_system(errno, "vips__file_open_write", _("unable to open file \"%s\" for writing"), filename); return NULL; } return fp; } /* Load up a file as a string. */ char * vips__file_read(FILE *fp, const char *filename, size_t *length_out) { gint64 len; size_t read; char *str; len = vips_file_length(fileno(fp)); if (len > 1024 * 1024 * 1024) { /* Over a gb? Seems crazy! */ vips_error("vips__file_read", _("\"%s\" too long"), filename); return NULL; } if (len == -1) { int size; /* Can't get length: read in chunks and g_realloc() to end of * file. */ str = NULL; len = 0; size = 0; do { /* Again, a 1gb sanity limit. */ size += 1024; if (size > 1024 * 1024 * 1024) { g_free(str); vips_error("vips__file_read", "%s", _("out of memory")); return NULL; } str = g_realloc(str, size); /* -1 to allow space for an extra NULL we add later. */ read = fread(str + len, sizeof(char), (size - len - 1) / sizeof(char), fp); len += read; } while (!feof(fp)); #ifdef DEBUG printf("read %ld bytes from unseekable stream\n", len); #endif /*DEBUG*/ } else { /* Allocate memory and fill. */ if (!(str = vips_malloc(NULL, len + 1))) return NULL; rewind(fp); read = fread(str, sizeof(char), (size_t) len, fp); if (read != (size_t) len) { g_free(str); vips_error("vips__file_read", _("error reading from file \"%s\""), filename); return NULL; } } str[len] = '\0'; if (length_out) *length_out = len; return str; } /* Load from a filename as a string. Used for things like reading in ICC * profiles, ie. binary objects. */ char * vips__file_read_name(const char *filename, const char *fallback_dir, size_t *length_out) { FILE *fp; char *buffer; if (!(fp = vips__file_open_read(filename, fallback_dir, FALSE))) return NULL; if (!(buffer = vips__file_read(fp, filename, length_out))) { fclose(fp); return NULL; } fclose(fp); return buffer; } /* Like fwrite(), but returns non-zero on error and sets error message. */ int vips__file_write(void *data, size_t size, size_t nmemb, FILE *stream) { size_t n; if (!data) return 0; if ((n = fwrite(data, size, nmemb, stream)) != nmemb) { vips_error_system(errno, "vips__file_write", _("write error (%zd out of %zd blocks written)"), n, nmemb); return -1; } return 0; } /* Read a few bytes from the start of a file. This is used for sniffing file * types, so we must read binary. * * Return the number of bytes actually read (the file might be shorter than * len), or -1 for error. */ gint64 vips__get_bytes(const char *filename, unsigned char buf[], gint64 len) { int fd; gint64 bytes_read; /* File may not even exist (for tmp images for example!) * so no hasty messages. And the file might be truncated, so no error * on read either. */ if ((fd = vips__open_read(filename)) == -1) return 0; bytes_read = read(fd, buf, len); close(fd); return bytes_read; } /* We try to support stupid DOS files too. These have \r\n (13, 10) as line * separators. Strategy: an fgetc() that swaps \r\n for \n. * * On Windows, stdio will automatically swap \r\n for \n, but on Linux we have * to do this by hand. */ int vips__fgetc(FILE *fp) { int ch; ch = fgetc(fp); if (ch == '\r') { ch = fgetc(fp); if (ch != '\n') { ungetc(ch, fp); ch = '\r'; } } return ch; } /* Alloc/free a GValue. */ static GValue * vips__gvalue_new(GType type) { GValue *value; value = g_new0(GValue, 1); g_value_init(value, type); return value; } static GValue * vips__gvalue_copy(GValue *value) { GValue *value_copy; value_copy = vips__gvalue_new(G_VALUE_TYPE(value)); g_value_copy(value, value_copy); return value_copy; } static void vips__gvalue_free(GValue *value, void *user_data) { g_value_unset(value); g_free(value); } GValue * vips__gvalue_ref_string_new(const char *text) { GValue *value; value = vips__gvalue_new(VIPS_TYPE_REF_STRING); vips_value_set_ref_string(value, text); return value; } /** * vips__gslist_gvalue_free: * @list: (element-type GValue): a [struct@GLib.SList] of GValue * * Free a GSList of GValue. */ void vips__gslist_gvalue_free(GSList *list) { g_slist_foreach(list, (GFunc) vips__gvalue_free, NULL); g_slist_free(list); } /** * vips__gslist_gvalue_copy: * @list: (element-type GValue): a [struct@GLib.SList] of GValue * * Copy a GSList of GValue. * * Returns: (element-type GValue) (transfer full): a copy of @list */ GSList * vips__gslist_gvalue_copy(const GSList *list) { GSList *copy; const GSList *p; copy = NULL; for (p = list; p; p = p->next) copy = g_slist_prepend(copy, vips__gvalue_copy((GValue *) p->data)); copy = g_slist_reverse(copy); return copy; } /** * vips__gslist_gvalue_merge: * @a: (element-type GValue): a [struct@GLib.SList] of GValue * @b: (element-type GValue): a [struct@GLib.SList] of GValue * * Merge two GSList of GValue ... append to a all elements in b which are not * in a. Works for any vips refcounted type (string, blob, etc.). * * Returns: (element-type GValue) (transfer full): the new value of @a */ GSList * vips__gslist_gvalue_merge(GSList *a, const GSList *b) { const GSList *i, *j; GSList *tail; tail = NULL; for (i = b; i; i = i->next) { GValue *value = (GValue *) i->data; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_REF_STRING); for (j = a; j; j = j->next) { GValue *value2 = (GValue *) j->data; g_assert(G_VALUE_TYPE(value2) == VIPS_TYPE_REF_STRING); /* Just do a pointer compare ... good enough 99.9% of * the time. */ if (vips_value_get_ref_string(value, NULL) == vips_value_get_ref_string(value2, NULL)) break; } if (!j) tail = g_slist_prepend(tail, vips__gvalue_copy(value)); } a = g_slist_concat(a, g_slist_reverse(tail)); return a; } /** * vips__gslist_gvalue_get: * @list: (element-type GValue): a [struct@GLib.SList] of GValue * * Make a char * from GSList of GValue. Each GValue should be a ref_string. * * If @list is empty, the return value will be `NULL`. * * Returns: (transfer full) (nullable): a newly-allocated string containing * all of the list elements joined together, with '\n' between them. */ char * vips__gslist_gvalue_get(const GSList *list) { const GSList *p; size_t length; char *all; char *q; /* Need to estimate length first. */ length = 0; for (p = list; p; p = p->next) { GValue *value = (GValue *) p->data; size_t l2; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_REF_STRING); /* +1 for the newline we will add for each item. */ (void) vips_value_get_ref_string(value, &l2); length += l2 + 1; } if (length == 0) return NULL; /* More than 10MB of history? Madness! */ g_assert(length < 10 * 1024 * 1024); /* +1 for '\0'. */ if (!(all = vips_malloc(NULL, length + 1))) return NULL; q = all; for (p = list; p; p = p->next) { GValue *value = (GValue *) p->data; size_t l2; strcpy(q, vips_value_get_ref_string(value, &l2)); q += l2; strcpy(q, "\n"); q += 1; } g_assert((size_t) (q - all) == length); return all; } gint64 vips__seek_no_error(int fd, gint64 pos, int whence) { gint64 new_pos; #ifdef G_OS_WIN32 new_pos = _lseeki64(fd, pos, whence); #else /*!G_OS_WIN32*/ /* On error, eg. opening a directory and seeking to the end, lseek() * on linux seems to return 9223372036854775807 ((1 << 63) - 1) * rather than (off_t) -1 for reasons I don't understand. */ new_pos = lseek(fd, pos, whence); #endif /*G_OS_WIN32*/ return new_pos; } /* Need our own seek(), since lseek() on win32 can't do long files. */ gint64 vips__seek(int fd, gint64 pos, int whence) { gint64 new_pos; if ((new_pos = vips__seek_no_error(fd, pos, whence)) == -1) { vips_error_system(errno, "vips__seek", "%s", _("unable to seek")); return -1; } return new_pos; } /* Need our own ftruncate(), since ftruncate() on win32 can't do long files. DANGER ... this moves the file pointer to the end of file on win32, but not on *nix; don't make any assumptions about the file pointer position after calling this */ int vips__ftruncate(int fd, gint64 pos) { #ifdef G_OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle(fd); if (vips__seek(fd, pos, SEEK_SET) == -1) return -1; if (!SetEndOfFile(hFile)) { vips_error_system(GetLastError(), "vips__ftruncate", "%s", _("unable to truncate")); return -1; } } #else /*!G_OS_WIN32*/ if (ftruncate(fd, pos)) { vips_error_system(errno, "vips__ftruncate", "%s", _("unable to truncate")); return -1; } #endif /*G_OS_WIN32*/ return 0; } /* TRUE if file exists. True for directories as well. */ gboolean vips_existsf(const char *name, ...) { va_list ap; char *path; gboolean result; va_start(ap, name); path = g_strdup_vprintf(name, ap); va_end(ap); result = g_file_test(path, G_FILE_TEST_EXISTS); g_free(path); return result; } /* TRUE if file exists and is a directory. */ gboolean vips_isdirf(const char *name, ...) { va_list ap; char *path; gboolean result; va_start(ap, name); path = g_strdup_vprintf(name, ap); va_end(ap); result = g_file_test(path, G_FILE_TEST_IS_DIR); g_free(path); return result; } /* Make a directory. */ int vips_mkdirf(const char *name, ...) { va_list ap; char *path; va_start(ap, name); path = g_strdup_vprintf(name, ap); va_end(ap); if (g_mkdir(path, 0755)) { vips_error("mkdirf", _("unable to create directory \"%s\", %s"), path, g_strerror(errno)); g_free(path); return -1; } g_free(path); return 0; } /* Remove a directory. */ int vips_rmdirf(const char *name, ...) { va_list ap; char *path; va_start(ap, name); path = g_strdup_vprintf(name, ap); va_end(ap); if (g_rmdir(path)) { vips_error("rmdir", _("unable to remove directory \"%s\", %s"), path, g_strerror(errno)); g_free(path); return -1; } g_free(path); return 0; } /* Rename a file. */ int vips_rename(const char *old_name, const char *new_name) { if (g_rename(old_name, new_name)) { vips_error("rename", _("unable to rename file \"%s\" as \"%s\", %s"), old_name, new_name, g_strerror(errno)); return -1; } return 0; } /* Break a command-line argument into tokens separated by whitespace. * * Strings can't be adjacent, so "hello world" (without quotes) is a single * string. Strings are written (with \" escaped) into @string. If the string * is larger than @size, it is silently null-terminated and truncated. * * Return NULL for end of tokens. */ const char * vips__token_get(const char *p, VipsToken *token, char *string, int size) { const char *q; int ch; int n; /* string return defaults to "". */ if (size > 0) string[0] = '\0'; /* Parse this token with p. */ if (!p) return NULL; /* Skip initial whitespace. */ p += strspn(p, " \t\n\r"); if (!p[0]) return NULL; switch ((ch = p[0])) { case '[': *token = VIPS_TOKEN_LEFT; p += 1; break; case ']': *token = VIPS_TOKEN_RIGHT; p += 1; break; case '=': *token = VIPS_TOKEN_EQUALS; p += 1; break; case ',': *token = VIPS_TOKEN_COMMA; p += 1; break; case '"': case '\'': /* Parse a quoted string. Copy up to " or end of string, interpret * any \", */ *token = VIPS_TOKEN_STRING; do { /* Move q to the next matching quote, or the end of the string. */ if (!(q = strchr(p + 1, ch))) q = p + strlen(p); // number of characters we copy to the output n = VIPS_MIN(q - p - 1, size - 1); g_strlcpy(string, p + 1, n + 1); /* We might have stopped at an escaped quote. If the * char before the end is a backslash, swap it for a quote. */ if (q[-1] == '\\') string[n - 1] = ch; string += n; size -= n; p = q; } while (p[0] && p[-1] == '\\'); // step over the terminating quote, if we hit one if (p[0] == ch) p += 1; break; default: /* It's an unquoted string: read up to the next non-string character. * We don't allow two strings next to each other, so the next break * must be brackets, equals, comma. */ *token = VIPS_TOKEN_STRING; q = p + strcspn(p, "[]=,"); n = VIPS_MIN(q - p, size); g_strlcpy(string, p, n + 1); p = q; /* We remove leading whitespace, so we trim trailing whitespace from * unquoted strings too. Only if the string hasn't been truncated. */ if (n != size) while (n > 0 && g_ascii_isspace(string[n - 1])) { string[n - 1] = '\0'; n--; } break; } return p; } /* We expect a token. */ const char * vips__token_must(const char *p, VipsToken *token, char *string, int size) { if (!(p = vips__token_get(p, token, string, size))) { vips_error("get_token", "%s", _("unexpected end of string")); return NULL; } return p; } /* We expect a certain token. */ const char * vips__token_need(const char *p, VipsToken need_token, char *string, int size) { VipsToken token; if (!(p = vips__token_must(p, &token, string, size))) return NULL; if (token != need_token) { vips_error("get_token", _("expected %s, saw %s"), vips_enum_nick(VIPS_TYPE_TOKEN, need_token), vips_enum_nick(VIPS_TYPE_TOKEN, token)); return NULL; } return p; } /* Fetch a token. If it's a string token terminated by a '[', fetch up to the * matching ']' as well, for example ".jpg[Q=90]". * * Return NULL for end of tokens. */ const char * vips__token_segment(const char *p, VipsToken *token, char *string, int size) { const char *q; if (!(q = vips__token_must(p, token, string, size))) return NULL; /* If we stopped on [, read up to the matching ]. */ if (*token == VIPS_TOKEN_STRING && q[0] == '[') { VipsToken sub_token; char sub_string[VIPS_PATH_MAX]; int depth; int i; depth = 0; do { if (!(q = vips__token_must(q, &sub_token, sub_string, VIPS_PATH_MAX))) return NULL; switch (sub_token) { case VIPS_TOKEN_LEFT: depth += 1; break; case VIPS_TOKEN_RIGHT: depth -= 1; break; default: break; } } while (!(sub_token == VIPS_TOKEN_RIGHT && depth == 0)); i = VIPS_MIN(q - p, size); g_strlcpy(string, p, i + 1); } return q; } /* We expect a certain segment. */ const char * vips__token_segment_need(const char *p, VipsToken need_token, char *string, int size) { VipsToken token; if (!(p = vips__token_segment(p, &token, string, size))) return NULL; if (token != need_token) { vips_error("get_token", _("expected %s, saw %s"), vips_enum_nick(VIPS_TYPE_TOKEN, need_token), vips_enum_nick(VIPS_TYPE_TOKEN, token)); return NULL; } return p; } /* Maximum number of tokens we allow in a filename. Surely this will be * plenty. */ #define MAX_TOKENS (1000) /* Find the start of the right-most pair of brackets in the string. * * A string can be of the form: * * "hello world! (no really).tif[fred=12]" * * we need to be able to find the fred=12 at the end. * * We lex the whole string noting the position of each token, then, if the * final token is a right-bracket, search left for the matching left-bracket. * * This can get confused if the lefts are hidden inside another token :-( But * a fixing that would require us to write a separate right-to-left lexer, * argh. */ const char * vips__find_rightmost_brackets(const char *p) { const char *start[MAX_TOKENS + 1]; VipsToken tokens[MAX_TOKENS]; char str[VIPS_PATH_MAX]; int n, i; int nest; start[0] = p; for (n = 0; n < MAX_TOKENS && (p = vips__token_get(start[n], &tokens[n], str, VIPS_PATH_MAX)); n++, start[n] = p) ; /* Too many tokens? */ if (n >= MAX_TOKENS) return NULL; /* No rightmost close bracket? */ if (n == 0 || tokens[n - 1] != VIPS_TOKEN_RIGHT) return NULL; nest = 0; for (i = n - 1; i >= 0; i--) { if (tokens[i] == VIPS_TOKEN_RIGHT) nest += 1; else if (tokens[i] == VIPS_TOKEN_LEFT) nest -= 1; if (nest == 0) break; } /* No matching left bracket? */ if (nest != 0) return NULL; /* This should be the matching left. */ return start[i]; } /* Split a vips8-style filename + options. * * filename and option_string must be VIPS_PATH_MAX in length. */ void vips__filename_split8(const char *name, char *filename, char *option_string) { char *p; g_strlcpy(filename, name, VIPS_PATH_MAX); if ((p = (char *) vips__find_rightmost_brackets(filename))) { g_strlcpy(option_string, p, VIPS_PATH_MAX); *p = '\0'; } else g_strlcpy(option_string, "", VIPS_PATH_MAX); } /* True if an int is a power of two ... 1, 2, 4, 8, 16, 32, etc. Do with just * integer arithmetic for portability. A previous Nicos version using doubles * and log/log failed on x86 with rounding problems. Return 0 for not * power of two, otherwise return the position of the set bit (numbering with * bit 1 as the lsb). */ int vips_ispoweroftwo(int p) { int i, n; /* Count set bits. Could use a LUT, I guess. */ for (i = 0, n = 0; p; i++, p >>= 1) if (p & 1) n++; /* Should be just one set bit. */ if (n == 1) /* Return position of bit. */ return i; else return 0; } /* Test this processor for endianness. True for SPARC order. */ int vips_amiMSBfirst(void) { #if G_BYTE_ORDER == G_BIG_ENDIAN return 1; #elif G_BYTE_ORDER == G_LITTLE_ENDIAN return 0; #else #error "Byte order not recognised" #endif } /* Return the tmp dir. On Windows, GetTempPathW() will also check the values of * TMP, TEMP and USERPROFILE. */ static const char * vips__temp_dir(void) { const char *tmpd; if (!(tmpd = g_getenv("TMPDIR"))) { #ifdef G_OS_WIN32 static char *tmp_dir = NULL; if (tmp_dir == NULL) { char *dir = NULL; wchar_t wdir[MAX_PATH]; if (GetTempPathW(G_N_ELEMENTS(wdir), wdir)) dir = g_utf16_to_utf8(wdir, -1, NULL, NULL, NULL); if (dir == NULL) dir = g_strdup("C:\\temp"); tmp_dir = g_steal_pointer(&dir); } tmpd = tmp_dir; #else /*!G_OS_WIN32*/ tmpd = "/tmp"; #endif /*!G_OS_WIN32*/ } return tmpd; } /* Make a temporary file name. The format parameter is something like "%s.jpg" * and will be expanded to something like "/tmp/vips-12-34587.jpg". * * You need to free the result. */ char * vips__temp_name(const char *format) { static int global_serial = 0; char file[FILENAME_MAX]; char file2[FILENAME_MAX]; char *name; int serial = g_atomic_int_add(&global_serial, 1); g_snprintf(file, FILENAME_MAX, "vips-%d-%u", serial, g_random_int()); g_snprintf(file2, FILENAME_MAX, format, file); name = g_build_filename(vips__temp_dir(), file2, NULL); /* We could use something like g_mkstemp() to guarantee uniqueness * across processes, but the extra FS calls can be difficult for * selinux. * * g_random_int() should be safe enough -- it's seeded from time(), so * it ought not to collide often -- and on linux at least we never * actually use these filenames in the filesystem anyway. */ return name; } /* Strip off any of a set of old suffixes (eg. [".v", ".jpg"]), add a single * new suffix (eg. ".tif"). */ void vips__change_suffix(const char *name, char *out, int mx, const char *new, const char **olds, int nolds) { char *p; int i; int len; /* Copy start string. */ g_strlcpy(out, name, mx); /* Drop all matching suffixes. */ while ((p = strrchr(out, '.'))) { /* Found suffix - test against list of alternatives. Ignore * case. */ for (i = 0; i < nolds; i++) if (g_ascii_strcasecmp(p, olds[i]) == 0) { *p = '\0'; break; } /* Found match? If not, break from loop. */ if (*p) break; } /* Add new suffix. */ len = strlen(out); g_strlcpy(out + len, new, mx - len); } typedef struct { const char unit; int multiplier; } Unit; guint64 vips__parse_size(const char *size_string) { static Unit units[] = { { 'k', 1024 }, { 'm', 1024 * 1024 }, { 'g', 1024 * 1024 * 1024 }, { 'b', 1024 * 1024 * 1024 } }; guint64 size; int n; char *unit; /* An easy way to alloc a buffer large enough. */ unit = g_strdup(size_string); size = 0; n = sscanf(size_string, "%" G_GUINT64_FORMAT " %s", &size, unit); if (n > 1) for (int j = 0; j < VIPS_NUMBER(units); j++) if (tolower(unit[0]) == units[j].unit) { size *= units[j].multiplier; break; } g_free(unit); VIPS_DEBUG_MSG("parse_size: parsed \"%s\" as %" G_GUINT64_FORMAT "\n", size_string, size); return size; } /* Look up the const char * for an enum value. */ const char * vips_enum_string(GType enm, int v) { GEnumValue *value; if (!(value = g_enum_get_value(g_type_class_ref(enm), v))) return "(null)"; return value->value_name; } const char * vips_enum_nick(GType enm, int v) { GEnumValue *value; if (!(value = g_enum_get_value(g_type_class_ref(enm), v))) return "(null)"; return value->value_nick; } int vips_enum_from_nick(const char *domain, GType type, const char *nick) { GTypeClass *class; GEnumClass *genum; GEnumValue *enum_value; int i; char str[1000]; VipsBuf buf = VIPS_BUF_STATIC(str); if (!(class = g_type_class_ref(type))) { vips_error(domain, "%s", _("no such enum type")); return -1; } genum = G_ENUM_CLASS(class); if ((enum_value = g_enum_get_value_by_name(genum, nick))) return enum_value->value; if ((enum_value = g_enum_get_value_by_nick(genum, nick))) return enum_value->value; /* Compat for "last" members. Assumes all enums define a `_LAST` value; * behaviour is undefined otherwise. Note that there could be potential * gaps in enum values (e.g. VipsInterpretation), so we cannot return * `genum->n_values` directly. */ if (nick && g_str_equal(nick, "last")) return genum->values[genum->n_values - 1].value + 1; for (i = 0; i < genum->n_values; i++) { if (i > 0) vips_buf_appends(&buf, ", "); vips_buf_appends(&buf, genum->values[i].value_nick); } vips_error(domain, _("enum '%s' has no member '%s', " "should be one of: %s"), g_type_name(type), nick, vips_buf_all(&buf)); return -1; } int vips_flags_from_nick(const char *domain, GType type, const char *nick) { GTypeClass *class; GFlagsClass *gflags; GFlagsValue *flags_value; int i; char *p, *q; char str[256]; if (!(class = g_type_class_ref(type))) { vips_error(domain, "%s", _("no such flag type")); return -1; } gflags = G_FLAGS_CLASS(class); /* Allow an integer as a value. */ if (sscanf(nick, "%d", &i) == 1) return i; /* It can be a list of nicks, in which case we OR the bits together. */ i = 0; g_strlcpy(str, nick, sizeof(str)); for (p = str; (q = vips_break_token(p, "\t;:|, ")); p = q) { if ((flags_value = g_flags_get_value_by_name(gflags, p)) || (flags_value = g_flags_get_value_by_nick(gflags, p))) i |= flags_value->value; else { vips_error(domain, _("flags '%s' has no member '%s'"), g_type_name(type), p); return -1; } } return i; } /* Scan @buf for the first "%ns" (eg. "%12s") and substitute the * lowest-numbered one for @sub. @buf is @len bytes in size. * * If there are no %ns, use the first %s. * * Set @c to the %s char we search for. */ int vips__substitutec(char *buf, size_t len, char c, char *sub) { size_t buflen = strlen(buf); size_t sublen = strlen(sub); int lowest_n; char *sub_start; char *p; char *sub_end; size_t before_len, marker_len, after_len, final_len; g_assert(buflen < len); lowest_n = -1; sub_start = NULL; sub_end = NULL; for (p = buf; (p = strchr(p, '%')); p++) if (g_ascii_isdigit(p[1])) { char *q; for (q = p + 1; g_ascii_isdigit(*q); q++) ; if (q[0] == c) { int n; n = atoi(p + 1); if (lowest_n == -1 || n < lowest_n) { lowest_n = n; sub_start = p; sub_end = q + 1; } } } if (!sub_start) for (p = buf; (p = strchr(p, '%')); p++) if (p[1] == c) { sub_start = p; sub_end = p + 2; break; } if (!sub_start) return -1; before_len = sub_start - buf; marker_len = sub_end - sub_start; after_len = buflen - (before_len + marker_len); final_len = before_len + sublen + after_len + 1; if (final_len > len) return -1; memmove(buf + before_len + sublen, buf + before_len + marker_len, after_len + 1); memmove(buf + before_len, sub, sublen); return 0; } int vips__substitute(char *buf, size_t len, char *sub) { return vips__substitutec(buf, len, 's', sub); } /* Absoluteize a path. Free the result with g_free(). */ char * vips_realpath(const char *path) { char *real; /* It'd be nice to use realpath here, but sadly that won't work on * linux systems with grsec, since it works by opening /proc/self/fd. */ if (!g_path_is_absolute(path)) { char *cwd; cwd = g_get_current_dir(); real = g_build_filename(cwd, path, NULL); g_free(cwd); } else real = g_strdup(path); return real; } /* A very simple random number generator. See: * http://isthe.com/chongo/tech/comp/fnv/#FNV-source */ guint32 vips__random_add(guint32 hash, int value) { #define FNV_ADD(HASH, VALUE8) (((HASH) ^ (VALUE8)) * 16777619u) hash = FNV_ADD(hash, value & 0xff); hash = FNV_ADD(hash, (value >> 8) & 0xff); hash = FNV_ADD(hash, (value >> 16) & 0xff); hash = FNV_ADD(hash, (value >> 24) & 0xff); return hash; } guint32 vips__random(guint32 seed) { guint32 hash; hash = 2166136261u; hash = vips__random_add(hash, seed); return hash; } static void * vips_icc_dir_once(void *null) { #ifdef G_OS_WIN32 /* From glib get_windows_directory_root() */ wchar_t wwindowsdir[MAX_PATH]; if (GetWindowsDirectoryW(wwindowsdir, G_N_ELEMENTS(wwindowsdir))) { /* Usually X:\Windows, but in terminal server environments * might be an UNC path, AFAIK. */ char *windowsdir; if ((windowsdir = g_utf16_to_utf8(wwindowsdir, -1, NULL, NULL, NULL))) { gchar *full_path; full_path = g_build_filename(windowsdir, "system32", "spool", "drivers", "color", NULL); g_free(windowsdir); return (void *) full_path; } } #endif /*G_OS_WIN32*/ return (void *) VIPS_ICC_DIR; } const char * vips__icc_dir(void) { static GOnce once = G_ONCE_INIT; return (const char *) g_once(&once, vips_icc_dir_once, NULL); } #ifdef G_OS_WIN32 static HMODULE vips__dll = NULL; #ifdef DLL_EXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) vips__dll = hinstDLL; return TRUE; } #endif #endif /*G_OS_WIN32*/ static void * vips__windows_prefix_once(void *null) { char *prefix; #ifdef G_OS_WIN32 prefix = g_win32_get_package_installation_directory_of_module(vips__dll); #else /*!G_OS_WIN32*/ prefix = (char *) g_getenv("VIPSHOME"); #endif /*G_OS_WIN32*/ return (void *) prefix; } const char * vips__windows_prefix(void) { static GOnce once = G_ONCE_INIT; return (const char *) g_once(&once, vips__windows_prefix_once, NULL); } char * vips__get_iso8601(void) { char *date; #if GLIB_CHECK_VERSION(2, 62, 0) { GDateTime *now; now = g_date_time_new_now_local(); date = g_date_time_format_iso8601(now); g_date_time_unref(now); } #else /*!GLIB_CHECK_VERSION(2, 62, 0)*/ { GTimeVal now; g_get_current_time(&now); date = g_time_val_to_iso8601(&now); } #endif /*GLIB_CHECK_VERSION(2, 62, 0)*/ return date; } /* Convert a string to a double in the ASCII locale (ie. decimal point is * "."). */ int vips_strtod(const char *str, double *out) { const char *p; *out = 0; /* The str we fetched must contain at least 1 digit. This * helps stop us trying to convert "MATLAB" (for example) to * a number and getting zero. */ for (p = str; *p; p++) if (g_ascii_isdigit(*p)) break; if (!*p) return -1; /* This will fail for out of range numbers, like 1e343434, but * is quite happy with eg. "banana". */ *out = g_ascii_strtod(str, NULL); if (errno) return -1; return 0; } libvips-8.18.2/libvips/iofuncs/vector.cpp000066400000000000000000000102531516303661500204150ustar00rootroot00000000000000/* helper functions for Highway * * 29/07/21 kleisauke * - from vector.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include /* If we are building with -fcf-protection (run-time checking of * indirect jumps) then Orc won't work. Make sure it's off. * * https://gcc.gnu.org/onlinedocs/gcc/\ * Instrumentation-Options.html#index-fcf-protection * https://gitlab.freedesktop.org/gstreamer/orc/issues/17 * * orc 0.4.30 and later work with cf-protection. */ #ifdef __CET__ #ifndef HAVE_ORC_CF_PROTECTION #undef HAVE_ORC #endif #endif #ifdef HAVE_HWY #include #elif defined(HAVE_ORC) #include #endif /*HAVE_HWY*/ /* Cleared by the command-line `--vips-novector` switch and the * `VIPS_NOVECTOR` env var. */ gboolean vips__vector_enabled = TRUE; void vips__vector_init() { #ifdef HAVE_ORC orc_init(); #endif /*HAVE_ORC*/ /* Check whether any features are being disabled by the environment. */ const char *env; if ((env = g_getenv("VIPS_VECTOR"))) return vips_vector_disable_targets( g_ascii_strtoll(env, nullptr, 0)); /* Look for the deprecated IM_NOVECTOR environment variable as well. */ if (g_getenv("VIPS_NOVECTOR") #ifdef ENABLE_DEPRECATED || g_getenv("IM_NOVECTOR") #endif ) vips__vector_enabled = FALSE; } gboolean vips_vector_isenabled() { #ifdef HAVE_HWY return vips__vector_enabled && vips_vector_get_supported_targets() != 0; #elif defined(HAVE_ORC) return vips__vector_enabled; #else return FALSE; #endif } void vips_vector_set_enabled(gboolean enabled) { vips__vector_enabled = enabled; } /** * vips_vector_get_builtin_targets: * * Gets a bitfield of builtin targets that libvips was built with. * * Returns: a bitfield of builtin targets. */ gint64 vips_vector_get_builtin_targets() { #ifdef HAVE_HWY return HWY_TARGETS; #else return 0; #endif } /** * vips_vector_get_supported_targets: * * Gets a bitfield of builtin targets that are supported on this CPU. The * targets returned may change after calling [func@vector_disable_targets]. * * Returns: a bitfield of supported CPU targets. */ gint64 vips_vector_get_supported_targets() { #ifdef HAVE_HWY return hwy::SupportedTargets() & HWY_TARGETS & ~(HWY_EMU128 | HWY_SCALAR); #elif defined(HAVE_ORC) return orc_target_get_default_flags(orc_target_get_default()); #else return 0; #endif } /** * vips_vector_target_name: * @target: A specific target to describe. * * Generates a human-readable ASCII string descriptor for a specific target. * * Returns: a string describing the target. */ const char * vips_vector_target_name(gint64 target) { #ifdef HAVE_HWY return hwy::TargetName(target); #elif defined(HAVE_ORC) return orc_target_get_flag_name(orc_target_get_default(), log2(target)); #else return NULL; #endif } /** * vips_vector_disable_targets: * @disabled_targets: A bitfield of targets to disable at runtime. * * Takes a bitfield of targets to disable on the runtime platform. * Handy for testing and benchmarking purposes. * * This can also be set using the `VIPS_VECTOR` environment variable. */ void vips_vector_disable_targets(gint64 disabled_targets) { #ifdef HAVE_HWY hwy::SetSupportedTargetsForTest( vips_vector_get_supported_targets() & ~disabled_targets); #endif } libvips-8.18.2/libvips/iofuncs/vips.c000066400000000000000000000614711516303661500175440ustar00rootroot00000000000000/* Read and write a vips file. * * 22/5/08 * - from im_open.c, im_openin.c, im_desc_hd.c, im_readhist.c, * im_openout.c * 19/3/09 * - block mmaps of nodata images * 12/5/09 * - fix signed/unsigned warnings * 12/10/09 * - heh argh reading history always stopped after the first line * 9/12/09 * - only wholly map input files on im_incheck() ... this reduces VM use, * especially with large numbers of small files * 14/2/11 * - renamed to vips.c from im_open_vips.c, some stuff chopped out for * image.c ... this file now just does read / write to disc * 28/3/11 * - moved to vips_ namespace * 25/2/17 * - use expat for xml read, printf for xml write * 16/8/17 * - validate strs as being utf-8 before we write * 9/4/18 Alexander-- * - use O_TMPFILE, if available * 23/7/18 * - escape ASCII control characters in XML * 29/8/19 * - verify bands/format for coded images */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define SHOW_HEADER #define DEBUG */ /* Enable linux extensions like O_TMPFILE, if available. */ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_FILE_H #include #endif /*HAVE_SYS_FILE_H*/ #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #ifdef HAVE_IO_H #include #endif /*HAVE_IO_H*/ #include #include #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ #include #include /* Open mode for image write. * * We use O_RDWR not O_WRONLY since after writing we may want to rewind the * image and read from it. */ #define MODE_WRITE CLOEXEC(BINARYIZE(O_RDWR | O_CREAT | O_TRUNC)) /* Mode for read/write. This is if we might later want to mmaprw () the file. */ #define MODE_READWRITE CLOEXEC(BINARYIZE(O_RDWR)) /* Mode for read only. This is the fallback if READWRITE fails. */ #define MODE_READONLY CLOEXEC(BINARYIZE(O_RDONLY)) /* Our XML namespace. */ #define NAMESPACE_URI "http://www.vips.ecs.soton.ac.uk/" /* Open for read for image files. */ int vips__open_image_read(const char *filename) { int fd; /* Try to open read-write, so that calls to vips_image_inplace() will * work. When we later mmap this file, we set read-only, so there * is little danger of scrubbing over files we own. */ fd = vips_tracked_open(filename, MODE_READWRITE, 0); if (fd == -1) /* Open read-write failed. Fall back to open read-only. */ fd = vips_tracked_open(filename, MODE_READONLY, 0); if (fd == -1) { vips_error_system(errno, "VipsImage", _("unable to open \"%s\""), filename); return -1; } return fd; } /* Open for write for image files. */ int vips__open_image_write(const char *filename, gboolean temp) { int flags; int fd; fd = -1; #ifndef O_TMPFILE if (temp) g_info("vips__open_image_write: O_TMPFILE not available"); #endif /*!O_TMPFILE*/ #ifdef O_TMPFILE /* Linux-only extension creates an unlinked file. CREAT and TRUNC must * be clear. The filename arg to open() must name a directory. * * This can fail since not all filesystems support it. In this case, * we open as a regular file and rely on the delete-on-close * mechanism, see vips_image_delete(). */ if (temp) { char *dirname; g_info("vips__open_image_write: opening with O_TMPFILE"); dirname = g_path_get_dirname(filename); fd = vips_tracked_open(dirname, O_TMPFILE | O_RDWR, 0644); if (fd < 0) g_info("vips__open_image_write: O_TMPFILE failed!"); g_free(dirname); } #endif /*O_TMPFILE*/ flags = MODE_WRITE; #ifdef _O_TEMPORARY /* On Windows, setting _O_TEMPORARY will delete the file automatically * on process exit, even if the processes crashes. */ if (temp) { g_info("vips__open_image_write: setting _O_TEMPORARY"); flags |= _O_TEMPORARY; } #endif /*_O_TEMPORARY*/ if (fd < 0) { g_info("vips__open_image_write: simple open"); fd = vips_tracked_open(filename, flags, 0644); } if (fd < 0) { g_info("vips__open_image_write: failed!"); vips_error_system(errno, "VipsImage", _("unable to write to \"%s\""), filename); return -1; } return fd; } /* Predict the size of the header plus pixel data. Don't use off_t, * it's sometimes only 32 bits (eg. on many windows build environments) and we * want to always be 64 bit. */ static gint64 image_pixel_length(VipsImage *image) { gint64 psize; switch (image->Coding) { case VIPS_CODING_LABQ: case VIPS_CODING_RAD: case VIPS_CODING_NONE: psize = VIPS_IMAGE_SIZEOF_IMAGE(image); break; default: psize = image->Length; break; } return psize + image->sizeof_header; } /* Copy 2 and 4 bytes, optionally swapping byte order. */ void vips__copy_4byte(int swap, unsigned char *to, unsigned char *from) { guint32 *in = (guint32 *) from; guint32 *out = (guint32 *) to; if (swap) *out = GUINT32_SWAP_LE_BE(*in); else *out = *in; } void vips__copy_2byte(gboolean swap, unsigned char *to, unsigned char *from) { guint16 *in = (guint16 *) from; guint16 *out = (guint16 *) to; if (swap) *out = GUINT16_SWAP_LE_BE(*in); else *out = *in; } guint32 vips__file_magic(const char *filename) { guint32 magic; if (vips__get_bytes(filename, (unsigned char *) &magic, 4) == 4 && (magic == VIPS_MAGIC_INTEL || magic == VIPS_MAGIC_SPARC)) return magic; return 0; } /* offset, read, write functions. */ typedef struct _FieldIO { glong offset; int size; void (*copy)(gboolean swap, unsigned char *to, unsigned char *from); } FieldIO; static FieldIO fields[] = { { G_STRUCT_OFFSET(VipsImage, Xsize), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Ysize), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Bands), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Bbits), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, BandFmt), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Coding), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Type), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Xres_float), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Yres_float), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Length), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Compression), 2, vips__copy_2byte }, { G_STRUCT_OFFSET(VipsImage, Level), 2, vips__copy_2byte }, { G_STRUCT_OFFSET(VipsImage, Xoffset), 4, vips__copy_4byte }, { G_STRUCT_OFFSET(VipsImage, Yoffset), 4, vips__copy_4byte } }; int vips__read_header_bytes(VipsImage *im, unsigned char *from) { gboolean swap; int i; GEnumValue *value; #ifdef SHOW_HEADER printf("vips__read_header_bytes: file bytes:\n"); for (i = 0; i < im->sizeof_header; i++) printf("%2d - 0x%02x\n", i, from[i]); #endif /*SHOW_HEADER*/ /* The magic number is always written MSB first, we may need to swap. */ vips__copy_4byte(!vips_amiMSBfirst(), (unsigned char *) &im->magic, from); from += 4; if (im->magic != VIPS_MAGIC_INTEL && im->magic != VIPS_MAGIC_SPARC) { vips_error("VipsImage", _("\"%s\" is not a VIPS image"), im->filename); return -1; } /* We need to swap for other fields if the file byte order is * different from ours. */ swap = vips_amiMSBfirst() != vips_image_isMSBfirst(im); for (i = 0; i < VIPS_NUMBER(fields); i++) { fields[i].copy(swap, &G_STRUCT_MEMBER(unsigned char, im, fields[i].offset), from); from += fields[i].size; } /* Set this ourselves ... bbits is deprecated in the file format. */ im->Bbits = vips_format_sizeof(im->BandFmt) << 3; /* We read xres/yres as floats to a staging area, then copy to double * in the main fields. */ im->Xres = VIPS_MAX(0, im->Xres_float); im->Yres = VIPS_MAX(0, im->Yres_float); /* Some protection against malicious files. We also check predicted * (based on these values) against real file length, see below. */ im->Xsize = VIPS_CLIP(1, im->Xsize, VIPS_MAX_COORD); im->Ysize = VIPS_CLIP(1, im->Ysize, VIPS_MAX_COORD); im->Bands = VIPS_CLIP(1, im->Bands, VIPS_MAX_COORD); im->BandFmt = VIPS_CLIP(0, im->BandFmt, VIPS_FORMAT_LAST - 1); /* Coding and Type have missing values, so we look up in the enum. */ value = g_enum_get_value(g_type_class_ref(VIPS_TYPE_INTERPRETATION), im->Type); if (!value) im->Type = VIPS_INTERPRETATION_ERROR; value = g_enum_get_value(g_type_class_ref(VIPS_TYPE_CODING), im->Coding); if (!value) im->Coding = VIPS_CODING_ERROR; /* Offset, Res, etc. don't affect vips file layout, just * pixel interpretation, don't clip them. */ /* Coding values imply Bands and BandFmt settings -- make sure they * are sane. */ switch (im->Coding) { case VIPS_CODING_ERROR: vips_error("VipsImage", "%s", _("unknown coding")); return -1; case VIPS_CODING_NONE: break; case VIPS_CODING_LABQ: if (im->Bands != 4 || im->BandFmt != VIPS_FORMAT_UCHAR) { vips_error("VipsImage", "%s", _("malformed LABQ image")); return -1; } break; case VIPS_CODING_RAD: if (im->Bands != 4 || im->BandFmt != VIPS_FORMAT_UCHAR) { vips_error("VipsImage", "%s", _("malformed RAD image")); return -1; } break; default: g_assert_not_reached(); break; } return 0; } int vips__write_header_bytes(VipsImage *im, unsigned char *to) { /* Swap if the byte order we are asked to write the header in is * different from ours. */ gboolean swap = vips_amiMSBfirst() != vips_image_isMSBfirst(im); int i; unsigned char *q; /* We set xres/yres as floats in a staging area, then copy those * smaller values to the file. */ im->Xres_float = im->Xres; im->Yres_float = im->Yres; /* Always write the magic number MSB first. */ vips__copy_4byte(!vips_amiMSBfirst(), to, (unsigned char *) &im->magic); q = to + 4; for (i = 0; i < VIPS_NUMBER(fields); i++) { fields[i].copy(swap, q, &G_STRUCT_MEMBER(unsigned char, im, fields[i].offset)); q += fields[i].size; } /* Pad spares with zeros. */ while (q - to < im->sizeof_header) *q++ = 0; #ifdef SHOW_HEADER printf("vips__write_header_bytes: file bytes:\n"); for (i = 0; i < im->sizeof_header; i++) printf("%2d - 0x%02x\n", i, to[i]); #endif /*SHOW_HEADER*/ return 0; } /* Read a chunk of an fd into memory. Add a '\0' at the end. */ static char * read_chunk(int fd, gint64 offset, size_t length) { char *buf; if (vips__seek(fd, offset, SEEK_SET) == -1) return NULL; if (!(buf = vips_malloc(NULL, length + 1))) return NULL; if (read(fd, buf, length) != (gssize) length) { g_free(buf); vips_error("VipsImage", "%s", _("unable to read history")); return NULL; } buf[length] = '\0'; return buf; } /* Does it look like an image has an extension block? */ int vips__has_extension_block(VipsImage *im) { gint64 psize; psize = image_pixel_length(im); g_assert(im->file_length > 0); return im->file_length - psize > 0; } /* Read everything after the pixels into memory. */ void * vips__read_extension_block(VipsImage *im, size_t *size) { gint64 psize; void *buf; psize = image_pixel_length(im); g_assert(im->file_length > 0); if (im->file_length - psize > 100 * 1024 * 1024) { vips_error("VipsImage", "%s", _("more than 100 megabytes of XML? sufferin' succotash!")); return NULL; } if (im->file_length - psize == 0) return NULL; if (!(buf = read_chunk(im->fd, psize, im->file_length - psize))) return NULL; if (size) *size = im->file_length - psize; #ifdef DEBUG printf("vips__read_extension_block: read %d bytes from %s\n", (int) (im->file_length - psize), im->filename); printf("data: \"%s\"\n", (char *) buf); #endif /*DEBUG*/ return buf; } static int parser_read_fd(XML_Parser parser, int fd) { const int chunk_size = 1024; gint64 bytes_read; gint64 len; bytes_read = 0; do { void *buf; if (!(buf = XML_GetBuffer(parser, chunk_size))) { vips_error("VipsImage", "%s", _("unable to allocate read buffer")); return -1; } len = read(fd, buf, chunk_size); if (len == -1) { vips_error("VipsImage", "%s", _("read error while fetching XML")); return -1; } /* Allow missing XML block. */ if (bytes_read == 0 && len == 0) break; bytes_read += len; if (!XML_ParseBuffer(parser, len, len == 0)) { vips_error("VipsImage", "%s", _("XML parse error")); return -1; } } while (len > 0); return 0; } #define MAX_PARSE_ATTR (256) /* What we track during expat parse. */ typedef struct _VipsExpatParse { VipsImage *image; /* Set on error. */ gboolean error; /* TRUE for in header section. */ gboolean header; /* For the current node, the type and name. */ XML_Char type[MAX_PARSE_ATTR]; XML_Char name[MAX_PARSE_ATTR]; /* Accumulate data here. */ VipsDbuf dbuf; } VipsExpatParse; static void parser_element_start_handler(void *user_data, const XML_Char *name, const XML_Char **atts) { VipsExpatParse *vep = (VipsExpatParse *) user_data; const XML_Char **p; #ifdef DEBUG printf("parser_element_start: %s\n", name); for (p = atts; *p; p += 2) printf("%s = %s\n", p[0], p[1]); #endif /*DEBUG*/ if (strcmp(name, "field") == 0) { for (p = atts; *p; p += 2) { if (strcmp(p[0], "name") == 0) g_strlcpy(vep->name, p[1], MAX_PARSE_ATTR); if (strcmp(p[0], "type") == 0) g_strlcpy(vep->type, p[1], MAX_PARSE_ATTR); } vips_dbuf_reset(&vep->dbuf); } else if (strcmp(name, "header") == 0) vep->header = TRUE; else if (strcmp(name, "meta") == 0) vep->header = FALSE; else if (strcmp(name, "root") == 0) { for (p = atts; *p; p += 2) if (strcmp(p[0], "xmlns") == 0 && !vips_isprefix(NAMESPACE_URI "vips", p[1])) { vips_error("VipsImage", "%s", _("incorrect namespace in XML")); vep->error = TRUE; } } } /* Chop history into lines, add each one as a refstring. */ static void set_history(VipsImage *im, char *history) { GSList *history_list; char *p, *q; /* There can be history there already if we're rewinding. */ VIPS_FREEF(vips__gslist_gvalue_free, im->history_list); history_list = NULL; for (p = history; *p; p = q) { if ((q = strchr(p, '\n'))) { *q = '\0'; q += 1; } else q = p + strlen(p); history_list = g_slist_prepend(history_list, vips__gvalue_ref_string_new(p)); } im->history_list = g_slist_reverse(history_list); } static int set_meta(VipsImage *image, GType gtype, const char *name, const char *data) { GValue save_value = G_VALUE_INIT; GValue value = G_VALUE_INIT; g_value_init(&save_value, VIPS_TYPE_SAVE_STRING); vips_value_set_save_string(&save_value, data); g_value_init(&value, gtype); if (!g_value_transform(&save_value, &value)) { g_value_unset(&save_value); vips_error("VipsImage", "%s", _("error transforming from save format")); return -1; } vips_image_set(image, name, &value); g_value_unset(&save_value); g_value_unset(&value); return 0; } static void parser_element_end_handler(void *user_data, const XML_Char *name) { VipsExpatParse *vep = (VipsExpatParse *) user_data; #ifdef DEBUG printf("parser_element_end_handler: %s\n", name); #endif /*DEBUG*/ if (strcmp(name, "field") == 0) { if (vep->header) { if (strcmp(name, "Hist") == 0) set_history(vep->image, (char *) vips_dbuf_string(&vep->dbuf, NULL)); } else { GType gtype = g_type_from_name(vep->type); /* Can we convert from VIPS_SAVE_STRING to type? */ if (gtype && g_value_type_transformable( VIPS_TYPE_SAVE_STRING, gtype) && set_meta(vep->image, gtype, vep->name, (char *) vips_dbuf_string(&vep->dbuf, NULL))) vep->error = TRUE; } } } static void parser_data_handler(void *user_data, const XML_Char *data, int len) { VipsExpatParse *vep = (VipsExpatParse *) user_data; #ifdef DEBUG printf("parser_data_handler: %d bytes\n", len); #endif /*DEBUG*/ vips_dbuf_write(&vep->dbuf, (unsigned char *) data, len); } /* Called at the end of vips open ... get any XML after the pixel data * and read it in. */ static int readhist(VipsImage *im) { VipsExpatParse vep = { 0 }; XML_Parser parser; if (vips__seek(im->fd, image_pixel_length(im), SEEK_SET) == -1) return -1; parser = XML_ParserCreate("UTF-8"); vep.image = im; XML_SetUserData(parser, &vep); XML_SetElementHandler(parser, parser_element_start_handler, parser_element_end_handler); XML_SetCharacterDataHandler(parser, parser_data_handler); if (parser_read_fd(parser, im->fd) || vep.error) { vips_dbuf_destroy(&vep.dbuf); XML_ParserFree(parser); return -1; } vips_dbuf_destroy(&vep.dbuf); XML_ParserFree(parser); return 0; } int vips__write_extension_block(VipsImage *im, void *buf, size_t size) { gint64 length; gint64 psize; psize = image_pixel_length(im); if ((length = vips_file_length(im->fd)) == -1) return -1; if (length < psize) { vips_error("VipsImage", "%s", _("file has been truncated")); return -1; } if (vips__ftruncate(im->fd, psize) || vips__seek(im->fd, psize, SEEK_SET) == -1) return -1; if (vips__write(im->fd, buf, size)) return -1; #ifdef DEBUG printf("vips__write_extension_block: written %zd bytes of XML to %s\n", size, im->filename); #endif /*DEBUG*/ return 0; } /* Append a string to a buffer, but escape " as \". */ static void target_write_quotes(VipsTarget *target, const char *str) { const char *p; size_t len; for (p = str; *p; p += len) { len = strcspn(p, "\""); vips_target_write(target, (unsigned char *) p, len); if (p[len] == '"') vips_target_writes(target, "\\"); } } static void * build_xml_meta(VipsMeta *meta, VipsTarget *target, void *b) { GType type = G_VALUE_TYPE(&meta->value); char *str; /* If we can transform to VIPS_TYPE_SAVE_STRING and back, we can save * and restore. */ if (g_value_type_transformable(type, VIPS_TYPE_SAVE_STRING) && g_value_type_transformable(VIPS_TYPE_SAVE_STRING, type)) { GValue save_value = G_VALUE_INIT; g_value_init(&save_value, VIPS_TYPE_SAVE_STRING); if (!g_value_transform(&meta->value, &save_value)) { vips_error("VipsImage", "%s", _("error transforming to save format")); return meta; } /* We need to validate the str to make sure we'll be able to * read it back. */ str = g_utf8_make_valid(vips_value_get_save_string(&save_value), -1); if (str) { vips_target_writef(target, " name); vips_target_writes(target, "\">"); vips_target_write_amp(target, str); vips_target_writes(target, "\n"); g_free(str); } g_value_unset(&save_value); } return NULL; } /* Make the xml we append to vips images after the pixel data. */ static char * build_xml(VipsImage *image) { VipsTarget *target; const char *str; char *result; target = vips_target_new_to_memory(); vips_target_writef(target, "\n"); vips_target_writef(target, "\n", NAMESPACE_URI, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION); vips_target_writef(target, "
\n"); str = vips_image_get_history(image); if (g_utf8_validate(str, -1, NULL)) { vips_target_writef(target, " ", g_type_name(VIPS_TYPE_REF_STRING)); vips_target_write_amp(target, str); vips_target_writef(target, "\n"); } vips_target_writef(target, "
\n"); vips_target_writef(target, " \n"); if (vips_slist_map2(image->meta_traverse, (VipsSListMap2Fn) build_xml_meta, target, NULL)) { VIPS_UNREF(target); return NULL; } vips_target_writef(target, " \n"); vips_target_writef(target, "
\n"); result = vips_target_steal_text(target); VIPS_UNREF(target); return result; } static void * vips__xml_properties_meta(VipsImage *image, const char *field, GValue *value, void *a) { VipsTarget *target = (VipsTarget *) a; GType type = G_VALUE_TYPE(value); const char *str; /* If we can transform to VIPS_TYPE_SAVE_STRING and back, we can save * and restore. */ if (g_value_type_transformable(type, VIPS_TYPE_SAVE_STRING) && g_value_type_transformable(VIPS_TYPE_SAVE_STRING, type)) { GValue save_value = G_VALUE_INIT; g_value_init(&save_value, VIPS_TYPE_SAVE_STRING); if (!g_value_transform(value, &save_value)) { vips_error("VipsImage", "%s", _("error transforming to save format")); return target; } str = vips_value_get_save_string(&save_value); vips_target_writef(target, " \n"); vips_target_writef(target, " "); vips_target_write_amp(target, field); vips_target_writef(target, "\n"); vips_target_writef(target, " ", g_type_name(type)); vips_target_write_amp(target, str); vips_target_writef(target, "\n"); vips_target_writef(target, " \n"); g_value_unset(&save_value); } return NULL; } /* Make the xml we write to vips-properties in dzsave, or to TIFF. A simple * dump of all vips metadata. Free with g_free(). */ char * vips__xml_properties(VipsImage *image) { VipsTarget *target; char *date; char *result; date = vips__get_iso8601(); target = vips_target_new_to_memory(); vips_target_writef(target, "\n"); vips_target_writef(target, "\n", NAMESPACE_URI, date, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION); vips_target_writef(target, " \n"); g_free(date); if (vips_image_map(image, vips__xml_properties_meta, target)) { VIPS_UNREF(target); return NULL; } vips_target_writef(target, " \n"); vips_target_writef(target, "\n"); result = vips_target_steal_text(target); VIPS_UNREF(target); return result; } /* Append XML to output fd. */ int vips__writehist(VipsImage *image) { char *xml; assert(image->dtype == VIPS_IMAGE_OPENOUT); assert(image->fd != -1); if (!(xml = build_xml(image))) return -1; if (vips__write_extension_block(image, xml, strlen(xml))) { g_free(xml); return -1; } #ifdef DEBUG printf("vips__writehist: saved XML is: \"%s\"\n", xml); #endif /*DEBUG*/ g_free(xml); return 0; } /* Open the filename, read the header, some sanity checking. */ int vips_image_open_input(VipsImage *image) { /* We don't use im->sizeof_header here, but we know we're reading a * VIPS image anyway. */ unsigned char header[VIPS_SIZEOF_HEADER]; gint64 psize; gint64 rsize; image->dtype = VIPS_IMAGE_OPENIN; /* We may have an fd already, see vips_image_rewind_output(). */ if (image->fd == -1) { image->fd = vips__open_image_read(image->filename); if (image->fd == -1) return -1; } vips__seek(image->fd, 0, SEEK_SET); if (read(image->fd, header, VIPS_SIZEOF_HEADER) != VIPS_SIZEOF_HEADER || vips__read_header_bytes(image, header)) { vips_error_system(errno, "VipsImage", _("unable to read header for \"%s\""), image->filename); return -1; } /* Predict and check the file size. Only issue a warning, we want to be * able to read all the header fields we can, even if the actual data * isn't there. */ psize = image_pixel_length(image); if ((rsize = vips_file_length(image->fd)) == -1) return -1; image->file_length = rsize; if (psize > rsize) g_warning("unable to read data for \"%s\", %s", image->filename, "file has been truncated"); /* Set demand style. This suits a disc file we read sequentially. */ image->dhint = VIPS_DEMAND_STYLE_THINSTRIP; /* Set the history part of im descriptor. Don't return an error if this * fails (due to eg. corrupted XML) because it's probably mostly * harmless. */ if (readhist(image)) { g_warning("error reading vips image metadata: %s", vips_error_buffer()); vips_error_clear(); } return 0; } int vips_image_open_output(VipsImage *image) { if (image->fd == -1) { /* Don't use im->sizeof_header here, but we know we're * writing a VIPS image anyway. */ unsigned char header[VIPS_SIZEOF_HEADER]; if ((image->fd = vips__open_image_write(image->filename, image->delete_on_close)) < 0) return -1; /* We always write in native mode, so we must overwrite the * magic we read from the file originally. */ image->magic = vips_amiMSBfirst() ? VIPS_MAGIC_SPARC : VIPS_MAGIC_INTEL; if (vips__write_header_bytes(image, header) || vips__write(image->fd, header, VIPS_SIZEOF_HEADER)) return -1; } return 0; } libvips-8.18.2/libvips/iofuncs/vipsmarshal.list000066400000000000000000000024071516303661500216370ustar00rootroot00000000000000# see glib-genmarshal(1) for a detailed description of the file format, # possible parameter types are: # VOID indicates no return type, or no extra # parameters. if VOID is used as the parameter # list, no additional parameters may be present. # BOOLEAN for boolean types (gboolean) # CHAR for signed char types (gchar) # UCHAR for unsigned char types (guchar) # INT for signed integer types (gint) # UINT for unsigned integer types (guint) # LONG for signed long integer types (glong) # ULONG for unsigned long integer types (gulong) # ENUM for enumeration types (gint) # FLAGS for flag enumeration types (guint) # FLOAT for single-precision float types (gfloat) # DOUBLE for double-precision float types (gdouble) # STRING for string types (gchar*) # BOXED for boxed (anonymous but reference counted) types (GBoxed*) # POINTER for anonymous pointer types (gpointer) # PARAM for GParamSpec or derived types (GParamSpec*) # OBJECT for GObject or derived types (GObject*) # NONE deprecated alias for VOID # BOOL deprecated alias for BOOLEAN INT: VOID INT64: INT64, INT INT64: POINTER, INT64 libvips-8.18.2/libvips/iofuncs/window.c000066400000000000000000000221071516303661500200630ustar00rootroot00000000000000/* Manage sets of mmap buffers on an image. * * 30/10/06 * - from region.c * 19/3/09 * - block mmaps of nodata images * 6/7/25 * - use much larger mmap windows to limit scrolling */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_TOTAL #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #ifdef HAVE_SYS_MMAN_H #include #endif #include #include #ifdef G_OS_WIN32 #include #endif /*G_OS_WIN32*/ /* Sanity checking ... write to this during read tests to make sure we don't * get optimized out. */ int vips__read_test; /* The window size we aim for. * * Large enough to hold the needed pixels, then expanded up to this size. 10MB * on a 32-bit machine (since VMEM is limited), 10gb on a 64-bit machine (since * the VMEM limit will be extremely large). */ static gint64 vips__window_bytes = (gint64) 1024 * 1024 * (sizeof(size_t) > 4 ? 10000 : 10); /* Track global mmap usage. */ #ifdef DEBUG_TOTAL static int total_mmap_usage = 0; static int max_mmap_usage = 0; #endif /*DEBUG_TOTAL*/ static int vips_window_unmap(VipsWindow *window) { /* unmap the old window */ if (window->baseaddr) { if (vips__munmap(window->baseaddr, window->length)) return -1; #ifdef DEBUG_TOTAL g_mutex_lock(&vips__global_lock); total_mmap_usage -= window->length; g_assert(total_mmap_usage >= 0); g_mutex_unlock(&vips__global_lock); #endif /*DEBUG_TOTAL*/ window->data = NULL; window->baseaddr = NULL; window->length = 0; } return 0; } static int vips_window_free(VipsWindow *window) { VipsImage *im = window->im; g_assert(window->ref_count == 0); #ifdef DEBUG printf("** vips_window_free: window top = %d, height = %d (%p)\n", window->top, window->height, window); printf("vips_window_unref: %d windows left\n", g_slist_length(im->windows)); #endif /*DEBUG*/ g_assert(g_slist_find(im->windows, window)); im->windows = g_slist_remove(im->windows, window); if (vips_window_unmap(window)) return -1; window->im = NULL; g_free(window); return 0; } int vips_window_unref(VipsWindow *window) { VipsImage *im = window->im; g_mutex_lock(&im->sslock); #ifdef DEBUG printf("vips_window_unref: window top = %d, height = %d, count = %d\n", window->top, window->height, window->ref_count); #endif /*DEBUG*/ g_assert(window->ref_count > 0); window->ref_count -= 1; if (window->ref_count == 0) { if (vips_window_free(window)) { g_mutex_unlock(&im->sslock); return -1; } } g_mutex_unlock(&im->sslock); return 0; } #ifdef DEBUG_TOTAL static void trace_mmap_usage(void) { g_mutex_lock(&vips__global_lock); { static int last_total = 0; int total = total_mmap_usage / (1024 * 1024); int max = max_mmap_usage / (1024 * 1024); if (total != last_total) { printf("vips_window_set: current mmap " "usage of ~%dMB (high water mark %dMB)\n", total, max); last_total = total; } } g_mutex_unlock(&vips__global_lock); } #endif /*DEBUG_TOTAL*/ static int vips_getpagesize(void) { static int pagesize = 0; if (!pagesize) { #ifdef G_OS_WIN32 SYSTEM_INFO si; GetSystemInfo(&si); pagesize = si.dwAllocationGranularity; #else /*!G_OS_WIN32*/ pagesize = sysconf(_SC_PAGESIZE); #endif /*G_OS_WIN32*/ } return pagesize; } /* Map a window into a file. */ static int vips_window_set(VipsWindow *window, int top, int height) { int pagesize = vips_getpagesize(); void *baseaddr; gint64 start, end, pagestart; size_t length, pagelength; /* Calculate start and length for our window. */ start = window->im->sizeof_header + VIPS_IMAGE_SIZEOF_LINE(window->im) * top; length = VIPS_IMAGE_SIZEOF_LINE(window->im) * height; pagestart = start - start % pagesize; end = start + length; pagelength = end - pagestart; /* Make sure we have enough file. */ if (end > window->im->file_length) { vips_error("vips_window_set", _("unable to read data for \"%s\", %s"), window->im->filename, _("file has been truncated")); return -1; } if (vips_window_unmap(window)) return -1; if (!(baseaddr = vips__mmap(window->im->fd, 0, pagelength, pagestart))) return -1; window->baseaddr = baseaddr; window->length = pagelength; window->data = (VipsPel *) baseaddr + (start - pagestart); window->top = top; window->height = height; /* Sanity check ... make sure the data pointer is readable. */ vips__read_test &= window->data[0]; #ifdef DEBUG_TOTAL g_mutex_lock(&vips__global_lock); total_mmap_usage += window->length; if (total_mmap_usage > max_mmap_usage) max_mmap_usage = total_mmap_usage; g_mutex_unlock(&vips__global_lock); trace_mmap_usage(); #endif /*DEBUG_TOTAL*/ return 0; } /* Make a new window. */ static VipsWindow * vips_window_new(VipsImage *im, int top, int height) { VipsWindow *window; if (!(window = VIPS_NEW(NULL, VipsWindow))) return NULL; window->ref_count = 0; window->im = im; window->top = 0; window->height = 0; window->data = NULL; window->baseaddr = NULL; window->length = 0; im->windows = g_slist_prepend(im->windows, window); if (vips_window_set(window, top, height)) { vips_window_free(window); return NULL; } window->ref_count = 1; #ifdef DEBUG printf("** vips_window_new: window top = %d, height = %d (%p)\n", window->top, window->height, window); #endif /*DEBUG*/ return window; } /* A request for an area of pixels. */ typedef struct { int top; int height; } request_t; static void * vips_window_fits(VipsWindow *window, request_t *req, void *b) { if (window->top <= req->top && window->top + window->height >= req->top + req->height) return window; return NULL; } /* Find an existing window that fits within top/height and return a ref. */ static VipsWindow * vips_window_find(VipsImage *im, int top, int height) { request_t req; VipsWindow *window; req.top = top; req.height = height; window = vips_slist_map2(im->windows, (VipsSListMap2Fn) vips_window_fits, &req, NULL); if (window) { window->ref_count += 1; #ifdef DEBUG printf("vips_window_find: ref window top = %d, height = %d, " "count = %d\n", top, height, window->ref_count); #endif /*DEBUG*/ } return window; } /* Update a window to make it enclose top/height. */ VipsWindow * vips_window_take(VipsWindow *window, VipsImage *im, int top, int height) { /* We have a window and it has the pixels we need. */ if (window && window->top <= top && window->top + window->height >= top + height) return window; g_mutex_lock(&im->sslock); /* We have a window and we are the only ref to it ... scroll. */ if (window && window->ref_count == 1) { if (vips_window_set(window, top, height)) { g_mutex_unlock(&im->sslock); vips_window_unref(window); return NULL; } g_mutex_unlock(&im->sslock); return window; } /* There's more than one ref to the window. We can just decrement. * Don't call _unref, since we've inside the lock. */ if (window) window->ref_count -= 1; /* Is there an existing window we can reuse? */ if ((window = vips_window_find(im, top, height))) { g_mutex_unlock(&im->sslock); return window; } /* Add a margin around our window to try to reduce window scrolling. * * This will be very large on 64-bit machines, but rather small on 32-bits. */ gint64 line_bytes = VIPS_IMAGE_SIZEOF_LINE(im); gint64 window_bytes = height * line_bytes; gint64 margin_bytes = (VIPS_MAX(window_bytes, vips__window_bytes) - window_bytes) / 2; gint64 margin_lines = VIPS_CLIP(0, margin_bytes / line_bytes, VIPS_MAX_COORD); top -= margin_lines; height += margin_lines * 2; top = VIPS_CLIP(0, top, im->Ysize - 1); height = VIPS_CLIP(0, height, im->Ysize - top); #ifdef DEBUG printf("vips_window_take: top = %d, height = %d\n", top, height); #endif /*DEBUG*/ if (!(window = vips_window_new(im, top, height))) { g_mutex_unlock(&im->sslock); return NULL; } g_mutex_unlock(&im->sslock); return window; } void vips_window_print(VipsWindow *window) { printf("VipsWindow: %p ref_count = %d, ", window, window->ref_count); printf("im = %p, ", window->im); printf("top = %d, ", window->top); printf("height = %d, ", window->height); printf("data = %p, ", window->data); printf("baseaddr = %p, ", window->baseaddr); printf("length = %zd\n", window->length); } libvips-8.18.2/libvips/meson.build000066400000000000000000000056761516303661500171200ustar00rootroot00000000000000libvips_sources = [] libvips_components = [] subdir('include/vips') subdir('foreign') if get_option('deprecated') subdir('deprecated') endif subdir('arithmetic') subdir('resample') subdir('colour') subdir('conversion') subdir('convolution') subdir('freqfilt') subdir('histogram') subdir('draw') subdir('iofuncs') subdir('morphology') subdir('mosaicing') subdir('create') libvips_lib = library('vips', enumtypes, link_whole: libvips_components, dependencies: libvips_deps, version: library_version, darwin_versions: darwin_versions, gnu_symbol_visibility: 'hidden', install: true, link_args: nodelete_link_args, ) libvips_dep = declare_dependency( link_with: libvips_lib, dependencies: libvips_deps, ) pkg.generate( libvips_lib, requires: [ glib_dep, gio_dep, gobject_dep ], name: 'vips', description: 'Image processing library', ) if enable_introspection vips_gir = gnome.generate_gir( libvips_lib, namespace: 'Vips', nsversion: '@0@.0'.format(version_major), identifier_prefix: 'Vips', symbol_prefix: 'vips', export_packages: 'vips', header: 'vips/vips.h', sources: libvips_sources, dependencies: libvips_deps, includes: ['GObject-2.0', 'Gio-2.0'], install: true ) if get_option('vapi') gnome.generate_vapi( 'vips', sources: vips_gir[0], packages: [ 'glib-2.0', 'gio-2.0', 'gobject-2.0' ], install: true ) endif endif # # The following configuration is only valid when the modules are enabled # if not modules_enabled subdir_done() endif if magick_module shared_module('vips-magick', 'module/magick.c', magick_module_sources, magick_module_headers, name_prefix: '', dependencies: [libvips_dep, magick_dep], install: true, install_dir: module_dir ) endif if libjxl_module shared_module('vips-jxl', 'module/jxl.c', jpeg_xl_module_sources, name_prefix: '', dependencies: [libvips_dep, libjxl_dep, libjxl_threads_dep], install: true, install_dir: module_dir ) endif if libheif_module shared_module('vips-heif', 'module/heif.c', heif_module_sources, name_prefix: '', dependencies: [libvips_dep, libheif_dep], install: true, install_dir: module_dir ) endif if libpoppler_module shared_module('vips-poppler', 'module/poppler.c', poppler_module_sources, name_prefix: '', dependencies: [libvips_dep, libpoppler_dep, cairo_dep], install: true, install_dir: module_dir ) endif if openslide_module shared_module('vips-openslide', 'module/openslide.c', openslide_module_sources, name_prefix: '', dependencies: [libvips_dep, openslide_dep], install: true, install_dir: module_dir ) endif libvips-8.18.2/libvips/module/000077500000000000000000000000001516303661500162255ustar00rootroot00000000000000libvips-8.18.2/libvips/module/heif.c000066400000000000000000000041531516303661500173070ustar00rootroot00000000000000/* libheif as a dynamically loadable module * * 14/2/21 kleisauke * - initial */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #if defined(HAVE_HEIF) && defined(HEIF_MODULE) /* This is called on module load. */ G_MODULE_EXPORT const gchar * g_module_check_init(GModule *module) { #ifdef DEBUG printf("vips_heif: module init\n"); #endif /*DEBUG*/ extern GType vips_foreign_load_heif_file_get_type(void); extern GType vips_foreign_load_heif_buffer_get_type(void); extern GType vips_foreign_load_heif_source_get_type(void); extern GType vips_foreign_save_heif_file_get_type(void); extern GType vips_foreign_save_heif_buffer_get_type(void); extern GType vips_foreign_save_heif_target_get_type(void); extern GType vips_foreign_save_avif_target_get_type(void); vips_foreign_load_heif_file_get_type(); vips_foreign_load_heif_buffer_get_type(); vips_foreign_load_heif_source_get_type(); vips_foreign_save_heif_file_get_type(); vips_foreign_save_heif_buffer_get_type(); vips_foreign_save_heif_target_get_type(); vips_foreign_save_avif_target_get_type(); return NULL; } #endif /*defined(HAVE_HEIF) && defined(HEIF_MODULE)*/ libvips-8.18.2/libvips/module/jxl.c000066400000000000000000000040001516303661500171600ustar00rootroot00000000000000/* libjxl as a dynamically loadable module * * 10/5/21 jcupitt * - from heif.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #if defined(HAVE_LIBJXL) && defined(LIBJXL_MODULE) /* This is called on module load. */ G_MODULE_EXPORT const gchar * g_module_check_init(GModule *module) { #ifdef DEBUG printf("vips_jxl: module init\n"); #endif /*DEBUG*/ extern GType vips_foreign_load_jxl_file_get_type(void); extern GType vips_foreign_load_jxl_buffer_get_type(void); extern GType vips_foreign_load_jxl_source_get_type(void); extern GType vips_foreign_save_jxl_file_get_type(void); extern GType vips_foreign_save_jxl_buffer_get_type(void); extern GType vips_foreign_save_jxl_target_get_type(void); vips_foreign_load_jxl_file_get_type(); vips_foreign_load_jxl_buffer_get_type(); vips_foreign_load_jxl_source_get_type(); vips_foreign_save_jxl_file_get_type(); vips_foreign_save_jxl_buffer_get_type(); vips_foreign_save_jxl_target_get_type(); return NULL; } #endif /*defined(HAVE_LIBJXL) && defined(LIBJXL_MODULE)*/ libvips-8.18.2/libvips/module/magick.c000066400000000000000000000053361516303661500176330ustar00rootroot00000000000000/* magick as a dynamically loadable module * * 21/4/21 kleisauke * - initial */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #if (defined(HAVE_MAGICK6) || defined(HAVE_MAGICK7)) && defined(MAGICK_MODULE) /* This is called on module load. */ G_MODULE_EXPORT const gchar * g_module_check_init(GModule *module) { #ifdef DEBUG printf("vips_magick: module init\n"); #endif /*DEBUG*/ extern GType vips_foreign_load_magick_file_get_type(void); extern GType vips_foreign_load_magick_buffer_get_type(void); extern GType vips_foreign_load_magick_source_get_type(void); extern GType vips_foreign_load_magick7_file_get_type(void); extern GType vips_foreign_load_magick7_buffer_get_type(void); extern GType vips_foreign_load_magick7_source_get_type(void); extern GType vips_foreign_save_magick_file_get_type(void); extern GType vips_foreign_save_magick_bmp_file_get_type(void); extern GType vips_foreign_save_magick_buffer_get_type(void); extern GType vips_foreign_save_magick_bmp_buffer_get_type(void); #ifdef ENABLE_MAGICKLOAD #ifdef HAVE_MAGICK6 vips_foreign_load_magick_file_get_type(); vips_foreign_load_magick_buffer_get_type(); vips_foreign_load_magick_source_get_type(); #endif /*HAVE_MAGICK6*/ #ifdef HAVE_MAGICK7 vips_foreign_load_magick7_file_get_type(); vips_foreign_load_magick7_buffer_get_type(); vips_foreign_load_magick7_source_get_type(); #endif /*HAVE_MAGICK7*/ #endif /*ENABLE_MAGICKLOAD*/ #ifdef ENABLE_MAGICKSAVE vips_foreign_save_magick_file_get_type(); vips_foreign_save_magick_bmp_file_get_type(); vips_foreign_save_magick_buffer_get_type(); vips_foreign_save_magick_bmp_buffer_get_type(); #endif /*ENABLE_MAGICKSAVE*/ return NULL; } #endif /*(defined(HAVE_MAGICK6) || defined (HAVE_MAGICK7)) && defined(MAGICK_MODULE)*/ libvips-8.18.2/libvips/module/openslide.c000066400000000000000000000032331516303661500203540ustar00rootroot00000000000000/* openslide as a dynamically loadable module * * 11/2/21 kleisauke * - initial */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #if defined(HAVE_OPENSLIDE) && defined(OPENSLIDE_MODULE) /* This is called on module load. */ G_MODULE_EXPORT const gchar * g_module_check_init(GModule *module) { #ifdef DEBUG printf("vips_openslide: module init\n"); #endif /*DEBUG*/ extern GType vips_foreign_load_openslide_file_get_type(void); extern GType vips_foreign_load_openslide_source_get_type(void); vips_foreign_load_openslide_file_get_type(); vips_foreign_load_openslide_source_get_type(); return NULL; } #endif /*defined(HAVE_OPENSLIDE) && defined(OPENSLIDE_MODULE)*/ libvips-8.18.2/libvips/module/poppler.c000066400000000000000000000033341516303661500200550ustar00rootroot00000000000000/* poppler as a dynamically loadable module * * 21/4/21 kleisauke * - initial */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #if defined(HAVE_POPPLER) && defined(POPPLER_MODULE) /* This is called on module load. */ G_MODULE_EXPORT const gchar * g_module_check_init(GModule *module) { #ifdef DEBUG printf("vips_poppler: module init\n"); #endif /*DEBUG*/ extern GType vips_foreign_load_pdf_file_get_type(void); extern GType vips_foreign_load_pdf_buffer_get_type(void); extern GType vips_foreign_load_pdf_source_get_type(void); vips_foreign_load_pdf_file_get_type(); vips_foreign_load_pdf_buffer_get_type(); vips_foreign_load_pdf_source_get_type(); return NULL; } #endif /*defined(HAVE_POPPLER) && defined(POPPLER_MODULE)*/ libvips-8.18.2/libvips/morphology/000077500000000000000000000000001516303661500171375ustar00rootroot00000000000000libvips-8.18.2/libvips/morphology/countlines.c000066400000000000000000000111241516303661500214650ustar00rootroot00000000000000/* count lines * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on : * * 19/9/95 JC * - tidied up * 23/10/10 * - gtk-doc * 17/1/14 * - redone as a class, now just a convenience function */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pmorphology.h" typedef struct _VipsCountlines { VipsMorphology parent_instance; double nolines; VipsDirection direction; } VipsCountlines; typedef VipsMorphologyClass VipsCountlinesClass; G_DEFINE_TYPE(VipsCountlines, vips_countlines, VIPS_TYPE_MORPHOLOGY); static int vips_countlines_build(VipsObject *object) { VipsMorphology *morphology = VIPS_MORPHOLOGY(object); VipsCountlines *countlines = (VipsCountlines *) object; VipsImage *in = morphology->in; VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); double nolines; if (VIPS_OBJECT_CLASS(vips_countlines_parent_class)->build(object)) return -1; /* Compiler warnings. */ nolines = 1; switch (countlines->direction) { case VIPS_DIRECTION_HORIZONTAL: if (!(t[0] = vips_image_new_matrixv(1, 2, -1.0, 1.0)) || vips_moreeq_const1(in, &t[1], 128, NULL) || vips_conv(t[1], &t[2], t[0], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_project(t[2], &t[3], &t[4], NULL) || vips_avg(t[3], &nolines, NULL)) return -1; break; case VIPS_DIRECTION_VERTICAL: if (!(t[0] = vips_image_new_matrixv(2, 1, -1.0, 1.0)) || vips_moreeq_const1(in, &t[1], 128, NULL) || vips_conv(t[1], &t[2], t[0], "precision", VIPS_PRECISION_INTEGER, NULL) || vips_project(t[2], &t[3], &t[4], NULL) || vips_avg(t[4], &nolines, NULL)) return -1; break; default: g_assert_not_reached(); } g_object_set(object, "nolines", nolines / 255.0, NULL); return 0; } static void vips_countlines_class_init(VipsCountlinesClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_countlines_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "countlines"; vobject_class->description = _("count lines in an image"); vobject_class->build = vips_countlines_build; VIPS_ARG_DOUBLE(class, "nolines", 2, _("Nolines"), _("Number of lines"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsCountlines, nolines), 0, 10000000, 0.0); VIPS_ARG_ENUM(class, "direction", 3, _("Direction"), _("Countlines left-right or up-down"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsCountlines, direction), VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL); } static void vips_countlines_init(VipsCountlines *countlines) { } /** * vips_countlines: (method) * @in: input image * @nolines: (out): output average number of lines * @direction: count lines horizontally or vertically * @...: `NULL`-terminated list of optional named arguments * * Function which calculates the number of transitions * between black and white for the horizontal or the vertical * direction of an image. black<128 , white>=128 * The function calculates the number of transitions for all * Xsize or Ysize and returns the mean of the result * Input should be one band, 8-bit. * * ::: seealso * [method@Image.morph], [method@Image.conv]. * * Returns: 0 on success, -1 on error. */ int vips_countlines(VipsImage *in, double *nolines, VipsDirection direction, ...) { va_list ap; int result; va_start(ap, direction); result = vips_call_split("countlines", ap, in, nolines, direction); va_end(ap); return result; } libvips-8.18.2/libvips/morphology/labelregions.c000066400000000000000000000107501516303661500217540ustar00rootroot00000000000000/* labelregions.c * * 5/11/09 * - renamed from im_segment() * 11/2/14 * - redo as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pmorphology.h" typedef struct _VipsLabelregions { VipsMorphology parent_instance; VipsImage *mask; int segments; } VipsLabelregions; typedef VipsMorphologyClass VipsLabelregionsClass; G_DEFINE_TYPE(VipsLabelregions, vips_labelregions, VIPS_TYPE_MORPHOLOGY); static int vips_labelregions_build(VipsObject *object) { VipsMorphology *morphology = VIPS_MORPHOLOGY(object); VipsImage *in = morphology->in; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *mask; int segments; int *m; int x, y; if (VIPS_OBJECT_CLASS(vips_labelregions_parent_class)->build(object)) return -1; /* Create the zero mask image in memory. */ if (vips_black(&t[0], in->Xsize, in->Ysize, NULL) || vips_cast(t[0], &t[1], VIPS_FORMAT_INT, NULL) || !(t[2] = vips_image_copy_memory(t[1]))) return -1; mask = t[2]; g_object_set(object, "mask", mask, NULL); segments = 1; m = (int *) mask->data; for (y = 0; y < mask->Ysize; y++) { for (x = 0; x < mask->Xsize; x++) { if (!m[x]) { /* Use a direct path for speed. */ if (vips__draw_flood_direct(mask, in, segments, x, y)) return -1; segments += 1; } } m += mask->Xsize; } g_object_set(object, "segments", segments, NULL); return 0; } static void vips_labelregions_class_init(VipsLabelregionsClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "labelregions"; vobject_class->description = _("label regions in an image"); vobject_class->build = vips_labelregions_build; VIPS_ARG_IMAGE(class, "mask", 2, _("Mask"), _("Mask of region labels"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsLabelregions, mask)); VIPS_ARG_INT(class, "segments", 3, _("Segments"), _("Number of discrete contiguous regions"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsLabelregions, segments), 0, 1000000000, 0); } static void vips_labelregions_init(VipsLabelregions *labelregions) { } /** * vips_labelregions: (method) * @in: image to test * @mask: write labelled regions here * @...: `NULL`-terminated list of optional named arguments * * Label regions of equal pixels in an image. * * Repeatedly scans @in for regions of 4-connected pixels * with the same pixel value. Every time a region is discovered, those * pixels are marked in @mask with a unique serial number. Once all pixels * have been labelled, the operation returns, setting @segments to the number * of discrete regions which were detected. * * @mask is always a 1-band [enum@Vips.BandFormat.INT] image of the same * dimensions as @in. * * This operation is useful for, for example, blob counting. You can use the * morphological operators to detect and isolate a series of objects, then use * [method@Image.labelregions] to number them all. * * Use [method@Image.hist_find_indexed] to (for example) find blob coordinates. * * ::: tip "Optional arguments" * * @segments: `gint`, output, number of regions found * * ::: seealso * [method@Image.hist_find_indexed]. * * Returns: 0 on success, -1 on error. */ int vips_labelregions(VipsImage *in, VipsImage **mask, ...) { va_list ap; int result; va_start(ap, mask); result = vips_call_split("labelregions", ap, in, mask); va_end(ap); return result; } libvips-8.18.2/libvips/morphology/meson.build000066400000000000000000000007061516303661500213040ustar00rootroot00000000000000morphology_sources = files( 'nearest.c', 'morphology.c', 'countlines.c', 'rank.c', 'morph.c', 'morph_hwy.cpp', 'labelregions.c', ) morphology_headers = files( 'pmorphology.h', ) libvips_sources += morphology_sources morphology_lib = static_library('morphology', morphology_sources, morphology_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += morphology_lib libvips-8.18.2/libvips/morphology/morph.c000066400000000000000000000601701516303661500204340ustar00rootroot00000000000000/* morphology * * 19/9/95 JC * - rewritten * 6/7/99 JC * - small tidies * 7/4/04 * - now uses im_embed() with edge stretching on the input, not * the output * - sets Xoffset / Yoffset * 21/4/08 * - only rebuild the buffer offsets if bpl changes * - small cleanups * 25/10/10 * - start again from the Orc'd im_conv * 29/10/10 * - use VipsVector * - do erode as well * 7/11/10 * - gtk-doc * - do (!=0) to make uchar, if we're not given uchar * 28/6/13 * - oops, fix !=0 code * 23/10/13 * - from vips_conv() * 25/2/20 kleisauke * - rewritten as a class * - merged with hitmiss */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pmorphology.h" #ifdef HAVE_ORC #include /* We can't run more than this many passes. Larger than this and we * fall back to C. * TODO: Could this be raised to 20? Just like convi. */ #define MAX_PASS (10) #define MAX_SOURCES (8 /*ORC_MAX_SRC_VARS*/) /* A pass with a vector. */ typedef struct { int first; /* The index of the first mask coff we use */ int last; /* The index of the last mask coff we use */ int r; /* Set previous result in this var */ int d1; /* The destination var */ int n_const; int n_scanline; /* The associated line corresponding to the scanline. */ int line[MAX_SOURCES]; /* The code we generate for this section of this mask. */ OrcProgram *program; } Pass; #endif /*HAVE_ORC*/ /** * VipsOperationMorphology: * @VIPS_OPERATION_MORPHOLOGY_ERODE: true if all set * @VIPS_OPERATION_MORPHOLOGY_DILATE: true if one set * * More like hit-miss, really. * * ::: seealso * [method@Image.morph]. */ typedef struct { VipsMorphology parent_instance; VipsImage *out; VipsImage *mask; VipsOperationMorphology morph; /* @mask cast ready for processing. */ VipsImage *M; int n_point; /* w * h for our matrix */ guint8 *coeff; /* Mask coefficients */ #ifdef HAVE_ORC /* The passes we generate for this mask. */ int n_pass; Pass pass[MAX_PASS]; #endif /*HAVE_ORC*/ } VipsMorph; typedef VipsMorphologyClass VipsMorphClass; G_DEFINE_TYPE(VipsMorph, vips_morph, VIPS_TYPE_MORPHOLOGY); /* Our sequence value. */ typedef struct { VipsMorph *morph; VipsRegion *ir; /* Input region */ int *off; /* Offsets for each non-128 matrix element */ int nn128; /* Number of non-128 mask elements */ guint8 *coeff; /* Array of non-128 mask coefficients */ int last_bpl; /* Avoid recalcing offsets, if we can */ #ifdef HAVE_ORC /* In vector mode we need a pair of intermediate buffers to keep the * results of each pass in. */ void *t1; void *t2; #endif /*HAVE_ORC*/ } VipsMorphSequence; #ifdef HAVE_ORC static void vips_morph_finalize(GObject *gobject) { VipsMorph *morph = (VipsMorph *) gobject; for (int i = 0; i < morph->n_pass; i++) VIPS_FREEF(orc_program_free, morph->pass[i].program); morph->n_pass = 0; G_OBJECT_CLASS(vips_morph_parent_class)->finalize(gobject); } #endif /*HAVE_ORC*/ /* Free a sequence value. */ static int vips_morph_stop(void *vseq, void *a, void *b) { VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VIPS_UNREF(seq->ir); #ifdef HAVE_ORC VIPS_FREE(seq->t1); VIPS_FREE(seq->t2); #endif /*HAVE_ORC*/ return 0; } /* Morph start function. */ static void * vips_morph_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsMorph *morph = (VipsMorph *) b; VipsMorphSequence *seq; if (!(seq = VIPS_NEW(out, VipsMorphSequence))) return NULL; /* Init! */ seq->morph = morph; seq->ir = NULL; seq->off = NULL; seq->nn128 = 0; seq->coeff = NULL; seq->last_bpl = -1; #ifdef HAVE_ORC seq->t1 = NULL; seq->t2 = NULL; #endif /*HAVE_ORC*/ seq->ir = vips_region_new(in); seq->off = VIPS_ARRAY(out, morph->n_point, int); seq->coeff = VIPS_ARRAY(out, morph->n_point, guint8); if (!seq->off || !seq->coeff) { vips_morph_stop(seq, in, morph); return NULL; } #ifdef HAVE_ORC /* Vector mode. */ if (morph->n_pass) { seq->t1 = VIPS_ARRAY(NULL, VIPS_IMAGE_N_ELEMENTS(in), VipsPel); seq->t2 = VIPS_ARRAY(NULL, VIPS_IMAGE_N_ELEMENTS(in), VipsPel); if (!seq->t1 || !seq->t2) { vips_morph_stop(seq, in, morph); return NULL; } } #endif /*HAVE_ORC*/ return seq; } #ifdef HAVE_HWY static int vips_dilate_vector_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VipsMorph *morph = (VipsMorph *) b; VipsImage *M = morph->M; VipsRegion *ir = seq->ir; int *off = seq->off; guint8 *coeff = seq->coeff; VipsRect *r = &out_region->valid; int sz = VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int x, y; guint8 *t; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; #ifdef DEBUG_VERBOSE printf("vips_dilate_vector_gen: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top); #endif /*DEBUG_VERBOSE*/ /* Scan mask, building offsets we check when processing. Only do this * if the bpl has changed since the previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); seq->nn128 = 0; for (t = morph->coeff, y = 0; y < M->Ysize; y++) for (x = 0; x < M->Xsize; x++, t++) { /* Exclude don't-care elements. */ if (*t == 128) continue; off[seq->nn128] = VIPS_REGION_ADDR(ir, x + r->left, y + r->top) - VIPS_REGION_ADDR(ir, r->left, r->top); coeff[seq->nn128] = *t; seq->nn128++; } } VIPS_GATE_START("vips_dilate_vector_gen: work"); vips_dilate_uchar_hwy(out_region, ir, r, sz, seq->nn128, off, coeff); VIPS_GATE_STOP("vips_dilate_vector_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_dilate_vector_gen"); return 0; } static int vips_erode_vector_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VipsMorph *morph = (VipsMorph *) b; VipsImage *M = morph->M; VipsRegion *ir = seq->ir; int *off = seq->off; guint8 *coeff = seq->coeff; VipsRect *r = &out_region->valid; int sz = VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int x, y; guint8 *t; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; #ifdef DEBUG_VERBOSE printf("vips_erode_vector_gen: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top); #endif /*DEBUG_VERBOSE*/ /* Scan mask, building offsets we check when processing. Only do this * if the bpl has changed since the previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); seq->nn128 = 0; for (t = morph->coeff, y = 0; y < M->Ysize; y++) for (x = 0; x < M->Xsize; x++, t++) { /* Exclude don't-care elements. */ if (*t == 128) continue; off[seq->nn128] = VIPS_REGION_ADDR(ir, x + r->left, y + r->top) - VIPS_REGION_ADDR(ir, r->left, r->top); coeff[seq->nn128] = *t; seq->nn128++; } } VIPS_GATE_START("vips_erode_vector_gen: work"); vips_erode_uchar_hwy(out_region, ir, r, sz, seq->nn128, off, coeff); VIPS_GATE_STOP("vips_erode_vector_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_erode_vector_gen"); return 0; } #elif defined(HAVE_ORC) #define TEMP(N, S) orc_program_add_temporary(p, S, N) #define SCANLINE(N, S) orc_program_add_source(p, S, N) #define CONST(N, V, S) orc_program_add_constant(p, S, V, N) #define ASM2(OP, A, B) orc_program_append_ds_str(p, OP, A, B) #define ASM3(OP, A, B, C) orc_program_append_str(p, OP, A, B, C) /* Generate code for a section of the mask. first is the index we start * at, we set last to the index of the last one we use before we run * out of intermediates / constants / parameters / sources or mask * coefficients. * * 0 for success, -1 on error. */ static int vips_morph_compile_section(VipsMorph *morph, Pass *pass, gboolean first_pass) { VipsMorphology *morphology = (VipsMorphology *) morph; VipsImage *M = morph->M; OrcProgram *p; OrcCompileResult result; int i; pass->program = p = orc_program_new(); pass->d1 = orc_program_add_destination(p, 1, "d1"); /* "r" is the result of the previous pass. */ if (!(pass->r = orc_program_add_source(p, 1, "r"))) return -1; /* The value we fetch from the image, the accumulated sum. */ TEMP("value", 1); TEMP("sum", 1); CONST("zero", 0, 1); CONST("one", 255, 1); pass->n_const += 2; /* Init the sum. If this is the first pass, it's a constant. If this * is a later pass, we have to init the sum from the result * of the previous pass. */ if (first_pass) { if (morph->morph == VIPS_OPERATION_MORPHOLOGY_DILATE) ASM2("copyb", "sum", "zero"); else ASM2("copyb", "sum", "one"); } else ASM2("loadb", "sum", "r"); for (i = pass->first; i < morph->n_point; i++) { int x = i % M->Xsize; int y = i / M->Xsize; char offset[256]; char source[256]; /* Exclude don't-care elements. */ if (morph->coeff[i] == 128) continue; /* The source. sl0 is the first scanline in the mask. */ g_snprintf(source, 256, "sl%d", y); if (orc_program_find_var_by_name(p, source) == -1) { SCANLINE(source, 1); pass->line[pass->n_scanline] = y; pass->n_scanline++; } /* The offset, only for non-first-columns though. */ if (x > 0) { g_snprintf(offset, 256, "c%db", x); if (orc_program_find_var_by_name(p, offset) == -1) { CONST(offset, morphology->in->Bands * x, 1); pass->n_const++; } ASM3("loadoffb", "value", source, offset); } else ASM2("loadb", "value", source); /* Join to our sum. If the mask element is zero, we have to * add an extra negate. */ if (morph->morph == VIPS_OPERATION_MORPHOLOGY_DILATE) { if (!morph->coeff[i]) ASM3("xorb", "value", "value", "one"); ASM3("orb", "sum", "sum", "value"); } else { if (!morph->coeff[i]) { /* You'd think we could use andnb, but it * fails on some machines with some orc * versions :( */ ASM3("xorb", "value", "value", "one"); ASM3("andb", "sum", "sum", "value"); } else ASM3("andb", "sum", "sum", "value"); } /* orc allows up to 8 constants, so break early once we * approach this limit. */ if (pass->n_const >= 7 /*ORC_MAX_CONST_VARS - 1*/) break; /* You can have 8 sources, and pass->r counts as one of them, * so +1 there. */ if (pass->n_scanline + 1 >= 7 /*ORC_MAX_SRC_VARS - 1*/) break; } pass->last = i; ASM2("copyb", "d1", "sum"); /* Some orcs seem to be unstable with many compilers active at once. */ g_mutex_lock(&vips__global_lock); result = orc_program_compile(p); g_mutex_unlock(&vips__global_lock); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) return -1; #ifdef DEBUG printf("done matrix coeffs %d to %d\n", pass->first, pass->last); #endif /*DEBUG*/ return 0; } /* Generate a set of passes. */ static int vips_morph_compile(VipsMorph *morph) { int i; Pass *pass; #ifdef DEBUG printf("vips_morph_compile: generating vector code\n"); #endif /*DEBUG*/ /* Generate passes until we've used up the whole mask. */ for (i = 0;;) { /* Skip any don't-care coefficients at the start of the mask * region. */ for (; i < morph->n_point && morph->coeff[i] == 128; i++) ; if (i == morph->n_point) break; /* Allocate space for another pass. */ if (morph->n_pass == MAX_PASS) return -1; pass = &morph->pass[morph->n_pass]; morph->n_pass += 1; pass->first = i; pass->last = i; pass->r = -1; pass->n_const = 0; pass->n_scanline = 0; if (vips_morph_compile_section(morph, pass, morph->n_pass == 1)) return -1; i = pass->last + 1; if (i >= morph->n_point) break; } return 0; } /* The vector codepath. */ static int vips_morph_gen_vector(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VipsMorph *morph = (VipsMorph *) b; VipsImage *M = morph->M; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; int sz = VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int j, i, y; OrcExecutor executor[MAX_PASS]; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; #ifdef DEBUG_VERBOSE printf("vips_morph_gen_vector: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top); #endif /*DEBUG_VERBOSE*/ for (i = 0; i < morph->n_pass; i++) { orc_executor_set_program(&executor[i], morph->pass[i].program); orc_executor_set_n(&executor[i], sz); } VIPS_GATE_START("vips_morph_gen_vector: work"); for (y = 0; y < r->height; y++) { for (i = 0; i < morph->n_pass; i++) { Pass *pass = &morph->pass[i]; void *d; /* The last pass goes to the output image, * intermediate passes go to t2. */ if (i == morph->n_pass - 1) d = VIPS_REGION_ADDR(out_region, r->left, r->top + y); else d = seq->t2; for (j = 0; j < pass->n_scanline; j++) orc_executor_set_array(&executor[i], pass->r + 1 + j, VIPS_REGION_ADDR(ir, r->left, r->top + y + pass->line[j])); orc_executor_set_array(&executor[i], pass->r, seq->t1); orc_executor_set_array(&executor[i], pass->d1, d); orc_executor_run(&executor[i]); VIPS_SWAP(void *, seq->t1, seq->t2); } } VIPS_GATE_STOP("vips_morph_gen_vector: work"); VIPS_COUNT_PIXELS(out_region, "vips_morph_gen_vector"); return 0; } #endif /*HAVE_HWY*/ /* Dilate! */ static int vips_dilate_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VipsMorph *morph = (VipsMorph *) b; VipsImage *M = morph->M; VipsRegion *ir = seq->ir; int *off = seq->off; guint8 *coeff = seq->coeff; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int sz = VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int x, y; guint8 *t; int result, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; #ifdef DEBUG_VERBOSE printf("vips_dilate_gen: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top); #endif /*DEBUG_VERBOSE*/ /* Scan mask, building offsets we check when processing. Only do this * if the bpl has changed since the previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); seq->nn128 = 0; for (t = morph->coeff, y = 0; y < M->Ysize; y++) for (x = 0; x < M->Xsize; x++, t++) { /* Exclude don't-care elements. */ if (*t == 128) continue; off[seq->nn128] = VIPS_REGION_ADDR(ir, x + le, y + to) - VIPS_REGION_ADDR(ir, le, to); coeff[seq->nn128] = *t; seq->nn128++; } } VIPS_GATE_START("vips_dilate_gen: work"); for (y = to; y < bo; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, le, y); VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); /* Loop along line. */ for (x = 0; x < sz; x++, q++, p++) { /* Dilate! */ result = 0; for (i = 0; i < seq->nn128; i++) result |= !coeff[i] ? ~p[off[i]] : p[off[i]]; *q = result; } } VIPS_GATE_STOP("vips_dilate_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_dilate_gen"); return 0; } /* Erode! */ static int vips_erode_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsMorphSequence *seq = (VipsMorphSequence *) vseq; VipsMorph *morph = (VipsMorph *) b; VipsImage *M = morph->M; VipsRegion *ir = seq->ir; int *off = seq->off; guint8 *coeff = seq->coeff; VipsRect *r = &out_region->valid; int le = r->left; int to = r->top; int bo = VIPS_RECT_BOTTOM(r); int sz = VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int x, y; guint8 *t; int result, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += M->Xsize - 1; s.height += M->Ysize - 1; if (vips_region_prepare(ir, &s)) return -1; #ifdef DEBUG_VERBOSE printf("vips_erode_gen: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top); #endif /*DEBUG_VERBOSE*/ /* Scan mask, building offsets we check when processing. Only do this * if the bpl has changed since the previous vips_region_prepare(). */ if (seq->last_bpl != VIPS_REGION_LSKIP(ir)) { seq->last_bpl = VIPS_REGION_LSKIP(ir); seq->nn128 = 0; for (t = morph->coeff, y = 0; y < M->Ysize; y++) for (x = 0; x < M->Xsize; x++, t++) { /* Exclude don't-care elements. */ if (*t == 128) continue; off[seq->nn128] = VIPS_REGION_ADDR(ir, x + le, y + to) - VIPS_REGION_ADDR(ir, le, to); coeff[seq->nn128] = *t; seq->nn128++; } } VIPS_GATE_START("vips_erode_gen: work"); for (y = to; y < bo; y++) { VipsPel *p = VIPS_REGION_ADDR(ir, le, y); VipsPel *q = VIPS_REGION_ADDR(out_region, le, y); /* Loop along line. */ for (x = 0; x < sz; x++, q++, p++) { /* Erode! */ result = 255; for (i = 0; i < seq->nn128; i++) result &= !coeff[i] ? ~p[off[i]] : p[off[i]]; *q = result; } } VIPS_GATE_STOP("vips_erode_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_erode_gen"); return 0; } static int vips_morph_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsMorphology *morphology = (VipsMorphology *) object; VipsMorph *morph = (VipsMorph *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); VipsImage *in; VipsImage *M; VipsGenerateFn generate; double *coeff; int i; if (VIPS_OBJECT_CLASS(vips_morph_parent_class)->build(object)) return -1; in = morphology->in; /* Unpack for processing. */ if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (vips_check_matrix(class->nickname, morph->mask, &t[1])) return -1; morph->M = M = t[1]; morph->n_point = M->Xsize * M->Ysize; if (vips_embed(in, &t[2], M->Xsize / 2, M->Ysize / 2, in->Xsize + M->Xsize - 1, in->Ysize + M->Ysize - 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[2]; /* Make sure we are uchar. */ if (vips_cast(in, &t[3], VIPS_FORMAT_UCHAR, NULL)) return -1; in = t[3]; /* Make an int version of our mask. */ if (vips__image_intize(M, &t[4])) return -1; M = t[4]; coeff = VIPS_MATRIX(M, 0, 0); if (!(morph->coeff = VIPS_ARRAY(object, morph->n_point, guint8))) return -1; for (i = 0; i < morph->n_point; i++) { if (coeff[i] != 0 && coeff[i] != 128 && coeff[i] != 255) { vips_error(class->nickname, _("bad mask element (%f should be 0, 128 or 255)"), coeff[i]); return -1; } morph->coeff[i] = (guint8) coeff[i]; } /* Try to make a vector path. */ #ifdef HAVE_HWY if (vips_vector_isenabled()) { generate = morph->morph == VIPS_OPERATION_MORPHOLOGY_DILATE ? vips_dilate_vector_gen : vips_erode_vector_gen; g_info("morph: using vector path"); } else #elif defined(HAVE_ORC) /* Generate code for this mask / image, if possible. */ if (vips_vector_isenabled() && !vips_morph_compile(morph)) { generate = vips_morph_gen_vector; g_info("morph: using vector path"); } else #endif /*HAVE_HWY*/ /* Default to the C path. */ generate = morph->morph == VIPS_OPERATION_MORPHOLOGY_DILATE ? vips_dilate_gen : vips_erode_gen; g_object_set(morph, "out", vips_image_new(), NULL); if (vips_image_pipelinev(morph->out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; /* Prepare output. Consider a 7x7 mask and a 7x7 image -- the output * would be 1x1. */ morph->out->Xsize -= M->Xsize - 1; morph->out->Ysize -= M->Ysize - 1; if (vips_image_generate(morph->out, vips_morph_start, generate, vips_morph_stop, in, morph)) return -1; morph->out->Xoffset = -M->Xsize / 2; morph->out->Yoffset = -M->Ysize / 2; vips_reorder_margin_hint(morph->out, morph->n_point); return 0; } static void vips_morph_class_init(VipsMorphClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; #ifdef HAVE_ORC gobject_class->finalize = vips_morph_finalize; #endif /*HAVE_ORC*/ object_class->nickname = "morph"; object_class->description = _("morphology operation"); object_class->build = vips_morph_build; VIPS_ARG_IMAGE(class, "out", 10, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMorph, out)); VIPS_ARG_IMAGE(class, "mask", 20, _("Mask"), _("Input matrix image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMorph, mask)); VIPS_ARG_ENUM(class, "morph", 103, _("Morphology"), _("Morphological operation to perform"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMorph, morph), VIPS_TYPE_OPERATION_MORPHOLOGY, VIPS_OPERATION_MORPHOLOGY_ERODE); } static void vips_morph_init(VipsMorph *morph) { morph->morph = VIPS_OPERATION_MORPHOLOGY_ERODE; morph->coeff = NULL; } /** * vips_morph: (method) * @in: input image * @out: (out): output image * @mask: morphology with this mask * @morph: operation to perform * @...: `NULL`-terminated list of optional named arguments * * Performs a morphological operation on @in using @mask as a * structuring element. * * The image should have 0 (black) for no object and 255 * (non-zero) for an object. Note that this is the reverse of the usual * convention for these operations, but more convenient when combined with the * boolean operators. The output image is the same * size as the input image: edge pxels are made by expanding the input image * as necessary. * * Mask coefficients can be either 0 (for object) or 255 (for background) * or 128 (for do not care). The origin of the mask is at location * (m.xsize / 2, m.ysize / 2), integer division. All algorithms have been * based on the book "Fundamentals of Digital Image Processing" by A. Jain, * pp 384-388, Prentice-Hall, 1989. * * For [enum@Vips.OperationMorphology.ERODE], * the whole mask must match for the output pixel to be * set, that is, the result is the logical AND of the selected input pixels. * * For [enum@Vips.OperationMorphology.DILATE], * the output pixel is set if any part of the mask * matches, that is, the result is the logical OR of the selected input pixels. * * See the boolean operations [method@Image.andimage], [method@Image.orimage] * and [method@Image.eorimage] * for analogues of the usual set difference and set union operations. * * Operations are performed using the processor's vector unit, * if possible. Disable this with `--vips-novector` or `VIPS_NOVECTOR` or * [func@vector_set_enabled]. * * Returns: 0 on success, -1 on error */ int vips_morph(VipsImage *in, VipsImage **out, VipsImage *mask, VipsOperationMorphology morph, ...) { va_list ap; int result; va_start(ap, morph); result = vips_call_split("morph", ap, in, out, mask, morph); va_end(ap); return result; } libvips-8.18.2/libvips/morphology/morph_hwy.cpp000066400000000000000000000110551516303661500216610ustar00rootroot00000000000000/* 24/08/22 kleisauke * - initial implementation * 20/08/23 kleisauke * - speed-up implementation */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "pmorphology.h" #ifdef HAVE_HWY #undef HWY_TARGET_INCLUDE #define HWY_TARGET_INCLUDE "libvips/morphology/morph_hwy.cpp" #include #include namespace HWY_NAMESPACE { using namespace hwy::HWY_NAMESPACE; using DU8 = ScalableTag; constexpr DU8 du8; // Compat for Highway versions < 1.3.0 #ifndef HWY_LANES_CONSTEXPR #define HWY_LANES_CONSTEXPR #endif HWY_ATTR void vips_dilate_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int32_t sz, int32_t nn128, const int32_t *HWY_RESTRICT offsets, const uint8_t *HWY_RESTRICT coeff) { int32_t bo = VIPS_RECT_BOTTOM(r); HWY_LANES_CONSTEXPR int32_t N = Lanes(du8); const auto zero = Zero(du8); const auto one = Set(du8, 255); for (int32_t y = r->top; y < bo; ++y) { VipsPel *HWY_RESTRICT p = VIPS_REGION_ADDR(ir, r->left, y); VipsPel *HWY_RESTRICT q = VIPS_REGION_ADDR(out_region, r->left, y); /* Main loop: unrolled. */ int32_t x = 0; for (; x + N <= sz; x += N) { auto sum = zero; for (int32_t i = 0; i < nn128; ++i) { auto mmk = Set(du8, coeff[i]); /* Load with an offset. */ auto pix = LoadU(du8, p + offsets[i]); pix = IfThenElse(Ne(mmk, one), AndNot(pix, one), pix); sum = Or(sum, pix); } StoreU(sum, du8, q + x); p += N; } /* `ne` was not a multiple of the vector length `N`; * proceed one by one. */ for (; x < sz; ++x) { int32_t sum = 0; for (int32_t i = 0; i < nn128; ++i) sum |= !coeff[i] ? ~p[offsets[i]] : p[offsets[i]]; q[x] = sum; p += 1; } } } HWY_ATTR void vips_erode_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int32_t sz, int32_t nn128, const int32_t *HWY_RESTRICT offsets, const uint8_t *HWY_RESTRICT coeff) { int32_t bo = VIPS_RECT_BOTTOM(r); HWY_LANES_CONSTEXPR int32_t N = Lanes(du8); const auto one = Set(du8, 255); for (int32_t y = r->top; y < bo; ++y) { VipsPel *HWY_RESTRICT p = VIPS_REGION_ADDR(ir, r->left, y); VipsPel *HWY_RESTRICT q = VIPS_REGION_ADDR(out_region, r->left, y); /* Main loop: unrolled. */ int32_t x = 0; for (; x + N <= sz; x += N) { auto sum = one; for (int32_t i = 0; i < nn128; ++i) { auto mmk = Set(du8, coeff[i]); /* Load with an offset. */ auto pix = LoadU(du8, p + offsets[i]); pix = IfThenElse(Ne(mmk, one), AndNot(pix, one), pix); sum = And(sum, pix); } StoreU(sum, du8, q + x); p += N; } /* `ne` was not a multiple of the vector length `N`; * proceed one by one. */ for (; x < sz; ++x) { int32_t sum = 255; for (int32_t i = 0; i < nn128; ++i) sum &= !coeff[i] ? ~p[offsets[i]] : p[offsets[i]]; q[x] = sum; p += 1; } } } } /*namespace HWY_NAMESPACE*/ #if HWY_ONCE HWY_EXPORT(vips_dilate_uchar_hwy); HWY_EXPORT(vips_erode_uchar_hwy); void vips_dilate_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int sz, int nn128, int *restrict offsets, guint8 *restrict coeff) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_dilate_uchar_hwy)(out_region, ir, r, sz, nn128, offsets, coeff); /* clang-format on */ } void vips_erode_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int sz, int nn128, int *restrict offsets, guint8 *restrict coeff) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_erode_uchar_hwy)(out_region, ir, r, sz, nn128, offsets, coeff); /* clang-format on */ } #endif /*HWY_ONCE*/ #endif /*HAVE_HWY*/ libvips-8.18.2/libvips/morphology/morphology.c000066400000000000000000000047771516303661500215210ustar00rootroot00000000000000/* base class for all morphological operations * * properties: * - one input image */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "pmorphology.h" G_DEFINE_ABSTRACT_TYPE(VipsMorphology, vips_morphology, VIPS_TYPE_OPERATION); static void vips_morphology_class_init(VipsMorphologyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "morphology"; vobject_class->description = _("morphological operations"); operation_class->flags = VIPS_OPERATION_SEQUENTIAL; /* Inputs set by subclassess. */ VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMorphology, in)); } static void vips_morphology_init(VipsMorphology *morphology) { } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_morphology_operation_init(void) { extern GType vips_morph_get_type(void); extern GType vips_rank_get_type(void); extern GType vips_countlines_get_type(void); extern GType vips_labelregions_get_type(void); extern GType vips_fill_nearest_get_type(void); vips_morph_get_type(); vips_rank_get_type(); vips_countlines_get_type(); vips_labelregions_get_type(); vips_fill_nearest_get_type(); } libvips-8.18.2/libvips/morphology/nearest.c000066400000000000000000000210721516303661500207460ustar00rootroot00000000000000/* nearest.c * * 31/10/17 * - from labelregion */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pmorphology.h" /* A seed pixel. We fill outwards from each of these. */ typedef struct _Seed { int x; int y; int r; /* Bits saying which octant can still grow. When they are all zero, the * seed is dead. */ int octant_mask; } Seed; typedef struct _VipsFillNearest { VipsMorphology parent_instance; VipsImage *out; VipsImage *distance; /* Size of our image. */ int width; int height; /* All our seed pixels. There can be a lot of these. */ GArray *seeds; } VipsFillNearest; typedef VipsMorphologyClass VipsFillNearestClass; G_DEFINE_TYPE(VipsFillNearest, vips_fill_nearest, VIPS_TYPE_MORPHOLOGY); static void vips_fill_nearest_finalize(GObject *gobject) { VipsFillNearest *nearest = (VipsFillNearest *) gobject; VIPS_FREEF(g_array_unref, nearest->seeds); G_OBJECT_CLASS(vips_fill_nearest_parent_class)->finalize(gobject); } struct _Circle; typedef void (*VipsFillNearestPixel)(struct _Circle *circle, int x, int y, int octant); typedef struct _Circle { VipsFillNearest *nearest; Seed *seed; int octant_mask; VipsFillNearestPixel nearest_pixel; } Circle; static void vips_fill_nearest_pixel(Circle *circle, int x, int y, int octant) { float *p; float radius; int dx, dy; if ((circle->seed->octant_mask & (1 << octant)) == 0) return; /* We need to do this as float, or we'll have dithering along edges. */ p = (float *) VIPS_IMAGE_ADDR(circle->nearest->distance, x, y); dx = x - circle->seed->x; dy = y - circle->seed->y; radius = sqrtf(dx * dx + dy * dy); if (p[0] == 0 || p[0] > radius) { VipsMorphology *morphology = VIPS_MORPHOLOGY(circle->nearest); VipsImage *in = morphology->in; int ps = VIPS_IMAGE_SIZEOF_PEL(in); VipsPel *pi = VIPS_IMAGE_ADDR(in, circle->seed->x, circle->seed->y); VipsPel *qi = VIPS_IMAGE_ADDR(circle->nearest->out, x, y); int i; p[0] = radius; circle->octant_mask |= 1 << octant; for (i = 0; i < ps; i++) qi[i] = pi[i]; } } static void vips_fill_nearest_pixel_clip(Circle *circle, int x, int y, int octant) { if ((circle->seed->octant_mask & (1 << octant)) == 0) return; if (x >= 0 && x < circle->nearest->width && y >= 0 && y < circle->nearest->height) vips_fill_nearest_pixel(circle, x, y, octant); } static void vips_fill_nearest_scanline(VipsImage *image, int y, int x1, int x2, int quadrant, void *client) { Circle *circle = (Circle *) client; circle->nearest_pixel(circle, x1, y, quadrant); circle->nearest_pixel(circle, x2, y, quadrant + 4); /* We have to do one point back as well, or we'll leave gaps at * around 45 degrees. */ if (quadrant == 0) { circle->nearest_pixel(circle, x1, y - 1, quadrant); circle->nearest_pixel(circle, x2, y - 1, quadrant + 4); } else if (quadrant == 1) { circle->nearest_pixel(circle, x1, y + 1, quadrant); circle->nearest_pixel(circle, x2, y + 1, quadrant + 4); } else { circle->nearest_pixel(circle, x1 + 1, y, quadrant); circle->nearest_pixel(circle, x2 - 1, y, quadrant + 4); } } static void vips_fill_nearest_grow_seed(VipsFillNearest *nearest, Seed *seed) { Circle circle; circle.nearest = nearest; circle.seed = seed; circle.octant_mask = 0; if (seed->x - seed->r >= 0 && seed->x + seed->r < nearest->width && seed->y - seed->r >= 0 && seed->y + seed->r < nearest->height) circle.nearest_pixel = vips_fill_nearest_pixel; else circle.nearest_pixel = vips_fill_nearest_pixel_clip; vips__draw_circle_direct(nearest->distance, seed->x, seed->y, seed->r, vips_fill_nearest_scanline, &circle); /* Update the action_mask for this seed. Next time, we can skip any * octants where we failed to act this time. */ seed->octant_mask = circle.octant_mask; seed->r += 1; } static int vips_fill_nearest_build(VipsObject *object) { VipsMorphology *morphology = VIPS_MORPHOLOGY(object); VipsFillNearest *nearest = (VipsFillNearest *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); int ps; int x, y, i; if (VIPS_OBJECT_CLASS(vips_fill_nearest_parent_class)->build(object)) return -1; if (vips_image_wio_input(morphology->in)) return -1; nearest->width = morphology->in->Xsize; nearest->height = morphology->in->Ysize; ps = VIPS_IMAGE_SIZEOF_PEL(morphology->in); nearest->seeds = g_array_new(FALSE, FALSE, sizeof(Seed)); for (y = 0; y < nearest->height; y++) { VipsPel *p; p = VIPS_IMAGE_ADDR(morphology->in, 0, y); for (x = 0; x < nearest->width; x++) { for (i = 0; i < ps; i++) if (p[i]) break; if (i != ps) { Seed *seed; g_array_set_size(nearest->seeds, nearest->seeds->len + 1); seed = &g_array_index(nearest->seeds, Seed, nearest->seeds->len - 1); seed->x = x; seed->y = y; seed->r = 1; seed->octant_mask = 255; } p += ps; } } /* Create the output and distance images in memory. */ g_object_set(object, "distance", vips_image_new_memory(), NULL); if (vips_black(&t[0], nearest->width, nearest->height, NULL) || vips_cast(t[0], &t[1], VIPS_FORMAT_FLOAT, NULL) || vips_image_write(t[1], nearest->distance)) return -1; g_object_set(object, "out", vips_image_new_memory(), NULL); if (vips_image_write(morphology->in, nearest->out)) return -1; while (nearest->seeds->len > 0) { #ifdef DEBUG printf("looping for %d seeds ...\n", nearest->seeds->len); #endif /*DEBUG*/ /* Grow all seeds by one pixel. */ for (i = 0; i < nearest->seeds->len; i++) vips_fill_nearest_grow_seed(nearest, &g_array_index(nearest->seeds, Seed, i)); /* Remove dead seeds. */ i = 0; while (i < nearest->seeds->len) { Seed *seed = &g_array_index(nearest->seeds, Seed, i); if (seed->octant_mask == 0) g_array_remove_index_fast(nearest->seeds, i); else i += 1; } } return 0; } static void vips_fill_nearest_class_init(VipsFillNearestClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->finalize = vips_fill_nearest_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "fill_nearest"; vobject_class->description = _("fill image zeros with nearest non-zero pixel"); vobject_class->build = vips_fill_nearest_build; VIPS_ARG_IMAGE(class, "out", 2, _("Out"), _("Value of nearest non-zero pixel"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsFillNearest, out)); VIPS_ARG_IMAGE(class, "distance", 3, _("Distance"), _("Distance to nearest non-zero pixel"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsFillNearest, distance)); } static void vips_fill_nearest_init(VipsFillNearest *nearest) { } /** * vips_fill_nearest: (method) * @in: image to test * @out: image with zero pixels filled with the nearest non-zero pixel * @...: `NULL`-terminated list of optional named arguments * * Fill outwards from every non-zero pixel in @in, setting pixels in @distance * and @value. * * At the position of zero pixels in @in, @distance contains the distance to * the nearest non-zero pixel in @in, and @value contains the value of that * pixel. * * @distance is a one-band float image. @value has the same number of bands and * format as @in. * * ::: tip "Optional arguments" * * @distance: [class@Image], output, image of distance to nearest * non-zero pixel * * ::: seealso * [method@Image.hist_find_indexed]. * * Returns: 0 on success, -1 on error. */ int vips_fill_nearest(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("fill_nearest", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/morphology/pmorphology.h000066400000000000000000000043211516303661500216670ustar00rootroot00000000000000/* base class for all morphology operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PMORPHOLOGY_H #define VIPS_PMORPHOLOGY_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_MORPHOLOGY (vips_morphology_get_type()) #define VIPS_MORPHOLOGY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_MORPHOLOGY, VipsMorphology)) #define VIPS_MORPHOLOGY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_MORPHOLOGY, VipsMorphologyClass)) #define VIPS_IS_MORPHOLOGY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_MORPHOLOGY)) #define VIPS_IS_MORPHOLOGY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_MORPHOLOGY)) #define VIPS_MORPHOLOGY_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_MORPHOLOGY, VipsMorphologyClass)) typedef struct _VipsMorphology VipsMorphology; struct _VipsMorphology { VipsOperation parent_instance; VipsImage *in; }; typedef struct _VipsMorphologyClass { VipsOperationClass parent_class; } VipsMorphologyClass; GType vips_morphology_get_type(void); void vips_dilate_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int sz, int nn128, int *restrict offsets, guint8 *restrict coeff); void vips_erode_uchar_hwy(VipsRegion *out_region, VipsRegion *ir, VipsRect *r, int sz, int nn128, int *restrict offsets, guint8 *restrict coeff); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PMORPHOLOGY_H*/ libvips-8.18.2/libvips/morphology/rank.c000066400000000000000000000355061516303661500202470ustar00rootroot00000000000000/* Rank filter. * * Author: JC * Written on: 19/8/96 * Modified on: * JC 20/8/96 * - now uses insert-sort rather than bubble-sort * - now works for any non-complex type * JC 22/6/01 * - oops, sanity check on n wrong * JC 28/8/03 * - cleanups * - better selection algorithm ... same speed for 3x3, about 3x faster * for 5x5, faster still for larger windows * - index from zero for consistency with other parts of vips * 7/4/04 * - now uses im_embed() with edge stretching on the input, not * the output * - sets Xoffset / Yoffset * 7/10/04 * - oops, im_embed() size was wrong * 10/11/10 * - cleanups * - gtk-doc * 17/1/14 * - redone as a class * 12/11/16 * - oop, allow index == 0, thanks Rob * 12/1/21 * - add hist path for large windows on uchar images */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pmorphology.h" typedef struct _VipsRank { VipsMorphology parent_instance; VipsImage *out; int width; int height; int index; int n; gboolean hist_path; } VipsRank; typedef VipsMorphologyClass VipsRankClass; G_DEFINE_TYPE(VipsRank, vips_rank, VIPS_TYPE_MORPHOLOGY); /* Sequence value: just the array we sort in. */ typedef struct { VipsRegion *ir; /* Sort array. */ VipsPel *sort; /* For large uchar images, the sort histogram. */ unsigned int **hist; } VipsRankSequence; static int vips_rank_stop(void *vseq, void *a, void *b) { VipsRankSequence *seq = (VipsRankSequence *) vseq; VipsImage *in = (VipsImage *) a; VIPS_UNREF(seq->ir); VIPS_FREE(seq->sort); if (seq->hist && in) for (int i = 0; i < in->Bands; i++) VIPS_FREE(seq->hist[i]); VIPS_FREE(seq->hist); return 0; } static void * vips_rank_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsRank *rank = (VipsRank *) b; VipsRankSequence *seq; if (!(seq = VIPS_NEW(out, VipsRankSequence))) return NULL; seq->ir = NULL; seq->sort = NULL; seq->hist = NULL; seq->ir = vips_region_new(in); if (!(seq->sort = VIPS_ARRAY(NULL, VIPS_IMAGE_SIZEOF_ELEMENT(in) * rank->n, VipsPel))) { vips_rank_stop(seq, in, rank); return NULL; } if (rank->hist_path) { if (!(seq->hist = VIPS_ARRAY(NULL, in->Bands, unsigned int *))) { vips_rank_stop(seq, in, rank); return NULL; } for (int i = 0; i < in->Bands; i++) if (!(seq->hist[i] = VIPS_ARRAY(NULL, 256, unsigned int))) { vips_rank_stop(seq, in, rank); return NULL; } } return (void *) seq; } /* Histogram path for large uchar ranks. */ static void vips_rank_generate_uchar(VipsRegion *out_region, VipsRankSequence *seq, VipsRank *rank, int y) { VipsImage *in = seq->ir->im; VipsRect *r = &out_region->valid; const int bands = in->Bands; const int lsk = VIPS_REGION_LSKIP(seq->ir); /* Get input and output pointers for this line. */ VipsPel *restrict p = VIPS_REGION_ADDR(seq->ir, r->left, r->top + y); VipsPel *restrict q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); VipsPel *restrict p1; /* Find histogram for the first output pixel. */ for (int b = 0; b < bands; b++) memset(seq->hist[b], 0, 256 * sizeof(unsigned int)); p1 = p; for (int j = 0; j < rank->height; j++) { int i; i = 0; for (int x = 0; x < rank->width; x++) for (int b = 0; b < bands; b++, i++) seq->hist[b][p1[i]] += 1; p1 += lsk; } /* Loop for output pels. */ for (int x = 0; x < r->width; x++) { for (int b = 0; b < bands; b++) { /* Calculate cumulative histogram -- the value is the * index at which we pass the rank. */ unsigned int *restrict hist = seq->hist[b]; int sum; int value; sum = 0; for (value = 0; value < 256; value++) { sum += hist[value]; if (sum > rank->index) break; } q[b] = value; /* Adapt histogram -- remove the pels from the left hand column, * add in pels for a new right-hand column. */ const int next = bands * rank->width; p1 = p + b; for (int j = 0; j < rank->height; j++) { hist[p1[0]] -= 1; hist[p1[next]] += 1; p1 += lsk; } } p += bands; q += bands; } } /* Inner loop for select-sorting TYPE. */ #define LOOP_SELECT(TYPE) \ { \ TYPE *q = (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); \ TYPE *p = (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top + y); \ TYPE *sort = (TYPE *) seq->sort; \ TYPE a; \ \ for (x = 0; x < sz; x++) { \ TYPE *d = p + x; \ \ /* Copy window into sort[]. \ */ \ for (k = 0, j = 0; j < rank->height; j++) { \ for (i = 0; i < eaw; i += bands, k++) \ sort[k] = d[i]; \ d += ls; \ } \ \ /* Rearrange sort[] to make the index-th element the index-th \ * smallest, adapted from Numerical Recipes in C. \ */ \ lower = 0; /* Range we know the result lies in */ \ upper = rank->n - 1; \ for (;;) { \ if (upper - lower < 2) { \ /* 1 or 2 elements left. \ */ \ if (upper - lower == 1 && \ sort[lower] > sort[upper]) \ VIPS_SWAP(TYPE, \ sort[lower], sort[upper]); \ break; \ } \ else { \ /* Pick mid-point of remaining elements. \ */ \ mid = (lower + upper) >> 1; \ \ /* Sort lower/mid/upper elements, hold \ * midpoint in sort[lower + 1] for \ * partitioning. \ */ \ VIPS_SWAP(TYPE, sort[lower + 1], sort[mid]); \ if (sort[lower] > sort[upper]) \ VIPS_SWAP(TYPE, \ sort[lower], sort[upper]); \ if (sort[lower + 1] > sort[upper]) \ VIPS_SWAP(TYPE, \ sort[lower + 1], sort[upper]); \ if (sort[lower] > sort[lower + 1]) \ VIPS_SWAP(TYPE, \ sort[lower], sort[lower + 1]); \ \ i = lower + 1; \ j = upper; \ a = sort[lower + 1]; \ \ for (;;) { \ /* Search for out of order elements. \ */ \ do \ i++; \ while (sort[i] < a); \ do \ j--; \ while (sort[j] > a); \ if (j < i) \ break; \ VIPS_SWAP(TYPE, sort[i], sort[j]); \ } \ \ /* Replace mid element. \ */ \ sort[lower + 1] = sort[j]; \ sort[j] = a; \ \ /* Move to partition with the kth element. \ */ \ if (j >= rank->index) \ upper = j - 1; \ if (j <= rank->index) \ lower = i; \ } \ } \ \ q[x] = sort[rank->index]; \ } \ } /* Loop for find max of window. */ #define LOOP_MAX(TYPE) \ { \ TYPE *q = (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); \ TYPE *p = (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top + y); \ \ for (x = 0; x < sz; x++) { \ TYPE *d = &p[x]; \ TYPE max; \ \ max = *d; \ for (j = 0; j < rank->height; j++) { \ TYPE *e = d; \ \ for (i = 0; i < rank->width; i++) { \ if (*e > max) \ max = *e; \ \ e += bands; \ } \ \ d += ls; \ } \ \ q[x] = max; \ } \ } /* Loop for find min of window. */ #define LOOP_MIN(TYPE) \ { \ TYPE *q = (TYPE *) VIPS_REGION_ADDR(out_region, r->left, r->top + y); \ TYPE *p = (TYPE *) VIPS_REGION_ADDR(ir, r->left, r->top + y); \ \ for (x = 0; x < sz; x++) { \ TYPE *d = &p[x]; \ TYPE min; \ \ min = *d; \ for (j = 0; j < rank->height; j++) { \ TYPE *e = d; \ \ for (i = 0; i < rank->width; i++) { \ if (*e < min) \ min = *e; \ \ e += bands; \ } \ \ d += ls; \ } \ \ q[x] = min; \ } \ } #define SWITCH(OPERATION) \ switch (rank->out->BandFmt) { \ case VIPS_FORMAT_UCHAR: \ OPERATION(unsigned char); \ break; \ case VIPS_FORMAT_CHAR: \ OPERATION(signed char); \ break; \ case VIPS_FORMAT_USHORT: \ OPERATION(unsigned short); \ break; \ case VIPS_FORMAT_SHORT: \ OPERATION(signed short); \ break; \ case VIPS_FORMAT_UINT: \ OPERATION(unsigned int); \ break; \ case VIPS_FORMAT_INT: \ OPERATION(signed int); \ break; \ case VIPS_FORMAT_FLOAT: \ OPERATION(float); \ break; \ case VIPS_FORMAT_DOUBLE: \ OPERATION(double); \ break; \ \ default: \ g_assert_not_reached(); \ } static int vips_rank_generate(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsRankSequence *seq = (VipsRankSequence *) vseq; VipsRegion *ir = seq->ir; VipsImage *in = (VipsImage *) a; VipsRank *rank = (VipsRank *) b; int bands = in->Bands; int eaw = rank->width * bands; /* elements across window */ int sz = VIPS_REGION_N_ELEMENTS(out_region); VipsRect s; int ls; int x; int i, j, k; int upper, lower, mid; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += rank->width - 1; s.height += rank->height - 1; if (vips_region_prepare(ir, &s)) return -1; ls = VIPS_REGION_LSKIP(ir) / VIPS_IMAGE_SIZEOF_ELEMENT(in); for (int y = 0; y < r->height; y++) { if (rank->hist_path) vips_rank_generate_uchar(out_region, seq, rank, y); else if (rank->index == 0) SWITCH(LOOP_MIN) else if (rank->index == rank->n - 1) SWITCH(LOOP_MAX) else SWITCH(LOOP_SELECT) } return 0; } static int vips_rank_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsMorphology *morphology = VIPS_MORPHOLOGY(object); VipsRank *rank = (VipsRank *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); VipsImage *in; if (VIPS_OBJECT_CLASS(vips_rank_parent_class)->build(object)) return -1; in = morphology->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (vips_check_noncomplex(class->nickname, in)) return -1; if (rank->width > in->Xsize || rank->height > in->Ysize) { vips_error(class->nickname, "%s", _("window too large")); return -1; } rank->n = rank->width * rank->height; if (rank->index < 0 || rank->index > rank->n - 1) { vips_error(class->nickname, "%s", _("index out of range")); return -1; } /* Enable the hist path if it'll probably help. */ if (in->BandFmt == VIPS_FORMAT_UCHAR) { /* The hist path is always faster for windows larger than about * 10x10, and faster for >3x3 on the non-max/min case. */ if (rank->n > 90) rank->hist_path = TRUE; else if (rank->n > 10 && rank->index != 0 && rank->index != rank->n - 1) rank->hist_path = TRUE; } /* Expand the input. */ if (vips_embed(in, &t[1], rank->width / 2, rank->height / 2, in->Xsize + rank->width - 1, in->Ysize + rank->height - 1, "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[1]; g_object_set(object, "out", vips_image_new(), NULL); /* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause * too many recalculations on overlaps. */ if (vips_image_pipelinev(rank->out, VIPS_DEMAND_STYLE_FATSTRIP, in, NULL)) return -1; rank->out->Xsize -= rank->width - 1; rank->out->Ysize -= rank->height - 1; if (vips_image_generate(rank->out, vips_rank_start, vips_rank_generate, vips_rank_stop, in, rank)) return -1; rank->out->Xoffset = 0; rank->out->Yoffset = 0; vips_reorder_margin_hint(rank->out, rank->width * rank->height); return 0; } static void vips_rank_class_init(VipsRankClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "rank"; object_class->description = _("rank filter"); object_class->build = vips_rank_build; VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsRank, out)); VIPS_ARG_INT(class, "width", 4, _("Width"), _("Window width in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRank, width), 1, 100000, 11); VIPS_ARG_INT(class, "height", 5, _("Height"), _("Window height in pixels"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRank, height), 1, 100000, 11); VIPS_ARG_INT(class, "index", 6, _("Index"), _("Select pixel at index"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRank, index), 0, 100000000, 50); } static void vips_rank_init(VipsRank *rank) { rank->width = 11; rank->height = 11; rank->index = 50; } /** * vips_rank: (method) * @in: input image * @out: (out): output image * @width: width of region * @height: height of region * @index: select pixel * @...: `NULL`-terminated list of optional named arguments * * [method@Image.rank] does rank filtering on an image. A window of size @width by * @height is passed over the image. At each position, the pixels inside the * window are sorted into ascending order and the pixel at position @index is * output. @index numbers from 0. * * It works for any non-complex image type, with any number of bands. * The input is expanded by copying edge pixels before performing the * operation so that the output image has the same size as the input. * Edge pixels in the output image are therefore only approximate. * * For a median filter with mask size m (3 for 3x3, 5 for 5x5, etc.) use * * ```c * vips_rank(in, out, m, m, m * m / 2); * ``` * * The special cases n == 0 and n == m * m - 1 are useful dilate and * expand operators. * * ::: seealso * [method@Image.conv], [method@Image.median], [method@Image.spcor]. * * Returns: 0 on success, -1 on error */ int vips_rank(VipsImage *in, VipsImage **out, int width, int height, int index, ...) { va_list ap; int result; va_start(ap, index); result = vips_call_split("rank", ap, in, out, width, height, index); va_end(ap); return result; } /** * vips_median: (method) * @in: input image * @out: (out): output image * @size: size of region * @...: `NULL`-terminated list of optional named arguments * * A convenience function equivalent to: * * ```c * vips_rank(in, out, size, size, (size * size) / 2); * ``` * * ::: seealso * [method@Image.rank]. * * Returns: 0 on success, -1 on error */ int vips_median(VipsImage *in, VipsImage **out, int size, ...) { va_list ap; int result; va_start(ap, size); result = vips_call_split("rank", ap, in, out, size, size, (size * size) / 2); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/000077500000000000000000000000001516303661500167115ustar00rootroot00000000000000libvips-8.18.2/libvips/mosaicing/chkpair.c000066400000000000000000000132261516303661500205020ustar00rootroot00000000000000/* find image overlaps * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 02/05/1990 * Modified on : 18/04/1991 * 8/7/93 JC * - allows IM_CODING_LABQ coding * - now calls im_incheck() * 13/7/95 JC * - rewritten * - now uses im_spcor() * 13/8/96 JC * - order of args changed to help C++ API * 24/1/11 * - gtk-doc * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" /* vips__correl: * @ref: reference image * @sec: secondary image * @xref: position in reference image * @yref: position in reference image * @xsec: position in secondary image * @ysec: position in secondary image * @hwindowsize: half window size * @hsearchsize: half search size * @correlation: return detected correlation * @x: return found position * @y: return found position * * This operation finds the position of @sec within @ref. * * The area around * (@xsec, @ysec) is searched for the best match to the area around (@xref, * @yref). It searches an area of size @hsearchsize for a * match of size @hwindowsize. The position of the best match is * returned, together with the correlation at that point. * * Only the first band of each image is correlated. @ref and @sec may be * very large -- the function extracts and generates just the * parts needed. Correlation is done with [method@Image.spcor]; the position * of the maximum is found with [method@Image.max]. * * ::: seealso * [method@Image.match], [method@Image.mosaic]. * * Returns: 0 on success, -1 on error */ int vips__correl(VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, double *correlation, int *x, int *y) { VipsImage *surface = vips_image_new(); VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(surface), 5); VipsRect refr, secr; VipsRect winr, srhr; VipsRect wincr, srhcr; /* Find position of window and search area, and clip against image * size. */ refr.left = 0; refr.top = 0; refr.width = ref->Xsize; refr.height = ref->Ysize; winr.left = xref - hwindowsize; winr.top = yref - hwindowsize; winr.width = hwindowsize * 2 + 1; winr.height = hwindowsize * 2 + 1; vips_rect_intersectrect(&refr, &winr, &wincr); secr.left = 0; secr.top = 0; secr.width = sec->Xsize; secr.height = sec->Ysize; srhr.left = xsec - hsearchsize; srhr.top = ysec - hsearchsize; srhr.width = hsearchsize * 2 + 1; srhr.height = hsearchsize * 2 + 1; vips_rect_intersectrect(&secr, &srhr, &srhcr); /* Extract window and search area. */ if (vips_extract_area(ref, &t[0], wincr.left, wincr.top, wincr.width, wincr.height, NULL) || vips_extract_area(sec, &t[1], srhcr.left, srhcr.top, srhcr.width, srhcr.height, NULL)) { g_object_unref(surface); return -1; } ref = t[0]; sec = t[1]; /* Make sure we have just one band. From vips_*mosaic() we will, but * from vips_match() etc. we may not. */ if (ref->Bands != 1) { if (vips_extract_band(ref, &t[2], 0, NULL)) { g_object_unref(surface); return -1; } ref = t[2]; } if (sec->Bands != 1) { if (vips_extract_band(sec, &t[3], 0, NULL)) { g_object_unref(surface); return -1; } sec = t[3]; } /* Search! */ if (vips_spcor(sec, ref, &t[4], NULL)) { g_object_unref(surface); return -1; } /* Find maximum of correlation surface. */ if (vips_max(t[4], correlation, "x", x, "y", y, NULL)) { g_object_unref(surface); return -1; } g_object_unref(surface); /* Translate back to position within sec. */ *x += srhcr.left; *y += srhcr.top; return 0; } int vips__chkpair(VipsImage *ref, VipsImage *sec, TiePoints *points) { int i; int x, y; double correlation; const int hcor = points->halfcorsize; const int harea = points->halfareasize; /* Check images. */ if (vips_image_wio_input(ref) || vips_image_wio_input(sec)) return -1; if (ref->Bands != sec->Bands || ref->BandFmt != sec->BandFmt || ref->Coding != sec->Coding) { vips_error("vips_chkpair", "%s", _("inputs incompatible")); return -1; } if (ref->Bands != 1 || ref->BandFmt != VIPS_FORMAT_UCHAR) { vips_error("vips_chkpair", "%s", _("help!")); return -1; } for (i = 0; i < points->nopoints; i++) { /* Find correlation point. */ if (vips__correl(ref, sec, points->x_reference[i], points->y_reference[i], points->x_reference[i], points->y_reference[i], hcor, harea, &correlation, &x, &y)) return -1; /* And note in x_secondary. */ points->x_secondary[i] = x; points->y_secondary[i] = y; points->correlation[i] = correlation; /* Note each dx, dy too. */ points->dx[i] = points->x_secondary[i] - points->x_reference[i]; points->dy[i] = points->y_secondary[i] - points->y_reference[i]; } return 0; } libvips-8.18.2/libvips/mosaicing/global_balance.c000066400000000000000000001262001516303661500217630ustar00rootroot00000000000000/* Parse ".desc" files from mosaiced images to generate (x,y) offsets for * every sub-image. Find all overlap stats and solve balancing with LMS. * Regenerate mosaic, with balancing fixed. * * 1/12/93 JC * - first version, unfinished! * 6/9/95 JC * - LMS fixed, now works, more or less * 12/9/95 JC * - now does positions correctly too * - ignores trivial overlaps * 19/9/95 JC * - prints correct number of balance factors! * 10/11/95 JC * - now tracks im_copy() calls too, so you can save sub-images * 12/1/96 JC * - slightly clearer diagnostics * - better centre of factors around 1.0 with log() average * 1/3/96 JC * - new im_global_balance_float variant lets our caller adjust factor * range if output has burn-out * - im_global_balance_search uses the above to produce scaled output ... * very slow! * 11/3/96 JC * - now tries current directory too for input files * 22/3/96 JC * - horrible bug in position finding! now fixed * 1/8/97 JC * - revised for new mosaic functions and non-square images * 12/9/97 JC * - code for im_lrmosaic1() support * - output type == input type, so works for short images too * 6/1/99 JC * - new gamma parameter, do scale in linear space * - removed _search version, as can now be done with ip * - renamed _float to f suffix, in line with im_conv()/im_convf() * 15/2/00 JC * - balancef() did not scale in linear space * 2/2/01 JC * - added tunable max blend width * 7/11/01 JC * - global_balance.h broken out for im_remosaic() * 25/02/02 JC * - better transform function scheme * 21/3/01 JC * - quicker bailout on error * 8/11/02 JC * - add <> around file names so you can have spaces :( * 9/12/02 JC * - track original params and always reuse them ... makes us proof * against geo reconstruct errors * 10/3/03 JC * - weed out overlaps which contain only transparent pixels * 4/1/07 * - switch to new history thing, switch im_errormsg() too * 24/1/11 * - gtk-doc * 12/7/12 * - always allocate local to an output descriptor ... stops ref cycles * with the new base class * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Strategy: build a tree describing the file * relationships in the desc file, then walk that passing constraints * back up to the root. Look up file names in symbol_table. */ /* Define for debug output. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "pmosaicing.h" #include "global_balance.h" #define MAX_ITEMS (50) /* How pix an overlap has to be (in pixels) before we think it's trivial and * we ignore it. */ #define TRIVIAL (20 * 20) /* Break a string into a list of strings. Write '\0's into the string. out * needs to be MAX_FILES long. -1 for error, otherwise number of args found. " " out[0] = "fred" out[1] = "jim poop" out[2] = "sn aff le" */ static int break_items(char *line, char **out) { int i; char *p; for (i = 0; i < MAX_ITEMS; i++) { /* Skip to first '<'. */ if (!(p = strchr(line, '<'))) break; out[i] = line = p + 1; if (!(p = strchr(line, '>'))) { vips_error("break_files", "%s", _("no matching '>'")); return -1; } *p = '\0'; line = p + 1; } if (i == MAX_ITEMS) { vips_error("break_files", "%s", _("too many items")); return -1; } return i; } /* Try to open a file. If full path fails, try the current directory. */ VipsImage * vips__global_open_image(SymbolTable *st, char *name) { char *basename; VipsImage *image; if (!(image = vips_image_new_from_file(name, NULL))) { /* TODO(kleisauke): Is this behavior the same as im_skip_dir? * i.e. could we open a filename which came * from a win32 (`\\`) on a *nix machine? */ basename = g_path_get_basename(name); if (!(image = vips_image_new_from_file(basename, NULL))) { g_free(basename); return NULL; } g_free(basename); } vips_object_local(st->im, image); return image; } static void junk_node(VipsImage *image, JoinNode *node) { VIPS_FREEF(g_slist_free, node->overlaps); } /* Hash from a filename to an index into symbol_table. */ static int hash(char *n) { int i; int r = 0; int l = strlen(n); for (i = 0; i < l; i++) r = ((r + n[i]) * 43) & 0xffffff; return r % SYM_TAB_SIZE; } /* Make a leaf for a file. */ static JoinNode * build_node(SymbolTable *st, char *name) { JoinNode *node = VIPS_NEW(st->im, JoinNode); int n = hash(name); /* Fill fields. */ if (!node || !(node->name = vips_strdup(VIPS_OBJECT(st->im), name))) return NULL; node->type = JOIN_LEAF; node->dirty = 0; node->mwidth = -2; node->st = st; vips__transform_init(&node->cumtrn); node->trnim = NULL; node->arg1 = NULL; node->arg2 = NULL; node->overlaps = NULL; node->im = NULL; node->index = 0; g_signal_connect(st->im, "close", G_CALLBACK(junk_node), node); /* Try to open. */ if ((node->im = vips__global_open_image(st, name))) { /* There is a file there - set width and height. */ node->cumtrn.oarea.width = node->im->Xsize; node->cumtrn.oarea.height = node->im->Ysize; } else { /* Clear the error buffer to lessen confusion. */ vips_error_clear(); } st->table[n] = g_slist_prepend(st->table[n], node); return node; } /* Make a new overlap struct. */ static OverlapInfo * build_overlap(JoinNode *node, JoinNode *other, VipsRect *overlap) { OverlapInfo *lap = VIPS_NEW(node->st->im, OverlapInfo); if (!lap) return NULL; lap->node = node; lap->other = other; lap->overlap = *overlap; lap->nstats = NULL; lap->ostats = NULL; node->overlaps = g_slist_prepend(node->overlaps, lap); node->st->novl++; return lap; } static void overlap_destroy(OverlapInfo *lap) { JoinNode *node = lap->node; node->overlaps = g_slist_remove(node->overlaps, lap); g_assert(node->st->novl > 0); node->st->novl--; } static void junk_table(VipsImage *image, SymbolTable *st) { int i; for (i = 0; i < st->sz; i++) VIPS_FREEF(g_slist_free, st->table[i]); } /* Build a new symbol table. */ SymbolTable * vips__build_symtab(VipsImage *out, int sz) { SymbolTable *st = VIPS_NEW(out, SymbolTable); int i; if (!st || !(st->table = VIPS_ARRAY(out, sz, GSList *))) return NULL; st->sz = sz; st->im = out; st->novl = 0; st->nim = 0; st->njoin = 0; st->root = NULL; st->leaf = NULL; st->fac = NULL; g_signal_connect(out, "close", G_CALLBACK(junk_table), st); for (i = 0; i < sz; i++) st->table[i] = NULL; return st; } /* Does this node have this file name? */ static JoinNode * test_name(JoinNode *node, char *name, void *b) { if (strcmp(node->name, name) == 0) return node; else return NULL; } /* Look up a filename in the symbol_table. */ static JoinNode * find_node(SymbolTable *st, char *name) { return vips_slist_map2(st->table[hash(name)], (VipsSListMap2Fn) test_name, name, NULL); } /* Given a name: return either the existing node for that name, or a new node * we have made. */ static JoinNode * add_node(SymbolTable *st, char *name) { JoinNode *node; if (!(node = find_node(st, name)) && !(node = build_node(st, name))) return NULL; return node; } /* Map a user function over the whole of the symbol table. */ void * vips__map_table(SymbolTable *st, VipsSListMap2Fn fn, void *a, void *b) { int i; void *r; for (i = 0; i < st->sz; i++) if ((r = vips_slist_map2(st->table[i], fn, a, b))) return r; return NULL; } /* Set the dirty field on a join. */ static void * set_dirty(JoinNode *node, int state, void *b) { node->dirty = state; return NULL; } /* Clean the whole table. */ static void clean_table(SymbolTable *st) { (void) vips__map_table(st, (VipsSListMap2Fn) set_dirty, (void *) 0, NULL); } /* Do geometry calculations on a node, assuming geo is up to date for any * children. */ static void calc_geometry(JoinNode *node) { VipsRect um; switch (node->type) { case JOIN_LR: case JOIN_TB: case JOIN_LRROTSCALE: case JOIN_TBROTSCALE: /* Join two areas. */ vips_rect_unionrect(&node->arg1->cumtrn.oarea, &node->arg2->cumtrn.oarea, &um); node->cumtrn.iarea.left = 0; node->cumtrn.iarea.top = 0; node->cumtrn.iarea.width = um.width; node->cumtrn.iarea.height = um.height; vips__transform_set_area(&node->cumtrn); break; case JOIN_CP: /* Copy from child. */ node->cumtrn = node->arg1->cumtrn; break; case JOIN_LEAF: /* Just use leaf dimensions, if there are any. */ if (node->im) { node->cumtrn.iarea.left = 0; node->cumtrn.iarea.top = 0; node->cumtrn.iarea.width = node->im->Xsize; node->cumtrn.iarea.height = node->im->Ysize; vips__transform_set_area(&node->cumtrn); } break; default: vips_error_exit("internal error #98356"); /*NOTREACHED*/ } } /* Propagate a transform down a tree. If dirty is set, we've been here before, * so there is a doubling up of this node. If this is a leaf, then we have the * same leaf twice (which, in fact, we can cope with); if this is a node, we * have circularity. */ static int propagate_transform(JoinNode *node, VipsTransformation *trn) { if (!node) return 0; if (node->dirty && node->arg1 && node->arg2) { vips_error("vips_global_balance", "%s", _("circularity detected")); return -1; } node->dirty = 1; /* Transform our children. */ if (propagate_transform(node->arg1, trn) || propagate_transform(node->arg2, trn)) return -1; /* Transform us, and recalculate our position and size. */ vips__transform_add(&node->cumtrn, trn, &node->cumtrn); calc_geometry(node); return 0; } /* Ah ha! A leaf is actually made up of two smaller files with an lr or a tb * merge. Turn a leaf node into a join node. Propagate the transform down * arg2's side of the tree. */ static int make_join(SymbolTable *st, JoinType type, JoinNode *arg1, JoinNode *arg2, JoinNode *out, double a, double b, double dx, double dy, int mwidth) { VipsTransformation trn; /* Check output is ok. */ if (out->type != JOIN_LEAF) { vips_error("vips_global_balance", _("image \"%s\" used twice as output"), out->name); return -1; } /* Fill fields. */ out->type = type; out->mwidth = mwidth; out->a = a; out->b = b; out->dx = dx; out->dy = dy; out->arg1 = arg1; out->arg2 = arg2; out->thistrn.a = a; out->thistrn.b = -b; out->thistrn.c = b; out->thistrn.d = a; out->thistrn.idx = 0; out->thistrn.idy = 0; out->thistrn.odx = dx; out->thistrn.ody = dy; /* Clean the table and propagate the transform down the RHS of the * graph. */ clean_table(st); if (propagate_transform(arg2, &out->thistrn)) return -1; /* Find the position and size of our output. */ calc_geometry(out); /* Now normalise the result, so that out is at (0,0) again. */ trn.a = 1.0; trn.b = 0.0; trn.c = 0.0; trn.d = 1.0; trn.idx = 0; trn.idy = 0; trn.odx = -out->cumtrn.oarea.left; trn.ody = -out->cumtrn.oarea.top; clean_table(st); if (propagate_transform(out, &trn)) return -1; return 0; } /* Make a copy node. */ static int make_copy(SymbolTable *st, JoinNode *before, JoinNode *after) { /* Check output is ok. */ if (after->type != JOIN_LEAF) { vips_error("vips_global_balance", _("image \"%s\" used twice as output"), after->name); return -1; } /* Fill fields. */ after->type = JOIN_CP; after->arg1 = before; after->arg2 = NULL; /* Copy over the position and size from the before to the after. */ calc_geometry(after); return 0; } /* Process a single .desc line. */ static int process_line(SymbolTable *st, const char *text) { char line[1024]; #ifdef DEBUG printf("read: %s\n", text); #endif /*DEBUG*/ /* We destroy line during the parse. */ g_strlcpy(line, text, 1024); if (vips_isprefix("#LRJOIN ", line) || vips_isprefix("#TBJOIN ", line)) { /* Yes: magic join command. Break into tokens. Format is eg. #LRJOIN [] */ char *item[MAX_ITEMS]; int nitems; JoinType type; JoinNode *arg1, *arg2, *join; int dx, dy, mwidth; if ((nitems = break_items(line, item)) < 0) return -1; if (nitems != 5 && nitems != 6) { vips_error("global_balance", "%s", _("bad number of args in join line")); return -1; } if (!(arg1 = add_node(st, item[0])) || !(arg2 = add_node(st, item[1])) || !(join = add_node(st, item[2]))) return -1; dx = atoi(item[3]); dy = atoi(item[4]); if (nitems == 6) mwidth = atoi(item[5]); else mwidth = -1; if (vips_isprefix("#LRJOIN ", line)) type = JOIN_LR; else type = JOIN_TB; if (make_join(st, type, arg1, arg2, join, 1.0, 0.0, dx, dy, mwidth)) return -1; } else if (vips_isprefix("#LRROTSCALE ", line) || vips_isprefix("#TBROTSCALE ", line)) { /* Rot + scale. Format is eg. #LRROTSCALE \ [] */ char *item[MAX_ITEMS]; int nitems; JoinType type; JoinNode *arg1, *arg2, *join; double a, b, dx, dy; int mwidth; if ((nitems = break_items(line, item)) < 0) return -1; if (nitems != 7 && nitems != 8) { vips_error("global_balance", "%s", _("bad number of args in join1 line")); return -1; } if (!(arg1 = add_node(st, item[0])) || !(arg2 = add_node(st, item[1])) || !(join = add_node(st, item[2]))) return -1; a = g_ascii_strtod(item[3], NULL); b = g_ascii_strtod(item[4], NULL); dx = g_ascii_strtod(item[5], NULL); dy = g_ascii_strtod(item[6], NULL); if (nitems == 8) mwidth = atoi(item[7]); else mwidth = -1; if (vips_isprefix("#LRROTSCALE ", line)) type = JOIN_LRROTSCALE; else type = JOIN_TBROTSCALE; if (make_join(st, type, arg1, arg2, join, a, b, dx, dy, mwidth)) return -1; } else if (vips_isprefix("copy ", line)) { /* vips_copy() call ... make a JOIN_CP node. */ char *item[MAX_ITEMS]; int nitems; JoinNode *before, *after; if ((nitems = break_items(line, item)) < 0) return -1; if (nitems != 2) { vips_error("global_balance", "%s", _("bad number of args in copy line")); return -1; } if (!(before = add_node(st, item[0])) || !(after = add_node(st, item[1])) || make_copy(st, before, after)) return -1; } return 0; } /* Set the dirty flag on any nodes we reference. */ static void * set_referenced(JoinNode *node, void *a, void *b) { if (node->arg1) node->arg1->dirty = 1; if (node->arg2) node->arg2->dirty = 1; return NULL; } /* Is this a root node? Should be clean. */ static void * is_root(JoinNode *node, void *a, void *b) { if (!node->dirty) return (void *) node; else return NULL; } /* Scan the symbol table, looking for a node which no node references. */ static JoinNode * find_root(SymbolTable *st) { JoinNode *root; /* Clean the table, then scan it, setting all pointed-to nodes dirty. */ clean_table(st); vips__map_table(st, (VipsSListMap2Fn) set_referenced, NULL, NULL); /* Look for the first clean symbol. */ root = (JoinNode *) vips__map_table(st, (VipsSListMap2Fn) is_root, NULL, NULL); /* No root? Hot dang! */ if (!root) { vips_error("vips_global_balance", "%s", _("mosaic root not found in desc file\n" "is this really a mosaiced image?")); return NULL; } /* Now dirty that - then if there are any more clean symbols, we have * more than one root. */ root->dirty = 1; if (vips__map_table(st, (VipsSListMap2Fn) is_root, NULL, NULL)) { vips_error("vips_global_balance", "%s", _("more than one root")); return NULL; } return root; } /* Walk history_list and parse each line. */ int vips__parse_desc(SymbolTable *st, VipsImage *in) { GSList *p; for (p = in->history_list; p; p = p->next) { GValue *value = (GValue *) p->data; g_assert(G_VALUE_TYPE(value) == VIPS_TYPE_REF_STRING); if (process_line(st, vips_value_get_ref_string(value, NULL))) return -1; } /* Find root. */ if (!(st->root = find_root(st))) return -1; return 0; } /* Count and index all leaf images. */ static void * count_leaves(JoinNode *node, void *a, void *b) { if (node->type == JOIN_LEAF) { node->index = node->st->nim; node->st->nim++; } return NULL; } #ifdef DEBUG /* Print a JoinNode. */ static void print_node(JoinNode *node) { char *basename = g_path_get_basename(node->name); printf("%s, position %dx%d, size %dx%d, index %d\n", basename, node->cumtrn.oarea.left, node->cumtrn.oarea.top, node->cumtrn.oarea.width, node->cumtrn.oarea.height, node->index); g_free(basename); } #endif /*DEBUG*/ #ifdef DEBUG /* Print a leaf. */ static void * print_leaf(JoinNode *node, void *a, void *b) { if (node->type == JOIN_LEAF) print_node(node); return NULL; } #endif /*DEBUG*/ /* Count all join nodes. */ static void * count_joins(JoinNode *node, void *a, void *b) { if (node->type == JOIN_TB || node->type == JOIN_LR || node->type == JOIN_LRROTSCALE || node->type == JOIN_TBROTSCALE) node->st->njoin++; return NULL; } #ifdef DEBUG /* Print a few spaces. */ static void spc(int n) { int i; for (i = 0; i < n; i++) printf(" "); } #endif /*DEBUG*/ #ifdef DEBUG static char * JoinType2char(JoinType type) { switch (type) { case JOIN_LR: return "JOIN_LR"; case JOIN_TB: return "JOIN_TB"; case JOIN_LRROTSCALE: return "JOIN_LRROTSCALE"; case JOIN_TBROTSCALE: return "JOIN_TBROTSCALE"; case JOIN_CP: return "JOIN_CP"; case JOIN_LEAF: return "JOIN_LEAF"; default: vips_error_exit("internal error #9275"); /*NOTEACHED*/ return NULL; } } #endif /*DEBUG*/ #ifdef DEBUG /* Print a join node. */ static void * print_joins(JoinNode *node, int indent) { char *basename = g_path_get_basename(node->name); switch (node->type) { case JOIN_TB: case JOIN_LR: case JOIN_TBROTSCALE: case JOIN_LRROTSCALE: spc(indent); printf("%s to make %s, size %dx%d, pos. %dx%d, of:\n", JoinType2char(node->type), basename, node->cumtrn.oarea.width, node->cumtrn.oarea.height, node->cumtrn.oarea.left, node->cumtrn.oarea.top); spc(indent); printf("reference:\n"); print_joins(node->arg1, indent + 2); spc(indent); printf("secondary:\n"); print_joins(node->arg2, indent + 2); break; case JOIN_CP: spc(indent); printf("copy to make %s of:\n", basename); print_joins(node->arg1, indent + 2); break; case JOIN_LEAF: spc(indent); printf("input image %s\n", basename); break; } g_free(basename); return NULL; } #endif /*DEBUG*/ #ifdef DEBUG /* Print an overlap. */ static void * print_overlap(OverlapInfo *lap, void *a, void *b) { char *basename_node = g_path_get_basename(lap->node->name); char *basename_other = g_path_get_basename(lap->other->name); printf("-> %s overlaps with %s; (this, other) = (%.4G, %.4G)\n", basename_node, basename_other, *VIPS_MATRIX(lap->nstats, 4, 0), *VIPS_MATRIX(lap->ostats, 4, 0)); g_free(basename_node); g_free(basename_other); return NULL; } #endif /*DEBUG*/ #ifdef DEBUG /* Print the overlaps on a leaf. */ static void * print_overlaps(JoinNode *node, void *a, void *b) { char *basename; if (node->type == JOIN_LEAF && g_slist_length(node->overlaps) > 0) { basename = g_path_get_basename(node->name); printf("overlap of %s with:\n", basename); g_free(basename); vips_slist_map2(node->overlaps, (VipsSListMap2Fn) print_overlap, NULL, NULL); } return NULL; } #endif /*DEBUG*/ #ifdef DEBUG /* Print and accumulate the error on an overlap. */ static void * print_overlap_error(OverlapInfo *lap, double *fac, double *total) { char *basename_other = g_path_get_basename(lap->other->name); double na = *VIPS_MATRIX(lap->nstats, 4, 0); double oa = *VIPS_MATRIX(lap->ostats, 4, 0); double err; if (fac) { na *= fac[lap->node->index]; oa *= fac[lap->other->index]; } err = na - oa; printf("-> file %s, error = %g\n", basename_other, err); *total += err * err; g_free(basename_other); return NULL; } #endif /*DEBUG*/ #ifdef DEBUG /* Print and accumulate the overlap errors on a leaf. */ static void * print_overlap_errors(JoinNode *node, double *fac, double *total) { char *basename; if (node->type == JOIN_LEAF && g_slist_length(node->overlaps) > 0) { basename = g_path_get_basename(node->name); printf("overlap of %s (index %d) with:\n", basename, node->index); g_free(basename); vips_slist_map2(node->overlaps, (VipsSListMap2Fn) print_overlap_error, fac, total); } return NULL; } #endif /*DEBUG*/ /* Extract a rect. */ static int extract_rect(VipsImage *in, VipsImage **out, VipsRect *r) { return vips_extract_area(in, out, r->left, r->top, r->width, r->height, NULL); } /* Two images overlap in an area ... make a mask the size of the area, which * has 255 for every pixel where both images are non-zero. */ static int make_overlap_mask(VipsImage *mem, VipsImage *ref, VipsImage *sec, VipsImage **mask, VipsRect *rarea, VipsRect *sarea) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(mem), 6); if (extract_rect(ref, &t[0], rarea) || extract_rect(sec, &t[1], sarea) || vips_extract_band(t[0], &t[2], 0, NULL) || vips_extract_band(t[1], &t[3], 0, NULL) || vips_notequal_const1(t[2], &t[4], 0.0, NULL) || vips_notequal_const1(t[3], &t[5], 0.0, NULL) || vips_andimage(t[4], t[5], mask, NULL)) return -1; return 0; } /* Find the number of non-zero pixels in a mask image. */ static int count_nonzero(VipsImage *in, gint64 *count) { double avg; if (vips_avg(in, &avg, NULL)) return -1; *count = (avg * VIPS_IMAGE_N_PELS(in)) / 255.0; return 0; } /* Find stats on an area of an IMAGE ... consider only pixels for which the * mask is true. */ static VipsImage * find_image_stats(VipsImage *mem, VipsImage *in, VipsImage *mask, VipsRect *area) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(mem), 5); gint64 count; /* Extract area, build black image, mask out pixels we want. */ if (extract_rect(in, &t[0], area) || vips_black(&t[1], t[0]->Xsize, t[0]->Ysize, "bands", t[0]->Bands, NULL) || vips_cast(t[1], &t[2], t[0]->BandFmt, NULL) || vips_ifthenelse(mask, t[0], t[2], &t[3], NULL)) return NULL; /* Get stats from masked image. */ if (vips_stats(t[3], &t[4], NULL)) return NULL; /* Number of non-zero pixels in mask. */ if (count_nonzero(mask, &count)) return NULL; /* And scale masked average to match. */ *VIPS_MATRIX(t[4], 4, 0) *= (double) count / VIPS_IMAGE_N_PELS(mask); /* Yuk! Zap the deviation column with the pixel count. Used later to * determine if this is likely to be a significant overlap. */ *VIPS_MATRIX(t[4], 5, 0) = count; #ifdef DEBUG if (count == 0) g_warning("global_balance empty overlap"); #endif /*DEBUG*/ return t[4]; } /* Find the stats for an overlap struct. */ static int find_overlap_stats(OverlapInfo *lap) { VipsImage *mem = lap->node->st->im; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(mem), 1); VipsRect rarea, sarea; /* Translate the overlap area into the coordinate scheme for the main * node. */ rarea = lap->overlap; rarea.left -= lap->node->cumtrn.oarea.left; rarea.top -= lap->node->cumtrn.oarea.top; /* Translate the overlap area into the coordinate scheme for the other * node. */ sarea = lap->overlap; sarea.left -= lap->other->cumtrn.oarea.left; sarea.top -= lap->other->cumtrn.oarea.top; /* Make a mask for the overlap. */ if (make_overlap_mask(mem, lap->node->trnim, lap->other->trnim, &t[0], &rarea, &sarea)) return -1; /* Find stats for that area. */ if (!(lap->nstats = find_image_stats(mem, lap->node->trnim, t[0], &rarea))) return -1; if (!(lap->ostats = find_image_stats(mem, lap->other->trnim, t[0], &sarea))) return -1; return 0; } /* Sub-fn. of below. */ static void * overlap_eq(OverlapInfo *this, JoinNode *node, void *b) { if (this->other == node) return this; else return NULL; } /* Is this an overlapping leaf? If yes, add to overlap list. */ static void * test_overlap(JoinNode *other, JoinNode *node, void *b) { VipsRect overlap; OverlapInfo *lap; /* Is other a suitable leaf to overlap with node? */ if (other->type != JOIN_LEAF || node == other) return NULL; /* Is there an overlap? */ vips_rect_intersectrect(&node->cumtrn.oarea, &other->cumtrn.oarea, &overlap); if (vips_rect_isempty(&overlap)) return NULL; /* Is this a trivial overlap? Ignore it if it is. */ if (overlap.width * overlap.height < TRIVIAL) /* Too few pixels. */ return NULL; /* Have we already added this overlap the other way around? ie. is * node on other's overlap list? */ if (vips_slist_map2(other->overlaps, (VipsSListMap2Fn) overlap_eq, node, NULL)) return NULL; /* A new overlap - add to overlap list. */ if (!(lap = build_overlap(node, other, &overlap))) return node; /* Calculate overlap statistics. Open stuff relative to this, and * free quickly. */ if (find_overlap_stats(lap)) return node; /* If the pixel count either masked overlap is trivial, ignore this * overlap. */ if (*VIPS_MATRIX(lap->nstats, 5, 0) < TRIVIAL || *VIPS_MATRIX(lap->ostats, 5, 0) < TRIVIAL) { #ifdef DEBUG printf("trivial overlap ... junking\n"); printf("nstats count = %g, ostats count = %g\n", *VIPS_MATRIX(lap->nstats, 5, 0), *VIPS_MATRIX(lap->ostats, 5, 0)); print_overlap(lap, NULL, NULL); #endif /*DEBUG*/ overlap_destroy(lap); } return NULL; } /* If this is a leaf, look at all other joins for a leaf that overlaps. Aside: * If this is a leaf, there should be an IMAGE. Flag an error if there is * not. */ static void * find_overlaps(JoinNode *node, SymbolTable *st, void *b) { if (node->type == JOIN_LEAF) { /* Check for image. */ if (!node->im) { vips_error("vips_global_balance", _("unable to open \"%s\""), node->name); return node; } if (!node->trnim) vips_error_exit("global_balance: sanity failure #9834"); return vips__map_table(st, (VipsSListMap2Fn) test_overlap, node, NULL); } return NULL; } /* Bundle of variables for matrix creation. */ typedef struct { SymbolTable *st; /* Main table */ JoinNode *leaf; /* Leaf to be 1.000 */ VipsImage *K; /* LHS */ VipsImage *M; /* RHS */ int row; /* Current row */ } MatrixBundle; /* Add a new row for the nominated overlap to the matrices. */ static void * add_nominated(OverlapInfo *ovl, MatrixBundle *bun, double *gamma) { double ns = pow(*VIPS_MATRIX(ovl->nstats, 4, 0), 1.0 / (*gamma)); double os = pow(*VIPS_MATRIX(ovl->ostats, 4, 0), 1.0 / (*gamma)); *VIPS_MATRIX(bun->K, 0, bun->row) = ns; *VIPS_MATRIX(bun->M, ovl->other->index - 1, bun->row) = os; bun->row++; return NULL; } /* Add a new row for an ordinary overlap to the matrices. */ static void * add_other(OverlapInfo *ovl, MatrixBundle *bun, double *gamma) { double ns = -pow(*VIPS_MATRIX(ovl->nstats, 4, 0), 1.0 / (*gamma)); double os = pow(*VIPS_MATRIX(ovl->ostats, 4, 0), 1.0 / (*gamma)); *VIPS_MATRIX(bun->M, ovl->node->index - 1, bun->row) = ns; *VIPS_MATRIX(bun->M, ovl->other->index - 1, bun->row) = os; bun->row++; return NULL; } /* Add stuff for node to matrix. */ static void * add_row(JoinNode *node, MatrixBundle *bun, double *gamma) { if (node == bun->leaf) vips_slist_map2(node->overlaps, (VipsSListMap2Fn) add_nominated, bun, gamma); else vips_slist_map2(node->overlaps, (VipsSListMap2Fn) add_other, bun, gamma); return NULL; } /* Fill K and M. leaf is image selected to have factor of 1.000. */ static void fill_matrices(SymbolTable *st, double gamma, VipsImage *K, VipsImage *M) { MatrixBundle bun; bun.st = st; bun.leaf = st->leaf; bun.K = K; bun.M = M; bun.row = 0; /* Build matrices. */ vips__map_table(st, (VipsSListMap2Fn) add_row, &bun, &gamma); } /* Used to select the leaf whose coefficient we set to 1. */ static void * choose_leaf(JoinNode *node, void *a, void *b) { if (node->type == JOIN_LEAF) return node; return NULL; } /* Make an image from a node. */ static VipsImage * make_mos_image(SymbolTable *st, JoinNode *node, transform_fn tfn, void *a) { VipsImage *im1, *im2, *out; switch (node->type) { case JOIN_LR: case JOIN_TB: if (!(im1 = make_mos_image(st, node->arg1, tfn, a)) || !(im2 = make_mos_image(st, node->arg2, tfn, a))) return NULL; if (vips_merge(im1, im2, &out, node->type == JOIN_LR ? VIPS_DIRECTION_HORIZONTAL : VIPS_DIRECTION_VERTICAL, -node->dx, -node->dy, "mblend", node->mwidth, NULL)) return NULL; vips_object_local(st->im, out); vips_image_set_string(out, "mosaic-name", node->name); break; case JOIN_LRROTSCALE: case JOIN_TBROTSCALE: if (!(im1 = make_mos_image(st, node->arg1, tfn, a)) || !(im2 = make_mos_image(st, node->arg2, tfn, a))) return NULL; out = vips_image_new(); vips_object_local(st->im, out); vips_image_set_string(out, "mosaic-name", node->name); if (node->type == JOIN_LRROTSCALE) { if (vips__lrmerge1(im1, im2, out, node->a, node->b, node->dx, node->dy, node->mwidth)) return NULL; } else { if (vips__tbmerge1(im1, im2, out, node->a, node->b, node->dx, node->dy, node->mwidth)) return NULL; } break; case JOIN_LEAF: /* Trivial case! */ if (!(out = tfn(node, a))) return NULL; break; case JOIN_CP: /* Very trivial case. */ out = make_mos_image(st, node->arg1, tfn, a); break; default: vips_error_exit("internal error #982369824375987"); /*NOTEACHED*/ return NULL; } return out; } /* Re-build mosaic. */ int vips__build_mosaic(SymbolTable *st, VipsImage *out, transform_fn tfn, void *a) { JoinNode *root = st->root; VipsImage *im1, *im2; VipsImage *x; switch (root->type) { case JOIN_LR: case JOIN_TB: if (!(im1 = make_mos_image(st, root->arg1, tfn, a)) || !(im2 = make_mos_image(st, root->arg2, tfn, a))) return -1; if (vips_merge(im1, im2, &x, root->type == JOIN_LR ? VIPS_DIRECTION_HORIZONTAL : VIPS_DIRECTION_VERTICAL, -root->dx, -root->dy, "mblend", root->mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); break; case JOIN_LRROTSCALE: case JOIN_TBROTSCALE: if (!(im1 = make_mos_image(st, root->arg1, tfn, a)) || !(im2 = make_mos_image(st, root->arg2, tfn, a))) return -1; if (root->type == JOIN_LRROTSCALE) { if (vips__lrmerge1(im1, im2, out, root->a, root->b, root->dx, root->dy, root->mwidth)) return -1; } else { if (vips__tbmerge1(im1, im2, out, root->a, root->b, root->dx, root->dy, root->mwidth)) return -1; } break; case JOIN_LEAF: /* Trivial case! Just one file in our mosaic. */ if (!(im1 = tfn(root, a)) || vips_image_write(im1, out)) return -1; break; case JOIN_CP: /* Very trivial case. */ if (!(im1 = make_mos_image(st, root->arg1, tfn, a)) || vips_image_write(im1, out)) return -1; break; default: vips_error_exit("internal error #982369824375987"); /*NOTEACHED*/ } return 0; } static int vips__matrixtranspose(VipsImage *in, VipsImage **out) { if (!(*out = vips_image_new_matrix(in->Ysize, in->Xsize))) return -1; for (int y = 0; y < (*out)->Ysize; y++) for (int x = 0; x < (*out)->Xsize; x++) *VIPS_MATRIX(*out, x, y) = *VIPS_MATRIX(in, y, x); return 0; } static int vips__matrixmultiply(VipsImage *in1, VipsImage *in2, VipsImage **out) { int xc, yc, col; double sum; double *mat, *a, *b; double *s1, *s2; /* Check matrix sizes. */ if (in1->Xsize != in2->Ysize) { vips_error("vips__matrixmultiply", "%s", _("bad sizes")); return -1; } /* Allocate output matrix. */ if (!(*out = vips_image_new_matrix(in2->Xsize, in1->Ysize))) return -1; /* Multiply. */ mat = VIPS_MATRIX(*out, 0, 0); s1 = VIPS_MATRIX(in1, 0, 0); for (yc = 0; yc < in1->Ysize; yc++) { s2 = VIPS_MATRIX(in2, 0, 0); for (col = 0; col < in2->Xsize; col++) { /* Get ready to sweep a row. */ a = s1; b = s2; for (sum = 0.0, xc = 0; xc < in1->Xsize; xc++) { sum += *a++ * *b; b += in2->Xsize; } *mat++ = sum; s2++; } s1 += in1->Xsize; } return 0; } /* Find correction factors. */ static int find_factors(SymbolTable *st, double gamma) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(st->im), 7); double total; double avg; int i; /* Make output matrices. */ if (!(t[0] = vips_image_new_matrix(1, st->novl)) || !(t[1] = vips_image_new_matrix(st->nim - 1, st->novl))) return -1; fill_matrices(st, gamma, t[0], t[1]); #ifdef DEBUG vips_image_write_to_file(t[0], "K.mat", NULL); vips_image_write_to_file(t[1], "M.mat", NULL); #endif /*DEBUG*/ /* Calculate LMS. */ if (vips__matrixtranspose(t[1], &t[2]) || vips__matrixmultiply(t[2], t[1], &t[3]) || vips_matrixinvert(t[3], &t[4], NULL) || vips__matrixmultiply(t[4], t[2], &t[5]) || vips__matrixmultiply(t[5], t[0], &t[6])) return -1; /* Make array of correction factors. */ if (!(st->fac = VIPS_ARRAY(st->im, st->nim, double))) return -1; for (i = 0; i < t[6]->Ysize; i++) st->fac[i + 1] = *VIPS_MATRIX(t[6], 0, i); st->fac[0] = 1.0; /* Find average balance factor, normalise to that average. */ total = 0.0; for (i = 0; i < st->nim; i++) total += st->fac[i]; avg = total / st->nim; for (i = 0; i < st->nim; i++) st->fac[i] /= avg; #ifdef DEBUG /* Diagnostics! */ printf("debugging output for vips_globalbalance():\n"); for (i = 0; i < st->nim; i++) printf("balance factor %d = %g\n", i, st->fac[i]); total = 0.0; printf("Overlap errors:\n"); vips__map_table(st, (VipsSListMap2Fn) print_overlap_errors, NULL, &total); printf("RMS error = %g\n", sqrt(total / st->novl)); total = 0.0; printf("Overlap errors after adjustment:\n"); vips__map_table(st, (VipsSListMap2Fn) print_overlap_errors, st->fac, &total); printf("RMS error = %g\n", sqrt(total / st->novl)); #endif /*DEBUG*/ return 0; } /* TODO(kleisauke): Copied from im__affinei */ /* Shared with vips_mosaic1(), so not static. */ int vips__affinei(VipsImage *in, VipsImage *out, VipsTransformation *trn) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 2); VipsArrayInt *oarea; gboolean repack; oarea = vips_array_int_newv(4, trn->oarea.left, trn->oarea.top, trn->oarea.width, trn->oarea.height); /* vips7 affine would repack labq and im_benchmark() depends upon * this. */ repack = in->Coding == VIPS_CODING_LABQ; if (vips_affine(in, &t[0], trn->a, trn->b, trn->c, trn->d, "oarea", oarea, "odx", trn->odx, "ody", trn->ody, NULL)) { vips_area_unref(VIPS_AREA(oarea)); return -1; } vips_area_unref(VIPS_AREA(oarea)); in = t[0]; if (repack) { if (vips_colourspace(in, &t[1], VIPS_INTERPRETATION_LABQ, NULL)) return -1; in = t[1]; } if (vips_image_write(in, out)) return -1; return 0; } /* Look for all leaves, make sure we have a transformed version of each. */ static void * generate_trn_leaves(JoinNode *node, SymbolTable *st, void *b) { if (node->type == JOIN_LEAF) { /* Check for image. */ if (!node->im) { vips_error("vips_global_balance", _("unable to open \"%s\""), node->name); return node; } if (node->trnim) vips_error_exit("global_balance: sanity failure #765"); /* Special case: if this is an untransformed leaf (there will * always be at least one), then skip the affine. */ if (vips__transform_isidentity(&node->cumtrn)) node->trnim = node->im; else { node->trnim = vips_image_new(); vips_object_local(node->st->im, node->trnim); if (vips__affinei(node->im, node->trnim, &node->cumtrn)) return node; } } return NULL; } /* Analyse mosaic. */ static int analyse_mosaic(SymbolTable *st, VipsImage *in) { /* Parse Hist on in. */ if (vips__parse_desc(st, in)) return -1; /* Print parsed data. */ #ifdef DEBUG printf("Input files:\n"); vips__map_table(st, (VipsSListMap2Fn) print_leaf, NULL, NULL); printf("\nOutput file:\n"); print_node(st->root); printf("\nJoin commands:\n"); print_joins(st->root, 0); #endif /*DEBUG*/ /* Generate transformed leaves. */ if (vips__map_table(st, (VipsSListMap2Fn) generate_trn_leaves, st, NULL)) return -1; /* Find overlaps. */ if (vips__map_table(st, (VipsSListMap2Fn) find_overlaps, st, NULL)) return -1; /* Scan table, counting and indexing input images and joins. */ vips__map_table(st, (VipsSListMap2Fn) count_leaves, NULL, NULL); vips__map_table(st, (VipsSListMap2Fn) count_joins, NULL, NULL); /* Select leaf to be 1.000. * This must be index == 0, unless you change stuff above! */ st->leaf = vips__map_table(st, (VipsSListMap2Fn) choose_leaf, NULL, NULL); /* And print overlaps. */ #ifdef DEBUG printf("\nLeaf to be 1.000:\n"); print_node(st->leaf); printf("\nOverlaps:\n"); vips__map_table(st, (VipsSListMap2Fn) print_overlaps, NULL, NULL); printf("\n%d input files, %d unique overlaps, %d joins\n", st->nim, st->novl, st->njoin); #endif /*DEBUG*/ return 0; } /* Scale im by fac -- if it's uchar/ushort, use a lut. If we can use a lut, * transform in linear space. If we can't, don't bother for efficiency. */ static VipsImage * transform(JoinNode *node, double *gamma) { SymbolTable *st = node->st; VipsImage *in = node->im; double fac = st->fac[node->index]; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(st->im), 8); VipsImage *out; if (fac == 1.0) { /* Easy! */ out = in; } /* TODO(kleisauke): Could we call vips_gamma instead? */ else if (in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT) { if (vips_identity(&t[0], "bands", 1, "ushort", in->BandFmt == VIPS_FORMAT_USHORT, //"size", 65535, NULL) || vips_pow_const1(t[0], &t[1], 1.0 / (*gamma), NULL) || vips_linear1(t[1], &t[2], fac, 0.0, NULL) || vips_pow_const1(t[2], &t[3], *gamma, NULL) || vips_cast(t[3], &t[4], in->BandFmt, NULL) || vips_maplut(in, &t[5], t[4], NULL)) return NULL; out = t[5]; } else { /* Just vips_linear1 it. */ if (vips_linear1(in, &t[6], fac, 0.0, NULL) || vips_cast(t[6], &t[7], in->BandFmt, NULL)) return NULL; out = t[7]; } vips_image_set_string(out, "mosaic-name", node->name); return out; } /* As above, but output as float, not matched to input. */ static VipsImage * transformf(JoinNode *node, double *gamma) { SymbolTable *st = node->st; VipsImage *in = node->im; double fac = node->st->fac[node->index]; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(st->im), 6); VipsImage *out; if (fac == 1.0) { /* Easy! */ out = in; } else if (in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT) { if (vips_identity(&t[0], "bands", 1, "ushort", in->BandFmt == VIPS_FORMAT_USHORT, //"size", 65535, NULL) || vips_pow_const1(t[0], &t[1], 1.0 / (*gamma), NULL) || vips_linear1(t[1], &t[2], fac, 0.0, NULL) || vips_pow_const1(t[2], &t[3], *gamma, NULL) || vips_maplut(in, &t[4], t[3], NULL)) return NULL; out = t[4]; } else { /* Just vips_linear1 it. */ if (vips_linear1(in, &t[5], fac, 0.0, NULL)) return NULL; out = t[5]; } vips_image_set_string(out, "mosaic-name", node->name); return out; } typedef struct { VipsOperation parent_instance; VipsImage *in; VipsImage *out; gboolean int_output; double gamma; } VipsGlobalbalance; typedef VipsOperationClass VipsGlobalbalanceClass; G_DEFINE_TYPE(VipsGlobalbalance, vips_globalbalance, VIPS_TYPE_OPERATION); static int vips_globalbalance_build(VipsObject *object) { VipsGlobalbalance *globalbalance = (VipsGlobalbalance *) object; SymbolTable *st; transform_fn trn; g_object_set(globalbalance, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_globalbalance_parent_class)->build(object)) return -1; if (!(st = vips__build_symtab(globalbalance->out, SYM_TAB_SIZE)) || analyse_mosaic(st, globalbalance->in) || find_factors(st, globalbalance->gamma)) return -1; trn = globalbalance->int_output ? (transform_fn) transform : (transform_fn) transformf; if (vips__build_mosaic(st, globalbalance->out, trn, &globalbalance->gamma)) return -1; return 0; } static void vips_globalbalance_class_init(VipsGlobalbalanceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "globalbalance"; object_class->description = _("global balance an image mosaic"); object_class->build = vips_globalbalance_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsGlobalbalance, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsGlobalbalance, out)); VIPS_ARG_DOUBLE(class, "gamma", 5, _("Gamma"), _("Image gamma"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGlobalbalance, gamma), 0.00001, 10, 1.6); VIPS_ARG_BOOL(class, "int_output", 7, _("Int output"), _("Integer output"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsGlobalbalance, int_output), FALSE); } static void vips_globalbalance_init(VipsGlobalbalance *globalbalance) { globalbalance->gamma = 1.6; } /** * vips_globalbalance: (method) * @in: mosaic to rebuild * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * [method@Image.globalbalance] can be used to remove contrast differences in * an assembled mosaic. * * It reads the History field attached to @in and builds a list of the source * images that were used to make the mosaic and the position that each ended * up at in the final image. * * It opens each of the source images in turn and extracts all parts which * overlap with any of the other images. It finds the average values in the * overlap areas and uses least-mean-square to find a set of correction * factors which will minimise overlap differences. It uses @gamma to * gamma-correct the source images before calculating the factors. A value of * 1.0 will stop this. * * Each of the source images is transformed with the appropriate correction * factor, then the mosaic is reassembled. @out is * [enum@Vips.BandFormat.FLOAT], but if @int_output is set, the output image * is the same format as the input images. * * There are some conditions that must be met before this operation can work: * the source images must all be present under the filenames recorded in the * history on @in, and the mosaic must have been built using only operations in * this package. * * ::: tip "Optional arguments" * * @gamma: `gdouble`, gamma of source images * * @int_output: `gboolean`, `TRUE` for integer image output * * ::: seealso * [method@Image.mosaic]. * * Returns: 0 on success, -1 on error */ int vips_globalbalance(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("globalbalance", ap, in, out); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/global_balance.h000066400000000000000000000073641516303661500220010ustar00rootroot00000000000000/* Header for the .desc file parser in vips_global_balance() * * 1/11/01 JC * - cut from global_balance.c */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Number of entries in spine of file name hash table. */ #define SYM_TAB_SIZE (113) typedef enum _JoinType JoinType; typedef struct _OverlapInfo OverlapInfo; typedef struct _JoinNode JoinNode; typedef struct _SymbolTable SymbolTable; /* Type of a transform function. */ typedef VipsImage *(*transform_fn)(JoinNode *, void *); /* Join type. */ enum _JoinType { JOIN_LR, /* vips__lrmerge join */ JOIN_TB, /* vips__tbmerge join */ JOIN_LRROTSCALE, /* 1st order lrmerge */ JOIN_TBROTSCALE, /* 1st order tbmerge */ JOIN_CP, /* vips_copy operation */ JOIN_LEAF /* Base file */ }; /* An overlap struct. Attach a list of these to each leaf, one for each of * the other leaves we touch. */ struct _OverlapInfo { JoinNode *node; /* The base node - we are on this list */ JoinNode *other; /* Node we overlap with */ VipsRect overlap; /* The overlap area */ VipsImage *nstats; /* Node's stats for overlap area */ VipsImage *ostats; /* Other's stats for overlap area */ }; /* Struct for a join node. */ struct _JoinNode { char *name; /* This file name */ JoinType type; /* What kind of join */ SymbolTable *st; /* Symbol table we are on */ int dirty; /* Used for circularity detection */ /* Params from join line in .desc file. */ double a, b; double dx, dy; int mwidth; /* Cumulative transform for this node. What our parents do to us. * cumtrn.area is position and size of us, thistrn.area is pos and * size of arg2. */ VipsTransformation cumtrn; /* X-tras for LR/TB. thistrn is what we do to arg2. */ JoinNode *arg1; /* Left or up thing to join */ JoinNode *arg2; /* Right or down thing to join */ VipsTransformation thistrn; /* Transformation for arg2 */ /* Special for leaves: all the join_nodes we overlap with, the * VipsImage for that file, and the index. */ GSList *overlaps; VipsImage *im; VipsImage *trnim; /* Transformed image .. used in 2nd pass */ int index; }; /* We need to keep a table of JoinNode, indexed by file name. Hash into one * of these from the name to get a pointer to the base of a list of JoinNode * which hash to that offset. */ struct _SymbolTable { GSList **table; /* Ptr to base of hash table */ int sz; /* Size of hash table */ VipsImage *im; /* Malloc relative to this */ int novl; /* Number of unique overlaps */ int nim; /* Number of leaf images */ int njoin; /* Number of join nodes */ JoinNode *root; /* Root of join tree */ JoinNode *leaf; /* Leaf nominated to be 1.000 */ double *fac; /* Correction factors */ }; VipsImage *vips__global_open_image(SymbolTable *st, char *name); SymbolTable *vips__build_symtab(VipsImage *out, int sz); int vips__parse_desc(SymbolTable *st, VipsImage *in); void *vips__map_table(SymbolTable *st, VipsSListMap2Fn fn, void *a, void *b); int vips__build_mosaic(SymbolTable *st, VipsImage *out, transform_fn tfn, void *a); libvips-8.18.2/libvips/mosaicing/im_avgdxdy.c000066400000000000000000000040421516303661500212100ustar00rootroot00000000000000/* @(#) Function which averages the difference x_secondary[] - x_reference[] * @(#) and y_secondary[] - y_reference[] of the structure points; * @(#) The rounded integer result is returned into dx, dy * @(#) No images are involved in this function. * @(#) * @(#) int vips__avgdxdy(points, dx, dy) * @(#) TiePoints *points; * @(#) int *dx, *dy; * @(#) * @(#) Returns 0 on success and -1 on error. * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 20/12/1990 * Modified on : 18/04/1991 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pmosaicing.h" int vips__avgdxdy(TiePoints *points, int *dx, int *dy) { int sumdx, sumdy; int i; if (points->nopoints == 0) { vips_error("vips__avgdxdy", "%s", _("no points to average")); return -1; } /* Lots of points. */ sumdx = 0; sumdy = 0; for (i = 0; i < points->nopoints; i++) { sumdx += points->x_secondary[i] - points->x_reference[i]; sumdy += points->y_secondary[i] - points->y_reference[i]; } *dx = rint((double) sumdx / (double) points->nopoints); *dy = rint((double) sumdy / (double) points->nopoints); return 0; } libvips-8.18.2/libvips/mosaicing/im_clinear.c000066400000000000000000000110471516303661500211620ustar00rootroot00000000000000/* @(#) Function which calculates the coefficients between corresponding * @(#) points from reference and secondary images (probably from the scanner), * @(#) previously calculated using the functions vips__{lr,bt}calcon() and vips_chpair() * @(#) It is assumed that a selection of the best(?) possible points has * @(#) been already carried out and that those nopoints points are in arrays * @(#) x1, y1 and x2, y2 * @(#) No images are involved in this function and the calculated parameters * @(#) are returned in scale angle deltax and deltay of the TiePoints struct. * @(#) * @(#) int vips_clinear(points) * @(#) TiePoints *points; * @(#) * @(#) Returns 0 on success and -1 on error. * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 20/12/1990 * Modified on : 18/04/1991 * 24/1/97 JC * - tiny mem leak fixed * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" int vips__clinear(TiePoints *points) { VipsImage *mat, *matinv; double *g; double value; double sx1 = 0.0, sx1x1 = 0.0, sy1 = 0.0, sy1y1 = 0.0; double sx2x1 = 0.0, sx2y1 = 0.0, sx2 = 0.0, sy2 = 0.0, sy2y1 = 0.0, sy2x1 = 0.0; int i, j; int elms; double scale, angle, xdelta, ydelta; int *xref, *yref, *xsec, *ysec; double *dx, *dy, *dev; xref = &points->x_reference[0]; yref = &points->y_reference[0]; xsec = &points->x_secondary[0]; ysec = &points->y_secondary[0]; dx = &points->dx[0]; dy = &points->dy[0]; dev = &points->deviation[0]; elms = points->nopoints; if (!(mat = vips_image_new_matrix(4, 4))) return -1; if (!(g = VIPS_ARRAY(NULL, 4, double))) { g_object_unref(mat); return -1; } for (i = 0; i < points->nopoints; i++) { sx1 += xref[i]; sx1x1 += xref[i] * xref[i]; sy1 += yref[i]; sy1y1 += yref[i] * yref[i]; sx2x1 += xsec[i] * xref[i]; sx2y1 += xsec[i] * yref[i]; sy2y1 += ysec[i] * yref[i]; sy2x1 += ysec[i] * xref[i]; sx2 += xsec[i]; sy2 += ysec[i]; } *VIPS_MATRIX(mat, 0, 0) = sx1x1 + sy1y1; *VIPS_MATRIX(mat, 1, 0) = 0; *VIPS_MATRIX(mat, 2, 0) = sx1; *VIPS_MATRIX(mat, 3, 0) = sy1; *VIPS_MATRIX(mat, 0, 1) = 0; *VIPS_MATRIX(mat, 1, 1) = sx1x1 + sy1y1; *VIPS_MATRIX(mat, 2, 1) = -sy1; *VIPS_MATRIX(mat, 3, 1) = sx1; *VIPS_MATRIX(mat, 0, 2) = sx1; *VIPS_MATRIX(mat, 1, 2) = -sy1; *VIPS_MATRIX(mat, 2, 2) = (double) elms; *VIPS_MATRIX(mat, 3, 2) = 0.0; *VIPS_MATRIX(mat, 0, 3) = sy1; *VIPS_MATRIX(mat, 1, 3) = sx1; *VIPS_MATRIX(mat, 2, 3) = 0.0; *VIPS_MATRIX(mat, 3, 3) = (double) elms; g[0] = sx2x1 + sy2y1; g[1] = -sx2y1 + sy2x1; g[2] = sx2; g[3] = sy2; if (vips_matrixinvert(mat, &matinv, NULL)) { g_object_unref(mat); g_free(g); vips_error("vips_clinear", "%s", _("vips_invmat failed")); return -1; } scale = 0.0; angle = 0.0; xdelta = 0.0; ydelta = 0.0; for (j = 0; j < 4; j++) { scale += *VIPS_MATRIX(matinv, j, 0) * g[j]; angle += *VIPS_MATRIX(matinv, j, 1) * g[j]; xdelta += *VIPS_MATRIX(matinv, j, 2) * g[j]; ydelta += *VIPS_MATRIX(matinv, j, 3) * g[j]; } g_object_unref(mat); g_object_unref(matinv); g_free(g); /* find the deviation of each point for the estimated variables * if it greater than 1 then the solution is not good enough * but this is handled by the main program */ for (i = 0; i < points->nopoints; i++) { dx[i] = xsec[i] - ((scale * xref[i]) - (angle * yref[i]) + xdelta); dy[i] = ysec[i] - ((angle * xref[i]) + (scale * yref[i]) + ydelta); value = sqrt(dx[i] * dx[i] + dy[i] * dy[i]); dev[i] = value; } points->l_scale = scale; points->l_angle = angle; points->l_deltax = xdelta; points->l_deltay = ydelta; return 0; } libvips-8.18.2/libvips/mosaicing/im_improve.c000066400000000000000000000114561516303661500212320ustar00rootroot00000000000000/* @(#) Function which improves the selection of tiepoints carried out by * @(#) vips_clinear() until no points have deviation greater than 1 pixel * @(#) No reference or secondary images are involved * @(#) Function vips__improve assumes that vips_clinear has been applied on points * @(#) No images are involved in this function and the result is * @(#) returned in outpoints which is declared as a pointer in the * @(#) calling routine. Space for outpoints should be allocated in the calling * @(#) routine * @(#) * @(#) int vips__improve(inpoints, outpoints) * @(#) TiePoints *inpoints, *outpoints; * @(#) * @(#) Returns 0 on success and -1 on error. * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 20/12/1990 * Modified on : 18/04/1991 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" static void copypoints(TiePoints *pnew, TiePoints *pold) { int i; pnew->reference = pold->reference; pnew->secondary = pold->secondary; pnew->deltax = pold->deltax; pnew->deltay = pold->deltay; pnew->nopoints = pold->nopoints; pnew->halfcorsize = pold->halfcorsize; pnew->halfareasize = pold->halfareasize; for (i = 0; i < pold->nopoints; i++) { pnew->x_reference[i] = pold->x_reference[i]; pnew->y_reference[i] = pold->y_reference[i]; pnew->x_secondary[i] = pold->x_secondary[i]; pnew->y_secondary[i] = pold->y_secondary[i]; pnew->contrast[i] = pold->contrast[i]; pnew->correlation[i] = pold->correlation[i]; pnew->deviation[i] = pold->deviation[i]; pnew->dx[i] = pold->dx[i]; pnew->dy[i] = pold->dy[i]; } pnew->l_scale = pold->l_scale; pnew->l_angle = pold->l_angle; pnew->l_deltax = pold->l_deltax; pnew->l_deltay = pold->l_deltay; } /* exclude all points with deviation greater or equal to 1.0 pixel */ static int copydevpoints(TiePoints *pnew, TiePoints *pold) { int i; int j; double thresh_dev, max_dev, min_dev; double *corr; min_dev = 9999.0; max_dev = 0.0; corr = &pold->correlation[0]; for (i = 0; i < pold->nopoints; i++) if (corr[i] > 0.01) { if (pold->deviation[i] / corr[i] < min_dev) min_dev = pold->deviation[i] / corr[i]; if (pold->deviation[i] / corr[i] > max_dev) max_dev = pold->deviation[i] / corr[i]; } thresh_dev = min_dev + (max_dev - min_dev) * 0.3; if (thresh_dev <= 1.0) thresh_dev = 1.0; for (i = 0, j = 0; i < pold->nopoints; i++) if (pold->correlation[i] > 0.01) if (pold->deviation[i] / corr[i] <= thresh_dev) { pnew->x_reference[j] = pold->x_reference[i]; pnew->y_reference[j] = pold->y_reference[i]; pnew->x_secondary[j] = pold->x_secondary[i]; pnew->y_secondary[j] = pold->y_secondary[i]; pnew->contrast[j] = pold->contrast[i]; pnew->correlation[j] = pold->correlation[i]; pnew->deviation[j] = pold->deviation[i]; pnew->dx[j] = pold->dx[i]; pnew->dy[j] = pold->dy[i]; j++; } pnew->nopoints = j; for (i = j; i < VIPS_MAXPOINTS; i++) { pnew->x_reference[i] = 0; pnew->y_reference[i] = 0; pnew->x_secondary[i] = 0; pnew->y_secondary[i] = 0; pnew->contrast[i] = 0; pnew->correlation[i] = 0.0; pnew->deviation[i] = 0.0; pnew->dx[i] = 0.0; pnew->dy[i] = 0.0; } /* Return non-zero if we changed something. */ if (j != pold->nopoints) return -1; return 0; } int vips__improve(TiePoints *inpoints, TiePoints *outpoints) { TiePoints points1, points2; TiePoints *p = &points1; TiePoints *q = &points2; /* p has the current state - make a new state, q, with only those * points which have a small deviation. */ for (copypoints(p, inpoints); copypoints(q, p), copydevpoints(q, p);) { /* If there are only a few left, jump out. */ if (q->nopoints < 2) break; /* Fit the model to the new set of points. */ if (vips__clinear(q)) return -1; /* And loop. */ VIPS_SWAP(void *, p, q); } /* q has the output - copy to outpoints. */ copypoints(outpoints, q); return 0; } libvips-8.18.2/libvips/mosaicing/im_initialize.c000066400000000000000000000043711516303661500217100ustar00rootroot00000000000000/* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "pmosaicing.h" int vips__initialize(TiePoints *points) { if (vips__clinear(points)) { /* vips_clinear failed! Set some sensible fallback values. */ int i, j; double xdelta, ydelta, max_cor; double a1, a2; int *xref = &points->x_reference[0]; int *yref = &points->y_reference[0]; int *xsec = &points->x_secondary[0]; int *ysec = &points->y_secondary[0]; double *corr = &points->correlation[0]; double *dx = &points->dx[0]; double *dy = &points->dy[0]; int npt = points->nopoints; max_cor = 0.0; for (i = 0; i < npt; i++) if (corr[i] > max_cor) max_cor = corr[i]; max_cor = max_cor - 0.04; xdelta = 0.0; ydelta = 0.0; j = 0; for (i = 0; i < npt; i++) if (corr[i] >= max_cor) { xdelta += xsec[i] - xref[i]; ydelta += ysec[i] - yref[i]; ++j; } if (j == 0) { vips_error("vips_initialize", "no tie points"); return -1; } xdelta = xdelta / j; ydelta = ydelta / j; for (i = 0; i < npt; i++) { dx[i] = (xsec[i] - xref[i]) - xdelta; dy[i] = (ysec[i] - yref[i]) - ydelta; } for (i = 0; i < npt; i++) { a1 = dx[i]; a2 = dy[i]; points->deviation[i] = sqrt(a1 * a1 + a2 * a2); } points->l_scale = 1.0; points->l_angle = 0.0; points->l_deltax = xdelta; points->l_deltay = ydelta; } return 0; } libvips-8.18.2/libvips/mosaicing/im_lrcalcon.c000066400000000000000000000167701516303661500213520ustar00rootroot00000000000000/* @(#) Functions which takes an initial estimate of deltax, deltay * @(#) between reference and secondary images (probably from the scanner), * @(#) and looks in three areas of the overlapping part of the reference image * @(#) corresponding to reference and secondary. For every other halfreasize * @(#) point of the three areas of the reference image * @(#) the contrast is calculated * @(#) an area 2*halfcorsize+1 centered at this point * @(#) Results are saved in the structure points * @(#) The function expects the following valid data in points: * @(#) deltax, deltay, nopoints, halfcorsize, halfareasize * @(#) and fills in the members: * @(#) x, y_reference[], contrast and x,y_secondary[], * @(#) based on deltax and deltay * @(#) Input image should are either memory mapped or in a buffer. * @(#) The initial setting checks all points of reference * @(#) in the overlapping area of the images to be mosaiced * @(#) To speed up the procedure the ysize of the box can be reduced * @(#) during the calculation of the ysize * @(#) An easy way is to change FACTOR to 1 2 or 3. * @(#) The calculation of the contrast is carried out based on bandno only. * @(#) The variable bandno should be between 1 and ref->Bands * @(#) * @(#) int vips_lrcalcon(ref, sec, bandno, points) * @(#) VipsImage *ref, *sec; * @(#) int bandno; * @(#) TiePoints *points; see mosaic.h * @(#) * @(#) Returns 0 on success and -1 on error. * @(#) * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 20/12/1990 * Modified on : 18/04/1991 * 8/7/93 JC * - now calls im_incheck() * 12/7/95 JC * - reworked * - what a lot of horrible old code there was too * 24/1/97 JC * - now ignores black stuff (all bands zero) when selecting possible tie * points, part of new mosaic policy * 26/9/97 JC * - now skips all-black windows, instead of any-black windows * 11/4/01 JC * - ooops, < 0 should have been <= 0 * 10/3/03 JC * - better error message for overlap too small * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" /* A position and contrast. */ typedef struct { int x, y; int cont; } PosCont; /* Search a window for black pelss ... true if window is all black. * One-band uchar only. */ static int all_black(VipsImage *im, int xpos, int ypos, int winsize) { const int hwinsize = (winsize - 1) / 2; const int left = xpos - hwinsize; const int top = ypos - hwinsize; const int ls = im->Xsize; int x, y; VipsPel *line; /* Loop over image. */ line = im->data + top * ls + left; for (y = 0; y < winsize; y++) { for (x = 0; x < winsize; x++) if (line[x]) /* Not all black. */ return 0; line += ls; } return -1; } /* Calculate a value for 'contrast' within a window * of (odd) size winsize*winsize centered at location (xpos, ypos). * One band uchar only, */ static int calculate_contrast(VipsImage *im, int xpos, int ypos, int winsize) { const int hwinsize = (winsize - 1) / 2; const int left = xpos - hwinsize; const int top = ypos - hwinsize; const int ls = im->Xsize; int x, y; VipsPel *line, *p; int total; line = im->data + top * ls + left; for (total = 0, y = 0; y < winsize - 1; y++) { p = line; for (x = 0; x < winsize - 1; x++) { const int lrd = (int) p[0] - p[1]; const int tbd = (int) p[0] - p[ls]; total += abs(lrd) + abs(tbd); p += 1; } line += ls; } return total; } /* Compare two PosConts for qsort. */ static int pos_compare(const void *vl, const void *vr) { PosCont *l = (PosCont *) vl; PosCont *r = (PosCont *) vr; return r->cont - l->cont; } /* Search an area for the n best contrast areas. */ int vips__find_best_contrast(VipsImage *im, int xpos, int ypos, int xsize, int ysize, int xarray[], int yarray[], int cont[], int nbest, int hcorsize) { /* Geometry: we test squares of size windowsize, overlapping by * hcorsize. */ const int windowsize = 2 * hcorsize + 1; /* Number of squares we can fit in area. */ const int nacross = (xsize - windowsize + hcorsize) / hcorsize; const int ndown = (ysize - windowsize + hcorsize) / hcorsize; /* Number of squares we search. */ int elms; /* All points in this area. */ PosCont *pc; int x, y, i; if (nacross <= 0 || ndown <= 0) { vips_error("vips__lrcalcon", "%s", _("overlap too small for your search size")); return -1; } /* Malloc space for 3 int arrays, to keep the int coordinates and * the contrast. */ if (!(pc = VIPS_ARRAY(NULL, nacross * ndown, PosCont))) return -1; /* Find contrast for each area. */ for (i = 0, y = 0; y < ndown; y++) for (x = 0; x < nacross; x++) { const int left = xpos + x * hcorsize; const int top = ypos + y * hcorsize; /* Skip this position if it is all black. */ if (all_black(im, left, top, windowsize)) continue; /* Find contrast and note. */ pc[i].x = left; pc[i].y = top; pc[i].cont = calculate_contrast(im, left, top, windowsize); i++; } /* Note number found. */ elms = i; /* Found enough tie-points? */ if (elms < nbest) { vips_error("vips_mosaic", _("found %d tie-points, need at least %d"), elms, nbest); g_free(pc); return -1; } /* Sort areas by contrast. */ qsort(pc, elms, sizeof(PosCont), pos_compare); /* Copy the n best into our parent. */ for (i = 0; i < nbest; i++) { xarray[i] = pc[i].x; yarray[i] = pc[i].y; cont[i] = pc[i].cont; } g_free(pc); return 0; } int vips__lrcalcon(VipsImage *ref, TiePoints *points) { /* Geometry: border we must leave around each area. */ const int border = points->halfareasize; /* Height of an area. */ const int aheight = ref->Ysize / AREAS; /* Number of points we find in each area. */ const int len = points->nopoints / AREAS; int i; VipsRect area; /* Make sure we can read image. */ if (vips_image_wio_input(ref)) return -1; if (ref->Bands != 1 || ref->BandFmt != VIPS_FORMAT_UCHAR) { vips_error("vips__lrcalcon", "%s", _("not 1-band uchar image")); return -1; } /* Define bits to search for high-contrast areas. Need to be able to * fit at least 1 window in. */ area.height = aheight; area.width = ref->Xsize; area.left = 0; area.top = 0; vips_rect_marginadjust(&area, -border); area.width--; area.height--; /* Loop over areas, finding points. */ for (i = 0; area.top < ref->Ysize; area.top += aheight, i++) if (vips__find_best_contrast(ref, area.left, area.top, area.width, area.height, points->x_reference + i * len, points->y_reference + i * len, points->contrast + i * len, len, points->halfcorsize)) return -1; return 0; } libvips-8.18.2/libvips/mosaicing/im_tbcalcon.c000066400000000000000000000073701516303661500213360ustar00rootroot00000000000000/* @(#) Functions which takes an initial estimate of deltax, deltay * @(#) between reference and secondary images (probably from the scanner), * @(#) and looks in three areas of the overlapping part of the reference image * @(#) corresponding to reference and secondary. For every other halfreasize * @(#) point of the three areas of the reference image * @(#) the contrast is calculated * @(#) an area 2*halfcorsize+1 centered at this point * @(#) Results are saved in the structure points * @(#) The function expects the following valid data in points: * @(#) deltax, deltay, nopoints, halfcorsize, halfareasize * @(#) and fills in the members: * @(#) x, y_reference[], contrast and x,y_secondary[], * @(#) based on deltax and deltay * @(#) Input image should are either memory mapped or in a buffer. * @(#) To make the calculation faster set FACTOR to 1, 2 or 3 * @(#) Calculations are based on bandno only. * @(#) The function uses functions vips__find_best_contrast() * @(#) which is in vips_lrcalcon() * @(#) * @(#) int vips_tbcalcon(ref, sec, bandno, points) * @(#) VipsImage *ref, *sec; * @(#) int bandno; * @(#) TiePoints *points; see mosaic.h * @(#) * @(#) Returns 0 on success and -1 on error. * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 20/12/1990 * Modified on : 18/04/1991 * 8/7/93 JC * - allow IM_CODING_LABQ coding * - now calls im_incheck() * 12/7/95 JC * - reworked * - what a lot of horrible old code there was too * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" int vips__tbcalcon(VipsImage *ref, TiePoints *points) { /* Geometry: border we must leave around each area. */ const int border = points->halfareasize; /* Width of an area. */ const int awidth = ref->Xsize / AREAS; /* Number of points we find in each area. */ const int len = points->nopoints / AREAS; int i; VipsRect area; /* Make sure we can read image. */ if (vips_image_wio_input(ref)) return -1; if (ref->Bands != 1 || ref->BandFmt != VIPS_FORMAT_UCHAR) { vips_error("vips__tbcalcon", "%s", _("help!")); return -1; } /* Define bits to search for high-contrast areas. */ area.width = awidth; area.height = ref->Ysize; area.left = 0; area.top = 0; vips_rect_marginadjust(&area, -border); area.width--; area.height--; if (area.width < 0 || area.height < 0) { vips_error("vips__tbcalcon", "%s", _("overlap too small")); return -1; } /* Loop over areas, finding points. */ for (i = 0; area.left < ref->Xsize; area.left += awidth, i++) if (vips__find_best_contrast(ref, area.left, area.top, area.width, area.height, points->x_reference + i * len, points->y_reference + i * len, points->contrast + i * len, len, points->halfcorsize)) return -1; return 0; } libvips-8.18.2/libvips/mosaicing/lrmerge.c000066400000000000000000000666331516303661500205300ustar00rootroot00000000000000/* Merge two images left-right. * * Copyright: 1990, 1991 N. Dessipris * Author: N. Dessipris * Written on: 20/09/1990 * Updated on: 17/04/1991 * 1/6/92: JC * - check for difference bug fixed * - geometry calculations improved and simplified * - small speedups Kirk Martinez for Sys5 29/4/93 * 7/8/93 JC * - ANSIfied * - memory leaks fixed, ready for partial v2 * - now does IM_CODING_LABQ too * 8/11/93 JC * - now propagates both input histories * - adds magic lines for global mosaic optimisation * * * May/1994 Ahmed Abbood * * - Modified to use partials on all IO * June/1995 Ahmed Abbood * * - Modified to work with different types of images. * * 16/6/95 JC * - tidied up a little * - added to VIPS! * 7/9/95 JC * - split into two parts: im_lrmerge() and im__lrmerge() * - latter called by im_lrmosaic() * - just the same as public im_lrmerge(), but adds no history * - necessary for im_global_balance() * - small bugs fixed * 10/10/95 JC * - better checks that parameters are sensible * 11/10/95 JC * - Kirk spotted what a load of rubbish Ahmed's code is * - rewritten - many, many bugs fixed * 24/1/97 JC * - now outputs bounding area of input images, rather than clipping * - ignores 0 pixels in blend * - small tidies * 7/2/97 JC * - new blend, caching * 25/2/97 JC * - old blend back, much simpler * - speed this up at some point if you think of an easy way to do it * 29/7/97 JC * - IM_CODING_LABQ blend now works, was bug in im_wrapone() * - small tidies * 10/1/98 JC * - merge LUTs now shared between all running mergers * - frees memory explicitly in im__stop_merge, for much better memory * use in large mosaics, huge improvement! * 18/2/98 JC * - im_demand_hint() call added * 19/2/98 JC * - now works for any dx/dy by calling im_insert() for bizarre cases * 26/9/99 JC * - ooops, blend lut was wrong! wonder how long that's been broken, * since feb97 I guess * 2/2/01 JC * - added tunable max blend width * 8/3/01 JC * - switched to integer arithmetic for integer blends * 7/11/01 JC * - more sophisticated transparency handling * - tiny blend speed up * 19/3/02 JC * - move fl cache to main state for better sharing * 15/8/02 JC * - records Xoffset/Yoffset * 20/6/05 * - now requires all bands == 0 for transparency (used to just check * band 0) * 24/1/11 * - gtk-doc * - match formats and bands automatically * 22/5/14 * - wrap as a class * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include /* Define for debug output. #define DEBUG */ #include #include #include #include "pmosaicing.h" /* Blend luts. Shared between all lr and tb blends. */ double *vips__coef1 = NULL; double *vips__coef2 = NULL; int *vips__icoef1 = NULL; int *vips__icoef2 = NULL; /* Create a lut for the merging area. Always BLEND_SIZE entries, we * scale later when we index it. */ int vips__make_blend_luts(void) { int x; /* Already done? */ if (vips__coef1 && vips__coef2) return 0; /* Allocate and fill. */ vips__coef1 = VIPS_ARRAY(NULL, BLEND_SIZE, double); vips__coef2 = VIPS_ARRAY(NULL, BLEND_SIZE, double); vips__icoef1 = VIPS_ARRAY(NULL, BLEND_SIZE, int); vips__icoef2 = VIPS_ARRAY(NULL, BLEND_SIZE, int); if (!vips__coef1 || !vips__coef2 || !vips__icoef1 || !vips__icoef2) return -1; for (x = 0; x < BLEND_SIZE; x++) { double a = VIPS_PI * x / (BLEND_SIZE - 1.0); vips__coef1[x] = (cos(a) + 1.0) / 2.0; vips__coef2[x] = 1.0 - vips__coef1[x]; vips__icoef1[x] = vips__coef1[x] * BLEND_SCALE; vips__icoef2[x] = vips__coef2[x] * BLEND_SCALE; } return 0; } /* Return the position of the first non-zero pel from the left. */ static int find_first(VipsRegion *ir, int *pos, int x, int y, int w) { VipsPel *pr = VIPS_REGION_ADDR(ir, x, y); VipsImage *im = ir->im; int ne = w * im->Bands; int i; /* Double the number of bands in a complex. */ if (vips_band_format_iscomplex(im->BandFmt)) ne *= 2; /* Search for the first non-zero band element from the left edge of the image. */ #define lsearch(TYPE) \ { \ TYPE *p = (TYPE *) pr; \ \ for (i = 0; i < ne; i++) \ if (p[i]) \ break; \ } switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: lsearch(unsigned char); break; case VIPS_FORMAT_CHAR: lsearch(signed char); break; case VIPS_FORMAT_USHORT: lsearch(unsigned short); break; case VIPS_FORMAT_SHORT: lsearch(signed short); break; case VIPS_FORMAT_UINT: lsearch(unsigned int); break; case VIPS_FORMAT_INT: lsearch(signed int); break; case VIPS_FORMAT_FLOAT: lsearch(float); break; case VIPS_FORMAT_DOUBLE: lsearch(double); break; case VIPS_FORMAT_COMPLEX: lsearch(float); break; case VIPS_FORMAT_DPCOMPLEX: lsearch(double); break; default: g_assert_not_reached(); return -1; } /* i is first non-zero band element, we want first non-zero pixel. */ *pos = x + i / im->Bands; return 0; } /* Return the position of the first non-zero pel from the right. */ static int find_last(VipsRegion *ir, int *pos, int x, int y, int w) { VipsPel *pr = VIPS_REGION_ADDR(ir, x, y); VipsImage *im = ir->im; int ne = w * im->Bands; int i; /* Double the number of bands in a complex. */ if (vips_band_format_iscomplex(im->BandFmt)) ne *= 2; /* Search for the first non-zero band element from the right. */ #define rsearch(TYPE) \ { \ TYPE *p = (TYPE *) pr; \ \ for (i = ne - 1; i >= 0; i--) \ if (p[i]) \ break; \ } switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: rsearch(unsigned char); break; case VIPS_FORMAT_CHAR: rsearch(signed char); break; case VIPS_FORMAT_USHORT: rsearch(unsigned short); break; case VIPS_FORMAT_SHORT: rsearch(signed short); break; case VIPS_FORMAT_UINT: rsearch(unsigned int); break; case VIPS_FORMAT_INT: rsearch(signed int); break; case VIPS_FORMAT_FLOAT: rsearch(float); break; case VIPS_FORMAT_DOUBLE: rsearch(double); break; case VIPS_FORMAT_COMPLEX: rsearch(float); break; case VIPS_FORMAT_DPCOMPLEX: rsearch(double); break; default: vips_error("lrmerge", "%s", _("internal error")); return -1; } /* i is first non-zero band element, we want first non-zero pixel. */ *pos = x + i / im->Bands; return 0; } /* Make sure we have first/last for this area. */ static int make_firstlast(MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; VipsRect rr, sr; int y, yr, ys; int missing; /* We're going to build first/last ... lock it from other generate * threads. In fact it's harmless if we do get two writers, but we may * avoid duplicating work. */ g_mutex_lock(&ovlap->fl_lock); /* Do we already have first/last for this area? Bail out if we do. */ missing = 0; for (y = oreg->top; y < VIPS_RECT_BOTTOM(oreg); y++) { const int j = y - ovlap->overlap.top; const int first = ovlap->first[j]; if (first < 0) { missing = 1; break; } } if (!missing) { /* No work to do! */ g_mutex_unlock(&ovlap->fl_lock); return 0; } /* Entire width of overlap in ref for scan-lines we want. */ rr.left = ovlap->overlap.left; rr.top = oreg->top; rr.width = ovlap->overlap.width; rr.height = oreg->height; rr.left -= ovlap->rarea.left; rr.top -= ovlap->rarea.top; /* Entire width of overlap in sec for scan-lines we want. */ sr.left = ovlap->overlap.left; sr.top = oreg->top; sr.width = ovlap->overlap.width; sr.height = oreg->height; sr.left -= ovlap->sarea.left; sr.top -= ovlap->sarea.top; #ifdef DEBUG printf("lrmerge: making first/last for areas:\n"); printf("ref: left = %d, top = %d, width = %d, height = %d\n", rr.left, rr.top, rr.width, rr.height); printf("sec: left = %d, top = %d, width = %d, height = %d\n", sr.left, sr.top, sr.width, sr.height); #endif /* Make pixels. */ if (vips_region_prepare(rir, &rr) || vips_region_prepare(sir, &sr)) { g_mutex_unlock(&ovlap->fl_lock); return -1; } /* Make first/last cache. */ for (y = oreg->top, yr = rr.top, ys = sr.top; y < VIPS_RECT_BOTTOM(oreg); y++, yr++, ys++) { const int j = y - ovlap->overlap.top; int *first = &ovlap->first[j]; int *last = &ovlap->last[j]; /* Done this line already? */ if (*first < 0) { /* Search for start/end of overlap on this scan-line. */ if (find_first(sir, first, sr.left, ys, sr.width) || find_last(rir, last, rr.left, yr, rr.width)) { g_mutex_unlock(&ovlap->fl_lock); return -1; } /* Translate to output space. */ *first += ovlap->sarea.left; *last += ovlap->rarea.left; /* Clip to maximum blend width, if necessary. */ if (ovlap->mwidth >= 0 && *last - *first > ovlap->mwidth) { int shrinkby = (*last - *first) - ovlap->mwidth; *first += shrinkby / 2; *last -= shrinkby / 2; } } } g_mutex_unlock(&ovlap->fl_lock); return 0; } /* Test pixel == 0. */ #define TEST_ZERO(TYPE, T, RESULT) \ { \ TYPE *tt = (T); \ int ii; \ \ for (ii = 0; ii < cb; ii++) \ if (tt[i + ii]) \ break; \ if (ii == cb) \ (RESULT) = 1; \ } /* Blend two integer images. */ #define iblend(TYPE, B, IN1, IN2, OUT) \ { \ TYPE *tr = (TYPE *) (IN1); \ TYPE *ts = (TYPE *) (IN2); \ TYPE *tq = (TYPE *) (OUT); \ const int cb = (B); \ const int left = VIPS_CLIP(0, first - oreg->left, oreg->width); \ const int right = VIPS_CLIP(left, last - oreg->left, oreg->width); \ int ref_zero; \ int sec_zero; \ int x, b; \ int i; \ \ /* Left of the blend area. \ */ \ for (i = 0, x = 0; x < left; x++) { \ ref_zero = 0; \ TEST_ZERO(TYPE, tr, ref_zero); \ if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ \ /* In blend area. \ */ \ for (x = left; x < right; x++) { \ ref_zero = 0; \ sec_zero = 0; \ TEST_ZERO(TYPE, tr, ref_zero); \ TEST_ZERO(TYPE, ts, sec_zero); \ \ if (!ref_zero && !sec_zero) { \ int inx = ((x + oreg->left - first) << BLEND_SHIFT) / bwidth; \ int c1 = vips__icoef1[inx]; \ int c2 = vips__icoef2[inx]; \ \ for (b = 0; b < cb; b++, i++) \ tq[i] = c1 * tr[i] / BLEND_SCALE + \ c2 * ts[i] / BLEND_SCALE; \ } \ else if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ \ /* Right of blend. \ */ \ for (x = right; x < oreg->width; x++) { \ sec_zero = 0; \ TEST_ZERO(TYPE, ts, sec_zero); \ if (!sec_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ } \ } /* Blend two float images. */ #define fblend(TYPE, B, IN1, IN2, OUT) \ { \ TYPE *tr = (TYPE *) (IN1); \ TYPE *ts = (TYPE *) (IN2); \ TYPE *tq = (TYPE *) (OUT); \ const int cb = (B); \ const int left = VIPS_CLIP(0, first - oreg->left, oreg->width); \ const int right = VIPS_CLIP(left, last - oreg->left, oreg->width); \ int ref_zero; \ int sec_zero; \ int x, b; \ int i; \ \ /* Left of the blend area. \ */ \ for (i = 0, x = 0; x < left; x++) { \ ref_zero = 0; \ TEST_ZERO(TYPE, tr, ref_zero); \ if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ \ /* In blend area. \ */ \ for (x = left; x < right; x++) { \ ref_zero = 0; \ sec_zero = 0; \ TEST_ZERO(TYPE, tr, ref_zero); \ TEST_ZERO(TYPE, ts, sec_zero); \ \ if (!ref_zero && !sec_zero) { \ int inx = ((x + oreg->left - first) << BLEND_SHIFT) / bwidth; \ double c1 = vips__coef1[inx]; \ double c2 = vips__coef2[inx]; \ \ for (b = 0; b < cb; b++, i++) \ tq[i] = c1 * tr[i] + c2 * ts[i]; \ } \ else if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ \ /* Right of blend. \ */ \ for (x = right; x < oreg->width; x++) { \ sec_zero = 0; \ TEST_ZERO(TYPE, ts, sec_zero); \ if (!sec_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ } \ } /* Left-right blend function for non-labpack images. */ static int lr_blend(VipsRegion *out_region, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; VipsImage *im = out_region->im; VipsRect prr, psr; int y, yr, ys; /* Make sure we have a complete first/last set for this area. */ if (make_firstlast(inf, ovlap, oreg)) return -1; /* Part of rr which we will output. */ prr = *oreg; prr.left -= ovlap->rarea.left; prr.top -= ovlap->rarea.top; /* Part of sr which we will output. */ psr = *oreg; psr.left -= ovlap->sarea.left; psr.top -= ovlap->sarea.top; /* Make pixels. */ if (vips_region_prepare(rir, &prr) || vips_region_prepare(sir, &psr)) return -1; /* Loop down overlap area. */ for (y = oreg->top, yr = prr.top, ys = psr.top; y < VIPS_RECT_BOTTOM(oreg); y++, yr++, ys++) { VipsPel *pr = VIPS_REGION_ADDR(rir, prr.left, yr); VipsPel *ps = VIPS_REGION_ADDR(sir, psr.left, ys); VipsPel *q = VIPS_REGION_ADDR(out_region, oreg->left, y); const int j = y - ovlap->overlap.top; const int first = ovlap->first[j]; const int last = ovlap->last[j]; const int bwidth = last - first; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: iblend(unsigned char, im->Bands, pr, ps, q); break; case VIPS_FORMAT_CHAR: iblend(signed char, im->Bands, pr, ps, q); break; case VIPS_FORMAT_USHORT: iblend(unsigned short, im->Bands, pr, ps, q); break; case VIPS_FORMAT_SHORT: iblend(signed short, im->Bands, pr, ps, q); break; case VIPS_FORMAT_UINT: iblend(unsigned int, im->Bands, pr, ps, q); break; case VIPS_FORMAT_INT: iblend(signed int, im->Bands, pr, ps, q); break; case VIPS_FORMAT_FLOAT: fblend(float, im->Bands, pr, ps, q); break; case VIPS_FORMAT_DOUBLE: fblend(double, im->Bands, pr, ps, q); break; case VIPS_FORMAT_COMPLEX: fblend(float, im->Bands * 2, pr, ps, q); break; case VIPS_FORMAT_DPCOMPLEX: fblend(double, im->Bands * 2, pr, ps, q); break; default: g_assert_not_reached(); return -1; } } return 0; } /* Left-right blend function for VIPS_CODING_LABQ images. */ static int lr_blend_labpack(VipsRegion *out_region, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; VipsRect prr, psr; int y, yr, ys; /* Make sure we have a complete first/last set for this area. This * will just look at the top 8 bits of L, not all 10, but should be OK. */ if (make_firstlast(inf, ovlap, oreg)) return -1; /* Part of rr which we will output. */ prr = *oreg; prr.left -= ovlap->rarea.left; prr.top -= ovlap->rarea.top; /* Part of sr which we will output. */ psr = *oreg; psr.left -= ovlap->sarea.left; psr.top -= ovlap->sarea.top; /* Make pixels. */ if (vips_region_prepare(rir, &prr) || vips_region_prepare(sir, &psr)) return -1; /* Loop down overlap area. */ for (y = oreg->top, yr = prr.top, ys = psr.top; y < VIPS_RECT_BOTTOM(oreg); y++, yr++, ys++) { VipsPel *pr = VIPS_REGION_ADDR(rir, prr.left, yr); VipsPel *ps = VIPS_REGION_ADDR(sir, psr.left, ys); VipsPel *q = VIPS_REGION_ADDR(out_region, oreg->left, y); const int j = y - ovlap->overlap.top; const int first = ovlap->first[j]; const int last = ovlap->last[j]; const int bwidth = last - first; float *fq = inf->merge; float *r = inf->from1; float *s = inf->from2; /* Unpack two bits we want. */ vips__LabQ2Lab_vec(r, pr, oreg->width); vips__LabQ2Lab_vec(s, ps, oreg->width); /* Blend as floats. */ fblend(float, 3, r, s, fq); /* Re-pack to output buffer. */ vips__Lab2LabQ_vec(q, inf->merge, oreg->width); } return 0; } static void ovlap_free(VipsImage *image, Overlapping *ovlap) { g_mutex_clear(&ovlap->fl_lock); } /* Build basic per-call state and do some geometry calculations. Shared with * tbmerge, so not static. */ Overlapping * vips__build_mergestate(const char *domain, VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 4); VipsImage **array; Overlapping *ovlap; int x; /* TODO(kleisauke): Copied from vips_insert, perhaps we * need a separate function for this? * (just like im__insert_base) */ if (vips_image_pio_input(ref) || vips_image_pio_input(sec) || vips_check_bands_1orn(domain, ref, sec) || vips_check_coding_known(domain, ref) || vips_check_coding_same(domain, ref, sec)) return NULL; /* Cast our input images up to a common format and bands. */ if (vips__formatalike(ref, sec, &t[0], &t[1]) || vips__bandalike(domain, t[0], t[1], &t[2], &t[3])) return NULL; if (!(array = vips_allocate_input_array(out, t[2], t[3], NULL))) return NULL; if (vips_image_pipeline_array(out, VIPS_DEMAND_STYLE_SMALLTILE, array)) return NULL; if (mwidth < -1) { vips_error(domain, "%s", _("mwidth must be -1 or >= 0")); return NULL; } if (!(ovlap = VIPS_NEW(out, Overlapping))) return NULL; ovlap->ref = array[0]; ovlap->sec = array[1]; ovlap->out = out; ovlap->dx = dx; ovlap->dy = dy; ovlap->mwidth = mwidth; /* Area occupied by ref image. Place at (0,0) to start with. */ ovlap->rarea.left = 0; ovlap->rarea.top = 0; ovlap->rarea.width = ovlap->ref->Xsize; ovlap->rarea.height = ovlap->ref->Ysize; /* Area occupied by sec image. */ ovlap->sarea.left = -dx; ovlap->sarea.top = -dy; ovlap->sarea.width = ovlap->sec->Xsize; ovlap->sarea.height = ovlap->sec->Ysize; /* Compute overlap. */ vips_rect_intersectrect(&ovlap->rarea, &ovlap->sarea, &ovlap->overlap); if (vips_rect_isempty(&ovlap->overlap)) { vips_error(domain, "%s", _("no overlap")); return NULL; } /* Find position and size of output image. */ vips_rect_unionrect(&ovlap->rarea, &ovlap->sarea, &ovlap->oarea); /* Now: translate everything, so that the output image, not the left * image, is at (0,0). */ ovlap->rarea.left -= ovlap->oarea.left; ovlap->rarea.top -= ovlap->oarea.top; ovlap->sarea.left -= ovlap->oarea.left; ovlap->sarea.top -= ovlap->oarea.top; ovlap->overlap.left -= ovlap->oarea.left; ovlap->overlap.top -= ovlap->oarea.top; ovlap->oarea.left = 0; ovlap->oarea.top = 0; /* Make sure blend luts are built. */ vips__make_blend_luts(); /* Size of first/last cache. Could be either of these ... just pick * the larger. */ ovlap->flsize = VIPS_MAX(ovlap->overlap.width, ovlap->overlap.height); /* Build first/last cache. */ ovlap->first = VIPS_ARRAY(out, ovlap->flsize, int); ovlap->last = VIPS_ARRAY(out, ovlap->flsize, int); if (!ovlap->first || !ovlap->last) return NULL; for (x = 0; x < ovlap->flsize; x++) ovlap->first[x] = -1; g_mutex_init(&ovlap->fl_lock); g_signal_connect(out, "close", G_CALLBACK(ovlap_free), ovlap); return ovlap; } /* Build per-call state. */ static Overlapping * build_lrstate(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth) { Overlapping *ovlap; if (!(ovlap = vips__build_mergestate("lrmerge", ref, sec, out, dx, dy, mwidth))) return NULL; /* Select blender. */ switch (ovlap->ref->Coding) { case VIPS_CODING_LABQ: ovlap->blend = lr_blend_labpack; break; case VIPS_CODING_NONE: ovlap->blend = lr_blend; break; default: vips_error("lrmerge", "%s", _("unknown coding type")); return NULL; } /* Find the parts of output which come just from ref and just from sec. */ ovlap->rpart = ovlap->rarea; ovlap->spart = ovlap->sarea; ovlap->rpart.width -= ovlap->overlap.width; ovlap->spart.left += ovlap->overlap.width; ovlap->spart.width -= ovlap->overlap.width; /* Is there too much overlap? ie. right edge of ref image is greater * than right edge of sec image, or left > left. */ if (VIPS_RECT_RIGHT(&ovlap->rarea) > VIPS_RECT_RIGHT(&ovlap->sarea) || ovlap->rarea.left > ovlap->sarea.left) { vips_error("lrmerge", "%s", _("too much overlap")); return NULL; } /* Max number of pixels we may have to blend over. */ ovlap->blsize = ovlap->overlap.width; return ovlap; } /* The area being demanded can be filled using only pels from either the ref * or the sec images. Attach output to the appropriate part of the input image. * area is the position that ir->im occupies in the output image. * * Shared with tbmerge, so not static. */ int vips__attach_input(VipsRegion *out_region, VipsRegion *ir, VipsRect *area) { VipsRect r = out_region->valid; /* Translate to source coordinate space. */ r.left -= area->left; r.top -= area->top; /* Demand input. */ if (vips_region_prepare(ir, &r)) return -1; /* Attach or to ir. */ if (vips_region_region(out_region, ir, &out_region->valid, r.left, r.top)) return -1; return 0; } /* The area being demanded requires pixels from the ref and sec images. As * above, but just do a sub-area of the output, and make sure we copy rather * than just pointer-fiddling. reg is the sub-area of out_region->valid we * should do. * * Shared with tbmerge, so not static. */ int vips__copy_input(VipsRegion *out_region, VipsRegion *ir, VipsRect *area, VipsRect *reg) { VipsRect r = *reg; /* Translate to source coordinate space. */ r.left -= area->left; r.top -= area->top; /* Paint this area of ir into out_region. */ if (vips_region_prepare_to(ir, out_region, &r, reg->left, reg->top)) return -1; return 0; } /* Generate function for merge. This is shared between lrmerge and * tbmerge. */ int vips__merge_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { MergeInfo *inf = (MergeInfo *) seq; Overlapping *ovlap = (Overlapping *) a; VipsRect *r = &out_region->valid; VipsRect rreg, sreg, oreg; /* Find intersection with overlap, ref and sec parts. */ vips_rect_intersectrect(r, &ovlap->rpart, &rreg); vips_rect_intersectrect(r, &ovlap->spart, &sreg); /* Do easy cases first: can we satisfy this demand with pixels just * from ref, or just from sec. */ if (vips_rect_equalsrect(r, &rreg)) { if (vips__attach_input(out_region, inf->rir, &ovlap->rarea)) return -1; } else if (vips_rect_equalsrect(r, &sreg)) { if (vips__attach_input(out_region, inf->sir, &ovlap->sarea)) return -1; } else { /* Difficult case - do in three stages: black out whole area, * copy in parts of ref and sec we touch, write blend area. * This could be sped up somewhat ... we will usually black * out far too much, and write to the blend area three times. * Upgrade in the future! */ /* Need intersections with whole of left & right, and overlap * too. */ vips_rect_intersectrect(r, &ovlap->rarea, &rreg); vips_rect_intersectrect(r, &ovlap->sarea, &sreg); vips_rect_intersectrect(r, &ovlap->overlap, &oreg); vips_region_black(out_region); if (!vips_rect_isempty(&rreg)) if (vips__copy_input(out_region, inf->rir, &ovlap->rarea, &rreg)) return -1; if (!vips_rect_isempty(&sreg)) if (vips__copy_input(out_region, inf->sir, &ovlap->sarea, &sreg)) return -1; /* Nasty: inf->rir and inf->sir now point to the same bit of * memory (part of out_region), and we've written twice. We * need to make sure we get fresh pixels for the blend, so * we must invalidate them both. Should maybe add a call to * the API for this. */ inf->rir->valid.width = inf->sir->valid.width = 0; /* Now blat in the blended area. */ if (!vips_rect_isempty(&oreg)) if (ovlap->blend(out_region, inf, ovlap, &oreg)) return -1; } return 0; } /* Stop function. Shared with tbmerge. Free explicitly to reduce mem * requirements quickly for large mosaics. */ int vips__stop_merge(void *seq, void *a, void *b) { MergeInfo *inf = (MergeInfo *) seq; VIPS_UNREF(inf->rir); VIPS_UNREF(inf->sir); VIPS_FREE(inf->from1); VIPS_FREE(inf->from2); VIPS_FREE(inf->merge); g_free(inf); return 0; } /* Start function. Shared with tbmerge. */ void * vips__start_merge(VipsImage *out, void *a, void *b) { Overlapping *ovlap = (Overlapping *) a; MergeInfo *inf; if (!(inf = VIPS_NEW(NULL, MergeInfo))) return NULL; inf->rir = NULL; inf->sir = NULL; inf->from1 = NULL; inf->from2 = NULL; inf->merge = NULL; /* If this is going to be a VIPS_CODING_LABQ, we need VIPS_CODING_LABQ * blend buffers. */ if (out->Coding == VIPS_CODING_LABQ) { inf->from1 = VIPS_ARRAY(NULL, ovlap->blsize * 3, float); inf->from2 = VIPS_ARRAY(NULL, ovlap->blsize * 3, float); inf->merge = VIPS_ARRAY(NULL, ovlap->blsize * 3, float); if (!inf->from1 || !inf->from2 || !inf->merge) { vips__stop_merge(inf, NULL, NULL); return NULL; } } inf->rir = vips_region_new(ovlap->ref); inf->sir = vips_region_new(ovlap->sec); if (!inf->rir || !inf->sir) { vips__stop_merge(inf, NULL, NULL); return NULL; } return inf; } int vips__lrmerge(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth) { Overlapping *ovlap; #ifdef DEBUG printf("lrmerge %s %s %s %d %d %d\n", ref->filename, sec->filename, out->filename, dx, dy, mwidth); printf("ref is %d x %d pixels\n", ref->Xsize, ref->Ysize); printf("sec is %d x %d pixels\n", sec->Xsize, sec->Ysize); #endif if (dx > 0 || dx < 1 - ref->Xsize) { VipsImage *x; #ifdef DEBUG printf("lrmerge: no overlap, using insert\n"); #endif /* No overlap, use insert instead. */ if (vips_insert(ref, sec, &x, -dx, -dy, "expand", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); out->Xoffset = -dx; out->Yoffset = -dy; return 0; } if (!(ovlap = build_lrstate(ref, sec, out, dx, dy, mwidth))) return -1; if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, ovlap->ref, ovlap->sec, NULL)) return -1; out->Xsize = ovlap->oarea.width; out->Ysize = ovlap->oarea.height; out->Xoffset = -dx; out->Yoffset = -dy; if (vips_image_generate(out, vips__start_merge, vips__merge_gen, vips__stop_merge, ovlap, NULL)) return -1; return 0; } const char * vips__get_mosaic_name(VipsImage *image) { const char *name; if (vips_image_get_typeof(image, "mosaic-name")) { if (vips_image_get_string(image, "mosaic-name", &name)) return NULL; } else name = image->filename; return name; } void vips__add_mosaic_name(VipsImage *image) { static int global_serial = 0; /* TODO(kleisauke): Could we call vips_image_temp_name instead? */ int serial = g_atomic_int_add(&global_serial, 1); char name[256]; /* We must override any inherited name, so don't test for doesn't * exist before setting. */ g_snprintf(name, 256, "mosaic-temp-%d", serial); vips_image_set_string(image, "mosaic-name", name); } libvips-8.18.2/libvips/mosaicing/lrmosaic.c000066400000000000000000000155171516303661500206770ustar00rootroot00000000000000/* join left-right with an approximate overlap * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 07/11/1989 * Modified on : 29/11/1989, 18/04/1991 * * * Modified and debugged by Ahmed Abbood . 1995 * 14/6/95 JC * - rewritten for new balance ideas * - more bug-fixes * 1/11/95 JC * - frees memory used by analysis phase as soon as possible * - means large mosaics use significantly less peak memory * 26/3/96 JC * - now calls im_lrmerge() rather than im__lrmerge() * 2/2/01 JC * - added tunable max blend width * 24/2/05 * - im_scale() makes it work for any image type * 25/1/11 * - gtk-doc * - remove balance stuff * - any mix of types and bands * - cleanups * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Define for debug output. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" #ifdef DEBUG static void vips__print_mdebug(TiePoints *points) { int i; double adx = 0.0; double ady = 0.0; double acor = 0.0; for (i = 0; i < points->nopoints; i++) { adx += points->dx[i]; ady += points->dy[i]; acor += points->correlation[i]; } adx = adx / (double) points->nopoints; ady = ady / (double) points->nopoints; acor = acor / (double) points->nopoints; printf("points: %d\n", points->nopoints); printf("average dx, dy: %g %g\n", adx, ady); printf("average correlation: %g\n", acor); printf("deltax, deltay: %g %g\n", points->l_deltax, points->l_deltay); } #endif /*DEBUG*/ int vips__find_lroverlap(VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 6); VipsRect left, right, overlap; TiePoints points, *p_points; TiePoints newpoints, *p_newpoints; int i; int dx, dy; /* Test cor and area. */ if (halfcorrelation < 0 || halfarea < 0 || halfarea < halfcorrelation) { vips_error("vips__lrmosaic", "%s", _("bad area parameters")); return -1; } /* Set positions of left and right. */ left.left = 0; left.top = 0; left.width = ref_in->Xsize; left.height = ref_in->Ysize; right.left = xref - xsec; right.top = yref - ysec; right.width = sec_in->Xsize; right.height = sec_in->Ysize; /* Find overlap. */ vips_rect_intersectrect(&left, &right, &overlap); if (overlap.width < 2 * halfarea + 1 || overlap.height < 2 * halfarea + 1) { vips_error("vips__lrmosaic", "%s", _("overlap too small for search")); return -1; } /* Extract overlaps as 8-bit, 1 band. */ if (vips_extract_area(ref_in, &t[0], overlap.left, overlap.top, overlap.width, overlap.height, NULL) || vips_extract_area(sec_in, &t[1], overlap.left - right.left, overlap.top - right.top, overlap.width, overlap.height, NULL)) return -1; if (ref_in->Coding == VIPS_CODING_LABQ) { if (vips_LabQ2sRGB(t[0], &t[2], NULL) || vips_LabQ2sRGB(t[1], &t[3], NULL) || vips_extract_band(t[2], &t[4], 1, NULL) || vips_extract_band(t[3], &t[5], 1, NULL)) return -1; } else if (ref_in->Coding == VIPS_CODING_NONE) { if (vips_extract_band(t[0], &t[2], bandno_in, NULL) || vips_extract_band(t[1], &t[3], bandno_in, NULL) || vips_scale(t[2], &t[4], NULL) || vips_scale(t[3], &t[5], NULL)) return -1; } else { vips_error("vips__lrmosaic", "%s", _("unknown Coding type")); return -1; } /* Initialise and fill TiePoints */ p_points = &points; p_newpoints = &newpoints; p_points->reference = ref_in->filename; p_points->secondary = sec_in->filename; p_points->nopoints = VIPS_MAXPOINTS; p_points->deltax = 0; p_points->deltay = 0; p_points->halfcorsize = halfcorrelation; p_points->halfareasize = halfarea; /* Initialise the structure */ for (i = 0; i < VIPS_MAXPOINTS; i++) { p_points->x_reference[i] = 0; p_points->y_reference[i] = 0; p_points->x_secondary[i] = 0; p_points->y_secondary[i] = 0; p_points->contrast[i] = 0; p_points->correlation[i] = 0.0; p_points->dx[i] = 0.0; p_points->dy[i] = 0.0; p_points->deviation[i] = 0.0; } /* Search ref for possible tie-points. Sets: p_points->contrast, * p_points->x,y_reference. */ if (vips__lrcalcon(t[4], p_points)) return -1; /* For each candidate point, correlate against corresponding part of * sec. Sets x,y_secondary and fills correlation and dx, dy. */ if (vips__chkpair(t[4], t[5], p_points)) return -1; /* First call to vips_clinear(). */ if (vips__initialize(p_points)) return -1; /* Improve the selection of tiepoints until all abs(deviations) are * < 1.0 by deleting all wrong points. */ if (vips__improve(p_points, p_newpoints)) return -1; /* Average remaining offsets. */ if (vips__avgdxdy(p_newpoints, &dx, &dy)) return -1; /* Offset with overlap position. */ *dx0 = -right.left + dx; *dy0 = -right.top + dy; /* Write 1st order parameters too. */ *scale1 = newpoints.l_scale; *angle1 = newpoints.l_angle; *dx1 = newpoints.l_deltax; *dy1 = newpoints.l_deltay; return 0; } int vips__lrmosaic(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int mwidth) { int dx0, dy0; double scale1, angle1, dx1, dy1; VipsImage *dummy; VipsImage *x; /* Correct overlap. dummy is just a placeholder used to ensure that * memory used by the analysis phase is freed as soon as possible. */ dummy = vips_image_new(); if (vips__find_lroverlap(ref, sec, dummy, bandno, xref, yref, xsec, ysec, hwindowsize, hsearchsize, &dx0, &dy0, &scale1, &angle1, &dx1, &dy1)) { g_object_unref(dummy); return -1; } g_object_unref(dummy); /* Merge left right. */ if (vips_merge(ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, dx0, dy0, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } libvips-8.18.2/libvips/mosaicing/match.c000066400000000000000000000213761516303661500201620ustar00rootroot00000000000000/* Match images. */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" /* Given a pair of points, return scale, angle, dx, dy to resample the 2nd * image with. */ int vips__coeff(int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, double *a, double *b, double *dx, double *dy) { VipsImage **t = VIPS_ARRAY(NULL, 2, VipsImage *); if (!(t[0] = vips_image_new_matrixv(4, 4, (double) xs1, (double) -ys1, 1.0, 0.0, (double) ys1, (double) xs1, 0.0, 1.0, (double) xs2, (double) -ys2, 1.0, 0.0, (double) ys2, (double) xs2, 0.0, 1.0))) { g_free(t); return -1; } if (vips_matrixinvert(t[0], &t[1], NULL)) { g_object_unref(t[0]); g_free(t); return -1; } *a = *VIPS_MATRIX(t[1], 0, 0) * xr1 + *VIPS_MATRIX(t[1], 1, 0) * yr1 + *VIPS_MATRIX(t[1], 2, 0) * xr2 + *VIPS_MATRIX(t[1], 3, 0) * yr2; *b = *VIPS_MATRIX(t[1], 0, 1) * xr1 + *VIPS_MATRIX(t[1], 1, 1) * yr1 + *VIPS_MATRIX(t[1], 2, 1) * xr2 + *VIPS_MATRIX(t[1], 3, 1) * yr2; *dx = *VIPS_MATRIX(t[1], 0, 2) * xr1 + *VIPS_MATRIX(t[1], 1, 2) * yr1 + *VIPS_MATRIX(t[1], 2, 2) * xr2 + *VIPS_MATRIX(t[1], 3, 2) * yr2; *dy = *VIPS_MATRIX(t[1], 0, 3) * xr1 + *VIPS_MATRIX(t[1], 1, 3) * yr1 + *VIPS_MATRIX(t[1], 2, 3) * xr2 + *VIPS_MATRIX(t[1], 3, 3) * yr2; g_object_unref(t[0]); g_object_unref(t[1]); g_free(t); return 0; } typedef struct { VipsOperation parent_instance; VipsImage *ref; VipsImage *sec; VipsImage *out; int xr1; int yr1; int xs1; int ys1; int xr2; int yr2; int xs2; int ys2; int hwindow; int harea; gboolean search; VipsInterpolate *interpolate; } VipsMatch; typedef VipsOperationClass VipsMatchClass; G_DEFINE_TYPE(VipsMatch, vips_match, VIPS_TYPE_OPERATION); static int vips_match_build(VipsObject *object) { VipsMatch *match = (VipsMatch *) object; double a, b, dx, dy; VipsArrayInt *oarea; VipsImage *x; g_object_set(match, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_match_parent_class)->build(object)) return -1; if (!match->interpolate) match->interpolate = vips_interpolate_new("bilinear"); // FIXME: Invalidates operation cache if (match->search) { int xs, ys; double cor; if (vips__correl(match->ref, match->sec, match->xr1, match->yr1, match->xs1, match->ys1, match->hwindow, match->harea, &cor, &xs, &ys)) return -1; match->xs1 = xs; // FIXME: Invalidates operation cache match->ys1 = ys; // FIXME: Invalidates operation cache if (vips__correl(match->ref, match->sec, match->xr2, match->yr2, match->xs2, match->ys2, match->hwindow, match->harea, &cor, &xs, &ys)) return -1; match->xs2 = xs; // FIXME: Invalidates operation cache match->ys2 = ys; // FIXME: Invalidates operation cache } /* Solve to get scale + rot + disp to obtain match. */ if (vips__coeff(match->xr1, match->yr1, match->xs1, match->ys1, match->xr2, match->yr2, match->xs2, match->ys2, &a, &b, &dx, &dy)) return -1; /* Output area of ref image. */ oarea = vips_array_int_newv(4, 0, 0, match->ref->Xsize, match->ref->Ysize); if (vips_affine(match->sec, &x, a, -b, b, a, "interpolate", match->interpolate, "odx", dx, "ody", dy, "oarea", oarea, NULL)) { vips_area_unref(VIPS_AREA(oarea)); return -1; } vips_area_unref(VIPS_AREA(oarea)); if (vips_image_write(x, match->out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } static void vips_match_class_init(VipsMatchClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "match"; object_class->description = _("first-order match of two images"); object_class->build = vips_match_build; VIPS_ARG_IMAGE(class, "ref", 1, _("Reference"), _("Reference image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, ref)); VIPS_ARG_IMAGE(class, "sec", 2, _("Secondary"), _("Secondary image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, sec)); VIPS_ARG_IMAGE(class, "out", 3, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMatch, out)); VIPS_ARG_INT(class, "xr1", 5, _("xr1"), _("Position of first reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, xr1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "yr1", 6, _("yr1"), _("Position of first reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, yr1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "xs1", 7, _("xs1"), _("Position of first secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, xs1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "ys1", 8, _("ys1"), _("Position of first secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, ys1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "xr2", 9, _("xr2"), _("Position of second reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, xr2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "yr2", 10, _("yr2"), _("Position of second reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, yr2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "xs2", 11, _("xs2"), _("Position of second secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, xs2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "ys2", 12, _("ys2"), _("Position of second secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatch, ys2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "hwindow", 13, _("hwindow"), _("Half window size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMatch, hwindow), 0, 1000000000, 5); VIPS_ARG_INT(class, "harea", 14, _("harea"), _("Half area size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMatch, harea), 0, 1000000000, 15); VIPS_ARG_BOOL(class, "search", 15, _("Search"), _("Search to improve tie-points"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMatch, search), FALSE); VIPS_ARG_INTERPOLATE(class, "interpolate", 16, _("Interpolate"), _("Interpolate pixels with this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMatch, interpolate)); } static void vips_match_init(VipsMatch *match) { match->hwindow = 5; match->harea = 15; match->search = FALSE; } /** * vips_match: (method) * @ref: reference image * @sec: secondary image * @out: (out): output image * @xr1: first reference tie-point * @yr1: first reference tie-point * @xs1: first secondary tie-point * @ys1: first secondary tie-point * @xr2: second reference tie-point * @yr2: second reference tie-point * @xs2: second secondary tie-point * @ys2: second secondary tie-point * @...: `NULL`-terminated list of optional named arguments * * Scale, rotate and translate @sec so that the tie-points line up. * * If @search is `TRUE`, before performing the transformation, the tie-points * are improved by searching an area of @sec of size @harea for a * match of size @hwindow to @ref. * * This function will only work well for small rotates and scales. * * ::: tip "Optional arguments" * * @search: `gboolean`, search to improve tie-points * * @hwindow: `gint`, half window size * * @harea: `gint`, half search size * * @interpolate: [class@Interpolate], interpolate pixels with this * * Returns: 0 on success, -1 on error */ int vips_match(VipsImage *ref, VipsImage *sec, VipsImage **out, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, ...) { va_list ap; int result; va_start(ap, ys2); result = vips_call_split("match", ap, ref, sec, out, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/matrixinvert.c000066400000000000000000000262421516303661500216170ustar00rootroot00000000000000/* solve and invert matrices * * 19/4/20 kleisauke * - from im_matinv */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include /* Our state. */ typedef struct _VipsMatrixinvert { VipsOperation parent_instance; VipsImage *in; VipsImage *out; /* .. and cast to a matrix. */ VipsImage *mat; /* The LU decomposed matrix. */ VipsImage *lu; } VipsMatrixinvert; typedef VipsOperationClass VipsMatrixinvertClass; G_DEFINE_TYPE(VipsMatrixinvert, vips_matrixinvert, VIPS_TYPE_OPERATION); static void vips_matrixinvert_dispose(GObject *gobject) { VipsMatrixinvert *matrix = (VipsMatrixinvert *) gobject; VIPS_UNREF(matrix->mat); VIPS_UNREF(matrix->lu); G_OBJECT_CLASS(vips_matrixinvert_parent_class)->dispose(gobject); } /* DBL_MIN is smallest *normalized* double precision float */ #define TOO_SMALL (2.0 * DBL_MIN) /* Save a bit of typing. */ #define ME(m, i, j) (*VIPS_MATRIX((m), (i), (j))) /** * lu_decomp: * @mat: matrix to decompose * * This function takes any square NxN [class@Image]. * It returns a [class@Image] which is (N+1)xN. * * It calculates the PLU decomposition, storing the upper and diagonal parts * of U, together with the lower parts of L, as an NxN matrix in the first * N rows of the new matrix. The diagonal parts of L are all set to unity * and are not stored. * * The final row of the new [class@Image] has only integer entries, which * represent the row-wise permutations made by the permutation matrix P. * * The scale and offset members of the input [class@Image] are ignored. * * See: * * PRESS, W. et al, 1992. Numerical Recipes in C; The Art of Scientific * Computing, 2nd ed. Cambridge: Cambridge University Press, pp. 43-50. * * Returns: the decomposed matrix on success, or `NULL` on error. */ static VipsImage * lu_decomp(VipsImage *mat) { int i, j, k; double *row_scale; VipsImage *lu; if (!(row_scale = VIPS_ARRAY(NULL, mat->Xsize, double))) { return NULL; } if (!(lu = vips_image_new_matrix(mat->Xsize, mat->Xsize + 1))) { g_free(row_scale); return NULL; } /* copy all coefficients and then perform decomposition in-place */ memcpy(VIPS_MATRIX(lu, 0, 0), VIPS_MATRIX(mat, 0, 0), (size_t) mat->Xsize * mat->Xsize * sizeof(double)); for (i = 0; i < mat->Xsize; ++i) { row_scale[i] = 0.0; for (j = 0; j < mat->Xsize; ++j) { double abs_val = fabs(ME(lu, i, j)); /* find largest in each ROW */ if (abs_val > row_scale[i]) row_scale[i] = abs_val; } if (!row_scale[i]) { vips_error("matrixinvert", "singular matrix"); g_object_unref(lu); g_free(row_scale); return NULL; } /* fill array with scaling factors for each ROW */ row_scale[i] = 1.0 / row_scale[i]; } for (j = 0; j < mat->Xsize; ++j) { /* loop over COLs */ double max = -1.0; int i_of_max; /* not needed, but stops a compiler warning */ i_of_max = 0; /* loop over ROWS in upper-half, except diagonal */ for (i = 0; i < j; ++i) for (k = 0; k < i; ++k) ME(lu, i, j) -= ME(lu, i, k) * ME(lu, k, j); /* loop over ROWS in diagonal and lower-half */ for (i = j; i < mat->Xsize; ++i) { double abs_val; for (k = 0; k < j; ++k) ME(lu, i, j) -= ME(lu, i, k) * ME(lu, k, j); /* find largest element in each COLUMN scaled so that */ /* largest in each ROW is 1.0 */ abs_val = row_scale[i] * fabs(ME(lu, i, j)); if (abs_val > max) { max = abs_val; i_of_max = i; } } if (fabs(ME(lu, i_of_max, j)) < TOO_SMALL) { /* divisor is near zero */ vips_error("matrixinvert", "singular or near-singular matrix"); g_object_unref(lu); g_free(row_scale); return NULL; } if (i_of_max != j) { /* swap ROWS */ for (k = 0; k < mat->Xsize; ++k) { double temp = ME(lu, j, k); ME(lu, j, k) = ME(lu, i_of_max, k); ME(lu, i_of_max, k) = temp; } row_scale[i_of_max] = row_scale[j]; /* no need to copy this scale back up - we won't use it */ } /* record permutation */ ME(lu, j, mat->Xsize) = i_of_max; /* divide by best (largest scaled) pivot found */ for (i = j + 1; i < mat->Xsize; ++i) ME(lu, i, j) /= ME(lu, j, j); } g_free(row_scale); return lu; } /** * lu_solve: * @lu: matrix to solve * @vec: name for output matrix * * Solve the system of linear equations Ax=b, where matrix A has already * been decomposed into LU form in @lu. Input vector b is in * vec and is overwritten with vector x. * * See: * * PRESS, W. et al, 1992. Numerical Recipes in C; The Art of Scientific * Computing, 2nd ed. Cambridge: Cambridge University Press, pp. 43-50. * * ::: seealso * [method@Image.matrixmultiply]. * * Returns: 0 on success, -1 on error */ static int lu_solve(VipsImage *lu, double *vec) { int i, j; if (lu->Xsize + 1 != lu->Ysize) { vips_error("matrixinvert", "not an LU decomposed matrix"); return -1; } for (i = 0; i < lu->Xsize; ++i) { int i_perm = ME(lu, i, lu->Xsize); if (i_perm != i) { double temp = vec[i]; vec[i] = vec[i_perm]; vec[i_perm] = temp; } for (j = 0; j < i; ++j) vec[i] -= ME(lu, i, j) * vec[j]; } for (i = lu->Xsize - 1; i >= 0; --i) { for (j = i + 1; j < lu->Xsize; ++j) vec[i] -= ME(lu, i, j) * vec[j]; vec[i] /= ME(lu, i, i); } return 0; } static int vips_matrixinvert_solve(VipsMatrixinvert *matrix) { VipsImage *out = matrix->out; int i, j; double *vec; if (!(matrix->lu = lu_decomp(matrix->mat))) return -1; if (!(vec = VIPS_ARRAY(matrix, matrix->lu->Xsize, double))) return -1; for (j = 0; j < matrix->lu->Xsize; ++j) { for (i = 0; i < matrix->lu->Xsize; ++i) vec[i] = 0.0; vec[j] = 1.0; if (lu_solve(matrix->lu, vec)) return -1; for (i = 0; i < matrix->lu->Xsize; ++i) ME(out, i, j) = vec[i]; } return 0; } static int vips_matrixinvert_direct(VipsMatrixinvert *matrix) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(matrix); VipsImage *in = matrix->mat; VipsImage *out = matrix->out; switch (matrix->mat->Xsize) { case 1: { double det = ME(in, 0, 0); if (fabs(det) < TOO_SMALL) { /* divisor is near zero */ vips_error(class->nickname, "%s", _("singular or near-singular matrix")); return -1; } ME(out, 0, 0) = 1.0 / det; } break; case 2: { double det = ME(in, 0, 0) * ME(in, 1, 1) - ME(in, 0, 1) * ME(in, 1, 0); double tmp; if (fabs(det) < TOO_SMALL) { /* divisor is near zero */ vips_error(class->nickname, "%s", _("singular or near-singular matrix")); return -1; } tmp = 1.0 / det; ME(out, 0, 0) = tmp * ME(in, 1, 1); ME(out, 0, 1) = -tmp * ME(in, 0, 1); ME(out, 1, 0) = -tmp * ME(in, 1, 0); ME(out, 1, 1) = tmp * ME(in, 0, 0); } break; case 3: { double det; double tmp; det = ME(in, 0, 0) * (ME(in, 1, 1) * ME(in, 2, 2) - ME(in, 1, 2) * ME(in, 2, 1)); det -= ME(in, 0, 1) * (ME(in, 1, 0) * ME(in, 2, 2) - ME(in, 1, 2) * ME(in, 2, 0)); det += ME(in, 0, 2) * (ME(in, 1, 0) * ME(in, 2, 1) - ME(in, 1, 1) * ME(in, 2, 0)); if (fabs(det) < TOO_SMALL) { /* divisor is near zero */ vips_error(class->nickname, "%s", _("singular or near-singular matrix")); return -1; } tmp = 1.0 / det; ME(out, 0, 0) = tmp * (ME(in, 1, 1) * ME(in, 2, 2) - ME(in, 1, 2) * ME(in, 2, 1)); ME(out, 1, 0) = tmp * (ME(in, 1, 2) * ME(in, 2, 0) - ME(in, 1, 0) * ME(in, 2, 2)); ME(out, 2, 0) = tmp * (ME(in, 1, 0) * ME(in, 2, 1) - ME(in, 1, 1) * ME(in, 2, 0)); ME(out, 0, 1) = tmp * (ME(in, 0, 2) * ME(in, 2, 1) - ME(in, 0, 1) * ME(in, 2, 2)); ME(out, 1, 1) = tmp * (ME(in, 0, 0) * ME(in, 2, 2) - ME(in, 0, 2) * ME(in, 2, 0)); ME(out, 2, 1) = tmp * (ME(in, 0, 1) * ME(in, 2, 0) - ME(in, 0, 0) * ME(in, 2, 1)); ME(out, 0, 2) = tmp * (ME(in, 0, 1) * ME(in, 1, 2) - ME(in, 0, 2) * ME(in, 1, 1)); ME(out, 1, 2) = tmp * (ME(in, 0, 2) * ME(in, 1, 0) - ME(in, 0, 0) * ME(in, 1, 2)); ME(out, 2, 2) = tmp * (ME(in, 0, 0) * ME(in, 1, 1) - ME(in, 0, 1) * ME(in, 1, 0)); } break; /* TODO(kleisauke): * We sometimes use 4x4 matrices, could we also make a * direct version for those? For e.g.: * https://stackoverflow.com/a/1148405/10952119 */ default: g_assert(0); return -1; } return 0; } static int vips_matrixinvert_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsMatrixinvert *matrix = (VipsMatrixinvert *) object; if (VIPS_OBJECT_CLASS(vips_matrixinvert_parent_class)->build(object)) return -1; if (vips_check_matrix(class->nickname, matrix->in, &matrix->mat)) return -1; if (matrix->mat->Xsize != matrix->mat->Ysize) { vips_error(class->nickname, "%s", _("non-square matrix")); return -1; } g_object_set(matrix, "out", vips_image_new_matrix(matrix->mat->Xsize, matrix->mat->Ysize), NULL); /* Direct path for < 4x4 matrices */ if (matrix->mat->Xsize >= 4) { if (vips_matrixinvert_solve(matrix)) return -1; } else { if (vips_matrixinvert_direct(matrix)) return -1; } return 0; } static void vips_matrixinvert_class_init(VipsMatrixinvertClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = vips_matrixinvert_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "matrixinvert"; vobject_class->description = _("invert a matrix"); vobject_class->build = vips_matrixinvert_build; VIPS_ARG_IMAGE(class, "in", 0, _("Input"), _("An square matrix"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatrixinvert, in)); VIPS_ARG_IMAGE(class, "out", 1, _("Output"), _("Output matrix"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMatrixinvert, out)); } static void vips_matrixinvert_init(VipsMatrixinvert *matrix) { } /** * vips_matrixinvert: (method) * @m: matrix to invert * @out: (out): output matrix * @...: `NULL`-terminated list of optional named arguments * * This operation calculates the inverse of the matrix represented in @m. * The scale and offset members of the input matrix are ignored. * * ::: seealso * [ctor@Image.matrixload], [method@Image.matrixmultiply]. * * Returns: 0 on success, -1 on error */ int vips_matrixinvert(VipsImage *m, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("matrixinvert", ap, m, out); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/matrixmultiply.c000066400000000000000000000107551516303661500221710ustar00rootroot00000000000000/* Multiply two matrices. * * Copyright: 1990, K. Martinez and J. Cupitt * * 23/10/10 * - gtk-doc * 31/1/25 * - wrapped as a class */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include /* Our state. */ typedef struct _VipsMatrixmultiply { VipsOperation parent_instance; VipsImage *left; VipsImage *right; VipsImage *out; VipsImage *mat1; VipsImage *mat2; } VipsMatrixmultiply; typedef VipsOperationClass VipsMatrixmultiplyClass; G_DEFINE_TYPE(VipsMatrixmultiply, vips_matrixmultiply, VIPS_TYPE_OPERATION); static void vips_matrixmultiply_dispose(GObject *gobject) { VipsMatrixmultiply *matrix = (VipsMatrixmultiply *) gobject; VIPS_UNREF(matrix->mat1); VIPS_UNREF(matrix->mat2); G_OBJECT_CLASS(vips_matrixmultiply_parent_class)->dispose(gobject); } static int vips_matrixmultiply_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsMatrixmultiply *matrix = (VipsMatrixmultiply *) object; if (VIPS_OBJECT_CLASS(vips_matrixmultiply_parent_class)->build(object)) return -1; if (vips_check_matrix(class->nickname, matrix->left, &matrix->mat1) || vips_check_matrix(class->nickname, matrix->right, &matrix->mat2)) return -1; if (matrix->mat1->Xsize != matrix->mat2->Ysize) { vips_error(class->nickname, "%s", _("bad sizes")); return -1; } g_object_set(matrix, "out", vips_image_new_matrix(matrix->mat2->Xsize, matrix->mat1->Ysize), NULL); /* Multiply. */ double *out; double *s1; s1 = VIPS_MATRIX(matrix->mat1, 0, 0); out = VIPS_MATRIX(matrix->out, 0, 0); for (int yc = 0; yc < matrix->mat1->Ysize; yc++) { double *s2 = VIPS_MATRIX(matrix->mat2, 0, 0); for (int col = 0; col < matrix->mat2->Xsize; col++) { /* Get ready to sweep a row. */ double *a = s1; double *b = s2; double sum; sum = 0.0; for (int xc = 0; xc < matrix->mat1->Xsize; xc++) { sum += *a++ * *b; b += matrix->mat2->Xsize; } *out++ = sum; s2 += 1; } s1 += matrix->mat1->Xsize; } return 0; } static void vips_matrixmultiply_class_init(VipsMatrixmultiplyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->dispose = vips_matrixmultiply_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "matrixmultiply"; vobject_class->description = _("multiply two matrices"); vobject_class->build = vips_matrixmultiply_build; VIPS_ARG_IMAGE(class, "left", 1, _("Left"), _("First matrix to multiply"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatrixmultiply, left)); VIPS_ARG_IMAGE(class, "right", 2, _("Right"), _("Second matrix to multiply"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMatrixmultiply, right)); VIPS_ARG_IMAGE(class, "out", 3, _("Output"), _("Output matrix"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMatrixmultiply, out)); } static void vips_matrixmultiply_init(VipsMatrixmultiply *matrix) { } /** * vips_matrixmultiply: (method) * @left: input matrix * @right: input matrix * @out: (out): output matrix * @...: `NULL`-terminated list of optional named arguments * * Multiplies two matrix images. * * The scale and offset members of @left and @right are ignored. * * ::: seealso * [method@Image.matrixinvert]. * * Returns: 0 on success, -1 on error */ int vips_matrixmultiply(VipsImage *left, VipsImage *right, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("matrixmultiply", ap, left, right, out); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/merge.c000066400000000000000000000135541516303661500201640ustar00rootroot00000000000000/* merge two images left/right or up/down * * 22/5/14 * - from vips_merge() * 13/6/17 * - tag as SEQUENTIAL */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pmosaicing.h" typedef struct { VipsOperation parent_instance; VipsImage *ref; VipsImage *sec; VipsImage *out; VipsDirection direction; int dx; int dy; int mblend; } VipsMerge; typedef VipsOperationClass VipsMergeClass; G_DEFINE_TYPE(VipsMerge, vips_merge, VIPS_TYPE_OPERATION); static int vips_merge_build(VipsObject *object) { VipsMerge *merge = (VipsMerge *) object; g_object_set(merge, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_merge_parent_class)->build(object)) return -1; switch (merge->direction) { case VIPS_DIRECTION_HORIZONTAL: if (vips__lrmerge(merge->ref, merge->sec, merge->out, merge->dx, merge->dy, merge->mblend)) return -1; break; case VIPS_DIRECTION_VERTICAL: if (vips__tbmerge(merge->ref, merge->sec, merge->out, merge->dx, merge->dy, merge->mblend)) return -1; break; default: g_assert_not_reached(); } vips__add_mosaic_name(merge->out); if (vips_image_history_printf(merge->out, "#%s <%s> <%s> <%s> <%d> <%d> <%d>", merge->direction == VIPS_DIRECTION_HORIZONTAL ? "LRJOIN" : "TBJOIN", vips__get_mosaic_name(merge->ref), vips__get_mosaic_name(merge->sec), vips__get_mosaic_name(merge->out), -merge->dx, -merge->dy, merge->mblend)) return -1; return 0; } static void vips_merge_class_init(VipsMergeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "merge"; object_class->description = _("merge two images"); object_class->build = vips_merge_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_IMAGE(class, "ref", 1, _("Reference"), _("Reference image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMerge, ref)); VIPS_ARG_IMAGE(class, "sec", 2, _("Secondary"), _("Secondary image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMerge, sec)); VIPS_ARG_IMAGE(class, "out", 3, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMerge, out)); VIPS_ARG_ENUM(class, "direction", 4, _("Direction"), _("Horizontal or vertical merge"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMerge, direction), VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL); VIPS_ARG_INT(class, "dx", 5, _("dx"), _("Horizontal displacement from sec to ref"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMerge, dx), -100000000, 1000000000, 1); VIPS_ARG_INT(class, "dy", 6, _("dy"), _("Vertical displacement from sec to ref"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMerge, dy), -100000000, 1000000000, 1); VIPS_ARG_INT(class, "mblend", 7, _("Max blend"), _("Maximum blend size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMerge, mblend), 0, 10000, 10); } static void vips_merge_init(VipsMerge *merge) { merge->mblend = 10; } /** * vips_merge: (method) * @ref: reference image * @sec: secondary image * @out: (out): output image * @direction: horizontal or vertical merge * @dx: displacement of ref from sec * @dy: displacement of ref from sec * @...: `NULL`-terminated list of optional named arguments * * This operation joins two images left-right (with @ref on the left) or * up-down (with @ref above) with a smooth seam. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * @dx and @dy give the displacement of @sec relative to @ref, in other words, * the vector to get from the origin of @sec to the origin of @ref, in other * words, @dx will generally be a negative number. * * @mblend limits the maximum width of the * blend area. A value of "-1" means "unlimited". The two images are blended * with a raised cosine. * * Pixels with all bands equal to zero are "transparent", that * is, zero pixels in the overlap area do not contribute to the merge. * This makes it possible to join non-rectangular images. * * ::: tip "Optional arguments" * * @mblend: `gint`, maximum blend size * * ::: seealso * [method@Image.mosaic], [method@Image.insert]. * * Returns: 0 on success, -1 on error */ int vips_merge(VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int dx, int dy, ...) { va_list ap; int result; va_start(ap, dy); result = vips_call_split("merge", ap, ref, sec, out, direction, dx, dy); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/meson.build000066400000000000000000000013221516303661500210510ustar00rootroot00000000000000mosaicing_sources = files( 'mosaicing.c', 'merge.c', 'mosaic.c', 'match.c', 'mosaic1.c', 'chkpair.c', 'matrixinvert.c', 'matrixmultiply.c', 'global_balance.c', 'lrmerge.c', 'tbmerge.c', 'lrmosaic.c', 'tbmosaic.c', 'remosaic.c', 'im_avgdxdy.c', 'im_clinear.c', 'im_improve.c', 'im_initialize.c', 'im_lrcalcon.c', 'im_tbcalcon.c', ) mosaicing_headers = files( 'global_balance.h', 'pmosaicing.h', ) libvips_sources += mosaicing_sources mosaicing_lib = static_library('mosaicing', mosaicing_sources, mosaicing_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += mosaicing_lib libvips-8.18.2/libvips/mosaicing/mosaic.c000066400000000000000000000221601516303661500203310ustar00rootroot00000000000000/* mosaic two images left/right or up/down * * 22/5/14 * - from vips_mosaic() * 4/9/18 * - add docs for transform output * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include "pmosaicing.h" typedef struct { VipsOperation parent_instance; VipsImage *ref; VipsImage *sec; VipsImage *out; VipsDirection direction; int xref; int yref; int xsec; int ysec; int mblend; int bandno; int hwindow; int harea; int dx0; int dy0; double scale1; double angle1; double dx1; double dy1; } VipsMosaic; typedef VipsOperationClass VipsMosaicClass; G_DEFINE_TYPE(VipsMosaic, vips_mosaic, VIPS_TYPE_OPERATION); static int vips_mosaic_build(VipsObject *object) { VipsMosaic *mosaic = (VipsMosaic *) object; VipsImage *x; int dx0; int dy0; double scale1; double angle1; double dx1; double dy1; g_object_set(mosaic, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_mosaic_parent_class)->build(object)) return -1; /* A placeholder used to ensure that memory used by the analysis * phase is freed as soon as possible. */ x = vips_image_new(); switch (mosaic->direction) { case VIPS_DIRECTION_HORIZONTAL: if (vips__find_lroverlap(mosaic->ref, mosaic->sec, x, mosaic->bandno, mosaic->xref, mosaic->yref, mosaic->xsec, mosaic->ysec, mosaic->hwindow, mosaic->harea, &dx0, &dy0, &scale1, &angle1, &dx1, &dy1)) { g_object_unref(x); return -1; } g_object_unref(x); break; case VIPS_DIRECTION_VERTICAL: if (vips__find_tboverlap(mosaic->ref, mosaic->sec, x, mosaic->bandno, mosaic->xref, mosaic->yref, mosaic->xsec, mosaic->ysec, mosaic->hwindow, mosaic->harea, &dx0, &dy0, &scale1, &angle1, &dx1, &dy1)) { g_object_unref(x); return -1; } g_object_unref(x); break; default: g_assert_not_reached(); /* Compiler warnings. */ dx0 = 0; dy0 = 0; scale1 = 1; angle1 = 1; dx1 = 0; dy1 = 0; } g_object_set(mosaic, "dx0", dx0, "dy0", dy0, "scale1", scale1, "angle1", angle1, "dx1", dx1, "dy1", dy1, NULL); if (vips_merge(mosaic->ref, mosaic->sec, &x, mosaic->direction, mosaic->dx0, mosaic->dy0, "mblend", mosaic->mblend, NULL)) return -1; if (vips_image_write(x, mosaic->out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } static void vips_mosaic_class_init(VipsMosaicClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "mosaic"; object_class->description = _("mosaic two images"); object_class->build = vips_mosaic_build; VIPS_ARG_IMAGE(class, "ref", 1, _("Reference"), _("Reference image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, ref)); VIPS_ARG_IMAGE(class, "sec", 2, _("Secondary"), _("Secondary image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, sec)); VIPS_ARG_IMAGE(class, "out", 3, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, out)); VIPS_ARG_ENUM(class, "direction", 4, _("Direction"), _("Horizontal or vertical mosaic"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, direction), VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL); VIPS_ARG_INT(class, "xref", 5, _("xref"), _("Position of reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, xref), 0, 1000000000, 1); VIPS_ARG_INT(class, "yref", 6, _("yref"), _("Position of reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, yref), 0, 1000000000, 1); VIPS_ARG_INT(class, "xsec", 7, _("xsec"), _("Position of secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, xsec), 0, 1000000000, 1); VIPS_ARG_INT(class, "ysec", 8, _("ysec"), _("Position of secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic, ysec), 0, 1000000000, 1); VIPS_ARG_INT(class, "hwindow", 9, _("hwindow"), _("Half window size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic, hwindow), 0, 1000000000, 5); VIPS_ARG_INT(class, "harea", 10, _("harea"), _("Half area size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic, harea), 0, 1000000000, 15); VIPS_ARG_INT(class, "mblend", 11, _("Max blend"), _("Maximum blend size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic, mblend), 0, 10000, 10); VIPS_ARG_INT(class, "bandno", 12, _("Search band"), _("Band to search for features on"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic, bandno), 0, 10000, 0); VIPS_ARG_INT(class, "dx0", 13, _("Integer offset"), _("Detected integer offset"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, dx0), -10000000, 10000000, 0); VIPS_ARG_INT(class, "dy0", 14, _("Integer offset"), _("Detected integer offset"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, dy0), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "scale1", 15, _("Scale"), _("Detected scale"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, scale1), -10000000.0, 10000000.0, 1.0); VIPS_ARG_DOUBLE(class, "angle1", 16, _("Angle"), _("Detected rotation"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, angle1), -10000000.0, 10000000.0, 0.0); VIPS_ARG_DOUBLE(class, "dx1", 17, _("First-order displacement"), _("Detected first-order displacement"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, dx1), -10000000.0, 10000000.0, 0.0); VIPS_ARG_DOUBLE(class, "dy1", 17, _("First-order displacement"), _("Detected first-order displacement"), VIPS_ARGUMENT_OPTIONAL_OUTPUT, G_STRUCT_OFFSET(VipsMosaic, dy1), -10000000.0, 10000000.0, 0.0); } static void vips_mosaic_init(VipsMosaic *mosaic) { mosaic->mblend = 10; mosaic->hwindow = 5; mosaic->harea = 15; mosaic->scale1 = 1.0; } /** * vips_mosaic: (method) * @ref: reference image * @sec: secondary image * @out: (out): output image * @direction: horizontal or vertical join * @xref: position in reference image * @yref: position in reference image * @xsec: position in secondary image * @ysec: position in secondary image * @...: `NULL`-terminated list of optional named arguments * * This operation joins two images left-right (with @ref on the left) or * top-bottom (with @ref above) given an approximate overlap. * * @sec is positioned so that the pixel (@xsec, @ysec) in @sec lies on top of * the pixel (@xref, @yref) in @ref. The overlap area is divided into three * sections, 20 high-contrast points in band @bandno of image @ref are found * in each, and a window of pixels of size @hwindow around each high-contrast * point is searched for in @sec over an area of @harea. * * A linear model is fitted to the 60 tie-points, points a long way from the * fit are discarded, and the model refitted until either too few points * remain or the model reaches good agreement. * * The detected displacement is used with [method@Image.merge] to join the * two images together. * * You can read out the detected transform with @dx0, @dy0, @scale1, @angle1, * @dx1, @dy1. * * ::: tip "Optional arguments" * * @bandno: `gint`, band to search for features * * @hwindow: `gint`, half window size * * @harea: `gint`, half search size * * @mblend: `gint`, maximum blend size * * @dx0: `gint`, output, detected displacement * * @dy0: `gint`, output, detected displacement * * @scale1: `gdouble`, output, detected first order scale * * @angle1: `gdouble`, output, detected first order rotation * * @dx1: `gdouble`, output, detected first order displacement * * @dy1: `gdouble`, output, detected first order displacement * * ::: seealso * [method@Image.merge], [method@Image.insert]. * * Returns: 0 on success, -1 on error */ int vips_mosaic(VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int xref, int yref, int xsec, int ysec, ...) { va_list ap; int result; va_start(ap, ysec); result = vips_call_split("mosaic", ap, ref, sec, out, direction, xref, yref, xsec, ysec); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/mosaic1.c000066400000000000000000000423711516303661500204200ustar00rootroot00000000000000/* 1st order mosaic functions * * 31/7/97 JC * - done! * 12/9/97 JC * - mods so global_balance() can work with 1st order mosaics * 27/12/99 JC * - now uses affine() stuff * - small tidies * 2/2/01 JC * - added tunable max blend width * 23/3/01 JC * - better mosaic1 calcs ... was a bit broken * 14/12/04 * - works for LABQ as well * 25/1/11 * - gtk-doc * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pmosaicing.h" /* Define for debug output. #define DEBUG */ /* define this to get old not-really-working joiner. #define OLD */ /* Like vips_similarity(), but return the transform we generated. */ static int apply_similarity(VipsTransformation *trn, VipsImage *in, VipsImage *out, double a, double b, double dx, double dy) { trn->iarea.left = 0; trn->iarea.top = 0; trn->iarea.width = in->Xsize; trn->iarea.height = in->Ysize; trn->a = a; trn->b = -b; trn->c = b; trn->d = a; trn->idx = 0; trn->idy = 0; trn->odx = dx; trn->ody = dy; vips__transform_set_area(trn); if (vips__transform_calc_inverse(trn)) return -1; if (vips__affinei(in, out, trn)) return -1; return 0; } /* A join function ... either left-right or top-bottom rotscalemerge. */ typedef int (*joinfn)(VipsImage *, VipsImage *, VipsImage *, double, double, double, double, int); /* similarity+lrmerge. */ int vips__lrmerge1(VipsImage *ref, VipsImage *sec, VipsImage *out, double a, double b, double dx, double dy, int mwidth) { VipsTransformation trn; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 1); VipsBuf buf; char text[1024]; t[0] = vips_image_new(); /* Scale, rotate and displace sec. */ if (apply_similarity(&trn, sec, t[0], a, b, dx, dy)) return -1; /* And join to ref. */ if (vips__lrmerge(ref, t[0], out, -trn.oarea.left, -trn.oarea.top, mwidth)) return -1; /* Note parameters in history file ... for global balance to pick up * later. */ vips__add_mosaic_name(out); vips_buf_init_static(&buf, text, 1024); vips_buf_appendf(&buf, "#LRROTSCALE <%s> <%s> <%s> <", vips__get_mosaic_name(ref), vips__get_mosaic_name(sec), vips__get_mosaic_name(out)); vips_buf_appendg(&buf, a); vips_buf_appendf(&buf, "> <"); vips_buf_appendg(&buf, b); vips_buf_appendf(&buf, "> <"); vips_buf_appendg(&buf, dx); vips_buf_appendf(&buf, "> <"); vips_buf_appendg(&buf, dy); vips_buf_appendf(&buf, "> <%d>", mwidth); if (vips_image_history_printf(out, "%s", vips_buf_all(&buf))) return -1; return 0; } /* similarity+tbmerge. */ int vips__tbmerge1(VipsImage *ref, VipsImage *sec, VipsImage *out, double a, double b, double dx, double dy, int mwidth) { VipsTransformation trn; VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 1); VipsBuf buf; char text[1024]; t[0] = vips_image_new(); /* Scale, rotate and displace sec. */ if (apply_similarity(&trn, sec, t[0], a, b, dx, dy)) return -1; /* And join to ref. */ if (vips__tbmerge(ref, t[0], out, -trn.oarea.left, -trn.oarea.top, mwidth)) return -1; /* Note parameters in history file ... for global balance to pick up * later. */ vips__add_mosaic_name(out); vips_buf_init_static(&buf, text, 1024); vips_buf_appendf(&buf, "#TBROTSCALE <%s> <%s> <%s> <", vips__get_mosaic_name(ref), vips__get_mosaic_name(sec), vips__get_mosaic_name(out)); vips_buf_appendg(&buf, a); vips_buf_appendf(&buf, "> <"); vips_buf_appendg(&buf, b); vips_buf_appendf(&buf, "> <"); vips_buf_appendg(&buf, dx); vips_buf_appendf(&buf, "> <"); vips_buf_appendg(&buf, dy); vips_buf_appendf(&buf, "> <%d>", mwidth); if (vips_image_history_printf(out, "%s", vips_buf_all(&buf))) return -1; return 0; } /* Join two images, using a pair of tie-points as parameters. */ static int rotjoin(VipsImage *ref, VipsImage *sec, VipsImage *out, joinfn jfn, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int mwidth) { double a, b, dx, dy; /* Solve to get scale + rot + disp. */ if (vips__coeff(xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, &a, &b, &dx, &dy)) return -1; /* Scale, rotate and displace sec. */ if (jfn(ref, sec, out, a, b, dx, dy, mwidth)) return -1; return 0; } /* Like rotjoin, but do a search to refine the tie-points. */ static int rotjoin_search(VipsImage *ref, VipsImage *sec, VipsImage *out, joinfn jfn, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int halfcorrelation, int halfarea, int mwidth) { VipsTransformation trn; double cor1, cor2; double a, b, dx, dy; double xs3, ys3; double xs4, ys4; int xs5, ys5; int xs6, ys6; double xs7, ys7; double xs8, ys8; /* Temps. */ VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 3); /* Unpack LABQ to LABS for correlation. */ if (ref->Coding == VIPS_CODING_LABQ) { if (vips_LabQ2LabS(ref, &t[0], NULL)) return -1; } else { t[0] = ref; g_object_ref(t[0]); } if (sec->Coding == VIPS_CODING_LABQ) { if (vips_LabQ2LabS(sec, &t[1], NULL)) return -1; } else { t[1] = sec; g_object_ref(t[1]); } t[2] = vips_image_new(); /* Solve to get scale + rot + disp. */ if (vips__coeff(xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, &a, &b, &dx, &dy) || apply_similarity(&trn, t[1], t[2], a, b, dx, dy)) return -1; /* Map points on sec to rotated image. */ vips__transform_forward_point(&trn, xs1, ys1, &xs3, &ys3); vips__transform_forward_point(&trn, xs2, ys2, &xs4, &ys4); /* Refine tie-points on rotated image. Remember the clip * vips__transform_set_area() has set, and move the sec tie-points * accordingly. */ if (vips__correl(t[0], t[2], xr1, yr1, xs3 - trn.oarea.left, ys3 - trn.oarea.top, halfcorrelation, halfarea, &cor1, &xs5, &ys5)) return -1; if (vips__correl(t[0], t[2], xr2, yr2, xs4 - trn.oarea.left, ys4 - trn.oarea.top, halfcorrelation, halfarea, &cor2, &xs6, &ys6)) return -1; #ifdef DEBUG printf("rotjoin_search: nudged pair 1 from %d, %d to %d, %d\n", xs3 - trn.oarea.left, ys3 - trn.oarea.top, xs5, ys5); printf("rotjoin_search: nudged pair 2 from %d, %d to %d, %d\n", xs4 - trn.oarea.left, ys4 - trn.oarea.top, xs6, ys6); #endif /*DEBUG*/ /* Put the sec tie-points back into output space. */ xs5 += trn.oarea.left; ys5 += trn.oarea.top; xs6 += trn.oarea.left; ys6 += trn.oarea.top; /* ... and now back to input space again. */ vips__transform_invert_point(&trn, xs5, ys5, &xs7, &ys7); vips__transform_invert_point(&trn, xs6, ys6, &xs8, &ys8); /* Recalc the transform using the refined points. */ if (vips__coeff(xr1, yr1, xs7, ys7, xr2, yr2, xs8, ys8, &a, &b, &dx, &dy)) return -1; /* Scale and rotate final. */ if (jfn(ref, sec, out, a, b, dx, dy, mwidth)) return -1; return 0; } #ifdef OLD /* 1st order mosaic using vips__find_lroverlap() ... does not work too well :( * Look at vips__find_lroverlap() for problem? */ static int old_lrmosaic1(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, int halfcorrelation, int halfarea, int mwidth) { VipsTransformation trn1, trn2; int dx0, dy0; double a, b, dx, dy; double a1, b1, dx1, dy1; double af, bf, dxf, dyf; int xpos, ypos; int xpos1, ypos1; /* Temps. */ VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 2); VipsImage *dummy; t[0] = vips_image_new(); /* Solve to get scale + rot + disp. */ if (vips__coeff(xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, &a, &b, &dx, &dy) || apply_similarity(&trn1, sec, t[0], a, b, dx, dy)) return -1; /* Correct tie-points. dummy is just a placeholder used to ensure that * memory used by the analysis phase is freed as soon as possible. */ dummy = vips_image_new(); if (vips__find_lroverlap(ref, t[0], dummy, bandno, -trn1.area.left, -trn1.area.top, 0, 0, halfcorrelation, halfarea, &dx0, &dy0, &a1, &b1, &dx1, &dy1)) { g_object_unref(dummy); return -1; } g_object_unref(dummy); /* Now combine the two transformations to get a corrected transform. */ af = a1 * a - b1 * b; bf = a1 * b + b1 * a; dxf = a1 * dx - b1 * dy + dx1; dyf = b1 * dx + a1 * dy + dy1; printf("transform was: a = %g, b = %g, dx = %g, dy = %g\n", a, b, dx, dy); printf("correction: a = %g, b = %g, dx = %g, dy = %g\n", a1, b1, dx1, dy1); printf("final: a = %g, b = %g, dx = %g, dy = %g\n", af, bf, dxf, dyf); t[1] = vips_image_new(); /* Scale and rotate final. */ if (apply_similarity(&trn2, sec, t[1], af, bf, dxf, dyf)) return -1; printf("disp: trn1 left = %d, top = %d\n", trn1.area.left, trn1.area.top); printf("disp: trn2 left = %d, top = %d\n", trn2.area.left, trn2.area.top); /* And join to ref. */ if (vips_merge(ref, t[1], out, VIPS_DIRECTION_HORIZONTAL, -trn2.area.left, -trn2.area.top, mwidth)) return -1; return 0; } #endif /*OLD*/ typedef struct { VipsOperation parent_instance; VipsImage *ref; VipsImage *sec; VipsImage *out; VipsDirection direction; int xr1; int yr1; int xs1; int ys1; int xr2; int yr2; int xs2; int ys2; int hwindow; int harea; gboolean search; VipsInterpolate *interpolate; int mblend; int bandno; } VipsMosaic1; typedef VipsOperationClass VipsMosaic1Class; G_DEFINE_TYPE(VipsMosaic1, vips_mosaic1, VIPS_TYPE_OPERATION); static int vips_mosaic1_build(VipsObject *object) { VipsMosaic1 *mosaic1 = (VipsMosaic1 *) object; joinfn jfn; g_object_set(mosaic1, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_mosaic1_parent_class)->build(object)) return -1; if (!mosaic1->interpolate) mosaic1->interpolate = vips_interpolate_new("bilinear"); // FIXME: Invalidates operation cache jfn = mosaic1->direction == VIPS_DIRECTION_HORIZONTAL ? vips__lrmerge1 : vips__tbmerge1; if (mosaic1->search) { if (rotjoin_search(mosaic1->ref, mosaic1->sec, mosaic1->out, jfn, mosaic1->xr1, mosaic1->yr1, mosaic1->xs1, mosaic1->ys1, mosaic1->xr2, mosaic1->yr2, mosaic1->xs2, mosaic1->ys2, mosaic1->hwindow, mosaic1->harea, mosaic1->mblend)) return -1; } else { if (rotjoin(mosaic1->ref, mosaic1->sec, mosaic1->out, jfn, mosaic1->xr1, mosaic1->yr1, mosaic1->xs1, mosaic1->ys1, mosaic1->xr2, mosaic1->yr2, mosaic1->xs2, mosaic1->ys2, mosaic1->mblend)) return -1; } return 0; } static void vips_mosaic1_class_init(VipsMosaic1Class *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "mosaic1"; object_class->description = _("first-order mosaic of two images"); object_class->build = vips_mosaic1_build; VIPS_ARG_IMAGE(class, "ref", 1, _("Reference"), _("Reference image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, ref)); VIPS_ARG_IMAGE(class, "sec", 2, _("Secondary"), _("Secondary image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, sec)); VIPS_ARG_IMAGE(class, "out", 3, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsMosaic1, out)); VIPS_ARG_ENUM(class, "direction", 4, _("Direction"), _("Horizontal or vertical mosaic"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, direction), VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL); VIPS_ARG_INT(class, "xr1", 5, _("xr1"), _("Position of first reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, xr1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "yr1", 6, _("yr1"), _("Position of first reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, yr1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "xs1", 7, _("xs1"), _("Position of first secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, xs1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "ys1", 8, _("ys1"), _("Position of first secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, ys1), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "xr2", 9, _("xr2"), _("Position of second reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, xr2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "yr2", 10, _("yr2"), _("Position of second reference tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, yr2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "xs2", 11, _("xs2"), _("Position of second secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, xs2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "ys2", 12, _("ys2"), _("Position of second secondary tie-point"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMosaic1, ys2), -1000000000, 1000000000, 1); VIPS_ARG_INT(class, "hwindow", 13, _("hwindow"), _("Half window size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic1, hwindow), 0, 1000000000, 5); VIPS_ARG_INT(class, "harea", 14, _("harea"), _("Half area size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic1, harea), 0, 1000000000, 15); VIPS_ARG_BOOL(class, "search", 15, _("Search"), _("Search to improve tie-points"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic1, search), FALSE); VIPS_ARG_INTERPOLATE(class, "interpolate", 16, _("Interpolate"), _("Interpolate pixels with this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic1, interpolate)); VIPS_ARG_INT(class, "mblend", 17, _("Max blend"), _("Maximum blend size"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMosaic1, mblend), 0, 10000, 10); VIPS_ARG_INT(class, "bandno", 18, _("Search band"), _("Band to search for features on"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsMosaic1, bandno), 0, 10000, 0); } static void vips_mosaic1_init(VipsMosaic1 *mosaic1) { mosaic1->hwindow = 5; mosaic1->harea = 15; mosaic1->mblend = 10; } /** * vips_mosaic1: (method) * @ref: reference image * @sec: secondary image * @out: output image * @direction: horizontal or vertical join * @xr1: first reference tie-point * @yr1: first reference tie-point * @xs1: first secondary tie-point * @ys1: first secondary tie-point * @xr2: second reference tie-point * @yr2: second reference tie-point * @xs2: second secondary tie-point * @ys2: second secondary tie-point * @...: `NULL`-terminated list of optional named arguments * * This operation joins two images top-bottom (with @sec on the right) * or left-right (with @sec at the bottom) * given an approximate pair of tie-points. @sec is scaled and rotated as * necessary before the join. * * If @search is `TRUE`, before performing the transformation, the tie-points * are improved by searching an area of @sec of size @harea for a * object of size @hwindow in @ref. * * @mblend limits the maximum size of the * blend area. A value of "-1" means "unlimited". The two images are blended * with a raised cosine. * * Pixels with all bands equal to zero are "transparent", that * is, zero pixels in the overlap area do not contribute to the merge. * This makes it possible to join non-rectangular images. * * If the number of bands differs, one of the images * must have one band. In this case, an n-band image is formed from the * one-band image by joining n copies of the one-band image together, and then * the two n-band images are operated upon. * * The two input images are cast up to the smallest common type (see table * Smallest common format in * [arithmetic](libvips-arithmetic.html)). * * ::: tip "Optional arguments" * * @search: `gboolean`, search to improve tie-points * * @hwindow: `gint`, half window size * * @harea: `gint`, half search size * * @interpolate: [class@Interpolate], interpolate pixels with this * * @mblend: `gint`, maximum blend size * * ::: seealso * [method@Image.merge], [method@Image.insert], [method@Image.globalbalance]. * * Returns: 0 on success, -1 on error */ int vips_mosaic1(VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, ...) { va_list ap; int result; va_start(ap, ys2); result = vips_call_split("mosaic1", ap, ref, sec, out, direction, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/mosaicing.c000066400000000000000000000035261516303661500210340ustar00rootroot00000000000000/* base class for all mosaicing operations * */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Define for debug output. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_mosaicing_operation_init(void) { extern GType vips_merge_get_type(void); extern GType vips_mosaic_get_type(void); extern GType vips_mosaic1_get_type(void); extern GType vips_match_get_type(void); extern GType vips_globalbalance_get_type(void); extern GType vips_matrixinvert_get_type(void); extern GType vips_matrixmultiply_get_type(void); extern GType vips_remosaic_get_type(void); vips_merge_get_type(); vips_mosaic_get_type(); vips_mosaic1_get_type(); vips_matrixinvert_get_type(); vips_matrixmultiply_get_type(); vips_match_get_type(); vips_globalbalance_get_type(); vips_remosaic_get_type(); } libvips-8.18.2/libvips/mosaicing/pmosaicing.h000066400000000000000000000142721516303661500212210ustar00rootroot00000000000000/* Local definitions used by the mosaicing program * If VIPS_MAXPOINTS change please ensure that it is still a multiple of * AREAS or else AREAS must change as well. Initial setup is for * VIPS_MAXPOINTS = 60, AREAS = 3. * * Copyright: 1990, 1991 N. Dessipris * Author: Nicos Dessipris * Written on: 07/11/1989 * Modified on : 29/11/1989 */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* TODO(kleisauke): This import is needed for vips__affinei */ #include /* Number of entries in blend table. As a power of two as well, for >>ing. */ #define BLEND_SHIFT (10) #define BLEND_SIZE (1 << BLEND_SHIFT) /* How much we scale the int version up by. */ #define BLEND_SCALE (4096) struct _MergeInfo; struct _Overlapping; typedef int (*VipsBlendFn)(VipsRegion *out_region, struct _MergeInfo *inf, struct _Overlapping *ovlap, VipsRect *oreg); /* Keep state for each call in one of these. */ typedef struct _Overlapping { VipsImage *ref; /* Arguments */ VipsImage *sec; VipsImage *out; int dx, dy; int mwidth; /* Ref and sec images, overlap, output area. We normalise these, so * that the output image is always positioned at (0,0) - ie. all these * coordinates are in output image space. */ VipsRect rarea; VipsRect sarea; VipsRect overlap; VipsRect oarea; int blsize; /* Max blend length */ int flsize; /* first/last cache size */ /* Sections of ref and sec which we use in output, excluding * overlap area. */ VipsRect rpart; VipsRect spart; /* Overlap start/end cache */ GMutex fl_lock; /* Need to lock on build */ int *first, *last; /* Blend function. */ VipsBlendFn blend; } Overlapping; /* Keep per-thread state here. */ typedef struct _MergeInfo { VipsRegion *rir; /* Two input regions */ VipsRegion *sir; float *from1; /* VIPS_CODING_LABQ buffers */ float *from2; float *merge; } MergeInfo; /* Functions shared between lr and tb. */ extern double *vips__coef1; extern double *vips__coef2; extern int *vips__icoef1; extern int *vips__icoef2; int vips__make_blend_luts(void); void vips__add_mosaic_name(VipsImage *image); const char *vips__get_mosaic_name(VipsImage *image); int vips__affinei(VipsImage *in, VipsImage *out, VipsTransformation *trn); int vips__attach_input(VipsRegion *out_region, VipsRegion *ir, VipsRect *area); int vips__copy_input(VipsRegion *out_region, VipsRegion *ir, VipsRect *area, VipsRect *reg); Overlapping *vips__build_mergestate(const char *domain, VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth); void *vips__start_merge(VipsImage *out, void *, void *); int vips__merge_gen(VipsRegion *out_region, void *seq, void *a, void *, gboolean *stop); int vips__stop_merge(void *seq, void *, void *); int vips__lrmerge(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth); int vips__tbmerge(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth); int vips__lrmerge1(VipsImage *ref, VipsImage *sec, VipsImage *out, double a, double b, double dx, double dy, int mwidth); int vips__tbmerge1(VipsImage *ref, VipsImage *sec, VipsImage *out, double a, double b, double dx, double dy, int mwidth); #define VIPS_MAXPOINTS (60) /* VIPS_MAXPOINTS % AREAS must be zero */ #define AREAS (3) typedef struct { char *reference; /* filename of reference */ char *secondary; /* filename of secondary */ int deltax; /* initial estimate of displacement */ int deltay; /* initial estimate of displacement */ int nopoints; /* must be multiple of AREAS and <= VIPS_MAXPOINTS */ int halfcorsize; /* recommended 5 */ int halfareasize; /* recommended 8 */ /* x, y_reference and contrast found by vips_calcon() */ int x_reference[VIPS_MAXPOINTS], y_reference[VIPS_MAXPOINTS]; int contrast[VIPS_MAXPOINTS]; /* x, y_secondary and correlation set by vips_chkpair() */ int x_secondary[VIPS_MAXPOINTS], y_secondary[VIPS_MAXPOINTS]; /* returns the corrected best correlation * as detected in 2*halfareasize+1 * centered at point (x2, y2) and using * correlation area 2*halfareasize+1 */ double correlation[VIPS_MAXPOINTS]; /* Coefficients calculated by vips_clinear() */ double l_scale, l_angle, l_deltax, l_deltay; /* used by vips_clinear() */ double dx[VIPS_MAXPOINTS], dy[VIPS_MAXPOINTS]; double deviation[VIPS_MAXPOINTS]; } TiePoints; int vips__chkpair(VipsImage *, VipsImage *, TiePoints *point); int vips__initialize(TiePoints *points); int vips__improve(TiePoints *inpoints, TiePoints *outpoints); int vips__avgdxdy(TiePoints *points, int *dx, int *dy); int vips__lrcalcon(VipsImage *ref, TiePoints *points); int vips__tbcalcon(VipsImage *ref, TiePoints *points); int vips__coeff(int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, double *a, double *b, double *dx, double *dy); int vips__clinear(TiePoints *points); int vips__find_lroverlap(VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1); int vips__find_tboverlap(VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1); int vips__find_best_contrast(VipsImage *image, int xpos, int ypos, int xsize, int ysize, int xarray[], int yarray[], int cont[], int nbest, int hcorsize); libvips-8.18.2/libvips/mosaicing/remosaic.c000066400000000000000000000127511516303661500206650ustar00rootroot00000000000000/* Use one mosiaced file to mosaic another set of images. * * 1/11/01 JC * - from global_balance * 25/02/02 JC * - detect size change * 10/4/06 * - spot file-not-found * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Define for debug output. #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "pmosaicing.h" #include "global_balance.h" typedef struct { VipsOperation parent_instance; VipsImage *in; VipsImage *out; char *old_str; char *new_str; int new_len; int old_len; } VipsRemosaic; typedef VipsOperationClass VipsRemosaicClass; G_DEFINE_TYPE(VipsRemosaic, vips_remosaic, VIPS_TYPE_OPERATION); static VipsImage * remosaic_fn(JoinNode *node, VipsRemosaic *remosaic) { SymbolTable *st = node->st; VipsImage *im = node->im; VipsImage *out; char filename[FILENAME_MAX]; char *p; if (!im) { vips_error("vips_remosaic", _("file \"%s\" not found"), node->name); return NULL; } /* Remove substring remosaic->old_str from in->filename, replace with * remosaic->new_str. */ g_strlcpy(filename, im->filename, FILENAME_MAX); if ((p = g_strrstr(filename, remosaic->old_str))) { int offset = p - &filename[0]; g_strlcpy(p, remosaic->new_str, FILENAME_MAX - offset); g_strlcpy(p + remosaic->new_len, im->filename + offset + remosaic->old_len, FILENAME_MAX - offset - remosaic->new_len); } #ifdef DEBUG printf("vips_remosaic: filename \"%s\" -> \"%s\"\n", im->filename, filename); #endif /*DEBUG*/ if (!(out = vips__global_open_image(st, filename))) return NULL; if (out->Xsize != im->Xsize || out->Ysize != im->Ysize) { vips_error("vips_remosaic", _("substitute image \"%s\" is not the same size as \"%s\""), filename, im->filename); return NULL; } return out; } static int vips_remosaic_build(VipsObject *object) { VipsRemosaic *remosaic = (VipsRemosaic *) object; SymbolTable *st; g_object_set(remosaic, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_remosaic_parent_class)->build(object)) return -1; if (!(st = vips__build_symtab(remosaic->out, SYM_TAB_SIZE)) || vips__parse_desc(st, remosaic->in)) return -1; remosaic->old_len = strlen(remosaic->old_str); remosaic->new_len = strlen(remosaic->new_str); if (vips__build_mosaic(st, remosaic->out, (transform_fn) remosaic_fn, remosaic)) return -1; return 0; } static void vips_remosaic_class_init(VipsRemosaicClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *object_class = (VipsObjectClass *) class; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; object_class->nickname = "remosaic"; object_class->description = _("rebuild an mosaiced image"); object_class->build = vips_remosaic_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRemosaic, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsRemosaic, out)); VIPS_ARG_STRING(class, "old_str", 5, _("old_str"), _("Search for this string"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRemosaic, old_str), ""); VIPS_ARG_STRING(class, "new_str", 6, _("new_str"), _("And swap for this string"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsRemosaic, new_str), ""); } static void vips_remosaic_init(VipsRemosaic *remosaic) { } /** * vips_remosaic: (method) * @in: mosaic to rebuild * @out: (out): output image * @old_str: gamma of source images * @new_str: gamma of source images * @...: `NULL`-terminated list of optional named arguments * * [method@Image.remosaic] works rather as [method@Image.globalbalance]. It * takes apart the mosaiced image @in and rebuilds it, substituting images. * * Unlike [method@Image.globalbalance], images are substituted based on their * filenames. The rightmost occurrence of the string @old_str is swapped * for @new_str, that file is opened, and that image substituted for * the old image. * * It's convenient for multispectral images. You can mosaic one band, then * use that mosaic as a template for mosaicing the others automatically. * * ::: seealso * [method@Image.globalbalance]. * * Returns: 0 on success, -1 on error */ int vips_remosaic(VipsImage *in, VipsImage **out, const char *old_str, const char *new_str, ...) { va_list ap; int result; va_start(ap, new_str); result = vips_call_split("remosaic", ap, in, out, old_str, new_str); va_end(ap); return result; } libvips-8.18.2/libvips/mosaicing/tbmerge.c000066400000000000000000000416351516303661500205130ustar00rootroot00000000000000/* Merge two images top-bottom. dx, dy is the offset needed to get from sec * (secondary image) to ref (reference image). * * Usage: * * int * vips_tbmerge(ref, sec, out, dx, dy) * VipsImage *ref, *sec, *out; * int dx, dy; * * Returns 0 on success and -1 on error * * Copyright: 1990, 1991 N. Dessipris * Author: N. Dessipris * Written on: 20/09/1990 * Updated on: 17/04/1991 * 1/6/92: J. Cupitt * - check for difference bug fixed * - geometry calculations improved and simplified * - small speedups * 30/6/93 K.Martinez : coped with IM_CODING_LABQ images * 7/7/93 JC * - ANSIfied * - proper freeing on errors, ready for partial * 8/11/93 JC * - now propagates both input histories * - adds magic lines for global mosaic optimisation * * * 16/May/1994 Ahmed. Abbood * - Modified to use partials on all IO * * June/1995 Ahmed Abbood * * - Modified to work with different types of images. * * * 16/6/95 JC * - added to VIPS! * 7/9/95 JC * - split into two parts: im_tbmerge() and im__tbmerge() * - latter called by im_tbmosaic() * - just the same as public im_tbmerge(), but adds no history * - necessary for im_global_balance() * - small bugs fixed * 10/10/95 JC * - better checks that parameters are sensible * 11/10/95 JC * - Kirk spotted what a load of rubbish Ahmed's code is * - rewritten - many, many bugs fixed * 28/7/97 JC * - new non-rectangular im_lrmerge adapted to make this * - small tidies * 18/2/98 JC * - im_demand_hint() call added * 19/2/98 JC * - now works for any dx/dy by calling im_insert() for bizarre cases * 2/2/01 JC * - added tunable max blend width * 8/3/01 JC * - switched to integer arithmetic for integer blends * 23/3/01 JC * - oops, iblend was broken * 7/11/01 JC * - more sophisticated transparency handling * 15/8/02 JC * - records Xoffset/Yoffset * 20/6/05 * - now requires all bands == 0 for transparency (used to just check * band 0) * 24/1/11 * - gtk-doc * - match formats and bands automatically * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "pmosaicing.h" /* Return the position of the first non-zero pel from the top. */ static int find_top(VipsRegion *ir, int *pos, int x, int y, int h) { VipsPel *pr = VIPS_REGION_ADDR(ir, x, y); VipsImage *im = ir->im; int ls = VIPS_REGION_LSKIP(ir) / VIPS_IMAGE_SIZEOF_ELEMENT(im); int b = im->Bands; int i, j; /* Double the number of bands in a complex. */ if (vips_band_format_iscomplex(im->BandFmt)) b *= 2; /* Search for the first non-zero band element from the top edge of the image. */ #define tsearch(TYPE) \ { \ TYPE *p = (TYPE *) pr; \ \ for (i = 0; i < h; i++) { \ for (j = 0; j < b; j++) \ if (p[j]) \ break; \ if (j < b) \ break; \ \ p += ls; \ } \ } switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: tsearch(unsigned char); break; case VIPS_FORMAT_CHAR: tsearch(signed char); break; case VIPS_FORMAT_USHORT: tsearch(unsigned short); break; case VIPS_FORMAT_SHORT: tsearch(signed short); break; case VIPS_FORMAT_UINT: tsearch(unsigned int); break; case VIPS_FORMAT_INT: tsearch(signed int); break; case VIPS_FORMAT_FLOAT: tsearch(float); break; case VIPS_FORMAT_DOUBLE: tsearch(double); break; case VIPS_FORMAT_COMPLEX: tsearch(float); break; case VIPS_FORMAT_DPCOMPLEX: tsearch(double); break; default: vips_error("vips_tbmerge", "%s", _("internal error")); return -1; } *pos = y + i; return 0; } /* Return the position of the first non-zero pel from the bottom. */ static int find_bot(VipsRegion *ir, int *pos, int x, int y, int h) { VipsPel *pr = VIPS_REGION_ADDR(ir, x, y); VipsImage *im = ir->im; int ls = VIPS_REGION_LSKIP(ir) / VIPS_IMAGE_SIZEOF_ELEMENT(ir->im); int b = im->Bands; int i, j; /* Double the number of bands in a complex. */ if (vips_band_format_iscomplex(im->BandFmt)) b *= 2; /* Search for the first non-zero band element from the top edge of the image. */ #define rsearch(TYPE) \ { \ TYPE *p = (TYPE *) pr + (h - 1) * ls; \ \ for (i = h - 1; i >= 0; i--) { \ for (j = 0; j < b; j++) \ if (p[j]) \ break; \ if (j < b) \ break; \ \ p -= ls; \ } \ } switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: rsearch(unsigned char); break; case VIPS_FORMAT_CHAR: rsearch(signed char); break; case VIPS_FORMAT_USHORT: rsearch(unsigned short); break; case VIPS_FORMAT_SHORT: rsearch(signed short); break; case VIPS_FORMAT_UINT: rsearch(unsigned int); break; case VIPS_FORMAT_INT: rsearch(signed int); break; case VIPS_FORMAT_FLOAT: rsearch(float); break; case VIPS_FORMAT_DOUBLE: rsearch(double); break; case VIPS_FORMAT_COMPLEX: rsearch(float); break; case VIPS_FORMAT_DPCOMPLEX: rsearch(double); break; default: vips_error("vips_tbmerge", "%s", _("internal error")); return -1; } *pos = y + i; return 0; } /* Make first/last for oreg. */ static int make_firstlast(MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; VipsRect rr, sr; int x; int missing; /* We're going to build first/last ... lock it from other generate * threads. In fact it's harmless if we do get two writers, but we may * avoid duplicating work. */ g_mutex_lock(&ovlap->fl_lock); /* Do we already have first/last for this area? Bail out if we do. */ missing = 0; for (x = oreg->left; x < VIPS_RECT_RIGHT(oreg); x++) { const int j = x - ovlap->overlap.left; const int first = ovlap->first[j]; if (first < 0) { missing = 1; break; } } if (!missing) { /* No work to do! */ g_mutex_unlock(&ovlap->fl_lock); return 0; } /* Entire height of overlap in ref for oreg ... we know oreg is inside * overlap. */ rr.left = oreg->left; rr.top = ovlap->overlap.top; rr.width = oreg->width; rr.height = ovlap->overlap.height; rr.left -= ovlap->rarea.left; rr.top -= ovlap->rarea.top; /* Same in sec. */ sr.left = oreg->left; sr.top = ovlap->overlap.top; sr.width = oreg->width; sr.height = ovlap->overlap.height; sr.left -= ovlap->sarea.left; sr.top -= ovlap->sarea.top; /* Make pixels. */ if (vips_region_prepare(rir, &rr) || vips_region_prepare(sir, &sr)) { g_mutex_unlock(&ovlap->fl_lock); return -1; } /* Make first/last cache. */ for (x = 0; x < oreg->width; x++) { const int j = (x + oreg->left) - ovlap->overlap.left; int *first = &ovlap->first[j]; int *last = &ovlap->last[j]; /* Done this line already? */ if (*first < 0) { /* Search for top/bottom of overlap on this scan-line. */ if (find_top(sir, first, x + sr.left, sr.top, sr.height) || find_bot(rir, last, x + rr.left, rr.top, rr.height)) { g_mutex_unlock(&ovlap->fl_lock); return -1; } /* Translate to output space. */ *first += ovlap->sarea.top; *last += ovlap->rarea.top; /* Clip to maximum blend width, if necessary. */ if (ovlap->mwidth >= 0 && *last - *first > ovlap->mwidth) { int shrinkby = (*last - *first) - ovlap->mwidth; *first += shrinkby / 2; *last -= shrinkby / 2; } } } g_mutex_unlock(&ovlap->fl_lock); return 0; } /* Test pixel == 0. */ #define TEST_ZERO(TYPE, T, RESULT) \ { \ TYPE *tt = (T); \ int ii; \ \ for (ii = 0; ii < cb; ii++) \ if (tt[i + ii]) \ break; \ if (ii == cb) \ (RESULT) = 1; \ } /* Blend two integer images ... one scan-line. */ #define iblend(TYPE, B, IN1, IN2, OUT) \ { \ TYPE *tr = (TYPE *) (IN1); \ TYPE *ts = (TYPE *) (IN2); \ TYPE *tq = (TYPE *) (OUT); \ const int cb = (B); \ int ref_zero; \ int sec_zero; \ int x, b; \ int i; \ \ for (i = 0, x = 0; x < oreg->width; x++) { \ ref_zero = 0; \ sec_zero = 0; \ TEST_ZERO(TYPE, tr, ref_zero); \ TEST_ZERO(TYPE, ts, sec_zero); \ \ /* Above the bottom image? \ */ \ if (y < first[x]) { \ if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ /* To the right? \ */ \ else if (y >= last[x]) { \ if (!sec_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ } \ /* In blend area. \ */ \ else { \ if (!ref_zero && !sec_zero) { \ const int bheight = last[x] - first[x]; \ const int inx = \ ((y - first[x]) << BLEND_SHIFT) / bheight; \ int c1 = vips__icoef1[inx]; \ int c2 = vips__icoef2[inx]; \ \ for (b = 0; b < cb; b++, i++) \ tq[i] = c1 * tr[i] / BLEND_SCALE + \ c2 * ts[i] / BLEND_SCALE; \ } \ else if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ } \ } /* Blend two float images. */ #define fblend(TYPE, B, IN1, IN2, OUT) \ { \ TYPE *tr = (TYPE *) (IN1); \ TYPE *ts = (TYPE *) (IN2); \ TYPE *tq = (TYPE *) (OUT); \ int ref_zero; \ int sec_zero; \ const int cb = (B); \ int x, b; \ int i; \ \ for (i = 0, x = 0; x < oreg->width; x++) { \ ref_zero = 0; \ sec_zero = 0; \ TEST_ZERO(TYPE, tr, ref_zero); \ TEST_ZERO(TYPE, ts, sec_zero); \ \ /* Above the bottom image? \ */ \ if (y < first[x]) \ if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ /* To the right? \ */ \ else if (y >= last[x]) \ if (!sec_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ /* In blend area. \ */ \ else { \ if (!ref_zero && !sec_zero) { \ const int bheight = last[x] - first[x]; \ const int inx = \ ((y - first[x]) << BLEND_SHIFT) / bheight; \ double c1 = vips__coef1[inx]; \ double c2 = vips__coef2[inx]; \ \ for (b = 0; b < cb; b++, i++) \ tq[i] = c1 * tr[i] + c2 * ts[i]; \ } \ else if (!ref_zero) \ for (b = 0; b < cb; b++, i++) \ tq[i] = tr[i]; \ else \ for (b = 0; b < cb; b++, i++) \ tq[i] = ts[i]; \ } \ } \ } /* Top-bottom blend function for non-labpack images. */ static int tb_blend(VipsRegion *out_region, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; VipsImage *im = out_region->im; VipsRect prr, psr; int y, yr, ys; /* Make sure we have a complete first/last set for this area. */ if (make_firstlast(inf, ovlap, oreg)) return -1; /* Part of rr which we will output. */ prr = *oreg; prr.left -= ovlap->rarea.left; prr.top -= ovlap->rarea.top; /* Part of sr which we will output. */ psr = *oreg; psr.left -= ovlap->sarea.left; psr.top -= ovlap->sarea.top; /* Make pixels. */ if (vips_region_prepare(rir, &prr) || vips_region_prepare(sir, &psr)) return -1; /* Loop down overlap area. */ for (y = oreg->top, yr = prr.top, ys = psr.top; y < VIPS_RECT_BOTTOM(oreg); y++, yr++, ys++) { VipsPel *pr = VIPS_REGION_ADDR(rir, prr.left, yr); VipsPel *ps = VIPS_REGION_ADDR(sir, psr.left, ys); VipsPel *q = VIPS_REGION_ADDR(out_region, oreg->left, y); const int j = oreg->left - ovlap->overlap.left; const int *first = ovlap->first + j; const int *last = ovlap->last + j; switch (im->BandFmt) { case VIPS_FORMAT_UCHAR: iblend(unsigned char, im->Bands, pr, ps, q); break; case VIPS_FORMAT_CHAR: iblend(signed char, im->Bands, pr, ps, q); break; case VIPS_FORMAT_USHORT: iblend(unsigned short, im->Bands, pr, ps, q); break; case VIPS_FORMAT_SHORT: iblend(signed short, im->Bands, pr, ps, q); break; case VIPS_FORMAT_UINT: iblend(unsigned int, im->Bands, pr, ps, q); break; case VIPS_FORMAT_INT: iblend(signed int, im->Bands, pr, ps, q); break; case VIPS_FORMAT_FLOAT: fblend(float, im->Bands, pr, ps, q); break; case VIPS_FORMAT_DOUBLE: fblend(double, im->Bands, pr, ps, q); break; case VIPS_FORMAT_COMPLEX: fblend(float, im->Bands * 2, pr, ps, q); break; case VIPS_FORMAT_DPCOMPLEX: fblend(double, im->Bands * 2, pr, ps, q); break; default: vips_error("vips_tbmerge", "%s", _("internal error")); return -1; } } return 0; } /* Top-bottom blend function for VIPS_CODING_LABQ images. */ static int tb_blend_labpack(VipsRegion *out_region, MergeInfo *inf, Overlapping *ovlap, VipsRect *oreg) { VipsRegion *rir = inf->rir; VipsRegion *sir = inf->sir; VipsRect prr, psr; int y, yr, ys; /* Make sure we have a complete first/last set for this area. This * will just look at the top 8 bits of L, not all 10, but should be OK. */ if (make_firstlast(inf, ovlap, oreg)) return -1; /* Part of rr which we will output. */ prr = *oreg; prr.left -= ovlap->rarea.left; prr.top -= ovlap->rarea.top; /* Part of sr which we will output. */ psr = *oreg; psr.left -= ovlap->sarea.left; psr.top -= ovlap->sarea.top; /* Make pixels. */ if (vips_region_prepare(rir, &prr) || vips_region_prepare(sir, &psr)) return -1; /* Loop down overlap area. */ for (y = oreg->top, yr = prr.top, ys = psr.top; y < VIPS_RECT_BOTTOM(oreg); y++, yr++, ys++) { VipsPel *pr = VIPS_REGION_ADDR(rir, prr.left, yr); VipsPel *ps = VIPS_REGION_ADDR(sir, psr.left, ys); VipsPel *q = VIPS_REGION_ADDR(out_region, oreg->left, y); const int j = oreg->left - ovlap->overlap.left; const int *first = ovlap->first + j; const int *last = ovlap->last + j; float *fq = inf->merge; float *r = inf->from1; float *s = inf->from2; /* Unpack two bits we want. */ vips__LabQ2Lab_vec(r, pr, oreg->width); vips__LabQ2Lab_vec(s, ps, oreg->width); /* Blend as floats. */ fblend(float, 3, r, s, fq); /* Re-pack to output buffer. */ vips__Lab2LabQ_vec(q, inf->merge, oreg->width); } return 0; } /* Build per-call state. */ static Overlapping * build_tbstate(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth) { Overlapping *ovlap; if (!(ovlap = vips__build_mergestate("vips_tbmerge", ref, sec, out, dx, dy, mwidth))) return NULL; /* Select blender. */ switch (ovlap->ref->Coding) { case VIPS_CODING_LABQ: ovlap->blend = tb_blend_labpack; break; case VIPS_CODING_NONE: ovlap->blend = tb_blend; break; default: vips_error("vips_tbmerge", "%s", _("unknown coding type")); return NULL; } /* Find the parts of output which come just from ref and just from sec. */ ovlap->rpart = ovlap->rarea; ovlap->spart = ovlap->sarea; ovlap->rpart.height -= ovlap->overlap.height; ovlap->spart.top += ovlap->overlap.height; ovlap->spart.height -= ovlap->overlap.height; /* Is there too much overlap? ie. bottom edge of ref image is greater * than bottom edge of sec image, or top edge of ref > top edge of * sec. */ if (VIPS_RECT_BOTTOM(&ovlap->rarea) > VIPS_RECT_BOTTOM(&ovlap->sarea) || ovlap->rarea.top > ovlap->sarea.top) { vips_error("vips_tbmerge", "%s", _("too much overlap")); return NULL; } /* Max number of pixels we may have to blend together. */ ovlap->blsize = ovlap->overlap.width; return ovlap; } int vips__tbmerge(VipsImage *ref, VipsImage *sec, VipsImage *out, int dx, int dy, int mwidth) { Overlapping *ovlap; if (dy > 0 || dy < 1 - ref->Ysize) { VipsImage *x; #ifdef DEBUG printf("vips__tbmerge: no overlap, using insert\n"); #endif /* No overlap, use insert instead. */ if (vips_insert(ref, sec, &x, -dx, -dy, "expand", TRUE, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); out->Xoffset = -dx; out->Yoffset = -dy; return 0; } if (!(ovlap = build_tbstate(ref, sec, out, dx, dy, mwidth))) return -1; if (vips_image_pipelinev(out, VIPS_DEMAND_STYLE_THINSTRIP, ovlap->ref, ovlap->sec, NULL)) return -1; out->Xsize = ovlap->oarea.width; out->Ysize = ovlap->oarea.height; out->Xoffset = -dx; out->Yoffset = -dy; if (vips_image_generate(out, vips__start_merge, vips__merge_gen, vips__stop_merge, ovlap, NULL)) return -1; return 0; } libvips-8.18.2/libvips/mosaicing/tbmosaic.c000066400000000000000000000144331516303661500206630ustar00rootroot00000000000000/* join top-bottom with an approximate overlap * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 07/11/1989 * Modified on : 29/11/1989, 18/04/1991 * Modified and debugged by Ahmed Abbood . 1995 * 14/6/95 JC * - adapted for new balance ideas * - more bug-fixes * 1/11/95 JC * - frees memory used by analysis phase as soon as possible * - means large mosaics use significantly less peak memory * 26/3/96 JC * - now calls im_tbmerge() rather than im__tbmerge() * 30/7/97 JC * - im__find_tboverlap() returns 1st order params too * 2/2/01 JC * - added tunable max blend width * 24/2/05 * - im_scale() makes it work for any image type * 25/1/11 * - gtk-doc * - remove balance stuff * - any mix of types and bands * - cleanups * 18/6/20 kleisauke * - convert to vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "pmosaicing.h" int vips__find_tboverlap(VipsImage *ref_in, VipsImage *sec_in, VipsImage *out, int bandno_in, int xref, int yref, int xsec, int ysec, int halfcorrelation, int halfarea, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1) { VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(out), 6); VipsRect top, bottom, overlap; TiePoints points, *p_points; /* defined in mosaic.h */ TiePoints newpoints, *p_newpoints; int i; int dx, dy; /* Test cor and area. */ if (halfcorrelation < 0 || halfarea < 0 || halfarea < halfcorrelation) { vips_error("vips__tbmosaic", "%s", _("bad area parameters")); return -1; } /* Set positions of top and bottom. */ top.left = 0; top.top = 0; top.width = ref_in->Xsize; top.height = ref_in->Ysize; bottom.left = xref - xsec; bottom.top = yref - ysec; bottom.width = sec_in->Xsize; bottom.height = sec_in->Ysize; /* Find overlap. */ vips_rect_intersectrect(&top, &bottom, &overlap); if (overlap.width < 2 * halfarea + 1 || overlap.height < 2 * halfarea + 1) { vips_error("vips__tbmosaic", "%s", _("overlap too small for search")); return -1; } /* Extract overlaps as 8-bit, 1 band. */ if (vips_extract_area(ref_in, &t[0], overlap.left, overlap.top, overlap.width, overlap.height, NULL) || vips_extract_area(sec_in, &t[1], overlap.left - bottom.left, overlap.top - bottom.top, overlap.width, overlap.height, NULL)) return -1; if (ref_in->Coding == VIPS_CODING_LABQ) { if (vips_LabQ2sRGB(t[0], &t[2], NULL) || vips_LabQ2sRGB(t[1], &t[3], NULL) || vips_extract_band(t[2], &t[4], 1, NULL) || vips_extract_band(t[3], &t[5], 1, NULL)) return -1; } else if (ref_in->Coding == VIPS_CODING_NONE) { if (vips_extract_band(t[0], &t[2], bandno_in, NULL) || vips_extract_band(t[1], &t[3], bandno_in, NULL) || vips_scale(t[2], &t[4], NULL) || vips_scale(t[3], &t[5], NULL)) return -1; } else { vips_error("vips__tbmosaic", "%s", _("unknown Coding type")); return -1; } /* Initialise and fill TiePoints */ p_points = &points; p_newpoints = &newpoints; p_points->reference = ref_in->filename; p_points->secondary = sec_in->filename; p_points->nopoints = VIPS_MAXPOINTS; p_points->deltax = 0; p_points->deltay = 0; p_points->halfcorsize = halfcorrelation; p_points->halfareasize = halfarea; /* Initialise the structure */ for (i = 0; i < VIPS_MAXPOINTS; i++) { p_points->x_reference[i] = 0; p_points->y_reference[i] = 0; p_points->x_secondary[i] = 0; p_points->y_secondary[i] = 0; p_points->contrast[i] = 0; p_points->correlation[i] = 0.0; p_points->dx[i] = 0.0; p_points->dy[i] = 0.0; p_points->deviation[i] = 0.0; } /* Search ref for possible tie-points. Sets: p_points->contrast, * p_points->x,y_reference. */ if (vips__tbcalcon(t[4], p_points)) return -1; /* For each candidate point, correlate against corresponding part of * sec. Sets x,y_secondary and fills correlation and dx, dy. */ if (vips__chkpair(t[4], t[5], p_points)) return -1; /* First call to vips_clinear(). */ if (vips__initialize(p_points)) return -1; /* Improve the selection of tiepoints until all abs(deviations) are * < 1.0 by deleting all wrong points. */ if (vips__improve(p_points, p_newpoints)) return -1; /* Average remaining offsets. */ if (vips__avgdxdy(p_newpoints, &dx, &dy)) return -1; /* Offset with overlap position. */ *dx0 = -bottom.left + dx; *dy0 = -bottom.top + dy; /* Write 1st order parameters too. */ *scale1 = newpoints.l_scale; *angle1 = newpoints.l_angle; *dx1 = newpoints.l_deltax; *dy1 = newpoints.l_deltay; return 0; } int vips__tbmosaic(VipsImage *ref, VipsImage *sec, VipsImage *out, int bandno, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, int mwidth) { int dx0, dy0; double scale1, angle1, dx1, dy1; VipsImage *dummy; VipsImage *x; /* Correct overlap. dummy is just a placeholder used to ensure that * memory used by the analysis phase is freed as soon as possible. */ dummy = vips_image_new(); if (vips__find_tboverlap(ref, sec, dummy, bandno, xref, yref, xsec, ysec, hwindowsize, hsearchsize, &dx0, &dy0, &scale1, &angle1, &dx1, &dy1)) { g_object_unref(dummy); return -1; } g_object_unref(dummy); /* Merge top-bottom. */ if (vips_merge(ref, sec, &x, VIPS_DIRECTION_VERTICAL, dx0, dy0, "mblend", mwidth, NULL)) return -1; if (vips_image_write(x, out)) { g_object_unref(x); return -1; } g_object_unref(x); return 0; } libvips-8.18.2/libvips/resample/000077500000000000000000000000001516303661500165505ustar00rootroot00000000000000libvips-8.18.2/libvips/resample/affine.c000066400000000000000000000535161516303661500201560ustar00rootroot00000000000000/* affine transform with a supplied interpolator. * * Copyright N. Dessipris * Written on: 01/11/1991 * Modified on: 12/3/92 JC * - rounding error in interpolation routine fixed * - test for scale=1, angle=0 case fixed * - clipping of output removed: redundant * - various little tidies * - problems remain with scale>20, size<10 * * Re-written on: 20/08/92, J.Ph Laurent * * 21/02/93, JC * - speed-ups * - simplifications * - im_similarity now calculates a window and calls this routine * 6/7/93 JC * - rewritten for partials * - ANSIfied * - now rotates any non-complex type * 3/6/94 JC * - C revised in bug search * 9/6/94 JC * - im_prepare() was preparing too small an area! oops * 22/5/95 JC * - added code to detect all-black output area case - helps lazy ip * 3/7/95 JC * - IM_CODING_LABQ handling moved to here * 31/7/97 JC * - dx/dy sign reversed to be less confusing ... now follows comment at * top ... ax - by + dx etc. * - tiny speed up, replaced the *++ on interpolation with [z] * - im_similarity() moved in here * - args swapped: was whxy, now xywh * - didn't agree with dispatch fns before :( * 3/3/98 JC * - im_demand_hint() added * 20/12/99 JC * - im_affine() made from im_similarity_area() * - transform stuff cleaned up a bit * 14/4/01 JC * - oops, invert_point() had a rounding problem * 23/2/02 JC * - pre-calculate interpolation matrices * - integer interpolation for int8/16 types, double for * int32/float/double * - faster transformation * 15/8/02 JC * - records Xoffset/Yoffset * 14/4/04 * - rounding, clipping and transforming revised, now pixel-perfect (or * better than gimp, anyway) * 22/6/05 * - all revised again, simpler and more reliable now * 30/3/06 * - gah, still an occasional clipping problem * 12/7/06 * - still more tweaking, gah again * 7/10/06 * - set THINSTRIP for no-rotate affines * 20/10/08 * - version with interpolate parameter, from im_affine() * 30/10/08 * - allow complex image types * 4/11/08 * - take an interpolator as a param * - replace im_affine with this, provide an im_affine() compat wrapper * - break transform stuff out to transform.c * - revise clipping / transform stuff, again * - now do corner rather than centre: this way the identity transform * returns the input exactly * 12/8/10 * - revise window_size / window_offset stuff again, see also * interpolate.c * 2/2/11 * - gtk-doc * 14/12/12 * - redone as a class * - added input space translation * 22/1/14 * - auto RAD decode * 1/8/14 * - revise transform ... again * - see new stress test in nip2/test/extras * 7/11/17 * - add "extend" param * - add "background" parameter * - better clipping means we have no jaggies on edges * - premultiply alpha * 18/5/20 * - add "premultiplied" flag */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG #define VIPS_DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include #include "presample.h" typedef struct _VipsAffine { VipsResample parent_instance; VipsArea *matrix; VipsInterpolate *interpolate; VipsArea *oarea; double odx; double ody; double idx; double idy; VipsTransformation trn; /* Interpolate parameter, prepared and ready for use. */ VipsInterpolate *affine_interpolate; /* How to generate extra edge pixels. */ VipsExtend extend; /* Background colour. */ VipsArrayDouble *background; /* The [double] converted to the input image format. */ VipsPel *ink; /* True if the input is already premultiplied (and we don't need to). */ gboolean premultiplied; } VipsAffine; typedef VipsResampleClass VipsAffineClass; G_DEFINE_TYPE(VipsAffine, vips_affine, VIPS_TYPE_RESAMPLE); static void vips_affine_dispose(GObject *gobject) { VipsAffine *affine = (VipsAffine *) gobject; VIPS_UNREF(affine->affine_interpolate); G_OBJECT_CLASS(vips_affine_parent_class)->dispose(gobject); } /* We have five (!!) coordinate systems. Working forward through them, these * are: * * 1. The original input image. iarea is defined on this image. * * 2. This is embedded in a larger image to provide borders for the * interpolator. window_offset and window_size control the embedding. * These are the coordinates we pass to VIPS_REGION_ADDR()/ * vips_region_prepare() and the interpolator. * * The borders are sized by the interpolator's window_size property and offset * by the interpolator's window_offset property. For example, * for bilinear (window_size 2, window_offset 0) we add a single line * of extra pixels along the bottom and right (window_size - 1). For * bicubic (window_size 4, window_offset 1) we add a single line top and left * (window_offset), and two lines bottom and right (window_size - 1 - * window_offset). * * 3. We need point (0, 0) in (1) to be at (0, 0) for the transformation. So * shift everything up and left to make the displaced input image. This is the * space that the transformation maps from, and can have negative pixels * (up and left of the image, for interpolation). iarea works here too. * * 4. Output transform space. This is the where the transform maps to. Pixels * can be negative, since a rotated image can go up and left of the origin. * * 5. Output image space. This is the wh of the xywh passed to vips_affine() * below. These are the coordinates we pass to VIPS_REGION_ADDR() for the * output image, and that affinei_gen() is asked for. */ static int vips_affine_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) seq; const VipsAffine *affine = (VipsAffine *) b; const VipsImage *in = (VipsImage *) a; VipsInterpolate *interpolate = affine->affine_interpolate; const int window_size = vips_interpolate_get_window_size(interpolate); const int window_offset = vips_interpolate_get_window_offset(interpolate); const VipsInterpolateMethod interpolate_method = vips_interpolate_get_method(interpolate); /* Area we generate in the output image. */ const VipsRect *r = &out_region->valid; const int le = r->left; const int ri = VIPS_RECT_RIGHT(r); const int to = r->top; const int bo = VIPS_RECT_BOTTOM(r); const VipsRect *iarea = &affine->trn.iarea; const VipsRect *oarea = &affine->trn.oarea; int ps = VIPS_IMAGE_SIZEOF_PEL(in); int x, y, z; VipsRect image, want, need, clipped; #ifdef DEBUG_VERBOSE printf("vips_affine_gen: " "generating left=%d, top=%d, width=%d, height=%d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG_VERBOSE*/ /* We are generating this chunk of the transformed image. This takes * us to space 4. */ want = *r; want.left += oarea->left; want.top += oarea->top; /* Find the area of the input image we need. This takes us to space 3. */ vips__transform_invert_rect(&affine->trn, &want, &need); /* That does round-to-nearest, because it has to stop rounding errors * growing images unexpectedly. We need round-down, so we must * add half a pixel along the left and top. But we are int :( so add 1 * pixel. * * Add an extra line along the right and bottom as well, for rounding. */ vips_rect_marginadjust(&need, 1); /* We need to fetch a larger area for the interpolator. */ need.left -= window_offset; need.top -= window_offset; need.width += window_size - 1; need.height += window_size - 1; /* Now go to space 2, the expanded input image. This is the one we * read pixels from. */ need.left += window_offset; need.top += window_offset; /* Clip against the size of (2). */ image.left = 0; image.top = 0; image.width = in->Xsize; image.height = in->Ysize; vips_rect_intersectrect(&need, &image, &clipped); #ifdef DEBUG_VERBOSE printf("vips_affine_gen: preparing left=%d, top=%d, width=%d, height=%d\n", clipped.left, clipped.top, clipped.width, clipped.height); #endif /*DEBUG_VERBOSE*/ if (vips_rect_isempty(&clipped)) { vips_region_paint_pel(out_region, r, affine->ink); return 0; } if (vips_region_prepare(ir, &clipped)) return -1; VIPS_GATE_START("vips_affine_gen: work"); /* Resample! x/y loop over pixels in the output image (5). */ for (y = to; y < bo; y++) { /* Input clipping rectangle. We offset this so we can clip in * space 2. */ const int ile = iarea->left + window_offset; const int ito = iarea->top + window_offset; const int iri = ile + iarea->width; const int ibo = ito + iarea->height; /* Derivative of matrix. */ const double ddx = affine->trn.ia; const double ddy = affine->trn.ic; /* Continuous cods in transformed space. */ const double ox = le + oarea->left - affine->trn.odx; const double oy = y + oarea->top - affine->trn.ody; /* Continuous cods in input space. */ double ix, iy; VipsPel *q; /* To (3). */ ix = affine->trn.ia * ox + affine->trn.ib * oy; iy = affine->trn.ic * ox + affine->trn.id * oy; /* And the input offset in (3). */ ix -= affine->trn.idx; iy -= affine->trn.idy; /* Finally to 2. */ ix += window_offset; iy += window_offset; q = VIPS_REGION_ADDR(out_region, le, y); for (x = le; x < ri; x++) { int fx, fy; fx = floor(ix); fy = floor(iy); /* Clip against iarea. */ if (fx >= ile && fx <= iri && fy >= ito && fy <= ibo) { /* Verify that we can read the whole stencil. * With DEBUG on this will range-check. */ g_assert(VIPS_REGION_ADDR(ir, (int) ix - window_offset, (int) iy - window_offset)); g_assert(VIPS_REGION_ADDR(ir, (int) ix - window_offset + window_size - 1, (int) iy - window_offset + window_size - 1)); interpolate_method(interpolate, q, ir, ix, iy); } else { /* Out of range: paint the background. */ for (z = 0; z < ps; z++) q[z] = affine->ink[z]; } ix += ddx; iy += ddy; q += ps; } } VIPS_GATE_STOP("vips_affine_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_affine_gen"); return 0; } static int vips_affine_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsAffine *affine = (VipsAffine *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); VipsImage *in; VipsDemandStyle hint; int window_size; int window_offset; int edge; /* TRUE if we've premultiplied and need to unpremultiply. */ gboolean have_premultiplied; VipsBandFormat unpremultiplied_format; if (VIPS_OBJECT_CLASS(vips_affine_parent_class)->build(object)) return -1; if (vips_check_coding_known(class->nickname, resample->in)) return -1; if (vips_check_vector_length(class->nickname, affine->matrix->n, 4)) return -1; if (vips_object_argument_isset(object, "oarea") && vips_check_vector_length(class->nickname, affine->oarea->n, 4)) return -1; /* "interpolate" be set explicitly to NULL to mean default setting. */ affine->affine_interpolate = affine->interpolate; if (affine->affine_interpolate) g_object_ref(affine->affine_interpolate); else affine->affine_interpolate = vips_interpolate_new("bilinear"); in = resample->in; /* Set up transform. */ window_size = vips_interpolate_get_window_size(affine->affine_interpolate); window_offset = vips_interpolate_get_window_offset(affine->affine_interpolate); affine->trn.iarea.left = 0; affine->trn.iarea.top = 0; affine->trn.iarea.width = in->Xsize; affine->trn.iarea.height = in->Ysize; affine->trn.a = ((double *) affine->matrix->data)[0]; affine->trn.b = ((double *) affine->matrix->data)[1]; affine->trn.c = ((double *) affine->matrix->data)[2]; affine->trn.d = ((double *) affine->matrix->data)[3]; affine->trn.idx = 0; affine->trn.idy = 0; affine->trn.odx = 0; affine->trn.ody = 0; if (vips__transform_calc_inverse(&affine->trn)) return -1; /* Set the default value for oarea. */ vips__transform_set_area(&affine->trn); if (vips_object_argument_isset(object, "oarea")) { affine->trn.oarea.left = ((int *) affine->oarea->data)[0]; affine->trn.oarea.top = ((int *) affine->oarea->data)[1]; affine->trn.oarea.width = ((int *) affine->oarea->data)[2]; affine->trn.oarea.height = ((int *) affine->oarea->data)[3]; } if (vips_object_argument_isset(object, "odx")) affine->trn.odx = affine->odx; if (vips_object_argument_isset(object, "ody")) affine->trn.ody = affine->ody; if (vips_object_argument_isset(object, "idx")) affine->trn.idx = affine->idx; if (vips_object_argument_isset(object, "idy")) affine->trn.idy = affine->idy; #ifdef DEBUG printf("vips_affine_build: copy on identity transform disabled\n"); #else /*!DEBUG*/ if (vips__transform_isidentity(&affine->trn) && affine->trn.oarea.left == 0 && affine->trn.oarea.top == 0 && affine->trn.oarea.width == in->Xsize && affine->trn.oarea.height == in->Ysize) return vips_image_write(in, resample->out); #endif /*!DEBUG*/ /* Check for coordinate overflow ... we want to be able to hold the * output space inside INT_MAX / TRANSFORM_SCALE. */ edge = INT_MAX / VIPS_TRANSFORM_SCALE; if (affine->trn.oarea.left < -edge || affine->trn.oarea.top < -edge || (guint64) affine->trn.oarea.left + affine->trn.oarea.width > edge || (guint64) affine->trn.oarea.top + affine->trn.oarea.height > edge) { vips_error(class->nickname, "%s", _("output coordinates out of range")); return -1; } if (vips_image_decode(in, &t[0])) return -1; in = t[0]; /* Add new pixels around the input so we can interpolate at the edges. * * We add the interpolate stencil, plus one extra pixel on all the * edges. This means when we clip in generate (above) we can be sure * we clip outside the real pixels and don't get jaggies on edges. */ if (vips_embed(in, &t[2], window_offset + 1, window_offset + 1, in->Xsize + window_size - 1 + 2, in->Ysize + window_size - 1 + 2, "extend", affine->extend, "background", affine->background, NULL)) return -1; in = t[2]; /* We've added a one-pixel border to the input: displace the transform * to compensate. */ affine->trn.idx -= 1; affine->trn.idy -= 1; /* If there's an alpha and we've not premultiplied, we have to * premultiply before resampling. See * https://github.com/libvips/libvips/issues/291 */ have_premultiplied = FALSE; if (vips_image_hasalpha(in) && !affine->premultiplied) { if (vips_premultiply(in, &t[3], NULL)) return -1; have_premultiplied = TRUE; /* vips_premultiply() makes a float image. When we * vips_unpremultiply() below, we need to cast back to the * pre-premultiply format. */ unpremultiplied_format = in->BandFmt; in = t[3]; } /* Convert the background to the image's format. */ if (!(affine->ink = vips__vector_to_ink(class->nickname, in, VIPS_AREA(affine->background)->data, NULL, VIPS_AREA(affine->background)->n))) return -1; /* Normally SMALLTILE ... except if this is strictly a size * up/down affine. */ if (affine->trn.b == 0.0 && affine->trn.c == 0.0) hint = VIPS_DEMAND_STYLE_FATSTRIP; else hint = VIPS_DEMAND_STYLE_SMALLTILE; t[4] = vips_image_new(); if (vips_image_pipelinev(t[4], hint, in, NULL)) return -1; t[4]->Xsize = affine->trn.oarea.width; t[4]->Ysize = affine->trn.oarea.height; #ifdef DEBUG printf("vips_affine_build: transform: "); vips__transform_print(&affine->trn); printf(" window_offset = %d, window_size = %d\n", window_offset, window_size); printf(" input image width = %d, height = %d\n", in->Xsize, in->Ysize); printf(" output image width = %d, height = %d\n", t[4]->Xsize, t[4]->Ysize); #endif /*DEBUG*/ /* Generate! */ if (vips_image_generate(t[4], vips_start_one, vips_affine_gen, vips_stop_one, in, affine)) return -1; /* Finally: can now set Xoffset/Yoffset. */ t[4]->Xoffset = affine->trn.odx - affine->trn.oarea.left; t[4]->Yoffset = affine->trn.ody - affine->trn.oarea.top; in = t[4]; if (have_premultiplied) { if (vips_unpremultiply(in, &t[5], NULL) || vips_cast(t[5], &t[6], unpremultiplied_format, NULL)) return -1; in = t[6]; } if (vips_image_write(in, resample->out)) return -1; return 0; } static void vips_affine_class_init(VipsAffineClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_affine_class_init\n"); gobject_class->dispose = vips_affine_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "affine"; vobject_class->description = _("affine transform of an image"); vobject_class->build = vips_affine_build; VIPS_ARG_BOXED(class, "matrix", 110, _("Matrix"), _("Transformation matrix"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsAffine, matrix), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_INTERPOLATE(class, "interpolate", 2, _("Interpolate"), _("Interpolate pixels with this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, interpolate)); VIPS_ARG_BOXED(class, "oarea", 111, _("Output rect"), _("Area of output to generate"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, oarea), VIPS_TYPE_ARRAY_INT); VIPS_ARG_DOUBLE(class, "odx", 112, _("Output offset"), _("Horizontal output displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, odx), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "ody", 113, _("Output offset"), _("Vertical output displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, ody), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "idx", 114, _("Input offset"), _("Horizontal input displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, idx), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "idy", 115, _("Input offset"), _("Vertical input displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, idy), -10000000, 10000000, 0); VIPS_ARG_ENUM(class, "extend", 117, _("Extend"), _("How to generate the extra pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, extend), VIPS_TYPE_EXTEND, VIPS_EXTEND_BACKGROUND); VIPS_ARG_BOXED(class, "background", 116, _("Background"), _("Background value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOOL(class, "premultiplied", 117, _("Premultiplied"), _("Images have premultiplied alpha"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsAffine, premultiplied), FALSE); } static void vips_affine_init(VipsAffine *affine) { affine->extend = VIPS_EXTEND_BACKGROUND; affine->background = vips_array_double_newv(1, 0.0); } /** * vips_affine: (method) * @in: input image * @out: (out): output image * @a: transformation matrix coefficient * @b: transformation matrix coefficient * @c: transformation matrix coefficient * @d: transformation matrix coefficient * @...: `NULL`-terminated list of optional named arguments * * This operator performs an affine transform on an image using @interpolate. * * The transform is: * * ``` * X = @a * (x + @idx) + @b * (y + @idy) + @odx * Y = @c * (x + @idx) + @d * (y + @idy) + @doy * ``` * * where: * * ``` * x and y are the coordinates in input image. * X and Y are the coordinates in output image. * (0,0) is the upper left corner. * ``` * * The section of the output space defined by @oarea is written to * @out. @oarea is a four-element int array of left, top, width, height. * By default @oarea is just large enough to cover the whole of the * transformed input image. * * By default, new pixels are filled with @background. This defaults to * zero (black). You can set other extend types with @extend. * [enum@Vips.Extend.COPY] is better for image upsizing. * * @interpolate defaults to bilinear. * * @idx, @idy, @odx, @ody default to zero. * * Image are normally treated as unpremultiplied, so this operation can be * used directly on PNG images. If your images have been through * [method@Image.premultiply], set @premultiplied. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @interpolate: [class@Interpolate], interpolate pixels with this * * @oarea: [struct@ArrayInt], output rectangle * * @idx: `gdouble`, input horizontal offset * * @idy: `gdouble`, input vertical offset * * @odx: `gdouble`, output horizontal offset * * @ody: `gdouble`, output vertical offset * * @extend: [enum@Extend], how to generate new pixels * * @background: [struct@ArrayDouble] colour for new pixels * * @premultiplied: `gboolean`, images are already premultiplied * * ::: seealso * [method@Image.shrink], [method@Image.resize], [class@Interpolate]. * * Returns: 0 on success, -1 on error */ int vips_affine(VipsImage *in, VipsImage **out, double a, double b, double c, double d, ...) { va_list ap; VipsArea *matrix; int result; matrix = VIPS_AREA(vips_array_double_newv(4, a, b, c, d)); va_start(ap, d); result = vips_call_split("affine", ap, in, out, matrix); va_end(ap); vips_area_unref(matrix); return result; } libvips-8.18.2/libvips/resample/bicubic.cpp000066400000000000000000000404531516303661500206620ustar00rootroot00000000000000/* bicubic (catmull-rom) interpolator * * 12/8/10 * - revise window_size / window_offset stuff again * 7/2/16 * - double intermediate for 32-bit int types */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Bicubic (Catmull-Rom) interpolator derived from Nicolas Robidoux's * original YAFR resampler with permission and thanks. */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "templates.h" #define VIPS_TYPE_INTERPOLATE_BICUBIC \ (vips_interpolate_bicubic_get_type()) #define VIPS_INTERPOLATE_BICUBIC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE_BICUBIC, VipsInterpolateBicubic)) #define VIPS_INTERPOLATE_BICUBIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE_BICUBIC, VipsInterpolateBicubicClass)) #define VIPS_IS_INTERPOLATE_BICUBIC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE_BICUBIC)) #define VIPS_IS_INTERPOLATE_BICUBIC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE_BICUBIC)) #define VIPS_INTERPOLATE_BICUBIC_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE_BICUBIC, VipsInterpolateBicubicClass)) typedef VipsInterpolate VipsInterpolateBicubic; typedef VipsInterpolateClass VipsInterpolateBicubicClass; /* Precalculated interpolation matrices. int (used for pel * sizes up to short), and double (for all others). We go to * scale + 1 so we can round-to-nearest safely. */ /* We could keep a large set of 2d 4x4 matrices, but this actually * works out slower since for many resizes the thing will no longer * fit in L1. */ static int vips_bicubic_matrixi[VIPS_TRANSFORM_SCALE + 1][4]; static double vips_bicubic_matrixf[VIPS_TRANSFORM_SCALE + 1][4]; /* We need C linkage for this. */ extern "C" { G_DEFINE_TYPE(VipsInterpolateBicubic, vips_interpolate_bicubic, VIPS_TYPE_INTERPOLATE); } /* Pointers to write to / read from, number of bands, * how many bytes to add to move down a line. */ /* T is the type of pixels we are reading and writing. */ /* Fixed-point version, for 8 and 16-bit types. */ template static void inline bicubic_unsigned_int_tab(void *pout, const VipsPel *pin, const int bands, const int lskip, const int *cx, const int *cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int b1 = bands; const int b2 = b1 + b1; const int b3 = b1 + b2; const int l1 = lskip / sizeof(T); const int l2 = l1 + l1; const int l3 = l1 + l2; const int l1_plus_b1 = l1 + b1; const int l1_plus_b2 = l1 + b2; const int l1_plus_b3 = l1 + b3; const int l2_plus_b1 = l2 + b1; const int l2_plus_b2 = l2 + b2; const int l2_plus_b3 = l2 + b3; const int l3_plus_b1 = l3 + b1; const int l3_plus_b2 = l3 + b2; const int l3_plus_b3 = l3 + b3; for (int z = 0; z < bands; z++) { const T uno_one = in[0]; const T uno_two = in[b1]; const T uno_thr = in[b2]; const T uno_fou = in[b3]; const T dos_one = in[l1]; const T dos_two = in[l1_plus_b1]; const T dos_thr = in[l1_plus_b2]; const T dos_fou = in[l1_plus_b3]; const T tre_one = in[l2]; const T tre_two = in[l2_plus_b1]; const T tre_thr = in[l2_plus_b2]; const T tre_fou = in[l2_plus_b3]; const T qua_one = in[l3]; const T qua_two = in[l3_plus_b1]; const T qua_thr = in[l3_plus_b2]; const T qua_fou = in[l3_plus_b3]; int bicubic = bicubic_unsigned_int( uno_one, uno_two, uno_thr, uno_fou, dos_one, dos_two, dos_thr, dos_fou, tre_one, tre_two, tre_thr, tre_fou, qua_one, qua_two, qua_thr, qua_fou, cx, cy); bicubic = VIPS_CLIP(0, bicubic, max_value); out[z] = bicubic; in += 1; } } template static void inline bicubic_signed_int_tab(void *pout, const VipsPel *pin, const int bands, const int lskip, const int *cx, const int *cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int b1 = bands; const int b2 = b1 + b1; const int b3 = b1 + b2; const int l1 = lskip / sizeof(T); const int l2 = l1 + l1; const int l3 = l1 + l2; const int l1_plus_b1 = l1 + b1; const int l1_plus_b2 = l1 + b2; const int l1_plus_b3 = l1 + b3; const int l2_plus_b1 = l2 + b1; const int l2_plus_b2 = l2 + b2; const int l2_plus_b3 = l2 + b3; const int l3_plus_b1 = l3 + b1; const int l3_plus_b2 = l3 + b2; const int l3_plus_b3 = l3 + b3; for (int z = 0; z < bands; z++) { const T uno_one = in[0]; const T uno_two = in[b1]; const T uno_thr = in[b2]; const T uno_fou = in[b3]; const T dos_one = in[l1]; const T dos_two = in[l1_plus_b1]; const T dos_thr = in[l1_plus_b2]; const T dos_fou = in[l1_plus_b3]; const T tre_one = in[l2]; const T tre_two = in[l2_plus_b1]; const T tre_thr = in[l2_plus_b2]; const T tre_fou = in[l2_plus_b3]; const T qua_one = in[l3]; const T qua_two = in[l3_plus_b1]; const T qua_thr = in[l3_plus_b2]; const T qua_fou = in[l3_plus_b3]; int bicubic = bicubic_signed_int( uno_one, uno_two, uno_thr, uno_fou, dos_one, dos_two, dos_thr, dos_fou, tre_one, tre_two, tre_thr, tre_fou, qua_one, qua_two, qua_thr, qua_fou, cx, cy); bicubic = VIPS_CLIP(min_value, bicubic, max_value); out[z] = bicubic; in += 1; } } /* Floating-point version. */ template static void inline bicubic_float_tab(void *pout, const VipsPel *pin, const int bands, const int lskip, const double *cx, const double *cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int b1 = bands; const int b2 = b1 + b1; const int b3 = b1 + b2; const int l1 = lskip / sizeof(T); const int l2 = l1 + l1; const int l3 = l1 + l2; const int l1_plus_b1 = l1 + b1; const int l1_plus_b2 = l1 + b2; const int l1_plus_b3 = l1 + b3; const int l2_plus_b1 = l2 + b1; const int l2_plus_b2 = l2 + b2; const int l2_plus_b3 = l2 + b3; const int l3_plus_b1 = l3 + b1; const int l3_plus_b2 = l3 + b2; const int l3_plus_b3 = l3 + b3; for (int z = 0; z < bands; z++) { const T uno_one = in[0]; const T uno_two = in[b1]; const T uno_thr = in[b2]; const T uno_fou = in[b3]; const T dos_one = in[l1]; const T dos_two = in[l1_plus_b1]; const T dos_thr = in[l1_plus_b2]; const T dos_fou = in[l1_plus_b3]; const T tre_one = in[l2]; const T tre_two = in[l2_plus_b1]; const T tre_thr = in[l2_plus_b2]; const T tre_fou = in[l2_plus_b3]; const T qua_one = in[l3]; const T qua_two = in[l3_plus_b1]; const T qua_thr = in[l3_plus_b2]; const T qua_fou = in[l3_plus_b3]; const T bicubic = bicubic_float( uno_one, uno_two, uno_thr, uno_fou, dos_one, dos_two, dos_thr, dos_fou, tre_one, tre_two, tre_thr, tre_fou, qua_one, qua_two, qua_thr, qua_fou, cx, cy); out[z] = bicubic; in += 1; } } /* uint32 version needs a double intermediate. */ template static void inline bicubic_unsigned_int32_tab(void *pout, const VipsPel *pin, const int bands, const int lskip, const double *cx, const double *cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int b1 = bands; const int b2 = b1 + b1; const int b3 = b1 + b2; const int l1 = lskip / sizeof(T); const int l2 = l1 + l1; const int l3 = l1 + l2; const int l1_plus_b1 = l1 + b1; const int l1_plus_b2 = l1 + b2; const int l1_plus_b3 = l1 + b3; const int l2_plus_b1 = l2 + b1; const int l2_plus_b2 = l2 + b2; const int l2_plus_b3 = l2 + b3; const int l3_plus_b1 = l3 + b1; const int l3_plus_b2 = l3 + b2; const int l3_plus_b3 = l3 + b3; for (int z = 0; z < bands; z++) { const T uno_one = in[0]; const T uno_two = in[b1]; const T uno_thr = in[b2]; const T uno_fou = in[b3]; const T dos_one = in[l1]; const T dos_two = in[l1_plus_b1]; const T dos_thr = in[l1_plus_b2]; const T dos_fou = in[l1_plus_b3]; const T tre_one = in[l2]; const T tre_two = in[l2_plus_b1]; const T tre_thr = in[l2_plus_b2]; const T tre_fou = in[l2_plus_b3]; const T qua_one = in[l3]; const T qua_two = in[l3_plus_b1]; const T qua_thr = in[l3_plus_b2]; const T qua_fou = in[l3_plus_b3]; double bicubic = bicubic_float( uno_one, uno_two, uno_thr, uno_fou, dos_one, dos_two, dos_thr, dos_fou, tre_one, tre_two, tre_thr, tre_fou, qua_one, qua_two, qua_thr, qua_fou, cx, cy); bicubic = VIPS_CLIP(0, bicubic, max_value); out[z] = bicubic; in += 1; } } template static void inline bicubic_signed_int32_tab(void *pout, const VipsPel *pin, const int bands, const int lskip, const double *cx, const double *cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int b1 = bands; const int b2 = b1 + b1; const int b3 = b1 + b2; const int l1 = lskip / sizeof(T); const int l2 = l1 + l1; const int l3 = l1 + l2; const int l1_plus_b1 = l1 + b1; const int l1_plus_b2 = l1 + b2; const int l1_plus_b3 = l1 + b3; const int l2_plus_b1 = l2 + b1; const int l2_plus_b2 = l2 + b2; const int l2_plus_b3 = l2 + b3; const int l3_plus_b1 = l3 + b1; const int l3_plus_b2 = l3 + b2; const int l3_plus_b3 = l3 + b3; for (int z = 0; z < bands; z++) { const T uno_one = in[0]; const T uno_two = in[b1]; const T uno_thr = in[b2]; const T uno_fou = in[b3]; const T dos_one = in[l1]; const T dos_two = in[l1_plus_b1]; const T dos_thr = in[l1_plus_b2]; const T dos_fou = in[l1_plus_b3]; const T tre_one = in[l2]; const T tre_two = in[l2_plus_b1]; const T tre_thr = in[l2_plus_b2]; const T tre_fou = in[l2_plus_b3]; const T qua_one = in[l3]; const T qua_two = in[l3_plus_b1]; const T qua_thr = in[l3_plus_b2]; const T qua_fou = in[l3_plus_b3]; double bicubic = bicubic_float( uno_one, uno_two, uno_thr, uno_fou, dos_one, dos_two, dos_thr, dos_fou, tre_one, tre_two, tre_thr, tre_fou, qua_one, qua_two, qua_thr, qua_fou, cx, cy); bicubic = VIPS_CLIP(min_value, bicubic, max_value); out[z] = bicubic; in += 1; } } /* Ultra-high-quality version for double images. */ template static void inline bicubic_notab(void *pout, const VipsPel *pin, const int bands, const int lskip, double x, double y) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int b1 = bands; const int b2 = b1 + b1; const int b3 = b1 + b2; const int l1 = lskip / sizeof(T); const int l2 = l1 + l1; const int l3 = l1 + l2; const int l1_plus_b1 = l1 + b1; const int l1_plus_b2 = l1 + b2; const int l1_plus_b3 = l1 + b3; const int l2_plus_b1 = l2 + b1; const int l2_plus_b2 = l2 + b2; const int l2_plus_b3 = l2 + b3; const int l3_plus_b1 = l3 + b1; const int l3_plus_b2 = l3 + b2; const int l3_plus_b3 = l3 + b3; double cx[4]; double cy[4]; calculate_coefficients_catmull(cx, x); calculate_coefficients_catmull(cy, y); for (int z = 0; z < bands; z++) { const T uno_one = in[0]; const T uno_two = in[b1]; const T uno_thr = in[b2]; const T uno_fou = in[b3]; const T dos_one = in[l1]; const T dos_two = in[l1_plus_b1]; const T dos_thr = in[l1_plus_b2]; const T dos_fou = in[l1_plus_b3]; const T tre_one = in[l2]; const T tre_two = in[l2_plus_b1]; const T tre_thr = in[l2_plus_b2]; const T tre_fou = in[l2_plus_b3]; const T qua_one = in[l3]; const T qua_two = in[l3_plus_b1]; const T qua_thr = in[l3_plus_b2]; const T qua_fou = in[l3_plus_b3]; const T bicubic = bicubic_float( uno_one, uno_two, uno_thr, uno_fou, dos_one, dos_two, dos_thr, dos_fou, tre_one, tre_two, tre_thr, tre_fou, qua_one, qua_two, qua_thr, qua_fou, cx, cy); out[z] = bicubic; in += 1; } } static void vips_interpolate_bicubic_interpolate(VipsInterpolate *interpolate, void *out, VipsRegion *in, double x, double y) { /* Find the mask index. We round-to-nearest, so we need to generate * indexes in 0 to VIPS_TRANSFORM_SCALE, 2^n + 1 values. We multiply * by 2 more than we need to, add one, mask, then shift down again to * get the extra range. */ const int sx = x * VIPS_TRANSFORM_SCALE * 2; const int sy = y * VIPS_TRANSFORM_SCALE * 2; const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1); const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1); const int tx = (six + 1) >> 1; const int ty = (siy + 1) >> 1; /* We know x/y are always positive, so we can just (int) them. */ const int ix = (int) x; const int iy = (int) y; /* Back and up one to get the top-left of the 4x4. */ const VipsPel *p = VIPS_REGION_ADDR(in, ix - 1, iy - 1); /* Look up the tables we need. */ const int *cxi = vips_bicubic_matrixi[tx]; const int *cyi = vips_bicubic_matrixi[ty]; const double *cxf = vips_bicubic_matrixf[tx]; const double *cyf = vips_bicubic_matrixf[ty]; /* Pel size and line size. */ const int bands = in->im->Bands; const int lskip = VIPS_REGION_LSKIP(in); /* Confirm that absolute_x and absolute_y are >= 1, because of * window_offset. */ g_assert(x >= 1.0); g_assert(y >= 1.0); g_assert(ix - 1 >= in->valid.left); g_assert(iy - 1 >= in->valid.top); g_assert(ix + 2 < VIPS_RECT_RIGHT(&in->valid)); g_assert(iy + 2 < VIPS_RECT_BOTTOM(&in->valid)); #ifdef DEBUG printf("vips_interpolate_bicubic_interpolate: %g %g\n", x, y); printf("\tleft=%d, top=%d, width=%d, height=%d\n", ix - 1, iy - 1, 4, 4); printf("\tmaskx=%d, masky=%d\n", tx, ty); #endif /*DEBUG*/ switch (in->im->BandFmt) { case VIPS_FORMAT_UCHAR: bicubic_unsigned_int_tab( out, p, bands, lskip, cxi, cyi); /* Handy for benchmarking bicubic_float_tab( out, p, bands, lskip, cxf, cyf ); bicubic_notab( out, p, bands, lskip, x - ix, y - iy ); */ break; case VIPS_FORMAT_CHAR: bicubic_signed_int_tab( out, p, bands, lskip, cxi, cyi); break; case VIPS_FORMAT_USHORT: bicubic_unsigned_int32_tab( out, p, bands, lskip, cxf, cyf); break; case VIPS_FORMAT_SHORT: bicubic_signed_int32_tab( out, p, bands, lskip, cxf, cyf); break; case VIPS_FORMAT_UINT: bicubic_unsigned_int32_tab( out, p, bands, lskip, cxf, cyf); break; case VIPS_FORMAT_INT: bicubic_signed_int32_tab( out, p, bands, lskip, cxf, cyf); break; case VIPS_FORMAT_FLOAT: bicubic_float_tab(out, p, bands, lskip, cxf, cyf); break; case VIPS_FORMAT_DOUBLE: bicubic_notab(out, p, bands, lskip, x - ix, y - iy); break; case VIPS_FORMAT_COMPLEX: bicubic_float_tab(out, p, bands * 2, lskip, cxf, cyf); break; case VIPS_FORMAT_DPCOMPLEX: bicubic_notab(out, p, bands * 2, lskip, x - ix, y - iy); break; default: break; } } static void vips_interpolate_bicubic_class_init(VipsInterpolateBicubicClass *iclass) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(iclass); VipsInterpolateClass *interpolate_class = VIPS_INTERPOLATE_CLASS(iclass); object_class->nickname = "bicubic"; object_class->description = _("bicubic interpolation (Catmull-Rom)"); interpolate_class->interpolate = vips_interpolate_bicubic_interpolate; interpolate_class->window_size = 4; /* Build the tables of pre-computed coefficients. */ for (int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++) { calculate_coefficients_catmull(vips_bicubic_matrixf[x], (float) x / VIPS_TRANSFORM_SCALE); for (int i = 0; i < 4; i++) vips_bicubic_matrixi[x][i] = vips_bicubic_matrixf[x][i] * VIPS_INTERPOLATE_SCALE; } } static void vips_interpolate_bicubic_init(VipsInterpolateBicubic *bicubic) { #ifdef DEBUG printf("vips_interpolate_bicubic_init: "); vips_object_print_dump(VIPS_OBJECT(bicubic)); #endif /*DEBUG*/ } libvips-8.18.2/libvips/resample/interpolate.c000066400000000000000000000424461516303661500212540ustar00rootroot00000000000000/* vipsinterpolate ... abstract base class for various interpolators * * J. Cupitt, 15/10/08 * * 12/8/10 * - revise window_size / window_offset stuff again: window_offset now * defaults to (window_size / 2 - 1), so for a 4x4 stencil (eg. * bicubic) we have an offset of 1 * - tiny speedups * 7/1/11 * - don't use tables for bilinear on float data for a small speedup * (thanks Nicolas Robidoux) * 12/1/11 * - faster, more accuarate uchar bilinear (thanks Nicolas) * 2/2/11 * - gtk-doc * 16/12/15 * - faster bilinear * 27/2/19 s-sajid-ali * - more accurate bilinear */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include /** * VipsInterpolate: * * An abstract base class for the various interpolation functions. * * Use `vips --list classes` to see all the interpolators available. * * An interpolator consists of a function to perform the interpolation, plus * some extra data fields which tells libvips how to call the function and * what data it needs. */ G_DEFINE_ABSTRACT_TYPE(VipsInterpolate, vips_interpolate, VIPS_TYPE_OBJECT); /** * VipsInterpolateMethod: * @interpolate: the interpolator * @out: write the interpolated pixel here * @in: read source pixels from here * @x: interpolate value at this position * @y: interpolate value at this position * * An interpolation function. It should read source pixels from @in with * [func@REGION_ADDR], it can look left and up from (x, y) by @window_offset * pixels and it can access pixels in a window of size @window_size. * * The interpolated value should be written to the pixel pointed to by @out. * * ::: seealso * [struct@InterpolateClass]. */ /** * VipsInterpolateClass: * @interpolate: the interpolation method * @get_window_size: return the size of the window needed by this method * @window_size: or just set this for a constant window size * @get_window_offset: return the window offset for this method * @window_offset: or just set this for a constant window offset * * @window_size is the size of the window that the interpolator needs. For * example, a bicubic interpolator needs to see a window of 4x4 pixels to be * able to interpolate a value. * * You can either have a function in @get_window_size which returns the window * that a specific interpolator needs, or you can leave @get_window_size `NULL` * and set a constant value in @window_size. * * @window_offset is how much to offset the window up and left of (x, y). For * example, a bicubic interpolator will want an @window_offset of 1. * * You can either have a function in @get_window_offset which returns the * offset that a specific interpolator needs, or you can leave * @get_window_offset `NULL` and set a constant value in @window_offset. * * You also need to set [property@Object:nickname] and * [property@Object:description] in [class@Object]. * * ::: seealso * [callback@InterpolateMethod], [class@Object] or * [func@Interpolate.bilinear_static]. */ #ifdef DEBUG static void vips_interpolate_finalize(GObject *gobject) { printf("vips_interpolate_finalize: "); vips_object_print_name(VIPS_OBJECT(gobject)); G_OBJECT_CLASS(vips_interpolate_parent_class)->finalize(gobject); } #endif /*DEBUG*/ static int vips_interpolate_real_get_window_size(VipsInterpolate *interpolate) { VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS(interpolate); g_assert(class->window_size != -1); return class->window_size; } static int vips_interpolate_real_get_window_offset(VipsInterpolate *interpolate) { VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS(interpolate); /* Default to half window size - 1. For example, bicubic is a 4x4 * stencil and needs an offset of 1. */ if (class->window_offset != -1) return class->window_offset; else { int window_size = vips_interpolate_get_window_size(interpolate); /* Don't go -ve, of course, for window_size 1. */ return VIPS_MAX(0, window_size / 2 - 1); } } static void vips_interpolate_class_init(VipsInterpolateClass *class) { VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); #ifdef DEBUG GObjectClass *gobject_class = G_OBJECT_CLASS(class); #endif /*DEBUG*/ #ifdef DEBUG gobject_class->finalize = vips_interpolate_finalize; #endif /*DEBUG*/ vobject_class->nickname = "interpolate"; vobject_class->description = _("VIPS interpolators"); class->interpolate = NULL; class->get_window_size = vips_interpolate_real_get_window_size; class->get_window_offset = vips_interpolate_real_get_window_offset; class->window_size = -1; class->window_offset = -1; } static void vips_interpolate_init(VipsInterpolate *interpolate) { #ifdef DEBUG printf("vips_interpolate_init: "); vips_object_print_name(VIPS_OBJECT(interpolate)); #endif /*DEBUG*/ } /** * vips_interpolate: (skip) * @interpolate: interpolator to use * @out: write result here * @in: read source data from here * @x: interpolate value at this position * @y: interpolate value at this position * * Look up the @interpolate method in the class and call it. Use * [method@Interpolate.get_method] to get a direct pointer to the function and * avoid the lookup overhead. * * You need to set @in and @out up correctly. */ void vips_interpolate(VipsInterpolate *interpolate, void *out, VipsRegion *in, double x, double y) { VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS(interpolate); g_assert(class->interpolate); class->interpolate(interpolate, out, in, x, y); } /** * vips_interpolate_get_method: (skip) * @interpolate: interpolator to use * * Look up the @interpolate method in the class and return it. Use this * instead of [func@interpolate] to cache method dispatch. * * Returns: a pointer to the interpolation function */ VipsInterpolateMethod vips_interpolate_get_method(VipsInterpolate *interpolate) { VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS(interpolate); g_assert(class->interpolate); return class->interpolate; } /** * vips_interpolate_get_window_size: * @interpolate: interpolator to use * * Look up an interpolators desired window size. * * Returns: the interpolators required window size */ int vips_interpolate_get_window_size(VipsInterpolate *interpolate) { VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS(interpolate); g_assert(class->get_window_size); return class->get_window_size(interpolate); } /** * vips_interpolate_get_window_offset: * @interpolate: interpolator to use * * Look up an interpolators desired window offset. * * Returns: the interpolators required window offset */ int vips_interpolate_get_window_offset(VipsInterpolate *interpolate) { VipsInterpolateClass *class = VIPS_INTERPOLATE_GET_CLASS(interpolate); g_assert(class->get_window_offset); return class->get_window_offset(interpolate); } /** * VIPS_TRANSFORM_SHIFT: * * Many of the libvips interpolators use fixed-point arithmetic for coordinate * calculation. This is how many bits of precision they use. */ /** * VIPS_TRANSFORM_SCALE: * * [const@TRANSFORM_SHIFT] as a multiplicative constant. */ /** * VIPS_INTERPOLATE_SHIFT: * * Many of the vips interpolators use fixed-point arithmetic for value * calculation. This is how many bits of precision they use. */ /** * VIPS_INTERPOLATE_SCALE: * * [const@INTERPOLATE_SHIFT] as a multiplicative constant. */ /* VipsInterpolateNearest class */ #define VIPS_TYPE_INTERPOLATE_NEAREST (vips_interpolate_nearest_get_type()) #define VIPS_INTERPOLATE_NEAREST(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE_NEAREST, VipsInterpolateNearest)) #define VIPS_INTERPOLATE_NEAREST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE_NEAREST, VipsInterpolateNearestClass)) #define VIPS_IS_INTERPOLATE_NEAREST(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE_NEAREST)) #define VIPS_IS_INTERPOLATE_NEAREST_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE_NEAREST)) #define VIPS_INTERPOLATE_NEAREST_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE_NEAREST, VipsInterpolateNearestClass)) /* No new members. */ typedef VipsInterpolate VipsInterpolateNearest; typedef VipsInterpolateClass VipsInterpolateNearestClass; G_DEFINE_TYPE(VipsInterpolateNearest, vips_interpolate_nearest, VIPS_TYPE_INTERPOLATE); static void vips_interpolate_nearest_interpolate(VipsInterpolate *interpolate, void *out, VipsRegion *in, double x, double y) { const int ps = VIPS_IMAGE_SIZEOF_PEL(in->im); const int xi = (int) x; const int yi = (int) y; const VipsPel *restrict p = VIPS_REGION_ADDR(in, xi, yi); VipsPel *restrict q = (VipsPel *) out; int z; for (z = 0; z < ps; z++) q[z] = p[z]; } static void vips_interpolate_nearest_class_init(VipsInterpolateNearestClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsInterpolateClass *interpolate_class = VIPS_INTERPOLATE_CLASS(class); object_class->nickname = "nearest"; object_class->description = _("nearest-neighbour interpolation"); interpolate_class->interpolate = vips_interpolate_nearest_interpolate; interpolate_class->window_size = 1; } static void vips_interpolate_nearest_init(VipsInterpolateNearest *nearest) { #ifdef DEBUG printf("vips_interpolate_nearest_init: "); vips_object_print_name(VIPS_OBJECT(nearest)); #endif /*DEBUG*/ } static VipsInterpolate * vips_interpolate_nearest_new(void) { return VIPS_INTERPOLATE(vips_object_new( VIPS_TYPE_INTERPOLATE_NEAREST, NULL, NULL, NULL)); } /** * vips_interpolate_nearest_static: * * A convenience function that returns a nearest-neighbour interpolator you * don't need to free. * * Returns: (transfer none): a nearest-neighbour interpolator */ VipsInterpolate * vips_interpolate_nearest_static(void) { static VipsInterpolate *interpolate = NULL; if (!interpolate) { interpolate = vips_interpolate_nearest_new(); vips_object_set_static(VIPS_OBJECT(interpolate), TRUE); } return interpolate; } /* VipsInterpolateBilinear class */ #define VIPS_TYPE_INTERPOLATE_BILINEAR (vips_interpolate_bilinear_get_type()) #define VIPS_INTERPOLATE_BILINEAR(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE_BILINEAR, VipsInterpolateBilinear)) #define VIPS_INTERPOLATE_BILINEAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE_BILINEAR, VipsInterpolateBilinearClass)) #define VIPS_IS_INTERPOLATE_BILINEAR(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE_BILINEAR)) #define VIPS_IS_INTERPOLATE_BILINEAR_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE_BILINEAR)) #define VIPS_INTERPOLATE_BILINEAR_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE_BILINEAR, VipsInterpolateBilinearClass)) typedef VipsInterpolate VipsInterpolateBilinear; typedef VipsInterpolateClass VipsInterpolateBilinearClass; G_DEFINE_TYPE(VipsInterpolateBilinear, vips_interpolate_bilinear, VIPS_TYPE_INTERPOLATE); /* in this class, name vars in the 2x2 grid as eg. * p1 p2 * p3 p4 */ /* Fixed-point arithmetic, no tables. */ #define BILINEAR_INT(TYPE) \ { \ TYPE *restrict tq = (TYPE *) out; \ \ const int X = (x - ix) * VIPS_INTERPOLATE_SCALE; \ const int Y = (y - iy) * VIPS_INTERPOLATE_SCALE; \ \ const int Yd = VIPS_INTERPOLATE_SCALE - Y; \ \ const int c4 = (Y * X) >> VIPS_INTERPOLATE_SHIFT; \ const int c2 = (Yd * X) >> VIPS_INTERPOLATE_SHIFT; \ const int c3 = Y - c4; \ const int c1 = Yd - c2; \ \ const TYPE *restrict tp1 = (TYPE *) p1; \ const TYPE *restrict tp2 = (TYPE *) p2; \ const TYPE *restrict tp3 = (TYPE *) p3; \ const TYPE *restrict tp4 = (TYPE *) p4; \ \ for (z = 0; z < b; z++) { \ tq[z] = (c1 * tp1[z] + c2 * tp2[z] + c3 * tp3[z] + c4 * tp4[z] + \ (1 << VIPS_INTERPOLATE_SHIFT) / 2) >> VIPS_INTERPOLATE_SHIFT; \ } \ } /* Interpolate a pel ... int16, int32 and float types, no tables, float * arithmetic. Use double not float for coefficient calculation or we can * get small over/undershoots. */ #define BILINEAR_FLOAT(TYPE) \ { \ TYPE *restrict tq = (TYPE *) out; \ \ const double X = x - ix; \ const double Y = y - iy; \ \ const double Yd = 1.0f - Y; \ \ const double c4 = Y * X; \ const double c2 = Yd * X; \ const double c3 = Y - c4; \ const double c1 = Yd - c2; \ \ const TYPE *restrict tp1 = (TYPE *) p1; \ const TYPE *restrict tp2 = (TYPE *) p2; \ const TYPE *restrict tp3 = (TYPE *) p3; \ const TYPE *restrict tp4 = (TYPE *) p4; \ \ for (z = 0; z < b; z++) { \ tq[z] = c1 * tp1[z] + c2 * tp2[z] + c3 * tp3[z] + c4 * tp4[z]; \ } \ } /* The fixed-point path is fine for uchar pixels, but it'll be inaccurate for * shorts and larger. */ #define SWITCH_INTERPOLATE(FMT, INT, FLOAT) \ { \ switch ((FMT)) { \ case VIPS_FORMAT_UCHAR: \ INT(unsigned char); \ break; \ case VIPS_FORMAT_CHAR: \ INT(char); \ break; \ case VIPS_FORMAT_USHORT: \ INT(unsigned short); \ break; \ case VIPS_FORMAT_SHORT: \ INT(short); \ break; \ case VIPS_FORMAT_UINT: \ FLOAT(unsigned int); \ break; \ case VIPS_FORMAT_INT: \ FLOAT(int); \ break; \ case VIPS_FORMAT_FLOAT: \ FLOAT(float); \ break; \ case VIPS_FORMAT_DOUBLE: \ FLOAT(double); \ break; \ case VIPS_FORMAT_COMPLEX: \ FLOAT(float); \ break; \ case VIPS_FORMAT_DPCOMPLEX: \ FLOAT(double); \ break; \ default: \ g_assert(FALSE); \ } \ } static void vips_interpolate_bilinear_interpolate(VipsInterpolate *interpolate, void *out, VipsRegion *in, double x, double y) { /* Pel size and line size. */ const int ps = VIPS_IMAGE_SIZEOF_PEL(in->im); const int ls = VIPS_REGION_LSKIP(in); const int b = in->im->Bands * (vips_band_format_iscomplex(in->im->BandFmt) ? 2 : 1); const int ix = (int) x; const int iy = (int) y; const VipsPel *restrict p1 = VIPS_REGION_ADDR(in, ix, iy); const VipsPel *restrict p2 = p1 + ps; const VipsPel *restrict p3 = p1 + ls; const VipsPel *restrict p4 = p3 + ps; int z; g_assert((int) x >= in->valid.left); g_assert((int) y >= in->valid.top); g_assert((int) x + 1 < VIPS_RECT_RIGHT(&in->valid)); g_assert((int) y + 1 < VIPS_RECT_BOTTOM(&in->valid)); SWITCH_INTERPOLATE(in->im->BandFmt, BILINEAR_INT, BILINEAR_FLOAT); } static void vips_interpolate_bilinear_class_init(VipsInterpolateBilinearClass *class) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(class); VipsInterpolateClass *interpolate_class = (VipsInterpolateClass *) class; object_class->nickname = "bilinear"; object_class->description = _("bilinear interpolation"); interpolate_class->interpolate = vips_interpolate_bilinear_interpolate; interpolate_class->window_size = 2; } static void vips_interpolate_bilinear_init(VipsInterpolateBilinear *bilinear) { #ifdef DEBUG printf("vips_interpolate_bilinear_init: "); vips_object_print_name(VIPS_OBJECT(bilinear)); #endif /*DEBUG*/ } VipsInterpolate * vips_interpolate_bilinear_new(void) { return VIPS_INTERPOLATE(vips_object_new( VIPS_TYPE_INTERPOLATE_BILINEAR, NULL, NULL, NULL)); } /** * vips_interpolate_bilinear_static: * * A convenience function that returns a bilinear interpolator you * don't need to free. * * Returns: (transfer none): a bilinear interpolator */ VipsInterpolate * vips_interpolate_bilinear_static(void) { static VipsInterpolate *interpolate = NULL; if (!interpolate) { interpolate = vips_interpolate_bilinear_new(); vips_object_set_static(VIPS_OBJECT(interpolate), TRUE); } return interpolate; } /* Called on startup: register the base libvips interpolators. */ void vips__interpolate_init(void) { extern GType vips_interpolate_bicubic_get_type(void); extern GType vips_interpolate_lbb_get_type(void); extern GType vips_interpolate_nohalo_get_type(void); extern GType vips_interpolate_vsqbs_get_type(void); vips_interpolate_nearest_get_type(); vips_interpolate_bilinear_get_type(); vips_interpolate_bicubic_get_type(); vips_interpolate_lbb_get_type(); vips_interpolate_nohalo_get_type(); vips_interpolate_vsqbs_get_type(); } /** * vips_interpolate_new: (constructor) * @nickname: nickname for interpolator * * Look up an interpolator from a nickname and make one. You need to free the * result with [method@GObject.Object.unref] when you're done with it. * * ::: seealso * [func@type_find]. * * Returns: an interpolator, or `NULL` on error. */ VipsInterpolate * vips_interpolate_new(const char *nickname) { GType type; if (!(type = vips_type_find("VipsInterpolate", nickname))) { vips_error("VipsInterpolate", _("class \"%s\" not found"), nickname); return NULL; } return VIPS_INTERPOLATE(vips_object_new(type, NULL, NULL, NULL)); } libvips-8.18.2/libvips/resample/lbb.cpp000066400000000000000000000723431516303661500200240ustar00rootroot00000000000000/* lbb (locally bounded bicubic) resampler * * N. Robidoux, C. Racette and J. Cupitt, 23-28/03/2010 * * N. Robidoux, 16-19/05/2010 * * N. Robidoux, 22/11/2011 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* * 2010 (c) Nicolas Robidoux, Chantal Racette, John Cupitt. * * N. Robidoux thanks Adam Turcotte, Geert Jordaens, Ralf Meyer, * Øyvind Kolås, Minglun Gong, Eric Daoust and Sven Neumann for useful * comments and code. * * C. Racette's image resampling research and programming funded in * part by an NSERC (National Science and Engineering Research Council * of Canada) Alexander Graham Bell Canada Graduate Scholarship, by an * NSERC Discovery Grant awarded to Julien Dompierre (grant number * 20-61098) and by N. Robidoux's Laurentian University professional * allowance. */ /* * LBB has two versions: * * A "soft" version, which shows a little less staircasing and a * little more haloing, and which is a little more expensive to * compute. We recommend this as the default. * * A "sharp" version, which shows a little more staircasing and a * little less haloing, which is a little cheaper (it uses 6 less * comparisons and 12 less "? :"). * * The only difference between the two is that the "soft" versions * uses local minima and maxima computed over 3x3 square blocks, and * the "sharp" version uses local minima and maxima computed over 3x3 * crosses. * * If you want to use the "sharp" version, comment out the following * three pre-processor code lines: */ /* #ifndef __LBB_CHEAP_H__ #define __LBB_CHEAP_H__ #endif */ /* * LBB (Locally Bounded Bicubic) is a high quality nonlinear variant * of Catmull-Rom. Images resampled with LBB have much smaller halos * than images resampled with windowed sincs or other interpolatory * cubic spline filters. Specifically, LBB halos are narrower and the * over/undershoot amplitude is smaller. This is accomplished without * significantly affecting the smoothness of the result (compared to * Catmull-Rom). * * Another important property is that the resampled values are * contained within the range of nearby input values. Consequently, no * final clamping is needed to stay "in range" (e.g., 0-255 for * standard 8-bit images). * * LBB was developed by N. Robidoux and C. Racette at the Department * of Mathematics and Computer Science of Laurentian University in the * course of C. Racette's Masters thesis in Computational * Sciences. Preliminary work directly leading to the LBB method and * code was performed by C. Racette and N. Robidoux in the course of * her honours thesis, and by N. Robidoux, A. Turcotte and E. Daoust * during Google Summer of Code 2009 (through two awards made to GIMP * to improve GEGL). * * LBB is a novel method with the following properties: * * --LBB is a Hermite bicubic method: The bicubic surface is defined, * one convex hull of four nearby input points at a time, using four * point values, four x-derivatives, four y-derivatives, and four * cross-derivatives. * * --The stencil for values in a square patch is the usual 4x4. * * --LBB is interpolatory. * * --It is C^1 with continuous cross derivatives. * * --When the limiters are inactive, LBB gives the same result as * Catmull-Rom. * * --When used on binary images, LBB gives results similar to bicubic * Hermite with all first derivatives---but not necessarily the * cross derivatives (this last assertion needs to be double * checked)--at input pixel locations set to zero. * * --The LBB reconstruction is locally bounded: Over each square * patch, the surface is contained between the minimum and the * maximum of the 16 nearest input pixel values. * * --Consequently, the LBB reconstruction is globally bounded between * the very smallest input pixel value and the very largest input * pixel value. It is not necessary to clamp results. * * The LBB method is based on the method of Ken Brodlie, Petros * Mashwama and Sohail Butt for constraining Hermite interpolants * between globally defined planes: * * Visualization of surface data to preserve positivity and other * simple constraints. Computer & Graphics, Vol. 19, Number 4, pages * 585-594, 1995. DOI: 10.1016/0097-8493(95)00036-C. * * Instead of forcing the reconstructed surface to lie between two * GLOBALLY defined planes, LBB constrains one patch at a time to lie * between LOCALLY defined planes. This is accomplished by * constraining the derivatives (x, y and cross) at each input pixel * location so that if the constraint was applied everywhere the * surface would fit between the min and max of the values at the 9 * closest pixel locations. Because this is done with each of the four * pixel locations which define the bicubic patch, this forces the * reconstructed surface to lie between the min and max of the values * at the 16 closest values pixel locations. (Each corner defines its * own 3x3 subgroup of the 4x4 stencil. Consequently, the surface is * necessarily above the minimum of the four minima, which happens to * be the minimum over the 4x4. Similarly with the maxima.) * * The above paragraph described the "soft" version of LBB. The * "sharp" version is similar. */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "templates.h" #define VIPS_TYPE_INTERPOLATE_LBB \ (vips_interpolate_lbb_get_type()) #define VIPS_INTERPOLATE_LBB(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE_LBB, VipsInterpolateLbb)) #define VIPS_INTERPOLATE_LBB_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE_LBB, VipsInterpolateLbbClass)) #define VIPS_IS_INTERPOLATE_LBB(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE_LBB)) #define VIPS_IS_INTERPOLATE_LBB_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE_LBB)) #define VIPS_INTERPOLATE_LBB_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE_LBB, VipsInterpolateLbbClass)) typedef struct _VipsInterpolateLbb { VipsInterpolate parent_object; } VipsInterpolateLbb; typedef struct _VipsInterpolateLbbClass { VipsInterpolateClass parent_class; } VipsInterpolateLbbClass; /* * Absolute value and sign macros: */ #define LBB_ABS(x) (((x) >= 0.) ? (x) : -(x)) #define LBB_SIGN(x) (((x) >= 0.) ? 1.0 : -1.0) /* * MIN and MAX macros set up so that I can put the likely winner in * the first argument (forward branch likely blah blah blah): */ #define LBB_MIN(x, y) (((x) <= (y)) ? (x) : (y)) #define LBB_MAX(x, y) (((x) >= (y)) ? (x) : (y)) static inline double lbbicubic(const double c00, const double c10, const double c01, const double c11, const double c00dx, const double c10dx, const double c01dx, const double c11dx, const double c00dy, const double c10dy, const double c01dy, const double c11dy, const double c00dxdy, const double c10dxdy, const double c01dxdy, const double c11dxdy, const double uno_one, const double uno_two, const double uno_thr, const double uno_fou, const double dos_one, const double dos_two, const double dos_thr, const double dos_fou, const double tre_one, const double tre_two, const double tre_thr, const double tre_fou, const double qua_one, const double qua_two, const double qua_thr, const double qua_fou) { /* * STENCIL (FOOTPRINT) OF INPUT VALUES: * * The stencil of LBB is the same as for any standard Hermite * bicubic (e.g., Catmull-Rom): * * (ix-1,iy-1) (ix,iy-1) (ix+1,iy-1) (ix+2,iy-1) * = uno_one = uno_two = uno_thr = uno_fou * * (ix-1,iy) (ix,iy) (ix+1,iy) (ix+2,iy) * = dos_one = dos_two = dos_thr = dos_fou * X * (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1) (ix+2,iy+1) * = tre_one = tre_two = tre_thr = tre_fou * * (ix-1,iy+2) (ix,iy+2) (ix+1,iy+2) (ix+2,iy+2) * = qua_one = qua_two = qua_thr = qua_fou * * where ix is the (pseudo-)floor of the requested left-to-right * location ("X"), and iy is the floor of the requested up-to-down * location. */ #if defined(__LBB_CHEAP_H__) /* * Computation of the four min and four max over 3x3 input data * sub-crosses of the 4x4 input stencil, performed with only 22 * comparisons and 28 "? :". If you can figure out how to do this * more efficiently, let us know. * * This is the cheaper (but arguably less desirable in terms of * quality) version of the computation. */ const double m1 = (dos_two <= dos_thr) ? dos_two : dos_thr; const double M1 = (dos_two <= dos_thr) ? dos_thr : dos_two; const double m2 = (tre_two <= tre_thr) ? tre_two : tre_thr; const double M2 = (tre_two <= tre_thr) ? tre_thr : tre_two; const double m3 = (uno_two <= dos_one) ? uno_two : dos_one; const double M3 = (uno_two <= dos_one) ? dos_one : uno_two; const double m4 = (uno_thr <= dos_fou) ? uno_thr : dos_fou; const double M4 = (uno_thr <= dos_fou) ? dos_fou : uno_thr; const double m5 = (tre_one <= qua_two) ? tre_one : qua_two; const double M5 = (tre_one <= qua_two) ? qua_two : tre_one; const double m6 = (tre_fou <= qua_thr) ? tre_fou : qua_thr; const double M6 = (tre_fou <= qua_thr) ? qua_thr : tre_fou; const double m7 = LBB_MIN(m1, tre_two); const double M7 = LBB_MAX(M1, tre_two); const double m8 = LBB_MIN(m1, tre_thr); const double M8 = LBB_MAX(M1, tre_thr); const double m9 = LBB_MIN(m2, dos_two); const double M9 = LBB_MAX(M2, dos_two); const double m10 = LBB_MIN(m2, dos_thr); const double M10 = LBB_MAX(M2, dos_thr); const double min00 = LBB_MIN(m7, m3); const double max00 = LBB_MAX(M7, M3); const double min10 = LBB_MIN(m8, m4); const double max10 = LBB_MAX(M8, M4); const double min01 = LBB_MIN(m9, m5); const double max01 = LBB_MAX(M9, M5); const double min11 = LBB_MIN(m10, m6); const double max11 = LBB_MAX(M10, M6); #else /* * Computation of the four min and four max over 3x3 input data * sub-blocks of the 4x4 input stencil, performed with only 28 * comparisons and 34 "? :". If you can figure how to do this more * efficiently, let us know. */ const double m1 = (dos_two <= dos_thr) ? dos_two : dos_thr; const double M1 = (dos_two <= dos_thr) ? dos_thr : dos_two; const double m2 = (tre_two <= tre_thr) ? tre_two : tre_thr; const double M2 = (tre_two <= tre_thr) ? tre_thr : tre_two; const double m6 = (dos_one <= tre_one) ? dos_one : tre_one; const double M6 = (dos_one <= tre_one) ? tre_one : dos_one; const double m7 = (dos_fou <= tre_fou) ? dos_fou : tre_fou; const double M7 = (dos_fou <= tre_fou) ? tre_fou : dos_fou; const double m3 = (uno_two <= uno_thr) ? uno_two : uno_thr; const double M3 = (uno_two <= uno_thr) ? uno_thr : uno_two; const double m4 = (qua_two <= qua_thr) ? qua_two : qua_thr; const double M4 = (qua_two <= qua_thr) ? qua_thr : qua_two; const double m5 = LBB_MIN(m1, m2); const double M5 = LBB_MAX(M1, M2); const double m10 = LBB_MIN(m6, uno_one); const double M10 = LBB_MAX(M6, uno_one); const double m11 = LBB_MIN(m6, qua_one); const double M11 = LBB_MAX(M6, qua_one); const double m12 = LBB_MIN(m7, uno_fou); const double M12 = LBB_MAX(M7, uno_fou); const double m13 = LBB_MIN(m7, qua_fou); const double M13 = LBB_MAX(M7, qua_fou); const double m8 = LBB_MIN(m5, m3); const double M8 = LBB_MAX(M5, M3); const double m9 = LBB_MIN(m5, m4); const double M9 = LBB_MAX(M5, M4); const double min00 = LBB_MIN(m8, m10); const double max00 = LBB_MAX(M8, M10); const double min10 = LBB_MIN(m8, m12); const double max10 = LBB_MAX(M8, M12); const double min01 = LBB_MIN(m9, m11); const double max01 = LBB_MAX(M9, M11); const double min11 = LBB_MIN(m9, m13); const double max11 = LBB_MAX(M9, M13); #endif /* * The remainder of the "per channel" computation involves the * computation of: * * --8 conditional moves, * * --8 signs (in which the sign of zero is unimportant), * * --12 minima of two values, * * --8 maxima of two values, * * --8 absolute values, * * for a grand total of 29 minima, 25 maxima, 8 conditional moves, 8 * signs, and 8 absolute values. If everything is done with * conditional moves, "only" 28+8+8+12+8+8=72 flags are involved * (because initial min and max can be computed with one flag). * * The "per channel" part of the computation also involves 107 * arithmetic operations (54 *, 21 +, 42 -). */ /* * Distances to the local min and max: */ const double u00 = dos_two - min00; const double v00 = max00 - dos_two; const double u10 = dos_thr - min10; const double v10 = max10 - dos_thr; const double u01 = tre_two - min01; const double v01 = max01 - tre_two; const double u11 = tre_thr - min11; const double v11 = max11 - tre_thr; /* * Initial values of the derivatives computed with centered * differences. Factors of 1/2 are left out because they are folded * in later: */ const double dble_dzdx00i = dos_thr - dos_one; const double dble_dzdy11i = qua_thr - dos_thr; const double dble_dzdx10i = dos_fou - dos_two; const double dble_dzdy01i = qua_two - dos_two; const double dble_dzdx01i = tre_thr - tre_one; const double dble_dzdy10i = tre_thr - uno_thr; const double dble_dzdx11i = tre_fou - tre_two; const double dble_dzdy00i = tre_two - uno_two; /* * Signs of the derivatives. The upcoming clamping does not change * them (except if the clamping sends a negative derivative to 0, in * which case the sign does not matter anyway). */ const double sign_dzdx00 = LBB_SIGN(dble_dzdx00i); const double sign_dzdx10 = LBB_SIGN(dble_dzdx10i); const double sign_dzdx01 = LBB_SIGN(dble_dzdx01i); const double sign_dzdx11 = LBB_SIGN(dble_dzdx11i); const double sign_dzdy00 = LBB_SIGN(dble_dzdy00i); const double sign_dzdy10 = LBB_SIGN(dble_dzdy10i); const double sign_dzdy01 = LBB_SIGN(dble_dzdy01i); const double sign_dzdy11 = LBB_SIGN(dble_dzdy11i); /* * Initial values of the cross-derivatives. Factors of 1/4 are left * out because folded in later: */ const double quad_d2zdxdy00i = uno_one - uno_thr + dble_dzdx01i; const double quad_d2zdxdy10i = uno_two - uno_fou + dble_dzdx11i; const double quad_d2zdxdy01i = qua_thr - qua_one - dble_dzdx00i; const double quad_d2zdxdy11i = qua_fou - qua_two - dble_dzdx10i; /* * Slope limiters. The key multiplier is 3 but we fold a factor of * 2, hence 6: */ const double dble_slopelimit_00 = 6.0 * LBB_MIN(u00, v00); const double dble_slopelimit_10 = 6.0 * LBB_MIN(u10, v10); const double dble_slopelimit_01 = 6.0 * LBB_MIN(u01, v01); const double dble_slopelimit_11 = 6.0 * LBB_MIN(u11, v11); /* * Clamped first derivatives: */ const double dble_dzdx00 = (sign_dzdx00 * dble_dzdx00i <= dble_slopelimit_00) ? dble_dzdx00i : sign_dzdx00 * dble_slopelimit_00; const double dble_dzdy00 = (sign_dzdy00 * dble_dzdy00i <= dble_slopelimit_00) ? dble_dzdy00i : sign_dzdy00 * dble_slopelimit_00; const double dble_dzdx10 = (sign_dzdx10 * dble_dzdx10i <= dble_slopelimit_10) ? dble_dzdx10i : sign_dzdx10 * dble_slopelimit_10; const double dble_dzdy10 = (sign_dzdy10 * dble_dzdy10i <= dble_slopelimit_10) ? dble_dzdy10i : sign_dzdy10 * dble_slopelimit_10; const double dble_dzdx01 = (sign_dzdx01 * dble_dzdx01i <= dble_slopelimit_01) ? dble_dzdx01i : sign_dzdx01 * dble_slopelimit_01; const double dble_dzdy01 = (sign_dzdy01 * dble_dzdy01i <= dble_slopelimit_01) ? dble_dzdy01i : sign_dzdy01 * dble_slopelimit_01; const double dble_dzdx11 = (sign_dzdx11 * dble_dzdx11i <= dble_slopelimit_11) ? dble_dzdx11i : sign_dzdx11 * dble_slopelimit_11; const double dble_dzdy11 = (sign_dzdy11 * dble_dzdy11i <= dble_slopelimit_11) ? dble_dzdy11i : sign_dzdy11 * dble_slopelimit_11; /* * Sums and differences of first derivatives: */ const double twelve_sum00 = 6.0 * (dble_dzdx00 + dble_dzdy00); const double twelve_dif00 = 6.0 * (dble_dzdx00 - dble_dzdy00); const double twelve_sum10 = 6.0 * (dble_dzdx10 + dble_dzdy10); const double twelve_dif10 = 6.0 * (dble_dzdx10 - dble_dzdy10); const double twelve_sum01 = 6.0 * (dble_dzdx01 + dble_dzdy01); const double twelve_dif01 = 6.0 * (dble_dzdx01 - dble_dzdy01); const double twelve_sum11 = 6.0 * (dble_dzdx11 + dble_dzdy11); const double twelve_dif11 = 6.0 * (dble_dzdx11 - dble_dzdy11); /* * Absolute values of the sums: */ const double twelve_abs_sum00 = LBB_ABS(twelve_sum00); const double twelve_abs_sum10 = LBB_ABS(twelve_sum10); const double twelve_abs_sum01 = LBB_ABS(twelve_sum01); const double twelve_abs_sum11 = LBB_ABS(twelve_sum11); /* * Scaled distances to the min: */ const double u00_times_36 = 36.0 * u00; const double u10_times_36 = 36.0 * u10; const double u01_times_36 = 36.0 * u01; const double u11_times_36 = 36.0 * u11; /* * First cross-derivative limiter: */ const double first_limit00 = twelve_abs_sum00 - u00_times_36; const double first_limit10 = twelve_abs_sum10 - u10_times_36; const double first_limit01 = twelve_abs_sum01 - u01_times_36; const double first_limit11 = twelve_abs_sum11 - u11_times_36; const double quad_d2zdxdy00ii = LBB_MAX(quad_d2zdxdy00i, first_limit00); const double quad_d2zdxdy10ii = LBB_MAX(quad_d2zdxdy10i, first_limit10); const double quad_d2zdxdy01ii = LBB_MAX(quad_d2zdxdy01i, first_limit01); const double quad_d2zdxdy11ii = LBB_MAX(quad_d2zdxdy11i, first_limit11); /* * Scaled distances to the max: */ const double v00_times_36 = 36.0 * v00; const double v10_times_36 = 36.0 * v10; const double v01_times_36 = 36.0 * v01; const double v11_times_36 = 36.0 * v11; /* * Second cross-derivative limiter: */ const double second_limit00 = v00_times_36 - twelve_abs_sum00; const double second_limit10 = v10_times_36 - twelve_abs_sum10; const double second_limit01 = v01_times_36 - twelve_abs_sum01; const double second_limit11 = v11_times_36 - twelve_abs_sum11; const double quad_d2zdxdy00iii = LBB_MIN(quad_d2zdxdy00ii, second_limit00); const double quad_d2zdxdy10iii = LBB_MIN(quad_d2zdxdy10ii, second_limit10); const double quad_d2zdxdy01iii = LBB_MIN(quad_d2zdxdy01ii, second_limit01); const double quad_d2zdxdy11iii = LBB_MIN(quad_d2zdxdy11ii, second_limit11); /* * Absolute values of the differences: */ const double twelve_abs_dif00 = LBB_ABS(twelve_dif00); const double twelve_abs_dif10 = LBB_ABS(twelve_dif10); const double twelve_abs_dif01 = LBB_ABS(twelve_dif01); const double twelve_abs_dif11 = LBB_ABS(twelve_dif11); /* * Third cross-derivative limiter: */ const double third_limit00 = twelve_abs_dif00 - v00_times_36; const double third_limit10 = twelve_abs_dif10 - v10_times_36; const double third_limit01 = twelve_abs_dif01 - v01_times_36; const double third_limit11 = twelve_abs_dif11 - v11_times_36; const double quad_d2zdxdy00iiii = LBB_MAX(quad_d2zdxdy00iii, third_limit00); const double quad_d2zdxdy10iiii = LBB_MAX(quad_d2zdxdy10iii, third_limit10); const double quad_d2zdxdy01iiii = LBB_MAX(quad_d2zdxdy01iii, third_limit01); const double quad_d2zdxdy11iiii = LBB_MAX(quad_d2zdxdy11iii, third_limit11); /* * Fourth cross-derivative limiter: */ const double fourth_limit00 = u00_times_36 - twelve_abs_dif00; const double fourth_limit10 = u10_times_36 - twelve_abs_dif10; const double fourth_limit01 = u01_times_36 - twelve_abs_dif01; const double fourth_limit11 = u11_times_36 - twelve_abs_dif11; const double quad_d2zdxdy00 = LBB_MIN(quad_d2zdxdy00iiii, fourth_limit00); const double quad_d2zdxdy10 = LBB_MIN(quad_d2zdxdy10iiii, fourth_limit10); const double quad_d2zdxdy01 = LBB_MIN(quad_d2zdxdy01iiii, fourth_limit01); const double quad_d2zdxdy11 = LBB_MIN(quad_d2zdxdy11iiii, fourth_limit11); /* * Part of the result which does not need derivatives: */ const double newval1 = c00 * dos_two + c10 * dos_thr + c01 * tre_two + c11 * tre_thr; /* * Twice the part of the result which only needs first derivatives. */ const double newval2 = c00dx * dble_dzdx00 + c10dx * dble_dzdx10 + c01dx * dble_dzdx01 + c11dx * dble_dzdx11 + c00dy * dble_dzdy00 + c10dy * dble_dzdy10 + c01dy * dble_dzdy01 + c11dy * dble_dzdy11; /* * Four times the part of the result which only uses cross * derivatives: */ const double newval3 = c00dxdy * quad_d2zdxdy00 + c10dxdy * quad_d2zdxdy10 + c01dxdy * quad_d2zdxdy01 + c11dxdy * quad_d2zdxdy11; const double newval = newval1 + .5 * newval2 + .25 * newval3; return newval; } /* * Call lbb with a type conversion operator as a parameter. * * It would be nice to do this with templates but we can't figure out * how to do it cleanly. Suggestions welcome! */ #define LBB_CONVERSION(conversion) \ template \ static void inline lbb_##conversion(void *restrict pout, \ const VipsPel *restrict pin, \ const int bands, \ const int lskip, \ const double relative_x, \ const double relative_y) \ { \ T *restrict out = (T *) pout; \ \ const T *restrict in = (T *) pin; \ \ const int one_shift = -bands; \ const int thr_shift = bands; \ const int fou_shift = 2 * bands; \ \ const int uno_two_shift = -lskip; \ \ const int tre_two_shift = lskip; \ const int qua_two_shift = 2 * lskip; \ \ const int uno_one_shift = uno_two_shift + one_shift; \ const int dos_one_shift = one_shift; \ const int tre_one_shift = tre_two_shift + one_shift; \ const int qua_one_shift = qua_two_shift + one_shift; \ \ const int uno_thr_shift = uno_two_shift + thr_shift; \ const int dos_thr_shift = thr_shift; \ const int tre_thr_shift = tre_two_shift + thr_shift; \ const int qua_thr_shift = qua_two_shift + thr_shift; \ \ const int uno_fou_shift = uno_two_shift + fou_shift; \ const int dos_fou_shift = fou_shift; \ const int tre_fou_shift = tre_two_shift + fou_shift; \ const int qua_fou_shift = qua_two_shift + fou_shift; \ \ const double xp1over2 = relative_x; \ const double xm1over2 = xp1over2 - 1.0; \ const double onepx = 0.5 + xp1over2; \ const double onemx = 1.5 - xp1over2; \ const double xp1over2sq = xp1over2 * xp1over2; \ \ const double yp1over2 = relative_y; \ const double ym1over2 = yp1over2 - 1.0; \ const double onepy = 0.5 + yp1over2; \ const double onemy = 1.5 - yp1over2; \ const double yp1over2sq = yp1over2 * yp1over2; \ \ const double xm1over2sq = xm1over2 * xm1over2; \ const double ym1over2sq = ym1over2 * ym1over2; \ \ const double twice1px = onepx + onepx; \ const double twice1py = onepy + onepy; \ const double twice1mx = onemx + onemx; \ const double twice1my = onemy + onemy; \ \ const double xm1over2sq_times_ym1over2sq = xm1over2sq * ym1over2sq; \ const double xp1over2sq_times_ym1over2sq = xp1over2sq * ym1over2sq; \ const double xp1over2sq_times_yp1over2sq = xp1over2sq * yp1over2sq; \ const double xm1over2sq_times_yp1over2sq = xm1over2sq * yp1over2sq; \ \ const double four_times_1px_times_1py = twice1px * twice1py; \ const double four_times_1mx_times_1py = twice1mx * twice1py; \ const double twice_xp1over2_times_1py = xp1over2 * twice1py; \ const double twice_xm1over2_times_1py = xm1over2 * twice1py; \ \ const double twice_xm1over2_times_1my = xm1over2 * twice1my; \ const double twice_xp1over2_times_1my = xp1over2 * twice1my; \ const double four_times_1mx_times_1my = twice1mx * twice1my; \ const double four_times_1px_times_1my = twice1px * twice1my; \ \ const double twice_1px_times_ym1over2 = twice1px * ym1over2; \ const double twice_1mx_times_ym1over2 = twice1mx * ym1over2; \ const double xp1over2_times_ym1over2 = xp1over2 * ym1over2; \ const double xm1over2_times_ym1over2 = xm1over2 * ym1over2; \ \ const double xm1over2_times_yp1over2 = xm1over2 * yp1over2; \ const double xp1over2_times_yp1over2 = xp1over2 * yp1over2; \ const double twice_1mx_times_yp1over2 = twice1mx * yp1over2; \ const double twice_1px_times_yp1over2 = twice1px * yp1over2; \ \ const double c00 = \ four_times_1px_times_1py * xm1over2sq_times_ym1over2sq; \ const double c00dx = \ twice_xp1over2_times_1py * xm1over2sq_times_ym1over2sq; \ const double c00dy = \ twice_1px_times_yp1over2 * xm1over2sq_times_ym1over2sq; \ const double c00dxdy = \ xp1over2_times_yp1over2 * xm1over2sq_times_ym1over2sq; \ \ const double c10 = \ four_times_1mx_times_1py * xp1over2sq_times_ym1over2sq; \ const double c10dx = \ twice_xm1over2_times_1py * xp1over2sq_times_ym1over2sq; \ const double c10dy = \ twice_1mx_times_yp1over2 * xp1over2sq_times_ym1over2sq; \ const double c10dxdy = \ xm1over2_times_yp1over2 * xp1over2sq_times_ym1over2sq; \ \ const double c01 = \ four_times_1px_times_1my * xm1over2sq_times_yp1over2sq; \ const double c01dx = \ twice_xp1over2_times_1my * xm1over2sq_times_yp1over2sq; \ const double c01dy = \ twice_1px_times_ym1over2 * xm1over2sq_times_yp1over2sq; \ const double c01dxdy = \ xp1over2_times_ym1over2 * xm1over2sq_times_yp1over2sq; \ \ const double c11 = \ four_times_1mx_times_1my * xp1over2sq_times_yp1over2sq; \ const double c11dx = \ twice_xm1over2_times_1my * xp1over2sq_times_yp1over2sq; \ const double c11dy = \ twice_1mx_times_ym1over2 * xp1over2sq_times_yp1over2sq; \ const double c11dxdy = \ xm1over2_times_ym1over2 * xp1over2sq_times_yp1over2sq; \ \ int band = bands; \ \ do { \ const double double_result = \ lbbicubic(c00, \ c10, \ c01, \ c11, \ c00dx, \ c10dx, \ c01dx, \ c11dx, \ c00dy, \ c10dy, \ c01dy, \ c11dy, \ c00dxdy, \ c10dxdy, \ c01dxdy, \ c11dxdy, \ in[uno_one_shift], \ in[uno_two_shift], \ in[uno_thr_shift], \ in[uno_fou_shift], \ in[dos_one_shift], \ in[0], \ in[dos_thr_shift], \ in[dos_fou_shift], \ in[tre_one_shift], \ in[tre_two_shift], \ in[tre_thr_shift], \ in[tre_fou_shift], \ in[qua_one_shift], \ in[qua_two_shift], \ in[qua_thr_shift], \ in[qua_fou_shift]); \ \ const T result = to_##conversion(double_result); \ in++; \ *out++ = result; \ } while (--band); \ } LBB_CONVERSION(fptypes) LBB_CONVERSION(withsign) LBB_CONVERSION(nosign) #define CALL(T, conversion) \ lbb_##conversion(out, \ p, \ bands, \ lskip, \ relative_x, \ relative_y); /* * We need C linkage: */ extern "C" { G_DEFINE_TYPE(VipsInterpolateLbb, vips_interpolate_lbb, VIPS_TYPE_INTERPOLATE); } static void vips_interpolate_lbb_interpolate(VipsInterpolate *restrict interpolate, void *restrict out, VipsRegion *restrict in, double absolute_x, double absolute_y) { /* absolute_x and absolute_y are always >= 1.0 (see double-check assert * below), so we don't need floor(). * * It's 1 not 0 since have a window_offset of 1. */ const int ix = (int) absolute_x; const int iy = (int) absolute_y; /* * Move the pointer to (the first band of) the top/left pixel of the * 2x2 group of pixel centers which contains the sampling location * in its convex hull: */ const VipsPel *restrict p = VIPS_REGION_ADDR(in, ix, iy); const double relative_x = absolute_x - ix; const double relative_y = absolute_y - iy; /* * VIPS versions of Nicolas's pixel addressing values. */ const int lskip = VIPS_REGION_LSKIP(in) / VIPS_IMAGE_SIZEOF_ELEMENT(in->im); /* * Double the bands for complex images to account for the real and * imaginary parts being computed independently: */ const int actual_bands = in->im->Bands; const int bands = vips_band_format_iscomplex(in->im->BandFmt) ? 2 * actual_bands : actual_bands; g_assert(ix - 1 >= in->valid.left); g_assert(iy - 1 >= in->valid.top); g_assert(ix + 2 < VIPS_RECT_RIGHT(&in->valid)); g_assert(iy + 2 < VIPS_RECT_BOTTOM(&in->valid)); /* Confirm that absolute_x and absolute_y are >= 1, see above. */ g_assert(absolute_x >= 1.0); g_assert(absolute_y >= 1.0); switch (in->im->BandFmt) { case VIPS_FORMAT_UCHAR: CALL(unsigned char, nosign); break; case VIPS_FORMAT_CHAR: CALL(signed char, withsign); break; case VIPS_FORMAT_USHORT: CALL(unsigned short, nosign); break; case VIPS_FORMAT_SHORT: CALL(signed short, withsign); break; case VIPS_FORMAT_UINT: CALL(unsigned int, nosign); break; case VIPS_FORMAT_INT: CALL(signed int, withsign); break; /* * Complex images are handled by doubling of bands. */ case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: CALL(float, fptypes); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: CALL(double, fptypes); break; default: g_assert(0); break; } } static void vips_interpolate_lbb_class_init(VipsInterpolateLbbClass *klass) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(klass); VipsInterpolateClass *interpolate_class = VIPS_INTERPOLATE_CLASS(klass); object_class->nickname = "lbb"; object_class->description = _("reduced halo bicubic"); interpolate_class->interpolate = vips_interpolate_lbb_interpolate; interpolate_class->window_size = 4; } static void vips_interpolate_lbb_init(VipsInterpolateLbb *lbb) { } libvips-8.18.2/libvips/resample/mapim.c000066400000000000000000000362631516303661500200310ustar00rootroot00000000000000/* resample with an index image * * 15/11/15 * - from affine.c * 12/8/18 * - prevent float->int overflow * - a bit quicker * 17/12/18 * - we were not offsetting pixel fetches by window_offset * 30/1/21 afontenot * - avoid NaN * 21/12/21 * - improve edge antialiasing with "background" and "extend" * - add "premultiplied" param */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include #include "presample.h" typedef struct _VipsMapim { VipsResample parent_instance; VipsImage *index; VipsInterpolate *interpolate; /* How to generate extra edge pixels. */ VipsExtend extend; /* Background colour. */ VipsArrayDouble *background; /* The [double] converted to the input image format. */ VipsPel *ink; /* True if the input is already premultiplied (and we don't need to). */ gboolean premultiplied; /* Need an image vector for start_many / stop_many */ VipsImage *in_array[3]; } VipsMapim; typedef VipsResampleClass VipsMapimClass; G_DEFINE_TYPE(VipsMapim, vips_mapim, VIPS_TYPE_RESAMPLE); /* Minmax of a line of pixels. */ #define MINMAX(TYPE) \ { \ TYPE *restrict p1 = (TYPE *) p; \ \ TYPE t_max_x = max_x; \ TYPE t_min_x = min_x; \ TYPE t_max_y = max_y; \ TYPE t_min_y = min_y; \ \ for (x = 0; x < r->width; x++) { \ TYPE px = p1[0]; \ TYPE py = p1[1]; \ \ if (first) { \ t_min_x = px; \ t_max_x = px; \ t_min_y = py; \ t_max_y = py; \ \ first = FALSE; \ } \ else { \ if (px > t_max_x) \ t_max_x = px; \ else if (px < t_min_x) \ t_min_x = px; \ \ if (py > t_max_y) \ t_max_y = py; \ else if (py < t_min_y) \ t_min_y = py; \ } \ \ p1 += 2; \ } \ \ min_x = t_min_x; \ max_x = t_max_x; \ min_y = t_min_y; \ max_y = t_max_y; \ } /* Scan a region and find min/max in the two axes. */ static void vips_mapim_region_minmax(VipsRegion *region, VipsRect *r, VipsRect *bounds) { double min_x; double max_x; double min_y; double max_y; gboolean first; int x, y; min_x = 0.0; max_x = 0.0; min_y = 0.0; max_y = 0.0; first = TRUE; for (y = 0; y < r->height; y++) { VipsPel *restrict p = VIPS_REGION_ADDR(region, r->left, r->top + y); switch (region->im->BandFmt) { case VIPS_FORMAT_UCHAR: MINMAX(unsigned char); break; case VIPS_FORMAT_CHAR: MINMAX(signed char); break; case VIPS_FORMAT_USHORT: MINMAX(unsigned short); break; case VIPS_FORMAT_SHORT: MINMAX(signed short); break; case VIPS_FORMAT_UINT: MINMAX(unsigned int); break; case VIPS_FORMAT_INT: MINMAX(signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: MINMAX(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: MINMAX(double); break; default: g_assert_not_reached(); } } /* bounds is the bounding box -- we must round left/top down and round * bottom/right up. */ min_x = floor(min_x); min_y = floor(min_y); max_x = ceil(max_x); max_y = ceil(max_y); /* bounds uses ints, so we must clip the range down from double. * Coordinates can be negative for the antialias edges. */ min_x = VIPS_CLIP(-1, min_x, VIPS_MAX_COORD); min_y = VIPS_CLIP(-1, min_y, VIPS_MAX_COORD); max_x = VIPS_CLIP(-1, max_x, VIPS_MAX_COORD); max_y = VIPS_CLIP(-1, max_y, VIPS_MAX_COORD); bounds->left = min_x; bounds->top = min_y; bounds->width = (max_x - min_x) + 1; bounds->height = (max_y - min_y) + 1; } /* Unsigned int types. */ #define ULOOKUP(TYPE) \ { \ TYPE *restrict p1 = (TYPE *) p; \ \ for (x = 0; x < r->width; x++) { \ TYPE px = p1[0]; \ TYPE py = p1[1]; \ \ if (px >= clip_width || \ py >= clip_height) { \ for (z = 0; z < ps; z++) \ q[z] = mapim->ink[z]; \ } \ else \ interpolate(mapim->interpolate, q, ir[0], \ px + window_offset + 1, \ py + window_offset + 1); \ \ p1 += 2; \ q += ps; \ } \ } /* Signed int types. We allow -1 for x/y to get edge antialiasing. */ #define LOOKUP(TYPE) \ { \ TYPE *restrict p1 = (TYPE *) p; \ \ for (x = 0; x < r->width; x++) { \ TYPE px = p1[0]; \ TYPE py = p1[1]; \ \ if (px < -1 || \ px >= clip_width || \ py < -1 || \ py >= clip_height) { \ for (z = 0; z < ps; z++) \ q[z] = mapim->ink[z]; \ } \ else \ interpolate(mapim->interpolate, q, ir[0], \ px + window_offset + 1, \ py + window_offset + 1); \ \ p1 += 2; \ q += ps; \ } \ } /* Float types. We allow -1 for x/y to get edge antialiasing. */ #define FLOOKUP(TYPE) \ { \ TYPE *restrict p1 = (TYPE *) p; \ \ for (x = 0; x < r->width; x++) { \ TYPE px = p1[0]; \ TYPE py = p1[1]; \ \ if (isnan(px) || \ isnan(py) || \ px < -1 || \ px >= clip_width || \ py < -1 || \ py >= clip_height) { \ for (z = 0; z < ps; z++) \ q[z] = mapim->ink[z]; \ } \ else \ interpolate(mapim->interpolate, q, ir[0], \ px + window_offset + 1, \ py + window_offset + 1); \ \ p1 += 2; \ q += ps; \ } \ } static int vips_mapim_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsRect *r = &out_region->valid; VipsRegion **ir = (VipsRegion **) seq; const VipsImage **in_array = (const VipsImage **) a; const VipsMapim *mapim = (VipsMapim *) b; const VipsImage *in = in_array[0]; const int window_size = vips_interpolate_get_window_size(mapim->interpolate); const int window_offset = vips_interpolate_get_window_offset(mapim->interpolate); const VipsInterpolateMethod interpolate = vips_interpolate_get_method(mapim->interpolate); const int ps = VIPS_IMAGE_SIZEOF_PEL(in); const int clip_width = in->Xsize - window_size; const int clip_height = in->Ysize - window_size; VipsRect bounds, need, image, clipped; int x, y, z; #ifdef DEBUG_VERBOSE printf("vips_mapim_gen: generating left=%d, top=%d, width=%d, height=%d\n", r->left, r->top, r->width, r->height); #endif /*DEBUG_VERBOSE*/ /* Fetch the chunk of the index image we need, and find the max/min in * x and y. */ if (vips_region_prepare(ir[1], r)) return -1; VIPS_GATE_START("vips_mapim_gen: work"); vips_mapim_region_minmax(ir[1], r, &bounds); VIPS_GATE_STOP("vips_mapim_gen: work"); /* Enlarge by the stencil size. */ need.width = bounds.width + window_size - 1; need.height = bounds.height + window_size - 1; /* Offset for the antialias edge we have top and left. */ need.left = bounds.left + 1; need.top = bounds.top + 1; /* Clip against the expanded image. */ image.left = 0; image.top = 0; image.width = in->Xsize; image.height = in->Ysize; vips_rect_intersectrect(&need, &image, &clipped); #ifdef DEBUG_VERBOSE printf("vips_mapim_gen: preparing left=%d, top=%d, width=%d, height=%d\n", clipped.left, clipped.top, clipped.width, clipped.height); #endif /*DEBUG_VERBOSE*/ if (vips_rect_isempty(&clipped)) { vips_region_paint_pel(out_region, r, mapim->ink); return 0; } if (vips_region_prepare(ir[0], &clipped)) return -1; VIPS_GATE_START("vips_mapim_gen: work"); /* Resample! x/y loop over pixels in the output (and index) images. */ for (y = 0; y < r->height; y++) { VipsPel *restrict p = VIPS_REGION_ADDR(ir[1], r->left, y + r->top); VipsPel *restrict q = VIPS_REGION_ADDR(out_region, r->left, y + r->top); switch (ir[1]->im->BandFmt) { case VIPS_FORMAT_UCHAR: ULOOKUP(unsigned char); break; case VIPS_FORMAT_CHAR: LOOKUP(signed char); break; case VIPS_FORMAT_USHORT: ULOOKUP(unsigned short); break; case VIPS_FORMAT_SHORT: LOOKUP(signed short); break; case VIPS_FORMAT_UINT: ULOOKUP(unsigned int); break; case VIPS_FORMAT_INT: LOOKUP(signed int); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: FLOOKUP(float); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: FLOOKUP(double); break; default: g_assert_not_reached(); } } VIPS_GATE_STOP("vips_mapim_gen: work"); return 0; } static int vips_mapim_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsMapim *mapim = (VipsMapim *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); VipsImage *in; int window_size; int window_offset; /* TRUE if we've premultiplied and need to unpremultiply. */ gboolean have_premultiplied; VipsBandFormat unpremultiplied_format; if (VIPS_OBJECT_CLASS(vips_mapim_parent_class)->build(object)) return -1; if (vips_check_coding_known(class->nickname, resample->in) || vips_check_twocomponents(class->nickname, mapim->index)) return -1; in = resample->in; if (vips_image_decode(in, &t[0])) return -1; in = t[0]; window_size = vips_interpolate_get_window_size(mapim->interpolate); window_offset = vips_interpolate_get_window_offset(mapim->interpolate); /* Add new pixels around the input so we can interpolate at the edges. * * We add the interpolate stencil, plus one extra pixel on all the * edges. This means when we clip in generate (above) we can be sure * we clip outside the real pixels and don't get jaggies on edges. * * We allow for the +1 in the adjustment to window_offset in generate. */ if (vips_embed(in, &t[1], window_offset + 1, window_offset + 1, in->Xsize + window_size - 1 + 2, in->Ysize + window_size - 1 + 2, "extend", mapim->extend, "background", mapim->background, NULL)) return -1; in = t[1]; /* If there's an alpha and we've not premultiplied, we have to * premultiply before resampling. */ have_premultiplied = FALSE; if (vips_image_hasalpha(in) && !mapim->premultiplied) { if (vips_premultiply(in, &t[2], NULL)) return -1; have_premultiplied = TRUE; /* vips_premultiply() makes a float image. When we * vips_unpremultiply() below, we need to cast back to the * pre-premultiply format. */ unpremultiplied_format = in->BandFmt; in = t[2]; } /* Convert the background to the image's format. */ if (!(mapim->ink = vips__vector_to_ink(class->nickname, in, VIPS_AREA(mapim->background)->data, NULL, VIPS_AREA(mapim->background)->n))) return -1; t[3] = vips_image_new(); if (vips_image_pipelinev(t[3], VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; t[3]->Xsize = mapim->index->Xsize; t[3]->Ysize = mapim->index->Ysize; mapim->in_array[0] = in; mapim->in_array[1] = mapim->index; mapim->in_array[2] = NULL; if (vips_image_generate(t[3], vips_start_many, vips_mapim_gen, vips_stop_many, mapim->in_array, mapim)) return -1; in = t[3]; if (have_premultiplied) { if (vips_unpremultiply(in, &t[4], NULL) || vips_cast(t[4], &t[5], unpremultiplied_format, NULL)) return -1; in = t[5]; } if (vips_image_write(in, resample->out)) return -1; return 0; } static void vips_mapim_class_init(VipsMapimClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_mapim_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "mapim"; vobject_class->description = _("resample with a map image"); vobject_class->build = vips_mapim_build; VIPS_ARG_IMAGE(class, "index", 3, _("Index"), _("Index pixels with this"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsMapim, index)); VIPS_ARG_INTERPOLATE(class, "interpolate", 4, _("Interpolate"), _("Interpolate pixels with this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMapim, interpolate)); VIPS_ARG_ENUM(class, "extend", 117, _("Extend"), _("How to generate the extra pixels"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMapim, extend), VIPS_TYPE_EXTEND, VIPS_EXTEND_BACKGROUND); VIPS_ARG_BOXED(class, "background", 116, _("Background"), _("Background value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMapim, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_BOOL(class, "premultiplied", 117, _("Premultiplied"), _("Images have premultiplied alpha"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsMapim, premultiplied), FALSE); } static void vips_mapim_init(VipsMapim *mapim) { mapim->interpolate = vips_interpolate_new("bilinear"); mapim->extend = VIPS_EXTEND_BACKGROUND; mapim->background = vips_array_double_newv(1, 0.0); } /** * vips_mapim: (method) * @in: input image * @out: (out): output image * @index: index image * @...: `NULL`-terminated list of optional named arguments * * This operator resamples @in using @index to look up pixels. * * @out is the same size as @index, with each pixel being fetched from that * position in @in. That is: * * ``` * out[x, y] = in[index[x, y]] * ``` * * If @index has one band, that band must be complex. Otherwise, @index must * have two bands of any format. * * Coordinates in @index are in pixels, with (0, 0) being the top-left corner * of @in, and with y increasing down the image. Use [ctor@Image.xyz] to * build index images. * * @interpolate defaults to bilinear. * * By default, new pixels are filled with @background. This defaults to * zero (black). You can set other extend types with @extend. [enum@Vips.Extend.COPY] * is better for image upsizing. * * Image are normally treated as unpremultiplied, so this operation can be used * directly on PNG images. If your images have been through * [method@Image.premultiply], set @premultiplied. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * See [method@Image.maplut] for a 1D equivalent of this operation. * * ::: tip "Optional arguments" * * @interpolate: [class@Interpolate], interpolate pixels with this * * @extend: [enum@Vips.Extend], how to generate new pixels * * @background: [struct@ArrayDouble], colour for new pixels * * @premultiplied: `gboolean`, images are already premultiplied * * ::: seealso * [ctor@Image.xyz], [method@Image.affine], [method@Image.resize], * [method@Image.maplut], [class@Interpolate]. * * Returns: 0 on success, -1 on error */ int vips_mapim(VipsImage *in, VipsImage **out, VipsImage *index, ...) { va_list ap; int result; va_start(ap, index); result = vips_call_split("mapim", ap, in, out, index); va_end(ap); return result; } libvips-8.18.2/libvips/resample/meson.build000066400000000000000000000013621516303661500207140ustar00rootroot00000000000000resample_sources = files( 'thumbnail.c', 'mapim.c', 'affine.c', 'quadratic.c', 'resample.c', 'similarity.c', 'resize.c', 'shrink.c', 'shrinkh.c', 'shrinkh_hwy.cpp', 'shrinkv.c', 'shrinkv_hwy.cpp', 'reduce.c', 'reduceh.cpp', 'reduceh_hwy.cpp', 'reducev.cpp', 'reducev_hwy.cpp', 'interpolate.c', 'transform.c', 'bicubic.cpp', 'lbb.cpp', 'nohalo.cpp', 'vsqbs.cpp', ) resample_headers = files( 'presample.h', 'templates.h', ) libvips_sources += resample_sources resample_lib = static_library('resample', resample_sources, resample_headers, dependencies: libvips_deps, gnu_symbol_visibility: 'hidden', ) libvips_components += resample_lib libvips-8.18.2/libvips/resample/nohalo.cpp000066400000000000000000001516441516303661500205470ustar00rootroot00000000000000/* nohalo subdivision followed by lbb (locally bounded bicubic) * interpolation resampler * * Nohalo level 1 with bilinear finishing scheme hacked for VIPS by * J. Cupitt based on code by N. Robidoux, 20/1/09 * * N. Robidoux and J. Cupitt, 4-17/3/09 * * N. Robidoux, 1/4-29/5/2009 * * Nohalo level 2 with bilinear finishing scheme by N. Robidoux based * on code by N. Robidoux, A. Turcotte and J. Cupitt, 27/1/2010 * * Nohalo level 1 with LBB finishing scheme by N. Robidoux and * C. Racette, 11-18/5/2010 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* * 2009-2010 (c) Nicolas Robidoux, Chantal Racette, John Cupitt and * Adam Turcotte * * N. Robidoux thanks Geert Jordaens, Ralf Meyer, Øyvind Kolås, * Minglun Gong, Eric Daoust and Sven Neumann for useful comments and * code. * * N. Robidoux's early research on Nohalo funded in part by an NSERC * (National Science and Engineering Research Council of Canada) * Discovery Grant awarded to him (298424--2004). * * C. Racette's image resampling research and programming funded in * part by an NSERC (National Science and Engineering Research Council * of Canada) Alexander Graham Bell Canada Graduate Scholarship, by an * NSERC Discovery Grant awarded to Julien Dompierre (grant number * 20-61098) and by N. Robidoux's Laurentian University professional * allowance. * * A. Turcotte's image resampling research on reduced halo funded in * part by an NSERC Alexander Graham Bell Canada Graduate Scholarship * awarded to him and by a Google Summer of Code 2010 award awarded to * GIMP (Gnu Image Manipulation Program). * * Nohalo with LBB finishing scheme was developed by N. Robidoux and * C. Racette at the Department of Mathematics and Computer Science of * Laurentian University in the course of C. Racette's Masters thesis * in Computational Sciences. Preliminary work on Nohalo and monotone * interpolation was performed by C. Racette and N. Robidoux in the * course of her honours thesis, by N. Robidoux, A. Turcotte and * E. Daoust during Google Summer of Code 2009 (through two awards * made to GIMP to improve GEGL), and, earlier, by N. Robidoux, * A. Turcotte, J. Cupitt, M. Gong and K. Martinez. */ /* * Nohalo with LBB as finishing scheme has two versions, which are * only different in the way LBB is implemented: * * A "soft" version, which shows a little less staircasing and a * little more haloing, and which is a little more expensive to * compute. We recommend this as the default. * * A "sharp" version, which shows a little more staircasing and a * little less haloing, and which is a little cheaper (it uses 6 * less comparisons and 12 less "? :"). * * The only difference between the two is that the "soft" versions * uses local minima and maxima computed over 3x3 square blocks, and * the "sharp" version uses local minima and maxima computed over 3x3 * crosses. * * The "sharp" version is (a little) faster. We don't know yet for * sure, but it appears that the "soft" version gives marginally * better results. * * If you want to use the "sharp" (cheaper) version, uncomment the * following three pre-processor code lines: */ /* #ifndef __NOHALO_CHEAP_H__ #define __NOHALO_CHEAP_H__ #endif */ /* * ================ * NOHALO RESAMPLER * ================ * * "Nohalo" is a resampler with a mission: smoothly straightening * oblique lines without undesirable side-effects. In particular, * without much blurring and with no added haloing. * * In this code, one Nohalo subdivision is performed. The * interpolation is finished with LBB (Locally Bounded Bicubic). * * Key properties: * * ======================= * Nohalo is interpolatory * ======================= * * That is, Nohalo preserves point values: If asked for the value at * the center of an input pixel, the sampler returns the corresponding * value, unchanged. In addition, because Nohalo is continuous, if * asked for a value at a location "very close" to the center of an * input pixel, then the sampler returns a value "very close" to * it. (Nohalo is not smoothing like, say, B-Spline * pseudo-interpolation.) * * ==================================================================== * Nohalo subdivision is co-monotone (this is why it's called "no-halo") * ==================================================================== * * One consequence of monotonicity is that additional subdivided * values are in the range of the four closest input values, which is * a form of local boundedness. (Note: plain vanilla bilinear and * nearest neighbour are also co-monotone.) LBB is also locally * bounded. Consequently, Nohalo subdivision followed by LBB is * locally bounded. When used as a finishing scheme for Nohalo, the * standard LBB bounds imply that the final interpolated value is in * the range of the nine closest input values. This property is why * there is very little added haloing, even when a finishing scheme * which is not strictly monotone. Another consequence of local * boundedness is that clamping is unnecessary (provided abyss values * are within the range of acceptable values, which is "always" the * case). * * Note: If the abyss policy is an extrapolating one---for example, * linear or bilinear extrapolation---clamping is still unnecessary * UNLESS one attempts to resample outside of the convex hull of the * input pixel positions. Consequence: the "corner" image size * convention does not require clamping when using linear * extrapolation abyss policy when performing image resizing, but the * "center" one does, when upscaling, at locations very close to the * boundary. If computing values at locations outside of the convex * hull of the pixel locations of the input image, nearest neighbour * abyss policy is most likely better anyway, because linear * extrapolation produces "streaks" if positions far outside the * original image boundary are resampled. * * ======================== * Nohalo is a local method * ======================== * * The interpolated pixel value when using Nohalo subdivision followed * by LBB only depends on the 21 (5x5 minus the four corners) closest * input values. * * =============================== * Nohalo is second order accurate * =============================== * * (Except possibly near the boundary: it is easy to make this * property carry over everywhere but this requires a tuned abyss * policy---linear extrapolation, say---or building the boundary * conditions inside the sampler.) Nohalo+LBB is exact on linear * intensity profiles, meaning that if the input pixel values (in the * stencil) are obtained from a function of the form f(x,y) = a + b*x * + c*y (a, b, c constants), then the computed pixel value is exactly * the value of f(x,y) at the asked-for sampling location. The * boundary condition which is emulated by VIPS through the "extend" * extension of the input image---this corresponds to the nearest * neighbour abyss policy---does NOT make this resampler exact on * linears near the boundary. It does, however, guarantee that no * clamping is required even when resampled values are computed at * positions outside of the extent of the input image (when * extrapolation is required). * * =================== * Nohalo is nonlinear * =================== * * Both Nohalo and LBB are nonlinear, consequently their composition * is nonlinear. In particular, resampling a sum of images may not be * the same as summing the resamples. (This occurs even without taking * into account over and underflow issues: images can only take values * within a banded range, and consequently no sampler is truly * linear.) * * ==================== * Weaknesses of Nohalo * ==================== * * In some cases, the initial subdivision computation is wasted: * * If a region is bi-chromatic, the nonlinear component of Nohalo * subdivision is zero in the interior of the region, and consequently * Nohalo subdivision boils down to bilinear. For such images, LBB is * probably a better choice. * * ========================= * Bibliographical reference * ========================= * * For more information about Nohalo (a prototype version with * bilinear finish instead of LBB), see * * CPU, SMP and GPU implementations of Nohalo level 1, a fast * co-convex antialiasing image resampler by Nicolas Robidoux, Minglun * Gong, John Cupitt, Adam Turcotte, and Kirk Martinez, in C3S2E '09: * Proceedings of the 2nd Canadian Conference on Computer Science and * Software Engineering, p. 185--195, ACM, New York, NY, USA, 2009. * http://doi.acm.org/10.1145/1557626.1557657. */ /* Uncomment to enable bounds checking for VIPS_REGION_ADDR(). */ #define DEBUG #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "templates.h" #define VIPS_TYPE_INTERPOLATE_NOHALO \ (vips_interpolate_nohalo_get_type()) #define VIPS_INTERPOLATE_NOHALO(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE_NOHALO, VipsInterpolateNohalo)) #define VIPS_INTERPOLATE_NOHALO_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE_NOHALO, VipsInterpolateNohaloClass)) #define VIPS_IS_INTERPOLATE_NOHALO(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE_NOHALO)) #define VIPS_IS_INTERPOLATE_NOHALO_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE_NOHALO)) #define VIPS_INTERPOLATE_NOHALO_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE_NOHALO, VipsInterpolateNohaloClass)) typedef struct _VipsInterpolateNohalo { VipsInterpolate parent_object; } VipsInterpolateNohalo; typedef struct _VipsInterpolateNohaloClass { VipsInterpolateClass parent_class; } VipsInterpolateNohaloClass; /* * NOHALO_MINMOD is an implementation of the minmod function which * only needs two "conditional moves." * NOHALO_MINMOD(a,b,a_times_a,a_times_b) "returns" * minmod(a,b). The macro parameter ("input") a_times_a is assumed to * contain the square of a; a_times_b, the product of a and b. * * For uncompressed natural images in high bit depth (images for which * the slopes a and b are unlikely to be equal to zero or be equal to * each other), or chips with good branch prediction, the following * version of the minmod function may work well: * * ((a_times_b) >= 0. ? ((a_times_b) < (a_times_a) ? (b) : (a)) : 0.) * * In this version, the forward branch of the second conditional move * is taken when |b|>|a| and when a*b<0. However, the "else" branch is * taken when a=0 (or when a=b), which is why the above version is not * as effective for images with regions with constant pixel values (or * regions with pixel values which vary linearly or bilinearly) since * we apply minmod to pairs of differences. * * The following version is more suitable for images with flat * (constant) colour areas, since a, which is a pixel difference, will * often be 0, in which case both forward branches are likely. This * may be preferable if "branch flag look ahead" does not work so * well. * * ((a_times_b) >=0. ? ((a_times_a) <= (a_times_b) ? (a) : (b)) : 0.) * * This last version appears to be slightly better than the former in * speed tests performed on a recent multicore Intel chip, especially * when enlarging a sharp image by a large factor, hence the choice. */ #define NOHALO_MINMOD(a, b, a_times_a, a_times_b) \ (((a_times_b) >= 0.) ? ((a_times_a) <= (a_times_b) ? (a) : (b)) : 0.) /* * Absolute value and sign macros: */ #define NOHALO_ABS(x) (((x) >= 0.) ? (x) : -(x)) #define NOHALO_SIGN(x) (((x) >= 0.) ? 1. : -1.) /* * MIN and MAX macros set up so that I can put the likely winner in * the first argument (forward branch likely blah blah blah): */ #define NOHALO_MIN(x, y) (((x) <= (y)) ? (x) : (y)) #define NOHALO_MAX(x, y) (((x) >= (y)) ? (x) : (y)) static void inline nohalo_subdivision(const double uno_two, const double uno_thr, const double uno_fou, const double dos_one, const double dos_two, const double dos_thr, const double dos_fou, const double dos_fiv, const double tre_one, const double tre_two, const double tre_thr, const double tre_fou, const double tre_fiv, const double qua_one, const double qua_two, const double qua_thr, const double qua_fou, const double qua_fiv, const double cin_two, const double cin_thr, const double cin_fou, double *restrict uno_one_1, double *restrict uno_two_1, double *restrict uno_thr_1, double *restrict uno_fou_1, double *restrict dos_one_1, double *restrict dos_two_1, double *restrict dos_thr_1, double *restrict dos_fou_1, double *restrict tre_one_1, double *restrict tre_two_1, double *restrict tre_thr_1, double *restrict tre_fou_1, double *restrict qua_one_1, double *restrict qua_two_1, double *restrict qua_thr_1, double *restrict qua_fou_1) { /* * nohalo_subdivision calculates the missing twelve double density * pixel values, and also returns the "already known" four, so that * the sixteen values which make up the stencil of LBB are * available. */ /* * THE STENCIL OF INPUT VALUES: * * Pointer arithmetic is used to implicitly reflect the input * stencil about tre_thr---assumed closer to the sampling location * than other pixels (ties are OK)---in such a way that after * reflection the sampling point is to the bottom right of tre_thr. * * The following code and picture assumes that the stencil reflexion * has already been performed. * * (ix-1,iy-2) (ix,iy-2) (ix+1,iy-2) * =uno_two = uno_thr = uno_fou * * * * (ix-2,iy-1) (ix-1,iy-1) (ix,iy-1) (ix+1,iy-1) (ix+2,iy-1) * = dos_one = dos_two = dos_thr = dos_fou = dos_fiv * * * * (ix-2,iy) (ix-1,iy) (ix,iy) (ix+1,iy) (ix+2,iy) * = tre_one = tre_two = tre_thr = tre_fou = tre_fiv * X * * * (ix-2,iy+1) (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1) (ix+2,iy+1) * = qua_one = qua_two = qua_thr = qua_fou = qua_fiv * * * * (ix-1,iy+2) (ix,iy+2) (ix+1,iy+2) * = cin_two = cin_thr = cin_fou * * * The above input pixel values are the ones needed in order to make * available the following values, needed by LBB: * * uno_one_1 = uno_two_1 = uno_thr_1 = uno_fou_1 = * (ix-1/2,iy-1/2) (ix,iy-1/2) (ix+1/2,iy-1/2) (ix+1,iy-1/2) * * * * * dos_one_1 = dos_two_1 = dos_thr_1 = dos_fou_1 = * (ix-1/2,iy) (ix,iy) (ix+1/2,iy) (ix+1,iy) * * X * * * tre_one_1 = tre_two_1 = tre_thr_1 = tre_fou_1 = * (ix-1/2,iy+1/2) (ix,iy+1/2) (ix+1/2,iy+1/2) (ix+1,iy+1/2) * * * * * qua_one_1 = qua_two_1 = qua_thr_1 = qua_fou_1 = * (ix-1/2,iy+1) (ix,iy+1) (ix+1/2,iy+1) (ix+1,iy+1) * */ /* * Computation of the nonlinear slopes: If two consecutive pixel * value differences have the same sign, the smallest one (in * absolute value) is taken to be the corresponding slope; if the * two consecutive pixel value differences don't have the same sign, * the corresponding slope is set to 0. * * In other words: Apply minmod to consecutive differences. */ /* * Two vertical simple differences: */ const double d_unodos_two = dos_two - uno_two; const double d_dostre_two = tre_two - dos_two; const double d_trequa_two = qua_two - tre_two; const double d_quacin_two = cin_two - qua_two; /* * Thr(ee) vertical differences: */ const double d_unodos_thr = dos_thr - uno_thr; const double d_dostre_thr = tre_thr - dos_thr; const double d_trequa_thr = qua_thr - tre_thr; const double d_quacin_thr = cin_thr - qua_thr; /* * Fou(r) vertical differences: */ const double d_unodos_fou = dos_fou - uno_fou; const double d_dostre_fou = tre_fou - dos_fou; const double d_trequa_fou = qua_fou - tre_fou; const double d_quacin_fou = cin_fou - qua_fou; /* * Dos horizontal differences: */ const double d_dos_onetwo = dos_two - dos_one; const double d_dos_twothr = dos_thr - dos_two; const double d_dos_thrfou = dos_fou - dos_thr; const double d_dos_foufiv = dos_fiv - dos_fou; /* * Tre(s) horizontal differences: */ const double d_tre_onetwo = tre_two - tre_one; const double d_tre_twothr = tre_thr - tre_two; const double d_tre_thrfou = tre_fou - tre_thr; const double d_tre_foufiv = tre_fiv - tre_fou; /* * Qua(ttro) horizontal differences: */ const double d_qua_onetwo = qua_two - qua_one; const double d_qua_twothr = qua_thr - qua_two; const double d_qua_thrfou = qua_fou - qua_thr; const double d_qua_foufiv = qua_fiv - qua_fou; /* * Recyclable vertical products and squares: */ const double d_unodos_times_dostre_two = d_unodos_two * d_dostre_two; const double d_dostre_two_sq = d_dostre_two * d_dostre_two; const double d_dostre_times_trequa_two = d_dostre_two * d_trequa_two; const double d_trequa_times_quacin_two = d_quacin_two * d_trequa_two; const double d_quacin_two_sq = d_quacin_two * d_quacin_two; const double d_unodos_times_dostre_thr = d_unodos_thr * d_dostre_thr; const double d_dostre_thr_sq = d_dostre_thr * d_dostre_thr; const double d_dostre_times_trequa_thr = d_trequa_thr * d_dostre_thr; const double d_trequa_times_quacin_thr = d_trequa_thr * d_quacin_thr; const double d_quacin_thr_sq = d_quacin_thr * d_quacin_thr; const double d_unodos_times_dostre_fou = d_unodos_fou * d_dostre_fou; const double d_dostre_fou_sq = d_dostre_fou * d_dostre_fou; const double d_dostre_times_trequa_fou = d_trequa_fou * d_dostre_fou; const double d_trequa_times_quacin_fou = d_trequa_fou * d_quacin_fou; const double d_quacin_fou_sq = d_quacin_fou * d_quacin_fou; /* * Recyclable horizontal products and squares: */ const double d_dos_onetwo_times_twothr = d_dos_onetwo * d_dos_twothr; const double d_dos_twothr_sq = d_dos_twothr * d_dos_twothr; const double d_dos_twothr_times_thrfou = d_dos_twothr * d_dos_thrfou; const double d_dos_thrfou_times_foufiv = d_dos_thrfou * d_dos_foufiv; const double d_dos_foufiv_sq = d_dos_foufiv * d_dos_foufiv; const double d_tre_onetwo_times_twothr = d_tre_onetwo * d_tre_twothr; const double d_tre_twothr_sq = d_tre_twothr * d_tre_twothr; const double d_tre_twothr_times_thrfou = d_tre_thrfou * d_tre_twothr; const double d_tre_thrfou_times_foufiv = d_tre_thrfou * d_tre_foufiv; const double d_tre_foufiv_sq = d_tre_foufiv * d_tre_foufiv; const double d_qua_onetwo_times_twothr = d_qua_onetwo * d_qua_twothr; const double d_qua_twothr_sq = d_qua_twothr * d_qua_twothr; const double d_qua_twothr_times_thrfou = d_qua_thrfou * d_qua_twothr; const double d_qua_thrfou_times_foufiv = d_qua_thrfou * d_qua_foufiv; const double d_qua_foufiv_sq = d_qua_foufiv * d_qua_foufiv; /* * Minmod slopes and first level pixel values: */ const double dos_thr_y = NOHALO_MINMOD(d_dostre_thr, d_unodos_thr, d_dostre_thr_sq, d_unodos_times_dostre_thr); const double tre_thr_y = NOHALO_MINMOD(d_dostre_thr, d_trequa_thr, d_dostre_thr_sq, d_dostre_times_trequa_thr); const double newval_uno_two = .5 * (dos_thr + tre_thr) + .25 * (dos_thr_y - tre_thr_y); const double qua_thr_y = NOHALO_MINMOD(d_quacin_thr, d_trequa_thr, d_quacin_thr_sq, d_trequa_times_quacin_thr); const double newval_tre_two = .5 * (tre_thr + qua_thr) + .25 * (tre_thr_y - qua_thr_y); const double tre_fou_y = NOHALO_MINMOD(d_dostre_fou, d_trequa_fou, d_dostre_fou_sq, d_dostre_times_trequa_fou); const double qua_fou_y = NOHALO_MINMOD(d_quacin_fou, d_trequa_fou, d_quacin_fou_sq, d_trequa_times_quacin_fou); const double newval_tre_fou = .5 * (tre_fou + qua_fou) + .25 * (tre_fou_y - qua_fou_y); const double dos_fou_y = NOHALO_MINMOD(d_dostre_fou, d_unodos_fou, d_dostre_fou_sq, d_unodos_times_dostre_fou); const double newval_uno_fou = .5 * (dos_fou + tre_fou) + .25 * (dos_fou_y - tre_fou_y); const double tre_two_x = NOHALO_MINMOD(d_tre_twothr, d_tre_onetwo, d_tre_twothr_sq, d_tre_onetwo_times_twothr); const double tre_thr_x = NOHALO_MINMOD(d_tre_twothr, d_tre_thrfou, d_tre_twothr_sq, d_tre_twothr_times_thrfou); const double newval_dos_one = .5 * (tre_two + tre_thr) + .25 * (tre_two_x - tre_thr_x); const double tre_fou_x = NOHALO_MINMOD(d_tre_foufiv, d_tre_thrfou, d_tre_foufiv_sq, d_tre_thrfou_times_foufiv); const double tre_thr_x_minus_tre_fou_x = tre_thr_x - tre_fou_x; const double newval_dos_thr = .5 * (tre_thr + tre_fou) + .25 * tre_thr_x_minus_tre_fou_x; const double qua_thr_x = NOHALO_MINMOD(d_qua_twothr, d_qua_thrfou, d_qua_twothr_sq, d_qua_twothr_times_thrfou); const double qua_fou_x = NOHALO_MINMOD(d_qua_foufiv, d_qua_thrfou, d_qua_foufiv_sq, d_qua_thrfou_times_foufiv); const double qua_thr_x_minus_qua_fou_x = qua_thr_x - qua_fou_x; const double newval_qua_thr = .5 * (qua_thr + qua_fou) + .25 * qua_thr_x_minus_qua_fou_x; const double qua_two_x = NOHALO_MINMOD(d_qua_twothr, d_qua_onetwo, d_qua_twothr_sq, d_qua_onetwo_times_twothr); const double newval_qua_one = .5 * (qua_two + qua_thr) + .25 * (qua_two_x - qua_thr_x); const double newval_tre_thr = .125 * (tre_thr_x_minus_tre_fou_x + qua_thr_x_minus_qua_fou_x) + .5 * (newval_tre_two + newval_tre_fou); const double dos_thr_x = NOHALO_MINMOD(d_dos_twothr, d_dos_thrfou, d_dos_twothr_sq, d_dos_twothr_times_thrfou); const double dos_fou_x = NOHALO_MINMOD(d_dos_foufiv, d_dos_thrfou, d_dos_foufiv_sq, d_dos_thrfou_times_foufiv); const double newval_uno_thr = .25 * (dos_fou - tre_thr) + .125 * (dos_fou_y - tre_fou_y + dos_thr_x - dos_fou_x) + .5 * (newval_uno_two + newval_dos_thr); const double tre_two_y = NOHALO_MINMOD(d_dostre_two, d_trequa_two, d_dostre_two_sq, d_dostre_times_trequa_two); const double qua_two_y = NOHALO_MINMOD(d_quacin_two, d_trequa_two, d_quacin_two_sq, d_trequa_times_quacin_two); const double newval_tre_one = .25 * (qua_two - tre_thr) + .125 * (qua_two_x - qua_thr_x + tre_two_y - qua_two_y) + .5 * (newval_dos_one + newval_tre_two); const double dos_two_x = NOHALO_MINMOD(d_dos_twothr, d_dos_onetwo, d_dos_twothr_sq, d_dos_onetwo_times_twothr); const double dos_two_y = NOHALO_MINMOD(d_dostre_two, d_unodos_two, d_dostre_two_sq, d_unodos_times_dostre_two); const double newval_uno_one = .25 * (dos_two + dos_thr + tre_two + tre_thr) + .125 * (dos_two_x - dos_thr_x + tre_two_x - tre_thr_x + dos_two_y + dos_thr_y - tre_two_y - tre_thr_y); /* * Return the sixteen LBB stencil values: */ *uno_one_1 = newval_uno_one; *uno_two_1 = newval_uno_two; *uno_thr_1 = newval_uno_thr; *uno_fou_1 = newval_uno_fou; *dos_one_1 = newval_dos_one; *dos_two_1 = tre_thr; *dos_thr_1 = newval_dos_thr; *dos_fou_1 = tre_fou; *tre_one_1 = newval_tre_one; *tre_two_1 = newval_tre_two; *tre_thr_1 = newval_tre_thr; *tre_fou_1 = newval_tre_fou; *qua_one_1 = newval_qua_one; *qua_two_1 = qua_thr; *qua_thr_1 = newval_qua_thr; *qua_fou_1 = qua_fou; } /* * LBB (Locally Bounded Bicubic) is a high quality nonlinear variant * of Catmull-Rom. Images resampled with LBB have much smaller halos * than images resampled with windowed sincs or other interpolatory * cubic spline filters. Specifically, LBB halos are narrower and the * over/undershoot amplitude is smaller. This is accomplished without * a significant reduction in the smoothness of the result (compared * to Catmull-Rom). * * Another important property is that the resampled values are * contained within the range of nearby input values. Consequently, no * final clamping is needed to stay "in range" (e.g., 0-255 for * standard 8-bit images). * * LBB was developed by N. Robidoux and C. Racette of the Department * of Mathematics and Computer Science of Laurentian University in the * course of C.'s Masters Thesis in Computational Sciences. */ /* * LBB is a novel method with the following properties: * * --LBB is a Hermite bicubic method: The bicubic surface is defined, * one convex hull of four nearby input points at a time, using four * point values, four x-derivatives, four y-derivatives, and four * cross-derivatives. * * --The stencil for values in a square patch is the usual 4x4. * * --LBB is interpolatory. * * --It is C^1 with continuous cross derivatives. * * --When the limiters are inactive, LBB gives the same results as * Catmull-Rom. * * --When used on binary images, LBB gives results similar to bicubic * Hermite with all first derivatives---but not necessarily the * cross derivatives--at the input pixel locations set to zero. * * --The LBB reconstruction is locally bounded: Over each square * patch, the surface is contained between the minimum and the * maximum values among the 16 nearest input pixel values (those in * the stencil). * * --Consequently, the LBB reconstruction is globally bounded between * the very smallest input pixel value and the very largest input * pixel value. (It is not necessary to clamp results.) * * The LBB method is based on the method of Ken Brodlie, Petros * Mashwama and Sohail Butt for constraining Hermite interpolants * between globally defined planes: * * Visualization of surface data to preserve positivity and other * simple constraints. Computer & Graphics, Vol. 19, Number 4, pages * 585-594, 1995. DOI: 10.1016/0097-8493(95)00036-C. * * Instead of forcing the reconstructed surface to lie between two * GLOBALLY defined planes, LBB constrains one patch at a time to lie * between LOCALLY defined planes. This is accomplished by * constraining the derivatives (x, y and cross) at each input pixel * location so that if the constraint was applied everywhere the * surface would fit between the min and max of the values at the 9 * closest pixel locations. Because this is done with each of the four * pixel locations which define the bicubic patch, this forces the * reconstructed surface to lie between the min and max of the values * at the 16 closest values pixel locations. (Each corner defines its * own 3x3 subgroup of the 4x4 stencil. Consequently, the surface is * necessarily above the minimum of the four minima, which happens to * be the minimum over the 4x4. Similarly with the maxima.) * * The above paragraph described the "soft" version of LBB. The * "sharp" version is similar. */ static inline double lbbicubic(const double c00, const double c10, const double c01, const double c11, const double c00dx, const double c10dx, const double c01dx, const double c11dx, const double c00dy, const double c10dy, const double c01dy, const double c11dy, const double c00dxdy, const double c10dxdy, const double c01dxdy, const double c11dxdy, const double uno_one, const double uno_two, const double uno_thr, const double uno_fou, const double dos_one, const double dos_two, const double dos_thr, const double dos_fou, const double tre_one, const double tre_two, const double tre_thr, const double tre_fou, const double qua_one, const double qua_two, const double qua_thr, const double qua_fou) { /* * STENCIL (FOOTPRINT) OF INPUT VALUES: * * The stencil of LBB is the same as for any standard Hermite * bicubic (e.g., Catmull-Rom): * * (ix-1,iy-1) (ix,iy-1) (ix+1,iy-1) (ix+2,iy-1) * = uno_one = uno_two = uno_thr = uno_fou * * (ix-1,iy) (ix,iy) (ix+1,iy) (ix+2,iy) * = dos_one = dos_two = dos_thr = dos_fou * X * (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1) (ix+2,iy+1) * = tre_one = tre_two = tre_thr = tre_fou * * (ix-1,iy+2) (ix,iy+2) (ix+1,iy+2) (ix+2,iy+2) * = qua_one = qua_two = qua_thr = qua_fou * * where ix is the (pseudo-)floor of the requested left-to-right * location ("X"), and iy is the floor of the requested up-to-down * location. */ #if defined(__NOHALO_CHEAP_H__) /* * Computation of the four min and four max over 3x3 input data * sub-crosses of the 4x4 input stencil. * * We exploit the fact that the data comes from the (co-monotone) * method Nohalo so that it is known ahead of time that * * dos_thr is between dos_two and dos_fou * * tre_two is between dos_two and qua_two * * tre_fou is between dos_fou and qua_fou * * qua_thr is between qua_two and qua_fou * * tre_thr is in the convex hull of dos_two, dos_fou, qua_two and qua_fou * * to minimize the number of flags and conditional moves. * * (The "between" are not strict: "a between b and c" means * * "min(b,c) <= a <= max(b,c)".) * * We have, however, succeeded in eliminating one flag computation * (one comparison) and one use of an intermediate result. See the * two commented out lines below. * * Overall, only 20 comparisons and 28 "? :" are needed (to compute * 4 mins and 4 maxes). If you can figure how to do this more * efficiently, let us know. */ const double m1 = (uno_two <= tre_two) ? uno_two : tre_two; const double M1 = (uno_two <= tre_two) ? tre_two : uno_two; const double m2 = (dos_thr <= qua_thr) ? dos_thr : qua_thr; const double M2 = (dos_thr <= qua_thr) ? qua_thr : dos_thr; const double m3 = (dos_two <= dos_fou) ? dos_two : dos_fou; const double M3 = (dos_two <= dos_fou) ? dos_fou : dos_two; const double m4 = (uno_thr <= tre_thr) ? uno_thr : tre_thr; const double M4 = (uno_thr <= tre_thr) ? tre_thr : uno_thr; const double m5 = (dos_two <= qua_two) ? dos_two : qua_two; const double M5 = (dos_two <= qua_two) ? qua_two : dos_two; const double m6 = (tre_one <= tre_thr) ? tre_one : tre_thr; const double M6 = (tre_one <= tre_thr) ? tre_thr : tre_one; const double m7 = (dos_one <= dos_thr) ? dos_one : dos_thr; const double M7 = (dos_one <= dos_thr) ? dos_thr : dos_one; const double m8 = (tre_two <= tre_fou) ? tre_two : tre_fou; const double M8 = (tre_two <= tre_fou) ? tre_fou : tre_two; const double m9 = NOHALO_MIN(m1, dos_two); const double M9 = NOHALO_MAX(M1, dos_two); const double m10 = NOHALO_MIN(m2, tre_thr); const double M10 = NOHALO_MAX(M2, tre_thr); const double min10 = NOHALO_MIN(m3, m4); const double max10 = NOHALO_MAX(M3, M4); const double min01 = NOHALO_MIN(m5, m6); const double max01 = NOHALO_MAX(M5, M6); const double min00 = NOHALO_MIN(m9, m7); const double max00 = NOHALO_MAX(M9, M7); const double min11 = NOHALO_MIN(m10, m8); const double max11 = NOHALO_MAX(M10, M8); #else /* * Computation of the four min and four max over 3x3 input data * sub-blocks of the 4x4 input stencil. * * Surprisingly, we have not succeeded in reducing the number of "? * :" needed by using the fact that the data comes from the * (co-monotone) method Nohalo so that it is known ahead of time * that * * dos_thr is between dos_two and dos_fou * * tre_two is between dos_two and qua_two * * tre_fou is between dos_fou and qua_fou * * qua_thr is between qua_two and qua_fou * * tre_thr is in the convex hull of dos_two, dos_fou, qua_two and qua_fou * * to minimize the number of flags and conditional moves. * * (The "between" are not strict: "a between b and c" means * * "min(b,c) <= a <= max(b,c)".) * * We have, however, succeeded in eliminating one flag computation * (one comparison) and one use of an intermediate result. See the * two commented out lines below. * * Overall, only 27 comparisons are needed (to compute 4 mins and 4 * maxes!). Without the simplification, 28 comparisons would be * used. Either way, the number of "? :" used is 34. If you can * figure how to do this more efficiently, let us know. */ const double m1 = (dos_two <= dos_thr) ? dos_two : dos_thr; const double M1 = (dos_two <= dos_thr) ? dos_thr : dos_two; const double m2 = (tre_two <= tre_thr) ? tre_two : tre_thr; const double M2 = (tre_two <= tre_thr) ? tre_thr : tre_two; const double m4 = (qua_two <= qua_thr) ? qua_two : qua_thr; const double M4 = (qua_two <= qua_thr) ? qua_thr : qua_two; const double m3 = (uno_two <= uno_thr) ? uno_two : uno_thr; const double M3 = (uno_two <= uno_thr) ? uno_thr : uno_two; const double m5 = NOHALO_MIN(m1, m2); const double M5 = NOHALO_MAX(M1, M2); const double m6 = (dos_one <= tre_one) ? dos_one : tre_one; const double M6 = (dos_one <= tre_one) ? tre_one : dos_one; const double m7 = (dos_fou <= tre_fou) ? dos_fou : tre_fou; const double M7 = (dos_fou <= tre_fou) ? tre_fou : dos_fou; const double m13 = (dos_fou <= qua_fou) ? dos_fou : qua_fou; const double M13 = (dos_fou <= qua_fou) ? qua_fou : dos_fou; /* * Because the data comes from Nohalo subdivision, the following two * lines can be replaced by the above, simpler, two lines without * changing the results. * * const double m13 = NOHALO_MIN(m7, qua_fou); * const double M13 = NOHALO_MAX(M7, qua_fou); * * This also allows reordering the comparisons to put space between * the computation of a result and its use. */ const double m9 = NOHALO_MIN(m5, m4); const double M9 = NOHALO_MAX(M5, M4); const double m11 = NOHALO_MIN(m6, qua_one); const double M11 = NOHALO_MAX(M6, qua_one); const double m10 = NOHALO_MIN(m6, uno_one); const double M10 = NOHALO_MAX(M6, uno_one); const double m8 = NOHALO_MIN(m5, m3); const double M8 = NOHALO_MAX(M5, M3); const double m12 = NOHALO_MIN(m7, uno_fou); const double M12 = NOHALO_MAX(M7, uno_fou); const double min11 = NOHALO_MIN(m9, m13); const double max11 = NOHALO_MAX(M9, M13); const double min01 = NOHALO_MIN(m9, m11); const double max01 = NOHALO_MAX(M9, M11); const double min00 = NOHALO_MIN(m8, m10); const double max00 = NOHALO_MAX(M8, M10); const double min10 = NOHALO_MIN(m8, m12); const double max10 = NOHALO_MAX(M8, M12); #endif /* * The remainder of the "per channel" computation involves the * computation of: * * --8 conditional moves, * * --8 signs (in which the sign of zero is unimportant), * * --12 minima of two values, * * --8 maxima of two values, * * --8 absolute values, * * for a grand total of 29 minima, 25 maxima, 8 conditional moves, 8 * signs, and 8 absolute values. If everything is done with * conditional moves, "only" 28+8+8+12+8+8=72 flags are involved * (because initial min and max can be computed with one flag). * * The "per channel" part of the computation also involves 107 * arithmetic operations (54 *, 21 +, 42 -). */ /* * Distances to the local min and max: */ const double u11 = tre_thr - min11; const double v11 = max11 - tre_thr; const double u01 = tre_two - min01; const double v01 = max01 - tre_two; const double u00 = dos_two - min00; const double v00 = max00 - dos_two; const double u10 = dos_thr - min10; const double v10 = max10 - dos_thr; /* * Initial values of the derivatives computed with centered * differences. Factors of 1/2 are left out because they are folded * in later: */ const double dble_dzdx00i = dos_thr - dos_one; const double dble_dzdy11i = qua_thr - dos_thr; const double dble_dzdx10i = dos_fou - dos_two; const double dble_dzdy01i = qua_two - dos_two; const double dble_dzdx01i = tre_thr - tre_one; const double dble_dzdy10i = tre_thr - uno_thr; const double dble_dzdx11i = tre_fou - tre_two; const double dble_dzdy00i = tre_two - uno_two; /* * Signs of the derivatives. The upcoming clamping does not change * them (except if the clamping sends a negative derivative to 0, in * which case the sign does not matter anyway). */ const double sign_dzdx00 = NOHALO_SIGN(dble_dzdx00i); const double sign_dzdx10 = NOHALO_SIGN(dble_dzdx10i); const double sign_dzdx01 = NOHALO_SIGN(dble_dzdx01i); const double sign_dzdx11 = NOHALO_SIGN(dble_dzdx11i); const double sign_dzdy00 = NOHALO_SIGN(dble_dzdy00i); const double sign_dzdy10 = NOHALO_SIGN(dble_dzdy10i); const double sign_dzdy01 = NOHALO_SIGN(dble_dzdy01i); const double sign_dzdy11 = NOHALO_SIGN(dble_dzdy11i); /* * Initial values of the cross-derivatives. Factors of 1/4 are left * out because folded in later: */ const double quad_d2zdxdy00i = uno_one - uno_thr + dble_dzdx01i; const double quad_d2zdxdy10i = uno_two - uno_fou + dble_dzdx11i; const double quad_d2zdxdy01i = qua_thr - qua_one - dble_dzdx00i; const double quad_d2zdxdy11i = qua_fou - qua_two - dble_dzdx10i; /* * Slope limiters. The key multiplier is 3 but we fold a factor of * 2, hence 6: */ const double dble_slopelimit_00 = 6.0 * NOHALO_MIN(u00, v00); const double dble_slopelimit_10 = 6.0 * NOHALO_MIN(u10, v10); const double dble_slopelimit_01 = 6.0 * NOHALO_MIN(u01, v01); const double dble_slopelimit_11 = 6.0 * NOHALO_MIN(u11, v11); /* * Clamped first derivatives: */ const double dble_dzdx00 = (sign_dzdx00 * dble_dzdx00i <= dble_slopelimit_00) ? dble_dzdx00i : sign_dzdx00 * dble_slopelimit_00; const double dble_dzdy00 = (sign_dzdy00 * dble_dzdy00i <= dble_slopelimit_00) ? dble_dzdy00i : sign_dzdy00 * dble_slopelimit_00; const double dble_dzdx10 = (sign_dzdx10 * dble_dzdx10i <= dble_slopelimit_10) ? dble_dzdx10i : sign_dzdx10 * dble_slopelimit_10; const double dble_dzdy10 = (sign_dzdy10 * dble_dzdy10i <= dble_slopelimit_10) ? dble_dzdy10i : sign_dzdy10 * dble_slopelimit_10; const double dble_dzdx01 = (sign_dzdx01 * dble_dzdx01i <= dble_slopelimit_01) ? dble_dzdx01i : sign_dzdx01 * dble_slopelimit_01; const double dble_dzdy01 = (sign_dzdy01 * dble_dzdy01i <= dble_slopelimit_01) ? dble_dzdy01i : sign_dzdy01 * dble_slopelimit_01; const double dble_dzdx11 = (sign_dzdx11 * dble_dzdx11i <= dble_slopelimit_11) ? dble_dzdx11i : sign_dzdx11 * dble_slopelimit_11; const double dble_dzdy11 = (sign_dzdy11 * dble_dzdy11i <= dble_slopelimit_11) ? dble_dzdy11i : sign_dzdy11 * dble_slopelimit_11; /* * Sums and differences of first derivatives: */ const double twelve_sum00 = 6.0 * (dble_dzdx00 + dble_dzdy00); const double twelve_dif00 = 6.0 * (dble_dzdx00 - dble_dzdy00); const double twelve_sum10 = 6.0 * (dble_dzdx10 + dble_dzdy10); const double twelve_dif10 = 6.0 * (dble_dzdx10 - dble_dzdy10); const double twelve_sum01 = 6.0 * (dble_dzdx01 + dble_dzdy01); const double twelve_dif01 = 6.0 * (dble_dzdx01 - dble_dzdy01); const double twelve_sum11 = 6.0 * (dble_dzdx11 + dble_dzdy11); const double twelve_dif11 = 6.0 * (dble_dzdx11 - dble_dzdy11); /* * Absolute values of the sums: */ const double twelve_abs_sum00 = NOHALO_ABS(twelve_sum00); const double twelve_abs_sum10 = NOHALO_ABS(twelve_sum10); const double twelve_abs_sum01 = NOHALO_ABS(twelve_sum01); const double twelve_abs_sum11 = NOHALO_ABS(twelve_sum11); /* * Scaled distances to the min: */ const double u00_times_36 = 36.0 * u00; const double u10_times_36 = 36.0 * u10; const double u01_times_36 = 36.0 * u01; const double u11_times_36 = 36.0 * u11; /* * First cross-derivative limiter: */ const double first_limit00 = twelve_abs_sum00 - u00_times_36; const double first_limit10 = twelve_abs_sum10 - u10_times_36; const double first_limit01 = twelve_abs_sum01 - u01_times_36; const double first_limit11 = twelve_abs_sum11 - u11_times_36; const double quad_d2zdxdy00ii = NOHALO_MAX(quad_d2zdxdy00i, first_limit00); const double quad_d2zdxdy10ii = NOHALO_MAX(quad_d2zdxdy10i, first_limit10); const double quad_d2zdxdy01ii = NOHALO_MAX(quad_d2zdxdy01i, first_limit01); const double quad_d2zdxdy11ii = NOHALO_MAX(quad_d2zdxdy11i, first_limit11); /* * Scaled distances to the max: */ const double v00_times_36 = 36.0 * v00; const double v10_times_36 = 36.0 * v10; const double v01_times_36 = 36.0 * v01; const double v11_times_36 = 36.0 * v11; /* * Second cross-derivative limiter: */ const double second_limit00 = v00_times_36 - twelve_abs_sum00; const double second_limit10 = v10_times_36 - twelve_abs_sum10; const double second_limit01 = v01_times_36 - twelve_abs_sum01; const double second_limit11 = v11_times_36 - twelve_abs_sum11; const double quad_d2zdxdy00iii = NOHALO_MIN(quad_d2zdxdy00ii, second_limit00); const double quad_d2zdxdy10iii = NOHALO_MIN(quad_d2zdxdy10ii, second_limit10); const double quad_d2zdxdy01iii = NOHALO_MIN(quad_d2zdxdy01ii, second_limit01); const double quad_d2zdxdy11iii = NOHALO_MIN(quad_d2zdxdy11ii, second_limit11); /* * Absolute values of the differences: */ const double twelve_abs_dif00 = NOHALO_ABS(twelve_dif00); const double twelve_abs_dif10 = NOHALO_ABS(twelve_dif10); const double twelve_abs_dif01 = NOHALO_ABS(twelve_dif01); const double twelve_abs_dif11 = NOHALO_ABS(twelve_dif11); /* * Third cross-derivative limiter: */ const double third_limit00 = twelve_abs_dif00 - v00_times_36; const double third_limit10 = twelve_abs_dif10 - v10_times_36; const double third_limit01 = twelve_abs_dif01 - v01_times_36; const double third_limit11 = twelve_abs_dif11 - v11_times_36; const double quad_d2zdxdy00iiii = NOHALO_MAX(quad_d2zdxdy00iii, third_limit00); const double quad_d2zdxdy10iiii = NOHALO_MAX(quad_d2zdxdy10iii, third_limit10); const double quad_d2zdxdy01iiii = NOHALO_MAX(quad_d2zdxdy01iii, third_limit01); const double quad_d2zdxdy11iiii = NOHALO_MAX(quad_d2zdxdy11iii, third_limit11); /* * Fourth cross-derivative limiter: */ const double fourth_limit00 = u00_times_36 - twelve_abs_dif00; const double fourth_limit10 = u10_times_36 - twelve_abs_dif10; const double fourth_limit01 = u01_times_36 - twelve_abs_dif01; const double fourth_limit11 = u11_times_36 - twelve_abs_dif11; const double quad_d2zdxdy00 = NOHALO_MIN(quad_d2zdxdy00iiii, fourth_limit00); const double quad_d2zdxdy10 = NOHALO_MIN(quad_d2zdxdy10iiii, fourth_limit10); const double quad_d2zdxdy01 = NOHALO_MIN(quad_d2zdxdy01iiii, fourth_limit01); const double quad_d2zdxdy11 = NOHALO_MIN(quad_d2zdxdy11iiii, fourth_limit11); /* * Part of the result which does not need derivatives: */ const double newval1 = c00 * dos_two + c10 * dos_thr + c01 * tre_two + c11 * tre_thr; /* * Twice the part of the result which only needs first derivatives. */ const double newval2 = c00dx * dble_dzdx00 + c10dx * dble_dzdx10 + c01dx * dble_dzdx01 + c11dx * dble_dzdx11 + c00dy * dble_dzdy00 + c10dy * dble_dzdy10 + c01dy * dble_dzdy01 + c11dy * dble_dzdy11; /* * Four times the part of the result which only uses cross * derivatives: */ const double newval3 = c00dxdy * quad_d2zdxdy00 + c10dxdy * quad_d2zdxdy10 + c01dxdy * quad_d2zdxdy01 + c11dxdy * quad_d2zdxdy11; const double newval = newval1 + .5 * newval2 + .25 * newval3; return newval; } /* * Call Nohalo+LBB with a careful type conversion as a parameter. * * It would be nice to do this with templates somehow---for one thing * this would allow code comments!---but we can't figure a clean way * to do it. */ #define NOHALO_CONVERSION(conversion) \ template \ static void inline nohalo_##conversion(void *restrict pout, \ const void *restrict pin, \ const int bands, \ const int lskip, \ const double x_0, \ const double y_0) \ { \ T *restrict out = (T *) pout; \ \ const T *restrict in = (T *) pin; \ \ const int sign_of_x_0 = 2 * (x_0 >= 0.) - 1; \ const int sign_of_y_0 = 2 * (y_0 >= 0.) - 1; \ \ const int shift_forw_1_pix = sign_of_x_0 * bands; \ const int shift_forw_1_row = sign_of_y_0 * lskip; \ \ const int shift_back_1_pix = -shift_forw_1_pix; \ const int shift_back_1_row = -shift_forw_1_row; \ \ const int shift_back_2_pix = 2 * shift_back_1_pix; \ const int shift_back_2_row = 2 * shift_back_1_row; \ const int shift_forw_2_pix = 2 * shift_forw_1_pix; \ const int shift_forw_2_row = 2 * shift_forw_1_row; \ \ const int uno_two_shift = shift_back_1_pix + shift_back_2_row; \ const int uno_thr_shift = shift_back_2_row; \ const int uno_fou_shift = shift_forw_1_pix + shift_back_2_row; \ \ const int dos_one_shift = shift_back_2_pix + shift_back_1_row; \ const int dos_two_shift = shift_back_1_pix + shift_back_1_row; \ const int dos_thr_shift = shift_back_1_row; \ const int dos_fou_shift = shift_forw_1_pix + shift_back_1_row; \ const int dos_fiv_shift = shift_forw_2_pix + shift_back_1_row; \ \ const int tre_one_shift = shift_back_2_pix; \ const int tre_two_shift = shift_back_1_pix; \ const int tre_thr_shift = 0; \ const int tre_fou_shift = shift_forw_1_pix; \ const int tre_fiv_shift = shift_forw_2_pix; \ \ const int qua_one_shift = shift_back_2_pix + shift_forw_1_row; \ const int qua_two_shift = shift_back_1_pix + shift_forw_1_row; \ const int qua_thr_shift = shift_forw_1_row; \ const int qua_fou_shift = shift_forw_1_pix + shift_forw_1_row; \ const int qua_fiv_shift = shift_forw_2_pix + shift_forw_1_row; \ \ const int cin_two_shift = shift_back_1_pix + shift_forw_2_row; \ const int cin_thr_shift = shift_forw_2_row; \ const int cin_fou_shift = shift_forw_1_pix + shift_forw_2_row; \ \ const double xp1over2 = (2 * sign_of_x_0) * x_0; \ const double xm1over2 = xp1over2 - 1.0; \ const double onepx = 0.5 + xp1over2; \ const double onemx = 1.5 - xp1over2; \ const double xp1over2sq = xp1over2 * xp1over2; \ \ const double yp1over2 = (2 * sign_of_y_0) * y_0; \ const double ym1over2 = yp1over2 - 1.0; \ const double onepy = 0.5 + yp1over2; \ const double onemy = 1.5 - yp1over2; \ const double yp1over2sq = yp1over2 * yp1over2; \ \ const double xm1over2sq = xm1over2 * xm1over2; \ const double ym1over2sq = ym1over2 * ym1over2; \ \ const double twice1px = onepx + onepx; \ const double twice1py = onepy + onepy; \ const double twice1mx = onemx + onemx; \ const double twice1my = onemy + onemy; \ \ const double xm1over2sq_times_ym1over2sq = xm1over2sq * ym1over2sq; \ const double xp1over2sq_times_ym1over2sq = xp1over2sq * ym1over2sq; \ const double xp1over2sq_times_yp1over2sq = xp1over2sq * yp1over2sq; \ const double xm1over2sq_times_yp1over2sq = xm1over2sq * yp1over2sq; \ \ const double four_times_1px_times_1py = twice1px * twice1py; \ const double four_times_1mx_times_1py = twice1mx * twice1py; \ const double twice_xp1over2_times_1py = xp1over2 * twice1py; \ const double twice_xm1over2_times_1py = xm1over2 * twice1py; \ \ const double twice_xm1over2_times_1my = xm1over2 * twice1my; \ const double twice_xp1over2_times_1my = xp1over2 * twice1my; \ const double four_times_1mx_times_1my = twice1mx * twice1my; \ const double four_times_1px_times_1my = twice1px * twice1my; \ \ const double twice_1px_times_ym1over2 = twice1px * ym1over2; \ const double twice_1mx_times_ym1over2 = twice1mx * ym1over2; \ const double xp1over2_times_ym1over2 = xp1over2 * ym1over2; \ const double xm1over2_times_ym1over2 = xm1over2 * ym1over2; \ \ const double xm1over2_times_yp1over2 = xm1over2 * yp1over2; \ const double xp1over2_times_yp1over2 = xp1over2 * yp1over2; \ const double twice_1mx_times_yp1over2 = twice1mx * yp1over2; \ const double twice_1px_times_yp1over2 = twice1px * yp1over2; \ \ const double c00 = \ four_times_1px_times_1py * xm1over2sq_times_ym1over2sq; \ const double c00dx = \ twice_xp1over2_times_1py * xm1over2sq_times_ym1over2sq; \ const double c00dy = \ twice_1px_times_yp1over2 * xm1over2sq_times_ym1over2sq; \ const double c00dxdy = \ xp1over2_times_yp1over2 * xm1over2sq_times_ym1over2sq; \ \ const double c10 = \ four_times_1mx_times_1py * xp1over2sq_times_ym1over2sq; \ const double c10dx = \ twice_xm1over2_times_1py * xp1over2sq_times_ym1over2sq; \ const double c10dy = \ twice_1mx_times_yp1over2 * xp1over2sq_times_ym1over2sq; \ const double c10dxdy = \ xm1over2_times_yp1over2 * xp1over2sq_times_ym1over2sq; \ \ const double c01 = \ four_times_1px_times_1my * xm1over2sq_times_yp1over2sq; \ const double c01dx = \ twice_xp1over2_times_1my * xm1over2sq_times_yp1over2sq; \ const double c01dy = \ twice_1px_times_ym1over2 * xm1over2sq_times_yp1over2sq; \ const double c01dxdy = \ xp1over2_times_ym1over2 * xm1over2sq_times_yp1over2sq; \ \ const double c11 = \ four_times_1mx_times_1my * xp1over2sq_times_yp1over2sq; \ const double c11dx = \ twice_xm1over2_times_1my * xp1over2sq_times_yp1over2sq; \ const double c11dy = \ twice_1mx_times_ym1over2 * xp1over2sq_times_yp1over2sq; \ const double c11dxdy = \ xm1over2_times_ym1over2 * xp1over2sq_times_yp1over2sq; \ \ int band = bands; \ \ do { \ double uno_one, uno_two, uno_thr, uno_fou; \ double dos_one, dos_two, dos_thr, dos_fou; \ double tre_one, tre_two, tre_thr, tre_fou; \ double qua_one, qua_two, qua_thr, qua_fou; \ \ nohalo_subdivision(in[uno_two_shift], \ in[uno_thr_shift], \ in[uno_fou_shift], \ in[dos_one_shift], \ in[dos_two_shift], \ in[dos_thr_shift], \ in[dos_fou_shift], \ in[dos_fiv_shift], \ in[tre_one_shift], \ in[tre_two_shift], \ in[tre_thr_shift], \ in[tre_fou_shift], \ in[tre_fiv_shift], \ in[qua_one_shift], \ in[qua_two_shift], \ in[qua_thr_shift], \ in[qua_fou_shift], \ in[qua_fiv_shift], \ in[cin_two_shift], \ in[cin_thr_shift], \ in[cin_fou_shift], \ &uno_one, \ &uno_two, \ &uno_thr, \ &uno_fou, \ &dos_one, \ &dos_two, \ &dos_thr, \ &dos_fou, \ &tre_one, \ &tre_two, \ &tre_thr, \ &tre_fou, \ &qua_one, \ &qua_two, \ &qua_thr, \ &qua_fou); \ \ const double double_result = \ lbbicubic(c00, \ c10, \ c01, \ c11, \ c00dx, \ c10dx, \ c01dx, \ c11dx, \ c00dy, \ c10dy, \ c01dy, \ c11dy, \ c00dxdy, \ c10dxdy, \ c01dxdy, \ c11dxdy, \ uno_one, \ uno_two, \ uno_thr, \ uno_fou, \ dos_one, \ dos_two, \ dos_thr, \ dos_fou, \ tre_one, \ tre_two, \ tre_thr, \ tre_fou, \ qua_one, \ qua_two, \ qua_thr, \ qua_fou); \ \ { \ const T result = to_##conversion(double_result); \ in++; \ *out++ = result; \ } \ \ } while (--band); \ } NOHALO_CONVERSION(fptypes) NOHALO_CONVERSION(withsign) NOHALO_CONVERSION(nosign) #define CALL(T, conversion) \ nohalo_##conversion(out, \ p, \ bands, \ lskip, \ relative_x, \ relative_y); /* * We need C linkage: */ extern "C" { G_DEFINE_TYPE(VipsInterpolateNohalo, vips_interpolate_nohalo, VIPS_TYPE_INTERPOLATE); } static void vips_interpolate_nohalo_interpolate(VipsInterpolate *restrict interpolate, void *restrict out, VipsRegion *restrict in, double absolute_x, double absolute_y) { /* absolute_x and absolute_y are always >= 2.0 (see double-check assert * below), so we don't need floor(). * * It's 2 not 0 since we ask for a window_offset of 2 at the bottom. */ const int ix = (int) (absolute_x + 0.5); const int iy = (int) (absolute_y + 0.5); /* * Move the pointer to (the first band of) the top/left pixel of the * 2x2 group of pixel centers which contains the sampling location * in its convex hull: */ const VipsPel *restrict p = VIPS_REGION_ADDR(in, ix, iy); const double relative_x = absolute_x - ix; const double relative_y = absolute_y - iy; /* * VIPS versions of Nicolas's pixel addressing values. */ const int lskip = VIPS_REGION_LSKIP(in) / VIPS_IMAGE_SIZEOF_ELEMENT(in->im); /* * Double the bands for complex images to account for the real and * imaginary parts being computed independently: */ const int actual_bands = in->im->Bands; const int bands = vips_band_format_iscomplex(in->im->BandFmt) ? 2 * actual_bands : actual_bands; g_assert(ix - 2 >= in->valid.left); g_assert(iy - 2 >= in->valid.top); g_assert(ix + 2 <= VIPS_RECT_RIGHT(&in->valid)); g_assert(iy + 2 <= VIPS_RECT_BOTTOM(&in->valid)); /* Confirm that absolute_x and absolute_y are >= 2, see above. */ g_assert(absolute_x >= 2.0); g_assert(absolute_y >= 2.0); switch (in->im->BandFmt) { case VIPS_FORMAT_UCHAR: CALL(unsigned char, nosign); break; case VIPS_FORMAT_CHAR: CALL(signed char, withsign); break; case VIPS_FORMAT_USHORT: CALL(unsigned short, nosign); break; case VIPS_FORMAT_SHORT: CALL(signed short, withsign); break; case VIPS_FORMAT_UINT: CALL(unsigned int, nosign); break; case VIPS_FORMAT_INT: CALL(signed int, withsign); break; /* * Complex images are handled by doubling of bands. */ case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: CALL(float, fptypes); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: CALL(double, fptypes); break; default: g_assert(0); break; } } static void vips_interpolate_nohalo_class_init(VipsInterpolateNohaloClass *klass) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(klass); VipsInterpolateClass *interpolate_class = VIPS_INTERPOLATE_CLASS(klass); object_class->nickname = "nohalo"; object_class->description = _("edge sharpening resampler with halo reduction"); interpolate_class->interpolate = vips_interpolate_nohalo_interpolate; interpolate_class->window_size = 6; interpolate_class->window_offset = 2; } static void vips_interpolate_nohalo_init(VipsInterpolateNohalo *nohalo) { } libvips-8.18.2/libvips/resample/presample.h000066400000000000000000000050461516303661500207160ustar00rootroot00000000000000/* base class for all resample operations */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef VIPS_PRESAMPLE_H #define VIPS_PRESAMPLE_H #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ #define VIPS_TYPE_RESAMPLE (vips_resample_get_type()) #define VIPS_RESAMPLE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_RESAMPLE, VipsResample)) #define VIPS_RESAMPLE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_RESAMPLE, VipsResampleClass)) #define VIPS_IS_RESAMPLE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_RESAMPLE)) #define VIPS_IS_RESAMPLE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_RESAMPLE)) #define VIPS_RESAMPLE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_RESAMPLE, VipsResampleClass)) typedef struct _VipsResample { VipsOperation parent_instance; VipsImage *in; VipsImage *out; } VipsResample; typedef struct _VipsResampleClass { VipsOperationClass parent_class; } VipsResampleClass; GType vips_resample_get_type(void); /* The max size of the vector we use. */ #define MAX_POINT (2000) int vips_reduce_get_points(VipsKernel kernel, double shrink); void vips_reduceh_uchar_hwy(VipsPel *pout, VipsPel *pin, int n, int width, int bands, short *restrict cs[VIPS_TRANSFORM_SCALE + 1], double X, double hshrink); void vips_reducev_uchar_hwy(VipsPel *pout, VipsPel *pin, int n, int ne, int lskip, const short *restrict k); void vips_shrinkh_uchar_hwy(VipsPel *pout, VipsPel *pin, int width, int hshrink, int bands); void vips_shrinkv_add_line_uchar_hwy(VipsPel *pin, int ne, unsigned int *restrict sum); void vips_shrinkv_write_line_uchar_hwy(VipsPel *pout, int ne, int vshrink, unsigned int *restrict sum); #ifdef __cplusplus } #endif /*__cplusplus*/ #endif /*VIPS_PRESAMPLE_H*/ libvips-8.18.2/libvips/resample/quadratic.c000066400000000000000000000216621516303661500207000ustar00rootroot00000000000000/* Resample an image with a quadratic transform. * * Original code from Reimar Lenz, * Adapted by Lars Raffelt for many bands, * VIPSified by JC ... other numeric types, partial output * * 7/11/12 * - rewritten again for vips8 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define DEBUG_GEOMETRY */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "presample.h" typedef struct _VipsQuadratic { VipsResample parent_instance; VipsImage *coeff; VipsInterpolate *interpolate; /* The coeff array argument, made into an in-memory double. */ VipsImage *mat; /* Transform order. */ int order; } VipsQuadratic; typedef VipsResampleClass VipsQuadraticClass; G_DEFINE_TYPE(VipsQuadratic, vips_quadratic, VIPS_TYPE_RESAMPLE); static void vips_quadratic_dispose(GObject *gobject) { VipsQuadratic *quadratic = (VipsQuadratic *) gobject; VIPS_UNREF(quadratic->mat); G_OBJECT_CLASS(vips_quadratic_parent_class)->dispose(gobject); } static int vips_quadratic_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsRegion *ir = (VipsRegion *) vseq; VipsQuadratic *quadratic = (VipsQuadratic *) b; VipsResample *resample = VIPS_RESAMPLE(quadratic); VipsInterpolateMethod interpolate_fn = vips_interpolate_get_method(quadratic->interpolate); /* @in is the enlarged image (borders on, after vips_embed()). Use * @resample->in for the original, not-expanded image. */ const VipsImage *in = (VipsImage *) a; const int ps = VIPS_IMAGE_SIZEOF_PEL(in); double *vec = VIPS_MATRIX(quadratic->mat, 0, 0); int clip_width = resample->in->Xsize; int clip_height = resample->in->Ysize; int xlow = out_region->valid.left; int ylow = out_region->valid.top; int xhigh = VIPS_RECT_RIGHT(&out_region->valid); int yhigh = VIPS_RECT_BOTTOM(&out_region->valid); VipsRect image; image.left = 0; image.top = 0; image.width = in->Xsize; image.height = in->Ysize; if (vips_region_image(ir, &image)) return -1; for (int yo = ylow; yo < yhigh; yo++) { double fxi, fyi; /* input coordinates */ double dx, dy; /* xo derivative of input coord. */ double ddx, ddy; /* 2nd xo derivative of input coord. */ VipsPel *q; fxi = xlow + vec[0]; /* order 0 */ fyi = yo + vec[1]; dx = 1.0; dy = 0.0; ddx = 0.0; ddy = 0.0; switch (quadratic->order) { case 3: fxi += vec[10] * yo * yo + vec[8] * xlow * xlow; fyi += vec[11] * yo * yo + vec[9] * xlow * xlow; dx += vec[8]; ddx = vec[8] * 2.0; dy += vec[9]; ddy = vec[9] * 2.0; case 2: fxi += vec[6] * xlow * yo; fyi += vec[7] * xlow * yo; dx += vec[6] * yo; dy += vec[7] * yo; case 1: fxi += vec[4] * yo + vec[2] * xlow; fyi += vec[5] * yo + vec[3] * xlow; dx += vec[2]; dy += vec[3]; case 0: break; default: g_assert_not_reached(); } q = VIPS_REGION_ADDR(out_region, xlow, yo); for (int xo = xlow; xo < xhigh; xo++) { int xi = fxi; int yi = fyi; /* Clipping! */ if (xi < 0 || yi < 0 || xi >= clip_width || yi >= clip_height) { for (int z = 0; z < ps; z++) q[z] = 0; } else interpolate_fn(quadratic->interpolate, q, ir, fxi, fyi); q += ps; fxi += dx; fyi += dy; if (quadratic->order > 2) { dx += ddx; dy += ddy; } } } return 0; } static int vips_quadratic_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsQuadratic *quadratic = (VipsQuadratic *) object; int window_size; int window_offset; VipsImage *in; VipsImage *t; if (VIPS_OBJECT_CLASS(vips_quadratic_parent_class)->build(object)) return -1; /* We have the whole of the input in memory, so we can generate any * output. */ if (vips_image_pipelinev(resample->out, VIPS_DEMAND_STYLE_ANY, resample->in, NULL)) return -1; in = resample->in; if (vips_check_uncoded(class->nickname, in) || vips_check_noncomplex(class->nickname, in) || vips_check_matrix(class->nickname, quadratic->coeff, &quadratic->mat)) return -1; if (quadratic->mat->Xsize != 2) { vips_error(class->nickname, "%s", _("coefficient matrix must have width 2")); return -1; } switch (quadratic->mat->Ysize) { case 1: quadratic->order = 0; break; case 3: quadratic->order = 1; break; case 4: quadratic->order = 2; break; case 6: quadratic->order = 3; break; default: vips_error(class->nickname, "%s", _("coefficient matrix must have height 1, 3, 4 or 6")); return -1; } #ifdef DEBUG double *vec = VIPS_MATRIX(quadratic->mat, 0, 0); printf("vips_quadratic_build:\n"); printf("\ta = %g, g = %g\n", vec[0], vec[1]); if (quadratic->order > 0) { printf("\t--------\n"); printf("\tb = %g, h = %g\n", vec[2], vec[3]); printf("\tc = %g, i = %g\n", vec[4], vec[5]); } if (quadratic->order > 1) { printf("\t--------\n"); printf("\td = %g, j = %g\n", vec[6], vec[7]); } if (quadratic->order > 2) { printf("\t--------\n"); printf("\te = %g, k = %g\n", vec[8], vec[9]); printf("\tf = %g, l = %g\n", vec[10], vec[11]); } #endif /*DEBUG*/ if (!quadratic->interpolate) quadratic->interpolate = vips_interpolate_new("bilinear"); // FIXME: Invalidates operation cache window_size = vips_interpolate_get_window_size(quadratic->interpolate); window_offset = vips_interpolate_get_window_offset(quadratic->interpolate); /* Enlarge the input image. */ if (vips_embed(in, &t, window_offset, window_offset, in->Xsize + window_size, in->Ysize + window_size, "extend", VIPS_EXTEND_COPY, NULL)) return -1; vips_object_local(object, t); in = t; /* We need random access to our input. */ if (!(t = vips_image_copy_memory(in))) return -1; vips_object_local(object, t); in = t; if (vips_image_generate(resample->out, vips_start_one, vips_quadratic_gen, vips_stop_one, in, quadratic)) return -1; return 0; } static void vips_quadratic_class_init(VipsQuadraticClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VIPS_DEBUG_MSG("vips_quadratic_class_init\n"); gobject_class->dispose = vips_quadratic_dispose; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "quadratic"; vobject_class->description = _("resample an image with a quadratic transform"); vobject_class->build = vips_quadratic_build; VIPS_ARG_IMAGE(class, "coeff", 8, _("Coeff"), _("Coefficient matrix"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsQuadratic, coeff)); VIPS_ARG_INTERPOLATE(class, "interpolate", 9, _("Interpolate"), _("Interpolate values with this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsQuadratic, interpolate)); } static void vips_quadratic_init(VipsQuadratic *quadratic) { } /** * vips_quadratic: (method) * @in: input image * @out: (out): output image * @coeff: horizontal quadratic * @...: `NULL`-terminated list of optional named arguments * * Transform an image with a 0, 1, 2, or 3rd order polynomial. * * The transform we compute: * * ``` * x = x' + a : order 0 image shift only * + b x' + c y' : order 1 + affine transf. * + d x' y' : order 2 + bilinear transf. * + e x' x' + f y' y' : order 3 + quadratic transf. * * y = y' + g * + h y' + i x' * + j y' x' * + k y' y' + l x' x' * ``` * * where: * * ``` * x', y' = coordinates of srcim * x, y = coordinates of dstim * a .. l = coefficients * ``` * * The coefficients are in the input matrix, ordered as: * * ``` * a g * -- * b h * c i * -- * d j * -- * e k * f l * ``` * * The matrix height may be 1, 3, 4, 6 * * ::: tip "Optional arguments" * * @interpolate: [class@Interpolate], use this interpolator (default bilinear) * * ::: seealso * [method@Image.affine]. * * Returns: 0 on success, -1 on error */ int vips_quadratic(VipsImage *in, VipsImage **out, VipsImage *coeff, ...) { va_list ap; int result; va_start(ap, coeff); result = vips_call_split("quadratic", ap, in, out, coeff); va_end(ap); return result; } libvips-8.18.2/libvips/resample/reduce.c000066400000000000000000000146051516303661500201710ustar00rootroot00000000000000/* 2D reduce ... call reduceh and reducev * * 27/1/16 * - from shrink.c * 15/8/16 * - rename xshrink -> hshrink for greater consistency * 9/9/16 * - add @centre option * 6/6/20 kleisauke * - deprecate @centre option, it's now always on * 22/4/22 kleisauke * - add @gap option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "presample.h" /** * VipsKernel: * @VIPS_KERNEL_NEAREST: the nearest pixel to the point * @VIPS_KERNEL_LINEAR: convolve with a triangle filter * @VIPS_KERNEL_CUBIC: convolve with a cubic filter * @VIPS_KERNEL_MITCHELL: convolve with a Mitchell kernel * @VIPS_KERNEL_LANCZOS2: convolve with a two-lobe Lanczos kernel * @VIPS_KERNEL_LANCZOS3: convolve with a three-lobe Lanczos kernel * @VIPS_KERNEL_MKS2013: convolve with Magic Kernel Sharp 2013 * @VIPS_KERNEL_MKS2021: convolve with Magic Kernel Sharp 2021 * * The resampling kernels vips supports. See [method@Image.reduce], for example. */ typedef struct _VipsReduce { VipsResample parent_instance; double hshrink; /* Shrink factors */ double vshrink; double gap; /* Reduce gap */ /* The thing we use to make the kernel. */ VipsKernel kernel; /* Deprecated. */ gboolean centre; } VipsReduce; typedef VipsResampleClass VipsReduceClass; G_DEFINE_TYPE(VipsReduce, vips_reduce, VIPS_TYPE_RESAMPLE); static int vips_reduce_build(VipsObject *object) { VipsResample *resample = VIPS_RESAMPLE(object); VipsReduce *reduce = (VipsReduce *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); if (VIPS_OBJECT_CLASS(vips_reduce_parent_class)->build(object)) return -1; if (vips_reducev(resample->in, &t[0], reduce->vshrink, "kernel", reduce->kernel, "gap", reduce->gap, NULL) || vips_reduceh(t[0], &t[1], reduce->hshrink, "kernel", reduce->kernel, "gap", reduce->gap, NULL) || vips_image_write(t[1], resample->out)) return -1; return 0; } static void vips_reduce_class_init(VipsReduceClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_reduce_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "reduce"; vobject_class->description = _("reduce an image"); vobject_class->build = vips_reduce_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_DOUBLE(class, "hshrink", 8, _("Hshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReduce, hshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_DOUBLE(class, "vshrink", 9, _("Vshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReduce, vshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_ENUM(class, "kernel", 3, _("Kernel"), _("Resampling kernel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsReduce, kernel), VIPS_TYPE_KERNEL, VIPS_KERNEL_LANCZOS3); VIPS_ARG_DOUBLE(class, "gap", 4, _("Gap"), _("Reducing gap"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsReduce, gap), 0.0, 1000000.0, 0.0); /* The old names .. now use h and v everywhere. */ VIPS_ARG_DOUBLE(class, "xshrink", 8, _("Xshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReduce, hshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_DOUBLE(class, "yshrink", 9, _("Yshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReduce, vshrink), 1.0, 1000000.0, 1.0); /* We used to let people pick centre or corner, but it's automatic now. */ VIPS_ARG_BOOL(class, "centre", 7, _("Centre"), _("Use centre sampling convention"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReduce, centre), FALSE); } static void vips_reduce_init(VipsReduce *reduce) { reduce->gap = 0.0; reduce->kernel = VIPS_KERNEL_LANCZOS3; } /** * vips_reduce: (method) * @in: input image * @out: (out): output image * @hshrink: horizontal shrink * @vshrink: vertical shrink * @...: `NULL`-terminated list of optional named arguments * * Reduce @in by a pair of factors with a pair of 1D kernels. * * This will not work well for shrink factors greater than three. * * Set @gap to speed up reducing by having [method@Image.shrink] to shrink * with a box filter first. The bigger @gap, the closer the result * to the fair resampling. The smaller @gap, the faster resizing. * The default value is 0.0 (no optimization). * * This is a very low-level operation: see [method@Image.resize] for a more * convenient way to resize images. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @kernel: [enum@Kernel], kernel to interpolate with * (default: [enum@Vips.Kernel.LANCZOS3]) * * @gap: `gdouble`, reducing gap to use (default: 0.0) * * ::: seealso * [method@Image.shrink], [method@Image.resize], [method@Image.affine]. * * Returns: 0 on success, -1 on error */ int vips_reduce(VipsImage *in, VipsImage **out, double hshrink, double vshrink, ...) { va_list ap; int result; va_start(ap, vshrink); result = vips_call_split("reduce", ap, in, out, hshrink, vshrink); va_end(ap); return result; } libvips-8.18.2/libvips/resample/reduceh.cpp000066400000000000000000000413371516303661500207030ustar00rootroot00000000000000/* horizontal reduce by a float factor with a kernel * * 29/1/16 * - from shrinkh.c * 10/3/16 * - add other kernels * 15/8/16 * - rename xshrink as hshrink for consistency * 9/9/16 * - add @centre option * 6/6/20 kleisauke * - deprecate @centre option, it's now always on * - fix pixel shift * 22/4/22 kleisauke * - add @gap option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" #include "templates.h" typedef struct _VipsReduceh { VipsResample parent_instance; double hshrink; /* Reduce factor */ double gap; /* Reduce gap */ /* The thing we use to make the kernel. */ VipsKernel kernel; /* Number of points in kernel. */ int n_point; /* Horizontal displacement. */ double hoffset; /* The hshrink we do after integer reduction. */ double residual_hshrink; /* Precalculated interpolation matrices. short (used for pel * sizes up to int), and double (for all others). We go to * scale + 1 so we can round-to-nearest safely. */ short *matrixs[VIPS_TRANSFORM_SCALE + 1]; double *matrixf[VIPS_TRANSFORM_SCALE + 1]; /* Deprecated. */ gboolean centre; } VipsReduceh; typedef VipsResampleClass VipsReducehClass; /* We need C linkage for this. */ extern "C" { G_DEFINE_TYPE(VipsReduceh, vips_reduceh, VIPS_TYPE_RESAMPLE); } /* Get n points. @shrink is the shrink factor, so 2 for a 50% reduction. */ int vips_reduce_get_points(VipsKernel kernel, double shrink) { switch (kernel) { case VIPS_KERNEL_NEAREST: return 1; case VIPS_KERNEL_LINEAR: return 2 * rint(shrink) + 1; case VIPS_KERNEL_CUBIC: case VIPS_KERNEL_MITCHELL: return 2 * rint(2 * shrink) + 1; case VIPS_KERNEL_LANCZOS2: return 2 * rint(2 * shrink) + 1; case VIPS_KERNEL_LANCZOS3: return 2 * rint(3 * shrink) + 1; case VIPS_KERNEL_MKS2013: return 2 * rint(3 * shrink) + 1; case VIPS_KERNEL_MKS2021: return 2 * rint(5 * shrink) + 1; default: g_assert_not_reached(); return 0; } } template static void inline reduceh_unsigned_int_tab(VipsReduceh *reduceh, VipsPel *pout, const VipsPel *pin, const int bands, const short *restrict cx) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reduceh->n_point; for (int z = 0; z < bands; z++) { typename LongT::type sum; sum = reduce_sum(in + z, bands, cx, n); sum = unsigned_fixed_round(sum); out[z] = VIPS_CLIP(0, sum, max_value); } } template static void inline reduceh_signed_int_tab(VipsReduceh *reduceh, VipsPel *pout, const VipsPel *pin, const int bands, const short *restrict cx) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reduceh->n_point; for (int z = 0; z < bands; z++) { typename LongT::type sum; sum = reduce_sum(in + z, bands, cx, n); sum = signed_fixed_round(sum); out[z] = VIPS_CLIP(min_value, sum, max_value); } } /* Floating-point version. */ template static void inline reduceh_float_tab(VipsReduceh *reduceh, VipsPel *pout, const VipsPel *pin, const int bands, const double *restrict cx) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reduceh->n_point; for (int z = 0; z < bands; z++) out[z] = reduce_sum(in + z, bands, cx, n); } /* Ultra-high-quality version for double images. */ template static void inline reduceh_notab(VipsReduceh *reduceh, VipsPel *pout, const VipsPel *pin, const int bands, double x) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reduceh->n_point; typename LongT::type cx[MAX_POINT]; vips_reduce_make_mask(cx, reduceh->kernel, reduceh->n_point, reduceh->residual_hshrink, x); for (int z = 0; z < bands; z++) out[z] = reduce_sum(in + z, bands, cx, n); } static int vips_reduceh_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsReduceh *reduceh = (VipsReduceh *) b; const int ps = VIPS_IMAGE_SIZEOF_PEL(in); VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; /* Double bands for complex. */ const int bands = in->Bands * (vips_band_format_iscomplex(in->BandFmt) ? 2 : 1); VipsRect s; #ifdef DEBUG printf("vips_reduceh_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ s.left = r->left * reduceh->residual_hshrink - reduceh->hoffset; s.top = r->top; s.width = r->width * reduceh->residual_hshrink + reduceh->n_point; s.height = r->height; if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_reduceh_gen: work"); for (int y = 0; y < r->height; y++) { VipsPel *p0; VipsPel *q; double X; q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); X = (r->left + 0.5) * reduceh->residual_hshrink - 0.5 - reduceh->hoffset; /* We want p0 to be the start (ie. x == 0) of the input * scanline we are reading from. We can then calculate the p we * need for each pixel with a single mul and avoid calling ADDR * for each pixel. * * We can't get p0 directly with ADDR since it could be outside * valid, so get the leftmost pixel in valid and subtract a * bit. */ p0 = VIPS_REGION_ADDR(ir, ir->valid.left, r->top + y) - ir->valid.left * ps; for (int x = 0; x < r->width; x++) { const int ix = (int) X; VipsPel *p = p0 + ix * ps; const int sx = X * VIPS_TRANSFORM_SCALE * 2; const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1); const int tx = (six + 1) >> 1; const short *cxs = reduceh->matrixs[tx]; const double *cxf = reduceh->matrixf[tx]; switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: reduceh_unsigned_int_tab(reduceh, q, p, bands, cxs); break; case VIPS_FORMAT_CHAR: reduceh_signed_int_tab(reduceh, q, p, bands, cxs); break; case VIPS_FORMAT_USHORT: reduceh_unsigned_int_tab(reduceh, q, p, bands, cxs); break; case VIPS_FORMAT_SHORT: reduceh_signed_int_tab(reduceh, q, p, bands, cxs); break; case VIPS_FORMAT_UINT: reduceh_unsigned_int_tab(reduceh, q, p, bands, cxs); break; case VIPS_FORMAT_INT: reduceh_signed_int_tab(reduceh, q, p, bands, cxs); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: reduceh_float_tab(reduceh, q, p, bands, cxf); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: reduceh_notab(reduceh, q, p, bands, X - ix); break; default: g_assert_not_reached(); break; } X += reduceh->residual_hshrink; q += ps; } } VIPS_GATE_STOP("vips_reduceh_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_reduceh_gen"); return 0; } #ifdef HAVE_HWY static int vips_reduceh_uchar_vector_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsReduceh *reduceh = (VipsReduceh *) b; const int ps = VIPS_IMAGE_SIZEOF_PEL(in); VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; const int bands = in->Bands; VipsRect s; #ifdef DEBUG printf("vips_reduceh_uchar_vector_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ s.left = r->left * reduceh->residual_hshrink - reduceh->hoffset; s.top = r->top; s.width = r->width * reduceh->residual_hshrink + reduceh->n_point; s.height = r->height; if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_reduceh_uchar_vector_gen: work"); for (int y = 0; y < r->height; y++) { VipsPel *p0; VipsPel *q; double X; q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); X = (r->left + 0.5) * reduceh->residual_hshrink - 0.5 - reduceh->hoffset; p0 = VIPS_REGION_ADDR(ir, ir->valid.left, r->top + y) - ir->valid.left * ps; vips_reduceh_uchar_hwy(q, p0, reduceh->n_point, r->width, bands, reduceh->matrixs, X, reduceh->residual_hshrink); } VIPS_GATE_STOP("vips_reduceh_uchar_vector_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_reduceh_uchar_vector_gen"); return 0; } #endif /*HAVE_HWY*/ static int vips_reduceh_build(VipsObject *object) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsReduceh *reduceh = (VipsReduceh *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 3); VipsImage *in; VipsGenerateFn generate; int width; int int_hshrink; double extra_pixels; if (VIPS_OBJECT_CLASS(vips_reduceh_parent_class)->build(object)) return -1; in = resample->in; if (reduceh->hshrink < 1.0) { vips_error(object_class->nickname, "%s", _("reduce factor should be >= 1.0")); return -1; } /* Output size. We need to always round to nearest, so round(), not * rint(). */ width = VIPS_ROUND_UINT( (double) in->Xsize / reduceh->hshrink); /* How many pixels we are inventing in the input, -ve for * discarding. */ extra_pixels = width * reduceh->hshrink - in->Xsize; /* The hshrink we do after integer reduction. */ reduceh->residual_hshrink = reduceh->hshrink; if (reduceh->gap > 0.0 && reduceh->kernel != VIPS_KERNEL_NEAREST) { if (reduceh->gap < 1.0) { vips_error(object_class->nickname, "%s", _("reduce gap should be >= 1.0")); return -1; } /* The int part of our reduce. */ int_hshrink = VIPS_MAX(1, floor((double) in->Xsize / width / reduceh->gap)); if (int_hshrink > 1) { g_info("shrinkh by %d", int_hshrink); if (vips_shrinkh(in, &t[0], int_hshrink, "ceil", TRUE, nullptr)) return -1; in = t[0]; reduceh->residual_hshrink /= int_hshrink; extra_pixels /= int_hshrink; } } if (reduceh->residual_hshrink == 1.0) return vips_image_write(in, resample->out); reduceh->n_point = vips_reduce_get_points(reduceh->kernel, reduceh->residual_hshrink); g_info("reduceh: %d point mask", reduceh->n_point); if (reduceh->n_point > MAX_POINT) { vips_error(object_class->nickname, "%s", _("reduce factor too large")); return -1; } /* If we are rounding down, we are not using some input * pixels. We need to move the origin *inside* the input image * by half that distance so that we discard pixels equally * from left and right. */ reduceh->hoffset = (1 + extra_pixels) / 2.0 - 1; /* Build the tables of pre-computed coefficients. */ for (int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++) { reduceh->matrixf[x] = VIPS_ARRAY(object, reduceh->n_point, double); reduceh->matrixs[x] = VIPS_ARRAY(object, reduceh->n_point, short); if (!reduceh->matrixf[x] || !reduceh->matrixs[x]) return -1; vips_reduce_make_mask(reduceh->matrixf[x], reduceh->kernel, reduceh->n_point, reduceh->residual_hshrink, (float) x / VIPS_TRANSFORM_SCALE); for (int i = 0; i < reduceh->n_point; i++) reduceh->matrixs[x][i] = (short) (reduceh->matrixf[x][i] * VIPS_INTERPOLATE_SCALE); #ifdef DEBUG printf("vips_reduceh_build: mask %d\n ", x); for (int i = 0; i < reduceh->n_point; i++) printf("%d ", reduceh->matrixs[x][i]); printf("\n"); #endif /*DEBUG*/ } /* Unpack for processing. */ if (vips_image_decode(in, &t[1])) return -1; in = t[1]; /* Add new pixels around the input so we can interpolate at the edges. */ if (vips_embed(in, &t[2], ceil(reduceh->n_point / 2.0) - 1, 0, in->Xsize + reduceh->n_point, in->Ysize, "extend", VIPS_EXTEND_COPY, nullptr)) return -1; in = t[2]; /* For uchar input, try to make a vector path. */ #ifdef HAVE_HWY if (in->BandFmt == VIPS_FORMAT_UCHAR && (in->Bands == 4 || in->Bands == 3) && vips_vector_isenabled()) { generate = vips_reduceh_uchar_vector_gen; g_info("reduceh: using vector path"); } else #endif /*HAVE_HWY*/ /* Default to the C path. */ generate = vips_reduceh_gen; if (vips_image_pipelinev(resample->out, VIPS_DEMAND_STYLE_FATSTRIP, in, nullptr)) return -1; /* Don't change xres/yres, leave that to the application layer. For * example, vipsthumbnail knows the true reduce factor (including the * fractional part), we just see the integer part here. */ resample->out->Xsize = width; if (resample->out->Xsize <= 0) { vips_error(object_class->nickname, "%s", _("image has shrunk to nothing")); return -1; } #ifdef DEBUG printf("vips_reduceh_build: reducing %d x %d image to %d x %d\n", in->Xsize, in->Ysize, resample->out->Xsize, resample->out->Ysize); #endif /*DEBUG*/ if (vips_image_generate(resample->out, vips_start_one, generate, vips_stop_one, in, reduceh)) return -1; vips_reorder_margin_hint(resample->out, reduceh->n_point); return 0; } static void vips_reduceh_class_init(VipsReducehClass *reduceh_class) { GObjectClass *gobject_class = G_OBJECT_CLASS(reduceh_class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(reduceh_class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(reduceh_class); VIPS_DEBUG_MSG("vips_reduceh_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "reduceh"; vobject_class->description = _("shrink an image horizontally"); vobject_class->build = vips_reduceh_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_DOUBLE(reduceh_class, "hshrink", 3, _("Hshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReduceh, hshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_ENUM(reduceh_class, "kernel", 4, _("Kernel"), _("Resampling kernel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsReduceh, kernel), VIPS_TYPE_KERNEL, VIPS_KERNEL_LANCZOS3); VIPS_ARG_DOUBLE(reduceh_class, "gap", 5, _("Gap"), _("Reducing gap"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsReduceh, gap), 0.0, 1000000.0, 0.0); /* Old name. */ VIPS_ARG_DOUBLE(reduceh_class, "xshrink", 3, _("Xshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReduceh, hshrink), 1.0, 1000000.0, 1.0); /* We used to let people pick centre or corner, but it's automatic now. */ VIPS_ARG_BOOL(reduceh_class, "centre", 7, _("Centre"), _("Use centre sampling convention"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReduceh, centre), FALSE); } static void vips_reduceh_init(VipsReduceh *reduceh) { reduceh->gap = 0.0; reduceh->kernel = VIPS_KERNEL_LANCZOS3; } /** * vips_reduceh: (method) * @in: input image * @out: (out): output image * @hshrink: horizontal reduce * @...: `NULL`-terminated list of optional named arguments * * Reduce @in horizontally by a float factor. * * The pixels in @out are * interpolated with a 1D mask generated by @kernel. * * Set @gap to speed up reducing by having [method@Image.shrinkh] to shrink * with a box filter first. The bigger @gap, the closer the result * to the fair resampling. The smaller @gap, the faster resizing. * The default value is 0.0 (no optimization). * * This is a very low-level operation: see [method@Image.resize] for a more * convenient way to resize images. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @kernel: [enum@Kernel], kernel to interpolate with * (default: [enum@Vips.Kernel.LANCZOS3]) * * @gap: `gboolean`, reducing gap to use (default: 0.0) * * ::: seealso * [method@Image.shrink], [method@Image.resize], [method@Image.affine]. * * Returns: 0 on success, -1 on error */ int vips_reduceh(VipsImage *in, VipsImage **out, double hshrink, ...) { va_list ap; int result; va_start(ap, hshrink); result = vips_call_split("reduceh", ap, in, out, hshrink); va_end(ap); return result; } libvips-8.18.2/libvips/resample/reduceh_hwy.cpp000066400000000000000000000163061516303661500215700ustar00rootroot00000000000000/* 22/07/23 kleisauke * - from reducev_hwy.cpp * 02/12/23 kleisauke * - prefer use of Dup128VecFromValues */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021100301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" #ifdef HAVE_HWY #undef HWY_TARGET_INCLUDE #define HWY_TARGET_INCLUDE "libvips/resample/reduceh_hwy.cpp" #include #include namespace HWY_NAMESPACE { using namespace hwy::HWY_NAMESPACE; using DI32 = ScalableTag; using DI16 = ScalableTag; using DI8 = ScalableTag; using DU8 = ScalableTag; constexpr DU8 du8; constexpr Rebind du8x32; constexpr DI8 di8; constexpr DI16 di16; constexpr DI32 di32; #if HWY_IS_BIG_ENDIAN #define HWY_ENDIAN_LOHI(lo, hi) hi, lo #else #define HWY_ENDIAN_LOHI(lo, hi) lo, hi #endif HWY_ATTR void vips_reduceh_uchar_hwy(VipsPel *pout, VipsPel *pin, int32_t n, int32_t width, int32_t bands, int16_t *HWY_RESTRICT cs[VIPS_TRANSFORM_SCALE + 1], double X, double hshrink) { #if HWY_TARGET != HWY_SCALAR const auto initial = Set(di32, VIPS_INTERPOLATE_SCALE >> 1); #ifdef HAVE_HWY_1_1_0 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * r0 g0 b0 r1 g1 b1 r2 g2 b2 r3 g3 b3 */ const auto shuf3_lo = Dup128VecFromValues(di8, HWY_ENDIAN_LOHI(0, -1), HWY_ENDIAN_LOHI(3, -1), HWY_ENDIAN_LOHI(1, -1), HWY_ENDIAN_LOHI(4, -1), HWY_ENDIAN_LOHI(2, -1), HWY_ENDIAN_LOHI(5, -1), -1, -1, -1, -1); const auto shuf3_hi = Dup128VecFromValues(di8, HWY_ENDIAN_LOHI(6, -1), HWY_ENDIAN_LOHI(9, -1), HWY_ENDIAN_LOHI(7, -1), HWY_ENDIAN_LOHI(10, -1), HWY_ENDIAN_LOHI(8, -1), HWY_ENDIAN_LOHI(11, -1), -1, -1, -1, -1); /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * r0 g0 b0 a0 r1 g1 b1 a1 r2 g2 b2 a2 r3 g3 b3 a3 */ const auto shuf4_lo = Dup128VecFromValues(di8, HWY_ENDIAN_LOHI(0, -1), HWY_ENDIAN_LOHI(4, -1), HWY_ENDIAN_LOHI(1, -1), HWY_ENDIAN_LOHI(5, -1), HWY_ENDIAN_LOHI(2, -1), HWY_ENDIAN_LOHI(6, -1), HWY_ENDIAN_LOHI(3, -1), HWY_ENDIAN_LOHI(7, -1)); const auto shuf4_hi = Dup128VecFromValues(di8, HWY_ENDIAN_LOHI(8, -1), HWY_ENDIAN_LOHI(12, -1), HWY_ENDIAN_LOHI(9, -1), HWY_ENDIAN_LOHI(13, -1), HWY_ENDIAN_LOHI(10, -1), HWY_ENDIAN_LOHI(14, -1), HWY_ENDIAN_LOHI(11, -1), HWY_ENDIAN_LOHI(15, -1)); const auto shuf_lo = BitCast(di16, bands == 3 ? shuf3_lo : shuf4_lo); const auto shuf_hi = BitCast(di16, bands == 3 ? shuf3_hi : shuf4_hi); #else /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * r0 g0 b0 r1 g1 b1 r2 g2 b2 r3 g3 b3 */ alignas(16) static constexpr int8_t tbl3_lo[16] = { HWY_ENDIAN_LOHI(0, -1), HWY_ENDIAN_LOHI(3, -1), HWY_ENDIAN_LOHI(1, -1), HWY_ENDIAN_LOHI(4, -1), HWY_ENDIAN_LOHI(2, -1), HWY_ENDIAN_LOHI(5, -1), -1, -1, -1, -1 }; alignas(16) static constexpr int8_t tbl3_hi[16] = { HWY_ENDIAN_LOHI(6, -1), HWY_ENDIAN_LOHI(9, -1), HWY_ENDIAN_LOHI(7, -1), HWY_ENDIAN_LOHI(10, -1), HWY_ENDIAN_LOHI(8, -1), HWY_ENDIAN_LOHI(11, -1), -1, -1 -1, -1 }; /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * r0 g0 b0 a0 r1 g1 b1 a1 r2 g2 b2 a2 r3 g3 b3 a3 */ alignas(16) static constexpr int8_t tbl4_lo[16] = { HWY_ENDIAN_LOHI(0, -1), HWY_ENDIAN_LOHI(4, -1), HWY_ENDIAN_LOHI(1, -1), HWY_ENDIAN_LOHI(5, -1), HWY_ENDIAN_LOHI(2, -1), HWY_ENDIAN_LOHI(6, -1), HWY_ENDIAN_LOHI(3, -1), HWY_ENDIAN_LOHI(7, -1) }; alignas(16) static constexpr int8_t tbl4_hi[16] = { HWY_ENDIAN_LOHI(8, -1), HWY_ENDIAN_LOHI(12, -1), HWY_ENDIAN_LOHI(9, -1), HWY_ENDIAN_LOHI(13, -1), HWY_ENDIAN_LOHI(10, -1), HWY_ENDIAN_LOHI(14, -1), HWY_ENDIAN_LOHI(11, -1), HWY_ENDIAN_LOHI(15, -1) }; const auto shuf_lo = BitCast(di16, LoadDup128(di8, bands == 3 ? tbl3_lo : tbl4_lo)); const auto shuf_hi = BitCast(di16, LoadDup128(di8, bands == 3 ? tbl3_hi : tbl4_hi)); #endif for (int32_t x = 0; x < width; ++x) { const int ix = (int) X; const int sx = X * VIPS_TRANSFORM_SCALE * 2; const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1); const int tx = (six + 1) >> 1; const int16_t *k = cs[tx]; auto *HWY_RESTRICT p = (uint8_t *) pin + ix * bands; auto *HWY_RESTRICT q = (uint8_t *) pout + x * bands; #if HWY_ARCH_X86 || HWY_ARCH_WASM || HWY_TARGET == HWY_EMU128 /* Initialize the sum with the addition on x86 and Wasm, * avoids an extra add instruction. Should be safe given * that only one accumulator is used. */ auto sum0 = initial; #else auto sum0 = Zero(di32); #endif auto sum1 = Zero(di32); /* unused on x86 and Wasm */ int32_t i = 0; for (; i + 4 <= n; i += 4) { /* Load four coefficients. */ auto mmk_lo = BitCast(di16, Set(di32, *(int32_t *) &k[i])); auto mmk_hi = BitCast(di16, Set(di32, *(int32_t *) &k[i + 2])); auto source = LoadU(du8, p); p += bands * 4; auto pix = TableLookupBytesOr0(source, shuf_lo); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk_lo, sum0, /* byref */ sum1); pix = TableLookupBytesOr0(source, shuf_hi); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk_hi, sum0, /* byref */ sum1); } for (; i + 2 <= n; i += 2) { /* Load two coefficients at once. */ auto mmk_lo = BitCast(di16, Set(di32, *(int32_t *) &k[i])); auto source = LoadU(du8, p); p += bands * 2; auto pix = TableLookupBytesOr0(source, shuf_lo); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk_lo, sum0, /* byref */ sum1); } for (; i < n; ++i) { auto mmk = Set(di16, k[i]); auto source = LoadU(du8x32, p); p += bands; auto pix = BitCast(di16, PromoteTo(di32, source)); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk, sum0, /* byref */ sum1); } sum0 = RearrangeToOddPlusEven(sum0, sum1); #if !(HWY_ARCH_X86 || HWY_ARCH_WASM || HWY_TARGET == HWY_EMU128) sum0 = Add(sum0, initial); #endif /* The final 32->8 conversion. */ sum0 = ShiftRight(sum0); auto demoted = DemoteTo(du8x32, sum0); StoreU(demoted, du8x32, q); X += hshrink; } #endif } } /*namespace HWY_NAMESPACE*/ #if HWY_ONCE HWY_EXPORT(vips_reduceh_uchar_hwy); void vips_reduceh_uchar_hwy(VipsPel *pout, VipsPel *pin, int n, int width, int bands, short *restrict cs[VIPS_TRANSFORM_SCALE + 1], double X, double hshrink) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_reduceh_uchar_hwy)(pout, pin, n, width, bands, cs, X, hshrink); /* clang-format on */ } #endif /*HWY_ONCE*/ #endif /*HAVE_HWY*/ libvips-8.18.2/libvips/resample/reducev.cpp000066400000000000000000000715441516303661500207240ustar00rootroot00000000000000/* vertical reduce by a float factor with a kernel * * 29/1/16 * - from shrinkv.c * 10/3/16 * - add other kernels * 21/3/16 * - add vector path * 2/4/16 * - better int mask creation ... we now adjust the scale to keep the sum * equal to the target scale * 15/6/16 * - better accuracy with smarter multiplication * 15/8/16 * - rename yshrink as vshrink for consistency * 9/9/16 * - add @centre option * 7/3/17 * - add a seq line cache * 6/6/20 kleisauke * - deprecate @centre option, it's now always on * - fix pixel shift * - speed up the mask construction for uchar/ushort images * 22/4/22 kleisauke * - add @gap option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_PIXELS #define DEBUG_COMPILE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" #include "templates.h" #ifdef HAVE_ORC #include /* We can't run more than this many passes. Larger than this and we * fall back to C. */ #define MAX_PASS (10) /* The number of params we pass for coeffs. Orc limits this rather. */ #define MAX_PARAM (8 /*ORC_MAX_PARAM_VARS*/) /* A pass with a vector. */ typedef struct { int first; /* The index of the first mask coff we use */ int last; /* The index of the last mask coff we use */ int r; /* Set previous result in this var */ int d1; /* The destination var */ int d2; /* Write new temp result here */ int n_param; int n_scanline; /* The code we generate for this section of this mask. */ OrcProgram *program; } Pass; #endif /*HAVE_ORC*/ typedef struct _VipsReducev { VipsResample parent_instance; double vshrink; /* Reduce factor */ double gap; /* Reduce gap */ /* The thing we use to make the kernel. */ VipsKernel kernel; /* Number of points in kernel. */ int n_point; /* Vertical displacement. */ double voffset; /* The vshrink we do after integer reduction. */ double residual_vshrink; /* Precalculated interpolation matrices. short (used for pel * sizes up to int), and double (for all others). We go to * scale + 1 so we can round-to-nearest safely. */ short *matrixs[VIPS_TRANSFORM_SCALE + 1]; double *matrixf[VIPS_TRANSFORM_SCALE + 1]; #ifdef HAVE_ORC /* And another set for orc: we want 2.6 precision. */ int *matrixo[VIPS_TRANSFORM_SCALE + 1]; /* The passes we generate for this mask. */ int n_pass; Pass pass[MAX_PASS]; #endif /*HAVE_ORC*/ /* Deprecated. */ gboolean centre; } VipsReducev; typedef VipsResampleClass VipsReducevClass; /* We need C linkage for this. */ extern "C" { G_DEFINE_TYPE(VipsReducev, vips_reducev, VIPS_TYPE_RESAMPLE); } /* Our VipsReducevSequence value. */ typedef struct { VipsReducev *reducev; VipsRegion *ir; /* Input region */ #ifdef HAVE_ORC /* In vector mode we need a pair of intermediate buffers to keep the * results of each pass in. */ short *t1; short *t2; #endif /*HAVE_ORC*/ } VipsReducevSequence; static int vips_reducev_stop(void *vseq, void *a, void *b) { VipsReducevSequence *seq = (VipsReducevSequence *) vseq; VIPS_UNREF(seq->ir); #ifdef HAVE_ORC VIPS_FREE(seq->t1); VIPS_FREE(seq->t2); #endif /*HAVE_ORC*/ return 0; } static void * vips_reducev_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsReducev *reducev = (VipsReducev *) b; VipsReducevSequence *seq; if (!(seq = VIPS_NEW(out, VipsReducevSequence))) return nullptr; /* Init! */ seq->reducev = reducev; seq->ir = nullptr; #ifdef HAVE_ORC seq->t1 = NULL; seq->t2 = NULL; #endif /*HAVE_ORC*/ /* Attach region. */ seq->ir = vips_region_new(in); #ifdef HAVE_ORC /* Vector mode. */ if (reducev->n_pass) { seq->t1 = VIPS_ARRAY(NULL, VIPS_IMAGE_N_ELEMENTS(in), short); seq->t2 = VIPS_ARRAY(NULL, VIPS_IMAGE_N_ELEMENTS(in), short); if (!seq->t1 || !seq->t2) { vips_reducev_stop(seq, in, reducev); return NULL; } } #endif /*HAVE_ORC*/ return seq; } #ifdef HAVE_ORC static void vips_reducev_finalize(GObject *gobject) { VipsReducev *reducev = (VipsReducev *) gobject; for (int i = 0; i < reducev->n_pass; i++) VIPS_FREEF(orc_program_free, reducev->pass[i].program); reducev->n_pass = 0; G_OBJECT_CLASS(vips_reducev_parent_class)->finalize(gobject); } #define TEMP(N, S) orc_program_add_temporary(p, S, N) #define PARAM(N, S) orc_program_add_parameter(p, S, N) #define SCANLINE(N, S) orc_program_add_source(p, S, N) #define CONST(N, V, S) orc_program_add_constant(p, S, V, N) #define ASM2(OP, A, B) orc_program_append_ds_str(p, OP, A, B) #define ASM3(OP, A, B, C) orc_program_append_str(p, OP, A, B, C) /* Generate code for a section of the mask. first is the index we start * at, we set last to the index of the last one we use before we run * out of intermediates / constants / parameters / sources or mask * coefficients. * * 0 for success, -1 on error. */ static int vips_reducev_compile_section(VipsReducev *reducev, Pass *pass, gboolean first) { OrcProgram *p; OrcCompileResult result; int i; #ifdef DEBUG_COMPILE printf("starting pass %d\n", pass->first); #endif /*DEBUG_COMPILE*/ pass->program = p = orc_program_new(); pass->d1 = orc_program_add_destination(p, 1, "d1"); /* We have two destinations: the final output image (8-bit) and the * intermediate buffer if this is not the final pass (16-bit). */ pass->d2 = orc_program_add_destination(p, 2, "d2"); /* "r" is the array of sums from the previous pass (if any). */ if (!(pass->r = orc_program_add_source(p, 2, "r"))) return -1; /* The value we fetch from the image, the accumulated sum. */ TEMP("value", 2); TEMP("sum", 2); /* Init the sum. If this is the first pass, it's a constant. If this * is a later pass, we have to init the sum from the result * of the previous pass. */ if (first) { CONST("c32", 32, 2); ASM2("loadpw", "sum", "c32"); } else ASM2("loadw", "sum", "r"); for (i = pass->first; i < reducev->n_point; i++) { char source[256]; char coeff[256]; g_snprintf(source, 256, "sl%d", i); SCANLINE(source, 1); pass->n_scanline++; /* This mask coefficient. */ g_snprintf(coeff, 256, "p%d", i); PARAM(coeff, 2); if (++pass->n_param >= MAX_PARAM) return -1; /* Mask coefficients are 2.6 bits fixed point. We need to hold * about -0.5 to 1.0, so -2 to +1.999 is as close as we can * get. * * We need a signed multiply, so the image pixel needs to * become a signed 16-bit value. We know only the bottom 8 bits * of the image and coefficient are interesting, so we can take * the bottom bits of a 16x16->32 multiply. * * We accumulate the signed 16-bit result in sum. Saturated * add. */ ASM2("convubw", "value", source); ASM3("mullw", "value", "value", coeff); ASM3("addssw", "sum", "sum", "value"); /* orc 0.4.24 and earlier hate more than about five lines at * once :( */ if (pass->n_scanline > 4) break; } pass->last = i; /* If this is the end of the mask, we write the 8-bit result to the * image, otherwise write the 16-bit intermediate to our temp buffer. */ if (pass->last >= reducev->n_point - 1) { CONST("c6", 6, 2); ASM3("shrsw", "sum", "sum", "c6"); ASM2("convsuswb", "d1", "sum"); } else ASM2("copyw", "d2", "sum"); /* Some orcs seem to be unstable with many compilers active at once. */ g_mutex_lock(&vips__global_lock); result = orc_program_compile(p); g_mutex_unlock(&vips__global_lock); if (!ORC_COMPILE_RESULT_IS_SUCCESSFUL(result)) return -1; #ifdef DEBUG_COMPILE printf("done coeffs %d to %d\n", pass->first, pass->last); #endif /*DEBUG_COMPILE*/ return 0; } static int vips_reducev_compile(VipsReducev *reducev) { Pass *pass; /* Generate passes until we've used up the whole mask. */ for (int i = 0;;) { /* Allocate space for another pass. */ if (reducev->n_pass == MAX_PASS) return -1; pass = &reducev->pass[reducev->n_pass]; reducev->n_pass += 1; pass->first = i; pass->r = -1; pass->d1 = -1; pass->d2 = -1; pass->n_param = 0; pass->n_scanline = 0; if (vips_reducev_compile_section(reducev, pass, reducev->n_pass == 1)) return -1; i = pass->last + 1; if (i >= reducev->n_point) break; } return 0; } #endif /*HAVE_ORC*/ /* You'd think this would vectorise, but gcc hates mixed types in nested loops * :-( */ template static void inline reducev_unsigned_int_tab(VipsReducev *reducev, VipsPel *pout, const VipsPel *pin, const int ne, const int lskip, const short *restrict cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reducev->n_point; const int l1 = lskip / sizeof(T); for (int z = 0; z < ne; z++) { typename LongT::type sum; sum = reduce_sum(in + z, l1, cy, n); sum = unsigned_fixed_round(sum); out[z] = VIPS_CLIP(0, sum, max_value); } } template static void inline reducev_signed_int_tab(VipsReducev *reducev, VipsPel *pout, const VipsPel *pin, const int ne, const int lskip, const short *restrict cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reducev->n_point; const int l1 = lskip / sizeof(T); for (int z = 0; z < ne; z++) { typename LongT::type sum; sum = reduce_sum(in + z, l1, cy, n); sum = signed_fixed_round(sum); out[z] = VIPS_CLIP(min_value, sum, max_value); } } /* Floating-point version. */ template static void inline reducev_float_tab(VipsReducev *reducev, VipsPel *pout, const VipsPel *pin, const int ne, const int lskip, const double *restrict cy) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reducev->n_point; const int l1 = lskip / sizeof(T); for (int z = 0; z < ne; z++) out[z] = reduce_sum(in + z, l1, cy, n); } /* Ultra-high-quality version for double images. */ template static void inline reducev_notab(VipsReducev *reducev, VipsPel *pout, const VipsPel *pin, const int ne, const int lskip, double y) { T *restrict out = (T *) pout; const T *restrict in = (T *) pin; const int n = reducev->n_point; const int l1 = lskip / sizeof(T); typename LongT::type cy[MAX_POINT]; vips_reduce_make_mask(cy, reducev->kernel, reducev->n_point, reducev->residual_vshrink, y); for (int z = 0; z < ne; z++) out[z] = reduce_sum(in + z, l1, cy, n); } static int vips_reducev_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsReducev *reducev = (VipsReducev *) b; VipsReducevSequence *seq = (VipsReducevSequence *) vseq; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; /* Double bands for complex. */ const int bands = in->Bands * (vips_band_format_iscomplex(in->BandFmt) ? 2 : 1); int ne = r->width * bands; VipsRect s; #ifdef DEBUG printf("vips_reducev_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ s.left = r->left; s.top = r->top * reducev->residual_vshrink - reducev->voffset; s.width = r->width; s.height = r->height * reducev->residual_vshrink + reducev->n_point; if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_reducev_gen: work"); double Y = (r->top + 0.5) * reducev->residual_vshrink - 0.5 - reducev->voffset; for (int y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); const int py = (int) Y; VipsPel *p = VIPS_REGION_ADDR(ir, r->left, py); const int sy = Y * VIPS_TRANSFORM_SCALE * 2; const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1); const int ty = (siy + 1) >> 1; const short *cys = reducev->matrixs[ty]; const double *cyf = reducev->matrixf[ty]; const int lskip = VIPS_REGION_LSKIP(ir); switch (in->BandFmt) { case VIPS_FORMAT_UCHAR: reducev_unsigned_int_tab(reducev, q, p, ne, lskip, cys); break; case VIPS_FORMAT_CHAR: reducev_signed_int_tab(reducev, q, p, ne, lskip, cys); break; case VIPS_FORMAT_USHORT: reducev_unsigned_int_tab(reducev, q, p, ne, lskip, cys); break; case VIPS_FORMAT_SHORT: reducev_signed_int_tab(reducev, q, p, ne, lskip, cys); break; case VIPS_FORMAT_UINT: reducev_unsigned_int_tab(reducev, q, p, ne, lskip, cys); break; case VIPS_FORMAT_INT: reducev_signed_int_tab(reducev, q, p, ne, lskip, cys); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: reducev_float_tab(reducev, q, p, ne, lskip, cyf); break; case VIPS_FORMAT_DPCOMPLEX: case VIPS_FORMAT_DOUBLE: reducev_notab(reducev, q, p, ne, lskip, Y - py); break; default: g_assert_not_reached(); break; } Y += reducev->residual_vshrink; } VIPS_GATE_STOP("vips_reducev_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_reducev_gen"); return 0; } #ifdef HAVE_HWY static int vips_reducev_uchar_vector_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsReducev *reducev = (VipsReducev *) b; VipsReducevSequence *seq = (VipsReducevSequence *) vseq; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; const int bands = in->Bands; int ne = r->width * bands; VipsRect s; #ifdef DEBUG printf("vips_reducev_uchar_vector_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ s.left = r->left; s.top = r->top * reducev->residual_vshrink - reducev->voffset; s.width = r->width; s.height = r->height * reducev->residual_vshrink + reducev->n_point; if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_reducev_uchar_vector_gen: work"); double Y = (r->top + 0.5) * reducev->residual_vshrink - 0.5 - reducev->voffset; for (int y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); const int py = (int) Y; VipsPel *p = VIPS_REGION_ADDR(ir, r->left, py); const int sy = Y * VIPS_TRANSFORM_SCALE * 2; const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1); const int ty = (siy + 1) >> 1; const short *cys = reducev->matrixs[ty]; const int lskip = VIPS_REGION_LSKIP(ir); vips_reducev_uchar_hwy( q, p, reducev->n_point, ne, lskip, cys); Y += reducev->residual_vshrink; } VIPS_GATE_STOP("vips_reducev_uchar_vector_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_reducev_uchar_vector_gen"); return 0; } #elif defined(HAVE_ORC) /* Process uchar images with a vector path. */ static int vips_reducev_vector_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsImage *in = (VipsImage *) a; VipsReducev *reducev = (VipsReducev *) b; VipsReducevSequence *seq = (VipsReducevSequence *) vseq; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; int ne = r->width * in->Bands; OrcExecutor executor[MAX_PASS]; VipsRect s; #ifdef DEBUG_PIXELS printf("vips_reducev_vector_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG_PIXELS*/ s.left = r->left; s.top = r->top * reducev->residual_vshrink - reducev->voffset; s.width = r->width; s.height = r->height * reducev->residual_vshrink + reducev->n_point; if (vips_region_prepare(ir, &s)) return -1; #ifdef DEBUG_PIXELS printf("vips_reducev_vector_gen: preparing %d x %d at %d x %d\n", s.width, s.height, s.left, s.top); #endif /*DEBUG_PIXELS*/ for (int i = 0; i < reducev->n_pass; i++) { orc_executor_set_program(&executor[i], reducev->pass[i].program); orc_executor_set_n(&executor[i], ne); } VIPS_GATE_START("vips_reducev_vector_gen: work"); double Y = (r->top + 0.5) * reducev->residual_vshrink - 0.5 - reducev->voffset; for (int y = 0; y < r->height; y++) { VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y); const int py = (int) Y; const int sy = Y * VIPS_TRANSFORM_SCALE * 2; const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1); const int ty = (siy + 1) >> 1; const int *cyo = reducev->matrixo[ty]; #ifdef DEBUG_PIXELS printf("starting row %d\n", y + r->top); printf("coefficients:\n"); for (int i = 0; i < reducev->n_point; i++) printf("\t%d - %d\n", i, cyo[i]); printf("first column of pixel values:\n"); for (int i = 0; i < reducev->n_point; i++) printf("\t%d - %d\n", i, *VIPS_REGION_ADDR(ir, r->left, py)); #endif /*DEBUG_PIXELS*/ /* We run our n passes to generate this scanline. */ for (int i = 0; i < reducev->n_pass; i++) { Pass *pass = &reducev->pass[i]; for (int j = 0; j < pass->n_scanline; j++) orc_executor_set_array(&executor[i], pass->r + 1 + j, VIPS_REGION_ADDR(ir, r->left, py + j + pass->first)); orc_executor_set_array(&executor[i], pass->r, seq->t1); orc_executor_set_array(&executor[i], pass->d2, seq->t2); for (int j = 0; j < pass->n_param; j++) orc_executor_set_param(&executor[i], ORC_VAR_P1 + j, cyo[j + pass->first]); orc_executor_set_array(&executor[i], pass->d1, q); orc_executor_run(&executor[i]); VIPS_SWAP(signed short *, seq->t1, seq->t2); } #ifdef DEBUG_PIXELS printf("pixel result:\n"); printf("\t%d\n", *q); #endif /*DEBUG_PIXELS*/ Y += reducev->residual_vshrink; } VIPS_GATE_STOP("vips_reducev_vector_gen: work"); VIPS_COUNT_PIXELS(out_region, "vips_reducev_vector_gen"); return 0; } /* Make a fixed-point version of a matrix. Each * out[i] = rint(in[i] * adj_scale), where adj_scale is selected so that * sum(out) = sum(in) * scale. * * Because of the vagaries of rint(), we can't just calc this, we have to * iterate and converge on the best value for adj_scale. */ static void vips_reducev_vector_to_fixed_point(double *in, int *out, int n, int scale) { double fsum; int i; int target; int sum; double high; double low; double guess; fsum = 0.0; for (i = 0; i < n; i++) fsum += in[i]; target = rint(fsum * scale); /* As we rint() each scale element, we can get up to 0.5 error. * Therefore, by the end of the mask, we can be off by up to n/2. Our * high and low guesses are therefore n/2 either side of the obvious * answer. */ high = scale + (n + 1) / 2; low = scale - (n + 1) / 2; do { guess = (high + low) / 2.0; for (i = 0; i < n; i++) out[i] = rint(in[i] * guess); sum = 0; for (i = 0; i < n; i++) sum += out[i]; if (sum == target) break; if (sum < target) low = guess; if (sum > target) high = guess; /* This will typically produce about 5 iterations. */ } while (high - low > 0.01); if (sum != target) { /* Spread the error out thinly over the whole array. For * example, consider the matrix: * * 3 3 9 0 * 1 1 1 * 1 1 1 * 1 1 1 * * being converted with scale = 64 (convi does this). We want * to generate a mix of 7s and 8s. */ int each_error = (target - sum) / n; int extra_error = (target - sum) % n; /* To share the residual error, we add or subtract 1 from the * first abs(extra_error) elements. */ int direction = extra_error > 0 ? 1 : -1; int n_elements = abs(extra_error); for (i = 0; i < n; i++) out[i] += each_error; for (i = 0; i < n_elements; i++) out[i] += direction; } } #endif /*HAVE_HWY*/ static int vips_reducev_build(VipsObject *object) { VipsObjectClass *object_class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsReducev *reducev = (VipsReducev *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 5); VipsImage *in; VipsGenerateFn generate; int height; int int_vshrink; double extra_pixels; if (VIPS_OBJECT_CLASS(vips_reducev_parent_class)->build(object)) return -1; in = resample->in; if (reducev->vshrink < 1.0) { vips_error(object_class->nickname, "%s", _("reduce factor should be >= 1.0")); return -1; } /* Output size. We need to always round to nearest, so round(), not * rint(). */ height = VIPS_ROUND_UINT((double) in->Ysize / reducev->vshrink); /* How many pixels we are inventing in the input, -ve for * discarding. */ extra_pixels = height * reducev->vshrink - in->Ysize; /* The vshrink we do after integer reduction. */ reducev->residual_vshrink = reducev->vshrink; if (reducev->gap > 0.0 && reducev->kernel != VIPS_KERNEL_NEAREST) { if (reducev->gap < 1.0) { vips_error(object_class->nickname, "%s", _("reduce gap should be >= 1.0")); return -1; } /* The int part of our reduce. */ int_vshrink = VIPS_MAX(1, floor((double) in->Ysize / height / reducev->gap)); if (int_vshrink > 1) { g_info("shrinkv by %d", int_vshrink); if (vips_shrinkv(in, &t[0], int_vshrink, "ceil", TRUE, nullptr)) return -1; in = t[0]; extra_pixels /= int_vshrink; reducev->residual_vshrink /= int_vshrink; } } if (reducev->residual_vshrink == 1.0) return vips_image_write(in, resample->out); reducev->n_point = vips_reduce_get_points(reducev->kernel, reducev->residual_vshrink); g_info("reducev: %d point mask", reducev->n_point); if (reducev->n_point > MAX_POINT) { vips_error(object_class->nickname, "%s", _("reduce factor too large")); return -1; } /* If we are rounding down, we are not using some input * pixels. We need to move the origin *inside* the input image * by half that distance so that we discard pixels equally * from left and right. */ reducev->voffset = (1 + extra_pixels) / 2.0 - 1; /* Build the tables of pre-computed coefficients. */ for (int y = 0; y < VIPS_TRANSFORM_SCALE + 1; y++) { reducev->matrixf[y] = VIPS_ARRAY(object, reducev->n_point, double); reducev->matrixs[y] = VIPS_ARRAY(object, reducev->n_point, short); if (!reducev->matrixf[y] || !reducev->matrixs[y]) return -1; vips_reduce_make_mask(reducev->matrixf[y], reducev->kernel, reducev->n_point, reducev->residual_vshrink, (float) y / VIPS_TRANSFORM_SCALE); for (int i = 0; i < reducev->n_point; i++) reducev->matrixs[y][i] = (short) (reducev->matrixf[y][i] * VIPS_INTERPOLATE_SCALE); #ifdef DEBUG printf("vips_reducev_build: mask %d\n ", y); for (int i = 0; i < reducev->n_point; i++) printf("%d ", reducev->matrixs[y][i]); printf("\n"); #endif /*DEBUG*/ } /* Unpack for processing. */ if (vips_image_decode(in, &t[1])) return -1; in = t[1]; /* Add new pixels around the input so we can interpolate at the edges. */ if (vips_embed(in, &t[2], 0, ceil(reducev->n_point / 2.0) - 1, in->Xsize, in->Ysize + reducev->n_point, "extend", VIPS_EXTEND_COPY, nullptr)) return -1; in = t[2]; /* For uchar input, try to make a vector path. */ #ifdef HAVE_HWY if (in->BandFmt == VIPS_FORMAT_UCHAR && vips_vector_isenabled()) { generate = vips_reducev_uchar_vector_gen; g_info("reducev: using vector path"); } else #elif defined(HAVE_ORC) if (in->BandFmt == VIPS_FORMAT_UCHAR && vips_vector_isenabled() && !vips_reducev_compile(reducev)) { generate = vips_reducev_vector_gen; g_info("reducev: using vector path"); /* We need an 2.6 version if we will use the vector path. */ for (int y = 0; y < VIPS_TRANSFORM_SCALE + 1; y++) { reducev->matrixo[y] = VIPS_ARRAY(object, reducev->n_point, int); if (!reducev->matrixo[y]) return -1; vips_reducev_vector_to_fixed_point( reducev->matrixf[y], reducev->matrixo[y], reducev->n_point, 64); } } else #endif /*HAVE_HWY*/ /* Default to the C path. */ generate = vips_reducev_gen; t[3] = vips_image_new(); if (vips_image_pipelinev(t[3], VIPS_DEMAND_STYLE_FATSTRIP, in, nullptr)) return -1; /* Size output. We need to always round to nearest, so round(), not * rint(). * * Don't change xres/yres, leave that to the application layer. For * example, vipsthumbnail knows the true reduce factor (including the * fractional part), we just see the integer part here. */ t[3]->Ysize = height; if (t[3]->Ysize <= 0) { vips_error(object_class->nickname, "%s", _("image has shrunk to nothing")); return -1; } #ifdef DEBUG printf("vips_reducev_build: reducing %d x %d image to %d x %d\n", in->Xsize, in->Ysize, t[3]->Xsize, t[3]->Ysize); #endif /*DEBUG*/ if (vips_image_generate(t[3], vips_reducev_start, generate, vips_reducev_stop, in, reducev)) return -1; in = t[3]; vips_reorder_margin_hint(in, reducev->n_point); /* Large reducev will throw off sequential mode. Suppose thread1 is * generating tile (0, 0), but stalls. thread2 generates tile * (0, 1), 128 lines further down the output. After it has done, * thread1 tries to generate (0, 0), but by then the pixels it needs * have gone from the input image line cache if the reducev is large. * * To fix this, put another seq on the output of reducev. Now we'll * always have the previous XX lines of the shrunk image, and we won't * fetch out of order. */ if (vips_image_is_sequential(in)) { g_info("reducev sequential line cache"); if (vips_sequential(in, &t[4], "tile_height", 10, // "trace", TRUE, nullptr)) return -1; in = t[4]; } if (vips_image_write(in, resample->out)) return -1; return 0; } static void vips_reducev_class_init(VipsReducevClass *reducev_class) { GObjectClass *gobject_class = G_OBJECT_CLASS(reducev_class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(reducev_class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(reducev_class); VIPS_DEBUG_MSG("vips_reducev_class_init\n"); #ifdef HAVE_ORC gobject_class->finalize = vips_reducev_finalize; #endif /*HAVE_ORC*/ gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "reducev"; vobject_class->description = _("shrink an image vertically"); vobject_class->build = vips_reducev_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_DOUBLE(reducev_class, "vshrink", 3, _("Vshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsReducev, vshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_ENUM(reducev_class, "kernel", 4, _("Kernel"), _("Resampling kernel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsReducev, kernel), VIPS_TYPE_KERNEL, VIPS_KERNEL_LANCZOS3); VIPS_ARG_DOUBLE(reducev_class, "gap", 5, _("Gap"), _("Reducing gap"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsReducev, gap), 0.0, 1000000.0, 0.0); /* Old name. */ VIPS_ARG_DOUBLE(reducev_class, "yshrink", 3, _("Yshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReducev, vshrink), 1.0, 1000000.0, 1.0); /* We used to let people pick centre or corner, but it's automatic now. */ VIPS_ARG_BOOL(reducev_class, "centre", 7, _("Centre"), _("Use centre sampling convention"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsReducev, centre), FALSE); } static void vips_reducev_init(VipsReducev *reducev) { reducev->gap = 0.0; reducev->kernel = VIPS_KERNEL_LANCZOS3; } /** * vips_reducev: (method) * @in: input image * @out: (out): output image * @vshrink: vertical reduce * @...: `NULL`-terminated list of optional named arguments * * Reduce @in vertically by a float factor. * * The pixels in @out are * interpolated with a 1D mask generated by @kernel. * * Set @gap to speed up reducing by having [method@Image.shrinkv] to shrink * with a box filter first. The bigger @gap, the closer the result * to the fair resampling. The smaller @gap, the faster resizing. * The default value is 0.0 (no optimization). * * This is a very low-level operation: see [method@Image.resize] for a more * convenient way to resize images. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @kernel: [enum@Kernel], kernel to interpolate with * (default: [enum@Vips.Kernel.LANCZOS3]) * * @gap: `gboolean`, reducing gap to use (default: 0.0) * * ::: seealso * [method@Image.shrink], [method@Image.resize], [method@Image.affine]. * * Returns: 0 on success, -1 on error */ int vips_reducev(VipsImage *in, VipsImage **out, double vshrink, ...) { va_list ap; int result; va_start(ap, vshrink); result = vips_call_split("reducev", ap, in, out, vshrink); va_end(ap); return result; } libvips-8.18.2/libvips/resample/reducev_hwy.cpp000066400000000000000000000171521516303661500216060ustar00rootroot00000000000000/* 19/08/22 kleisauke * - initial implementation * 07/09/22 kleisauke * - implement using ReorderWidenMulAccumulate * 29/11/22 kleisauke * - prefer use of RearrangeToOddPlusEven * 02/10/23 kleisauke * - prefer use of InterleaveWhole{Lower,Upper} on RVV/SVE */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" #ifdef HAVE_HWY #undef HWY_TARGET_INCLUDE #define HWY_TARGET_INCLUDE "libvips/resample/reducev_hwy.cpp" #include #include namespace HWY_NAMESPACE { using namespace hwy::HWY_NAMESPACE; using DI32 = ScalableTag; using DI16 = ScalableTag; using DU8 = ScalableTag; constexpr DU8 du8; #if HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE) constexpr Rebind du8x32; #endif constexpr DI16 di16; constexpr DI32 di32; #if defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) #define InterleaveLower InterleaveWholeLower #define InterleaveUpper InterleaveWholeUpper #endif // Compat for Highway versions < 1.3.0 #ifndef HWY_LANES_CONSTEXPR #define HWY_LANES_CONSTEXPR #endif #if HWY_IS_BIG_ENDIAN #define HWY_ENDIAN_LOHI(lo, hi) hi, lo #else #define HWY_ENDIAN_LOHI(lo, hi) lo, hi #endif HWY_ATTR void vips_reducev_uchar_hwy(VipsPel *pout, VipsPel *pin, int32_t n, int32_t ne, int32_t lskip, const int16_t *HWY_RESTRICT k) { #if HWY_TARGET != HWY_SCALAR const auto l1 = lskip / sizeof(uint8_t); #if !defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) /* Ensure we do not cross 128-bit block boundaries on RVV/SVE. */ const int32_t N = 16; #else HWY_LANES_CONSTEXPR int32_t N = Lanes(du8); #endif const auto zero = Zero(du8); const auto initial = Set(di32, VIPS_INTERPOLATE_SCALE >> 1); /* Main loop: unrolled. */ int32_t x = 0; for (; x + N <= ne; x += N) { auto *HWY_RESTRICT p = (uint8_t *) pin + x; auto *HWY_RESTRICT q = (uint8_t *) pout + x; #if HWY_ARCH_X86 || HWY_ARCH_WASM || HWY_TARGET == HWY_EMU128 /* Initialize the sum with the addition on x86 and Wasm, * avoids an extra add instruction. Should be safe given * that only one accumulator is used. */ auto sum0 = initial; auto sum2 = initial; auto sum4 = initial; auto sum6 = initial; #else auto sum0 = Zero(di32); auto sum2 = Zero(di32); auto sum4 = Zero(di32); auto sum6 = Zero(di32); #endif auto sum1 = Zero(di32); /* unused on x86 and Wasm */ auto sum3 = Zero(di32); /* unused on x86 and Wasm */ auto sum5 = Zero(di32); /* unused on x86 and Wasm */ auto sum7 = Zero(di32); /* unused on x86 and Wasm */ int32_t i = 0; for (; i + 2 <= n; i += 2) { /* Load two coefficients at once. */ auto mmk = BitCast(di16, Set(di32, *(int32_t *) &k[i])); auto top = LoadU(du8, p); /* top line */ p += l1; auto bottom = LoadU(du8, p); /* bottom line */ p += l1; auto source = InterleaveLower(HWY_ENDIAN_LOHI(top, bottom)); auto pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk, sum0, /* byref */ sum1); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum2 = ReorderWidenMulAccumulate(di32, pix, mmk, sum2, /* byref */ sum3); source = InterleaveUpper(du8, HWY_ENDIAN_LOHI(top, bottom)); pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum4 = ReorderWidenMulAccumulate(di32, pix, mmk, sum4, /* byref */ sum5); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum6 = ReorderWidenMulAccumulate(di32, pix, mmk, sum6, /* byref */ sum7); } for (; i < n; ++i) { auto mmk = Set(di16, k[i]); auto top = LoadU(du8, p); p += l1; auto source = InterleaveLower(HWY_ENDIAN_LOHI(top, zero)); auto pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum0 = ReorderWidenMulAccumulate(di32, pix, mmk, sum0, /* byref */ sum1); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum2 = ReorderWidenMulAccumulate(di32, pix, mmk, sum2, /* byref */ sum3); source = InterleaveUpper(du8, HWY_ENDIAN_LOHI(top, zero)); pix = BitCast(di16, InterleaveLower(HWY_ENDIAN_LOHI(source, zero))); sum4 = ReorderWidenMulAccumulate(di32, pix, mmk, sum4, /* byref */ sum5); pix = BitCast(di16, InterleaveUpper(du8, HWY_ENDIAN_LOHI(source, zero))); sum6 = ReorderWidenMulAccumulate(di32, pix, mmk, sum6, /* byref */ sum7); } sum0 = RearrangeToOddPlusEven(sum0, sum1); sum2 = RearrangeToOddPlusEven(sum2, sum3); sum4 = RearrangeToOddPlusEven(sum4, sum5); sum6 = RearrangeToOddPlusEven(sum6, sum7); #if !(HWY_ARCH_X86 || HWY_ARCH_WASM || HWY_TARGET == HWY_EMU128) sum0 = Add(sum0, initial); sum2 = Add(sum2, initial); sum4 = Add(sum4, initial); sum6 = Add(sum6, initial); #endif /* The final 32->8 conversion. */ sum0 = ShiftRight(sum0); sum2 = ShiftRight(sum2); sum4 = ShiftRight(sum4); sum6 = ShiftRight(sum6); #if HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE) /* RVV/SVE defines demotion as writing to the upper or lower half * of each lane, rather than compacting them within a vector. */ auto demoted0 = DemoteTo(du8x32, sum0); auto demoted1 = DemoteTo(du8x32, sum2); auto demoted2 = DemoteTo(du8x32, sum4); auto demoted3 = DemoteTo(du8x32, sum6); StoreU(demoted0, du8x32, q + 0 * N / 4); StoreU(demoted1, du8x32, q + 1 * N / 4); StoreU(demoted2, du8x32, q + 2 * N / 4); StoreU(demoted3, du8x32, q + 3 * N / 4); #else auto demoted0 = ReorderDemote2To(di16, sum0, sum2); auto demoted2 = ReorderDemote2To(di16, sum4, sum6); auto demoted = ReorderDemote2To(du8, demoted0, demoted2); StoreU(demoted, du8, q); #endif } /* `ne` was not a multiple of the vector length `N`; * proceed one by one. */ for (; x < ne; ++x) { auto *HWY_RESTRICT p = (uint8_t *) pin + x; auto *HWY_RESTRICT q = (uint8_t *) pout + x; int32_t sum = VIPS_INTERPOLATE_SCALE >> 1; for (int32_t i = 0; i < n; ++i) { sum += *p * k[i]; p += l1; } *q = VIPS_CLIP(0, sum >> VIPS_INTERPOLATE_SHIFT, UCHAR_MAX); } #endif } #undef InterleaveLower #undef InterleaveUpper } /*namespace HWY_NAMESPACE*/ #if HWY_ONCE HWY_EXPORT(vips_reducev_uchar_hwy); void vips_reducev_uchar_hwy(VipsPel *pout, VipsPel *pin, int n, int ne, int lskip, const short *restrict k) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_reducev_uchar_hwy)(pout, pin, n, ne, lskip, k); /* clang-format on */ } #endif /*HWY_ONCE*/ #endif /*HAVE_HWY*/ libvips-8.18.2/libvips/resample/resample.c000066400000000000000000000101071516303661500205230ustar00rootroot00000000000000/* base class for all resample operations * * properties: * - one in, one out * - not point-to-point * - size can change in any way * - bands, type, format etc. all fixed */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include "presample.h" /** * VipsSize: * @VIPS_SIZE_BOTH: size both up and down * @VIPS_SIZE_UP: only upsize * @VIPS_SIZE_DOWN: only downsize * @VIPS_SIZE_FORCE: force size, that is, break aspect ratio * * Controls whether an operation should upsize, downsize, both up and * downsize, or force a size. * * ::: seealso * [ctor@Image.thumbnail]. */ G_DEFINE_ABSTRACT_TYPE(VipsResample, vips_resample, VIPS_TYPE_OPERATION); static int vips_resample_build(VipsObject *object) { VipsResample *resample = VIPS_RESAMPLE(object); #ifdef DEBUG printf("vips_resample_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ g_object_set(resample, "out", vips_image_new(), NULL); if (VIPS_OBJECT_CLASS(vips_resample_parent_class)->build(object)) return -1; return 0; } static void vips_resample_class_init(VipsResampleClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "resample"; vobject_class->description = _("resample operations"); vobject_class->build = vips_resample_build; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsResample, in)); VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsResample, out)); } static void vips_resample_init(VipsResample *resample) { } /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ void vips_resample_operation_init(void) { extern GType vips_thumbnail_file_get_type(void); extern GType vips_thumbnail_buffer_get_type(void); extern GType vips_thumbnail_image_get_type(void); extern GType vips_thumbnail_source_get_type(void); extern GType vips_mapim_get_type(void); extern GType vips_shrink_get_type(void); extern GType vips_shrinkh_get_type(void); extern GType vips_shrinkv_get_type(void); extern GType vips_reduce_get_type(void); extern GType vips_reduceh_get_type(void); extern GType vips_reducev_get_type(void); extern GType vips_quadratic_get_type(void); extern GType vips_affine_get_type(void); extern GType vips_similarity_get_type(void); extern GType vips_rotate_get_type(void); extern GType vips_resize_get_type(void); vips_thumbnail_file_get_type(); vips_thumbnail_buffer_get_type(); vips_thumbnail_image_get_type(); vips_thumbnail_source_get_type(); vips_mapim_get_type(); vips_shrink_get_type(); vips_shrinkh_get_type(); vips_shrinkv_get_type(); vips_reduceh_get_type(); vips_reducev_get_type(); vips_reduce_get_type(); vips_quadratic_get_type(); vips_affine_get_type(); vips_similarity_get_type(); vips_rotate_get_type(); vips_resize_get_type(); } libvips-8.18.2/libvips/resample/resize.c000066400000000000000000000270221516303661500202200ustar00rootroot00000000000000/* resize an image ... up and down resampling. * * 13/8/14 * - from affine.c * 18/11/14 * - add the fancier algorithm from vipsthumbnail * 11/11/15 * - smarter cache sizing * 29/2/16 * - shrink more affine less, now we have better anti-alias settings * 10/3/16 * - revise again, using new vips_reduce() code * 1/5/16 * - allow >1 on one axis, <1 on the other * - expose @kernel setting * 16/6/16 * - better quality for linear/cubic kernels ... do more shrink and less * reduce * 22/6/16 * - faster and better upsizing * 15/8/16 * - more accurate resizing * 9/9/16 * - add @centre option * 6/3/17 * - moved the cache to shrinkv * 15/10/17 * - make LINEAR and CUBIC adaptive * 25/11/17 * - deprecate --centre ... it's now always on, thanks tback * 3/12/18 [edwjusti] * - disable the centre sampling offset for nearest upscale, since the * affine nearest interpolator is always centre * 7/7/19 [lovell] * - don't let either axis drop below 1px * 12/7/20 * - much better handling of "nearest" * 22/4/22 kleisauke * - add @gap option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include #include "presample.h" typedef struct _VipsResize { VipsResample parent_instance; double scale; double vscale; double gap; VipsKernel kernel; /* Deprecated. */ VipsInterpolate *interpolate; double idx; double idy; gboolean centre; } VipsResize; typedef VipsResampleClass VipsResizeClass; G_DEFINE_TYPE(VipsResize, vips_resize, VIPS_TYPE_RESAMPLE); /* Suggest a VipsInterpolate which corresponds to a VipsKernel. We use * this to pick a thing for affine(). */ static const char * vips_resize_interpolate(VipsKernel kernel) { switch (kernel) { case VIPS_KERNEL_NEAREST: return "nearest"; case VIPS_KERNEL_LINEAR: return "bilinear"; /* Use cubic for everything else. There are other interpolators, like * nohalo, but they don't really correspond well to any kernel. */ default: return "bicubic"; } } static int vips_resize_build(VipsObject *object) { VipsResample *resample = VIPS_RESAMPLE(object); VipsResize *resize = (VipsResize *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 6); VipsImage *in; double hscale; double vscale; int int_hshrink; int int_vshrink; if (VIPS_OBJECT_CLASS(vips_resize_parent_class)->build(object)) return -1; in = resample->in; /* Updated below when we do the int part of our shrink. */ hscale = resize->scale; if (vips_object_argument_isset(object, "vscale")) vscale = resize->vscale; else vscale = resize->scale; /* Unpack for processing. */ if (vips_image_decode(in, &t[0])) return -1; in = t[0]; if (resize->kernel == VIPS_KERNEL_NEAREST) { int target_width; int target_height; /* The int part of our scale. */ if (resize->gap < 1.0) { int_hshrink = floor(1.0 / hscale); int_vshrink = floor(1.0 / vscale); } else { target_width = VIPS_ROUND_UINT(in->Xsize * hscale); target_height = VIPS_ROUND_UINT(in->Ysize * vscale); int_hshrink = floor( (double) in->Xsize / target_width / resize->gap); int_vshrink = floor( (double) in->Ysize / target_height / resize->gap); } int_hshrink = VIPS_MAX(1, int_hshrink); int_vshrink = VIPS_MAX(1, int_vshrink); if (int_vshrink > 1 || int_hshrink > 1) { g_info("subsample by %d, %d", int_hshrink, int_vshrink); if (vips_subsample(in, &t[1], int_hshrink, int_vshrink, NULL)) return -1; in = t[1]; hscale *= int_hshrink; vscale *= int_vshrink; } } /* Don't let either axis drop below 1 px. */ hscale = VIPS_MAX(hscale, 1.0 / in->Xsize); vscale = VIPS_MAX(vscale, 1.0 / in->Ysize); /* Any residual downsizing. */ if (vscale < 1.0) { g_info("residual reducev by %g", vscale); if (vips_reducev(in, &t[2], 1.0 / vscale, "kernel", resize->kernel, "gap", resize->gap, NULL)) return -1; in = t[2]; } if (hscale < 1.0) { g_info("residual reduceh by %g", hscale); if (vips_reduceh(in, &t[3], 1.0 / hscale, "kernel", resize->kernel, "gap", resize->gap, NULL)) return -1; in = t[3]; } /* Any upsizing. */ if (hscale > 1.0 || vscale > 1.0) { const char *nickname = vips_resize_interpolate(resize->kernel); /* Input displacement. For centre sampling, shift by 0.5 down * and right. Except if this is nearest, which is always * centre. */ const double id = resize->kernel == VIPS_KERNEL_NEAREST ? 0.0 : 0.5; VipsInterpolate *interpolate; if (!(interpolate = vips_interpolate_new(nickname))) return -1; vips_object_local(object, interpolate); if (resize->kernel == VIPS_KERNEL_NEAREST && hscale == floor(hscale) && vscale == floor(vscale)) { /* Fast, integral nearest neighbour enlargement */ if (vips_zoom(in, &t[4], floor(hscale), floor(vscale), NULL)) return -1; in = t[4]; } else if (hscale > 1.0 && vscale > 1.0) { g_info("residual scale %g x %g", hscale, vscale); if (vips_affine(in, &t[4], hscale, 0.0, 0.0, vscale, "interpolate", interpolate, "idx", id, "idy", id, "extend", VIPS_EXTEND_COPY, "premultiplied", TRUE, NULL)) return -1; in = t[4]; } else if (hscale > 1.0) { g_info("residual scale %g", hscale); if (vips_affine(in, &t[4], hscale, 0.0, 0.0, 1.0, "interpolate", interpolate, "idx", id, "idy", id, "extend", VIPS_EXTEND_COPY, "premultiplied", TRUE, NULL)) return -1; in = t[4]; } else { g_info("residual scale %g", vscale); if (vips_affine(in, &t[4], 1.0, 0.0, 0.0, vscale, "interpolate", interpolate, "idx", id, "idy", id, "extend", VIPS_EXTEND_COPY, "premultiplied", TRUE, NULL)) return -1; in = t[4]; } } if (vips_image_write(in, resample->out)) return -1; return 0; } static void vips_resize_class_init(VipsResizeClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_resize_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "resize"; vobject_class->description = _("resize an image"); vobject_class->build = vips_resize_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_DOUBLE(class, "scale", 113, _("Scale factor"), _("Scale image by this factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsResize, scale), 0.0, 10000000.0, 0.0); VIPS_ARG_DOUBLE(class, "vscale", 113, _("Vertical scale factor"), _("Vertical scale image by this factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsResize, vscale), 0.0, 10000000.0, 0.0); VIPS_ARG_ENUM(class, "kernel", 3, _("Kernel"), _("Resampling kernel"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsResize, kernel), VIPS_TYPE_KERNEL, VIPS_KERNEL_LANCZOS3); VIPS_ARG_DOUBLE(class, "gap", 4, _("Gap"), _("Reducing gap"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsResize, gap), 0.0, 1000000.0, 2.0); /* We used to let people set the input offset so you could pick centre * or corner interpolation, but it's not clear this was useful. */ VIPS_ARG_DOUBLE(class, "idx", 115, _("Input offset"), _("Horizontal input displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsResize, idx), -10000000.0, 10000000.0, 0.0); VIPS_ARG_DOUBLE(class, "idy", 116, _("Input offset"), _("Vertical input displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsResize, idy), -10000000.0, 10000000.0, 0.0); /* It's a kernel now we use vips_reduce() not vips_affine(). */ VIPS_ARG_INTERPOLATE(class, "interpolate", 2, _("Interpolate"), _("Interpolate pixels with this"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsResize, interpolate)); /* We used to let people pick centre or corner, but it's automatic now. */ VIPS_ARG_BOOL(class, "centre", 7, _("Centre"), _("Use centre sampling convention"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsResize, centre), FALSE); } static void vips_resize_init(VipsResize *resize) { resize->gap = 2.0; resize->kernel = VIPS_KERNEL_LANCZOS3; } /** * vips_resize: (method) * @in: input image * @out: (out): output image * @scale: scale factor * @...: `NULL`-terminated list of optional named arguments * * Resize an image. * * Set @gap to speed up downsizing by having [method@Image.shrink] to shrink * with a box filter first. The bigger @gap, the closer the result * to the fair resampling. The smaller @gap, the faster resizing. * The default value is 2.0 (very close to fair resampling * while still being faster in many cases). * * [method@Image.resize] normally uses [enum@Vips.Kernel.LANCZOS3] for the final * reduce, you can change this with @kernel. Downsizing is done with centre * convention. * * When upsizing (@scale > 1), the operation uses [method@Image.affine] with * a [class@Interpolate] selected depending on @kernel. It will use * [class@Interpolate] "bicubic" for [enum@Vips.Kernel.CUBIC] and above. It * adds a 0.5 pixel displacement to the input pixels to get centre convention * scaling. * * [method@Image.resize] normally maintains the image aspect ratio. If you set * @vscale, that factor is used for the vertical scale and @scale for the * horizontal. * * If either axis would drop below 1px in size, the shrink in that dimension * is limited. This breaks the image aspect ratio, but prevents errors due to * fractional pixel sizes. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * This operation does not premultiply alpha. If your image has an alpha * channel, you should use [method@Image.premultiply] on it first. * * ::: tip "optional arguments" * * @vscale: `gdouble`, vertical scale factor * * @kernel: [enum@Kernel], kernel to reduce with * (default: [enum@Vips.Kernel.LANCZOS3]) * * @gap: `gdouble`, reducing gap to use (default: 2.0) * * ::: seealso * [method@Image.premultiply], [method@Image.shrink], [method@Image.reduce]. * * Returns: 0 on success, -1 on error */ int vips_resize(VipsImage *in, VipsImage **out, double scale, ...) { va_list ap; int result; va_start(ap, scale); result = vips_call_split("resize", ap, in, out, scale); va_end(ap); return result; } libvips-8.18.2/libvips/resample/shrink.c000066400000000000000000000127151516303661500202200ustar00rootroot00000000000000/* shrink with a box filter * * 30/10/15 * - from shrink.c (now renamed as shrink2.c) * - split to h and v shrinks for a large memory saving * - now handles complex * 15/8/16 * - more accurate resize * - rename xshrink -> hshrink for greater consistency * 9/2/17 * - use reduce, not affine, for any residual shrink * - expand cache hint * 22/4/22 kleisauke * - add @ceil option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include "presample.h" typedef struct _VipsShrink { VipsResample parent_instance; double hshrink; /* Shrink factors */ double vshrink; gboolean ceil; /* Round operation */ } VipsShrink; typedef VipsResampleClass VipsShrinkClass; G_DEFINE_TYPE(VipsShrink, vips_shrink, VIPS_TYPE_RESAMPLE); static int vips_shrink_build(VipsObject *object) { VipsResample *resample = VIPS_RESAMPLE(object); VipsShrink *shrink = (VipsShrink *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); int hshrink_int; int vshrink_int; if (VIPS_OBJECT_CLASS(vips_shrink_parent_class)->build(object)) return -1; hshrink_int = (int) shrink->hshrink; vshrink_int = (int) shrink->vshrink; if (hshrink_int != shrink->hshrink || vshrink_int != shrink->vshrink) { /* Shrink by int factors, reduce to final size. */ if (vips_reducev(resample->in, &t[0], shrink->vshrink, "gap", 1.0, NULL) || vips_reduceh(t[0], &t[1], shrink->hshrink, "gap", 1.0, NULL) || vips_image_write(t[1], resample->out)) return -1; } else { if (vips_shrinkv(resample->in, &t[0], shrink->vshrink, "ceil", shrink->ceil, NULL) || vips_shrinkh(t[0], &t[1], shrink->hshrink, "ceil", shrink->ceil, NULL) || vips_image_write(t[1], resample->out)) return -1; } return 0; } static void vips_shrink_class_init(VipsShrinkClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_shrink_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "shrink"; vobject_class->description = _("shrink an image"); vobject_class->build = vips_shrink_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_DOUBLE(class, "vshrink", 9, _("Vshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsShrink, vshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_DOUBLE(class, "hshrink", 8, _("Hshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsShrink, hshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_BOOL(class, "ceil", 10, _("Ceil"), _("Round-up output dimensions"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsShrink, ceil), FALSE); /* The old names .. now use h and v everywhere. */ VIPS_ARG_DOUBLE(class, "xshrink", 8, _("Xshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsShrink, hshrink), 1.0, 1000000.0, 1.0); VIPS_ARG_DOUBLE(class, "yshrink", 9, _("Yshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsShrink, vshrink), 1.0, 1000000.0, 1.0); } static void vips_shrink_init(VipsShrink *shrink) { } /** * vips_shrink: (method) * @in: input image * @out: (out): output image * @hshrink: horizontal shrink * @vshrink: vertical shrink * @...: `NULL`-terminated list of optional named arguments * * Shrink @in by a pair of factors with a simple box filter. * * For non-integer factors, [method@Image.shrink] will first shrink by the * integer part with a box filter, then use [method@Image.reduce] to shrink * by the remaining fractional part. * * This is a very low-level operation: see [method@Image.resize] for a more * convenient way to resize images. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @ceil: `gboolean`, round-up output dimensions * * ::: seealso * [method@Image.resize], [method@Image.reduce]. * * Returns: 0 on success, -1 on error */ int vips_shrink(VipsImage *in, VipsImage **out, double hshrink, double vshrink, ...) { va_list ap; int result; va_start(ap, vshrink); result = vips_call_split("shrink", ap, in, out, hshrink, vshrink); va_end(ap); return result; } libvips-8.18.2/libvips/resample/shrinkh.c000066400000000000000000000302231516303661500203620ustar00rootroot00000000000000/* horizontal shrink by an integer factor * * 30/10/15 * - from shrink.c * 22/1/16 * - reorganise loops, 30% faster, vectorisable * 15/8/16 * - rename xshrink -> hshrink for greater consistency * 6/8/19 * - use a double sum buffer for int32 types * 22/4/22 kleisauke * - add @ceil option * 12/8/23 jcupitt * - improve chunking for small shrinks */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include "presample.h" typedef struct _VipsShrinkh { VipsResample parent_instance; int hshrink; /* Shrink factor */ gboolean ceil; /* Round operation */ } VipsShrinkh; typedef VipsResampleClass VipsShrinkhClass; G_DEFINE_TYPE(VipsShrinkh, vips_shrinkh, VIPS_TYPE_RESAMPLE); /* Fixed-point arithmetic path for uchar images. */ #define UCHAR_SHRINK(BANDS) \ { \ unsigned char *restrict p = (unsigned char *) in; \ unsigned char *restrict q = (unsigned char *) out; \ \ for (x = 0; x < width; x++) { \ for (b = 0; b < BANDS; b++) { \ int sum = amend; \ for (x1 = b; x1 < ne; x1 += BANDS) \ sum += p[x1]; \ q[b] = (sum * multiplier) >> 24; \ } \ p += ne; \ q += BANDS; \ } \ } /* Integer shrink. */ #define ISHRINK(ACC_TYPE, TYPE, BANDS) \ { \ TYPE *restrict p = (TYPE *) in; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ for (b = 0; b < BANDS; b++) { \ ACC_TYPE sum = amend; \ for (x1 = b; x1 < ne; x1 += BANDS) \ sum += p[x1]; \ q[b] = sum / shrink->hshrink; \ } \ p += ne; \ q += BANDS; \ } \ } /* Float shrink. */ #define FSHRINK(TYPE) \ { \ TYPE *restrict p = (TYPE *) in; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < width; x++) { \ for (b = 0; b < bands; b++) { \ double sum = 0.0; \ for (x1 = b; x1 < ne; x1 += bands) \ sum += p[x1]; \ q[b] = sum / shrink->hshrink; \ } \ p += ne; \ q += bands; \ } \ } /* Generate an area of @out_region. @ir is large enough. */ static void vips_shrinkh_gen2(VipsShrinkh *shrink, VipsRegion *out_region, VipsRegion *ir, int left, int top, int width) { VipsResample *resample = VIPS_RESAMPLE(shrink); const int bands = resample->in->Bands * (vips_band_format_iscomplex(resample->in->BandFmt) ? 2 : 1); const int ne = shrink->hshrink * bands; VipsPel *out = VIPS_REGION_ADDR(out_region, left, top); VipsPel *in = VIPS_REGION_ADDR(ir, left * shrink->hshrink, top); int amend = shrink->hshrink / 2; int x; int x1, b; switch (resample->in->BandFmt) { case VIPS_FORMAT_UCHAR: { unsigned int multiplier = (1LL << 32) / ((1 << 8) * shrink->hshrink); /* Generate a special path for 1, 3 and 4 band uchar data. The * compiler will be able to vectorise these. * * Vectorisation doesn't help much for 16, 32-bit or float * data, don't bother with them. */ switch (bands) { case 1: UCHAR_SHRINK(1); break; case 3: UCHAR_SHRINK(3); break; case 4: UCHAR_SHRINK(4); break; default: UCHAR_SHRINK(bands); break; } break; } case VIPS_FORMAT_CHAR: ISHRINK(int, char, bands); break; case VIPS_FORMAT_USHORT: ISHRINK(int, unsigned short, bands); break; case VIPS_FORMAT_SHORT: ISHRINK(int, short, bands); break; case VIPS_FORMAT_UINT: ISHRINK(gint64, unsigned int, bands); break; case VIPS_FORMAT_INT: ISHRINK(gint64, int, bands); break; case VIPS_FORMAT_FLOAT: FSHRINK(float); break; case VIPS_FORMAT_DOUBLE: FSHRINK(double); break; case VIPS_FORMAT_COMPLEX: FSHRINK(float); break; case VIPS_FORMAT_DPCOMPLEX: FSHRINK(double); break; default: g_assert_not_reached(); } } static int vips_shrinkh_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { /* How do we chunk up the image? We don't want to prepare the whole of * the input region corresponding to *r since it could be huge. * * Reading a line at a time could cause a lot of overcomputation, depending * on what's upstream from us. In SMALLTILE, output scanlines could be * quite small. * * Use fatstrip height as a compromise. */ const int dy = vips__fatstrip_height; VipsShrinkh *shrink = (VipsShrinkh *) b; VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; int y, y1; #ifdef DEBUG printf("vips_shrinkh_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ for (y = 0; y < r->height; y += dy) { int chunk_height = VIPS_MIN(dy, r->height - y); VipsRect s; s.left = r->left * shrink->hshrink; s.top = r->top + y; s.width = r->width * shrink->hshrink; s.height = chunk_height; #ifdef DEBUG printf("vips_shrinkh_gen: requesting %d lines from %d\n", s.height, s.top); #endif /*DEBUG*/ if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_shrinkh_gen: work"); for (y1 = 0; y1 < chunk_height; y1++) vips_shrinkh_gen2(shrink, out_region, ir, r->left, r->top + y + y1, r->width); VIPS_GATE_STOP("vips_shrinkh_gen: work"); } VIPS_COUNT_PIXELS(out_region, "vips_shrinkh_gen"); return 0; } #ifdef HAVE_HWY static int vips_shrinkh_uchar_vector_gen(VipsRegion *out_region, void *seq, void *a, void *b, gboolean *stop) { /* How do we chunk up the image? We don't want to prepare the whole of * the input region corresponding to *r since it could be huge. * * Reading a line at a time could cause a lot of overcomputation, depending * on what's upstream from us. In SMALLTILE, output scanlines could be * quite small. * * Use fatstrip height as a compromise. */ const int dy = vips__fatstrip_height; VipsImage *in = (VipsImage *) a; VipsShrinkh *shrink = (VipsShrinkh *) b; VipsRegion *ir = (VipsRegion *) seq; VipsRect *r = &out_region->valid; const int bands = in->Bands; int y, y1; #ifdef DEBUG printf("vips_shrinkh_uchar_vector_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ for (y = 0; y < r->height; y += dy) { int chunk_height = VIPS_MIN(dy, r->height - y); VipsRect s; s.left = r->left * shrink->hshrink; s.top = r->top + y; /* Request one extra input pixel on the right so the Highway path can * safely process a full SIMD vector. */ s.width = (r->width + 1) * shrink->hshrink; s.height = chunk_height; #ifdef DEBUG printf("vips_shrinkh_uchar_vector_gen: requesting %d lines from %d\n", s.height, s.top); #endif /*DEBUG*/ if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_shrinkh_uchar_vector_gen: work"); // each output line for (y1 = 0; y1 < chunk_height; y1++) { // top of this line in the output int top = r->top + y + y1; VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, top); VipsPel *p = VIPS_REGION_ADDR(ir, s.left, top); vips_shrinkh_uchar_hwy(q, p, r->width, shrink->hshrink, bands); } VIPS_GATE_STOP("vips_shrinkh_uchar_vector_gen: work"); } VIPS_COUNT_PIXELS(out_region, "vips_shrinkh_uchar_vector_gen"); return 0; } #endif /*HAVE_HWY*/ static int vips_shrinkh_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsShrinkh *shrink = (VipsShrinkh *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 2); VipsImage *in; VipsGenerateFn generate; if (VIPS_OBJECT_CLASS(vips_shrinkh_parent_class)->build(object)) return -1; in = resample->in; if (shrink->hshrink < 1) { vips_error(class->nickname, "%s", _("shrink factors should be >= 1")); return -1; } if (shrink->hshrink == 1) return vips_image_write(in, resample->out); /* We need new pixels at the right so that we don't have small chunks * to average down the right edge. */ if (vips_embed(in, &t[1], 0, 0, in->Xsize + shrink->hshrink, in->Ysize, "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[1]; /* For uchar input, try to make a vector path. */ #ifdef HAVE_HWY if (in->BandFmt == VIPS_FORMAT_UCHAR && in->Bands <= 4 && vips_vector_isenabled()) { generate = vips_shrinkh_uchar_vector_gen; g_info("shrinkh: using vector path"); } else #endif /*HAVE_HWY*/ /* Default to the C path. */ generate = vips_shrinkh_gen; if (vips_image_pipelinev(resample->out, VIPS_DEMAND_STYLE_THINSTRIP, in, NULL)) return -1; /* Size output. * * Don't change xres/yres, leave that to the application layer. For * example, vipsthumbnail knows the true shrink factor (including the * fractional part), we just see the integer part here. */ resample->out->Xsize = shrink->ceil ? ceil((double) resample->in->Xsize / shrink->hshrink) : VIPS_ROUND_UINT((double) resample->in->Xsize / shrink->hshrink); if (resample->out->Xsize <= 0) { vips_error(class->nickname, "%s", _("image has shrunk to nothing")); return -1; } #ifdef DEBUG printf("vips_shrinkh_build: shrinking %d x %d image to %d x %d\n", in->Xsize, in->Ysize, resample->out->Xsize, resample->out->Ysize); #endif /*DEBUG*/ if (vips_image_generate(resample->out, vips_start_one, generate, vips_stop_one, in, shrink)) return -1; return 0; } static void vips_shrinkh_class_init(VipsShrinkhClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_shrinkh_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "shrinkh"; vobject_class->description = _("shrink an image horizontally"); vobject_class->build = vips_shrinkh_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_INT(class, "hshrink", 8, _("Hshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsShrinkh, hshrink), 1, 1000000, 1); VIPS_ARG_BOOL(class, "ceil", 10, _("Ceil"), _("Round-up output dimensions"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsShrinkh, ceil), FALSE); /* The old name .. now use h and v everywhere. */ VIPS_ARG_INT(class, "xshrink", 8, _("Xshrink"), _("Horizontal shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsShrinkh, hshrink), 1, 1000000, 1); } static void vips_shrinkh_init(VipsShrinkh *shrink) { } /** * vips_shrinkh: (method) * @in: input image * @out: (out): output image * @hshrink: horizontal shrink * @...: `NULL`-terminated list of optional named arguments * * Shrink @in horizontally by an integer factor. * Each pixel in the output is * the average of the corresponding line of @hshrink pixels in the input. * * This is a very low-level operation: see [method@Image.resize] for a more * convenient way to resize images. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @ceil: `gboolean`, round-up output dimensions * * ::: seealso * [method@Image.shrinkv], [method@Image.shrink], [method@Image.resize], * [method@Image.affine]. * * Returns: 0 on success, -1 on error */ int vips_shrinkh(VipsImage *in, VipsImage **out, int hshrink, ...) { va_list ap; int result; va_start(ap, hshrink); result = vips_call_split("shrinkh", ap, in, out, hshrink); va_end(ap); return result; } libvips-8.18.2/libvips/resample/shrinkh_hwy.cpp000066400000000000000000000056201516303661500216140ustar00rootroot00000000000000/* 15/11/24 kleisauke * - from shrinkv_hwy.cpp */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" #ifdef HAVE_HWY #undef HWY_TARGET_INCLUDE #define HWY_TARGET_INCLUDE "libvips/resample/shrinkh_hwy.cpp" #include #include namespace HWY_NAMESPACE { using namespace hwy::HWY_NAMESPACE; using DU32 = ScalableTag; constexpr Rebind du8x32; constexpr DU32 du32; constexpr int64_t max_uint32 = 1LL << 32; constexpr int32_t max_bits = 1 << 8; HWY_ATTR void vips_shrinkh_uchar_hwy(VipsPel *pout, VipsPel *pin, int32_t width, int32_t hshrink, int32_t bands) { #if HWY_TARGET != HWY_SCALAR const auto multiplier = Set(du32, max_uint32 / (max_bits * hshrink)); const auto amend = Set(du32, hshrink / 2); int32_t ix = 0; for (int32_t x = 0; x < width; ++x) { auto *HWY_RESTRICT p = (uint8_t *) pin + ix * bands; auto *HWY_RESTRICT q = (uint8_t *) pout + x * bands; auto sum0 = amend; int32_t xx = 0; for (; xx + 2 <= hshrink; xx += 2) { auto pix0 = PromoteTo(du32, LoadU(du8x32, p)); p += bands; auto pix1 = PromoteTo(du32, LoadU(du8x32, p)); p += bands; pix0 = Add(pix0, pix1); sum0 = Add(sum0, pix0); } for (; xx < hshrink; ++xx) { auto pix0 = PromoteTo(du32, LoadU(du8x32, p)); p += bands; sum0 = Add(sum0, pix0); } sum0 = Mul(sum0, multiplier); /* The final 32->8 conversion. */ sum0 = ShiftRight<24>(sum0); auto demoted = DemoteTo(du8x32, sum0); StoreU(demoted, du8x32, q); ix += hshrink; } #endif } } /*namespace HWY_NAMESPACE*/ #if HWY_ONCE HWY_EXPORT(vips_shrinkh_uchar_hwy); void vips_shrinkh_uchar_hwy(VipsPel *pout, VipsPel *pin, int width, int hshrink, int bands) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_shrinkh_uchar_hwy)(pout, pin, width, hshrink, bands); /* clang-format on */ } #endif /*HWY_ONCE*/ #endif /*HAVE_HWY*/ libvips-8.18.2/libvips/resample/shrinkv.c000066400000000000000000000415731516303661500204120ustar00rootroot00000000000000/* vertical shrink with a box filter * * Copyright: 1990, N. Dessipris. * * Authors: Nicos Dessipris and Kirk Martinez * Written on: 29/04/1991 * Modified on: 2/11/92, 22/2/93 Kirk Martinez - Xres Yres & cleanup incredibly inefficient for box filters as LUTs are used instead of + Needs converting to a smoother filter: eg Gaussian! KM * 15/7/93 JC * - rewritten for partial v2 * - ANSIfied * - now shrinks any non-complex type * - no longer cloned from im_convsub() * - could be much better! see km comments above * 3/8/93 JC * - rounding bug fixed * 11/1/94 JC * - problems with .000001 and round up/down ignored! Try shrink 3738 * pixel image by 9.345000000001 * 7/10/94 JC * - IM_NEW and IM_ARRAY added * - more typedef * 3/7/95 JC * - IM_CODING_LABQ handling added here * 20/12/08 * - fall back to im_copy() for 1/1 shrink * 2/2/11 * - gtk-doc * 10/2/12 * - shrink in chunks to reduce peak memuse for large shrinks * - simpler * 12/6/12 * - redone as a class * - warn about non-int shrinks * - some tuning .. tried an int coordinate path, not worthwhile * 16/11/12 * - don't change xres/yres, see comment below * 8/4/13 * - oops demand_hint was incorrect, thanks Jan * 6/6/13 * - don't chunk horizontally, fixes seq problems with large shrink * factors * 15/8/16 * - rename yshrink -> vshrink for greater consistency * 7/3/17 * - add a seq line cache * 6/8/19 * - use a double sum buffer for int32 types * 22/4/22 kleisauke * - add @ceil option */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" typedef struct _VipsShrinkv { VipsResample parent_instance; int vshrink; /* Shrink factor */ size_t sizeof_line_buffer; gboolean ceil; /* Round operation */ } VipsShrinkv; typedef VipsResampleClass VipsShrinkvClass; G_DEFINE_TYPE(VipsShrinkv, vips_shrinkv, VIPS_TYPE_RESAMPLE); /* Our per-sequence parameter struct. Somewhere to sum band elements. */ typedef struct { VipsRegion *ir; VipsPel *sum; } VipsShrinkvSequence; /* Free a sequence value. */ static int vips_shrinkv_stop(void *vseq, void *a, void *b) { VipsShrinkvSequence *seq = (VipsShrinkvSequence *) vseq; VIPS_FREEF(g_object_unref, seq->ir); VIPS_FREE(seq->sum); VIPS_FREE(seq); return 0; } /* Make a sequence value. */ static void * vips_shrinkv_start(VipsImage *out, void *a, void *b) { VipsImage *in = (VipsImage *) a; VipsShrinkv *shrink = (VipsShrinkv *) b; VipsShrinkvSequence *seq; if (!(seq = VIPS_NEW(NULL, VipsShrinkvSequence))) return NULL; seq->ir = vips_region_new(in); /* Big enough for the largest intermediate .. a couple of scanlines. */ seq->sum = VIPS_ARRAY(NULL, shrink->sizeof_line_buffer, VipsPel); return (void *) seq; } #define ADD(ACC_TYPE, TYPE) \ { \ ACC_TYPE *restrict sum = (ACC_TYPE *) seq->sum + sz * y; \ TYPE *restrict p = (TYPE *) in; \ \ for (x = 0; x < sz; x++) \ sum[x] += p[x]; \ } /* Add a line of pixels to sum. */ static void vips_shrinkv_add_line(VipsShrinkv *shrink, VipsShrinkvSequence *seq, VipsRegion *ir, int left, int top, int width, int y) { VipsResample *resample = VIPS_RESAMPLE(shrink); const int bands = resample->in->Bands * (vips_band_format_iscomplex(resample->in->BandFmt) ? 2 : 1); const int sz = bands * width; int x; VipsPel *in = VIPS_REGION_ADDR(ir, left, top); switch (resample->in->BandFmt) { case VIPS_FORMAT_UCHAR: ADD(int, unsigned char); break; case VIPS_FORMAT_CHAR: ADD(int, char); break; case VIPS_FORMAT_USHORT: ADD(int, unsigned short); break; case VIPS_FORMAT_SHORT: ADD(int, short); break; case VIPS_FORMAT_UINT: ADD(gint64, unsigned int); break; case VIPS_FORMAT_INT: ADD(gint64, int); break; case VIPS_FORMAT_FLOAT: ADD(double, float); break; case VIPS_FORMAT_DOUBLE: ADD(double, double); break; case VIPS_FORMAT_COMPLEX: ADD(double, float); break; case VIPS_FORMAT_DPCOMPLEX: ADD(double, double); break; default: g_assert_not_reached(); } } /* Fixed-point arithmetic path for uchar images. */ #define UCHAR_AVG() \ { \ int *restrict sum = (int *) seq->sum + sz * y; \ unsigned char *restrict q = (unsigned char *) out; \ int amend = shrink->vshrink / 2; \ unsigned int multiplier = (1LL << 32) / ((1 << 8) * shrink->vshrink); \ \ for (x = 0; x < sz; x++) \ q[x] = ((sum[x] + amend) * multiplier) >> 24; \ } /* Integer average. */ #define IAVG(ACC_TYPE, TYPE) \ { \ ACC_TYPE *restrict sum = (ACC_TYPE *) seq->sum + sz * y; \ TYPE *restrict q = (TYPE *) out; \ int amend = shrink->vshrink / 2; \ \ for (x = 0; x < sz; x++) \ q[x] = (sum[x] + amend) / shrink->vshrink; \ } /* Float average. */ #define FAVG(TYPE) \ { \ double *restrict sum = (double *) seq->sum + sz * y; \ TYPE *restrict q = (TYPE *) out; \ \ for (x = 0; x < sz; x++) \ q[x] = sum[x] / shrink->vshrink; \ } /* Average the line of sums to out. */ static void vips_shrinkv_write_line(VipsShrinkv *shrink, VipsShrinkvSequence *seq, VipsRegion *out_region, int left, int top, int width, int y) { VipsResample *resample = VIPS_RESAMPLE(shrink); const int bands = resample->in->Bands * (vips_band_format_iscomplex(resample->in->BandFmt) ? 2 : 1); const int sz = bands * width; int x; VipsPel *out = VIPS_REGION_ADDR(out_region, left, top); switch (resample->in->BandFmt) { case VIPS_FORMAT_UCHAR: UCHAR_AVG(); break; case VIPS_FORMAT_CHAR: IAVG(int, char); break; case VIPS_FORMAT_USHORT: IAVG(int, unsigned short); break; case VIPS_FORMAT_SHORT: IAVG(int, short); break; case VIPS_FORMAT_UINT: IAVG(gint64, unsigned int); break; case VIPS_FORMAT_INT: IAVG(gint64, int); break; case VIPS_FORMAT_FLOAT: FAVG(float); break; case VIPS_FORMAT_DOUBLE: FAVG(double); break; case VIPS_FORMAT_COMPLEX: FAVG(float); break; case VIPS_FORMAT_DPCOMPLEX: FAVG(double); break; default: g_assert_not_reached(); } } static int vips_shrinkv_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsShrinkvSequence *seq = (VipsShrinkvSequence *) vseq; VipsShrinkv *shrink = (VipsShrinkv *) b; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; /* How do we chunk up the image? We don't want to prepare the whole of * the input region corresponding to *r since it could be huge. * * Reading a line at a time could cause a lot of overcomputation, depending * on what's upstream from us. In SMALLTILE, output scanlines could be * quite small. * * Use fatstrip height as a compromise. */ int dy = vips__fatstrip_height; int y, y1, y2; #ifdef DEBUG printf("vips_shrinkv_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ for (y = 0; y < r->height; y += dy) { int chunk_height = VIPS_MIN(dy, r->height - y); memset(seq->sum, 0, shrink->sizeof_line_buffer); const int start = (r->top + y) * shrink->vshrink; const int end = (r->top + y + chunk_height) * shrink->vshrink; for (y1 = start; y1 < end; y1 += dy) { VipsRect s; s.left = r->left; s.top = y1; s.width = r->width; s.height = VIPS_MIN(dy, end - y1); #ifdef DEBUG printf("vips_shrinkv_gen: requesting %d lines from %d\n", s.height, s.top); #endif /*DEBUG*/ if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_shrinkv_gen: work"); for (y2 = 0; y2 < s.height; y2++) { int chunk_y = (y1 + y2 - start) / shrink->vshrink; vips_shrinkv_add_line(shrink, seq, ir, s.left, y1 + y2, s.width, chunk_y); } VIPS_GATE_STOP("vips_shrinkv_gen: work"); } VIPS_GATE_START("vips_shrinkv_gen: work"); for (y1 = 0; y1 < chunk_height; y1++) vips_shrinkv_write_line(shrink, seq, out_region, r->left, r->top + y + y1, r->width, y1); VIPS_GATE_STOP("vips_shrinkv_gen: work"); } VIPS_COUNT_PIXELS(out_region, "vips_shrinkv_gen"); return 0; } #ifdef HAVE_HWY static int vips_shrinkv_uchar_vector_gen(VipsRegion *out_region, void *vseq, void *a, void *b, gboolean *stop) { VipsShrinkvSequence *seq = (VipsShrinkvSequence *) vseq; VipsImage *in = (VipsImage *) a; VipsShrinkv *shrink = (VipsShrinkv *) b; VipsRegion *ir = seq->ir; VipsRect *r = &out_region->valid; const int bands = in->Bands; int ne = r->width * bands; /* How do we chunk up the image? We don't want to prepare the whole of * the input region corresponding to *r since it could be huge. * * Reading a line at a time could cause a lot of overcomputation, depending * on what's upstream from us. In SMALLTILE, output scanlines could be * quite small. * * Use fatstrip height as a compromise. */ int dy = vips__fatstrip_height; int y, y1, y2; #ifdef DEBUG printf("vips_shrinkv_uchar_vector_gen: generating %d x %d at %d x %d\n", r->width, r->height, r->left, r->top); #endif /*DEBUG*/ for (y = 0; y < r->height; y += dy) { int chunk_height = VIPS_MIN(dy, r->height - y); memset(seq->sum, 0, shrink->sizeof_line_buffer); const int start = (r->top + y) * shrink->vshrink; const int end = (r->top + y + chunk_height) * shrink->vshrink; for (y1 = start; y1 < end; y1 += dy) { VipsRect s; s.left = r->left; s.top = y1; s.width = r->width; s.height = VIPS_MIN(dy, end - y1); #ifdef DEBUG printf( "vips_shrinkv_uchar_vector_gen: requesting %d lines from %d\n", s.height, s.top); #endif /*DEBUG*/ if (vips_region_prepare(ir, &s)) return -1; VIPS_GATE_START("vips_shrinkv_uchar_vector_gen: work"); for (y2 = 0; y2 < s.height; y2++) { VipsPel *p = VIPS_REGION_ADDR(ir, r->left, y1 + y2); int chunk_y = (y1 + y2 - start) / shrink->vshrink; vips_shrinkv_add_line_uchar_hwy(p, ne, (unsigned int *) seq->sum + ne * chunk_y); } VIPS_GATE_STOP("vips_shrinkv_uchar_vector_gen: work"); } VIPS_GATE_START("vips_shrinkv_uchar_vector_gen: work"); for (y1 = 0; y1 < chunk_height; y1++) { VipsPel *q = VIPS_REGION_ADDR(out_region, r->left, r->top + y + y1); vips_shrinkv_write_line_uchar_hwy(q, ne, shrink->vshrink, (unsigned int *) seq->sum + ne * y1); } VIPS_GATE_STOP("vips_shrinkv_uchar_vector_gen: work"); } VIPS_COUNT_PIXELS(out_region, "vips_shrinkv_uchar_vector_gen"); return 0; } #endif /*HAVE_HWY*/ static int vips_shrinkv_build(VipsObject *object) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object); VipsResample *resample = VIPS_RESAMPLE(object); VipsShrinkv *shrink = (VipsShrinkv *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); VipsImage *in; VipsGenerateFn generate; size_t acc_size; if (VIPS_OBJECT_CLASS(vips_shrinkv_parent_class)->build(object)) return -1; in = resample->in; if (shrink->vshrink < 1) { vips_error(class->nickname, "%s", _("shrink factors should be >= 1")); return -1; } if (shrink->vshrink == 1) return vips_image_write(in, resample->out); /* Make the height a multiple of the shrink factor so we don't need to * average half pixels. */ if (vips_embed(in, &t[1], 0, 0, in->Xsize, VIPS_ROUND_UP(in->Ysize, shrink->vshrink), "extend", VIPS_EXTEND_COPY, NULL)) return -1; in = t[1]; /* Determine the accumulator size based on the band format. */ switch (resample->in->BandFmt) { case VIPS_FORMAT_UINT: case VIPS_FORMAT_INT: acc_size = sizeof(gint64); break; case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: acc_size = sizeof(double); break; default: acc_size = sizeof(int); break; } if (vips_band_format_iscomplex(resample->in->BandFmt)) acc_size *= 2; /* We have to keep a line buffer as we sum columns. */ shrink->sizeof_line_buffer = (size_t) in->Xsize * in->Bands * vips__fatstrip_height * acc_size; /* For uchar input, try to make a vector path. */ #ifdef HAVE_HWY if (in->BandFmt == VIPS_FORMAT_UCHAR && vips_vector_isenabled()) { generate = vips_shrinkv_uchar_vector_gen; g_info("shrinkv: using vector path"); } else #endif /*HAVE_HWY*/ /* Default to the C path. */ generate = vips_shrinkv_gen; /* SMALLTILE or we'll need huge input areas for our output. In seq * mode, the linecache above will keep us sequential. */ t[2] = vips_image_new(); if (vips_image_pipelinev(t[2], VIPS_DEMAND_STYLE_SMALLTILE, in, NULL)) return -1; /* Size output. * * Don't change xres/yres, leave that to the application layer. For * example, vipsthumbnail knows the true shrink factor (including the * fractional part), we just see the integer part here. */ t[2]->Ysize = shrink->ceil ? ceil((double) resample->in->Ysize / shrink->vshrink) : VIPS_ROUND_UINT((double) resample->in->Ysize / shrink->vshrink); if (t[2]->Ysize <= 0) { vips_error(class->nickname, "%s", _("image has shrunk to nothing")); return -1; } #ifdef DEBUG printf("vips_shrinkv_build: vshrink = %d\n", shrink->vshrink); printf("vips_shrinkv_build: shrinking %d x %d image to %d x %d\n", in->Xsize, in->Ysize, t[2]->Xsize, t[2]->Ysize); #endif /*DEBUG*/ if (vips_image_generate(t[2], vips_shrinkv_start, generate, vips_shrinkv_stop, in, shrink)) return -1; in = t[2]; /* Large vshrinks will throw off sequential mode. Suppose thread1 is * generating tile (0, 0), but stalls. thread2 generates tile * (0, 1), 128 lines further down the output. After it has done, * thread1 tries to generate (0, 0), but by then the pixels it needs * have gone from the input image line cache if the vshrink is large. * * To fix this, put another seq on the output of vshrink. Now we'll * always have the previous XX lines of the shrunk image, and we won't * fetch out of order. */ if (vips_image_is_sequential(in)) { g_info("shrinkv sequential line cache"); if (vips_sequential(in, &t[3], "tile_height", 10, NULL)) return -1; in = t[3]; } if (vips_image_write(in, resample->out)) return -1; return 0; } static void vips_shrinkv_class_init(VipsShrinkvClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VIPS_DEBUG_MSG("vips_shrinkv_class_init\n"); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "shrinkv"; vobject_class->description = _("shrink an image vertically"); vobject_class->build = vips_shrinkv_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; VIPS_ARG_INT(class, "vshrink", 9, _("Vshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsShrinkv, vshrink), 1, 1000000, 1); VIPS_ARG_BOOL(class, "ceil", 10, _("Ceil"), _("Round-up output dimensions"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsShrinkv, ceil), FALSE); /* The old name .. now use h and v everywhere. */ VIPS_ARG_INT(class, "yshrink", 8, _("Yshrink"), _("Vertical shrink factor"), VIPS_ARGUMENT_REQUIRED_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsShrinkv, vshrink), 1, 1000000, 1); } static void vips_shrinkv_init(VipsShrinkv *shrink) { } /** * vips_shrinkv: (method) * @in: input image * @out: (out): output image * @vshrink: vertical shrink * @...: `NULL`-terminated list of optional named arguments * * Shrink @in vertically by an integer factor. * * Each pixel in the output is * the average of the corresponding column of @vshrink pixels in the input. * * This is a very low-level operation: see [method@Image.resize] for a more * convenient way to resize images. * * This operation does not change xres or yres. The image resolution needs to * be updated by the application. * * ::: tip "Optional arguments" * * @ceil: `gboolean`, round-up output dimensions * * ::: seealso * [method@Image.shrinkh], [method@Image.shrink], [method@Image.resize], * [method@Image.affine]. * * Returns: 0 on success, -1 on error */ int vips_shrinkv(VipsImage *in, VipsImage **out, int vshrink, ...) { va_list ap; int result; va_start(ap, vshrink); result = vips_call_split("shrinkv", ap, in, out, vshrink); va_end(ap); return result; } libvips-8.18.2/libvips/resample/shrinkv_hwy.cpp000066400000000000000000000131121516303661500216250ustar00rootroot00000000000000/* 14/11/24 kleisauke * - from reducev_hwy.cpp */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include #include "presample.h" #ifdef HAVE_HWY #undef HWY_TARGET_INCLUDE #define HWY_TARGET_INCLUDE "libvips/resample/shrinkv_hwy.cpp" #include #include namespace HWY_NAMESPACE { using namespace hwy::HWY_NAMESPACE; using DU32 = ScalableTag; using DU16 = ScalableTag; constexpr Rebind du8x16; #if HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE) constexpr Rebind du8x32; #endif constexpr DU16 du16; constexpr DU32 du32; constexpr int64_t max_uint32 = 1LL << 32; constexpr int32_t max_bits = 1 << 8; #if defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) #define InterleaveLower InterleaveWholeLower #define InterleaveUpper InterleaveWholeUpper #endif // Compat for Highway versions < 1.3.0 #ifndef HWY_LANES_CONSTEXPR #define HWY_LANES_CONSTEXPR #endif #if HWY_IS_BIG_ENDIAN #define HWY_ENDIAN_LOHI(lo, hi) hi, lo #else #define HWY_ENDIAN_LOHI(lo, hi) lo, hi #endif HWY_ATTR void vips_shrinkv_add_line_uchar_hwy(VipsPel *pin, int32_t ne, uint32_t *HWY_RESTRICT sum) { #if HWY_TARGET != HWY_SCALAR #if !defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) /* Ensure we do not cross 128-bit block boundaries on RVV/SVE. */ const int32_t N = 8; #else HWY_LANES_CONSTEXPR int32_t N = Lanes(du16); #endif const auto zero = Zero(du16); auto *HWY_RESTRICT p = (uint8_t *) pin; /* Main sum loop: unrolled. */ int32_t x = 0; for (; x + N <= ne; x += N) { auto pix0 = PromoteTo(du16, LoadU(du8x16, p + x)); auto sum0 = LoadU(du32, &sum[x + 0 * N / 2]); auto sum1 = LoadU(du32, &sum[x + 1 * N / 2]); sum0 = Add(sum0, BitCast(du32, InterleaveLower(du16, HWY_ENDIAN_LOHI(pix0, zero)))); sum1 = Add(sum1, BitCast(du32, InterleaveUpper(du16, HWY_ENDIAN_LOHI(pix0, zero)))); StoreU(sum0, du32, &sum[x + 0 * N / 2]); StoreU(sum1, du32, &sum[x + 1 * N / 2]); } /* `ne` was not a multiple of the vector length `N`; * proceed one by one. */ for (; x < ne; ++x) sum[x] += p[x]; #endif } HWY_ATTR void vips_shrinkv_write_line_uchar_hwy(VipsPel *pout, int32_t ne, int32_t vshrink, uint32_t *HWY_RESTRICT sum) { #if HWY_TARGET != HWY_SCALAR #if !defined(HAVE_HWY_1_1_0) && \ (HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE)) /* Ensure we do not cross 128-bit block boundaries on RVV/SVE. */ const int32_t N = 8; #else HWY_LANES_CONSTEXPR int32_t N = Lanes(du16); #endif const uint32_t multiplier = max_uint32 / (max_bits * vshrink); const uint32_t amend = vshrink / 2; const auto multiplier_v = Set(du32, multiplier); const auto amend_v = Set(du32, amend); /* Main write loop: unrolled. */ int32_t x = 0; for (; x + N <= ne; x += N) { auto *HWY_RESTRICT q = (uint8_t *) pout + x; auto sum0 = LoadU(du32, &sum[x + 0 * N / 2]); auto sum1 = LoadU(du32, &sum[x + 1 * N / 2]); sum0 = Add(sum0, amend_v); sum1 = Add(sum1, amend_v); sum0 = Mul(sum0, multiplier_v); sum1 = Mul(sum1, multiplier_v); /* The final 32->8 conversion. */ sum0 = ShiftRight<24>(sum0); sum1 = ShiftRight<24>(sum1); #if HWY_ARCH_RVV || (HWY_ARCH_ARM_A64 && HWY_TARGET <= HWY_SVE) /* RVV/SVE defines demotion as writing to the upper or lower half * of each lane, rather than compacting them within a vector. */ auto demoted0 = DemoteTo(du8x32, sum0); auto demoted1 = DemoteTo(du8x32, sum1); StoreU(demoted0, du8x32, q + 0 * N / 2); StoreU(demoted1, du8x32, q + 1 * N / 2); #else auto demoted0 = ReorderDemote2To(du16, sum0, sum1); auto demoted = DemoteTo(du8x16, demoted0); StoreU(demoted, du8x16, q); #endif } /* `ne` was not a multiple of the vector length `N`; * proceed one by one. */ for (; x < ne; ++x) { auto *HWY_RESTRICT q = (uint8_t *) pout + x; *q = ((sum[x] + amend) * multiplier) >> 24; } #endif } #undef InterleaveLower #undef InterleaveUpper } /*namespace HWY_NAMESPACE*/ #if HWY_ONCE HWY_EXPORT(vips_shrinkv_add_line_uchar_hwy); HWY_EXPORT(vips_shrinkv_write_line_uchar_hwy); void vips_shrinkv_add_line_uchar_hwy(VipsPel *pin, int ne, unsigned int *restrict sum) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_shrinkv_add_line_uchar_hwy)(pin, ne, sum); /* clang-format on */ } void vips_shrinkv_write_line_uchar_hwy(VipsPel *pout, int ne, int vshrink, unsigned int *restrict sum) { /* clang-format off */ HWY_DYNAMIC_DISPATCH(vips_shrinkv_write_line_uchar_hwy)(pout, ne, vshrink, sum); /* clang-format on */ } #endif /*HWY_ONCE*/ #endif /*HAVE_HWY*/ libvips-8.18.2/libvips/resample/similarity.c000066400000000000000000000207461516303661500211130ustar00rootroot00000000000000/* simple wrapper over vips_affine() to make scale / rotate easy from the * command-line * * 3/10/13 * - from affine.c * 25/10/13 * - oops, reverse rotation direction to match the convention used in the * rest of vips * 13/8/14 * - oops, missing scale from b, thanks Topochicho * 7/2/16 * - use vips_reduce(), if we can * 17/11/17 * ` - add optional "background" param * ` - don't use vips_reduce() since it has no "background" param * 10/3/18 * - add vips_rotate() class for convenience */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include "presample.h" typedef struct _VipsSimilarityBase { VipsResample parent_instance; double scale; double angle; VipsInterpolate *interpolate; VipsArrayDouble *background; double odx; double ody; double idx; double idy; } VipsSimilarityBase; typedef VipsResampleClass VipsSimilarityBaseClass; G_DEFINE_ABSTRACT_TYPE(VipsSimilarityBase, vips_similarity_base, VIPS_TYPE_RESAMPLE); static int vips_similarity_base_build(VipsObject *object) { VipsResample *resample = VIPS_RESAMPLE(object); VipsSimilarityBase *base = (VipsSimilarityBase *) object; VipsImage **t = (VipsImage **) vips_object_local_array(object, 4); double a = base->scale * cos(VIPS_RAD(base->angle)); double b = base->scale * -sin(VIPS_RAD(base->angle)); double c = -b; double d = a; if (VIPS_OBJECT_CLASS(vips_similarity_base_parent_class)->build(object)) return -1; if (vips_affine(resample->in, &t[0], a, b, c, d, "interpolate", base->interpolate, "odx", base->odx, "ody", base->ody, "idx", base->idx, "idy", base->idy, "background", base->background, NULL)) return -1; if (vips_image_write(t[0], resample->out)) return -1; return 0; } static void vips_similarity_base_class_init(VipsSimilarityBaseClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "similarity_base"; vobject_class->description = _("base similarity transform"); vobject_class->build = vips_similarity_base_build; VIPS_ARG_INTERPOLATE(class, "interpolate", 5, _("Interpolate"), _("Interpolate pixels with this"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarityBase, interpolate)); VIPS_ARG_BOXED(class, "background", 6, _("Background"), _("Background value"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarityBase, background), VIPS_TYPE_ARRAY_DOUBLE); VIPS_ARG_DOUBLE(class, "odx", 112, _("Output offset"), _("Horizontal output displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarityBase, odx), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "ody", 113, _("Output offset"), _("Vertical output displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarityBase, ody), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "idx", 114, _("Input offset"), _("Horizontal input displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarityBase, idx), -10000000, 10000000, 0); VIPS_ARG_DOUBLE(class, "idy", 115, _("Input offset"), _("Vertical input displacement"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarityBase, idy), -10000000, 10000000, 0); } static void vips_similarity_base_init(VipsSimilarityBase *base) { base->scale = 1; base->angle = 0; base->interpolate = NULL; base->odx = 0; base->ody = 0; base->idx = 0; base->idy = 0; base->background = vips_array_double_newv(1, 0.0); } typedef VipsSimilarityBase VipsSimilarity; typedef VipsSimilarityBaseClass VipsSimilarityClass; G_DEFINE_TYPE(VipsSimilarity, vips_similarity, vips_similarity_base_get_type()); static void vips_similarity_class_init(VipsSimilarityClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "similarity"; vobject_class->description = _("similarity transform of an image"); VIPS_ARG_DOUBLE(class, "scale", 3, _("Scale"), _("Scale by this factor"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarity, scale), 0, 10000000, 1); VIPS_ARG_DOUBLE(class, "angle", 4, _("Angle"), _("Rotate clockwise by this many degrees"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsSimilarity, angle), -10000000, 10000000, 0); } static void vips_similarity_init(VipsSimilarity *similarity) { } /** * vips_similarity: (method) * @in: input image * @out: (out): output image * @...: `NULL`-terminated list of optional named arguments * * This operator calls [method@Image.affine] for you, calculating the matrix * for the affine transform from @scale and @angle. Other parameters are * passed on to [method@Image.affine] unaltered. * * ::: tip "Optional arguments" * * @scale: `gdouble`, scale by this factor * * @angle: `gdouble`, rotate by this many degrees clockwise * * @interpolate: [class@Interpolate], interpolate pixels with this * * @background: [struct@ArrayDouble] colour for new pixels * * @idx: `gdouble`, input horizontal offset * * @idy: `gdouble`, input vertical offset * * @odx: `gdouble`, output horizontal offset * * @ody: `gdouble`, output vertical offset * * ::: seealso * [method@Image.affine], [class@Interpolate]. * * Returns: 0 on success, -1 on error */ int vips_similarity(VipsImage *in, VipsImage **out, ...) { va_list ap; int result; va_start(ap, out); result = vips_call_split("similarity", ap, in, out); va_end(ap); return result; } typedef VipsSimilarityBase VipsRotate; typedef VipsSimilarityBaseClass VipsRotateClass; G_DEFINE_TYPE(VipsRotate, vips_rotate, vips_similarity_base_get_type()); static void vips_rotate_class_init(VipsRotateClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "rotate"; vobject_class->description = _("rotate an image by a number of degrees"); VIPS_ARG_DOUBLE(class, "angle", 4, _("Angle"), _("Rotate clockwise by this many degrees"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsSimilarity, angle), -10000000, 10000000, 0); } static void vips_rotate_init(VipsRotate *rotate) { } /** * vips_rotate: (method) * @in: input image * @out: (out): output image * @angle: `gdouble`, rotate by this many degrees clockwise * @...: `NULL`-terminated list of optional named arguments * * This operator calls [method@Image.affine] for you, calculating the matrix * for the affine transform from @scale and @angle. * * Other parameters are passed on to [method@Image.affine] unaltered. * * ::: tip "Optional arguments" * * @interpolate: [class@Interpolate], interpolate pixels with this * * @background: [struct@ArrayDouble], colour for new pixels * * @idx: `gdouble`, input horizontal offset * * @idy: `gdouble`, input vertical offset * * @odx: `gdouble`, output horizontal offset * * @ody: `gdouble`, output vertical offset * * ::: seealso * [method@Image.affine], [class@Interpolate]. * * Returns: 0 on success, -1 on error */ int vips_rotate(VipsImage *in, VipsImage **out, double angle, ...) { va_list ap; int result; va_start(ap, angle); result = vips_call_split("rotate", ap, in, out, angle); va_end(ap); return result; } libvips-8.18.2/libvips/resample/templates.h000066400000000000000000000312611516303661500207220ustar00rootroot00000000000000/* various interpolation templates */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include /* * Various casts which assume that the data is already in range. (That * is, they are to be used with monotone samplers.) */ template static T inline to_fptypes(const double val) { const T newval = val; return newval; } template static T inline to_withsign(const double val) { const int sign_of_val = 2 * (val >= 0.) - 1; const int rounded_abs_val = .5 + sign_of_val * val; const T newval = sign_of_val * rounded_abs_val; return newval; } template static T inline to_nosign(const double val) { const T newval = .5 + val; return newval; } /* * Various bilinear implementation templates. Note that no clampling * is used: There is an assumption that the data is such that * over/underflow is not an issue: */ /* * Bilinear interpolation for float and double types. The first four * inputs are weights, the last four are the corresponding pixel * values: */ template static T inline bilinear_fptypes( const double w_times_z, const double x_times_z, const double w_times_y, const double x_times_y, const double tre_thr, const double tre_thrfou, const double trequa_thr, const double trequa_thrfou) { const T newval = w_times_z * tre_thr + x_times_z * tre_thrfou + w_times_y * trequa_thr + x_times_y * trequa_thrfou; return newval; } /* * Bilinear interpolation for signed integer types: */ template static T inline bilinear_withsign( const double w_times_z, const double x_times_z, const double w_times_y, const double x_times_y, const double tre_thr, const double tre_thrfou, const double trequa_thr, const double trequa_thrfou) { const double val = w_times_z * tre_thr + x_times_z * tre_thrfou + w_times_y * trequa_thr + x_times_y * trequa_thrfou; const int sign_of_val = 2 * (val >= 0.) - 1; const int rounded_abs_val = .5 + sign_of_val * val; const T newval = sign_of_val * rounded_abs_val; return newval; } /* * Bilinear Interpolation for unsigned integer types: */ template static T inline bilinear_nosign( const double w_times_z, const double x_times_z, const double w_times_y, const double x_times_y, const double tre_thr, const double tre_thrfou, const double trequa_thr, const double trequa_thrfou) { const T newval = w_times_z * tre_thr + x_times_z * tre_thrfou + w_times_y * trequa_thr + x_times_y * trequa_thrfou + 0.5; return newval; } /* * Bicubic (Catmull-Rom) interpolation templates: */ template static T inline unsigned_fixed_round(T v) { const int round_by = VIPS_INTERPOLATE_SCALE >> 1; return (v + round_by) >> VIPS_INTERPOLATE_SHIFT; } /* Fixed-point integer bicubic, used for 8-bit types. */ template static int inline bicubic_unsigned_int( const T uno_one, const T uno_two, const T uno_thr, const T uno_fou, const T dos_one, const T dos_two, const T dos_thr, const T dos_fou, const T tre_one, const T tre_two, const T tre_thr, const T tre_fou, const T qua_one, const T qua_two, const T qua_thr, const T qua_fou, const int *restrict cx, const int *restrict cy) { const int c0 = cx[0]; const int c1 = cx[1]; const int c2 = cx[2]; const int c3 = cx[3]; const int r0 = unsigned_fixed_round( c0 * uno_one + c1 * uno_two + c2 * uno_thr + c3 * uno_fou); const int r1 = unsigned_fixed_round( c0 * dos_one + c1 * dos_two + c2 * dos_thr + c3 * dos_fou); const int r2 = unsigned_fixed_round( c0 * tre_one + c1 * tre_two + c2 * tre_thr + c3 * tre_fou); const int r3 = unsigned_fixed_round( c0 * qua_one + c1 * qua_two + c2 * qua_thr + c3 * qua_fou); return unsigned_fixed_round( cy[0] * r0 + cy[1] * r1 + cy[2] * r2 + cy[3] * r3); } template static T inline signed_fixed_round(T v) { const int sign_of_v = 2 * (v >= 0) - 1; const int round_by = sign_of_v * (VIPS_INTERPOLATE_SCALE >> 1); return (v + round_by) >> VIPS_INTERPOLATE_SHIFT; } /* Fixed-point integer bicubic, used for 8-bit types. */ template static int inline bicubic_signed_int( const T uno_one, const T uno_two, const T uno_thr, const T uno_fou, const T dos_one, const T dos_two, const T dos_thr, const T dos_fou, const T tre_one, const T tre_two, const T tre_thr, const T tre_fou, const T qua_one, const T qua_two, const T qua_thr, const T qua_fou, const int *restrict cx, const int *restrict cy) { const int c0 = cx[0]; const int c1 = cx[1]; const int c2 = cx[2]; const int c3 = cx[3]; const int r0 = signed_fixed_round( c0 * uno_one + c1 * uno_two + c2 * uno_thr + c3 * uno_fou); const int r1 = signed_fixed_round( c0 * dos_one + c1 * dos_two + c2 * dos_thr + c3 * dos_fou); const int r2 = signed_fixed_round( c0 * tre_one + c1 * tre_two + c2 * tre_thr + c3 * tre_fou); const int r3 = signed_fixed_round( c0 * qua_one + c1 * qua_two + c2 * qua_thr + c3 * qua_fou); return signed_fixed_round( cy[0] * r0 + cy[1] * r1 + cy[2] * r2 + cy[3] * r3); } template static T inline cubic_float( const T one, const T two, const T thr, const T fou, const double *restrict cx) { return cx[0] * one + cx[1] * two + cx[2] * thr + cx[3] * fou; } /* Floating-point bicubic, used for int/float/double types. */ template static T inline bicubic_float( const T uno_one, const T uno_two, const T uno_thr, const T uno_fou, const T dos_one, const T dos_two, const T dos_thr, const T dos_fou, const T tre_one, const T tre_two, const T tre_thr, const T tre_fou, const T qua_one, const T qua_two, const T qua_thr, const T qua_fou, const double *restrict cx, const double *restrict cy) { const double r0 = cubic_float( uno_one, uno_two, uno_thr, uno_fou, cx); const double r1 = cubic_float( dos_one, dos_two, dos_thr, dos_fou, cx); const double r2 = cubic_float( tre_one, tre_two, tre_thr, tre_fou, cx); const double r3 = cubic_float( qua_one, qua_two, qua_thr, qua_fou, cx); return cubic_float(r0, r1, r2, r3, cy); } /* Given an offset in [0,1] (we can have x == 1 when building tables), * calculate c0, c1, c2, c3, the catmull-rom coefficients. This is called * from the interpolator as well as from the table builder. */ static void inline calculate_coefficients_catmull(double c[4], const double x) { /* Nicolas believes that the following is an hitherto unknown * hyper-efficient method of computing Catmull-Rom coefficients. It * only uses 4* & 1+ & 5- for a total of only 10 flops to compute * four coefficients. */ const double cr1 = 1. - x; const double cr2 = -.5 * x; const double cr3 = cr1 * cr2; const double cone = cr1 * cr3; const double cfou = x * cr3; const double cr4 = cfou - cone; const double ctwo = cr1 - cone + cr4; const double cthr = x - cfou - cr4; g_assert(x >= 0. && x <= 1.); c[0] = cone; c[3] = cfou; c[1] = ctwo; c[2] = cthr; } /* Generate a cubic filter. See: * * Mitchell and Netravali, Reconstruction Filters in Computer Graphics * Computer Graphics, Volume 22, Number 4, August 1988. * * B = 1, C = 0 - cubic B-spline * B = 1/3, C = 1/3 - Mitchell * B = 0, C = 1/2 - Catmull-Rom spline */ static double inline cubic_filter(double x, double B, double C) { const double ax = fabs(x); const double ax2 = ax * ax; const double ax3 = ax2 * ax; if (ax <= 1) return ((12 - 9 * B - 6 * C) * ax3 + (-18 + 12 * B + 6 * C) * ax2 + (6 - 2 * B)) / 6; if (ax <= 2) return ((-B - 6 * C) * ax3 + (6 * B + 30 * C) * ax2 + (-12 * B - 48 * C) * ax + (8 * B + 24 * C)) / 6; return 0.0; } static double inline sinc_filter(double x) { if (x == 0.0) return 1.0; x = x * VIPS_PI; return sin(x) / x; } using VipsFilterFn = double (*)(double); template static double inline filter(double x); template <> double inline filter(double x) { x = fabs(x); if (x < 1.0) return 1.0 - x; return 0.0; } /* Catmull-Rom. */ template <> double inline filter(double x) { return cubic_filter(x, 0.0, 0.5); } template <> double inline filter(double x) { return cubic_filter(x, 1.0 / 3.0, 1.0 / 3.0); } template <> double inline filter(double x) { if (x >= -2 && x <= 2) return sinc_filter(x) * sinc_filter(x / 2); return 0.0; } template <> double inline filter(double x) { if (x >= -3 && x <= 3) return sinc_filter(x) * sinc_filter(x / 3); return 0.0; } template <> double inline filter(double x) { x = fabs(x); if (x >= 2.5) return 0.0; if (x >= 1.5) return (x - 5.0 / 2.0) * (x - 5.0 / 2.0) / -8.0; if (x >= 0.5) return (4.0 * x * x - 11.0 * x + 7.0) / 4.0; return 17.0 / 16.0 - 7.0 * x * x / 4.0; } template <> double inline filter(double x) { x = fabs(x); if (x >= 4.5) return 0.0; if (x >= 3.5) return (4.0 * x * x - 36.0 * x + 81.0) / -1152.0; if (x >= 2.5) return (4.0 * x * x - 27.0 * x + 45.0) / 144.0; if (x >= 1.5) return (24.0 * x * x - 113.0 * x + 130.0) / -144.0; if (x >= 0.5) return (140.0 * x * x - 379.0 * x + 239.0) / 144.0; return 577.0 / 576.0 - 239.0 * x * x / 144.0; } /* Given an x in [0,1] (we can have x == 1 when building tables), * calculate c0 .. c(@n_points), the coefficients. This is called * from the interpolator as well as from the table builder. * * @shrink is the reduction factor, so 1 for interpolation, 2 for a * x2 reduction, etc. */ template static void calculate_coefficients(T *c, const int n_points, VipsFilterFn filter_fn, const double shrink, const double x) { const double half = x + n_points / 2.0 - 1; int i; T sum; sum = 0.0; for (i = 0; i < n_points; i++) { const double xp = (i - half) / shrink; double l = filter_fn(xp); c[i] = l; sum += l; } for (i = 0; i < n_points; i++) c[i] /= sum; } /* Calculate a mask element. */ template static void vips_reduce_make_mask(T *c, VipsKernel kernel, const int n_points, const double shrink, const double x) { switch (kernel) { case VIPS_KERNEL_NEAREST: c[0] = 1.0; break; case VIPS_KERNEL_LINEAR: calculate_coefficients(c, n_points, filter, shrink, x); break; case VIPS_KERNEL_CUBIC: calculate_coefficients(c, n_points, filter, shrink, x); break; case VIPS_KERNEL_MITCHELL: calculate_coefficients(c, n_points, filter, shrink, x); break; case VIPS_KERNEL_LANCZOS2: calculate_coefficients(c, n_points, filter, shrink, x); break; case VIPS_KERNEL_LANCZOS3: calculate_coefficients(c, n_points, filter, shrink, x); break; case VIPS_KERNEL_MKS2013: calculate_coefficients(c, n_points, filter, shrink, x); break; case VIPS_KERNEL_MKS2021: calculate_coefficients(c, n_points, filter, shrink, x); break; default: g_assert_not_reached(); break; } } /* Machinery to promote type T to a larger data type, prevents an * overflow in reduce_sum(). Defaults to a 32-bit integral type. */ template struct LongT { typedef int32_t type; }; /* 32-bit integral types needs a 64-bits intermediate. */ template <> struct LongT { typedef int64_t type; }; template <> struct LongT { typedef int64_t type; }; /* 32-bit floating-point types needs a 64-bits intermediate. */ template <> struct LongT { typedef double type; }; /* 64-bit floating-point types needs a 128-bits intermediate. */ template <> struct LongT { typedef long double type; }; /* Our inner loop for resampling with a convolution of type CT. Operate on * elements of type T, gather results in an intermediate of type IT. */ template ::type> static IT inline reduce_sum(const T *restrict in, int stride, const CT *restrict c, int n) { IT sum; sum = 0; for (int i = 0; i < n; i++) { sum += (IT) c[i] * in[0]; in += stride; } return sum; } libvips-8.18.2/libvips/resample/thumbnail.c000066400000000000000000001540321516303661500207040ustar00rootroot00000000000000/* make a thumbnail ... wraps up the process of thumbnailing, including * premultiply, colour management etc etc * * 2/11/16 * - from vipsthumbnail.c * 6/1/17 * - add @size parameter * 4/5/17 * - add FORCE * 29/5/17 * - don't cache (thanks tomasc) * 30/8/17 * - add intent option, thanks kleisauke * 31/10/18 * - deprecate auto_rotate, add no_rotate * - implement shrink-on-load for openslide images * 16/11/18 * - implement shrink-on-load for tiff pyramid * 3/2/19 kleisauke * - add option_string param to thumbnail_buffer * 23/4/19 * - don't force import CMYK, since colourspace knows about it now * 24/4/19 * - support multi-page (animated) images * 27/8/19 kleisauke * - prevent over-pre-shrink in thumbnail * 30/9/19 * - smarter heif thumbnail selection * 12/10/19 * - add thumbnail_source * 2/6/20 * - add subifd pyr support * 27/2/21 * - simplify rules re. processing space, colour management and linear * mode * 14/4/22 * - add a seq to thumbnail_image to stop cache thrashing * 28/4/22 * - add fail_on * 1/3/23 kleisauke * - skip colourspace conversion when needed * 27/1/24 * - make icc profile transforms always write 8 bits * 22/8/25 kleisauke * - remove seq line cache from thumbnail_image, use hint instead */ /* Copyright (C) 1991-2005 The National Gallery This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #define VIPS_TYPE_THUMBNAIL (vips_thumbnail_get_type()) #define VIPS_THUMBNAIL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), VIPS_TYPE_THUMBNAIL, VipsThumbnail)) #define VIPS_THUMBNAIL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_THUMBNAIL, VipsThumbnailClass)) #define VIPS_IS_THUMBNAIL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_THUMBNAIL)) #define VIPS_IS_THUMBNAIL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_THUMBNAIL)) #define VIPS_THUMBNAIL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_THUMBNAIL, VipsThumbnailClass)) /* Should be plenty. */ #define MAX_LEVELS (256) typedef struct _VipsThumbnail { VipsOperation parent_instance; VipsImage *out; int width; int height; VipsSize size; gboolean auto_rotate; gboolean no_rotate; VipsInteresting crop; gboolean linear; char *output_profile; char *input_profile; VipsIntent intent; VipsFailOn fail_on; /* Bits of info we read from the input image when we get the header of * the original. */ const char *loader; /* Eg. "VipsForeignLoadJpeg*" */ int input_width; int input_height; int page_height; int orientation; /* From vips_image_get_orientation() */ gboolean swap; /* If we must swap width / height */ int n_pages; /* Pages in file */ int n_loaded_pages; /* Pages we've loaded from file */ int n_subifds; /* Number of subifds */ /* For pyramidal formats, we need to read out the size of each level. */ int level_count; int level_width[MAX_LEVELS]; int level_height[MAX_LEVELS]; /* For HEIF, try to fetch the size of the stored thumbnail. */ int heif_thumbnail_width; int heif_thumbnail_height; /* Pyramids are stored in subifds. */ gboolean subifd_pyramid; /* Pyramids are stored in pages. */ gboolean page_pyramid; } VipsThumbnail; typedef struct _VipsThumbnailClass { VipsOperationClass parent_class; /* Fill out the info section of VipsThumbnail from the input object. */ int (*get_info)(VipsThumbnail *thumbnail); /* Open with some kind of shrink or scale factor. Exactly what we pass * and to what param depends on the loader. It'll be an integer shrink * factor for vips_jpegload(), a double scale factor for vips_svgload(). * * See VipsThumbnail::loader */ VipsImage *(*open)(VipsThumbnail *thumbnail, double factor); } VipsThumbnailClass; G_DEFINE_ABSTRACT_TYPE(VipsThumbnail, vips_thumbnail, VIPS_TYPE_OPERATION); static void vips_thumbnail_dispose(GObject *gobject) { #ifdef DEBUG printf("vips_thumbnail_dispose: "); vips_object_print_name(VIPS_OBJECT(gobject)); printf("\n"); #endif /*DEBUG*/ G_OBJECT_CLASS(vips_thumbnail_parent_class)->dispose(gobject); } static void vips_thumbnail_finalize(GObject *gobject) { #ifdef DEBUG printf("vips_thumbnail_finalize: "); vips_object_print_name(VIPS_OBJECT(gobject)); printf("\n"); #endif /*DEBUG*/ G_OBJECT_CLASS(vips_thumbnail_parent_class)->finalize(gobject); } /* Fetch an int openslide field from metadata. These are all represented as * strings. Return the default value if there's any problem. */ static int get_int(VipsImage *image, const char *field, int default_value) { const char *str; if (vips_image_get_typeof(image, field) && !vips_image_get_string(image, field, &str)) return atoi(str); return default_value; } static void vips_thumbnail_read_header(VipsThumbnail *thumbnail, VipsImage *image) { thumbnail->input_width = image->Xsize; thumbnail->input_height = image->Ysize; thumbnail->orientation = vips_image_get_orientation(image); thumbnail->swap = vips_image_get_orientation_swap(image); thumbnail->page_height = vips_image_get_page_height(image); thumbnail->n_pages = vips_image_get_n_pages(image); thumbnail->n_subifds = vips_image_get_n_subifds(image); /* VIPS_META_N_PAGES is the number of pages in the document, * not the number we've read out into this image. We calculate * ourselves from page_height. * * vips_image_get_page_height() has verified that Ysize is a simple * multiple of page_height. */ thumbnail->n_loaded_pages = thumbnail->input_height / thumbnail->page_height; /* For openslide, read out the level structure too. */ if (vips_isprefix("VipsForeignLoadOpenslide", thumbnail->loader)) { int level_count; int level; level_count = get_int(image, "openslide.level-count", 1); level_count = VIPS_CLIP(1, level_count, MAX_LEVELS); thumbnail->level_count = level_count; for (level = 0; level < level_count; level++) { char name[256]; g_snprintf(name, 256, "openslide.level[%d].width", level); thumbnail->level_width[level] = get_int(image, name, 0); g_snprintf(name, 256, "openslide.level[%d].height", level); thumbnail->level_height[level] = get_int(image, name, 0); } } } /* Detect a pyramid made of pages following a roughly /2 shrink. * * This may not be a pyr tiff, so no error if we can't find the layers. */ static void vips_thumbnail_get_pyramid_page(VipsThumbnail *thumbnail) { VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS(thumbnail); int i; #ifdef DEBUG printf("vips_thumbnail_get_pyramid_page:\n"); #endif /*DEBUG*/ /* Single-page docs can't be pyramids. */ if (thumbnail->n_pages < 2) return; for (i = 0; i < thumbnail->n_pages; i++) { VipsImage *page; int level_width; int level_height; int expected_level_width; int expected_level_height; if (!(page = class->open(thumbnail, i))) return; level_width = page->Xsize; level_height = page->Ysize; VIPS_UNREF(page); expected_level_width = thumbnail->input_width / (1 << i); expected_level_height = thumbnail->input_height / (1 << i); /* This won't be exact due to rounding etc. */ if (abs(level_width - expected_level_width) > 5 || level_width < 2) return; if (abs(level_height - expected_level_height) > 5 || level_height < 2) return; thumbnail->level_width[i] = level_width; thumbnail->level_height[i] = level_height; } /* Now set level_count. This signals that we've found a pyramid. */ #ifdef DEBUG printf("vips_thumbnail_get_pyramid_page: %d layer pyramid detected\n", thumbnail->n_pages); for (int i = 0; i < thumbnail->n_pages; i++) printf(" %d - %d x %d\n", i, thumbnail->level_width[i], thumbnail->level_height[i]); #endif /*DEBUG*/ thumbnail->level_count = thumbnail->n_pages; } /* Detect a TIFF pyramid made of subifds following a roughly /2 shrink. * * This may not be a pyr tiff, so no error if we can't find the layers. */ static void vips_thumbnail_get_tiff_pyramid_subifd(VipsThumbnail *thumbnail) { VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS(thumbnail); int i; #ifdef DEBUG printf("vips_thumbnail_get_tiff_pyramid_subifd:\n"); #endif /*DEBUG*/ for (i = 0; i < thumbnail->n_subifds; i++) { VipsImage *page; int level_width; int level_height; int expected_level_width; int expected_level_height; if (!(page = class->open(thumbnail, i))) return; level_width = page->Xsize; level_height = page->Ysize; VIPS_UNREF(page); /* The main image is size 1, subifd 0 is half that. */ expected_level_width = thumbnail->input_width / (2 << i); expected_level_height = thumbnail->input_height / (2 << i); /* This won't be exact due to rounding etc. */ if (abs(level_width - expected_level_width) > 5 || level_width < 2) return; if (abs(level_height - expected_level_height) > 5 || level_height < 2) return; thumbnail->level_width[i] = level_width; thumbnail->level_height[i] = level_height; } /* Now set level_count. This signals that we've found a pyramid. */ #ifdef DEBUG printf("vips_thumbnail_get_tiff_pyramid_subifd: " "%d layer pyramid detected\n", thumbnail->n_subifds); #endif /*DEBUG*/ thumbnail->level_count = thumbnail->n_subifds; } static int vips_thumbnail_get_heif_thumb_info(VipsThumbnail *thumbnail) { VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS(thumbnail); VipsImage *thumb; if (!(thumb = class->open(thumbnail, 1))) return -1; if (thumb->Xsize < thumbnail->input_width) { thumbnail->heif_thumbnail_width = thumb->Xsize; thumbnail->heif_thumbnail_height = thumb->Ysize; } VIPS_UNREF(thumb); return 0; } /* Calculate the shrink factor, taking into account auto-rotate, the fit mode, * and so on. * * The hshrink/vshrink are the amount to shrink the input image axes by in * order for the output axes (ie. after rotation) to match the required * thumbnail->width, thumbnail->height and fit mode. */ static void vips_thumbnail_calculate_shrink(VipsThumbnail *thumbnail, int input_width, int input_height, double *hshrink, double *vshrink) { /* If we will be rotating, swap the target width and height. */ gboolean rotate = thumbnail->swap && thumbnail->auto_rotate; int target_width = rotate ? thumbnail->height : thumbnail->width; int target_height = rotate ? thumbnail->width : thumbnail->height; VipsDirection direction; /* Calculate the horizontal and vertical shrink we'd need to fit the * image to the bounding box, and pick the biggest. * * In crop mode, we aim to fill the bounding box, so we must use the * smaller axis. */ *hshrink = (double) input_width / target_width; *vshrink = (double) input_height / target_height; if (thumbnail->crop != VIPS_INTERESTING_NONE) { if (*hshrink < *vshrink) direction = VIPS_DIRECTION_HORIZONTAL; else direction = VIPS_DIRECTION_VERTICAL; } else { if (*hshrink < *vshrink) direction = VIPS_DIRECTION_VERTICAL; else direction = VIPS_DIRECTION_HORIZONTAL; } if (thumbnail->size != VIPS_SIZE_FORCE) { if (direction == VIPS_DIRECTION_HORIZONTAL) *vshrink = *hshrink; else *hshrink = *vshrink; } if (thumbnail->size == VIPS_SIZE_UP) { *hshrink = VIPS_MIN(1, *hshrink); *vshrink = VIPS_MIN(1, *vshrink); } else if (thumbnail->size == VIPS_SIZE_DOWN) { *hshrink = VIPS_MAX(1, *hshrink); *vshrink = VIPS_MAX(1, *vshrink); } /* We don't want to shrink so much that we send an axis to 0. */ *hshrink = VIPS_MIN(*hshrink, input_width); *vshrink = VIPS_MIN(*vshrink, input_height); } /* Just the common part of the shrink: the bit by which both axes must be * shrunk. */ static double vips_thumbnail_calculate_common_shrink(VipsThumbnail *thumbnail, int width, int height) { double hshrink; double vshrink; double shrink; vips_thumbnail_calculate_shrink(thumbnail, width, height, &hshrink, &vshrink); shrink = VIPS_MIN(hshrink, vshrink); return shrink; } /* Find the best jpeg preload shrink. */ static int vips_thumbnail_find_jpegshrink(VipsThumbnail *thumbnail, int width, int height) { double shrink = vips_thumbnail_calculate_common_shrink(thumbnail, width, height); /* We can't use pre-shrunk images in linear mode. libjpeg shrinks in Y * (of YCbCR), not linear space. */ if (thumbnail->linear) return 1; /* Shrink-on-load is a simple block shrink and will add quite a bit of * extra sharpness to the image. We want to block shrink to a * bit above our target, then vips_shrink / vips_reduce() to the * final size. * * Leave at least a factor of two for the final resize step. */ if (shrink >= 16) return 8; else if (shrink >= 8) return 4; else if (shrink >= 4) return 2; else return 1; } /* Find the best pyramid (openslide, tiff, etc.) level. */ static int vips_thumbnail_find_pyrlevel(VipsThumbnail *thumbnail, int width, int height) { int level; g_assert(thumbnail->level_count > 0); g_assert(thumbnail->level_count <= MAX_LEVELS); for (level = thumbnail->level_count - 1; level >= 0; level--) { double shrink = vips_thumbnail_calculate_common_shrink(thumbnail, thumbnail->level_width[level], thumbnail->level_height[level]); // not >=, shrink can clip to 1.0 if (shrink > 1.0) return level; } return 0; } /* Open the image, returning the best version for thumbnailing. * * For example, libjpeg supports fast shrink-on-read, so if we have a JPEG, * we can ask VIPS to load a lower resolution version. */ static VipsImage * vips_thumbnail_open(VipsThumbnail *thumbnail) { VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS(thumbnail); VipsImage *im; double factor; if (class->get_info(thumbnail)) return NULL; g_info("selected loader is %s", thumbnail->loader); g_info("input size is %d x %d", thumbnail->input_width, thumbnail->input_height); /* For tiff, scan the image and try to spot page-based and ifd-based * pyramids. */ if (vips_isprefix("VipsForeignLoadTiff", thumbnail->loader)) { /* Test for a subifd pyr first, since we can do that from just * one page. */ thumbnail->subifd_pyramid = TRUE; vips_thumbnail_get_tiff_pyramid_subifd(thumbnail); if (thumbnail->level_count == 0) { thumbnail->subifd_pyramid = FALSE; thumbnail->page_pyramid = TRUE; vips_thumbnail_get_pyramid_page(thumbnail); if (thumbnail->level_count == 0) thumbnail->page_pyramid = FALSE; } } /* jp2k uses page-based pyramids. */ if (vips_isprefix("VipsForeignLoadJp2k", thumbnail->loader)) { if (thumbnail->level_count == 0) { thumbnail->subifd_pyramid = FALSE; thumbnail->page_pyramid = TRUE; vips_thumbnail_get_pyramid_page(thumbnail); if (thumbnail->level_count == 0) thumbnail->page_pyramid = FALSE; } } /* For heif, we need to fetch the thumbnail size, in case we can use * that as the source. */ if (vips_isprefix("VipsForeignLoadHeif", thumbnail->loader)) vips_thumbnail_get_heif_thumb_info(thumbnail); /* We read the openslide level structure in * vips_thumbnail_read_header(). */ factor = 1.0; if (vips_isprefix("VipsForeignLoadJpeg", thumbnail->loader) || vips_isprefix("VipsForeignLoadUhdr", thumbnail->loader)) { factor = vips_thumbnail_find_jpegshrink(thumbnail, thumbnail->input_width, thumbnail->input_height); g_info("loading with factor %g pre-shrink", factor); } else if (vips_isprefix("VipsForeignLoadTiff", thumbnail->loader) || vips_isprefix("VipsForeignLoadJp2k", thumbnail->loader) || vips_isprefix("VipsForeignLoadOpenslide", thumbnail->loader)) { if (thumbnail->level_count > 0) { factor = vips_thumbnail_find_pyrlevel(thumbnail, thumbnail->input_width, thumbnail->input_height); g_info("loading pyramid page %g", factor); } else g_info("loading with factor %g pre-shrink", factor); } else if (vips_isprefix("VipsForeignLoadWebp", thumbnail->loader)) { factor = vips_thumbnail_calculate_common_shrink(thumbnail, thumbnail->input_width, thumbnail->page_height); /* Avoid upsizing via libwebp. */ factor = VIPS_MAX(1.0, factor); g_info("loading with factor %g pre-shrink", factor); } else if (vips_isprefix("VipsForeignLoadPdf", thumbnail->loader) || vips_isprefix("VipsForeignLoadSvg", thumbnail->loader)) { factor = vips_thumbnail_calculate_common_shrink(thumbnail, thumbnail->input_width, thumbnail->page_height); g_info("loading with factor %g pre-shrink", factor); } else if (vips_isprefix("VipsForeignLoadHeif", thumbnail->loader)) { /* 'factor' is a gboolean which enables thumbnail load instead * of image load. * * Use the thumbnail if, by using it, we could get a factor > * 1.0, ie. we would not need to expand the thumbnail. * * Don't use >= since factor can be clipped to 1.0 under some * resizing modes. */ double shrink_factor = vips_thumbnail_calculate_common_shrink( thumbnail, thumbnail->heif_thumbnail_width, thumbnail->heif_thumbnail_height); factor = shrink_factor > 1.0 ? 1 : 0; if (factor == 1) g_info("selected HEIF thumbnail for shrinking"); else g_info("selected main HEIF image for shrinking"); } if (!(im = class->open(thumbnail, factor))) return NULL; g_info("pre-shrunk size is %d x %d", im->Xsize, im->Ysize); return im; } static int vips_thumbnail_build(VipsObject *object) { VipsThumbnail *thumbnail = VIPS_THUMBNAIL(object); VipsImage **t = (VipsImage **) vips_object_local_array(object, 20); VipsImage *in; int preshrunk_page_height; double hshrink; double vshrink; VipsImage *gainmap; /* TRUE if we've done the import of an ICC transform and still need to * export. */ gboolean have_imported; /* TRUE if the image needs to transformed with a pair of ICC profiles. */ gboolean needs_icc_transform; /* The format we need to revert to after unpremultiply. */ VipsBandFormat unpremultiplied_format; #ifdef DEBUG printf("vips_thumbnail_build: "); vips_object_print_name(object); printf("\n"); #endif /*DEBUG*/ if (VIPS_OBJECT_CLASS(vips_thumbnail_parent_class)->build(object)) return -1; /* We have to support both no_rotate and auto_rotate optional args, * with no_rotate being the new and not-deprecated one. * * If the new no_rotate flag has been set, that value overrides * auto_rotate. */ if (vips_object_argument_isset(object, "no_rotate")) thumbnail->auto_rotate = !thumbnail->no_rotate; // FIXME: Invalidates operation cache if (!vips_object_argument_isset(object, "height")) thumbnail->height = thumbnail->width; // FIXME: Invalidates operation cache /* Open and do any pre-shrinking. */ if (!(t[0] = vips_thumbnail_open(thumbnail))) return -1; in = t[0]; /* After pre-shrink, but before the main shrink stage. */ preshrunk_page_height = vips_image_get_page_height(in); needs_icc_transform = thumbnail->output_profile && (thumbnail->input_profile || vips_image_get_typeof(in, VIPS_META_ICC_NAME)); /* RAD needs special unpacking. */ if (in->Coding == VIPS_CODING_RAD) { g_info("unpacking Rad to float"); /* rad is scrgb. */ if (vips_rad2float(in, &t[1], NULL)) return -1; in = t[1]; } /* In linear mode, we need to transform to a linear space before * vips_resize(). */ have_imported = FALSE; if (thumbnail->linear) { /* If we are doing colour management (there's an input * profile), then we can use XYZ PCS as the resize space. */ if (in->Coding == VIPS_CODING_NONE && (in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT) && (vips_image_get_typeof(in, VIPS_META_ICC_NAME) || thumbnail->input_profile)) { g_info("importing to XYZ PCS"); if (thumbnail->input_profile) g_info("fallback input profile %s", thumbnail->input_profile); if (vips_icc_import(in, &t[2], "input_profile", thumbnail->input_profile, "embedded", TRUE, "intent", thumbnail->intent, "pcs", VIPS_PCS_XYZ, NULL)) return -1; in = t[2]; have_imported = TRUE; } else { /* Otherwise, use scRGB or GREY16 for linear shrink. */ VipsInterpretation interpretation; if (in->Bands < 3) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_scRGB; g_info("converting to processing space %s", vips_enum_nick(VIPS_TYPE_INTERPRETATION, interpretation)); if (vips_colourspace(in, &t[2], interpretation, NULL)) return -1; in = t[2]; } } else if (!needs_icc_transform) { /* In non-linear mode, use sRGB or B_W as the processing space * but only when not transforming with a pair of ICC profiles. */ VipsInterpretation interpretation; if (in->Bands < 3) interpretation = VIPS_INTERPRETATION_B_W; else interpretation = VIPS_INTERPRETATION_sRGB; g_info("converting to processing space %s", vips_enum_nick(VIPS_TYPE_INTERPRETATION, interpretation)); if (vips_colourspace(in, &t[2], interpretation, NULL)) return -1; in = t[2]; } /* Shrink to preshrunk_page_height, so we work for multi-page images. */ vips_thumbnail_calculate_shrink(thumbnail, in->Xsize, preshrunk_page_height, &hshrink, &vshrink); /* In toilet-roll mode, we must adjust vshrink so that we exactly hit * page_height or we'll have pixels straddling page boundaries. */ if (in->Ysize > preshrunk_page_height) { int target_page_height = rint(preshrunk_page_height / vshrink); int target_image_height = target_page_height * thumbnail->n_loaded_pages; vshrink = (double) in->Ysize / target_image_height; } /* Both vips_premultiply() and vips_unpremultiply() produces a float * image, so we must cast back to the original format. Use NOTSET * to mean no pre/unmultiply. */ unpremultiplied_format = VIPS_FORMAT_NOTSET; /* If there's an alpha, we have to premultiply before shrinking. See * https://github.com/libvips/libvips/issues/291 */ if (vips_image_hasalpha(in) && hshrink != 1.0 && vshrink != 1.0) { g_info("premultiplying alpha"); unpremultiplied_format = in->BandFmt; if (vips_premultiply(in, &t[3], NULL) || vips_cast(t[3], &t[4], unpremultiplied_format, NULL)) return -1; in = t[4]; } if (vips_resize(in, &t[5], 1.0 / hshrink, "vscale", 1.0 / vshrink, NULL)) return -1; in = t[5]; /* Also resize the gainmap, if any. */ if ((gainmap = vips_image_get_gainmap(in))) { if (vips_resize(gainmap, &t[15], 1.0 / hshrink, "vscale", 1.0 / vshrink, "kernel", VIPS_KERNEL_LINEAR, NULL)) return -1; g_object_unref(gainmap); /* Make sure we don't have a shared image. */ if (vips_copy(in, &t[8], NULL)) return -1; in = t[8]; vips_image_set_image(in, "gainmap", t[15]); } if (unpremultiplied_format != VIPS_FORMAT_NOTSET) { g_info("unpremultiplying alpha"); if (vips_unpremultiply(in, &t[6], NULL) || vips_cast(t[6], &t[7], unpremultiplied_format, NULL)) return -1; in = t[7]; } /* Only set page-height if we have more than one page, or this could * accidentally turn into an animated image later. */ if (thumbnail->n_loaded_pages > 1) { int output_page_height = rint(preshrunk_page_height / vshrink); /* Make sure we don't have a shared image. */ if (vips_copy(in, &t[8], NULL)) return -1; in = t[8]; vips_image_set_int(in, VIPS_META_PAGE_HEIGHT, output_page_height); } /* Colour management. * * We always export as depth 8, to match the no profile case which * uses vips_colourspace(sRGB|B_W). */ if (have_imported) { /* We are in PCS. Export with the output profile, if any (this * will export with the embedded input profile if there's no * output profile). */ g_info("exporting to device space with a profile"); if (vips_icc_export(in, &t[9], "output_profile", thumbnail->output_profile, "intent", thumbnail->intent, "depth", 8, NULL)) return -1; in = t[9]; } else if (needs_icc_transform) { /* We can transform to the output with a pair of ICC profiles. */ g_info("transforming with supplied profiles"); if (vips_icc_transform(in, &t[9], thumbnail->output_profile, "input_profile", thumbnail->input_profile, "intent", thumbnail->intent, "embedded", TRUE, "depth", 8, NULL)) return -1; in = t[9]; } else if (thumbnail->output_profile) { /* We are in one of the resize space (sRGB, scRGB, B_W, GREY16, etc.) * and need to go to PCS, then export. */ g_info("exporting with %s", thumbnail->output_profile); if (vips_colourspace(in, &t[9], VIPS_INTERPRETATION_XYZ, NULL) || vips_icc_export(t[9], &t[10], "output_profile", thumbnail->output_profile, "intent", thumbnail->intent, "depth", 8, NULL)) return -1; in = t[10]; } else if (thumbnail->linear) { /* We are in one of the scRGB or GREY16 spaces and there's * no output profile. Output to sRGB or B_W. */ VipsInterpretation interpretation; if (in->Bands < 3) interpretation = VIPS_INTERPRETATION_B_W; else interpretation = VIPS_INTERPRETATION_sRGB; g_info("converting to output space %s", vips_enum_nick(VIPS_TYPE_INTERPRETATION, interpretation)); if (vips_colourspace(in, &t[9], interpretation, NULL)) return -1; in = t[9]; } if (thumbnail->auto_rotate && thumbnail->orientation != 1) { g_info("rotating by EXIF orientation %d", thumbnail->orientation); /* Need to copy to memory, we have to stay seq. */ if (!(t[11] = vips_image_copy_memory(in)) || vips_autorot(t[11], &t[12], NULL)) return -1; in = t[12]; /* Also rotate the gainmap, if any. */ if ((gainmap = vips_image_get_gainmap(in))) { vips_image_set_int(gainmap, VIPS_META_ORIENTATION, thumbnail->orientation); if (vips_autorot(gainmap, &t[17], NULL)) return -1; g_object_unref(gainmap); vips_image_set_image(in, "gainmap", t[17]); } } /* Crop after rotate so we don't need to rotate the crop box. */ if (thumbnail->crop != VIPS_INTERESTING_NONE) { /* The image can be smaller than the target. Adjust the * arguments to vips_smartcrop(). */ int crop_width = VIPS_MIN(thumbnail->width, in->Xsize); int crop_height = VIPS_MIN(thumbnail->height, in->Ysize); int original_width = in->Xsize; int original_height = in->Ysize; g_info("cropping to %dx%d", crop_width, crop_height); /* Need to copy to memory, we have to stay seq. * * FIXME ... could skip the copy if we've rotated. */ if (!(t[13] = vips_image_copy_memory(in)) || vips_smartcrop(t[13], &t[14], crop_width, crop_height, "interesting", thumbnail->crop, NULL)) return -1; in = t[14]; int crop_left = -vips_image_get_xoffset(in); int crop_top = -vips_image_get_yoffset(in); /* Also crop the gainmap, if any. */ if ((gainmap = vips_image_get_gainmap(in))) { double xscale = (double) gainmap->Xsize / original_width; double yscale = (double) gainmap->Ysize / original_height; if (vips_crop(gainmap, &t[16], crop_left * xscale, crop_top * yscale, crop_width * xscale, crop_height * yscale, NULL)) return -1; g_object_unref(gainmap); vips_image_set_image(in, "gainmap", t[16]); } } g_object_set(thumbnail, "out", vips_image_new(), NULL); if (vips_image_write(in, thumbnail->out)) return -1; return 0; } static void vips_thumbnail_class_init(VipsThumbnailClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); gobject_class->dispose = vips_thumbnail_dispose; gobject_class->finalize = vips_thumbnail_finalize; gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "thumbnail_base"; vobject_class->description = _("thumbnail generation"); vobject_class->build = vips_thumbnail_build; /* We mustn't cache these calls, since we open the file or buffer in * sequential mode. */ operation_class->flags |= VIPS_OPERATION_NOCACHE; VIPS_ARG_IMAGE(class, "out", 2, _("Output"), _("Output image"), VIPS_ARGUMENT_REQUIRED_OUTPUT, G_STRUCT_OFFSET(VipsThumbnail, out)); VIPS_ARG_INT(class, "width", 3, _("Target width"), _("Size to this width"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsThumbnail, width), 1, VIPS_MAX_COORD, 1); VIPS_ARG_INT(class, "height", 113, _("Target height"), _("Size to this height"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, height), 1, VIPS_MAX_COORD, 1); VIPS_ARG_ENUM(class, "size", 114, _("Size"), _("Only upsize, only downsize, or both"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, size), VIPS_TYPE_SIZE, VIPS_SIZE_BOTH); VIPS_ARG_BOOL(class, "no_rotate", 115, _("No rotate"), _("Don't use orientation tags to rotate image upright"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, no_rotate), FALSE); VIPS_ARG_ENUM(class, "crop", 116, _("Crop"), _("Reduce to fill target rectangle, then crop"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, crop), VIPS_TYPE_INTERESTING, VIPS_INTERESTING_NONE); VIPS_ARG_BOOL(class, "linear", 117, _("Linear"), _("Reduce in linear light"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, linear), FALSE); VIPS_ARG_STRING(class, "input_profile", 118, _("Input profile"), _("Fallback input profile"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, input_profile), NULL); VIPS_ARG_STRING(class, "output_profile", 119, _("Output profile"), _("Fallback output profile"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, output_profile), NULL); VIPS_ARG_ENUM(class, "intent", 120, _("Intent"), _("Rendering intent"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, intent), VIPS_TYPE_INTENT, VIPS_INTENT_RELATIVE); VIPS_ARG_ENUM(class, "fail_on", 121, _("Fail on"), _("Error level to fail on"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnail, fail_on), VIPS_TYPE_FAIL_ON, VIPS_FAIL_ON_NONE); /* BOOL args which default TRUE arguments don't work with the * command-line -- GOption does not allow --auto-rotate=false. * * This is now replaced (though still functional) with "no-rotate", * see above. */ VIPS_ARG_BOOL(class, "auto_rotate", 130, _("Auto rotate"), _("Use orientation tags to rotate image upright"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsThumbnail, auto_rotate), TRUE); /* Renamed as input-profile and output-profile for consistency with the * rest of the API. */ VIPS_ARG_STRING(class, "import_profile", 131, _("Import profile"), _("Fallback import profile"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsThumbnail, input_profile), NULL); VIPS_ARG_STRING(class, "export_profile", 132, _("Export profile"), _("Fallback export profile"), VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, G_STRUCT_OFFSET(VipsThumbnail, output_profile), NULL); } static void vips_thumbnail_init(VipsThumbnail *thumbnail) { thumbnail->width = 1; thumbnail->height = 1; thumbnail->auto_rotate = TRUE; thumbnail->intent = VIPS_INTENT_RELATIVE; thumbnail->fail_on = VIPS_FAIL_ON_NONE; } typedef struct _VipsThumbnailFile { VipsThumbnail parent_object; char *filename; } VipsThumbnailFile; typedef VipsThumbnailClass VipsThumbnailFileClass; G_DEFINE_TYPE(VipsThumbnailFile, vips_thumbnail_file, vips_thumbnail_get_type()); /* Get the info from a file. */ static int vips_thumbnail_file_get_info(VipsThumbnail *thumbnail) { VipsThumbnailFile *file = (VipsThumbnailFile *) thumbnail; VipsImage *image; g_info("thumbnailing %s", file->filename); if (!(thumbnail->loader = vips_foreign_find_load(file->filename)) || !(image = vips_image_new_from_file(file->filename, NULL))) return -1; vips_thumbnail_read_header(thumbnail, image); g_object_unref(image); return 0; } /* Open an image, pre-shrinking as appropriate. */ static VipsImage * vips_thumbnail_file_open(VipsThumbnail *thumbnail, double factor) { VipsThumbnailFile *file = (VipsThumbnailFile *) thumbnail; if (vips_isprefix("VipsForeignLoadJpeg", thumbnail->loader) || vips_isprefix("VipsForeignLoadUhdr", thumbnail->loader)) { return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "shrink", (int) factor, NULL); } else if (vips_isprefix("VipsForeignLoadOpenslide", thumbnail->loader)) { return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "level", (int) factor, NULL); } else if (vips_isprefix("VipsForeignLoadPdf", thumbnail->loader) || vips_isprefix("VipsForeignLoadSvg", thumbnail->loader) || vips_isprefix("VipsForeignLoadWebp", thumbnail->loader)) { return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "scale", 1.0 / factor, NULL); } else if (vips_isprefix("VipsForeignLoadJp2k", thumbnail->loader)) { /* jp2k optionally uses page-based pyramids. */ if (thumbnail->page_pyramid) return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "page", (int) factor, NULL); else return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } else if (vips_isprefix("VipsForeignLoadTiff", thumbnail->loader)) { /* We support three modes: subifd pyramids, page-based * pyramids, and simple multi-page TIFFs (no pyramid). */ if (thumbnail->subifd_pyramid) return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "subifd", (int) factor, NULL); else if (thumbnail->page_pyramid) return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "page", (int) factor, NULL); else return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, NULL); } else if (vips_isprefix("VipsForeignLoadHeif", thumbnail->loader)) { return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, "thumbnail", (int) factor, NULL); } else { return vips_image_new_from_file(file->filename, "access", VIPS_ACCESS_SEQUENTIAL, "fail_on", thumbnail->fail_on, NULL); } } static void vips_thumbnail_file_class_init(VipsThumbnailClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsThumbnailClass *thumbnail_class = VIPS_THUMBNAIL_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "thumbnail"; vobject_class->description = _("generate thumbnail from file"); thumbnail_class->get_info = vips_thumbnail_file_get_info; thumbnail_class->open = vips_thumbnail_file_open; VIPS_ARG_STRING(class, "filename", 1, _("Filename"), _("Filename to read from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsThumbnailFile, filename), NULL); } static void vips_thumbnail_file_init(VipsThumbnailFile *file) { } /** * vips_thumbnail: * @filename: file to read from * @out: (out): output image * @width: target width in pixels * @...: `NULL`-terminated list of optional named arguments * * Make a thumbnail from a file. * * Shrinking is done in three stages: using any * shrink-on-load features available in the image load library, using a block * shrink, and using a lanczos3 shrink. At least the final 200% is done with * lanczos3. The output should be high quality, and the operation should be * quick. * * See [ctor@Image.thumbnail_buffer] to thumbnail from a memory buffer, or * [ctor@Image.thumbnail_source] to thumbnail from an arbitrary byte source. * * By default, libvips will only use the first frame of animated or multipage * images. To thumbnail all pages or frames, pass `n=-1` to the loader in * @filename, for example `"x.gif[n=-1]"`. * * The output image will fit within a square of size @width x @width. You can * specify a separate height with the @height option. Set either @width or * @height to a very large number to ignore that dimension. * * If you set @crop, then the output image will fill the whole of the @width x * @height rectangle, with any excess cropped away. See [method@Image.smartcrop] for * details on the cropping strategy. * * Normally the operation will upsize or downsize as required to fit the image * inside or outside the target size. If @size is set to [enum@Vips.Size.UP], * the operation will only upsize and will just copy if asked to downsize. * If @size is set to [enum@Vips.Size.DOWN], the operation will only downsize * and will just copy if asked to upsize. * If @size is [enum@Vips.Size.FORCE], the image aspect ratio will be broken * and the image will be forced to fit the target. * * Normally any orientation tags on the input image (such as EXIF tags) are * interpreted to rotate the image upright. If you set @no_rotate to `TRUE`, * these tags will not be interpreted. * * Shrinking is normally done in sRGB colourspace. Set @linear to shrink in * linear light colourspace instead. This can give better results, but can * also be far slower, since tricks like JPEG shrink-on-load cannot be used in * linear space. * * If you set @output_profile to the filename of an ICC profile, the image * will be transformed to the target colourspace before writing to the * output. You can also give an @input_profile which will be used if the * input image has no ICC profile, or if the profile embedded in the * input image is broken. * * Use @intent to set the rendering intent for any ICC transform. The default * is [enum@Vips.Intent.RELATIVE]. * * Use @fail_on to control the types of error that will cause loading to fail. * The default is [enum@Vips.FailOn.NONE], ie. thumbnail is permissive. * * ::: tip "Optional arguments" * * @height: `gint`, target height in pixels * * @size: [enum@Size], upsize, downsize, both or force * * @no_rotate: `gboolean`, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: `gboolean`, perform shrink in linear light * * @input_profile: `gchararray`, fallback input ICC profile * * @output_profile: `gchararray`, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * * ::: seealso * [ctor@Image.thumbnail_buffer]. * * Returns: 0 on success, -1 on error. */ int vips_thumbnail(const char *filename, VipsImage **out, int width, ...) { va_list ap; int result; va_start(ap, width); result = vips_call_split("thumbnail", ap, filename, out, width); va_end(ap); return result; } typedef struct _VipsThumbnailBuffer { VipsThumbnail parent_object; VipsArea *buf; char *option_string; } VipsThumbnailBuffer; typedef VipsThumbnailClass VipsThumbnailBufferClass; G_DEFINE_TYPE(VipsThumbnailBuffer, vips_thumbnail_buffer, vips_thumbnail_get_type()); /* Get the info from a buffer. */ static int vips_thumbnail_buffer_get_info(VipsThumbnail *thumbnail) { VipsThumbnailBuffer *buffer = (VipsThumbnailBuffer *) thumbnail; VipsImage *image; g_info("thumbnailing %zd bytes of data", buffer->buf->length); if (!(thumbnail->loader = vips_foreign_find_load_buffer( buffer->buf->data, buffer->buf->length)) || !(image = vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, NULL))) return -1; vips_thumbnail_read_header(thumbnail, image); g_object_unref(image); return 0; } /* Open an image, scaling as appropriate. */ static VipsImage * vips_thumbnail_buffer_open(VipsThumbnail *thumbnail, double factor) { VipsThumbnailBuffer *buffer = (VipsThumbnailBuffer *) thumbnail; if (vips_isprefix("VipsForeignLoadJpeg", thumbnail->loader) || vips_isprefix("VipsForeignLoadUhdr", thumbnail->loader)) { return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", (int) factor, NULL); } else if (vips_isprefix("VipsForeignLoadOpenslide", thumbnail->loader)) { return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "level", (int) factor, NULL); } else if (vips_isprefix("VipsForeignLoadPdf", thumbnail->loader) || vips_isprefix("VipsForeignLoadSvg", thumbnail->loader) || vips_isprefix("VipsForeignLoadWebp", thumbnail->loader)) { return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "scale", 1.0 / factor, NULL); } else if (vips_isprefix("VipsForeignLoadJp2k", thumbnail->loader)) { /* Optional page-based pyramids. */ if (thumbnail->page_pyramid) return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "page", (int) factor, NULL); else return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } else if (vips_isprefix("VipsForeignLoadTiff", thumbnail->loader)) { /* We support three modes: subifd pyramids, page-based * pyramids, and simple multi-page TIFFs (no pyramid). */ if (thumbnail->subifd_pyramid) return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "subifd", (int) factor, NULL); else if (thumbnail->page_pyramid) return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "page", (int) factor, NULL); else return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } else if (vips_isprefix("VipsForeignLoadHeif", thumbnail->loader)) { return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "thumbnail", (int) factor, NULL); } else { return vips_image_new_from_buffer( buffer->buf->data, buffer->buf->length, buffer->option_string, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } } static void vips_thumbnail_buffer_class_init(VipsThumbnailClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsThumbnailClass *thumbnail_class = VIPS_THUMBNAIL_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "thumbnail_buffer"; vobject_class->description = _("generate thumbnail from buffer"); thumbnail_class->get_info = vips_thumbnail_buffer_get_info; thumbnail_class->open = vips_thumbnail_buffer_open; VIPS_ARG_BOXED(class, "buffer", 1, _("Buffer"), _("Buffer to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsThumbnailBuffer, buf), VIPS_TYPE_BLOB); VIPS_ARG_STRING(class, "option_string", 20, _("Extra options"), _("Options that are passed on to the underlying loader"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnailBuffer, option_string), ""); } static void vips_thumbnail_buffer_init(VipsThumbnailBuffer *buffer) { } /** * vips_thumbnail_buffer: * @buf: (array length=len) (element-type guint8): memory area to load * @len: (type gsize): size of memory area * @out: (out): output image * @width: target width in pixels * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.thumbnail], but read from a memory buffer. * * One extra optional argument, @option_string, lets you pass options to the * underlying loader. * * ::: tip "Optional arguments" * * @height: `gint`, target height in pixels * * @size: [enum@Size], upsize, downsize, both or force * * @no_rotate: `gboolean`, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: `gboolean`, perform shrink in linear light * * @input_profile: `gchararray`, fallback input ICC profile * * @output_profile: `gchararray`, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * * @option_string: `gchararray`, extra loader options * * ::: seealso * [ctor@Image.thumbnail]. * * Returns: 0 on success, -1 on error. */ int vips_thumbnail_buffer(void *buf, size_t len, VipsImage **out, int width, ...) { va_list ap; VipsBlob *blob; int result; /* We don't take a copy of the data or free it. */ blob = vips_blob_new(NULL, buf, len); va_start(ap, width); result = vips_call_split("thumbnail_buffer", ap, blob, out, width); va_end(ap); vips_area_unref(VIPS_AREA(blob)); return result; } typedef struct _VipsThumbnailSource { VipsThumbnail parent_object; VipsSource *source; char *option_string; } VipsThumbnailSource; typedef VipsThumbnailClass VipsThumbnailSourceClass; G_DEFINE_TYPE(VipsThumbnailSource, vips_thumbnail_source, vips_thumbnail_get_type()); /* Get the info from a source. */ static int vips_thumbnail_source_get_info(VipsThumbnail *thumbnail) { VipsThumbnailSource *source = (VipsThumbnailSource *) thumbnail; VipsImage *image; g_info("thumbnailing source"); if (!(thumbnail->loader = vips_foreign_find_load_source(source->source)) || !(image = vips_image_new_from_source(source->source, source->option_string, NULL))) return -1; vips_thumbnail_read_header(thumbnail, image); g_object_unref(image); return 0; } /* Open an image, scaling as appropriate. */ static VipsImage * vips_thumbnail_source_open(VipsThumbnail *thumbnail, double factor) { VipsThumbnailSource *source = (VipsThumbnailSource *) thumbnail; if (vips_isprefix("VipsForeignLoadJpeg", thumbnail->loader) || vips_isprefix("VipsForeignLoadUhdr", thumbnail->loader)) { return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", (int) factor, NULL); } else if (vips_isprefix("VipsForeignLoadOpenslide", thumbnail->loader)) { return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "level", (int) factor, NULL); } else if (vips_isprefix("VipsForeignLoadPdf", thumbnail->loader) || vips_isprefix("VipsForeignLoadSvg", thumbnail->loader) || vips_isprefix("VipsForeignLoadWebp", thumbnail->loader)) { return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "scale", 1.0 / factor, NULL); } else if (vips_isprefix("VipsForeignLoadJp2k", thumbnail->loader)) { /* Optional page-based pyramids. */ if (thumbnail->page_pyramid) return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "page", (int) factor, NULL); else return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } else if (vips_isprefix("VipsForeignLoadTiff", thumbnail->loader)) { /* We support three modes: subifd pyramids, page-based * pyramids, and simple multi-page TIFFs (no pyramid). */ if (thumbnail->subifd_pyramid) return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "subifd", (int) factor, NULL); else if (thumbnail->page_pyramid) return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "page", (int) factor, NULL); else return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } else if (vips_isprefix("VipsForeignLoadHeif", thumbnail->loader)) { return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, "thumbnail", (int) factor, NULL); } else { return vips_image_new_from_source( source->source, source->option_string, "access", VIPS_ACCESS_SEQUENTIAL, NULL); } } static void vips_thumbnail_source_class_init(VipsThumbnailClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsThumbnailClass *thumbnail_class = VIPS_THUMBNAIL_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "thumbnail_source"; vobject_class->description = _("generate thumbnail from source"); thumbnail_class->get_info = vips_thumbnail_source_get_info; thumbnail_class->open = vips_thumbnail_source_open; VIPS_ARG_OBJECT(class, "source", 1, _("Source"), _("Source to load from"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsThumbnailSource, source), VIPS_TYPE_SOURCE); VIPS_ARG_STRING(class, "option_string", 20, _("Extra options"), _("Options that are passed on to the underlying loader"), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET(VipsThumbnailSource, option_string), ""); } static void vips_thumbnail_source_init(VipsThumbnailSource *source) { } /** * vips_thumbnail_source: * @source: source to thumbnail * @out: (out): output image * @width: target width in pixels * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.thumbnail], but read from a source. * * One extra * optional argument, @option_string, lets you pass options to the underlying * loader. * * ::: tip "Optional arguments" * * @height: `gint`, target height in pixels * * @size: [enum@Size], upsize, downsize, both or force * * @no_rotate: `gboolean`, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: `gboolean`, perform shrink in linear light * * @input_profile: `gchararray`, fallback input ICC profile * * @output_profile: `gchararray`, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * * @option_string: `gchararray`, extra loader options * * ::: seealso * [ctor@Image.thumbnail]. * * Returns: 0 on success, -1 on error. */ int vips_thumbnail_source(VipsSource *source, VipsImage **out, int width, ...) { va_list ap; int result; va_start(ap, width); result = vips_call_split("thumbnail_source", ap, source, out, width); va_end(ap); return result; } typedef struct _VipsThumbnailImage { VipsThumbnail parent_object; VipsImage *in; } VipsThumbnailImage; typedef VipsThumbnailClass VipsThumbnailImageClass; G_DEFINE_TYPE(VipsThumbnailImage, vips_thumbnail_image, vips_thumbnail_get_type()); /* Get the info from a image. */ static int vips_thumbnail_image_get_info(VipsThumbnail *thumbnail) { VipsThumbnailImage *image = (VipsThumbnailImage *) thumbnail; /* Doesn't really matter what we put here. */ thumbnail->loader = "image source"; vips_thumbnail_read_header(thumbnail, image->in); return 0; } /* Open an image. We can't pre-shrink with an image source, sadly. */ static VipsImage * vips_thumbnail_image_open(VipsThumbnail *thumbnail, double factor) { VipsThumbnailImage *image = (VipsThumbnailImage *) thumbnail; g_object_ref(image->in); return image->in; } static void vips_thumbnail_image_class_init(VipsThumbnailClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS(class); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); VipsOperationClass *operation_class = VIPS_OPERATION_CLASS(class); VipsThumbnailClass *thumbnail_class = VIPS_THUMBNAIL_CLASS(class); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; vobject_class->nickname = "thumbnail_image"; vobject_class->description = _("generate thumbnail from image"); operation_class->flags = VIPS_OPERATION_SEQUENTIAL; thumbnail_class->get_info = vips_thumbnail_image_get_info; thumbnail_class->open = vips_thumbnail_image_open; VIPS_ARG_IMAGE(class, "in", 1, _("Input"), _("Input image argument"), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET(VipsThumbnailImage, in)); } static void vips_thumbnail_image_init(VipsThumbnailImage *image) { } /** * vips_thumbnail_image: (method) * @in: input image * @out: (out): output image * @width: target width in pixels * @...: `NULL`-terminated list of optional named arguments * * Exactly as [ctor@Image.thumbnail], but read from an existing image. * * This operation * is not able to exploit shrink-on-load features of image load libraries, so * it can be much slower than [ctor@Image.thumbnail] and produce poorer quality * output. Only use this operation if you really have to. * * ::: tip "Optional arguments" * * @height: `gint`, target height in pixels * * @size: [enum@Size], upsize, downsize, both or force * * @no_rotate: `gboolean`, don't rotate upright using orientation tag * * @crop: [enum@Interesting], shrink and crop to fill target * * @linear: `gboolean`, perform shrink in linear light * * @input_profile: `gchararray`, fallback input ICC profile * * @output_profile: `gchararray`, output ICC profile * * @intent: [enum@Intent], rendering intent * * @fail_on: [enum@FailOn], load error types to fail on * * ::: seealso * [ctor@Image.thumbnail]. * * Returns: 0 on success, -1 on error. */ int vips_thumbnail_image(VipsImage *in, VipsImage **out, int width, ...) { va_list ap; int result; va_start(ap, width); result = vips_call_split("thumbnail_image", ap, in, out, width); va_end(ap); return result; } libvips-8.18.2/libvips/resample/transform.c000066400000000000000000000142551516303661500207360ustar00rootroot00000000000000/* affine transforms */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include #include #include #include /* DBL_MIN is smallest *normalized* double precision float */ #define TOO_SMALL (2.0 * DBL_MIN) /* Calculate the inverse transformation. */ int vips__transform_calc_inverse(VipsTransformation *trn) { double det = trn->a * trn->d - trn->b * trn->c; if (fabs(det) < TOO_SMALL) { /* divisor is near zero */ vips_error("vips__transform_calc_inverse", "%s", _("singular or near-singular matrix")); return -1; } double tmp = 1.0 / det; trn->ia = tmp * trn->d; trn->ib = -tmp * trn->b; trn->ic = -tmp * trn->c; trn->id = tmp * trn->a; return 0; } /* Init a VipsTransform. */ void vips__transform_init(VipsTransformation *trn) { trn->oarea.left = 0; trn->oarea.top = 0; trn->oarea.width = -1; trn->oarea.height = -1; trn->iarea.left = 0; trn->iarea.top = 0; trn->iarea.width = -1; trn->iarea.height = -1; trn->a = 1.0; /* Identity transform */ trn->b = 0.0; trn->c = 0.0; trn->d = 1.0; trn->idx = 0.0; trn->idy = 0.0; trn->odx = 0.0; trn->ody = 0.0; (void) vips__transform_calc_inverse(trn); } /* Test for transform is identity function. */ int vips__transform_isidentity(const VipsTransformation *trn) { if (trn->a == 1.0 && trn->b == 0.0 && trn->c == 0.0 && trn->d == 1.0 && trn->idx == 0.0 && trn->idy == 0.0 && trn->odx == 0.0 && trn->ody == 0.0) return 1; else return 0; } /* Combine two transformations. out can be one of the ins. */ int vips__transform_add(const VipsTransformation *in1, const VipsTransformation *in2, VipsTransformation *out) { out->a = in1->a * in2->a + in1->c * in2->b; out->b = in1->b * in2->a + in1->d * in2->b; out->c = in1->a * in2->c + in1->c * in2->d; out->d = in1->b * in2->c + in1->d * in2->d; // fixme: do idx/idy as well out->odx = in1->odx * in2->a + in1->ody * in2->b + in2->odx; out->ody = in1->odx * in2->c + in1->ody * in2->d + in2->ody; if (vips__transform_calc_inverse(out)) return -1; return 0; } void vips__transform_print(const VipsTransformation *trn) { printf("vips__transform_print:\n"); printf(" iarea: left=%d, top=%d, width=%d, height=%d\n", trn->iarea.left, trn->iarea.top, trn->iarea.width, trn->iarea.height); printf(" oarea: left=%d, top=%d, width=%d, height=%d\n", trn->oarea.left, trn->oarea.top, trn->oarea.width, trn->oarea.height); printf(" mat: a=%g, b=%g, c=%g, d=%g\n", trn->a, trn->b, trn->c, trn->d); printf(" off: odx=%g, ody=%g, idx=%g, idy=%g\n", trn->odx, trn->ody, trn->idx, trn->idy); } /* Map a pixel coordinate through the transform. */ void vips__transform_forward_point(const VipsTransformation *trn, double x, double y, /* In input space */ double *ox, double *oy) /* In output space */ { x += trn->idx; y += trn->idy; *ox = trn->a * x + trn->b * y + trn->odx; *oy = trn->c * x + trn->d * y + trn->ody; } /* Map a pixel coordinate through the inverse transform. */ void vips__transform_invert_point(const VipsTransformation *trn, double x, double y, /* In output space */ double *ox, double *oy) /* In input space */ { x -= trn->odx; y -= trn->ody; *ox = trn->ia * x + trn->ib * y - trn->idx; *oy = trn->ic * x + trn->id * y - trn->idy; } typedef void (*transform_fn)(const VipsTransformation *, const double, const double, double *, double *); /* Transform a rect using a point transformer. */ static void transform_rect(const VipsTransformation *trn, transform_fn transform, const VipsRect *in, /* In input space */ VipsRect *out) /* In output space */ { double x1, y1; /* Map corners */ double x2, y2; double x3, y3; double x4, y4; double left, right, top, bottom; /* Map input VipsRect. */ transform(trn, in->left, in->top, &x1, &y1); transform(trn, in->left, VIPS_RECT_BOTTOM(in), &x3, &y3); transform(trn, VIPS_RECT_RIGHT(in), in->top, &x2, &y2); transform(trn, VIPS_RECT_RIGHT(in), VIPS_RECT_BOTTOM(in), &x4, &y4); /* Find bounding box for these four corners. Round-to-nearest to try * to stop rounding errors growing images. */ left = VIPS_MIN(x1, VIPS_MIN(x2, VIPS_MIN(x3, x4))); right = VIPS_MAX(x1, VIPS_MAX(x2, VIPS_MAX(x3, x4))); top = VIPS_MIN(y1, VIPS_MIN(y2, VIPS_MIN(y3, y4))); bottom = VIPS_MAX(y1, VIPS_MAX(y2, VIPS_MAX(y3, y4))); out->left = VIPS_ROUND_INT(left); out->top = VIPS_ROUND_INT(top); out->width = VIPS_ROUND_INT(right - left); out->height = VIPS_ROUND_INT(bottom - top); } /* Given an area in the input image, calculate the bounding box for those * pixels in the output image. */ void vips__transform_forward_rect(const VipsTransformation *trn, const VipsRect *in, /* In input space */ VipsRect *out) /* In output space */ { transform_rect(trn, vips__transform_forward_point, in, out); } /* Given an area in the output image, calculate the bounding box for the * corresponding pixels in the input image. */ void vips__transform_invert_rect(const VipsTransformation *trn, const VipsRect *in, /* In output space */ VipsRect *out) /* In input space */ { transform_rect(trn, vips__transform_invert_point, in, out); } /* Set output area of trn so that it just holds all of our input pels. */ void vips__transform_set_area(VipsTransformation *trn) { vips__transform_forward_rect(trn, &trn->iarea, &trn->oarea); } libvips-8.18.2/libvips/resample/vsqbs.cpp000066400000000000000000000266101516303661500204170ustar00rootroot00000000000000/* vertex-split subdivision followed by quadratic b-spline smoothing * * C. Racette 23-28/05/2010 based on code by N. Robidoux and J. Cupitt * * N. Robidoux 29-30/05/2010 */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* * 2010 (c) Chantal Racette, Nicolas Robidoux, John Cupitt. * * Nicolas Robidoux thanks Adam Turcotte, Geert Jordaens, Ralf Meyer, * Øyvind Kolås, Minglun Gong and Eric Daoust for useful comments and * code. * * Chantal Racette's image resampling research and programming funded * in part by a NSERC Discovery Grant awarded to Julien Dompierre * (20-61098). */ /* * Vertex-Split Quadratic B-Splines (VSQBS) is a brand new method * which consists of vertex-split subdivision, a subdivision method * with the (as yet unknown?) property that data which is (locally) * constant on diagonals is subdivided into data which is (locally) * constant on diagonals, followed by quadratic B-Spline smoothing. * Because both methods are linear, their combination can be * implemented as if there is no subdivision. * * At high enlargement ratios, VSQBS is very effective at "masking" * that the original has pixels uniformly distributed on a grid. In * particular, VSQBS produces resamples with only very mild * staircasing. Like cubic B-Spline smoothing, however, VSQBS is not * an interpolatory method. For example, using VSQBS to perform the * identity geometric transformation (enlargement by a scaling factor * equal to 1) on an image does not return the original: VSQBS * effectively smooths out the image with the convolution mask * * 1/8 * 1/8 1/2 1/8 * 1/8 * * which is a fairly moderate blur (although the checkerboard mode is * in its nullspace). * * By blending VSQBS with an interpolatory method (bilinear, say) in a * transformation adaptive environment (current GEGL, for example), it * is quite easy to restore that resampling for identity geometric * transformation is equivalent to the identity, and rotations are not * affected by the above, implicit, blur. Contact N. Robidoux for * details. * * An article on VSQBS is forthcoming. */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "templates.h" #define VIPS_TYPE_INTERPOLATE_VSQBS \ (vips_interpolate_vsqbs_get_type()) #define VIPS_INTERPOLATE_VSQBS(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), \ VIPS_TYPE_INTERPOLATE_VSQBS, VipsInterpolateVsqbs)) #define VIPS_INTERPOLATE_VSQBS_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ VIPS_TYPE_INTERPOLATE_VSQBS, VipsInterpolateVsqbsClass)) #define VIPS_IS_INTERPOLATE_VSQBS(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIPS_TYPE_INTERPOLATE_VSQBS)) #define VIPS_IS_INTERPOLATE_VSQBS_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), VIPS_TYPE_INTERPOLATE_VSQBS)) #define VIPS_INTERPOLATE_VSQBS_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), \ VIPS_TYPE_INTERPOLATE_VSQBS, VipsInterpolateVsqbsClass)) typedef struct _VipsInterpolateVsqbs { VipsInterpolate parent_object; } VipsInterpolateVsqbs; typedef struct _VipsInterpolateVsqbsClass { VipsInterpolateClass parent_class; } VipsInterpolateVsqbsClass; /* * THE STENCIL OF INPUT VALUES: * * Pointer arithmetic is used to implicitly reflect the input stencil * about dos_two---assumed closer to the sampling location than other * pixels (ties are OK)---in such a way that after reflection the * sampling point is to the bottom right of dos_two. * * The following code and picture assumes that the stencil reflexion * has already been performed. (X is the sampling location.) * * * (ix,iy-1) (ix+1,iy-1) * = uno_two = uno_thr * * * * (ix-1,iy) (ix,iy) (ix+1,iy) * = dos_one = dos_two = dos_thr * X * * * (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1) * = tre_one = tre_two = tre_thr * * * The above input pixel values are the ones needed in order to * IMPLICITLY make available the following values, needed by quadratic * B-Splines, which is performed on (shifted) double density data: * * * uno_one_1 = uno_two_1 = uno_thr_1 = * (ix-1/4,iy-1/4) (ix+1/4,iy-1/4) (ix+3/4,iy-1/4) * * * * X or X * dos_one_1 = dos_two_1 = dos_thr_1 = * (ix-1/4,iy+1/4) (ix+1/4,iy+1/4) (ix+3/4,iy+1/4) * or X or X * * * * tre_one_1 = tre_two_1 = tre_thr_1 = * (ix-1/4,iy+3/4) (ix+1/4,iy+3/4) (ix+3/4,iy+3/4) * * * In the coefficient computations, we fix things so that coordinates * are relative to dos_two_1, and so that distances are rescaled so * that double density pixel locations are at a distance of 1. */ /* * Call vertex-split + quadratic B-splines with a careful type * conversion as a parameter. (It would be nice to do this with * templates somehow---for one thing this would allow code * comments---but we can't figure a clean way to do it.) */ #define VSQBS_CONVERSION(conversion) \ template \ static void inline vsqbs_##conversion(void *restrict pout, \ const VipsPel *restrict pin, \ const int bands, \ const int lskip, \ const double x_0, \ const double y_0) \ { \ T *restrict out = (T *) pout; \ \ const T *restrict in = (T *) pin; \ \ const int sign_of_x_0 = 2 * (x_0 >= 0.) - 1; \ const int sign_of_y_0 = 2 * (y_0 >= 0.) - 1; \ \ const int shift_forw_1_pix = sign_of_x_0 * bands; \ const int shift_forw_1_row = sign_of_y_0 * lskip; \ \ const int shift_back_1_pix = -shift_forw_1_pix; \ const int shift_back_1_row = -shift_forw_1_row; \ \ const int uno_two_shift = shift_back_1_row; \ const int uno_thr_shift = shift_forw_1_pix + shift_back_1_row; \ \ const int dos_one_shift = shift_back_1_pix; \ const int dos_two_shift = 0; \ const int dos_thr_shift = shift_forw_1_pix; \ \ const int tre_one_shift = shift_back_1_pix + shift_forw_1_row; \ const int tre_two_shift = shift_forw_1_row; \ const int tre_thr_shift = shift_forw_1_pix + shift_forw_1_row; \ \ const double twice_abs_x_0 = (2 * sign_of_x_0) * x_0; \ const double twice_abs_y_0 = (2 * sign_of_y_0) * y_0; \ const double x = twice_abs_x_0 + -0.5; \ const double y = twice_abs_y_0 + -0.5; \ const double cent = 0.75 - x * x; \ const double mid = 0.75 - y * y; \ const double left = -0.5 * (x + cent) + 0.5; \ const double top = -0.5 * (y + mid) + 0.5; \ const double left_p_cent = left + cent; \ const double top_p_mid = top + mid; \ const double cent_p_rite = 1.0 - left; \ const double mid_p_bot = 1.0 - top; \ const double rite = 1.0 - left_p_cent; \ const double bot = 1.0 - top_p_mid; \ \ const double four_c_uno_two = left_p_cent * top; \ const double four_c_dos_one = left * top_p_mid; \ const double four_c_dos_two = left_p_cent + top_p_mid; \ const double four_c_dos_thr = cent_p_rite * top_p_mid + rite; \ const double four_c_tre_two = mid_p_bot * left_p_cent + bot; \ const double four_c_tre_thr = mid_p_bot * rite + cent_p_rite * bot; \ const double four_c_uno_thr = top - four_c_uno_two; \ const double four_c_tre_one = left - four_c_dos_one; \ \ int band = bands; \ \ do { \ const double double_result = \ (((four_c_uno_two * in[uno_two_shift] + \ four_c_dos_one * in[dos_one_shift]) + \ (four_c_dos_two * in[dos_two_shift] + \ four_c_dos_thr * in[dos_thr_shift])) + \ ((four_c_tre_two * in[tre_two_shift] + \ four_c_tre_thr * in[tre_thr_shift]) + \ (four_c_uno_thr * in[uno_thr_shift] + \ four_c_tre_one * in[tre_one_shift]))) * \ 0.25; \ \ const T result = to_##conversion(double_result); \ in++; \ *out++ = result; \ \ } while (--band); \ } VSQBS_CONVERSION(fptypes) VSQBS_CONVERSION(withsign) VSQBS_CONVERSION(nosign) #define CALL(T, conversion) \ vsqbs_##conversion(out, \ p, \ bands, \ lskip, \ relative_x, \ relative_y); /* * We need C linkage: */ extern "C" { G_DEFINE_TYPE(VipsInterpolateVsqbs, vips_interpolate_vsqbs, VIPS_TYPE_INTERPOLATE); } static void vips_interpolate_vsqbs_interpolate(VipsInterpolate *restrict interpolate, void *restrict out, VipsRegion *restrict in, double absolute_x, double absolute_y) { /* absolute_x and absolute_y are always >= 1.0 (see double-check assert * below), so we don't need floor(). * * It's 1 not 0 since we ask for a window_offset of 1 at the bottom. */ const int ix = (int) (absolute_x + 0.5); const int iy = (int) (absolute_y + 0.5); /* * Move the pointer to (the first band of) the top/left pixel of the * 2x2 group of pixel centers which contains the sampling location * in its convex hull: */ const VipsPel *restrict p = VIPS_REGION_ADDR(in, ix, iy); const double relative_x = absolute_x - ix; const double relative_y = absolute_y - iy; /* * VIPS versions of Nicolas's pixel addressing values. */ const int lskip = VIPS_REGION_LSKIP(in) / VIPS_IMAGE_SIZEOF_ELEMENT(in->im); /* * Double the bands for complex images to account for the real and * imaginary parts being computed independently: */ const int actual_bands = in->im->Bands; const int bands = vips_band_format_iscomplex(in->im->BandFmt) ? 2 * actual_bands : actual_bands; g_assert(ix - 1 >= in->valid.left); g_assert(iy - 1 >= in->valid.top); g_assert(ix + 1 <= VIPS_RECT_RIGHT(&in->valid)); g_assert(iy + 1 <= VIPS_RECT_BOTTOM(&in->valid)); /* Confirm that absolute_x and absolute_y are >= 1, see above. */ g_assert(absolute_x >= 1.0); g_assert(absolute_y >= 1.0); switch (in->im->BandFmt) { case VIPS_FORMAT_UCHAR: CALL(unsigned char, nosign); break; case VIPS_FORMAT_CHAR: CALL(signed char, withsign); break; case VIPS_FORMAT_USHORT: CALL(unsigned short, nosign); break; case VIPS_FORMAT_SHORT: CALL(signed short, withsign); break; case VIPS_FORMAT_UINT: CALL(unsigned int, nosign); break; case VIPS_FORMAT_INT: CALL(signed int, withsign); break; /* * Complex images are handled by doubling bands: */ case VIPS_FORMAT_FLOAT: case VIPS_FORMAT_COMPLEX: CALL(float, fptypes); break; case VIPS_FORMAT_DOUBLE: case VIPS_FORMAT_DPCOMPLEX: CALL(double, fptypes); break; default: g_assert(0); break; } } static void vips_interpolate_vsqbs_class_init(VipsInterpolateVsqbsClass *klass) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS(klass); VipsInterpolateClass *interpolate_class = VIPS_INTERPOLATE_CLASS(klass); object_class->nickname = "vsqbs"; object_class->description = _("B-Splines with antialiasing smoothing"); interpolate_class->interpolate = vips_interpolate_vsqbs_interpolate; interpolate_class->window_size = 4; interpolate_class->window_offset = 1; } static void vips_interpolate_vsqbs_init(VipsInterpolateVsqbs *vsqbs) { } libvips-8.18.2/man/000077500000000000000000000000001516303661500140435ustar00rootroot00000000000000libvips-8.18.2/man/meson.build000066400000000000000000000001311516303661500162000ustar00rootroot00000000000000install_man( 'vipsedit.1', 'vipsheader.1', 'vips.1', 'vipsthumbnail.1' ) libvips-8.18.2/man/vips.1000066400000000000000000000054461516303661500151170ustar00rootroot00000000000000.TH VIPS 1 "30 June 1993" .SH NAME vips \- run vips operations from the command line .SH SYNOPSIS .B vips [options] [command] [command-options] [command-args] .SH DESCRIPTION .B vips(1) is the VIPS universal main program. You can use it to run any VIPS operation from the command line, to query the VIPS class hierarchy, and to maintain parts of the VIPS library. To run a VIPS operation, the first argument should be the name of the operation and following arguments should be the operation arguments. For example: $ vips invert lena.v lena2.v .SH OPTIONS .TP .B -l BASE-NAME, --list=BASE-NAME List operations below BASE-NAME. This prints a one-line summary of every operation in vips below the class BASE-NAME, where BASE-NAME may be a full vips class name, or a nickname. If BASE-NAME is not supplied, this will list all classes below VipsOperation. .TP .B -p PLUGIN, --plugin=PLUGIN Load PLUGIN. Note that plugins in $VIPSHOME/lib/vips-plugins-MAJOR.MINOR are loaded automatically. .TP .B -v, --version Show VIPS version. .TP .B -c NAME, --completion NAME Print completions for .B NAME .SH COMMANDS .TP .B operation-name operation-arguments Execute a named operation, for example add. .SH EXAMPLES Run a vips operation. Operation options must follow the operation name. $ vips insert lena.v lena2.v out.v 0 0 --background "128 0 0" Get a "usage" message for an operation. $ vips insert insert image @sub into @main at @x, @y usage: insert main sub out x y where: main - Main input image, input VipsImage sub - Sub-image to insert into main image, input VipsImage out - Output image, output VipsImage x - Left edge of sub in main, input gint default: 0 min: -100000000, max: 100000000 y - Top edge of sub in main, input gint default: 0 min: -100000000, max: 100000000 optional arguments: expand - Expand output to hold all of both inputs, input gboolean default: false background - Colour for new pixels, input VipsArrayDouble operation flags: sequential List all draw operations. $ vips -l draw VipsDraw (draw), draw operations VipsDrawink (drawink), draw with ink operations VipsDrawRect (draw_rect), paint a rectangle on an image VipsDrawMask (draw_mask), draw a mask on an image VipsDrawLine (draw_line), draw a line on an image VipsDrawCircle (draw_circle), draw a circle on an image VipsDrawFlood (draw_flood), flood-fill an area VipsDrawImage (draw_image), paint an image into another image VipsDrawSmudge (draw_smudge), blur a rectangle on an image .SH RETURN VALUE returns 0 on success and non-zero on error. .SH SEE ALSO vipsheader(1) .SH COPYRIGHT The National Gallery and Birkbeck College, 1989-1996. libvips-8.18.2/man/vipsedit.1000066400000000000000000000024521516303661500157570ustar00rootroot00000000000000.TH VIPSEDIT 1 "30 June 1993" .SH NAME vipsedit \- edit header of a vips image file .SH SYNOPSIS .B vipsedit [OPTION...] vipsfile .SH DESCRIPTION .B vipsedit alters a VIPS image file's header. This is useful for setting the resolution, for example. The options are: -x, --xsize=N set Xsize to N -y, --ysize=N set Ysize to N -b, --bands=N set Bands to N -f, --format=F set BandFmt to F (eg. uchar) -i, --interpretation=I set Interpretation to I (eg. xyz) -c, --coding=C set Coding to C (eg. labq) -X, --xres=R set Xres to R pixels/mm -Y, --yres=R set Yres to R pixels/mm -u, --xoffset=N set Xoffset to N -v, --yoffset=N set Yoffset to N -e, --setext replace extension block with stdin Be very careful when changing Xsize, Ysize, BandFmt or Bands. vipsedit does no checking! .SH EXAMPLES To set the Xsize to 512 and Bands to 6: vipsedit --xsize=512 --bands=6 fred.v or vipsedit -x 512 -b 6 fred.v Extract the XML metadata from an image with .B vipsheader(1), edit it, and reattach with .B vipsedit(1). vipsheader -f getext fred.v | sed s/banana/pineapple/ | vipsedit -e fred.v .SH RETURN VALUE returns 0 on success and non-zero on error. .SH SEE ALSO vipsheader(1) .SH COPYRIGHT K. Martinez 1993 libvips-8.18.2/man/vipsheader.1000066400000000000000000000017761516303661500162720ustar00rootroot00000000000000.TH VIPSHEADER 1 "12 July 1990" .SH NAME vipsheader \- prints information about an image file .SH SYNOPSIS vipsheader [OPTIONS ...] files ... .SH DESCRIPTION .B vipsheader(1) prints image header fields to stdout. .SH OPTIONS .TP .B -a, --all Show all fields. Fields are displayed to be convenient for humans to read, so binary data, for example, is summarized rather than simply printed. .TP .B -f FIELD, --field=FIELD Print the value of .B FIELD from the image header. Fields are printed in a way suitable for programs to understand, so, for example, binary data is base64-encoded and printed as a stream of characters. The special field name .B getext prints the VIPS extension block: the XML defining the image metadata. You can alter this, then reattach with .B vipsedit(1). You can use multiple "-f" arguments to print the values of many fields. .SH EXAMPLES $ vipsheader -f width ~/pics/*.v 1024 1279 22865 1 256 .SH SEE ALSO vipsedit(1) .SH COPYRIGHT N. Dessipris .SH AUTHOR N. Dessipris \- 12/07/1990 libvips-8.18.2/man/vipsthumbnail.1000066400000000000000000000054461516303661500170230ustar00rootroot00000000000000.TH VIPSTHUMBNAIL 1 "13 May 2010" .SH NAME vipsthumbnail \- make thumbnails of image files .SH SYNOPSIS .B vipsthumbnail [flags] imagefile1 imagefile2 ... .SH DESCRIPTION .B vipsthumbnail(1) processes each .B imagefile in turn, shrinking each image to fit within a 128 by 128 pixel square. The shrunk image is written to a new file named .B tn_imagefile.jpg. This program is typically faster and uses less memory than other image thumbnail programs. For example: $ vipsthumbnail fred.png jim.tif will read image files .B fred.png and .B jim.tif and write thumbnails to the files .B tn_fred.jpg and .B tn_jim.jpg. $ vipsthumbnail --size=64 -o thumbnails/%s.png fred.jpg will read image file .B fred.jpg and write a 64 x 64 pixel thumbnail to the file .B thumbnails/fred.png. .SH OPTIONS .TP .B -s N, --size=N Set the output thumbnail size to .B N x .B N pixels. You can use "MxN" to specify a rectangular bounding box. The image is shrunk so that it just fits within this area, images which are smaller than this are expanded. Use "xN" or "Mx" to just resize on one axis. Append "<" to only resize if the input image is smaller than the target, append ">" to only resize if the input image is larger than the target. .TP .B --path=FORMAT Set the output path format. Three substitutions are performed: .B %s is replaced by the input basename with any suffix removed, .B %d is replaced by the input dirname, and .B %c is replaced by the current working directory. The default value is .B %d/tn_%s.jpg meaning JPEG output, to the same directory as the input file, with .B tn_ prepended. You can add format options too, for example .B %c/%s/tn_%s.jpg[Q=20] will write JPEG images to a tree within the current directory with Q set to 20. .TP .B -e PROFILE, --eprofile=PROFILE Export thumbnails with this ICC profile. Images are only colour-transformed if there is both an output and an input profile available. The input profile can either be embedded in the input image or supplied with the .B --iprofile option. .TP .B -i PROFILE, --iprofile=PROFILE Import images with this ICC profile, if no profile is embedded in the image. Images are only colour-transformed if there is both an output and an input profile available. The output profile should be supplied with the .B --oprofile option. .TP .B -c, --crop Crop the output image down. The image is shrunk so as to completely fill the bounding box in both axes, then any excess is cropped off. .TP .B -d, --delete Delete the output profile from the image. This can save a small amount of space. .TP .B -t, --rotate Auto-rotate images using EXIF orientation tags. .TP .B -a, --linear Shrink images in linear light colour space. This can be much slower. .SH RETURN VALUE returns 0 on success and non-zero on error. Error can mean one or more conversions failed. .SH SEE ALSO vipsheader(1) libvips-8.18.2/meson.build000066400000000000000000000772761516303661500154550ustar00rootroot00000000000000project('vips', 'c', 'cpp', version: '8.18.2', meson_version: '>=0.55', default_options: [ # this is what glib uses (one of our required deps), so we use it too 'c_std=gnu99', # we use some C++14 features 'cpp_std=c++14', # do a release (optimised) build by default 'buildtype=release', # turn off asserts etc. in release mode 'b_ndebug=if-release' ] ) version_parts = meson.project_version().split('.') version_major = version_parts[0] version_minor = version_parts[1] version_patch = version_parts[2] # rules: # sources changed: increment revision # binary interface changed: increment current, reset revision to 0 # binary interface changes backwards compatible?: increment age # binary interface changes not backwards compatible?: reset age to 0 library_revision = 2 library_current = 62 library_age = 20 library_version = '@0@.@1@.@2@'.format(library_current - library_age, library_age, library_revision) darwin_versions = [library_current + 1, '@0@.@1@'.format(library_current + 1, library_revision)] gnome = import('gnome') pymod = import('python') pkg = import('pkgconfig') i18n = import('i18n') # if we're optimising (eg. release mode) we turn off cast checks and g_asserts if get_option('optimization') not in ['0', 'g'] add_project_arguments('-DG_DISABLE_CAST_CHECKS', language: ['cpp', 'c']) add_project_arguments('-DG_DISABLE_CHECKS', language: ['cpp', 'c']) add_project_arguments('-DG_DISABLE_ASSERT', language: ['cpp', 'c']) endif # in debug mode we automatically enable leak checks # also true for 'debugoptimized' if get_option('debug') add_project_arguments('-DDEBUG_LEAK', language: ['cpp', 'c']) endif host_os = host_machine.system() cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') # Prevent use of void* pointer arithmetic to support MSVC add_project_arguments(cc.get_supported_arguments('-Werror=pointer-arith'), language: ['cpp', 'c']) if host_os == 'windows' add_project_arguments(['-DUNICODE', '-D_UNICODE'], language: ['cpp', 'c']) endif # libFuzzer related things fuzzing_engine = get_option('fuzzing_engine') if fuzzing_engine == 'libfuzzer' if not cc.has_argument('-fsanitize=fuzzer') error('fuzzing_engine libfuzzer requires "-fsanitize=fuzzer"') endif fuzzer_args = ['-fsanitize=fuzzer-no-link', '-fsanitize=fuzzer'] add_project_arguments(cc.first_supported_argument(fuzzer_args), language: ['cpp', 'c']) endif glib_dep = dependency('glib-2.0', version: '>=2.52') gio_dep = dependency('gio-2.0') gobject_dep = dependency('gobject-2.0') gmodule_dep = dependency('gmodule-no-export-2.0', required: get_option('modules')) expat_dep = dependency('expat') thread_dep = dependency('threads') m_dep = cc.find_library('m', required: false) # Start to form our dependencies # External dependencies we've detected external_deps = [ glib_dep, gio_dep, gobject_dep, gmodule_dep, expat_dep, ] # External dependencies of modules we've detected # These dependencies are not included in vips.pc module_deps = [] # Required deps that may or may not be external versioned libraries other_deps = [ thread_dep, m_dep, ] nodelete_link_args = cc.get_supported_link_arguments('-Wl,-z,nodelete') prefix_dir = get_option('prefix') lib_dir = prefix_dir / get_option('libdir') project_source_root = meson.current_source_dir() project_build_root = meson.current_build_dir() if gmodule_dep.found() and gmodule_dep.get_variable(pkgconfig: 'gmodule_supported') == 'true' # Disable modules by default when building static libraries modules_enabled = get_option('modules').enabled() or get_option('default_library') == 'shared' elif get_option('modules').enabled() error('GModule is not supported on your system, please reconfigure with -Dmodules=disabled') else modules_enabled = false endif module_dir = lib_dir / 'vips-modules-@0@.@1@'.format(version_major, version_minor) cfg_var = configuration_data() cfg_var.set_quoted('G_LOG_DOMAIN', 'VIPS') cfg_var.set('ENABLE_MODULES', modules_enabled) # Detect and set symbol visibility if get_option('default_library') == 'shared' and host_os in ['windows', 'cygwin'] cfg_var.set('DLL_EXPORT', true) if cc.has_function_attribute('visibility:hidden') cfg_var.set('_VIPS_PUBLIC', '__attribute__((visibility("default"))) __declspec(dllexport)') else cfg_var.set('_VIPS_PUBLIC', '__declspec(dllexport)') endif elif cc.has_function_attribute('visibility:hidden') cfg_var.set('_VIPS_PUBLIC', '__attribute__((visibility("default")))') endif # we also need to be able to mix vector and scalar arithmetic vector_arithmetic_check = ''' typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16))); int main(void) { v4f f = {1, 2, 3, 4}; f *= 12.0; v4f g = {5, 6, 7, 8}; f = g > 0 ? g : -1 * g; } ''' # gcc 7.2 seems to work, but then gets confused by signed constants in templates signed_constants_check = ''' typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16))); template static void h( v4f B ) { v4f f; f = -1 * B; } ''' have_vector_artih = cpp.compiles(vector_arithmetic_check, name: 'Has vector arithmetic', dependencies: m_dep) and \ cpp.compiles(signed_constants_check, name: 'Has signed constants in vector templates', dependencies: m_dep) cfg_var.set('HAVE_VECTOR_ARITH', have_vector_artih) # HAVE_TARGET_CLONES target_clones_check = ''' static int __attribute__((target_clones("default,avx"))) has_target_clones(void) { return 0; } int main(void) { int (*func)(void) = has_target_clones; return func(); } ''' if meson.can_run_host_binaries() rres = cc.run(target_clones_check, args: '-Werror', name: 'Has target_clones attribute') have_target_clones = rres.compiled() and rres.returncode() == 0 else have_target_clones = cc.links(target_clones_check, args: '-Werror', name: 'Has target_clones attribute') endif # `target_clones` attribute is incompatible with: # - ThreadSanitizer on Clang and GCC # https://github.com/llvm/llvm-project/issues/163369 # https://gcc.gnu.org/PR122894 # - Profile-guided optimization on GCC # https://gcc.gnu.org/PR122895 cflags = ' '.join(get_option('c_args')) broken_fmv = get_option('b_sanitize') == 'thread' or \ get_option('b_pgo') != 'off' or \ cflags.contains('-fprofile-generate') or \ cflags.contains('-fprofile-use') if broken_fmv warning('Broken FMV support detected: disabling `target_clones` support') endif cfg_var.set('HAVE_TARGET_CLONES', have_target_clones and not broken_fmv) func_names = [ '_aligned_malloc', 'posix_memalign', 'memalign' ] foreach func_name : func_names cfg_var.set('HAVE_' + func_name.to_upper(), cc.has_function(func_name)) endforeach cfg_var.set('HAVE_PTHREAD_DEFAULT_NP', cc.has_function('pthread_setattr_default_np', args: '-D_GNU_SOURCE', prefix: '#include ', dependencies: thread_dep)) # needed by rsvg and others zlib_dep = dependency('zlib', version: '>=0.4', required: get_option('zlib')) if zlib_dep.found() external_deps += zlib_dep cfg_var.set('HAVE_ZLIB', true) endif libarchive_dep = dependency('libarchive', version: '>=3.0.0', required: get_option('archive')) if libarchive_dep.found() external_deps += libarchive_dep cfg_var.set('HAVE_LIBARCHIVE', true) endif fftw_dep = dependency('fftw3', required: get_option('fftw')) if fftw_dep.found() external_deps += fftw_dep cfg_var.set('HAVE_FFTW', true) endif # TODO: simplify this when requiring meson>=0.60.0 magick_dep = dependency(get_option('magick-package'), required: false) if not magick_dep.found() # very old versions called it "ImageMagick" magick_dep = dependency('ImageMagick', required: get_option('magick')) endif magick_found = not get_option('magick').disabled() and magick_dep.found() magick_module = false if magick_found magick_module = modules_enabled and not get_option('magick-module').disabled() if magick_module cfg_var.set('MAGICK_MODULE', true) module_deps += magick_dep else external_deps += magick_dep endif magick7 = magick_dep.version().version_compare('>=7.0') # IM7 uses # IM6 uses (since 6.2.3) but still provides # GM uses magick_include = magick7 ? '#include ' : '#include ' if magick7 cfg_var.set('HAVE_MAGICK7', true) else # come here for imagemagick6, and graphicsmagick1.x, which also uses # the im6 API cfg_var.set('HAVE_MAGICK6', true) cfg_var.set('HAVE_NUMBER_SCENES', cc.has_member('struct _ImageInfo', 'number_scenes', prefix: magick_include, dependencies: magick_dep)) func_names = [ 'InheritException', 'AcquireExceptionInfo', 'SetImageProperty', 'SetImageExtent', 'AcquireImage', 'GetVirtualPixels', 'ResetImageProfileIterator', 'ResetImageAttributeIterator', 'ResetImagePropertyIterator', 'MagickCoreGenesis', 'SetImageOption', 'BlobToStringInfo', 'OptimizePlusImageLayers', 'OptimizeImageTransparency', 'GetMagicInfo' ] foreach func_name : func_names cfg_var.set('HAVE_' + func_name.to_upper(), cc.has_function(func_name, prefix: magick_include, dependencies: magick_dep)) endforeach cfg_var.set('HAVE_CMYCOLORSPACE', cc.compiles(magick_include + '\nColorspaceType colorspace = CMYColorspace;', name: 'Has CMYColorspace', dependencies: magick_dep)) cfg_var.set('HAVE_HCLPCOLORSPACE', cc.compiles(magick_include + '\nColorspaceType colorspace = HCLpColorspace;', name: 'Has HCLpColorspace', dependencies: magick_dep)) # GetImageMagick() takes two args under GM, three under IM cfg_var.set('HAVE_GETIMAGEMAGICK3', cc.compiles(magick_include + '\nint main() {(void)GetImageMagick(NULL, 0, NULL);}', name: 'GetImageMagick takes three arguments', dependencies: magick_dep)) endif magick_features = [ 'load', 'save' ] foreach feature : magick_features cfg_var.set('ENABLE_MAGICK' + feature.to_upper(), feature in get_option('magick-features')) endforeach if 'save' in get_option('magick-features') cfg_var.set('HAVE_IMPORTIMAGEPIXELS', cc.has_function('ImportImagePixels', prefix: magick_include, dependencies: magick_dep)) cfg_var.set('HAVE_IMAGESTOBLOB', cc.has_function('ImagesToBlob', prefix: magick_include, dependencies: magick_dep)) endif endif cfitsio_dep = dependency('cfitsio', required: get_option('cfitsio')) if cfitsio_dep.found() external_deps += cfitsio_dep cfg_var.set('HAVE_CFITSIO', true) endif # quant package we use quantisation_package = disabler() imagequant_dep = dependency('imagequant', required: get_option('imagequant')) if imagequant_dep.found() external_deps += imagequant_dep cfg_var.set('HAVE_IMAGEQUANT', true) quantisation_package = imagequant_dep endif # only if libimagequant not found quantizr_dep = disabler() if not quantisation_package.found() quantizr_dep = dependency('quantizr', required: get_option('quantizr')) if quantizr_dep.found() external_deps += quantizr_dep cfg_var.set('HAVE_QUANTIZR', true) quantisation_package = quantizr_dep endif endif cgif_dep = disabler() if quantisation_package.found() cgif_dep = dependency('cgif', version: '>=0.2.0', required: get_option('cgif')) if cgif_dep.found() external_deps += cgif_dep cfg_var.set('HAVE_CGIF', true) cfg_var.set('HAVE_CGIF_ATTR_NO_LOOP', cc.get_define('CGIF_ATTR_NO_LOOP', prefix: '#include ', dependencies: cgif_dep) != '') cfg_var.set('HAVE_CGIF_FRAME_ATTR_INTERLACED', cc.get_define('CGIF_FRAME_ATTR_INTERLACED', prefix: '#include ', dependencies: cgif_dep) != '') cfg_var.set('HAVE_CGIF_GEN_KEEP_IDENT_FRAMES', cc.get_define('CGIF_GEN_KEEP_IDENT_FRAMES', prefix: '#include ', dependencies: cgif_dep) != '') endif endif libexif_dep = dependency('libexif', version: '>=0.6', required: get_option('exif')) if libexif_dep.found() external_deps += libexif_dep cfg_var.set('HAVE_EXIF', true) # some libexif packages need include , some just # how annoying # libexif includes don't need libexif prefix cfg_var.set('UNTAGGED_EXIF', cc.has_header('exif-data.h', dependencies: libexif_dep)) # 0.6.22 adds a couple of EXIF 2.3 ASCII tags cfg_var.set('HAVE_EXIF_0_6_22', libexif_dep.version().version_compare('>=0.6.22')) # 0.6.23 adds some OffsetTime* and GPS* ASCII tags cfg_var.set('HAVE_EXIF_0_6_23', libexif_dep.version().version_compare('>=0.6.23')) endif libjpeg_dep = dependency('libjpeg', required: get_option('jpeg')) if libjpeg_dep.found() external_deps += libjpeg_dep cfg_var.set('HAVE_JPEG', true) # features like trellis quant are exposed as extension parameters ... # mozjpeg 3.2 and later have #define JPEG_C_PARAM_SUPPORTED, but we must # work with earlier versions cfg_var.set('HAVE_JPEG_EXT_PARAMS', cc.has_function('jpeg_c_bool_param_supported', prefix: '#include \n#include ', dependencies: libjpeg_dep)) endif # we need libjpeg for uhdrload and save libuhdr_dep = disabler() if libjpeg_dep.found() libuhdr_dep = dependency('libuhdr', required: get_option('uhdr')) if libuhdr_dep.found() external_deps += libuhdr_dep cfg_var.set('HAVE_UHDR', true) endif endif # png package we use png_package = disabler() # look for libpng first png_dep = dependency('libpng', version: '>=1.2.9', required: get_option('png')) if png_dep.found() external_deps += png_dep cfg_var.set('HAVE_PNG', true) cfg_var.set('HAVE_PNG_SET_CHUNK_MALLOC_MAX', cc.has_function('png_set_chunk_malloc_max', prefix: '#include ', dependencies: png_dep)) png_package = png_dep endif # only if libpng not found if not png_package.found() # - it's sometimes called "spng.pc", sometimes "libspng.pc", we must search for # both # - we need 0.7+ for PNG write support # TODO: simplify this when requiring meson>=0.60.0 spng_dep = dependency('spng', version: '>=0.7', required: false) if not spng_dep.found() spng_dep = dependency('libspng', version: '>=0.7', required: get_option('spng')) endif if not get_option('spng').disabled() and spng_dep.found() external_deps += spng_dep cfg_var.set('HAVE_SPNG', true) png_package = spng_dep endif endif # libwebp ... target 0.6+ to reduce complication # webp has the stuff for handling metadata in two separate libraries -- we # insist on having both of them libwebp_dep = dependency('libwebp', version: '>=0.6', required: get_option('webp')) if libwebp_dep.found() external_deps += libwebp_dep external_deps += dependency('libwebpmux', version: '>=0.6') external_deps += dependency('libwebpdemux', version: '>=0.6') cfg_var.set('HAVE_LIBWEBP', true) endif pangocairo_dep = dependency('pangocairo', version: '>=1.32.6', required: get_option('pangocairo')) if pangocairo_dep.found() external_deps += pangocairo_dep cfg_var.set('HAVE_PANGOCAIRO', true) endif # text rendering with fontconfig requires pangoft2 pangoft2_dep = dependency('pangoft2', version: '>=1.32.6', required: get_option('fontconfig')) fontconfig_dep = dependency('fontconfig', required: get_option('fontconfig')) fontconfig_found = pangoft2_dep.found() and fontconfig_dep.found() and pangocairo_dep.found() if fontconfig_found external_deps += pangoft2_dep external_deps += fontconfig_dep cfg_var.set('HAVE_FONTCONFIG', true) endif libtiff_dep = dependency('libtiff-4', required: get_option('tiff')) if libtiff_dep.found() external_deps += libtiff_dep cfg_var.set('HAVE_TIFF', true) # ZSTD and WEBP in TIFF added in libtiff 4.0.10 cfg_var.set('HAVE_TIFF_COMPRESSION_WEBP', cc.get_define('COMPRESSION_WEBP', prefix: '#include ', dependencies: libtiff_dep) != '') # TIFFOpenOptions added in libtiff 4.5.0 cfg_var.set('HAVE_TIFF_OPEN_OPTIONS', cc.has_function('TIFFOpenOptionsAlloc', prefix: '#include ', dependencies: libtiff_dep)) # TIFFOpenOptionsSetMaxCumulatedMemAlloc added in libtiff 4.7.0 cfg_var.set('HAVE_TIFF_OPEN_OPTIONS_SET_MAX_CUMULATED_MEM_ALLOC', cc.has_function('TIFFOpenOptionsSetMaxCumulatedMemAlloc', prefix: '#include ', dependencies: libtiff_dep)) endif # 2.40.3 so we get the UNLIMITED open flag librsvg_dep = dependency('librsvg-2.0', version: '>=2.40.3', required: get_option('rsvg')) cairo_dep = dependency('cairo', version: '>=1.2', required: get_option('rsvg')) librsvg_found = librsvg_dep.found() and cairo_dep.found() if librsvg_found external_deps += librsvg_dep external_deps += cairo_dep cfg_var.set('HAVE_RSVG', true) # CAIRO_FORMAT_RGBA128F added in cairo 1.17.2 cfg_var.set('HAVE_CAIRO_FORMAT_RGBA128F', cc.has_type('CAIRO_FORMAT_RGBA128F', prefix: '#include ', dependencies: cairo_dep)) endif openslide_dep = dependency('openslide', version: '>=3.4.0', required: get_option('openslide')) openslide_module = false if openslide_dep.found() openslide_module = modules_enabled and not get_option('openslide-module').disabled() if openslide_module cfg_var.set('OPENSLIDE_MODULE', true) module_deps += openslide_dep else external_deps += openslide_dep endif cfg_var.set('HAVE_OPENSLIDE', true) cfg_var.set('HAVE_OPENSLIDE_ICC', cc.has_function('openslide_get_icc_profile_size', prefix: '#include ', dependencies: openslide_dep)) cfg_var.set('HAVE_OPENSLIDE_CACHE_CREATE', cc.has_function('openslide_cache_create', prefix: '#include ', dependencies: openslide_dep)) endif matio_dep = dependency('matio', required: get_option('matio')) if matio_dep.found() external_deps += matio_dep cfg_var.set('HAVE_MATIO', true) endif # lcms ... refuse to use lcms1 lcms_dep = dependency('lcms2', required: get_option('lcms')) if lcms_dep.found() external_deps += lcms_dep cfg_var.set('HAVE_LCMS2', true) endif # require 1.2.2 since 1.2.1 has a broken ImfCloseTiledInputFile() openexr_dep = dependency('OpenEXR', version: '>=1.2.2', required: get_option('openexr')) if openexr_dep.found() external_deps += openexr_dep cfg_var.set('HAVE_OPENEXR', true) endif # require 0.14 for LIBRAW_COMPILE_CHECK_VERSION_NOTLESS libraw_dep = dependency('libraw_r', version: '>=0.14', required: get_option('raw')) if libraw_dep.found() external_deps += libraw_dep cfg_var.set('HAVE_LIBRAW', true) endif # 2.4 is the first one to have working threading and tiling libopenjp2_dep = dependency('libopenjp2', version: '>=2.4', required: get_option('openjpeg')) if libopenjp2_dep.found() external_deps += libopenjp2_dep cfg_var.set('HAVE_LIBOPENJP2', true) endif # simd package we use simd_package = disabler() # Require 1.0.5 to support the `ReorderDemote2To(u8, i16, i16)` operation # See: https://github.com/google/highway/pull/1247 libhwy_dep = dependency('libhwy', version: '>=1.0.5', required: get_option('highway')) if libhwy_dep.found() external_deps += libhwy_dep cfg_var.set('HAVE_HWY', true) # 1.1.0 adds `InterleaveWhole{Lower,Upper}` and `Dup128VecFromValues` cfg_var.set('HAVE_HWY_1_1_0', libhwy_dep.version().version_compare('>=1.1.0')) # Always disable SSSE3 since it is rare to have SSSE3 but not SSE4 disabled_targets = ['HWY_SSSE3'] # Avoid disabling the AVX3_DL target, see: https://github.com/google/highway/pull/1356 #disabled_targets += ['HWY_AVX3_DL'] # Always disable special AVX512 targets since the FP16/BF16 ops they introduce are unused. disabled_targets += ['HWY_AVX3_ZEN4', 'HWY_AVX3_SPR'] if libhwy_dep.version().version_compare('>=1.3.0') disabled_targets += ['HWY_AVX10_2'] endif # Optionally, build without AVX512 support (helps to reduce binary size at the cost of performance) #disabled_targets += ['HWY_AVX3'] add_project_arguments('-DHWY_DISABLED_TARGETS=@0@'.format('|'.join(disabled_targets)), language: ['cpp']) simd_package = libhwy_dep endif # only if highway not found if not simd_package.found() # we use loadpw etc. orc_dep = dependency('orc-0.4', version: '>=0.4.11', required: get_option('orc')) if orc_dep.found() external_deps += orc_dep cfg_var.set('HAVE_ORC', true) # orc 0.4.30+ works with cf-protection, but 0.4.30 has a bug with multiple # definitions of OrcTargetPowerPCFlags, so insist on 0.4.31 cfg_var.set('HAVE_ORC_CF_PROTECTION', orc_dep.version().version_compare('>=0.4.31')) simd_package = orc_dep endif endif # pdf loader we use pdf_loader = disabler() # pick 4200 as the starting version number ... no reason, really, it'd # probably work with much older versions pdfium_dep = dependency('pdfium', version: '>=4200', required: get_option('pdfium')) if pdfium_dep.found() external_deps += pdfium_dep cfg_var.set('HAVE_PDFIUM', true) pdf_loader = pdfium_dep endif libheif_dep = dependency('libheif', version: '>=1.7.0', required: get_option('heif')) libheif_module = false if libheif_dep.found() libheif_module = modules_enabled and not get_option('heif-module').disabled() if libheif_module cfg_var.set('HEIF_MODULE', true) module_deps += libheif_dep else external_deps += libheif_dep endif cfg_var.set('HAVE_HEIF', true) # added in 1.10.0 cfg_var.set('HAVE_HEIF_ENCODER_PARAMETER_GET_VALID_INTEGER_VALUES', cpp.has_function('heif_encoder_parameter_get_valid_integer_values', prefix: '#include ', dependencies: libheif_dep)) # added in 1.11.0 cfg_var.set('HAVE_HEIF_ENCODING_OPTIONS_OUTPUT_NCLX_PROFILE', cpp.has_member('struct heif_encoding_options', 'output_nclx_profile', prefix: '#include ', dependencies: libheif_dep)) # heif_init added in 1.13.0 cfg_var.set('HAVE_HEIF_INIT', libheif_dep.version().version_compare('>=1.13.0')) # heif_encoding_options.image_orientation added in 1.14.0 cfg_var.set('HAVE_HEIF_ENCODING_OPTIONS_IMAGE_ORIENTATION', cpp.has_member('struct heif_encoding_options', 'image_orientation', prefix: '#include ', dependencies: libheif_dep)) # heif_error_success added in 1.17.0 cfg_var.set('HAVE_HEIF_ERROR_SUCCESS', libheif_dep.version().version_compare('>=1.17.0')) # heif_get_disabled_security_limits added in 1.19.0 cfg_var.set('HAVE_HEIF_GET_DISABLED_SECURITY_LIMITS', cpp.has_function('heif_get_disabled_security_limits', prefix: '#include ', dependencies: libheif_dep)) # heif_security_limits.max_total_memory added in 1.20.0 cfg_var.set('HAVE_HEIF_MAX_TOTAL_MEMORY', cpp.has_member('struct heif_security_limits', 'max_total_memory', prefix: '#include ', dependencies: libheif_dep)) endif libjxl_dep = dependency('libjxl', version: '>=0.7', required: get_option('jpeg-xl')) libjxl_threads_dep = dependency('libjxl_threads', version: '>=0.7', required: get_option('jpeg-xl')) libjxl_found = libjxl_dep.found() and libjxl_threads_dep.found() libjxl_module = false if libjxl_found libjxl_module = modules_enabled and not get_option('jpeg-xl-module').disabled() if libjxl_module cfg_var.set('LIBJXL_MODULE', true) module_deps += libjxl_dep module_deps += libjxl_threads_dep else external_deps += libjxl_dep external_deps += libjxl_threads_dep endif cfg_var.set('HAVE_LIBJXL', true) # need v0.8+ for bitdepth support cfg_var.set('HAVE_LIBJXL_0_8', libjxl_dep.version().version_compare('>=0.8')) # need v0.9+ for chunked write cfg_var.set('HAVE_LIBJXL_0_9', libjxl_dep.version().version_compare('>=0.9')) endif # only if pdfium not found libpoppler_module = false if not pdf_loader.found() libpoppler_dep = dependency('poppler-glib', version: '>=0.16.0', required: get_option('poppler')) if not cairo_dep.found() cairo_dep = dependency('cairo', version: '>=1.2', required: get_option('poppler')) endif if libpoppler_dep.found() and cairo_dep.found() libpoppler_module = modules_enabled and not get_option('poppler-module').disabled() if libpoppler_module cfg_var.set('POPPLER_MODULE', true) module_deps += libpoppler_dep module_deps += cairo_dep else external_deps += libpoppler_dep external_deps += cairo_dep endif cfg_var.set('HAVE_POPPLER', true) pdf_loader = libpoppler_dep endif endif # niftiio.pc is not present, and only provides the CMake package definition # files since v3.0.0, so, as a last resort, fall back on heuristic grabbing the # libs when -Dnifti-prefix-dir= is specified # # cmake find fails on ubuntu due to /usr/lib/x86_64-linux-gnu madness, so it's # simplest to create a niftiio.pc in this case # # create /usr/lib/x86_64-linux-gnu/pkgconfig/niftiio.pc: # # prefix=/usr # libdir=${prefix}/lib/x86_64-linux-gnu # includedir=${prefix}/include/nifti # Name: niftiio # Description: Core i/o routines for reading and writing nifti-1 format files # Version: 3.0.1 # Requires: xproto # Libs: -L${libdir} -lniftiio -lznz # Cflags: -I${includedir} # # TODO: simplify this when requiring meson>=0.60.0 nifti_prefix_dir = get_option('nifti-prefix-dir') libnifti_dep = dependency('niftiio', method: 'pkg-config', required: false) if not libnifti_dep.found() libnifti_dep = dependency('NIFTI', version: '>=3.0.0', method: 'cmake', modules: ['NIFTI::niftiio'], required: get_option('nifti').enabled() and nifti_prefix_dir == '') endif if nifti_prefix_dir != '' and not libnifti_dep.found() nifti_inc = include_directories(nifti_prefix_dir / 'include' / 'nifti') nifti_lib = cc.find_library('niftiio', has_headers: ['nifti1_io.h'], header_include_directories: nifti_inc, required: get_option('nifti')) znz_lib = cc.find_library('znz', has_headers: ['znzlib.h'], header_include_directories: nifti_inc, required: get_option('nifti')) libnifti_dep = declare_dependency(dependencies: [nifti_lib, znz_lib], include_directories: nifti_inc) endif libnifti_found = not get_option('nifti').disabled() and libnifti_dep.found() if libnifti_found external_deps += libnifti_dep cfg_var.set('HAVE_NIFTI', true) endif headers = [ 'sys/file.h', 'sys/param.h', 'sys/mman.h', 'unistd.h', 'io.h', 'direct.h' ] foreach name : headers cfg_var.set('HAVE_' + name.underscorify().to_upper(), cc.has_header(name)) endforeach cfg_var.set('ENABLE_DEPRECATED', get_option('deprecated')) cfg_var.set('HAVE_NSGIF', get_option('nsgif')) cfg_var.set('HAVE_PPM', get_option('ppm')) cfg_var.set('HAVE_ANALYZE', get_option('analyze')) cfg_var.set('HAVE_RADIANCE', get_option('radiance')) gettext_domain = 'vips@0@.@1@'.format(version_major, version_minor) cfg_var.set_quoted('GETTEXT_PACKAGE', gettext_domain) cfg_var.set_quoted('VIPS_PREFIX', prefix_dir) cfg_var.set_quoted('VIPS_LIBDIR', lib_dir) if cc.has_function('ngettext') cfg_var.set('ENABLE_NLS', true) have_bind_textdomain_codeset = cc.has_function('bind_textdomain_codeset') else libintl_dep = cc.find_library('intl', required: false) if libintl_dep.found() other_deps += libintl_dep cfg_var.set('ENABLE_NLS', true) have_bind_textdomain_codeset = cc.has_function('bind_textdomain_codeset', prefix: '#include ', dependencies: libintl_dep) else have_bind_textdomain_codeset = false endif endif cfg_var.set('HAVE_BIND_TEXTDOMAIN_CODESET', have_bind_textdomain_codeset) if host_os == 'darwin' profile_dir = '/Library/ColorSync/Profiles' elif host_os == 'windows' # need double escapes since this will get pasted into a #define in a C # header ... the C:\Windows is usually overwritten with the result of # GetWindowsDirectoryW() profile_dir = 'C:\\\\Windows\\\\System32\\\\spool\\\\drivers\\\\color' else profile_dir = get_option('prefix') / get_option('datadir') / 'color' / 'icc' endif cfg_var.set_quoted('VIPS_ICC_DIR', profile_dir) config_file = configure_file( configuration: cfg_var, output: 'config.h' ) config_dep = declare_dependency( sources: config_file, include_directories: include_directories('.'), compile_args: '-DHAVE_CONFIG_H', ) libvips_deps = [config_dep] + external_deps + other_deps gir = find_program('g-ir-scanner', required: get_option('introspection')) enable_introspection = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled()) build_summary = { 'Build options': {'enable debug': [get_option('debug')], 'enable deprecated': [get_option('deprecated')], 'enable modules': [modules_enabled], 'enable docs': [get_option('docs')], 'enable C++ docs': [get_option('cpp-docs')], 'enable introspection': [enable_introspection], 'enable examples': [get_option('examples')], 'enable C++ binding': [get_option('cplusplus')], 'enable RAD load/save': [get_option('radiance')], 'enable Analyze7 load': [get_option('analyze')], 'enable PPM load/save': [get_option('ppm')], 'enable GIF load': [get_option('nsgif')], }, } build_features = { 'Optional external packages': {'FFTs': ['fftw', fftw_dep], 'SIMD support': ['libhwy or liborc', simd_package], 'ICC profile support': ['lcms2', lcms_dep], 'deflate compression': ['zlib', zlib_dep], 'text rendering': ['pangocairo', pangocairo_dep], 'font file support': ['fontconfig', fontconfig_found ? fontconfig_dep : disabler()], 'EXIF metadata support': ['libexif', libexif_dep], }, 'External image format libraries': {'JPEG load/save': ['libjpeg', libjpeg_dep], 'UHDR load/save': ['libuhdr', libuhdr_dep], 'JXL load/save': ['libjxl', libjxl_found ? libjxl_dep : disabler(), libjxl_module], 'JPEG2000 load/save': ['OpenJPEG', libopenjp2_dep], 'PNG load/save': ['libpng or spng', png_package], 'image quantisation': ['imagequant or quantizr', quantisation_package], 'TIFF load/save': ['libtiff', libtiff_dep], 'image pyramid save': ['libarchive', libarchive_dep], 'HEIC/AVIF load/save': ['libheif', libheif_dep, libheif_module], 'WebP load/save': ['libwebp', libwebp_dep], 'PDF load': ['PDFium or Poppler', pdf_loader, libpoppler_module], 'SVG load': ['librsvg', librsvg_found ? librsvg_dep : disabler()], 'EXR load': ['OpenEXR', openexr_dep], 'WSI load': ['OpenSlide', openslide_dep, openslide_module], 'Matlab load': ['Matio', matio_dep], 'NIfTI load/save': ['libnifti', libnifti_found ? libnifti_dep : disabler()], 'FITS load/save': ['cfitsio', cfitsio_dep], 'GIF save': ['cgif', cgif_dep], 'RAW load': ['libraw', libraw_dep], 'Magick @0@'.format('/'.join(get_option('magick-features'))): [get_option('magick-package'), magick_found ? magick_dep : disabler(), magick_module], }, } # external_deps can have duplicates (eg. cairo can appear several times), # which will make summary fail seen_deps = [] foreach dep: external_deps + module_deps if dep.type_name() != 'internal' and dep.name() not in seen_deps summary(dep.name(), dep.version(), section: 'Dependencies') seen_deps += dep.name() endif endforeach foreach section_title, section : build_summary summary(section, bool_yn: true, section: section_title) endforeach foreach section_title, section: build_features foreach key, arr : section dep_name = arr[0] found = arr[1].found() if found and arr[1].type_name() != 'internal' dep_name = arr[1].name() endif dynamic_module = arr.length() > 2 ? [' (dynamic module: ', arr[2], ')'] : [] summary('@0@ with @1@'.format(key, dep_name), [found] + dynamic_module, bool_yn: true, list_sep: '', section: section_title) endforeach endforeach subdir('libvips') if get_option('docs') subdir('doc') endif if get_option('examples') subdir('examples') endif if get_option('cplusplus') subdir('cplusplus') endif # these lines removed by a regexp for oss-fuzz builds, don't touch! subdir('man') subdir('po') subdir('tools') subdir('test') subdir('fuzz') libvips-8.18.2/meson_options.txt000066400000000000000000000123251516303661500167300ustar00rootroot00000000000000# core options option('deprecated', type: 'boolean', value: true, description: 'Build deprecated components') option('examples', type: 'boolean', value: true, description: 'Build example programs') option('cplusplus', type: 'boolean', value: true, description: 'Build C++ API') option('cpp-docs', type: 'boolean', value: false, description: 'Build C++ documentation (requires doxygen)') option('docs', type: 'boolean', value: false, description: 'Build API reference and tools documentation (requires gi-docgen)') option('modules', type: 'feature', value: 'enabled', description: 'Build dynamic modules') option('introspection', type: 'feature', value: 'auto', description: 'Build GObject introspection data') option('vapi', type: 'boolean', value: false, description: 'Build VAPI') # External libraries option('cfitsio', type: 'feature', value: 'auto', description: 'Build with cfitsio') option('cgif', type: 'feature', value: 'auto', description: 'Build with cgif') option('exif', type: 'feature', value: 'auto', description: 'Build with libexif') option('fftw', type: 'feature', value: 'auto', description: 'Build with fftw3') option('fontconfig', type: 'feature', value: 'auto', description: 'Build with fontconfig') option('archive', type: 'feature', value: 'auto', description: 'Build with libarchive') option('heif', type: 'feature', value: 'auto', description: 'Build with libheif') option('heif-module', type: 'feature', value: 'auto', description: 'Build libheif as module') option('imagequant', type: 'feature', value: 'auto', description: 'Build with imagequant') option('jpeg', type: 'feature', value: 'auto', description: 'Build with jpeg') option('uhdr', type: 'feature', value: 'auto', description: 'Build with libuhdr') option('jpeg-xl', type: 'feature', value: 'auto', description: 'Build with libjxl') option('jpeg-xl-module', type: 'feature', value: 'auto', description: 'Build libjxl as module') option('lcms', type: 'feature', value: 'auto', description: 'Build with lcms2') option('magick', type: 'feature', value: 'auto', description: 'Build with libMagic') option('magick-package', type: 'string', value: 'MagickCore', description: 'ImageMagick package to build with') option('magick-features', type: 'array', choices: ['load', 'save'], value: ['load', 'save'], description: 'Enable libMagic load or save capabilities') option('magick-module', type: 'feature', value: 'auto', description: 'Build libMagic as module') option('matio', type: 'feature', value: 'auto', description: 'Build with matio') option('nifti', type: 'feature', value: 'auto', description: 'Build with nifti') option('nifti-prefix-dir', type: 'string', value: '', description: 'Prefix where nifticlib is installed (optional)') option('openexr', type: 'feature', value: 'auto', description: 'Build with OpenEXR') option('openjpeg', type: 'feature', value: 'auto', description: 'Build with libopenjp2') option('openslide', type: 'feature', value: 'auto', description: 'Build with OpenSlide') option('openslide-module', type: 'feature', value: 'auto', description: 'Build OpenSlide as module') option('highway', type: 'feature', value: 'auto', description: 'Build with highway') option('orc', type: 'feature', value: 'auto', description: 'Build with orc-0.4') option('pangocairo', type: 'feature', value: 'auto', description: 'Build with pangocairo') option('pdfium', type: 'feature', value: 'auto', description: 'Build with pdfium') option('png', type: 'feature', value: 'auto', description: 'Build with png') option('poppler', type: 'feature', value: 'auto', description: 'Build with poppler') option('poppler-module', type: 'feature', value: 'auto', description: 'Build poppler as module') option('quantizr', type: 'feature', value: 'auto', description: 'Build with quantizr') option('raw', type: 'feature', value: 'auto', description: 'Build with libraw') option('rsvg', type: 'feature', value: 'auto', description: 'Build with rsvg') option('spng', type: 'feature', value: 'auto', description: 'Build with spng') option('tiff', type: 'feature', value: 'auto', description: 'Build with tiff') option('webp', type: 'feature', value: 'auto', description: 'Build with libwebp') option('zlib', type: 'feature', value: 'auto', description: 'Build with zlib') # not external libraries, but we have options to disable them to reduce # the potential attack surface option('nsgif', type: 'boolean', value: true, description: 'Build with nsgif') option('ppm', type: 'boolean', value: true, description: 'Build with ppm') option('analyze', type: 'boolean', value: true, description: 'Build with analyze') option('radiance', type: 'boolean', value: true, description: 'Build with radiance') # fuzzing options option('fuzzing_engine', type: 'combo', choices : ['none', 'libfuzzer', 'oss-fuzz'], value: 'none', description: 'Select the fuzzing engine') option('fuzzer_ldflags', type: 'string', description: 'Extra LDFLAGS used during linking of fuzzing binaries') libvips-8.18.2/po/000077500000000000000000000000001516303661500137065ustar00rootroot00000000000000libvips-8.18.2/po/ChangeLog000066400000000000000000000000221516303661500154520ustar00rootroot00000000000000started 17 dec 03 libvips-8.18.2/po/LINGUAS000066400000000000000000000000111516303661500147230ustar00rootroot00000000000000de en_GB libvips-8.18.2/po/POTFILES.in000066400000000000000000000271111516303661500154650ustar00rootroot00000000000000cplusplus/include/vips/VConnection8.h cplusplus/include/vips/VError8.h cplusplus/include/vips/VImage8.h cplusplus/include/vips/VInterpolate8.h cplusplus/include/vips/VRegion8.h libvips/include/vips/arithmetic.h libvips/include/vips/basic.h libvips/include/vips/buf.h libvips/include/vips/colour.h libvips/include/vips/connection.h libvips/include/vips/conversion.h libvips/include/vips/convolution.h libvips/include/vips/create.h libvips/include/vips/dbuf.h libvips/include/vips/debug.h libvips/include/vips/dispatch.h libvips/include/vips/draw.h libvips/include/vips/error.h libvips/include/vips/foreign.h libvips/include/vips/format.h libvips/include/vips/freqfilt.h libvips/include/vips/gate.h libvips/include/vips/generate.h libvips/include/vips/header.h libvips/include/vips/histogram.h libvips/include/vips/image.h libvips/include/vips/internal.h libvips/include/vips/interpolate.h libvips/include/vips/intl.h libvips/include/vips/mask.h libvips/include/vips/memory.h libvips/include/vips/morphology.h libvips/include/vips/mosaicing.h libvips/include/vips/object.h libvips/include/vips/operation.h libvips/include/vips/private.h libvips/include/vips/rect.h libvips/include/vips/region.h libvips/include/vips/resample.h libvips/include/vips/sbuf.h libvips/include/vips/semaphore.h libvips/include/vips/thread.h libvips/include/vips/threadpool.h libvips/include/vips/transform.h libvips/include/vips/type.h libvips/include/vips/util.h libvips/include/vips/vector.h libvips/include/vips/video.h libvips/include/vips/vips7compat.h libvips/include/vips/vips.h cplusplus/VConnection.cpp cplusplus/VError.cpp cplusplus/VImage.cpp cplusplus/VInterpolate.cpp cplusplus/vips-operators.cpp cplusplus/VRegion.cpp libvips/arithmetic/abs.c libvips/arithmetic/add.c libvips/arithmetic/arithmetic.c libvips/arithmetic/avg.c libvips/arithmetic/binary.c libvips/arithmetic/boolean.c libvips/arithmetic/clamp.c libvips/arithmetic/complex.c libvips/arithmetic/deviate.c libvips/arithmetic/divide.c libvips/arithmetic/find_trim.c libvips/arithmetic/getpoint.c libvips/arithmetic/hist_find.c libvips/arithmetic/hist_find_indexed.c libvips/arithmetic/hist_find_ndim.c libvips/arithmetic/hough.c libvips/arithmetic/hough_circle.c libvips/arithmetic/hough_line.c libvips/arithmetic/invert.c libvips/arithmetic/linear.c libvips/arithmetic/math2.c libvips/arithmetic/math.c libvips/arithmetic/max.c libvips/arithmetic/maxpair.c libvips/arithmetic/measure.c libvips/arithmetic/min.c libvips/arithmetic/minpair.c libvips/arithmetic/multiply.c libvips/arithmetic/nary.c libvips/arithmetic/profile.c libvips/arithmetic/project.c libvips/arithmetic/relational.c libvips/arithmetic/remainder.c libvips/arithmetic/round.c libvips/arithmetic/sign.c libvips/arithmetic/statistic.c libvips/arithmetic/stats.c libvips/arithmetic/subtract.c libvips/arithmetic/sum.c libvips/arithmetic/unary.c libvips/arithmetic/unaryconst.c libvips/colour/CMYK2XYZ.c libvips/colour/colour.c libvips/colour/colourspace.c libvips/colour/dE00.c libvips/colour/dE76.c libvips/colour/dECMC.c libvips/colour/float2rad.c libvips/colour/HSV2sRGB.c libvips/colour/icc_transform.c libvips/colour/Lab2LabQ.c libvips/colour/Lab2LabS.c libvips/colour/Lab2LCh.c libvips/colour/Lab2XYZ.c libvips/colour/LabQ2Lab.c libvips/colour/LabQ2LabS.c libvips/colour/LabQ2sRGB.c libvips/colour/LabS2Lab.c libvips/colour/LabS2LabQ.c libvips/colour/LCh2Lab.c libvips/colour/LCh2UCS.c libvips/colour/Oklab2Oklch.c libvips/colour/Oklab2XYZ.c libvips/colour/Oklch2Oklab.c libvips/colour/profile_load.c libvips/colour/profiles.c libvips/colour/rad2float.c libvips/colour/scRGB2BW.c libvips/colour/scRGB2sRGB.c libvips/colour/scRGB2XYZ.c libvips/colour/sRGB2HSV.c libvips/colour/sRGB2scRGB.c libvips/colour/UCS2LCh.c libvips/colour/uhdr2scRGB.c libvips/colour/XYZ2CMYK.c libvips/colour/XYZ2Lab.c libvips/colour/XYZ2Oklab.c libvips/colour/XYZ2scRGB.c libvips/colour/XYZ2Yxy.c libvips/colour/Yxy2XYZ.c libvips/conversion/addalpha.c libvips/conversion/arrayjoin.c libvips/conversion/autorot.c libvips/conversion/bandary.c libvips/conversion/bandbool.c libvips/conversion/bandfold.c libvips/conversion/bandjoin.c libvips/conversion/bandmean.c libvips/conversion/bandrank.c libvips/conversion/bandunfold.c libvips/conversion/byteswap.c libvips/conversion/cache.c libvips/conversion/cast.c libvips/conversion/composite.cpp libvips/conversion/conversion.c libvips/conversion/copy.c libvips/conversion/embed.c libvips/conversion/extract.c libvips/conversion/falsecolour.c libvips/conversion/flatten.c libvips/conversion/flip.c libvips/conversion/gamma.c libvips/conversion/grid.c libvips/conversion/ifthenelse.c libvips/conversion/insert.c libvips/conversion/join.c libvips/conversion/msb.c libvips/conversion/premultiply.c libvips/conversion/recomb.c libvips/conversion/replicate.c libvips/conversion/rot45.c libvips/conversion/rot.c libvips/conversion/scale.c libvips/conversion/sequential.c libvips/conversion/smartcrop.c libvips/conversion/subsample.c libvips/conversion/switch.c libvips/conversion/tilecache.c libvips/conversion/transpose3d.c libvips/conversion/unpremultiply.c libvips/conversion/wrap.c libvips/conversion/zoom.c libvips/convolution/canny.c libvips/convolution/compass.c libvips/convolution/conva.c libvips/convolution/convasep.c libvips/convolution/conv.c libvips/convolution/convf.c libvips/convolution/convi.c libvips/convolution/convi_hwy.cpp libvips/convolution/convolution.c libvips/convolution/convsep.c libvips/convolution/correlation.c libvips/convolution/edge.c libvips/convolution/fastcor.c libvips/convolution/gaussblur.c libvips/convolution/sharpen.c libvips/convolution/spcor.c libvips/create/black.c libvips/create/buildlut.c libvips/create/create.c libvips/create/eye.c libvips/create/fractsurf.c libvips/create/gaussmat.c libvips/create/gaussnoise.c libvips/create/grey.c libvips/create/identity.c libvips/create/invertlut.c libvips/create/logmat.c libvips/create/mask_butterworth_band.c libvips/create/mask_butterworth.c libvips/create/mask_butterworth_ring.c libvips/create/mask.c libvips/create/mask_fractal.c libvips/create/mask_gaussian_band.c libvips/create/mask_gaussian.c libvips/create/mask_gaussian_ring.c libvips/create/mask_ideal_band.c libvips/create/mask_ideal.c libvips/create/mask_ideal_ring.c libvips/create/perlin.c libvips/create/point.c libvips/create/sdf.c libvips/create/sines.c libvips/create/text.c libvips/create/tonelut.c libvips/create/worley.c libvips/create/xyz.c libvips/create/zone.c libvips/draw/draw.c libvips/draw/draw_circle.c libvips/draw/draw_flood.c libvips/draw/draw_image.c libvips/draw/drawink.c libvips/draw/draw_line.c libvips/draw/draw_mask.c libvips/draw/draw_rect.c libvips/draw/draw_smudge.c libvips/foreign/analyze2vips.c libvips/foreign/analyzeload.c libvips/foreign/archive.c libvips/foreign/cairo.c libvips/foreign/cgifsave.c libvips/foreign/csvload.c libvips/foreign/csvsave.c libvips/foreign/dcrawload.c libvips/foreign/dzsave.c libvips/foreign/exif.c libvips/foreign/fits.c libvips/foreign/fitsload.c libvips/foreign/fitssave.c libvips/foreign/foreign.c libvips/foreign/heifload.c libvips/foreign/heifsave.c libvips/foreign/jp2kload.c libvips/foreign/jp2ksave.c libvips/foreign/jpeg2vips.c libvips/foreign/jpegload.c libvips/foreign/jpegsave.c libvips/foreign/jxlload.c libvips/foreign/jxlsave.c libvips/foreign/magick6load.c libvips/foreign/magick7load.c libvips/foreign/magick.c libvips/foreign/magickload.c libvips/foreign/magicksave.c libvips/foreign/matlab.c libvips/foreign/matload.c libvips/foreign/matrixload.c libvips/foreign/matrixsave.c libvips/foreign/niftiload.c libvips/foreign/niftisave.c libvips/foreign/nsgifload.c libvips/foreign/openexr2vips.c libvips/foreign/openexrload.c libvips/foreign/openslideconnection.c libvips/foreign/openslideload.c libvips/foreign/pdf.c libvips/foreign/pdfiumload.c libvips/foreign/pngload.c libvips/foreign/pngsave.c libvips/foreign/popplerload.c libvips/foreign/ppmload.c libvips/foreign/ppmsave.c libvips/foreign/quantise.c libvips/foreign/radiance.c libvips/foreign/radload.c libvips/foreign/radsave.c libvips/foreign/rawload.c libvips/foreign/rawsave.c libvips/foreign/spngload.c libvips/foreign/spngsave.c libvips/foreign/svgload.c libvips/foreign/tiff2vips.c libvips/foreign/tiff.c libvips/foreign/tiffload.c libvips/foreign/tiffsave.c libvips/foreign/uhdrload.c libvips/foreign/uhdrsave.c libvips/foreign/vips2jpeg.c libvips/foreign/vips2magick.c libvips/foreign/vips2tiff.c libvips/foreign/vipsload.c libvips/foreign/vipspng.c libvips/foreign/vipssave.c libvips/foreign/webp2vips.c libvips/foreign/webpload.c libvips/foreign/webpsave.c libvips/freqfilt/freqfilt.c libvips/freqfilt/freqmult.c libvips/freqfilt/fwfft.c libvips/freqfilt/invfft.c libvips/freqfilt/phasecor.c libvips/freqfilt/spectrum.c libvips/histogram/case.c libvips/histogram/hist_cum.c libvips/histogram/hist_entropy.c libvips/histogram/hist_equal.c libvips/histogram/hist_ismonotonic.c libvips/histogram/hist_local.c libvips/histogram/hist_match.c libvips/histogram/hist_norm.c libvips/histogram/histogram.c libvips/histogram/hist_plot.c libvips/histogram/hist_unary.c libvips/histogram/maplut.c libvips/histogram/percent.c libvips/histogram/stdif.c libvips/iofuncs/buf.c libvips/iofuncs/buffer.c libvips/iofuncs/cache.c libvips/iofuncs/connection.c libvips/iofuncs/dbuf.c libvips/iofuncs/error.c libvips/iofuncs/gate.c libvips/iofuncs/generate.c libvips/iofuncs/ginputsource.c libvips/iofuncs/header.c libvips/iofuncs/image.c libvips/iofuncs/init.c libvips/iofuncs/mapfile.c libvips/iofuncs/memory.c libvips/iofuncs/object.c libvips/iofuncs/operation.c libvips/iofuncs/rect.c libvips/iofuncs/region.c libvips/iofuncs/reorder.c libvips/iofuncs/sbuf.c libvips/iofuncs/semaphore.c libvips/iofuncs/sink.c libvips/iofuncs/sinkdisc.c libvips/iofuncs/sinkmemory.c libvips/iofuncs/sinkscreen.c libvips/iofuncs/source.c libvips/iofuncs/sourcecustom.c libvips/iofuncs/sourceginput.c libvips/iofuncs/system.c libvips/iofuncs/target.c libvips/iofuncs/targetcustom.c libvips/iofuncs/thread.c libvips/iofuncs/threadpool.c libvips/iofuncs/threadset.c libvips/iofuncs/type.c libvips/iofuncs/util.c libvips/iofuncs/vector.cpp libvips/iofuncs/vips.c libvips/iofuncs/window.c libvips/module/heif.c libvips/module/jxl.c libvips/module/magick.c libvips/module/openslide.c libvips/module/poppler.c libvips/morphology/countlines.c libvips/morphology/labelregions.c libvips/morphology/morph.c libvips/morphology/morph_hwy.cpp libvips/morphology/morphology.c libvips/morphology/nearest.c libvips/morphology/rank.c libvips/mosaicing/chkpair.c libvips/mosaicing/global_balance.c libvips/mosaicing/im_avgdxdy.c libvips/mosaicing/im_clinear.c libvips/mosaicing/im_improve.c libvips/mosaicing/im_initialize.c libvips/mosaicing/im_lrcalcon.c libvips/mosaicing/im_tbcalcon.c libvips/mosaicing/lrmerge.c libvips/mosaicing/lrmosaic.c libvips/mosaicing/match.c libvips/mosaicing/matrixinvert.c libvips/mosaicing/matrixmultiply.c libvips/mosaicing/merge.c libvips/mosaicing/mosaic1.c libvips/mosaicing/mosaic.c libvips/mosaicing/mosaicing.c libvips/mosaicing/remosaic.c libvips/mosaicing/tbmerge.c libvips/mosaicing/tbmosaic.c libvips/resample/affine.c libvips/resample/bicubic.cpp libvips/resample/interpolate.c libvips/resample/lbb.cpp libvips/resample/mapim.c libvips/resample/nohalo.cpp libvips/resample/quadratic.c libvips/resample/reduce.c libvips/resample/reduceh.cpp libvips/resample/reduceh_hwy.cpp libvips/resample/reducev.cpp libvips/resample/reducev_hwy.cpp libvips/resample/resample.c libvips/resample/resize.c libvips/resample/shrink.c libvips/resample/shrinkh.c libvips/resample/shrinkh_hwy.cpp libvips/resample/shrinkv.c libvips/resample/shrinkv_hwy.cpp libvips/resample/similarity.c libvips/resample/thumbnail.c libvips/resample/transform.c libvips/resample/vsqbs.cpp tools/vips.c tools/vipsedit.c tools/vipsheader.c tools/vipsthumbnail.c libvips-8.18.2/po/POTFILES.skip000066400000000000000000000000001516303661500160110ustar00rootroot00000000000000libvips-8.18.2/po/README000066400000000000000000000033121516303661500145650ustar00rootroot00000000000000translators ----------- see this page for a howto: http://developer.gnome.org/doc/tutorials/gnome-i18n/translator.html Things like msgid "/File/_Save Image As ..." are menu items. You only need to translate the last part (following the final "/"). The underscore character marks the accelerator (the underlined character in the menu item). So you could put: msgstr "Sevy i_mago os ..." and it would display as "Sevy imago os ...", with the "m" underlined. tips ---- cd vips-8.x find cplusplus/include libvips/include \ -name '*deprecated*' -prune -o \ -name '*.h' \ -printf '%h\0%d\0%p\n' | \ sort -t '\0' -n | \ awk -F '\0' '{print $3}' > po/POTFILES.in find libvips tools cplusplus \ -path libvips/deprecated -prune -o \ -path libvips/foreign/libnsgif -prune -o \ -path cplusplus/examples -prune -o \ \( -name '*.c' -o -name '*.cpp' \) \ -printf '%h\0%d\0%p\n' | \ sort -t '\0' -n | \ awk -F '\0' '{print $3}' >> po/POTFILES.in cd vips-8.x/po intltool-update --pot make a new vips8.x.pot translation template from the sources add header # test translation file # Copyright (C) 2019 # This file is distributed under the same license as the libvips package. # John Cupitt , 2019. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: vips 8.9.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-08-06 15:19+0100\n" "PO-Revision-Date: 2019-08-06 15:19+0100\n" "Last-Translator: john \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=s;\n" edits to make vips8.xx.pot into test.po msgfmt -cv -o /dev/null test.po check translation for errors libvips-8.18.2/po/de.po000066400000000000000000007006641516303661500146530ustar00rootroot00000000000000# German translation of vips. # Copyright (C) 1990-2009 Imperial College, London and others. # This file is distributed under the same license as the vips package. # Copyright of this file (C) Chris Leick 2010-2013. # See also http://www.gnu-darwin.org/www001/src/ports/graphics/vips/work/ # vips-7.12.4/doc/pdf/vipsmanual.pdf # msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-06-05 11:45+0200\n" "PO-Revision-Date: 2014-03-12 21:58+0100\n" "Last-Translator: Chris Leick \n" "Language-Team: Debian German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" # http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650& # db=man&fname=/usr/share/catman/p_man/cat3/il_c/ilAbsImg.z #: libvips/arithmetic/abs.c:200 msgid "absolute value of an image" msgstr "absoluter Wert eines Bildes" #: libvips/arithmetic/add.c:178 msgid "add two images" msgstr "zwei Bilder hinzufügen" #: libvips/arithmetic/arithmetic.c:185 #, c-format msgid "not one band or %d bands" msgstr "nicht ein Band oder %d Bänder" #: libvips/arithmetic/arithmetic.c:190 libvips/foreign/spngsave.c:422 msgid "bad bands" msgstr "falsche Bänder" #: libvips/arithmetic/arithmetic.c:518 msgid "arithmetic operations" msgstr "arithmetische Transaktionen" #: libvips/arithmetic/arithmetic.c:524 libvips/arithmetic/avg.c:235 #: libvips/arithmetic/deviate.c:237 libvips/arithmetic/hist_find.c:431 #: libvips/arithmetic/hist_find_indexed.c:475 #: libvips/arithmetic/hist_find_ndim.c:313 libvips/arithmetic/hough.c:179 #: libvips/arithmetic/max.c:452 libvips/arithmetic/measure.c:201 #: libvips/arithmetic/min.c:452 libvips/arithmetic/stats.c:442 #: libvips/colour/CMYK2XYZ.c:126 libvips/colour/colour.c:316 #: libvips/colour/colourspace.c:566 libvips/colour/XYZ2CMYK.c:125 #: libvips/conversion/conversion.c:332 libvips/conversion/switch.c:202 #: libvips/convolution/canny.c:448 libvips/convolution/convolution.c:124 #: libvips/convolution/correlation.c:162 libvips/convolution/edge.c:223 #: libvips/convolution/gaussblur.c:138 libvips/convolution/sharpen.c:328 #: libvips/create/create.c:116 libvips/foreign/foreign.c:1223 #: libvips/freqfilt/freqfilt.c:93 libvips/histogram/case.c:252 #: libvips/histogram/hist_entropy.c:117 libvips/histogram/hist_equal.c:120 #: libvips/histogram/hist_local.c:367 libvips/histogram/hist_norm.c:147 #: libvips/histogram/histogram.c:204 libvips/histogram/hist_plot.c:339 #: libvips/histogram/maplut.c:750 libvips/histogram/stdif.c:300 #: libvips/iofuncs/system.c:284 libvips/morphology/morph.c:960 #: libvips/morphology/rank.c:564 libvips/mosaicing/global_balance.c:1924 #: libvips/mosaicing/match.c:208 libvips/mosaicing/matrixinvert.c:450 #: libvips/mosaicing/matrixmultiply.c:159 libvips/mosaicing/merge.c:134 #: libvips/mosaicing/mosaic1.c:510 libvips/mosaicing/mosaic.c:191 #: libvips/mosaicing/remosaic.c:170 libvips/resample/resample.c:110 #: libvips/resample/thumbnail.c:968 msgid "Output" msgstr "Ausgabe" #: libvips/arithmetic/arithmetic.c:525 libvips/arithmetic/hough.c:180 #: libvips/colour/CMYK2XYZ.c:127 libvips/colour/colour.c:317 #: libvips/colour/colourspace.c:567 libvips/colour/XYZ2CMYK.c:126 #: libvips/conversion/conversion.c:333 libvips/conversion/switch.c:203 #: libvips/convolution/canny.c:449 libvips/convolution/convolution.c:125 #: libvips/convolution/correlation.c:163 libvips/convolution/edge.c:224 #: libvips/convolution/gaussblur.c:139 libvips/convolution/sharpen.c:329 #: libvips/create/create.c:117 libvips/foreign/foreign.c:1224 #: libvips/freqfilt/freqfilt.c:94 libvips/histogram/case.c:253 #: libvips/histogram/hist_equal.c:121 libvips/histogram/hist_local.c:368 #: libvips/histogram/hist_norm.c:148 libvips/histogram/histogram.c:205 #: libvips/histogram/hist_plot.c:340 libvips/histogram/maplut.c:751 #: libvips/histogram/stdif.c:301 libvips/iofuncs/system.c:285 #: libvips/morphology/morph.c:961 libvips/morphology/rank.c:565 #: libvips/mosaicing/global_balance.c:1925 libvips/mosaicing/match.c:209 #: libvips/mosaicing/merge.c:135 libvips/mosaicing/mosaic1.c:511 #: libvips/mosaicing/mosaic.c:192 libvips/mosaicing/remosaic.c:171 #: libvips/resample/resample.c:111 libvips/resample/thumbnail.c:969 msgid "Output image" msgstr "Ausgabebild" #: libvips/arithmetic/avg.c:227 msgid "find image average" msgstr "Bildmittelwert finden" #: libvips/arithmetic/avg.c:236 libvips/arithmetic/deviate.c:238 #: libvips/arithmetic/max.c:453 libvips/arithmetic/min.c:453 #: libvips/histogram/hist_entropy.c:118 msgid "Output value" msgstr "Ausgabewert" #: libvips/arithmetic/binary.c:89 msgid "binary operations" msgstr "binäre Transaktionen" #: libvips/arithmetic/binary.c:96 libvips/arithmetic/find_trim.c:216 #: libvips/arithmetic/measure.c:221 libvips/colour/colour.c:585 #: libvips/conversion/extract.c:200 libvips/draw/draw_flood.c:593 #: libvips/draw/draw_rect.c:173 libvips/draw/draw_smudge.c:215 #: libvips/mosaicing/matrixmultiply.c:147 msgid "Left" msgstr "links" #: libvips/arithmetic/binary.c:97 msgid "Left-hand image argument" msgstr "linksseitiges Bildargument" #: libvips/arithmetic/binary.c:102 libvips/colour/colour.c:591 #: libvips/mosaicing/matrixmultiply.c:153 msgid "Right" msgstr "rechts" #: libvips/arithmetic/binary.c:103 msgid "Right-hand image argument" msgstr "rechtsseitiges Bildargument" #: libvips/arithmetic/boolean.c:269 #, fuzzy msgid "boolean operation on two images" msgstr "eine Wahr-/Falsch-Transaktion für ein Bilderpaar" #: libvips/arithmetic/boolean.c:277 libvips/arithmetic/boolean.c:578 #: libvips/arithmetic/complex.c:258 libvips/arithmetic/complex.c:538 #: libvips/arithmetic/complex.c:771 libvips/arithmetic/math2.c:241 #: libvips/arithmetic/math2.c:472 libvips/arithmetic/math.c:261 #: libvips/arithmetic/relational.c:246 libvips/arithmetic/relational.c:613 #: libvips/conversion/bandbool.c:238 tools/vips.c:627 msgid "Operation" msgstr "Transaktion" #: libvips/arithmetic/boolean.c:278 libvips/arithmetic/boolean.c:579 #: libvips/conversion/bandbool.c:239 #, fuzzy msgid "Boolean to perform" msgstr "Boolesch zur Durchführung" #: libvips/arithmetic/boolean.c:570 msgid "boolean operations against a constant" msgstr "boolesche Transaktionen mit einer Konstante" # http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650& # db=man&fname=/usr/share/catman/p_man/cat3/il_c/ilAbsImg.z #: libvips/arithmetic/clamp.c:155 #, fuzzy msgid "clamp values of an image" msgstr "absoluter Wert eines Bildes" #: libvips/arithmetic/clamp.c:162 #, fuzzy msgid "Min" msgstr "primär" #: libvips/arithmetic/clamp.c:163 #, fuzzy msgid "Minimum value" msgstr "Minimalwert des Bildes" #: libvips/arithmetic/clamp.c:169 msgid "Max" msgstr "" #: libvips/arithmetic/clamp.c:170 #, fuzzy msgid "Maximum value" msgstr "Maximalwert des Bildes" #: libvips/arithmetic/complex.c:251 msgid "perform a complex operation on an image" msgstr "eine komplexe Transaktion mit einem Bild durchführen" #: libvips/arithmetic/complex.c:259 libvips/arithmetic/complex.c:772 #, fuzzy msgid "Complex to perform" msgstr "komplex durchzuführen" #: libvips/arithmetic/complex.c:531 #, fuzzy msgid "complex binary operations on two images" msgstr "eine komplexe Transaktion mit einem Bild durchführen" #: libvips/arithmetic/complex.c:539 #, fuzzy msgid "Binary complex operation to perform" msgstr "durchzuführende Rundungstransakktion" #: libvips/arithmetic/complex.c:762 msgid "get a component from a complex image" msgstr "einen Bestandteil eines komplexen Bildes holen" #: libvips/arithmetic/complex.c:978 msgid "form a complex image from two real images" msgstr "ein komplexes Bild aus zwei echten Bildern erstellen" #: libvips/arithmetic/deviate.c:229 #, fuzzy msgid "find image standard deviation" msgstr "Standardabweichung des Bildes" #: libvips/arithmetic/divide.c:210 msgid "divide two images" msgstr "zwei Bilder teilen" #: libvips/arithmetic/find_trim.c:183 msgid "search an image for non-edge areas" msgstr "" #: libvips/arithmetic/find_trim.c:189 libvips/arithmetic/getpoint.c:153 #: libvips/arithmetic/measure.c:195 libvips/arithmetic/nary.c:87 #: libvips/arithmetic/statistic.c:167 libvips/arithmetic/unary.c:88 #: libvips/colour/CMYK2XYZ.c:120 libvips/colour/colour.c:381 #: libvips/colour/colour.c:474 libvips/colour/colourspace.c:560 #: libvips/colour/XYZ2CMYK.c:119 libvips/conversion/addalpha.c:90 #: libvips/conversion/arrayjoin.c:394 libvips/conversion/autorot.c:207 #: libvips/conversion/bandbool.c:232 libvips/conversion/bandfold.c:161 #: libvips/conversion/bandjoin.c:201 libvips/conversion/bandjoin.c:437 #: libvips/conversion/bandmean.c:212 libvips/conversion/bandrank.c:254 #: libvips/conversion/bandunfold.c:164 libvips/conversion/byteswap.c:238 #: libvips/conversion/cache.c:108 libvips/conversion/cast.c:529 #: libvips/conversion/copy.c:271 libvips/conversion/embed.c:568 #: libvips/conversion/extract.c:194 libvips/conversion/extract.c:434 #: libvips/conversion/falsecolour.c:380 libvips/conversion/flatten.c:416 #: libvips/conversion/flip.c:240 libvips/conversion/gamma.c:142 #: libvips/conversion/grid.c:199 libvips/conversion/msb.c:247 #: libvips/conversion/premultiply.c:261 libvips/conversion/recomb.c:224 #: libvips/conversion/replicate.c:196 libvips/conversion/rot45.c:268 #: libvips/conversion/rot.c:365 libvips/conversion/scale.c:155 #: libvips/conversion/sequential.c:243 libvips/conversion/smartcrop.c:433 #: libvips/conversion/subsample.c:267 libvips/conversion/tilecache.c:408 #: libvips/conversion/transpose3d.c:167 libvips/conversion/unpremultiply.c:323 #: libvips/conversion/wrap.c:119 libvips/conversion/zoom.c:373 #: libvips/convolution/canny.c:442 libvips/convolution/convolution.c:118 #: libvips/convolution/correlation.c:150 libvips/convolution/edge.c:217 #: libvips/convolution/gaussblur.c:132 libvips/convolution/sharpen.c:322 #: libvips/create/buildlut.c:263 libvips/create/invertlut.c:288 #: libvips/foreign/foreign.c:1866 libvips/freqfilt/freqfilt.c:87 #: libvips/histogram/hist_entropy.c:111 libvips/histogram/hist_equal.c:114 #: libvips/histogram/hist_ismonotonic.c:118 libvips/histogram/hist_local.c:361 #: libvips/histogram/hist_match.c:161 libvips/histogram/hist_norm.c:141 #: libvips/histogram/hist_plot.c:333 libvips/histogram/hist_unary.c:88 #: libvips/histogram/maplut.c:744 libvips/histogram/percent.c:109 #: libvips/histogram/stdif.c:294 libvips/iofuncs/ginputsource.c:274 #: libvips/iofuncs/sbuf.c:83 libvips/iofuncs/system.c:277 #: libvips/morphology/morphology.c:71 libvips/mosaicing/global_balance.c:1918 #: libvips/mosaicing/matrixinvert.c:444 libvips/mosaicing/remosaic.c:164 #: libvips/resample/resample.c:104 libvips/resample/thumbnail.c:1803 msgid "Input" msgstr "Eingabe" #: libvips/arithmetic/find_trim.c:190 #, fuzzy msgid "Image to find_trim" msgstr "Bilddateiname" #: libvips/arithmetic/find_trim.c:195 libvips/histogram/percent.c:122 msgid "Threshold" msgstr "" #: libvips/arithmetic/find_trim.c:196 msgid "Object threshold" msgstr "" #: libvips/arithmetic/find_trim.c:202 libvips/conversion/arrayjoin.c:415 #: libvips/conversion/embed.c:595 libvips/conversion/flatten.c:422 #: libvips/conversion/insert.c:499 libvips/conversion/join.c:270 #: libvips/foreign/foreign.c:1880 libvips/foreign/pdfiumload.c:721 #: libvips/foreign/popplerload.c:571 libvips/resample/affine.c:699 #: libvips/resample/mapim.c:574 libvips/resample/similarity.c:133 msgid "Background" msgstr "Hintergrund" #: libvips/arithmetic/find_trim.c:203 libvips/conversion/embed.c:596 #, fuzzy msgid "Color for background pixels" msgstr "Farbe für neue Bildpunkte" #: libvips/arithmetic/find_trim.c:209 msgid "Line art mode" msgstr "" #: libvips/arithmetic/find_trim.c:210 msgid "Enable line art mode" msgstr "" #: libvips/arithmetic/find_trim.c:217 #, fuzzy msgid "Left edge of image" msgstr "linker Rand des Teilbilds im Hauptbild" #: libvips/arithmetic/find_trim.c:223 libvips/arithmetic/measure.c:228 #: libvips/conversion/extract.c:207 libvips/draw/draw_flood.c:600 #: libvips/draw/draw_rect.c:180 libvips/draw/draw_smudge.c:222 msgid "Top" msgstr "oben" #: libvips/arithmetic/find_trim.c:224 libvips/arithmetic/measure.c:229 #: libvips/conversion/extract.c:208 msgid "Top edge of extract area" msgstr "obere Kante eines extrahierten Bereichs" #: libvips/arithmetic/find_trim.c:230 libvips/arithmetic/hough_line.c:149 #: libvips/arithmetic/measure.c:235 libvips/conversion/copy.c:284 #: libvips/conversion/embed.c:574 libvips/conversion/extract.c:214 #: libvips/conversion/smartcrop.c:439 libvips/create/black.c:140 #: libvips/create/fractsurf.c:104 libvips/create/gaussnoise.c:168 #: libvips/create/logmat.c:208 libvips/create/perlin.c:295 #: libvips/create/point.c:141 libvips/create/sdf.c:304 #: libvips/create/text.c:571 libvips/create/worley.c:308 #: libvips/create/xyz.c:191 libvips/draw/draw_flood.c:607 #: libvips/draw/draw_rect.c:187 libvips/draw/draw_smudge.c:229 #: libvips/foreign/rawload.c:146 libvips/histogram/hist_local.c:373 #: libvips/histogram/stdif.c:308 libvips/iofuncs/image.c:1087 #: libvips/morphology/rank.c:570 msgid "Width" msgstr "Breite" #: libvips/arithmetic/find_trim.c:231 libvips/arithmetic/measure.c:236 #: libvips/conversion/extract.c:215 libvips/conversion/smartcrop.c:440 msgid "Width of extract area" msgstr "Breite des extrahierten Bereichs" #: libvips/arithmetic/find_trim.c:237 libvips/arithmetic/hough_line.c:156 #: libvips/arithmetic/measure.c:242 libvips/conversion/copy.c:291 #: libvips/conversion/embed.c:581 libvips/conversion/extract.c:221 #: libvips/conversion/smartcrop.c:446 libvips/create/black.c:147 #: libvips/create/fractsurf.c:111 libvips/create/gaussnoise.c:175 #: libvips/create/perlin.c:302 libvips/create/point.c:148 #: libvips/create/sdf.c:311 libvips/create/text.c:578 #: libvips/create/worley.c:315 libvips/create/xyz.c:198 #: libvips/draw/draw_flood.c:614 libvips/draw/draw_rect.c:194 #: libvips/draw/draw_smudge.c:236 libvips/foreign/rawload.c:153 #: libvips/histogram/hist_local.c:380 libvips/histogram/stdif.c:315 #: libvips/iofuncs/image.c:1094 libvips/morphology/rank.c:577 msgid "Height" msgstr "Höhe" #: libvips/arithmetic/find_trim.c:238 libvips/arithmetic/measure.c:243 #: libvips/conversion/extract.c:222 libvips/conversion/smartcrop.c:447 msgid "Height of extract area" msgstr "Höhe des extrahierten Bereichs" #: libvips/arithmetic/getpoint.c:149 #, fuzzy msgid "read a point from an image" msgstr "Band aus einem Bild extrahieren" #: libvips/arithmetic/getpoint.c:154 libvips/arithmetic/statistic.c:168 #: libvips/arithmetic/unary.c:89 libvips/colour/CMYK2XYZ.c:121 #: libvips/colour/colour.c:382 libvips/colour/colour.c:475 #: libvips/colour/colourspace.c:561 libvips/colour/XYZ2CMYK.c:120 #: libvips/conversion/addalpha.c:91 libvips/conversion/autorot.c:208 #: libvips/conversion/bandfold.c:162 libvips/conversion/bandjoin.c:438 #: libvips/conversion/bandunfold.c:165 libvips/conversion/byteswap.c:239 #: libvips/conversion/cache.c:109 libvips/conversion/cast.c:530 #: libvips/conversion/copy.c:272 libvips/conversion/embed.c:569 #: libvips/conversion/extract.c:195 libvips/conversion/extract.c:435 #: libvips/conversion/falsecolour.c:381 libvips/conversion/flatten.c:417 #: libvips/conversion/flip.c:241 libvips/conversion/gamma.c:143 #: libvips/conversion/grid.c:200 libvips/conversion/msb.c:248 #: libvips/conversion/premultiply.c:262 libvips/conversion/replicate.c:197 #: libvips/conversion/rot45.c:269 libvips/conversion/rot.c:366 #: libvips/conversion/scale.c:156 libvips/conversion/sequential.c:244 #: libvips/conversion/smartcrop.c:434 libvips/conversion/subsample.c:268 #: libvips/conversion/tilecache.c:409 libvips/conversion/transpose3d.c:168 #: libvips/conversion/unpremultiply.c:324 libvips/conversion/wrap.c:120 #: libvips/conversion/zoom.c:374 libvips/convolution/canny.c:443 #: libvips/convolution/edge.c:218 libvips/convolution/gaussblur.c:133 #: libvips/convolution/sharpen.c:323 libvips/freqfilt/freqfilt.c:88 #: libvips/histogram/hist_equal.c:115 libvips/histogram/hist_local.c:362 #: libvips/histogram/hist_norm.c:142 libvips/histogram/hist_plot.c:334 #: libvips/histogram/hist_unary.c:89 libvips/histogram/maplut.c:745 #: libvips/histogram/percent.c:110 libvips/histogram/stdif.c:295 #: libvips/mosaicing/global_balance.c:1919 libvips/mosaicing/remosaic.c:165 msgid "Input image" msgstr "Eingabebild" #: libvips/arithmetic/getpoint.c:159 libvips/arithmetic/max.c:480 #: libvips/arithmetic/min.c:480 #, fuzzy msgid "Output array" msgstr "Ausgabewert" #: libvips/arithmetic/getpoint.c:160 libvips/arithmetic/max.c:481 #: libvips/arithmetic/min.c:481 #, fuzzy msgid "Array of output values" msgstr "Feld von Eingabebildern" #: libvips/arithmetic/getpoint.c:166 libvips/arithmetic/max.c:459 #: libvips/arithmetic/min.c:459 libvips/conversion/composite.cpp:1741 #: libvips/conversion/embed.c:656 libvips/conversion/wrap.c:125 #: libvips/draw/draw_flood.c:566 libvips/draw/draw_image.c:275 #: libvips/draw/draw_mask.c:338 msgid "x" msgstr "x" #: libvips/arithmetic/getpoint.c:167 libvips/arithmetic/getpoint.c:174 #, fuzzy msgid "Point to read" msgstr "keine Punkte zum Mitteln" #: libvips/arithmetic/getpoint.c:173 libvips/arithmetic/max.c:466 #: libvips/arithmetic/min.c:466 libvips/conversion/composite.cpp:1748 #: libvips/conversion/embed.c:663 libvips/conversion/wrap.c:132 #: libvips/draw/draw_flood.c:573 libvips/draw/draw_image.c:282 #: libvips/draw/draw_mask.c:345 msgid "y" msgstr "y" #: libvips/arithmetic/getpoint.c:180 #, fuzzy msgid "unpack_complex" msgstr "Maske zu komplex" #: libvips/arithmetic/getpoint.c:181 msgid "Complex pixels should be unpacked" msgstr "" #: libvips/arithmetic/hist_find.c:422 #, fuzzy msgid "find image histogram" msgstr "Minimum des Bildes finden" #: libvips/arithmetic/hist_find.c:432 #: libvips/arithmetic/hist_find_indexed.c:476 #: libvips/arithmetic/hist_find_ndim.c:314 #, fuzzy msgid "Output histogram" msgstr "Ausgabebild" #: libvips/arithmetic/hist_find.c:437 libvips/conversion/extract.c:440 #: libvips/conversion/msb.c:253 libvips/histogram/hist_equal.c:126 #: libvips/histogram/maplut.c:762 msgid "Band" msgstr "Band" #: libvips/arithmetic/hist_find.c:438 msgid "Find histogram of band" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:461 msgid "find indexed image histogram" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:469 libvips/conversion/bandrank.c:261 #: libvips/histogram/case.c:239 libvips/morphology/rank.c:584 #: libvips/resample/mapim.c:555 msgid "Index" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:470 libvips/histogram/case.c:240 #, fuzzy msgid "Index image" msgstr "Eingabebild" #: libvips/arithmetic/hist_find_indexed.c:481 libvips/convolution/compass.c:177 msgid "Combine" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:482 msgid "Combine bins like this" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:150 #, fuzzy msgid "image is not 1 - 3 bands" msgstr "Bild muss ein oder %d Bänder haben" #: libvips/arithmetic/hist_find_ndim.c:159 #, fuzzy, c-format msgid "bins out of range [1,%d]" msgstr " »bins« außerhalb des Bereichs [1,%d]" #: libvips/arithmetic/hist_find_ndim.c:304 #, fuzzy msgid "find n-dimensional image histogram" msgstr "%d-dimensionale Bilder nicht unterstützt" #: libvips/arithmetic/hist_find_ndim.c:319 msgid "Bins" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:320 #, fuzzy msgid "Number of bins in each dimension" msgstr "Anzahl der Bänder in einem Bild" #: libvips/arithmetic/hough.c:170 msgid "find hough transform" msgstr "" #: libvips/arithmetic/hough_circle.c:115 msgid "parameters out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/arithmetic/hough_circle.c:226 msgid "find hough circle transform" msgstr "" #: libvips/arithmetic/hough_circle.c:233 libvips/foreign/pdfiumload.c:714 #: libvips/foreign/popplerload.c:564 libvips/foreign/svgload.c:789 #: libvips/foreign/webpload.c:190 libvips/mosaicing/mosaic.c:274 #: libvips/resample/similarity.c:200 msgid "Scale" msgstr "" #: libvips/arithmetic/hough_circle.c:234 msgid "Scale down dimensions by this factor" msgstr "" #: libvips/arithmetic/hough_circle.c:240 msgid "Min radius" msgstr "" #: libvips/arithmetic/hough_circle.c:241 msgid "Smallest radius to search for" msgstr "" #: libvips/arithmetic/hough_circle.c:247 #, fuzzy msgid "Max radius" msgstr "Kacheln maximal" #: libvips/arithmetic/hough_circle.c:248 msgid "Largest radius to search for" msgstr "" #: libvips/arithmetic/hough_line.c:142 msgid "find hough line transform" msgstr "" #: libvips/arithmetic/hough_line.c:150 msgid "Horizontal size of parameter space" msgstr "" #: libvips/arithmetic/hough_line.c:157 msgid "Vertical size of parameter space" msgstr "" #: libvips/arithmetic/invert.c:178 msgid "invert an image" msgstr "ein Bild invertieren" #: libvips/arithmetic/linear.c:446 msgid "calculate (a * in + b)" msgstr "(a * in + b) berechnen" #: libvips/arithmetic/linear.c:454 libvips/create/sdf.c:332 msgid "a" msgstr "a" #: libvips/arithmetic/linear.c:455 msgid "Multiply by this" msgstr "hiermit multiplizieren" #: libvips/arithmetic/linear.c:461 libvips/create/sdf.c:339 msgid "b" msgstr "b" #: libvips/arithmetic/linear.c:462 msgid "Add this" msgstr "dies hinzufügen" #: libvips/arithmetic/linear.c:468 msgid "uchar" msgstr "" #: libvips/arithmetic/linear.c:469 msgid "Output should be uchar" msgstr "" #: libvips/arithmetic/math2.c:233 #, fuzzy msgid "binary math operations" msgstr "binäre Transaktionen" #: libvips/arithmetic/math2.c:242 libvips/arithmetic/math2.c:473 #: libvips/arithmetic/math.c:262 #, fuzzy msgid "Math to perform" msgstr "durchzuführende Berechnung" #: libvips/arithmetic/math2.c:464 #, fuzzy msgid "binary math operations with a constant" msgstr "unäre Transaktionen mit einer Konstante" #: libvips/arithmetic/math.c:253 #, fuzzy msgid "apply a math operation to an image" msgstr "eine komplexe Transaktion mit einem Bild durchführen" #: libvips/arithmetic/max.c:444 msgid "find image maximum" msgstr "Maximum des Bildes finden" #: libvips/arithmetic/max.c:460 msgid "Horizontal position of maximum" msgstr "horizontale Position des Maximums" #: libvips/arithmetic/max.c:467 msgid "Vertical position of maximum" msgstr "vertikale Position des Maximums" #: libvips/arithmetic/max.c:473 libvips/arithmetic/min.c:473 #: libvips/create/identity.c:157 libvips/create/invertlut.c:294 #: libvips/resample/thumbnail.c:988 msgid "Size" msgstr "" #: libvips/arithmetic/max.c:474 #, fuzzy msgid "Number of maximum values to find" msgstr "Position des Maximalwerts des Bildes" #: libvips/arithmetic/max.c:487 libvips/arithmetic/min.c:487 msgid "x array" msgstr "" #: libvips/arithmetic/max.c:488 libvips/arithmetic/min.c:488 #, fuzzy msgid "Array of horizontal positions" msgstr "Feld aus Konstanten" #: libvips/arithmetic/max.c:494 libvips/arithmetic/min.c:494 msgid "y array" msgstr "" #: libvips/arithmetic/max.c:495 libvips/arithmetic/min.c:495 #, fuzzy msgid "Array of vertical positions" msgstr "Feld aus Konstanten" #: libvips/arithmetic/maxpair.c:151 #, fuzzy msgid "maximum of a pair of images" msgstr "ein Bilderpaar zusammenführen" #: libvips/arithmetic/measure.c:191 #, fuzzy msgid "measure a set of patches on a color chart" msgstr "messen eines Satzes von Patches auf ein Farbdiagramm" #: libvips/arithmetic/measure.c:196 msgid "Image to measure" msgstr "zu vermessendes Bild" #: libvips/arithmetic/measure.c:202 libvips/arithmetic/stats.c:443 msgid "Output array of statistics" msgstr "Ausgabefeld von Statistiken" #: libvips/arithmetic/measure.c:207 libvips/conversion/arrayjoin.c:401 #: libvips/conversion/grid.c:212 libvips/conversion/replicate.c:202 msgid "Across" msgstr "über" #: libvips/arithmetic/measure.c:208 msgid "Number of patches across chart" msgstr "Anzahl der Patches über ein Diagramm" #: libvips/arithmetic/measure.c:214 libvips/conversion/grid.c:219 #: libvips/conversion/replicate.c:209 msgid "Down" msgstr "hinunter" #: libvips/arithmetic/measure.c:215 msgid "Number of patches down chart" msgstr "Anzahl der Patches ein Diagramm hinunter" #: libvips/arithmetic/measure.c:222 libvips/conversion/extract.c:201 msgid "Left edge of extract area" msgstr "linke Kante eines extrahierten Bereichs" #: libvips/arithmetic/min.c:444 msgid "find image minimum" msgstr "Minimum des Bildes finden" #: libvips/arithmetic/min.c:460 msgid "Horizontal position of minimum" msgstr "horizontale Position des Minimums" #: libvips/arithmetic/min.c:467 msgid "Vertical position of minimum" msgstr "vertikale Position des Minimums" #: libvips/arithmetic/min.c:474 #, fuzzy msgid "Number of minimum values to find" msgstr "Position des Minimalwerts des Bildes" #: libvips/arithmetic/minpair.c:151 #, fuzzy msgid "minimum of a pair of images" msgstr "ein Bilderpaar zusammenführen" #: libvips/arithmetic/multiply.c:195 msgid "multiply two images" msgstr "zwei Bilder multiplizieren" #: libvips/arithmetic/nary.c:80 #, fuzzy msgid "nary operations" msgstr "unäre Transaktionen" #: libvips/arithmetic/nary.c:88 libvips/conversion/arrayjoin.c:395 #: libvips/conversion/bandjoin.c:202 libvips/conversion/bandrank.c:255 #: libvips/conversion/composite.cpp:1589 libvips/iofuncs/system.c:278 msgid "Array of input images" msgstr "Feld von Eingabebildern" #: libvips/arithmetic/profile.c:293 #, fuzzy msgid "find image profiles" msgstr "Bildmittelwert finden" #: libvips/arithmetic/profile.c:301 libvips/arithmetic/project.c:332 msgid "Columns" msgstr "" #: libvips/arithmetic/profile.c:302 msgid "First non-zero pixel in column" msgstr "" #: libvips/arithmetic/profile.c:307 libvips/arithmetic/project.c:338 msgid "Rows" msgstr "" #: libvips/arithmetic/profile.c:308 msgid "First non-zero pixel in row" msgstr "" #: libvips/arithmetic/project.c:324 #, fuzzy msgid "find image projections" msgstr "Minimum des Bildes finden" #: libvips/arithmetic/project.c:333 msgid "Sums of columns" msgstr "" #: libvips/arithmetic/project.c:339 msgid "Sums of rows" msgstr "" #: libvips/arithmetic/relational.c:238 #, fuzzy msgid "relational operation on two images" msgstr "eine relationale Transaktion für ein Bilderpaar" #: libvips/arithmetic/relational.c:247 libvips/arithmetic/relational.c:614 #, fuzzy msgid "Relational to perform" msgstr "relational durchzuführen" #: libvips/arithmetic/relational.c:605 msgid "relational operations against a constant" msgstr "relationale Transaktion für eine Konstante" #: libvips/arithmetic/remainder.c:192 msgid "remainder after integer division of two images" msgstr "Rest nach Ganzzahldivision zweier Bilder" #: libvips/arithmetic/remainder.c:354 msgid "remainder after integer division of an image and a constant" msgstr "Rest nach Ganzzahldivision eines Bildes und einer Konstante" #: libvips/arithmetic/round.c:173 msgid "perform a round function on an image" msgstr "eine Rundungsfunktion für ein Bild ausführen" #: libvips/arithmetic/round.c:181 msgid "Round operation" msgstr "Rundungstransakktion" #: libvips/arithmetic/round.c:182 #, fuzzy msgid "Rounding operation to perform" msgstr "durchzuführende Rundungstransakktion" #: libvips/arithmetic/sign.c:174 msgid "unit vector of pixel" msgstr "Einheitsvektor von Bildpunkten" #: libvips/arithmetic/statistic.c:161 msgid "VIPS statistic operations" msgstr "statistische VIPS-Transaktionen" #: libvips/arithmetic/stats.c:434 #, fuzzy msgid "find many image stats" msgstr "ein Bild umdrehen" #: libvips/arithmetic/subtract.c:174 msgid "subtract two images" msgstr "zwei Bilder subtrahieren" #: libvips/arithmetic/sum.c:149 #, fuzzy msgid "sum an array of images" msgstr "ein Bilderpaar zusammenführen" #: libvips/arithmetic/unary.c:81 msgid "unary operations" msgstr "unäre Transaktionen" #: libvips/arithmetic/unaryconst.c:138 msgid "unary operations with a constant" msgstr "unäre Transaktionen mit einer Konstante" #: libvips/arithmetic/unaryconst.c:142 msgid "c" msgstr "c" #: libvips/arithmetic/unaryconst.c:143 msgid "Array of constants" msgstr "Feld aus Konstanten" #: libvips/colour/CMYK2XYZ.c:114 libvips/colour/CMYK2XYZ.c:182 msgid "transform CMYK to XYZ" msgstr "" #: libvips/colour/colour.c:178 msgid "too many input images" msgstr "zu viele Eingabebilder" #: libvips/colour/colour.c:310 #, fuzzy msgid "color operations" msgstr "Transaktionen" #: libvips/colour/colour.c:377 msgid "color space transformations" msgstr "" #: libvips/colour/colour.c:470 msgid "change color coding" msgstr "" #: libvips/colour/colour.c:581 msgid "calculate color difference" msgstr "" #: libvips/colour/colour.c:586 #, fuzzy msgid "Left-hand input image" msgstr "zweites Eingabebild" #: libvips/colour/colour.c:592 #, fuzzy msgid "Right-hand input image" msgstr "Haupteingabebild" #: libvips/colour/colourspace.c:145 #, fuzzy msgid "too few bands for operation" msgstr "Rundungstransakktion" #: libvips/colour/colourspace.c:524 #, fuzzy, c-format msgid "no known route from '%s' to '%s'" msgstr "unbekanntes Argument »%s«" #: libvips/colour/colourspace.c:554 msgid "convert to a new colorspace" msgstr "" #: libvips/colour/colourspace.c:572 msgid "Space" msgstr "" #: libvips/colour/colourspace.c:573 msgid "Destination color space" msgstr "" #: libvips/colour/colourspace.c:579 msgid "Source space" msgstr "" #: libvips/colour/colourspace.c:580 #, fuzzy msgid "Source color space" msgstr "nicht unterstützter Farbraum %d" #: libvips/colour/dE00.c:236 msgid "calculate dE00" msgstr "" #: libvips/colour/dE76.c:113 msgid "calculate dE76" msgstr "" #: libvips/colour/dECMC.c:61 msgid "calculate dECMC" msgstr "" #: libvips/colour/float2rad.c:206 msgid "transform float RGB to Radiance coding" msgstr "" #: libvips/colour/HSV2sRGB.c:112 msgid "transform HSV to sRGB" msgstr "" #: libvips/colour/icc_transform.c:272 libvips/colour/scRGB2BW.c:134 #: libvips/colour/scRGB2sRGB.c:161 #, fuzzy msgid "depth must be 8 or 16" msgstr "»mwidth« muss -1 oder >= 0 sein" #: libvips/colour/icc_transform.c:284 #, c-format msgid "unimplemented input color space 0x%x" msgstr "nicht implementierter Eingabefarbraum 0x%x" #: libvips/colour/icc_transform.c:360 #, c-format msgid "unimplemented output color space 0x%x" msgstr "nicht implementierter Ausgabefarbraum 0x%x" #: libvips/colour/icc_transform.c:437 #, fuzzy msgid "no device profile" msgstr "kein eingebettetes Profil" #: libvips/colour/icc_transform.c:764 msgid "unable to load or find any compatible input profile" msgstr "" #: libvips/colour/icc_transform.c:782 msgid "transform using ICC profiles" msgstr "" #: libvips/colour/icc_transform.c:786 libvips/resample/thumbnail.c:1030 msgid "Intent" msgstr "" #: libvips/colour/icc_transform.c:787 libvips/resample/thumbnail.c:1031 msgid "Rendering intent" msgstr "" #: libvips/colour/icc_transform.c:793 msgid "PCS" msgstr "" #: libvips/colour/icc_transform.c:794 msgid "Set Profile Connection Space" msgstr "" #: libvips/colour/icc_transform.c:800 msgid "Black point compensation" msgstr "" #: libvips/colour/icc_transform.c:801 msgid "Enable black point compensation" msgstr "" #: libvips/colour/icc_transform.c:975 msgid "import from device with ICC profile" msgstr "" #: libvips/colour/icc_transform.c:981 libvips/colour/icc_transform.c:1264 msgid "Embedded" msgstr "" #: libvips/colour/icc_transform.c:982 libvips/colour/icc_transform.c:1265 msgid "Use embedded input profile, if available" msgstr "" #: libvips/colour/icc_transform.c:988 libvips/colour/icc_transform.c:1271 #: libvips/resample/thumbnail.c:1016 #, fuzzy msgid "Input profile" msgstr "Profil" #: libvips/colour/icc_transform.c:989 libvips/colour/icc_transform.c:1272 #, fuzzy msgid "Filename to load input profile from" msgstr "Name der Datei, aus der geladen werden soll" #: libvips/colour/icc_transform.c:1052 libvips/colour/icc_transform.c:1218 #, fuzzy msgid "no output profile" msgstr "kein eingebettetes Profil" #: libvips/colour/icc_transform.c:1147 msgid "output to device with ICC profile" msgstr "" #: libvips/colour/icc_transform.c:1153 libvips/colour/icc_transform.c:1257 #: libvips/resample/thumbnail.c:1023 #, fuzzy msgid "Output profile" msgstr "Ausgabewert" #: libvips/colour/icc_transform.c:1154 libvips/colour/icc_transform.c:1258 #, fuzzy msgid "Filename to load output profile from" msgstr "Name der Datei, aus der geladen werden soll" #: libvips/colour/icc_transform.c:1160 libvips/colour/icc_transform.c:1278 #: libvips/colour/scRGB2BW.c:160 libvips/colour/scRGB2sRGB.c:187 #: libvips/foreign/dzsave.c:2361 libvips/foreign/tiffsave.c:381 msgid "Depth" msgstr "" #: libvips/colour/icc_transform.c:1161 libvips/colour/icc_transform.c:1279 #: libvips/colour/scRGB2BW.c:161 libvips/colour/scRGB2sRGB.c:188 msgid "Output device space depth in bits" msgstr "" #: libvips/colour/icc_transform.c:1251 msgid "transform between devices with ICC profiles" msgstr "" #: libvips/colour/icc_transform.c:1328 msgid "unable to get media white point" msgstr "weißer Medienpunkt kann nicht abgefragt werden" #: libvips/colour/icc_transform.c:1423 #, fuzzy msgid "libvips configured without lcms support" msgstr "VIPS wurde ohne FFT-Unterstützung konfiguriert" #: libvips/colour/Lab2LabQ.c:137 msgid "transform float Lab to LabQ coding" msgstr "" #: libvips/colour/Lab2LabS.c:82 msgid "transform float Lab to signed short" msgstr "" #: libvips/colour/Lab2LCh.c:132 msgid "transform Lab to LCh" msgstr "" #: libvips/colour/Lab2XYZ.c:177 msgid "transform CIELAB to XYZ" msgstr "" #: libvips/colour/Lab2XYZ.c:183 libvips/colour/XYZ2Lab.c:237 msgid "Temperature" msgstr "" #: libvips/colour/Lab2XYZ.c:184 msgid "Color temperature" msgstr "" #: libvips/colour/LabQ2Lab.c:125 msgid "unpack a LabQ image to float Lab" msgstr "" #: libvips/colour/LabQ2LabS.c:104 msgid "unpack a LabQ image to short Lab" msgstr "" #: libvips/colour/LabQ2sRGB.c:552 #, fuzzy msgid "convert a LabQ image to sRGB" msgstr "ein Bild invertieren" #: libvips/colour/LabS2Lab.c:78 msgid "transform signed short Lab to float" msgstr "" #: libvips/colour/LabS2LabQ.c:127 msgid "transform short Lab to LabQ coding" msgstr "" #: libvips/colour/LCh2Lab.c:111 msgid "transform LCh to Lab" msgstr "" #: libvips/colour/LCh2UCS.c:206 libvips/colour/UCS2LCh.c:273 msgid "transform LCh to CMC" msgstr "" #: libvips/colour/profile_load.c:123 #, fuzzy, c-format msgid "unable to load profile \"%s\"" msgstr "Profil »%s« kann nicht geöffnet werden" # Portable Pixmap #: libvips/colour/profile_load.c:147 #, fuzzy msgid "load named ICC profile" msgstr "PPM aus Datei laden" #: libvips/colour/profile_load.c:151 msgid "Name" msgstr "" #: libvips/colour/profile_load.c:152 #, fuzzy msgid "Profile name" msgstr "Dateiname" #: libvips/colour/profile_load.c:158 libvips/foreign/foreign.c:1894 #, fuzzy msgid "Profile" msgstr "Profil" #: libvips/colour/profile_load.c:159 #, fuzzy msgid "Loaded profile" msgstr "kein eingebettetes Profil" #: libvips/colour/rad2float.c:184 #, fuzzy msgid "unpack Radiance coding to float RGB" msgstr "Nur Radiance-Kodierung" #: libvips/colour/scRGB2BW.c:154 msgid "convert scRGB to BW" msgstr "" #: libvips/colour/scRGB2sRGB.c:181 #, fuzzy msgid "convert scRGB to sRGB" msgstr "ein Bild invertieren" #: libvips/colour/scRGB2XYZ.c:88 msgid "transform scRGB to XYZ" msgstr "" #: libvips/colour/sRGB2HSV.c:133 msgid "transform sRGB to HSV" msgstr "" #: libvips/colour/sRGB2scRGB.c:141 #, fuzzy msgid "convert an sRGB image to scRGB" msgstr "ein Bild invertieren" #: libvips/colour/XYZ2CMYK.c:113 libvips/colour/XYZ2CMYK.c:193 msgid "transform XYZ to CMYK" msgstr "" #: libvips/colour/XYZ2Lab.c:231 msgid "transform XYZ to Lab" msgstr "" #: libvips/colour/XYZ2Lab.c:238 msgid "Colour temperature" msgstr "" #: libvips/colour/XYZ2scRGB.c:103 msgid "transform XYZ to scRGB" msgstr "" #: libvips/colour/XYZ2Yxy.c:98 msgid "transform XYZ to Yxy" msgstr "" #: libvips/colour/Yxy2XYZ.c:103 msgid "transform Yxy to XYZ" msgstr "" #: libvips/conversion/addalpha.c:84 msgid "append an alpha channel" msgstr "" #: libvips/conversion/arrayjoin.c:388 #, fuzzy msgid "join an array of images" msgstr "ein Bilderpaar zusammenführen" #: libvips/conversion/arrayjoin.c:402 #, fuzzy msgid "Number of images across grid" msgstr "Anzahl der Patches über ein Diagramm" #: libvips/conversion/arrayjoin.c:408 libvips/conversion/join.c:263 msgid "Shim" msgstr "Scheibe" #: libvips/conversion/arrayjoin.c:409 libvips/conversion/join.c:264 msgid "Pixels between images" msgstr "Bildpunkte zwischen Bildern" #: libvips/conversion/arrayjoin.c:416 libvips/conversion/join.c:271 msgid "Colour for new pixels" msgstr "Farbe für neue Bildpunkte" #: libvips/conversion/arrayjoin.c:422 #, fuzzy msgid "Horizontal align" msgstr "horizontaler Versatz vom Ursprung" #: libvips/conversion/arrayjoin.c:423 #, fuzzy msgid "Align on the left, centre or right" msgstr "am Rand der unteren, mittleren oder höchsten Koordinate ausrichten" #: libvips/conversion/arrayjoin.c:429 #, fuzzy msgid "Vertical align" msgstr "vertikaler Versatz vom Ursprung" #: libvips/conversion/arrayjoin.c:430 #, fuzzy msgid "Align on the top, centre or bottom" msgstr "am Rand der unteren, mittleren oder höchsten Koordinate ausrichten" #: libvips/conversion/arrayjoin.c:436 #, fuzzy msgid "Horizontal spacing" msgstr "horizontaler Versatz vom Ursprung" #: libvips/conversion/arrayjoin.c:437 #, fuzzy msgid "Horizontal spacing between images" msgstr "Bildpunkte zwischen Bildern" #: libvips/conversion/arrayjoin.c:443 msgid "Vertical spacing" msgstr "" #: libvips/conversion/arrayjoin.c:444 #, fuzzy msgid "Vertical spacing between images" msgstr "Bildpunkte zwischen Bildern" #: libvips/conversion/autorot.c:203 msgid "autorotate image by exif tag" msgstr "" #: libvips/conversion/autorot.c:213 libvips/conversion/rot45.c:274 #: libvips/conversion/rot.c:371 libvips/convolution/compass.c:170 #: libvips/foreign/dzsave.c:2375 libvips/mosaicing/mosaic.c:281 #: libvips/resample/similarity.c:207 libvips/resample/similarity.c:276 msgid "Angle" msgstr "Winkel" #: libvips/conversion/autorot.c:214 msgid "Angle image was rotated by" msgstr "" #: libvips/conversion/autorot.c:220 msgid "Flip" msgstr "" #: libvips/conversion/autorot.c:221 msgid "Whether the image was flipped or not" msgstr "" #: libvips/conversion/bandary.c:211 libvips/conversion/bandary.c:280 #: libvips/conversion/composite.cpp:1299 msgid "no input images" msgstr "keine Eingabebilder" #: libvips/conversion/bandary.c:257 msgid "operations on image bands" msgstr "Transaktionen für Bänder von Bildern" #: libvips/conversion/bandbool.c:75 #, fuzzy, c-format msgid "operator %s not supported across image bands" msgstr "Transaktionen für Bänder von Bildern" #: libvips/conversion/bandbool.c:225 #, fuzzy msgid "boolean operation across image bands" msgstr "Transaktionen für Bänder von Bildern" #: libvips/conversion/bandbool.c:233 libvips/conversion/bandmean.c:213 #: libvips/conversion/recomb.c:225 libvips/convolution/convolution.c:119 #: libvips/convolution/correlation.c:151 libvips/morphology/morphology.c:72 #: libvips/resample/resample.c:105 libvips/resample/thumbnail.c:1804 msgid "Input image argument" msgstr "Eingabebildargument" #: libvips/conversion/bandfold.c:123 msgid "@factor must be a factor of image width" msgstr "" #: libvips/conversion/bandfold.c:155 msgid "fold up x axis into bands" msgstr "" #: libvips/conversion/bandfold.c:167 libvips/conversion/bandunfold.c:170 #: libvips/create/eye.c:108 #, fuzzy msgid "Factor" msgstr "Q-Faktor" #: libvips/conversion/bandfold.c:168 msgid "Fold by this factor" msgstr "" #: libvips/conversion/bandjoin.c:195 msgid "bandwise join a set of images" msgstr "einen Satz Bilder bandweise zusammenführen" #: libvips/conversion/bandjoin.c:431 #, fuzzy msgid "append a constant band to an image" msgstr "Band aus einem Bild extrahieren" #: libvips/conversion/bandjoin.c:443 msgid "Constants" msgstr "" #: libvips/conversion/bandjoin.c:444 #, fuzzy msgid "Array of constants to add" msgstr "Feld aus Konstanten" #: libvips/conversion/bandmean.c:206 msgid "band-wise average" msgstr "bandweiser Durchschnitt" #: libvips/conversion/bandrank.c:248 #, fuzzy msgid "band-wise rank of a set of images" msgstr "einen Satz Bilder bandweise zusammenführen" #: libvips/conversion/bandrank.c:262 msgid "Select this band element from sorted list" msgstr "" #: libvips/conversion/bandunfold.c:126 msgid "@factor must be a factor of image bands" msgstr "" #: libvips/conversion/bandunfold.c:158 msgid "unfold image bands into x axis" msgstr "" #: libvips/conversion/bandunfold.c:171 msgid "Unfold by this factor" msgstr "" #: libvips/conversion/byteswap.c:232 #, fuzzy msgid "byteswap an image" msgstr "ein Bild drehen" #: libvips/conversion/cache.c:98 libvips/conversion/tilecache.c:402 msgid "cache an image" msgstr "ein Bild zwischenspeichern" #: libvips/conversion/cache.c:114 libvips/conversion/tilecache.c:810 #: libvips/foreign/dzsave.c:2448 libvips/foreign/jp2ksave.c:971 #: libvips/foreign/tiffsave.c:290 msgid "Tile width" msgstr "Kachelbreite" #: libvips/conversion/cache.c:115 libvips/conversion/tilecache.c:811 #: libvips/foreign/dzsave.c:2449 libvips/foreign/jp2ksave.c:972 #: libvips/foreign/tiffsave.c:291 msgid "Tile width in pixels" msgstr "Kachelbreite in Bildpunkten" #: libvips/conversion/cache.c:121 libvips/conversion/grid.c:205 #: libvips/conversion/sequential.c:249 libvips/conversion/tilecache.c:414 #: libvips/foreign/dzsave.c:2455 libvips/foreign/jp2ksave.c:978 #: libvips/foreign/tiffsave.c:297 msgid "Tile height" msgstr "Kachelhöhe" #: libvips/conversion/cache.c:122 libvips/conversion/sequential.c:250 #: libvips/conversion/tilecache.c:415 libvips/foreign/dzsave.c:2456 #: libvips/foreign/jp2ksave.c:979 libvips/foreign/tiffsave.c:298 msgid "Tile height in pixels" msgstr "Kachelhöhe in Bildpunkten" #: libvips/conversion/cache.c:128 libvips/conversion/tilecache.c:817 msgid "Max tiles" msgstr "Kacheln maximal" #: libvips/conversion/cache.c:129 libvips/conversion/tilecache.c:818 msgid "Maximum number of tiles to cache" msgstr "maximale Anzahl von Kacheln, die zwischengespeichert werden soll" #: libvips/conversion/cast.c:523 msgid "cast an image" msgstr "ein Bild umwandeln" #: libvips/conversion/cast.c:535 libvips/conversion/copy.c:305 #: libvips/foreign/ppmsave.c:492 libvips/foreign/rawload.c:174 #: libvips/foreign/vips2magick.c:482 libvips/iofuncs/image.c:1108 msgid "Format" msgstr "Format" #: libvips/conversion/cast.c:536 msgid "Format to cast to" msgstr "Format, in das umgewandelt werden soll" #: libvips/conversion/cast.c:542 msgid "Shift" msgstr "" #: libvips/conversion/cast.c:543 msgid "Shift integer values up and down" msgstr "" #: libvips/conversion/composite.cpp:1304 #, fuzzy, c-format msgid "must be 1 or %d blend modes" msgstr "Bild muss ein oder %d Bänder haben" #: libvips/conversion/composite.cpp:1314 #, c-format msgid "blend mode index %d (%d) invalid" msgstr "" #: libvips/conversion/composite.cpp:1421 #, fuzzy msgid "images do not have same numbers of bands" msgstr "Bilder müssen die gleiche Anzahl Bänder haben" #: libvips/conversion/composite.cpp:1428 #, fuzzy msgid "too many input bands" msgstr "zu viele Eingabebilder" #: libvips/conversion/composite.cpp:1438 #, fuzzy msgid "unsupported compositing space" msgstr "nicht unterstützter Farbraum %d" #: libvips/conversion/composite.cpp:1486 #, fuzzy msgid "blend images together" msgstr "falscher Bildtyp" #: libvips/conversion/composite.cpp:1492 msgid "Compositing space" msgstr "" #: libvips/conversion/composite.cpp:1493 msgid "Composite images in this colour space" msgstr "" #: libvips/conversion/composite.cpp:1499 libvips/conversion/smartcrop.c:474 #: libvips/resample/affine.c:706 libvips/resample/mapim.c:581 msgid "Premultiplied" msgstr "" #: libvips/conversion/composite.cpp:1500 libvips/resample/affine.c:707 #: libvips/resample/mapim.c:582 msgid "Images have premultiplied alpha" msgstr "" #: libvips/conversion/composite.cpp:1548 #, c-format msgid "must be %d x coordinates" msgstr "" #: libvips/conversion/composite.cpp:1556 #, c-format msgid "must be %d y coordinates" msgstr "" #: libvips/conversion/composite.cpp:1582 msgid "blend an array of images with an array of blend modes" msgstr "" #: libvips/conversion/composite.cpp:1588 #, fuzzy msgid "Inputs" msgstr "Eingabe" #: libvips/conversion/composite.cpp:1595 #, fuzzy msgid "Blend modes" msgstr "Öffnen-Modus" #: libvips/conversion/composite.cpp:1596 msgid "Array of VipsBlendMode to join with" msgstr "" #: libvips/conversion/composite.cpp:1602 msgid "x coordinates" msgstr "" #: libvips/conversion/composite.cpp:1603 #, fuzzy msgid "Array of x coordinates to join at" msgstr "Feld aus Konstanten" #: libvips/conversion/composite.cpp:1609 msgid "y coordinates" msgstr "" #: libvips/conversion/composite.cpp:1610 #, fuzzy msgid "Array of y coordinates to join at" msgstr "Feld aus Konstanten" #: libvips/conversion/composite.cpp:1716 msgid "blend a pair of images with a blend mode" msgstr "" #: libvips/conversion/composite.cpp:1722 msgid "Base" msgstr "" #: libvips/conversion/composite.cpp:1723 #, fuzzy msgid "Base image" msgstr "sonst Bild" #: libvips/conversion/composite.cpp:1728 msgid "Overlay" msgstr "" #: libvips/conversion/composite.cpp:1729 #, fuzzy msgid "Overlay image" msgstr "Zeilensprungbild" #: libvips/conversion/composite.cpp:1734 #, fuzzy msgid "Blend mode" msgstr "Öffnen-Modus" #: libvips/conversion/composite.cpp:1735 msgid "VipsBlendMode to join with" msgstr "" #: libvips/conversion/composite.cpp:1742 msgid "x position of overlay" msgstr "" #: libvips/conversion/composite.cpp:1749 msgid "y position of overlay" msgstr "" #: libvips/conversion/conversion.c:328 msgid "conversion operations" msgstr "Umwandlungstransaktionen" #: libvips/conversion/copy.c:235 #, fuzzy msgid "must not change pel size" msgstr "Bilder passen in der Bildpunktgröße nicht zusammen" #: libvips/conversion/copy.c:260 msgid "copy an image" msgstr "ein Bild kopieren" #: libvips/conversion/copy.c:277 msgid "Swap" msgstr "austauschen" #: libvips/conversion/copy.c:278 msgid "Swap bytes in image between little and big-endian" msgstr "Byte im Bild zwischen Little- und Big-Endian austauschen" #: libvips/conversion/copy.c:285 libvips/conversion/embed.c:575 #: libvips/create/black.c:141 libvips/create/fractsurf.c:105 #: libvips/create/gaussnoise.c:169 libvips/create/perlin.c:296 #: libvips/create/point.c:142 libvips/create/sdf.c:305 #: libvips/create/worley.c:309 libvips/create/xyz.c:192 #: libvips/foreign/rawload.c:147 libvips/iofuncs/image.c:1088 msgid "Image width in pixels" msgstr "Bildbreite in Bildpunkten" #: libvips/conversion/copy.c:292 libvips/conversion/embed.c:582 #: libvips/create/black.c:148 libvips/create/fractsurf.c:112 #: libvips/create/gaussnoise.c:176 libvips/create/perlin.c:303 #: libvips/create/point.c:149 libvips/create/sdf.c:312 #: libvips/create/worley.c:316 libvips/create/xyz.c:199 #: libvips/foreign/rawload.c:154 libvips/iofuncs/image.c:1095 msgid "Image height in pixels" msgstr "Bildhöhe in Bildpunkten" #: libvips/conversion/copy.c:298 libvips/create/black.c:154 #: libvips/create/identity.c:143 libvips/foreign/rawload.c:160 #: libvips/iofuncs/image.c:1101 msgid "Bands" msgstr "Bänder" #: libvips/conversion/copy.c:299 libvips/create/black.c:155 #: libvips/foreign/rawload.c:161 libvips/iofuncs/image.c:1102 msgid "Number of bands in image" msgstr "Anzahl der Bänder in einem Bild" #: libvips/conversion/copy.c:306 libvips/foreign/rawload.c:175 #: libvips/iofuncs/image.c:1109 msgid "Pixel format in image" msgstr "Bildpunktformat im Bild" #: libvips/conversion/copy.c:312 libvips/iofuncs/image.c:1115 msgid "Coding" msgstr "Kodierung" #: libvips/conversion/copy.c:313 libvips/iofuncs/image.c:1116 msgid "Pixel coding" msgstr "Bildpunktkodierung" #: libvips/conversion/copy.c:319 libvips/foreign/rawload.c:181 #: libvips/iofuncs/image.c:1122 msgid "Interpretation" msgstr "Interpretation" #: libvips/conversion/copy.c:320 libvips/foreign/rawload.c:182 #: libvips/iofuncs/image.c:1123 msgid "Pixel interpretation" msgstr "Bildpunktinterpretation" #: libvips/conversion/copy.c:326 libvips/foreign/tiffsave.c:332 #: libvips/iofuncs/image.c:1129 msgid "Xres" msgstr "Xres" #: libvips/conversion/copy.c:327 libvips/foreign/tiffsave.c:333 #: libvips/iofuncs/image.c:1130 msgid "Horizontal resolution in pixels/mm" msgstr "horizontale Auflösung in Bildpunkten/mm" #: libvips/conversion/copy.c:333 libvips/foreign/tiffsave.c:339 #: libvips/iofuncs/image.c:1136 msgid "Yres" msgstr "Yres" #: libvips/conversion/copy.c:334 libvips/foreign/tiffsave.c:340 #: libvips/iofuncs/image.c:1137 msgid "Vertical resolution in pixels/mm" msgstr "vertikale Auflösung in Bildpunkten/mm" #: libvips/conversion/copy.c:340 libvips/iofuncs/image.c:1143 msgid "Xoffset" msgstr "Xoffset" #: libvips/conversion/copy.c:341 libvips/iofuncs/image.c:1144 msgid "Horizontal offset of origin" msgstr "horizontaler Versatz vom Ursprung" #: libvips/conversion/copy.c:347 libvips/iofuncs/image.c:1150 msgid "Yoffset" msgstr "Yoffset" #: libvips/conversion/copy.c:348 libvips/iofuncs/image.c:1151 msgid "Vertical offset of origin" msgstr "vertikaler Versatz vom Ursprung" #: libvips/conversion/embed.c:479 libvips/foreign/heifload.c:581 #: libvips/foreign/svgload.c:532 libvips/iofuncs/image.c:3156 msgid "bad dimensions" msgstr "falsche Abmessungen" #: libvips/conversion/embed.c:561 libvips/conversion/embed.c:652 msgid "embed an image in a larger image" msgstr "ein Bild in ein größeres Bild einbetten" #: libvips/conversion/embed.c:588 libvips/resample/affine.c:692 #: libvips/resample/mapim.c:567 msgid "Extend" msgstr "vergrößern" #: libvips/conversion/embed.c:589 libvips/resample/affine.c:693 #: libvips/resample/mapim.c:568 msgid "How to generate the extra pixels" msgstr "Wie werden die zusätzlichen Bildpunkte erzeugt?" #: libvips/conversion/embed.c:657 libvips/conversion/wrap.c:126 msgid "Left edge of input in output" msgstr "linker Rand der Eingabe in der Ausgabe" #: libvips/conversion/embed.c:664 libvips/conversion/wrap.c:133 msgid "Top edge of input in output" msgstr "oberer Rand der Eingabe in der Ausgabe" #: libvips/conversion/embed.c:806 #, fuzzy msgid "place an image within a larger image with a certain gravity" msgstr "ein Bild in ein größeres Bild einbetten" #: libvips/conversion/embed.c:811 libvips/conversion/flip.c:246 #: libvips/conversion/join.c:249 libvips/morphology/countlines.c:146 #: libvips/mosaicing/merge.c:140 libvips/mosaicing/mosaic1.c:516 #: libvips/mosaicing/mosaic.c:197 msgid "Direction" msgstr "Richtung" #: libvips/conversion/embed.c:812 msgid "Direction to place image within width/height" msgstr "" #: libvips/conversion/extract.c:150 libvips/conversion/smartcrop.c:341 msgid "bad extract area" msgstr "falscher extrahierter Bereich" #: libvips/conversion/extract.c:188 libvips/conversion/smartcrop.c:429 msgid "extract an area from an image" msgstr "einen Bereich eines Bildes extrahieren" #: libvips/conversion/extract.c:400 msgid "bad extract band" msgstr "schlecht extrahiertes Band" #: libvips/conversion/extract.c:428 msgid "extract band from an image" msgstr "Band aus einem Bild extrahieren" #: libvips/conversion/extract.c:441 msgid "Band to extract" msgstr "zu extrahierendes Band" #: libvips/conversion/extract.c:447 libvips/foreign/heifload.c:1089 #: libvips/foreign/jxlload.c:1133 libvips/foreign/magick6load.c:309 #: libvips/foreign/magick7load.c:386 libvips/foreign/nsgifload.c:627 #: libvips/foreign/pdfiumload.c:700 libvips/foreign/popplerload.c:550 #: libvips/foreign/tiffload.c:203 libvips/foreign/webpload.c:183 msgid "n" msgstr "n" #: libvips/conversion/extract.c:448 msgid "Number of bands to extract" msgstr "Anzahl zu extrahierender Bänder" #: libvips/conversion/falsecolour.c:374 #, fuzzy msgid "false-color an image" msgstr "ein Bild einfügen" # http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650& # db=man&fname=/usr/share/catman/p_man/cat3/il_c/ilAbsImg.z #: libvips/conversion/flatten.c:410 #, fuzzy msgid "flatten alpha out of an image" msgstr "absoluter Wert eines Bildes" #: libvips/conversion/flatten.c:423 libvips/foreign/foreign.c:1881 #: libvips/resample/affine.c:700 libvips/resample/mapim.c:575 #: libvips/resample/similarity.c:134 #, fuzzy msgid "Background value" msgstr "Hintergrund" #: libvips/conversion/flatten.c:429 libvips/conversion/premultiply.c:267 #: libvips/conversion/unpremultiply.c:329 msgid "Maximum alpha" msgstr "" #: libvips/conversion/flatten.c:430 libvips/conversion/premultiply.c:268 #: libvips/conversion/unpremultiply.c:330 #, fuzzy msgid "Maximum value of alpha channel" msgstr "Maximalwert des Bildes" #: libvips/conversion/flip.c:236 msgid "flip an image" msgstr "ein Bild umdrehen" #: libvips/conversion/flip.c:247 msgid "Direction to flip image" msgstr "Richtung, nach der das Bild umgedreht werden soll" #: libvips/conversion/gamma.c:136 #, fuzzy msgid "gamma an image" msgstr "ein Bild umwandeln" #: libvips/conversion/gamma.c:148 libvips/conversion/scale.c:168 msgid "Exponent" msgstr "" #: libvips/conversion/gamma.c:149 #, fuzzy msgid "Gamma factor" msgstr "Q-Faktor" #: libvips/conversion/grid.c:165 msgid "bad grid geometry" msgstr "falsche Gittergeometrie" #: libvips/conversion/grid.c:195 #, fuzzy msgid "grid an image" msgstr "ein Bild umdrehen" #: libvips/conversion/grid.c:206 msgid "Chop into tiles this high" msgstr "" #: libvips/conversion/grid.c:213 #, fuzzy msgid "Number of tiles across" msgstr "Anzahl der Patches über ein Diagramm" #: libvips/conversion/grid.c:220 #, fuzzy msgid "Number of tiles down" msgstr "Anzahl der Patches ein Diagramm hinunter" #: libvips/conversion/ifthenelse.c:525 msgid "ifthenelse an image" msgstr "fallsdannsonst eines Bildes" #: libvips/conversion/ifthenelse.c:529 msgid "Condition" msgstr "Bedingung" #: libvips/conversion/ifthenelse.c:530 msgid "Condition input image" msgstr "Bedingung des Eingabebilds" #: libvips/conversion/ifthenelse.c:535 msgid "Then image" msgstr "dann Bild" #: libvips/conversion/ifthenelse.c:536 msgid "Source for TRUE pixels" msgstr "Quelle für TRUE-Bildpunkte" #: libvips/conversion/ifthenelse.c:541 msgid "Else image" msgstr "sonst Bild" #: libvips/conversion/ifthenelse.c:542 msgid "Source for FALSE pixels" msgstr "Quelle für FALSE-Bildpunkte" #: libvips/conversion/ifthenelse.c:547 #, fuzzy msgid "Blend" msgstr "Mischung" #: libvips/conversion/ifthenelse.c:548 msgid "Blend smoothly between then and else parts" msgstr "nahtlos zwischen »dann«- und »sonst«-Teilen mischen" #: libvips/conversion/insert.c:460 msgid "insert image @sub into @main at @x, @y" msgstr "" #: libvips/conversion/insert.c:466 msgid "Main" msgstr "primär" #: libvips/conversion/insert.c:467 msgid "Main input image" msgstr "Haupteingabebild" #: libvips/conversion/insert.c:472 libvips/draw/draw_image.c:269 msgid "Sub-image" msgstr "Teilbild" #: libvips/conversion/insert.c:473 libvips/draw/draw_image.c:270 msgid "Sub-image to insert into main image" msgstr "Teilbild, das in das Hauptbild eingefügt werden soll" #: libvips/conversion/insert.c:478 msgid "X" msgstr "X" #: libvips/conversion/insert.c:479 msgid "Left edge of sub in main" msgstr "linker Rand des Teilbilds im Hauptbild" #: libvips/conversion/insert.c:485 msgid "Y" msgstr "Y" #: libvips/conversion/insert.c:486 msgid "Top edge of sub in main" msgstr "oberer Rand des Teilbilds im Hauptbild" #: libvips/conversion/insert.c:492 libvips/conversion/join.c:256 msgid "Expand" msgstr "expandieren" #: libvips/conversion/insert.c:493 libvips/conversion/join.c:257 msgid "Expand output to hold all of both inputs" msgstr "Ausgabe so expandieren, dass sie beide Eingaben vollständig enthält" #: libvips/conversion/insert.c:500 #, fuzzy msgid "Color for new pixels" msgstr "Farbe für neue Bildpunkte" #: libvips/conversion/join.c:231 msgid "join a pair of images" msgstr "ein Bilderpaar zusammenführen" #: libvips/conversion/join.c:237 msgid "in1" msgstr "in1" #: libvips/conversion/join.c:238 msgid "First input image" msgstr "erstes Eingabebild" #: libvips/conversion/join.c:243 libvips/freqfilt/phasecor.c:111 msgid "in2" msgstr "in2" #: libvips/conversion/join.c:244 libvips/freqfilt/phasecor.c:112 msgid "Second input image" msgstr "zweites Eingabebild" #: libvips/conversion/join.c:250 msgid "Join left-right or up-down" msgstr "von links nach rechts oder von oben nach unten zusammenführen" #: libvips/conversion/join.c:277 libvips/create/text.c:585 msgid "Align" msgstr "ausrichten" #: libvips/conversion/join.c:278 msgid "Align on the low, centre or high coordinate edge" msgstr "am Rand der unteren, mittleren oder höchsten Koordinate ausrichten" #: libvips/conversion/msb.c:168 #, fuzzy msgid "bad band" msgstr "falsche Bänder" #: libvips/conversion/msb.c:241 msgid "pick most-significant byte from an image" msgstr "" #: libvips/conversion/msb.c:254 #, fuzzy msgid "Band to msb" msgstr "Bänder auf N setzen" #: libvips/conversion/premultiply.c:255 #, fuzzy msgid "premultiply image alpha" msgstr "zwei Bilder multiplizieren" #: libvips/conversion/recomb.c:183 msgid "bands in must equal matrix width" msgstr "»in«-Bänder müssen die gleiche Breite wie die Matrix haben" #: libvips/conversion/recomb.c:218 msgid "linear recombination with matrix" msgstr "lineare Neukombinierung mit der Matrix" #: libvips/conversion/recomb.c:230 msgid "M" msgstr "M" #: libvips/conversion/recomb.c:231 #, fuzzy msgid "Matrix of coefficients" msgstr "Matrix der Koeffizienten" #: libvips/conversion/replicate.c:192 msgid "replicate an image" msgstr "ein Bild nachmachen" #: libvips/conversion/replicate.c:203 msgid "Repeat this many times horizontally" msgstr "horizontal so oft wiederholen" #: libvips/conversion/replicate.c:210 msgid "Repeat this many times vertically" msgstr "vertikal so oft wiederholen" #: libvips/conversion/rot45.c:264 libvips/conversion/rot.c:361 msgid "rotate an image" msgstr "ein Bild drehen" #: libvips/conversion/rot45.c:275 libvips/conversion/rot.c:372 msgid "Angle to rotate image" msgstr "Winkel zum Drehen eines Bildes" #: libvips/conversion/scale.c:151 #, fuzzy msgid "scale an image to uchar" msgstr "ein Bild zwischenspeichern" #: libvips/conversion/scale.c:161 libvips/iofuncs/system.c:311 msgid "Log" msgstr "" #: libvips/conversion/scale.c:162 msgid "Log scale" msgstr "" #: libvips/conversion/scale.c:169 msgid "Exponent for log scale" msgstr "" #: libvips/conversion/sequential.c:239 msgid "check sequential access" msgstr "" #: libvips/conversion/sequential.c:256 msgid "Strategy" msgstr "Strategie" #: libvips/conversion/sequential.c:257 libvips/conversion/tilecache.c:422 msgid "Expected access pattern" msgstr "erwartetes Zugriffsmuster" #: libvips/conversion/sequential.c:263 msgid "Trace" msgstr "" #: libvips/conversion/sequential.c:264 msgid "Trace pixel requests" msgstr "" #: libvips/conversion/smartcrop.c:453 #, fuzzy msgid "Interesting" msgstr "Interpretation" #: libvips/conversion/smartcrop.c:454 msgid "How to measure interestingness" msgstr "" #: libvips/conversion/smartcrop.c:460 msgid "Attention x" msgstr "" #: libvips/conversion/smartcrop.c:461 #, fuzzy msgid "Horizontal position of attention centre" msgstr "horizontale Position des Minimums" #: libvips/conversion/smartcrop.c:467 msgid "Attention y" msgstr "" #: libvips/conversion/smartcrop.c:468 #, fuzzy msgid "Vertical position of attention centre" msgstr "vertikale Position des Minimums" #: libvips/conversion/smartcrop.c:475 msgid "Input image already has premultiplied alpha" msgstr "" #: libvips/conversion/subsample.c:228 libvips/resample/reduceh.cpp:546 #: libvips/resample/reducev.cpp:1001 libvips/resample/shrinkh.c:399 #: libvips/resample/shrinkv.c:562 msgid "image has shrunk to nothing" msgstr "Bild ist zu nichts geschrumpft" #: libvips/conversion/subsample.c:259 #, fuzzy msgid "subsample an image" msgstr "ein Bild zwischenspeichern" #: libvips/conversion/subsample.c:273 libvips/conversion/zoom.c:379 msgid "Xfac" msgstr "" #: libvips/conversion/subsample.c:274 #, fuzzy msgid "Horizontal subsample factor" msgstr "horizontaler Versatz vom Ursprung" #: libvips/conversion/subsample.c:280 libvips/conversion/zoom.c:386 msgid "Yfac" msgstr "" #: libvips/conversion/subsample.c:281 #, fuzzy msgid "Vertical subsample factor" msgstr "vertikaler Versatz vom Ursprung" #: libvips/conversion/subsample.c:287 msgid "Point" msgstr "" #: libvips/conversion/subsample.c:288 msgid "Point sample" msgstr "" #: libvips/conversion/switch.c:129 #, fuzzy msgid "bad number of tests" msgstr "falsche Achsenanzahl %d" #: libvips/conversion/switch.c:161 #, fuzzy msgid "test images not 1-band" msgstr "Bild muss ein Band haben" #: libvips/conversion/switch.c:189 msgid "find the index of the first non-zero pixel in tests" msgstr "" #: libvips/conversion/switch.c:195 msgid "Tests" msgstr "" #: libvips/conversion/switch.c:196 #, fuzzy msgid "Table of images to test" msgstr "Bild in TIFF-Datei speichern" #: libvips/conversion/tilecache.c:421 libvips/foreign/foreign.c:1243 msgid "Access" msgstr "" #: libvips/conversion/tilecache.c:428 msgid "Threaded" msgstr "" #: libvips/conversion/tilecache.c:429 msgid "Allow threaded access" msgstr "" #: libvips/conversion/tilecache.c:435 msgid "Persistent" msgstr "" #: libvips/conversion/tilecache.c:436 msgid "Keep cache between evaluations" msgstr "" #: libvips/conversion/tilecache.c:806 #, fuzzy msgid "cache an image as a set of tiles" msgstr "ein Bild zwischenspeichern" #: libvips/conversion/tilecache.c:994 #, fuzzy msgid "cache an image as a set of lines" msgstr "ein Bild zwischenspeichern" #: libvips/conversion/transpose3d.c:135 msgid "bad page_height" msgstr "" #: libvips/conversion/transpose3d.c:163 #, fuzzy msgid "transpose3d an image" msgstr "ein Bild einfügen" #: libvips/conversion/transpose3d.c:173 libvips/foreign/foreign.c:1887 #, fuzzy msgid "Page height" msgstr "Kachelhöhe" #: libvips/conversion/transpose3d.c:174 #, fuzzy msgid "Height of each input page" msgstr "Höhe des extrahierten Bereichs" #: libvips/conversion/unpremultiply.c:317 #, fuzzy msgid "unpremultiply image alpha" msgstr "zwei Bilder multiplizieren" #: libvips/conversion/unpremultiply.c:336 #, fuzzy msgid "Alpha band" msgstr "falsche Bänder" #: libvips/conversion/unpremultiply.c:337 msgid "Unpremultiply with this alpha" msgstr "" #: libvips/conversion/wrap.c:115 msgid "wrap image origin" msgstr "" #: libvips/conversion/zoom.c:328 msgid "zoom factors too large" msgstr "Zoomfaktoren zu groß" #: libvips/conversion/zoom.c:367 #, fuzzy msgid "zoom an image" msgstr "ein Bild kopieren" #: libvips/conversion/zoom.c:380 #, fuzzy msgid "Horizontal zoom factor" msgstr "horizontaler Versatz vom Ursprung" #: libvips/conversion/zoom.c:387 #, fuzzy msgid "Vertical zoom factor" msgstr "vertikaler Versatz vom Ursprung" #: libvips/convolution/canny.c:436 msgid "Canny edge detector" msgstr "" #: libvips/convolution/canny.c:454 libvips/convolution/gaussblur.c:144 #: libvips/convolution/sharpen.c:334 libvips/create/gaussmat.c:185 #: libvips/create/gaussnoise.c:189 msgid "Sigma" msgstr "" #: libvips/convolution/canny.c:455 libvips/convolution/gaussblur.c:145 #: libvips/convolution/sharpen.c:335 libvips/create/gaussmat.c:186 msgid "Sigma of Gaussian" msgstr "" #: libvips/convolution/canny.c:461 libvips/convolution/compass.c:184 #: libvips/convolution/conv.c:134 libvips/convolution/convsep.c:130 #: libvips/convolution/gaussblur.c:158 libvips/create/gaussmat.c:213 #: libvips/create/logmat.c:229 #, fuzzy msgid "Precision" msgstr "Komprimierung" #: libvips/convolution/canny.c:462 libvips/convolution/compass.c:185 #: libvips/convolution/conv.c:135 libvips/convolution/convsep.c:131 #: libvips/convolution/gaussblur.c:159 msgid "Convolve with this precision" msgstr "" #: libvips/convolution/compass.c:159 msgid "convolve with rotating mask" msgstr "" #: libvips/convolution/compass.c:163 msgid "Times" msgstr "" #: libvips/convolution/compass.c:164 msgid "Rotate and convolve this many times" msgstr "" #: libvips/convolution/compass.c:171 msgid "Rotate mask by this much between convolutions" msgstr "" #: libvips/convolution/compass.c:178 msgid "Combine convolution results like this" msgstr "" #: libvips/convolution/compass.c:191 libvips/convolution/conva.c:1323 #: libvips/convolution/convasep.c:918 libvips/convolution/conv.c:141 #: libvips/convolution/convsep.c:137 msgid "Layers" msgstr "" #: libvips/convolution/compass.c:192 libvips/convolution/conva.c:1324 #: libvips/convolution/convasep.c:919 libvips/convolution/conv.c:142 #: libvips/convolution/convsep.c:138 msgid "Use this many layers in approximation" msgstr "" #: libvips/convolution/compass.c:198 libvips/convolution/conva.c:1330 #: libvips/convolution/conv.c:148 libvips/convolution/convsep.c:144 msgid "Cluster" msgstr "" #: libvips/convolution/compass.c:199 libvips/convolution/conva.c:1331 #: libvips/convolution/conv.c:149 libvips/convolution/convsep.c:145 msgid "Cluster lines closer than this in approximation" msgstr "" #: libvips/convolution/conva.c:236 libvips/convolution/conva.c:242 #: libvips/convolution/conva.c:760 libvips/convolution/convasep.c:151 msgid "mask too complex" msgstr "Maske zu komplex" #: libvips/convolution/conva.c:997 libvips/convolution/conva.c:1247 #: libvips/convolution/convasep.c:840 msgid "image too small for mask" msgstr "Bild zu klein für Maske" #: libvips/convolution/conva.c:1319 msgid "approximate integer convolution" msgstr "" #: libvips/convolution/convasep.c:914 msgid "approximate separable integer convolution" msgstr "" #: libvips/convolution/conv.c:130 #, fuzzy msgid "convolution operation" msgstr "Umwandlungstransaktionen" #: libvips/convolution/convf.c:374 #, fuzzy msgid "float convolution operation" msgstr "Umwandlungstransaktionen" #: libvips/convolution/convi.c:1245 #, fuzzy msgid "int convolution operation" msgstr "Umwandlungstransaktionen" #: libvips/convolution/convolution.c:109 #, fuzzy msgid "convolution operations" msgstr "Umwandlungstransaktionen" #: libvips/convolution/convolution.c:130 libvips/convolution/correlation.c:156 #: libvips/draw/draw_mask.c:332 libvips/freqfilt/freqmult.c:130 #: libvips/morphology/labelregions.c:124 libvips/morphology/morph.c:966 msgid "Mask" msgstr "" #: libvips/convolution/convolution.c:131 libvips/morphology/morph.c:967 #, fuzzy msgid "Input matrix image" msgstr "Eingabebild" #: libvips/convolution/convsep.c:126 #, fuzzy msgid "separable convolution operation" msgstr "Umwandlungstransaktionen" #: libvips/convolution/correlation.c:144 #, fuzzy msgid "correlation operation" msgstr "Umwandlungstransaktionen" #: libvips/convolution/correlation.c:157 #, fuzzy msgid "Input reference image" msgstr "Zeilensprungbild" #: libvips/convolution/edge.c:213 #, fuzzy msgid "Edge detector" msgstr "falscher Bild-Deskriptor" #: libvips/convolution/edge.c:258 msgid "Sobel edge detector" msgstr "" #: libvips/convolution/edge.c:291 msgid "Scharr edge detector" msgstr "" #: libvips/convolution/edge.c:324 msgid "Prewitt edge detector" msgstr "" #: libvips/convolution/fastcor.c:218 #, fuzzy msgid "fast correlation" msgstr "Interpretation" #: libvips/convolution/gaussblur.c:126 msgid "gaussian blur" msgstr "" #: libvips/convolution/gaussblur.c:151 libvips/create/gaussmat.c:192 msgid "Minimum amplitude" msgstr "" #: libvips/convolution/gaussblur.c:152 libvips/create/gaussmat.c:193 #: libvips/create/logmat.c:209 #, fuzzy msgid "Minimum amplitude of Gaussian" msgstr "Minimalwert des Bildes" #: libvips/convolution/sharpen.c:316 msgid "unsharp masking for print" msgstr "" #: libvips/convolution/sharpen.c:341 libvips/draw/draw_line.c:284 #, fuzzy msgid "x1" msgstr "x" #: libvips/convolution/sharpen.c:342 msgid "Flat/jaggy threshold" msgstr "" #: libvips/convolution/sharpen.c:348 libvips/draw/draw_line.c:305 #, fuzzy msgid "y2" msgstr "y" #: libvips/convolution/sharpen.c:349 msgid "Maximum brightening" msgstr "" #: libvips/convolution/sharpen.c:355 #, fuzzy msgid "y3" msgstr "y" #: libvips/convolution/sharpen.c:356 msgid "Maximum darkening" msgstr "" #: libvips/convolution/sharpen.c:362 msgid "m1" msgstr "" #: libvips/convolution/sharpen.c:363 msgid "Slope for flat areas" msgstr "" #: libvips/convolution/sharpen.c:369 msgid "m2" msgstr "" #: libvips/convolution/sharpen.c:370 msgid "Slope for jaggy areas" msgstr "" #: libvips/convolution/sharpen.c:378 libvips/create/logmat.c:201 #: libvips/create/mask_butterworth_band.c:136 #: libvips/create/mask_gaussian_band.c:121 libvips/create/mask_ideal_band.c:112 #: libvips/create/sdf.c:326 libvips/draw/draw_circle.c:248 msgid "Radius" msgstr "" #: libvips/convolution/sharpen.c:379 libvips/create/logmat.c:202 msgid "Radius of Gaussian" msgstr "" #: libvips/convolution/spcor.c:317 msgid "spatial correlation" msgstr "" #: libvips/create/black.c:136 msgid "make a black image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/buildlut.c:134 #, fuzzy, c-format msgid "x value row %d not an int" msgstr "x-Wert keine Ganzzahl" #: libvips/create/buildlut.c:149 msgid "x range too small" msgstr "x-Bereich zu klein" #: libvips/create/buildlut.c:259 libvips/create/tonelut.c:221 msgid "build a look-up table" msgstr "" #: libvips/create/buildlut.c:264 libvips/create/invertlut.c:289 #, fuzzy msgid "Matrix of XY coordinates" msgstr "Matrix der Koeffizienten" #: libvips/create/create.c:112 #, fuzzy msgid "create operations" msgstr "Transaktionen" #: libvips/create/eye.c:103 msgid "make an image showing the eye's spatial response" msgstr "" #: libvips/create/eye.c:109 msgid "Maximum spatial frequency" msgstr "" #: libvips/create/fractsurf.c:100 #, fuzzy msgid "make a fractal surface" msgstr "ein schwarzes Bild erstellen" #: libvips/create/fractsurf.c:118 libvips/create/fractsurf.c:119 #: libvips/create/mask_fractal.c:93 libvips/create/mask_fractal.c:94 #, fuzzy msgid "Fractal dimension" msgstr "falsche Abmessungen" #: libvips/create/gaussmat.c:129 libvips/create/logmat.c:147 #, fuzzy msgid "mask too large" msgstr "Maske zu komplex" #: libvips/create/gaussmat.c:181 #, fuzzy msgid "make a gaussian image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/gaussmat.c:199 libvips/create/logmat.c:215 #, fuzzy msgid "Separable" msgstr "Trenner" #: libvips/create/gaussmat.c:200 libvips/create/logmat.c:216 msgid "Generate separable Gaussian" msgstr "" #: libvips/create/gaussmat.c:206 libvips/create/logmat.c:222 #, fuzzy msgid "Integer" msgstr "Zeilensprung" #: libvips/create/gaussmat.c:207 libvips/create/logmat.c:223 #, fuzzy msgid "Generate integer Gaussian" msgstr "Rest nach Ganzzahldivision" #: libvips/create/gaussmat.c:214 libvips/create/logmat.c:230 msgid "Generate with this precision" msgstr "" #: libvips/create/gaussnoise.c:160 #, fuzzy msgid "make a gaussnoise image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/gaussnoise.c:182 libvips/histogram/stdif.c:329 msgid "Mean" msgstr "" #: libvips/create/gaussnoise.c:183 #, fuzzy msgid "Mean of pixels in generated image" msgstr "keine Bildpunktdaten in angehängtem Bild" #: libvips/create/gaussnoise.c:190 #, fuzzy msgid "Standard deviation of pixels in generated image" msgstr "Standardabweichung des Bildes" #: libvips/create/gaussnoise.c:196 libvips/create/perlin.c:323 #: libvips/create/worley.c:329 msgid "Seed" msgstr "" #: libvips/create/gaussnoise.c:197 libvips/create/perlin.c:324 #: libvips/create/worley.c:330 #, fuzzy msgid "Random number seed" msgstr "falsche Achsenanzahl %d" #: libvips/create/grey.c:89 #, fuzzy msgid "make a grey ramp image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/identity.c:139 msgid "make a 1D image where pixel values are indexes" msgstr "" #: libvips/create/identity.c:144 #, fuzzy msgid "Number of bands in LUT" msgstr "Anzahl der Bänder in einem Bild" #: libvips/create/identity.c:150 msgid "Ushort" msgstr "" #: libvips/create/identity.c:151 msgid "Create a 16-bit LUT" msgstr "" #: libvips/create/identity.c:158 msgid "Size of 16-bit LUT" msgstr "" #: libvips/create/invertlut.c:124 msgid "bad input matrix" msgstr "falsche Eingabematrix" #: libvips/create/invertlut.c:129 msgid "bad size" msgstr "falsche Größe" #: libvips/create/invertlut.c:149 #, fuzzy, c-format msgid "element (%d, %d) is %g, outside range [0,1]" msgstr "Element außerhalb des Bereichs [0,1]" #: libvips/create/invertlut.c:284 msgid "build an inverted look-up table" msgstr "" #: libvips/create/invertlut.c:295 msgid "LUT size to generate" msgstr "" #: libvips/create/logmat.c:197 #, fuzzy msgid "make a Laplacian of Gaussian image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/mask_butterworth_band.c:110 msgid "make a butterworth_band filter" msgstr "" #: libvips/create/mask_butterworth_band.c:115 #: libvips/create/mask_butterworth.c:91 msgid "Order" msgstr "" #: libvips/create/mask_butterworth_band.c:116 #: libvips/create/mask_butterworth.c:92 msgid "Filter order" msgstr "" #: libvips/create/mask_butterworth_band.c:122 #: libvips/create/mask_butterworth_band.c:123 #: libvips/create/mask_gaussian_band.c:107 #: libvips/create/mask_gaussian_band.c:108 libvips/create/mask_ideal_band.c:98 #: libvips/create/mask_ideal_band.c:99 msgid "Frequency cutoff x" msgstr "" #: libvips/create/mask_butterworth_band.c:129 #: libvips/create/mask_butterworth_band.c:130 #: libvips/create/mask_gaussian_band.c:114 #: libvips/create/mask_gaussian_band.c:115 libvips/create/mask_ideal_band.c:105 #: libvips/create/mask_ideal_band.c:106 msgid "Frequency cutoff y" msgstr "" #: libvips/create/mask_butterworth_band.c:137 #: libvips/create/mask_gaussian_band.c:122 libvips/create/mask_ideal_band.c:113 msgid "Radius of circle" msgstr "" #: libvips/create/mask_butterworth_band.c:143 #: libvips/create/mask_butterworth_band.c:144 #: libvips/create/mask_butterworth.c:105 libvips/create/mask_butterworth.c:106 #: libvips/create/mask_gaussian_band.c:128 #: libvips/create/mask_gaussian_band.c:129 libvips/create/mask_gaussian.c:93 #: libvips/create/mask_gaussian.c:94 msgid "Amplitude cutoff" msgstr "" #: libvips/create/mask_butterworth.c:86 msgid "make a butterworth filter" msgstr "" #: libvips/create/mask_butterworth.c:98 libvips/create/mask_butterworth.c:99 #: libvips/create/mask_gaussian.c:86 libvips/create/mask_gaussian.c:87 #: libvips/create/mask_ideal.c:84 libvips/create/mask_ideal.c:85 msgid "Frequency cutoff" msgstr "" #: libvips/create/mask_butterworth_ring.c:101 msgid "make a butterworth ring filter" msgstr "" #: libvips/create/mask_butterworth_ring.c:106 #: libvips/create/mask_butterworth_ring.c:107 #: libvips/create/mask_gaussian_ring.c:101 #: libvips/create/mask_gaussian_ring.c:102 libvips/create/mask_ideal_ring.c:98 #: libvips/create/mask_ideal_ring.c:99 #, fuzzy msgid "Ringwidth" msgstr "Kachelbreite" #: libvips/create/mask.c:114 msgid "base class for frequency filters" msgstr "" #: libvips/create/mask.c:122 msgid "Optical" msgstr "" #: libvips/create/mask.c:123 msgid "Rotate quadrants to optical space" msgstr "" #: libvips/create/mask.c:129 msgid "Reject" msgstr "" #: libvips/create/mask.c:130 msgid "Invert the sense of the filter" msgstr "" #: libvips/create/mask.c:136 msgid "Nodc" msgstr "" #: libvips/create/mask.c:137 msgid "Remove DC component" msgstr "" #: libvips/create/mask_fractal.c:88 msgid "make fractal filter" msgstr "" #: libvips/create/mask_gaussian_band.c:102 libvips/create/mask_gaussian.c:81 msgid "make a gaussian filter" msgstr "" #: libvips/create/mask_gaussian_ring.c:96 msgid "make a gaussian ring filter" msgstr "" #: libvips/create/mask_ideal_band.c:93 msgid "make an ideal band filter" msgstr "" #: libvips/create/mask_ideal.c:79 msgid "make an ideal filter" msgstr "" #: libvips/create/mask_ideal_ring.c:93 msgid "make an ideal ring filter" msgstr "" #: libvips/create/perlin.c:291 #, fuzzy msgid "make a perlin noise image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/perlin.c:309 libvips/create/worley.c:322 msgid "Cell size" msgstr "" #: libvips/create/perlin.c:310 msgid "Size of Perlin cells" msgstr "" #: libvips/create/perlin.c:316 libvips/create/point.c:155 msgid "Uchar" msgstr "" #: libvips/create/perlin.c:317 libvips/create/point.c:156 #, fuzzy msgid "Output an unsigned char image" msgstr "kein »uchar«-Bild mit einem Band" #: libvips/create/point.c:132 #, fuzzy msgid "make a point image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/sdf.c:178 msgid "circle needs a, r to be set" msgstr "" #: libvips/create/sdf.c:183 msgid "rounded-box needs 2 values for a" msgstr "" #: libvips/create/sdf.c:196 msgid "box needs a, b to be set" msgstr "" #: libvips/create/sdf.c:202 msgid "box needs 2 values for a, b" msgstr "" #: libvips/create/sdf.c:216 msgid "rounded-box needs a, b to be set" msgstr "" #: libvips/create/sdf.c:222 msgid "rounded-box needs 2 values for a, b" msgstr "" #: libvips/create/sdf.c:227 msgid "rounded-box needs 4 values for corners" msgstr "" #: libvips/create/sdf.c:242 msgid "line needs sx, sy to be set" msgstr "" #: libvips/create/sdf.c:248 msgid "line needs 2 values for a, b" msgstr "" #: libvips/create/sdf.c:259 #, fuzzy, c-format msgid "unknown SDF %d" msgstr "unbekannte Kodierung" #: libvips/create/sdf.c:300 #, fuzzy msgid "create an SDF image" msgstr "ein Bild drehen" #: libvips/create/sdf.c:318 msgid "Shape" msgstr "" #: libvips/create/sdf.c:319 msgid "SDF shape to create" msgstr "" #: libvips/create/sdf.c:325 msgid "r" msgstr "" #: libvips/create/sdf.c:333 msgid "Point a" msgstr "" #: libvips/create/sdf.c:340 msgid "Point b" msgstr "" #: libvips/create/sdf.c:346 msgid "corners" msgstr "" #: libvips/create/sdf.c:347 msgid "Corner radii" msgstr "" #: libvips/create/sines.c:122 msgid "make a 2D sine wave" msgstr "" #: libvips/create/sines.c:128 msgid "hfreq" msgstr "" #: libvips/create/sines.c:129 #, fuzzy msgid "Horizontal spatial frequency" msgstr "horizontaler Versatz vom Ursprung" #: libvips/create/sines.c:135 msgid "vfreq" msgstr "" #: libvips/create/sines.c:136 msgid "Vertical spatial frequency" msgstr "" #: libvips/create/text.c:411 msgid "invalid markup in text" msgstr "ungültige Auszeichnung im Text" #: libvips/create/text.c:471 msgid "no text to render" msgstr "kein Text zu rendern" #: libvips/create/text.c:553 #, fuzzy msgid "make a text image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/text.c:557 msgid "Text" msgstr "" #: libvips/create/text.c:558 #, fuzzy msgid "Text to render" msgstr "kein Text zu rendern" #: libvips/create/text.c:564 msgid "Font" msgstr "" #: libvips/create/text.c:565 #, fuzzy msgid "Font to render with" msgstr "kein Text zu rendern" #: libvips/create/text.c:572 #, fuzzy msgid "Maximum image width in pixels" msgstr "Bildbreite in Bildpunkten" #: libvips/create/text.c:579 #, fuzzy msgid "Maximum image height in pixels" msgstr "Bildhöhe in Bildpunkten" #: libvips/create/text.c:586 #, fuzzy msgid "Align on the low, centre or high edge" msgstr "am Rand der unteren, mittleren oder höchsten Koordinate ausrichten" #: libvips/create/text.c:592 msgid "Justify" msgstr "" #: libvips/create/text.c:593 #, fuzzy msgid "Justify lines" msgstr "leere Zeile" #: libvips/create/text.c:599 libvips/foreign/pdfiumload.c:707 #: libvips/foreign/popplerload.c:557 libvips/foreign/svgload.c:782 msgid "DPI" msgstr "" #: libvips/create/text.c:600 libvips/foreign/pdfiumload.c:708 #: libvips/foreign/popplerload.c:558 #, fuzzy msgid "DPI to render at" msgstr "kein Text zu rendern" #: libvips/create/text.c:606 msgid "Autofit DPI" msgstr "" #: libvips/create/text.c:607 msgid "DPI selected by autofit" msgstr "" #: libvips/create/text.c:613 msgid "Spacing" msgstr "" #: libvips/create/text.c:614 msgid "Line spacing" msgstr "" #: libvips/create/text.c:620 #, fuzzy msgid "Font file" msgstr "Profil" #: libvips/create/text.c:621 #, fuzzy msgid "Load this font file" msgstr "diese Seite aus der Datei laden" #: libvips/create/text.c:627 msgid "RGBA" msgstr "" #: libvips/create/text.c:628 msgid "Enable RGBA output" msgstr "" #: libvips/create/text.c:634 msgid "Wrap" msgstr "" #: libvips/create/text.c:635 msgid "Wrap lines on word or character boundaries" msgstr "" #: libvips/create/tonelut.c:225 msgid "In-max" msgstr "" #: libvips/create/tonelut.c:226 msgid "Size of LUT to build" msgstr "" #: libvips/create/tonelut.c:232 msgid "Out-max" msgstr "" #: libvips/create/tonelut.c:233 #, fuzzy msgid "Maximum value in output LUT" msgstr "Maximalwert des Bildes" #: libvips/create/tonelut.c:239 msgid "Black point" msgstr "" #: libvips/create/tonelut.c:240 #, fuzzy msgid "Lowest value in output" msgstr "linker Rand der Eingabe in der Ausgabe" #: libvips/create/tonelut.c:246 msgid "White point" msgstr "" #: libvips/create/tonelut.c:247 msgid "Highest value in output" msgstr "" #: libvips/create/tonelut.c:253 msgid "Shadow point" msgstr "" #: libvips/create/tonelut.c:254 msgid "Position of shadow" msgstr "" #: libvips/create/tonelut.c:260 msgid "Mid-tone point" msgstr "" #: libvips/create/tonelut.c:261 msgid "Position of mid-tones" msgstr "" #: libvips/create/tonelut.c:267 msgid "Highlight point" msgstr "" #: libvips/create/tonelut.c:268 msgid "Position of highlights" msgstr "" #: libvips/create/tonelut.c:274 msgid "Shadow adjust" msgstr "" #: libvips/create/tonelut.c:275 msgid "Adjust shadows by this much" msgstr "" #: libvips/create/tonelut.c:281 msgid "Mid-tone adjust" msgstr "" #: libvips/create/tonelut.c:282 msgid "Adjust mid-tones by this much" msgstr "" #: libvips/create/tonelut.c:288 msgid "Highlight adjust" msgstr "" #: libvips/create/tonelut.c:289 msgid "Adjust highlights by this much" msgstr "" #: libvips/create/worley.c:304 #, fuzzy msgid "make a worley noise image" msgstr "ein schwarzes Bild erstellen" #: libvips/create/worley.c:323 msgid "Size of Worley cells" msgstr "" #: libvips/create/xyz.c:139 #, fuzzy msgid "lower dimensions not set" msgstr "Abfragen der Abmessungen: %s" #: libvips/create/xyz.c:156 libvips/foreign/heifsave.c:671 #: libvips/foreign/webpsave.c:736 #, fuzzy msgid "image too large" msgstr "Bild zu schmal" #: libvips/create/xyz.c:187 msgid "make an image where pixel values are coordinates" msgstr "" #: libvips/create/xyz.c:205 #, fuzzy msgid "csize" msgstr "falsche Größe" #: libvips/create/xyz.c:206 msgid "Size of third dimension" msgstr "" #: libvips/create/xyz.c:212 #, fuzzy msgid "dsize" msgstr "falsche Größe" #: libvips/create/xyz.c:213 msgid "Size of fourth dimension" msgstr "" #: libvips/create/xyz.c:219 #, fuzzy msgid "esize" msgstr "falsche Größe" #: libvips/create/xyz.c:220 msgid "Size of fifth dimension" msgstr "" #: libvips/create/zone.c:90 msgid "make a zone plate" msgstr "" #: libvips/draw/draw.c:101 #, fuzzy msgid "draw operations" msgstr "Transaktionen" #: libvips/draw/draw.c:108 #, fuzzy msgid "Image" msgstr "Eingabebild" #: libvips/draw/draw.c:109 #, fuzzy msgid "Image to draw on" msgstr "zu speicherndes Bild" #: libvips/draw/draw_circle.c:230 #, fuzzy msgid "draw a circle on an image" msgstr "einen Bereich eines Bildes extrahieren" #: libvips/draw/draw_circle.c:234 #, fuzzy msgid "cx" msgstr "x" #: libvips/draw/draw_circle.c:235 libvips/draw/draw_circle.c:242 msgid "Centre of draw_circle" msgstr "" #: libvips/draw/draw_circle.c:241 #, fuzzy msgid "cy" msgstr "y" #: libvips/draw/draw_circle.c:249 #, fuzzy msgid "Radius in pixels" msgstr "Bildbreite in Bildpunkten" #: libvips/draw/draw_circle.c:255 libvips/draw/draw_rect.c:201 msgid "Fill" msgstr "" #: libvips/draw/draw_circle.c:256 libvips/draw/draw_rect.c:202 msgid "Draw a solid object" msgstr "" #: libvips/draw/draw_flood.c:562 msgid "flood-fill an area" msgstr "" #: libvips/draw/draw_flood.c:567 libvips/draw/draw_flood.c:574 msgid "DrawFlood start point" msgstr "" #: libvips/draw/draw_flood.c:580 msgid "Test" msgstr "" #: libvips/draw/draw_flood.c:581 #, fuzzy msgid "Test pixels in this image" msgstr "keine Bildpunktdaten in angehängtem Bild" #: libvips/draw/draw_flood.c:586 msgid "Equal" msgstr "" #: libvips/draw/draw_flood.c:587 msgid "DrawFlood while equal to edge" msgstr "" #: libvips/draw/draw_flood.c:594 #, fuzzy msgid "Left edge of modified area" msgstr "linke Kante eines extrahierten Bereichs" #: libvips/draw/draw_flood.c:601 #, fuzzy msgid "Top edge of modified area" msgstr "obere Kante eines extrahierten Bereichs" #: libvips/draw/draw_flood.c:608 #, fuzzy msgid "Width of modified area" msgstr "Breite des extrahierten Bereichs" #: libvips/draw/draw_flood.c:615 #, fuzzy msgid "Height of modified area" msgstr "Höhe des extrahierten Bereichs" #: libvips/draw/draw_image.c:265 #, fuzzy msgid "paint an image into another image" msgstr "ein Bild in ein größeres Bild einbetten" #: libvips/draw/draw_image.c:276 libvips/draw/draw_image.c:283 #, fuzzy msgid "Draw image here" msgstr "- Bild-Kopfzeilen ausgeben" #: libvips/draw/draw_image.c:289 libvips/iofuncs/image.c:1164 msgid "Mode" msgstr "Modus" #: libvips/draw/draw_image.c:290 msgid "Combining mode" msgstr "" #: libvips/draw/drawink.c:86 #, fuzzy msgid "draw with ink operations" msgstr "arithmetische Transaktionen" #: libvips/draw/drawink.c:90 msgid "Ink" msgstr "" #: libvips/draw/drawink.c:91 #, fuzzy msgid "Color for pixels" msgstr "Farbe für neue Bildpunkte" #: libvips/draw/draw_line.c:280 #, fuzzy msgid "draw a line on an image" msgstr "eine mathematische Funktion für ein Bild ausführen" #: libvips/draw/draw_line.c:285 libvips/draw/draw_line.c:292 msgid "Start of draw_line" msgstr "" #: libvips/draw/draw_line.c:291 #, fuzzy msgid "y1" msgstr "y" #: libvips/draw/draw_line.c:298 #, fuzzy msgid "x2" msgstr "x" #: libvips/draw/draw_line.c:299 libvips/draw/draw_line.c:306 msgid "End of draw_line" msgstr "" #: libvips/draw/draw_mask.c:328 #, fuzzy msgid "draw a mask on an image" msgstr "einen Bereich eines Bildes extrahieren" #: libvips/draw/draw_mask.c:333 msgid "Mask of pixels to draw" msgstr "" #: libvips/draw/draw_mask.c:339 libvips/draw/draw_mask.c:346 msgid "Draw mask here" msgstr "" #: libvips/draw/draw_rect.c:169 #, fuzzy msgid "paint a rectangle on an image" msgstr "einen Bereich eines Bildes extrahieren" #: libvips/draw/draw_rect.c:174 libvips/draw/draw_rect.c:181 #: libvips/draw/draw_rect.c:188 libvips/draw/draw_rect.c:195 #: libvips/draw/draw_smudge.c:216 libvips/draw/draw_smudge.c:223 #: libvips/draw/draw_smudge.c:230 libvips/draw/draw_smudge.c:237 #, fuzzy msgid "Rect to fill" msgstr "Ziel zu klein" # http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650& # db=man&fname=/usr/share/catman/p_man/cat3/il_c/ilAbsImg.z #: libvips/draw/draw_smudge.c:211 #, fuzzy msgid "blur a rectangle on an image" msgstr "absoluter Wert eines Bildes" #: libvips/foreign/analyze2vips.c:308 msgid "header file size incorrect" msgstr "Kopfdatendateigröße nicht korrekt" #: libvips/foreign/analyze2vips.c:352 msgid "header size incorrect" msgstr "Kopfdatengröße nicht korrekt" #: libvips/foreign/analyze2vips.c:370 libvips/foreign/niftiload.c:397 #, c-format msgid "%d-dimensional images not supported" msgstr "%d-dimensionale Bilder nicht unterstützt" #: libvips/foreign/analyze2vips.c:423 libvips/foreign/niftiload.c:440 #, c-format msgid "datatype %d not supported" msgstr "Datentyp %d nicht unterstützt" #: libvips/foreign/analyzeload.c:120 msgid "load an Analyze6 image" msgstr "ein Analyze6-Bild laden" #: libvips/foreign/analyzeload.c:141 libvips/foreign/cgifsave.c:1058 #: libvips/foreign/csvload.c:586 libvips/foreign/csvsave.c:274 #: libvips/foreign/dzsave.c:2588 libvips/foreign/fitsload.c:254 #: libvips/foreign/fitssave.c:143 libvips/foreign/heifload.c:1267 #: libvips/foreign/heifsave.c:883 libvips/foreign/jp2kload.c:1319 #: libvips/foreign/jp2ksave.c:1060 libvips/foreign/jpegload.c:346 #: libvips/foreign/jpegsave.c:364 libvips/foreign/jxlload.c:1210 #: libvips/foreign/jxlsave.c:1178 libvips/foreign/magick6load.c:977 #: libvips/foreign/magick7load.c:849 libvips/foreign/matload.c:138 #: libvips/foreign/matrixload.c:370 libvips/foreign/matrixsave.c:228 #: libvips/foreign/niftiload.c:708 libvips/foreign/niftisave.c:441 #: libvips/foreign/nsgifload.c:762 libvips/foreign/openexrload.c:149 #: libvips/foreign/openslideload.c:1097 libvips/foreign/pdfiumload.c:810 #: libvips/foreign/pngload.c:313 libvips/foreign/pngsave.c:386 #: libvips/foreign/popplerload.c:687 libvips/foreign/ppmload.c:827 #: libvips/foreign/ppmsave.c:578 libvips/foreign/radload.c:276 #: libvips/foreign/radsave.c:155 libvips/foreign/rawload.c:139 #: libvips/foreign/rawsave.c:196 libvips/foreign/spngload.c:830 #: libvips/foreign/spngsave.c:863 libvips/foreign/svgload.c:1008 #: libvips/foreign/tiffload.c:376 libvips/foreign/tiffsave.c:524 #: libvips/foreign/vips2magick.c:578 libvips/foreign/vipsload.c:233 #: libvips/foreign/vipssave.c:191 libvips/foreign/webpload.c:338 #: libvips/foreign/webpsave.c:1035 libvips/iofuncs/connection.c:125 #: libvips/iofuncs/image.c:1157 libvips/resample/thumbnail.c:1216 msgid "Filename" msgstr "Dateiname" #: libvips/foreign/analyzeload.c:142 libvips/foreign/csvload.c:587 #: libvips/foreign/fitsload.c:255 libvips/foreign/heifload.c:1268 #: libvips/foreign/jp2kload.c:1320 libvips/foreign/jpegload.c:347 #: libvips/foreign/jxlload.c:1211 libvips/foreign/magick6load.c:978 #: libvips/foreign/magick7load.c:850 libvips/foreign/matload.c:139 #: libvips/foreign/matrixload.c:371 libvips/foreign/niftiload.c:709 #: libvips/foreign/nsgifload.c:763 libvips/foreign/openexrload.c:150 #: libvips/foreign/openslideload.c:1098 libvips/foreign/pdfiumload.c:811 #: libvips/foreign/pngload.c:314 libvips/foreign/popplerload.c:688 #: libvips/foreign/ppmload.c:828 libvips/foreign/radload.c:277 #: libvips/foreign/rawload.c:140 libvips/foreign/spngload.c:831 #: libvips/foreign/svgload.c:1009 libvips/foreign/tiffload.c:377 #: libvips/foreign/vipsload.c:234 libvips/foreign/webpload.c:339 msgid "Filename to load from" msgstr "Name der Datei, aus der geladen werden soll" #: libvips/foreign/archive.c:138 #, fuzzy msgid "unable to create archive" msgstr "es können keine Profile erstellt werden" #: libvips/foreign/archive.c:146 #, fuzzy msgid "unable to set zip format" msgstr "Dateistatus kann nicht abgefragt werden" #: libvips/foreign/archive.c:163 #, fuzzy msgid "unable to set compression" msgstr "»%s« kann nicht gesetzt werden" #: libvips/foreign/archive.c:175 #, fuzzy msgid "unable to set padding" msgstr "»%s« kann nicht gesetzt werden" #: libvips/foreign/archive.c:184 libvips/iofuncs/target.c:158 #, fuzzy msgid "unable to open for write" msgstr "»%s« kann nicht zur Eingabe geöffnet werden" #: libvips/foreign/archive.c:205 libvips/iofuncs/util.c:1192 #, fuzzy, c-format msgid "unable to create directory \"%s\", %s" msgstr "Daten für »%s« können nicht gelesen werden, %s" #: libvips/foreign/archive.c:240 #, fuzzy msgid "unable to create entry" msgstr "Thread kann nicht erstellt werden" #: libvips/foreign/archive.c:256 #, fuzzy msgid "unable to write header" msgstr "Thread kann nicht erstellt werden" #: libvips/foreign/archive.c:265 #, fuzzy msgid "unable to write data" msgstr "Daten können nicht gelesen werden" #: libvips/foreign/cgifsave.c:407 libvips/foreign/cgifsave.c:832 #: libvips/foreign/quantise.c:403 libvips/foreign/quantise.c:423 msgid "quantisation failed" msgstr "" #: libvips/foreign/cgifsave.c:587 #, fuzzy msgid "dither failed" msgstr "Schreiben fehlgeschlagen" #: libvips/foreign/cgifsave.c:771 #, fuzzy msgid "frame too large" msgstr "Zoomfaktoren zu groß" #: libvips/foreign/cgifsave.c:810 #, fuzzy msgid "gif-palette too large" msgstr "Zoomfaktoren zu groß" #: libvips/foreign/cgifsave.c:883 #, fuzzy msgid "save as gif" msgstr "Bild als ASCII speichern" #: libvips/foreign/cgifsave.c:893 libvips/foreign/pngsave.c:260 #: libvips/foreign/spngsave.c:736 msgid "Dithering" msgstr "" #: libvips/foreign/cgifsave.c:894 libvips/foreign/pngsave.c:261 #: libvips/foreign/spngsave.c:737 msgid "Amount of dithering" msgstr "" #: libvips/foreign/cgifsave.c:900 libvips/foreign/heifsave.c:792 #: libvips/foreign/jxlsave.c:1106 libvips/foreign/pngsave.c:274 #: libvips/foreign/spngsave.c:750 libvips/foreign/webpsave.c:893 msgid "Effort" msgstr "" #: libvips/foreign/cgifsave.c:901 msgid "Quantisation effort" msgstr "" #: libvips/foreign/cgifsave.c:907 libvips/foreign/heifsave.c:770 #: libvips/foreign/pngsave.c:267 libvips/foreign/ppmsave.c:507 #: libvips/foreign/spngsave.c:743 libvips/foreign/tiffsave.c:318 #: libvips/foreign/vips2magick.c:510 msgid "Bit depth" msgstr "" #: libvips/foreign/cgifsave.c:908 libvips/foreign/heifsave.c:771 #: libvips/foreign/vips2magick.c:511 #, fuzzy msgid "Number of bits per pixel" msgstr "Anzahl der Bänder in einem Bild" #: libvips/foreign/cgifsave.c:914 #, fuzzy msgid "Maximum inter-frame error" msgstr "interner Fehler" #: libvips/foreign/cgifsave.c:915 msgid "Maximum inter-frame error for transparency" msgstr "" #: libvips/foreign/cgifsave.c:921 msgid "Reuse palette" msgstr "" #: libvips/foreign/cgifsave.c:922 msgid "Reuse palette from input" msgstr "" #: libvips/foreign/cgifsave.c:928 #, fuzzy msgid "Maximum inter-palette error" msgstr "interner Fehler" #: libvips/foreign/cgifsave.c:929 msgid "Maximum inter-palette error for palette reusage" msgstr "" #: libvips/foreign/cgifsave.c:935 #, fuzzy msgid "Interlaced" msgstr "Zeilensprung" #: libvips/foreign/cgifsave.c:936 msgid "Generate an interlaced (progressive) GIF" msgstr "" #: libvips/foreign/cgifsave.c:945 msgid "Reoptimise palettes" msgstr "" #: libvips/foreign/cgifsave.c:946 msgid "Reoptimise colour palettes" msgstr "" #: libvips/foreign/cgifsave.c:952 #, fuzzy msgid "Keep duplicate frames" msgstr "ein Bild nachmachen" #: libvips/foreign/cgifsave.c:953 msgid "Keep duplicate frames in the output instead of combining them" msgstr "" #: libvips/foreign/cgifsave.c:1010 libvips/foreign/csvsave.c:325 #: libvips/foreign/dzsave.c:2531 libvips/foreign/heifsave.c:1003 #: libvips/foreign/jp2ksave.c:1176 libvips/foreign/jpegsave.c:295 #: libvips/foreign/jxlsave.c:1294 libvips/foreign/matrixsave.c:281 #: libvips/foreign/pngsave.c:336 libvips/foreign/ppmsave.c:634 #: libvips/foreign/radsave.c:208 libvips/foreign/rawsave.c:252 #: libvips/foreign/spngsave.c:813 libvips/foreign/tiffsave.c:474 #: libvips/foreign/vipssave.c:244 libvips/foreign/webpsave.c:987 #: libvips/iofuncs/target.c:305 msgid "Target" msgstr "" #: libvips/foreign/cgifsave.c:1011 libvips/foreign/csvsave.c:326 #: libvips/foreign/dzsave.c:2532 libvips/foreign/heifsave.c:1004 #: libvips/foreign/jp2ksave.c:1177 libvips/foreign/jpegsave.c:296 #: libvips/foreign/jxlsave.c:1295 libvips/foreign/matrixsave.c:282 #: libvips/foreign/pngsave.c:337 libvips/foreign/ppmsave.c:635 #: libvips/foreign/radsave.c:209 libvips/foreign/rawsave.c:253 #: libvips/foreign/spngsave.c:814 libvips/foreign/tiffsave.c:475 #: libvips/foreign/vipssave.c:245 libvips/foreign/webpsave.c:988 #, fuzzy msgid "Target to save to" msgstr "zu speicherndes Bild" #: libvips/foreign/cgifsave.c:1059 libvips/foreign/csvsave.c:275 #: libvips/foreign/dzsave.c:2589 libvips/foreign/fitssave.c:144 #: libvips/foreign/heifsave.c:884 libvips/foreign/jp2ksave.c:1061 #: libvips/foreign/jpegsave.c:365 libvips/foreign/jxlsave.c:1179 #: libvips/foreign/matrixsave.c:229 libvips/foreign/niftisave.c:442 #: libvips/foreign/pngsave.c:387 libvips/foreign/ppmsave.c:579 #: libvips/foreign/radsave.c:156 libvips/foreign/rawsave.c:197 #: libvips/foreign/spngsave.c:864 libvips/foreign/tiffsave.c:525 #: libvips/foreign/vips2magick.c:579 libvips/foreign/vipssave.c:192 #: libvips/foreign/webpsave.c:1036 msgid "Filename to save to" msgstr "Name der Datei in die gespeichert werden soll" #: libvips/foreign/cgifsave.c:1117 libvips/foreign/dzsave.c:2647 #: libvips/foreign/heifload.c:1333 libvips/foreign/heifsave.c:948 #: libvips/foreign/jp2kload.c:1392 libvips/foreign/jp2ksave.c:1123 #: libvips/foreign/jpegload.c:419 libvips/foreign/jpegsave.c:442 #: libvips/foreign/jxlload.c:1283 libvips/foreign/jxlsave.c:1241 #: libvips/foreign/magick6load.c:1065 libvips/foreign/magick7load.c:930 #: libvips/foreign/nsgifload.c:837 libvips/foreign/pdfiumload.c:870 #: libvips/foreign/pngload.c:386 libvips/foreign/pngsave.c:445 #: libvips/foreign/popplerload.c:747 libvips/foreign/ppmload.c:900 #: libvips/foreign/radload.c:349 libvips/foreign/radsave.c:274 #: libvips/foreign/rawsave.c:314 libvips/foreign/spngload.c:903 #: libvips/foreign/spngsave.c:923 libvips/foreign/svgload.c:1076 #: libvips/foreign/tiffload.c:451 libvips/foreign/tiffsave.c:585 #: libvips/foreign/vips2magick.c:650 libvips/foreign/webpload.c:413 #: libvips/foreign/webpsave.c:1093 libvips/resample/thumbnail.c:1463 msgid "Buffer" msgstr "Puffer" #: libvips/foreign/cgifsave.c:1118 libvips/foreign/dzsave.c:2648 #: libvips/foreign/heifsave.c:949 libvips/foreign/jp2ksave.c:1124 #: libvips/foreign/jpegsave.c:443 libvips/foreign/jxlsave.c:1242 #: libvips/foreign/pngsave.c:446 libvips/foreign/radsave.c:275 #: libvips/foreign/rawsave.c:315 libvips/foreign/spngsave.c:924 #: libvips/foreign/tiffsave.c:586 libvips/foreign/vips2magick.c:651 #: libvips/foreign/webpsave.c:1094 msgid "Buffer to save to" msgstr "Puffer, in den gespeichert werden soll" #: libvips/foreign/csvload.c:339 libvips/foreign/csvload.c:400 #: libvips/foreign/csvload.c:432 #, fuzzy msgid "unexpected end of file" msgstr "Unerwartetes Ende der Zeichenkette" #: libvips/foreign/csvload.c:438 #, c-format msgid "line %d has only %d columns" msgstr "" #: libvips/foreign/csvload.c:477 #, fuzzy msgid "load csv" msgstr "CSV aus Datei laden" #: libvips/foreign/csvload.c:490 msgid "Skip" msgstr "überspringen" #: libvips/foreign/csvload.c:491 msgid "Skip this many lines at the start of the file" msgstr "so viele Zeilen ab dem Dateianfang überspringen" #: libvips/foreign/csvload.c:497 msgid "Lines" msgstr "Zeilen" #: libvips/foreign/csvload.c:498 msgid "Read this many lines from the file" msgstr "so viele Zeilen aus der Datei lesen" #: libvips/foreign/csvload.c:504 msgid "Whitespace" msgstr "Leerraum" #: libvips/foreign/csvload.c:505 msgid "Set of whitespace characters" msgstr "Satz von Leerraumzeichen" #: libvips/foreign/csvload.c:511 libvips/foreign/csvsave.c:223 msgid "Separator" msgstr "Trenner" #: libvips/foreign/csvload.c:512 msgid "Set of separator characters" msgstr "Satz von Trennzeichen" #: libvips/foreign/csvload.c:654 libvips/foreign/fitsload.c:330 #: libvips/foreign/heifload.c:1404 libvips/foreign/jp2kload.c:1452 #: libvips/foreign/jpegload.c:273 libvips/foreign/jxlload.c:1344 #: libvips/foreign/matrixload.c:454 libvips/foreign/niftiload.c:784 #: libvips/foreign/nsgifload.c:900 libvips/foreign/openslideload.c:1171 #: libvips/foreign/pdfiumload.c:930 libvips/foreign/pngload.c:239 #: libvips/foreign/popplerload.c:807 libvips/foreign/ppmload.c:959 #: libvips/foreign/radload.c:202 libvips/foreign/spngload.c:754 #: libvips/foreign/svgload.c:915 libvips/foreign/tiffload.c:299 #: libvips/foreign/vipsload.c:306 libvips/foreign/webpload.c:261 #: libvips/resample/thumbnail.c:1677 msgid "Source" msgstr "" #: libvips/foreign/csvload.c:655 libvips/foreign/fitsload.c:331 #: libvips/foreign/heifload.c:1405 libvips/foreign/jp2kload.c:1453 #: libvips/foreign/jpegload.c:274 libvips/foreign/jxlload.c:1345 #: libvips/foreign/matrixload.c:455 libvips/foreign/niftiload.c:785 #: libvips/foreign/nsgifload.c:901 libvips/foreign/openslideload.c:1172 #: libvips/foreign/pdfiumload.c:931 libvips/foreign/pngload.c:240 #: libvips/foreign/popplerload.c:808 libvips/foreign/ppmload.c:960 #: libvips/foreign/radload.c:203 libvips/foreign/spngload.c:755 #: libvips/foreign/svgload.c:916 libvips/foreign/tiffload.c:300 #: libvips/foreign/vipsload.c:307 libvips/foreign/webpload.c:262 #: libvips/iofuncs/sbuf.c:84 libvips/resample/thumbnail.c:1678 #, fuzzy msgid "Source to load from" msgstr "Puffer, aus dem geladen werden soll" #: libvips/foreign/csvsave.c:215 #, fuzzy msgid "save image to csv" msgstr "Bild in CSV-Datei speichern" #: libvips/foreign/csvsave.c:224 msgid "Separator characters" msgstr "Trennzeichen" #: libvips/foreign/dzsave.c:2008 #, fuzzy msgid "overlap too large" msgstr "Überlappen zu schmal" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/dzsave.c:2316 #, fuzzy msgid "save image to deep zoom format" msgstr "Bild in PPM-Datei speichern" #: libvips/foreign/dzsave.c:2326 libvips/foreign/dzsave.c:2327 #, fuzzy msgid "Image name" msgstr "Bilddateiname" #: libvips/foreign/dzsave.c:2333 msgid "Layout" msgstr "" #: libvips/foreign/dzsave.c:2334 msgid "Directory layout" msgstr "" #: libvips/foreign/dzsave.c:2340 msgid "Suffix" msgstr "" #: libvips/foreign/dzsave.c:2341 msgid "Filename suffix for tiles" msgstr "" #: libvips/foreign/dzsave.c:2347 #, fuzzy msgid "Overlap" msgstr "kein Überlappen" #: libvips/foreign/dzsave.c:2348 #, fuzzy msgid "Tile overlap in pixels" msgstr "Kachelhöhe in Bildpunkten" #: libvips/foreign/dzsave.c:2354 #, fuzzy msgid "Tile size" msgstr "Kachelbreite" #: libvips/foreign/dzsave.c:2355 #, fuzzy msgid "Tile size in pixels" msgstr "Kachelbreite in Bildpunkten" #: libvips/foreign/dzsave.c:2362 libvips/foreign/tiffsave.c:382 #, fuzzy msgid "Pyramid depth" msgstr "Pyramide" #: libvips/foreign/dzsave.c:2368 msgid "Center" msgstr "" #: libvips/foreign/dzsave.c:2369 #, fuzzy msgid "Center image in tile" msgstr "Bild in PNG-Datei speichern" #: libvips/foreign/dzsave.c:2376 msgid "Rotate image during save" msgstr "" #: libvips/foreign/dzsave.c:2382 msgid "Container" msgstr "" #: libvips/foreign/dzsave.c:2383 msgid "Pyramid container type" msgstr "" #: libvips/foreign/dzsave.c:2389 libvips/foreign/heifsave.c:784 #: libvips/foreign/pngsave.c:224 libvips/foreign/spngsave.c:700 #: libvips/foreign/tiffsave.c:260 msgid "Compression" msgstr "Komprimierung" #: libvips/foreign/dzsave.c:2390 msgid "ZIP deflate compression level" msgstr "" #: libvips/foreign/dzsave.c:2396 libvips/foreign/tiffsave.c:360 msgid "Region shrink" msgstr "" #: libvips/foreign/dzsave.c:2397 libvips/foreign/tiffsave.c:361 msgid "Method to shrink regions" msgstr "" #: libvips/foreign/dzsave.c:2403 msgid "Skip blanks" msgstr "" #: libvips/foreign/dzsave.c:2404 msgid "Skip tiles which are nearly equal to the background" msgstr "" #: libvips/foreign/dzsave.c:2410 msgid "id" msgstr "" #: libvips/foreign/dzsave.c:2411 msgid "Resource ID" msgstr "" #: libvips/foreign/dzsave.c:2417 libvips/foreign/heifsave.c:763 #: libvips/foreign/jp2ksave.c:1000 libvips/foreign/jpegsave.c:167 #: libvips/foreign/jxlsave.c:1120 libvips/foreign/tiffsave.c:268 #: libvips/foreign/webpsave.c:829 msgid "Q" msgstr "Q" #: libvips/foreign/dzsave.c:2418 libvips/foreign/heifsave.c:764 #: libvips/foreign/jp2ksave.c:1001 libvips/foreign/jpegsave.c:168 #: libvips/foreign/tiffsave.c:269 libvips/foreign/webpsave.c:830 msgid "Q factor" msgstr "Q-Faktor" #: libvips/foreign/dzsave.c:2427 msgid "No strip" msgstr "" #: libvips/foreign/dzsave.c:2428 msgid "Don't strip tile metadata" msgstr "" #: libvips/foreign/dzsave.c:2434 #, fuzzy msgid "Base name" msgstr "Bilddateiname" #: libvips/foreign/dzsave.c:2435 #, fuzzy msgid "Base name to save to" msgstr "Name der Datei in die gespeichert werden soll" #: libvips/foreign/dzsave.c:2441 #, fuzzy msgid "Directory name" msgstr "Richtung" #: libvips/foreign/dzsave.c:2442 #, fuzzy msgid "Directory name to save to" msgstr "Name der Datei in die gespeichert werden soll" #: libvips/foreign/dzsave.c:2462 libvips/foreign/tiffsave.c:353 #, fuzzy msgid "Properties" msgstr "Transaktionen" #: libvips/foreign/dzsave.c:2463 msgid "Write a properties file to the output directory" msgstr "" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/dzsave.c:2527 #, fuzzy msgid "save image to deepzoom target" msgstr "Bild in PPM-Datei speichern" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/dzsave.c:2584 #, fuzzy msgid "save image to deepzoom file" msgstr "Bild in PPM-Datei speichern" #: libvips/foreign/dzsave.c:2643 #, fuzzy msgid "save image to dz buffer" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/exif.c:199 #, fuzzy msgid "exif too small" msgstr "Ziel zu klein" #: libvips/foreign/exif.c:203 #, fuzzy msgid "exif too large" msgstr "Fenster zu groß" #: libvips/foreign/exif.c:208 #, fuzzy msgid "unable to init exif" msgstr "kann nicht gekürzt werden" #: libvips/foreign/exif.c:1496 msgid "error saving EXIF" msgstr "Fehler beim Speichern von EXIF" #: libvips/foreign/fits.c:185 libvips/foreign/matlab.c:113 #: libvips/iofuncs/vips.c:145 libvips/mosaicing/global_balance.c:1240 #: libvips/mosaicing/global_balance.c:1684 #, c-format msgid "unable to open \"%s\"" msgstr "»%s« kann nicht geöffnet werden" #: libvips/foreign/fits.c:236 msgid "no HDU found with naxes > 0" msgstr "" #: libvips/foreign/fits.c:274 msgid "dimensions above 3 must be size 1" msgstr "Dimensionen größer drei müssen die Größe eins haben" #: libvips/foreign/fits.c:289 #, c-format msgid "bad number of axis %d" msgstr "falsche Achsenanzahl %d" #: libvips/foreign/fits.c:300 #, c-format msgid "unsupported bitpix %d\n" msgstr "nicht unterstützte »bitpix« %d\n" #: libvips/foreign/fits.c:585 libvips/iofuncs/vips.c:208 #, c-format msgid "unable to write to \"%s\"" msgstr "auf »%s« kann nicht geschrieben werden" #: libvips/foreign/fits.c:726 #, c-format msgid "unsupported BandFmt %d\n" msgstr "nicht unterstütztes BandFmt %d\n" #: libvips/foreign/fitsload.c:101 libvips/foreign/niftiload.c:130 #: libvips/foreign/openslideload.c:874 msgid "no filename available" msgstr "" #: libvips/foreign/fitsload.c:181 #, fuzzy msgid "FITS loader base class" msgstr "Basisklasse" #: libvips/foreign/fitsload.c:246 msgid "load a FITS image" msgstr "ein FITS-Bild laden" #: libvips/foreign/fitsload.c:321 #, fuzzy msgid "load FITS from a source" msgstr "ein FITS-Bild laden" # http://de.wikipedia.org/wiki/Flexible_Image_Transport_System #: libvips/foreign/fitssave.c:129 msgid "save image to fits file" msgstr "Bild in FITS-Datei speichern" #: libvips/foreign/foreign.c:417 msgid "load and save image files" msgstr "Bilddateien laden und speichern" #: libvips/foreign/foreign.c:618 #, fuzzy, c-format msgid "file \"%s\" does not exist" msgstr "Datei »%s« nicht gefunden" #: libvips/foreign/foreign.c:623 #, c-format msgid "\"%s\" is a directory" msgstr "" #: libvips/foreign/foreign.c:632 libvips/foreign/foreign.c:1976 #, c-format msgid "\"%s\" is not a known file format" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/foreign/foreign.c:720 #, fuzzy msgid "buffer is not in a known format" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/foreign/foreign.c:782 #, fuzzy msgid "source is not in a known format" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/foreign/foreign.c:987 #, fuzzy msgid "images do not match between header and load" msgstr "Bilder passen in der Bildpunktgröße nicht zusammen" #: libvips/foreign/foreign.c:1218 #, fuzzy msgid "loaders" msgstr "Dateilader" #: libvips/foreign/foreign.c:1229 msgid "Flags" msgstr "Schalter" #: libvips/foreign/foreign.c:1230 msgid "Flags for this file" msgstr "Schalter für diese Datei" #: libvips/foreign/foreign.c:1236 libvips/iofuncs/target.c:316 msgid "Memory" msgstr "" #: libvips/foreign/foreign.c:1237 msgid "Force open via memory" msgstr "" #: libvips/foreign/foreign.c:1244 #, fuzzy msgid "Required access pattern for this file" msgstr "Komprimierung für diese Datei" #: libvips/foreign/foreign.c:1250 libvips/resample/thumbnail.c:1037 #, fuzzy msgid "Fail on" msgstr "scheitern" #: libvips/foreign/foreign.c:1251 libvips/resample/thumbnail.c:1038 msgid "Error level to fail on" msgstr "" #: libvips/foreign/foreign.c:1257 msgid "Revalidate" msgstr "" #: libvips/foreign/foreign.c:1258 msgid "Don't use a cached result for this operation" msgstr "" #: libvips/foreign/foreign.c:1264 msgid "Sequential" msgstr "sequenziell" #: libvips/foreign/foreign.c:1265 msgid "Sequential read only" msgstr "sequenziell nur mit Lesezugriff" #: libvips/foreign/foreign.c:1271 msgid "Fail" msgstr "scheitern" #: libvips/foreign/foreign.c:1272 msgid "Fail on first warning" msgstr "scheitert bei erster Warnung" #: libvips/foreign/foreign.c:1278 msgid "Disc" msgstr "Platte" #: libvips/foreign/foreign.c:1279 msgid "Open to disc" msgstr "offen zur Platte" #: libvips/foreign/foreign.c:1520 msgid "saver does not support any output type" msgstr "" #: libvips/foreign/foreign.c:1845 #, fuzzy msgid "savers" msgstr "Dateispeicherer" #: libvips/foreign/foreign.c:1867 msgid "Image to save" msgstr "zu speicherndes Bild" #: libvips/foreign/foreign.c:1872 msgid "Keep" msgstr "" #: libvips/foreign/foreign.c:1873 msgid "Which metadata to retain" msgstr "" #: libvips/foreign/foreign.c:1888 msgid "Set page height for multipage save" msgstr "" #: libvips/foreign/foreign.c:1895 #, fuzzy msgid "Filename of ICC profile to embed" msgstr "einzubettendes ICC-Profil" #: libvips/foreign/foreign.c:1901 msgid "Strip" msgstr "" #: libvips/foreign/foreign.c:1902 #, fuzzy msgid "Strip all metadata from image" msgstr "einen Bereich eines Bildes extrahieren" #: libvips/foreign/foreign.c:2132 #, fuzzy, c-format msgid "\"%s\" is not a known target format" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/foreign/foreign.c:2191 #, fuzzy, c-format msgid "\"%s\" is not a known buffer format" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/foreign/heifload.c:821 libvips/foreign/jxlload.c:747 #: libvips/foreign/nsgifload.c:448 libvips/foreign/webp2vips.c:501 #, fuzzy msgid "bad page number" msgstr "falsche Seitennummer %d" #: libvips/foreign/heifload.c:873 msgid "undefined bits per pixel" msgstr "" #: libvips/foreign/heifload.c:885 msgid "not all pages are the same size" msgstr "" #: libvips/foreign/heifload.c:982 #, fuzzy msgid "bad image dimensions on decode" msgstr "Überlaufganzzahl der Bildabmessungen" #: libvips/foreign/heifload.c:989 #, fuzzy msgid "unable to get image data" msgstr "Dateistatus kann nicht abgefragt werden" #: libvips/foreign/heifload.c:1074 #, fuzzy msgid "load a HEIF image" msgstr "ein FITS-Bild laden" #: libvips/foreign/heifload.c:1082 libvips/foreign/jp2kload.c:1234 #: libvips/foreign/jxlload.c:1126 libvips/foreign/magick6load.c:302 #: libvips/foreign/magick7load.c:379 libvips/foreign/nsgifload.c:620 #: libvips/foreign/pdfiumload.c:693 libvips/foreign/popplerload.c:543 #: libvips/foreign/tiffload.c:196 libvips/foreign/webpload.c:176 msgid "Page" msgstr "Seite" #: libvips/foreign/heifload.c:1083 libvips/foreign/jxlload.c:1127 #: libvips/foreign/magick6load.c:303 libvips/foreign/magick7load.c:380 #: libvips/foreign/nsgifload.c:621 libvips/foreign/pdfiumload.c:694 #: libvips/foreign/popplerload.c:544 libvips/foreign/tiffload.c:197 #: libvips/foreign/webpload.c:177 #, fuzzy msgid "First page to load" msgstr "Name der Datei, aus der geladen werden soll" #: libvips/foreign/heifload.c:1090 libvips/foreign/jxlload.c:1134 #: libvips/foreign/magick6load.c:310 libvips/foreign/magick7load.c:387 #: libvips/foreign/nsgifload.c:628 libvips/foreign/pdfiumload.c:701 #: libvips/foreign/popplerload.c:551 libvips/foreign/tiffload.c:204 #: libvips/foreign/webpload.c:184 #, fuzzy msgid "Number of pages to load, -1 for all" msgstr "Anzahl der Patches ein Diagramm hinunter" #: libvips/foreign/heifload.c:1096 msgid "Thumbnail" msgstr "" #: libvips/foreign/heifload.c:1097 #, fuzzy msgid "Fetch thumbnail image" msgstr "Miniaturansicht auf GRÖẞE setzen" #: libvips/foreign/heifload.c:1103 libvips/foreign/jpegload.c:196 #: libvips/foreign/tiffload.c:210 msgid "Autorotate" msgstr "" #: libvips/foreign/heifload.c:1104 libvips/foreign/jpegload.c:197 msgid "Rotate image using exif orientation" msgstr "" #: libvips/foreign/heifload.c:1111 libvips/foreign/jpegload.c:204 #: libvips/foreign/pngload.c:171 libvips/foreign/spngload.c:678 #: libvips/foreign/svgload.c:797 libvips/foreign/tiffload.c:225 msgid "Unlimited" msgstr "" #: libvips/foreign/heifload.c:1112 libvips/foreign/jpegload.c:205 #: libvips/foreign/pngload.c:172 libvips/foreign/spngload.c:679 #: libvips/foreign/tiffload.c:226 msgid "Remove all denial of service limits" msgstr "" #: libvips/foreign/heifload.c:1334 libvips/foreign/jp2kload.c:1393 #: libvips/foreign/jpegload.c:420 libvips/foreign/jxlload.c:1284 #: libvips/foreign/magick6load.c:1066 libvips/foreign/magick7load.c:931 #: libvips/foreign/nsgifload.c:838 libvips/foreign/pdfiumload.c:871 #: libvips/foreign/pngload.c:387 libvips/foreign/popplerload.c:748 #: libvips/foreign/ppmload.c:901 libvips/foreign/radload.c:350 #: libvips/foreign/spngload.c:904 libvips/foreign/svgload.c:1077 #: libvips/foreign/tiffload.c:452 libvips/foreign/webpload.c:414 #: libvips/resample/thumbnail.c:1464 msgid "Buffer to load from" msgstr "Puffer, aus dem geladen werden soll" #: libvips/foreign/heifsave.c:430 #, fuzzy msgid "unimplemented format conversion" msgstr "nicht implementierte Maske" #: libvips/foreign/heifsave.c:540 #, fuzzy, c-format msgid "%d-bit colour depth not supported" msgstr "%d-dimensionale Bilder nicht unterstützt" #: libvips/foreign/heifsave.c:573 #, fuzzy msgid "Unsupported compression" msgstr "nicht unterstützter Farbtyp" #: libvips/foreign/heifsave.c:755 #, fuzzy msgid "save image in HEIF format" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/heifsave.c:777 libvips/foreign/jp2ksave.c:985 #: libvips/foreign/jxlsave.c:1113 libvips/foreign/tiffsave.c:374 #: libvips/foreign/webpsave.c:836 msgid "Lossless" msgstr "" #: libvips/foreign/heifsave.c:778 libvips/foreign/jp2ksave.c:986 #: libvips/foreign/jxlsave.c:1114 libvips/foreign/webpsave.c:837 msgid "Enable lossless compression" msgstr "" #: libvips/foreign/heifsave.c:785 #, fuzzy msgid "Compression format" msgstr "Komprimierungsfaktor" #: libvips/foreign/heifsave.c:793 libvips/foreign/heifsave.c:808 msgid "CPU effort" msgstr "" #: libvips/foreign/heifsave.c:799 libvips/foreign/jp2ksave.c:992 #: libvips/foreign/jpegsave.c:223 #, fuzzy msgid "Subsample mode" msgstr "Öffnen-Modus" #: libvips/foreign/heifsave.c:800 libvips/foreign/jp2ksave.c:993 #: libvips/foreign/jpegsave.c:224 msgid "Select chroma subsample operation mode" msgstr "" #: libvips/foreign/heifsave.c:807 msgid "Speed" msgstr "" #: libvips/foreign/heifsave.c:814 msgid "Encoder" msgstr "" #: libvips/foreign/heifsave.c:815 msgid "Select encoder to use" msgstr "" #: libvips/foreign/heifsave.c:1030 #, fuzzy msgid "save image in AVIF format" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/jp2kload.c:239 #, fuzzy msgid "unable to create jp2k stream" msgstr "Thread kann nicht erstellt werden" #: libvips/foreign/jp2kload.c:555 #, fuzzy, c-format msgid "unsupported colourspace %d" msgstr "nicht unterstützter Farbraum %d" #: libvips/foreign/jp2kload.c:604 #, fuzzy msgid "too many image bands" msgstr "zu viele Argumente" #: libvips/foreign/jp2kload.c:608 #, fuzzy msgid "no image components" msgstr "keine Bilddaten" #: libvips/foreign/jp2kload.c:625 msgid "components differ in geometry" msgstr "" #: libvips/foreign/jp2kload.c:632 msgid "components differ in precision" msgstr "" #: libvips/foreign/jp2kload.c:1003 libvips/foreign/jp2kload.c:1100 #, fuzzy msgid "decoded image does not match container" msgstr "»ink«-Bild passt nicht in das Bild" #: libvips/foreign/jp2kload.c:1222 #, fuzzy msgid "load JPEG2000 image" msgstr "ein FITS-Bild laden" #: libvips/foreign/jp2kload.c:1235 #, fuzzy msgid "Load this page from the image" msgstr "diese Seite aus der Datei laden" #: libvips/foreign/jp2kload.c:1241 msgid "One-shot" msgstr "" #: libvips/foreign/jp2kload.c:1242 #, fuzzy msgid "Load images a frame at a time" msgstr "diese Seite aus der Datei laden" #: libvips/foreign/jp2kload.c:1604 libvips/foreign/jp2ksave.c:1428 #, fuzzy msgid "libvips built without JPEG2000 support" msgstr "VIPS wurde ohne FFT-Unterstützung konfiguriert" #: libvips/foreign/jp2ksave.c:818 #, fuzzy msgid "not an integer format" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/foreign/jp2ksave.c:963 msgid "save image in JPEG2000 format" msgstr "" #: libvips/foreign/jpeg2vips.c:886 libvips/foreign/spngload.c:529 #: libvips/foreign/vipspng.c:723 #, c-format msgid "out of order read at line %d" msgstr "" #: libvips/foreign/jpegload.c:116 #, c-format msgid "bad shrink factor %d" msgstr "falscher Schrumpffaktor %d" #: libvips/foreign/jpegload.c:175 msgid "load jpeg" msgstr "JPEG laden" #: libvips/foreign/jpegload.c:189 libvips/foreign/webpload.c:197 msgid "Shrink" msgstr "verkleinern" #: libvips/foreign/jpegload.c:190 libvips/foreign/webpload.c:198 msgid "Shrink factor on load" msgstr "falscher Verkleinerungsfaktor %d" #: libvips/foreign/jpegload.c:265 #, fuzzy msgid "load image from jpeg source" msgstr "Bild in den JPEG-Puffer speichern" #: libvips/foreign/jpegload.c:338 msgid "load jpeg from file" msgstr "JPEG aus Datei laden" #: libvips/foreign/jpegload.c:413 msgid "load jpeg from buffer" msgstr "JPEG aus Puffer laden" #: libvips/foreign/jpegsave.c:153 msgid "save jpeg" msgstr "JPEG speichern" #: libvips/foreign/jpegsave.c:174 #, fuzzy msgid "Optimize coding" msgstr "Bildpunktkodierung" #: libvips/foreign/jpegsave.c:175 msgid "Compute optimal Huffman coding tables" msgstr "" #: libvips/foreign/jpegsave.c:181 libvips/foreign/pngsave.c:231 #: libvips/foreign/spngsave.c:707 msgid "Interlace" msgstr "Zeilensprung" #: libvips/foreign/jpegsave.c:182 msgid "Generate an interlaced (progressive) jpeg" msgstr "" #: libvips/foreign/jpegsave.c:188 msgid "No subsample" msgstr "" #: libvips/foreign/jpegsave.c:189 msgid "Disable chroma subsample" msgstr "" #: libvips/foreign/jpegsave.c:195 msgid "Trellis quantisation" msgstr "" #: libvips/foreign/jpegsave.c:196 msgid "Apply trellis quantisation to each 8x8 block" msgstr "" #: libvips/foreign/jpegsave.c:202 msgid "Overshoot de-ringing" msgstr "" #: libvips/foreign/jpegsave.c:203 msgid "Apply overshooting to samples with extreme values" msgstr "" #: libvips/foreign/jpegsave.c:209 msgid "Optimize scans" msgstr "" #: libvips/foreign/jpegsave.c:210 msgid "Split spectrum of DCT coefficients into separate scans" msgstr "" #: libvips/foreign/jpegsave.c:216 msgid "Quantization table" msgstr "" #: libvips/foreign/jpegsave.c:217 msgid "Use predefined quantization table with given index" msgstr "" #: libvips/foreign/jpegsave.c:231 msgid "Restart interval" msgstr "" #: libvips/foreign/jpegsave.c:232 msgid "Add restart markers every specified number of mcu" msgstr "" #: libvips/foreign/jpegsave.c:291 #, fuzzy msgid "save image to jpeg target" msgstr "Bild in JPEG-Datei speichern" #: libvips/foreign/jpegsave.c:360 msgid "save image to jpeg file" msgstr "Bild in JPEG-Datei speichern" #: libvips/foreign/jpegsave.c:438 msgid "save image to jpeg buffer" msgstr "Bild in den JPEG-Puffer speichern" # http://de.wikipedia.org/wiki/MIME#image #: libvips/foreign/jpegsave.c:514 msgid "save image to jpeg mime" msgstr "Bild in JPEG-MIME speichern" #: libvips/foreign/jxlload.c:247 libvips/foreign/jxlsave.c:644 #: libvips/iofuncs/dbuf.c:81 libvips/iofuncs/util.c:759 msgid "out of memory" msgstr "Hauptspeicher reicht nicht aus" #: libvips/foreign/jxlload.c:572 #, fuzzy msgid "bad buffer size" msgstr "falsche Größe" #: libvips/foreign/jxlload.c:598 libvips/foreign/webp2vips.c:724 msgid "not enough frames" msgstr "" #: libvips/foreign/jxlload.c:677 libvips/foreign/radiance.c:706 #, fuzzy msgid "image size out of bounds" msgstr "Bild muss ein Band haben" #: libvips/foreign/jxlload.c:1113 #, fuzzy msgid "load JPEG-XL image" msgstr "ein OpenEXR-Bild laden" #: libvips/foreign/jxlsave.c:1078 msgid "save image in JPEG-XL format" msgstr "" #: libvips/foreign/jxlsave.c:1092 msgid "Tier" msgstr "" #: libvips/foreign/jxlsave.c:1093 msgid "Decode speed tier" msgstr "" #: libvips/foreign/jxlsave.c:1099 libvips/morphology/nearest.c:315 msgid "Distance" msgstr "" #: libvips/foreign/jxlsave.c:1100 msgid "Target butteraugli distance" msgstr "" #: libvips/foreign/jxlsave.c:1107 msgid "Encoding effort" msgstr "" #: libvips/foreign/jxlsave.c:1121 #, fuzzy msgid "Quality factor" msgstr "Q-Faktor" #: libvips/foreign/magick6load.c:273 #, fuzzy msgid "load with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/magick6load.c:295 libvips/foreign/magick7load.c:372 msgid "Density" msgstr "" #: libvips/foreign/magick6load.c:296 libvips/foreign/magick7load.c:373 msgid "Canvas resolution for rendering vector formats like SVG" msgstr "" #: libvips/foreign/magick6load.c:316 libvips/foreign/magick7load.c:393 msgid "All frames" msgstr "" #: libvips/foreign/magick6load.c:317 libvips/foreign/magick7load.c:394 #, fuzzy msgid "Read all frames from an image" msgstr "einen Bereich eines Bildes extrahieren" #: libvips/foreign/magick6load.c:365 #, c-format msgid "unsupported image type %d" msgstr "nicht unterstützter Bildtyp %d" #: libvips/foreign/magick6load.c:414 libvips/foreign/magick7load.c:469 #, c-format msgid "bad image dimensions %d x %d pixels, %d bands" msgstr "" #: libvips/foreign/magick6load.c:444 #, c-format msgid "unsupported bit depth %d" msgstr "nicht unterstützte Bit-Tiefe %d" #: libvips/foreign/magick6load.c:852 libvips/foreign/webp2vips.c:638 msgid "unable to read pixels" msgstr "Bildpunkte können nicht gelesen werden" #: libvips/foreign/magick6load.c:947 #, fuzzy, c-format msgid "unable to read file \"%s\"" msgstr "Profil kann nicht gelesen werden" #: libvips/foreign/magick6load.c:971 msgid "load file with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/magick6load.c:1037 #, fuzzy msgid "unable to read buffer" msgstr "In den Puffer kann nicht geschrieben werden." #: libvips/foreign/magick6load.c:1059 #, fuzzy msgid "load buffer with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/magick7load.c:350 #, fuzzy msgid "load with ImageMagick7" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/magick7load.c:412 #, c-format msgid "Magick: %s %s" msgstr "" #: libvips/foreign/magick7load.c:489 #, fuzzy, c-format msgid "unsupported bit depth %zd" msgstr "nicht unterstützte Bit-Tiefe %d" #: libvips/foreign/magick7load.c:843 #, fuzzy msgid "load file with ImageMagick7" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/magick7load.c:924 #, fuzzy msgid "load buffer with ImageMagick7" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/magick.c:804 #, fuzzy, c-format msgid "libMagick error: %s %s" msgstr "" "Datei »%s« kann nicht gelesen werden\n" "libMagick-Fehler: %s %s" #: libvips/foreign/magick.c:807 #, fuzzy, c-format msgid "libMagick error: %s" msgstr "EXR-Fehler: %s" #: libvips/foreign/magick.c:810 msgid "libMagick error:" msgstr "" #: libvips/foreign/matlab.c:121 #, c-format msgid "no matrix variables in \"%s\"" msgstr "keine Matrixvariablen in »%s«" #: libvips/foreign/matlab.c:203 #, c-format msgid "unsupported rank %d\n" msgstr "nicht unterstützte Rangstufe %d\n" #: libvips/foreign/matlab.c:211 #, c-format msgid "unsupported class type %d\n" msgstr "nicht unterstützter Klassentyp %d\n" #: libvips/foreign/matlab.c:265 msgid "Mat_VarReadDataAll failed" msgstr "»Mat_VarReadDataAll« fehlgeschlagen" # http://www.dateiendung.com/format/mat #: libvips/foreign/matload.c:122 msgid "load mat from file" msgstr "Mat aus Datei laden" #: libvips/foreign/matrixload.c:128 libvips/foreign/matrixload.c:241 #, fuzzy, c-format msgid "bad number \"%s\"" msgstr "falscher Modus »%s«" #: libvips/foreign/matrixload.c:137 msgid "no width / height" msgstr "" #: libvips/foreign/matrixload.c:143 msgid "width / height not int" msgstr "" #: libvips/foreign/matrixload.c:155 #, fuzzy msgid "width / height out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/foreign/matrixload.c:159 msgid "zero scale" msgstr "" #: libvips/foreign/matrixload.c:250 #, c-format msgid "line %d too short" msgstr "" # http://www.dateiendung.com/format/mat #: libvips/foreign/matrixload.c:272 #, fuzzy msgid "load matrix" msgstr "Mat aus Datei laden" # http://de.wikipedia.org/wiki/Rohdatenformat_(Fotografie) #: libvips/foreign/matrixsave.c:175 #, fuzzy msgid "save image to matrix" msgstr "Bild in Rohdatenformatdatei speichern" #: libvips/foreign/matrixsave.c:321 #, fuzzy msgid "print matrix" msgstr "falsche Eingabematrix" #: libvips/foreign/niftiload.c:404 #, fuzzy msgid "invalid dimension" msgstr "falsche Abmessungen" #: libvips/foreign/niftiload.c:415 #, fuzzy msgid "invalid resolution" msgstr "ungültiges Argument" #: libvips/foreign/niftiload.c:429 libvips/foreign/niftiload.c:433 #: libvips/foreign/niftisave.c:309 #, fuzzy msgid "dimension overflow" msgstr "Überlaufganzzahl der Bildabmessungen" #: libvips/foreign/niftiload.c:534 #, fuzzy msgid "unable to read NIFTI header" msgstr "Kopfdaten für »%s« können nicht gelesen werden" #: libvips/foreign/niftiload.c:562 #, fuzzy msgid "unable to load NIFTI file" msgstr "Profil kann nicht gelesen werden" #: libvips/foreign/niftiload.c:592 #, fuzzy msgid "load a NIFTI image" msgstr "ein FITS-Bild laden" #: libvips/foreign/niftiload.c:700 msgid "load NIfTI volume" msgstr "" #: libvips/foreign/niftiload.c:775 msgid "load NIfTI volumes" msgstr "" #: libvips/foreign/niftisave.c:115 libvips/foreign/niftisave.c:322 #, fuzzy msgid "unsupported libvips image type" msgstr "nicht unterstützter Bildtyp %d" #: libvips/foreign/niftisave.c:122 #, fuzzy msgid "8-bit colour images only" msgstr "nur skalare Bilder" #: libvips/foreign/niftisave.c:132 #, fuzzy msgid "3 or 4 band colour images only" msgstr "nur RGB-TIFF mit drei oder vier Bändern" #: libvips/foreign/niftisave.c:251 msgid "bad nifti-ext- field name" msgstr "" #: libvips/foreign/niftisave.c:260 #, fuzzy msgid "unable to attach nifti ext" msgstr "Dateistatus kann nicht abgefragt werden" #: libvips/foreign/niftisave.c:315 libvips/foreign/nsgifload.c:644 #: libvips/foreign/webp2vips.c:550 #, fuzzy msgid "bad image dimensions" msgstr "falsche Abmessungen" #: libvips/foreign/niftisave.c:375 #, fuzzy msgid "unable to set nifti filename" msgstr "Dateistatus kann nicht abgefragt werden" # http://de.wikipedia.org/wiki/Flexible_Image_Transport_System #: libvips/foreign/niftisave.c:427 #, fuzzy msgid "save image to nifti file" msgstr "Bild in FITS-Datei speichern" #: libvips/foreign/nsgifload.c:420 msgid "no frames in GIF" msgstr "" #: libvips/foreign/nsgifload.c:463 #, fuzzy msgid "bad frame" msgstr "falscher Parameter" #: libvips/foreign/nsgifload.c:607 libvips/foreign/nsgifload.c:754 #: libvips/foreign/nsgifload.c:831 msgid "load GIF with libnsgif" msgstr "" #: libvips/foreign/nsgifload.c:892 #, fuzzy msgid "load gif from source" msgstr "TIFF aus Datei laden" #: libvips/foreign/openexr2vips.c:122 #, c-format msgid "EXR error: %s" msgstr "EXR-Fehler: %s" #: libvips/foreign/openexrload.c:129 msgid "load an OpenEXR image" msgstr "ein OpenEXR-Bild laden" #: libvips/foreign/openslideload.c:186 msgid "invalid associated image name" msgstr "ungültiger zugehöriger Bildname" #: libvips/foreign/openslideload.c:229 msgid "specify only one of level and associated image" msgstr "" #: libvips/foreign/openslideload.c:236 msgid "specify only one of attach_assicated and associated image" msgstr "" #: libvips/foreign/openslideload.c:353 libvips/foreign/openslideload.c:462 #: libvips/foreign/openslideload.c:613 #, fuzzy, c-format msgid "opening slide: %s" msgstr "Fehler beim Öffnen des Dias" #: libvips/foreign/openslideload.c:373 #, c-format msgid "reading associated image: %s" msgstr "zugehöriges Bild wird gelesen: %s" #: libvips/foreign/openslideload.c:457 #, fuzzy msgid "unsupported slide format" msgstr "nicht unterstützte Bit-Tiefe" #: libvips/foreign/openslideload.c:468 msgid "invalid slide level" msgstr "ungültige Diastufe" #: libvips/foreign/openslideload.c:554 #, c-format msgid "getting dimensions: %s" msgstr "Abfragen der Abmessungen: %s" #: libvips/foreign/openslideload.c:560 msgid "image dimensions overflow int" msgstr "Überlaufganzzahl der Bildabmessungen" #: libvips/foreign/openslideload.c:708 #, c-format msgid "reading region: %s" msgstr "Region wird gelesen: %s" #: libvips/foreign/openslideload.c:973 msgid "load OpenSlide base class" msgstr "" #: libvips/foreign/openslideload.c:996 libvips/foreign/tiffsave.c:367 msgid "Level" msgstr "Ebene" #: libvips/foreign/openslideload.c:997 msgid "Load this level from the file" msgstr "diese Ebene aus der Datei laden" #: libvips/foreign/openslideload.c:1003 msgid "Autocrop" msgstr "" #: libvips/foreign/openslideload.c:1004 #, fuzzy msgid "Crop to image bounds" msgstr "Transaktionen für Bänder von Bildern" #: libvips/foreign/openslideload.c:1010 msgid "Associated" msgstr "dazugehörig" #: libvips/foreign/openslideload.c:1011 msgid "Load this associated image" msgstr "dieses zugehörige Bild laden" #: libvips/foreign/openslideload.c:1017 #, fuzzy msgid "Attach associated" msgstr "dazugehörig" #: libvips/foreign/openslideload.c:1018 #, fuzzy msgid "Attach all associated images" msgstr "dieses zugehörige Bild laden" #: libvips/foreign/openslideload.c:1024 #, fuzzy msgid "RGB" msgstr "GB" #: libvips/foreign/openslideload.c:1025 msgid "Output RGB (not RGBA)" msgstr "" #: libvips/foreign/openslideload.c:1089 msgid "load file with OpenSlide" msgstr "Datei mit OpenSlide laden" #: libvips/foreign/openslideload.c:1164 #, fuzzy msgid "load source with OpenSlide" msgstr "Datei mit OpenSlide laden" #: libvips/foreign/pdfiumload.c:196 #, fuzzy msgid "unknown error" msgstr "Unix-Fehler" #: libvips/foreign/pdfiumload.c:291 #, c-format msgid "%s: too large for pdfium" msgstr "" #: libvips/foreign/pdfiumload.c:307 #, fuzzy, c-format msgid "%s: unable to load" msgstr "»fd« kann nicht geschlossen werden" #: libvips/foreign/pdfiumload.c:318 #, c-format msgid "%s: unable to initialize form fill environment" msgstr "" #: libvips/foreign/pdfiumload.c:364 libvips/foreign/popplerload.c:237 #, fuzzy, c-format msgid "unable to load page %d" msgstr "»fd« kann nicht geschlossen werden" #: libvips/foreign/pdfiumload.c:476 libvips/foreign/popplerload.c:331 #, fuzzy msgid "pages out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/foreign/pdfiumload.c:511 #, fuzzy msgid "page size out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/foreign/pdfiumload.c:683 msgid "load PDF with PDFium" msgstr "" #: libvips/foreign/pdfiumload.c:715 libvips/foreign/popplerload.c:565 #: libvips/foreign/webpload.c:191 msgid "Factor to scale by" msgstr "" #: libvips/foreign/pdfiumload.c:722 libvips/foreign/popplerload.c:572 #, fuzzy msgid "Background colour" msgstr "Hintergrund" #: libvips/foreign/pdfiumload.c:728 libvips/foreign/popplerload.c:578 msgid "Password" msgstr "" #: libvips/foreign/pdfiumload.c:729 libvips/foreign/popplerload.c:579 msgid "Password to decrypt with" msgstr "" # Portable Pixmap #: libvips/foreign/pdfiumload.c:801 libvips/foreign/popplerload.c:678 #, fuzzy msgid "load PDF from file" msgstr "PPM aus Datei laden" #: libvips/foreign/pdfiumload.c:864 libvips/foreign/popplerload.c:741 #, fuzzy msgid "load PDF from buffer" msgstr "JPEG aus Puffer laden" #: libvips/foreign/pdfiumload.c:922 libvips/foreign/popplerload.c:799 #, fuzzy msgid "load PDF from source" msgstr "JPEG aus Puffer laden" #: libvips/foreign/pngload.c:157 libvips/foreign/spngload.c:664 #, fuzzy msgid "load png base class" msgstr "Basisklasse" #: libvips/foreign/pngload.c:231 libvips/foreign/spngload.c:746 #, fuzzy msgid "load png from source" msgstr "PNG-Datei aus Datei laden" #: libvips/foreign/pngload.c:305 libvips/foreign/spngload.c:822 msgid "load png from file" msgstr "PNG-Datei aus Datei laden" #: libvips/foreign/pngload.c:380 libvips/foreign/spngload.c:897 #, fuzzy msgid "load png from buffer" msgstr "JPEG aus Puffer laden" #: libvips/foreign/pngsave.c:212 msgid "save png" msgstr "PNG speichern" #: libvips/foreign/pngsave.c:225 libvips/foreign/spngsave.c:701 msgid "Compression factor" msgstr "Komprimierungsfaktor" #: libvips/foreign/pngsave.c:232 libvips/foreign/spngsave.c:708 msgid "Interlace image" msgstr "Zeilensprungbild" #: libvips/foreign/pngsave.c:238 libvips/foreign/spngsave.c:714 msgid "Filter" msgstr "" #: libvips/foreign/pngsave.c:239 msgid "libpng row filter flag(s)" msgstr "" #: libvips/foreign/pngsave.c:246 libvips/foreign/spngsave.c:722 msgid "Palette" msgstr "" #: libvips/foreign/pngsave.c:247 libvips/foreign/spngsave.c:723 msgid "Quantise to 8bpp palette" msgstr "" #: libvips/foreign/pngsave.c:253 libvips/foreign/spngsave.c:729 #: libvips/foreign/vips2magick.c:489 msgid "Quality" msgstr "" #: libvips/foreign/pngsave.c:254 libvips/foreign/spngsave.c:730 msgid "Quantisation quality" msgstr "" #: libvips/foreign/pngsave.c:268 libvips/foreign/spngsave.c:744 msgid "Write as a 1, 2, 4, 8 or 16 bit image" msgstr "" #: libvips/foreign/pngsave.c:275 libvips/foreign/spngsave.c:751 msgid "Quantisation CPU effort" msgstr "" #: libvips/foreign/pngsave.c:281 libvips/foreign/spngsave.c:757 msgid "Colours" msgstr "" #: libvips/foreign/pngsave.c:282 libvips/foreign/spngsave.c:758 #, fuzzy msgid "Max number of palette colours" msgstr "maximale Anzahl von Kacheln, die zwischengespeichert werden soll" # http://de.wikipedia.org/wiki/Rohdatenformat_(Fotografie) #: libvips/foreign/pngsave.c:332 libvips/foreign/spngsave.c:809 #, fuzzy msgid "save image to target as PNG" msgstr "Bild in Rohdatenformatdatei speichern" #: libvips/foreign/pngsave.c:382 msgid "save image to png file" msgstr "Bild in PNG-Datei speichern" #: libvips/foreign/pngsave.c:441 msgid "save image to png buffer" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/popplerload.c:529 msgid "load PDF with libpoppler" msgstr "" #: libvips/foreign/ppmload.c:264 msgid "bad magic number" msgstr "falsche magische Zahl" #: libvips/foreign/ppmload.c:521 #, fuzzy msgid "file truncated" msgstr "Datei wurde gekürzt" #: libvips/foreign/ppmload.c:746 #, fuzzy msgid "load ppm base class" msgstr "Basisklasse" # Portable Pixmap #: libvips/foreign/ppmload.c:821 msgid "load ppm from file" msgstr "PPM aus Datei laden" #: libvips/foreign/ppmload.c:894 #, fuzzy msgid "load ppm from buffer" msgstr "JPEG aus Puffer laden" #: libvips/foreign/ppmload.c:951 #, fuzzy msgid "load ppm from source" msgstr "PNG-Datei aus Datei laden" #: libvips/foreign/ppmsave.c:308 #, fuzzy msgid "too few bands for format" msgstr "unbekanntes Bandformat %d" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/ppmsave.c:485 #, fuzzy msgid "save to ppm" msgstr "Bild in PPM-Datei speichern" #: libvips/foreign/ppmsave.c:493 libvips/foreign/vips2magick.c:483 #, fuzzy msgid "Format to save in" msgstr "Format, in das umgewandelt werden soll" #: libvips/foreign/ppmsave.c:500 msgid "ASCII" msgstr "ASCII" #: libvips/foreign/ppmsave.c:501 #, fuzzy msgid "Save as ascii" msgstr "Bild als ASCII speichern" #: libvips/foreign/ppmsave.c:508 msgid "Set to 1 to write as a 1 bit image" msgstr "" #: libvips/foreign/ppmsave.c:514 libvips/foreign/tiffsave.c:409 msgid "Squash" msgstr "quetschen" #: libvips/foreign/ppmsave.c:515 msgid "Save as one bit" msgstr "" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/ppmsave.c:572 msgid "save image to ppm file" msgstr "Bild in PPM-Datei speichern" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/ppmsave.c:661 #, fuzzy msgid "save image in pbm format" msgstr "Bild in PPM-Datei speichern" #: libvips/foreign/ppmsave.c:693 #, fuzzy msgid "save image in pgm format" msgstr "Bild in den PNG-Puffer speichern" # http://de.wikipedia.org/wiki/Portable_Pixmap #: libvips/foreign/ppmsave.c:725 #, fuzzy msgid "save image in pfm format" msgstr "Bild in PPM-Datei speichern" #: libvips/foreign/ppmsave.c:757 #, fuzzy msgid "save image in pnm format" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/quantise.c:469 msgid "libvips not built with quantisation support" msgstr "" #: libvips/foreign/radiance.c:438 msgid "scanline length mismatch" msgstr "" #: libvips/foreign/radiance.c:455 msgid "overrun" msgstr "" # http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html #: libvips/foreign/radiance.c:689 msgid "error reading radiance header" msgstr "Fehler beim Lesen der Radiance-Kopfzeilen" #: libvips/foreign/radiance.c:776 #, fuzzy, c-format msgid "read error line %d" msgstr "Lesefehler" #: libvips/foreign/radload.c:125 #, fuzzy msgid "load rad base class" msgstr "Basisklasse" # http://www.dateiendung.com/format/mat #: libvips/foreign/radload.c:194 #, fuzzy msgid "load rad from source" msgstr "Mat aus Datei laden" #: libvips/foreign/radload.c:268 msgid "load a Radiance image from a file" msgstr "ein Radiance-Bild aus einer Datei laden" #: libvips/foreign/radload.c:343 #, fuzzy msgid "load rad from buffer" msgstr "JPEG aus Puffer laden" #: libvips/foreign/radsave.c:92 #, fuzzy msgid "save Radiance" msgstr "Bild in Radiance-Datei speichern" #: libvips/foreign/radsave.c:151 msgid "save image to Radiance file" msgstr "Bild in Radiance-Datei speichern" #: libvips/foreign/radsave.c:204 #, fuzzy msgid "save image to Radiance target" msgstr "Bild in Radiance-Datei speichern" #: libvips/foreign/radsave.c:270 #, fuzzy msgid "save image to Radiance buffer" msgstr "Bild in Radiance-Datei speichern" #: libvips/foreign/rawload.c:131 msgid "load raw data from a file" msgstr "Rohdaten aus einer Datei laden" #: libvips/foreign/rawload.c:167 libvips/iofuncs/image.c:1185 msgid "Size of header" msgstr "Größe der Kopfdaten" #: libvips/foreign/rawload.c:168 libvips/iofuncs/image.c:1186 msgid "Offset in bytes from start of file" msgstr "Versatz in Byte vom Anfang der Datei" # http://de.wikipedia.org/wiki/Rohdatenformat_(Fotografie) #: libvips/foreign/rawsave.c:138 #, fuzzy msgid "save image to raw" msgstr "Bild in Rohdatenformatdatei speichern" # http://de.wikipedia.org/wiki/Rohdatenformat_(Fotografie) #: libvips/foreign/rawsave.c:190 msgid "save image to raw file" msgstr "Bild in Rohdatenformatdatei speichern" #: libvips/foreign/rawsave.c:246 #, fuzzy msgid "write raw image to target" msgstr "Rohdatenbild in Datei-Deskriptor schreiben" #: libvips/foreign/rawsave.c:308 #, fuzzy msgid "write raw image to buffer" msgstr "Rohdatenbild in Datei-Deskriptor schreiben" #: libvips/foreign/spngload.c:403 #, fuzzy msgid "unknown color type" msgstr "unbekannter Kodierungstyp" #: libvips/foreign/spngload.c:562 #, fuzzy msgid "libspng read error" msgstr "Lesefehler" #: libvips/foreign/spngsave.c:164 libvips/foreign/vipspng.c:1013 #, fuzzy msgid "bad png comment key" msgstr "falsche Gittergeometrie" #: libvips/foreign/spngsave.c:688 #, fuzzy msgid "save spng" msgstr "PNG speichern" #: libvips/foreign/spngsave.c:715 msgid "libspng row filter flag(s)" msgstr "" # http://de.wikipedia.org/wiki/Rohdatenformat_(Fotografie) #: libvips/foreign/spngsave.c:859 #, fuzzy msgid "save image to file as PNG" msgstr "Bild in Rohdatenformatdatei speichern" #: libvips/foreign/spngsave.c:919 #, fuzzy msgid "save image to buffer as PNG" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/svgload.c:680 libvips/foreign/svgload.c:698 msgid "SVG rendering failed" msgstr "" #: libvips/foreign/svgload.c:764 msgid "load SVG with rsvg" msgstr "" #: libvips/foreign/svgload.c:783 msgid "Render at this DPI" msgstr "" #: libvips/foreign/svgload.c:790 msgid "Scale output by this factor" msgstr "" #: libvips/foreign/svgload.c:798 msgid "Allow SVG of any size" msgstr "" #: libvips/foreign/svgload.c:805 msgid "Stylesheet" msgstr "" #: libvips/foreign/svgload.c:806 msgid "Custom CSS" msgstr "" #: libvips/foreign/svgload.c:812 msgid "High bitdepth" msgstr "" #: libvips/foreign/svgload.c:813 msgid "Enable scRGB 128-bit output (32-bit per channel)" msgstr "" #: libvips/foreign/svgload.c:906 #, fuzzy msgid "load svg from source" msgstr "CSV aus Datei laden" #: libvips/foreign/tiff2vips.c:470 libvips/foreign/tiff2vips.c:488 #, c-format msgid "required field %d missing" msgstr "benötigtes Feld %d fehlt" #: libvips/foreign/tiff2vips.c:530 msgid "unknown resolution unit" msgstr "unbekannte Auflösungseinheit" #: libvips/foreign/tiff2vips.c:670 #, c-format msgid "bad page number %d" msgstr "falsche Seitennummer %d" #: libvips/foreign/tiff2vips.c:680 #, fuzzy, c-format msgid "bad number of pages %d" msgstr "falsche Achsenanzahl %d" #: libvips/foreign/tiff2vips.c:708 libvips/foreign/tiff2vips.c:750 #: libvips/iofuncs/source.c:854 msgid "read error" msgstr "Lesefehler" #: libvips/foreign/tiff2vips.c:792 #, fuzzy, c-format msgid "TIFF does not contain page %d" msgstr "TIFF-Datei enthält nicht Seite %d" #: libvips/foreign/tiff2vips.c:802 msgid "no SUBIFD tag" msgstr "" #: libvips/foreign/tiff2vips.c:808 #, c-format msgid "subifd %d out of range, only 0-%d available" msgstr "" #: libvips/foreign/tiff2vips.c:816 msgid "subdirectory unreadable" msgstr "" #: libvips/foreign/tiff2vips.c:857 #, fuzzy, c-format msgid "not %d bands" msgstr "nicht ein Band oder %d Bänder" #: libvips/foreign/tiff2vips.c:870 #, c-format msgid "not at least %d samples per pixel" msgstr "" #: libvips/foreign/tiff2vips.c:885 msgid "samples_per_pixel not a whole number of bytes" msgstr "" #: libvips/foreign/tiff2vips.c:898 #, fuzzy, c-format msgid "not photometric interpretation %d" msgstr "unbekannte fotometrische Deutung %d" #: libvips/foreign/tiff2vips.c:910 #, c-format msgid "not %d bits per sample" msgstr "" #: libvips/foreign/tiff2vips.c:926 #, c-format msgid "%d bits per sample palette image not supported" msgstr "%d Bit pro Musterfarbpalettenbild nicht unterstützt" #: libvips/foreign/tiff2vips.c:985 #, fuzzy msgid "unsupported tiff image type\n" msgstr "nicht unterstützter Bildtyp %d" #: libvips/foreign/tiff2vips.c:1593 msgid "bad colormap" msgstr "falsche Farbzusammenstellung" #: libvips/foreign/tiff2vips.c:2320 #, c-format msgid "decompress error tile %d x %d" msgstr "" #: libvips/foreign/tiff2vips.c:2598 #, fuzzy msgid "tiled separate planes not supported" msgstr "Datentyp %d nicht unterstützt" #: libvips/foreign/tiff2vips.c:2617 libvips/foreign/tiff2vips.c:2900 #: libvips/foreign/tiff2vips.c:3024 #, fuzzy msgid "unsupported tiff image type" msgstr "nicht unterstützter Bildtyp %d" #: libvips/foreign/tiff2vips.c:2751 #, c-format msgid "out of order read -- at line %d, but line %d requested" msgstr "" #: libvips/foreign/tiff2vips.c:3060 #, fuzzy msgid "subsampled images not supported" msgstr "%d-dimensionale Bilder nicht unterstützt" #: libvips/foreign/tiff2vips.c:3072 msgid "not SGI-compressed LOGLUV" msgstr "" #: libvips/foreign/tiff2vips.c:3089 #, fuzzy msgid "width/height out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/foreign/tiff2vips.c:3098 #, fuzzy msgid "samples out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/foreign/tiff2vips.c:3184 libvips/foreign/tiff2vips.c:3212 #, fuzzy msgid "tile size out of range" msgstr "Parameter außerhalb des Bereichs" #: libvips/foreign/tiff2vips.c:3404 #, c-format msgid "page %d differs from page %d" msgstr "" #: libvips/foreign/tiff.c:224 libvips/foreign/tiff.c:239 #, fuzzy msgid "unable to open source for input" msgstr "»%s« kann nicht zur Eingabe geöffnet werden" #: libvips/foreign/tiff.c:347 libvips/foreign/tiff.c:362 #, fuzzy msgid "unable to open target for output" msgstr "»%s« kann nicht zur Ausgabe geöffnet werden" #: libvips/foreign/tiffload.c:183 #, fuzzy msgid "load tiff" msgstr "TIFF aus Datei laden" #: libvips/foreign/tiffload.c:211 msgid "Rotate image using orientation tag" msgstr "" #: libvips/foreign/tiffload.c:217 msgid "subifd" msgstr "" #: libvips/foreign/tiffload.c:218 msgid "Subifd index" msgstr "" #: libvips/foreign/tiffload.c:291 #, fuzzy msgid "load tiff from source" msgstr "TIFF aus Datei laden" #: libvips/foreign/tiffload.c:368 msgid "load tiff from file" msgstr "TIFF aus Datei laden" #: libvips/foreign/tiffload.c:445 #, fuzzy msgid "load tiff from buffer" msgstr "TIFF aus Datei laden" #: libvips/foreign/tiffsave.c:251 #, fuzzy msgid "save image as tiff" msgstr "Bild in TIFF-Datei speichern" #: libvips/foreign/tiffsave.c:261 msgid "Compression for this file" msgstr "Komprimierung für diese Datei" # http://de.wikipedia.org/wiki/Abhängige_und_unabhängige_Variable #: libvips/foreign/tiffsave.c:275 #, fuzzy msgid "Predictor" msgstr "Prädiktor" #: libvips/foreign/tiffsave.c:276 msgid "Compression prediction" msgstr "Prognose der Komprimierung" #: libvips/foreign/tiffsave.c:283 msgid "Tile" msgstr "Kachel" #: libvips/foreign/tiffsave.c:284 msgid "Write a tiled tiff" msgstr "ein gekacheltes TIFF schreiben" #: libvips/foreign/tiffsave.c:304 msgid "Pyramid" msgstr "Pyramide" #: libvips/foreign/tiffsave.c:305 msgid "Write a pyramidal tiff" msgstr "ein pyramidenförmiges TIFF schreiben" #: libvips/foreign/tiffsave.c:311 msgid "Miniswhite" msgstr "" #: libvips/foreign/tiffsave.c:312 msgid "Use 0 for white in 1-bit images" msgstr "" #: libvips/foreign/tiffsave.c:319 #, fuzzy msgid "Write as a 1, 2, 4 or 8 bit image" msgstr "ein BigTIFF-Bild schreiben" #: libvips/foreign/tiffsave.c:325 libvips/foreign/tiffsave.c:326 msgid "Resolution unit" msgstr "Einheit der Auflösung" # http://de.wikipedia.org/wiki/Liste_von_Dateinamenserweiterungen/T #: libvips/foreign/tiffsave.c:346 msgid "Bigtiff" msgstr "BigTIFF" #: libvips/foreign/tiffsave.c:347 msgid "Write a bigtiff image" msgstr "ein BigTIFF-Bild schreiben" #: libvips/foreign/tiffsave.c:354 msgid "Write a properties document to IMAGEDESCRIPTION" msgstr "" #: libvips/foreign/tiffsave.c:368 msgid "Deflate (1-9, default 6) or ZSTD (1-22, default 9) compression level" msgstr "" #: libvips/foreign/tiffsave.c:375 #, fuzzy msgid "Enable WEBP lossless mode" msgstr "»fd« kann nicht geschlossen werden" #: libvips/foreign/tiffsave.c:388 msgid "Sub-IFD" msgstr "" #: libvips/foreign/tiffsave.c:389 msgid "Save pyr layers as sub-IFDs" msgstr "" #: libvips/foreign/tiffsave.c:395 msgid "Premultiply" msgstr "" #: libvips/foreign/tiffsave.c:396 msgid "Save with premultiplied alpha" msgstr "" #: libvips/foreign/tiffsave.c:402 msgid "RGB JPEG" msgstr "" #: libvips/foreign/tiffsave.c:403 msgid "Output RGB JPEG rather than YCbCr" msgstr "" #: libvips/foreign/tiffsave.c:410 msgid "Squash images down to 1 bit" msgstr "Bilder auf ein Bit zusammenquetschen" #: libvips/foreign/tiffsave.c:470 #, fuzzy msgid "save image to tiff target" msgstr "Bild in TIFF-Datei speichern" #: libvips/foreign/tiffsave.c:520 msgid "save image to tiff file" msgstr "Bild in TIFF-Datei speichern" #: libvips/foreign/tiffsave.c:581 #, fuzzy msgid "save image to tiff buffer" msgstr "Bild in TIFF-Datei speichern" #: libvips/foreign/vips2jpeg.c:176 #, c-format msgid "%s" msgstr "%s" #: libvips/foreign/vips2jpeg.c:1059 #, fuzzy msgid "libvips built without JPEG support" msgstr "VIPS wurde ohne FFT-Unterstützung konfiguriert" #: libvips/foreign/vips2magick.c:319 #, fuzzy msgid "unsupported image format" msgstr "nicht unterstützter Bildtyp %d" #: libvips/foreign/vips2magick.c:349 #, fuzzy msgid "unsupported number of image bands" msgstr "nicht unterstützter Bildtyp %d" #: libvips/foreign/vips2magick.c:464 #, fuzzy msgid "save with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/vips2magick.c:490 #, fuzzy msgid "Quality to use" msgstr "kann nicht gesucht werden" #: libvips/foreign/vips2magick.c:496 msgid "Optimize_gif_frames" msgstr "" #: libvips/foreign/vips2magick.c:497 msgid "Apply GIF frames optimization" msgstr "" #: libvips/foreign/vips2magick.c:503 msgid "Optimize_gif_transparency" msgstr "" #: libvips/foreign/vips2magick.c:504 msgid "Apply GIF transparency optimization" msgstr "" #: libvips/foreign/vips2magick.c:574 #, fuzzy msgid "save file with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/vips2magick.c:646 #, fuzzy msgid "save image to magick buffer" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/vips2magick.c:677 #, fuzzy msgid "save bmp image with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/vips2magick.c:710 #, fuzzy msgid "save bmp image to magick buffer" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/vips2magick.c:743 #, fuzzy msgid "save gif image with ImageMagick" msgstr "Datei mit ImageMagick laden" #: libvips/foreign/vips2magick.c:776 #, fuzzy msgid "save gif image to magick buffer" msgstr "Bild in den PNG-Puffer speichern" #: libvips/foreign/vips2tiff.c:1454 msgid "can only pyramid LABQ and non-complex images" msgstr "" "nur LABQ und nicht-komplexe Bilder können pyramidenartig verwendet werden" #: libvips/foreign/vips2tiff.c:1477 msgid "tile size not a multiple of 16" msgstr "Bildgröße kein Vielfaches von 16" #: libvips/foreign/vips2tiff.c:1835 libvips/foreign/vips2tiff.c:2024 msgid "TIFF write tile failed" msgstr "Schreiben des TIFF-Bildes fehlgeschlagen" #: libvips/foreign/vipsload.c:126 msgid "no filename associated with source" msgstr "" #: libvips/foreign/vipsload.c:157 #, fuzzy msgid "load vips base class" msgstr "Basisklasse" #: libvips/foreign/vipsload.c:225 msgid "load vips from file" msgstr "Vips aus einer Datei laden" #: libvips/foreign/vipsload.c:297 #, fuzzy msgid "load vips from source" msgstr "Vips aus einer Datei laden" #: libvips/foreign/vipspng.c:450 msgid "unsupported color type" msgstr "nicht unterstützter Farbtyp" #: libvips/foreign/vipspng.c:564 #, fuzzy msgid "unable to read PNG header" msgstr "Kopfdaten für »%s« können nicht gelesen werden" #: libvips/foreign/vipspng.c:756 #, fuzzy msgid "libpng read error" msgstr "Lesefehler" #: libvips/foreign/vipspng.c:1112 msgid "compress should be in [0,9]" msgstr "Komprimierung sollte in [0,9] liegen" #: libvips/foreign/vipspng.c:1140 #, c-format msgid "can't save %d band image as png" msgstr "" #: libvips/foreign/vipspng.c:1341 #, fuzzy, c-format msgid "unable to write to target %s" msgstr "auf »%s« kann nicht geschrieben werden" #: libvips/foreign/vipssave.c:114 #, fuzzy msgid "no filename associated with target" msgstr "dieses zugehörige Bild laden" #: libvips/foreign/vipssave.c:139 #, fuzzy msgid "save vips base class" msgstr "Basisklasse" #: libvips/foreign/vipssave.c:187 #, fuzzy msgid "save image to file in vips format" msgstr "Bild in Vips-Datei speichern" #: libvips/foreign/vipssave.c:240 #, fuzzy msgid "save image to target in vips format" msgstr "Bild in Vips-Datei speichern" #: libvips/foreign/webp2vips.c:407 #, fuzzy msgid "unable to parse image" msgstr "es kann nicht zu einem %s-Bild ausgegeben werden" #: libvips/foreign/webp2vips.c:595 #, fuzzy msgid "unable to loop through frames" msgstr "es kann nicht zu einem %s-Bild ausgegeben werden" #: libvips/foreign/webpload.c:162 #, fuzzy msgid "load webp" msgstr "JPEG laden" # Portable Pixmap #: libvips/foreign/webpload.c:253 #, fuzzy msgid "load webp from source" msgstr "PPM aus Datei laden" # Portable Pixmap #: libvips/foreign/webpload.c:330 #, fuzzy msgid "load webp from file" msgstr "PPM aus Datei laden" #: libvips/foreign/webpload.c:407 #, fuzzy msgid "load webp from buffer" msgstr "JPEG aus Puffer laden" #: libvips/foreign/webpsave.c:248 #, fuzzy msgid "picture version error" msgstr "Version ausgeben" #: libvips/foreign/webpsave.c:290 msgid "picture memory error" msgstr "" #: libvips/foreign/webpsave.c:333 #, fuzzy msgid "anim add error" msgstr "Lesefehler" #: libvips/foreign/webpsave.c:347 #, fuzzy msgid "unable to encode" msgstr "kann nicht gesucht werden" #: libvips/foreign/webpsave.c:443 #, fuzzy msgid "chunk add error" msgstr "Lesefehler" #: libvips/foreign/webpsave.c:549 libvips/foreign/webpsave.c:590 #, fuzzy msgid "mux error" msgstr "Unix-Fehler" #: libvips/foreign/webpsave.c:610 libvips/foreign/webpsave.c:620 #: libvips/foreign/webpsave.c:658 #, fuzzy msgid "config version error" msgstr "Umwandlungstransaktionen" #: libvips/foreign/webpsave.c:640 msgid "invalid configuration" msgstr "" #: libvips/foreign/webpsave.c:669 #, fuzzy msgid "unable to init animation" msgstr "kann nicht gekürzt werden" #: libvips/foreign/webpsave.c:700 #, fuzzy msgid "anim close error" msgstr "XML-Fehler beim Speichern" #: libvips/foreign/webpsave.c:705 #, fuzzy msgid "anim build error" msgstr "Lesefehler" #: libvips/foreign/webpsave.c:713 libvips/mosaicing/lrmerge.c:308 #: libvips/mosaicing/tbmerge.c:186 libvips/mosaicing/tbmerge.c:261 #: libvips/mosaicing/tbmerge.c:593 msgid "internal error" msgstr "interner Fehler" #: libvips/foreign/webpsave.c:746 #, c-format msgid "failed to allocate %zu bytes" msgstr "" #: libvips/foreign/webpsave.c:819 #, fuzzy msgid "save as WebP" msgstr "Bild als ASCII speichern" #: libvips/foreign/webpsave.c:843 msgid "Preset" msgstr "" #: libvips/foreign/webpsave.c:844 msgid "Preset for lossy compression" msgstr "" #: libvips/foreign/webpsave.c:851 msgid "Smart subsampling" msgstr "" #: libvips/foreign/webpsave.c:852 msgid "Enable high quality chroma subsampling" msgstr "" #: libvips/foreign/webpsave.c:858 msgid "Near lossless" msgstr "" #: libvips/foreign/webpsave.c:859 msgid "Enable preprocessing in lossless mode (uses Q)" msgstr "" #: libvips/foreign/webpsave.c:865 msgid "Alpha quality" msgstr "" #: libvips/foreign/webpsave.c:866 msgid "Change alpha plane fidelity for lossy compression" msgstr "" #: libvips/foreign/webpsave.c:872 msgid "Minimise size" msgstr "" #: libvips/foreign/webpsave.c:873 msgid "Optimise for minimum size" msgstr "" #: libvips/foreign/webpsave.c:879 msgid "Minimum keyframe spacing" msgstr "" #: libvips/foreign/webpsave.c:880 #, fuzzy msgid "Minimum number of frames between key frames" msgstr "maximale Anzahl von Kacheln, die zwischengespeichert werden soll" #: libvips/foreign/webpsave.c:886 msgid "Maximum keyframe spacing" msgstr "" #: libvips/foreign/webpsave.c:887 #, fuzzy msgid "Maximum number of frames between key frames" msgstr "maximale Anzahl von Kacheln, die zwischengespeichert werden soll" #: libvips/foreign/webpsave.c:894 libvips/foreign/webpsave.c:915 msgid "Level of CPU effort to reduce file size" msgstr "" #: libvips/foreign/webpsave.c:900 #, fuzzy msgid "Target size" msgstr "falsche Bildgröße" #: libvips/foreign/webpsave.c:901 msgid "Desired target size in bytes" msgstr "" #: libvips/foreign/webpsave.c:907 msgid "Passes" msgstr "" #: libvips/foreign/webpsave.c:908 msgid "Number of entropy-analysis passes (in [1..10])" msgstr "" #: libvips/foreign/webpsave.c:914 msgid "Reduction effort" msgstr "" #: libvips/foreign/webpsave.c:921 #, fuzzy msgid "Mixed encoding" msgstr "Bildpunktkodierung" #: libvips/foreign/webpsave.c:922 msgid "Allow mixed encoding (might reduce file size)" msgstr "" #: libvips/foreign/webpsave.c:928 msgid "Smart deblocking" msgstr "" #: libvips/foreign/webpsave.c:929 msgid "Enable auto-adjusting of the deblocking filter" msgstr "" # http://de.wikipedia.org/wiki/MIME#image #: libvips/foreign/webpsave.c:1153 #, fuzzy msgid "save image to webp mime" msgstr "Bild in JPEG-MIME speichern" #: libvips/freqfilt/freqfilt.c:83 #, fuzzy msgid "frequency-domain filter operations" msgstr "unäre Transaktionen" #: libvips/freqfilt/freqmult.c:126 msgid "frequency-domain filtering" msgstr "" #: libvips/freqfilt/freqmult.c:131 #, fuzzy msgid "Input mask image" msgstr "Eingabebild" #: libvips/freqfilt/fwfft.c:145 libvips/freqfilt/fwfft.c:266 #: libvips/freqfilt/invfft.c:124 libvips/freqfilt/invfft.c:203 msgid "unable to create transform plan" msgstr "Umwandlungsplan kann nicht erstellt werden" #: libvips/freqfilt/fwfft.c:351 msgid "forward FFT" msgstr "" #: libvips/freqfilt/invfft.c:263 msgid "inverse FFT" msgstr "" #: libvips/freqfilt/invfft.c:267 msgid "Real" msgstr "" #: libvips/freqfilt/invfft.c:268 msgid "Output only the real part of the transform" msgstr "" #: libvips/freqfilt/phasecor.c:107 msgid "calculate phase correlation" msgstr "" #: libvips/freqfilt/spectrum.c:100 msgid "make displayable power spectrum" msgstr "" #: libvips/histogram/case.c:164 #, fuzzy msgid "bad number of cases" msgstr "falsche Achsenanzahl %d" #: libvips/histogram/case.c:169 #, fuzzy msgid "index image not 1-band" msgstr "»ink«-Bild nicht 1x1 Bildpunkte" #: libvips/histogram/case.c:233 msgid "use pixel values to pick cases from an array of images" msgstr "" #: libvips/histogram/case.c:245 msgid "Cases" msgstr "" #: libvips/histogram/case.c:246 #, fuzzy msgid "Array of case images" msgstr "Feld von Eingabebildern" #: libvips/histogram/hist_cum.c:158 msgid "form cumulative histogram" msgstr "" #: libvips/histogram/hist_entropy.c:107 msgid "estimate image entropy" msgstr "" #: libvips/histogram/hist_entropy.c:112 #: libvips/histogram/hist_ismonotonic.c:119 #, fuzzy msgid "Input histogram image" msgstr "Eingabebild" #: libvips/histogram/hist_equal.c:110 msgid "histogram equalisation" msgstr "" #: libvips/histogram/hist_equal.c:127 msgid "Equalise with this band" msgstr "" #: libvips/histogram/hist_ismonotonic.c:114 msgid "test for monotonicity" msgstr "" #: libvips/histogram/hist_ismonotonic.c:124 msgid "Monotonic" msgstr "" #: libvips/histogram/hist_ismonotonic.c:125 msgid "true if in is monotonic" msgstr "" #: libvips/histogram/hist_local.c:304 libvips/histogram/stdif.c:236 #: libvips/morphology/rank.c:491 msgid "window too large" msgstr "Fenster zu groß" #: libvips/histogram/hist_local.c:355 msgid "local histogram equalisation" msgstr "" #: libvips/histogram/hist_local.c:374 libvips/histogram/stdif.c:309 #: libvips/morphology/rank.c:571 #, fuzzy msgid "Window width in pixels" msgstr "Kachelbreite in Bildpunkten" #: libvips/histogram/hist_local.c:381 libvips/histogram/stdif.c:316 #: libvips/morphology/rank.c:578 #, fuzzy msgid "Window height in pixels" msgstr "Kachelhöhe in Bildpunkten" #: libvips/histogram/hist_local.c:387 #, fuzzy msgid "Max slope" msgstr "Kacheln maximal" #: libvips/histogram/hist_local.c:388 msgid "Maximum slope (CLAHE)" msgstr "" #: libvips/histogram/hist_match.c:154 msgid "match two histograms" msgstr "" #: libvips/histogram/hist_match.c:162 #, fuzzy msgid "Input histogram" msgstr "Eingabebild" #: libvips/histogram/hist_match.c:167 libvips/mosaicing/match.c:196 #: libvips/mosaicing/merge.c:122 libvips/mosaicing/mosaic1.c:498 #: libvips/mosaicing/mosaic.c:179 msgid "Reference" msgstr "" #: libvips/histogram/hist_match.c:168 msgid "Reference histogram" msgstr "" #: libvips/histogram/hist_norm.c:137 msgid "normalise histogram" msgstr "" #: libvips/histogram/histogram.c:195 #, fuzzy msgid "histogram operations" msgstr "binäre Transaktionen" #: libvips/histogram/hist_plot.c:329 msgid "plot histogram" msgstr "" #: libvips/histogram/hist_unary.c:84 #, fuzzy msgid "hist_unary operations" msgstr "unäre Transaktionen" #: libvips/histogram/maplut.c:738 msgid "map an image though a lut" msgstr "" #: libvips/histogram/maplut.c:756 msgid "LUT" msgstr "" #: libvips/histogram/maplut.c:757 #, fuzzy msgid "Look-up table image" msgstr "ein Bild kopieren" #: libvips/histogram/maplut.c:763 msgid "Apply one-band lut to this band of in" msgstr "" #: libvips/histogram/percent.c:105 msgid "find threshold for percent of pixels" msgstr "" #: libvips/histogram/percent.c:115 msgid "Percent" msgstr "" #: libvips/histogram/percent.c:116 #, fuzzy msgid "Percent of pixels" msgstr "Einheitsvektor von Bildpunkten" #: libvips/histogram/percent.c:123 msgid "Threshold above which lie percent of pixels" msgstr "" #: libvips/histogram/stdif.c:240 #, fuzzy msgid "too many bands" msgstr "zu viele Argumente" #: libvips/histogram/stdif.c:290 msgid "statistical difference" msgstr "" #: libvips/histogram/stdif.c:322 #, fuzzy msgid "Mean weight" msgstr "Kachelhöhe" #: libvips/histogram/stdif.c:323 #, fuzzy msgid "Weight of new mean" msgstr "Höhe des extrahierten Bereichs" #: libvips/histogram/stdif.c:330 msgid "New mean" msgstr "" #: libvips/histogram/stdif.c:336 msgid "Deviation weight" msgstr "" #: libvips/histogram/stdif.c:337 msgid "Weight of new deviation" msgstr "" #: libvips/histogram/stdif.c:343 #, fuzzy msgid "Deviation" msgstr "Beschreibung" #: libvips/histogram/stdif.c:344 msgid "New deviation" msgstr "" #: libvips/iofuncs/buf.c:605 #, c-format msgid "%zd bytes of binary data" msgstr "" #: libvips/iofuncs/connection.c:118 #, fuzzy msgid "Descriptor" msgstr "Beschreibung" #: libvips/iofuncs/connection.c:119 #, fuzzy msgid "File descriptor for read or write" msgstr "Datei-Deskriptor, in den geschrieben werden soll" #: libvips/iofuncs/connection.c:126 #, fuzzy msgid "Name of file to open" msgstr "falscher Dateityp" #: libvips/iofuncs/error.c:241 #, fuzzy msgid "system error" msgstr "Lesefehler" #: libvips/iofuncs/error.c:394 msgid "image must be uncoded" msgstr "Bild muss unkodiert sein" #: libvips/iofuncs/error.c:423 #, fuzzy msgid "image coding must be 'none' or 'labq'" msgstr "Bildkodierung muss NONE oder LABQ sein" #: libvips/iofuncs/error.c:452 msgid "unknown image coding" msgstr "unbekannte Bildkodierung" #: libvips/iofuncs/error.c:478 #, fuzzy, c-format msgid "coding '%s' only" msgstr "Nur LABQ-Kodierung" #: libvips/iofuncs/error.c:504 msgid "image must one band" msgstr "Bild muss ein Band haben" #: libvips/iofuncs/error.c:530 #, c-format msgid "image must have %d bands" msgstr "Bild muss %d Bänder haben" #: libvips/iofuncs/error.c:556 msgid "image must have one or three bands" msgstr "Bild muss ein oder drei Bänder haben" #: libvips/iofuncs/error.c:583 #, fuzzy, c-format msgid "image must have at least %d bands" msgstr "Bild muss %d Bänder haben" #: libvips/iofuncs/error.c:612 msgid "images must have the same number of bands, or one must be single-band" msgstr "" "Bilder müssen die gleiche Anzahl Bänder haben oder eines muss ein Band haben" #: libvips/iofuncs/error.c:640 #, c-format msgid "image must have 1 or %d bands" msgstr "Bild muss ein oder %d Bänder haben" #: libvips/iofuncs/error.c:665 msgid "image must be non-complex" msgstr "Bild muss nicht-komplex sein" #: libvips/iofuncs/error.c:690 msgid "image must be complex" msgstr "Bild muss komplex sein" #: libvips/iofuncs/error.c:718 #, fuzzy msgid "image must be two-band or complex" msgstr "Bild muss nicht-komplex sein" #: libvips/iofuncs/error.c:745 #, c-format msgid "image must be %s" msgstr "Bild muss %s sein" #: libvips/iofuncs/error.c:771 msgid "image must be integer" msgstr "Bild muss ganzzahlig sein" #: libvips/iofuncs/error.c:797 msgid "image must be unsigned integer" msgstr "Bild muss aus vorzeichenlosen Ganzzahlen bestehen" #: libvips/iofuncs/error.c:826 msgid "image must be 8- or 16-bit integer, signed or unsigned" msgstr "" "Bild muss aus 8- oder 16-Bit Ganzzahlen mit oder ohne Vorzeichen bestehen" #: libvips/iofuncs/error.c:853 msgid "image must be 8- or 16-bit unsigned integer" msgstr "Bild muss aus 8- oder 16-Bit vorzeichenlosen Ganzzahlen bestehen" #: libvips/iofuncs/error.c:880 msgid "image must be 8- or 16-bit unsigned integer, or float" msgstr "" "Bild muss aus 8- oder 16-Bit vorzeichenlosen Ganzzahlen oder " "Fließkommazahlen bestehen" #: libvips/iofuncs/error.c:908 msgid "image must be unsigned int or float" msgstr "" "Bild muss aus 8- oder 16-Bit vorzeichenlosen Ganz- oder Fließkommazahlen " "bestehen" #: libvips/iofuncs/error.c:935 msgid "images must match in size" msgstr "Bilder müssen in der Größe passen" #: libvips/iofuncs/error.c:962 #, fuzzy msgid "images must be odd and square" msgstr "Bild muss %d Bänder haben" #: libvips/iofuncs/error.c:989 msgid "images must have the same number of bands" msgstr "Bilder müssen die gleiche Anzahl Bänder haben" #: libvips/iofuncs/error.c:1045 msgid "images must have the same band format" msgstr "Bilder müssen das gleiche Bandformat haben" #: libvips/iofuncs/error.c:1072 msgid "images must have the same coding" msgstr "Bilder müssen die gleiche Kodierung haben" #: libvips/iofuncs/error.c:1096 #, fuzzy, c-format msgid "vector must have %d elements" msgstr "Vektor muss 1 oder %d Elemente haben" #: libvips/iofuncs/error.c:1133 #, fuzzy msgid "vector must have 1 element" msgstr "Vektor muss 1 oder %d Elemente haben" #: libvips/iofuncs/error.c:1136 #, c-format msgid "vector must have 1 or %d elements" msgstr "Vektor muss 1 oder %d Elemente haben" #: libvips/iofuncs/error.c:1162 msgid "histograms must have width or height 1" msgstr "Histogramme müssen eine Breite oder Höhe von eins haben" #: libvips/iofuncs/error.c:1167 msgid "histograms must have not have more than 65536 elements" msgstr "Histogramm dürfen nicht mehr als 65536 Elemente haben" #: libvips/iofuncs/error.c:1204 #, fuzzy msgid "matrix image too large" msgstr "Zoomfaktoren zu groß" #: libvips/iofuncs/error.c:1209 #, fuzzy msgid "matrix image must have one band" msgstr "Bild muss %d Bänder haben" #: libvips/iofuncs/error.c:1244 #, fuzzy msgid "separable matrix images must have width or height 1" msgstr "Histogramme müssen eine Breite oder Höhe von eins haben" #: libvips/iofuncs/error.c:1271 #, fuzzy msgid "precision must be int or float" msgstr "" "Bild muss aus 8- oder 16-Bit vorzeichenlosen Ganz- oder Fließkommazahlen " "bestehen" #: libvips/iofuncs/generate.c:695 msgid "demand hint not set" msgstr "Hinweisanfrage nicht gesetzt" #: libvips/iofuncs/generate.c:714 libvips/iofuncs/generate.c:742 msgid "generate() called twice" msgstr "generate() zweimal aufgerufen" #: libvips/iofuncs/generate.c:783 libvips/iofuncs/image.c:3249 #, c-format msgid "unable to output to a %s image" msgstr "es kann nicht zu einem %s-Bild ausgegeben werden" #: libvips/iofuncs/ginputsource.c:164 libvips/iofuncs/ginputsource.c:229 #, c-format msgid "Error while seeking: %s" msgstr "" #: libvips/iofuncs/ginputsource.c:185 msgid "Cannot truncate VipsGInputStream" msgstr "" #: libvips/iofuncs/ginputsource.c:206 #, fuzzy, c-format msgid "Error while reading: %s" msgstr "Fehler beim Lesen von XML: %s" #: libvips/iofuncs/ginputsource.c:275 msgid "Stream to wrap" msgstr "" #: libvips/iofuncs/header.c:1336 #, c-format msgid "field \"%s\" not found" msgstr "Feld »%s« nicht gefunden" #: libvips/iofuncs/header.c:1575 #, c-format msgid "field \"%s\" is of type %s, not %s" msgstr "Feld »%s« ist vom Typ %s, nicht %s" #: libvips/iofuncs/header.c:1855 #, fuzzy, c-format msgid "field \"%s\" is of type %s, not VipsRefString" msgstr "Feld »%s« ist vom Typ %s, nicht %s" #: libvips/iofuncs/image.c:526 msgid "unable to close fd" msgstr "»fd« kann nicht geschlossen werden" #: libvips/iofuncs/image.c:747 #, fuzzy, c-format msgid "%s %s: %d x %d pixels, %d threads, %d x %d tiles, %d lines in buffer" msgstr "%s %s: %d Threads, %d x %d Kacheln, Gruppen von %d Scan-Zeilen" #: libvips/iofuncs/image.c:760 #, c-format msgid "%s %s: %d%% complete" msgstr "%s %s: %d%% komplett" #: libvips/iofuncs/image.c:779 #, fuzzy, c-format msgid "%s %s: done in %.3gs \n" msgstr "%s %s: Erledigt in %ds \n" #: libvips/iofuncs/image.c:961 #, c-format msgid "unable to open \"%s\", file too short" msgstr "»%s« kann nicht geöffnet werden, Datei zu klein" #: libvips/iofuncs/image.c:988 #, c-format msgid "bad mode \"%s\"" msgstr "falscher Modus »%s«" #: libvips/iofuncs/image.c:1060 msgid "image class" msgstr "Bildklasse" #: libvips/iofuncs/image.c:1158 msgid "Image filename" msgstr "Bilddateiname" #: libvips/iofuncs/image.c:1165 msgid "Open mode" msgstr "Öffnen-Modus" #: libvips/iofuncs/image.c:1171 msgid "Kill" msgstr "töten" #: libvips/iofuncs/image.c:1172 msgid "Block evaluation on this image" msgstr "Blockauswertung dieses Bildes" #: libvips/iofuncs/image.c:1178 msgid "Demand style" msgstr "Nachfragestil" #: libvips/iofuncs/image.c:1179 msgid "Preferred demand style for this image" msgstr "für dieses Bild bevorzugter Nachfragestil" #: libvips/iofuncs/image.c:1192 msgid "Foreign buffer" msgstr "Fremdpuffer" #: libvips/iofuncs/image.c:1193 msgid "Pointer to foreign pixels" msgstr "Puffer für fremde Bildpunkte" #: libvips/iofuncs/image.c:1651 #, c-format msgid "killed for image \"%s\"" msgstr "für Bild »%s« abgeschossen" #: libvips/iofuncs/image.c:2067 msgid "memory area too small -- should be %" msgstr "" #: libvips/iofuncs/image.c:2259 #, fuzzy msgid "unable to load source" msgstr "Verlauf kann nicht gelesen werden" #: libvips/iofuncs/image.c:2372 #, c-format msgid "bad array length -- should be %d, you passed %d" msgstr "" #: libvips/iofuncs/image.c:2896 libvips/iofuncs/memory.c:320 #: libvips/iofuncs/memory.c:394 #, c-format msgid "out of memory -- size == %dMB" msgstr "Hauptspeicher reicht nicht aus – Größe == %dMB" #: libvips/iofuncs/image.c:3192 msgid "bad image descriptor" msgstr "falscher Bild-Deskriptor" #: libvips/iofuncs/image.c:3312 #, c-format msgid "auto-rewind for %s failed" msgstr "automatischer Rücklauf für %s fehlgeschlagen" #: libvips/iofuncs/image.c:3387 libvips/iofuncs/image.c:3518 #: libvips/iofuncs/image.c:3697 msgid "image not readable" msgstr "Bild nicht lesbar" #: libvips/iofuncs/image.c:3433 libvips/iofuncs/image.c:3661 msgid "no image data" msgstr "keine Bilddaten" #: libvips/iofuncs/image.c:3539 libvips/iofuncs/image.c:3728 #: libvips/iofuncs/image.c:3737 msgid "image already written" msgstr "Bild bereits geschrieben" #: libvips/iofuncs/image.c:3563 libvips/iofuncs/image.c:3749 msgid "image not writeable" msgstr "Bild nicht schreibbar" #: libvips/iofuncs/image.c:3619 msgid "bad file type" msgstr "falscher Dateityp" #: libvips/iofuncs/init.c:1279 #, fuzzy msgid "flag not in [0, 5]" msgstr "Schalter nicht -1 oder 1" #: libvips/iofuncs/mapfile.c:189 libvips/iofuncs/mapfile.c:355 msgid "unable to CreateFileMapping" msgstr "»CreateFileMapping« nicht möglich" #: libvips/iofuncs/mapfile.c:196 libvips/iofuncs/mapfile.c:367 msgid "unable to MapViewOfFile" msgstr "»MapViewOfFile« nicht möglich" #: libvips/iofuncs/mapfile.c:235 msgid "unable to mmap" msgstr "»mmap« nicht möglich" #: libvips/iofuncs/mapfile.c:250 libvips/iofuncs/mapfile.c:361 msgid "unable to UnmapViewOfFile" msgstr "»UnmapViewOfFile« nicht möglich" #: libvips/iofuncs/mapfile.c:256 msgid "unable to munmap file" msgstr "»munmap« der Datei nicht möglich" #: libvips/iofuncs/mapfile.c:278 msgid "file is less than 64 bytes" msgstr "Datei ist weniger als 64 Byte groß" #: libvips/iofuncs/mapfile.c:283 libvips/iofuncs/mapfile.c:317 msgid "unable to get file status" msgstr "Dateistatus kann nicht abgefragt werden" #: libvips/iofuncs/mapfile.c:289 msgid "not a regular file" msgstr "keine reguläre Datei" #: libvips/iofuncs/mapfile.c:323 msgid "unable to read data" msgstr "Daten können nicht gelesen werden" #: libvips/iofuncs/mapfile.c:387 #, c-format msgid "unable to mmap: \"%s\" - %s" msgstr "»mmap« nicht möglich: \"%s\" - %s" #: libvips/iofuncs/mapfile.c:398 #, c-format msgid "unable to mmap \"%s\" to same address" msgstr "»mmap %s« zur gleichen Adresse nicht möglich" #: libvips/iofuncs/object.c:344 #, c-format msgid "parameter %s not set" msgstr "Parameter %s nicht gesetzt" #: libvips/iofuncs/object.c:779 #, c-format msgid "no property named `%s'" msgstr "keine Eigenschaft namens »%s«" #: libvips/iofuncs/object.c:785 #, c-format msgid "no vips argument named `%s'" msgstr "kein VIPS-Argument namens »%s«" #: libvips/iofuncs/object.c:791 #, c-format msgid "argument `%s' has no instance" msgstr "Argument »%s« hat keine Instanz" #: libvips/iofuncs/object.c:1531 libvips/iofuncs/operation.c:744 #: libvips/resample/interpolate.c:658 #, c-format msgid "class \"%s\" not found" msgstr "Klasse »%s« nicht gefunden" #: libvips/iofuncs/object.c:1582 msgid "base class" msgstr "Basisklasse" #: libvips/iofuncs/object.c:1596 msgid "Nickname" msgstr "Nickname" #: libvips/iofuncs/object.c:1597 msgid "Class nickname" msgstr "Klassen-Nickname" #: libvips/iofuncs/object.c:1603 msgid "Description" msgstr "Beschreibung" #: libvips/iofuncs/object.c:1604 msgid "Class description" msgstr "Klassenbeschreibung" #: libvips/iofuncs/object.c:1842 #, c-format msgid "no value supplied for argument '%s'" msgstr "" #: libvips/iofuncs/object.c:1845 #, c-format msgid "no value supplied for argument '%s' ('%s')" msgstr "" #: libvips/iofuncs/object.c:2037 libvips/iofuncs/object.c:2056 #, fuzzy, c-format msgid "'%s' is not an integer" msgstr "»%s« ist keine positive Ganzzahl" #: libvips/iofuncs/object.c:2480 #, fuzzy, c-format msgid "expected string or ), saw %s" msgstr "%s erwartet, %s gesehen" #: libvips/iofuncs/object.c:2523 #, c-format msgid "unable to set '%s'" msgstr "»%s« kann nicht gesetzt werden" #: libvips/iofuncs/object.c:2536 msgid "not , or ) after parameter" msgstr "kein »,« oder »)« nach Parameter" #: libvips/iofuncs/object.c:2543 msgid "extra tokens after ')'" msgstr "keine zusätzlichen Token nach »)«" #: libvips/iofuncs/operation.c:230 #, c-format msgid "%d pixels calculated" msgstr "" #: libvips/iofuncs/operation.c:338 msgid "default enum" msgstr "" #: libvips/iofuncs/operation.c:342 msgid "allowed enums" msgstr "" #: libvips/iofuncs/operation.c:370 msgid "default flags" msgstr "" #: libvips/iofuncs/operation.c:375 msgid "allowed flags" msgstr "" #: libvips/iofuncs/operation.c:391 libvips/iofuncs/operation.c:399 #: libvips/iofuncs/operation.c:411 msgid "default" msgstr "" #: libvips/iofuncs/operation.c:402 libvips/iofuncs/operation.c:414 #, fuzzy msgid "min" msgstr "in" #: libvips/iofuncs/operation.c:404 libvips/iofuncs/operation.c:416 msgid "max" msgstr "" #: libvips/iofuncs/operation.c:437 msgid "input" msgstr "Eingabe" #: libvips/iofuncs/operation.c:438 msgid "output" msgstr "Ausgabe" #: libvips/iofuncs/operation.c:613 #, fuzzy msgid "operation is blocked" msgstr "Transaktionen" #: libvips/iofuncs/operation.c:659 msgid "operations" msgstr "Transaktionen" #: libvips/iofuncs/operation.c:750 #, fuzzy, c-format msgid "\"%s\" is not an instantiable class" msgstr "»%s« ist kein bekanntes Dateiformat" #: libvips/iofuncs/operation.c:1221 #, c-format msgid "unknown argument '%s'" msgstr "unbekanntes Argument »%s«" #: libvips/iofuncs/operation.c:1346 msgid "too few arguments" msgstr "zu wenige Argumente" #: libvips/iofuncs/operation.c:1465 msgid "too many arguments" msgstr "zu viele Argumente" #: libvips/iofuncs/region.c:551 libvips/iofuncs/region.c:621 #: libvips/iofuncs/region.c:763 libvips/iofuncs/region.c:1839 msgid "valid clipped to nothing" msgstr "gültig an nichts angeklammert" #: libvips/iofuncs/region.c:661 msgid "bad image type" msgstr "falscher Bildtyp" #: libvips/iofuncs/region.c:705 msgid "no pixel data on attached image" msgstr "keine Bildpunktdaten in angehängtem Bild" #: libvips/iofuncs/region.c:711 msgid "images do not match in pixel size" msgstr "Bilder passen in der Bildpunktgröße nicht zusammen" #: libvips/iofuncs/region.c:744 libvips/iofuncs/region.c:1821 msgid "dest too small" msgstr "Ziel zu klein" #: libvips/iofuncs/region.c:833 msgid "bad position" msgstr "falsche Position" #: libvips/iofuncs/region.c:1619 #, fuzzy msgid "stop requested" msgstr "Fehler abgefragt" #: libvips/iofuncs/region.c:1703 libvips/iofuncs/region.c:1891 #, c-format msgid "unable to input from a %s image" msgstr "Eingabe von einem %s-Bild nicht möglich" #: libvips/iofuncs/region.c:1726 msgid "incomplete header" msgstr "unvollständige Kopfzeilen" #: libvips/iofuncs/region.c:1796 msgid "inappropriate region type" msgstr "Ungeeigneter Regionstyp" #: libvips/iofuncs/sbuf.c:80 msgid "buffered source" msgstr "" #: libvips/iofuncs/sbuf.c:275 #, fuzzy msgid "end of file" msgstr "ln des Bildes" #: libvips/iofuncs/sink.c:261 #, c-format msgid "stop function failed for image \"%s\"" msgstr "»stop«-Funktion für Bild »%s« fehlgeschlagen" #: libvips/iofuncs/sink.c:298 #, c-format msgid "start function failed for image \"%s\"" msgstr "»start«-Funktion für Bild »%s« fehlgeschlagen" #: libvips/iofuncs/sink.c:330 msgid "per-thread state for sink" msgstr "Status pro Thread für »sink«" #: libvips/iofuncs/sinkdisc.c:106 libvips/iofuncs/util.c:555 msgid "write failed" msgstr "Schreiben fehlgeschlagen" #: libvips/iofuncs/sinkdisc.c:135 msgid "per-thread state for sinkdisc" msgstr "Status pro Thread für »sinkdisc«" #: libvips/iofuncs/sinkmemory.c:107 msgid "per-thread state for sinkmemory" msgstr "Status pro Thread für »sinkmemory«" #: libvips/iofuncs/sinkscreen.c:203 msgid "per-thread state for render" msgstr "Status pro Thread für »render«" #: libvips/iofuncs/sinkscreen.c:1191 msgid "bad parameters" msgstr "falsche Parameter" #: libvips/iofuncs/source.c:322 libvips/iofuncs/target.c:114 #, fuzzy msgid "don't set 'filename' and 'descriptor'" msgstr "kein Datei-Deskriptor" #: libvips/iofuncs/source.c:399 msgid "input source" msgstr "" #: libvips/iofuncs/source.c:407 libvips/iofuncs/target.c:326 msgid "Blob" msgstr "" #: libvips/iofuncs/source.c:408 #, fuzzy msgid "Blob to load from" msgstr "Puffer, aus dem geladen werden soll" #: libvips/iofuncs/source.c:553 #, fuzzy msgid "unimplemented target" msgstr "nicht implementierte Maske" #: libvips/iofuncs/source.c:691 #, fuzzy msgid "unable to open for read" msgstr "Datei »%s« kann nicht zum Lesen geöffnet werden" #: libvips/iofuncs/source.c:932 #, fuzzy msgid "pipe too long" msgstr "»%s« zu lang" #: libvips/iofuncs/source.c:1207 libvips/iofuncs/source.c:1232 #: libvips/iofuncs/target.c:225 msgid "bad 'whence'" msgstr "" #: libvips/iofuncs/source.c:1252 #, fuzzy msgid "bad seek to %" msgstr "falscher Schrumpffaktor %d" #: libvips/iofuncs/sourcecustom.c:173 msgid "Custom source" msgstr "" #: libvips/iofuncs/sourceginput.c:219 msgid "GInputStream source" msgstr "" #: libvips/iofuncs/sourceginput.c:227 msgid "Stream" msgstr "" #: libvips/iofuncs/sourceginput.c:228 #, fuzzy msgid "GInputStream to read from" msgstr "Name der Datei, aus der geladen werden soll" #: libvips/iofuncs/system.c:185 #, fuzzy msgid "unable to substitute input filename" msgstr "»munmap« der Datei nicht möglich" #: libvips/iofuncs/system.c:191 #, fuzzy msgid "unable to substitute output filename" msgstr "es kann nicht zu einem %s-Bild ausgegeben werden" #: libvips/iofuncs/system.c:226 #, fuzzy, c-format msgid "command \"%s\" failed" msgstr "Befehl fehlgeschlagen: »%s«" #: libvips/iofuncs/system.c:269 msgid "run an external command" msgstr "" #: libvips/iofuncs/system.c:290 msgid "Command" msgstr "" #: libvips/iofuncs/system.c:291 msgid "Command to run" msgstr "" #: libvips/iofuncs/system.c:297 #, fuzzy msgid "Input format" msgstr "Eingabebild" #: libvips/iofuncs/system.c:298 #, fuzzy msgid "Format for input filename" msgstr "erstes Eingabebild" #: libvips/iofuncs/system.c:304 #, fuzzy msgid "Output format" msgstr "Ausgabebild" #: libvips/iofuncs/system.c:305 msgid "Format for output filename" msgstr "" #: libvips/iofuncs/system.c:312 msgid "Command log" msgstr "" #: libvips/iofuncs/target.c:317 #, fuzzy msgid "File descriptor should output to memory" msgstr "Datei-Deskriptor, in den geschrieben werden soll" #: libvips/iofuncs/target.c:327 #, fuzzy msgid "Blob to save to" msgstr "Puffer, in den gespeichert werden soll" #: libvips/iofuncs/target.c:499 #, fuzzy msgid "write error" msgstr "Lesefehler" #: libvips/iofuncs/targetcustom.c:235 msgid "Custom target" msgstr "" #: libvips/iofuncs/thread.c:150 msgid "unable to create thread" msgstr "Thread kann nicht erstellt werden" #: libvips/iofuncs/threadpool.c:190 msgid "per-thread state for vipsthreadpool" msgstr "Status pro Thread für »vipsthreadpool«" #: libvips/iofuncs/type.c:952 #, fuzzy, c-format msgid "unable to convert \"%s\" to int" msgstr "»%s« kann nicht zur Eingabe geöffnet werden" #: libvips/iofuncs/util.c:533 msgid "unable to get file stats" msgstr "Dateistatus kann nicht abgefragt werden" #: libvips/iofuncs/util.c:697 #, c-format msgid "unable to open file \"%s\" for reading" msgstr "Datei »%s« kann nicht zum Lesen geöffnet werden" #: libvips/iofuncs/util.c:719 #, c-format msgid "unable to open file \"%s\" for writing" msgstr "Datei »%s« kann nicht zum Schreiben geöffnet werden" #: libvips/iofuncs/util.c:740 #, c-format msgid "\"%s\" too long" msgstr "»%s« zu lang" #: libvips/iofuncs/util.c:785 #, c-format msgid "error reading from file \"%s\"" msgstr "Fehler beim Lesen von Datei »%s«" #: libvips/iofuncs/util.c:831 #, fuzzy, c-format msgid "write error (%zd out of %zd blocks written)" msgstr "Schreibfehler (%zd aus %zd Blöcken geschrieben) … Platte voll?" #: libvips/iofuncs/util.c:1098 msgid "unable to seek" msgstr "kann nicht gesucht werden" #: libvips/iofuncs/util.c:1123 libvips/iofuncs/util.c:1130 msgid "unable to truncate" msgstr "kann nicht gekürzt werden" #: libvips/iofuncs/util.c:1216 #, fuzzy, c-format msgid "unable to remove directory \"%s\", %s" msgstr "Daten für »%s« können nicht gelesen werden, %s" #: libvips/iofuncs/util.c:1233 #, fuzzy, c-format msgid "unable to rename file \"%s\" as \"%s\", %s" msgstr "" "Datei »%s« kann nicht gelesen werden\n" "libMagick-Fehler: %s %s" #: libvips/iofuncs/util.c:1361 msgid "unexpected end of string" msgstr "Unerwartetes Ende der Zeichenkette" #: libvips/iofuncs/util.c:1379 libvips/iofuncs/util.c:1449 #, c-format msgid "expected %s, saw %s" msgstr "%s erwartet, %s gesehen" #: libvips/iofuncs/util.c:1758 msgid "no such enum type" msgstr "" #: libvips/iofuncs/util.c:1776 #, fuzzy, c-format msgid "enum '%s' has no member '%s', should be one of: %s" msgstr "Aufzählung »%s« hat keinen Bestandteil »%s«" #: libvips/iofuncs/util.c:1795 msgid "no such flag type" msgstr "" #: libvips/iofuncs/util.c:1814 #, fuzzy, c-format msgid "flags '%s' has no member '%s'" msgstr "Aufzählung »%s« hat keinen Bestandteil »%s«" #: libvips/iofuncs/vips.c:324 #, c-format msgid "\"%s\" is not a VIPS image" msgstr "»%s« ist kein VIPS-Bild" #: libvips/iofuncs/vips.c:381 msgid "unknown coding" msgstr "unbekannte Kodierung" #: libvips/iofuncs/vips.c:391 msgid "malformed LABQ image" msgstr "" #: libvips/iofuncs/vips.c:400 #, fuzzy msgid "malformed RAD image" msgstr "kein RAD-Bild" #: libvips/iofuncs/vips.c:471 msgid "unable to read history" msgstr "Verlauf kann nicht gelesen werden" #: libvips/iofuncs/vips.c:504 #, fuzzy msgid "more than 100 megabytes of XML? sufferin' succotash!" msgstr "mehr als 10 Megabyte XML? Leidende Succotash!" #: libvips/iofuncs/vips.c:538 #, fuzzy msgid "unable to allocate read buffer" msgstr "In den Puffer kann nicht geschrieben werden." #: libvips/iofuncs/vips.c:544 msgid "read error while fetching XML" msgstr "" #: libvips/iofuncs/vips.c:556 #, fuzzy msgid "XML parse error" msgstr "Lesefehler" #: libvips/iofuncs/vips.c:621 msgid "incorrect namespace in XML" msgstr "falscher Namensraum in XML" #: libvips/iofuncs/vips.c:669 msgid "error transforming from save format" msgstr "Fehler beim Umwandeln vom gespeicherten Format" #: libvips/iofuncs/vips.c:770 libvips/iofuncs/window.c:231 msgid "file has been truncated" msgstr "Datei wurde gekürzt" #: libvips/iofuncs/vips.c:822 libvips/iofuncs/vips.c:913 msgid "error transforming to save format" msgstr "Fehler beim Umwandeln in das zu speichernde Format" #: libvips/iofuncs/vips.c:1027 #, c-format msgid "unable to read header for \"%s\"" msgstr "Kopfdaten für »%s« können nicht gelesen werden" #: libvips/iofuncs/window.c:230 #, c-format msgid "unable to read data for \"%s\", %s" msgstr "Daten für »%s« können nicht gelesen werden, %s" # http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650& # db=man&fname=/usr/share/catman/p_man/cat3/il_c/ilAbsImg.z #: libvips/morphology/countlines.c:135 #, fuzzy msgid "count lines in an image" msgstr "absoluter Wert eines Bildes" #: libvips/morphology/countlines.c:139 #, fuzzy msgid "Nolines" msgstr "Zeilen" #: libvips/morphology/countlines.c:140 #, fuzzy msgid "Number of lines" msgstr "Anzahl der Bänder in einem Bild" #: libvips/morphology/countlines.c:147 #, fuzzy msgid "Countlines left-right or up-down" msgstr "von links nach rechts oder von oben nach unten zusammenführen" #: libvips/morphology/labelregions.c:120 #, fuzzy msgid "label regions in an image" msgstr "Anzahl der Bänder in einem Bild" #: libvips/morphology/labelregions.c:125 msgid "Mask of region labels" msgstr "" #: libvips/morphology/labelregions.c:130 msgid "Segments" msgstr "" #: libvips/morphology/labelregions.c:131 msgid "Number of discrete contiguous regions" msgstr "" #: libvips/morphology/morph.c:886 #, fuzzy, c-format msgid "bad mask element (%f should be 0, 128 or 255)" msgstr "falsches Maskenelement (%d sollte 0, 128 oder 255 sein)" #: libvips/morphology/morph.c:956 #, fuzzy msgid "morphology operation" msgstr "unäre Transaktionen" #: libvips/morphology/morph.c:972 msgid "Morphology" msgstr "" #: libvips/morphology/morph.c:973 #, fuzzy msgid "Morphological operation to perform" msgstr "durchzuführende Rundungstransakktion" #: libvips/morphology/morphology.c:65 #, fuzzy msgid "morphological operations" msgstr "arithmetische Transaktionen" #: libvips/morphology/nearest.c:305 msgid "fill image zeros with nearest non-zero pixel" msgstr "" #: libvips/morphology/nearest.c:309 #, fuzzy msgid "Out" msgstr "Ausgabe" #: libvips/morphology/nearest.c:310 msgid "Value of nearest non-zero pixel" msgstr "" #: libvips/morphology/nearest.c:316 msgid "Distance to nearest non-zero pixel" msgstr "" #: libvips/morphology/rank.c:496 #, fuzzy msgid "index out of range" msgstr " »bins« außerhalb des Bereichs [1,%d]" #: libvips/morphology/rank.c:560 msgid "rank filter" msgstr "" #: libvips/morphology/rank.c:585 msgid "Select pixel at index" msgstr "" #: libvips/mosaicing/chkpair.c:201 msgid "inputs incompatible" msgstr "Eingaben inkompatibel" #: libvips/mosaicing/chkpair.c:205 libvips/mosaicing/im_tbcalcon.c:105 msgid "help!" msgstr "Hilfe!" #: libvips/mosaicing/global_balance.c:151 msgid "no matching '>'" msgstr "kein passendes »>«" #: libvips/mosaicing/global_balance.c:160 msgid "too many items" msgstr "zu viele Elemente" # Propogate a transform down a tree. If dirty is set, we've been here before, # so there is a doubling up of this node. If this is a leaf, then we have the # same leaf twice (which, in fact, we can cope with); if this is a node, we # have circularity. #: libvips/mosaicing/global_balance.c:463 msgid "circularity detected" msgstr "Zirkularität entdeckt" #: libvips/mosaicing/global_balance.c:497 #: libvips/mosaicing/global_balance.c:557 #, c-format msgid "image \"%s\" used twice as output" msgstr "Bild »%s« zweimal als Ausgabe benutzt" #: libvips/mosaicing/global_balance.c:606 msgid "bad number of args in join line" msgstr "falsche Anzahl von Argumenten in »join«-Zeile" #: libvips/mosaicing/global_balance.c:648 msgid "bad number of args in join1 line" msgstr "falsche Anzahl von Argumenten in »join1«-Zeile" #: libvips/mosaicing/global_balance.c:684 msgid "bad number of args in copy line" msgstr "falsche Anzahl von Argumenten in »copy«-Zeile" #: libvips/mosaicing/global_balance.c:742 msgid "" "mosaic root not found in desc file\n" "is this really a mosaiced image?" msgstr "" "Mosaik-Wurzel nicht in Beschreibungsdatei gefunden\n" "ist das wirklich ein Bild?" #: libvips/mosaicing/global_balance.c:753 msgid "more than one root" msgstr "mehr als eine Wurzel" #: libvips/mosaicing/global_balance.c:1519 #: libvips/mosaicing/matrixmultiply.c:90 msgid "bad sizes" msgstr "falsche Größen" #: libvips/mosaicing/global_balance.c:1914 #, fuzzy msgid "global balance an image mosaic" msgstr "ein Radiance-Bild aus einer Datei laden" #: libvips/mosaicing/global_balance.c:1930 msgid "Gamma" msgstr "" #: libvips/mosaicing/global_balance.c:1931 #, fuzzy msgid "Image gamma" msgstr "Bilddateiname" #: libvips/mosaicing/global_balance.c:1937 #, fuzzy msgid "Int output" msgstr "Ausgabe" #: libvips/mosaicing/global_balance.c:1938 #, fuzzy msgid "Integer output" msgstr "detaillierte Ausgabe" #: libvips/mosaicing/im_avgdxdy.c:65 msgid "no points to average" msgstr "keine Punkte zum Mitteln" #: libvips/mosaicing/im_clinear.c:138 #, fuzzy msgid "vips_invmat failed" msgstr "»im_invmat« fehlgeschlagen" #: libvips/mosaicing/im_lrcalcon.c:206 msgid "overlap too small for your search size" msgstr "Überlappen zu schmal für Ihre Suchgröße" #: libvips/mosaicing/im_lrcalcon.c:245 #, c-format msgid "found %d tie-points, need at least %d" msgstr "es wurden %d Verbindungspunkte gefunden, mindestens %d sind nötig" #: libvips/mosaicing/im_lrcalcon.c:290 msgid "not 1-band uchar image" msgstr "kein »uchar«-Bild mit einem Band" #: libvips/mosaicing/im_tbcalcon.c:119 msgid "overlap too small" msgstr "Überlappen zu schmal" #: libvips/mosaicing/lrmerge.c:785 msgid "mwidth must be -1 or >= 0" msgstr "»mwidth« muss -1 oder >= 0 sein" #: libvips/mosaicing/lrmerge.c:817 msgid "no overlap" msgstr "kein Überlappen" #: libvips/mosaicing/lrmerge.c:887 libvips/mosaicing/tbmerge.c:692 msgid "unknown coding type" msgstr "unbekannter Kodierungstyp" #: libvips/mosaicing/lrmerge.c:905 libvips/mosaicing/tbmerge.c:710 msgid "too much overlap" msgstr "zu viel Überlappung" #: libvips/mosaicing/lrmosaic.c:122 libvips/mosaicing/tbmosaic.c:93 msgid "bad area parameters" msgstr "falsche Bereichsparameter" #: libvips/mosaicing/lrmosaic.c:143 libvips/mosaicing/tbmosaic.c:114 msgid "overlap too small for search" msgstr "Überlappen zu klein für Suche" #: libvips/mosaicing/lrmosaic.c:171 libvips/mosaicing/tbmosaic.c:142 msgid "unknown Coding type" msgstr "unbekannter Kodierungstyp" #: libvips/mosaicing/match.c:192 #, fuzzy msgid "first-order match of two images" msgstr "zwei Bilder subtrahieren" #: libvips/mosaicing/match.c:197 libvips/mosaicing/merge.c:123 #: libvips/mosaicing/mosaic1.c:499 libvips/mosaicing/mosaic.c:180 #, fuzzy msgid "Reference image" msgstr "Zeilensprungbild" #: libvips/mosaicing/match.c:202 libvips/mosaicing/merge.c:128 #: libvips/mosaicing/mosaic1.c:504 libvips/mosaicing/mosaic.c:185 msgid "Secondary" msgstr "" #: libvips/mosaicing/match.c:203 libvips/mosaicing/merge.c:129 #: libvips/mosaicing/mosaic1.c:505 libvips/mosaicing/mosaic.c:186 #, fuzzy msgid "Secondary image" msgstr "zweites Eingabebild" #: libvips/mosaicing/match.c:214 libvips/mosaicing/mosaic1.c:523 msgid "xr1" msgstr "" #: libvips/mosaicing/match.c:215 libvips/mosaicing/match.c:222 #: libvips/mosaicing/mosaic1.c:524 libvips/mosaicing/mosaic1.c:531 msgid "Position of first reference tie-point" msgstr "" #: libvips/mosaicing/match.c:221 libvips/mosaicing/mosaic1.c:530 msgid "yr1" msgstr "" #: libvips/mosaicing/match.c:228 libvips/mosaicing/mosaic1.c:537 msgid "xs1" msgstr "" #: libvips/mosaicing/match.c:229 libvips/mosaicing/match.c:236 #: libvips/mosaicing/mosaic1.c:538 libvips/mosaicing/mosaic1.c:545 msgid "Position of first secondary tie-point" msgstr "" #: libvips/mosaicing/match.c:235 libvips/mosaicing/mosaic1.c:544 msgid "ys1" msgstr "" #: libvips/mosaicing/match.c:242 libvips/mosaicing/mosaic1.c:551 msgid "xr2" msgstr "" #: libvips/mosaicing/match.c:243 libvips/mosaicing/match.c:250 #: libvips/mosaicing/mosaic1.c:552 libvips/mosaicing/mosaic1.c:559 msgid "Position of second reference tie-point" msgstr "" #: libvips/mosaicing/match.c:249 libvips/mosaicing/mosaic1.c:558 msgid "yr2" msgstr "" #: libvips/mosaicing/match.c:256 libvips/mosaicing/mosaic1.c:565 msgid "xs2" msgstr "" #: libvips/mosaicing/match.c:257 libvips/mosaicing/match.c:264 #: libvips/mosaicing/mosaic1.c:566 libvips/mosaicing/mosaic1.c:573 msgid "Position of second secondary tie-point" msgstr "" #: libvips/mosaicing/match.c:263 libvips/mosaicing/mosaic1.c:572 msgid "ys2" msgstr "" #: libvips/mosaicing/match.c:270 libvips/mosaicing/mosaic1.c:579 #: libvips/mosaicing/mosaic.c:232 #, fuzzy msgid "hwindow" msgstr "Windows-Fehler" #: libvips/mosaicing/match.c:271 libvips/mosaicing/mosaic1.c:580 #: libvips/mosaicing/mosaic.c:233 msgid "Half window size" msgstr "" #: libvips/mosaicing/match.c:277 libvips/mosaicing/mosaic1.c:586 #: libvips/mosaicing/mosaic.c:239 msgid "harea" msgstr "" #: libvips/mosaicing/match.c:278 libvips/mosaicing/mosaic1.c:587 #: libvips/mosaicing/mosaic.c:240 #, fuzzy msgid "Half area size" msgstr "falsche Bildgröße" #: libvips/mosaicing/match.c:284 libvips/mosaicing/mosaic1.c:593 msgid "Search" msgstr "" #: libvips/mosaicing/match.c:285 libvips/mosaicing/mosaic1.c:594 msgid "Search to improve tie-points" msgstr "" #: libvips/mosaicing/match.c:291 libvips/mosaicing/mosaic1.c:600 #: libvips/resample/affine.c:651 libvips/resample/mapim.c:561 #: libvips/resample/quadratic.c:328 libvips/resample/resize.c:376 #: libvips/resample/similarity.c:127 #, fuzzy msgid "Interpolate" msgstr "Zeilensprung" #: libvips/mosaicing/match.c:292 libvips/mosaicing/mosaic1.c:601 #: libvips/resample/affine.c:652 libvips/resample/mapim.c:562 #: libvips/resample/resize.c:377 libvips/resample/similarity.c:128 msgid "Interpolate pixels with this" msgstr "" #: libvips/mosaicing/matrixinvert.c:313 libvips/mosaicing/matrixinvert.c:329 #: libvips/mosaicing/matrixinvert.c:354 libvips/resample/transform.c:60 msgid "singular or near-singular matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:407 msgid "non-square matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:440 #, fuzzy msgid "invert a matrix" msgstr "ein Bild invertieren" #: libvips/mosaicing/matrixinvert.c:445 msgid "An square matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:451 libvips/mosaicing/matrixmultiply.c:160 #, fuzzy msgid "Output matrix" msgstr "Ausgabebild" #: libvips/mosaicing/matrixmultiply.c:143 #, fuzzy msgid "multiply two matrices" msgstr "zwei Bilder multiplizieren" #: libvips/mosaicing/matrixmultiply.c:148 msgid "First matrix to multiply" msgstr "" #: libvips/mosaicing/matrixmultiply.c:154 msgid "Second matrix to multiply" msgstr "" #: libvips/mosaicing/merge.c:116 #, fuzzy msgid "merge two images" msgstr "zwei Bilder hinzufügen" #: libvips/mosaicing/merge.c:141 #, fuzzy msgid "Horizontal or vertical merge" msgstr "horizontaler Versatz vom Ursprung" #: libvips/mosaicing/merge.c:147 #, fuzzy msgid "dx" msgstr "x" #: libvips/mosaicing/merge.c:148 msgid "Horizontal displacement from sec to ref" msgstr "" #: libvips/mosaicing/merge.c:154 #, fuzzy msgid "dy" msgstr "y" #: libvips/mosaicing/merge.c:155 msgid "Vertical displacement from sec to ref" msgstr "" #: libvips/mosaicing/merge.c:161 libvips/mosaicing/mosaic1.c:606 #: libvips/mosaicing/mosaic.c:246 #, fuzzy msgid "Max blend" msgstr "Mischung" #: libvips/mosaicing/merge.c:162 libvips/mosaicing/mosaic1.c:607 #: libvips/mosaicing/mosaic.c:247 #, fuzzy msgid "Maximum blend size" msgstr "Maximalwert des Bildes" #: libvips/mosaicing/mosaic1.c:494 #, fuzzy msgid "first-order mosaic of two images" msgstr "zwei Bilder subtrahieren" #: libvips/mosaicing/mosaic1.c:517 libvips/mosaicing/mosaic.c:198 #, fuzzy msgid "Horizontal or vertical mosaic" msgstr "horizontale Position des Maximums" #: libvips/mosaicing/mosaic1.c:613 libvips/mosaicing/mosaic.c:253 #, fuzzy msgid "Search band" msgstr "falsche Bänder" #: libvips/mosaicing/mosaic1.c:614 libvips/mosaicing/mosaic.c:254 msgid "Band to search for features on" msgstr "" #: libvips/mosaicing/mosaic.c:175 #, fuzzy msgid "mosaic two images" msgstr "zwei Bilder subtrahieren" #: libvips/mosaicing/mosaic.c:204 msgid "xref" msgstr "" #: libvips/mosaicing/mosaic.c:205 libvips/mosaicing/mosaic.c:212 msgid "Position of reference tie-point" msgstr "" #: libvips/mosaicing/mosaic.c:211 msgid "yref" msgstr "" #: libvips/mosaicing/mosaic.c:218 msgid "xsec" msgstr "" #: libvips/mosaicing/mosaic.c:219 libvips/mosaicing/mosaic.c:226 msgid "Position of secondary tie-point" msgstr "" #: libvips/mosaicing/mosaic.c:225 msgid "ysec" msgstr "" #: libvips/mosaicing/mosaic.c:260 libvips/mosaicing/mosaic.c:267 msgid "Integer offset" msgstr "" #: libvips/mosaicing/mosaic.c:261 libvips/mosaicing/mosaic.c:268 msgid "Detected integer offset" msgstr "" #: libvips/mosaicing/mosaic.c:275 msgid "Detected scale" msgstr "" #: libvips/mosaicing/mosaic.c:282 msgid "Detected rotation" msgstr "" #: libvips/mosaicing/mosaic.c:288 libvips/mosaicing/mosaic.c:295 msgid "First-order displacement" msgstr "" #: libvips/mosaicing/mosaic.c:289 libvips/mosaicing/mosaic.c:296 msgid "Detected first-order displacement" msgstr "" #: libvips/mosaicing/remosaic.c:89 #, c-format msgid "file \"%s\" not found" msgstr "Datei »%s« nicht gefunden" #: libvips/mosaicing/remosaic.c:117 #, c-format msgid "substitute image \"%s\" is not the same size as \"%s\"" msgstr "Bild zum Ersetzen »%s« hat nicht die gleiche Größe wie »%s«" #: libvips/mosaicing/remosaic.c:160 #, fuzzy msgid "rebuild an mosaiced image" msgstr "Bilddateien laden und speichern" #: libvips/mosaicing/remosaic.c:176 msgid "old_str" msgstr "" #: libvips/mosaicing/remosaic.c:177 msgid "Search for this string" msgstr "" #: libvips/mosaicing/remosaic.c:183 msgid "new_str" msgstr "" #: libvips/mosaicing/remosaic.c:184 msgid "And swap for this string" msgstr "" #: libvips/resample/affine.c:516 msgid "output coordinates out of range" msgstr "Ausgabekoordinaten außerhalb des Bereichs" #: libvips/resample/affine.c:640 #, fuzzy msgid "affine transform of an image" msgstr "Band aus einem Bild extrahieren" #: libvips/resample/affine.c:644 msgid "Matrix" msgstr "" #: libvips/resample/affine.c:645 msgid "Transformation matrix" msgstr "" #: libvips/resample/affine.c:657 #, fuzzy msgid "Output rect" msgstr "Ausgabe" #: libvips/resample/affine.c:658 msgid "Area of output to generate" msgstr "" #: libvips/resample/affine.c:664 libvips/resample/affine.c:671 #: libvips/resample/similarity.c:140 libvips/resample/similarity.c:147 #, fuzzy msgid "Output offset" msgstr "Ausgabewert" #: libvips/resample/affine.c:665 libvips/resample/similarity.c:141 msgid "Horizontal output displacement" msgstr "" #: libvips/resample/affine.c:672 libvips/resample/similarity.c:148 msgid "Vertical output displacement" msgstr "" #: libvips/resample/affine.c:678 libvips/resample/affine.c:685 #: libvips/resample/resize.c:360 libvips/resample/resize.c:367 #: libvips/resample/similarity.c:154 libvips/resample/similarity.c:161 #, fuzzy msgid "Input offset" msgstr "Xoffset" #: libvips/resample/affine.c:679 libvips/resample/resize.c:361 #: libvips/resample/similarity.c:155 msgid "Horizontal input displacement" msgstr "" #: libvips/resample/affine.c:686 libvips/resample/resize.c:368 #: libvips/resample/similarity.c:162 msgid "Vertical input displacement" msgstr "" #: libvips/resample/bicubic.cpp:629 #, fuzzy msgid "bicubic interpolation (Catmull-Rom)" msgstr "doppelt kubische Interpolation (Catmull-Rom)" #: libvips/resample/interpolate.c:183 msgid "VIPS interpolators" msgstr "VIPS-Interpolatoren" #: libvips/resample/interpolate.c:359 #, fuzzy msgid "nearest-neighbour interpolation" msgstr "Nächste-Nachbar-Interpolation" #: libvips/resample/interpolate.c:577 #, fuzzy msgid "bilinear interpolation" msgstr "Bilineare Interpolation" #: libvips/resample/lbb.cpp:872 #, fuzzy msgid "reduced halo bicubic" msgstr "doppelt kubische Halo-Reduzierung" #: libvips/resample/mapim.c:551 #, fuzzy msgid "resample with a map image" msgstr "ein Bild nachmachen" #: libvips/resample/mapim.c:556 msgid "Index pixels with this" msgstr "" #: libvips/resample/nohalo.cpp:1551 #, fuzzy msgid "edge sharpening resampler with halo reduction" msgstr "neues Kantenschärfungsmuster mit Halo-Reduzierung" #: libvips/resample/quadratic.c:225 msgid "coefficient matrix must have width 2" msgstr "" #: libvips/resample/quadratic.c:247 msgid "coefficient matrix must have height 1, 3, 4 or 6" msgstr "" #: libvips/resample/quadratic.c:318 msgid "resample an image with a quadratic transform" msgstr "" #: libvips/resample/quadratic.c:322 msgid "Coeff" msgstr "" #: libvips/resample/quadratic.c:323 msgid "Coefficient matrix" msgstr "" #: libvips/resample/quadratic.c:329 msgid "Interpolate values with this" msgstr "" #: libvips/resample/reduce.c:135 #, fuzzy msgid "reduce an image" msgstr "ein Bild nachmachen" #: libvips/resample/reduce.c:141 libvips/resample/reduceh.cpp:586 #: libvips/resample/shrink.c:149 libvips/resample/shrinkh.c:436 #, fuzzy msgid "Hshrink" msgstr "verkleinern" #: libvips/resample/reduce.c:142 libvips/resample/reduce.c:172 #: libvips/resample/reduceh.cpp:587 libvips/resample/reduceh.cpp:610 #: libvips/resample/shrink.c:150 libvips/resample/shrink.c:166 #: libvips/resample/shrinkh.c:437 libvips/resample/shrinkh.c:453 #, fuzzy msgid "Horizontal shrink factor" msgstr "falscher Schrumpffaktor %d" #: libvips/resample/reduce.c:148 libvips/resample/reducev.cpp:1070 #: libvips/resample/shrink.c:142 libvips/resample/shrinkv.c:625 #, fuzzy msgid "Vshrink" msgstr "verkleinern" #: libvips/resample/reduce.c:149 libvips/resample/reduce.c:179 #: libvips/resample/reducev.cpp:1071 libvips/resample/reducev.cpp:1094 #: libvips/resample/shrink.c:143 libvips/resample/shrink.c:173 #: libvips/resample/shrinkv.c:626 libvips/resample/shrinkv.c:642 #, fuzzy msgid "Vertical shrink factor" msgstr "falscher Schrumpffaktor %d" #: libvips/resample/reduce.c:155 libvips/resample/reduceh.cpp:593 #: libvips/resample/reducev.cpp:1077 libvips/resample/resize.c:343 msgid "Kernel" msgstr "" #: libvips/resample/reduce.c:156 libvips/resample/reduceh.cpp:594 #: libvips/resample/reducev.cpp:1078 libvips/resample/resize.c:344 msgid "Resampling kernel" msgstr "" #: libvips/resample/reduce.c:162 libvips/resample/reduceh.cpp:600 #: libvips/resample/reducev.cpp:1084 libvips/resample/resize.c:350 msgid "Gap" msgstr "" #: libvips/resample/reduce.c:163 libvips/resample/reduceh.cpp:601 #: libvips/resample/reducev.cpp:1085 libvips/resample/resize.c:351 msgid "Reducing gap" msgstr "" #: libvips/resample/reduce.c:171 libvips/resample/reduceh.cpp:609 #: libvips/resample/shrink.c:165 libvips/resample/shrinkh.c:452 #, fuzzy msgid "Xshrink" msgstr "verkleinern" #: libvips/resample/reduce.c:178 libvips/resample/reducev.cpp:1093 #: libvips/resample/shrink.c:172 libvips/resample/shrinkv.c:641 #, fuzzy msgid "Yshrink" msgstr "verkleinern" #: libvips/resample/reduce.c:187 libvips/resample/reduceh.cpp:618 #: libvips/resample/reducev.cpp:1102 libvips/resample/resize.c:384 msgid "Centre" msgstr "" #: libvips/resample/reduce.c:188 libvips/resample/reduceh.cpp:619 #: libvips/resample/reducev.cpp:1103 libvips/resample/resize.c:385 msgid "Use centre sampling convention" msgstr "" #: libvips/resample/reduceh.cpp:414 libvips/resample/reducev.cpp:848 #, fuzzy msgid "reduce factor should be >= 1.0" msgstr "Schrumpffaktoren sollten >=1 sein" #: libvips/resample/reduceh.cpp:437 libvips/resample/reducev.cpp:870 #, fuzzy msgid "reduce gap should be >= 1.0" msgstr "Schrumpffaktoren sollten >=1 sein" #: libvips/resample/reduceh.cpp:467 libvips/resample/reducev.cpp:900 #, fuzzy msgid "reduce factor too large" msgstr "Zoomfaktoren zu groß" #: libvips/resample/reduceh.cpp:580 libvips/resample/shrinkh.c:430 #, fuzzy msgid "shrink an image horizontally" msgstr "horizontal so oft wiederholen" #: libvips/resample/reducev.cpp:1064 libvips/resample/shrinkv.c:619 #, fuzzy msgid "shrink an image vertically" msgstr "vertikal so oft wiederholen" #: libvips/resample/resample.c:100 #, fuzzy msgid "resample operations" msgstr "arithmetische Transaktionen" #: libvips/resample/resize.c:323 #, fuzzy msgid "resize an image" msgstr "ein Bild nachmachen" #: libvips/resample/resize.c:329 #, fuzzy msgid "Scale factor" msgstr "Q-Faktor" #: libvips/resample/resize.c:330 msgid "Scale image by this factor" msgstr "" #: libvips/resample/resize.c:336 #, fuzzy msgid "Vertical scale factor" msgstr "vertikaler Versatz vom Ursprung" #: libvips/resample/resize.c:337 msgid "Vertical scale image by this factor" msgstr "" #: libvips/resample/shrink.c:133 #, fuzzy msgid "shrink an image" msgstr "ein Bild invertieren" #: libvips/resample/shrink.c:156 libvips/resample/shrinkh.c:443 #: libvips/resample/shrinkv.c:632 msgid "Ceil" msgstr "" #: libvips/resample/shrink.c:157 libvips/resample/shrinkh.c:444 #: libvips/resample/shrinkv.c:633 #, fuzzy msgid "Round-up output dimensions" msgstr "falsche Abmessungen" #: libvips/resample/shrinkh.c:352 libvips/resample/shrinkv.c:485 msgid "shrink factors should be >= 1" msgstr "Schrumpffaktoren sollten >=1 sein" #: libvips/resample/similarity.c:123 msgid "base similarity transform" msgstr "" #: libvips/resample/similarity.c:197 msgid "similarity transform of an image" msgstr "" #: libvips/resample/similarity.c:201 msgid "Scale by this factor" msgstr "" #: libvips/resample/similarity.c:208 libvips/resample/similarity.c:277 msgid "Rotate clockwise by this many degrees" msgstr "" #: libvips/resample/similarity.c:273 #, fuzzy msgid "rotate an image by a number of degrees" msgstr "Tangens des Bildes (Winkel in Grad)" #: libvips/resample/thumbnail.c:959 #, fuzzy msgid "thumbnail generation" msgstr "- Miniaturansichten-Generator" #: libvips/resample/thumbnail.c:974 #, fuzzy msgid "Target width" msgstr "Kachelbreite" #: libvips/resample/thumbnail.c:975 msgid "Size to this width" msgstr "" #: libvips/resample/thumbnail.c:981 #, fuzzy msgid "Target height" msgstr "Kachelhöhe" #: libvips/resample/thumbnail.c:982 #, fuzzy msgid "Size to this height" msgstr "Kachelhöhe" #: libvips/resample/thumbnail.c:989 msgid "Only upsize, only downsize, or both" msgstr "" #: libvips/resample/thumbnail.c:995 msgid "No rotate" msgstr "" #: libvips/resample/thumbnail.c:996 msgid "Don't use orientation tags to rotate image upright" msgstr "" #: libvips/resample/thumbnail.c:1002 msgid "Crop" msgstr "" #: libvips/resample/thumbnail.c:1003 msgid "Reduce to fill target rectangle, then crop" msgstr "" #: libvips/resample/thumbnail.c:1009 #, fuzzy msgid "Linear" msgstr "Zeilen" #: libvips/resample/thumbnail.c:1010 msgid "Reduce in linear light" msgstr "" #: libvips/resample/thumbnail.c:1017 #, fuzzy msgid "Fallback input profile" msgstr "Profil" #: libvips/resample/thumbnail.c:1024 #, fuzzy msgid "Fallback output profile" msgstr "kein eingebettetes Profil" #: libvips/resample/thumbnail.c:1050 #, fuzzy msgid "Auto rotate" msgstr "Winkel zum Drehen eines Bildes" #: libvips/resample/thumbnail.c:1051 msgid "Use orientation tags to rotate image upright" msgstr "" #: libvips/resample/thumbnail.c:1061 #, fuzzy msgid "Import profile" msgstr "Profil" #: libvips/resample/thumbnail.c:1062 msgid "Fallback import profile" msgstr "" #: libvips/resample/thumbnail.c:1068 #, fuzzy msgid "Export profile" msgstr "Profil" #: libvips/resample/thumbnail.c:1069 msgid "Fallback export profile" msgstr "" # http://www.dateiendung.com/format/mat #: libvips/resample/thumbnail.c:1210 #, fuzzy msgid "generate thumbnail from file" msgstr "Mat aus Datei laden" #: libvips/resample/thumbnail.c:1217 #, fuzzy msgid "Filename to read from" msgstr "Name der Datei, aus der geladen werden soll" #: libvips/resample/thumbnail.c:1457 msgid "generate thumbnail from buffer" msgstr "" #: libvips/resample/thumbnail.c:1470 libvips/resample/thumbnail.c:1684 #, fuzzy msgid "Extra options" msgstr "unäre Transaktionen" #: libvips/resample/thumbnail.c:1471 libvips/resample/thumbnail.c:1685 msgid "Options that are passed on to the underlying loader" msgstr "" #: libvips/resample/thumbnail.c:1671 msgid "generate thumbnail from source" msgstr "" #: libvips/resample/thumbnail.c:1797 #, fuzzy msgid "generate thumbnail from image" msgstr "Band aus einem Bild extrahieren" #: libvips/resample/vsqbs.cpp:378 msgid "B-Splines with antialiasing smoothing" msgstr "B-Splines mit Kantenglättung" #: tools/vips.c:166 #, c-format msgid "'%s' is not the name of a vips class" msgstr "" #: tools/vips.c:282 #, fuzzy, c-format msgid "'%s' is not the name of a vips operation" msgstr "genannte VIPS-Transaktion ausführen" #: tools/vips.c:355 #, c-format msgid "no package or function \"%s\"" msgstr "kein Paket oder Funktion »%s«" #: tools/vips.c:584 #, fuzzy msgid "execute vips operation OPER" msgstr "genannte VIPS-Transaktion ausführen" #: tools/vips.c:627 #, fuzzy msgid "Operation help" msgstr "Transaktion" #: tools/vips.c:706 msgid "[ACTION] [OPTIONS] [PARAMETERS] - VIPS driver program" msgstr "[AKTION] [OPTIONEN] [PARAMETER] - VIPS-Treiberprogramm" #: tools/vips.c:772 #, fuzzy, c-format msgid "unable to load \"%s\" -- %s" msgstr "»mmap« nicht möglich: \"%s\" - %s" #: tools/vips.c:916 #, c-format msgid "unknown action \"%s\"" msgstr "unbekannte Aktion »%s«" #: tools/vipsedit.c:129 #, c-format msgid "'%s' is not a positive integer" msgstr "»%s« ist keine positive Ganzzahl" #: tools/vipsedit.c:142 msgid "unable to start VIPS" msgstr "VIPS kann nicht gestartet werden" #: tools/vipsedit.c:165 #, fuzzy msgid "vipsedit - edit vips file header" msgstr "»vipsfile« - »vipsfile«-Kopfzeilen bearbeiten" #: tools/vipsedit.c:193 #, fuzzy, c-format msgid "usage: %s [OPTION...] vips-file\n" msgstr "Aufruf: %s [OPTION …] vipsfile\n" #: tools/vipsedit.c:200 #, c-format msgid "could not open image %s" msgstr "Bild %s konnte nicht geöffnet werden" #: tools/vipsedit.c:206 #, c-format msgid "could not read VIPS header for %s" msgstr "VIPS-Kopfzeilen für %s konnten nicht gelesen werden" #: tools/vipsedit.c:216 #, c-format msgid "bad endian-ness %s, should be 'big' or 'little'" msgstr "falsche Byte-Reihenfolge %s, sollte »big« oder »little« sein" #: tools/vipsedit.c:230 #, c-format msgid "bad format %s" msgstr "falsches Format %s" #: tools/vipsedit.c:244 #, c-format msgid "bad interpretation %s" msgstr "falsche Interpretation »%s« " #: tools/vipsedit.c:254 #, c-format msgid "bad coding %s" msgstr "falsche Kodierung %s" #: tools/vipsedit.c:268 #, c-format msgid "could not seek on %s" msgstr "auf %s konnte nicht gesucht werden" #: tools/vipsedit.c:271 #, c-format msgid "could not write to %s" msgstr "auf %s konnte nicht geschrieben werden" #: tools/vipsedit.c:278 msgid "could not get ext data" msgstr "zusätzliche Daten konnten nicht abgefragt werden" #: tools/vipsedit.c:287 msgid "could not set extension" msgstr "Erweiterung konnte nicht gesetzt werden" #: tools/vipsheader.c:221 msgid "- print image header" msgstr "- Bild-Kopfzeilen ausgeben" #: tools/vipsthumbnail.c:459 #, fuzzy msgid "bad geometry spec" msgstr "falsche Gittergeometrie" #: tools/vipsthumbnail.c:528 msgid "- thumbnail generator" msgstr "- Miniaturansichten-Generator" #~ msgid "bad image size" #~ msgstr "falsche Bildgröße" #, fuzzy #~ msgid "unable to ping blob" #~ msgstr "»%s« kann nicht geöffnet werden" #~ msgid "coords outside image" #~ msgstr "Koordinaten außerhalb des Bildes" #~ msgid "absolute value" #~ msgstr "absoluter Wert" #~ msgid "average value of image" #~ msgstr "Durchschnittswert des Bildes" # im_exptra() transforms element x of input to # pow(e, x) in output. #~ msgid "10^pel of image" #~ msgstr "10^pel des Bildes" #~ msgid "e^pel of image" #~ msgstr "e^pel des Bildes" #~ msgid "x^pel of image" #~ msgstr "x^pel des Bildes" #~ msgid "[x,y,z]^pel of image" #~ msgstr "[x,y,z]^pel des Bildes" #~ msgid "photographic negative" #~ msgstr "Fotonegativ" #~ msgid "calculate a*in + b = outfile" #~ msgstr "Berechnen von a*in + b = Ausgabedatei" #~ msgid "vectors not equal length" #~ msgstr "Vektoren ungleicher Länge" #~ msgid "calculate a*in + b -> out, a and b vectors" #~ msgstr "Berechnen von a*in + b -> out, a und b Vektoren" #~ msgid "log10 of image" #~ msgstr "log10 des Bildes" #~ msgid "atan of image (result in degrees)" #~ msgstr "Arkustangens des Bildes (Ergebnis in Grad)" #~ msgid "cos of image (angles in degrees)" #~ msgstr "Kosinus des Bildes (Winkel in Grad)" #~ msgid "acos of image (result in degrees)" #~ msgstr "Arkuskosinus des Bildes (Ergebnis in Grad)" # hinter diesem String folgt ein Flag. #~ msgid "round to smallest integer value not less than" #~ msgstr "auf kleinsten ganzzahligen Wert runden, nicht weniger als" # hinter diesem String folgt ein Flag. #~ msgid "round to largest integer value not greater than" #~ msgstr "auf größten ganzzahligen Wert runden, nicht größer als" # hinter diesem String folgt ein Flag. #~ msgid "round to nearest integer value" #~ msgstr "auf nächsten ganzzahligen Wert runden" #~ msgid "sin of image (angles in degrees)" #~ msgstr "Sinus des Bildes (Winkel in Grad)" #~ msgid "average image bands" #~ msgstr "durchschnittliche Bildbänder" #~ msgid "unit vector in direction of value" #~ msgstr "Einheitsvektor in Richtung des Wertes" #~ msgid "asin of image (result in degrees)" #~ msgstr "Arkussinus des Bildes (Ergebnis in Grad)" #~ msgid "position of maximum value of image, averaging in case of draw" #~ msgstr "" #~ "Position des Maximalwerts des Bildes, durchschnittlich im Fall des " #~ "Zeichnens" #~ msgid "position and value of n maxima of image" #~ msgstr "Position und Wert von n Maxima des Bildes" #~ msgid "position and value of n minima of image" #~ msgstr "Position und Wert von n Minima des Bildes" #~ msgid "measure averages of a grid of patches" #~ msgstr "Durchschnittsmaße eine Gitters aus Flickstücken" #~ msgid "remainder after integer division by a constant" #~ msgstr "Rest nach Ganzzahldivision durch eine Konstante" #~ msgid "remainder after integer division by a vector of constants" #~ msgstr "Rest nach Ganzzahldivision durch einen Vektor von Konstanten" #~ msgid "pel^x of image" #~ msgstr "pel^x des Bildes" #~ msgid "pel^[x,y,z] of image" #~ msgstr "pel^[x,y,z] des Bildes" #~ msgid "many image statistics in one pass" #~ msgstr "viele Bildstatistiken in einem Durchgang" #~ msgid "pixelwise linear regression" #~ msgstr "bildpunktweise lineare Regression" #~ msgid "phase of cross power spectrum of two complex images" #~ msgstr "Phase des Kreuzleistungsspektrums zweier komplexer Bilder" #~ msgid "single band images only" #~ msgstr "nur Einzelbandbilder" #~ msgid "uncoded images only" #~ msgstr "nur unkodierte Bilder" #~ msgid "pow( left, right)" #~ msgstr "pow( links, rechts)" #~ msgid "pow( @in, @c )" #~ msgstr "pow( @in, @c )" #, c-format #~ msgid "" #~ "intent %d (%s) not supported by profile \"%s\"; falling back to default " #~ "intent (usually PERCEPTUAL)" #~ msgstr "" #~ "Ziel-%d (%s) nicht von Profil »%s« unterstützt; Rückfall auf " #~ "Standardabsicht (normalerweise WAHRNEHMUNG)" #~ msgid "CMYK input profile needs a 4 band input image" #~ msgstr "CMYK-Eingabeprofil benötigt ein Eingabebild mit vier Bändern" #~ msgid "RGB input profile needs a 3 band input image" #~ msgstr "RGB-Eingabeprofil benötigt ein Eingabebild mit drei Bändern" #~ msgid "uchar or ushort input only" #~ msgstr "nur »uchar« oder »ushort«-Eingabe" #, c-format #~ msgid "" #~ "intent %d (%s) not supported by profile; falling back to default intent " #~ "(usually PERCEPTUAL)" #~ msgstr "" #~ "Ziel-%d (%s) nicht vom Profil unterstützt; Rückfall auf Standardabsicht " #~ "(normalerweise WAHRNEHMUNG)" #~ msgid "CMYK profile needs a 4 band input image" #~ msgstr "CMYK-Profil benötigt ein Eingabebild mit vier Bändern" #~ msgid "RGB profile needs a 3 band input image" #~ msgstr "RGB-Profil benötigt ein Eingabebild mit drei Bändern" #~ msgid "lcms library not linked to this VIPS" #~ msgstr "gegen die »lcms«-Bibliothek wird in diesem VIPS nicht verlinkt" #~ msgid "lmcs library not linked to this VIPS" #~ msgstr "gegen die »lmcs«-Bibliothek wird in diesem VIPS nicht verlinkt" #~ msgid "out of range [0,255]" #~ msgstr "außerhalb des Bereichs [0,255]" #~ msgid "bad display type" #~ msgstr "falsche Anzeigetyp" #~ msgid "display unknown" #~ msgstr "Anzeige unbekannt" #~ msgid "input not 3-band uncoded char" #~ msgstr "Eingabe ist kein unkodiertes Zeichen mit drei Bändern" #~ msgid "3-band uncoded float only" #~ msgstr "nur unkodierte Fließkommazahlen mit drei Bändern" #~ msgid "bad greyscale mask size" #~ msgstr "falsche Grauskala-Maskengröße" #, c-format #~ msgid "bad greyscale mask value, row %d" #~ msgstr "falscher Grauskala-Maskenwert, Reihe %d" #, c-format #~ msgid "%d underflows and %d overflows detected" #~ msgstr "%d Unter- und %d Überläufe entdeckt" #~ msgid "pangoft2 support disabled" #~ msgstr "Pangoft2-Unterstützung deaktiviert" #~ msgid "zoom factors should be >= 0" #~ msgstr "Zoomfaktoren sollten >=0 sein" #~ msgid "vectors not same length" #~ msgstr "Vektoren ungleicher Länge" #~ msgid "direction" #~ msgstr "Richtung" #~ msgid "bad arguments" #~ msgstr "falsche Argumente" #~ msgid "image does not have that many bands" #~ msgstr "Bild hat nicht so viele Bänder" #~ msgid "factors should both be >= 1" #~ msgstr "beide Faktoren sollten >=1 sein" #~ msgid "parameters would result in zero size output image" #~ msgstr "Parameter würden zu einem Ausgabebild der Größe Null führen" #, c-format #~ msgid "%d overflows and %d underflows detected" #~ msgstr "%d Über- und %d Unterläufe entdeckt" #~ msgid "expect 1xN or Nx1 input mask" #~ msgstr "1xN- oder Nx1-Eingabemaske wird erwartet" # ref und in sind Objekte #~ msgid "ref not smaller than or equal to in" #~ msgstr "»ref« nicht kleiner oder gleich »in«" #~ msgid "end of file while skipping start" #~ msgstr "Dateiende während des Überspringens des Startes" #, c-format #~ msgid "unexpected EOF, line %d col %d" #~ msgstr "unerwartetes Dateiende, Zeile %d, Spalte %d" #, c-format #~ msgid "unexpected EOL, line %d col %d" #~ msgstr "unerwartetes Zeilenende, Zeile %d, Spalte %d" #, c-format #~ msgid "required field %d=%d, not %d" #~ msgstr "benötigtes Feld %d=%d, nicht %d" #~ msgid "4 or 5 bands CMYK TIFF only" #~ msgstr "nur CMYK-TIFF mit vier oder fünf Bändern" #, c-format #~ msgid "" #~ "no resolution information for TIFF image \"%s\" -- defaulting to 1 pixel " #~ "per mm" #~ msgstr "" #~ "Keine Auflösungsinformationen für TIFF-Bild »%s« – Standard auf 1 " #~ "Bildpunkt pro mm" #, c-format #~ msgid "unsupported sample format %d for lab image" #~ msgstr "nicht unterstütztes Musterformat %d für LAB-Bild" #, c-format #~ msgid "unsupported depth %d for LAB image" #~ msgstr "nicht unterstützte Tiefe %d für LAB-Bild" #, c-format #~ msgid "unsupported sample format %d for greyscale image" #~ msgstr "nicht unterstütztes Musterformat %d für Graustufenbild" #, c-format #~ msgid "unsupported depth %d for greyscale image" #~ msgstr "nicht unterstützte Tiefe %d für Graustufenbild" #, c-format #~ msgid "unsupported sample format %d for rgb image" #~ msgstr "nicht unterstütztes Musterformat %d für RGB-Bild" #, c-format #~ msgid "unsupported depth %d for RGB image" #~ msgstr "nicht unterstützte Tiefe %d für RGB-Bild" #~ msgid "error writing output" #~ msgstr "Fehler beim Schreiben der Ausgabe" #~ msgid "File descriptor" #~ msgstr "Datei-Deskriptor" #~ msgid "error setting JPEG resolution" #~ msgstr "Fehler beim Setzen der JPEG-Auflösung" #, c-format #~ msgid "" #~ "unable to ping file \"%s\"\n" #~ "libMagick error: %s %s" #~ msgstr "" #~ "Datei »%s« kann nicht angepingt werden\n" #~ "libMagick-Fehler: %s %s" #, c-format #~ msgid "unable to write \"%s\"" #~ msgstr "»%s« kann nicht geschrieben werden" #~ msgid "error reading resolution" #~ msgstr "Fehler beim Lesen der Auflösung" #~ msgid "bad int" #~ msgstr "falsche Ganzzahl" #~ msgid "bad float" #~ msgstr "falsche Fließkommazahl" #~ msgid "not whitespace before start of binary data" #~ msgstr "kein Leerraum vor dem Start der binären Daten" #~ msgid "write error ... disc full?" #~ msgstr "Schreibfehler … Platte voll?" #~ msgid "binary >8 bit images must be float" #~ msgstr "binäre Bilder >8 Bit müssen aus Fließkommazahlen bestehen" #~ msgid "layer buffer exhausted -- try making TIFF output tiles smaller" #~ msgstr "" #~ "Ebenenpuffer aufgebraucht – versuchen Sie die TIFF-Ausgabekacheln zu " #~ "verkleinern" #~ msgid "internal error #9876345" #~ msgstr "interner Fehler #9876345" #~ msgid "can't have strip pyramid -- enabling tiling" #~ msgstr "" #~ "nicht ummantelte Pyramide nicht möglich – Zerteilung wird eingeschaltet" #~ msgid "unsigned 8-bit int, 16-bit int, and 32-bit float only" #~ msgstr "nur vorzeichenlose 8-Bit-Ganzzahl und 32-Bit-Fließkommazahl" #~ msgid "1 to 5 bands only" #~ msgstr "nur 1 bis 5 Bänder" #~ msgid "images do not match" #~ msgstr "Bilder passen nicht zusammen" #~ msgid "mask sizes power of 2 only" #~ msgstr "Maskengröße nur Potenzen von 2" #~ msgid "unimplemented mask type" #~ msgstr "nicht implementierter Maskentyp" #~ msgid "bad args" #~ msgstr "falsche Argumente" #~ msgid "bad args (f)" #~ msgstr "falsche Argumente (f)" #~ msgid "bad args (ac)" #~ msgstr "falsche Argumente (ac)" #~ msgid "dimension should be in (2,3)" #~ msgstr "Dimension sollte in (2,3) liegen" #~ msgid "window too small" #~ msgstr "Fenster zu klein" #~ msgid "bad input matrix size" #~ msgstr "falsche Eingabematrix-Größe" #~ msgid "bad in_max, out_max parameters" #~ msgstr "falsche »in_max«-, »out_max«-Parameter" #~ msgid "bad Lb, Lw parameters" #~ msgstr "falsche »Lb«-, »Lw«-Parameter" #~ msgid "Ps not in range [0.0,1.0]" #~ msgstr "»Ps« nicht im Bereich [0.0,1.0]" #~ msgid "Pm not in range [0.0,1.0]" #~ msgstr "»Pm« nicht im Bereich [0.0,1.0]" #~ msgid "Ph not in range [0.0,1.0]" #~ msgstr "»Ph« nicht im Bereich [0.0,1.0]" #~ msgid "S not in range [-30,+30]" #~ msgstr "»S« nicht im Bereich [-30,+30]" #~ msgid "M not in range [-30,+30]" #~ msgstr "»M« nicht im Bereich [-30,+30]" #~ msgid "H not in range [-30,+30]" #~ msgstr "»H« nicht im Bereich [-30,+30]" #~ msgid "bad lut_size" #~ msgstr "falsche »lut_size«" #~ msgid "mask image not 1 band 8 bit uncoded" #~ msgstr "Maskenbild nicht 8-Bit-kodiert mit einem Band" #, c-format #~ msgid "unable to set property \"%s\" to value \"%s\"." #~ msgstr "Eigenschaft »%s« kann nicht auf Wert »%s« gesetzt werden." #, c-format #~ msgid "start function failed for image %s" #~ msgstr "Startfunktion für Bild %s fehlgeschlagen" #~ msgid "evaluate with N concurrent threads" #~ msgstr "mit N gleichzeitigen Threads auswerten" #~ msgid "set tile width to N (DEBUG)" #~ msgstr "Bildbreite auf N setzen (DEBUG)" #~ msgid "set tile height to N (DEBUG)" #~ msgstr "Bildhöhe auf N setzen (DEBUG)" #~ msgid "set thinstrip height to N (DEBUG)" #~ msgstr "»thinstrip«-Höhe auf N setzen (DEBUG)" #~ msgid "set fatstrip height to N (DEBUG)" #~ msgstr "»fatstrip«-Höhe auf N setzen (DEBUG)" #~ msgid "show progress feedback" #~ msgstr "Fortschrittsrückmeldung anzeigen" #~ msgid "leak-check on exit" #~ msgstr "Lückenprüfung beim Beenden" #~ msgid "images larger than N are decompressed to disc" #~ msgstr "Bilder, die größer als N sind, werden auf die Platte dekomprimiert" #~ msgid "disable vectorised versions of operations" #~ msgstr "vektorgesteuerte Versionen von Transaktionen deaktivieren" #~ msgid "cache at most N operations" #~ msgstr "höchstens N Transaktionen zwischenspeichern" #~ msgid "cache at most N bytes in memory" #~ msgstr "höchstens N Byte zwischenspeichern" #~ msgid "allow at most N open files" #~ msgstr "höchstens N offene Dateien erlauben" #~ msgid "trace operation cache" #~ msgstr "Transaktionszwischenspeicher aufzeichnen" #~ msgid "dump operation cache on exit" #~ msgstr "Transaktionszwischenspeicher beim Beenden ausgeben" #~ msgid "VIPS Options" #~ msgstr "VIPS-Optionen" #~ msgid "Show VIPS options" #~ msgstr "VIPS-Optionen anzeigen" #, c-format #~ msgid "%dx%d %s, %d band, %s" #~ msgid_plural "%dx%d %s, %d bands, %s" #~ msgstr[0] "%dx%d %s, %d Band, %s" #~ msgstr[1] "%dx%d %s, %d Bänder, %s" #, c-format #~ msgid " %s, %d band, %s" #~ msgid_plural " %s, %d bands, %s" #~ msgstr[0] " %s, %d band, %s" #~ msgstr[1] " %s, %d Bänder, %s" #, c-format #~ msgid "" #~ "map failed (%s), running very low on system resources, expect a crash soon" #~ msgstr "" #~ "»map« fehlgeschlagen (%s), die Systemressourcen werden knapp, ein Absturz " #~ "steht bevor" #~ msgid "too little data" #~ msgstr "zu wenige Daten" #~ msgid "bytes" #~ msgstr "Byte" #~ msgid "KB" #~ msgstr "KB" #~ msgid "MB" #~ msgstr "MB" #~ msgid "TB" #~ msgstr "TB" #, c-format #~ msgid "unable to make temporary file %s" #~ msgstr "temporäre Datei %s kann nicht erstellt werden" #~ msgid "usage:" #~ msgstr "Aufruf:" #, c-format #~ msgid "%s: " #~ msgstr "%s: " #~ msgid "vips diagnostic" #~ msgstr "Vips-Diagnose" #~ msgid "vips warning" #~ msgstr "Vips-Warnung" #~ msgid "nonsense mask parameters" #~ msgstr "unsinnige Maskenparameter" #~ msgid "mask must be 1D" #~ msgstr "Maske muss 1D sein" #~ msgid "dir not 0 or 1" #~ msgstr "»dir« nicht 0 oder 1" #~ msgid "flag should be 0 (horizontal) or 1 (vertical)" #~ msgstr "Schalter sollte 0 (horizontal) oder 1 (vertikal) sein" #~ msgid "image too small for window" #~ msgstr "Bild zu klein für Fenster" #~ msgid "zero input images!" #~ msgstr "null Eingabebilder" #, c-format #~ msgid "index should be in range 0 - %d" #~ msgstr "Index sollte im Bereich 0 - %d liegen" #~ msgid "size must be even and positive" #~ msgstr "Größe muss gerade und positiv sein" #~ msgid "wrong sizes" #~ msgstr "falsche Größen" #~ msgid "calloc failed" #~ msgstr "»calloc« fehlgeschlagen" #~ msgid "factor should be in [1,0)" #~ msgstr "Faktor sollte in [0,1) liegen" #~ msgid "shift by zero: falling back to im_copy" #~ msgstr "verschieben um Null: Rückfall auf »im_copy«" #~ msgid "would result in zero size output image" #~ msgstr "würde in einem Ausgabebild der Größe Null resultieren" #~ msgid "image and band_fmt must match in sign" #~ msgstr "Bild und Band-Fmt müssen im Kennzeichen zusammenpassen" #, c-format #~ msgid "ioctl(0x%x) failed: %s" #~ msgstr "ioctl(0x%x) fehlgeschlagen: %s" #, c-format #~ msgid "cannot open video device \"%s\"" #~ msgstr "Videogerät »%s« kann nicht geöffnet werden" #~ msgid "cannot get video capability" #~ msgstr "Videofähigkeit kann nicht abgefragt werden" #~ msgid "card cannot capture to memory" #~ msgstr "Karte kann nicht in Speicher digitalisiert werden" #~ msgid "unable to map memory" #~ msgstr "Speicher kann nicht abgebildet werden" #, c-format #~ msgid "channel not between 0 and %d" #~ msgstr "Kanal nicht zwischen 0 und %d" #~ msgid "compiled without im_video_v4l1 support" #~ msgstr "ohne »im_video_v4l1«-Unterstützung kompiliert" #~ msgid "tag file as big or little-endian" #~ msgstr "Kennzeichendatei als Big- oder Little-Endian" #~ msgid "set width to N pixels" #~ msgstr "Breite auf N Bildpunkte setzen" #~ msgid "set height to N pixels" #~ msgstr "Höhe auf N Bildpunkte setzen" #~ msgid "set BandFmt to F (eg. uchar, float)" #~ msgstr "»BandFmt« auf F setzen (z.B. uchar, float)" #~ msgid "set interpretation to I (eg. xyz)" #~ msgstr "Interpretation aif I setzen (z.B. xyz)" #~ msgid "set Coding to C (eg. labq)" #~ msgstr "Kodierung auf C setzen (z.B. labq)" #~ msgid "set Xres to R pixels/mm" #~ msgstr "»Xres« auf R Bildpunkte/mm setzen" #~ msgid "set Yres to R pixels/mm" #~ msgstr "»Yres« auf R Bildpunkte/mm setzen" #~ msgid "set Xoffset to N pixels" #~ msgstr "»Xoffset« auf N Bildpunkte setzen" #~ msgid "set Yoffset to N pixels" #~ msgstr "»Yoffset« auf N Bildpunkte setzen" #~ msgid "replace extension block with stdin" #~ msgstr "Erweiterungsblock mit STDIN ersetzen" #~ msgid "set Xsize to N (deprecated, use width)" #~ msgstr "»Xsize« auf N setzen (missbilligt, benutzen Sie »width«)" #~ msgid "set Ysize to N (deprecated, use height)" #~ msgstr "»Ysize« auf N setzen (missbilligt, benutzen Sie »height«)" #~ msgid "set Type to T (deprecated, use interpretation)" #~ msgstr "Typ auf N setzen (missbilligt, benutzen Sie »interpretation«" #, c-format #~ msgid "bad file name format '%s'" #~ msgstr "falsches Dateinamensformat »%s«" #~ msgid "show all fields" #~ msgstr "alle Felder anzeigen" #~ msgid "" #~ "print value of FIELD (\"getext\" reads extension block, \"Hist\" reads " #~ "image history)" #~ msgstr "" #~ "Wert von FELD ausgeben (»getext« liest Erweiterungsblock, »Hist« liest " #~ "Bildchronik)" #~ msgid "allocation failure in mergeup" #~ msgstr "Reservierung in »mergeup« gescheitert" #~ msgid "Need more than one image" #~ msgstr "Mehr als ein Bild benötigt" #~ msgid "load PLUGIN" #~ msgstr "ERWEITERUNG laden" #~ msgid "PLUGIN" #~ msgstr "ERWEITERUNG" #~ msgid "list classes|packages|all|package-name|operation-name" #~ msgstr "classes|packages|all|package-name|operation-name aufführen" #~ msgid "generate headers for C++ binding" #~ msgstr "Header für C++-Anbindung erzeugen" #~ msgid "generate bodies for C++ binding" #~ msgstr "Rumpfdaten für C++-Anbindung erzeugen" #~ msgid "generate links for vips/bin" #~ msgstr "Verweise für VIPS/Bin erzeugen" #~ msgid "possible actions:\n" #~ msgstr "mögliche Aktionen:\n" #~ msgid "SIZE" #~ msgstr "GRÖẞE" #~ msgid "set output to FORMAT" #~ msgstr "Ausgabe auf FORMAT setzen" #~ msgid "FORMAT" #~ msgstr "FORMAT" #~ msgid "resample with INTERPOLATOR" #~ msgstr "neues Muster mit INTERPOLATOR erstellen" #~ msgid "INTERPOLATOR" #~ msgstr "INTERPOLATOR" #~ msgid "don't sharpen thumbnail" #~ msgstr "Miniaturansicht nicht schärfen" #~ msgid "export with PROFILE" #~ msgstr "mit PROFIL exportieren" #~ msgid "PROFILE" #~ msgstr "PROFIL" #~ msgid "import untagged images with PROFILE" #~ msgstr "nicht gekennzeichnetes Bild mit PROFIL importieren" #~ msgid "don't delete profile from exported image" #~ msgstr "Profil aus exportiertem Bild nicht löschen" libvips-8.18.2/po/en_GB.po000066400000000000000000005261221516303661500152300ustar00rootroot00000000000000# en_GB for vips # Copyright (C) 2017 # This file is distributed under the same license as the vips package. # John Cupitt , 2017. # msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-06-05 11:45+0200\n" "Last-Translator: John Cupitt \n" "Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: libvips/arithmetic/abs.c:200 msgid "absolute value of an image" msgstr "" #: libvips/arithmetic/add.c:178 msgid "add two images" msgstr "" #: libvips/arithmetic/arithmetic.c:185 #, c-format msgid "not one band or %d bands" msgstr "" #: libvips/arithmetic/arithmetic.c:190 libvips/foreign/spngsave.c:422 msgid "bad bands" msgstr "" #: libvips/arithmetic/arithmetic.c:518 msgid "arithmetic operations" msgstr "" #: libvips/arithmetic/arithmetic.c:524 libvips/arithmetic/avg.c:235 #: libvips/arithmetic/deviate.c:237 libvips/arithmetic/hist_find.c:431 #: libvips/arithmetic/hist_find_indexed.c:475 #: libvips/arithmetic/hist_find_ndim.c:313 libvips/arithmetic/hough.c:179 #: libvips/arithmetic/max.c:452 libvips/arithmetic/measure.c:201 #: libvips/arithmetic/min.c:452 libvips/arithmetic/stats.c:442 #: libvips/colour/CMYK2XYZ.c:126 libvips/colour/colour.c:316 #: libvips/colour/colourspace.c:566 libvips/colour/XYZ2CMYK.c:125 #: libvips/conversion/conversion.c:332 libvips/conversion/switch.c:202 #: libvips/convolution/canny.c:448 libvips/convolution/convolution.c:124 #: libvips/convolution/correlation.c:162 libvips/convolution/edge.c:223 #: libvips/convolution/gaussblur.c:138 libvips/convolution/sharpen.c:328 #: libvips/create/create.c:116 libvips/foreign/foreign.c:1223 #: libvips/freqfilt/freqfilt.c:93 libvips/histogram/case.c:252 #: libvips/histogram/hist_entropy.c:117 libvips/histogram/hist_equal.c:120 #: libvips/histogram/hist_local.c:367 libvips/histogram/hist_norm.c:147 #: libvips/histogram/histogram.c:204 libvips/histogram/hist_plot.c:339 #: libvips/histogram/maplut.c:750 libvips/histogram/stdif.c:300 #: libvips/iofuncs/system.c:284 libvips/morphology/morph.c:960 #: libvips/morphology/rank.c:564 libvips/mosaicing/global_balance.c:1924 #: libvips/mosaicing/match.c:208 libvips/mosaicing/matrixinvert.c:450 #: libvips/mosaicing/matrixmultiply.c:159 libvips/mosaicing/merge.c:134 #: libvips/mosaicing/mosaic1.c:510 libvips/mosaicing/mosaic.c:191 #: libvips/mosaicing/remosaic.c:170 libvips/resample/resample.c:110 #: libvips/resample/thumbnail.c:968 msgid "Output" msgstr "" #: libvips/arithmetic/arithmetic.c:525 libvips/arithmetic/hough.c:180 #: libvips/colour/CMYK2XYZ.c:127 libvips/colour/colour.c:317 #: libvips/colour/colourspace.c:567 libvips/colour/XYZ2CMYK.c:126 #: libvips/conversion/conversion.c:333 libvips/conversion/switch.c:203 #: libvips/convolution/canny.c:449 libvips/convolution/convolution.c:125 #: libvips/convolution/correlation.c:163 libvips/convolution/edge.c:224 #: libvips/convolution/gaussblur.c:139 libvips/convolution/sharpen.c:329 #: libvips/create/create.c:117 libvips/foreign/foreign.c:1224 #: libvips/freqfilt/freqfilt.c:94 libvips/histogram/case.c:253 #: libvips/histogram/hist_equal.c:121 libvips/histogram/hist_local.c:368 #: libvips/histogram/hist_norm.c:148 libvips/histogram/histogram.c:205 #: libvips/histogram/hist_plot.c:340 libvips/histogram/maplut.c:751 #: libvips/histogram/stdif.c:301 libvips/iofuncs/system.c:285 #: libvips/morphology/morph.c:961 libvips/morphology/rank.c:565 #: libvips/mosaicing/global_balance.c:1925 libvips/mosaicing/match.c:209 #: libvips/mosaicing/merge.c:135 libvips/mosaicing/mosaic1.c:511 #: libvips/mosaicing/mosaic.c:192 libvips/mosaicing/remosaic.c:171 #: libvips/resample/resample.c:111 libvips/resample/thumbnail.c:969 msgid "Output image" msgstr "" #: libvips/arithmetic/avg.c:227 msgid "find image average" msgstr "" #: libvips/arithmetic/avg.c:236 libvips/arithmetic/deviate.c:238 #: libvips/arithmetic/max.c:453 libvips/arithmetic/min.c:453 #: libvips/histogram/hist_entropy.c:118 msgid "Output value" msgstr "" #: libvips/arithmetic/binary.c:89 msgid "binary operations" msgstr "" #: libvips/arithmetic/binary.c:96 libvips/arithmetic/find_trim.c:216 #: libvips/arithmetic/measure.c:221 libvips/colour/colour.c:585 #: libvips/conversion/extract.c:200 libvips/draw/draw_flood.c:593 #: libvips/draw/draw_rect.c:173 libvips/draw/draw_smudge.c:215 #: libvips/mosaicing/matrixmultiply.c:147 msgid "Left" msgstr "" #: libvips/arithmetic/binary.c:97 msgid "Left-hand image argument" msgstr "" #: libvips/arithmetic/binary.c:102 libvips/colour/colour.c:591 #: libvips/mosaicing/matrixmultiply.c:153 msgid "Right" msgstr "" #: libvips/arithmetic/binary.c:103 msgid "Right-hand image argument" msgstr "" #: libvips/arithmetic/boolean.c:269 msgid "boolean operation on two images" msgstr "" #: libvips/arithmetic/boolean.c:277 libvips/arithmetic/boolean.c:578 #: libvips/arithmetic/complex.c:258 libvips/arithmetic/complex.c:538 #: libvips/arithmetic/complex.c:771 libvips/arithmetic/math2.c:241 #: libvips/arithmetic/math2.c:472 libvips/arithmetic/math.c:261 #: libvips/arithmetic/relational.c:246 libvips/arithmetic/relational.c:613 #: libvips/conversion/bandbool.c:238 tools/vips.c:627 msgid "Operation" msgstr "" #: libvips/arithmetic/boolean.c:278 libvips/arithmetic/boolean.c:579 #: libvips/conversion/bandbool.c:239 msgid "Boolean to perform" msgstr "" #: libvips/arithmetic/boolean.c:570 msgid "boolean operations against a constant" msgstr "" #: libvips/arithmetic/clamp.c:155 msgid "clamp values of an image" msgstr "" #: libvips/arithmetic/clamp.c:162 msgid "Min" msgstr "" #: libvips/arithmetic/clamp.c:163 msgid "Minimum value" msgstr "" #: libvips/arithmetic/clamp.c:169 msgid "Max" msgstr "" #: libvips/arithmetic/clamp.c:170 msgid "Maximum value" msgstr "" #: libvips/arithmetic/complex.c:251 msgid "perform a complex operation on an image" msgstr "" #: libvips/arithmetic/complex.c:259 libvips/arithmetic/complex.c:772 msgid "Complex to perform" msgstr "" #: libvips/arithmetic/complex.c:531 msgid "complex binary operations on two images" msgstr "" #: libvips/arithmetic/complex.c:539 msgid "Binary complex operation to perform" msgstr "" #: libvips/arithmetic/complex.c:762 msgid "get a component from a complex image" msgstr "" #: libvips/arithmetic/complex.c:978 msgid "form a complex image from two real images" msgstr "" #: libvips/arithmetic/deviate.c:229 msgid "find image standard deviation" msgstr "" #: libvips/arithmetic/divide.c:210 msgid "divide two images" msgstr "" #: libvips/arithmetic/find_trim.c:183 msgid "search an image for non-edge areas" msgstr "" #: libvips/arithmetic/find_trim.c:189 libvips/arithmetic/getpoint.c:153 #: libvips/arithmetic/measure.c:195 libvips/arithmetic/nary.c:87 #: libvips/arithmetic/statistic.c:167 libvips/arithmetic/unary.c:88 #: libvips/colour/CMYK2XYZ.c:120 libvips/colour/colour.c:381 #: libvips/colour/colour.c:474 libvips/colour/colourspace.c:560 #: libvips/colour/XYZ2CMYK.c:119 libvips/conversion/addalpha.c:90 #: libvips/conversion/arrayjoin.c:394 libvips/conversion/autorot.c:207 #: libvips/conversion/bandbool.c:232 libvips/conversion/bandfold.c:161 #: libvips/conversion/bandjoin.c:201 libvips/conversion/bandjoin.c:437 #: libvips/conversion/bandmean.c:212 libvips/conversion/bandrank.c:254 #: libvips/conversion/bandunfold.c:164 libvips/conversion/byteswap.c:238 #: libvips/conversion/cache.c:108 libvips/conversion/cast.c:529 #: libvips/conversion/copy.c:271 libvips/conversion/embed.c:568 #: libvips/conversion/extract.c:194 libvips/conversion/extract.c:434 #: libvips/conversion/falsecolour.c:380 libvips/conversion/flatten.c:416 #: libvips/conversion/flip.c:240 libvips/conversion/gamma.c:142 #: libvips/conversion/grid.c:199 libvips/conversion/msb.c:247 #: libvips/conversion/premultiply.c:261 libvips/conversion/recomb.c:224 #: libvips/conversion/replicate.c:196 libvips/conversion/rot45.c:268 #: libvips/conversion/rot.c:365 libvips/conversion/scale.c:155 #: libvips/conversion/sequential.c:243 libvips/conversion/smartcrop.c:433 #: libvips/conversion/subsample.c:267 libvips/conversion/tilecache.c:408 #: libvips/conversion/transpose3d.c:167 libvips/conversion/unpremultiply.c:323 #: libvips/conversion/wrap.c:119 libvips/conversion/zoom.c:373 #: libvips/convolution/canny.c:442 libvips/convolution/convolution.c:118 #: libvips/convolution/correlation.c:150 libvips/convolution/edge.c:217 #: libvips/convolution/gaussblur.c:132 libvips/convolution/sharpen.c:322 #: libvips/create/buildlut.c:263 libvips/create/invertlut.c:288 #: libvips/foreign/foreign.c:1866 libvips/freqfilt/freqfilt.c:87 #: libvips/histogram/hist_entropy.c:111 libvips/histogram/hist_equal.c:114 #: libvips/histogram/hist_ismonotonic.c:118 libvips/histogram/hist_local.c:361 #: libvips/histogram/hist_match.c:161 libvips/histogram/hist_norm.c:141 #: libvips/histogram/hist_plot.c:333 libvips/histogram/hist_unary.c:88 #: libvips/histogram/maplut.c:744 libvips/histogram/percent.c:109 #: libvips/histogram/stdif.c:294 libvips/iofuncs/ginputsource.c:274 #: libvips/iofuncs/sbuf.c:83 libvips/iofuncs/system.c:277 #: libvips/morphology/morphology.c:71 libvips/mosaicing/global_balance.c:1918 #: libvips/mosaicing/matrixinvert.c:444 libvips/mosaicing/remosaic.c:164 #: libvips/resample/resample.c:104 libvips/resample/thumbnail.c:1803 msgid "Input" msgstr "" #: libvips/arithmetic/find_trim.c:190 msgid "Image to find_trim" msgstr "" #: libvips/arithmetic/find_trim.c:195 libvips/histogram/percent.c:122 msgid "Threshold" msgstr "" #: libvips/arithmetic/find_trim.c:196 msgid "Object threshold" msgstr "" #: libvips/arithmetic/find_trim.c:202 libvips/conversion/arrayjoin.c:415 #: libvips/conversion/embed.c:595 libvips/conversion/flatten.c:422 #: libvips/conversion/insert.c:499 libvips/conversion/join.c:270 #: libvips/foreign/foreign.c:1880 libvips/foreign/pdfiumload.c:721 #: libvips/foreign/popplerload.c:571 libvips/resample/affine.c:699 #: libvips/resample/mapim.c:574 libvips/resample/similarity.c:133 msgid "Background" msgstr "" #: libvips/arithmetic/find_trim.c:203 libvips/conversion/embed.c:596 msgid "Color for background pixels" msgstr "" #: libvips/arithmetic/find_trim.c:209 msgid "Line art mode" msgstr "" #: libvips/arithmetic/find_trim.c:210 msgid "Enable line art mode" msgstr "" #: libvips/arithmetic/find_trim.c:217 msgid "Left edge of image" msgstr "" #: libvips/arithmetic/find_trim.c:223 libvips/arithmetic/measure.c:228 #: libvips/conversion/extract.c:207 libvips/draw/draw_flood.c:600 #: libvips/draw/draw_rect.c:180 libvips/draw/draw_smudge.c:222 msgid "Top" msgstr "" #: libvips/arithmetic/find_trim.c:224 libvips/arithmetic/measure.c:229 #: libvips/conversion/extract.c:208 msgid "Top edge of extract area" msgstr "" #: libvips/arithmetic/find_trim.c:230 libvips/arithmetic/hough_line.c:149 #: libvips/arithmetic/measure.c:235 libvips/conversion/copy.c:284 #: libvips/conversion/embed.c:574 libvips/conversion/extract.c:214 #: libvips/conversion/smartcrop.c:439 libvips/create/black.c:140 #: libvips/create/fractsurf.c:104 libvips/create/gaussnoise.c:168 #: libvips/create/logmat.c:208 libvips/create/perlin.c:295 #: libvips/create/point.c:141 libvips/create/sdf.c:304 #: libvips/create/text.c:571 libvips/create/worley.c:308 #: libvips/create/xyz.c:191 libvips/draw/draw_flood.c:607 #: libvips/draw/draw_rect.c:187 libvips/draw/draw_smudge.c:229 #: libvips/foreign/rawload.c:146 libvips/histogram/hist_local.c:373 #: libvips/histogram/stdif.c:308 libvips/iofuncs/image.c:1087 #: libvips/morphology/rank.c:570 msgid "Width" msgstr "" #: libvips/arithmetic/find_trim.c:231 libvips/arithmetic/measure.c:236 #: libvips/conversion/extract.c:215 libvips/conversion/smartcrop.c:440 msgid "Width of extract area" msgstr "" #: libvips/arithmetic/find_trim.c:237 libvips/arithmetic/hough_line.c:156 #: libvips/arithmetic/measure.c:242 libvips/conversion/copy.c:291 #: libvips/conversion/embed.c:581 libvips/conversion/extract.c:221 #: libvips/conversion/smartcrop.c:446 libvips/create/black.c:147 #: libvips/create/fractsurf.c:111 libvips/create/gaussnoise.c:175 #: libvips/create/perlin.c:302 libvips/create/point.c:148 #: libvips/create/sdf.c:311 libvips/create/text.c:578 #: libvips/create/worley.c:315 libvips/create/xyz.c:198 #: libvips/draw/draw_flood.c:614 libvips/draw/draw_rect.c:194 #: libvips/draw/draw_smudge.c:236 libvips/foreign/rawload.c:153 #: libvips/histogram/hist_local.c:380 libvips/histogram/stdif.c:315 #: libvips/iofuncs/image.c:1094 libvips/morphology/rank.c:577 msgid "Height" msgstr "" #: libvips/arithmetic/find_trim.c:238 libvips/arithmetic/measure.c:243 #: libvips/conversion/extract.c:222 libvips/conversion/smartcrop.c:447 msgid "Height of extract area" msgstr "" #: libvips/arithmetic/getpoint.c:149 msgid "read a point from an image" msgstr "" #: libvips/arithmetic/getpoint.c:154 libvips/arithmetic/statistic.c:168 #: libvips/arithmetic/unary.c:89 libvips/colour/CMYK2XYZ.c:121 #: libvips/colour/colour.c:382 libvips/colour/colour.c:475 #: libvips/colour/colourspace.c:561 libvips/colour/XYZ2CMYK.c:120 #: libvips/conversion/addalpha.c:91 libvips/conversion/autorot.c:208 #: libvips/conversion/bandfold.c:162 libvips/conversion/bandjoin.c:438 #: libvips/conversion/bandunfold.c:165 libvips/conversion/byteswap.c:239 #: libvips/conversion/cache.c:109 libvips/conversion/cast.c:530 #: libvips/conversion/copy.c:272 libvips/conversion/embed.c:569 #: libvips/conversion/extract.c:195 libvips/conversion/extract.c:435 #: libvips/conversion/falsecolour.c:381 libvips/conversion/flatten.c:417 #: libvips/conversion/flip.c:241 libvips/conversion/gamma.c:143 #: libvips/conversion/grid.c:200 libvips/conversion/msb.c:248 #: libvips/conversion/premultiply.c:262 libvips/conversion/replicate.c:197 #: libvips/conversion/rot45.c:269 libvips/conversion/rot.c:366 #: libvips/conversion/scale.c:156 libvips/conversion/sequential.c:244 #: libvips/conversion/smartcrop.c:434 libvips/conversion/subsample.c:268 #: libvips/conversion/tilecache.c:409 libvips/conversion/transpose3d.c:168 #: libvips/conversion/unpremultiply.c:324 libvips/conversion/wrap.c:120 #: libvips/conversion/zoom.c:374 libvips/convolution/canny.c:443 #: libvips/convolution/edge.c:218 libvips/convolution/gaussblur.c:133 #: libvips/convolution/sharpen.c:323 libvips/freqfilt/freqfilt.c:88 #: libvips/histogram/hist_equal.c:115 libvips/histogram/hist_local.c:362 #: libvips/histogram/hist_norm.c:142 libvips/histogram/hist_plot.c:334 #: libvips/histogram/hist_unary.c:89 libvips/histogram/maplut.c:745 #: libvips/histogram/percent.c:110 libvips/histogram/stdif.c:295 #: libvips/mosaicing/global_balance.c:1919 libvips/mosaicing/remosaic.c:165 msgid "Input image" msgstr "" #: libvips/arithmetic/getpoint.c:159 libvips/arithmetic/max.c:480 #: libvips/arithmetic/min.c:480 msgid "Output array" msgstr "" #: libvips/arithmetic/getpoint.c:160 libvips/arithmetic/max.c:481 #: libvips/arithmetic/min.c:481 msgid "Array of output values" msgstr "" #: libvips/arithmetic/getpoint.c:166 libvips/arithmetic/max.c:459 #: libvips/arithmetic/min.c:459 libvips/conversion/composite.cpp:1741 #: libvips/conversion/embed.c:656 libvips/conversion/wrap.c:125 #: libvips/draw/draw_flood.c:566 libvips/draw/draw_image.c:275 #: libvips/draw/draw_mask.c:338 msgid "x" msgstr "" #: libvips/arithmetic/getpoint.c:167 libvips/arithmetic/getpoint.c:174 msgid "Point to read" msgstr "" #: libvips/arithmetic/getpoint.c:173 libvips/arithmetic/max.c:466 #: libvips/arithmetic/min.c:466 libvips/conversion/composite.cpp:1748 #: libvips/conversion/embed.c:663 libvips/conversion/wrap.c:132 #: libvips/draw/draw_flood.c:573 libvips/draw/draw_image.c:282 #: libvips/draw/draw_mask.c:345 msgid "y" msgstr "" #: libvips/arithmetic/getpoint.c:180 msgid "unpack_complex" msgstr "" #: libvips/arithmetic/getpoint.c:181 msgid "Complex pixels should be unpacked" msgstr "" #: libvips/arithmetic/hist_find.c:422 msgid "find image histogram" msgstr "" #: libvips/arithmetic/hist_find.c:432 #: libvips/arithmetic/hist_find_indexed.c:476 #: libvips/arithmetic/hist_find_ndim.c:314 msgid "Output histogram" msgstr "" #: libvips/arithmetic/hist_find.c:437 libvips/conversion/extract.c:440 #: libvips/conversion/msb.c:253 libvips/histogram/hist_equal.c:126 #: libvips/histogram/maplut.c:762 msgid "Band" msgstr "" #: libvips/arithmetic/hist_find.c:438 msgid "Find histogram of band" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:461 msgid "find indexed image histogram" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:469 libvips/conversion/bandrank.c:261 #: libvips/histogram/case.c:239 libvips/morphology/rank.c:584 #: libvips/resample/mapim.c:555 msgid "Index" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:470 libvips/histogram/case.c:240 msgid "Index image" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:481 libvips/convolution/compass.c:177 msgid "Combine" msgstr "" #: libvips/arithmetic/hist_find_indexed.c:482 msgid "Combine bins like this" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:150 msgid "image is not 1 - 3 bands" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:159 #, c-format msgid "bins out of range [1,%d]" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:304 msgid "find n-dimensional image histogram" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:319 msgid "Bins" msgstr "" #: libvips/arithmetic/hist_find_ndim.c:320 msgid "Number of bins in each dimension" msgstr "" #: libvips/arithmetic/hough.c:170 msgid "find hough transform" msgstr "" #: libvips/arithmetic/hough_circle.c:115 msgid "parameters out of range" msgstr "" #: libvips/arithmetic/hough_circle.c:226 msgid "find hough circle transform" msgstr "" #: libvips/arithmetic/hough_circle.c:233 libvips/foreign/pdfiumload.c:714 #: libvips/foreign/popplerload.c:564 libvips/foreign/svgload.c:789 #: libvips/foreign/webpload.c:190 libvips/mosaicing/mosaic.c:274 #: libvips/resample/similarity.c:200 msgid "Scale" msgstr "" #: libvips/arithmetic/hough_circle.c:234 msgid "Scale down dimensions by this factor" msgstr "" #: libvips/arithmetic/hough_circle.c:240 msgid "Min radius" msgstr "" #: libvips/arithmetic/hough_circle.c:241 msgid "Smallest radius to search for" msgstr "" #: libvips/arithmetic/hough_circle.c:247 msgid "Max radius" msgstr "" #: libvips/arithmetic/hough_circle.c:248 msgid "Largest radius to search for" msgstr "" #: libvips/arithmetic/hough_line.c:142 msgid "find hough line transform" msgstr "" #: libvips/arithmetic/hough_line.c:150 msgid "Horizontal size of parameter space" msgstr "" #: libvips/arithmetic/hough_line.c:157 msgid "Vertical size of parameter space" msgstr "" #: libvips/arithmetic/invert.c:178 msgid "invert an image" msgstr "" #: libvips/arithmetic/linear.c:446 msgid "calculate (a * in + b)" msgstr "" #: libvips/arithmetic/linear.c:454 libvips/create/sdf.c:332 msgid "a" msgstr "" #: libvips/arithmetic/linear.c:455 msgid "Multiply by this" msgstr "" #: libvips/arithmetic/linear.c:461 libvips/create/sdf.c:339 msgid "b" msgstr "" #: libvips/arithmetic/linear.c:462 msgid "Add this" msgstr "" #: libvips/arithmetic/linear.c:468 msgid "uchar" msgstr "" #: libvips/arithmetic/linear.c:469 msgid "Output should be uchar" msgstr "" #: libvips/arithmetic/math2.c:233 msgid "binary math operations" msgstr "" #: libvips/arithmetic/math2.c:242 libvips/arithmetic/math2.c:473 #: libvips/arithmetic/math.c:262 msgid "Math to perform" msgstr "" #: libvips/arithmetic/math2.c:464 msgid "binary math operations with a constant" msgstr "" #: libvips/arithmetic/math.c:253 msgid "apply a math operation to an image" msgstr "" #: libvips/arithmetic/max.c:444 msgid "find image maximum" msgstr "" #: libvips/arithmetic/max.c:460 msgid "Horizontal position of maximum" msgstr "" #: libvips/arithmetic/max.c:467 msgid "Vertical position of maximum" msgstr "" #: libvips/arithmetic/max.c:473 libvips/arithmetic/min.c:473 #: libvips/create/identity.c:157 libvips/create/invertlut.c:294 #: libvips/resample/thumbnail.c:988 msgid "Size" msgstr "" #: libvips/arithmetic/max.c:474 msgid "Number of maximum values to find" msgstr "" #: libvips/arithmetic/max.c:487 libvips/arithmetic/min.c:487 msgid "x array" msgstr "" #: libvips/arithmetic/max.c:488 libvips/arithmetic/min.c:488 msgid "Array of horizontal positions" msgstr "" #: libvips/arithmetic/max.c:494 libvips/arithmetic/min.c:494 msgid "y array" msgstr "" #: libvips/arithmetic/max.c:495 libvips/arithmetic/min.c:495 msgid "Array of vertical positions" msgstr "" #: libvips/arithmetic/maxpair.c:151 msgid "maximum of a pair of images" msgstr "" #: libvips/arithmetic/measure.c:191 msgid "measure a set of patches on a color chart" msgstr "measure a set of patches on a colour chart" #: libvips/arithmetic/measure.c:196 msgid "Image to measure" msgstr "" #: libvips/arithmetic/measure.c:202 libvips/arithmetic/stats.c:443 msgid "Output array of statistics" msgstr "" #: libvips/arithmetic/measure.c:207 libvips/conversion/arrayjoin.c:401 #: libvips/conversion/grid.c:212 libvips/conversion/replicate.c:202 msgid "Across" msgstr "" #: libvips/arithmetic/measure.c:208 msgid "Number of patches across chart" msgstr "" #: libvips/arithmetic/measure.c:214 libvips/conversion/grid.c:219 #: libvips/conversion/replicate.c:209 msgid "Down" msgstr "" #: libvips/arithmetic/measure.c:215 msgid "Number of patches down chart" msgstr "" #: libvips/arithmetic/measure.c:222 libvips/conversion/extract.c:201 msgid "Left edge of extract area" msgstr "" #: libvips/arithmetic/min.c:444 msgid "find image minimum" msgstr "" #: libvips/arithmetic/min.c:460 msgid "Horizontal position of minimum" msgstr "" #: libvips/arithmetic/min.c:467 msgid "Vertical position of minimum" msgstr "" #: libvips/arithmetic/min.c:474 msgid "Number of minimum values to find" msgstr "" #: libvips/arithmetic/minpair.c:151 msgid "minimum of a pair of images" msgstr "" #: libvips/arithmetic/multiply.c:195 msgid "multiply two images" msgstr "" #: libvips/arithmetic/nary.c:80 msgid "nary operations" msgstr "" #: libvips/arithmetic/nary.c:88 libvips/conversion/arrayjoin.c:395 #: libvips/conversion/bandjoin.c:202 libvips/conversion/bandrank.c:255 #: libvips/conversion/composite.cpp:1589 libvips/iofuncs/system.c:278 msgid "Array of input images" msgstr "" #: libvips/arithmetic/profile.c:293 msgid "find image profiles" msgstr "" #: libvips/arithmetic/profile.c:301 libvips/arithmetic/project.c:332 msgid "Columns" msgstr "" #: libvips/arithmetic/profile.c:302 msgid "First non-zero pixel in column" msgstr "" #: libvips/arithmetic/profile.c:307 libvips/arithmetic/project.c:338 msgid "Rows" msgstr "" #: libvips/arithmetic/profile.c:308 msgid "First non-zero pixel in row" msgstr "" #: libvips/arithmetic/project.c:324 msgid "find image projections" msgstr "" #: libvips/arithmetic/project.c:333 msgid "Sums of columns" msgstr "" #: libvips/arithmetic/project.c:339 msgid "Sums of rows" msgstr "" #: libvips/arithmetic/relational.c:238 msgid "relational operation on two images" msgstr "" #: libvips/arithmetic/relational.c:247 libvips/arithmetic/relational.c:614 msgid "Relational to perform" msgstr "" #: libvips/arithmetic/relational.c:605 msgid "relational operations against a constant" msgstr "" #: libvips/arithmetic/remainder.c:192 msgid "remainder after integer division of two images" msgstr "" #: libvips/arithmetic/remainder.c:354 msgid "remainder after integer division of an image and a constant" msgstr "" #: libvips/arithmetic/round.c:173 msgid "perform a round function on an image" msgstr "" #: libvips/arithmetic/round.c:181 msgid "Round operation" msgstr "" #: libvips/arithmetic/round.c:182 msgid "Rounding operation to perform" msgstr "" #: libvips/arithmetic/sign.c:174 msgid "unit vector of pixel" msgstr "" #: libvips/arithmetic/statistic.c:161 msgid "VIPS statistic operations" msgstr "" #: libvips/arithmetic/stats.c:434 msgid "find many image stats" msgstr "" #: libvips/arithmetic/subtract.c:174 msgid "subtract two images" msgstr "" #: libvips/arithmetic/sum.c:149 msgid "sum an array of images" msgstr "" #: libvips/arithmetic/unary.c:81 msgid "unary operations" msgstr "" #: libvips/arithmetic/unaryconst.c:138 msgid "unary operations with a constant" msgstr "" #: libvips/arithmetic/unaryconst.c:142 msgid "c" msgstr "" #: libvips/arithmetic/unaryconst.c:143 msgid "Array of constants" msgstr "" #: libvips/colour/CMYK2XYZ.c:114 libvips/colour/CMYK2XYZ.c:182 msgid "transform CMYK to XYZ" msgstr "" #: libvips/colour/colour.c:178 msgid "too many input images" msgstr "" #: libvips/colour/colour.c:310 msgid "color operations" msgstr "colour operations" #: libvips/colour/colour.c:377 msgid "color space transformations" msgstr "colour space transformations" #: libvips/colour/colour.c:470 msgid "change color coding" msgstr "change colour coding" #: libvips/colour/colour.c:581 msgid "calculate color difference" msgstr "calculate colour difference" #: libvips/colour/colour.c:586 msgid "Left-hand input image" msgstr "" #: libvips/colour/colour.c:592 msgid "Right-hand input image" msgstr "" #: libvips/colour/colourspace.c:145 msgid "too few bands for operation" msgstr "" #: libvips/colour/colourspace.c:524 #, c-format msgid "no known route from '%s' to '%s'" msgstr "" #: libvips/colour/colourspace.c:554 msgid "convert to a new colorspace" msgstr "convert to a new colourspace" #: libvips/colour/colourspace.c:572 msgid "Space" msgstr "" #: libvips/colour/colourspace.c:573 msgid "Destination color space" msgstr "Destination colour space" #: libvips/colour/colourspace.c:579 msgid "Source space" msgstr "" #: libvips/colour/colourspace.c:580 msgid "Source color space" msgstr "Source colour space" #: libvips/colour/dE00.c:236 msgid "calculate dE00" msgstr "" #: libvips/colour/dE76.c:113 msgid "calculate dE76" msgstr "" #: libvips/colour/dECMC.c:61 msgid "calculate dECMC" msgstr "" #: libvips/colour/float2rad.c:206 msgid "transform float RGB to Radiance coding" msgstr "" #: libvips/colour/HSV2sRGB.c:112 msgid "transform HSV to sRGB" msgstr "" #: libvips/colour/icc_transform.c:272 libvips/colour/scRGB2BW.c:134 #: libvips/colour/scRGB2sRGB.c:161 msgid "depth must be 8 or 16" msgstr "" #: libvips/colour/icc_transform.c:284 #, c-format msgid "unimplemented input color space 0x%x" msgstr "unimplemented input colour space 0x%x" #: libvips/colour/icc_transform.c:360 #, c-format msgid "unimplemented output color space 0x%x" msgstr "unimplemented output colour space 0x%x" #: libvips/colour/icc_transform.c:437 msgid "no device profile" msgstr "" #: libvips/colour/icc_transform.c:764 msgid "unable to load or find any compatible input profile" msgstr "" #: libvips/colour/icc_transform.c:782 msgid "transform using ICC profiles" msgstr "" #: libvips/colour/icc_transform.c:786 libvips/resample/thumbnail.c:1030 msgid "Intent" msgstr "" #: libvips/colour/icc_transform.c:787 libvips/resample/thumbnail.c:1031 msgid "Rendering intent" msgstr "" #: libvips/colour/icc_transform.c:793 msgid "PCS" msgstr "" #: libvips/colour/icc_transform.c:794 msgid "Set Profile Connection Space" msgstr "" #: libvips/colour/icc_transform.c:800 msgid "Black point compensation" msgstr "" #: libvips/colour/icc_transform.c:801 msgid "Enable black point compensation" msgstr "" #: libvips/colour/icc_transform.c:975 msgid "import from device with ICC profile" msgstr "" #: libvips/colour/icc_transform.c:981 libvips/colour/icc_transform.c:1264 msgid "Embedded" msgstr "" #: libvips/colour/icc_transform.c:982 libvips/colour/icc_transform.c:1265 msgid "Use embedded input profile, if available" msgstr "" #: libvips/colour/icc_transform.c:988 libvips/colour/icc_transform.c:1271 #: libvips/resample/thumbnail.c:1016 msgid "Input profile" msgstr "" #: libvips/colour/icc_transform.c:989 libvips/colour/icc_transform.c:1272 msgid "Filename to load input profile from" msgstr "" #: libvips/colour/icc_transform.c:1052 libvips/colour/icc_transform.c:1218 msgid "no output profile" msgstr "" #: libvips/colour/icc_transform.c:1147 msgid "output to device with ICC profile" msgstr "" #: libvips/colour/icc_transform.c:1153 libvips/colour/icc_transform.c:1257 #: libvips/resample/thumbnail.c:1023 msgid "Output profile" msgstr "" #: libvips/colour/icc_transform.c:1154 libvips/colour/icc_transform.c:1258 msgid "Filename to load output profile from" msgstr "" #: libvips/colour/icc_transform.c:1160 libvips/colour/icc_transform.c:1278 #: libvips/colour/scRGB2BW.c:160 libvips/colour/scRGB2sRGB.c:187 #: libvips/foreign/dzsave.c:2361 libvips/foreign/tiffsave.c:381 msgid "Depth" msgstr "" #: libvips/colour/icc_transform.c:1161 libvips/colour/icc_transform.c:1279 #: libvips/colour/scRGB2BW.c:161 libvips/colour/scRGB2sRGB.c:188 msgid "Output device space depth in bits" msgstr "" #: libvips/colour/icc_transform.c:1251 msgid "transform between devices with ICC profiles" msgstr "" #: libvips/colour/icc_transform.c:1328 msgid "unable to get media white point" msgstr "" #: libvips/colour/icc_transform.c:1423 msgid "libvips configured without lcms support" msgstr "" #: libvips/colour/Lab2LabQ.c:137 msgid "transform float Lab to LabQ coding" msgstr "" #: libvips/colour/Lab2LabS.c:82 msgid "transform float Lab to signed short" msgstr "" #: libvips/colour/Lab2LCh.c:132 msgid "transform Lab to LCh" msgstr "" #: libvips/colour/Lab2XYZ.c:177 msgid "transform CIELAB to XYZ" msgstr "" #: libvips/colour/Lab2XYZ.c:183 libvips/colour/XYZ2Lab.c:237 msgid "Temperature" msgstr "" #: libvips/colour/Lab2XYZ.c:184 msgid "Color temperature" msgstr "" #: libvips/colour/LabQ2Lab.c:125 msgid "unpack a LabQ image to float Lab" msgstr "" #: libvips/colour/LabQ2LabS.c:104 msgid "unpack a LabQ image to short Lab" msgstr "" #: libvips/colour/LabQ2sRGB.c:552 msgid "convert a LabQ image to sRGB" msgstr "" #: libvips/colour/LabS2Lab.c:78 msgid "transform signed short Lab to float" msgstr "" #: libvips/colour/LabS2LabQ.c:127 msgid "transform short Lab to LabQ coding" msgstr "" #: libvips/colour/LCh2Lab.c:111 msgid "transform LCh to Lab" msgstr "" #: libvips/colour/LCh2UCS.c:206 libvips/colour/UCS2LCh.c:273 msgid "transform LCh to CMC" msgstr "" #: libvips/colour/profile_load.c:123 #, c-format msgid "unable to load profile \"%s\"" msgstr "" #: libvips/colour/profile_load.c:147 msgid "load named ICC profile" msgstr "" #: libvips/colour/profile_load.c:151 msgid "Name" msgstr "" #: libvips/colour/profile_load.c:152 msgid "Profile name" msgstr "" #: libvips/colour/profile_load.c:158 libvips/foreign/foreign.c:1894 msgid "Profile" msgstr "" #: libvips/colour/profile_load.c:159 msgid "Loaded profile" msgstr "" #: libvips/colour/rad2float.c:184 msgid "unpack Radiance coding to float RGB" msgstr "" #: libvips/colour/scRGB2BW.c:154 msgid "convert scRGB to BW" msgstr "" #: libvips/colour/scRGB2sRGB.c:181 msgid "convert scRGB to sRGB" msgstr "" #: libvips/colour/scRGB2XYZ.c:88 msgid "transform scRGB to XYZ" msgstr "" #: libvips/colour/sRGB2HSV.c:133 msgid "transform sRGB to HSV" msgstr "" #: libvips/colour/sRGB2scRGB.c:141 msgid "convert an sRGB image to scRGB" msgstr "" #: libvips/colour/XYZ2CMYK.c:113 libvips/colour/XYZ2CMYK.c:193 msgid "transform XYZ to CMYK" msgstr "" #: libvips/colour/XYZ2Lab.c:231 msgid "transform XYZ to Lab" msgstr "" #: libvips/colour/XYZ2Lab.c:238 msgid "Colour temperature" msgstr "" #: libvips/colour/XYZ2scRGB.c:103 msgid "transform XYZ to scRGB" msgstr "" #: libvips/colour/XYZ2Yxy.c:98 msgid "transform XYZ to Yxy" msgstr "" #: libvips/colour/Yxy2XYZ.c:103 msgid "transform Yxy to XYZ" msgstr "" #: libvips/conversion/addalpha.c:84 msgid "append an alpha channel" msgstr "" #: libvips/conversion/arrayjoin.c:388 msgid "join an array of images" msgstr "" #: libvips/conversion/arrayjoin.c:402 msgid "Number of images across grid" msgstr "" #: libvips/conversion/arrayjoin.c:408 libvips/conversion/join.c:263 msgid "Shim" msgstr "" #: libvips/conversion/arrayjoin.c:409 libvips/conversion/join.c:264 msgid "Pixels between images" msgstr "" #: libvips/conversion/arrayjoin.c:416 libvips/conversion/join.c:271 msgid "Colour for new pixels" msgstr "" #: libvips/conversion/arrayjoin.c:422 msgid "Horizontal align" msgstr "" #: libvips/conversion/arrayjoin.c:423 msgid "Align on the left, centre or right" msgstr "" #: libvips/conversion/arrayjoin.c:429 msgid "Vertical align" msgstr "" #: libvips/conversion/arrayjoin.c:430 msgid "Align on the top, centre or bottom" msgstr "" #: libvips/conversion/arrayjoin.c:436 msgid "Horizontal spacing" msgstr "" #: libvips/conversion/arrayjoin.c:437 msgid "Horizontal spacing between images" msgstr "" #: libvips/conversion/arrayjoin.c:443 msgid "Vertical spacing" msgstr "" #: libvips/conversion/arrayjoin.c:444 msgid "Vertical spacing between images" msgstr "" #: libvips/conversion/autorot.c:203 msgid "autorotate image by exif tag" msgstr "" #: libvips/conversion/autorot.c:213 libvips/conversion/rot45.c:274 #: libvips/conversion/rot.c:371 libvips/convolution/compass.c:170 #: libvips/foreign/dzsave.c:2375 libvips/mosaicing/mosaic.c:281 #: libvips/resample/similarity.c:207 libvips/resample/similarity.c:276 msgid "Angle" msgstr "" #: libvips/conversion/autorot.c:214 msgid "Angle image was rotated by" msgstr "" #: libvips/conversion/autorot.c:220 msgid "Flip" msgstr "" #: libvips/conversion/autorot.c:221 msgid "Whether the image was flipped or not" msgstr "" #: libvips/conversion/bandary.c:211 libvips/conversion/bandary.c:280 #: libvips/conversion/composite.cpp:1299 msgid "no input images" msgstr "" #: libvips/conversion/bandary.c:257 msgid "operations on image bands" msgstr "" #: libvips/conversion/bandbool.c:75 #, c-format msgid "operator %s not supported across image bands" msgstr "" #: libvips/conversion/bandbool.c:225 msgid "boolean operation across image bands" msgstr "" #: libvips/conversion/bandbool.c:233 libvips/conversion/bandmean.c:213 #: libvips/conversion/recomb.c:225 libvips/convolution/convolution.c:119 #: libvips/convolution/correlation.c:151 libvips/morphology/morphology.c:72 #: libvips/resample/resample.c:105 libvips/resample/thumbnail.c:1804 msgid "Input image argument" msgstr "" #: libvips/conversion/bandfold.c:123 msgid "@factor must be a factor of image width" msgstr "" #: libvips/conversion/bandfold.c:155 msgid "fold up x axis into bands" msgstr "" #: libvips/conversion/bandfold.c:167 libvips/conversion/bandunfold.c:170 #: libvips/create/eye.c:108 msgid "Factor" msgstr "" #: libvips/conversion/bandfold.c:168 msgid "Fold by this factor" msgstr "" #: libvips/conversion/bandjoin.c:195 msgid "bandwise join a set of images" msgstr "" #: libvips/conversion/bandjoin.c:431 msgid "append a constant band to an image" msgstr "" #: libvips/conversion/bandjoin.c:443 msgid "Constants" msgstr "" #: libvips/conversion/bandjoin.c:444 msgid "Array of constants to add" msgstr "" #: libvips/conversion/bandmean.c:206 msgid "band-wise average" msgstr "" #: libvips/conversion/bandrank.c:248 msgid "band-wise rank of a set of images" msgstr "" #: libvips/conversion/bandrank.c:262 msgid "Select this band element from sorted list" msgstr "" #: libvips/conversion/bandunfold.c:126 msgid "@factor must be a factor of image bands" msgstr "" #: libvips/conversion/bandunfold.c:158 msgid "unfold image bands into x axis" msgstr "" #: libvips/conversion/bandunfold.c:171 msgid "Unfold by this factor" msgstr "" #: libvips/conversion/byteswap.c:232 msgid "byteswap an image" msgstr "" #: libvips/conversion/cache.c:98 libvips/conversion/tilecache.c:402 msgid "cache an image" msgstr "" #: libvips/conversion/cache.c:114 libvips/conversion/tilecache.c:810 #: libvips/foreign/dzsave.c:2448 libvips/foreign/jp2ksave.c:971 #: libvips/foreign/tiffsave.c:290 msgid "Tile width" msgstr "" #: libvips/conversion/cache.c:115 libvips/conversion/tilecache.c:811 #: libvips/foreign/dzsave.c:2449 libvips/foreign/jp2ksave.c:972 #: libvips/foreign/tiffsave.c:291 msgid "Tile width in pixels" msgstr "" #: libvips/conversion/cache.c:121 libvips/conversion/grid.c:205 #: libvips/conversion/sequential.c:249 libvips/conversion/tilecache.c:414 #: libvips/foreign/dzsave.c:2455 libvips/foreign/jp2ksave.c:978 #: libvips/foreign/tiffsave.c:297 msgid "Tile height" msgstr "" #: libvips/conversion/cache.c:122 libvips/conversion/sequential.c:250 #: libvips/conversion/tilecache.c:415 libvips/foreign/dzsave.c:2456 #: libvips/foreign/jp2ksave.c:979 libvips/foreign/tiffsave.c:298 msgid "Tile height in pixels" msgstr "" #: libvips/conversion/cache.c:128 libvips/conversion/tilecache.c:817 msgid "Max tiles" msgstr "" #: libvips/conversion/cache.c:129 libvips/conversion/tilecache.c:818 msgid "Maximum number of tiles to cache" msgstr "" #: libvips/conversion/cast.c:523 msgid "cast an image" msgstr "" #: libvips/conversion/cast.c:535 libvips/conversion/copy.c:305 #: libvips/foreign/ppmsave.c:492 libvips/foreign/rawload.c:174 #: libvips/foreign/vips2magick.c:482 libvips/iofuncs/image.c:1108 msgid "Format" msgstr "" #: libvips/conversion/cast.c:536 msgid "Format to cast to" msgstr "" #: libvips/conversion/cast.c:542 msgid "Shift" msgstr "" #: libvips/conversion/cast.c:543 msgid "Shift integer values up and down" msgstr "" #: libvips/conversion/composite.cpp:1304 #, c-format msgid "must be 1 or %d blend modes" msgstr "" #: libvips/conversion/composite.cpp:1314 #, c-format msgid "blend mode index %d (%d) invalid" msgstr "" #: libvips/conversion/composite.cpp:1421 msgid "images do not have same numbers of bands" msgstr "" #: libvips/conversion/composite.cpp:1428 msgid "too many input bands" msgstr "" #: libvips/conversion/composite.cpp:1438 #, fuzzy msgid "unsupported compositing space" msgstr "unsupported colourspace %d" #: libvips/conversion/composite.cpp:1486 msgid "blend images together" msgstr "" #: libvips/conversion/composite.cpp:1492 msgid "Compositing space" msgstr "" #: libvips/conversion/composite.cpp:1493 #, fuzzy msgid "Composite images in this colour space" msgstr "Destination colour space" #: libvips/conversion/composite.cpp:1499 libvips/conversion/smartcrop.c:474 #: libvips/resample/affine.c:706 libvips/resample/mapim.c:581 msgid "Premultiplied" msgstr "" #: libvips/conversion/composite.cpp:1500 libvips/resample/affine.c:707 #: libvips/resample/mapim.c:582 msgid "Images have premultiplied alpha" msgstr "" #: libvips/conversion/composite.cpp:1548 #, c-format msgid "must be %d x coordinates" msgstr "" #: libvips/conversion/composite.cpp:1556 #, c-format msgid "must be %d y coordinates" msgstr "" #: libvips/conversion/composite.cpp:1582 msgid "blend an array of images with an array of blend modes" msgstr "" #: libvips/conversion/composite.cpp:1588 msgid "Inputs" msgstr "" #: libvips/conversion/composite.cpp:1595 msgid "Blend modes" msgstr "" #: libvips/conversion/composite.cpp:1596 msgid "Array of VipsBlendMode to join with" msgstr "" #: libvips/conversion/composite.cpp:1602 msgid "x coordinates" msgstr "" #: libvips/conversion/composite.cpp:1603 msgid "Array of x coordinates to join at" msgstr "" #: libvips/conversion/composite.cpp:1609 msgid "y coordinates" msgstr "" #: libvips/conversion/composite.cpp:1610 msgid "Array of y coordinates to join at" msgstr "" #: libvips/conversion/composite.cpp:1716 msgid "blend a pair of images with a blend mode" msgstr "" #: libvips/conversion/composite.cpp:1722 msgid "Base" msgstr "" #: libvips/conversion/composite.cpp:1723 #, fuzzy msgid "Base image" msgstr "false-colour an image" #: libvips/conversion/composite.cpp:1728 msgid "Overlay" msgstr "" #: libvips/conversion/composite.cpp:1729 msgid "Overlay image" msgstr "" #: libvips/conversion/composite.cpp:1734 msgid "Blend mode" msgstr "" #: libvips/conversion/composite.cpp:1735 msgid "VipsBlendMode to join with" msgstr "" #: libvips/conversion/composite.cpp:1742 msgid "x position of overlay" msgstr "" #: libvips/conversion/composite.cpp:1749 msgid "y position of overlay" msgstr "" #: libvips/conversion/conversion.c:328 msgid "conversion operations" msgstr "" #: libvips/conversion/copy.c:235 msgid "must not change pel size" msgstr "" #: libvips/conversion/copy.c:260 msgid "copy an image" msgstr "" #: libvips/conversion/copy.c:277 msgid "Swap" msgstr "" #: libvips/conversion/copy.c:278 msgid "Swap bytes in image between little and big-endian" msgstr "" #: libvips/conversion/copy.c:285 libvips/conversion/embed.c:575 #: libvips/create/black.c:141 libvips/create/fractsurf.c:105 #: libvips/create/gaussnoise.c:169 libvips/create/perlin.c:296 #: libvips/create/point.c:142 libvips/create/sdf.c:305 #: libvips/create/worley.c:309 libvips/create/xyz.c:192 #: libvips/foreign/rawload.c:147 libvips/iofuncs/image.c:1088 msgid "Image width in pixels" msgstr "" #: libvips/conversion/copy.c:292 libvips/conversion/embed.c:582 #: libvips/create/black.c:148 libvips/create/fractsurf.c:112 #: libvips/create/gaussnoise.c:176 libvips/create/perlin.c:303 #: libvips/create/point.c:149 libvips/create/sdf.c:312 #: libvips/create/worley.c:316 libvips/create/xyz.c:199 #: libvips/foreign/rawload.c:154 libvips/iofuncs/image.c:1095 msgid "Image height in pixels" msgstr "" #: libvips/conversion/copy.c:298 libvips/create/black.c:154 #: libvips/create/identity.c:143 libvips/foreign/rawload.c:160 #: libvips/iofuncs/image.c:1101 msgid "Bands" msgstr "" #: libvips/conversion/copy.c:299 libvips/create/black.c:155 #: libvips/foreign/rawload.c:161 libvips/iofuncs/image.c:1102 msgid "Number of bands in image" msgstr "" #: libvips/conversion/copy.c:306 libvips/foreign/rawload.c:175 #: libvips/iofuncs/image.c:1109 msgid "Pixel format in image" msgstr "" #: libvips/conversion/copy.c:312 libvips/iofuncs/image.c:1115 msgid "Coding" msgstr "" #: libvips/conversion/copy.c:313 libvips/iofuncs/image.c:1116 msgid "Pixel coding" msgstr "" #: libvips/conversion/copy.c:319 libvips/foreign/rawload.c:181 #: libvips/iofuncs/image.c:1122 msgid "Interpretation" msgstr "" #: libvips/conversion/copy.c:320 libvips/foreign/rawload.c:182 #: libvips/iofuncs/image.c:1123 msgid "Pixel interpretation" msgstr "" #: libvips/conversion/copy.c:326 libvips/foreign/tiffsave.c:332 #: libvips/iofuncs/image.c:1129 msgid "Xres" msgstr "" #: libvips/conversion/copy.c:327 libvips/foreign/tiffsave.c:333 #: libvips/iofuncs/image.c:1130 msgid "Horizontal resolution in pixels/mm" msgstr "" #: libvips/conversion/copy.c:333 libvips/foreign/tiffsave.c:339 #: libvips/iofuncs/image.c:1136 msgid "Yres" msgstr "" #: libvips/conversion/copy.c:334 libvips/foreign/tiffsave.c:340 #: libvips/iofuncs/image.c:1137 msgid "Vertical resolution in pixels/mm" msgstr "" #: libvips/conversion/copy.c:340 libvips/iofuncs/image.c:1143 msgid "Xoffset" msgstr "" #: libvips/conversion/copy.c:341 libvips/iofuncs/image.c:1144 msgid "Horizontal offset of origin" msgstr "" #: libvips/conversion/copy.c:347 libvips/iofuncs/image.c:1150 msgid "Yoffset" msgstr "" #: libvips/conversion/copy.c:348 libvips/iofuncs/image.c:1151 msgid "Vertical offset of origin" msgstr "" #: libvips/conversion/embed.c:479 libvips/foreign/heifload.c:581 #: libvips/foreign/svgload.c:532 libvips/iofuncs/image.c:3156 msgid "bad dimensions" msgstr "" #: libvips/conversion/embed.c:561 libvips/conversion/embed.c:652 msgid "embed an image in a larger image" msgstr "" #: libvips/conversion/embed.c:588 libvips/resample/affine.c:692 #: libvips/resample/mapim.c:567 msgid "Extend" msgstr "" #: libvips/conversion/embed.c:589 libvips/resample/affine.c:693 #: libvips/resample/mapim.c:568 msgid "How to generate the extra pixels" msgstr "" #: libvips/conversion/embed.c:657 libvips/conversion/wrap.c:126 msgid "Left edge of input in output" msgstr "" #: libvips/conversion/embed.c:664 libvips/conversion/wrap.c:133 msgid "Top edge of input in output" msgstr "" #: libvips/conversion/embed.c:806 msgid "place an image within a larger image with a certain gravity" msgstr "" #: libvips/conversion/embed.c:811 libvips/conversion/flip.c:246 #: libvips/conversion/join.c:249 libvips/morphology/countlines.c:146 #: libvips/mosaicing/merge.c:140 libvips/mosaicing/mosaic1.c:516 #: libvips/mosaicing/mosaic.c:197 msgid "Direction" msgstr "" #: libvips/conversion/embed.c:812 msgid "Direction to place image within width/height" msgstr "" #: libvips/conversion/extract.c:150 libvips/conversion/smartcrop.c:341 msgid "bad extract area" msgstr "" #: libvips/conversion/extract.c:188 libvips/conversion/smartcrop.c:429 msgid "extract an area from an image" msgstr "" #: libvips/conversion/extract.c:400 msgid "bad extract band" msgstr "" #: libvips/conversion/extract.c:428 msgid "extract band from an image" msgstr "" #: libvips/conversion/extract.c:441 msgid "Band to extract" msgstr "" #: libvips/conversion/extract.c:447 libvips/foreign/heifload.c:1089 #: libvips/foreign/jxlload.c:1133 libvips/foreign/magick6load.c:309 #: libvips/foreign/magick7load.c:386 libvips/foreign/nsgifload.c:627 #: libvips/foreign/pdfiumload.c:700 libvips/foreign/popplerload.c:550 #: libvips/foreign/tiffload.c:203 libvips/foreign/webpload.c:183 msgid "n" msgstr "" #: libvips/conversion/extract.c:448 msgid "Number of bands to extract" msgstr "" #: libvips/conversion/falsecolour.c:374 msgid "false-color an image" msgstr "false-colour an image" #: libvips/conversion/flatten.c:410 msgid "flatten alpha out of an image" msgstr "" #: libvips/conversion/flatten.c:423 libvips/foreign/foreign.c:1881 #: libvips/resample/affine.c:700 libvips/resample/mapim.c:575 #: libvips/resample/similarity.c:134 msgid "Background value" msgstr "" #: libvips/conversion/flatten.c:429 libvips/conversion/premultiply.c:267 #: libvips/conversion/unpremultiply.c:329 msgid "Maximum alpha" msgstr "" #: libvips/conversion/flatten.c:430 libvips/conversion/premultiply.c:268 #: libvips/conversion/unpremultiply.c:330 msgid "Maximum value of alpha channel" msgstr "" #: libvips/conversion/flip.c:236 msgid "flip an image" msgstr "" #: libvips/conversion/flip.c:247 msgid "Direction to flip image" msgstr "" #: libvips/conversion/gamma.c:136 msgid "gamma an image" msgstr "" #: libvips/conversion/gamma.c:148 libvips/conversion/scale.c:168 msgid "Exponent" msgstr "" #: libvips/conversion/gamma.c:149 msgid "Gamma factor" msgstr "" #: libvips/conversion/grid.c:165 msgid "bad grid geometry" msgstr "" #: libvips/conversion/grid.c:195 msgid "grid an image" msgstr "" #: libvips/conversion/grid.c:206 msgid "Chop into tiles this high" msgstr "" #: libvips/conversion/grid.c:213 msgid "Number of tiles across" msgstr "" #: libvips/conversion/grid.c:220 msgid "Number of tiles down" msgstr "" #: libvips/conversion/ifthenelse.c:525 msgid "ifthenelse an image" msgstr "" #: libvips/conversion/ifthenelse.c:529 msgid "Condition" msgstr "" #: libvips/conversion/ifthenelse.c:530 msgid "Condition input image" msgstr "" #: libvips/conversion/ifthenelse.c:535 msgid "Then image" msgstr "" #: libvips/conversion/ifthenelse.c:536 msgid "Source for TRUE pixels" msgstr "" #: libvips/conversion/ifthenelse.c:541 msgid "Else image" msgstr "" #: libvips/conversion/ifthenelse.c:542 msgid "Source for FALSE pixels" msgstr "" #: libvips/conversion/ifthenelse.c:547 msgid "Blend" msgstr "" #: libvips/conversion/ifthenelse.c:548 msgid "Blend smoothly between then and else parts" msgstr "" #: libvips/conversion/insert.c:460 msgid "insert image @sub into @main at @x, @y" msgstr "" #: libvips/conversion/insert.c:466 msgid "Main" msgstr "" #: libvips/conversion/insert.c:467 msgid "Main input image" msgstr "" #: libvips/conversion/insert.c:472 libvips/draw/draw_image.c:269 msgid "Sub-image" msgstr "" #: libvips/conversion/insert.c:473 libvips/draw/draw_image.c:270 msgid "Sub-image to insert into main image" msgstr "" #: libvips/conversion/insert.c:478 msgid "X" msgstr "" #: libvips/conversion/insert.c:479 msgid "Left edge of sub in main" msgstr "" #: libvips/conversion/insert.c:485 msgid "Y" msgstr "" #: libvips/conversion/insert.c:486 msgid "Top edge of sub in main" msgstr "" #: libvips/conversion/insert.c:492 libvips/conversion/join.c:256 msgid "Expand" msgstr "" #: libvips/conversion/insert.c:493 libvips/conversion/join.c:257 msgid "Expand output to hold all of both inputs" msgstr "" #: libvips/conversion/insert.c:500 msgid "Color for new pixels" msgstr "" #: libvips/conversion/join.c:231 msgid "join a pair of images" msgstr "" #: libvips/conversion/join.c:237 msgid "in1" msgstr "" #: libvips/conversion/join.c:238 msgid "First input image" msgstr "" #: libvips/conversion/join.c:243 libvips/freqfilt/phasecor.c:111 msgid "in2" msgstr "" #: libvips/conversion/join.c:244 libvips/freqfilt/phasecor.c:112 msgid "Second input image" msgstr "" #: libvips/conversion/join.c:250 msgid "Join left-right or up-down" msgstr "" #: libvips/conversion/join.c:277 libvips/create/text.c:585 msgid "Align" msgstr "" #: libvips/conversion/join.c:278 msgid "Align on the low, centre or high coordinate edge" msgstr "" #: libvips/conversion/msb.c:168 msgid "bad band" msgstr "" #: libvips/conversion/msb.c:241 msgid "pick most-significant byte from an image" msgstr "" #: libvips/conversion/msb.c:254 msgid "Band to msb" msgstr "" #: libvips/conversion/premultiply.c:255 msgid "premultiply image alpha" msgstr "" #: libvips/conversion/recomb.c:183 msgid "bands in must equal matrix width" msgstr "" #: libvips/conversion/recomb.c:218 msgid "linear recombination with matrix" msgstr "" #: libvips/conversion/recomb.c:230 msgid "M" msgstr "" #: libvips/conversion/recomb.c:231 msgid "Matrix of coefficients" msgstr "" #: libvips/conversion/replicate.c:192 msgid "replicate an image" msgstr "" #: libvips/conversion/replicate.c:203 msgid "Repeat this many times horizontally" msgstr "" #: libvips/conversion/replicate.c:210 msgid "Repeat this many times vertically" msgstr "" #: libvips/conversion/rot45.c:264 libvips/conversion/rot.c:361 msgid "rotate an image" msgstr "" #: libvips/conversion/rot45.c:275 libvips/conversion/rot.c:372 msgid "Angle to rotate image" msgstr "" #: libvips/conversion/scale.c:151 msgid "scale an image to uchar" msgstr "" #: libvips/conversion/scale.c:161 libvips/iofuncs/system.c:311 msgid "Log" msgstr "" #: libvips/conversion/scale.c:162 msgid "Log scale" msgstr "" #: libvips/conversion/scale.c:169 msgid "Exponent for log scale" msgstr "" #: libvips/conversion/sequential.c:239 msgid "check sequential access" msgstr "" #: libvips/conversion/sequential.c:256 msgid "Strategy" msgstr "" #: libvips/conversion/sequential.c:257 libvips/conversion/tilecache.c:422 msgid "Expected access pattern" msgstr "" #: libvips/conversion/sequential.c:263 msgid "Trace" msgstr "" #: libvips/conversion/sequential.c:264 msgid "Trace pixel requests" msgstr "" #: libvips/conversion/smartcrop.c:453 msgid "Interesting" msgstr "" #: libvips/conversion/smartcrop.c:454 msgid "How to measure interestingness" msgstr "" #: libvips/conversion/smartcrop.c:460 msgid "Attention x" msgstr "" #: libvips/conversion/smartcrop.c:461 msgid "Horizontal position of attention centre" msgstr "" #: libvips/conversion/smartcrop.c:467 msgid "Attention y" msgstr "" #: libvips/conversion/smartcrop.c:468 msgid "Vertical position of attention centre" msgstr "" #: libvips/conversion/smartcrop.c:475 msgid "Input image already has premultiplied alpha" msgstr "" #: libvips/conversion/subsample.c:228 libvips/resample/reduceh.cpp:546 #: libvips/resample/reducev.cpp:1001 libvips/resample/shrinkh.c:399 #: libvips/resample/shrinkv.c:562 msgid "image has shrunk to nothing" msgstr "" #: libvips/conversion/subsample.c:259 msgid "subsample an image" msgstr "" #: libvips/conversion/subsample.c:273 libvips/conversion/zoom.c:379 msgid "Xfac" msgstr "" #: libvips/conversion/subsample.c:274 msgid "Horizontal subsample factor" msgstr "" #: libvips/conversion/subsample.c:280 libvips/conversion/zoom.c:386 msgid "Yfac" msgstr "" #: libvips/conversion/subsample.c:281 msgid "Vertical subsample factor" msgstr "" #: libvips/conversion/subsample.c:287 msgid "Point" msgstr "" #: libvips/conversion/subsample.c:288 msgid "Point sample" msgstr "" #: libvips/conversion/switch.c:129 msgid "bad number of tests" msgstr "" #: libvips/conversion/switch.c:161 msgid "test images not 1-band" msgstr "" #: libvips/conversion/switch.c:189 msgid "find the index of the first non-zero pixel in tests" msgstr "" #: libvips/conversion/switch.c:195 msgid "Tests" msgstr "" #: libvips/conversion/switch.c:196 msgid "Table of images to test" msgstr "" #: libvips/conversion/tilecache.c:421 libvips/foreign/foreign.c:1243 msgid "Access" msgstr "" #: libvips/conversion/tilecache.c:428 msgid "Threaded" msgstr "" #: libvips/conversion/tilecache.c:429 msgid "Allow threaded access" msgstr "" #: libvips/conversion/tilecache.c:435 msgid "Persistent" msgstr "" #: libvips/conversion/tilecache.c:436 msgid "Keep cache between evaluations" msgstr "" #: libvips/conversion/tilecache.c:806 msgid "cache an image as a set of tiles" msgstr "" #: libvips/conversion/tilecache.c:994 msgid "cache an image as a set of lines" msgstr "" #: libvips/conversion/transpose3d.c:135 msgid "bad page_height" msgstr "" #: libvips/conversion/transpose3d.c:163 #, fuzzy msgid "transpose3d an image" msgstr "false-colour an image" #: libvips/conversion/transpose3d.c:173 libvips/foreign/foreign.c:1887 msgid "Page height" msgstr "" #: libvips/conversion/transpose3d.c:174 msgid "Height of each input page" msgstr "" #: libvips/conversion/unpremultiply.c:317 msgid "unpremultiply image alpha" msgstr "" #: libvips/conversion/unpremultiply.c:336 msgid "Alpha band" msgstr "" #: libvips/conversion/unpremultiply.c:337 msgid "Unpremultiply with this alpha" msgstr "" #: libvips/conversion/wrap.c:115 msgid "wrap image origin" msgstr "" #: libvips/conversion/zoom.c:328 msgid "zoom factors too large" msgstr "" #: libvips/conversion/zoom.c:367 msgid "zoom an image" msgstr "" #: libvips/conversion/zoom.c:380 msgid "Horizontal zoom factor" msgstr "" #: libvips/conversion/zoom.c:387 msgid "Vertical zoom factor" msgstr "" #: libvips/convolution/canny.c:436 msgid "Canny edge detector" msgstr "" #: libvips/convolution/canny.c:454 libvips/convolution/gaussblur.c:144 #: libvips/convolution/sharpen.c:334 libvips/create/gaussmat.c:185 #: libvips/create/gaussnoise.c:189 msgid "Sigma" msgstr "" #: libvips/convolution/canny.c:455 libvips/convolution/gaussblur.c:145 #: libvips/convolution/sharpen.c:335 libvips/create/gaussmat.c:186 msgid "Sigma of Gaussian" msgstr "" #: libvips/convolution/canny.c:461 libvips/convolution/compass.c:184 #: libvips/convolution/conv.c:134 libvips/convolution/convsep.c:130 #: libvips/convolution/gaussblur.c:158 libvips/create/gaussmat.c:213 #: libvips/create/logmat.c:229 msgid "Precision" msgstr "" #: libvips/convolution/canny.c:462 libvips/convolution/compass.c:185 #: libvips/convolution/conv.c:135 libvips/convolution/convsep.c:131 #: libvips/convolution/gaussblur.c:159 msgid "Convolve with this precision" msgstr "" #: libvips/convolution/compass.c:159 msgid "convolve with rotating mask" msgstr "" #: libvips/convolution/compass.c:163 msgid "Times" msgstr "" #: libvips/convolution/compass.c:164 msgid "Rotate and convolve this many times" msgstr "" #: libvips/convolution/compass.c:171 msgid "Rotate mask by this much between convolutions" msgstr "" #: libvips/convolution/compass.c:178 msgid "Combine convolution results like this" msgstr "" #: libvips/convolution/compass.c:191 libvips/convolution/conva.c:1323 #: libvips/convolution/convasep.c:918 libvips/convolution/conv.c:141 #: libvips/convolution/convsep.c:137 msgid "Layers" msgstr "" #: libvips/convolution/compass.c:192 libvips/convolution/conva.c:1324 #: libvips/convolution/convasep.c:919 libvips/convolution/conv.c:142 #: libvips/convolution/convsep.c:138 msgid "Use this many layers in approximation" msgstr "" #: libvips/convolution/compass.c:198 libvips/convolution/conva.c:1330 #: libvips/convolution/conv.c:148 libvips/convolution/convsep.c:144 msgid "Cluster" msgstr "" #: libvips/convolution/compass.c:199 libvips/convolution/conva.c:1331 #: libvips/convolution/conv.c:149 libvips/convolution/convsep.c:145 msgid "Cluster lines closer than this in approximation" msgstr "" #: libvips/convolution/conva.c:236 libvips/convolution/conva.c:242 #: libvips/convolution/conva.c:760 libvips/convolution/convasep.c:151 msgid "mask too complex" msgstr "" #: libvips/convolution/conva.c:997 libvips/convolution/conva.c:1247 #: libvips/convolution/convasep.c:840 msgid "image too small for mask" msgstr "" #: libvips/convolution/conva.c:1319 msgid "approximate integer convolution" msgstr "" #: libvips/convolution/convasep.c:914 msgid "approximate separable integer convolution" msgstr "" #: libvips/convolution/conv.c:130 msgid "convolution operation" msgstr "" #: libvips/convolution/convf.c:374 msgid "float convolution operation" msgstr "" #: libvips/convolution/convi.c:1245 msgid "int convolution operation" msgstr "" #: libvips/convolution/convolution.c:109 msgid "convolution operations" msgstr "" #: libvips/convolution/convolution.c:130 libvips/convolution/correlation.c:156 #: libvips/draw/draw_mask.c:332 libvips/freqfilt/freqmult.c:130 #: libvips/morphology/labelregions.c:124 libvips/morphology/morph.c:966 msgid "Mask" msgstr "" #: libvips/convolution/convolution.c:131 libvips/morphology/morph.c:967 msgid "Input matrix image" msgstr "" #: libvips/convolution/convsep.c:126 msgid "separable convolution operation" msgstr "" #: libvips/convolution/correlation.c:144 msgid "correlation operation" msgstr "" #: libvips/convolution/correlation.c:157 msgid "Input reference image" msgstr "" #: libvips/convolution/edge.c:213 msgid "Edge detector" msgstr "" #: libvips/convolution/edge.c:258 msgid "Sobel edge detector" msgstr "" #: libvips/convolution/edge.c:291 msgid "Scharr edge detector" msgstr "" #: libvips/convolution/edge.c:324 msgid "Prewitt edge detector" msgstr "" #: libvips/convolution/fastcor.c:218 msgid "fast correlation" msgstr "" #: libvips/convolution/gaussblur.c:126 msgid "gaussian blur" msgstr "" #: libvips/convolution/gaussblur.c:151 libvips/create/gaussmat.c:192 msgid "Minimum amplitude" msgstr "" #: libvips/convolution/gaussblur.c:152 libvips/create/gaussmat.c:193 #: libvips/create/logmat.c:209 msgid "Minimum amplitude of Gaussian" msgstr "" #: libvips/convolution/sharpen.c:316 msgid "unsharp masking for print" msgstr "" #: libvips/convolution/sharpen.c:341 libvips/draw/draw_line.c:284 msgid "x1" msgstr "" #: libvips/convolution/sharpen.c:342 msgid "Flat/jaggy threshold" msgstr "" #: libvips/convolution/sharpen.c:348 libvips/draw/draw_line.c:305 msgid "y2" msgstr "" #: libvips/convolution/sharpen.c:349 msgid "Maximum brightening" msgstr "" #: libvips/convolution/sharpen.c:355 msgid "y3" msgstr "" #: libvips/convolution/sharpen.c:356 msgid "Maximum darkening" msgstr "" #: libvips/convolution/sharpen.c:362 msgid "m1" msgstr "" #: libvips/convolution/sharpen.c:363 msgid "Slope for flat areas" msgstr "" #: libvips/convolution/sharpen.c:369 msgid "m2" msgstr "" #: libvips/convolution/sharpen.c:370 msgid "Slope for jaggy areas" msgstr "" #: libvips/convolution/sharpen.c:378 libvips/create/logmat.c:201 #: libvips/create/mask_butterworth_band.c:136 #: libvips/create/mask_gaussian_band.c:121 libvips/create/mask_ideal_band.c:112 #: libvips/create/sdf.c:326 libvips/draw/draw_circle.c:248 msgid "Radius" msgstr "" #: libvips/convolution/sharpen.c:379 libvips/create/logmat.c:202 msgid "Radius of Gaussian" msgstr "" #: libvips/convolution/spcor.c:317 msgid "spatial correlation" msgstr "" #: libvips/create/black.c:136 msgid "make a black image" msgstr "" #: libvips/create/buildlut.c:134 #, c-format msgid "x value row %d not an int" msgstr "" #: libvips/create/buildlut.c:149 msgid "x range too small" msgstr "" #: libvips/create/buildlut.c:259 libvips/create/tonelut.c:221 msgid "build a look-up table" msgstr "" #: libvips/create/buildlut.c:264 libvips/create/invertlut.c:289 msgid "Matrix of XY coordinates" msgstr "" #: libvips/create/create.c:112 msgid "create operations" msgstr "" #: libvips/create/eye.c:103 msgid "make an image showing the eye's spatial response" msgstr "" #: libvips/create/eye.c:109 msgid "Maximum spatial frequency" msgstr "" #: libvips/create/fractsurf.c:100 msgid "make a fractal surface" msgstr "" #: libvips/create/fractsurf.c:118 libvips/create/fractsurf.c:119 #: libvips/create/mask_fractal.c:93 libvips/create/mask_fractal.c:94 msgid "Fractal dimension" msgstr "" #: libvips/create/gaussmat.c:129 libvips/create/logmat.c:147 msgid "mask too large" msgstr "" #: libvips/create/gaussmat.c:181 msgid "make a gaussian image" msgstr "" #: libvips/create/gaussmat.c:199 libvips/create/logmat.c:215 msgid "Separable" msgstr "" #: libvips/create/gaussmat.c:200 libvips/create/logmat.c:216 msgid "Generate separable Gaussian" msgstr "" #: libvips/create/gaussmat.c:206 libvips/create/logmat.c:222 msgid "Integer" msgstr "" #: libvips/create/gaussmat.c:207 libvips/create/logmat.c:223 msgid "Generate integer Gaussian" msgstr "" #: libvips/create/gaussmat.c:214 libvips/create/logmat.c:230 msgid "Generate with this precision" msgstr "" #: libvips/create/gaussnoise.c:160 msgid "make a gaussnoise image" msgstr "" #: libvips/create/gaussnoise.c:182 libvips/histogram/stdif.c:329 msgid "Mean" msgstr "" #: libvips/create/gaussnoise.c:183 msgid "Mean of pixels in generated image" msgstr "" #: libvips/create/gaussnoise.c:190 msgid "Standard deviation of pixels in generated image" msgstr "" #: libvips/create/gaussnoise.c:196 libvips/create/perlin.c:323 #: libvips/create/worley.c:329 msgid "Seed" msgstr "" #: libvips/create/gaussnoise.c:197 libvips/create/perlin.c:324 #: libvips/create/worley.c:330 msgid "Random number seed" msgstr "" #: libvips/create/grey.c:89 msgid "make a grey ramp image" msgstr "" #: libvips/create/identity.c:139 msgid "make a 1D image where pixel values are indexes" msgstr "" #: libvips/create/identity.c:144 msgid "Number of bands in LUT" msgstr "" #: libvips/create/identity.c:150 msgid "Ushort" msgstr "" #: libvips/create/identity.c:151 msgid "Create a 16-bit LUT" msgstr "" #: libvips/create/identity.c:158 msgid "Size of 16-bit LUT" msgstr "" #: libvips/create/invertlut.c:124 msgid "bad input matrix" msgstr "" #: libvips/create/invertlut.c:129 msgid "bad size" msgstr "" #: libvips/create/invertlut.c:149 #, c-format msgid "element (%d, %d) is %g, outside range [0,1]" msgstr "" #: libvips/create/invertlut.c:284 msgid "build an inverted look-up table" msgstr "" #: libvips/create/invertlut.c:295 msgid "LUT size to generate" msgstr "" #: libvips/create/logmat.c:197 msgid "make a Laplacian of Gaussian image" msgstr "" #: libvips/create/mask_butterworth_band.c:110 msgid "make a butterworth_band filter" msgstr "" #: libvips/create/mask_butterworth_band.c:115 #: libvips/create/mask_butterworth.c:91 msgid "Order" msgstr "" #: libvips/create/mask_butterworth_band.c:116 #: libvips/create/mask_butterworth.c:92 msgid "Filter order" msgstr "" #: libvips/create/mask_butterworth_band.c:122 #: libvips/create/mask_butterworth_band.c:123 #: libvips/create/mask_gaussian_band.c:107 #: libvips/create/mask_gaussian_band.c:108 libvips/create/mask_ideal_band.c:98 #: libvips/create/mask_ideal_band.c:99 msgid "Frequency cutoff x" msgstr "" #: libvips/create/mask_butterworth_band.c:129 #: libvips/create/mask_butterworth_band.c:130 #: libvips/create/mask_gaussian_band.c:114 #: libvips/create/mask_gaussian_band.c:115 libvips/create/mask_ideal_band.c:105 #: libvips/create/mask_ideal_band.c:106 msgid "Frequency cutoff y" msgstr "" #: libvips/create/mask_butterworth_band.c:137 #: libvips/create/mask_gaussian_band.c:122 libvips/create/mask_ideal_band.c:113 msgid "Radius of circle" msgstr "" #: libvips/create/mask_butterworth_band.c:143 #: libvips/create/mask_butterworth_band.c:144 #: libvips/create/mask_butterworth.c:105 libvips/create/mask_butterworth.c:106 #: libvips/create/mask_gaussian_band.c:128 #: libvips/create/mask_gaussian_band.c:129 libvips/create/mask_gaussian.c:93 #: libvips/create/mask_gaussian.c:94 msgid "Amplitude cutoff" msgstr "" #: libvips/create/mask_butterworth.c:86 msgid "make a butterworth filter" msgstr "" #: libvips/create/mask_butterworth.c:98 libvips/create/mask_butterworth.c:99 #: libvips/create/mask_gaussian.c:86 libvips/create/mask_gaussian.c:87 #: libvips/create/mask_ideal.c:84 libvips/create/mask_ideal.c:85 msgid "Frequency cutoff" msgstr "" #: libvips/create/mask_butterworth_ring.c:101 msgid "make a butterworth ring filter" msgstr "" #: libvips/create/mask_butterworth_ring.c:106 #: libvips/create/mask_butterworth_ring.c:107 #: libvips/create/mask_gaussian_ring.c:101 #: libvips/create/mask_gaussian_ring.c:102 libvips/create/mask_ideal_ring.c:98 #: libvips/create/mask_ideal_ring.c:99 msgid "Ringwidth" msgstr "" #: libvips/create/mask.c:114 msgid "base class for frequency filters" msgstr "" #: libvips/create/mask.c:122 msgid "Optical" msgstr "" #: libvips/create/mask.c:123 msgid "Rotate quadrants to optical space" msgstr "" #: libvips/create/mask.c:129 msgid "Reject" msgstr "" #: libvips/create/mask.c:130 msgid "Invert the sense of the filter" msgstr "" #: libvips/create/mask.c:136 msgid "Nodc" msgstr "" #: libvips/create/mask.c:137 msgid "Remove DC component" msgstr "" #: libvips/create/mask_fractal.c:88 msgid "make fractal filter" msgstr "" #: libvips/create/mask_gaussian_band.c:102 libvips/create/mask_gaussian.c:81 msgid "make a gaussian filter" msgstr "" #: libvips/create/mask_gaussian_ring.c:96 msgid "make a gaussian ring filter" msgstr "" #: libvips/create/mask_ideal_band.c:93 msgid "make an ideal band filter" msgstr "" #: libvips/create/mask_ideal.c:79 msgid "make an ideal filter" msgstr "" #: libvips/create/mask_ideal_ring.c:93 msgid "make an ideal ring filter" msgstr "" #: libvips/create/perlin.c:291 msgid "make a perlin noise image" msgstr "" #: libvips/create/perlin.c:309 libvips/create/worley.c:322 msgid "Cell size" msgstr "" #: libvips/create/perlin.c:310 msgid "Size of Perlin cells" msgstr "" #: libvips/create/perlin.c:316 libvips/create/point.c:155 msgid "Uchar" msgstr "" #: libvips/create/perlin.c:317 libvips/create/point.c:156 msgid "Output an unsigned char image" msgstr "" #: libvips/create/point.c:132 msgid "make a point image" msgstr "" #: libvips/create/sdf.c:178 msgid "circle needs a, r to be set" msgstr "" #: libvips/create/sdf.c:183 msgid "rounded-box needs 2 values for a" msgstr "" #: libvips/create/sdf.c:196 msgid "box needs a, b to be set" msgstr "" #: libvips/create/sdf.c:202 msgid "box needs 2 values for a, b" msgstr "" #: libvips/create/sdf.c:216 msgid "rounded-box needs a, b to be set" msgstr "" #: libvips/create/sdf.c:222 msgid "rounded-box needs 2 values for a, b" msgstr "" #: libvips/create/sdf.c:227 msgid "rounded-box needs 4 values for corners" msgstr "" #: libvips/create/sdf.c:242 msgid "line needs sx, sy to be set" msgstr "" #: libvips/create/sdf.c:248 msgid "line needs 2 values for a, b" msgstr "" #: libvips/create/sdf.c:259 #, c-format msgid "unknown SDF %d" msgstr "" #: libvips/create/sdf.c:300 msgid "create an SDF image" msgstr "" #: libvips/create/sdf.c:318 msgid "Shape" msgstr "" #: libvips/create/sdf.c:319 msgid "SDF shape to create" msgstr "" #: libvips/create/sdf.c:325 msgid "r" msgstr "" #: libvips/create/sdf.c:333 msgid "Point a" msgstr "" #: libvips/create/sdf.c:340 msgid "Point b" msgstr "" #: libvips/create/sdf.c:346 msgid "corners" msgstr "" #: libvips/create/sdf.c:347 msgid "Corner radii" msgstr "" #: libvips/create/sines.c:122 msgid "make a 2D sine wave" msgstr "" #: libvips/create/sines.c:128 msgid "hfreq" msgstr "" #: libvips/create/sines.c:129 msgid "Horizontal spatial frequency" msgstr "" #: libvips/create/sines.c:135 msgid "vfreq" msgstr "" #: libvips/create/sines.c:136 msgid "Vertical spatial frequency" msgstr "" #: libvips/create/text.c:411 msgid "invalid markup in text" msgstr "" #: libvips/create/text.c:471 msgid "no text to render" msgstr "" #: libvips/create/text.c:553 msgid "make a text image" msgstr "" #: libvips/create/text.c:557 msgid "Text" msgstr "" #: libvips/create/text.c:558 msgid "Text to render" msgstr "" #: libvips/create/text.c:564 msgid "Font" msgstr "" #: libvips/create/text.c:565 msgid "Font to render with" msgstr "" #: libvips/create/text.c:572 msgid "Maximum image width in pixels" msgstr "" #: libvips/create/text.c:579 msgid "Maximum image height in pixels" msgstr "" #: libvips/create/text.c:586 msgid "Align on the low, centre or high edge" msgstr "" #: libvips/create/text.c:592 msgid "Justify" msgstr "" #: libvips/create/text.c:593 msgid "Justify lines" msgstr "" #: libvips/create/text.c:599 libvips/foreign/pdfiumload.c:707 #: libvips/foreign/popplerload.c:557 libvips/foreign/svgload.c:782 msgid "DPI" msgstr "" #: libvips/create/text.c:600 libvips/foreign/pdfiumload.c:708 #: libvips/foreign/popplerload.c:558 msgid "DPI to render at" msgstr "" #: libvips/create/text.c:606 msgid "Autofit DPI" msgstr "" #: libvips/create/text.c:607 msgid "DPI selected by autofit" msgstr "" #: libvips/create/text.c:613 msgid "Spacing" msgstr "" #: libvips/create/text.c:614 msgid "Line spacing" msgstr "" #: libvips/create/text.c:620 msgid "Font file" msgstr "" #: libvips/create/text.c:621 msgid "Load this font file" msgstr "" #: libvips/create/text.c:627 msgid "RGBA" msgstr "" #: libvips/create/text.c:628 msgid "Enable RGBA output" msgstr "" #: libvips/create/text.c:634 msgid "Wrap" msgstr "" #: libvips/create/text.c:635 msgid "Wrap lines on word or character boundaries" msgstr "" #: libvips/create/tonelut.c:225 msgid "In-max" msgstr "" #: libvips/create/tonelut.c:226 msgid "Size of LUT to build" msgstr "" #: libvips/create/tonelut.c:232 msgid "Out-max" msgstr "" #: libvips/create/tonelut.c:233 msgid "Maximum value in output LUT" msgstr "" #: libvips/create/tonelut.c:239 msgid "Black point" msgstr "" #: libvips/create/tonelut.c:240 msgid "Lowest value in output" msgstr "" #: libvips/create/tonelut.c:246 msgid "White point" msgstr "" #: libvips/create/tonelut.c:247 msgid "Highest value in output" msgstr "" #: libvips/create/tonelut.c:253 msgid "Shadow point" msgstr "" #: libvips/create/tonelut.c:254 msgid "Position of shadow" msgstr "" #: libvips/create/tonelut.c:260 msgid "Mid-tone point" msgstr "" #: libvips/create/tonelut.c:261 msgid "Position of mid-tones" msgstr "" #: libvips/create/tonelut.c:267 msgid "Highlight point" msgstr "" #: libvips/create/tonelut.c:268 msgid "Position of highlights" msgstr "" #: libvips/create/tonelut.c:274 msgid "Shadow adjust" msgstr "" #: libvips/create/tonelut.c:275 msgid "Adjust shadows by this much" msgstr "" #: libvips/create/tonelut.c:281 msgid "Mid-tone adjust" msgstr "" #: libvips/create/tonelut.c:282 msgid "Adjust mid-tones by this much" msgstr "" #: libvips/create/tonelut.c:288 msgid "Highlight adjust" msgstr "" #: libvips/create/tonelut.c:289 msgid "Adjust highlights by this much" msgstr "" #: libvips/create/worley.c:304 msgid "make a worley noise image" msgstr "" #: libvips/create/worley.c:323 msgid "Size of Worley cells" msgstr "" #: libvips/create/xyz.c:139 msgid "lower dimensions not set" msgstr "" #: libvips/create/xyz.c:156 libvips/foreign/heifsave.c:671 #: libvips/foreign/webpsave.c:736 msgid "image too large" msgstr "" #: libvips/create/xyz.c:187 msgid "make an image where pixel values are coordinates" msgstr "" #: libvips/create/xyz.c:205 msgid "csize" msgstr "" #: libvips/create/xyz.c:206 msgid "Size of third dimension" msgstr "" #: libvips/create/xyz.c:212 msgid "dsize" msgstr "" #: libvips/create/xyz.c:213 msgid "Size of fourth dimension" msgstr "" #: libvips/create/xyz.c:219 msgid "esize" msgstr "" #: libvips/create/xyz.c:220 msgid "Size of fifth dimension" msgstr "" #: libvips/create/zone.c:90 msgid "make a zone plate" msgstr "" #: libvips/draw/draw.c:101 msgid "draw operations" msgstr "" #: libvips/draw/draw.c:108 msgid "Image" msgstr "" #: libvips/draw/draw.c:109 msgid "Image to draw on" msgstr "" #: libvips/draw/draw_circle.c:230 msgid "draw a circle on an image" msgstr "" #: libvips/draw/draw_circle.c:234 msgid "cx" msgstr "" #: libvips/draw/draw_circle.c:235 libvips/draw/draw_circle.c:242 msgid "Centre of draw_circle" msgstr "" #: libvips/draw/draw_circle.c:241 msgid "cy" msgstr "" #: libvips/draw/draw_circle.c:249 msgid "Radius in pixels" msgstr "" #: libvips/draw/draw_circle.c:255 libvips/draw/draw_rect.c:201 msgid "Fill" msgstr "" #: libvips/draw/draw_circle.c:256 libvips/draw/draw_rect.c:202 msgid "Draw a solid object" msgstr "" #: libvips/draw/draw_flood.c:562 msgid "flood-fill an area" msgstr "" #: libvips/draw/draw_flood.c:567 libvips/draw/draw_flood.c:574 msgid "DrawFlood start point" msgstr "" #: libvips/draw/draw_flood.c:580 msgid "Test" msgstr "" #: libvips/draw/draw_flood.c:581 msgid "Test pixels in this image" msgstr "" #: libvips/draw/draw_flood.c:586 msgid "Equal" msgstr "" #: libvips/draw/draw_flood.c:587 msgid "DrawFlood while equal to edge" msgstr "" #: libvips/draw/draw_flood.c:594 msgid "Left edge of modified area" msgstr "" #: libvips/draw/draw_flood.c:601 msgid "Top edge of modified area" msgstr "" #: libvips/draw/draw_flood.c:608 msgid "Width of modified area" msgstr "" #: libvips/draw/draw_flood.c:615 msgid "Height of modified area" msgstr "" #: libvips/draw/draw_image.c:265 msgid "paint an image into another image" msgstr "" #: libvips/draw/draw_image.c:276 libvips/draw/draw_image.c:283 msgid "Draw image here" msgstr "" #: libvips/draw/draw_image.c:289 libvips/iofuncs/image.c:1164 msgid "Mode" msgstr "" #: libvips/draw/draw_image.c:290 msgid "Combining mode" msgstr "" #: libvips/draw/drawink.c:86 msgid "draw with ink operations" msgstr "" #: libvips/draw/drawink.c:90 msgid "Ink" msgstr "" #: libvips/draw/drawink.c:91 msgid "Color for pixels" msgstr "" #: libvips/draw/draw_line.c:280 msgid "draw a line on an image" msgstr "" #: libvips/draw/draw_line.c:285 libvips/draw/draw_line.c:292 msgid "Start of draw_line" msgstr "" #: libvips/draw/draw_line.c:291 msgid "y1" msgstr "" #: libvips/draw/draw_line.c:298 msgid "x2" msgstr "" #: libvips/draw/draw_line.c:299 libvips/draw/draw_line.c:306 msgid "End of draw_line" msgstr "" #: libvips/draw/draw_mask.c:328 msgid "draw a mask on an image" msgstr "" #: libvips/draw/draw_mask.c:333 msgid "Mask of pixels to draw" msgstr "" #: libvips/draw/draw_mask.c:339 libvips/draw/draw_mask.c:346 msgid "Draw mask here" msgstr "" #: libvips/draw/draw_rect.c:169 msgid "paint a rectangle on an image" msgstr "" #: libvips/draw/draw_rect.c:174 libvips/draw/draw_rect.c:181 #: libvips/draw/draw_rect.c:188 libvips/draw/draw_rect.c:195 #: libvips/draw/draw_smudge.c:216 libvips/draw/draw_smudge.c:223 #: libvips/draw/draw_smudge.c:230 libvips/draw/draw_smudge.c:237 msgid "Rect to fill" msgstr "" #: libvips/draw/draw_smudge.c:211 msgid "blur a rectangle on an image" msgstr "" #: libvips/foreign/analyze2vips.c:308 msgid "header file size incorrect" msgstr "" #: libvips/foreign/analyze2vips.c:352 msgid "header size incorrect" msgstr "" #: libvips/foreign/analyze2vips.c:370 libvips/foreign/niftiload.c:397 #, c-format msgid "%d-dimensional images not supported" msgstr "" #: libvips/foreign/analyze2vips.c:423 libvips/foreign/niftiload.c:440 #, c-format msgid "datatype %d not supported" msgstr "" #: libvips/foreign/analyzeload.c:120 msgid "load an Analyze6 image" msgstr "" #: libvips/foreign/analyzeload.c:141 libvips/foreign/cgifsave.c:1058 #: libvips/foreign/csvload.c:586 libvips/foreign/csvsave.c:274 #: libvips/foreign/dzsave.c:2588 libvips/foreign/fitsload.c:254 #: libvips/foreign/fitssave.c:143 libvips/foreign/heifload.c:1267 #: libvips/foreign/heifsave.c:883 libvips/foreign/jp2kload.c:1319 #: libvips/foreign/jp2ksave.c:1060 libvips/foreign/jpegload.c:346 #: libvips/foreign/jpegsave.c:364 libvips/foreign/jxlload.c:1210 #: libvips/foreign/jxlsave.c:1178 libvips/foreign/magick6load.c:977 #: libvips/foreign/magick7load.c:849 libvips/foreign/matload.c:138 #: libvips/foreign/matrixload.c:370 libvips/foreign/matrixsave.c:228 #: libvips/foreign/niftiload.c:708 libvips/foreign/niftisave.c:441 #: libvips/foreign/nsgifload.c:762 libvips/foreign/openexrload.c:149 #: libvips/foreign/openslideload.c:1097 libvips/foreign/pdfiumload.c:810 #: libvips/foreign/pngload.c:313 libvips/foreign/pngsave.c:386 #: libvips/foreign/popplerload.c:687 libvips/foreign/ppmload.c:827 #: libvips/foreign/ppmsave.c:578 libvips/foreign/radload.c:276 #: libvips/foreign/radsave.c:155 libvips/foreign/rawload.c:139 #: libvips/foreign/rawsave.c:196 libvips/foreign/spngload.c:830 #: libvips/foreign/spngsave.c:863 libvips/foreign/svgload.c:1008 #: libvips/foreign/tiffload.c:376 libvips/foreign/tiffsave.c:524 #: libvips/foreign/vips2magick.c:578 libvips/foreign/vipsload.c:233 #: libvips/foreign/vipssave.c:191 libvips/foreign/webpload.c:338 #: libvips/foreign/webpsave.c:1035 libvips/iofuncs/connection.c:125 #: libvips/iofuncs/image.c:1157 libvips/resample/thumbnail.c:1216 msgid "Filename" msgstr "" #: libvips/foreign/analyzeload.c:142 libvips/foreign/csvload.c:587 #: libvips/foreign/fitsload.c:255 libvips/foreign/heifload.c:1268 #: libvips/foreign/jp2kload.c:1320 libvips/foreign/jpegload.c:347 #: libvips/foreign/jxlload.c:1211 libvips/foreign/magick6load.c:978 #: libvips/foreign/magick7load.c:850 libvips/foreign/matload.c:139 #: libvips/foreign/matrixload.c:371 libvips/foreign/niftiload.c:709 #: libvips/foreign/nsgifload.c:763 libvips/foreign/openexrload.c:150 #: libvips/foreign/openslideload.c:1098 libvips/foreign/pdfiumload.c:811 #: libvips/foreign/pngload.c:314 libvips/foreign/popplerload.c:688 #: libvips/foreign/ppmload.c:828 libvips/foreign/radload.c:277 #: libvips/foreign/rawload.c:140 libvips/foreign/spngload.c:831 #: libvips/foreign/svgload.c:1009 libvips/foreign/tiffload.c:377 #: libvips/foreign/vipsload.c:234 libvips/foreign/webpload.c:339 msgid "Filename to load from" msgstr "" #: libvips/foreign/archive.c:138 msgid "unable to create archive" msgstr "" #: libvips/foreign/archive.c:146 msgid "unable to set zip format" msgstr "" #: libvips/foreign/archive.c:163 msgid "unable to set compression" msgstr "" #: libvips/foreign/archive.c:175 msgid "unable to set padding" msgstr "" #: libvips/foreign/archive.c:184 libvips/iofuncs/target.c:158 msgid "unable to open for write" msgstr "" #: libvips/foreign/archive.c:205 libvips/iofuncs/util.c:1192 #, c-format msgid "unable to create directory \"%s\", %s" msgstr "" #: libvips/foreign/archive.c:240 msgid "unable to create entry" msgstr "" #: libvips/foreign/archive.c:256 msgid "unable to write header" msgstr "" #: libvips/foreign/archive.c:265 msgid "unable to write data" msgstr "" #: libvips/foreign/cgifsave.c:407 libvips/foreign/cgifsave.c:832 #: libvips/foreign/quantise.c:403 libvips/foreign/quantise.c:423 msgid "quantisation failed" msgstr "" #: libvips/foreign/cgifsave.c:587 msgid "dither failed" msgstr "" #: libvips/foreign/cgifsave.c:771 msgid "frame too large" msgstr "" #: libvips/foreign/cgifsave.c:810 msgid "gif-palette too large" msgstr "" #: libvips/foreign/cgifsave.c:883 msgid "save as gif" msgstr "" #: libvips/foreign/cgifsave.c:893 libvips/foreign/pngsave.c:260 #: libvips/foreign/spngsave.c:736 msgid "Dithering" msgstr "" #: libvips/foreign/cgifsave.c:894 libvips/foreign/pngsave.c:261 #: libvips/foreign/spngsave.c:737 msgid "Amount of dithering" msgstr "" #: libvips/foreign/cgifsave.c:900 libvips/foreign/heifsave.c:792 #: libvips/foreign/jxlsave.c:1106 libvips/foreign/pngsave.c:274 #: libvips/foreign/spngsave.c:750 libvips/foreign/webpsave.c:893 msgid "Effort" msgstr "" #: libvips/foreign/cgifsave.c:901 msgid "Quantisation effort" msgstr "" #: libvips/foreign/cgifsave.c:907 libvips/foreign/heifsave.c:770 #: libvips/foreign/pngsave.c:267 libvips/foreign/ppmsave.c:507 #: libvips/foreign/spngsave.c:743 libvips/foreign/tiffsave.c:318 #: libvips/foreign/vips2magick.c:510 msgid "Bit depth" msgstr "" #: libvips/foreign/cgifsave.c:908 libvips/foreign/heifsave.c:771 #: libvips/foreign/vips2magick.c:511 msgid "Number of bits per pixel" msgstr "" #: libvips/foreign/cgifsave.c:914 msgid "Maximum inter-frame error" msgstr "" #: libvips/foreign/cgifsave.c:915 msgid "Maximum inter-frame error for transparency" msgstr "" #: libvips/foreign/cgifsave.c:921 msgid "Reuse palette" msgstr "" #: libvips/foreign/cgifsave.c:922 msgid "Reuse palette from input" msgstr "" #: libvips/foreign/cgifsave.c:928 msgid "Maximum inter-palette error" msgstr "" #: libvips/foreign/cgifsave.c:929 msgid "Maximum inter-palette error for palette reusage" msgstr "" #: libvips/foreign/cgifsave.c:935 msgid "Interlaced" msgstr "" #: libvips/foreign/cgifsave.c:936 msgid "Generate an interlaced (progressive) GIF" msgstr "" #: libvips/foreign/cgifsave.c:945 msgid "Reoptimise palettes" msgstr "" #: libvips/foreign/cgifsave.c:946 msgid "Reoptimise colour palettes" msgstr "" #: libvips/foreign/cgifsave.c:952 msgid "Keep duplicate frames" msgstr "" #: libvips/foreign/cgifsave.c:953 msgid "Keep duplicate frames in the output instead of combining them" msgstr "" #: libvips/foreign/cgifsave.c:1010 libvips/foreign/csvsave.c:325 #: libvips/foreign/dzsave.c:2531 libvips/foreign/heifsave.c:1003 #: libvips/foreign/jp2ksave.c:1176 libvips/foreign/jpegsave.c:295 #: libvips/foreign/jxlsave.c:1294 libvips/foreign/matrixsave.c:281 #: libvips/foreign/pngsave.c:336 libvips/foreign/ppmsave.c:634 #: libvips/foreign/radsave.c:208 libvips/foreign/rawsave.c:252 #: libvips/foreign/spngsave.c:813 libvips/foreign/tiffsave.c:474 #: libvips/foreign/vipssave.c:244 libvips/foreign/webpsave.c:987 #: libvips/iofuncs/target.c:305 msgid "Target" msgstr "" #: libvips/foreign/cgifsave.c:1011 libvips/foreign/csvsave.c:326 #: libvips/foreign/dzsave.c:2532 libvips/foreign/heifsave.c:1004 #: libvips/foreign/jp2ksave.c:1177 libvips/foreign/jpegsave.c:296 #: libvips/foreign/jxlsave.c:1295 libvips/foreign/matrixsave.c:282 #: libvips/foreign/pngsave.c:337 libvips/foreign/ppmsave.c:635 #: libvips/foreign/radsave.c:209 libvips/foreign/rawsave.c:253 #: libvips/foreign/spngsave.c:814 libvips/foreign/tiffsave.c:475 #: libvips/foreign/vipssave.c:245 libvips/foreign/webpsave.c:988 msgid "Target to save to" msgstr "" #: libvips/foreign/cgifsave.c:1059 libvips/foreign/csvsave.c:275 #: libvips/foreign/dzsave.c:2589 libvips/foreign/fitssave.c:144 #: libvips/foreign/heifsave.c:884 libvips/foreign/jp2ksave.c:1061 #: libvips/foreign/jpegsave.c:365 libvips/foreign/jxlsave.c:1179 #: libvips/foreign/matrixsave.c:229 libvips/foreign/niftisave.c:442 #: libvips/foreign/pngsave.c:387 libvips/foreign/ppmsave.c:579 #: libvips/foreign/radsave.c:156 libvips/foreign/rawsave.c:197 #: libvips/foreign/spngsave.c:864 libvips/foreign/tiffsave.c:525 #: libvips/foreign/vips2magick.c:579 libvips/foreign/vipssave.c:192 #: libvips/foreign/webpsave.c:1036 msgid "Filename to save to" msgstr "" #: libvips/foreign/cgifsave.c:1117 libvips/foreign/dzsave.c:2647 #: libvips/foreign/heifload.c:1333 libvips/foreign/heifsave.c:948 #: libvips/foreign/jp2kload.c:1392 libvips/foreign/jp2ksave.c:1123 #: libvips/foreign/jpegload.c:419 libvips/foreign/jpegsave.c:442 #: libvips/foreign/jxlload.c:1283 libvips/foreign/jxlsave.c:1241 #: libvips/foreign/magick6load.c:1065 libvips/foreign/magick7load.c:930 #: libvips/foreign/nsgifload.c:837 libvips/foreign/pdfiumload.c:870 #: libvips/foreign/pngload.c:386 libvips/foreign/pngsave.c:445 #: libvips/foreign/popplerload.c:747 libvips/foreign/ppmload.c:900 #: libvips/foreign/radload.c:349 libvips/foreign/radsave.c:274 #: libvips/foreign/rawsave.c:314 libvips/foreign/spngload.c:903 #: libvips/foreign/spngsave.c:923 libvips/foreign/svgload.c:1076 #: libvips/foreign/tiffload.c:451 libvips/foreign/tiffsave.c:585 #: libvips/foreign/vips2magick.c:650 libvips/foreign/webpload.c:413 #: libvips/foreign/webpsave.c:1093 libvips/resample/thumbnail.c:1463 msgid "Buffer" msgstr "" #: libvips/foreign/cgifsave.c:1118 libvips/foreign/dzsave.c:2648 #: libvips/foreign/heifsave.c:949 libvips/foreign/jp2ksave.c:1124 #: libvips/foreign/jpegsave.c:443 libvips/foreign/jxlsave.c:1242 #: libvips/foreign/pngsave.c:446 libvips/foreign/radsave.c:275 #: libvips/foreign/rawsave.c:315 libvips/foreign/spngsave.c:924 #: libvips/foreign/tiffsave.c:586 libvips/foreign/vips2magick.c:651 #: libvips/foreign/webpsave.c:1094 msgid "Buffer to save to" msgstr "" #: libvips/foreign/csvload.c:339 libvips/foreign/csvload.c:400 #: libvips/foreign/csvload.c:432 msgid "unexpected end of file" msgstr "" #: libvips/foreign/csvload.c:438 #, c-format msgid "line %d has only %d columns" msgstr "" #: libvips/foreign/csvload.c:477 msgid "load csv" msgstr "" #: libvips/foreign/csvload.c:490 msgid "Skip" msgstr "" #: libvips/foreign/csvload.c:491 msgid "Skip this many lines at the start of the file" msgstr "" #: libvips/foreign/csvload.c:497 msgid "Lines" msgstr "" #: libvips/foreign/csvload.c:498 msgid "Read this many lines from the file" msgstr "" #: libvips/foreign/csvload.c:504 msgid "Whitespace" msgstr "" #: libvips/foreign/csvload.c:505 msgid "Set of whitespace characters" msgstr "" #: libvips/foreign/csvload.c:511 libvips/foreign/csvsave.c:223 msgid "Separator" msgstr "" #: libvips/foreign/csvload.c:512 msgid "Set of separator characters" msgstr "" #: libvips/foreign/csvload.c:654 libvips/foreign/fitsload.c:330 #: libvips/foreign/heifload.c:1404 libvips/foreign/jp2kload.c:1452 #: libvips/foreign/jpegload.c:273 libvips/foreign/jxlload.c:1344 #: libvips/foreign/matrixload.c:454 libvips/foreign/niftiload.c:784 #: libvips/foreign/nsgifload.c:900 libvips/foreign/openslideload.c:1171 #: libvips/foreign/pdfiumload.c:930 libvips/foreign/pngload.c:239 #: libvips/foreign/popplerload.c:807 libvips/foreign/ppmload.c:959 #: libvips/foreign/radload.c:202 libvips/foreign/spngload.c:754 #: libvips/foreign/svgload.c:915 libvips/foreign/tiffload.c:299 #: libvips/foreign/vipsload.c:306 libvips/foreign/webpload.c:261 #: libvips/resample/thumbnail.c:1677 msgid "Source" msgstr "" #: libvips/foreign/csvload.c:655 libvips/foreign/fitsload.c:331 #: libvips/foreign/heifload.c:1405 libvips/foreign/jp2kload.c:1453 #: libvips/foreign/jpegload.c:274 libvips/foreign/jxlload.c:1345 #: libvips/foreign/matrixload.c:455 libvips/foreign/niftiload.c:785 #: libvips/foreign/nsgifload.c:901 libvips/foreign/openslideload.c:1172 #: libvips/foreign/pdfiumload.c:931 libvips/foreign/pngload.c:240 #: libvips/foreign/popplerload.c:808 libvips/foreign/ppmload.c:960 #: libvips/foreign/radload.c:203 libvips/foreign/spngload.c:755 #: libvips/foreign/svgload.c:916 libvips/foreign/tiffload.c:300 #: libvips/foreign/vipsload.c:307 libvips/foreign/webpload.c:262 #: libvips/iofuncs/sbuf.c:84 libvips/resample/thumbnail.c:1678 msgid "Source to load from" msgstr "" #: libvips/foreign/csvsave.c:215 msgid "save image to csv" msgstr "" #: libvips/foreign/csvsave.c:224 msgid "Separator characters" msgstr "" #: libvips/foreign/dzsave.c:2008 msgid "overlap too large" msgstr "" #: libvips/foreign/dzsave.c:2316 msgid "save image to deep zoom format" msgstr "" #: libvips/foreign/dzsave.c:2326 libvips/foreign/dzsave.c:2327 msgid "Image name" msgstr "" #: libvips/foreign/dzsave.c:2333 msgid "Layout" msgstr "" #: libvips/foreign/dzsave.c:2334 msgid "Directory layout" msgstr "" #: libvips/foreign/dzsave.c:2340 msgid "Suffix" msgstr "" #: libvips/foreign/dzsave.c:2341 msgid "Filename suffix for tiles" msgstr "" #: libvips/foreign/dzsave.c:2347 msgid "Overlap" msgstr "" #: libvips/foreign/dzsave.c:2348 msgid "Tile overlap in pixels" msgstr "" #: libvips/foreign/dzsave.c:2354 msgid "Tile size" msgstr "" #: libvips/foreign/dzsave.c:2355 msgid "Tile size in pixels" msgstr "" #: libvips/foreign/dzsave.c:2362 libvips/foreign/tiffsave.c:382 msgid "Pyramid depth" msgstr "" #: libvips/foreign/dzsave.c:2368 msgid "Center" msgstr "" #: libvips/foreign/dzsave.c:2369 msgid "Center image in tile" msgstr "" #: libvips/foreign/dzsave.c:2376 msgid "Rotate image during save" msgstr "" #: libvips/foreign/dzsave.c:2382 msgid "Container" msgstr "" #: libvips/foreign/dzsave.c:2383 msgid "Pyramid container type" msgstr "" #: libvips/foreign/dzsave.c:2389 libvips/foreign/heifsave.c:784 #: libvips/foreign/pngsave.c:224 libvips/foreign/spngsave.c:700 #: libvips/foreign/tiffsave.c:260 msgid "Compression" msgstr "" #: libvips/foreign/dzsave.c:2390 msgid "ZIP deflate compression level" msgstr "" #: libvips/foreign/dzsave.c:2396 libvips/foreign/tiffsave.c:360 msgid "Region shrink" msgstr "" #: libvips/foreign/dzsave.c:2397 libvips/foreign/tiffsave.c:361 msgid "Method to shrink regions" msgstr "" #: libvips/foreign/dzsave.c:2403 msgid "Skip blanks" msgstr "" #: libvips/foreign/dzsave.c:2404 msgid "Skip tiles which are nearly equal to the background" msgstr "" #: libvips/foreign/dzsave.c:2410 msgid "id" msgstr "" #: libvips/foreign/dzsave.c:2411 msgid "Resource ID" msgstr "" #: libvips/foreign/dzsave.c:2417 libvips/foreign/heifsave.c:763 #: libvips/foreign/jp2ksave.c:1000 libvips/foreign/jpegsave.c:167 #: libvips/foreign/jxlsave.c:1120 libvips/foreign/tiffsave.c:268 #: libvips/foreign/webpsave.c:829 msgid "Q" msgstr "" #: libvips/foreign/dzsave.c:2418 libvips/foreign/heifsave.c:764 #: libvips/foreign/jp2ksave.c:1001 libvips/foreign/jpegsave.c:168 #: libvips/foreign/tiffsave.c:269 libvips/foreign/webpsave.c:830 msgid "Q factor" msgstr "" #: libvips/foreign/dzsave.c:2427 msgid "No strip" msgstr "" #: libvips/foreign/dzsave.c:2428 msgid "Don't strip tile metadata" msgstr "" #: libvips/foreign/dzsave.c:2434 msgid "Base name" msgstr "" #: libvips/foreign/dzsave.c:2435 msgid "Base name to save to" msgstr "" #: libvips/foreign/dzsave.c:2441 msgid "Directory name" msgstr "" #: libvips/foreign/dzsave.c:2442 msgid "Directory name to save to" msgstr "" #: libvips/foreign/dzsave.c:2462 libvips/foreign/tiffsave.c:353 msgid "Properties" msgstr "" #: libvips/foreign/dzsave.c:2463 msgid "Write a properties file to the output directory" msgstr "" #: libvips/foreign/dzsave.c:2527 msgid "save image to deepzoom target" msgstr "" #: libvips/foreign/dzsave.c:2584 msgid "save image to deepzoom file" msgstr "" #: libvips/foreign/dzsave.c:2643 msgid "save image to dz buffer" msgstr "" #: libvips/foreign/exif.c:199 msgid "exif too small" msgstr "" #: libvips/foreign/exif.c:203 msgid "exif too large" msgstr "" #: libvips/foreign/exif.c:208 msgid "unable to init exif" msgstr "" #: libvips/foreign/exif.c:1496 msgid "error saving EXIF" msgstr "" #: libvips/foreign/fits.c:185 libvips/foreign/matlab.c:113 #: libvips/iofuncs/vips.c:145 libvips/mosaicing/global_balance.c:1240 #: libvips/mosaicing/global_balance.c:1684 #, c-format msgid "unable to open \"%s\"" msgstr "" #: libvips/foreign/fits.c:236 msgid "no HDU found with naxes > 0" msgstr "" #: libvips/foreign/fits.c:274 msgid "dimensions above 3 must be size 1" msgstr "" #: libvips/foreign/fits.c:289 #, c-format msgid "bad number of axis %d" msgstr "" #: libvips/foreign/fits.c:300 #, c-format msgid "unsupported bitpix %d\n" msgstr "" #: libvips/foreign/fits.c:585 libvips/iofuncs/vips.c:208 #, c-format msgid "unable to write to \"%s\"" msgstr "" #: libvips/foreign/fits.c:726 #, c-format msgid "unsupported BandFmt %d\n" msgstr "" #: libvips/foreign/fitsload.c:101 libvips/foreign/niftiload.c:130 #: libvips/foreign/openslideload.c:874 msgid "no filename available" msgstr "" #: libvips/foreign/fitsload.c:181 msgid "FITS loader base class" msgstr "" #: libvips/foreign/fitsload.c:246 msgid "load a FITS image" msgstr "" #: libvips/foreign/fitsload.c:321 msgid "load FITS from a source" msgstr "" #: libvips/foreign/fitssave.c:129 msgid "save image to fits file" msgstr "" #: libvips/foreign/foreign.c:417 msgid "load and save image files" msgstr "" #: libvips/foreign/foreign.c:618 #, c-format msgid "file \"%s\" does not exist" msgstr "" #: libvips/foreign/foreign.c:623 #, c-format msgid "\"%s\" is a directory" msgstr "" #: libvips/foreign/foreign.c:632 libvips/foreign/foreign.c:1976 #, c-format msgid "\"%s\" is not a known file format" msgstr "" #: libvips/foreign/foreign.c:720 msgid "buffer is not in a known format" msgstr "" #: libvips/foreign/foreign.c:782 msgid "source is not in a known format" msgstr "" #: libvips/foreign/foreign.c:987 msgid "images do not match between header and load" msgstr "" #: libvips/foreign/foreign.c:1218 msgid "loaders" msgstr "" #: libvips/foreign/foreign.c:1229 msgid "Flags" msgstr "" #: libvips/foreign/foreign.c:1230 msgid "Flags for this file" msgstr "" #: libvips/foreign/foreign.c:1236 libvips/iofuncs/target.c:316 msgid "Memory" msgstr "" #: libvips/foreign/foreign.c:1237 msgid "Force open via memory" msgstr "" #: libvips/foreign/foreign.c:1244 msgid "Required access pattern for this file" msgstr "" #: libvips/foreign/foreign.c:1250 libvips/resample/thumbnail.c:1037 msgid "Fail on" msgstr "" #: libvips/foreign/foreign.c:1251 libvips/resample/thumbnail.c:1038 msgid "Error level to fail on" msgstr "" #: libvips/foreign/foreign.c:1257 msgid "Revalidate" msgstr "" #: libvips/foreign/foreign.c:1258 msgid "Don't use a cached result for this operation" msgstr "" #: libvips/foreign/foreign.c:1264 msgid "Sequential" msgstr "" #: libvips/foreign/foreign.c:1265 msgid "Sequential read only" msgstr "" #: libvips/foreign/foreign.c:1271 msgid "Fail" msgstr "" #: libvips/foreign/foreign.c:1272 msgid "Fail on first warning" msgstr "" #: libvips/foreign/foreign.c:1278 msgid "Disc" msgstr "" #: libvips/foreign/foreign.c:1279 msgid "Open to disc" msgstr "" #: libvips/foreign/foreign.c:1520 msgid "saver does not support any output type" msgstr "" #: libvips/foreign/foreign.c:1845 msgid "savers" msgstr "" #: libvips/foreign/foreign.c:1867 msgid "Image to save" msgstr "" #: libvips/foreign/foreign.c:1872 msgid "Keep" msgstr "" #: libvips/foreign/foreign.c:1873 msgid "Which metadata to retain" msgstr "" #: libvips/foreign/foreign.c:1888 msgid "Set page height for multipage save" msgstr "" #: libvips/foreign/foreign.c:1895 msgid "Filename of ICC profile to embed" msgstr "" #: libvips/foreign/foreign.c:1901 msgid "Strip" msgstr "" #: libvips/foreign/foreign.c:1902 msgid "Strip all metadata from image" msgstr "" #: libvips/foreign/foreign.c:2132 #, c-format msgid "\"%s\" is not a known target format" msgstr "" #: libvips/foreign/foreign.c:2191 #, c-format msgid "\"%s\" is not a known buffer format" msgstr "" #: libvips/foreign/heifload.c:821 libvips/foreign/jxlload.c:747 #: libvips/foreign/nsgifload.c:448 libvips/foreign/webp2vips.c:501 msgid "bad page number" msgstr "" #: libvips/foreign/heifload.c:873 msgid "undefined bits per pixel" msgstr "" #: libvips/foreign/heifload.c:885 msgid "not all pages are the same size" msgstr "" #: libvips/foreign/heifload.c:982 msgid "bad image dimensions on decode" msgstr "" #: libvips/foreign/heifload.c:989 msgid "unable to get image data" msgstr "" #: libvips/foreign/heifload.c:1074 msgid "load a HEIF image" msgstr "" #: libvips/foreign/heifload.c:1082 libvips/foreign/jp2kload.c:1234 #: libvips/foreign/jxlload.c:1126 libvips/foreign/magick6load.c:302 #: libvips/foreign/magick7load.c:379 libvips/foreign/nsgifload.c:620 #: libvips/foreign/pdfiumload.c:693 libvips/foreign/popplerload.c:543 #: libvips/foreign/tiffload.c:196 libvips/foreign/webpload.c:176 msgid "Page" msgstr "" #: libvips/foreign/heifload.c:1083 libvips/foreign/jxlload.c:1127 #: libvips/foreign/magick6load.c:303 libvips/foreign/magick7load.c:380 #: libvips/foreign/nsgifload.c:621 libvips/foreign/pdfiumload.c:694 #: libvips/foreign/popplerload.c:544 libvips/foreign/tiffload.c:197 #: libvips/foreign/webpload.c:177 msgid "First page to load" msgstr "" #: libvips/foreign/heifload.c:1090 libvips/foreign/jxlload.c:1134 #: libvips/foreign/magick6load.c:310 libvips/foreign/magick7load.c:387 #: libvips/foreign/nsgifload.c:628 libvips/foreign/pdfiumload.c:701 #: libvips/foreign/popplerload.c:551 libvips/foreign/tiffload.c:204 #: libvips/foreign/webpload.c:184 msgid "Number of pages to load, -1 for all" msgstr "" #: libvips/foreign/heifload.c:1096 msgid "Thumbnail" msgstr "" #: libvips/foreign/heifload.c:1097 msgid "Fetch thumbnail image" msgstr "" #: libvips/foreign/heifload.c:1103 libvips/foreign/jpegload.c:196 #: libvips/foreign/tiffload.c:210 msgid "Autorotate" msgstr "" #: libvips/foreign/heifload.c:1104 libvips/foreign/jpegload.c:197 msgid "Rotate image using exif orientation" msgstr "" #: libvips/foreign/heifload.c:1111 libvips/foreign/jpegload.c:204 #: libvips/foreign/pngload.c:171 libvips/foreign/spngload.c:678 #: libvips/foreign/svgload.c:797 libvips/foreign/tiffload.c:225 msgid "Unlimited" msgstr "" #: libvips/foreign/heifload.c:1112 libvips/foreign/jpegload.c:205 #: libvips/foreign/pngload.c:172 libvips/foreign/spngload.c:679 #: libvips/foreign/tiffload.c:226 msgid "Remove all denial of service limits" msgstr "" #: libvips/foreign/heifload.c:1334 libvips/foreign/jp2kload.c:1393 #: libvips/foreign/jpegload.c:420 libvips/foreign/jxlload.c:1284 #: libvips/foreign/magick6load.c:1066 libvips/foreign/magick7load.c:931 #: libvips/foreign/nsgifload.c:838 libvips/foreign/pdfiumload.c:871 #: libvips/foreign/pngload.c:387 libvips/foreign/popplerload.c:748 #: libvips/foreign/ppmload.c:901 libvips/foreign/radload.c:350 #: libvips/foreign/spngload.c:904 libvips/foreign/svgload.c:1077 #: libvips/foreign/tiffload.c:452 libvips/foreign/webpload.c:414 #: libvips/resample/thumbnail.c:1464 msgid "Buffer to load from" msgstr "" #: libvips/foreign/heifsave.c:430 #, fuzzy msgid "unimplemented format conversion" msgstr "unimplemented output colour space 0x%x" #: libvips/foreign/heifsave.c:540 #, c-format msgid "%d-bit colour depth not supported" msgstr "" #: libvips/foreign/heifsave.c:573 #, fuzzy msgid "Unsupported compression" msgstr "unsupported colour type" #: libvips/foreign/heifsave.c:755 msgid "save image in HEIF format" msgstr "" #: libvips/foreign/heifsave.c:777 libvips/foreign/jp2ksave.c:985 #: libvips/foreign/jxlsave.c:1113 libvips/foreign/tiffsave.c:374 #: libvips/foreign/webpsave.c:836 msgid "Lossless" msgstr "" #: libvips/foreign/heifsave.c:778 libvips/foreign/jp2ksave.c:986 #: libvips/foreign/jxlsave.c:1114 libvips/foreign/webpsave.c:837 msgid "Enable lossless compression" msgstr "" #: libvips/foreign/heifsave.c:785 msgid "Compression format" msgstr "" #: libvips/foreign/heifsave.c:793 libvips/foreign/heifsave.c:808 msgid "CPU effort" msgstr "" #: libvips/foreign/heifsave.c:799 libvips/foreign/jp2ksave.c:992 #: libvips/foreign/jpegsave.c:223 msgid "Subsample mode" msgstr "" #: libvips/foreign/heifsave.c:800 libvips/foreign/jp2ksave.c:993 #: libvips/foreign/jpegsave.c:224 msgid "Select chroma subsample operation mode" msgstr "" #: libvips/foreign/heifsave.c:807 msgid "Speed" msgstr "" #: libvips/foreign/heifsave.c:814 msgid "Encoder" msgstr "" #: libvips/foreign/heifsave.c:815 msgid "Select encoder to use" msgstr "" #: libvips/foreign/heifsave.c:1030 msgid "save image in AVIF format" msgstr "" #: libvips/foreign/jp2kload.c:239 msgid "unable to create jp2k stream" msgstr "" #: libvips/foreign/jp2kload.c:555 #, fuzzy, c-format msgid "unsupported colourspace %d" msgstr "unsupported colourspace %d" #: libvips/foreign/jp2kload.c:604 msgid "too many image bands" msgstr "" #: libvips/foreign/jp2kload.c:608 msgid "no image components" msgstr "" #: libvips/foreign/jp2kload.c:625 msgid "components differ in geometry" msgstr "" #: libvips/foreign/jp2kload.c:632 msgid "components differ in precision" msgstr "" #: libvips/foreign/jp2kload.c:1003 libvips/foreign/jp2kload.c:1100 msgid "decoded image does not match container" msgstr "" #: libvips/foreign/jp2kload.c:1222 msgid "load JPEG2000 image" msgstr "" #: libvips/foreign/jp2kload.c:1235 msgid "Load this page from the image" msgstr "" #: libvips/foreign/jp2kload.c:1241 msgid "One-shot" msgstr "" #: libvips/foreign/jp2kload.c:1242 msgid "Load images a frame at a time" msgstr "" #: libvips/foreign/jp2kload.c:1604 libvips/foreign/jp2ksave.c:1428 msgid "libvips built without JPEG2000 support" msgstr "" #: libvips/foreign/jp2ksave.c:818 msgid "not an integer format" msgstr "" #: libvips/foreign/jp2ksave.c:963 msgid "save image in JPEG2000 format" msgstr "" #: libvips/foreign/jpeg2vips.c:886 libvips/foreign/spngload.c:529 #: libvips/foreign/vipspng.c:723 #, c-format msgid "out of order read at line %d" msgstr "" #: libvips/foreign/jpegload.c:116 #, c-format msgid "bad shrink factor %d" msgstr "" #: libvips/foreign/jpegload.c:175 msgid "load jpeg" msgstr "" #: libvips/foreign/jpegload.c:189 libvips/foreign/webpload.c:197 msgid "Shrink" msgstr "" #: libvips/foreign/jpegload.c:190 libvips/foreign/webpload.c:198 msgid "Shrink factor on load" msgstr "" #: libvips/foreign/jpegload.c:265 msgid "load image from jpeg source" msgstr "" #: libvips/foreign/jpegload.c:338 msgid "load jpeg from file" msgstr "" #: libvips/foreign/jpegload.c:413 msgid "load jpeg from buffer" msgstr "" #: libvips/foreign/jpegsave.c:153 msgid "save jpeg" msgstr "" #: libvips/foreign/jpegsave.c:174 msgid "Optimize coding" msgstr "" #: libvips/foreign/jpegsave.c:175 msgid "Compute optimal Huffman coding tables" msgstr "" #: libvips/foreign/jpegsave.c:181 libvips/foreign/pngsave.c:231 #: libvips/foreign/spngsave.c:707 msgid "Interlace" msgstr "" #: libvips/foreign/jpegsave.c:182 msgid "Generate an interlaced (progressive) jpeg" msgstr "" #: libvips/foreign/jpegsave.c:188 msgid "No subsample" msgstr "" #: libvips/foreign/jpegsave.c:189 msgid "Disable chroma subsample" msgstr "" #: libvips/foreign/jpegsave.c:195 msgid "Trellis quantisation" msgstr "" #: libvips/foreign/jpegsave.c:196 msgid "Apply trellis quantisation to each 8x8 block" msgstr "" #: libvips/foreign/jpegsave.c:202 msgid "Overshoot de-ringing" msgstr "" #: libvips/foreign/jpegsave.c:203 msgid "Apply overshooting to samples with extreme values" msgstr "" #: libvips/foreign/jpegsave.c:209 msgid "Optimize scans" msgstr "" #: libvips/foreign/jpegsave.c:210 msgid "Split spectrum of DCT coefficients into separate scans" msgstr "" #: libvips/foreign/jpegsave.c:216 msgid "Quantization table" msgstr "" #: libvips/foreign/jpegsave.c:217 msgid "Use predefined quantization table with given index" msgstr "" #: libvips/foreign/jpegsave.c:231 msgid "Restart interval" msgstr "" #: libvips/foreign/jpegsave.c:232 msgid "Add restart markers every specified number of mcu" msgstr "" #: libvips/foreign/jpegsave.c:291 msgid "save image to jpeg target" msgstr "" #: libvips/foreign/jpegsave.c:360 msgid "save image to jpeg file" msgstr "" #: libvips/foreign/jpegsave.c:438 msgid "save image to jpeg buffer" msgstr "" #: libvips/foreign/jpegsave.c:514 msgid "save image to jpeg mime" msgstr "" #: libvips/foreign/jxlload.c:247 libvips/foreign/jxlsave.c:644 #: libvips/iofuncs/dbuf.c:81 libvips/iofuncs/util.c:759 msgid "out of memory" msgstr "" #: libvips/foreign/jxlload.c:572 msgid "bad buffer size" msgstr "" #: libvips/foreign/jxlload.c:598 libvips/foreign/webp2vips.c:724 msgid "not enough frames" msgstr "" #: libvips/foreign/jxlload.c:677 libvips/foreign/radiance.c:706 msgid "image size out of bounds" msgstr "" #: libvips/foreign/jxlload.c:1113 msgid "load JPEG-XL image" msgstr "" #: libvips/foreign/jxlsave.c:1078 msgid "save image in JPEG-XL format" msgstr "" #: libvips/foreign/jxlsave.c:1092 msgid "Tier" msgstr "" #: libvips/foreign/jxlsave.c:1093 msgid "Decode speed tier" msgstr "" #: libvips/foreign/jxlsave.c:1099 libvips/morphology/nearest.c:315 msgid "Distance" msgstr "" #: libvips/foreign/jxlsave.c:1100 msgid "Target butteraugli distance" msgstr "" #: libvips/foreign/jxlsave.c:1107 msgid "Encoding effort" msgstr "" #: libvips/foreign/jxlsave.c:1121 msgid "Quality factor" msgstr "" #: libvips/foreign/magick6load.c:273 msgid "load with ImageMagick" msgstr "" #: libvips/foreign/magick6load.c:295 libvips/foreign/magick7load.c:372 msgid "Density" msgstr "" #: libvips/foreign/magick6load.c:296 libvips/foreign/magick7load.c:373 msgid "Canvas resolution for rendering vector formats like SVG" msgstr "" #: libvips/foreign/magick6load.c:316 libvips/foreign/magick7load.c:393 msgid "All frames" msgstr "" #: libvips/foreign/magick6load.c:317 libvips/foreign/magick7load.c:394 msgid "Read all frames from an image" msgstr "" #: libvips/foreign/magick6load.c:365 #, c-format msgid "unsupported image type %d" msgstr "" #: libvips/foreign/magick6load.c:414 libvips/foreign/magick7load.c:469 #, c-format msgid "bad image dimensions %d x %d pixels, %d bands" msgstr "" #: libvips/foreign/magick6load.c:444 #, c-format msgid "unsupported bit depth %d" msgstr "" #: libvips/foreign/magick6load.c:852 libvips/foreign/webp2vips.c:638 msgid "unable to read pixels" msgstr "" #: libvips/foreign/magick6load.c:947 #, c-format msgid "unable to read file \"%s\"" msgstr "" #: libvips/foreign/magick6load.c:971 msgid "load file with ImageMagick" msgstr "" #: libvips/foreign/magick6load.c:1037 msgid "unable to read buffer" msgstr "" #: libvips/foreign/magick6load.c:1059 msgid "load buffer with ImageMagick" msgstr "" #: libvips/foreign/magick7load.c:350 msgid "load with ImageMagick7" msgstr "" #: libvips/foreign/magick7load.c:412 #, c-format msgid "Magick: %s %s" msgstr "" #: libvips/foreign/magick7load.c:489 #, c-format msgid "unsupported bit depth %zd" msgstr "" #: libvips/foreign/magick7load.c:843 msgid "load file with ImageMagick7" msgstr "" #: libvips/foreign/magick7load.c:924 msgid "load buffer with ImageMagick7" msgstr "" #: libvips/foreign/magick.c:804 #, c-format msgid "libMagick error: %s %s" msgstr "" #: libvips/foreign/magick.c:807 #, c-format msgid "libMagick error: %s" msgstr "" #: libvips/foreign/magick.c:810 msgid "libMagick error:" msgstr "" #: libvips/foreign/matlab.c:121 #, c-format msgid "no matrix variables in \"%s\"" msgstr "" #: libvips/foreign/matlab.c:203 #, c-format msgid "unsupported rank %d\n" msgstr "" #: libvips/foreign/matlab.c:211 #, c-format msgid "unsupported class type %d\n" msgstr "" #: libvips/foreign/matlab.c:265 msgid "Mat_VarReadDataAll failed" msgstr "" #: libvips/foreign/matload.c:122 msgid "load mat from file" msgstr "" #: libvips/foreign/matrixload.c:128 libvips/foreign/matrixload.c:241 #, c-format msgid "bad number \"%s\"" msgstr "" #: libvips/foreign/matrixload.c:137 msgid "no width / height" msgstr "" #: libvips/foreign/matrixload.c:143 msgid "width / height not int" msgstr "" #: libvips/foreign/matrixload.c:155 msgid "width / height out of range" msgstr "" #: libvips/foreign/matrixload.c:159 msgid "zero scale" msgstr "" #: libvips/foreign/matrixload.c:250 #, c-format msgid "line %d too short" msgstr "" #: libvips/foreign/matrixload.c:272 msgid "load matrix" msgstr "" #: libvips/foreign/matrixsave.c:175 msgid "save image to matrix" msgstr "" #: libvips/foreign/matrixsave.c:321 msgid "print matrix" msgstr "" #: libvips/foreign/niftiload.c:404 msgid "invalid dimension" msgstr "" #: libvips/foreign/niftiload.c:415 msgid "invalid resolution" msgstr "" #: libvips/foreign/niftiload.c:429 libvips/foreign/niftiload.c:433 #: libvips/foreign/niftisave.c:309 msgid "dimension overflow" msgstr "" #: libvips/foreign/niftiload.c:534 msgid "unable to read NIFTI header" msgstr "" #: libvips/foreign/niftiload.c:562 msgid "unable to load NIFTI file" msgstr "" #: libvips/foreign/niftiload.c:592 msgid "load a NIFTI image" msgstr "" #: libvips/foreign/niftiload.c:700 msgid "load NIfTI volume" msgstr "" #: libvips/foreign/niftiload.c:775 msgid "load NIfTI volumes" msgstr "" #: libvips/foreign/niftisave.c:115 libvips/foreign/niftisave.c:322 #, fuzzy msgid "unsupported libvips image type" msgstr "unsupported colour type" #: libvips/foreign/niftisave.c:122 msgid "8-bit colour images only" msgstr "" #: libvips/foreign/niftisave.c:132 msgid "3 or 4 band colour images only" msgstr "" #: libvips/foreign/niftisave.c:251 msgid "bad nifti-ext- field name" msgstr "" #: libvips/foreign/niftisave.c:260 msgid "unable to attach nifti ext" msgstr "" #: libvips/foreign/niftisave.c:315 libvips/foreign/nsgifload.c:644 #: libvips/foreign/webp2vips.c:550 msgid "bad image dimensions" msgstr "" #: libvips/foreign/niftisave.c:375 msgid "unable to set nifti filename" msgstr "" #: libvips/foreign/niftisave.c:427 msgid "save image to nifti file" msgstr "" #: libvips/foreign/nsgifload.c:420 msgid "no frames in GIF" msgstr "" #: libvips/foreign/nsgifload.c:463 msgid "bad frame" msgstr "" #: libvips/foreign/nsgifload.c:607 libvips/foreign/nsgifload.c:754 #: libvips/foreign/nsgifload.c:831 msgid "load GIF with libnsgif" msgstr "" #: libvips/foreign/nsgifload.c:892 msgid "load gif from source" msgstr "" #: libvips/foreign/openexr2vips.c:122 #, c-format msgid "EXR error: %s" msgstr "" #: libvips/foreign/openexrload.c:129 msgid "load an OpenEXR image" msgstr "" #: libvips/foreign/openslideload.c:186 msgid "invalid associated image name" msgstr "" #: libvips/foreign/openslideload.c:229 msgid "specify only one of level and associated image" msgstr "" #: libvips/foreign/openslideload.c:236 msgid "specify only one of attach_assicated and associated image" msgstr "" #: libvips/foreign/openslideload.c:353 libvips/foreign/openslideload.c:462 #: libvips/foreign/openslideload.c:613 #, c-format msgid "opening slide: %s" msgstr "" #: libvips/foreign/openslideload.c:373 #, c-format msgid "reading associated image: %s" msgstr "" #: libvips/foreign/openslideload.c:457 msgid "unsupported slide format" msgstr "" #: libvips/foreign/openslideload.c:468 msgid "invalid slide level" msgstr "" #: libvips/foreign/openslideload.c:554 #, c-format msgid "getting dimensions: %s" msgstr "" #: libvips/foreign/openslideload.c:560 msgid "image dimensions overflow int" msgstr "" #: libvips/foreign/openslideload.c:708 #, c-format msgid "reading region: %s" msgstr "" #: libvips/foreign/openslideload.c:973 msgid "load OpenSlide base class" msgstr "" #: libvips/foreign/openslideload.c:996 libvips/foreign/tiffsave.c:367 msgid "Level" msgstr "" #: libvips/foreign/openslideload.c:997 msgid "Load this level from the file" msgstr "" #: libvips/foreign/openslideload.c:1003 msgid "Autocrop" msgstr "" #: libvips/foreign/openslideload.c:1004 msgid "Crop to image bounds" msgstr "" #: libvips/foreign/openslideload.c:1010 msgid "Associated" msgstr "" #: libvips/foreign/openslideload.c:1011 msgid "Load this associated image" msgstr "" #: libvips/foreign/openslideload.c:1017 msgid "Attach associated" msgstr "" #: libvips/foreign/openslideload.c:1018 msgid "Attach all associated images" msgstr "" #: libvips/foreign/openslideload.c:1024 msgid "RGB" msgstr "" #: libvips/foreign/openslideload.c:1025 msgid "Output RGB (not RGBA)" msgstr "" #: libvips/foreign/openslideload.c:1089 msgid "load file with OpenSlide" msgstr "" #: libvips/foreign/openslideload.c:1164 msgid "load source with OpenSlide" msgstr "" #: libvips/foreign/pdfiumload.c:196 msgid "unknown error" msgstr "" #: libvips/foreign/pdfiumload.c:291 #, c-format msgid "%s: too large for pdfium" msgstr "" #: libvips/foreign/pdfiumload.c:307 #, c-format msgid "%s: unable to load" msgstr "" #: libvips/foreign/pdfiumload.c:318 #, c-format msgid "%s: unable to initialize form fill environment" msgstr "" #: libvips/foreign/pdfiumload.c:364 libvips/foreign/popplerload.c:237 #, c-format msgid "unable to load page %d" msgstr "" #: libvips/foreign/pdfiumload.c:476 libvips/foreign/popplerload.c:331 msgid "pages out of range" msgstr "" #: libvips/foreign/pdfiumload.c:511 msgid "page size out of range" msgstr "" #: libvips/foreign/pdfiumload.c:683 msgid "load PDF with PDFium" msgstr "" #: libvips/foreign/pdfiumload.c:715 libvips/foreign/popplerload.c:565 #: libvips/foreign/webpload.c:191 msgid "Factor to scale by" msgstr "" #: libvips/foreign/pdfiumload.c:722 libvips/foreign/popplerload.c:572 msgid "Background colour" msgstr "" #: libvips/foreign/pdfiumload.c:728 libvips/foreign/popplerload.c:578 msgid "Password" msgstr "" #: libvips/foreign/pdfiumload.c:729 libvips/foreign/popplerload.c:579 msgid "Password to decrypt with" msgstr "" #: libvips/foreign/pdfiumload.c:801 libvips/foreign/popplerload.c:678 msgid "load PDF from file" msgstr "" #: libvips/foreign/pdfiumload.c:864 libvips/foreign/popplerload.c:741 msgid "load PDF from buffer" msgstr "" #: libvips/foreign/pdfiumload.c:922 libvips/foreign/popplerload.c:799 msgid "load PDF from source" msgstr "" #: libvips/foreign/pngload.c:157 libvips/foreign/spngload.c:664 msgid "load png base class" msgstr "" #: libvips/foreign/pngload.c:231 libvips/foreign/spngload.c:746 msgid "load png from source" msgstr "" #: libvips/foreign/pngload.c:305 libvips/foreign/spngload.c:822 msgid "load png from file" msgstr "" #: libvips/foreign/pngload.c:380 libvips/foreign/spngload.c:897 msgid "load png from buffer" msgstr "" #: libvips/foreign/pngsave.c:212 msgid "save png" msgstr "" #: libvips/foreign/pngsave.c:225 libvips/foreign/spngsave.c:701 msgid "Compression factor" msgstr "" #: libvips/foreign/pngsave.c:232 libvips/foreign/spngsave.c:708 msgid "Interlace image" msgstr "" #: libvips/foreign/pngsave.c:238 libvips/foreign/spngsave.c:714 msgid "Filter" msgstr "" #: libvips/foreign/pngsave.c:239 msgid "libpng row filter flag(s)" msgstr "" #: libvips/foreign/pngsave.c:246 libvips/foreign/spngsave.c:722 msgid "Palette" msgstr "" #: libvips/foreign/pngsave.c:247 libvips/foreign/spngsave.c:723 msgid "Quantise to 8bpp palette" msgstr "" #: libvips/foreign/pngsave.c:253 libvips/foreign/spngsave.c:729 #: libvips/foreign/vips2magick.c:489 msgid "Quality" msgstr "" #: libvips/foreign/pngsave.c:254 libvips/foreign/spngsave.c:730 msgid "Quantisation quality" msgstr "" #: libvips/foreign/pngsave.c:268 libvips/foreign/spngsave.c:744 msgid "Write as a 1, 2, 4, 8 or 16 bit image" msgstr "" #: libvips/foreign/pngsave.c:275 libvips/foreign/spngsave.c:751 msgid "Quantisation CPU effort" msgstr "" #: libvips/foreign/pngsave.c:281 libvips/foreign/spngsave.c:757 msgid "Colours" msgstr "" #: libvips/foreign/pngsave.c:282 libvips/foreign/spngsave.c:758 msgid "Max number of palette colours" msgstr "" #: libvips/foreign/pngsave.c:332 libvips/foreign/spngsave.c:809 msgid "save image to target as PNG" msgstr "" #: libvips/foreign/pngsave.c:382 msgid "save image to png file" msgstr "" #: libvips/foreign/pngsave.c:441 msgid "save image to png buffer" msgstr "" #: libvips/foreign/popplerload.c:529 msgid "load PDF with libpoppler" msgstr "" #: libvips/foreign/ppmload.c:264 msgid "bad magic number" msgstr "" #: libvips/foreign/ppmload.c:521 msgid "file truncated" msgstr "" #: libvips/foreign/ppmload.c:746 msgid "load ppm base class" msgstr "" #: libvips/foreign/ppmload.c:821 msgid "load ppm from file" msgstr "" #: libvips/foreign/ppmload.c:894 msgid "load ppm from buffer" msgstr "" #: libvips/foreign/ppmload.c:951 msgid "load ppm from source" msgstr "" #: libvips/foreign/ppmsave.c:308 msgid "too few bands for format" msgstr "" #: libvips/foreign/ppmsave.c:485 msgid "save to ppm" msgstr "" #: libvips/foreign/ppmsave.c:493 libvips/foreign/vips2magick.c:483 msgid "Format to save in" msgstr "" #: libvips/foreign/ppmsave.c:500 msgid "ASCII" msgstr "" #: libvips/foreign/ppmsave.c:501 msgid "Save as ascii" msgstr "" #: libvips/foreign/ppmsave.c:508 msgid "Set to 1 to write as a 1 bit image" msgstr "" #: libvips/foreign/ppmsave.c:514 libvips/foreign/tiffsave.c:409 msgid "Squash" msgstr "" #: libvips/foreign/ppmsave.c:515 msgid "Save as one bit" msgstr "" #: libvips/foreign/ppmsave.c:572 msgid "save image to ppm file" msgstr "" #: libvips/foreign/ppmsave.c:661 msgid "save image in pbm format" msgstr "" #: libvips/foreign/ppmsave.c:693 msgid "save image in pgm format" msgstr "" #: libvips/foreign/ppmsave.c:725 msgid "save image in pfm format" msgstr "" #: libvips/foreign/ppmsave.c:757 msgid "save image in pnm format" msgstr "" #: libvips/foreign/quantise.c:469 msgid "libvips not built with quantisation support" msgstr "" #: libvips/foreign/radiance.c:438 msgid "scanline length mismatch" msgstr "" #: libvips/foreign/radiance.c:455 msgid "overrun" msgstr "" #: libvips/foreign/radiance.c:689 msgid "error reading radiance header" msgstr "" #: libvips/foreign/radiance.c:776 #, c-format msgid "read error line %d" msgstr "" #: libvips/foreign/radload.c:125 msgid "load rad base class" msgstr "" #: libvips/foreign/radload.c:194 msgid "load rad from source" msgstr "" #: libvips/foreign/radload.c:268 msgid "load a Radiance image from a file" msgstr "" #: libvips/foreign/radload.c:343 msgid "load rad from buffer" msgstr "" #: libvips/foreign/radsave.c:92 msgid "save Radiance" msgstr "" #: libvips/foreign/radsave.c:151 msgid "save image to Radiance file" msgstr "" #: libvips/foreign/radsave.c:204 msgid "save image to Radiance target" msgstr "" #: libvips/foreign/radsave.c:270 msgid "save image to Radiance buffer" msgstr "" #: libvips/foreign/rawload.c:131 msgid "load raw data from a file" msgstr "" #: libvips/foreign/rawload.c:167 libvips/iofuncs/image.c:1185 msgid "Size of header" msgstr "" #: libvips/foreign/rawload.c:168 libvips/iofuncs/image.c:1186 msgid "Offset in bytes from start of file" msgstr "" #: libvips/foreign/rawsave.c:138 msgid "save image to raw" msgstr "" #: libvips/foreign/rawsave.c:190 msgid "save image to raw file" msgstr "" #: libvips/foreign/rawsave.c:246 msgid "write raw image to target" msgstr "" #: libvips/foreign/rawsave.c:308 msgid "write raw image to buffer" msgstr "" #: libvips/foreign/spngload.c:403 #, fuzzy msgid "unknown color type" msgstr "unsupported colour type" #: libvips/foreign/spngload.c:562 msgid "libspng read error" msgstr "" #: libvips/foreign/spngsave.c:164 libvips/foreign/vipspng.c:1013 msgid "bad png comment key" msgstr "" #: libvips/foreign/spngsave.c:688 msgid "save spng" msgstr "" #: libvips/foreign/spngsave.c:715 msgid "libspng row filter flag(s)" msgstr "" #: libvips/foreign/spngsave.c:859 msgid "save image to file as PNG" msgstr "" #: libvips/foreign/spngsave.c:919 msgid "save image to buffer as PNG" msgstr "" #: libvips/foreign/svgload.c:680 libvips/foreign/svgload.c:698 msgid "SVG rendering failed" msgstr "" #: libvips/foreign/svgload.c:764 msgid "load SVG with rsvg" msgstr "" #: libvips/foreign/svgload.c:783 msgid "Render at this DPI" msgstr "" #: libvips/foreign/svgload.c:790 msgid "Scale output by this factor" msgstr "" #: libvips/foreign/svgload.c:798 msgid "Allow SVG of any size" msgstr "" #: libvips/foreign/svgload.c:805 msgid "Stylesheet" msgstr "" #: libvips/foreign/svgload.c:806 msgid "Custom CSS" msgstr "" #: libvips/foreign/svgload.c:812 msgid "High bitdepth" msgstr "" #: libvips/foreign/svgload.c:813 msgid "Enable scRGB 128-bit output (32-bit per channel)" msgstr "" #: libvips/foreign/svgload.c:906 msgid "load svg from source" msgstr "" #: libvips/foreign/tiff2vips.c:470 libvips/foreign/tiff2vips.c:488 #, c-format msgid "required field %d missing" msgstr "" #: libvips/foreign/tiff2vips.c:530 msgid "unknown resolution unit" msgstr "" #: libvips/foreign/tiff2vips.c:670 #, c-format msgid "bad page number %d" msgstr "" #: libvips/foreign/tiff2vips.c:680 #, c-format msgid "bad number of pages %d" msgstr "" #: libvips/foreign/tiff2vips.c:708 libvips/foreign/tiff2vips.c:750 #: libvips/iofuncs/source.c:854 msgid "read error" msgstr "" #: libvips/foreign/tiff2vips.c:792 #, c-format msgid "TIFF does not contain page %d" msgstr "" #: libvips/foreign/tiff2vips.c:802 msgid "no SUBIFD tag" msgstr "" #: libvips/foreign/tiff2vips.c:808 #, c-format msgid "subifd %d out of range, only 0-%d available" msgstr "" #: libvips/foreign/tiff2vips.c:816 msgid "subdirectory unreadable" msgstr "" #: libvips/foreign/tiff2vips.c:857 #, c-format msgid "not %d bands" msgstr "" #: libvips/foreign/tiff2vips.c:870 #, c-format msgid "not at least %d samples per pixel" msgstr "" #: libvips/foreign/tiff2vips.c:885 msgid "samples_per_pixel not a whole number of bytes" msgstr "" #: libvips/foreign/tiff2vips.c:898 #, c-format msgid "not photometric interpretation %d" msgstr "" #: libvips/foreign/tiff2vips.c:910 #, c-format msgid "not %d bits per sample" msgstr "" #: libvips/foreign/tiff2vips.c:926 #, c-format msgid "%d bits per sample palette image not supported" msgstr "" #: libvips/foreign/tiff2vips.c:985 msgid "unsupported tiff image type\n" msgstr "" #: libvips/foreign/tiff2vips.c:1593 msgid "bad colormap" msgstr "bad colourmap" #: libvips/foreign/tiff2vips.c:2320 #, c-format msgid "decompress error tile %d x %d" msgstr "" #: libvips/foreign/tiff2vips.c:2598 msgid "tiled separate planes not supported" msgstr "" #: libvips/foreign/tiff2vips.c:2617 libvips/foreign/tiff2vips.c:2900 #: libvips/foreign/tiff2vips.c:3024 msgid "unsupported tiff image type" msgstr "" #: libvips/foreign/tiff2vips.c:2751 #, c-format msgid "out of order read -- at line %d, but line %d requested" msgstr "" #: libvips/foreign/tiff2vips.c:3060 msgid "subsampled images not supported" msgstr "" #: libvips/foreign/tiff2vips.c:3072 msgid "not SGI-compressed LOGLUV" msgstr "" #: libvips/foreign/tiff2vips.c:3089 msgid "width/height out of range" msgstr "" #: libvips/foreign/tiff2vips.c:3098 msgid "samples out of range" msgstr "" #: libvips/foreign/tiff2vips.c:3184 libvips/foreign/tiff2vips.c:3212 msgid "tile size out of range" msgstr "" #: libvips/foreign/tiff2vips.c:3404 #, c-format msgid "page %d differs from page %d" msgstr "" #: libvips/foreign/tiff.c:224 libvips/foreign/tiff.c:239 msgid "unable to open source for input" msgstr "" #: libvips/foreign/tiff.c:347 libvips/foreign/tiff.c:362 msgid "unable to open target for output" msgstr "" #: libvips/foreign/tiffload.c:183 msgid "load tiff" msgstr "" #: libvips/foreign/tiffload.c:211 msgid "Rotate image using orientation tag" msgstr "" #: libvips/foreign/tiffload.c:217 msgid "subifd" msgstr "" #: libvips/foreign/tiffload.c:218 msgid "Subifd index" msgstr "" #: libvips/foreign/tiffload.c:291 msgid "load tiff from source" msgstr "" #: libvips/foreign/tiffload.c:368 msgid "load tiff from file" msgstr "" #: libvips/foreign/tiffload.c:445 msgid "load tiff from buffer" msgstr "" #: libvips/foreign/tiffsave.c:251 msgid "save image as tiff" msgstr "" #: libvips/foreign/tiffsave.c:261 msgid "Compression for this file" msgstr "" #: libvips/foreign/tiffsave.c:275 msgid "Predictor" msgstr "" #: libvips/foreign/tiffsave.c:276 msgid "Compression prediction" msgstr "" #: libvips/foreign/tiffsave.c:283 msgid "Tile" msgstr "" #: libvips/foreign/tiffsave.c:284 msgid "Write a tiled tiff" msgstr "" #: libvips/foreign/tiffsave.c:304 msgid "Pyramid" msgstr "" #: libvips/foreign/tiffsave.c:305 msgid "Write a pyramidal tiff" msgstr "" #: libvips/foreign/tiffsave.c:311 msgid "Miniswhite" msgstr "" #: libvips/foreign/tiffsave.c:312 msgid "Use 0 for white in 1-bit images" msgstr "" #: libvips/foreign/tiffsave.c:319 msgid "Write as a 1, 2, 4 or 8 bit image" msgstr "" #: libvips/foreign/tiffsave.c:325 libvips/foreign/tiffsave.c:326 msgid "Resolution unit" msgstr "" #: libvips/foreign/tiffsave.c:346 msgid "Bigtiff" msgstr "" #: libvips/foreign/tiffsave.c:347 msgid "Write a bigtiff image" msgstr "" #: libvips/foreign/tiffsave.c:354 msgid "Write a properties document to IMAGEDESCRIPTION" msgstr "" #: libvips/foreign/tiffsave.c:368 msgid "Deflate (1-9, default 6) or ZSTD (1-22, default 9) compression level" msgstr "" #: libvips/foreign/tiffsave.c:375 msgid "Enable WEBP lossless mode" msgstr "" #: libvips/foreign/tiffsave.c:388 msgid "Sub-IFD" msgstr "" #: libvips/foreign/tiffsave.c:389 msgid "Save pyr layers as sub-IFDs" msgstr "" #: libvips/foreign/tiffsave.c:395 msgid "Premultiply" msgstr "" #: libvips/foreign/tiffsave.c:396 msgid "Save with premultiplied alpha" msgstr "" #: libvips/foreign/tiffsave.c:402 msgid "RGB JPEG" msgstr "" #: libvips/foreign/tiffsave.c:403 msgid "Output RGB JPEG rather than YCbCr" msgstr "" #: libvips/foreign/tiffsave.c:410 msgid "Squash images down to 1 bit" msgstr "" #: libvips/foreign/tiffsave.c:470 msgid "save image to tiff target" msgstr "" #: libvips/foreign/tiffsave.c:520 msgid "save image to tiff file" msgstr "" #: libvips/foreign/tiffsave.c:581 msgid "save image to tiff buffer" msgstr "" #: libvips/foreign/vips2jpeg.c:176 #, c-format msgid "%s" msgstr "" #: libvips/foreign/vips2jpeg.c:1059 msgid "libvips built without JPEG support" msgstr "" #: libvips/foreign/vips2magick.c:319 #, fuzzy msgid "unsupported image format" msgstr "unsupported colour type" #: libvips/foreign/vips2magick.c:349 msgid "unsupported number of image bands" msgstr "" #: libvips/foreign/vips2magick.c:464 msgid "save with ImageMagick" msgstr "" #: libvips/foreign/vips2magick.c:490 msgid "Quality to use" msgstr "" #: libvips/foreign/vips2magick.c:496 msgid "Optimize_gif_frames" msgstr "" #: libvips/foreign/vips2magick.c:497 msgid "Apply GIF frames optimization" msgstr "" #: libvips/foreign/vips2magick.c:503 msgid "Optimize_gif_transparency" msgstr "" #: libvips/foreign/vips2magick.c:504 msgid "Apply GIF transparency optimization" msgstr "" #: libvips/foreign/vips2magick.c:574 msgid "save file with ImageMagick" msgstr "" #: libvips/foreign/vips2magick.c:646 msgid "save image to magick buffer" msgstr "" #: libvips/foreign/vips2magick.c:677 msgid "save bmp image with ImageMagick" msgstr "" #: libvips/foreign/vips2magick.c:710 msgid "save bmp image to magick buffer" msgstr "" #: libvips/foreign/vips2magick.c:743 msgid "save gif image with ImageMagick" msgstr "" #: libvips/foreign/vips2magick.c:776 msgid "save gif image to magick buffer" msgstr "" #: libvips/foreign/vips2tiff.c:1454 msgid "can only pyramid LABQ and non-complex images" msgstr "" #: libvips/foreign/vips2tiff.c:1477 msgid "tile size not a multiple of 16" msgstr "" #: libvips/foreign/vips2tiff.c:1835 libvips/foreign/vips2tiff.c:2024 msgid "TIFF write tile failed" msgstr "" #: libvips/foreign/vipsload.c:126 msgid "no filename associated with source" msgstr "" #: libvips/foreign/vipsload.c:157 msgid "load vips base class" msgstr "" #: libvips/foreign/vipsload.c:225 msgid "load vips from file" msgstr "" #: libvips/foreign/vipsload.c:297 msgid "load vips from source" msgstr "" #: libvips/foreign/vipspng.c:450 msgid "unsupported color type" msgstr "unsupported colour type" #: libvips/foreign/vipspng.c:564 msgid "unable to read PNG header" msgstr "" #: libvips/foreign/vipspng.c:756 msgid "libpng read error" msgstr "" #: libvips/foreign/vipspng.c:1112 msgid "compress should be in [0,9]" msgstr "" #: libvips/foreign/vipspng.c:1140 #, c-format msgid "can't save %d band image as png" msgstr "" #: libvips/foreign/vipspng.c:1341 #, c-format msgid "unable to write to target %s" msgstr "" #: libvips/foreign/vipssave.c:114 msgid "no filename associated with target" msgstr "" #: libvips/foreign/vipssave.c:139 msgid "save vips base class" msgstr "" #: libvips/foreign/vipssave.c:187 msgid "save image to file in vips format" msgstr "" #: libvips/foreign/vipssave.c:240 msgid "save image to target in vips format" msgstr "" #: libvips/foreign/webp2vips.c:407 msgid "unable to parse image" msgstr "" #: libvips/foreign/webp2vips.c:595 msgid "unable to loop through frames" msgstr "" #: libvips/foreign/webpload.c:162 msgid "load webp" msgstr "" #: libvips/foreign/webpload.c:253 msgid "load webp from source" msgstr "" #: libvips/foreign/webpload.c:330 msgid "load webp from file" msgstr "" #: libvips/foreign/webpload.c:407 msgid "load webp from buffer" msgstr "" #: libvips/foreign/webpsave.c:248 msgid "picture version error" msgstr "" #: libvips/foreign/webpsave.c:290 msgid "picture memory error" msgstr "" #: libvips/foreign/webpsave.c:333 msgid "anim add error" msgstr "" #: libvips/foreign/webpsave.c:347 msgid "unable to encode" msgstr "" #: libvips/foreign/webpsave.c:443 msgid "chunk add error" msgstr "" #: libvips/foreign/webpsave.c:549 libvips/foreign/webpsave.c:590 msgid "mux error" msgstr "" #: libvips/foreign/webpsave.c:610 libvips/foreign/webpsave.c:620 #: libvips/foreign/webpsave.c:658 msgid "config version error" msgstr "" #: libvips/foreign/webpsave.c:640 msgid "invalid configuration" msgstr "" #: libvips/foreign/webpsave.c:669 msgid "unable to init animation" msgstr "" #: libvips/foreign/webpsave.c:700 msgid "anim close error" msgstr "" #: libvips/foreign/webpsave.c:705 msgid "anim build error" msgstr "" #: libvips/foreign/webpsave.c:713 libvips/mosaicing/lrmerge.c:308 #: libvips/mosaicing/tbmerge.c:186 libvips/mosaicing/tbmerge.c:261 #: libvips/mosaicing/tbmerge.c:593 msgid "internal error" msgstr "" #: libvips/foreign/webpsave.c:746 #, c-format msgid "failed to allocate %zu bytes" msgstr "" #: libvips/foreign/webpsave.c:819 msgid "save as WebP" msgstr "" #: libvips/foreign/webpsave.c:843 msgid "Preset" msgstr "" #: libvips/foreign/webpsave.c:844 msgid "Preset for lossy compression" msgstr "" #: libvips/foreign/webpsave.c:851 msgid "Smart subsampling" msgstr "" #: libvips/foreign/webpsave.c:852 msgid "Enable high quality chroma subsampling" msgstr "" #: libvips/foreign/webpsave.c:858 msgid "Near lossless" msgstr "" #: libvips/foreign/webpsave.c:859 msgid "Enable preprocessing in lossless mode (uses Q)" msgstr "" #: libvips/foreign/webpsave.c:865 msgid "Alpha quality" msgstr "" #: libvips/foreign/webpsave.c:866 msgid "Change alpha plane fidelity for lossy compression" msgstr "" #: libvips/foreign/webpsave.c:872 msgid "Minimise size" msgstr "" #: libvips/foreign/webpsave.c:873 msgid "Optimise for minimum size" msgstr "" #: libvips/foreign/webpsave.c:879 msgid "Minimum keyframe spacing" msgstr "" #: libvips/foreign/webpsave.c:880 msgid "Minimum number of frames between key frames" msgstr "" #: libvips/foreign/webpsave.c:886 msgid "Maximum keyframe spacing" msgstr "" #: libvips/foreign/webpsave.c:887 msgid "Maximum number of frames between key frames" msgstr "" #: libvips/foreign/webpsave.c:894 libvips/foreign/webpsave.c:915 msgid "Level of CPU effort to reduce file size" msgstr "" #: libvips/foreign/webpsave.c:900 msgid "Target size" msgstr "" #: libvips/foreign/webpsave.c:901 msgid "Desired target size in bytes" msgstr "" #: libvips/foreign/webpsave.c:907 msgid "Passes" msgstr "" #: libvips/foreign/webpsave.c:908 msgid "Number of entropy-analysis passes (in [1..10])" msgstr "" #: libvips/foreign/webpsave.c:914 msgid "Reduction effort" msgstr "" #: libvips/foreign/webpsave.c:921 msgid "Mixed encoding" msgstr "" #: libvips/foreign/webpsave.c:922 msgid "Allow mixed encoding (might reduce file size)" msgstr "" #: libvips/foreign/webpsave.c:928 msgid "Smart deblocking" msgstr "" #: libvips/foreign/webpsave.c:929 msgid "Enable auto-adjusting of the deblocking filter" msgstr "" #: libvips/foreign/webpsave.c:1153 msgid "save image to webp mime" msgstr "" #: libvips/freqfilt/freqfilt.c:83 msgid "frequency-domain filter operations" msgstr "" #: libvips/freqfilt/freqmult.c:126 msgid "frequency-domain filtering" msgstr "" #: libvips/freqfilt/freqmult.c:131 msgid "Input mask image" msgstr "" #: libvips/freqfilt/fwfft.c:145 libvips/freqfilt/fwfft.c:266 #: libvips/freqfilt/invfft.c:124 libvips/freqfilt/invfft.c:203 msgid "unable to create transform plan" msgstr "" #: libvips/freqfilt/fwfft.c:351 msgid "forward FFT" msgstr "" #: libvips/freqfilt/invfft.c:263 msgid "inverse FFT" msgstr "" #: libvips/freqfilt/invfft.c:267 msgid "Real" msgstr "" #: libvips/freqfilt/invfft.c:268 msgid "Output only the real part of the transform" msgstr "" #: libvips/freqfilt/phasecor.c:107 msgid "calculate phase correlation" msgstr "" #: libvips/freqfilt/spectrum.c:100 msgid "make displayable power spectrum" msgstr "" #: libvips/histogram/case.c:164 msgid "bad number of cases" msgstr "" #: libvips/histogram/case.c:169 msgid "index image not 1-band" msgstr "" #: libvips/histogram/case.c:233 msgid "use pixel values to pick cases from an array of images" msgstr "" #: libvips/histogram/case.c:245 msgid "Cases" msgstr "" #: libvips/histogram/case.c:246 msgid "Array of case images" msgstr "" #: libvips/histogram/hist_cum.c:158 msgid "form cumulative histogram" msgstr "" #: libvips/histogram/hist_entropy.c:107 msgid "estimate image entropy" msgstr "" #: libvips/histogram/hist_entropy.c:112 #: libvips/histogram/hist_ismonotonic.c:119 msgid "Input histogram image" msgstr "" #: libvips/histogram/hist_equal.c:110 msgid "histogram equalisation" msgstr "" #: libvips/histogram/hist_equal.c:127 msgid "Equalise with this band" msgstr "" #: libvips/histogram/hist_ismonotonic.c:114 msgid "test for monotonicity" msgstr "" #: libvips/histogram/hist_ismonotonic.c:124 msgid "Monotonic" msgstr "" #: libvips/histogram/hist_ismonotonic.c:125 msgid "true if in is monotonic" msgstr "" #: libvips/histogram/hist_local.c:304 libvips/histogram/stdif.c:236 #: libvips/morphology/rank.c:491 msgid "window too large" msgstr "" #: libvips/histogram/hist_local.c:355 msgid "local histogram equalisation" msgstr "" #: libvips/histogram/hist_local.c:374 libvips/histogram/stdif.c:309 #: libvips/morphology/rank.c:571 msgid "Window width in pixels" msgstr "" #: libvips/histogram/hist_local.c:381 libvips/histogram/stdif.c:316 #: libvips/morphology/rank.c:578 msgid "Window height in pixels" msgstr "" #: libvips/histogram/hist_local.c:387 msgid "Max slope" msgstr "" #: libvips/histogram/hist_local.c:388 msgid "Maximum slope (CLAHE)" msgstr "" #: libvips/histogram/hist_match.c:154 msgid "match two histograms" msgstr "" #: libvips/histogram/hist_match.c:162 msgid "Input histogram" msgstr "" #: libvips/histogram/hist_match.c:167 libvips/mosaicing/match.c:196 #: libvips/mosaicing/merge.c:122 libvips/mosaicing/mosaic1.c:498 #: libvips/mosaicing/mosaic.c:179 msgid "Reference" msgstr "" #: libvips/histogram/hist_match.c:168 msgid "Reference histogram" msgstr "" #: libvips/histogram/hist_norm.c:137 msgid "normalise histogram" msgstr "" #: libvips/histogram/histogram.c:195 msgid "histogram operations" msgstr "" #: libvips/histogram/hist_plot.c:329 msgid "plot histogram" msgstr "" #: libvips/histogram/hist_unary.c:84 msgid "hist_unary operations" msgstr "" #: libvips/histogram/maplut.c:738 msgid "map an image though a lut" msgstr "" #: libvips/histogram/maplut.c:756 msgid "LUT" msgstr "" #: libvips/histogram/maplut.c:757 msgid "Look-up table image" msgstr "" #: libvips/histogram/maplut.c:763 msgid "Apply one-band lut to this band of in" msgstr "" #: libvips/histogram/percent.c:105 msgid "find threshold for percent of pixels" msgstr "" #: libvips/histogram/percent.c:115 msgid "Percent" msgstr "" #: libvips/histogram/percent.c:116 msgid "Percent of pixels" msgstr "" #: libvips/histogram/percent.c:123 msgid "Threshold above which lie percent of pixels" msgstr "" #: libvips/histogram/stdif.c:240 msgid "too many bands" msgstr "" #: libvips/histogram/stdif.c:290 msgid "statistical difference" msgstr "" #: libvips/histogram/stdif.c:322 msgid "Mean weight" msgstr "" #: libvips/histogram/stdif.c:323 msgid "Weight of new mean" msgstr "" #: libvips/histogram/stdif.c:330 msgid "New mean" msgstr "" #: libvips/histogram/stdif.c:336 msgid "Deviation weight" msgstr "" #: libvips/histogram/stdif.c:337 msgid "Weight of new deviation" msgstr "" #: libvips/histogram/stdif.c:343 msgid "Deviation" msgstr "" #: libvips/histogram/stdif.c:344 msgid "New deviation" msgstr "" #: libvips/iofuncs/buf.c:605 #, c-format msgid "%zd bytes of binary data" msgstr "" #: libvips/iofuncs/connection.c:118 msgid "Descriptor" msgstr "" #: libvips/iofuncs/connection.c:119 msgid "File descriptor for read or write" msgstr "" #: libvips/iofuncs/connection.c:126 msgid "Name of file to open" msgstr "" #: libvips/iofuncs/error.c:241 msgid "system error" msgstr "" #: libvips/iofuncs/error.c:394 msgid "image must be uncoded" msgstr "" #: libvips/iofuncs/error.c:423 msgid "image coding must be 'none' or 'labq'" msgstr "" #: libvips/iofuncs/error.c:452 msgid "unknown image coding" msgstr "" #: libvips/iofuncs/error.c:478 #, c-format msgid "coding '%s' only" msgstr "" #: libvips/iofuncs/error.c:504 msgid "image must one band" msgstr "" #: libvips/iofuncs/error.c:530 #, c-format msgid "image must have %d bands" msgstr "" #: libvips/iofuncs/error.c:556 msgid "image must have one or three bands" msgstr "" #: libvips/iofuncs/error.c:583 #, c-format msgid "image must have at least %d bands" msgstr "" #: libvips/iofuncs/error.c:612 msgid "images must have the same number of bands, or one must be single-band" msgstr "" #: libvips/iofuncs/error.c:640 #, c-format msgid "image must have 1 or %d bands" msgstr "" #: libvips/iofuncs/error.c:665 msgid "image must be non-complex" msgstr "" #: libvips/iofuncs/error.c:690 msgid "image must be complex" msgstr "" #: libvips/iofuncs/error.c:718 msgid "image must be two-band or complex" msgstr "" #: libvips/iofuncs/error.c:745 #, c-format msgid "image must be %s" msgstr "" #: libvips/iofuncs/error.c:771 msgid "image must be integer" msgstr "" #: libvips/iofuncs/error.c:797 msgid "image must be unsigned integer" msgstr "" #: libvips/iofuncs/error.c:826 msgid "image must be 8- or 16-bit integer, signed or unsigned" msgstr "" #: libvips/iofuncs/error.c:853 msgid "image must be 8- or 16-bit unsigned integer" msgstr "" #: libvips/iofuncs/error.c:880 msgid "image must be 8- or 16-bit unsigned integer, or float" msgstr "" #: libvips/iofuncs/error.c:908 msgid "image must be unsigned int or float" msgstr "" #: libvips/iofuncs/error.c:935 msgid "images must match in size" msgstr "" #: libvips/iofuncs/error.c:962 msgid "images must be odd and square" msgstr "" #: libvips/iofuncs/error.c:989 msgid "images must have the same number of bands" msgstr "" #: libvips/iofuncs/error.c:1045 msgid "images must have the same band format" msgstr "" #: libvips/iofuncs/error.c:1072 msgid "images must have the same coding" msgstr "" #: libvips/iofuncs/error.c:1096 #, c-format msgid "vector must have %d elements" msgstr "" #: libvips/iofuncs/error.c:1133 msgid "vector must have 1 element" msgstr "" #: libvips/iofuncs/error.c:1136 #, c-format msgid "vector must have 1 or %d elements" msgstr "" #: libvips/iofuncs/error.c:1162 msgid "histograms must have width or height 1" msgstr "" #: libvips/iofuncs/error.c:1167 msgid "histograms must have not have more than 65536 elements" msgstr "" #: libvips/iofuncs/error.c:1204 msgid "matrix image too large" msgstr "" #: libvips/iofuncs/error.c:1209 msgid "matrix image must have one band" msgstr "" #: libvips/iofuncs/error.c:1244 msgid "separable matrix images must have width or height 1" msgstr "" #: libvips/iofuncs/error.c:1271 msgid "precision must be int or float" msgstr "" #: libvips/iofuncs/generate.c:695 msgid "demand hint not set" msgstr "" #: libvips/iofuncs/generate.c:714 libvips/iofuncs/generate.c:742 msgid "generate() called twice" msgstr "" #: libvips/iofuncs/generate.c:783 libvips/iofuncs/image.c:3249 #, c-format msgid "unable to output to a %s image" msgstr "" #: libvips/iofuncs/ginputsource.c:164 libvips/iofuncs/ginputsource.c:229 #, c-format msgid "Error while seeking: %s" msgstr "" #: libvips/iofuncs/ginputsource.c:185 msgid "Cannot truncate VipsGInputStream" msgstr "" #: libvips/iofuncs/ginputsource.c:206 #, c-format msgid "Error while reading: %s" msgstr "" #: libvips/iofuncs/ginputsource.c:275 msgid "Stream to wrap" msgstr "" #: libvips/iofuncs/header.c:1336 #, c-format msgid "field \"%s\" not found" msgstr "" #: libvips/iofuncs/header.c:1575 #, c-format msgid "field \"%s\" is of type %s, not %s" msgstr "" #: libvips/iofuncs/header.c:1855 #, c-format msgid "field \"%s\" is of type %s, not VipsRefString" msgstr "" #: libvips/iofuncs/image.c:526 msgid "unable to close fd" msgstr "" #: libvips/iofuncs/image.c:747 #, c-format msgid "%s %s: %d x %d pixels, %d threads, %d x %d tiles, %d lines in buffer" msgstr "" #: libvips/iofuncs/image.c:760 #, c-format msgid "%s %s: %d%% complete" msgstr "" #: libvips/iofuncs/image.c:779 #, c-format msgid "%s %s: done in %.3gs \n" msgstr "" #: libvips/iofuncs/image.c:961 #, c-format msgid "unable to open \"%s\", file too short" msgstr "" #: libvips/iofuncs/image.c:988 #, c-format msgid "bad mode \"%s\"" msgstr "" #: libvips/iofuncs/image.c:1060 msgid "image class" msgstr "" #: libvips/iofuncs/image.c:1158 msgid "Image filename" msgstr "" #: libvips/iofuncs/image.c:1165 msgid "Open mode" msgstr "" #: libvips/iofuncs/image.c:1171 msgid "Kill" msgstr "" #: libvips/iofuncs/image.c:1172 msgid "Block evaluation on this image" msgstr "" #: libvips/iofuncs/image.c:1178 msgid "Demand style" msgstr "" #: libvips/iofuncs/image.c:1179 msgid "Preferred demand style for this image" msgstr "" #: libvips/iofuncs/image.c:1192 msgid "Foreign buffer" msgstr "" #: libvips/iofuncs/image.c:1193 msgid "Pointer to foreign pixels" msgstr "" #: libvips/iofuncs/image.c:1651 #, c-format msgid "killed for image \"%s\"" msgstr "" #: libvips/iofuncs/image.c:2067 msgid "memory area too small -- should be %" msgstr "" #: libvips/iofuncs/image.c:2259 msgid "unable to load source" msgstr "" #: libvips/iofuncs/image.c:2372 #, c-format msgid "bad array length -- should be %d, you passed %d" msgstr "" #: libvips/iofuncs/image.c:2896 libvips/iofuncs/memory.c:320 #: libvips/iofuncs/memory.c:394 #, c-format msgid "out of memory -- size == %dMB" msgstr "" #: libvips/iofuncs/image.c:3192 msgid "bad image descriptor" msgstr "" #: libvips/iofuncs/image.c:3312 #, c-format msgid "auto-rewind for %s failed" msgstr "" #: libvips/iofuncs/image.c:3387 libvips/iofuncs/image.c:3518 #: libvips/iofuncs/image.c:3697 msgid "image not readable" msgstr "" #: libvips/iofuncs/image.c:3433 libvips/iofuncs/image.c:3661 msgid "no image data" msgstr "" #: libvips/iofuncs/image.c:3539 libvips/iofuncs/image.c:3728 #: libvips/iofuncs/image.c:3737 msgid "image already written" msgstr "" #: libvips/iofuncs/image.c:3563 libvips/iofuncs/image.c:3749 msgid "image not writeable" msgstr "" #: libvips/iofuncs/image.c:3619 msgid "bad file type" msgstr "" #: libvips/iofuncs/init.c:1279 msgid "flag not in [0, 5]" msgstr "" #: libvips/iofuncs/mapfile.c:189 libvips/iofuncs/mapfile.c:355 msgid "unable to CreateFileMapping" msgstr "" #: libvips/iofuncs/mapfile.c:196 libvips/iofuncs/mapfile.c:367 msgid "unable to MapViewOfFile" msgstr "" #: libvips/iofuncs/mapfile.c:235 msgid "unable to mmap" msgstr "" #: libvips/iofuncs/mapfile.c:250 libvips/iofuncs/mapfile.c:361 msgid "unable to UnmapViewOfFile" msgstr "" #: libvips/iofuncs/mapfile.c:256 msgid "unable to munmap file" msgstr "" #: libvips/iofuncs/mapfile.c:278 msgid "file is less than 64 bytes" msgstr "" #: libvips/iofuncs/mapfile.c:283 libvips/iofuncs/mapfile.c:317 msgid "unable to get file status" msgstr "" #: libvips/iofuncs/mapfile.c:289 msgid "not a regular file" msgstr "" #: libvips/iofuncs/mapfile.c:323 msgid "unable to read data" msgstr "" #: libvips/iofuncs/mapfile.c:387 #, c-format msgid "unable to mmap: \"%s\" - %s" msgstr "" #: libvips/iofuncs/mapfile.c:398 #, c-format msgid "unable to mmap \"%s\" to same address" msgstr "" #: libvips/iofuncs/object.c:344 #, c-format msgid "parameter %s not set" msgstr "" #: libvips/iofuncs/object.c:779 #, c-format msgid "no property named `%s'" msgstr "" #: libvips/iofuncs/object.c:785 #, c-format msgid "no vips argument named `%s'" msgstr "" #: libvips/iofuncs/object.c:791 #, c-format msgid "argument `%s' has no instance" msgstr "" #: libvips/iofuncs/object.c:1531 libvips/iofuncs/operation.c:744 #: libvips/resample/interpolate.c:658 #, c-format msgid "class \"%s\" not found" msgstr "" #: libvips/iofuncs/object.c:1582 msgid "base class" msgstr "" #: libvips/iofuncs/object.c:1596 msgid "Nickname" msgstr "" #: libvips/iofuncs/object.c:1597 msgid "Class nickname" msgstr "" #: libvips/iofuncs/object.c:1603 msgid "Description" msgstr "" #: libvips/iofuncs/object.c:1604 msgid "Class description" msgstr "" #: libvips/iofuncs/object.c:1842 #, c-format msgid "no value supplied for argument '%s'" msgstr "" #: libvips/iofuncs/object.c:1845 #, c-format msgid "no value supplied for argument '%s' ('%s')" msgstr "" #: libvips/iofuncs/object.c:2037 libvips/iofuncs/object.c:2056 #, c-format msgid "'%s' is not an integer" msgstr "" #: libvips/iofuncs/object.c:2480 #, c-format msgid "expected string or ), saw %s" msgstr "" #: libvips/iofuncs/object.c:2523 #, c-format msgid "unable to set '%s'" msgstr "" #: libvips/iofuncs/object.c:2536 msgid "not , or ) after parameter" msgstr "" #: libvips/iofuncs/object.c:2543 msgid "extra tokens after ')'" msgstr "" #: libvips/iofuncs/operation.c:230 #, c-format msgid "%d pixels calculated" msgstr "" #: libvips/iofuncs/operation.c:338 msgid "default enum" msgstr "" #: libvips/iofuncs/operation.c:342 msgid "allowed enums" msgstr "" #: libvips/iofuncs/operation.c:370 msgid "default flags" msgstr "" #: libvips/iofuncs/operation.c:375 msgid "allowed flags" msgstr "" #: libvips/iofuncs/operation.c:391 libvips/iofuncs/operation.c:399 #: libvips/iofuncs/operation.c:411 msgid "default" msgstr "" #: libvips/iofuncs/operation.c:402 libvips/iofuncs/operation.c:414 msgid "min" msgstr "" #: libvips/iofuncs/operation.c:404 libvips/iofuncs/operation.c:416 msgid "max" msgstr "" #: libvips/iofuncs/operation.c:437 msgid "input" msgstr "" #: libvips/iofuncs/operation.c:438 msgid "output" msgstr "" #: libvips/iofuncs/operation.c:613 msgid "operation is blocked" msgstr "" #: libvips/iofuncs/operation.c:659 msgid "operations" msgstr "" #: libvips/iofuncs/operation.c:750 #, c-format msgid "\"%s\" is not an instantiable class" msgstr "" #: libvips/iofuncs/operation.c:1221 #, c-format msgid "unknown argument '%s'" msgstr "" #: libvips/iofuncs/operation.c:1346 msgid "too few arguments" msgstr "" #: libvips/iofuncs/operation.c:1465 msgid "too many arguments" msgstr "" #: libvips/iofuncs/region.c:551 libvips/iofuncs/region.c:621 #: libvips/iofuncs/region.c:763 libvips/iofuncs/region.c:1839 msgid "valid clipped to nothing" msgstr "" #: libvips/iofuncs/region.c:661 msgid "bad image type" msgstr "" #: libvips/iofuncs/region.c:705 msgid "no pixel data on attached image" msgstr "" #: libvips/iofuncs/region.c:711 msgid "images do not match in pixel size" msgstr "" #: libvips/iofuncs/region.c:744 libvips/iofuncs/region.c:1821 msgid "dest too small" msgstr "" #: libvips/iofuncs/region.c:833 msgid "bad position" msgstr "" #: libvips/iofuncs/region.c:1619 msgid "stop requested" msgstr "" #: libvips/iofuncs/region.c:1703 libvips/iofuncs/region.c:1891 #, c-format msgid "unable to input from a %s image" msgstr "" #: libvips/iofuncs/region.c:1726 msgid "incomplete header" msgstr "" #: libvips/iofuncs/region.c:1796 msgid "inappropriate region type" msgstr "" #: libvips/iofuncs/sbuf.c:80 msgid "buffered source" msgstr "" #: libvips/iofuncs/sbuf.c:275 msgid "end of file" msgstr "" #: libvips/iofuncs/sink.c:261 #, c-format msgid "stop function failed for image \"%s\"" msgstr "" #: libvips/iofuncs/sink.c:298 #, c-format msgid "start function failed for image \"%s\"" msgstr "" #: libvips/iofuncs/sink.c:330 msgid "per-thread state for sink" msgstr "" #: libvips/iofuncs/sinkdisc.c:106 libvips/iofuncs/util.c:555 msgid "write failed" msgstr "" #: libvips/iofuncs/sinkdisc.c:135 msgid "per-thread state for sinkdisc" msgstr "" #: libvips/iofuncs/sinkmemory.c:107 msgid "per-thread state for sinkmemory" msgstr "" #: libvips/iofuncs/sinkscreen.c:203 msgid "per-thread state for render" msgstr "" #: libvips/iofuncs/sinkscreen.c:1191 msgid "bad parameters" msgstr "" #: libvips/iofuncs/source.c:322 libvips/iofuncs/target.c:114 msgid "don't set 'filename' and 'descriptor'" msgstr "" #: libvips/iofuncs/source.c:399 msgid "input source" msgstr "" #: libvips/iofuncs/source.c:407 libvips/iofuncs/target.c:326 msgid "Blob" msgstr "" #: libvips/iofuncs/source.c:408 msgid "Blob to load from" msgstr "" #: libvips/iofuncs/source.c:553 #, fuzzy msgid "unimplemented target" msgstr "unimplemented input colour space 0x%x" #: libvips/iofuncs/source.c:691 msgid "unable to open for read" msgstr "" #: libvips/iofuncs/source.c:932 msgid "pipe too long" msgstr "" #: libvips/iofuncs/source.c:1207 libvips/iofuncs/source.c:1232 #: libvips/iofuncs/target.c:225 msgid "bad 'whence'" msgstr "" #: libvips/iofuncs/source.c:1252 msgid "bad seek to %" msgstr "" #: libvips/iofuncs/sourcecustom.c:173 msgid "Custom source" msgstr "" #: libvips/iofuncs/sourceginput.c:219 msgid "GInputStream source" msgstr "" #: libvips/iofuncs/sourceginput.c:227 msgid "Stream" msgstr "" #: libvips/iofuncs/sourceginput.c:228 msgid "GInputStream to read from" msgstr "" #: libvips/iofuncs/system.c:185 msgid "unable to substitute input filename" msgstr "" #: libvips/iofuncs/system.c:191 msgid "unable to substitute output filename" msgstr "" #: libvips/iofuncs/system.c:226 #, c-format msgid "command \"%s\" failed" msgstr "" #: libvips/iofuncs/system.c:269 msgid "run an external command" msgstr "" #: libvips/iofuncs/system.c:290 msgid "Command" msgstr "" #: libvips/iofuncs/system.c:291 msgid "Command to run" msgstr "" #: libvips/iofuncs/system.c:297 msgid "Input format" msgstr "" #: libvips/iofuncs/system.c:298 msgid "Format for input filename" msgstr "" #: libvips/iofuncs/system.c:304 msgid "Output format" msgstr "" #: libvips/iofuncs/system.c:305 msgid "Format for output filename" msgstr "" #: libvips/iofuncs/system.c:312 msgid "Command log" msgstr "" #: libvips/iofuncs/target.c:317 msgid "File descriptor should output to memory" msgstr "" #: libvips/iofuncs/target.c:327 msgid "Blob to save to" msgstr "" #: libvips/iofuncs/target.c:499 msgid "write error" msgstr "" #: libvips/iofuncs/targetcustom.c:235 msgid "Custom target" msgstr "" #: libvips/iofuncs/thread.c:150 msgid "unable to create thread" msgstr "" #: libvips/iofuncs/threadpool.c:190 msgid "per-thread state for vipsthreadpool" msgstr "" #: libvips/iofuncs/type.c:952 #, c-format msgid "unable to convert \"%s\" to int" msgstr "" #: libvips/iofuncs/util.c:533 msgid "unable to get file stats" msgstr "" #: libvips/iofuncs/util.c:697 #, c-format msgid "unable to open file \"%s\" for reading" msgstr "" #: libvips/iofuncs/util.c:719 #, c-format msgid "unable to open file \"%s\" for writing" msgstr "" #: libvips/iofuncs/util.c:740 #, c-format msgid "\"%s\" too long" msgstr "" #: libvips/iofuncs/util.c:785 #, c-format msgid "error reading from file \"%s\"" msgstr "" #: libvips/iofuncs/util.c:831 #, c-format msgid "write error (%zd out of %zd blocks written)" msgstr "" #: libvips/iofuncs/util.c:1098 msgid "unable to seek" msgstr "" #: libvips/iofuncs/util.c:1123 libvips/iofuncs/util.c:1130 msgid "unable to truncate" msgstr "" #: libvips/iofuncs/util.c:1216 #, c-format msgid "unable to remove directory \"%s\", %s" msgstr "" #: libvips/iofuncs/util.c:1233 #, c-format msgid "unable to rename file \"%s\" as \"%s\", %s" msgstr "" #: libvips/iofuncs/util.c:1361 msgid "unexpected end of string" msgstr "" #: libvips/iofuncs/util.c:1379 libvips/iofuncs/util.c:1449 #, c-format msgid "expected %s, saw %s" msgstr "" #: libvips/iofuncs/util.c:1758 msgid "no such enum type" msgstr "" #: libvips/iofuncs/util.c:1776 #, c-format msgid "enum '%s' has no member '%s', should be one of: %s" msgstr "" #: libvips/iofuncs/util.c:1795 msgid "no such flag type" msgstr "" #: libvips/iofuncs/util.c:1814 #, c-format msgid "flags '%s' has no member '%s'" msgstr "" #: libvips/iofuncs/vips.c:324 #, c-format msgid "\"%s\" is not a VIPS image" msgstr "" #: libvips/iofuncs/vips.c:381 msgid "unknown coding" msgstr "" #: libvips/iofuncs/vips.c:391 msgid "malformed LABQ image" msgstr "" #: libvips/iofuncs/vips.c:400 msgid "malformed RAD image" msgstr "" #: libvips/iofuncs/vips.c:471 msgid "unable to read history" msgstr "" #: libvips/iofuncs/vips.c:504 msgid "more than 100 megabytes of XML? sufferin' succotash!" msgstr "" #: libvips/iofuncs/vips.c:538 msgid "unable to allocate read buffer" msgstr "" #: libvips/iofuncs/vips.c:544 msgid "read error while fetching XML" msgstr "" #: libvips/iofuncs/vips.c:556 msgid "XML parse error" msgstr "" #: libvips/iofuncs/vips.c:621 msgid "incorrect namespace in XML" msgstr "" #: libvips/iofuncs/vips.c:669 msgid "error transforming from save format" msgstr "" #: libvips/iofuncs/vips.c:770 libvips/iofuncs/window.c:231 msgid "file has been truncated" msgstr "" #: libvips/iofuncs/vips.c:822 libvips/iofuncs/vips.c:913 msgid "error transforming to save format" msgstr "" #: libvips/iofuncs/vips.c:1027 #, c-format msgid "unable to read header for \"%s\"" msgstr "" #: libvips/iofuncs/window.c:230 #, c-format msgid "unable to read data for \"%s\", %s" msgstr "" #: libvips/morphology/countlines.c:135 msgid "count lines in an image" msgstr "" #: libvips/morphology/countlines.c:139 msgid "Nolines" msgstr "" #: libvips/morphology/countlines.c:140 msgid "Number of lines" msgstr "" #: libvips/morphology/countlines.c:147 msgid "Countlines left-right or up-down" msgstr "" #: libvips/morphology/labelregions.c:120 msgid "label regions in an image" msgstr "" #: libvips/morphology/labelregions.c:125 msgid "Mask of region labels" msgstr "" #: libvips/morphology/labelregions.c:130 msgid "Segments" msgstr "" #: libvips/morphology/labelregions.c:131 msgid "Number of discrete contiguous regions" msgstr "" #: libvips/morphology/morph.c:886 #, c-format msgid "bad mask element (%f should be 0, 128 or 255)" msgstr "" #: libvips/morphology/morph.c:956 msgid "morphology operation" msgstr "" #: libvips/morphology/morph.c:972 msgid "Morphology" msgstr "" #: libvips/morphology/morph.c:973 msgid "Morphological operation to perform" msgstr "" #: libvips/morphology/morphology.c:65 msgid "morphological operations" msgstr "" #: libvips/morphology/nearest.c:305 msgid "fill image zeros with nearest non-zero pixel" msgstr "" #: libvips/morphology/nearest.c:309 msgid "Out" msgstr "" #: libvips/morphology/nearest.c:310 msgid "Value of nearest non-zero pixel" msgstr "" #: libvips/morphology/nearest.c:316 msgid "Distance to nearest non-zero pixel" msgstr "" #: libvips/morphology/rank.c:496 msgid "index out of range" msgstr "" #: libvips/morphology/rank.c:560 msgid "rank filter" msgstr "" #: libvips/morphology/rank.c:585 msgid "Select pixel at index" msgstr "" #: libvips/mosaicing/chkpair.c:201 msgid "inputs incompatible" msgstr "" #: libvips/mosaicing/chkpair.c:205 libvips/mosaicing/im_tbcalcon.c:105 msgid "help!" msgstr "" #: libvips/mosaicing/global_balance.c:151 msgid "no matching '>'" msgstr "" #: libvips/mosaicing/global_balance.c:160 msgid "too many items" msgstr "" #: libvips/mosaicing/global_balance.c:463 msgid "circularity detected" msgstr "" #: libvips/mosaicing/global_balance.c:497 #: libvips/mosaicing/global_balance.c:557 #, c-format msgid "image \"%s\" used twice as output" msgstr "" #: libvips/mosaicing/global_balance.c:606 msgid "bad number of args in join line" msgstr "" #: libvips/mosaicing/global_balance.c:648 msgid "bad number of args in join1 line" msgstr "" #: libvips/mosaicing/global_balance.c:684 msgid "bad number of args in copy line" msgstr "" #: libvips/mosaicing/global_balance.c:742 msgid "" "mosaic root not found in desc file\n" "is this really a mosaiced image?" msgstr "" #: libvips/mosaicing/global_balance.c:753 msgid "more than one root" msgstr "" #: libvips/mosaicing/global_balance.c:1519 #: libvips/mosaicing/matrixmultiply.c:90 msgid "bad sizes" msgstr "" #: libvips/mosaicing/global_balance.c:1914 msgid "global balance an image mosaic" msgstr "" #: libvips/mosaicing/global_balance.c:1930 msgid "Gamma" msgstr "" #: libvips/mosaicing/global_balance.c:1931 msgid "Image gamma" msgstr "" #: libvips/mosaicing/global_balance.c:1937 msgid "Int output" msgstr "" #: libvips/mosaicing/global_balance.c:1938 msgid "Integer output" msgstr "" #: libvips/mosaicing/im_avgdxdy.c:65 msgid "no points to average" msgstr "" #: libvips/mosaicing/im_clinear.c:138 msgid "vips_invmat failed" msgstr "" #: libvips/mosaicing/im_lrcalcon.c:206 msgid "overlap too small for your search size" msgstr "" #: libvips/mosaicing/im_lrcalcon.c:245 #, c-format msgid "found %d tie-points, need at least %d" msgstr "" #: libvips/mosaicing/im_lrcalcon.c:290 msgid "not 1-band uchar image" msgstr "" #: libvips/mosaicing/im_tbcalcon.c:119 msgid "overlap too small" msgstr "" #: libvips/mosaicing/lrmerge.c:785 msgid "mwidth must be -1 or >= 0" msgstr "" #: libvips/mosaicing/lrmerge.c:817 msgid "no overlap" msgstr "" #: libvips/mosaicing/lrmerge.c:887 libvips/mosaicing/tbmerge.c:692 msgid "unknown coding type" msgstr "" #: libvips/mosaicing/lrmerge.c:905 libvips/mosaicing/tbmerge.c:710 msgid "too much overlap" msgstr "" #: libvips/mosaicing/lrmosaic.c:122 libvips/mosaicing/tbmosaic.c:93 msgid "bad area parameters" msgstr "" #: libvips/mosaicing/lrmosaic.c:143 libvips/mosaicing/tbmosaic.c:114 msgid "overlap too small for search" msgstr "" #: libvips/mosaicing/lrmosaic.c:171 libvips/mosaicing/tbmosaic.c:142 msgid "unknown Coding type" msgstr "" #: libvips/mosaicing/match.c:192 msgid "first-order match of two images" msgstr "" #: libvips/mosaicing/match.c:197 libvips/mosaicing/merge.c:123 #: libvips/mosaicing/mosaic1.c:499 libvips/mosaicing/mosaic.c:180 msgid "Reference image" msgstr "" #: libvips/mosaicing/match.c:202 libvips/mosaicing/merge.c:128 #: libvips/mosaicing/mosaic1.c:504 libvips/mosaicing/mosaic.c:185 msgid "Secondary" msgstr "" #: libvips/mosaicing/match.c:203 libvips/mosaicing/merge.c:129 #: libvips/mosaicing/mosaic1.c:505 libvips/mosaicing/mosaic.c:186 msgid "Secondary image" msgstr "" #: libvips/mosaicing/match.c:214 libvips/mosaicing/mosaic1.c:523 msgid "xr1" msgstr "" #: libvips/mosaicing/match.c:215 libvips/mosaicing/match.c:222 #: libvips/mosaicing/mosaic1.c:524 libvips/mosaicing/mosaic1.c:531 msgid "Position of first reference tie-point" msgstr "" #: libvips/mosaicing/match.c:221 libvips/mosaicing/mosaic1.c:530 msgid "yr1" msgstr "" #: libvips/mosaicing/match.c:228 libvips/mosaicing/mosaic1.c:537 msgid "xs1" msgstr "" #: libvips/mosaicing/match.c:229 libvips/mosaicing/match.c:236 #: libvips/mosaicing/mosaic1.c:538 libvips/mosaicing/mosaic1.c:545 msgid "Position of first secondary tie-point" msgstr "" #: libvips/mosaicing/match.c:235 libvips/mosaicing/mosaic1.c:544 msgid "ys1" msgstr "" #: libvips/mosaicing/match.c:242 libvips/mosaicing/mosaic1.c:551 msgid "xr2" msgstr "" #: libvips/mosaicing/match.c:243 libvips/mosaicing/match.c:250 #: libvips/mosaicing/mosaic1.c:552 libvips/mosaicing/mosaic1.c:559 msgid "Position of second reference tie-point" msgstr "" #: libvips/mosaicing/match.c:249 libvips/mosaicing/mosaic1.c:558 msgid "yr2" msgstr "" #: libvips/mosaicing/match.c:256 libvips/mosaicing/mosaic1.c:565 msgid "xs2" msgstr "" #: libvips/mosaicing/match.c:257 libvips/mosaicing/match.c:264 #: libvips/mosaicing/mosaic1.c:566 libvips/mosaicing/mosaic1.c:573 msgid "Position of second secondary tie-point" msgstr "" #: libvips/mosaicing/match.c:263 libvips/mosaicing/mosaic1.c:572 msgid "ys2" msgstr "" #: libvips/mosaicing/match.c:270 libvips/mosaicing/mosaic1.c:579 #: libvips/mosaicing/mosaic.c:232 msgid "hwindow" msgstr "" #: libvips/mosaicing/match.c:271 libvips/mosaicing/mosaic1.c:580 #: libvips/mosaicing/mosaic.c:233 msgid "Half window size" msgstr "" #: libvips/mosaicing/match.c:277 libvips/mosaicing/mosaic1.c:586 #: libvips/mosaicing/mosaic.c:239 msgid "harea" msgstr "" #: libvips/mosaicing/match.c:278 libvips/mosaicing/mosaic1.c:587 #: libvips/mosaicing/mosaic.c:240 msgid "Half area size" msgstr "" #: libvips/mosaicing/match.c:284 libvips/mosaicing/mosaic1.c:593 msgid "Search" msgstr "" #: libvips/mosaicing/match.c:285 libvips/mosaicing/mosaic1.c:594 msgid "Search to improve tie-points" msgstr "" #: libvips/mosaicing/match.c:291 libvips/mosaicing/mosaic1.c:600 #: libvips/resample/affine.c:651 libvips/resample/mapim.c:561 #: libvips/resample/quadratic.c:328 libvips/resample/resize.c:376 #: libvips/resample/similarity.c:127 msgid "Interpolate" msgstr "" #: libvips/mosaicing/match.c:292 libvips/mosaicing/mosaic1.c:601 #: libvips/resample/affine.c:652 libvips/resample/mapim.c:562 #: libvips/resample/resize.c:377 libvips/resample/similarity.c:128 msgid "Interpolate pixels with this" msgstr "" #: libvips/mosaicing/matrixinvert.c:313 libvips/mosaicing/matrixinvert.c:329 #: libvips/mosaicing/matrixinvert.c:354 libvips/resample/transform.c:60 msgid "singular or near-singular matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:407 msgid "non-square matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:440 msgid "invert a matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:445 msgid "An square matrix" msgstr "" #: libvips/mosaicing/matrixinvert.c:451 libvips/mosaicing/matrixmultiply.c:160 msgid "Output matrix" msgstr "" #: libvips/mosaicing/matrixmultiply.c:143 msgid "multiply two matrices" msgstr "" #: libvips/mosaicing/matrixmultiply.c:148 msgid "First matrix to multiply" msgstr "" #: libvips/mosaicing/matrixmultiply.c:154 msgid "Second matrix to multiply" msgstr "" #: libvips/mosaicing/merge.c:116 msgid "merge two images" msgstr "" #: libvips/mosaicing/merge.c:141 msgid "Horizontal or vertical merge" msgstr "" #: libvips/mosaicing/merge.c:147 msgid "dx" msgstr "" #: libvips/mosaicing/merge.c:148 msgid "Horizontal displacement from sec to ref" msgstr "" #: libvips/mosaicing/merge.c:154 msgid "dy" msgstr "" #: libvips/mosaicing/merge.c:155 msgid "Vertical displacement from sec to ref" msgstr "" #: libvips/mosaicing/merge.c:161 libvips/mosaicing/mosaic1.c:606 #: libvips/mosaicing/mosaic.c:246 msgid "Max blend" msgstr "" #: libvips/mosaicing/merge.c:162 libvips/mosaicing/mosaic1.c:607 #: libvips/mosaicing/mosaic.c:247 msgid "Maximum blend size" msgstr "" #: libvips/mosaicing/mosaic1.c:494 msgid "first-order mosaic of two images" msgstr "" #: libvips/mosaicing/mosaic1.c:517 libvips/mosaicing/mosaic.c:198 msgid "Horizontal or vertical mosaic" msgstr "" #: libvips/mosaicing/mosaic1.c:613 libvips/mosaicing/mosaic.c:253 msgid "Search band" msgstr "" #: libvips/mosaicing/mosaic1.c:614 libvips/mosaicing/mosaic.c:254 msgid "Band to search for features on" msgstr "" #: libvips/mosaicing/mosaic.c:175 msgid "mosaic two images" msgstr "" #: libvips/mosaicing/mosaic.c:204 msgid "xref" msgstr "" #: libvips/mosaicing/mosaic.c:205 libvips/mosaicing/mosaic.c:212 msgid "Position of reference tie-point" msgstr "" #: libvips/mosaicing/mosaic.c:211 msgid "yref" msgstr "" #: libvips/mosaicing/mosaic.c:218 msgid "xsec" msgstr "" #: libvips/mosaicing/mosaic.c:219 libvips/mosaicing/mosaic.c:226 msgid "Position of secondary tie-point" msgstr "" #: libvips/mosaicing/mosaic.c:225 msgid "ysec" msgstr "" #: libvips/mosaicing/mosaic.c:260 libvips/mosaicing/mosaic.c:267 msgid "Integer offset" msgstr "" #: libvips/mosaicing/mosaic.c:261 libvips/mosaicing/mosaic.c:268 msgid "Detected integer offset" msgstr "" #: libvips/mosaicing/mosaic.c:275 msgid "Detected scale" msgstr "" #: libvips/mosaicing/mosaic.c:282 msgid "Detected rotation" msgstr "" #: libvips/mosaicing/mosaic.c:288 libvips/mosaicing/mosaic.c:295 msgid "First-order displacement" msgstr "" #: libvips/mosaicing/mosaic.c:289 libvips/mosaicing/mosaic.c:296 msgid "Detected first-order displacement" msgstr "" #: libvips/mosaicing/remosaic.c:89 #, c-format msgid "file \"%s\" not found" msgstr "" #: libvips/mosaicing/remosaic.c:117 #, c-format msgid "substitute image \"%s\" is not the same size as \"%s\"" msgstr "" #: libvips/mosaicing/remosaic.c:160 msgid "rebuild an mosaiced image" msgstr "" #: libvips/mosaicing/remosaic.c:176 msgid "old_str" msgstr "" #: libvips/mosaicing/remosaic.c:177 msgid "Search for this string" msgstr "" #: libvips/mosaicing/remosaic.c:183 msgid "new_str" msgstr "" #: libvips/mosaicing/remosaic.c:184 msgid "And swap for this string" msgstr "" #: libvips/resample/affine.c:516 msgid "output coordinates out of range" msgstr "" #: libvips/resample/affine.c:640 msgid "affine transform of an image" msgstr "" #: libvips/resample/affine.c:644 msgid "Matrix" msgstr "" #: libvips/resample/affine.c:645 msgid "Transformation matrix" msgstr "" #: libvips/resample/affine.c:657 msgid "Output rect" msgstr "" #: libvips/resample/affine.c:658 msgid "Area of output to generate" msgstr "" #: libvips/resample/affine.c:664 libvips/resample/affine.c:671 #: libvips/resample/similarity.c:140 libvips/resample/similarity.c:147 msgid "Output offset" msgstr "" #: libvips/resample/affine.c:665 libvips/resample/similarity.c:141 msgid "Horizontal output displacement" msgstr "" #: libvips/resample/affine.c:672 libvips/resample/similarity.c:148 msgid "Vertical output displacement" msgstr "" #: libvips/resample/affine.c:678 libvips/resample/affine.c:685 #: libvips/resample/resize.c:360 libvips/resample/resize.c:367 #: libvips/resample/similarity.c:154 libvips/resample/similarity.c:161 msgid "Input offset" msgstr "" #: libvips/resample/affine.c:679 libvips/resample/resize.c:361 #: libvips/resample/similarity.c:155 msgid "Horizontal input displacement" msgstr "" #: libvips/resample/affine.c:686 libvips/resample/resize.c:368 #: libvips/resample/similarity.c:162 msgid "Vertical input displacement" msgstr "" #: libvips/resample/bicubic.cpp:629 msgid "bicubic interpolation (Catmull-Rom)" msgstr "" #: libvips/resample/interpolate.c:183 msgid "VIPS interpolators" msgstr "" #: libvips/resample/interpolate.c:359 msgid "nearest-neighbour interpolation" msgstr "" #: libvips/resample/interpolate.c:577 msgid "bilinear interpolation" msgstr "" #: libvips/resample/lbb.cpp:872 msgid "reduced halo bicubic" msgstr "" #: libvips/resample/mapim.c:551 msgid "resample with a map image" msgstr "" #: libvips/resample/mapim.c:556 msgid "Index pixels with this" msgstr "" #: libvips/resample/nohalo.cpp:1551 msgid "edge sharpening resampler with halo reduction" msgstr "" #: libvips/resample/quadratic.c:225 msgid "coefficient matrix must have width 2" msgstr "" #: libvips/resample/quadratic.c:247 msgid "coefficient matrix must have height 1, 3, 4 or 6" msgstr "" #: libvips/resample/quadratic.c:318 msgid "resample an image with a quadratic transform" msgstr "" #: libvips/resample/quadratic.c:322 msgid "Coeff" msgstr "" #: libvips/resample/quadratic.c:323 msgid "Coefficient matrix" msgstr "" #: libvips/resample/quadratic.c:329 msgid "Interpolate values with this" msgstr "" #: libvips/resample/reduce.c:135 msgid "reduce an image" msgstr "" #: libvips/resample/reduce.c:141 libvips/resample/reduceh.cpp:586 #: libvips/resample/shrink.c:149 libvips/resample/shrinkh.c:436 msgid "Hshrink" msgstr "" #: libvips/resample/reduce.c:142 libvips/resample/reduce.c:172 #: libvips/resample/reduceh.cpp:587 libvips/resample/reduceh.cpp:610 #: libvips/resample/shrink.c:150 libvips/resample/shrink.c:166 #: libvips/resample/shrinkh.c:437 libvips/resample/shrinkh.c:453 msgid "Horizontal shrink factor" msgstr "" #: libvips/resample/reduce.c:148 libvips/resample/reducev.cpp:1070 #: libvips/resample/shrink.c:142 libvips/resample/shrinkv.c:625 msgid "Vshrink" msgstr "" #: libvips/resample/reduce.c:149 libvips/resample/reduce.c:179 #: libvips/resample/reducev.cpp:1071 libvips/resample/reducev.cpp:1094 #: libvips/resample/shrink.c:143 libvips/resample/shrink.c:173 #: libvips/resample/shrinkv.c:626 libvips/resample/shrinkv.c:642 msgid "Vertical shrink factor" msgstr "" #: libvips/resample/reduce.c:155 libvips/resample/reduceh.cpp:593 #: libvips/resample/reducev.cpp:1077 libvips/resample/resize.c:343 msgid "Kernel" msgstr "" #: libvips/resample/reduce.c:156 libvips/resample/reduceh.cpp:594 #: libvips/resample/reducev.cpp:1078 libvips/resample/resize.c:344 msgid "Resampling kernel" msgstr "" #: libvips/resample/reduce.c:162 libvips/resample/reduceh.cpp:600 #: libvips/resample/reducev.cpp:1084 libvips/resample/resize.c:350 msgid "Gap" msgstr "" #: libvips/resample/reduce.c:163 libvips/resample/reduceh.cpp:601 #: libvips/resample/reducev.cpp:1085 libvips/resample/resize.c:351 msgid "Reducing gap" msgstr "" #: libvips/resample/reduce.c:171 libvips/resample/reduceh.cpp:609 #: libvips/resample/shrink.c:165 libvips/resample/shrinkh.c:452 msgid "Xshrink" msgstr "" #: libvips/resample/reduce.c:178 libvips/resample/reducev.cpp:1093 #: libvips/resample/shrink.c:172 libvips/resample/shrinkv.c:641 msgid "Yshrink" msgstr "" #: libvips/resample/reduce.c:187 libvips/resample/reduceh.cpp:618 #: libvips/resample/reducev.cpp:1102 libvips/resample/resize.c:384 msgid "Centre" msgstr "" #: libvips/resample/reduce.c:188 libvips/resample/reduceh.cpp:619 #: libvips/resample/reducev.cpp:1103 libvips/resample/resize.c:385 msgid "Use centre sampling convention" msgstr "" #: libvips/resample/reduceh.cpp:414 libvips/resample/reducev.cpp:848 msgid "reduce factor should be >= 1.0" msgstr "" #: libvips/resample/reduceh.cpp:437 libvips/resample/reducev.cpp:870 msgid "reduce gap should be >= 1.0" msgstr "" #: libvips/resample/reduceh.cpp:467 libvips/resample/reducev.cpp:900 msgid "reduce factor too large" msgstr "" #: libvips/resample/reduceh.cpp:580 libvips/resample/shrinkh.c:430 msgid "shrink an image horizontally" msgstr "" #: libvips/resample/reducev.cpp:1064 libvips/resample/shrinkv.c:619 msgid "shrink an image vertically" msgstr "" #: libvips/resample/resample.c:100 msgid "resample operations" msgstr "" #: libvips/resample/resize.c:323 msgid "resize an image" msgstr "" #: libvips/resample/resize.c:329 msgid "Scale factor" msgstr "" #: libvips/resample/resize.c:330 msgid "Scale image by this factor" msgstr "" #: libvips/resample/resize.c:336 msgid "Vertical scale factor" msgstr "" #: libvips/resample/resize.c:337 msgid "Vertical scale image by this factor" msgstr "" #: libvips/resample/shrink.c:133 msgid "shrink an image" msgstr "" #: libvips/resample/shrink.c:156 libvips/resample/shrinkh.c:443 #: libvips/resample/shrinkv.c:632 msgid "Ceil" msgstr "" #: libvips/resample/shrink.c:157 libvips/resample/shrinkh.c:444 #: libvips/resample/shrinkv.c:633 msgid "Round-up output dimensions" msgstr "" #: libvips/resample/shrinkh.c:352 libvips/resample/shrinkv.c:485 msgid "shrink factors should be >= 1" msgstr "" #: libvips/resample/similarity.c:123 msgid "base similarity transform" msgstr "" #: libvips/resample/similarity.c:197 msgid "similarity transform of an image" msgstr "" #: libvips/resample/similarity.c:201 msgid "Scale by this factor" msgstr "" #: libvips/resample/similarity.c:208 libvips/resample/similarity.c:277 msgid "Rotate clockwise by this many degrees" msgstr "" #: libvips/resample/similarity.c:273 msgid "rotate an image by a number of degrees" msgstr "" #: libvips/resample/thumbnail.c:959 msgid "thumbnail generation" msgstr "" #: libvips/resample/thumbnail.c:974 msgid "Target width" msgstr "" #: libvips/resample/thumbnail.c:975 msgid "Size to this width" msgstr "" #: libvips/resample/thumbnail.c:981 msgid "Target height" msgstr "" #: libvips/resample/thumbnail.c:982 msgid "Size to this height" msgstr "" #: libvips/resample/thumbnail.c:989 msgid "Only upsize, only downsize, or both" msgstr "" #: libvips/resample/thumbnail.c:995 msgid "No rotate" msgstr "" #: libvips/resample/thumbnail.c:996 msgid "Don't use orientation tags to rotate image upright" msgstr "" #: libvips/resample/thumbnail.c:1002 msgid "Crop" msgstr "" #: libvips/resample/thumbnail.c:1003 msgid "Reduce to fill target rectangle, then crop" msgstr "" #: libvips/resample/thumbnail.c:1009 msgid "Linear" msgstr "" #: libvips/resample/thumbnail.c:1010 msgid "Reduce in linear light" msgstr "" #: libvips/resample/thumbnail.c:1017 msgid "Fallback input profile" msgstr "" #: libvips/resample/thumbnail.c:1024 msgid "Fallback output profile" msgstr "" #: libvips/resample/thumbnail.c:1050 msgid "Auto rotate" msgstr "" #: libvips/resample/thumbnail.c:1051 msgid "Use orientation tags to rotate image upright" msgstr "" #: libvips/resample/thumbnail.c:1061 msgid "Import profile" msgstr "" #: libvips/resample/thumbnail.c:1062 msgid "Fallback import profile" msgstr "" #: libvips/resample/thumbnail.c:1068 msgid "Export profile" msgstr "" #: libvips/resample/thumbnail.c:1069 msgid "Fallback export profile" msgstr "" #: libvips/resample/thumbnail.c:1210 msgid "generate thumbnail from file" msgstr "" #: libvips/resample/thumbnail.c:1217 msgid "Filename to read from" msgstr "" #: libvips/resample/thumbnail.c:1457 msgid "generate thumbnail from buffer" msgstr "" #: libvips/resample/thumbnail.c:1470 libvips/resample/thumbnail.c:1684 #, fuzzy msgid "Extra options" msgstr "colour operations" #: libvips/resample/thumbnail.c:1471 libvips/resample/thumbnail.c:1685 msgid "Options that are passed on to the underlying loader" msgstr "" #: libvips/resample/thumbnail.c:1671 msgid "generate thumbnail from source" msgstr "" #: libvips/resample/thumbnail.c:1797 msgid "generate thumbnail from image" msgstr "" #: libvips/resample/vsqbs.cpp:378 msgid "B-Splines with antialiasing smoothing" msgstr "" #: tools/vips.c:166 #, c-format msgid "'%s' is not the name of a vips class" msgstr "" #: tools/vips.c:282 #, c-format msgid "'%s' is not the name of a vips operation" msgstr "" #: tools/vips.c:355 #, c-format msgid "no package or function \"%s\"" msgstr "" #: tools/vips.c:584 msgid "execute vips operation OPER" msgstr "" #: tools/vips.c:627 msgid "Operation help" msgstr "" #: tools/vips.c:706 msgid "[ACTION] [OPTIONS] [PARAMETERS] - VIPS driver program" msgstr "" #: tools/vips.c:772 #, c-format msgid "unable to load \"%s\" -- %s" msgstr "" #: tools/vips.c:916 #, c-format msgid "unknown action \"%s\"" msgstr "" #: tools/vipsedit.c:129 #, c-format msgid "'%s' is not a positive integer" msgstr "" #: tools/vipsedit.c:142 msgid "unable to start VIPS" msgstr "" #: tools/vipsedit.c:165 msgid "vipsedit - edit vips file header" msgstr "" #: tools/vipsedit.c:193 #, c-format msgid "usage: %s [OPTION...] vips-file\n" msgstr "" #: tools/vipsedit.c:200 #, c-format msgid "could not open image %s" msgstr "" #: tools/vipsedit.c:206 #, c-format msgid "could not read VIPS header for %s" msgstr "" #: tools/vipsedit.c:216 #, c-format msgid "bad endian-ness %s, should be 'big' or 'little'" msgstr "" #: tools/vipsedit.c:230 #, c-format msgid "bad format %s" msgstr "" #: tools/vipsedit.c:244 #, c-format msgid "bad interpretation %s" msgstr "" #: tools/vipsedit.c:254 #, c-format msgid "bad coding %s" msgstr "" #: tools/vipsedit.c:268 #, c-format msgid "could not seek on %s" msgstr "" #: tools/vipsedit.c:271 #, c-format msgid "could not write to %s" msgstr "" #: tools/vipsedit.c:278 msgid "could not get ext data" msgstr "" #: tools/vipsedit.c:287 msgid "could not set extension" msgstr "" #: tools/vipsheader.c:221 msgid "- print image header" msgstr "" #: tools/vipsthumbnail.c:459 msgid "bad geometry spec" msgstr "" #: tools/vipsthumbnail.c:528 msgid "- thumbnail generator" msgstr "" #~ msgid "Neither global nor local color map" #~ msgstr "Neither global nor local colour map" libvips-8.18.2/po/malkovich.po000066400000000000000000002015351516303661500162310ustar00rootroot00000000000000# test translation file # msgid "" msgstr "" "Project-Id-Version: nip2 7.9.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2005-06-08 14:51+0100\n" "PO-Revision-Date: 2003-11-04 12:30+0000\n" "Last-Translator: malkovich \n" "Language-Team: malkovich \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: libsrc/convolution/im_addgnoise.c:78 #, fuzzy msgid "too many bands" msgstr "Malkovich" #: libsrc/convolution/im_sharpen.c:247 msgid "input not 3-band short" msgstr "" #: libsrc/convolution/im_sharpen.c:258 msgid "parameters out of range" msgstr "" #: libsrc/colour/im_icc_transform.c:200 libsrc/colour/im_icc_transform.c:210 #, fuzzy, c-format msgid "unable to open profile \"%s\"" msgstr "Malkovich" #: libsrc/matrix/im_invmat.c:69 msgid "singular matrix in ludcmp" msgstr "" #: libsrc/matrix/im_invmat.c:206 #, fuzzy msgid "singular matrix" msgstr "Malkovich" #: libsrc/acquire/im_clamp.c:69 msgid "bad input format" msgstr "" #: libsrc/acquire/im_clamp.c:74 msgid "bad black format" msgstr "" #: libsrc/freq_filt/im_invfftr.c:89 libsrc/freq_filt/im_invfftr.c:171 #: libsrc/freq_filt/im_invfft.c:94 libsrc/freq_filt/im_invfft.c:142 #: libsrc/freq_filt/im_fwfft.c:112 libsrc/freq_filt/im_fwfft.c:217 #: libsrc/freq_filt/im_fwfft.c:308 libsrc/freq_filt/im_fwfft.c:420 #, fuzzy msgid "one band uncoded only" msgstr "Malkovich" #: libsrc/freq_filt/im_invfftr.c:126 libsrc/freq_filt/im_invfftr.c:209 #: libsrc/freq_filt/im_invfft.c:106 libsrc/freq_filt/im_invfft.c:156 #: libsrc/freq_filt/im_fwfft.c:123 libsrc/freq_filt/im_fwfft.c:228 #: libsrc/freq_filt/im_fwfft.c:321 libsrc/freq_filt/im_fwfft.c:433 #, fuzzy msgid "unable to create transform plan" msgstr "Malkovich" #: libsrc/freq_filt/im_invfftr.c:252 libsrc/freq_filt/im_invfft.c:199 #, fuzzy msgid "one band complex uncoded only" msgstr "Malkovich" #: libsrc/freq_filt/im_invfftr.c:256 libsrc/freq_filt/im_invfft.c:203 #: libsrc/freq_filt/im_fwfft.c:515 #, fuzzy msgid "sides must be power of 2" msgstr "Malkovich" #: libsrc/freq_filt/im_invfftr.c:276 libsrc/freq_filt/im_invfft.c:223 #: libsrc/freq_filt/im_fwfft.c:535 msgid "fft_sp failed" msgstr "" #: libsrc/freq_filt/im_fwfft.c:511 msgid "one band non-complex uncoded only" msgstr "" #: libsrc/conversion/im_extract.c:162 msgid "bad extract area" msgstr "" #: libsrc/conversion/im_extract.c:167 libsrc/conversion/im_extract.c:252 msgid "band selection out of range" msgstr "" #: libsrc/conversion/im_extract.c:172 #, fuzzy msgid "unknown image coding type" msgstr "Malkovich" #: libsrc/conversion/im_extract.c:177 msgid "can't extract band from IM_CODING_LABQ" msgstr "" #: libsrc/conversion/im_extract.c:256 libsrc/arithmetic/im_powtra.c:184 #: libsrc/arithmetic/im_deviate.c:171 libsrc/arithmetic/im_multiply.c:186 #: libsrc/arithmetic/im_ceil.c:92 libsrc/arithmetic/im_maxpos.c:94 #: libsrc/arithmetic/im_costra.c:117 libsrc/arithmetic/im_costra.c:202 #: libsrc/arithmetic/im_tantra.c:117 libsrc/arithmetic/im_tantra.c:203 #: libsrc/arithmetic/im_measure.c:189 libsrc/arithmetic/im_sign.c:146 #: libsrc/arithmetic/im_expntra.c:184 libsrc/arithmetic/im_logtra.c:123 #: libsrc/arithmetic/im_abs.c:147 libsrc/arithmetic/im_add.c:254 #: libsrc/arithmetic/im_avg.c:166 libsrc/arithmetic/im_max.c:232 #: libsrc/arithmetic/im_min.c:231 libsrc/arithmetic/im_lintra.c:281 #: libsrc/arithmetic/im_invert.c:117 libsrc/arithmetic/im_stats.c:238 #: libsrc/arithmetic/im_floor.c:92 libsrc/arithmetic/im_remainder.c:103 #: libsrc/arithmetic/im_remainder.c:212 libsrc/arithmetic/im_subtract.c:171 #: libsrc/arithmetic/im_sintra.c:117 libsrc/arithmetic/im_sintra.c:202 #: libsrc/arithmetic/im_log10tra.c:123 libsrc/arithmetic/im_divide.c:150 msgid "not uncoded" msgstr "" #: libsrc/conversion/im_magick2vips.c:54 libsrc/conversion/im_magick2vips.c:61 msgid "libMagick support disabled" msgstr "" #: libsrc/conversion/im_magick2vips.c:190 #, fuzzy, c-format msgid "unsupported colorspace %d" msgstr "Malkovich" #: libsrc/conversion/im_magick2vips.c:214 #, fuzzy, c-format msgid "unsupported bit depth %d" msgstr "Malkovich" #: libsrc/conversion/im_magick2vips.c:409 #, fuzzy msgid "unable to read pixels" msgstr "Malkovich" #: libsrc/conversion/im_magick2vips.c:431 #, fuzzy, c-format msgid "" "unable to read file \"%s\"\n" "libMagick error: %s %s" msgstr "Malkovich" #: libsrc/conversion/im_magick2vips.c:456 #, fuzzy, c-format msgid "" "unable to ping file \"%s\"\n" "libMagick error: %s %s" msgstr "Malkovich" #: libsrc/conversion/im_magick2vips.c:467 #, fuzzy msgid "bad image size" msgstr "Malkovich" #: libsrc/conversion/im_copy.c:138 libsrc/conversion/im_copy.c:275 msgid "in must be uncoded" msgstr "" #: libsrc/conversion/im_copy.c:142 msgid "Coding must be NONE or LABQ" msgstr "" #: libsrc/conversion/im_copy.c:146 #, c-format msgid "BandFmt must be in range [0,%d]" msgstr "" #: libsrc/conversion/im_copy.c:169 msgid "sizeof( pixel ) has changed" msgstr "" #: libsrc/conversion/im_copy.c:312 #, fuzzy msgid "unsupported image type" msgstr "Malkovich" #: libsrc/conversion/im_ppm2vips.c:250 #, fuzzy msgid "internal error" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:131 libsrc/conversion/im_tiff2vips.c:144 #: libsrc/conversion/im_vips2tiff.c:127 msgid "TIFF support disabled" msgstr "" #: libsrc/conversion/im_tiff2vips.c:284 libsrc/conversion/im_tiff2vips.c:307 #: libsrc/conversion/im_tiff2vips.c:326 #, c-format msgid "required field %d missing" msgstr "" #: libsrc/conversion/im_tiff2vips.c:288 #, c-format msgid "required field %d=%d, not %d" msgstr "" #: libsrc/conversion/im_tiff2vips.c:632 #, fuzzy msgid "read error" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1029 #, fuzzy msgid "bad colormap" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1085 libsrc/conversion/im_tiff2vips.c:1135 msgid "3 or 4 bands RGB TIFF only" msgstr "" #: libsrc/conversion/im_tiff2vips.c:1284 #, fuzzy msgid "unknown resolution unit" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1360 #, fuzzy, c-format msgid "unsupported sample format %d for lab image" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1370 #, fuzzy, c-format msgid "unsupported depth %d for LAB image" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1417 #, c-format msgid "unsupported sample format %d for greyscale image" msgstr "" #: libsrc/conversion/im_tiff2vips.c:1426 #, fuzzy, c-format msgid "unsupported depth %d for greyscale image" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1466 #, c-format msgid "unsupported sample format %d for rgb image" msgstr "" #: libsrc/conversion/im_tiff2vips.c:1475 #, fuzzy, c-format msgid "unsupported depth %d for RGB image" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1489 #, c-format msgid "unknown photometric interpretation %d" msgstr "" #: libsrc/conversion/im_tiff2vips.c:1550 #, fuzzy, c-format msgid "bad page number %d" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1577 libsrc/conversion/im_vips2tiff.c:265 #, fuzzy, c-format msgid "unable to open \"%s\" for input" msgstr "Malkovich" #: libsrc/conversion/im_tiff2vips.c:1627 libsrc/conversion/im_tiff2vips.c:1661 #, c-format msgid "TIFF file does not contain page %d" msgstr "" #: libsrc/conversion/im_vips2tiff.c:228 #, fuzzy, c-format msgid "TIFF error in \"%s\": " msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:245 #, fuzzy, c-format msgid "unable to open \"%s\" for output" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:381 #, fuzzy, c-format msgid "file \"%s\" too long" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:393 #, fuzzy, c-format msgid "error reading from file \"%s\"" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:416 #, fuzzy, c-format msgid "unable to read profile \"%s\"" msgstr "Malkovich" #. Out of space! #. #: libsrc/conversion/im_vips2tiff.c:688 msgid "layer buffer exhausted -- try making TIFF output tiles smaller" msgstr "" #: libsrc/conversion/im_vips2tiff.c:919 msgid "TIFF write tile failed" msgstr "" #: libsrc/conversion/im_vips2tiff.c:994 #, fuzzy msgid "internal error #9876345" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:1109 #, fuzzy msgid "TIFF write failed" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:1238 #, fuzzy msgid "bad JPEG quality parameter" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:1244 #, c-format msgid "" "unknown compression mode \"%s\"\n" "should be one of \"none\", \"packbits\", \"ccittfax4\", \"lzw\", \"deflate\" " "or \"jpeg\"" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1258 #, fuzzy msgid "bad tile sizes" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:1265 #, c-format msgid "bad tile size %dx%d" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1273 msgid "tile size not a multiple of 16" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1282 #, c-format msgid "" "unknown layout mode \"%s\"\n" "should be one of \"tile\" or \"strip\"" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1294 #, c-format msgid "" "unknown multi-res mode \"%s\"\n" "should be one of \"flat\" or \"pyramid\"" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1306 #, c-format msgid "" "unknown format \"%s\"\n" "should be one of \"onebit\" or \"manybit\"" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1318 #, c-format msgid "" "unknown resolution unit \"%s\"\n" "should be one of \"res_cm\" or \"res_inch\"" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1327 #, fuzzy msgid "bad resolution values" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:1342 #, c-format msgid "unknown extra options \"%s\"" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1346 msgid "can't have strip pyramid -- enabling tiling" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1356 msgid "can only pyramid LABQ and non-complex images" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1529 #, fuzzy msgid "unknown coding type" msgstr "Malkovich" #: libsrc/conversion/im_vips2tiff.c:1537 msgid "unsigned 8-bit int, 16-bit int, and 32-bit float only" msgstr "" #: libsrc/conversion/im_vips2tiff.c:1543 msgid "1 to 4 bands only" msgstr "" #: libsrc/arithmetic/im_powtra.c:188 libsrc/arithmetic/im_tantra.c:121 #: libsrc/arithmetic/im_tantra.c:207 libsrc/arithmetic/im_expntra.c:188 #: libsrc/arithmetic/im_logtra.c:127 libsrc/arithmetic/im_sintra.c:121 #: libsrc/arithmetic/im_sintra.c:206 libsrc/arithmetic/im_log10tra.c:127 #, fuzzy msgid "not non-complex" msgstr "Malkovich" #: libsrc/arithmetic/im_powtra.c:193 libsrc/arithmetic/im_expntra.c:193 #: libsrc/arithmetic/im_lintra.c:290 libsrc/arithmetic/im_remainder.c:217 #, c-format msgid "not 1 or %d elements in vector" msgstr "" #: libsrc/arithmetic/im_deviate.c:175 libsrc/arithmetic/im_costra.c:121 #: libsrc/arithmetic/im_costra.c:206 libsrc/arithmetic/im_measure.c:193 #: libsrc/arithmetic/im_avg.c:162 libsrc/arithmetic/im_stats.c:234 msgid "bad input type" msgstr "" #: libsrc/arithmetic/im_multiply.c:177 libsrc/arithmetic/im_remainder.c:94 msgid "not same size" msgstr "" #: libsrc/arithmetic/im_multiply.c:182 libsrc/arithmetic/im_add.c:250 #: libsrc/arithmetic/im_remainder.c:99 libsrc/arithmetic/im_subtract.c:167 #: libsrc/arithmetic/im_divide.c:146 #, fuzzy msgid "not same number of bands" msgstr "Malkovich" #: libsrc/arithmetic/im_minpos.c:80 msgid "input must be uncoded" msgstr "" #: libsrc/arithmetic/im_gadd.c:91 libsrc/arithmetic/im_gadd.c:107 #, fuzzy msgid "Unable to accept image1" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:79 #, fuzzy msgid "absolute value" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:98 #, fuzzy msgid "add two images" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:123 msgid "average value of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:142 msgid "multiply two complex images, normalising output" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:167 msgid "standard deviation of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:186 #, fuzzy msgid "10^pel of image" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:205 #, fuzzy msgid "e^pel of image" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:234 #, fuzzy msgid "x^pel of image" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:263 msgid "[x,y,z]^pel of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:299 msgid "average of 4 images" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:318 msgid "divide two images" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:352 msgid "calculate a*in1 + b*in2 + c = outfile" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:371 msgid "photographic negative" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:402 msgid "calculate a*in + b = outfile" msgstr "" #: libsrc/arithmetic/arith_dispatch.c:427 msgid "vectors not same length" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:438 msgid "calculate a*in + b -> out, a and b vectors" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:470 msgid "calculate max(white)*factor*(in/white), if clip == 1" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:489 #, fuzzy msgid "log10 of image" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:508 #, fuzzy msgid "ln of image" msgstr "Malkovich" #. Name #: libsrc/arithmetic/arith_dispatch.c:527 msgid "tan of image (angles in degrees)" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:546 msgid "atan of image (result in degrees)" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:565 msgid "cos of image (angles in degrees)" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:584 msgid "acos of image (result in degrees)" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:603 msgid "round to smallest integal value not less than" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:622 msgid "round to largest integal value not greater than" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:641 msgid "round to nearest integal value" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:660 msgid "sin of image (angles in degrees)" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:679 msgid "unit vector in direction of value" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:698 msgid "asin of image (result in degrees)" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:723 msgid "maximum value of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:758 msgid "position of maximum value of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:818 msgid "measure averages of a grid of patches" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:843 msgid "minimum value of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:871 msgid "position of minimum value of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:890 msgid "remainder after integer division" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:919 msgid "remainder after integer division by a constant" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:948 msgid "remainder after integer division by a vector of constants" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:968 msgid "multiply two images" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:989 msgid "pel^x ofbuildimage" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:1010 msgid "pel^[x,y,z] of image" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:1041 msgid "many image statistics in one pass" msgstr "" #. Name #: libsrc/arithmetic/arith_dispatch.c:1060 msgid "subtract two images" msgstr "" #: libsrc/arithmetic/im_measure.c:106 #, c-format msgid "patch %d is out of range" msgstr "" #: libsrc/arithmetic/im_measure.c:148 #, c-format msgid "patch %d, band %d: avg = %g, sdev = %g" msgstr "" #: libsrc/arithmetic/im_abs.c:183 #, fuzzy msgid "unknown input type" msgstr "Malkovich" #: libsrc/arithmetic/im_add.c:190 #, fuzzy, c-format msgid "not one band or %d bands" msgstr "Malkovich" #: libsrc/arithmetic/im_add.c:194 #, fuzzy msgid "bad bands" msgstr "Malkovich" #: libsrc/arithmetic/im_invert.c:121 msgid "not UCHAR" msgstr "" #: libsrc/arithmetic/im_remainder.c:239 #, fuzzy msgid "division by zero" msgstr "Malkovich" #: libsrc/relational/im_blend.c:338 #, fuzzy msgid "images not uncoded" msgstr "Malkovich" #: libsrc/relational/im_blend.c:344 libsrc/relational/im_ifthenelse.c:183 msgid "size and format of then and else must match" msgstr "" #: libsrc/relational/im_blend.c:349 libsrc/relational/im_ifthenelse.c:188 msgid "conditional image must be uchar" msgstr "" #: libsrc/relational/im_blend.c:354 libsrc/relational/im_ifthenelse.c:193 msgid "conditional image must be one band or same as then and else images" msgstr "" #: libsrc/relational/im_ifthenelse.c:167 msgid "then image must be uncoded or labpack" msgstr "" #: libsrc/relational/im_ifthenelse.c:172 msgid "else image must be uncoded or labpack" msgstr "" #: libsrc/relational/im_ifthenelse.c:177 msgid "condition image must be uncoded" msgstr "" #: libsrc/histograms_lut/im_maplut.c:112 #, c-format msgid "%d overflows detected" msgstr "" #. Switch for input types. Has to be uint type! #. #: libsrc/histograms_lut/im_maplut.c:473 #, fuzzy msgid "bad input file" msgstr "Malkovich" #. Switch for LUT types. One function for non-complex images, a #. * variant for complex ones. Another pair as well, in case the input is not #. * uchar. #. #: libsrc/histograms_lut/im_maplut.c:504 #, fuzzy msgid "bad lut file" msgstr "Malkovich" #: libsrc/histograms_lut/im_maplut.c:554 msgid "lut is not uncoded" msgstr "" #: libsrc/histograms_lut/im_maplut.c:558 msgid "lut seems very large!" msgstr "" #: libsrc/histograms_lut/im_maplut.c:570 msgid "input is not uncoded" msgstr "" #: libsrc/histograms_lut/im_maplut.c:574 #, fuzzy msgid "input is not some unsigned integer type" msgstr "Malkovich" #: libsrc/histograms_lut/im_maplut.c:579 msgid "" "lut should have 1 band, or same number of bands as input, or any number of " "bands if input has 1 band" msgstr "" #: libsrc/histograms_lut/im_maplut.c:586 msgid "input is uchar and lut does not have 256 elements" msgstr "" #: libsrc/histograms_lut/im_histnD.c:212 #, fuzzy msgid " uncoded images only" msgstr "Malkovich" #: libsrc/histograms_lut/im_histnD.c:218 msgid " unsigned 8 or 16 bit images only" msgstr "" #: libsrc/histograms_lut/im_histnD.c:225 #, c-format msgid " bins out of range [1,%d]" msgstr "" #: libsrc/histograms_lut/tone.c:233 msgid "bad in_max, out_max parameters" msgstr "" #: libsrc/histograms_lut/tone.c:237 #, fuzzy msgid "bad Lb, Lw parameters" msgstr "Malkovich" #: libsrc/histograms_lut/tone.c:241 msgid "Ps not in range [0.0,1.0]" msgstr "" #: libsrc/histograms_lut/tone.c:245 msgid "Pm not in range [0.0,1.0]" msgstr "" #: libsrc/histograms_lut/tone.c:249 msgid "Ph not in range [0.0,1.0]" msgstr "" #: libsrc/histograms_lut/tone.c:253 msgid "S not in range [-30,+30]" msgstr "" #: libsrc/histograms_lut/tone.c:257 msgid "M not in range [-30,+30]" msgstr "" #: libsrc/histograms_lut/tone.c:261 msgid "H not in range [-30,+30]" msgstr "" #: libsrc/histograms_lut/tone.c:342 libsrc/histograms_lut/tone.c:390 msgid "not 1 by n or n by 1 image" msgstr "" #: libsrc/histograms_lut/tone.c:396 msgid "not 1024-point IM_BANDFMT_SHORT lut" msgstr "" #: libsrc/histograms_lut/tone.c:413 libsrc/histograms_lut/tone.c:487 msgid "input not LabS or LabQ" msgstr "" #: libsrc/inplace/im_insertplace.c:81 msgid "inputs differ in format" msgstr "" #: libsrc/inplace/im_insertplace.c:85 msgid "input should be uncoded or IM_CODING_LABQ" msgstr "" #: libsrc/inplace/im_insertplace.c:104 msgid "small not inside big" msgstr "" #: libsrc/iofuncs/im_mapfile.c:134 libsrc/iofuncs/im_mapfile.c:301 #, fuzzy msgid "unable to CreateFileMapping" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:150 libsrc/iofuncs/im_mapfile.c:313 #, fuzzy msgid "unable to MapViewOfFile" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:177 #, fuzzy msgid "unable to mmap" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:178 #, c-format msgid "" "map failed (%s), running very low on system resources, expect a crash soon" msgstr "" #: libsrc/iofuncs/im_mapfile.c:195 libsrc/iofuncs/im_mapfile.c:307 #, fuzzy msgid "unable to UnmapViewOfFile" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:201 #, fuzzy msgid "unable to munmap file" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:224 libsrc/iofuncs/im_mapfile.c:265 #, fuzzy msgid "unable to get file status" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:229 msgid "file is less than 64 bytes" msgstr "" #: libsrc/iofuncs/im_mapfile.c:233 msgid "not a regular file" msgstr "" #: libsrc/iofuncs/im_mapfile.c:270 #, fuzzy msgid "unable to read data" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:333 #, fuzzy, c-format msgid "unable to mmap: \"%s\" - %s" msgstr "Malkovich" #: libsrc/iofuncs/im_mapfile.c:343 #, fuzzy, c-format msgid "unable to mmap \"%s\" to same address" msgstr "Malkovich" #: libsrc/iofuncs/im_binfile.c:88 libsrc/iofuncs/im_render.c:1079 #, fuzzy msgid "bad parameters" msgstr "Malkovich" #: libsrc/iofuncs/im_binfile.c:116 #, fuzzy, c-format msgid "unable to open %s: file has been truncated" msgstr "Malkovich" #: libsrc/iofuncs/im_binfile.c:126 #, c-format msgid "%s is longer than expected" msgstr "" #: libsrc/iofuncs/error.c:114 #, fuzzy msgid "windows error" msgstr "Malkovich" #: libsrc/iofuncs/error.c:123 #, fuzzy msgid "unix error" msgstr "Malkovich" #: libsrc/iofuncs/error.c:149 libsrc/iofuncs/error.c:150 #: libsrc/iofuncs/error.c:170 libsrc/iofuncs/error.c:171 #, fuzzy, c-format msgid "%s: " msgstr "Malkovich" #: libsrc/iofuncs/error.c:149 msgid "vips diagnostic" msgstr "" #: libsrc/iofuncs/error.c:170 msgid "vips warning" msgstr "" #: libsrc/iofuncs/im_readhist.c:163 msgid "history file too large" msgstr "" #: libsrc/iofuncs/im_readhist.c:174 #, fuzzy msgid "unable to read" msgstr "Malkovich" #: libsrc/iofuncs/im_header.c:102 #, c-format msgid "no such int field \"%s\"" msgstr "" #: libsrc/iofuncs/im_header.c:124 #, c-format msgid "no such double field \"%s\"" msgstr "" #: libsrc/iofuncs/im_header.c:146 #, c-format msgid "no such string field \"%s\"" msgstr "" #: libsrc/iofuncs/im_printdesc.c:112 msgid "" msgstr "" #: libsrc/iofuncs/im_printdesc.c:118 #, fuzzy msgid "" msgstr "Malkovich" #: libsrc/iofuncs/im_printdesc.c:124 msgid "" msgstr "" #: libsrc/iofuncs/im_printdesc.c:130 msgid "" msgstr "" #: libsrc/iofuncs/im_printdesc.c:136 msgid "" msgstr "" #: libsrc/iofuncs/im_printdesc.c:142 msgid "" msgstr "" #: libsrc/iofuncs/im_render.c:511 libsrc/iofuncs/im_render.c:666 #: libsrc/iofuncs/threadgroup.c:330 #, fuzzy msgid "unable to create thread" msgstr "Malkovich" #: libsrc/iofuncs/package.c:436 #, fuzzy, c-format msgid "unable to close plugin \"%s\"" msgstr "Malkovich" #: libsrc/iofuncs/package.c:438 libsrc/iofuncs/package.c:488 #: libsrc/iofuncs/package.c:502 #, fuzzy, c-format msgid "plugin error: %s" msgstr "Malkovich" #: libsrc/iofuncs/package.c:462 msgid "plugins not supported on this platform" msgstr "" #: libsrc/iofuncs/package.c:486 #, fuzzy, c-format msgid "unable to open plugin \"%s\"" msgstr "Malkovich" #: libsrc/iofuncs/package.c:499 #, c-format msgid "unable to find symbol \"package_table\" in plugin \"%s\"" msgstr "" #: libsrc/iofuncs/package.c:513 #, c-format msgid "corrupted package table in plugin \"%s\"" msgstr "" #: libsrc/iofuncs/package.c:636 libsrc/iofuncs/package.c:692 #, fuzzy, c-format msgid "function \"%s\" not found" msgstr "Malkovich" #: libsrc/iofuncs/package.c:664 #, fuzzy, c-format msgid "package \"%s\" not found" msgstr "Malkovich" #: libsrc/iofuncs/package.c:802 #, fuzzy msgid "too few arguments" msgstr "Malkovich" #: libsrc/iofuncs/package.c:824 #, fuzzy msgid "too many arguments" msgstr "Malkovich" #: libsrc/iofuncs/package.c:1031 msgid "flag not 0,1,2" msgstr "" #: libsrc/iofuncs/im_wrapmany.c:158 #, fuzzy msgid "too many input images" msgstr "Malkovich" #: libsrc/iofuncs/im_wrapmany.c:176 msgid "descriptors differ in size" msgstr "" #~ msgid "Stack overflow." #~ msgstr "Malkovich" #~ msgid "Spine stack overflow, runaway recursion?" #~ msgstr "Malkovich" #~ msgid "Frame stack overflow, expression too complex." #~ msgstr "Malkovich" #~ msgid "Stack underflow." #~ msgstr "Malkovich" #~ msgid "Frame stack underflow, you've found a bug!" #~ msgstr "Malkovich" #~ msgid "Spine stack underflow, you've found a bug!" #~ msgstr "Malkovich" #, fuzzy #~ msgid "" #~ "Error in binary \"%s\".\n" #~ "left = %s\n" #~ "right = %s" #~ msgstr "Malkovich" #~ msgid "Member not found." #~ msgstr "Malkovich" #, fuzzy #~ msgid "" #~ "Member \"%s\" not found in object \"%s\".\n" #~ "object = %s\n" #~ "tag = %s\n" #~ "Reference attempted in \"%s\"." #~ msgstr "Malkovich" #~ msgid "Bad argument." #~ msgstr "Malkovich" #, fuzzy #~ msgid "" #~ "Error in unary \"%s\".\n" #~ "argument = %s" #~ msgstr "Malkovich" #~ msgid "Symbol on left hand side of '.' is not scope" #~ msgstr "Malkovich" #~ msgid "Right hand side of '.' is not tag." #~ msgstr "Malkovich" #~ msgid "Bad left hand side." #~ msgstr "Malkovich" #~ msgid "Unimplemented." #~ msgstr "Malkovich" #~ msgid "invoking method:" #~ msgstr "Malkovich" #~ msgid "Close _without Saving" #~ msgstr "Malkovich" #~ msgid "translator_credits" #~ msgstr "Malkovich" #~ msgid "About %s." #~ msgstr "Malkovich" #~ msgid "%s: (c) 2003 The National Gallery" #~ msgstr "Malkovich" #~ msgid "" #~ "%s comes with ABSOLUTELY NO WARRANTY. This is free software\n" #~ "and you are welcome to redistribute it under certain conditions,\n" #~ "see http://www.gnu.org." #~ msgstr "Malkovich" #~ msgid "Homepage:" #~ msgstr "Malkovich" #~ msgid "Linked to VIPS library version:" #~ msgstr "Malkovich" #~ msgid "Temp files in:" #~ msgstr "Malkovich" #~ msgid "Help page not found." #~ msgstr "Malkovich" #~ msgid "No indexed help page found for tag \"%s\"" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Search for" #~ msgstr "Malkovich" #~ msgid "Case sensitive" #~ msgstr "Malkovich" #~ msgid "Regular expression" #~ msgstr "Malkovich" #~ msgid "Search from start" #~ msgstr "Malkovich" #~ msgid "Unable to open location." #~ msgstr "Malkovich" #~ msgid "" #~ "Unable to open URL \"%s\"\n" #~ "windows error code = %d" #~ msgstr "Malkovich" #~ msgid "Browser window opened." #~ msgstr "Malkovich" #~ msgid "" #~ "Opened window for URL:\n" #~ "\n" #~ " %s\n" #~ "\n" #~ "This may take a few seconds." #~ msgstr "Malkovich" #~ msgid "" #~ "Attempted to launch browser with command:\n" #~ "\n" #~ " %s\n" #~ "\n" #~ "You can change this command in Preferences." #~ msgstr "Malkovich" #~ msgid "" #~ "Opened window for URL:\n" #~ "\n" #~ " %s\n" #~ "\n" #~ "You may need to switch desktops to see the new window." #~ msgstr "Malkovich" #~ msgid "Cancelling" #~ msgstr "Malkovich" #~ msgid "Computing image." #~ msgstr "Malkovich" #~ msgid "" #~ "Calculating all the pixels in an image. Press the\n" #~ "Cancel button to stop computation early." #~ msgstr "Malkovich" #~ msgid "Calculating" #~ msgstr "Malkovich" #~ msgid "About %d seconds left" #~ msgstr "Malkovich" #~ msgid "Thumbnails" #~ msgstr "Malkovich" #~ msgid "Image files found in: \"%s\"" #~ msgstr "Malkovich" #~ msgid "Searching ..." #~ msgstr "Malkovich" #~ msgid "Search incomplete!" #~ msgstr "Malkovich" #~ msgid "Not implemented." #~ msgstr "Malkovich" #~ msgid "Complex math ops not implemented." #~ msgstr "Malkovich" #, fuzzy #~ msgid "Macro error." #~ msgstr "Malkovich" #~ msgid "Builtin \"%s\" takes %d argument." #~ msgid_plural "Builtin \"%s\" takes %d arguments." #~ msgstr[0] "Malkovich" #~ msgstr[1] "Malkovich" #~ msgid "" #~ "Argument %d to builtin \"%s\" should be \"%s\"\n" #~ "you passed:\n" #~ " %s" #~ msgstr "Malkovich" #~ msgid "" #~ "Object %s\n" #~ "is not a class." #~ msgstr "Malkovich" #~ msgid "Member \"%s\" not found in class \"%s\"." #~ msgstr "Malkovich" #~ msgid "" #~ "Too many arguments to superclass constructor \"%s\".\n" #~ "No more than %d arguments are possible." #~ msgstr "Malkovich" #~ msgid "Superclass constructor \"%s\" expects %d arguments, not %d." #~ msgstr "Malkovich" #~ msgid "Bad superclass." #~ msgstr "Malkovich" #~ msgid "Superclass constructor \"%s\" should have no secret arguments." #~ msgstr "Malkovich" #~ msgid "First element in superclass of \"%s\" must be class or constructor." #~ msgstr "Malkovich" #~ msgid "" #~ "Too many arguments to class constructor \"%s\".\n" #~ "No more than %d arguments are possible." #~ msgstr "Malkovich" #~ msgid "Class not found." #~ msgstr "Malkovich" #~ msgid "Class \"%s\" not found." #~ msgstr "Malkovich" #~ msgid "" #~ "Member \"%s\" of class \"%s\" should be of type \"%s\", instead it's:" #~ msgstr "Malkovich" #~ msgid "_%s() not implemented for class \"%s\"." #~ msgstr "Malkovich" #~ msgid "Edit color \"%s\"" #~ msgstr "Malkovich" #~ msgid "Set color" #~ msgstr "Malkovich" #~ msgid "Bad value." #~ msgstr "Malkovich" #~ msgid "Double-click to edit this color, or drag-and-drop between colors" #~ msgstr "Malkovich" #~ msgid "Name clash." #~ msgstr "Malkovich" #~ msgid "" #~ "Can't create column \"%s\".\n" #~ "A column with that name already exists." #~ msgstr "Malkovich" #~ msgid "Empty column." #~ msgstr "Malkovich" #~ msgid "There are no objects in the current column." #~ msgstr "Malkovich" #~ msgid "Too few items." #~ msgstr "Malkovich" #~ msgid "" #~ "This column only has %d items, but %d items\n" #~ "are needed by operation \"%s\"." #~ msgstr "Malkovich" #~ msgid "Save Column \"%s\"" #~ msgstr "Malkovich" #~ msgid "Name" #~ msgstr "Malkovich" #~ msgid "Toolkit" #~ msgstr "Malkovich" #~ msgid "Filename" #~ msgstr "Malkovich" #~ msgid "Set menu item text here" #~ msgstr "Malkovich" #~ msgid "Add to this toolkit" #~ msgstr "Malkovich" #~ msgid "Store column in this file" #~ msgstr "Malkovich" #~ msgid "New menu item from column \"%s\"" #~ msgstr "Malkovich" #~ msgid "Menuize" #~ msgstr "Malkovich" #~ msgid "Edit caption, press enter to accept changes, press escape to cancel" #~ msgstr "Malkovich" #~ msgid "Enter expressions here" #~ msgstr "Malkovich" #~ msgid "Close the columnview" #~ msgstr "Malkovich" #~ msgid "Open the columnview" #~ msgstr "Malkovich" #~ msgid "Column menu" #~ msgstr "Malkovich" #~ msgid "Edit caption ..." #~ msgstr "Malkovich" #~ msgid "Select all" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Make column into menu item ..." #~ msgstr "Malkovich" #~ msgid "" #~ "Left-drag to move, left-double-click to set title, right-click for menu" #~ msgstr "Malkovich" #~ msgid "Delete the column" #~ msgstr "Malkovich" #~ msgid "Too many shared nodes in graph." #~ msgstr "Malkovich" #~ msgid "Disable optimisation, or raise MAX_RELOC" #~ msgstr "Malkovich" #~ msgid "Member \"%s\" of class \"%s\" should have no arguments." #~ msgstr "Malkovich" #~ msgid "Unable to find image range." #~ msgstr "Malkovich" #~ msgid "Find image range failed." #~ msgstr "Malkovich" #~ msgid "Convert menu" #~ msgstr "Malkovich" #~ msgid "Scale" #~ msgstr "Malkovich" #~ msgid "Interpret" #~ msgstr "Malkovich" #~ msgid "Reset" #~ msgstr "Malkovich" #~ msgid "value" #~ msgstr "Malkovich" #~ msgid "zombie" #~ msgstr "Malkovich" #~ msgid "workspace" #~ msgstr "Malkovich" #~ msgid "workspace group" #~ msgstr "Malkovich" #~ msgid "root symbol" #~ msgstr "Malkovich" #~ msgid "external symbol" #~ msgstr "Malkovich" #~ msgid "built-in symbol" #~ msgstr "Malkovich" #~ msgid "Escape to cancel edit, press Return to accept edit and recalculate" #~ msgstr "Malkovich" #~ msgid "top level" #~ msgstr "Malkovich" #~ msgid "class" #~ msgstr "Malkovich" #~ msgid "instance" #~ msgstr "Malkovich" #~ msgid "definition" #~ msgstr "Malkovich" #~ msgid "parameter \"%s\"" #~ msgstr "Malkovich" #~ msgid "member" #~ msgstr "Malkovich" #~ msgid "function" #~ msgstr "Malkovich" #~ msgid "of" #~ msgstr "Malkovich" #~ msgid "XML library error." #~ msgstr "Malkovich" #~ msgid "model_save_filename: xmlNewDoc() failed" #~ msgstr "Malkovich" #~ msgid "model_save_filename: xmlNewDocNode() failed" #~ msgstr "Malkovich" #~ msgid "Save failed." #~ msgstr "Malkovich" #~ msgid "" #~ "Save of %s \"%s\" to file \"%s\" failed.\n" #~ "%s" #~ msgstr "Malkovich" #~ msgid "filemodel_save_all: no save method" #~ msgstr "Malkovich" #~ msgid "Load failed." #~ msgstr "Malkovich" #~ msgid "" #~ "Can't load XML file \"%s\",\n" #~ "it's not a %s save file" #~ msgstr "Malkovich" #~ msgid "" #~ "Can't load XML file \"%s\",\n" #~ "Unable to extract version information from namespace." #~ msgstr "Malkovich" #~ msgid "" #~ "Can't load XML file \"%s\",\n" #~ "The file does not contain a %s." #~ msgstr "Malkovich" #~ msgid "Save %s %s" #~ msgstr "Malkovich" #~ msgid "Save successful." #~ msgstr "Malkovich" #~ msgid "" #~ "%s \"%s\" successfully saved\n" #~ "to file \"%s\"." #~ msgstr "Malkovich" #~ msgid "Object has been modified." #~ msgstr "Malkovich" #~ msgid "" #~ "%s \"%s\" has been modified since you loaded it\n" #~ "from file \"%s\".\n" #~ "Do you want to save your changes?" #~ msgstr "Malkovich" #~ msgid "%s \"%s\" has been modified. Do you want to save your changes?" #~ msgstr "Malkovich" #~ msgid "Select file" #~ msgstr "Malkovich" #~ msgid "Choose" #~ msgstr "Malkovich" #~ msgid "TIFF image files (*.tif, *.tiff)" #~ msgstr "Malkovich" #~ msgid "JPEG image files (*.jpg, *.jpeg, *.jpe)" #~ msgstr "Malkovich" #~ msgid "PNG image files (*.png)" #~ msgstr "Malkovich" #~ msgid "VIPS image files (*.v)" #~ msgstr "Malkovich" #~ msgid "PPM image files (*.ppm, *.pgm, *.pbm)" #~ msgstr "Malkovich" #~ msgid "Workspace files (*.ws)" #~ msgstr "Malkovich" #~ msgid "Recombination matrix files (*.rec)" #~ msgstr "Malkovich" #~ msgid "Morphology matrix files (*.mor)" #~ msgstr "Malkovich" #~ msgid "Convolution matrix files (*.con)" #~ msgstr "Malkovich" #~ msgid "Matrix files (*.mat)" #~ msgstr "Malkovich" #~ msgid "Definition files (*.def)" #~ msgstr "Malkovich" #~ msgid "ICC profiles (*.icc, *.icm)" #~ msgstr "Malkovich" #~ msgid "All files (*)" #~ msgstr "Malkovich" #~ msgid "Unable to determine space free in \"%s\"." #~ msgstr "Malkovich" #~ msgid "free in \"%s\"" #~ msgstr "Malkovich" #~ msgid "Increment filename" #~ msgstr "Malkovich" #, fuzzy #~ msgid "After Save, add 1 to the last number in the file name" #~ msgstr "Malkovich" #~ msgid "Show thumbnails" #~ msgstr "Malkovich" #~ msgid "Show thumbnails for files in this directory" #~ msgstr "Malkovich" #~ msgid "Overwrite" #~ msgstr "Malkovich" #~ msgid "File \"%s\" exists. OK to overwrite?" #~ msgstr "Malkovich" #~ msgid "circular" #~ msgstr "Malkovich" #~ msgid "circular to label %d" #~ msgstr "Malkovich" #~ msgid "label %d" #~ msgstr "Malkovich" #~ msgid "unevaluated" #~ msgstr "Malkovich" #~ msgid "class (0x%x)" #~ msgstr "Malkovich" #~ msgid "members" #~ msgstr "Malkovich" #~ msgid "secret" #~ msgstr "Malkovich" #~ msgid "from" #~ msgstr "Malkovich" #~ msgid "NULL pointer" #~ msgstr "Malkovich" #~ msgid "symbol" #~ msgstr "Malkovich" #~ msgid "constructor" #~ msgstr "Malkovich" #~ msgid "symref" #~ msgstr "Malkovich" #~ msgid "compileref" #~ msgstr "Malkovich" #~ msgid "image \"%s\"" #~ msgstr "Malkovich" #~ msgid "tag \"%s\"" #~ msgstr "Malkovich" #~ msgid "unknown element tag %d" #~ msgstr "Malkovich" #~ msgid "Current:" #~ msgstr "Malkovich" #~ msgid "Directories" #~ msgstr "Malkovich" #~ msgid "Files" #~ msgstr "Malkovich" #~ msgid "Selection:" #~ msgstr "Malkovich" #~ msgid "Create Dir" #~ msgstr "Malkovich" #~ msgid "Delete File" #~ msgstr "Malkovich" #~ msgid "Rename File" #~ msgstr "Malkovich" #~ msgid "Error" #~ msgstr "Malkovich" #~ msgid "Close" #~ msgstr "Malkovich" #~ msgid "Create Directory" #~ msgstr "Malkovich" #~ msgid "Directory name:" #~ msgstr "Malkovich" #~ msgid "Create" #~ msgstr "Malkovich" #~ msgid "Cancel" #~ msgstr "Malkovich" #~ msgid "Delete" #~ msgstr "Malkovich" #~ msgid "Rename" #~ msgstr "Malkovich" #~ msgid "Directory unreadable: " #~ msgstr "Malkovich" #~ msgid "Current: " #~ msgstr "Malkovich" #~ msgid "Bad identifier." #~ msgstr "Malkovich" #~ msgid "" #~ "Enter an identifier. Identifiers start with\n" #~ "a letter, and then contain only letters, numbers,\n" #~ "apostrophy and underscore." #~ msgstr "Malkovich" #~ msgid "Bad floating point number." #~ msgstr "Malkovich" #~ msgid "\"%s\" is not a floating point number." #~ msgstr "Malkovich" #~ msgid "Bad integer." #~ msgstr "Malkovich" #~ msgid "\"%s\" is not an integer." #~ msgstr "Malkovich" #~ msgid "Bad unsigned integer." #~ msgstr "Malkovich" #~ msgid "Bad positive integer." #~ msgstr "Malkovich" #~ msgid "Left-click to change value" #~ msgstr "Malkovich" #~ msgid "Heap full." #~ msgstr "Malkovich" #~ msgid "" #~ "The main calculation heap has filled. Raise\n" #~ "the heap size limit in the Preferences panel." #~ msgstr "Malkovich" #~ msgid "Typecheck error." #~ msgstr "Malkovich" #~ msgid "" #~ "Expected %s, instead saw:\n" #~ " %s" #~ msgstr "Malkovich" #~ msgid "on" #~ msgstr "Malkovich" #, fuzzy #~ msgid "at %d" #~ msgstr "Malkovich" #~ msgid "at (%d, %d)" #~ msgstr "Malkovich" #~ msgid "at (%d, %d), offset (%d, %d)" #~ msgstr "Malkovich" #~ msgid "Pin up" #~ msgstr "Malkovich" #~ msgid "Check this to pin the dialog up" #~ msgstr "Malkovich" #~ msgid "Save Image \"%s\"" #~ msgstr "Malkovich" #~ msgid "Replace Image \"%s\"" #~ msgstr "Malkovich" #~ msgid "Double-click to open a viewer on this thumbnail" #~ msgstr "Malkovich" #~ msgid "Unable to open image \"%s\" for read." #~ msgstr "Malkovich" #~ msgid "Unable to write to file." #~ msgstr "Malkovich" #~ msgid "File \"%s\" is already open for read." #~ msgstr "Malkovich" #~ msgid "Error writing image to file \"%s\"." #~ msgstr "Malkovich" #~ msgid "Unable to paint on image." #~ msgstr "Malkovich" #~ msgid "" #~ "Unable to get write permission for file \"%s\".\n" #~ "Check permission settings." #~ msgstr "Malkovich" #~ msgid "Modify" #~ msgstr "Malkovich" #~ msgid "Modify disc file?" #~ msgstr "Malkovich" #~ msgid "" #~ "This image is being shown directly from the disc file:\n" #~ "\n" #~ " %s\n" #~ "\n" #~ "If you paint on this file, it will be permanently changed.\n" #~ "If something goes wrong, you may lose work.\n" #~ "Are you sure you want to modify this file?" #~ msgstr "Malkovich" #~ msgid "No image value" #~ msgstr "Malkovich" #~ msgid "%dx%d %s pixels, %d band, %s" #~ msgid_plural "%dx%d %s pixels, %d bands, %s" #~ msgstr[0] "Malkovich" #~ msgstr[1] "Malkovich" #~ msgid "Ruler menu" #~ msgstr "Malkovich" #~ msgid "Header for \"%s\"" #~ msgstr "Malkovich" #~ msgid "OK" #~ msgstr "Malkovich" #~ msgid "/_File" #~ msgstr "Malkovich" #~ msgid "/File/_New" #~ msgstr "Malkovich" #~ msgid "/File/New/_Point" #~ msgstr "Malkovich" #~ msgid "/File/New/_HGuide" #~ msgstr "Malkovich" #~ msgid "/File/New/_VGuide" #~ msgstr "Malkovich" #~ msgid "/File/New/_Arrow" #~ msgstr "Malkovich" #~ msgid "/File/New/_Region" #~ msgstr "Malkovich" #~ msgid "/File/sep3" #~ msgstr "Malkovich" #~ msgid "/File/_Replace Image ..." #~ msgstr "Malkovich" #~ msgid "/File/_Save Image As ..." #~ msgstr "Malkovich" #~ msgid "/File/sep1" #~ msgstr "Malkovich" #~ msgid "/File/Image _Header" #~ msgstr "Malkovich" #~ msgid "/File/Re_calculate Image" #~ msgstr "Malkovich" #~ msgid "/File/sep2" #~ msgstr "Malkovich" #~ msgid "/File/_Close" #~ msgstr "Malkovich" #~ msgid "/_View" #~ msgstr "Malkovich" #~ msgid "/View/_Toolbar" #~ msgstr "Malkovich" #~ msgid "/View/Toolbar/_Status" #~ msgstr "Malkovich" #~ msgid "/View/Toolbar/_Display control" #~ msgstr "Malkovich" #~ msgid "/View/Toolbar/_Paint" #~ msgstr "Malkovich" #~ msgid "/View/Toolbar/_Rulers" #~ msgstr "Malkovich" #~ msgid "/View/M_ode" #~ msgstr "Malkovich" #~ msgid "/View/Mode/_Select" #~ msgstr "Malkovich" #~ msgid "/View/Mode/_Pan" #~ msgstr "Malkovich" #~ msgid "/View/Mode/Zoom _In" #~ msgstr "Malkovich" #~ msgid "/View/Mode/Zoom _Out" #~ msgstr "Malkovich" #~ msgid "/View/Mode/P_aint" #~ msgstr "Malkovich" #~ msgid "/View/sep1" #~ msgstr "Malkovich" #~ msgid "/View/Zoom _In" #~ msgstr "Malkovich" #~ msgid "/View/Zoom _Out" #~ msgstr "Malkovich" #~ msgid "/View/Zoom _100%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom to _Fit" #~ msgstr "Malkovich" #~ msgid "/View/_Zoom" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/6%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/12%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/25%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/50%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/100%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/200%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/400%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/800%" #~ msgstr "Malkovich" #~ msgid "/View/Zoom/1600%" #~ msgstr "Malkovich" #~ msgid "/_Help" #~ msgstr "Malkovich" #~ msgid "/Help/_Image View" #~ msgstr "Malkovich" #~ msgid "/Help/_Paint Bar" #~ msgstr "Malkovich" #~ msgid "Left" #~ msgstr "Malkovich" #~ msgid "Top" #~ msgstr "Malkovich" #~ msgid "Width" #~ msgstr "Malkovich" #~ msgid "Height" #~ msgstr "Malkovich" #~ msgid "Left edge of region" #~ msgstr "Malkovich" #~ msgid "Top edge of region" #~ msgstr "Malkovich" #~ msgid "Width of region" #~ msgstr "Malkovich" #~ msgid "Height of region" #~ msgstr "Malkovich" #~ msgid "Edit \"%s\"" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Set Region" #~ msgstr "Malkovich" #~ msgid "at (%d, %d), size (%d, %d)" #~ msgstr "Malkovich" #~ msgid "%dx%d %s pixels, %d band" #~ msgid_plural "%dx%d %s pixels, %d bands" #~ msgstr[0] "Malkovich" #~ msgstr[1] "Malkovich" #~ msgid "scope \"%s\"" #~ msgstr "Malkovich" #~ msgid "reference to symbol \"%s\"" #~ msgstr "Malkovich" #~ msgid "" #~ "Press Escape to cancel edit, press Return to accept edit and recalculate" #~ msgstr "Malkovich" #~ msgid "" #~ "Value display\n" #~ "Left-click to edit expression" #~ msgstr "Malkovich" #~ msgid "line too long" #~ msgstr "Malkovich" #~ msgid "end of line inside string" #~ msgstr "Malkovich" #~ msgid "no end of string" #~ msgstr "Malkovich" #~ msgid "no end of comment!" #~ msgstr "Malkovich" #~ msgid "bad char constant" #~ msgstr "Malkovich" #~ msgid "illegal character \"%c\"" #~ msgstr "Malkovich" #~ msgid "Circular dependency." #~ msgstr "Malkovich" #~ msgid "Circular dependency detected near symbol \"%s\"." #~ msgstr "Malkovich" #~ msgid "" #~ "%s: usage:\n" #~ "%s filename1 filename2 ...\n" #~ "\tstart in GUI mode, loading the named files" #~ msgstr "Malkovich" #~ msgid "" #~ "%s -script filename arg1 arg2 ...\n" #~ "\tread in filename as a set of definitions, set list argv to\n" #~ "\t[\"filename\", \"arg1\", \"arg2\", ...], set argc to length of list;\n" #~ "\tprint the value of symbol \"main\" to stdout; exit; useful for\n" #~ "\trunning %s as an interpreter on unix" #~ msgstr "Malkovich" #~ msgid "" #~ "%s -main arg1 arg2 ...\n" #~ "\tas -script, but read the definitions from stdin rather than from a\n" #~ "\tfile; useful for here-is shell scripts" #~ msgstr "Malkovich" #~ msgid "" #~ "%s -workspace arg1 arg2 ...\n" #~ "\tas -main, but read a workspace save file instead; run in GUI mode\n" #~ "\tprint the value of the final row in the save file on exit" #~ msgstr "Malkovich" #~ msgid "" #~ "%s -benchmark\n" #~ "\tload all start objects and quit; useful for bechmarking the compiler" #~ msgstr "Malkovich" #~ msgid "symbol \"main\" not found" #~ msgstr "Malkovich" #~ msgid "symbol \"main\" has no value" #~ msgstr "Malkovich" #~ msgid "Unknown file type." #~ msgstr "Malkovich" #~ msgid "Unable to load \"%s\"." #~ msgstr "Malkovich" #~ msgid "Unable to load." #~ msgstr "Malkovich" #~ msgid "Error loading plug-in \"%s\"." #~ msgstr "Malkovich" #~ msgid "Error loading plug-ins in directory \"%s/lib\"" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Ink dropper" #~ msgstr "Malkovich" #~ msgid "Duplicate" #~ msgstr "Malkovich" #~ msgid "Pen" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Line" #~ msgstr "Malkovich" #~ msgid "Text" #~ msgstr "Malkovich" #~ msgid "Smudge" #~ msgstr "Malkovich" #~ msgid "Flood" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Flood Blob" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Fill Rectangle" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Pan" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Select" #~ msgstr "Malkovich" #~ msgid "" #~ "unable to change max file descriptors\n" #~ "max file descriptors still set to %d" #~ msgstr "Malkovich" #~ msgid "unable to read max file descriptors" #~ msgstr "Malkovich" #~ msgid "-script needs an argument" #~ msgstr "Malkovich" #~ msgid "Startup error." #~ msgstr "Malkovich" #~ msgid "" #~ "Startup error log:\n" #~ "%s" #~ msgstr "Malkovich" #~ msgid "Welcome to %s-%s!" #~ msgstr "Malkovich" #~ msgid "" #~ "A new directory has been created in your home directory to hold startup,\n" #~ "data and temporary files:\n" #~ "\n" #~ " %s\n" #~ "\n" #~ "If you've used previous versions of %s, you will probably want\n" #~ "to move any files over from your old work area and remove any old temps." #~ msgstr "Malkovich" #~ msgid "No temp area" #~ msgstr "Malkovich" #~ msgid "%s free" #~ msgstr "Malkovich" #~ msgid "%d cells free" #~ msgstr "Malkovich" #~ msgid "Selected:" #~ msgstr "Malkovich" #~ msgid "%s in \"%s\", %d cells in heap, %d cells free, %d cells maximum" #~ msgstr "Malkovich" #~ msgid "modified" #~ msgstr "Malkovich" #~ msgid "No objects selected." #~ msgstr "Malkovich" #~ msgid "Find in workspace not implemented yet." #~ msgstr "Malkovich" #~ msgid "Find again in workspace not implemented yet." #~ msgstr "Malkovich" #~ msgid "There are no errors (that I can see) in this workspace." #~ msgstr "Malkovich" #~ msgid "Recalculate" #~ msgstr "Malkovich" #~ msgid "Completely recalculate?" #~ msgstr "Malkovich" #~ msgid "Insert image" #~ msgstr "Malkovich" #~ msgid "Merge workspace" #~ msgstr "Malkovich" #, fuzzy #~ msgid "No recent workspaces" #~ msgstr "Malkovich" #~ msgid "Open workspace" #~ msgstr "Malkovich" #~ msgid "Caption" #~ msgstr "Malkovich" #~ msgid "Set workspace name here" #~ msgstr "Malkovich" #~ msgid "Set workspace caption here" #~ msgstr "Malkovich" #~ msgid "New Workspace" #~ msgstr "Malkovich" #~ msgid "Create Workspace" #~ msgstr "Malkovich" #~ msgid "Set column name here" #~ msgstr "Malkovich" #~ msgid "Set column caption here" #~ msgstr "Malkovich" #~ msgid "New Column" #~ msgstr "Malkovich" #~ msgid "Create Column" #~ msgstr "Malkovich" #~ msgid "Delete selected objects?" #~ msgstr "Malkovich" #~ msgid "Are you sure you want to delete %s?" #~ msgstr "Malkovich" #~ msgid "/File/_New ..." #~ msgstr "Malkovich" #~ msgid "/File/_Open ..." #~ msgstr "Malkovich" #, fuzzy #~ msgid "/File/Open _Recent" #~ msgstr "Malkovich" #~ msgid "/File/_Save" #~ msgstr "Malkovich" #~ msgid "/File/_Save As ..." #~ msgstr "Malkovich" #~ msgid "/File/_Program" #~ msgstr "Malkovich" #~ msgid "/File/Re_cover After Crash ..." #~ msgstr "Malkovich" #~ msgid "/_Edit" #~ msgstr "Malkovich" #~ msgid "/Edit/Delete" #~ msgstr "Malkovich" #~ msgid "/Edit/Select All" #~ msgstr "Malkovich" #~ msgid "/Edit/Duplicate" #~ msgstr "Malkovich" #~ msgid "/Edit/sep2" #~ msgstr "Malkovich" #~ msgid "/Edit/_Find" #~ msgstr "Malkovich" #~ msgid "/Edit/Find _Next" #~ msgstr "Malkovich" #~ msgid "/Edit/_Jump To Next Error" #~ msgstr "Malkovich" #~ msgid "/Edit/sep4" #~ msgstr "Malkovich" #~ msgid "/Edit/_Group" #~ msgstr "Malkovich" #~ msgid "/Edit/U_ngroup" #~ msgstr "Malkovich" #~ msgid "/Edit/_Recalculate" #~ msgstr "Malkovich" #~ msgid "/Edit/sep3" #~ msgstr "Malkovich" #~ msgid "/Edit/_Preferences" #~ msgstr "Malkovich" #~ msgid "/View/_Statusbar" #~ msgstr "Malkovich" #~ msgid "/View/_Regular" #~ msgstr "Malkovich" #~ msgid "/View/Show _Formula" #~ msgstr "Malkovich" #~ msgid "/View/No _Edits" #~ msgstr "Malkovich" #~ msgid "/_Insert" #~ msgstr "Malkovich" #~ msgid "/Insert/New C_olumn ..." #~ msgstr "Malkovich" #~ msgid "/Insert/sep6" #~ msgstr "Malkovich" #~ msgid "/Insert/Ima_ge From File ..." #~ msgstr "Malkovich" #~ msgid "/Insert/Workspace From File ..." #~ msgstr "Malkovich" #~ msgid "/Insert/Matrix From File ..." #~ msgstr "Malkovich" #~ msgid "/_Toolkits" #~ msgstr "Malkovich" #~ msgid "/Help/_About" #~ msgstr "Malkovich" #~ msgid "/Help/sep7" #~ msgstr "Malkovich" #~ msgid "/Help/_This Window" #~ msgstr "Malkovich" #~ msgid "/Help/_Users Guide" #~ msgstr "Malkovich" #~ msgid "/Help/_Quick Tour" #~ msgstr "Malkovich" #~ msgid "/Help/_Mosaic Tour" #~ msgstr "Malkovich" #~ msgid "/Help/_Nerd Tour" #~ msgstr "Malkovich" #~ msgid "/Help/M_enu Reference" #~ msgstr "Malkovich" #~ msgid "/Help/_Configuration" #~ msgstr "Malkovich" #~ msgid "/Help/sep6" #~ msgstr "Malkovich" #~ msgid "/Help/_Go to VIPS Home Page" #~ msgstr "Malkovich" #~ msgid "Open Workspace" #~ msgstr "Malkovich" #~ msgid "Save Workspace As" #~ msgstr "Malkovich" #~ msgid "Duplicate Workspace" #~ msgstr "Malkovich" #~ msgid "Duplicate Selected Rows" #~ msgstr "Malkovich" #~ msgid "Insert File" #~ msgstr "Malkovich" #~ msgid "Sliders" #~ msgstr "Malkovich" #~ msgid "Toggle buttons" #~ msgstr "Malkovich" #~ msgid "Text, plus scale and offset" #~ msgstr "Malkovich" #~ msgid "Display as" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Edit matrix \"%s\"" #~ msgstr "Malkovich" #~ msgid "Set matrix" #~ msgstr "Malkovich" #~ msgid "Save Matrix \"%s\"" #~ msgstr "Malkovich" #~ msgid "Replace Matrix \"%s\"" #~ msgstr "Malkovich" #~ msgid "" #~ "Cell (%d, %d):\n" #~ "%s" #~ msgstr "Malkovich" #~ msgid ": cell (%d, %d): %s" #~ msgstr "Malkovich" #~ msgid "" #~ "Unable to load from file \"%s\".\n" #~ "Error log is:\n" #~ "%s" #~ msgstr "Malkovich" #~ msgid "" #~ "Unable to load from \"%s\".\n" #~ "Error log is:\n" #~ "%s" #~ msgstr "Malkovich" #~ msgid "model_save: xmlNewChild() failed" #~ msgstr "Malkovich" #~ msgid "XML load error." #~ msgstr "Malkovich" #~ msgid "Can't load node of type \"%s\" into object of type \"%s\"" #~ msgstr "Malkovich" #~ msgid "Delete?" #~ msgstr "Malkovich" #~ msgid "Are you sure you want to delete %s \"%s\"?" #~ msgstr "Malkovich" #~ msgid "No options." #~ msgstr "Malkovich" #~ msgid "You need at least one option in your option list" #~ msgstr "Malkovich" #~ msgid "Set option caption here" #~ msgstr "Malkovich" #~ msgid "Options" #~ msgstr "Malkovich" #~ msgid "Value" #~ msgstr "Malkovich" #~ msgid "Set option default value here" #~ msgstr "Malkovich" #~ msgid "Edit option" #~ msgstr "Malkovich" #~ msgid "Set option" #~ msgstr "Malkovich" #~ msgid "Orderlist menu" #~ msgstr "Malkovich" #~ msgid "Delete item" #~ msgstr "Malkovich" #~ msgid "Delete selected items" #~ msgstr "Malkovich" #~ msgid "Delete all items" #~ msgstr "Malkovich" #~ msgid "Current options - right button for menu" #~ msgstr "Malkovich" #~ msgid "Enter new option fields here" #~ msgstr "Malkovich" #~ msgid "Paintbox bar menu" #~ msgstr "Malkovich" #~ msgid "Font not found." #~ msgstr "Malkovich" #~ msgid "Font \"%s\" not found on system." #~ msgstr "Malkovich" #~ msgid "Select font" #~ msgstr "Malkovich" #~ msgid "Set font" #~ msgstr "Malkovich" #~ msgid "Clear undo history?" #~ msgstr "Malkovich" #~ msgid "" #~ "Are you sure you want to clear all undo and redo?\n" #~ "This will free up memory, but you will no longer be\n" #~ "able to undo or redo any of the painting you have\n" #~ "done so far." #~ msgstr "Malkovich" #~ msgid "1 round" #~ msgstr "Malkovich" #~ msgid "2 round" #~ msgstr "Malkovich" #~ msgid "3 round" #~ msgstr "Malkovich" #~ msgid "4 round" #~ msgstr "Malkovich" #~ msgid "5 round" #~ msgstr "Malkovich" #~ msgid "6 round" #~ msgstr "Malkovich" #~ msgid "10 round" #~ msgstr "Malkovich" #~ msgid "2 italic" #~ msgstr "Malkovich" #~ msgid "3 italic" #~ msgstr "Malkovich" #~ msgid "4 italic" #~ msgstr "Malkovich" #~ msgid "5 italic" #~ msgstr "Malkovich" #~ msgid "6 italic" #~ msgstr "Malkovich" #~ msgid "10 italic" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Pan window" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Zoom out" #~ msgstr "Malkovich" #~ msgid "Undo last paint action" #~ msgstr "Malkovich" #~ msgid "Redo last paint action" #~ msgstr "Malkovich" #~ msgid "Clear all undo and redo buffers" #~ msgstr "Malkovich" #~ msgid "Nib" #~ msgstr "Malkovich" #~ msgid "Click to select font" #~ msgstr "Malkovich" #~ msgid "Enter text for text tool" #~ msgstr "Malkovich" #~ msgid "Error in %s: %s" #~ msgstr "Malkovich" #~ msgid "definition is too long!" #~ msgstr "Malkovich" #~ msgid "not top level" #~ msgstr "Malkovich" #~ msgid "not strings" #~ msgstr "Malkovich" #~ msgid "Not found." #~ msgstr "Malkovich" #~ msgid "File \"%s\" not found on path" #~ msgstr "Malkovich" #~ msgid "Revert to Defaults" #~ msgstr "Malkovich" #~ msgid "Revert to installation defaults?" #~ msgstr "Malkovich" #~ msgid "" #~ "Would you like to reset all preferences to their factory\n" #~ "settings? This will delete any changes you have ever made\n" #~ "to your preferences and may take a few seconds." #~ msgstr "Malkovich" #~ msgid "Preferences" #~ msgstr "Malkovich" #~ msgid "Unable to display preferences." #~ msgstr "Malkovich" #~ msgid "" #~ "No preferences workspace was found.\n" #~ "Preferences probably failed to load when %s started." #~ msgstr "Malkovich" #~ msgid "Program" #~ msgstr "Malkovich" #~ msgid "Edit window" #~ msgstr "Malkovich" #~ msgid "Menu item text" #~ msgstr "Malkovich" #~ msgid "Load column from this file" #~ msgstr "Malkovich" #~ msgid "Edit column item \"%s\"" #~ msgstr "Malkovich" #~ msgid "Set column item" #~ msgstr "Malkovich" #~ msgid "Unable to save." #~ msgstr "Malkovich" #~ msgid "You can only save toolkits, not tools." #~ msgstr "Malkovich" #~ msgid "You can't save auto-generated toolkits." #~ msgstr "Malkovich" #~ msgid "Toolkit tree menu" #~ msgstr "Malkovich" #~ msgid "Edit ..." #~ msgstr "Malkovich" #~ msgid "Tool changed." #~ msgstr "Malkovich" #~ msgid "" #~ "Tool changed by someone else!\n" #~ "You're going to loose edits unless you're careful." #~ msgstr "Malkovich" #~ msgid "Bad drag." #~ msgstr "Malkovich" #~ msgid "" #~ "Sorry, you can only drag tools between toolkits\n" #~ "You can't reorder toolkits, you can't nest toolkits\n" #~ "and you can't drag tools to the top level." #~ msgstr "Malkovich" #~ msgid "Sorry, you can't drag to or from from pseudo toolkits." #~ msgstr "Malkovich" #~ msgid "Set toolkit name here" #~ msgstr "Malkovich" #~ msgid "Set toolkit caption here" #~ msgstr "Malkovich" #~ msgid "New toolkit" #~ msgstr "Malkovich" #~ msgid "Nothing selected." #~ msgstr "Malkovich" #~ msgid "No toolkit selected." #~ msgstr "Malkovich" #~ msgid "Display this name" #~ msgstr "Malkovich" #~ msgid "Load definition" #~ msgstr "Malkovich" #~ msgid "Reload" #~ msgstr "Malkovich" #~ msgid "Reload startup objects?" #~ msgstr "Malkovich" #~ msgid "" #~ "Would you like to reload all startup menus, workspaces\n" #~ "and plugins now? This may take a few seconds." #~ msgstr "Malkovich" #~ msgid "No tool selected" #~ msgstr "Malkovich" #~ msgid "Bad regular expression." #~ msgstr "Malkovich" #, fuzzy #~ msgid "No match found for \"%s\"." #~ msgstr "Malkovich" #~ msgid "Find in all toolkits" #~ msgstr "Malkovich" #~ msgid "Enter search string here" #~ msgstr "Malkovich" #~ msgid "No match found." #~ msgstr "Malkovich" #~ msgid "No top-level symbol called \"%s\"." #~ msgstr "Malkovich" #~ msgid "Symbol \"%s\" has no tool inforation." #~ msgstr "Malkovich" #~ msgid "Go to definition of this symbol" #~ msgstr "Malkovich" #~ msgid "Go to definition" #~ msgstr "Malkovich" #~ msgid "Object information." #~ msgstr "Malkovich" #~ msgid "No unresolved symbols found." #~ msgstr "Malkovich" #~ msgid "Link report." #~ msgstr "Malkovich" #~ msgid "No documentation available." #~ msgstr "Malkovich" #~ msgid "" #~ "On-line documentation is only currently\n" #~ "available for VIPS functions and nip builtins." #~ msgstr "Malkovich" #~ msgid "/File/New/_Tool" #~ msgstr "Malkovich" #~ msgid "/File/New/Tool_kit ..." #~ msgstr "Malkovich" #~ msgid "/File/New/Separator ..." #~ msgstr "Malkovich" #~ msgid "/File/New/Column Item ..." #~ msgstr "Malkovich" #~ msgid "/File/New/Program Window ..." #~ msgstr "Malkovich" #~ msgid "/File/_Open Toolkit ..." #~ msgstr "Malkovich" #~ msgid "/File/_Save Toolkit" #~ msgstr "Malkovich" #~ msgid "/File/Save Toolkit _As ..." #~ msgstr "Malkovich" #~ msgid "/File/Pr_ocess Text ..." #~ msgstr "Malkovich" #~ msgid "/File/_Reload Start Stuff ..." #~ msgstr "Malkovich" #~ msgid "/Edit/C_ut" #~ msgstr "Malkovich" #~ msgid "/Edit/_Copy" #~ msgstr "Malkovich" #~ msgid "/Edit/_Paste" #~ msgstr "Malkovich" #~ msgid "/Edit/_Select All" #~ msgstr "Malkovich" #~ msgid "/Edit/Delete This _Tool ..." #~ msgstr "Malkovich" #~ msgid "/Edit/Delete This Tool_kit ..." #~ msgstr "Malkovich" #~ msgid "/Edit/_Find ..." #~ msgstr "Malkovich" #~ msgid "/Edit/_Jump to Definition of ..." #~ msgstr "Malkovich" #~ msgid "/Edit/_Info ..." #~ msgstr "Malkovich" #~ msgid "/_Debug" #~ msgstr "Malkovich" #~ msgid "/Debug/_Trace ..." #~ msgstr "Malkovich" #~ msgid "/Debug/_Link ..." #~ msgstr "Malkovich" #~ msgid "/Help/_Program ..." #~ msgstr "Malkovich" #~ msgid "/Help/_Documentation For This Tool ..." #~ msgstr "Malkovich" #~ msgid "Overflow error." #~ msgstr "Malkovich" #~ msgid "%s too long." #~ msgstr "Malkovich" #~ msgid "Not rectangular." #~ msgstr "Malkovich" #~ msgid "" #~ "Matrix of real is not rectangular.\n" #~ "Found row of length %d, should be %d." #~ msgstr "Malkovich" #~ msgid "List only has %d elements, unable to get element %d." #~ msgstr "Malkovich" #~ msgid "No arguments allowed." #~ msgstr "Malkovich" #~ msgid "Object \"%s\" should have no arguments." #~ msgstr "Malkovich" #~ msgid "C stack overflow. Expression too complex." #~ msgstr "Malkovich" #~ msgid "No value." #~ msgstr "Malkovich" #~ msgid "Symbol \"%s\" has no value" #~ msgstr "Malkovich" #~ msgid "Symbol \"%s\" is not defined." #~ msgstr "Malkovich" #~ msgid "Can't duplicate." #~ msgstr "Malkovich" #~ msgid "You can only duplicate top level regions." #~ msgstr "Malkovich" #~ msgid "Can't delete." #~ msgstr "Malkovich" #~ msgid "You can only delete top level regions." #~ msgstr "Malkovich" #~ msgid "Delete Region?" #~ msgstr "Malkovich" #~ msgid "Are you sure you want to delete Region \"%s\"?" #~ msgstr "Malkovich" #~ msgid "Region menu" #~ msgstr "Malkovich" #~ msgid "blocked on" #~ msgstr "Malkovich" #~ msgid "" #~ "Left-click to select, shift-left-click to extend select, double-left-" #~ "click to edit, right-click for menu, left-drag to move" #~ msgstr "Malkovich" #~ msgid "You can only duplicate top level rows." #~ msgstr "Malkovich" #~ msgid "You can only delete top level rows." #~ msgstr "Malkovich" #~ msgid "Drag between columns not yet implemented." #~ msgstr "Malkovich" #~ msgid "Row menu" #~ msgstr "Malkovich" #~ msgid "Ungroup" #~ msgstr "Malkovich" #~ msgid "Replace from file ..." #~ msgstr "Malkovich" #~ msgid "Click to open or close class" #~ msgstr "Malkovich" #~ msgid "Minimum" #~ msgstr "Malkovich" #~ msgid "Maximum" #~ msgstr "Malkovich" #~ msgid "Lower slider value" #~ msgstr "Malkovich" #~ msgid "Upper slider value" #~ msgstr "Malkovich" #~ msgid "Set slider value here" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Edit slider \"%s\"" #~ msgstr "Malkovich" #, fuzzy #~ msgid "Set Slider" #~ msgstr "Malkovich" #~ msgid "Status bar menu" #~ msgstr "Malkovich" #~ msgid "Magnification" #~ msgstr "Malkovich" #~ msgid "Attempt to redefine root symbol \"%s\"." #~ msgstr "Malkovich" #~ msgid "Name \"%s\" repeated in scope." #~ msgstr "Malkovich" #~ msgid "Can't redefine %s \"%s\"." #~ msgstr "Malkovich" #~ msgid "Set toggle caption here" #~ msgstr "Malkovich" #~ msgid "State" #~ msgstr "Malkovich" #~ msgid "Set toggle state here" #~ msgstr "Malkovich" #~ msgid "Edit toggle" #~ msgstr "Malkovich" #~ msgid "Set toggle" #~ msgstr "Malkovich" #~ msgid "" #~ "Can't create dialog with name \"%s\"\n" #~ "an object with that name already exists in kit \"%s\"" #~ msgstr "Malkovich" #~ msgid "tool \"%s\", toolkit \"%s\", refers to undefined symbol" #~ msgstr "Malkovich" #~ msgid "Trace buffer stack overflow." #~ msgstr "Malkovich" #~ msgid "/File/_Clear" #~ msgstr "Malkovich" #~ msgid "/View/Operators" #~ msgstr "Malkovich" #~ msgid "/View/Builtin Functions" #~ msgstr "Malkovich" #~ msgid "/View/Class Construction" #~ msgstr "Malkovich" #~ msgid "/Help/_Trace ..." #~ msgstr "Malkovich" #~ msgid "Trace" #~ msgstr "Malkovich" #~ msgid "Slider value ... edit!" #~ msgstr "Malkovich" #~ msgid "Left-drag to set number" #~ msgstr "Malkovich" #~ msgid "VIPS library error." #~ msgstr "Malkovich" #~ msgid "Unable to set XML property." #~ msgstr "Malkovich" #~ msgid "Unable to set property \"%s\" to value \"%s\"." #~ msgstr "Malkovich" #~ msgid "8-bit signed integer" #~ msgstr "Malkovich" #~ msgid "16-bit unsigned integer" #~ msgstr "Malkovich" #~ msgid "16-bit signed integer" #~ msgstr "Malkovich" #~ msgid "32-bit unsigned integer" #~ msgstr "Malkovich" #~ msgid "32-bit signed integer" #~ msgstr "Malkovich" #~ msgid "32-bit float" #~ msgstr "Malkovich" #~ msgid "64-bit float" #~ msgstr "Malkovich" #~ msgid "128-bit complex" #~ msgstr "Malkovich" #~ msgid "" #~ msgstr "Malkovich" #~ msgid "TIFF image" #~ msgstr "Malkovich" #~ msgid "JPEG image" #~ msgstr "Malkovich" #~ msgid "PNG image" #~ msgstr "Malkovich" #~ msgid "PPM/PGM/PBM image" #~ msgstr "Malkovich" #~ msgid "VIPS image" #~ msgstr "Malkovich" #~ msgid "%s, %s, %s, %dx%d, %d band" #~ msgid_plural "%s, %s, %s, %dx%d, %d bands" #~ msgstr[0] "Malkovich" #~ msgstr[1] "Malkovich" #~ msgid "Bad filename." #~ msgstr "Malkovich" #~ msgid "Filenames may not contain ':' characters." #~ msgstr "Malkovich" #~ msgid "Filename is too long." #~ msgstr "Malkovich" #~ msgid "Filename contains only blank characters." #~ msgstr "Malkovich" #~ msgid "Unable to open." #~ msgstr "Malkovich" #~ msgid "" #~ "Unable to open file \"%s\" for writing.\n" #~ "%s." #~ msgstr "Malkovich" #~ msgid "Unable to write." #~ msgstr "Malkovich" #~ msgid "" #~ "Unable to write to file \"%s\".\n" #~ "%s." #~ msgstr "Malkovich" #~ msgid "bytes" #~ msgstr "Malkovich" #~ msgid "KB" #~ msgstr "Malkovich" #~ msgid "MB" #~ msgstr "Malkovich" #~ msgid "GB" #~ msgstr "Malkovich" #~ msgid "TB" #~ msgstr "Malkovich" #~ msgid "" #~ "unable to make temporary file \"%s\"\n" #~ "%s" #~ msgstr "Malkovich" #~ msgid "Out of memory." #~ msgstr "Malkovich" #~ msgid "" #~ "Request for %s of RAM triggered memory allocation\n" #~ "failure." #~ msgstr "Malkovich" #~ msgid "Unknown type." #~ msgstr "Malkovich" #~ msgid "VIPS type \"%s\" not supported" #~ msgstr "Malkovich" #~ msgid "Error calling library function \"%s\" (%s)." #~ msgstr "Malkovich" #~ msgid "VIPS operator \"%s\"" #~ msgstr "Malkovich" #~ msgid "%s, from package \"%s\"" #~ msgstr "Malkovich" #~ msgid "\"%s\" takes %d argument:" #~ msgid_plural "\"%s\" takes %d arguments:" #~ msgstr[0] "Malkovich" #~ msgstr[1] "Malkovich" #~ msgid "And produces %d result:" #~ msgid_plural "And produces %d results" #~ msgstr[0] "Malkovich" #~ msgstr[1] "Malkovich" #~ msgid "flags:" #~ msgstr "Malkovich" #~ msgid "PIO function" #~ msgstr "Malkovich" #~ msgid "WIO function" #~ msgstr "Malkovich" #~ msgid "coordinate transformer" #~ msgstr "Malkovich" #~ msgid "no coordinate transformation" #~ msgstr "Malkovich" #~ msgid "point-to-point operation" #~ msgstr "Malkovich" #~ msgid "area operation" #~ msgstr "Malkovich" #~ msgid "" #~ "Argument %d to \"%s\" is the wrong type.\n" #~ "You passed:\n" #~ " %s\n" #~ "Usage:\n" #~ " %s" #~ msgstr "Malkovich" #~ msgid "doublevec" #~ msgstr "Malkovich" #~ msgid "imagevec" #~ msgstr "Malkovich" #~ msgid "Bad regular expression \"%s\"." #~ msgstr "Malkovich" #~ msgid "Select exactly one object and try again." #~ msgstr "Malkovich" #~ msgid "More than one object selected." #~ msgstr "Malkovich" #~ msgid "No backup workspaces found." #~ msgstr "Malkovich" #~ msgid "" #~ "You need to enable \"Auto workspace save\" in Preferences\n" #~ "Before automatic recovery works" #~ msgstr "Malkovich" #~ msgid "No suitable workspace save files found in \"%s\"" #~ msgstr "Malkovich" #~ msgid "Open workspace backup?" #~ msgstr "Malkovich" #~ msgid "" #~ "Found workspace \"%s\",\n" #~ "dated %sDo you want to recover this workspace?" #~ msgstr "Malkovich" #~ msgid "" #~ "Can't create workspace \"%s\".\n" #~ "A symbol with that name already exists." #~ msgstr "Malkovich" #~ msgid "Default empty workspace" #~ msgstr "Malkovich" #~ msgid "\"%s\" needs %d arguments, there are %d selected." #~ msgstr "Malkovich" #~ msgid "Too many names selected." #~ msgstr "Malkovich" #~ msgid "You can only remove top level rows." #~ msgstr "Malkovich" #~ msgid "Not all selected objects are top level rows." #~ msgstr "Malkovich" #~ msgid "Unable to ungroup." #~ msgstr "Malkovich" #~ msgid "" #~ "You can only ungroup lists (comma-separated lists of things enclosed in " #~ "square brackets).\n" #~ "Use Format=>Decompose to break compound objects into lists." #~ msgstr "Malkovich" #~ msgid "" #~ "Can't create workspacegroup \"%s\".\n" #~ "A symbol with that name already exists." #~ msgstr "Malkovich" #~ msgid "No text specified." #~ msgstr "Malkovich" #~ msgid "" #~ "Enter some text to paint in the entry widget at the top of the window." #~ msgstr "Malkovich" #~ msgid "Edit regions (+CTRL to create)" #~ msgstr "Malkovich" #~ msgid "Pan image (also use middle mouse button)" #~ msgstr "Malkovich" #~ msgid "Zoom in (also 'i' key)" #~ msgstr "Malkovich" #~ msgid "Zoom out (also 'o' key)" #~ msgstr "Malkovich" #~ msgid "Ink:" #~ msgstr "Malkovich" #~ msgid "Find" #~ msgstr "Malkovich" #~ msgid "at %1$d" #~ msgstr "Malkovich" #~ msgid "Tool" #~ msgstr "Malkovich" #~ msgid "Range" #~ msgstr "Malkovich" libvips-8.18.2/po/meson.build000066400000000000000000000000431516303661500160450ustar00rootroot00000000000000i18n.gettext( gettext_domain ) libvips-8.18.2/suppressions/000077500000000000000000000000001516303661500160455ustar00rootroot00000000000000libvips-8.18.2/suppressions/asan.supp000066400000000000000000000000531516303661500176760ustar00rootroot00000000000000interceptor_via_lib:libMagickCore-6.Q16.so libvips-8.18.2/suppressions/lsan.supp000066400000000000000000000012041516303661500177100ustar00rootroot00000000000000# Likely false positives leak:PyMem_Malloc leak:PyObject_Malloc # Known leaks in Fontconfig, most likely false positives due to # missing instrumentation (i.e. it's build without ASan/LSan). leak:FcConfigSubstituteWithPat leak:FcDefaultSubstitute leak:FcFontSetList leak:FcFontSetMatch leak:FcInit leak:FcPatternBuild leak:FcValueSave # Freed on exit, see: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36298#c1 leak:GOMP_parallel leak:___kmp_allocate # Fixed in libheif >= v1.18.0, see: # https://github.com/strukturag/libheif/pull/1061 # TODO: Does this requires calling heif_deinit()? leak:x265::x265_malloc leak:x265_12bit::x265_malloc libvips-8.18.2/suppressions/tsan.supp000066400000000000000000000200121516303661500177160ustar00rootroot00000000000000## The suppressions below match only the top frame of report stacks # dispose() may run multiple times, but always serially, so non-racy race_top:vips_*_dispose # using thread-local regions in generate functions is fine race_top:vips_*_gen # these helpers are used by the above generate functions race_top:make_firstlast race_top:reduce_sum race_top:vips_combine_pixels3 race_top:vips_composite_base_select race_top:vips_convi_uchar_hwy race_top:vips_embed_base_find_edge race_top:vips_embed_base_paint_edge race_top:vips_rect_includesrect race_top:vips_rect_intersectrect race_top:vips_reduceh_uchar_hwy race_top:vips_reducev_uchar_hwy race_top:vips_region_paint_pel race_top:vips__transform_invert_point # unlocked access to image/region fields, which is fine race_top:buffer_move race_top:vips_buffer_unref_ref race_top:vips_image_decode_predict race_top:vips_image_iskilled race_top:vips_region_buffer race_top:vips_region_copy race_top:vips_region_image race_top:vips_region_prepare race_top:vips__image_copy_fields_array race_top:vips__region_check_ownership # unlocked access/assignment to ->read_position, which is fine race_top:vips_source_read race_top:vips_source_seek # an unlocked FALSE/TRUE assignment, which is fine race_top:vips_image_set_kill race_top:vips_object_set_property race_top:vips_region_region race_top:vips_source_decode race_top:vips_source_rewind race_top:vips__demand_hint_array # an unlocked NULL assignment, which is fine race_top:vips_image_pio_input race_top:vips_image_wio_input # an unlocked singleton init of ->argument_table, which is fine race_top:vips_argument_init # an unlocked increment of ->local_memory, which is fine race_top:vips_malloc # buffers are thread-local (held in a GPrivate), so non-racy race_top:vips_buffer_free race_top:vips_buffer_undone # local static variables ought to be non-racy race_top:vips_getpagesize race_top:vips_get_disc_threshold # callers are expected to call this once during startup, so non-racy race_top:vips_cache_set_max race_top:vips_cache_set_max_files race_top:vips_cache_set_max_mem race_top:vips_concurrency_set race_top:vips_vector_set_enabled # guarded with vips_tracked_mutex, so it should be fine race_top:vips_tracked_aligned_alloc race_top:vips_tracked_aligned_free race_top:vips_tracked_close race_top:vips_tracked_get_files race_top:vips_tracked_get_mem race_top:vips_tracked_malloc race_top:vips_tracked_open # guarded with vips__meta_lock, so it should be fine race_top:meta_init race_top:meta_new # guarded with g_async_queue_lock(), so it should be fine race_top:vips_threadset_add_thread race_top:vips_threadset_reuse_wait # task is popped from the queue locked, then executed and freed # unlocked, which is fine race_top:vips_threadset_work # guarded with vips__global_lock, so it should be fine race_top:vips_area_new race_top:vips_buf_all race_top:vips_buf_rewind race_top:vips_buf_vappendf race_top:vips_error_freeze race_top:vips_image_sanity race_top:vips__link_make race_top:vips__link_map race_top:vips__region_count_pixels # guarded with vips_cache_lock, so it should be fine race_top:vips_cache_drop_all race_top:vips_cache_get_lru race_top:vips_cache_insert race_top:vips_cache_trim race_top:vips_entry_ref race_top:vips_entry_touch race_top:vips_object_ref_arg race_top:vips_operation_equal race_top:vips_operation_hash # use of pool->stop is unlocked, but fine race_top:vips_thread_main_loop # quarks (i.e. GQuark) are likely non-racy race_top:vips_reorder_free race_top:vips_reorder_prepare_many race_top:vips__reorder_set_input # attaching/updating the time struct of an image is likely safe race_top:vips_progress_add race_top:vips_progress_update # semaphores are likely non-racy race_top:vips_*semaphore_* # pool->exit is atomically updated, so it should be fine race_top:vips_worker_work_unit # guarded with area->lock, so it should be fine race_top:vips_area_copy race_top:vips_area_free race_top:vips_area_unref # guarded with cache->lock, so it should be fine race_top:vips_rect_equal race_top:vips_rect_hash race_top:vips_tile_cache_ref race_top:vips_tile_find race_top:vips_tile_new race_top:vips_tile_ref race_top:vips_tile_search race_top:vips_tile_unref # guarded with pool->allocate_lock, so it should be fine race_top:direct_strip_allocate race_top:image_strip_allocate race_top:sink_area_allocate_fn race_top:sink_area_position race_top:sink_memory_area_allocate_fn race_top:sink_memory_area_position race_top:vips_maplut_stop race_top:vips_worker_allocate race_top:wbuffer_allocate_fn race_top:wtiff_layer_row_allocate # thread-local state work functions are non-racy race_top:sink_memory_area_work_fn race_top:sink_work race_top:wbuffer_work_fn # guarded with image->sslock, so it should be fine race_top:rtiff_seq_start race_top:vips_arithmetic_start race_top:vips_bandary_start race_top:vips_composite_start race_top:vips_convasep_start race_top:vips_convf_start race_top:vips_convi_start race_top:vips_foreign_load_start race_top:vips_foreign_load_temp race_top:vips_hist_local_start race_top:vips_morph_start race_top:vips_rank_start race_top:vips_region_build race_top:vips_region_dispose race_top:vips_shrinkv_start race_top:vips_start_many race_top:vips_window_find race_top:vips_window_fits race_top:vips_window_new race_top:vips_window_set race_top:vips_window_take race_top:vips_window_unref race_top:vips__region_start race_top:vips__region_stop race_top:vips__start_merge ## The suppressions below match all frames of report stacks # foreign generate functions ought to be non-racy race:direct_strip_work race:image_strip_work race:png2vips_generate race:rad2vips_generate race:read_jpeg_generate race:read_webp_generate race:rtiff_fill_region race:rtiff_stripwise_generate race:vips_fits_generate race:vips_foreign_load_heif_generate race:vips_foreign_load_jp2k_generate_tiled race:vips_foreign_load_jp2k_generate_untiled race:vips_foreign_load_jxl_generate race:vips_foreign_load_magick7_fill_region race:vips_foreign_load_magick_fill_region race:vips_foreign_load_nsgif_generate race:vips_foreign_load_pdf_generate race:vips_foreign_load_png_generate race:vips_foreign_load_ppm_generate_1bit_ascii race:vips_foreign_load_ppm_generate_1bit_binary race:vips_foreign_load_ppm_generate_ascii_int race:vips_foreign_load_ppm_generate_binary race:vips_foreign_load_svg_generate race:vips__openexr_generate race:vips__openslide_generate race:wtiff_layer_row_work # TSan may produce false positives for callbacks invoked from # non-instrumented code. Such callbacks should be listed below. race:readjpeg_emit_message race:source_fill_input_buffer race:source_fill_input_buffer_mappable race:vips_foreign_load_heif_read race:vips_foreign_load_heif_wait_for_file_size race:vips_foreign_load_jp2k_read_source race:vips_foreign_load_jp2k_seek_source race:vips_foreign_load_jp2k_skip_source race:vips_foreign_load_png_stream race:vips_png_read_source # g_object_get*() is uninstrumented, but likely non-racy race:g_object_get race:g_object_get_property race:g_object_get_valist # using thread-local regions in generate functions is fine # this also catches all ->correlation, ->point, ->process_line and # ->scan subclass functions race:vips_arithmetic_gen race:vips_bandary_gen race:vips_colour_gen race:vips_correlation_gen race:vips_statistic_scan race:vips_point_gen race:vips_sdf_gen # guarded with vips__minimise_lock, so it should be fine race:vips_image_minimise_all # guarded with vips_cache_lock, so it should be fine race:vips_cache_free_cb # finalize() is only called once by a single thread, so non-racy race:vips_image_finalize # only called optionally when the whole program is done, so non-racy race:vips_shutdown # same as `race_top:vips_*_dispose` above, but matched against all # frames of report stacks race:vips_image_dispose race:vips_operation_dispose # thread-local state allocate/dispose functions ought to be non-racy race:sink_memory_thread_state_new race:sink_thread_state_dispose race:vips_sink_thread_state_new race:write_thread_state_new # the double-buffered output and write-behind threads are non-racy race:wbuffer_flush race:wbuffer_new race:wbuffer_position race:wbuffer_write race:write_free libvips-8.18.2/suppressions/ubsan.supp000066400000000000000000000001031516303661500200600ustar00rootroot00000000000000# https://github.com/libexif/libexif/pull/147 undefined:libexif.so libvips-8.18.2/suppressions/valgrind.supp000066400000000000000000000164441516303661500205750ustar00rootroot00000000000000# hide GObject type init allocs, they can only happen once and are not really # leaks { type_init Memcheck:Leak fun:*alloc ... fun:g_type_register_* } { type_init2 Memcheck:Leak fun:*alloc ... fun:g_type_init_* } { type_init3 Memcheck:Leak fun:*alloc ... fun:g_type_create_* } { type_init4 Memcheck:Leak fun:*alloc ... fun:g_type_class_ref } { type_init5 Memcheck:Leak fun:*alloc ... fun:g_type_add_interface_static } # module init does this { init7 Memcheck:Leak ... fun:*alloc* ... fun:_dl_init } # g_get_home_dir has a private buffer { gwd Memcheck:Leak fun:*alloc ... fun:g_get_home_dir } # selinux on ubuntu generates a leak report we ignore { selinux Memcheck:Leak fun:*alloc ... obj:/lib/libselinux.so.1 } # gdk and x init { gdk_init Memcheck:Leak fun:*alloc ... fun:gdk_display_open } { x_init_ext Memcheck:Leak fun:*alloc ... fun:XInitExtension } { gio Memcheck:Leak fun:malloc ... fun:g_simple_async_result_complete } { pthread Memcheck:Leak fun:calloc ... fun:_dl_allocate_tls ... fun:pthread_create@@GLIBC_* } # hide all dbus reports, not the app's problem { dbus Memcheck:Leak fun:*alloc ... obj:*/libdbus-1.so.* } # hide all orbit leaks, not our problem { orbit Memcheck:Leak fun:*alloc ... fun:ORBit_* } # other lib init { fontconfig_init Memcheck:Leak fun:*alloc ... fun:FcConfigParseAndLoad } { fontconfig2 Memcheck:Leak fun:malloc fun:strdup fun:FcValueSave obj:*/libfontconfig.so.* } { fontconfig3 Memcheck:Leak fun:realloc ... fun:FcFontMatch } { fontconfig4 Memcheck:Leak fun:realloc ... fun:FcPatternAddInteger } { fontconfig5 Memcheck:Leak fun:realloc ... fun:FcPatternDuplicate } { fontconfig6 Memcheck:Leak fun:realloc ... fun:FcDefaultSubstitute } { fontconfg7 Memcheck:Leak ... fun:FcFontRenderPrepare } { fontconfg8 Memcheck:Leak ... fun:FcInit } { freetype_init Memcheck:Leak fun:*alloc ... fun:FT_Open_Face } { harfbuzz Memcheck:Leak fun:calloc ... fun:hb_shape_plan_execute } { goffice_init Memcheck:Leak fun:*alloc ... fun:libgoffice_init } { g_module_init Memcheck:Leak fun:*alloc ... fun:g_module_open } { gtk_module_init Memcheck:Leak fun:*alloc ... fun:gtk_module_init } # libheif init has some static data { heif_init Memcheck:Leak ... fun:heif_init } # gdk-x11 makes a toplevel object { gdk_x11_init Memcheck:Leak fun:*alloc ... fun:_gdk_x11_window_get_toplevel } # the icon theme allocates stuff on lazy load { gtk_icon_theme_has_icon Memcheck:Leak fun:*alloc ... fun:gtk_icon_theme_has_icon } # tooltip labels are not really owned by anyone and will not be freed on exit { gtk_tooltip_set_markup Memcheck:Leak fun:*alloc ... fun:gtk_tooltip_set_markup } # pango makes a PangoLanguage for every script you use { pango_language Memcheck:Leak fun:*alloc ... fun:pango_language_from_string } # pango makes a PangoOTRuleset for every font you use { pango_ot_ruleset_get_for_description Memcheck:Leak fun:*alloc ... fun:pango_ot_ruleset_get_for_description } # pango makes a PangoOTInfo for every font you use { pango_ot_info_get Memcheck:Leak fun:*alloc ... fun:pango_ot_info_get } # fonts pango has loaded { pango_fc_fontset_get_font_at Memcheck:Leak fun:*alloc ... fun:pango_fc_fontset_get_font_at } # font maps pango has loaded { pango_fc_font_map_load_fontset Memcheck:Leak fun:*alloc ... fun:pango_fc_font_map_load_fontset } # ... and font descriptions from every "sans 12" type string { pango_font_description_from_string Memcheck:Leak fun:*alloc ... fun:pango_font_description_from_string } { pango_layout_get_lines_readonly Memcheck:Leak ... fun:pango_layout_get_lines_readonly } { pango_layout_get_size Memcheck:Leak ... fun:pango_layout_get_size } { pango_layout_get_pixel_extents Memcheck:Leak ... fun:pango_layout_get_pixel_extents } { FcFontSetList Memcheck:Leak ... fun:FcFontSetList } { FcFontSetSort Memcheck:Leak ... fun:FcFontSetSort } # gettext has annoying uninit warnings { gettext Memcheck:Cond fun:__GI___strcasecmp_l ... fun:__dcigettext } { gettext Memcheck:Value8 fun:__GI___strcasecmp_l ... fun:__dcigettext } # dlopen madness { expand_dynamic_string_token Memcheck:Addr8 ... fun:expand_dynamic_string_token } { decompose_rpath Memcheck:Addr8 ... fun:decompose_rpath } # gsk { gsk_renderer_realize Memcheck:Leak ... fun:gsk_renderer_realize } { gsk_renderer_render Memcheck:Leak ... fun:gsk_renderer_render } # there are loads of these, but they are not our problem { iris1 Memcheck:Leak match-leak-kinds: possible ... obj:/usr/lib/x86_64-linux-gnu/dri/iris_dri.so } { radeon1 Memcheck:Leak match-leak-kinds: possible ... obj:/usr/lib/x86_64-linux-gnu/dri/radeonsi_dri.so } { wl_display_read_events Memcheck:Leak match-leak-kinds: possible ... fun:wl_display_read_events } # gtk { gdk_pixbuf_loader_close Memcheck:Leak ... fun:gdk_pixbuf_loader_close } # libz has a warning too ... see this from libpng / libxml2 etc. { libz Memcheck:Cond fun:inflateReset2 } # libvips can generate this one spuriously { libvipswrite Memcheck:Param write(buf) ... fun:write_vips } { pixman1 Memcheck:Cond ... fun:pixman_image_composite32 } { cairo1 Memcheck:Cond fun:rsvg_cairo_surface_to_pixbuf } { rsvg Memcheck:Cond obj:*/librsvg-2.so.* } { murrine Memcheck:Leak fun:calloc fun:g_malloc0 fun:raico_blur_create } { signal_connect Memcheck:Leak fun:calloc fun:g_malloc0 fun:g_closure_new_simple fun:g_cclosure_new fun:g_signal_connect_data } # ruby has some annoying ones too { ruby1 Memcheck:Cond ... fun:rb_parser_compile_file } { ruby2 Memcheck:Value8 ... fun:rb_parser_compile_file } { ruby3 Memcheck:Cond ... fun:rb_file_expand_path } { ruby4 Memcheck:Value8 ... fun:rb_file_expand_path } { ruby5 Memcheck:Value8 ... fun:rb_enc_str_new } # helgrind stuff ... run against glib-2.40.x or earlier, later glibs have # their own mutex primitive which helgrind can't see { helgrind1 Helgrind:Race fun:g_thread_proxy ... fun:start_thread fun:clone } { helgrind2 Helgrind:Race fun:strlen fun:pthread_setname_np fun:g_system_thread_set_name fun:g_thread_proxy ... fun:start_thread fun:clone } # there's an unlocked assign FALSE which is fine { helgrind3 Helgrind:Race fun:vips_region_prepare_to } # unlocked read of pixels-processed-so-far, which is fine { helgrind4 Helgrind:Race fun:vips_sink_base_progress } { helgrind4a Helgrind:Race fun:wbuffer_allocate_fn } # helgrind can't see g_private { helgrind5 Helgrind:Race fun:g_private_set } # use of *stop from generate funcs is unlocked, but fine { helgrind6 Helgrind:Race fun:vips_threadpool_run } libvips-8.18.2/test/000077500000000000000000000000001516303661500142475ustar00rootroot00000000000000libvips-8.18.2/test/README.md000066400000000000000000000002761516303661500155330ustar00rootroot00000000000000# libvips test suite This is in two parts: a few simple bash scripts in this directory are run on "meson test", and a fancier Python test suite that's run by GitHub actions on each commit. libvips-8.18.2/test/meson.build000066400000000000000000000043501516303661500164130ustar00rootroot00000000000000variables_data = configuration_data() variables_data.set('abs_top_srcdir', project_source_root) variables_data.set('abs_top_builddir', project_build_root) variables_data.set('PYTHON', pymod.find_installation().full_path()) variables_sh = configure_file( input: 'variables.sh.in', output: '@BASENAME@', configuration: variables_data ) script_tests = [ 'cli', 'formats', 'seq', 'stall', 'threading', 'keep' ] foreach script_test : script_tests test(script_test, files('test_' + script_test + '.sh'), workdir: meson.current_build_dir(), # Increase the timeout as running the tests with sanitizers # enabled could be slower than the default 30 seconds. timeout: 120, ) endforeach test_token = executable('test_token', 'test_token.c', dependencies: libvips_dep, ) test_token_sh = configure_file( input: 'test_token.sh', output: 'test_token.sh', copy: true, ) test('token', test_token_sh, depends: test_token, workdir: meson.current_build_dir(), ) test_connections = executable('test_connections', 'test_connections.c', dependencies: libvips_dep, ) test_connections_sh = configure_file( input: 'test_connections.sh', output: 'test_connections.sh', copy: true, ) test('connections', test_connections_sh, depends: test_connections, workdir: meson.current_build_dir(), ) test_descriptors = executable('test_descriptors', 'test_descriptors.c', dependencies: libvips_dep, ) test_descriptors_sh = configure_file( input: 'test_descriptors.sh', output: 'test_descriptors.sh', copy: true, ) test('descriptors', test_descriptors_sh, depends: test_descriptors, workdir: meson.current_build_dir(), ) test_timeout_webpsave = executable('test_timeout_webpsave', 'test_timeout_webpsave.c', dependencies: libvips_dep, ) test('webpsave_timeout', test_timeout_webpsave, depends: test_timeout_webpsave, workdir: meson.current_build_dir(), ) test_timeout_gifsave = executable('test_timeout_gifsave', 'test_timeout_gifsave.c', dependencies: libvips_dep, ) test('gifsave_timeout', test_timeout_gifsave, depends: test_timeout_gifsave, workdir: meson.current_build_dir(), ) libvips-8.18.2/test/test-suite/000077500000000000000000000000001516303661500163555ustar00rootroot00000000000000libvips-8.18.2/test/test-suite/__init__.py000066400000000000000000000000001516303661500204540ustar00rootroot00000000000000libvips-8.18.2/test/test-suite/conftest.py000066400000000000000000000001321516303661500205500ustar00rootroot00000000000000import sys import os sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers')) libvips-8.18.2/test/test-suite/helpers/000077500000000000000000000000001516303661500200175ustar00rootroot00000000000000libvips-8.18.2/test/test-suite/helpers/helpers.py000066400000000000000000000216311516303661500220360ustar00rootroot00000000000000# vim: set fileencoding=utf-8 : # test helpers import os import tempfile import pytest import pyvips IMAGES = os.path.join(os.path.dirname(__file__), os.pardir, 'images') RAD_FILE = os.path.join(IMAGES, "sample.hdr") JPEG_FILE = os.path.join(IMAGES, "sample.jpg") JPEG_FILE_XYB = os.path.join(IMAGES, "sample-xyb.jpg") TRUNCATED_FILE = os.path.join(IMAGES, "truncated.jpg") SRGB_FILE = os.path.join(IMAGES, "sRGB.icm") MATLAB_FILE = os.path.join(IMAGES, "sample.mat") PNG_FILE = os.path.join(IMAGES, "sample.png") PNG_INDEXED_FILE = os.path.join(IMAGES, "indexed.png") TIF_FILE = os.path.join(IMAGES, "sample.tif") TIF1_FILE = os.path.join(IMAGES, "1bit.tif") TIF2_FILE = os.path.join(IMAGES, "2bit.tif") TIF4_FILE = os.path.join(IMAGES, "4bit.tif") TIF_OJPEG_TILE_FILE = os.path.join(IMAGES, "ojpeg-tile.tif") TIF_OJPEG_STRIP_FILE = os.path.join(IMAGES, "ojpeg-strip.tif") TIF_SUBSAMPLED_FILE = os.path.join(IMAGES, "subsampled.tif") OME_FILE = os.path.join(IMAGES, "multi-channel-z-series.ome.tif") ANALYZE_FILE = os.path.join(IMAGES, "t00740_tr1_segm.hdr") GIF_FILE = os.path.join(IMAGES, "cramps.gif") WEBP_FILE = os.path.join(IMAGES, "1.webp") WEBP_LOOKS_LIKE_SVG_FILE = os.path.join(IMAGES, "looks-like-svg.webp") WEBP_ANIMATED_FILE = os.path.join(IMAGES, "big-height.webp") EXR_FILE = os.path.join(IMAGES, "sample.exr") FITS_FILE = os.path.join(IMAGES, "WFPC2u5780205r_c0fx.fits") OPENSLIDE_FILE = os.path.join(IMAGES, "CMU-1-Small-Region.svs") PDF_FILE = os.path.join(IMAGES, "ISO_12233-reschart.pdf") PDF_PAGE_BOX_FILE = os.path.join(IMAGES, "page-box.pdf") CMYK_PDF_FILE = os.path.join(IMAGES, "cmyktest.pdf") SVG_FILE = os.path.join(IMAGES, "logo.svg") SVGZ_FILE = os.path.join(IMAGES, "logo.svgz") SVG_GZ_FILE = os.path.join(IMAGES, "logo.svg.gz") TRUNCATED_SVGZ_FILE = os.path.join(IMAGES, "truncated.svgz") GIF_ANIM_FILE = os.path.join(IMAGES, "cogs.gif") GIF_ANIM_FILE_INVALID = os.path.join(IMAGES, "invalid_multiframe.gif") GIF_ANIM_EXPECTED_PNG_FILE = os.path.join(IMAGES, "cogs.png") GIF_ANIM_DISPOSE_BACKGROUND_FILE = os.path.join(IMAGES, "dispose-background.gif") GIF_ANIM_DISPOSE_BACKGROUND_EXPECTED_PNG_FILE = os.path.join(IMAGES, "dispose-background.png") GIF_ANIM_DISPOSE_PREVIOUS_FILE = os.path.join(IMAGES, "dispose-previous.gif") GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE = os.path.join(IMAGES, "dispose-previous.png") DICOM_FILE = os.path.join(IMAGES, "dicom_test_image.dcm") BMP_FILE = os.path.join(IMAGES, "MARBLES.BMP") NIFTI_FILE = os.path.join(IMAGES, "avg152T1_LR_nifti.nii.gz") ICO_FILE = os.path.join(IMAGES, "favicon.ico") CUR_FILE = os.path.join(IMAGES, "sample.cur") TGA_FILE = os.path.join(IMAGES, "targa.tga") SGI_FILE = os.path.join(IMAGES, "silicongraphics.sgi") AVIF_FILE = os.path.join(IMAGES, "avif-orientation-6.avif") AVIF_FILE_HUGE = os.path.join(IMAGES, "17000x17000.avif") HEIC_FILE = os.path.join(IMAGES, "heic-orientation-6.heic") RGBA_FILE = os.path.join(IMAGES, "rgba.png") RGBA_CORRECT_FILE = os.path.join(IMAGES, "rgba-correct.ppm") MOSAIC_FILES = [os.path.join(IMAGES, "cd1.1.jpg"), os.path.join(IMAGES, "cd1.2.jpg"), os.path.join(IMAGES, "cd2.1.jpg"), os.path.join(IMAGES, "cd2.2.jpg"), os.path.join(IMAGES, "cd3.1.jpg"), os.path.join(IMAGES, "cd3.2.jpg"), os.path.join(IMAGES, "cd4.1.jpg"), os.path.join(IMAGES, "cd4.2.jpg")] MOSAIC_MARKS = [[489, 140], [66, 141], [453, 40], [15, 43], [500, 122], [65, 121], [495, 58], [40, 57]] MOSAIC_VERTICAL_MARKS = [[388, 44], [364, 346], [384, 17], [385, 629], [527, 42], [503, 959]] JP2K_FILE = os.path.join(IMAGES, "world.jp2") UHDR_FILE = os.path.join(IMAGES, "ultra-hdr.jpg") unsigned_formats = ["uchar", "ushort", "uint"] signed_formats = ["char", "short", "int"] float_formats = ["float", "double"] complex_formats = ["complex", "dpcomplex"] int_formats = unsigned_formats + signed_formats noncomplex_formats = int_formats + float_formats all_formats = int_formats + float_formats + complex_formats colour_colourspaces = ["xyz", "lab", "lch", "cmc", "labs", "scrgb", "hsv", "srgb", "yxy", "oklab", "oklch"] cmyk_colourspaces = ["cmyk"] coded_colourspaces = ["labq"] mono_colourspaces = ["b-w"] sixteenbit_colourspaces = ["grey16", "rgb16"] all_colourspaces = colour_colourspaces + mono_colourspaces + \ coded_colourspaces + sixteenbit_colourspaces + \ cmyk_colourspaces max_value = {"uchar": 0xff, "ushort": 0xffff, "uint": 0xffffffff, "char": 0x7f, "short": 0x7fff, "int": 0x7fffffff, "float": 1.0, "double": 1.0, "complex": 1.0, "dpcomplex": 1.0} sizeof_format = {"uchar": 1, "ushort": 2, "uint": 4, "char": 1, "short": 2, "int": 4, "float": 4, "double": 8, "complex": 8, "dpcomplex": 16} rot45_angles = ["d0", "d45", "d90", "d135", "d180", "d225", "d270", "d315"] rot45_angle_bonds = ["d0", "d315", "d270", "d225", "d180", "d135", "d90", "d45"] rot_angles = ["d0", "d90", "d180", "d270"] rot_angle_bonds = ["d0", "d270", "d180", "d90"] # an expanding zip ... if either of the args is a scalar or a one-element list, # duplicate it down the other side def zip_expand(x, y): # handle singleton list case if isinstance(x, list) and len(x) == 1: x = x[0] if isinstance(y, list) and len(y) == 1: y = y[0] if isinstance(x, list) and isinstance(y, list): return list(zip(x, y)) elif isinstance(x, list): return [[i, y] for i in x] elif isinstance(y, list): return [[x, j] for j in y] else: return [[x, y]] # run a 1-ary function on a thing -- loop over elements if the # thing is a list def run_fn(fn, x): if isinstance(x, list): return [fn(i) for i in x] else: return fn(x) # make a temp filename with the specified suffix and in the # specified directory def temp_filename(directory, suffix): temp_name = next(tempfile._get_candidate_names()) filename = os.path.join(directory, temp_name + suffix) return filename # test for an operator exists def have(name): return pyvips.type_find("VipsOperation", name) != 0 def skip_if_no(operation_name): return pytest.mark.skipif(not have(operation_name), reason='no {}, skipping test'.format(operation_name)) # run a 2-ary function on two things -- loop over elements pairwise if the # things are lists def run_fn2(fn, x, y): if isinstance(x, pyvips.Image) or isinstance(y, pyvips.Image): return fn(x, y) elif isinstance(x, list) or isinstance(y, list): return [fn(i, j) for i, j in zip_expand(x, y)] else: return fn(x, y) # test a pair of things which can be lists for approx. equality def assert_almost_equal_objects(a, b, threshold=0.0001, msg=''): # print('assertAlmostEqualObjects %s = %s' % (a, b)) assert all([pytest.approx(x, abs=threshold) == y for x, y in zip_expand(a, b)]), msg # test a pair of things which can be lists for equality def assert_equal_objects(a, b, msg=''): # print 'assertEqualObjects %s = %s' % (a, b) assert all([x == y for x, y in zip_expand(a, b)]), msg # test a pair of things which can be lists for difference less than a # threshold def assert_less_threshold(a, b, diff): assert all([abs(x - y) < diff for x, y in zip_expand(a, b)]) # run a function on an image and on a single pixel, the results # should match def run_cmp(message, im, x, y, fn): a = im(x, y) v1 = fn(a) im2 = fn(im) v2 = im2(x, y) assert_almost_equal_objects(v1, v2, msg=message) # run a function on an image, # 50,50 and 10,10 should have different values on the test image def run_image(message, im, fn): run_cmp(message, im, 50, 50, fn) run_cmp(message, im, 10, 10, fn) # run a function on (image, constant), and on (constant, image). # 50,50 and 10,10 should have different values on the test image def run_const(message, fn, im, c): run_cmp(message, im, 50, 50, lambda x: run_fn2(fn, x, c)) run_cmp(message, im, 50, 50, lambda x: run_fn2(fn, c, x)) run_cmp(message, im, 10, 10, lambda x: run_fn2(fn, x, c)) run_cmp(message, im, 10, 10, lambda x: run_fn2(fn, c, x)) # run a function on a pair of images and on a pair of pixels, the results # should match def run_cmp2(message, left, right, x, y, fn): a = left(x, y) b = right(x, y) v1 = fn(a, b) after = fn(left, right) v2 = after(x, y) assert_almost_equal_objects(v1, v2, msg=message) # run a function on a pair of images # 50,50 and 10,10 should have different values on the test image def run_image2(message, left, right, fn): run_cmp2(message, left, right, 50, 50, lambda x, y: run_fn2(fn, x, y)) run_cmp2(message, left, right, 10, 10, lambda x, y: run_fn2(fn, x, y)) libvips-8.18.2/test/test-suite/images/000077500000000000000000000000001516303661500176225ustar00rootroot00000000000000libvips-8.18.2/test/test-suite/images/1.webp000066400000000000000000000731601516303661500206500ustar00rootroot00000000000000RIFFhvWEBPVP8 \vҾ*&p>NCѴQ93u>ʧ-:c *d/ Uœo经OnzO3wK[;>x?{ /@s=@?`/~y-WG_ u?eQlŠs78е[Ks7R!iʧV^4K*:'ѩOw*w >kMmGF W\_|=|= ʟ04OPg~ݢs(+0\ߎ,lnl2S֐ 3qw%^Yw$UiJ N p 5GܽGYh#[{`nbGEpN$,8#x`e0Nx.Ɗ?>}LN;;"QƜ;$M~z\2elJ~+w}ݸ 5]ISV&[F ۢxfd142fج+.SB aTL "׏% J3ÍiVfk 6qHI,'x5=/ws Ʃxm(oUKe"GqDžVQ"k-y%1w -;T .fWk΁ߟ` bu,ǹ[jqۤ_6~cH6? h9Rf<^VSg,s)lUd<f+U._K*J24fa\ 3ޯ]e/Lv7ю@`FVÒM%W;OTVz'b 7.Gw6%8~Tݧ!*Tˤ [Yb/6>ܦUU S˕:9 6D:k۶1 > zZr4PnhCn͡+9lC|!>2;cJzrF=n$<2@uc8Z5Ael|.9n& 꾲L*<6_{ 1YW#pUN2c82 #Z&;Nnz&e:V9:Zup:7<fTʏU" @{Q__֦ * 9A75֧y-_?~g/h޸:?NAXM8b)B^uw#gr_u1q8[]","髺>18ؿxQT`P1%d{w2"5APV}X6t;؀> {;~Q@نYh̟>,Gm2z#%ϊvVIO՟lZI#, e=jE/־oZ)7<ڢV)B]{dBK;SBr`Y+̡=>[aq =-n}-RStBG ߶֛S#h7x|Y{}-N |61NQId{Σ}4bPMgt6#˥L:v|"&8뉉sm{΅: !-NJNV,9o-/>mVc17s?gpsj"0ROC7脃\YL{Zl8y[SM},*C84߽Œ6!kZk,W|/'"vyHg#m^+>C1Y xw:O~LDvcT3aZz6RW_K9!AuR8iî&q~f#1`VM*|jCɫ\Q@bQi(q xÉ<'D&gC_\2԰ˬZ񪙯h[a-(1~#uE{q8(ҭXh܍w+Pb̿V L,e,[^6Mx-4W<1,h2fj=^;p=Iرj*1wL:hC̕=r#-qQ#\`)?$EdϹ3*VS?-&$_◭_C]I(^ w Sb-נgZw# S78iD`i,%X6^\3豋J2G>V(\HDkF7f<+}QA0VzpgdfOk1cDE*c06Cfq wM"ُU35%Nwj+R y,}|XdD&6"$6-*k@1 SFV^r@G@" _'ʻ 0 !뿇Jp#*w cBm3ד\ɍmjo?mtNrYcN2k#,EO`w"cZJH%/$>6n7> gh ?N 2 )gC2pǯ Y]E"'HF*e cgQ䒂pi=5+c*_a~OU"$f|Kdqy-Kp*!wH8'C_X:T Ji_7%id-]?iƣq;F֯K|`K[Eɒ0e?T֧(iL}bzFOf__ϹNnzzQa|V9(x_œM%{bi7{l*MEMaEW?؊{1 ZM[=~0ͬ,"2G~ljp@|eK ~=cݛh|Ï^,ukq 4Xϵ/yJ=ddԣhQ D,1xuQ""#ciye#炪|*ð1ZDԫF>KǞ~яwoq̂ue؎=)4*mͶ  ނڕz9A -s=%A (lVB;5Qϛd0 Z3F73|Щ${ˣlvfC0FjT@7J 7e.f4zemp@1zưP7pV*Ҧ&i+5 cǝp[`}i (Ⱥ~YA;" PcJb*Y/2샎M&/zwnA L-6;>Ŝ#4ܑ5}̹S'g1gmQİdʯhO]Hn5J\J,H&G#nJXfOnAG`߳% lOoo`*鵦? 55$C^Ji.11Sm[wvL 0R,p>(TAL) ƎU!~/A!a5^$!HLwI:^s:8SA;Φ}A3 _JzqBMX>VyjjBO:? ,D }0(zwoT5%ֽ(%egL Z_IW#]ER&p`\-r./e_@QXRDw]]릳t%WeMf9!$ݓiOK8@޼T#q#_R~q'Y.s Ybux+HSoLl;cZپ,(y x Ӛ3U΀O7d߉U/̹u2D}O>a?RgФ4͜[~n|d?t.Ì&mL`<;UѶ, E!=-RIDcCot=OA7Zj [r5#1e'mI`^QK^ $h-#6 h`!zg08跦D۬U[8npgy$9PN xwk@"~_{U,cctwT&=%[TCY] X|?~LsD49#uXMI(y6*\f`u'_Bq2vvL;]+|MFBnڳEx&PU)sO>(i;C<JvB(k~h.pi{]܎P´rL,'^,dvy"TGn`30Xc 1ВmFR&6yS #]g*M5)BUsNCkǾ\5 ;е6D,Xf9/% OB~zTNGCw=c=iZ~-k`()ȯP99 %ז}&}UX!pmlZΰ-h:mtU=`IH0<ӡ潳|_VR&+`Zu%\G(`f 0ebZNM S1]-` +I@mbWvo'Q2ig_!4tw8TZ-NՍ;ҎЕRدlۉ L8TR4٧58V7N|gW:%_*zgk[4F%I–cdpP!QzK[Ψ{pb_5ݐvM߇$_!Ӽ0bDN0?H1r x3/4 a 0գ8:%Ũ+2#R`zR<uH. P}$gy[ku\\j %j@e>~]Ye;DlR۴kڮ&a*;]b3ATdnR@$R@\,ÇFNkB>J[lo%*֤G@?wGo8u/@/ | e8ٞICǀӉk-7UhoW<6>Ux) 6nѽ raਬةa =2Q* ˭aP05d3C{;"ɎUgP4&-L{fC0//6*vWʪ3mĝ7)Po05{s33Oe%{w!L9)7ysHj3k0Xp$w2NP%p!fӯymFҌ+kBa0T;X!ŇAͺ" ok_> <Fow"RG4' #ZܓՆ!i7HA/YH=gsU+`3_j8Dwdn/BWwXW'P|sF&%^3őJq`$Ţo)EF] IԆ|R;]O&ݾoP^ʇDm٪3гiv-K]5VKXJ=sC̍{֡rw`0uI%:S,E[le9"R(-r/#,#zj|N9i>xρb ^;D2N?e3\ky޹z7N0dm /M<gFr2 -9.aȰk(0ljp 4n{cz! x?:_Ht^mbHi'/N͞q8UArCPA A!d@p 7@|Mr;\Dݾ(|RϚC^ .c>XxSJ=XrF.ʹejqz.ͅ`DcXq._C%zm'8mԲD+ QɽK{}2ϻ!yKRVpW2z2<"x لYʷTc1r8<΀\~VtD^tݕ:3'eǢqRy aVW hsMwꠝw34*i$.ioGq/OÒ,i afbX:*FUTÁƲ'n*) ,2[FTbg$=lfGzx։j,U@J.td6~ĴEHR,D}kˤmba`7z>2mJb~X3zE}(bHE=fdqDa$YwE*;!-q1 #U4[}4=FL>3v,S+N=.8bb3֬RPђH" !" M[!-|ZXgDI1 HCqx0x>9K!{W h+q}(Z\S#a.b,F?mc9) 50"", DD${aoeM¹srs*wN{_<h|33C.oM1q6h6mUJ$ڕZ(bD|d}97vy 4KƢ+7*K kov%|T ԹX *p^}:w][FGԶ/,9&ȤM|d.)ݢ],Nk]w +=-Qjm`iɾMI/u9 _M˩{XRvcRc?gYs`%"`zŇI7bf2w𠩴HB_ Fr鏱]2p3DJ07Z9˾F2 S2|И*6λ49 @;AQUXӼrG:B·۫鞲>9'ZӁ<2t IuB;"d;7z(\k5c{ta /hZ$݅Esq}>@l  h7(RlŻB: =FĤ"*DJLs=UDV @C؎¬%L{@C HsHL[ s`VJ!,0O܁Amzr~4($W2W(~|NWb6 ١$aCl2:aA 1rSInw(矀,ߘx}=`GE@HV_ 381H2~j 0G(Pi7w^/6UH$_ 1#W.?KT14x{Ic 2oUD>{ZneIXx?3dRJFe"-jD:I35UI2Qi<5W 0o x| *GnXu3sQSF1cW+J_%d6dR ;P%E .1eˋ׉y{Uv L O䰩¯d ^W*,43ص ҖԯL5@qӐתy3}RY SןfGHa';T[1<8ME'frQ^/0,YJez]{ͬ=OZCl-'W&T :W94t!t|a>.OG?@LOiN;؇utM^(fN\o}קF*,;7bzn %:p)thǐEEam=Xi((1B)dy_ѯ[$b#P4 2sj !aG|PF2ºl^ɢ(X=,\d3,a|cmˉ.]m%pDq\ν!?}*%e2dj]wSNTaĖ)ٹ:^مb:ŋMԙء}HFҰq1(y3:[#MfVV7e->X&wg`o!" (x |*~E NgfR/3g` Ւ'ϭ_-Z\ϓmika @ c8Tu|~^ +~u3J:\+b5%WIZۧH}J})OH~Pk$)Ev1s 9?V~pݙ1ӀlYU9O/4e=gޝ>59[p[`kZ]Q+d2.IH\83#?Oat4R( ̀٫#O].Z k^w#̜)SU^d&* a޿FcYM7^*~,ۨ?8ɟw]נ%gf77I.rO lO(7|I`@ŷ_`9Ŝjũ n4>r?OTj9C\N[pEL+Q߸=Pxqy\."ƃǩ,{;{4O#P rKt?Q~8D+%sX.ӄ6#ifLYNņт]Y/tK"W K3~;lmS-g߾ܘO101:]ő/qpgx >Q'ng R.vWՁ Su9hALpfr|aK\u˴,> jVXԆԃ:ɍ]g uZLDeBґeD7xkفHr`[TQcV0) 65:^uN^R1VT)2"BŤ@"/A$ܲp]KYtyc=n1+kC3: 34Wӎ`E]ϧWXכ RֱUa{ pw T‡@W 6s{<ÞY,m>L0_Uz`:*QUK)ٕWӆ\ً%BҺnljGҭcM^Uk+ h r@b=<<CP%:KZ r=)/S.݉/e#jۿyT-6V%4b=Iwv[`Y ñphhbdy1L7knmq+зf5s0Ú|YHA<^r `oJvg~杻/zxlWD_`GDas`Ǚ`7ZQq:S]R@f 0Zz^L5dT܎ЌRџeTRZ=d>X1pF}B\`9xزA%0 ;1`@Yx?G37QtK3{\Ɗ3 OLaMV)]$|(S: az:ή VgfݱG<k6l-)ך+*xR3M;7e}>uo |O>q^^hv0hyD y~5H?/8}A? r㣹c4&lS K)F3D\OanXj -NNq@?p߾Ac0\8^QF) uS[DBd86sb0j)P=R8g6857r]Mg  #q8@L~ЮQ|RjH_1q݀[?[@"ߕ$8h%H_i2P& Yѻ +I8 V,NP9v"7u{ٮy)qvw%mG" ?g~ u]Iڼ7$Xex"飰-#`8ƳfIV;UVHr72D7BQ9+|,(:tO%zq䆄 [El)=C `E9YO .rɖP, ̦{jW9 o&}`j?Q٨auJw3Y}:do{zgt/gGZ?Bo<UBw?|V7|t QZgI貫B#i/V5 |g1݁U.^E *_nURzjuCnc\JĶ3#M4M/-] E\+QElA`i @OPo+H~$eJ|,s|A|w]qה0@Go_XDf0zGBb]'ohq#:wٙb 1{,@jhswavB-U XwFP^__@\]Tm!`p1a tȉLGxQ"Ǣj: K,]]{_D}QfD3 oc%b'!F9=Iƹ ݭqh365T7g 'q4 K铘?'p_92WSZ&?,w H8/+"((n `iaTiQON5[R>km^@nbXg:1ٱYp+)i}="♈livP$X0NfJGSbeX D *w^D)V/~ V\dvͺ<(V<k?%t=&0T>SR -ɼ"!(Woƾ5cg"??o2L:Q߂1hr91Cw?a҃3O22 %u 1w5pŌ\dÖCD͕*]SUҜ>Kya(k8nQU] Քf|bb(m녶^i/ 錭M'쑤tf  /k${uv m&g⽞۬NA ތkʐrfо5BFӦgwӖ>x >ҸO%[7'̮!Zu%!oWhO#mTXa 2ųY> 4MOw=hey5EC־Ҕ5Cweka'eċ 5SҲ k4tB>#kDT+4Cszۭ., wt~Qck\EAy^)fY;B?ѕy򱔇et/mj,kW;K<*꺂EJwpS 8eTٔ f>Yiw^E"7TRUL-M0+d-=8Ac y*{/nLHaw caYj[1Q &q|4Kf֟q!2Rk^ CJxr |PI譂"RSM7sK{ZH"%5F: фOZ~9/]wz-se*fdq.z?7PQI: ' WBH2ēt_`d ?*zdCY'V7M@Zoϧ mEn78^屈8E AŲ΋O~.y [*ʼn}@X5!sW耫tETհAn5dT9k9El5"Lȼ[4@m.@/o 1>P۩qDpoǧ5ճ"N +?@XcL,+^C7/$g։Ax?c[.Ei if8rq)b'R :|>Sw_v2e٣Wo]ĸ K"|!SflJL3T' )[q5J*$P:VA!D)A\tj5d?Aя{c{ <&OGI QQAUd JPz 7f߱"uhPa Z2Qt>>kp$U1V_nxr0R%ߡ鯸U Z0$(>_W<+fp=t^pxb<ifz{d`d_  Ibd(&ȕp%?3!BLɞ&6nZCL~?ztoyu쩐IX sI{W{M,`tI+ܤ8>rf*Z ˜cS7-fw`Q)y3a7J#ꐊob]4kX_,䌗'2>DL ;2ݜi΄iwBZ@E+Y ȡVki yW~TSht?NNRCa\,o`Fʜ. r7]mV[Qhv{"&gǂއu Ϛ[F^ׅ3d1WK̦ +\/%I[F:sYPzY%/3 %qő", w vŶ8dO$U,r(<* ]>&k{-[^0EHܦ!;aǶtA>`*;ꎱߖkEPb& TD9YQs0q]',eT~VǷVSg %.oBZz FP%pBo_,_Zh>1I y;j ~քy}z"ZHU5%m]'e!EmnR."Boe x΁ ȌLFjv;"!PXGVt1= vL/'#4o@fGvu**.kr /ekw5p:=PZα/w//H6O1q42u~w*ق @_Z]2Z 4%ru-2Snȃ]%̒e q:6晙l2ma@Cnek;2KOk /bFZzOs_cIsA}Jcn J,+4g^@Z{J&bIdHw/ axON+Lے|Z>(iDwl6m FCbrhC; .].[f|]usRvuڜ }Lc AԽSRB ky}.FEYգal8Ic3:ROiNe,hλ /%1mKFpFؖ=璀pYD*^Jqۍƀ`dB[]5WxڇaYվ! f^5Ǿa&O̦(liҩ$Z^EC~Բ3:Y?ſ^!T;ӯe"Hr \KwɘZ2Ӱ+v- ԤTa.e8V'9 Si*X˞FPbI[$c[ aUx[ٲr 륗avh7g EOld3>M߶;1mj)HLڰ2c"04I61y#~+*&gڠRbbpꑿKKr :a0w6;/66gB-['.4˃b"k7C7CL~ I0ߨ/ÓRIl8I߿_WY[ vڻ~5'?6_FfX2.6ΥnT&X,c, 'IWH{! ~<.6\@'>p݂#ѓ"B;ּysӟɀC󒨢{2|{I5Nq ٠j> Y`5Wtj,N!ar,sDl¦.Q`?=+?Tyc&'棫DbT|fX-1R+ͣ 4_y4AKYwBYuoF'y?pwIa4kÄTp" F7~B7nՀͼUt/(b}pظgQ"R{>t3K_0vy ;1A70,OD$u {ߐPUG}|BuJ"$HV fE}}΂ lP8%ߠ7jbH$; ҳG'~\R6alǑS=t۱Տ_T`2U p\eSOIqv`,-Ĝ /'< e#G,>)oN*+cLlR߫4ɖ>,wjz>E7!uPd:%^ZА@c_9$qWWC?EL_J'Z!K{L$Yj)$ #*.蕫[*h4Tz's'%U\P \T:'aQr>duH)^oCpWnI B,{q~Gкr.M^1 =dztG, Mtᖀ: `"ZH@ *]a)sb")qըHRgMBrɀ]*YydSi)Zg@TekIn\T:' JXOL-q&S(˚)K)Fi"K otdx2hQ_ Ț@ o@L(0Ӳowk]#cvԬg'zIvu,ގ.0Xf 7;Z7]4om$!Z1Ƴ9o !O%|yQt5b0'7q-(dy]q]J=;xB!&^"P|9R]$<9ʄywf˽HsEvb7FGXrR$W%2|gaHZ~԰$g\yr:ng닙A$ȺܺA;waHT;_|x|\Eewńy[QasMTQtm˸\8on(EeKS~ j9tT# FTYl t_RX9zXOP ePa6" S$1N md lQkt6p!t5zlweKv2.E(51^8S)"N-ǜ4sbmc7^:.wwBfaXUnTgQ8Rszazm^h#3 .axA`|"gLImV\36|"HՎwP<;0#B.5դ$3Ҽ#?E*@Ekt4ƈ$"X]O ,߱O`T"I TBE]n%> u V<@i4k(C4q=&9va/5n ypO|yJbP𭃬V i"ktGrmlͩGmYL;Яזqe KA[$|s]= `W"KVnwti!O&Z/0A?.S9ŐDPKz6E>e 0-k 毛eYvA}Sʅ0㇯SR&mjKbzUiT/zﱕu&;U2{uw,2\]*ݞ(-JC}5"_|S]Ǚ>nQ ʼnIq t'f(2 <Ӷ(LLwYPhBn*;7YV[?qǝ %<)aVzLRp3q\.(C' fg #$fJu 璼fб$+\[.n:5=T@wܻH)E`fNywZs( vs~G&)Dlk u+$њʗ͹M}hѲVi7~\gBiu\S@ 0V:֔V/1Ж )JB=V#;qid5CA!vn>* 8UFSrE篩e}C@dпǜw!E +5!Dk$DwŽ;o,u=3#nMY߳ XF +l enG*M 2{}3^V7J+o 媧wZsSGSN% 9'u!5.;jZaeseAw>VhgY@jmsLLKO s RjD) P8{I\w~>Z|Xd / K1sS: Rd!<,3b{]$i\Ep-aM Ѕ)ԹV [\|Ua5,FiW|5KW .rw[TWRYk'Xwje]g,7Ho2$Dۦv+X `yByWLAsV)⏘atITБi1œ|#- /T@%i+|u d;5tMjkD81aE]f*?kw!0cC,c*s L!wY{t:YS\A_x)LKuҎ?xҫݥ*yj4+~-JAb,OX WWa)eS!Jw' 3vF!W۹jo[t͟?23cVp\]d]F*Y|CÐF='C8 Nb~Rd{\ y)Λ/pxjcRZx.xḧla9`x @l|?]S>~wD4} *L~9'h/v `u!#FPkMZ$}OdI^IB2eq[!EU4ei!&/d{7Fu ,&p$kG_A'<8O@͍E0-Nђ޻>y,?1:\KX)$H"->#?;OnY1hĶhxzE puKQ].];,ؙQߠK$ʋ<ܒ킁gWNtGW >b) pz(NrHpGHPK>}amQ53pԁsAUySIUuBi:@2N3WgKH,C6x_7SRžm(S1r4 Pv>PvNPzv+Xl!Bj??JmUC`3c-S.4adu5"Hp8ZQ3lT:h%AG-u3)4b>AޠC[.>rEULz(8Jfketߙm9BBXم`bxBW}^@G)^AP8`&piSkgcC]r Op?UkbIЉ!Ҳ|0?^ [#NЕ9"D.}˝T=.dGfnp=' a ^G|_cK*X}٪uOE6+ȅW"5Ԙ`i9 @ 'Du*xB-wzv{X'vY`I{I M,KZCJdm)3aBs{/r0og-@!oJdh$%|nxE2#km`aRJ'OJH>~pe?:&$'=я(e9Ba#2Y.*4^3=.Z .\Nueug z'RqAI*\NECN dnD.34cN}xHTopus#9ftQD„(O >%VMuZ9êFl`g یZ +iƌiLHY.Qy-f-uK0UOb󕻔 &ʲ;pw0:H5Nښ%|ۊj8.C?PힽrΧQl4>h7ԙIk(ganp@nwn s"!+WUQZ>ccM2g7&:D}GocIҭJ0zܟ۟_ޒw ߆T"WG25fr9}iqC|ӎ:KsD꥕rƹ9DnjI-oRa}.BJ/Vj#>M1f!̔8gb:'z1={ٸzpF{.}ĢŌWX ~ig|j}J) VA-9R+59#7zhfnpĸZ*&LMT#r-U#&ܮ 4;E,:?ɹBs_wbBYMk+j];bZKPŞ;7K2D(#W7SĻMӃv`Jw:eF7:؞C6+%&\Ȅja1̺b¥P0DjOL,;*q;1 hZ"Jil5R3ߟYu\ēo;LzpBNخiSx+K>GsjɵTVZ|1[Ɲ&&N@x7<j9b 59Uǽ^G_uyduױ:El4ѐf=_9& }NkƃX\|KyEp$=F\YNȩ9Bg$Kh(%gyP)DR۴zkR^ Tp՘Db"w`Vx"U1#tpFsC 6/KF[A`ԛٚ]p;tc80{,NЗO0c;G0©rj#w-[҉ 2a* mʗa' f_征9` " 1kZhaZrL\ JdU9qV-W6Tω`V32gh 4(ي :72E},]̑ /U[k(]x&vƫiռIvԇG#=y:ѠSh$6GJ͎axrh?f_!xM]@J$ĉB&|Va\J\buq^q9|875_-:Whp8B% Pܐk͈c4)`ousms-WE5zvߊ[}=Qj暑 t7tH JwD8{u%/t~=DQ.F7ފ:`%yawV.u!ؐ%"g:CkĶsC!5\Fh:Q!$qǒӥ7"Wb3^4,HQP"o\Uw01X1p;3imtðb&mZVQD`O**JW l ~q)R>ޕ3XOd'*F+qW-vE?Ǭ}8}fnmEHVLqpRN4EpBv̮MEW80FMx*yvɵ↹&PcIT +ڽwгX}:8)e_|E^kľoPRM31eSavLHݔ](t-xnya|%p`2 @]7WX8 a/E̻{zãn8^M(rs^(`] 1!xPTYoc7?+d{B!Voc0t&_ԃ$W)I(Ý)mۛ06ENXZNrӚuجG2]7jc֫dgpO5E݀\ JcfzqNNL y@Ǯ-|bM'*2eK hP&&qRLk8b#!g|IdBAPYvduK8xEgZ 99HDbV5hc im;]/t mܶk]7, {v<:yqp[g3 $ ;%,5 uunc[!Qɣ2\Evk_CZ}z=r]lzЍ! *ZpԨdZe!1YPT0M>},SupiI IH>ѱd 3I3~zϜ˲r.%28oW!~رm 5"9 >GDʠC%4TTR{uS/> hcU5T<}weoB4?X =2.-9KCĈzI仉GLp%$xOī#˄b.MJ8*?2M~]6F*%tfٮ&#@6DjiO}YFIںeb$=0}(v>O{(0D PXw6L[@40 ܛ_.+oRJF"p}֐ǻ\jȎqGM&lh'Ѿd((s (K k( !wx)gmيPumm o_zC!= If6ã5s)w%*w)>s$t埐Ju+\2ƻɽ@dhߑOEx`YU8L%\#hڥl_ #zpr]#$v$[h^cn2uՅdi:ƴ}f?+/Y ](̪-|;>\$M)e ]sSwG_WF2p>>O8{(;KwCrqfdF= kwv7 }r޲eŋZTs9bPou-m33'T)TˏkznqnzvCw@jX\](hpI neE;!2]|z|U$-kʛWxC{}M,*å`G A4? KɊ!=%,'/hfߚNx~D"}n]ff#@%{ui傟\@޿oT' 3!% xhW:ڏuX;(֕YeE;h'x`1y,)sD#ۍu xKi!ܿsxպ%]rW*W^7q>D-ť^ ~w$^r_Ur]V)%]SثO5 !e A ʿ ZQXLՉ4@ǘCfcB dF\$`3cTusNiFE O9Йx0 +Ǔ-ۙ`{ULMv>Z*/Z!u $`Ly pԨ8^=Յt`g/'Ҹa#K"-.AX}fme$vm@`i4BbfmL1M_NnܭGf ԝ-BCzAn\I=*`VVHN:m>˨V`lX4 uł j8qS;i:pU3Gp͕v# I Õ@x/LfM=9;h"+ӂWEKkWLMPD{nGC,FGDz,Iy2H4<2[I4"lCՇDrEJcrc:I^ .Waf'?D5e g[lp:"RXߋI'0ໜLK؃`\%e%6jB0$cbٜ,jp@_B1QuTe>>.악mz ꂼKQ1bI,(&+A9D$IhHūu|_z6h%ם;o);XXP.0;'^^߃ (2|02RzhO^I׾ BAduP۠@uaJEwD-OBfT`zL6|=Ӵo9?WmQNQC]1Vpm6\jj`9Z!1&B)'m3V'@0U @|ADއ̊.̖ yR'Nmt]ġ vv ޠZӊ 7FӉLĝ`#ϤR^A̐WT%h;ss^|A ]aFԮzٌٜ{5RrchOi~My^hdRnsx!L(uF 4nѺ:.W"Fad+6ǖd-r}O7,1$xG$ZiΫd'T-<4ہK]ajLF>I6e[!Lg{p2,, H1F\C!WX]u(nM"{!\cùPkO:z=%=<H9uCЕ݁Bwd/봞wU?;KKj|?WGk'%z̦PmL5oQpO݉ШW?ǬLO#`HS\nb]kvO/ p+7 ]θk)I!PK GNV(?ẅPnIv1f^5K>RUwg\ ="4'O1SA tBbA[ Ɗ=ʋףFZY9'*yCN5m^gR$8Mu+bMw$z}D^3RHp|h$34\ `=vd&w#fOXZ]}peN5rMj*3Lk$G玕P`HG3xK7]#{4挸Pjlq LK56wh'w 4(:y HSY-7KHA oSJ]t NXcfpҤں5|0@ *BY'+d #Jlu:@ 0&熢KJ!)Ggp94KKsCZّ 1 J']@y~!;l"܆uu:ڍJfvbd67UvpiTt`΢^cQRw_JՕ8/9eQq]ME޸2×DbГnA3 R FZ۴<1_/yDW)ׇkkW8K bt1>?*Pcdž A #Q/n.r%+B$k@扰XɸTY_sxl%[/uyBJ% T>=x,czJVӰ2A$OpZx@ʰEώ5H4Q߀:Y:K@u5N@UZCW)sĬw~U.8~k5['tZUW[pő} K*s0ƻ$@ڶ$|S#RB"d{J(LŒshWuxDw>z ?]K]8 4|^fE?zގP( ~aƢPěײO]ln/T%/Z |ڛLyL?N|X4Gs$(yzQc:"􋔛,{u$"Ŏbr0(65P]?%^oeb\K@n{o$VR][x<2@6'YҐ~o?A.k*P<0+h~lozF5Abw᧚[4.b y: `u(tqI,qPvvMuɜvI=99ԜJQdItb6Ü%t0soԧvl9[&P̠Hl<;}z;. >_s?=^r,5ȶ {o)Nk^'`ڸ6Gͤ*2v}b6?9|N|=m *#wM.u)a$Yǻl^]SHinBUa=ڿَQfhI{@3)<`{)\PjHA7LX!?P'rZ^:f s h2TA4sytمFNOTՕo)m;٠Ӎ_TڪImpf)2DӃ<.1e?Wh tL&P@}a&ư$o.g ȾD!sM-N͌%)jcQ~K(N?ͤW׃0$)w: |I)n\˿ wLR`Ub#?'TJQJT; d[g8p}A$/6b(fzXA'~ 8pEw y+Xv$-WR2Z}TAW`1:Ky+f_b;_ !=4b4,*_wjE+KHd'\n@r!?2U^L1^3N?foZ#KpNSβ0k0Wn?0{7m-<\2W#Adʿ'b; &֠b 퓩E[LJ,uD7{blYLMz D zZi\$ 9ȽkD2Jf^OCmM=Uo}([EwEF(~By!;iW|J#(bSS~2r=& L"hc ,q1r#x$+cܓ{}҂ӼU@SG۩Ts9J,/+m'RNS&\u<@>Y[źQ7.}|2ʝ?$lʮ2ASMgjf{KՖQl,ICeXzb[|J2eF#c3v |=)azB6MQ%J@J{s˯8Q05Au5bLe] *c\\/hxIn{(eK :ZR2{,f:JjM kYO |J,Z#G"ʿX5҂jsifkka.? l$Nvfk)/Z:{>by3/Y~AWVP P2BđI/DqALxD ]V-%èD+Jfli=s6ʑdΦ @VH+?#W=v9{զh% = G)tWgd,́elY_{e+$FuSd%T7}D4ԩ "lc+l܊GW%o2Ekny̎KD3>Mj1'ҷt#.)|?G)tk3:^֍^j$-9ƻUlt+P D!SA||okbZJ1ï}[F^g!n%ӶD˷%܈>).f= qć6m ui2R@u1-V+ᑒW: 1|,B9qu rqsYhe QiMy {UUl`[SS양f2*(fJ3e+pW$@#Z<J2!z{אַWZ!(gG?K2dzCEWV8jKc*jz|IIv (wl04frsڠj8t*AFɖW3t$06xْm%}Y/:bt;8k4rp@jf +xAS*9T,d rX: Q2 L~g1`!B#cZۯ+2|@||b % U)u ߡpGtac|P>4>e`5x-,uMH_~G"@Y)'37 ]'U)4~J_{^NSek+d~CR~,Z*Oh'#}9ͲnHZ$/&dA& E$L@8̧)Hf[$ UksBk֕nyhN2EA@uvp<"i6XRyEb3YMqSB:TwfWQ'݋zL5_B# 7u`yX鵃le锆f .fDz\Th8r0 lٺV,~|03ѰAYs=u=կY^b0iֆݏ5s/jAzJ"viiɒ+\x'YLjuv Q!r#?lq߰u{-5+anTo EڼAaj?\UԒPQ4r /޴#K&?UfX@C"S>OQ ڋ@C=twWEU>iXYF(H>A#LQ0x zL YsJ֪-}P܁ 2M}PZ-QFfjU ߲9"mg3=\Tj:<#/- Xm(u ZwQHr{+BHWTz\Iv6,qrN(AMA-==i IPΟ}|?,>ѬRMĆ#j؂@7BnJs:x9^jNS^bQG坆@\$O&( t*ŀpL8u6Dܲ-Yl;VNآj%'!bvBsClvl`+ƍa~j8b"$IP[KCld'EwbWHpqJˬ= 3r&/`]@NegQ]6mNYPҟE@, P9FK(TM ^X)K݀dXz_y`fS zkn8Թ;[W$ &T9qS" ^G V>BiLN P#*iȴDJqkmä\ٔ6Y3l{͉kޒZǻU^Nq=GR Sy*}Hx>ARE2|2/?wAl\Wa( 1Isҗ $4]%)pkڰZ?3 G[%̞mq ~;::?aN`d!\xEhFD+sAN 2ϯ ?{U$L(4xKcNv/%=;-C7|ӸkuQ \y{\ ]COibra*B-}q,Ғ(MJܜ)~"W=#L329^$PD8망W mJ >QBN1^`ƪdY-KgFmtn NkY:SΣ~dQJ٭0ࣗNXة/'މjˈbeHcЙ| __3,K9Sx5YazfN9Ck!2ݩ)Ъ x0>;oQwKMkzJڇwXkW&[[@^G7jZ $wTUvl,)#Eaw;UU>} ^9-1"z&"g |c5,'Z2CMimIhJ:Xe˹A=uY/q[h zEV4f-]ljWC?@th].گQ]$٤J&E-C*,0.!4PYX~oڱOv^M Y`E=,hQ|d:gg#tޛX yfEڊ61/`ycb0$*ņ5G\ {FAj݂#uۚXdTa&TݯoA]! >D)ښSU|f9@]Z6 Xڗ kDNtv7gB\ %-ݨ=C ؜ *YHs @^4S Trog7Ss<de[' 闕C >ER:%EE@w<1# R@%߹kSam].67VR?z$NJ/qKSWL;eBNQl9685e^g=W6&]!_kW糤sEĒ?$|$ڄ3)X|aV'K,A:[>y!9 o/!,R!BT(nK̇X D{>ڗd T98+4Gszoɹπ *g]t%%5MDhۗ2c/Ms% Kp'OW4ȩL $2qHWn}`Z[󳂣0xTE`sfrb@\⚷r[`YІd?'L˝@qTgS[0"ӮNClD(DxWÛ'59EM}Ʋbme^7^=Pw K[ 7顤4 v ,4Ipbf'}՟z=%/Lh9$Cwj@6(1$aR(!~>'qL[ix/@#k{Cg{5q nbۉbdev9"HQO)Lx'[!w.+J{@Wndtmq=JPŸ%)̈́MFMq%  9~^F:bUGۃWqyeЁ 5 e;YBV^]U6Ц}y </kNcukC]c: Xb}_eBv4~0D^u\nB+)c. .ףF$yqxMwOΊbFd}AH6* #_rx==|bvbBPUWh=TAXu*?J64]jaҸxOp# D}:#6 (7-3D7 dQ5JQchk)^n'fyv$tjK[F,Q' 3RnA>s0$#`;N?\uBęUKq# F6@ ^,tk¼Yex[X<]d>~a,kzA*|' Br?A{|xTֳ CqS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4PO(5㦚_:<8pK/21}؋xa|+9b>_Yqa|C 7t-W«&ɺ t%J+\P]_|%9? -v!=JFwA`dgzX/[|;4@|z6>sîIHE )0!~< Di)eZ} Ødẇ[fyAd^!睩FNl>tzO/ÅZ%3-#,ٵ6@+Iao5M;T1ƫ<mJUpk=tN %}Eh剢PB37.Bc&U#1*B؀ϝE7vN3ʸJ}B饎1Ç/L}:&,5ş;Y`p-Q'L!f`n(gҕ^є|9÷FdsZk|CYT\}DhҴbmF0gEB@sKUG#HeA[, 5aɘ)Rt8^J| DWOc¤sCra.,`rN}ë[/Weqh替uuՂ䍀t-.U&-JJHl?pnNW7 \Iw 2`$/*k;gM{`#U/9oUGa,$Qbt53Z;=V7t&Z~lE9l2T1Օ{Wp)B\TG1_68TIX-p]tkRrɰ|[)}P]7MdźI1rXP z-7D7n:ڃ=7@ e'P5?v2^mĊN(=CWU;}.u7DjiMK߳}# hWz ^|5QZB][CaN-eἨ&hBIYɶN#Bu¢M#{ g$Kj`/ rpWe4U_ ~TU+,+-55q\xh(G )?2g)OXmhqUbus>DђYO؊ 0#HkM1Y!%yIq)# &_؎OjW"]8jzVUH>eFخ);"iY_$,4eUd.B؏sxڥ,aY= u8VqE2  Bj<*rD:N= }9]V1Cwgdm9BÄT \ˡ)z.֣5k*g*Vy2#/#C<26U3P_!!C9Z/d̸e*q:;Z3K :{&.'=D.A]6P|]2w@Vׄ"Se1۝~WI[?VF(cD g#Kֈec$WyC0.j [20߮BaE?ϵ)׹}l 2JJFG5{+QT>}_FqFQhQUwJt)v2'N wd5_ `?"5{Z+k򐿊 bU)D&_X4X>% S}b(.RS|/no!# (Qc@t<ֳv{߃HasX":c"2SޭxC߈~] JoJ#eמ|IGyx)XQ8gl$@5IW Ut nlT6 $1 >tcA}4EH0c.Зv&C7;0Y11.]wvIϲU,&8dbF@E܎ g`T~ qh\ll3oq, -[!q1,ߑBY ^HA 885ہ_s鎺"S RfNvuT+stz2lu7 EDmDR솄sXY0vR nۥ6P ub*z= s{"0 0=bpU!(O :C8*tpTW1\אbMF$uLMjbtc^%"ί:H;3-.jXOp |[;}f!HKn#__?ƥH-[˵*.(M1lΎkX `{|zvh Ygn)).m4@g%*H7T'a?&IV 2c w01dKWe Hf[/ԂǼătCr?.: riN kVTEc~;Sqf-ߗtwF9`𖌜5WG%#-E̗8'+ԴuKh20-k\*wu9DSjD9w8Traڎ$ɟaA Ř#1kYbګ3 t*C(] 04IC霴ux,Ò;N0kBzR·gnsvڨWEw:NGUAh,5'؆UG>Qzfh2aix͇Unnܳݪ?,-uOy%Cx eBtd! ,эZBg;晅( nfqXroRﶊqD9<6w: ]"gI8,nv 0E}fL20?"iLR2N3weРmony%zKKMYQ#}V\',ǧopгlTӻ#`#H'y#p,.5R4to'h0A]xUS(9q)WaΕ ǩ:v_Iύk,J0RlY4%l16Ww`JoʲG*²R. ;zx{Gܜ7k}G&BO7AxBqZ[S]_n _`ԓ~bVZW#R$Į@fE;7/x%er%' 10jR5 su_AEaXmV_j&ϵF9{^>0"va^Ӏp6U C%/&15AVk 2I;<6h<MLN/" [G²gig_.vK00([]Eޝ3>:ؒlG'NPܧ2VoHX.JѼ8S"kg]83*Q-Y ?Xlh_*vX񓅊I]Kh  KN{)V̓ªe< Ed&wĆ'n&H4I=RZt㝺u֬@oUN+dVD*؋T!7 DC?(dl Xm3Ib.| dV(yWf G˿櫧Gs8VQkȫ N$8ʸwhTy3G$2~䟴Fqsm,7x(?$ (U~h0l# D??+:+Ls=18qC9b &_G]@3{W{g-;*upJ7,4E!)}{䓷`{r3&1bf!$0m]Uݸ2>bܘѳ\mOS&ɹ?]ݙoM}]5pYVW w}HIyWz2{ƄO" vN9Lϡ]0S_=B3-B jA-0j퀂ȋu5%JyGeEj)?sX2~a^9!طip LQi|P y;h7=6E h}VD[Ȣ[Ġ NG{Di Y"8r'a-WsՎ#@*2ӣ-"+xɨ( Sc5G>Qr2z"'i2I fmR/F9)æAlDb|' c@p t ͋%Lw] Eܔ{(?-/kZ/J3 +be W/+$GixEszd gp߄z&tٖݐb^03ʠ ovݒL z?\ {0)lg۞Vw$ aSds 8CcYVoCEc P9^>hgPi7V3h]dݭx؂[6VO%9҄Gx;kɂhb];FzYCvypЉyլ^P;\a=/fVƻ*`voS$n ;-?CReP2QH]Wtȳ|[R f xǬfp ]N*dMGI_ϔdu9.9)V|W{BA6p,UY~Vx^//ڥyW_5.A\I𙎛Őv{U@ fQѭK|D Bi0fF ͇:BrXTZٶCj F$a2Јl^샰4IbYܐhQD&,"_zt|@|@|b@95Z.}oiE|p>4P܂v[waJF/f%2ACDPꕿPtfI葟쟬h$p{zP ٳ{.(I±{Q`|J|z,M` ˜pC̜e=D{DvYk|jdir ݚC9?Pm#p;a-CN =gV&~y7%RHM9y  {8{%i,#IkjSđn-+A!0,t'Xye/'_!HFimiDZ7CP,[x?Q_|>}oYZ>A2DycCi< h4ߟj9rV֩L` x!k z+=!Sb )5'w|޿홆ۏ!>ZO)zt`VA~Cg~w!x<:Urca1mmI-* 1VwcL/V*"Ekdh8_EmH X0p}PIkBKj&C0Puc78bbtmH!Xљ|vH^}0y@Z޲#c $HDz͢f%/tJ _'l;u/uOQ]ܞ693~J:aBEdgť2F*/|r;%SR`Xh?&YzAH@iMK'IijB**ytR ^[ڌo%+J2Y~Wwb~Q S=V>ZԎ%$`Ңdb\Ƕx%5.īUՏrXV"3O[lޏB{%c՚q*4֐?p, { nH#^y!B8h'$"$(ެZ A oB$nޮ`XT\Jr} ͯ.fNnF$ѥ'b: 0}မVu`,{? KL_=])月a2q1gaG/3:DMݲCGERi_3+-jt{^7~x*C0mpȤDߋ`Yx ocF? CE|?>[?<nSμ/֟o> bbWf? *(W_r8HH&ԐB:>Bka~"jlq˰(p!\GbAcr͡{3מC_F ebކp3"sX}|8NG\<[ݤb^8C8={aSz=NՕK1BuRj ff ~kJR)`gV 4#9@ny@\yV2ِ̙,Ga7 Jw3+r(*5*h@6MxQkDJ^& ̈́s뾥,g_ ;[:LWUʲƉߦ++9b' W5퀈`X_2g>[Z,<إEj$y_NU}eMW6peoslx1C[+KPQH+V%Ċoҍ+a=t!^0lahk"նq>c,ZsOZ'H5RZ Fk T#]:, \fLˡ4"#-!?$-Ѿ0s.$i_R6dylڮ~%\z]BWSZZE=ß Ow$׆uv"?)iH`az7 YJ'pfO:ؓǻdf2d]Ֆrp?uNeAlMZQC3/3S69VE>xW,SS%ECl k O+F>C>F5ifגac by , }S`ۤW3Q\sI)ɀZ4ř_ O]tp" ơq7E*qmE<\:)KM>d>z?jμB6dSibmIEl4윞 [iP=߆N[=/,;Ӻ+B*w71GW FQTQG="* .:@3b^ vBf"8x܄XRcPIe+3J-gDFGo([{SeLg7` u]@a߿G"Dc\~ZR|&|I+ߣ{ە-@*p5wv"gthe L-Q((Ml;y.Q朞"iP1(uc8`d2^',`팷#_݁< {{DGg/wTWW`\%4rs>n3dqU%Et Y!<1 Q%Mxt.!0=k6DkîR©ďn²^5PS9yCE~PD8❭zhn[;jVzU,W@U_,񷤤{mkp4DYKۡT"}B齳mc@ش;צb(sDNp0,zv6 mL|m/ӎmgjNW[F<RrDxW[[Q=~pxgZ%$"ͽ\Ug_c\*G`}1F= /!魊#t^Mp$65 z.0l`C :^҈ۯM"&zݝDҬ?z)TqPi)9ҾOh-RnzxqZT!їX(9P(ODD*g8$S0\JY|zQ4gO@dxk끇.1mc|qCy`u1_*%ruA;sD2GM5=m}a=Ż|Z!1 &'(kdiXKleZ<~`czun*e8s91.?{1b P!Iˤ/*4/fW2> ͨO} cn5RqO ;4l>q&8PO ` {/:weQaam`Q^ 9Zw0rdM63]|̓bhY6j%WTc+}ҷ4RYcrv3 j)X+] &"O6"OBB%Eem_.N=Z%Z*]4ٽ%YjnxǞ vJ{̎ S_ɸݕkA~)-v9y (kbǽX0miU=rBds\WT'T[Cxij+!HeHZ}+-a't'M(.DG&~P֘(zE+e8@oK~$HfCLJ*)z!%dcgV_X%kmF=-L6}1io 1Y!ivNMHnZP4ey},HwF<(a9H o%j4eq \%|'sΛB<խ0|u1.x| _jWrrYE]1WI*N++ߗ U_2y?5 ҠSh^i V Jf{( Ʒ1EFq,Ek V|V^?pRJYoì ~LH;J Po\t*'۬sÆ˩ ]bIPƻRs1ˇX6\$u[Ҭ]P:ؠw_fXwI|>}sKFGr`t+n<`g(]Wj eoLrTz`. hȼDcZ*?-6gG2ڪ2.ȳ0 7;c*#s85t3 &> 7ylQ깒)rO\rHݶ`Hˬ3Q.V[?؎5T] 3*>y=dLt2afpB\F<JhPDO"͸*|w][hivo؞rt4m\b-a7W (Kfvh[7Hۏ'ؒϽUpݚuuRqEKBQ:-"@U ]xէEg"p6j1ьحwQ=pq*q/gь>M/g e硗E(,8%|ٶ$ q 3Ŭ:N).z\g۽dR`vs1)??ֳۛqxb/YyDNӜO /ղr%go_6x'Js`{ztex/O}yzʷ+/-\zvtDx7#eoу֔N:tN^nX} pb>λraiM;hߘ樥 wATA ` ݕ b%l^F*mGҲo"0;R0!pq!ɉ6U`t_0D?ɸ ܓFlv#<\!/("t+BA"{4Eaqzo(1tLCˇ3 U{Gy*qcju6S$Y.!%VI𕏩 ~vPge =S;a<9o ;㎒In'igLgt郞~<@ŻpXZe@?])bM5bw%AklGgnI/g)mXq+LȽ"t#yB5 +IZ1`0P; Kon`!xj^>[nwI8N(u}EXInq[CV}"}m801zH j&K'T4}ϫ~f[F\U,e>יtu {n[ܚ )fWm8mѣh!x7"{e$e.*h9ۀb`ZC0|s  cTFkk[ܥ יHisd:mkZ|iJ+kꖍQњ3M\pnYӹ8v8 B֥-.٤hk6Io wQ$9RSE7+ᢧu3N= /_A8,B:ʹVX(tdwC;pEtaKEĥ%:ʵߋ@ט<zҷӘ(tV÷qG㟏rzF$ s]ǤF &z'5ז@0mwB qAf# 0){d+nT^`i.j0|LYRޙf$ac\Y)J\z0:I{)^A#Wl,/Z~Ա7 CPNDZq-Z^J鐐h4]"abeʼDlMA8܍)l.ɸ@- & {'ػu.I7Y&Tv1[2/*(hMﴆan8`o?LJP@-W)xAmhd!%.vN)}Cc<6Bg)I8ru.EWQQtY]gO&Tӽ߹ Ln=p[jsq&YuW:5H>K(K+7AMA̍"ql,nop` n HP7L ,Dx?xه䜵g>F?6=y¼zfKY nR&Kk+@heOpxX1SR_hvm#6J f{8gJT#]8_YLAw.RZ&V Z Jzy]2 ="Cn <>'L\G e5 W,ҡ2BrOaF1fgW'kOf3Cn9tPcZUÏP8l}Ek m!fM:fi $9>֓v&egB.Ji߂48aMQC(ZTg u dag6*fӌFN/orYK: yIdr) A屰=qh]q毬t k;m*mI7uتN yZYCco(Jf8nRkP필2}W40{p~%?\5]IsLlS\VcV{D\w ,4vX_4߯f)Z L:{VU5~OP0ٖx~ixNlBAϫ`LtW:Ex-&LR~zZG-ӥANrcD*Vl)ʤ-rs^w'r"2rCw -@kFFc:aEٞv O8ynGLu[?g[wo:"Q#QΥ`2G<εEX^Hxn ۺsO|0]bOﶲ l؝}֣NhϜc|3G*s) t6ȕ1QNS0ɜ 1@ʚ5P1mVr CqPMPPp莐>՚~ն_gL5D?K)ELRdyt f|UA[b>N1-\G]6-Trn"YJ3xõHg(£K@|6f}4"f1ժE"aڜfXZ=]B,O(DlXrUГTsi]? 812!qK/L8B2b$`DWs!N@4QaDVåGw#{)pmm7(Iɵ{a ),{ v-Wˮ}0^g1K})E:%W"{laaܧ2V(1*7i! 4߃F4jUO浧NP3Mv-,G}C(ֶny8 \x+fU \4ۆ6(~ǖRPkRྕd[ ϔ*՞?"h C\S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4PKUF 8Xh j6$M#g̚zs|,|+@> 6hR`Jy?BQ+ˉ֐;{;XVbUa7MDz;ֲ[ܟ*LDvEG|@|zxg\^AVFV۹sֻIVa$POr0i-tHGLe&[= X8#!ikptx9GpTd WRqFty6Nϧz٠ua&iWq vhΈBP&F㩖BJޭ"A.z.T{g'i|w"qZ`}D7l\p]ԓOvC *XFqonSlly_ ?>>`/p?Z&>rYEau}uІS_Pr{ ݬ;0--W(P|_I MҼ_n~%ǮO8W9CȎmSχf܈B cBP#FK&*dB8_3FGsFpIH͌HiW5= ND7[(bϳ쎽plPY'='0R|B'ؗsUv1.Z%N0zgђ-ŶQFLYpI#:51+FLO )&0లq̓%ǒm=Bfd?K"|33^BYaprUW{hJ_̅W9+4Ǿj ks9T@[,jժtNFVϸ_2 CR`dz[R\銜~: PBLb=M$ċ-[[zo8 k5eC$2kUAۨ.zj;ǤUNEUՒ1f#*0[řGU5n>[mܻMWzƊO/RFSs.2"W4!d{)lw~2@%-')H$A$N @sd!+P$懁uf/K.jn; 3!LCY!5e2ZMYqjJݡ9Ej[ .L~{C+}yh\#LO 3/~Cߓ링|.O[Q0! e`֊+"!P?wtMJe ?U3yA'Gc3iJOE=@X'rHkK-V^RLiP5{bĈ4Y`<} T=qHzƇA|/ 5zsx{V9닺.g8ZS)rՓt'! uY|ɱZx%MQ@3 1 hL*1?vK*Ϗr;}&R4P*`IU',(ϜD&*z3AK+I` ; h=!Wh(6KLWp%qFqE'H(dP8FE7Dl4-]l^X*,=i5`=}󁆂cЭrrCJ7咴#n-* NbZFtcRŐk/!SSjB>]YUwoJ+t`8kUtF23p`yP4.b6~+ypXڻoM\o -a|2E*'yTnc`TiT3r.W!v7(%e8 /ݘ$mÙ,aN,ߩX.I5wgDkxӲ]@Zp[\"wΨ6 5~VV]GpIX(LU_?JXTOW &7gYӱUQƴ>\o l$K#5( MJOT;)ƪ+i =Fr|s1kǀ7g7w|T0NJѪ4U5ճ"ڭ\> mDbؗ"RrRT0)9kZ[C:ss^J2/yex'Td5z ;ȃI^ɐ ZolOXih׊U #5|T_. `#0 M?By.LXYD3SulQ "rAg*7QCטx x֎%k:^W؄ƤA{#W-{ģ&Io劬&ގcnRYbXXRz[߅obI}(uOlޣ\H}EyF}N+>5ۋ ҟtRaN iVE2!Sq.Š_`5}BϏ7) gZawqѩ*c դ.6S "»VsMieMq(%?'T&w NEu8aALUp' ;.ScPp{AƪFENے3.4jyށpj<Εq '=D,e}V6vӣ󫄋lrRҙo..A;0qdJ1_{;kL >CO#^tCEdAkDPd^M𫏚ژH*ÇCR?`6tk/k(: B~=[XX3E_Ģe-)uGd/M3y&s';W;l[1s 1/{Ō+^ɾwC1%"P֜f _OiI=]j(sR6Em%V{kv] la˵~z≙R)),,!E4Аb84 Sǭ9VK3E3Wewӵgc.Mzu#@_'_P},ɂBtm璜:C#w~ :=讃\1Á̔"$'MM烬._V91Jl\P#V]0˕ Gn!Pljݝ8~bݜ\M8Z͘zsj.7Cc;O F7 jKig/<`{dv<9ѳJ`fӄ0`i̘:ei]`Gu2ۀApN.zۅ!\MBZn^ rLjR ]ȦrZBXM2?!PНnp"1\[nGr,aQ]?h.ڮy~h [˸HLNI= [qc7Tq!{C)FEU!V>jC T_\ˉmeF0\I!/(o2#S7OtQfCp$Pm~ ]zxCaK.excw@RF~-mA#PʺC;AW Dh s{_ܦV "C PBQ}FNν}&Ý4SNC7؛IjyP)x`W+[No4P1י Qpn˪F iesj(pfB18@0F 9{p'<6 v ^iF?#t@0a vlطH|I.߅+=a4=!~4Aqy@|]q/C%%>7ԕ9sO,ߍC/#W֠sq>OBf![2KE͵$Azz5NAPU&E\*Ǘ.h K\GtG+dV3A6k:m~w.ٌ)0 QsJ}B*g:, bfS/*,zct:U/nCv5;KJej/FBc5yo: uج̌K?d:J$C5#7*<A%,A#;6Icd0G-N%] 6Bj L` $ 9?f..NXLvZ5$ "-,+ng >lh+C 8g/̟X0hm^]bN I>>|VZ`56:i5<1 6jPHkYTO*!_T)Id2/uD@4$1TxHPH8@S~oET!YX%⬆lfddW`S|(?\xwlj$ƧIj"EvP5G v 4CIlvQLZ|n 92)KmKΊpk6$MM%&pM׼JnfX*,21鰻S=%k Sk5=WMLN_3LK šOB1yi>0Fa_G%QPxo8-f #@sV YZH;]^tR.kР; JB5 ,T1ODs'F.RiȞ'oVx?Qu_%,ҭahH&'0щUF"τQJؼ\0sha .|;bk m0ao8eC᷅#uAshQxM2/Px?[p #;xow~v@MF~vlOԘN12\6rF0QY?||$@|bQMp2uS~~-E —x@|j!Esk FTy|a aF5h=ѺTs"T5HҹzU@=*njRmA0NEWIf0; i4J t^xcL:{տp>=)萈eA6т>ƀ.塝ӥ4*sNvww_(g' 蓦P2oZp{$UG]Wae}%?&-3܍з zМظj};1xm oJ4}x,[/D<,W.Q {)f QImP_LzaqtI/*Ps )Xw`'XݢzZ%^ 疞>{".?Dz0>uC㣩- m'|Gxܵh~, 8.RXOܡx8·by$:%B,r4sAK#>APѲyFZs]a蒵O/N񞔛fju jOxBUۅUJ @~ yx34mJ*>`9@W23z.Bk{<fO yWՉx~Na HЬ"2҂Ň#|fV8, 46|;"I0m0v-mu(*,vHohM/1%N㥨Ac80Nͼ J-I#dvP9"vx+yjtS!}ㅜ{ENovtUAឯQvkuQ @FF9_$#$Ug= Ŋ/7 uثMJSZ-w\C8Km[=xQD5`RoaxDr+3dct~=*pAıHF8Jd˲tXCjZ2VB:3cZf_ne?RDa,f/Z$=gVݹ@g,Ji\{Y=]1Capv \P,>[fi Y%dibK2r8:҇Z'0丨œ R;⯩d3 =D+wk/ C֯.G;@_-1}3L^3\hk*aP\Ѹ*_GV )Pi6@cDU<>*nMW-eO$Wu#z5v䫱s嶯xjZߌg㢃7\YN0>#q 8~$>Ăzzzv#2Za `6,^;•ҩrL 6~ޛрr>hд-N7ajW+dX@W *HCwG{_+䔀9&;Y߇GAa<)42R?E@3g~oQ*1 ԟrI1g+TYiCZNʃ}p.kOc.YoM> s&wǸ[^^9 4 $۱kzg_L& |RI@5&O"B L[Mz Vmqm-gS)iq||~& v|HL}e)~72h]3f~Yx%l~JcaN;]jϓ{j-m Rzr!M$Un M$˯KQ/@Q=&(4k>:4V݋ Vȭe':F)3̓.Şdq>DQѝ=E#DL0H =cςYP2^t{?jpfQ9~I Ro1(fv 'FȹD97&Hn?=f[veTcLD_6<>SJdH6L*~2uN O@r֠ H ʬt²N#y 7Iyy~zR+dv*ߦ,0W6$aeI{]B8XͶ3z5@vcyٱu&<lj?B|2BZYh~>F]~7mOsBr7?ph8Td1b{-NZHZEKwd)l'*ӊز8qQ 3 1EeԲ\E:kU֖&|ҍXLƶ;ٚ=d۵(H00*㣿;P|T ?BqNoUH=$ uE(W QuZ" p7Pn>Ϭx%(en&{6,uyEH㠾QE3 @EF)ҼqB]PO|b̔ |p{k&)NhdA?®Z~u*5W[Œr"qaTNA#+`j]]LxuU wz*TPqxxWЛ"*[䪏Vv*Iz#x*Am'ܘ~Uf{[hw8.8\)7ov>E#-;bS[sVMRx:??c|NG}*>t)Dg8 :zJN^'R  p1 Qҳ$ ~|Q`UqQ JF7O v| I6Y3pwHC'Sn'kV\cN-|d`ns01_׳9a<Ó6״qIT#Ng:@p*"~<ۉv$X /ha ؁^OFsǝYM[l0u QӰS=M >X&ʜJڰ5Fԯ{ ?a-?&Q1hCl&*%#I*bFtI蜋bwF'7|1IzW֪Drb]͆H<~ohv+GK1>Ͱ&ɥtGIi _H南kÞވZCHG6wXU#bk{sG ~ZjDLUԬu_>qng?r_-kPq= NɊ >PzSs>6i qAWIwsv8eU vd305C F%Z P# n4]88n pp^4j_C'}G]z/Q}9meVbbrWׅ.xym3,`(u'6nE~OM;3jXY`Խlkds*#0C %+*X"uTF=xR-:KəHw,5 h_`Gd>݊\AL>ۗ~cv XL.x!l'K7i]Ff=ޮ~?x]wt0_b$*w%45QOdEqP$)IT kd̷ J9]n]c5`dz^vE}vs <ש>yx)cnԃ goR(ț?4cV"o@#w&G)kb+}yCbЇ4) ơܭJc )dt 6;-||@|b[Xha_@|j@!L]캵l{EK>i-3Ns/ 1G,E.N%d&6%8D` 0W'*ݳ  +V>o We=eي<&׋aXƭ>=1F/Ss9t3jre%~kmD2]Nn5 Zҏȋ&VXWIb!VFs%Mgik;#o/IޟgńɣFk>.FBVI 9M (قSpO2}zǚ$xzv&~S3l2BM?"w%B"ڡ 옹PQ+9Z@1# l'V4 ҩo s=NNs|dJT)dl!|!m9SʮCVBZ4j顭jcR!1𔃪ˠJ& U>mY1 i $^^N6D-#|Bby"`c;icSV4hwR>YV~Mww~2wTxV}jpͤ^82*י( gj*+ۇgwT3N1b %\ s&$ g:C0uښqOP1m]>NjfȁN.w+MlY* "Ҝ9:mCYjÃ@/42$m`r(ߔ:cĨ])|ܫL`.pK03E*g 4TisS@ߝL )4e#0H? OCD ƺF;+HWwېkc @4 `Q N-[8$Xyl*EQ~&+z6 n,Gqg&D_A3䆥I3 5wL~Ѥo)"JH\$o ٩vXFo[f>v"/,yJ dH̏y]ߺɻ=֧߿?]Qp A}ޜLG$7?U:U ϔőWtHD 8U{][@Bj) *JEQ'^kQ;StZsrD=8õF-cJɴPFf X]^rpH| Ԝ8 L_)*Q9ZOܝA} KV-v50Wm` ) QAҨ OsEER VOZ&[5Ka̓ ˓lT҃^MY0p]B(H4D|u95h;RL6^_1 ^nfϐ Eڶe¡zAxkcd_cN5<"ŏC܋ѯaF6YE2eϝ6 F#&1Bb5O1=#Ix@ǚAƟ\K8q ۺ<t.q-fƑH55KFZõ?_ЇzocZXx_g#{hT}&12X}KEV7 wX>loOCX!R;SU$abwuOys`{yIj [G@"X$>֖) 9~( *91%e{mrrc"Ң8prᬢ?.Fw?MzIRA0YBykfaJzz?*g_QeP1i!S'^kHn0mFbsݥZ]W!*v?=0D*f4?viO}cV,u׼8A&fnipj٤߷Pu5niϑyK.f&ӸW A 9d0i\[^׉keQg8vnMI'ⸯsl$/Xd,AD+\N?~GD` Uޢӫnu?Oy@Fh޸]3)3l[Bs!9FNs"w%+LćuQh"pASuR<ڽ[]<""]c;Q@v~? dxW;kд7Q~ ]\uUe]7|S&>kC*#?ߡF}C3<FF=͝@r Rv6tJ7|&pC8J83=Li`- մ. eʜL!s[o>p"}"5Q➵4GoGb=xUDu_*X$<-S_U4SpW|zL0^{*?aB@#7FҏWPYteXh!ѫ3Z2h},jX%SFVLƹ8h&iǧp⋱oi> #W:O8_ٚg pQtXOsd, i/{7dy9Np6,8#1r9rpɑb45yzWZ(PY#uQђ;INmT_R\u"Z bF)tADj`لؗ)iUȀbs;-8F7r::xqY]BoxEHfPLC&I-Z3U ﮃy< ƱSK EϗwpXzh4C!YG\3.X0q (K?TA/AENk;,g[:+Cg[L,Z`rH~o_td=wɰZ#U],(Fqf=Rg'ۏ [^yH李NkGVo%2=Dŝ뷻9t2/Z}W8^ .C8#Qr;!NQgBg;NGm1a%}I+;C0Kno TzΊqo *dd"( B<1 q&:9ZO_AM=W,l_:󀏸,N,K> FQ,:8H PD k1Nb#'7wNf2o|g@=Fisd^f/{^m-S/>Z4x/F0lOA#_uD|-@Sϑ׷}WaaT:)@#AכMk[6y: ]-t"MmҞI,Sv*s$tv Ѽ Qu?Õ'cBa}r(Ä\5柾Ձ(usoA|Dώ( q4|[z}d@հe@LՕ^lzߝ0d0y Rcl\J;X/UN}h%6n'YLR̵ᖤr5%+>=}}F0U`*x2W.ib7x8]+Wy^/6gZc^keRpB&KRDB rzo z jܼO1T}9 _Y| &.a;*knjhx߅v%T?r=3nkvǖ->%G&i^^:{V~VNT]$ O;ipF "k~EsѸ潨 ] ̡$%( uOVIxO<߉nւiQTr))ZE=[u_6'vHFB?KḛX]!DhxV*Po|q`U`&|ry& sJT"qe.:4T.@à#>%BKG wzsm뻞؁7A r:iO2B$9 q17b9O&(Z/Hެf @!:;K)p(|=Wɣta' .HC4jv9o^ uIS \p&FuuXlWp=@!;+4K l d(C@t!Yt8w=0CЍ/E/\  ,}i3C{\:ꘅiO]G*be2KڧVrRGTHE֮@X\|\|WqE/7}^%\,t(yڽ]bٝeUU`7luAd6G~XCFLI2Sk)Xp(=f-na0КiFTPdn`A˂') v$,>I %oz|ø0.l; _Hޜ~/HDbA@p!>B;InTMS-ke 29\3瀠dGٖl d:Al<nw_#Hx5ufE^R+,@\+AF6;懔+\_2iXvOZZD9Q`[4юב v@mRQ 4Omq*]b}6om v B{S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8OЭk":4@8-_hೋ:t {h"*FeC o#د0:B38B!;癘g!E6_% azߦ_|@|w@0HK@r4؛l#:ŕv(x`y־)H(ۜ['ӳ nar`IRK&EB9iX{7AޖЁ)$~ ݬi]yo`\#J؊Ua;ǡ5[<ߗcL粔wTOt.ut;jS %#_H5]5C.NjVfN?;q8upmށ IuB^B] apzB^x.*BwiT rL eS>杵w!')~!!k:e:Mkp']J R9>`&[a 9 ss.J3DQyFXWq*WJQ`Kb5mXKYlĒS1 X-ňk*DeBjLN^pi8K챕-sI ִéBF9/l2YYqG[UA8 'tqzG/=4ҒdQ#y~G=|+O6l?X8@xw#2Qaӝ"M6!h:!^d8]Cce' 6:˟;U5b@΃ȋp]Uj:,$,7rtn|E^&?%ֶ>KN=arta֏5tU;ҙc{•C )+Hx?;}- Eiv|K{*RGHylݦRϭ(W2Pl,_յC}I4wi~E]yGCq ό^-bGfqta] \,r>|ŗ͛l8Mk7 l\n]"0 T+3oO|Lw2D`;R>2Z0[.RwוNu0mi._GTÌX(6EoPon^2o\/].ˏSc: BC?^%rߝzW\.:gKczIq8G|iaae`ص&=/)LJ(0V ;3v,xaYX z-Ô`؞0%QѠ+Ș`݀f g͗ b8jyeCS#&=;ߴ^hb紽Zىy?jr >kX`l;gdh<暱[bP.:N^}}0&PƸ$t@-29a$P$FҊW1`HoF5̉G5U="ںՔ?5NHJ4} uDR%Gq`G,Eb J1.waP('5 PrE@,\}dF$Y_ٙH1gwհލt.ԭčأmHfڊYm@k'MU\^zK,8Χl|z􆓪-;Eԙ)B 僦 81kf7Eߴ*ďr b4]qZd)>V|QA?r4fGC;y !(%'d&tlXG3Q) 3xQ @cu~ I5;T<6e]JOg_|#uҤ8y245&tBx0Q%-;y3^r}ku5@v'C8?MRw)t{,%o뫩h[4:$T 3LO <Vdv!IAJ oE\tY8m2 [a {W0H\^Ś^Wg3 α Hs0ٖ@@?o*xxq${Z1h^{;f;AioO$ġV v2kȝy)#DF`#UTRQ0l *t*흈+>aȰ[5=Eq7vf1h] ɆhoZ~GD K;G/`[=Юi-@z5L z2Ěb=`wzHXswD:J98GK o_\Xɯt@G3"dA7@ZkBvk3|Zc`L:lyƬeI (*Հ4RkSgK>bIr^O;PYSFė* M\}:*򵹵=S:9 N{ ?.{?W?zox'\У#9Y=?O8]GhQwTk@:iE Cv٣CJa.8|' 6~^?V&+[rDskA:mk?GR${ 2N48-^alSݯ'Kp_jS,CSƫj&dO~D%z>sUIk$3 1eS|Ѕ_#QI  iF؂h\ԹFJ+ 4 %sZہ&pXJ޷J'PWV.ł QUyn<ڰMl˶ FFP I).w# !c8_+Ecio={&Q%jռJ(>b8\LY7lMҤecqdUN֩::7{=-/[ 4=0yuƈ![LA'^S6GI 8r֥?Fuw'RHKպ:5pTOyT`8D;=Tbn{m+_R}I*dJt(Tu`7 z)v+/JĐyQރd5'VakڮcL*\oPHBpxWƟ$+C?:/8,Ev+Fp-#0+A8Zd~dtZDKr]0(+Am>H˛F4U4 Q B73v$_Af|&rE}ܦO⊬lj2 (`Ie =ɹwU9ϱ$޲e81tn2\kBVӜ +qH xQUB,=ڇB87]+{G'9tš:'⺀|Prȇgcn[&\wa^Ӆl}8DA<Ƅ{kz. RV $7NR%=/@zV=$vrhkd4𖃾+Z" KGe:JX݁ rM;e7JIPx/b)I&m)13 qug0+(@َqQ\$al6Di-# +` J, ϱG$^g(ݑƒZ|37;h V3a(B,B҆Ou)}H8flHL hr_2P%VKc_ik*?K&@9i11 bX܏(t衽հ>Nz'A?`ו6O/,0FmW 0a`5Rhd>LS#~{7-W_zʪD>e-jdm(QalB j|@|@|bRe @l7/r/c^|Ƭn61QssX E/+b,joQ@yZ c<4zkZ)ΣyN9Ig:FC ^H1&>dP<L]p>=%ڇTj1ryS[[.J e!p~@\8ͦTH)M#ɶ8@YgQord>B4mw! ??Z˃Vh q͇&"K`? ;OyW(P68;'z>FG@? _U嚸B5Ȗ{L䌰~y#H+U,@ y ??=H-.SqHܼ> yBs6hj3Y| $[Q.dL #qzEDʘj3-B.ݦh}4P)*/26p ,6am^bA.UprTu7mT:ҷ'L? LUhF|>v zJGNy 3y2vJO7DlTCFA8EV:ۥY{7" ?㵘EN{p;K5ns݆:ZS>p/`ఃN7׆˿ \k>Dn R_2dF+Cu)xsFSi.H7B |O]v<~=m;$lm9|kz WZbUՠi{'b)(SQEz>_ (QB7B/D Bz\TpI_48c)vg_SC0BV{b# a_Qぽwr 4CS3>NP}Eȑ"d~CaDPj,?Q QH,RLj+.%+r2%|71k80B<9sѲlLj G\{ǖ7 تTχunW),^*+"a(5!h}WmBn`olv=>#9f0=?wvPuTw \}ݖ^3)_yۙa-)׭=5>Q v) CKs'(3 /$iZ8O68f$לb |ud(oӐ>: sltQqjs7Ht%70`` *tM`Rt!2 k{ d\i0TUWtK=eH;UhKw*;c ~"ϓg6 (G[ƅ`- uhuzFb+,c k@Q(ùd E2|?@rF>|/VS_ț-4!H{/IZΠ& eߠ5.C6IPL~Z9+'N}f*QR '%b=Pv'Mѡ)cS˙ }<2Q_dxw*F gF( r-(,x + x䫝ֿ-32G0QOWCRAa#LW_ȜN _?ym@ oMixh:,j|x} *4]z%伉ł( |!&YEP|z5$F\%i3GSlJd~#dPKccIǜJYoO3;XN+\ ԥ~^n$d?pYl{BVDͶ aкz 9\yXf/8] ('ejT}X85#8ɢSX yXHc{7GuP9<@`V) ]|Zz/;(jNy;P*4e ~cF6#(VaGjfh4`y3?z@l1I493`~V"&StBȭB&.&k׹$xל4TD;mI%8o"LWаH]}ɘv۷1y3 gNnT6ÚLtӳIYƑ̵QKh2߱=}@tPIXR]n|ͰK/˫BV%p?q(܌}(N+NsHC͎}% z\d"a @1Zu!lOKnDkQ@)%a)$m1NUxI&G `\9>60ۊ!N@L Gsa܎`S8ϭ]&֔] gV.Q_n=_(S8D'JsgCey l$EFIIzz菬QL|O fOLEۡ+/m\QzI=~iߴE3$'7f'HPrPE? h7f DIIi$Ex:`{5gvɣJ w|xVC9QN_KaH~EpӍtZ)d[Q"Dy k?-3KA{ͯ EE5T:Cbeas*jWR|&+nXP%NE.1{#wDKИpw"!L2kR' t]vFU&EwζkXvg5@ViBȎ땰1;u>us`.(=G/XnFN|"BC qF᝶c9RUdș/Hʃ"݋u`:$u1 ?0v4 !DʩY=HӤnթeuwIݠb.p,:haj+J.Z=STg!DZsa@k9w%nj 6>ww @w;qR8xP ܁ Qjҁ#X1k|j-.b-M^@ɁXq:7s}$=&ghXkyt,כ/=% /8 Aj۷e5߾5hڜ|!c/=&NH>=1 MU8OzKl%bzvR;6֐@swDq7\,ٲ*{Z)o$ODx|Nuakop18"Q 5رg ;NE?ؿ/N\؍1W|"YMkB}z̤}ST V`ŧ=G[2((ՅmF ̬ˇ֟MҊ}|Xgd%P>A7Rb+\*L%i/@t.3HAyazޓ:סvv>!mؙ# U3 ~Ɔ,k& VكcϏ"5݄OQ*q\t{cX }s^л!uy^e'̚q=Y 2iȆ:\ؠo)C\ZWAlH ơXxIwsbaJ_Qűxƽ#;<;EQvyfsg B{ {̧"E'%*im~W3aMU}9Vg.c6e8 d\uޕ`G!d\&0`#! 5*ih3n|U5l{LP5apl; f,U}ZF7=MDsi^I\׌9S)=aؽ lfض]Ih,ן#FrOɼR#"N[|!_65u:T"qMK?T} &^|jEX~&aGeY bܠ+<)Ijp-d1I)G~ f1"S+S9RY_m)}wEd鄭r @{(֐Y <  'i6!Bmj#|7SZlDisK}*Km4GE{xTV5~@W/= JǃuGtԦ!aF2tkނӇ֊%ՋjȲgVQjB6v[/<{KElM~FEz>i16EcYݶ}0yx8j?٣VSfl-&%w9dx4Yݏ49)h1b`B59yg!~笸?H#;>IAlp8y v)x!!lƝM=jicB|C UZ$ti!~Ÿ|cvjYw=IaԻQHEɤh\O(Uq7xNGw08LTN [6CVn/e/пBI-ݵߤCY7I!okg0P0OhJMv lbqYN=*enhrGKrLu~tX X -0dgV8_,Fd%*Ը -Х7rK}l_B*%ɦ?AKa]}Mc!\-z <ㅜ7 %s$hg8 cȜ d8cNຣ_?/`1zO]:$<~#^HtOK~ƴ}VX}la8D9Js{`2խkMiӄW "X)f?% mw"8X:}GZ}Y&tjS9o| ~T><- 7aTKd4$"X!㺖J,=-G,*$=q֙1&:|Hkg&X4K9[$`'!3[OU0);b[Jl82J'tN#.EG <Εk+"yk洐"B{_\ܹ$ 2R,(S W] mwTU\rE-S//Ɍ$c/) WýK! lKk1=0=TTBHU?;u7m+;{xIq&pYIF:74c\Tyr+=ГF,Fcp1߄IA TT"a/_srp9y2gjVw|8+Yp&H/ۡ _#6'Ûm?9>6peEsFjSAp<{LE^n.F?G.s$\9κB&?{ 9iyy&y -E۰W]pyF{+P~.䜴z;0.͓G۔i9`ޜ&\pv8ʲA H˪p-棻2#-a#"DE0e ZTpx>f"z漑mhMj[J==#D )]Th+9awL{rg/nr2YlTFݼت#?l 95*/aU )VGy=^KKh[BFp(,Ey)ߎo]zQ3e#Dѳ5$/D6l"L?sK`S`f#D@)hg$ɗ ]q؂WdSnfs) U68Oߦ gN] tGy* 'Aq^dW 2yHH&I=:upEraZq/ܘ}︢}0Ps]42'i6qdCD#Feol\$.RM4k>Ӊ܅\Df^(rPa'"NbeP.ye_D Ft+Nox9tiJ r>^=?KoAG4 9ubhK, 1AWj* |{_ZpN4.agۍc{^45NJum)Y+ 3o.^"[4u둋'x;rͧ7:cжD>4~C_ڭOmG7/˩nVE MW֙>@{Uy|P]Ƿiyy@(#f1& EaQlt fK\0eeZåZ M/1'J1DARvq23sgPn~=(bZMÙ1RvԬΩ. :-j`%: |L#$n aKy&x 杋[k;G<ãy0dNV%rߩc҅߬I.7jmA|[V@&qJ_%p$f068Al;UJʞn iA|ԠLqh t>kbz}s(ST \&^tG?f?* Gdu7P8$.Vc=j*9 n*HZ [gLbw?ٛQeT4/#ھ դ`-S:ɦVYwC*q=L+6&.}MQxT{;?Gv;P%"btZB˳~xw_R6,(W]u,FO>ȩwеcƄ.x嗉۾o H3IRt :9b] 3+JUgo<; }!b|b*Y"w-\[vMiXWՏGCZOT/yᗬ rU"MC)qMߔ(ST{e,X ,=(dĎg_ T%k۸#56P[,*ҦٺS>>lIT}(~q>Bue73XDH?jC} MYm2ԑ1Qx^ y.loC]f}?6o=KR<-ĒiiwH# gʼn '9lL1dԹli Bl\gN[g9emKrtLBL|"-7)uϥT'W:XH^3)\wc{37\>ܧS[`\X5cE>ŠY^#Iĵd; aa=QmN[΋f}V7CT"b5G@m6|Vp+;K@fbl}ҩ=gej'wS ߮(nOų R@6aꛊt4 20d<(Nվq~k\ĭ4ߓ2 BS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8!z" #dnO8h p_ϢKc({|+@:x6wB~.[m?'-ZC&vlں0l !MH>Yx~> &^鍔??`6< Oј OIwԖ't;{*D&%?@T8hB1}QE+ls=ދm"XVYIT8F:'돱<)DF :]Q0HeRGWn h07~~t6{յ#Ñ+l!wƿG 1Hߜ~tl܍K}t -1Q_02b#q彔J(k3gڂ-z]}F`a3KP]bm/t1xLd"E`l.oN;t-_ IGv>M Kg3ڒݕh K>gxq$/!a&(BJ ~ 5xJbwb\bl9,oKh%[fx y>|ڇClx.SRBHN[p9M8ɮk\^"mkáU!;PbYz58'I>,Ʋ2H6-cgXE')YR7=_~c KP;l:O?C3~ѷx fEп{KعC(#MkL^O<%j7 !^,%UE~IkCP_"_ azb(C\INwƢC%| UyLVDR9{]P@6+3z(mظ ? =ta Pa6:]-','Ԅ񽯯6`@,рophO @~wJ{G#~RyUBR)àX;3<~ %n1em'Şpj]zw "Ip;Vۀbe&-|U ʠ$ 7hiy'ivz"(| QB-M޿^j z`Uz{͚hs2"J7tcҏ̡Y("H X{*WAKpRQY\.P_C;zP3&Vl, ,^5E?YFǖgM zƈh{lЍU֊J-rtTْB# X-AU1d窩YXKB[ %<#n{v7::enIp[bsj`]r5VF1>耪2b/o!)*KTh)3!}Y!pu H *NwY&=k;#c7Fd[Fq4g7"`HRnGF; %;]VK?k[ ټYo-TZHy3%eR$"yұ&1AY1eF;6'v;co[Q:^h6&0rzNdQHA);ٛ@,SڽYBK q}י썈0YB¹% fD }}y31!Wk?_ _ `Q\J2 Ccb@gzj`ȁh#e]psI1{ l]ET- Sd\5E7_eìF)~`I{>\kRj :4prq\iΑEȏ[Siskf{n%db1ILYyp)Nb9!$roi|"cDo BӋyp~֧厁r(,A"#^nL3 NCw(6>{?(Fb]q=L/%~I5RtC 9 ivn,RQ%*]Jͺm}o-M/˄ʜoi}ؖªF,2#3cdc|3 Cs @c-qE“Az/2DlguLݪWuš`lnx>s7%A|sSS`hA\${Q]ݚ"'u/a3U UıZ|ɣ^zNgS]Zu!ĈW2m`WwN]ՐTAӨlT`PpR(\D^>@;^/̖ZYݐJxlB6JT[Ě얜Z^Ո-Ty:aяX  *ۛ|O\(iDġ.d5.;uPM\DN"D*D|wTe$ {q`>}["oIfd˖: ĦSb\ ~,1ve&n\[s&`UiÕc?oYfxUNj8X|M=R 2Bȣ㋼ZR+H(+=O}9k `gSf_[k@}J{S賧q.T 歋0?dBŭƮr07U_ghٵ*m{98CRyE/w?!}~/ǚz0PrA8]4׳@9cE !M#NFeܲ쨖!L ygNDcaW?y¾+Jj3[ =~Hqs$ ٶuPp7ո$2DD)WWrW^{Pޑ(Ե'JG*ܣ".|痂գsm]4gY,KzZt{u^ ϿSߨW_Ff5\Isg+J+Ul|%~  җG+9$=mh6֌39%ՈƖXb7ґYbO4;(WCIY!Co5(} $!HغTxD`UddtvۿR,:S&Q]ze%0sI\a+XIe~Dk<Ӓ]uO}q4ץaѣm7:՚-X>aLTby0;dξF(+na+DW#5VVHWT$$#a I 3d}%>`xj:UjR@  I>!u$ǝ\4 \Psė+q5*lD7E΀4G)!;[ *ųx fxV/>1m=mkRkkڱn"Ƃ_"$P"Nv`VUspn+2 F}KXh*]O @|Z㞯u)l|Enx6?l<BWyMV"ǫiD7x`}ğkM;@'7!Y!uՃݪ mJ>HߵbZ/々4ȬP\]2o3E,",ԽR sF #O prg$O,SfEY DG_ͫi܍ z8lQ$k߰l+g_{`nɈ| ėf=CUfT yS KA3EEh;av"bs$g,4=t(ɝ;M%hzlb2[~uF6;` :0*c i0 90ѽpt7Faub1:3!}fe>!q&YFNi(Q]7ZS (Ft9ZSEnq I7eҫi͞m.QoC$tEfBvXdF~(.\nE:[!#01[ *6 Na=;^s1ע e 488<24nLY16W0wii dxBD-0&gB 7lXc!j"O g LFsBzw"oDZq jiבnS,M%y;JE7K\)%TRNҠ(={ct;ӡ)سm߹6 LI!ԥH8HѲka/֦ u8kF#!dTR짆TO3rsGSX_qt+ڐU6=kh4&cۃXԶ׶7p3|JI>?6U.LXo4uVrHbX7Qʭ^7Q^¹(Q Žn!9 RcNn졇W][SHˌKsiϩQNn=[ptԮ/bBbC6y)[ \BG3y3n^+ nXrLnrK<N8"I]Ćw T ;Sǟ9>2zR?m,ڂ$oyMsnJ(QDT4:RXڦ:rw}ɦmϧc1[Y#Fc-]!v1 hg7N;g5@PTI c_K.y&T&THAVe--8E{ʩ/6T$֩XyT /({.;:'nmy*V~4oV\<>cpRRsmt/'M:m࣋$$~owˋyfq=kPN+bCmoV0L>*\%ض(7b^E 6^wJKgݨ(4qcfъQ / B ǔ`Ne$!)yx4-GkYqAaa7V5@<ǁ]0Tc'g6fmkB'[TEh2+F% VHǡ)w^?6I^9u{Ya{zw<=Ētxa$j86~l\jP'd|OtWw#35$9Q(bIɒz^Bk%DJ}ee]vBC7cIŘC>WŌ%\"!+ 1/ԥ?xNzOw x| 7+J-4'@*quS&utW;{сԟ3 {8oBk //ś۹fI @ر@W4$.T,Q\9րt4e.iYP |?4(:J8Nb=p }L1)$bBw%;F\~~13M(=AHhJ&.-BxkcyG 7[eaFC=ϒ JGy #,[ AGG&X, ^Mf.`5 M( lh.NO#qJ!-+-gB IRq=TTb.SB:=jCq#9~чk\>Wx+ l藩7bF!'ѓ(2WsxVxj"A ?%ވO,.6@\m DQ.j)i1SUE&2#2ourdn w^{0-\M OzIsvDd? C%~ @P }ﮆ (BÞi-Y3њ Z1j}TrGi^ &=Oy/‘Xs}r_ Jh1瓷@s(ܖN.%!PHNA̬[C\yGTk#_2.("4"6K;T bN^Ҭ"cQ #̷\r'jID:25WQvHH +\V!r%^ lJ Tj[f3~C֋d#}޾Ϟ6uv./AH)Z|`;(ҍ,| R/bf2*DtO`;p9rRitp%HgtxW}zRρ._"0~|5@u&[-5M f . Xq0[{GD☯aV"'7_VYL^ f a Tt4]9!e#TwMT)7r:',Y|"*vV6sOӍntuޣFN=݀Gy3CC$11h(#ڲUDl&+MM1lROIy!h4m^n"r/|LrM3WzJ aqVspCUHZ؉ Kͧ.~Sl?~M0Rz΅#脫-f(Ĕ}b7?zul1RLe+[,**#4ᐁjl@̘ɉ.a9`8YmZ8 }\ 6O^ 0@mL3l !]|^16NJw*Ny6w0v8l0?;~`wP\=1]3UU!OXVDTܫ=ҖВ$`Q9}Ս'|`;v:Ϙ=jsl&rR'wq T\G堂#m=5SC?_oJo NC+4eZ%}"\tZHΛcz놁_ 7u{<^WL OE$=hS03.f7J:{ s "?,=GtR,q6q|ŏÇZtWd2rj⯝VjmE7ybEp~cY؊0՚}4Wj^z&6}k1m'~Fb2Ï[,nm Phe!<}Tkk :Uig;ya: yJbx@]NQK1sr("s hdQu̻tᅜX\g:E +sZ =0\ 7Fz`ϜZz%kƊirǴ@AX g19 !G%4ay;s$@ F\2w2d׋_+d?)<=E Eӑ<~YJ3=\N1m@R=~&oTv9v{β`r8zŷǑ}}"I[!`3/oY>}YNtU,FTKSejkQRŝPhHƄ_a} /z$,%d`dgs6>Z2l2$SfwM ,gtt1-=56,jKpiUauiMI:' G#^ oBEKcI5(\O8kJR㭅#S.` C@`v B}^k}C i=Q$X]ON?y7@Ƨ˘1|\-U&]VV&/@FKx d8!fƺ~MRU4(c[N(zF2L~ 3;-RS6!k%pT$c˸WArΆ56Ыb@"V| t-hF:g)4q)|3b 僿z]]@+d1)~>\&`^,\:C\S'nXsR/@?y& J]GP9v"V<sj`{$aӫ9oH )/e[bXߡ8b8L.W {z@.*ʰ/^rGֱcdRJ샚 ׇRc,)I_0s>IvT^Z+!:.t"Vq+]㣬7qkh #Q_*"5z xN'-劀-Zي,;KҎB+xfYOOD u;IOBPL^mKM91$ Z+1 [QbGFg7!hڙwjy|8pL1({QE7nߘdW-!IC}Z"hPwɘĉ˃w6 1ZD*xq@ rӇלW/o]DgkJ$1#v4dU5 1Wۘ}zW"}n;XlMѩ])ߘR\G6g%JFYU2>_&;yt1w=C.a•5U` DKJƓX3#u-\M:M7TٙWVȣ7&s8Z}A試ÇDHLC3Y)%r"'Qn\y7xAp dR*-%\F]`:úT ",*D q'?ﱭ\d9ikGZÆaފ/N8;qMɉYn(H2( ` P с/4 ?x ^S ݇0 ҃k-R0-ci\k_i龠r4qxD'\bg" #֯pfY||@|b<3PSl%65I@@|j\ lt-OZR/-cr;}vp>Ln*8ґe_$lni2Uź[ĴG7 3 C$jhp\t'm0V*Ź`E8ClDʎ}__/P/(z]e92!㡠{OA VŶ~)"dehQ}lluat֒J$q +@,] u4\H_ n$ gH4A@ 9EsUv/,_0%)]evh飫}؂%y+0hcP#;Azw8,_Py-ʙ3S1b(3 TA& monq_h- r@|FWk= g˧1}ī'5hpS叛N|4}h}BI`iբD>='imH526 _5)3_x!f/&rcZ("C>nr? C'?\@&IZtpO+\j.%Cb(W6#Hܯo>wTeG[ NnVwK(f%+TY|@~ Q*RV?\;zMl]%? z ĬmOokgR~co2o5o gfGt6 nчt׮5lWwtuƆU닊(6(MVV  N66CӦű JkqYf kǺ^A1v!c`O<վ6~?}uۚ5r%KE$),2/hG?Npѥdi#}b5i*PRK"@ s% @d ]Jy|p1l0 d$E4n{ Uhk)i(ċ;fWk-R\ݷUmeQQ>|s@)AnT:y`7yu6$8.%0Eg6TP)K] hY&:V&[?d6#| pLJxLhUڥ1GRlbNa˪ ɷ X~'SS1bw;zy-f_g}wě;,0(,·P"ŭ.8vCP7p6KɌW*hb  |ۏu5l"8s0JAL?vZ;x:~)rg/\HB|dvfh2؉9r:39B+}^r(A@/csF6;zK;W41%œ$qXyxY řJ~:;TE B N4]J\'Q I/l(js&_?ҪS .y4:)#~1R؀f,Ococx#^UMZWw~9~Syt8ЗpTM4vyBՂk򗸪&>2up1)9XK'AK >N9aR1"vW0SFmĉ7EZH,M4à^TZ a5_ĺ/B#;Dwig~39 2]>Y3!q &)=='Gz#<`*;,{t pÀ?jYrr2feU.{rY!opE1^YPlIaZA5UGsBQbX< =zr([[*24<&Mlw'Mtl/*[x妦+\ L=Y}ۜWW3 |f0t'E6pٝZ@Ha e T4 ,ujp'jX\|o)rh Inrt% ipH/p`/p84͖SŴ$NTD  D1^D&K;L߻؎h4/ upJ S'$B0^ӷ_*,IM`hGQ=>13-"Ŝ5=ػX(8uߪ&rJO Xj.xZRe|,Z>JD+U/ gR- ".ym_[ypj9ɔNN:R]ӟR=WFeiLrx88GzMd²0/l8OdpCMdl;9FW0nLB+Z)2ov j!?DR4؊t_Xz[mg<ͳ qlkmP'3X:-nHVoZp.,ͭ'_P\V+0G?-El/477E֬UCW^QG(Zu@:ܐ.UYi~E-t ]A&wM:(-͝'`5So;i(ܼYB~R,bFDs)yO,`:"­~_#޹8,͇u?߬Fi7֦άvYZg`>q%@0{$C˸.;H> @M[ϩbVw9`$ȣ"C1V iD.hlnt"VqBGɈΕqwrٓM 8 O-?fi')d%Zbk >$`` 2λ0Lt߆(|BS } t#mcy W OMP` QPe' \'*%3-ϙ0=| =@9UGReY"=I@(OU,~BQt #lާ.-dnGl ) 4-Jౘ|ǮwtDC V!4IHztX&9ضTbeklg7hqhYM3tp0=O˞$205%wȩqVCr|j2镈$Q2lZ$}~B*xf80zWU~vk%(xՓvE-H02ﵑڄ{;=:b qD7Ռ̺Z0ފ>-p[:˞D>l{MIݳ=xBF(YE.#%9mW@4a=Z н+e@)2|%RM} Ûpf ʙڀ2~4d@BI^' )gjhEufLLwm >v`czs4 Ex檡ZfP8v1J'Q2LPAXt+cҙF}v54 tyX!?X s fVhmOEZڿa>\?Qna>?ɮNiCGAde'OwR<盛Mg6Ny(-UeO"P_Є Le[|;,ï@|w;M@@+kk?N ٶT^Y>^t_" 5;&O-3`v+ͺ|1%8c152 e'r XA[|(Rb* +/ͽ؋IZG=Ü":}h}4NbbZJ3 QuׁO_aOu5Cl^-(dIЕ)5o\w^Հ'-/,.gui6H|e*K%tu*,RR~ے=.]N=}faB;cF0gi9dYhvRNxLOÐ DW''ܠ`J~./ u ++ 6K{gU8$o Q4emM<32CݰKDcx-˩|{i'>RE2az\XL39fCLKxE<ݳ|BJr܆(q )fB ݠ%׍ *|iqXY U)dY(;ѳҝ#NːW f:t.;xGߴfU0{g$*> C$M[7ZNUY>]s \ p;gY~/A|f!vds0 RH>jBစ@ ).`?>X#(GI!(< 5%D?T=߮LARfzl8Vj+$ݗ;?%B_g5yK 48IC1j)S$CXOZ:Teę`@  0 pÆvMS0Mi.}[?DJGp_&6k pf :* M9&P۠QV5k$,WthzA[ `Oi4Mx]-6 ] x4K z :@Ӛ7#0knETF3I$|+%+aOb723RE+=&D3ڶ-% |nuLhi拂4ykت8&X kwp$M]uqA= t"xWD/~γʫLY4ļQúy3IW D,u#N|rvA']zXdJ0.Ti\'C>!FY%o 4b#ڸ3$Ez `Jjrr"tL~Jg`~F?3~\wя#nBjC5;wf|vZb) x*R|'6u!2ͫ6ޠk:;XAQoKC^Iw ~:s-b־iSk>BԳ2#$U6U{ ߆MNgWnKW%8rI j&v+C |9 [_VύTbl^SpKڴt:jjRL2oKE/ >\Ԩ~'1kjN (/01Aco9 Xwv?qtvN-j'}'q T\ipcEU #ɲVVˠzO3vO9.TQ'&m#j(vFkY-a L%r'M *@un fp;Iq. Kc}ƥv,B?P5Kj&Lg*&\F-,ki~K3 i* *ϊWȵB8%~9A=Gʼ|}.;{Dv'-sg Sd ݇c|b8jv}n0CZCʜ/mPi!9f?u3_FWW;_kJ'ׂK!J]ʼA2{[n1ҩŕ>KSos=vRzwI~t.rވI{>d$PUF~(jGI!k̼1|Uq!er1"!Ȍ};M2ҳ>*S|~/\|}$KjbY>ykVTI]CR"V8K%yq057u. &d8E]FęP G"G;Yڤ.W<.dgp~8Q$aўQ*yԁ/ҵc s.T4r\'R >$tS< \EfOV+fsJbpPK"ESS5<`3Afe-5q])+)_Omv0 7g8.w(IJK1JwǿV%v|5V:ŗfJX.ֳ;Fȸm 3rJfamnaܸh -&A'RгeL8\oHPl; I >:y)vM]ׇh뮜&,b@ /ѱ|.P_J4ɛ$%J eFor9q s{P̅RLWEJHLl&4ӨnY є)`hJ!i:1_qY#9@eqha`ߔ7 ~oRW~,w?.p+隮SҘCT!>-䒥&. M iGDqIGŹ_>S>+n#V^TzrX:E@+kP2+Y@֜[MMVJ /|^SVYMd\r.(L(G lʈG.2cqa_ܚ3Qm7R5jTN=Muytl KhT ~7WXb-lqL !wta(G?'p)+(ŶҏUOGؿ-Hӭjmv P }s褎B@7@rL2æFԙJ԰kq G }P{g~_Üo&C˶8^]YX7i^8- nX_^M6͇S!&e#lAM Fl &[=<^ K#N:- zqCsfttNRz P&ܷ 8^!z;fL{"%&]P ]p M +eL-uttfoiosϯ&?1aX)AF)S%, 9Ls\ՆyV̾6"TAT,wU[uмin`zYyͺU_U)_Jz)_-#AzdBy$x z#k^RϕaC~ك)H|:Y6j <-sb\\dO䈝& ]hu.dp4p*܏a1kn=#/g@T1$={j6H"F[f:}赑X8~wcW1ؼ"Yl<}&3x[rJ$ W+^MuzA H>Qb5}g.gK[f"bp-%Yhޞz#li@$AhGxok>)jN8deImq˹lÔM9MbH<_xx;VhR +ZK{a_2M: etiDyzuꯖ7DIP[WqzGn探ț@]" Wua1)MW^fq+WPh)UIJkG';޸Q/=1 DQ>5=Zܤn7Ս/;4>ߣYJv;O*鋦۫@3LVVuzIs]اF`/G,G'TQ#f0˚~k:?+ :8};dQ\WӈX ,|Ag\${*qjF.mK|L8}5#37c) BZh»0 udg[jo(NAx2ZZ:BSJ-Te'10'j{8ҷz1&gUA96k2"~GbY@ཊcn)mQXEwaw?iHOE%GհbChO)޾i H3%ZZ^"kğg5ԑ h+`N'kZ^aEa_qOy9pW$oԯkQE' QWP (ezv پ]>`! m-o.@v,ư|[X[ 0Qi`~R|@|@@]~ Jc4.`"s.x*պ-xoKF *UԅP&?NdDZSmQR ,ˈ9zcKԴ)xpGkhb<6|I@|z0FZߠ wz@}pܶl ͠LYc M[ek[L?'F4fǸSbgq8Kh}? )pCͭ4#'Qj`mڏg-ubi⻘mc3 \E ,JofapXi ]t5qH&XAvǡU-fO?E$bu ;1؆:Yi$¼gw8"ixiޟOt enKOcV'SiY8#_3UI`0,J)Izl;P ܖbˌ)qmq3wUn~h~(sOz>l mxB vwB2ї4?䨖9" V(>-%kl@:ŔӹQztTܒm9Kb*Un4"_ѩTqP(=Hop` @ķ<{DO6 xZ3NsM$Ғ|>/羓|8(: ~Fu(C2|؋)> z|lV1qWQf43zSU5)3T#\C*T/klr6U Ӕ9Œu3*r*!Z&"3(rX _ÓQ?)wZ!:7+lgmsILnAX޶ޯ:v g̟1U 4n>Q̫w_q1pH_jiWXDz?ۆA:)n\Ν:q Rn)񮊙 BW>-^]v~Vq`DCqJ[+R[[p)䂞54믺Pi-vt )=$'KU^ LK!yB{m\DE|K ` #^W{F6:S{qϹ"lKwӑHyD#SCA)^g̺S-I 398H@X?D| L?Uu BJܗGQ56sИ||%&صFb/\C\u.{NW'" /EN}^6n㤡> Y=MI!&rsU4߆WbayF/nC_/=Dr㙯#U7$z1 ڻ}Ot6Jcs|P1qeZӃ֞e9E[hQXSa Qb Љ!/kݚHffm]8j#Z^n#'DvEn'JdQj3Lf~D=d 6/pɏEmX,k9Rj5?m؏ܥZJdA馸]s lTRR'/ KhCYs68oK . +ggG_.rroY9%%LG{yW^FaJP2VSoɒG%dHBs vѡtaL6,.$䟡t4{T=sAyXyi4hXKOaYE˞2_YqȒY8L%gA?(CB˸SEu\řW< 'Pn34 EEA"g̎ND &߬-NiKCcO($xƩmNG&?{ KV$CՕnQj=΁1ojQ<uCFAd`Й PWw ^- sꈞFǾ<miJӴG/m]0p;?r0ji?:?3ew}y.%4TxP^/:"*Uj@]PC+k+~֯xWBԓD5eZQeН|SIqʧCV9pT9MyC J G%Tm6h]5?]m6%&f)ZÌzz#_݉^Pǎچy8֊Wһ itM;8'I' E>d'ۊPmD]o]` \m_B&=Lh*Pҝ:oC:(^4v{h8I2%=018ķ&mJ$g<ڲ zz^@byш}YqBo+<"%تg-ˉvR[N/BjQ죅)-~EX'ڰ\8]scM% @fw/ߙ7Wc w!#s6ʍsqpۋIEQs`{ɨJwtn^Xur BKVU-h8Lɑu~Nʵq >.$ra :;ִ~kW(zMu8+zG f9EƉ+Ot_/5u/R<5AX/1Z+1jiOȳ>pO1M}:M'b^%Jlj ꬄ w;mLiV%XDBwl|JJHo,$I沥 IxHn[[n6EݕʋƼz7jQ9&!l|?]O2YA@ 7is+I JI.Ǹ݌":&t=b;(ӊ㝧FmpU:ycPk? X Fܯ`?||@>jZ $]h挝 ,MXn@@>pCW sAu59{|0)|Z^0PY9S PR"~D6=_n9[9^3Zk 3I |6@U`k* *gB4zJ 0j&;gr|$|B乡} 9*L&Wײ`Q8` ^9۔l 3xZlN>~[tu@OXhjj:K|>c=v%B{ ̠XWB;MF'pz]nj9O4<*}Iq<TbܝO,AI!ꏩruAF=~~P['Ϊѓ7nfUd6v1erz1C\8aŵ0MDܶMibPDE7@4DFRh/ӞWpQ5 tՍsVu '[ZH|>;}g@}q=|jG,qP-}c#y0>+.ȌBùO3Lz ͦCʚ&NwddOn woMo5y[Dt/>D+ @_=0[&+#~.G,,V2j!HdiH6(= 'a{@ m^YMoU[aPind:&?b08M;]K_GǏC5- -RcGd'ՌE%-e;) }q|SE܀iMչV_|5l+`ML9MMAw8c_?=aMDJ9GI6}[[bM@FuA]{ў a.iNw9`*v|N% q77i4~ Ks)kClD'k] (;ܐ@'-T\YRmo(ayu/nQ IKo ɛ Sޡd6_ei$u)^>vZr\bXig1`ΈS 'Zy5aa$錏 |G/<ʽ6HI:R/9g5|îi,>i2IǕTl6;'7bOlvsg\s{ Jk0H<@F@{rYjo5=7ܞ`^|Iu7"l[24<(!6WѬ Li%:s[:<]V[ nܲP2Faӎr㛒=K͹I1tpe6iS 6U%zN(sC 9j;a+E5144gY3YubAQ,PGOnS=WB6xEP?W%ͬ ьG/?2##]+9L7٣$|ń`PjVO=4_Z*7>0)CH99@" 4>o|I> H]]?&[o\jHSE!:$]OEK .v⢕ɷjQAv(5Ei"']QΏsgQKns'/EkX&iwsBTطlDYάcG+zkOM!fV:GTrq 6D\4ԥ\*k^YT :sK%G%@?Gs\l&ц~":{L>F.LJo5xY>vTVǃB,)]`(~ ,`>fDu'iT6VxG8S {x&κLGtޠWl+@뇸G]? ԳK+Ptsd shF@ؐ΂[8+2~r&ߎʟfe=a<>iv"9I8E(1ot G-l6cuE=RC/;bBt>Pbj/Tt|b}Us`/,MȄfJQWYE? yi$ܯPT""q UIɨ{;+6@PFv =UU_#ƼjԐ2[r\R `Ll;R*KP0<KUo ZVQ^r (uR8~Ժ rp!4e}EYH,?a'̮s}[Aų)jiQ2e^z;6tD#$+{>^(n"++xj^:vfE.mzn9hU IIGTSQsƁa-Һ3~cG0 Z۪ΔȹvӓX&NB0ÞWm8\s]fhI}xv&2I:'ts&8k(kwQlidkVR4H|4 (%\cbH1K~+y޳klh)>q2Vt{ /A 9H֏SQ*KFRqr0P{\aҞBkUS·{4./gDQxLtzxEKo9ږ4 A VG:+Gkk<~@"<6T D,NV{zH)tozk`'J<*(WZ8Kޒ{@d]eB .Bb/x_pu'Zf`"6Y[)كJZ$G4~NVGnp Zn+3֟nTܿW'JTɦ!4 P\&vM׊. ,S\)|/<$s##e=EӮU{k<~căG\B*qµ,xCx"'0:>P'P% -)'L{8wD%^ O$B{;'b5םCċBfxeQa%3c9+m chKĦwU RGJr@7`-GvH$Xa~|t'0Z֜ V!G9, 'Bfe\a5g|0ۼ#)CVa٬QTT捿xu xoUat,2'%Μm .J^RQ'^k,=0LuG(+OI 4qŬ4BRSQ8lԋVߩ½As 1.NV<#zω2¹xkGלdS-CB=/괿Hn5-`!ԷkRd-@y@svuiYR{:4$r v dQ8\edچA)Ě*zߚ8+h.^_B s0e[N6 C%L;DH~KDv<FFsEx n:h.{nڈ-4M_|MY*tnȡ }wDd*E2YGo?g͑>[<ڬt$3AOm9GsX$4K4^UE?k/'z2{Ib}X?7F(J/\ːNS弛\{Ǝa q#ar#c h&L7\xZ?jM71NZ<t[kĪCIq Bُ7"ϕ,  AS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8[xË։L5)_:,|F|: $r6<:xX;1/SCd>ڟF'5 hKʊ])~_+n*VЊl0 Wpe-|; ò|++5m(0ϮɯyW4HѝQcOd!dˈY!vZ#VƋ 3\}KLA< :\D!$n])EoqRb&;S 1xdjV,KML%*_UѠWGI+b:SZz3#?7mueTT'5nx鿯]/0 yKayR:Q[xDj"Roݵ%]eU@,tP|ƊXڝ\C(@:!ݣg$J)LDhQ5q=~3ߓx>}V9IꙚkjP'쁫zܙkg\∅Zk[9W*W} X_@5sKjn6\Ki 4㳨u GYjb`N@"VRV풹)ѠgˣI㊄?l>sq^%2O,"Ve lI lkp߃8W-̞'9L}fvxDظ6rɮ@ёqT,RGJ콭 ڬȸt@vwWGlI('d#ժ?M컚@.c؞ nguRgswnfW&}i w$Jr26@J`IC2K'o]Fh~ͻquӂj ~Ƨ;exZMB'_ W"?i2ȄN?rQWs]xQM0ޖq8ˮYD'JM /6Ϧ)w L+p).O>;mOpbO4nh_֨gr 9 nb$؎O\>iT ^2{^J0oi5)'!hMm?Ilk_Юf' p4(R[AZ_̙F&U&Se:% &0#'B6haR !=,>? !2A?\f5s6 b-t>$JO+; 2q|u=i`dZV⑛N_p 2ŀwk=:f#3~龱S{*kg"٫VU?o ^v3/MG$ن) ՆzF=*$hzKobU+P ȏ589e%RdAL8X3$+fOQ[?+ٍ-q3D ;=6ZB~QƈH1Ȥ4lAms ku.ՂG]=ljNyxUIPQS ^ kF6" IV̥#n崷?rί?5 eJJ?I @f(/Wv_>X>xh|<$G'#xhRÆvr->&eW%g  C2'xՉ|S`kD 5Ҕjbj.]+^z*"u3FŎR-D+?ƅOS(=NAL0hٟ@SǦY ʎm\$V% 9N2Kjw^n @bۘL51k cP-AؾU5Ţ('n*Ŋdx+*^a\-|f.6XJG0u:fq*cBB'v/ro .&:Ȼ!>,}/Q4" [7ox_AFuOlz5ٷ&J5fB!a(⤁ލc0Y}NDYNz bxKa9>[}.GkApd8R]42G`3$$v'eʰ,Kɸ$CK$pqlx@ti_Y @BtTUB&gaH%:- >E@k(<_@bd _(U'QAk(B#b{k )%B9k)_? rч&FШSkr;<"e҄m VGYu3>pdTE{*΍" ADoԂTiz`䖡+"|ށatOPiOz|wu3\UCM㗢FBW!6뻌_gzԂK>\)hkKTY4] $+Tp>CGNTœ80?9| $ڪ?(~U4&ɷY+A7pƍֆQȪ/[)/r!~CGv;L=?tLXNP2j8L3T{.<+#*@3@*b`vk♻,HՑ!p5 e`P[: G6~^F07Md,Ίd`*62YnrbZعH*Δ0NT7FfQ^rv-Y='S\_ZҾp+ojrxfQ)yRioJ7]2"&q ٲ2"67 e$Q>#5)oeӀ x O{czBt$S_5Hmʜ0rqAw`5ka \TnC 9L::LX{nSE!o̓~ߩ[ʁ%9Ȩ>|*rNO[2(<(!W;tVI^ = Oy$d X *=>fدeY%qPĕ׃,1ŻQ>dPH`LrUsP FYeLME&//Klm6GXViu.~:l]=qc qx&e6mh*f(: iǝ/7\ |RnAg6( ZـQj %H.QS,%V!BP`X!L;`C#7$ř&2Ex[03dQ5Ln{9 kuBk {͹6Pu§F ?2J&٭vOs!ԛ5< ?nh+ ۑ\ÈY{>E8*GJvq 7*eTMAl;[ ہe_τ)xa׫T $hԗ;# .˜7/x[/Xcӛ ͨ~uHp¶5-N_e}K6xW}VJ[T L4U*PǛsb' J= HQn@K<+߁g9\0E05N@C={Xn׉ \WFq^!h|$){*(M*ɳ 3IF0^ GF0$!UkjQm{4_V`~__տ`5~Rl"jJ\85LSZH;eNQ 4) 2]-FNbm|{-a G -%7Q4?! ,yB= h$w$a 4\bہz3QDzEە4Te]Ts ij^D{ ߖfr`'Ќ>OK,>|輷z ޵wVPskxɂ tSmEH!L=_]ͦ6DM.5N>@(=݇mG9iBK.s-e4?#1ډ81!n )[[xۓjS 2%srd]]72DE/?@։L*|&'aޫ YuV3w֧S(>oZb˒% {"H>~^(f`W|>)=yY/7ng Ue|o9W bZUXxPȹS$܀yѼ[1%SYO4UOɢ2ҡDӗX%S"(M O d.^O[E rABkڰ[c9C`})^ K0 2{fP7#*.6/z߽s3ڗkaEsv,Bq q_َ #.C-Ba'Dv^j\TU~u'l`#yang%'0zpIAhor3-tjrWBvS*_ m6B9-+?CY)vD sP'2<]1rAZ0*GqFvd+gkW'D=r7)Yb-ikF+;M-|6|R1Kᾓ2 ,FX(PL0 ~4ۡJv٬'!O2E(QaR|@>@pof 9ߊ>_ wެ|>4P,[ ͘8 ugt= ZN/YG㪔qL 'twᡔqze36fxU#ٟZ_W MgP2=qtg|E|z, }.lH:&Oaz4ausGXb8Z/I[+ϳe-V8AJ(_L5C (f XU̘S I?82|QO^cb/7]<9hd{dt`uwO{g#'պBˎJRlGWN;M{4Cnp>`QD]*NmuA$@66YB25OLCҡ_LU#*)Dw9Mʨ<}CMfcɎ3HJg$5N8C(fAvW  DޘXC/CI!fo_M KNp=hʼ}"gsy\IGCM+#Mt 36B_d?)ؐӅGw|F-osw1&15qzez{ ۚqh.a\JW mwHչ=&%/fN֓LԤI >mjW.; WIO`T|wg(H^ 2%\Y͠2mA.As ;GXMvB171LIn0 < ,lo`IzF] (1NݯJDGpx"g⳨-cf U:EocY|zTCnok{*T ַ^3Yiĩ|6( {⌰{VY&Tr;F >gtR^BVo5;f K[~\siF^R)Lx6xJȆ/hS'%ChCcQHi< 9Vb{ JRCT1ʯ԰ݪ\k\뽔G`N]p%WB;HcmqwW{_d6ʉ0F`XhD Ŭ.іx:c?uv.<op#5}Tu6X*[Ŝ0?%"8q)BDiBOBXHI{%}rYWT~+ ڎ,7{#yEE/SzEez)`oV2?!DۙnN'U*= EV{{ ˓*(P춁FinF$$|J*pfO&9*^@c8Wd3A v Xj˙\l)΢`Js?σJ^=hXR@D G*i#o)~7%9tdE%Y_لUM{ӭ!!p{=A]l0 s)LO#;09Af,[CS!x#~"|߈yhOm. 6q?{ ut)R8frT^q?C=:bN##"BeEo W؈l4A-(94q%H΂x4}bhK|\FJDY0ɄYOA# RN0}9\&?% %v3w:1x2#/m Z~_XͭbT^TU7*a5]8_L  5]ơRk *]ɔJypK?,&Ԅ5IwsT\(Nj޳/Ip<ȤbFv<VbqnEk8ؙѹx]pL:ѓYwZ/2$Dg bn_6e*4U  "ȮQ]'G6hxğPJ5fZl,!3\=wJ06ԉ[1Bla lv\SbDDK\1$QAhbkF6r=mw ?Ѝ<-3k|#>/d6d<҈6 WDo\Q{AǀXrnxs(efGѿ'2wY6 {"Hvv %,{mlİ<_7֊nST\ b7 FySc] ~ OVj1NUώea}߼I/ 3{V i]ʇcӱhF鸹A=_'a?)?Ĵڼ\6@7~G*Cn]2qrJQ&͉o|h'G-DF/ >m(@~+.p(JAɯ[D>YU@%ѭ1`+KW]oXoRѥkPg(־Kle;V+֍)>O֋b9oe]Ђ%J=b_{^kr^G@#|YlM/&Vӱ\%MS bn?RȹS^_KEE%?</PmHDA]tA\$59-#`|AdcXL2\OUv la®Ӈ=T7zDʥxE]r~nku3j${!9'y&K}q+ɦx1*aJoxGt0.}ZdH8Q],T+U-܈܈Z{xc YR5"|BM1|/=ڛAP?Ifo.~߂^a,^W#Rz:XK<Fiy5X8[>%&^6<s8,:ף vą z>(p]o]2;u#?7+7X W tQhF#sHӕ jJztqgd*qp`nZjn;gqNzSh\pmPsbVz[Mԋ^/:An)Ǟ]m dD{Df;2LhJ;w)@Mz 9< s*$3A.ZBdHlsFCcASܦN\`a쑌#*\S+XO ѐe(^R^9Cm9-}J!p`1౬7C9FmUF% yRR` NyHch t[MA|@8xP#|HK 1_|0>e 6ETEu q|[-wx bneB{,F;E8xI4OgOewp>{Iw|6En[ѣgSWHluP>=#YC0L)MZN/4c:/3{)5JP2u_~74}o.0:hY .1N,e Ec!-/Ղ/Bh0d8@Oݰs'尐xXR cix,HQRč4 3,y~%-\ HGZqq_^. CsT$Èr2ϛu$$O럊:3"O Nl_6UKclQqlX63_?^Rcb&pY6HR{xT㿡 xO5giهvv}R:qJxKeUsQ 9Uf br ^?߇Ԝ G? W<{aʵZ?+Ά2;"!AMCE 09wve 6z-|?sR$.@L+e5aݪ+"MyZQ RB ~:o),~-iUŽQSF>5lԡD$C2}cy0 }uR X6D]ڡJYQѮ\wwOHr9ϕ)RM2g /bljܫ6ܨڞ#AIϥL}"ҐJOվKu=tڹkňlDz,lq&+A8Y-I/ ,hu]Y:X|&?[Cμm7lo/g|Yg٧v*SѠ6˄L"Ĉ /- A*%hJ`aت1S\.lF^}`XLij?'r݅j|scG%rƍ $u \=˳y̋;HRZ}Fy%+Vca"ԽaW!kc?Z5H=6A52#<WTvߣuɬ/,k.RE[@W1L5*l1@/Ɓۉ <5Mxd9*yXmOK Mh3]BUE6,OuNF%Sʄg̗n`W&W\V,氿bR"xzRIfҋcRU\Z5$}. )1N*Q;$;\z4(okjD:* ~G>='x4ƥ~]ץ`w /5,Mol"=I%>h ~ ߀Jf1wgӕn~ o:wE2:q۪Ӽ @NSbi^;P@ƶJ}Ӗ(U14Gs s''>]}PC0Gucǫt7qL&8v+icf<迶z`;`*vQjզ"-^*wѰiyccRx $Άb1~:in(kQ]sU-B@ׁF";y5oA2ʖŌg 9I i}v? p/DL-Ou&}Ut `Ҫޟ–Im\~J45]^̄?#q2ǵ܄/|\P?7PV#dq'()FX.u٪?(ݞ4 ¼o}\$&f^֝G>߁_#2cKUg=I_wÜRfaΌHlYesN92#U.lF; x }QZ.~p,AYNLpx5Yk[7'P}L`bG49}þB!tD7T~\VRЮd畟ۃsv- a&"lUÜJzX_2䯜GJ@rE׽E*,KyZ10Dc"O o=%6k2\xӺhƾݹˡv,A/G(vqTcVShK%I&~cv6vq@' RJ4 _~ktO;c3FK#aۿZ SޏvmyAҿM3d[47&mSEq,J-- vb!x:f:%&6-ѐuvg\ڋڄF4A(ݫz턠Iӏv:'צ˶8~h_L\")6| p0ɒAѦKJrL|ΔI~v"ʎX2mǙL ʯOzyx+@$,{$X$t)Xȅ댰_O' n# p#>̨6 54(oDe8V}t:#-K*%'?5hKCjsoťm3plj?6 ]D( so?i)KKbU5M'Yy)Ըf4 N~;?˂58* 4t yF@v:?8Xkȷ y>U9 3h*\J=poH: j\$eK6׼z7{y(Hɑ6Dsr9n)f=!!֕3Tz^Onwy~NUcbCʸ@>\+diӯ][RJRIJ㣮\`LƕO0S$N[jOԻ. ٣[TB߉H|%ù,&((Ga H*ZV/-Xq8!P Į%;n3jg98`i)ҩmɟw}y>D߱_::kRBN%\=Q c ~~,Af0>4@tg#ao;ŀ ͗І[^td9r ՞ E Y".P|Ć0 B-kmmf3( l:ח5En 좠'?q);k)4%+cm5YPqƏKTr&!^|3&oWlq7FɌ<'Zt~Kw|qa25w8&FITK@_-퓀% 7tko瀖Rž. !2oPCzm蠂Iz}0Xb8_k j/uj,_p 5kF37p,>>;pxbi;:.\%NXf~; q_Ft288QTvѮA`}dTWDY iG BX{Yr_Q*~9@,$},2ҶmJh#+Jř_;<^,y79*Jjuԍ(X9iw˂P.Y40yʧC4ݔ|F#< 1:9ĬVL|{3~Uml3ڥpSv\0C>.U4f;Fm5C'l=M &-?M`MD\i„my_- cSۚeKc(VXa-'1M.7NAWa~Q◴=CȻwBsq{p(xl si Z$U N:bym#ܸ&6F }سrTt4f2y8(xedtyD Hur[mr yC97_ qpfw2 vMԾZb+ )Q7 C%X;/;In\o=0W}DGQXe' ZƇ嚡PC^"wEޒAӒ8ƚ4(q.$a@9=)j /YTل.5 /$XO7/vaK=7z-+u7;b>-Cr'>Bx/@:M31%j=Ҍ79p c^""I$GE#&RAJK9;R}ZXh;: Ӹʫ./4xU6zL\0S = 屐:P.E?Ar%  >VCsS鳺@fz?Ҽ1)MJ1-\ @S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0Q>P9 S:48Ǻ͕8Іya9Rb0(⎪OL]c Zwqקg;䁽GUcƣd{|^zd8o|;í|w'\F:JlQc8)'{>j1)SФ a9fiL58xbj)lX Ӄ}{ e'_ڏbartvs:ؒ_G{,]<Ű>U1#~/6o gS4W"·ILht|,7m :H "}r1 (!YS iR %,E8aDY|=U|倫Π"Ah x{fRM#;M<!>[9`#< .ehMFq'qB-W[ҧxIڡ+bF,f:/-G݋VlN2eA5Uccơ>[i4R$|sPQ$Lj,u$_;bLD`XpwɱFק<>3}nr~5$a7JP񋮤GLPC_W#ə[y;g:84}e)cQ/}le8f2Nu4f8]U'̚9qO4@|]֚;N'G Pf,$1VљdDw"p}ϭ&Կ0tÚO$;ē]Nwێ'ZǨ7L ]"~MĂNԘQW|T>e1<9Y (t)hَЉ;-~%ٛJˣW.DFIYn?t̀"MkJżg0&JqD@&ddwPMDQ޴>4k$x:u+ZәΫG0OL2V|rg4:y<8\OFNg68psJh^]g`VfzpT!&e9:F}-.wH<u&_4{lE4mEz 4JcQ+,U0Pm^#hԶٕoS1yFeNL9EbC-E3~7I Tv'22 GE"z/d LhS >cN3A f {SK~'=:_[R̢լAb2%4f~Gݯb̦1kb8>xXKpVCcUݍc]zE9O1ZUM*jrZbRۯJHۦkLX Ⱥ1:qIHR%0sRk;F sKA mA ~5XQQYao'HL8oo)k E>+Ρ`,M-S>'dDTr?F@me><ݔ\0M!VV_7_TMcJ~8~QMcIUD._fAXZ+,P^n lLj7*)|r6W+ڞ bVCDM<ҹt\oc֣*S姶A\}d`F-G<ε2‡mwg`tG?Ab  gV5J`hȻ`ye&xV~!^D#S_,bOcbM4>yEz*" c Mz|:`r "R~nDzPT0ɩSiDqPRd0UrAROj>}tRZ@[ZuĮ^&fA}z0ƵBSQ(h~ 修 ڨ%8+KUjO%cZiyL% tέ s'50֪ Rȏt歜WQZ;xZ\(="l$3#!hZ{SjvҦUjTZc z!Lh@r_^m:- a1!78m*Suԋi޾e~[2밚E1 P@Mcng x5bDS,N~/ZZ7jVѮ `7:LGu=fL{%6n LJؿQ${JS+"h .dCl(ƂP2T5%nhSvj2E"iu/v,Yg6Uщz 'jW!"[I;HfZm^ EaJR)Up\ pGso^sV.xb90@eq"Z~GG 5 usl~AZ d |FQ+GR梨 [tYq'J5pz03C ;YD0촲͵xR65$Պcܤ%w˸ҧSh'$~" W2ޤ .oOAtHZ1D9z}frܸYѹ7"vak@+*p"iѰQSm2ݵ?+eb`*lYU⪱HܤN fg9Ր\ypb )Y0͂q '#NM4}5P{zGxpg)avaD2eޠ-ֲPFڢKߒtD,145ܛ+ha+BV:׭K- ]YcQyV3F.>?_ ۠ %M1V ~Jh9X3+NU(&^h.wՏI/gVqow{o*{GR|V?1r5?oשgsQ(KDܿno# ZJ[ jܖK5\ W>"#MerDG惢(P n͝+B5F);& $U+,w^ŘÏp+/:y+aI2b_Z+~&OCct ߂uarRG J $ |9z>AG]g~LjT6e$xJjVa,! $$TO.U=Z`=.Iz/dk$ S %.Щ׶J! R~&aoK:+G2 ssVU]?zdsj+{*j@I(צNn:i? fئ\dp|x!t|#A`^\5Oj qEf/ࢄw䎱c>B>K??mNF =μ2nJ;\*.9UKoj]QTyaVڥ=كCZX=&=vNtũn]xJm2@!̚&pxD({K +OR07 O )W oqSJh*.ȍcɵ89XOq2+fb%f "n;u.SB?(իDŽ(W.\WQ\qUx7OK+!D͉(!=ͨY~;ÍKf`ga# #P7J<"&m\N,8pIg6l|~mEɇT*|xj /xvm?Ho} \g*':w eRBW55͔H p=>އޱ]p2'\LO3cW hn32qQڠ y6c4QW^ٴ f>M3&A[=w-^ѭL: S4p˼F+RŗMꮯf"%R}c"|.T+&'eOÎ%](nRwՉleN!MWƚscޫhM?/fLƒHK}NI:]T?"wbŹV'/O W9CawxE*a) ,}v(,ؚb 3誸[De09F)<`Un~cɈ:jOY$wIP'$+ U|=gN3a7v@ɳ +1X{\N7aeDYX"?k8s?L@ :7gwQiJIMѲ& W$YRͷ9So[VƧ~/ƈU%Pg_l]}Qδ 7%(RD3K"T $SaIHP@ƉԳ\.о>0D\8A j.| b6#E7?D/y_n6/3*ŸVWDL-ǵ9S!baVE(ʴnd$ﴮLƎ60Nr&fܿqN>eufE2 Gv>(;T=.\i&'.@9kʑ\ό?INƒp>`ZPmh?d2e2T 2 pk/8G/пVTAw~Na)W;<wbdᢠ^,yup4p@?!P6”%Fl\']?X5ȣ 5&h4:jHT jRNl_'OSŕ c;_z4^.XNZi̿9 _ 3Qvц(:X5ҙQV$~0 $lTOҀ ܟ$tGTܜ\lP|ʂ7>q]M]5^G "C`yV+vtrW/ʰ|ՐiO ͙^cwfFqbav B~wi A6Y@[G^VbdrEcYH;gQmͺKC;qvj;%NzFk}ŏ¾jaC?IZa-E: _ D@J\z:e!eH O~i)UWv!4jaM3 r@1@Gː @z :>dmpm~{v>cu5Q+dB8|DoNm_&B4,QhY^|8xHE hR8?85GG:@|hpo&YLqS 8[vn0n0-lXi^.dd,yT8ԒO 3ֱ$ i`ĝ?X ;y@Twf˴do|D|z(!ѿR~hd"oi5Ȋk ^7).L9\A*S)5ph Z)s0HpD _p٪Zb!M^ L!M}[Qՙʆ ? nzξӢ|Ή͍`J׸pL/ RLdUXT)yF89}ڒM;aR Sd\*UQ9So/FjFd"v?~̔q z[vx\Q -n{]AvޝW(zy^.j[͹y*dyn 'Q_4y ^طpymp=\gH4 |>iuBqRx?鏸<=uO1r)զ3vc̭7B+OS%D ^ ;G9gA{sPW~16bF<^i_kScd6S#қG_4ooh=.R oCezb')hDVDK,i3*KD(zUYYCK&W:S:sg :ұ{w WT#f|Y0,':[~De̪Ya(g2 mJMX`.#HFga^lB®}``@<ܸc8ާ7Z.^ ]#@A p\ ኽퟚ 07]QrOiqZHqrjȭ(gvәLfwƂ?bѡ{Aר{xO?xgP3L q+x<`VdX|<[8$o|60T`"ݰ'}NjQ0 ͎Rk~yvYZToDaV-"c Klxyn}K\'2 1ϲqnJ:1Q++R2_j8[Wo7q`">evm?i8`Z:̊|+ k 3ǁV]ԗ%˺ακ,)J5 ӚnWo7%_|;'.ڄ}%{c@vҷ;ɒӧFTՙHZml A8zYvL%*'\^C ɘ UC?B.CPv4!~KjSFޯXWNJ)OiO Ͻ˃a6= :9Ҵu޾$^G,Z#0`v $ZJ@@UtRfhXXF̘?ȊwR^#tK}ܷ+iֺ_UT!W4ke0*5,Ps8 wpwns7HN =F>,1΄LqFGbaL?m4|Iw)0\u ?-G2yfȌRᆘTHGM(9{֓q3a?n.B6FHY[Phl ǘ_HŒ Bسl E# _{bPغo!sAa zͻ!?fevC@8lsvy<Wl d,@o]n 5ɮ;0yY pڦ؜WOkD.4lwlwBI;{Yj_!CXxY1+8lnsaܗww"4_Jɷf7?ձr"q?6.?n_eZx5"GAf$)D>ή衘Ura:Zj&&,%7y6Q`BI"cz`_\nQb!3S0;޼޽xEU(I>6kc=S=1@( ,-"sc_uN% -_p@Kf8UHN0?I W·IJv0 y2@Z6,ݢoh?:ĻWD2͹Bs >_CXىU+֏OŏMVESS\nV> P]*'w0䜭:!"GVEBpCL:$JVѽq\˪~vfu.s ]ъ-֟ECto %Œ y LJ&ums%T)b2H'ڜRV;Փ7㧾~4$Ђ{:X`X#`8瓺> dd'7qt#qCqCc@6{[f(@w z{%50ls6V+HȰnMn_4e$7)W}/zV{l#g #\wwG{S臁9݁)m"Ǒ7r+eLbgƙ[zDCY7,讔 eN}}f@|C 0]kT!j2;[_I@0&6!+P7+/9 LI[=6}GʅXOUu0}nX /4qLª73 \2p"e d "/HiY[OcυxTa뗈eXGݥ`b ׹⇼#HejQ$HRCpӟQoAЙ߈rnd2;Ff)Yt Ӳsp3},{ЉвmBd0N+lJ d@ PƉ`γVjp 5XP{A9'VaYm6LR!O݁|<݂kPWyW{`~81ԙnT5im7-X w9lG\g1fM# oDd аf?|,K:`ߝ!B֎&-(O-/ZCp;{b;ao4շN`T6g=S&N _"1(P !Z4Mћ= b-=z {s(> cJtVM$J'Ck"BpdQl҂!qSpxiG+1C]pHdCvFe3pKG;Jvĝ%+W$n\M ,E'a5"dR+G\H >gW qQzxD> Y1F{&H^pamebQe\nf_^ [؄ ӮH4*1#@8el:\50qur^'ۅL8vcBNV @-i-~|%r*\ʴlnxWz8H,0H] 2{ JBA}]kaÀ> Ξ!MdSe}jG[| [aseTax-s2 ,R,pIZqa7Gw<Kz85BWM|eR aQxnTqŶEukP׭Sڐ~~㣤#XJu~i9o㚃_|$ 6rx=\4 SУrE<0[_+ &E#ܵP//k oCL~2rsN늁qςOTz)ª%Nncbi) :%7AZkae O_"Ye!NbZ~mLvǿ#U- y.7=lX=,B)Y.( AĕW.?y}a"#gGQ4 oZYy&,ܡјX. ;X O;y.eRGd"?~[ZXAo2]QhlzevB-z~AQ-Vu "LgbW~A |(6oHF27LPT@#/|||cg/ShKdkߵ~FE+<@@|h $}jۻo=p 3Q !E Z&*  3AW?8Y]N$u+bRl@i(-VYAW8@qu.aVm1@/IHyIljil풔}Yƾx=@%(6lGkz&Qs=h=)njBt3iF04DcK{6oεFswZN'.*/{G?ܮF:C3()bHR,$1MqG56k%G%z">nCH M vEn[8W˪މ:Gq>M/jmu:OlNh?ۄBt 'GK(.)N*Yd[}'G ه>vk,ad{IO#JCq 50{B?4D- GT C-zNjG%5 M .oD@ޚ ^@t#^yqPw쾸̆<93|Lݒ>VXvM°4阦)\w`ծ݃cK™>ڊ_e]ȝ ÝL~' {G8[ueD٬_oN\>Ad\EOq}ԿZQIP*O&DJZܔ4 qbfVUNry+.q=ŧo!25!]z+RöƗ7HP۱ @X,"k"uǂQp qH~R'|ZN dL"iy+C_Ke y{(}9Ro,$%+a"*OO"ԈZnF H9epvp K}kp &s>|`YJ;Guc,5{7wlE-Jan~qIun e6 ,jwõR V~PWƖf9cE-k:49[ =թL@GGϢ4mmp+7N3b -d:$_Od6l?Q8q`?@ п'{:(v}P{+NR*hrb͚ya s#.*a%6EreK<ޱ.t^GZtec[f3=:BPO2xgJWZNbmL57'"6mfE_>@@>AeCqztSVW9ǾOeppqp[9'SR (jsNda)lGm"9cfk?h4n"dxߞft3HgDyf 3?z44+H>?>m0tk`Rg+J Ы`v0UΛ&D-rњk_+ht<[ )x}+ )k [W.fX,BϪ4Uҁ3U6'$ x!g?ij-J++8pY mB07'YEi4y5hΘԡ@&۵^5݅`ZP71ETi qx>?B[cnk."ZN0l<ǞnL$)u4)p2^]ס"M,] K9hJm4-dcXQa@G`J5Qh*8ZPŹvՐS$vЩbN$!&ukjnwqsyY#GF*-2 }[q{։BvN +]|^Œznn k˭ m*hy=ú܄']pP ?J_Y˫m4 pHf`Ih v $ټҜ^gGpq#{ua}512=MNΊ5NK>H߁:>fW XhE Oẑ_GVKxte&@߿7N0Pxbk?ނ"\#m̞UC[?A ~*v]2t sWZ$t@y g!x/,Ew,b;UmD^A?\{\SUD>ɕ#Qw0(%6W!sR]^$Aq_z+i{{+œ峜~g{JWU*X`m" 6|<΢RB!ȃo[`0nfp*:9_6o-LJg]򱉫g tS47ͯUsaE}wS7-E"?/A6 SBF,JwF/Pq[H lSڗڊ]#~$* = NuE)04-AkեDd:$*ɼTؽZ=$%aI!: kTFQU?\.ǁ ,||$ %;gAJYòȠ :->g7C{yb(I՗34R}a+8e̿ÁgLx@Np [8WtHs~ Hf뽒EH7±N wq?fgPSp8Ak\urZ3mld`g0]؂9Bq"2Nw5w ;:ŘQJj˯"W*'.>bqX@}*&ց{;(}_&e]QLKCCc*(7>ߠk.D;9q tH~^ fOr'Hl^słe㢻 _V2m}νR mO5klz/;->V[ǪxE,hiD {Jjl|l|rGҶ9T7%|4'L̍ܰ1^2 j>Hfdx~|zя#[,r@C- \u%%yFa'(Yʻ77.Nl5mㄼWtNznjY8f*DA(g6㱴p꿓^c(Vd˳!*sZJٔ90cuU#sJ< cQLB 0A!24cV0ǛY . JjX SF&?Y"((UI%ӆn‰?kKaOؾ4Xҭ?p"WQm>}ؼ+7K|W[գ8YD{}{|6z'slbLܕ8Q\ eLHJc5dwڔ+0>4Rh=njM,5k!/̩8L"q @X!NbT++0ꚕi]{.aM<"nVsT(O5M6{ QcWE$C'`F'd!KIv _Z 5a*4xvx)*-C.ʶ\;/hWN5F -w$/\`B@xLJd6|rO:W3TA>($j2:g냲: zǹN,.Sb&&x(  EQǝ*IQHƍaJeHcMms31Ct_\iɎD]V])v%K==UQq!5>'WNV6k:zܦCcnLA{ JSqDGM ێ\f+Bw Q;wbDkыv#h;!<}MID0bU _#CgO>(3wQD6,g:+kmlT/M%`d he-/ٍsb>ßs MlcRuϹ#8'5\fl:X/!rMT'E˩RB! iƙ|X.珍TuX :0U;/9 H&g @z1JY/?zb+|LSKd"Ŕ~ ;=*TUjkHgnVy9^d'j$[E,1d*HMTD` qj2Ti7rn(gWf M8XsDjT1w-5ssZZs1'aXi>&+ιdE}tѬLvAaE^\m他Dm{"O5R['H ͶNK7=~ a~P=C |{` eגѵbE!ed+.#d*HS,Y9 z.q Kw--"a_ ^]7+ fg`+LT"7o*wB/iIgP78i&+9 gDKhBnv6M fn$;Jq"\pb1ͧ+lʘrZgWqL0,svݑmBqs[1iIjܬ<~0WH!gt ֯#-Ps5"Wcy$ ՓavN%t_-b]Ƒܧ ۾TA : #" ':ZO4[{ګ0|Tw|p ɃjXQ5%=5AƱ'ΐb7El{ن?߀0lD/0 QT8uiHIw!KT=`ן{bԢZ5Hn7;16~SjL).B/'H-?dŐxؽ^K` <סXQ0oWD0&Q{FeZ܆uќʹn1=~="|詅^lO %N3wZҭ_>/?%vNNSJVTSfWNt.7Aܬxӑ}Sk{Y`+J0ïNא7Ǎqm*sfytW̊8_/54}2im m>|`&qxw6'g&d}e@ M!˯+>5R y GD"vHby^}rAOJ #F Gޝ!(Cc Az`QH]q[ I$a27kO 4BI21|w[t"aeoFr/hv5 >mmBbʎH2w$Jyr$<" Kf #T>$я|h,ꣵrmeV[xq[e'C^<:yF߂N'!5}DiWBzznEX:pRl+3K'˶t4Wƀ&dyvm6s!rJTU|ɛ>X,3PF^^n&I. <pE)/goLY^bGtL[O[U<m|$ :C(g٠E g}q#&{M㯘V\lfRFKB A8>`Ǵ;Lo;FgkHD2US_;">x ӲNY63PG ZRc$-B¨vQmm0)7b>[ ._n7YA (v S#]!' @'뻉:`6_g/+?h k!I`}S=stcPhu z>c7mI]h^ Z.h$r)/P9C9~(!Bm-G2Gώ*VZN&9Dd 2ȩFpEiWgǨ\9zl1j>3hbb>cњmEHueVtI/HmFj'< TA Cb&Y{hf,? eێӸYbc\{hL).7x[PG*;ڍcs"}jل5q>5ՓYT(1BDxΔR}%6=S允,"ߎf5ԵOG%~jrwI%:jzkgËdNrbfvlypq'GJI5IY*eDitqeBT/D]z]n=؛x&f|K/) n!KaR$U;mqlz5|KJ#rӹ~Kp}<إѡ[;w1i-n믤s]!Za~{iu2{s>bJs,HnuU[;>yLa.(vYb Pd9;L{ [cĽAr J.J4dK!&!S8\)mT/]Ha4pcT.ջ=V\@T}^א,pv#c]:XV Ê]Op7F;%~{ke3H@ 3zo|s/YYK︅(iZFJ`OÖT./ 'f֠6x(dw}Fk Jui^i)IE>Ц% 6U&"|/SZ\ݰ>aoVn2{Rdwe2+|3ddОQpqNnä$CcTwM>\_Y偠v[eX_.z3qJ¸RB'9\=\2WRӨ M@XB(^ WP`i{P\;,%0cal) ~1H 7q}$75MeQ$:d+Rj,_#OX.+%^Qv2Rޔ}I1WY18* BRz lRʩ葴9M:}_8߻F˸<9@ruV{’#-2FPK~N+嶭?è35N8I֝D ܢ } `%`.J,@sϷD_{8_ErvǸ[rP|[[%[$.fXKrita5g\)V4*d0%"QE;\(fS$UK^)P[c(Euګ۞zɪ^X 6Va}: wn?dБq U5잊Zh@zMX1o0TM'@jtWi֒<^$`|;3޽Rq}2PcO`ëߜunG^wұs=eX / @i~TadIfGoɎ)R/H*z v>t;>++cA#H a?$t>-fh!ʮՉd&XY];۟]5fH  ҧpx6;.q6G>ZP={G5Ebf|>Zey_d\أ? RQ04}̜֠;? $7Mr4 rEt:t-ZBOS쯈mѡEr[h`i= 8[55766Z\ϷWp_yx9*:F$ -#̳sEo΁Hs za1!bޥBfK I!AۥjWNO C@tA:t89x$eމHx*fwE}͑2:E?ӽ YJ5q,&xtؽǍFU#֝ q1?߁  #E>ZwBHgNK"nj]&ԞWMf $f/q}zMNahΗl" ؾ"ġT4?VNh>*onX3CqJK2vsL$XL<.6/|Pv*1ݦsxVZ_T.iBdhP sЙ7~^#pΫy_kޏEuݲ dm@:44Y8<"#WJєDpinh.?@(3Ǒ` /xy!iP2R+'lЧ/ʭ31DӔY-LD2.dnA4ǝ<˻ 靲=#%IÇ/U$>͌Ґyj Ka w3kCyRYnH? :,ٓ(Ο .<-oiZytV60j=~LApJ}y ;XDP(ܱH %p7o6? ?, ~XfG;>e=ѷ72A0VEZ*IL.Uk2hR^A)6C9  Lkfjĥϑn֘\~%džש<~#<4^?GN7kRm@S&h^i'Bs>6W&MWWHTl0B\w=_;Юç['8'gu+ =+l:(l|6$"8R]*7Gd3"]C l~-0j"qߺVm;,x]h=Z~ 0y;ɝ>w(]/'-Fw̕2HEҿtbizќX1y߫e~xRB0#iA~^SF9MyVW*# 1 ȿIɀt= ƕ=!w!npk\3N=.)2L6BK1cl@ٜĜr>|}^Q3Exsv>zt*Ux-_zVn۲bhV7Ja!+~?p@0 J ~$E4/_ #1H`6T}(*.NIgf$o,Vi,4zŢ֗Fíox!eS3<%mblALn0Klibl7l/ pY.FBh$f2#N`tCj-b8N739MF&sobV+8jX06o4{}7V?= )zmh%l ?<^4Ab8b| .#BNzóCt4lh犫feLhGZWG3er|y[ IVD9Xs\6X}|ȱE3eݺB÷4ڿTEvjFZ+kJs8Ǚޒ^A*~NnlHLA_|"uVbB948Ѧ9O/'Uj*.韇~k3\Ľ{.MǟWmdOC#RdyÀ|#[jɎb)M fC6,1,av]zhgO &{[?{{$fΨ(B:+ھ5E`~!?LrXgٶfwبs=WKg\jR8 +|'6.^:O{+aWdMO@lg?ϘA܊qNs*܆9;|6妜ӤOnkSIPNZhzDBr qGM5/`xkxmޝf(|F gf @͐`)}k?#%7:ņiQm '4}3s)Ȋ:#?c;r/SF2_qAܥikkbkQCIT`lkK6g \Lfg v}Fry--BP#X)Q`fEA P9j);+Qz >TEA^2S2pd(۟ 7747= :۾40yLNꪌn7$wñ/Ǟծ_|1J y_ic1dXwo5-rLQljƜcP\7dc4[RW2?iRpٕD'>v:p ˻pDJ6[W\@m 6/e 9bb0eCG)=u7 EHC\nFYh>w.//RE*k:n'UwO%oS0CJ d=b ;\Dx0Ļ|\!Et(]4y/QYV|OnU+bҨv~@H5PL~w(s be7'(ddk"TKfOLN?LA a_):(yA\ 2:Z:g.BtO*CmhtCz\޸C9wV9D؃8AH{A|3CE];Fm|_4tΰ%'}@@G @oD)XN{-YkZRͼB0 hqzӣ=6f:`aH;)rN)>5zEk+UU  =&̘VW3MKhmC mPmL&,*̮te6Q|\ "̏.]awǷb8M|QR^$3L:%7C3+GTG75#戍&x04>Cc&֢s|^v*O+s>h?,P֜abpPm3$gSr!gLiܛywE`O vE? }-Voϑw0/w(pV%>NuϼLOoZ@Wgj5S6a1L+[ x5ʙ^|tnܽo7Ba*(Bw+K ѐ'eR%f rmPPvݮ^c:(6^!U\jsL%|)p p9dONvFt̖+7n>C! | y1mp#d/ A~)@cL FDl,ŝlίX]GF8E!1`,T"'QVUMm{oa;~y >k?7[=Fə: j~rtD Vs>$dp1/jX P*l1Ux2DNzݥzF[%Cs+>v%dnuQfX@7̖lrw8+*,dѷV l@CvXt m$.#4ħć*FZ#\j1'GMWa̟d7y^zp,^%|$@||bP#  O۽~~0ɀp1ަ_|G4K6ŬFVB_ S@p!7PWyEI(S'l 2lC$$:i.!+ ygS_߾iWv} D8~:?A~1_D/Ǡ@e{qN͎V˓1V,^AOlv,<}`B~13&v;u&\!Wwݪ ҎUT~O5w ;+ f6&x災l+Lmpm-4m ;lXtF"3*9lLmFg8vc`@@>mye.>$&Z:5̄SGKУ ^ǖL90{Q9t:/70!хlka"Wg[!YYz~r\NƑqj,!Y?P?p4^Q} V501_V/:̢j.(rY_g? _Լ }?p@O2gXld63R8&[SE^z-5z+zSM) p]@eRz^`A kHg J촺_DBsr[F4@k=Zg掐T ::,*mQ]2yHCY[eHiIxO`$:y<&݌7Rug vA{RŠpŅ28^MF{lc^ieo,D+fs&z"_n;C@GeDr6-M Vd ^7L)1!ɭ~G ?lP̘ ʩZȄwP.b\H"k)8~l/h*AK|N4BZ^E]|fU_t;5jcvn c)wJ|TJiF{@:)=>k:KΤ5QGFۊȪE};:T!#!Cio#h LJ7tJx$_G8if: K+:h_ [LXib[=NVxwϬh1k/R @w,SbQ{'8I;2/C`ttw 庯g:Wk(@_ڟnYRբj+OLyOɚ"l->ï^))cNȸVx B3Bp۩',4X S$1I3kɔf=UlzhHa4 ]I2#Φu՝Hzl^G%$h˜\cGw,rŏ99zLIB"m['쮸-EOm%`DwX+Nݽu%Rlz Y:f0+X]TzvTwGnl T%HV -?44I@*:g(j| r^ӻBLԂ+iPJkAC`1gs?RJ)DG:0=Vt$P3c8sp-SiKS|W GS#R,7ucz١Yo@ș'^m?_)uATںrtBmVZUE$^-sj1DWZ*]%b5vAXᩘp=LfHt k)2/G{>XX0򯼀;h:PP gÀz~ Q rk~#mC?w *45nVn@mXl{iV>yq~" ]bRRjg" dQ[U#9w9|YuPŠ {V kjm>tmC?!-҇J߰[rV%ftXwD!WLz_chȼ6jD_}o/*]Eڼ=`M,VC39toHH j«dh${1<|8<=$`: Jrɽ5(}cSgr y#d@JDr?z>RNNKvd@s*c{s)>_}:|qԁv )Xs'%{N K RhECQ}hX5 pJԣ ci,%SD.Sh/|+@c Y챁ߏ0IhXGX/*T i?%kM c/ JDs ~#,GWilFn.bFM f_[9x{+uk`ago`!WFEujdl* ?Xm/Ji6;)͜h^ksDb r1qAgʤqYstT:͘6͐qAge`g&>MhHbȩ XٳjJNpNň#E$+zIeHyOEa_o~ 6#2&K:A cDHCۆ A7ೋ/]cܮn) Rimٺ;*]5sxKUmuϮdz|iUByk?XpȸpeS3V*>?tUj*0wD`_N΃N&/{2 ޯFbX: nĆ#\F{-l8 3SЭ4ƿKgifS*3{WCS!&(MXF`y%s4&AͶ-*c{/B\2L/C@P\)"oaC.OGQ7AQ+FY=3Rė^40tF |x!U4f@zK1vf |& o h8_7UYpY_KL\,b^[W;AـD޿f5$߶~9_YCzNR)}]VI0` dC0 8s=! ]7%Y)Xo'9C۝u0>jR (1hΡ,ǎy2t(/Ŭ}0[9[O݋ZGnT 7ۦ .wzvGNrѸgЦ[qys69!}8M P8*u.ukJ<Yy[}FM|鿏\1yWz*MOyRKa ں>,,\ƪ ½t6 1%!n$D:nGeqσ`F\zd&X2E]C.2ݓg/>*Jm9iD!x5JiAE-AYLĜ{#4hjwЁ1ݳ`%_5 uŊ*H6/qWSːXꍴƖJo;ٴӑeŊ6^mɬ#+Xm5ۺT6F2c|K]H8U$߹$iU[h # HDN~ފ*nbZ0C5uvp;0_bgQ\8ȅ|~m)As-I_LTn2W(- ߯Kng'Oq["(\׀ ^`nK&T' I%7rSQ11ZsQU?r46R/8,BzL*g  @?;rJ -g+Rd!ՅիF%z6Gj@^ɸ @S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPPM{8[{:4:8>_/9̎uj1:> OWbئ}.*ΟJ#^*0msȬ$%Q,z[}#V9p䏶xmF.+|;ð|w+1NRW0}qW94Y3u?2aͭRh fxkDp]d71z7(JGrtpN3n.IC`~v'%JZz;j hzNGw3Ȇ%J{_K9!QRL qO6j#azĨ8j([t~4VŸ=?6fs"僋e!7*Mf}kR (wUaNǤMzV#+WI-~EGP<4} | -U6ht` ~#t,it[ )Izzg\n5heote12%pɰ@R ݏg1ZAP NZ7P+;?>Maa@mYue뤺]+,r^~4] eS%Xq!B< Һ#Vڊ{2"Rd"JD~IŊR[/MPWi&[Q"%gӔfф\?H%>(}⪁dC'/OJ\^UOeݤoi iId٢Sr[S)kv\%(# vԀi``tL].BG,/7 jXzˑdS?Gr8Q0'E#ǕΞ@Ru`@w$s#,\qTZN4^T'4hH\G"v}_WVAx "]ñꎕhӂƂN-gYx Lv]c ya|ӆ$WtzԨbf1Sq/a(b!3kU _3m~EFH$ꅀnaC9\aB|%+$xZwE[Wy0~c|/Od*3B,Jrfl#럼xkʹgfO [Fa* b[}v)F8zC[y}l(@:gVL\L-HC{$3 Q4>Xu!"p4Sk,>N|%$M$h17*H` DN5 &5@nf  Lջ3IɃЁ8ˎ{ɏPq׿On`ܫB[8{ 艡)\/AD!MJ9obף@ -i{4Wm2Fh8VfiQjS?#^wh]XHhLZD棄]`YD՜]L;74d}f'5 gIg'30D(w@lݱDTF.'y=PCJQ8Df4#cz;6zF><>WG(اfP(@'%"$RCifdҬRIW[%Y|N]"N*_JbYA~|뢘S.<~h[~;`_>AQޑZ4TuǛZyPi &5=Y? ">8Eo3Sۇ'н{2bQu8wEk5م|7Ʌ\ @jO9k@ ¶LE-Zp1\] qLyZr. ;CAL!Nxn0`}0J,p"InrMWס: uq_s/Ñ{?K~Y΃`>KW`0C;8(,K.n)'̝c_=X]bsyxBuX _C#GӋK͈+u\e;KM,vQ)u|evp@NP!~к #!E}Mcz^Wi SmV/HmV=F̧Y] *5A钊|W'zEi8m:"ѮӚ"yξQ8b.BPTăT@iI!dqѼ j7sztGSSsDfp4{ͱa"LVRM1hD}Ao*ĸd-2zoh%ٶlK 蠳HAPبR,+cG+n}Th{d6:*JQOSx|PR"|`tBnI!uO;A}X+FdYi)fh3`zWs`d`ݐAf]g"Sg_ʅP|".+ > O^ @/䉒*6JC8u w3\7ҚV:4):٦[Rک7I[63ߌO?,i}/3fRPӹDnJQķ$ķ/; VDŽ9eF3&Sq"@ܸBm$<:wcg S65ӡ~cqta9nT) &P;n=j>l cEMNx18KiPHD ē/"ݾ{\БǗ ehFikʓ]JEsV?d|Ǣa`[N UO3\ԤEP|(y\385LLAWS|l.+1/ d!lkj~eEc [OΟ,`@ 5[:q፿K{>V]%ƾcuďMN g)iv\2nwS0$ 4ű˫mEi{FE< Ne^+{!3(K3R߻j- hUОA'"+WP``h'nZULJH)Q^F)B-A|xCqϩ C<͕I0vIMh/BK, v [VE㵔,'6]{+ؑZ*=cǡ>9z\ӠZ%IpQ6sS93nAb\ p=+N :[ZRF"3a(%25Dп&Σg Wl`rǼnk͵£x^du5x)*[E PrE꤁I6:\cuPΣ-]tɢ٠U` m@sMQԥ9yVjD}/o̗$Y+U(-)?arxfV8y(p'mꥎ4pwR[hZ ;? Ėf۾i[`s:yžz?@ezͨK0=W/)$nL 0gL=gHg\B77!+SǍ!޾Z`ְ{9ֱ=QWyVA6ט#StB3bWz@D!/:@TY\}H oX`#墌0[7";l5<{d%;TZ(ڧKZE bm>ŋJ:az۟-dL;Й݋^x*cFܫx%42b]P'#g_d5ؼ"߁qW^߰q92NP+m:?QY5'H~~֨}}iixt9T0d~YYLl-* $ |fS.Y>z'=YUꡰ'{ W/溦X8YՎFNznHD/=_lqf_j3iT S'?G,9Qol~[5E8>9{ \Eu'ұD$Fe#o,-SV|rllb7^x1+@A%F"4I|A.dXovC5q+U.Ÿ1dKDEX\YʹLS.qX0s'kQN.@8s!OcWkCr' ȎغnڪTW5ve 9 SնQ{bm&a  hS]8bY5;*$[3a;+Xn%V c+.-HAL%dw툄B1$̀bQ6=@Muϥre,oEEj%PC5/ij ,J=yn4JJk״z=2i!{~(LQqotWe"q,şr4F An$(jsX`")sB js3%ZZ؂- C x.O1i¯soY=0؈w뤐q7.{<,0c&*o-[@oDh30~I2rkAnjԟ6(Hl3^j>otwg\.,U K#TkYG?&AN3> L]W 7AA S)8tlVM= `ldG<'_UuE8cYnHz<_dw$;%h{O(8 j殦\ 3+(HvøQ"oBˊZ 7uWaeŰƓX!xr!ꊈ&^;憤#|p Ȓ6_43fmNpE9]xble .=|{ k9f9.0(/c +GdC*dt5 R7BJQh4Uj7gWyn8 hGc(G8!S7<|*[…n A>X#DG:,e!bIV7FsxC/U?9Tm'=K< yH?G4 nR\@{K<<  Ob EgFч2tTaU:ŸH駱'y4/mڗ 국5m13ܵ +EM% E {h(fWv۫'t`t,f2* u;z;tʰ ' pR Ze Wp!pwذ2ureLs^,Q^zcf7|@8xHyD^pqƩW"/ '@@|i'\9whS)RЂI/&*zcAkpA  v.m_@5.!  @h0X>=!8Q!yfTO9xjfY8y&mVZx%':^ti8Ҵ>VxC U6=Nfn8)Vhx)Ex.b3[#Ò LӈqSmDAWܘz8lkͥhԑDcA[TEuhy剓)hLsl= NDQS.v9ŢAȵZp)J>2/Csc¾t >ѡp5bsr e`eqRhD"hnyɹ8Dq7}&gxC'u]Hwh$``v~v|>@}m+/3P#[fVsvNb{ZF"I'ë$õ*e;bv;J{qUpI.~?D7).N3J_An>b1A%9} OPm#2C-;({6=?JJtN+KȄ%DX(?=iceYA)&'Dj>47m.y0X,Jdk{/r/t=Ua$ܑq(GFmPv5Ado/|u87Pk9Jngbα0ar{<./L1T&xv,LX97n Y@YwgrofJ.4h,9p c$G1b)klFd\Kd7,w%oN\] ?F! 1鬰)Qb%7ԩe1Up)(d7R( ŭw5) ʉgQ[:ܥ(cQtB5[Zƴ .*7gXGլY9jmfύP:MA/ӲF wmt4Un~O0R6=iXq1݉Uu$y֔R{z\>Sܼ8+^§RBw|sxR/+W7=Q]Chㄟ# L|FT.NartU}v 3cIqb1:9',~ |YSV3x]δq5VWP<O1!Z2h*`\И|]9_V`CݰJ1cKe@VλZjctݏ\"@Y[y[SΪEEuu(Jr#l8QrhDFPB)8pw'yaha7zhؾqUk ~Y,^ӫEsZL/s&kgǴOl-P=iR)06N럌~Yv ݓaIhS 8!(Cڧ;A();$\<`Kjz{q]?@ ?'+,X0KyCq!2ɬ @^u V>|h&LvNWеi}w +$Ύ;~ H Ȥ8`B528ĀuϖC41>[b%Lz8*%U +/"IsGST6Q!l%^L|d@UY#$:S` _ʋ%li-vBnl ?^e`( jm9]ظM62zdԠzkC %zFזUN#9HYQ0ҾKg1!sg $H)1*Ҝpa|/ޘO9G8"KH.3!;jF`lc yO){6yt+jA#!V2}YZYd3Nz*e>Q{3/!/.HcT6ߙ(ʴCh,&zFǂIŐǒp X;/tQ!0Y|e.s,S"?݇)*'ʋ*럡jfit'^=BHEʹ#4~ᨏ[[#oqD,^^Y1>źb6=/GM5H-!YTg`#+GWC횘R?0Z;^p4J LF,i~גr;^Dߍ^K]p;zFʩInnTO`͉ d`N~OS Ke%\[ ri'T]"}7J/e<БEwb1O1˵öJJsa9q+aCVGsWe|z"K(k ʒE{' SE&s6KfjSx9z1ΏDcS 7dfČ;Q-cRϔ6/ K_Yj CKT,e}jz9rU3yR { ߵTXX8|ư9v'e2ysx D҇dz ^_%i-ƜȀMW4 =N\Qy"¾,x^=Hdd5uJ=HpHAh7>m l[QdCҘL 1HKDn9W"G~q&G/,]RW u^A &pk| շ)\\Sf 4~M"GaX`=iŪT$<;$0GRZ8\d TX&RfKf՟#ϏwXyo!{iL5PZ+~,&p E ]_8m9SDDDw̺k/w,j;=?2u~7HѶf/L{섏%;U3ZL3&8$ѭF^zxO˺u6 Onƨ^xz @ @A\/i6x`+e'c6b2nHɏԠ=jSZ!aKcq+9t;M`e1b>F`:MG龜u;2X҇>z놊Vq1= S=_$9u.6^qfM"꫔m9!^U@^-Ar e:׵'a H0vˡ4 vTIFot7>Jl VA4;?q4 ƾ7c('G\|*kM>.+Pe:x8陽P0pJ%̾\!0?8q̖2"LV*|(nn'mMTG $h-:%Lٸ7r<NJ׃~0&BQ] o(̇C(턟"Dy 9HbI0TA&_YDg)`> A29RzlG#ܧ&$#t QTV]Sy_K3jQ L6MT$,R1یFG;Xǰҭt*O?74= PdωUeKc(;kcԪ\OFú9KK"?d4+JAZF nFlX 5GhF0|Ӵ%)/|͇ua|1CNVKm1Q.U7UBdi\!IH4ZP7L~ڧ@@|j@;:rաn\786aDX*|,O/-Os^D ze2INm6?sÞj11{BRcJT X5o`4>='Cc\ cW5F?17RD^euׅ0/Bc /A:Jǒ\zie?Q*[&p :"4r~;GAMȢe5ٲkkދ^ *;],?O^j;.b>ǼfNJ: h'RF?!S:L.r8acZ$ ?3 8| { \X;#M3a/S[MTc}Q;+l?CfES(cgR*6<ߟ+X /tퟥ٪9 l ȍ2" pCI9qCC=$ aU1ܡ|>;}u[m5AU@{ i$~2ŎG-2g춧oU#dd{Ա["('nw~s/ {mv(B$._>I:0>#AXuDb!#"BոoG`Ҵ`] @{Iް"|Ic_Y ^no£w%,քuB gRLﺼ~Ʉ3|y^Œ4{jtU\&Awi\Y΅!ȴGj'98W[ fRèhרp ߈m*Eub>[y;Cd-a0ҼH%g9r.v u ,1E u/"wʹ"7^! CԦnswR{qQ Jo M s *mPx1vs0wP=wARR5-Us(3 < E_+ܙ"rٰxP$l/h_bvT 7<ʦ}E6V -ʑJfg8̖>L?٣ri5e¢#3"~5B]uw,j>cWV D7e tDG/y:ΫHb $4*x{oF],ked GD\xJdv[ckۇƁ͆ɥ<[.c'B%lfg_;\%"KGjÓlXEJ #iϼ VFG]x e&Z9 Mty뫸exo5/9E /OtKNB"X$[;<_Ο|o̻:g3$~27~E3C*npT4} B+poPU/].:!Gⲻ6ޜeȫT׊jk hx@>JhYr'jXL햧z b} eOW,m0?G+p,3Bs&dK[{ԛ ki2wrr5&fӴ7elVh_bZ8ZFSWEXƥY6)lf<0N0\͘ݠ;]5,{\H72n*Oo>EVED3_Uwu Hf́p2ₛޡ"Ţ/0lV!̉/d#`hGf%Fp1k J>JMzI5МTК à|%~(6=%A(µH? ^6Wڣ.>jaas[Ǧ+f(6DkϋI/F~=g&^OL"4#Ԛs&LR{R,]P%:y_aPu [{x`/7jnPp]r *kV'srle3LD+} lő*;T֞- FYR#)@#(fo%qt2ۉp k h;hpK/ବc+zax-ҦQ+ݲxʠ<8]u}8w{b*BؑٳzZ V { ǃyXT;aqD&(^;u`9poUOo*QzT2WfU*LS8z1KnOn[s a>kwȦ-@%؃Za=<=h^CY91k09pR:֘ήJdٵ9YE! "yL @@"j/ AS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4-4PK@w8hpH|,QYۣE:xUP#;wUIЅ<vzW8O]֡v/1qEt႗\cZeGWv] tq&s?| @|wCPi=tk`ۢ!xIgŨ+ܸ!UduBܜr@n}Rnc_L; h,H[zypxZL'T2Ldž[?n-jC5*$ZmD+嚵~XOs8Erw\EOsH4hCV^- 0\3 }X˯&s@ΰn;ʹ6)N3SkjTԠP,'mܬӁH9 x <KUQ;з'>bPTB)2a*l|)f9?g }~6@7hn󝆋B<vFh6"l3l qXfp_@7eG RH»JґZhkrKM*a8دb@DPq| ! yWw̉kr7l]mHߪ/7Ҿqta>+ZJJR潋" SaIC3G[1OE|"ޯ6Mw-R r 5O TJ0q's: -/ɘv3R0zO4n.?b oze6%l0N̾z\keq|M nsDQGF{C>SkI]=wTZ!Mf -,(|vAJ%/ lFuKN;_ @숣m7c?ZHCŀ4_>>xy'|sd`wȵZ&PLdJ.<L3 3E[`WU[yHעs)k-g΁@1|b&<%sE/~9g4yHUzwi6Sx,!o5Q}9Gނ1Ht#>4_!ߟL)mFĮX|Q ePGѢUŃjlD%s^!X`8.$:"k6no0tX1Җ2-yWKt0}Swv1٭ދ7SZԫEV8{L lڋ4W&ץ уoiCQٽkɑ W|QᶆNֹV~bt3Ȕ ֑3׿ru<[sDU.O̜dB7keLod o2_׺>j0YAxrZ򨞗/Ϫ8`2{d!u#vciŽz9 lo9Y*wVUD5ow@SA=l29I* P`*4 Yc{KS Lv5N@wI|χ mNEwL=f{ܲVDi Li";s ws}u2N 5ЉP({\7? SCq9' &=܄XYh 5ZM5Qэ:0^!%5xE5z&~1BPƒ J`$߮޻ҠLWaJ})yosb٤Q4:&9{3F#d#_Nr^pY!vL%a\A6Ÿc/ܞ:&hyN@F8·pڰ} #ٗ7 wݱB%q'&00(Q;"N2*6puƣ݂7lc/3Y{萃?.!_[Yvl=ǝt(}}ꖑшpb3VImDNz>P K{7:R\8$ @8+ux6|}4t"2ĀpͯJfך~1Ƈmĕ gTJvsTw5T`_,'PvSƱH[> sM)zj3eT@EVZAHԳz>s@ ;@OTHUCL8\x>XoY&OBz)`B>ÇV6c_~4EyEsDJu"W>P&9NZI7$X6HQGZUJa!~|gsz/A.A6?џHDN*mS%S2r9Lƶޢ,}p,rUp8b5nb &Uw.@!7\v7j>ED#01{lKf@oՔDO۹ %a OȤDx}Xxf@?п"Z߶L&`l8nZc γ8| sLb>tDD4DݙhȀ{%-:Ú -nkjYdC7 OR꾟y~:0sӜ(m@ruzPx0j &Ajx˼h5+#So}޹WoN-o1摠:u5uJ y I|m᫣@iziŦ NUBcF*nEVq) ɖ?G\C&OmQO&[?H5A0koŌ2KdmXx\hV+(2N:n0h81,(bcSv|x{F:S2Ro3tNd V篦^Ókrfxg /̚U=ji713B`+2*tyG^#,8/iSvdW+!_WÉTc{w7ޘ>YB4nFs<ɀWXb^ Sq!/uj 4o-J՝MS>g S@z oT|<u6%"k,*ݗxWc`KRX;9.8Yeѩ O½\1H5Lww B,Z5L_CjDF4| 3O87 pɚH.!ћ=':`p0ٶse^I`jsEP whԅs"X Uj3 i++r ڸTOf9QJtĥoCkE[DJCݙ@e#fK'_ nn0wWȖ!9[}ѼWB q[ xۃt>&m @dc?8 @(T@ `t˱d¢&xb`c5\W@ 1upeՒֱR.GYdT4B{ vJAԵ&α)jGFƬ \y@ 1Pԣzu^q a ԹPg` 0P-AFq8`ʱM/ttg/k' F1~ճF6ܛ$Wi^m,d Uxmbpq~4W)%[k\n۶PӐȇR-) )v$m-uY?.a)r=Pv6|$ B ({> G}OG5\]lk%{tp5ob|}7P}0g?-^0Ƶ,ky|F1>:M%YϮq}|DjU9h5XF%I?ڵ `եf\oUJtь,fŘlt+N=ȎP-٤ołe;DHg0ie3GLA斵h:)vnH5CV=WВ7NmIkp+)'xxd8A@` _<+r,N.A©7qgNV*]r$ө-P (Bp^*GGь-!cT|VI(/$, 8bzՋRcNcpΝoWf.hcPJ{+jIy 60Zyܤ!h0kRɘ53[50+O{Zd#տ 2.ߟҰY4o<]vhJc*1@Mئl p[hk\3C{*m,Q\ Ja|@:D$2gH$:(0҅gesxrk=@|jT6Į0B17kXmՋ! mDXHo%tt_ yDF٫&sts?)oծe>=OUH&tf+﹀/oy\ LB#6|6(橣\AE1lip[luWJ w@K Q&WfKTUFV_j7_5JV脧Թk&^ҤlFBaՄ;9O0GeXUd8j9tǹlumTM`oz(Y?\$ 0c!4|/JLLp %OA9;S>H?G}?G`:n !h?ߛ")O쇽Kw%[=7OMXSGLaUi lKM6򻆹 Gu0ʖ.*Cސ@vݙ. s%jucûie46mu#fdtt\G4զ{?`[8hX.)#Bb oi4Eؕg2O+,}UuN"fRnJ:q͇i}~0B#:֢,$om@(em*t`v]Un؁Ԡ.  ̾x/D-j/wB- M@ރ moSnUJr Bj,rf9^>$K$Y5t Udyw +LaJr\XN=fy' e:ʷI䦨sITDr6*~)'<zs>i6^sf0X}| 8%tɌ k%ZDk ' &e7+pQ/G1sAǿhYRE\6 u`7XaNO < ɲo82wl6/pФ[Ҋ :jӦ^Bn&Pq$ K!&WT /U878A9rV{  2kst6lL V>XQ}JiU]\_MgI"®R=?Lyqmlix6?| !^֣{3F{K'?>cz%JGt^mX`?"uʴw?)"qc0%!yL2N/xBf{hZh6T63h\Y܏UM"X6qZl89ET*:5;b򿮧z2kYo;׈%LOlV}U4NӒ|:5O.=}ɀw?.Ѕ{~Vc3܃ ;kce'xIɴA*ꠀb L> PҸ)Tѧ3[BpYuHQKR/K7~Nc_J3)w.H5W7>1Ԏ90L%X&zR!־M̡EV9ncԠOe"п,@,'P/VYKPA/Ӯ5d›cʇc) ֢;!ख़N:)D`wmUѴ@\=Vڭ垾&jY?Ac^ɑ7ǃS+ (id?1WVXl!&'#$ưan ;NO#5PMՒ /:|%Q{lžv%6.8[ [ }?GBl}8r} xbS+:rnv~ёXh󯑷EQ⚔BՠDDF}gطPDTx*wA?E#D*vO1HJeUT#SP#d?p(}]޹|~] Li'd >wp֤ܸ ƠF[#rg҂i;z_%ʂ,@Nc02.+,Cor/M( {.^}wΣyvkuji~8$voqZ{qzI9qL =:~=C,)tsxX_8iZ+$_~Yzy']>=CAwv_CǕOUy)[+ҸKhX$ʓMjn[%(o#W d3yiO>meގPI WbpSZNӿPP}IG,'Yް T$nk\vU ǡGoxNz-_B0Пid?aN_)Zӷ81++E/պc6yqp #WuV#i7kR` Bp׬Z0Ubba4 Z]G7KQ4dOrsRKE$2Ng|Y%gTp'|)9Kg sů_)lSZRF8R e4H;% bS=2PǗJݶA㢥t~4 *¹I_PR~j"s\^=O[:FxRa.gDCsؖ{͛>!u#e'Onͪ) n2qE_(dQBeV6Ğ@|d)' )ˋ@|05X8=QCv%]'oip<:~b&U M@dV/U s^i)Y{IS§#V9Ե,N[qxn}I@|z(!}5BN`D 'p)^>Myum;FwJ.7qKʥ\hqLe/4.b^N+JF/G5BE8Z9ܹxHثйqH "fOGck@A#& woNEzӆlJQ;T׻"CI§epCѼqܣ /GxTb-C諹??_'}?_d.Lݤ8|*hkWHrW>b8(WUڗy+D@Ӕ-[7)c(Srü<֎P%a@ォ~Tƿd'#m~55HgsY??ޠnݢ/UBOt)8SM`UtxItmKe[}wd}[/n$#`Ck''[[cl&OJI1oPD(eWiȞB+]+Jv&jr{ $,ޱ^%ߵrŶMdD:qH:Mn% ĝbVYQ&@D}$,Vc · DHБ81F[+N&+L;A IM,~)ֳ2פpSQptjA!Al@:Tb"?fcqsp=l5R&D6%O l!tz% 8!jcyE/+5ngg];7`M|-.n>VIe>9AA 9_$;6kNt$/`a]r5CdC)QX[ SXD`Lc~If@n!4ϼ֓vvʦ {Dy tdSբ;3C`Wٵdž逋w>Gµv/_H~B溠ڳT 3y^x= +#DUUŘC #hz1>BϦ".lݝZ#rT)Nkq!eP~@875Ubuz%pH}1>sެfh/q]oxyW &F:8o<'ěF  WY +#$~Nv!l\멏^C'`"vfަ^CKT MdhDv 2j߄˱֊C X] K]z{shVEDs\ެu2ť](>']ѷf$Dfn{qы>`W1 ED~.͚3^癛DZWLCwZ۲+[BtUJqq)c݀?W%Ix~lubIS5g ÄBٹ`w}W-ȘM}e_Ŧg1 s%1Om@y~xѵטj4^)uAL7Q0ǐϷ%ºk;Sxځ7 \]?'8bVL6jJ3u+e* ݑӓjFǗ w Мx2dʎ,5w޷<^˂oNmG`]sg/p R`gI@9,30%}\c ],piw@D=wDOUv\"7EI6Z*zڒnzrQvL+T,E%qm[@$&BئN)4",y!W^_S^l_1w2@[KςnwYsؤ_QrK5|p5?YIr\%U!ke@XV 9w;wlA`'&,ѫZDF6U*5mG4^^q\GX%C^`Fo; db^y'QQ..Jy. E$M)TOrFFhM\@U)`><#5*21d&'TL̥P G@1?h/" x (Sl/R9wrC]TOQJvKdԏ~D,#=]|lBJ6šZ1bYOxK/|"<6pJWu3ru2gɬZlc* RƗw)T{-5J'v"x٫IxuGVT%n/lab)x +۶}F@0snpı*[0ЃZM`_<,ی-2/-PHʒAl߇Qx\1WcYi E]RT`V:6Jě3@"Dg4 "i|b,QT Sq,m-VRgt.9^#bJE&ԖHg.\(kv :nzgO ȿw/:c2*'"C鯳 kr h*Pr,mNa._K#Cg: ^&h ڢh}0B$ʛPŸ'B}tYa!B|*ZIJMة-l}ܭL x8%r6,ڇ1A4AѲ`s쥕AdB`A,6IM:`d 5v]Md&oOz"03t]xS^{>Jۻ5O =Ԋ/ũr5~ Bw=6#>#BhIoW9vOkt Aq!-RM1*=U^wgQO|O p g fͤTRu4O Ǽ2o^+͕ @QЖkG5*dbxK.^ Ebigu7-~a>U9]O5WOp'mXߦYT,6ҦLMt U 4Q_jp1 ll_#NW_{Wh?19=C(^Y,LGI;}~l7$x;(`-JhC7@~VJ^l<պJhTsݝxN@jgôdftGꊥ!fN5s )$Jn ~"E37}w=m0igkaK>>_ #'󈆰Rb@oF?_)rFAQ<0U5^ߗ[I跰T޶vDw#gC]]3mIA RG"$E^R/x9z+X|1=oD$ݒYdTq5TQ;i(˜s #:o@ Ҽ_$C00kvj]Z替˒@EK-Q]1^G co͟iS&̌r+`N%`v A7=`Uu[\eiF1=)ܴ ^n m/?TblZ& `rԹNS( ] {)Z2[Ok9!RVxOi`G/ Tzdú:[|Oo!0<,Z"Q:-g.@*,NlONo^ |ǕFbxmCr`iFdl$;;cos Fpd+ȟ\`%(Nrf년Cb+J*ܽ59џWdF) O)*cmhY]yBg@ -ڠ&wp2$ieO>"M&ѝoхւ1yZ9& Z&%NeFյ}<69EiZ 3Z&f>GHÍ{=F@90#{N!obHEe3JGEqFĬ ^9! R49tr푧;N_GS9ؚP"0&NnJKǤ|?T+yqZ n~B^kouпH"{--åhS^) kxV~qДՏ7LL ~R. kb^R3h $qKRvpV \GYwªTs$ɔOo&ˈm/|>@=, "6i7Q),IHeBr:^7ZD*tiD>8GBj%P? $M^Vqg3y\JpK!TS-9B\gϲ#9mէ&l<-<W8m}a0oOoyut?T֘Fh}H{{L]R:l>JÝR st)o_[ҬÃܪfp|噕QO-/|y]i$OA]|{R H[B<޲ |x{x$ x[ۺ.K6n G߳F8o?¥@?=aeoN(ު5s#΃i2c6ۖJ~TuDr0-!J\5yMz;  zIqˈ9n7X-krK_j9G(<KʆN 䵮Z!nv@1*mqnnJ65y,l=mqڑW ;[Î7D ^_rYź^ +KwNMF?miPwtwUSC4߶;vqǘCЊE[0y5@̾<$\8a_"ş-wW&NM_ٮ/,~(!H}!9(I@t"~M'>~OwdPS+bz褀61PVxAE!ُ]BF1 q™IaJ6)<6*+j Vܛ7'p'}9X3?^{ޱ)bOFv/V2Y*=Q&p2`kWU^kQHy#t`u.&O/peWs ƻu e,f۵'NV|fdmɈK!E ʴ;QPGi^Rd/⸐4R&0V;>%Zl<;z0 6wd Iqie$*YZET3󒊱@߁c 4gB#;g:"NFIz"ܬ j26\t82:g iG_!TjuCCđȽMcLfLB'g6A4|G%>@FTHRմ2Y|v n J@d4|9TeM3a?"RR*<:? W)jA;ܪfr·_"8s4ߦ/?1^8t"{Ȓt~`IyKK@)޴\.QJtu1mQd7Mn}u`x#xmKV\'p|N[,f{)PS^`x}X P$Fs:w+4z4TkpM;\$_ZcD x(-bZA8XSi_;(|>*$6p:ǵOٰP-[d98v}V w%y P)lH,4φ#25% C|Ѫ~PC(;NoH(/IwGbǛl:ݠcDB&/7.C.:YOEw؉ehۚ[yg[~wt.%,YBnS&g^J#:4-uOe!!PA +HlsaGBhZh ӨQƑ}>5EeBh#傇KB*\C)Q킜RK{sܟ1$1KU~&Eu^I={`= GUE!X7f_fe N@;rQ͌|t`Gp9UC\n`㟼ɂ.7[Bg d"ɝiUԨDaD* YAEI2z''}:R/7a+P#,{uap+*LN6Q~VF(HIT/"w)kQG.)fo QOo汓.\>uPOHfof2쀘l4CjÝ 2,˝$X ӹ-VAM=Hm|cP#-1op<i.iοphL=6~kMm`24OD)XmtmUZ1—v[ ]i>ˆg>߭0Pă[[yd"$Lm-._N_A W/3TPa@PrOO\E`vA+~_:N`5\faLwޑ قw LLRͭEt TѠ<` *r{.n6޼!\# 63@.T{xW+X} ӿsHwƒ l'F&6YE^n~N5F QQ' S06&%P`:AUW{(uKAxԲ&*T$y=^u8(M|zn<-Z_ ϓ1IeAG2F>3Uκϕrιc%WѦT U>pIr3prlлН۳cW-X#F ]W l{\v-T[]FZMmأ#˃!?PoTG諸@Bjs y>Ou7+u*eO/l6# dI{:{Q^4b$}LG*k_Sg7˼hLO8vMQ*Gz.ã~廢Ixۥ'yZ9)F@eDod>8ɿ`w& !F dΖk sGҜ f>V:^6q8b@SZxz7p??h)C|onOs1U}"ܾi*%IAum.(HF^_Xy 8ۦ }sbKv_F>*4Pc !f#*='„wo=!{!\*%.NCVt{|>be{2~{XK:]WU؄VJ76P/HHhAJ./=)5仗63&zcFE"ٿ& 8Ckp&B#-$`4"Y՗LCѼ;*@(]Yt,+J[б Ԩsx >bx*//v@}񯞤 Õ?CmޓS]M&@:=4m0ihϹGfm&|J@G?| -@3n3UALpq"q1SS}8M)$j#~AS-ΤfU>vm|>Vpb;=+QVHhQyQ:T*Ux*O=Q*KGL55FTF8QceT@ܚ]-Gd ;áW( 2ktsI]f-1<$D]QѤMF!30 bRSݯKڜ t(r7\uNh p*]/?ŰG[!DUӹ(ӼΧpwN˞=f"a*+bh.WISڱWfj>//)q7F]s;# ܂L!p;:W 9h&RSf;mK6q gօDvIB}”i+z1$CL&:"e1">{ZfPu8 FEd~E%jYTB$r fz ܄XG. ̨>7C2nPn#}n;hS" v֌7ꮀ4o1Kπ:Ubsn `z:E4yZp/*Ͻ@֚qBE֣ԖSg.(6NH"#C}f @FGyK=LBI7s* 1&f;J?42nq\JK2`FAEp!_]YٓG,dȂ{J*H.rMbwC42Y?w2 e%y͸TBgG5L0?{iմ?I,( nZ(?,@Io_n)!-#yKw~^&LVO1Enpv2!gnya&K^I PduX4W׉՝2%IvG.rW-MFqvE`3ߌӚhuC%]aSX$S![&`DtDIJ .VlnnSn[( (V"!R8ۣH!)1FɮYY|a<*k\ ?Op$0cɒ^kgmU f/qYgιlpxL2=߃׋}m9 WULJH6f/?[p[ZJR+1Y8 3k|8-+KWd2,{?@~3vIn?|@1*#R0Mx#eHŎe}<ژRPsk<> nm.=FH5TW3|oFjINsڔ2n_*ۻI@y`}OS(dg|_6TiNMt6Bh gXgԍ IkW>k7*QS羜r7Vȣ4,`>ҀnwWbM L|Q閲iOWKTnjiQ.g@u]ÔJ.MpJj QB5"|bd-ӻ^2jkMUIM+ַ_p후~>2R9^=$`1>q+r-|[%ӥ$}uK+fF۰c/6h4>6ZQEJiw&k|sws;.Ջ Q|(fĦmڢ_T'^I^^I_r93O+ "*2ljsPPRyՅЏFulblFӨjKNNRp=0-x &33` sKLm2V4&2|ПΉ玮1@R2H),t$ "?as -$yg@A *CҸPǢ1k%AIrTX=0޷0+Zh JZ ͟Q21Tj|ohnH^CVk'xBL‘:0h)7'ɓ? R?̀o"}eecN?F,+'Is^L X=^U[5R\<<: 5GϜv]Һ0rvYT1,̮yRdV#"^3mEYÇy5*$aW {R%z$ ^(t{YNhx ;i˞ߚ{ב\v2:|q4\-0dPq``'VF)]2b yh2tS!03q)>liJNc*[ ߬rŊo#D^}x;jfpR!])U ȲCQ]Nڬ.r=dK,YbyNjA`@Gq1 y&[pw/.Q朦ܑC8 N;g ֎SXZeB~!r_fW>x 'Yg *nF2-.1M&"ֲzX΁&RqFA_#,km;Q`M&9TnΙ>,ǝ| y``- Bz: $Mz>UՠH!x]\-:awZ063Sj"Q[7$t[j;) Ej$ peB▗\ )#T%ͷ3z^Al\A)s;2oZL[N&-& tNeoyG8~EJ =|Oqf?7ا-{ >h%^.`v౶I9}fb$"{  G"zt~>q +m#QC^U cqPwARf!h]۝;[laR=,FyWJmʮRB,Bfy)lmSR}=͠~n7O(kjr^b[󩴟=h12I/ӪWʼY(іn 9w]z :uO-0NZnvO(l:iUR-J 3$RItՁ܊HE7J6<&y*~Vȱ9Qų(fkʊm p82 [6T/P;D/S3iq1V~vfyʖT avA=]b+O)HL6 zTC:I,ˡA=c]q\/DޯۗήzTR ڮlƨ4,,m)g4 0w=='ruo5B>8_dIQ 8l RCRp{ Ws7샰NJ@wb*8Hfqe 4EBZ׽-HgPApюW~eRȧ;hd\Rj6Qo5{4xM5i *Z*w 5Ly`*H u/ 4<-;LpR[C{5*|V/rƍ ܛGF<ѣD2*{08RTpك(Os'z`'A*BDoFl7oERC#"Xy(:q9!{PUঘmNŌD//Dd$야T%uG `K̊(7oYj%ȕo}l'O5E?8!+p|r{|bl՟Y8 K}x,k "ȅ6r\O!X]e+`g&)87ycZd"hX<CgjM2njXtʈIG)U%dAX j:Bu-VM*}T3?XXD1 wo#~T#dm[6H4?סdK@JGʖHP/E ԟFu]gbOHξ3.nywf`Tڂ"F7\;҈#Nݺ iU=-00+=PtL%T}^T>mNsjb"Y(cluZr>{lW1F]TeM ^E =1#V| i'δkpl3],ǀi}U`<3;Ɨ)6ɛVЍ'CC雙aS'cq<<(*.8Qg~XCOq`mʴ]DnaD"qC!-@|k@0 rp mAE!`P8{;˴@0 ]pGM~bɱ5zŢLps<*-tn>!)`{vU<l >='@4ĝ}'v\ dAʑS@֑G2m!rA+e gkA.q߶G3: 3p/1pIR;8n`?\o0,CEIX߿7/Fd΋vGYf Ո|-$ &4D]49?{lMmE1ټKP0R1$oaDNQɥO|XPF >9MbX Xl^?j菽Pλ^}Ꙧ1$9w&کb 0:ӮgtP @n \Y햖6l{Zj*74[A4-mU!B|}{5iR3> wڂhFzɱu](S$M}$t6hc=Jpi? 7s."m @M6b\gCed_r][cB!ϼ#?iUԀ˷" nIlKzlP gW `ZlAmlͼA(YBZ)hlm-LyvG?VO$"j{ <\MO| DtY>A(4f 凸 (@ u"!2$=#mG8T3%>I$NOR 9> qkJQ[zjvGb<]A@]sH-<U3`#&Q"{ 9p/+=?a%dvٹO=m{%iv҇c[<뚆>s qB}:o%˹*4]&x{-23 >Ե'ëxTJPE 5aȱθRqQmS;A9 0& n3h,4HLޮq[FiX' 94Q0T3{o]6qĵ GX '2 sp-kwB7P]Snp)O;( {P.<_Y@{L1:͚:T6[1mmi钀ݔ21bKPP1*huliRg(Mv'D84ӿ M92\[arMO7 }8~ۿ/_u8k'Y ':iI{Q}J V-r+.1'`%Y)F)ّjK_Q-=Y#g̷ףq#"tĐR`Q_WS+/o%i[͊-x#юŖHdߤZ:G|eZO{ 1:WO; |~N-h*;|6/ؔ8KgLeABԅ? eF}hѴ` 7"xbQl7;Qg]!W6 }U{NY Ww+rC* JS>rIÓzH{;3xHjŸSޕY9kɤsx2zy_ׁLի*CG,jx fAZD&b9rQo)`2_N>2 R]%4Яe;sG)ʋa8~]o ıϒH,96z?݀ `)qvͅmwZXkY sQyw.˖Nmڰʾ͝&ZvjwJZXdVBsxmf :=d#PlІj NJgdX%-PKxワmG4aoJ#_x:m kdFÊёsY-+o}Z I翳iF FWꖟIN@2*L^\Eq1&O*pK]e&D8HXE ^|P|8~5+aK*@Q.W.1?]C|Eī3jHƺ+zYXƦQO/t D!Gob&2ɳXk@;=¤aH?cIZ=B 3(j"TRi*6IM!n$P(!yL>]@w;p]wyIm9Jޕ "j鎎HqB%Pzl.ui>IEBDŜ5#/v6p p@HcI!.T8FBoq0ow !zyjHQ쎿6\^fIXG*F)csIݫDJtፋ)kClyG|ŨI6do:4ƨ -OOf@NZt,#1σLk h4+l,7'n^P ?#ś qQq&KNɿ`?3C'5e zl+1t}iĖpmWC6bmG߃7U79"w5jzR'WZ }ž' Hw]`5O59P+#i7?-+k0pGO{pj.ȀZ}ԏ$ h*9bbP!PD:096 $/l;6;/: K`IWb 3zM! ћL{U>ķaXX~QOK ,P2)PtToF8?7^b] _wb?TrA`Q:yD4_ШCO_}k*p`܁mYrp<NrSC/#v.8qb%p)`?d'T=H"5T/sS މ[wt(z3Pfc&#U=V/ac-)SQD夿+5>bN^;v^wOG}l pڠ 4Ҟ$^ȝ78xuR| *<s.*&;{1!ɋx,h~6 f˲/Z6lԚS(D?^ue)Eq{%vΞ>kҗOBS^Ԁ4m-(-? |V񟹡/ׁHwe7 m0ayⷙU-:LYX"DW&H[ o!g4?pfbI_85<ُC[Κ!|Դ*|Nf>ZIHE,*\P$IwLk7zAs 4:|Xg{j|Kw>]Y$eҞIQtD>B`- wINEv(oITnPWJ6|c(ГʦhcQF1SQk̞6z,L`3~*^u2Eh 'EɔRDU1Q>WHt=hͲ#l>G8D+rK!DHzTh CV w份k4E$wdA^R)X"VEHm ';D(ZM #(j7%7P<= twX!R~0Xp741ŀ ,kYnK f|>t"Xmt TFo$7v꥕dM*s'8׮{f>}ZL CCU\/m)I^"5}pWrU3wY[Go,+`p~w; ?^wb1Q Xu{/A+ڏXAw}=;K\עYQxG9VU:7P`w+z4CԎĮt!vWC#4uynk3LK_1 'R*C23z]87pq:%Lo"5ϜV> SZ\Oj; %8zFs5{uk? B7S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4r+aᮛd$@:4ÀyQL+aC<:x mh[Ğ?bh:W5srCD)G?iQQ:#m W9yEg[rWZ6? V\Gpڀ3$<C?H'5W^}:&&LlO5u&7:g!hQ1qJ|4KSg-EgS!OF<1-..1bD w"K& m7^;;_OfxU\{a_=z&D7hY>]/OqAj;ԏ$C?c\R'Skr XE '@B^3;W4ĭ5P~7EbHY X֟*.a+Ix!LJ.h\h4DMixM9Ї/__V~>`?/0# c>0?k>1 Fj6L4GX"$ƒgSR ~TR kCz/L !6:Pp]:+UmCm,UK-gfdhu2!vD /E40D6(iPA)0H'd; 鸶I:ºҀbL9qAH_lkqBw,x}QG~F^Gz_psv鴅 4 s[zDtU*- ]G]Rkoer%12:\Bp5%M_=1w,Y%A0x|8i^ݸE:4~% ]~tefԁvڤP- K,U!1_Mgܻ8z9c k3U;MJެX+ L`t2a-qp*I=fkp;Z&ŠdۇOD%)!Q8e-D7ybwC½`VZa#*fIؠGPyMlBeP5yqVAX s#)bnRzo{luMf 'rEdvnm >GyԛUZZeC} 393iYɜ |!2h茹9N >E):|AlAɊdWmi莪f=v]:fB #f喔yfDٳn.%?WhM/~8^>X^>)9jNp X7-4gtk쩬0oI/[3€R! <|b* ?҈'Ʋ>o p"TZd$bS!A`CpB|,™:c 5+n*+}hӀ=N>2 DO$)Yf [#.rPo~/$ھ2VBl9BnX_F~OI:?GSf'#"n {QȜv%J#EB Im-wh%YH9# W!w3șjC 8vjoii tp~'qΰ[4[$ ]datZU[Y9 Tv5w8žHr:^.@KKȠh Εik7.-ÔMO7BLk.$ >`>q>je2+CIA₽ 8L%(phii C1 r @* :n(7b0M[Azwܓ`%V`"<_K_ԏ4 iڰV7ٓPňBb>jaJnqg*5, |7I(0(QXg ;1: E+DmGIj_uփNne)5ބ-R=Yq-28q*YG=M5],i5R:/_WvHn;~A+(b zk~倗{5BhU++ggr)g[<=q-_ob_O:Y1qLjvY] 9ϡzIG,jL$ 5N R"ZKIKO@QS$z583dʿe2G|X񃇋zZt 5ЌC~ƕ`Y6 T׊,RcƲt1]@$s,~N#AQhBu />L6&GD(,J?y@ZfgFf597OA*LMh$@~܏tOx$QvzuМf;2lZ?199>dFUY 1-i˗72[[v[_#VËzG ryͺ@x@o nS< X@X/L@ޢNlyeޔѷtRh>^;'p[Dw7hHXřrUۧHV̚lEn#=s_h\)².4^j!8攒a4,S0k%DQwvQbQbnxfU-a> |VdG -ՙ]_ Q2EEBIAA$ڡio-f ;e@"X\l57rR S魯LɻGxQS.f9hM(J2kz8#rՔ{ <˲G KBw1gj*wӶb{KߔǬ^ f3+EUMrbcchs֬ ff f}g33fu%=p*[pIǐ  Ka)c,r=F'1=s#|415=})0ۚ O(!CSFOpBuLG]5wбI W{-:rPvP:CچTx?D|K0)WP 'vRX8+6n8c$W`4{.TtҘ) ݟwHV&Lb-9L;9_*1e~ *^.Jbs2 v:&1`tO@1ܖX,abx Z-{EZ \"_<#'sJ=Iٍ* 9p.sXkhcyj+LHp 0 -o=s7uX4zW$4!`Ӓ~GN61cFқm>*`l :Vf ̦^FTJ,%ɲh hF"B>̗wv 2 R=m~(,,xZVcoQ'QBPZsݔ>p @[AY,oa jH&_ː_K(`Vln׺9R&[:p?pmxCvpt gq ѫWk;&ɘL6I{WQAS Z‡2\,MΨ?kX,^с)~~aAF{,z(ɳaU U*µ[-8Fl4>00laa.ܷVtz`tjC9i‡۩&mݞ4_Ї y?sҁJu&V$5ЗBKG*[s1(psiQi(8< 8hͨ Qf=?NIwCO616fG`{ӽӚ_)i0`ܩ)Ӭgotq[;w >x[ZE%s7{6cb Vª ;[N;xO$e#&i쯣5Rr Tu,k"f͗O}%"ډz\w; J{< +Z2w"@K746G^h- MG=PZKƖ,^/˦pdM4مSn-$-/4}،B&EiMrjt(C|]ȏ;%V! aJo\fT @wHhkɟILFZ&nX'@0o,60&i<5k`Y%e^2ziQ<͍>&iIn]hIxئU)SEpss*F6u&Y+_Ͼ}C)Wpv-<#گ=" I+(#% Hs# TJB2²^V+61A匭Ԩe'.݆z<KbCG"nE~_,Q\ 37|@|@|b)Jn24WW H7va[| 681?'o%h4{AQew94,41R52%8nbFYֱBNM;5i"ʥ&b@)4StGɟ%.BYD?ebD`?_v5"Bߒj]}%Z @Ų'y{c֛a@u> S5-Kk=k?VlY _\KoSsL !Z6?).ҚL1C\1'4yk|.LEH.=:%sΎW!zK!9gEag3bgZ>ӗZ>1ٚ``ijF5H5 NNP~rg,W fxW].,1 M(nY?kjAƏ?CX2қ3+yU%Ѥm?fc 6IKw=Xnf½4| nh@_h07ETaWݢO$ՁɌZ RPaXı)Eg5.5v‰nӦ΁de&#M > 5ܦk(hB-$9lKJ {M|wW @r˟]8n y hg:O7,G.HÞ" "J*t\H-U˃yuҚsf7:!^!ɿ(}e`X[Nff_=.{O THpH(&!Ozra}̵3xN%:v(M`%a<2;*بA#7^qE_ӻqeBYN'JFM"Gdd{S>PHVA*a +xkeJ-'E?@)w0f׾mQ5AsėG߽nִHaljF&s9\KS  BD:t茪#<)TغO/=qnG.Z2iycg?uRwmD)@V I bEUrI4 ZeBbmdf~dL; P.?T=V^U6v(XQů m.Y f~ "Ntүʖ$tb-"8{D՜ Ԧc3,Q!9 |?i^Sp؏ 4 Gp6hd]ݤ^~%q|.רgFMb855|`b% O՚*GDۛ\p՟}ciL|۶̖| <ڥWw~rSqRE.aV]"i/]u]~M4fMlHVI{%&w{ɝA&)lLc(({LB,-V> -s@<<3ӊ< "iD|;s&>Bg)xv:4<'B<n~,%{bywCzREx[1dDYMjRU1cтڹJ|xqNyDWuXǵ`]# <2Ng~ ?%Luߜ^r%߳dV(Ĥ*U)c^Rz=)g/PmPyw$ج܈ r|0۫%%)Ux)˞#IFh5r`dw"v5fZFY!3F !>Nq A9wx+cza]fƎҴ<}qYZpЁ9,H&Z'Ll WfO6e!NgIAO[$xS A}{fJ4l ҫ\P;x%9L^']]ϴ fWKhoG6!ÓQʢ¯$U.}Lyce(c`6s Jꐄ+T4ǢuޮSlY.:"i5 .$GmJ]iK7ni A:45zuum4eͺ$0[ǰ{Զ2X9~Ef6LnRkㆭ}OK%ԇ~lc ϳkb3@lIJ7|ąC*!;hFn˗-i:ueuIqU1PZ CfX[(!;ne#P0X,G gMJIio|Ջ ?zWU,lbjo"}R$&d #˳{}AfXgUÁVS:!$avZϺѰ3˭_<+rqقsd:欞7G͹@(5{Tp,-` C*Pp0Ϛ4P}ڼ0}j۴ +MHK)=nQh/k粨vkZxzV_n >1N7t*x7Y<7~d_GGHwR~N|Nǎ{"d%5q˺MTLJhb4Z{ vEcsuvG1E;\0jv pm*U;f*[ǝKYqw-~]{!"!B>T(*K!C19uˋ X4`7"4/rOF'y&2'ORyÇF,s"KQЦcҡx̳([g1Nc!Q~N"G{A鼻0IiC"nP:=(7$z;~),)჊<{ %<$ ͙X誎2X2ϒ~+7AZ :t >@yuz"")G? E<Xx dl{ 3Ou~\ܣ⁣}DH 2obvjkC;f! kc89hUL j SH )"{nU\@&Cdo4B8Fo.( t/'[pGEܲKa|t;8~FCJOSN_ ,iMOdWL?c꺒`w&W^=4;d%ɻ-f#!,x;Tǂ, 5vcprᵲ=u͡G{ÓH! dDuU3(583B~wXbrx4PfA7ʽ 5bϰz>d֎^8ਜ 0U':/R+HgxC? _?,w7? ?1 ӵ9I[@b_\4ovZ c\ E,Ln`p>ZsUh4AbӐo{?MnL2l[\d @+3Ha'Ŏ0a(R˄x"i# 'MI'~VͶaPma dΚY{XU+՗KTt2Q (jT N#ܝ5:Cz6& @R9E:|#V<+¯>PDF0CjǴ;gFcm Gdq|HTXT'PE(^ɲ?TJl?Bcg) UUymC*AYurl} UdwjEA#M!^|~VOYZMUX@ozPɩEpaOg`g|Lm2uUBSqv:U uKTI^,؄'K:mU{z6fZI'`8`dOU w =B>,nŭom[,&:/)~#MV[o1>zNG:lLO]pt;3 kSyo켹h_tl;:05v)gƳc_Vq=Cp4٘o $X0zn;(K.҃&kxx ^If @Y*bAوٸ/gwƄmEm=•O„U6 } wyаֺU*$.?J$M댭+*em"U>d{v솲W/y7oHBjNm4kKzQR2?N+1,YVCy" ٙ`԰7EZ`P: %I5!yTnN4 8nV*?EQ4 (ש>EŜRlBs#e- w ULIagZ_gŢj+E}QW2}2~ES6*jv`bq.Q~ygɚPVmو(b'sUNG_ W_|u/"(Tu!iZ0XU#./bM G -߸W'"?.?7]f #?@LOIn?zjAC(,20E;jCj8-+_Zvs)E@&ᰌg#{rѼ'\/<}1'"oy' &IH+ܣzlR:LĴB\I_wsӱ3;&~nȔQbʂgS Ad!m\ .i*R7+c!ἒRb j ܳ+O UXhEtcʝ۔Dz >93մXvzbnY̘#f<Z%&qɽ!9!RrMWݭ@ "6~sB#Қs^&;(aWSٛ,+EAИ{?,=B8 ˟:6R.;}6xֿj@MIv])~IXlZyJȌgpW5?;_LNM2%weK uDiR h ^j"At^ ?;YYFŗ/qj*1;X O年-R 7+x5ЭS;JQ$thU,zxSL!36S=ȴg,fRVi&VPL%7)E#6%[ǔyBE<\ *WD/QCTxBPւuYqeU( &M^&D5DnqsPZ13|D3?VYgau麝\fPalQ֨gQxv r_NIegAy\]5ϜJ4ce3\.e1rҷ蚢rMiU0I3y?~'ۆa̲|hT>{)1-? vPRm=ck0AYXs#GVoC0$`|,]B|T/BaCWRa߆+g10j7)5IY'sPD,M|}}Vk+w"%#1pr4Sj:?V)u7Rv7Ҷ ba>h. LN-q m_nq cD4Un -kQYm'|s} #, \`m8{ !*qlOQ42. %i7ip2DԳ=K%#N ͊pz+C$]e}$dCp?u X(1m #*Т^u꼾9] Lnz"=xJ{x=mhY*"KkJKWtwf JxF%~P:!{pFzZ+Jq5lz >-u*>85mNRYj],=QfKjwWT\&qzɋWP_K;(k j@L){"ݤڡWPpet:6^sJ$YI&V<"ɂ kvt8AW몌HV5pNq(;Q \j(Ŭsځ\ŦFgayR,d0GD; @ʌyc B8Zc^!݇7@r+cU ]DknU'l\x 4l `ٍ(L"&yQ-,1ZNo\_z0-)Hw^r#ʶ+I9]Vr^I5S 95i%w(O]ɚ~I4﷏5~,|0!; LE2ÅoQJ3샒T*{6AV GG!V;4Ө ZQW*fL˪ YzayjHm +fDL֗_*z*:&ME:_b-rw6$ߑH.*QwP)n}}7} RYg[L(:"p3~ytbK8j^d$j҆=Ϥ0l#NA}]m9l.p[x{+u[TK5BX1p|W:l(#Lm\zBx+{-PnQ: *} 1L{.xy50*1H*}t,԰lu$T'XAs̥]L*2JFu-`">1[=z4xA Ҭı,]jC4b:+`(]'R1  *}+ȀҮY  *1`Y=[柼9QR@,ZLUi͜=L\ζP=?L`SrrB<7(I 7arIOqeU':S v~舳p7;p愷/7Cp?7m@-_@_:V> وf 2z$ʸrZZ5yı<]d[sPcXL[R<,3+.Ώ™.~+| / 杁:c)?Q~ӫZ k{i!+r:<>z^$YFZ u e×CC]#y.-{ BdS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4kxJۿ:<8pI7|>*$9bfP>Ba꿽ԮUv2']B?_M'Wuf֯l PO$1V敝BQ:RgL}C|4ð|w O!}hۚopy?E͙OpJ>Uuk v`8y?C»&W}vs~ % E(WG >~~SBфPSH?2.iAi~m>r#KJ*P: Y&!7ŵ3:5 8GQ"g_uU855ש%:|cT$%^O2KzRħ{A-яehҽĤ;`>:kQoqf0QXC7*Jˀ&9e0oB/|0MMSjB{$iO^@Ѝ;hJr~ tfO&PGKy"Ƽ~$)~ 3-$mcz}ɟ.;yoɫּTγEA-hp&5oswgmv`\.4%hT1p/]j"|"WE4bcպT{Z{khmi ƀ*ZY5 $2 @@Nl>mݲj=^%wnL<7]%-T6]3xcF'[wV"te{2G6%87DXkt+s/oi@]5a<a$xQ)ˌRp֣@*9Tt`cǩ0?O7Xj:n5|$twg֩34]eU JIEv#i/w>o-*JPe$?2#"wj>oٝNG=gqZL9STlM _5amF#CS׽ҍ˳$B una[\;>A)V&:{N"Z8fU!ѱ oFGD`jCK)z5wUULX[TAw]IĻ?H8DpR ;/Z 5_Րك-֪vUSK`SKzf(uz~u.p4cjOTAA~(%VUr?y5oÕcqt>5^OW[W_F1{DT 0ʡY|Z >|Qiv*Ujs [^͘nX†fzCbdO&?SGm~S 2 : kL[b%Oz\*lhl_0$Lz1;FZi*# 8GQdߴIb[2ѓLz5PV{h|-G 1jdq bMOz}#cC_)晚ː98AHtg?]ՋIatd/m~j؃gI+~݌S L*EǕdžȸT!q)ĊcÞNɉ)8[c_yD7?_$Eo*jdy 5xkC?;|yl| p1N4.&WOG~n̒U TR"*˺q1o}PIX L"9hLX@%ń,=e(٭)$GNj{?BE14*0EPs @rd '2CzTF>Ugh ņafL".þ.QRry:(QjM X2\c˰o64$s:ZW#2xuRal-,w935Tj&UiWҮ?*\t=cR`S?A FP&lLmDʑoo'Aclyh2-ohdq)7E2X-r2$y΃:jpߌ@fDI3& ǗԠ12qul5:X4ТJw3(sfCj{NNfTsf͕&rI" MJgq>Rz?Tc/8?}(ŵ~d,r}ZR2V P^Bǻe3V>a#r sGާ  /2VkAAѲ}>߃$FI\͚e iWe礄DD> zߐ`4|/:IVH /Z:% tFaȞZEoTҸkvP /c1k̭yyem.q )L@G&0:[ӣR32A(cRc(ߩ5|gBmE1˦Joo5]y_,N_ Sz3&=_+ "T$Ϫ%;r c:$kEmp S8NH.ɲ GvJ/nX 4*IߘЫU8QE'6;ԅQ:4 s n#G(B]e.QIpSL;m1{&lܟMgC' Ⱦ`joaq`uC#suVɪ_c&O_;yn DӕAEd9q"i%t%\*Ю*mjT?uRFk~WݕH}$'`l^2 31>oP}~}Z xY5gR(.l͟+M6^$(vUKY&f!mg6aЫLλEbիjY'2֩1L;ό*M8E: T>% 1jдsՁv81CnEzIG?FLB@fz^5pNs!OݿW\@MXRDWQa1H- pA!#hqSĜE9*XQ]ΟP%*K!mJLYes<7F}? $i%5NG\0бvRI302Z [K|zJo/zLTk$ 89D'obxƒ/`u ~hEݼ57bsQ)qА=Gw +jnTԧП-X; XDYofgu V~[@-򔵬+@~ T:B!#ke2QNx2sVjW- $ u B1H$!MsK2eӀ̻?VW "v? yv!dt^+(>]sT@©#M,$"iY\e+X;5Tf"DOD 9Ɲ3FNS$oAا Ɓ2'mRUgl"(Ny*(g1,&u28M@b(QbHBL||>@e 7+gSwql>!vFfbm I6 #c&0K3h7k2i1ΆYqb;V|J@|z$YMW<<^è 7\*mWa鴉AAy| %Tk٥O6v?qq)ʴyWel? ub0Aw SsOB1d7 FVwk y[S#*xCҒxuX|>;}rD|1k:9,KYHoRq4]Ho=MPoea3L{+=ُ <:c0ye>I'jC| 3`XWj6:k:JM) 9K-oJ(Mz)Z:T B']"YߟY;oCZm?DEyL^#g'URS!m>v_"nq$Y>JT+2ţL#>Ę|(Gڼ"@'[?(?:wo`{VUZ,:؃-{$YVО7BYkEъg9W&k U]1Y?i-L(Ȏσ=,Ÿ@ )cuEKڣWסq_d5}mFHsD/%r R_]H. 2,D`5XKi%xm9eƦXjnj΅,E&ȟqy>AN?%{ŮvYuSg ȲZXx^Ctk~;gB 0d|%@5> 2/a n$R]l.(*V,A")ⲛq^;^n_9+a֎,s"ZEk1F0VʮeFV㚹\AFLPwrMeoúo_g<8La! ix9bqz$쯍+{pU ѱ2p2AYB) LD-0jv/>~ F_XsŦl/jtʕƙ+my #qݨ52x$e wūo~tC+⨑3Pmk(f_ *j9˪XI7@#?x:^MݳlG@>XgF=BV+Bk!^Я-v?mU߾#H.b Sb{& du( X,xdKe,htf&gImW)#?0͹n*.KꜢ[nBw~U83d, }`]=F>0ʇJ:trM1_}vIH clˍ C6wtKipe-S wNW֛7ѢF>f:G<]ycw^^u-/0Zs_M{m0VvBqIeN #ʨd^N|[;De'h­We ŷ( -SU3%VzOKA2."InB_<:!h?VV6ϪBBK"2IH2 ";;JK M6v7eM,lI怕VByDDfte\S\얈j^(Y*N 6Y&lizwa6T@%Rei^sdJTI(bΓ;Eؿ άruK^)K!m-Z4zh*,$3 lx]Y`&恄&#Z);p{b]e3M|%ĩ1 Ro:Zc2&h95aw v8TO ?]~CFA[7މׁ !nS&; ˟Ƶçdϋ!'ެǟ9vێm<m`6;Yjdnjk{1+^b$}%s;^}h_}Ffʴ iZиVl&?;;Y^U%0 c,[TdלWB|WYGZ/YYֽ|8Y)\5_ UvvZ)lq R1[TC" "4}ƊOS\QAZuԘ@YHƩHpǸ٢үzJ %Wl|bIMq^pAxnWt0am%׮U~,B\~. ׈|q g'@P!qSAg@2%WȽjz6E§[W}۱ב󣼡+Pb/8P# W|o0;Ta'GKQ4L`/2Z0=ãe1)ήDRMKVQë.Ç JUl7H*`ޫʞ3Bn!IWR#,8uIܫ~(|M_WRww ;AC<ȯÖ2~y݈̔#hmiݤ`HXt.̸ O`[Q-}$-U%?AzR˂h|T\v?\>m"|N\r j)4B/,ӷ ö)T\CBBq}IvcG9=g.0x^2H-/s{OS+"SUp"g…,@MhEިD0ȩsڇ.~O p5VC XJ"̳~ n٩HwR.?E^3YI⬒*~|iL T94]t/Tbrј H^@||b9AF 46VY~6rDk5٤ @M?k.th)M&"?rdR sj͌|} ~T0l[\Xܮ<M&>8ueXi`C6h2`E+zI|iP|4~0~jsVs'_Fuk;/AMԂN ܚc:b=-c6ȷŗp'z\U[R'F,%=lqAռ<r KM@xԖg {"xv(r5y/rN>EW "̽ij/VL3ء`IV9It;ŝ@%c8z*g\~E1G'\3(%x :_(Ts_m+R6%x9Ͱ/<~VNI?߶r{*\}w|tA 2[H^J|Ri>*MB-}6Ɍ@}xZ6G9W9 DYF!y~|]7ͱ0f~Ш /&1) 6MtJ1ln0)i}5}ՈDĿI}0eFmY PU)ߝF h3[7.iePdHvVm#EEI@sץuT|WAb_52vVs-¸Wi & LeLƠSeBöq2_[0ma"ޖrP׸|Wi~1pȩzxߠc(tpH lc:F 5z4‚7dB,s$`O_E1󺧱>/-{N_Do#}DNcV rDRSYӅjߗqu.Ad#lQ̎ԼɁRnCҀWĊvZķ 2;@N7T1/mַw)DdqL$ 5G~OuSe@6~s GYtxH5xn[d{.28,ek㳳G o[똆[E3)*V(Tu\GuA QڏkAf Kd]1)N<EڮQo+jgKo8+T:9jm`kT# ưtO.VM2ۜewhUqу37>MkKdӗF ݮԐTcb1νLӑGKkwRGD0>qúQ,w6"~.*o]S»UHj8ey;u[qyy dԶ]$o/.xC "&f,#qn".H#_#3K枯ڭU BL2J>ߡkX vKn(M+doN(22wbc~r$E ލnF2#=kBwia-љ?5"ޑv׆*}r$Be:fh' Jՙ]n 흚2T9Gwx.~Z{kkX`]ԚdoǢ@xoLj7 s%yN0.gm$As*DgV1l+EhwO5KO(WO1ɉPX;7Ct+4wj2 Ay x*TI[?(KryҢ-ehҭw$/A0ooɭ <_紊W\{8}DنŨö \rØ eJT ,!p<&MXvXI:f?Pb=8DKs%Z=;߀Re' #DVV w:Z5p;yz5F$F-tʵE`C(@E-JS`Ѕ,;J7,*d :sz3bj=I% fCcn( ׈\B=YqEd1xN#2.baR?/n[+$9d:! 7]%h}].SZ^Vgͽ 8II}aQ:g9#>v7gYˠ2q&~Nq?o4Ͱ8XT U|,%L;:e';$} +ñoB+ :)?뢐j,77z2=B]ٺm##wNgH"WvR3 [$C_T :ήnA̦bI&Afj=*`QK8-98EKd2Y!xAN4/X>!Ք#, e TԞyJ8.幒o{f8XJo+7zپirsɮ /UχеU;BN>=>fxNJ'uOky1O!Ϥ_愕QNPg',$h06ɔ͑vO 0?>rC jW;!j)\")KaADL!n*np,O`34(~}14zG(%3,,V$,!oWs|ZmY4Cgj֫@Z{jkk U(~*5sX'~-s?|>Xz(b(&zLnFlؿ"65PYǏ*tL2w(cGd[hco ;Kamy[s@dgf.~yoV*涴9z -A.M+5J&gXJ26^PQ_{,_6 b{#cAcEX]VGH#a U/,2UwύXNu2Na)O٫pT`6SUn,/knSI0[zaYKӮVM^r+/٫8(D!֤_C9G>)Z~7[e΍}M7*˓BB)ԾH"69&qh$ɸsgt+7ZD<( yvr& (rL3!U9ݔ6w{3NLt@]HvI LwIeDelP̍‖BG$Bz@W3) B1H^{ib+!Ivk@ )Ms&cF85OE$^6& VUIbNC/s~vuozwXlx,v؂Wͨf .aE1xuSh땶q"u!!aZ OH{W&niIvM_m>=M\ s!/$ [ycW<{\Rg55B;ZKW,q6&xᎸtS#Sx2%&72fb7(]oo&ZNynTŎT-C};89.g78w`Yޙ:ktGe V!n: @]Ԍv t VdwUD3-0=hhvC|zVD ʲ>Jޔ1Y=y 3+b!P5*9Q7oLؘI C%S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4ApBO08X ƑfNSu2/ 9bn:/.Gu%Vd+dz Ւh& 1cz eyN Z Fs*|;<|w k4r2w|.0vWSn!n($ض)ǐ)"hMV)h$,jxx)YϏTH4Cy)cc@`K~$αi1gMTFeۻ p=45zb@T7 5}b^X)56K܏zd~ Ua:|GM-8łmB%bi#`p߮P6'|$HJg@5f" _^2)D e^vQgw"= 8CAHCEjY tW}Cj#/p^ c~kG4x+IyCn 3/{$D( P]'ߜt8)m((8cHh;ߌo-')~}m^4:ԑcz˾pA ec*28y3-^ɬ"!&(l7b@3~S{X_c!ygᎫ^`m,."aa*)-= P5w\ـ}:6p/lڲ 0u8 #I`eK/) ;<7eN)HNpU聳*PL4^+bq.p䃫Qv(%d}MF5`ómy4VrfDR~WK ۏ}GvR_~E㎥7.XE D (^~Rи0BWbs%a͑cٝ;{@别?h[ ( :YX5߯t2*Vy)4/Dv%0e;GR?3gWwZ췼^^n'h'?s1[VXuwdgx~+g#8e#Cd=#`򳱍xuikX|xM"OeRLj\8J%=_;hW-eƤ_Y|ǢpB>JT߀kaJU;kJ"UwZ6t i>pXZ8$di_xmeS9-[iczV#V~ㄻo۰&%;V"e#>k8A,(uɯ,OD``W#(]ӢUy޹/Ia)|_ނk1ຜZ:,90D%5ZK~M_>XOz_캤rs+*xBC8jFR|C)Γt2`lqG&*Sk-P0ߎ=VgiWLzlxh9,XKbm ^x"IG#n+iw6*Fk܆E33%|x= 1 .G^6-y&Q$?l ڀu LAռ*740vrdiNՌ~IUU|&&AgafDTQpnNϙG%״PC͋|f`hyBt3X(F 0"}ni]<9sW5g 7dΠk/!BýpH 1pYTW ϐ󊚷!%4?yx+3jA\bM=& B-6XPjnqН֞` 04C5zp7s&owU>=y\':f[H8BFzٗILB !^cq0xZ`l؄pMAe_J9upDZ-Ж[7TS{i±AQ4zsҽ2:úwm (OpdY,cOCyE?J1-n]\U?]%J" c!+ '6WX6ɭ d,M\6Z Odl`\LTM?ѹqB~U>qpȞ<"a?X9 ĤE,I1eILu3o;yHhZᬯ"m^()ѬYQY^k~r/h}-EdmgJtRTwn"-߰V+hɄ=(n(+$} N gXrԒ/t=:Q˺L{ qc %qm~ E;3]ꚜFr}=~l%pΰ;ܘKuci.ȽGe|xmʽ]PXibDgfuV޷E>SA(9Dm8Cx $6ɣTΚ= WJGH\ax7Rß͍y" ~3aSīN#\ 0ΚVLfف2͕b< Rgήtszx_΀D!?g"+ W1T_S7f} d%R2(﷌\pZqa*5}kF|kLOL icL1#H}: =1:+5 aV?ᘷg|GI~-N˩!xoã?ꪈݐИniYv<ּy( `; ә so(EtKuiV4z_8,Hw,>CO6mgLWm@J"?˱|^Է `աv7<,v]>C\pyZRuHQGfS؎@X(&ahRTX"8x>+A#Ep4 3mEλbVlzXäe'hp~9Wt2Hfb-OQD6+x0-o2 ʰuk#}B=8 sBaĖ+nkWgbWrb!%IkH&U#.Xuiv7) 7rRwu4M@;& 8gw4iSO%<9H"QYZ[/!g~쌹~TN3¼!k ||q}*9 'p/"aex6xmY^ˈlW)aݚ 'ϒ@/BU0l $F6iZ_DR6+]zݚ{*Wᗗ8sp/VG<)=, ޼k|C;Z~ZN'MZ43qXt [kނ3@`7oSL_rJWq{`+ꪣrY:I[g a>z֑G&3S L-R9TqGNP-BuC 3Co鉶5TsZ[{`YȗSH9|ų D,!w떗lYh`1TH`+o~׿962^ r걹Z^[m$cCcW=TVjzw/81g_8ZU'}:H~hq.Qx NAF>n 1ۨWz{~Hc|ͽ̘Dㄔ+|ouEBŤ/v >V/i X}tx'4#\אL.&tGvL.ptm8>/kU8}Uܧ 鮑B'n ܯʿ: Du@'R3NQ^b ztXAaIg?pkp^_|=q&#AԲ]Jc/*ۚ4iBG3 1A֧nx?'_\$J?~|m p|r/{$f$A_B)d6EDugzYZ B-*F UF9 *f*Ye nUh ӌ'xoVxQݢro/#*3pQ,ݤ'? pd#.b&..9s.<U=sR w]NR"7=)VBihUh.7IGqq"6Q:) a$⮳S- Q@zmMM;I1wog q0'G?4a>ZD юGKuvȑAG2ඣA:z/jפY(0P%ܤu5؅O5g ._N|smVAQLhOoBQIUHzd$ (ZNEȕ8}C8N]?jrr*#"ɡ>kG&m;zJԢ(lXk9v5k^Qڰ#6Ir.uK|*L3feS2;!h GٸE5) y?hn$<߶=Rx~ o-捭v)@,v;"Bq(z+M%|i9d3%lb!>p AQzawv+&֢1wӇDNpZ B$\Dѐ`i,>j#\*re S| hV)*3VȉGd#-m/5WE6=Hq ^RΆIJ=&tOy@ӻ|4m%#%=|:ܩ ,Ԥw_lN)]K腪M =G`# ɻu;4W|I.',I2OW(v'^*zgwoaubv> X|31vz?,Q\JU|@|@|b܌ӝ] ?fՓ|>4>e2ZᴴKt69m:⟰"k =ʝ6Jc(>eDO o?HZQn$X8/_8-jhsT;Nw-Th9x{: <4]OzG>=!萌+ƥ _WmV2*ԙ~ Nǒ˾ό;3Iv&y9aPk~glV?  Ѥ$bgB,|'lBo/g͚Fw\82wvg#QD8:ĮPcum:r;YJ{BW<.N`7XW$(*} 2ʖ'r鎣y;avܫJꆍۏ5QIz-#b%1݂a̠ c1#*a]\㝢W0gB=GNml9w[쪿yVU/ h]@@j( ]k8;u׉+0Ty;Wp'l g';+aSӯ+$mE74id䕳GJ{F.窒Wl8&oAy@l! ]~RBQSnzm)~.+&:wL{\u[]ʕEp$O 3:-Q*q!`Z}52]=%0.dC; gpeWP|"}_Ц%#gRc@4=4l7$HHF ;@_ UU?`C!f .}AKTBAKo قiJeS$y/1r2;>Ɓ5bG3,/K֬+KAJرa͘j1GcqjK:R~t^ڤ̘@dSFױP}#4s8._j4}Z޹jr& I)Ӽ+G9k´xDQ6jt<5 3_vpGjw6攱6TBw7vxZﴤ i0k6 ;KQ3Xlyn%9nDPw_O<`3x7Ռ O0!wM Um_9ri1 ?sNc U+ɨ@)0OWYEǨ5Ԇi-!yWm ˖jXo)~b>6~^6u<ܟ F$w҄k|(K*N1b_#3MEïYoUڒ{m`PCo'moK]׆s)!zH`iG^x &)n@%orR {18G@gYv2:K-PY+44,b'µ@ATGQ >n*bUL5|s&]8$/Km }^M l/`FN*e䳸fdO֒g60F-/4|PꜛMY>a HvҹdP.wqGc&Ȇ%glOS#c31(i?V!W7wK bv}JExk?g-"]\,%Q2Լj{3p6cgpjax8, 4U~a˙[Ƀ%٥Ŝxұ+h$ƝSs\Fw<ŲTqShF Қ "<)ᬸR(mbbx#'gC&;5c,D%X>>d?R߈ҧ!}ў}NwdڔoLX$y]*^K:u竔G:#YD7HüN1(Y:95R Xև<I)+2F"ȵHOm˵^n5Nsݫ?SY|;⼿=Ua׏3jϞi^ g>P˙30$vCqƐ ab (?!TG2rv\s㙉 ir5mܮT~*9!% {H*0$޽mya)h`FSITn=+H[a5Š67 }ǂ !vQ/U&:E<o  6 EX˩tŔd~].Z X \mwDBm3Ô]v&0'>&J~)c VLI=p HW̾H=ݚs:$xypldqGi=1sdE,.Qʮ7sPc+ї^?x9-a]@á1}|:+q_nN=1;eRױ i~ܽtDz=C"+W+⒑W2_|z@A؀HY [G1|~j9N{&=g]&(T~zXeM6acVC"&(Mvs@BۤrELlj}> "'Hq"Ck\cڧp@|磖ϻYGko::QD { c!,` E=Vȁ/fn5:JT8#uߞ 8BXͬM.O*JOrôE{&N~uZ)N;I+u͘b :'Jh/[* D/u|JGW??D&Kky1K" >eaCBεW.u-d֮nze9<ٜ#HIt͊mn8K6.]}Sμ|@jgUbPQ/ i*D 7OdW^,ˉcz/RAAWa dG{+=1Iu6:eWZDo6N$}1knی9¤I XG&K-9mm"/?H>J\y¯gxg%nHc)})~D]˥G_>a6~JCflry1OX$OΞZm+Z7ۍ+6i,pҤk¸ESuIɰo̒2`z$G69֏nۛD? 1h5/:pbG{FQ :4( aVm2dG sQᏱchTԎ qOtdVPlO路"ӟai6YU/ J 3ޅ"84 U˭ݳI[rh &AJIR_&ɠa0@(x 6˫A:NdK NWCѽd&+٠Xt`cW>"·<|dzQ0`x>7Tg-G!3<)9 nS_nb<<Wn2~a{/vƌlF&|nb6^H4zD WP5a?ƃOQYB^\$ Q1 N^ EPYk8Mdegr3XS;x/pka;5\JJ47퓫k; yehkwng@0Y(yI᝝r>9%D @K5#(NR3t0ZD으 !%oR/mX l+wӲu^yd5yϜY_9o6董n11H@¯e<-5zCf¨;_ғ3X-xe&Jy"oRt:G/";@قu.4y[.t-JS,G>q޸&0JVa7dOYJ}0a \2R.3?iXK*?@~zcށ?y@K $$ |+&R[!{ cN>6_MO,ƦU;r5٢uX́BL{Ej+=mGh60uRkiވ!vB < @4ٚ:;6։; b'wI(j "^[.ew@ $A|dpsbz[1y@>`C̕ ek'G O*o?UpצOILb!ӂ3BMS Yz<&kVT]gG:CsecaGH9з $BNu+]Y .9dE2oaJ@. KhU黆F-x ј>fL1AUFH tQcEw*>Xg 9j7>UJ[QHKXh_a%~7XaZzD >,Mp-4x0sbiA͂eHҖ/-6ޜf|QԎ |NXC]먧)`AN2^mOžQH>)>TRG ~Y]ɵ_ f iܵKӾk>4]cxCǚ5F! ":b]f7߫.Z&K `. 4htBcû@(kO`FHf) !xJLn2pŪI}zr, lyiğ+:gtWMfG;].^Hڏw]<w0<Ӄ[[#|+"XйQ}&R1 K{ GM+ ۆ7`I%0_IWn 0N<& '?<6n(+X`:DzbXE79<F=u_1pFoe*spr[lh <eFCJB;svxAso/@pոGĜ6UD! WƣX^' yp*i%% .+J /FHi3A7`k)5n'2#,umy ZMd4e0G=Ĩ$]tl.; {m< b oƵJ6]j?/.mpWe)ص߳(7Ǭ4ucL8 )  k*83$ N*ܨ Ju9żDzء>^!,F a_x5p "u+k-W4M+2?UH*^,闙v rB1<2y7ڮ0XI1M# Ltp0 dZ\iz>.a }C3 y.mkY7FPu}p82\i_d 8EBki^ ABzkW"mDrdET Ë7ȓ\'7 %/{%Jg5@Us/{7l_,9v3ŘHb09؅R]BTypGPݤp_9x@#}$] ~$˂BhhТ3|uA:R$(j{/ܼy1x/DȽ+p=.XwmV `%>XGbj: nS}~duL&cg,aF*s_G_*3\ ]VYmPB&ß- b%P`'7x^Hqۅ$KS~zbU଒% 97F= r@{˷!7`9fqH8&^tnrھw䋄è?Wt(QT'oUUݥ3a|lk E|F*$QAy!) 6I\3*6-&&wdTU_}*4uӨiN5;.qubƷE7:ǀw|g٧DXMk %|y౅5_J}/C[9DeYG\[ފDMqH`ewէɊnA \ 2&u',h9SCyK]1VUspmv)NPis|Dʑ_8ଚglaI_1y%W- Jsb| E,G͟!Y$('u1_*〠GMq{>D5=nPp8}}cطF6_Qĥq UV!렄EWVI9)L3Fj'QU3nn\H Yդ˰Dv:p?=VʓN񳄄Vvo3Lܵ'Ŀ*3͇-sɞgPAXjMHTT/Ԡs6#dԍӡt;?ס#85RfdΞf+{oRv7 ^j"_{]& p|o!"߇-/Hj(u[V.wGw^nzy" RK/5"G )y]62j#m<@<+gTa|iY%[b{;q>~ 뜃D՜rGM:dhYSɞ]aZxol`..Ye>*J [DA詀'Z} p9C:S?qY: J0j{;zү M R>R+`7u%F/ˏ6ԦfVyLFxXAcR)YRڹ?3Tޅb֊Euz_W4B }t2<1=[8*Ո2>Q~ "fo25ĩ~ k2dR}JYҞ(y:k]'1/9M=-=SWaWàqZʩ.z\Fè,Tr低,P -$t~&,D$ B4F)Ub),?Ev֠L:Ll7q녣<ϋsSާ%Nl@U=htF&ު9]}aRBd\e7[]pr6Dr( GC#ik89HUjf]T,%Myi_b= ryjFa^s\N[h/’Y6y{:utny-h85_@Lpm^=P6a$ӥ,HhsP? CS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0PG1FR8H tPML_| @:x Tjl6rrr[%,g*?lW3hKz3q~xj:r չr΂>|Tî@|w ;dwrp3M049 dQZ7eZ䧼JӿM1)(yPmeEJ&%<'LVݒب%h$}o)3h]!&XƠ婆EN9>opLbx&F ((dwʹci]W Eݮ ?,yq77~zi&m_dxY#_NyM4ACXS)Peo(qD3@lv;>;oΨR>IY4n=sX~6Pub Oq|ް(HjErϧu; JJᗎ8#y֌3dˏ ڒj'bl^ ;15%!\U5=ĥ/P".?6͔g .(A#ѨVxpұ›ކĊBB|}B8o*'%<Ă0W]!=IlgxNے&}'L+RR @GZ7SCGgh$ֽ: 3@ G ?"ˇ|/:wckĦGG?s5&ZyUs.<6&?KgrV+6*O!MBM@fWo,=7sPC&3S* 0DdH:e\äxĭֲJLZ6zbRi=1;J&Qw@$<6N-$aB-_g 4h\SkS>]s UwhAP&mP#+W6C:z\Ai;pZq6XH@{E$$5;LO^/3dSG# {·C .Qw92+!l3dp5( ML?͙ePǪjjC=Ӌ &VIu_ՒLkK`Q14&|! '~/2CݵM 5$P<4 v1Υd +{1jDaWF^_+'/ /Sxe)MdWd]BD-cN 5cŲF_C dC}8ga;V1nXAlIc@ti}j(#Q(qs3Tԏy70Kc4֗,0W#i. tܤ~mF+[GMEҞ:/B3<~=~M>xV~Oz` .G?# nvcb/E).Nno#7X;P^ ?{|;(3{@4 ,Ϸ(\F$/&XG#JtF{}@mB]#81aG.;b1-֟oĴs蔥:"aY+ nSNRfI@FtM?NFIŪwZ7nbأWœryE'&56bǒݱzw+0DeW󪪼;EDCpl_Z(Ӽ*pG{A@-38LW"m⪵`oяifF3'iNd`)`hZ1H ^> zPl f sߤ N_pK|[uq!U/)Y@\kJ3Bw#pmߛ㺢WaP"$(LEo0:tU10~!Gm $ ,Nh;6ı8/@!s`{rWPdYRQ;.߮jM|2:=v K7NxlN:݆cQG{#G\Q˭H cuXB(4#lմ]cAw{`gpAlnD:3ʰDBVs͙9}o) PdWϪ iMD^=`:S 8U3}>읗n]7::FcEtIN,@aZBw_Co~\qgD-\#¬V0+@k|ikORj?,/a#m3N^V(ZS?s1%<<=rՔEBSri+Z3e՜< 0LPB{)5eLS&=/ j_ofD Oi= ".CG12RkyFфY\E-5?s2nˉ&{L3³0: fjSJ˱B}RB9^Ļ,g8QziR3Yȹq_8!bzU nB'/Dդzs0:t8. u1p,~@Xf0<6V:zÃeol&SC WpM7[4|H]c$MdXRݰCחMBՅ@d<(1FBE[uWUk*jnZ %%lнz 7ζyVpbCy$:G-Rz^Y9|1zuVHRҔv7O.ɽ_:C,oԡɿy*409C"a^ܕkπ4l}Ӳ xL,\#bZ m5r{[6!.Q_9Iux "VOS4y1C)Z vq)~\%ClS zrc.S-х-EMfJقgXt ><ma80Z=%u>-zLez794{@QQ f JN2_ ܡWגдT~mr%8 tmnBaR29zʓSOV*=JvuQeL'љdC9\uSՠUskIo~nGqaju1̒Q540X!.H<0%+zȐ1|^jbJ^$3b׽X E]|KҼYxb[ ~IJ*B2'63p5;0j h@jKPC əƦT;E%:[:4Z)0.*':+?.Y CE1_[ Iy0ܚ%ߊhb@ԓR9`?w]hu謕0+pmb]u|!+M|G&nB=kq<0c%SXf+C.sH*=sYć6̅\8XT fwt۷7U8w&s4ʖYj\F&a5)C۰K # J)C7b~DUJ5alH4ބ*sl %rb8,-:bYw操"%%5=q+Df<F(WJS|U7nem!<>!\sN.0 ")X3|SwdV^vު2},a5?MÂ3iX kDOt~PGLc$ Nify?'EludG[1q>w3-Tang~X!ݴL1 0?qCSrJCß]:,-+g>=e(foVm:'iČVO $=# 4YvZZk|fEh^Մ4:^y!8~FIޞ Hk#WxD b1!4@>4_Э:V!$.ϔ悶8;A Ɋ0Q ȥ%U|@@>!f1m%)@@|j % #Ip؈ʀkt 1X 9}6J ]q{kwsln04-Y.}:Md+M@g~** q&M[C D>ѵq b{#jhV#s0 #K@3^zډۈQC2ACl yIO12!K#!AIz 'XxS;Փ#ىݩ*a/mr>Ҷu Lf<[ٶ.hN QÅ8<&VȴXŒlґǍw|݊3x[X{Dz=,>$ :gaEo3~)9$7Hd+t$Dhta6 KR0tC/ᆇ@laR%s԰"o,dm!@TK7ug7s.*KJfq=\a#""\ϋt!,oP4|p:o49Ԩ9ul4gҎȱl@+uU{!_f 5v'4+[C`m }4~I 8C]H83Ya>kS3S(2a`T]E0"\gp?[f]?1*Ohndʧl^=dZ8b7z10^74y`d%Fǂ'(e(UDq4KvvHGSY@, 0h/k3*֘e:]'28M>^ T>>JA\ =/>Qù)9_ʬU+SP1&dq`Vc*'? :\;lFe~656[1aGt љ?5Y)0C8`h`ӱ_$wSsG)6^DZ)PJi_M 3Igߴy] Isj|jюL?<8V&PE*p+ NF}{EEy9<9+kah b%㕽I'`"=ߪMp@zb4v^ g>%u}%=eit/MYhh%kueDL~ݶ̢wq>쫡IMY^#J*u$6iUCmBs+,XfT7kr›f3HC03wZ zl &\YXC @ɴVgə'!u7>ϰI imwʍ4kЏ]@'MѪs#@1Hˑ}lftA4W`C)_! PCne1(t}o ]J9zO*4>gpCps8 L5bG4)ad&ؤ}ȏ!(n_K(J Pj msۦ|FE/uG|2p,䎺&“`!| g MYi5!^ջwP՚UGl$HU7%.;bX{m165WM̈́w9*(Hn1vӝ #LشJ Z8`;-J6[L#Cc`eȴ1ptr~au CI}sb=~|oiyTVyO leq$VZ_N"iߒ@C-wB9ǔB@0 t1 \S"O5Fn[%pW=s\,'- hA̹&"})"Tog(^ࢶn)eC&)\.,6ƌܕ`@w{, KDX"H [*yw1wI^zUGaÌ!Gx#|+GH{N+FZk8TrnUIuyzڻHD1"o+#ҿWfdEQΩOV9'4h.bJT`*s{=0T҄!dzAPއVr5?a9P`.8: b2H!$5N0CBNee:\݇;רLT̋I,p:fͿIWٯ/p*9O1JjY\.yNe$w{37rDɀ~ry>gr?,qUz8eJa+,MfXJ^#:Sr+y>'{;  ,фN &Y1Tsu?ĿV]f>9%e.)=mcK*(j|ۉmbc. 8^J-DQA:6*Ǩq?8Ǡ7l "M$3qJpX$Ba[rFz6b~g"CU)sW ?@[_S hj#8 =W8"ۧ:F1vŗ03ԕ|V !W62Y t x6ס? ַe]sSv<-hpBWJFe'1U4zI߯LH8;yZ*Q RG<W i .`O*GT%|-ZϝS m-XPs컌LZ1?i< Sם(59JQ]>"l{mUgpYV.y rQҬb(U^:7ۃdf bH+-?A]M( ۞G,Ngԥ>>k'm9w~Z斅auxEEYvVd#f52 [ׇRKDÛY&ҵ~ _L9{' 5Zdùq Do0y%'KDptx 9mܺ)P$ٗ׈8坲 szL>aZ88w۞ omC!yBc)1gJ1.TnZ[x`6Of<].tCsSwj893Wx` ᑩ? |db 6X[Eo)qpUjnKX77cTLN#`lK $'!ӵGP  ЯY @|@>!B?  |i  GcEt$w3%@5z.4+x;t߰ZFnkM>*E@ Pfv۷i:KS'ʂ pݘpaS8Wq|op>="Ls S2x_W|9Fѝ{u\Ócd$~ nNHhuxuWhjkv#Q q/slLĕ6寰Xz>% |l'/| HI5Rf7y 1\PHTYNs] MW*KLu5Y.ts>hε(|MZb_\yʟie+VK3.-t()'04}#/jDR v=?,4뉆WoIɧ23}(L/>Z_-`(vҍC{>z~c_ܵk~RhA<ީi> \7E*|>@,(i9@eMdfj}fK΃L* 3,J41%DxQ?fppXBm~RXKG,IB6aiItȈt*ٝ"S̓Oޣ]-Kq%F]jӮM0h騇27/zxD"ݶ$F|XqXSiAz'R[Ϳ&9P.-{ǣ Uْ+zi{ xhB.qR EZjsɍhrY|y⼣v~ &θ#|IʡݒJ ;EH0h5AA@ >P9_P 3`*i mAi_t"n>aYy 3RZ_y6ʠBR/ľ\7l&UZe;tiTRuFcuO߬,H %Ѐ2q3^V)6LǬ Hy‰; COk&f*.θwʕdI>0F%±GkzY;~h {lWs Vb(Sns]jSM;X֫:#BXi"D۔ Ad=gKs4ѱZ/L( ɟbf~D/q:܈Rof^ 112+Rf"-l4RʮÌ[w_BQqMӬ po]Bl8䞉g0s_w']]dW)cR^W{a0?"5 lmXg+ A:NUgKlZf石\Wv\DygޞFFN:/ 1oQFF}[z-t =96QI"GSN|0hϰZVtE溇\VPřgĻlsCfcXY.[FFpϬ^M!e:nfV+xLs@eBP哇g> DMҞW4K?OzGoȣjQxa^pe= Zv1pSe\V.8' /z`L܍4㤸y*)ګrԦ½G ̭~.4Gĵx?2<+#YT|u9|]0(q֤ؒ΄*1.kkBLڎ}0k}vՌYyo8EȉwjEx 8`TQ<6-*7WL kB vR8M53G>X4U$;E]U_{TbW G761]P_ψ4&m<^jiw !\vrS'\]G<4>:Qqƣ8@P}ELL/Eng Oʉʃ2=?)5)i5vBσኘ2t/:@.!!egfWl/@[r!@/ 4H.fwEJ,1ѮO>ݻۮPqAZAY~$`6vъk%ND$ !\R8%gUXGBYbSYccE3B􌅔Ka P{rCp3+s6%k󼰛o$9Q{COQ.,l :1?Ĭ!2/'PtU wUl{DLV2!OQQ:ē(g]hXK]bL6 aX7bƓ+?|{&%M, {F)K=5R`} GW3aJUxL3ݡhsEq-%$Ao2"| u`qz˺wq![;? teOӡV?b ˗nnɗ9YW*ŅfYZy= Z{LMNjY  0j9LH r] k$y:`s eϊ9\4+3R\wUb:0Ot FmMN~lvOœ:/* BnCOKi(GW])mNã(}kQ|0o1_(sE$B =$ ћҔ9Gs~\X%JyИv(JkE`hĴ,^f~W(?׷Vy&p9WVŐWĕ$ӄC~FI^shd"XMM%F2'-"dAmw&7FmŵɚZ-@dY}kt`T|!m!z;s")wXFx.8g}t cm).NU*A((@KJ8m?ğKxVZԚuh ܁$X5,jRqD&'&1{5-e9JT.6Lg)P@ 2&[!]r.OظW^vmccf}6tw&-jt~}tmďWyj6* S32Q*PPp0:9ԭ#}oK?G94AMc>-/K(#-kar?n88Wa5m7^J[]u1ЙJRZy )7qԸ*${e0^5/)J*l|U@+)Hd Ŭ2j( F3$x bb=>揦S=Z1qTVQdݍڐEs Dy*@~u#e: )y3?^L}hyNsvA0.q}۱:+At:scrHır vm/=1KWٔ8COXFm4k%F2G}D#V|7 {X5 Z=_OZ:44v_}Ĕ' LY>j41N9VU\)3 PyF @T&ni0Ĕw3|7&5Bs7SR7:pSeQb[O@0k1wG{קfł?Z eagbf$]uV?P6,LMDkIdY^qc ε=TB[J'M̴ #j@U$9ZXDe`^W`.Û9a2H `/}~sM 28Kuvwe1rdڱ~wR?8,B*t|w:{reP8Àm`NB@NX8O-Dr Qx nDwW|d@r('4YT[J6.)aQ`(׶0C-CHh񍬌.uKߣS.nJ~?umL^g:z\xڀ[/Tp/<ɠiQ/:ֵ vGBbqc 9REJU:(!6`,T5Pa܎^:Ԗ@˄ [̻9@hƶ>3 @˰~ӳ>W~gjyL}8q!Y`,bS/.ۋ-0 v׾,Гބڬjr-gl%w9TO3$Tp݂$¶äl8tn &E4Pc>ڨƭrVS]mdtGf0韥䦈OT~5Z㩆IE0ٶ6~9_\X-Q Pl|c>_u`*Kÿ([Fz.Ce-̈^#; a?QAOu>bvJJrje:]w[NJȪn;3j&_8\1Y@kKlQj_HFZ~a0e 9H<݄;-v00GЭ\X!u5"2T8sp1=;1PU(]-,SH(b=fR*6x[ބ%1ބʹpJh5WY^h[EudAtTO19px5,dtW݇IcqD,뢠cò=_i-I :WGLh82~Lhbb  R,!ihj/)i7"Y_T8B,1l&ukYdۏ DS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8PKWH߱ 9 6t/0x~P ?ʘ `E DmRgsQd O7!7H , >\XĮRbƽhr>b#NmA?Z\0mnu=j%f>q];^f{ |t4ÃӚâpS:V Nו,g}7 ʔ`8%cJ4z1ESzDžNĘ ,oVJqsMn ip_ ];*gWC#|[js>%\uS<-sX"HW nm7 _|-:[wкbb8.^?e2a '?olO#7Vf;bBYL ȝ+N$v%U2C+]N)ϟ#O;"9j&-!F>T𛐷?~7ߏmOvdƙ#do;;چ!"g8CMdXf=IN_V4{,U}nnԂOg.bD¤q1ґ0L^qSoũ?w=] CmՅws8riE7,r 9It^;Kʙ;]q c8F1L62LYW!"P'oʰKBl`o{߶u~ߛ3S\}lR{{=-ϼ GhA .¹0T-MkWOڱ19()k6&Qx܉rXSE9!0ԍk z%'\;\szئ?.ڟ{+W3⬷.rߖ^B6biQJ^5b6TT3L@M6c8^kkق>n}'|H蠊wDg=+k3/_t4LzY CPm՛Zwr'K??uCyޮhwxCqugIӭL??UxjSLDG׆ٗE}"hX{ôT>eRug{a/̓PEQbޤLńq6̶2ǗMt(ƏR!Jgtm+IQUgC`w*dsIOa64 >:{z jpSWx[uR+]p\E$חmcUzQmI_Vwu1)qxѾ2ԻpGPMQQKh>ޭ2.$<9麰I+U#քIGHސv:JP: HsӱI 8C!I6 ' ^U'j)H`V[H8ՠZEXq&5YCAg"M^ܑ֫S '~*|ђ21*ELVaS:Z'Dmk(SN6@R eFvDC̘LFfv ja5-dOzf@i;%9MO' +GG)HjQx/wδR,.H!8C+`LPgB} P[GìLO YAm)ֵQ FeۉΟ|\@Π'|~=>8d~Oz3Y+dM/H">=DVũa7׉|V!:#ƚw*Td=f*e::M*ĪGmjqtG妬өۨ?vFssz:EۿЉ&E@?K{!0م[!ws;+VՒP3%p:M–lLOތX"ȐFZ7FWb4_vxP/RhL3* 1ʟA.3~nGſ_yP_ۇr+rr]"32i@Ļr27O/#}~yD &qM;AvAoe^|ɴ5o]A ǒ!n) F +|uT8ONd2!FY̧8NZIg|0Vg]N GJD$i sK&ȃ{SM/"rٺ#ZN*:O2mԎYeQ3ovnqu.֗5BtҽQƳmƴ fbxEzz|Rvf.FzyJx)A[lx8y,*+~O.!)"lx_CKx}~oDH 2-vX,r1QDQ} oD<9Q.]kh4cLɓw 0?wu ւ|52UmN_bNŪY)^3V5KYzNRyoϭn9t:E`Us(@3Ⴊe(9cۙuGZown%p9s*a$vW=:[r^>FkbwKPan?A=jl<.quTZRm"mSݫNW9=椗2- ;,-eTeS$ vY uSwJ6nJ~>Qfbo.'׈Z?+An%w({PV@: N0,loi}d 4@2#Y"lA=ϯo}9=F p$)N IgR&Ӯ$Kç ^1VwGf}yʥojwg~Gg{\3I9vpepd |yMd,b/2 3'T5lAV麺SH,㵇>G߁+y0}䜒>V;ЊATU72r|qхĐ[w޽%4{~DyCS< H8QbC$'5`w.M0cM&/gb'2-U>A#|W%7󸉣 v /fpg\:+W6,Qw2TrJb`U98Н&gl3UyC̎7&>V~kpb=!'T=xZi .6#){ `iFm2uXgA/3~fm^v2_qpC:»UK.VoUȘ654Qu )ѩE׀rWwhϲ0ǬtGpKtt3h5Aᛉ@ D3A.#Mf,ZWaP#N+g|4mFΫ)sW++6g7DZl"GX]Fs'ƑSeAa:˯_"JET޽\st#m2#hp%*5sX]1ZV>_m{҅g'n/XUj5/$ku,DazLqNB_o~zTHG}?>A`񸧽G^Lst<&g( EbשgITBoc&2cG5 UYۭ2l#3$vh*AU>ϯy<2/?"+!)|#Vy*q:ɵNS_rwD|`1'X7<|P"x ]ziAA{NDX0]`,G:q|! 8B8-!f0֙uYrW=)anR@>,@1?'dUeP3کZilVw4#YmifË4(gj>pP\=2OlzA%o}oQou;K"R'lO R0+(lJ-gȪLe*T!#ZL keY 8-wtpbV=k njЋ,UށH;V7an{o\a[`>LT+ʊP2l1WC}6eɆ|綎}JOc C81:$QMwwOҁuph6,.+FMgX?MW7bl`C}i-%LʔwmX|}=W+okx@Ig;(#ݍiԗt0ħNhtYfk^Ci^SE.%= @W1J~2!'Vi^U}0@BTl 盈8oTIq -{7Te&V5řګbn*1HS< ^|QtjU7p=|AshmLrz!le+$W~VT[OQ֓v/:nh!)j5+ &ŝPGV IFzA^q2ЀV¦30mX=yXĹ9%O`Ek3qhwjkWzT=TKf|JzFUٞ`@oP~' Rۚ~ 9ppHq̑X!"稜hKCJs`-V79TDљ 쏩 1ߟHExY4*xeK ]/,rD}Iֈp4"̢P}"l%Da+!:#'`C{6OR'`Ɣ>h"6ڴb G;v km,' O( ۽4lP=@hŸo}bE.lˈ{jK;y a`m6([σn&fwHM\[qL`R/ M `ˎz:df4lW,+ӗ y)GY |R0;}:yxem\`*YO1+Ǚߛ'9$_K/i&!խ-v*g3ݦ,)F}𭎣(A5N^l˲Limil;wy^ $}b;&X6eEm,Qaug/?x GI'g5elY#?U5N鹶7ԗ~@ `_o̘lzvBdK_ pH/PW| ~$B H{uT3~&"ߺ~e:$hq ֡csHuΗsI7 T5c _?݁=|5>;$>s&#?;;24GTu_ Yټ' cI=:0< J  Iy_ |U;,ʔkjIˋ6X`6js*[d(H 0x W{ծz37%u\Q عQޤ7QQdico1x']? }?D Ad4eRf o ׀F#l%*+=zZ!MB(۟AW^opLyԹhءTYڐZ8^.Iyp)P7c+֛&9D*GTGYfa}i}]ޡccܾxґ>>OܵuP 4&s@6V(n!X D#]R% r9)iϵきۥEP u?׮PHr]k.x\Q5`; @eI765z_So=,sdO c|1mޱ7_9e"PX:1+amNbl=VD(Ř"y_XV-7F]!׫nf^pUj 6+C'1)jlQw^#V'Yg"Hit YJ?DEr.gVe@$"0k2ΡwV*@hf8,  %KܠBWky--uBVVi#rލLcAI8ZL)ggO_.އL0Di#N?W&֧iM"%OF"Ξ˦qE!B+n9dU SƅJ0Jp#Mnlxzϕʄ ǬŌ{ ̢; *X ',Ȯb*w@EӤ@^n}DM UB:zGs`1LPF|zuF9Y"fn5x)JAxH&9,l5¢o\5>j\_z2faEN%7~[Huk(LCwire'S2B׫4p缾ӗ4_'X0?aTrn[4h/qP/04Kx^ 0?R1ƺ5/L03#Һ"0F#Q13Y]IWQ/?O~kk!p !~ a֛,Co3zvoڴq{yupxA䠀!^8.L/\ 2]0:qMB6jBjC@K}U% <L\8u޶h ,Ut0/O!Ky1Sq{sVʞc4HIWOⲥՁMhilZZ_7SVJ7qKzdS[\RyIkE~lxKF*1CMY0d nw2tFqe ]W#tpKHm67F_nӚE'~E| c}9ƣV}n{E~kHnVt?̚XA$U C@P/ˑZ2pi_xԃ_?wY9q/G9.ر-$1/Gm =Æo|=pla}(h+cH@L^CYl xL.qVB'!rfo~G 8PSe #"=Kt2ǻ: r W!r(yb:\ .&H.~I),V3"v:x?PPnKuܨX )J]A~IH$W$0̼.i_a|[Y oc-,^.EUݠTu R\aEjx[`l*`ggZP ECjؠ}T5A8<DݫCa 瞤g$p#(i/e&PRij(e &B> HDP{{A"g4X[3 2 ]ܼ>X@hap.] J>`,d𼭚z!{ycP8Ed6W*qf\-&9T1fGM*֗Uh#8&^mpM!(l|vMKeIJnTI9!rڜJ0;l߲v#]ur+`(hR*n5afESޫSa3'GRÂd& UHgzcFHy?G2h͕zr↣]G*bi#.m:*#]Tqh\7qn4R+qn` k>,Ⴞۦp tH_Jŗx2>AnK tT~ީ.ⶅQIԮxI{&]rSt]XLԬ$ڙ<}%8Iѻ,V]14!#Ld2|Qbų~fB}& u~H3txVVf-2 0T:!@&9M+^SXZoH4E"x qgr m{{Ck(3OzMGRyÇHLUpQ=FdN@DjY{ $^1U6zː=}p2ڜ1<+ap^UIȵCW8*aAJz#raq$b{H@8ʨ^?'7 -"rJ -tl+Ei½\[t~Vyq~Zm4ʮǚVc%3{N܀h }$&(䗶bʮՁڴMd[VuC7ZBifPDlo&)"˞ٱrs6Bn.E" z ];L AærCر 0\P`C!R^M K2pvq&Rk{`8ֱdv ;qbO!% ~{=}$6Nt4fi6|J՘97m(T.|SdT̬Ӣ2CG &]o`[OD/XyV  L (k} ӗnzDyaQSk)y_>ws 9m,\ Kk鋐`a}H-*f/z}6Tٸ2G^ܙZQ"^Lo9ȟna w!l/D:T ͮe6/9&Qt%YFXur(Lsø-lW=)QBk%t ,7?,y_Jh?elD5pKpŏPPd.u)\49!m9^ {O5+\|7TS(:@:qP[HLY1Hi;d"\o 6 ASk Tz-FGXҋplWM?{N(wR7Tpd9CDdKҳdzRIqƬpؖм{\d#7#kJ %bu֭j3W骡2m2 0̕_k6ide̶wx0¬cV4KgFj OrI+yWE"jMMkge~6}H%l\4 pfDL(b2])I]X9m|hF//i㼙qM?9bǖ-O8e$ҕ= g=¿%% җ|U6E!FjD. c(m(çN;2e5#_%&jq DôFb XNzⱿxHǪEk{Ƣ:!D`tY?:[t(]zlMn-]%; 98^Y{x|w r7db+rwzV(Qa+[9v< (qs# "_J@ȋC_̥ 5,A(mGFU2/OITJ '4?6d{lƤqe$f:3'&$IߒZO3{}7u]ǀXp6|} !1'*|KF55$jDL{PHQM"y?x y34V?Zu=%/S-_ߍ `_o̘α0I/!'2ērZl'V89gCd|@D*CI{4_-*_;± N!_+L"AwsaVNz"Dut}KiG4_Gr|e6~2^F})D&ڥG`S0U@G"2%>TpQ 5wLwL5n>L5M?LB8l9Qo#LO̫u`aaphCقaR(+[dѬcE'({G}Sjst~9_ڍ%ۦo3ɰ]ԅUc0s}wOy5yݵ&w8 Ҝ>AJQ8xnwO?G7:CYHDۘ>$CNڛwDhs NRH:-4tJevxfܡ( '~~C$&}F?W]s\Qo/ķ s);Ak xN|2&oU s~/1Yo{䘨10=yB*X?F7.* 1at>?fɕc,:NʇC̪YT@A~WxGh^C,jK\1gy$n,4gq:?wR*` 9S2r'X<;Sُ÷F&E܃{UF1$¦ĝ2 tpU  ʼnɽUen]'&sL]Mm&v32!Fs<6LI&WN:%fGoutH̎Pf=M5aT@Ξ+9n$ 'jXg|g^ m瘍'+p rՅ~D42wx{_ba{$%VDUQEnEYPɢ1I63r;: !.hlo,xkQ')~v+ N(I\ʸFd! d1&ԒW;f>IP!|F?R8"!eLR2RHj4W |ɳu+U]h@MbN ҍ~YBc.ϪXR>Ϳ,Cڎ iq 8 ]z37}Lrx!vӓMQ8b0V[vnkalgr63GgV۵?cP]*]4P`C5YK5gJEZ#O Vlh IjtG" |C8H9i#mr3ÿW"iT+*ud[pɽ6ϲ2C <nVxqq ZwCj&Z4W'K" \{riwpM]W/ O8:8 v0}09qɗ:W~?3Hzt3S[A"gO·RXIt rJ]غ%/zYjOuuɌ`;EKoחf`y|$Ek2Fk[c ԙX݇^/ "ZRKx`&vd΃V<68c{Zp(¹gcT+cff6aa$Dt4씃T0'`RFOΧkKIL|~wGmQ?폞ڸݟ<,5Ԩ0%1^%fJ(pǔi fa ٦޸/eшjmܡӬ y_rG}仈_] A![1mN$Q-8ҖTn=kE|"mc9>yA֔a_BOQHI "UMW'fuS*p,ۿUJ?H{m(kI%=5 p%%_ּc6}3bƢck6q.J]Fρ,-:Y4a7  vDcf%D{@S լ^sѽDŽ<,>\q,BKY7͜AtAk iZSEnUuͅE,剻fO3tPT2K?4hm.tFv+{#9g @NvyFːB. ʞH1W=ż0ٍ S,: '" <2Rp2mJIOxX,Z% /d|lcsZtĩK 't\YwANFtiA!J6w#U,KbM @X&{\㿭Q+NթmW ղw\<:?A_z!ADS~9Ni1h%.T]ZsV^{~~N(ngQbrLDA$ TDމQءH͸I9&>LArS}9,Z,{X )Jj!E{(Qv*׼KvǭMLz~Jd+K#(8RWS9*)nd(Qqv"m8? 5y.VJ5Xଘy`VKKA@LI`6@H`+ʸox8=8N$%zoBpƭSz~;M=G4??{]0*68-l2EKFbd!VH5X5QXf8P4iR ⓗ+v;Ş=r;Y^G]%E:B3)9;MM tXp!:iX6L/}m$f!R q:VN>4Pa+*g Qwal/3)J8T0?i/ ǿkȫt9}IPO}uH1IrA~Z*pc #@2F,hTSJIePGNn5|:?P.B_1 ~P2Ƽs/;49Cj=?ŅD|Ҫ"}6r%`s`Wfw3DMQ_L~Æxy_ţ ;IB}z;2DX:86{fhcYy}nҒuIIx%1N'O \= }arՆ1Xޡ /H, g'9a!F R\hz?+'6dB`pU2vf jh#Q'=q56\eaZšC*Qo~} ݩ[id'z߷ε=^> v6IP0˄[r3F3އ +PFF^Űk\|/$qa5䤎8yEdTTs4ҽB+_]OH_c}:HbCvgh=*mB 2P0Thh+.8 oeJ?8)N#E1eW:ZyuWz7o;Ӓ"w VicrzI'nqg+2EIY3*$ޢdκ-Y, UQi(%qP?YG'\f|.\,vzp.QѧL|z$\o:"ڠkmyhl ^S=r,!9p-IHWBʛq7 sFήW[őҷ+մ&9Bûpwg~IUf0Ƥ =C< Ѱ ( տ+/:LT.ў5䱉MCE~r*۞YIrylZ #G}Q{t QP 6l[jDNK ZݷT2Ng3-0_xLw&Larf<쒰訑Lhu5&XEorI9{7㙊 f*uN P^{2EO 7A  7c LߊgzmFk5ª&w!MݼMZg`5!T8u鴊rH;BK+P^XQ&i =Hg\,*ZQWJ.CPrn7嵧o+>59kiٮQy}ѹ! ^62м8% CS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4POUq:<8P O7wS|+@9^<_"Ns,3Fm';dHo>fɅ2@՘(Eq|$@|w/!PXt?:K=Y왠`TB Z}Ib˹kߕ r 2Z|V͡2m> 7:@jv/ O -6BV=K{ų:B)e͟g)s)!"VC"<äBZR(HF3&?qz+I\oŝ].,ߞ#$ UZQKH]-$P*9=#'Ӣ,o;QH"=VAĎ BlΨ>uW1"$/BTf;[ݐze`HS憎 کHϨ.[^ҫ!31{DgeӸn2hCЭ`|/g-3h2,'^`ERkF=Tr`e4kcB-dԢ\um#BIkGA ? i^bY HP@kV[^l?Z6 b$%'ttfV%x Oׁvm^-4CyoeFf-Z1.(,{WS%ھpC,؀w2(3ZYpH=2r XF,a 2=0?R~#D+Yuc)Ӟ/TԽOɉ;VbKq7L!]" =_bcq"!gId>QUO*/+WS4O=D;rCN-@NRi: &Z̲_*3^Urɽ2+]C#fu|X;cҵzއ#1*lLZ[QkKfbGf!$o;TT?JU)~*1`xO;bpN[ӴuwUH]((:P.dU-b( >NzsPe r8)2>4nd8Ypeջ꣫"Z9y+d\q;ۺܯ}!M%Z&υgG g)ӗ z{в[,>vCvƺɀ) L J'O"I j~:(ͩo~ZtdTzu~c"hAαgpr/~4}DmfK5٘ݺRIf0,pԺc侷o"׳EHT6|=ιMw;BLׇ@5&~Wmo.ӳ|oܞj4/=Dt;q+)m? @ HSU:RI>n&]}\1SV2pzU@R,m{)UTjR8LH6B\ɟ@_Pdy`lR1*8e~O~ldF 2V.!v~rKd"h%z6۝ui!U ﱲX\&qL a,oGXCWQJS t'vGdWhX܊h`wsq`C0IdƜt?(d-}Dz|?iIhjjwguyQ=! mq?fc _(cf"'d+yS//D4 l ƈtUq䦬dOtkI.#@$w ^OLRüVn @zrz1S xU4v9<ҟLuB. /퐸ױm'"KtHX%so 1u!Busq3ulJ1>Ф /t4iSO(H'Uʠ/.‡v٠9%rQRizxɞV6(FqΙ$B{Bq "0HMR ] 7y[(tΞ*:)o H*Yc.6KCϣDMxVCɅːl;;ʍ}9 w?jQu^M *2$Ps1U)7568sa t \Cݢ!h[w8v?jM`)Jf$(ftd!cH=B W=x5(%O75m$FI澩.0'8L>S?WK8x`ݏA2^zcqIb7?q^|;/Z7 1uh&^U9)YyM*z5u*D9ڃw7e~bGtAtᓱbDb={®ZMaI0$~فi' ʴr$$E`-+FcȑG@CŸC\Hsϻ2[$to+ow?P|Q "12_&X} Չ''CߝZS*L#Bӕ΅,A1s2@U&!пv=.H^F- j# eA`UѨ$)1H'QrtJ$n"h-Qa$uy`^ O x~xgl@UŬIga6Xr_ʓۗI,T6| kDM0TK<  ۔:k1$,λ"D%ϨIz4fPYc,uNmѷo)ٹx,ɼGSUΕfo DZli5DJ-ާ\.l q@gvІT\b? (Q 3ҳsbRnpNӘ]E3!6:BVlZsJ"&̀-U@IQDy3k q`3is^?thL2x)cQEsfN~f$)lC+ov g .{ v V |f*13:]˵pVçl SQI]XV_Ownm=NC ][Zm>#|C/ f$/{&ѵ|nUY8+2K~DI F8nt.t 6\j$b~Իwg' :ǭ,08b@>>''r"SF1*$Noзiv9f:qAШHI:!IP{4[Z݈Ig]r6㾯Rʉg t*k`oO8V_`hke6) 7l>nx1Y)b.&$w[zdaRS _]+}[zk>OYQ! Gha(EK IWG'>we 6)g*Ss"-Z bEjqEE5655.u%٫/BX.U亹: M`;]|FY{OyK(}s9ǣEVxəۚ.Rx6m|'{ H*%ϞUG"ϖRs RD$wQLcp v;ΰ WWَo&I?݁Q{W*_E1j~Hp)#EٞHE+o9W( = 6.i DdK泯C?!OB}oĖ]"X_qt$?O/` ㊹ܧqRNg(^.b՛&1-I l7|՘M1B. [AS?vyVQ]遜D%p!_|Xdn85 E8¨l =`ʱkFr8ia>zdںsOѼk|3K!XC@tJR7/!n1`z a^/2v}=+ofd 7ӻt{m#1J40wS%}A_'Mq]Cd&Er(«:Pmņ28&@"!)c0:%D+0,҉=(FڨUPufp|ʏ˘ت Ǿ5OyI78/V -(+d.$Co(o>'OXMf]P0c{rz#îbo^m黝[=~g ;f k/uڀ`Br!Q[)".W$EA s%D+k^O֝\? ̑Bl5~gAA^X`EhuN,MMQhu%tMW/P?y߫ `o!ze~3 GoSe'23D/l_Yol` mQʡ[:%*S;Kϧ@>Xo%Ĵ5dZ@VaFqL^h䍴TNPdke$R5sso!!b,QahOUnr|@|#>=Y󊱏?g^@|k0<;%vX܁ocGE%_'5@xf7 }k^Nl\]4h%.+Wldyٕ#CvU$E S9EܪXpdSs<P|j0U M>?\ZPPUȠ F  Lva. k)t-*FЏ䧪2>rr7Cga) &}SG} on'No,*-{7sclEȊ ]Y8;jH!9hzIek9$&A&gc:'69 Iclsލ퐬nGSңSl)s7f_q$UV|*OΗ>{78og 6GU>5[0XyAaaY0.xAjp*5W R|ʚKL ) #IJ_&ѓ誢w_뮲%].,DF̫t$6q4騀QD^UgB Ň$5_$~z 0;"/c9uF^GBϰbehi5mMmL=K0rO ;@w_MQL`egEq٭t](O3^3oA?i4<ճlc>e[d R. M~~Hl;FLtKsnPˬU!#\~{X!]5c)Iۮ5Ω}\&Bcbڤǚ@{?h;Ig,MĴ=lp bjCsM< V/j(<-XR㦸ͨJP J*x{|#FT jʂR?W 4ڿ,| N*s ]V1aqXB&fZ]IjyBṅ*]#4bGZ(eu2a^1u:7>jӤ>Uw#%+{j𸕫?_MLbP=YW鋷 /wf9iYc `72$=;.uB63}s*;1Ov!s_ߴCڶti.MEnK-ML.U:p)$ $̄ lG]:ٰeg#yV'`ExaYߺi t8Ffz5[@P,2-q[AaxSOZ/162"P"75K?MW3odv& +x`S4qTKG;8eȡ? #2BjGĀI` w6:eLƙ tG;b)ź ߾{ގ; sn1&H𻆸@!,{WM簋v42>ܛSl=F|CR䵂VE/i'աs1^ *:,>_Dй {Ϳ_)1ݨ}UL ?VW_,JH>mKUxyI[P!Vffxb: fiVɺO]귖/}M_J=99Cby%RoĽ۔eBUM<<1e``:o{a"_0 >j8Eu}@{RV|Ge{>dfM'Iv_T,/0>mNց0ٙNݬNPiv!/hFZw \ НU^O1սO=rmg"PM8bsT+^paph֋Љjvfy'43 "rp' ' O[LW創¤]uM`~4A7]c&'jZb3$Y#Ώ@wP{t#8bo b:.@nHw Zr EZ֪oҲ :0M`ʐGܭHo{]va:f P]6_Tf̷V:lEz R-0egVg$`.q4U-4j, KSzNO]_ru#*6%pm"64əj9IRXg´ Ci*.I! Uv%";i1?o37@Q#j_)"9tJHUelxBaége2T y4ބ906?43蛔^>BJu痴>yՏp8+݊`{v;($8zb-eA 4< 9N3t304d ˀ}D!_!z*T4%,7g't70ei}I"pxޟ$om-!:(y;CH%^ +Ct#=ҢJ![x[iq)Һyco%5: UfaX(x4_5m7M#&6Ͳ]z!hDe͔KƇP L|Ec$r-8KoF 7#d=8^]I+euzNRi٦ 94ERr^B ȺEfBO~nTJ0)"R4;-‹BY[GeÖjoYҐLUxVQfU,_Sc}3FPPa^dQ,XSAykď bIikϹ:KϕBAN%_RHclF\6q6rza OVMߗW!^9E0]$,PKLm'*p[m"XwXjK픳N&U(L-/0H,ڏO BrݢoojE햺Iάp!7)] 2,)i' x 4X%S!Q+qbFNttZ BoJH72.+%tI`mY)}Ti1gݓ{A|^Fإؤr"=*M7jXlEVu71NZ,FCQN[!-XPE!(|8xPp,o,w?M >@@|j'k?P&^@џA (э"7ӌS3FaS"ZXE/|v@Yn; |{Lr<A>_2a^QV_vӂ$Cc>$Zծ=lCzϽj( Uc.sb[yyd #h5s4/^G*:4T7Im{*貄@2EjޣaS!t4ʹgb?H\ Ǚ|d])6C!EJu@So{{}mBh~h>8Ѻxz9ыo/vC׮ʚ[v{28 P7;:N*wV}jv sG/1h#F^dF}e7Joc qm<Ǡ' miMΟV%biS٬}\vAvgw|}h9M)y7nS&mJqzaN2N(vv/qGw3ԜNVgci ,8tN0,I I?+%T+[3+p]淎dysS0iw=--& 8qZԎ4\#AE~{=H9Ĺ]/:M_j=Q͘xtڣL`BIZ?D7nsIČK9)*ON/x]t*sH跅2Bf(*fQjaEc8݅U8%"C_Kb%hz S w1 k%urM;kUB텴>[85.LআEXfW]tbav ~U!E"@6k0JށSEy|puѭhz;#`Xij)9RlW0b~dC[^}WS(>T`C\+(-9-I gD!Odc骩Lo^z٤hgudj7GI(aˣitP' cK1 oRA'P^7C8s77$N}U D>Z[$ ٔ1{Q:f ]C6zlLn^|f:ą̠Zec_3È`2J;Həʺ*d &:Z^Eyi9X~Fٕf',lwHaKh~& (IbgbLE۾-,.^,~ ="UEP( };kIo'DifC%isyB6tb[bF{I+"R~0VYa[MY[FhhɎY7l0uTj!XX$uW~RB#.hozq*ԟhKMT34GJqU05SڢNy\@S}9a+@!L$]7'MA iľFi!g-F7^Qb@n˝F6:5k,xgnB#x7U } D ϷY~mb f6;p힝fJi>.?] h?U` VO6^aY2;WQ1;"sgҳg Jm&Ɨ3' !9$j! Y%爾VTc9c[{䵦 6Q 1锬,֪~W 6bŠG0=/ЕYH=mhay#z29l i[܀du|vՖ7%BFyb[˒/ (/vaw@aGl$V|aY^4bF<-[S 1˰,!WJ,~CYO@;-k2&%Tw*mD^!zf2VUkP}9?PX)_~kd9DטE ~fR?b,}8Ï"uP vaW0?{wsLa[kh fٛ3nzCXMG#z>&k^2iT` ry Xl/GʋCzx31طv%4<t< t?ʚRx\8QM97~/8omԪx0@ɇ'ZU4ZcwKE84;tg-b2*H6CLˬzƍ 6woP˂^moHzGfćNVGM)EeBBH *B!~vRVhC~psy|xۍ1.DqafeBYGKx4z79ɜ%płңxHXPZ<&y ]wH<cM{KuK9"F|e|uv (:E0#$7*%3n? PXّM~8R4kM w?7y7܊NF*|68d #\+vǧ*b;=7' WlpY[6S #tf ~)u~X,G0N'18(1DrOzPRJK?r3R8#9Idn=]ޢcV>hl6BۍT?rɍnW^6Sw+# SɋHQIʱ2EB&muv}HԢ9` =NJyД_~JL'w2@'^08pAJ.p-\> 9,X D͂;Jy"O2`?<=G%u)AvY]?㱝f(RetD@`C|Wy>op{WFh2#Tхrf1&Pژ)ɯNrݯc{ylJƷY*T{NSͤ8[ؠp|!GCr TxG~Q1[|0M4.ha՞|8棐d߫BHSXP laUIcubkg?X5@bȯ&׎+} ?`BG앎^rb;儰p"aeIGNjfl'a$#+A g` _# bK/708xQHdrV7v_[*.CRH(ߞtSjv4q\ZŰ8Կ l- -xV>q7Y=؅ _LeF̲L+TlR17[&ʰFboY 5Öd'QQAP|dXJYes8Nun,sO!|dԂb<*0Wڋ]%Lv A _{r{$mGyZs,|'/Lu5yd65 G ;̟G?z:WWoCzsxmgsQZxh\PU?#qkl}ӫ'εqCU%LN~3"|-aC˄pzDMU/4gGBT޸ ?`eץnU9&]ƗTyL($KJb$0>mA]&Mt`áEH=T'H,C`"!,_ӺHשm{|2ޕ3|(6S};X~~?E@]B |)S;]5Ϝ{A|e89hC)z3TZC95 [wAhc+n'#H'ccd103 w҂۞N<<@7'5=Q ޏ`?jptM)B%~:W\>`/O})Yݤx(nӵhu<5_$#)P\enp 19B3c+؋$律z(['8k1S 4qӽ`=7,y>ӓQ5J9 х_Lney4K:ډR>H d8Eq ɸJjYai]sZoCiP$n-/@{taAE? ®-/vWbꃋSO`^Һm6h Ày 6dVCNc+VPsn{( Ya;V /`&KUM!Vo9bp65+w3 F,؎~QC"1"$K/nMS;*PPYU줄cOogޭ}HF4FznKVݡ4G1l[EaWܴr.Gs-}hd*:$q OU=@CՉ;=ZD|K89%])=*ff,LOi0ݛ+v$+L=%͇i,)]:A1tM'9:ܝ/i7dܢnʣțc§v;3Zyro"*hEu0;KsA0Pc[68I!7.^|/t$BEDesاsRA+FiWE;_i&ifǻZ:A#d2~RI;E7 wTT7/FrHY Clj1TBbW-UOyD/s ><ӝ6rd'R;% duzU\/AkĥwKm [Ekdx,v[]:Lm#8 8OeCUuDܿsR=xv984lAm)5l?4(֓Gi(KF,d/QڻrخB E5# #؋۶D҉r@^|8 Bz@=$F ,&Qt4q !K%ԎF$~Mn EfzA6/BXOjElfR#Wt9;cmcv%3R3BmB^'fi=:\\ "[pb{Qۯo2dtR@P3 1ЫsaKZ ˩, Zy{=BLJ0|],a "ڲ YH'9PM3$>Er*a`DՇ3*qAqgC@A#pD`~|gXF[g>0tA0 J/f z_:<.}QHӖ-S3wQn|7=,퇷&KKJP#d/ [R0NY~!I`nT6y j0If^؞5:u|Y&\Y.UO 1l5{Oڴ4 -"K{'3pfx#cD VbFek)| SzDz6+`b8z`־lwkC=rR jZNN:"gIc6gY^2R_\x܌ւt<0Q9d+ ! UP0fy~Sfe g[^a# # %[Vt<a`MN{< "̵L}p;\LqD`..voPG&4caXM T66Vv!2貭Oo!Ap]LH-kWU0NzHA e~T'&sXö\nhW_̯W2cKgSRB18T*J}Dx⮙-I/!,%.s˹z 17&.Ly@1q].d@Muvx=)XsWzRˈPGQ)FoJϷ S|%֋&P\KW/3cfΔS\r=+Dx5մ/#Ł^'* ߕEuwm*=;LC/gKM/p[jWHC w :=&[!}Yvhd,U,Q"̥tN{} mYԹņQ8|Hx#]AA#!nҒHO6) a6[<)8zF6ih[ʝ5kzF0EZg"58#h>x)]z!@Ô q|3' V/ ! Ԯ*\m Kb#M>WLRpUПN uCh,>o,{r`PVƄ?'PEcޤD h+'IYa S0Vx0_].Q-zRHHC^2#K3:8{'3Bq-1ȸxuOt!Œiz|~s{Ί3 ԯ1Y}3ЫHz|6BS=qLL3۪wys F[]k#5 v/VwzEE?d?a)x?xCXL0U k#hJ &tUr.M6a)Q3^XOC K`'|ߨ$\rl !. }F^$͟h1G  9u=4']pPD$@cnON]}=y)eo&>lQMϦ?Zt~dG)^9. c#̢I /ƶeuvBMiԜB ٭mK++Z.:po2p5k0]h8#R'/v|T8{}!d|u}!J≑Y DיO6-Jc"BK͋aZIxwSoB+O)ets'j*Ʒ:(JE$1F07_5TNdZH eŚkI#:J 7bMAX$,@ ZX8C8~v3e>'x00ڼѠ4?4RV*E/@;-le 9 2hcO.Eigx~ zIҮzoK- ?LT4H#߮x0VwA$NXVar$><;]R7J]Aɚ OcAi>쒹)Ġs K3ZB>y9%:5bRp]e7#dq}z'bU j}u\*,ӄV՟*S6E>U8df6r ;߯qb'PT NLƸ%FeBIFyj" BO$ebSLl ӪTvUC%\x?& ɟճ|YU(j}r!ɖU,Y!ʄ17ƐLۭAAߟ3^X(H9 ehQ5 2ڂ63_loU2[c@)ܐ% 4 TUM Q}O-â`=|)otTL75a KDfsdf#r\ ;Tj ew6  vh!`4vKRWE,٧>G0 *(iΈ5BPtn^Lh36Z>}6@&L+9?2ڱ c^I}缥D-&4Wm_ymhC0h J^@x#{Ԡ viW~@i\|[ps ;PB=3-̳#g_Y[xG5ˣ`$rw]Z@ <71 = hPIfNFiAFR!t׆'[Y6eمeᎃ;Rm޵8d0aegRs/V:eکV6x->;cY-bO_9,91i@` w#V`\2`sl `֢ו/Vq;9?)U0߻UrOw=է |`jJ,QaiOL|@||b\)x'{ wB qn@@]S2hKHjp-h=6p(_vp`Ԃ=O=y:}Cq&7\>?*|9E'H}3N>5DzaSJKVgZ^kd˰h?4 68384o-aڙZ|lPc08ޛFrѻp-}Po/ʼ]RXJO44pѩ4잒bDZk7Մ\}F qHgdeong" ?8\JK?8Pj0$jV|/0b|9ß:(zmTiUVSؿte6cy1$uW:fpbp!`#%@ TN N~wCZ Io2Kw C.s5Y-Kޛ8"KR5("ێ+h64PF/BCGtQԳOaj1"P9q؜E錼կ 86?}3ojâ~O:waLAوcX ΃$mai6݇%ӥf\G𘻮Ϛ^ڒA=Esw?oC#24`XtnȌɠRgcXThEb4LMoX9I6F^ |_*w*wt"f*@~}_Z?t5MKYĸih&j՚JV`[$ie5xٰiQ Y Au'TJWem#^KYN+)Gֺܹz;yRk-Ğ ~A~+Ո#:=l¡$?vћ̿a+(5O`C< aWR,I`}T@vnZ H#2YZ,ǹTF%UɨRjNF;L;x\!yΤ_Y8|(M7 wZ]b}fb"^?ncYFR5wO H\ }ڹ96` {NϙQNȫAd k5(:: Nͪ R>y9"£j%Pmt ʮE}п\zj.ã{5Tl*Ce OTf4_ENH 3>|:쾺YU 7n9º4OA3uxRn W=THYk8u0V|ykp7J!KLsk)U-,n9?4| uH홿R=sKּPٶN:b^,}XŢG'Uܪj;5Jm3r/ø!%h?[~ _y?U~P 3vڼ6Ն~YO~fv},*E|ub;0@~ SC C~ *i%QXA"lhP8U=#)MY5>ù72ZR<C;YZp'v<-0T_Eèr`+> qscng pxMhfd4 { pl~䟅`5ӃbOdVaI|$G[ʁ(,ISvXZdX^p+4 ÄC`'"꣜F_ .01OuDBgqJAAwWc%#u;xNLlDPg*)gCd0)Sަ޴PTӧU4ͪPJiЫi=+Mnl\.aU9803sxA!vZ"cs5dB`E)(55a9YYb&#mqsSџSJgMr0Oiֿ5 d'K sQji}gleg#"-N{Llt ^,%# u9ZN0FPyf2%JegƁ`YqEn|~%l N95v.փU}-61}@q&AW_ꢹV0/ חH91t˄ݔ [fP/`!/{Fe̅\=B _֕d#voΒ#- j1ue|+#PQuP=},m̏Gܯt!†." (ZB]w'JK0f0񡂗 }DPJLo-gLoX,UƴaL 4C䄐Y]GF,ʷqP$kf Okn2sn߸?OTr}s$,xy'wOXRH#n`ɞlV&^ft&d{0IMt)cےUX6ۣ^ nlgB |^Nu3LRIe˻u 8x!k:]pK&ENqr+G 6bЮ,vR@csvQYnRLi4>9rdkF>>"@̙li|o,'T=%QĖ+[UԜ@EOa@0T¯(+Hn1垵i~f0AmbFjFDc~ƕ^|: ͒r {te)4UZ 4Cl mYH4ճ&]u]C{ASCy_+ ̉{ȋ#!07MxCCeBFK6 ^wRy`|YKߐX fm`ksxt%WE^US-C6Ӷ~ϰ 38I1朼H̀8zm}3H^s ,c蟈XZVMW-V/'PhvQZA}Cu/7B)ȋ| Ȃ]0PeOET%ʗ1r:=*hL$9eEٹo\F$=ݾ7Kn3 )XhNZe" ??v7Y+\]j*n Tfџ(pyd^+M 'acH__iGg8+4ɴ|SUs]c.ʊX\#O;UDG9o՜N'-؇ݏ?l"[('nG7 >-")v> aƚ쮖Mq@[wvlS6qV>݂mhpuC0e]7z=1Ix(8+R/duF@flx"xCښfܬߒU+5фEh"s=g7ET voQ2.u,rF6yLGR:bJ?W'ƃOܜd EZ(WrA[I\ Uխ\0=v,q{6N-ݠ deunZNWIxU#XD}OĽ\'#}!Jg4T;!̼5QPAYk>!o||@|cx?n# /{=ۿV{+PH@Wi47_c21 Bc6P\&؄8L9 Oz2wyLwGyϡSxrYZȏ|6pŚnj,wE3'`6#X ;h#{}M`ˋ'Ӂ/ cEmو\^Gz'(c!< 0T儘]dьw2LFđK@;pYPt.B%$򥳝FYn8}ug)? pkN?"}M ߚN}sbJbk;A^``F%jq!Z\+~m}W ꐀ aE:Tb$bRо& ^+U:dqWӭ;~/^%pfۄ3W:1= lI `ˀZ(G s<鳄8Y8h3; 8G$z S/1fb;eEƛ_z1?l=sjg B0?.pGP\+pִH}wI _ qMBk蘹fEQ56ku|QgXR3K\zh[=D^8zdm\Lv\f#b4ZM(REaho14*gqV {a446 ct-Zfcͯrʊ^ږJѶcبV}<-:_l8VČ//˨AUX%<(PK۬@qi2Q!M1kW% QEi ~Z;{`\5VoP -->bll}yGD+ճi-~'rK* a{SK'u;~^3jR~JPi_h[" l}ʟzMMIhi3]!=R䚀+RXQR/ANCSt>GjVcU3Aoigp=-6H! KNFWf? tZ+odN:qrT1ӶK95̥"T;mqmWa@BT NE4!'Bo"РS.U6 ?U"CŶ!4R]+C#$ß#ONQOZaa!}[ݯ|Mtsvv0xIy[pt>[+w)aݛ{/ǝ 7+qȈkl5f2cinwΖoAƕgE}ǻI 3+3O &Lo-F.j>jx%.Z)ys2 H|82OUkꍒ?U~: 1[v&Fh)Zf&!e2&Ǵ:l\s_^_XV?it;s,A;\nl׻UT=ZJq™;!Dm nю ~kIqZJ2{-iCflNf Dhc `2/0;"?nFCZHz#[<(%- X(˹D f@MkG mz<%G.wt8vFJ#;k>T!JBzX5O}{邜6gGG_Y2r3_==obi^AlWh*8|K&'@:JN"L妡jԕ%Fw}b\O KH/!W튊S %tx mYEپAcdjpf~q_ԓ1ؾH3q~q*r//}L)=^NBag4~jS\6 V73:d)v6jl6Rq-:}m Zs}/f#FeIU $iЭXs?r\z2-fgQٴ1p/}@p?b`eAW#`E}<CF&#?`qp8}-[i0:XNMK|+}Hϱ~hWzjpn]RVX#1gz5|{F ᡐ(8 ^ݳljBW |۴X[=Gʈ%QO'BX J6ɇW 4{:)+c? sx|"UrU7֠9GS=cQO/e'[]M N="}܏Smh).JkORg xz%SՎlRzq]I!OohQkK"1js9ޑ\:qK!QtJE۴^Υ'eybg@emc1L<v9M.?|/拇lk}-r9ӕ5[AMgfQ9yH O-75T`*g"s(z'RÐlɸD$&?]fIRֵ 2~X@==4/M4Id&Q)ؗ#fFQ\BBޠ?F &x+ʳ~2{kiÚ2аA)XJOT񮟲.)it_*T?J2uA cܸ*A#y;\# c. D|NaPjn67 g1/kX)Qak a>9n-suW$FQ_VR 绕gގKl-abm;ou1L0(/nZ*Q}?xvɢ9'4|ʎ1#ZGXO<})z[W#:%XHNIͥ ԙ;˖'zv]l"$1τ{la}`r%{+- Ҳ`3ٕ5Kw%ACxDHhZ 97mutAèX q#PW7bUgÐ>}O]W$;צI5eЭthͽesuH)Q%&x*K}r>4o&Qǹ0-юheCAD *lC2\:b{!92T" "' Uc>/j,&yOHyQR A4좚.v$$=Xf`PWt pUD-'A,IMyn~>cY)1>ʊi06i-}hX.va~Th yXeoRλ$ Jt\e?f]h:"G24I^(cU4xMKۍGk^B#e8;+?aEoLs/jW!) U"!8wǷ"0Cdfy` 8|Mi6"b$rA7pTAO?jcC\cl0]u%1|]3dHZ)j$*r!t;`Yg} ׽tq#R"~M URxPGw{*Yӟ]q8!$R|wmǔyOC:chD $ hapl[&v#@>0:N ˚R"kJ:>qb DS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ8&Uqj:4:( Mjk-| 9V6\ [GZa2x^uFCH#W08j;ýd6 2}Z{D|@|w8"h$oh7W^~KG}lW} _ΘI^Tѵi/^:J-Kݻ]Eu;hKS_٬]I7Ӈd+Eoo>t#3.|Ve~Fʎi")9@cult*:7¹H9O p+VFRqp&ƯU |j׈rTLZ |8,[Y$r]./vk{S:*A ه g&%W H{4oUpTu5C +!Yb<ߎ.^t?+Ig?kސFd!i^ Gm&(-Pn$Ef%O$ n#f/%U`ScoʡV>)K߰8>zސ@8jQKO'_ A%Wh<0[WD0$Pf,Ӽ;^Ps}+M%E)<9qE + E|ANL)S w )?Pze? )Bt+ln7hJrAF߬9ey$UoOpgnޮIp"6AR6UexM{)[9jR΀i2 s >T:BEgBCBbsM-e튢-)ig=ي&`%"gKjD5b1 hgS֜Lуh:3TA‡ Wf!mQ}*Y6uynć٬2ӥ3`e@` 7\z`1yx+:@~R!r!쭠@{1&'*di-t74[Wpl,+Tjݺ?] ұUe$4Hů^`g0a?CWKa Kksi._3:*쇁M;w̑ض%>K+NrP!/TuWպ2<'0y|m!2r![>N/}-׻8[N{~KҒUGV&UR8/&pq:V^PMiodQJY/ œg̃+۾nlXOuT(laG|}fY"ёωA9CK[oz.FZA3Y%3+Tp2~M>rOn{S})$&B"S]j+^\er.ۜ0 O,J 8,bJa9(|J U/wCiZZ/BإenwQfpcAHchM?l^6+bX暂+o9}o%o({8Q'k^!$[3Kt)~ʃŘFzyN+=z@ַڙY/ɜ{7<ɱEdK?1(Pb,,:UtsmE(ո7!תr|Ft3%_R+FcdkAT K,/Y-Y@Ob`S[6ޢC' $pˍ9[М3|$-5BXFiq)iAk5fhyiNݫaW茟^9 A6p~h﹕9e!UBhƥq?򡾒FxzغIo#$l.4Cmg&awI$K!gwo>^ʡf+f(wug;<$[)BހR~,lUqf~EߙUL\ rf8΁,оugFTXG[塞aqݼ mr+&Eu.Cj+R*7 ӧZptǯd>w4Aݫ(t@4qX&KfPm ABٓMm߱#ْa>ZioEUJoP.}! J#Onz*})<.Q:yx/8oȦc%ʤu~a`c4m,4GVϙgXTӵx2ҏ&vsD 02Ǯgt3 ,9^ a%{gG%y'Cw))8=ymy"f$r`viܛŏq2=sy J\<@=%jTWju[К)P V2 RGe"n&uaZzi hjdp2gM2 (o EpNs"&윉MlufP3?MF tg|Umr$ Qm\b"BdLFL?^h=fxxq$yR "Դ &nzUp2f1'}#iR ƒ5j} @G"M.]4JHw"LCOFR,Yy,={@!q%Y4]{(;ZMafhkHqh6=Jz/\V u 8FYJM_VEj B`~ihJKSe_3[fir@SppcjˆlƴPZ5HvLÉKjW|Aju !@OvӜLK;l"hib1޶qdY*Պ{̖[ 3ޗ7u(A0}JZIŁnDɈf>»'96=Y4/aF1vjBj;Ǵk`g;DFw8<C*Uf-p嬓K^YB..Q-7l1|(O<ڐ4F;T(,@) 5$+!eC`ң܏-PA |Rx\\)?'DŽ\wv7`GXϹuٽ'CTaFޭmw /E M߸O@t A":f^SW2}eMLʁFe$~[4b6Dp_j ;I HnXr<'z*5x )nl5Q f1>Qp(f3KXJujQHA^?F@{Pj󳢖* ngO"sedL&kVSW=3*UBox'b+{xct31 sg}S8F%vG4  (ҡCZptA:GTc-l*b<;G`$-onczNbX0Lϵ~lA0Y@*Km̔hgoc̵%"ɠ5%O/ŵ N'>o%Dm덦lItVvZ,&nό2)B vxy _eKԐZwxS#)b+2}z)6K5dwU(lTZ9Oӣs}ykmHix"^Sf#jsT +`; JB6#}aOO;3h;n' Jq+}][.Quu:&Er~(:5BL_=>_}X %ʉ{& 0 ,S0v.pNFOJSeb3M?LY?P: r+Zz}ԧX_|.pr$o0@r+ =M!6\nLF sf[&{}رp=Chn,B'wcd0seG";u)`ڊ d}%ur(YʱamUtx-Ky$gOϭ #z?o8 My0"*}Y al!ѬLa9hB&^c3Wĕ5AnW^"5bAiwgsͤ%Xip4= /[Up>}Gp"aku](LJTsH{Hj#Sz`@5ë4;&sy YEHPW^-_,2L@|@|@|b!~ac>Й;u^|jemATz!F.f/= 9ngdž;0G\ql Q9i^+M@T9㪓,kyvKRѿG$|yW>=50r428~ \G#七I[gqá{LJVw6VAo: x$ZNOb>euD Kqf۟!lGI +b׃qpЏH`7L/}rF(i0pN31-̍1oצZgܲVxدx`^]+2 韎 hOo21H?8%>XPrp=gZɰ$Ӥ9{5C$ 7m)lhBn?,cBYל8܀5\qgxPr[B6uI/-jS (k2k1 z7?I4F`Wq0CW|@;(dGv6B+xa?yhT/xr?_*urko-fsJ&H&*l 8,ɭ(Ɨ!К`#MV2/KmrZ]Md!-@xA>`L5ܐ M0'V.cdL)VHydd)x$5m\J7.I.7L s;EY%=60ǔ4xN-sݜ@_G7uP+7waɠXpoR&=rI> CLlNv[4CXs4/f,^ Qǵx*t [VCtinDl灩8 Q׼;M(xL'DFL HB ecX9} *O0P~u P.yu:U) '+/iYAA 骓7ig[جК֩@k=ݨiAI/f]MGuh{dbKlu QQ9L";Hl4~qq[x :W_!/S.jGZ Γ@m2|I~(eU~/q<2v_:%+{@^7_YK$ĥ KDҗNoP{sc&m~훷2IgAJ7'YpAno5+L*8sl_D2Qr*.NSNCDDBwH[}vnP#u]]4'FK*ϱ-D~:y w oǼ|.fS3E\g.Lޯu-S\Dt\_nyPxnFa_:}f',2ʸlH 5yJ(~m84 *m@.E->G: 6+[F\zο0?77qP7Nװ戹;$0 8e^-n1wI)iܷѐGrohSgxYEg: Ĥ,){V èXA2 ޖ"^[5r6p?tvAjV7; \ue*zy`L3"Ksdf^h0\'4Q2_nɆp!ziI+'FӀjR Ot;} p ~״ a 4O*$[ryK*:ɿ?f~/60M*dFƿN4"Cqz(t*qxX]`),'՗n[A9UrNb5LL ,zVB%2VZ{[xzrW0v^u&wbݝ+}ɁFH1wi^AgH=`</ H1.ZHyv 21~".`mg@R wFx^(Vw/QlYb)p-Iþ&V6$xK"sUBUgZTqkm4DCA[!wT Fb]pL!Buh} ~ `ԗd&x;xWV4DP.H%/3#&zGny OYdۧHuRFgrӡOA2 wcEz]cUQ+ nihp6`ަCi\(1ta&qQ ù4 Y02t兙Ԣfz>!㮚RwsFws{+$+l7WMár3Tg]U[ SRb }|=_:A16 mRT_EӾDmwV +,/\-1Z9fsDaDrN"n?zM" c.p|(7D5ݲmo2RyM42/;KgrX/8[?F$l|| Հ- :wt"IR922f.F^;7tK*ԮHQѰ#Sr/NN); !B712%l TՅ#a\!vbw T"VB d:Z G ( gs'1w'2~0UD֫$ ,]^f8BK}"d yЍBȆ7zsJopUT߫tɬ#kv͒9>RۮD&~ "VwG) נM*9Vf=+|flV65,uKGQ%Z~ e$rPC5#]Y:\2ݨ\dtxZnZ"^(7iq'Vn")%1X5 `C7kkv('fCONwwYe4Po:m?i`#!Oqhmgb?mLUu 0mL:SY^MW"8CtGطkR`-.`!*tQ.^M hfk+?q+@nnYmƪNN F Ũt }ĊYłiBOtNޗyD0ׯHѼT% P+*):7?% &e2Q9靕 i Igknjɢ+Gm҅Tgd:c[Yҏ*pM1 VrM_-||ES\Ke%pC75a(R*`9=Ŝ@Mw(* ~a͙d@SpԈ=4D f^ k*=&ʜ2aY^)DWtZ\#x /v؊E)EF718[MYjA_ԇ,O9݉U뫫`{p/ nfrO( S(^^Kϫ b^C}XN(,$Ol}= 0ic<5ʿΚ ][FM8D,_W [𐄤^q6Oz_s{]bK-jڳ(=J jC" ̶SwCglI08Ѥ?dTvmq"k|O[ A80H$;̿^g!1zqb{\y <z!JM' WY@jӀ.){MΖBRd*jzVה~_jJ8P$̈́Z7_1Q K+dmT|ޭXלU ڟnRɫyߔqJ49ՍVt PRՄ1bʲ]k^bjӍ9 H!wYgʧK)px8l= |W7T7F% KE/i y%;3#T0~t PYt ātמ)ghuJ B+`پ`(n6Ta oXp ꒖mQRs{dbMDP%-e>WQ=:ʭlJx\b\막 屿@tTD>WqDMRwƖBI(z-g̺]߸df8u9co&:vQ "KͶZ]zndJ19F3oDp*~2\$gDoApW%3̾aJ7̥GRT^ҸJMSxzI %P@NbPC^|@|@|bI\bˮ=zlT0nB% @@|j`}"54@hL)1s`֋dXeڜt4o9BzyjӮKxp ezB7fk=CFucC[>=/p1Y0SPz] N!`tnhaX:snLx\R[sOEH[m_^Y.x9Y3b p7WTPg#c;#! bkETVٸs`Ό0 <>oTNKͮfZXX!qy]tV?SOB%Oʹ0YxH0 E}tF3d5r+O"uƧ_ =?s?IfcRhg[*'~\VPXJ2F]\/R]][(F"rLk@Y9!V5_{=Oy/اADiVnK=<&_|>@8 _yjzEW >B7z3{\< <=H"cYӀ-p[j)ÅphnWώq Y&EWs˰}͂SBOd";FeȀL;V]AĦń!0W5\y3U!`$bKΪ~=6 xg^MŽ/%clu-m=<[o.qJ`"*>Vj-c@&8P\,$76L-' ?=WYG hTv,ѻ!>S=ڴ 6 89qisX@;DR .TX6\\Dm, ʓNvC[D }?iizH"kO˝Rhu8L@0#fXKfx*H:7؂0M,|U̞̔|h~&>dh `B\['k6n9}W5iU)`_Ny[,pֽvB2I Z.xtfK͓eqَk 5Fa'6_}x8 5UaZ}[_e?a򸰧K(v(Sǂ;7O =w` !سH*+rOODB1R e 5ئPUG=*Ġ<>hAEAJ_L|+;EL0I@(P+L6-%O@; iMu8Qy|N? ǑږypQ?fWv܉qz՚lhS{mz=UHHRd0ޝ0&p2s`5T9=لXU`#p/oQ4gk" ŵS=Dq5V(cIɐ.HkGQ\v u潲Fl g"{{FJ*v$䐴gfKoʞ OǍC_N<ʮi!Tv.nɍ-A)Sw'> P?d0Var1Jw&⁡har>k)ۃ2HXfaHf- %3ʬMh ;P ^^E,R6 (Ay=#+ukIZȸqQh(sPb .Nѓ(-:+YnmάA\Ј:v׀]ke/wu|1 "({d~p;fK1|16C=x-~yj:AYy{! m$'ɜ.I^x Hx3(ݹb@: 8E%!z,<#ybũdA<|p}YBz'"&mRSџ eX0Rei7<&2(|xq-!Lw*M3f\_i,llc^AapA&:qW-6U1._:5*iGUL ½JW:Wk@͛^^om=Ͻ=>vzؐS;'hUH֓߬՝K ?fydr >Dt۝ :tʨ[tJohS!@6ӯVL& praC7饰E*Eav;3N$-G@%;wxߜ>dm=6߉b=ŹI K$^Π/$tS)$\ũ]I9 >g&ZN2^i!aNAϫVxJ2#κn)fc''P;v Ժ se$--ç;߉!$҆ք+†Eddy RS)N<; \lMNQ zq s/T w*ǭBޒɑ`(#/Cmց ʠ6 {vq&jJ_Utl ^|Wph{TT;Jd=#efDD9™/[u3uAHߛn@QJ)tg4فT]x9KK+NMg?cݚ7}VY.pSZ{p&T>G8?xr7/xsHY?K4c8U_n'z]3Y>NLTbHUQw[XPzjEFgI] ;+2\#aZBe8,VtB鳊fj,W8akS5G ՂVZ:1< Z*w} փ ; ԠA0GS$:֒cgN)̍ )ީ׎re+ ۟O;v|p%zz7r3b<5/f[.v(*FTG3 [}u4ƪ^Qxr UP3a4/qCD/N2')BkLTx?Y6 jQy?RφP]B71PPv<ŝ5eZ׃Hz+JkZK- .[x".oI\X*2F<<<Ȥ<rӃktKfMI0d6'|+Otu7it ^)owsȷB* haxD ROUl]s]1ee~ y7)J%pԅͫ|@j}O뮴o6>Z>Hr`GfnwꙷwR 8;eQ%"HGQTQW\{Â*ts F}i3̀y+S Ǖ? O/7)d)@))tGyS:U1.N땏дvSgSUW5N3BKkD'HZ6ϑp`)uºXXԔ m 0q4lU fyJ b)? oҭo\ o ,}l&Kkـ~)fC:۶}ʶ|46(v_L7}i xğH̞l4\"J=Jϛź:z$I(Y߄k^ᄡ֜\sE'Zٲ'['z?ՒhiƬqsozBApilP8fwvX"Got|GW!xӁϨ}uɠY|9Xmb}Aus *2a\%Ա? 9<3JqùJǒ*V3˼jZkߒ/‡AWZmWGlSKFJكL|OrA)5,LţRuՎNQ6+`Pe(T#67To.-4NCD+`^tVKN;jϪTQYݰGd'4K|wv S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰe^8HC|/2ow8 $no vJ?$D>ZZO?~0<dn4j? pׅAT20CKp3( #t-HnP:xS:&ᄂy~Wi }D?]Sƨ@ os U^s7_8.xOz:",e[YbLX?/!zM*wҐ.E MBRO9*uZWp#Tdrz:\i[0"YKH 7U&ڕ tJap݈ymXPGfsZٰWNjILzP)4֡,'{h ԓ$tx䐖r '!*] slL|?v ptxE)N|^34$'_8t6Ed*HT.d wAEa 2QE;kPX"r0d D L&Ղ8P*=jyJ& 4@P k=81s2+m/E D]{gw Y:)ms.OF9ijψƂuKj6H䛔Yβ~s\rj M9 s͑8GIM҈Kk4Sa~Yr㕗1~?i*@icAA0LJ_|8E{&SjZJKp=~=;17m\P(vՍP@3%g ~FLhwt;{6c}y ȩLqpc""] ]II~g³% +7YC#<bI YZsQ.tOjH,Ton'c[iZz=< CC',#/:=x[vSN~ƌ=_KN{QO~4V`$LޞBs¦?+^hδP$L*)DD/V)N`vdt\|u/.cHBF20>+(号"|k3g 81+_ ʓ+AnF>C$KcpNDhiwY=* K a @1$r۶ӈgYCx]/ awוWB6QmS+'xSkI<]@+fZQBg^W$S7)^鬒 mn Lu7 El9B<-)(G鞐a(&`m;AmrjĿ^[Oʝ_‡A& ˈ)Chg2ؓ< -N偏(t -S)NT_9w ~a8-)͏~_zND4 t.QOАGAI|pBK5L'êdޒ΍p-us^`is(UBa(H%iDld*T Oon4hlw Us՜ IyZ"s! (<7j=XB;o⠋-X1Xٜ@.7#-R7{焘*Um=r SPf-93L0(do"%d9Џz3VBíbF3~"&獟oǟɭTHU8l*L+f>EHy}"Q{$/H!.:2IsѢPF8ZVi H,'FeA*5P`%NbLQw*9O`wFB]"ATӌpl<'G;SjŲ m7 AX%+QOl0o>0jMȝOBTLǦpb;? r/.ⶐ_\[!?\YڇQ8TFнB@࠿\X8,IU*wqZ$N&*-]Ƒ]Ƚ[(~3#Z"eJ);InQs=@)>ыeeDߵWU©3~!Iol!z/&=6E|W 巙>! kM0IQоoOG;UahA&Hq1dm(Fع8=bl.=s-tCkV)軞\ON(nw.Nyy>F <,M)cre>pq^nFW"=.E9d\[[`GWWuN't# &XL w&bZD߹U |@~6 + CZ-͑}Zmu:[Ƒ躰Bg.YQiS-w%pw`>"Qfڍ:}8N~pZ MLR(EjQRWI|@>@0| l'@@|d,^yO+ FKJmYOHaGKy~3.+?Ɯ*Cb^fOvL#A&Qu6 iydR{5,(Q[\Z%8V nLoy@WFw_u vbth֎tp͗kzS[W  tO oynú97qM@fȮ'!rCNnp10XB*ü^Z|{Ԋ8-:|i`1pujZ\x!)5P3JXkO|TXO”(mk?b~J8ޱ>ъA'~vN@OR{hUJl=3 ԵҚ̰"8zPV f= tǜAZP:tH+O#BPPr\@DK[\ ^l<g32`x"Цjfy]MBNN@52xt=PB(ߨT5wբ:ѦO(6UN#WzwXԓBU'T6|K|!&v5Q}u5mqTP9Hr_V Q&7֧B*q ! qbEyV86|x<}Y3FgQ f-A3Kڬ%3я,z  hePU#7A hanUz.x*FGEXWdkD~w|uzmJZ#(sh][LFSa?sحa(o: @hEpOA5b4B JjT:3&z_fH lq#5|G!Sm,s&S=B%qd G?b7$ba{\6)li+Y+8p`9`1y,ҖEp˭Qn:JrkWO }'9m#^ƛC8h~QՂb;n,$a:| *i}?e'`s 0Y۷|ދF`> ln7^^:w+?Ӡ$?U']fK*Քw~+πΌfFpN/[[(C4%fZ3mwܑ>~H !0eyOthY ܮQrY'LnE"̙^+zaWimi`I*?f>M)9kheHbO5~FChmՅO wgFRZoc?x*xM8d~AV:^rs&|G.S:c'ePfDQ^2F}I?&;vㅧSf,ÑʷւlŠ5Mt.:\yѻ&~s婖=fB_K+ 숊f{Oһvztpe@Hv=`ߎh8bQaPh]c=^mVYORmO{PBjMhnk=)js'Bq?›B)DCV5˜`|\ʁ}[eB,1g4]ILPz y#? u%A>H[ WֽSOc)MS5dmҺTI" y( dos%-ejTzF YWyեQ|&/V4j#VEi|Tr{4n:;rLiϜp3yy t9Ņ5$mj\ņ$4fN&9\Spxz4's`\~r?^J0՜"vt8?xً펕m8H!I¿7tKwg*Qq#^#RAtcu.(Xlke8Ri:E"cY_c !;*iJ(x!fz noMh8|@y[ :iq5\fzl2l=<^༞ς̑^5 #lNW`Z&߇2.!Ĉ),DoO\ 4tK>]E9 Sp 6V^^aNÅla܉Gw~3۰yêU:-A0Z*< Y- fz͡H+Lc[>wђ$Xk,Ygnrɼݱ22KK1Phn,k8nct&> *Mh4I~]!'Iu_N^ъ?"֍CthT~LL >:E/\t6F΄N0՛XN8W6a&;pe,p,,nsrLy@uF5 @d]q6~ \ǵ 7sͲM 8?@l֨Ra;Ͻ^$uK:ECT̞[\bPj` S T쇜Ͷ|o7vu5cl L1[p#Gh= ihVȘRlXh3YF5Rю{/e?x|+eb*UZ7 ذ:FdW=:0IT2@8avp&+ȸ[%۾!x 7#O4Q.+EZ-H35т.QK-g9_UnG3n ,)0 ,P?j2`EZ&q%*&k`*ACE:&?Vȱ`n-.bDM7dQF{em_pl>x F͕/W5`QHa7B_nL:^~ 捸NWA@N!q&O1j51s}= @dUXiz#| X*"&OꙡCMu,*{2Q *pɈԇ%p/ty`OmwF՞ϫIQ1 k C S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4PE< D8hG| v>}xugGy?:@>@54wR˝ +s?]8Th-L1hXY|kp t`"4|G֡JHm3'|;4ó|w&@uwuĢ3Iyth.Q kJJjqCA}``Ă'Ɵ>ݹSA87 Ŷ\7 1k*c|/NAe2 Z4wyF(f|_d?Ԧ()<c4\&x)uc ̢a~akߝ}ǚo]TgXqYOiF1:a\F6,R\"ۓۈ?!P*X=1MsNɆa 9`v'Rټz9|B>'"2^y`E(K" ] e Pt>UE*4o7fh>Gh9{BNKt䆦ooElB޸!#tU b%_&88EoQA$HAbF} 1}(wxO(G+O^G>%9vp̚ >-'3'$aw;\vlN ox !I<85]N0抚pd SX!JjCawrsV1ħ F~Utc5L>GmBjDe$kOfSg3 mi~6ͬYeSMSz|YO-kz2 ? S5!,jCP(Q,^$ۦґ6kZ.@ƈK۠+d~lTtFj!6TdI}\5-f<<.tıG㛶{Ѣ&2!> v߼('6| kv%N;QF'V؀YjKJ^.嫄`UsY8[*?o+PS=S Z ]2j1v11)ߢ)fnn j`jx@6&2Po^UʰvpsƸxi'쑬(ƀI%`1ɉs6I;&:W*L42 [E:7?y"LIKsy`/8FFp O.-Z{=)uB|㆜XNgR Aat"^ 1ZJ9:!d,]V:-1O4\lpREs*:`ӑ],^_ZjU4B ٸ=荄7(>b>Ay#Fyy#PZ@7'9NZ~-m7]xŏ? b+. QBp)B6N=~V1Y=nc+ N_F>K/`?,T,͂eiOCQ K'pꯦa\ɧڒMb\.JJO@E7 H&3׻~(N6|U%`4}|d3HAPi d팗>5To+Ǎޡi;bB!פ#Np=2OTFBd.0/|".VmwB6iW瓥BF ouW02HKh\ۺRGk˫X˼¢\iH.xgƅg3ǹ_ie!1g6bTĝ^;ĵ z+[3By+T@;VZ\Eo9z1+6&&M ۣVG-ʑZ\ֲ$i f-4G={PE](mdI/r#f. kpWܺ|o횜ZZ]o#Yk-j_vޘUbFl(181 ?@=Ȳ1;q\npˌtXK^.:$ٻKeiey4m?I$ $E~(PƤӹ5* #hҵ7/ѿS8(7|Nv6!^BjUJxopAjۋ1nh!x'BADڃ~ y:@A^XS,lAR};!p7p%uZ4"[Y7U|xxD(^ ]X )!r&6;wyYWY:B {ד}PPD؅Q /rDo.Que E,,Dͦj14ṭӘ2T\n.ͬf~qF t/-l19(UPxP Fme (a(R>4-?ǫ8'3H~>5O`w qw(T]Qe; v;q2_հ`EɄlF56?ҨFGxr)w{@>gJ|}#/C:= |8}&q k}?4\zmS()4 Ҫ8wF鞎SEDEQ H+5*|3aL?G@ S=ly'7yE,Ox㓗螠Ġ0 tiaKXM^ƑqrSQ("Tܲ4a郹_&Y7WԒ1zFf~\tt&Vk Hl*ػ10hLT#lZ6rLɣJ=['M)S6v5K4%?ӕ.ZF¸>Ð@4$:N[V%fW`Ic"^~v_ÛRi#yqK ɼ&Qf %u3?xn_?V#k֟ FE07X'Cߙ{s'_bvzRt?:: *-{QKeܟ.b#vܯ.>~}% eL1ph׽UE1UXo;|2=k-ӥ-1Z>^àzF%~xJm ը0hkhhO~bȱKǶ\WRL {gtJm2E:9'%?WoCC 4dNX&\Df*eWDC5=dB̝]8{_`\I,mEa!"?H'PL\QHY7Rq}\ۑ[A~puўNJS0W\}Oհd_-sdUi4e5â*{SfAL$ژ! bSމ42`X!timF"Jc6Ln.2ru| TJGh.7KE׉Nm1r*Mn7 1Mc ,VQV 0rzI@x־2z%{"&LWI6#:"n?=\)Q֖צtE_?oXw q>l($+  }sɜ'l}EB"ѼutUàdm>2*k-yGnx3Cf#dcZ-b5bfͻ)1qї1b ۸]o[Soߧ±AsXKLH[<`#jπ+FWMGoA*4{PNB4KqE(Cd.8Ʃ؟لfґCnADt3C!H_IJ4 G.u@ J,XόZZHf{"T5Z"c"=wCfo%^#jd,R6z쉯y/32')XEOYy {j ,5wSZą32TRrAAu#,S2<7yKa7~|l Qң\̦ie~M/v2Ρ;2*I\E.cE(mA<id* @_rd bz c4_MJ?=>1m=%jDMԧ\4 q0P_d&\'a?&Ϝ5kwNwAʥw;Ul(dF2y|3jų"/ )\=fʺMW誗A:g ݉ ujpz[(kd qɩ>4sx4Gy;' I-5Α+4"bF!tLI4F_:D?`Mћud?gʄ`!崬]߁(0,\Y;M$_߇޺h}:"+iͮv nӝhfw}zUĎ(_ .cA)(<[?L]9%ͣroO#*O[#?}>ixe1j:xQR:pbg, Gq #UI,юw= ƃ,DGP[Ӛǡk7C*NoR'UĹDԊ̜|x^eEyHß:pЎ"念4x1|WĿp[9u2LHӧTlgd*g\Ta9HV)Z/3@;qK[ď0 Lo4aq i`bS*3/r/3U cF+.v{`k{GJfMqZk+ָHUr3zgjY4i&k?F¯ֽY]WF~DI5|&b?nNpj=v'd`xZCeod=R*XFî ]c\T3pQ1ɊB§]mږ5$ta@8oN @o9kZEj'cɢ\k7 dN$"e d{ՁUNA1RQ$z~}SMЃBٺ1%~aH'&߈Y1NZ&רH2C*6f>5qonQ2(L(5zMÁ'1YF^v{-8BO]|:Df8}7;/hM>Ǽ"#!j11#"GgU׌nx:LE_,Qh"M|@|@|bܿUνQu ZģS4O|p>4*!rm$#Y*k!ʱᔅ-w>-ETA  2 Ãw:osj ֵ~Y/]{& J=rL%խsg6"T\F|he|>ohꀏes_i>-qUKuAhHlE}]ܳH!=_C5ԗ?W OQI|6ʶY: U)BF8_ l  K +0Vufl'0 e_ 7&(8=;ѼcP:;G!&v0Y54,%X!#@}q y ԵXmiwٻ&U; @i mÜ jʲ+vRĞ)rC15m]MW*$ZqJ^>S-$uKבfY[Czޢ>2Spi{n|^~Fki.VRMRP6ASlT!j'c}=/. fVI(ornI:#l B +v/CLu㛶|qTpLMiZypff߆G~cg_cNJsnœD;'&9WW}fz`zAmqJ/E:[8d*-I 49;'6#xmrnv΅W5{qGU4nL&Uʎ-hX>E9kY=;"q 3JvhIї3\,&ŁzXJP*n/I_kFIpCJl66Nzb=CNT)h <+\q"FfXʠ`'f mFRg]Sԭ͑p|7[BdhX5/uecO7c6:2VFR@$=J꫅;n&IP.KZVאt`UhKTe,8A|OkVrsC0O\>:Y꫋C@da# `}]*tOjX"P>1[0A_2'/R?uz,:[}Bi<`~`uKV<ՌO|ǡy'ersQwsʜ/FA _毋>F}s=ޢ8H]_=b}IM*;qX9U vј\+~-R[:SǜW?}3.5*9Q^դӇ?=BNy4;.DzP4%fCKՐkzQ E<(>)" EmߡN ז˗ft|?A|?X?LJ'O`e N?XXVZp2|„6va[O(Xd+o$ԋȞu>am1x)/G/t_}'TzroEC%,leR'[x{swu@Ktst٢wB C #v)wm͡>4=#Eb1]CՑC.AVUޯ&#h͸~ f ", }2DP gxt'p*]- &,y[0M$N5Z]t_kYNl/ xik`~߽14@PWrd5:ˮƪ V| oCrn9{myu菂` YSXf|geUPVjI.g5ySlS/}bd3%+l0~90b}~vȴquH&}}ςJr%fie5cqw4naʺ١NZ^g2lkktjJF;͖ ttY䡊SRɽ1柙bB;h+X?][۳?C@m5Xy#79~A;QfЀ#7891BaJ@GT`hQ {+^im jk3A]sԞ ^]TF\<*ySf ѩ3f?F9.j^x\8~3(~\ZӗdL̗r: T ޚ- iτq d5Z?xJ*(Q|D#"NcKR2Ѯ^wCT3k7zNW,SIyϽ_%\ 8 ~ ـdCڿy_,?֖]}4o!AyЉd֣^lLX:.|+F&bw !gƪ]blvoLz0pΘ23@ac)?\ȃ|d;bA}P"R 9+,9p ͓8ÿQ^G^sp!ow'hG?JA+nuD ]js8!8TpE6+>2-B 76iĕ&I_r$ȆJ42 Bꯛ~>5U/g`hH`aOfO5[{7[PqE1{\nA0ڍҀ7ɳru q(6 ȗZV昢nZ-/0;L/ f j@jĚ޲s׾֐=e+:׍ݩ]WܳЍԥz]9֮*Yֺemz|34*{ .UGoĽd }ϻ\.ʔ3MQ Eݾ$/nO=.#..Py]X9՝·&una:1@bؓΏlvKkǫ\jNTFP T4,ȫMYA (!,^ƒ41A=1$Se3Lt:q戯;7n@YѴp4\pfl"pO7#/jKi% %=L)Թ?5*L)%oV,r (΄9fWB뢷)!nJvxˏ'5Qj([RDB_]xȠ%|Ç&n 4(P{l?Eê^_+|4T6cv'p9N3Ihٯ}K_%ٟѣS9Rb(%J>b$cXشA;BR;Hų^F%¸5uD:sTTlɚ@~2@I\uޘaj{p8Ǯ{غ(gTb:Q:")=)~-6Xow0Z-O@z|^(qfGmʪ] JrgnYt]rz7?e<׉oDq^(vZcϭH@*Ys / ٺh7sg8?s?7ֆxmG:,.jhUs13|C5ҙ5R8:)ņ^Of(5 ^z-x͝`[>d.l=S=l6^#`nJz/@,urNeZU-[(_KIe,Pe "| pns70͢/[f 8 㢣k,,xR.AmyMfUz_,<8aw MO|oCb],ֿY=Aiu{.`mtJ`0Y!?e2!ׇA"pAMw !\6+mo.<A U{dMÓ4yiFP6㊤POA6*8:XW(Uʽ`oK$3C?@ݧ/?oi+zH&ͰfSsAIHΉ"E Ԯmeuw6X1|L99v>Piy Ldn$|C0pH2%_!E2ёix[}˝IL[&K/cMpV ѻ6#¼\W<^іt匌Jv:vsu5{5mfί?g[uERtR>|Edҩp+مFU*5]gݶ ٔ16L$zU`Rb~"$׊F?q{IDf{o1&C+PJ{ f9@# a?[{Xb1Aݾn磊.k(2+ B?F_(&5xiTd.^b=W~9ysW/gtbV[{s̪oh@ÆhL0 ? H3+bF$tV(S)n };}l 9 ҟ**@WC6*߼;?Iӑ[)mWf % +TN38H\=_;|[`9$vz@NjH3 lC#+W 4=wAR!Q!R7W#Ѥ˗oc|-JHT<`3[:=рS,"ze(wE yoQ%>aZjrIpûvEj}76QVI] u9t䘻Pf ? a648WM:Bx#l1[w%B$w,ny=P/&xYi+K;)eyțhtW6pk s~d$u!{FwCb&h8k=o,2{7cuVC7|>@Kb $9f 8qs\ft#̮iĔ8?W*0 l'?OLR /uإ+"5 -$I?q5n'@&BZPӈFJ3égaK!PrG%dNco~6={-+/!$4g~]l3҃Y\_~٩zd 9vN즳 'S,C#9la;@+Pogʅ!#Eh$f@jUmPxE2&L$8{xbr*G gX|K:1;06UbwESsG#/J$<7x\\wm1^TV=2Eוeavvy:8_M|z՘HQ=TW’#E~dtg/u5w/汳w9J5P#ے!xEVeEh9i<2_;[#KZd 3igYY'w.af^ߧQ5Y.>2 >mp_*S{C`ɷQ.n\5vV2ZG +dDg}GHM`+]*[E0N,Ģyip{kC ShD]HbYqԵ a! /4V~9. 4Lڈ~@:샇@  =w]C޺*߂$3-/7s 87?œ?Ў,UGh;#Ė(d6<%<X~Na(=~)zfwg܌Hqڹ`TK'QO}In=.u0ޥli\ZJx%+SЂ$ c kZĿm~_o&6̊j᷎b-N׺T/OOR.Bh:o|?FE>Pyj:(bѩ%b M61O4  ^ 6<*W) lTVA9iAfGFi">:O5SN/'8GvZޙ'ѴG#PdxrW$HSRU`cpzQ`{1G ܼniB SX~+\;L澾ɾ3R147vS`6r46:z9^nك֑"/f?eTT8<-OS>xaxlr S߃h }P"Xͧƀ$]_khiz&AENd̉,s/@m"kw?T>/P^Zb}?Yd['ìx+:^oVB% SSRh+OBěr@!SAQ dkEn?ƺ>R8S~S[&!æuhb v9\hܧ$)H܋1ϔ HTB9\嗚]xTo#kÛ~AuXzI'x5nET>]>4Գp+)9Qdi@nx)ժBtZc׻bMV ΓM7sH5z:o:asV|/"$TiQu߉sx}[jie%xsK%BA2Wk$|׌!'MCԫWo׽mIh^, VXN dmw[!xYՂl\~ywJK*1C&$kUY\\tGkNS\_x ip*}F?'xƮ'ՉM6qClrn5BNL@jՕX0[S߾QEkvf03_t6A"SiW)~Ήd6;+D)L܃F/qO@. Z^+S^̍er]0Fmu.$$e:?V'10q o" 确Hj%JxK^)MF0#7]l+b sVxrDNcq]x^PFGav+?>$~'3(^ѣ$vBq*äh$o0>ˠv!>x@G I, v7k!|-cu`H2oh[:Ai+TT <fy^:zٓݗ 1ߡ!M(6VΤ2ևH\-`غp;;w.H>4{% E= Ė>D4؈t+…x.ϰpZG7vV3l ggmR3B%alQ3@ZkcX4'8p>"xυֹM^< 3jxrtdL܈ք/46Vp yI:ZxVbiD&(_oVg@ c >? XG/Z )'Fv*B]@B'eiR9`'q 􌮰1h8B.\s7z^vWGR!ƾp0*3Y3šltܗF8-5bS|efzXrC쮔u'QFqKeGUe &\QSs*}R|~~vlPrJ^Щ`|w|p;`PQ.9AȲKSb՞DOۖ/qt^gPd)9Xtݪb\6O.ZLA:n6|vHM/:ʲҼyXU򟃉Yi$} {2j-jztcTāx;b|$ó@> 0vqo>ڿsk{19T#pډ-S =nhnbj{Ig(H]jټ'YvRz!p-|DEՊtkp=gې*SrZ4L/e܋b=m?TE%@`IDRi+j!] fnu@.πX_ ã'\ GZ1񉅝Z-_롈Ǥ~k׸0r;ߩ-wVi?/v {9qFJ )Wx"!Q*kVG;snu@q=n!]:ebAb. sR>ޝ-2"‚DI٦YУd`?&f`hF0 hw; 2Vu*2%۝=kr8t=/sL?x^!6"]T |h,+I,R&d5^2jAq;+˫W6(ƴzwQjywjMH?IQ lXS:ZR`dYb5B1#73C Ló~m_ |-O.Җm HMZ%'Iޝ,O߇A-}a,D gv im F8_)V52#&&wӎ;uƋZT⏘uwL7TXT4Hީ o7ET07yަO0yMt/dRkWzp13IQJaИ~k[z!]76a]h_s>Ky0 ,{ݢ(%,/0i@X Hcȹc=%IFݹA̅k?YDmdSu0:"+}1N;b_Bwh0d0]y=7Z}g@U ֒B@#hjȑ'nvLhtѐC_ ZUhZgjZEÚ nL^i߇:=˩ԫw$}siw-|,/FcAr URqqĻ z{mFY&YA.b]C‡9Y_Q9"^TE>WxXaGNeF$x3)@!ñg~7 I#)0k(~h(sQta'̄R?gAOF+`㫰Ԩ‹!C8\Q-²8%C{äZ;,(q` ddU|8/ )2\QEA R((H[kѺ"JEoA<ٮvnl5x49N#a6.'s G?aIԗOv;is/O wi tZ'tsCru(>i\BqCx:h&[{]?a'dU2qSRwxc{yw/ERP@{rG+d4m7z􏜆Q Lz`5VO԰>2y/J'%dc[{lkt4("i휙i"˪n?!azcDS!2*w%H\^Q桰?ѓaOªEF\H+3noPw½ $j[cAޅ/orJs*`$n"HR7JB8T'g0G\OGi쳖 L]gY b/]吀5lS#YY([xz{tХNfpƴdSr #PNT$]*V=uzK@ 4_Q@ԣ\65)Z]p 1X8U:MUVtPHeR>)dhg̠cb\hcߴgFN5 ?ck25"m#ތRk$[?u4tbgm7z2W| Մ(^:ޓdwufC/v Lrp?2NJ:֨^%^`N[j^uL V8 8b/cZIZ~esm]^7n#/y"{st;1rv>|EWh.$u#gZ/T)^ODKpm`Bu5sXŐ]~h&aoYVnn?9S6 r*+C|DӕBMg&(_bʃl! `=bY\Ј0>_rgt̄17#&@eŪ_VM c5УC<޵rFSE&•Sc d./ߎmoeLEUm^0PalCjeOT: X2+񫻴cV-`6>Z5y\k AaD|r8򞠷lT5@NYqPqA7?/9:YLe<lj ^6NVrnofAT 6[~f2\o'lYyq>AxI<$K6&=6,C6pK x2]%흃V?J7]"ӤjKgrR-iB (U󒲞F^`Qq𖧼@QʐlE&P,K/uJC n:Ų}BӻG/ 7;GDcnBzXZѬjuі:}RoA)@r-omf9wk}ܪ6LQ7-L휫{Gd@T[6»d74NLK3"#]khw@n(3GE̲Cpp G0i⫪%S|]<ε Qݚ[\""¦{͂ڌV7t$(\i߮aE4CG^`7ڍ8`1â!sS%Sd>Y"%)%K:"7z<8=0y \RӹlM>%0!}Ju(,QalH|||cnQ^`G! ѹPw||iDO̦΃-߉A>QdT`4~dKИFiml_aBYYpj\*F(`<&jGF>=) 6%:PrnZQ#ETIJW'!,9 AHk"[5rvw(TaM[$[`}]}a=e^4:"JOԟRkR+uKcLUz#pqðIE$KrYٹKh L D=RIۘ1fi~e:}@n!9 ,_!4DK[ι.:xޜ2􇚐Pбz`F[gL?+o@}\9NMLiBAU.MX*tjKS?l+>/.km_-u%>2EiHy)aK6ify PwT"?MWRiЏv $m(} Xgջ'x*OxJ'?]#>dAA˅KdX1 "; uH'_Fmz%P+Ze9c~G갔P(MSS򾚖\M`S+Vtûw:$W*XB/yVkJhφT,I7\6 ¬1V1q39p;W5˕ҚPjN*VuMP8C.5~Xn!~̪HR@Tf$h'Ig(S/ T]oK!:X8/D){-[7q Qs=C:$ކ33xW#j A P1eۺbo)cGeQ$,qi &*uw֚q.s~3#zqKOF@8bqk5r,Fh1RV2z^Bj=4S,`(7eTOi>ّ{,$) *쒎-}2Nˑtrs@CK:sA[F/Zw ?ZX,+\J%6R>%1꒨` I\zγȟ_C88M_ Z"3΄ Q;nt86"xNG IAL! =z~E؟? \~?H ?$ b`׻Qѵ[6 H+`./ БLqC1uâFuu~c_D_Y<ۦ։N-') cyA;C3w߬SĕGmB"n"Ba&v\Zf^J-6@O:uu?8 ΒLcJw(5>D=*$?,<KKKp~gF1 D>sk yG7ٰoݕ6<]Q.~Su aU9IB\:W: #=i.^p;ޛISȓ[N\Egu~U} IFc#b sM EN7Ar #ޅ^83r@Y(lN1HC qR:f~eXKiPؐ!{mmۏ]& Cuq 1UֻT#t EZck7|pKJZŵæGZ\=!Gxg{c ײN.[, 4/VHg+NhIrz+aGYz,) FE~|<8 3w/MEQ?(Ʒ kQ-|? j0ܒo—pL1?-s6oT7 ϱ;_Qv+4_ZkY.6?00fQl[va' 59VH#e$'Sq&UkR?~A B49Z?SFd otXK%wk%A&~Wo+FۭE~zj}qKH.%(x%?Y4c@F̱ ?ζ I+J‚ xY1oz۠If6Ġ*+D ϓ*ɿT.`.z#]E`\!#L J?̵apl٭!+BBdً^J^{#QD,?i(1qVNW /EYiiSiLK1I1?NS 'ev[ =òξRfZ k'M2 sz)Gqoqp ϶23H°*>lQpµک'H$׌^u[n=*w3-4 ۖF9X 3ĩV9V9|xe@߲ґ;vEML(b3G J1z`HI?ך!4.3|#Ջ+#mw3^ p"Vn u l? /")Fq)`m5>~Snbus3{# fT{j( McxZg| G_g~_vO+\ZGs(8Ubfh^v 8:D5{xz9U?m!xXM]YJCL )ٿ'F=6e+`RR~|@wX&<Ͳ2'&65%vhā$$97 A~ᅭYRT>ө'BOaS^he!W۝Kݣ\`L P0oH@jApP|p= €Naq.$ 1 mxD wI2ֵH@>cE^t,aw "7!(KlXF]% ӉoB<3x)h+%G^:;`zUtBFO¸U1K=&n9 #Ex$u:kZ5I|(,Q4ws4LZgct7 Rt%/L"g?EWShQJ'kh7Љlyf'1`0#A {N{h65w| _Nd1kKN=b[-E7hmb/x~QXsCB`ըP\5T.@ JqSj({d{U` Pao<DŽ#c'4#/ӆ3KjsL1`L }!a*)VU^B7miz ëi5*z:+,,#s&7,UMnw`PМ_6΃"v|>~8c2B670 bXc"&C_.gۦ+BLb|wq5 -A:)*0Ie'7&W}~^g}{P4]! ? *x_b3 1jF Ba5DDKWm^5tO N! 9c玬1cOM` 20F32,A5.#L )7+^iN,/[@Tw R3S 2zLHg%"Y(;|?mވf= {!Q7F`Э р*BDh7r4~NJ%$Zޭe2,{O}<8HMCs=h`xV'[(c:MC!֭Ի͉b,LgX1*L^8: p*Pxwzn/aΰEc:M(؈,K|>wr=̩=x$>w<˧3LF#$Oweѷ@ƻxIj<`-z sA:p1FYbV8vX ,cz RoacRY90%եEj`DH؞[9|YM^,d+Rzs~ө_VEp8ī3n!  _Gˣ]!Z4*}gME% pVP ?S̓ty5YUXx_3E>SP3@i1|@|@|b\?y0n09Jy ?@:aHg-svΣ{>gdec\O+xqCurz\a.p$ׅz2nX.E 㗶ҹo+5Y+7RWgUef用47SOYT|n3cr\C"M4Rm:!`Ukxpde*4W}tq!=cpekuML@`C7~ k? X>|UQ`Z7hM ^oݝ 8tYra#n;9@P=1cJجeO#_J,>"oFaL=#k BU/.f0/* *oB;n |}b/"]$S)lp}UE@hz]iEK x;l?&.}lSBƾK{ f!$"0H7N,`\>a%3V$g0Q NK܆/6|t4wxSHH{ }TVN L7*9j0R'cqV۝v&=]cjFX|N^ ]fQMe (-lXjw”M2&} :)Fn!#{w 9'pXɪf"5ZJ[̰n ;mHuF^q?ogES2_w|[{h:ȉ̊sEʥAf)|F>݈a<";(w$JO05@6"͒9uE?> kXgn*꧋ S5vepFaȊ@ ! {oaq?l:jSYtG?8*qmJP QK䣒V,}W=Zۀ"F@Zr4E'Q CP*t OV@6,,r*'X6r&6>a{UN3 !Fz"S^Y[xf!CfHc`u^"boPD]l,0vV"p5'. u(7$V)t̸#YV̕]y3+$):!QJ 9$#b!+q ctx+vRL5 mO[̰ \'۳6zfہWC;@ҷEl貵I&e_i{TyFec^ 3`?gʈ6wEOڡ=*<2`ߤts|9Hulg 9tV ^0ө#$BO蠵!GeRٺv^Ѯ,Yua1w*`','FvA:|dQ*D ω}KDoծ0w7o|8A5k7r}1-Ŏ^ 'Zu>Om,)z#? po$?}Is/m7)RnʣӒ":Ÿ83ado5mr3D]>x܁qO" % Sg%Y\jl u9 NWv™0qDܲ?Xb_nu#b~yBUzSkQϕSu@dW~V!&XGi2GcNUN.,`t'`.3V1Fjkvlo淘mS' Sù%܈ c3'c cQQw oH4QZ|)aƕS:™3bWhc0EjY+m20ewG]2mlXh aou=SH?R׍Qw`5w <,8ީ"O!TۻWXxЄcc:BGdE]̭w4B Z-p񢘞b8BUOrTf=\+l;v}>jB]}Y1mJIGk= $Bᔛs(U$?b1Mȳ#F3]9ˏ/32;1g`Oe4OSj#+} ]nIe@]҄ ='A`烇9VƺvzNdyCLp;k d 4q 25+,b;@i Fj@ҖAj 0rf@CMlh<:f}FO#;TJ4)4-MqտN[NܟoZvt{"pC#wDgxIUѰ͒s󼌺< 85'X;@7JFq0g!<_b u)!]qPoRNl.L=xI&EK=تˡGxtz"%j$x^:p@~o @rh<ݝNi2Na/#7n8y``p_<<,n ")`dyBz:Y:}^?'+78%s3ˀrI/ 8TwJ ,@Uՙ.z3",q%zo"~Z$[Z͟i%a 1Zޅr't>?RJ0_"> %MX_5H 0pW ([ҀH]Rz]<@;WjM\xfF`=>K+9f<703Ӟwy i [G1߼slS5DLdM %\@1,זG`55>_*IO:R)@`ܻh:QpStkqJ`PlD?beت~}ᜮP ,)g# <᧲ /}w;wifq'P3I}j+/۝˙c3/Rk& +5_q7 *M3~)qsA+DM@+aӣ(Ҟ119^ fd.~ Ox^X!zM޷X\*6'FP~A+pO|a1yowy4Ux58#)znM[ݝ8o0<=7e?K K鯹;K1n T\慎CHhńmHzA0U3T3"Awc)SF \` ג0K,dk<={z[731C#?Vm?`0͛cQk;MC^]Fg(?OQτIQzgت"hMzxPFjj?ƿ|3 v #L PdHK].w.rɝGE#~S4꽊Նp}̅O r*M2Sƍ= ~ Xa4( L+BE(ׁa@l7s'TYC^Ìۃ9j3\|ue9&`n\2 -ЅX0B3]+1xJ2av^ݝη8]%lp"+~KlzA限 oFkrDÇO+w] _5Φ.{Fwi#3f5AyЉM2~tK"'=:B , =Z&j%˺K[m:1ح:z+wdr] 7?P4MuN4&s颾x&T3#2EEB.=A<+%{I_ Bn!zq!ًK( W5i73*iuu6 g~ig4$STOFp8=˷4QGY nmbPޚ+$*PUݐ1tvq{ Jx IgP9Jk7eoc՛)gP|9pK|Jy1!g3W>j T02ftbQa:f?uM/Eo^ͧVcS&0O@9TI^E9RJ`:[P0,~0I]Mu-bf1Eu\YIKPCBn޴%[mM`v4\;;$m=09"0Q#Ook ek'{y>s/)?at6 ?VGЏ1C]Ǩs}m o]GiYs5 b]ԃΟSʧlԻ.Th0;[C˾JI 2x-Y_vȎ6%C dD)U'{漺lXD2OwgYS5`bJ[8yp,< kޢQo=ƮֆG~@vfOG}siU߸`7HCq~gff7D,0DQ!@'@yšp`Ė1L\'?AC4YHJӢ%#2aRIBPWd6Xs:!|"τٔc8#U[6Z`=HtN[Y:G| | ՛GWoMbG;CI a݆d([yteD,kQ-D(!yӊ4 AHN/ a8%)볟eu,]a 8)zv|(ɰnyR8Ip#z:7pEKkx sE C[S(𧧵[Y] C/\Q 31 0 B~uƖs.5I5&/ŀZ 2wEHnydFE /E@e6<4T*U^8"o\nM<8'?_II 2#L?i ״kV5t2[IbNZwj;;) #h)4ޠF$n{X< +4] EC k߿v%",t<*U᜾{ډy32yqE{ ȁz$x".ѭpNfAÑRcb8Iѻ٠I@T~>R3v8nZ4gflQA  O$QLZ vԯ@g5$,d $dP߷)\xYٗ)uY|?%_ 8j[\C]-~Ә$ G$V͔\HkoD"6t(86ujG;Ka$dbe<&xi@י. dYdHc.:(n 334/!먬'i ۤ zge;ɈOޏb_&/? mfYGr/(>iZйbc̎9 CYIόIT~,s8] Fi-6 t$r2/OD& HiP<8:K<6T(lS l͆x: ":UYt`O=kRnf( dl˳p]IKR^U }^CcC3^/~\bF$-ĿfjkXZ̐><'❪ TBv8pg?h~D;0%'asK_5x [i0U!e;qL?ëϏ)?RQ] =Xqo,dP;%:%MWFU }hV<,MF腼Z &GsX*w*d("3$f݉⒕yd*!ՠү)*|nj[vM1aUeI~RJᣑq'3I0^/jCdM1~=)6堳g:.O"L_dG "EyB,]AQ@ͷbQk;BAgRfԺYWp^ ^v&`G{*%z|亷UˊNSP+bqʼn0"` 9 a36bμX)w a͔w˴4:|ggvB*P'+aagI(]"W܅ ?PYm-#y+5MwV/\-%$fꗕt; 58|!s^w>Iji?t:?vǍ*0wo gġ cZ3j6 LYH2C 6UBw5 6nTrc/ <j\8%=8}t-)X0/2ⱦ]a@%'#[. ߛgyvlœ0X(<0 ~,`pR_n<2F|2 z[A1ΠsTUM5/¤|n(KJSKGrD\sCdVzbL"KzCk=':G:d|LШw.Hݶb>,㽶3eOOX[#LV{$#:'u6B!DF$ R^}"4 wq `w=ycH_q^C&V=p՝n\WZ&,ah;q@3&iqC7[xZp}"V5%U(L1ߋ3'tN:Η?DDpWֿVca4`f%# aHTZgLfxk3+YK`bZ٬*OY'Zd.+ *D.C)o))>|t*0lALYa0%[v9<7 1WXn!>q%$#t %,ҊPܕAW$B\v7*Ѭ^yu9m`zv~ȥS;Br32Dp"PU{7`\[| mv&-j„$<g Xx)@#B8xML#\hھp)ºR=J= fd8򡐼z eOc ^^e#W9FBx&䦵n4kfE/F:vQ78ռҝػ%G;$"Wp] h_3'As}qk\"(=\{!z_#s9}FM.+FЌU6QgVbOj۰>/@ճMR! _~EQyldg8|l2-q^[CE=h9leB`#UnP gs,. I G<zBugRa GThD4'vfȥKE31qIZo6Lr 1` C톀 5#*)`P`Pd>uvXmse7T;fGN`a5>-^mS3z(YGyjb暅nbImf9NOO ʵʂ&75=z|47+|uRRU?p]2{i% &^3)S{+e.cVGG!GJNd-G{7DuJN\C(T ش:WȢW8C Nz./0VOI7ͯU7>ŧf_M^+D7MqFxWA|٭ FF!v`D\~9k^? 9\>?7a csp+{DZ N_!rvyF&Yq>ag%gux%%6D"|HY9H YLa@8CsZ\ & 9fn3[8PSm dW~gbQõkhׄ!gE&44 L&8|ysnuclb5_ -gLpًo g n|e#{+}R] %P9:^d~{Y•%!ݾr>rJ.puֈu5xO<0'UCY&H`oaI4JLqZ nv(~,64QJ6}k'Vi.VE1ZDy"5 ғ;.K8 V ~>mH@{n17$_] \ȴ1/f=䆐M;r&waADG~t몺g+3=a&sq`{="@ڃL2^lDe#.eF=AVFXmC}GB%ipXof[ hw3ǷǪr'ߝu{[-P4/rU`&9dדYSiV>FMB]@ Bvgyp|=̲oVrAqX V֧ ]p -9'h/ߎ5"wP/!4iuh]1+t '0>#Sro҆Jl"xF~fb^Fmhʧ7n4PGz}~`OFs?5,hҀRN{[Q=#$(;<B;Hƅ^R2!%-LV܋T2daJlա@)tkIyl[_$ _tjS+Yئ4mbU%"?(-ozʿ'ԗ"^,aM՗4Isy=FHK6uDΨwuSUlק LM;;]p]=BCޣ&T|, L09f$vRbdN1Z?G?opl wDٚIe nT5p럡Wb54`@gW2 ի#;` u٠c:42iwo,h.]9CuMB+S+0:?qgW;yg]qrX ST*5t&h tO `d 3d\UU?ˠ}qW\ :BPɶ*GEODrdeH1eQX~י#ٗx7<3ƓO??0T|* Mo3\yXZ؍r(':=+t[f)#[<*\Ï7to3*(Xaןln:j3ĆGFOJZ~2*u1MQ6S\ ~HoHsƾͬڎv3Vwpݪ~)xHYqqg}8F#Վ[Ӏu }zYjOh^8rgCOmQʝ04I_1Iz5<{w\H]`) p(]Y7ay&su^YJhRUxQfD)"rkQ=@l M_XcmtpK%eD+O Ṗ<[ssV03Bwc MoN~buykEJfƻS.(mR2ur_-Ӱ=$JS0f &YץÙۉ&,r xԧ#] ۣzp4P~'7$(oD h Dz ݯSp<@o 9NeJЌd|*@CvAC ioU34~/mt PTRxsUj`q;Jxc'2ֳi28hee)M0@ hx ޢ1K=g'~tAZ @fZUd+pӱP+E8oY*W8uH'3k U+@Ҩb{_̷ڶ쌄BPQ;>{1Ӱ3}`q$f ov;aӁ@T.Bl?\?6!-c _I MW~'G5*ʻn:1j&S{'(;+!hɫ LXXd@ǣ-8F[ad.~BNaGW% 8Z!:q̝zۢ8M)5M-TYvsjүG"_]+?kA>G1r92-k4sfևa0#kw_}զ6֠+YZNZZ?Ej$'&E YUԁ bC 4 G.N9bFh\GpTs!V`QcLHHAlh_ 1_ōrz{-_bt,Q ?y`l M{`!JR{4a7$5Q\vNJ_ƽ/=BKNܣY;0iN%7P|*"no+rh$JWj=Z,Dx'Ǔ?@̗9C%Cwұɍ-;2ǵX#"ՐDuW@ʌmOp)rM\{L Rƹ R vm)Q:o;Ghza8|Bԫ:vc*_pJ_Ro}8)DyXoߒr x8ɐod}6sl:R?699ϊ뵮q!ֲ%vpBul_,>F mm ED>9L:"ؘk9 XoM7&Ķ4H൳߿:v9y8K{Ɂ'|SֈVZ)'@)kI}cYJ` Ug4$J>YSʐkĂ&2,>ݻRz9)ZI.K6V*#m OZ0Q i^ugRסe9l9u9MiS>OvdDP=[}Ŗk 'X ~w/c4jck9)qU#]W7gl_SolxAX_3y%:dE'@{M@mm|9s[Z=37y>L;FNtљڂ 7)[BƼ_-OkaE}FPd?c}H3ɬcL+=y`Xj=% A JD$=t2Қ j9r-8V8ʴaWŒ0F8Ϛ29VYc)DRyPj]+Se-TQJan0c69VVQX{OԮ׫,C pV)*-xvgpv3Ee/i*IEv~H VvDDTl66p<:~G@~uI)P j >Sk&R0+p@B~w2WrĜjdant b*7{RBti&B}FQ E0r[1[_lǵVo|Ʉޛ y#_<:6x qOސ%#ۿ=Rɏ8|uZcpP\dxC @;fW7 )&~zG6y)% O%@lP{DsQzWfIu!f ;ynq2CU,d;E2- :22JBE~c85l'(ī"/hyTI;-̌gn[Jx@"v](xK0j7^KvwFsd4ToZce 9m`!fBI+'Rq62 i:~Qb#d>Cle Tr.X@g7/?L3ҸvǨ0gylTH]79YocMqc`Ca3UP|++(kdp9?r$IbpK'̯d_^V՘f*[?%qrlsKsw.dE;EAZ,+U: i;!V>U&O6^տ"!#~u8-n63!w=zgTʳɭ >X/&țq)h31V4f8\r1Oy1k;+rh"@Aa4sbܳױ7B"CjWp*i^I5D%}ş>ZRs^E`ަn'"LUy4 -BlV>QD$]thܷ+W"CCDžr/[Mli*gˎd&G$҅@j-Z4#IeH\ K{ j ιEw-p&=yē wzxf Q:=2µ/ܑş|"Q0;l@[}޿1Z$Tj;MOLD`Wx} e%voy!0pS<УXQQ`̩E4)#2i`GDp車} =yxh7+HF-w9{tYw[Ls٦L7F+Y-+yia:aⱊ.\z_\U2b0ə/lzC&23!}Q!%00ʗ&BӐ=rs:^Zfi$-*e P  tU1gu qߧYꕄs(K:e!1Qxq@d6bcl9MVdQ~Ͽ |HW,`)\\&VԆerWa Mt 6TT}‚{u^{Jr0N%,+?TfhwqrARsHRԝ,n%f)qhǞ6 A.`ڽ]טf\ACYyvAF\cFYP#Y? g|hj.znJ0?ԑmJ}OI{-8`!b(c:Rhss"{|jiOz\"1lB[M(A~!0?;ȌS慘xvQ;CF8Cm gV2U`?Q 'qNT_k1v۔86?0>=#px#xԽMot~l}11pX>Q=ͧ핷}xX$2W.]cWg{}Ce˷ĥu$=Ѱ"+ktAx0}3rF`t@帎~0M\GKAMFySAYe5t} ^1F.9t%vcRS7B=+:/cIx)gOC?ԦVEjBgWPŋ$8Y[xDadZ6M<]f$@)a -qACe!yI:(Km-]Hc3~MTTA,膖Zƫa5]~׻΀QB\8 \uL҆#᭿]|b?t0PYNj}#v#j` G΋lC9VhK 90SgLuo7茿htJRq,ݻ5k՛X@e _/sAtQM?>?izhGc6I/$|Bh#.i*6GFk4CKwV/tsSI+7&}dcFϜP$J Z޶i' >4[z3O5"ʅ;hLmڊ g)Uh:m;r0CXs ;E˞r5oSPhMBPC1ln˩ڝqf$[J2*A{C7cલȋ{<{jl_#03`!x?Vb2fȯC>BZg%,|j˗"/ K $B]-6"0S$y翎[|G]_隢NYWRŸ 4X54bo wvi،5E֎!‰ش#p8[ 3 NaL?Z(uwI,vŠ[w"cy:Iay)U/PK #AY`NmbM+}Qm<33y=hxxF ]Jͩ&7UĐKp0"e$Mf_o%V8"z=k7闀tw_($~oB{EO0Y&,BR!c1y\Hv?1T'A>E6࿛>3W6ԧZHqMJf|.j\)#|w_بS|ӝ $7Lz0s1qD{>ҩ71 _!%(9UfX.C $?xZoWno"O"L j9{ߦP~c|f!=ir9+̭7&ϓEwfʡ7?Өۨ:B@ ] ]M]m|&[i^QM19ĠǤ@'n94S-VtH._+^`}**0PmTcz' ko |Y5$Is ^xJwDn#ը~QUR(/ 9au֦jM& "w>Zd0g7p+[*i'ǼOهe0[Sv[*T)YhgO67zFvUP-oK*:yڈ[tqR:}T*= )6Gctx=8쌠7sr*2ml[%|| ^m3p`\2Hm@#59ی;#6A|^\w?w*Kkܘq Z j}2k4 (?;Y)VkֱO#گvj1W@( ( # {Me*ЂF<2[̀O,40P;LŖh?O$B'<*zioY M7g:pZ~YѢB˱_DZg&?P$>fx*tE Y ,Yo)Qaz~@뭐{<3cRό<~B3=T+In%g4"{5v}ĩ:"}"6l($-vpojxiFyIU;z"+V_Z' WOb5R!=crC"8}5o`Ih2fx@E/ĭ۸NWAUcCgmj ȑ[^Xtw2Tb9 oc= 9/6b U+@F8N:H, Yc]{;bRYt#cLn勪F ¸~_$F'| ,TY ׼OwFEߡyH%A;- @?Y]Iz)+HL}Z (cR2'c}Qzp#o*) N?We3r}~"^uڜUW`?}ȯa;`Eʕ8ul-"S2RC&rYmtq*8˜m1"${"E?]ze,N=+'ʋ;YͷS6Iҭ`G61;FAƔ|C^F̫?sLDSeM_al*k/m:/c30a> SR9ZM2lOOuma:eaI*("?f8PYpa%bGktWZU Wۺk0z%˒CD0;mmfF\u=%&[q2x$ $qE Lv{Һ'T/տ?K:(_yϼ NV7ؿdفAg}R־.n]&K\o繄N"-@; ߓSo>l4jM0{Oriyb|7Q !@< 5T% .],`1N<{GfggqU/&0a{{%8o³wzM"5a'ᚊ;DUPQi88vR2p^]BRPꁸ(3.%$;PwӴ1?J4d\9XΆ0MJ?U1޼;7þV&\dWC/Za3^~>[Rg;h 5z>vR=x 8.n<{TG\`V# H1y=@~D䦙I_`'NNւY|;8m ,'MŸqwD̫euo>wls2#ݸԌ(&;CE4'l Mn:j)_VTr)4!=w-_H~-bzGMy7H1po}7ӑ< O[!53ru}Ͽ BT;@_țrcR|}BpS<-# f۔}M,C'U*yRuE%"ȊS UhDl!8ذл0-7 Iڨ+=]h JiX470:¹#ױ**0u#TT_٦^G*m9>K[A ``0LN HNo0)5\RKs͸#de3s'NR3(g&A6MH%hΣ$A}kgpx@XEβPuwbRQ#,-7QvO (vM=nU,T\z@BD1Γ>zBcʫgw!5MGXv"QO],k|RΕpuF-n/鎾{X-hІ`ԆW0##[Na:xKwBҊʰDj!ޫwͭwMm8vOqG9v_~W0[DuBƍ dV ޷;[/Q05F>[kcO|}_+bPg B wטM"(aV*9,`AwӠ:1><*$vdPu< vaqt|4{4uhmo+sŽ_v @S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPPM朇Zy:4@R: )O9V1&8j)NΘy}:[]8c7aL(pSZwKjAZ A'U q-˟iS||wP620/06ZrR[;Gzs1͹&bga@ JH$6M15[`p}Gߍ|tZeˑxT*͇g]y t_R%Ig {Ee_cIܙlKz]b_W MuA`]ORx8 T^me ^&q37]td#:lu0- EcH Y k(Xj.Nʴ]Ԗp/o@ا:C㈌zgItc_QD;m '6kIn}E{} "үwxiK =.$<8=v *z) qm[- EFdM♹ "H )vQI?/{kU ]AWY:{XQv^(%'#@l!ɸ5RO!MV_rX'~(vpkL@)n7%W=Ei5c5oC2p3JـP(%{dX;+24J}? ̀CZ)u/ ><0 vp]x<rw:O v.Z- L>3x%d<^[yPN1QzW˶chI~zJa5\B3zh4̸mݎ7{2YzSkq!_z2CseW4 $~~""pQy;wZ~& ʡ XiuΘYfc7ޚs\6{E &ݢKZw,9֡ T0"DoUaRԆr~gc"٘!Sf9Q5G&2kEf5("8d`6,_ `D7=|5ߓ EKHΪ.F4 Pr.Cgw?(BD#0G?ELpm8 ]KQ]NiŽ`bvIcD5AҸ[T^kQ\Fn&J'- ' ?*g2ilwMp5*Kl֒E1efG &o|=٠Z}-]GI{|&PgNg'T03e }56h&,mg6KPҝ,HdBٺ G0DvnSOkcXQO< C7 ZkYlQ-?` !J׸u}}Q/RSn([T lP,{'G?y"q\ CѡA7-/7E3o?Tcu@U;`_|qX'el"C Yt[E稻S-Ď0;cR,,qbBR=gʑ2F!2MtyF`355}"%W(*T;Qs?@eGz"<IfHKj1EnbM>DԫzOIp>':D3H1J\B.9(r=G3 u*G THn63=j~h>Cg\Tvj=SGe4Fǒֶ :`'!MN'~ȕp;?5j[QwQ2"Ӱ 9wPा"2KtIOÞQ繧aܸL _W"Q8Ff { ~] \6QPt\뵹zGэ0 I^şI}lzA/S˜g#޴mΝ5f<h9B؂nRSƢu&'tgUq'gGRwq XRզẋ^5c&@`9VƇ'cwpg9̍ {QT2?@..=u’J|h$o3sɛH>dAD?s-3lDMVu{؂l FHM_.E֠8?B+o ԍ[/PcERF9O][_迠IS <@Y𺪁m sTTdGl:my6iߕܛ J;,@ӌI,WpeYLTy5( Ug\O{O!;m>!%VMUo5-{xaꈩB$nZ Zav2@lG5Nκޏ5kרwfG*шL+JkSxnEDEsA@cp8o HkM%/.+X˞~x=PY =t.y-ED덏3luv60$ G*rkM}_}ģNxa#Pi9e ԦpKW Hѡd) m]"Fa(}m&F-8p^@ YPqjե8iѰ녲ڀ d: Θێd+ӯ&ɍ>%$LNc1JH9):t*c]#D˗ڲMtˆhTP#}2 }2\2QmӤvh-hU4R>mC]{0EgBW+ŚeN%Rʖ%?<!=C>[eFNi=6*O^BA^@xto:gV`,xLK:>pkOKFIbL0i+wrc8b7qpOnN3eDm+ x^viAlہ 7)Hv\Z&834d(/[7DT/ ?z0.)0`[GeR `?7hU]m)_)lzjT+&}m䀛r![^"8N#j?n:aZF֪ "wlX$W(E@ۜ6 І 5 TN Tw q3bi&|/J.*cDQ+Vd m5x~a^.M-<LokC@0]+5}E_ʾ r=~Lfr itXD{J]wD2,6 +C^B!~=>djdgbo(cV(4XcRž-P0 `Xl\*$~Ic׹FXFű2^#6ݝ,~"WlEsY[)ȗ?N(@8y(xIA"5Th8_W">]e+ڍvFg|T&Y)oE;Ev%H=Ex#xfE&?Oc^. [=bY?aq $,E/H$q;h5hȦSj ~S>ky+})2!$eX1e]\}i.D6)ُӈڥ@%~s_ c[i8cz4&9@2OY<|G+}!)NPr4=(p 55Rq+jL\L\O!Pi3Apd΀|ZҬS$hP zϤzW,Z*Jy"z1%Y%A)B3YM9 s!ޕ/`K?6/bZZCONGP_{u&Dd/KJv61}AVc_W(Q\0æT|@8hH#uv2bel'|P8:T ש8Yk[U)Q|EVj_{+?&wIQ7:9bG$A~`'@4$>=#@8-AxQ+84 &ÖV{^eng0}Զ6-`NJМ3 IJ)У4={'MV3&:H.o\PbGԲg^+T`ҰzsOY0M4[T2'y>H(~@O VlBqcnZ}`֮oXY}0Vo'$uSM/ _ x[4 /;O.5A0R;f^KBF"= w gEi:{9)n:mIn|VЕ$l3!70X؍~g)\X*kt}!]oO=w Qo] "E!bA%MN^t#֨{-g>_hB$ K$}Y?,p3$wm%L1p]x@ bPMSn+$Il+kQWw|t,'6#G{nR- IZfud<0BH44bx:VLbO悌KG8ݿM]o*X~^Fuꜹ4(#~P:wO AXÔhD3R^%俢'K^jK I%2*cBe/p" $v ¡vJ3d/ DA6у% T SJ&1p:MDSaKFN˗&X^`< am1bOȗT!*G],$AN.L.2Yﰌ b-jk^wqJ<]ng'#k u|WMG'~K6 VXXzA 4™vqW9d,: D*3Jc4B-CQ -E9ښR&ܺh# OX[uo"LkoG]<Űoj)6 )'نKHaŶ>:js#* NjIl!$f ?4y2_4+to-5yEhjʧ'S3Ue,yu%:@ >Mt Y\;u 59fKV:tO[MYr.hVa#!20}`YC#BMH7A0IQ"~ ֽۯ̃@\30C)./8ㅥg倆78|v+#]P>O#Fc\ǔH73VUGt Po)TXB#"95O7TCnڻH"3IRi-H.VfN!Y'Œ^o[xXt/%šOXM<iy z|Vh "-]Zf iW1 6nK^/{N6;(v%;knd%$vo(Bf]l#)rc)ƐJݴ^ȡZDbGQw5쮗g 68H4Om_nTav5OVsdJ "Loca7;Ɂ8Mҩgz" X7grXh,0Hx?4R[!dl̨կC}hbOpBuN[rm*xX9#;A { 31:r+ydGq~c-2Bîg1 h' L+"04~+vȖP_\>jLɫdcs?j[O)'3\$2Ѯ溨BtnUtGhIb,ݐRJ_W}-gͥ6obeiegHjK.oIZhd6 fgh3)]<3qu;9nKiwbDO%ܤ9ذ @0E܉(@m. :ɶwtl, +0`x p][9!*oOkf$w PԱhlkf\x`J1Ŀ㶘C<8N\r0y.Ӥ+jف%KyK@] 1%PCHÑy5>΋ FW$\s0~v^VĀqx E}]h˃z ~ >n H &"0&铰&S9o\?a{ \LR' K9^mic;:5mNLbRN6y kAەym\M͕!Z^2ękI1`,=)OՋuE>Żbj.q퓵%4Y}uPrML&O@v\:M̙DZQ nROk#|کt1[μV5UH498&ạ֕fw9|ܢ8~.zȬBLG4py/u4Fvs*%7xnI&8hUԟ@f@;8e&؎/NX1`_ VL!-ԢR Na9LMfSKG>rE$j%L@83S =jhOd#KFH  6Kxrc`[ L) 8?7qǺTق#~g?ƽ]Sx`;9R捼aN]$ adeHFIb>|`)|pc=͍FV0&GFx6v>\Qn6[; ES?Ac01X!ho=h55Q= fg?UAl*>( [T܃oqSg9N:hWԕQ8#+ljХk%en}h  L>+3]7i=DTPN2d!'-uM Ep/3#IxW3|bf f$Vv"ehd ƛq@+ۓS1.h!8u4v Ńm,M #4iGXg,ؔi)saGX=D/v+rIJ|~Լ.zJ_xbz?ވRk=C8THZJ:-%Vwϓm Rxmr`66y7 gfGI 54 #Wfރ>eН" -wt2_Lì21e㦌+ncjSYV:r?Y _ɧ$E H)ۮT:Ut?~9 ޺Tg细 !F)5F(eszPn;\k+Q1Dǖ\2ďJ lҚ~a_"i5:i"Q\g-~^-[>TlJaJHe#V+R4)׃^QQ4Hkl(+0~D/4NO 7j8ƫbQI%c4ߜ1XvhyӕQ=q@)WLT\2P͓lBz.׃M5Pki^2QT\ùz?u#]((l`~rYO44^R\Tfs!Zп.JCVU1bmy6~|d0wr22atc6NI5;? N4h{9BԀgb O6K;OUFx2.cGh >אIn6A, .!F2_eǵV!X=5\POiBF8tN2G*ౝ]S3l}KPT7%%#B3nrxZX,UFBSQIF|0?ۦ$yq!C|@|@>#NfI܏~٭nܘhvyQλ^iac'_XxFfw>KgQ|O#[#9WMMud~V4$5) 16bVT_K >=#~I_ExE8F/,scPµ<XKm!`}5`OPā@ F"e=p $vYb26[3SO~_$pΣTOsť3:UzmS0DMp HrGU^4/AFqIQggzELRO㥥B݈ U2gk/49g'SwЉw 4eDhӅz!ķղU,Dw&Htt߂%ή9FJ $宭B*m}&Jk%u2H</fhNGH <ۮR>d~~2}%ڱFq]6™'rϓ0m$s70)vڱVLjTca59 O)f͗\) = (dkX -c;.2t1k<"׫9MVd8j<2x2^28FB%+p3L5"FW=90:y[s/su],Bϖ:W_$$  3T2s3Tx "e*kM ЊaXJ3*DԞg|%;j$d}A y:Sǖue#Óa;]ĒjGU2wV32eJ"B@~m1ٚdwO3\F]@Nqʛ^"cDS@i/a. 8uɺʨ5G0;/Sf濔Y0~GOӋ#fde!17? 0"rYM,nv1dn<2ȅFieo1?r>?8C[$Ҵ*e  {%V<u mёrȭ(r:nsj< *P5TYc!eѲ( K}h|»^=ևaP{FcMcKhťRgHzA=&HU:]WJπg ~K-Z /2Z]\>@\lq ho5 ZQ))_ڶ|N,z)!cu/%? ݇gCC7eڑpRohԄͺ֎ehm@&!v>>o;ʧ*H*9?MӌM? !(NAyEfK )H_r:g\5kˤ+zDz`>LЪWZpuB==,K^ػ ^Us^fidڀPRKRbCFxx.\mMoV@׋ gWQ6h}`ȍD> BjCݎ, W^٩vY.p.LW)^RCqomdw Y%S>l(*خP#ez5+3n%u:Y6CGu7NVp/N%tX[~k! bP{WfkeZr9:֛ pټChZe^D{mku HqP^gl+}SHF6}k5 ۝ M1IgG(<S#A:.q|r>78,3ro: 5QJTeO3N`B]<5JaPxFFY@Z1 {U$WX']C(:a&a+R F^ne[a'@ HĹK*7Iofw;sv?/HK.{H!5%mr瘛*sx.ܪ簚lE!wǝ2u@zM\oܖʄd}]G 󔧨P݆iWZ"J6(m2QG+ɭN}ךǝwWD[PĖW8c)%oѝ;{2\?b32 :X4"G{0'6W o&OfBϮSf]NdPJU˰jI֠=ع<6'"I/ f__h@}.%&Ȕ_iqC38࿎LZ!C;;B X㎙Ldjg6E@-Us@ͨa N*9uw]H% ?BqsEWx8-ר֛ };pT W+5No/$ʠgLc*}NN;Ԟ) ecnosߛp&shi=ҷ$n(*ik{0L= YEy?(!DC ('r71"s%'B@DxV2*#FNzQ_ PiNr^mBT.T{=\cBܫb28U9ițcwݒ9mcoGmZ% o' 4..⤨'2dk~zs<<@ kǾfg~1R_| ;fǕ94W+~R s9 YlzvWߎY erPP΂ AdN]8PqT':MYjWfA[P;FѡQ|+tnA^l:Mw7OMj8:+b݈KH 3y%tË́oQJk)yX6nQ)HCdWꩲ%̬3F1#2SO^m [~9H}cGw~5 C0(ZNn/ JaMRŃx'!Ospxt@ B 1H ,MPK3lȿ^VF:\Vi-zDy kS\rYb0=f s(qKh%[>=΂U}W PK)<[tz ~x{,|jZvJxl족K0?6ݙmi [D7?JxЎLK@"٫37Zwy {hGeCDr. ':beRNLB@h,aLv]:?Af%S _#=a7{'`qkΧ ȱ|/Z,c#3-2jI}.ekMc6$6W=seiRU6sckgRv,w2(_TD0PytdM_ NŗD'b+*'&vy-D`2j^ШM0iJ5TX+) ; r[Ce?1__EzϘ)d"ECHCvw*cf'Vb1qYatg[_9l1vu6TD "\ ?H(TΑKr#,Q}u׷U 5dLtXX'^ΠP~F3x}zuW$n{F2zjȝ @S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP#8x t`)?@p-\WdY|&L66C\/nB4ID, .Y\a=IKqhˆ'2TO$n_Pa6'c_I AP,,諲yJj# cC0`#ia.lY3T?C9p\^֙`w -Q@]AGQΕvn\7pxWt lժ3E'FLƵ+,% <,JuJk$崑hξG{ɍϫItp\=T5PO N|U7?gp9se1 m?< a*(or;^r1E"χbq fDRaeք*;E2bRIGKЎcNfńnb8=D1PbPhow¦UhtY:*ǡ2fc.|="7@^=61/L`Q(֞ν /͇O|jJc(  GX`׽fU4q#"ŗEA˲sGcP+6=Uss{b\?W<$pjP˻3FK7[ - ߩ.tC4yyzn~Tm='J2,3mm].y=% lϑLz> OBfRGTXyKmt_tkxLbuD8ҺKp_ D7i> ~Cw]>& =@,ip ؉Zs땾&\J_7XýH"<|?Ğ{0qBvdP3B#r{]\X7|7(RNVaʋmݼnEw4=8APmT3 &i48$߁+OmF ;s_ dR"{5|;߈#v`r(;i3A3$ Bws4ĩč!ԙt}&'$3rfp^/ ;?ВD6Zogᖶ<Ŧ<]xn W &23h91!cy1,}_TeK\U*%e':ky7j2vY3 ,S3Eq;C]$ };J2ɅCOPU1!:/$iTKZ.nsΈb1O!~u5sX6c=Y<;^3CR{qXkĖ-%Ti;$ER}Nw͜QE.lS,1m1ooUVMeo%Uc}-[T,DŽhfm/g^FdWǸ +vtL\z4.dՁfkSvޣbAix 4;Vkg;Cx 2~0gzG2۽嘳kES*zZP!YvHr*QY̒GFUms c<_At98IFPwɧ|3ÓXT@5[G8V` H%3Ʈ'j`a%'_l*R(acAz!(țT"|HfY.Io:QT&b M̾2lBD6 GOH:7Z!"9y]K)b£038t FƻvƸ!nΡgRaާR? $a-M0(Hq 48 ɢ)/]\Uc9#o:pcqf++A&?!TY9fխ:O5pƶ}/xOݭe%y`D W~i^<ђk=Oye'a 5+*;Z*x^NZ[\gJJNicy3W_⠎*ݼBu^C9VFUw֓xIsI᜔"ЂY(=;~|F4@M^{P(nQl+ci72$˔~kD mWbDlf4Zs6*CO?I|dlc>~Z)0QXo`%gAr^x8 mܝdr+Uq?v>6!cmfbǹV"fXL@B0Mm!!HF?(ߒB̺w7UuPV~@M?E~5v>k_n\6؅o-GP,dķ9XF~: ;yD_w(P?&nvMx52N1غ *ws/[-wGMISov`]IWe{itzLf7p+VݾdZ#&v[NclȪ?U-GxFv˿j˟ENr%s@59Zx@>#>}Mtmi^]B|\KW#蟾E#GX s:,#?{Xޥ.fbTT¶tVmǒqA5|%w$f [$h` V7@ov:X/Q:@ ioMU󇈯}bȮ:{n1$Jwpʍ҅ ։p Ș}ˏ? gCHY/g 慸s!5ŝ7w>mGziv-'[\ڲ1]\]yX-g; ltO DL3ת=whI 3MZ?Q~&ǘozd S,d#XKt>gRENy>0CH@sv8pj QE_!"и 6Ji25kFJ)FfV!C˚.Q$h v2!6GjfE(B6Hg|Xӊ#Ƹ/ym DDA*Zf4FD2%gl o7G<:=.n֏'?k\F4'@b66 CZٞi$; 0Sh!~LofP%+S.eF8QܚUĉ'JRW%9P\x>:,RLhbsH^tM!. ]A1I+Yg- 2Y$BhskGd}rqIM^$2؉p=>r/#+QaI{t d6fȯBqI! ~-'4qJϕ~Cx $F֑hN ߀ :ФK~O<>GytBº%?98i_0<"^OX-399J6|&$IhF+hd<cYXkzʝD]-1B@Sݵ2h|_Ybf VSe_CPT+y5z@+I䏊xTg4ufss-}(!&i@ati[5eLONW|[%qw~zN.z(NQr~4fh\^`*4an IZUf$lN{<< XX4f`i2>6 ݈;%(PkXkemqXո󞘅;͗%ύ y:D$T5S,>ȂJ4Ԕ!nك PMzW/^pQw17|][˙0vi"P^ѽ- yHֱ`^!"67:yc0 ޑ:m&e5ꄷfN'Oc-̠ͩH)lQ&џ%v !1mџ¡ yCL`|P>4Pp $qz/o9g~p (Hݶ$ia#!NӘ D4["Po%W$zE>M8 $5MVuk:)??l@GÓM^Ä @fE^]KgG!0p7b"y@N vUȮNB$$%&w+k_(Z;Lx|\距QK9xA6qEvJ0 9ߤl3L X4mZ` LqpU)C0!gGX`ΪJNmp@+fp7&9ݦp>>M) `8wR >_at^z? WK8W@/ǁW[_Ujg=s"w(H YPz?0g8{#.ŸTw1v7IRu:AإZDaO>C՟=1#NIWWQ>]@! JbUR5s".,\98&+r:3׷~Xt="lQʲϏ9!n{O5e-'PP3%7kw{Juc^u\>ί>9o\`X :-LG)G"Dˁ'tց8G~Nնb}q^-E ӭrxoH@Y3{5$'O=*ѭub`)iM?Oxnnf! ])6E" ol<4@@4DQ,~%]"9|zSZ{SX b-ua!D0:hA_;=6yРu@VY43)muԘlCoA@-Y+wHk~|8*I4._/N,+rCxYsmxe ]6m_QĘU i&"emM B0m W޹1Ļ ^VL+~_! n?4q[t\) h;*qeLjCR\LQ p?N]yh)p1%$wul1n~C6ziq[C?Ǻ?/ՁiSBu2wV ˰':;l[gaٺLN[\VO0|MSd]za>0S-Gp7jBWkʆ?bK=#)Td8TޝgdE U/ZB +湷̱S4mCxQh5;9/Ѷ:vf@VrY@ ;\e#REbdhIt0;L9|S'^rl&Õ%p:C1b!iNZzk%U6Փߚ̺ݎҧi֥(>=lXŒ7!<6m昝ݱƞ L*DSL;[s\oΠsIw(@v$[ި϶:9FFA8u u͚{j/ C STQcy|]<&+nvz.IU acӯ]UQ8PΓL20e|:*WQZVoI5 (a~= $篂S;(ܴ fO=L *u->TIkCM4ӣ8H>E/8zJo&wXw> 6Q <10>d4`;H^̰ E]Pzw\ph+f)MPs3ӗslo9 ,J>*7~B~mLBSM/Ţ\t^ИNhjFz_k/<,l{No8z6oEN'"%[5.@f`Ti--#B**!jejѴ &jK][$xI>Pϕ9QQf|ٵ@t!k.fI1qҤTSH%օt7L ~<$*ȏ7J3I6oJg pS^QL$̖D26և:*/ULHVe 8 (o;]R;~ E(VWJ/X7AnjZf דLF'_fH 0Y4v2l]96LYwԶ'M(.Ȃ:2+xPW(oOU"?=k nV+/–ƱĭIZ%!' xSr3 >ْ冺 e&SώB'{CUؠÏ! 6zZn͌d :,TSf(ѧ#1 `zbP&Яkij¯\ Մ?6/S&{z,>痾<3 X|Ibn'L&Ր@sX҇iM* 85Ϟ20L%n;?FS1u4 %JtxqrLʏ>`)/qmʠjW8h3\#!#$)AEh<79c@1yOAvy%`meʸƒ.4(%~=P}>"g [d9( KQY2ʧ1o@y_ڶz<$@2tk{U0i:.e*DPsk' )?W/4|l ^||j@~gPQ`؆̹Z )&(!.v^vXN;O]GRE)E9 M }Ma~,\beEQj`<U&=QxOM__Ѹ+ހԒݥ }bJ RAna19@H QEgw12Sʳ/0B#r Fc`Lkg}}{laTL6dgbm7 qq@n]qwI]KV!rU s!-to^ VZ$H^沸ג]pdL66O5n(+f" lA=}ղB'6}>\9u_ƒ7R\/6GۥaO=L8rpæ)<0!p,DZM k7̶VS_,S @T7w8g3DC2m{Կu`)휃? CFw~ y󣲏ka({ȏ$S>}뾂IΊ" b_C9i~Na 9[z YiAŰ#Ǹ;& UW +G&Зҥ9e>S1CTMdbP`P\8҇''xsd܁rVby3yʹma UsaON؛Î.Q F5|s^Vhv>| E .R蝃wӘZ V7REyP]=Vf 0TY@{*9ו!xX5FX2rSb= ReJO u-x3!X;8[ˤQ㪬Y.o{:-P33#['F8&}졺o\P(-^ p~ AfޛnC c¦ٸ|~9~6NWn GG+]I ]N(utx L@/-yyyy(~ApΥ(ʵUڞ>{E ,@{=3#Lc[%ɤE j@G"RЅ Q jVMO[%u)slic6E+怕 )@UcBKZ}%Q ȷRc+^ ,+8CU G] I}qi o[&o8l l Ğ VوW0nm)]U5Uq YaeʣGꗩdm>SLfpKoyP51BR1 4rBxCI?*.; OőT64Eg,Y}J4fL]<()XgBp?:춟xa7t0$[BѦL^-N M.?nM{ 1m\lR*-~2dm$#)`oxV<,BAAQ`Xԯ%m䷕b97_? G0"rk. v#4kG_ q/*& pCF\-yJD~8? I_^ؽ;g67 },V7q(%G 1x8C3P/NɬDY;91A~CF(Bp1p'9D@ga,~ \oStqPBSu7x"Oݬ[L)?N*Wbj@9|s-l "N T.o蒉ei=QI푑 6j}&[% "6оQkL ΍ZeQ&љX||'Pm ܳjz]7"N 5xA-TNp૒Aaw#61Qg|NrCƙcGP<"j]QHsmHCYXt'tN'wτ莳}ɹQ7ZǪpv-_FqY#ؑrz;s Bz#9j19 68CLwy\/32bk #v^ \7aÎujk: 8fMk/: iQ_ctEfIkws#4OSq5? >_ҎL20PTゖGU}=>?{1vf&l9Q bDz'ҾGCRڪ#*@&|A5y|!;8YmjYI ݲ Kaf~Z0c|@X&J)sc-:lWkHSz?n,fftcᬝ"2@uObPse=+ƀH1FpFMt蓰pțF5H B/I,AI~RmgvkCDlО1/aIq,X"HwX|(:edN -$ I9BRh?mhї~Ff# QeT6@g1vo6a;4+?Aݍe[hOC{kg"7 ֒eF4$G׼ERJBar}N%Ax/ K_N_181ExX=l71SzKyZ{"Ͱfs>a n DHVzgytAF4ɴbmވ(Q1X)Nģq)ێ]caQ8)|mry:[}wDk0+ΖkiFv( z£*:vDY؈U}Ih*F)AK,/d^;߼=r,jTWjQsCt@i3±b5ufBi\6wl` 蚅kWL%gMļ)nY5~>k6_xZQxȃj3Zͼ(E{d4TJ:'A%͋73 @2wR0fuz͘*4(O\l()U<3)Y֡cFAhuա8%F]ټsfeL[z!0T\H^i]`/<$?Is ެg?r#<ũk+}bQVȧ37zVPz ^:]֐%J;!J0?ZϑE_yI.q}EՃ5ĶUq)j3U#ݘ"{udL\ @?InÂ_7 m`]wto3 '9\Y[՞2*chC =w X^20n-༝[+%HƕjP ?xuSݘi.SaR-y7%"@jw:í̔W0yA?$,@cluWPz&/΁74U W։|fs4\$JU'\T3 g1 @R~Ms"԰ux CWIVoO Rkke,+%>'͕K+)*oD(^7*ȑ ӋMMN:f|d/3k{t2 N~c1BV.:]=8::ѯEF*Z{?qB#e[&vwT$/Am4 @ mk3UaLtGi֢SQvМ~}y(GSp~)r5(ȮR(f,CddN3՟B5]\MgSn^Fu8Uߧ:X`A14l]^7SF}Ek~Li+G[VQXVFѤkݡiɫ j=LMub>+\r[P#GюZE =Z{Z@rWHA7 ?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP!y1H@:42Z)9!."9^ՠ l ɢ_m-GqK9|`07MKJ!;>5=}gIX7g@|:ð> ̅ƍqf|?{L)G=6= S6+q?n| nZG&G~z_sM H\0 'F*r4@ F w^]LMv\j +u\p ,X+B8F}dgiBe߹Gnʡw Q=r''>!!U ]gfI. i'+KK}htu T(s=ց Wu^k"Mp讟[{W29J5aC㱯wRVf~:t㢦|>;3 d c8Ʌ&} Z6U5ꥧL U*CҌXP'ʵH̚LmAu9n y8HUdk Dכ#]u Ҹ;#T%YAt:/ #~FU*J-dJ>,]+Yy5Ϧ,GYsp)FX[pwhg!%GD/O8<+n,խ$].9[ \'Q@Ol`KsCfMq"G ]"{,gvqx&60"Y~iDl]kV"j3nz 'sFGZ K})e8#c,+rБ%%Fsʸb9tQPV u?rV8y?2-F1Kw7Z4>$y\Fi.ys%7ip1 3~FHz/"rjRXj~"um ?vYVCD+iq|$`u~g_>/}X|:Ggdd kC'G "bB55XܾfAg Y<=gw[՝pbѐ 8U[HW%vS@aG(\w#'iJ8x{L*3VtG{e.$צ6 lL : %N)kD iWAGjo(ڮ |Ϙ\;H@'ĻdM1PH֠`d# `TN A_"J[atùgI?[9|ap YҦ{Gux uoAJLXd7sHm/}Uf)>2TDՖ&Tw pȵ}N94) V~ٴӓrrL7ԗc]K&eJuġEm-A.qg@i42SHuw:N.Ф_YX-E_ V5zcP !E@yiҁcm>"kVAXZz}A@E|YNΑ5c0X>:z.O+LGh9谛rS3E2CAAڜZO1*)GFˁG3Q#Wd,,wXӊbޮeV;!6^ D[O;FFk,iK}l+|ns{KDTqEz_ly>F/>^א.S#` C~#ȯ˗V 7ph=!pW$5OyŗGRiI͕ 4GiQwh_46F*.=\mVU6b9~ :@P1_2L#^FƱITS 4B1j*=XUNXP_Sf_nGO0n/.yC"5ϲ;u@;F9bTVݐ O6(zf|ߨqfC*lHpBpC2pe Qh,GX {z k*\0g~뺉@OgbP֡YMÞ9Ta|h~2x%zK=}5R̮ `DX?Uhx1va@kUBPrNWm_9-AW=!r_2Rkm&dԖ^vr',ѿ^ke +zOuҟt=x\%0!=jl^{'؛kwD@D: 97b>Urq H=teׇ@ 9A>':gV"K[[?8y334b8یn-)U5 4hhz( #߈e*3mae Jr> dq 4Tk8r׾?SͨwaOf%TLߟrJH{J{a##0PwyA3H9RdcM~F2Xgq\{=pFmix vj:u iG9Zf5Ǹҵ/oگZd9O7,|(q = А`惋_w%/jx9YZC>J}0ɸEc!U{j[e>'4>(ԍi(>Y>_Gb<4ƮeC6FNq5UZzmu naL&N  ~:Nи &յX+\lb0/ F6\,()BૠIpGUw -,kJ7u8SmN`T::<ƼɵW*'@~ g~YSp6&YPnlg C?iDzCiC( t($jѓ82j ÅK )<]C]5g46ߢ6UAv#aMŐMPRʙJM9겕-z,zBN=ib 965 _D\ƭ%4ZMov˹U?уtNmڻNO$Jw,VVuBY9!i*M F/LV+zU1L(BC _[,f3dy跗$+y0sKGe8j7r͏5IݬX^-}E9AZj ľ7:J6Zԣd51u!6%=I_{`:v.W y?mHޣ@sT?&ߞ.{q1Itxt~T/F9F"G`jvY}<}<ؙLZy2R"YАhWQWH3:nWI\|pb!u\w!7qM-L;lHi%{j4Kv<g(,cq/>n.rAkj]Lo$d'dg9w?Y]7w2T&erA_ccRlWqA ͨ@Z#%  tQܮX2zh``W][N Q;\@"Q@l;xm`>웻RpvD8\|Y%ϢVxyA@NՅtFUXV? JBy,Qy'BQkzc`x2#:YZ*]s.xiZ ސ׿pV6-3Ĥ|ef(rtFxٰ̓PX˵bNF f+z[zǘ0ُu7\nm@(tCyX$䔦r`X1ҋ5$jgh6e299I)D^6JFGrtG;w#CۏG= vg8DKΫiV݁!Y ZYZf;\# = f &9ʓu|`&GEJuiVDWKmOzƒFBNK+K#ţ]Ajd`{ UͷCלxۡDHɝW^VDĄIܛ.$\׈woGA'i=/X?2&9^ 늞ʱKw^!7QZ#lقG`c|7ǧK}x.sy2 {mf* rb_"Oq$Qxß_=8hP xP`}S@|jba,-4vrH!K(pQ:.7΄@54~zX/YUCjb,6F]rkEHdb텵'"#o>='p*Uj׭V ˿ A>|k},1y:bڣ?j&P豆c(E!OlXe^|P%PiяʡWX[+8D 𸰼$94{w>Em|U{8Its:oL&.7h$0%&C5`-U1i1DΈGpõV>;H(%rL1ayBȎ]: DAɌ m'YW/pڄ6 0rwwYpHnI"7w6Mtoa?Q+~ kP,o6DAzy?Ƹڎ6Fsz0{L G7j|>}]1 cImn9_= ?Deu/orH8h \gHu|7&)p4rT%36}NƩWc> Wq[Kڼ Ȧ=C2DR@&(|7eFߨ8:\%=׵rBq5[#i$"TR#ChLdD @ByɑmފO}R\ blX; dcX,)ZCp-WMѰNcAP`bCrIA?gtTD=ٿmԸJ8Vqijș߁e4HQJnz ἶYoOrB=SE,|6kpSB2Q[04iZ KgH 4l~-2RCܕYqJg PwU KWĆ-?8|٪ ǫD$^}~eZʠ4?? ៙_P'rQ?M'*[qʞ41ԕ':L|zd(?BL 3[|?6pWW~PhӪ:u=WڳH0p8QK 9 ;X(LהxA+l@|yNϖɻ S?]3XuaHq,ySyT?xD'WPBlbmzIJ>;4zI RVf¯VF?'^js3#%&w$X?j3 0keTz^TseQXf٪ujz 2aR_?By7(RLfP<{ '3#DDMY8at5¥CNɛ46e5qzKܕ1T~Jsk4n_n3p@H7YtB< +toJ<%~oB 76x$'uz Pktj @li(g\DK)0@ 4fi?֍$y$ T>{&j Fֱ(Rq!Ş{/q tdF@nj˪J2ܞ[s h$;2hrJ vʊY bVT)hG캷U[@. uAjED:oZ ]#bЭr UFTN˞,z Sf/ )E|_%+f(i#-FN2 ^$:Q)+3Lj9;A(xvzprg˾a:L7:,K/> xG0^\qjh& pW$f\ZԘ>vʂqCu#O6jd3WQA-`,q"E-!;8[<SMH+0JY}XaRǁ]#7@,2Ox"yYpbDeoz{G@A,DL觶&&e~r8KiocoquFzȘ|^7ڝAj}NBK] `0H׆Ji4Ԝ1}ɋo>Yx9}LJ&{3u3# $_tYbȜġsv6$ZYG#Fޡv6?WNcT C=P=/n` 2l"7ƨD{gD[!uiF!̡Eqsۊ";[d_$IZPTLnJC:.U텝V0[Ok(Z|/nX+!%Zl[L 69amy6-۸&@uem)LjdpUSFt܆-.")ro9[giVoP0Vl>{H4#6]l2lXdFc4V)U+D%  KT:N)šB)թŭKAMolm c|;:'sޢ})+(S1,PXj退}%|'QM2{`>Fw=;nl-yLLlShg\ga"u O7 eyӶM]֘}o, <" )fyw~-}f;e>q]Ɔ\S] xG8M\!JBr'Ld\b>z̴2Dל`Yw)RBQPńiN,hVL[CETSp}O-EBgڄtTB2R1P-K|'3t(|{0'8S(š*Nw8-4 ,l&l ^h}˳i$?/RMKrPß?;KWE@:~屳[dWpېie MMst*3GMʌN;?wl,Ѫo$&󑥁#c\'P^+}禣?j+ˑ B cq*bZBPOŸ8hF|iAT#Pf:W||@|iK,7'z ) Kmac0)o4nщ-m;)U[i~+MwILXX}<+4)s_qs|D@|z <0 ̋Tr֦@ç?;ICaj;c` Heo$֐H3ˏV"-$GΧB& -/=FɾgrߝlqKwmՄm?pRIHyOs!pYWfk Y|UUhctr8VSՌ*$YzƖdjhaFu3~~9u ˀ$l!ZjUb4YX"Okq)808pJd'5vqKxfUhzUT4gL`֘|ر`Hy3kˋyu:0={.>H}~P@H3ɏx~?|>@c}N#v#ZwFJ]>BڦQsɻ*։f>X{O\Mb%lw8v܆U_BA3B`7/pa/Ǯ)-tAYu ;]2EM?ꠢ\W'l E]CJ7ž@+xotglHJ$}FLD~ioyxE UO"e!KEΡi)AG' 5+.R2{ID/0vxذxU_N}njr -7V^(NIj2V8fˑ@bp%sr9Mlu+nIN\ApeDפd۳*aeR_ϣzh>eĖm[oT}.NKK7$ X4s=Bf=`@ da1~X|$B^ 0C dc$F)zWˬ»Q`W %R yCcYڥwMV74Yw:̍Z)ZvQ3 BS][??&57菈)㾅iLB~'KRcu@ߩfSAl]ƂЭS1 ^do,&+yaαb׍'K 9\6u4=j0wRYhT/ 井Ŕ뙹(9JD#Sٷ_Q["vyw񥌄]czmH]-zz*zg ;=n 5il:IEDlTk>" +n=V[DlQם@G%`4cI$^/dD$]综"9}Ȳ!ݮTE>{hXx8oeFܧr1F$H_P6Yx|:5>6qwY2ˎʊ#1&'^f,.'z4.N eŞ5d)B\nd57G{lv? ᪾~~'nq4} ++_ v;$ xI|5(b -<5 rXjh(K7 0Y4{C{ڳ&jG@.>n CGV# F4ng`8SP'IJ76q#?keaq܂6xz^H3)LpX9mMnP f>;eA7|2шz)i( ?'\&۝k$ (Ȱb qZWVC#$* +] ~bxE&hZ.]& ^/!e*leTt`eѹ 7X#je 2ҡs tYEuJ!Gn~]rc6.Ts^ą'f0F8o^chR9α?Fm}r g~=Pu }iZ;5; ;/4K@99(BA=fMˡBױ4BܢVܛACTn%&:ӫ3KۀL?t-ro HO'_Yu4 ,l{q?lWE NjA2hyv)s5Q4Ynwmc&o_Pm2| w?Q;crWƥ;楼t囯v]cڂu$\B*t=HzyyPԺ 業iE%MǨ@;Z{g/iVQj??y}uj4mKqfnpF vAj.(Q  }* 1bM_axf %Lovak>QJBX̢(.I_&A],)ΩAp.h q<%՘_#u҅ۿ nT-$.u׾P.D$aM@&A@$2_hcB@+V o=%}| Y23evo񝝹E , IlhZ-Ȓ>c\7_ H#0M 3-#{g-MU]!|.(Rloy:n8u9X{+qJsK+DX}7\ke/3, ju97K\hHN& Agcu!tK$3:f !!ӹ7-ܭSH]Mg!plu%yļS4ZFͶh z@z`P] Ej鐆J&Wm UIh#=t,fZ1#2 jev7G&7*:#YjgEpWwiB%Ț#hEco/M`x(#qIwզpUUϓq("(-0tA.Ԓs)x>Hm{ 2XauԿI^OG`3eɲNDպ(:\`?T/(-S{ e9^f?5奇EDb fl:ww7sF_hp^ !%@;6F}Z]t˓Am[*:N^M 3ě7ZgUUYga2yEe2_ⓤ>~׍|~Y!)pSe$='Qb %/()VHe:(k; #'_Fv$3jl.)+SUdXt*tfl 8ϰ/f pyhj,ۣ˽HH㼗7ՋݮS raVM$ /㈄,-M:Ib{.gm)UTG\ z!=DnTҪ)c`nPMuDd͛Mu`4OS]?;!n5m Y3M'(&M.Hv/K*G8uFC`c*k{ jjlXrqS=Ƿ;8|>؋_,&1$Q^*2ͽ, ѥEiUf7!/yY)B[ʱjTx*yh3;rfߢ1(*sEjlul_R7QS#RAu.%߂<@8뿕fjgyE% ?0S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPMOa_:,@> ?^Nß| |,@> ̊UK%#T䯘sT/1|PcT5mzrgi:R《y}~mE_$cj%SոbSo1S|î@|wp$[5)[G\|Lt2󯖂LC @gНy]rY6Y'o/K x8yM+b`) ZKgH%GX2Hl,c0HWS$ƜL*#yu2."#$Arv_?s(md>ii5&x2^xDL2L4PQN5xMvNvMH࿘Q:u]T%%tY!yX|nG; X1 !I"ί}39ae^Hk_‡&}RvI;b`3u;{⊲H9*Uv%Y3K_&P\ G]4+D35%P`:|vluC\/; huM.ƝYR|LG=9)fW9X7(CrݬouOB4kU y@IN -9k J,x<4}!W9J{'6o< y)l\*:5H{?=hac"1e$,)#֖S-ק3([QwK6WFҸ+BYGSzW,0iFdآo1TC#A8O3eنpMӗAl&@>pm䨲VT\?BUC{BP$mW%]Q'QHg˒d ݉TyJeHlxK2-fcD0v^dr03(=~K~e>;M/H(}k"Z'P\ +B"@N.ar_o0փ6٫o]rN&ښY)G(:94W!]"E"?x}EZegn2>Vs8a}W D`:мҺ'3}%cs[n pFm{4il΅XT$Q`IjrZA5G.39rRc_M}=+aX ʓ2r~mc6Z$霤- \0:=MsTe1]==ONᶰiЮa[V埛Ĉ͋F3eam`;Y `8l)T~<d p&{{Wd(l:a@F҃{Rk|:O`/?\_]czEظhKnv.d]kç‡n,a 6nTFd uwv[c+~猰=C[M<>Q> ҽ2̗.7T &G!vyG>Yrkuu]2W0\bD.Ug_Jb/an06g$2ps MHbbYwgqa`TZz2WU=p{z7!I؜[N4ǣMHqCk6>C֗&EGַ#b鬁O[Rje^KE_^5} ?v}hI_1n#G D }H`f# JEj6vKvњP(*嵝IlC_ho܈?׭RR6чѰU+ktN_a]d/mD:mZ<6buU>`*I\ q~4@!,J?tE*5 #g0=ˠBH8??,˴&KOYw1 xv>Z{,:6R z =!N9ڎEX:5ތ"rB8t)ܥd"in] M 5qң(:ʓsrMoeח~ )?`܈UOƂmGa}'¼f`+JcTv=ɑ`ȆR%Ry7#vI hwco]Lz_X#3x j*Us {C!r6 Q@~w A1^6X҄ʯLw[m *[wVjճ|:BfY~lXS5vBmH9MNn>7h*m^9vR4Y-Ns_(kJ3C:}ץfLA%/uxy˶OPI~=Ʌƙ!h>\ ĵ@pϞ|^*6~4g:4_iabT⑫I}k^e\nJ]F fQ]8>ĻVtdVToJUm@sm@meU^ŷnTRo\]7=\{쐕Rj6);|vf<RuB#\W .Dp#W%୓ =Rqqozvf?$ T tDaXe}nP /.C<n%ϡ0\0M"Z:+J1V( <(*6=ȕ}Gr4f Z#Jeh}ԀLXq/|VN7MjCu@g@Z;ɉH A5`gf$MW }k{@4.C8*K"eQmH4B>bggF8JY hӁݘ#fd :n#X*x1 l/eܝm]ːE"a7S+IbDz(&Wd+q5N'jT7# Y&hlg7*OJ &t;+򦥝rf l{|Q_t>LRw[Cf^A>DFOO=nGEƟQ853۰b /F4]YHXt܇"0nlv}0|KGTs?GCRhT)Uw Je@V+yaM[f!b|4ff 3־kGtM*l!NHs"E}~%l>W \7TѶP84NHy \z,tB#u1n;8tó߀)sor83~ 7CmOB=yANx}G\ɉHt*%#Ywz{2p@ G6n愈)$thR)?-x.L\ze~\^ ՚YN"KR@Ȱgř}W?E yF>Ne677HCa i[xMgD=(gӐCxj8 '(ü6߰+ƾOGoZ:Wfn洂hlwV D6]/D]TdЀ0||,mR),n5RFEj}A! ru {v}{jw DZ ,RjUHBu=pT+ՠ#n&+rѰ :|N"MA.^ؽ[zw Ŝ(;82Zg+>Lͪ\@bsZڰ)(z"rGTG nb㣽j2]tC٨˼ m.xf]U3yvL;'i"%$EdA#X,sn%+ [.YI1c<ǧ-S| qwȸ=hG v%Drm؞)vju(~O>0=g@R6q_8mbk4%gk $c% UoGIFo j!J XJuȀS>}L|ȤL$ο L(CC|aAU+D PW$~P4sa+ ֏ɘ.D> ;s:檢bw[+Bjb+u'a*H7(?d23KF .B#1]0.r.r|Q--t."r(דtSeW8leW#=u :e,:e# T2t/]yڛ0|ϕ8xP.Іtk#4@|j8(ͅF& QZ"^bC+H%b. 2No^rNmM:@Z%C!pq. $QYTD5<|](yTՏG|B 6.OO+%m5!9elI}',Yȅ;b` ^d0ThHw'֢߇4xh9~˵dhba gTU<2 qkJKUQͤqڎ8rʩAL*> K0VcIqU#OznXZyKª,"Hcz_M DVAəOqKdio1қ_!~kbR n BqF z}+u+j9Sh 9ƀb=].@L/ݚ#T~|U/ F8+)E!*k+ssay9^$ tVҕN!u0&kp!Oae|t4i!}}YswJ N#ʢI1fU =JqgXN/eȡKLh>pyw<跍sɕc΍DK=l-fKm? /?rt[0 ]Z@O+hM8\# H˯OH1UVĘ =XV8a}朧ʺv3g̔>Wt)t1䊯{q>Fy0,Z9veMGN9y\]LUl:Y6bf%dN(~1ĥx,48^I\t{"qǡ8r};40ɩ&0&׷>q +%YLI"65*A7L9ce{lRNiW_6*{y7%k =:`lAHI%BgzWZ\Jlg\~1%9#2f'|!끑 TT(y fB8T|Nr_e 3"7_ ?3^CZ5^Zzuj^!̺w  Ψ:+'HWRRtЮ Gnt%j~Ds6!!+EwdӋ摗c2{0RM -b)=^vގK* ;HXm֫8ZȀ8n0"cVjB 4xҽ#Gn/ }ꉟq׮z4 ;)B] _Onjĸ m$*2NQjl,538?5CReBi7:B2=tU_C'^ Pغ%iN*o1VݡCS@y3BΠ&HwȻ:W 씑tiO@zd&MR8u.nv$PZ5[OUk“^!`J2f242#$8hr&RtE$KdwV!Hx:33N EkIvj \{I3hCN˚vpd$u,+FhQ)휹ROHrg=F?a ?і@&/|2iĚgs&s2W򋘘&4KJqlt@2Vh)b#?ie=з " =eZqv0owAvuᬅgf .NU+D)C׃.Kr$^{6˳*M\A <7o[#IIM3˫v}2(r 0zVnr$<EŚ_gGA~>< /gډ2GͶ2j>1'8bic?(OGaZy@FL 9Baÿ<\)P1pl#5~иP]t  c&G6ˆt^o-}<,'UϙBQvSFsEzl0bă]y.?JٌhS ^+A^94/qKXho_.'B+8 W4AX6?c1kϓOP[.2C(IߨÔ[N3%*be ,1.Pk^B-sc|~J$Z.t1뮋G1tD-C-K|:_'FrbۙkG&\$;KҶ̓ʌ@7b]\Aq8ZUS3 QznxZr`35Wo ~wDMEӇ&ma(]Mmt oCUS$^ =-'$ }\oG09&ۼΜ~XD՛ ФL,(GO[xn /LklI[h޹gBBthꪩt z'76~ed:jڰtk+ `pL/?<[Y]rN }ʸ: /V!L;0tc5xV뵒gZj|r׃hNkEQa_5l*M,f"p[jg&J%kL՝ɑF;[ߏX@b0;٢ql| yoC -lޞ2سˣ%I*^(ZdRe\dC5p@+!YN2CuF3Rf{E;̇XzԓLm#!%Ykh9 cyjAwrR0% Ƒ\b٬#͕JOf)L W}j*\.[{v_V#%q3e>mCă_L ))]qІn|(H**)ZpjSuu,t}R%R!ئ忁DƗn'qpI )x(mUIxs}Eq&]. !W(PNρ8hH8mx`30a:ΰ|0Ơ M /X;κ%ͩ2WzI|D|zؾ?Vۈ_:pI9^8^;汀8*['ۘP[idҲkه87d{NQ_#ȃ%X9M=F· g"񨋪jL#r?I:k_BK֛g|vOumYQ୾(VjkdRc4-+gW@"`kt(?3 :߄7ؚǭ<}Yzý݉?A&,8<I #8_E|I^gLsvgzc WlrL-5%ʘ&ZlBz4gfFĔ^@N0 ǥ4UuCpu? ;R@#H#3JAJ E̐MӠk gEOU_+%FmՅ2KΖ{ufy[;z}sO"f229&*cƫl5A_yka:MљOrm뭡 f gj ʗ.>C$e -ݨah'5X|(v[ko *%E c{͂rs)/9.M(.I$H/! -B'^IZ_] m 'Ǖԏf -| cefԍH8KLUq<ދH0-lkz\p&:݃e~h|/YYfkfͻ1P.h*ti K&ࡁo/t+Bn.<υў[O0dpߨU6# WzKM^8l| I9VjSN'ɍx42@b#(aOyؙcM1z_H#r}Ȱͅ9b&;"CϿ8,4!$\z-Qoo֭ب ft 0;I,hVqdsKSN`wUsS68J6JBWDD9D|{U`8v㥟+9=͹ěg}@ڄ! ]\%jg@Bpi]_cuHuJm"A˧S|$7F<Ɖ6LPfC"M}Y@R,_ . ~I_[HpC;CFɒ.&rZbѷ%Lo`d!̿J sb_vD+@@k!,˦.^tgnw<(bzrXc86Պk# ވ.7j(}w65|Yrو DK-IAbm"5ePA$ "v\1s`|_"/8ׅe9%6ɬ5=Y8=q3B1;?& >rgmbnP7aW}K\:C=:[oRnO-NT!]C; ޚz1(` yi1Km7B!Wz(IMu){59Rb1RNW ~r [q{dmDv7M?i?LStB[i6QgL|k>(*޻B"GK4TB,fRoyAaڤ\Cv N%^6\n\-f<~H/ @fxoΟ}e;<@ob/sBVi/JIs?H&%fAւhp^T̪rߵkڪJL}@,fĪ8-E-C]&͠Mi6*J:I_x5GJ6d! ɾL7M.M_0; }pj5ձȫkGMpoG1`r"51ʫ,}(n3嵽y9ϖ Au]-7Vm ͣZlVd3K,*?Q4;DKl cb{NjPj[Ķj K񺛷kOoR:11s&LGdEM'Jæ4|M/}kO/ h7*@k/[Wo+Jڿ1J!)K9VT/!@KF#[$#♋+bIɠKIH%-i#Sut#L<3Bv닶n@H4r>nf}8M;HzYyɩSIFa^ؓQ*auv97 XA P"#tMV5@_[65&}0=H,>*=e3Zꠉ֖jz&,G$h}3? v͈+b^̜'(ڵ5\cyFީE9D_=I4وq*dW!M !U( ye*0}\1_msYՓ(B 3QIDko2㎇?ݏ]flڱ_xYdjճ穴{PQe*=11X)S#8P.9g>c$=]3Xٌj ze!,L 6_H~(B "YahP*];mu1Y;FU|P''Z[1LrS|19rڔ4TnOHiY2&7,1uUX lyHn CG`Ƞ Ck<9kN#``7&j;7.zbR}q3Qm7`iX?3JN"-8i@XmyiWes~ Dm^PDaS#>*MO^ ƔM.{btx%&xJ;B j+ -e/I[aЯbneWevJnjܖB!wK:>llB;)8ۻ0(viTMU/7 J&(5fd9Ţ_21 I 0?\i)" Fvy:NW& mMIh%aD?q֦ j`=z6 @#]αi+9Ft42S9% G8-9@ ;/8 L$ׂۆ|PKv3STqQzJ Cϒ$ kr/_DaXBX{/ѐcjeg G1CcO٬NIS- vERJU z? nFD"?.hyf@SMe]1L܇Ez%5 ߛI K| = <5GLq'6OCbD 9IiY:z3vה{ kvpSdkOplH`JjQ<{&u_u nDU_%|[.G@4۟{s0P؋@>Sx }CFgh@$5-QmgzPV6)52cdsazF`GnyASS]h݁\"Yʖ5@ߍ2WΟb ˂ 1O)a~Dfs9oUo3μ3Fu(\Oz6E{'dGٍRsաY>8+8T7@9jiqjL^HX&T; ';L۔GOVc@ -"&a㟳SEc)<|}he}ݱ%w'HRl tB|;vCQ&eG5g*NLdy>IM93fcie'T6@dS&z[ja"YV.^ƒGU GvP8QSv9 tSqϮ"(X $/ 1߁AA_oQlea22G729n`:Or$$'jXڼ.ّ- ?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPpqWG?:,8,u|9RfP#c̰ _΃|tR4~-LC ' ˈ!Eo lF?W=YJP|@|w-8!rb~"5U3:!ѝ&OX iC? +tL| (_hk:x$ wϡo{ݺ6uO_bw%X`<\hH/=)hR3Z ৱiVD˖9YA?)v۩!p˿"ME$o_[qdھ둑x$'7b{{S 1`iTaUU~?~,z {tn|i|YH)@Q쁋9c-pSVxBߵQRsŏi A>q^8rMdɸY>|\=r`}}<]Lak3v(aμ1w-@jbYn /5Y]&|:lRsےXhNjGpXjJdQk+X{gNh=Nl k-o|8Vbp͂˴SCYC]Hh7lnfJ3%](ö R؎RoNl!v+*+^|0׽(jvΟ˩R$N)C? lZ]UUB"۹/̟G/r}6vն 5?2uǭ">YrQe //|׾Ũ4ʧ@9U(>6l"BrjUOCTz_헠Il+O{,,!03ÈM'R<} HQ&x('Ewr4:&JWcu@bc+-c@ ʽ%ٵ8a썊ap 3, ˝[𣐹wpk*CMi?8CdF6*u"[D̈Ba ;.sZ$;Psʖ;YZz޷2^B/hK?TRzgi+Gw/<Ꮝ05!#iV򢉳iJbZَUD0O< =7:k[_)m ;h^ɓ@d%{{*jZ&s qXߥ4.57Q+9 ¢I_> |:/[!5E4Z/Q6e 'pUW9ⓓ̂LJWs5 ضZ(DDc泓7bXl)$[c!im#xnb^ǕTI  h3<|x4Lp\]W+ɤY/)}& ŷ:R~ j9;2-d@`_{,Yg9\S;U+TeB-Ә 훗xvӡᰴ_*u]^ț˽k`ռҤ1[x_e/9*_،HLxPWD g1dcᕌuaRaK[͈ HYćg;w/mGyȃW%yB 4䒵S-9mc`ӱV0GU`D^%r幤eָ$E#1)xI%O$$(.dLFy #Q~/}?x,Tw:qžw!+N{-lT2&o%Mո-t? @^bX yطP2@$??RGf';ைe~3\CXh{]u Ҁ5?Gl1 5${ @=Y+А!uL6[}owMCɰjW`=氙)Xl\ 9E/I zM߲<9+ XA 1;~dl{k3@lhX6+1ixk^=F,A;cI9EkVT.UI/j5L[((⸘F`0q{)Ɔn2(iT܇c ZDO\ <'@}89PM*OрUZFM]\ɵ:-(T(=^𝾄 N0͆`Xc*+ief؍'z]DVM;K[XKZ؛g_G ħ/E'qwA0>pr m s9'.$p[ʿ `Gx1Pi: )k][uj`+BV,=ø)B{Y` ]G]BqD]p-ySMNc6Yԕ)p/M;|[Z<'AQMRZӈ~ ^7zpnz ~_Li.IΨzL|Gc4I'^;Ӷ~}d3U_betjSEqULakW~urrla㍗WMՉ]H6<#0 -<vD'_\'xPٗ]!e ǶW2 w^˲զvɘyKYqx>ܦP$wy߃-p׎>:_繴=0:JDݤH \M.'&jr!ָ[4/=Ue0N늺6Nt$<9  xw=ݒqO=NTQd-/ ǹeYEܟF'oOさ.7HkB9?:'{NjL᳁?2(K=;ŗgFF/{R!';k:uB^oŧǫp$Αscԥd?#&·wG3Fѹೋ+BMj?ؿj͹E֨udtƣ.& ).#6.Kj5'ymICzᏩ Tc`f\Apơ||k 7,yΘQhKI-"F-  ZQZii'kz9Ýe>[+o;)N Fa_W5F81axon^V#|p3:Kt\)"pb%\O[AFiтjAŷ'?s*mջ3S8r:֪НQ%_nLh7P(~MYVt s琾#$ެTg c8z{9i9L"ΐ7Jp0[f޸Irz:~J5:q1: 1Adݾw)'u74bO,8U2[oiS-!M.ئǣKLVYdŏ )KrK(O2ȚB>J3l'&~3EK:چ},p*oX1̫]JL gica!|vfZ YOlm~@ѧy{<F+:9?<` nXrndA*a4d,y7`!"`9S}}n)I Y|-ȀõTZ" ̵/H%P?aV2 $.-:d[ڹ%gڼW=t,ָ "%J0 7r-Ta蟒Pom7J;XKs]]zǝnxUk : ma5Zev%hguViU-#$slW~ߥ^ħ igDؠJ8_Jw8e=?(24kt!p5q`}Qt2?y?p@OBv? *9xɪT #SOJ8Nȟ|46!(`4 㺥S0/8+C̜OmwX6{i='zx31p`LWzV}j⟐ztS.19N4&cE'uJ&RBg ;SH"g FGL};0_] {ӡUmnBZ?QHoSo-ے.4߅dRf3S)8]Ȕn i_v7yUm:zE2fǡ߀&N &]?\YǶZG-:?ꌯy^,U#}/9LƷn 8¦D;== T.F."'AE˵t\%/yY(0 emS YkKޙc'-a[b#O{*?CtpɥVHjDz!#G'zH8B* .- w1 #,3BUK%̠/ L3mr׃?;=!,ס[0ؗAc/謞__.Tݓ6*~r3|;橮uz<(R<||@||b@ gbj̩f&30)uʚt_"09~TB-~z,8Ke\楉lU0yxۛ1^TE%>= pb?oqvp-+BުrNЇ_!ʱxMOF*\ՌbVMr*9ݑ\&lD35t j= ˰WN]#?2J[FfKcIAqLQz򳹶YN!30|*Yh#NYdFD^Lo!83 }p>Rq1RHoݏPQ:DZf(*^> W{,x)Ҽ^ўѝy(pY|>2$HX#9V,jI@A^%"भ+KTyˠR[Q4/Nkdh.GNS~du#|>c}pyP׋QT|(5-1 irYMt7[{B0l.f6giF^rJuR*ILEƗ< sVwrp#LʉXAtK=YmY:=#80 N. ̤%~?Y,c1=i GSZ_b &sD1Ijd=zK0qg V<aC*:&9u}haV`` ǩ){`IJ53]W!O `[qF6鹉w=9z@5L|,Ҧcך[%%*Dy5f7s8ҡs#GuBX3mv@C7:a"9JgIؠc.UPSyq/8KQgC%%9[yi^]ϭOz3pҚA&eMxVIrڗ &h&oSgevj:DS^1[$0z=aoyj1aG[sB/'-l_ɘF[d5"'0p+?2:"miJ&Qz/SO' +T[X]29uI\ޓ%EЍgʁHݩI6}zJ@(]UK&rHvzoPUxp )?eqrx%;{zū&0+Ăoz?>*Z*bl(W&x=sfxx"G_tVZL1 j#U\FG!ᆎh:XAT2N!x $'f );e?A k$WU:\?愡a*O,Ֆb+ pDND_:-4StZ[lӄ> ~ ܞF`Xў10-g}3\^2! 7 C2ef\ V:L|r:Paw+?g+׆?<@FgKɌ2dmI />xc/?1m#o}qK+>΁5A/rN:Vucˠ;(!}A)R C_!=g:ߩ?wWxjaԍ/2j ~*; ͞txc$2)lnP/Ʉ Nz^C/b]My3Ӯ[j5 HL cKiw_Q_-*j̹ &i-9l@;1]O^\YXYs]X~?oޒ&'I&QUG&~NcӮ=N9â2UZOX"ˮ:%%T{FUYD 8 GwAb*a.}jh %qV?ВGc!6b*uQj58m7٬w(RNZS=xx='6X%ݔ4&22}\4iBZFx̤d YJԗx}FuodGHmþw꒥\/qkjYEKH84G [̣Rv ̣8o6tEY: ,X*)8g.]jhR>L70}UqZ+iiA35)Eu%ޭtVaQWL|FU36m)zn-fw!@v1eWfwoՀV8>%wVwdnB߂ZBe{)3b~Dy &^x6/`Xcl}Y/% ?&FEA!Fzƶ@[˴+mYcV[F%Zq#NTt,6zG߶4!޴Q]g܊n}U9LZ+9`ep#Kl1rNhOYpBWuJFv,sHL R@tsRFV 9/Y|B^pdCQ~u;j&YeB(| ["?մx׬<1ُ-ˌhlwkب8Zg45N)mDrvH9]^ 0SĊ~aᏼsݗGqW{NM 1C1}{ׂRauJGϜО*M GX'!i;?Ĥ.4VЬ6ʖjk L677\5`'(%Q62\.Z2Bx7"kiU}Wim_V 1lFF1:=" Ӆ8QaGBuMCilB_ro󀡻:I<XΦYb_R0#j(}Zo&C&dC+9QX}g5Qx3D34RB3X ~*lEKIqGnj S/DLUɁ_ōoMiȜz3r=Ѯkuy,0!EgYOJǛlk&p厴Gtȼǒ$DkIE¢[X9Kd.q{2>GZn|Őj0Fw/m1iWVB^ QC>篣7 CGݿ K2x{>K.:k`$'$gg|pA:Ǘ^6HlmU5XCTS5"+FЛ?R )ƷdgcacS"uzPf;}(L4 _f@ōZ QޜZq~yRx$o9:Q[Q{=F|ÆAKuH mp7B ڞlAF87 pOPhB5I0FW~yuYF|^yԴO_XbnJaw(Wf&X0" j<آ%u>[wCfqYUS2M0g^{h/ ;h;%a&7±eJ $2nJҍ㖈iTmG$SL-h Q1xQ~^G S'R`]p \.ˬ›FplV(,ґfI7HlqȐFό"zE!pȭ1aUgM{PJk>lX0EJ^9/ 닥X۴.c)tZ'dX>gY<1*Ӥ5h/*I6 "',ߑ͡5`yU$XE1ڿq3,S\L/!1񗞻n7uDO$E,A(?ն54'V!tfPؐ6!s6A., M׵?_BB-|^Gy6z= 0}RcG4w"6 `a䫱S$: Ke`38qhzDK Z񨁦PYVH,-UL {̥bZ&c俦[ ?}gO#}G0u[dRL37韈PB%7|@8xPX X:FY| @|i# E[['hfbV;3z!?+Ѥ[SNɪn;aCd>&biX&3z7kaJ>H5*j(|ʚph%V$V%$tqX]!b Ľ01U8ixe+GVҸtjЃ @ *5WGV|0bZψ=U^t/$ QDzx^H?O~M,b,&2,\.6 [EҀ63 r_o(K}bTg:.)"ŔW&vvVPrF3{ɵjxZw?Gu#bX3g@]*V >Oj/r7Y딩w(\$.VJ.5~N{gIư¶ ȹk:mERKUW˦t^/!q2np;qIA^̓'}gj~n tbT\$ӡ{X(̼%*8k}Y~ؚɿ#0[!opD5Tꔸ[f(Avo!}G`Y|D#.qizꄢm{jpWC G Y#LbU^C;)~?0"-V qrJuH-O &΀w qX/ɶ۔嚘܄JEpl7H @}ĕcz^y72:HU͉oA#*"T $-eu!MYq(\bN‘o,OO$ibTnBv>H6^)Kz5;A[y{ihLcQƆ*Z´F]D_J?E`L/7X<\Č'E눧`wxk_ NXw#_PwMZRx_:=-e I/54vl&Cl4Ii89Ly=t!W< Bv"wSECJD^9bY 7xԕpQ.X= K0֝Xn&%RV8':l~̌L0@\x˟LNz!>{B0odԲ:_8B0 sX, DMh?Y{=j9mL(կ ͤמ t5U\ݾ|~9;hDkmCcNCYz? } L 8 $fu}Ϻa3!K7F,H{*)y@z2 -X'9o{yK\ q+ R/.{@}9POocqEe\ڤRyɤH?~0'CfGuoæ~8xRĘSyA#$P>%]aeꂈ Fٲ *GkUrH\_!@"I]&7@m0}Ies-z+oP5GdsC75_F9wA(ÁW@1>ȪX~D樂W _af앀;Ŀ:Hjdv(bYF7| άDڌYǍջXmZ\"$u@Fig 8vhn3g1o&M{$FgnΝ6dk1jϙbHH˨PR: uG/ٜ Eɇ.na1 ~MX.-Q &K5pO6Dp[0w%C 4יgS 6IATtp?THTEb[Q;cY~ R{uxOOy]\5)l SIGև6Xv+ܳX|j[5.(,AbPT_(2yo6u6 &8 yrr]3a M0><6G ><6 v/2H^{봹K@^5~aQYJOsF,;xֲg\c!_oR6Rv(G\1A@i-vӑjN6))tG'PbdX|0~'6lq7dzbv^^wzjӟ禎n_k;O~et;|! ܓ FW :ia]圈͌7㽯CdW"!A)Rr~<TgI`i0 %q4Oſװ׋yz姀U $e(@y*̠g.6KHtwɩ3s$]9F.;m7#oN5JG=ݎT݃~~~ z[[Dj:gU.n8_\"ed*XZA ~ Ap$9I%mEojsT1CCrs_7Mp4i.uJj̏g?ѸG錚 O҆6f*3-#Tz3 O,ȿψ 3b$$cQvkuaS-Oj 8M5 28Y异Om#y2 Z[[Eҩo !Kor1ޭ.TSU$0o5ŵ+,IY仡KaǤݘc[[~H>\m/ҕ39Zat9bjfc:UeJ=+"P; i*bA#% J"W=`Vu!PeGQb@zCߥuGciʹ'J0͋X]cHN<)ͯ񈣽x!c΃n$RvHE8k (KwiSOԞQX4` .փRN;0|D)M{ b2%`!= V[v^T.kZ5p1RNA l|[5Wc=lHC>&đ!#)[b x,bjM\<-Aä#6P?̪{[T@'uIF#(B Wڷl.6*P8@b.\~ftAZtHA΃^53vSXy#M|G<`AWucOCO TF**dMY }΀䖮Qʄ_i֞Ƙ< 7]^e'KvSu9GEgH`|.M[-{ FcVsF!!,EKIjeגPZ`ቜ .@2C+7uYH)r;TZ ->~{ZxIxf=$*N\ouˀB_Z#`7#U= # &+ @d‚!"1K מȅ†|^a|l1IQK9z)*@RSsA g"騥%VJ)'OJlsQohW ο@ rCtFcVh ) vJfFX|"tVXCs p=;e.?Y;nڳbE32H ~'!Sj<&0YCFvm(j[z keI-J6T圼0Ysz_`夲mA#I]G)9q9S5RHeݡ˟x! 8&ENDsTсâ8Wnj ^Z0!ctnuu*\vMjWTЌDK'ɜ8q sJr+6T'a=݆ayz{fwPIQC#,Sqsv 'ՀF7~4xY*DCer]ҟߚo\$:ո'|iVC㮷 B5*d8pzxdHN/Qmu^{E ?3.g:?B\}w꡵8 ,FmӜ_0 #)"@HYS&Gslyλ-樯-K#xC l|3XX()l' 9u'|;UK_4S)c֨>f™@d;Ӟ RAlr/Da_ lIkz,F@< 젻Ϩ{utqB"0 0;+L{y/i.n#ޮQ:3BN?C\EAd)?[odPwZY0-"!Q<a\h`xKM}rGTd |k=vTX~Qi|P}Gy(:Vyc=ZD͑3EtE XmKc}7$/ $$I=gf ?۷M|!  24rˮ ]n!Ry_\|\zŝ4ĒgFHbe6Ac,\H )woܦJcly=QfR/ -nvd =#Eb[,ʖhv9Dꗑ^:aHsFA CPx. Y=_>xoWTZ:ma+ԫw.L rYISYH Ғ{'"y;ǒ bm`-s(ZZҹylվYI3Vc8=1DO %3gF6ᥛڵ <5`Pg^5TMcojVdrn~7T60:\Si8Flw|Dy:C$=d_?վ;kTGZ$} "2 P'D?!gC3rH.OQ]&VV0G8Sk\v8Uc yIZ_9*`Zpհ9S>|5~C$M^6 ҝѴ}pŌ5"ѦXO-`wUkSjf \ qO`ٮ~c[)1b 5=! 0o޹U&Yuƚ :eƳèLZDfy727b~Lm6bQ{joYq e$2(!c=մh:^v{e,T19 =$MP_prۭx"i>X㸬c=7|/b<7!O"QfRmg}d2YJdz uQC͂+=+MXFٸLBHjAOpu6o}ݼ-5YK`O]՗.~ f/Mf%74嬆Kns1JϙG)N, $U-$$8I>h\.ooಀo[~;C/"bgϮŏ! $PZOHWvXj𹙈' ]< !~2If }1˿ tPn-uE+>׵V!X}5'NA5T T`D{6 JX2NJ"pM@#8R٧?+vS "hct"d µlM4SEjo[dF&i ,$>Jt;P;Ɛu b(7k{~ cZUj/Έxh+殢6 k8۸emas]HSi,2e3.Q0`z2^if ?Z{L[Pނ׻o7Q8\YxoiKn%{ Px΁v9%_Sӽ aL`C U2§B{q/jlݺkPw+XYH^@vxM/=|hYMK~U+ɌLQnb-iҮTu[p!Dvo#>PYb\zqm3 Kp8WE|葨ЕN".R!ȝ3}I$SۙŘز$6ƣ$7$|ʚգ "wq_aۉ>Uy(j$gMIčZCO5M1*݂yˇЦeS19i7I%Q3Xz7ȑ΍$Q/sѹ-R 0tMv'9OLfcmMƩG6hrg`A_a\9fQ(385:)\e=aMs # /ĵ,r}%^Ɣ(퓅c R@;Mlڄz\|}[G\4\wnG3oѾȥe-$Kޙ.k&$i7`LvyL16(dpQfч<ӧjį)ӬBxNp\uۉ f!{bFy 9,2 XZ1H |K;}zIHή{eVCK //8nN7=L1>n{b$VgV "3|I /%{0lk @Ƽ^[G!I:"HUЛ/41_;ЦnZ8"8B#WAk3Hd@i 1 FX=Psjˑя2%[۞ڻ~k9ZeUT3nL'џ6_WС؛B "-.spq $ƔWoul`siNI K!5ި|-JZrp%/ڪ%]/`Wތ7b:KBŜSY[3Yr,`eE+ rHLf3p>9Cܓ3 .Q %Y۪c&I(ҥ-)oIZrjt?ݢЅR68deo#._ s>=|B_0ڀ9˼>d䏇;d|zԃNtYɑ]>P~G/^/*:ӷ,/M\}Lg$<#]~(>z-;S}Ame曢P]ZJ>NNK5c,')E$$@

,cP?><w>oWmvVHz8\ q\Rܽ/p\ |n"TdLqšH[M)ZZSEA02y(橒V,`xRTɑXdEz979ؠVmn^B뎠_C!S*^z9q!z/woOSMoCed.i i2xWIOts 7;{azƴ?n_W5R/Ab^0UU0#˧hZ"82n,v4!yg]rѲ`KzZ-~q*BwҷR 9҆z.zW}> }2Ds^Y qЍάW[*Z1FZRh\^>~e\4r: _Lr/(ob$f[H>e>_Be(mJ|U"EL; (`Q1B"~o/CD !j 2)lg։N(Vo2#fξҟpKQY$QtUH{52H5g5N%"9x9Ϲu"m5Q@4! f .J9o1e=5#&7W}Pė_zTvzg[׹R 'g⍿x6d(%F @Oŭ!ek#rSO~F|gJyu t2{H,hT:W td6"䩦%bu6}h60Ϣ5lg[׮熯o_9j27Xe8f)K{O mVP69D!gژsW$C3 .4]XɰO {C|6=4#Ͼj,WnKUյȫ>..ަR/M65f|,@=0+Jc [pr_1a'Vhᢹt!+Y;@Ԛ¤H;yJ>2Aws% .#& _.̀.CPn!jCSRevd<ޛjp5uEmHkG-jѫZ 5k炙EjH.iiUbwdlZnK{xFksuvg4BD୬?Kixg %^!{ iJcoͿ@33u$۫Z"䙸G 2Š(3կ"›K_Ul@)׺ -LvR ,V*1_|hbOz.-:q6j9,.)1zw/dQ1s`pmA!qx ՚t) r@0" d瘫|˞#¨j ʽGw2ĈZLwPѷBޓOV#pS*-NBXDBOFx߲qyM-Q t9/aCW+2AWxoMhVK3YlO+W C}fx F.*ث U2Ʉ L̳Ocq:%s?l9MX~ZߠR̢Jtx%!ڶO"){{&ahdkW&:nvK+S")/ONs͗>޻>DX?6֭4SGyf8붚"87&QE|M2o(?KcAݫԐKaDfh%Q&u.BkSҐ2&ә8I?F;WO SÍt`y0CD?RQ-TOT@Z?yQSxa!<=U.W0ՐjR*tOBH˜F9آ2',ziz>EJ:^1ԯJ:(5J#~`6Mi@0!Uj=LE聝{/M&] 0:K\".cWWþb=`!J xHS\|8>3.FWү^ތzǞ8AsGy룙~I2,UKmmrf`DuvXs !-z:O%quF~n-c%SG[( c';~DA&!SpJ T6F8 _g*Y6y3#AuyM 0Zq#E6ՄuVM@+v0U$!h4嗚&½rf8W׎WSK_<$*61mXTM=:ijGϳ1f5'5CFA b>GXߋ$Fe n:WPtPAb)ay~ǣ?=qŊùK? x^k3XW *R3KɣiUѮa WL@CHJeS[&45AҀ\`].gaE1V?F,ӻ}hZOpQەH w}V깑ޡ]^Ǥcc3nF)/P"3fwsNT!E"dUn$<]q4&N,c|mMơr-$C[ڥ}7uwzH$r PӠ)wTF[2ugȬN*U8,,RZ)Pgsst zG+u0k#ݳ&8<8y ;}%~%$nmgvG|e٢ڰ ÑF OBK3|vᢙq&N^Ek43uϔ:"sHA 2-6jPZ)]3G>$1;oHa c9[Xa)K{FG+DaZ [׻!l~nK̠#bH~p.\ ۻir <^);t{*fs. k!cG7l5&.S+j2L0[Ҳ[A SS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP"O8HB8@1oU)8 T{T)9:_iUz6?߅pBAqm08i3mW/ Yԩ"$2leAŒpZ~.拍o-'Miv/y[*تcH# X*(eg<$GYjl]"||uZ6I69do+0:qF?6 ҿ%0ܟ:Ku'+\dX"W+fǭϨ a&{C[ʎ'V#ae2$]gJFKWs(0 FY~j1t͝i+ɵ,=4DP(| ]Q7R?U5=W ޗfW!r~UK*GMd5Z?ͥs=sIӋ4vhL ;"H)Jiƽ.ljE$"ЉUZ !8hB`&|B!-`,~ȱIwE5RxKΫ|l'VV+-s5:Q7L Su O>pp 4'VXr' LUJsz&rJ-Cfڮ[vIZa 5:nf eIk岹K΁\Tpnj.;q}Elw>4򑠗 .Đ-EPaEH+x훻#$_h9 o#/)i qˋ PHT2=: >$s&\ϛ-)@ 95p,?jN H4p']ur<wŒ_xܢt%(ݼ_mDڵ>y{X襠A+n,bވi9:爧6}e7qfըb\^<yKBă?@HݺG|v--؇/_9XVɿY6/uVcѻ :WM;Ew"0ҦO-yN."QUYGsI#qQ@<քn'Ѭn7ʐx`Z|.0|Ix6O`^jMs^3ÿO!#GPa݊Cca:8L}gZ?{2EjdHpGR'#d=@K:쎳|_NYH4Ъ h?G[dvGXD$ci)DyYŧySr S̥^G_ x@iZd y@+ɂ{GŒ,0 )L[NẶh2K;U)2ɦ运3Ց\᫑LD%xD:7KO\N3d{$gwT"͍IWߵnf_"aGڥ4Ql顄uI4"Y"Ge0UZt` RʙFD鰊)KM\| ,2h[v ˯v#}OAy,R, u7 '_PIkۏ!/2Ai=5!iLc\9M~Bea}Qg7|'u;pn*Ӭy`\Xΰ8egU?L6iR ڔԹJ7n ׵0o?x`c[|TRmصW?U"$0(CFڜT *M!61 &%s$ Eبl»H-&̝h% 7D[j<z ™9[PYl±a>lD}y)c&! k Ȥ˽^CMv3P[룺%RR@nű-U5[,tw!x,(nj|V*r|"t"7Ѧ]9+!숺Rr2%X,YC 47Fx .j/1$"H҈K"t"xn, ߆,Gc|i/m`52aiڣ:O-gҬX<: ũ{.UVB01`Vrɷ!e#=O{[G0 E |Fa\A]|r ^R|@|a%M`FZ|@a=m}ĭb $ cT x??ipFoŔs$ES<n;5/+(q( ޸VV η=ΰGຟ(bl;9W\X_ FO.\f[yK '<̐&$3?.*BHSILQ+IFKo0jU0}D &>t+??0?KhdA"~#~8inаav/ں][- E`͟MEkLRfD oٞlEq6-ARjw!oNEdaJo-\Pi. $MiK?/Dl)dlݐRGS:S;ńt aOQXg/FP{9'?ƕܦ ޟ< a60ЂLַCIDݖnY < 7_b])PbZ4fRk)Q&F ௒i|{p̧(z7 |H`?^™YuydwlF:8=t~@ssf`+7`L0*/u󥰔n=AX5RЍ"f;.S/QmqV.y>9EgF ʢyօj>@RwG-LR~~gհ#S n"RCT#8L5\&J |e|G@G͞(%my7Z>9Qh֤GP zj(@Oü dUrnFs&IRdˬXtXhZwG0ޖ$}cZ]va1=rȅ<a[z5@Z^44ЎASռzobe^h3^U{kAMhC+o{W%LQʛaG,\zԬ3lv5,TR?7fbg5è%uh`vli11}?(=fq( :N&r[ 墹fIu\` U0mclP`j7 1ְ|?UA+YFOQj1S>ԅ4?/;Ěؾ Bnl'rK ]z5k{šQIDsM_ iSZ߷Uf,LCݿd0u\h_ƖiiV )+'KD8@hx5s<Y3fTJf0|DR7{MUW޳N>8uYqZϐhΠC]OTGM_cX}gEivL=9/yB{/WՏHZrWIKCMaբ=a:Љx{) 1~+ Q' k?*"+p$:LO}i @8?L#uٲR"~AކGЫpi]rΛ$;=S$ۦW QZfu|:ǀ[C=mUXd=& _pO*i5 K%Z~GƙQƆtaƂ|rF^Ϭ4.mMd#<]JA~cI:bi56FS_D|љ*cq{~gk0t+gyv8d>Hdn.葔|;vI94F7l"S};^W͸]+T33W{5Mn|s t!Iѹ 3U\k,uJsË 7ʐZЈ۽?2~-Sܝ9#DfXie$CÛ I2M_q:L 1+R6<Եり +fjfg&7unYM㒢>3j~3_&'`~cƌxsWO][؂YP'o ҩRa<  *5V%+ |2C5v pc H<)uJc_ =g'|lvN$<5(:cr [.O_DLuc!OD.lx? 0?W߰á~ 5_-ܘ{eSO= HOsPWT퉶])~X-Q{P4v8ھW_9pZdh ,)~jM? gDae5{j)(+K+Bo ,n":T  JUooHUe╷g=L_8M=W¥E*DSErcΒmlfQf4iq s1G{*C2mOto$Z%2U϶w c|S7Pz\B=ܮS?]|;t3qXX@ͽ4+AUzvO}vCLls\ȑ֯vœUp*OGzR.33_K5#%ظճdHbӷ&ɓd2nHW3M$|F A1p8@D{}Ky8' R|i"LtѸ'&ĎEwQD$V7 J$E={} t v(UijƱZawLqk8t7 ?sXqccDtarrMJ6󿙳edCC7q|q렀)*j.bMn|;&8/#[Ōy{X7tva+bÈC`) %XjLk6OyTOqAѓ 91+hPikO#EٴPܠ(D8oT/OY63Lpv.24I|FVQ}-0!˱!;U-ҀLxz _Tc{T lx/"(QҶ;dHgo]&oVs>bFAjL-V>t쀖^{ʯܕwW”L&|smgW0 6z?$" 磈2*{\~ڋ;y*grRG\ɼwƮR,_Xq!j_ #+[IwՀ@i!Xy{yJrȨ!%^]gu1eF))V=qF?1d#D_{]GV'c 'hmH.LIῪ{FcZ(z_֜|Notխ"pBXG,Y!\>V ԶICv.k<6ɼΥ͗yg+DI6T3ffRdtQwǷ X.5q\x$Z#\ {Yv(}m6cQk:0Ee1zQ-Gh(y/"K;lMU_>2ttxr}+9^f9EZvyH|F!YFb5'J'Ʈ" =PFfa;4_y:Ipjڙ`C5~xi̟m!FT .[:L*~9Ҹ!Il8‹LTwӪOޠi#.,s44Jsf4jeB j ~\<Ŵ 拸,L (GCD -B{I{TMu!yCh0(fp(!V*}չ3tڽd/|;u`$NlSamnHzVةOZ$c+-ZZ$99Zs "Jq v _6 1PV !EܥwJ8h"zVx˛ `*e4fIu,cmCY@BXU@}leҪ.{StF(66@o6N}%CW(PP m\:y 7"TbQGOɪ0&Il\vJ NgȈ"ٱO`IO֐#ў9pWoZ>;wMFkRUG1ht_ .O})mEcj41_ݧ6{HPa{oX$Ia8?W!ȕ?gB6WҀu@2yHuv8 cYTλ&ܮ'Hٹ,"atJوW>C XJKwk#ۨv h񕲧@rE|Wtk(HBam+!< 4 (qewGׁR*dC8bX#S.k H^)-+"lȬ)qp a\uqekRu[\;78MmS<&kI׶0IOSv,:ZBi]]M\}c1E|uR(yF(Ja~-Ul h퉇4vtHN`k?}&ݫs#X;NasoIҧ(Mކz%XN -qL=Nk#}+͍l-FOAuSmϐKw\@itw1wq/ֶ`/c %sR0_'e;MLPnz['t$ |7v?~9Ԡ >zO$I/]SY6 @_R_[I[iC?"P e X:/O( Mxn̮{2]hSE,y˿NeA1)DȧD/%\{N?>ɤ–1'/1^,+iN&3ڦxX YY)3~=&`v%?Z1U0g AiI{r}*WNgR (>Su a=!O01X3Z),rcrgQ MrMipYX٢wA6ۭGP:3QCp1`wͱwxYh^HFFR_ɘgQ# ÚR;{´{#.kkF!#e2tTى)= UƋs=ՉB%/JQsG܄l5R5 ]kraQbUe_=zp>s@"t\F, &CZ]Q8>n^ E8@<}66{{(Up0ּ.x&tSM8Oێ2m쟃\[N#8.Ei^[s`_nf7#/{s-<OZhrjKŊͭ|g/lbU#ݬqޢt}e4T~}e_E*1~# ]iEo gzYR:œ9qmrlt_E9srMzC=xS Gf oj==tnl2jdiN?8Tr (rvW|Cy9|@)3p$WUdiәķxi" *ۤV2qi |"l/oNVKNUb 1Kr)9?rU bn7͌.`_4eR$u%QfLw.R|Q2fS'~,y?v $G:>XTM5vŏhQ`7a߹^Vqlf# 塐RR{ccH>x O37y(qel\2\`Y =O`Gj ~͎ v1dI,܇~,#QAumjcvXVl/rirza.KhoL݊jgH:#N(1h  nuPf7yĺKiS߹IЯ='mgK#܍ӷ1Cqܞ-`oAlfTl e۪~Ѷd5n*/޾[͛Lޜk_!Ѥ(^N FM*WU-C|.q DGmG\0E0kQ+)A|1.iO  c{8Ud }Μ {aL;mҶwqn; M|*шyp~N/0K{]ۚl`C1R*ja'_.ۂXEA@}N.bI}ݚ{^U9"Z2tޕ >%(')frj[?Au؅ uyowg\pgCk'GHka+4VL }bůy1#|ׇ$EԿ([J쥦*cOB)7^ǤW[!ŖڂhPE4J!O;e{>ع݈ G<&x uYz;_Nq62e׀ d eߖ_m&WpHOЏA5i3fx!U?f:"Ğd)PVBK~"A%Y EڞLD+91E$"_uåJ\ž2Q$&Ko,RT^CpCZImjHi߾?ma61ܴ Ϊ z<)dM1\7e#!`QSE8rug%.fHlv(&./TSIB{ґ &"&FiWGMvVO&V'VZA I!iQ`_2\z24e݄I>[;1n Kk\ RKr'jm*31p8%udV). M.kmküDfw(*:KZL殥mV4gsh[-BFh(FD`xm%k CF5L]@+K $(ރsaLJ@?ζG=gܩ{g%\1ͫ/!PYRΜ [2Zrfd=ǽu|0{$o~ۣ۶UlFO{=М;pWa9VyPLdx pdtgy>۳RKR]v"4SN>irdgI5j3m2U~A5P AW嘓Jx´q[~4י+]}a ڼ:;^RR&roW) {C.T R݂1$6(BD\TCKN-vH/>)]SQ홎ERE*ICGEo_7F,:n1B̅sgb|0[%W[N9|6=u&f댧 éP3tR?3Е\J,Ӥ#OWCEj2ͮ񡮂KW;;̌82]o/;NM~[|S.& ~WwO"sR\>e;=E|ӧ̜]W%~XIzlsبbRHW.K*-9kZm#M EvmLhV(=,u6C;Z, mh;!⌥sʼn _( :%}P~)]'VUA籗擮_ l (”Sa,H8i3`V+MIqkqgv;]Ck? ߇< G'[>bƔk|Z()=, 5癢EZtwVN%I=).2sOXQT- 6s;P$kDf N:Bn)}4[0kq.J1]:{cϲ~d 05ϙN^i*@8'-Z6+n_yT8Bz~@ɉV @[(@S"'h\Ǡ<~j4e{|)ɡ!=)\-^լ[ho!Q[-\q$:\,7oMh#SѢ4j+-1lZOyl @ฯ zC ɭ1fv !U}R物l^1WQvj9kSF+XaLw|`-;jm*O9& 3(ȆQZt,ߧ}|"PCk|Xp%[?&;0Q QL6X{Nm_qk2'> MA;Sù4d:22Sl7 &rʁ:niYK]7h\S%(؞} =p,u,szYc 06v 鬦/o!e ▸px:#ѻil,܏1~LILq4WgJnDU]]Y[53[6٣c0+SS핚gf}$Ŭɮ@ho,P^ˌ̽`@lB ^3TPډmmoP[Ҿq#~֢hJOeYUUBX8 -xRNB^yRP4u0m07z#E&^k#N!AwV!{ˊ0bZ'kz 4;Gnq@Xao%uR F/Tvt{5x!GR*}q,N@'XT! u0ײ{7Ծ-_>TO;ϙyB!1җ`p^Ζ^j%m[/wR#xXw/ؠ.EMHp]lBUL ?0AƢHFlRbL*\njR.G'jMpCsdHOxLنrh֧@Yg{[b$E6^G r/Pc ̨M)pi0=o;Hnt$0'CmOe0}0]n{fn)#̦a[Bn$Hp>y9g@D5OAsO})fHއ(jf)ޯq:yc /,xXt33g-T, >)k"}XGX~qP)'^}ċc^4a|`QN0+RGaPJT͈%15r~d#r!6vBErO-:p\# Nb4v=֕ y,,E]Vyeu~lL&>c7"!6aF/-_䠧(|q] yYX`W+S$c2*ɉ|j cdO FcV9_;u+ uoU_$X4DXE^i|x _1$a;@npWn '˵t疩 K؆gY^]ܵW,v86.n8uNc:3Hhׅ ę3=5R6:@VisKu71aOp< &W%Dz!/~"]2'p}zȪtbϨFq7$b [@zv1@35S|}K:E -),?y#R%s),`4YFZQ|$T?*J ]OdO8xPVoך;dw/|Ơ70w d0.09@Ch]sgɤ(+8fə.tj`Hm}=I8]A/ƵC"J6hfW7'?_/r`r9_?p8eKY;6\O&0,&5fߛUAF%Vs3z BmOr0MR4";N(R0Z> L_Ħ8qDؙOG ٩V+X&x 3;:gtcOʵh4 |DKY;SR#2Rb,M R*Hh/ (4T %Im y)Ū L'<#uE\K$NΥ?{!X-Л/wM3i;7=fqm_oBaF$JX:Z终N\9H$薖MQ2\Fνd&RYaE -x:gVJNua/-᫆ffXbaYcv9MLk@`A^}E ĠDS>*N%2d|И݃BOgzX6RWwO0@0cWDD/-b<=`Xy-i%. q̻ٓô#]bQ5v^jq{)) o}8%Sn+"b`$ȾL_ԯ)m"W +HW@ k>Wq06N}eZ\YL'GL !߆ud߻v yOwn8xfH]b>3ǭC(s!' )UI0Wmq1 Wc|qn0Ug N8GO Be1Q4{l WZNKKКN(7JJEW5kFQYbhߔ $Hx`ƨg86&uxAzaX=oeH >Z.~?i?8 &9M{!(Y{]6ߕDlȔ;<9$KGT7uꤍljakضj7@٭Ͱھ Ɨ1KT&ƲS.  _< ɩŵ0a%kwKXGVy;:G#:M5}01]Ԅ̃ ruS=' W\e#Т̹K9X6n l'J|'e$Gʯ߈Bro}aKZTf>HM9%Z[at4A1-Cn{T"%t@x);5nлߨ]gWVvOzNx6F:ZR}9UWaJ88)9h޿s?6G$%cx"q&5(E5f{LQ0sb:4\JMy8Y3M情8y${e˽A2FI{@{2hLÒuϬv(q ߿`-x\tG*/^srC_x|}CeEsR*"euXw#vXtEUF 37W`zyAQ|ÛX>N  ZmN[bUs4[;49l',,^rbT] &gWNW`Y˃!T|fh9 {epm- %ۆ\IbWws&4jôpgbQ_HB;r~IZ_ 鵵$5*sf 1)g1\ƿS|Z[OPߚkIT|;PM3s[L3+CX墌7=Ms"kGha6 K $swF.h Ur.[&ƏF\E5Sեhi t>D-vԉM6m`(Wؾo_DJ8ju4 [4.[*k,B>g˅@' )5 +;ʌ29͗xJfd[:%aYuaGvA/@Ln{"^~dp1Q8z;Ӥhr&+[)Zր,o}(tGy?]\יs&YlPH`6ڮ1nitLuyf/ͥHUH΋sO2:{ig`x np׺A\lE^p}gpqrF8&) V~;Av"36L·7 ӃO#Sg%zl=neQlP-Vv|7JygN˽݄5l(]iq,$LvRyRx<0[`@CPGxΨ! X(Gk.Gm928 M|n]uo7!3\9WjvuIˣ|2hCCD_9g6bR8gЋۀRp<_0׋Xn람dt'ŀxY! |i4CwID{ovk:-Hh%e>Vgp"/œA{"Mμ6E\8 sXIm@, 1L.b+?x#M>Ҝ],fh8\FZ&"À+@W 1hJZ@ ˷z_NeB߫0I,<*ZSJz,Ϟo}A,0sݮkE!;Γl2ea];I' t 냑X6 Ssl>u7\ïaDѫ-{^tZq6-0 +z:^N#IBߍd鮿맙&@?_hI!L ƈi:Wz ~NJʭ9HH 5{F"W YtKeo8lXCQQ+$x$$C<1M,E7KF`$@t\PY<<=Ǐtb]H' z`}#1P4jQ)F riRj Yg}mdSnF ߁ErT 07Up[Fc/\2ӦۍM_\gX I ԝCEv7edz ]$\\[5"WFl-T5\,(JE)U?筕VWM⼈,I 5* *7˃,wy &lQu dޯ$ Nj:dc q3UC nFohE19% BrD]jw= #MIRq/FU|35+n-4x}IZ e{N>e1Sy-9O]bNZ}C<1NRq-0B?;. 3 P&-n^UR}:Ho:k]WYNꠉ*x%~&!qt<1`W &CD!Ͽ4fˁd 89Cu}=YBQ U?&S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPlu?͘8G8pI}ĩo%9V  Ve`;jhu˾$gk[ = 0L|qƽΛy=ȶU⥁-r"@\>ToA|57 7D郏"ޡ~g Y;hg jيIka}ѼwwSLfSQU"}FQ ЙB͓)6e -*%wr V}-/!c!],` W &o f̊[^e}D8,DykAu]~-xc]?N]Mk L@SDIGL޽,%䣧JT;E{$\ȿKf!m V0XwW$E"{fɞ~2#|`?,:%%Ӳ)=!h#ueS!#hw`G#9'nH¢\a9TL|-NKwT>ʼ*9ergj W/]-s̾Kju'=Ծ#<|)G TFFQVi{,4>F=SC뒱m&g  [\0(BSNlgIZ־A.E ! ೕ6^YebqCLJ) $Z:Pe^XTy`NoDXO!=pѹ ŘQE 1oue#s϶%h QM_pcNN'π\_8%w[rqJS?"KHuo>b@񓫷+{q\Ux?a5:+WHVSc%gaDI7 <ה!l&WƢM fǐY.Lf^wYzUAN$Hugyd{\`M\($* ~(x Wh5f/B3?]1ݞ=6yvr$KgU adf)5?;k> cYPf. ϲ}WĐ/r0>qsjBA_b<.n׳}9iXc/@q SBaㅆlpA̪=UyV{JNl;$LZj?ATlZ+l. AWmAxήːV*8w`d>\E ?k lHC()0EtH 2@lmmx29HҪsf5_hj9֎I2:FtZN][oôr.bL.Ŧ?i?c5vM Mu)zx ˪9޷E̩ u^vq|'^@X6|!k1jf˱T=h}ta!_ȾS._3-rꯔi:3ztahՓ:AfۿMxV  BX nƝN+B3$q{x/[,vO u D7g|/Oi>k! /B;uE䁛XYntQX_Io6Tܶ JM Fmy<(!#V8زȪ@&~[cxA;= 4kܻM/(~o/s~dCL('Ut9ST!ԇo ٻ "2x6I/d2[lHM+jcÅ7-%m2O#$\8?-٢5`Y=lb"3#Dlsl prTR,q~k*/t;d3<Arr 84[Bi|8dL>iT`̦,X1cf[ vY;،(H'E5UҜW{H&GbΟL(?H N0FҭjDZzh&TN"1Ӝpmdu@JUG*O_׳ }ːLFd }R^.`뜮ˍW?(/~_TЮ͈f>nߥd̃緔W<3sjsYM&l/b**JYUv41#F#S蚤BP+ \ S/)!HoWbE|XG+Q5;&aZuև/ŴuNsiW/ᖒ%.?QZo"Ƕ3'U+Z7D˵s9Vfu_YXhwm nQ~OMxR7w~:47B(7֊>#9@G@=;m7fE&qsJvoRCWak< E.Y^06S OƘoE=1Z4,y &;ؠJt'!INGpxvƖiz^nVv囇}l|6iHg7dc: Zk9o; --nH0670݅rX~P&+M^INS b2>XdhX.z/^6 gyYmkuϑgyA{]{<1&v$πS Tf'MjkF؜pMwwma.qMZPu_khv =4#fu>EF+^6x7T5?`MP }ӏ}T+`Lșqf'dq+nQ8'90 N8.S5+:˥7ǽom]Q'OYk48owp~*%G]4蓼q}F߉Ohs5KyFC,yvc4"rHK͕)d8aun{ݢ*$2\MpCG ;F4oFせ͒CXWsibL_'cu7g4!J'::U!>$\/ϒ[z^Jwj^ؙNOlA=x ӥv\_lCw)H}5!J[:>ֈ4:9d=gE\-KzK]Cg9zz=(x6,$&a~"QkۓA^waD6a,HaZdס@Wog`LȈo6"p;K4)&\M;ܡ@x(Q;-.7(+&VV#?o^q~QILQLe ?0P[uaVpvFsڋ^M6NywՇ8q\#  ɾ}瘮ެ5E䝌4P{)InT> ֲ)&2wsQ.Wh ~{[¦."l?^j2C^Yi6r/n K/ /d.a.r1է(}F޿d|F:h5[ صeºA HN$y^ NꣅdkZ`YP< +ov.oG.oKМ(\m]@:fx^S7ن/± 1[-3LImUH:ϣs#(u"Fr?Su)K9K^I^v*IT|9k@?]ɾnʅK8oeʼn'UKxXIKMǥ37wM/~0gk|WHFw|\nۭؼ;%QI)Znt*"/9[A@ծ{H嗹 ;ItL;YbXH6i≰A3Z3":I`sqڽ7\f߆M~8l8+:z |ypMK(.?!M -t=?u{BmVN8'deQ{EhvU^s蕥Xa/꽓NW6˪ Qvʣ)@QM~_OFE_̕5)11-콬 0?\dm:<L Dv4"y"Aoq|0`6EynZL 4(mH Yc0tpj`gN1E[zk&W _w1VxЊ BJW$<8'mϢFu`{ǤKP>,+`Sy-/=+/95r̼7 lgXpGYz}8e'Shv `S/SyxXR`D\&(ݐ5a\4v s:՚}|#.4ՈgwN_'g`-Jn1˕lKuFܹp/HcGQsu -k4RGfDqRʄC&AQ*V'RGC7Ap1)GkIÂZ'_b*f0IuG=J~e8uXឞ!kܓ #P4G4Vdd*  If2gWSa,Wfl|Lш-$ApXV3L?$,FI94Gݏݻ׀Y:emhm|PσT^kWuSJ !fr1Rz 5)yJ^H_& 1Q60: EAdp2|vD:Oq PwoBF_=-u՛Xwx#%IG͓K{X*,D }34;'H? &oF $ J~{FG;LOsW=yp[ڑ7G$ -3GKZ\TOjOZbz{P{ؔ/5U |~I~a=-4qLmK0~ y\&_l<81q[P?NtB{tCo*7F3p"x$5*Z>2)V˔ATpn6wx<= &eķvm=F]RS^eEI*p]F.[3\E_^5(qYPE^"k&xn^Eėsٵ?gױǩmZnEact8|Dyko3OrgƐ֔麵#@1?"5cA:+|}H$[67D,&W.ERt?_C,?pWj? ? Gmz1ik =8K+ju&6EWsQ3wݶCw~f>"Gv*G?1]#_*ֆ_cxΛ,W] "YpgC55(9n0|T2d7F9RPySG5 M'W߲`ضsv_ji3 vv~S&eg^T-W_fkS ?XuS?F e))=\H×[LDnrSlA,HWJұ[M®{թޅ5x iR?LH%"90b_!%'(Vԏs2Y[LG"9Ȭ3s19y0%"0)>;gv-s`9ͬ?Df>?9S#XEG[߶y#;BmNj ΗÌ&kgd<`lCaU!Jy?{f+u.Kk%mpث 1%[" vN82WU >8k`RcJG@:F7P>1x QP}pU* :^P_4Q[QdZ'>oth-ZRQ|}v'$WYv66V/g4J g29:AjkQ䂃'jNoɸ5kVvیQIQ+;-L+r>d{"cτ?B~Do6Q[<H㓎:kx)>CG0ڽd|wo"_~Cz6g]WXoW5_ˣtl9aW}^Sݞ^}&?)Ru]mbl~#=*.s}}d;FxUn/ zSRim/B)6RK(ohqMa*IT>δywEi*sv,O3&,*?{j7cΝIOP%C# _"p^u`R ǥz y+n4%Crl*aG2T"d~[9 =%ۡuWQ#ExO͏sP[ߌqkջa~ωH܊" =e>[(sq.؏ vSlo?G1+&p-iө;>BE*LeSTSaw1 Lb}Rc*@w~"31!AOhU}%x{6Pn3~+K_ߜ6=XUz0Jlg{"  }#WAX"Z"LrƻjOX &I(9YQ--,q9U:^G=[7M7OW5_r7l` xbÖpkC&>S!5Gu'ԫ8R0UU])exUlw rƠ$T "[H|+ {q`2u7mfM@vj̰(aAys ܨG랶M{ r-dqܽЬtsyr7J[t.)y66;A+Q4}R@d^h:DDwNs^G5ulSͳ;j‚.2xG{ըՃ(4^>pÅc-D;(!g2J#[`&z9Zg)X-'|v^)0KИ#|+އf^$ ͵ǶO˥[*ft[P<4TBM4& GgA f^G ιk9ѡ@хm_^bzdC1ß|0Ɣ E)!g<}IF*%wRc-Eq" fJ؈*[\Z"aV`g< bh5hL SMD{C܈H-W`?zXRo"(-IiK8y@|(Z̢T6@\Ą܌m?bEf$w􂰲IXV4oCv y}!y\?Y8C,NhZútzYw ,u[]aH'ZL7MtjP{i Z:Ƈ}޵kd!{ ԁi-t .h#qFn?FDإ3m5˭E8]몡M*GaazA_5lgAOracu q[ÄJ#V|EA\&a y9䙋O![%nMl}%fa_ N>Ij3o: a?bV\-QPTV4acD {GLru̺S잞5-)'~ ^~'pLnWOEg-s+!ҾC! Bò"yWQqk n4殹v T(ß~؜W:I J2}zѿ;v#,*_y+n%$#7V\8=ib~W85^ׂaI-J eF[@g4 = '3YQR^׮?ڢr1!Q҃M~l{UEP< +بbRiZqʶ7=x7hqk:{=8P,6ApGPnr*kt1 # uoVqB!2ph MkfeeBYwáP C]lz]$Qڕv*4q`8IZ2Uo^2*D*_iBp޹(*Q^zǷV^WKh*vAS]8dLge$\ֹpXq˨|yISnpەR#\2 u e7LW] cH\҆_ ̰ AEe*pW;U!zUdY c\*Li54%Uqi_<lboit78{V-Go+)/T+-J8RB߽:c*6跣Ř~/,;A8DJ~y1;Fk7i%qTg2~# v74*d *8,OO;`?Y3"uY7].61{]i[̪y_C4+ Ũ'YQ@7~~H!U љѫ󥠭9+1}hRw9\;73!\1fLOJ!e^K)S2)X#L>QT"Mqr%ZFV 3͈/.5@Ϣ?Wi5t. 's׀O`$#Z K8,}WBq 3S d[u:=}}Kzgkî0?B?Et=Zi K 0ǺhPsќ !"d^E`Y HS{æGX߷@ ?F;vzS_Jv/8/}PM{'Sr qQ ZX(fIn6?W]NT<):oLPr2xGp~hJӘТ:m034fMtRFQMWwKӝa?23HO2u3&_Lfp5"ry;*i3AвJBʐ6 p֒.?R!rg7W$I PL΍[gtOϭQѲ^X{fTVEW &Ủ{3LQέ8]&] 4tSURuT#Yr|oQ!6V$k0JȞ}NE{+SuΣ]W;kکrx!FdUyhZZ}Lu8I&$fוO7]}Q6A)=@UHجn R)4ֳⱉx+o6xaDkRRAȹdˈ[=y$ hIn ~ƩSH1w ']L4b"wz]_XWuXWթEa&oayzp# Υ+f|`y@ <%|h^0j9 TM1_ wh$'fxaYӵRS*L28>?K[2'4[aIVXE_L )'CMfq=k !)o~!) d@rEUm0ط갏HXV) *3\h92ٳ8;tuxyT-a12>N %勡M&YN2"y5"XG)(5ap^DRnXJ\ټb6F<-wׅQ[Z;n5i35 0n=NsdxQΦP?&L;6'J@"!mk&KzbDz(d@t^ҚXk8XN~r[${_p5~?>^9+هdIsZV-v%+G}l~/ŋMQ"Sܵ&S)I2q ZHyg'q |-@MSԯ"K®>iQ$",W3荦T}fuz|hYHU[TZޢfKKASh#~П0Et`xq3t0\d91 tOv{ f:…8n@螕A% VAMکeDިOm DUtPKX9\LdO}gA Pޢ +j]:{}vW'IEG+pUwh6nD~)&(|eXV X6bE  [n{>dri 5/յ>a`jvoYBnllx(@`O},G9&'~[LWK:pmLL)t' Jp[pR BFgPj~4JfI.&ۚ>Ӧ ubεiG+' ZeG&gҳMnd:#tkP/I7+YY靴ƾc͏Z"7wU12>3ꬠyM5r6{G?^uE!g';T >d _`j"lb?/ ;im&Sʖب8E}[Ġ!RiVNspP轨$5n.=qlN Rs66x˺z/6 ڞct)wTOoD[qZ[ px~V`ZcDl}k%RpRl~*};WePm%f2>A8 \ e[ʚ՛Hcz0,jku)z\h "ؽ MJyNXz ͗̈mOT+!$HNtJ'TMSnZskSBNi˸2)s&R{4rU,[ {[8ddip9DfT~ozI>О=zqYh$o8{r$Y8c̛[.~Mߞrbk3-:z?aT`% /c{G S&dIน6K ˢOj.xӂ0jNBf_yA*E'vf!JKBoQ,k߯[cUq8t029{.JRrw524hq)@rzhSDj=+^DB1[p<Z`Wu\J؊Qx3PWH zl,,2B52*H$o)ӲNХͤҽf VXdƜH(! h&!XIF'=IODpDam Q`{< 8Gp}r9f|8JyH lj =;%0LQ4 s%j 領Vbg}1 5+B5b;} )p;oUdEJnG>ٝ$EpdR6Ko[_WI3~RN?``7@4?GwbJx^t"gPo<ŠDH7﷡X?{Eh)8 '|@p5hr2@P~D%|5X_f#jr. ծ7UK_]5J5Svu5XzR"Ձ?i^=:3hXKoCi )Y[^`g9+X߸J^ {]% QیUg,>HWC'*) I&JE ?,=>`[']6d AWA{Ƚ :n7. \ukVu7glGArOl`;bq^#E!" \' mEv%@ Y i ]q 9`ޓcX J,d|e_LiOm6`rAN /-uyfkwP]3e+aO.[AM:Wȶ$n+jI;UgqƐR|@?;+[*dx`Hl {[XP8'OPr5S|̤7 V!!kK&tHxVX%fsAz*ksAͬ,B{~ V.{G.HEf17󯴭+'kïw2ЎV N$'rMhnjɻWXj`6eF<*N| rY"Uw" "ceP!E1 qH<~+Xaw_M2wT|r aOۺ%X?MxDfl8>dzK4JY9$-Bh~ظYE8?NL1]q%UAm {ے/2&G5Ic׻Feǧs݌Y|b'HsQxKeo/W[C y_*P'tBD|,ԐH]q |!e7d(DIE;ߘ!&(ewW"ϔ6`u`)4yWQz||'إT-&OMq &l5ӸCq`!ͽt![1c}u<}?6 5@]fUY2luH.ldN=W,5+"_Iѣ LUA.g.FcZd,~PS+kw֗-8<|D?> W ?@? ]1wjߓ0rxO%__,U-Oދ1(>՝@6f{LL V!.F5MYyYTohL/*?'0i/mf%7ĜNq]Јm.bQL+a$FEUYA`w}x7oEx5$){Zil0x`6jR&XJè8g~,R(4A}Vܩiu*x5ޖ*P.&OwTظ+_.Ǫ֪Y.*b"[`!QB a.A766G[XD?Y]8y79TY}C#?8Np&)yM0=()SpsD$r }(2͊5 ME׍W5=Zt~DYʮUG=[/$R==OENcf-M*);vSHЖx^YN1j)>W+5bPDoI 59E.S2pBEp%Qs6ɸeD(.c6ȿ5R4?v,غB3l⻫g! }aR4C2 .4DH/p&,?LD8ÇqOrJ֨݌yA LG;m$%^Ƕ^\ RNWJvOϳ`qcGMưH#nj&V87]nW"CJfۣ>i? vIŌB##'"U2[l)dmps{C去H;La_)YRlUbjV~$R0:`O5M,3:@UKAa5>!:]43ݭ~䎡yY$OVRXD=nKT8y{/ Д$'@]U5R ۟0gģ-һkY̗&k: P% 4 [R'o] $Ss3:@ jg|رE35 ubl䧔5.}3wjТ58_bA9NhmH2xJ L}/0G@M$}gEfOnٳj6"/͡s869 J`k5ǫŀOym[:،*܅Pcॖ;U*w}1L)eoM@Լ93^302'EU*'lwj° -?Hwh#Cew~2'*v;c?Է*X尔 κզCG:? h*+I}wӱ(ٮbl֝ew~Yodvzv갵Ɨ#dPerʧ\ r Y`,l[?kԎ JrҵiҶEr1XpNY5emk-/O&c(úTK6^O5p'W9 ΰZkK@[@ vv ]>&09&a&;[_);%PUOTvtgJZnDa]VIH/u +ug?)t/KX U ثwǝN=pQ@wGO骺>'Gَ7cf7tWz"?h?iQSr;Y;7}9Q&#TJ5LZA}Iv'Q/r#ZyQ2xݢ$ici>(> $yJViuq[r 8*K B?c~ौy }^\d!4i*,|Y`Up=SY&ri&@ݕ_q"5 ;,"#jQyY<ڍ_ȐaQ(3ߦxsZB6ld%ۯC4Q&QEloL/ߜ 6B2o>Sd@ ,q6Ё">;BgIJG<%wbs>0 2VDܧxlDV\/TAh}w$mٳ6]Xu­jߊ!IƃVDXxi>orPN`"hK iz:)Kpp`һΙˇuᒵN}G,QPo $_ޟywvhĀYۨZ9b'f8>=/|[AU*1^h[ D||@>/;Zc5 Tj96B|>4pp-j G,@,i9ig%?!YY2}3IJ-GDP8x&/.ԕq {' lsQ x@!Ɩ&|n/(FYr_1lᎸȈz{Q D)d)fGMz/ Lxضj=M5,+{Ւا5^UGx+7lrwP}-+CXB*pt٥9.07Ƈ5ƖUE-? _ H gLnl$j婬9<>m3WDd9+؉q6k  ^I.Nri!{dl[i46TX/C48Sl'щ4_c*uU({\*w°(cV8ErĝRuhߚI~LC"Yb4=_Pe>Qx>y3M‡O}.߀a`,`m7\-Pqq)9t]3vRTa;&ETXb$<0f]RSɹn[F6d sz9F-G[s/-zW(dplS>þ\bhz7BUd:ߞ~Tq&J![}]qXdC!KJh6sjàƂ4C ]|CGʗےT'R50+zҁ!G+|Uʣ6ּN*wen^Fn1_+xCƈ)?HvD=#}p0ois'&igc',&3gsbN7&1[[S@}(B([]m CBPgEdT\'$u;lM^~`IPb c uBp6$#KNLG?qxX!lڢ^ҹ>7Wtr "H:%a3Aby9iWғ[l8j(w w %3:?bOSHo>=D c<&KT\`]j+V!=rUMV &:x$_uLbϺBP v_&|Ց1E~Eи!m@uY/m0QT sKn|CX!$c}a(cidzM(,x㚸YS/_ Zu5NДN9O.YjdIa@S#Kc KxyQ r d.VR F`Rg*mn,E[_^MK;Qa*^Ox4&ۜƸ ?!!YiP$T`#*%}ᮥy؇i((mک, ~EѦoq ʿ1쏡i=`̐f$ι E.I*n?E$vN+Sp%K]|b6Nex[O7śuʚLφhK'$?߇H ok]W o vAzƿF^S}7ߡ#-$@s cRhQzW=jMYT'k ە;kTɴu .X5iʕs'|aVՃd>웚A|bspedZ4_/t״"e*֔ar. 24 ,p0ruׄx ~f=~G[qhDìmLxVyuH39|\"Xa995I JG4SjJUlzBt՗0/F4k /H|?c)Og A\3 TgA?&ݵ/."7C@*^cm[TyP>ލa U;osҙɲu񧛞÷%Z8ؚl.?VuçQ c([n 9ֲF@NmoNKEnJ6W;8 ʘ:sJ"(l7R| 5RFjZ1ԏ%\L8L#aM$! .u0Jl[>Bny2 ARwIazDUB oC &s4^HX:ʀҠw%p|"_Q&~꿈 qeBJ_lj2hpKh˜UD8HL"磑@B!7 6yhJpMRߋCPf5j&~b욖vު?6()3}&FlfM7/omp Zzi^h,E)1GG0 H}ȵi +ЗMA!tAުܫ@"?*pGFꉱmg k5AIun-#!NG8:nIn8㷄;j G@ީ%K;mɸm|(FA% h> tOAsIpfv0&"Fy!dDWƲ•d-eA㡬y A Qq dvZAqӌg؋aV@h62^o3[굖C)"xǜvk?fGfOt-bѸ:T_縗uvUʡ3PӞ?MD7DAЗ,͌ YB9xT { Śv@k!A#sRAؤSu,$AU6{*[hC$7\ $x1˺;E<:W9w'm&'ҳ/R__ϠmZ#6gR!tkfPL we;6#NVop-8 `d:]N,4c~6KQY,W 6+uu>`bNg`^t\{%īNmB*"֣!m!]$Z툆ggDrߴ݊x{V\#ɮ#[n :M`/*6 vwq]|9b&y9v}۳Z*tnݳ&ݲp ,D-ג[n* 2j2<ؿYuyTAv_1Lإ0ksA:g&SF$h!>,l\?©Ⱥy#4x>=2Zg!KM'dK kTͺxY/r=Q}NQ,_%Co8!` =Gs@_8{@'XwX\ vQfm kIͯ)o?Cɳ~ 5FWٓ9ZA BKDBP^"ߐU}E>]ԃȚQ*mTlvyrY? ;|d2sюoq/$ьf`c f!'YB༗b 45r,F2+&f_{JO wgVeO/Üy3 ,C#[_Y$*O YhVXTbgߔbK(%~ x95s#,O60W'Q/9+T1F6YRZ/F~;LYT ϼLủlH@3]j]Gs 97h{>] Eě1$]c>[nQ#H$WsB}lʀ?pgl< c9'.dwa ,:9A_|ʖa﬌`n' >1RְmN" $,s9qnĉI =?ݽ-e/{,;1ˌpǶ@[SeOd;hf[`q=]J9bMoq/.\hw=FRbO7yQ)[1Gl˞ʭNPZ"c@)P{HtRW}Ju.$8#vQbB;#WZ%Hi] uLZ@_C% j=HBOIi%encvI#UGܛaޙ}h"95䌸 pT v=Ёq0'f-<1/)9z̞wyC2ozv])f$6c={Zy) q}I< }!xkcPƆ2$YU8 ^0s*ɽB!I>P 4/9 yɊ aIC4GˤӔ o ;l-ShkhvU"e"pbS Y= ;/ hY(&~s/Uޓ྆4ފ<Ԏg'Sg7m 0Obz}!p3>!A[M0™xa8 <>ku}hMHXMwG9kN.,IjL'}L%y~ /`o|f /o+wf'ßxRKyRܼ*A[A6[ ˺^xnyiMUi9Tb=TPrJ4!F'V;'Ffcפ6ܜLRp+ .,$u!sga3r{֠3ɰaU|̎xؙMJIM90K[ij/ZJ:Jhȁp0bR, nSq7SUx^{GZ42(BɿX-0D}\4ig k}Imap>x]+dQ4E\$w*\ Bm?6Jhp{I+nTntފ8<$h8K͸{އE(.~Q@.Q>"}Ro\R׏2pѰ,n0KcNa)[X8Z&I ߙD?.V"!'aJ1>drcy`H$ ÕK5H?ΏQYRo"cЃZN9q̓C0!5 r54|%R 4-/L.iߊ0¹w` yG !erp9YKEr_uGy{ZN,{oOWp@(U H OPI\hj" ʤŶLDu_#aֲ5n,vqۿ )B%n.hyS'.K<3UB8)SA0g#El?"_6W\ǂ7s#a`TnEuE z rzO7h.\~Xcmy)-h8fbBީD{CX:RbbAW9ͣt Yyaa?U~#퓡^ۄ\";7YkܸN0 +|۲,)87H/YSTg[7v ÆvI-+YB.m你 =V3ږ13>9ElsPT,#2j,hև:v9-R"/mW o;}y=S@Em-՚S^\QY  쟆-0d؆oKBCDYx~tHװаñ>7n_1E!癹.PnKвVOm$ Y9T -2ƙ4:bIZRFËR΄UwJgZVj.V diP2a)g"z li^i"/!7Cc~Wѩ] xqOr4]tf)?. LF@ y؅hxntzK4ͷ%/N\=S{xofR jcr%lV{mU2QNaU&H[ǵ> R>7F|` "x J,6 vL}2"9ҭq":簵\BǦ q;HhvxXU פ1˳[;At bg[Elb µleb3-"Jz:h1gΛ.r-`]Bp0Rsf 4nV]{vLkʋz6NJDRy|A>?,E%-S[gs&'uIgb;/x8W{7y>nv+$iS qйJ+/ D_Z9炿Zcm ?-I]mmtIGӉȫQI0+(5P}SlS:4L䜳z>B_ZA•4 v b JET &_X^ڴYCXYNi70&,`詬R&Cosfhl#=hMa4P^%m)bMURM/\Q ".SYMr6%ֽ(p?cQ&V.Tq;T?ީio._QBFq$ganV҃BIIqF?yFG<0lUhjپާNIWk6D<79|CB86vw ν+@MTrH`qƦ lkvh*+I':́n%Jʭnets xHvC\gaO̤^enz;W'ǽ7m;A $ujkP>x x# "|wf P ГঊYIyqTiz>aD-60[}@.qȼ j:@n;ȫ;dt]L.+W6}I*^`*5Bnl_-Mz!0ARd !qL|UciexD0fuiRL^Ldn$b@ <,-H&GCEEow;zid7ڒoMʰ\so, z[Ш_ LL&[EUHO (J_(s*`m:-P=x< ;=;g-W8cֻ? $qoFGjF6[4ݰ&qd :h)Up!uvAyKl€ӪO C;@o3kg)'eL!Wwt/̧h. %Qrhznx T+vaR{" #~j$=&OAT ˠFvH8L71xoW-n /-TY^Zz4o0h?6 W4Oةqq ustR-hN5 .pL=ů-䖚$b_ZUW!b:f zV eCo~2Q-5؉WJVxd7=8{&޲76}b7&:x&|)C[2Q5g.U,v6Y*,ڄwּtWVbo&W\t-3[`ݫ_d ?h3 獓`H|r$Z֎to!igJ{KL2uX 3HQ90Ӹ4N L y4s{/14aj#\" 7Ȳ.TW!~ P8L&[| g0lBX=t9$ۂO(fZx઀άS-R)C~5О > kiՑU(U&vdbGȖhK)۫)8b\18_DY߀njBm N-Bŗ6򗃵S]$\F ~`=G eUw=AԌ5 Y],)w.v ͑m-y<^ʟQ퇠 Ďn6Qfw]9jHcwIgd n6u&! |To5}{"K*uh+dG%PG9Y^W :P+~ J=#Im#Չ 5fd:F+̖^*__ڎ/S@.MO'Pމ},.tU[k WOleЉ@&e la,&C: dٚO@#=R%c+h~7VOӊUc.E 6#/#qK42 b=J,[P>#͎"{ɒ=" b@N hotHj_'a A_4k'b"a8PM8_\H26{ߚEI&s q98{D犒 W>S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0g\?@8x̤[J?L|+@|+>^w8za6?M2lFR_GÍe|H$KQ3l>%,Cvv%ޒ Ӣ"Zp|:5 ևq) *B]΂oIxDGFHTBO11ߟL܉̃ڿ*2+s/]P@`Ͷ. HD.HΧ3:MAG"17: eaW^(sTcU4hLP 9Qt$ZKM_8h!s7? C>;p1~ORt:xB|r+ +[zh^z-VF.=R0&G[ˆlnDȆnPAr~mV<*"^pR ;`=:ðc7Gb(ivDб ZA1^:Vߧ^`KKB`|MV%Kq/.DZ ]V6lYMt2š<kX]C" +ȝO# V_W` 9p*7pVi-Y'r>y teŤ{CVK;eցVe#ٌ(yTUq ~\QQ~a[@-\E[_V4!9 ȄT(L x/9(4z"]@ ;%#w0Up> 2#Rf6J6v=s1&N ko}H0'|5~Op_$ _B[yx^\` {,a;-4yfr7[Y mejd \:QRy 8@Q}'7w K{(tlmO@gCwUh*In,cy/+Sդ[x'lTv/1? >V2om&YL`0|KpVvt64D fs|IcDZ*|*۲ezɡjll M pH.rt%FiDR)_5"BV>,ؓ(:Ayx%2rC0L ihHG/K5m:?63,8f3TPx_ܺPa6xFϏPLe:̈́E9}˃Oq#y;aloiYGHcV-%((.wޔ0$h)`&mԥy͚z5sI$io (|ՐbBeh+I wL&d`)E 2w%όІҷJRYN>"O. 𹮉1tt-wTV8u 6XzHiʝKF[OՖ=.zMͨ(?]yQ}s|¬FF6*(ݢ.lX`X~Mn@YZC&C̼e1Q eyYgGk8eocƙkRD.;E&ouerBf-p.CB+.X-[`OyY\Z %B_&@} 'e v[#=GҺZ9u,tJ fz<#Yț" g' N>xZ+9t|o6|769ha [AʷPu\ +(?[ zW/s@-/o =N%:b{\#5p&3*ʮ`LK;Șp8o= ~R ߏ+Nk GXBGU-]xʉPb,t%:2s"Gi΋wYү>[FZ5@pcJM~! lӨ83PE|e _h\UUOʗ7Z<r`> /Bc~ TL}f*ћ[l?n2I?ЙKkگݶ1G97]iA{iF Uo\@a? Xl\/#](F/$(fU _u. !z#_- (p[ M­@ԝkw|=X'UuYYٓ.a0rl†gw5}8PzEwK/q(vT}4hLJvXEΖGWS{twb}s9WuQ.A)~i5aN3q,-sBfb4!xj9vP&Rm8>%I:D? &aS]?ChiBK1Y/Tҋl%q>7pqeZ+K@g}R9uy}2-wm<ǒV\i qw3y]B ;H w ㈋GG:ZWXts|ز_{R!_^Iơ6`w9x=M8lEƏ!{/3QnfVbOfqŌFSk7PEsK|~Wxl/ҀD/w j_v$W" 8ZCAW2ff.+&C_j!]a%nVKl4^ŠQ߇'{5cVMH_^FidFY4`b;+:^0򻉘ȏGP|ǗnZ0oA# zr:&<͓o85D-m>X%Rm1r@o>q`}i9Llʂߴ700*X(x)v۫oZGNPُ YLd81O/kg=Fd xK} tOƮJDM:Ow+J*&zNZ iN5Qy;pk$ý ,f NCwV_0ݺrEOHDFS &fP}N[lWyD !`$!$*7OK23$l@]y|mx T.JriՈ$;yW,&@@Z/bnl䥙Ϣ)rRP#S3Cf rvwQ@իu%Ɯ?c}cS җa :fRa-'܄ LQTU?j>i4[ŲzPl>r{3`TG O R/shfݦw4r~(DY ygAܞsl5УyC83Uz3S ͫ|wدOʍgl fFrl>fzFG/sQ4lΆY>@ݖ}{j7,,*G)nbk?ވ U$|^ fo ›J"]#bߘ yK"} !}!?7>[ drvv}_c!Ƕ^^|$v^I*<zt{{]w2e3ܱG(8Y{ _A`\Fr#Wvq#G7TyGrd6r$9 H)]B ŘVʅ?Z%/ҩxh0Or6-x'ŗZzVQ4JV}Q8TUS*/ 08 5 ^u/:u,EK8 :kY%G-S$T':A/.ƜD{}}[5}[AWfDPC[ xL4&ʼn8giBmAd+a8vHm, uXIn2ж]wfE0WeVzzB}D|}@ ]7C  3 rzr0`^okz"p#lJXs h|e/ "H6jik;# f\ԪҴxk+YS(s`G_ތD g zuEᒘ0,ӱD/R@f^Ut?jr\`[`?{_#x#~n_f(y3 7Rcs*-9 aNY1OȒzYn|@8hHہ e`X|>4P` 8 @d{NR_w_c6X]KFq'i^=L{Ł@J6w lt˹ز dU';ʸsIOYӳ5 _I4&6R'ɄM7sd~\.(AaZ3JMlƻ`햻g׻CCAA෈L%=[:ghY%;1XU֦1ZDK} 3m9 mv%بz V)4$:|'=ˉgTk\qe~e`i=8$^jD\w\$R a"ԜhTl*5<>u Bsyݬ\sc 7c]8N|7$R"u-8T[-osUHi䗜QL=R!4ō-3#( F|Fp3;LJ<(z>!t/0E`,ગh>B@W_M9QHŹEo#U(ZMU+Z塛jpׯ8Ç,?$392f s3TVTQf避bͦ*{<=p":x%pm2Xfǵb?B1>#8P6?^L9> E!jI ǹ!+.Ĕd2뮎Hޣ?x"f"9]={`5y(+@r!"w׼J.$5J3p\qKpu-o.G?#sn Ph%\Ȏ<#ܧ@?D6/sB8?%/ Z.sC3ʞȠq^;gDnW5ͮ$Um ceR1Edl3O.pr&.?Bnu&(i*JEv_>K识Q+kYRgaD~iyCē;もAd{ 57Az荌yFSP>I5Z{-&_3K 16dvTZ.̘F[[W4 6ѿ='y=IJUZk#WHD.cgֈrf5J/"P;M{8/ ; 0HI'8ׂD΁ӡLY#d6;k\L_ 88fb ,]~q =Z0$I}G;Nש.j|o{)VA\:p9aO,$1j[~viezziO *2x͕DǘbЗ],;-YPufxgϳ00"zV1(9hAZP)@`6A760MfJ}t -5ps! i;biFxeʋUhR<<҅`}oehO7bI(cÖ/ZYКy =#{­@ ۈ7_0y=uD'[QP|~^buT(G0DWfaE@eNJ,Keӏo^m,oj\"g$ y;$%jod4( CcV2{ *\Jv/n蜋_},$*SN.NB/BM[EHV7iޙ9E*=M뉞"-zw s.{"P}9M>[0 +SeĵCKtk[\bMC)CKP\Ι#.2rp7#͹+r/ y߻ ')D>*0f ZiDQ q`PJzʔ]<ѓ9uܵM$ %߆v̶Cڣ]uہmR7ⷮpHN5>.i~jA{ |7n%%MwQa"f9ܝY{恆dE#(9 _x8.Epc:q$m!IٛP2)"^u\u"'hyXKt[)YOfayCZ4 Hgr~o#=zN. PF vX,Imkc$]zqyWUlU>$Vv77&)+6AMP};?z|Du]jtfԋLi 7ۇ}8WN(Gѥ_b=|7P5ύk\`ܺKݶT7V^Q5"ϲ^g0 LNHxs4́ߗ1=2r~Mڄ:x5* $rcspU&yqc{ߢD|xLBY Hv>[0/D‰=P7埤':/U]=)ÃtQpYal$*lJ6iZΛS h dדu(=V5}FHX0A/P0&} MpVK `K+@iYŒ;A4b)QH8FR8m i"y5!;PrIM'_kkcllД^n"ƞMO4޹N|$iX$?R#1gv!g [!ֱ wSNR)YZʗoBv%'NK'IT/ɱƁ׋Jp^k p%d34EofL:7qھ#dJ<@&4D5)\ *"P26&/Xoy8.X7/%vjk@Nu1J#;Pkhұ/ӂ& |3fNVǫBB>7iAgtQ5J0OdFj 5{mn?Y; %bmN["xO]Fހ9q%W_Ցm*qŬnvٝ*)g͜lѿNN0@XNڂq&4SfR)ORV,5&b%7M˰Vkz^v, @7x\o-uUɪa l/xēg9Ɋ0oʯ{#hSҦnKߎn-vA~ޮ|mTտPh̷wEm1,&!Px7ƉzI|Os`zpFX R)j7-~’˒JH-D3yPe%ˏ:+ʖdCozS^;g =FYD%XIB5_byoū9E-{Q`AHU6jRW+@˯`u PML D[ ng^8@w߄ps|WOv@||>Oy~H 72À C`׆g[ WR$l-Vb6adEw7%B >:dU/7 s"9|RO=e}fܚw9vnfv5ijnt5>KYRsmT K+Ax} ;() Z%Z ;G8$g֝!n;*_,NEU4wjhNM;a:f'™NPyMv鶢x2CM k釼/lw? ?S&~WK5#2gJ ʿ ̡}o5JqG CpLͩux!>@.W5[>dxT}+wfvh/>-+.!y pCKPxT'ތD'F=UG'QWc\ͼ>'ŃL&|D J )t#uNfIU Ub1zypcS*лLYS[}tE"q,ݽC} Ѡ49Wv8~Bb`5ώzMs ~^ns $=&3Ѐ7~ &t 02,.S)Z q0GЇy}ׁfBWۻڀa|lx]3V@{}VZuTHHH&N9|`O;;?jy my8 b?1qZ:E7635/L+DtSƂ@VOY8>z$[k27Սt R'MZAHtX+Z~6&Gq%[9b];MNXpQZK05Owfhgй` u_$]<|d Tż=*W6GC?a =` ;E&]XVT83KBgH 8h4BY%l>[}vDٱ> G3fH-6(rN=:74xUgn'QS 4:#&[,;NQ2 KDQg0u>=lX02iMq8wڊ"ds!q*QTTnM-5Vv29KcKlւ1,znS ?tSVuǬѳ0 {}3*pXjAU*׀ js@Ru[ҹJ{B|)Ʈ+_h=$ˁ]DJHE>׉ wlE VW&%C߂ E Wa! 'xcer-bJ- ED<<!:_^tR1fRG- i\`唼ChXx`|P;;] I#7u&l rqo3VM_6u1'_^Δ%6dCýbE@QW x6q=eQ3VvY)iy yEԟ/6+^n3 ʤp`LC}%<9h{C_m^_I]FcU^՛o % 霡gh@IZA_l,!{*M˒.=wҟo.:їYQ*Q  .tGgrMiխ0F(j9QVG3M"$uD5D+D՛h՛QDor, E*DX4nԋy+j釮Ry'aP)qmz%6nG"+ x5Rc;'UIb:F̰Pia7TA?Øɰޮ}$$ܜ|r%DM qZs|aoz q@ka c0(/1ɛ kA@7dv?I}V, j _V[7y2 Pe@ɖӖ+Qؼ^Q=WIont2x;RΖ]^s`]n6иuyX}XksiD&ikXشtp9nB!gҍYChW(.M[8L I TM=7v|I䆳723 F7LE=E<\Y * $A+x)T'PKe2w{2bCBYr kots\Wʶ؜f"{@|XHrAU=.V yI:nzmwWK9(D'ɛev1MǔE1kM3aʝG6n^k":xwHAyDckQ*8`73S= qwrSZ@I@3E~!DJ5:rMJ$ǏJ*-_a L&oD O<G^Kx[ uPSG+ȋh}1hyUᠩA-C5#\~V ~EH췚kNG6pyk9لfN7b 㡵0K9[%~ TTaE;2bAFHW)0vDWdcQ!A-9ƊEm-geW} @4R\fZM$v2%6>^#0uEDrX)cXalp!5{(ٍ[vo)3࣫zdBR 5bUcۨE)d`JҩHEI Luvf"^&QUjǢ* 7q~" ט_c3Gzd}7CuFt7b 'vNʵ~ՒP2yH< |/r!M}j2m$LQzrz$4ܿ 8#?h2K@"$NA_`캋GY+G-.@c(  Q>".3Ro/"Kr<Dp`.!v=B7WeZȈ|ЩegY -a(sW^Ə}AvE0+G9~>g^ff`K~MKT"ˇl?:_%;TP_nݵ`@4e06O+7͘MOn2eo)M繓wcinFb4MW; ($?sD޻~?k̫Xz X?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4#ˁւf/8xqwc O|Վ.:¬p [ホ-YDߛ'*Ha\~eFU8 6lhhF*}bTH(' >ĥ<K.5#8$:tgPj3MDr!}^B|5/0s($RKSM \{wGĻ8G< W^ @kgGG DhAI,J$9yo+C+Um}c K,N8~0:S%`Ȼkk<9ЀGDpcEfPM-~6uξėMYд% \. O?]u9kܐ{k{ԴKm+N&3?[tq_ *pgyO+{Eĥ}" $?!c>!p94g[(M 3Eq;nEw*\zQ'y.#93ϑaINl |o/q1*"kvBҶF1Xv%Y{C?2NOjXA61PMQ3д)x-{ԃ%dq _){/_4l8nyLG壥p%B]P}wѺUy -O `U (fOH/њ>5j!/3lq6ݧ. <,X] 7|pB}q>L-2V^ OgR'![֎  =Eb6 ؕ:fTiE*{T,545@#:T\f:+xrp046ˀֳ]9'Eg1]m/!\ JkJw? \V#BVMPP_Ue׈rxm1lh]WN>';z^ó3߽Dr}b,ۧ^ DͽD'liO=#TH=}7~i:W 2ٍ:Q߼/C`DY6K5^>4&V&Yi7Uމ:.c6Zm?b=2YԷ'5VF{T*?Mh"e*Oƿ@Ԣv5 o40~vd&5} tc8(N9ϓCAh{i)a+[PorS~n3r?їͽY+̣6c 9KR!-a~[G ZP#\tA1UD2׭bJ]=qH2/of=:R.y'$"W@ly>EXM$̊6!\tIT^1>=dK6י H mZeSJԹȪ[<(ܾ*MJ2"%Ns>$޶6|b(zaT9!̚lbȿe4LS:މ {3遬+)wE0 s& !Z")Od M@R@ې%7q*^03qXCzrDȷ]<݅3u3BlՊ*,s%|N5&DTo1/΀D,*&_]g u[l Fn TL ֞=aϢ',H!c.yNlz1ek- q$%VjnBɭ%IjT(`WfR485?a'K;kŠUDKeo4$Kb#Uv_ͳ3"@r2bJd 4Z+⒎ZOQ^؛E!f!f7)q/SZŐC ]~ÛmjokH> `ܨ`A͘`2Ӊz8=L9N_˜U3LvҥHZ4Yiu\3=(.O$ʈiJ-ϋut;RB=}'֬rnd!!"M0wKk'ik2we堶c4d.'ѥuP;duA~Zx})B &piC8WM@J4ƳF̄XaDlTw;fClT9"OkaX6̹9< &ZK%'r$L< II{իɟFi2g)|ZѴ'"E~>Nj}.=A**XU,<<\tO-g=/&+RW.>ô(8u7yE \y2Q)Ңȃ- pRN#`IɎt_e,YFA@t#ǻi?ZUPKk)G[P[ P.F=lg*/kJ'dE8bP5]|.: Ü^RI9 5s25;s_+Q9p([5j?BT_%IsKнf(O}Ù^&}3zrՂzXɡ m@{q3gqdW|/eXfE^`%)ȝT_5/Tj>$a7@. I8aSo(qOW]hQbO\b|=:]"zL84YFHuTʹaEχL5 *Lԕ 8S#HSq]^[o`o6n%R \O ߁ :52xp":hGMtȖ 9AgEZwalb-´mJ4?"+( i(jdLz[s+|$9> 饎O.%6̦A{6w$LFB׆(:}W"݀Fh@;!HU6t!\zA(RZv@*ج N7;*P29

tu;ܐPTk-aY_fez}xPUp*.;]^w e ^O(NsOe"kO}UM'VB*PAU0NF DzoibV^ۿI;t;69,"Fgpp: wv.q'}b9QLǺb0Z \_&#=i۟ XF0BK6"މv6M#Kr*)}-kS+i 9; ӕ[`704yĩk6|7{FS;S*p6*n:v*ۗU]Ep_*v$e~RZǵccx~N㪿lLJOB(,ya&$Z9 ]&TO ྐྵވ^ZX cIv@ƚ&UeВaN Lzw.x)FWcaaej*p9JĀ;KzC ^vQ#e ZW fW3$6k Ho$cȌ%"#~Xv‘sU 2W 'g||@|b@a@?!QP|||i@5Mnf;E->\H>#1C_\Uu- v$kbYfQD8M$@JWf#.3rZ틌tr??eb|;$;2t _AXpyXQR_;&xA ˲TՄEO_ZV MrtgUJ\[8 3wTY_{~ hĀ`tޣ1W]{Gpz ɇҕ>OkZ7ToM*=Z&8G=?7Mw!! ‡ q^D7}A*K\.lK!%IWRah }H7H1QbP7`/gm{x+ a3.yAPUB|])b#=)9(, y@jT^;;&$f?sH'J)J9Iɑ@1nb.$ <1cSI'JfeLHЧk@HPSk.fKmU[|zEZgZ,un9o}˒3A7pΡ уx7sv-7f3ֶ|"SKB>sݬdd {? /o@ǁ"6n0f%1ʝ^f1ҎK'urM'T?Yؿ%|R&b&D$/2W|Z+](<kU$&?mu^r]p,!ؙmhVF쾬OQP)LtpSrAS*Z%8 Wi#}شS+4DJmO,sx#Z Jڢ5K09HCqvzh gaf)E܀'< kf$KJM(x rqT]HX4ќ|A C9Ba_p4pɥQR%͐1T0I'ޢBGomcSԆE XR`u$3hS(?Fͱ>H18;*Wjz8I$L!m=h<3&ϐ|WlLTKd7'抓Щ&e G~MfzkGܓTУۇ}'$cc':{<ռ&ӫ$u#W=c4cǔ ڨm`3p7F*0\7uVd3/1S. ݨ?}8 5߇. '?w 5<&\ [\_حi2w s*xS"l d&)V=/aJDe*N|)I| ydDPJ`yv<T=ZJة.EgaBn_V7aԩ_0q'yB +X:(^OUWZD#^6 4ZOB6:7u1AH[,wl#9!c92OdD@/jzJ~yiǶ̽>#j|*ڬh mZ;K9tzjr)L%~@]͚uZ6sL$.Ni/8X %}oP{jB„I?=Hזl5pvZ*P>4{{[0>rAz5GpæꆴҮTwug 4Y_ʉU 1fk6JP)]|aqBؗ7T0R]Ba \8 <۾ F+,G<`|ba$ValSln܋=zZ/BM=,DM!r-^_W"X.(#^C:57-ֈ{JɎj::~h}(LT" :0S뼈 zb2E.t} )Tee @O |׊{Pq*"*{3yrԬJ\=8(!ξ< g}1lp!@X 3ay[D4*w/ȴxpEjt5v'dv1}_X 1y14n_ >cIgi C?Z>ϺW?=бZr jyo_efZݼ:|Q`tVrd /M:tuES  pԝg.$B'p/N_sq%0LXk]媅VgףZU.H;t Q6Qu(oQwd+\T-T7"$qB%ʹZ;梐k,k!VA%@ 'Yuzܞb^iW I[Yyo3+ipKM˫r4ȴmXythcYEttA2 \pb>QՓ¨<9L:Aۦ=pPfKu8 >s `D~:qufjz``\rOp DY50/ii鄾L!/$ [̦p#BLlD@%b+*1rq؛!F65L0 r|G&.f}.*T71cܶG3ǯ]2bfqS_+y"rnjY%~),:l4+f q}sæ 䂎,HŠ!}8&PҷOaMQr1s&,(m֫55el~f9?C]ΠdFȀu.$E~rI |; L[e=aqXe!j5Fm HKZ?p.xQ6Q t%0~T]Q=+#. i1K=LNus&T!^VZjN0kԐeL:L7N6h5K@;pN+A.(tq$Aa;h[[ԳEՌ"ߌ8S7قt3G3Q㴾mJl>T?|_('䁨a:|;D`> A= QsKLlxBWsa}ܩAH|GPM#;sRT‹dNei:Ӭ^] WcrU1^Tx,%渎.qE&55 NjN=ʻ:r{ 2&ŁøUst?;X9Hkor 1B)ZxW`t)`9nLT p;ߕ*;"<6סQ)A18]ZNὮR`æRN6ϩ-TOP\Vc;D,`[x@<BD O > ](&

t]k9>ce@rɗH01T0 Jv0kY. ,ShuRṡiY3X0;2A,lE[* КwAa%^N4dxzQ@^(OvKe!2Kŧ"*\)~h/=m=?Wq!fC 8cQnWWݯl6(8]w$L/ӿ'P0$7‡'S\;}O9~ش^IWgSol4d|"?n?밠덢!@Cg9\Y vX^ƷzXZѬVBPo"6ZYC?ül"OavAAHH.-A*K 0^<:fM~KkLLk5Î *Ҧ˜0y\=Vv˝;59:1~RlPWhl;51#0VկU(9.s87y8%*ژʣw* QK@j   1 HeGۈP›aDTGLZ_%٢s 7byXzY;(ȯDR+>D޳7W R3lb{Hqސ՜RT] /܃qcb۲* Hl x~^"w# .Xq@ _}YZjc5.({1h|'vN3KJER RmCӵ3~,N*q: 4 7%@un9ϓL/ZKYr3q9K^gw֝0_^x-!~yKdoJIAL$Eq_VxN7lnԤېZ;dq7oXjRۄ_)^w8d *Jt86a+mN9iVW"ey_Gki-{2/ ]vԎ2I(fZWW-iu)tH[L40DȐh$Fk&Br% 2Ҡp ǺRQ@,X!6"w)w!Zc=9ap'. /_k-\᥻E~@r>aS$d}E}ALaq#Ɩg_+w]J?"}ŏ8P=ӳAî$oa,QnjkË(yU#냗])Q!Lr-3 `tK4|JJݎ@T Z{,WuY ~'-譹D,^;>pUyK,7n MۯS饅ϐP ^m4C9e8ҵڹEDķssF\!M*p<Ԫ{Ub ĞִxX|V *~Pc̡%68! dpQ֐\)`sOd=Fs-W.GWSBXX z8Q.`* K9YD* VP>T`U*T/ (Sgri~kF_R6zl<Mϟmd#_)1|;uy3Ո9ĭsvݠއ9 억#$ZnhBXQ[:]3q(:ah!d5?h3)H5N*UF령Ta}!qȲtm- ̦bWiiH>ih;{ I@24B\y9/CH)_Ce/N[@pW8k ?FK 2uC^vN6XSg0ry>ە C8.wXQ?ak[{RF  ^:R^A!~B)~|㳭J`>yQz{\*fNoGodkP Z idEĻKgZ DYjrZyhHAXs g* O2J4qZ/" c`rKKi)!Ox[D+XOp+(MCi$}[BrD4-aXa$Vm>NQ;ts{Fǁ ˎ [UoGҝ!zkOmMTO uk  4r L sPGHt'cqVE>P5dW(`_x"I>Is8H)4ܦ$nPnD❋)ůۊs ;k a˳ؤ@E{jax564 P,) , L*[Zy>-McV3CqPF6TلLU '1kt[OYNӵU޽gvOY+G4/t,Gz# ՚ 8>-~l,)HG+ryH(< sɎnr(6Ӝ1Eb V杖3?7`?E~VѶ kMD{- %7? #x\nUUM(c.X`2^* 5_OBgvUc( $9N,d ]Uw <+륑|3Ey8)22aYж*BEZ&2[#jc7k$qu?Q(a +: ,vĘ0{`{tdYdh. ř/o #q ^JBekȨonj\}diJ]@"/DѫHd;HvEfLqޤaID͈VW!D]`Ոs,ZYG"Ulo(b5"6EKv!ۗ $w;Gq6 Qo1Ob*ިp  &rz>0@ ɪqU^MrAPv .))E#O"B'$_̳c@lW3Y TtZKq"52D0)gA%}w ,J{mpF70qVKa\1z5_rvϽՖFSlvg T6Z^غTlD?:ue[ght@U1:tvUlͯLcK)mO@ '<4?o~R" .^: &\6{Ɍ 0&G?f'/Z_Al~O$2em)@܏ /XmI_ aUjH`{ъ:hT&J#k{?QQtaol.wP~sعP}> 96p ϓTv[ h\dV5ɗC|uMp֓7)LNWn=HbcQLCMJwp4¼.x $N!'EX)3Vdܡ~Z ;}:LU#p\lRldZ'R[+4ft>= B@#~ys*F`~S'zޢB1j7;"@Hvx z?Q)> DپkB4Z[{1"p40]ZJЋ+fxsbT-O!#++njd&YF/cop!B&#oOh_vrxAXxeOro`4nT7gKP >3ڠ^mPp{I)hWl*7[n%rp E 5[ҴGzl\glynv䨹/f@OPC@XToj"v"m]ż|~3Witm% Q=5F|lwEdVɝȬ .ћ o8|T:Qj(Nz$" 1Ir$\n FpLRJkwX~!<\wmq1M"`;Yt3ÿڋJ0c5EύM~NDY)u=^W46ʩ. 7JQ1ћNc,6ÇkN>Vo a[ ]UsofE$?s`xV8 }*̊D"a:4zkX|}NiC81_Xk!3ڑ4x+Kpm U} N1?#8oA5mm:Ф^ǷSApTXD|iCB$uqU=SSYzoЂwغ!Qbay6`ѽw a?k'px.JU6Q4rܥQz9X pe2-6;yl3SqSKKe ?ŵUsx:j+χݢ97Rw?#\7So_aH8]( kN٭EƂP]8 s{V|w†R#PfKXqe5 ߮ t9/"sph(7:!ɨv~V#TGae+{P p,C=A\v^ؙ[*;'dok;C0xcQF)ӯxw\׿;&3U. &@Z2'q;sBRc1a 3u$yjƖx;]@J5bWVp[Q-940N2!D0U|) * bx$;xOYE$Z[S+Z{bw "tⳆJQ|+" bhx q!k8 vHiRgYqzjJ$Z$U-⏖WN}"US>HSaxAG#f%oSD_И zc]"vϭ >/΂_m'Ba ] j=׼DDw [MDG,eZ Ƀ蜅DڹSG:2*EVLFu_{m7*!iP;_ e5l+ ܮ\ϔ*Im_Hú.2.d"L\ `S/r/A T ca$FgZ@?Hp4ג[5 Kt^hg?#E9ROۿv 3&IF "i)} ϳ"et頜WuS_FGfϙg. W'Y1M30*˃]Ґ!ӂƭգ*4A7!O|i#wumWzݧbʆ$gԈl՜eń}]/ ,%~L*z}j׷_v5\ff>$#*C( 3[˷G5>wҴ%.meF6Huo.%2e.+#S.>(|/gyshl $ǡknY_Y #(Ew Pjz39?An;R?QղQM{f(NOvIȥ*aԩ:hUJrEK+/tUg0Sq=& 76VFOu$τbjRqlg^ΣKKmz%4ET7Ia]K%m ŋ>8 59DqS;ѱ*5X _m),Awѕgq`mo <`JesG4s)!|<Zd4ZyRC#"3E~Vuڠ5kF|ց7^ UtiFU\=&qQ]^Gc+Gb@ֲ4pkdA*em*lxm+9937EI+dpy 5"jcI6nL24h2]" Im2Q*1ڤngY`#{SѨk5qYom $G7 d)r)bgϗ k3FWHvZ^b֙a$ꐫ\E\(5H3\g$"ߧ^ez~!^*i_רK:5 0S()?L;qf8QQJ7Cl1IeR*hR/27+8u5vmj+SF?J-=AJ{2csBWZ!7U pJ+OAl= `.rhOriKx}>P&F))F2}M#lwŢiZ6b&4>OVx 5f3nEiSJ ~r,q9dxRQG^4tN2"xJn3:p**>Ʋ45;A$e tH^WH>6+[,#>PugW}>2)oD պШ먆|ⲕ91sL&7$ډ 386 ;QC!֏r%^A wzo'݋R= "s,c1[U}Ek;}zwU"KUlF f#{]Bg{"q/KƑPD #D5]NmLG2hSuoIsCH=~H1W0xuotUb2=x[eΘ$iT>!.$N8cL~<+uzypJ՟t +Ir[ ฃ '%vO8Jj 7gn!wab9V=:&V⿜.Rc;˸l]MUω)Gڡ.q@ZؙBdU(b=îLbDFJ!2P}tM% Sc;f^3 Kh{"_.&ȥoZ-*:iP[AH9+nzzÑmrr݀׌,a|ƾ)Ee=pǮ]?e  |'$M@q3EyVv Mi_&L\lVD,bů CoX" `ꦝrճI^,Bvd2L(_ ) Z㝢KF\|iSs&%wze?BW7^hpvu %:6:2#gY>]XPWFFCKuSP'w6[s^z|1`(a /QOHF359S)UR=^d̾n_ժtG|T{j`/wwԕpRh;hzm_`ѼA K_,oE T/IӢWwKmr m¨q&ߵ.8Pk,xЋr@'v H??D(Oce-ODԏk1=},1SRv_|HJZ;cWz AD A ӿ"M'gx] ]Dիn\& ~:Kf"6Ïh>>z]8 ?c5lďA"d77+=!wS%@;O6%a'}D|=J=b?v@X !ki?e-l?ݦWKr_ i%c]!(K}{2n:N:*ڬ}T,3@ܐĥKU% 8xGOZO/?gDXM (||P`OI;f:S*~.! D?L" MKndF%0W4p^ xjzUQi=yDz^CI;Ѣ\N!dڽۺJˆ/oPQm'8!{-,ߠ/TٜR+ nDlN~C=J6ZEyGw+yyy/fұ`'Ͱw9y$P-WP*I%&tO?KٝlZ[sU鼥 ? ߇Ӭ ;'~U \?Jʫ_6 =f,R,m3iq>o\U<( k{EbH ^^(mع d띭 f8jפi|sPixxz&H@&O dEZ~H"[&ٶo0*aqIO7M{񴰞 5V1Mv' M_LiǛ޿ؘfq+S4x- ]_w}p(5T^*k {Pw4Kp*sŗ!q>V۷YY+Ru%7ONzт6Vs tM:S5W"tim|>{tTf$d?jؚġt)<5}Gל1NVA@u]fs ڑcRb9f6yz E)TQVⳳYFn'BkU'~]H{߽w+/AT.dJOO31c۲J u;ݗbeHw%9zU%oef,M0EIF(Y5zv>1*R#Ooҙ80+B/[NѪrTGa̘Iy'BU \UҚ\<)te@?'l7񝈃B鞋-My~>żS\V n<_8w\hkE3'>Әs"wzb̥} B07la//j(q"odw} d|nKgz\cqYv Z2o mrT`nbnS% !5e6t*a Gp9M䆘 0NKW,͸Ӯ{8a16iyg- SH] _dr_*!^CPO:^xcG$q?p$_o;~ x$+V w)"Y'uۋL6(>%Ux:"KȪ=Ew6E *:b  _^ZMfՑ f'hh-]B1ٯN"~q} 7E,|'M8Mv?ۍݨFg8FT,(*dBi;Npgٛ'ه0)= /-w-! m;S777a!J9ġCqYx .MP+P38g/?tk%{oћ=&Ka?*e'9#Fr%jKC| p LT=緧ZcDvFg3w:Ws^=Dv6γlkKyy6$E,_"Aޛ>H.;=blEwb\Fn0o NX/̡?Gd: _v|wY](\Ѡh]H`NWt Mda!ZCdq*Y]jX1Q$eAS/Ol4:>/amG]ZJ;hlHf)fmWK'L+'Mh&FpЩk ":0'UqpHï&DmN @H?zJv+p kW,kK3Y?'en`A|XS}9]@: d]MgQ eG?EbCl%M.M}N Gȭ)hn_pe{! +L"X`)BMSӱ16ku;cPn_ޖC%Ybx̏P[{O<+T=<<;S0ёx+gq?y > Ӫ[vZӽ]} 3DHljUfT't!tO ݼ o+Wg~dmln޹e4.Ю(nl[fVaI1IC+k JTAfs/@c u$ ŢI. v%H߄{|Mq"j3ociKCi8 E4 B B:gL lqO¥+j\_JL2)!cSE\#g.cyAҵdR=:V-twNJn!q9I;Szwvgd_$H19^;&Q)|NŔK/ɯ@_R~G8ӱz&gx>C%x2X:3_WX%PTߞH<]m"‹BΕ/K,l^g02MuXXU,Q*kKx8c_ mD;/bwc.burڶ3ut02Lh|HluaSߊ~m1MT{ .#% Fj& ԃJmdw2,ڙkZ)ɭMbj!V[Y j%_϶MwI2P:XW|LYdlCtd%.|q;Fo1P@ͨ|av#)'5zd+jB;{O~cB$PT,*q#El~l| Ͱ7#dmFlJ d(NE$otHkMbyb#l]ӳמ}{m[G^ܸ}+,-lf&i[Ng9ų_ L Mvq:HA@e>|8gLtނKFsk3 0NbaTֳȴ/@xX!nDqe,S'))ϣoI?W +ExK{Ec|pG{IҍKQOי 2mרs{9z(xWNتul{YMj/EXS#x9R@/2фkZ3 _&K.}i`J>SIRπ5,+b扦2\;L˦!̻n@ԃS܄ZJ)u=$i_5A&Ԋ`ȅ~ jt9lHTN] g[5G93qAo[Y'?ngy7\-&ﮯ+EPk?UpP, _O)6K3h~#PCWcIi$#e3 jY``_W16_sxb$ku]38("fLEFi*4SBivmj;fJ`T%t| jFR tBM&"ˌ0^]ST]䒛l%=6,s9smB\,iA* 2)_6x|dO=#}:L*$KLfV>_DU{ bʶԒZ ×DF[Uyժ=l_ڠzvd876͇ZLAİc_ }ثm&];_:nVRf-Z~p3E}XFQ^ <|N' zd=L7T@ޙ}|buaC`f;=v-3k+'tN>PnK * RMH+)X4 ctɯyHzQn7kjPuΖ6vI9jz d 2;2᳃]^![5Ow鄷->K & 7Վ֪ǐ˲PGk)د||@|bgV#u k>=YI?|>4=R\_N22Kf"E(uP&rn 0QImN{{9~ XN8B ||kF@+§.8gИ '9`` fڃ6F_"Cj_"K[rgIަϓ\|N.g*xԤ`@x+ 8Rvx h7h|Fjs T k*/w~uk_V+ BpK@E&O\ z of%.$̥kX\@tFelCat^󱛖=R^8r{c+So LgN  `aDPiQaq{ $x(ׇ%4h)UʛEn)4jϼ_SHY 0YJ<)cu10=DRoc)V<@)DJnOT.yV!¬V$ʍ蜥Rp+|'/m4|[&I<][Q|)uCt Ȥ[gX`06s>Z旮=^tOf =(*LMM)XDLtnhl^PA^Y./X<.gA=)[*M (:'jH $xbAϐ>Q>8ܑ- A Lp`E%YDԤc"CvWytG;P]?j拠Yk K۟pՠFGa8^(79tcܠSC$I &ˮ3SZ8Jt V\5ߤlYA(;Z[/?b E2_sEOeW" qQ}70?y>`VpʫZ~d&̽tks!da!?$D>} pf䊷O)^⮧xz~?륂"D5Mo*<Sc??\љ0rŹYx7Vst{7 ׏Mb0&a.[tJ$on>VZr-kĹ߭1NN0*s9>ᨏXpPcj{/zT*V X 36Dq,RMx0oIQʢ~%4xժWQ _QmM8f&a k)ڲDb=%x0.VF6F-8q~ M$f.{VW .&M'>3]/縅*kϫG[Oj&x-^m 21At&vOq/ O֦+{C?@HJIaIrfZF>7)OW@A%;tQ0'H|t.i`d.)wAR&WB{)MG');rbRm1gFYQ@Q`o2;Sye_$Wi~x 5.?z i١!l0yH7d' ;Y^N/Y ǂz ϼKz" KuArT &sN̎&-Lz;Ϩ u-|[d/z][:V.ԯf*豰y:v` : w:9WHDq[,GKiQ"q5<:aΠ?t<)( p=k0ןIo|i_ Wwd0^ڵ<쯻m#fA (MxSqF'*,4!7X65^%~A|Zw P5 dy6ͥv˜(4l0W02%[*cb Ba0#(}_ ӽ~6=1G?f,{-[R^-5Ɇp;T5kex|&NȜo-b!hz{QBx<*VΛ4 gv KM+!i|Fw?d"βJ?MR }xCB8硹/hyn f-rBnPi-|%bUߑ~.&èj=>GQ WyD!OF=*$4yfZ\t~_uKx:J ?mx[`2|]E;⾱IL}( Y{kRM>6j8uFM-{ճΌ{M$S2 fd[Q6믒VİJEQnƐ=&1i{[8-Pa AJd`) U#f s N~K~j#>EܾPuU~AecG1S٪oiS >ǭJ2aɧMdnB'_wrJ$w6ˠ uE] :{Yk ɋ"o.(R+ml`@%аrF5;/O@^?Ɩ?̾ b<׮$V/""y,tG-+ }X؜v$Y;MwfɃBbI=YdsDq8tP(&&qqpű2K;O]·6KyejӞtYbB6.݊X2y|2Tw} la.ܴ#qЄ{NLݳM o݈*[ Hા=%J1Ii[WϨbS]<(+pչYڨ.wN0X]x{BdNwC^(]DL?AoA)Z͙Z1A8JXApg\C@q$W ^~ sTpf}ȕؗ/LaK@ 虵6aiW9paAKOX3W%Ǧ)س0t# †`_5wrѦJTz1TbY I7Jzݡ3 z)ڠ 3W4DžڜOsy$рU6!jt139`!O.EdqP˸S:͚EKX]{ Gb0?iSp`ᝤyrv~b; *er<JY$ &~ $ pIGd=vUQAiHXZSU#é=:VE[^tA'&yt]uy5U˫ey.3bM= ©ta]}搥~屸KP- ,?  ;-c/ԷD6^Iץ)_G3G= zS禖[GKiͽU/7U!xopOPٳi#2IbF}"f]7sy'*uI~G!D=UqJcK߯LD#Y᧕B1)_ʚ? Y7Dh%B`2e.#izX!ڹ\mL@hu"'!> "U(=xn3V+5GCSܕ5'5NNrsL4 )`C%uY2r]8?rSP,qDg+ ;Eb ='G* G?`}Qq"Ěāi-n07p bM)v ̍iJF褫$r&#)c˖1\kfO&b-fzmS4ɧ:]R+bN9GzqQ\&А,SGx[|I8{,.~U2412z"RQIbEgy*"̛%%_aTclȕg8^ϤuS|ׂ0뭁Xv&*[EdA*-(5k?b>{uɩ=d͗o8lW{=Ϗ0" "JL V_UkVeq.O^Ȭj6|h_!͛b9ok{6f͕r-1W('M),ȟm )nf(ezɋtqu f*#s֎:m6.@T`/CΓk~ gZ^ fuo$BuEEW\J}TbKgѕsZ83o3Z+xO8jt—^J_Gy2zʹ+ՃO;w) BiGi d5a_8[OyM 8ck炩s[x"et6o8gq^wSbG`sPD#,ńSs1 ̬emڀ(x05m޻39W)l*X%u4.49٢_S Qd"H<KW Wv od|+y[`Uތd6̏g y@ g}&B3xy8 >:(v%WT6gjWfK͠ @%V/ Ы |q!)B!M$ K|M)y%b4ns@:؋9, =aBaJ ~;c q@S.cT9 EbIǍ!G@Z.D>'luL&#6o)A4aCY@НA/3j|;u*Gż9"`r~IgEE 7E\x5B<|${{a_$? ILPB_cQ@c?'/2v ɬ?BCz *$PJ7-h>۔|eܔ4dpjQXG=N\f6C~w#wTP ]N@.wӓj[(I?9eb vqc?:G΂}:ٜ=iPd&CM *&>?$<hNx(]3+e/XNJWgj#Rs\I c,|'_  \ K&8m-Iȅ? 'v H(2 VhXUF& ;#=:PYI$8Ga`;2 4w~[HxTTh x%oB8#sqL6Sn\:|ZO l0LN}L;Dc!xЀUž3/ dfMbpB^Yw1 fkhゾ+Q32w_3&p /mY$*0\HS&-1k '!nuAC;<'Pv̙}jG֩]c*wW&i;}N5sNK-ȯ7u-oeIIHB/߄ȉ?eqb9P m O8ayN*})7=mq EŪLڼ0W֛Q!YƜ^15oH.fK̻f!wgblT_.ۺB5 8dicAB"qp &rPU Go! Ps*;aȥ;$S.X̰FP9~*pnûS '#[P~n?X͗S"c[.;ʲ1ygIR7a^gPUdfآjE*i[$%KT(FZm9^P{ezu[M΋7KkEvIs/Nu ArSy.? S-k+9i pPOFf"l6) ?[@NvV%c͛rIO~Ԫͣ{6;-dk fjCN?U˅n]%Ÿf4+SO)C sܳqi1p|k>/DJO,uSɼw ~M\&//Ȁ¼(սگ\J?u((gZiIaZ52i@} Xᇙc`vp}n;J Av SEx,!4?jD\kgJM"!YMNʈlnF%-~ sFl] Q=}2>\cA"ђTY`َ!mE1 a5Xdx lrqxHE[4`9&. fYMdF~N+EM, _ U\᩻uE@G0w&QRSKn#mӄv ܄ [;heNcDփϮ5T'Dd,F0Z}kuai< XJ$8c?8` G K ©qsv Ӑ+:_W蚯?C$[y(@@N ;>^{` z~::b٠..HnPK3 24\9N6yKÇ0ttu[p@#F H+aq|a*yN FEgGMč|-ƒV\;h`hWf:C*W+df#:q ]ڹ>C4Q 'ԺY\{QК҆)JQln(DVHˉA^<ʣr."p:a|{+-gЅ$~ Ë=PZhsdrflt1Jed;ʣ>\Ygd3)x%WX! XJMze )HOWR2[SR\xBi$#!Yڀ|x5הQzG$o`0 .a6Mz&0W_:yIkJp(|iwF@PD^rՉåZn di Iv"KZ/vΡX@zk1TTɸ7i>j\K%*qeȍ/ iIBK^+V@&#@}3_2 a4JF3̇@Y V H4;)b#툭oV_R8ł/Dc<ՕmX7t #b(nA 00 R8wVwƞ8J}J@Jy"^)eP_9Dru"d@ڥ ".}W4â)/`ЮTNSjy9pݷPwf[]X٦9:e iZS#LE%&DQ YFsr0+D\{uF5E?SHuw%$~{IA3n `yFv({|=`Ynؼ?n%DEe}}]6`PnR7 n<)vL&4]:3Y, s57v />\HŘṒ1A5j D!O%1 ?8$;t^n&%oR8q_kq"?r+k7>HeP!T4q~}<tc9ؤ0ƐWĥA㓬i\6:F+<Q6U#p54GX{?l"RE WRfqkxo,7N,}DzSiJd _Og٬E~HфSWkbx*:QJEDZT#_@Z "0RuLY#w/RM6HIudu}7/&?HX `UWⴳP@lCO+Fq9,;}!ŨF m}[EVVoMv PYcDowHu4?]7ԮazfdQme@t)qU4b?ȗ^!" 1}m'K.s "H xQBiٷOcƐaB'8da$ 51Z'Wz,\j [m$qoveG TpB mWwtU&J* p;ᄐ%8 |R$) X moOD[|jr5؝l9 ^DH4~+xT`jEjȒ,Gr|du&= ZhL5]__-x?ӭ|m۷bӠC[!n"?Uv;"Xkz,jP^o[^8rsë́QqpQ>HFJ,{KȋW $#-J?&;Ýwh|Z \jXA>g3RX<4/Ō^mC𶽮J.CQF6X*Yz,a;*& tL?VKC[cƪSl$ha.-i4dGGl(U$H|ulh ~Hq/$!7aT&zܲ!WVctڗ`n#tR%at%85!J5QR)}q Hh\E?IFs\RıB7k*eufbVKVY ;n'.*6|_j]q^ 7 @B 1-ƯM1> ϑ ғy}ژߛWAK`k;ZA!FaOƢ/% px!qAnJ,Ӹ#L q,t١:}(V:hh" H1ig&y36/׹p!(<3{+LDeCQ s.<|K}:Sg -)47*g60O_3NϪA(@́cB@r9 )P[tP#%d,BC:Hƒy58aDB٦EIߎ5=hhGgıؠB-cKA2e>X q{1׏ɛYMbzM l̠Yyd̰+S ,5yB Beo,*wIϹO_QP;l 3ƶ,f E鎕#IM6=^;&WAuPX؃ћ]x+Ŏղ>tVܵU# o,%gG?Dݓ񄛟3^9CžK"A;7#\y<A]!ʛ}P|`'l=/KpdBfZyȰY\q_,`}m(S:QJu5Q%:9&usrtZ@s%/#7jG[RP~ev<|n&w )u(Ci Oϊ/7ӆ @MC?O o 4WOL `UsɢrOʹ^K񭳚c=ζkAI[{3):gG74O!c}&>-QD'AT9G!Z4r5f&_vX%ng1NeQl5/;OG ^?BV5{s7ݺm?P3FԧEUpdǷ(](b&Ѵ+A256~dV6BX%I~i<e,[ApM*&dܾ¦dȷbɊ N*'jzs0Wg?rq%#oZr< o1,ؑ.>`D7uQ |~N EdS O>%͚ |qa.sCH& HQ/oݑwOǺ= . U[`U6˴m {K0d<* uݮ  z__2nB2y{)"UJJL1%m#>0#KS:t[1=8tZ'}_1Ro%x,X{9Q2iPm= ӢXzʱVJ}.SA4OITNyM=k>Sz:28(q;7vʤ.c^`qDf[NbKEPn8{/x/9JԪЗORܶq &>Ul3CcĔfT <`+n>O_n"ʤoĉ0H}v:޲Nu^e"è(@z}(K>Ö'4n2@IՉMotῂa҈e_WpKh[ *f<_0r.hOٯpU9ԙOCnNHsc@# W'z-n13sL;_:'k T;y}6*Y@,YvzZ4hL_85  pVΧE*/tU=YR¿{1; 34TOu>p`n)n5K X4R ] 3͢{8ûn <'b4:Ӫ%GLOTiiI{{a1YrqAh;󿣄}62ZGP?\E*ɹk{$^fZ W.i~ݧ:!p Ok~>V~Ӓ$}I\&5]n?,qhv?b A j=d3e[bHmuP͚!O P?0/J¥ wpp2bGVSW;8n;8V,_0(;'I~):5x&5^IT"KnTC'hN7kXA2@pr8KNa{~%@DS E6TcO q8s,.1b/@)0IQo5;c|Rs]o͡ O$gm5-Dfm~:|JC>g2ar(C4^my?q#,r%d"1&Ko퀮O4lV}EA;0;ᒀwnX@,5asQՅ&/ָZܨsͻݛ}\jOtO<\g?,{`o #:ؗ S`% 0%QrbXDUq$|_9j[a{-SPP,vʦs!vkqqU*(P{?/Z0zY)'ϐz [*xxm`, ]%#ЫƏ+WPVܠҔo=8jQ`4M{tÃloj-"2SMiX+ +.2MAK-ʖV'՜D$!@p@3Q]@DTЀ|I x ^VlH"7 )})Qڕؙu4 Ͽ ^-jw2=^ͪpx 0Sw#ȋEvby} ͝*u`.yqQ T: B^_=jMB~{6eb AEAgSMXX4̕+G,:*_L#6L̷LFſ۝ .% kV#G$4Խ9%ӵR u\Xn$4%ޥjDa"*HEYˁif4& yO+חфt]CշyVD! a%xj5:B$xFre `CpOn9ڮGpSKQPnD-#[e.5O\4HV YD fLI9`F_TTHƒZTKPgvMrV^ZĺKJO4߃@~~(NQYKm!CӘ԰Th..<0tGPK ZcD+< 9cF7Rړb\Z{>T> R&c ֋U?Ϧn}t~'"XH[jQyv\4'6I`cREVlgR_y;BnEJj$X^7ˤ1:A)3AE i?^nƌ>m->vmh[3=DރEc~aah 6RJTm41Ha)$ZE{z3%R?pYt@Ou7lPID.f߹ r$5<ۄ*>Aay_C󭢨4SY<R(+/Ph (rX#=^+ͧ&Pud"&zʑLMkD;F*OCZ&5AdjJvVkk_!NX0+ R8 0wp*3}W'):$Ό0DXQnD&B{[/gi*H )D!ÊVe|dx1qNKEQ?}r)YC92L n&4~I<&2}6%!؎_XQ]V#~vgm$(ęrSõ<}9'i{S'>>oH몌ŋ #Qu^M"Pjld` k}YвG'XB-cH$ڭ]v7Q,'̄d'N%6¥/ðSN'іlY#?sgJ9=$?U╳yb3 f T*U;1;[DA:8_Z6#@ˆj9y' =;Q]vw[nG˥haP :KTpE7)u^ԉD#rΚ\p>]z2.1`6S ?"[$bH.yP#΀:EZmgE{<3||`Ay_L.O$dvpOE Oʠ-DkqX=vӮQ eb@癱h260 q#)3N!Z5Hj0 !_&0g -#=f) KEz}ZN$J|@|$@|bpo:|N;Jd9-w?|j@'l/d+7L ZI㝮Rʟ,W$+%7En҈$yj<^ܹSd="6putYAg%cQZM|. wgRSpje0ǿXrmQ[ǵy*]cTC)&RC[um\fo& ]",3FހC+JA腆lަltWnrʊf܃j0\ye $`_7#e@.?}U )U0ef_?D,AZG;@%vWe* (=XيU\=V;Z8l-d>uAAD=ա&90Ļo>,`.C5hS> Qdsy%׌"cq*2Wy?o#) Ss/g-DKA9EV };_"V}cK_#Ms஋*7E;*#-ZzMfFp|Am#tw*!{~7 nj߾?Pԍm+J(d.f]*jM_+t&e^]ygPW?) citoxĽvd5{@ E|G}3ie |LiŕK߁p|OƱcl-CK!d* )m[`9d[c1Jҡ56l(SsL_Hn>1,a[4XMG(EAmr,O'Y>uj)ٺL?G_dSESD}V򼢢/4i׽9QM(?AyTFe/(!j8K!]` }$ ZV|N19;kfDHbhٔ[La+t))}%MV_{#6tjcl1񕢲= Q1$)U>j:")Q1ߕx i~^")CX2EX 򫺦2f3Lp-h #evhN-C+wG|@c@WcO5J*rׂvhy~D7TwP U$Ru3HkΌ N[seLpts œ׀K0M✽36 =ұ%\*ݐZ {w6DѸCƒ5g5.`&$0HD_4Cs!QJg0&Akךdyg8 ,2u'n lZ"[q~M87GU k,/Sn?_tO`vUm(|)_#9 跱+EqsD eu؉epl$f 7U:=YvI+t-M&$(mX;?U]k Wʾ\[Xkac˒Dc{S_޹ >oh|=75yXRD/n5ƵvʃоnEѻT[R[;}o = 35?yH鸦)D<\(zI8Luktp#u8{c q\mS= 3iu릿um+d;vkAMB$Ga&EŒҊMFwIf%+Tv&_tŪP"qa7ߢM O>='iR"ƍ*o6yV*S;brl)ELX@s{/G(+"4Wr% Pwx59 \i/=x_v8>5Y膠 ޒ`jbE{I,अ'9o@ M޲+$nSX+ ^y)$)|E D˲G 7;  &BOBn#{K2_Q%b?#M b_N=,M El]«yYb^ʬ=Hb,N~4γ.)8j+e`ka3JMJ @~E챌 Z2MrkC(ٹ%ęhs)XvTQ͓t'z!7M˙I5{/ J_Dt#*{eetUlАGjɝ1^ݓ&W*E);(֧zӉCAyX ̖Fӥz/ ͘NrW"\MaA^rZƩn`:q`;ǟWQX| IHѨSKvmxm.ck'RIio0GØsO<,;fX-=$]9]5-ǔO Nu1do2k~oLrHq"IXof+vQPoTng׼&yU4yɐ (`-):mÈFv/I 1{OCV' Lh=?IAia)Quf^\\;ÓaiKYVS/O덅_@K4}_r( <7Mjx9]jɧ_d?[*DJvf/q.|Xq߳hrn\HX "IIf,"RiG-m 0 vko<`! *}mKMQҹ 8(?Eu!(p tX#a'V%,8*wy }?.A,&2C}{ԕ[Sʼn8VB; A@a6*˲;c-PD4cq(*^Y%/헼jgYGcd́oXDI<&x]V̟vhEeM#BOYlXnCvRio3Y kvFՂ9pTuBM֔ "(vU06Xi9oT2C~͓nEx:o2+ Jw˦!jGmD(ɲŏň>:|`h/l<-6).Yю,8#ZI8ˡu}c%n^ǎ9|ѓ=1AڢX\p mSt?2]=@;E)qGIR^g)}Vg]q7Q8'Ñx"?2`q)z޴`g\#b%j x!N?%J|j{ 6R>W~zj2d#qަ9ƮCw/:]eE3^da2lKgd13\aBE3b4S4LW*'2*f sb/ٷ+5jfnm1 !OZ5p }܂J*:2G RTbm&=naɅӤiH[uM=(5\\F]RRQfJg/ಚ0T% Ne璚QYU5V5O-~ܘeΦx.QRM1y)'EFz"$z< cmhsΦxcn)FC4*m&R碳1xDuիʕ5WRΝ UCW% XXiOM^dJt;f ,2OUN74dr/\[qv1z/gvm!l>xYiz5n->u9E}3So [@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0IMK@߁G])WM`EcYMya7;oٝ3CZwYjہ_+j\Au:[Su*i)\͗%Lq_ U5p 䁺:'.:|B1D8ݾ# %cl||G+_c)=~t zIT BgJ)<%V1'5VvI5/m'j8wZr -Gua*;Q? Co s&5J :TKhPbJu(W1 x|c.6YMWD^ڞ6kU s,nJNQc2)X1vҔRׂHE͟[ojjְyL_ܰY={b)Wסl٭9pTRH{0񺗅Sጴt?u?!/)I\ |Z9ebr^{!6|%+Pnw %.>.Ϡy–; }F#-;אhAW JTk Fi,<V&.sby;o+Y Žt)Tfܻ.]%ՖÏX@97uc~%eZ8jvұU5l@ӇF jkmJ\C eA>QO%3TMD߶Q'+O췌/Jк9syE7 q%`{x#0:Y7w$~gƻ̡C\>m7سiǍ/+unVmHRlqz*WNκ? ئ~x1C Ԗ̡<RwVUwom 灱ǞgJ.háֵ5I^ξ*փK:z%.U&ПsZ9OTjm|tm/<@=Qjv$81|N,oYOlAOl? w? A\N&3}º2h0!^X:DmOР`tUI xoIKvH1 \G;Pq Xqy 0zީ3W-~jZ2m׾c6B~{9 1$Pٚ875 ޽jB'.E=X7f 7 iƽߢ(* O b-3|מ@1lkn^7dbVVPeVZ۱b>~XЛ25+ěp0Epa%7'FP=Y"(x[ye.-0ɬR 9f3: UtXqYc Xf0}9m쪌b=IWM#dD̺=4?ƹA,`Dwp/ǹ;/Q],w1m7i˻I_*J( ,VjI~ `;%YЎN43@)YԀ:*\ɍsβkRK#f}61XyLAS1W> &TA6޾qkFHig)XIٟy+X#M rk6؟Q^4sӗZEmx5[) !g]G@S?(*$qN38l.?r(kd;AqOԎc̗زHlFziFhmEӐa S?z>yJ;GQ DR'9zƇXO}L/d%ԠK7NZ_Za`Y.}}$aENo_ppil0r5.9;lEx`3ڔ^aڀapD/Oq|P# W2aSj u_O+E. &R)!959Ю1prs׬+6H`R:tc :FQ%\RSM'@ж]ƿ]Q_jwvB>]finen/ W ȼĜu/2S}D V5-x/c8O书o|xmi{L)nJ,1nL_Wi/f8 לN~" lm:YWCRizZ'.6$j >N'o0  8;l|-{$d+j:4dnk3Vd6rƆTQ'hj2 i^fbŸmH1HinkNqȱz|b3R>a8y͢:4? ٷy$+(MZ)~$"rt.\ ;=@S(8'sǽup)1ZǑ5wyĐm0Tl:We^,֤P8#$D``UC7uAڹY#۸B\%B~,iXlT)s:u Z-y[^'3U;I7D^II v}yDafA=`獎y3K1T2h#ś}f^q Qg=, Z~6")Mu[Wx:_U?  b-Rl&aMJab1X_oIR=4'L@a *S FSrEEi~}N1;!T(LT@x_1Վ*,:ݪo6Wz` /@b3¨]rߜv1㔞6U …-3!Z_!lwzAZx̽mo+akn$@ƘVJJy<0JܲQX|Yի:D?xkO:O5 ,‰K(#EBvXmCfMG` :'71(1kuI 9nn;, ~]}z73%k0+GCv%5'4zwAPPC8v e'7E7uqu eg^ }X`WRh0 YPc=\ѓ9&(07?GT ķ1+ AH;8 ^$RͱVٶF亏B<1o6K>]QxeV}0^J& _TCp8߈ݼpBZ f\UԺȨ-gG{z'r=~RrFAzFY8&ј]aY7b kXz܈`r-#w;Yd@rV ct.vg4ciG iuZ<}tt#V#~X=nXԝa[ECuK tC:U\ 2ZEy~1e:@ZRE' xje3"| | F M"IT͓]uN{4D}Zр08],_sOObi A`XF9 ;kо\_|;n3-|4zI1V[ۻhhw&:?\? rmS@ PSJ#,UTMpλȶu]BGiׄl !o+Hij_WjIC f ֏^B޳aRjRۨDs V1uMmoE)o=Z7glւ6-rzeX[bt]<˕g-`:+ [2 r`m?%9>euBߖm:_,QC3KOZGW94E ֿM0vR3!- qC;RJd lDH*i/İ%[l1H? ߃\ ;:o$MjzyAwċIbqQ)|c̰o <\o&T_O>k"ytf )$YYls.$+z{t6dHاƳacC/967A0S Rbn2Gxa #2H:7*9`@+m,*#:#sB8{@bÛGgQ?7wW>>߆Q },3Kn7y+8i\zXA  /=%c+o7 raYkټe6eUPN)X=J_f^&mͅ^h#iqj*6V_3%7&flbնT!.YvRYhm14$:p2GVJZ9ܭ|'ϛm mB/?BvIVbyo2I;t,!s['\Fk D2OB%ck{ =ݱJT&VsYra+ jܢ.ǝۂ|$fli3'k&{Rb* &Ng" .b1wͣ| 5/7rwtz*M6qrcG` 6hvuX}{I?N/zmFX˴޻# 88|&Ay}Afg`7lr@YRzg.Ƌ)b?#v*O筜Ö@dpQ@^$z|bj_ #g Hly*3~PjUqW1o*[yOńd~5.~W'҇;Q?} e1kX'=h,؁PS"=q{eRWfLf9j6m85 zHO6H_} 7ā]`JP?{}+Ϣ׮1 l23,iT T)_3usɚ10rxfyS?uHhYYwtC,ѩrV-E:SP:<I%zQS>6MO|EvD0P``֭ NVT;MZ745E7{ ORYdھem8ڃ UԲ+7W/Uu|=B$1qU myf" ^!.sE *Rae~' Ѷ'޼7Q_es-ٍłb"pq6YխaW? z7ɬUɦ>k =$Qn:#)|Nh $khd*Rϔ/.Ϊ"0QhMU]#&;Zgޱ7Mg%b¯e+Z`{1jƺ;/4UD@} Ƿ]$6\!FiGoPY6D6ɡZ.)4Q%/SCźEjBE o\1%KwbTWjp)&g [O8}k7Ӝ^3铒Һ`䙬R\9e'Pm #g0s;_$OUhqӜC6ZсO|ƫd)idyTIGajVU^m&w ?fhT]P:C囹V ,+m':wYm'қ@X j-/A7GʊEC1J;eަYͶSHsƗT$1_u>u(6]:=B{b~KG4 pңm _KRa`1FBS|TBqbcv[${Nا: YRL 5f .=)Dd{<9#jv,Ⅿv,YdC$u=KTK?/x%$,)ER\F_?-+l<\8&e Z1U)KPmO9u~Fƨ$x8|Rož "zPj{0}@UBםtVȬG+Aq;f]e=SR^ ONg{%zG&5FacK@n [ n\BH.BnR}sԡދ}4-{΅x[4S{ 9au򫠮2>B(Lp RZ?a8Z**zcrXt} `%oΓ}&S>IҎ(Wj}sJhClW\9'%'إLĸ?hFd1WNTS#yv!bǓy(%kM?!琫H*@|3G*g^gLgHF.w"Sm:<OWzKDO DbW]emfsᄴBY -SpNXBi)S*+TWJ{Bv|<)qy oOu!MʈQgFiLd&iy1%]郍)*L/a* %ɶz"t+PFFOp+hg'2MN8`s;| Sf'gz<]3P pdFs9 lTN; |/1 yJ C u߁{{.Njrb\1mB$nL݊=& .._t1NL9ܡQ6|S|!h21,fKkveA'8O"?a FuۣAbʶi;T@F;H1\$>IE,W\cueR u-0**`_Pw،^p,s)-^&5dn0]$*b*TOU Mv=ٮ {}J[3Se 3S S\W+qcDªMC/ͫ(֜No@Z')XRWr#4&V=&.}K?0v!?T<[p=Ul s ?2plw;ZI i夊&XNnN)N]z4){ty3̜>pCJ eXYgn[v<`1>-\&٧Pwzx=eƦ5Ŝ&etΌq&qG![c 㠀d ˕w7Pl _`ere  $] N|*k,$+HڤӞXkIT<#tĠLǬc]`jyQ fũGꆹc|60Fa0EiY lh[+Fmat<LV.C ,U_׫Sv?|@|@|b!úrY x _#܃B R|@|P@ V %yI34=ArQB J7_f[ӵ/SZwʕWQA@G|bҪ,:I{]/XW`?Ǡ@VmuŇIˆI"gn{KI V/'I g ]sѸ-P<3 u'm՝_ eCnUx`nVnO( =bW\ڎ` 6{Cnκ }n%ۇj=T3 Vg/37m li}_|I '9e7@i%9<9_Lԋ-s4#ǎNn BY> W˞-mU}gNzlm= do5~zѳ]\q@$J:oz㘷)K):(#8r:!w{)obe6i2Hr o*M@ G|䐴Ӿ^_:@аOKǸ Olr^_%Dx7% }2f<>G;9ysci#㹮BZ޸֑W^괐ZX.p ~g4%hmuZGUKf_%40(_ =e|0Q[]yS2c )0%Cl|"xÿwLEh%oe#&l= P򋪩Ԏ.INk z˕O$+]M|N)t;Wc.ܔNsocUV1wKA ȩۖzZHi!'ڲM+O/JE~[ׄYG?]Bϫ?5J0"vm ]œ6j,s$'ԩ]PAq≱IziJh \fԹ{7߼sVv20,(g7 h_B,XhK ]{W7]mη05H1#c K` bR b%lSN*YbKN>wA8\&Xn:Փ.j?@,~Oèpߔr/<5y\;Bw 5#J]8i&ɯ emr0ʾcaL&ْ\LOw{Z 8w.s y sqTHS"D8L#S$E*;C}TZSQH`q'@y]!$ ϭ Pu!NF&4T _u(h\ɉ9qՂS *m , z 2 P@~IQty']S+NSfQ1T?s9yL$`FVc֞u˧h¤; W7*C"be!1jvf/j)$\ĵ@C~Zd1*qs8*tˑe`^ R2zH#A6o!|ks,TڛBybsݾuNK2͂K~^5:bȌU:bCPܭ\E;e'":\a*YjYAΕ޸Ϊh [|~E_fu_ZBGX{{(ƩH-`\pf$ȓܔ5]6trL=)M뭽:l1bˁE+.s~Ãز  j=!gW( f1݅@ 01)pzaMA;&oÏځ&{ׅkD%jڋW Mo6QZIJK ☼GE6b@5cY wr-s+ \CIbpfzwES~ l=eu|l SYqdM<\]71Dƣ )͐8BQl%VLf娍i@]YG.N/> Z?i a q@CspęmfrUl ;pK,yhQ&ޟݞUO$IJN9=@H_|6ї`DiNELFEaC^,R|7pp)x ;5ii]d]P3|Ɔ?0c9qu! d $9Ѭ l^Z0ѿ19'06Z? fM^I5˸޷ e1mp:]X !q (ae0s3oGQgK=}E;Q1cI)hԍđ}$ `2j'~/*y1mLyFTA%l适MVם 7w^[,# BEѷ UAaT`j>@kz]ܞYя`vsY6]K0̒G#ZoPp˽7qY\"a4oިoLЄI?pBiG1.653+R_Ozkt_tC&7SJ֩qV *RAr$ :GZ1#R0o;O-{Y|FlEӃu}HusiO̿zx}F,ܒinx.E/_{SAÿFRw2t@4Mh,r,,hoTVX/ -K:^oGg2XIZ:mrȈܖUa07=f2OܻysQi݊*|wɾ:qIkNVx.6xa* }Ò{Lc/](: ٳs'lf-}n}b :!Wd?mfd("~#B.[XmB ;at!T}͗cwvy:h=s l>2' 3 vpU榳~rZБSXӃ#~6OCڼMs`]y`14-AEw7 aEDHEaЎS$5MLt~_;dnP̪el&4 "'ٙӇ,Eh>YM~$  Yo/ȘI)pw۶XS(s ,(&:?.8FECmE*S t>о[m VS`뢡Br`vl"*gϸ̉, ĥj\Ȋ~ |\S5z}SZʹW"nCO/f5Cij㣃qsDN]pq ʣ '$ 6+TGmKZ'rw?N (RjehW956%I%K-.QY.Fԅܔ-lAKiUbZW&P5[=7cZa,tdSC>9XaF’),'MV۱G1pߧ57`(_i&wpW|.HsjL'{#H,XoBΩjɏ~B- (Ԡ &Xfb$?a~?֌CGٰ A(fb$1rslg"A *]bT{B54 DN":0k0eZ!u#JaB\-O^IVb2B@zт#lSUrxGMV9e/%|/9$ & e[~v/ #M..z6A*:蔵40O%3ɒ%!hGu9Smg+Oƥ07}Q~JRZOinyo_B ZY(-KG<8.KWψi%" YmFfCCz,eΎcC 7KOA**PJz$d+̲-Z3g{ db,#h sC5Jx$;z|@B%s!(tOVm?{A :r{x^ XD) CLHyHuVas6'; ֯֕r*˘Fy0v2 ˒ى`DTn_r6qX6{ԆA3|'S?1W.YqB!cUǬ=̹NRWe@#ަ]Ţb1ͪ5Ծ?(f"",<Ǚo@ECĔtnSBT4ưMdf2a"w4{~[M[̿4rȰF2 xV _Wc&"5d"9,ccO+0}3',^}H4hKiK3߹MLq!_Y|:]`N,ZOL jD@`zHx_+HQS.G*&8G6RFo &7+E_{ў s3|\p?<(Ԏ8zTѐ#*1l'cI?krHv Z 2m _Bg$bCG /F~PXf.oD@,yf#>FJ--@`,iX#gd<2Mݐ~3ucGo69e#u ם_n<;ĩl~As{~rG}Ab?ps폖O9kW8PxV o-S qS|^֔$,UF9G;LL|J ğP>^& M(Jqk|"3yζ;N7|f;Q Nu:lO^ʰgZ֕IvT;88>jχG q`σIeJtF" \ёRúeFZqeȬZ&rM'a_*xiRC;k$Ȫml淢WvxZlrNn-ɞH7q ͗ {Lp((Ƅ9 27ڢG  C,$y֋Ve+qUédܾvm| C Us~_z1!`8s?LQyj42(@sc/$nRiZOX@L0!ژI@z?eB׷͘> m vUw7qXO|`).ī.5:-X9R: nNGp[}Ra.wTb8Oȥi̷iLr-{~˫6t$ܹe`KDBŤ۬b: |:k 3[}:M7ڝPH}b#T /ѣj!ӰVbGܙ E9SWiw!z?߮Nwlu6>& YdFb") pS1<]KXj7{N 0y *;%T^󅟬n%!4ͬKy3ؙ`R,X ?)0l )(M F$9HːBfzmXF*w Y6:dR S:$}ea2KBwQDG3W8HlwlM*B=JTw}VLRP+N{L| tIP B YL$RsچDwKH6$0P_wȂB&:v7&L31{;>lh>Z-K% ] ^ EЩgA|fX{ÒmgjQ=SK|r݌scVNs*͵7Yxt:볆!Ǧ+ Y4ƱgU<Ӫ 5ڻljŜpθz/I/^} V$*(<3{\n7cz3~g9L_n pvo6Pr*1؝cv"KKѰzPB-w݀V<9;):QR -{2?eRG(dvų]Fqr~@Ѹ41**5B GBgZ"]B'mxCGLuĖB}A7y S$o"Z9a#"aH{)l6MEL.`eJT!?,-[,d-'5b(HY\׽\0sh F9'x4`H{-m7w֓xmi]p;(STx$GyMI92u}Xa^V Dbo1U @%92uf\(%uRQ >j;qf6Q 6+P ϐ.f_a _)LU9tڮ !sDt*Nv u?}41vs yzI|iÄ*#vdcjr!?v4F& }#_rW~ՏOr֫Msąu/N=5"4m =EϘB'A2W$8I09{ߎtllhhk2Eyܥœ [)pzY¡Og6%c7Kk^=X٣~fn=N?rWi7ģR*s"sEh&-붅;G2ZGcjs7E!Z,ܢ+_FTֺD\s]B%Jv p1t4 —O`\Thi ]-Ȗ +?$Q6J<*00Rb qIWmհ~"gd=7g?QbF@Un>?QY`r y)n!vy10`Sw*|ُ`j,L6X?;Ui2s#taGJ08u%XDM_ZWDr6Q}yX1\B-$~`=sdz2@^.o\ ί0\='{ i.GhI„ ! p=/rKq e3zؿw=%fBGcR\?%!X_ɡD%zO6>p݈mkn)-~Dr7 F%Wv sQ0Ԧbq7Հqs#Dnc-q{8M(o~D߾(k|8Qʈ&I5(e.0ƨBQ#Dha^e!To3m` cL;a6B)pTgW|@YgAU;iu e-n *HlTSB ?9 ]u-?SV,cTvUqт\; !;HrND >V# mg+\B=Em[ҍ\-.n*'WmeUև.H 19L%c K5ڔ'Xh'8׻.2T/I fPy:̒ExxZKI ]jXAMT!6 ;lj9ɾŐq$Ȑ{XFA)l`x=]ʺs:iBG8ޢ;N e0Ws|30gE̝~kRps ) Yַ-էř*XJ)*DžiBZ%A&UI^=ќ]c{~0RK$d>7H䅯s*\֣)FYlMeos-ab%G#6U\)(GiM"b㐕DGvg4dJlcCрW!ƃG7V)옉*#lt}_Qx²5{,Q?Mq;"Lr7y5nFyU 7._u: ` YzI@w'fj0a7wN-ie%!Syv!gp~%/T-4=x0KDmJ&w2L:>hw9f:}A$ C0)SJD3\ߛͭ(^"`߹w$!#of(ٝaֶ^֖M`P~2[Zm*<~vl塃æ'oeE8y^EuxY3Z׳MKzN+@$é(]uc@_5E4<=-uH1@¡ Uxɲ{xl=IUmD כ[8; /Yކt#n,G{= `ׯ(A`}Z'{ih Qѽ!Q| #qzɄcL%D+"KLq.6w| ؟xh5:~ͿHiJi]ήBPD!!k,se_JS>N65GSP1@9**[[4+"!UpYG1rgKrj1 rƲY?ũ ̻A}gzvUIK߾ 92U(' KU&7͔R˞:reOU[|527,`Fp_76/*6BCM)J2NcWF !ir#]hJyˬSv{14v]P@j\4{ 1g^3;ݰ*o!V|`gpHkA;Wq*'\u ^V ]/ ;F+] )3B:z'j !-pJ"Ba&R? oFf vUP4-w[pL,!l*iv. LeMpyCpDf4Ughb60D{]9m,O%'}XR(}@z/t-R8#EվIH}a \W= SJ(-br]`%~ ˧|||b@&_H!8"DkC_Aa0EOjC]yI~ lbnk:oR; UssC M  vݬ/ ZaK6 y"0Z]5%mDe3_?ۂ8|b|; Ri ʊװ=)"Yvnz_n5@0r5M9 Qt^=L E-iH p4`,km+n> C|n}d3*i4I#-T_Nxu(<`L 3߽-~T;b0~˅ܣ7# l#3 7H1NTw\ G,―k.h6"`6DHoQ=pi-r(7?o6+wo|u.kKp{N~O0'|ߓ7}\9U>ǽ "=TrŨx }K3tI&>.N6eSAr:tm>-xnk.POgx}0mm}1]TO{6D'/fS979s}a )/%~qZsyDl5E~Y@);FM "S +j\`x{&hA ^_X W_< d+<~'`/s帽]L')>N' !Fٹgi=np^cK{vxA<'w}_5EvknfoyZ0fd]ks_) 4% $MmU1B?Zu)湐bNbP&܃m!v-`XNyw[D:"®?-Η!>ҴgUTqYŚNO0.E}_@xOncKKP z(|9UK,+]H]FVE6{5ȈUocy4DnD=_Yn{UP4,Qt1v UkGQC.i52xƂL+tM?=YH0Z9C=$3!3DU ԫck?@eY9JعE.ՠ3t;L.tcĜ4-8[`I.prE/kyS~"8f6Whi߸ZMaHZ ?L3EnGZ(x'W@)G9.v~0&%V_>.wG?z@r Dn7/j#ז7ZyOLGe'r<Ʌ@U=!d貔 %J?P 8I--&}Y!P*^-3=rA}'"5v:x /L ]2~fxY˧ro?>5d1Jn5`9'^ud]b!C  KXǂيds0ōMJEZ&pp 3l,l;xE@$6[ن~;:4'I % |3pbB ta׋x>T(Q^i)4 C ^4$Q'Xf< 7OJ-#R,|uA?_j=lckG7ԉL1H0lh)/L5֧ӳQ#P!2nRMD\mto;Ur@8Aj -ypo aˎ*@<3VNeJ(ax&I:GV缙o:45ڠƍ!EVTT's2d$KpAi}XR C)tlcf|y/<D4S,bwC/p* )#rیr^I†yfN_os:8l :ת/{$ԸʂqܱUU3} 0'xa|s6 3:M hT%ٹKbgˬS[C<He5'+i MzTEPgnA10WzM¾ξŞW,A4e499(銅 ,qupY8\*d >c[\Sa\I؇tYfkOK\&lwDy BNcw}G} "5"mS֔DR T `f}kۜ@aD~GqאHvn/72UR23 F*9YkyLoW{ʳ'>w 'O[Fj|pE}aǮP2ʩ }x7~^w \{K iך{ -r5PR  >[J TZ愖7%]k(\`2`1:L6׍@R:^uo+MU*P|4>x圓>̣OU+-I蕢XIƩ:->0ců%J@f'k\>I /ᝋz hTa;/e{ ۑ8Nʰ=y=MT7.W-3 @ƮBa`PEHĈ9a 2dXޝ)"np/"D܉ϒ`k0XGV%l3^&؟iOJڢ?P8F_'Mk&w%+v@UWSm왺<+5RDs>6o8v|Ēj 1|掆@LM|-Kk85p:_|:5M P԰z0^e6keY|v!+ o-TR#ir>ۨE>v? ~aO@cܲ@W̃T<++@hGOyKg@whVnYXvc%etӌcՂݱ}/jA]IG^ߝ }ClJA0 }뽓_!>qQ7"7fj熥$'SDY `aQ5gy`o [#IDo6fO ڽz _ ,3-MXL?~271jgB嘦ɟ&A0IX) Z;Vm].#`GO'3s L@*Wrk0'[ Jba=E3pSfA&B|@e}- kd@m#{g:g^_jkc| ZqKw#a ǘ1!}[.- l CA&YpmҟBV :oqTu{/&TpH8UO?EvX_6ʾva&% FT"ڃn_`:k|,v{HpM{s::$=MXZ`}6EIcTwh;\K R9ƞqWm)ֻL"D]k"Q lgGFxS43I˴۽-a|j!ȪˣGln@X+aIkb1r846*ppt;ϔat 7Lt/KDzߞr8#6w* MW@6/'yYcIWx{{#Jnu%S&::$U 6c\ `aL5 DOʶ`A3ީn,AީXdlAcƙǥ+}kvӄ> 3`ygYԆeFj|yhO?aذ<[l&wދQA{.(_Jb"U-OLU+$Q1gFs6CH? v/R"B# *QЙe]90(l["Wf&O}Pu18F,ڤJ% Y]+{9&n!k,LRtBopn>R4VV~i54$7ݻY!o%ٴ|Ƈ8Iu UW5^.Fy5;/z*S+ be$!0vd$i˥Đ*) /G3~BV|5Q˿n1/䣱X4" VW@Nmm (v9ӛmwGGq}I-K cnlP8R, $UGN|5_>xmoWN|? WgI, 0V;cĉUg|! . }YT/&AK+ pMmJ2b;iՈ @KDFkH*m0_[πUTY\R\RQ,g 65 BNjf7J=׬[{6?^ӷ/ 6GDc/5@C6Z0,h7(>#4 yIUr_¾(^dʩ8kģ5e|Gl~i'"H7͐HU/8MYY"/L`5Ktq$ˋzlkۜYv{kveD  5Z<>yQ1PRV-oeto)v0&{|p{ \Wh;9OaQ M8V]f |7{YEw&Qt> <շ_UV=NEg7X 2N_נ催aOxk[hdF|=A3ڊFv1ça{K%,W蓫B9Ӭ#i Wͨ=0XV >|l.,ֲBKKf fhn0}-`(k;yf9^!aQ :c5Pc(k%JPK,Ȝ9hQxB(o /y9Gjcz{2Kvu 5m  %X+BZ/xhΜl40)$lx{y7{55n*ߙA々 s϶A6an6oIlnτe oK?,NȐF`t2Ά{8 ;,0AmqVYin&L\Xw:t,n:/jb 36(9-+9߂P0/4\N,끞._3Kku07d'}#5.Pi"%nc*¶ =wv_^|As^`ӸHsߛ໴+4ׂN8pX@zxL+Id_&8vOX5NlxAFsrWF(QS C0_ 쿆U$^ynv/@`1W%]Onz9rGҽAż쾓]4zO$W,[}/2tܙм䉠ΆR}<9)C/v!"▎@[iǞs3t΁衈!?R( a`ɦ}(FST1T.G=89.ʏdLFCT'.lR@h#VӴcٙ<@+Ad(BM1NxSP#nHƎ%2t U9g1N|Xo#д9sTG /tjVC<3X!O~tk%cM~-6`m:̑A䢷zw640w#I3)^S.:w "&h B4%i vSCRH Ǵ.?EµR}l! ?H1' |~K8 Qy@~g3h U t\!ˀƲCӲNV,_v+EkhoM1'CV DW XOu[(VXR!h*EWnN+'MSFuY#CehR^|c3myoo>m)GwSgrMtIˬg&i/e4;XXdciݯ-B;쳉bHoTOR=m,P״ OV V"^➯v-/cFm)rP3&'%  C2O kos(g_+` 1˻A3z5_L?T8ḪTMP ` 61CU+*\W{\b)Ӥ!p\IըLQR=)fwMG MPseAʃ+{HVX^8dխi/[Yh,ZQZ?eq8-EQ7w6J`E#^c,&fOg.ں ͠E?Q t`OL/lj^ǝˡy&edEu L?S^ta Ѿ^?)n bZ[JDnS"cOMP9)`NǷ%+AC?w2)p[WF[jtMClD* ?ǹ@γ_FUWj~@Y'$PGK%継@'=[4X#n.?; %a 1!k'uB&ϖCE/{X냵.d\ʈBPW ^hA {Ac1dXᣉ)*-aPӞ#~B^P [8 e=g>b 5k3`ʆ\\ni|"YG%DŽa\W%?dq`7I#1|5][_y :BȌ]F&)9{YcE J,]$44E͂&n`43uULy>(`sSrG(Snd {Xzֿ33W'%9ǧ+:^UI܆_j&LitVN6\I0?;k3t9NY'sOu߅s( 5kU%zB }u]ڤwh{ʟ _lb><$įEWXWֽ!#2G 7eth *Em*Y| ,gD4#S/zʉ3-S%)H>knS4^r^"xFĆIt݃ERyHY8}-q|A1ڄʾ͉qgq MͮgA)]O/LfG)s GJB>_ x$_q8X N< U`9[ur}5 T,u=[`(]5A%|K 1JA}zc .?Tus'9XAgАYgb w*9ī9 rWprS|Aq"sw υ$ï| ê~KX?v` 57+5z'bo.lɈ{c_+O)FS15q}zᥳų7 SO:k\R{D! <[3k fT+/ Η:5J%?yj4J33x#!6AmbO8;Fɉsѕٌ´}%3U2[gEA k7ӟZ5d1 }s{}x; É,*|9K!=`ldvګ*Xq^eұ'/i Mjc4{` ߷Uh*=ȉDWb=nd"?U2tg0`uKh.R=lK-s̟m:ǵa ח vbU# i.]YFET;kYt\ݝ&x!P=yy ej O4ivaq/g.}i/#S)ٙחͨ=_/0A\qE݆D%p~'W2y#a\J%S%)^ 2p= ʥR.z[ċidR_=*+(Iiz; Iu$\IGۆ]W#9L4UCI7O LUQAcOSUy(:^op}^IH^FEX'ɍ Cs+RzI -.g5EROy3Tn$ͱsOnk-Aa JnweDF݌+"ڀ޵4=p$ŔXAM4#x~rbA. sv҈fqze?DZإ9Ͻh.pqe;xœ$P2*bDn)^6O)5oTݖ/Goy^JKIʅ?-_ pPAY%:>:7 D )Qñ˄UW^4}o $Mf4:^֭c>s9 bT-Po@~rF /Nr!75,xgI푳//3w?D|m oҨ*962ݙ/}\?t~ң}r *mo=+vCS7QNA[17Yu`f $gV7t7DE]Jc-JjIUk$ aA jV-`]&?zJ* L:)jhdlDDSoXʇ%1%6wq[hW3z!(Jٮz+!SʈF 6`,H } KfL$g*g~TEgBJՑȦ$B=~={`G7BşbmM߶xthREZݷ7 xrySUp ~ 1Cq= 7vÙ><| Cf7jCkb%D`_PmmLy<վ(`+%YLr1A.ч~xtyOA"?^Q/:(㙻N/[GI؁&(55!4S(;,?\R uu㽳|2ȀFݬbXLk1_vN.WzPZYxnl8&дsҽ42O;}vQOp袖HTָ4e5Xh =Td7L)b[}%\Q *DoPDFgkkuI3WMʽO\}ܗ#P{\,(_L|Tu{ >.8t&`]2˷f#oUC઄=wyFDȤy }n5ٖ?pO]| ~Vخ1&f7Ak&wTl3MrO#vL`=I>;%L7 ;8\SJ~~?Dh z?UJWv4Fbf3UXðge[(KaGw4#(\|0tmAٯZl>{})M:?j{ܾGËGNC5|.TS)Æ)|Kjpf}z z(qD]֓g .Տ̃؛T7oQ[Wb Qj/CZg7vN\%1K"MEUu AJcAz,iy͘w2bROu8Z-8\+aOVCX'Lf]G &:Wf~KEAttwO).WRcg6(٪h\ir{[# \;T,v,w^!!T0i4Fw0iIv* Yݒ.hZMGGѹqѯF[t^)GV9yvwrEGwyIPgޣunp ;'Ct@(iyI5-0df^8lhn^: 6T wiT,&UퟵY5%\h6,OUR67uS@~oBsBǵ,_ˎR0wqGI~#N3O"NnjTƿ!Å.Gb3c?nW[3&8JNkz1 H<~ ~GVE/ v}>9T{/Nq+7 }KtRVlPJ:<T(P2<'YNW'Nal\@||P®rqیɚkV q|a~,nJCl#-F\n"< a]@ B˟< }30f]dF{MyYRgИ/@>L< ƄرmEX$(;6ִ0- oQ#PMyw_GhlOE.$q ~Q :M:|Tk>@ֻscE Ճ"mՉ#:rn+-˻C hr{K'ʺ1sn{,(Sa3u8m8BTӸA~wvSaWSrVBw]sK Ga# ݯ n 6etU m$oWGd)v 8$ zS@Ͼgö ?pdLV.=M?qoizȕjf>x5C)ql)p[9w9Rցƥ"]3aWv5HqfK`9}%$63]qZUMbp/!4`:k4"̊'8M a{Py T$:OZma0֣0i̿HhW,5x;Qqo=~|=oc}yU);,c Ov$3g1\An+]7k j 7o$ :A` <6J9o ?,UmB`?lcKHNi6mc;WpriPn. vds+pVѕXN]xȏQZGIeR۷?uS2g1aC?:xKL} kGs[n3L3E&sw"@RȤ0OBIP@)ۜD\N+,+OlZi'S_B7uUA-<1UOf40ocxdE514 <ٹ&Ж H~zͺv$yó)LiI2+Pvm6BψJ0̡nݯPg}aӭX)T 怄_rԜYl*0傮uסּeeew 2m E 5UD}3R:8wJYif%(4 LUwn^zӜtJQE<]:*לp;|.CڊBЗC1Q:*ֹ {q; JPe”BYIxi)J5QgДƶ^Zg*f=Ö.(}}KևWDq&bqlFٳ9 ,rcCEWP{T%wńHcgZAc [?e9yOG#;M6_ \S=y{GnVU;a_82V~12+MO7?u7¦>ze?[!qRS1=:++esq6< |zf G,.]YT 䵝S YZJFtHR2<%V uNm=fЪ`p9Jšˈ7qM`{2niԛXE$PpQ<~JzNmhFCjlXU2OmcƦ6>^'T kt~&%S/d1Y=PhX ہaGW;U=^iVRєq>zVT>Fծܓ PRL{қN˝7ό9M9ca=W5g\Zn^yw@ W6Ej@oF0YW"5.vn|(_zEJ6rZA_t\I S*$l7`Ӹ= RaQ\qt\%aȕp`7ͭ{XovjW8HTOQ6nE971*\0]ڣBNą`!s殲eճVZ6.ɖm 39OAJaP &%P uTjo`bI*'?\Nn8Mi qH|*rkۃ>us A̓'T+/; N{vX(8zRn?aql\"Ge|d4׃CP{T\`>v]{+ O:G]Ul`1A9q,H'= Βa aUd:E-uDX|"5oˇR!cirRL>]c[qgTϯ[?B +|) eR8Wl.^J4?C8̌l9dɴHU x<)mu̞ĭSHh| dmw DUA*h~>=Dy ó?>95ny7J0!-1Sn+w_;N羖O bz!/tw:83#|+=xU~H\k0X aV#M.ԆBĈjKj. s%#SQmƚ"ȕ'X3ʳP9XMc~Fv}g,;{#96Қ#͞cHhUj;Q(֫'ʃΪ6']FtBOX|"%ϘRns|O/:GU NJOl=6{l)nf+vvƮA3E`ҙ%ACUrC=kWPba_(%pcRFs>agOK>BW@\Rj#9wN%S{/SAذrRe)&WE8eWɳΫ}o1A$//4bl%lqZB􏽮D,-ՉI|hI+Q 3(DMq$B{[[v Ci%) ZWV, g7X޺=xқrOU$)Bcl5AϐJm/1, &\\ȎW;h)c$/PI5\̬=$ybqA1 b/ŅLO86+iVpe҄T_ZBj2cbs%. $0L@}ORk&*&`Vi/|X-hb"`x"3O:*[POa :d?kh>q7ï wuóE>/ fj":=U$rtkZdBȷnHl(UvR pw L Kov]:jP2+PP'Čeo/{F9aŷ| Ҧ*-4{ R%R0J͈$?+#p_3|0g:3P3 Eο_`]?l0)N&+׀Oqbj%B]LڱþQP=[GSC<%k85$\ JGeb RsƝguSKRGwͿwN:_*1 pr2c_%Ƭa֦jm8NSXveGۉ~b23(C߂٥9F3$П}{*okp <{i fp }մB!9B1cz< ^@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0IMKWIF:4@8u ue?"%: (؆X#OI\۳BS38'>@U)'vgtΑ+b.2K m^xf|:[~1bT0BV7Gc |_ꨖfB- :1[9 ŕ+X6{AHy[^ݳѺ˓Rn"0|,J#=:R>83Ogm#>랱2ݗ6z;l#PɅ3:,^urgFeLb\ڌ`е MQVWf H$_֕kzo{f\|5?:]{~0WuW~>̀9 7A9VN!)@@AtR@sETZJCvǥ!M̑k<|0Y욗}-Q)uO[kX@0?|8e(杻W1B>Fu,$-b}E֢:ތ "x't<kg#;˰':dk  DC Z2]}s?4cĺF#hRp!.ؚ`Chkp^zYxkydG 1+xDbxt+$50>5DlwM:Xtj':?N'sKyԽЏzN*nF:K%KRsVb$rŨ?Q/nRSIim7b΁BTt8+ 7*JjOa~{h S@ٌ0&&Ow+(UrD ޠ* ix6|>SvUU0fBŤq va @񞂄,Xґws9LqH?JEǞ3è g̅ X@} WGj73< /T@ȍKN8'Z#ol O#u;yFS@Y 5om$O~w͋Dqz#u:.&Ţ^oXI'p^Zq{^K5Q⼐2*qF `M=? =*WzU9CNbJP>fv|4 CO>W&ngk\9!vNqFK%5(l t L20`Xxp =. 6eoϗlFa#I)O}5.ɿI<)DNkkJ _}鷀\';/ ̄ Er9FZMXczL5O^ (Jd5 2J`֒qI5,*ʐZUbQWy |BuӔC'2!PQh$L gtcobu: jFMgtJs k+>U)$\Mg(=51S+!#>sw6XG,#_A7lTSx s4{;ql{ o82N  O|sO׎S0kg5ateÊܑ*BT ԑHQa\&6GN6­;a@Eb«ph4!z*(I xd/?fЎRwDgw87,J*Ⱦ*Yuo =}XNC (B xjlY!e_f4G Co<'3LߒyHMfbIoODS%'lGW+"9z__@]Z#|s ':FIeE4vze:X*Α-X26][H}LQ:Ŗ υgt5yf+Mkk{ω[ /ܞ]MQ 1H$>3BɜP'x #>T颈6|f|'Ia@j5Y؃@/12C9G}ĂWSu›`x@Z0v^#k1؜>sx!4sݛ >Cm7rvٗg]/ YUn }PU6s zQ"UAinzBohh%:̓n CN )vl&)E53Gv30RI"OT}`[l+Lx*?l |y"^g<^xfj:kX/ јteA HKї(| ?s0*- y=iU~#LkdjFQ~R :qB%nol)tDž )G 0KBVɼfl U ODWOgV.vCQ3&3HmS_ #HzNLCz6S{1+ſQ+;gm*0rnᠰG p2rBP 7xHj^Eh V*ɗ烇 DrۚeNZWM,ķOeC с|vbdg$$(nEL ?!vO O?tpFL -n ג ?DK?.kZc"/~moS(JD݅q[#䧵QZVEK |ܡci,>H6`Bbj|wf,\ü 쾾Ѩ(Z.F1M(MhS`={Ҥy%c_ɟ*AE -HR]fbӲ74'5<Ɂp'\7d@R,tܦNimY)F\pؤb{]cy)YGvk,T |ѽgv-0pLFM'JeJV F woimI7o i',= ^y!̊6ރ r ϻrjrc3ŖU94*>+?wmHP1lX ɯljZ]^B1k> eSeڟ8XbUA[݃_ꈴML9X2|iݢS_jJPR9:Á5{G>l#s~`+ [-s\d= Av&KS]: ďZ7BP! h$مNw9`U͜mv{;Jx3P w NA:F:D24ңá?u gȠVK<{rwF)g % Cmw* ,M" ї*twLT4i?0f{xjW(Z~_ȕWAMe1ν/c87Q46ī9R>}rO3YX@n̚ay5hWM)3 TרyLE#B6쥜=ᡩŷIS\}||>!;X 0bt٠g 1ĵ|ƜPFxXx:TD_BDZa?4 jP*&b 㽏Km4*k&{s|=*Tme5f<˅&C|v.w1J*pzm Z9Kݎ/97%vXDb,k? u҆J:CAQN:NX=vt^ (*JwD#xi<[]U=ڋG%623fɗ_'8.Ɍԓ;@qea)Ք@Rb%Ŗ B){*GI-yI݇pj@]n omii7,ZUS㱉ߛ^v%=j<%yaZo Y,~6qMVkB.{&Im3tlwZZ&{8',vΚ .#nVs_a9~6m0vM R71>N:MLS6c@MVE'>.$7J4Ci E}Bo$ 仁XZqGxz b@ ~Ȧg~Df#M`QwnXu;Df@> GQfs!bq &4Α HkM2]Uq{`#Fd6|,[h>j}o㼨dS 7fJr!jZB>Gc." gZ"^60uCZ!wDE"/L<&:^$R4Qae 2Ue&GQ1O R3m$J*xqQFկWt'Ji6FA Ԓ?38tBs 3&|{-JA̰V$r?I:Ys ylQG!e2%"PerE<= OMl0.[:  պzF)YxqaĀ:8$4H\|1L3Az: " 2HؚnJ@h:1h%F]-WEK+ծRApoq߭H,N:l= 8@#ZX Wo\)6N֖_ 0)1 SyѺ/ Rn'Lha$G؋}hR+Tow\R)*[ocA3ck;)Y8iPa7X& )!r q^WƯ0 s@q<\ P^5t?rU4W#.;/ /K*^aOwipCL::{d^@jMku.`6tz'95i).tdXI ]#9*qjjFgǥ^ZzNY{هYµ3j„Ah$vg/@~ǽ)z;Ig5`tC6h #a8htk3ކ殂XWop׌P{Tqbl}G`tG\TJ]傄!+RK_- vl>ljPu|hvtp*+n.?Fx@g] _^ѠH.k`2P-oYCV7Pl?&ׁw@b쵈Ĉ>P-2 v+o Pz:Q Ɵ뉶I9d3*& }t8˪@CCu̶zWdY=3-+nt;E6 ;wReF]՛ˆa_~ucgfg-Q^WU4m^s0&9 u4&kٕK߷x'1`ӛɇ`Xyò"n Nnh|)ZH$ 3!|-gN;5 11"9' kKI2"TؒIˠ@CO ?k \cdQ6?)-O[('D0{Pg ֪%qx.+Mקk͊<x,Bxg>"'evybSS<_4)7QX=9/ûQ(bt9qc<{BWyfT5/(mljd2 Ro6: g1qъeսpIIt3}0xSϿO(MfCZaV&~.vqѫG>=qܙ'Em*Jir$?"].nDzXާ8H@ AlwhU~{eEQNȟPd4oqF_䜭* 1o70y-Y$B.ֽ/SpDu|*Hq[3Bxxm7j;[BvMlXm(C,AWW]|5oiи`Zpƞx&ܜHC*\UKKt㛞#7ޑjN3=S/j rl'98{>T"qKqk|eDž6Ug K ~GI"Adsw0`ZSu,Ǵt6׾ D/ ^lZ7fe^ MzN<}+ai-M/W@JC6ǣ NfElqbZA&;?Z(І|e0VWJE4[ӉŦ ˥q ?#}R|t)>;_.j0qImTCEocV%)5a,GZT0!S>ET^1dG+ ЩľY Ϙaxo@ضRf oEY=+^stvsJ$rKw8>!&*u?TX_}%re{*Ųx?@=e)x)oW#@I $zvg3~Txz_éX.W!opS"iB7^}@[5 Tt-|L^`y&K9`5]WH WMbSAK &*yXj*:F9T<&0gQF\y-ơm#qWchj[>s#EL|Լ됱9ZO_A䞬brx3pkߎirSRAQhfDVcGʼnNN0 d9,7@6` (E9q鎃`"WbZ?$h Z D63kQi<>ysƄafj||sW|"u4?w=+K{{cPi k+B0Ebl|]X-BMCaqHKDP(S bzq{©V.*޸TuhN^y<Tr3DB~B Sy0Fj.RhѼfPBAҵ7^"i{ R+Ϣ*I|0 鎓huܖr: _/E 48>h3R.CQ/er)TjS11pZNH (e*G+u[qm!P B." Ra$k!$.i1Xh)d0  g&ٶk J] ث?|8xXBJV{i39\qO#zb0SSth/|P>4P>e@`Jm!giDqjӓ=.8Zˊǧɩ,Wʒ*r+)FT=t&NcgD!ce(>3#(oMІ'|6z A{6gBεcUsئk%;;" (L[%='bve!NJ }rP B>)o/`k8ٲϝZ\ ;U4Oݡ hB"VFm&$}Nh_9E(6 >^H{\>W0O1;)s׫V"Ι P8hKq)t5Xa$"Y8zͽ.R+JwaȰM? `e ǺK}5o }LC1X&6ptcEaZngQ3yیkYYg '">pjsI%mh{͊^; :%\K_!dHηvr븏9cßQo__,ٞ]nCD\>IpJ;/q4W_.ּyTmVu$l^UTP%̾X^vO eR< 8@t#OFVTt'M5dahJ珸I0,!bל -]=# :3A-C(E]YFs/mǹU1,@_/NTVW3_|0 :.*o|h?aV*1W[h3B|&&t\c~=O`v()q@n$U`FL,J[A)4Ku;_qx-Z`m$7/4st j3$vXKSHY;d:2pJ)B$j@/khJ fM᷏d6iP;v):vPX[<#7)I22҃EJ..\hUV72-i^̱?r {~"h?͑/\֖~@:M9':B֔[QHMB>@l% j<wy8%IuI' JQSmHcT##/Z- 5R]hoYl,r낖 j7__DEbB2T_# ے3hYELh+ lf@Fj kn?/Y*+#`mGEaUGZy!cӴA(LJ[N\>yIal_}W%OdIӲ Iwۦ$_QQr/ crP}M4p+ N ."D$Wh꿇otO]v6%+ C}97ddi)!ʟUw:,ԟ'];u((@'M'G)D- ʢs/6C?Qo/eVtS5f!c$Ը_L Ғ|]`pʏVTQ7ЂYwʇOњ&"Ya! ev_#ef{,{ eŷ]fnaTq_WgBE5m&k%9t%|ǜ^˰h70xݠJikF-PHAL[|S@T"4QvyQmi笥/jZeJ%]Ur0" 1kM94:>%b-t35^J?{/Yׇ_}C%4`@ӽt-zQNU֨A; ޳9v1C7Z(&<`9]!yǪrv,m4A_fӋεʬG"6ˏJ8^PhMjd9yr|CάWy8 @n9'UP#X4./&U57yAK ) V_[?ns] D*}v{W ԴN.mEYL7$B( B staѸkg Utl:/0:3:jD( "Ocg_HyHᠮ1 cQ$}}Ur1'ʟMV >Q33Z8h-3ш#qzD8ϴa'KKDQޭo cpS tk0.dzi_O8읱SW둠+ ׉ ka*_JS\9XBl\Syr AyN֛2鰛* |X'ڶ g,>l63 Rr7 3E-+u cΡ!0iS$؛1\Gshz)1RǂNunn KthcggG_<'dde#2P]Sb2| J8j@@+)Tv_o{0N_BVwyk7tSDS o27:XJao Da @/1K~BGs4wI,;J>8==@V$(1 Sҕqd쮤Ȕ͙YdA(Lc>J2 _;پxps++:r<@K#DnEʗsֳ iL|A6d[=FG7"%b&?;ߒDdIqu} pQrk]muh|E@i5Dg{|<$xUM >q#޶ѬuTG!y-"&ꋺU&Ϥ٫-Dc~63#y%ܝK`mYZtsqȣ#[ C.@7h57+O! M!j5E^~=ŁӽӒ3M ׹=Ai_I O)|4tUqj~u߭)G,v{ "&, 13)*r@I-鷐 )l;60VNV2l0PqqUÚ ngUpӭ-A zS8VyI2$sI .HQc)ʨ='Զ"]VHȬ2`RJC\uI{ e8.e5gU {fJ`.w=SyR9*IPGF~ĝ {6ăkNLJeH4Q'c ]nkjjƪi_}۩e$]M'ًh Y6n?v^÷)=gDel>F2"^ŵ2$YxgC]%La 7D|$_XB&Wb,DKA&S%\'}ԋkL; dY^؏-Ѱ. +N9Y='u8TM]Z=|D7aZYV4t*ڬQNfѮiX%'t/>[!۩E# A/.(oSrk@ЗDO=40؂<=B(cԃ1jА"[vA 5 LRey9 ?[* S9¸8 T71ʟRƔn<&QM²-hc+ϱ7,=>2$_\s F Ը|~ 5='Npp!J $J gkkXbMK5{|0kˊrw#XD/ K)"]pC@Pf!JrEQ{[U\FBKIi]UeC=^$zs7VY*&G3rhN;Gyq?Q@S\#g D05EvK|tLk|q9Vi|^\e B݇y̳aɏ3ș#^ ̙*@ha4u0f9  _@KS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4 ѽ8hĬoh9^ `z>ݳME/;㏖ob!,Fߢ׍>m\Ut֏UDu?F#I|:u %^=|Oٶ9g-BN3͸Ƶ0⃤K(>YTn= (`~3389Sgbnci*^(s:4BX{g14Ёbo>/P"-s C ,Zybh72m8 oW"d{'O@-V[\?y'ϚO=Yϸ|;D'PG,&h_fie+ZY),gw%)}4ýB`&#zM^5t"!N~`?A % pkT>!(pSA9e0- 2q2Mj0#`eA* F[ȥӼ~> ^84ꐒzL#XsfR0ZjƂ)ŸZr$Zb\;n7Z4,/KZvO[LvE}k·ʶ(xHӖ# ӏwFἝ+&͒h~+}Ro*'hdB7u)K'i215 8@qwD:# ,Ҁuɫk۠SXWX^r`| CB# P_S"u,S$M9܌']rL@leQO[C@m_wa`]xh˂ö/-#Lr }'kV< u8C"yNw1nVY~f#u31 "\l~Le3%y.5WTtP(VA<OU J`2(akOAvo}GoyqML e3r8 /x؊a BO_s~L4tv3EB=4E$ NfĨQmU528qG{7}jn>@lㇴ\wP.T44)F<2劕>|R/v,lg! s3ja?'2p(DYvŚd.lz}Jy QL+Wz6n{t6Dw 'Z_}N:x08Dܷ˖7^[ސُCrqc]J\:0+Sb10ti3e+Uy.n/u: (#KЧ% \9@ÔM|!Hi <߅ hBʡMueX!'rYtVSsRǔV!1|e %E`lt޴XSGŨbn/cuY,V%!4lP8|ݏ^ahGlz/-(mzSΥ/j[`;6$&ΘQ9E#kLnD*E~Z,M8{tH7nbY{!|*㳁ύIϟ8=XׅKMptKA _ ǘi{a7.4/o<*4뤂/u?4a$9i XCh4RǬHfF5v.xai^ύlYBPǍ6ZȾ6U(#oi%4B/P.Sihܶ]d=7X+D3{>9IZJ_^ :󫃵 CĆ>[&aϧ Kånwr;rO«ώ@zS8ҝوIKz HNWsr"sSk)0X{ Z&27"ua?_944KrL\qI6$\T, k\hۻ!Vtp'Z>l:ߊV8/i(|Hr&Fb!>1fjB,ˏ^S ~7ouĶhVNN6nv~6q'A (2``SI(h8k:"*HKDpEФnwBh6zm` z3fWt'0lD BQ>_zO}Ljqyo 8む"U# RoMq -yF [FM#OӫyETY~m"mmRJ>(T c9 F\by?d-kT8%4KHk53_0)7h!Y+EYm{ϩZX7)6y$xl3V۵'c>*1E >ll@q\xYJR!07'ֿ+6[reIbM'Ͳ9*3GyHefvUFj.tqp8.)YIۢDp n9g`ydcpy1R* Lk3ҧ7FlcBŗNUUϱ#/jli3~`F0hy"0/=33^_d|>n2ofKM$|nL+J 4V:fqȪg |ꪴ[9 cd@f9p]y 876,K<LJkMi +&efjm-T;_CֶJ`*u2iPѮ҃1 ;%њtpBQUiH[ĉjf]:\+q"D^QZinX:k\/I./$75O Y@^֊Eu+u=/leGI 8e=ڐx CQ RuǷjAG7BN8u!/^J2J+[aS"7 sCa'z^xF}5׋ɔ`@{/_Ak}4tgA_ b9R:#áAv-6B=hGԑ}cљ*U,ĭ/! ?j`lYK6 ~{[;̖'\ 葅hV' G3Q%$.*%K, Rp!#.t=֣vo8g@lI"F:9ޱZl P4<|e1ϛ9UpY`qT>Y뀗E݂h9o|pe?wV.mJC{jO r wy\A'[J|]&CI4Yr =z0,.aW= rL%ezI|>wP/Fm0z.X9_ou4rQ-~je>'>0VF'r>\ ݸ#T%ϲ¾?5p~fgdSf/ U(u+2o쌘!\P<>9A۱tk(鰿s6=`4}q$,&SRW`[P6:u}3{vͯ&Ò%_D`gKR4\~S:Rwݰe0jn,7!h K$_T[BumW6Bv\4a"4 a? , ?v|'~N#tuX8( ӾȊ 'KXiff$N>o[e0dX5=S MAѶ%z:;#_ U2BR^f%3mXĹ2peceWn *;_-(-kEVШ!Wg :.d>ڶx[^"fJϑِܒ{{'@jۻpyVu!p7_L!@}vGkv2k<*$#ctZC߾-GWR:,Y_DY鷂Z-XboUJ 1 FE.%ԣ v#D~ 3'nUԄet&y:$9n T٫|le̛?W+N>/-I?,E3̡cD1#9?èba t`N83 "|z@acZEQzFĚ|`={,E"i;Gvښ\pTFuxk堧O kTKf(1Jw;䗞"fwbS>?C̡5(2Bd%#k`Ğ%ca۩ޤvf+i.knCc^V{SoQ1B%VBC5bCqǾaH[=2 µu:EC"Go8gfn&'ҳa6I` J+DNDux=ư|⹯JvC^KCArElJ36: } S51fWXK[>nR5!E;0W~O?ۏ?iWwXv@% 2HWvpl=ևY^v͓p)_ OhQjUBf0 PW?05yC ,w?W;'u_27<{\%XD~Xp+^ \hL):yQ:ُ8RSaq P,MN ^f1;FtFLwI8` ˵ǚ'?Vil;HM*!e9.p^.߇q?t`  '*X a-0=LWt5Lϟ"ɱ7V3*;N^j$}ѬZ;굥%lxSWuU,]C 6Q.5bbGfy*ڇvPCIk痢&jG)J-,r_~v?3]tORL<yC x[M* {~-(ŷg',ZsU-' pסuEZ{/:>ao\!:cTK u04Ch?)O?o VG3shL:a0^ͼ*\e\~&5`LRjVM}=y!@Djͬǟ"o[<,76%iR2ʊodTQm8J/;1+ǭ׏ÂxK˸;.+FjdYEAhd4"B6bTMn|7uˏyAt{IOv3ח~,=4+~=@l@]$n2x]Ŝ$raB-[!9}3.<_0˜܅V 'd>#@Ytn;|`LifovN)똁/ qvͫ܂vi.5ʫn>c{Ҭeէ)i Yb??Y?mFp9d$TI#vHͷe qy~uj ]4þsxv7vU#.2/?W.ա+)s f"z3^SK#K>!p-[X:_14KzeRd,>Z0-mv '$MB1,+Gm5VY益#8ߊ#CS,QYvS5-eФ('$ixv~+~T"h ;;NZ) 8/9Ʊ YS 5u%K~3dY0Nb+6-Xۼ񍽴ky_[c҆#vCXͬ/G{IM5[k+積 \d~tHLspmsJ߲oI* ډ4F*i[*BA$IχfՁPS՝s Vi6e:e [jpܺ( W\ejrzn!d~gJ8##QD-ȺۃmU.FKSS׹T]3d03ox&7C76 uOk,BZK'i@ $tH%{ѵGoqZWYMXxymEUĽثmThA`0E<>xM 9KL|ho@J/~H},K|[ B 09c?U$:0"ND(JKI ݷ ~H'惂7Etb0/ juI'^OODruEszyyG^cu1% u.n"5,4:W+ԔQ$'VÅZdk@z^jK@Ԥ+>l:ݾ\N5cQO-$|'m( V ,a*3*N2hIB3U)Qk6a~Mxů1)Kl ޷ N4\O$' =;enfk/n)}h7E)DlRtpwDCOdޚ̋M/fQGFzx~'3{AD*o.fUG\opM}SXLl{j( 4v+7B]wI`Ct".Cs:At&uX? t;}3\rEgT>;uœs&f6jaș&|n6/E^9`1+$i AŎCPIN+#~yX5Jf,>r>G#v^fg5<WT;_F9BBȫ\ϊ&>6_(S #].XڛF (1|}8IZ׎0V+ fM?]Z"jf#W7PtXyjۉ0k"o݅#ۆ]zwPIvo*,Z!3^TtQUK;yw2n%t WH%_F [a ƁLwpPD{BR"q*ڬrDT(; O|5&|v  9~R &է{5;g$i.#$VwT AX\0 86`ie}'2 Dm`%o9tV~wW y8%䃟Ϧ~k\|>4>Ɋbux5њ킞C2C\De6;t&zZe֙3W#Pf}(oRwխ!Aݱ+c<.L=y鎿1+{r}_XMu4ѡK#3BdZ hSY"~\د{b@ )gb2@ٝK4h~Hs.ԓL3cA8x MS8ifJ(|>4p` kkn왳Tb m}Hp!6+KFcj~}twt YJ\GJH x1$E#}DxLy9 sE|;F> A/IYJG ,*mճ䳭SGC-lQhA=5VX8w>t\j<|3ق沀ߍO8˻JX4_5H.K!DhyLeUZNŐ+%P{lF2H, K>=7C}QR]0M7=ԬF QjNh8xa9WmvvŘLTKR]/_5-$E4e ֒^Gy}:G'F{,K=nrXaVܔ#x>SK3VY_he=I@&Vw۾NXYf%]Yfj=qP5nH z( 6n&O40nfv(j K(\S sϢuF61T3|q evw"łv_M馟팠!G@\쭪uJC֠&a/HќzlQvuw`\QXU.N1:c"Gf r?HdƉU%G8L;yraYD̼G[Vg ?QH& MP VlZ0|W]ކ^Y=>G'e_mY1h:Abp!cT(/%}|A?n6 G[<Ŏ8/  ;O tშN(VV:LP;ueJԊB?n c^w Dq Y ߩ$~kBb ok.SB uމ]8*RY߳gVe^3!=S=-E;}K"P̮BοrQ2ֲꚵ^pAK%U } }Jۅw"^7bHKFޒʕﺥ;`jdg8Qŧq<ѾpN$5-82e~:^߇eNF 3[xdZʼnh p1ܰ0|FƱ:~G8*,cn!M ÜutjLN )s}5*y X789`wiF[rƷd~t)~n# ;:xEqK?!./st_Sv7` uW PS=Vo\f+s!iհ)t$֧؋C'B?)jA-{`J!;[&2}'c`p[9~C}T$#oaX+~1# C$k/)Gb!?v:'M9s@'MLDP7?RU]aH&½K:h405B`Қ(m\1A?x[OU/^ pxAܑՀRF"}>ZM tNԂPIlx8}ߚct\etÒ8H|펜diIg}~RkCNuX ,p7W+l 1 ٠TW_-o8;H]גaz:Gw}]' T i\8k4ZhY!OVg'A=ͬHW /?,yywq%oK9,G# 0 S.*l]y'hngHqJI3iqFRq*f>Z60PZN )䩊F곽6ժ|[Ⱥ)-lDTp6~G c<[ªI[Fj л#U&9%XҖ3i;q1?N8.`:>&COvX곾#7WfE$ԹAkNaZ*!)"EfJUJ͒9Ĥƾ͠HD~8wfL̍ Y6 v)eՐ@+ak雀xvV:3d^Ahq?pV3S@XT!);^ҏZHIRL.efr9l"@w0$C n`cXzqkȥ$H Kй锧V`\1,1*1]2gLPa8mS~`h8`է|bi ^nlot7 K22 F@MOB֌`ɢ\Q (iy*uV ?AZV13x5HmZ[4::Ox"I{%Dko"; Ԭ~,|2:AFe/ߟa;wgvjI(׸STT JcwbϥýT51;0x6Yso!{[ Tѣ8)'T,|B+U?s'O'sV8Y! TZTA$`>~zr7c2 2]JH6B/+C[Mgɗd!2f-uטDky #rxfq/v ,sT#Fxh=J{2@N֫x MVRSCa'_eVkX;P߯ЭNYZv5!-y}ג6 Y\`PZ7'[ډBh#3Cf6=1/n1;MAn#-ַg@Qj57`8EWxvT5XH4iWv E~WFiNeoiY $}KLJ ?s@f)Uh\ī~(åk񺏤K$$&Ҹ" ?Osųb)JgķS YaK 6KXOT Tc 8Ɋӗœa@YxC2Oa8> #@aDMz14| Ą ~2ǖuBހMu{bCa(yb磌Z,Faڝg5pΊ(2QE\.y-Ri$ h D`H%~p .nB_p|Ncr0ĀYqĽnChRM 92H-Pmɤ 7x)vղOB_ٍ$zMӚI.m11K̜;yJHKF/E|6%b ۥ=ũ|şy{$/KtK``€8'TXIUN0I-vq?)qwv;NX悝bu$~훡A>knNG7yнs4: Ef\j9*C%Ew{~ [xƿ Zeï&]w_fk(ib3?(l*V5DʴP΀9'bL3ahw#Jmr#bH.H7Ux$9R`?l!&_~MZh4@QwuP|U<'2ή5t'T&0_&FzZq>ceP@.IYS]ct`Kc,Xdj]nA'w;EYUn;礼hSSf%AXsļ̮!G-5[j5FJPkk^VIc!_XߓkL.k^}WXG{ +/v,Mzbܟ̱u@Pn4k 7+I{)k٦iyMz/O 5l ϟH}Rf#TeMA,Ct`;pga1EhIezCBVARtD'}Ֆ|9ԫ׆Uh'2E9`eƎCUF*(g#-e~;+?GsF?f># 1ʻ5E9iak'vkjfE8EF:]ŏn+ ^| V+GMmY/J#)O$ bob<۱ qn-f¡w"(.utVR2Kg! =トE}k z.p}jCr|H@ҮwعGb},XBa8cQ줮E-H;fV3`m)4ЮWE9ǭFVqK߸M2GH([h 6Eնy&'z@u.[OS5)IGqj';BxY) `AwS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4A&:4> -x!!Oư:h?vmeXޣPBrKaJoG8o[9 ۢe|dcy!\*76?.u\.u\?a ǩBpa'H#JkEV7stfQޣXwֶb+M՛quF+-bUD mC >sOǣk7neAuFh^b9[Qյ@۴{6!\X\Jz*FԒQFG=qm#+p30Dhm$_p\_!t? >X@9߸$\vknwĖZ NN8tuQ'*=p NQ8p#9旨i qN]՗Q~[|7N!.r`vo"8]>QOQ' ᰸݁qY"-G7:cW!VgzZȟ45, SqB h680-U(Z(lX([ŸwV< R䒳'p_ VRsEJj~Ō[{ Cid cTQ|ZP wUlhK&(`}e-9:3_A^~[yP-:;b*2˯Sg-sG(K=Mk^4`kdClS| -/w`_Q'6CYvӾi\Ej)k@9oIKviߋ27LK7|M<#kS-Bfu8̚Wu”F]O#95?c[ #рsS@?Yɟn0 |D0(%@fqC%W~=SO40]"ČS2D!13aghT#DEM) N='Ylo,s& y[)}H4E&^ p%tWH|@YC(gzCGjbx[vh &݊9bnYE2 l(JtM^wꢌ\gL`G(7]yQe5eT\i.U%y.&{G~nB9]O!#"8T{~z lϓq{S]m2FbGvI𩿓_5 6o$,  lAr)3h?)v* C} cc%IM:. lIuH(>r>D-eAs-0RtG%+I޳K,F6i6 M`eG"u=H`i&V~Rk>-k=j!QF9X]jA.~ d^o]R[?p*5cE4-I EURȝZH%ŠIڗ 2\N(Ids~[fr_-[ ?OFjO_ΒjhPՏ"5.,_ӂ9= X\!iଊկif;H?xM@Z@T<lzx= ,r TL6@;h]} F%8lğSVf駜cRw\ފ撮xMhӱ&'#7,`ڦ:7qigh!,iE6q'܌6.Ud8_PhK2e(; ԍߵ/ E< ^mq}Oެ/ @_rjn,$0^~AF2>f )Y\ϐŋaъغx]pb/t)EnssDF߳y ͌<߭,fkS74ZwTtc{HPv%:ʰb؋8Ex݄nZo#Cǐ\Q,W;CKm 2?:,*tV9X]}!N"NpAu^澷fh]YxI' P'iZpJHbp~Q?`O XVACg}k'!BT|՝`#[m.Ct] 1 eSeP02۱Md:}Vw7uM;d_P[r1i6BM iw5$t'QSD:z?Io]LCsQ"|J.@cӆ4JgbAm t8郛q]eL>yN&"S+!/~*i}va! zOR &q_2nn/MȤֿm/5#WP>x.fQnO(z aq.Wmޜ8/{L>dRL3R7hkI?V$zGV 8.2Ԉ*eY1j.uuLduw(gP z_&M$¼/;"v _kX@h.Q H},-6L*ĤdyKh:>X*]v?+c06o[5U:`׆sCyftGʦvߥ":.OpY@zs*t ,`}7Bx %rP]\ ΕL/͠@hcLᑓ;Y?0g`HvO0Qc{8e?8tBy8ˡ]e0 \ lǶol79_ >9E(d CIJYUX<>_`]S$FaҮ?b=ctOZs&Dž;Z`׉.&b"tՋF+jp8ESkܲRΤd?.q?GQ,`꺣Jݭ? wi$TH((5A$"O$ 0t]D)~09m83ƙKa|PsW NFbD$ %;`;V>NC!Rچ){mlqd}lSH5O4,NSoM80!e-M[æ4C5};*} Ʌ;&Y(uV!tA䶳bēEm "٭$eIt+(+r%+dyP^ߍZ|ASg466rJ֚"Vb p{vk Y=3/iCyx{iWQM;0g8I@A2e5@-Ը[jU}}k"/,3 LӽQRhsTd:=:oߢMMۥXye\Y%pν}YCQ,ʁ=b 24P5'Zbُ?c#3܄{?U4zp> Ysj>uKs?~)+]KcA2_qڡ~>׏YEJ!7__́1WG`//'v +YD mMEaĄLߵC# (?=N̨Br$ Z~qN?LNbV2[DtbI*>\"6PC+aHŜ 4ՃXm"@Gi+yJd0{1"c=r>?Vt4Is˰V09̙ g)Rg[b]t*^G)E!ޔVMΗh&CԷҶlcy` '3rq14{q~@(M?wMNL M[cJi&+vc @Mv|.1oVC"|"WߪhៅO%z>MO]V#M#\7`B4V T( ]0}$?Q}N GzOb]Q"@~;&2W5r*"JeyJQnBa5C_QHN$lzB8(};g1$3+d3m?Rs?Sya>|?çT ])N@C|Gx횦WWYE7m7fX5@s]MセZnE}'I%Wt Ŕҭ|l'#6[]z &I(V l<匥5+n] [p5$6NH0# WL4ko$K;Ys ]{Z  O6 a[JD1fPH(F#><\^&62CٌN.F٪(ҽXx wmW:Ӥt;Ih~ruJ}#3NWQ_5_n̡_LYMI$MAəwNM  ee:{(Zw0 nis^D%|YH ɟA88x;_'v۟!4)r_p24GIp҅3&+)]*LzN qS@rW{ &a{(̩;D*8PI }8*, 3w"1*Kp 6 sǎN{;e=Oc[\vu;o<|fQ`@_ K2c gNtm6 n=/[`6 C` ѐgy/$ U3WD "|xNs0*w:hDc3un&WNGH=.1 #a◗FY0Rrlډ@ *Iҍ!C La.7߁)4YAg}r %&ʼn E`.>dK5*M]'9h`7i)0i,_7UO ie3H&c+(a t߹]dZ|pH2N&uAu P_MbNhҕ]gÒ*N43g23䏣37'۶Ϸ7\}P  Y&.?nᯆwd7 v~ `O\S>낾u6D,o׺C+҆HS!ʝbJ9ڽ$g>$S oMyyu{݋LD،( .oŕy^OӪS՞PУ?^%nMN{{GIsSXϔq^q  W7~b#Hf7'xف^ob,<~.P')Rq:Z>n (R ,2=k%Zj=a![#p8SX 3s隟XҜfٕ4K ) EJ6? bI=`b wkI)mA_r؀~2w Vg6” F=\h(RON`2,}!vjІ!-58*&31u&e%sJ;e?W*MFiÌ|6P;FgW]dUL-ܩE8[D@bA˾mlAllYӑ[VAjAp&+)Zo◱'?oV ^ND7:wkשEm|}8Źe#Xa6j>!t|Azڧގˣ~׊W0mU+DoDڪ^Qp=A~K?G^ w.NFڔvO^<\ίL$jNƅr$mu8LUQC'0}I?e땙h&mniW &x7$ˈJ}_PESRG1.N1=Nl\ -}-#%jR9vr/*Z9!m_:L#KWT6"+u-࠭hy5/]ჰOu{11yJ"4!c5.D>0X8p2ŕaRn#@Fbd:Y"!6zYejvM#I# T`+\_Ӑ)ʐ4W4> D?A#ٓF(RJkY?kqYeiOA.=ԏmCkGUItOƯO cȽ L nFwr!tpH`(n;Vh>jX3Mk񎲴A۲*՜v X}nへ99AQh+}='/XwiTuqVH6 Z7+t,.; P'֮l<`DmR;M.>;[1}8Tܑ>yPN`='#N=oT]#̙׏,>d6hÃьYbIC;MfPmnv,|:vjGZm3o D+7LVxT욍뿦̶cjb.d֖ֈF;*UBumg@WT kc 7W( x^_9RYy 4aζK.HI:ǢЯ-ԗU? j/e5C{*!/B/BsXeg~aLF+eP`+uwMD` x,5dAI3 2 6l$t`?I~JK$9ɗL]%K(4ׁ#@|.ؖlmi+4NycN yS=^K(fYC&ZD[B 7@פn \s$?*s|86@Yckxe|^4Z} ۍFH!݃hkj~d7Yic4}\pop8N!O .xIDrRUvb>oDKR^EAsu<A7He8MVzbF +"e΁TgDךÅf])p g+Ӛ6ب J=62m0~̫@Y Y(=yPEc{lh-پԟ}e6n &PNU2BKOTE 3e>s˾o4WT1e88w~GYKW26I4|FqV8ˉKYHX@6P ad#@AB'~-L 4gyȺOdEJL= \>kO.2y5z-d2xm1u1 :C{6sήK6ǟ`g_4Gh#3e}Â[%y`N=\s=$/(}̢$1MM$̸X;_گ VU?b#^D–,3RL~S.q3\ y|LkMO`2),Ng$}&0.:%Jl':3[ʀ<:liEl q+Ծ$+kk8_T-ݠgm/KO ^/%c1=w= 2.K]rc~Z,{$Fzb ZD\^$ൖuU\/e@6h-p@n+k"/!\ھ,5/^ř<2hk4U<k[:)Bƌ}H6`A!vTfHˁKj E>̿z|t{b$og!J rJ0^,-3.: _3{^Cg *DZ {!2)Sx芮7k/aZ#A\5L&)Ytħ3]Y$$|xHUqv Zw\eYY}趛DhMoja5ƽN+yqV[pvUlo|@|>R´ɤޖ !V2 oE@|jО{O,R/}7L&wt's+)Ь7ѫNR"ISI ˑF']c._"6WࢧK.}g@h}fN jܬ???g'z8'vMJw#|uDQߪLeF¹'9 Acr۰k"L.DrZeT'[ފmDh|SaOx44á%ң+ОC o/IMe %3}*WR{iC;z^?G)0o0 {]lʳRM?*M3ByKS'`ͱrG=GcndIHCyv5glGSEArg| Yͥڡ1 lRQin0|{RS>Z/udMO4D&`kj X6Om݅Y/ ^R+g8$1Ҙ} [(--+笨H?4Y&S??_I}9 }$7M }}˓9pO[Y$"24Xl)cſ`{c%`fՕd (4e1bL.'eێf]/odySHo:'IDY;J.>NӀNZERNT8p p ~9bc6n' -|}5B0&=Q~m76iNN14jSi.5F<Nh%04Xj~)hW&0 `z!?ALI`CkyY=@bKNNcxQDফݹޯu ϫrj8͠Fa;`YSeI>Cm.97L=?GM,O 89$y~5}bfQsAd͸Hz'y,g^ͬcNN<`\s`̀~!mrrRp<;W_vʠZZ*n@lX8Gb%FGôf- ˝K #o8ɿ& 8X?G\%i0e ҝ(!j}೓jf ;~Jڲ*ːR {00$踢!pYA═KaBIUu^U3b+)n9sn4'0/zPzW&;GAVS dDh[Gd1KE.1CoYyghnҧ &+;ѵeߟR\炻)|ip M>Md5/U t<~FPRS•]HzMnHE6D #,#CzC0CxH;p ,q?_2nbWcŪtr?ۤ@]VMӬmDooƌ f*ok>%ڹ%͗.ݗ`.xݠ~P U~ вDgvy#kOoЕ E=U%~Hݭo0ϘQX;6# 9#ESƄNh2d0+|s}l/eCA"&xzNۄ!Ju fT: g~?zsDTƽV?T2S\NQ| MTqw:-~};|P{6b#?J6ȓlf K,HuWEXzS'6}To X+Zͥpl~cUxn#(=.TuS>|^;J4;VfAhb']ass7 G qfP4OOqHU:Dh>cMgֲ DTЈ\ظI7uW3;Ϣ  v\%!d+j>Zݹrf ӕWFRQ'e!X2- rN[Ycqy8 +~5<3^^)Nv1Qс̲xkkn{۔?o zS+UW|yE5g*t"`tSSb՟ǮBJ@ *O׵XѤ ?1N_MQ-$ay є"LR@B0##:"7Ug.K)=3@_C/Ao/I)C-؇7du: SɋEjZmKH?? ~ߐxcM>a2ܚE,x%_<2N~M]j+,i PT l4|J ~3D?R۳\N?-Jar-TKEte`6|gMW.r#Y}pʓ?wpx#2FIЁ:hr096y>;n܋Qb"՚˖ >n'UXvM.<}%ϾU"%ÿ2O5;B3՞Cܴ)vfr5W3{Ck@E].:g`܀SJ.y7ʅ)c q!X q2dK2fgCkO|Y|RSwRTZU@>%L9HO~Fae RaBSB9z\p9Sl/ݻoJ4D|Y"ӱ4VaA:uiשܫV$6fJ-5Hk5`"hUbMʓ[Kdh?+:0 G>9W101ui&vQx3M%'Li:@"Nܠ 5Ne7aJ'?|a^ 9W3;#{v-4xƠޓR9oW?~Ad ҧbT{֒ ~=ĘPb#Hd  Y[̂`Kg̼`+ok&q?j7. IhؤCX1>]S(wKhz ZEQ+[yz8|ha+WLNvb)?t8g& EO,ha9'Q'beIDJn15K/|Sȣ&eFܩQHσ?A9yMjEpN&! ^s0BIÐ:C9ۇ_i2'͊V )j [3f4ķf+TZQBҍ;k!A/H:atrJ)4el-u$Fq?{_. \TJN^Ziuj`){?(.ΖK%`WS$| adYa63ՑE;F9gnp! cT"|\o%V m ѡA+Ti/'9QaB=5pg,d G> ic="+hf a@ S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP12":,4рbaUo e 9^Z Ӑdo]/A"*hu3Wnreyq-MSE#Cde6 2%PX`c|;]? ?nڣ,^F|ذtx׏'GC4BЋuv!j{ߍX)FmuTqq L{+Ŗ+9ʉ' Rls,IY@4n95-)_(]Ӹ㤛5>xF}/TtX T*xzKD6taC /sE[5 IݞֽmI H6FM/H1Q7 UOo4? ~OL- XN>kD9셑GRFl_ I C;|'>+_gY *62iƾ)_Fۻ\\قN`ċd'` 6ڎ>y 1 Li%*B E3ѐSp-|IQ;Y,VDՌ▯L!ߒR|'\[8Oh"9Caݹgc,8? U#|?FN&0ae#7BSb*uH/D7fdRdVzA?`4Wz8 {ٰutz5ga]/0O|S-iAQ ٣9C\.k~#S e;< 21c }SsC*5A;J}?Ï*H<`KٓҀԒZC1m3 ft[)4[\|r)XA8Dz$o| ʨk85E7a:OֹQfG=2]irbx\۟.ޱMJv>[O'3L%[bq.ZjQɈyW&-l K^oԖ>Lަ΋9?-QdF=ٝnhNxV0vG{vhUԇk {Mym7t*P^=a#:-/3+ J슏Z\[EAd9$ޏH_Tz;/gfh t PK'JZӖnhnpւzi0=,k7:=p IVr.$'7%6ZVB{:Э4ڏw&k ,wQѲ+{Tۼ4RIPzB1K f6n?'6(cmݷ PA{Yy{s^t'*dy* 8!0^6 qPqybiKO`$!i*ϓN0L +K v_ 9G_cW Xc'βz)\4;ӨSSqLx={ gWIXZ:kg5DruUZDTmÈm~&6jE5l)± G \y O pxj!Cc'~ݰYbGk(ƽ&a |5 ?<#̘hZYaɌձQ4^;ad+^'9$|u$!OzPi #p'/ `[;da͵ӥRm)79<^ņgdT=PFiabNb ^,9ԩbfhgF Mj4"|>7!Oł6@j, pws<؈ؓܜ'VGc >_UǗ*mXFLrc c1&IUmKE,q5]RQ~2殭9p ̙Bؚ) "ٛ@~V<\ޔw|ه=$Xu^T{*Nx| +X75@93͹;JXF~baf /3f$Hʆu @|=ɱWfVNNrԫ`?.ԧfFFyӀ`^l6|9ˠ }`-RD;iʵwZd Ih*݁1xrk\qi1d>.ENi5BH:ԩM#V6q- 11d ?p KjJ[PْaG7ءwq}:H CC"etַ X|oR+=%)"Ȥf[ބy%+OkW@Lpo$1eh450GSn;bvsO 8>s[y}`ryrDG.HD<}h%fkYf ;\~qP:(: ]/`2-1>q+e{.g7{㥢rB+[xKh$38ڢ|$;] !c%X39EarҥO 'V]nUO0et ޑ6ri8ȼYN9ō/:\ \^2WK/4['skݕcY6 m%xd50śiA!ȅߙbaHȐF 6xr ^XqK%q$4$ şw 7X%" ^au Al o&T.zZ-[%9 ֑;5D Z(<ag=/S>E6e^Ì(Ya 1qy̐ \%/i.Sܰ YԚkX(1'6dVސF`JkRe{0pD ^2[J 3Ꭱ~rڸL>*r Mt .=C<{5LJM(xc_ˇ"KjS#y ;rg6ve~{Zhw?iݣ#P5B2Jz^+l Wvo$Všy"219S6ԂKϹ6iY =N'0f\E㷸f.F͖ t8R2d9~IE.Rk+uUʮ ~ @$;VRu^~f}H5tuca j8Ari`_   &eWrTh&t= ZP\'oYX xvq1 铷 jQQ)M`k~Z=5BiECV2t gԆku߉hV&"Q{ @ވX) ,6(9%e-zvUw~`EzJb2xB؏6q`uOF5v$[c(Ii zߕy䒌̑v?`m~]9k"M@UL *XK<ގoec n "9]jFIB80ShYbcbrM&Xah.ZB #: P-mA鼯ِt GCf϶-8h<G^xLF>KPΝ 1#d!/_BeJr>Ť^D٦cqr{d@O9>D)$ikw99\١ l3聘G6ncvrM_.AՑ⍃ 5g-AG{g^:5rYZN]!,wOܜ~J aAv|wl70!?1wFY':0vG,?5sX%OnA}R.A8E6鿍wI ~*mA> w|xslDФa߁1 ?wayJ+r猸`3ھh_ YTyg@EdB?<i. |b+-ָ̭lWfAVsp̞Y[ۺWt WH)Z*A&?RGi f;iV{^)?f!C,PE$곫{Hg"Tۂؗxb/DSc 8-ҿ ٱe a|Ʉ߳aivFlYrWD-fT#X`5VE@S}O*G3ouЩQB;9t" _P|.]? AʫOw60~n/oYFT#-Wώ 9 A"FMćQj[c9HK$8Qe"<?0&\K4 `F`uaN#Ut~vhKLBP[孳e7B$/KҎ_O;\}VFpI=iP? ;oh&C:(΂ uev'CRLQ- s+TV8}S8O+IZTP īW !ݥ6j=6ަSY?M|/ c69J?!FÌxt/ s5Cm[|\7 (rojs9eB{cރ,;.;״6]ř E*+L\Eq>d O SO-,94orCqYźҙUaF!gaW";4<[=~ؐ]_!$"O1$]Bz׌fyqRׁ˸y͡ zNbVxYE1?X9Sd+?UN.T Fϟ}MR=ݵ0a>ϠqW^qd(| w%a?hVqhiS ֡ع!$rel<_ (JzIXOH2W )Vt yCYGF6&',a4P6(n^od eA sw@zeAb(l߱o1ekP-N-3c?u"I]5%rCwi?$4Gb,XaAóOtмlb.c)Yj%~[mއ͔O 5ԨJÓ= 5ûeU mAd4>( {imD3D~-68(:ΙT'B#3HzJ<I!a0>ęjt% 87*?;]ɾx>+n)+usH|f0B20-0usTH#t\"d(gѻ;+}Pyc#| S<*1F͍|F ̘!/#&ӑa[wG#ξU ܷk f1y5Mc78GWχ?h? O蹀\=/ý~3!z7&2_|lN k ,f!#cSR 91[o `j\L_c$MJ*Cl|FF{o/JOi Ɩ.owd)A\} \O> &M< /~aouJ 6oJNPU`:s%* &7h1.Zj) -) I{H%%XstE^fk<~< BB`h,RYc.t '%FƜn1냡<@8՘}W=P+|uGޱGڀS:ER, re2řa7ϻY k臏4D *e'xNDM 7BJƅc ~Kp$Jcj PY^@41 hIwUK?wAhj Z DS@!$9* F7]/56]v}s-j*G ${zg ћF8G%cX@p?BXV8zXUd C{_(Eԅ6J~sPNQxhCYhzU P iMo=G7?`(C/yymL rC0+ NoO^L9\з 3mb3k)Վ˸Q R YN]W&Z 6Cw Se7Jxz_h yƦr17,}JY~`,C3 &x 3"MV)r7\B~ ܧB`ģ baT4Tv~8/sN3ӷ_Z,0зx*Wӻ[57p>maͲT~|S܎w| G9ncj7_?eG~YTl#\5So=X9NsG p7+٘*vPc a8H#9dWK+oE ]~0AA:VhVɃW?6) u71%*y$a_:OT7)h$8-*CinٹLKd!\qw]jI f*2vO&31f. q|6 HH#1ʨ?:Vdw ܛ@Ŗa0%qt4evྎ`G/8US|QQ945] V)f!%^=ttg;f63\tHݺ`oo>JvF~X"{Dc9.Q8K7c‡4 #,/Q|fǺkMx>d2NT6.\K9.dtqS9=2HIXB G9{ G)C :6foKW^F>Z8U)#eĒO(&ܷ\Oĝ߀jxg1זh|ӳV1KF'^auܳ`?S]0CWr3M.[ej5]Jhi$hUAqݢIeLogQUF7h,A鞫-+Y9^Zf0-cJ&l B|{F4eD,965m`- ̫@8##LM(S↑ߋ2?Ksdzr`2kxNIY(A#N)r JkB7PLzd WzhSt7|fK/dH%vi(Lbg:ꝔJZu/ϡ`r|us=|,57  qGl9i3I* >%J(碚 e\!%-JzF&/Z`{f;+}zCtzbQ/^VT a$ s2@=C8 [\  "Bc !k(j\nkO֧ɻ@=uMy,Iӱ9idUZp[vʚzik6KP=†KҀ{ RJWD*Ψju4Eޅr|CA>7z 7_Y;YGs:n7L$ ]ǀ9|>F%wI6kSOLg KZMg=q`{`C |$0|@縔-vY8"2B+VT$#@|má oĻ;C-h/+mR u`c[,B$wb_Wbp{RU k U0;zpL!"GdyJިnC..xv"8`^ %Ik< ) IorakdL֏}6bhB;ԸeAO 56`cB F0L~@S^84iP4|4[i]nrM9FI$:&`'0:\;J诰7u$uDhl\(h'0x+ u?Ɂ:8*S3iudL.ye6Pp߼v͎jg?0mye\'{xEs`^1JcI95gІq3Rs?Z*9U%D6[YOA_ },=٣۷ڠat@K4nOYh]Zy*,I-!%d]3[Yy UiͨT>L lj$zO (0xxAIfB(X$-ZW, ZBBx;acy|mfN9ȿŵ-|hm%us}Y ^ [Bk9'PVIC1H8ALaݢE W0%FPBϽE/|@|#>ymXDFMyP*"| v%C/t@7ǧ'q0҉8hI!+Zw1f"h8AIu%^U?gv IiHZBJ.= qs 7oIgq9#u`HJ7~KajlГz_{ lAlM1$(uQ_%𭢲6L;+Y Q$pN᫮MLRX74+S4$HIz+k7m}gbUx;ϾH]!]xP;nƬ;>8HEob۹$74;)FϘ7"mnU4~hO@~eZԨhh\\dnD< -b6)VХ;,쨍ҫ dbFAwkIGYbW~I? L ?wt@nlƿ0p<تD V|kX icZ7gΉq8f[19ݔ]Я| EEjɑ}h(`\$/M"M7܍Xf%gn2- 9cĀ04 +v>Bˑ3ғj{QJoٳT:0l'QgK,_V(H 62~144xz9G!g)fM|Wr y|%[=QE~3(liuUd wػSMŽ .H>*{*?_3+A׈(K$e5Fx>S viR.Mw 8Cgo<[ULp!)H$AdEy??u ˺{tȧA>%pNad/ex^:`rԼFv1n\AKoRzfq,.V˷ \i;zw]f"yuW!+ÓA=\EH_@ [XČSKP7zѻĜc-Mωu(r˵fAfsTs>UZj ';9kg[.ځսNˍAMTQɪH`3 -@:}~h@b)Uv-FQ7D^ukZ |UB]8}%)6ZFԺ_UTwCA DsZ4޼DZϺgNjp/8VSJ竓lg9nFNZlvyhÎ4I(5 `]|X8hHO:(cmz 3![tD_ YGXJ|?/n%\L%8Gv0^sÃ`-u!zx1P^Pz&nD']0P axP}+50InĔ.`BJF77{(r ܌`ޢٳ4s.Als'dV%6hwg~LMR S6h@#@T.OBAa`J%YJ)21~x_:"1JI;\% R'G(Jt٭U]7̹iT4Du,Ϯ"Uj|6"1ڬe;%2B㏉68P̱ m֬CːCQۈ{fa%n_EZ^ vÃgtj*ڹp jNZ@x]7߀Y?fӆFהn[ZI+/RD8Al](7 d5BT LTfPsBq&Z8bk*ڣ +|s`AoouE.Wˀ(d%kD)%7~1 ?T9 8B4\$#0\m)B/6emZ+ m ufӍ˱tK{wB}*5#6#xҥWOKWNS6z#¨DfډYY]2d( fawzE-h:jVawM9X1m FDx|%L-8K Ook )&g6)5$`h =P ypW8.:izd%2o ]'\92$X(݊lBj`0m#}Y';{|2 iM;d XՅ2 \#CyQS^{;T9,͢A"Gm15-OH 7kHs~ 鸃llQG;?b)cW(N ' ^B M9hՖ1ʆ+6/^v*lyC7M65fW:jNߢ +-oi,8 @M }{)͋J kRռ*M62LM* %&зi-wD[B8ט9}VUdۓMm+48\^,Zw8{ퟛNgϰ|0#{|Ӥozh ){QrhXQ%'RMtjyVpb+h<l`mprㇱA~O௖ԑ@uX#B5UrT63ussOsͼ-z0}wO]T',!Eyv^rt'*yY=֐:cQ"hv CTۼz֤QE|*vפhzS~qzeGIjKkUÿf%{ oÊ#i'kf'W?]+!l|7;c˸=x(P0vҤeG6ZE>y`yU'F+T3\$"xG gY{kؐRe'΀G3؞awCb:i#^ d؍ M5E P}I,nhڻ܏_Z6^Dag"֎Y l!94=op:~FC-Wo.ļV,[ՔC+so;(s8}ρ.vogazm-@Z y$G%Is'aa.ּ‰Tm!k5Pf1Cp5CF^q{סlC^2X`w{ij yStKPYt5:J?7fwR-3>4dp;fbA$tP"kt==R*:?d><߳{o (ypkZRnZg]&P~g&mXEa%*РDUxwVYw%_r?L:AyX LY~+˴&N|-J!<\C5v'vwMyBx"I{.B:lh_M'>b7 6հvopqd]c?> WC\|;5|PvO#VNh3I#ByEh.P{xr@H_Sd0入쎳uF|1xcf rMWeɓTzdNİ/x|e?? $+vX?͔Vd6 GlU;c"$9<^_N k3_0"Ug' 5,e9ug6NmǰS@CbQ3fCh OUĽ"!}r:NqVע61 2?xνj'qJ͚5EJN:eY>~0wuU~>`'~7 !5 wuIB9/ׂj/N۽i("Mpx;ܾkkAp?in'pIPt( ӡ jAM͍^+c6,o Y3̃ ;O xFAfC\KS L^|d^1]qGט3w3 Z r.mώGzD}i{>t- 1/ ApǿX["S7P4Vcn>Nͳ=2/̗+UpK8l\bSkߞ-?e@쒌HCYz?\nSѯgkM>U ,{b~ʴ<p+kN+9J+ G-KdE=DptN,.P-49s YQbúT]ȮvQT4ib}`$d m@YK6X2a/xm~br"Gzmg-hc;=4OTg+x ,֖9:-&GFGz0bbGdB'&T{ykf2 soxwIEȍs\*4,JΏE|"wR?NSvZC!32撝i''?mL5't ;/xGBX_V4ѿZں!aO 1 qlb$g=r)gui9~_l. [5eJȂx.tWg\ϛ} _>GR bw uCwtSl[\'}x\8sjrUX[)r#`%. jd uA_c-/@JM,)FFQ`^>@|qMfQH0,ADv Re_Nd5_0 d(*P/ȇuzKg;Njo?'[toȻj?.?p : h|ˁV1#ku&IǗ{gFiKATi;p(q2!rB+z4Xl$'f"[f)K1RcͺG6YE52R}STqxA,FpHXQ6=&#.o_}E,ܠsZ5(#-Pɠ#j B:l? pEPw~4bnhBZA\IV{yYLBw.c&Ԝxb^(`T{ ?Vɦb3={dNV^=2V)hH2B/} C~k9O?n)ڛe 5xro@n ~ l?S{.0E~q}(M?_[WU[~SAz$ܓ5yO[0NN!Kl =s>?mG9j+s]T[ӓ_{)%ٯ*}V)ާ UFKF"oҧFֶqKTM>&0S,rܬ8 Ġt 0I{{/ zKaKT=BݘM Z Q}IHuKIV<[ƹ=pUUG䃴H'KH2x'!X.\plE:mT1WUcԿ+0'х0:)Je4ʜk-_ w,vI U@pG sQy-T`L/ .O zQ?84i-@M->ٓբ:%#dE XwgFBb8{jl`(X)?Kۇ{^ v.gJsPbv~EqI~)O$yWAS!?@Q>HSͱc)dJSdC_;بLQ@q5W !tE5^L1]xOwī%j#Y+Ojݒ@nSiOy!C2dp&7&d`[p!i֝Ied&8ln殱`k#tyt`n&D~c^`гL<:/FۚbuIq-uZ+y.\5}zT' aY(CUժzB)Ej藯HZG@)04jO5OJp(#f?}McчWmQt]>!QAM頋v)u>SQ*L_t|rsO( L;J_;XxE܄'{͗I δN2?KpOc6bQ괺9XaFihٙtMX7뱴 =0ߑr8xf-Q!M !LgC-gH5@SeSW^7^/WiL.%eEtP1(n ,T,V]-.MlZeR$ oП5?8Ԑl{!HFԕ/8UL(],HOR4-gs15rY}ƙAڼϻSz߀eihKFFJrH1"> }=:_E0[oF);5 j FT@'z0~*!s?%׻ӊB,b)WR4ȸ>{wIEbG *ZR%!z9;&4ڻ=]@(j=*,:/bp jW6w?hrU;쐱^ 0Kw 9dzpc f<9hdBx-Ɣpo/tETޅ?yx؉տ('v46N`ym~ق8)tCp{{ec4 Us&Q`~Y0 Ei=sOk k+e3:kGRvI"Sv_.;PS;t ||8͚z$݊M}-r@^x9a0=A&#W=J˗#WW{!cMS(.,>8r"cfTiHiKFJvTHk9 ߠԼG)fHX=S|jM2մգUwg|$[6+RN0Y=CԞ/&J/``3GaVc qHoO cQ)ً`;;?<qscI\8Iz\ bVQZYc [x `H;whpQUC#[PYƌIG5UqUu!N,Vƿ+c )WIu*@VFإGP;]z&e0]9s5] ֧ %mXjkG=uAC7* xm zmGc!nQY}W_v?<,r8{O;_#ݖXJĎE2!|{$-{ta:*[_ul`F5`A{J@}%t׭7evPEjC}ܪc0ƖWt/ ;_Wd=iWE=K#OٗC fWRm2v]9s P$>`'9l>C8Tk ɦwsD)/6lv?Kna;S"hŨ,3bQC#y`iJͳ!Q-RMocl Wsqv} [7wTU|(SV#t }C`PVLUo(#C/YZ%@uaa@H[|MJ,Bȱf#>3l=u3cp 2 'io6 Kg55ͭϰ^|^|Bf#c %꼌_8iWR49hI봥+74cdFࣥAч(,Ӽ[fwG%qc~_Jq+pvZjsnlzX%ႱR;d84Ͻ9+"4*`rXx?ݞ nmV̶,i7SkRE_3#IAԞ!TKcN ]̨L 30 u \-HqW鿽R!CʯGwXAկ}P4ٗ,My(|zLY:0/d\06 i!Qd;yTD~JR'tyP<䌡 XW 7dD҉^ ':88Jɥ]ڗo;ځ]Y 0WocL{ZX|ez{?3SC6wk ;]^uH!铷ȴg""5]5u1M3|Ru)Zp)ufٹ~Xn[{HX>Rm79R+te{k`mzI=Z.''x](^{}(ݩ&y){Eog C*T۞T?t0U-Ip DnN0{7e@'Qδ8~EfEO)W4;*/^#"qOBjjs{Aڬo7} `&WH:O 9 |;f)ٶ*T!Lg:4<( # RGs"Cjn|>4p*,1kC}.rqh5E+z_]C[H_vFg* &e%A$9t,$VEgZzk:5O|^w@":]I;W$NF6ņY%+uL`gXE'E}ZRP‘M&$#M}ŭ L鿫9>B?@۹~-һڮs7ẗvkÒqCtə/Qł'è ̓vq͑%JK\ϫ).$IX+X˰i8 !So6o&Ѻ2;A1hJxϿxP}Ye5T4xfTb|JfK+l֭ajNyO-?a}|?x/Y~P_EKgϗh9 7>itA 9OJ﹌gzp_:`evOPZ<[N4l0mᄁTAT 5]Z/8&XM1'NX+0y?]޽ R0mgޮ\Dx3}UryIQB7B.`Қ eRwʪl(mG /ۡ<٬fxo$N%fvIKS+X-M +e(2L)c"|q9AL==ܞIRχ7a0#˞Pvԗi9z _ $Q̡o% he*|*rl`ońm͒zPi֎:N Oa.']οınS=YNz FDva#܆Hk t_x NgQ:i3FT4D3HM&!*YʉF ?ϱ0 TE[顃SbKb IRA2.[+p2Naml* ?_d!%>S;{i_gxjDkb̗k9xotS@y"BiuNb\ʡNi2\~1^7>C\֮Z/^ k0ekM,0KOt2B05  WX'Ne1\:8_Ժgprǿ*~ [kԢ@܏I=/qO_mɺדyVЧkр?X_eS$:-n eE\ 5N\]#}*Cl5%d*&swsVAƑWFvS΅rM;G~_>%gyUjݡs?PtTkvJXNT7d&j9'7M QV5F )9cإF$ɁYܚ6ϻ{(r:t"S7{*A4H=Y&W{pI>MOb>+[==5D=bR{fC49euc(-4ZRO <Y#&5JU`Ӡ&8]p{ #n, n@m [VgV7aȁ*r))^~O@5OU@D]˖ضOiK+Ck9l+hG^qTGkjEBs{l(M9%»(ȇM1gyC3j쮋d5|=%+_@ý\XBr^]}+X$qT1m$dA h:-WSJp0 Ej7JrpcBnn_@pR{g O-̊Je7{ݒW1\]-izf}ዃSP˼f 8n|={K|[q۪ =TP&Ą4)^M'Kq4K&=r_AeB> ti+ M#uDϯeS>C$E8p}ڊiRŒ좸g(uf~/OƔ??\ .4؟6lGBC.{w2T0QvʊE&Q|,dMX|?h(3J2Lf )޴ PA noeHaXp=&*A? nvVt׏,-e`oM2`2/ЧX^SرW f,gAY >ŐHڍ7/Ug/wUurx#q *V'be'_3qMsǔwc'qĵ 'oɐ\؅,<J;Ә~zդ#zg#G7aGuZF1HL N^;b=gGe+N˜vzȐB?J/^@roC>qO]RĒMCʠkv ^JQe5nMDw.:>cnSG$,[i|{cI:g]ؗoGʾߜaAX26 uR&Qr)b_8./SJhDPI@~挵%-.A*l/ݲc&yЪƌ #W`Tepd#` ! ֈ5o*8UjVϩ+mW/Wic*)>Pq,VTm TѶm[QKu-,֫? @3/)c|n6 wKQ &ɫqp%X+nh#\rO{oo* _Y:;Y⒩&M}Yhsof[-Hj OӮ!R ћ_3 $&O4 }w"!]Db=61;@'<¾ Y2P`Q_>.OhPřĦtFC0/n/(AA%j/N^''PT_!h6?'c`qy闫?V.WD'8<7_?Ab^łɻA5AZ͟:PdE5A5}x? O|'NHɉ5ђw&kqVn;x'.\쎹>?c}}?c}.W!pP`6H -{8kT_^2) bhD3"wO EKOi:V~>&eyŤzqVL:#G nļ5Ust,LOJRhH@IjVjX㕯du!\f҃2klN hJCWRflh&ߖ94O]Dԧn!ۊ@'ddE߂-b瞅hUi$*X@Lxn0˓!9or@E#Ӈwb+kRuѣ+*20mՒL3J-D^ |`` ䷾2O4w?UL8t|%+iB~ .PnJݕXlWXb75v/KƷ"LvJ~K5ͳw(?;LrFױ%\ %%ԯÐ@t߰B b(v1+'8J.$[a krj$X6BF-053j'CsW_t%zR!f#M5xcjpXG^ -Tnoxzˤ%y:r*#"xU}Y*qx׊J*de)iO 𭪎ky5_C7ykcӫ~8{Z\ޫwm)*_FUAϙ .u~/` u_^ [P'D%0S4"p(Yޟ>,{ +%+;CC*]먶P|a}jߐufOp4X %"_.Dȫ O7hE7cbc1#QJ%@?P 3z A,ί! Z`_m(+l}(NS?^MPH!ES{ATc*dLUvD% /쾖"E4* XžWI%*k4bPv\Ԙ(" ڣLв߄[6 Uzoų'E3rp|^5idIZwY[2>Hc{T*g;?x36 /l!xX}~vicIgM|b鏗M^ٓctca?yVjI|5f&ZEӑg$K}H]& !{Wɯ*e:ѯSb(>( ;&56e%kÉy5#MC%zIi ϰSbW0HE#gFL-]^9NwpѲ4oҗ#ޡ5/>H6QE7o>};̞!WŪ U9Jw,NJm#hNB(wmuI -|7]8$"W*Y4O-ss3& 7&'ez]b Μ5QO!ӊ㯸ZgF$Uq_ȌP$iWQswL]TEv%+ᝢߍ 66#3|T홦z{ut :Wnf$lp *耗eT]&)l|=af#CbGO/$>Ɔca!ӌ,m#xUYڟ;1z`aO`8M8XtDĭ$XY,x'ΞkhQp8sL{jCH`0Q41-Pǒu^/*v3wHcKgcX{*QFc!5. ha?<HRsi0z KñVD;`5?ȸA!x!"&JO& J3…U-?ف-aáF t2+YPZ| :f4kRjOw)U_D*(صXdR'ƱtuԑBZK V2 &^č/ì ֣9~ Y9B%ZoJf-Th>\A.m8"(n,g7ӋW束L0}B 9p>& !_}u|:+BۺCY0x*8p/.>@Qiv/zBTK\ݖM,^BՊSp 0ĶpxLcEZG~PD6DrQV=_",C~;+- f5E,Hs<^?Gj fG)oZdDKV#nL ]b5Hg |W%=JJVk]]ZhY.Wa:3vMZLFBE(Aj oQoS uyxIr:<CAL=ZҮw9H>vku@Ո/K"۟S ~ͦՎ3vQNJs薲au-NM[݀y(u~ f&L2++6FLlh`pFb9 ~)!~{iC! nw6бyAoxaݦUVT-EuA'=(q#^Rˬ{E1*AgT ()&{]`8 &_g *n_c?/d{{O-w2(~yh75e_E'4.)p>_35-UK k+7tu"ËPO@bpc=›IqT3N?;w 3lՓ"ڱiVӈ>1ƕ/2RŶ Tc^?M`4=|w!nɊą@J3ѫi'n;P:cu)dݞПP;9J%قuah(PuVjWџ?4ElǑo.I c^ zٯ/˫U@AgMò̬.| oBZ(ū2orB$)CܝǸ#@_Іï~zC8[WN=N-c|Q#Ao9=-CLdftU>y8MlGvw P>Cltl[ ХINCwY(B ED?aew9^zYCy(ul ӄ_bU^ƧؼCag,z$@O{t ^k2[@C)G ~-[|遊?!馛 wx}1Nx(H<e6Ӈ6y!CRB.f:V\w~*QJ D}?Q`%Rد$mLWђ2=ixH)[0ag~;WuV<8yY3ߨ6H:I>QE$;>h'7jӁƢ@x  >@g>OU>,NptW%*DT̟d 8-q'O " :#!'Z:ׂVzu c@zS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPSS"Y5H:$8pjAEp,X:>@+h"|Zr'`XU ڞݲ}=84(' X?*P>jV~@{|;u@uA*cܵZuKU8XYBRȦ;}^.BuD"Oi-ׯs &Cϥ`K~ 'ȿZɩacA3kLs8!!QQ3{PlȐ 5<$f}LͥRӀ+s7Oi ] ^_OwÝ"H/PCa^}R9+5e/)&BU!o pٰDz[E9Z%*a#%*5ֳSwbXTeRV 50;U/Ml BߺoX3/bJ @FDVtj !ν۲P+k1 -EWB(FfH3meC"!OL=6R etqCw10l 綸Vd]8$WW3{i!؅ʷ5Hq~&6bibPjnMVΧlc4K<<[i-&ڑvvxY:6ǀ[~\`Y,]ưTUBE_(NeXh c;qꞦQk`8Xzbx[>Hf{Xl3^S#uY3ӄ>qc6I*y&iեOsv54Y]ï0^༯,x9|?x3&'.}?-v&I}ic쵤e [eK~Y!fF~q]>L+=&el- mʭdHz&jl8.ޅh@=ǯZ4ibhvtVD @Tx&;!} ϔM`%1H몟cq=xu`&?0(gg F8hЉ~7R'e#|hC9*Zø[L'Hn` MG?W[PY{s)lNDR-[PкQyZcR8qi$(VO<𥃡}P=pF<?q ]|tuWOJbq]9)L-ZFFZGXU]`$?JٛЪ3S0UKul'5~~G+X&6_TC(njNcg$pbqan]Ć >D [6~mH*ݬXnۄJPdVм7?KZx'[QNH#.Yn2mQI2,!qxn29"p?> |% း`~5?\EBdb^@WM/@9!xzP$rjG Hl QR+BJ-nӵi#-#/>OypHibu1W-f.6bW]! t_LChb )JRLRNҚ)ALcv'/?+DoM8cPo^D.:;%ӒQy dhW3;ົcgiMV$Ӳ?jfFh'rQokdfyĖCC|$: S #%d;j #`1i8zJf= 6_H|X.*H~|a]f$ѺQd腁s5  `փ\ajc~?l3g6jfom=$5o|]?_ ?b}K o?q^yrF bTN g)[.ZP]BUpZf+n2Loo ,qBɝ SkeOT8߻yrT>kBŵ-]] l_ˣĈ;ŸŃُDeYnK(>qEio?MKst"-qqOy| Ews͑PstKn3ja!cuD]HS8_*ǛJݜ? i9r>_r XyO=KNa*#lldz S' zh/g [~A>LRMd$aa X[iؿ/aB%u ʭ6a"h{MJ`553UoO=_:OρEW꿖;^ |9;Wwd!$'yr:^k8p8(NOB;7%}9!pJʧ|'_m&QkOϢңS >ɷx^eXzTDv=".,׋QXau#XةcQo$j73cJ*Md@LnhZ[;ޡ?z¯nBRBMy/%) 6ڸL_$,JCi. ] 6QPaNݶwtخDa.* #o zI\;Jn1Ն?;;R;KFCFiz(Oˤ răN/G|5 ZSo]m4z3*Fn2Eqn̓Ee{s^!l7h$`9.xt`=m?)ǁI(ۈT2jZ|(Kp)e 9^FU+넆/vhE'\~lz{I l$,bPhdXyngѷ3rN6<j8Np2I\nf;yT}bpb;nwD,S ҟgm_:d0 ry=BZ@7 $䭭o%U!!چ,H[ޗOJM&ybC"|$(]T > Ȍ&O I> 6 9"R3H\X@G|l0y1jɂt7q`ni4<-F~'G5r3üzrVaabk5Y[)w\_.Uqds`2$F-x"/>2Bst;I. ;L, J)nyiQo#ȯ%VQ X2 FU%L$`[)lRYKa~϶D(~Ɔ~U"(;b8vȩwz(z ~n:Yy9Kd EF=ޭcT̛m;c{ɆӨ'qV́^\"5KĆ9Uj v}CUѨxlLw9@=e7,+$zqs𪈬 +*;ԂZDƉV}:䑊Pl%$7;rqZIxm<])`Urɯd WYKmCQVqF5Ơa\9Z>GdǮijpdUXoZ~ޏh0B>63}1>ӗᮚ2dP5 ~Tv)ʶzD1P[ԅotU$EiTazޗ?]H4f3(n3^;OgAhĬb:94CH@ILp(2;YxrzdiKo+2\49J=/`$MbU<`du\ޯ39zfP">d28TPp7߃XfVph4ԾLF >e[W_g= mb3(5K| V@֍\=SYjzx1*J[4}4jCr"gkvv@bIn`⋻VcޏLE2 q9pmZmu'_v!F= ~I4LtxRWg8 Oa]My co+Q(|H#f|i8*ȼ& E2c6L; Xށc ՞3P 'Sl*NbB~Yіf'!^ N<$Zn?59M>LuUv 9K[vm%ܓK<*>fݣZ9,lk@BIFN zJGW`;CgHIC9s~c~XyncY>7};"@5ian<5Hj\ z@O&.D"%88[T; su<# =9S?G6%R;5\^8+C2N_8Bìπɂ;A$V7`8^謷c@+cg`Z\+1JZ?y(F?npk IbJ[X/@f%USysǂ.Ϭ zyӠM=? y w"錨d5 CZ"V7sݼ̀1mbl:w[5u 9TR˂ &sV^jɖT.]4-I^ uR]Jaiq: F-dzgoՒ9S'~pr \HܰOcnQ'(*S{gYy4?26]7z&d^Qz_RtFIrǺxkA0.v #&-ff(8 =]hvczX"% DZe<Y7$C[#%m{E,클FcOQ Ӌz8l{oA2k{靬W;LV>a|@:<ҋɃ6^O͟Т#|40p_ |$n6 "܀]b;q~K8ct wrKlL 51O[߭U3S `.1qZ}R|~ x/Cl6ق+h"R 27ڻq#d[_Zzut δG)88,!3ˬ4܄+l'Qzkh5UTN֐ aKbetpͽ#ꁌIF"?ݫS{'V{@.[0JكoqdF177.-'L,ׅɮL`6,1P' mbN?OKz6G_nr qKv0滯kiX?UP-&v|"v5"ZŲ=X5‘@s<1MT__~d-)\ѯSDf?  C(~[ i}i )gBa'ʀȣ~τw1S}F:%m)&(3quFMtD0??Ey@=h&(g  5LeMpRNiԩFo%M E$%PgZK'to HeTxǕT!4pyp׷v/fO6|:/V7q-cƚM*`(s gL=l:eDŽ9sI=w弍d :$!0Iq\Egj~?E yXmKˈ%u=Zi9h}El=䏟Ci;տ 9"]}o;-WDV2!loI[D(cf#o +ZL2AvǤn:cy=1[.ٕA]J3 J!,)(ei6 =] G-h)zI8 4Ҫ57JP֨FAF*a(U@9.AJC<~hp puJS0DHcͭ6N6RϒӼ<3EJײT=iCgRշ"JvSysχT"cϴ>yU扡vBaOy[P[:wk1Ky e"ù(ʘ!͐Zfs)8$_.i??0 ݢ=~ ,IHKy sMLVx/dCXZA@h=?&3d19!NED~A%ǫƖ88l"ۚ)4h/(5ڞ4dP%pnZʐ+sծT}61B=ϟϙ^'$]e.w:dM$M@@D~})t<LfG%h0dXE;^dGdʅNJ% AB|uޯLђ1TIRlo c 7:N:ht" oGX:}Cuihjfll 9X*ooƛ*[V~sƦIc9Bs7QNӹ[lڰPqƠ4X|N|,WcT.-_Oq.$Ƿ܏kj6y@ޕϫs : qtOf x=|+#~lhu[l+dRqUHH@:CZ ɷgA6dzlnLSgc6QEC pr 2? T(&& t[`6% ϧKuDWY&?ecʾ׭{y"_kFgUb˪TvBC3B<=ӑ4i uz~\=UeSyN!.8-:m^1sEPaWqIv91`d*kC"gǓn-6@+> 1db*ҋg#aM"m%hsb+ÿ5Hg@IAm[Ku:&Gx16DUZD Y"1:ֈwqRұ8CtUpuHO2s2?XW?9kpPd֘xV~[D-٥&wPg`ކ2aH7.6L0V$m`ٝhɧeV ʧVO H!Z`),G!O6 U%f[%.,SD;BlK48?"~[KNsR9kSĐM-_Q|H{E֍/,1(`x*3Zf`Vv tm苺:Ay/5X+r_i:?]vuP QoƩ-ldP@Wj"B=)FL1Kp" f,+Yј0g:6O<:\įV+3+}'/6^0h>bL$؈0/lQ@|K12jh .Wx7ˊi%_g˱n9|vaUZR=L%Gֈr0bRw򡈚89 &Bn9K`7_oA ~/@J|9]5[(o-(J_'anC]][l{)Q_9"$rhWMg?*Υ}~KVW-!lH[(. ~7/ҵTl%R&\\&V)")֔ϴtRzJf#ăC˰688^d!@[ר~[Sp )Zy٪D YS״>@zڛ7ҫVqQ p)4Fc U?RFVq?4IzDnFdXxJ_ E#3uzpX2rxIJ1,_J)RABdx0,/A<4V謦YKW)+u>bhȆ;k}=+NNm!/Y½X ,~!Sދ2r{m*çwfI FZL3hl7G1)=FA+mW&jS4V3U)o@\jUlgVJDX+NS;gCR&\ <(͉AhM_!i D%?)B-;7≼Jkh Q&tSh9C=œ4oN;ȄLAwu s=4V8<m=qKW=럊$;omh>o%Kv~=ދ !bb, EH&ǁ^TUPGE| <>sߖ"U=T;I`ovlx PNHȭ|8x0n[gWߤg" _4P#@|@/Оw-j`t) BS'37^y|T%5Kԁ(@x3S.Ѩw/&}.Ayu+R.l,R~ߒ—O? y]:ByR8ǒ v1BI# GN]5%wDcDSe&81HGmM{wU$"{emYhWq3/ 7f J_VB[NZ?YgRx 9;v8`og񳸳#/f ! GC5C|{궘-Fe`MBV͟BEcQ]3Px(|dJc 24tC8V7gjkH5 f(qL_Jk­' ƽbaXCHz!pI=2dtU&VH8@HP.IKgiR'0u RKQM)zK_M v?۪h-S=xو@q'OMOs 8?R?DI8KOv|3AA-{סWȩqnvP_d )4p 3uf7)r`U"]Umc@>1"[AB?~\+Mllc#Ŗ8abl'#`,AhO)ޚ88x4B[w[3`GӯՃ.G^ ҽ^*7j(qdm~|ʤz={2M70 ^hh}u3FXis'rOa׸Fp9Aoʏ&ovBV-V7Г] GT`i=yU~P 7{Ķ> <@l,r9$hC, ow%.u? `: L"u97Z_ӭD3ēT;ss-5SDE"\ =J^ϣŤL&_< YZ_6Ǡ^](y'RlzGvY`SфD^4EMtM,/P皪AHJMi"Ulwb^Ŏ7%E`TpUP ' cNVy5Ɏ"Y*uJ.'G|9!No7GG,hͬ(R?{  Sq=m$GiATvKЀA%:f{߼A;|i&RhCB1v~d9q8WR&|~o+qnc<z~4g>ꭗgb=C VefI,H r2u<1-@Ү~,ѼY%Tp@3=2m[L^J'w]~B).="D!e|dYe+zIYFT p<9m5 Y$ d*;/P [HvF?Th蠠`~eRzk;f?:#POLdp+`|2N,xי͊XfP1 b*< ٗdOd]tPJS& ,jgWaRwC(ɯ&>L¹XFݫ4-xnm07+E,@o2Ӝ.VLZ0d #K77qT9d+2 Pi2o9P(5S* r;ֱ}=7ܰ}O|Rz/,;ڡb&뤇yܠr·SgB۱QOpr!!#*(`!d0JU@(ڞG3쎡Gd"3ݣ;Vfr+1b({@pdNx& ؄uBLJIg×Op?Ik炾n$F0kRMaex8LvݧQ|4u8k5s`##ǣ9o-Z|nTX:Q8;wP'(0e >dfo7K.>#&!Q:~eafuW%/OY^R1|OM/Dm!wBd3Ģn/'rI64Mt 4h,3'Zyz;6>;kILkdFЍ4dOnnrm7u!8 y+xfP # qn;ׯRc{aNq:1gvGS0}J^@hnE>gА$ P| nCX B<2^H1fǹ>ݗcv}=kOӰSp_SKm$:NF@04dg3wd[2E˹nD/*Ïtf(qZ9,Bd=NLȳz pXD'{"Yp7f֞7@g%Jp r]G\ruAlQG̦<9Ja;DǸN`(zs0YdYoB\rl'C*PstYPb'ת+{M;zv׏S ^! dAS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP$[g4 .}?_+).NxL `Iv\$Z)QwWJ9ExC Izn?Ѫ%)dܯ%|zɅCuNd1??C.:!/c _XMP"I`RoKkN@ՊS^pss\7eCQ:h"FeJc9d?Aj_0I&86puz[ $?@HnK5Ct'Ԙ*]E'2R :=M` akKRݷ `+ \=.>PjKI}6r2*#=6Yfov1gŘ1h Y=˳s{7|*ӟxm?$,к9`ԅ2Z nZ]N NmX| _ ߍx "^sNgSl"4>CcG7Aټ2;bPC]{#QPaV^k}彶4מ!. ж#~!]oq~'b5HZ_rm-bJn1)ӜjԸZxpέۥutECxEEɋWc|g8cP%fIګ4;@Bvsw2*5&{|bߺ/󯁌ѫmġ=LAyԽ[Ay{T%,{T(>iSeAo ƓҲ|ؙ JtTpEc 7l7 R2 'V,;)!R#u$V3$_m17zvmX2NЬl fګV dq'[.4hzGA[Y^$bW{&i3́U5L8N3olglp՚9}'m Wrdl$s,m|qM%>8¿-q.t)E~0dYUB,C( lO,fCu:vEXpV51 Vh`tQLHYM%<YuTg;"1 [$xVnXv7bIzL$4YY,&kq􈼠!&'7v*9 .0jÃFfMm3I;n@xw9a~at7itT=$\h&iA n 42c]qV,9Eeh5egKS'2cٰ*b uxob185e=:ګ(FԥXcsL(P7 @1/ |Ҳ~<#-H'X Pn 8mbͽ7ݒcximtHCQVr"଱ 9=nd^ܩdSoTKڋllLW]! Zukczh^aF\tkĩjű|^~ l̥1~'6RߚPxf-&tC/GugkŦԇ@hdv/ul)i`{$Ȁ\U@W/85_ɀ"{##8{A* dfdlX?+7˰(=X>icS, 9r:+U+ eyi^4bj3tƉ^OdLE.hE5#V6ofkw1nUM ʊRBpؗ8&OR f:^X-o| +Z dʖnsBN4{>xf)ebU9Z֐{)NOl|`l9 ]-KW'|N/%:n๫TIfD+|ftCҩ^ΑuHjԊ_mt!MQH?6 7164Z$-8ߕM+ AN=9'4?aYc1 [;CHHFQ |qZkn35͓6iyJN gq\nAtzn*a6[  sg`4b #CK![<~3 _<bm/#wi3XO׽ɀ.fH; GU#m̆* D =wz1,"i`1>1lE3/к|c#dy̷S]/xw8>0qyivQe0 4IT;zQ/[ܪfqC2d|E3X!:@Zkz1.BJ!H s/$;VyAԗt!ut;ӑ#DT仫8@tx\pp{4N<8og-lV$ O4<_at> q#G-)%xcxY+O @J31`'FĞJ=tu,ƶ3|r{,QJhڔ9Lwa28iZF@" DuNjh+LnUG|\/3ا¬з̀_`Yj$F Owk4otS!ܑluv7!bYŌM8j81!;8rNvlv4 0:e\"Th[{ % eNol,AȋG07ϒϥ.8d:aP^&¹br({R2uu57sYq^#kTDs՜%#w_-}3GrEa];}YxXMisF/ҝDdk/iUT/* M,efrhڠsqF^#s=DW5?) Ct(䎸I[Q_7IZ@J;ĊT$8"Ȋ&w7;5.3! hX z`SL{t#Ŏ͠붯g.KȪxL{ 'rx߸*`q,XUlG#T9έç8jLX5nf XtBv,Y$ 2cJ*Ⱦi -W}Z"KV$c)%Y1\M1T+e{Y>^,e'pKOZn~H>N N3CR>`G\u~<Њvŭ}@P'+>Xo_+%-N(<[(&Ky J$YQٖtM')^N=tv}›WEhq>)[f\tVm RQS(I7vk`$X['1soCBFg(W^BdJݢ9r* =L(Oڞ`'_sFp̚@Rh#Z2Nm'ʬ +=s9M)\s'40\):E^깛) C{|n Q7O&FܬT#e8eR5_)dߩ%} F1St#:ϗ(5up),,DZuivq Bc0SpDi63-Bt|Әv,dG ]@r++֣9O<}(S7|7;KS6ps^]:C IbiD6ԭ ib )0}g+%COkAwK.6F>Їufo68-MnfrJ' 2Nj-c&ײJkmw3" _d# _eIHC \ܵQr˦K\[)26j)OۨiakC!!]5(aXHIa?{A tA_=iJW礡@cE&ň Y՜o2FsZV?wO:{ E𿂨3˒",oܭ&"cx=p64Vp~Wti<R~F1Ь7鎄-̻:IVeݶ,[- ]Y6M_p;w"T,Xr^EmхJ9vE`Q`\Bf70A l A n9a\e*>/)0[b4:8hR͖:0֗Yز!6pDg'MJe͊lkvaKdRbdZ?9`Bi!YgiGLu;=4$6x*Tfʹuߟ+ sv VЃU*t^ȑƬH ma ld 5gVW03#ӻ]p^V>sR|Ϗ=-z7lfE7 Yh(U}z-.5+2}S@4}?>R~/+,\10 vO eդ-ozr}7B@8Ywu<*s"FEB>x5Z,Ǟ_& N]Z*uYu r8:lWFo0),G \g@Y|"?}őbQ b٫V0|C^SȱP-gr[ 5PT=ldh^p^YPLV,#gɝ ЄsڃBV>Gc*U>GV~ˈ$l\Wn7\ٍH+FT aslsB ZOB=Km 'N gjCӇ{`gi{{6V; {CiGQ!za|m{@9ܹ԰>HEDȽ֥f!nt[.mͳ$8,Ub.p w |Q6..aр05ջ.Afh86O`H?do44_5CeT$ҲÇdQ-ikVݕ U=*sGhh Jqob[~=ueb(1Ȝ.q`?bqak2DQ3{p7eV렺SlXkWlLtwX w UAϺ\-wZR4%A^` 0;UTw͐-ؐ`{88(:뫎mU|*jZk̴ \YM ,-Gzj2lخO;!B~Kzlxж7 3N,QZ)n_!k}7u$c?Q$m&tL\FB7g> R%}ܚ iq5. zR(U?!y 6FN/AoI:U/f-3 s#Vœ.QtUɧ A\,l0.ʦ#k،{= Ot/(Gfd/X 3:Hl8t=&;AUVr6isM#?]=ɪ)JN^K@TkUsU՟7IJ3s;ny;z O ~+i|uX7 XfOmL <e.ovC]mQa'H3:e`Hјnz]>8~,JwA}ߺ9B:Ɇ#zYtLM]8%wXX᱕)1Kj VHaAתvDgkIRS2%#A)_bJN-sY=SR` xؓ.(Q&iTp1U39̥v5 v৙Ss] 6{~ѴG.iK~ e/`FEw?.:kS9jrR"(1}(AMSOʿaFR$'@4@Iܴ`>ڀ4>A<;OFͷ;]VuK~5>I@/ܖE#\ܑ:-NPb`M&`Ljv`{ ~PB!7$7)^l 96φىs'! 6X}q+j&i?::SV`,O۽?,FR E@y6 EEQRuSjbkqCDt۞UVދxwc wGT],kF32( X㱶} t~F 6tv -|kiM"a(D&6^[y((EP0Gn{ve  "gAY%ם/ ]JD#Σ-I2$/=wI"s#Snfar3?'=XBO%"^irxp9<~C1 YؘG|w:yFbP,<)Z592E#SQIeU?ܓV]30f `C8Dx U.<_u[FيW6΀=f=p>BEu-TqHŹC{1kcz&#lJ5kmԾou3.X/?#kAu8ry*CwEk<ؗ$r'ul٪h" tq4Sm~E U!8rvZҠ [I7 MٙޑXFJQt\m!#cWoK_tN+)9? 䖗WxJ[82h_2J!-%P8TMpBL*]/D Vq'LfK[5*iX?T 6A  W~tsu]Hj"!+EIv2 u;P7w1Xx#UJ{!иԬʳi^|"xKS! L B;xUu5I"*<*kݐICHRoh"+=4r+PH_qJTDN"3+.[R6v_ 85,ۮ‹T,M{CΠs-#_P~dp:Iզwδ,3G( q}k|zZ[m_֋0o/}ʝG Zw$U3oLn$Jq"fAl/th{YrĈ/NK _SӸKa7\+U>T\9fYMawL@6u'PNj0(I@T GhcLʋg1tq] d9+Zw/)0CN v/\ڷe)}IJkf=^Juh 3k|I&Z\h/2!N}Q-V%97-oaA2:it\>sJq2VsA+?Nj@Q&ji,2`PE. 6uϗGQc=yQ tMc̝ 8r+*_jݥUԎ $Q"Edu$?DB͝ 3R wl~z8P i ]h+nEqGVrn:hJqľ|dpz<i\Gs1ȹ tɫ;$C Z2G.CVoVdN0]鳂WhPOmwh{_q}|@3vJt|5qwY{݊%Q7xz['úWMZG *dK+rz5{TVTi1l7O,+L~ҜA ;^3;3|;9f D?z_yr Et[<2Qv4s鐙^ 2H57{F wȠ䆅&"LJ s34v)(>a[Vn;yhtK|K3X 4KrC5GZDqnjn]Y&T0^뿍)8 ?5߲`/냧>7o4zk*&inD>䑧iJԑڞ}}*Gr2 Υn\sk #b͌(7gb`v{GteS.tf-8RA\G&Jh_>Nӱ-.Ŧ\-c֣:*oDSe3|;XUvaa:b`Fг@bo(V+Y OR -1:w#h-b}aߞ%s|fh`HLe ̜v jr9r?eóXo:,1DȾԞwJ ;4 .4@dO4L+zt3헥?utӧ~/^е4#/'] υBA  :"_5=ËW_ETKE1H+ŭ0pJ)d=ۆA#6vǜR˝@^|=+DA)aQ%\yYcsgWۖF30wI˟ ^'? 7;V7Pg5?5Sw ~?l~/2oN \~B(d}RzAÉ #[Z+!gVdja"T x0nc<4F#_%??b</`C@!/0[8AIb&kouff朷"mJ@d+}t݃Fݭ2J &[Y J~ Ql. kH #33լbnc2V"_ O  L [$B\`^\E,(V i'М9ifg}4)։j[(6׶ opq 7XX{2Y˅1'S8!Ԫ>nz :;;wϟܾC*4V5MR. k8׼_a}4?Cd̏82G3캆e/8䁓}*A9Pl׾f$pG $nT嬙H\ ,VOs5 0y@NHV d  ]j~Q~}قA$B2=d6- 5K玍u=>QiKvǏ(%8jCHf ""^Bݮ+>ʤoGhHsjU3|h:ђ7ЌlT<^n𥐥7඼zHOOl:~{#/*o]1mT]>ߐ|REG T/ީ 7OdpU|ȞJ+NW2G+_C)(NI!t&(ElH+%"K)xp gC3C2TK-Iy 4Zjr.4O]>Bbgs:ʋPH(#$I;% nPtSp/DŽz`gz&6I|o/+;§5쫒ufŜ?qTĸEH2aކU& ZOQ6!/{lsY}[=_83v1`4?)"XaӘxηWK*>ǟb3f&f1~ڥI*6RHtK4Sιv99s4R{RM8+[/ ""Q>D#:F?i}-լ.:/VұwPN\- GL07yhVb4{ߩ|_0n+lL2[ !Ni) i/z `n eX_$ޮ[+;.o7'9[uX= 8,9_p:E+&a5$ȋ} փo$ .T .vE~#~?tk_ڈ<&u:?O^?‰ppx:F>Wo2-­17gRFEXF5q,eR9 S{͖7ptu:s[Zj\S-ºbƏ|n8kx=8un]m ՛.uL9`_htF*xI0R^=|J!u^?iOP, VNhxH\}d P~0R(—RS})ڄ|Cҍ#V0H׷)uZn+\3gҌz3Rn&n]jzJ?Ims3C:{4{f߶~81Tݦc #Rm)/5K ȓҁ&b!8$I# qm%gX=3y[(p(Q Ö1ikM#F'x佽 Ũ@a?&_KrvT1E e+v܄7GVD$IL"C:A":)^7W8|XFP:͝;]$(4 ǮQ֤&VL_1%؉߾L5]Ǥs/2dHD I Lx;-!@\s<ԇ8<  o]Mf9Ŋ\y8ڜ6J̇$B`c7hIg ݚwͻI٥{5} Ht&dp#N2a;k$[Hrh>*dknWOS RgzQ}bp-0B)^{y|bq<3@Ɋd-yZ][y{/4;ӆdT yxwdx AS&a)kesi&֛c+tCJ v[JQN0ŽL&+>+܍HQfa|[63ߒI?bj0dY>>L\K9h\Ηz+yjZeZmUHPr{5XwgU pZxЯ`Nl^r|)=Yl)e>"2ҙLе`nPH0c#=B%zp/;W`y1}v -|?$ҝ S'a< RYsi0,,rޙxN ܽAw*+ :r'B裄b݂VNFk K`Zi.9yfoAk7umU52:^2pq!4!~mm4-፫q=g{R1Ift7mVi(^UxJ]f{+G➡Ց0l9UaTLw /k!{JE\./9oY & jSm:ZQsL!JV*6/uK7E$ehW(/ڱpe۴Oc6:{ɬrT {@]댠jwӪՐ4Ԏc+-zmrfD m]_%]$KI@7ȩE'8NL/* ̍"3㤣&M4,6%H_[nҖ`j}CQxXи:`BW9M6)R#Fբmw@h+7 } ʲ=aGx"Uڿn}.s4Hu #QoUf>*0t;W]TSx$e$<=Ӕ[xװ=G;I૜Y 1!19OdOGLH 'zZ)qf7aj ^qKh9]rP]?CM_Ľ^+qpẓ{b8l/&(9Ëu&!]:I+) .ٻ㩉"ݠ޵TfL!Rb&j+M#.yz_`c}.`kyy3[8T{{>֕Y3LJ N`R%cS)NU>..w<7ž-ƵݕSjMi*sLLdzlfgIFP !35$X %iח+-UIf'-Ϸ# ʪwޯr:KT#]~όyW#FeCZS`-C}BqCޤ7JdpUdJ]M~U>Oo+}mP2\գߋ2e(wZ̜8'X7 Pw5*Ε9&JmǸhTEPE4^jXScvY+m[CSù ^"yx UnA+dnƝzښ'cI[=+dJyܯFO{͕z,hE(8 et'I`Ҝg*9d؏}47;M!< qvøTapwH q\CW{|tkp)$*[hǓ/fa0.??i@\#ӧexeb9'gsQ–4.9 s -DN+@ DbRٓ&u3ATX?KCЋ YBU e@0S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPnpҷ|8h x%S]?z?:@>%v KCt<P A MׄXxlE++mY;n^I;"iD:|;.u`+.An"k$=4r[2٣>Yz_IL C|'~> '?jT{mg5/$g[ȓpq^ nXt_ rZY.lœhz€ö@C4mbD8l'Y!PYH3K C:[5˿XcAa "O(Q%>uVO<# gr-0zj{+dJ:؊3F"siڳ <6Mkn|''rbqz@f<1I X>٫'4;Q靭Dг#q0eYC?[.sĖUL+)U@ N("LG0PRRw4m6AntTG|23󣊕xRza|UPWͺ6 E'W9r('҃` 2?Ls' -ۦ &߭@`oLO6v>j1'=!5ܣ]d>Q{P}TEu_B }AU?~7{+QQQ)v#.xNG ҤȨ\MӶ֗` O9nBaH-_ec+[]2Da<3f5;C쀸RFk *9*ײRhs~L @C"w9Măl+zgh@X@ ge, kVZʱˣW10E49)Sf1BR2c!iMBMQ u]B#ά9jxH} Bb)_i}~+-]Nfpbڠ2wI)% f>T)2+ų)YNLǻ$w5ż7\l*BYz ;-j]3]9TE1;W-Lu'ԓY%9pd( P\}6 #@`coCpUe<2UʹA@^h _br}";|n#iaw,oʯwT,>b2 ~g \O:鳢b\d)j\e_= ZP]yze!#.Vluٿ.=a5lp^N }vi#2}nA7•$yh%-%MJZI3RI ?rɘgƍ7T d^:VǞ"K-}ӘHZW}5N|5_g:%X~Ot{} Dnj(C@#׌ڵ (io"vYQUr*UzH{:YrHk|k0TAUZTzGGC!Dh׉ߣ .eCŎ:8Ψר'4A$?`onQ b7[OPm` M^>09;)>dPw"/@=Fd.A!;ۚiwMZD} 3L|nwb[1-Mgtm* HD2{0ʍ?KV≴& i2jm\c?eZ+?""#9}J^MvP ]_#IgߏNu{#B3).d𺜉Ф_y358(+"|hqn۵/GFR{#ow?NWPz"\vdZtO/CǏcd7}0b7pݮc9DXI>ҪuawV97{Q {1 <;d\rx4s Y _< ;H4i?t=½B$ɥ0>}IcXeTݠB>MsbkT^N.<;XpS?꾾keV:kZLchbg'(i酨n4Ci4ZM%X1lx3+a([iፏ >gLHwUUCw XT<(b|.])XAL<#igm (h*Zr<IX'܉9oycibbj5m7]uvSQc^Jܙmur+w ĽoXp="?|o3 nZ ,Yg σχE0$/b_j$?jqwL(2Ъ^!A~XeE]%c3گ.F9F)^Yy"Wz؄06>4 zRk†t1ގP$;~8/vgܿL*OY/,@m, " aնVC ,lFMNc&~3L9angw-}V!gK%XTЇ9''O@*HHZо޺h,d}qXP<蹕aUe3bP,k]N{Lɉi(_?_d*.0S!{v>=փ"ܞgeK9,%0IUmɬY0zdKUds|ey] ѕw٬AD3hl'l(ݑUQkwP K*0 Y^ȳЮ/b[Auw+xi+U;hojyE.g c^>uwrN %԰r~j5i7EFIfI ɗn7w n/zq )x i7Lqr2M-eEke=5W$IE8h!Rh@bvW[1ZgyN&+H3hd,)I}TRNPJmcg*dq;B?BDƀ`TsqoZB\moFmwĠ7=-IT€@KF'jWu'6JtлaPpC=g򅶇MǍ!5*HTG2-,roFDm[~p8bEo乕SRD/wʭR;("Fd,>\& |FZ{t s%UwY&hc;h)0 LfeM4JMmVLc)Yh}N3q"$BᗇfTn:hgW7T ; _2nt-$ А;d1Xg|tW37pIHz3WX_O׋^[cլ:"mfDYm'UfPIh7BݻY Tajdŵ}'"S'kR m{ J\kbfjQ` >;kY77RDžn[3.Feg` +;(>,Ŷ sr䋛I~5F=OQViglJJe%3o1{n ur!rN #sYo < ޟ+:y\zy6K"韇ɭy1כCV&+&bx _&RQ9T֣{hDKم4L{cioݨc6FL18!(4X!(y ,/b x<Pk;mFzep1EGyd" DHݓ\lۧl0R) _.M,d.}{ёz,|OӜ[YQ+M:*h@oʨ qȁ1˲3#F#*F+Iϐo$%/݇;vnYgP%g!Sk<ٰƂ?&N[e 199 #c!WT:[(WaU2IƸfo7zx3օ%g\!)WױjU AgکX ޜ [f+*Uٰ9sacOKFr| Hd7qPũ-际g[ﴛIJ7Py;4\A#}FUP#d g#qjcN܇nX&_߽2rO: #c^F@$g-$h*{ /b@$%pԎʮ Ya8~euݔY+u3=ɂDM aY73EslJ65QnHlj:lijl(ʾ2 ,'c ܛ}TQoa^F!;Od4MP}Y~%,#k:9ƎǨgWune1~Ҩ4.Y7 ||$@|b#gk?)=?},r||pY7uspu&=IK:FcnAgڴ&éjؕ O,˷u @ S\pP0YJH' fli.!3|& w n=}D6%L4b9h8Uɼ;DK]>w\R gXv)v3AeF9TW̿N#;FgȨ =g!x'ͣ>O.6LXuUXS @ Z12_(7c]4K?R|tsD6WnrsH`LS]ӥ ? , G'~X@:&XZ9Z8p4XP.hͽWT!u@0'OSrnDdտ6V^C2OU]ꁗ1NxIzC ΦPsIz7^jEO+h\k|d; E*/Rhzj%C~7CO@,ڠGtՐ%dS[&m\HHԚ0!ߣj@o>ZՎh[u\;b0lqi`A%9pD(ׂ?UԧnMsyD 8768$0,[ vc~1,ohbh#dz=7u ?pncqP&BBM)3<)4v)<SK#pG7B*0f =ň,LٰgfǓy>lVyBoEShALVjg8kb~,a:>]vD a )AŒ{ _ .ˣcM⋚2Nt5P1>>cq`*;cI}'bdeREXGŗs%/7_r={l8x ']",V Y*[kd4}Hnq|#hfko>XFF^CsZjJYё)Xy ߓRK3Oo#eb2'Zq%*ͣG7 5vdj"Zyj PqIJ I|bxx Η;AlhAzR<=,^jD@KCU34oh{*t|ڕ,f{9{cyPa Ĉ5D$4GFrWݽ!4c l?P~{UvK+⤀"?6[ES.?WX7=E~܀ 8O{-e2/b858Dxmҳﶬ ͖??t=b"gUmo <קq>`.RsP;AP jf#1M{DDq@K4OtIDmEa=c7XۓGUMTFCP8E-/Yf,Z%gW021Y8E9Fk*$Jdm!di1+[ref#A"ˀ]Qo!jB|<bT3lbR2*ޓ~.%~Zq*5]Srn|<V)󑃰5DenXB~vYP;5LqXNi:շmք W|g7Kmɚ#1LGxkx~*Nk_CmҾ2iQ_p4̬>tW-utOWhNaGxmTŹb\3f?+ 0 Ys1qD4 phA^Q [XE[<K\D5u[vrT$ATB&tGE&^}2i5Rʓtr옎-nSB[Z QN7.'U<ul9O{h)Vz `V OR;o: نݰnQ`e%v}q &MbZS,oy/l-k姠kܘܯ*/5)+9El\0xͶ:9;pQtB%gh YY1KO&ˡm0H EڀH6㐡kSe^޶N5~ ZB)i',6RH!:CD=wZW3`jFMzIW\r<ח6G쾇xέZRE1^5)&.=0k!uk 'u<P6QBo*_w;}v=6;:81n8?ڰB-AX+78az\ Mh$kv&/9'#"¢ӆTM&R}N߸ĂltOMU>GDz0hN#)huf`e^4a~h!>qh!mꫫBn@P\=S2}ݞn})AXC}?E@]uDIٰj Qw*/G35g]J D">㢐bd/dt_RرBE?ȏwlSIb0Gx'Ȁ]Ho,h KO#oo1XN/b=Nl;Z>t(yW|m52җ%$·t峙KiCO$pN\iFpQ5X,wU51B$ lV9KPxL dVƽok]ζMϧ?m|0;O}Tu'K]ÙTKd>dL3Esv#?u>✲v|]ffs:z`S:R/ ޞ0C^MT*֐D/ +y#-a^ 0m;JLB:HDloY(=y \+~ 9c?qw+ǫOY|VJL#oTtfTjx0?N"u cYsY Ky`4ps3=cS vpd1=s>&p̠Iz K'sf}qYt~i=2u9-T"sP:7h|m2,iqV`VlgFE\xEDև`LpH0V=,?4+-:xlQ}`(J4gȚUw}o݅Z'PӀ v\2?,}^H?gП=_JۄyM&cLj= 3jXx c($:.#zgdo!KU/5|@8x@AiVz40P1;d۾h[n΢ ƴYVݑ|TDق}5r*\΅VT ?2qA^?aCcv s $^X_ +@_Qˈ+ DyH牖 ##A[σ g0aڧۅBL^̷b-8VHx9zA @vK;۪Q%hn^L!zg]`} jQfaCG $ F%QHY4@榵բ'i+aEjnSm:;E!q*ss[.%^0+ET%(9TXN! `ZƖ_Zd8w/}QbD>N|kL,57:O\>v,pYEqС rH!mY|N5 {\U5cZD -w~c".}6?3Lʮܱ1r0gʸB 0lfB´I)Ic$߇{>7ny,:z+I>Uc%[ŴˇIiVwZϕX*$M 5Qm*/9(,wK㹞}WLsEvs_s= G@RskZaz֕]UbZi3DDcАa+lд~Ψz"B=%^h5O,3fV7:qpIQvZf}D8mk$A<|QpYȔPjA[F5G66 '\[ WG%𥳐D]<[-vY%: !_ ^?1ot7 :zE@ŭ|5O61Mvs.`A oByZp(u(^о>yق'il>D-n7LCJni'GUl$UT"~Ű$ u.GKOWJIݱ.nh> vA(VSpTY*|+Ư:RPtߗwx?J-r61Jv+u|^lÞ*/K|gadV~Ѧ2 ð9Ɋsu9-#_SV8m&j,i"괓0`/d vzpawOU4oV}GwT|v޻vam/t@) 0!Zҭ# d(o#.߇?~?FSȿOL}+S]}Hhv<8}pn,;t3̓5XŖDx<[R;BL 6ȃŋ?zz !;Uu8cRơ^fS3$DwelČVV)HJEVoS:;nZ~O|/!N|DvVy>MPtዕN@R~qu;xrq)Yu$xO $s$}>/Wc]sr쎜-!cv 7\:Z%_#n8^)t wO|'m._ν'lgXeLj5աh)P׋a9s%I&NF>% co*"ؑ5Pd%+\ xG蓡$kuڙO"'^U[oչnv' xP ˷&jd0:Ę"&R_kؠk0GNzc=2>; ޙhW+_BcsLrps֕R[0?حbC*enPQCl{ֲ!n׳)T)Akrk-7ŝ")^4&RCX92Iqk0LLf2u .Sd3ξ!flvC;~7Y'(u)B(ϡ%xvx 7k}߫`ak_h쌭`KlMH?&+i4si9KF"`̿\d-JJSdN qoIPc=&D0k(뮉o4u`M'_u" [ 7tf*pHemJX1U#ԈP 'l4|Nܽ Ds.tv)t 6 ͧ5+ڳ;"u@zk):_2AㅨG{iǵE I ۃ\ĆfR~H?oYCĵi2v~D; GNN7szT^LyO|8_Li Z$VJ,fKo @*@-x(q_D p,14?=Wh/‰$$nɜgL'Y'wz+vo3濺4IU ͪ579dJhwAjJ~°*wH\N?̴xzZJLRM3͊imͱW:NgTL\wb A!NƧyvYB+Mq$+{Z:J-tGH9u^P?LE^>b \/M_A)3m]`ABr<,9=@bJPR:'j4>$sn7]U7F镄Is;&&܋iƏY_5g&||\h?_=D f{! y:4H ߅|l,D. ݷ^i!˟B$ nYWðwO+uHxHaܛȗ1ܳ~xPgCZ! ]`Ȋ}e]i ÓLW~Z!8e0_B) ܗec`TM(5Y3:x$eEM+l*@A||娻운Ln+_3bN|5?d~OFcOt[᧾B'X X`kCسTDZÃIWǍ+aʐ+2#;WN#[ ;<&1x!s̤ S0;^#1k k92Uγ`aI9nb1xSvXQ:g0i#9{^U?D,*<7ՍwC'}W'":dfT} h2Q9:Gc$f`ds8ªGANFl`5'.8zPVJG2 MH踍^h#6ބf_cGdg# #Ǽ`b5q۱|Qf*h[h 3 ON:<QGz׊yTB|_ /i ~}f`{%5mCO} xy5X̞6g w rϔ7 C֜첕+U0bMRyUXr2ǨW4~wկq=q XӸe1 bƗ[\)mLXe%=l5jZo)m4ՖS+# @:+]ă; SHMCMP _]؈%?8K{k!p\|$~.fRy_Yxb1 3+@.1n݁YOo<5L-=>vwj"hʆi <"fi9juVXZj5x95]Y LU|޷3ב'`Cv^H"ꜨhaGC䏎NX4;FNsn2\ׅ&M{l]!x7w`?OQe׽ 8nόdWjk֯K$3Mf54,R Gb mR#5Yl{FHB`C2)06[7noF Kn a<g&hު6zKGav ϓD_t-x0_2ո@>C[s٣#0b8~*Z^"7n#n?& еf')3 e r->*n^VXHg}[DED:\-{`mH|mtx-(ݐcXϫsYu޸(\g~5v6YaV[o W0c|/_E 2?#CLkw&@IKρ*YW}#8!uz=V{;iyO֔Z.{cSy_y%iEq,ٽ2sb]djÇ!H5Uc>ڔn1K}[O<daU;/GG(7͎VDrV-{>+Q'>1ydBusdSx~f9qg!|RV/8պgPCau86K 2Bjq_=.daHXK]ey4XYes0ꃻ&ِ@M K|)TKYN0s{bk=!O[U0$C1pDozr)0Aშ ݹwp 2Xqg58Al^cJ<Z7o!+}2*k#~>Ĝd5=֭7ᑩPx`ж]^0 ?Zr7D@ ~:w/)rS\EC+*d# 靭Cs ,b?,d9F`*DCvC:UɈk;Fs. ή$4(Ft-3s Ǭؠ)Y5ĄZfoc'`-H@$ij`e> zJKYO5s2=!)]Y n,2:{7qHǐz {v|g˜ ZzGNQ4{eP_BE%&;i=_x$Tπ34{2\iF~ag/S+|Lpפϫ=OTur??a ^-I/_% >ܠS=ND[hC_݁D;\Ha` 9UWζH05h#VgWy3nܸ^, .i7}ifWôvK]ٽ'"FsOBtjϤ;סz"Fx\c2ĭ}?F:.z c1EJœ')%z =z<`>cgm[eLɏZ5XY 3`wq@NY1pd!0k.foqN,`>@=XSS[Ӂm'Bǰ,W[!{{tY"\4XK}9)3CZ=\C(N Eub +# E$i89%]t02p&6gڻ\kb#kN\bоq^d»(ᜓW;wQ|@>K}l?O3qiQN6?|>DP 4ڠ}sFy˘:_`.jYل@||D:sj_`TM%48Ct)=MBY\ˣ hwԶ3=k| > w H}/]Y.4Vxzŵh#i߽K$_s}|! |> ::"ۻw}%]ÏhLxi${1gaǏOᬶpd:]Ca8L~^=3$KQƆq{cD5eqѨZK䟜{)25LsSP'ZkIr$n붊9T_޽ 8(7|B. ¿POhVcEvUWq(T6YYJ,C<>3r.&+XN 6짻#`58ɳ:-\F?FV$- (=2j>c jZ=-(KΚ:TЯnly9vtR+8}>J ψ^hQ0HM05#!BrDF9 aZ•Pv#(9L*e!.a,N| }PČW6|yX RXC֔aGQ}4ᤧc.Y@0N' d ,RK8uE)F[<|K6M=0:IӾ.΅`3<SPM.3MDuz?:?f6Ⓐ cJ} dg e.}8Gh׺)ڷ1!? ˎ~1NfF!zzfXޔ1[6=u!lͿP,UdI4PG.N;/e`9J;%`e㦾s\OiWp 't\]7l",ʷ| "zSԎh醽|qaY.{&j} nD5B^A$ڥND5v d,l.p>YOײY[AE&k6xn*9\~DO9eJoj{CŮ7&&6Sa#c41[@N"foO->ΈHҬR^0w79S8VbW;D^ڸS bՒ@Ga=c_iJuybDf.hQ#U?&%Gzs|ߵ-íª-Qi^1Xظ2R5 wF5]2Zici2ԉNJSܼI:NVM%Mζ3%"%iyV*No..Q9ۘO8`Bjze5H$}x1>(N̆\ .9*k_H`|fY\]ͱ,/8b۬Y2 ү,O)!D1S1-"UHC9xf5XA3 0eH C^58޽vt4̰W.3=+TP\?`abs攫=jLL/}[>5Bͮ+q"wGc,Ѫ/Ս4۬aA'c |'w:~ƭM[4p{(w\ #b| {.K_ mxL:&.X͖;lQ -'!2EtGؒUM-Ubh6D1{0[L-JN4]l g,ykIqt0.O[vqle0OIp3Y VuH{qπy02f? ?GE `2^r6O[ ̛"<5lpB+Y^/LYf3g#b:|d(oř*X T7v&~M24ChƮ vjgFe|(RJ;0 beP1T#o0 F DHU>;`q4ߧ~#'-%^'[Y;EKx#ۭsZ*'(oAM?>8[-݀Lm!$ }ySe_f"SL|AE^7H͞!o&Q&+[vY"wz[ RYNc[r~ v xEO 4 3=%]-ߴgL,;);f[F` K琠!K 4^}I^x*Ywekd/Aq(#uʓW.߾XG="|KG!Z/ k <,IU'Y1V!%_ B[|*>& Up* :'JUt- cw90D0/kK UJu|e.pr)/_t(Pԟm)_W[ucF@.Ucƽ1ɆSyw͜ƀSi ,.=k'\nUZ$]@Q19LTM@1[_V'*$Aܙp^2qk⪓ډ҈};ksHmS)z.B:~R |_zV@?\w8XAmof17.">n֗JEZ.}ljf/l***UE<I+0i/=i(:-3&|RfrRI}#wf,z77d[TEFX- ,x4ngkDu<-Ծ~^msv0!)KMgLDbT~" Ԅ&,Ȓel_qVG3*@Dq[JB GDXtu  YY|bJc\Z'B%rl^@^bR0%M̟iy oi&y! _R_a X/BuO:lWUH$DI8Jsnis6_ Z1 Ë׍B]*/ȣr~Íu.A${Hs6݇$$! oԻGEV4B,$_#jW\i⊗睳4#A)ib8iv l_<}?y}cy 迓S0=l lMpT-Nj%shؔd9΃'boH*Y;`v{%3ԥ;ufh aNZ{A?-=3r2trtˆkD1Gۄ ]K)\Ʊʈ0*Z:dNǴݪv Y2DK"2uے‚Ap-/ lf.<J 8G[W]S]îx^ɰ% Qw9M@*Nތ;ɤZDٗce'h*3R MN<؛8c1V !p:4 Sq݄9oߡY /V=o9Vy@9$XiJ0PPy.oTZ?e6|s.<WIclm`fV:JNcƒrfIL"12 +6]W㷽A\džNId m";tj¯ 'bI:y), -?f؅41 -OK@p I9IeVnT]mf(JEߎOY4KxI}IZGfrg߿gs뚩 A*#.v/=]~O#4zO H 3_Xң!% #XTnLٗ̐_Ύ\&|,"=؉(ho?b ٸu-Ȣ@3XjRC_='C"AS `xl}sL+KK'eT#΍N*E?W%DK)~wISl{Vџ3uEZ4&6AP4#~yoYa健Bs0Z3B>bY^9~ ٍD:5f<@&JR)"/zӾJ1:aSE >MmH)P2C%Fs\ =Yq# F˕of/ 4wJ#.8x@e)d݅=^*u3V-p\Ƹ}:a[c=M΢`Bv8yU{R?bjiځ i LH$0V&!JV+NW_Dw1[~O'4ok3fpg]dkN>mָO'\{QhH>ؗJofiŔO=PG4'YKҗxO&Ѻ/v I Bb*{㾿#OLu϶ ~vmaVY+& C2ʱydx#.<{n{Wtr>ޅ#Bi1sKkq_J8-Do5L4j`M +gwyWc$pCh+!kkF:9u 5̶^[_7uzB\/tat҈z3C&OFIC_KUf͝c$`eTgh\Q{VjdJuQ\r(\| (|tӿ F52"3< M<᮶Hq&bXJ3Bs?)U\O E8 )U2Px=h BK-h$v9kwi鏶 aw~h8ї=1|^b W+Q`!QHDA4Ѽ:AY@ .'+@TE\!B&T{)-i/$(I/0gYbcA֜=j 'e>H7[eHSx#h#[@՟'$k F4*S4M/i4+$FnES˷2G~ 4iթG ay脙]2ב^a֒B.mܜX# PU& /,*ffIcg$nmb|mG ViUQZ"X:jÂg]!eъqg^F2UЋU4ޛsv, #T!f=yxfF݄MMݎ%T_m S>h^47{\#zD;Rw|4S /x$%[fQJ.+KȾ?ǹ G!xȫZ+--L(31;5MU$r5R&<|9DJD9 9W > iH5z:*%]dBt>N)LiMjHdž;V@R +ŜHp&Ca6xBM'O\$-/GB(=:w6~V5K켴#ҿW9֦M5hJ)#mf''͢>=JT'z;cPQ֣KwJD>E:Ld5ߧ;G݂~o-#l0&lXz,I >6~"j,cMLŮle>O}v*>ΊysE]QvIHk F݉"MlJ?0_1}#qR-frY(igvA)Z%mu`92 Rgr<ő}n\&vpnuҳsM 61ԅNI1f;w4ERj1(b+-hس?'uPs`in!fڧT@<=Gr~~MAqgM.O?80gI?͒A+ʧeIg/᯾/}X=(^)ϤU9 fLWsB眰V*>36,Nڑd"#20rd+U*?+(*Pfhn6ׇ phohōq)7 xӫ%;ߊ'2yiW_.@IZCx7:\M[{F?Hdc3ЋRWCXBkcW֔؞h*Pd)aFc?*)7|"g# Z"w{u$7s)E7! RMB,Q5[A *pǗ,S_1R7_&/|{&z`/jڌL~<] #BZBm\zѬgZZvǣ:Y݉~6 1bS/sFK5<Ggڕs{}>.f@}r*6QJ`5VXݭi|ZKM3%^!v|/u7i48Z$\Β61_7kxkQ@6 pxp":,KmNij\~Ŧ9x; @ӄ+wҰ7m\-?P}nljuHQ/+Zw|x|?ʌyu2Tsz ׎UuG. ͎=D5 kx:zT8H1r(+$[-+:xD%CX\UCD[g=iK_~O㎛']7tp0,5[_#0 cd 8(6ژG- gBS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPF%#ҿ8XG8dGtNwAO6#ȭb| @|+@>)BU'Em3Ld%x?F3T5u+"@8 fyb՜jc@RNp +:X |5b`FDWVSn F?h e`̓~3Haf9G:KT^LQ*Od? vL/}(wUՍ*Ň(?/`h\KmOiIz//de+iZ:Md2GZ!Gڜ`+_X\,Nڕ:Gq@ZLGa,˨K7G5*U<߱S##k,3k 82DCPօ$G$)pa#ÑpI6(+9,3`iaɉϏ_ GٌGv~>: >&b&]&sPͼ 5j*P VDI\U Rf O%KlUvm ^pf4y2=uep@Fѯ@p?(Hs\1x[@i q/ņ\M\ Cvha_9T/=-JPUK`~g-X3#T"\zZyh+CF$n|Cb7캝~'nqg 闤y HFfTMO5 tSO۞1YL 1!4 {| )Vj2e^i7rbuOUrvERIneP1ANL<@[P# X@z"%-yÞviyKllw-g "y6lsc.[cZXfQ Ӽa'b(. 3$ԁ##zL}NO?tzgܽ4&H OT1$ v,~*T(pޑvA>6}yC N¨ G2nnbu|Х27.K[ӕK&!-7S'3HEc!nA%0H<,ΕeSJfHceRN5xMRxNNjL}α#|QF#7WnCoϿ4}|{IO!`g~؀xsR˱i9Dz{ ݤ<4: +VY\aޮSү WqN.;Ƭ -4?3{H.EqxoIFfW>08̢浧$Xܻ"k: 9+1(I!2pW+:2>|[Qk7"vvKWάB3Ti@t}rjnGc`X6 qG%38[a<$7d wBneq>plVV 'x8Z)LHbM{qQ&l&#jccku o2x(7&'V7%nlD:L" TU !Wu %Ph a_q(fe `j vxj`?ϴ38R]v\p^:q~.):@u+ %ucuFPkc?[\t2ϒX鿶 韂}ic:.*qւ)=x^f{kp[ƍ|%\/ j\jdY(}KQ7_]XM2ͷp ^@Ǻ>CI[_#*`ccr3+CB9m2Tp 3E"(>|N'vy UW{"*g7@f`ksG1㫖Nh,{/66CfQɝ4[gXAx1s=TP cd#!|xM2¶oҧ9CK+6`H{<j$S_m@O.3IP{CeG!!/7>_#\ɵFMtݡM( $ 7|^6}9CBT^/ '"hnvtD.Apm.Ύ/##ikhB) t1׈gvـqwEa| spD԰NjBzE?K7ʔG3[ߜ!$uA+ݚ04V!_C"&GaNnDop!(.{o%"ÅLx1oUP4b܏te  Z)}p(DaKc^,&"](b50 l%FٯpLWZZ?6;Ăꃕ16YMrb`uK)Fb cɞV?@rjܨ: i|~q~`d>: 7c&1Lw>? E4C"UcmPX|:+x^}Hز^}(6jQL<e/ъ$9QkdVzzv"3*3sRG秛T]TbPC- !QڷmvH*Dffƻm] K7mrɂy DX؃|Gz_"]!!hjY2|_ER8) +uN9=f̤a3mZ'qqj՛}&\Ov.78ٹٹ ]Ŗ?ڂIXN[?_G<δKcCز kж\ TTL5Bh08҆X!gSsϼu$VFT֣k(/#T^B/ T?M>jNC(F&AMrMwRWO}(¯=BLô܇֞9ViAo\]e^[{z*CcmG "bzńzS9XC؎մCL2 ݉vAm s_&RZɯ2ATm9U4 ؂쫂aF!@0XZjڋ9=@c4]?CAJGzvaH],|Ԭzk{olhBYߍB$f*=gA. Dgsy9S YgR-VD(5xN aEMh~~H3w&YI,3! }1'Ѭ^+$\( |Mj1ϯx5N+Я\D}N L,_<1pt>demR ̒_4)qGh ehӈܔj&&-COȗ¨ec# QW@ k=ᦜTDM{3iZSQk"G"h|K  \fJ2@R3N$sMɖ&*FC_i{#H*k'>г^Al (}gn G<é%"%%G WhWpgֈ̍y:^ܾbynxe)1 [s!H9\BQhٚ8\٨\XR*{8ld;X'y: д5oA ޅV]RJD+2QpTcl ]H:k RivWйhK+m>ٸ{냷] )Qw9 u;Cc XxhEk:w}Ճvo߷&Y÷"u"!찪ͮ&qW;Ig Y'̒KE77n(ڟ{ڿRr{-Fcb!?Q}3g(qCĴy?ō=˟( g GX`[I^(|b$?d4%o\tQ/|sSRN1Un%[A*HM8>;6`x MBXTf0m:TC((f|y~@Ž7d^hfA?<;br #4`ȷѦ Z?&Mxlf.=e|V܆^a࠭oI`gTKB|_'8p R|bFb(1#^3K !YPk4S4p<@¢+{5h.+AXzD 7 ,I5l__m-IwϰBt~!V’V/ފ ׁ gϽbU\(Psl'!giFy͙C{#Ы5Wʢ|@|>X  ~s: (;f |@|juD4-UCNMo~}ެPX1DΝ JçL?N[n/nrRYK MсXnBCmbLsK&%\Y2=t?g8+݀T<9lZLk6y>" K̙ z(Gyu}"$Iw^j$ +6dlrBDDuޝ#(q,Nf.m+uzB )Ro?oU-Ӭ#kF()ߠY~I"K@-Kҵ*9>~Zub%C8\iL U>CABRt{<:&߷ML gfXǶv[۹**yԜ־硻*2!2G7d|ٰh~HʬO, =tk8B!,-(/j( ү= R"rpiݰQ`2? G:oxR^a OBSR1$)1[sRK"ۏ?g2/'z8/;Mgߐ*7c"17 McxN[M̈́H|G t,r(xOcu ` gb$X$^U(`-ܜ\euK}}}=b[7 x؞dc ll[؅wCI{.}llζTM+MrnbI ݢ` TܢMi󺮂AoC9-)QQ`$8z$Q ?&5e ؊ZbP<" ObؤNEpN>');uNO5??1ă#!b\4[.&zl^_1#I]܊=8хaYhs }AS5? ~鍶E)䇄?K4=Ž@"%ѡAK Ow-hQ3iu _)&nNJٗzu8w\ɳ'R{"@Ȍph -HLc\a985nף,e &>d#pMMwK>Tiܖ)"QftɅ3{e)m g3cnFeN}0,zhbr<%g`5PsϱADVVxGj۰Cb+&l4W.v'~? h qSٽX "9Ȇu)/J{N9sK ?H 7,`b6VP~&"."r(zV~k9U"JTMH~Vf /M7nʔVax㛅2Y6XAlCMhiI0~IrlnFB<KPu8Nz' vwkO7pnLy$ő"3'J h)*#3[?UC^ x },|O5cOYb v*JCd-[tR(D9Ԏ>B~V.| V.stXUs"; T0H`Em !JTUsCQ3]p臛u*#d1_k׭FV"Սo!t e@As1u۵2(OK:>`Vj,l[Hs0E>&Э8:rPIOn~xIf ĶF"3ot = xLIAZ$?<_.Gy+- 䑏3 ϭ@{{LSI>2z`vSFgAgi;E] FY iʣz}n7IO&קYPw_u H@ ï+dU-]'?=`#p#/<4V9]+2G1.)FϒA`PnM fD֧>I ]D1LqEN\pKr`ՀjTm} ԖһXcъ.4OhRɀǸ:q+~Xବޗ<% ^r>vg۟oI%*DmHG%_ꡘq61z͉ZHSE;G.v)]yęTl9r dY:ή5[-CEf(\?ݦt2jLs6I"`m |9u}+>د]dC!:Q1inZ1:N[1Kp6\ Ic{w߸p ~S?nd*d| -n{5ّb=mq-gM۷x˭mug&Y/o WstBR,.&&t]!J>%|2" CP`ɚh5 t(H[:`jŒ0XdIKѶ-cBR)2\ CX_-Ry~{Y`YɂAG4,Hb*nE$T+u2o-]R*O 8Fߺdnӌ0'H7Q>m "ᾳ`[E7vx\= `y'v]6mζ!b6 pc+zU̩w&$cR%oF♟KrXEno#[F R#E2k!Z{&n4S @ro+h Nl NfԪkME}tZ;qnS.<5&q0:bևt)ij-oq@ J[ ="Q.t+G Ws/|.ŗWPo ך/}=IE&0Am ˞P2V[[@nXʘa9jJ>0bGӇM@=Lz﻽>{Xf`2g- >[S)ǭ[V]U+ymMO[YSbGF C`_?L*WA-d!0cxOWX `y wy.jv)&F5$$ k+mv%Cy̭suԝ;yqx\ ҹ1B_)@3R*" HAnǐ\{R&H̪0Y@tn+#>A\9}Da~@wtRb͹i`5FHC1%iQ4]͹i=MLݓU+q2R5(/z3ʞiygLǻJg/@)FT.{U@W'6OdX-Wor۶%iz$rt 4ЂOpǡ%hxR{\-̉aMXE*S]>ߓh*hk'aOy녝9'WJ\Gu0YBx fPL5daD~iugHcw %I[`%ài`XKxH8pp uw6~鷚:NMID}.i! C]/r6؂n[ݐíL KvFAc(wJy1jx~[j3,*@&ȤxhyvOaޠsm]Q7_ ߏXwM+P9MOmSq9/bax ȓMᱠvN(2oᐧ^3ULg ﰠDJmkĜ*L0 nr\yx(5z/m=iNKmh4aL O_^Wʨ}ТE|lCF#ﳔC^ŷ jj[3){.VƋͨuAEK^i*JZƯE?9ӦҞ 3u }UGʜvsmkUw$Qp2-<(QDžJoZp(8&m>U?u\B{Ś@wm GI+6PZN;"4A< -RLTR"[Ȟ"4ǠTݐ05s,Bx2m.g䤏fA SV:XzGμrW!'E Wc1#w Vgmr/$- ++hcיKpt"t.a V$=rޮG֬lo:~6sԻb Kw`ϵ.: 168{T>x.(lX {pY;Jp,-rM{slVW@v[խݙeK|?-.ZBMv$EJa[xUR1$o&]"f4D'v_@)Ǎjy m,!:]n+_G3EUlUY㎨\X3?~[Vg 7*"4ђeތ F́#U;Rq2HU%`g \/J0r7 >lh-u&VFH%.i?[|ѿ ?o F4?V$P'E7qYU*YѳD 9W.pe* äY%RMf?&Hvؚ` ]A8q'Hf=*ZI0ķ(RqGYiN$ya3 ]$"b Pm-Ga  |Y3%#焭a%9#B8{j#mUh:4q5e{ِX4p Z)eH:nYI1/1X([vMd'/YKnA9` j_;V.KGI$T5]~e磮ݩS !oҜ|BABW8Ja|0z"{m,%%'UVXHT^>mw<Uz LKj]nڂhSJSXa.58DgG!u(JUXG$1o_-UzVir <><,(n^3G6Robը)?'z \F/$sbs.apsޛXjϔ"طH {[hu+C9));$Xm? B6,H>B#k1P,#D~) 7(jQ|'E88ǖ ^20Z9 CA=~Ç|%v99Q+ddq :3 [Xqp *gi,UzځΓ!Io;4$Xi9|i+~"Sn?5M0f3/GZi' pjE8, m@Nɱآ$Y i̝raAHzaw~Jޗ:ERTHF ٧KdA!mc%]%bqi_sC?m!Qiߝ6v)a*k@TAHMD5xȪ yOyu/ 4~kgKG_3ra~X)Ѩ]ԡ^&^δGY(r b_W|&SeZ\1D<aa37t{CMHA;P>˻mYOuSVXΥlšTa}߭H[|YB 0|_AͻE:`;0ָ2Ԁ>9/ ZCP-^p!-iDT;^|ۆ|NEtt.'EPl V22ͱo(EC1?' 䃭/9fl`ws~v}N R467H7 |0e ;~fϞ0(.7 ]M) z|5 0d86I⤸" oAdxQ6b -հ AXwEzK5a+HN੨)Щ!UqV|h=T8ޙRVbIOY6~/鴀iyi}2ש #1de9BT0vҽXCHs4ίS>tHTcK<~}@AupQs̝Aqtn/g͉ClU7AnNå1KИ^@v-m S'xMizA!o,rCnpbEa:<T*5ED>'n*uJu[ojs: ņMT#k0߆ ,\z6;xVYIɌ@8' mjʄq -GkƉh׺쑻U0] rB/_\:&9ӯ౺g̫g>ᬿ1r)ceƳȉ{{Y+ x&vx҃$π*UͰA,*[s|v⪤W*n'9egp=`oRUZ @U~\ j\Y> HcᲦ1cGG+M-NZ~WlPP05\U= ieSQ3Vד8s D>1\S0Is4#nzgZ £yc,ncA%_Wإ4XtP,h6t&n6SϪUG=\gxyQ \G7)qU5:v2t%D>LxT sC1 \gIdZfIYXQI?m4QmBmrߚR$seI*7=;\~M(7L{cwN-Ҩt$ԠXbVJ14E ; Z 0e"|sQ~;PA%LQ'@x>s[r[eڇ?M~QO؀БR\ONAqC $2QzӸf!k__-ߎ8+4Op_w/~K6̩(x tzA[1ĊAټ]S(,|gx46gIi}n|"nQ[D4ճ9z!{K+Q 'xқַ5ѿdbͅ8eMNxW2̅>:E:1Rp;uZL6r&h?g ØMUZTA[Zj273Sm֠ \B:hTEzDM P~fMDS OuakL ᒖR;RJ+>q=.,yl(k.i~_qDا]9R3=LI=,&Neu#Ojz Q[wUR,A)Il/-U.eA /Ir%9zL_%TyVZrnBwgiش5]ƛʺ E`IňN]/C\>gBYQ(\`[h˧ipczH &L{_f+Wٴ W:dN][OD!N IIu+jI;_3M:|$ o/԰)Da3Wβ"Yř\i:_ӄ/^i&) n}u 6dNQ^YImJ7*s,g>5R\$;XNuK@VavHu}m aQa V&pI[ҪK#}2XzW6o(Tgk`ֱ'$=.Eize율ގrJwڿN.x:lA mp@ZOb bΓ)SAfügDt`;a &6Xx.yQRQN~& meT*^䟕k'z2J}.q8ah%bF6|(a*ڿ~y!HCGP*DvRe!(剴26W 6H7]=]TL.qr08M%0"pc'”Do#1Fؙc0OmӔa-mkV@@Ѷ柧8`_3g$1$4 }ck$Ȫ"G ,/Im ֻ0Ao)ZZNs55)m*<ɯ@^^*T1Gv,[Iտe5^AO+A`Ȓ[k))60K4/6ІEaI]јqa.jOKYmpt.lOr[D (8pv)()TA]cGLejHۨo<\$ωe%ߞw@lW ;-C-M{{tǂ—XW0C}4zq>llILY\ [|ti[ޚOi%r$g2|8^xa1GIhc@93 y(Ex+V`n,Ō6U_b 7n| ~[D qjG Yr`e1P {05O)/iPIҒ C9 h]Fց"%дcDf?jw0]^}rVȶ'%=-KJ&--DKKG?$&v&#әQi =j&-S3o_:)L!m~ ^Gh&7L!ęX/tO/2FyHllZCu|2PGN\L /5I|Tt(_?>|@:6 Pjc@|c-Zf+xBK\!F q lUD 2NV_|2/gg6R͑28T^T7E[$t< 'kh'qIYrfO.B r\cQktV ` ߜi%зQ]/!t/4.-~d:7Sn3|zB)v:>trm_?wE7_Z7 "î~kOOb6ֱ5ؘdA(#Aᄗ\23&ҪKVFR@ÿ6"܉;WK f"i;x7i )GmT58R5< yq >#t"FSWYPba8NVan (5b 7my&o:<!rfӎ2;y!qq Ma45lu,A2"0guEzh Jzǫ~?؈V A>Di]?L~"q{>ֳWf[ }`Tpe,;&.&?1SXA-!l^ &?ٽ{@4ꡃ NLj:SSLlU}FuʄvS>魡$wuCBkO# ڐzkq/ wUo&h_zAwxb)*=6 a>Ø)75{ l_B^_"&HbZޞ`#[ DRƍO-Y]`*ʝ/RM6N)l[Xz⹐ [y`7-r;=kHY3(px۞%Q;1/^H/!R@h ,pCuWy dKeHN/t [lƙ kI|!h쓱eD3,SsG2P Tw)n.Y6+D+,DšyhsB ~TA+..>[)R>.?b}}?ݱn\. $YZ77%,nkGO']5b ̒Cţ0&O2?چo-o7S h!$dLG .Ȼ;7Gs) *8eP('x#AYvΤ{:r ]/#V$ݙs)-vz ]G%q:J2i# Qcx}M+ hϤTA ENrO ew N\j6rF-Í?`fzݴ]r!ϪY@nV_GK'y+Bݚ3 +d+J7&Xy[fp8V'ڵMy4n~BSߛ*!M 7h"(YtдZd&"񗈹HNtCaoe%|@8(0Bu#h/ @OPGvOط=yW`8Gʣo6輪um(!#= 4}ʃlNkqPӡ"KQ+\ [2`??2ޒ0ݮ:iנ!y["PUv#*:svU ? ش?&aC`$ˣ"Ha*[HGdF%w qdj),TW6(H5.9pѐTqaH# [x&XnKO$uጵ!|2ҡ $I|dSv߹mm.t]}\O;\=8 @ּ`04LU7ߝn4|mk+1b]/SoYB 4L$TJW]#r9d.ù{XcpO~\Vg$vSnԠMc=_6KFe-M+L,?;#=:NmDRL[epqd _|N<7~oOK;GO hKQ\Lqc3"vl% ޯ1'g"i8 0# )gwAɿPڹRmvwg#$%`#CT0 y$Ua@ ªtx54w[9̢m;Rxa<[H^=h)QcA~V估 Q\]&.h?B6Z-ekqf WǤjl2 |(H0"nUSxd &<.|h7AT{?{=1z?j(AӨG<-Zu92Ld֪?J+FNӉ5ҥ,|XΗ#|Db+q5p漝_r.+N̓kW0^jW!_@6&&(73lZA0mMesNޫR%҂QT?!!-ﰾglq#tl"qJh^Љ6|g%ѕ%%{Q9YAlϊ+;x>"j2آcA+un6='&ۛtgdo*gi85wOm%G75M扊a+vi"h1E4SS7J;'(5Ǿ9umb_T+vuYWFlE*q@^88TSkp ܩhNYmbi*a:G^(+CT_` AiUMSrɯܟ7- V^-54!N`x՛hdn[z9ovͧ=^tHbP/PvA0oitΏXC+{gZX 8vЙ<' i?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPʞIJN:,8pwi cc6otmAE*cXϲ!KK O-f`^VС.H3=ƚ$,"_ J,Tύtx0BPTf T_|m{ S nc7EJ_;C,ܐ-2_6v'ױ:Q?JS?ɔ爒pL (Uv jFDqP;SsB:#WAqoik#iqpmFI?}1#:/ ILDFu2"eŜf@ӳVe0&niNXNԍČ㡦. F⎷5 4J ' @}FۊXA>qm?z*N|'0vdUN3|72(s8%.fjQ ށa[l`f_/oۮG/x~ J/3wS /d/r'&(d+D:Q2Hr6fՅǃըb1Od'Z*VNQMIbq@-i "=0,̦{,xGd ]\Ws*UxXlF[r^%'ۂ'@BԢ}@i$ˋ;19r_-kM&2Ol rMmd$wLM}:ՏnP4\5;P1v32;ba M{M0,Oh7m #ŴAs4GI FD[󖬞Z#yA+5 0u!h;ܶT*4wt$;~~1vR}ͦ,c!y5MuHMRr v`v6Z_c&b!+<]yJP=x:rT8ax.gn_$C$?0E^jt'*wgB-%'~dxMEӮq:Ksfd4IU' @CjJ4,[Wjbς81P{!5 }P ʾ@:H@qE+|I\A (R F "T頜r!a|{!}H2]Ɓ{ޒ>y /tU2R*Y ISMjc:I%}> eWNGdvI&H RR.vET/Zx˴O1 oKjM :^Xudg|U6Ƽ !1; NegF kC4 X%k&m[ ,BÇ?_ ~:E?j\Qc>%aERWVO3k' 㥣wLm?xp$%x{hqa>/UL.u3Ma'e}oyN|T][ O*{fNhf#ɾy('y.$338Klfϔ YIضC5"b2c oZaǹUK(T y:3XFZyW6hBn|4:"8$,{Oi Z6v?V~;F؉q!.i@1 rD7n/|/njmu_Yn)i9vw:4BC%ZqȺF .o', ۑmm #trtN.-1I4 03aU07ztբ'm:L'),jaa+헍~i }%XNx(p?+jr2xCp|fSLiÑ֨AN+ )It##-V,]ȑytpx*# ivҋв&d`C*._XIPJQ3QrQ Łp+,+; V^!7@H Sxͻ=iSOLJ<\3DEW `TVrue$D0ʰv"iZ0 ]C*?.SR$* k&.o=fXfsܳ#4԰hrz=I ]W8Ѭr X-m&p߼ʰJs;ooYC)izzf{ V°?h 7nL=gczd+KY@Y;TĝRjNd \1'+S5/2˸Rn"ӐEZ {`aT[oy5]u>/xG]DNቊҧVq00WSC%vE0_>I=?%{iRY>I?.h8MVL_gzK~ҵ0_oAJ VBq3Kɝ[15aI:q[R\yFR>>3ZmYf`_,;RD9m^T`ײe4-4ÏR#\oel8ÆtyФO^WQҡaD3kx~{@;l yn}-U&TwC5.~R TFOyOz&ݣnUˬE}eO-]bZ"$w*sQwK,L&#W[ ݜʤJ6gŒZiEW pa1JPc#B^ ILM4ĥ+ 7، ܻޱk.B{|eE rc3k$58_оU(Uqa1 RGECr=E&pctR*U,j|PgM+Pt.Yٓ0Nb!J"+.O8ݚֹ0uNl0<}1BAHw,jlkɢRg'8#>N>X&tMNHx%=|4Z]o#D@7o|?JoF4ߚuuY -艧=+-HO:mݟޫvʇ2G*li%AWUA8RU"3ff%f%{->ǪWikHnʲ@Ftf>Z֐p+TσWH:L@ yE?+'21v7O)ygxi.H?svM@ 4ը>TZj;6q8 &c[7&&/ӋjJ zOQg2+͗ .]&7z$va cXJp6xqp;,NkH3huUup5/{a.& m`tsI̻zmn6wltB8?;_>NH3jb;><'W lfH&l2[_@E+ π cŭZ& ݂!~8KڻeEPA3EQܬ=wϒ[K(K/Z~X#N"58x<gǒtX(pwnObmސ2B)>߂˷/6bO[r7:[ ^y4b_wy&ɋ7aNMG=~ΉEScl/ pL@ Zp(dv;V7xJ^hudEK.n̡cr]߆8K;+q**d2$A&H\3lr,-[fmy~) DRg j1&lƪ=5J~ t;E.3B=x⻪FXZĔ~œd-<`v/w1|QtBhDTC~/SyU%/|@|@|c)8(Yc"6 |j# \ uddі./&h-bsgCZ~]ĕ$P} <i3#P~hdGbCd`NJDa/Xrc>=@T! 4KFS^׸ 7[ϱ(UB2_x":]qWQ #W'3>ˆzo9gG"WߛP>~Yc0 V 1x 1O{KJ`Xt͋H Kzڬ4y}o '' ?'}RfLWoэppv%P_I8lJo0%vO g"?\ 2=UkPhCl4>]MS7?qQLϬ(fOx50LmGZ ssTMRx&fh-1mxΦ;5d+S>bGW=)s="Q\[Rb]O|*,UaDU,.ik3ӎ # W|W{t5w?GOɪ<[R5 ȊpD`c"؄h;-D]YЁt^EB.P0t$R]+ Y $? SN4EwZX]sb?ePwo* |qRi)_PM<>:Aqk@2C|c'ys.h71L)dLX^QHMŽ׼̫~`*>Ag.[)>ڰ̐ G(PR& Y8yV,!9 Jc+HiyĎ ?{pRlGC(\kH;/q?-=V]R4cwe)/qCԜ<J1K?&{ڄ5\JQa" iͣLZ ph~Y4w[DpITY܌Ȯ\~i&' _oMŖ{{q 5x\!P2q*lAsY"fo"'F3C/IC݋ ;K0 Ppu DB=>$6k$%Nê QlyQ_n hI ̀©,V"ZH fdT.&03\Y?Z_yzvF7YVU7 ܤ}?H#[fH0ݨd5cD "O#ѩIML*DN_ Ӏ^ta=͐qWuLM2y%8*j+uu:,|nO NbAtEO? ?pI?v)]:7 o!{.h*jsϖV/ 燶Q+ G3ΟatbYKFE/uc3إjFAG)i>x#y/xFO M$qR ~}]}mHCB7"ʛ6!CZn)0+TaB9"7\=t N OB{oьst%oY9RkC=W~yL8E\?ԄMsOpfvh8T2m>mo.+EVQ"wy緩#fƪ|T/259 Z)[!kp $f2dz< e(#ֹyqc}+!4ދTY]Fb'R9J*+!|) sha``339ZxpF܈e)ddrJq j%M\[mpۋX]#Caf׫+؁P1jbIL-O |cn#JTQuYJN}=<0 Jm13anܖUal@ 8ٳw]V``jnl| PAӌxq6*ed0ϑ2Gwl % +Ȅ]Om~) M`oL3KGZ입v>\:a5(͙), hzESd#KUj++VF9j0 rCpY>^0WWg:XKV$03:IPKj$7S0!)rIQf,[q"JD(ʗ?tTP)"Nr>K2,J|c׭KM{} K N "4}"e q<O៍:^IcbW0c)/D)+)GsfYK%^牾YG{@S*pu1@Wk*{D "xr?#I"kƯJ8Ybnf!m|%7. XYG)vz]},jm*XL! ыW]g@$zi`4,U t˷׀X ˾39j`U8ݱ˙r{/g1 -E`/:6n;e!(7wgV B`_~"th=w/C; 1WF0=<يԝ=+Xxgf'Ѻ\$"dyߦ?MD*KV0uc֊JD[0&_:`+KZ=\ MKImC7e) 176r ]z[X͂Z~sӬ%Rf֡_\9x@*`iy+9S7`0г||3_ʌcְFj j2@*,δ- ?@@-cnqAڿNdS^q8cs~6ԕ/Kh?".XZ+E|ÌoyEl,.PqJ vG* Y Ŷ!F: V]!`%FĬ>lZ}yb-M"A8-{|ߥ\鉣I2}$إ&]G< U!j1 Ïռձj⍞,􅇿3#45[ -I|lq=8_(Kފ9\U>\?PCteǙ`WK\j'ʸZg LA}[?iҭ/)FE;O=I9da,WK߃B&d%gNhqWe_5`SXXf2RllmmwELʅiXR ߝܔ^Z${υuvesm%&(S{/!Pw'M]xg PF-dp>ѰĎD9g+ N %|ӫc* aԋ n!XMX;*6l&I꒝Ī⤰-,5=;@?&U3$V:ɖϔ ^>@ !_}?84v Jp CrMN5/ QEqT 2lAqSvOT{An)Mjߘm O>ği"_3"ɔ5,(fy_yZ%ʨ*~C,cGsF|i"ƍ i:q u Ra-nI?tC2Uv^VWK<" p)` n0W*2es[}JU߸ܻCGӨ=ѕ1VAQ*nwW&ٿ?e0v(7Y{$}=[@i%^Sz^n Jm/p-0,a PVB+E;egU%K'ha:#\{?t0w5*̻~U[瓉s^EW Ln:R;H극sʰ}^ס|$޵B%,r/<;فrotwC3T+_!6\Q1%v NCp+%óe-Au9#w%Ҫ(#uUL*#xy>4}&Yۀ8z=,j՜B/^(*?lD+y-˥ݘtym⚉V5&QbMFQ}^"D]oM-%][he"Oo*ย,^0瀦IT5 )cx6QU F PXQAlp'.r~;斁?z: Lݓ'vQm_'Mc '1lpGۮu¶%F3o-tSVLBܑ._fhZ`۟ShN1C#.ʂ^gU`PiV l r6K<T3(_㼘)MdV޳[w\Udqc玗Ba:ˬcjO }⿆do—=py7Lz &)$Z/)N4I2Q=#)G;0v+|@/ Tp)^ߩ>,ϪiסJIEm8t\\#Qz`cMp= R &*;jqBͪ.=>o]tR~NXHbZ%zTP3h[\}tvj՚oIRqs5TZN4:yHTC\F;}VYmY0P1S0ЅMHgOS" N[3 MYM}IxƒMy B·r.xMoXQw KkϾOՓu/eHg/"yՎTi?"V\¯UQd Se.D(: B[zdsuGnF) >I֑XK(=bVDG,ŝ36U[Δ#7uKm{a؎?R _P舆bF,T̗Ȇd Uz̴?^*%-QY`9KUS"_@j;;%.,נ}B#,' G+o -gjW촴8ユU;qY4Aj X7\KSLSO]ugo0 .#"O0fq6v07.LѿE]?y ) nFy._שuDwWX]0Pgp6KPT)JlӲ? vnJ2ufUw,!<1d=0Oܿ`=I X4x*hZ% r^R Zi2uGIߌ6q;(1JTO0mp?-0^I*O{F~ʳdIEЁXk~, H[G!GShVx3ųNj ,-\$GՇ c0r)g#}&pMZ;%я ͬM,RC^cjQҩpNŔ'[EvQSN:BYEws0Hk.J5ՁQOH$AҠ0 zcۘdZ{^r晃{7 QBOĿ_*֯ULwDfO֥Rɢ9 Np谦85,zT ,Ţ50l/@ِ z1?;<iZFǯ LdxY d·u=1Tck%i'KW.Q&Mv?wݣ?J@m+LDs{ubW*:ٽ {AlQ`"|,ت4Z  xn6" o"V0+QP`?n_jSeKHo J-#j `e/K3@IɠHXv4˳ L7bGm-^D-<3xI!8L"[nSmde`9.[D{ nx}ϰqv=e,A3h ` Zl,\bu1j_r^0ۚ9yީ}b@Vm56R?飣 E..+r=]B5ь׮l.Eh-*3G*m[tp D DDz02-?ovԶl)rf\xjY֧s4=`δ}+՝Q^vwZŇ7S@ex``!~O ײfrťxT@{^S9Ve!]=;؀<t EgF>Kǧd'opu+ Z & pÑkb0=$C6 ',ے"%aĩ <դޫ9bfo( aG- -o?E]U?_q{pwe DZ "\#8kGF ]H"AR4tZΗ$Zș=uZd2޸֧ `NZ42J%e>/w'}h;.Aɴ܈?J3|i􆋦&Rl z;Z9ݐ.OEbs塦حs ^552OO#٦a%\>9\m6@qQ )i|Mf 3 o+Z l5I@Na8J/Ft#5]#: H%GMxQ0ܥgQ ws$CϺ[vC#*^@2+\%[2f4Z` Ⴣ=)u|nUE-P7ݔĪc1&S! M 8G+;ޘɒIO\gn蒯4rԤjn ~2m5};*#VO-o gaƖ\D- D.*Lv ,8r\Jk:-ԝ,eؿu\b#djɤQǛ\yaC"{{a}D)ۼC:ՖRy>ElW MNģۀ!eP5>݋83w!0/g%αp8;10-SdETd l$hLy+NG/LvC6cJ&ZȰ[3kCMo_wrb U+Ryd P^Wp%} sYâi!X@<ҋx=kmb\q]IgMzf+?Fh{2qM_njM z%Ԉ&TI-XfbU-8yJF,Uu EԪn!3Ks0H6|f;(L9o5yzN~fP Xa͚!# I.XG]r.8K_L,}7>^fŸHX#2WIwYէ/ W^:++^Ccw"AѴ maGAM'F^PGu]:d"4y_#Br1"()E_%Io#JJF|GWBXeǺe^#l f6>7TA%\i3g f3DX"Cy'm#[! 7?D#)`xh'^jT'=$CM=Ƭ]te1crW-go;MxG350<Dq0`wc@μNo G-gZp!r_y>a-/)Dw 9^@ƁĔ[Pޠywt}ĭq j?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP9 /sĴ$o:<DSUتhJ:¼lIzFe8 !RH[+DYuY!(u=GWyfMZ֓`ML|:ï> ă-VT)ˈ Uf4YaqC7Q6.bl#I|Җ%,`9 yGS؏zrJ$\0wܝw:ȷ|-_Bwv΅l5P10EUL=@i4ATXPB[pũ3>[}fzZ-cCXcLmr νb݅m8~?Oj[RHrgeǛn^ ]7 %NM5G̘O04?Gʡ E=@S l }~ڶY;p]BL-_C)gƒ!˝9ևz h5fRlFHN;9$,)t~~%-[Mx QV'3YxNH:H }%.-3R0 6 ;wV+9誂l˳qBNa}Rdf〕-wm8FQ*hjP%pdõh;) %X+쉷'@:ٶxًV5/-8/?2"OQK F7iMpI>/L5zHWf2c9ղpZ+Y[tJ67ՂZPCPM{P}''Sy6?]5NPZw^"Xȑ« ]qU rO wU2x$ 5 =`sAm_Nr'Ȋ>U0  )5RQoNh,T,T#+PyEw}hجPjqIa1-J -}tٿ˫w}6d's蔦fQ< oP@"^$yKWؔWBz :{1tJHsI"5Tږt#[]ҘD[#ُvK~VgR,8OIX.Y27Ę]v]kNja \8[yo4P+%Żh)d{ohL$bՙRX4U0=c`E_m1b. kܖӳj~5&\'1ZS̳nS$'ꩍ/c#Pޟ?+䚑5Nii::HW*T!c-lm*_Wa|.OF_р% ^ ƕUme4\ lOV6DӘ%tDGjǡIZSsPQHU?>Dik, ߷Ã;#3E.1}ur+-U%l(u>W>La՛2729eT/<5_Zv@vZFN)+5?h< 8;To>%d`N +x.-^CQk[jWbJR}@ȳق=Dh'+|ĿH>!<ʯEi.T4Ŏn3oaxpi!ݗy`(L߉?r̢x1ҚG > G>K@#:O8|Y6b-xޕAV&+l^8kݸCx< 84KmnD"b؄h )q;3Y2yʓUV G!M4zғYTkkM##4D1ڷc(@ rc^k)>U'/g ئ(mlɿW&\vMoƿn%C/}>AּR^^<߁wFݍ[nPwD'!C?q|LQ7kwT! 1e Rc^VȠ ļ/VB>M*>:_Qnئd]|v@ܲrfzh%%[e,S hQ0?w8heH.MUU_ m;Z>q&Vg@}::D<s @s( rZ8väP[b =]wKg=2ÏATʙ~ \$e_r H KnuƣwOwWhR|_,5TXi 1?!( $ۂ$As/[b$\!Z<}g{5*Z %UQtmC|Λ T?h"$)CbJDTwbS:!+c&V<ڲNne&qx`mۣl.l~j:_Us8Be.wųYA _ T.oa=WN9fljDp$HdE Hq" U5!SX#y&Ů*f'ؗA;'3$T7bBߣgեI3im6qĩHd<_uͅ?4/~ƚg> ߹ٲj22aܞ{UyGNm+P'MDuiДU8UTi(k7,yvl.E]g k`A( .t!ĸD~|׀Q©m{i¿tBu/ 151 $Ni:M*薈_|B쯟wWG 3͜~@ҷM/Kt'5ܣmP>lt*᧸)֦3م) 2Ze:XCJ/  /%|+!Ʊg A:?R[Ǟ6_h{w@a~Ce_SWuW7AQP!@pΔ2R1Jk+L+aƯֽrд@ ǣ%kˠl4zЗ!1; tĵʷGn,oNsF1&WТfbREI{ @C%-$=P3=%`]g5pC9pC# Urþ^&SFL8BoDr n< `K<۹ةRkA ƌ`E6\u{h̫J#Afm /4G +8&V(S I`4[Ĉ ^^Ҽ Nz٭jW%\@Z$5o:Ib=> ժe i" u?]\ ʟ_KQ'6Qz3ǵ _.uIcDtP-`1# 2~AEFcdn FF(x?}~xZ `%Gh8=XIq,Fr3~_eYx>W(o/`r6c.+CTG^xOQ;+E߻Zb ;ŠweNJppk oyA5@e `Hmy_I:]E#nz5Z9=eu9rEWe.)2UGWY/x!$Sۚ4\3^8746O<VfP'fSx?IY@_CuƶvwA.!oJĬpu6bR+'h3 "-3iaRrpWBIP9L`lkėS OiZ ˎ"n8?.}k&aӥbard "#thGm#)Vӱ1^e|̝ͤ{TnJwOhhZM1T Ccwo/bb{޼nq9g>T2V5]nrhu);;< 17PR3 ~6`+ty?S_f i@:C9Uzۥ&]_W{8hM43y ]; &n pQlߺ$%Yr2 2J/XR;V|G@|z+LFw+튿R؂RnQKIO㑠0o\Cx{ɛ)p$'}Td0 ,O$%Y#k6kk#=Y!l;7$'m1yb8k//KJ(Cj^FkTMf94n6Ó``Ƙ-XVx"8ձ'h468ֿIm7K3nBg9i4*6>:b_\߮0r2 Gφqe-V% Շ֝iB,a Ѥ 7}"F%ki@}^y-™&4=\TWZ{$?#i6M.C_ F!v) {YagʎsyT,,ݢn~RE`g؉B`ҷ.w<몾;d]D2RDChzvFס4HI}$9Ȥq4+9ёsN$YC//`My擜'˟u;X{fQ -7AٰxN}@zG<x2AGV@>: /Xĉ#դFD?L\+&788~}?.7>+A0Y0GKx7xI{] >W7i;U}/%U22eQ{Re0Xh,݃\0}N+j67z;w=ez*EidǶ)٩ lV~F'on_G/M0^%鹬] C-F;ՀDCk۶.0=%2oC;e o2XhXG.PiQo" SlVb:w{Q -[GLȆS7ϡޡU勲LʏB8Gܝ\|bmW>G;9nShb1)E|d.Y~y7c'NwTK{VPv2,wѶ;5gU1(LߋloĈrj@!5KSzX柁j/!sLnN7OBx]ER}Aa z=4\TE/7di_k.n]Ma2Ƹ\pp+ \U*R!D@2J7ʧ@ѩ2ֽUkN7if1h$XfHS%#x~P吭\EfcR׼5"}O%4_d|wکsZG{U.zV# 1ZiJuc Sx:BjR/bZOZ|~.u@O/q.'wxã~3+?5f̰gUr,oToP9=u#N[O'i@G29Yi_ : bv_D7S: ϗz>,?Zt,+]g+woui;.siy\2&|Fĉ1@0t!D"k !0ʰn[OT@3 msbIbZUw72{]D$[CW $>xFǎeX07Ktv]T^yL]\tOB|*A?g"V3թ⮙pBͮi]R<f^Y/0!Ǻ'76~:u Bq #R*.8Hǔ&4'ıU{$T0ūӒ2#Qډt &qv~zm~] TUM59zF*\#USplau8 I7?d"Te@سtL /?CܚR\n҂- );JIS~gHQ2rOe)^ yT.I͢z$+BE~_ X @Pfbp*Zh~gsVގ_O%d혖pr9Pm)d+XO hX_)Jbr& D|qԞ0?wy.h0\Սxo_n[Xd'Qu/D L`uW̗|\G}3eG۫+ ޠbkbP1v 8 C7^l)pjtL'V^Q>Q/\8MoXпi:P-&o eƽpȬ|`ͨTWI:hAVw ԻVҜN+imK&VKzK(NSt:_ wRL[fDrO)|6],tǎKE(HZ9\'8cyH yF<3u/ ĺOG.M඾2EH"+K34BȄpD۰_'uhJŅkqfkv$,ݹTDHu|EEK4eIt({I^*tQ 碔S/5ɐ\P }PDAǟ檱˴M?Y0qeѰIB:8}9}E ]AFܨst*z2B4+ De7as2IA+JS"$+YG ?u cB&@řkA2ęKؒGFA̓kJeG8O3a D0̮~@{i6 9Wsniҏ&F̽Z^77TȚ:jl7T0~NecO1l\/',VC=^UQoo &mwX ͐rћPj+cFeAޗ3l5oȱ7"ZlP8Z২_(Iyr9 `VMJ~]|lXj/gnAo֌{kqcН?rIEpsAu#O@Qm+à*忺/bH4RXV]9^#ЗwD?t\K8(#.>V}"Ej?b" ޲^Fk*6͡Tma{4L { [kl~i* ż*^r u+<(6CrK*y6+Ϙ$#ޅתls ;'[oJKm{Q֯FClI뎒,`) ϳ!ڎi {x`S#<U&G˦EqiF!g}@&0ִu5@g5SsI,*̱WF m]Ӕ|f+ .}k(÷S* x.rGCԜ m6Άd%Nfmh2UP葯|㟂< 0j:PNIGGU"`H.FzqbzdVJjD!42D9#id2}C8bRWE3G)dvEyG}g \cŽj%I@aBؼ>dtL,L:mJuƹ;Y ۪CsN%瓙~C*bQhj63խ2!2ɞUնU:?v=If£a?1-z:J{qR':RJF+ 5wQy*[B`˛3/;D}/'u{Tu}($Eer@n`Z"o῰R{v&҄&.ϚU)kߊ#c<6] U9P]mK5/|&%dpiR!GbIPQ -k|@|#>@OS#x=u_bG;||jM3J=8}%ŦI7%GeT, A:~QgJqw#!lgYXBZ{lh ߩ$ BzCF>=h``J[Bt~oމq~7`#U۸gL`sCMZ\VK d#Yv+AۈBLaU;dXA)5NoB_9˖d ? l]&bkr+>I֞K@&w3}MBA6mp$U\sA*naPnnV!҅q}ߐD#ܕp"Ǔ+TsIDC&E%Uw_5׮\E]tXD)&خJU;OΣv Scf ؈0JKoN]G#U(}c}ZMKxQ j?C$aglnM{887N2Cڂ(٨wԸ@ztLz!gɼM/5܂g/*bb ="`߸Z+^9@GJ}u~q&:e]E@H]BJxV:Hǀ(ѲZ|Dt)_ Hkȇ-p |wB N->i9"ijR \t_8bjVPa?[g; cSЉ4ᥴxnI[6!.,U?>*@1˝ J Fh>,G* (cJflĬxD {Djn*/8sBg{6PO vG"/ GBD7VH3‰46nKpN(٣ij Hsmsqcx5e}y44xQ1ATw0ɼ`WɌDۓԽ;W;Mfv Jh|^Zep(╭Dpl34?J8ߒ%F9FݴW%H~rWmX5/Rݓ5\ B2K \Zw]s =Iuwa"c&|Hef,?51v5Yhc#`E\)^jx $w\L9Wa4ۙr}-qVzA0ͼ~mZNcG{`<p.8A`YfBUE3ńd%^aEg9eƴ_Pr꪿BCo;fgkO `3Ey}`a3?bvm^~u-{YpA\q6]"K4*c]ւTxysPD$/8pЛsxhXD]3Z> 0U}x,}D0ReZFKo-ב#KssMc%a -ɤOzE8nEƂ!C(Gu+:n~ӷp1"'{ҐZwd|C֣v:5XcO)dL=>A>wFU Iš~*fyxogX(ӓLji k1p6A1~-CrӢ}%b c%l9:P4 j$rn/dU.70@y& ȋXs';ѣItj< 0oy{rBb49&\N3؝.%xp^&xBU S<X mD v o%& cE :8vJ̦H/ w]%+*wŢXE>n3FI6hz~t7M ~>S<:7rF .d>'䬷8.!NaEp tfj]?Q/̏ykz D{5o[X͑d3U쇠ogZX'uǃ3P2*̈1/MR_$Pûr`zN=F :rK蠠$E쫠fqHF13{vڒֿ 3ɚv >I{RtJ#rlZ@g T&˴d6`e &0; <-QDD$YYJxg`ÊԮcQFf+j!N < k=Gr#E>"(_ja_q߮ڜdNJYH@h\1HT@fd*T[KF8Ώrx.x8cF.ֽ)y_/'<̉Hɶ̃:DuXz)Klkc [戹E'ShV,s3bd8<S-iK,b= 򰞴ʵ̬J]ӌfd, {pPK|6VqjF%jTF j% Z`*-"d#q`esRTuw)T&ND+8Y/cnJKB虓i'ぷ[l`{ Rv{;uj1_zFjsY)kXx ڗ(IZ۷C|IR2)@RTnֱ %$=&b$zT_¿_4Ya+d1wu :+܁]%EdCKzsB,(t!/ Z5% X<8yQt%V i&"]R#t._~QT%k\qR{|\)mZ G#Lkzj ZVuH1W!h kR[A|Mk3[OҐ?0Hۘjr|G)7'T&hJ{Zu]z 첾Hh-,݁)(tP~ Dr}R\OI#|a/ch SQ?˙;INd`HT=0V.<9=5 vZ{](i ^v|P՗L3Ze*4x:nA v5{QoT?iak+tX6wkSiVnf>C%$+ἹE(bֶ'T3ذ2h-=(.7TeXĝ/q1`H Ec:. K|_rӳvJ?._en|I@{ ETq U_T]&K>k'9Y&:Y'JŴzeRU'tYcRP`E:,P)¢ k@ S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4×h~:,4}4: r?#:Sw8=NPz @9H= (B5Kȓp݅Aʺ'%|;ï|wWUDUfLJ&~7v@ýL &|#r#R:\ ʏ A|'9ɤyPW1V,`BU,&aWH2dZ25ԭ(o,똼TlůNy]0Z[b| KzyófKniQ/T7K-2_1uu`|ce }ɼ7b&7$3@evŖ]j%& ~} Y7|726HUlj;Y{QUax(=)+ާHlc٪sA{[2HzjP_+c'rٟmؘ9/x^SlD3bJl2u@*%CU.Lq7 !#.QQ,| O'rg g-{ߵqeqdg͙%{R/M~fVn|R DAI޶9xkuz+2lH&s@vz?P /{*ETU_aG0̓ufŽB[yР>QV-#Lrv}#` z# ?Jf.NYw8MuO Ljk0>졙ްYFWp^^))kFwY2)FQߟ gRMoOCsy} Dw5>--F̢ciz닉IY;l\*'6A.gQppyqdV-%kg2k-CdĦU˃\u1%߰"`FjL7}<#VLeL'4F嬀n*!v eLdG-ax (к!hIod*PBa2X/B&SD sy {RA{2C6#E"RN k,w`/+ι'Ҥ .53eU~7ģ"-RwiH({!$~L;e!:SQ3ba:=H6 ̃r$,!4SrǤ菍oO}-h DFՖaդ _+b4>{0aM̴ u+^_O#s>(Nl=9b_`(5$d*7YI%xGm2Ň8ޓ3tInzdE2ye,bVLC8@ַtGt3zj3_nX7RVgyӡsv?,_q0mrv\ F8k!7t5+ӝBS𽘌7v08SxF~s/@`Fjz0Ӿ XMw.)Dehrs1@ShMP*߬ZD)I)uCv1ZL"+ypΔD=her [_lFyoSWzY3' ixil{QFșĝAi/ }LqI$b,&#e`rU_a IS,(pb&ǥryh=V0J nl׬nphjbCy }I@3Zu.k13G;|[;I"JnOeL° 7ZBMU.M_1ok%*Lۂi77$^dB> V gݛ IRQpZ`4Ǐ;*8lETn jYͪPHڕ!VOyru8#m&^`~BgmWJ3/kΟcEj }7MUh|/s'\LW|re.Eӓ~(?aH2П!gUSfn)"8gxRϙ^NTb/ؖ7rJN̶o ){wG6ZǪtiKǧkz[S=HneB6c#4yX ޗ_MOx ^[ܟP=ft nTnHɋDfQAE,eQic~H!8d95EPi6yH2EƈR\fE !^Hy5JO<܈eg"8K>ZК\Lڝ*:~%i͠43s1Wh;<?Qx'V9͉ z?6.0{Q*\ְ=MJ^Gd#Ծe~NCW{ E]3d쫽7}&ioѰz8zBo~2ْڊ/ZbDO3?BУf -Rl ;Jg^B/BPxT;Nc0 .PP#}ƌ{ Y Y6%jH-wB&ҧGۤNtQS-yJXѳdM;p8QhvHbp*>Ah'mW Hj';a B\Ч9 rtEѸqB#IVNЂCS fqʎ#Gt.&G/RI 7N$=ǀ9hlp._߰f51]'7|l9MPp.̿X2?ہ򞋰@;~#:|c^xNj`[65htO`\ ҟvo sgtLOg~5YP#@a ^Vj C[KZ5le$=2N3LrxVKp}x4揶,p:Oxa-8)Ŋo'[uWhut$A;Z1Hsc!tbàaw9,Oy滽cSo5'1:_Tؗ4)E\\ f*J><MPcPb~8@QǭRq5lѓF}ց0$h K)eRүZKi8wKdg}0 Ԩ)J !mTo'z#"AVk5Kv%>gG\b9YqGk%Q]겜yݠqwy<*bB)tL Kt9)q"5 4N"nLSJ;Z٠"//>cV'[Qd;0~.^n/4xR.x@fX^(zۼ峠P`ホL5Oq%DMų%"ޠc'2ú"z bzrep[DnJǧk5}#Rq iQbUNŞ_ݫ_Psʬr89p܈E'5K+5hLF/4'9 IOJaE  dQ(M [4fu1Gjb]#nYСj?ZOlגĉKQ/S7^0Ԫ z`/NtAJz]tЊ‰q%Z"msbJpJKl)+*ؘ2W 23<amp yzTE4(`H9H)b,A n .ʕj*AXNH(> V2 _HHiGYy2aQq6c ىO 3`#'*7$UI sѶ^M 6 P!m-'JdXx3)) `!r$ 6{kT!@KvEQƄQ]|\31#LnXfO Ӑ$~2\v<A\g)v> #̮ݽӁQ0Hl:A]i͓1@bz er-1DG-^]&nKwi65mnK('<>+,Cj<ӊR.w'SbRe~3xG$R>{t sj1 wߙOYyÉl6倮 x(.tMoΨbȬХڀ7XP&VuD/j;q1ד.SܕOm\قk06-o̅ E` 9+M@g~f0/e~tcc:aXsx x(Qq#p{e?:\#`oSj3_L89tm+ qC_XNQLD'`YE -b%;/H17,)Q.OA7P: 8w̜l_VMiMܭRFPV*4y2dy]F1V$fAˢ`R)*ط fs$f[ n7K(e7Dzg8fGlaYdkCg /nQy|PK [:\ \ݬ$}yɵMOIǝ9eUy;mA`[vZȃ&_F..[_ Ww||@|b$q{Ӑ>ߡ|WEǻ|||i kebw)vIߚ'G:[І D0}r }$h3Z pee'tsfj>Fa5-ekFc*-T>Mѭ]?|;|H@|zQ V_8̕bUә D׎b,~%m(]H:"Fm1rY NO7.T\rRѓB1s<أ/ ưKƟEoMt\<.&z>qS`9= T9c-MIHWM2lm(!FZ->Y i_fb5xYRݢ - -MCt}("~#*EO_Cd)D;X\94W4Fj{>/~UCqv58)͙g[K%hmgXt_9b&,t_MEQ%SWհ z/@?Ԉn0T،' Up,Rk#`_קwqG(2ӈ#'6Gr^ .&XxobK;ؔԭ5U3Y9)T66j=72PAjeM{(}]ǟ[&QjZAsٔaM|@Ey5+9b,Uo#7bO{2^\;ɱu( lpmnJ覵¿zve0+& Dnj"N2 m*y3h,L$??X(T%tAEI~jWTN񟯉!,~#HdDڣY>f.b&/!^&%h*Bk_(wRxu܃Fg=c|# G5g+YRn 95ڒUEp$sd A7qH"_MSaXކ?Hp(@^_yyys% gT*Z |%ڵ}#0*an\;,B6fo=/NܰqEa ,x]Ṥi(/-`<|^{2z[w-٦ |v :R^ nb Q7-βMCCs%==sb2R;D%-uP$3*l8!oiWӐ M|U]=(N/i8j T5a);hVL8Q⋷ *JjSY+:R&OFo|0~tlKf83d+޸ 3( LLwo2wo ]7dY=E1!3]RX 4;{8ѱتwAU}yKuFj|l}9sS\<^5C]g$5瞡mAL L&(5t4eGsW"o2D~<FV$Z{83-h_amlȜfũ}^O. P@Z&{3F'`6PYͩ`@a{U|8jaUYmx_Tvrkҝ7wTSeGy֙+)%$/%ad57"ˡ;Ibb-~/K)i]PNƺh#m2P272׽JfQ& LԯU]ƔO4e-+6-p;Duؾ)d1VbZpÍ̓/9-a, +$fe'۵/A0O)(7 Lh_L<»ѼebDJlآ@nOBZ]!oUXۆYڷ$^qHС|D}S5i(~]:)+veH(PK,dJ eL\ W!OQ'L5B&f[å`$浮pjy%)H|F1-,,g}2H]5G|@z ̀kKqIٸr#Qdw݃BK/ߘ)GӜQ7pHyI\, e9όke#]|dq28l湔?F0V2瞏[;JjUʧlyQ[ %xS˻!$eH->^F 4~`Ĺm{J?Hw y%~CCXI0A +Sn+)VjKT2`C(XLucMUOvZAtY\^c|u"*a[WB_$u4Po&Fs5HW(5ߛyRi?z:i2'I^fzy rDiZC Q !tFI)v|:ʩ SC(/{,MEme>!~^ ┭3KWӓ Tr#?;0rN> l3uoǘW Dv#Ff ]:vvPRԬ|m$3@nw:{75c/7')k!^F~:rh2S؃ ,cUB<M|EMtlXMz 3s0.qahMzy"P`\s5Y^@d?vLآ8&2%EDŊ=ٝÔVsm/UItw?YJg,?a71҃V(GW;r7I?t/5ipO\tzx_L%*@A ~o;CjÔO~@ㄇia^pH\ EHJ䘟GY 4ӱv~8+?%*~8-븰9r"Be`&):-aF\>1N\g%5TBkE$8d?^k.vLr.MH8p6]߀k=FVC":,(| @>?]n}zHTHXjKoV91W~FF`PzsE~{} {Y1U:`fgȍ*9+?e$tc B1]z~MJ3-&BxcW.Y݅,ii}AԵRGYdKȏ{G2l`NxbPN9Q2`k&5?J Uߊ;q q;sg` /lRd#RB8O m̝|ͣDrcy"FN,vl|E|uLsGli+(<8rl;Q$jYe^z#ZLmx߾7,S,y]g[>\ǐ 4fW=a"ZJӋ[۰0 >=<ʭ4[Ʈ*'ZA(BWFp4'بbqa;]bt8Q'd$@ (g9Y|:$PLz}%>ɍ*(vd7|بYu\߮*cai9A>G:Ժ9׎4I2s՚8,:zvk1Ԍ@z%_ D u!Md\Y{ٯ@z,]䒅O>,x Wc*ȹܛـ ]tdEm0? j9Ч# [\ ǣ_Ώ&tBH{#x*zE൹ f-87g%-P6I6+# 7ʐA `iPϞ3,۶e{ '5OF< h*y1¤Γ? 9Թw6p5s6=<E;a+>SXަ{̿Pzs)q y$&&62*mn-%r(AħIC%֣!ο~tq3a3mWo+]pW#"Q7;k·+ nrO{ / -zG' /HR̖? "|F4D@u"l㥮gux 7g'aR%_Z,V*F jym o8j5T"=ˁ`1l^(7j3g߬0ؼϟ=m }q@$l+ My `Vɴ;mOYJM|!r}ck?JyyJRȎ~l"DҾ*=MZ7Vhr*NnϚ2ɏȑ5AnU t~}jNn)1vR>'L X5y U0B}iuZGNwM"HIlP"4V+U\ NVN^e틄e`MHF dտ:7f{{ɐ 5XX68ū!  :Y]( }H)|cUZՆ={&Ol83F /5t$uuB_Mua[g!S!e}ZG-+l+EaJ;3] . DTs?#1wJۧDv3`oiv (=J͵E~aS0wH/ϡɇNleӂۚtU)X>f1c)bzӇ3\PP,pOHuը3' ͗9?JJA/҆f9d'FYaIOKɾ&l@@|jZl,?ih7oa U?;ft HPr=D5'n(eH5Ι8w/lMm/ !9X!VrZ3Vuc9 < "i_->=0q^k_4Akag͂J^,1: yVi"'yfbq pc=8%n9FRLͬ ~mͪLjI??Q,lK-"+kkFͲ ʜ\b/f I9q-aG?+ \d^MVl0ʫXY]+p֭si9n [$f|G8B;; ,hֿt xH[^#G#SlͨD@:cAV"s H/"(it╉N\LV u&*.3$l>aAd%FuǜVy-bDq4kƚ8?>W??k—\)c\F='k@t`Q54E::g#8\¤2ʶJvĈTɖ.( [e?2Ub> 7(]OJ5;oV3y;ӴnCCu͆xWg"X4i3A[R,H*(rcTߎa#~)>U5 M1080/9fs[・ow-:dO"r כ(Q,~943(7hMŨ.YUst.9QکGɜAISMKOk#U?*-a*ax"62pi8[F&ϴ <SOcvc5r/?x7A.5)Q{!K4NZS A$zqCܩ|$=nN)<s|GP.+CžpJ^0>ƙ%d<,}y)_gV(JHKUqxS`=( Y۝d6ߡ$]J "ފ""6Xt7u K]{H=HMccg7&l ͻkGG/D~;O󔇀*L})ʁ5nA{Ve( e3N־) j=kVǽQИtVVBϞpQC.gڇ*f. ܲGx3ܣ :jK"*=f@c LT|Y)rԖc\C aUqLh7,d*s,Ge ǐ?[.+lѰi,q'%"" &iɖE+ӛ,♴,a0T0(om}mQ}g. B\R`/eW?y =<:LX\XDB[J(d' eGx4K:WF +y($3WhG69'8NTX4fa_YPǵ!&'cnqv0c y٣dG'x[]ع,'8x 7,tsQRA%pqd*ȳLGӼΝ%&;beȫS0Ⲕ{kP,\,hf.V>@%ԚτzCu(@4_~4Xv,2jt,f= 2a9B8G"<-&gjˑ.#*S2l~/qp2<_\o`Fޣ Dω>zcnāw7eS9FՒkS c!ı! K%x 2;6-sizќD*=mƌ/@Bx~ui=~ 0}{׬"{CWܖyUҝNs۔:m-8zLS8jCKkK,=a'&>Zč׿vh}0$Yh Yh1h}YV~rG\ģMHȧr. מ{98|fx+XzfM'tou%{8+@c\xȡuZM/6(uhOH~X+l 4dɹ`z$^j@q GLcjj:鐗}j_C( W_M éx%Z,D=-BƉT-H˖wW-M םwkћb_y( T@ge\[)Yg>\v9MFMŜYy6 xa3ZrnE37wGŴ,1u,! rJQt,Fe6wUpt 8NR)=d]H㉲޹rn'z:';Ja$oUvu8(Uo[=΅@nch(q>KT'P3@/}ۦD zY͏;~I2GcE͎n|+$Iӯjv]k$ kҘ1l*]9+ckۃE@,GFDB#! ^Fx٥P/RLgM<=s(Ş-GI }Ŏê%]pig/ԝ]f@<^ekD=E$￙W{4iTfZ])Rs?xTř)wTB(t}![nHj=`жqW\F'En0}5SsDE*:RR{B)G.r a_Qdϫ($=<t.KE&ŲIifyiKanVn\ͮQED#5_.U2CKy*l9${Y3ӁC(H*$0bFʰ̿Ie78tsōyz.!j8ň@Uy 6 Tڶtv,C*TjE/ D aiƲ ȯˎLqTki$S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4ݺQ֝,׎8Xt` ,SH?hE9^Z83{ ' Vf|l q94QŕF Oi8O+E1ԶI%Wޠ#0@(/Gz#S~yL|:|w0&'_uϴնbss,!|u9NL$4r)[LX2]X֪q}:d!U;Yv k X@n#ޥX6aq}9kPeD:j|ޟo;e_5ȟTEE icEmM ik: U"[MP>ƌgv\Q%]9WB8B>N?/kWFXi'ޞA2~^83R"<4j Xm0TD&jЧ^'m#A͈{* ;!d@ƚI/:6,K/@x  } 5 /kGyCEn_ܔe(s,.y/y3 ݃1lLJH!'L˯|Fee=ޔ|rN[</~1U" ډP+%jbQY3ɞ9z>PDp *Łe1#>nBM M~bRuQp=EIՀR;J4lȅ pח@G`9hJ;8ǟbz y\l6Y?rO!HnAq<ڜy`WhwKpm>d;@[,˔j.fx̟KahH :2xMsP\OUH SD?:TC溥)[U=GyA3cBTY47Wtg?zH5)`C `6dZ/m%߯6Rpm 4(č#>8e7BqA #:S?`}ǜf=RF$cT6]qQI6W3kq9 qyu$1o궲 ꬚^pۇdDN8Hr 5BcM?&Uo׽򾽪S/Gx"yTO6Lߧee_<[6VR ~$=قkGF7*j[~u>oP@v9V\TO7/n͞ kdiۙenz<8!B9t/9sy[{|i<&(=TN^,wp6)港3B>ڻʟp`b~Od9Uh]yh C Y=TZBG/Vp}#hVΜcw\d>h2!SϘfޕͣ󹒰66{d_RF f{1@4ِmT0̓0 $}Ebkg>§O 9NKfO#8l_葵wS:Ŵp"ֆ}/gM_df&SQAܪHe;I( 8 3TjE ),~d1M/2)&|zXk!ޤ]:'-IQU!*yBQ{z06o鹥^)Nȯ[L+tw ?\pjd >k_vN k?_`^ tk}Lp 7߆M\M~$j5pq5>sk-- ٸ%g?ٮ&k_ Poےh#ë[&`(0V>JRI/%%H/]ؑLH.rƶP8 d<d3*Ě=W"of6Y\Z~V7@? Kن"lML빨7AL4IQfuI&2A#8)C"vZY.%v*oP|΀Ҟz|3|/O>LI*O H~~'W1`dg=)Yƨl 5_i%*y-m*n1$~}4Te]A6<-.^_Ҭw֎ƗcqO; VFH`-iA2]-˶oݙ$ũ^iYmÓE74ME\e} RJ_/VBw2]}xP0Wܘ˽иC  f4/@/#a o$L[deℙÂǁ%ŐTBvD,dvA/xS6GU?sN*m*ų)B8hhFvG@8t#*)|ݲ> ɱKRFF+@ڕUcGBnfSNoScy V7'Zjg!d^-<?A6zC(iA`UOE~i+uV> =E@0~^[Z44L[˳l}tc̉Dp񑩗~w"-Hm`b.;X;y*vDŢ~sEgiSP p$G$ 7̏ʖDE"\33[pLmqdžAskKZA3>˴nugbtԬ+L)kj?&쒑숄t<< ɁTvP!~C|vM\:/"\zգ !zIw{ Qo^YB3^33~'XVt4얳IP[zBÊBFE.IF {0**~yo"XsP) uNJ35y2ы 71>a7J6>nU8QQwu}x߻2@"uqo^@@iķ=e,pd,$0qdo&B%nMdI<tn%V&/Nc(w7SGkȆ&uD{RskF3 &P?Ow8gt1Rkꂁ։gRG =ީ}+,^/@: sV]遞 P߷`qz 8^ yc6A -7J-'U4lۓ^,a1Ħ- Α(?Y £;4*. d:Xp ]c7B4G20wg硲]_2>aM_ԋ\bȁ>TQS,E.]xkWY#n9J? w,nQ2HP'~^[JE9S=*(+uƹ7x)_ T2O>"h>5iغ@;>I9(l2SYWTWz7y8<plclUX7&匪NbV5Ɓ9@=7h3C7BPG8(t!OK;Ѹt499p~T|n@'E_H!'Kp~#+Plj'=ߟ53wxIte/A:ttdg n)X6>_/ ѺϜLipx{HSHzV"}?18np-`x1;M[-rRHeJQ뽭د8g:3{d '4;:"HڼY*#qCvPEq&ΐ jo'cy)ݫCҷ I1GIz@;d+'Tn[e[9=$P]C&ԗ&~#ao4׎%!gۓ.=MAS[`#B G4׀t ?xȔΨKpTЬ׭Vגl ǣpK>@&s+݉kTRὗ+B(@ѳ#}oqNJ`M:A(Xu-LF.Հki$$ B`9W_5R -cg ]/8q&w~*:Ec sp?&!y<2wL&,_/ Xg;@}?MqJ^N*XL)a k HÖm6`cKjA vFEqINh̾?)z7 / )C<0SJO聒ڲ3T8`Q&~s`êƢoXi .ړ(*[` D' Grzb,~ h$F_.vpt07ǥy~E;0>{K[TEV2u$㸼19ҍJW #2`鈔rCRaYEDd/=:B&)EٻMAj\}I<{9{cxs6;H&MRrUQ9~p,B`y!T v!<33|%RQˮi̋ [3Pd[مg~/O/6܋ K9ŽyGrd+`г6͞rz5sʣ#:Y 8f2Չnj߳8x {3<Z`\:|>4>d;/ueET- q[DecNwUq6* $obД!#Oa kСJ ҟRb4h#d0W|;4E|w7j mځc~I J}=q1gل]5 dmZXtRMy;7}c&.ZS;srCi$mYn`kQ2t{C 1SsMƃaiuX4^?J6j롩tj\H?Wmc;lڐ:8-"@y@jMiRT38{AbB4VحdPĩ4\7Y0;1;h1C2TYTqTzϧ{g%ʇLVgMZ\_DYù2T.9j:-wz0/qsc"YP"4rGA q?C*!PC7 ̾~{X|u#)}viwamhSG7־ߠnM`&R"a^c?洘O(7T[khC GCӱ$e7bzR_P5Ǻ*<030|]u&"X{ B`_ۜWN#zfg#xkclB׷! PE ) ]:e5Ҏ+k?p%G[-4\h#9/XSuɲ9Ȏ,aE<c;'9F8a GD@Ni$"IV" R" DwI\|bTf$k fEa$P눽 &?CBD0+Dj.&WS%3г[z H٦ =√a󡦐KBZi@<`΋. ?| 4K_}' gk0 _Hkgm 1qP,O{sPl>мĢ`u}YE)\lHlI{>*)ڒ?TCfP|yhVu D 9+v )DDM~1J|aQ ,kbs_?AsK#jC"Wb7U@t&4t+ʺ,O$gӣ=7)NO}{lw! }yAQaB"aHg48D3(cCqu%܏hQ 1[>2 ZAZr0CCϑ_`w>ky~ ARE;*OǛ6-OyLVޒe7_"Lwwur*+D80|meG#Y_5&@M1`t Cpߑs7z&QB7*n_w_&%xZpa5fPKSaSˁMJjPTPpFxу@iJ⃼^Ƥ[ӲF[hT^8`B% Y'ʛ-|DJ$i7$}p4<.(Ep4A]e'&zHG__XGjHۙ՟5ukLh0/U\klzu:]wkKjDY"G\owxXRRC>" B濜Ҷ϶ c8s]VWC|"uz̍3H|Ag eη$,8VGt.ZyeM.\;5dz#&򎸑j* =L$fs̜[]jؼitJ,#b|6s}wnޯu3Oxq-I3 rn@MN66MGc*jj^ID%>$ަ7m$1+CuM:^Hk|)azS 6οLHD JH\\Y—݄u}H'C=w9ӜƑ qئ/!O2 Q5mMO j.Xdv6ST;Znq/y_sS""_}In<'lt@'gTbo|,Uc)+ݖA_sy$QJ!P-{,ۖ369ODS< G ?[BnK6vV̳Vwb9D}e&abw[wWêuo%y``[}U)*g Iګ3Cղh|Zh@ {EAoq'Q]100j$V7FP}\,0'2f>-H"! Ө!TTJcRT }bF;,uZEϝG`ɻ {@quV PJ j];:Q^o2#n *4#agҬԝVZCj@?y< 7.MsSC({R#J} VO5HM(^ntP yn"otÜŜ8mߗ֐!K*;_}ezżdyfVW\N:g0r" PCZ=ܥ8̃ՂC\ 3mɄGTy Jĥ[CJG5rߊ_J-:$gd|az>tYdL+t/?H1m%;n8F0䍡 !U ,*TJDN f4|f^^weD 2j&ج =,:@葦7[2gQWJ{KM.Cy\BBI"\}E;wy~'_ڤ-/'0L?Gة?y?CAݼ}u#c.߻WW3WnNz2$JǏǓe'O(tr7eIE#hnJ9}m!3=']Z{ޱE(Qr)}}p7AVimnmZ&nR+\+(/>jFX'Y]e|QVmX7-vOJZ\{#<{ئR{@5ωv;qX8)J5kԐi?rL#4 ǹU5 ƷNʜO2^-)nAĴl6!VI=b|E(WjA):\fO]sMkbڗ}-2Rj;apuҷsGb&esP@sa _8xP{OD7&\]%1?<|@|i̹Zu'K4n2(?yVx(i#Rb)2-mC-xLvfgD#.;DqQNG g|;DE@|wpX"_=8k#2ڄ/D z'Ƥ[a!$~Qڡ:9"9a{}Y9PblkHQP޳MQ[),)juYQ֛ '#~q#ٞpȘYY*nEc 50Ǯ]Q>Č6.CaI@Td+A9s棽ϐm,"MEsWy09 l )LwHCf侀wkfDma{ YnySs,8蔲5w׹J[?lf:I\Q16UzeIr Bbhmu=|,ˡf<|>;U}c e|lYb3y4>%.EjS(n\dIw ,hE˜" `*YjXJ\"l?szv% u8Qsv7ʺŴ#<.;v(uŭ5P /CջMjI^Z R+܊ i}0˔iz?EXA$@,>$T)=%v~ N>5oz(Nv]%}٤:ޗ|i!Xrt_{Jw扦c'KC=-,c(EIraQrB,vRjL|KwȧMƢX5\S>Dk__넠u騤dv $""um;UW1scCz#7G6,+3J"SvIORs?ǽɡMQ^jc56˷Vgԏ;%Ӹ7-3M^u_Qͣvb} l ")YȞIy<+׫ HK4?V))]dY`묛n|p(\h؉m3/xҽu^OɎ:=L oB efNQA}J V+N>|*%26 %8 5. Q%>9\e /gYțqyń( I)^ݓ|^v!FXr*LK&tO0:a=]HQܤ|V׊°~{25 Nsr.B7*̓_\-#. ?x ~꿇.?u`es cz8$ LW_g3!:Z\%`!IeD'Ъ@EN{l~gs-1%@S=]'eOZn Nx:5s.V7/N`JWXu«;Y)=I1A۠Ao~Q;ؚ=<}LG+'b!CfY['τLz ɓЖ:JLV &i Ŗw&Y)AnDV ޘ ֬T }(_H",t"\G!cRb{֧:Jo(CYg@@=o:U8'!ߞeV m M]Aox`!̸_p *ae^d U,E;l K(XsI?wKw BY*~{h)@xaN:}5Er( .XrFzlr/:}6m?a[ZHFeQ@ cykxsTt~rlPTA8(8??/ Sx:rv|]=H<JtFbr?}5l BDYNeB-3K|b|" = GUmx_ʡ4i065'`zriG !&bb;lXO7;]k̗qwI)h|eH5=ٗ絫\+"O:%`R{OaS18qu.ڰҥW-Vt;3{b}B>q@z9Gp:KPhߖ 8ƻ`zFSibnݽArټqqU9’ cx3?}D:v9wHCdCNާG. b[ 4$Gyj,g hei'#LY.v2"=ʫ9I1uQט,|Em Ul#6< 棐㬩|vK@1ԀoQ7 3 SSI .&.ډOC/rk0eAba5y9Ͳ:A` Z ܦ:^O"q@<2׃Q\@WV-,hX.gmPW3ɬ_V(უ5 )Z6D1~"~8FzCO$K ruhJ)-Z>2{̷-+ fPu&J]U#.ݷ$oqR<9p#qz$!9YU3M95nȆijS6[~eGci5H~b>?0HviTbQ;[nu;vi 6I:;5i(<Q_O ,4~~t(MsmpS\{#`fs KP$0Z[`WɃ-(/ol7Ͻ_L l"\|44|6ee'PA*֭̒K[)*;EBAqqÛm3\qs!^BXDUcCb ƌl=-1C9"eix8ߣT.? A,ZlTiRb-YA$0Tk[o_ʿƶg֫)LqMFkP2A"wZ,swl˒Y 27 fhl7L#\Za#?it1?U۳O1my\.j >qa c~wH!-Z9R21yy̗:.粼CF7#P,ϻY/MGdG` g}OĄ\A} @/U QNa3qiPw.Oom||@9e&^?jgY',o!&!l#g~@gz}H~_{.aa*QÝ` $>ظ%+^/@Ĕ+@DDD)jq^8MqB*JbWhTZ>V3C}b?knz=˹zu珀^ViQD|q9!E PXk_30^ 'm;eG0F]\y5fdS!U~;zvj^=%}rEQ-/*/pFg_v+>v%"*3o^KPKB* ARˠ㙿^-a\I|y zPP,d\#'4E !JtV?{= Axɉ,;S8sp~lܚ_̺D@=f(ú@wDvY̡?_)p !!q\ڠ}jڜ|LyO7>8Q:cn#W76s1})Til^Z엓BRzk;iSktW!XC6cy6"k.%lPT l{P7E"ZlT^;XQxzj0#fPf m?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4艓>rN|#>@ y>X!۷|+@:h13z2MQ;x w;cRˆ>!e>, #n,/-C[O (c?= LS`.#kp~X-y8ƴUߥW}8c(D{#i}i`(rU~WJJ'j~!38^<m1iO+$fr? =>e2ekYQמYN4{ kgos3vR fpU%Q}}n?`OEX]G{7vq?Lʝqi0x |)M~ ɫO \u)6yPzj̵ßV%v `Ҕwع,d,T.}'_‡pt+v$/ŴwsO V]gu͖]q5ULz)t@Z m[|&涺4G$l (6pzz p}g]V>RTƱo8`^Md]{ 0>xw̹i!nTȲ3ҕ% {qIӢJ)~a %m#G&z̧h<x$P K6i񘶎NІH'f́ ?%."Sm#*JQ#K!7;ZATcP>&=<ݹj[Жcn_~DiNS^ 4 k eZsb~ލ~?l.}6XM~ɁGol螬 U`À=:I)N_qgȎ?#"nh/ y!hqN?xǘdX-?Qr>,&Stbby!y1 Wp)aEP'Ery"ʏiu/$&!OaRF1R{NbζZW\D *%n#cER%ʻ-|/.}v݈K[‚UM?yJ1Y j`bBw&kGgfg-á~ֿtx6YEbX j0`:~5]+"5E|!$ca$]1dSctl؇Hf}L_[u`$N_Y#;4.ff:%|(al1SwFdm0Aà$Nu9!Տ{~Ȃk˕6aGFTIGت4ROO.m^ , -'.++[2[ތ| 1`R|VaxܔyQ1/&l75ke~-L>TH7":07ՏbT6R}V/_D1$T;TuUXޘō"s43f^ߜJ㖴|I! 6|UZgkp~C2" !Xe4S\w=h8 XbAwqX;3 PafQ&RC.(7XyIF-bO'Q imd;S/ZPe'N#5s1 A)/2Ɏ6?bpsDv@=K-JVDH2FHNmYa=XC0SAFsVN6]_@fL?T=E2;!t>/Eeuza'@AK^J]G2EW^ϋ€j*lcNu>_ 45Fbi ] AnqKO񥇢b Feρr$r\|vrU8?RSg94>igDf $Wn.ˣ;~n#h*8 - p5)zN*=wd.bfݺٿEg cDsw9 HqbNt1杳his-؃;&T)uǷxzt;df2:*+(;Փ&гzV)r_b 1vL!-7,Ad~u5;'^&&6pZBhPI[aͮ"<zpBQX)CuVfav9z=m]>tbpMjH#1a=Sb5rNpn(Fti"3m`F6PȆ,dvDeyq|h\8?]$xIa DfE7z@Bfj#B`JI;a g(H;IJ)hki^c硔"+ys3CF-aI 1&cqF(/40ȳ=9nK4Rϓ<B <R㋓(ν $&;l !=͞N{}S۶hoNoh8:Q1Pf]qybZăs8[q 齙|ѐPhi"K5aEUWp/p>|}  ?K:y][N٣^K15Vݳ-&Bf.j?ݯ/9'G$[7` KOX 8j L$!nֳsj"9nڶR'Ow$Atf~\7Dzrax('"E:ANxK, AqF]8?Ǯ07m`Y+*9zO6-Yΰ\BG+-(؏Q`TQB֭0D'Ԝ :gjY',$@nJXM/':*€(^7P)q@oF3[):t#&dtDKlcdFBf@d͊]]4=pݕ0i>J'ٝvON7"8q)uV$evW"S;}.9s pVϗAi&ق8NmUɓ06-j{ 3 Qn%JG)Q {XEمѼ}-.3{W5eC97ԣ?qbF)bt]%[eK% 6hD/f@Լ'A鍴 #&9EUؗ 7FZ(p$W|+8d졦" Hk"ub1J_I&\M`,Y,^{`>m>3XԴpSqL \H]ոЫHU&%y_lܔ-hTX+>Yߛ%rALh> 5,!1guVJV3)1-K)/Ftĭa!ἡc1`#ZPbOU,`_#̺ʪZXeG]usj{[~ .M?5ϟg\-.C0]}M"Y=fksS2O@%T$)w-EG+u9Mx4jH5*؊O 3QaK2>f-@,_?pp9!02=٪QBt[U1av>d?q*2& 6?g|t_IV՗1487O$ kSi5TwQ;z0'' K=ӝ).VDmN.yS5quZ*sy,fT3q7* G{Yïp>\})N>aJ:L`߅D E}}=W?d^K\rF'V :}SaOW}>QO2<:4TmdS7ܫv ֨=qNlp 8LWWi[vkwI5;GgP\ݖnQhU^"S>(0*v{CPG#t-b.({ڐW:aH1f>ܠ;-={Xjd9H<:L16T[4~iB#QOy-Xb**F|pb'Qz.G/ijz2`IfGnŪꂕޯVhhK[ [Z>0x¼@v8{(nθ7{Z[_fS~TS.<6_}Rq7WH^NDMi x fp@ KTq_|#8hPʢ>үTS`e|@|` 8ׄ;t['b BMn ;AXf&EFb.LҺ):`4a/[s@P+Zɫqdcp{d~Q? hl=WFl\ǟh**T@sxc#U8ޜ;˘-}oE5QgqVYc90#ɩ3{? 7 eKLd?6( ]V-Δ^icЈ;'Fkds@`􀹽oTmq`%Pj92=Mрy-}۰Y >9kW)i {z}5۴_}qM3m .LG)P)Vj+1E< $\w gu^ .Վ?^iG0šwdqy $OY#E.##yfLMOdR`־1@:oSS! JVXVcLZA?  Ov(S< ck;>˳$(WجfLC:.nT/A獬#jxl5e+m瞟"F۹iX{t)݌Ll"Q?k<,"ˍhhKؑj xwSEcIe!tד[sUڎ ʌK<{LeeQm)*D>1E+_l"c~K;RxyaG46Br,c󉛹qL,t2z4l?6P(:! ˖\:LȕHwOfmAZΣvP;^?Hx(.M:&In<'Fh&v7kfǷs7-q{D\"b1td_P{_W5ZbZCxҟ-&v(# ݸyQD1?/bW]KdZ~>`[@G_.7L[Vhyj0AD럙(}`&;l1;_w>=ss k㷭V< <>G(}P<|ʎQmeF9g;r+^)`oY@xԪD+Kna4/ ^ɕC!43Pm)5?,W8XOmEp)@y\ -Gc]=K 8l671Pr)$F?NX 8Lݏ#,@1m\R$~rLF5" o)]z7R . CU~?à~/Gv7 !/} 4aW5 GO0`4H"k0+ bǤcMG/Kg"aF\֛zF{3ީ*Fu 1ÓhzvhZ.~duFLDpI(VBߛn"(~ r^eྴ&>j%<-=ƃl34AT:nM8&&E8 /'$|x4ǑѠt.+׋NFz,bʐh|n𘀻@jl hKǡ#`689dE/Vyԃ'. 'el3i>#zk!;jj&U%gɐs\2m5N)xФI)m=ǑhN Mq{pjp& G/,j,+|٨:%I^{9N0ZKt(WYIqBڵW. ª'bBկ.ͩpkyȫfDbx\z(=d'p[SN-Gk hv~t#5IP -13|ς"nEj(zPWc;R@yW#檄kπ0ۛOk(#(NQP^1k1n?}Σx]&dU^ϰQ]JޫvT G,1fK:5OǴ1(uxo10!_Yb@\bh= Ǻ^тe䩊X+J]yf21XFN@YwM\`^o?Bu _ >|Z^#=S-w:V2p'4a7>a]]3k@yG1%Z r ğFkfw;㭕a՟H=Es+Z2=@c_6c=7U?Bvծ^,d'I+] `IuA 4\Z\$j!}B3%ÕMzJ~uk6+c-V7)t$!9Ns iYaiɹ3ٿVD1janx@[ʹ%#nVMW슢ꌕirj~QZjf LT6BT%zf^<6p;L.5&I5-i xr튈VЄUi(֎6`0ަS<`pX\^<*h+,>QS’L4b=S94ow=N|HIJ8UۋMMWAd]M[g{5/nt;mm,Jdr>]Wě65KqfaY?@*caMApXRgSx2X7+i)f.8{sp5ҏE'=ҥNS.4pl |"L+ %);Ơ2H7c'07"KңՋh˽i<4eӤZeKhR0{{£KPk}Q^(V)N%kiqAVf' Y+LtB5i]$K^g6#B0es!<ժᣏ;9Qڷ5FTRJKs`hYqJM HH܉ M2CHC9:/V'-j (DX~uC]MNMC80c{:OBLG^/rMu7lrHٙ'+Rq(~0DP(Rh@F7A& tP6?jkĔ|SЌcd}~C DO `(QRM`} n>OK(*Nt~OElm!s0}NvReF޵IXyu%G F"bp4jȓQ>S)A7O_£n!Z3߾G4=x#RbHBTmAׯiHN41.~HII'pPKUa~||@|bnFu !nG8z>JI@@|iNkċt7GaaݐȅcNeF*(?GE-\S^?+X\0t:H]%..6slkYyB`X(G۷6Y? _g@?Щ24C`#A;Lň:Κc E븊>'/L:rvI VCE_{Q3ia`FzscO ]1*nivUwk3tW/ZBmCEl'2I\gJrN! XLi\'{q/N{Yb $[uȩ궐@X|D,"<.7$M/}A-5P~ed.]%P"Zl>50`@t1>pc~^_1@0 >~VofV&1ݩ“vN+9_|?'? ?ԼG'W5k^,|u(_fAwCGC(T]=qѧW'o-cth|t@Lq.E 'HaݩY<Ƭ񵥧1 fkysVq( =W3KM^.=d? 9ob n1݃0^9E`mTЊ!4a5X ;H.[x\_8\en*ܭ=)8?)2elȫLuC# 5 ­ވVAz~YDwO*x=/U4gEצs ES}|zdYYG3 C9DJuc,RXEPר&IPNwk)~ibYT&:I{4.v=w ܾbHO/ryt%ifeh{x` n+"O=91Cc' S4u5yv.(']z@`ћss%4]t*LW8?l4f3;')Pƨ$W_5?Wt+ѯ}(0 6i? xvGSˑ$HL MHfՍkd6 KǡM0x Z}܅(έE/0M_ P3J@iEYekg>B|c,I#o 7*?~31 gYĉgFlVVTw"EJTXֻsLrrnn\fp,8rd組wm<̭cfliNϸN6㪤um_$kNыΧ'KrYHg6ƨg g1Im~ ⛲?MH@t>*> bab: .qp61Dy`Of rwNjZ_zHO4Ѧ`X`zdt;._* 3ށfeK3@Sr!J y0SI|ۙ>;P"w;a;"`p|lݤ_ ɵ["z"A}*3|Ħ>;e]&Wyg$&%E~ϛzj¾CFIP?yy*>j)c) rOQ%|Xh!c3j ,*m#2В=pmń?0d!]D:}te>3^r"89ߵā[lblS*%<2pw8A6ֽ߀jTa!ܗ4N@ݭY*M^էHNwwS+s~rgY6~yE@]tA'n}%( 7̬?WR~%Hy=‡01cPR<9M3M4^ ޱk5Lޯ*ƷHu>ID6. x657eXjiKjM灓1|$I~Brk.V 3bq~O9%92Dϭ]I#-=Z@b*XX2Akp91;Ԣ|cM.+o4ҴEW,a1`JOkO;:\L`+[ B4,\1:`A0N'LPWBe\bQX`[2gP^0 *fҁ4~XEy:lxdE9(ۢeVu9CZ;`#"Ƹ(G˪¿u_DR\SExYA˱qk-MC+f/Yg6ǑvH{], Zy 0`62z&sԚUI[05m,Hs:$IJ,ۂd(Mѹa`uUH*{ @yaҕE򺋘GIQ88`KAdI:ݤoN&hUqqNρ?Q2Tۍʵ ^ ӭ_Qd(Ox:j0̫kzPmk5apRf/_LNu^/3€VmY P R ȣH&GoHe=K8ML"f\[|ş s~J ᱷ '<@$.z@~hV_ N7s\WpϷm&I {x}}?dv/7zi{g^|0lw9~N8]J8 d#񌥚Z,o&Dɖ(X`&lNLmg z7٢ n?pS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4LVύr}{j':4 3Ϲ1C*=M:pcaTi"CGBVtTN9Gb',d!z`_MTK%[2o k||wPD|C"8@y9 ϫIxj!qQ1ΰ{BP*𺂨 8WqE4~ȐvAsfsFf"*nZ';37,X މ2 L!mBz5-)N.CM^p9D+Fkٴf2'd]( țbtҋZ3Q8k&9 21^ߎw>$C3lcϭؙoS\=-JՀn݌$J>vuUiǃxJSd' ΫvR|$~CP.r |>@(ʒ'w}))۶s.Wʇ?&hqxS !u1nyfj@  >hQh&d1XP6ZKq@ q%$}9aqޘm!bDdLP/+%4n4S&x^(̀DM8M„UPt:RbKPDž%%$ F4K #&z/F飵1K{Bxoct%0 r͇~T R38g@XPTPλ^my8v\ 0(;p%ZIRB<l dJ_6shleYAF+E ׮ariިjtR}[[O |S |ds;u@w:&4Xq=Ja5>osm ʍ%n.)-5 b]ܡP-sRDr`PtA!r4xc%pH*1Jn%UX%9y3I*77<)ڛ\+M†@Ey,~٘o mI%'uV*Sq Mj~j[9oE$Ox|5I?ȃp*;*[cYW/}8u:dJt_H}0NݼV`"a&cns,:"`3BNlڗk|L"b==j㏉MPDZeIk^!aIrjR !Ga|nk!Q/cnXԒ1Tazd٦L\5VwNGf-tjY[)iz7ghRxD?wlj1ѥe`.8däp"Jy85P9z[K+ Z lT ,# ma.K- Iof;$F&Lg&NuK;WKFyZf*,r.J%" DMB`>)Q;d1y<(SS1"?rg"hK,b隶^32W ~rмSq2wX4IOH/ :d?rR@eDWP5pN^i`BKnctAj蜧!Ӂ Ukk(讅BΛJ43 Szi``,|BeŠx-RNֿZ,'wo&hqP5#T37CpWdxu&4hDv=v+Y*Ay4@Z'v4nO +ep$LYU^X1jX<|bo)߈>u9l2ɉ5XlvELG0݅kd8%ҷ9}dIVwT -Bems K[𮝋`l=_XHnQ!o[liƩT_˚ȓ)^u, F(gMf@ g, yic~.6|!eٙvdU`klK0K~WU Z0)W9eJO|E%:d9;rW;H ~]g Lt g{\ze FyP@AϬYGm5 }$PvWvf p#IcZgU6$E_u|M0 $tiH̗Eeٵ[.4` C]Go<7AʕU>9Yp7`%jRmf l1mkQre!K D@dnuT̟o6p!ʣ27fR<+9JMCwuXxS -,|?^?Y"gkR̓@NP,kmD~;وoH ۥ'W]i^9ۖx]abQ̵uI хyŢ}!+[-{Z+ :s֨w 4,ےB}=ix 'o>x5ue/H]E^mLX`dUUjD tbAWIˆ`@Z.ga&9⊛ Ry > ! vYMk;3TIF@ 1;MO ;׵wI& a^bɼH`9/mP_p? xYG\ܔ'';nEw3;1{qGZWThtC4kg I\3rCQ'6e7 m~7wT̡i<׏cfAV|{GQk ;眖F_s=.2 *ᆄtӼ)/@b/|gsI֎kI]/εȹRRfKNڸ @ @ zo~1ET&$e~~OH`=q[?CJF+)=$MSԡJ9 d&Wt/WJ=Lg!iv B!wM "uo~=lNVu۬FVMqoRKRԃ* 6E÷`,83+/Dn+H VZٲp'2 i_mpv G4׼C'9/5ID:7"oďغnJ +mfՔ{w,;U+f'%Y|d/Gݸ@&jae5t 0ֱVMe5F!;kM0t^ݤMhLԅ>Uʢ -Q6NDD6xt[/ׁw`7Ab![XobHo8{t!g>)TQ_UӢK+JRy3؟(o @`"1jz YsBMZ?@/ Q /TÔ^7 +rd/==3墮J%A|D%ji7.\/h  $؟8xxHHnBw"Y||>4p3!\5&R'DHT C([G45ƀJ|}XPeyr,iK]A3;X'}{ru1e|T4 /a<6>=PfP6{1^p0q?ik{n^!CDY r^9$>* [Y<{sRETsԻyzW}݋?*rb)] A,Ug!oLY<#w(FE3X]m%O^ =g{ۑ0r R$A:0WH{oྕR K mfBSJ2F Ij{xY9Y`=x f?*/Jbz :q{6P\v7TjhH2Y떛-Z%WԡKD^aIo NrMs|V.F!FO `8MC1[=U#ZJ{X%>ޡjûk00>k@s8|>q}gG*^ϲS@9|>uOy*(5ճLѪ|+[ ёb U9[JNR3Ve{4yDUW<5Ȣw@ElFeQ`J`IV?;n5_8UݬnLSz3^ XGtlhrs.P ?[^ ޘ3װh,)[ Cu([5,TP (a6ᚶ]uY`ePK+6']yi!^hCjf]5qyZf]DYw@9Ŗi"b{Y_qx(j`^Zk=hߢj*@fR\G 4XڙP} DSA( F;pu'% ]wrI(QAAސ-T(7C+(]M'Y$(WOAկfA_ {Y(RۈneRU^x&&xu  Bzhh8վTq:{9M){z57ftcu^ݼRLwӨ ;cO&)6}oyF(V0`u@Qы}rWWHiBٔƜ}+T$V^bF(%Q:Ѓq)U Ӑ@ A#l{TaQ^o~{p BQY>5$}]6~Hm]5n&"мLȠ#iz8|g^7B;3Ni$9-+kX;i)tO8ȼ,9ɗDbvPp{xYڦBp2ߡU,L{YIE{3iꝉ<riSO؝{,18osrIokфw#K 'oZ1pt]xmS{\5yp彰Jυy г] z`RD!$e&I26E;bn}nnӡnw0.v_v}+p 6o?% dx+gJI˭ٶAv4N{Gd;nT/Q "}llLLp`dEB}ޗ냫r:A)1 ?<5lӒi}i*G`gr^ G6ڟFV=+N2"N!@aKXW6 &dh@3+CٕF>ޭ$[lIO7~20]X 4٤\+f|0c36=xoR+i\23qA]ۆz}k~8/.^I >cSj*8WǶ-E{{oFTrK*%#/ 3;2(0_-1)H*#9X ~o,lQP? {7qGs1Q5XGcXFؠJRkxa$8g :בOHdSXUA_q.$Y'%`\LsXcxMK .#•6rqlPq[{ >NOl'B m'/#c{py0֘->9̒Ya[0^ӈvT=cC4|B4%҉ޗ_T%,þ[AQY݃Jf@0 3ݑRDztZټ\9"OHK$,Vwq`2F9ퟜQ.d 5Hc &:w -G`i)vsbڄY(jK֍ hF'%Ϝ,3?^|",ܨ(Ϧ fCepbqk(^[p3 k. T3?BaˎKIT]4lATtQnv5#5T޲gUe _Q7a)6X"|{ya2{eP!8/dbXwo-+ Zuz\B{(ybL3?됓*sQSNRz /ǵ%Е?* ir\s/+Ncz3y g4~/5Z1o-[P=ivpBq&_n9k9ϽDtuB^{%{VڭDpR@ ]JA´\cPb!:rdb\  Z qӉ罿\%X kh2y]zT>?V \^p6lqN%%c/:5f.8:=y!o9R &\<ǁ<;+$g/Ϡ>g\*,s@ Gܭ('OEQY.'σe]glm{9^Agβ_ I=fC|dd3怡1'pxusW 8`%dSu].lKvʝnM YȜm 3$SzECly'oEx +Z%bJ1=Zh2>E;qةڂląHr$fj5["d9`D8.d)\p xt*M6 "֝$~Șf[/wğC-܉= fP֘Ī~8/>9A`#{'3?xpIp>0Ƌ^#?|кWkGȅ2<7V.Z 8;=Ae%ؔ"C<2NDj#CK|jljBĹZKԔ"( Ī-*Vߦvìb6' FWM%6{鱡;:Xj(Y$tJEayx]@J!Oh8LIwT~㜿x1qvȧi1)&c$gPEcroKL;o"!3 6" =CsLq1|M-B)A K< 0EIM"կȠQ"S$/<¼EsfF4l(/XAMpW~rk\m6Em$``Yg]@{,bԬ$ Uq҈bF{KG!~(f]p,KoB2pż|ov9!* sbB-u/}uVCW7悐ط;iq<9,?JIoE@uіN3 Cր7$]%;ߖZgۗr}5hg6s-j:8IZ7蓠泬ԱnM8+ Nm# J+Z(`j so g_6*2\49ǿMZDi[œz>mVÓ2ME+cV~1OLF퀋09lE(P|\7l=}xY,;d`{GIQ5oNj>|Y )ɆuIBv4# \j9^pR_[5Z8o2l(VINzFy&;c2GûN 'aOrg|P ҡ 8'Hfo|$";mʔȼ޵͜۾Ը$VG ]<61bB3#ėPW [z.lEMY9;lhK|>rnD";NڽaI"w,g7BYpwScjknlJXnϠI\hm3h"~ɼR6e8 9ԩG)Z FaY _dt25il/_Rp50v'6}ފE>~QDCָUc FE&M% ?+Y~",⩼!ehGR(5]qW,SzA{w< j+ܰ75ͭN4=۳ɺDS|BG-,;Y9V{%!(-o]tˆ7$5Zڪ)>| *Ap׵Fd((AU {8m:}0d=sѦX~#V5Ht㳉hdجPv rf_+KX:a Ø%(_7kݥt9TAe@QijO]}{\yE#x+nu$cxM.T\fr¸T2;t&}: cu[$LY7at8g$\iqIUNƸwD&12D"G8S*d˔G٦]c48ޮ;HF 厛=ppIb oאflb`0u!8`rsOoHB&4ЩG9ذ^&IFs=RlocfW[fA p1~Ðz9\Czc2@MKI+*#2?74vxHRi9(nk*ɭhv@]tom Ik8 ´VZiD&GqS\ǷNʁ?)j5wS&wQ6-ip95.u+hWKר $U:L}yݯD_ԹA (ԴьpoQLZ9nM#]q9zzc8)4#7mC!Bn|>@i=\ E@T1g\nvׂcJiu}.HY`yWDBܖt `WOnENdR->~:MRiۙg#+LRAE-l[pKgbm`~Cv3.Id!ʿ!*H~ٷ%B8nզH,.fdO@#^Jޢ0_g8ڡR$& T8&OOY _x"=poNL\hu>R{FA&bBteᨛ`k:..^L^fTQ@W!X]s=GsYq@E 7 ;J ێSW9=]0:-bɌg6tXd߿Gj;#/Q&8T8h^rm#b)e2Z$9?i? ~H5߇.a z4;%Ԫ{K^w0])?'5NnҭɎTi4jy9 gC SB3Ъ =& LR##va{1nDRfe.lj2xI%"tn .ߢ{vD4TrBwktp٦^A@E/_=;W͞38S(E˨W'+aۥLs &eDVKGV݉ge+#H/A:A |vهv y]`=}wRDƗl Nq;1|f+IB"w_>0=o\6ȡqU;>L}fE~UnHRʤf7!dBdքӘk'f0uv"+F6+e=pECy)s9.=5o`"^~Xq `Vl3d^_k+dC %OPU௱!-T48JECoyqɊ5wUX>JE:D V'm$bYC&>q9GZk@uhEae쀥2ԐfRHC'/Gu~̖KMQ(#_uya)u0[,ڳ8G(qFyw 0mSj9jɮZt m;*=q$~+JsY^7~W?VoapPh7!Ҝ=p% =$6r}VFr_߸ROHTex%"'Y \k-uj l 0tKad5th UaC%OUs~'?VGPbmL(l$fHO~4 dEEn ~ø]Y/ڦ|*=h5Y˨+zciR PjͮM>6'G~e@4vRXϊJvJ]>FI3@2slYVvLǴ h*!`Mn7A۲oxETj EZhlWg=÷d@Vg i4j"lZ3tT- ɷLϋ2(]HpSbG{)*F^~(%22_2kǑKDaDV/֣L\!_`Z)jNP 'ۀfk}8Bh4PpFpl{d@آJoV{$k1ޞ*DeeJު7*:KTZ5;UmJg}ٿ&ŝ#(Z$YŐ[ץUHoVI4ղ83789=ҥ; (Degs?YhlCqn;F>62k0eFwPb_if+i;WW3c醰1xu't5eȜUIMkc'$G,YJ !@&6PH N9+T.Be9D'L6}B3HOGd`T4mSi$m|0(V܊_Q0!BZV>3e#iZ|_֜ ;}LYxJa{o<OBGp sN:W bǫWM <rxoGuZػKK%b \W\ O-h$ؗ JZcP}j8O5M4{h*F3y{0v6}?ljѢZoyD숫t=:dX"Z\4%uV%$mkvU X F H/t|^ K{` ;=򨟒uO7(<&5Pb \Tu6J6o@rohO%%ogZscOi-wg뼟+9̢koy6'U G;kK.Y|Z+`@xEz`;Nuqm0r)żzE (dҸ{@^iMK9DE[y>R/`(6 5LE_UT 9df{y ?H7!|qݺf&>< BE~n%)T]$10IOrB 1P!Cy)B>I#k+5Hy.lׯr,e/4C rha !ؚ iB#u7Q89@]M`%B-k@m#hbv4$Gbolf%9tʁD/u*ϙ:ްbVjuy{ QjF~P5=MbϰB%r zvO:(]v[jblLnE$Q[4ɛ)F0pr4r-m{'>\K!#ݦr{`]gl!ЍΉz[sjo{cqEYB/B̤S)ja e࣭l9r zµ o;k>XgmK [$Bw0v& i󙟁HgqƲ>5 Ѝ-Z' z5-e3"r. !G{I\me BNnEމx.ZOúd*7) Jȸl"6o1?;h'b:|e1Z{t=wQ}sf` 2Vgyr!W׊2:d}kt@XQ B~&e$ic acB` 4e,)Տ/*Vk~G2Z5#$1-g!Xp8<:x ʣ)d+1ZY Dv\9^ MLП?P8L&3Ju# 8$'r/tu}щT*uAzE],K֓Ph{.1j&HRCl!? o?"S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8K'7*m#_:,:(U}CFo#?bmo:¬t"Mr:e +يlN1OEKa"·"ް`d%-ϒ3[@?XQ |î@|w0kii~e)k7,p[j_X 2~3@1'M},Ht~ pouIV$HrCGg+&b{^W6 FAFP0biSYAד-1`םЌ6ٲ@Rl`8܌ aC?eT;?PO2AvR~e}$q d /Fk#1׿ v3'eElz }b6$xP? ֬ ӿ'a0qFN oFڬX ?#Q+%.fm,:F gs7dH@ Cuyaڢ`'U={PqS AV ھ)HO˜;Q؝dp0uD)s4~WUM6 vM3l:gOT6cZD,G[QQT* -]S E ٓXD#yE}v5P(.3)OX3BS}|մW.2[Oוs rI,3wMCDH@й@&hsf:+!oW\D] H-(~Ϥ&lsJ f C`{Q;9I%B[2+҅5z\/jycPS?˯$9BP 4v׀3lv0x 7!X3n n[`=}w{\ˊ_[L 뉤;=,l(y80!쵏[2T:Osd eʗ^.sI!c3|^s4\!,a[.9Cl`nL~X3'ؼblŇzf-amL)o1e1(c+-Zߺ3'ÙF;̚ y?h)32N󠊸U/h !eT蟶ɽ+ϊ2w:g+}HJ%VЄESAL@fʀ]>toVDMW!xQh3ϤJnad0|sG<΄g  [- X0.X⯷@Ibъ#L賽<;Ǽj4 XևY oY?VLB|/rݻT*}Nd4oסxp@[Yn n^2k7.٘[6Tz,w7?G Yf dFY]N:G~}XkVXfo_~Ia%6ˍMv|BXo} ,?!Gi?w9=iX5` H8dc0@Wb5w?$8֮0gܒ9QHH8#{-ܬJ;v'b&a:su(=Ǘ1PT`PjSeLL+·HuأEYR}2u=>F@-K.goF(&6džz |V snѯp_Q"\&:bיG]_ Zoi.1a*8 L᪜=xD9==XR𧺿r+JA[2]bXVJ~6:~Vzq}4Q7dȯtܖt2 9KiXxQ>+%?Q ʼnHRڅg~i^]Oa^2bkd6y&[2P)_x D l\./ w(8(d`?<\Wndeve{:*h͓Ԉ#;@iV %Bmct_ခG/2xv#)pg}*$hg̃3J'7JeMA|lBЭ4(줌K奙'o9IH1x}erj^*) JVG/N3uv\`YH/n;qu Eq RY3xg'W$xgDdNln%ˡDfJSbbN1ff} r}?xzxvu.C 1eF+L7TXX[7i&_ !sm'%oBt&2?K1[cyЗrҵθV`VsV 謿v8؃j̞ס#1?"i/qY'% ?QgT#s5Tq}=Ũ Bĩv~BpY>6K1SY`Okb g!%fURV u-]tiLfX*ݥ=VYӇgX 7"tF4֞ 'uqEV6\P?PTbpXIWGѻ `Jzv_흽9 sg{.>DhOIXiǁBbHHV pS'+F8Ș" B1֛*q;,j)TFA~ eKޚN(oqhdsRm˿N0f#'/otG9ꇰ9{u kd,+7Mj[nbU33>hQ̀L8\̥T.`|k[Lp"%pTb m)#QΜ>Pȭ<U)í]kAmng o~T8Y P]xvӥhRm-|ҭhhIw(O a$H2R` j.\rsz8ZN!8F}̸`M/DzMd+@10# wF|Lň8=@RA[a~cm9Z33\UIxQkgIѯWEU3D2t z#7)sHG/*pTɧ(lFlI2ELb A hrt^{af>F".,ǝ,"Ał-<ߞZWsx_؟z;uUށ^aP&A,F$+ȪLki Iv1AX>D`zZ3@2{çFK]^ Ew?j8tv.`?oAwsp&5b|8/ O_ZFyR{._, ?nWˑT<(hVulPn!!ߢeE?R w[.vCA"k(: qL5IY9,5=oS ]+}M&0Z6Й,ILYtF#}EIB7ω;d1&Ew]{Vp{D>}&>1[EyUh4Fr?XfI@hߋgmIzĮE"ҧ%/OnK]\e$ڼ5M 3!Tu%ۍmYEQ-Zu+Aeˀ^KW9sYE Mpwځi4Ww6d _aqgj67FGDl3cHT* 3IM/9Q4ݍxLfBX ̨΍߿}caטk(c˺UdRݜgc7yf, s |4|=ᐩ>suɐe@+bNI4aհ}aD<s޾o!ú! 1#:BCBF}-!١S `Cl<3Eєt=Wvd/4b"ڽ8!y/2 ;JxƫvT2j:pX(hHZEK\!] "`o晙Hn̓2JZxxK: ShI CCUBjtWҎ׀mWҒv$UEcZ ێIAhK5]XbmgcN MY2a-8@\A !?1/6PSBCG,JF_\Ɵ3Xh :BE|[,^bb2A  qyAv{ =ps9 txP~[nAi(g]H:? W%G`BI/}G^&dXVHp!rLWZdJTA :Do\MLL]yS{4+G%ݾuĘ*R1?Gac|@:<$!<3 }; ƿ||P e$:Uh-ioNwTA'[ݳ{|GWm^JxD  CW\@ky-ˑBWXͩ+C0>=߀inT֜HQ?1uG~S:-a]M2KeXE%x5Cnb,lRܞa;$MxQ.ҩۘi)5QKMɳyi}g%/8{F= (} _HuH ,suµƲB@ZAfJ'L4(c7<0P@*40t`N#2δA'a~;8uJ(E` u0ˬ\z 4iNk"MY,])Eb/5Ð>jfs%~=U +'A!bp `z/\|7T@$#ѩc>WUhSLJ%Kk? _ Gv~T lUNoIAU` de9c4U/o~Y:O /;ḗ|T)c gְ7^:=yORhH*",ǾLs:Eqf\2<@QAc.z9쇌ךUzr-|x-k"i#gi;A~5շЛG &MjF2fmggGA5pbmddgv.|n00ҼhW/Bw(͓}BϮ5c$}SrT4hJqp \jHrM-3{1ל(e}z_is*i+.)ck ( LZq,ցϣH YNcqA`wٞuKM.޵ ~7\_\ˆ/V ΝAHt?c4`YkEzfr-HHÅ'_.<!0 2'ܛN mMwʻʐ2BZcHHOv-6XrG-9Kpf PU({֏x)TրieVO-&@D:FNy'N/s0\$@. 2q6]ɪރkǬvښw蜗?/(877lvoZ5'KNtHn>6i3<#Ezyji^T.o,8Jxl;7IIsFaG^5*!ӑzOOsPa7΍+d|6:KID@ٵ"Xc(.BW@CNEiH{N썝cQz{x" G$Win?B?.pm ,bS+n3]9xVHxiaA:̾޸p{~_*o=xuj3 58RBrJ)ŘXd֢!I6#JL\~>g`D)j+9^hL\P 're\Lp_9*/sDhFm=*fp.NF%H~J>껯[x2TYl7YF/E;8$! ܎4c lŧt%tBO6T-ut`acY>DUoID :Xw,I ͛lc;Bȹ,,OgKȀw[|h*3\JԿwʚϏF7{cSPJ{%M$sTܺ0@VA= eWmk}i%/{@T#*H鍘-k ON.4:!#_bFxa)bsbUsf'٫hL& 햱bd)#7dG6uw&lk5U9{dӧ$K#P}Z}q EŐSQtK+b ?ZAZTD[ Nh66]1 pq;i'saSv@,S&N\YI Mc{~g}'Ўwj dAKꑂw(&4q6~ ELZ:eWVE2}~c䮑T_ܡ@p92J\3㭡M`3{0jO чuce$Mں~k pkZ``x&ELԣGztQh85NQZΘ8s [p={Fxuôo$ <9u8=fba|T~:1vmb&L$Ƀi >ϤmnkaH#5jk-Xp|:2p*#crs.I UP.XLgy?L"Jy.$_aIgBi8%֬׀M ~C, D.~2۠jtl,LjGbp3ex[UQr@ n+&)G}DT z]Iۉ|y0 눞ՌU S䊮`1{?gj%ixKH_f;uo/ ܍ÂFlVW<wPe i^K,.؋hr($(&]0?'(oA22W}M %/O*!HEi~k+2-!Ys:jcܦxҡG{{yc17:وd /}YbJ1ld: f#_.~=IkGL׵7lmt)*Jo2ϼ;:۟Efmw+4V|s?yHQcԅ(OGBN>JFDͲQ|6=R1=w}sӺoZI@\ڦ6oaAvہvjLG7(Š)2HTW>m%)eD3l8*aHMy>Kf0GExҁ* -t?#'I?qy/=>4AZ/e[9,`cdžҗ{R#eW"+ ࠨn}bK&87?L рui˲!V)7~KyGJO=j$sDvS6VWaRA(D4FH<[AMd[@Ƕ5/}0kUE9J f+,d.c[M{1lEF:V( 7E 0k"vlIMIa澩ꥹ`-cYl SjPp_2n: /0wf- V8/.+Ofb"-SaPDzRބeq>΢K|e i&1㽥UĽW $\! }efB[DWv d+f#(R+Xkq<:K>e9&'{ɥڣp(>p 0sGG :#ͯƧxYݝ%K:wALIf9#7g 'aI'}҇m`3! 253c mDEqC`}lPy`uYk-T =ݖ(b0k c1D/yvhZSh'oT/Γ5X&.G۪m%̨F#H%#9HC:ʔudkv&O@cJhXVW%x# N7TrU^ ES 2[  \S01N8JiY>Z|5%`D 0rDr0Q#DNɓI,^wԎٱuoS2cwti!/31 Q}A )1(Nv4noqUemEi '{Č:Dg}dp+J>pYdL"$yhG`:ӽX>_^sN6#+68mL #wOc8>_3mdWm dz$:\vO*D~ Ӵa~Lܱq nlIX@MdUdBGӕ !KK`%|E M#/ ap\O-~Z6z:01s^-'PZDS>x*?+1!D? zMcqliT13poEU} 2 o՝2/0w\hPQF^ x>tR_BD4Wy-E(zb"e}6|r:N<`7-X.XP ,~w 1&#_PߑG$)P#`rFDW9{~rk| 1VnE_hԄ56||>@!rKWacK.Ls|0rn؀ILĄP"M̀nd2%&wk'T;vɡϻ l?$rp!4ybK߆̩#bsgoZ aU[zБ{|0y lC?r~xTh\)D6VlfKd]m Y-5lv*B@?|3&6Hg^F9aAͼMAHa'NȡCe #A!= D;'Zv8V_ֈ>YYRA./GsBsߥYl_v}6Ka YӪYw|@5EyYq 8f*Zảꤲk}.voF}(p svO d g\uu3Suj p:q"> ^ʷ`E/C-? &H@\`$ݡ7pp-3CūUaTCq$k7Qgɕp^Uo\eelwg_\X <UӟXs3#O]6WevKP}w).dn)jHJZXG S""H,3,ruSd67NJ#'5SDc7㮀g2߾b^}r@dXLo!`.P!ޓװ2RQe#<^}xP7:[%xr&A޵1U?+mU?J Ri1er&W E Ɣ&*VY&ՎlԅFrYPNn7M5wLo},!w%HBr(g:9L?vM{ }U0!yĶf!t';5Em3&':@^vēԽUI,&x0,RhZ=7*E0>u(C9h 6 (ذYETs )\hnIlQI4Rɢ?[a u!H{:`Ti|XB[[Qqݱ,',xWeV ]pzGHF_RhF&;@ o\6^p8~R^ 3z>g''3߽ )amwG-{\[|1mQɐ&şNcG~vh;pO`cgduYoˇ} *?VQf\`7K%D(Af.@C S@40E&"96 qo/=& '(>Fܼ5Hu_YE.SWHRP38ūhwd0d5vO^p[fx6E4yxB=yZi%%X 9 !(%͎4KSwhZIbcooYd& =nNJTuth>%*w_KRN&'8ϱ/E-!pXuhA`!,ʝ6Wm j85R(poXmI*:Vt\\2]"n&,7¸ ZُWoo) wg%fx uR,_'_\ޞM)1(3HE6 /@C*mF+1zTvDe4Nq̸  ]cb_ۇ-0s 82N nk0rS[G[/b^ij}!=wVl2aIy7hiNrیkAS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4Hy_*R֯8hE|m?Sϙ-n:¬hc4+a># ? ]~fB[TqFK֤/|:ê@> ?LCH¨ăA{">Ƿ3t?gQvRyscyZC8%gtfQ UٲfI VF,jaV>Bm:}kՁ0J@wF=:N1wp"4\39Y2EYXٽw"꧘QF@_nxuf;v~ܥ<+ #;x]jaj䧇rc|>@|>|}Pce)О?PZDd2ߥ1ZkIFP.lBh7A=ڛz3-T t|&(GsI$I (=H&v> E5>SSiu *%=t>ymK,vVJԏ%hQI4UTcf5Tքm}2v)-҈m!dB)=z]Ο2 2A Bv{ ?wcy$z{ntj|E,1@(5[  w*DS6 =85"$pu \q{ɚp) >petՏb:Z>WUkV:4 RS\Z][56NK8a>]i Q7ͫF؁%zk1(@`GA"0ʱАG;sE7j&<;g˾!ƥ(r}}6,WJ_&&@U Vjgqg(  vw~=.VP2Yϱ)rm ZaX~MЁTSΟ|7'+mZ~$o@rw!v&e$W9%Žb~n{wdNRFֱ2ds)-mc2oi>O'I)f>W =&y :Ӹp؍$әBCFh'RׇMMu|kЬ} 6IME&lgթWg|cV~2j&BLWutec[1o!~#MrA}wn٘_AAe=woKrܒ M.S ),mYBd>!\?$Z]U&g -A37ytyҏFW>6XnKW|+:V %VB_#ȎOvb/E k@zfI2IA'n 2%,mFba9Fd&Kjю]gerkȖ߶{|L~.6Zߜt$m\$%~MU!Y]WUνhNvu_%Wá~OpE &W)E9`{`oyO{`Pb0KRdB,oX7o:hsqFϹfڨ$woTHbKIN!r8#FIs&l6b{A]a:DNɨ6,yDꯋ\(]|5`k?JK'57lheH:/:%5k9&(d_ RLF6fׂ"kѸ3}gF9駳Aאc5DPAN PjrlZOH^ z45V,yS+M!bxcBlX64de  X?Q[[vewaifͮ@A9P%Oh|(lw11"hOcI: øg[K+$|@J=.U+`Y'E}:t-S[h22 x{_~XoGa@[FBH%OڎLbk2/)F U}}@1DLd\͊:;:1 ΤmGګa(np2{]ꮺVW7v6560'vk3DjH"fj_{y2ya)}{շ<)xf1D{ZUNfՀ`h) Dg3 3axuf>dlڲ}ƏsB馩D;ц z[0#kYo"+%ߚy0&Y;Vwm=ե!u# G'Ί>ӡ5; |83mgd^ϹR-%a 5hGzBkJBM@bN`o؛– Am%GN$^m=6)aE[=5[<͵ v5H :7"waN51!3D1#<(J&*b"@0G-%S |L,r<ؠ;F K_A~2Nvا&A-|tŠ_τfrYE8~v?P%h%y~mO5qEO g3$1`(Hmۭ]YްA cʹԊP}R};Na\p8(V6 ܑ5=$2c:uC2(x=OCS(П} y7|6qtHBIp.3n=F@Un< R?!:xs|7(wVgYzT$RUfFB[̈́';m/beG^@p 5e45oT\->)צ}vHɛFyW-W~y$ގC0l]Yض=S_6W|V,N4/qԻij ̵z|9/G=p?@Ba~R?viUͱscQT>)fQ&:6n|]ow6Y{ ȊPo< z)r!:*i<tRA0VbɈKQIv@n̂Wyw'_D3qRĢE "6o|yajM[SuMglacQ'⽦G>jF~e\N탯qqiLcE:=-iUnfJEMDy[ZS /&KnVp͟Xӱ$\r.Sitn]VC<U n“xtBM5΂bIm`e%m~&lTkM]rnuLͰy Pm4CC3I 2|/ &;<>h1)]luYմyKiPBeNN*IWm9wxr Ncɑ0fL8,]`6Sy qo°ձ5/̍$m"m7Uu!!L/IQ~60{pio\ 65>>R- Tp0GKҬ{\mEZ҈/njQfѩ25G$|Hxga?dfx32_vqxRHt 0;_"Ee!sx^wk9A)^' { F**NZỴ 1 YOG&tR@t3\"97IbYfy\ݲ|@;1=nRId_7A)+&ʡZ?)NhY -xGw?Y]bz`>KB.x6:~-#[vY8ZBvɃFq,(M`)Ɋ`̽}+KJI1J|ߺ"׮48zlT :D6@('H 2k =%^yUG6oV[| T?{8/hRYhW);%7EREqyeY!'x#y5dvAMF sIu(اSSq$G?YbCN߁?_.?`?ѻ_{wH?u?;yv*>}h;a1v?\ł Q1m7沫g-kX٢#j`Nlwk'!`5W_I)8>3?:8zuFJu(ߥDh+ ΢lۡTU͜+'@!ֽ4<{%\DK}_ ~hK0b΀$Dc2]B(i9#OYXexl8_x7p@7yꚘ)82qqC,13F=Z\ޅ:Y(fh @eY M7i_\u/>D"ϝk4( R:ϿMͻ!/$%+ ]."^ܪœ@MA.l&hBFJ>ԈA(n #է@@Q*MB)iKF%x1="wڲ"XE5srTqˢ7APӕeIjp] C062DZ'c\ʉ} uQ%~ŹQ[|97?8]x['E T\?<6@@jٯhOM_9 Dp}9!0ª dt#)-&IO$7(㺩lՍd8xaN2~O޷‹un*>etsBoc۽$PsIeV@/T}P77Z!N+'~eMVh46 \xB-u>f֭J!gRR&s+Bx4:ET^ ឯ][H{KgkKZY;+LY!vl+،p;#ĵ8M6' . _'1P4.^BZmǍ\ey!j>~⚨BrSzQF̢: 괲є#f3nlcx?  Jwp܄p:w} 5+H.8yB!t$+iq 5.n ߶vZ_ @C>N+V" n7l-tȈO?Yc5tN 2kyJ3Pc%/p]7pR<+VX@?lJy1^ L8%x$r4M ܰi]{f h`1EmZzFo#% $zP#/qTbhВ0UgPtOi崲*@vϨ 'KhWB|~ ̮^^YlB96l#ģJ/20tْ=M? .e!KA[Q(Ehgh>ZV)He%Ic~pl; 1&/K"=%~<~ѥei] Y;{I4vתI CgN +IZ0ijj.)-w Rn3v#XFzɆl$6o2E(-!QδAۃ]i`yROA#lva ӧ][-YnS&J|*@8@^z/xC(1ܑNA]Fa\e.S`EOBin !HWW<=@E*ۀvHNGvenY3a e[}rW@xEr9 ǽ,`1n L5uRZȸ(H$`)XFeDvbBr "*EI njP6DPsBHx+a)Lc3%'6XAd?AUxd=0}pďbDrzp>!NYEKuE2'udF7g93 u SU$G8/v^4%CcxnQz,g>"[*>hdqu sAUS8E>JJ.+LϳX[<̿4XHjҧTAWZ 6a#Vp|;(& 1!؍;]*nޝR4z| *}:kwY@*hq a?.p 7.'wZxt:H6@۴-#C&,,DL(BITK,ucfֆēd#dyϚ'Lv؃xZÖwM.k#3X_%dd;!؈iYS*c 6Du`x;9 Ci*Ȇ7N9q9\̿hmnky=sNV͗5E1GB|JwOư /~o˾f w1x>ʴz1/m̉/he⚾nb3&,6I*nJ$iX0Q'o[ #3SK- IhL0QuxӸߋJ<-1-a6"T:oP[ޓ#55yoN/51DPd8Au)aڲY7E_ֆqb_N qӆb,B:W$wV =XUD^vEĩ:H,2 HǒW>DTƲ:X'(,Ɏfh7=t-Qzً7PX8ޫ\"?JR>,|#|>wc ZGM8ܺU/|@|p@ nqFrt6qo^a3s"пwl r|mL9hy.~4Hjgxo-'&wMĝ|KV*7q|C@|zLQQ씢w OT|= 3GʸĴq2EnG*+lQ,J] (1 ԬmT܈h_C2]뭴.Ĺ]G'b5 " Z$ .t(:* 8F'vGN|pF i` 1;swrE]1^(Ⱦ[\aK_q}KZ}oi$$SʑJ=7ٸj_ʩBȷrnԤ$BN=bHxJM EҾXsœP!{.l7j-×'ɦb&}R≾:kmt1̲fT 30_|>A=fΆD1?̀S29k K_'C1R\mlTej?`; ^#iZv2~0Rrf-X5bYVʥ9*{HJuSHcfw @4H҅m&yh48Ӂ7fWFhrb0 FwQ0 b{@(٘1YKs+h">a9݃"y)"q=p{{";8BRLc .`YC##oW VP~ N5?ҋ5DM PmhPo}dyiLeqS;BW:=&!qu ~T&eɋ)޷c؅/bRܥ.=ת͟>:eg2P0A^ 2EҠp'#-ؐ1MXORA۞zVIA.D}kX>&0O&5;&BfWi×W 咚0'^؍_-I?Si|UJ HP7/J&{Meg\8@r:>/|ϴXn0s: im6^rpWP79d\gD~kR= -PC(ve*m6d:;-\ygQgZvAzjp:~ޭq#yA[m_݃@V irƘɛN(2$ԝ[JߍCVk@j2Y أ3EضTmK5k L=J+LWgn J'"fv%nېTcq ^V4cQOwϥGC=ĕLd;J#S~IKKbvk%,bCJhI.4cTM%g= bU.v?# oot.n+*;pN'N-uH:?3z\iFҺȕVe2oI͞7&N ^sFU#DX#]0NN'2j>5%ZOR)IԮ2h +S8/˿zJ2_BFb1RQcGkP"npS: ) U\~)bV7͑IɪB5yDF^Qj[|ׯy"ő6*GFG 9иZHّ{(κ~xVeX00ґr<{}tv8ʭů 4!JKxB-0|%OaаzaJuvil:et706@!0m;ϩjH̫aa+Nf cK\IiuDJ$V_&݉EEY6AoIAy֍a ֲ!ԉ9a\vH P.@\:k=<ޖi,R@a@ZkzI/˺.I#WV{itU=w]hDWZ=T<>u֮ hk4Y/ڷ_G^Ϟk ִZnJ6F,Sk\˷v&<4Mテ?\?*0(PF=oß|-`O? ?e'`qI$ER\[M!v0CFFEOQ,a>bʧxv(FM9$b{ILTN, U?zq0bpLhV+Í̲mqصM"fs ^D:+=tӼGj âf7i~ɛcZJHt)A` 7r[LtY 8%ihb8h #qFޖID<;׼@ {_#ib2]iڤzF&ze;8|Q=/^PD{sSΫ9l |" 4W;p45| R'؅LYmjk<C S{H*P"0㛽aq_|)OBwP;QGٹ)Xf9ĵqzkWYZ,Zn9_.&{#cṈMjd\_7P@9f>4~gș2r 0t*צ3HD?^6Vѿ88#.#p*a BezR/Wf4 N-EK,##nDŋ߮̚~.2˄%3tm0><6`l??,hP(>Q& $JRLG% cAw!U$(?4)]!X)s9W g9M`kDcno>@;;)c.= vhcf}P3sjÌݻz =,`p?ŜV[m\E<͏jO߁+ޡ ߷{4W+PUk:&Ī۸Bƍ~.T[G0y/E|~,_,: "ǎ^;B(ׇTcAËD*Z &emHMJB ~D"rO"x;\=\?ÕJey_7pꈧX"9>+ Åd)WA xWE&yh$c܂D~St'&901~gBMd$JD6~F笂#id+$x !`쪈"~̳u@f$eMʗ%݅܋62@gf"n6艷)_1ʀ3~6TQČcx2:`Ŧo0BY DZYlS1y>rr5OAN Mԁ0*>B׭;x"WR{cy,~fXTHD,ˌA{aZ6AvʊTZZ~`S>+C&A1y=[ 'Ý}@ʐgˑz:⛆' C`5}堺FŵɛL@&"ә fK:AfYlp33oƒx߄v"Iry8e_riɃ!VZ8n8A79wa; q>S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0YA>1Ţ@8x8d Fiͮ_p @ʽzu_\DA!L=CbKIW[&|7Ti-)$zqci.ߡߍ?C.u$-J bRPLKA'+;dAxd CvD[3+m9{yON6x 6fmY*iHbPYdGh`⿦ K.tGr2p[Cl[Õgc"އx5Q2S2墯urP$4dQ׍<ff 呈ԡ>bE-yn-\eQ?֬wzǀ~Ph[d"p-UB-&Pw ,ƯT|@7 %B *3%^M'́UoGHO@gItZȽx`Pnh7}a䧓g`%[M,陣SWWq }3SJ:F& #u??W1oTKō },*H1z5'z <^}yQBO}`JPRMȕlu!0T[( )Fajvddl3|]+(W-'`8Ry`kjjӊ9o&,5'ƶSTJrgPƦQŰl"WC- P| ÷VԅDpt]#8h PxqHi9ħussiZZY73 grApz ㋫>DVޟ2F~%{!X#"KER]y~* 4S Zwkz߉bR_Lq%j-h dcDn 4Nvu?qAo.n?B JtZ5x[N\7zxaW Kj?JtMu`&_k4-_]? Yt"psH_D=.n+@VJG>ݳ枲 , 3[oNמ`+Β*Pت:_jzAb0D6t$P:ع :>Q{66dmyUI\t7jf#[TO& ?|L,<'QM\˲2~ ||V!8]*CFL/_24edܦ6DյX _ߵ=D_ݻGʽT:C:SCT˖S\;"~~Vk1sY%DuqhwG6evsh^ Yy[`6 0ivpؔ!ǜ0x^}ZLh)_nݮAA43ŒhIT6V8l@k;E1Wrjm mrh(@wljFw@}WD0yEv)qV3 ,ғDa[Q2ȸ0LHt]fچ Rl}y0(%7>.@#NUu/* "4bs|ɂ-M"μ N9C"rvx<E%cwH)Y]p%oP"QNW9+UշOEh RM]O2[۬?Q z4 E*G51/cA_1twqgO!'5DE4D1YǀaFL7vC.ώx_b^C{EA(uqXXn-X-xmlњ ᤍtH12{Xfz6F Pۓij.7;xT':.L?*SV{݇f;W$=i¹D^;ކȶnas<f~_<5/BF= xV;l#|',.3|,(0QW0@8b 4}PXD:9r:*}v*>? DZ[b=)b L!>*6iQXyZPYKqz<^p`ޛ`]Zߦc2b佊x ܱ8E~^lfS1ѥ ad ,"J٘9+&ĻY%)qP`h pp(WXފOطw; SQYMݱ\$1$ (H[O@|h՜;q?Fԭp9rߜl |ԣH%F (t|] ddc`9:EV;/4CqNvo»{6&륲Y8C3UgG̬m/evfyy E`M } 0q~:y;T'H ]-aBC…`9ZS4*'Ok>ny,f{hw}5֔]Q<(j\L+)]I1);V|!%eW;F?ŎgN<>uE:yAZ6.tčgKj%U x3&BG5V7K#Cg_Ûr> ܁d њB?7CB3-HXQ{CE)"/g]Gκc8Zw"Rsyje[vuS% cIOzKI.i94߄|$h.5"?8w!> \~l֍ܜKƊ&MK׆$ Be%@˕wjN|X/_1tjlzw[#!Fb@%ᅝۛ4cXuUC.E60}`@w?\q˹<)S0N(-83xIDi'vI5$*2ԁ#˄L'ᩖcYEq ͡$Ouy*S5m0?Jp\Oڄe($:_3^q`?|ok(5)~g  jtNfb4=ik$I(r#9 Ռ" Do>w-i堆C?*YGk7{/lڙ6`=I/}X  ZbGl Hzz%ºnՃp|RpڝS횭(8pj'ђK.6˟G L _gjRK#nN}׳|@|@>@Ob._SN?Ѐ~x IK$pki`룃O Al~Dz0SzйP>?e_ 2eg("Slsb b\ K&ۖ4NaW#.vl /_O>$YkUPZPXi`Fc,hi{j &<{̏[Z C#dA"%vI6-?3 BMvl/8/f2-PAUx6Rx5ߙa?EL<"Z!$İ h@FA;4!vR;ʄB~Lhpᾅ.-aཡ~bvDfwo 2hˠܥt g;" 9_#sh&!_( E5ۮsB4]~D㐥;-:83`SJmqǧIZ31zCPT gR 8Tl9q969 a3="_o IR~ bU%$5[КyƮ?6EE{99twb&˅0"~ 3XJB$ bWy+p*vBU> G}6#a"RK$ ׂC@N_u5wnJ@V0e T#ܜ?U#sx ^x"{WY jYW.ˀ8,=l0ArlЮn>9c0TorCec칠 Yi.iF/f.v~w i~@x:$q·L([?R-S S."mҲG4E#Y BWƊeR$#jphԅG1:׹^p<3.*1F )Z\@x ~'9/ЄR|5qAWLж2|`["Wyz…an8}(φ1ueb4EYB uSqCV}M:HN]U[K3xKZ+L"?ͣf?T-AvQ(W \vЋ8CJ#~ZX;nb% #?_mlm铄bvFA>vf>~vQ*ޑx*5 ȏcD{EY5.']]z=8jI܋"0 #}wEPx(s׽ WT73p}C!ٌ=w0 Ve}@/ev?R+cnq?/27P'A#ғ}43sֈO UO%6LMfٿL27&(/g,X[ k\G$KuF(`Gc5cJLR ;ċ3T\iIV}ˋ-J qgrɵ/WbtXW}94`:CxHQ{_K2ZV9r訐 Bp$ nvμk?se _Z I%~(]9XVr<'.|`? = Lx蛘ݤdPHP3JhOPYm2]:5d$CWffh Ye5m̹lZ}ҍ)W>Cj wَx8/V- : .R|HX 0ly!MwJ}Y 1Zl{ky=un4^t\c*Gf OqT>] W\Av)(,N4 ±{DwS {*H=03{ip@2K݃f#U*-wR|2tP7ehuNR<ROl`OP`mTg/{b7R+dW$52M9tWq jvG|XF[JjYE6O 9J?uup3H,(Nb:-Vs&7L;#ȱ9V*lT5"Od7-z+@_ VbX"姹£Pzv{Y>_5Qͬ:Fc+2wl;sL.N2{APE2}F KǍ Go#jw!; &k-^Qa*Kh?̯͢%TrFIj^8)5vffٞ sJ6r,(O\4,g*Q._9QOl3c` %Uz`f.[Y02X3;9H1_lB?;7]Lb72 ^FvYsWS߻}҈+ S%Q<*>$sk`|)gҪh(e bәV|AkWQvi3'XFaq,} t:r%Cex0k^ FĢ.KeR2!mntOܶ43kMa[4:׵Ui/8`5 $S2%w8 m O |7*2L|>7N~0FSP;hEIj7NdcL^<a34w6kIJr q}(o)_xlA!UC޵ޥ>a]I* ;i_ ?ہ= xp I_]KcD[J-Q5|^ꋽ!QI3__:-oQC6NzMkڙ; 5 <S+M4FTIҐ)$Z(;.=.1B&jףh]0gUw2KF$!\ɴEȼdJSd%Ϸ|);BlȱiU0S^Ã!@87PaAx+F8+1xW.Rɭ|ZTfwkr|m5l+ss$`ֻ5-Cϼ ~lYRyoZVSMNz'BgO.||^0Q@^aFL鎆 UccPb|q,h5VU\14m],_? _ ȃ T9R3)Zc0;b3DS)L.j>t,zM%5\EA[ŗad(O`knlw(jOe L_q_ Y'dUxLvc *HP% Qٍ` V6mMbw8NPR&cȗ,S,”}x)'TzcB@vernYS1r ?!8n1"۪x:M/638IsmwL$+ǿA%/Rrxn.֞Z[l_i.q5_Acǩx -u8.H  97L';P\ jyjA(V'mG+}*T9I&j]/WAJ7Sl}gMecJԂq)ke-vm0L>ؓ1E%yh)v(-KCdY ocZ_,e ۢ U:k% ESV~+<k2Tph$ GcspXrD3:_p пa9B~ 4ӒLK_s^mqA. /?l^nN%K#A̢ɠ̨0 hn@9CK:ҒRKٜ +bH*%/ٻ2N(#Cn4J/~8sϽ@{lC糆8u0ъ4 "H jh8"3ͯIhe8}0KNFTS')jEh ETu>?:0R}l<* #h:AoH)ܦ+ ~bd9`HL@O71^-1 0\Hb$&‚⫹eExZa3w Z[.'`?C}u/4`Kt?:'TGݳE߿} "vZE }3 qӔ:~Lf!ΒǍZ24be/vQbd6i~ jRa  rt"E7UK,$' 4=t@2C篳4GQ5r 񲥠RU%G~S~ I 3bVIk?u*4t=L35~THT#0vީْ[%`p B=ݭvJ{>_C4z_ٿL)&9H4η׳ULYA/~eu)c"Rx#fKw_gņz%z ~n9 sG=.ͺѾs=dD=Tu|kqLx!HKU} {٪a<.|5~bW˛E=Y@_8jwÌ$z2IWA3ypކ'WK?<w*skl9iT2DWSr@hD5ozxy uh(Sn +L\J 1@UB4%ɒڲqϷ~UxgH ; 7<7b[j?V6D'5](qSvF\NЊ&#(qgb@n,aolyzETSh@C3LX#7Ȥ$RUټhZmz䔞3Jo2oث1ݻP 5xen5nRB[o.FF/PckDN3 g9`*6 )-쩂\KSr׉_y|zlbK@4UFWԫ֋8yu?PYݳQɉ$H('ݮ=2{ )IMY=;$G\=&NKzC6=]3ɚIԟIU~"9 VˢQ功" !"qA8Ekb W EdPq}g9;`٭֙ץNE2JC)79$E]c}t)6?_Q\Ga^lIs;E'7ા;zԗTfVj=\0*.(I۸w.LY_)]`Nv{ I?wH(O*`)S[\jp3:JJD xT"YB#~;AC1Qݨ[!djUJ'{` G1CT̼~ ?]ⴓXK 6hQئ^Tmku)@o3dG= 21 vOd NWnwREcdm4f-ċ*QT#)`+o$;K% \C#c5Bc,ڠ* 2}k:ZK?쀔iqx.[P>䮜C5$(qv!p˴@=R)?ձyF>t\iC64*>EwnAé~Գv@ ΫA >]|L7A^:\$&=z O/UA,QNR>KHO316\.y꣹QCJ *Xl7Ip=Y ~aq*3lN1L*ѹo$X'8πoޥ>\_Ŗ|t_Òt^`!Q ˷(UУ㠑;{%V6Mwɬ')Rũ\/[7elZSH#CuUz,3N@*|b#%V_$&~1*no|07s2\3ʿ3:Z R q$7ނbݭr6wgEn+G0xL:!35XT;xe0u4 >GEc'9'U@#jQ9FA6p  "ȟi 9?)pJa{IF^m8c&񼲂E vCqH) Nm]Yxt9z9du ?M0PNZWڜVxǕdž,GjN6?a~ %'%u/fWm;28@}"'휒T_h϶]>auOΎ7HHuv;s cOɫ`~( [4-fijl$UDL{GwT2l>uH]jE>&ZWwv%I JxܥѩQ$dzQxbcOtʝ# u`A7Cpt m6[0;0kKLmERUeϐ,wZmdv%2t}192_k ?{}!_ r>S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0Y?,n_d:4D ב^b}$pͧ/9^^8&bIDgC5r !aI^ |P̴QU@nr{W "?ԌM|:@|wvۜzcvo3JX4aD4s)Qip]$F-/u4\]ҾӰo(8bbzY*TU;&@? K/ h>xմE00D XE6|gbZ)9 Fӧ;x05?RӼϤA9l0AgcP-T博8̈p갡̥7?s f;g@Yhg'HM/iG3r㉞0RĚnë>{GcwMyK5d|0=eC/|>|>|}$:z0!+CjḺT.7˕V1!gLt|òM/Ѝ+ж &/ \f1eB}6Yj܀] dlb  hgwּ]"]u *

*4 z0TǶiU8!F843ďe8nmOB@(I點FKw v c󓷲S|. LG$ܬrw5l >3kX'/H#EJL_7MXuߨZ۸gtU @zԾK5K F{2Z4JIgY&F)jeSV|#[{H蘑pܢB4@@B״rA7 oyMrxLu=ʞ0FNkӈ-#?"u2_g yXHH&|eT0PNn-3H9Afsg}bnWdzA8;~dgAL;p5Sv&M>=A2<`%@5>D Dy ʫ p95. B tx8-o]𣦇i›@0lɩ$['mlS~R 4#S]TcfIzE]}XHWln[r *.8G|.1plx"8`hܱ7xe&AH#3~r1X%su"|u*XqpXʂjH)mfQ]k5K nt,ܩHs3\RCq=#.7ʄ[ARAKtppO ] [`/&ۆ0"N~EJhlqp.Uk:̓C#KSLr+^$ǃ~dvU}P&i4K"˶e|٨ H<<>wG]N [cĥgcy:.c ޱ7x\9 :'s/!&(ț$͜ gʯt 7xP_K>9T}*il.y_$$m'C,,5 &GӔ: IqB)ɝ7opemf0W)saW Jʁ3^Jn͓V ρ]i,ًm/ό/?XrbI+Td% 86q?ZEB W7SPk"Rh7MD`LZRY/ZU?²q&g-3bՇO /uƱ\Bk쓿$Oj[rY{ V{dm˿$q3_S<*'&SnW; Ҟ>{5 lT4W!p!&jC0^NIܤKzޒm튎Y;rCP5BACg(;xe{/ oO, ʡ1&[XJsĀ4Ns̙kgI_?XZ-ՆMw X 4Bqʛl~%IN(ȷ6xtnpP TjMIbtd+4^*arX4f9V!}f ;q&Ӈ]Z^tXy1N¬]0Av${,H͚%ߥz.t0luv8ݸF o0f `!=iQT(iQ*6&7,5f"HRI VYdEp| 18ofvp,>쓾ڴ@W]հy3֔֐/ H+2w)g΀$$5ؚc$0耪{ܨu$s|8ړE羍cHtmkdKG' avsd°_aۘ {k_ d8׷<>Ȍ#;ߑ@ ij> jC?+]Ր4.F CZ\hRW6b4ve/ԣ2hnl"oU񨑊9)~vZ2M4k?= LW *v}TS#J!0I!Ls4H;]|KOSqu;PSښ3qIYUisΌ9bJaI)\n߻QC.#)$o;Cq]ÊCGd-(^F*9ژڿ63r Yd!ς>dNXPl^/-!تH.{toNBWeLAݝrӊ"ԬS[ !S A?KiQvk)y*ub%/E!Nc2o+l6 '# 5e8㇥֢\ :~pQ6E74p7G(ǭ Mt{]KƢv1: AKƑ b//GM836y#vwq:Ĩ 4(J[VsZ&*8^ԛm쀼^˷6Y=HgۛS Y+h,&Da#o/LK7,&𲉨!ol߅*|߈w25i JD]QAm➰r7r{OBYW39[ xCX?d@16k_ЌmXY]1CW!zrx/@Fm9"¹ƴtd8PlO^>7?<9^\_u@ І2/%B&b$xOW޴J_(>s^j6qyv&S"GNlfITmέT{jL=I"IH׮I024HgeyEい$iM46dwa@o'lUiV䥼6 r #c2aΕb)ۓiNv. Q'pj:&!] #=&~WL[;\m,\53J8Xz\_?[p)|0 Ɛ |֎3VT$zg[FMio8jzeTy8)ґh8Pz`W) 'fҶ.8Kk.*Nl$|TC|z5)GHg0.6'PV;o7q7|\"nk}Q1wb:t _LejM+[(z&4 dWKH{,|6"*]*ٚ&JY~+1Ld6RX ZCXf;:b)Jb1F~JPTU2.1u)w mJRf?e j#zb0Y k"ѕ3r5V76N7qV氤j{ee^beN`ѓ(R B* 93^)UzpN;X[Lvw) |>@Y}^}ԇ8;/4kĬ@ں%MxO;k4.p0 ]r -}l*S)fԓXxSjŖ!V,LJ667BX0)E} 2p{T v DlID%F-ôHYZ:+$Bk8?1us{,Y Th T5?nS(=T/5 >|K֋v!-))9csܑv!;@pP%Gr_$Ⱥ'usy gec+ 6| ;@*%(QVUmCv -U,Ɂ"Sn_ZՍWB뿈*JH]4bp(;lv!WHEZz;vj)ZQY Hk :C.Ґ6B5]B=ѻdkj.\iQLu>e 3=|nỉROgth ܒR5(EB4> ضxū1d [oܰI%i3]rVLť\A=l*rž KKW'$wx>pۇa%R}EПJ h;fM)R= n< ƵkpTD?\xL#1M=ඒud+L>S˪+iگq6 6XP66$Qpա•i7C b(NygPy8ݳ`3xe#|y4km2Pv덲,y2+ʶjҷu4Ӻo}{#8eyr0@QحJܠ'$4ѴT@+5?|ΠBpe!d#vUm%0b;5k_}]Kwz??_?%5J"*Pl'b6 ru_.#`:8e6;8h_ Q3Z59D1w䆐Pv,fcGElTC* ij.t_à~C?$g?H+&h?S?Y\Q 6U0{ElαGY1Nu#>#>͵"* eU˫g@Edp$_F[Hիw^Ht%3/Bm>nŤZM%*+BƝlgo]+U4w>>)&)d3,7N1oq`MU0B jb}$׊=r 5N6^]E}0n>FbT?ƑOhLs"QLP2 MIӥX೥abq]0gpQnб0x4nR Z҅ٞWÓJOhW cA-BAil5ۢf lDHB:7 JQ̉ { # ^ P)C F:u8K  1 mKR:\Jؾ2~h<MNbRPY]po}4Ok0PqMi;3Lm_0b$^Ӱg (qFXD b.vUִ(dӷ_Ln P(P4~tNvz:DB9D(Dެi51ą?~2ENB##8ٙZ7֙ݢ,Cκ YŚF URL9A"VC;^Oe8Z1)v8=O@*xb?^ լI(>QrѲJ*%`lzʬLo'^u8|l$O'ߺ\l;av}V8M'\TP8'"|-bKnuj` {qOj a\x#/fokc,`žN܏̕*/˧ ]Opuo$u~[q/4A>&S$__[BmDϐe93٦rc8ֵp7p<^`W?ɺ %Dj@t߼ԧxv( $`qW"<)~A pWFBT.b'nbpJ y,'RH`wØџDN#6dLۢW84|2NUٍ%2  zP:j~l`zO2C4vOYX pT2>wX$4M<.Nngn"oy/%H5/+Xd7hqG()C0k<0z ԅnܼٳ7ت .Dl9Җmc~˰9ɹ/p`~6T@. O n-k[qOdaItD>jۼ#uQTqI$}U*AIA&}G/S43ȱ-~՞]B=ү;:7ԡȢ"X*%[M5Vob6;sL2?[҈Ij:%FXY]J#fW Ə)OL%T)a cZ>KMg[= R8a>.$0@Ʉ"aP #sL漳)j<$ӿq<ĥ^Ol~ ]L9$Ĵ RzNMTad[̐3]z.SHL>^G ]b߰տ]ykc+͈?'PO(B&ODxȈiC\ң-nƽo*ng@'G=vMdӄ#5QI)1?bS`>gj,Q&;Tamws\lb JSp-L^Zt!WyR^n.جdhrt^43X$RJh'Wh{½K)tU UKȗ4c]‚oF{>a)cbKh#VT*+ւI^ZYfUZqx^i%;b@q쒞+ǤbaY`xNe3l:V%jCǕRs'ԝeW6'VdF!W1, DAw/9"E*^jV1gtm~?s 7U^,hFhQL`b9+́> b&YTDxff~ޘON.?f!'`_kb`sbqŒH* Z-3NqF(o(s8=jyXCT(Wy L4XtR \$)W88MK@4R~/)86"PK_{F`e_dJzSAGJ5FI{lӣ4QWQAd x4E&OP3;885nW]<6MWGf|i 8/ŵvH܇`rF818 vmOpp"lTTʇ]Z"~mGEˍujdN~v|G@|z ?Ym4Ěźf 7JG3klǦ[nkjz?{΍$]u*V鮮6>QFұ?=:)^ 4C> Փ3Gr`+_wh2߱_n5@n{P88:Nձ#ҠU]H!@fb>;Zbç~X]~]8i>,KJ _@J$WG9.{;RۅBfrVK"iYaco^FTr˯0ȖGKflgjL1o2C^=R(634N* X!@{}Yl`z9\Wf^{W эa[LB-AѧmGb]r"bџz/uN1\@>@Xb8@w}@d2j:V;;c3%~gjIfl΁E߽(}9(ynP>D"F%ϖ,C4o, aDOrTω bG: ]ȝ. !pa]`8QZ /d\Ъ_v8M»MA3}fu LK1䱻H:?]_U;B5=0E)eq΢7 @a+ʹwYp Qjb .U@;03L@-!iB+oC ɫœiwffRB,jI#%+7}8߼;}d~GH6) aTk(Gej $Nd #Jl,o* RŐk{nKHw=0lP0$V\L@&'a!>(Np(f$!<@hT=SK4>PF3s Z+- X2ŵx6N`&wYn(wz78w<(Gfʌ02ݒ{\ҬFj1FRGF4]!, {} ݌$1Dfg,!:  2aFkP i- W-O߻5bh_2I>?+!Vp8" M5iߐ_|PimuYKߤ6AN3 i#( F dNeO9kϠ\>@- ;NƧK9{Wq%g |&龬y1r^z0 $ "v6JjHS\?̻R b:)B.:[jaꪼđaږ4*5)qՋB_mӾ?o\Wg0ٔ/$L2n;asN0+XeE͝;•3h?;û+Fu+cKOf` .D*$IdbR* W2stkI7yL0T`}Sw|%5Q c~4''Ѳ]oƉg އ?^"/1q,trvzԕ;ld:^Ƿm4Z *s&AM7b?FBHǚ4$حh׭zDAz CuzVNIA >>βw/Nb$M#;%mKnLy3f]{yygXWbm/wO_/+X%$?Zm@QK=]s0pY> @M KV04e)8 )=pMn.1Ջv|I8iDn^~PwffCIn9g 7E1ܔQJN0Z{n(DC[݂vƹf{}sKdJ /s`-f9J8NMƥ4aiV[6p#ȟX?ST"O~g@[z[# j\]^軒# 64%,d]БkODgР~QZoC&յmV$n F鷓[[%[a5CD-5>qHÖol\!8. IX0~TXg=({7aq) I:/IjpvIl*4 'Ch5gm9Tڐ=K0Bfb(.}(h)4@CCfgD::GVDq ~PA[%ht :bf ʫ&bXw@w7 ZJOsJUpzta9p@w)GECvDܿ|3T@[afmJlރ^ \ASnN.'< cgۯgAzK/WeLQXr?,fYz_M`7Pc) O4,|m)T;8;Gxw+\ 7{x80ZĵxsI%NN\z}v8R#4xg"n پ|uMbJ\/aԾkS{@seϓzS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4Y1)PbFȫ@8h h9i^:> +ˮ ",5 ,%; R?i5/ ;|WkT-r6P٪=>H?|:ï@> #" 0 զCJ%)˘X){!Ў0j/Tn̻I͎TT ݈YU3oHJ쪒"`j qFvW#XIy~QҤȸSCa0PgTwdB$USuDl P 'T5=U 3!Y<)GLUHtr ׯYҶlxWpicBs"{ sÒX]}n $d:ci.ّ8o?W_Y}i_g` jmGi HP{┑dñ%UƬ}qgp*?v",9  F*^$;[#kDž`~zv-'E1N@# ѥB#{vE+ج ֶP4?mS عz9[`5"`yΚ0>N\dd*ce&y[KcJu6^:gfZ#w;0>ڭ16%B_ALW06RqjWW'A .K5"HdL/l(ghZiXrs΄uesQՔρO@,jw8~96!=}հ%wzwzM GcMT F1{߸_cÚ;h$ Gr-,/ՒfkU-A>6ɿAe(;~N|5óO.â> ѿ#!X?wSX:Ne&!rX/ `p4A0<9瘏e@8Iia޺E\6u0/<7V`Es2I̖li]liKeL&oY'l]\U2keؼKt{[,BaD;ts *+^;<3p0 k6VG&{Z.S[ VUߓ rp8yvt:{gq陻!js4$y7Hfx* `Z{wk]@< [-C$\zmMy "&UкrH =My#q?*QceF6`+lWpⲗ lcV>t ɝx+{(//!@Yx .nD)BG!)Q8^Nվ];_h^(ZL5H߈taEG]V 0+Owř| aY(V툀OJ#6>4U6B*XAdDy{LL{kw 2L6B3({۷6/Ͻ6TJXi;y$4C|*Gq[MsB6"lA4ILXvk֚ mK)js!C/0FLTĺ'/Q*๤j@CA[hc:8yaҬDK r1)#6v}WOoPk+_ŴNg춄}EYw赸q6#*9%k@AH%浧w5YrR$h]Wse{I X# ꉄ3c+P)cKݱ'q` i_{,T&L(d@ sd "Z \O&=Q נёY^>1Dwn>xIP ( f]:8pv[0{iyR >`^=mяU1)5ԯE%32zֺ;iR|g)U\ x`hA*]~\~RIOuBOp '(|UeEc3(EJhsSӓ-4G)^JB@iƑU4 %yl .I᲎^3FD V앎|虼$]jN@r*5 fI<'},l_aZ{{ |äxj);y.{9l+I3BS QW[d^;sе}@&_x]CN "jnUڄEj tAc=h{y/ĎcFuI۴({ƒZzGX7i]-dӕOl%zo &F٫١Jz5IR'z'܏.5/b>kVx(?e<5G-p/'.8Ōrie;M=7ůx{\|\7=zH ǎ.gK/p'>?P 횁Kxz6"r jCsOq-FwF콯iJp9VH Sd:rժlg>RݠQY nz@Y,/8,h֪FUuhX5R )1 m'`S ~S)/0lKurv1D VM0]E4a yu2Ƅ ~P[ r5Rfw21ݺǒ=rb8YN>wSWn+RҦ v@As8d;C8H@,e1sJ '~5.I>dk"IZZ['F^$O:vMA b>a\BΏj6N產1wE'CHOe~Fn)BE nt/&a "䆴[#!˭|摙6%7BئFA,$tM C@a_RKJij(\xu9>r#.͂Eߢ7t8SӍŲX,m;Buq/H +Wa/&Е7cI =n4/(zWd3U"w O ~~R/UGi;ܽ4'x:6̭a:,fP7!WD(Nl: %Ldv~W%-K\ U'_3W&>H4ݶ%z`rtΦ6#7c`_gmW5I4&HJf 8d[A=7-PˆjnkcOn`FE?@LjRFjɼ5ÛukI^{ci7[ X靺=>N謮&*gST.|BGHg`fi>-yB΍YK`S#Q͒ɇYڃƏ*4ɋ22͹L`FMʅZ([k:Dk\kgU㣦;cIIYfK1kMڱkq'o=Tu=fXz{cocTūK ,8E }KV|vzF*ڹ\v ?EhՙD&T8a=}GXNS(¡c:7^oc^n(jl뵚OYՐ`QVY\E< d7xFeᷛՖ1/Z)$-#Ph HzRnl#:<ګE 8xF|%**ISµ, *|c|@|01?x=b~c>`,~pޅ+ua,-XjCDrKA3ƒsg(؃ `ƖF sk #*"d٭[YLoy|F|w/O8s9],h ۜ#Tm_/#/wX*E{1Ņ/aqQ}uV! z+;_S¬פP[=.2[/]<3<颓ך\U(  S&!33?w*}c<~`UR &.R0Vau_~ģMrWeodՔ=Ds3kaէ~aSY&J'$KUS^ %rc@% GXU5 VWx>_/,?7~57  IˊEI%~ 'D,Y8z$( |(I` Ɓlҙ|h֎:ѿ~jl࢈5H13#hLF%if{&>m9ꃨ`dʶC?>jt|X57.7\jXӪ-$5Gm*~(D9G6T1 #1 )&Leg2:"bғ9}TMqDҜv}!NFػuH'xvN:坙VɥcՓ3 %@H0a4, 57F)lC4iLȕHpY:=+ObU=w(j Vz(.eޜp^ Ǡ! Nÿ-u2gip|N?@jZM<߬g(4 c1K^_^7J`8> ʶ mWH_€.".! w<4Dn;@SܚģʪĞ䕡߽lAV}BS,rbW(Q,MMhWXWi$?n( ކǴ k5U)zG墅S=Ϻ0j%I&46˷ɧ4$Pzx ˓7TI̞yP?K~ AމR p8خw{U-t:v-}e$Sb/$ |)rY&$[nA$7.5F/zŢ" Kq3P -Uw䕩O帽~:;0XHD+]Z>k߲q?o1"s4ߘX#3jn2^1[*y;@G8/7Q$f)ӟqpv(Ԟ:+faFfxF(@/T7*TF9U!T_UY:=D7/lJԁ slCU#)#TȴH#6"v1ؖ We–pM Ȣ^K%`'7}3KoUQzd U/5ؐT*-uC.v~0E:N?߆~×0GY[]&n|y9SSѩtF'2ŷFxY/ ,鎣H>/j`\ f-An{#4ΚTAu 6h> Z:z3FMŝpJ4 s( oӾ/>+ɄB[/lU\)K7󧳎Wg}ZLهCdl \X+Mr?\4hK㢀WFHl&$g|0vaQX-3H],]Y^bqLy}f-jlR~n EaKh2A=[ m ]6Sy"SD\BE;v@ZSWoqˁVHARrO&q>ġ**`gSEt%^-U` sZ|\w";1UDC7jc?gIlٗD\ -fXtZ^c C7ڮx}q眔ofOm])7p4aP-iaUCFBh9S_xwVT Z|cO_"ֱjdyy`'8'@F>^({} toܻx\C?K9̆RiUBhVjzO`ޟ[IM~ϴs<o"}~sh>_hXsJ0(⎝J3/jhEӯ4"DbHR'1հWbgvկ$Γx)]] :mUeȐ\%* c@`#ox0.3ֈo[?w' Z]mtUas$D /hFʗW쬄P?`yVM~&lik!cR:ap6"1:zjꗺQ.~bx)w0Q.WrO,ZY@? OB#UUh%߭XFl~& 13.C3fjAEvah38ޯڋ*J-S"kǯYUg?O0 Zu.~yZ˛ֈ(Mw/ KzDgJFJEL`PǦi1}gJ`Q꫞BH eX' 7)?ܐM'8ؘ}?\#Bҕ@_TycG.$^/|߸lh) ܖi' Qf9@'4BXm0,]'&r#6dAE B†eC/qLs')o>p9nS{"KD0M(~\nڪodiQ7b;ͥ1P/ {e_GN7XVR眗[u@L[b -˾&D)| < *4_5Zd|D-lcF'N)An\Fܕ=lԃ%hCEb+,!qBo'+03l,W8cm-Mo{pkaYW "%(ᖏQ@SS{N]w*(RݕnǼB w^knUهqaJhig>yd&'{YٿO(9ԥg,;xK)#lh&bS j܂+~X{ZݬB"T/9NIHNhϨ2#v I*οJV&Df o>-er4L_ܲ(ށ&C?W}_W02ŕseg^cн׾W3nGz[f̬{eD[Up "3լQP!ȁm7WhTrIp̭˜C83+_hi*ĥvu  'ds3~b93p'V L &x:11o0^L?p'1c-.7xNr>[Z@!,^K-Oɺ#eLY\&Jx^ʄ1QR^T E7=0 cRU dk'iNOCh/'"tj|ZXw@*^EfϿDTP5&yXU^s1d)EEn`ּ档;ڠZl90R<Ԍ@`wmҕ1ь4 WbU6bjeHejPQ6ckf`y ΢~d;I?6n w[S &y*M{0kpՍ#s.D9Zrn0F=zxt_9IX!1%7+GJ`l~ B~FN{m 4SEQQ#DAn! 3*lb]Q8;gx23НZܟDıtGfBs$ `櫑f2p~M8H?tUД t%lP˝SrpFиLjEY#raFqFTqy:>, 5&[|>,LC ܢ nէ 7;pهK9:2$e] F?dx<uag ׵sȓM#jz ²P:P'zq}$aLS'au- Ii. (F#4SzӰIg_ &ƆeZmL;g~R>>5 i2JBZfy'.b!ip2ZV(j>(!ș]+Sd O&?ݩ?jcM7C9Exi ЍK1J|=H_ж_ZXEkẆ$]HPNT]RI2 ZrRj-s9%@rt'~!M*U37bJPEsr G W;= Vdm9Mή3TcrL7ej?Ƿx߶irQeǀ%-9[l~$@r@#Qw'[U%`!r5vCkYv{bB|9Ku$0D[;6lRrkI9( >6-]K 8DNtk ҲCy^}gD+Ų@VqGԇWlhi6AnYꜪL:1*§xw,uH_sCFE~1@N6mES'`)b@2̝uLx.#&<@街hL}<8"WN_ћ2Ey{9 ^(͆a>-(p">E.< V"y >?UV (IQ%='tm]weG_73c)=an)0rBᯗ0t3Tȁk4=!2t`v)(JGތEL!=s&'LVѿ3:ՕjulXWCͽ JGQڞX_r?ꏀ&L37dlǚߡf^2:k0*4mǸԧ Pa>%9Tz8@*Dq~a*Kw m]N~m?KB32X<.PA{;uJhЀD"J&MK[Ztu%_[{*:ͩ&U7#C@$ݩ>~?S/ORqvga/{$ek ,&e/U\HM}4Rv^]&h5Yk MR0=")2T݊X:\u^cϰGgekN,aP\pw2(_ݛC 왷T-y{ǧ_0S1uƓd/ͬoDxoD "BFTB貯9[uI'gʫ}S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4HoT8)N2:,<À$ x_ʼnrT :¼h"=~C#Ӌǣ Zt3auڛ}qn\<3݇,A%DO|:ï|vpu%4XTfKz]luA9QN NqL4jN_M:XfZ3{'wyLd1;v"bKik\ /<@93y\ԍԵ0k:&xuHTXoѢ6E,yc6Hwy#KhmQ8KGݖ|xP?P?V47ݩX)dE^)}E-ʐj+@qvEtbȅ6*L1G))lTܤF%kT+*GDQ( Ѿƣ}vw]J?FC.GM!گP{L {X=6]ӸH'ܻ`vuX?5=#ԴaO X{IC/ .!3ӐWӮ P3_!*g"6vcRwcuI(V: `X&'ฎЪ/,(B(cwRBHʫMb7=a@}N!n 6 #n 7&t=1VCEZ/WSN!8_1]܎ڳJԣC2);}2$ HeY>hݠ6^3=Z2 ϭ湉ha`GpyWSV(l{@@R50:7ψ!V^` >pÌ4%_nɚm 98rjdmf1xXBjnM[  ^ْSߕǦ^n<Vl[fu$rjTF"59xwέB,i#Rx}3b58IyK_ފUdN⋡|mo}.GxE2jp$wN+Ha) ߋ\r ^_;(ro:FozWx'V,c@`x̗F\K⚑&MvrDNm۶ٗIHi^%?y9BނH}񲶑eFڈ㰝ۺkZ/g+J>A"]8I F_ԍyOo!fΫ* ΆGc#N=S9(B9aJi讇W|24̉CHBxf; ҵ$?Ƕ{Rcʞ'$qA$Ow>3j:kқ&bnH*7F=8/A,kwRWA:"fw.,c(4h^|I~@Aq"R~/嫩홹X8r¯?5xUiDkM9w~[-7} h!?02p4%jVZ.Y8OqD]jƫKQT|ƇWb`c vb{b%7J/lg*{gr7d]= UKtMr @`su8V#5 !? QTHQm:ѽ="P (ܰdR!؆.mWDQcG>q9ߢB~*jP tR5WUؽAKUPY:*pTve"Ul| Kɍوٳg;GZ1YZr8V 4{o 3~tISIٞf ~zx1/\|O=̰ 䇟mZSy oS}Iem|6ZWT Y΄ :‡o]=\L*߂YJPT=gЫ_I[K-,z'Nd>d3~\*\I%ukMH'x8Pt;!z_ǎQB;M{y3Y?{504vq~"Υ/߼ud):R T[ѾChby-Qb= V:w9ԑV*0-Qሏ:r4q06D<X $7{ZR~%bhʀcEBMb"@TEV>r<dYx"vL>o+rlbbe'L<,Jc,M(BrVΑ34OV>%ԁYEY3b= 7E1֚l{4:$->,;ҲAK21Z *< #,7䒛}_e B7tC>=yЀX^ gc"KCBy]Hyi cyf-.wtՔTN9?'LIV[; =%Mvobf/Aq|ﯻQT)/z d!7INowW}^4?˅G-p|ee.10:M1jM9gT O&1T+`PdΈ<7I#R`r.ttk/B.e6vT+rQ]mk⥟ 5l ;G$~D]wB&v_~gR:*oѻy25>cGA6Z7`'=w*p7t0>6|P^ Cجɣ6ʞL;_=4HP AơTi%bM=aa,r .|d &w==K3twh|[x}ɄedV $)jX=mJ=#T\ZxU=xͳl&KIL"]w8:qF=1xe=(=tJߙm[Y`WI䤽&>#SiC8}ȭkYW*I  в]sK#artdX# *[$ u<` Uf #y\bG2z7iNQYz(BZ^5 +-SJx"rbÝ~6 QjwN*eԗn(jZ۠^섢hIHD[(gtf_n9J~q5Hwly| 5'Vs?h)33=si*oz@-#&t?V:H2.x1^m ^Qyh1TU89.mzW92Tgj3).r Oqg 砷KU{ϣzIbG /^}}[f-"[3[_%,92f&wz&zk]KzWp]x_OJHGψGZc( |Yhc I:DFq|Y5}:i1b^[U\^-Y?9$%C6TUf]G`, ֋(b0, iEzWGh5n-覾Jjj|&W}rX #8Y#~&42հG}T SZ2SpZ1pg=6KUd6c'ʘ iL:=@faÖ5u6.0/J}әJ|@:<,?V"`z!9?}?@@|j@KGNf1פEt=.*?YF03-s8<|7Ionޅq\3Ҕ5%>+:By@,|GQJ^0eUBwuzB)  3~W|1R; h9ղNO3Ph"vn7?_QP4t^SmD."?mD4{P% {8BEGe_#i:yN/٥I=\6䊓Nr+{-fBFmOOg=6 MD 楊ˌ3_;#T5N]S<:] >o4x7]4na)$ͮI;(|gT@$NTQ+c|>?}m A&sVFN DMj"y,X1>bQě;-KZ.H3 / :Dx9\](Z1F= zב^p`o?b Fm\v{5pVP;BWx捊'=rDϔЦziIº!{]o5Py@FkJvu/Nȥ l v8PnT|۾щ鶒d<x3مm*RٱF.D5i!66}.>cc[ ׎ev#=dRK,猜~ω\20ްp&Kt$h 䁡 Guͣjlq'w H UoFZkIEY ! 2%D_'vz3>`p RXHg,&Y5]JH7Uՙ=撹7GbhheYZw LI:ҶTۮL4*'Zz'KfJD\8EZ)ibj@ }V eſ$Cnnl,c+t5|̓aN)2*zQ6a=ݼD,L`X2 6^j(W+}R ذp~f晼]_Nvo}Rޑu9/9_f@HBbʧr嬝ָ.(Q@s,Jgu$ .ƀ\D"Tnb7Ǟܨ? yhDBm(1:z^I`#wikĘW@d~rY%~m&6әv`e7a k0ocz[/|bUz;'ZeR#*<[5p ʔ`YC#kjKt4&߃*reDŜƟ^2I]Mp,,9/YӞqߕV4'֚}%YWrL/siT(8-" ѳpL>-34 Bl@ٶ5:K7sҗ`‹{kxw{qj})spHhNhRN\ZTpIُQAߗ8=mObQqxp#^D/U: cde굍zLiL9mȄ wNCQv!ۊ8@˓M4/ƨԊf Ĵ>@nm t/\ߦ@j)dP&Fi̻zZdTOS C Ǝ^ۻzM_?Я= ;}VS&;ڦYo )AG1 Sc=uT?d}pگ*DFY6zrdPbptYB=ϩH|܋\\oWcqoRF頚Ҭ=gRDbf9m 8Ekyoc0jN\n%)$rMLHJYxrNYUcl*qE>x- y TXCW1AZ 8T0}1.2(B@/Cr]3iJBg q?i܀`!1";`3^xVJ2XoKs#q=l/Q"',Џ_r`PDr12?H z ǖCpNmb$2)iH8q `[X&TG\ .% r0丐͡OSQR}TOޥ r|}6P:j]NFg̍ s"u"7xg30=Д #Z}Nkhaȑ=17g f]vI/)^ߌszQL>SPӟGM=_'1JKI:_Jv'S A{}cv )hiDJFgb}vE׼B$^r-4rDJ7RlwD* nOG@-=5`R))/9Jlh2!,onAnp-҉O~:}⫽tϧu{ .[ٛ0m8n'9~B0 PZ+e\wq&>dsQB)@7DTQ$j"T|4]au0l|.6A-\J4z!&m=_=/jK'n v6 gPkF Å1Оʝe % NfY.@V-J Dv'o$qjvl4_dH,O5 {_YNJt5Z_?|l޳%?R+-VϔGz!(k"̫A@MԄ^|g7_>T߬`B=2F;/`MƸ2 }-؁ !#޸V>lu}fO\e<IS_=VIy/!" 9/oިI.ly(RHʡ@cL$k)6Yj[8CDWgJK*h`'ǹ!LaGKAFҵO.x'+(gfG֕fz#fprutNJBYp*||>@ |c;?FAՔk|0>4Ppxq: ~SЩ/YSrW/|2-vw`SB ^mx}! jN^U \E,+dj8F/y|LG@|w r6wS: zukƣ++Iad`JͅN&tF:2b>1Ο<4%|룬] Y؁qo˩0okT  о? הݒ۞#7j4ntkeu9lf g?k¸6s[ifOl_#ϩ'I\E$. IO%!Ǡ;Wه'*?JUӷ[_PY`J*Lo/CVs{%?ȭ)ŵYV0쑂yJ]F&Sؖu_+dD}*nx5¢N|>U}pv>mV\79򻉔C+Nd1* 3 K))i- DH3@?ݠD1T t!gw"*{7牞gWZc~3:/bB>:L4QcbnEAx4BBИSĹy*DΔ1;`!.q4L*7KL18@ >棪iځ("/Jcn;N@Ӭr靬b=a*Y.N0 {8vü7^hN'm͂AȠ:?dqݿ ΀m%qm1J{,\Äxi#9_'`{ qNRSDf3Ϩ]Io3kdʝ Zg8 6_p;hffA Lkɣ8jƜh-wfhފj]Fa;cx/<{|#.9\q1ys(;tpJ•h KXP1)V\˛_:%b UuG l p ;NS: VfLʊq'g\ygRy(atǀ`.IF~^λjsӠ1*҆a*=kKOjq`Ma3C1{_tXk !y{@$SW~x=1C^q槰Tw9tq։wTж>(В R+ښbZ pΑH wx}K?7ShPDW$Ԙ3fsE`\l,H\33c)2CfcOH[eWܨzp!tNަ$e|V{/0#u͕f,HL[+R1^_l3f`A С*v[bdJ8! +jT#-Pa4) =4IhZpQE҃.H+Q`,u:5X<[Kw{: cm>\§7i 0 B(wEP!g./Ft/ó~qv X~r-<=HzzT`8DHv ̸Łͫ5.Jz~N>S-sƸZ@VN)y'oړ0\[<$=gsXfVsD۵[?\xqa0*;=!:ĉZG*Ioh޾7?NC@i1ؚ xad%oKJå6 '6&mߌ,LC>qBkeф^ύz;v Nd*F˯:@>itASU, "l4 ė{fe[iDa8Y݃4MSڧ𝅆B2o]|;nNT*`GtA.^ P>{N]ϝnh\ #[sfyks 츻I]Q(?藄,3Z2_[\i$Lpɚ] NHf~\R֤Vqqk{ `)_|PP-z߉_!9IçB` ˉ~jR0TBRy+R% u*T߄qAn_=hz8+@/iUfg-t\Xm>nI=;ㅵN5+ w8_*]NτOams+˸8>]iaGˇL=샮/S/xٙ\&C 2Ƭ%LZU/9فXh>똟i>OB+<$UFG2Eu-&@Bj?XĂ |N@d>s?}<;h|rRŞ"/qZ0blCq ЩNq̖avi4(Lz< ]_0@2Bx u[w`/"f9!Ŀoi:#J2 I`bȪK$~R(]wq̦1J ;܅rl\bxVQ{g2"=b܍!ą?]x[GW϶"ݐQm ;u'iCq܏~"bllm҈ox%hE1&Vw_$ٰ .ۆT-qϏE翾돲K'7f=YR!wH&_z|fvTKĩ`Li-2Xrc@6qvW҉0fTT7:C8#ޞ∪7JAؑbtK~+7ĭVX*밻dBZAqo]zNgNJ-`q`L40lik $T5iJ,2:;;<&ҡەaԄR ߸Xx !FGپsS訒d3~RsrN,}Q8Z,{*7T5+e&DF kj>^!#ùTϹݠrzMJR_[p"FZ]Ɲ7qf3ҳ'÷VS? tvLF7(onV;F-#<,MgK 5g[X'MpHAl❹ J%7(VHؼrYǞ)y)C&*pѨtd ˕}$= ]稓ILw&e=3lo y3, #s~e5p QB>"r+{fdHJKhlhMwmBIe,EUhq cjEMgWI R|#7R `gc#!,yF\ēzaͼUz|[T:дE^쿇"鉌a%;z-}cLFc4ИbKJy7'=~_;AM:TܹqHW H]rI;[j=rtb>+8VMN{*u7-?(ׁͭ Ž=rT(N4]WD2=-WusI\ C H.LoVks".2;sFJP:IS] HI|5gP d {M)Iܬ @O-D#G.5p7V V'=3n~桳IJ[/nS#^yJl97[5Ycz`Fo?6q'zc%lΟ y[<I{ ~ʽJ TN\:3%teױ赦@AËWqPx4A I] t_^jF¿0&R+[Nl>gx)P)K<(sS ߅U)#I}K=9^yI[ [ ClDuB ޸ٞD*=@/h?5"+5VhA 3dEߑXfwa:@[4CFYqC]xՒ-cak`ѡW#w6/ل;Ky@'2u%ЛCN,u C] 9&Z[ڊE&#tDdyN2lۜ%:, `\h+g nF,w@mJ5P45 1m&'5i xsG4/uLGpHCF Qr YN%te WćyCmŬrz3mN2k u?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4K*S,vA:,0_gp"E:>Bdmأp. h,23N6kAL`lí(@$4]0@[dV Yn\ 2?A`.u!6p VuW7GWmԐ]ՐSUL5xPϖ|R=2VJ-m(}d}Gb7< 0o%1l ]П&C3|u/p7"7J ГF҂A&d?L὜!ߥZ|=4`xoii{lkU̓2* v? m/{+KR%LM vI{p_3d3a%TKU%[m3mBz>x|ia]*zS0=݀'Z2JvGI<8:87niŜWz?? O*X )~NqR:q |k>b3s@z"'6*K@I+]&N9=V@fAIq#q94Oc?4Q }p W[i`Ws-sӂg-|ň5X,<4p k ;=Es|K l1~(N >!'˲D sܺ $ЂX(IB !m+)ϑ^e{)H6Q1~EU_o&P `|NJ'joؔώn5jXZKQ~[ #uQ҂, @xәSvЃT$<g,lI?YVv~΂s хo8Y~Er@7Ty/7'J+:Ky`ׅm$SߥAbE8-sXm\^&H‚@VSFԌ^YÔpV ˋ!s[2*O9 x/j\($ebaSZҟ W1lIw(@uLm&jQhCEM %&f!Xo.~Mп鑀\G; Ÿ}YΪNS/OG*A{ LPY0W؂zy s;9!uYŖ֋b 7A:#%8wN֗)3ii+ xC-+sѪT u8QlClР9q5/]:tNcvJRrTHBw@Μ{ȖL(+ zhi :A L{WaWCKͶ]x<8ʥJO0Hم%K  76R< IyA Onw}RzHZbh5 t $&6G-y\zl>հlc^%1V)XrhuDY7Wʞ @lt#~ @2<[g>uf9 ^G>ќG; -mXtE̺[һ+~~\$s:!OZQf'  IHpVS[1a&!Ee c`jd4Q $,]=\5_ /_ \!7So8J+""n#) *1JN'|H$Rce9v1Sz?sUx5ysd tBj(j4nZ3 Rҋcƾ${ޜz?/=*ݝPT[".~Ff5fWy2,N.AWـGG&HC c, [MȫQf˾_G"z]}0DdڰI'lz٠Ws Rؐ=UWq%=}ft´Qڠ>ȳa?VxuIj82eI+ܬ_/.K'xo!?,+0 (KoFgT!R4OdzVd}C@\)8ކpT0Eotz,2upG|7 7<4 3qFƑ gʧb 'D&u7R?}s |U:nmWfV6?WTΦxX+>3tӗ} ;8i-$#dSC:(v'!H so  c9,h4m3fbDm~17c˙_Oo^:1Ğa֮Pd3e7ozt!#rcVYn&?4dž2S΋C`Dw|sw^+qĿkӹ)><@s9F` ''5ILˁ[.(j- !7.ZP9'tc]|/*^2{DeM@7\cyD~Ǖ'JL 2Gm>3'u0aR!I<P vQ_dlGbTxN`07䅨t,hF%#uwU}wӦ'];HIZI> ҐlIJ3z,_r~y}?\h@nLȬ'Rrbc׾E*_yTҲyI3C_HuN7½B"Xؗl0 r{v_N-Am -rWla&7e14\B(`끯qƐGE( ؊*1dܨJHd5U8k':6$&(iܻ-I5p0h491@t/ϬtVnc7\S20y9~&C*w^~K'v{1`iϟx{bs>ZOG';:M p^F}vǍ0Kw|QfyhL%7ĥZ8\$MhrVUlK1aC ].(et҈\^ZPoI^@AFH؁̚"UB/_=K9.6"b  Y?we<iͮ噩6Բ oF(0w+V2Wц)Q7ndҜ ۢHP -:x0vǶt4TJ(a6zR7JwIsԲ˳RۜF}Rv楖5,ia2,q`+'7jz:G<ADL}fn- Թf/c* /{˸@ݣχ+/: mN6X5%:7JksR ,y͛ )Q_`me$70VE}REDZ/nSW\5zUGĵh/&q\?ʮNt>?bM_cs}F&VIէ Juwv}CbCbNJՉ-6!;NY`e^])'F؈x\Qf98OjFBsqnU" @q#M+*\he^u_*T= ;@SGFrbu# Ύ`BJJ 2RŦF￉* z^`Ku\^8Lm_ ⾖,:<|6j?`!36̑||P` _4 asQal!y ܸ7/63;os qursL+CŷKr 6YGh~6ԡ5u@i|?__~28^.]R ޭ_"*~4{t}4A_RJD!9A/ gU]mKh]]Or|Gqn.>6:>R?1] 3gMUƓ8S" 7''S ` xM-P9S{}"x<9f5] \_lR"׀ߗ霠%o2֤֘Cvĵn2 "P^jK-22F0}C2g|qͿkwܺkق?nwqLΗ_忚h|zrm 1<5bߥI|&ۈ -|x1jZ^֥WDE3_?7*{? ?+#I2!BӏMoV'A s g^MQ2\.K˻G-,3xKO` sWEqz^abV6'^4#Ki+J8``  rx%iKK/,5rg`s&-& ~ZUl:2N%?Ra{FѩGg)z9?})Q\];~]xhsޅI;1I\jKQ%_jS]$Y#. !%a6u%"cWqR݁e;Dq6D7rƔ9CQҥx&:X\icrGQVTbs6wv@c֙xT ЍD1<[618OXaOĎʓ ڙUX_Ogn">"ܛ7e6~ X^؊46$j^FԸT.jU e~I y?AqԚx/v;7Ɨ){M 1-3sj.dGZw''B-Y JL)PbrpLQuT^( ls3w '4rVڣ 6!$~lrZ%p ϽD}_6:c;O .yn\}#Ԕ.;tTN 0}B!ӑ~E_߸yHSn.P(Bt\,byj~ىJvcWx-O<݃Ԯaj8*]ܡ^:/K5M9@5r D7[q:q<9aZxַGw\{3ѭݹVFS(B֜9RJ<@3:Sr] ; XbՕ{-ysz&hox-k;aݳg}T o &5ɾwĒFˬ3~ WA hF$|C+8Vyrvl L*c TwAR-ugcG>?= p![G>HeSu{$s/.v~á8~K=߸O:&FCh^&6ΡT;ð ڤ &~f Mܭs0{MaM\ i\!0"WOMI$/b ǘ|r"I8vj{I9\?xB+U6eŒAo;7<˥&?g (yӎ&<q}.;[4,(#qTDsݩG0SRNĮ,lyBwF /I J Zt#o?t]Ef\hJ{C²&Us pzP(@G$ ⑭dLsJ;aBdz/Fe VtgNgcl-Ӈ@[({]e=R',J/2'/?:m9!I,5+X䊦82AV}]=v#NWLUUuaj/"+’%Y[% :Dms93Q]%Xg0ӠY)`2( ?5$1`[./#DVo\&S4/ 5YJQ_QBEƥ4Z JEb,KZ?j8wK~ꢇvQ]8 `0uEoh(b0BPYhmp梸;Oxq@yS DI6j?/rdnB|Ҿ#8*RR cSG2ʏg )pê#tU>w<lYs6kI ׆M~ybn*._„NGm3Q92v5Z,ьKP \YSxt681Cj_-ޣ=JBG2b<ӛ3H 4e./sLgdR[U)6+d䈡C^M4 t礶i8x^vRPDu^ق-i?:h2`T׶1ſZy, d|a^MXmd0m EdiLD{#йhEHwGGRR@[/SZgF࠙dkCtpnw~yZcSMz6-L2rޮmk*'15 7Z88b1JGg= |α:U[ځ{JyŌ {ĘWQUZee_j>5K]/Xc7+P!0Tɉdf^ rݻI7w1R%UN9R;E% /K7fL0THpv鐦 dp ^R' izUC`k(gIRbj _$d"%;x#jЧH+[! AIDVY1&cYT1xZW)SzW ҏnbY.YK/"\R,$N\Q*> +>0o,J*Xx7 _RX;ߊY˥c:hbK eDjYz:~9:݈:C3e8u#"GJ EC:*Aff則뿮R)'x$.YT04d* C#lk|79`)مl>o8;I<=NlNkFmK2᳞m?:rU>g+/>+x.ZCr?ta۰4jTܔO*h'QM21rτBs]b]^̫t\ @tjv12挩7pE&ZE:5ߠCTs,e#|[JIk'zt`>6eab:G3.!-b}*B{aڍb7scOaU>BLP,ۅχ; zb*AԷG=0vS@cZpcnvL!dt>!ռ #cl4x1''ija:J nЯKدk:٭R}D4 ;'ImKyId~w,qoJMन$XuS'ÊY*8MǎL/|OAԸ_sQMNRS$h29t B5YF\=ẗ*X-G{(s|I)~LZD1g| Gx 1Z]hFEo;w$I3] Ts(KZ`O֡ E IW3,BEM7H"RFkǦd<nS,KLO<*DZ-ݨW>`yyo4,䯮]R6RNЪMPDnG z&B2`_C+2.:͌~sy-/EͧbXG>(27bLb7䎛\*dS(5 RߤKD4sFL8~,G{ liy|||bv$4>HA@|i\ "b M57SSLEm# H-߀UGּchdOj#ߺ/IXwAF116^%@EM%Krnhc3Ä|_??]bD`//t-I__ѫB h!Kpkl眢4pj+"]"?y,>Hyh(<.^=9{%c~8Ւqim'>7YУ=( TǣMSUzOLs),.~L?<Q]9{׎%EE#=KS꒏rZ݃tǍ}wޞ]\a6kM&tra RU+*a: BkO6%\ns0>|t X둴5n֋lٸ$_cCCY:cq˹'IvTRt?LO/\rҷQk9 W0KjKLfۄJd/e'UP_]d.6̪W\wwj&U^Ϻ&%? u1qXy^fF2VAsr 0h(3"S&ɴ8)i4`zdbXF$6B8xr9a]Om12u]l),Ys|E#;gXSJl4Lܘ!tlw.5L32{WpY3ǛJ>WMd(^dIh'rWug\[ ZtwJKbm?"NAs.Ti~B t38,&kl.:nPN&4T fƮ РX,5. 9́Rۚ-2={f4iCU'p[v&&`"{‘|gS&sy QaOms6.덩o+ZE.*Z(e)}W]@ JQSv%hw~&- *o9J%F>7O%%dӇrhD t#S>ݧe):3RБ=̙( O܅zXFs^qRmhێq9!$,[VٿV'ZY=V4G>-g?!}E%`~{4D_~?KG-uUod<]Y>5)F;uf"d4iڴ=S%@'%urL` +[SL" w]}t5.w}ʿ$_;?owR.݃c-`!41DHL2َ8.Mu:0,ߟYP6RI!Kl#ɕmIwŖ ~sxJÐQ6O{!|O#jt!gk*@X"d`JV%ŞRإ xc8/ JgZxzض0,BXn~#Pi&$6HxG%1qjO f}6dpT5 ]q.HOiL|E(L3j$~0<_b3Qf3vȘYlrV:>,zD!Nw⅌!C8`Vj%F^hr-6zܼ6sf@=}FwU [71%h=(_(*ٽ2l\E@$DH۝ gHG8"Hꚛ3 X@j`Zjp1^ԙSݘpi0ʹcv>1:%qЬ?S>'Fb & * TnEk_6"cK4UW!gMT<򎻀[?# KW~Y};F2-۝bh,KkWdqhd ?W&YENM<.͎и`[Z*¯ksv]hX ;ņ{)UBgŢc[GbsK)tf:!p*i3lM b9Fsto4 㩩AW]:JDQf#ѣ"Øč_< FZO, n668K +[VQռ*fw,#dm$]WpD/X,/=r/\&q 㰐Ԣp[;U9UT&ÄgLJ7q!~܃@/ݹҨӄFt|M}Vs.h16L"^TzDXX:shFis9p>B\cC꽥7t̕zF!T*Ӱ4 av]b;yx@*O6qү¬Zmٖx9gFxuR?NVc)˓KCI-ڏN&v>}H. e U<ТШn y@b0B14 79F 3m.U΁W4BySj3=fH_l;Ic2y/)y\@70gdTY99@gll0[W4r*Jwz.oo E)\v-5ٮ? ڤCO{7o~v[ oTGJ<=odr~'l*rlOxoZ!zOc [!LS5J]}?"(' tX7-1P5n*_[} f tw[~+(L=vgGfV ~FiTwxi]0EPWnj%pdUiBzED~G /ԡq &p1aK\4eA'u搨&@@ |!w&<3a#F/eI&`BF'pzh&IVL]Ũ|b:MIdd99f :E0#q5.U@$}ٱ$Qn h_8W#IqbRÇWvb[6dx`$#C|Ӹ v?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP02/<l!:4@8"8?Zxc(ҹ9Z^>l_XB l 5MD?6qqbXSS).77\I.5 |@> bBWi`iC>3 :lV@țDqt;1bQV*v?,vY["%}70Sic ~a 1VSF?k0{C8?Mie>؉hիB.Y7|:k1K-+pO54OxsIUGR1?^f;<$K裰9ij+W@= 9=d@3|7nGw =(b)Y|>@|>|}7m gWfӍЂ~xU `FAatƝ4M( WNIX\*}qYdzLqǁld|,_ 8)Y82Zam)Vkg?_S|=+>WA~OI7߇3jź83_F| )7"1`qKK9Җq ـK V‰6bEHN7?fB9|:y37V=]Q1(50Fؓ̆(`ph_ ΃E'Zk۹|,!$ jWe,aVtL8kU}1%4kz8ݑHؑLegܣ纠`w>!WF>?5z3F},8H‚c'xK~. 1HE{u#% Y<_=x+tjjH@$5[_A-D]JHol:312> }=:V+r8 lZZMQsifrs(>G8,rG\*7yc|VC1h6n!mi%ͮmG#.oQ'm8hĄ(WJ-0sD K!?˂ xtVU Y&ª2WRr&s;''ЫA@}CT%f/_.Ъ:vsp/vR5e)}la/zt.LYw})7qЇE!YE% 6 c( x߈4"[mwwekCUv.SN~- יlVLN1z:n2Wb;WkU\"SO)=~) ;9U\oWF/Q:T́%lT|S/ƃLtLr|oLQ= d~Fs)|,p*~$Z?>Z! $p"OBeS'7yzW{^s84[;: 7( д *Q g5V:o ~3]bꗧkŮԅH,ֺ(qF?O*D>)aAqiXk];G48P?(gr yb)d:M+CqMn%V'M+N wQ?晑$ԕ*n{)3X|[)mLݡ 0 d7Jm+_hi!/*D BE0:N$bNpƶ|5})] 5hN 4tfPw V*)Qe<\n@7WqFG:kdWRA< [6xa>ƁR."VNMc0&S$%(.K*LٺNJXyKyze_ Cw \ 'ƲѰ3jl/y󣆒]jDY' ϗ"{[}R-QF pl3d 7KZbGyx: 5\?3o[(gIGsi279An)}acԼR}=vy}asϑkuNx] Η|k薢wԲWqInsij'`\FV\F {,ߗ>oR!J䉰ǜ 70ObZ˜"(չI9硛,_jyn|'~`p'nf HZYfj1-mzk#jQa %]s7tuZ8;hn2[/;܍0M7U|@|#>^fG4 O]&1Do|@||j@ OLDBu| .]g?ϲ6Ca{cN0mg!iS_AC~lS7$q#Je{ץ+.RM7L|lH|z :E}Na^PM/b HȢvo>z@|v>e~{)K{鞕7]5_ܲu$b$\3m@Mm;,h#*5׹S :sÁ,ACnͬM|7ef8ڒ@[nA&Y[̟" z+w@_{KӑơXh*׍3qzP)3 A *xwD.B~>c !>5חJZd'VtX>z75! !_4 Ɨߊ$'ND 9Z Ŗ[gË]|>q}hȉu44XIdtv*mE{`.{R6bB&GrNGͱ7by$Owb>s@2ʆ57+V^ 7,EH%]A/Pa''0KA'M/*# JŚ3ɲˁ0<DA$˥aLT`8G1˰kޒa^w-3)b) ee*KB~z9)FM o5c4<)h-%vNfgu|07R*q?~\53*H~uNUA*`:P޽OZf-^!0UU Wdք]_A͔_\c[нf n.l:9 VC^U&>jbWRUDq'A0J9Xie4*{ŞJ}[gJ g5,D:5lT7?8'Hs>2폱Զ2-Kl xF󪒇HCls豗-OF%f< .iAb˥nP`1j  g@DŽa0ޚcM 6]-ݑ}S^gϪBdF?_U1WPqgnH i\B-7Yc ;2l@򬐄PJs't464\ x#) ؉eFO(~X#kQm=&#q"-# ߅ 6\Q/u⽱LUˆӻ]%9cmLwx, vIG Jel ]EVQQۈȑy~oD!5wJ_oApe@G8C/PVKڛdG#ԟ7̅ʟ4Papi Sz2NiI%a6QrV0[@MZ 46! ۾u*JkX7ےΝ.LMm>ī3~o+}ד!ApvmFizPA{Rk!L# մBÝ,Z+4fX*՚sS#夂16u&c3SZ,g>bcק_%2ǤyNn@L^*Ο' ALTpfuH$D%ѝRk>8 d?a\zش\[ofLҏ?dA N &YsSWTY}%hʻ,xŽw8QPuWPjvK)[ |1;)]*YqOUӁ_e2ŅtE dr`2v9UrKQYhAB .a3+C?"6|\SR4$s\0:lS]]h@ƪil=^E\C;x~S{6l<Β0LĖ?qGx5)ds]Nj(~\g[k&/d6]!ft 8 5Za_a:s`v峪X*[t4x%h9Mv/w["=;J9DЊT%(03n%)IC Ѷ'Fզ>QRk!vt07Z!vf*/5oW[F liƽqwqAn^OPUi(UΒ)p\!k_.DW痞>C0w9i,jg/u 1ZAB;niV Oo"n'ݲ+*JYsq 0B wBDŝ (M?~6b}k׺yjaZLqYpc/j@ r:̹IGxʸeVT3YMZ;Aھ?wI@C*r27e.[`HXc+Q!{3S}\= kupipCȥQN%v,-(eUT/T3`2fQ 'mM65*EBgR ,ܧnA͌iԻU| %ö-`IէKaᎹՁ#N}q9Lj]QWİjuB 2E/E^)ɓ?*{Wxq QvA6 M`71X89Fke6FJ";y8W%C7X> 4R׵q/#(  GF8-Q4=Yj _Ï#B~Kˎ'2RS@:XhяqD$Zg~E@J f-1_HR_͘R:1(6(bp"q=ZP-(^r$mњOUH_pT2ǡz 7pP+쩎N$lhb=~yuw Uq@yJ^8&OD%vVg7b]T1֏oۻD?݄=qƽenUq!fI"N QVOC s! _b/("jёEi\]A 1DcvU8x  6x_0_c2|ܽOz|jv%!V`˧.X풵>6A9L#Ysc+P']>2D)ìywn9Q."hFtgP9m{B+tGW7&&`mB&tqp>=%suUwJ'ׂ4@;}b-.)U1SPdžH9/,QCIѬ[r)!>1]jzH"o9S4(:aSb*\3ˉ{=}T| 4:ͭ`JK$PHP]nk2o`qqrNp)BW"t\,m ~.X{M1M9m-:KSkӬ"޴ ŤpR>W' j\7<: W G?YPv!^jR`]7ܡ 3xK-֑\ sq hCit[h[rqPjC*z3 hV(|Ÿ~ Ds0)-8sΈn^@ɐt RX*=U ֩cYGI$A­$$DJ^ =AvE񌖵8˥Gb3[M$EYgFyY c<IZn!xa"͈XeN+GXePqV$8F͗R#d,՞VBP4EFOssa}cj۵ Z7kDot3\=33{'L.~[@W o *aZoXZӕzDI/:ڎt[Rc8& {Ŀy&&-FV0r>ޛ_]$yO$sBtwbϩ1NW7$B+]TchFr˅J7MTu%?o9C(dƼ8m$!f*tx#⒳8\0mNg9J6Uj#4&IQ'辝L|maTckZ%Nje;awj!0jN,^7rf}Twx(66:{Z#&:s )ПsA*= ?+Q1.3wMG^ `|Œolc؉U h_̀?#7C''#Ec^A͉< Ǻ뿻k >(OL'7WBAx1{&Ц2ȡh mK'U?&UV,&ê]a_қM;7 fT%_ToHnײ.fݙ~ N!WA5IBr= *GgUàV䠮TR"F8[f:z"S?ݏ2U7R[~z!)'2c'w~H!L2Sit$ڡ\a\z+F  *^?k%ue{MH82(ETesx\NrZR4F&7_^mod[xrm7>k ْx@$G/עՒHb)RIt?A&PW` Gٷ Z_NL/6$er~Ef註nѰwyl T&,$¨~0l>g:តdb1XncXՄ֧D<*m{=Zo*ߜ{*1^="dS3E;&#Wl} WrvdK߽r6 M&$Tٵ~gX5cQ㥞]FOg\Ip)6];(6~ )cD(jާ+2dX4`>Y%y;bk~ѮbfwNAE[jc$cU>|Xd < 9w:Ogu_~,ed s=^OVcMKzOV 0ncIs'$z0D!2)s<õ Q3ץS"&V6I ZߡF^k4)n'2 e+$7}*1o@2jb_#ݯ"*#lOpŤGd+sEqG̃QCXZ/T|kHyj??:q(UrZru_%Nyu7<[8*k7Fz{<$fYDcRJ*Rm]P9-X"GQ0Yp,b3_,m:X5#BeJauMc *N1@r@ٽv6TNgy޵r爷Bs֟|ݜ*j3e\{Y.y ; +Ql`90NA]dt(dsո Z謧/| oߕeݍ]ɕd]Ksy|um% y`N@w.Ag50./^Zx!$'#/c$y}o}q/I)Ugz87 s \5 Ƙz^#z/l> 0 ć*ܠI*TS "J+>Y}uȾ%;wf!Ȁ' S]aQMƴ,#|lI?j dk5:Wet'y2 >bY+dtLGOx @?Kz,A/Z_T(5q+wN$tRQ#02 o:N?GT(,q.oq6Z!.=pot:0@yWņ:mbwԵ%#-S=w=$P%fyʖ堜)t GS=}(Oe'@zXUZuE1m΀ǓAF8 kK^?8~Г`6UbtQb/=фФV5!K#WLBmO|/Mad`Ya iqzT(6KϦhjSÔ)yqK";D;JVʁy-Z^2 NЅԕ>2ݭ狌L.̬_vD*OpTs:,jPc|E>CozBay渪"EnPZK 1ɰJf=n;X'$3% 2„FG˻8 ĵא>Zڊ QD8O$甌OX7uf.0(:t!6$B1E"]ުrJ[(hVvvK'd0$5a`n l^Dg7NI% SA-;bN>ͦ}LSS,>I"4g>޲U/q2(fƽ;3kV |_͗a[Ժ#2=Ҥ*4;KFTL5O bs#coTGL^h6z[ ]R:7g&g%ҥ+(@Ybk 윚8C|1tOJ9W-4#i_eZ9WS ! ӶoSCf]FRwawKz4& zHc5n}^2| 's%4{rҔ\r1\TC8G\X w@MS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8JU1 P@8hH&S!E}ҿ:x1}=,vԟ87OL[M9_ m7Uj~W(<LpS~t`|> ]k-a0ڴYN ^&ځ,tSN{^Z2EY(W,Y Z]`7I`/npkNNņKۆ@C4ޒQ~H+NϦ5ID\MFVi:"YeR4}/XpcɑL&Wl♨0N#)kgm+ CF3.[:`#t bb62wH]Q$|T 7u~v>X"xM;(6צ2Ypk!qe_?ҿ$C_iA$jC¸<o,&xz `FVJUq%a]4cDO"~|Y?s}Wj8z$Q@渂VGPOR\QtDZ5ШAu*~aMR//Ƅ vhB0(u5Ib"Tf.۞7~)\NњT*UH};ւdb>Kj:084kιR|B{xS]*pfhEEV?iRm-DAWemYZ^(ޖ-/lI_f,,CgJ9n>5xz.]z(/yKRl(Pଶ'iM,ѕ!Ζ HOgVVCGT3zR;rGL&ҭ(ľS7-=4adh|lի^2/ ֑4%ӏTE-EzoJWېeIx-Nrg"yH5m]VQ`Qa!TBxّF̟_o̴z=;WxA"| -"_S4C_Wä_K~Otuz; :%HL{.i`=Q˞fyI՟3 ,U3Tn?@f{ҽ[zXըW uK$5& Hf/*{3Y!ȏt&F u<Mޏzf|xXiLYBP=#c0^X܄ XБ4{ #~ׁэ_\=M_,GMq,|ԝ2ɀѠ 2@"a6;oa(zۋ?MԃjI !.t.bIWv<16e63Fԛ76|7vl #}lUNIhLZfp;LIBZtۙ .H[n q{ʕF,ILgeOnyDvAXtz1ܘjy5d``w^'zU$1G]{\ۏ  SW'H/,G-䬽l% Le Lba㰯=V6Egu|A.R9=v4P/WH0Otg|5?b 3]1gy\}EW.1fN$DzVA NSA[*}g}s4OH R5n)6ZPuzDz*%N$ŶfmZ6%cgM r!&>*g]a@?nWþq]Y<ֵTJT4ێg!b%t>!"y ù.k|LW-.u\1w=!U6LsʓɅG&d޾5qd(wdjH?_^)VHļWGʙAMϕ謶z4kP6l3N2 Giv`c~O| кX0i/ܕttD!(l08|? b̟ MQ2yRi[޿[v# 7!rq, e&m냝(z vЧs8:k8@Rv#aA$fO y\_̀5+5-?lPܝ?B$ׄJ69oYqy9!/𫶴lEK.-yV.\k\L-VO0,Ov8 C ]cy'@# ҍuTyZyu E!7uub QIc9xDΦdc81]'cN5Ҝ1E9U"S66OMϖ?4Տ1TxE}!޸~>h96h+9Y xˆge8Rc!}$ד sPʬtd] XE0Hn hR"̋+&l(P:SBz(w&ݭM,rur\.z'm]f_Ǧ;V.`#w“'E&zSju\g꼣ʶz; mx\ `g~sAV?kniw}sSRx #_t`mQ6&BM6Brqg_([d Al5+mެl'oa$)p4/p:XaJY>{ b )9#bIJ?-15NJ<%1:y>aww4h"n̙[U͉5#wrDۄI>= ۄMSIZ+VH[ 1nlccg-ȵ>@:;od*8)Y&{#!z1Ȋh)JV_!l7h44o/?Ϡ/Z~Ȣ}j;vӰOjH9!GD.-fUΗH8s9$o0ec2B$H-a*(xbusU:3j.M}@Xי2:9a~(!i".9w;I{陰Fchæ=ym<**ަP(`F%p63_<:D--Ejs1YNQ0/}8m*+>]g mky eRY:l5L _'/'aRuYQ!Ǚ4a;{H܁ ݹ-7|'Eنg{Pf6]*xDw@gn"GO1amN7 `[F&O{1 jyѐt2=Xڔ&iMWcu7 Hg&tyMWa9Wt[aJp7Tnd%V}rZ)BuкK[YBP%>!?]C uWSo] DPŵjAƪp!$-pb(~F:ĭ.!q0 @a 8%ZgLj#?ͥ&-8bue]Zǚ($6at\_sNUh*S׉TZrTsvel`~l: ʥ4Ϡ@?fdpU ⻵-p7*m`P I*iz4=GOM.Qqp$02lyڨO . Y(q }߾#$.?Qa;kG1e7ZxyZOeweY8/LXZk^?\l 5FOVU"w$Q=@/cR.VT^J_f:{&M]S4'5TRX+$uƎ㦙w w=R)HpEXLZ!/74FQ!.5J0ŧ%}[遃!8{)KF듧ܪ}i#E0 };~={,A?|v<2~@dΞa"Cٱ4 Z*~?*;ekz,ծуӢriOἠNa׭yI3,U_ EG(X_/_)VݎJxn"[y v]yGtV9LV?*e0k}:'] 'd!?O.nL ֈu_ 7c.uJڮYI2ڼ~?uL=C]]w$ÂEILA%aJCE Y=',ⱹ(, d")u֓$JPaZa8*aV BG}bzIU[a_x XqbHXgbš_HgWe 0ͺ֙]-6 HJ2::^E`]U_#!/R>_s 0^7A$r(勅g66~a}w߃˿w])џĦqdw6^:Š&>Tg@/+ktrT %!A+D"37L PlB9Ldzyyq`BՇ75Mx;d`kokΪ("2 ߒ:6 V`'ڊ_mQ\S\7;CSbOLđ"6Vgsd5\# [g0͎ ]V~6dbj8R,̿ԇ.>4<(4Rl~.o6B@UJJ&<5HGf㮕͍t*lK" ŀU<iUmWoC bJ9G (ْJ@)pA@OEו#@pVpeeB,q/Q#hTh9DsIYQ1<){0JUUe(k+{؀&(ws|•p'K4Cr&~-a+6 h N\V:U;-G{PTH{ ]h axZ7*F%9N\At{ SjX䉤̌Fv6D#cYEKy\)"lgߙb?3a "xXZӯ>ƠQ8.?ՙ5 VFb -Y![e֩> -e/6SB%2*w4hoas E#h^)m{k3BY\q~?7"s[Ч\8,~.X5axP2^$hŧ:ƽNA\4G~}N7 ]l4O. *m.,"py[-뼍0]kx _:70v篮(E<⋰tKd,Peo}z͟ةTz@WzCwbC+vzgǙ@&Kf/Bk ڭp~OqgRAu=oR_ۣ>͙vc)`H̀61,l= mP0,F$:j?OYπAft9mvM%cQУY 7⸵fWpH2*5>(WKZN[C髬?}(!i' kd_N^/VpSp|A>,#/DWH3=d<:~aZyn$,§v :Iv", gĎ*X<;ҥM鶤i: =zs=0gp",͇01( fT[v_Gx';3O#>@W4;"8 5~5tF-0#iud=?|1trkPgHLZ_1zݍ:Kۄ0/<҉xҚ9#sRMz%9r dl? VC`׀l6bεsbY'>64J+aV )E04aWnZ Hު>OhIbYhF?F?Z>F4߂X)vaQÉߕ'=|fvll݅5'瞣kvǒr08 E5dwiJ<;ptuh10zضtn'O '}:2^;aq։L~`f wAzOtp1U޳_y,CJaY UՙXlQ%VvFt}j?<8 ַ_*-^y85=wu>^h! ].4 Ø |?3ޱ=`ukb@{[1(H]v@ۻH[ ꫬdpk}7 V t8mxy1[jwp80 K8_qZq^Uw;vo$9(gM~|H]<^iUtPWFԦc:K*ldHu}(hG$[aRF.ns*ޜ!&M+h/j_3Sڑ IeqE+k*p7B|bU[wjDn/2Y!mB(]HM[w'^ĻS+qP3D&bO䋕1VoP4/kӪw0 n? [a/VXwٯ%JAZ1Q>+8"QG<[V& rk>LR[ϊ-vAH^2M͉1vlX k-ߢ;LO32n l!O`{ 0@` : m,m2s͙_|GYer~u-YA|C~\[s>\/5Ka^uj6qgvA, YY>8r?K~c+j35l-)HRVo&`,SEuc7͖M"-gpNH>ֈN<˥qSI m?l5MzJ4=} U02(udDfk6(nx(lv|^(hX`DOkaK iPM(T #)ʫsfPU,]٬nރ2Gabpc(MM)dZHmYϵr@0x?'uBoQfï= e2ψW5)qC0\s_1Բ[RQቖc7cciCv8C RL2ˀSVW2b"yBk=fJŃS7 #FZͽ40ې2_?{u Bz:U.vJ۝(Vbd-/ dҏkn@n љ}r{`fT`b*_>=@`da;V$`apo/[VJ ZU#?|} p;16](CYZv—6ǁJg0eg'TD}XIO_$\[jX*/spHq+0j>Jy_@Mܜ:iwLdnN'ߚV{d hƌAL9Skrnxy"Ɂ-Y2jʢ^זby"tR}ebWLA1 s B5pM޻P!lP^]ux21݂ .$ׄ;}]ajRܴ!HWX/l{`݌QlUaW-Q)ˀ fħ|a,gJP7=90g? +?be}? }NqѶ2ƒ6G?LwkB6x:tѭF\=o8LFq=}^Rsi΀\gQ')6% hH7 nQ1] ^&"à?z|1U~,e7"&$(ia}`s s;,\ny1 7 N)#LkUQEdbE¹7J1Ր{yf Yیږ 4wZN2 irHt2BY_x0ĄuHy׶%xg˚N+VX/+CB~ m¿ 6 e/ad/9faXmZ;ndž+niU$zhh_m8C{1λ@bD҅xc4բ wp򌕰Hu߉<~zDsɰ䒲pGg\D)iȼ rvM[_tnLP+*HA*wҊڐ2(_d8^ Bp{uؚ&0_agfVQ.҈ͥZ [M嘯w9G_K~gd_d]H}6oda)*N* aO]LO@e~i- +c{i~@3;M[B^#ܖ^3g*Pp{m oHA wŐpeN߅/S]Bv W'zU8y2Sf %x/YZ鮮qcdqT gהiN|P顕֧:v&4TԼ['K /9jH0v ZOy% hףYڗXNjj!YcL99?uD"nYӞ3g{ JeY&/⊔SQ0QBnx {{Wr7cK&HCwbW{:PCI4xe};ȴE,q0W5"%p&,ij@vP ػ%Ʃ.TUu}Uz<.$k4z=/֊}U3#t'  ]RG}|£Etϲ xP$O-T\`f,bA?v5 "e5aD`dVC0"(XʀXq 3⤡qㅅ%Otσ| <7H1* g*mq1;)MB: Eqly!2/&%QO}J"91y$#2:LRNtV4ٝ L;࡫7C?z{" hx#@TZE)(2U{%ܐfEn~.P| #7Ӽ:&.> R) ~DS3ϨQ&tu0/|XPe'䛳 ؚJ5еohfhyI*dMFe?Ŧwu`>ڪQ @#`X*:)x яv F% /&Kh1(2+ q}Dx9$zoϿU8)KǴPmrʓ5jv2=ߔ9Gc! T=X=MyeCp<+LI*~TxwEF{Oɹ渜 ^T4f̓*]\齏Ų= ڻL!m$ɼK?2.Ħ ud>bko5lQIG}@ޗW*r<\ה^7ٲSUegչf)N7U3;T UE /IW]Kީt7>aϾ[V w%AqǠ1I7n9bf!KO$WO4@0*,J3n7̧XZ[.[3wd7`Quσ?62 Z+#`cBrl\ND߿:ܿ̚a!>mO5fp6c9I bЬ1/isچ372w >]?Ggl7dI{3Z8j0:O$֚ SdyL4H?“)4\cpZ7aW)~2CqM~3佊b⒤qu!GwV#[yEdq ;2Ui*psgUќzA; c11βz>s~W.z۞:@"c[4$%+kau7KK,+**#(gyMdgqAQj}څc 9k҅%$Ge;7O CIIV>5ИvYd^±fZ6aŢ80Lȷx=>B1N(wxlW ɷN{c-ՙY)E;8jJc?nԔEX[Qɱٯ#KSB:Lzog>8߇Maz#l$1ԽhŮ{p:y%loFJ5 Œn.TO|î|-2P.As$X`{=A_OIqHi%C}@g{mh"=/[p/77(rtYrqbOFc &j/DrRps|}+L4iA`BU\ 藏>B>"/W "?5@JQBJd> 4 4h'Z]ip_h,i.O "{Hz_fm=Z #P!hG tnJj2A܀۝RPEߣçZJwCڹ0OH6|ZD$gLȐGnl 0m 0[/%ަXNW^S~8a\n4أޱc9r$(4aRmPrə-` `Pîȧ->H=*J,hAh4}CxX@ O3xnA0()Źǽ MrVRt[5A)3c.[:aɳMXU9>|Tm+gyi^Sf ڀK20`Tr5I=3M5G`s;'6a@aa9mxNXzɶ`p1+-JalwZJtSSOs7(̼@[R Z %3LnnghJǾ;D CGEZrmև#~Ri)b7f.u .8/Z!RYb!y٤ bQgI//SANM{6&XBE^1h^nK~G 9u~.%|d$X OBm .>dRS2R_ Crq%pP|Vndi|aYWf K*7{Iq.4 .5^BG;,Ӌ# 61 "H=fY-"4q{r5:M:ż'U?->o^.P~DB+{ܸ9&.r%LaN|4?靁8B}:p_}|=E|?5sˀ oVt { ea6MMfKm8_=`WcM|$Pkn<3TqL`y4ШiDIȴ}ޝ#fIn:- _ih)@ ƔpL@;A2m:*4=$zxJ#T+Hia;Aakasѱ7bHU ? cFr\:(E*22qT#d;XgA-O`vF\% .F6cJ_#YzȌl!&߇ۉj-`P"bۧ N[Vc_ry8aL2l0G.Y&crP*¤(BJYwMbt?]?Z$OUҫ~ u\܋"f\F=lh0O^x%L< bOBvԾS:xWo^ZFd~J"/  b=ب0fq 9KN;% }z-YP4#DdZux"W $j%JB(B ,;=|ˊV @;p:_Huh5Uz̬5Q3gpB)"Ŏ$B#t[F 5FE%Xԯqެ _?Dn Hu{AUS svWkc7m>ˢWigV|"eÐDane~'Kjdu%OFZfФ|ua"3f>gXl`Wr҄K"M6dvŒ0GP[ۃ vH7s!ͯ+@z:yD'WְgzʇU4|2tk%~ :U낣G֚"Y"o>(:NkSC/' 3,!}jzFUFpF)7}&jo'/FԲ8Pl@\ 8ʡ*b$LzKp%:0{Kqu'Ci=tzGs eH|xIKQUJt%3XdHE7Thnۼ|[| nQãhZqqSKFO>-N0x)&<o-Kqc|1SՆ>,tOޫ冾x[(iiU:avo~작RPvVW$?(/2ǕBW;J|Gy/,O<){ S J\=PS3Ynee8 j\x Qq>s0MsI|,Ul=;گ|;G/sd$nwU o΃!$ͰɺL7[&&q}OuW|ID]$ a`X9ҕ*7~U"}B#<0kQ'3Ss"Jb@OOEH>V$gQ&>o 022ا\%FLiB?fR1Ь8 g*,n-sCd>R9 #/Nig4eaG"]6XӪAGp@NuniǸC^<߇qԖ Ք²6Gl?5/`ߙr"M^g҈F,(73;)]hUuL8wÊ,ȴ}ǚq^tchpͲ6W}?\8, *RlD rid=}_e}KWO9[5tH@ 25CRvwT 2e$yhj[p9Y+^U qdWc@3ɂXo'F mF~4u/݇X%KP~geLqv‰C],&q=I??6O@J =AǭLB;Oixmr\u6;J0ZJ < ˘{196YϯҒTNm)C[O|SBYCq3lս2Pbd($f:J .7Za*3[RAD,,E`$Lym6zHb8ʗ4j!ۢ 1ph$gkWcq bئ| Q,rF}"ܷ&-6Fn|w|hHح(A^8#<}>D)Wmr\#uW; $̤4%!O!e;1THEqacE7zKèo -W-T0Uyj=T')g;GD7#O!W](^ ԍ[>Y Մ_VsCo%*`\tnNa%Fþ׈4.nZ\ ?xþ#üJ; ?^Wh<"h9WRvlZS"53/U]nG*{iJ` «I}t78, ! RidC[7X@C`Ю2 tdKp$R*U<&"QNqEQ!xxЎtz`d(4ס;PZx 545 ųgft{SPL<- ^xXK\!8V^,dRAcDrS6ɥQ#U ~,7zAz-j^θJ|Jk "PaHoK!m$y[S(isBL&: k؍[|taP{ cϏaK+63cau2 ( :%ݝWQX!b`=X=!RYTkt.G `j^_8.-MW>_?Uk̋kJ!T7YNgL5z~lln;!C%650fdtȏ%kn,} *'不ۡ2>LρÍt%T* \K?ChrҊ}#p1oo$& uB?<d8hx@w@? Z]Jp]|0>3pz$[:2LWwsAy-Ĺ6eD+4n&NCtXVoNwmm u!sT4K/Ƥ)G0>=  bƓ1v}}_ R:`2;:0o]:/ 4iP*"!A:ۇHrHdv]I[p$Y}f:b[j165F;6Ck+?s;O7h] NwANpҦ/Wx&B;1_L‰@4?y=%,-ƺmR(0Ɇ~d^5K|[%LP!80iXA҄LHCncOy<9 97^)#f`H4OE;F"BB5vV-kaڢFԕ(WT@[}gm,'0 /4INgyM 1np\bm1ơK5K-W_}GЪOHi8=dX(1`CƤxky/̆mSMx戕 U13vt`a Wm,:2gr.K`WhNËyHEv/q }@<VM.oy6[CoaF#h+(NɥMr؉ED;/~m ЛܑAa F77о&XG0׈K դjaPK ASB;P'm &c-i)s H-Bgg!X6Ñp:5`U 2LuNե z$#*G;n W'Z0o!H smN|[=Zb>(O; lK8]dHHҽb8Ҫ}9 tg܇E0`ᰟzԤpH_ʧf@L>aZ9cӱ4.CK7ѬV*tvo&m%E5ÕtH%}Rb ʝ]a.:qmQƬI WWja̲Ķ)SNo3]up~q–EyDaKXalm D#X)zck8/LYloy=CCkONE)vPӔ%+Q%a$.ئǕ6t~'eFztu? Y|RWxLJ.|rvXr6=*1k*2F&>.hVm¶ k>".z/2K#4t;pa;t'U8ݤ]Qup0Zj5g|ăoC~t09~slxŚItxE eˎmb3|!cTy\:pV"Ʊi724P=I;)~* RGӿ %7] 6](fX qQҟTgtf ! WQ1 _?hK~ )`?$ ' ~eQs:7q]}TNhs?fI_Gޙhoo!S)[pA" UvX F i`1QB(aj/#h 'q0le-ڸWSX3qo2l$cRpECs-d_"qŶ̻ƚjYمR$6Ȏ<#Rfk~N,<'lE8DxI5&J p Gn2qGr6Mճc. 1a\[Õh.]#)y%TY[[;׍ׇSM0YHw6^]֦c] NjExOD BW8j N~LMA I}l5v=nN:\<[IDK >h4#J/kP?4C/b.=es~-=y?G4D(¼`~ -[?0|'${ЃHaS`\w;^{5U؇zԚ (lW/o&*,ů<gm1fƅypѰRR^aB  Sa̘|U@!PL> 4<K|.~6~wNG7Cr jyD7b`2P"|rTneX]IؠuAHڠEHYt!J2X4es0f~"#$/q!݀igIR  |jʻ1GuF 0;k̑忄TVf虋Uxx{wDZ %-l޼`V)$hCu{խoE=cbxaoQiHo?!FE搫$ƚpw18m2,. ]!m:_?'e:L6 m)5ۢDأY*wRPj D@%CJ]DewmX3x^0mLpT v ccICS3Xmaa5rԴM1u=vʮwa={R וbNydz\^uڻ!ήp" _ٱTLG`Ʀe{CL\1ĕ9O9JYYi~DgmޖM\Lƽ0AN֝KVSz$r~3t rXЂƞ̭&恒Գ GmzA{\~?jT9/kCKRd+!@D/&k"SYz%ryE.ҏXXecS*a͎zχm O,ݒ{PH]eIN{…-4 ]D@<xk>Rl|6PyoIXΪyB:1zr3hGz@AU嬏 )o+ߧԜ]J/*IRѽ5]uе4~zD9Ivwwy3t,#Ȼ!ɘ2צQZ+9zO%!*pcL\Ra]G$.=/?ay፴QzjkؠDUъ5$x9Qs)=aNXc$gFEZNkX`I:CusCfzhp2X 3̘ac 6¿D;Ў*?R~:dNXqYwgһWU`Fs,ع6\fn_rN0O԰Bw\<PJxzՉ2ѹ*1&:{Z DWV] r ̀fxX]##,s[LLE ҞpSMGb' D0Kщykͦ)@ġBĜo m]@,n^G odE>?ͼ.b 8};j*645ikN~1ȯ&R2q&oo(_~a?(9b9jZ+>/#{@{g$AjI "祀g{=}bYRZ]Jzs=QZaɼy!3"ͯ }5W{wMxA ^Oc #L"/JLd 1{O3" @6hW{x)f\c@hq(z>q޶ܼ\IΐWB*î.YcR"E({7u qo35E<} CD+BBȱ,F!J+ỏc 2:(U(:) kSw,d>j F*z8񇒣 CjB6Cc" :U73 5Ux&f,R 3(3t/h[ߕw`yףOƅȀZɞӷ5ko+>A-[ }a]ݥ({D%z}h8#fLa C~-//)s%>;w9u58c@6Ä`KI'j1iw`3RW $rPD;l :,< O&!#n} دwD@@|i rhq.)P~$ޔ~) 6FVR*qu)4bg8X2S@ )X9k2a똰؍"( 2AKx90>= @dNV UmhW@{~J )?6ѯ/m-g!ok¡֐ƒOenyӔQĨҽ Ԕ / @qV+zZIY #.f0oGrb5Ix %^-z䠾w 46`:+fI272\{ڎ2]B;߰jd<TmOC[J'fC6҇n6wÑZ.Fv B8}TpQecqnȇ`$V1:U9SCtUB[I://'[ts0K.zr\B|>M}d? 4' C;1YDܾÉe@?fɵS;E5FY xٱU (qTO@ iWPѐEAମ꒗yu]I|H[qAv(Ad (瘂K 4ɣm9ΒR\7dA5;(ptZ?.&9VojqSvx!6%mO/\KOх.i"S iq11XJbϘVfݺLٕ,ă_)/,&5$FE-u'Xot(ԍ8#x#ҿ*FgQh| [>H˪ebR! יd!)F<9<3>֘IZ<뭂rs&9<`cv E,w;cUA^M+<> oxo~ {] fDɋ yfUԌ>"߂rXȸ'+^߲Tj3ܱI!k0;s #b}~UQ©|8Ph.-56w&|S?F-%_߈;."2Jz))} /o%757չCv_*oR38XaW"??".+ ][Y8ESm *#2A cPy$)Ddv Z@wvwS#HfϨcGejVxNeO;Jeؐюat7MX%{VtǼxdX2"Kj|@v0R5m=?6=b%(%0_UPT +"AƪkjV`_%*0%  @I'J< }B-  cP%u=% >= ZA׺^>WsH4_=8o)%OwZbGl72Pt|ف)ǝ3.ua_=?=C kF\?ÿ$ +;uTʈR/E-$C-5r} >T(¨yw]ptCݎ_3&șV!zVN)>NvOIDߞ0hs8nVi`ZP?@xVE Pu|X<)Tj%m#QI?s@ 30dxzؔil3 Zkɰ?( i2E`vubdf\aFbRh QՖ,UCNhe|VڂJ,E1)'A47ԵƔV C'>D_wg nәAȕQB cNؤ1H|"Cѩ UuY0c8ML;= AU2 ;vZZkǪ>Lɫ?>W:0v|=Nf[mF<U[ɥdlkZpQ R^ڮefhm5AqD4}ZN(^{['-2knqZ=-=9kFݜcUCcHwu6&jsfPᵰtt+*©{Zw !\a#I^;n|7@էFfⓞQUMf[Yƌf:?hs-^'_x=_B EI^m\NX_4>tlBtuv~Z4Z1(4A%˴c}95쾄U43хSo J}a.2>`D^T^Kf9\o40WoW 7L\Hds(Mb<:H:D׉ar4tOwJ!c{Yx/6۵׵NANzJ;DžmZ^&!XwJskװv;?ANuxJd*&1j$ZISgoHrS ]IxLU:kCff@b` P vDqS&%m+%QS +|EEgA˫fl* oAxxh H> $OFkOyXX2(-Gi#~Ų |,y[kw̴wֻ+é? #|,=ϵtG}IS@΍W6jϿ[I1)"*l3}1ɀ$Y_29MQ!iҟ1Vj+oMB@CH=$m> +<Yb$7hc`ut~A`E[d)$LKf8M=(a<ffWs*V "rӘprӓf7Cjc/7)u| h9, xGz2;86AϾM,Lo>L?6r^! 44yu5JC/z %.gecVPtk5%YHs,ړ,I='RKBJ L)(%U61dHyW(2Zh~Zz1 SłP"wZ4k0BsFnѼJ2VQ>񱔰Nl@Z6LCh[͜@=Xˎ2I+5e&S'p)(}є046DJՁ .!ُL{kpR;hJ 7dQ}~(H$So$wCߞ~ͼ*jf+K<+IO\)իjtvm>0V 듸z0u35 k VԙR_M\ ` x ;!H4%  XNVFY!$sXK]~I `][4Lb`eqg%yF*_ę\ukì/L$TTq)hq$2 \KvXA3Һ]^1I3_%"qAU%B~ yա9MG n"mZ͒ɧ409j['-* F⣇vgs 8CCd 5jk;[*-p-~F}̾c8,5?>bL VIbGٱ-s`q/# C;jC&6ߩ//:}nl-Jq-0`Iqg?9ԫ\U2z 9>M_ ^]~>/PL*\w ڏon9;Dcx3 Zkǯ3'?s#,YuCv#e8&CKr4Z)O$UZb$PPO$JJ `S1IQ%j4?Sp1M<ðH͖5Rrx![I`nwV ^3a> ˪Ʈ:]UՖI%TPOcZװ$x&)Wqhi|ܖD{ʸf-6!2-=^t*'2)7""{6_y(cCq/&g@mh;,am$G\:׏^B9mn\(&IeRH0,9-lIq̯Mq#NB:4%Y2PeM>\ 2"wX-ɷޞwQ ATY;ݾoe-KثowY ڮN}:rolZS3ѩ`ʴ 7OTw+(D%=B,d&T8ኲEv$n/B.S~pnt {W1VP@>ұR:t͋ -$I$.izMgx O2Hڴ];u1e7Iw0B춹Ś+zaMv=f>=;2rmpv@R̃Nd3rk& 6,i B#[fQ~uFvۏ 1 Zl@xB(ԑ?_yZOVNZWRWI8KdR{ J,'< UKt{;x=Ⱦ(D7q ݣ57ܤ<Ѕ'^r#Pǚng  `j&S 8_G@Rgp|cP AlP,J;3qŽQСUm$,Ax%bW\ok4q˗j 3)+wx\Zmˮ 2o'{BhoW~S5v䫾ё%)1nIZ&sa[Ca nrotFD: ` )htJq{ Hu 23^[qQͩ⊛Sk7VǽJr!I9>9-39I-YgJ峲aZ v]"6.lk uZ9˝BLk}(p/EN<|7ߓ@|T *PpXZ!6n)HJNL8Gk! źf% H-u;ў0;B{jVsʾ5#iAuE}0VbaP-l) @ů$8{4x'LI77C ,<%P̅!g y|TX;ËT?a=Z!8L+"AqczG<^1= IKѾ3$P3ҩJ 0,uB(l s{Yy`|q΁As ow9ebs$3;`VnMGp­/^t%qfT$3 ;[E"u>ԳsbjAn M2%roߒ\׭}G+pK41s07AvܩY?r \mTmW o)zZu')[yhEqi8P<u_mz%~_C;EN`q'v]o.Ëbƪ]:SoZ 6/L1 'iXh@9o46^wbj.lj~m"Ż"&Z^JA5 LWya|,ږ.s/,e{s*{L*$$0L2V Ŗ\ B=>0:ZcUR>K^~=QrI{ {,l2`<EN_φ oC'P֝EH?:j(yC~svj#ŔSt™1C\W7íY9 u.wgڥ VG;jKz\UsL*PgN5tyu:iqroZï\^k%ri0lr:Rv9qG\zm`q馠/Tؽmo^TI[,/:Txd(e^~t?^Ypj%a=1GQ%C>L,ՁOFIH!*#~/pwFW<6%xߣΎ{K.p;&mKSEa ʲo[!I ,EQ'Q7j=Yo L &Qř8 u]9ol(Ps7x ΪRM0sȾ-s!#p.zeNx/:TSt@J#A(PqO W8WoEAѥd B]%VK iDĂ 54Ĥ%o%J}XMUY OGs'|'l󥿼1Mzorùf8T'\ಲ8(!O'hGƬ{E,}c> d&M߹Yt%4JDYHN>AۃP\G]M6߉Ueov Q߅qA-fh\.8u%%_^Rn>½ZH7Cq8qk1b% eT mXh?e sat+0T2|.$}(@v ,4\]bC>Pޝ**;k+}$jhl?ᇤk)l+n+uԚ}h[9_\?߯f,`zx[~+~Qfr"vwS@dA -Ҁ2*ojZi2kz13m`ϝ6'D>\.6̈셹oHl<̝9xb3 x7x N XC$ [Y4 cp-w 'lhKw{UXx>cC& ;Tٌw5zkͬLш\2;gwf 8VX/ n ޸IC`j5h7=Jka<Ț@L<Uz;Y?b s&OW C;zXh,LZ(uT4䉸hI"uCw2Xz80?ae)S 6r}X Q?<ΰak٭D=gR!aR=ٲ iT8Yv;{5m@b/XQA ʋE-*; _NwJ9 SlhnN,'j]hR/sILhpHpC0u?B/]ڮĭ X TUzo'GVƷGn;oI?JR6ycER;%J֕mu9 a`jeX\T֣%H"52gŗxս 'T͆A{aBTA/VFo0-1$SA[% :!?xp`0W jl jG~鹲_ZRH~=H܂_NA~۟PnGX\"grYo1;|XqSG\u~h<q#`o`]O Ƃ~ctbGB[.$87z6wX""Z3%v^:O %#? \Vj¬N?Jo7oR5%mZ|$sGTVd y eJweRNF6CJ ,PBPF*@ŝC^Gӌ +9w4UQ)D5'Y>+7t SYM?SKONpufPICJ!/P <l˜2! _, =qi0sk ޙ%vVFy 鑣 ?v3S/şd*R? ~0ߍ91ܲN$k@`4_ݕ .H3zO5wDtBv2a]yK\BTR.Y ѣ;'ql5бD-J@__ˁ~;w L{o>2F0f[?  .u;J9Hd(N%E{*"Ͳrdc- WE8cK+9XѽS Bp~ kj 9b;CLChȒAB ͞\?9A51sC_ iSDdV;JF9Tk#m7P,2W#E|سJ^bJ4qYkc4Wzg1rɯ&TdePV#GWD*IIwKd#Ts8%?-8Duȉ3Q: 4J vh3L1X\hRYǘk킃? w:}? " NvY"%LAD(Ǝ&WK4;lmK9)Z:}PPo4'"u@J^>5qtn8:a<莏6} y%51~vZm@97U٤ )Na = }^)Q0UWbP^n8-P {cLs8V#?ϚqQiZQeT7va6v-<O\ BނLf^{T A`a%& ̳$l)od/̙mM8\ROC4DnsFҡ~Dˬu4 *!S " $(( d!9?`#Sbf tPI !ї ϊgǔ`w,53+$Trs=ۻϥAoAx6ֆx\EO6sM'CF+\W4 [e03)xQ܁OfNcR짐Vl"AMl#p*-&b*+F0GN ,VS]zgb"dr4{׫|rg[]`2KIxQl 3r m#LԾc$D_W+X!ą% H/Z0g,wfBlhr O`x-TC@#ZXi:3q~YZ iJc;R<kVN'5r&S;CYrb3jڠ!E^ ԇTfx/>?949C[=I*ٲ'T_o, ݹLB& j9,*8xXC,.66}Sz4#Խ[Ky)e$ZEԘݵ."E'X\҈vA/RIxd,Azjybћ_iS=.41NF9ߜM5wd(1ugi΀cNQ-PZfe^E_MޭQÎ.~›UBZVI ~'lgS?v8#5h)$>+.{5l: ]54s:Dǝ zP0H\}2L|2dv<щ3N8IDfs-![ 7 ï_ɳNί~9#gR-~2*BܡZ\ݝu Rq% \E0ySRI#h6kQyxQZm V?"%D, D)+G&a ;Ls TIpjs ^dfqQIOyS3&=\FGڐ"gV-7E9.Q器Y8a ,.Z `pl#f qY,. lBJ_g üDŽmRS(NW.xr۴S7AqGi&|ئw7 ʌ;g΃{삭7bcdw>!h>{U$&NTt=0U9v[]aLqyy5U,Pwdd4SVEcPDJV9o#`|]FZR љ{7Qw⚆&cc> ?=Fr.'zxy7?&cMi֧nT6#x|˭\z{2c#Nզ:u8ZĒ HunKĴTOp٧t&5']X凞AY۱J$B8z؍BC,Y{΍cZ aZ.1={"8 #۽dv>;ٴlT McKg=3Ш.SE҃Ӎt}c=dGu8 zc#] \DzeL9I"JUIu:)GQkSm 44B21FK\/hQ0[se(Zg.0gVi)#ߝεqD,m:<օ_FH&EBœf35܋Xg 2AʲvZ6cBƌ-U]hs/+n~_Lj@ $18ǿ}V3\JNd%IkYUB:o}\ˠOdRMi\Vs zo5Tra`\wHlqh}+*Q)t Y]ҔqlR%/]t|Fpw"?iMcJYڦϱLS ,%uKrX\c+hʷ;x6NS꽙Q@1$'I̊UgwXG9\0㞲2z7*m}E(58"Xo|~|ji1{:\*%`mw3<~E]FrIK\LNVC2LvB* od+^0ߙ3YGP;SƐ NבmW%W .e{q+ :Age/Kk ]oh͒ă OZ;L9⟾Pg5^_Y!VIF. er͊v2溁/R7Ue"(_ۨUB>̝⇪u N@?er22geB|f c0lAMICsh`3Ntugx~PPFޜ6HjJuM@15Q:"q _3vFom]*0z*+6dq+PVEI 6:E&$Sܬ;Z,o4)Rh:ɰ铣Y_;trM'](ŲYw"]$+"\ Z!~ ?c+N>lT)'mC@N|&\~4QC=_,r74=);z>,9SD%w6HClXiVfJG*X/kۼBJ`!Wx?΄䷀G[ShL{whՑRQ#4} dϗ lv+C^!Wq8Jz ^"  d+ojJP[[A# <6S$N ֛z,~TA1}ɕ:xLiS\/ wUe Jgs#t"SAD u|8p8~3o9$d/T`UL5|xKPAngdnO.  @ W!W쎷?~0ߍ,acs<[R[3N2 $*AKjrYJ |^4OKN4:mo0%UpU XqPm6Lm%j^m<@:_ρ;w%;Bֶ#Uw,?y~d856S>XyC;_'L J>wqhzfO gK~J9LaC5ݔOȠY"8`i\U\q"XbD'P=oT=X9#9qP]r9J^\.};IK_CpzޭdYCvoFꡐTAg;O-T ! 34kz / FpÇVQa MXznt|c0eZfiMs?$\0 ] !oJ-'12Nd{QQq/p2*cu<.Fr`UHkj1EK%K0,}޳9H\i-~cjk@%dؐWn&Yɯk dߞ>W&'75VFBq-iqG2wuj OΈG>=+$$1*\)rɻԞp e;{xLZR,U9-Ŭmq}qTD܅i7 @] "A퉇qGDIX(:#Ίg/ni"npfn[] #MB{3׳VpYz"Œ/:!L 2p5f⬀;=DtQ /2% A>H]mK"6>YcSaW-lBUvp'ij]V/VVm 4e#&nyznl*ݤ;w={Q4,uF :ٓ _f;#XqJqɖlI.  ̑)G3]trȖ\cpat4!j2 m<7Mq^0 h,p70'O D1WY9h7Ht (u'CT:[+5n_%=$i=A+c*S:<2G:nZT1#߯Id}I+w&V PwnߕW|OJ3Wc~YZb6S'A'}..vD~ ҿzX]߇hʳ e 23î[EtO" 8}Z4&N M2^84Hbp#M7B90iC[W/(b)98(QW( [ ="0T>A +G4a#CO㺘xRB{Zԃ5qOFЄؑ"S#i|98 hpCJ[/?Ѱ@~"D e]bc W杪Ӡö:[R| CiUyMRynY:&ڭ_=:<,M sM-IQ:[Qr-.~"DY?x%{,[5v+gSM5WlXG"M e[bT:hT.#XuC]}t Q2k%3Iwݰm4CBOtc$ \{Mt}("fz!Ruܓ!mMB_==6w.;S:n"o|O =K Mmw*gCQtF%AAqoٵ|zKU `Y9½JdfH85;y盀#0V{nQ,'#8.+B4 o=Y XK%>C塄-jc=?P#hcfl!* lj f*ف+" :Mg;AeI N0-%VU^E-678n!?`0E^FjS֠ݑR8Ñd hqM]JF',O>i\Ȁij븻77IYTAzadDZ}GCv˞bLQ^Bo)BB4PuZ:AQ nG|ÞRMNjB "%ܟ2\oYv _Gi@OB/gPzQӗd(Cxb 'rzbpx ,9S|\BU@bkk弻Ҽ-AE则NH aS,w?XqU@6x{6d`?Pӣ 0ַgtB7'|oK"f .4<'VZB0 m4Aت3)k'r;%Q,*Zv ?kH%Hb-'6hK%)xǫFRUL=bB6ǞzIՇ!DUS.+>G+ c~QMzB08Lao @v&HRy<}PG=H8R쨈+/3CTŷ.aE4WY x]CKЄ~IScLwS~V`#@v;aG7\.Wp##^cҨ0Ti=IkԚjLn^'uEe+Rԅ^`%gJ:v}T˕XbE[E)Gl9?ߞvC;%p#ӸN܏xT1!Wo<ٍKޤu vxw#[tkCy")bB\ez]~"ÞKT_wJ0+*5UmZ%KosE&yŌN6c҆3!mbM[8Uz)taT9AˀX^Iu `N?Z7ߧ8<6pAjUQJ\0ۯFi Fޜ)qvC{(zIEP8lNig?evlo$ f'7ƏIx~]/'Uguǭhۯx!&?g9hCE v˸4 moҜ/h A emgJ1:Fl_OD , ]`C)\11padk/T~d%Gr) .6:?^0@ի cj6-HvKVsl:FY/ue\YW2jH ˲41 c*C^S<>-^8ͫ*(ZJK̠RzgCM#HrHqb`gЖ'KZY {ah)Z:?0Y*)K;J٤AݡC2MnTlV!>tİd~(pmCDɜ%3vŔe̯bW{P@@N+!P{&ͽ%dFƊ pj6rcK1aC vb +gf?5 >DhFB*fC0rc,w !75'>EL X<?GL巰 ngP <2/]-blk(H2V!Ƅ/sB:k2e6Tj*?@xٲ)98rK'tk zAsS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPD:4< oզug'):po=F|0fLě5j\ Lz?QCh*˪?0+2ŸF i`B{ָBdEM]>|ð@|w &-z%>i 1mgG-MM%Ƅ]"*˜a zW|R <({xksS ;9Gj:hFInBѱ\x! Y>}rLTF :k`!@A8 Wđ{qK[MdAm[%k甲@ t"];#?l #Qusv*oDd^!dMYz ͥ;8.}#/ S (x̒nHԭ .p=hYK* fS |B5,С)毅L;I `91*~YƣhޕcCiةỸ{^ٓdߚŇ96&Ttʄlt )z+AH۷d^ڠV'-s&-( \C v!DasK<}f @@}ΧPYgDL1xٽ :؀)GB \%3\}Z6BCbzT,:^g ZԸD#dG}<.zX̛'Ec$daHo0PO;6GI %mK(3E n7~a0H9ĵCN]lLͧ/SY?fQeMχxMR8ES8x. `Vֻ]h~~%؈*Olye~taںJO+)}N1=%VƭtV-TO7:&7B-]*Ќg Ja0zYt.#h}rbԤ+փ.R 2Bxޮd! ݠ3%"igos.NxD y4fC:>̅᫗P9ʇJ} K影ӵoQuXQIU`Q?0|L i`zBy[+`s^옖W&(Y7;ee%L;vJGN8f9L?J߆qYڈ(ִwX:q ּ̲'5 A'${o\ 5T5.{[ӣxz@܅}b{?niԹuxh/s$OQ[Ew.4ż tiW?1RiXFKٕ,DmMfxC)eRhg\I+8 #5 &TuzuXD?:c[͆ |Iib5ԓ^|0߶`MYNGƅm@v]ţ'6Ni&K .4_ɯ?'|  ߁IU5ZB9j. Y=7'Gٛ']&j|1A^Yz[#I I)C B3 d=expfeA֩xF+nI g&;[챍T=T;*EUJAKo'6  tLj3jicݭ[֭xKF&A7P]sMg 3chtJ27nh}ʘgJF4Rs1p%V8Rf;;DfI:C.lywPyֺ˙4OQpU,5ϦVdAYN[x. zk;7Ë{e$rJZoPVhQжv_|jy}I|Nq775~s3n VXA_N@W4{t9_r>s%9{`2Xg{>8u[@e4-$[$y-vfs]-Ѓ$ tWo?lsL1A33J,pڙ68 ̙B#P''0gP'cĞכ)㲼7,̤R~ L&Iag$Z1S[kịSmʍgW^}HD~x+Vz*%sLo)ėD)u߼D$ g [[ -{D=lBڤU&:Ś9l.Qt T\lP"H~{.*`EcϞ##:_=ɿ}p0m6GݠӨw-&IZ?bY=ѕ*9I. qG#/WR  H>m!1ÞS,"Js8#A.^QL^7naw Yk}ӏU_ d u^Vgey]Ciy*e,٦ׂSޤKW psڿPAduf36N,2+:){ׄxA')xIIv<18ʭ1CM|WB=Ŝ_`KrBr-;6\Üb-臁HNZBzv?f@El$46H'W,'p^ Pzԁe [=0[E`ŶX $Ӊl#Qo,܆.=aθ]`e[-dh2e tʸz 8uvE*-SE(l L!<ڔX( ,}FkXpD5y&&^@S%dFrBggVͮj(4R8ɛɶ+?L2NßL=CᯠhY ϚT|iLJо3'ͭnu:{^ BغnuIW5Y:3^[1}cUTpOH9n8v)a%du+Q @֦'͏﬐8M-*&@4yiEl3+æs1δK۞OY:=j9e:|bFKNMvX5y<#ZjVBd`fԵ\iU FA.|cGG+m?>MڸM70^w{qz=cv<;Зmf k8yfuGMր]#w63ܱ4$,s';e<#,'rNz1L2V=2|/nr6J->( 'u>Y֌(:Go9 ,͝lIHal 2HXI;NԧGs$H uX[ο`RWE@ XiC~n}mAEdEteP!ޛէ%j/`pH shGSXT}2ݝ}RđuCif>dM;aQp] yAd).vm;ʩrA3?+A^P!$-}>5}N6JWQn?ZOh2G3,Ҷ$4׿1T'}BE_vhi&|aQ\Ut#֣ri>B'&d- JV%-_Ȧσ X`S'Jgsp)};{q^rfJU]?O6i,s+u#UdدG5EN_Kz+Qd =IL! pQ| ̄؜OXHK"W;{mhcIYˎod|/JKtUes&2嗻!ȿ+Ge|]4]gSh$(eYL3ft@"?8 ;oS'#|0>4pX.gzUp{YUBZX$mP/C~vILCz[/?njQZ$l&!k w)"?O"X0)Ǟƚ;4њ~I?|H@|z$&[8~E0jsW [ip*}- ֬BMЋ 'A`; nd=\^GRq*4fMϼvII2XKh3'w5TʭƇ.ж ~)'/qnA:|(^ĿBed|Eo@Rמwg-O5uRiv1Q"iܢ,X!S0%ՑU@ඝѰfp bhOqP+.bcG=` &b(1 }j_/"*\EA9O4|2v1H/Vٹ!<~Xy=2r֐AQ=VC"@JoVu"'u['!W!|>@;}h6No WK\Va)%Iwujem&-SƆQ)&Z!4FH,{;muRhX$0qUYә?݉ܩcz%È^+mvۮ)o͡b) .to]zy (iZa[Ut+{>.GY$gܯ֝# sJHLvc8 167@y/Z}Ni~dQaH@ѥTK^IbK;nBQ[fwa{ؽs۬ ЩW9G8^-e5 -AGݓMVp*/#(9g*6񢆴vzjٝ*V7l1dvt4ՕX_8mkN7 (P Q]oV5G33b25竻ldqVx-5l?6`F$$a`hm&߅ÿsqG@oU;[7wwԎ-ԓ QI@ CUh}SL}JUM+QiQ@tBVHm$)zrb~91GװǩQ-?Avg^}/yEM.8v+LqÄ6}sud|鋓=.$82GOל(7ZMRj:3ASx:x`:'ԲA:n'NYX#טfX7lzwJ% ŸƦl=eLMrjnRHgfb̏{>?wZZT'\ +zYߎ LDŽ"d:'3ͅL1T2 ii+^0PaF;x laY}feZV}#_α4uEZ`|2CG垩<3NرB꿹]$YKbv^*ۂ?{.a~ ӟ:.v8yGf^T8^ƪO?fwC_[&miO7C6Ic`ʯiu'%2MDu:!郤(!:LJƥ觤F1&`G8 T29NaL) ~жhϻkZCKECiÈ૱'Pgʐ6yMܚϕho,!׳VVJ8ˀ?xړŨi_=N^'׶g#a@ׅ DS#ց)LbN yu}vX9|Ӻn{[ˬ}']]okw5h־o:D2QéO.. 4s9 =.wr*V:vo/%>p*Y+nv'\FU ^Nphe.yN:ZQkMU1LʔV4trKlN3~λoJ0>)~*d\4V!JVpbu,A'3nqD A#5K!V{Rn16ɦ_׊>X$gZvo˰'X ֹߟ}>,ِaGjoVKץV<.}m`11H>Vj&[V(z5NأP:K8NQQ"ڌUa T`cdx 9FhcNd/O+ʛ? ēie(qA@J4㩣tͤd.sO0h0]{8ZCl.Gn2+9q6:r7Nb8[[0:WUԣ<2!K)lHyw5;1jģVI&/6ʅbYe_͐,U5]t*?>`E1b.5ހr$:bċ5YE`kKď%+I^#WdZ]h-RUZТw))u00P7WҴK3TUtO8k@2@ˌ1|0v0K~vmǍE nn7?'k4]T݂]dg$YW}1܊*ٍk܇ɵ g*~81C'%6r-0ȫ8> EJ{gXFNYCNcW rE1̍#;8}C`sH.\}IhSg`!Gq\AH70X4̔XSoMFfXKE D]򡬽>%c} Y~y C[3v"}*b;]g;V(YxX#Zo jOu䕓:5=m+[6_(iz шxWB-}pN.y Q䜧|{ pgR-; T*S 3GW'2hu /p]^lr}!.ygN;拎iɞBDYPKKS⪈81`cU8u;Xv+źzs/TIUf; d!84Vu?EX#xPz%w61rO"<)5&YtZ7 es蕣G~PZFһ:0HŻ%B}!\Os%H_JJR?(Y‘#k91 X7o ?xg)"+2f&=Uđz93sZ_B' ֏ ~5'*SW캝- G$spC an-힡qB`*LQHA 촭աJ:nf72sD&qP"S>gn D'V?WjviEEElMB^f \ Pȩ^ߥ%C|Ixϭ'9'7mj$b}Yzs*y%n,jG cI^hBN;?rgl-~32^hxz@*ZIňM47 %fj;Dk}d.0tr fP@,S||@|b 3iP%~Z4|PƜ0ld{ | /KZEX}.Pg`JD!|LGTǐ*jIpr:dKOJ/ fa-o]QyOzFr?P>=YtՑ4jGsGW'Nleݒ 1I qH_֪)&1A]o&͋ɤ_#8?=F@ 96Zy?DP?& q6M}l &Veu‘| wyC{'WK ro6A򠕦)Nw*m)|kIlХ8DG#+Q]<-7 z~ |=Pɏ"iPH0KA: vGz$\cxBwn\E%4ԝ 7E O`׌_uI;)y9$pG옇a;&"SscrJqOiHY PV%]7L;|>@;}_$ uC(OyxϙYAPq&ҍ.c9ت&bu]-_֛2 C90#RSM%Œo.L˝K֚qcmJv!k`ΦS O~1hfOL ,I%Ic:GǴsK_AG?y $~Qn|8xra +hb:l骁Pr6cIY2\f8hKCXA$[Q.[h:$Qa$yNiCcau~E)g6HPOkYWS}I6zi>in*0s DoN]H7s[#I*M}$֝iFXǿ½?B͠Hdvoߕ3 VܴφA nR]^ըMiYYLzRg˜U3gR ;`DRrg&smwZy!^Ϻrئ/}w'4 ̹>; kYaQ3~!oB|ʊ%p1ygXC*rrD`<^)b?A,`t(_ h0X(YnfENW TxxfJնj(Ic?5HK;xa6dpWsfs"T+!pHO?A ϓނ!Uj~ M7e3"xjY ` L;rV,15mxUw:hCzq(ƾ~XCq})Vt `5P>Lf>%H$C16o죒]5kb /fXaʭh</r_x+!dP#'Et#nqETfq@ 9:d'У/Bv̹\tF<֢ӽ00q#r:P¦6Ɇ=mVЕ-=R [" 2[C/T]cwϪ *R zrgo0~g;wRGF9f=#/8ӳ {"*!/tKͺ"lpVJωUip=~.uzSp FTbQ)-0C4|'UtdHVV~h#S|b<<$cC=&V{^LWE$I49muQ*5=q-$41Kv3@cS 3 LIU&Cmy @?@'B7hwO3]]&~9ZҀdZjJ%Z}R)kxUrW@\{fФJxGͼJr6^E5e !kvCσN}(G 4 1WMX;BNM::e$˄c\ݺy *9fP$IU&zp:2zGWך/Uو]uDBtxuM[ˢ8 O(#(EhMCoO!h(0Qc.Hs!t\k!y()H_i>ƺ: %˚)l@VH2tC5td zb?FgչfwC$ ,ϐ9(Pd7y |MhB>1 T2I oF\̖mWKae piôʁ_"ȄؼF[1 t>vS|YSْm ?/+J} q#2 ELLE (J7/|ki{&o[bhf%jcIgH˛X -f2ۋ䢍seB>Z`ۣ/9'p^r9MSYuDKdLj,]Xġv *\"6 K9g~*Җ3F;#{:3d"SwԺ˛"k΢v,5<:I>iJ*RE8^(2Qǐ} %59mΥi0Um34J[/*|qQp^,)7,'b^!%x2hw732\}/=W(?_Xc@m> ;_,vlw8E_\UTC@ e `7=Yj(U4N!-n<ئ_qc+*>k>dO;>kTf~ǒiYڃP(B7*l''S̤HOXB/`MU8GMI) Ø|Ʉ5ڧqQ6PAK;C*uJyHZJDVTa1R]UAI.uvʷ EWp 5>)7G%D Fc `w iV GdҤ1`>XZ13'uEa#qDsWpw*Ev]tK0ml`P7W}C!?()F ֘+Gz6d*0P&VYCFz›Ynö/_!ѓI v:mCa˳ʜӋZLgJ~GȱTh}Duܬۋ&l  h@Ā;;c>bŲhP%J#f[}D|G\$W: l*9g^ghw\5(،@`ٷΉLmG4_pAO-E,7 {AS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPܳPo:4@81L9 b5[1:t?fHrNyM@] #WxX#5|aTLjeb F>^Y5Px@bV|;@|wH%p54| d)@^Kbr4&|L/0ɵ&Zl:yTh{`97'57>hUyn=589 dx@P /J}u@̠Uy@b i ńt^/Zܕ F ڄMǺκP,'frfoYLằx+&VY$ڐvv.ߟNPRbLxCpJ _Mȁ=rV؃*CM'F3JY?UmuXB5_:~:Mz|6ߓO}QDs_r!#/d 4eӅEPM"4[ItbLv'W O.Mp!NRu%DU9?;G;JGֵX6!;+ 7\8VVlCGFUofeUO~6:rOhThw<)Yrh5m ě884At$(GtB`óx`YW .THyedO?| =b@'ObXbG% Atݮ;-~8.MD^*gSLꥊ?ŗ3(i>]ܲLs Y5)ۧ D:VoLXÉ=ww {FɊQ_(" Q|Ix%g6.Z{)99s@!{b*zHz sq$̑DsTWE">?rXˢ9]?ǍrM0Qx@= G4Fn[_q1HϞ&9pf-l^^E \tܼb(a [\0c)CgtdD#*LٟzyAe""kP3 3 dcnbl,c@3TR1odt+K(4m!,ilgy=v_\89uiu^%dC߱9`G.숆UOa_x3 {ٽ15V]Gz>g[Z'*T$@.چ7bQ-Leᥧլ m݅AQrR')ĩϔ^vJ&iM [bH,ݰCZ'`w?TtY PՅ~H˦W1 Ej}KkP <%3rAi&F4$;çڇg9#ÎAE.^I;0#*xXq݋Ei PBMC壄(9`ywk#iʰWa.4|Sk1.rϣ3%\K#71ra+wvNRTB3g6aK? .yQB$L(zwy?@'1Y};K~ɼ`R2L>ض]i.-E߹yӢE9UJ] G#'0v}cGYoZB2w|4C)m i|^;K6~J7b yxU:N}U:CJKZ {"u,LLXGA /='qW@($}g" Ikjͼ=1\aVG8vGζFlLwxcA.NX;I3[bøBߤ+9$)gvR7ሖ*#˒yj̫5VJB}{͐P}8)I-P}zBwlX$*#`]o[טZlݻ[w:?,4g} H|sm{Fl}L+ՙqLVgy)͗ OC. Y" )BiroHtXQH_A,Ȱ&Nv>9%C*ƫƛ e8~Á("nP{P}S}3-M?AZUBGm֗{0!Q+f,Y-n =7w[9Fn+JDŎ NcE@D X}%Yŝ+쇶Rx4/ ۇQN5Nչ vԹMv;KWW65zYX7C wuQ.6㠙<9%Ę!){JܳXYCvY <]%3eԲ!ke#𱿶D[boMwc4$iB [Z".l^P?СC.X6,+I;WL/+xX.3&S+M,]K6od .4GD^c뗷+ USeC'/fR8DZwjږa+ܳxڪ@_؏yXgwN.[P8sf-JNJ*v+ 8sU=%xo͆ Rbǫ`#5*H?]:rP9T:nicda)\)C3+GzOW ڜ<~`;f8;:׾70%ڤ[酑Dh?,TaB2zՇ:DM гW.N({nwe׌lcoiKDCF;nf֓|GlpxKJӿh\,/ s/"oe{fPotgfQ6iNLuFcpu\|~!r|e#gFOd^|-z+3?@'WUt_6w(-5`[c?Iz [`^/&dA>FX;>a2s?xu:L.ݢݒ]3L8xugnԚo'کÇ[bF3EUlV8 K>E݅^)Y [  K3~,`- MۚIY}GXTwVpb}EDÃ^gK] 'f݂ޓ1!G^b[[JsY.Sޔ0c/ەj$bxFrZMwun]/i͡"Mbb5$`)Z;{e&K]:5ƴ`[f;E-}>덡E"w19E&eJ98y yIڕH#֚\ ;\S`:'X |kM%$L#܄3b>"lHxd}P\ՕB5TcP=4?w?gzxr=F˚}׍$q$V2kdJ0wG*{;k4eZTF!~6N``h]A~cGRwDETq;R$76v?_`q-@XihGY}utƪ-:DAp ޜ܎4 .[T~/%|'5u*zo@gx]D+oU;G@d,԰ύjzo^ѷgKI_|H:R8xڭ4WZ/JS"]\0rR&ȫWg&H8am7s*Vus<@$]C`<~d~M/1mXAֲP*5CݱM"R|1Ȟ֭vk,4y+MiwcYH'>%xu)PJ$ߨnwS7'Jb&bpۇKq(}lze<`2ig%F#QQ o]$5;6L*${rcO>L>lX\t)٩= :nT1CC o* 1μ"zߜVXA~_DKFG -ٴ1\'=gdv`랤kQJ?ˣB{YtF̩ݱlVmnM̦FGjCX"RY&)יV)ޟG.sD}A?fW[ʼnt*YM,\"b&N,SRbBy1m̒t^G魀 pTN7g>y #GptAStc]D7SɊ4[$P"u$,%Je+Vn\kXƀL qahtPa&^ȸQ^s)KD5=`jAx٢Z\a t*?lVa vSz `@>/ r+ZdFyMR7طD(T({ A,RAux'FjuXvRä6&kGQ=$ֹW.iX!w \UK]%2>uZ A/1iNҕGǙu]aH[:K?}Gjىp N6+iV> FeFA;^5 ߊioJ\}+"vlɥݷk(s2"^zo)*S+E97`7W+Tb"1Vb;?9 m3pw1 `y~~x#Rd\\"EP$PQc.a)G+r:s1W>lϏ(*zf$96xٚf \Ymf0p^ZY7Pn4R.b+Z5vs"QUx=_ir2SX+u`.cn?qF,|ck3zS66΂bXQ )k$5qy4̈́uvmq&þ(P$]n㥛p-ճ3MLXI͛g>S|fR='u,?f;V5-gR=M8"<"80k*(D!Ne ~y2X"&%H-?|o __\t]x(a+\.w5 :XEטlfŨBBϳOHQ'*[{W4h-1SnL'U*LVi&yX\b-k?N8bWZcC. ׫JH2%-l,qhDcSf$.mٰ3x'J?PFT h+׉ٕb*:U_K#f{ҩQ=YqVj -kħtz" R տ.&bo2eN8{1zR]u0<)e7br J@=u>"l %PD#xQ%&}d6sԼ6Qw821':|<4{M@ aad  .59iyKdyV^ciUղo & 6FL0\< &xZLD ,n {~PBb˨&yC}ؕ=Fcۤ:% W?UϠzU19!ןh,IX[;8Iol!)H{Nš.qONywV-57y.3%NVM' qw]FQb:B3TTiBFcF\Ό++er~C yjb'Ju" XlDZ?&^Xi #8ΕU(YIĦoA41c_ľs"DThr2!z9bϖctԿCf%Lt+vb?p9(p9'<cb$ojrh?6w??hσ6 Cߧ4~ߜsZ+BITm-BMF0[EϳNJ.#Q` ^!_1lkW2s<B4[\ku!VQ2gTE*{Z:<-,9Ǔ tv1aÚ-l ]Fz?̐ B=78Szש Q&&8Pg ClIYtxۈ~T>}3`Mu*J`x"TZG(K y6ZɳƘE 4HOh &y H1/hW,TPRSʑE p|c"gE}޺;ڌ1ѿ>#JAZ:HD`dzjY!f1ΛS 9JVUPM%X3xxPɚDBpgk[S\|j+2[VlpAL 7_*hzz D*/;e_CWaj/Gv+To @{1ǖ'4 jLku Kح>=#P,1f@.^*uId 6Ieb1e5og.I.Dwtm#Y;V 7 -S/oi| +NjЗ66uj^UA{rɱV'!&ӍX:o]njgv̊O*il}g gqt3)q,ŵQ]tÄh7'Y!RN$"6zA6JШ r\RQavf!Xk0uD(GMi{/eBibPJޖzg=U Y]T)0_ܔ< ]ZJ5%|IPDYk i^']eB͂#@B )3oMM_bںz(9c]~&FieR9RKeA;a݋lg]I^P%S%9-ա0wM~52OP (L=]fu:HdÝ!,{j=4?>5 b#Cjx|8@.ƓZ8VmK55޶\򙢨\X+X+vnu>gdu`իUXV5Q*c֣yKkFbPjܣO>Gi6N$WtKA-BU_-F3s=u@ saSgVV( Lv.GO͡R|wmoJmP0׵t`8!DU[=[gF ( Ye`DN4eAŤ _$~#/Af\bc adq:EpTyScmLfr͌zrȽ,K^0s .{m9>_2Z xP ѩVkHdXmds~wN:˵4tiz4 u0qWVÕ2,&60k 0h Ņ_đ !Ɉ83&D+7;_cdӉ\^YSQEza$".Kr4)1`vy݁C&A*{d&579#惨$94d9E15+tMH (I{Bʆ?wL2<*_mm|Rak ReM[fb>v!ߕ\8cI[Ʋ2ZXso*2$(P;k.ŒiuK74xni )H& ̨вn5+CDXQBأx},┊7>.Ɔ+uN^GZ$xBʝNSL#iH+/h ,sjI})i(E"q nVPhR9BbhHe`{I#ɮspЏ욚0sO\;ݧMrwRZyqmkI)[ p]Kw`0ofa/:WR_B gU=i׸d"xJsJ{ h7${Jqƿ8Ұ-ޫZ6n+9!DMeNARN ƓZ+\{F*ۙb: R`;ilvG73xeE0KdѳpMJVLyݏ,OPs`֩O}"X#g^v{g~ VR%{_!Sq seD.gUE*s@m 1%ƌfGMt%sMNjb6^}wY?9Ua}s$㫳@@9+=QlV}zP/8@*:Gb F~CQd4mjӎM;y(-=N]We`HB;57@8}c4z(Dz, ѱv9 "/YPttm0E|w#U4\ uXX‘GO7jo⮽eNltbs^?ieN݌v;2-]$t2 rM>YB`\sŇ{jmD zg }7i,) ^E|AeF;ľ`cMrnoNh(>ov&'@A{G%S/b땍4*'iqN[`u.[^ s={/OW_rRjouR3e. EXJR \"(BL9GMM g)@f̏3FBŷVY=8? ӻG9r)%FvLd\K)7lm:̠ꋵ MLv_V`&@SC:UB^+=:zzԂ{h61WXNu(rZn>ꇝ9}=*}J8c0yUd@ubUKO)Ƌȇ/;B&k[/*?hu8 xZY4=HE1jn\ʅ)(9O&cden A٩qu7j8EdMrVWamSp(/_8uBPqlg>&k!%p~})>8]hj۞YM({p+BoU c2m'"-,3@y{'nރ PB6% nlxc< j"`{mmtjH HwR]u{pf,WՕ '=15mIm+_Ĉ&ۼ| A9 T Gb~1-QE%憈)q4#V@I#h$|X)0NJA=+.mKt&\%j PyX$%΅\ut ʃk#j9֍uQb+LFU~M ':k$חJC@>O,R-CEBB'g EkInA]HFty$$V=o}PK"Wu6dNqɰwnʹ{ ))o3BTTt;&POPZ>],d* Nu+]Ρઅ"lKttaa)qN]g˧mȅ(9r&/GZ2O4Oj?n K˴w$$~jQӦ~{~Vȵ->Q#\wXk16o'_.ݢ]g WWcgɝ">-ꉾ7i-Z齪i4{ R ڽAqM+;QX^׉[B9cŒ_/veC^r7_sbymb!{)Ez!z|U^Ö2S `ՙ_XIms/ })C[^ b$>Ju:($LQƆ<;eEz+Hg\m}*~o@ MZKR(akv(D87MUiՕ҇b\nx0`s!vB<?ޫ?qA/ yh3z$PZLюIz6v}Cd&*b' +yˠ[R 'Lhy<v>$& S6R^8# |AS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPrOnR:,ÀQR_r3 M:|(?5 =ZJw~=?c]ˤX+VT{E>Amk#(vnkև||wP*p`KwZPL m4nS&=C=,Qg9Oda&aYAvxO_*?2XGs谰^ <#/\w tX,{ᒙEL|^0tʲfIԝԏfؑژ]^3M8 E+w43ɿ&g?n#T'17om&ѷc场iլAOHEVZw>usﺅ-s8 yO!/Xt#{}{ΒXdEjLm&c B–Uj^QZHYս˛À]<x@:IP7 ba,y 6:٬ :~Qb!sY:ƽVmIR56gss "6Y;uTna;?a-7)јo%6"P+؃-;&+*^u[2 112?< ;9a$ R#=o](aDqH)ii&^Gj9N2J Uږ?&3+e4b ;$1Jgλ)0"*E6JI} Xăh]jLQ䪋b3Gk"[~楂Mo(..K͚xă8^o62]6m7lp~$LIDwՃQV!o_.t"Uo~jyY0V)SR,˃|dkbE >hߺ/.]d:xϢB%o I!.\rJ@YP0:-`xj6W-e$~ W6BOB+/N$)u 5\nzwZٟ yUl<|#ËMI"5%(u{\8H>gzĥ\ ʵ^hKh$1HM.pbc[*>)咠46U/z' R.X)-mГ>+1vޡG擖B Zodﱗ,'\ ĂÜפ45}~d*_:9{ p8mY;DEESK7;U _ϑaue6WF9(^Nop$)Jꁼ? ?Ck8S bSX_ 7M7T`N|7釀/m/+x/0}BX`^0"$boFH2Ifiv<*v6\ѼowqbVQ8$<0΅vʱ .s'F`Aث =W9<sHhUkJ<ޤo{X'T]CƟs~:&EWxeט-%:e`R#pVTgMq 7ȺO+e6+)j,v .~_L]'.OxVQCIufQե\crulg!Ѥ!S.i55%md-1u7q7{`)ߝ¢' #`6\\{ON4%m;RfAuomNAmpq˙%yF7e fx$L(#\ӛyxG ";مbD2erSWqu[2yhAepj1^&dً-;`7{H;ϒ>(Aީangm]!lޕB}=~C +bsZZXc'4:>?3+.;rAE)%qYe|g]#'[&Z5y?DzEFM- =K_cO1N'K[S } y1(ӡ܎V2iahTVXܛƂlaSPhDCX ed8SS{630`}] AX[Nm ?ah9"!^"jAMNT~Q2 z ZGYTtώp+%6a+\9dqG#pƷǸo/HEnUvhwQ.MX l~RBTU֋ob均_dAb1{b2Γ'f}hTvfyߡ03c6{+*UqAMBb[a/yջ8 ro)o_~X;5N Qr/2))}:$@NN_=0ϢļoS9faVK/ok$څ+ |ijA5l7 ѥe(Wgm&k]\ Pw:xWSتVZ20Yj Flǎ M 19]j8kP`jS/nifT68%\ FgEW_u/Nj:ՕK*Xmְ?={G ПPp_I6!Z nCpc؞"zpRlbĽPmth52>,G؅QǍZNI$-]ZI4@ j!cx3RrgהadY] q\U6F%.WD)DWߏ.ef(ty6v|P]n/:D tړ3`7:mE#;{lmd>]XcB2\_OEak0;y9~#@] G(ק#Oٍx|pپQ5TUY -߭HfobU"g|qP V գ a55-sJ6F H%J'2x8 0;{tY~: ;*@V1E;㧓Ṅ@2?~ī ƾ oʵ3$|dTxɏ|jKAx:ɾ3wIt$X ^>V #:m6%jC(pe DĎMTA:E*$"\Fq!m qP2/K]j] KK_B:[ۃFkǏϭE-W 6[>hQ RiG/ ;d#}jvKtDf)ks#7*[E2ާwb2ԴnxB8"c3o@C2XTCO83"sci{c1ɴ TBr' V>V̪d bs㘯qkc9LAܤԉ1ܷfP$~,}OYƋN[ 0߃%w&Ot`Oq>lő}"4ޜa!,%9x/ֈA@YP"uh@\uz3⚲0Cj|}nAUָ@PiQ5%'YDE{rs1 w gmK:c uεWdMS<6{rA>ҫ|BUxB&ዢu RCVj*u]mQVH'@◷$ p; Cw(}|;=!>Q2&+=ɾUGPbGy* t:NjzqL'PklNtiW6پ7T1+tqa9V T]U8 ^=v~$JMt醣ZpX<^ꪋ6J-rIY)eesl/Įcი2S|&g.'X]p"Q.m|υqj(|˶vuBJl'Vh+k1%qKn2ނ+^`pCI>~ĶkŨ#"zEcI]'Љd*;qtpbuB,5#nTէp8**0@)PPMs'f!M7^I10,tL%.!y:^Cߓo@mLk3ĝ9>j|c5YߙHUIgy zM:2"F^48 '3 JyQ* t@n=\;>c݂Ѳqw3q}YjݤLA[yk?0R$X Rͅj%cI]NBK7nbL)9B5ZC E];1/ROW%i9fTA4܍@8;[&ηrls2I Kz)3ni9o_89ZjUw8\bA͂^]%ŎYLJJn^Vo=|u|Ί<w:j(Sg5bnyeZ/F n38P)^`_/"Lpx01@@|j6x@gw5p01Fqۂ/\Mқ ÂBN}P$Pdaʪ}ЕX,򬭅K=w~KXm|OnS8`pKTb_|;4H@|zKi^HUlb3(?&<t2N~% ) gjYFh?w[ x앮պɈa\\L"xy'ৄfD?V]~KOXj&]vj`3杇ϬUɫNnkYHD L0F <_t7FÊٔ(Tr2wըELtPĊI0:j.F~ 5À%@MZE 1؍Gy=hC-P23U^EV,1`'|e2Dd(qkT2. CKj$ j/FiՖI(c|>@su Bcgl5ōN.΅/) >b"l ͒&Ǵ (G]_n=9pCs{ WFLGn_'*)SnuF*@PMlt95a4"WD˷Ɔ )i(!մ'X_w-e%Q3hSsZ_V[gjc W$%oa?u('L4Z,Gw*HD=qsk]p  `C." 2آB}h~) ~* G6 &ޜO*E0l%WdojZ8 Czņ45OVc#H?+u &7O dGuxdT%E yA)"bua%dE)6Y^b-Vl;;,hPޓf8ߺ&e$Dl=,fqu@kf*(:-Yc} dӳs,3kgV+ǿ낶ȓCh܈-pze2Vjv\ "3f]wI53ǒԬsjtRK2)yc*?QYDU'H}$ipZ'eU)XS:PQ/[?޻QF$D=(=NcKEz%*P] {g@lY5-eEw HSurqC}=`[R50׋:y#dR%cGQћ=l=Rb41P0db12_`w'aD}v[|mjIo(4&et5n ~&FQQЙQN-A)Rhm}r3VT&6q$6%|CUvf^)A#bWBr?B&u&#}Wn蔴XrT]'9*[3@Q(E[qpK$\¥}0};ihL||ss&{~V/'3N 61,kvHi ۨPcȈcJ`ᝬ&殗 %?uTl)UNcX+U쮤?_=~/ẾB7k^ GkKE^M^_FfEXzA63yfSศ,&jf}ʮv)r<N`'&F#8j(PDG:dw 1e1Ɂkqzn:HͷvV1æY"Vpr+ʍJ{{7yis5.Bq@ӴeiWgZm}u97XVs wV4.g&/*|h0.D rYkUU}$j% 4-QIHn(;+q(f8?F'dՕa!hw >CĴG@:bF|Gf~MR;n ެV] 8Y-:b@M&W 1:)(V1KmOV@MSA&kڋNFX&ʝ)V [R30CZeVD=[!Pln{6~l¾ }ԃYʤ}x*3(DR7 /o\dE>?$oXlʫL(Va(Š~U菽EgMk !g%99tdunW*4H8g$]x_lձ5Ibc k'1>!Tj\(!Ѹl L:zF@+lh3}~:trhaRq*%O xWsޞ_ Rbc *9UE([KTx&&ՠ"n>|KmK:PsDeS=n?b/GMs" 1s%V@ )AʹNbm26jl-m2qW?>53Py#i%yV- Ϝ࿽~l;X8]d ʞp'au,#crgeDq г_7)t JAM w"o"&Z6;̨;IjOld *5)u XWޒ7/b lfgmy|ƕeAR\ A\;o/@ DroQ B,ϩԍ#a7G_=GoֽG;?Mg-{W-\i F-|QZb8mqz"2JD R_K5> ,ij` e$Rm>RԡjJK!V:6k} M47E fv^ݘyc}׍<Q w)UA&ǭKD0Q(|[:QCf'pw>{PmHǐ.1^ @ƭt!m€j*J[PV.(&$G͵8B[!(C$mA q_6@'-,Ŧ\al^$.m\<ǒ^f2cP!>Xel8WVAfnFws1,V;gU:#esEV*Ag : i%ޯ!#plU "1󙄗AT9o=3ۢ,aIפTWV#,bc}z- 5%$kF~> +DC[c:ǹ (BO\:1V{)dZ"]%R @ymJ9sN=7fa  ])TCW5NA^տO ?=wRo0.܀\uUݎ0nnHdNh[lv"Yq8} U )8`wW!O`$g][C-Q?  L/Rvӭ˃ yZ`s<`>3cT@3-Ԍoܴ S]ܫ_>Z>`ceYa9^- 莮ݨsuV8 SZa̟VXvAjca/9 HJ/S)Jڴ ?[DG%CL'E9k-~h c;A^`}HesZC zّ^fb<(uSQ@ VƀI R2^0c<|'Q̓vk׃„VCWƬgI'c[~5N_%WAO׳ $`% dmʕAvj$EB1,+I=W?rQ\þHIU'*>"OYZAnn-5|gwM P8>QTaܕ7?]miL047|G~4yҁY0dۜ( 53*guA7">Saʺp XQ~?x_tQ#\{SuknQ ƪDp|ҍ\RfRUOSڟA#]*Wģqyd#CZzZ%9?Tv9(g1j5c^lHP4Q\7룗ϧCy_Tyr{.RB79cn%lU \ʵes$IZ8lI%]-CyIPYxl=޶yoAsƆ>b)V.{6Lbw ?e(PMhk|@|>@}J{ =#B%.LNp[?^EFADeZ`fhI G <4œv/?: f 0,">Y-/-N@A5.t膠'do4m 1T7x|>W}lcrY3}D::U-Ʈ[I!ר OSNutb{T)ibUsրjQ>fv t"d1sP"':|zNa#8l1Dv2i l=iՋϪ3 _A$A#tz&+\ɅIʯmV `x>bFjW{>$W'Q|{Lصޫ`)([۔YՄl>(ybwjs%!SCxyn*3ŨK&rWmU Ƣp|X#5 dEؼuX F 'cVn[OyA%jo'F?ʐ5Ŗ?6M]3ZS\R\Zgc )TƬ DLKz@bZ_##sa5(1ǯLI[8{44,3Z0H%`VILY!-?Œ\٘kU<ƂWwyҊMx3Xsh'nsZ%twZWri$ob'(ֱc(׼={ 4mnm]C'Z}_Gfu|Ηz'}*@xԎFJwBOѩ.ŞXbSJlܒp6 3nXUDA㐒Ai3l'zǑ4䍃N` ji\ͅ1{{T ;F;kCܳؕΜ._a\iT`wOm96N48o@PaӞ>y<v(|̃ )E;m7 $L*5U=ږ7%aCE''dnZ;G<|LRƳ돈\F"\7ЋZ͝I]T"ިq3p;W: jqg;p Ł/uf4 /# a3t#>F.g[( ;q-tjdb'*wz:…%ޘcl$_OgA saYٹ@B2ÿM5{zu` RLXriu-ᯬb _K{HBZk6#5+S)x~$g5H@jy!o]݊S]LMv ! "qpɬ>a^d%TUCcX?pa5lyOJ`AVLFzf.7w1#3 ٗp#mI hBڨ@n&9oQ^.oꃶ^:2[n zʜEo87GCt n :G[t Wuo \͆ۓ>g6V%6 9r2Q)^|@.&+ۀ]όA"6W kIF {7H6gMm%c \3c_Ob*Jۖ! Ed_暲x sg*vf&Gp3 Zlۓ$<5h/N@+J ɏB}uxOvHgEq+$s" wnNiS : wWՁnuE>F 6;_Y5MT$=d=Ó-5my;eOW3B6tQZ1B1-QiStYE}) s:".kIvJ@./Ҩbp-5Ng7&RՈ3<4gDJzK"B֧Z9Q&NJPjo~AUs9ɁBfJ02V9$[st?Sy0(),gTnEi4&v__`zl-3dԌ|=?2cIG ћ>ޭeMgчNW )`c7ct7qWNE P.5_툘Zn+£)aReˊvD%St!TM_Kc13Xg,64QJB&=(u-C?1ue jL>Dx}ľ լgv*ER1AfV ]7#Z6jj IXh/Vфb.;G_=ާiCbu̙2MZ}a8!SW|7:q<4=;VRv,pkN1lU̴ʡ:<٭R9 >I {9l Qc~},(p1&KVKu,x@aLG K~FW{1 K7Dj2"71 Ca!oBzd^EJ0Pd;d Kt;Z2 <57)fN>x'ឮ8;fijG)`7'h h ~W{ua1c&`lklv!:UIpϲ*'#"pP~a恿8) 7`p&e?˦DBV3)rT5ރ ܴ5c H汓#Ez޿1tk9 ι%]kޕ,x0c6\Զg:UKNX U娸;;o2>ވȀ{][Z0$xzf&KG$wb D -Fb`%}"IJtNX2=hjOv^\AmBYapeZ5iӕҷr@6?jzhF 0[<(5WUY (N%%w*eB+ ũ:,J;z%$8=J|A~򏠐!\W魛|Ed#@DXݵݮL_@yLd [۪;cҧ6O颹3NmȆ`xeQzTzq1g o1~i[-cYΙ.P<$/)D2@kgoZ=nv} :)L[:X WLxV\ƿAE/mR#AmS~] v;jCL]0n{ o%t#7rI7xG/sb{*ދpl 2z/[uј=:2.eOTm(Qݫ*z}',VHq<]qȃ:ԑe35DYX*)c?k[#?w F3${BYvFA /~y@gc!@;`sFC5*=Ӥ? F% }-S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP#':€ iz_|$8`>o)ai;;tR6I3^Xҵ$?߅?; &+-^z-75%=.=*QKpM!ݠ\zKoDg~\H1& 8Y.{YG%[L `V-Z<Hli0H!bfD NUX??v?׀u/x2ًz vu0{X_Vʵڜ/Xk9\Esh!& ާgo-/VR~%y]X8M1|k)Ƴ5(YN{y_RT[(vɯ ^ 4;Ae9 dwxb,dD y':: 9A6M*+%~ɂgn6ݼ=-n]ֱ [NڧSJ"e_ j҂ Z"/RcNU҃:ҘUNcԲQ,3\ 7>iٜ'9Y#z(Ie2޿TO*eNPZ'@Sy+wsq2& x::WJz |p2` w"&jZ<-݄MM*bIaEdA]¢οh ~s)Z괁>`&Κ.=; N gͼ 3‰  |<>(hz=]^6rBm02 i_7_xm+7 ~>'v!i5:<򓞴OĴpv]4n!>(5d ak3h'~5(:"FYnlWM|`"~ D.~c޴͋=Zl}HTwkɀiȂ9vF[T;zf"o6<#hj")7ٝ]N8>ogƤɠ/)> u=[imxT _QqJţD*,9Y8`PkKTp=uaZ =݇j.0E {;R鎫^DrVϘDK}q/euׅ͓>æuz }И:Br5#r3%SaON R1 ? `Jc ~CG>5~ɀd)B/}w<&;qx,*g(U-2"ь=?U7TA&i\ Z+o}ˆd~ǯUZ> V[iu[c MK瞋8\c؜dbJYF[zo>&5k}Vhއ_>NSÐ(j KìS*%܌fL&tPrGúŠn\6uA~\"HjDai֙$_Gyaϴ(jgY] 6rKcbP"+^?uiS:|vdZ2KVl0vU4 ;rG_ 2|u:Ƨ~ߖNs F Be&N$T+!Mcn\Fe = e zdPYl5*j$'&^+*[(kubOEWpjoKsAlo7_)[=\ԕsR|K#~#j<~۾Mqf_A?Cmo9鿔 9BvCk{kQ~KAX\R<ʬMú'mrv]KOCڋ%TpAkeN*axX_3"(S*T, &mWysמ1n54$mO(_ǤA) n ,l@Ȓ=:zEO)DńtB5iDlޒX*qG5|FV^5|jj=!0 :{dlց, svД-,Ų1zLw "1$bHZeT*gL +ad0ZF[ x Pua=B|QBv pHʩ?AҶ3z}@lq?0n/6ds> jD(W'B195`V35I|ۮ&X_Q錌.9QdYY) Zk\? p?7à.eAkY,,:TN"O `O1b#bZ#O8.>4N)aB#M7π?뵫9H^uݟ#)9Lt}4*ZQu]O2Te/vqRUl]]BYfs)( {ܼx=Ҋ/4nvO`eGS¢Zvtl3-3o#+I0+NX}AP'#1Fǁ/&!6*#ك@wg7 ZP.oP]OϠzN!:*;ns./ ObTX9bA-vn8Y8X>m0%᪃<7bo=> W"'Bi<,v@ J vkyz|]Nij2wkBSxmZ_C4*y'|vbA@l!grߧN1Ł4AQf"/+-r̆EzH+Rk⸁]JYHHCg.[3]n Q8?]Z2\ qw =>z5)e#([OL@wu9"`xF'S^;7gX ʵ%Z(1ʠhEDmQbF `{l^C[)s=r٠VP#+ӯ@Ŷ1~h8Wg@#ʘkc?z3u*hBLʆMq\$ ^apJPHS4|mrp|ݵJv_W:@%0qD"⚡P"p$x8#

meHub1Ѵ;J*9FY6Bl8iJ2KI5-ڍgJJQqk+m+匙V &LzpZz iJ漶+ڗۅ6J3w3 1"=~ҲqX}\){W6 p-4Rˎ(2!zPMǫkth_)M\M^gtCu2q,]-cܧu#@'Fտn"ކ?$C1M@GB}3;Ul)q?F_8HQ||&||cM>*7H<%n*}Nnx5?'s:a%5?_ipLN*=$pXKR$˨˿*dy vySڔvѣ cO;Hr>mhZy^۴RNǓ7s(dL _۬ܠU?r cfeyw|~A5uf>&_|o7_QFǃ?6;G |sk|x^_ԭ%1)5-+wP!B(܊3ދ~0`d*b&C#P pkw?& aj" %`B0iIB؊b؞{ HM2@#3?Qn|8WUΥGutQ!,QB}RV"j!h= (^y??3蕮C\؏6T{߳*3ߏΝ7XIK(mlpDM+msj}hփY >3{ x0F[8ݪPOWWOVO_=?Oc Ueʷ&C9SϊK c֥+Ruۣ=|]7KcӃL]-@*`,?꼥JUK3KKx1Ԋ!Ly"9뮍Z<g{<(2F &k{Y,B06-,/gvA(%hv^sEihZvOeدԅK"D!^ګz>|V92"\C{u~ggWHaz|1X4Wh3Yf / ~AbS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0#ˎ/)џ:,| d_ kDg|*:p&8o`}NgćX; lH,T\Ks(|{Hֽ)Y~ʨm6l#z,|;,@|w !e)y^ {vb C@3&MKHD}Yqv1s-b>3/D"gDO3>1dhwfEDls9{$TVHk-a3a*OJcuaAJ e-$Ѳ*NPGLl&uᗧ"dc\*)uHrWg*Δ1OOI#Z̀ҵ&J"!:HW` 9۟). UƱ=lJYsa+@f'f2χB%'< GT*`P-lxŝjFfA&y'BeN;7~>?0 ^Y2'"EPשğ*w'DoM* oZ0$`5 \DS/[14thE9ڊ'*7k19q"=kC yȻ ;﷭4X@%c2hhjE-}RxH' ކǚkGv/ 9 5L""G44'ruhr%f\ aR93fn@D}H[ xhDF]3G$@r <V"sCdk*%kLf!0p(vЉ3+̇jρ*L|d ^T_2`JQc3qV8ƘqLщ;uRRWb/^qYnn kwIBGywDPƏ_#:zҙZqMNa(cWlK$鲥 Wޑ|!Wm G=9% !1qw_ ZА|1~ʫ3'&阹lݚjt6l iaNO_>xåOtOp#6ӛsX{kHR }*BUk5;&W˷>o&Tk<)):ܦ6&t.(>[ե`j+szc5TWȻݧ}1y} ]|ѫ!ISszW̻CE}M+q(f)x6A/yP]S G-Mã) D 7 E"|%a;GsŖfrkMN)%# !6עGfŖӯ`x 5JV&7 xV1B@߶DI4ǫy)li tk#bXq0O,O;| a{Dr p#Aa"&䪋>Dm5Z.g RZ_;X.ޏgitR|y,\)Գ,yD:/lJ_gupTR@pB#4cQ-.Sݨ@ɧU,n\gNmipa0P~3%ٴn?s0-(O6Ș5q֬BųA7rIF U=YIҏt  pDR6vZ.4ن$%Hُ&<а˳36(Daq֬<ݾyd[~(ʓ ݀oU[|"3YD-C G-i(qXyc{"Tn@i^z$w٣-vkɷ,rI#9l_'4 e ~8amíXģQ?:P!cˈ[Fn9廎'+;3۔Q?ʇZΚcmN0,aUi.HnqHBT :tKVf9k b#T GE@C% p6˼+ ɛH&Q5Y)~DX{;[6"2@hI#'M~XU6uo(o 31\P(}j)dIu:إA2kaM]jT5kX-mNI3*햻Z\ ¾_C~])e{l:el~>C_*%_~_ZBr`,ݦ٤RR=zG]Ri/pK2#I\6=&OήsK4h -|샊ON̟ e*p縧JM|='a.v?c7hkmGfe%-7#by@):'߂Ol,NxY8HD8"sh}i 5$ +ח#ί~qJc53AJH @ekl-1R%.}Nvi+ҳ]j#FAHM\LU0(k±y-}2DZ88a8pBnIc0{+<Ұ1GV ݗ H;ҽk[NSWRD6z0VOas&{.#}y4fھ˼wX𸥆tҫy|4 S=soŞG6‹oV7@!BC  l9`0ܔvʿ6Lt|2(X9;t܄6}u8{u7ob-^E8ڎi3(WDW)"xAmص:").,d:U=FC^@. a+{%wGdTP.ƣBCK dyg"S7 qY# yҐ^ɯC,M"dtI~ W5Dfk@bf&i gۦGPXP!(F)* TUe%W_P;\_[PT̩imE2T}ʎ醙^Ļ9C2<ɧo <|.A*,tr LJ9A"N,$=XvJ5[)nRˉEy-C@4#GIf&އSB_t1*~1~@m";hsiK ]z2A1&`զR)KSzˌ"̞ꕛFGtPgC0\y}$yFۺs۞!ڢ{zPuzbL|FU ]"A&bb^jBpԪ3p+?u^]Yūj/ɽ0#w2Tc::. fTjCʙ dO>=@a(PY: [hkQg)ܬH0,&]tmui2fj%Mr6.Ip{IOky>o,S(1U1 ǼPTzD]y"?b˫)0nejn9UL~,:YHn?f:Њ^PSH'OWwwp\h]0p%+S\]mTE+un!kBHPc;q]iLB`Vsz5k-BWj_'<;59QD/lڡAzv}jr[H5sPa5!WYbʖr7xٮBDHk_^[fXt9+e׿5TZӭ;+iVyQlp>A`NA G}jQՁb9,&1~kLыW)3[\t ȸ; PLD$<Μ6įݯ 3T1[/ϡZKMosez9mpD]i5IqW!1F)^9\+I +UBE[ǠL, TeKTŠsu ܓeu 说7:B]6.UquAMj^N|RlqxjӂOY30hn@Q`p;j k*j~HZ'ME$B*tL{=~};#~z3^&ҟfH` C}Y TujvfԂNZ\NM1VP6=`f]B+ 4*z/AA^XhLAg .Y8W'` +L רY =X& bmӾ;9*-`cń_yXd20QRYy"YVon1j;u0TUzNBgM"%cQ|Ms>9YyZķ۟?O8}c/=6˜3)HVR=DO.WtO]`mh% rh>)t/d(tPJIGBM<92Lr&UU2UYC7Z #P{\YA(O6WJa:zI![\}Ptx)cnyލgUݛ5Wp9J ]Ą_~/mߎڹ&k*k7۝.ZPnI#7a +-Ԣ  tUӊ,GE]hFDLyϻ,aQaʽ^05yӇ\gc'k?\Λ;ļe40W=cp|H;&O]j@'|MM 菥 C.!G{r(8gV\cGl60zӵnI888ԮQHwJ {ۥ*vFS l[ĕQ꫱_kΫJ]{aLhE]@NJ5>pj,lc{SjZ+n /gB1H7DN. ^]OnMtn5˱ZՌ}B$k3L8WeCr9y< Ld" e;o_ iHN5$&8Z.lAegB |X.,d&6*& fR?G3Bp g; -&gJ`u4Ҍ58a(<0cf'hf){7}#]WDR$(agK] _(e"( xLh,R&-Š֔Ff9\2폖ʣ ]ʖ}<݃XmLs:xQ(nz\XfA2q&fUb?d y\uuB]dvXfUlZi+9',VLju5m,a]=utF~b4Nj %1+ @lRzM+H#1>b1"uDt5A-2z`Hq7rum `)MU$hʅ;UZ.)>0ę{Nu~=M'7 '˛^ ERLc#6e u*6(dsZW-NϚ釋58"WBt |Kc^BfʡS51!35>42+ Dv\b"L-qSsN)*A>8|ZC]-L}̱Ц)|Cr`lijrtw4Xx4acxj"zL@DpzU;ֻ`mKY9ħUu:Hqs{lnZ8ijq(L.}a#E,Fy&>NjhnIEow ,[fdt ڛ_(!Tb9J2xH8xw\44*Lޑw/6v+B s*`58ݜq ^m7 `&3佦ATTnLЃiu:Dl)!7 0)ܺ$O™s(+HꯆĩTocvfAʱ~xƮȩ)*oϢ$.|O->Q>"0GnCakޯHsZ:[)ѓ<܏cK M) gkF~Ck-:Vf>6|Ѓt$ǚo 5 aIA38~^}ޥsi6^LA=7>u5rEcu-L=HTT߰W|A!Ggj%/6$/Jg+ߵVU: xy@!Zj8,0$hM dp0krz" v$-!lW^-6]8VVTߊE?k=vB;?DfqryQj Qn!2-8S\y^ C`+v=pmgn!ubnuk->`x,eVb]_I%1=k|qdZBton%cB{[HZ XB;k xƐ IE6SWj_,j7_ۇS`8?4GGȧ I[,%4x{l *>t*Da6ӕEY6-$&wONzVȞmdpm-F?>;L}2ҫKHu߭=4Fz'Wp^lX:-M J9<_9Q)5C 6xg[~kn!r|Q+r=@0trI'[C*Z/1|Bo͟7{s^sع ct{a&Tpa: X=+rs+mNHWmp^J?؋(imi;|i O2QK\d'q (q9P2Uښm'Ȑ,!rc6ʋ+Z$hs(*Ζ9M'}1@F>vD"@qtrZս߿zPzZ%"0i4LiߩHFD4ѭ{-P3 7 b_GuC*֨2V9deR(?CZU tB{$,?CSܞS,r+թkv)|Eƪ ת&, Hh7xUcc8x@ ~ÿCߐo0C@T3%8W?Cp8FsӢ-Syf^Ӯ Gfݳc!,2H4>p_S ͫ)3DLe\$F*Զ\nIIg(oS?0|V ?{YL Kr2Ssq3F5(I:; zE87b(+z%/2c) Mn㏕z4"__DJXXٹdJvWןa;LiVaNBV{rBS#Fn,z(|iZggNi~5rVo; !nK7~"BF"%:Y.8=ClŎmInBew-ԟC`(筂4Q~r[G Ǵ;R4l#UE]S';zA^fmݘ[/F'6lѪ}ԀVxb+۬6h? ՜{-~V(_q䆇 "OKb`jѮ?/vP\ɤLqZvs#QFciCkt-OźsͨgwvieiX  % Q+6'S.I3AQ~TK=@#rj&*l($gUQ7] z:Xɍ wSVE+2 f$GNjq/SCr9,@L#f%#vWe lcUGJ!Bewa/zFntVG _WTh_Hlw}ߨm(J .qJe_[} <"m/[{ HZZ%1o"u)d-WRGhxzpbQo5@ϝ|kAV75>UOotrGtlvH|aIc|9L|y])-i["ɰ < B:-nw##_ܞgɿkI_OF-R܇:xB^^wGS£4% Ǩka )\M*0s㭝[ah~뤘R;x'9e;vJ҉ (BHE[sZ0N{0;c"iP$xie8>$C[p0`JNvj ],I8ڸ %aSL#|Rt,^*Մ^Yuֳ^) 4 GKV|wxM8zȀ~, $D~Ɯߨ*lt~LL)^Y\嗲4oЧ&V&,l!`cJuP>5) =۞gxv7 ϕ Iࡥ 'v7ϝXEO\ٟBl?pNZ  6;슏f `VN~4-:'7xqZ˃dEdЁ[5ŝeY ͡/ &,r{S FZZ5$=jqac ns8ᐜ|@@5XGSͻ?ree#¤^bSϛ? )yE@>}~|iF##kzf䞧ۤ>gnXPe  T%s;S3UQ zAYWh?^ٱ֎򓐅[+sIEh",b®Six-‡k騺 GBJXk* !ZS(*T" $Y_0KL a60dm((i| cLDঃ93bFVe!dDTt^0\ XzʎX.|ʵK[hV~n%mqEI8a ;`lvlWJZtX^0sM0 ļx\eYNa/A/eQCgcs \=:e?^>]u@It.&хʻo"?$\{g)q"5(k㻙vq))t8z-'򛄉{ vfmт_XfhdNh}*vIg6)S΍V|+b [&|e+&Oj& a-ksC䅚WsԌ_+IXQLww<f1 syThJ a%5; HU%^< BCs3ڔx`EMՒʄ{<*E@@B{)i1[wo/Br^jAowb\(u={Q" %Рfoy@#jԈ1~SlSA|ty;XJql9o8֕@G<= *d2,[fe]ͩlJi^ulY~'V݃%čzٮʲHxjB;/#(2[4G I'^kquV pvb㬱z{'&÷xO}&]e3Ԁ<7hPvddGڱ\Z0!?jY岯fOl|ol;wl$}*od ׏2niSՆ^7ݧ5}d=Ǡ /;OZvc |Wq e,\\V(Rн55f41XXIIs[Fp-mo"(g; SQȣ@vSy%hKQj'm>w]Ŏ9&WlT@~#nҰy.A/ܕz-uilp~@ecTP8N,J|}aL,\U/[\A9Z8=ǶǛ_ىn?EE]XŋްS0ƮPG2\hz^s_$vMX.@RhRY!v~_x}b 46`_}3^sЩ/"*FYy&/ Q'64 ̓(PM 2};l9r+urk߽@[䵂fsr*A<}J';k_#)x?Db%1 [%7NZBZ ~vA]YsA+ӇB h;E"4wqb!C:$MG')*vtB߷ߍ͇vKۓV.j29S?Cfy,V޸ (NVШ , D>LILTwؚ`1feqeC w{L6s e~mUӽ=>x'~lEpo_՜gLŵymIO@% x 7y|2#5axW[24:ѯXrUxQnvo gL4a4;%;YrrCl~u 1eJ=60BOSYZaC8~|ð@|w`b*=oԚcz9\NN2.&4b]uJ:1a}뿯L<9Z4; upWI& ݁R)Ƽ"2j2nR/ רM^S_? :;mz@yɸ3 ˌ`/֥\D0#r8fW,X]E#Anb7f4[ _5um$^j ';6W4.3D'tN}^ S7C?n0Ļ5;DŜ>5oiG"~(^ɦoC58KQuZFƄGs=*2UCZ(Hu[ƭ8cx︡IDA7,M%V^T/i ߌe}ۀ T P5Ve!_cW) Șv9\IckA%4&B'Ë9!9(O")biDB;gph莱1r,P]x?/OW]).?ree9N)`l ZjBtsc?i6T:an;* >.2^124-lc$Al{t(vo9> X."fR7@ #QJ^k|>t| OquMQokVhGX,3)'(s//MyRN- 5bo`XPK"+MV+߁~>X[g gqutJJ=Ak ٜ5hFM^!㥹"Y@<%+]xd_ek&+<7&S#ק <ߨ[Iz`o~qz 2',-oJQ̇M&Il>b-PX4UWH׻n r3F)hVw? Y2V,|]Br"8?BԦ},㄄F0aʥ=`0 4GkYo^ ^,.e4/J2 &Q7O֥DK;dd*T*ӢFU7x*4>ʏ1.Ih$ˣ҄O%}g-9B'vi+%O"IgȤr#e?Pӊ>>wtƮN PF/DTE|7 %[&C#9RO 4Cy=AÛ ,tiy'5o-3She;BB="7=`c`4oOy9bs׉+ 4(?ꘃc&bIE$!k[*w ϗ5TOLqX1%vDˏ@x@<6-܃ k#/Q=RCOjkpX3d:g?!!#o9pM-v]_&4@Uz>2I#uX-?2fn[K߅KF!E(v>T G4:u^i_MLCN;F pyV3Ρjopы( hbV}'bM6hF2Gujj847X Y܀,c8j74+ּGl34L9eMw.Y!vs̻G)ze 9>FstHww/۲t|5mM J'!.IrkeOHRD̂X,Û5dO}\;ghWV˯}q# `< {}x{[ȎGx)P؊94THDÙW/R̈́Y$n'T1@oѽM 6|45rA>۬z&!B#ӹ44#`g|i% F*l]&؁;.h "={kΥzdL#Q\]뛲u(=`Q ;1~XL5,sێ >z\dy$XM1mVG &R?RnjlcM MY_'|J#E!_Grg1/8~mb2W }fA@vƯ:uX5Pɖ F!Snr%wpwQh0_[I`g~}gqK(aa ?D͡I-v\YJY#.Aԓ]'4& @ߐepD׸cogH.R*y&@("4@9AϥgZOx4kXKvC}9푧~u4Ƣwxc{Ʌ<]:2Nq2'q{(<1Y$xٞj`una[35JoMO+&yyzspx ם עQ6ƛ"׫`MW~j E`ۺҏHԻG! $OmX-L8g5HsE6*ӋtgxX;FsV"&w % D+w׫MѾhj9us32~K"7NKuUSpৰuIM;4[rUᲮ0,j <>i C`KQLhnղ7yzpV!E6-{+L9OHb*66;:H3a+BLzE_z\Z<<:}2NA6 X׀ &02֢)мR-8_ऴlM%(G&ٗ84;1z%͕b>mvEض2HCpm-=U׈+MEwo%-s59Tς+^D Ie!C!:l$Aq.hC=&+>f6ɁmZx0il=l>˰=ZrUQktq8Z"Vajl( 1X_*}g)TL6KW\N?]y cY3_Axl(S)g$qq@_;s iW}q>G0-M۫z.I'O^2 #NEW'}0;n ))w- }WKwo.2,o`?`|.=c"jض̚U m$OSl3ۏPq @, (*}{^!QKؾûU_\ ,c/c·Z9 iHp4fۑi\;"eIJ$2H&bZS'㾰g%BU6 U4+O6 `1_ܠAnnJ@u 5J rؤTY[{+ ݰx:ҍJ3X0 kdD&#/u8ի8g@{Ŕq +`k Lmj ,XXU>2Rq#*hːyɳUE^Ҝ WB ݳ3W%R<$HFyN R#l~U^^q-!-P|[hm3 ";[㮘1}UW;g_`$s ~^Z& r mz!]ik]*2}ER!I;a/͢L*CFh$%*L\s?N!"4,-x?& TSv.~yk_j=@!VOIQpCIv(_R/%eKi.usu#JFձJ@Z2.FP˕.[tx~lY8?9BbW U-sE/.zPah@f.aꘄچv6/K~ Gi6>h4M5=`]wN"ZRJ]ϩxP]%P&T~I.g΄c4뭮O~cA#<v8Ĥ;)IBQ_D!Tn%~=a 뉔AMkHsjEո 7iث"iRv~װ% /Ƞ(@- G5{TY<[@baVs |}Rgwoؤ]=8nwP  U9o'2ax 6"a dp-+)xhNEYgXv d(]->ԏc` ʶ]u_5K= \*+`g@dW=UB0]Ȥ{szXaQ%8rp@aXx3C{fޮ: x 7:=:8QeO;u !ZZx2ϛpkAQ@7p%{B5_,7'fjg"֞@pD#ƀѠA<7ͧSO>k9I×8__Pp;݈BSᙒ h1T`d9][,xS g2sJGtp[P,9H\N61ڳՁ $),:~ދ.Z%"ys[+tɷIJzoY4+y.¥fMo<@5ȣ&@(Pvw//|_|QrE0"uX]V~RL Y@d[ 0! |"d $9M T `c|U!{ab4ZP)j QKdg|8xP%9 'ź33@|i@Nd&K({4Yb[~tvZwo"\> P<5'?V<S룩vXqHLtn?/agQ>ҙ̂d7|tC|z hdMҌ4&Wu+ʤYoiлiŅ+u_1L>>=B]"z%Ve>hge`CXp{W-t]|ϭ.F?s2{O& ĺrdv ZN=iN~r>V),[& 1g:*۪46YA.!-S:Y@Orz0XkK)%JfobB¥lXU.d̒laY{oH, {o]tpzIjl#@G,5WކzPRA=S>z1A>_ Dވ|oo.QŰ;NXMh7JۧX/fOte=14eL<D57 a3ςʒVP2!XtV#Hmď= oE{7Ja2V-Zr64F\Q6 w khU:CC=;cb}%;wl#iu_jŲ#bO qq`3$g**~?l8ՄTF$8ή-zXŝm^-<`-.:@'2I/7˯iqS˘eMp][DR @T?  L̗w O[%nW˒f(3*OfӂSBǚz r,޵x|;yU_zE\TC؇^I! n1u/M'5Ȱܖ#}ݚ+PtmWkyu KE 1T/46]{CΘuMڬE0S>-.oV !N D~y_é)gߚ}`tjmzfj >F$o=`8c@ɸ/(I3!Uȏ'cJ}&+7໿ HISRp oaG\ܜk䱀 2XΊ[. ~_. տ(QQGՄtID8#zoX@#ׄq3tZ1aSA (OXf`p:S6hK9FRkf4MaD(hqّ X:6<)?v-n,_ aU,gW̫KI-~MMOE!|#ck7@S 9?/\0=L "u _%pvҕP[(*Zώ ЯJ }Jcbƍ] Sᦎtbw4Fy޺0 =5k;sT ^Z%/I^вY4}') ڜ\,MrTPce*lDkSq#T!+(-iiyj6psPs=C+xUat!}7Cs_tEp._|[a i A OX T 17ߘK]J1ǜ{YSB,!J$uFVgXI-5?II5Y+zr`hjy{?^ݒ!M,pjimyaЕ]ZLm4+FMr 4F {dy"lO+`V;te\"T)ޢ=M_2Mk130LyD4bOȄdfu,*z5X:p+N')7ydZم45w-ˌTcub)E .vbmʬ˻GPH잣g] Rrv%Ϟ> V9lgUϒFϧ%FEPSbQ4vbm .%i195zPfv.`Cvز]kaEXK ].66TmNMpRFЯ@Q\*ꏷCL̩xq2r7 L8/Ȇs(h}5glm|_1m'2m$U` +0;8>ET>ξ3yrtBr`J=k%M`:E2  Q̩;D8;"K(1Ꭼt]ͥңIZK9X ,-;N={0m7T&|q=M'׽btA,]U0GUiV4mJ읹^>oꎿVwr(pZ&3jhkk#8#^TH7.l[MnI)x)Pu|W'*Hs RK--pZw^Ts-zbS\U ޤ5 JM5o:ܯR^-3r倿X;I+רIt7 F(e}9 b:G"Z'нP@HaMD@]$=N _fO#⭜,Oq*+V [(ԥn#@8;[ y ,O{PDCq%QqݪX[]VFԞ290q(҆ OiJ|'}aWh#3kqMsmòLϚ p|k ?D1MxE3 Y-n_U(# $G>%۩8;C2Ey7zև>r͝tuFIO櫒ЎC0͹G_}AGc=ÍJz*Ȉ<.~T~iq Ŧތ&FӔ2G)(2S 蚫^8٘Ә.oԥ2@sf~1R蟾X((w@,mr@)S_6\qub ZFPfe{BPJ2,7 ֧勪W_7ҎϸW!CLؾ3#odv)Z_SJ؝p͔ Ga FU'fHܬ1jM76(:g)%i;ȟO?Y& z@߉c͙ݝz{/$. %k!S`wf՚%:fSXqۂ$|I 79gV,t$J3DIT6bW aJB<129(B%`o\'FuTVh׻ f+u+((K*A|R"bmuh-  ؟7gk0(c^m\HXw5̯3+ NL<ߦDi*FAa_9%8||@|c#z҇\Wp@|p6ףH/ [ ) HtiHzۖ$bc ^«$ ?Fw n CP,w"=$ ;8s jkeGR ?|H|z$z&bsU(bp|9 QMdjk5eAj) pB͖hmdc$rlDJsr[?C|6+f~I# $}Yp]c RT]w)ΈxDI7m c*n~9&^+g7I#?jh*m,ZZex Pi+oW) 5QjC!< i 7FuU ?Ҍyp7JC8u)> Ky3wM9 7*f=7H*| N j|V%R͍shMs\zrU#S S\ó 0:e~*o'^Ò-Kcp5IEq\BrBEd-ܔ8H_OM.}Jh?mp4+DA5k徭im蚓` E =FdӔOu"*9+b̈́3hs G{? TCQ"] )8tu 2?-DD/_Z %|[tXZY>J!Q*pzi=AiI8'Q!7ŞQ tXE + ԏsP50P!gc4A GG'/_nGj֯N9#T[옆|%7NF}48D[ |9\2.a9FT*YOJm~ _4 `ۋgup u^4|Ͳr'~58H H4K@-QRk ^{Na6ph4wڸ԰Y!dev&Q`Rq- d e%H^"opM"47|:YIdmzQRedG!Fem}0oÝ ^ӍUs-ј״gDˁ㎉ \VinNq]n&Dw$HJ]`Q^ogRw0y'p*N Oy/. wá~g/iY?z?$jvKkU>U$RK]ʓu)Ƨ>?HK)RsmuIIKzȜ?p"0.jpuH.eg"6X!MX[$[!Q!wh>bzt\iÂ%AMw7S_gD94 @R$}񉡂<%b׻p]RUpFu 9QPE>E҃x`|̑Q*AG7ybcbJɬFɴqCYj6$N%W`i]{إOG dbTr%\ۺUlmt~S*ԜIhT(T$P!_u+L{/夣 < "z;NV郣٠w˝1GPB,{g.x0+i}+H,e(<*1Xdkz Po.$'RS9aB**'HҲuD:ߛj{)&Fqe %LFD2JA ïAtX2Ӟh-* < b!%މ/ C0S[.r$@p~|h:rS׊u؏XFs t>K Yu랁8~0w fJIH^)1}8P1/ZTE.1,k;n3Ew|XӜZz>"蛐슼Xn!=d S6:`ߞ [ !&7v"("K+TKu'tAHՏI;Qg/5J$!+"qn@af(Ϥk3s*·jl&k/"/YNqGrC n%cbE1ZvUܫrLk{&z LpHm[pZ3^#T9pɈL\t (&(uuj8?gM=g-0@}d٘e/U$K~`ӟRPjPM:Hwږt)v0 _leÕުS0N_ #x`,vRܢ!҄r'[0t7] 8 -Cד7pC}H D3 Ϫ1u ,[$(F艹`HJỳ);;ש~ymEPGQalXx-%(ӝR sX,,/@NEWĂ8Ƶ ct{'u;bw_:R8߸@T}?VٜJ' H4T~1d=H\ ΄zI辶㾻Kmc6xcuLE>9(^N?>u O~]PhsP5h6<5x}tkЗ z2 &d|*yPm<ۦn qkSc%y: .OKb#BM#uHw9՝|΅L;B{y4۩tt'^h&;idmtRoL'7ZX# ' _pq  sq zM ?N굼|$GZޜ}Jͺé!QjП.+KrۧЉ̒: dc'}vۦz :3gC.`<q鑖u oGad]Հ ~5Ƿx!&F4Bᐈ%B1b@(>hW$m'2x'kx[Ġ@T;EL`wS>aGee՗Ƌ'D|eVB 1آ""R- n0I!ɖ)^k|)'ᴧ§9-ښ)=0b2vhk.Lm|P\e{RЭwQ;H oiUG9.(/gwU= -snJrmx{R+bM XXo)M)ɪKLmUVg)w"A 7TLuK(?@0gn do~/lgBd =9g1%)Vz^^JA %hN]O`ڥ%V#ύlcE=ipPtX|?աL/::/#8@P 4H@0-p%>B_69B ;m2J(eh"vn\ŇA4SGYkzlcjk$M9UE @D!{yX)&|v;6_ ?@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0P)$I:4@R$Gt(79Vՠ0vHPlk eZj#*NꟚ J҄=%XE9"4 A'd>e:|:@> .G`5H@=f/(KlQz19KSUTV4P^{f1tiBLWMLP[S1P AdLc5dNkyʵ%X Q"6.kl!6DNuT'דq)?L9=HKVʏ%9 $ tD?T/>nB#m#DN#MQՏe2>1Iп/_zl4(b5Y-_hs$%YLAP133lXsޔ 3ր|eh? c_F"ǬOdžk%At҅B*w#Ax!Q0<4i` &t7"?ZtHdV} T͛"⁎b7D#syFp`޲O 򩜤;WBvws':Hhlهw'{ v♂Q Ĵ#4_{.`U8cZ"A pTWw?ѡ,Aw{*um(7eңݔɸ|&D2@Dt#~ kj{^PT Ħ!״|䐱W_=@Q(uqno=퉙r!IHgyCǢKOC2S5L <ʫ㊺>\^OpՄم%9aI֋T7X%`臁gj Uh:K< ܷ/q9 }a(z 4+0$<:C5 4Y.Ernh}wGX/[ ou3?(NVb9[IJQp 5~FZ< @mFh2!3HUdM %+ʁm( amk_WQ&hݚ<JU\,FW$q+ٕ( Y uü>ZrU,죻߆1ciL }Pt[aN ZpUkY7˞RLyZtD^(udZH|NJƠvsLؒg-nT:ח  JˠHrq [a WFpnB["%7E>d1LARRu9״:jOC湋bN>òO؂i"N= + sޚk5mT^2(qq|)Rеe$} ?)L;ɶ;Ff4*0lV0IB@G{,yQKp4-?WeXJʿNi =w~2è^Z*G L,7V%7]Ɠ75fmy6 &9p#Iy}O"lQv4s4A _W_ _魁:7o [ Y9G [>Y<{":tR<N/c1 Py X'%4i~Nc7p-m|ʠ*a6=W,p㐣VDt(J_ URv Y|2|2XDLDϘg!s]). +/y|hhXlX0az}ՐA;´DKTofq;^_#;y.ߌVZe*0flK7⃕ʇ(-힯)c hxst˂|y7|A8 pX>[DxMb#L;֩rĤǬ8ט %6VXhH"J> Р,d5ׅ4zPN+ĕSw>.t\EqG7 ?5߫t-ĩGm,nR`>W.GKQ(V"ߞ Nu y~~ _<BٓsI._]W'ڨ4K\(oW$/ӻ|jz}1}b-U8m9m1ZH3F]aȬ3Nfª914'xAuL!MT]Xj( xI GF%\9\P@vYe/_^=kGh/(If#NJ9~a~ު[6XZJ4FT?V&"$B=Tl\۪ ף,PŽטh/m97JP:NgLv"!gX9W%q\U^}E07zu!$]1ƸBa-.Ĭ#c|Y)0,|QNKȰ+d=r>ڟsD"9_疱d!)sB<#WJC7lޓl`=g_ڠO0Qab?}]FCc=JF%$*i-zZۜ\Ha8+Ƕ8,Ig:⑇Yt 791ZYG_ME;m/;m3/FBfsx=6ףy{;׵ި. Xn Xlg3%ݤ)&@Gf 39]Yan ,VsY,)7l1R! I+p& yT f:e;~A^!J=u\viWB]MG@Zo ov,詾Ί?Y[6tX5K&ܠZf)=`}zUޟWM(l2ݲhFl;3_k˘ q![ؼw9{1k_ZV}mU9LH\[t^ 1AOzЏ1 .0Wdt}:Xư@͇/q,I|zi5Z)$ܢdY(fjONwKOԌHX¥3Cƒx${דb%d. @o W!ou#l(@$15O]C ת"H/vF@F :}ĞA"'͌n %] )o8up5_뷣N_pB˂.R.febieG7) 74|ԭT[:á DbO#3$A.W"/QtAts0zV\VH#yB|Y,>.vG#M _:-7\qZSyE+-YENԛbR>CB#~B;sGl^ \"VЪ0wքIM{!/c:}9'$wD㣋v?= *ޒchމvFH4r`>1z~>6Xif/D萑a|c}1b m]Eذڼ6'ۆj`pe/j(w.ҒkS-(ŏg$/ =E7-)erZXu{Ѱ,#Qwb3ȜAg[)Q[4;h2:;M>󏹇dri)pC?ؿ7 A1ouR?rTU?^R*r 95eS=(hW!dx~m%1nz*w04/"v]n 5 /3G 0()DX2/%~S1T/X}Iq,E v+5o'F*Go+蜁Q|r rʲSF-9>G7aBbBj,c5 SZߝϯ GҢZyl 2Ia+Zg@X )x*g`Ar{Hζ}-ǂbLsړ7 No*A|0;4,0+F-${cuj t fF^p(v]DҦPHD Z;d%r֛㤜d:A <:'rLZQCA,GR7tlf YP,s.7L "%,syQ+u]ti ZxK$?CĻsgnwÞr~\BPz<7ŶdANstq1qU5qz&_ &4WF&[\Tx%uwLaso^>R-D[۞@he]###աp ee>O%"6:aY 'Y S( 2p'DpWS4q6uG,=j7#k3 :~ ~;R 7Z-)'J@D]v=Iqѐ8'c欷\tBmDvbmO{xwnR1v%U_p .['ןIxA{R7#N|SO r|@8hPx!oSӭ/_|@|iAw"yQrt//6G0e.f9*^]5tO& E4$!ZKv0FbLa??>= aJc-s,zl;JM6Sӳ>Oic(])xT1Ƈzao &eBFu\XuOh=ACw^܆]@  gD3~2AA`F}@ !2 |Okb׵$K| 0K;1Fmh|۫v PJbς`vH/oLvОSƷGPZ HO%!p™eZo,}]-gƞb1bLҝ" hRԣuv wu%t"0VOḪ;lGyvGR߆-j GjUPxtو :9:ʀPNF\@BԏX|+HIZ_QV$G<+?k o[a~ C:M1?m9: 3q-?p#=67{6YOfG.$[am63B 8W9R7ҍl4VJc?ݔrE 7!lʟa[}YvKCig߻tCn% WFJ^5O:dL%ݽƍw0 \sjvn\=YyGW}Z.>Pɕx bZBFdڨ5;Evs  3v~hNzf15's4p z.4N\^D8$DH?JA#'TH~S\CQA=,0X'0BNJosyrG){MaieJp,lK赧5Hx*Y50WIgUL/xn[ _)ɂ3 # " bRL1b[moA%p9/i p%x~6\qΧ!y^ɑN2׳ށiV|VՔ!2jrat|oom l"eNdg@2ɒ޾"IeAH jj 9LGB8FmNj6<__)5g{K gFa>T[MI?\[2^H;xi[8O 6_ԅvQ2K*g;:˚5imvMJBgr0\Jr<, B(KՀU°-Gr8 ߁^‡j5bFD@^fLZJ.;¦r4=0|˝BLN B2x-z$; /5 ^d*E216O+ [ߙl,!Ȓ AܾdƜ7пtecU> hrV0~93'j*rJO^$^/M{fr;k}ޫnn$/J)nn5G h!w}\rbKi/٢N1J&RÇ+ս<m^[f0c ( hm`Judlݙ`5 Cqo8+_ʺ ˽HaKpm@ێL{\̀@܍hAJ {b;HwW3R++9RSr'KL-q6â9cBENE4\G#8Cj\a7t{!n[fNBܽ H`@C%~(jh1*u-^yq ?aϔ*O9&a|,=j /<Љ;xF@l"4AoK_IS[U{s >,[@ K/0$Qpu@7@Q£sP0N]Vi|dT́SWh-S8BR598I~H+so&zZUp1f][3FEE^+}/2?.|78psd AMK_o.k ZnLY w-1V; DgE3\5S)V:;}a }vB̀deIzwAs,=XL3˃GtZƷPSǽb2-nn5g} ͯŖ?B+#kb  {l}Ke\ip*Z䠣6EN~}q<D+ VޢZk֌-+U^%U# o |a=uv(@tKP8*:/ {8~^jGyIp@xJS@!GAS'f1y;/ 0Y՟YA R#wl?viZձ_ j=frb:BOܒR"v/@:jBu]^^t#Z#A?gb}Q"V_Ÿf3$p Q¸Y4UN,fsY{}kɺhcE(-Ew ڈ+ز>Ñ*X?Aم-@N>1p&^{jW}t/߬ԺYsImtSG~ V?F.kԃ)U8,ofY6Au̇]) BSQخM$ilL`%nF3_y$XCM_^iĂj)\`w Dĸkxvgؔzٞόeѕj:s>!؁_f}_yq/O\&ސebL9>O?;o5ϐhQCi;,aT)N6rU6[KE +0kSe3T°FU] 0@#퀣Čx]/sDI8WnA?|yt6"K"q.89 db4ۂVg{VtX6'E>Iu YyvŴon1Ѷ05TS4,݃|yVP%ծ| Vi.QR̊_(Bulq!N;ᰄɃUPV}51¨#zYS\J vN:C~ū?qY$ G~%}y#a75J )'rC;!yt:L]J #Iܺ[.`l22(kڤ4.BÃv1x=C+i/fO6|o7̹YEn%YnM];̶IBf>!U{^Ϫ ӏRlSYR1QChDfOEsT1Qv a}0ã֎#~2lJϗHz5c8>ѥZ; T#d|EY ˩W+a~I>X%wHt3~ eeje%'ja^\~ 3 v$LOZ3 -],*jsd.YAdL{ GA!QLs,CU/K|steG޸;|,~Bory&T|M-}q1mn Na KuE2&r3o,F :Ԥ7mgUoT\(ss*-K{ )bpWp(0fԲr#UyVx ^'UCMT[/Դa:2U늑+n6MDŽ3 I PPiBl 1kvờ0$Vkc3)-V=4Q'5 yJ Sk.)()Lzx]ȞU\*'ۙ 0G$Ie|dL'eughJ~Q&NL2~6U z=A#/:e =jA:IYVEai6?жQk śT KKrJbT6w!3@wbc  󄚅 S~IAW)ߝI^M0c NS#]!pML9ǜXA]@]0uyDD 1Gv:.|@:D,"Mj gw?)??\;?|0>4PPz%Fg~Pn%mi ̀X$#uP&)8/ c|Laj? 8C>IDI8̠ C_&- pVE ^>=#萏,BI:78bYPzL{5m' ʝtKrbй"(G(T_ii= {РL*0eJ2+hтza}r*>1-LCR~W!|H2*}GQs UĎϪzH憱5{h9A h\U$aҧہ^mOhdn ghy ȲpEqJ|-vtQ!я>BX|Kn!\4~IFQemc񞓻f*@>&pw`^T1N>iJ98&g֌j]EgE<{.YgomEx2;ggxgx}U%2\2__7_'|>~4_ dU@hK7ͫB-46a|O'9B VZ`Dޕݕ̈́8*y'nzc!PŰ[Z 4āx1%ڤG1 W :ayWL^E̙|z#-.bPtlP5䋶u}dK #jE x Tc5c%R.Ʀu&O$Т9fpt]0-ۏ,j]e#/LXtMB\lEշ˵\[:nsJ7Kp3^i?Lͱ`0ܜqatX-/OHIaAW8KSQ#AOD?JZs?!-~$1:#VJCab,]97m 5WA?V1(08R,7!t@X`ʻt#YvVo4ͪ:'.3H=E7y`؄c8{N5c?',}dS7q?r&ʊ*=| fۗ1.ˢA Bf0z:ՅLPՄDŵHco~A4#E?=N;ݞ7C`.HU3^A]V1ofx4FrJ-|H<դct%rd=s]*ҳ*/I9eI[ʺ:e!?ύ=k?/J;'-2<\#E"phu:(Ut BDX:Ŏ7)a/6/URÏ!FovPM) oMӅ/X?Y^fV6 E~y Sn ޟp9-2V{fJ񶃽~t %A:˩`IaErX %͋8`"Max⣔Lk6MSGU.<|^\슘m}QVҵC\JI]#g/1@y竱ie D)|^|Vrl"4e8? bV>HT8a2xq6.1=wHꡧo)`. !~ JS Kh *4w=镮2ȧ33'uT|f>M`?;‹9qW=rV5\-|jgmK Qr''xޚphXNΙJf^}/4oStǭbS('R\r<6){aXŚ9)Fׯib yф!I0A5|ph5h% hj"sTDN;xk=55~\EK/̮evj6:)ş6>ic3ٿwyk{hT"LVړ 28,#2K1 O8d( >q hV2ه?٭zr94d&iq{F&U\ mD;* Z5j>^Z氌0xMMFTxVM{ڠ^ j٣cf f3ܤEא?8+0gN4UޙBJ ؠaz,͂ݰC?0Juc14$GUU]w<Ya8*̆69OP4hQj/[NDzr+5Wcԅd# pX ? _lj0-ڝWIz&NRr&t\?Ӫ^V1n^^]ŝCdpbZݠ. `3𘣵n(tKU,j읾{# 'Qt5wtu= ;: GxncyzIB;M9SqjRHFQr8=GZ&s2Zk?f(+f`i 6h*% qlMZ A:9Oe]zYeI%EO}gぷj<^ /3>`:m\|$W'3GQoM*h_SUoƶ`RsX_idU2-I=_3aѢs΍{JGɜ GxB .twz#@nAMDP/ f$e@s$&[&Dlq"=<94[)p-? aNu^y:6*m}:…jًI }i$*Y[L3W6!Hޒ('4L z5#U^|: EՠB`g$ LK=A #ьWge@cc/PLTɗ<-Մ6  fRYR-߅[h! U]l|I@B,_.WMsFV&D)7zFC'.LF6y^̹[ICy^ .lB|WѧѦ[z*WwRXF#Vr-ìJCk;x`l?PV̸_9F[G ʵ?dIy;o~#j4=:W|Jb吉 eג?.ڬ $Fٰ /|' J%a PK {Q\xE_jqӵ.kC 7*2vBE>jn{)cAVy1Û0Ĺ/4W!fH;U0廗H2L0 .rC7"Zu-҈|'eM, }Sf5&].qRqj"hoNy,:$0v.qӓs C 2#7ON;Km_HM Ba@(8flgB}j` fLiR3Ib =?y9 I) P)2J.,W񌐩DVdAqhȄ͈l8ňtV , ܊4ަE8̧~V7Q*:F0sL!X |B!t!.|i:V5"'b9i/]'`u9Fzn}0!:zwGH44鈯ػN*A}9oոz'MKI{2Nؖ8ۣwĬFRO(ٺǐnۺW`H 5`Q.`CTճLt>@U }~I3OH+.1$$7 =qS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8L:pO ?:,:0A/|fC:>۾axZ왅wy mjEeYcB.Ӈlb#|> bhIJ09o<:zA;/.zS9?0$,:lw+HL(/M,4A'zd?{^IyZ*rZNs S|MMB e`,[%S]Q.ݯ^z;(l!Td5M$n \FRwC vD\fLJz~aoE{g~! fmK7fl%(W'[ٖz}dl·E YFT =lczFx8"hdi(}\z-蓇Iֲ"n4y>"\ck[^`R&Jcc)u䓩h WF28o:'xE@,t 9KpoPr(ѫ1G3쪣+ß g}JoƵS VChB*ӏ. qy6p>AFx^?[h`Ãzb:s"Ԡe4Mg ~X#9u 3?ZR%J?$,Wn%j//Wˉ3OMzW[VU Eޗ>q,Ns3ĎKEkO{09, 0Hr3KZnSHBDx^ijj]fϓpKݳ8K={S`&|&VPT V?ՠGC&} LgG{b>r8yfΖZ\Gv+7$+ְ<7NN'd=6B`uI?``v8]M \ٿoer~?7܀е y:/+鹅䝩=MF FP2\RlfB {bzn?;7gdMAr=cR̢MǎxT?JDXS$uث/}9aԳarڕziEЖV;|N̪ǩSl rǯق`7ǚE1pt[_aL~zxBY50P#Aά]*v3w왱3è#^2fHۻ*j *R]Zzs.5'y:ձaP<-ד lGMt_M(7n94d+тEcow݀pr[/|B̤#Ֆ6NG ߮` yqN(,8Fl+%QuD+Nt+J|t{_}8p 53a bϝfm}aq9zn "CW:˻} Ҧ2`W /CHW 1ȟb dBu3^9[}2 @b w+xWԌQ wD ni&-4ל.HN!^E$N&4iDꏷ#"Pma]"QO@)?GI+(KC?iM/ ek 1{E/5EαU|>=t>y\Xo+S.x8sϯm̅0v9PT[MŒʼnx**UU(aq4LJ^Ț'f[^ V}XS.kD"PĽI\VBh> w%yÕwQ5۲M6+H)"$Ն"xv)H.wǚ:Ӳ҆;Wз]u "gp DQLUT}l3)ndr%N {ԭ56{Pְ{b@}OSbB5\⨕>X؊Q\*rgOh]t)!m_ M|x]ēnjʻv0[bN̈Z/DRhSc*Fy|v1jܾ1x8sp9pj x\2qat(AFgu-uGI#j)$ ^iOgjrIuO7||cHZiN:HV~TJTa??,Dək1C}X>걛w ՠ|p" GhwoUXٍ|3Pơu~6LX]q9>| ݹ!*[#-2Հ ȉdɫ:)/ou>8G(HcƣJocTݥKW@Of-zdK5GHWa_d%V(b6Ǹs`JL90C0Fr-e; GU bA+7Bq-Gvmfͅ &^РKh/[Z;MSiuPD*Fr̎LX-6@%q@"loH<ԇnўO}fL$YH>U3AK)BY~MżwXNYBLqs##&8ԊWj]S cj] U ps\gچ\u$jY?Op=M;:j[^}5D M8ѿHAm.XNKe,T0[1iz„D&zb pa{: /]nJ}Zn^ЁF՗;JDIShw#(>~!7ܘ4$\|r/Ug'S]\ vej}xz.*mg%)CMLPO2<@r%_4eT+AѤ^u#@7̀_w" E(G L@oX4P[z@sgQ%s2"*)k` ڜMYyE/=<2;fjqZ9hbc}A0WڳCQ+3F-&鶋T0yt2עdӓTf:ԮI]bV1HugŴ_qo\L0vPAC;3ڪeJ NI`K!X#hh~泞ڶ X6(+OZl\>+myls;[`r}[k arD IGZ8A3vwc%&Ň}1%jl h:PoR-o1޾OlÕ$/e[,mj?f<3sr 4zaAjRhSܷu=$j LisDU@CخrsL=MޚDtymUQ WR"^Xqz.9;RNс\;9B[g_!l,ɩv:mY]\+9z^PРPE*2[4v}W%gSN6 Eaho8=ȩpKٔRG't0TZ)XD5 LjRj13 o17-4ג:4LÀZe :Ť)|@||j K~u#TRqfXG*#,1qATK7LS4VΑ/7zF/C3 >EJZe0e:V|;,A|w0 v㶣Ľp%ft QL~5 &˘VٵTùӏ"Uq/TLg!NZ)"c!2>{SOivf2d@c*ue[IX$Zc d}AΌkd @y6˵fFJW;M!zM4{aRi->'fIH x…t߃\|\QU/^a e^tWŽwD^rIO:fݠɛLPR1Q_k>H@܀hp^ @2ѝlhF1 w)GĹQ.}K'ap¿hl 53 2#7 بW$労v'B|^h dU/OwGЊB){wzlϨ(NeG>kC`JVWw.Ǘ"RR|]xehwEjU3M(xQ,E)Bs:sqűXgť) P l,Cgف><3cɬr8c GIo2 ((i Dс$ێӃյ7R.$V2o蕉H=j"(uGKܶh*7WcjGGA&WjWT5W8P`xN욁iQW\ET ]]mK`v8oa Fd_Dz>(ZN^i$}Q{V6id=:!֦} 2Sq9f <5q@w`6Tx݁ a5.+ul6Cnv5qXҘ&ϊ]HJ:[N-GQ/-jTpڷcZs܁P`X(hO>mZt xRꉋs`KM)P[唓ة#QAT-W=@miHG6B4O*0C0Hv rZ#y5whg }GZ㋏vZgN90T]~ LT|7>h`3%) mf?*K$W Jm//gT!GrIE ݢWOZÖ: bFQ6,aՏaO=)}eN[4`0ߢe57wx}OÏCƥ!@/+9c "&0N> m%)7/% BU7Wũa~ rSusn†3L[)ơN 06`[B0s0UQ. ԍVזQ ]#phFEM>J5Ċj==.?x _ _ۀ~.]?s <W4p2w" xG 䐁OoBm+,yk(q^8P-F2PM3J\#B;٧)H4e=2 g+ӗmMyJ\y&a5O сa~'(Ynr0qA-'m_í_A? "A~I[;OhD?o-'$G>x4%실H1,m~qǙSI&hI#ʊupF3Z:MN`0֬&[lHrs&ܞ+мzG(XST֢PI0hNzT5ez6j`zP3jq }IcgGIZ< O iSl{vIpy%MKӇ#_x=/8Mm aAa3zUp;J@EEX)mtrCM;LʃwQ* Ճn5Һp*n/XtUp#مBFOHF69DFϝb]pEx߱H¡c?. &3*.X]q3-v!u(I=@*vYx!P'`JE3Y+n q ޸b局.jW -U`Z]Κu]2l_Zژ+U)MC/FN֩m-V {v]k_'޼lO0֌%/rJ&,!6xG{@]GzcE7]<0 Zތ( eNBHc}#|6G1Fڍʁ=]z%E zBc-E0GWK$%{)ӖHj{n]^S.h5jp7_=vY$˰[EK/照%٣-9eN/n 1na4R{8*JxڵVp'|@;ҁ}*se\h vdq\>z {J~xf䎞?~iiҢ4$S2/W.TX~ `?wZ!zvCFUVme j g¾eהJBG"na{Jrg)djw08=ČX;>,)0_HVs9p _LUWaA)%:V 4LxCKQ4re & hD\H~VM6f-V/idThw0V!'"cHЇu?Ws_ džǪ]ԐA$H#XI#g@}CsSpH:r|v/`^p@ctpX$ձqogJ!n#@a4bG#QfJڱ&4@ny"i~>a/gX! 3%'FV_iI˱ܠپ]qB+\=c;91n/bw Yz>v}἞Ƌ1Ȑ tYFMݒr7:ٌ֠BDX"#Q8x*uc~4z& PQrs,z>ndđ? sMTMd&% ʾ^-V'!@?^qvxYp)h-N8)99o9ݠ=o\%ꣽU;sK1`ƩD5c6/|jpǬ8Z෼L]PL}\)P^=V*F܇䕉pRY-A x2R; _9Y4@Ӽ`G@Of{C(e1ΣY5GOyٰQX (}VlZa}7CM5n`{c]SD5?xk>83cާSIn-^uqkG~Rj=?&XqF-R؋$E u7}o|b //Hk w D]& ZfGcxeeWm:8UWG 5q3;Gd¢)|1(R5YA]7@]M8ҕղp ! VwMOIxЅp>YmT.R_ U#Az6g]|\Bؚߗf;=4L}zZ׃;j]O-cD|~Q*O(Ooa]ǵcpd`.mXb4ȊK)\ Qqo=ZE{E*~?n:_MiF9Ioײ(̕N׭0j{+cvvN9_`-ϡ[uAE?^2EI!Clu\O!4i]z.u!40㶈TbcAc#ٶ &{x40ԋ6r^x$o督ϑs[?@'/9[ϦĐ8 }Jp[#uv,!߉{<x8>}>=^BLcoh#(z35'JaGdmRDqh$jEiL7c RM‘;(C-mmR͸׾0)Рq`Y| ;sqF-W$ee8_ i 26޵+@)=m7׽mSIEb$cZcE8E\=:{Rdb%EvwXansyL*X kN\]tHluj9S EG2h.6ҨߠJ+ %.BG%r,OiO)겖,8#-Ljk S]9bxXQRC]2=>:{l |-DQ)3AE.'1k.^aDmax1G̷E;z&ƬbUyXѾAw5b!ET>Pkrz `쬘^SxgIߞǞ5ޢת,VOFeb*M}SCN ؊Fe]z|:7 0Y"T*±[78_h0RD'E.?| ],~~? ?s'w_Iޒ4ͨʣc>v!mC z%ABEDXo:3EzjGmTbA^Hx&nSVm4#"o"˛L˖Z^[OJW+0}'\ N9O6q"ю'F5h761b%$Ikm&9_+Iۇp{[hWᲘ- :FSbyH HU35Jt ty6O>R3zY{ Z- MV|H)Wp'Q&ьR.'FVr,,R3mt x]E; Qj=Sf(/\aq\PɈ(b7]10C* "a>|)b[s,2"Eb=J%rhފ"t4hH2ۉG@,xDf]'kPЉbu-bZvYLQ'}C>wO+0KlU+E)-W\Ŕh([@2 ?5v)9R3k4P0zg5ۃsR&Ftv DRmlXyj.YWkW'-= |GU+ 'NHYFNS*nu6ez~[4ThѨ%(]C& ("R`GDC= IsS+B/ΈjT5AV`B{>UEXb`Y?M]?t 9Ax~(m1'ٳ2hp AAV߄$ Rhdj;?f4'HM$ެ T}MNMGԁ'14`0:`vp;.%)>ѻR;`5ȮL -Ϊ{ '͊wDɟlN aߥLzi%ňl4+-pӻvWXqpn%!idklAi N˫XHINr7BhTU ެ7@Zɺ(}xb0$-ϝ^I2zQz[wKOZ[GŸ_&?!uDģx&~7UOm|p1";ďZ~((ߖ77Z xs08="+;- kxH*SJе$DY +aPE*^C I,3S3-rITދb-Uy3Du㓍w6lRD ]tl!}jlg=m1I1FtERjzգ}%{0D~ė?Q?^7r9],t2t2j<t}C}soNoumtMRMXF\a&ρ,r^)_LP9"n>q6j9?0KnH]UEk㧞P$-j8z4VBKRj:i;Xmsw)8Com{Hn?(CE];NpmQ;:qK!y52,y'vmj! jdfGƗE@x9sL*&x? 2Zkjy|cn6 ϯs!uCd((ګ,6ucUrxA3 j Fǒg<QteĿ#2rumY;},Bqñtu\?Cөd7sH_^8dhWH0#m\;:pmA*ߕJ3:W$iQ9uZi$"RyHHyG^SOy4m + \n!:+mљD{C@sbXWal܅ybԖ}-je#"%UTr/rgez.ophb G"53;[|ru=eWɬiAP&Y O/YJȑ0v1'E"3aW|om8TXlS~*7hD}oI` rZ0C}Pj^wZh~VLIE5W %UhiѲt(Kc*/HjVSF͔OyL <S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0[\-8h t`\&d{ A:¬l(3%' iJ G=3UUX%'DThs 7=]2WQj.uHX__2٭g`MJ*5^c1Bb6 QUWUlJtHhYWAH=8j/]xLxfr5{T2~u`VB(SKOΜ 7òR ֭)WLݸq+,) R&pi11* 5vayJ!8G]Z'z򡛿 )68;EI:Ƭ6H_&գk*?Y#hzGA?#tmI)gW hW~Vt^{E"$?wp_‡( 'c$$wRa XsN;Ð#U1 y"`y rB'SIB~藘v>LBaƃƍ1wp}w\vVܫ\NWU{Q&ƵcМN!%WfܨHq5O7NE-2 urbQY{|-݊@gLeP`ojz5 8,w0]v1J,iTVnWFAJ2 _mh_:oB;ohjTMLOcۗAt|6g/(g0X($ jz[f:!`wURv9C3.MQW;~uu!Dw bS;{'_wLgXgUv"v; Eu菴&@F ]u #w&dUio+™Sp6ة75Ժq憿, w1MZy(v&'|uWEOӧg=Dğ@d6\WyC7%)&:GzzaI[+5銷թ~|8Ć/>Z7_Z pk.)/K}Bҩ3UvB#:GT Edn3`)yJ@ '`9fpXD?ܾ ߯PWFϖ,?SwK q%CGWA DKk(fϬ2%DiYta𔭀:aePΘ$ź 䋴NAŨ7 ϣ8E} %v5P# m-URQŻmdx"دփ@?k8?C>6Iޞv[K* l d>d"3ԝŸyf~!VSFPvJS[{cO=|tayuNtCz@4yӥyC!)C:*b‹rzǺ;}feGr}#)>fɅ#N 4It;LGn 4CDnEe,]zYeiE?"t{B>[+$S00Lj;J! U_0L+L\+ܓPcT3@4K)0۠%t[~,\gyLOY!@fQ޳!YWIo` -YZZi})uXU VbO/w? ɣȤl OP`$6rlqI'P(HAtcn럣ukǔbT^Z_eCb_|w@3=EdY(Ǝ*Ö'1͋Ssлi0[H`֓޶ QuT])sf\L ۬`Rq_ǢmOul%dW33O3|޴8ʃ2oHj<>8n"|r_0+ !1-d8;Dd__14ۼQ҆ȩ!OE~ؠ qmh2MlTP=>s; jRLZR]l _r\ G$'@R?Ab*zN-]+Q4e5 {]0˝xgY~V/5=5vjMT" arܮ&i}9<1þՍ +sR.m-{K:z#Kߔ#W zK@8MX"#8LWgB-˭.KJ4;^ @۽Z (,tapX̦vnG5R2NY0ke\*^j& 5+={\;@.9䢐K#Fshxg RjAn Ar;Q\Yg2w8shy1!5-z·3[:hߏAP#.YW:թ5u[@H^Kn~-{Z`naLp4E>ȶIVƬHX}t9# q4}pu+ڽhb¥ miV7Am>h4(_㔎IbO4luCK^ $w8% o*j2@#'_G_rn/edj +_@:m>v7\8dV_xPp,RBV JV{kÿ&V଩PY{a G$ "hg/m/@,1͐m! 071*Շ&P 2ŁӸ!ɐ-ÏxN y}>IbGܬHX2\ʹExeJDrE0ܔHl09q|Dˤ^J>cmؒ+ ;>aT4bwUھ3f#1HFo#BJdIJH_OOPh덭4LHĒ|Ar/F;9zO}ԞB|9wߝ0 tVDM='+b2^C0NMߜچTL_tR218?KKwgթ* []lP^&ju)aY3)+srt!DCʐE9,ym{%*ɨSDGFqa#drEAfD^rvA!{T "d KZᢷְ :.6K&m!]-  n4@K4(OoU+H]%ZǪ%كK~=ˤ*"tE[6SOB#ebYh^ӇNؾC4 _8HKSVn+& JR/&8oSl*5 ATӵ-V}67F^fpy7zJX[cޑ-,};4Kl Q7G|J3ӮR͸fYALfmz83k"z=?+zp^& Kf`fHvSK|6-g`6E Le)#c\`RL )T֋!ɉK=!\nQ h$%0/n"*Иd: rzS&s3[X:|| 2!q&Ź;,~-3DнeE1qC?%0wnKA97`oV0nRߝ`tE3M^ ]ɱTS%&EWܽ=6џ. E^nJ,-ps@||7vʼn$O "Պ{\B\4XB랦X HO[Rej=|bY" ?> -/3 ;dҬ]BG )5>S1{溅>#R`3rGh&s6xB4|bR4JƉ Fm wM!O?59 24_lJsP(gze>K 6H?G4*kjeϽ eΓsJk*&e8Sr?F#,'{|)MǏ#Mgv7˅:V4(uQѸD`#rpjҫ.0&k;wqH_ V v@Klm~1\ vl=~Ax@+(3#+X[$+BRH]Bb!V %RO8 ۡ`zA- IZSܷP~| $N4ytzZƟ B:#rw6("P&W a/+?2!7JBk m[D9Ekj waиtǚOβEG#O}Q=S[~<֒%F0ƭX$hrfC5K{h`gΡ8]Q1^֪>tMd pZѱ&;@x4#Nb/}[VVł9 +_8xG5'IGGk-m9S|@@|i9쾘H,½gvtOTc55A BY#\r1D`pٿN.`NOjܯu\q-H+#_?_dlD.]@?=i`.V=XOхEqOdLA;TjC'5ϵ 0Ta ? N\F(%+=2{՘>#@0 }T]\7u!fBf㽄(>)IWRjed!张 ~=29a.*7'*,22 $O]KCG<$Y>b12TT! jz[W~+'Vw6*0 1ܽr=gqu偳N\דIc } Kaa%@?I^d9߭cX=j.K'M/+zN,/P&f8; Ϝ)mxsz!OK ?󯼊zMy"oY^FpO@un':lZ E1c&^^@kkccȫPxKLAq6~)$=Hg88?CW-70G~|8@o %`=,mC牢F?dpV@,15d\ CƐJq'#ϧLy1$/`P*5~Fl_ul[39unnyWk%:GDeDH3z|{aBcT4 }eh-L[EGDmݞX9& ů![J#X*%^Հ{$Nu1T2j:\ _3 ']WJQAyn%UoiQ 2sR&KW|.{ җH;ЃrK?Rk`;X.kğTy0= {38b'7>Gogb&u[Wo*X&=J^Rf$"ʬKlDq*_f+ar恙b/F XH.54XTc+h-. јU-x[&zU$ _SǮ+ecp k^F0<F$Z3r'K@8PT >Eb.]KJ4 &!4Q/ _FB25Nw`RqO| gQ4+n"aA(} :om:Z+Qx+RY12lWHkK }1GLdGbY ACXvȽ -~o]pP$h2,d\m#AgK(eG_ wxࠠ[|x`#OWBF1OE0AB^;:>g(沖Q?5iDsB4ak ^m LY>@*=W}M c~Z#|Z0S-;ק0+Ӧv;˔<7?@vժj*GPy;$_'\5_=$WjѽL/HM-%(Wf^43e{uVΪ7˿|N M5bRdY E Af_EW.^8?t{&\NhAbif?"j۸ZP?0Gvp|'Gg$qyrΣ52|Bt !\d`OOC p1c̾ 1kH\dhaqOaJP[jvШ¹(u̎*,3tK n/::4 Bja0ݞ`gF^DJR5g@ί#싰`=s6p4/rxr6Sd"{KF΁C@s͏i*}yY "e˃_BHSױ*;H1Nx*@q!1:D)#}ob7< ۫C`@hk TDU,S#5V\zg9*Tm5X*ڽ- bfdb =,NIn㯣rk,\>s3&''֭0,w@-Bǯ9|*BP׷INгT{I&O?$E5턛D3tk"^] j騴"IXk8TC$9"Ev er.Z],&9J: CZ3R{`, LOhU\4!ǗClLK>`ldg_O&$B02Q3)bU'_KBm01#n'ɫַ!"z~RʪyBБu=M1mtC9\&i˷n9Az&xhCrnp)/?0n ^eQ zvwTMv m{㬟 WqB j%!tM ^{_;PNW Si 22IKa[๡46ejGp27V?pF)/ڣ~0k/YdN:60M1 r:NFA^,w\r9Tkػ+PbVf%b]=?(O!=v S=/b{4ڠul|ZǺDT1nPkrO@l[_} 9uo!bץp`K<-y~AWe'ovثUgTHkքm6iǕm=~>2TmsD}p SKX ]B ˧]ʗ*:2_rGK{_A[UuhYS :4IM{dTR ;h-m}4ǭ[DMtG4 za-VjX߲Ml;0Jjd8$ +u>.Ti~TGNvm#;pBznl{_K %~OMCA!5>˦;H@ mp?>uvGO= ^`e:TM@x k"`0wzC{O2:ܽ!`Pwa0\}Ҳ"]Y02<4xPWs2%1,9ӧq:0h"J_]~dM"f<+Nu7b?:?]loŌ.;&VIPq½f,ړ :qPbXVo|U͑P1؛Y681 Ť#?_lQfv9>~bq5U&ؘ s߆S378bؖC, s V% lrA3fф wU|"Dq9PF6 I0bw QOO:r]u>~n߶Zƙyla0#nKӄ١wO3q8ĻCS1J=bJų>fY5XJC'?r]Eհ*+/cԢiǚFVsHne=o 8+Z Sv/f@ś`<V!OZ % tzȊ)4[ U(VO=iYFOi߼ SWVJM\O EAIwlC2r_|J> TY RXWpS,%0Qe?)h\ӚVxMjH{/2ySx[%m ݄2 8WB8Hy+) Sf> &9|h`I1X=PҔZʀ2G|dwe5vFƀ=ș#R"|֋:Bi2igw(Qi3Hie:3@۸?_k^BS+S(2bGUOPM#./j-MT+퉇1AEy ](s\04rIȢThA-Auk'UShT} 9Я:wXLDBrAaZuO1j4cZASX Uu71߹:Vۚ)9BZL:i2~cem^r+,~8 OɐO/ƽg|9 ɋb0K{"Sz'DPTXajQ^;0cͷ+'Hp5=̷ O:;e)Zf~Ep0?~e.韄 t8 c7{(yr=j:ٿ,;^v,ܶ&/4;EEL>h6"ZƟHfxb充*2%A^C{.h_+WfFuu [%d'T ̌ФLV&cZ4ѻ,vǿx 2CO8c762Aהt]UcrDFR+dbcU{[gF8}sNWF N`XLj825Xpj)̖}/*ք~,Oq}^G0lWK\# *ҞOIo fڻ osJL(㉦s0zAQpIF.58v=y{Ev*lwj0p&^WkT:8.K \N.aODO(k`tfʩ7I3n MqcVG3sJ_?{`0dfhw|`cPu75&Y`P;lCj78y??d@r_vvlywR;(~oB)-߫76Pv&jP[޵l(W 3ī'A -@4piVNjv71rt8 * Dfш:W`7ӣWm'6 }FشY(.ɚ[I9h0x`4Zg td .9Fl ~L4qi`(_"k(kB3u, rmUy"%/`͗v/-[\P??`A$_A L0ryDhgm\s3H=NfmBŒ).ųB*}?OS١ 31/ ˔uߊ>uޢkM~SX-OgMSTc3_ѷ H^B#쁒i-%0Qp_X%6,}N-;Gw)@;, eM5ܝ:IFK;*S!S$!pM]}2L<"w{-{C-a"kp/.vO0 K*. Zիw2ɵЁnl5_`a­bqig1ÓV&z'|JYמ&x%a\K>*BjeGďU6G3@&kh]dmTÔVeyVatylɠER(gr-)))#;G2Y`F/pNloG+-No.IzW'd<; 6 KXf65G\ 0 |MǞA^"I<uC+k5,5WAL Ca5|I-kGn<:dKa# "A3Z].Cxp<^ sRmG4Ѥjϱs*76>^`.w019:ri6mrtWyd} _TP= M|QLKQ ˧LX"R Qzۉ;J .S8D'L^2(:Z0;! fTp.Sxb]F`Bj %%MI^e"{mw}+D#Jl K8^5s 5AoHt8&GSv& 0 F4R|5*SAApZzO*WggvCpM 3509S4kwr* GRx|%Q^dayמi]O^fvJ˧}n 'zqcMpKhʭh.{Goz16!kgui"@4#5( \N(#ia4ݞwZ^T&VT91-< p_gvCil1Y "x ItUn@r0 BI'[=IAg`V!Ҁy/ ,I"aH=bq(5߁h,$ykfXϢ ^` Vۄ"]1Y1M5aM\Ej (KU|I/#^NE܉nUPV.+( 6[pշnfc1q9L7:3e&倎ϝP`́fgy XAT)wBGKz>In oƥiw@O{mbwQF2(G fA&6ۂJd ۱~U 8+K=-DALJ3s9F@TP̬adOЉc;^Ns~ MxD~ѸMح !NU6,1ʾ^`Y}Q'{ma(ei%4T2KvcwH5a{fD,|VÙ(qָg5ꖡĕc:A(ٕC+*]28zFN*s#qY= QQ3ak_g{0{l..,*,3 /UYDyuK" IbΥYRKۨmwD7![SEkwL|()>_OY_$[_{βBoj}~v +JC8x[8&8G{tzqI;&=rãyikM.iq# i Mc OCX|”% 5z -g`"ٯå_qDb~2,8 1v(ŧ#ͽ*7)t\rldxg31s y1JL<G"4/@+1g<6 l_#oS>Wq7xy$wXsB֮? Aui޶_j+^84h";;1˥5 a!u?#O랎,,"T>/T9*X;q)5m:aR.nP"LjlV_}:~'QԠYY" $P-K>5,MZoeXgKU0=Cb&UcβdNB78*jvyA|\s.ı7u!W1o? xF}䓂A s)5х1O1y{;^k1@vnÆ$ڐ44Hŵ pbyn1x<^@ ׌_gpBW&e0A*| mw685"+x"UVw|ݖJ:t$Ģėm}_q&K \/g ]R2BWRW:i F9񑳈~k||wEdഔL,a.Nk`'SJgd^zςc Xr5ym2O q3ER'+szK̭=< "n,KRPJU} #.<MqoeuyÑSBxgNuFwP?jqr^ =TdR/D 増uA͐ӳ2kTK`h ڙS)Y\z+c%8ZmiBM`;*.^No@ *p_ƽysa=мcJ5VNzD .}i~,9=4;-vs"u8 WcA3YhIY /_ $Zm眦j2? "N+qY 9:9~ E]IX[iiǨ=\q:H@@|OJ"&j.zػS:UR nE-Xaod'!(vЬ_L.d%YCd"9mӫZN̿*َt%TAb XINBmI5|gfc\k~ez;utºv$t`ϰmMoZT" ")$5L4thcX*v|Ɇydy?N V!pZ1j7SqYU:,H5'4bJwSRwvGWxtsOH\ bi57OEgJNXwtp6r/kXpX6 4wMcEt[ȅ;## Y), ˈ4ilR8{ Ͻ}6:!2, oVԌE1({X֦\@kEW޷öpL[Tt9BUJ8TbNCzL辦& rHnlciHg3ꗓh?xw-Ґ"}&Oz.HX<=He' 1ibfJiflݨv A48y*|z=Lc#"uO8IPqtG|,㑰FM_L+K w=&@19]"_&=B9{5nw`3Hτ5ñs+LKWw͎%J;%?wzFnHPmJLZrO2!^4|04wܕf0}~[qzF>6[: k&aYhu~!Md=N-8i܋Z!]DiN!23OyHۓoP83%j?H ?P+=1swYYY 7}&/qYY+5/ zGP#ri& WpsYISr^0mIׁɗX,PF԰y8o<%s~hX^MZA^vI%{n"wL`iG゚Cݤ^2Ax,>w;'%'{LZ?1\8N.Ƈ$] )1q;uh`$a F< K8FCz[O| 0϶}I?E@{#B4gSs$)M_ ޓMCD:bƱreN ɧ*7ۿ<#[w~2f$IK-  Haj玴7]V>Z.-s(}CY 6r Ud{d/jyNߎWM䋚IYɀdjLH8,yɨSB^>Io|Q4M4Y-BH *9=Z(t1*c6Ng~Wl=^\|{b}G$֔]na}Ñ$埧^C'a*wGR xY* %%iLWF픤SRP^6WFD Ff<>DIҎ,Vh{]3=Y~cAO ײTzLhfށfR@/l k&~qOc3NY! +U Re> 3O?PS\=뉵KPh3'5w:&6H}-俽'E;mW4Rx:xiǨr<̀FNlyC׸Α <NǼ/:kbc+15.<=kK5n/?Ycr*Y}z˦[<('M! ǷW^G鿵!DNIBIJ {͏0^V.umUZ"=;Hkq~CZ'RPWU` ;  K IzjRG-'IP"j`g@&JFM $|z \:dOdGYM-򘩸LFߺxѼyi҂J[f\iokݥk0*ʈK 0,h;ūKiԴev!{Ya-L?t:*6;Ӛz|JlDE&C?Si-*|gP]3XnXJPi3_/و[z}{MVG'9.Xy%m56ulc(~r(1x%\OI\K@ @=]?^Ҵҭ u;>۠w*3rk_^]O[-eAxpW ֭_=35YkC:9:NiF88&7Mr@!̓_6]J?vIV?:z$ES)v^"];d h-\%*u} h*AҾbBCn+=NzuO]VLp;.ňO xь xfL$Ql륗TјXqբPmv Cα+xlsĪL%k??q^}-JjHeI<&X,t6w+ZA ;*GDȮ2 syYq!> hmg~{[K(0#ЫK7UNrAbˍk*iF֜zE~Ҭ3T9YC5D!b86(9av{G3K+׻皾;IƢZe:ۨ:dprQ/j震mҪY[`9Y3o٩+JU҅:DV]0~,wܚٲg$ݐ^&Rg;ASg;OT3:!eG"ϤC4`WrAHn-'ΓA? ;!=N:Bi[pV뻂COd Zf" m l q`k`~*҇jmx'?Bk3۽ m֫%o*p8! hPΜC|X!m [R}eԞ [L?Z aT)i ! Yh|\. : [Iޝ'"'A!VbhGyp 5&cymqEq^'dٿSJQج0X- +s-lV<>ڌ-5Xf͠aGn t k\1[Ҿkˋ[;'QRy4KHCǃ0!{Ng;UCR.BJ̬eR C:_s0ZZ\J\Hv_:@_fἥI s8+uG 厽c%<ۅtOe{i)m{TgZ\ 51"q ;J6Y:`cNF!HP/R=4;hd7 VS.GkJZU4 b>Զ@+6 cЦ_wKFC:kBgRǁC:,>@l=`VK{?|@|h2a- afGGCgXe)?KG p}7oL'V:*2h4LJX`?ODaŠ@ s٣:8vzKU=#~8׊#nMH_Ϲ,ZUH쟮w}z|vtlo¸ B/jZl!=A_|ZZ5j}B֕U41w6_C AYpъخ Ә-_]ٕV ]^753.BGRF> M? s? P#hQMɏ9)ӷN8 &1LWEp򔚬MRcy#44Das_d0c|coI ZZ;~W][K%cC˜ ~ LBN1#.qJE&žj 8@>7NҔ8zP UAKk?p R(+oa h&j+΁yV0oب3Lᮝ~5Z; |E*NUpxUKMu|'EuVj߆(Vg_[TKm`<9(a'% ,x,܌4j.m 3,362"vr#xY=c/G K:/ɜrnTRCOj߀(]W:K4?P E.xz ~*Ifce5jp?UkhTBjӫiBKn=YluMj=I·~dCwwr%i>Fl2gEۙ-.ua8oZzrug k+~:zdz%=Z H:&|wOy9].TJe BgRjxla##Ӫ~=' "R#+[\x5AUNaVc|8bn%5ŹyVsF6fKn~)EgH#5b>eݞ #n_GKwfsq7pn u!!O^HE Wmͬ]n _bQz{8k^pCB3s]tIϧK)PmF[-F +=O"3:gGXǺ_MgG/b;v`=9!T}VIWzdXԜ]P߯ȿ^ؔO7 T90jU(9n;eʢ+Ë Nz(HW1Wٷ4q3{~Ouȷ/gd;k߽(HɡLQ,dƺ l22"TĀ/`UX-n!gpso75+ Wfq0aҶ+"Aky*tZ&;HK xuTw$P:5VSlbA@_1ÏVe}AZl72ۅD3\l)YW.Kw8u9ݻ޾G <%@Ap0Xpx Fu3K>._hOBGOJeǏփT7j!7fm6mK(3Еy$J:҇3PuhIngècjfޭUa&lq$+f2ƨݩ`U5o~P>f9 E⽡Z HC9#UѾF~Q]P9YT38iNQvzᙺ+z p OJ4v ųZv0c|0ž YqOv#iDV mR͸E;J@Ĺ<#*dDJZy]sW3X@'g/~h;j[C7U4!6]p `xm61ցiNzOgwއ3Tk-̊ILv\۞u/JgA?H17I:VS::`8s]Bb:6B;H(> `P"a (bɾOrdn_l|8H 8JX|p@&8ϟ&z"Punʪ, j3F3W=>ti,R{[oS4o5~ >,rIADF. H_4zwxm[Zj]x|C|w{-uu-xDf ]o싁Ҕ6p\Icw2?s:R"O)@ ?AlOQT STqLna;n?vLzLz5ou] ѡqVBWfs3n ".J^_EtD@rv/]wsuٍ¢4x`k[I߁m"Q~#Ä@G\;Cag9D0r|K%':r2YZw⥡CI$.)5C:vӧ S[r&GducpAغl+>m.}/g y'e˸wuKB:J-ND$wh'i9ozLgAJЅlyyQNoCYeiӥ9ݔiA[E쮄(6X`ؠNVu]u/nj 5\AfD]_OH& ՋزoO]͈eՠ(܆?z'GIM͘l(*p 1QH/Z0ݗ,MS) sz۲ :Ĝyi6n1He69ִ/*:gF:Q&Us0H,7޹AH.*iQ9(m@rHFhy _6ͷY#+v0"˭͜g oҏvDi8rdoa+{rP IsYA+`[Ѿ?FCIcN47/w!\$ U:=9?%[m\ J_}\dm5)#>+ $C.@ө>ӓX-XцRcbCBHXn(-.Q?3 $I"dwEm`jqQq)oYM 0/Dp U@a`O*f̖ 4:K㿶vͬh}J;jAk#}`|mZ1 yLun0nِrdVW~i#]4]TPTN^(wġ+K] 1ZU%T &zL%;{D´}0:f0MԪ,h, Ǯ ^g5ѡ!EBwڒ~55nt.W|%DIa$r%B-v<9) 0c.,h+߇kG vB4 ΐ l +ayUvj]B +Z*cF>"ZSEVhZYZT| #II`y ,hJOO/X`'P%:.?D0iFvɖrtj|D ? av ʨgْ #YF5V ,[v%_KeEhM"03p?lx~p? 70 ]7_DЪfzB.1'Z逸N#u rS#?^ɲ$m& nVd#Q_cϮ' vow]H7ߧqM((;'ǒH@E4SyK5*va?ebxZGfUr9UV.>#2[%rz5bޟWKU,W~Ζ;n'|T<4K?ڋfL7yvۃIPSLȾNꝅ>i45bhGn;`42F#r.g+[e-+L+L-|v7_m RX2X=8ȖislU~OҩN&ˎV;pGrBHeW$8Aq,Z-s6ƒD,%6 ["7LU~R!@}lVĎK>m 8n$i\\EUv[(hBu)g/xLt$hg- wέKC&k n*]k ՟6^B`P[.PBVtlf"@ `~3#1^BYi@>:hm]|2t>D} \mP{!Ǘ"Ye!(QKUNqm77yp 6"pdo=-#~piMDkivZk5lES|@དB G䒫?jk&~2UU)@qߵK83vT,@G^Ⱥ @qZiל,;T2RR|Qr(;SrvU 1yzij⮚NRK3H &.52L?`0Rj,tFBhP-Q*njcٗ|I m,iƾ#%P8!o,I?JD5^¼bp蚓&I< iHMIaqr Gr[/J {7CAmS{L)80sbrҘ1+. ;|jg=c*Q[oam#4'46@oӓW hiV|YWj(.0әLXѡb&-f?UD<,vX܃zo dY 減Ėm[e҉*r$: d5>5 ܦ>{,֭4Yo/5EYn4=aRTpbg4)d]Xd8 ȭl/xNOv}~iD2wu$p_ ]ZxXL늑ip.M?GӪ>\x &lۆ{N)`ZL}ܝL4|fWJS1'2z _ ^x]Qϒ)\l /XO-% uG(?"5C>V먨eAj_C M *[CzRf:sԂte&4G^w5&´"]<+LbXg/w|[v[lN?+U 6,>aN1 xwB֖\ch#KT0+ x][2 4ypb9Ը:3[Y[Gh5A&4iG(;+_8k 4kh4Ʈ%N~vM)!*sƃxrn^ȫBagT>&8PiGnFU<22Eɍ R+_+J`fmu=$*lWx,zk:ғT@B-E'\x6jf+bY`? /fMPBի `BJn8qބ ˝WzV\9hd=v7Roo"dB"-yv!6o`hdӫGKի䍌i:ϡ=~K| ʛaV2VIUwT͒X4TxZ^mOS`#-tސ,u"ؒg@ ܣ̭n0k#x݀,>,]';enOLN;)4qot5*,!0]قJ0 B= n=c-VԌ <(9OB<{_0*jNM9ƭBlh]1[AuJlb=07:)ݿ;)z9oa[k;FJ+ O7{Hθ(ЛPR:ȺNW@KM6c~v.Ko?ۮ xlO0M``Q!TS/^ŵ*8(Q⻥4>wa.؂~Bi [o'D#h%3)(@S1zA-g>nxfp+^ix\m(a6DPp{4"G?F+%6GX#{cJR!>4-ztQH!b%ݓ aQ񜒎@j0u'^ܳը<2AbuQ/MoZgi#o?Q ^Q/V{R :K#g ;S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ<ݺQUGw~:,8pyRwo_: Xá0`*5X~dtA$8^?|:ì@> Ģ8E-Jy[j76LlqWp8nگT}PwOPY$o"Gs/򝆑4X;G-`R:gO;# dMj OF00Bm\ֺϒŊ.mv-4#2%snfKwмuY -9_0εAWk \37)7xL},OxrmJ@.8d k!fOz7D7mww6pW? $4 "8ha?#y*-Q!, <~=ԗ^BtYhfPdϜJM |hgU4mf=0kwSSM,hE#֘JzGx)}I-Rτ'ZE;KPK2dcY羘g*pR_YReQ@ $cPsmռv ’%dי|.Oɞb-c0w|^MvoͧӉ_R#B˨;f'! 1sUp<ܴkKw:auWu'fLN r{>X)1;NStkU]qۦg@8][<A+T Y+0jZۙc @ŧ)Bv:xa_m1:9NTKDcEkaQg !mr}D (G o+v۩?א [O-&\&'5d-vӋ_GǤ -|ջe>}RCV$ ~i E&lOkǻ@Z{ƤxF$hQ*muz<ħN.-,=~ QG@osJ?1(2{ڹg BK)~{mnQ*\U!-&bN}M5F%ߍq{x .݆>fdUISad~;LG1"C><ՠkLqGfdmƂ*хy/gPs'@8x絡o6]y4?ʻ`rV->R&D΢`;ugVNm&u`U^rEj_oPDW sl{dN?N/CI /A}, ˶ cexRvszέuU`l`C 3+.+_fjv7[*]Ƶ9˳abߌףrhn̋ 2n b,p.N %Q& ?ۜɺY5!S]!ͯL[qk$#]JHk.00aTȕG36tu{({;igv47d| hv¶,W8ϳKrjd %]%??Ӻf7cD|:űHZv @;1%@]&-,K8Ў2]_ԴVm!ab"}0 pJljkDAbInvAD_? tR{e[e .FD cEl\pgނ )KR[J@ٛ)0l6K)<)0: >;BGy({*HW8NQ"'݉%o2n(\r` w/wa%41cOfD a@{hsnYWڛ)U(}c1d$KFJMV8wI!nΘB+k͆w¬jv`^ /3>3s5OF tD# WnWxq `ӑs!:C3Vy#g5CftSY,tC$s|{JM|఼>?5u!%f  o!a{zm>a}Զwx`+Cߢr1b%X$s 砷R,bXk;IĢacoNGؤ5A}dl"91ke[_ ^B![̷h 7 ꦯ0%i=0(8*RAy}&[IYq<^7_lp怘1:0^]&sc&=dYƑPʼȳ?X$Ev4q ĉů+pP(^T"%,91wA!. GTdY1EWD463!LawZ32)E\]kX P&/ގev]U qV@*<;"z %g~z{}IDe_1}g (htm%DҤFRrsK%o rG.^&_:.rkgn_&8oC1%aXqFKÌP/jR/O`EfPvb\,>A@o*#CTpz;J">mRpk\V"?kjWF#sTM}? 5Z`.(۩x\ʹ!?x³z#(a%6 $ڰwK!{ ӦD(b ÖCpm]v OA\^֚9xhnۯO_yd4o#=v_^3ulS%*Z8rn4]GOVٍH0 We.* QAYV5!'xE;-" i^At"lJpяP5 %6Ph ?w)3v:x6DN SfA!+20G|IFN\nՖvG<掄ng -37B$uT9>qO[)2$ڥ<(w$N|UTwjD뭆^ǎ *XPREuJgb{S )H9wrp~2]xXTNOJ[Q$WWry+Y2¢b0:[ҷyał{H8MihZ.wx! 20e6F|BWTO޻TL i<)XI:Z`7Ll *ܳ1 !_R$5p*OxfG*W)P."3ʀxvxbwcTDHJG2EahE~/0>.N)c܊~r*gR*nnhc a"_y ;PQFVک/!{I1IJ=MvHmNGUoG0V3'Ju .x4Зy"uT"h%^D_[b_\w9,XzU}T/q[ S bɏ!I~Y0?p^HwjHcY~cR/vV sW1MMb7S{)X~¡"kA:] @`Ҫn~Wr׳BoMx^q썡u5kw|kAWk_1部ܬlvU=V2C[ Zw錚DY׃Y]T @iY2g; U2_|8H2©ETܽ7dy/]||PsJnqЮ 4fF򶊐zd{:NZ#2&zz4Uk{  ;/bU!^-HKSa.DDqָmc->=>G3=ǰ{l:ssw9@j 4z#ß@1C:7^,]_y R o楅`RPvi{a 1RC5}|:+ Ph&gwy423pt`M@Z_, ü T3X(Zo(,WCdW6>#Ufn$uB\;s_2jf1-0OHjLq@W . N ߓ> 'AcEG"جP-8B'j$b 6Uz_*G Vl :좞>ȖZ|_(PWFG-Jڷ31` Lts"ң{9y {7r3K9^Ƕ8 XJ(2NΌWK) 2a-v{MY PE^N[6V\,Kv;!pēfi/o8YaU}L쬫΅ST ;X*3MqhԑCfť`3Qܳ9y6mrUlx+׸tU$K.E] (UҒMJzQy@ _Yg7:YA+-f+!ۗ;~A?6j %9bE9՛wlN!qMz;eQ5l8N2Nnǭ @aGIЏ*knS8%Ub@Vz#j8#A%.E`Z{vB,s 5DKmHQ23_B@'~[~4o3JOB UA{xei%Fpʁ4_^) )$@tK? N$%H#Y/@m.< HԌƮ UpHV>~OGȧ5}L 4z1;N/ (1u*Q2JչP'\P=cGS`Qt٭e W2xT ffAh7>%mBsI5)g:f!,=c |E@F2G X4?;m^#.vy]v]? RX׸+>̌DߺǐdѴu| z,'iKUзIm/XgPg|:7ڬazLL儁!zm:¢ R,JqNkMB)2m+6rJ+GS{NU;0o0R dSb?f}A -nIH$q%^;;Żax9Q9f|cDT9TcSdOfGga6q2\><=!uʱ8!YUhf2M|Ll,!:D6ִ=VN98>*;vRpB}TΛXT-Ar/f7y<1#G@T QnJgt8~[6#(K#cӉWCD-i/Ev:SM<'|jKm?u|LsJ14sDM=S'ȞF>^ .!iDpƍ/+[H'~:CƯLQٷMT;yÊyܲ݋y<}zOr`0)kL \[WtsQxq ]*]IOS\~~`'CSN 3Q¬Vh:߅k={`ԆFsCl;Qj[mBVA].k `SKWLf )=>+?m>Jb%TLCcGɦ #='h"d~=Gdښ%}kqs=R};$0 Q]$$^z/[xa aӻy'^cKC3=pvkP7G;\ccxvTɋR)>XK?Ǩ6;2xg7=YZ}aMp?n34éC&v5J^ 3L|6ل ng{v5-4W=l8\ Ay=}?6^Qͮ:7I!pAqȷ?*gzlq: {`/fIW, 3d% DBFsEuryndZ G'w[W),ȁnP#sG|ү B-hC\Xʯ=) .Εjq%p@@[.N=kkQW% WzQ"ꦧ'DaՌ ݐ@0ib-1ݢhfԙ cFGX ?}p)O ]!V%@~LL_zNRcJ9[VK`_sIiͼ\L/=xQƷeRi RozO$_im'&g*ѭ>uVV~-PݬYXj|w[Q7W(+.vkl]w1zʼn'kuwqQsxz>I0I?/V#|nbU+'v<|ҔWіyDT. ^ Ϊ8G0.E=7"s!ŊE$GO:dN+C0fO.tǭƃy{8ًc&7~ t!h[ךu j͚y\s({ 工e4]+D#}`=56/(O*CSOMxI 7EW{@ Ɏ =NX#.ԩ4P .=Z"µ)O QttVyame.:pK6%Sq[_A-unmO ۮ! h.JSF?uAqFz";`J@Uz (W?&mG*NM(x唑f\:$lF:m3 [Lz3Kֵ%Tw9b|,XU;ү~c[isx=W$rd!ɡFOũ~ GfkHYc.2`qU/864pī^j!ZEʴAM1 `j,,sWRL^'ypS#>7WS%x3Z=}8_%IaMs?-)ԝe6l00 ra,y~2 $,+ʹlcvHcn7sucGDBr`HmUȎ;3Oo'V90Aj3OJAWթQxXܬw6fmx* ^ gXX; -kJ~89՚0VM%0)"QyR"D%ytIrlvm ܈!"⧦$BW |QHx+W&Vd9fi`ut)c: cfXGŊk-ezA(A1up[Ј+PhDxl>Y,M\eZwDr[߮,z* N=nAڭ|frF_\Fm]hœ|I1GD*{Zt eجXR}88VAN BI /I:;gDc=;Eʶs gs/>ak$߉o_Vsʀ-Z`ҠT8!^O.O[1unwuWR2z\Zܚ(qMBJH{}N(yNoIq}b6FyR-(p1xa'G` @0?+wK KMxmT9| ۯ|@8xHƽ%'@7ԤmS||i#@IGG*J:N)Kr}8:}M: q(wLȊS|"*oJ9I_* 7ʸ0>=ހhx!VDxgKIKs_5+2N=eq#3kan;,j9RXߣEw,IpSꦾ N-]R}4%%4zA\~KՓDniו?#;B#ćD0P:Gt Dr6ۏPlFхb~@ILU3V˦\4\Ü COtx:4_نrP):}yg/ zmQY6ҾoFT+pq4׸eQg=58oW.$7L,G'_ G| :X DZʞ'+ 6gM_t%0ub6,Wb=&M ՟T`\6wL0j ~xyɉw/'˗Xkٻ =@d{ˆ86fBףGv{ʺ`2drH%.\>) .jf*8B`M >ʸ'f7VyPR#6 Iᅲ۰8alZ_evխ**&":djMOQN t%=D"D/1X%U p 6YR[~v:$Ɯe]$$@X|)lչY.++4De7ʪ7\Ƒ7r^t_xk3LeE~ )MD 4dFh‰:w_oG8+00I+#ƅnHZyҺO8t}MVԞ=A0 ~Rӽb>^ R]L>PvOgXWKrEV?I+~tɫVy~4-G)nS6$r LLu&qk0}@:FIL ɈK.nn~~ݱ?f@Jl]R-( R͸ I}8,oɣ6ԧ@B W@3ou}.C7~Y]&H9Z4bA dﺨ'%XFIwqV _Niiţ{R:5aR.zlvSjWjTNk&eKb﫤$ӕm2CtKaq5V+ ,umѽKaOԤbF*зVB;e5``7OsBտ_t;˴lS9iNWݼʈ4P)g$2C 17P3|yFUA5$AQSM-FLEzT|O#6)fP EZatDŽR~=3:U,in-0yi{3GLjJPbù= F?] "+XԨc B ěQzgem@TR}˸/W%~?; 3s<ȨItgEp ZUC5{8aP ]=k1`JBI 2I)g| |l}e:EEf4:WOMF=ajcC؉>:(K".&7d(3^ku } C<ٜ"vni  |O}% ~z,dTK%[opMO8AYqB p"g{}]4GǻP,QgՖzxzJYwa/QK:3ӍdU/刨vs^|Jnh]urPUP:ᢱɞlH`YQXofX;u5sZ/RjCʈe1OJV(W8vB3dW+sT k%sn_H#'-ZZmaջ=Ԫh8hG 4Iu r-Q]f $:S=dZE2|w_8 0Ēӎ# Q֯x]^OA#jr9X,&^}`T/$'8|KEHrT'Çrc^" E^#$:{\%V⮻X=Rq o`I70;䨸Uz[u_.2h)9g> :"? u~fVTX#ZYm/n] 9rjkva ٛ }QpGByHԤSFs{<,++u,*9B?S^ r z[ /f.@'Zn%8F[(TmkB>hQ>;R1q  M o -VKdgX 1^a,JP;TZ_aL6Ex݀ v.>5I-i㠩0:%%V؄Wt?%װRp ID EBJB/E·El:[z>/Q4 |O45[0Ȭ| 3F'w?1)M4;Cx1Eʮc_C~F1㔯 F-}{c彙sImf契e-| sPl$!o-\O`;GirEc=] EW8:wNojfQU:~+S֫qFݥ׷m[$mY1gцaue8=} Yg3yҬ|.=˅=MI7DyuXC4<*Tf.`5bh#8R')=!Ŗ#ُm9au[6w> G$1pi_䣻e뚽[=S`.|'V e7֨Ef9iR<0NVVj%x".H@Ȯ5 FWU[UYQx_\6sdCw1_"Od ]ꁔk-vQVVZ酅A-tN\&S5m%gk_I]~* f!%>='D1e L?3BdpQ(YD[.aK 糘BFQ4&$A|[u/X$`iu9׷j/vW?t!gJ/;a{YuJQ Mbn{+)IrcK%GW6ݪťk+1BMypezY۽ g?O*~H4N5 LgtluDڕ{s=/DhKUB~-)If6TrLnhu0搋h$Un)՛ ?M] ˢU2nI's^f^Ds / 91V>Xڌr >c=k.C/!6b3,+ #ڹT1j])!$?YO=gۏ"23]7سPcNwsW^&ypف0qT|$UQh+ Ll haDA!evz"x)vLVaJޑQqR1ޫGlvGaPdv)],ckւ YHcR[aB/䨳9x| pWc>#wmraU{3P \>b'u_Il$zN#fwǙyKR|qъBҊ;+cкDܬW=tkM#>\hn30w?V)s_ @AnuKޞU PFw*uqU/u׵ucYLBrzIN^ 9\S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ<IM& q?@:4@ p {s>C/:`V ʺGa ?y}4 qH׹ @2:`(|Ő"?|:é> yOԇ17! wx# ؜Jz&NfvWMmai00z1\qAL8\G5N:6:b!Hbwy}8v՚LOLrkv(O8"_7SހSm^κ ~O895s} bbci(mWk -x.YDP n$.ᇽali(D\D2xմߗ=aKڲ,5BB|ݝX:58E*'r("inXp\.}j~=@ 3i`_8a(E6"-vsث$\X /Օַ]GmCM̟=@ѦdΩa33X[|'t!2.2:פ"\%b8WkE~vǗI ;yɼ? G vm?}l)K3Vns|lfE̱ O Q&?R-:=Db0McsDl#ڳ5ҷv\6C©S(r,Ycnj$: zl-r]z7y9<._bb}t2H3jDsYHȖ= zCHS`\G> .D8SS>QGR/dcS&!HJP!w㵍}x Gŏd8]sP/ R\ӭzo.ffNuaӲ3SF;A+^2Bwru(21IpVb΄tY@U0%$'Tw^AwȪBKZgiO 3v|*3^ ŶySpg9Y;k+1G(\seh1! db 8Xڡ%؁N%lBfy^n:/xX&tR d72y څ@}? qb2+H4**i["0.+.k5©R`bM[R lLd ._r ߐؚD ؜O&Ʃ"/!Oc 5*gk4ϛtз!tG"9S;5`x{ Ưsؤx o]]q rٸ-9fա@4>+U4/-\갓W'Ȑ mYWIjNn-Hk$%ȜҢˆ{WѺj!*={74x _?tfw#7:;4R) m`e/ =qS;N#hH co-<r>C]Fʼn9a꧰}b"LL/Ur^ DzaqLʱK=^~"1oH6j_vMFOZ)ӌ;6Wq|#^dr:AUJ3ܡTWDnz{S>L6y,F%\="y#Sz[zP 2|;`J"CE4 CKBu*zݽG(P$\QCFvWfKm*KGlO? ߿S5PuQ# .b1 Im n{B*Ǿ[ T܇I5zRWHօnx s5*!@y&&(7_qn$@)2C|rd@r66Br;1LbB#%sڌcc顮]WkoI<= l5ꏺ~ċm21QwQ͚ܳasV}R1X4K]bzFd׵D< )1ngwqޚ[)Ǵi7 N~:M(YwN)v'` Jͭ]{O'eBbHٲOZp_.0.Y:XFsJnfx3\ x0s}[@(9 4 込-pK`,s%Bc."~E !$, 9zb>kޏo.5KK` /Kn9MsB&?WN2]\֥WNƌrqtkPQ {hQj&e(n](YfkoFRGc^$ē@X+gJ#zG!F璟)CU` o}xp-&27S ǰ3爧h^Av4bxlp9AzvUY)s)r0G-Qv9wkArf)q}XI/!x\k 5ڔ0x&*q 3ZEz^X04pv4NLAՐHr}TPg樕1IWGw*:@_9KV:Cv. qsplN(g!̇1˚$P[O RW֖Bt+ђ'K YeiA*n|xXeebmw A_ddKדT{6iA+͹`V/9<%:{=?DBo3(S|<& (E3w;K[_U<櫆dƌ`FS~(z25*0SmtԳ\i %S;LTbր|6WgRO䆊;b1I[I$BԚ:H6dJZ4jO,]\">|&KQ0$|)nWuѳ|f[LlR:R4j<8qEBvq4(ЋῆOk9| EKdu v? ~$߹wSKb K(ɝY]ZJGq |x/6}# `m?c앎YB4fT8l&/Տb{_d44šaHFnh"ӿt K+n#tkݗZDF?fg2k;PKK;@v s72`gǁns@)HM @w\Mi_#a>=:i2LJ KwjRPŕ"CYr*Rq f7j}bP$J,>1=e1kO&rXd4R`p/Qd#}Xsyg4FPŎ&CĨjcf.kzn!Q֌YY²h"8* z>K`2ƿY( Z? O~SW,d]|͌/5ߝG@@|sY;l!E{OUY s[A3EU"eWX]vؓzOS]W-F @< =M.X9 pX\ HMoVJ{6@x5T10 ҇8Ү\R %Y܊ܪeCRN8%ܟL5EL( @5?&-"ю69/GXSfZRۗhE[*~=)19WCj=.N?ݟRϹ񟏐S{z%͎=ѓ{l[O1~cQʁ l29KGY}b}Z^l\r"Ժ˴o^9F?֟EA]/:<D$E5}/iϒ &E3| |h8Fb(<`u0VsԈ!d{2Tb>pvU.UpE쿻߈]Fo!dN>2YMuw|<"C .serzjS6]u)}CV*UD.Q/?7ƾ;%/|rGh<閑;: ;k2*B_#{^F\MY^3(pqcA0*JhXD[ޔ Dj?bB-ɖlEbѳ·F0̷CN:NPy{5Ba!jū%{hda]Q-w@oC[Ɂ8 o񠫎Kv,N9x'RӀ臄#S+WK}? 9g~;l)X`3uB3'(x?@]h}(]l}uTXE{v1d}INX?rP%7>ʁ: =uw,H_o&[g7>0F -}QP2CiW.iGb -WgUR40I:`}6q& ??LU;lQLӡ1;Ɯ,(+3m=p9M5N[!w5p%+P)E?~[AO>Ge2amjL\cƥ8 B A* 4'z9ߟ FOU0*̜7(}Iƭ$V"-9o5C@kGŜH~~)oѯֹxĉvq2L[ :.ste5JbĖHCξJqϿf:x 1L8Х#VD XO!)lHQdx=,hk>gc3HF[J{ЪⲲ SrhZ\(6Kc}9{5Ea'CE޹W>'WF<#muޭ"rM' ["9swX#ٹMi.O0lRlȦ^ktnM`S7>N!zM.AxeHМؾ"ka%M0:?.~'`.~ `EYwC?f +ߋ&/^axZdP1x9~ `yD_ ?S =$lYɛ ~i o"elVW<6lhn)@ ئއ+FvN7fis0m;L5N!SYk!Ӆ~NɐA(T8P\}qlNDhg'r]uO*/Q|6[FZ MifS8нWev,ofBX,b>ڌlք:AXzJI9H}( #f\.Y f/;A˝`@b+)F6a/!U[Ӏwq3jNteBI۷ *q,BÀXۭD1`bC7^'@J\ŕ_3$60g1AO-#yZ2sk3fŎc[kH筹kt} !- ;_y p-c4?ի"O^i= nu%WP6Ȑ.i- )T r?ww$dځYDa3ys{'eHAՁ 88WPMC.' eKR/zթaKNIy89;" QLvD&ރ)եxv{>:S*@ `6.@ HxfA@}*DSF2Y\ƣWZL}Jɕg&z4׺w#oQ{4*'}PۊI!T'IVgw*$u{Mp"[ZAd&>'fhfâീks>D"h*3Pɺ4*K bԈQP'HrjGޜb KX?iQ8.[ _o ]m!j9f[اQtɼur>I ;J WePE>=3iULŝXxǟEi~SMܮ!<`ƳWwHhϽʅvN17)uzGƏIb%}M;$Re]r T~ħ^Jf&͘NPT,]!2LN^>!4|=خREIʨQ;M" >0V:'aDLgFPla'dLFEt,0Mebejp='oW:\ϯ&[uF{X @G6NEvm}WP/-6J@/xJ#AS:RGɒ#1;⟟'+)zκAp e-"Clz zJiШ+X7n(~#b=r>H?pBy5dF65&D;\sy}*\&wF,U4mO2E83u) Xf)g]~Gu}{BX E Cֈo;>E .8jn,COJyam%JGgʼnrXJ< كt[ZwAS} ulDUR殜Q[(f.v2n?!5Cb:| 1k}aTب3 _= ;G0-z4,Z/:ɪ~ᐲvFӴS9*ady9QtN +;g{hógGڜ^ޮQ_~P qh]{ 8jV7"ܪHz{U"]|(ÿ|ITx>łTe0Z`5qjVnd GT~mN#S ^z >u>LҺ0m{UkZYTX_D5H /g8T'ܨLΏ+n:&.8L~G#8 M;*)('kEv (0t1+\$ο%MDuqlZ{ح7fnY4Pk}9+ȏp&'3O99K Q6Rݶ]t|qwʯGOAS]?֧R6a˺cD{4`FWIu6 Ѹ{A/Դ<v)bQKTB_ k$` nxl.9uQZ~. qlȿɢeLK ^u*d6pXusxcU . 0> WEKPů&1Ń2GBǩQհy[? EJa 8I S*,KuQX1&m@ ˦$9Ÿ!lK@,ݛ)úHf yoUGj%oqW'ư8m"|iT1kc N0؟l!W`aPe;S+b{ ݒֆ`T{[4Bľ9"$t$3Rt7W ѣ]|zg(܅}^ui0&6h24>2:$wne|ؓ7 *!e ;mϴV`įMѠ M ȳ.6&tdFuZY+4es!sYd.}2g[r.x{_y7͗!^?&aAw~Y{y2a ^$?ຏ:V ݄jh|>*|pQX6!]ü/sDʛjMvp _ C=_.hc|OvǗYG:/gM !qʋ=\]5aύ=kQ=N[]v !zV{Y09!ƷF|?O+|~@艠;))o5/sвRP<WTʒfu:(f vkI:ѕ=04ˀ_18t#9ͻct rM¾/69NFۙ<-Ut4UJi!Ub`fGVJ&qX 4|d%[1CQ'Dj5<8A90c91؄.ae 3CnRE("KAƲ>YR׆$+`2^&'\\Z.OͶ`N`J#@Lv"ax,\+ yV0km$F)˰؁b-s=3oDzF 8)#-dGS_Z~9翛Q _5R *Drג' t s* ȱjtW'&pODޟ4_Kǿjb  O]b~ J{m5+5#3/}5/!}IjhNo "+uۆ@<DGjB|e#"X铄] 2'<Svcah:4 9H)Iu.20}[SM ;sFrlR5N]-X"$Ms*R=jkP'@0٦rwa)u#֚Ih/mN ,xuk..? ퟷn BNV`5`tcf82Xddm3gw] c@Ϭeۼ?/2DyK0VKs-wxLo[UqOO ~D[xU6Dq/ ή̣MBGh\#{~& /@8 |4]`.  $&Ḫ"4LiKQʹ^r`v_cz*Yĭ!;[{LgP9xE2" p݃jOv$׻}b|5}l$sƈ>=P^?k:z:QDFvT>y+ $uTEHq͓ƿ_e~ &5%3_iQ\pyc+iΚ?.!elvUa:ṞlMc-䚇ӿSc[E&sC( kS|'xՎ:~sIVgGΦa,ͯ ~O nЯCyӹN9L 0)TMy,v97SiUr=R}n(r2o6dRqҒӞx,>v:íO: QOWEoK1%qHeeRB>]( y|31wx L 5CPU ]MO/,GNǥ5FPmjX lq =vt˜_Df)JZ*[%W-v[BvF dA!XBD~W}D<~G(-b˟yFT<Fɯ/ H3aIu;b|}lqjy]iXŭ @ua95Fn<7V,׉Ll&QM9-K9S@Ƈ{_!tsK u:T2Y2BbEn% B'!P7 'd~1T1M6S7xbjD(귅[ע/F S+AYΗ .Ozi/4~+zE+U,4pP}S9DFGT.T .)r^W5ӯp+'83 Iޓt_V;)úV }r_s6NTr Bw=5HCAV8#onlwW`#k?Gzko4y 6BJv@Tq0pTɟuc$.(_)dm޹ys n_g+R߃qs:}.\h!F,4MM{5".N(y+St7[I'*a@nَO3gx+BrIQy^j2J}CjTa;JBs2'Rup162,a0^Y t|O^2 Bco1V̗ ݅q)zH5:H|/<T>;k(OhKrqUs~O "S%  {1ux6f/K0RwM\,省$E}P֍#Y0i$g^iC@ wr"y\bX"t&dCxSSswoZRߩl t֪D7ksn{ퟥBjThP:vd' Jy^$ p~LjQ)F$Q&Q,K1J*$* BhȪ=_hO+Ɵ5GѦ긦9/jZN`ELƠL7)*a2cy&v 89R]Y^ 0k6D ooq~J> E.7Pb\捞->(|b1PbLjW> j),|1t=aB;89"[s0TKRte*W`}G^5=xlY[a;^꣎K<-cnY0hfIeɸ^!zVPqq۹ĩjwT]פ3FHu&k]R*ʼg ˵*.iV[~m37vo ,dZgC|3OS.ĵvP~F+7U TPR!(T;ez*%HO7= HIFs[xF0zA<7?A#ݸsX=]$jk5ZYRwM/ MCM7ũmpU@ōV[~1@~f)G.. 953Êw Q` fTC-y x0N_㉰,mB1wȓ̒ ٫+41ōs8] h(թd GJ{){l]ȶqcn]xpO,(9$1߅]rֶpMZ #B @A7/8~-aI_ 'XyёYe‡|/iB^FWlYd*)"n@Vt0 cS@ ][/L]{<1* :S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ891l~f01:,@tx %.rD+c51(1\Ǜ0z0=@' .?,<:_+$;gG.5l?~]7+(IYS?@&r ׄ^E)x]PBdI6vg",1D.YDW6RE&c̻AC QͰV:q<=MޖMG:vnB%Ph^BW*k5v=)y&]iHS{_ʗk?eRk)aQQ2] axCM]ZC@B2蠀dpj)$7MVp/gz| > 8r WD4R7=eAUR8I@WVy+b-p3+{i7]!LXl+J9s?S"=ѭJZ`mഠҲYZ`^QrޛmrȠe4AZŠ`? 1X(-uL2]SEW.Ka|>e |nq+|wcYx7;o*J$8m?$ , <(7_-NZLd&$ n}Zl$)ar.. g7iT  sɍ~/tc4Q-$ZCHb (tg[hd>UGH9 w*[qqVȧ%=)oVhG+,ѲH]O1čKT}u煪^"+f/L Y$8G<bNxq߰ѥċX5׮/`ݴE<ڑOۈK\RSJh~,Q0ʝz,_Rz|ܪG !Ə4x1fQԺ3NVC hz WEo\eѪjG 8x$KX;2 }:?[W6.`CEb߾w:?pȼ^ˆe_[O-˧cݪN9[ rs_aB3Up%;`7EjΎPt-1LV*6 Gf9;ڍ;7_Ny}h:u",ޔ C0B ;]&"0PEl5ޢ yqH*8q"t v jQ1א6[}67Q>@SO|^W{ƔՄ` ٦^xbu$rn3c}us˔1^ Ӊv"B}Oc=qGsVfl:+oDͺF^r#Dfl2}1  ,*2.Z^?B~5x;WsN a7\ 1P}KHWJ4:Pn"loSGJK4y=۬a^ZqE94{駰*7;R"MLdn{fО\ӢlHtˏ3T!b\P2~tM\ת"8Do ?Q1ew 9ץarьpV_$WmXFEd~5uǕ 98$QY-rWt,s7_-*E,#ez%g87%!&^5yMcHuu 4RJ85~!Xl 2N +e Pܜz`cEg3+2M ύ8*2ĶPUP`wx*fx_v 6t̢}҄Qh¼j+VzaD+ic5x Ju( w%ʜ6'9V @XR!XDyAߝx|>$ڪuiRZ%_Tۏy=,dƩBfS[].rݬC" sy'd?*;P" Pk47H!~z$ eC`..|itNߏJ7"zSR`.~3qG'K/;mXMcg'ک#ӭ)w"Ec Dzn"T׊9K9w{ I mVQQ.ɱ %{øsniCWŭ/ƸSԈD5^|>>brU=%KhԄ&r|r `Y ʯ\b/{B&AsEC%<J*.XJ3)~_UFoO+],Fϐ=JpOBb3` (>K;-Ҵ~6}Grnܪقs=>THQn3lɔVb89Q`5LZ=<{U؁Z;yX!?NI!q3/!,jq8Sٻ3vhn1j\ iwiz 8R!-0ƁǙ J#ytZvB*ȜtwqwJ֩db;a?HˡWvˣżjd y{$H7H=6c /mDb[^t Ud}Zh`ot[ "2IOХ_fJqZib g P#ARTØHXmب_Ļ]1!%ݼ}rE|Y/Ձ1_8v*rA'V?A&V/UQaB,=+pO }ǔPPdE#2: K86o+y,!BߥEE)Z2 ?]>DfGNo^hK'\x^+JH `eO겙bڟn2:#?Μ+@RtHo79y\ƕ0&6Z=H F^ !gl09J^]]zFBʂ@M)8`f,|2A.$eJ|Ir2a N(3n+ey+De4/)=f2ϕ ǞcڀV=fK1DS9k˼֏1)}P ZkQx`&&zjKPR[ 0yy_'2;i.Ú9 J"gBϞ44ϧhlI--Hq|SB?{c$L0m²ߢVIcESwdFOƶ&\>ZUC+$`?TIeI_-Bz#!Aاԥ> pVc(DΊ LpѷgaQ/[5; gR,Ϝe8F7TxȴjQ![pl?([&)GZvs}kIi VJE&P^9{w@^m֭+BbM/׿^H_op[Iݍ/J43[ o{ 3hd]s2:I=Ri[T/ '0[c{t~rvoҼY2;d4p*cvlC8z234b./y.!FLLD* iK= >jgdJٍ!c7o&ܸv}ѭA0pxV k'uvf]Co% kq8CBt#CR^ȲKQ+Z<aq K=XvYȢHwy4ChȳkB\|nx 4Uۄ( F֌^h^ 80\̟ >ubx$*I^_4W'p$$uFB,;Wߧ_ ą#oscA]Wa|@8xHpG #L%$-?_ES>3 2r5֟RJC&bQPL[:URC=IDo'YGkD޴eA!cqXK\aG.vL3W㹀 vtp)"PmT(- $Dv֔ɸqTcT!^zIMI$M&sD(0P$QY==!+&4suR e9*aUBs69i(d4~yuξ(zĐZ7%8UZ!QaP!۲h4PgL{h3lڜOݼ8K?,?V(վtAhzA9\o8ق0rvܵ^vvNcb-}U  VYʡ47(GN ,X$@,a\Te3FL=1ino֫ex> LpMSn!0 $7J+I/;jv. >8_LB6568M 9F Xo80q&*vCNU$s7ťv%'oHi2E݁c^C޷G;x~+թGSߺ^e,S[~Tay0kQ9t:MmpWՖr`M<27^CB +A6r}w]k|['U|M(u0W0oD0<qF?KXL[o> KK_#tY(O3;Wҹ>UfNeű@{_LPgAC?~ڌ3#v;?Q١RpK 3iv#Fqabgxfz<9Oüp\EH $QޠЉ_cEumkJ=NrƾV<b *9za =tfJ<nreHm^P[Ϥ[mwO*Ry-ylB2.udi ٜjOo%o?Qbl \}pN7jmt2lE:цȑۂ˝{$ $⌵7|DyyHT~%=6j;#BU{fp͵?hUz'6$ބ )\:8Lgxi͸;@~]wd#gESq .Ri2sdG]Ză@G lwDŽIG?,{R.S-EqrgOUN+/Hއ>Ê!nnTx1~v[OMʸ h2+kժ聯0m.u`?߆Ꟈ).Gп |s&Y ,\&j6d 6=tAK aE)f.Ax?-LxT}|®E4ЩX\،BU2f4FU!ii y|s[+-̲y hއx d 򹢷0 a4%mpjּoEQ-<Ĕ qi80qK@'Kl-+xRp(|A jYE UP)H էHh1| cC]!|2EAu3s2dfꘘigCI͡}1k=qD!hQ Йp;e\mmCle 1JBK–y>HMn*D]Qx~M[}(6VG5Y KϽMâOdǔA|)^  j-oHe'CwUj )r.hg**vCRBSMtĨ1 RN(P}X*ϔ*m5+DK} vv;2D' f '?Zr[b>u%y uBP(YFW3va3geLfjl@10.ƾS|`=+DbR%n I09 k,88EMc=\ 逐|NM磏7fᗥHAR5¥99rَ̀TDYL}ja&FY O]^ڐ\5^Rvx hɬ]p;zqEߠHN.=0m=s,!lTNsDFn9 R:n>ߤRwW[LKzS<@GPEɂ G o%)C;@HעPw%_ɻ qMgI7# %ͣIh I +M E9qj6Ar #U?ǚJWS+K(9vbQ*0M3VP.V) Tb8N5Ieoh肾нD!EJD MU5< K)y,`2MDw{4RLZ~ܚT'%1%v2@f^m:Wn})6R?7o1of(u{XĴٓA$gyrd}SpaQ\o yyH r*z$#/3 qzګr7 _$UK±D,JJB?JkkYv,e*D+t2D:^KVtH5y_GȢmIY+}Q>Q1DfyjD&)4;;IK- |@c~¸S^)"O$2#f8;M'&x늀92؋ *}a;ǔ M\+83&7+8TTJ,;pG&P*:hK\);Iw#t. H8#o"#u-I㧢fAo4VkrO=SQ3f8k:=^Aw a,ZD qEٟ=5lv`3FpIRn7  8#RijKtP~ΕŕEuF~a=3R?B,Q` ~T3VCxqlۢv8m DVj#vDb_AՍB sf*RgI'$Jllz[i-~X}v$yjtb4Y"6\xɍj,T"LRP7ɴh Xc^x|X*xs Rl u̹qɍڄubrhT}V%TK\qo)־niRյXȀT eō eN̜; vEe-S| I8rCGThqcIx؅mt,1rGT#ƷVZA̚oG e įTt1ioyFLAIGhƊhF'w>h+K۬מ(]^SVk|n{=ĐxoDmx++x@;υ. s̽طѧ3 Zxbto -]bk~L!k(]Yh/A1n0Rok>_cS0W=4[~ d]ȏ6Hcɳ*v.PCyzY{,L*ۘ^v'Ugc<)]ڦga/5Yi7UCa1vpk %4{x_z:KTx,[y:$h[EnWI8pĺ\YyPc6yo%b5w^>y[*4zC`/ʀBLu9ǻi 0Fc*Lb\@PPP pKv/=$Sg#440Ѯ %{ue,DϢX ! h=i4:,D [ Yz OY? { $.Z9;Fe:$8iG.)s.&`_r6ge"}e}.  κ1oCq!WL? ?[|$;`3LP;P08h4 ^wU>N´YIf*ت;Œfyd:d? ePֆڊC&`MԀm,l.-v BrXxolbɸ{HxYw^ !w&{BZ/(V\k@H̾V ~u)`ӬWs\{# , X^csoG1,p#4B۴.;e^?`gW9aG;dQΘ|'Κj'aK>KYd9G+@ BlikN?5!Atd;}H$YU:҆Z^. U>`_5::p C `fjς#QT26'2JDj!35ep,TbhPTeS O.(XY#wy8?ڽ=qLdX%.w< KPgkDd[~tz>zu` hI!;،=a`&&;x"oxFpw ?0=.3]0rbY:z }^tVJˌKa:bP{L!D{|*~a4x\y $?톴Mn )-d#J׭ '}Rbg"h+l$cx:P#$p87ab%(-&`.ѽH[b%i&@7+]+ϐۦQFccv)xW~فB0ڎLE*(HR3U^?<K+j6K B&>D`-<{=&6\f:Tya^1Gg$2!c:U#^$~!1xnH_EY2&һݩ>24kgfF)=O"|Z=HCJ9!d0ذD?"|s;LeCޫȚ0LpC"tnosk)fUB} Q!gn"r * >]f m'|pPr@>SN-HLȈµ  i\ƛK>wcJ2)7@#g|?( yHk) <+5 a3[OjorZβӖ(0>|7a+MB9dqBЌ>A#$A >p'w?`ֻ_;Fb,_49n)P>ilUxwnwUxR?](h !|} lyRT{Pm0h9*dqKP$x5k?k|~/ w~~ ws~|aؐAUL_ AǁT([6 ٦Ai6) $6"im9)!N,6,$鏢,yҕJ+KDL$ȿ|b12{EvNzާJ !H D2] lmSjyH;7dٝC#Xхۯ -oăW0v4KacP4!.,'OW! ,2}r=GgJ9Ғ`r8q7 xᩕTXU);Y48)9 Y7B'rTSHE;.ui>edWM= l4& jq{hK3)" ƈgtWv}}Wp@bVBS"WGf@Fr]{\IPqރ.S |w kMgszNBf{X'3?2}vkdi܈H jTxU_c7EZ`z ׺^岘)S rs^wקsG;Td*N7XN~ϧg@"xX; #fqE8Y:Ma?jvILgߓotEApicNحv=TFM T_ xHv?onf1܏09jm7T旘^'(>-Sg ݝp.&)ZaXCvPx1K> A5Ò һ!H S;\/P| t)=l;ݡvYc%y_Go .٘_ uEJc,Ťҿ#l$J^ge5OKӣKЮDD"> X"sd5]-&+SzZ*"6;8 CmIHvHI nz,=jlNt#đ&dP)h^&lXTTIj lWߑA Dv 'ݴXԓ> m7G@lju"?_N ryN#/pKijOxK1r[@JGp.v Ps*pN1S}=9k?Z:y>*(@Ow$5UϽV)D.K#/ %^@ςb~oy[S:ÊI i0U7)֟p8!%Uw稞c 1Q1}]2Sjo(IYlNz b0:[)+QU, XZɔ_?} 1?3x]glbK1._Y5Mfҫ 4}RCrҞw? ?+egU9|ew;^@Dz'ʽRW!BHP#=op|0uE@L\A5.s$a`jlѳ fG)1ID)l2:N2=Jӑ ǪMJ̈́Lk5^5F$RGE" S Z tRLlj9)PsZJ搫#jt]. 8ّo`֒olYG+ʝl{]Ӵh D>!2~Eq& :c5pRPJqUafl\9hr_z Z!4rk,:-N֞ͅ ecdLV F`7~[ ^zm樖8JZ:2du6q}vQ0=^Rg@d\Fc;bje J9T_FzpcY&fӧoYpE{xƀu!G⬸ Փ!9N *xz9Ac'?co*J}Xm_~w4:dr唭,޸2Ro>I?zG؊ȪoE*Iɻ"befr:dFeL({Lw@:kdkÿUtPl!^b:$_,9CgoWȼ)_Qn'~KAF޸EpX='b^"y0ې _D]|u=]d"x]Vch܄9oK.˂(.Ppp+Jl4.)fX6"YXwM)Cϝ:oIrmN*ԓ->z0)p9,AZݼ ".# M Gc٩1P7J_)Qŗw Oƻ6x'uVׇdg!\ȯ`=Xe,#QSTRzԚf{0JBCac{x0;I6IzY $l^ޣ6{F E]l_,&0N /4k4+na)o\%7yVs6̲3};pqNNvr3MHXl0ۨ>1.i|d;)ìN^8֊/D2JtjżS޸g,#?9!I[еq/8ܻvÍGَ6 q#Pp\b$4vPYWDRRSK?js\)\@ 6P ?ŧ/2\1]Efd=F Myό"vF1LI0㿏D'~A Vٗ 7Ulyh'aV-sR!R 7|Κb}XjW`C/ ?nxVpVxoԭ}CĮ]ene0Z#dS#v;i*Lе뗓.}ZziY$>F_^J^ZR-xd4s_ 'ӹJ HI\x0E#5yw1種i*gh -3WɤwU^h\NvL-BByÎ>UFу TF˵SIv>Htu#t 7 SuȌְ yevN C'갘l0[.JghDӰAr7TF?dq-ޞc /MIfݹ=+bY H,0@ˉ86\m<0Ϛꈢ•PԎ6hJ4U*Jxs-OfsZ8X:T\_fo{*]lƓ%rtĖHͧT:g}&_#^L9y=Jcaڦ'ZYN*ҁ5N5V1 Gi2c#1w-~d#9[Hh8_6φz1t5@ǡ>N fQnpDv]a "Y"akjz~uSDzMYp)2:IŌϫS|z|C GzOt%S#ZE5hsqB0$^]ͤFǨ(.:4˦!sQx~ ~RzhyZUC1KM< UM~CRyʼ=9ghd/kys0ڋn9)Qd4Zɲe&?xgƞ;.qB3,~ͺx'[0A;&-tB^^Z*0fdx/5Y.6 *-px`ᦶI`j]hP3wױ+Hw:]$sr"v;$YC6XVTi NR[p1\$]bz)[w/0oY+9ރ_,jAAv*&w1UM bRAhuW FdߠWC 0iy|#lzmK)L'oXxȡOyfnROVF&었LI*j~ r˫GM(C<Ü ą?e5صc]ԢlkPk.]f .n*҈ƅz?OzxA)QA ۨ]Aw6XbӢc+^qn r%}W9R)' UBk{@Mj')6swNfRu@0ˍюZ3!sx8vk FdJ~-֫/駷 +# ?e9X\)46 - ~nEB7yNf,eN)C"vJ_0NWhdz4^I]~3Pg͛9EWPj ɼĿ_Cy㚧sICGJUwA}IZC f#YVdd$5ir0fL&6 smЪ~t؁TC`QhI (K(w5)C<`2<;S.;7ob63 3kGE?gfg$DI`- A+MU.$0o> rɑ%E^8,BS'=Py2*A=(˾[Σg!͛A=jt]-.tNΛu d0@J>8c)UEy hZDuՑSM23ؐ,2-a}dٛO&W SƐo0˲0ZZE%l¬A8`Z.޻Ɏvs}j2yv $*wx.P0 \ ߲Sîpea#W0%nk&QQO! ka2>bWU|x&I'Wq.YiPV0%.Q8q?ꅧ~>Dl]ZT^9t>di1rR+I`ײ|b䎘aiοe'A-8" C7O ڂ5ju PW0BঽE6I!M.{ŶieeM5_o%w'X!%--E7GJ?݅5e&^]3t?b8&Ǟ]1a# 9i<3QUq2pyMi)&0L_ZHܜFw3F趸IE%yGR)N~<  QyfJSɭ>kHht/_\abN3o9K&9R!ڒ,sR/-79,3CF8Ln|PXUy5Gq^:=3QF!|mnw?il%I6|"W8Vm$܄Rh+ۅ! /97}v{^7M~+_2&x&1(w]T15 ZYo?ق#r#W?z[( z?X"v>SM(z?> =|b\D++vbO§u@Zy^P-,y{e*4, rc+cѺ `m0: tZUV^Pء<_X\'Ar1UJ(Hx.h"ܿw?)H< L2=)YEtEͥ+| DZ3 žlB '}NZ*xUD!Clr%Jʵb4^͏6%Y tL#f7]SH$1?bn$8\T^P D(S2f"<޿Kcyti.b2$lfR dỳs1+oKH^4cE֬># ӷG3O wud}~6B8K/".i0#ۧu5Κ*n(cY譀H! ei/sʥ)Ff]HWo,D^E9$ǃY s{ױiP||i@ oqW,_f6i,gT \ -w`مm=ހ`XqaXn_x_`I'0P=IαE acSY}ӧ":e_bDf[/}^|;&P~=Gn-P(27"@Fr faMAO*O-p$fW-*YWfMoͶܲ?W%trf~%~ۧ34bFLh+gC˴;_Gط|j!\*3Fs.k81$ų*4 μTd9@)A7a [b#Ša}boZ5楸DJTw|A'[>iHpLdU2.ŧkH.}6'c JoYSaE'=Fܥ7)zqmx-P;mjA5;xc, FSO|7iiKzzy,[ve8OJBЌ>_iO %Z%Z]$M-"I4VU*i[Y !RYJeG0MG F"HIbhHRخR?k6Qa~ P leo>UUPWzGh]"0(n.r*hm=Ϯ'?hA.$k\0S/sksV~xgZܩsYyY!>سD*K8e/ aLƬSzT/QG .v߇p?$h[?i $bEչQwijzZ9=N$RIkǿI=12a/[a7 G06]x471E;7f\%n,N3fǏw`mt=YRW.P#ѿ&N '5R|o! jgxߋ ̌<4 ꟑ"D.q-.',Su6ʣ5Οv۸ة08  ],3(㠢2EԳSmz *%.Ir/9% ';wԭh1SЍ:rg#C[bpR,1L'lc5\jy>u<(Xd2cSXq=|SqK+x֊EVTؖwt[ip2{g6K z x#귦2PͻHRӛ[weQA+Sk-;8͜k׏NB63 rdE MO(rN8LǏ0q `7Id :(BP]D'\k!Өom5=P dq7 D8idcKƺR\Ea!;"_S~{, #gcq=Wi#Wϑ*x E%^&Rбj>|wٕ0{]֞*3Pv cpA_| dMe6BP8cbB+C.H H"I9YS8^ V\ ?&ߋi݂6ìӟ%W<*^Q H'SLKۻt1+ad4;*bҰ-Ⱥ ?3sm\rtIK ZVp ;}h4^d"X?B~u[ ,P8@8Bn~(1#:YX1m/[G|ξI  О:Pms{IĖ~`m;fyʷjdJ姏6m=Y{(')KPj/hQTQ|&a~xL@ƢSZa1#p)TD$zu|:ehc 5alj;bB]*yVMqeg&f%s,` @QQȨx=Sx BFVto9w2 -MfC4 d޼[zJӎEP`-6pcwFC6@eP8n ʟtos*& ^/Fav;B[/6Vc v&aHwdB3X δ+UY P 5LK+:f5ӝx(镲4ơ16i.=Z]PU0~uM!a~=7C۹sß3?N! _՗Ϭ-jڣ58䙶eK+33yV)%ύ@;Eʙܯ*am\3⁃'`'TJu_t"Uj E @*u`|,øuF7 ōg-rzDk~Ճa?3rGvz{ڍj@zUE#o ytS ̱SuCd|%Y"U" aJbf i5t1!pnZOn|o-#EL3AE,'JuYHgHG?O+m7 qgVQOG?c*nnCbR0dr~ ErneLjл/ 5E0?8hxP b~ }:}}0u|@|hoU72WK!ڠOͯ7^E{W9}k s26)]upx2x}ka|;<@|wgi8fSb#3'0:bDʫCzC[0L jʭ<5Sİ֓ݚy4r8,FLKqz0" kP wm7\NE;Lb|Ս fX#.Ąۙ dLC&+jz/kxQ3|AK?߇ u,O {1eʹRvas¥ ޅڴt%Lj-[Ν(A5 '{7&oBmq˺L>P?IU3jJڐ4M`b%x)%h*3M=b$Hܺř*6!u:h0]뺸KO};%WB6(aōpMgE!Bf=bэ8Y6%6]3yjOMTVmQAm/dbK1^ 0(ىeOJ`4!VYۜ%| iDؼfl@جT' )TU [ 1+=OBK;ٻt23O쓹OFduxJgb[ro9F&ZL: P7vҙ0T̺j{*Ϲd uvp\NhfEɧV¿HJF4}~G Ome_QZ-5-Q?AV 8P@BoTM4m"Q>51:v[I3 3ֽm~}IR=c96MS:P-Hn^yaXǬѣ8V?Bb&yC#{$P gH E nt^<}Gl`,T=9ލqcNJţ/WSRiNh'_׏&IPbQS%8oB5 @'kAq?5 󅄬P3NZ33o'f7ØuJM·C (I;4NIrtUA`țzLC("suqGdnx7yr␢U3$b `ýڨFQHs=&xTI.7`.o~ ]0 2uщ*T3#,ǀB(qWNA&$zf=PC_:q8%m"PFr$Lzñz-yv}2ʇ'.܆wd1 YV"LwEZi9~3!iaȑD[KVDw0G?(Ƥ/KGa%b yQI qw6_JΨcF-Y,!\|.Ͳ4%6Hj%Kv|%KT t@˾rG &ˏB_6*:hmm|t- ٸ; o(( Axw՞uF;+N)vv'vwgfANg?Qw0\~+/٠U[v }s{zbYF+\KOϴҁ+*xbYfm'k#=@W)QQ+.bJƯ~?.ČdFb UgN~9} X25H;2 $yÂ{u2LT<2%.9R':_i<+mI-϶֮7XtlI^ʡ"ZBzZdvıYU<(~ M').({ y47.ܺ5%I ۂʓOmronlR_a.TkoG3<؛+Cmc ӽ)Hwʏ@/~$ܵtfӿ td<ڋ݌BXIrAn{9֊Wȿ YQrh=yYD4E5!<)w[}$zdv0ڳ4-H"n^vHz&\EV" Gk'A!z9؜yU;2ȑh-n긼%˲>ch>`5=tsr?)S$MC}_/h"&}ʢW#E$%nl'yĥWK0i}"rߒ9ETUX'"Od,ҍ2e9Pj9䮕=zU]f[UDdь7cT`AJO(ܵ:$+ު{Ċ$^ѫ?sA%-[9IBx1U?׽6̗+"<#jX邙>=dǤ)LۑT&n*@ OXnm#OH3/^bH'&vbى}o)ED97K\Zr$@B6 vDybpl u[>I`ܝYldR$ ,[cIH (X &2*oeJ>.6kHu񺙰/I&nP K-r!aa!>v\6V5~'U@\gj5}0Rexsyl$V|*DC]2&>Qe'{x: Բa:@E[SCBexj={:lm*&׆#  F}‘q.K u1mu([!43ebi6E6H+q2`؃ s!Fkx XrAɿfsU;#[=xu%SS.dytrphSJ 9Z4`Vm8\!%+_6j^_6Mƈ>ٛu8O45埧F4=zjxDOӘ$dv65bAg( #l17|9@1L$n^!*^3 (R_)`VQW* b@ *s/?@Gvj>Y猼w%Cx@aK.\a Vة(>UUC+ + 8n)Wvl$BF|o$@JDl7 (o@!k)7ٞ`qJsc=NulCl4V!#%%cvhs{4 : ͗ff>G.D9VR@bC4T* vbZm@\Wʘ}HT NlI 5<#sxU׍T[L&a:TBY~ri߻uh$0b(0u{X{@缬in>%0b}QU/٠DX0xqRWC hfu^TF+5(-$0=P`Pw$' NwؤONF 2hb6CwzHeW <)S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ<4"$ CtT8XF8`STk4__ Z9R  @ h#V˲^S7 G$ c2OB98 Yӳ-ƈ|:î@> ;,!`!͊^,༓إ{*{0Qk1$FU"lU!eΔx$830) \%ehIH /GX3]׉g;t}!J @sm{Rfx"TْW/[k%ϩQ*PD1b8nJ~SN?/; 3V= /bF  M0<-w=7wy C"_!,RN8I&<!\S;2G\ԕ5mdu.'Zdn|MO4uTx( &RG\˗S[w&Ï Ozlm:6 -ov|I#\:vD>-wQhO׮JWG~.h3t6U'͏ ؒ*3#,e<)/Nr6vʾޭ BSS+PBSA!z`Hx?w^P=nx 0uf{h dK7L~'J9ʿ,o&`LûBzwQjb f FDZ"$t^; IiVIhÇNw]HyY`cI&6Cr (ID| ?KԐC+v.TéI ѵǬ9K^ECV_/ P4Lבq6[Gg[x}3$cFBjٳ »0)y 5MiJW449ob {y;zzFK\u>u~SwsS %UM>Ik{ ҁZ缲L~g]ڋM볡(ȺV;Xk?;ȗebw2f6ufVL_s|;_5_H['w/;%k4KQ l[ȟ0 + *7 :yR!n8slURYg(ex_juWN)9ؙv  AM-*4dpEA$S@=azkhF8XGv, E9Q [n&K?B[i>Wj̆`1͋]YQ-`k^]{Ԡ*p[-߆`CѢZ VG^7"gsmLR V(q♊oh<O<с tUK+<*F.:$\qo栗\s.O(PKW5o^Cvd`Hy4.r-yjl1k!0w9Wۀ#']c{}ɏ;T "zBY?v P3&^/amf)F7ak-C?26f*Sh%;Z;WD,X*+k:ްYBrB2ӯ{UU$n}D }Rk ^IwEiіk& DA`+nUoԹ s"<4םgjќؖx+ 3tY@5dx/pwIP@iӁ[7[@*U6zh >G:.M}I&M\#n>*B WZAu;RSz[lX3QwRDK^rF3fxKi!5ٹq t[~Nn&>L/E^=y0:}^h8ʇNCoyMD]=<@ґGM_5,RRu8$f!<5bɒ6@Nr>l2Z) @/.yFgOP'r_C}!qxUl,^u;%#IxY3du@<>nChe=osd(}b ݴf=9Avtu0e7r[L+Ӣ82lE|q.!4ޗ:~F᫗)7ǰ0XRqM䰲:G,# `ūRRX5 w.N1G:BWȝڟYj/Y⹰+&^;Uŧ>;ԙLSO Ud9 CmZnDC nAyaLO7!p h"̄I(9 TCK Vv'*ݒs/sʱ^ 9=T(Sk=9T? A ?qQ9O7k8_Q&.ί'EJo7}uU&s0BCv&Y@pT!݈յr _nu#݆b[0*JFj'Nh-x0 d7 *Bܹny3Ścq1nņCGKFULyNiNwX&HE y)=ЇP1xȿFnV3y)rrN|7U$_c·u=jߡG_%y5`E%}zW5B2@_7dN]ΡCpŁ6F'5ܵ]ml,MPo!l`?.<ۀ0aCsF-쬨P+t1:aA>.nنga'F6컝\iiLK*R9~8 Pr0b tHx\,aBkRj~Xri'!gA BuX]^8,\~%Z^_.?Z $B=Ay m&75|Z9$s*{拃tb2okވO? Qjh4gw~46|Cd:dH Ad={̅'s4(xdeV7HAiFʋ2RªH ٙReJj=l=5 QE=Q+̫37Cu#HPZz.r28A0֖>,ϻ".zwf Jƌ*hW4a_ aTnzxmaHI_ڃAGIs.hߋ'Sm.3? 4uOM"qhvPZt` dY叧~ L*D!FXcĆddȈýe2tߎm85E]] zL4:־uq!L bd> X7CwUh+n%o:qX6—j6w`K>Qm+v\ aEftR&\e\M?#eiq;pK٣}"D ܳ`Ouԃw@0J\Z^ g:r:qRpO"q.%18yjɯt|}wUm{onLֆ@?V"^?B#pF`d~ꬫ z'/We.Ҵ4xIaVar7S6gڼr堣z5I6dqg:$DoJ?dA!w3uhc_iG`C95yG6$+,<YRވSe~BM<UϰO85$jJTTwDP < zӳWмI%tVM.J>ӑ<-]tr%-c( 1y 02FK쎳o9dO~GKwr!bvڡVT{nҲ"P2*. GJ@3<:E5$`shrKo.F4k fCPÖ\Z߭0"YmŇzCOl0\qf%l=GpϖlWaQی=Ks|,@R;#gm'у@Ƞ=RJy("?MYk}xt"ZYn24ly%;|Cs*3ώfRC'rl_. _5|?ps"k r+H/0ox{` }q4qtwLT϶B? ŷ0evZ#{:"P͆y1v[E $rAv  IԋT@Jt6am̒*PxRV$fI"h;E[&(^ TS5Z4jf<FJu{;Y'/G+ O{ D< ;Žiym9C8ݯ ^UjiJ.? 2q҃^ ,Saf"lt<`(sq9DwұmFZr9|M򏼜EF@NohSyyr&:GU?>LlpWSGG]&R:_v@H‰W $B)R)!/'"C/=I4k-\exHe}%`g= [{ֺ I*0[I|lN45K=P:u_+hHG9CtHeZdR&g!DÇ]h[Rd,,=;\ ޤ+Wz1dfV4CwPSZ}ZpJn` B'Ê5P| F.aTS$ix$ۇKL< 1aGc28`h '0 l[ᢾa"IΩ0)g`]1R[qB_s~Rtyx#տל f yQs `\3IQd?\A9/N#?n&7=U/Im4‹lV1A/ԦPde7S72[deMhמu#u*MBȘ$j?p߆?).GH q;"iQyH('ay/\A\iL3JSE*ʴ|UA .FjR9rbI LyFAOĵ3eh-&(1FNaDT"OK rc SYf%9┳7cmbNXܛw@ߦ<2!GɤlkGQ\Sd'a傭8Is\ ӫEkRJFW`'Gؗ f2芉7AJ1( Q#h`g$v[ҋs>ӉښF1RTM.Y/( !N"BٍVnDF  LǾX|޼! b8;ȒᩲNC8eT_ғ]+ef@Gp;O48hr(j"8?̄<ݧc8|E֖23v o,;Tj|淋 Y?3N4HSxd-ɫ$.Rr8156>Bej@64:R̞JHUe&ΩbϝH_^`Bn,۹t8ʺv>Pd oҟ˧G7v`|3tR Q&ޏrYssMMT֤<. hЖGz֕f6p \y#Ig t[<PɜX+`4Go[Tf[8.ނ Y_ʶZZd+u"ߋS/mDh\ @jƙ%2V's\cl$2HŸPh5lwSaӥҪK8˿ΚXΜ 2IihXa>v ͝q 3Kļ#W%lL dӉ ^8 *06WꗧkPq -pUb*S{B`S#*W|NF_Zj] b^!EYP%'o%?+xUyخC$C&-kOt^$GzD~'עb{!!w0{fxw&NBk& / [H销ȧsp> 4$Y7^w2K z%P}6~M8fX;щH2ɳWH:n&*?єhIURch@Iս @I>7=dzmǼN> .S -O0y l+@lWb|FG?ZZ`'pv\ c2+SD:q_ ×AUW˔޼$f_Y ӂHom ߛXF2!7y2Qr.aOiu-JPY-薫ם!:'ɹbzr:>b8T=> S*mTbVSa_ P[a߻/c4Z;=,7C/5Vw[BHp" M OiƤK{I?i Jak.v3_oͤMk2XNs.)fo\ bazáCs|jPI>3)Ӽ|40U멙}`XO3Pp/q!4$r L6L"q%+9* IҸ)a=fi zSz%OU'(Ʋ_0aS뛰 e,݆ʹ I/RA7Pf]-N nJUQe,U s]JrM/)iZSW8g>|<(/C856\8WN -* _on8#CqڿG6Qk1d'RƆЋ;4EQd ^H[ݎYh$٬~#fЈonsj;kwaJt~o74';H8ĩcMܴr̔B؜?N3gzq2,ܞ*x ^ɔ_,} LP$ݨƿMwt[G4݌'Dkl<g ̛QLh8 {19-aSSvY_-P>= _@USsZZ;uoB8 $Cʥ%*S31@Б=b^#1RNԾ-INbk@`\%qofٔ {9R1iuՍY9BRTb嘪ԧ"`]٢(-vb# GZ/ Pk98bf~̞5M@Yc>[=Hr^hpV'@?UjP%kd&XsA dV:܅[$ۜUb48 \f^]Bx=Q%&(8>"J0g]sP?(niX?N`V4Ҡ =XR/\q{6Zn 93g4:&G&Me3MOZ.`#00-"E4< G9;ˇ.16%[bZ01\_%ͧ?U<=yPb/.S,+K1A[s SjQ!Vbeݶc*kݦ u"W{ +wJBAŢ.f^UDl`~):UJa8s:­rd/jbⶀO59f"OftzoҠ&vԂ0_vWDk"@VOҀגw1 H5@QX$KX%^+]kVVԽCZ/~:,|"#n,Z|D`srJJ襜`ःoX1B1f9@6ei:/BO lS!uT~PŖC~׏n{p\{̝RU,p'甥| \[& 0-+b8O(^OnotNaV sG3Kz橖t)NƯMbt\w-9[OXrtv× C nh!+H!e6}/(%#-R3;8NesZGTB@*gE#h~lV1 gx0o[ӹl倔n=Hw̢bJ`9~Sk$Rd*)[ O2x^f_Q[ܻ7z: T0nfn|eu|ggw_]s6(.z8]ȇ{tB 2U!m GR[iZ"JB:2u!c]E>CyXAMjmAO۬¦й<!7ڤ\=Nb7MnCXΎA;M nwl0$[71.Rٜ?h1|Ya#CvW(1-f\hnwR,NREc 'wzsg}!wwX&HX1_wQSc*đ[xNwV@kD]XQ!sH3jpv'!TMo(5Rnw|%Roc k~|&,[CvXbϦ?o}5T 5Drs1'P_QӃu\?UE vE_}\[Γڶ8I]deIKU}%lJAY/ .w!Y(`RJs!>w+306lhr>EH>[\8+ѹ<w!$%V<]+ksد -._2Epfz2qq@\MG%@_nr$)݊`K*;JUM6 7+ڶlT0H){<;ZpH熙bmTI@paK} HyoIƌnyR0o$ὑj2F1Bsצ^LwQyVMkVȁni<8D>lgP<;z7Xf _lPWs.W"Oρ(eD>i1㉄]!C܊ *5zqug 9rV:i<괃\U>JcҵKQCao%qa!)R\%F\ hLqߧ <S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ<ഺoȕ.:<8p7at- D)K99^ |lAhi*~bhf6w~%Pt$u- k}WI6(D|:@|vПTt;ܚhz., Ԫ.7<~cL${Hon iӡ*_-"bD ^/uҿ=yx|鿶)Ren$h›?DE'Lͅ3m b<:< :?b5UR*l&L߳wp{N+F [smɽT.Rr^,L#ԊrVdڷ %q,`9pD7/? C.7:ǀ %G`@j5,Hb9q!ۻ%WFjn#iBN+&;>ϒן#52rUifɻ9$mVdxsEf @W')VDm UlO#@]W[ OG?cuИ>Y ="ހ9O/O`j_)2O_G ;-1^!R._͓7,'@;fS48^ yH!]] ssA^(e|wp#Ue"Op;;pE޹ŧ߂G#l}XZmR0@l3.v݈7;4]CYb.CH嘉z&#% z2w-* ]mStX2Sɮe/JLZ1E)Q^Zʆ1LL:g"[eQlLťI.LYrQǻƻ/hw2Y<>cZRXm,["竆*]e (ؚPSf63jD &荒gv8 rW>KH^/ϐZRFP0;`3cdFx_ QuNooف|_-_ o/y H1Khar1,3RP~Y'H:/WO2a@lWǺSK5JԊ]ﲛJQ΍‘nI7z돐ʶ΍9AJ s9FDB!L=ߙ@MiH >,YBAyM'Vod+㑯rm_Љ1 h@Rn%V8(!H#%}vbFz1J/8zP=k:/&v*hhÀ¸U*ì)o( Յw߄a9H U'D[D_ qeX%g$9 zmE}{=c&_% @Gפ]$oJv LcP cy: ݟjL ~T΄'Œ>E5c#|Y2ke:~^V-ŢU)?%aِ"能hW̨B2aߏe;\BSb:Rϸ -)g(kJPjI$ %4k}|v~&Τ,m# '=aJ"(^KkpPYqNz)UD5ӂINҴ)r{H)*O!T,QOْT($3"j./z}ד:\HAtB9ٴ^Q Uw OTn1]M.$,^e Yx/d_#<䉵ezZDk5b[͞,ra5!L t[֑ ?6^miH*/1C{ R"EoG:l7fRb+8N0I :ЮǷFQhaOje-hΩy'Ϛ('\f@k݁yg!qUEÃT~)o.5-e4L]m3w^}(ϴr\5e z]I42%P{<՟ֈ+6{;&fsD\O_k jd86xJWdE!?zNh>f%>4OrU1kwQuPz=^ (067χ~=JO#?Z3Sbx'3Js'qLTۉc @,9 a+!<Z[- {Ĉ'smx''噈P>-Ʌ:}A&OlC/Ns[ eJF,v0n[J-|-]N "Iz{a9ݖ$G6mrz3a:g٦^78sqjWu *'66LI*9;;'Y_,fuJs6&( z[&mƶ=_m !Fἦcy ,4]tȭcv 2#ACl3un xe/^N<Ϣ=DAP%/,EZ)w(]K8P}ڨojQ mG=~ Tj [<Y^q=K=^'AO/Fx~-M`)d%?F`@u"=Ty5^:Ty%nkM:aAE-P y0mz 乷 hwO|g`|G>}fkeڴ$5l rxљBRgT7H8Sn̲MJ-[8$G5XyĄH$?}o`nأd6wtv* 70 *.'8=ko U97%szM|MDyXXvb|D=n2h}X]g+KLpb8M:T 𥂗U+.\Wðǘچn Q.8@m4QbNZYFˬH?̒úzS8> [V-vMdնfYe1J/maLKǨ5 g}hXUlmapNq~<攡7*˔\Yy0h=ݧ-YkX]_/zU!_,!Uv ?,t[DD#(3pZJ$#3EEkw!pfq7s6.3LD%RuhG:g ノ}r{sa7*W[zM#%)2;$hpcVWF8&+ٰwNC;KOABUnk3~p5y˻ʻ$>4wcqP2yrg:ō8M*sEؖUvXk҂0m2{a]C]!U Ķ,3^-*s=7~CTyLZ<[(ʭ BM(Q־K#%ɁPĔbS)%O/ᘁ fX{̹ͻf GK>PkD*Um7t'hq|E,dF'tc&H "-l`q ck7LyIx[oKV'L:giAܸ_Dfh\2_iəҰGQa í#Z'#RJ B,Gv?qw$}Qq>/-h}yK|/@|@|i)%|]WZ.輙7tlgrwY ZRQCJ1p 'sڦ#:G?ϗ[夆R)-LOީ Yg%>=mN ʔ Rb<MpR5 b_j]AiѝPvjsJKc:U1$qJ&$3,J&`k[a>qaWŪ;J[E!ZI+W'iWjG>R!Vv>"0jn&3L)4YbĄ3p+[%kx~M+s=>'xݐ(5╒L-uʨ vdQӮR&T!xׂQ>@ݢlv塎FRNگ®nݯmp(_+QWdm4pr\38&03Ͱg4gßVq&Ȏ39mLWxWkZ ,G y487^hN5!B W9çP B_'50.Hz]OTOYdNi>!(>1: 3t$)H-|=ΰ gv ͒!#PXz-kO.7ḙX24&oB1;l3Ǒ²Bpl6Y" ϶vhF7n.fp-[*NO' o8uJgK1%g/ͩ`@x&FxpT͞(owGRDgW2df`A`Gdѣ rW ]zި>& '澉 ]߫ܧts"lqb|&a$HHj4 Hm]5'j\clk8P+^.Qb{kW@jy;@ >F?JuF*~%-\hѳ~4\ \.qQQM` HX3Nc+)L2pW%tmyI*>J[˕%+.xw.l?~0D6_]?n]? OvO]:;åkeq4FZֳI y3r%2&ƒ]R%ELѨ:];Y@<=*;q>8@by1C.e{1JbճS]4^3J I킔ߦ~2٠e,'*r3*Dhs&*sD\{;Z@4dҬ7"8'[xz ϮBtAkP yQXH3k?lAEV7*_qBrH)7ϷօEd(=_q_iR3R seH:ȹW&r]m)&Lt`cK~m @#MV7zPJ췿c^IԨJ>#江 gazJCgiR :$r`Y J}{+#%]upE93LOnQ׭-@d۷ 9xTii/iԒsoEd _#̳ !ـyY0@KT3qL*. R3 Pa$ >S WPW(/7}SW~$҅ZxE'!"F&=PJu jԘ)WF{\SO_rc/GŷB?P{n KB}[}; XU}0asu'Hnet$#nFC$\;;^?q(I"R49?ٲP{A^2bUMI3$uOwP@FDүӦ$ I樿UQ` eB)oLَ@ <0<Vشi3%ol0F[*7?0zP-ҧ-6ƕևჸbm{pì_ [|?!af\5Nڰ^F/go-#p~rs2_4YlORvm.b Jf5XGJ#jV(7D^ 7(ByN_򥝓Mh_{ *^ ]ɏ7+iu!Y9a]v8MZv.j,%0@gw @MD(3ى38V):[ DīR0^sԐz+,w{O7cF0V~itb`moGe!@ne[)3%x~?Lg3SrB0V X8,w 3L2NbŽV*Z3\ rle!R.|"!\^P1AZ kh(x{iԶeo>Qw~ s)<:ht? bi?)ύ6TY}) ?A3{0Zjk!/+-w҈Q%|)u$CK`DqjL)Hux`i7}TuSe#svvە62"lF(."kV#60muM %VIczW9ޣ!`)l#ӧhI4@oV;: :,q׊ԏ,S{G9-&MbȞ~bVWZ]EXu'&K)\,-ػ7s@:E$#5+C7{/X 6<&L,(4EoB6MP%b) ]P nG=m {'!nSo&ugE1a<<  $vtTyJp$xbic~tܢ)7[<4dbQ|BLBb N3>aCiy=y~s'~{!e[hux3pG Z`#w^ŒLq_ᲖXp9wc^F3w>IN o QW3ѹ٦vʏ,-[I${Ϯܤ *{>]wo,Se$$ilV\) ֑̔nO\aF{U#ЯE(pΪ}QuYU]*. VN H]cR Y$m($4bĜ۷^Y֑T#/{ɍb|YBX9~6{W|]bIկgj1pFEY)} L|r#ߺA k2E/zQ#mHGȞyZzs¤u8q?!:W4z琲S':hHȦw(ETrO"Y'Hk >DĕIҁ+X3֚qOo|K ԵiPО{H \=|X,3Lo ˋqL|:4$ !52 Tՠ||/@|iњg }FLTVo/?NAMX52;7Q&Y 6 e;5ֻ Z! Ժ0!MT_|,E|w+ILzhm} ЯQ4%%`s:ɤ$5gKpvaQ Tk[1"*jrb#:4~% +_薱GiFY3N'-9vāH~^:W*,Fc}R8zFX(ɭ/ Y$PpX8s,?ܼC ؇Wm!B5bTXiShL[ %d"UH~YYkcc'{h$ahbSQB$ֹl'4FغMD}%BvAϪo]j-+ gc:?ݴZ@npc?? l {v_8 c3Lyq˙,z*֩f߫fdI#1ϩу%~ $|NOɦrldHi%b?< 9W@9?JLwBr4OH&{}-$u.iI&S3m~aXQ+a9lP P{ MZ/y%,9(X]lQo^mUuu1^$ EHV4L3 ;doZww'pdT@6c-Xi[i|J-ʍ895[RI!á7p9_QJ0ya5ϔ8a%~`$/at]J^hD4lh&4H{b2 iZmV6ߨOm۾vMԛ0¾N'הE[<{>ܜ<GщbB`~0bmps2*jV{nKe|si,:uxɺ (Uct(hRlO@RӅLiO=XJuuƩ>qb0_NOrΦKM!XNAg@]x^/7A#1ҟjJf2$hzCMO DXrQS}#|LvsMKLQym/~z)%B[K w!RtŊt\P%,;5lqp+Vvlpi7SX3)[P #;q1>)q澉PE*\鉢Oי $v,AW`J;vl= ֣ Ʃdm#+ ǰUD/e/pLC/;渙1qkx?)x'UD=}|7܇>:}VRހp,z5u|*DG~o<nFӃݬUʃl..m?~nֿ٘kd'ucZfgTwi-.֮KD3|RkR3zVޚ,YUpnY1}^L700[wcCFo3̛HM|OehuO;YhaIJm!6 cr3̀)dj[a#tXSHDjIфxD*U!-/1}u#%tϕ{{V!ʵ 6zO A',~Q_fɢm2:R5 @`6W0M'cF,~!O AUQщӿnpJR ʬb2+,ɅFbzEAe?N1y74.c!{1($7_Q-eUE`D}+Kiij+QjGUW_υD؆)!t :ѝXG文x+Jb٠hR)i(KP#~b>Gc3;O+A)~( *azx<[ ^Y 3JV(-`U֭ C>o" íA%.؝[28J+)_TQ 20/拠4 N xnl_ɠ[VTnuaβOp9^1xQ kBj/۴ e^/}mA2 1np0ж1`KZ#Uo]U#F)jPNV#[CrWOiz#U}SF4{B@cRdo\8r?fM;7V֠D; eOxۋ7sk؏ -]Q<'@yw)aA%Sd%A:}ev "ˑITU"4gv"X;Wth˸(ܢj~BnUv9{%)L7lrC|zΔ]*}y2T0x'ш_HTIftr?{䩷QEuIn"}rfַ [4Rk› $n =ζ.:~#/rtЭJ@0dLg5vW3zuv;UʿK{Zz`WI8CP'.;Hl)$hbG|.ӊͲ'kb.mk6cgqvX {xGM% _x4l9 vJTiEJpɟH!2eg xRFhh eu}(*&#-yV#` EQ!",]0mz/%ؤ:P:vV94X ̾KL;z<.^[֊YeLeOe[Pk>H/:\RF?SHؔXàax`J\HGVo}x83; $YmdyX +ԌS:ϡe:0*i !a"A 7iO%9F`Lp8)6xQ c8:7,ۆQz\ϵ~i扃we^{aI^!5rD$l|#Ơ;zm'X$`~@ HƐtt4nC]e3+!'~7DcS'hjx.HZ?۶KưKt*tvIm;{-Z+ĪC$2&AlG^vl*0'cP&ǐ QfjTO]54`WmW\H4p W%wGџy'mF~-g=xv~li&`J;-ڠ=d*NjiRWx3+Y!Y9 g!Ff4,#T4'?"ljM踬Dz}:"G `F}h@Ho\8bq[_R,Y֫h0VcFp\ζIǬ~' `w!u +f/gRB e#!|8$H~YX]"WbtMxzV{ N?[dA^ FZ#^&YfAxZ|{1=)*x֜Kpu;mhSuV}s(ǃa0Mo.kˆj 3`#jSFV$Ig7΁ޫ}f4 !fbNo%ӗ,z[% zrof&OzQ~4 O/vK*ETO?F,,G:tP/]<S{RJ=9\F@Q%NIA).ҙ#&.W\ *ɺ<96?C.5%|(2vat$+uj+Xy >&zr;.bzjK۪r JLXVJHݷv:E tP?Y m&A`s9^:D1UT0'9b}Xe=ƐM ` k聜}B!@6tkM%?I Z.Ml]TV-v0EIq 8QC&3u]^Jtb l+5ApLm 9uwU#w|z.c qUEblCJ1}|UcY3FMr4E~}0WبUUΚ4Ǥi=hn;V BXdJ.SF+&00$s'RKoJ|—[K,jKYw2+2qO7Elb ts a.$Jy5á$~}DͺJS# :#i~`2$ĻfLKZ5#j~n5_G sR?1Xݖ&:C_OCz` (+ۭR4`zuP&3.EI VM49Ս4A}ԢglB)YNjBxo՚Z<_/3(BzDkloڈ!ι/xa qƃޮ]XaМPꟽ:ԨunqQ?0dC$5&BO+vU #%~۾S֚̆j"آ:)-22`*o*Wk̔wWD6&uǪ0t X_+ūj0$K#ȏ uYM xB V(NtpЂۤqZ[Q+~LDLXV)!d>#4Ϗ']z Np3\cm&+Eb|0͇c0MSz^OZUFuvt=QR}q\A ?=_xk̇3 _g>xL>-߇&$C9]O9d|{w pXU!5Fy$ JQSm φb@k&(yckd}Ք} _G }`Yy^v⾂J7׍< rDd杉&|")f؈;9;'@vHu$Y3:(bĚb`SUVG4ڞy,N=4(|N|6>U>ѿ ޠ r]-}_лvctDRIT'@.hmtPZY/su&O[nߝ_᎗=\ rf]VJ+kWcfVc|AU3W!A'")7tHF_4E%B4ӺT/2/78ݻ] H \4# -X+17/*:X+_Pv{L$=204b/Z@t?OĮ67"{d #yg>" $I &+YHjy+@y*8:mJRu@`H`xUڑ%D[A͹)I]k~:Sev5xҸHAWL|u ħ'a>IvH{+-}GvдT&c0'-}M4t4u+/:l "[/| }AD)Fmsaxg`L>1bj*'Vmr;S Au膨< _Ƅ"]-llu]PIWCrѭs)01`dly.k--;Y1}'%AٟĞ}gJ7LVyx :g:04Xe\֋E!LOnh_s2,΁RO\WS Tͪde4K7p"Ƭ1NWU3dPˆWah"rdo!6ׯA,9!P-PsNȃ_Ak,ͧ&=UrPv:G TOoGAiT%ͅ:c'%@ǕL7M?kFd/do@✗~rJ Nm8#vLYߧpݡX-[k`O|K9 ǐTBݙ"OuO/sGG28E 騜 s"19 | 7~*֪۴@QlsYq%nK^AգZ3P~@sa!72udc +H,xB%e&7Qht=&)ߪ BXT?nZe1?Gr)IUU~)Q+ܵWO ^:琁X“N Ia`B>c+Æ*lovѯiҵJOA}'۪i`>)%"K*-E~~7Xm,MScAAcq&xld}{ɍ&y`Fۤoؤ(l!T2E }P/#+~ m!5RNW ʀڼ)//D|ڽ,)aQѝkFd葪~"aoXtb, sSUq4}~eA!@=|qQuy6zjaةyvAiI7͈Hytvz.ҒsQpm^ƭV(rDŽz ԑn-MX0l0v^s@%_fk}\ ZlF|! s6, "I ֜%WM1q_U8*]6 ި;ͧ[B"y;v@xEFD~C1i=!_JN J3=E e:<]Q,PN\"-cg=EhR"B^ RI E^v~$jNe`%IڻA+ԇNGl)#+Ւ#Ii!$|W64 DQ:8cc"#$U7m7_m,z>'KH"[E/]­32ğ߀l 0a]N6 -M'ϝgO#7 ]5Q\I4k$8 ֫9XMM(ߪ$!f)4X c#_uymUjgt7lخ;7)vhb[|Uʥ:n"H1g )vuZ3$@?{W'xl:puH<ZR[.`^'ӵey;YK0G4%ra?.d>wf^,HC]JG)˻SjI]i Fs` [j?U=r`Q:pQ%S2gM<EƫAEgF$2;X|עT?2M=g6>.޲ mDcS~A8!O9Q@$5X!O6]5:7GDQh@v_JȰ4ʕwG/R]'AyݻPS]yV'z+#E'^fXyU槺`&ZYh7@8W]O(]pi~2h(<*88=3E Bg_W|wF#.}4]Jp6aj}Fh: -m0nbgUDߺ4w 0{e{ƒLf 76?r wu,Q3RQ6',qy$TUDpOH}{-M hedQ$-2ږw_Dݿ"*W1GKiAx9'Bn# huOYk▚9XV,V^PEl`&|ӿ|@|@> /w$I0 ř$ӿ|i(;1x;OA"ׂӊ@`o(O9UB@rXAJ[yM_njXf8zŎDH"K/Y~CjOlސ~,KN5>ڌv\ڥ]Ԟ*sЬهw^&8021Z+Lw@p2٫ehtYw[ȂL⸛iҘM}J5!47oR4"X^O2"@aAbco2[xyȪ< '* qķ$y>}\SҒE$WJouʿX("CaʃDΞAJA/&?]Ldz< (=)Z)ՖXH P|?r_X H%CG c}FE~nY# iy aѾ)oKukhS%vUP blխ!wtz?K5nK(rV.LܔYw 80'j́1>BY]}t&XI(\saCV?bʓ2ao)QPh'&"8 x㯠^gPpC L?4$JɳEW#1񪶰ٚ)ޕ Wz Ӛ&S,xIS֕oAIS5`⤦YtXBKA 7k G($mIfTZ$;_|9"T/M&̱v$W FcZ8YʷŭPd`k8 k??h õMgS#)`D^9G^2D@v wϔmUb%{7)qqƲaKŀϑA~yp^b:'Rl'!ЇI-O׵~BF4({3(M>xV?i5C1Tb/ћmtv{n2% u$SOJF>EY\[ew5,/Z.8кW xh2xdHXueP___&a-Z"]Q,0 <k [؜U$LV%H1hd 3_(:׊Vb&4W.sp) ]ʎqV{H ]}:FV.KsUWTw3Fی#2Y#z L5Bh49=>7$H@.=Ft\' %V/W0MҨ*)/٦ /t{V~],@?05Ng>wƒ6;/QHyr;ȷԛڭ`m(,w2% {IH)nu'4_@@j;cWIƢϾ$qr=XQxSy4L.6x_1jS^5 }mtjmO0A z<ҍ}Ux|4)¿Pް}+eCO5Cc4hi$ku4fֳ;+.to]]+Xii@hDVt<=6 _oV o8_/]`̓gb):loC5<JpMiq"$j8"x8Te ܜ~c{[uIkϞv.#suo$2lJTn!!~yϙ~v{SQgRtG 75 Fv_ pl˂ Shrmo=6s$bH$E㐙Z[MhviA\'ez Ļ 3a.,&/ i P|c༚ j m],iĜ .gjavhwb%7S>:z#ݿ4;%lCyNݰ!v r=vků1i/{#qEL&lĦ3|HXr>YeiO '@IX/<3Xg el۱1l?#ƍ/zOƃL9 uzj5^K' 1 $bM-P]je€rb O+dt]we}I/-EN>ßZ #47CעZF;@2e7JS ,gP(}2;ڊU"C=e\G0E0(U3 \Ѫ&"~MuD8 gLF_n.ˇi5jzyg,v((trW( nTUC[ɰΟt{CRf=Kp_}y-Iw6D GY[ q&~;"'8I T`YJ}'imKKKYPb}o(22,aaw|*£qe(VCJB/n%\m^ZY3TbӔJ_,@ڲ (Jz2/3N+Sw! 1ho1iJomK9ћjEM>W'{NvBh8!՜NZsmgJ{[-;l0σ{Y],@n7Td 6t=`dz5$`e!ӑܣ/_'CfM`D!XRʁe JJ5 " .rNÉj67r*{/A׉e5E`"Һ;?L Ć#Y#cY D0g PrsmLI "͋_UDԪzڒ]hz9 .67>U"M^X1- ѵo4 &çF0g_?AP)<+K]0AFUzgVIe>0l~%Y& v|4ưbn +qn- [,m(S2ICeq/f|l:9g'Z1P*uY隙?AMIޞPn:rRD!,yI~y+lrkW籤ylrby B F@S:lrFsmj$Ax#DKp%dO;q:M6vjEkWa?cpM5q`7._8H\~٫ª&1w ~:xfw$P6Y=KFC`Dd ޒ%iζrv:xev91udeze:徏JVwEKp`P͡+H<ӽ6,\0]yiBrKcot [KMO]NLc6`9=a^؏V01;2(O W)|@|@>@ qtM)_ ĥ jy|@|i'Y !mA?(Q z^Kߧ7:ފ'==ud,o2KT%pV,F qO'?? A`_d%r8q;( ܙFNUr6:"W\87HiFf.`c)Bj#e#~aө E/TPQJY]ex\] _?)++ JbaN\OSFϰg} Nx^։Y}Ī,žg8i`@X2L,#`+8뫶#:y2ʗ/wA;V?r&9e\}Nˮ>PdɐFD x6ɁJzQb#9p"jgmqSkVAʴNPSh ?QƆS>NGYݼxo7Rh* "sIlkaS`B +/0fgtx}(/K lIr9XP#Rn'J j^p1t2:S6irWvln\߿])"uo=WcW3wCjH~;<A>JA1-)i8%A\ ބ3㼦-T||qkiqH,cʒ PB6`MgFGzE >[y Sn.d/pI9T%z'Ǜ=B8s";N~<WfUG~{}:+eרSU\-z"KtnT)!Vf@[0P)#6SţWS(8{)cs2a)աη2aEĔ,g=}Z;J$d${Y?l9rxOH9 k$ 5H*u<Wj^O߃׷I=`&dP >R f'h"+DFR_ u;x!Q8xI&ŗqˈzN_.݃??s5˺ q\u Dt qnJGiM'?f촀g;b\c'i3()(DYش2bL}ތJY6Ea5ϖ/)5Ѻ3Qk|HW) 1Q*X=16o}lCD症 UdAF{J`Ru! )L eU#CM]a4 O* l,ZpVYhtiS(C\PVf6Ub͐UzbE!s p(3EZs߮+Rf8q(+r剓Ho]rXXq!?/bC#K->I}\`d18szR-2gYh늵 Gլ)1cox>"ָȠ+e|UetF^o+;laI]^ WBO6F%iZΎbq` Ow2`/vay㈔~ ͧ912"g`znx3cx@PWs^w yB.R|/xC$6! zI<4\CG+r }̥1g|2RU[}|PK>GCRr5 8Bي\8(ig+L18{8 D{3g4n-gae_ Znr< %,vXOOعo#0ŲPmBk.j{ƟE <37-vA o`bҳB[{z{bVBO那 i_ekH+ҝ(̱=`LgRD8oMy;]07qPC* Qفs{Cũɀ~s(8x"ld6>LQ#WX(@^dame:o*0 }mp66D}7>S5م|4guWĭLQENDnx^C&Zj\XEwjz hkHS JMO8tDb Ђeݴ.gxRw d ^-$2 >5ROM0(Zw*3n^c^ѻu>! ]lJ#c#ʼnG.;JN73LγN*+' :1eŸ$gR3"2 $y,1|1t lɹjI [з4wddSo.( ͫZOcF~C;Q%%26 doYcNki~!n{kT5F^iSbpdՒՄ=`Σ?<d$w uz? l {|>ˀ5u_V2e}I ĺ<&Yg(? o9 b-8]&&G5]aTVZ|(,DD\{Ň W #?dpO8Ё/k&-Rp6$QֲcWDld=,xƹ75&x㨜Z"Ab~i&d"F]29姵Tz4NPY`$2I},,E%D3]FkS$-a[ɣNv*M("eI8&G;9Fh)2"PAWA9?cDUTQW$h3k £ 1o{Z >xtb/C1BWB \ڮ֮Sl*%5pd;_jߜqOq&:65̞oWP49P OMhMcBo~=1Ӹ_GBȦA@1R=ӹ (X_;쏄4e܈V[9< iϦi* rN$;5{íppH@ʤW;fϵCOR)diZ 9!j~HƴW߾B8)bP(-94@h*7 YhKO`9!K!`Rϫ9|`rѪVۑz&1G)V_ɓg_$*?`<Ͷ/+7`I إInhI%a49 r YK4،Ӌ֠P:bf6gk$6~6M O1-";jԦtXRպ?T|"[Lm8Uq Mp\Vr?a1v@삍*Kc3~JUhăޯMWOզ$,j3<4cFR4ZrBOQN:ʧ $W5%Mz;,n'p fr!5AA!dz!2 U݀=}LX&^nZ(7?Uy^BPaن bٽng@;C C|>痚dq t{xdBXN|7Ipo|H_`F[͠$u YML1S O$|'W.$0gޭ󦗚`JxXi ˆJrҹ>Sl_ tsf0[RC&(;i~kx V@gohliջzmԘ8jв:dɖ@mcL1#r9=ucsĆ˽rV_n} F["=Y\-]P f2j gv,Q6[ jq)qO٦5aGj^T4JTכl kJo岏2;AO<⒔SI ^k] wH }?5o٥+H;PuxyΧ7H7"ǽ;`syB~^'Ĥn+ sL7\W#Z,**#V׼3*տ#B+kĆNXC r62_PdxÇ(`Pu.sI*F ZHbsUmҳ;A{ TKCg +TdⰢ&XABd}$-P>+,($ۓײRI|2sh>`}PJ,}ԸgۘVllI)25YM=]1τK^?ΚIg &eNTœ- .E|nؠ01xȬx&E=Mhm-S>3" ݦXn&3)gךn0[n EdHX#5K0 Z"Z{qs:bS[yoã8A~yDՠOϙ=9HfncUT x)yP!Q6t|K(~9nyF kL3Ut& TѐΈ wLҗW/ ;jh]p\?#LA!*ܵ=SVgtZ=2%u貃H_(Rx4p>vё ?__bY"1^iO ǃ춡FʎtrF,E~N@d 6VLN%]lES0;w!(X|20bȼm~!)\-J&ʃЭo6wΘ3˼+dW3Ju8kvwi$2KPN`YڿVECΤLhkдRqg<ӆf$BւeLV? SL'yVg3{wX8VL6RR|RpzTx)P/s?/RT9 /3ljy`"4qb2lz6՜" o>ј>vąoQy@ RA?v'YKl>xRFܽ[ >p'lf S9J/:Yw}ZzhˮхmhR`AlP3KZidto?v+#QQ̏ANܪ8maǖ>C@,JXlid" vcy(l\[ awO706X dt9U;dPZ5]Рk2q;0 Ӣv\(Φ5<`>scZiiS{& y. xe N3amI0%,*rqׁ #lKXh䯡Œ\!-c`p[w@* (&.v 󹰎pY?H%j:뮣äj2%v(s2dXڀQL]TZ2^ 0E&=]ɺrǼSp쨒H0ўv:1$"%n \Lhs=Klq}/-$_I99#qv".:!(ыȲ)~JĬ jR>eHHZ OY WNEܚ.%ƼINYr'R zސ o{yF" ISŲ 2PPlCvC X\Hm=hr׀. %e-,7 lS@X5HAV |X߈;9X'`C]H>64Pa$Z{)#tzaF%<:ywkŗݯ_l,ZREh,EgoH!`CBļw(W3yI^:E[_R1=g,t:!u`%ֽi)Tɾ4htr?JQ"071LH*ߤ# fg)W*Wj#_n{\H*]RW(Ʈ!@ wJmGG R@|j8k^a,quKQn%e.a|םXrY+;~X6451(S& sֹ4kKguc֤<2|,A|gmr('?G]SYIoc۔lkǙhxBkn^l@w>ѩys$ŗ+߆-"g2?gnuUa tXmM*#NOXѱj(|rt?"iH3m /%c=U!)I _dBPH;1B֊X r*ℨvi<#bK:WQٌ-N + VT**,f 8E&i0cb^~1ezw栎E.?.uol9i4luerS(ݼK:uS.}8?'d  #=RAYb}EIk%U}% CfZ(Elļ!}rl?.Ԫ9DONm.B#27~Pfgs:h/y9ԖIxOmjL4pi&=( QsCa}]b!*r=?y'pgcb  PCwv{Xcpl+ m8&:hC:hrj+,b28z׎c?Ʃa~œ$CE;h-^]C}xLW҂,A1C20oC[' 8}GGq5ǽ%o;Cgp!*lRl{-޿,gJ]Ɇ)NXahTqtȬ~7E7tC_n'+sMDx{\>*,1}`"Ç Z(Max0 ǀɮ|mh*!]LL377$HHlRYS'y 5\Iylqf!Z#P .e yO3( V'BF*TG<E?y?܆07iHMNT*x4Yk'|ff~Kn~o§rlp߅/`![*051.k'=䣧7橤 oayv`垨}梨RVrx\ib/!v/~^(ZU&ZDUy(FQOYvzSly82E-=w :`B$%` . bJ^rk6X1;2ź钭^ g_[jhIFIvW3܃;6 OV{(-`rH.6gk y9/P@Q(mOQ6)3C%~xa-FܹHGv+W/򇦋?ҽe[>QB{dboŪ"4#$D_.nS0Rm6!'lD_Ce{rPjaxF!bE)- W+%ӼҚD=6gGcK P>ܰ$ᅦD7_j?.tk?n?e!TJ7|IӜ{401 `=f_IPVrǏ/UOhU!=zoNL)M]z66,AjNqa1`,4_&)/_{aѠH(Kݫ=ZA!/]XAs痺5 D ʵ|>(δW Iux%qGy[m@ p_Ri3ȵS H3a7\v #(:#@YH d^`JM]*oՕ٩1'x6P@sȭ?%B9 !(θ`a|߃%`#wr8#B5qp Nm<^(-\weuSnHpg2lu vm+hmvuZ܆;VZY!K_[ĚYTTmШn0J&'ilb^ eL & G`A``J'wn8ׯ7U{a 5b2 ,خ0QK?B P8nd(c`Ak _rPF]8#_@}}jDŽi[=D;6g6 ^=Y<~42"m` >Als;7r0 Sk yU>Ptg*\ڋK6 gX'߂{]nuLH'o|:4`T_(s43IR4Bjp#e_N\ݏ ^d }l܁ܪ-H.?E:3Dcs,t-G$w Jk6qö/f~5JXV6_: qOebss Q@ ů% e=% Z>()@O;+_e~Ϲș^JіGHM]CfЂ\AKp1R&|>n .4s1N~d3 qdgA׀|l߉gWltF}*/y0t/.y1jɾ.ɱeN9?瓢_gAB ;(H6.:646f|DR,dl[ IGO"oց9Q _I`2LП/~^!׭#Y-+_+%>JP,$>Zћ=]۽ ʹAB4 ~[EAT ĘhJRw dKM5>֊&g= x:hpGoxuWq^k?OiwN-E]“yx~:'y'zphGa 2Q\]4d&mPFIG[ M Wc2Qվ8+05;)@48Zm9⪙e5hF̋9Pp7=T ?0!s5㛆D vam&*B.ʵE!dWL^&+?Q7Igf0 0cZ$5Y]TYMyg!~,XK{.Re+nLw~wߑ=fڥGos#OTZ6,21PF4qX7~͇(Q:.S=" gx~N m )+ s~K-~3s ɺ< S~K]8hhT_lj/HHǟr(R2_ k6a8~aSq'.9& vM3^7P ɵ]`VWꎜSRuTTD`/8#޶a\y`,:ݲ'(v6N-P\+! b=p|+yï+g\^tf:<lB$JIv2{q'XYry5)fU$éeZ? ƃv?,~O'#CQ'xA++kʱ޸sDZ?X̤iLR#UPh(3ʛG#H+`>oũ, yRM+5VeqybT2E 'uuoXIQ 7 XxtjsY?!uc;5K8խ%Obu8u:6INSݸg @^"nGq1a '2u[Ylh ݌B/@jܑ %ץdg tS(JU'¹+I V$p3BqVݭ7,w`iUu' Bɝ~F2^Љ0~RH{en/^ܞ] ʠ:_m{" H 'ܑƮC$Ȣ '=9.U2e>_loc[_nNJ@gb0ȄF)Q݊JAV#9lCPjtQ]`rWtQSֱ-0s#ۮ?P]阓n#+*sva-ġڋWccs9ﵩD]ao@w)qχB?7p!0@.b?7^hu* d-du[d±nz"Q30q; Y@zD. )_l]@hK1 FD-q3\Pٽk)k5s+0)sAQŧ5,_XDZol1nݩԘ䙛i>%O@[(rd5 FshpcOlߨ6ۯSoॼ,`G)H}+z Y/m `bIwlI˨r_aR;Ѻ_qd[Lhj8&:J'4ob^3;)Ϛ~93/qPY2ORsӒ='ݫ\d &AM9:Afj! !!5m편)$_F6C{{Z WCKAďFS?CҊήZW[sSR }F_ڰ5dm ^7Ev-#1Zxa1d/,cʢY+}+)q񲟿3 6,f<ʲ:OBڔ!VeЀRN퓷~Z`# ~wI"Y| z8ˮz'q^d~2=3qCȾ&6(S0͚+m-,HSi: *XjM0RD'WKe&3{Yb\ɭNٺ3a]x'R+*͞k]n_/Y PTDZWP:5NPH$'Bi1Pz_%ju{>ȅcAf3)\ (*ҳOʸ%rS#]Wкg?7dgh4͡ ڔw ;AUzUL0.^=Whﳐ \r+ѻcX 1BGHq}>akLUpPFdB:0 oB4>L\6?eK:fǔ#`7ӏu鱺bLgKK|M*.llodsf>'̛T)+!!nnRc]Գ)CsqF|$g'ݪ>c9ƘqfW wy=Dz۸dLI$?CrNMV1v: t$ӣw|ntk{i+vdUv#΃TF\.QɛH 鍻뺁qifouJ mFxa*ZLw;@Ia7?/BEURӷC@#V}ӗv+wM5aq;vCij&?i0Je'%"&AQ0=OC%Auo—_,K(,`'!y38E)~,X+JovT[=Ogd@1^r{!3ZzBM[Iy 8_:XǾfNՉ@YّvSHQـaL+r9G5!WI ),`4֬Xu?ҒM9.A`93/7C'%?HRno?}_L_&ׯ{UwX;ӳDFJOZ# 1]`E>G9՟zU)zR2%ײx=BSYڸ|༵5xA~16T\--XIU-<(aۈe * %*a}*ksuut%zH6&!* 6}̓yden.u,S@*>U i8^۸ֻ0tP:%H_T҅}x~e.ŗ6Z({aSڗ9y|k#-bϭO%n`hKc*UGLy%B_vb W2fG 㭺.$d;+c,G?/`+fdsm7% ʧ)Eᆪz&n$eZkI9_nC7H.S*9$okVtrS$ gFP B`Wr:`ϗXIV^ֶ{)&P{ʿ1 *D]9>֩~DJ2ʺJDLk <`9Lt+1[լnYt U o11OX+A)P"Cqn q)M;Ύ 4nr.֓NBJe])=:B]6ԭ; )c3'~K\B(0 dgL|BeXc3C%n{vF{j\esCM#_55Ӧ%9=H̯:QCMk\˿/૔MCu-O4{y! MX=N'2d<33@Ó|ڕ *ٞ† jjo>3v5@FpO'eoQ ro`[>(u,0)ldJj D&J㩭c&M}jM&8X1t J#e]_Wi1fHmưoKIAs r V ?ד-8aL*!xֈ A$8~H'pߠN!"TD7|XvZj~4 RrY mf-(npQS` rPmDh8a;>8}qO֭)[+aK (~;\S..g5q躡ٹQ֓U:IrfCȄ >US ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8K*@$@8h5ps[:@H< A r aܭP4ii5c* pGLGk'?;|s/)9ssD#@5250&םGܒcd #"W'F~mbm46kBV51 h]B :R $+)Mu m#0bSc-7W]"hHXO‚vQXhЄL[K;.) <|{-nz({p׏klHz>IOTJB- E/~dnL`֬`۹zQf}80C&\Wq?BioD$滑n(?Q$@s]YyVT|"Mn^M}bwOQg0ёUp&:I&}=n : sZr;Ca @k nmp`f[p/H`@ 3"AQ *vCg?̄DU) 6l z,"$jӛ='ݣjwQ/"s46w`jqG5mwن}Wھ.%_wo|=/>XG~ ߿ΐeDw1 =Qs*4 5CqÖͲ]|T./@=l'}~)#Kl}k"|WtEJn%̵#~{ j}V,3`dϞ^hDNo(W{A?ޘcc^Cg]ц&]C2 <_ Qs,% k'C1*{S(rm> N Din0`yP@N=˶6@)V^]\%[i~=:j2,{ZzYeZ?2MªpbP72kI2W}iR kHf17K=fLtm:m;B=,)qe_[2آ~-:H>mWrOz8'ڬ<\`WRi (GfU.Qt9tɢq'(/y 7,Ĩ:tOVhpl'y»9<'C \=w qmRЇ<1BM!}1 ^!4 dDOSd bH+)UQwuGPM)Ar Owic'̍JռtSDWJ %+,}>XNCL# -qGjKXTKf CTxIǮO6jXŮ(~ktȭӒ6:cQN3z:v%Sx^`UFZzsѭ`60=+me7W$ `7"Ǖn3 j51I!Z|/_2A Dԛd y7_UKAqg53a}3HY;%׵*M=':PJU Y-׆:_ڐ<'Y³2?f?m(?B)>.l7S.LMp;`=~ٲ94t[L/SkZI:ax?"+bP*C6Np.$䕿σ7Z_^|I 7ۙbZNYt v& ?8B,PO. dE <ML؀ BLc=kKfh XO_0my#^j\ן$Qjtʒ*,imSJ|R&JQ exnԪerk;d_dNK|8"sΫiYtĨB%x/&UƦJ{ IqȶG@tFySjz‘4c.\ߟE<: $2ЈS5}Up$UֽH i=3u. 8b}SXVsvso=N1Zfnor2R>(1Ot>֥czr(ܡbk)R }CjmqJ/}܇&qTU@;Sʌ0p,<Òo"27Q-U?ZLEE:fEg *ĕ-z],ްj ˜@y&~ޜcHjDR֕s+3ŷ<۴52Hd|Ut(Ȧnw;ъ0i, [㻅nHxdڧ]nA8@ $'Zo\ ]YWrEm$CnXq/t[#/C!?q#zTMb2)bI00z)a"U]us(]Ldx jTPCW)T˔E&SM㭞3#|6 =`dP?7TKesyYh`E4 jl.mF"/8_.:0X|;. F;.=cqlB53lg8J19]CEqB{T!okUy⒦izU.6 Aρ祶%..dS3Ew.* zbqa%^d㓻9oGEՐQ3+ lkJFuDx<_rfYo>l a0[K}u(狓}K@~"}ۍ QU|urjIea[ wQac%~ArIʪǿ!t>JHx9ۀy8a3B_0g{MX8|'nr2XX;_il!YO0DSs4yW'CAXxjciqgJ72tyI&lg>o?8xx@+ {=#:\||@|` aJǽoգXN~jºstt 5z)|dsד~rw:"*A_ֲ;X5ٚ)I- Y `*_|;LB|wA7s-]lrwMBKr7_tv[EJ>XH*O C_K+-Lp8JVR]O~"*73H"YD =4h; ~D+8cRK 1t'۪_d $70/H;gʨXûT h;O {E_,w čh|,V ,N^1?e3"%Ok߂Z&Jd4[V <.I]?/ΰw F=TLFFo)Z7 т)?z*l @B 8ͮ;j.t_}7|58V6_ ( pM'|]'g`'p D N0xշQn>_>V5ohuxK'@ kxTv5%fwpe-ѲkTo+]4in![cШr2'1V:3uh :k%zk=dKJ ,OʎI M- cp_unQ0FY[2iP gbF3V84n#Hby]~F1t\22x1kwy>sVЀlUE:uW oT",Iȷ^N/P:Xj6tx[⾉R@GJɴKeoS_Nt:EKpP.gnDQ_!UZC 2yN`EV h?3 ?NVĆ6eʏ;Hpw[x?SMݎghOXt%8lK5˼_r*uKٺDҷPֺ`Q8_*p7nk(RN @mS ;]"-GR%[I⦃$ h7u92 rt֭flH? -/mV01_kے"^إnk*нn]b/jPIu.%e=ou'NuZFJSDvr_'&z?(2׻:oE dZkBP_Q"wCH* !ĮAuDT#k=l.)MA#D4Us y>NM۝5z!Q5@U}^TSrhTF٩0;t-۴Zp3͸~kR1+$s9xBz<ZXS'-[MJtc 3]o VU>j5Ma=8?T/]lɔd.t.+k[L#?@=cK6B.O]Sa(u*uϫ.}O?ZpH2_9cÈ\P"5oRR賯UPjGYx{Ұ&q1J $yDrfØ_%@=MzSzyhH|ĴW][-LbDn{CWAc| vak8 1Ps6e c #oP 3trj nT#1y޴ްAJ8N:BnlP~f:[*/cպ~t_eΧ( ŷߕwӣBe+|Lzb-Aw#㟱 `1d̽ )FqpCwDB eN)t0vRLGn%sy^D*}yb˲m8v0ppn%]I.C2iN_uo Sv' D)Dkg9*FsC_>SH-#Va%7Pfߤ[$x0ϷoJ]G ~7$ǒC1r]^9{ػQSDh>SpRެv#:~'Υn&=8?u13y=-y N;vǃ~@[: O.]~V<]`U/to`ȢQظ'W.)԰z[^,``-/D]wWZ`Pc|T}]KW?IμZc.)' ՋWevDF ;۲޽. ~5Z)^3%>5bh ,svlRwÚ{9 #$BK|VXeYw-(7YXt7b)]jnllU!^N'eĤݒD6#}9mW'v Y>8XTWNHa#>)nE`mv 3Y( +ק!ۜ d`*%L?Ņۦq87\ xc8UqBI|bDMy k$l&˻P553~=qyuPQR`͝iG5 GԆ )cVO LŠb([r\%i@قxhx~u<8xAϻxݚH&a9UWg>;į S5 ^6pbILU=Qi ;$ Wt5..I"vcHp& QWA5Vp0]s7Cny#<~J @`h4wZ֯Y'=6?46'͠ ް(N»U@{7 8żWʪ8D#Қ3ef,a6y&v~Ŏ9l==SmbWaVG oUXx%2Mhn*WqO,yݴ)ޯ!K.SF]e3cxcOG"q}r&`^;-nOP:Axo 4c3RHF|a6zzj"]>*[/>FBR/1Hs5\Vgz|)p8y5d:!i!M?AQ__"*JKE7("&vkxpMjo6]!p[݌YW FĊt2SS("AU c^QXvQ9d_cc?:9c=.A cLkΓ 2SVI1KN8:т0Hߙ{2=o tt) k0j>AA7ve}b:E-# uH1{66 QE Uvdslha.n943d9._?7o=b.7.m 5bPlfܩʎ|Wzsdns")p*`Ё6Z^WEw?Wxzg^" c;2o>i#N]ݽHe "0^zdL5ۋYf3dnKPQ3uUBb6TaW` O{g#M5vA䴎X^ЍmV<(K,fY*2r@?;lſH{tBP ;:ifdj*M Go>`4،:ym19\`,A1 c 0uhlR}jj`TIH)4Ů *PsX*##X 3'K䌱2?|V<${֚΃Tm){:3T^㓬M o{dնSI9E~/Ɲ7gÁ-3ȕ(pv~{kj^L}LrG$4iRi@ TdIP\HkpE,l,ׂ:sy\L>w4%d#MSʺO,37b`!0ɣk:Ro /&C{ɭrֈejbnϯ]a-U&Kݑw 7D -j{|pPD+S0.VtLwR@2y^h{^W#4B$,dRpY9it8=yJ<Z (tJ}_e5T',w`YhǍ:Oч/N̙dTU0~$\fɈKiJڕAV|pH`o$nPaTF$͋CCz 2tT2e50F59>r)7tM{Ɩnj9j}ڶѓduB]  -/+C(g܋0qҮiՕ.p0!7Gޔf0H"SMFŚ~Ck)? g;2CKٯ< j9 Lü*Zx[ejé#zmQ]ɰ# BՍJXAz Qu&5qݹ@%u %, p8}rKz,BI9m{flr/~tV4S^ş)Yd^h(jU @o y,2 #Ol{&.hI3U'-Pkr~Ƣc ؀j˵}IB(i}WDuN'lDsHTHY.\8$~wz78n]@ ҽqZ!ʀC{nȊL`b1--y"B2(vXmC|y] K暥e_McȥBڛĒ2Y~(#ʑGȱ{[^`iJ2T|DV=b$G*Y^Ӂn!(ADn%+B2|ޫ!9&DA42쬋O1es$ʡI ؘIC0]׈kQN6-XVfL:R'%B$|j^aQSa,8 z9Hz ,ªsS/46IspM4nOԀiI-=-) B Wjޛ܋VGOk~P`Nv: A2ĀLS%349__ >_x//9ۂ7Wg44Gb8}Ǐ~]CSVg)z*$ԛroF;L N pދD.z[0j$4;ۨBjM90Ңzއ8Mm8@WAjZ 7*-,sFim]!~W=.[ub/XfIESz)^D6~ ƜĄX[n.% 5mXCv8FĀZ JᎫX۸ 1+,ӻ%82|fݨ*Q?<}]]OByA1Ҏb*B)WQ.mܹqxNyX^O\D HrƈܫQnX/r8 S1fH =s39NeE:ltu('χi 0B(2db*]5?m`HK#;i{bP:3Ӱ٠K]UY8Jde}IZOa'f9!C_4:Wmtր 姉cf+WX}.:/AV\=jLQ$n*63/SഖH$LTQ񍸾=JٹrS{Z[\9:?,t۪m(N> _uC-VU&J #Uhrٌ!*ҜMqo,N $d?9S{nQIeLO),Mp֙SƺLJ9!`4uu 7ћP_˟88ḳmwN n x9UUWOul Ch_r ,̦m7t8C\C"ʼ Yաq09třq `߄N$\ &!8* ]N|;1d753Fka yf ,9"6+zqIT`wO|Mf&ضg7c})^&'~yb{j^5d5*>C d5`(T*ݐlIPf );Ǵ:͚}c<Иsy/42v0 QQ#Q2DWbK"2WgP@U]ٶu(< dȡU'Z39ao3<ėy|KI8iZo$p t8J] ͝Y'sQ?BDzߪeǗ,XD?` M/.;V<* quQ:(ozs$ Yjcfavۢ%W54b⤴UNx/8ӊ z{yt* »mĂaI,5!!;Z.CƟii/FM*ځhk bMb^kysbŕL>]cGPӘ0LK8ҵ->ݷO>Py1V Cm*$g!5~{~33yJH"Da.D@UH@R`wB'S :L5x`hu4!w 3`^!>'KNP?nZߛdsjaxuˮS=`w; z-k:PQ8J:gPl QEkg }g62Sܷl,]1*V%̈́Yv&g(b pfѹ b 79pԞ$`rژdodۥV^59coJ%2[Nc5cNXnt/,t0i;V[ʋV{1)5\Ê/ذ<-Rt%txvQC ?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4XF8w8x%9Ah{9^  b`!.QiI 2wy3XY惘%>>)%)*ݙNBt%gbL>^|ê|wE@RoM^>ͺlۖvI5rgKSxi74SvmBMѿ1lC43orm(w6~7b5/'aY LE&=Y_DmY2~hr[/dv;$+=mI×,)_>%zH{Gjvx+Pr$暏 9dzFB0!r05}#|IzF5%/wafSzmo?CCxjLKǾ4Aa'Hf+ZҖtQrT{H̸ԬkE|ڡ\At3bBaH11Hu6zؽ\%1#N5^j1ۧ /\P{eㄾF?_G(Q]MWdk6wN~Pb xW h=hxA/ uu?xY>d=а_GX -3 $9ܭo9WKr31MTKUxA򔞀NB$7cڝ&B?/2M/HW|5"dpԸ7;f|[0. K#dOJPfdzrV@3%k!*[QsOm<} u%g^,6|)עxΟ>? M/G$sf dz,& rVje域7|P{Ѩ.FqёN9_yj-e]^]`'ÞUE6Lg^MS׊Pn2x3L?",lPԉ݃-$yZ Q}ۏ@Ag\$Y1p.z!H^ (*CL.H _ttrwp58VW|>~TYCl9ne-{tj M']?8%'ĩ *y.IC}grg+sdU;2{! NIZŬe12=Hfu^q81Qj7jd㟥E`}>&DmV:Ƹ{ETI0%=M[v;KzŒT&;B/4VmMsbh*4>#Mg2Agv*pz*Røse4E,(zO+tWQ#{ڶSMc~+pNgu7~g2:U#.ݥH ^&zvD1vQ* cDNH5^wb~oM`\cXt~_cb;b[* 0 ׹&+_BGcќ#7 *8wJWT1,CgL^]ڧkUqmt:U( FhW1x$?$<릧黟HVF˄H`y5XlO[?ˈs=A)Sj(Xb6znʪ? jǪNVD )#%&v@1{AĊgDWIji116)4h%#ˏt[`31׸8dV$QiY:%Qz -z8,@ͺ lj_xʿ.=ytN؈BԺTBw#Mk{TAY ?[W;{S[G'(y9^Y.]H)VFD^p.FgO"{{Ss;dH9Rʇqg w9%T}\(PzJp-=&#u֜⎍M`߰2؟XM2S *̕fj+ƗFmF>@VTWG Hj Y~Kd 缶k +_NN|CD}4+P+νfyۄ4tA2]ԍi;%NZ6abѐU' u|."sMu3h#S'&eܻgXx+7` : 3}󥤭N!r$]mAi:ѧo 29PO~MEyIwn*g |o 'nݞݟ?r}fPbr!tZ2WT3KFl F k]>Qw6KE~!N@: Jy,'#X+a'6h4?1qNٸGQe-yEv6Kk[muJIhxd94*!ӏQ*cJ@`(H\# A{LMA:k#:yrN?-'(?~;{iG;:%F2>Z!"|R#C݋ѧ ێk陇/׹#NChꐍVv:y_܈aB#<Qk<&-;Iay0#S|Ύ98gm@ޡCa9# ݫޔH \XՍkoHH*ߏ__~bg Wai[-N8b;]p 6uֳu%ayD{Xy_pǥ΢<ư(iESLP\*ԖzbBb;8Wi+o[*'5ivc wPNR6IL@d f e)2RZ~4l=QJb1f俥D=hP`U  cJ]8-NR3ᙒ5,GׯO(D+I{xpa9lǵ͈԰ (ķWTrB@E\.&_A\<7z:R 0:Kco9Uu[d(p&k>[:GxG& 2*)t=@SIP9v(\Ol~ykF3cNiCNG>a;/vTFjs"eG`G2 T5:,EgpyUT*Rm)w 0 f nh#d} g3 %C>PJ%-LS/Mql9h2rY8nS^N[59rjS'rmC\oڤY[쐳&Zw$ܰ.M$s29C)X齉2(|lj׫}XJ֖@;ZhW_NP}rW`{xb17?}7/h<+5Z};*ޢBE6?c4[u&΀EmԧZ~ܰ `Y2C H#~3(k^Ugn҈/kW50!lWU5XSD4u W jL`بZ頍[3|$֝XӠopk@.nYk(Dd.51)׃]\Ogeേ, O(p]WDZvN4S0<־ÀN,5lvݕ}[ Thg~sm9W$}A5 :%!D+}$CQIUsLu1rZN~\}Cre/\+H }A _0SĿ"]x?ɘr+u*K @&R/Z!3<[Z;9g48/i-AuFi1SitŤ@*>cP;a@UJI][H-MÆ $ayoq_0bm5f>vj$# NgaTJ-``Oɷz̝]kӍZ[39^kY'7풛}EWP;.AuYG*)OGAH|1]WtnUXuy!O:,{օX>F3.#xe&mUVsVu 찢,e4~Uz3}eK:=QV1Rҷ{=4>RȱԖ,*"O5-k.љr*|PVBLy1b&}U-q휖UK)@ E' l.sY?G:Q'.X `@g90@j[|*ܜt6OL -!qթ:B-+,zrHxV"Ssn~==; ")Q΄уgT)W'a(sKYYxR M2]Ե"]:LGi%G`qۊ9Ѓ*Nz n|s%C܄78D&Cw+tw%4XU{Jkk]sr!5 Y7,-;c=yt&U{A/aܿ Y(ŪZKK-F%m{g3@*cK o4gݏ!G^5BS/,Nl?+Wu]YH̻r & ׻U)[ޚ<1 @pғbA.xoO/A`!z]|SSŎpgnk&B'}eQ6Ķ;ϥ7CK?C_#4~cu`pg= u8 [?0hb3ae"DEm+%ߖg>Z#bqڌ!_*_q  8/hUA*Ǫf( ;Z! '| ,2O|rQš-hkU#V13I9m/QHUX@#bRe+N=&)_՛j0s (1Dq^jQlkO?K!Ogek~ L2k/.NR2Vp9߅OJm&͒$(NWRdaOׅQ U9߈Q{U7"CrchIX6BMfeh?FlGys {#j\ʝr_(;QMeҀYAJgj֚d6L_/r׌}׃tl!u)iP}뷺wnD\B<9c'l:; Eʇ|@|@> H>[͸p4 @@] qN2B B$rQ3-dbZ ϥ}]o^' (KNEs_O fvq̧Tͮ^rqbVbxP>= `kBAß#c-,(]tW2ᚂ$Wq6%fN}M!VaF _DTU*q%€Yے?HA@p ڛeWrfyD?{e"#y-Nϸb_#}? ,{:܊/;6e-8b5}ID(6w&ԗs k6luw 9=`kZgnXyb]7ro9AXܱv㸷4e_#;pV%Qӻ^e.I4s-HfkR+=(-k ޔ|~ŚO"׭*jW*t.G;]i"i}Lo\N8ʈEMv`2Kl ٯڰPCEK0>&eS!cۀ4X'ܽ+=u2GF լ6t=6CuVJZf5Csrv][\^oz(խBVAO!!G^q:q2!h+(MMtY1dm]ZEr<6|hN|:,lQ"v;nI8 ӤWxNyv5nsJM%N kCj~%Q1 Qt7 ^=5T8noCy/b30`AZ+LZVtܞqNfǷ}CWņ] 6(!T ryTis շY6f=tzѵJKL:.~xa@#e ?~>*!yOk\[eGbEy$0ױ>°X `фSF_kf*`sx+@%TDλ6?_5I:\^4\C" 68?ߨ +|8i"Lk&ób'sj[{(D>.3W>g"\cg׼tcK>iZ!e%>\[xZ*i:=r \2Ryy#/j`lb4T޿tjcsݐ׻%nzmxHCg bRp#̅c lL' >mR,[x~t%,uN'WyzBb| cDgA"ȫ+w*FeO3j[NWIũD|>K|_>yc^NcO=p$.+]e~oC`v/i 腼`+?Ky=XN a JCJ'@xXL ͩ88eOi1obZe4q#VhZm JwcɞU=x;W{OŠ۽|s.XϽ!#pCQÒ.nd.o(!/T^˫ [jƋ5Yv43jiW.ۋq|ΠM݉9&CChզVpy:qR+C Q ~K%4ςs􇖙BHb/S|CL^N]k ۄv3; \CGX$ww1Mv-!!ͭPU5 >3ɡ]Y+-,\c pPޡB$uWUYt98;&vZpZm+pw᳚LrF ؿrQ*0zܡ6` "aa .Dޤ<:V=,"s!I` }G?Q"@s.'/-kT{J_Tgl0P!ԬF'yC?v8ƧJq"{C&0:wt' 9k*SX-TL)A;۠{<)ӿ:J:6>~=45%l>Kp t#iK#aq%SCM6Rs{l1*e/+KJQ#:ӝˇN )#cfpNq馭6!O tvKʰJ8: 4ͤ= O38*gx苀WUU% rg}tZȸY[XϵrG(m E[:V@2gHs_xρ])YΙS7EL8Z#< >gEy{8'oCmU a?H;TkѾBCu \iqJpejj6F$ֆ ;÷v_aig/&&T5uF˧?qq)^A%ϺIأ[?_z;f = .-BiH$414^L'\;#@BJ}U}op3@!d4MbՒ,V"e0±"ŗ(YxP{fU?$n2Ѳ]ub. %ᧀ_o+oc/gv3GPJ"[>%Yh?ӳ b+ތ ۆ.:a67+q^z܉ wy9zY\6nv3\>RD%Y;d12O,0Hk8뢺;J?Md$[akgnI5{-^R;SIA8Ǥnz|d݁n]PU=j )t *!Z[h?½%5*붒{{:``qoTR5$HvcIT?Y|0eh$5khQO6#zLά) [SI3.¨)PcIGN%ĝ.怛ܥ\}EhU<@0{R.Kn-eI2Ep0.q}=>˞>3R+w-6 p~ئRJ q̬ wx oyYȎӬXe|D?_TZgVAێl 5qYQ4-'^Jg?JvU~hiɲ,17vZ֔͝}/+虘(0F׭#$ꕟ+>C{?Lnm0rt,\dR]89SO>oE?y@L0gc2" rx?SW'nXC'B$aaw&|xA1ZlxDƗԈvg qeD_ <'#,9W/H=$qF Gز B)Ct;B{B/Āby+AnTVS4a&ٖ^EHB!}?弶Pp|і431}4 5?kfzu{f徛w"0u8p;}:acjb/!ϜS&x#~ {*zvJT6bJKnń+c K6\( ^:C*<d70LRȉa<Ҩh'Ъ֔Z~6!MmCQBDwF kЅ&7RB^m5ݺMFm- _viS(m MOkF=&g)!XE/{7QH`~$ 0ltڒ:ܪ7"M!*q0X&h ި0rGZ~jP };!K93:7;k"! INf1hxbÆƀ/ks_#knQ].P:)¥'W/_\w;fZ%b~Cn DeBLO8 ~ZGb_\~N`/_~.`S6k*{;(ę?^qR19 ^IqD-eH24!2xz#T=?Zg}azv9U27K} p1D_떫L\;,[?,cԖ#F[~cS DČdD&r9S M7xd'x?,ó&Rl.W&x~fYl*p6NYJԵyi )D𺲣R]ѶOud;ʯ`~#Ex^]8 dž42s4 9~fUXnb=+q( uDrz/p݆,)s7NЉְF)l\sx4a*_WE3F~N*rsבicvQIkC1}ŐS˛Oƒ *Kk#2C_؆KY\= T06z' 0<gߟt8qxր9߅4ҡrdͻy+I=UNwh߻++>Y ןtqU%85q]R5iS{`i8i % !b0%7>rl#)B2J at(2^G=D7BVڢl[tAoD\ x7ıFmXvLg>HvAćGb$"fm .mtЧ6`8 {pacgyqʢ[nH+'zJ?@?4M9\`ox-愶LРSADs<167|ulJ ON!{EJ,`y>.-zq~s%'s׽ 3#$pyYmF]KTX`fҷ7T{ˇ8q-vːGKyk bӟ(ن R.}$X0_#UsnB\zB9)iW71Nlk% p }@.E /VÑ8L*gJR׉ZM1|xsPv%9Z7;tzgh y:h\Ppdܑ[cF5N_TO?|=i>? Owcby}z^#jX Eez/ǭu5@g/W; oeފM'Ѥd{׵ާY*ԳVd A=jⅅ7ݰ4mse72ap1ztNПIv-PsEզ1`#UII>1:rXjLu)9;&e? hrX2\)aIA_驝RUKhx#M =P2:b=>?rO2w;/yE};/91- i.C^2#oP}UP6uwB01Qh:~w#"fuCd4WLv>jխhXV:ZE8 8Yd?%Y8coQ^4JڊGq$}W w*Оw7v>!>LLW8"񴘇U~tIRj_JrF|g9S !J&k p|t_j0o)|eXKs3 9dfsCQM)>g̸C?"dѕ'X|mxx5{V䗁5άHoiBx1K}oT,#0a1ytuB*|&_ۃ/6Z!(`mJ nj-',ՄyJh QɒZoݞTb2Z^z4yf$R${= \T}7j$ހfHM>HB;8TjqܸmE%BNŨ ^K~jУYۿ4HcSe{|yւ炃7RwB -9(w*.*U[9mLXIe<<|GwJV6bnwIũ8 ?X)(BsA]K0[h9TYum5ӑWIv(1"ghF^ K[p|Y|NM4bMLe_c3HÊiUG0\> Rl[4=~Owoׇgghjhmh0R.% HoGJ2; A=u"l(0Rͺ 01Xb:Bl_?˕#c]p ];N)|7IJG3*38U`IA F Gdc81*cqs {m7qm5k-V?6.,ʑQ}xGaAUN%J~[г;YŴgء7XK {@uqw}-|=ɜjhVIW(տJ"} 4;?]OKtqq @ŏp ónzZsȶhpBGcC8.Z},_Ww ?JuA8[ "D\<_drsR*K]&{ck CAH@F<\l\T 7T3%oӞCMwd$Ph("iOO{.*8d.n^4pk؝6)9Y5!Ɩi&F@7 A.bzWR"$2(x锱&ր!gxIS >2ԔC* D\D2Dʟ\&_Rؑ u ʖ$.P[u6  6~052j`tftBي SQ4g1[n^}sw=E5p>sMNkW +혠V!@]kۻ@I^^d؊:f6!7;fhj %~BD7eDO0 Pn'JaUhA7MSGK]&CV: gvFyo|l)CA?ÀѺW"V d?:U1nE&[33;tZ`8=PHgk6;HÎheYkFVޞ}bCx[&m]vR?ѵ@ZE`lLARί2b2.kvY@&\ƀ%{/#=jZzt: 6]s㼒 {#s co#  ~`|5|H x0zO:yKN}?H+]/郟z#F }>Fi5_:r"_ȊfKJ~w/,咪k8 ՝ <ڍ~ FiDZɘKwtg=7Jh&w $^Y}8LR Z@o8urC/γˊN)MކLyӮ;hgc菴GD$IvnE~pZƩ9M !\^S;zUjy)m@9FCp!p9a35 Ù|ߘ1IzRҥ)k{EDcia A~YCތcx @"&Rv8Yr₅x?|Mmj^ES<>928Լwy I 2/N&$EE$~e 6uyî@kcDW|3 I{t"r ^GJCo bTsNдKO.."Xы>#d[ҫ8 rb{>(o[?lp6 .|%TQOPj1UIVe) P"8qI\}Ob Bϣ-aѐbD.4 ]A/̲WuǴwtFZI*aZ ?B>F ~73d ;j^]X=s=em sN=|vV:"ЂK?~%3T]t0}ݍ]3&]D? |UM d.&'W|>͕8fV.=N]Euo1 ~bs﫱/󻬻JU޶!U z潏޺k@>#|+߱{O7O:z ^As=)"+fbY^~#{\ȃHV{R?44mݾ'F0%TD1?pၸYjqKbЕO;oh\NJ< snzMt~DîG\q,fcPNK|cQtOsaƨ'=&/;d%d5J@&7tV.jի@΍0ysʹ?\.ippO>(Jni}lR v顿*t {dxN|O:}阔37E6 ȺIom/[2Ts C&) HOnr>%wĤ*[~T+u*msr?_%v c?<r;R3cNXx~2~<=wqYqn HCB!1a$.v@~< j p ?;Q6U"F*[]t\Hm3 GyG_+ ݱIc3e”YoUEH*WX[^2ρv H+n1Sr XpTxYo7/blV䆡cqDnSt-j1wC90ԡ#TL9 6a}"ƢDmsM7K/trLٺ\sl[< &)aM59W4Vke%|3^)q\ғ"$lˆ kkLrw}.>B~vؠNQݠnS031\&T0J,>::FU6 X}mEs#n2T V>b(z/+.TL6…%b?~#0B݄ }uu:Jf[&}fcGkĠu㷉WT^m%:Âxdy$?`dqcOAru& tE‡K10Ђͅu3 R*"lMԩ>J[ sZb=ܸa盰iC`!ד|wkq'j1\ o4 il=k];ʦV΄NPUp bqJwc-Wn`E\b^ / 겔Kl tÌCԳCie-X163N38\s-d߹5e Hz3"mDInl΂; #wJ\{ങ[U^XO; 6mcX8ib1^eȆlCH2o@U+*VNv\rlH$^[ Kx1S >Rd佞I0$+o D(3|m c$6#㑲Ǵo@~Z@ƟO0\ KFR'׊n޻f4\Z +XN+WO9[BZUu^r]8c[sbXTͽ6(i4—O,tӱ;r%L؅Tt8T]L 뚿y$i _ ҖF`7Zk] xsgZ'slUR`B̿R2_6q]Vkl%x2b ]=s3ہS<Hv yzY,E?WK$32%sz] [ mQ@z;ϗSM),y}\rMWY66}&Ok9܅Qb%܂S984=iz y T}{Y {1o\mt*:oTYVBbE%D=}t"F0vj l>kVf)i2\D8iLI@5dOr8;~sڣGa?s ]EWqnUg$[${oo!gWmd>@hdNYWq(Gu׋Cgyqx^o}D7)u{O3PQ~OaV!u @´8~2p${ae'o$ lbY\<_rTFS!0lT"-+`$RrcgC)6&p ~ԖtHMD>4dSmDPn y :cm21Q*eliTWJh09"zB6ΎV(vRLEUNm$D#1@/+B?U:aG'% 'T;8 cDt9DEGD0# qNjLfȧ\R1تLrLd'ϐbɘ2`-nr?T]ʣtM2RHBL{S>2GM t,nOc 1~cNЛfR^pa}{4+Չ6%NNCq9%P`x_lp!h)AT]5XZ]ǼUn@ɾU(\9Ե9d̠eγ&Ҡ !IHv|e8 >FᒻddJm T_CωO,Hh1}78|azNllri/2c)nGĿ}٘Go:@p@P@ 젢`>T$k)yyVÃvB 1ɰPFK2꫘Iӯ$2{gj6):|.&;7aF_崘 MHhkfu,RvߧY)6+Uq&6s=@Nrq (#$ R1dFɮp3a lm}*@SyiY(Lp ~MeD2j/K\06<t4 k@#i&<<Wf2e=MC'}!m0 Z6G%a_ 5i5TD>}fV}\Bzic2,Ƕ#<(#l$I})a%|~E+.CR~.`jn4~6r(H?.?` ?a~(?ױ?;a 4>ʌ2Z݇8 ._Ĥ _ tߌ*ä"+uK) ©"r!O&T3w )wpH:_Ghe?~;4xXw r#j 9zv;qϻH)je3A} ,D1Gy Gjpzm<o [?45ť[O>-n04AW*U*p0˄9CFgJuJ|GƹS2T*3Jq%U/&ˈ coW-q[we+:xWtxEifRlo5J@fyR?)7gP\TdPR/DYݔ0 H >|y|=Qdwac.:?IEEAs/¯?3ѹp=l#hp͟.K5Ҝ _,?߂h_ 59 I &W[_Z]'qy[C'mjӬAMQQ[ol{ꤾ˟6>ɢpnG,̐fj-_"+FM`  DS,U,S;(jN~Y4TkΏSCMKxeR$~97v qLn 0݆L[) NJ))ޖTP16g s'¨W, [Ck \{llڤFhyn ؒlF-52~d LJvБ!1; <Q9ZD܎dGS"t7%:. PY]6d ,R{0MZ41а_zQsP=\(/g0rT@dZn/"00m3 qFw ϴՒ^M!pr4q:A6[sr Z o;_;B75 x{8I&ʊtԯ]<`Gwuk@3(5OQHȿj}BTìD"vL $ur=X^q Vf Kꄭ _#N5T煉j ڎ9:&ɂfua,pҍ\Uyn{kz)ӑ.7yJ#l-ZEٯ0.qDzoK[>Frp.6ԕR+5ԽpXzk8KmO7s/'{'vjR}ƿF?#9fH* ^T։-࢒1>U"Zɞ5Pͽ[; =_o=6^l:1M2n؁khbvc5"Vb@eC&79Am0-ܣ Ȏ}枥-;4%HgԖ%[0؉zb" H< $my2G-@&Wqt){z2kN6!V._u;g#q:'fOG%!bk}hJnۘn'[\^9ϑܳ2+%6%YO* -($qQEl=[}ozS(Měr=L.vozs}0 ]kc | 1_ uJbqgkre9tDJ$)ZZ)e;S=Dْ]?@a`6~q\K :(ⶔCzV.`o;h $,HQ-{]+R "@$6m۠ T TÔZW#/Ճ _v%edEAFuDl/RM A=*h&_@?UGItF-76MR?qBfL ӤdB+<=/JG8h-rgd&c!Q@w)R6d^Np}L#ie`E|'ف?=j̴`T?D`z=f:U͔`D.'n+8sΘ~i4k({BBDlK s!SsYJ3Hn5!WZ? z HSோO|7xwKlU @vj+Xѭ[+VU[9,71HX7e(%=*pwcf۱X]~Kg4߬DKw*lXOb<4^SC<{&:GQ+:t>?p9$&މax5-ٞU@+}‰ipP[s8 lZ;ٲ;PrPM36$3}R32s]k+=((sbAUwEm=>]Y_cpx=@rF,DSI8P(R߭x3ZJF:Di O_N/mLE}0k<'Y+,O1EA\xtqIu3M[~.B]t4'zSH>)Vz]=[C 6BLP2a=pw  RBY;/ʀ愞cL}JG 'ht{ד^l>ͱ g} WA^q!WpR^EL,̺8ǗGJM颐|:2[ڶUSXȄ$Y0PlHx,n'(N uQ#` l:KvF9q:}o]_JV1aUӴ({e?A}ZwUFqbl6˪!6ۛL,}|Ib[@UG@lr`J>-l 0bE4pWKŇ|tS W;T0G?2a0"uj;`IUqFuOe50é-gK%){Cnrf'h\O\,ilT%XD,=$;} Vr9 =Kڻ|r6:n:UW܂҂맥m#tA!{T/"s<5Rkesl,7q [hy[XM &TϋTv-!dWD)gD% TVشQ-A^*րxۍ60%.&xu-cF6T:tq2YsnjTMq8\I)>_v [䩷 qc[ӭ:jT *.B7w8!R& `N|jR'Xv 5ak:._rŇNvfn5OyEe0YbJl"#MvEJ8x7I[gS\)e9]01{}wUGrִ Fs2xǩ|E3ddHpU$J12ĺ`*c$ج-/nݼZ?ݹ'\B 4M .좲ȤzRxy% mV<(IH@!IT\6#ಹ1_)*)fAE k| G1,s9 ޱ >>k%0U V=;%jT޺BkN$Ϗ :H?!O#R-ծQATθ"@r׶B͑ dEK09e#MkS/U(GL h2#wˆs&O\e" hxoK̘s6Z=|dYYϓ<7o#Jރ3+PMBR VXWFVKW@YMXZHca~Y|+` 3`GV,(3dWsOLqTYxFγ>0"r֖Oi-3/?iw ƈ8t `2>Cx~6NsIrxkhڔ$`?ۮӥnxe/}UBjYL2,f-7s]\)u'ӺkpQH. JA Xw(C&9+?T/~0b7Imve,Y=YֽXt.UNUAJr8Fy3݈s.[!,~՗q. (&s`?f&61$%dQ`DGZʯF#`eL1F0wW)팹h1w~<\•uk.Q[GKHF9?#Ds &TzP! aN K_N "# 9vjqrsh@W=acE!7CO?_mV p-šˢÔ_Y0A)x0c'8iQZLۼ"ўoNI 6 @S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP12k]O:,@8uO%x0:*bxZz> )G A小=P:X{p|TA?Y¬P3rz,=/G|;ð@|w'ZqGMQr rl~g4T|#0<>d͗;BdDnh4; @BB԰j7Q xUAcN'v8d/7anǷ= Ag:`˩ya1xWיU>/2H&8򏰙 Zg녇yY K Ն;Z^^Q_^_A 6mǚgb/"w3x)NVC1pq-|Fv?%<ƶx3Bq쥃Lj2) ;] ~(aѲtN*fWrNƃ`f>_Vg~L͸| CA̡"i{(641'YZ2̕^y,i6Ei~d6T+p+Z2HOMpv&WHn7N7ճ+òl^~t*ŗ۴ژ O+zeZFp~CQGBD^l9?~S2 K ik6ݔF9|a7,L`^ؔOLɠa^")wWVzc?"к\SWjLa.`]*0 $N`նA$pda@O5l7M‹KRCBFCr ()U:no?u(c\ه|"OuBՓLLgvu^ ZD׹Vt&ф@:͂1۵CI$uPVx{G!=,Fh։De+tSXľo:9f<:)b$JqC|ѐ]T]na Zk ,(™k'?\*F[(j^aTmk+} \XD"}UGJك6RzF?g*"}P{}{r@jTDA=f =4fx%P/ AJ%LW|襳5}FSUr\9S*FtgOYM~\}N|ߓg~O|_Goz}~R+kc*iO} 7 쿉`Wuί:?\Ja:aDJO“L x X2ڜ"-O1[:=ZQ}L.|Ùf.O& ? CS/${]* nJc!%|RmXŇSU.vش2" ܆__ EK[ђI#L8Ca?[1;]iY#k7=L_y%^B_9lJY^ZB j{f@Y`6<+M-^U\YPD)7v,tp[q Kq+(|tmh0DY,xZ?bIyO0i;5̣f0X֑)JƸ!4ߑJ"gKZxTr1 b1\$PWgoD z _MBZA~꠺[U COD|yR.Zzf($O zdyp1Vp)=JGc1n)@^KJT^UqH>~EAB5~ EeAv!5 D:'mZ)^PL."2F.*NuLN!i WйM=%ML}r06AGKtTO ؾ>S5DW^HmԚQӴ\w2(dRaBS Dp}WպϨa+@|=ټ{J/6Ù]VyBlR4U{\hhQ] @Wtx^t:(6ht\gq}jHc1c=tgVe2^Mj2Bᒄ V Tt)2d1b{18*fZ q>k?0WuCD!ovۡvu1uܶ0E $h/K#IK[λޯ {AyDz4Btl_8w]ikR\ a=)^LI%5JfB30v)5H$e ]D+26F[|q鐼Fx?q$^F_ǣڔ)$Y!]〫|SNŧ;awGSp᩟[Ƥ)C @VsW1st tCϔ+G*‹sp=Qנr|HPh@p"By1;fǹhp`uv%z2`WkUkg}'d vɰ ׄl=[f"]Eo`1ReKmy8t(6u횼CڴzAxeO9:ԾH3PyR{!Ldrh(7Wы>ht(WS!Cp1mj1|PbrsT >Ipe^>ܼcVFh%>t\̛rUS-Ѱ=DPZYg.=OR oA쀴@ӀVh4|6}$0h"I7=Sca97>"#=ޱٍ4R|d `W%պrH9P" &6'*k#us HQJ/|J~ͺ)ѹbZ%źy )0Qt#{ݐBdPZ!XbSXW@ bkYUHƾ7D3_+h@nf>xC Ǟy!Vf0GH*H,{76X V>3p#ԐYslYsOȶ؜!wケ66\0fRȴtN σ]=qD=}\AGJ6WČR |)C|H3GJ tA>f1J(sD?Z*Ikvu"V.r ]&s>s92JxU&~̊t]c=aS9t9]WOfz|W-0zJt@ޓB[Kx}!}fc<^4]Nd!]<3 {暫M;„҉2x3i+K2A[!B hxBxxw[3J="Qg{)eLy(?8X,h!w_+{N !ieK||@|i.4o>gb8N!Okm9grO!PP|qYPRIʞ/ q8vV$7 \ݮOG6㷊|ab|lC|z#*D Sp 57r,`~rWj O^h~yf;W^]`CC G,<&ܳ D~|8#0Z(d!(ܷJ \8H` R:*[7:䎿Xxe>3 w4=1OBiD]'yɊͬw+7iS.{AnNIH I"! Y'd߸FAзc3RN>Iܭ*CtY+r<%t6 5"j> -QNFn<%mCUR|;鶎uXXk%]ƺ M 6J.}>տ7__C/B;pr7ϗn-KO^6}d QgX.Wd6(g5vnKtCW3=A1M9!qUǷpĀhgBsM}ꔅ]ɷ[G>'z댁l[7pBNy/5ª"YA_%(?%ugs&3 ,K=]!F-lBAf+HUs+B#P8&(b GO0¿7IIFJU]OlUtKB4  e퉞6VVB; >i\  KBvʭ!,_4%O?ȴ]n|fg2H2eԖ͚e)aٖ&؟i !,oAE QU$b!Ү|J6Py GoI9WVE\ΛRtz_{OޞI%F(:Y<ۯ\ѶP~d|ꖌJfAnw5P<3Ylv:[#jšeafQȣ.JQ2m0qY;5俀~~_X:29 Ow 8:q*s@?s]}~1e[aRB 5: "GEkQaΕ! fHW-[<9Ъ}T4x!U|KKMeR\7G|qF dkӻwAx"D-SRǬ(C:S[U1Y,5M$»AM̞xxk&zOT9苁J $@Bu~ hw1f в0)(0(yD 6L1>PW}cW_y^+ кFUk/U? l?T? IYzc,1f? |IUnxB5N y*"YSy_v˥*]HAۏBe1ɠ{|l N ee63>6D`GEF ֥B朝a;#x&4y/c_^vGl!<ͳaTk5 ?P+?tӯ; GMU]ѨQ)% 偛_i??QÇƨ]K? ,&04|"1qW<{0xXaH5N_- o?H<a Μ!s9>ͷT<Y^G<䧮jrc=;ԺexrŖdR+16l@H-g(GFzw-5ե >mB4Bs8zn*J:I?zWCc 0_S^Kn֕nt[aqz˔ψǻ9,';d*A8RO* NhcDDᣇ)ͨT4U|ԺX.30pX_~5PW`|:P/%yۨ_aji%_FP-Ƹ?܃=c9zKH*(QSs#6kʷ 㻄3*Yuˇ*/̼8evtE=8R|"U;^Ok>$'l=Ed,W:>EeJ x(=d{>? %q5oZHp=Gq6"t<Dz Hi!@雷+3YX&ft uCig (>҃ /.KJEVT-@bhr)Nu/ݵu[AU{DHXpNtHѨײt9/1 p@LJ]9^4t!P;_D~\hhEm&5z;Bm[b>a|V/ǓtvvG![}wa0Xd"wE>SFDcSm;CB@ *ϩe"yxM#ğgIa[~!&Uof K 4}ho<9 c.M4t6N94};uVv-ˊ0].w@q*2I+7dV,a~5Wwb}2%#XCoZ&glw@UrN\Xli`ס'];Z_T_nUPTwN0Z8mX(>IdgYs]7]^(&eOS-r@K4f[6`*}#rj!uLk1O5ܾx P1&60ֳF|pY`§/oE=O2{6-VhrmԱx@U㓏H3O;|||byXb-j?"߶o}k'|>4p;˂|3c >|l͜Z[&;Zޒ4lp&G`ʎ?%?6*9T_Y9uvs+nvN"5N{UyL3/O|64H ^H󂶞祄y(/R { j NIIJrN=[<7Aސ[o.<"aK-Vе%:b#ZiC"M34aFKFhNh29zpC)Oߦۺˬ2T٢sa\Xѝtbk%1$ }z\+Xr@aS&si1.>?b邜8'wן xk-U] /hH^;=L: Qsw+߆q{ݞ@{R]mc|xw@dU,ݺb%PȃAFF2 WFcUS>!(lpI5O.}J?mpHr$eٟXY"qg/Ƃt_'K! d{CN^hMX@cki7@$36"1 Kj˂ ź${K }s, b?/QejF>YȢ#zȔed^f#}0= ,KA֧4=ڤռ&)1?$~5̴˭}[kt>)]f "o np& ݻ0s(!anoET ʪG B֯ݺ8r\D,NȨ}}~f v,1z(*i%wxJL15W-J3aF Ozm#Zo- n@,e_yyU#gX,#ҋb8 P/* {2d`c|\5bJ`QI/ww52ES$Sف74},9T /_fu&O%IḇpwW4̹$.-C(N,Oe(O Ӆ~^6s*dHK]s|[#5$s^8_lKִF!ֆu:yO"WS^]'Ѱ H2777% p ǂ +> the >6t+ٜ $zTYcNCy3wvQ gbc?|]]8+4 ZY=IcM,0>K;Z w_ƶCDn^E \1Yq]YgQz} d63k8!k>{@{`aqYbL{)PԷSr+(dv-qAA<*aVS< &˅2uVU VYVɣ U_$F5O~ozN bf՚KB2޹Xr 'Y~,"SZG F.apuXVk6de> RZ1A_j#?j~^Yn%Ւq&!.lV~ `Hgz 簹t / 6~_rBS (βQ,#@FʒtRtp nws?8͆yKPX9D+gR1\a!StSnOeyD7ԣ~P2wRR RTنKvАTvO$*ۦ[&8w3 ]!©o{"(tIj Ϻh0I<-I?N`m\&4ߛ+얗XdeP$Ri.$3* ?_[:W=C` G Nd.oAtP}T0% {Oq1*$qJqa{<CeB<6ԅOr .#M8jրV 8x?vh/DLiGJL锁vJ?$=`- f'd#W[dk|;e.m Abu(3FtZ8]n3Ld'fWq}ݓTӣ dZ0_2,| +̽g;["°Cn|M12 3dgL=ӅT{k7r%z.>3Kgmn\G53`aRCv=BY-L .D&RF!> *zEۂ#e@44J_F`nȐfi1w)]@rTd 3Rpϑ:u7SE|\TVD3et5m€+JY3C R(gd ,,#0P ]V= #Y&gzA|b]ڝ =Ia%]vŅrU,6uȻ,s*=~na WDAM<WDe?JNїG JRgᩁ%HwK\-6(\e92>秡= Z';BGbw6}k#-Wwm*r&ytUgF*0z& ^2o\Ld4cg{Le,ݳZIƗC!F_L܁+{xq 5$;&Y=lYj,9J8f2rv2 NE^̌(ѽ1Cyva.TWy(Wݯ/+yZ\z/[NκlE7Ҙj;h-ô16PEOǺn8"C͢I5j]/҃fKGyl v£0S|!W6|0& q-ke֢ Ս] +j:;(C%:X7L |%(,WP-2D{zfvb` Rvoj >S44=rī^D?ܒ+:ILAQNx֐u7ܘ84ԾV {pUGxAG[V8gf| 9-L䜶O?̴^*&&+|`2 h.LHT 'nD8T$M@FD~YUxhPuw{`Iò11bP*=HGRxY5F}ܝ:h8 g{^D0}"] e(3͘F~^L.z8GJQ>LW&>`~|2Է*Tb!LoFEC?a] hyLh(SV&>²FCM\erTS1YLCL"Jt'$I%Ux(SB+U=f ~f&L&*u2U5VQ(MsҮrq$t㸥eUAWǨMCqo.r=rp"RVfvD(*]qt:%M g?uʇT s:7]DZi6ju*, IQ2$uF,N𻻰T!ޠ ub hth)t^ /åuR:kIsFf>-|(x[aKs>LT tnz^O%b`x,&tZ~R#A7JQʌS40бN8(L?o;z$"^d!g;-(+&ȸ ~]։]'96?X}7 J{).EWK' A%|xaEgUY&{[+$Wgr0yWn0\zw*tWj( wˁ,l=e$ l 6NCV~ˁfIUƱ+sXxNϸq]JBH.d7)&8uzcJQb7%5ӈ_ ykdn$q¸8 ?>g!쭃uyi 24#D9J0xKp\/9F{0e;dG".`tfK 1l%(uEa1Nĩм 4>I; L\@H4*yg$|Ҧer"hpB3:w8)c\Q:QIEhqv  'M=th}^.C%]d+15$ȉU|k lxG93KgveE*n><$~NmՇ#$\WN܆>܄- mdaJ"E 8"`o$\xy#rXw\%+H4Xxghk["TcPgNAnN|؎HPvFeZ] Ix1usԥ_/47'GTw#"ʈu!HF7̪|:|w-76#~o[7^dRl5!w9{l;}ᣡ5`w !=/"W?2; 2{E1 eMeWTr׽LYKr,lA}$UvQR JepպNV{^nk5%5S.dR`cf(_6Ӗ.G+ K:7>(MVX S2 2~b~l {cCZFHJ Y@%HǾ*obxr2.6sX|~-ITʼn TGg.M/_p[~>`' |~:wA[@@/!9`FڣTsm4h:F{|m>bs%[T@ $:D6c bH95 LQMÊsp e:U|(:{X2瘚7+Yo:9;\{ݗR+U4=[]6pU6:IWe^Q&~BҰ=qBv"- Q32&D(FIp\WІLOn*\ꈠAa ?/7V2 j-t,6.4}dJN\s!y7e9 Dpj$XB~Pm s\ Ek;w9n !iiŶNP3`NcԀQ:o%qQ@Wf 8CuˀT0k/ K#-ЄtFS7;Vԓ}F `7D15{zOD0 }@8Bbq!&'ϵHd3ߢ/ge ~`@gBձR1V9^JJx,;32 H |lL1Jz6)a2XO tau_ Xs\^ g 4٬ԫ У (08UEi%uz陾$Χt1ţq2M5O*sڻBOcF:o sC dB'taT%<ў-m]˦KYTz1󲂿Ue .5 ݷ~;ɖ"RЯ*jm(D!c.QMz.YT/xhES,"瑮U8k py-ckai뇪? 4z xah%5 Yt!gK! C +| zH+l*+}?qE(~䒲gHSV̬z5 BY {e:UJ6g+H⊦tߔINSGzjq\UA26y]neoKwE$[ /,-4^JNn+ӧ*5hR?d ؙUZmx^`"Ly# iKBEAzZ #pX S3եHJnقϢNDvaTQ5~ S< QFm0{PhUDڻ)/RoGa7t}k>g̍-օB#T1N}gwtd.f{\WS%vZ$ut=/ ]xDgLhvak" y,{8{ SbD*5ڢVSS]@j$a_wq|>g~M>8~oֿ _\$? ?!{ oBy>2VR˻ V!`%Cĥ!z [ܐ?N]wEe~6$|1}0{:]GU/HK&d+oHhiD-D@OaFu˖zP %iA$F(kF)#' " "5?ʡE),"s͢u-ʫ{ CeZJs4J:8jppMѽ($9@Wa;d亴,5-`5>uT!=\#R?Ա, oҮ ë [w,8"yb[t}|Z18ϵmKK椔+/>//Dܴ`^R8`J7FYCsBECmSEٯͷ2㍁^$렱=)š/&ͽ(IHsɥk4TO9}CQ#hx10 _SX &s1d!f\ 3*O*9J3&B$uA&%kx+9d1^+hz[ȮL\k@ 1CrZ6Bvwnƈ!d_2l+DXeeiI \ꚡ9TGcpBBD-n\iTL( T ݝZq@>^módtyS\޳BdqakiB R(A<8CK9 B_J%H1sc\A Q7J5,`ȟW{1 E/N-A{N},~g"~ZЄ=`[$@{υW-GX仓ĎTJ5_Trbĝ$stx6 QBKһѱaw⅐dү cZVZ^=ӌYݥO w+g(K{H0w֝5 uFvm=ѶN ~!ؓ S`GL}6~o%|}#Lug(JBoa11&UTnFk۠Q G>~U' b#SrW 5ʞHŗk]wAA\UѥwU2Kb'T'2)"oeCZǬ2Q5}r0:s0ԯ$=}z]u]u14b/6m;Hj<'homW@͋VpۀaRt ^tzw84cުNgGD\av&T[e TNRef ?>_N yN u T81~$X۩#E}?wA1oE;qxa=|8Wxmд2(fqmK%!+? A)*qH5˵,2DZzMC=UaBB P jaTR+4]Mj݈!9`"*q+$ 2k𙆫CUz`$3 :u^`dӸ!xy6(J؊w/TIr,$pu( l#]aJԘfO( wjņȟۥ֪\ Sԏ:q.s `%YD=W9Mgr^82t@I5Ŋ*G4 6)reqV-ÜfCʯX8_un0&1N&ڛȳN}Gc)R,s: \]`y﯊iSoɰ`;gsCyHYx0UIE[O:u~80Z-p9=BUhs{ q b!\%@E*?Cr ǵPdZTɴ* IbٹBJ>??kRL=g$wBly[= *,s%$,}9$c :Ě:PVJ6BF?nOрYxD&M2h`Wkb)6-o:BP tݩKnG/( Vۤ.LOվ"2)2BgV>?<>.ooX/ P4%`4 =J /txܠqR='EOL&i X%!nEvh\~,¥^p3uAOm3Eaz.CiX˗_'EG6cۧbWo$!/K`ohWl]fg3)Vvbk뿑I$mPˀ!Gۊ lojкRə(9t(Cx%NLKadyE5A/~胕)4d laI7R9S&yME'o`si.sYlӐEpMFT!s[{RLKRk^d"Bsta}S?_ҜJIQ)M!E6a#%RO<$1D{'D3p:Rrɣ$,ܑx^Rgd@ 6/;kܼfv̌qY6,񙺱p֒?I _˨5[^,K’\7`d6p_F[~aUj5~B JδH{olEřArծ5\zCL5]ϲRUf5*K4n𐙴`q1QiϊH_hdܔ QA[*Jr҄)(p!b3$W1Q[tWRas?N[l7 ғG0#a׌zAz:A=?hȚ•W[ު[KmNi$@+;l-nQ([-}4LBd ew% :E1(Sv VLfY' w5ǝ4d4 ֕1zw"mڠX+1t<69q]f]{ܧ?I.aͺm6t.hєa3*m nonM[X#У v.=D?;|8PUY6#ʿ,J"? j5m@@2y:=6ɂrA"hL ,gGԿ"?|cKׇ 'F\4?&_Z+T)CqR\RP%ٰ0ݰK?] (|E|zvMEW0qHOcL_ ?WN~лGF5Z"*sۍź?K7C/ĹHjDփ}N{[t u̡TpDIf`2p$.lQL ߇..eޚ?m (H9͋!3wAѐhnXZEX58VDB0CF;P*D%iq]ޕVZ˫3 WkYk!lER4H\eKvMmh'aD {~h= +P]h.3*RC# KC\:S ^ipoJȹ΅u"k*!Lx^ S6::r25|cu[0dh!_:"Hg*-CASwɒt1ݧpO'_Qo.*GUHMTe(X"&5s}/[cKwks#OJY]X+o5#W2_E6x{e? A8ڝ 4rKkX*T~'١G$6x6c'( W+nJTsA~p|ex:,3%FB{57~3p2.q|mOř/U&ʿhPTE7}<$6pwK8w,TAjWaay3/}=2'w5 ErFj&kU%,]11W^IT`!^W睌tk{^ B]7]'-y>#C:wXnLƶ/ך,VNpto"H\w r;! C'j^? d, ؃9lj ->aCl4GtRg1w3YW̸b`4&ʵƈ~|0^UAd4g(=?<I>Rș1"!RڐV ?һO=uBqDǬ&}V6W?u:A5jC +]Z@ܙHWf_Jc62[fx -Dq[ {gZ̄ YO1'?qw;C~Py\B\BIK0)I roaFX,u>hjisxN؅~UfgʵkhB5+~ kҤR0Ǒu)# ,5h"EgRn~8xεc,`Qv | -?H3V JdGisdEc%QXcB8^f).bo#9[3cSk+>xW jNJ1SM}~ 4&U `7x!,K9@ы~Oh̵Iǥ g7nHPl!Lx+c6eQbY7fiL.췟Y*D7/DT3p\~:s{Ij6o̬qm,V'=3Su))gZ6|赡050{K1ǟAw*I!!v7> #CoTtFX>v-8ʔ}6:PIIrȰDrX"8Ù!Bd'94+%#ɴTr73"cl^ ` vlt y'.JkjX7tsD<q%.Q4f}s;*޳F<7ЪS\8RuevO3w:-ŋLX}KE짶e{]kM_c|ҜTs(T֞U` %W[V)|B0iQq(,/> | s-5 d gG. /s6?)6#?O"H4UhI\ɠж]Ehą{Bb6O2ɷY´p3sB2GKx`XϿlBgxp.glDIp m,x&l}3qܾ+V){r]M.EUTYVw 6Y x=ѧm@O9ЕH'l{!Z Epi!8&j`kUb-}4CdZ!O!Kgؘ6\ if@){?Tuӧ 9Ϲ(l(=#ו%iLHM41ӂV]cgy "ANY`?Sńɂh 8!MF}!h!GVZӶBmc~g |/4fZ)+BO'7#Z{/̨}?Ou@c܌kRJ2̙Oy׽nYB uR/k1{C&|*NAӊkC%52F_Ԛ|h)n]k$r>wT˷~veC4y^TGkdlY|R+ KMGdXFMyv/& DwUWE?\xa+2~&¥0v?B# )|pS@ܪUC s]?-p)0Μ 99F*[I5{3Ec@,k}ulE#z< uw%{+>ls"<SKԧnj?։f.3qF^[X UÕ: n-V 's"(7Ty4VhH9>w<-Z7~`٪\aaK$Pp8,^Ӗ^$]!M6o{"EI`d ^0v_=0_z8 ſ|E?ڠwh|0>4)Pd:n7z&@!,bJ1ƛ|^dx)k](#OFDpʚip(LqfKc*D/L33.P>=#pZPPK.SkV<s*o nB2J.W܎*iV8'&&=Hs8.=aw@ =JsN.L  %1%,g z95O <0}H*5Elը7.+XX+L]Z;B!'`sBX<>)4CƐ8Y%y~;uFH1GH!;)q`JWVsסY`?Rcߋ|QjHyiv{Ob:}c7ly&n2Hg3N`uZǴh1u.x ۋQwb8."Lj.a*)Q}:X9 ؊c#$"t43I5Fmɏ" J 0Rj^GFkM*V0&u$+BӼ6+ =5U$G$6^-&A_ ,: @s>ݣ]GIXWxZGq6>'E?L0?,\zj"rhL%×' ":}}}s3!3YvB^:P\7[]6 ls'5H=4kqVxG G,LDkU!a;!`GXv\Qw8(!?4^=%{H~epإ\x9>:ˋ !ߖ\ 1 )`zV(pt=lg͋be$g%|qw:\ @F' P wD6u/`Ɏ#]Lda!bghX&H:Mi7).DAspuF9UT=d1ۡ, 4 t)Ba:ZjO ʄp #g:@o.CP)CZT ;hU}}e5%PZ#&1VXAzB2}&65-+ #+ᒙ/E^һ,:$ "!!k_4wƥG{ sT>TR?+MS`M}\k('o9K^=oEAEyo} ;b4揽wr@Nsdm#T[ LRB$P~T&gvOvz9"|V- u #[￙% }Ϭ2npHK^BnRT,0LDiԙ9 8A8*['>ez,h^xO.ln\~KE !~Ҁ$kxa-SVnbѶGm8}Ĉ$O!EY8cI/UAoɘu>l}7ȭg&4%(aPF'R&D&+B>Au4j0[SסPPR! 5\/4`'2Ya>wIu-d (- 2 EJ<J/dOq.m.EFƇh.7cmЛBEk b?va CB_-65tޓE.X'{o^Ǥ/T1sr;e] haz&Y-FUc4o:?~=7@v-5-ba4O()'{rC/eQY#eRԓҜdu\9)VL'FTm&ҵROI(PJ_doʚ {!@x @kۿ)R 34?} [],i$P :RnP4:;=4rZas.۳ мQ! e4\M>\'H(v;ƿ%'{_!!q2ʌ;ݷT-8۔@Ɨ{` 10'j m86ʑyh3gQU T+3h4_K}a`JǤ^O%F ̒d~~bI -xi1_l0o[1VYo xbX k 1s#锻>n~~ ~m[_Jsդ@"ʎ  痩~R1U7% {hͥ4`tيKvuEo+hjWfOx9hGL@dq7Ƞ(*vrPBUL MG㲸)D3@%VD0Jh 2?GbAD?y+fQ-UE`9At d^a㟮?^yz V%^jȕ_liqjQR5 ^d]yi[ZҦ=`H(VMa@PamceɞY3?Q#D6 ?YM˗wp[<퓸)GUosxZvoC͈e@^DmL7Ey ظport,+z8}(pe'F2$[Asq6᳷_B+ ؈,m#jC8Ay< +)7F++d`̙ss%qB.}+"{'nQ\Gp'c٥^CZ[Z^#)](N8H_%l(`]4A-@3*>Y 3zļ໲lZRQLUlG㯿~0߿Ԗ"Zޑ/:En8)FF`Q psu,Y1xxT=Lz!nU˸?!Sy 8)rp@k)0D:[n:ڰ)G`jŧ!xzU dQ<J\τV[օRIGsiGOLO9xXUbE\LŽ`(N7J#ԌM9 HӾVΖA e1VG)k_ڵ$Td'\P8B )Š=f} ԌP K#~wm݊eHHh=ޢJL3Vvƽ7&8 GzcK3H ;@ CQݙAWe)5T|MuDNDw0$R jo-nJ\j!:<%?݂50$P;+)B(.^Ф=OB㶗o)n- #)^Dj[ J#tحDžS|6 ^η O<׸Zct|?Jp$N@YxkazFϤP2Ա4 r_C@勔 3ߺu(*؜iBP@fm|3O"û`7JaF5ST!%q3G LF^>F= '5Rc[vVqE_\]-l-N6bhx`)_+蛵7WfP3P5c\JU18$5].J, w'`t޺&2h!dǑz"/2ɮzWKim=O)}y/h^ͽ `JSNl"10޳Š:8bZ/s1* ߝ~iD%~NGp)_>/V`e3 Ƴ XT' B=dݚ#e;m4H1JA@ 6K *(8SD$. $,%Uc䅌279Gult5VΟPq.ّDf_>`?1ޟݛ`ҥP?L[dޟM'MwsVqe2X2xQW{<>qEWP7w= ˊQp,`_ea dG\å]}j{Db)BG%@+ͤ8̴]6hgQEe 9ŤTjo`@INA;9?RBfѯߐ Vȧ H;~EߎiK]؁.xx]UnWЧeW5ympYxXC,˕w*ĆV0"rE-Ax ׻+؊ /K9m SD.:5|S'gyV(;b# MM]CnT;J&BܲGq :E3e2غū!2%& P_ G ƃ3|?@qU"rOW8)L؃|Rm<[j(]K]ؚf '1_.gEY`\ȸ Wa]IeoF V7iL[T8 ~Qը837"?\#V D2zl'ѽ<j\SUL!)B{?oBsSV4@;mo̶Kc!\!!oo|h+@On35یyr TBeAHl}"*|Hc)63KaRTzG3mcIk&1ȴ {aY]M %3]]:txjgnd#aկ=Y[U,9DA{˽ Q2sHuy[AfjTڋ;4oU^?kp,aGCޭ skN/JX ^M8rJT;yj~&s'tdk0/mhh؊4:oΖTd=]p`]Nz|Ͳ[:Fjp'q!q1`-G:7PAIULez?}wf >b_2ok' 1nIwSrU)Bĝ9ƙrX#NoezcֿsMM^MjEoİ:2dJA, zEFׁQ.ԛ x$ԎY ̠.RD4Qo؁ )(YBJ6c?Bb)oU}qf*^ca!pA^!h1TI 9ʹdҽ,EvR9|ߕȘiv1 Z()J.߮#$TS*KW5#xӋg (e^`hҙ`T6gFDj PZ6q6]iYp4'Vcx0'1勵FմO%A'rO^h@DJvMr[Աs;%HqJD<6o*:L3|o#ÎWv=ےhu`+Et%F(a[frI@wyỢ/[ƪj5+rqL<& m$ W`!'6DP9WT̢f\ (O{.ئFUrՒVyUz"B⑤892Qp N/6;&1oqihߍş-yqL9ʹtHI-u$X ɧ>w$9OV|cTƻfKəHi#\p#_+)JY B$ se,Qc/uCs,-69o֚U|Bs gJ);s 7N/p5Mڬ{w4Rr6zx*JI" >~][[{0+ )E  PisX>j(G Pvm*60/ 6s )J-.U""XYV9m3Ynau6aMHo&Ոm @nh BƜt Wm2;#E8`0F"CWsې>`DR!"hsby )/<#̤^7Q.^ڍFT(T)d?GP]5O}R MHk [܁.vlV5g J/xU/V1029I vDה;Jؿm.a%@ j4'T]VѸv)ѡ%<)QH|@ }7v4r_ﹷF.=G82#,bI 9b l,e%yS%h-1-r}ȀvB+ѩ!S"?uBީ cQJCJ}oVz{:_,5w"jnNDm5 *JLZj߽PEKQl 2&I⣒B2 1!bשrvlSȤ^}+]Jt%G4ӳ߅ #'্,w\/c̳F"`q"J {"8JdD?,xrdtL@`?@˗|* ; Tr1Qk~S+PT^U>ˈ$]"FJ3hMK]>6|E#Pne we(0=E]//eJDk/ňӰΝ(cġ'EП?6.ef `#zh[&o" NGDZʦϞTD, l,}puukifwf@#ܚÍ t2L^_:GscnYTPlAFEXrY9vGk$O±be@|2? k?fDffITkyh(nR/"LBcᧆbm)UV>X'I[J  dD[:#ei(D;-Eˀ7Ϧ/tUf-O~Žlmׂ'UNcE҆@'GKH&qF#kh,b\P en}h}dZ, t&a ҥLiE4=OK=zsF nF: *B82n矏/224ye'r0Hn^T?C2ͭ+ڐ#7պ8WBX"(. ;7/%cMU\M0j*Nf n9a+r>dsC s s_-@;t24|8‰PrRpDA}Cͻꥆ'fX$C*c"TEgo=aQi$dX3>#C2mM$4 c:An=[mq=]7t!!/ͭASSc ,6) *&5K yV+HRnUc `81&>X U[%4q L3.K;{Mk}IžWoڄWY]1ωC;B8AxSʏ%~ z5cF`h]_/32B3%hqA 6Z;Ì*hda~`׳Exېҩ~!:\F뢝=1)^قFtLkA/PHpF< 3s/^W繯g {~sfn4 %Wr^Z>gZ(*YK+}q!FɆ C?G]xݫүWlEtƗFI tA !"Ӈ|>4pf V"WH]bG3D{LD?k _S'UiR IިYD^D1&ǂ YTvApdϳw\*ZRäү0>=-/qdW9/XK: _ǀOace,V1Xajw)4!Bͺ-#)l4kK/'L]F 7^Ncw:˿A<nP$1ؼG٘uғ~11S=X@w`u>y0 UP!.Ed.}Zgj0$2O_XPjCjWaďLqP~BDui<)Ibx,|%3~SUR= U?Cg Nd,DҹbtA' ^.d[oѕ(GKcjjB;{~QR_ (g3Xqa]8)o:WOLeo hmo_>l9Xv 9U9h?Ymkj XXS*76+iG95HQsS[Wdfr 3őx TO07RsK/_A{ Cb{҃/-_Ϙ7pS7/WȨ.eGx6|%AI-cJ?> 8!}+π1i!S]DR'CkdTbI{xK.L$+dt(ʇ3Ap+!` ޏ]rZ% 5]@ԯg#4:L9'2@0S5ti5ꂏR`%? gX";@LxI Ƚo+-m)"EҺ'Ga} A<Y xOԅ: 0: *JÀӆi}bHC-$a)ϸ~<ocC#5EI},)TI*>C P^K?VAQ^W?aX{u[kCjx\"'z篼c$`u}K: e-jӤI22c=յ4.spN7;;<4C >~NX;_P 7nb/}B6$ÈԓHӔ)s;kS{QJ KGg,}Ҿc.&w&~]'~?l~Nq1qH iZ2_qw,[6Rō\T8)?huDbR/:|$ ޥW7`i /]"SFq.Oiҕ},+4l l/ݤ}VDsm(ALwgH, j,7bk! l3=H?NZ^ʥs]qnfaܶ>euT|*Z UxT\Ͻ[ 5fQMo~=uIQ)k,B#mt"~76$†3oLAR!{ N{>W g,!$N)'nN2*l t'xsZ1n{88cj5!LI2K07+de^茚q(A*IFo1YceĠPRrW B5wyӸsY0·1ʱz6f,ԶC x@b%g5A 6vBIDFSoXxOq *#  j8- 쨴a3̌f1 +2^=9Sim_D q+w99 ?4c:f5F=!EO?PhԁuH)5Qb"ͩ;*.ptMH#Z -.֓zDJ2|U JؿrW% hz`u:`g6oXHP}Zg;`m%CZfd1Tt㲻:q8RlPv/:r1jվyd5p 7jex`kCՙ=wlIgM H)!BEѪgtWz䕽l2ޖ%cXqaZJ>Y,a{(z) d_QXw4reYA>q(@{l&QyR#TgaE,?M/A"5k//g.@eVNOVG0+}_2Cwn@, u@ $Kg(RyMC2fr1+{M HaX I+ ?0TnhuFyj:2JA7$gx"у@YܧsNmT-95~(a(Y[Z{٩H( ݁"U"l^n0ޡ3Z/z{]ItX%@I9)dx7$4Fc6vjag,"whI| {!*ŪOȐDXEC#clqGDU,!mFT>rl!6Vn|6Ş216:_xqJ-5%J$f@ jC1#d'e eGE@;[ ݜ5 WUO9,R~q#`CV"h?]BRx,-q'Zon^0:rtdtǍH,*nf^^>{VWQN9~({I99[/}t޳ TaF Ĭtx`$oWL ƊT壪~sڽAү7eNk#q*dE@_MFZ +;5o;#lM$NtPmNth7* 7*(޺P%ؗ/NdմD)2 8NXŭxs߳ɀ WF KȢ?Q8ZP/0Y]#N:k*)[(MbZk Вc+/"-[y@6|@|@|bb6S#yȗ4%c||j@Rr9Ŧ[lΥ.TD,|k>XK3S;? Ť ~y됐 YT>=/߀\PD q{Q?ʜ}$ 97@Gs5G*;[8K-7aŹKT&R{>{[R+^饬TՏPr2#ظۃ||e1JŒ`3?. /2 WPVjnmcg-hk3R,Gd-"MLAof%E yS%EDx{.K \cs9H30="kOiIQNn/3] W02$K=t $ĉDA4gk~U̻ ll>\`0L#)&?lw7,R/t@CHIa_7rtHNW6D$<*Pg ԹI~^TFiUI8bwdo}R΃i t\ר@h";{ߖs fGJo=?{xѽ.+˿O 2C1Ҙtv^ sɓ1(ԝTSCnq]b1_qteb/A*//5ŕE[׽ZYWvO1 =3P}[YD_# aC*t%,ѡe}f:)6+5t|fHI ɓA{&)y!if]Gb<S,a(JZvzy5 ;K`:M˖2xiNZ)w ن50py.K_X^ ڴ$ԘR#xC?yPf✝JDO*6.v\_=cA,7k/^DǙV ᭱-CONvAf.CS_f(yR@_;Hmk\HFс\ 'r!iܹ- ScNQIR+|)σôRrp˩=_w`C5Reh^Ν\ ۠Cd3sG$L%۩E߹46*WmcI?uZqUK6A-vʫ@(IM)/rJ !P1tIکvË6^~O8W}e 2)O~}'D˥v=-L8%#%ؚ&WYϬ f3AaB: 0LaT-.kOzh o2/ }L@U&h%%?VoNJcpQ(<{.,<{xʃ\(ˎ!D!tC_G$JL~ 1ڠ+o6Qw/7V\ ~ aӄJfTG- 됚]DbIy<!DX Qفx~FmF`LU}[prTZp0uޭ70l^vb%BCŁoc3aF[Uuf"[ſS=ey;jH3!T%ox"zl KkYW# +lbUR|vp5ODfj"Y1 Wet7>9= Bsڳ> i4`Pgbvqz=j kT{Gj\v8\B~ǼA⏾_~Jӝ=zf|7 qI@ҳ /mJo[p\Uٛ2 ?r?\& eYeK<+lՐ~" u%]a5zܠO?X3@9d;&'JkyWis~B-"GFi9Y[ⵠ~Olab% ^~68fr+lBeA-ɺto,?jD}&Q !cd[ToF?QX`&?uS9ttl""hct6:YeIKp,0%ܭ=ԇ?wZr-87']>gN{bʺA44eY CspU߮|eWC*a){\05oZv'I l[Rhief,&&KUQ#E6Y)O+$/nRLѻ'^']?u_8feJ?y_q8{S645k{%,wע+)8D`Di`UU1*4{eaD|Ibo 0`" L:$D5bNI7(g9fBu P36Sx3?S۵`'H$ hجZ }18/󱫾b'g#d; +tyS"w+t} L>^CzThC# iطOLN6zU1dn ;vPAA) %: 2F ]-l>,τpԜL?{;X3KnAge,΢BX9p6_a>Hd.a:r r߸!'D+T=񑠾%A{(]b22#Lk!f-ÆzCq;S38O _lRo|ى_gEm~•ۋ ˮD jBsgM;UbFZZ9(<#e0Ə!XoiKJS3|? Vn'}'2n_*E"`Ð0,x%p촄fBp+)9愋 P$T(WO,̗o:¨\.+9]I~U1Nr~)RJ. C[ӷ@xaUh  F`zi0)KF*bVA5)EůVF)סPZi+ dˆ-f Jϰ*ۭ8x>_ez'f{Wh(Tݤe%@64n* *?ULI]#_˜T0H SaaQf'O3.'`ġa{E=EWs[7V`É!*‡%i}Z %W6]ґ*cP725>, P\DìEoyJPXYs rW~,=aGapSCW)&D8 TJ5.hv's-v-uc=g.ϐP=rѴpC:4@- ͮ pA#7 BjG8eO" ,3.@O  (Ҵ3d+_A+|;_x}dۊ -S1kb8eo RL\h^$|x&&[ Ȧb2`RË~gxTTZmM-B&55{L䔈G[GyBI ϰD=߆uYTn$`͌>qFz}36z8VmP: :YjOy͕Ő0AU(i}8AR }רyLqׂLOq!F ]iu]DyH)@bijlxܝL5v&oOPQ.n S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP 88X(/sO?8 +ޔ91jM/ߡݏ?? 8v(@ c2-94bLZ('&*^M͎YtL$Щk^ <:ogd*1F%5:~"_~]*C>%/bځIOfeL7"u=B-yrڇ?2®yN8OGFv|:g1[_3ņבuvxZT;߅vR@4O15TM@Edb]y `Zg ]|Π1B5kta{|t]cxQr ᶊyx'd\Tzi jGn`TuoX =TX+? {X?S2 =?wH>pv1~fq}Xuf?`eʜ+#܃w7DhSS/ `HqPij:qRgkp~a]S$j} ?c&YˤOO=Ѹܤz#}nGVK?:[G1/cX }| Mj)SɆZdl9jUTPydqY\Ebi_9jSv2N뻾@&}+S%vVо1 8ʄsɄ[Gop{aBh>UT% MSgN(!2.E,q f)ESnX's 4)UW~A'9SnuؿӐ)g=1s=<-Eҫ8*D F_RIp-jw:,k#uUӻ 2mDʹ͍)KA=W qRV"O!v*|;Q^$FFxw7O3dYPAn4!C[|9ŭ]\![hGz`(VFE˃q.R]1 }Sl? NA0~1[sllm3핱a3[  EEnNbnҜL{Q;I<'bHAֹ pvPIS>%xS{c-0˦8y7n9Bj~[FC5-B QIrz\ShbI'Ad)XHzBTW ai"\~.P0TC2]S])&p;ǎ}kTKm@>ybHewKv) z'3[ɴƯ/4rI'q[pZ$f}僃`#{"#khj´3sDAҶ.vu+|nDkS_:\[H +o-wVՁrUu8ɬSpJzKMVHt*W$778KV.:OT$ hjj恈xڲ#0SJ"Wbe "M0G|YbOt@XJ0ȎivUQێF }8yU$`qgC=Y`&ƍ{woÃ8e88d/&5l-W\gL 8C0 EнC6ED05ğM@; >UGhDuHKƛ͔E=8[[ OPS[ q6Q)!! zItى<*O1$ֽez99A VInhq܏c߉7!Ӹi%8ĸ6CR.&wfEe_";.i}04ў|880xGVL||@|doI {Ľ7%Eإ /x Lk?~2#`?ƌ?"盄[H"xǙ=8-Z 7STwcSX9+n~9ɢ;V-|8*",/wd:h{`j:CNX!ĵ?IQ yigğ?@ WGwז;2D$WD7\пK7C  "C<"P6w :/6pK{}.|6r#Hɀր~*?#P[M *8b'MEvTBW>|23i=ss7IM#m]ddMO>#sS K; ?Kio!lm+qǬcey|*sDTF0x2|@WLJx&K~a(j&p XX&Yz$E\#Ku_ɹڌHSjYIF \_,s[!&8+ƥw:#GsqOC=#}'@/陓j>شbHdz#k;l j_  ?Yq:+]KSqjo##8\&aa*@Z`RKGK(%1^ߝlfh>Iq)a">4pk.& >`J U >o!,@ֺ"I7^s\3ϥgY$'tX ?4фݞY}h#So8/,{G𑳟"%MsUp: ~C($㐙/W.i^m^hV/Z}/U9VY%JܲHDEf>K`LwmD&/|eJo\HmZzYJd6W}S?˚ ،Sx: mcM4&LJG3eq.Y HqMVޣnjDZmϤٳo > 0&]xgɏ$*en"Ï aËR0].ٲsrJs^~q'Ge "(Ȧ;Х&; &P.\6|V<ң5lEf*0vw:ZB<7-L#Ku`!SfSĆ.p:`Q3֜h& eu/(q˂E7~xHB Fҧز"NJ>=ͅL>NꧯD QpY f?L1g/82uĥH. _ip^G 1lɕ~|2-(i˳ 7 wʎ*MU%Y%Plu+<5.: AZ88Y5Tfmˁ,x DZ"O,{QR f|Q 0ўhll7a dsyRyO||>@4$t'|@@|dnuާ=,hJM$ưPǸD:V+Nr4Ā'__+`?Ƙ sSӜzG}3X!_X 4)rx(JXW!3 2!e0#O87rp7o,6?Es&e ki8֜lp&.1hUHApBa:^flx>pDT #  Jnfǹ+yrD=N tK  to.߇Y 7 (z#M |e9đF_F(.:6%u8(8'`cqbyKe=Y $D]KwںMɜh\dw\F1[&7/jQ?h5(]􏝤ÐΑ5%:USF1UظX2lΜFwCNz|0u& s@[%h_C -;mVF ݖܜшVss{ZȟKjunN0CNtCnv_`;-mm`xKrqb EQ Oc]?}F0S?ZWOw+z=" mjkިܿ}H]ά*kT3Rc'VCi V=Omq\]p{j4: {ImԄ ;6z+ ?d2B19Q [cLci;UvC/Q:#Pd؁qP[Zb8^4Mnѓ2 ^5mS^:G,קJܭ1I SG9fSfdJUw?E,E+J4*&W\]i 5ždۜ؏qFu5.EUMd>WUXvS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP8ݤyh~:4 t?("9:`t$U~]j'ėE!7ݛ+!@$XRba#*7p/䅔~(}|7@S샥ır9ĺxzM{du}m˓L 9q!茁+dS>+v;[[#IN$d-D_Pz?_ƼeFO|>ILMjy>mad pa]1̕@z80^AԂضN&TqЦHy_ZZn#e4Ч_ Ky GP5R؂$:Qe}d{ je&yEu84u6pPSfx#Vv, K>8f9?my_ @8kY07F+-ԟH^2H*.(Wy?Fl cfY I%:)_38][rN5V<**(/\Ş}r,Im7p{%Rq셤x17*noޠnRzl0oM>MwMEiɌnh6b8 C:!n1Sap쿼Ŀ7PeTB aF#>WX_߁K/vON<)"81 +}Z->:ZKq(c^R>TYzyM;0wQgeY>B.-Yd7D -W_g-ys *,R>B! d4iǜU+UQwӼ5 ڛ`LxR$HV'w21.R=iP2eESItZAGa =K9j+ޔ|icCÖσ/VOi/qa 3ԕiKU.,9Rv0IUA_yGmx(AuD2lP1&ug{' 7гuUОP"56 Oh4$o]x,Ks TvYkbԋ6+FFa _=tǾm}=rc2e0㼡 GitLEVcA7'zu'\ـ;KDuWI]\g?DB9auNVt ~ ϫïONT'h废ؒ-8h2d5TՊ^UY}e+:agy).WAV(/3BD&җ?#Cӭ7o]e x"H9xLczK_^\z騩npZTcE-ՐɑzصpcIxԥ=<{ 5K{|Hz oqQ5Vh̍ƽK:v)|z$ku#i '^݉?~03= p(XxLϠt[ޢm{FAY[o8{~Vٙo-z1(Q:!"ۑɴo,]س!bS+a)j !0k/\ w{B^~j)`sN ͂w ;}XC9NXP\BXn5Yd`ߛ8Vl/!nb#Hᛚ0E_&ܽmDǾ3M)d:|yN&c=wAj1lZQdTE3E㼧D?Goq/Eq(N# ׄ8wLӉu @wZy9ne|KL˹aMև@忡w硞S'i*J.B_zų&e| |%~L.MtpV-$Q{7Dدd)x]73b$ x׼* %R'8 ,2 _Nm,`GG?#j}doHF9W:_vv4& 0aܫ&s4Q_ZB9y+[w*}RXTeW66ճD  8 2!%()}rx,Q %,uJQ$}-m&]XAOVAո:xVtGL-]P\Ss+SŻNǩYcsEٿ$EʀFSJ&G' -cPH53G.~|.,+עɖ $SX"`snڋZmdX Jw)~t  xB2/5jE+nՎT3FoP3\ɣg5 ;b=|i"/6ovGlO*Ywemxajn5n'4[-q c/K U^%fblaV|:}j,(!s!H9 s2qůvP$?H6S#Nl AK ?70%ґ7%0T IDhn)S4|J/NiQ,N-t`E Ny~^PpG'{08nC?WvUDH¦9%-bԛU]ժ)}?t42#rL $'[lem V|%pA)%20P;bOdt- %Qrn#>ZEgNiIH]/e f$ 0We֨j̎P ]&kvZb?b[ⅈ!Pq/eO*P<ȵZh:9Xn (mYY+hEL:6ufd 6,@1N.8TCoAF#lCE"(;T8"ٞ̓7\*,L) v>mEq0ʚ0[M(q{;XX\LA0)\U0=&;oqH wՕ#E/?8`œ߁B Q%;A$ƼZ$}˵)iԡ5UԬZm)gIykyFg&,8j)r~s!tL|5TfrUėyWi(i ޓPQ&n8pcyҫd{h"Po p˖;es!{'H<4qk9[GN-[ jJM*Ǣ~X?V1x@R_XG5(Jxd!ՍtAr)5j_]͋YEP-~a#Z_^P{9@)u^0.QżJ_x:ϩQ+} OB֮ >z7g˵S]+H^z[1q\p>@.MNȹvl@^ϧ=E\܏pD`pskYP`Zk_>@wmN6/1(?F҇с\w[ kӷBͰٲP&I(,@F8bSO"ddi!K`rRsS$rfK\?Il^+FMQPϬu/В0S(=͗lVmnC,0m!1-"هyuPg4f+aO0"0H5~sb&PyC*Ku1GA6S z)xoXpI`;]jbv,~EK댾bRxSF)]! ].&F]mGBZ2[:X{đ´Uftgs#04B "ͨmw꫱Ѻ?2 ^^ZH[Ċ c2#J;mT>gO@=X$eK s&T\>M9R:y<az<3DU쒕?SM3{/R)%dNDָ쪌=.Mc"QJZ%uL? jRK}©7nĄB~+u'wNO> !Il#[{c{Բ!+.U-M'}V&O/HX0VLzlF7-Zjv,}MQ9i~FV$d5װt\icR~fxF`ٓRogr9Of;‡V m_z1DOk$֠Y&;͐DEkV)Vs:XMLB6Ж\WJɉy2GlEwEwt!?>ݯz&tc=9<4gsdt~.(暌kO!G ix?Ssk'&޴Y|@|>@"L4r?#|@|h-CW8y.FJ&1KnQU4E5~}RLY8o˭%Xˏm%)MV\À`|LFH<@}sv'vLw]TױѼ 3!ze=Q%,{^TPǸf?l5 S!䫙7YtpA<@ /5rRx69kvkFȲya:jEn{ܯ іJ7=#U]pz[z?RQtی Qk{ލ X j𻇿idsGwA2{v Ӆe@ﮝv'#5,Ȅ+sf@+-ǻSwN@1>fgt Wa'^҈Ŝ0'"R۪*Q# uNvSR;d/- N?&ռ$퇕m#@P&[&\?yY9U@M3Bآ;scϥ8jhL:XbYK3ɱ藣* Rf>1GQ"_.~OAAizrCGqQ]<,ikC~3*Anwqjfi2)ؗ_2sj)W׏ g[+Te ARaINŲj!JCʋ#ۦ+[Q(UgmfY+S7jpc5:~Ggw%ZE}[ H``ZߚmQml@W䀵&D7/L" =77g@a9^s?.Կ}~a8<="E/" n?N^xp˼09k1B|r%R"Ų#ߠd`!'y/Mڪ ! yRbޏ_vщʍNt[mRT, 6-6 vnz oB9HUG۪;v(Vj&*C(7]UI[zc,z1,> oң4uV. z2xGTlݣ`_͈!X{cn}qjhLgz;0S_ok}nV.X˗Z mAcS71G)ԣ;j)9;Eo:aG07ښx}-C)W"_w;)z{`v yOSk -CQOo.Z %ThEQ@m5Yefet"PU}rq;B75ZJG U[4+˧"7KH`OUC!;G>dzVҼKk`9^`k>0a{]uPP/e1au7-&v~>@8dV('mDP'N7DqLjK$l#߆#f "(H 0 X5iB]窃qw ,& Xk^]lTŹ poWJʷ Z̾y3K_SgGv,*,wexW1s7ܭHAh"a˱LJFPHց7$[pbstA< ͆DOYRZ`5mDvfB==t ˄my$)B:=a)(exiHN> * w#p)sTek .΋V+*Eu p'c<@bWz% F(:Ω;VLްMzG2qVc %!kƻ(애 tzG:]*4 " ZZ%؇Xv +F3xҙ,,EXj{=[ t-Ra u4Fu"E]wm ҔV#)p<&'2FiqBt&KCuL +N7#:d"A;9F0A VkVBV{32+Jcb jQ/ePpԵDvA8*z~GILhwK" WqVm'Ӕvˮn0֖අ5un|C ).cl C1 Hji/}u2ѐn"y)qG}"lL O({gLs>N}~ tk =6L%RII78Gau u:Qcg6ZАs>{Fdr*O#oEK}2#1̠?;] z=rG*Z-ô=JߡTQ"zԏf8Io\QͰ}ZRmp3n98J9;h9×2{Qvz4*\LJoav"spRgKBSk, kh!Ȳ OZ2MZTjYD;^H )-Yg{^,=ީbƙ#=rx0(Ez\x^ O+hK0k @c i cGȘ ҋ۷5@iV5W!JOAmNndз~$FlA6Gz,q{ȳ2>pC͜~DRQ@q%&-zј#`oRx&w𬾌3F +b]^!Emd Wdԇ9 3SO1wqfNMVĘ LSZ$1 Wy`I$-*9̤9De5ЧГ\]QދJr㳱>ወq-N0xj ;q/+M+Q'52?A;N]pQ4锢f#heh) QIQL?R:)iH@?{5pI||@|bKLGP.]jϿ@|h@`2M{L&Fz  ]_f7 Dyqp; YjLy͒j_|W3j9vJ5KS}pƦ/c>=tg̺o#v](j*zǜ$>ILq¨~ +(lrՇg[/!杴ObaBe7ɥ$ k:bdzL4Lq&z)1:3{6}}B1J]dquZyuG=ɆHSj$B-d>:H.."6C)Ov==.Wz$y neg9橪]_@KN+NZVb?ɏ:>nBqpwb[sa=A1D"z؀+YHo# $xYS Wkt$)U+N׬8I4Q us ثn1@ԇ`?pQd4mX|>@w}a==c^{VyW6~^vXdD0_C,@cIW_EJ*kꖆn4x6WUR}q]&'Z&0Uw$elC+`pb|d"|cEyY7(,)aRM1<Ϣ/t O=59sJ^9n Q*Xl!WzC5" Iז@S֠wB}#?pbH):1@R | @!m躔wl,mh@Mj=W'_:l͐ʻa( i"%[*X 2}BT~i(PE m!IZ7sAW(::!" ʥ(Yj \ظNd5'bE@yn5F~*|w=VIbSh(;8_Y l4o jxH19Y?G QR\5pN} f⍜Ls⑟2糡Uxgk?U["2< QQZ7?Tku_2[ʀa0O $`ڡ|wj,sZMՏyd^]cV$|X8BCM8}{:+Q&xǺz¯3^Sf&KG..qe|48ר zq|Qe}mfڽRcEբMwN|j.O}9[/AJkjtEXhӇ?u9k1A$4(Ze+hɢKT}fDTbц8> Ut1cS=@}nJ-] E仃 \EP8ZC9au[r;gkq]Dh8ƟAG{j؆ʝ1kj^xzůb2]݅.e}_:Q Xh[<ۣMM3Av\.l~ FS҃b"Si_뼥?O$g$i]UO{1%(>ɚMoOHJ)7`,/2 W!cT6YB5j@zNai3?z(a5}IGeGjÛ$bjrd+O(0vrc{ũUqq"]ZXvbw1l{ogY+XD06BwXχn{ԯ^Q)v "(qs=:+$Kb[sp: &Qt(؈x!ƨ6'<.s[+yy=#[PJY]:#A5djPR0OMGN ~,'t!(2-Q|s/QAơ~\#4qzheYyt+ϵm%k d ;ˈmWeEv';<_ǝ.4[,jq`[ m᪑o S$"逆OhP,i~zm 8J6h\Tozs9H\e [!L"]\ʱgMCdrbTޱCۦJqrL yK!^N__ze8Tҷ';lBa*]-@)C苍a q}oY5 nAE&BX9/k{[QGPtD `hKo4`ǀ;υ4,֌yzO̊rpib_KwdŃ+\,dlü3&k-=" 0OsCQbce cJӽi(ZY-(4v#5Ġ(R5<wohdoaI@nќB@/Ҹ*I2͑;٦Mڠ}# ŕlE'J{p>?do 0:纼D)gjUrR3q2i(wg27Wo7We;~ @w@tjwKva=N7I 7z+?JN񯣇4bMxP/ɎͰMſzH_6@_DIO>;9#Cx_h)˂tw-Ϫ,>15LR sB179ohψ[`G Lhv';*UV8.z@r']XTљIHTC8^ ENs-VW~ ;L1s7@Z4L[ ;E`W3jYA!iN,jb.P[OʢJ/W_F V{b^`L;Ӽ5I|L,xH8*s2:cیYusڷ$Lϗ}p1>:iiXJzT'< a3M)֧8m8,/+z`ofY3ƃ4wUq:LAmUK#12| 7;T!`هz}mc E=/E:!~xo~nCc%n`mqz5 ?q>Űl ѷD1`^My$FSknCM' _jtX˒@GֿV$g+$jDfʗd 7l&5&H=>܏Oh٘e( nM!X]vpCQC1Wf]4C'㖺-˂sbW1x 4092<֥U (u.E~cdnO۾5w"Hq,`|y4=dֈ[[%p 2h{## T*]xat' &~Y"j9IW[{a */rֳ0[{x)/&I,nw\)o:UQ JFɏ{mۅ\l/=-VBjQS<;C3LRp 2ܲwPJ>D72B=@L(jEH8ۊO+fJZ"YNµu|T:gf([ESʊ +̭\Ee wNG> ۴DD<]2{0hjucљzɾinզy҇ʤSeLn:ړ!%Djg, c" ٠G~nV*Ocз*gF :9!і Lmj æ^>ZW#J:LɶznorDj%oK'9+.PjÚn`7`X$9t}%$.|3)otRZTytT;V?h Ynd>[dL_xݐ Y;X97GszQH0 FÔ؀l SE2|6](lN'$z^a(kx$ Msw1u C6B`Q^3w2+­W0"4%P<^D;c19hBy c}!(IZIъq:k@n$2h&Ӥ^ܢv =/S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0QF9dH:4р" OJpʐ:@>)0KCIem'N͎k3#vս e·r=g ~_|:@> Ѝ +Ol9ڞc8CJnXi%@!ƋT^0W-ݑ '%4GFY;!!Kj$spĮmVt- M_ai)TD}ݬAb$V^rCW%lHvJ_ +0OvM><]R8 nmZ”vmG^$=i(LESpCu' u>5mPȹB?5M!UdX:J"@Y]:LWbv N7|>@E-b#[w4Ccd삐1zBL052Q"_—BMB_tSͲ8bl&[p ۥ=տH:Ֆ>dV==(g2@rx¾@e ת9僲v<Ӥ=)5\ V-Pb^Y_ӈW)Fw p ]tkWe._6sb6:\41 Gh-z/UL1g:AZұ:3-p\ic Yvi*獲 wvnؓsPi𠬿 ڭ=N_ /}M*9G.\hu؜l2䨥|ik!؊6֞DHf囄Us9T;'Һ꾉e1P>\f_N1(@ݶ {߾T|i^OKzS9qv:Z]TеT JFxMW'F$`stN;컦zcm'Pފi E>^t!,?E! i!@MkY'd=M`!ҼG)oY3 R^W $/}!iGGE? K8i P3꾢[Q 26_|M*'3F|EOgq'|1%өTxnUK 'n*(wL$(^z8Q$*Y3\Bx JeQ֣u~? YWؿ C;e3E; /,Tp(42Mݐ:<FtH[m=>e]h>izGi۝em?N tKs}:0?%}B :o3Oc{ ښ7 g|n?uSAJؙ~tYqؿMFS`% EN}Q(!f_1.!X'ekTrWm 'H,W?9=iۛYYW8&0xapokؖ6Sx%PK)}~A ˡԟڢh] _Η^Sj/0>Eh^z?PN BHY`v$8jʳqmytR]U;NmИv `cXsLlaO,jd,]U ҢlLqY ?5 ,[/FOQgҲ0:tL1P"+[>[p> W=nJ@QV3,咻K@ hFh ׭1ӶD}6hpԵůE&j.˯pu>Q(q+\l]p Oe}pW0T΀7,(jjmYƹߐw}-_x73+&hȠ7DpMZ ~&*hKd:C+ Ȋwq$6RGc*) 7tJ'˱|fTF4r>qpn8\ $R -05F۷yJ;.z4nƝg5q8('JO^ A08Mn\D/"7e e! Jz}дD45 gJpU2pڏ;vn 'rUUm{Ut|Hf)Ett~'x4WEU&w1 [dl>ܤ/` MdʫDZa?9}3Kx!9#{R#ڂ. J䉇G6('3gN%B4gb/bcQtgI93fݘuP?:OҜصgv(\"b>$OYg7R;ZG2Ͻ>w52e\&zuFh,+8 *rDwRː_4 IƱ-!{nGSʋxfQ*Q1<z݂GK~`a G9LqkOX͸7y7't Ť"X`([? rLzXk"xoH`Tˇ֜-6jw*pNasyH^Cb̢$7>'2$E> }) ~NIy&P~"$ u}yd<$ ej:&,f0ŝ"S}9TDzq#t2]ߤ-wkq?ƧZ@:ӎ#Gq*!J!qjWV[qW͛bh& ltFj ̔Y&+=cCmW癧|l JGfi[Fh,,\+99qpP`gᐭ aцzJ 2S0 ϴPB}?49f8Y'; ?ӈVf5tf`!0Lsu"Қ&\:g3N'?T0b_bRVUd0- Թ&)x mF$\l*B@YxQeQSDM .kn%Z1G>QtmLYiIU줹2Bui4P3$z mg=r:gχSt7O34{;aQ h#=>}╾M3x>ElMI4o%`rAڴó8L'x_xX&m U0KV6kIgX$i;uQl!۰&-fhGoN[ܺ&'>,Y6`YG&&eLз|r KA`iGU7{ILz)|@|b i/W4Ul@|h]סMV̭JTPj6<˲غMwTx(NVՓQk&uIfR$GpGp2 }9GF-0|6㾀a(0c^6`_#гEa~\t^2\(=ES!™>u`~KH&ˎ]7Và$E(4lۙ QApq+ `. HŠ͸nE)[w4/m%L?Tn{(plk976d1QCw{japfhK- mhaWy%Ə5#t Vm@c\)ZVt|>;}n95p 9z7x#-)߀>ӳlږ>H q0}RDV/'y '=6hľߘ3tzJy@?UAskiU1Xg|r#5K.cҫ_!me~믇/"uxC hlgUf}u1Q,f˯We;v\(X5MȕwIr$";Ϗu9$]'k{hLap^>6'k$dzvoE鱴ر±Gg7RW6_5޵) @3\ j+d!=nqIi\ֈYz,ܱ{;=j' 1=Q!Sib}k##q䆻? {'[Ŀsvx.Z͏dΓ値3(a=B?ڤM]N=Qs u8vD185P5@r-o'֧$h7)N4fO"Bԉiߠ5Ȫ?)*_ݭ S"E¶-YIfZȍTq. VM:1 NDtQ/LnHvu1[԰x Kĉlא2YgXŬ!dfCjl3V a+~pk }InB˕ǖ]X] S\E{\j<7in3 t~ZH)ɳ9`C[$E"_ژcUz"vȶeG'o} \ǺnQka-dןF-ރb c~{B-VY2n +[ʖB,GQ(TYAFO]kl粵mJ>c:nc+PBYa =]BU?T 0CT=*߫ }[nҨ>q#Coӌ1cxCAtZ9 kun _@#Jq\ ?0}:+^glVdi?3JnUq/( ;Ǝ0GlD=U1Aj;mIi>6%wc¼؊tXRo ^{&^ưQU~~uci4;U+O=Z_M B#[n|RmlX{Ti#GQ4#~&9y2~@WkH^amݍz 'ySݛ;4/>.IUr7Vȷ</'`#%)ir:n3NΊH7Gh`#kZ8y]2;Yd0+8G%q%zq4f@3B~f&ųAS>@_u-B; E9=Zs|.*Р9o7f ؘ kgs:.37zܫҰZYpQ3TaU6UU[frԷs83g Ґ:$.5hwP u)2hG#6⪺wu9}Nu'u$~.:J``a'uƟ`LtJqyVRUGf"\gc\1d\,z1 1{Odü"hp[X~?|s$&V rLj&{2? NrX@yuDĮ3KҤ`k̆3M&JXa&dE/K,(Ǟِ V<$Joh@3qRd,qCwq͈Ĭi.8ZOJQa)7bs-Z0Wve:ƹNJe݅AnϱX,8hVM%B5֏V#=zm Zppa$;}6߻*4#aٞ [FX.ϾȈ ij[ޟWUV?8x@@i`<N'5C_ =F_@|@|gA CnYMnslU;Kҏ?G j&/CLߒlgMftYqdb џD !nx|C|w1<(3W]M5Fq&gd7<a"{G7y1v^=EAuuPeAv;)7Aepļz=E}*V'ּRx9G$<6Hw<Ϡ/>Hմ[0Sa(Us>2 'T*+4'5⟹X/ 5 A0Mnb=VƉC%x.q]tƌQ:mLX6,Ev$餤C}ZSÕAN˜hzǡ Py[s釩SRy6qcڭM5s$~o46|>@;Ku|XY,,W۲cb }('@hiK8E Dr.'fTҘ-GLŤ&):l3n\4F|.c\O.]`ТN[q>^)>](01hC\LN^#^(xRC/1^Cv0.w!G?-m{*`?OxJ-LO ODk"ȓ.voI%S@. ; L¨iđp{Gهr(| *7\!IRkxedBt4 RnAMF>z#&$&JRu3ѭ]EF N5Ws] c^W<(V^>h"&&яͨT7Z$a=,]Db&G\5#?h%P02,\݄䆫#FAoz:ӡz &% z8)R-8i⪘MhEf""~H?j &#O1g?RFaP~KLr#TN5,Z5S_X-5~3h=e}Jt <<~KvWAN֏9|<|ч'v);o1F S?Au&tE|fcfuakvB֋Edw'^5-Ûr5݇IcO[_u"z.gy^&/X QTߗԀh#%=- sDy;$7l? _u1vxX?n 2bWNK|6]BO]QOЄ^-Z[ճGmXYrr]֌6-}^RrGt>R3<o+ŋ̫Ci/i~4{*kAPnk:| h& <\#vؑG6Pp/8liE,%!aeiǵݝ 8btɟʮ|Ei'=nMՁ؏.6>F'Vg/ߔL\ Qc1 _GU@*IbmR+nC|FH@UD&pzOJe^Ql )IyL6~LJPD,`9q '?PFRoo }\XW٠Kd۽$MșY^wCׂʼwe1#J*^بjꔋzDኸ]rnIОlR7\巁y>1.c+aYm( x1WE5e$.D_Kdɯt!lj+W 6ܲD}zc=]\ϭK SI\6TQt,voRz: F㦙h>2ewI:&bv P!ȅAckK-kЭ}Y`:O1>C!j?M9K7NŽ֧.n%S@[eԁJ2eB-R^x ӭWN2Z '3rBx.(u}' ̫?Uedzҝ,bz[*E|Du'[$W-JXx"V'IQB'%#5b* D"v<FoStI5AK "s-b34}f*ϯD!] 5/nyҮN=wJ0< (@8bҰ㧛H"LNtS8.=K5WXGJC0Yn0@A'-؄zj{uw:<[ut}{3ɓ_vanuf XeԊE:8'_z-3gDdy `YK\l\hQIC q$cH1H TV.%J?Xg׼VW AWN;GdW^aфPULw*B{U5r֒`S*8.7>6DIOWlg svAtcédzRo&_la,wEp?ݤv穹nzR=뽪?g%x#ƥWzcy[vɻЖ73d^ (?#*Bǧ?XJ~|c 7qO "` -WEf#n":N-P t)hjPAPڗWi ot+Jv2S> >i o'oļ:k9@[O"޻jioXle;%ښ(y# q5 Sj7?=9hȒ_[W[IfDMB  Q1yfVD )3 S;m 5-6_ybK_ }Ղ.hwy-fje -z ?@:?]44闁kU27*A P34-/Kԕ'K,+*1ȧ7Oٙ둙>A;yTC=Fl1g.UGh^(Nv Օ⪒Hz .` _:*gŊc1?aJWeJME%p]EOëY9*6hTUyj!m=&sYXȚ- \5NiK/lR,\cɭF*L,f{D=A= hK+aszc\nT͏<RGTmttib4(Lޕ ڠ6K5S1w(A&!r'h(Ɓ&aK S+[ʷĸV@NOǽfP}eslU %;v:bQv&(_dh:7 ~@i8pM XY$ ;S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4OI[$߆e8hE8pF#@MO pr99VԠ jZrˍST(p{($kmo/|í|w@[T iiSJ5 c\!99<㢻Og ʰE4jwWr.\x%F5rǮ_ڣ5Us=2FWсDk1Sphvl LxڜS7 (Mr,Qj]Su ֓}ב7 9U᠕%ga9,/aOT5q{}}ʼn@tBI,'ȳ֑*f W$PcIVQI|`Xɘy"ϴo e~{x!}#^݅j9R=|PzHI°20o(lkqx iڙ]Û!pE8ZnzǸTu~5y6T\N=5i-CO4U{N0獠e38rUyhKP0I@E/*ifp .M8aX3_)*1<^ȁf%-'5A930I*S Lxi(̰? %܉G4 5 Zwܦ:5ӻl j4- 99[$Gdu\ =7>yxş=W7lbpPh%0vw6A'iz'KyFDgNK +Xx񤎃~&iriU"\\VzhGNZ  ٷ/ Z,UB$XT,JN<[9KWL-- Kyø@xSVLS%IջUC#ud,JiC J1!ZmJ# jKTe](2NJ6VNQj5Zmڤ@LN*(dYi ;%4DE8Owy<r"\X{6^V/գ#K Ҝmv}7g&o߃Ř\RGh=_' =D7á_ Y:OpL  H냞W/pc^=**1[U94D0͌ndߣ/['l r[{ Cb˫8m],$?wxpLǐ:y0,ӈ`p<.1o ]j\~d V CupT`l}R$>:Aͥ|7 sHyu0?w-К;,4 6" /m̀bw`3+ϤdedJ(™cW;ΣɃk p|@-c~[b-?z['Y:b,>Vζ}G*C|RgdNނkv :%'<!.u:ӺNj}RZ}aCOTCAэ#nT`P`*c%t^dgC,ÏAm4Hؖ!i8UX:_LRk=9rEX]*j$"aŬ1~ߔXQ XWiJd&|9[q2! Z.ٱ( n3&TTlü$RD {:zV{{,˄fT*ub0хi{l&)/r,A{ =+'"徨_וqN zW{H`4`VCK/lr,>F= O'K^pQgjSWSڤc[% 5(㨏L &'3Y6~<c3[|v3d^x0loZ{c|vYu@IF6Zn;4:"q麸ir03!S#%zU"\?f!JQ[$j NvEުq W އfH2$iڦ(T&NWiAR47>K2r m*[5E< pR>g_LtW4Anjsܦ詃Zdn u!幑Z $;AwJTNC&9@z e4ƻ6k?`]!p_`&{n's1+P|>>dÔ\`%KȹBxutNfZ?&gYwKU$ fP(1\e44«%65ncdvJ#\]WNѩG]B_I9w(v 'kXmZVD°I"2D礀4SJ\͎>BWP*mY濈ɓld&Ou a;VU&zDPB+iwMԼCy3#sCO)kr T]Kzae ܁&lnGcFS1pcyC^,sP><bSC*q]5 8wF!81WwE#&P Q'˨J0\27l HaDU7Zn4%a+k&6tIGgz*hPyw"*![u\mE>qHY 7hk|sh8uu)ӆq400Ft䧈B7uBsAXPNq"ʢl54/ &3Y!~C֒`xs(`mAy}&8=_]uЌB f_\Ia=t['!ndڃv́ 7/hB;'HJY2QP㈥|y.òw75/̯B3ZWY_{1l|;An#>`N4\ ϮgrY^:g49E#%dG!0өDJaϑCqqaA Ul]HkcDr6Wq1_.JtVǣMqHrDqg>Fkwgꬔ5C>=׹ 'د#20)⨿8B`O]Ejݶ%X>1ox<)»7MCs?HT8 %51(.I}PmxCX?.g# RY`,z gDjx)P4fY.mj@ٹ[kWK[g/< Y\!82$4 ݬh$L&X(B |꯻+&?H=uB WIg{,MnnM~phhN"#$:1yw܃9xqQbhѼzVOpZ#2ie"ބ4iqda,)2;c' U{T>z0R`}Tzcf̙dQt&X2]ȥi-<R`Q0#u9G58xX 7± 1 @|h)!;y$(`J)DeyWp? " UNߚaHɊ~Μz Pm.I)GxurGuD;S׎=|;4E|ަC-mhNZ(.  IegǨO#Kg"oX=nN55pf䟪0{z9GjoM(0R(omt*w l$kmF?[3λzsQP`?GW< ^㬫Ltm&%r/K1ƞ9v֦#G/jb{|O6Sz|jSr@VPKЁ;C< 嶢2Rwt{y3/dIM 4wKkktLuu o7~.?'g$(AKoh'\iVlhس$SH!8<L}NH΍ m30S07_smAѨyA.s8 E0=f+a7y;9 ^S lkiFSL1 W@ɷƋj8~a&!̸CɅ#\wO+&I2<"ygaO_^ Yj=]h'n V*bȮVbFDJ ۓu[!>LI4 [:uޙ-hPfk"b钳aXYIΤW ȍtk܂!M0FPQuʲ=D.н)Qbծhw*~})'-5^\bKHyCaun&W"X0:8h~Id$W_\,ݯ  s@oN-~QH&$.""7cFgO0{53b鿒gJNn4')若eRݻɠlI%, Bخz4_>%Άߩ)Λ*Ge81wgdHrt ^GAӼm L1dmϼ%#Xze^Z $>H27<; :r ݭղn;jbdrsn8AL$bZJ_TeGEro](vhTR[?β.aV@wV9ޭ=Cȕ ꠵l [l\R.!Z[!? Cϸt,`\* P)ǝ]Y8`ra`ŒpEUҫt-,{rࡸupd8UL 'n9yuWWoE,x !jDigN*]!9k^rrG% 6|`TsѢ*OSp]QJh:Eb!% "6Υ}+t :(-_am(<Ɲ(~r44n;ڔ,rHY/fНcEd/{ˀ5Vσ} NiPi3jrg#sX35|=%>A 0!0|$ U Jkcx+L %7VwF߹z12VA 9Лև>ΙmW.C# ayCoMgI/a*2ȂQx[WX=JRnzt])c{_\/vO=92C%þψi R6qOH.{7Dj?D68eaIxH@e#Qx&k>%"u0Dw(^ոehsX$m҃UW(.Yt[+{P#un"`V 8܁胆.0Q}Yr3Q4s(vU*9Z!@P"}q \Q1cү.bJG q-]09ܛkx\%q~Yhz]L{ƒORX7O0׿>"*E}+_l~O>J>=e>N]g}zA@ M2.PprRi@L3PWYPiO Huu6 QwtS+p9]ᜐ~k_ʄ6petsu,t$~lZ^yVtyEy4J,a~u M2\oQA&f?!tn3O#] %:*zm)!9ҁm%%܊/ebn*?˦ Lg|/_a d`1 ,Ɣ)oVN q]ƴ`^&i#rRrj(mk>7JLC!yCp=@; RYJUKa8E'h??'hp0%6ϑNQ pl~/|3/x<>dbM!Sk9h}׬Fr)WՁ1-|:nsW~FFtP!p_^V"m[xN#qMVט*evGzdkʾCC ; _V45%\i{̦OENrucY^AYrz)3NJs "Bl ƕݖuSyO4?M=<}. ) 8]iXSt$7SֈaY۽㆘S,B}?z32RhYz[f Bw;Ԃ_ɮl# q( 90.یvJn}O9K.oY˞Km!Ŀ(BVDk%mv5i闛2NqЯ+؃bxGȫz?iK%.1st˛v?nyPw.!f*yk=.iMa9p qk)Gr"鍉\!]$Ht~ {o].M),M2ߋHSD"X/y?BkM[>{<$hD]RUZ$)Z$R([מd)iwz5C2r 626z/&n:ߚQbkmB!J~m=1щjI@|%~' $ PDߪy`PakWCǨeQb625%S)!Zj} ҳ}ĥ5I"$\AgIL7k`w$7jn~p?àuHnS*Ҭ1<5eYPND̩llXF?*}0 $Ԧ}7yq;F6o܇HcabyPw7R YP:A;0H8lXA.czQfKA9soaF6!SXl6[iiod M5S/t#Enrق ")@(:dCy+ٮ|~|_D݅,\:`IfVX%9|V̽!ay!\W1ܣaK)&{ىWwG4Qթ0Rl\MI1;S!4%;x˰v})'heClOhi֚# y &QKv8Rqg""pUyl-϶(ǒ=k9d!5az'$L@ [FH#@M( 71kzm &h2'j ̘Uk傻^*nY..ii3zq*7An/)mLQz t'}ܭ\-|[y EVn}oWeݫ]=Big[˛ OY,+B[/y5PFqYQ0: 0jxIe[T2 UҡѝGW/|G=kh5طR-5VgEܪR]eZ~ ,RU9sl)ouG2ʔ[YD+(L(5w[8 Yl=k>>nm >NT]ϝ(%ϭ.msD}-9O݃tE-ś5CIXYL5!DGIwj_KQ~0'DrՀ2ܫ# Cq@g{Hd(Cu^l\ KL u"t#CBw C U"2uh+owz-XpȍU? 1/ v2D:hdIgR%wP<@(0{|\A`l¸B{+\3>@-8[ R|n>q FxG1&J`mFSTlaS4I :(=_-C;:&tKE1zont8\&͆&d)YGD;">ݰ954NP ͤ˝De{:2 bkvg3ΖTK̍il9 ldK,\L v&͒x2Ť@h>an\ߨL-ݽLcv*VV__~M СERc0voA八ƐݦYy.O,01~f?\>;paɢU\;zZ!HJ@Kul]|.zdgӵVOXL2d3FGxKyvq*[2׀j"yP?hw}>oT5FZc/ABϼH IճԬ ڜhJ*WpԧcbBG4]5Pv=˥6V _bj#СN)az:U]j." g?݆!k>`. 6G GKl+l0CyT6zc 4@Y&0u>SĿZ tFhEң9,'혫XS}P xג)C,t.|z5SW֐+]2oExg qGcx dLs Z[H*~DIt^1ZJ |1UpT(I'FJ[ɎH|AD8)tppF2Bҍe8kKپrpx_ ;rS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0[ac:,@@GF.ٿ3f.):@ M(S? TNFȁ_U tt _/M2讑:NwӷN|:ë> *X#Dс{XQ=pǻUPbu~ˆ)_-&Np],L4Bټp`p:n-I ;"X'iWb@^ "Wc~vKRo1/nu/"V(ݴ+ @8vE=Gm?v,U&l/HmX(<;RZBţaYPD:`i<0o&80OPGH|d.ї/|+3r)=PJ:?.v}>]~-t??xXl3R)}h0lǷWPO꫔b#DBK+ڤE\B"U`tCj6!o"$))y$4y_t|` Y=UQ7uû#K.=7*JT(3m?&n&bT@WC好 ORKW')j<׋.R ԉ6gX\]e{!D;m21fex.Jfl  ^^,zH E#CK[OՋFÏ2u#tR;:M[ۗ ᴻ0 LuXD@OwZ|xo2$rlDcM}0+q}N ͜Z̽?qǝa="au"H:}H<2Be 7_ EX =NW.-yuBt`^qtSv2& c$iX!W0`%&UXbC0:ǿZW[ uvf?ʟ$ec*\4"g3?9ƽEt|Q3d(OQ2]" oݰ@T;i՟@7!ʸwυN߁iiݜIs Zf]3J޴~~ !)4<+Ad[j\:.t/ "ے <[9N$E!k]?5H 77ORtJ؆Ls`ˆZ-Uτ>8ڸl"mbIk:b3':í~{0` 04k1)6TF+G&eU6`#`EⁱoYu2<~ XB@Tg˘ᎱD픮O+,bnBwYCՔ􄆄DYӯ #AuH \sn(B""v{. u4N|77Y>:Z` tKBP?G7fVj"Fqj'J(%:F?gLpeo ]3Q?2p4Cؕa0L\,n٭d<[o @*!;z.XT Mq®×(3g2cI&aH $:I6xkwFn cz~^QS߉873YSf2{LteŸ{B C,3abý(꜋i5ϬyLF)^Ď b[%pm`/^͟X2Cui` %*;y$AڒԻq!d0|<Ն\Ù7 0tauޫ)SpXP秂˭rRjI_34{)g b`p/aqkITz8m~Lrb⯜hJJ*O͆r/"$)۞*^ٸ2\>{3Dz#*pm RF0^OQ`6ׅY'abԔKqìXV-5A;ɿ6y&a(RMlR]1îE},?{3G\ƉtL|>SAS_Ȍ*ef+UE]JQ9nM{JƗ&"`u2([ϐa6TիL,!?P8t՛\AX_bAmzk=2:#o:GhJXA%]wI&+}F *ߕ\,`"~O}ҧ`7kZ@.-MY1 =`My#GcPj'p!;6 suܣۖ_1r6?6lXpX 2[] Pld_Q-*HVYb4(Į]1#oCZނ=ԡT-HmpxխyhN5ᖫ\O-=&#|e ^w[PZ+{ ߗs瀨IL9_OVlRkڮcxÎVDu搮\*ƑqI"ċ=|uٔ r1'P^Jqc 3 G!bQtkpv}E蒢FRL4F9YR-+8k^F)vtT) "gxDL|([MUKQzA(ڄ)jM%.s{y__ʬjVMTx}};ӊho6ho|Hcn-rð$O=z2 ŪRd f G'Nr R%][~L& "'N/r|"D_WG p]iylڭ28g075TD:,R~wSdTCy}uprLaɮv?D3W. S_e6(ޮJZT7Q1kǠ/]y'E~%^{ߊ0')Hd^N|"uve#gS.N_^)`4\U0zP DRF &DvjswYR!,Wq̐E}fhUҭ^:!g.' t< FEǚy*Z RXؘ\iB0{ -2DBMy&H4q Wʫpc˴Fd/ptmv J҄Hde"L!WLݥ/?ܵ9%{KGd*hߧDޔ]?SzkiSr)g6S;RGxsᜠGvHOv$8 d$\ZQl=r$ ZPzSh)ؓ)`uY7SO"m3bv5f4b[am>e&N ?$!]Ȍf l?ycj_*ֺLe*m:s/a$yˉ$,d'6)k\e)8=\3#ٍ]"ح?9b6~PD)D\LB@)lO[+JWIsjO]{,+-)5Fb<^Պ>y$IiokAd!hԢnAkovY鶌n=4q PvCj/9vFD-U=o3MxD>5uZ_kR@'"ٮݍ ޳w* i OOmUܿF[b<#۽灥aG?Yg ~3ٌ\.C4GB]HFv#keԏ ]v&0dBn#NЙ^ĹnmŅjc)8_M>gQ7@ %.p@>ʳʁ1EEo)Ks|f@]y; h4AtNpY:5b\|Į"P_ U|Fq|يaSAyTuCR0 Je듼"k}辏n^}`.,>jjT14.;LZ/t]1궙ҡ`(2ŗ;3;  =`sPIVCpt\!Z9qx8P9W7CiPEfINLG!nDaf"PxrvdnjJ+3SiNtO[w~;38IS,z#_k:CWK'`P|33}j\-Pe%"(1N Fٯ*'-_IGH"J'_UZҘ K'hхT@/kț>Hc`_ Qltڝpu\]"1#:4rThѷC3"H-.2?w?"[_:4L,_U@2$p_@@|hOז]?|< kp4%]d_wوh [.\N Q(/ܪVFw큲X̃p arŁ7GG )?|; D@|w *c:TU|D}0x ŻxLt! =o3dV;"[%2w CԾ42)̀kxcYc}x%6/}I8:5 J~15;֤ouyl}P;p3T ui&7zjY e5p9oH|>@UuЌOt$ =Ai4W5/beZ8%xbY:Ha3xXCUԆleN[b"Tkt@h\3o ٣Iwdd)4tFX]r鴶Q\UThq2(}E&@r^Na 1PB׳ᩁB5T@G:`'C|T)+ b5ϰR5>9󶙳 rT8B|_EzV_k6:&&֋UlS>3{' 5MXMw=@'̻Rxڤ\]R^VI؉☼`*#+u?4;Zg@'-D^&Bnl}Gg{Q===t"С^>T:]s#HWO*jB޷KZM { L6Rއ }ڌƞ{؏L_G0C7Mȳ}ی! %܉@#|Ouj7 ^Lx*E{f(Uħ)CamNR  4԰7?vپ3){ ҵߴ6yęӚH("LJ:EV9Ӽ $py i0AmV)BbAIav^=4&wΉ݉1v1CCXᎄHV4G3Qmü b8dk/. 7?x8 :Wxڏ*5D 9C0̛$'+4uIK0uC=˳YWVHQ?2*+8)CO.BG! o;< }qxx2 Zq 'w`.zɮ9tp^֮ʹ@ liR'}M)2T35O!Bg(z@kJ=);[?UlA觐X.)s2TUph tOdPH)|R%)Y"'1e 㧏po |w/T\8%) p̍sj`q/qxREwņvZq4)` ?MػE'vgȒ| oX2IudOcr]PO6mko꜎> M|ÇN"ț $?ynҩ;8ꗳ`XB?;5$S(5xY3y*qQƯ +Ĵ{u+ZMV>in/$ >˨=(fsme}gCa=U$v*Qu˲Mozh i|^ hmUiըlpI=#2Su ЇW )ѣt4\tSl{ѱF[iMy3M̥?UgC_Qb &Rmͮvc`:|yΗ'E"x7_?'y!,zO0Ԙ^8>b\CE4ܛ|Pr.nI`ෟ)~*(Iƈv[Px+ջ‹jGMGC+U2M& %N_m pXwЙe.ɢxO&% z_F+%]-KjfxՋl.r'v-8%yˈ=֮ O(acw{b@Or*#!@iUǭ $n2TncA]nr+3W=~IM7C?ΙW{i.E.U8^]jZZ: ΜiϚ]_' H~k uœ\-\kYb4FưV:9"|`Õ۸v-].%_<~,#QIN[Ext:iJaO@XF'Zp'}cӄ5y eINԠzmУ9q×6܊bA)J*8<3>_g "g O7751G=țiI ؀5KdNOZVϊɦf[,:}4V~<&({~]ʬ/\#)7X.87I*}g9GH2!E15./ "-߶BWj?&I|@ %G2O.b3_;Q9xKLMwxD( aGԠ14Uc%l;?u3z%l;|q»s[Sb;&*.#3JB^EBH,`̓? uQ9&t|dNr}_Af\2"EH EY-;4wKDc=}-43Sd&x See@ٯiU{G3ꫥkPu^.m瑅) Wi"1)m[:)d_zc` JS[aA(Zv#+O0)^& K!f)Պ:KۿgQi~ @ܘRp++ J|_a[jnP ) Jܧw8t}0BfфZIc\GI}3 Tt\D>/J"sɀ"PsLOrG.bREhY[P\_wuYq,_80x$ ]rebȒ d)}ܬ}n^%f2VڬJ=pfIN=+9Tc7ľ=TCTNr2ѵR*Ӯie͏?kf X0M1iDtV1XDDCi톦/K/]T*OS#g?Exg|5܄)"aЇ.J5{0TC纫KuN!UꊯF`KF|+~f՝~L_㙌D|3[k":+wI<םHR9̀X/dGTrXw*Z(QEqP3ncCrW9x6&2*u‘sY4]ǟeWESi'Uaهu9ڜ2#|Ѷo|<(j./Z|:A@|w0kcJ9%wt!>5^|xBHc5i &|>@#}da$iI I 61c4I-[q{q9v_q'i/@׶|l-`HH{ l ;r"sCVK@;(ޑj>bK) f_6:i $@&֎HsV% X*YV9\b"xjk<ͳ3 B cJD,A]TIr}2j)WV^N%q!$%ua`fK:LvVf@*3 #Js7?it\ tGХd?q(McKBv\=#mWˁdz1Ts~aAA~[pP]o2ľh^n$V=`'qq! Æȇ{'*X@W.+ف:0W:`(Gn8.ɬu4 Ӄ橖!257%,96 MFɏ,nC(Ux2l9u;^f@.y.#Su9V\%JX{A `g!h'O4tPJ]Vs\Ņy:7h>}6skا]GlvTW>_Nt|Mܾe_Ex;Eu&/kk e (! v9Y ?lSe/h}_ ɅS=c*_mRujMH6K{w (y FH]!`l/y<7ĥ$hGkrQf{.nv!R0t\7mb6GYa]~L;#Q(*|1qpȆV 66]ôcdv_t9'SfԐVlb߾T@SMGn)cQDzbD[V 3?wi? OX_I p [C\LY9R<]|ƍ6E/ƀ%N?QŠJ:L.u׊!n)럈T|`cQʫ|;è.#q] cH 8hE\41Y1镗_ +{\Ge47tdx YڝﮙEKP8{x}P'"uypm 4,+48ȱTAڗ50c(BmI H$wm}~/{ SIPkK8eG".4@+V8gvQ`D{wFP[Ll*2[>S<4IWW1_GXCHu`vl U-Nk*!* [K٬-aߊ u+[{].b1՚0 Uy$ lO1b=zlfvojʽcgꬵ%E5k]`)ißBoY(텑t rW8*E _x8An4'_,@HIpڒ _(#:.oȯABvARC5:蚚<"z@^lqqZ'͌dv6(^%b`d3v%VlrCV SRq-}}PJ3/mԎ{FgO6>b|3]U{NJdiN[[=UȯeZŒrs]\x+s>9}.pBD=+L@Z#|24a۠[? ^8Kinf,^ŝj'|bTj C>6oUJ40C1`'"TŦqM5!X3? D;2k6Uɡi 1R+ ƒTEXCy-Au>vkksT׮[Ճe42Qyn擛_|\xaySU؝!ސu6p"΅}8iWẀp|BKP. Y.9ݵ; {?#9a!!~f %;jez'O;2n/^; z;8@*C_'4#Ѥ>M5̲<l:YDdze>/;GZ\'\/_VJ CB4>n2&ktV `R(ē(a쵹 aߎ0Iӈ5ӏQ^ϕ`#ǫTU_ΆY ʁ;QI[O*RgaFAofm~[^o &lYU>PVs=V?)7&պ<ł\XNQ RCv EzŌP_hH. r0ρ~ͷ)4כ?ؽ#Vy\<jB7j5rcLk鼂8(>^!d[ɇ7gBSAO@6a вx2[x;+-M$+ڇR.CT+Xj'*~ǧo3J 44 ._45~^(p؜4nA×{rML&/D*1X[k$ .4T E?&ͯ›}I<.o5HZ %$6}g2]?ݖ<׃sx| )<wu_iլ*\ EnGBYӓY9|)k元k!ЛFK;#<. (S+e(w6!DZ`jh]b q5\NRvp;z\d JL0Ady[XjϷޞ)c 67FEh ZiotCBrͽ dʀ٘9 o+s>!.\d}L՜7I`26iW9[Djۦ. {"I`Ơu liswm^0KCul=$KjriD)‰EE|v2ԣo]쀶 q(Ѝ8hS ~Q'Q!g51o#--=#ĩK !c4 R5ob1WmƬAeKawrYpM&FʘKUH2g!AsgU9#$Q0wVI[Q!Ƈ'~3qAxn9vM]tQb5k:O\2 )_#hYmY9(2P(\家%F7 .-_w^Q/RS*haD60?zE I&p-CkG.>| qJvm:b`tumզ ;:S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϰ8 W4q>Lh^8xG8P Zf [9Bu9V hLW5!aF$T,R[&~(4A\ļi&?C|JH _k@~ՙ#6yli9]Ί65_+(eSW&3FEey _XܹΛa.NM? ߇?z]?{J"_oxOwɫrJ-Rm2 D\VPƂ:|]pAv)ߪk7oBpI]ADˏ"kz/.Er}Kƞw:eK$&Od+D l4=eAJcZuvQL)R KMݧ2xB9]]Yk0}o66Rrĺo MGJ7N߹wM!{c5eP+,7Q_XB[EŨVo1Hf}C`G {5rUăsqoǸ:~,o|]>0LE1M6P=#6.EmFEviVf5yV!#w+ Zf¸n5y݂ۜվNmtrfes&^a(О\| Y\Djw/Cy~*AD ƠR1_ܹ*]$2aINU5윋}u*ΥbZ&5Lѐ=?UҞxhRrP1jNj 5C ?mIu1)ED}Z[crJjw3xd5xL-1"v#=X*Y"Ձ~N̂583YeY$o.G5K` [G;\ bf&+tc2D 6Zพ1⚎ŴD&`9]e SXkUqKox\8 ]{K]c\˫'{T=Ը)Cl 6 L.8}_Og4gu85ܠMT#P˴Q\;s CF6_'kT:%e샟8雲gYBu~feVF)D$ٿJ'+}DWk|5蹁8?^'p3|{RTdL߯ԄX,}x :&D=>&#WVs(~'k4Nt32U5Rru!8jo#d֌!Co(RX.Fi+ܿ6GWl} dL,cS8lZ E9&k6!o8)/iI9y蛚!J$^E eM_xX{YI `ॹc>@̘O#Qhbco'c$?vܧV۫&W`ˍHis3)<_lfg.IUSfՌ/T9Lf2v|f㿧4)BC2fyPϳR iEh3k0 dq 9gsjTX8PXyi|N#)YZ6Vf+_P4OSMx5 /ug+]讐-n'iL]_3S4)5Bjeκ_uֶ]D6gѽ/VUY"[}= DqØXXU Zr />wj1m#rn=2> 罕P߷jgY??k9i$81Xai Z&罸$?W,ӠOYpH\ XЉ?,M*ցvjȈ}(-T 2'31y`)CJ-ۉ9~F0Z==L}Zfe&?C c~9Ԉ,eyFĨ#Wx6.TYt:$E_8&+BP͚_mBWjvϊ QuҺww*q<}_Ql緪| kU3I eΚK!Io7 ZԒ; g!hH1`;Mù]I]l}i;)d#Q>[1RTbњ4:_ld}}{@CGX;Ó5zmQYݖhG<Ie rL[P@|X#%;T5*lYG-gy R4jC-C.vD?Y s$зVYXXtJeeDW!R 7//`tO3c:zTB9JѧnP -ICuU3. \XI ڔ|مxxe5m+@cPn'E7Y'q@d}ɚ`N n萙r^[jjg]WZV%X>5=clpvL]W,QLS'D'5$l!K~?Sgq%':C*'G']cT`VG8OH$ij:XpzTy[U!^iuvetfnHruu] ߇Bj8iŵ+ug<:ԍLd i`=E W3"YÏz8k@>  ]3Xfsg(wGrtz4%ty9 +KjWM.+|S" {GAo,-ǂKPPh5뒰U,M~sL⢷n 8&⍨B:)A= 6NP3M>$nC~sd!wB?% $0\f< u[n*[\W,L4 0g,\$!B"!~?FϺI{πl9.kڑa2QO`)X;Ae=NEn -3DrN{ wR3(C-C L_V׫^5IDhP_pNA1蠘GIMb/-uE ?CNUv [th[af-C X5& R%HHyWӞ>=@E=dkSŮmA g8jr3){ip3D`W1 @G6!pe0!ʟ{[J‰dۿ Z../6`BRD6}jeS+#c\yƖaZHo"ژ4s>ԡջ)o}eN`Cѿ}:eya۠ʕfX3vB Hyg ԯPu;rJmeGRwxiK`z;.ًe35|OK}aŶ9Y~v飊'+ e Z/-6]m6^9$3GʘˌyU@Um}!cRIH)f@0 /~ZK6Nl]Q#X9! ?PC+͔jI;:]+QB!݃Oa8 .tai4aEV,bnX>- 2œ_Lzmir(ߍzHvT܀~$ 3'ESɼ }=(K&5J4ʲXxf!C4K _`Lxq|O6"٦/t߸yz&ؐ=6Nnoŏ֡tQʓK O[%,mj!.+l}!_ tq"{VW)j [J7]ēT #w6x1Ii7]c%p l+ ,joK4؍v;pB#L30[Z%\} ]T107lR"9P|^pRC0iOE+QC%x@.ľ+=*u R۵]%vSrS^' ;2Хj搜wgXpt.s=uOt]QzaR?lܗWQ08AuA]lDiNLǬ-y9[=[FwLE>: / K,u Sޔ1@;hknFG,Ȭ( hX*׉+-XP"óX~+3D>E! (pc ~ CSA u4ݼSFB3!݊D5thA8~,sSF.(o!l* L΃rs%%lW!JzcӗG;Hz|2·O†vM9e"I?#< t8P2xMAԷЅ~?$/_=l|00#~.:م3HhH$!MS:c=t`sƯ0N(26˩gA4\aϑ??atxs[!e&\*X iL~]>heY]ljl?DORBxA qz=:1d"3$o=*ϞW#6jH/vtҧ톪 ;|i |'"j5d |=NtP.O *$Hg*^~?+O}y0tӜs{s0 WMiq==c$Ji=zB*?w5t>|=^~zœN0%cOL;:!L6_j3;0YrPZ* j"ȪdSEMr?߇\ Ov(Z{:՛H;zMXoCSò2뼨'bj!FgVRi('@M>P9t!cΣQ+z.0QeQ?d]v.sx4 tHM.kʄOEX!-']lC`FY>)={<2zPSrֵ ]n̯g-o!Q͸myib MA$e%yIxI d*p56ӊ)Y<pZzBfHHkO%s-|lwB ~\4:9L8E 9?#+q8[Fˈe[5|ḿw9!p~zg{sj֚;o[R}${M x

neH|e,]_T If|G>9_~5`XBŃܕ`S m)-a«XT*Z%'dwTۇ cSZWФ4h sF ? ?jb_xsy:NcBӨ7HΑ"9giΒ W1`)ܭ ѝRnΈTd}4#a&h0 tf\M\`|03z*TOML$жc'@o{lR5t*6 J$ xRDUe#:7$tVF9>Jԗݛsl]_Et :Xt{9r{:D|BP? _ s ~T@*]\%.-%jI2ec* ƮIoߩt CoTh'Ey1Aь,G$x"p巜^%+b2=H$G̘N $_o&u6 g"[\iu,&/Miv^Z LYp5CxZL0>%vy:'gNDu71MP1lV]տR+ŽLZ^{e҇6ZxS)lI蒇*n%ggiH$ɐ&)]ǘ HM/U[߇Jټc6BUgR Y(}D8'$No^\I9"C/u?ƚ7s#YA ; ^ܞY)y [.8΀8vBƁ #' 8wAzC2 v|Yrs=7Sy [Ql0yyRc'd49X^`,e M$(05߳hXv!iT^sUGCC˧h݆wssل??v8J 1hڠ/1xI+ѫdzDžI&2@[lȼƸ>{~+ie8C2yMڃv3 n:(ftdש<>pccڋDR <[YXX)CifnF9@@ĵ>K ?"m·ػek"==iA/\Zؙ ԃ:X/ t9+jV&,55S@P"2۽;n(#NY]t:uJUHDMgǖDK"}*l\}0D>']}3Jm/ub2N9}o.-ܙa l5*Us^S/P3> 5QZ^qa x-[Y!IFdzkޝA'~'!,9H6\Čࠄۢ3Ts/MAlJw ޅG"@- |eq+':˶z7DU[k>`w.韇p_ê[~@9/"9t(X =P2}iZb6$/۱&vi$*b>oq?AQRAel^1ڌ9Ks(efBfu? R!#;ʎ[l\J>. lv̳]$CI0ݑ-pi]˱ N4Umgq Ƈy@Ԥ͸Of=K}X+u䖈-;+qr )Xfu[6@U('Qx0y^m* jJRv֨x$~?%ѕEdPy^A- vB2,(;s'KBdٛȹclnLUsv/8$Ϸfwx~yq|nTlj2ԁ\mUDu6W"=+Ph䷪.am&*jYQۮo.D[z=eL- *_QnHJjsZՎhH5q\߼N"j1lm+pU^X|m `g7oʳ3PB!܄aňC=, R̩GUeP+y:<42 q*$ͅnJ+Zwod3 n”SQ8ƿg=,G-S~('Tt| 5)`I:%li? 8jn,zsW`#[*rɒpWX| X!,26gCq\%/d|[xS^v{ȣ3n%_RRO1̍Lj \Q3vy6U}|F]N3y= 62.YhA@1~w>8pՇ FmJ@?EZpsvz0mYqn`&;fS8QV KnJZ®d&̏h 7ZEsD&ƘcG 3|BVnb'6lVZ x78I V15hހQB )y>N3pRoX̙_q=ͽ|LNUf&PFA=+dWGSKdG2]*˰ 6f )&Cx D^c ի MŎnzW\p]H zN<.dN(b!| hYo(Iow ‰P^>w}COpc"Z#S͈2#%e1%@- R7N5ݽ#èO^C>R<9fq~o~Tqe@63MwM]w:'L?EC~({X ]fe>p>iJXaAc%gePηK-Ԥsj1ȌGUҠd>YbGޗ{lQ.i.L{ ]N;H %F-^z4 e2'w'Xv4#bTǙ #znF8"$?84 lAə̼ 1MoOmcɟ'H~ekLg726wO3o/jX^ \֋R9=> >B_o0e'x=C)^\1l.-jkS?pntVIBq#C䥞 }Y\1DQj2t?|9!ʋ֣6aOaDė|nuݩ`f raj*[Z^dEgX+x6 ^XQYpVV2yA`{}eSdj=v=`@B8Õ%E&%vj?Ur`'HջHR'_8}RUT aPs=O\Xb5+ SzzJf,6-{QfY'P () JLX({K9lYc8`nAo=d"Scur/:Ԣ7q(Sz]-Tj/(zT#/N 4Q)x3Z "A{f$E"aj4IS'yekzƂ¸8AÕ\x%Nm!%O;VpJ euW$h_xOVS-:~z3)|s`Ay;nH.#5Yk.)_Z^#$H?iȔDM:'QtΞ78'^8V&Yri.IuR-fjR9`%Q]+%6q`V E_+lj=h1tv"rPkË`@"-^)|Q` !5R;ݎw*:2B8K53 PNN|||bC#@_bM3) mcE?߁~4|4utM efrG܎6SAT$}A0)0!DzW>;(d\ M|1_JiDhdzE8.,JwoL.v ',.uRl#|j>񵠺7k-<7Z ]@)fL?~Y]Ȱ8JG}V.u<nl,o],Exu%[&%&Ъ;tO4qںe4 +(JIFrޫ(Q<54-(Svt/G!Nh±'G.ۃ0dH GcC>sWЬ `1N(g-+s3qw5:9rI$ȬhοN) e`='㯼䱘I2X r0ƟfBf<3gxua%vP,? ?vg,U ҏk"LKJCNBkBޘ_7oQI HG,Qlw.|Y~1va3{ŝfscx?NWk+ceQ\|͸PO<6þTdYV>S2*\ K;wh9D}oixB%tJoV0V]f"kq#r! ƆM@)m(b]a#Λ g*x= ٥lWBm/R3Mx0HS\;`GÆPL1Y}GpZ:;.z8{% Gќd55xI5A!NΫ;vغ(8Wu:X\N݅32#?=*  hɚp ϠU\1QmxfMͺ%RWXcNxU3>sy)= k1pKx\'Uk).- H_p%L]ɢMp#(tB:,+w2ckbLrmm(Z]((z_C3d;]j_ q4P/E%RI yTxh<fv =+;x?ʊ&EȁQ6x?(ʝ a~OdO/[|՘y9](Nnٶ]߿L~*,ߚ"04zhl͗T ǣRS{$_5 oc&_m%u"hBc1{aM?.ֵ[}}M8Umx{aGQ'\On^6=la.lYn1;DulOjCSpBQ`<=̕WL]|xmՠMw.0wQ] Bz=\_lX4Bt3EHKGm}}V.<$ձ]La,M~_i+lr"yI.蟇[p_ë~SW蟇.k Tp,Uvc˱1&)-I Ʒ =~vx(;M{sG/&uYƚT3AyGoSmC$ ZJ:۴YyԦ}PD2?(1&tȓRJa0*mS)m\^Jpw?xbS#N89(+F(at=So*ΧrI顉 }߮t;i ^>=;p~G׆yHuZye]R @ݮgY-21WKdc2̗ 8)뚚N ȝu,/@UCqz>a23>O!+6B$ &u>5g"V^Nz4$f5DhBWD0~OWb+:NA},O=o);u?x5/sJk:hFlk>N(tml!Ak\1D-9^b͐#);4 X/yWJAu?zP;8J&p%{C(fݯOil,H}:cfIh# o]r-z(^fؕLo[D9tl$;5K?'.t B^#-Z-twp>067{;xýDe*4~̇:A5K NN.R0h m|\$xc;A1ɍ}_=UL1I{IFqxB0$wRJJOszEe*CB;5X+X=SGEDb RvŦS K!%Yyq#b Sꩬ"~9yX.-(TPx}Vh"V1,dYԐpGQ)dY .R%#Ħ?u8ރ.V{r ,`.B~\3dygi!=2g_?.y]V>>Ss*G GjlSc}j`PEKצV#0y'-T/ lby[n=*oeBm@HBiNs2Y+i>S],F`!o Þ$rhʗ}?yrz(|;vhīg.{&u~59巾#a6*Hf' U ̷ m 1[<FSfJ+ d;#aIݮ5TsOX ˜}Ǣ 7/Dl5-ea~a|$tM# tcVީ(gdQd-3h97'VI`g 9N3cxydp&XlW/ j_`4(Pr1;0yb+01j1q~,! GoUd//f Zxu9+w&C&^E~_0;;0yuPt|guvDӄ>mᅙwA@`jX0ީ 6miy@uWl `q~"dsDk k{ `!B哈#g@+/ idIẈ~ՆY;R8@'I-AS:-VՒWhZO6d$*oe=e?,4ξ]񬵌#f[/oԡ ?v|BIs){[?^u6"!&gpR#GgH1ߋ좸T#כ(Vk]Yx7ϐ[| ^ aE9QWMrr,@ΫBQKliz3UK#!vΉTvZKWRF5_ -{oy,<? Z6ğ@ݺ [կYH% eo5I5w2.9{m42n $}a-o+Z"/ 2OU_ HXG]w3qbDϩ5L",މ^6E۱Kkabݳ+c LكZn`QD/kw&Mt֏y+a /&0pBu wJʸpV/F#SwB%;͕"QeLnP?T_#9ܳ#۱0,wbyvsDP}D7SOQ\DBXVg}=g,I̫B2wn&S6 4֓vʡO ѩr ѶֈQ̱R@S K?=/&*>%riMg PXV/ܞhB($+"*6ᇚwxs.H¾"CKVGM ű˱dQvG_#2JvxW\6yt?,9cS$koe@$}0./ Qb v6ֲV/!;Ixe މw+1¼TJ{7C`/B+:ٕS!pgwg7-$4! #S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP!e|8%Q[8hF|e+i;O# *҅:>8) 2݈brŢ=UU M`]| @|w$zd7\6*yJnY6l16\q0 *5^{ĥеy$?!j>HRu!I \N7{}];}+2ۈ4hQGdeJ8-+&vprCxIN1{( !&?G9#};#Ęh%|X.TZa;!''^9e.BlNcud_)4FK0bTZ5#wkߓFx*ZpUs$ #ő>;D7|>-*}a<CR|2N;]֏3"TqLCd8#i@£&*/bww v:PrvlC S۸؜SۙW輙ܖ ;zkVԓMHzum$V`4dJ)E*:!. LoW=32rhAkȄ$ߢ4v-^ X5AZO.: ltW²Q6K@SXkCT%ɾ1p=7_sa(pim6~2܇̈p撡/ GqTH@lV *HI{1 6TBw1:$x ˘}FrxY ǀ!vYR ATG-\{A[~V [M0_ Z&@$L.¥!C Kf KSt߿2g('i6CG?8)XMQLٙs%(f~g<.}.%s4l>FGxݗ_<' *0:K'l7_>8 [N|,> -7˦oo]v7* t!yx}^fػ쇵'E ṱKU̞$@煷AK72 *2 9 7Lp45 ߺX"YGx|ӆj_~)'/Uը Ny#B,=t `r'd4omaY/% ՇȏիV(Zf@o'mg!G#5󳖝7DlxytS4"6/hJs+Q`}W؇UjjN8֩ ւ^݊;UD.F W~ g12@faդ;]'i:xZ-Ɍ4LI&ԟAa o OZX7"?sypGeK )e3?M)ڇ/i26:gQېEs*@R:L8 pex%wutiyP)f ՞I/H YJïF4CM@ ,%gbY7MpqWF*xOVqQ=x!dl:rTs˃sR@nSA1A=ŊSYfabYŵ,Ô-׶Uΰ2RrR'V gP.MI#rOSꋇW5So#A WvuO <×I{+mݢ*+ÓD35 z: .ˉ{ g謢ZKjA@= 5nɸf dzj>Jϵm}+#zM˅ME,gMRvŝf "QpS&U\-¾B]A*<gN$1pQ []}~7HZ|o_ٱ7>e&LxD\őƊs-Rfh.bO:8Wxj>9Zگ:zl1&9@\sVX2U&,~CLc VҪ1-g QCB`zUI5zZ)]c4DKZ -*62iA~ۉzK=`,*ڂ1>󺶥}X(#N׸rpU"k $sy u߹QIZșyEtvޓHgE+{Y̜[p8JVvs#Z6MMMvEk Fktpڗjmfl{ڹ "سM"`_[/u(ts~iq8~ȇa0aClE(?/t ]tlCT~LAi(7_F9CTŸa9P&MTy3:E({j ؂$Ӂt3anjg; 8Y8!m,d l=Pҵ <d&fФ@%nPu>lGܠMQV/)M5^ck`rZܕ}{Me׍Dl,8ߐ#&#4aOi:5n'-ǂ5J-ZX}Ae Ie4Ɔ"S gY'@ Z}mXž;0'\"aXUIUl.h"=I0wa) '7i8˵EpK\̚h%An'Y # ]^)NұL2ፘ+}/T"ݬ랛4DLEJV&c.S5۾+;@h5D-PJЊXk;IO=W+r,SVFC u}w{T%ZFUx ǩ R^I2"jN k1L(X=3驎 r*W5Egf$) w{C'g-q@9 EHi>3{y6GȧXE P (Uq3F`b .NΙ1R&Q3 @t&Z0'g SqYF$ډngӔi ^S(=I!3%\mnxU\iv$¸Kr$-_G¿'YQw2MܡOQ, A<+3_m o0;ڸ3l=pÁ=By4Zp<{rx$[_s;‰8|z}ԋ-]>@'Iz~"/f6O_ק4lmheV7"] [ ɤ&;9%*EYY <ήې9 x1M)) ůL=Eg7˲>>OyDRA`?s2b&7 :T p0hUPu%YJmt*j#u8Aã z KDm zFY@$24#}chPbz'$8#\q+c%f/-X Ap%.#æ<+|gꮙ~˖+Xa(h@)eXPT!cG[:epؓ i@?<\P>|Nl <}SY 邾/疯7#{b+-wGi+ZTߪ<3n) =A_Kmc!&ۆC TUb3#  \=@CyI{&*\1Ĥp e ͳo>]+N Itv8IS E`;K%h}f;;J\l X'>(#ck@(MG\Jjzگ;9q (Pʫ:?`utbqsX!i]Vշ▮Rr[6 wmEFcƛb' W\es2 "uG_| SPV7Ɣ|pR2, lxokfX)͢++mبh;kZ4." d$~ռޤYWKɛ+E\!yt^ВCJI'yZ6^- |c>y0@l `!s?8xP{_ |X`kz!,|@|i:lg D%1a. 憿g)~⪕(GR$8r;)˳!pOA{bf^%1I 5soP>=Pk e,mM {ҨfAxpJo9 v@$&4) W4:=_e2i5a}c#QS5 :~0f M[`@l)ۿ( sLryp44y&A*KHFTK &CJ-Jt ȍz# y` 3OB?tձ;dwedDw,ko4M5Ur맼^t)LT^Dv.*rG~8^Cfs# % nT2j{ _#$)F$)9Ȧ>/CۥD\0QpDT//MD*N<5 l5D5.Dtq7|>@|>>Wt7h7Z+;N3F6^$R,[A3ZuP4y=Kz3Z7F> wk]qQyH6| FRGipYakPZ~X#;;jC1PP 3^'`tPX#cO"D],r({ȺP-CLqSuhViaL_Cnv-γiZ]"@+!m)qVL$0(Ψң{O|<]Mb jZN1aP›x';}CtX uINB!-2Z<]V1aU:0kV t\(<ǃc @9|蓷՚'|3eŇAi4jb S.E=I9qaJotO?u^ $]v!q =JK(AxHH_+%6H N`&7ژd-{ מc#9bN B?[oY5J2 gǞRjHޘ^C ->-tYQ!0f^N{i!A8z :_-v$$ 5s-ifp?# Pr\I2X`tq,4A7BmX=rij+ PdǪ@nC,(!)]WL1'q>*dy$n"V7!q+ mgSi .i՛cu(.*-Z 5WQ_Y_jT>R!zui a`4%c*w<EM/3u RZaZcQ̝IEvbjw _0ԝ* @z=KV_3}H\J͝d fpL,]j!kLݽ~BZ>O4Q㺨L._t% ;vd#$ laBE^>(+ &r{N?~Z:"p ~v] :kT +ݫEPQNTB;9 /dNmwN @nowNA-5w'B9̬@ oxEk̑;  blWXX}-4V#FS'qRoPjTjFg~ޮ> #h/ e= !H 縢0䯶S~6Qb|OnKb)fMOtN}TJ5awb8(;Z;{' کG9M5ij{C *o@4rژs.WaVDU"84Sc`pyå7&w/=P4b BAFc[g%3jo0fy.ٸqE+1" o .qJ~d?HPx*uʗ[YqM=LE6H[<3y5* 2'47C]K/}  )lK)ӖM.*Ge-t}`k1m脎!IYFn7i/͌y{f!?sMP]/Z F?Q O3n&?1k "~ |˓}'Xx'[7j .0]\nEF׻ojߦuxthх[/OUݛTi?R'{ꢑ^H1V G53VK_BIų 9d*B{в>quOb#|/6ӱE 0XL)h$l1OVoZy)ذ/UĻGH:tf1l fY@?+;N2 @Uv7HkrLkhja>}(*wvg&͋Af֌=3N08KT+[>3[sE3'1SX ȵѢ[hOjʾY~ ־;,^DHyqԯMa+GgC UdnчD]P||nQC=lJ*:l#ְ#' ekF+բAa-S]B[Jg{~9*~%s:&p\ WgRی6yC Y[J0I5^BO DL ]NkqhL Fv;Hr9N wlCWsNl*t@lLuؔE5͜p]^0Ξ5Ty P×bxtVJ!-ӈngɕ1Ih. f, *B9cZQA@/;ve{%+ƞj0Y5z_L\jTkn۰e9(+O.`xqqwrKvI+who *MZOȽ-UiA j_`.rjG=&)ö7;}0&ilOj2~Tl9%lueE9r3)D@,Z (T# vS.j 8GQ+!8 cٯ ԉYw6Oq q!GXÜZ5i:+2eEl f酤 ILiLvFPPǛG(, b"Y2NP?va1l2:HmX rFp5* 䆭_crq7٤6_jXC'Je0ҰeYDkp֡)wqOB 0;q\4&#._=yY>BE!}NFUHEas䵞_ZH %޾{a /= BU$~uoY&8+}0FӃ&2 C Y$;i1(f6Ebc ȜGj7VPlHS1Xwo%ԑWf1uaT@OG־1yB̀DgR`BWr6 P}\ 2h/k 9weXe6e\N#PO*|||bH[?6h .PU?m|0>4?brJL*(# R#)/;خ@W"[v:p4bA& =&  GS~ǯS-p?0>=_GA[\UkU2WC5ш,kLJ#}Zblh->÷tBf@4$ns~3|9F$ KEIfa9~_//-,wVsotgZ'j8BfQYߒIW]OWާ{?@qYE-3E;Xż=0twx {m+Ȁ2^Jw=5gkW%*?8O+P+L^E`M4Ht5Kɏ+ <9B1;;ڸU/uhW~ 7cYHQsɿ'@~I#nU?,Ii9!j_sc_{|>O}YT::LÄ(Z8}mVܽfV鏅dr3q(?7#hX7/ (}usutx Xذ:.ǵnYCڭ-94rtpῪ.ٶTvU8Kژq=K䋂j"alI*2wKS&BNݣRCcb+)4njvcV-9F:hI8#ioPjeMw4v1HyVgj1czHO6E{| YB+"]!ЏP? $Qg1>ׅwm7AUZO ZT^;8;yAG(ےF޷#jB&thZ@j.jp\Y*_)Yߵ~ɸ}#s OVԇQu"W6'(^=@Cyf& ghvNIo"hgoDxO .AT%y|xd-aW0pd귻HN/W >chb}(Uϔ'yX26eoW d2z0kaHm"e9(*^y;Z1|*""=n[1:_)yȮA2d ύ< 8IȵP؀Mmǂ4Xbi$90`+ 7vӍ}h{-%]:thYRfΗ!9u{IVJ`$]fH Ya .<WÈAl ?a|\$n^R쓠t'7zܐI?~C~WXu. /6Io'iE5H0"HpDxBވ2`3]2qpsm\ P/&+)`μLew;b-;Pvm|0qc\YRf<N78t/uHC{8u#@V=R&leLރ _[(A}jXgݤ;@}9N[U ]WunVR{8϶-LJtZ!]G0Wb42լ+UD6g/楪7#`#4;|p8ASن}^Z(y¯&5R(q[űi{YNa`Df^qsX˪. ׈h7Pۿ Oh0&+ *!Q08mi .`r''t }OyB#,Ȃy]z*SM#. G gL IodmC 9IBk%ģ@`&D>ޯ+ꍴOg񊦦&Jۇ2Zs -߇35:rI16Ws ?)c8~RY fm;M]Zwvd*`nTzÓ4oyb] h~ 'Y FwB#S78ӹ^pUFg.}kb :2k"~-LN#-GOns<ɀ0C#`#A0 W'2Z- JyV''NdeU 49)7QT<պGϻ0?V~CFi^P Dq\qpf;מBG*>6g ;^,k_LM||=e`El:TO}M݂M44"ۮaR#`"[a5̰aͿT\x8'O:&\=NIpD;͔< @bDrXƮ&Ul*ZBOYxwlv 3(2,_NGMa9z ןAl};Iio1'=L%zzp&UA6RlZG(_&A='_о-昊@9ŧmQtj.V絓^ y~(|jAaA[[x K/~ٔLU]'̈́Mġ(Q1 ().,i (R=J/^Tޭ_?C2>Ev^$b%zBõ12le %M@3ԯTLބJ$ |=q`+$gM J$߯6RvP.^3vnX@LR:; 8]aƁūKi<=澖$y膒[B3:~{9\,>&gqέ~{.mNQ"6EdRt;p>p5$ډN0 An5F_ąQ,3 \ek͝FG7Wq0c{7+ Y HfSq;cfuxw23 J8y^g|7NE;fŠM&v`{[ޞw.yX#}OCyGvog:1DfãU`~yߥClDJ4q@~mvM #~pznsn8ۛk?ᔣYbTf$s.{x]48]k1mp>y=;V$Es&pcW-'CɪJ;]:˲WXa4[g`U x3,JbtHa UaWwb-*`J`V]T56_iώzjэh,jȞ pᣰt$V6\^~q1*L+a_NtE%Y$g*w ʎ[AqnV7FK˩ڕ]VbRΧ K8&6+i2ګV΀¿[%pJܟg xoRUZaWsgkUy~Rre;TDxZ$Bln&11Yk.,V$SrY/6npdpX"=88+"t짨') XRs/Eo% o`qۮPDtY4}+ h#1ǭ؆2ys"<")i&tW&̕c>Kk{g X WbG%RROE(Ktħh.D)omژ4.m^-n4PaO*"Tk3'7ȋigDӜyJbܘI)_y˟9~=L1[1kNzkKߩ, @vlB 歰6G#LO QO:HSE @OS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP:`)O8hF|U(')"@ /9NMh 0$`jmp@W*Lgf*{(X!t\ސ n+yDq+muKO|:ñ@|`_]R6E7*ꖴ_l =XHΞ$ʝmccJAnP+[8х_%H]N"w"2CtN8Hjp"=+"379eJ>L soXguNDst f⋿=KZ2*;IJ Y SdPl,)G2&g2Ob )Jގo@(p+NTIc(nMbBv׵d5A3l*։{?W\}_w1;1i쁵ڪwKr@ JAb!?:㮬hjȮ`Z~ˊXȟ*s$gG7KJԎsSAi1#UmR*4$ȳa;efFkKh#"F EpC f^"XƟI!i!z:@IF 3a[ESX8@lHdmB]b] $y)4<Z8Rbpg8F0iJ;Xw͎uLH!]=tqRZyع:i ;QsPzԄ AO  7u9joH]C wO$[A n,{Om^~|##yLwJ#ZpL'CVƌ-UX_c4ߥq51z@? '`v%ekF`9 'Y^4Fy)?&F9ԬMeFe8+ V&9 FYX?lr\V5Z}##4[ KG1fk*Y%_aL($\#=TnVÖ 8m+_[޴' @S!/3|Q)dG(pqQ=Ɩ! X(эp "4’ZbaQsXSٝ8CyJ)v-9 Hö]{4 [E3>+ORѨgd7-H(|);p%mn!73w5~*ע~ Ź_3A[U$=d=gB+epB@ ~ZD_$Lʽ0"a ׌l9>!{6,ĿIXdqVvmO Y31Vo7-42lo!Kx; ^9>ǪF1w<բ0@.4zNnRsv =T+$mWR: d/;w}0j͖^I"w4{bX$w4pn {C1Gf`7>X"`T{b ^+ = /o= 5I@n'/2ofl9eǕAs/0)a5@'P&gi SʜÏM gTޜtyRU:餟X] %1oZ5gqj3DQ+*yw\S)Swi4N^1h`_>wT\ð-.@g{^TI^f#U_4w7㧣^؁qjkf+kOT= v_pZ\iTOi'WM|J1?BJ@!uA#]Lz `K( ߯o2)*C-~Rjlzj{g9O|NQʮ `@z 6 ĸvAIK?|/GpN6D돦8jDCS=v^ˋ(;|eIS{;{8 ռEZiO*-1zi^ ·Yz hVb]>="Yߣ݉a[@z6`JɝVnd!X 028 dO^M 竔VuK9&t0|9YSC(@jlKJ7i_9~ ^zfUD1bDaOBJ,8r_C8>|ݕֆK@QLBwǥ}P;CK|{]&^zg*k359]u(Y4N콍uMnJlP.^7:ŌăgX"=oߤg0$.=\6m Z&!%rhX 7WJ5cZuja!1B@^rΰg*Iῖm.%e"s(% Yڦ鉜1UߨGCbfӯ̌W_ٹ-'@|b܋*H-Xj|jU1>Q/\nNn=9Y.r4؎]=bKbg+hB{Vuc" `rI4MLF~_J|L ^sq) ؓ$ɽ\udJ1q4w6`vZNl2qUnƒCE,ZEIyi#&C\M$_jSPXe^1"PoUHh}/ !dEb[@Rc=:P<,#?J6$CLPL긹[H#emX!_Ŋh"v] -mYsui HA"Է or(:".vf:C$Ļ>7ck?Q73%irF~ x~]O|dvڌya]-UOdF#\ed(, ȕy[@9]m%hHRWmdAs"7ȗ΁ph"dǁƺں }׉ r"_4{Lf)S5](u6>SQrc?BRRi'ȶ`~թ$6Y!.z}+77i/ۑ# *t9+5q${ Ӭ:5Y'E&[ذU,,Dm;HF)@UYc10^=2Sv>B͸".#GČ/"/Z bu ƶ -&H3#C(odOJN472ߥD8fl 9JǀPUK ) }(@!@Um rwrd XDُ!_q7v/6KˡlWoyǼ"{~QM줷W?)KEyНyN<` NPez@ryH|H"[R$1yR3QHa g«xY1N@ҴݠKU^J_ Gw]v5+O͹{F6h)Sl4I+Qϳ& !\('Ww4@O/͗f q\l^0[51\9XJu-8c>KD 24l5dϦ*L|v_ufniZo6XSP+"1YPA0a~M/9`,9V"Xh6͊3PaPGbg9ՄTI_wDBF5Н.Bf },9~t{'s"*Bǣn3gfN+RW!,_y/6řo )p~֬XYhf Ÿѭ+F/l\_1 UF( Pʰ %'Uz6;Җ6hscg W;>>=q^j22}FR`6$]a)3TCzbm Ŕ^! bWFf mPeMMtLQL~K;6$ڡ,A(`s;f4F(o5g4j sSsǎwmT GؔNuƲ K0Zձ@V, noxݒN8Lt¼6MwA4CqbPA;[w+[뭸6=MàFdPߵ$uoә"AJLz(҅{R9X?"S2+GԉoDa~zJ!2{1rRD`?i'UrYe;$M!1sGI洛B|eմݍ/>B#G<kNUԂR, ، ߡKRNAu;D3s'U}!~檰G: 7~hKLRӑ=B*gb0UL0p/tgT$DTرC=m_HGm0yZ1hw,3K>[W#Jʇ9ai!K[jғV1 :c{"##izmAZn9t&ZV,?EQT}QH zʖӘ[J(}sM$|ktP.v类Bf[ baUy"cgq`iu](Qr.+7|8Xh/ݿ3l;j"|@@|j@<8geC,vh$Fipk[KC\h\JŜkVùE%F5fܸL^$@I|T^wCr1'߫| ^5|њ>=% .Wzw)e8A©&DQxIW+u7}).Y) $TG׊qJ^Qv_?2|8Cm$JW+I5Ow b%~g#v$o#ScS@/,YS$rxE$$2%Hl N}Ws79{:`h4Bbtbxh їft=3^ϷYOfRh2:u Z,zc5 1M0KwVrfmWM;5_R\-!ywIpA8 S]-]:=|?!\)Z h"_N/ Y -| dH0b73h׈Z?W}?O$V>FDam&"no{n79wQIJ$LfȺ~D|?%[]KUny} ,&?-a'!?2+].ĩ? l\f 0ynO3v ɗ+m{o}9KG7C. 6$rcRXJs~ mNA~*M{ dmoρ$*iζ},ͮ8"g6F4͈./CAeHCO@PO1S'Li6go!W߹aU<,EPsm(xKeO ^zNzc0_hK5g Z3O-e_A|,?Sy TA9饟=@`0B}q޲iξ%eprz`:_3`wp))1ʏ8!ї4o$g t,"-jA9φBA-b6ڟv\cL$zIHdw E#=G?RClP<>v] [<D郌&Zcg"Ytx9\Gɱa߄w-Q=䃞ާ/+0T率%]ݽ.đV8~{y<gadU/jjt-uv+ZS$EQgjC|7|!J |yd 1,]SBQkX:p)٨KOW׬V6B7쥤jB)E}9U;!ie?ӕm'uFS}!U.pl3\'}.Ǡ9x=џ'1pCc|>Y?rw=FUg|B7rثE }q Ya((rVOdkM/mGz b fL6rB$V6D7oATL DٔB-(j:jڌxxĥrq,FǯiC!&U,9*c#I!t@o)l1.E5಍9_ Hs!;Nc:ml4H Rc,nZtTB'_WTJ( W DHQk|X3+X=g9.{ݢx_l:L !Ł.!y(%;5_*1&pհ/W|k+l(;@˾k,6pKcmLxPjQ,^l{i::$+L4/Z(+5prD&NSbJ ,(>ߍa=3r8!}^Kt42w}1`>9|zvDE@gzj \ubB\X(oHGn މA;v&w/o~黷{oCekg>G3ۢ}Ae*rB萍 ?36*B7ۮ3LcTLo.}␄CMYCٗxh-YRP&y,e\ybz/F߹BRI`ƧQν淴O/3D8 $+)Ҵ, aFlSNwr&a\"t4eio?_~ BwelbH$(<=QtPURGG8ZɻeR&їt,fX7rup IxPq W"gP@A؁FҪb^ ~>o\X6Rc[R9wi Zj}fe{@)mAF(%p",2Q/`+a|* D3Ȃ4ZhbA{b'#.Fڸ{pD)P:4Վ_ѧc):I^ڎpth_:HVEDP,O:ATШ`י39惂3~ _(x.d"=@*K%H<4mRg&tse>0mj0dO<ƿ\u\g]AlBq%x^$|[9M[38)4F%ۢN_T~1=0]k֛U1bj.IqG0q9iIvR ɯ]^:DB۔8na8DKoT<-C6g@#B+t~q>i1k4qj!ÒԢFN8uvr"PX-@Tg}goI%S?91M JԚtX*q3%bxϐL*S|G arW>WNѮ".FWO [Al}R%$~?ip\bѰ[tQdRM QKZy%[底07p&I9p;n<{s4ƪNolly6^/opnX1IkZK> qδ;q T"f")q2Cb`גd_TpՀ%8[#r ~qQdҺ UҢz=;[+ X|8+s . `*AK~3Ud5(^(G37~faϓtvL 硚D.Md @b=/X~fLº ~_E t 4IX֖u>2[BOƎ>j[WLễm$:b:,J_{\)n]j7a`;=HvZ!@d>'Ī#.'|]ʂ!F&Q7M#:h 1Οw!RS'SYEaQ"`Yrӓ2>tIUprD&_[c^i`gn:ȐO+DӋtKmG&%wxNm)j/5 Q4AJ/ ݽ^ZN _@+[bZ jLЭ?l~8~1=YU{=J[ܰpI߾=cxU0҄cFڥfʹ4(W[벆2hgfFT(Kތ8THNWAlay^ bZz+zPY=:k45) +^/]u(!ySPkhl]@Ka 9gR*kE%)nN#_3HVEmwa&!Ԥf̔ERl \S@wxE㤑͢gBSgkxnKe>ZDE+,f / lPE;HcDQP*2Y r(KO +)J;k||>@pGXƉ EC||j0U@<{@pOaz-r o mu݄Dz}Ua_LIOEK}㝱ipǯ7U֠*8`hU?|F@|z1.8/^B4R[ ӵR\I n^ ;4+w e p6 {<DLn͠C 1@2mkC$YcD$U>a_#SkɿcI;K[ka+šxR.*xyDuYQ E8{+ꋺ !Pb }mA'>8*~~b'Wŵ b|@g1bީ~ŀh]3s,dܫJ ڝشI`1{9h,4"Ҵ'|sd@t a^addsRmû>BL-6C@}Fm~) RcọœQR-3*Gl A7zM? 7?? p}7(P*1u9 %l\Z"C־ i%E`96l3v9 ڮ)ijҏ0}HLGktחIWrq/kM2<D4>fۓjZM<\(O@xJ!Tfjt>= Qi:f-+DkԹdW9 ފ*NBP=ւUk"Z%RktJ_]3iRD m,A(b_<ܿV e\@)ArA3y\zc`[J1<ڇCա)-6v'T?m`CzøcGPwʏE|&v#Ѷb۰[4)[Gu" s 2C#pܽ: .Q<1P"!;$ϰp ^ %an<6N^Bh6,MZ! ΅ڇ 5?wh8^%Ko;9[nJ546I 3l&7‹bU!hjjVnBeD}r+TBZ~ k(~mS4N].n(ޞ2WEF^193Q -C[+Ze!UcGQc7HmDHN Y*˜x0p3Vh=@6}?*Pp 9臲LɈz5(\jɺw>T:Ll9_ d 幍jX`+\ܼ/7tȡ1UgG9L)(y" ;τ+1'WvajQ|y!,M-U̪O芎qgM@Rkj`"(K(ݞ5RM{ i;&5I}Ί)` 3@0P3IX{JaJoaua~"k|ӀBh7J QP?~'|._>wW?xY]ܶ6^Y4 eK+\M h#9u!v+"a zx,Zo@[1XnTZm!4 /CL''`;%`ԠUp1#,rݐv՗S]dSbܾo>Gj^\(m(]ty- ֱ>U(T; M9fO9f o=XGWȂ7|OVe1#K݈j5FJ- *:yִaCk؏)(Pl3TD@=l{=^s1<[HƒT=aȝ η&x`pAbV:sAdCQ6xR'.?c{XX?dZYQ")3 %ʫf2mz9%E!ؕG`^&ׄ z5Xat ? jY&Ů(#:δ(B_Ϟm{:**毎uR K] uخ׌Es'E Pb >@B0o Q\ te4or܍;QJt; b4cN35пF"bmzd{]L7FO>CB.bU;VZE93z&GՕ<\ 5q 쬷B4NR1)YF.ꉬBe(c=Ib_`'=n GC_+ĈgoW̄?UYjjU]RYA]T} Oz.%kV_,J *8vn9a DwZ?5 P Gq}]WJ?騷Si,_$uHЊt4X;>sXCNLy#VMNMkFc#$d^-^ɫ LfIfAѯdXJ/ԏ7B% `B4nmE"jqٺlNw6=\H)36)WngxpS0,h\s'}8VՃa&xTKY_2CaA HŽȏ9^ wNPkY"I#euWvY|5QI =z;*o]5"zR@59^ ^Whա"-@7 ]3fJ<Ɲ \\沇|? Պ}f0`ML/`)q_k|?^hx&iϞ$ƅZ ;07,Z]^$%lDן1f @^iX_oT-OѨxFӳ_7:.ab[_ 9pqaL_GF?gZLBQ̐ńˏq]WO8e{y3_І_%f0SΏiYX0LWQK—Q%?>B0Ay*l@-˼*Pb=gR{Px)$JxdHJI\sԐh]MgO^)<|~j|!?, C:hc |Us]1 )$>:SO^yˠs0犼V|-܃A^n= l_VdxN<2@mov<9 9i3DZӋIIT, } ;Ļ4'Nvؕ\$7*1gn>S͡ . S(SzuFXY$H"/Lo be@QvM_ 'Mܦ-@֚s?h@+H|_ 0nuP7/7}EՂD_eLmZ\Y.ķ)\Ӝ]G&#I N?;zVSm V}8J2_AS|>lGXP.Z)>ŜCsii? 8=AhXvC9ب g9aP7"QNL3z ;0%nkzzGCɄS 4Ϣh2_m=z/V'bGƟGd9HJE~IdF3S6YuQPȒ3\Fe%|\~v/BѪb='V~B:u$8~U!ݏV!G;{b}&vjJP\M `+Sa=27jRAuB[[laP`5/2& \UI{b=^; )hO_5 ڹΖNj3K%}2A'u尩gKs_ ,n^gąf׾os *1\7/`$p1k;|6Jʄ 2ky5͉;RY|@|PıJqKt:Zk;_hkJ6.6ph?/4/ɕ=5Smؿc JpMp7$ߒ44DZ}.L3ldkQƼf)8Bg݌+fXT_W#;l?prti_ybJVK)FE_(.E0<خhy:?,󐸞2 S(ܘ^z/Vʝ6Y:@lWK@!}D?0a~9E:aK2&CA;a3s:wmk_fDEÍQaD>@c=A}o]\O)$ ⫝XG{m3Hoor$5ᆏ\) wTk˱ ٕ`2Ԗw-&"(5܈{h(Z6eVm; e+IgBjtswB[k$DwQcHXgeI2lpX_|;_Bf~?m^8nҐƑ:n(Yw&|O.XxT\6Ziu[6)Kl. mP&6@Le1Cyxb !Uy dFGSdiz! !YɻSRc;V@v#LxR5,s tM4:AP8ϙv2AҷcmfC2ڿ-$5ç6gA0q< BDl>قM#te[R!@APd[n0ku,jvBx;4Ĭm#P[<ՋnCYdKr3Cvڬ'q[=K!@ q,`Nӥ}B\V3ⷻe*EY Z}jEϊЧ GH߉fG|fS%F8CW÷~O'CzZ:)9ܫ%'{z{]NT{-d |)iQO]r-}Ky6bL :T)e#:m"c1́9Ұ"@U>~&vޙ9Gcm$+vPh JFsdr7"30.r48NDߚ-56zc0?6,~Y@sދq60?mk>Xk`%k/ɓ8/@΢ihh($s\! T6[ÁЩI!uV㮚(Ipmuvl ,Eir,^HI( 7U_5Sr2}v|֎#-:_"1sz7rz,%M;̧h |,bE-rtkanO D~VLVl*KDpZ㫐/(H4E"#AڎU`>!L-LjT'^HokrhV0 3&7e)M]˼S/Zh5,VGp` bJy\~8S*weDAleK%(K|"!Tlt X*X(ygڬc[Q${x c-q?,}q Y HgtDD]E>nAAmmڤʣ4hY_p%:`)9$~## ߅Ao5]G]c&EQLbe/i*{:]Gl<η/"N@+&ߖ:O'Yz)ЃFZgP E3 B-0Zף3h}eI~h.rPj][nOo j ٩,}re$ؓIGyY@\ݵo$XTogh6<zL(L; ?Z{cnXW662Iwhh#Q_pKJqr=+3~[ڳRK/ݾJ˯~U'C)Nsbqُn0o 8cNjTMF>L=&EdlZ!{h G6y񖋇]Rڇ]*iTj̫[ ϖRs@#i LYUC42-cǮ"|=Fnwډ@`G $ e"Jzt~n;Kp#Ed]0%+."(wVit%,֑Lg;0l=f\,6Z,> TE`]ЅM--2սqljxtG*=+3})'1<1Әt=oegcK-ݪ5"482qJ )Fm0_Wp+}6YG֠I> GP9)U9U`˄1NQ5旤tL8Iכ#.#IQT}ڝ@"ƾfU(:{J]Q#d-;F>1$x,MqMNa`{vs-:$^ȕ= PքA l3ס @p"B/r&Fd]=W|\.[+LE QfmLx*m&5bsIKmdcT 0#Hv4)P])g!IJw}s& 5JCY5%&MxW27R޺MGL< nOe'L+8i] _0 $tJP"o8xP6Hƞo ՊRurٕэ|Ƥ@h+:;tGNfV1S[3&˯;ԛ&/}_Q̉0| ET/d =Ks1]SUݎwNCP>=!@I)5H4 AͺQ1߫v}pW=Rll$/@UPX$s?H0P_vsJ_b77"HӾC,6g5wYBLdBǠLJ(DЏ#63: Cw aIZ&Ze?odƅ&ϴMO' Xo8QT,fPu|SA:ө*M]83+Z҈WFLWH$p&ו7WW LxB g+Z %㚮S~PZ$ٱM"z>Qݖ /l?:l̅}Xh( nA2b,- O%((S]}o:~?l2zɳks.7;>ɀ_ڵ u.[:~Bln휭O$YatL<]JY%šPlb`'>m>l;D^mwi=SRC3Dr^`| c[ȹ^XbN0sK>Ekw䱫V1D A4\i+Di(fE@Kb#F5K=ncT5vcMr]3XV/H: ]&.ΖޛPy scF%9h 4&emsа(2vĠy %M,"9_[w9~e]"4GU"&"t01~raNd汲,J:*T $ e\e  LWqkVn]Ըհ&#S^Ntj.)N-XA|x<+ϣ2,#of !ɟ$8uSaεig۬̒~K+u+E]!{s%a9/7E86zbKaZ*pg~aZlƸKmґ/E(玧IQ޲2[^>V TH9~LFx- 4rQkF5'-]e.߁a[uq'S5i3\I݃=Ӗgt5Oӫӵ@iGC4(N!U[]6і@^X#4}NO]:;\ک~ӵo+x@`[S]Miԏ[eŀvy|ٔ"%l U_"ˉ޳C[#؉<9&zP.$>URۂv#+U ݙJ z!7+yGrE1z ?:|J%tΎ0eQZFIʅG\i+fp[$m1j$Bq#p̠ y+% {Үuţ=nkJLGy3 F2-ӓh̢0nܺgO\& .d uڶ+U/sjmu?~p? Kj6r?R;`cZZ퀱)r[Cs(_:#/$Uޟݰ ,~3L%HX"\> lհ6y#j]Vx7{bt* #NڢnbZ6HVp T=&LEWr&fx@˫IB+4'pMz0/(˨]*e3tD;:HsQow r=򿽂3S!.,vQ19 Qz.s͂:/] #@Q7)c3~[)KJ ;Zt̫3\y`f٩w&IMpRU)Yө"IGlz1nCn9~~+;΢hwg%!,uW60H/`*YOpic3Grʅ 05_#A 2/r@~}F#K[arSF~r0m8S>m\/ 8wѥDN!'pQb`jJ)bz`wb^cyVTlbA< v0x$/ l(҂?xT_\L?sŐQQ dyWi+޽0ϠU@32PvˇuS :LzR93QJ w@r>=~2BMG\ɺOO#;_oxPUX`BLj>K(o8Rp]nZYxW;n0 *LP*ʍ`x_WC+QavF Qnݮ{vd N.տ{Mw̷\u7q4v%$W}Mj:}A'u!h,x;R)  nQsqI_ ;xu0-A,)FKt/95C4物(4~5ڵ,xCjZj"x ~g٘0,hGSvM'<>j)?-qzK*{ML.7}4\Q nm!q 1@E cXıH K?ȦPk~@m ^6 3VK&zǧ[PQ>ޚfIleI喥_[ @-ݳH]Ѹ252|V?Cgrx,w uߠŒ0.~4&+Ii"2B,%1b+ա`ϞDɟF,L2<3;~ׄ߶Hءjs4nڔ"l+G#BR|{2==;ݽDhӍgJVnW,˄̃ ά`ٸP`+f(k򥭚&2f QH:e;+ZM t܍g)Q+'CWLPv6z> }w>ÂV.s: !&Ǐ*-5x廋ng?v! e P 8B;l>݌ Ѿ9#@(sj!d}suti_?# ;t4'9"Jʹzz3Iu ORpe>1L)'QmuUӔl΂J÷)'"D*")s)01joMm.Էy;,mG"E~Ĥ£0#GI24F&7ک;X :^ڪ4J8('^[3'K=B@hjC9hK?E‚n*#to*'Ͻc`vj\q+n8# B "f߹ʜ4˂? iѳ9,cwN%pBcY;H1*Jž\V8'guDgmes "=ϼz+ɛcP FsQ'DaENfVC0\W2VaQS`dz}l~0ze0Իr ZAcc+fdpy+JXTJ+V%5_5Թ(hCk@zY'ޡ6PJ}ļ^YHarFS{iQ3pg4Z ?#g<˝|݊+:2蕑*4eGPj>Xrmc0m?e1iTyG@DDzǡp;pu1kTjX3*5t(isj1 p gM]=1'Y@^ v^@](/4+r-A !Z4M npj.Fw Uz~&=w8&TÔ̳SzFauT6n2-WeE/ ߻#(3MUϵJ["h #p'HXx!Gu̜v T2,ӾE'Nl~+܆YvA5 J1gi0;b[TrLo&,p`EPH *x<૽u5z/(fޢ (H_fHCUevN#$DqO5.z9yy"b EzU;\֐C!hXN2Ou8١{N;w=__Tw6CTY%v4]T`_ |?#>A9M27 K,@4EG8iL7vq5pt2bֲSlg=](Zū؍st4WXokNu'F~+Mx#ȾBo /sMp D= BMH18[+Vt Zi Hpg&;4Ѷ 8xP \ #ve,a#T6|@@|i49(%>̢v+K m014;xS\9o*#u@ÝOݮ,> W \ *R# H+LdrHؘ>=brfi:K++&y(<P2Nћ09Է'F85JǕ?^g>6Ƞ=b[757Ct46<9eMm'Mc/$3ͩlLoQf I#|Xh$%3/[AsWBګ}棉ENS?$,E j>f9ayjƈwke)(Р-Y4&`8Շo7lz\ws㛹t@\ɒJ_m}GA"$.#7_#r%CY5H"/$S% i=*Q@|>]=q ;6BgMw Մ?UskYA2=Z@?'j݄0EWy.OuE&2WɤX!@i=ap 8=LѶ)40Gy ]kyG0jq`<ËPώ`/8%[;Ӫ_ V4RT W3jnB@Hy`2Gajgw%0 |ɼ }0>v8KPWP)jQ-lJH OŒr.זKZ9:93 woި[;HdɄY|%Hn5rZ{{ry jL/i\3(G=+hsWv/嘂\ -q>4z3vQ 5rvm3W4}l2 r{%=Ϳ(~lW˫$puҤ8AV: Ed}3B[԰{9w}H85qW9sTx,g+|;4+4R q0mMD lM@xaotύ/4~Y+k45%'{;YISZ_#Z; cuJq-\a!epJ6yUnJ/hA#8mjG/vN8gӺ87ʉ)>Y"+w7>hn۔_Cx2oK`UT4r˔IWvF P099~D"t(R:ᙓUrƥgd#%YٲSr8=;"8ąpU +{diMd2 ٟ~*힕FQsTo*SMl9-EA;w Jν?hz4֔0-ވ<˙!//PLP*8j#Yo#n0wߑv<3%#}B,zQ0o`C6a%vi19ppj:v`Vˎy%HwhEdK?J_i$($>Q fy*ZGC@ -%BA$iSsI׈3t-gT+q*E@n5\όK9xS".7(!` *rL%wTENFMH 5-~=@fzhW <:TaYsaa` >ÜJ' &/gnj4ZeFڎ=[sD) _=fbe__TQ;yҕ 4|߼DesY$+J8X'm[7yڛIM0C「/| (8 C# NڽS;[ʞx;wi%tݓ5 y:*ɖQ829 rJ|rR,]MU KX]X!{uSu:hvl 381*B6͝b/w\xEʩ\5cU\_Zz4xmȼ_X,8\^U}04Պ4)mi=yOKyxvM͓y 2QZC>kSx4##&d2~Nyv:ˮؚruĀ$; A%wc3a.w}FAE :mt񓲟ܛ-5)2).nAf H :*~{ze+G `:pp2j31K Z=J=nB)TeG~a_ Ӊifv{;%/9zPd{C*{e0"抁(G"iYtali>2%L^ڕA8.sx@z@m Sl4 Y Q|}Mu`smBWC]n;K,sNN91msh9qeF? %{C^RťZ ot&ů3@?(GSAJtC }Hd]S8C4MC")j^䋀Gx~ HlRȪ#豶b`yHൎ FNXF!R$}fqY1u ؊ `i4X?Vtđ%S}]aAq>`$)(Oh%~OQr9OE1+[]./X}*Lp֬s]Rp9-73AOowZl0[nGrb_UIWboST2-@}sCGBdHys[36aįw؄Yd Zx"GrtaR6OeP'h'Lw`DR1e{ RGBlOE:?@d2b-̴Xšc gيqqҏ > vC KeA'^x׫ EkRgOmnٖ$,|ؗOz9ՠhx{d~y2uuvMZ:.. ( \C?"!aLN:~G[Xkd*F$ߖpVgh7vI>4Y)I_C/ѾSoR%97<`=6Զ=z5q谦WVc((IOEyw5|S^LyhCS ()bw/?ۜ8[v@)O}F,Ҙc:@*:qj%a-`t_nbMbN>'7۝0<ntq"Tbښ !AS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPjX$:44!s䭹Cr :@>x#4KJ7tݟMSSp0o@G)Zf&9,0%W6 ]:[?A.u%@{&1gD Z6LH4+ `[Gd،3eLq6rdJ/CT4=> #g6w - m%+YT+(uێt+~v|ʘ?x:o]iKE$*}wz'єIIE)2a1>6Ր5}1&1cHuCA?rS.Hxj:"m͓ɟ/܆Ek1>YνuN^j3g RU6V9$b_ZՐP$ah@XuMmb>mt__>?c 5 FJƟFG[;_ÎHtG&ܴRi?2>rMukei:>1g^`ffGКpY@v{ed3礦#繆hCQxu"ܬT!k;:VD_ՙPUq|ey ]]{P(ϓgJ!`b},y^us@P9/}$(p@(S3 mϧLrlSίUlӶ/OńK^F&{VNB54+&%x5UXE59/ K`l4ep6Ѧ 6wӒ+T *{fYH砐$(ŢB%8}UvP9eKe␘~LLMI":Y&e:t܈.^ɒnyo}7sy /Ǯ,0֒\c5*HrK짧6L\N.DjžbAA;2uZH&ˎgwavryVEz|Yw+DVNw$O8E5-0K|p.)Dl8 s+0OVUZEFXX ҷh` hg Mao ymJbȓt=3T?!,#j5)~Ctu<1(,`P<ݿ- AԳ d +'+JF޴0OyuX ojT3n;5pSWq Ki͉Uh u nfOkI(] ~*sRbޒ;FN"?Z3AJ*%R,,J;Dpճ>X\Y#-@i,xoYSTCiߵ/*_@{Hl6y!r{6܋K{FMlEy^7MM&AiB܎Ӻ]`&Pd)hjUk|Qf#eOTh^tvݶ;]c{<Bjݸq k!p C[h[wLm+Cڹx#:Almo ӐeL9ˌ A mvH XMM(eE_.X)b)ۧQ iȉ,/T41>_q3p+Xs^ƧIs~<&Ѽ[sY9DK0C 9&]:lb~?B~Ѵc ׫wIR^u޼|v8D_;/.2xFKp?Mh [r!2-y3feAeK^]`. _|j[KI>>%Bi\JFy[*1+Kٍ0<Ts/k̩~FAB)&}myϴh3!x6Q$ǢXKH)˥e6@ƮSLEpolR!5@a1@"mΑ˜[jW[HAwyňɝvq/ .kLɰp jЩHTH~lBgΤIHXjFѵp;R`&3a[RC{K)R/8ᦊiGZb G 6Mj;1uyJҰ(U5j/FyM s= (u .?8YT/,xgu}C0+`s)巟T& f0g*L&vm$aϽmí3' Օɪ$~hQz`73\7Ҽ+&৮1c_Ӥ"{xXx>S;CWJ<U+@UA8^DDxN L#=D.q͎npjT;.[DFx\/9yfChdNt=L8'N-)W0VV[g1nCj"1nƌL2]A)EpZG@ g1@`vj_ bz*djyo(|G>#&QgM͍?wOaϵ;Ze[2VjE-J͎MP~:!S]K>߳}:,n)>6ShC YjErcpЁcF~J1U'-RR?C`.4WQ閤(,.OBtЦSdٸ̵ĘvjO8$R]`{z dc,|c+|Qi\{.rly2b1\ x4m;{tqi8CDZqL6pJ26)maXݲ13s[oJ:p Ł/j?"C;buHRz%؃*Ws#6T[G2zNc ďY$ϱVxaO$ '6Tw: {ԿapVJAZ,V;.yR + 8:ۏ)>n3ы9lQ2u5[mݏD$KLX8w˜Fѕ&&^g 4í7eL87#m RJk9 xcDMw_BL ٰO UE Z q3Wi.-?օH4^ ,oaM?zޔ~kÈ]c oA"C&dI;s<33~x\1oȿ\FZJ\ϙ(~Oj"i`N9`Kazߤϗl}sEfJBtރ*vkֺv41+rUx1^~I_/- Sג5>I7$/I lX[*BympEpsriJ(8 xkX @6 fR_Ԅ ACbU@GbS,3EN?oLI(m| ŪP Ԫ?)ɉe ĹiF..b 7'x^hr|O>P&Hz/(I+ j?TmJ\JqUzmS՘7hl߬8Zzн^n^sWxyu@7W*U`DY:7-=2ˌ S23:`olq}@Bz %6N1mɢa *7<>m"`M)^ŝ9L^ ps"=_暷xnk>7ڕawp4uniO'w_1rm[^Qm"k2r;YdDCKD- xN6-LRFj\\~eS-{KLv59kyD`pPI+ )0oi=ǔ D<lqhyLZF,#1]أ? jKHT3Et^?ReMGW7]&kR( /g4bcT Bx<.|V!9ϻj߾omiТwlۛtgP@QL)߫809"~y aͭV)02T, 6vqF$ 4 g9+B'SI哸n!Y{Hy[X\ r I-XrLJl,3+ۡЍOWfŽp#ns8Ja6? * Vhsډ/-mtx6Kܻ4"O kپ y-o 910[H}eVPFiXa3^x_T3GjEަ1 BODnU gadnRgĄXF[:,,IsO?=*T@!qC$fNNοļ ($ `X|>} 8ad2r$^|DZYErs]=YUXu%`'6˩]M)rmwwiJfke]{!e ïg[ļw>s xvY(8$j(j;4*a8ldI~2&3;Yx(3=(O`cpFӚhm5N^08Sάeœ/8O=z?`UT2w c)TmHnp9x9l \=pZ΢_.cݿEL!`3\ܹf_]c;6°hm1@ Ȗg.*%F"ӆk5c&9>;+(n_y6L=~JТ~N2cEV菁!:A 55ؾVF\G#~H`#x1򦵂eO._}X)Y=5ABhWvp4 j*GKqzZrXzՆ܎u$16[+KV=/.ކQZxLT}իuVdIKYRQЙ4x'?~0X;$p [Crz1"T` |q4X4pujsvzHc7I0Vrjۼ)[+*s٠*TG7I|!Yl9`}9>/Bw-]{ʓ{Ȃ0'$ٞBQDGTtQ9q[6zͻ—fu[ͅL¿OaZ0̹cv*=rQy!l޽޽~ pRw.~e }wuƕx$uoNT]{Md*n4{T|6hY%4AjOIWP&H\_#1#CٙA6Dzl%.L 4GA66|ճBq_TY.޲C넡zjF;odA^<>}ZFj'Fq+ L<&@o3I^Ϧ-1JY5e[knk}R_A:+ r)Di@?4"Lh?LAN =,!{vV$tl i;B bFw9zm9Ŏc '۶Rw]WY!͋*A"D_yUv'}}y΂4$5FqDRJyma_A!&Wj^1VI-IUVTb),} |IZBGG|rTy;~RqlYnBvxMk;zuwTVҭdX8!G‡݄=g0םNYkHW;l_ 5l }qֹ_9ސѝݜRoroV[F'O4QQ#/RodhoH`Ǘ|(*E܀ 6^TQZ)%1Gm# DR#C b]#?#|{ Wnӳ7QVD- ~a//J~0KgCoÄF(+:֊Hk&lR<6dq# x3ʘK0?>ǕtX4D$ڦ]#n4o)LM&4#2R4l=ux풃_]TUw1*hىY+@`اA_=I:_zo|J[r5jH =-],fDC~d4u-ND :(kU$Ƀ< 6~NQ#PVpzѾ|N?7+|cXkPU$m nz#S*5}liT%益bն^ 7md\\Epj$@+@ )7HC3eϟ%yE@d2J;$"m CbxSZ- ĤIlj6Q~#<䮍?"7῎">b>iB. wvap_)Cٶve<Ed0VV_mB *@"ˌo}!N{_'.s<4TlB'?o P94z`K"ijvOd ƿ\a'bd>;'r Fiޢ i M)MlRF, ^ERYJܓ]G_9E\7\o.묉MN6R=3LKu⽞s  ]e$JqBu&\%˜􁥩u%lho3ڞehSY$VyGurt`-Nb{V[k vR>t]x㫠tT6R1yR´gMQi,W-t vbT4>!(!멳}3Ln |S)g$5A'|R4AFj˥E5Ύމ $m m[KL=iSCE%'n}d"}`\y%`/]IZ)NzE(rtX4[]/{?T=n-{BeZe/ސ|(x:0}aF|Xr|D)Mg ęZeeYKj?ۺ'ɝvQL:9AO{ZAX . Ӵ>pm_V#<=#q+uj?vonIfYCPҹ;-<債p$SfARnNȯ eԊq<2d|׏{!*p5^?9x2cQb#~.29 cs.E`b9krj2)ܘi6z )%2eKnwM^ug-I[,|NQQ<)99BƌA#OqZ|Գ.<Z,"\<кIU;3)^3殟=}hL['se:!=ndZT hj!hQפiKH hhP2]Ն2DJ<ز8w0OL/ꭓŒKT8j_!/zl`[Z&h+Nki,K7)yٌV@ Tzf6LÔkAs¼ ˕~hl}4 -?Թ&̩츫;FIlOeM!ݹTo.7f,*I*+fP`o 8b %Q [*>kRvTu|W [pYYH8kϟCzųoepB%9Zo!L C*'M.= b&/rsKGXÙ|AӺV Sv(Ec՚FGu6ğ< !1;-lg{> L@ȴjɓdU<8o^y]PB$W'xmO8OqϏJ= 2\~RutLa1G|#|@|b\pa_wI@|jY[jwa+lL^cfȓ|;A">c?u:#w4G7ë)_xk d2@o?<-&@OXiiUg.bJT7m@F4G&D.&F^Z UصQ=\Džą5n-%yh*)Y] ٻy9*U{js/?%G(tghErZd6dOC3&z-jŎg<|9|˞)[ٰ0%w=hZZAWHt}Z7ێtG5U<¤aΒ^JFUwUMHo`gFA[U=:∑6-={bQ% Ļ91(ݵ5|M1ŃW^4jYcM![ݙ> UzD$3%.y,dr ɮĊ+!۟H!z5;8,.M? G#+dpO}N-5$ hoRYA"S ],E.WS&"}zD&7k_&C8#&1o%~ 7/Ƚ׉PqA > )Qј :1p3 g$z$+Fx<-<,`X4.,%"OIǟ' |[T3S c4RwxC0hFsl(u/L^(FWCY41lJ hW}znnv֑40h*j1ɉ̑%) )D .Ue|f9YAc5pkn,W/'lW%Y| K|Ws_%}gϵFە`έ5~TMc?4>K2̱tVJKXX+IQ]A~VR;c243\:żq[ST݆&^?VJ?k[8s\0(T;CijhAz'AVP[p]K%,n[D^ǀwʣoD#l` B suGY)*2q9$LXH`rC4F5,7"$Q^>]Tqq}2 ?!"\S{%"a|~mmW?ȧۡqv\*sv jg~mD{%[TЩe7\4.99K 4H[.V9iJI tܽ | )&Jn- :.NUFȫ;⸶ 6/P@WcVy0~{h-Jؼ<rX׽ 1k p(=utҦ3YZ|[2CT6`\O޻o/WeTlDb8N~WLye}xH'=+L.Mo=`1˯/_?~0/_rzH\u[MGO5}PC%U)P V6{+&&65%KO] u{Oif/ 12 ˺WadF]HkfK:RUl \aK ٧Vz)Ԛ \r6۞wB{֬Uw􆜄$LD(@|Oǀa4'0I}B -+pUBK,84]& I\3$.3a$3IqrU#L@poO'nTYw">}dH0ƗTV#e:[.1s}QNNSX"e<WbV O1BuljEH$Nا_Q؎@p[1@:25S4I3>=0PUѼxˑEjm*a|0&DK+AcV]ܵY -9\P1\YKi]{ XkKPGu/ѕRhqc+f\ -tIc7-cT=d?A#5̔>4@u¾ٜKYui`>rL-4aa7mуVNx&$/*$"JmWjA16e+ rf E4 7`O4{%N&drm t<LZQq̙e{wٜԖsO(<*0I 96@?7|̓EN ./8PNq/4̝͍gVG5$ M#ڀ>%7CϢ˻ &'TrSR*O]5{n@ZrH+뻍k5wDN*Gmzz"-d^-|fD2;r4ԘCF T (b_|8Q0_I`lګX$r,_ JFS*p`2?Q!aIbshiqĻJgjk岩'h(uH $;l2)JaMʰֵd-XrrHafa+:EϲayoC@( s`m(0s w83 i:YvsĵMj%NZ~*ybuJCpzC K2xLt鞝2AIf+et9)Y}bxZ\*e*w4n\ʱ'v-V&\#p B'\f+8!|y]C2NږU#L16 0# O wΩƒxVXvJۣSfWm]X?9rG8`1gvg Oq tvȧwMΛa3ISiQ'Znb6ZU ;Y>ZO(}¨tHW|z2OL-ْ Apht)&ϴ\0MHK+ٖM/4=om˹{TVߦ>Q^XO.Qdf€QGV(7V, r^5 ;e8#u"W9 adR}k=fVa=po(־y=#M[far Ö FZ @YYŶLj)%-WhrP.k՝ G"Pww ŊrnV;Y~T MgPU5Aw27¸~HMf*IFs2- T%ee^UxC>@*4!୧w]})C`ahA\Iĵ[}=֣!I`E6i \\aD\C:E*(u gO?32p'ur/^By.b !(7R)س8PsIi "BhS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP:Q&Q8hql|9X=`2;9Vf8 )h|UǹroH$ M3ŔGSE{ngB%)3f<{ZK;SP# |*|;,|w-2[<6{k>{L* BiO$宊ސ)X̼ PТ㶏 0 yų 2Rͬ-ZIl% ,%N 螝vAQ &Ԋ}>bh!zj~*o*^!cyfi|N%mbI,X%w"pasÄ;G\cN0P;=ƕ}x{U8gIdBv<)q]%%WS`wcu%,<. =˕%ԔB5Ly1m|m<a+OC ŝ(@e͆SNR*aQ3}܁p kً7"z_mr}m.!ZI(OG &AμWxȯjV:ɱ_zŁe]z-oEl^'|^V ,,eN乘r]oс]:)Hչ#ĝf|@4RB"ǩcXؼcNV򗣼 Yj4z2>ўk$(9osR~ .nnݱƯqо-E_̮zZh1# iZ 4e] TRN \0\~#}8ٗse.Uu[8Xz i}g1/V s69S L|Vcȡ̡=>V@$ҊHn'X?' "&<1;RJyn8gOC029:Lƈy{q%J,W>mZMs($eo NAAF>x1ׅ) IB%Y(o4L֚ v/@ƺD 3E(UN>Ky NoIMQAIM[ W6N /ɇD>?HTT,6 nP6;',=U|_h _U~O |,M+>X XG u~23Sql*ʙTAs{uk3ty|c.B繇G~6DDJk0kl"SOжޫ-?/­tRYvk4|o*QɑGQ(&KDFMyvc7r/תg?(DawAϷaf 2@ӵ3,n":jBT]Zl ozp|uk@KDDx ӤPO +2d ON+D#ii;1cN*y4^\cPCPh%KAL]i9~9&)"b\Yr5z 6]A+KI"GU_mI sO"H9z?a}hCC7&b,WG5ŸǬ(M艓Y!4@2+t6Z? ̦9\jq,=Xh, :ҙz ؙ  Nn|B( _&ٰc^\)rg:ԤEr0qZ]#jnmVg<]L=qWwG7zA?/$ Z?Jp_hw!N\ [&!2dΉ^YΡ=\|)#`tSF7ϨL!%az緻_PIeCT;etH; W%f0ցH93ۢ4քܷʼgE9frY8yRXM1|^"1HJ>v(nF tQy]zFJ (Lbk uX,tx)4:zۿ X>gI{f E$]-mY_4UWաdtoG88I"έXN}b Ye 5]%6f*U8N 7NMUut-8~%נ/ vBk)`nV-G{S7RŤww>2=ňMnxvkE!(Wz[1`Pg&r^GnwƝvm_(*,e6Q>&%i3."&#z;28j XVg mɆ`!?(d8،; uW8пAm̲M 8v j%CdbwIWA_Wz/5ǰɘ}i;ɯQdTw6ADT- N\B+?Ͼ~3Oz,0dmK\{ҳkY~Y?T{*+dJFl-L,Oɓrʺgtr@|o4%pyJ.[U_ڰ(1Z?\XeQ0t[*vvZ?U6P 7"^gRXYJ;B6j\t^l e|e) s/mf` 20b e ܖEĆ*8.t w/, &sbdTR@ 㰘ԋ|H;Z 2Q*!aP9$hֹtAq|/j҉\W21v2n`WԹa/blOkjޤ8>vX7Q|h)ij_~(Yv?~dro|A ~ugְL*i]' dRy'#}^sҫ˴黙aïbQ&ӊ%g,- T@hH (Y*ЛbT y2Z -UnX^4#y/Ԛ +\0B/H)PۦUWU!K(O^nIQqN@H5!{>ӺniU=Fpp%J(*ř[K]12XWTlAIG.MbYR\YkUH3x`*:C ,{V ds n>)%&f""KyB;)!{N-UR[c{ 5T+B"eIW]A2PFrwr>y}HmXt䀑j=5Ki2Kg.)dbZ yɲJ=A4MG.eJto#NO^rƔvLiXuE@~j9OTuuex~gT!UoMd y4". s.Lh]Kwȅm6x']H? ƅ[>ËDR5kُ  zKQ( Bt\3k 'ʆ+yKqtԖe#=Jm!MH",gI!, a"/8 /tf3)з߬Amm YF2a㚸wrʀA;Ovx̗z S[dck ΏWUX**qz,-MqrccN[d L=M5śbx/ep&jY5HXkmR L϶ž0if(Fł6RG= K|Bi@Ij\V ae!~K#G7Tߦ7텇*sv*b^̫%|OՁXe/kg20bc:p mcy<;%(sOYnU|VEGaQWGt&$M ha'Ceh| 9b(gdZKQ+q~]xYK_(9}EN;R%0&8ŧn%H+[aN:,$˴lR ";B9Vb_󖴫{̷^é ဠc[0,^& ^ 9|@|@>@lU&^?0Xԣ6@@yl+LIT<+1/i]^ZXt`i( 칄 ȷ64 `F>7n.'@ ۞ ʗYiWQ~^_>=pZ @#jW*ZYeLoPFt2s_!K"oZQBŒIvUA(CEޕG_>.͉bUwQ-x 7JWpFs bʀZcCn*7 4}F|:x''CWsoxL,OD;,P՘=JI~C|hNQ5YaWĠ+_\mEBon7aYiNen|Cjf"ߐS24  p*~+WmJQFjc gh4Tjaj*@VZq[/ry,z!,Rןf0c'-էgEv0Fп|@}Z1 -/=-Igp[k wC7HؑQ жRhrtcotYpKUIkARi b) o5|5-[p}MB2ZJxfKW 0o1?@8H lI6yYګ:q.<)jY%Q3z)[{k1ݎ!x]s)Ze^ a UW|gVyWSN5{}S{l@)-RI`d?$/;XN?<~X[ >ys]Tȯm2K_16wwtM9$qsh%ߗG#H\~&JW?9 sGzX(Y8FE)&”NI1x'X]H% VGm@g_/V%_0Obbn26IV8#MU[ۄBU**obo ^k?uTD௷.&mG! 쐹$AF9t֍fy$ǚzpИ^˶HZ Mah WĵHHE_#E Om6}E_Ҭ=a>X~5J[ ;@pȷ" }F ,y/K2D_nh;_8òq#-cv2uݪۻϷ (Iv!|cqZi|40En0y19_1vaѴ<1*Ӫ 9nӚ=^=igepʖ>[fJܔNͣk:/[ؓAVB0C7t- 7oz*7nw?n(&)Z3~@:|Av $H +U=o~-ƅVR"L&*4=C4ûm6C:WƲ- k2f`mԙӔb,Dž2B[2l}8i'AoBկV@&*SqwCϓặX<}a-nFT;؀_N:/(n^`O1byb 3Sy/?G~ y>X?E~|Hh6@j)Zl7j/ؘWAI1b+T7O8k:9RaȻG& KfWfmϳ[ BLyV;m`:x )(}?%b;ϭp @FpzTxBz&-дej_Nur^X)WS$}g]ga 2FsfP2T՗Ȯ,dFuF,MK}1LQ#v(`ؿ>JњF RLnxBrӘCp/b:[AiP-j2Vl^HivWUOgrnyϲS zw /@CG؃ 9b:8+8d^D;17'ph-v@1,i3^{\yoPz-$=,@5"wS6 hXͧ wFv09"t ن3nk;OF &S8f l oA,ISgOjYX=W>oP0@RWIpԧhv \¹WnFx9P FwD)jYGl#)1 *|8mrb r6nWOJOgXiӞ[V֓,8%?%c,{7ٛkFQϙ33H&JzN\S4QݥJ3"Hۤ@H%by PCu1<, &f 8#.fwڀf酕({empE#nyׁ SaQRyW?{ l'KTh6 `2 ?P<RRsIV}cѕ$Af67Mgawo`Af04Y(vDvS AZԬ"8x/}F@AȜ:}]*NLځS?-فHO`J_-_ojx_5N343*F'=`o;-"@T;K0J~NO;ĩPNmr8N*!ŵ bRzA%Dլ3hyP) =Y=^cMBy:77XIt.9{_@y4Ӈg{:3IX#{];ޯE:)< ! {eeKʹ6ОYіE$Ñ8%]{W7jť7~\˨S}U:*ѮBgw? _O:gYj9"6|XH76Jyc)DnR7Ixvd®F#LEo!:$uaAXU1|__cNM>ghB3\1>k\h2hqFluFJ؊ e@L!;H3Alnϊ';?@z#{Ma6h^!R&Fsw^Oi˔(aW^ %B14f]QGO89v=ʖUR#Mw+Cpx,XDHa\ l?@#ԕfE(<#>; />E⭹`z M7=-1ݹ]|8i3T~ܶIT)Agr٢ :D]> h1qe-}J>`e$_ۨN=w r-xHе,]`VcV^k)*m -ayim\V9}>}'LP&b?u"DTЋJCO5#)W>ys #aꩮd%9s`~DR! `p1 6j6>No"!C/*9̰f=uØ)읓7{C[^~m5ޒPjm?Rk z!Em=II>ZZ)}Ȍ 1ghK"|e`b$NZ?BNB0geuDI9}ih (!=_991ΠWHÝV~TBWV\/n,󰙻щ+0FL+ǶnrFJI֭3ԪNa-pyb<*5/02W빤E93Nm6z ~8:q3l4K qŋr +߂r_P(IArWxڏ^ϗ`NtjBQ9ƺL L1|0u{wI ؟eT|@||clRG<_b7mE4?|j!bpq2 LCpT@ YYU$>y`|nH~v5K{4|KqS`'Y%vC7[K<1_z\CvZV9&V>=-.OkL2]190f?!Uu{C"ٚr,OF% t~}KTU`@}`ru#Z7FHdhâ@H>qMwⲱ5t#v-@w#qN! x/Bޕ+UPU>1y]c}R ty-<}րlKW+BȿX_rl%RFA\ϒތ~mÜ+͡|LE߆Ys!z}2*%>̢%od["s]0m  &%Neag ;D@BR&y%'&VH~պ0˵g0P;:/T4c BE?\ȷ)ҎC=z,0=[QB14a %`?߶F>f)^[k*Arx=`vV=ƕ NC;H3Eq 7O6\.}POwo.w4{">[ߔbqk$=OF7' ~FyCm+1 PH'nݑ>X;P2i0JTi(Z$h{Ha)_5F,@,YoXx*nH[RgtxZrmxN`ޔC"iԏBcj^`-DrcEL%j柦 ˝v.Lv?K wQe$TA^mmH1?$P"WUyVƿ8ڋA<L}\s{D6 $?DRĩ+q@s(D>]a뒃kتwdI~Mb^|桕 6"OCU r`< {c~ :~򳦎Jr1sgM>.vW]жB)5۽xuЛfPubX%UUkΠ9za6 9#%V1=ґVӗ[sr;kAӚ.I.F|Dj:68ro,u;.Uos Tcn+yBwL&Mm=-E."EnPtjkblDJ~MrV' 5; 6AA= ?x*1^ojjZn!P9}wRMTI@*N gpN>04v̩S+M訉JC¨3ϟܜҔΆ^gv'QY6ft?.D77aٺW#1\g~Kixs = Kg.C㺱t JeӄAo`g{_ W M.+7^)RAxcOr{ԁ ho^Dj4;'msR|kQǖG;D SRiOi1VdR*'ԣLEi*0Źq^h<]mцc}i$dJ9h8tY^H_=BO 8[߅*Tm'aeH.Bi).nҾ]ևNE``7g9W|rEE;ms 2*g,OS!*8 \Hz|*'[:N}.(HԺgjr˳` A4}a @E:*%%Dz_Y%)GZJJHѫ@iWt0G?)e]_pft47CAaHJ@z yl{I B%R֤><WkWH -Iȫ˻!a}9Df*S2L'm"ev>_A>mzןITd>_X 7jNRi^CQkfP-j~6BXvh`%k-iؠZx%=mĩ> 4m:C1#-Ly w_n! ZT(>8>&͕ J)gL_/P|I§ ~,nGܶ-}6)txE ԭ 3d|b^˹fNa?D8!f%E܈~֫|o}ЦѠ{e? &!K˔ 9g:`6ܕ.S NDrRL<.=Ȭƀ_]مu\ ۍc˯Xm;f?'9B+W߆$ ꀠb>\H>IBC!LNYis+)JV] $6u>s$_q֔GqBᑉg4su,BǪk9&m요-9j ZNs *ux31qٻ/TVJP;Ą }ezJX;̪1Vtv۝8, 2mR|%&j~\U_kψ4H;|fTq{zg MwOʈ~^~"QCu-W`[䋦4Q(4uK})A5VyI03]ӄcVU/h7{Ge=?UiXN>lµ ݸ䯿1 t"^qׇCkCx_H-ŧ2Q[ g¢!Y '*$^bLUC1=X_>pR\hnWсH1vO]s0Y \YˑK`a0P D+iL%Cg^C˶ΦwuBc8#-?'fj9K͏ak8hWem2הRAküNRG2.A]a 5 լؚ"UO) UGHtDV H C!{+}.&AeDҮ1/Tcj{R{!m yY] 1(A!vnf f!Lqİ|%0<\s_Y1SsfWʨL #B}S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPPM =:4|!ĕL"a,| :p@\@W N GȤ[U\Sn!n7gN *h-~rdxh(Zā!o|;4|w;FgDIМg41/WUY˝W#ĽǁyaRsf`,v*8}rTE:\؄$$zAsNr%b8$R,2 Aaѧ,< ]gLVNX{8 i¥|N!?![5Wg<%$/mZxs#_6|dlb=蔀 P؞9tG ϻSTtl۶.?t(Jv Tg ydǦÍA 3`υ ߂J5%Ǵb_e_ U~N`?a׊|m@ssӕ,vVIy>SAC'N!%eadᏸ_ǹJLOQMk$@Vg:k/hf[JMՑF%LldEߎkN(ul*HV{>W#3{cGىl[2.z+|R%5J݉莑(1:?J3'%:\-Z6\CSv?jVV@NqcK VfR Aqf1;rM/#;4;Qoyރ vVHTzkbn &(R,v(EnrQ~"l8`lԾ|_X%bb4Dػ7fPn ?KCВR)@@MW]E5B/ ^eѪa/,\`F0V`8cǀ["&܊|$c;{FOV~C܆ )q EBm#B}촌f N!4b .7b6,fșg -2, v|ƚ}K2Pz cGvqWh& TbU-<\ e Yunr_%)]j3 Q{|ĭ޷rU&zSQhٜ$ {$wt~2Й剺فNfr]Zvdv.sx 90~*a5 ݣӳG}m]!'xHNa0> U8rA2~\<>Me:M[J8d_ sJzɫZ}V4wD إI㷅Ѭ{T㑧-{L8Ⴁ?퐹ۡ9ؔMBr}5f;AW%!v`blz@ѝp,p3W@b%sueI ]wӹaJ-:ECΚv,ҥBWFs) 9 0R M/HA:y;.u}[ʟglĬ*sO2Gu7iMhJ[-/Z.fbؠQ:1(VBr~M9>XfR |+_F~Oh_EՆ@m˾r1En̨C!p$8qľ=hAmw9zٿ(#4Sj4Tu <8u\uDZRpSp醣΄gV|?ըxWiU;wۍ qP<0ףGENօsN0_,+9GTeVz}`XA\] +T `l7x`%]h'~"¸L0RVW)A´/q(CÒY̹CUÍ'7K~JCBri])jꍛA?^RYV057j;>,Y_Y;A" [{ċ&-vrl2h]*_c/z9_N⥝MYߛAEw-s-p։8Pn(ڴm4/ RV`!om^"Z.tU3&@&3MV0^G~np*dP]]LqΧ(CqxvJ]l:ti>tȶ$c=*"Uܠ* ˫JDg\Wb✋IlI=60rX(QF҉N:unNM Rj&BmSSţ;%[CLDBSՌ ȯ pd k EW$E4ݪ:dQIL^lg"+8[D,eȥ3W ?T}ٜ ,X7=)M\- =Yl3fѰYn}bݕ4Ni`RCe Ѥ{}[N2pс#\iIle0a@1ikBeJS"薣3[ m5>3BٝNzgF^/a<(>VvCԸuۄ晢 c#?)ҪWZڝ; 3 L 卟҃R0mX)D(E6ӕ?UΑ 3Î,Xo(P9 ƿ^3D#Z끥0]ݧIGENCufR=Zg6VqL#B6Sn5ipsgUT|Ea՘[V%=_o&xgPG3?NzkkrӒb. XgB0&vp ˫;`oKj}Ὄ{nPx'Q|oL7Љv,iQH$lG/:+; ']J=Ŵ"^#D}o=%>eAᘛ^@Gn5W.T:|? g::vć_Vnocܙ c}?;w+y]?;]1}hp =eK\}ҴTY~Jd1GJG-ܳx òf3+7 %?\h>ò O#uVq[f6} e]'z`@կ*D;E;(Yp۟ K~H&USʮP;fp̨$ '}*g L|>TIEW |ê'u)TpuRyc܊RUxO59(34>Wf,Ϊhn5↎Ak@KW_ $ߩٸ l;T$@ᶾe+Q;='=O~qӦ85֬M/?&aTzfKt sIK" RCs2sz$f e+0̆0*G ~A_,! GZſާ@h{xqHEk*D ȻMz'g]9Zŝu_sVBHc2K)Ԕ0Eyr1ɪW}bK铴e\s-STQ?%(I la =bIfm"ҭ;nuV1lߐ%B/z\\#[.B?(Iej̸_s[+7!*ؗ/]‡Tm &XÜ .1sYVy֡'[Xpy Z"S,K059!@L%, i{Pc~_e®6Tci#SiYY6NI6 MLuoZ逤ҖPz5sq(|n2y]zF0d,W4́NKib^@š&\>َݑ8Y= .tltPˇA)+FZ|A fCmڴg:fsC78wpѩu(Fʸ"`.^Q8 3yM µs:~u5RSA,J]coT^[6@ #?ȴ-qܟ_OA<%<|0>4p4dǙMeXEdAVw< ?/6Ӥ%q^KE I!WJ=i!,кZ| 'Z7d!'Jy\SWgLu>=%`bv](u1q!+Nk1o÷gHso+24 .7y fM Uw1*0dnбdiJ5վwoSfylU|Ì[ _~+ĐW0HԬP [9FCIFRtjB].&u;* ṱM2bgd& / sh<ݣ\T,dmxo,iIi ^X^9t1:CLGg 韪*A,sf1gMe!iY< ,vח炙B${;m4Tmg&9[Qֈ/^PE./֔9GQ1l3 nY!4)Ҵȓ_L"cFp[?+x>GLsM^7ږvBg[pp|Nssa (X_"E{T_]v7O9:k Kvsf5 ӱ,џE¶זt>E^;[lS9MpU>h է5le{ _;yG諎_$cv]+lۧzm_키n @D 7b]?g>h, SF1Aqb2sEd*Ip.n׹J_Gf y(_  rt_|nr{e}}nϿgXZ:1WA'J\ 7 Mme'PfMrlIotro6<4X$) ^ԞHsamBqP,-̀e+藉"9Y. ȦU+L$iҮ fJM U/4(eъ`ư>R "M7k gNcs[ְ&^H(Pn1/p%J\c-(&CbW%,3{)7:yA4HUA^:B*b c]:n吥#Y `.J1{qT~e+hk 焙Qp=Jp`ʂЏ,4ɹZJebq6v3:C!bAuIɼzv3.U}f0q͓;at _Lާ̡|5/C緲eLgP )[f:XlIN5"8H,C}pLH;oȚXzn k@>>gb DP5{UA0đq5UlcLgbMw[aQ 7n z|*+;w2Ԕ\礤Zo/RvtAQDLpY?(gww [Vǣ?ѹ$fD{h[px~-o'"~Fu6ϔn $sAGҝbs?A~?§߿ހU}m32j@K2GAnt>"Zs^լۯ-5Y!@p0?'Z綈kq0aUr,$j:*듙Rח 9ՖՁ7YnXp|Z+o*urpKY'NҐmV);޺>"2kH^nfdvďWc;tqנ2xi"n#[ ۶[6y6]Z267A3>2}^UzC_Monp # +[qǖ>VuA㈫&po&c4dfYoqDmbP[Si&ObKPSHY5~:޺jN֤ɲPU"#o$8FGb{=.Gn z"I}_t Re(ي˥G9{cْz p]߅6b `(2许Vũ~/0 йvu/TᔹتM.'hT}p܈?;yH@z.qUD at;F86.ÛE*9jNxoL_u+HouLd"ptfd7I8oxѠe w <~/5R/)xvvs:64򇯕e=<<&y'Z.f2A UiTTCCIck6UZh+ fKYHlخOd󻭐y{Yk1*2:̖ȫ˳O)MEDLwtӇM ^􉄹-{'jhUJ#c[&_j :M |,f ˔6ݮ0CF:3L-?祥qho9ǚ=BЏ/*sxГB2HtO%`^$x΄:FQniFH;b1!8"&jk;sUUr5fI(I~q[|}s BJdu AD5Rb)rЧȏMt#o$(g0diXz!M7ԿplYkԊW=:n_W-L*?O{a)6aĀg:"kE,,6Hd2ªbSg}Biyl,+ʺEŀ';_Otl>y_iulx AP6"ΛU~g1٤HQ?˿q^t&$/u;V g"7Q}j+Mn^nNuP&@X8+b(zΣ:U=:i"K Hxj9^LQfZ 8EZvw`SOƓe%qqDtyI'ql^bc/FW #_V 7(M&6G8|5Duq}pԶd䰺JvZ++zϨix!clX?'Wo<qCy~5]tx f4t<n)j2io Sw4žSW&Vv`W$P<#"3*((ѽRX fY vSZ\a\[h.sM%gP4VoUw`4\ڇ\6V%)||ߕ:&]&gbsz粤 Xؾ;c[f֟0tI3+ p?5gjsOMf`:c!Wzb8[1aSKZ jdt/)y0#1leW(P#&GtY(z0i)vH,OnJIcjJJk{ZupC =ЃWL㉇-*\FjZ$+{ dSX $ZLG5Js^ĴKG$|>_x*N7j7ռ C+Q|oNF=Bk 1FBҰv֭ٝh3Q6dM:pj$?ĕk=B lYN4RZ)noC`Dj)Mmc ]QA=AVEK@rYR7Ζ>iB\]A ut=IXtɊ&.O\o<M7Z0={y6 ҂;wlvKeXT9.` P×Ln=.clvGi4~Zc+ yU|L4KjuUZn<2u,̆bdo95UDL{0 ~) aP{W]$~2}klјR ')g3D7'U %b&R qwUq..X6 GOhOS#G-!{Oԣ|ӑqfNJCoBo}_ۜ#7IbD==]*wsFa~8 Ϥ'yzI&y9%M,RY5RWߣаT {N$[̱!5$-d5 sln=[ :6{I KILNx:bMS, #eāxtcθ0ctљ>1pLCհ:2G8F|"Bq~ʃB|F[UAtT",C&}][skCF&*4!uS! ص:!A 8 /z?ZN4t7|f2fˎ8Tu9#wIayUubJvlK N$r`5E)x0h+HSl JF|kKfN5.%f  FeM1Q 7\yּy4׎Yq)*iIw3ʆ"x/fF]F~5Q3(MlG':8 Ұ؂~H#A, rHa.$?п@#۽[]_؋o"iW< +-zjeO+N?$wE/ׇ +O{hhY;vEP3Y_._1(es_'QLqeaPqhۦ/33G>;D&1 1Yo7'~㻠_XFX18#GW|R %ZyxL)Li +]OH]U =^q>2e Dv|x !(ykwfXWN# xb\u@5WƼgJdRHTA1%7^AT5,9I%mnNɧo7d櫊p)̸̎0׺uEl ?J0t'~[Cjɶ;6z!p9P>GұZ:󛁿wd9G+3G:4I@:EG/08 PرX 42*\e,`4%LWR"sY_0pߦ́} 8'ꡎGY!*K o*;OS wViW<%ы T*$2xvN35aӫ.e2^* t@7;yCiE-+B]4c_{]<{K"W\aYȹsW{<B 4ǚ4A"Fo 8F)je`Ӗr?lv =έ{w3%louPèSywz@璜.=p Ww qu$>iV$ٮ$49Op112Rrc-54 S9;٦Iϭ{Hzhf]YKed/t| ҭUI8;QJ7ġ% hrw66BŚO,ª I2 g6!A`U] ɒM#K]" S\Mp:8?Lm0?rUFqЕ@oM(kc~|/Rgl\8 xۃ>钼-ɱ=QʹkjbMn.ѳzQŻE8bI $@Jwmaaku=b-J`A졝[r-f_5Oyb[I#Q+l,a4n@a<]͜DAQ,$!xbfA f27hw6#ץ >r82^"7jVRd{@`_fe(y u/ X׼'r#vQn=kwԽ@N>eUy$YC.D_?YUĒv8 XzMp%rzh6 (-!fEnqRSD+4s7B&xZوn?:%rQY{~hKLhBgK>LӀv{ K0I lHE +BH_paQ qoj/G|U& m8ggNp3 褀0l)<UW&4"]Gx' =.#xBG>9>p' m0cU~Fj"q}!2 Y_^r) pT9Y¾ tw*FŒfuI+a0{L iIZ2ZI a7_AnV(Gogh~kz\j-ɶ?t2.lQ +kӦH3Tþoݼ냒,õVyP#@y╎/VTG6:G+{L>L xw9k`Uv'7WI+{1  VYH[RKMmao3jTDV:>ޢZt#ovA?} +>(LE2 ?{k&KҭXU5%-@@NQռD:C)U|G]% )x&OpƓqD[T. ktݢZ8.6P*Cc$Xlp엤:舌Wřmre | bj:\/j߸C #Zɩ 3S#B`p:Qw@㑢GZ(+)D )ڽw339!Al&TOHy|&togBBsUa}_)"AiLljk`8wK7@~7z4εdx2ȟyoʀzZٙ&=n )GoRF :ʹIT qA5lXz/>`&ګ'[)X?ǭ<є,_)#'5 a살뙩k/%{F0HWNHtC:wrm0 . ,oxՒt+aXh9နY*vUЈ+?T\uhF $B~S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4rEd':$@>@#hEӴ:œx{ה (uЍIPG}=XO+YXy(x+ B)y L\ֱ8" { 5|4@|wF""EKk x<=E&*eYsP] QzV˄)i"03g\ܼ'ހ 5yb|%]dޅJcn㏃S/8_ 6>*vY5@f%}>HF?>?:ʼn1Y:#H="P{#d$whv]Q /z-??fPEnP X Z/2M|a=83X. =vAh8 Q5 ~6Bя K. 7lC:Da<o<@E"K>Z7ڶWS۸%VcsBc?q0Nӫp}ݏE7"EQRt™=-6 .GŒd\yCO]J &ߪRڸ?|~!z̮2!lvmyӤ@GJ(2QBl~O+>/}9pY)'I[! şV|G'MJ/7bk[s$lxٌSsrxeD(wRSC)tN[h,/KHSR KNk@g⒟%rR( {A|tHbK λ6\\H %4a'Cp 5ףDT񓓘NtA˦.7*0ů@Tpa[LF#AbUONWyq"qg#ktz(=ئ߃X jU }d.e<",A[Vh'xqvKQ :=@*>Ӥ |CA&*g$B_]oڝ+4э^5І^p95::}"TʦyǨ:Ԑs~eos:˚64K9g9;uװ ClFcކԑW4KSJ!! H?Y.HSӃG5eNU=ꃠjע{O $]3ndW;Aȩĉ=>k)Bxg=%אָY|w - ]K)MC.vRQQpq )>"&n^>XTɟ>nBdڟAHw/F{W, X,x-3Fit̂` t^iGڞ` @.KnޣO1)nwSqQ0+j~@u\' ˉ=t(EOC-vՖxAFemMD&Cd)~*=}sԁkFF`324SIfJT!{nAj~ _W p 3 r\$׶HvK I]s!eu\=_ ҢY q u1;N!oy4oۣd)&ӻr+=̕sjk/S5 S"2$)4=i(|2DV] :D.U&xȊ k0kMxqu lFOvs)uy_OxhcO+Eڼ(􏧯˷U*EG\T]AoYZw(O5r3@O,ZoRUWm5ulIc&tO>N+FF=ʊQ_HBy<-Ǧxeˢ/;\t0hw(hTk\և\ĔU.(^U.pI^|Hz&n(8?ٿu 8BS#Z`; _7P'SR=|ޠe%vCC.'ߚ)`LT k @(+1Q}N}} D>P*3L?nG1A1|(J) $3+voouSX=9C0D4P '5?gT#5eKi͋H}U-)<@!hN4(Nw ~# BXScma0Dƭz!fI g\w˚ dv]65 >HRH $;KE| n\ HbrV;[z|Q~ӎmЪTI`xT$;8VՇ;dG\~V 0;d4"@IŹRCY];{s}X\lC ^^½=@-H@0}S?<.fWMjtPh({c,}:^ AfV XC5p/ #Do†L}C.kg e[A.D26^, G/m8+/{NM3M< YIud.2^^2&8]HŸq@Aǽ '*soYOcmA F퀖z2Wˈt878tq&ͥ??FEwA3Wo#^vCSa&޲K?4D<1Si$yVa ::2%$NH9uB܌`w -}GF1&zA*Rk9#-yӮWm7(GF"gϮqTmoahPB\)a~L&Քi FF .KH#"S2+᫚|S9@":q% O7nj;f=쎭wP fϺ?TOȧ  ݲYFG1SgӢN?)lX,BۨpPЭjH9,H`R MD puPBR'5Ї%Aek<̨~igr]^AzL|^1nbN*} b 2un=!;t BY m;+3FF|ʟ9wp|XeQ?j$ Οl[FxxBF}_0,~P`T,7ټ2 n?f޴Pj ~=9o.eƟ BS8bѼ\0DKX.fu%u8֊[ Ɲ_afvX("NLm{fspŰ6Fq"S2_XDtAb:ՋuAW)w[Il,iAWYNSvkԍ~ MiKtLMZurXs=[DBsI"zA S\;stbO/jebTXon/Y}aXA2H8rޏ( M' Yh1JY+haT ØmA,yMOd-;4e>gAAF*Z&ˑ,扉N Ǩo p]D'" jW`v`~{>ֆ<(Fbeh1 M>sX$L׫hD)pC̯roL TJ?jXԘ6o#;gs5d]yEgWZ=JV h1x9;r/{tz!!9yrpEosnq'~%$a:']edfXfGc%I `>ֳ!;tcF{bW]r[RCe 06>P@ UZf@jZWlјP|U3+opj07U VіaAx415E4Y,œ[xO%]'u'ȧt "ػ#ο,> ?Ggq `IC)T-g?RPI*ψdr羌Ãv:p)ıs=M,x4 4ɘW^_o_u ؊<8Jck mL'.-@_t՜k1g;K<.UI[G w8(&3 CbA!^L%,n"L8·vֺ{l֪ݐ@C:~<_vbt5+V!Cs^Ca-I꩑CDC)ivp d4KCLVLX\smSx]H錁(gl׉)FŠQƲT3-[d~w"~9B121 +Wst32py?n9.Μ]VΊ{p`67=p `Ρ;!E;5qx9 Nt-Xs4 z6x¸!K.vY<}N%;f RtPbS7Bq;*Koq+BԌ Ovupl uTZ Ūe,Q4}%FWF8hx@~< &@| @|j}BJMJ`&g5ܗ@N ˡ؉\NcԳAze-'l "mU*x4̓Tfz؋5?>=蠊U0hhuupJHsyXj׉4 iC9Eڎtػ}u됱j;5|#q\v!Q7hH;o:[R/⮖ BKK;G!+HնB|-|qSUGOPKj+_-ABJRѹv񨺖fLĴɳb*GPu ;_$.>*4]%tl[[*yvȹDZ1J'U> DF7Xy|7{L1d5?gBg+@{T}3O}<5sۏt`EȠ_֘D2ahKҤ|@m=tWWǺ a# c~Qqg4S_ G4{EDWů\Jb@Bܻ6g^aF18D2xdLR$ "kU#! +ķĂ[tg'tl2qSBxe5Н^.ʹ;A&Ѕf k0'se2敢uKc #9Ч8yJ:*tbG{'/ < S,|<؈]dѩw5ȝl5 !5" `XYFLk\EݣG}ݓ"jNJ%rbX^v99b*Hb?>^}v%q m{4Yhq7U/ڱp'4ɂALTJOzݭO&G!BGa" H_Ȕj+)z޴i>`$kSa_'Sttؖ`D_ LkEwYߚLpOD,f ,Q$`W-Wk$EDgɣ!}#FB"mk} MC>]-57Dkxnz\<7w5$#|)ot[3&MqX˝ As@fRXT`U 26>AvLF/RLOsϊ#ɐ&XBüw=QPxr]*0$tCMA:\8bBUNdPlu׻i@=H,_Px_ Nt|%2JWN_Qόф.*ϾӎHg$L t7^ LjCb"'@#h<`lJoVleKe~^T-_*$s]tkOVVn)JkЋS2E9vS7NHʒwﲣ\>&'=YqXegy=w:#I:j9oEh)6g.c!SX77sIP^gKvಱdbz>˃\|id(ѩeGItYGi)I[[PUn/9(3uVd <\Ԉ !Ґ8I̛bDdFJuJ 0 X_1'v;7J Olǭk fwvLynv:->+ƾe67OÓ:9Aܼ}d!i/{01A U;G%r\(. fاѿt[u-;HrkyҴv[gþ UE ݒa C9 d4:EHtP8gɯ\4:Nz*.B F)!6{:{ `/o%򇄯r0p E"B{_?hщTwUy 6muo[pq  B" k+?F3q\<|ڥ*TcFČ^X>Ha#:-UkqF.+t3|a%JЗpfT?о㊝_ %2glŒVr@6-1RQz O\eH/;K!\|ȵ5wy_tL(gmꨴ~vwᩀϝ1raQp{-(ܣ[ ۳,R}Wc$z+t"w!KC+̩_d"^wOn'fMW9/R~1 $ibܥ1"%m&:sd7@.?[ U#a>mz)-{h+8#\'AU޸deuR|ʂr/DF'y-fiM& u pXsO]= 1R2ILwZSW;M[Kj&I)t^zE# 5"t~W z :YLv#Y:u_&!]>Vjk3T 4u Nx^[Z7&s Z!e-l'y-ĖW2)xGtpvw^2 bX1DTh7 g&ic8 KQ rD"h,-HQ*n'H)~e`aa/4GV<>Y&?1{ NB 85yYGBy0yTHUi1-:$jʿg 1@ 4G9|g"AN+^%!],=tGg/Z[rɊ `n/./q@Wd.EI9Cm >+$폤J;$(4nN'xTw/a2E&Ni{{"ˆ޼rPI,b*oG|@|@|b@P/tZ@L3|j 4`Rh ͠is?RiP yRx E94>iQI %XH? cm16ݛ.'ہHm|J % pAXJMzd̑iss-"0ɛ]K1r:0)ZNYnNac#Y(p9 =>?Σ; F/kˀIW\_+.9;ɩw)C:Y9=$!sT5Gi_plcC=r3ARk*5O]d%핃4JR蠀ɾQq2.H/gW/xL ]O?.+y[NR 3|=+Yov@ld70 'yH&2/:@]tӠ;R \_ Y6o9N2E*mhm' +#zۊ)rUc -3B%j7Y|>}u**xm'9xSh*\UrZĎ %/X0ULZd2D:>[|}$A]ffͬ ݽ8i.f[m˚di?`=6!uƪHt~a-:~jo g#KkDgADfڣ@G!!gq$ 7{I89xvdGf߲k8 1/hX`TT+0`n4l'5;?_k,{ڛ5- }NypRԴ3x;[YO 3Np[tf[)ndZIy 4.]D\LV<<ړTZV[Wm1׆N*e(D/=.竲Sgo)>e$`CURތPV/;,(p"-U-}:T{* 5TPIUA؈j*''rTg4!› [ym_hiN$r%~ܲ1{8%"KiJW7tD٩2z]f3M"'bRCTl3e`<ՆqJrduqcGB/,]<(v|#G7 ]eb5:/d˼>t4<" ALJ@" 앿:oC-۵c)/|t΁TX]xw}(7|c/L&0iTTbgpR'jٲeqpUm^$t+6-uH ;^|OOtcǣo)o"ZcNOI-ExLs9唈UaK61Adsb0&gD_5Tأ޹13ub0j /!υ1J[`DpWv\TmF(;_`s/fXxѰfjt@v[M.$?C5E8ln-ҁIPI_~$Nj@8FKuc~y4h \v:K,9|hGk*8UHZB+=\f(f 4s F0KI7T҆^nЯ.7rlh wt/y\˵_sWV #A%=j Łw–NnUMV@E mw z@D?R~  P~ON 7 崠Y=!ˍa@+tMg9 gVWLl4^{|ߢQJy@՘[ZG1lax"F1')WTiZ ^"u"J7 ZNF!rnhֶ}Detghe wyR֚鄳I`?{շ~mo{'vjYRͽ?'rFTڅcb7֨9eJd^M%z-A\K]g&o)˧Pp#,0D]Ip}hKn*|;)NO Nc>A 麗e:X/1QwcHݏM(%LAj 8Єe~_Hϕߗ{ۤUD27v Hp;(@.o}'izSz|sD́YE]x1v75J&l*v{P|܄hmIf./guhEyط&cTF#OL5rpcN )%~YED%Zj``˅\ SLE-#4FE.\S-ND}0,B-t3Īr.1Awxߟ2Y%(n%n7=6dFq;VX}f> l)vQ*5K> P_BtU58^gB|ZRZ-ig# l%d&:Ūj&nS8 0H`q>ֹ^#y :y3~ч ĕO5@XLʊL&SZ?d~P$Gnj˶{PfP !־D?bڍ+ DxԶ# )`T,ǚH?NgjPyf9\=W;D6 s\JD*+-x$< =yuj$ yb r'dwpIh`R?lL#u$1PX+y.nЉnʂÁ xt#˚rb"[ề*rq/gjAAɽ|>j@'2q!2h@?@ۀ!g+[ L8Pp忕xlN;;"I2=@lyΧk r 4%gKe9)E^ >\YƆoJG12V~LM)K4aLX;<%' {BH/>+DcM qZ'\<"}OMK& Z5 \ɩt`za4:RtʮPrMQǜj1w"p+LK7`r[̌17*.?QKZDyD2]WtEej"vąMJj/t{\PHJqrr@ШP8|n:'GIoD :,j`kltX/!(W3,RUɓPt>.P v,wEUX[:Q^u=Nmp<{`vM;Q%'Q7_zd'U8D"RJ%>"̦+&Jz^##eZlcKk}:9,.LoCBcĒ0C3:i無A`@3V?M, LTZ7lhD#`q8!ܮZ,PsZyi$u#Nq\dd7 A'H[ߏDP#^i#{Q?2ӘF%it\3-w V0`7;'\?r#[:"zM^ ;\S"kN+A q;F*Kĕo6n+PB8Jf-.t] GRf,vcZ OB`#!-92}9#~uJvة"E T*Z ; dG_ D"43`?n>/N;/A*Le]h%%9`8*uB/Kx}f}f \<(E8&79VEi6^MQަxZCсy؁dK>;x񑬌HP[m`LLeխ\TT ΃ u-{OkH@Txc'az. DDepg,(9pX7QJabcOaF碯~fG~hKs G¨lj,Y&]  .-qY,!WLRȢ")BK [ڍQON.7$f/[ ߢ]u]tI|\b>(jWފ7jZ !O@Dgw4*C''|\i&,8ا-w Mql" 5 |7y#6:,NϤ2 dpdYqiYE|ZlQ<⤪8\j3ۨU(t=Hg$%l{C&-pP5C=X+_c|=Nx?AT4TKֽC7+k&@Zp[e\ժH pHjK]Ja zR$QRi+}$o=l@/Dk6<eŸZQ,*{]$KJ" Wl5< z }Qo7:K\'hdf>0Y>gWqe:[BX3-2'q&ӼB~wٞ[b@'Q2m -̧z'-߽rj~+(D'"+Eߨ\cK6ڭS cT7Y]^N|N{9i:y%$۷JCv wJN凱 ?rS=:Axw6e2M谻>PP$>Xt[dinΌ'nac %C[S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4j˚+((U-/ ;xL}Wl :O .{-jp!6UaD`aB:}YQU2GQE"R e?a)?C~2`/o1h Sk>^=anʻf&H vߣPAp%DV^G? Y7;Tf{k\.o*A\?+WW]|`Ozc(ҐvBP)t%t'Wժ(:*EAR@{KĆOq0$䫅g"34I}rqA% P_`V pQk?v~@-3j3ɋm+y@֘(+2&q.lRs79O`:. 7,6Ƃ% ?}i_?ʸRO0M=Z$Q&^_?y^} 2etҙ-0 QlIJ$r{h'#r˸z5=8,6G"di^7PsI\8tT$94\Gbvڬ$b] ~-)0`H2v&;&_I#2$<^ HCdE ҵZ?׉Bl;E9`@W?5~%V6iYcE&+ޘqpJsYWf<2 )s8xF҅m3p2_|\J}=Q/57**2lH#}0>X` Oa4‘(CxSæǮ9 S뵩s $^WǑtv^<=&G-q?QK(dW lRM3^X:~q l1{0lf}Zig(P0#4Nxh؄[f;I^sՏ\˥pң RPݦ V0Yl\`3oDRw@εF5<$D!HD/oAN$QFo(3y>þKdgU"9Kt(ս=%wWTIlUiFBj>Ӕ ]vp9mE^^>/gcy&/$䇿?@U 7n h(z}/]tz݅/wU ` D^_9s!ۆ1_)Ů3ewcʎ46eA_ZH[XݐY[iZ2Ĺ.T5Toʨ)>SʯEĀRt;p %aIn|UР&2mج3WOȫ 3uc ϏM|S6tq2Zv&8i`1f8?_ O- 5X[S/ϏR8:pvw>97H02qL%ד~wt0PKcׯwNgmȇb:S-juy&9K@Kh SIZ(:qsaZ!eRoXnMNW痢2g j$b$`=m'9|($mrXi-Y)%v{#[mjڡW?~Mo>8-5/[^z};)JN(с[mj\Z*C1Ei}5?MNC`O-7/iO`Q%xE*NUlnf`G-TH5 njȘY_[;ZqH]ÊyqWmS]~oVO#4%.t?nYH4472s\b`$JCcpeX A7obT,VI+*#rCumW@&Fh Kt;x{TQLTJU0 'W},öiQWyu#f'hM (AJՆGbmxH[,$_aHX8m?5_ӵh]7xc,,f.I=ZWP̖N,o(eqgf&GSg#\cӫ廃l cz aKv2(i^ 0# %k{F{5Uz%f~;MU]O|wJmƥv('9~Bys{!׿<$EըX\28vmwVN٢*,yM)kI+tN͸? gnl*Pu=>)1~ǂgf%y8n*jO i̠V[h  iŖo 9yKe) ]H;Cy&R>i5$T'Mz&n^>"z)^?ž?'F@h/﷢A)Ou ގsC+|".^pa$k})-G* ̂ry/$> VɃj (ϔхӁQc6IDwR> X)Yg,%^)TtD "%AC ɆVzX[*;炨45+#Sd V+#Cx_lP"m* ɹ6vPtSM}ڰy=/̅40eBVhPȳI;fVbjlCx&UvRlIi󔋫aҐQ[~72q`8Nyտ:6^]BЇ"f=* #YdoSstAi[0qm,7Bss;u\Qk !AӔwۑ$|ggcEm2"I@f5o̽~S)T)K BϑUaֿ ܎Х.yl[ Vi$P490[B8%g_x\zHؿ*&^H޲1Έ6Clx!4ϴӢ2XHkX)qEHU5kcɜf~|.D;/?ZE>CB i9Y$n%0DKME.h_hA:[T-&r02BFJ" W)ff/(՜~$Ӟpϝv^`$#j>f  >H_S,>gM]fHP>> |Vاp4p F:Y/v@@V3q qŊ_4gc <-vw#6Ȏ'P\IǮIĩ6^,v6QT,yI,WhIgb*/_3$9#D&3,NU" ?b )Il щϓ5$*G(X6{|$ą3qj%ܫc yS琠+/|3@~j&Wՠ\&gy %]HP.Y*4}@ @gzR]4{.N=v]4o =҂+$ v {bL#(]1cr"'?C4XzɕbJJx7LksJ/+]:갶هAHϜ},Vp ~y|*Wڽ۹eI \nG~W3ˇƵB x| *͑ƃi3sȊgP誓77$FJ%Sai؃L8x$](XېOI|?t冐Țlj`>K/st|9'@VaM۫9#x,l\oAja۞jcȡMPJ9fj n7۪hW`R c3*U]|w&,FIcԠi) d,rk -Pе'v0>pmie8n_uAwuR&ؐ[Ŧ:BGB]gzPؚSqfatVWI_C"%6 0bXFr`iID.@иȬ ։?rHՂjU37ۭp/gy?R.I8{!U%U -*x94Y d*ND}HdCqsMbP=to8+O|=ŗG {݂%'JoO`)]eݒaǟA :f魣}gai}_IXg w*SVCRw=L1)u=8<Siv K {Ad.n#9gZle/5PSUB*#mbSHxY1XHY&LQ*Gy?o4͍uA6?oPGYN" "ЋHѻHcpCYQMY=xEe9UGFiY3iNL'JRfRXJZ{DÛH*.- 6QtstP/t("D )_ O5jE =&?)S!?4Wmd~(Q\ic>eOq?h ՗ N|yVc 0_ V98b{?'&[aƠld$5w8[8+3@^Rx4'zw<)a&/D$̻^]ٵ'bb|@?Ο 0J!ϐ=7re嫥;OKkb?BUB7(iYYnn6!Vm}&Qnp!YHT֥/b>+yZ9}ӳPեC1E񆪏Լ4q- dnU¼)1gj83T4Cz (2nE,-'.GgJ;?-_Coo|3:첮d%n [7[,@UO@OMD*bce6v1WO y(B|yE#q>d4$"L"JH^"3OP2{xv]w-߃eyQ+[USd]&ȟ!=[ (E] xö{ٗrtJ(UʡVMKe"[gM~_Yz&`4!@| 38 1lE#VCT)|ݷlr{ndfӭ'}>ڟ{Sn # g4fNϪuh݅c~X["8Y}A>Lvc0{*JMsY{Mb_pteK[@pl-^VaFjmIɞȷjILr:~%^ھrNYѲZ@Fgήaߍ/dOj V#ݗo &$Da`&[{R?J~ ѿ~F^NX L$b_giu6pMȲ"oh,{6a<$yՖ'% fvvtPfIֺMK7I闡pcr~bo~/!bWp g[H plJi^嫥cCf[X eN 2hqjV|_oRT,-isеOy?_ Y^f^^ή00{bH6cg@}U_@URyY݇06gT@zI6ڰ`z("I{X*-_zj'>HqZϙp[>XFy.-)-$c(1E> %=4AkrxZN]6&]f6~C%mF!0!a1PkhtJ@GME/-٫&`Xigcw j%,g-L%J z^_ZShX֏% P n G,H;ls2dh1a2vqT+|>_35ǂ>bZѳj,ܝ]A+Jw'& %`{N\\ 2HP{M{Ǻפ8+<vʯ9S= 8=􏔱[QKiMden ej Z1`Kۨ޻Wܹs) %wB{.u|]^؃ ڜğ{fpaLhky`/@&M [(%peqAMd֒=d,2h&- }fypY1h9i}VSa3t}!ؙz>K " ' j3p8;v&+0lù qMF3;^=6ӗdET oT.<>4P6=BQt䑜} 3 1)|*&0UM>JvMwq/7nSfPg+,ФWJP %Hr=B?F?&W?u/p;)Ґ8Tw"{ų rjȗ'WXͿH%r4HIO҅*X\0'Ւbl 3E=Ep˗7wXfB$H_=VF j+Œ?"h;-/YHl[1\65ؓ-0Oc/z&G]?gptS?f)9?Z6_R$MϿi6[~OMwkg '抵s0[O c#|[]ShVm#e3A$q!L3TŶ# (_;0/b+ m ɷy)wo&_wu Bkk]QfSb߄2?PH\L} OWTup~E,+D\3D'Bbfg-I;@orxButӑp4 mb~XG(3ҲҶqG^bUh̞Ji\XdzHozlFJ^p錠[27ڢN+O*z{7z_P `A!Y˷!t2"Err T;kK! 6 o,p܎,xj՟4ѠI"5؊%`&ZO/0TMѡ]8:2P o v$PN8>_yAE%_t3鎑X)BHVI5b~WIo!>S籇[zd}p<h{ƎhX|B z=;A3 U+P3 jcQ 0)NjB2뷪grɴ[w|g%}s+ܸE8unW3ZJIӏb%SS#: KQkh(qUWr\Ȫ?{%p㋰Я=T`pfBukXv@b&InDp!먭&SJXƎd;oH->9'̸#yYOC{$b?l|)7X'E=p02?U / Q\A4D[1p3nBx^@{yٹRA/`us{v?ne@vEZb-*e<{cuBX=‹ cJcT4p9-  9DBr0^5+szhqϚ[Z{BEm~Jqg}gqC&9H|2@NV{zpkDǷ]U3?D"oOX['mȣjat`b0*Ѫ2weDN$%G$TƢ0,KYN-ց F+CO4<=!}<0PV6A+J"j;qkyF+ Ү-""m22Z50A!,vm|8&\^@݋: ga } cʧN-'v4U?֙"Ge_qF(g_7H7 ؋7ٟ[Yz|W'㍨3ʀS .dB7_`3t;?䜉{̘+;Ņ7 GC)q\:V<[o.*]Fs ߎ%HCtyD٩;9T(k{SWP eSD)nԓ d7g"=%cpª@Ge AY어[[Ҥk g-Sq4|Aܱ2\G$zUV)(Q0fvkS񐦟Vg\7pJ9>ʤC,}; x]GISy"iaBHw[b  2m<|t_9 U0o% `2wXg`kj']U QMjiKODRm8\/ZБt1 Sqr:xdzHZgW$(uSy_.}I~ 8 `=ۧF(~ ݎvbgAKN$ڻCgW֐U۩^5.I?`N[|L=jAns,˜QW13doGPrY3Hnl $]g'@hl%PqSL$+&z?}UeЀY_O1\Ňh]5gVa Ds.*1Ɲ hklm%Qmꏳ膽A2E҆HQ 4GFK{q RdS,> vH" fgL>(9%ΏF(EeŇLf6ᆱz(rw n F{f~f:ԓf:sh9h)Y7MflmSFyc}c$%;Z;) \ͩnq亓 Q6p/#8Gρ1>Bѳ 'XՇ-/cHRNQÅO,sZG;nz'a@=PmwvJDQ]&KWI?~^ĕ\NL܌o % /]㰵b׏JZD6׎fz3a3|dl8Fy^z^E&[9{2rUk2\ɦ#cb߰ha I ʂj 3jt+^En8!ϸ~`13Kg"jl;hk޴t`okԐ/KeԘxWUh6DL}:|zz{[aD`T7.E\P}eS-O8Pޏ ̘pjW?5c}2'T8a$39-P8HzA @|tW {V~ZiOʹ%BLΖ6\4qMg6Ql~5, 7.Ns.gy94o̥c5=PcTv ;;w͞k*h64Q\bl CIM)}:b.cȹ\-ɻ u6uJ+3z- pij c67Z7y[ zHBwhbHKx1*X t i"j}C=wcߚenSZ;Ѥb&ϣk\3Ha_4w^ެ!]OppSH`PQrc,7 U.|ngy#Wmv>Y- /swx+C|Zu4>8]8CsN B>:-q]]~ ;Y %5<*/@OF6ue]=IYWAdK`25>?Z6#m= i`lI[؇ .xGpݔ xzu26^R7tu1'2$u;wͥ\ĴerC[" Z0/X10+3Ƶ(lf-Ydzapahd&/6 H1TbqbW&ɷ3'Vэ\D4XK~ni;`2覴UWJbA?bf D΃ynfN9Ri)?62~IܳhG~obͪaͧY_Ѕؐb}<67mA¼ME>g.E&-$cQDU,iun^BI5{``(1&!CZ=EoQ ͇籞 n( P}M:T$i9O:9ieAw;^VuD?"U}~+5{bZpS3+s&XA/ #XSگ|gTZ| I} Q0fp"M~~ ⥏ 8^9d{֐^ًj$D}ZVM{M 4O>-:Q-ɴ(ɧGz`QZ$A"jBA@" >F H `$"01 Z+YPrŤRo.lO-m05P{몎`TS?Y~s2%R tUDrzx rk9Lj8%+g8HYhCHc8围vëYﶒ0Gur߅و=yL݀n CZВ9u' kf[/ .@vz%9(gGeMO3+rVnE/ 24]znﮣa2Eww9 @])APul vϵIu#eܞ#> W#khY`*k[ \b\q{;ҡQ֮RQ]=F>ʰ) /Opȭp J;i8'P90AP2Du}J^`( fjF(qlfvBX*?S^"ґM2fǣ!|:=y~_[ѳF>:Nzui#"lȆ4eo|صm)oϐ$Eb?rN-$U킂8\]]֖A>)2?RD~Sܘc8x1*/cק躐y{qV!M%xܦYO!K2c!ljۇf4Ϲ|?9PJA Jtӻ\MSxݭ͆CM$F$O W>*dԘ CZaWbk@3M7KQshVhJ;p:T2w}>n_&$2e@_Rk"iD$> *7'{pn2H &lF@Uړvt)v vVS}5Ki>xxUL k\LM fV'"p ]C-Yg/Y}f|̊Ta^|h634%QxG4@o&Bq!(= cqI2QDKN,IA>2wfk)Jlb/5bO[eq3qchRUidRBi6\P\! S%X TeeN\cG /oGOWk\im@ C@{ݯL꥞x{2Cʓ1Ho.̥ڀ&о`^>}p2Tt$v|0-Ck7:ӐW9bTC(9=#Y`:0$ 89&' =?0}+K3 f"CK2joboWObuE۱k@O͉wK{]V39y'YSmP9嚻vXD3`=!ف`t*=d͙mxqE%`K)ƣ0!|)]Z KaA;2  d7; Х?vtڥK@1U3h;J  /#+2Ш$Hyf硱NQi +Nq _lg=?2^HPݛQQ!}hWN'/k<Hf|Vϴ ߐ9qr^ePTPy3lȭg^id10 o2&esjzI_vkOA V?!j&f'I;4(Uej#sG+ Nh1QJ.&4= mRUF0׹tŮLUlܰbO,f3G 5 U]v N*M~P3 |;L:&cP4-_/(ҹ.N}=ąè~rqQFWq\G`'iځɥeAT]us J~FDG/_/=2$MYB1L=*we:N,CӀwY\+=Z5Bl8ۙl|&uy,AE6Hay/ǮD4EnPY;_-Q't 0T-T}*lSZjNviǢ`3\0vmLFLDxɳ*M>G1jTq~֦&P6#yc`^%:q0kZt$pA5E8$JMh|Sb3 Qt*7176 (IiʥܦMke Ur*! / AStr[mN쑤vVWY2ږG>%Uo nžb 5nj9[L餳ܾcI!L׺};A5VxA6 B{`["RŴv-ՄOQñP\(@1 Oq:|g5 e(;;a-DQ#MzP=&mۇ*s&[,;k#/ejd ًj6#|'Y@l1R!9x_WQ';6_?m!5&Yf[y~bߤf dbbfF۟/D/6߶R(,%˛5ˉn ԡ'w8 8B7R:'GZ7]C~xq>~,B3֬SZx+z B u˱EPojz !Sm}1DWsCӌ*嘶}ُS'|ث&a([at>.dR[ډCI~B {@ۛ[xmŘ[Y;ѼMi )!fjwnE0tFRrh+ j=(ґ"!4B) (/jPmJոf(tcݫ^(q^V+}ɉdʷk42m 51@*aTˣs.ȳЃ^;};x&kA)Pc=WbYPeUre6nFtJi !aXX;h1 *jJfSMDzC7]Hpg-H|B=ex,ek"ç}kFJ%#< p>Pɭ2Q.Y9:k)P#%!.Ҝ^95 TonާW}2|tnjպ/ t;r=Q4/bG*`~piϞ};@nOfOĄNRSj~P=I@Lj6o\Wr Q_\,]@17 ]IFSiO+Su0MhJ|3uY3BXM 8sՌZ!9,?d:LI1؎s S(.ؕK ] NtRjjArM  }aXe]Rin]W'*"1[=.-€*ҁHYb()qQ gQW͊ )odmEJ݋u)gR+ <CA1*66;gtƠ4 8s NO`f M2]wG}`UK)Wօ1lb`]ȼH@*!=~n[^Ԕ:Zqdr P>fѬStCq@]+*n$ j;ζߢQg#Oܽgg.k#Z ҌeH_#B쵗O)K4 %~oĺA=šޔ+DnՆ}7-hA&PX[; `5Шr+Q0:rtM(L~.% 1 Ox4}):';pUJ 0U+DILfs?\2HÀJE-?T,^ >o 䰪'Bm,X"&xVoL{>R+7KIjUuO1sv}/\~!iXTO%*jhɭ NAE '|"<*;x9HûY/3;ut;/'hIVvd%~}xfu ̨ @yNЎ"ᝦ+4D<V/J), *%㠫.r|wܼH iѳm{x,򧭭Ej#@o[7%fY+6[G G壂C#nٶW{lE3K(f넕+}\y޶-$>VGQ7k JΈMqj /0~IQY\s50e*ݣL667O N&l c89i7XPLg9ڰzM)ho&~UN NH-c<?$:Ym /s?=E[ij;2N* ao e܋zeč [>vB dal<En'd3.jȕYM,0‰}ĔsM =_`w\wA >lW,& cԶ\T)K50").Z1 䚉?㇄`6.F[c@xH% $I{uX./6E M_/ N&`Kl^}Q*4oDn֠+QA|l&`/Օ+!/unոީ#=E]O )Ep|XRY4a u|q Q s,Z7P!P,JC.R8+_XO Fi1peR{Efti(3ratzE ީx^V@+yF?_/㉶'|_U_@AOĂ> ~;aߋSjRҴrO;A깗<\Ȫ_qsfK('翃dBq%:_W~@-,Q)Rq`/|@8h`Uv!!b?@|j@!|h ˖B,K6%8Gs t cg5Bg7Rcxzwlu PtoT[jhz e}>='RO.sicl'p5Eni+1zk1?,^*d!v4c6_F#Q=efP 1#Gr3lcH_.`B?췁="#=2wy. }=9unptyE Hޥʩ[BIjC84 %qKpq՝pWwYrs(\WQmh$-ë1o#tJj  $\'Z<\8 ΢J@~>˂Cpk~[BG}呶XeL|>@=c{_ 䫜#l)Z1OADiSXT:U'å$jFY>VĮ2И놃#Y28:BBW>3~K{`c, Yu_aD(o6Žp'i<3MЮS`D4uA XLKJ݄ ˭{+VDe]Ah.Qܨ[Od≮:Sn4^MOI &/64ᓌ?;UTݢZS..?4:<(g5ů;,Trn5nVc(t?7F^&QQU*)'a%_Z%B#Wոoٗ0WȤV0݇KMMe=M!+jrEj'LU{_'w[IC 5k(켿#/,Іq=yqYҦg3 򱼩+K'1`NfO!B`9-Q)q4דΚEo@xW0ҕ0g.pZVD<çK\#}4"b+;VceOaWwSw7X 3(V,LT[XG1Qxn1ɹz 3cxOsAr+U a0}XJ ji:kXGca'q `$EDg˻Iw#rWœi^ͥ-`TY=u(|U@^j>pgUw .‹gk:wmR @x/rjFژiF<7cեб\}nH Lhռ= {ȋ2{Z n#k{#y?V5/=Ku9G2Cq7OSo;|>9N[&nÿsOvx S( Tt[4S4Uz%zFY:}<5@av jQ-[$dw>6b{C< ;\WY:8T () ͂2rF̫ g-EREë߃z_وlmrCm B2m ]@kd͖d?Z ћ/SoэxZZp~ehAcFJ iaF TrI ScW'7\.RtӢۄWy\]g}a`5ϛX<Ms&e8\%LTSZiy,wƞ:}Tz}C#R3i<B ~9)|30W<\I#X=>z}ܜv-<E)UC-XCeב fb0A &9,Gb3O̫a 00y);O~pTfq,3*RU8>J_+cjC-E)+V# PB?^5Y#59cħEMr#2 \j N4ZoLqf\/$Wl k SelC;D 1m/,,Z[{'t q( lkPN\{X)-z@av"hHXKMq.dv,5]FwTe%hy@hl Jad۩`q^'p4O\cID,9JiqSlIU۪/@T%|<ӋȰiȱ>YIvy`!ƌ0U8 JZv;NT:w]f}Z |ACU##kxKA=Ŝ෾4:ʛxBӻmKs8JX[_n$}S! fď7ض$ufOl&{#)`5lG&DŽ_s{$BTtr8I=I) SP#!ED~B+M3{>e2Z?*ihivj.w4U$ܼ|ժ]}(֥u!D&lķcr*u%_ |&#E*hedQg^.cP3GM?wvs3sl*U}.Qگ-Zy/`=3R 3mR8UId)<̷:\4ITf꒩gpڒg?NtYyVSmF}7uIA}*m㞎!̄8pIw[l`hy{] 9hjqa-W "qB}wz<Ʌ +}sa S}_T$j^K˓t= IcCĨ51{?& TȸBęՓc3Ennv7ZA}"6!:CRaMf ? x({?]qhC{_ |W`ܭu8iID9LA| v_]4MDlBdk'7I԰98aj4y%Y]*JRsϥSt4>,aL0\2h +2mF)?Zfwz}iJkX`XOƣ.]aw-9D߾w5H@l,vZveU'IT(j5.yD*\mݮ[㮽2VMDcwfqG5BZ_5ۥ% V In38׵3D}RPDXENO[n 9*ב'uia4Njs.[}Z"XBԑ^@|cvX-f|:9Sc:4<4[C+}S=@!Th0N~G~)w.ư \?/?wFa ʕB$% gvٿSˏHg+; M!񾊩Z$Z{=?[\|)y:)6mpo)yfT4Q'#6#՘>/PgNR njSdYm$+`ZмFmHn lmOeh^^.Rٿ>*T#C'&㷘 ]dNLlqnIeP*-/jڜMF41-s8JM/uAjCClƜzcAbꈼ" @xfh 9Nv5>uQ_o'x>Jv8N-j6F/SPHCV||@|b" Cw Vj_|d9c'T "_-wK0vcnY06Ju[*kEY! D I_!ݣ2iӕ$ &9= G2/0|r 2Wd۪rXb Ua| p"|U3,sRU$~,_/`DQ vEB vSD>p-*&8eSv?a(rd!ϖȑ|L'w Cٲ%/쒇 q`€5rw}kklq':fʩϙmE&dJaJV: |iQ % j8Jyc:%,woaw[UBѱJ^D=4&11MRTX?ݕV}lҝNt,JRsg}-_&Jϊa[ЂUYOHηt[BV*:V d֕(=sJa,g9I2 S|>}eKFc ̆1D |AXWee |*W|-?x?Dֽb>FK174^j!W Y17.@y ڙ/tJXc=;I9f40 US n.9)~ĽX娡=vtI2A%O*/W7pmV|}h<Խ) ~S^b+;r^sYF{n S6Ӥb B5GN7jbCLT/\Xvf?M{^ozCm -.~䤁=N%9^Vtc(V,~4h%W`UkC2u΄0rŤױN@qL5O9 ov VOU֊2sZ{FqvaAӑ{0讷˗;({Ŕwٶefv|*uGH=J6bGՅKCDm]WՁr p~CS h3o8ZqυJ/ ^v8f]N>kUe q`1EKxKY[KàfRZ VYvw1d(GL}$Gѝ6=]SĖjk"NYK;0睇*]ptgb[Mw8Y kx肔Qm8Ţ>G4_uhvGcɀP8F&QOK 'XnQЂsy@ ̗y *{BtҭJ|nVP2XDeDmNQ`2E|+bbiTPgmـ7ߡz8lΙf3ޢi\x<=0'B A.0&`Zuw>TDKkͨ!aVa@ToE{mpV;ajҭBϊ0`gAP2 95oUH 3'v\ ֎ |ySEҸڬye_B*=JS4F>&P)_u@]rQmXݶ<;ִ* /wcޜ #îݘ\\G?ϳws]vBsQ \j@u`l} ᱻe~7Lf/}lQQ@eNbЭnA87̶:.fd3 z%o tE_;@XuJ|iUsAcfU$XE]8:Z~\0ש$]A6u`בBlIb>55&`zKf03u晿D=^? Xh;E@_dboulF1 zdeH`YK}EIV 7[~ @*$Q 8YϸU-_lURnB#s2A}}W1t[,˪Up$tg?~cw~bu{hO.][[ d_rd +bܗn Z?^$,~鿍Ep T'i@7!Ŷ`Q3 = TJ#pY&W2w XϪI$fK/q\-#>iHMv{ܔhwƜNlSh-晘]<9XRx U ?kc.C< $0ED :ѹ&Vu"QѻmQbn2u}[4WG,rU1L#ܩ)= gs&_TU`-=Z B{RmOiP~"ev#7:::B<^w3Yש~! =Laߕ0׈8CZ &^ .CedgԣC/;ys/fQ#O!d#oJg97s r/A= h@D`EZT(@cA꼰"~jA'hY@1J g1R H39{)]̘^flD@ՒmƣɎѿ)M6f %{Z, ЁQֹ[nT$ba\.s$iV\ Y\"8XUS&ɇKzjj䨍5Jxq 뀄 ]igR32!FYC)A'& ++~[{~0u7JF5M,ITrvtM7K3 'D*S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4PKyDwg!r:4@8}7=@G 53@mMgZ/yJHD784gS-kHtpxZϐ |$ò|w_fKp`t$`.}Tozsc )3-֛%]˼0/[EHXlf4>6e@ q 9i!|s~XtcI 3)PXnE+];j{hzFrrSS\j4d0ʔEc -"ơYȢ.a }.hKax*\THƼrX, X(ߖTE,Fd_s>7iJbp:幡{ $ҼƆE>pfLn+ O?Y~:_~{߀tذY٧FA@7 "l}7neQ뙹o/3ݣ?yWgn gN'_]rݮiZ)20UR% AI؎_XIMهXB"K/qwUclB&HcfYnץI*,NcD?3< *!^)JfVf`J'SuVJCj9i(%w Gh-poi~ȘE8[FdU$”k@LN'd4dfgP4 1Ǡ$Y.O[dc!ښK֯'0蹂9` .Qu V/0OX THW:Eڢ7+ A橸y 51ad2RX,KơYg6r)YH֬Kb N5jT 1hrtilw}yͦ7K$A=:.=^I5#v6x: ߵ`BX9*FriЦG=(v\uA9<?hÁP5F4EcV,HAٜ&i l^ F2/QҭLn0EҼۅ3;QEBf|[0r3YP"k_+{UfԠ901E]<1i$H>ةC"J&uy< -XK 3J% i|RXOW.l "^q5{(=; $9]Z/ ¾eeB9?U@׃T`Xΰv.8~9%bmw*XcʄOb("3:ڞ-9VKLCL49v)r*;^x)+r-WB8Wl;f OT\ZU #ya!e)``o'k2NZPAF{Vtch&eq[pÙw(l71s# iƙ;G wW;f$Y𘶇[YL<6 )a9Fc_le=K/.Tnz1B)]>u;&xx;\D1Q;Ccz+AP߅U( 9^p <[Z] nw6o2ڸQqn4)Xk.xlkz]Ko~M>#υߟ?~?K̗9@$F0֢6\diA2QCyzd|OU6}72:R>pU)=/2]ҴT3p}'n5bÆQbn(2!'m33ߪ bJs3gV1Ѵ}.pP2ֱJ)Cu( p#U]: jՏdwoɹrN|#tKaBsN|m; ZNOph^?0-x\aIuqʥ#|Y}+7*Q ]5 ):E8!๥t0K>ϓ# G92w L kjF.ԝ8>̓N_`\1/4+xF?rN8Jwki$;v*T2`ZK#aEC/gEbG Ob8SUm4pak[_ʌ WGz7.f"Ivb2Lhfo'kw7ԶP9}UQa:mR{sw? s )\UiO'iIC@6-#N`{ R3bOGPiB|̲ JEۙj]TCqqtaq\6JteʱW5qe@hZb4soABy 6lCH}Q/ J*ŦL20]iM#;0R7,؍{ 8 v-[BbrcWCJ3Om := Ê)76S![%Wiu!s3wu$sR^R!3R4djyWI0NŨMVă3O!E)z^HUrR盹dl{Ͷ7dn4{|-6–_=k9,sr:GPі \pC&, HgL.!@=eQHRJW7%Vy鳗.JM[ 'o߆~CES^DiPɼԤCf\+.]o<2[ ;4QR4qzcD/$Y\] 0K{M)p%iAZ&&1O?RHk#>pO 5u(V1S _% p v{/y6f$zz{UC '=ܖ_NyS([(lMIAĤC`6%c/ی֌ wGe`M\+I/Q<\5zJS.ϾmNcʝ^t[v]Kjt䏈mE( It4j8"՞euB5(s 4/M]~|ц 2C(S0= D"q*kc3 }hi1aw1dVB$ym>x(*4^ &٦¥-[ <]v +je׬{h2XyRm`]a@Rm ĢA:%H+)#uSWhƹ+Ot_a`86Tz>fE!sɢT3 s*cnFpǀ:a f$7Bk찲ʷ)9Ar!9r] 6&]aNs>M9~U.| ^ǎSkF=‹<wMgO BCGwiG*=YU 쒷c욷F {/ìj&ۊLUu1W(p ^BX,sr~+H1/RWlr%S\4Ml)ӎ?@c(bN+5=_??'6G0y0ICTQf'>&i٫AurtX8 f]UHS8+g?Ee^Q]e9NM/6;'[E],"/mn1Sp4Áhvo: F}ѯ+keA|Q]^{D*Yz׍̩MQ@ *1oEúuG-σ5X"`%B#c}yDM?`Q% Dz?LMZ ic.݄)E-G,Q^T8xPdl/k i N- H@*|$BMy"ڷ=O:-tӏ8\DCVEk)K$_cԼ_;R4 +9oZgQMHS)@nV'|Rp<0rq,OJHG.c !VXlF-f\tuSI.Te:yY|#xt^#|ut=p@t#Fmdcp 8 KE/@|(m2(Tz,;.̊'kdZI&5ˁA `֫Uڜ 3D6KHu<)Y‹f(5F2p@k] +ɵFǶB}NMZgS|ywq ƠH7E8t#«a޴ĥ\H# e%,?sJ[ImswCuWnqE"'s&a|n==vPg@S6zD?qR#NyYYVp\u*K#͊0{rzLGycfiG-=xE|-߇8BX1EFW<v-OP̯b գV !0-:{4)mRhw`A2YRmr줃ptP$O:bYPN=6[M>c?X[7]@qi!~ A8Ms Q \yġS$Y1C%56jwq=@t_סoQ_e!=I|s\2ĀNOo-!)$T9(Y~`p!$7*EHJRsK%B~ DI(nFY Cvǥj*uk ʴGA^8u&+zЈ6R<-;މrF5p5$#;n r`P^.;xZn(3b@]ؕ:-L)&FjwrQuHp®U}nPQR\[qj{=(uu(  <3FH*)yP-z>M-ԐPoa&t >/jj̼> R)~"[ss"{)A&ܩ:Q*pf?$,JHN7N> U uw2_/N|L$?]|4|#0IW>$=IDfowӆ))\_3糛$iU\29CitA}Gˀe?T=_F&Pf=f 6'BeUKFcH]ˋq{Kg%(r;6Q|lʃrqLF(c |d7kTd dCB&WeoK|E;57eBnI@ \`Ff2*?V~l YGlS߇\q?c-2Mu/' ?j6)8D!0f^G8I?cG'D@ Dna k >b0`Qx՚Tgh|DNy(4XkJqƷO`N&/qAJ EG܂N→tC'iL@\FPAF&_X`¦o @Ӛh&{2]% v̲5z"[9ʹ4/|HCIhn (bĨ \sZZn Zv@9v<@R]c1X}ڦg>MQvp)皙Q=X^$1~j )rU?;umK>W b1gy o4T,KmY0Yt`ZqQ;k2HaR(;}pV`G:۫C8ڃ8ѹoq jgm#/L{{MpGDΘT76t̖zfmqj=j.}kΈO0@)/[°Knj(TJ%;k l^K a& 2oa 2js㺱:V+3:yv?OP;>\Z}K)mZ˶Ok\"MR[zP2\hTl%kJK^JOo"/xo1'v&E dz iD/iv0!80'wT&?q\u5 ȭx7csPܓ`*"NIof<90ߕi`#LJ_XVnبF7[EŐ,[{tWv*5֤<:ϝ1Rv7kCC.qlf6dlNJJڃ"Tl)SعmJZ Ѷoxdc!qg m|ճA:B^ !!'/|˭JA:ᚌj9Y,*+'GxftEf)rg^hк+ȿe봪54eKL-|vhj&;HX!Blr5$n YgFD %  ;(|^!3sC{_\Ku1+M2%&iXi/^WCL=̻!`r=Lq`~_elĤӋōz#,םݴo%L$B|-bYF o ̠p `f_}s-H=d"71rF{}t0B(Qb$-"yRlPSql{φsM TF=mw'6]%YY`95MrxnJ56.Q S'Ĵ tC/>/U>J`F{Qz;b+}$ѰFp-wDݨ [b4/lxǫ2~@^ŭ[3C~A$kES,%שF&/G)1/XX522gCKrvL-ևHs7 hbmrπ{I[+mȥKFz9M=pz_F|Drp C;uE0C=<&1>`ԕqb^j36/wow8r+T 2Tܤqe|5|3CnM q; 4_A6zG,6,Od«$Cԩ (a:"OM}Qֺ67R4sRz|-z.^Aex!w=~!b'5)tFG&`w#WliÖ%,"wN G,5:"hȟlC`6̏eg#Xz;&jݘ*7& q쳜Vz ȰEӢFY)uA{;æ+T2%jȓkI ЖG'>4E7`:WB<:$մGb1 - yʆSw,wCAD HVX"Zk"îE-R{ y9Bы`ؑ˽8 RL(S2CJ!i ΔL٤>^2i >5*p Raل|jA17&γ"AiMѭzR㊎AjF#V[5\E}  ;܀%?MܴkT5cs߭t,,qkLWĩ2 hnC_:_~ _"ϟ Ey6{dm?Hg/E?L>T52ΔXSRE"sJ2Ea#l_<#.!uC\uM8"0uHB=e`SBCarrB}kTNRň-(O-9O!+0铲%C[R҄ gOJ@Y*WuH7 ne>G+MDG P/.ݺ _i7{}'QJg̥35؏6c_-/ᚐ:蠟Z\ 5®_Q|0܊C- E1 T@xS2(iL{9_Yu[k5/Iz{f욎Z~Replѝ#rҢ)Ϙ++#A5yfGOM 07_ZsxQמJE(1 Ɲ.nS*$4K|z@Ut|ɎåYO&/X$0Ob{F3L*G zEbE`E:_S4AY!n"l(wFBfj2Z;w#WԵҢO} Co*7; #FgӒxV=ww#M¿qh`9y&y\A5}0CN7UKQ/Ѵf #j~dkH'b"yWךB)F4̎x Sݟ%;5heƜЍkr7L-wʽ$l͛e0ˊxQ!@sm\K1+OG0Ć;Nlq_BX2OyES TIVYÙ,Fj Y9 ] y7i}ɊOE5.Of êyQs!f @dD,~ɩ%o}xcv'Hbv+07K$Qs~ԕ}ϭc⌷ч<wVP-9}.5q`wWTʆkW3|PY]xRԟ1mH"!G ρS n1+~( ʖ3uQ@@gR̮NE<&é3VOpȋBY okv1Awӏ-gL@"[nZx riHͷe A!Pi@1ӮS+QOW}bC#٫<4sq6dtMMLΜ4FubZ[Y\ Qt܈PƵcU6KlYZcb[8Qj ,L NM&)u@-vB'\ODÄGieTZRr #Vc?Xb(=OL roZ׬)I _Fـ\88 |]i}֧"JCcPR7, qѼCVGS#Eg 1RXyQB嬫JŤj䚸| cӴ J`)Y/jQY{"A*Zdr 'V40R+~؉viLG=#}"++) Vl"GYEZ 84 ;7]dYO9-etn?%J? B2uk2`4tIt!e` W={:C)kr, |^=̱ZR;(5}Lr9! gn\A \ IR wr ,~.CՆxtᩆEHo#C˼W* [ Ut#™y+Y0@಴[U7B\0_L %Ϫ E0>`1{A,GH4 JNPbqLLk2bX\Ozk&ݤ#QL~cSn<юI=' 4 &5O9@|B%' FwN^r[OEcӰ ;vB0i*T" 9XMv/%&w;ȏh-ReQ#x7z '?ii Vv F5)ke,e4>H+\PB[SG_-%# 9UT|y+᭠/WOP]7Qc{D%4f}̡F&$r`s\9&qXϵ̓XΕjLfvLV>@9萟BAtt{f@b钖Fػ˽MK$<3 D&9e?C/H d{Nϛ׾/;6<;4Oy®~z(lJ~4b3yQ%GK'vtğt~Ae>6CIUP28;D:!QML"LI'_Y10ܱ%k]3_P;AG<CQ#1{ZE;L~?ﶁTd 2"8r2NiapUΗ$#Z!ebERr ?\ŪAJtCRiE ֤N+Qk Jk%T?{ :K\yK4 ^3Qa4gkX=v|l/Bsxp'i%Z~&3]~g;D:S8*g? (DXS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP0PO<0 K,ڙ8hG|9S?MO͵ GrQ9bb6ש/bC]@ѐQm,!SBD==ئz1ȶY>QS %B_M[(b2o6~ŤnN,q#| |w- >mbKGYvf|-vE~ҩ0aЧ;J\R޸aψ˂>RQ1${-ݐ=ogqGM7eV9LEsZb.Y=NT,gwSR#T .s5?PC&- 5Q5 ԣq'zZL-v|6=e#8>Zً 'R&m.S`3jD6=6앁H6\0hA U84LLYv+9c*gd ſџ/0ac^$'5zK`L! *!^%]`Ѽ}[$g>2WnȦ&/Bq=k ise{VPf.v-}G3C+> @fP*]D^!ʮܬqg?ߨTv6Q=6%1.YԬܥǥS 6q@n+"ď-P5 o7 !K~O}tOSaiUkJ?Z Z26Vlq2׊ZV{w;/)XSk$=uJәgә5: Vdy=Ф},txB]QY9$x$3a[,l򒎻~0ᶱ7PtԡG{̝Ùiw8;`14 !6 ||^֩(2?) <FW7OeCvg2pz-JGSm;*:8Ldxv9VlXG0JP>Dssxpp>r촪p^YdW4:bazv{k-OJGspPd6ˁ[K SE[@Z=h<͹5v /%gtI9 g:*vT5$J&[_!f^OvB ]vky߀ VZ.z\>gm $ 瞱KE]+n4 s̀F|^3TgPQ0ejbb 0%D-^>ƺSҴҘ}~P^ ضT) bxXGÒ+JT&²[|*#*٧^VJ|uU+ƫCɠ!z4|;IU/0f_ uEVI׬". 7>nhƠ ;K&&$  ML;(v?0>shEĩB2 3YQܜt[R%V|fuY@,8756/okn?x<7 5՟Y@S k d:4nJ351LRWl "eڍ`?Ȳ[I 9Nj\lսFSДH^NHF]k=k,Re7jr$ZR 3?DuDH ]e'Z|`ځ?"fj){ڒ§ :*h]DW7Gȶ>o4*c[.دIh#{yY0OS9KppK jw$!L 0 q>oo ZOI .F#"tx4*++@ i9,O}՟?؉q_-rDaq$$DʤLs~#dŢݱ_LDB8Ulbsq8]ZԒU 0oO+gR9rڹ"SZ;LI2J}f>]gJ^0.zrQ~<웻z\XYey; +#̆r#(ե6b̟9g_g3%-mV7eA%oLMX6E|Msl1(2< Dr އw!u2tV@{S[ :HJ2ο>c2.z-+e1`Pr持pDd3hlQ璆%!q(j9v&8-q؃d{|mc2nw8RyvK:vcipٺ"͞σ<I;:5p"oҰyM71s>_x";znC7?Y)4ETɋ;vE> h&R+W:)?zRӵYL\%IuLJ'WBzl H0]'SvCZUsYbzSNr[6[cSXX/IeJjZbgDe5t,`4V0]W^a\2v%NZq6Cm;W ~鬿'm\w`$* 2cܥ_CU)>)Uq`:8e$ 6,`Mh;ew,?]g1)*+VRcUC^ sׂ3 ꯝCB $=kx#q=.|dnyYא*s/)8\ym)/z L(j)x:T<;žr436N0?n}S {L \GXק;^G WΑ>I#ܬwD&{o=.+UU'"r"w3#D6;GDhjV+\1&N ;e k 1xz֙$%Nw Wߌu$lyC4`Y2YiXhf~G1 lv8"L/WF C>6 J_|4u;Ε$Ci3-ƽl"uwR#V/@j4MTgp rK{Gfb,{qT_eMϘsEiOfAJZtcTROK{eңhgPc>)0?S)ԄON5*ee I! %HmQ> >dY\f)`dF–>29tl¥u61yo:dXœsظмc Տ]A0j<2lEwad=wiR GI^u#l9SguԱi߸%jsCl"Y"]PGQDj,}d#j¾ gKrf륔bNT1;/t:Tc.R AʘQP\~BQ0T׫ʤ%gtt<Bp$qt9KA.]9uʄnK@dF?kZcbe|?_uEvrOӿ }by)?&}ֲa}FA؟IlZqEu %aoxpԅ,(7\厹8|btg!FU<>}vnm q4Vr_B~LPgw|淐P'pD ނE#R* 8d ͅ}l (xV3Ib96@!OJTׅPqJBI@cuW_ zkYe׽ _1ɥnPlٺo_E$-{^V@H0faw̛T,iey(a/u/Yʺ胛,ST3ݫvIF'D2 Ϣ7c~4Ԭ1!Sn fz?cx{\tUÛ|yrc2KO=b401m3C/hCzČeH౲[);d tV\]J/\Z|bg _l)I۠ L4ϰ*^?oɾ~m{cKfCtLNP[!j[`).2ᔎOxHe/vx{I١KWS҅⍁ˎ [ ֟qq@s[,].gj,4; 盀He= |{a[ _d 5g^W [r* ip}} x߱A"-p!ƗDŦ*GZe^?k`78,cxm?5D{K)(»?B1)6E܆#mfni]/kq"c(K)7hu%-|z6?N^sÊV4,Q>4C'(zĬe+bRۮp' u5NIM[1gBr))55]6/!q{n'4*':OԳ0%Au\.3!8Zw¦mү5LzY#n{& «^#&29Ҝ%A f8P+y/%hTG)ȹ.F~eR!_Fi&TlKH}+fkSF{gd mt~Fe Umgdr$~M~Rv-[kF{ T18Ǎ(=:!Ewg=n!uuUk3?_ 6e]vw^r&(2Ped(Q^G?|8hX2!R)"&]Q/.{_@|j"< @JKql /kzi^vG?3A "預"(].zp5K? %0s8.H/vxs+1j.>=+@'3i5 *nOhf4ٶ^)HmWWћyLAZD4\!NoPQ}Du*XL8$b #DZ%;a?SvmX Dzг?C[SUO~^=Js%+^ #\ln:0s)>)_HjF"v!s(^A> j)@YR ivܿ׺^F;e"3 OB Ra&bΦKpwCu[:JݯhQ th V,w=hpMgMd%D,.B15 'g 5P[<5@M$2r/s%]?X]iH۴"J);sPCmtVʄo:, 87+IٵQ"32|NJ^[L$c W3Gnj͡!sX/B܌u:kx"z19 7}%KcI_#`@ڰ[P]_)T6 tfWߴD{V|ZsUK) wkT8c] 0fH_/$sۿF'к&3uFrC@ㅚ~.xTi5ў3*zc~[ͯSHn, Ӓ͝9>NJpE,:$GŃ1rŴj9*Uÿ9tM'BZ5QJ3+طe̛7Â`nATB}Xjjx$ P9j0݈G$'N[92Ӣ {}31C"3lkzF4@*̅U"sMS%,ch]~+v|"iیٴчFjrkVP c/n]TQ"N܅W٩2~;lvП(֪NLuav[P"(s1G)t'6G%⢡%cMfuҠvB1w!S4LqY[Q5TFstY'.H(9.J[7I嚡GmjY$7{i0`c2QG)6ѕl#6ӇЈ ߘV{=/T"IBFM84ukOdlGm_s"8ӊ4o Q294 g{ ix"Uºү{B6]=_gx켷}ͪ,|=˷&yܼL?22`KQTͰfg6{(Jnkrv=a($o]ؑ͘ 3eݲj*'Wx .xPX]uɨIA8w>2 Y m0oZrH@'ǫGgv2CGaKmcȃ,Ir'4u;L ҥܛų`9qۍTa fV*9B_7?e /?[.z/S?LuZ٭ra>EX9 6Qk Ν#5}UlRVzܠ h~-ngb6b%ȉ|}(lf젂 ͊[PBaA瀄\33A᧙~n P)c9b.Ȅv,M10cajFc94p"#jBH+14">KqO N- R +[Hҍ;[#*ՆCJ 'HteM󄶍x8=2N{33R\; ǝ峈 ١VŖ{W2Pt҆w5 CDt^${Nf vS#)bg/+ηDPȄǁiWί_>^g< [>)jsY aBݦ =K#ThόUj.OƃVB/"9Ҧ[ZZA z6 ꛈS)*6U0 I 08 kOfJA"S";]P9yr5_UNDRcAОw+%z$  ˾e:Pj~^ 񠊶t8Whr@ v#}LCPD:1ܚOƊ ӌ[81H}![dE43Jtb~mgX'hTyildpxޔm[ dbR>` IfnU6=|cD"ptH"Ȱ(3ئ$Ik4DXjB0:-|WqҤӟLwc'lJqĖ.+Cqq)HOz ʨs r،}_`x.UWpه~n]COI[6lrg؉GKuyT6{#IMh"l'̔mB Xfc*NY P;N2l2QϺiJe`fH~[pE 뎎vJ*=nmRr <8qM۹q ~P? Z٫{Ĝ3Efgкw"6v;rFKH$Wм WTD}بta_D]C@_x)I#$GZ#am=.e:s자c?gq t|9CM}r^ҍs^ngԎ },WvRaFfkN MJG_CZ?NM"TQ2H)8b+ilD;NRe$M_@zm6,B$/<\hl{i ]s7noj9Qt&ߖ}TJh`d*UfY8O=$;JN>;~"2Fѷ eUJo8 RڥOpߋԳ ɠ Ex:nftƓ4TFt 8݀/t V&>"h֢X *8 ?0wU=Bۋw,kc]iE;ǁWzCbD^yׅi@^FM& Vk`ﳽ2jǓ1Es²K6z Vï=tB&mYX}%mB[ K՟KmF4!.U/GvsFv(8ƹ)|5-mi( F=+d!o/3B`y-c[:OHLnZ >_+@tߘ؅WO1x^r*w >?/6"uW?:dJ@,< Dal<v̽=l0gG |ό%0@6m*T'Yd 7#s䝘xi{0bΌH)^ f:|QL_7D "t6Rli u'm>LxdhIؔ2m$]AߤnrLeeU۸n2GGն{YQވD6N_۾~#Cf=gD( eo3JJ6VPE1j'|$||bڟ~oe>:./ ??@,bU=XR1r|5Ļ,p^s^2H_J}W cL1ȣa$q5p58SƤ= Gܽє:aEVcf/_0>=;0lyQ"pJh&f?(MH,ZA]m?}M >D>zP/W̋Ov쫔~|R0s"IY 0}~ ҞO6c kCA6O R7MgR_7t",ęfԓ܃pn>ȒЮXD~m>6o,ҫvQm(|at쬅=݃ ݠ!Lu= ,H|քU43;G8ktv~8}*5iG*% &!*4P dCw<67ӃԳ}6KsB_L|O n+kư:!:jLN'|>uf{I g =u+$pOW}lj3Bc'κšHbz\Q f^(t)}ϴoF+}|Uf@u!OQ^d[Ҋݢk-tGi ˯TV6ՐQ2Y{+$uxőb+V7`zwEx{@Z. Vte{3ߖ qxȁ*T 8vYҴ Wp %:C\)Kd4uwLBdst0FB h%uY&62GNluˮ2ir5 ,ފX<3y̏ĸX]+̍VX*#S`7r]V5mow/fs"JmYBF64'%1C^S Ȣs #ڢb^ }3䤒%z,צNenKQ#-v!0Qq{ïsUޏ܍q r_i͒-/:˚3'i9cAc ]kl6'e@)F-ZHRa8pFÖ[D+(8i- DA ت)eS/Sɽds'm-e`fz2'FGW 9צ!Oԣ;xξSRl$3ލk+ౝy9w1FC!YD]FH5NBnW<O:gzhzcOEԑ 7 | S*&YR6ҸP%J?2燯wFdVC{-@=~$J ΣKcrulCm ㅤ&{[֏[vC2_*A;"Yotrj^9@O?Tim+3X ְbDgk hی^}/3  }`0gɻpݩ~+{h˯[:kYck%sYcw֐~ҁ+ui p@DNC7rP?)2h~Y˨:? Eq0pfje40nc%5[SeQ}r ޯՎ|2 g5,ͳftf_kdD!`#`; |8+i\miK PtAy%~rAtm ?b~ F,n{3ۀvx5D~A% /K>m&/BU]0] nrL5԰ v"4aɻj RŽ9n$ UCqVJjF4zZˉf(j=u]bdxBmay܏ҼN *V2<*cJ\?B ~*PkYbtUzؤn]Y^SaxUDW|Ԡ) :H۵= ukX{ỳ|ݬ[*l~RZ~h7bDEs\ iZ%J| N|?cʵ*1ԑB @=\_a@;//~3tٲVUq,󪺸o#Wlu c*؞I]S$CFN4C\|eV͜k(IXN4#Q7k~zoM:tV~!~";~MJ b^6INjCjP8d'JVf,XW(218Wd -!FٮNA pKG8 ^(/[l-.0m>aH+&!xy!{yDڎk.|T!l5ϝUR\:A1Q3KTҾ,<-0I k=g 4\gO7%Gճ‡LC7mb#n,ЌFn2aco  wĽ"Ź =Yi78=Y%yVuoOaeTElk+X@j!z;iER(r1p-)NF#91bbjkieՍDT2s=zj4'_17qW(lܭlh.EȽŪ۹qqyJuktJ j$K }>G $/p[kV~-H=X 3ޚr-%3:^jn^ed+Uh%P羿Al4Jfs"t F%x[ N(z9cXiˤCනqMC|ȋ8 ^J|h_@>Ƥ9[d1T ZL \gIkD7N~ѡ%PӂZZ/Oϰ"U,-bmJX~w9v ɎKc9 ys KpdTVZV#wZ\)XJ,0\Otl tͮHX4)VMzHe|HzlyA9OeZI.m_e0{ybѥ~ m`ylss~ə!Ic|`6yHZptٟ|=_mTmQُ++sz؊=m 4:nzs,i?;Kņjo߿qNccfJܯ*r>sê1ro+io@MHc,Q+m%`gX;=tV3<%Ƿ3;~LO5C:HLq9zbՙ^7\\mC0qqjj; 0f:kI,(j-NڽP[D0z-)~6DiCQc-\;F }%w\!h v}ŪD~XcKAT$$GoM`C?_eY$[ t[K QY,2Atf~tdw̛boL}>X*w{8aSD?j 7\Gpm.~aUO|0=ϺcT(]DaټpGqZز5]"6Zcؿ W"桵177_NGylfA &.GΆ޺( k$ͣ8c!~sZ2U71cژ|CxUf ɾ>=ӃڄP(avcnőUٍBFGA.h[ Ozjv"[ř-;(rB~NCs<7^½ff!"myY;07x@ĩsu6_cYr8`9Ŧ2C=ʑ5#6wXf('؅WKIe*Dcg}zawS0@`wYa gϬPhPGq_.GW+e3ai-a'^9-f $^x'ۢuj@V[Q 9RG~eZo}鰀Ϟ߷oO2wsUo">uo/k\ۑ\+0(e)cMo:LŴ7LMUf\*K4 0 NfC7É<;`vY~M;|"_ }~N`oOئ? %{uYciUA6L[ʹ$f+C>K\g)c8vaj:f$1#|v۰ylVnK֒ ޞqإ;ϑZhA Oj%AL]*NC+]3<7KC^\ރ͠JEHm]޼.C&gkdp] /pbwXQGI_wv1o1^\5mƘ[(300ň_oڵ R֤c9lgܖ ㎤x,y鄳=ٱo.Qz%"FJ-uߊe =kS;TŢPyǧ݇ a=i/m6@n>aJ֬._K7hS"XŔob+e5D@ &BxC$ќGDC my[$%d`"|O5N\)ba.PIo_,u=#N,  ؇UG,W v8s]h-ټ0^0U8QI&3;Զ}r!(2I؅IqI@q%GC^Q#qxߑqk-l1qy߮M:]mR:B,8D``p}"+6"Z ,5O2g'?'& JaX}FM~"'#=N6R5q}݄|^O-!1R ;8s~\*OFø;cR}f1ОK%>䲤0H6Y`K+ݗ9+u.y='B ۗoT{v91ļn^l.ihSO', Zқ҂n XE8?:v5ȠU@jof H\IYg/rS<"y˻h+Fr C^N"[#uE)4J?D[4U5!X_,^Ľ^ۜ=,/J3HSH%֐V&"Jr;!zE"98ʹ;xl:G 4>lP̮h*ӱ|En c`E8_41#Y0zR.,? TPGf9BGJs1I FNQgzT Sw#,{LHk+6s/\Dاj0:]÷s|0u)S-,o)uZ*R[}QS޵*N:Fy~5L/x7w@(וM]lsoWsrFK{>qT1+3 ju%qz̧47CTLf7|by#j}1xЦjv 9|n`ov$Lᅬ e9oyEɝ H(!&zLЀ4h)З?k&aahfh EqogО:PWv(}z-|Z7&`N<"gy-U\t=,)3uo7%ePf.2@zyïtV}]t!HCt/Ŕ⚔ )f,8^9Ŷi;%~鰆*:ЗiC[SPPEly+w\bi4B hFe|8(8Buo2;?|R}b) ( Z*ԺaG> XU(?~3)~cƤ(`wwX ВNnf ?`CN l@s_2q"Wl~x2HRuAvh4"@ᢦiiJ!lu-͏"oƈAPJ'*L 5^wtkbإ˚lP\:9,VU? pп'0ժ-ԟ>>S xcEVAZv256` 6Ƥ">֬9q2e9t*7Ρ%7}k8yAFO 4)abBXGN@_zT28sL,N eY ]C0j4lneia0끓n{L9421dU4 ' 0wlef Ž~斨1['Xex7eIg;VuT5|ڱ܋äZ$&s ^UOffrfj_ [ rE^V]C`Ӈ%}p+& sHMEո}[L'.[ GYx-,Tuij;EaBm ʜV}9?^I/&{j}L.n.͌>Hc?dۥo]z]fu q~ܪ\s]rFcKI16KN,$5*`hÙI> {qT":Yԑu&i 3yeL/sHoZm[tc=߂We.OZJ׾ 1KLL9vf:ڛ *D!>,hK4`?GWAHF8(G V *F~?W`%W9z.A|#10`7.PrnK9? >SV2ěsЋVFbGJ-q6TgIgB<,ӫ6V 6EۤP)$eNۊf#`eC2&* l4 \_v!e+qC+cab $ hb " n8B̸1=ңd@A1"ɞ^6?.(Ƣk,|^>Dt7 hi vŨyN=UIZpftۡsmxr_@?DzSwyWƆsƃGpK~4(3~ $@?輤*(R2ʓ=){pz2^|M"}q{*fK- v \ڰksV~*}EŎQ8ZRrOu(#}vY_L~aF_282V`ǠL "Iy(UOu)HU)k 9<.F#Ѧ]Mf&x|HĒKG87棎Li ĔӷiDGF^b嘽.KeD RM44^[ͰJW;s1:|#Dx^)"T `D\u̫F{x-Gm^8a5b2m`|@880Bܕ ?8 *^R$K 5GxQe#dBgy_ ///~3'?Ơ0} HʔK!;{ͽ Th*,u]\2Ⱦh~Jpxx eЃ"-?`I(PhrgyRԸ')&D{rVZnoo TE8$6T-Y=o҉,U(X8 sIZ8OQ_E|şGVz8_ ~:8\>f`yaDbml!gy;엾09S lz=he1dOkΔn }U3X1:x)LN3h"g;U/gZ\@˰-2h?k8 PWkvFyg$1fOգd߈no*rx"Ƭɍ۰]H=mvaU,G Dg= ^nDS'iPzQْ0E$-R00qM-ֹPK) |0#>!e5,4KRɱ[ʳ k;T}흡3Z1eF`uG`w؎sbr-8>UN04PB@ _)-p;k3Mzs&`V33TPiSF۫Eua3!LVѿ$KX?iSef_(#Pm02|Hܟ9Sa].X Ir;-T܉ TYp|-8.{ߵheEa/4ߗwqXհʳw$<5GzLa_0-ֈxbDf:敶SRVǘ_9pn,Yծ'(%x}1]-K>}}o)N: {ѫ;xI//ݰ޿*Nڅҧ G=Mψ]`sJ[v4\x#vЇ o[:.4' ;Eːp[:Rr^PɉX+R:g˔ eh] BNLנ#oVABqƯD4C%B!EvXӻDk_}0^HJщ?X:_Iz'SpԃX9THBՎoiij<#qۭih:o¯1ۧeZ YPXr*Mlt]Ƈ^:0'rIwlfWWNYQ˓.]E7#_4pcp[~&ǚ3 C`;UL7P &-:Za1TO9+ G"{~d ߣI޾:(a?JV+s*Hf?*&҆S4S{O~l%yp!L p4Q?OV5 "G@G*;)7Kf2zy8Z+ۂ/9ibRˤcfGVlT7p!6 'JkEDLӉQ'W=3m>{a!gZ~@ښ{' ֊#7p .|hCJ[\M+vvp1Ot}&N`za&g%^L1w# ѣFVBo &@6lK5lD:$EXH:ߌxN>6c\*55ý'Z_b{4R=k8[ZTQ5hgFR?m<Գ+qjt;k\/$;-ºbpRvGfAg k(qdt+ʃ>hil&8*&1rz]wRX0>荭.#C5?הPLM|^@z O_ _ OVZ?@1~rilwq4{>,X@c8*:cA3Ίe\{m1uz'L 0d,BDTt3ټ (%ЩU'_BKq$s3srw'?#a}*4A/H4$/ge *@-7X %hi_A}č8l\;Lf1ֳC Gq}4Tyi@dcFy}Lݫm=~iQ6GE5X 2>aR o|7 1s+/LMO!}vڎ#xp oC8;F_q/<1 roAj sZ~lb9;Mx*4F0LD"v Vi1WK fb뜠㛼X׼Mite{R*HɽU4vr'Awxzpk Iֹe"g;q^'AL1SQJ$ VFCi___ PL=kBrKVwО74xvgK?БW(JL.3lt9 0u&,x+ͽS8ʜ`za'#4 K\* a_lC|cCpdZj7*R! 0o('NT)s^<~ nsKODXp0ׁXۏR{r1}-2Wan;eXB2& Ɏ4=gtIq>%zt;;8Kj@@n1b䍍b". g9h~?0#Hh.M~8h>~" +PRzoj[5ΝX9GThZI@Ϙ;^ Û˟F> 7D JڸUq_¶c1fqoVrUzeI=|۱WMM}WC ˺ E]o>zpҌ]_y7`JUyC"J7AL\tK}/p,e!VK78mc47mJ@Y%_C)1><^s'!ANT`YsS>=AKg/7G0޳da~@/ڳ.>!ىu06W\QWBO q! Tއm@pv|j7~0?+OXG=HK20mÐ =HŅ^mָBV DŽcEÖ鎵&l'ԭS/j|5 $1/#T=Kd B(}-SpԻt.e}讝0Z٧MKx~Nh0sc!?ˤňʧp4p,v?l:t8pmcq7z6࿷ I}>Mdvrbq?V72~!k8墢z*A9y{ R>sv2f)faϋ"$wq2 Ԍ;)EAH4Z=JeS.dkз [iMտC|[XA҄u5kٛ?9a.,kFՍ_(O3\H(`;J׀,U>? ZO;'f'Jq. 8e HVsŖs- 'n@8`""f=%ƴ,มߜ /R QzP~A#qM/~4!T〓K|W4H , l)l?dn!'l͙!/(œ\N텭M-cyu0atn,ނ\,U5Ɠc)g_"09_,K=L}ʿN]bbD"#:,3Ou,aa+?DbѣaUB4eopKZ./]L<=VNˊ[!~d/͟)ki0 &ڭ=עk%!2]\QgQe%s)CB=AJa Q)̑oLGɈ*EjNwubkhvDHJ*uد.ve#TAS(B _ ||@> 2ts Tsa|@|j5vrɑA.8[TBgY6 Fd2zs1PS]<ȓ&%k:G7}4$"_wUf Ffn5|H@|z(9_0i"ґv៬m+̍%6]9u[_$j;\[ߐ{7]]ħ.@SMOԌƭyT= Lg0C(|Ds#Ꮊ&WYb|pE:ًhBXImR?[6O}(vzCu,. W;:wwƉ;-[ݽ­Q="z`5!+ pB[pɦGlbH4Z-MW=`?JqG%F&[H(S2-/LVD$J{Rb؞Bp^~Ѿ@Vy_8|}7JJCd|>~2 CdSo'-MN=ė3K5%O.1 կ]q6Iĵu3|6@ uO~~E*MȀ><꘷Dl & 2w݉iZx R?=OC; +i2PvORg5%%]̵i$O9Ie`O3 2u 9BtpJ?*U_&❚9$zZx@GvTG/œfHB? _똩}MUHXrL*~ioNvٗ$eH 1c*Q „:s0zIX8-~p2vvW*g/1#&=3zU| 5"II΂{c\/S\ۉd!rp'ol֡yx5֌5pHt"c[?rE ߄6T $8? C3`~C}c{VrǎO;V~8 yfM.؂\ⲅkXsf&mfdLP"!/]^ܮXhO*{9Tp2`|c\"h"Й'+ >m7 P/W@J , %)IHx;lv%lXÎЉV4t-V9'>##g2Y}T4%ؼWz YQo\7DV?52,.=:`lCR~xBREp-vQ7E(]xno?> 96KuM%¨4F0ˠ"PSB|B0TB^p亹D!YNJ۪/s콐Oͅq0bSU }hQu f5{|Lxǚj܉B;޸DNia.t*7PTU/u(B繡٫_qb5ЕDDeyMP7Sx<Ǯp1H%1jw[=2ivy}lek)3 "NbLdɢJԭIbcD+ V˂Dj[uv}FϦ8BIs”5Jkt+% :XY׽BA  DrxO'BNJI=Û3 Ǹ|hZHܩVu.S:(_6 TDV>9 ۪J0 |NtHh3P3rH |'kٰcGh^qp+~BNz+rO-h>=L@X7yȸUϕs":7GֱĂ_05frNd$KSVח3=@(%_ Cy>PىgJ| oQ%g9@?*ѡ({^Mv^- }aW7?wX_ԟ W+%ygY?Yd>% 2FcHҏ>[BVA[-F:h(dV_G(nҺʓ|e'Gn: bFB(w5+v~5tm]h?cI,rd|ȟ_%SG ?4 l{2k}EI_niX]x2cՉ瀞j._)Op=tP޻ $3`RSW/Ew1"uq_\`eљ]Iqx1H~Æ''E~6=T()Ȟx[lo^`_`o%W5()rԠɷtL%hF_Q`I:YVr"b {+k3l=x>ϙq{-DBa]qwȸ["!/o::o벇mH OH h"4bTTc˻^:Z?i`{g&Bf'Oi YQR9d܌bxKɗ6b$΋cόɮG|H:c\\(W-:/RbYѷ:ttB7OTw(ɦ^V+lbc^՛ /w- 7#vBd,:u2Qvw~čfY [K4+59Ɉx~"|>A 7y&վ&e4woQgwT_v*Iѧ)?(A6_@E4¥_;hn7Ľ`]wli,Ɉ+G˲I[fIB+-ua(IN甋Ny)}&evG(8l(y>e <9 EǴGnL 3XOEԿ&Ǝ!uMUi8D ʧy@LAT\ |A\iDs|@||bjhs ^Y!rW85-@|j*ܑCb ܆fk$.t?x4 ??Qqwu*95mkʡP>=#萅N?B)+ep;7U9ʑ G.NzXpzB6YosΈۏaWqƼaaɍri( T`X# l0n}FiFb/H[(;#y!mq?O_SgHpOk4 g2`:4KuaW|qup, 9{,]| ҏ.N&t6ALNDaOQu'@"ȪFV%PJA$A*ÍV\7Phk ч',m(kyjMm.`i ă7T ljxfs+R"/,b,"eNB33|>~28B}c$/~gb-b^wu[:(6r`K_&'7^SSɥǫK^Hg<4go҈-Vd5\V%p$kFUUVw@>B~ϳF|@ jH=Ff{v95QE[}b]ۭ eXupkZ|̸/(WZ7%>**qM4kcbԳL!nJ; q>@ngH^cH5F ] W-AJΈa ~.ka쥷+<9Fr_+xX`Y xtS .^_1w_]3&o _Kf׶Ҋ=x6 >Aѐ2$vӭgR'+rH2iCuo;bLih~hdHSjΣ-Q*c= /n7yBj̚jv%-E-~v) ~(@Rԅ]y2bNJǥdXMd3y,6Eʧ~_qCطB/"shٳrNO:X\e8JM-Xϕ`+gp<&5Ȼ:C̳w{Ն'Vz槕S9D++nEmVfVG-/~$Ѩ:dи;^ +۠( 'Zg 96@Fܸd`&6e`` BXN\AєwEҶEg +W?? >~ɀ][SX|T)}ue7_=\wb1&V^o/I3d/k0都n# {-E+l^ygɓ.CLLl XdSwsx)ᅅWUqG]sr!Z& KhaDTa%}:~^1~ܭEWs|8PrQw6`K~v("P#OILp4:L0pc#$wMD)Sc ?uɓJ@rItdqeMCI*=1OW'H!Ռ5=[Y{'{OEHYa,fnt:k\`DɪՙjK }(Azt]%a( -ZO>UHb| >76]>ہD0a)Q7sxtM=Q|fChIŽbӀTE*ɺVXoHIꓶ1ԷըY(0s* <Ӯl*rfj?zZ5 QhUS[2KڶqF[3\aK}8<PzA- r8 m'9Z>)s7%,[@,FJdCVa8|[QlBr4"a>@r̓fC^: ч,KDKǾ^SM#XKfr>+9q%m{rP}k̟ S_!LPȊU\8]iL@wCM#I"ߍfM8B <4OI5c"[*0,]Asd:4~|[mźl@j%=Ei Y?WrǒNVYS}]~C a0H洦^,IMr4EuPN"8l?m3KeqO+z3$?Lj S'].hQ׀)L;40z),'&fk~sFPmhtx 'g9>ڶ@v> V[ٌ*ʴtHg,Әj\)\ȫĂZ!—(1.DHqae?kdYhfmhvȱEryKى9:d-vU '^&niw]d aK c7Mو`.&n T93*E:؂#@ Um`!:hL<7N!Bɵ4CtQ;&Ut6G7Hbtɑ> ǒh=ւ4k l1e/J,d_=+-${9eѸ y1}GJL}K ѻ^4C6K "Dq?)cšo#2{ ~SP k8~ /$lhR9R;)'u%}Pܬ%;Y^bb`3ڊP,\\;,^VQw֙LI1΢~?hH8N"#,R7q ;݆<nJO'tykL}염b~fJ#XO<|(c3&['kzU([`B- 4l Z;L-Xn?Yw Ùhams"a%l|Y/H6#1bJjJ b7kp {.(S*`r}ӑ|lW1.b[٪`B:_OdvВ˦\0p+vGpCQo\k9U<(j/r F6l13ث JovTqD\ P'G!-ORV]W cnPQ>xWb8qѝٍҐ^.]Ad6L*=h$ZZrH7i|`> 2oAnp>k[t(ԜW=YF(aPOYgWwev}y%\徽K-ꮖη]`帾DS20Z zE8pMQIln?.lu#g?%VGZMᶘwx?f_FyNԸҾj騱_LEtDzڎQj󽨘CK7>_lgq^p aI.DN#lCfClp5DF?~ػqsPPmrNA+6xK䤻Rd orSyCNfea[܌*Jw1t.2Wgw\p9M*tl|jbE `y6@DF)dIbvkv.'_%'h[4TH +@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPOl8XF:(NG$?:z:aDq%[AX}46)<*rNgybmB1O dP0(PoL0|;@|wKG3>tAU[^pC<;PR|/z_^`<%TY1iPOLZsy/ G IAJǫ xȏ79Q] +|XhTQF(R~׻ۆcL,|ȩnrʆ3a棲ȩx'Wwӗ-?-2L3v冭 &@B-.8*y>1ZI Qh2%Yiƾ,IiFAm(3ĥbB*B/f@(K(3i;̭ov)@*R*~u%D;/|'>/oO>CZV @]_M{=8L 9eB1O/QhSd^&yǚP9%J/ "YF<ڡW1̯z4P9hib/._KXPv7%>Zk0l.7vZ!NsK+|K8VD\84 5ð&Lh"%yvR^0a]9}9 M&=Ye%&M!X5-0TWTtfH4W37)! }2{ &zD)=-!_b}qQEUhC 4B!T&Cݚ9iOuPjp/&v5ʾ_123G\%'e'gXL1K0 b I%([|eD3 eCYu Cm,+NR'Sg 4DNjV{ЈP^$c"Bi 'D8_tqsy|BͬE7U7P+Qdg>V$]3B#BI"zVճ!k e$zU {aIph԰Mcĭoqq/v(+kyq)džrspkxlFYޥ;*=sܬAOɪ|>w% "S>(%$%n"oZo1 xl .ۍY@+19zjH`]\%D7?>`{EoL.T/ .J3 /PoX`9 DgCRإ9F"ϐ11g~˧0޺]z1I,ȃ3m(b,d,`OȠ4DXxl:Z_;We3E$233P2JpO0 H 7|0^> ;g"DQnԠ_d_Bh{5cA^rgnM.AbAPsUpʢW=|v=N݈ߦrA;,WV!^x 9!'A/86G 11ڍnO?GXِL1SEM$~$+L pl'N:"@簾0ū+,(?mmծZ>; v}ՑFkS&m $@gj=n)rSqLթQ-~=g$'Ao:=M̑5RLTlf {9r5lgr -ì.Q[Ų=SJeF"i1PC(@쁒9NқnD;,৤da*|"FH橜7QĸH]jG^ )'"o_xH4zffU6*SR50"3H^FPsVYn zn_!#mX,1fAuq tBnjt <` @Fj|PDIކNlS8;π< 0$M99T?HPH*nnCh@Kz"oY݋6Uˀrϼ7+@"W.#Em}0=B G> e_Wfu"*ӳ/t'Q*Is9N <:A `ߕ,G\fCیƦkŶoX\ 0"`DqCN Xڔ%Zf,2Lm &߷.Jw&0u*8VtQc0];?ͮ=`.ͣX+>:ƆyˤV:k ]#*%LpdxvjRb*}DD%/|#fDEp2H~ `QaZ[k;8$*azVJ]kVU"r KcV;x(0}+H仃D-VF")l4[%L c$1=[^KI7hАW][X*Gًyt_89WR$ᔌBgp}A%+( ̰=̦疍v,岜 Ei3$8̣C;oWGoPzU\ Yi/J`&Oַ>k3._!kehQ2"C]d*?IZaxu)\+G6A.T%bXPm0S/fHT/B0^ \nqM*` bJqD1SQ]HO]Qɣ$?4D,+ݗ* E"[d{z q,f1Mbo[NpFK.ÏiQ 6#]Of.S8 M#w-CC cR@gg zl߮!QDVD*@_lH3CHjc 6'坽=lj;T6 k >KפCTD)cnNq'6߿}N 9Dt6#bi-OqAն8yԵp-L6;qtrFNȭ 2Nߐ@S[tГ"h ".ɥ5=+\JkUYTay_Gb—g8]'tg e"p2 Wx2?#7cҔe]fj9!7REO,zKMD- tT.efH eLӧ4XRpS*'_iy)Ս^CouD*~HR.HU>ɉe{wKHvHn-LWu㥻9(&:_vgrIؒT:[P P O>CL#%rg1jYqtwn37R i񌀂YU1AY!C}>NnFywz)NnZ|ߛ,i5&fR)vwVyh!CvDׇP1fAEe288wy"Byh*a=5ud'[*_g-jNp^\ͤAZe}~mՅ4 \>`ADH($73iL΀fjw+@ ^ұ,لs aG#şpq }/\wR9We+ݲs5bA;Ui׏2fu1gXJn\5њsaz/ 0(S9&p#},Ǡ QmyH*v%a7.PJ@Yf}*3\Ã91oDcʄ+b;Fړ9 q"uh8bh4 1LSI\LH6HDId$cp T(|kZ7 il+ݹfےTm.ն8w}uczq6$֦4o b`U?A|=_T?3Qr%|{tGV(~I Nxcʅ爀7##n7D9cE"id%zϕ~怆n>8~IM#gFT`<4aC.qZC4S-z &jf퇊 Bb#M}Sqkry)Э&gz!n?U}#NʆqF"So0;떲*6o}A_ R?Zq㙭{hJ8lv< ߔ<2rZ>Ub#b8l.lw r[g3\f^@u'y1dvIZvEpLha],q0ya4s;J{U57#+ K B=GxR݆_QB Xƺ=[ SV~t_ن1ҕş^X~`"?1*٧=h8ȕ ,ĚƜ"۵w ǃi>*^/5$C$UJKt@EnNjO7y :.6Iֈ$v&2R#368 u"~pN#ˬIrJ!_U8|TH ?|@|> XT&(-^*_&ZO@|j"FDt42V&!< 2g1 h98w]'& :i3#%1,4&rOFEvyL%ldP`u|jf.>=萋9R:>pMHQ]/h~v3ȋņ΀LYXhoYsάfBDP*di(K/d^Vr .ti`ELBS`CAM@OsWY#k)r'ZPpy.Ό߸_&ߢxJEeB:M*ÃGx<¨Zlܦ)[9i /ujݚ({cI?`8Oto_}>Oh jVGG) n%'vV~Dԫ˙_Z0%KXN)CN"۠_ӭO2)L@EOpsx{._sOQ8#E._gq%ta9Tv<|>`~2 ;u$~ܢ^2U+yS;7Y%˔:P;<7 C8k-2v֒'|p 'ħd%<d4wpEUVI[JV^= "ցc3my~ѧ)@c\U+©P䏔p$GS _%+h00i>.G8~Y|نɣ֟/KJ UR9XO=}hc p8m< ntN?Ծ]딾uǬf4;͔޲]vEdh@''Wi"xưah\i'#x-ipMʴL2p$` l,S7@䈔%tFb&e()Γ'r5[|9ʼn@(YckN)zskDO-]fR>3h.']8#!+tg>H,N'BZigc n-rzzN)\Q@pƝ>o@"$@valpy2ATnhЯVy*w߭A G*cʾ&М"QBhVuvc;6(n!Nx ha5FBj3)Hf]X#)no0ZE>b1 5Q'ƭ:}:ZB.r>FeǷ bY'MUsX{տ'ϸ>[͎-[Iе|HdDgLt#Hy= Ḱ.YMrYy̽ DfXob40(T$QF2q16L&"/$֒hNaz#K7imβ5n,Yvĕ1m)}([fCJ:SvI5xNdD5ɹ|uq 9"¬sϞàNC>'T"pi&*a61JwraTo! ^"> pk|c %]DhWD!0KgE =+T%(ɧtzƏ$7T/\NL aT\J38r-5~Ӥ#yB͹?}#m?$%G*/:Vj (7ze[!"wǍdTJdNmWDW=easѕm5*wA9 v4dQc  ei]Sq'\U^ @!2`i7_ݿ`YAMe)Ȫ0b2muBXRBI=$`'^ dUGw%`vZ_zAp;>{l|W5rNEƒ-8/l>dpV2[K'F2zKwMJ~Om(.S$ײJftJhyb1=Lp$< s\γAbJG߻k~ Q'cmm3иHMXO,Rp%" e+:G73/G$o_ˊ{ͦ8׽3BZPݗOdžt,E͋7HWr$P-38ѵ2̉ZHp]؋% u׆=pb5Kj\ם?Ş,ܨc 6ԃ&'=c! ΟnbgkRsаKaW_|,Pe VFR)SQpY2-d3Y-wGňĝ;[ӕojBI_RfȜ(B`UqM8̭vNat8?t9H;`١.Kul޵լhx%`dŜAG;Z/Ƈ,'c5W,E0&r5k)Gt |J_'*0h<< '\~&,$h*S-V"ǪQL:tdo|.$ЌGfUQp>C㛳 c]BY ={I*& W2OE{q u.a6 Ft=ZBlIq]ILZ=c(LK@ X [+NjȁJehLˊ= &CP:l+GXo,YA]&nLsw;YC\<5ޱ+"wFn5Ah;KXf1BIBZju>n`I47GtK$nS],] }-+Abh<)Yl{N {D"' _Գւ]8[~s~,oVq+OJ2XjL:'ex9ͣ{(DSŸުTLfNuʟk瞼' :fbׄDT}+eqìS9%]#`ѹIx=_ơWԶC"m ^a9`_o8CaO<% EzGIKepK9JAO͓U^J8$= !\+ҐlaRxpO4`,ƷHGڜhu{So_o=I os.L8J"V$AȘ\;}t'ׁOJ.{](fcmmwT8{l_y[+Mdk : _CvJw¶ǝ0a1**FumƗ!XoH)I@ ҆\j G㭴P11Y jAY*jn2_H p'̹(~k NvGߪi( ޓ.X1Dte7%l>d" R6AbT&oSA N;IO8aɸIvޫ:QӬw6%[V2LK=zJn|ޮ(Q1vx\4ެ'dK[CLYS*+RmtN]X rb7`4 SkF99IR( &p K_fN2Ni(\k_90$DZW_Fc1HNҤEI;%G@կ2jh͋4!Rr{= cta9ͬL(o Y` %=tG#HЮ)-Xv^8~bj P#DbT\1hSi>CH[lu+VΓYS]k8$"}67E6}]Dߘrx<)\,\H^sfw2TA_W`ӭVJ! Y'C O1Ѡ0n _%&d PT@|>@|GKE:ˀ<#!@@9V0EpK8KS]+AVn_a2؀fȃk!pOĽX"Σ Q?dtA&9t:zj>_3F!.p>=@4e'/ھ1&Պe Lv҂%j8]y%Ӷ|[a5J /g]9DBk}Xkf7aU>[ oȸp*;*KRSH<$DJ쀮zRreÁ}UwJkhS(=1H LtGbJhr+$ Q8w'w|: B]RE08Q&6q%ؠ!3 ƿ1+QM^6ϢFzˆ **y'v6)Ȩ1cb8@> %GbZo7Q;Gl )˟E{2i;Tl%S'y!JWq dh|>~28;mtsfv[ Nc+V=.r^YS.L9叆Hh0H/iB!k|]{vH$Nh.e-LrC5,hSkRúʺ3Xz44a<@ςDX;IG▶_pxNxHQYoT&=q QLI0wK*&pI; f2|F<(iO lysk4lnhoLXCɠ՚Ly&s2y0Ċ%9n3vDDitA~v/U}[ί{֟BpGG4 U"}CwqfqH%> i5uF6os^Z]b ȑbQw K ꇹfzeW -hX}T>  zpM^rhۛŞ3f́ś5Ew:("#[HVaGta CR|XK 2N9GȾZ{˽}«v{z|Ɯ>[7'mFa)~"˲˙enZ:c٭ޮwExR/X\2Jү9zbp@;H1wGl.l#1RyeѵFm]Z7ȜlA A<1[x*t_ðW'X6,ؐH/(Emo5\bᗻXғagɹLF471H@U.H%[ x)$d3ǐ%o޶Knno')u(>z@Jtb86gk nu)np쳏zd'T?60-h۠G%exLH>d @Al(g')3_tMiUMmnTΙp10ctSڼ0>=L%0kuyB`;E4tj**I A#m NPYPSu]Nr0RT}bd~3:tCeDJ#ċG 'su.0IpQ~W氠3.fPLHgqZ#E7>]x- Ws%Mgvfk"Pea,7wV 20WgU k;mV EC3c/L\y͵ bXvîI% `21Yc@ s/>^HkHc+q)0f+SMr~ͤX#dh$>y6W;(.1yG[H?.Q.:k~yPsW*[F+ -> 0]'CمX魍]Й>Nd)!*;H}) 2x Q+t':g2]f`C#-x8ӕlǠ<KL_ԽH.+ 9!Kbu륷 9ç*!n{y?u ϰ.fp$lJNWJuM1EV8lVAQgR`upJ[U '#!燂<;UXWNj/10~a-_/R=m=s^E鄟Z;h0) &C1;Ÿv:y8ZaHT[6T( . )?e:|g~rxB ʳݡhhIsƃD"2)4?t:tfOCr%&i|@|wUEG'D7Q´ IUtl D52~PMT:S FOM!B`o{WawF>F_u%uBڑ̄߸T;XA̙7n'9 zW7  x3GMɣl(9N5\p9oS}MC8t\'j:C "{rѮo/LݬX[v@R{{8Hte{u-}8IT9^#,⠰;l833D{.g9oT^/_G ?W8>}x\ss|6ⷘ/ufҺve+xqg&Oh\yn._Wz+dc%ne@$,bR+EO`6Ӌv0!13 w11{ke?ǏJ4>z[n3syA묯eR{)[e8T7hC'{мusOl?LP8آ5'ݑTkǺFMvV,LGBHUV5!@otΓJ(cg_6_4*JGr3T\%O늓X)6X.I,E :: 6<|_Co)9H ⰓˌYrj݄LVMYfs n$=kp UpPen Ea,*B퓅85nGS5oceBx+vNA``%%3F(bEVot; MQ~}I(2g&t/斉yQ^?lcCT[(`Pewl~%~`&:[r8#gt~}C@7q`Ԏ@e4? 9 |8< 3v UN\܆ 1XN(Sex=k-( 3- XǺu~2W+R N2sry$}q'eF檊dtAOuFֻob-Ė9T.$e\_zXi9. gQϣߊ'/ S#Z!a|m,( bť[Ǩ7.z!Nz"86vq[Y[WI8 }0_K\i&mKzH3$X !Cdl)f&F0ELw+Ͱ~m.lk+;IRq<3k/ F8Ev`?V02`V|z@RG#z4r :鹳?l!Lt5(S~B-n }uηҊ ?İM=~y9jk*]>e(gyJ}a2@jؚɡ[=+oKSn%ǿ27s ##O^T@pB_YX8ˠЎ7CD7> |-~O!-]c`;Cf侙 ȣy?)dX1f+y=9-E[:hwP薇h%* 2qHɼENȽd$bMeR#=hp)w )ie(LcAUC, M(P)^O=33Mk}PʷSLT/i2 мC{qy&ܺNK,[ǧfd YӧfhkSnc 8`h&5إᇝ_C2H!GZL^iYX 2\!滈b[Jc'r==޾´~Bu 9|7 TJ|7AGaqn RY'@. }/+ 6:o<a N\IP_EOƗa}Bɯ9}7 ܁tFO+fjH\jUb B^8bl')2w~&Ey3z}_ O+\ixXY'bwu $2btW|aB$ }7diИX |n"T@@{oa-ef}:bw$_"zjSS*#fsƊ0\-if&XjsÌS Z(Ny4/ &a1jtfk75 ۤ~"Wс=W$5/=Zz\I5Sޠ[ :]&MAѵ,Е98o0LH嫊{XU҅8|91 "zuJm+u" JlfuI~ـ@at(Q)S1{^ԻT|XG/H;lSZ_f򤃿5sdc`2?7+&dFgWPX-Ka1Ps84A5v8U]:7o[T> lZlgTI&$IwǕoS؝ԂcArlȱd5I=\F>4jJ 3}Fz髳NYJ w%$fUG n.Kg|CzDY㋸nŗUfdvS~=~AICП]p1:+ 3.|[e(D%kT_ԫ{ n,*/BC8PCFnݙE`h:%7+hmj `V]Mj{RÞ <@7n2=1}11у\V{j2 @J(+[wo0 NvX@e=bѫvx2 ZZ;8{H/!B'Շ`;Rdc&I7x%+5K/i&B@YBo%f2:/F,Г ySJ[wF ;o6SOCeo6 eHv=׹4&NX#C_c!4o=< t)n?7Xآ4f/Hm6ԟ|A>nbǩI1ӦOWx#1*N1b@Ÿ@,a%WT"KޟY`H kؗr 7gN y10>*aꍳgybt65RW&{ G+Ok|Nę9mPʥe]0ؘY8y@l(t6eGGkد5CO[={̺:>w$ۿp6g%ú(i amx/GN5p6oJ]Sۭ 1-hRXը'cLˁ 0m}a Jg%QQDb2CT[ ȹg2 H]̂Z?Rn29 qoHC rk)k(w6h٪x,/y6~鷃)S{îrw˖2uZIV,qD+\B;.޴"_dٺa̘dxHyq_p.*ggM\L $L:l!cMIKW00Ov$x:ĝ ;gT ɩxUG^S|%I?- ,'k?<< VB"8m%щZl,쿄yy;ZHo~P'd-<4Mj uv5wk)!!s :4*\ԔU:W{ӫmˇxdPγYI0T7GнOtL nI-L-tDr̔xiߛ@ݴf_Jٻ.e-p$!R@vF1K/Uh Co *9Ycg *p+د9c1?$d(y7^#BWOF _@`q`Ūe:w6[TEM,Ɋ!V=gpj8lPbH-*(1YP!k3'@ 3}tPsn>=‹vp xCʜ_`ҙ9#3hglu&}\4O)s HHG }AćLM=%3L|~TQ8k`UMo> Q?<\˵tW_DolXcN yho?d,|l5/%"yu/]GMfKL820.7qn op:ajl]7:*iJv#&OP(6sW[2yg]&\\S!O8@Ժ!:,G 32 )=v0%}/p'|$/@~{kOPFMi. ~Zf―O6;:nP!"@>@~ԡ3XP'V&~㖈4n 9!Uw$$AqTP*IJ r;aCcɝHKޙ}|W饁8ҽ0N,2wδtJvQ9;VSܯ=](5;n7g1G3+%< ;y`uv f0y_6D kwd}CteViWX'$F[&Aaor<)(GY,` 4T|@||cd%Ϳ$NSfvޙ?| Hay;;Wq\59hʭ-0*]Lr`mzH=PG.V3GwnVA8rg4킩XJ+2?F#P>='р?ܾV(HaN/}0aƉ#DN2 5*^pJm+l^)?4ĤK:lA?DJpN㒗ȕ{-33 1)0xȡjU7h`NqӾVNo!Wۘ=< dž%cu]&O38rX)}&DM5h]LEC)!%.Xl*ߩp Q_fHDzۦY"=꾽j*sj}Lci8'd h20fb孇QI4L6E'˻#a5Ma" ^!Nxh ?_ԬS5T/R9H4e+nuHSjDF8RcޖɿdD,sT0KI~kzZ| [~ɋN_hQ8ǵS^[/Ⱥ-GLM ; xs+e"CH C(&ׄr|>j/-:H$.Wi7\d~0]H?Y;ӔMmLT>52>ro\mg/8ٖyl$m|\'Ԟq[d7'S~PeG^Km96 (RP?*NEb)0)uiCONF6%E8L4G7 "+2d'`\f3[n2(M 'Kw g2Zs,rQ/Q9#_'(A7cwe&,Gޭi =o˓#Z\ DF FXO͖%px]#TV\KN%:^0H`sR`>^T hrL;\\)FZVo4>8:HUϿn<׷tHb yJr%UѬهd?E4ѝi43v5S_b!$:%8: {:Tr/poP=EB{2S/5 ^Iz\c1!NjH37!esA߼f8pQkS>Hw,IFP5679 O7&`EGw8y3EQK^qkZ `@_5%0ޙ& K#wjΩV֛7Dc]k:&=YENMlg]Cwk8H>MR )eW83͖u,ϥݼD+C0[qLG~y6 ~t\{`1Ug/CRm}1;Ӆ@Sw#mI6#T~ ̱X#Eӛ&t@0kTsW* 3_.Ȼt.ӍQ4WK[=RuOM8zy\"&(_N{ckU2oa T,$nlI{v9vػp4565Bg0j OV=FK< ;QVHӂD۽μ6Nw+&G (&lM a 챟$5V&S+xfڏG{ͲkO-10st8ۆ=7ʪ55EjVwxƮVz]Gmv+{B\#_očR{lV~<Z^.Λݣ6E6v̨вv-"]r3l Uૺxy\_@iE+'vzh!_=u7-袝e]~T,?O|}bm5C5H362r%,/omBJ2qadz&;QaK߶eS_>H2?-(6P #7=Yۣly|e?LnR> eD_-C~SnrUR0wX@htI':]^'=[Ylh48~+Nh(-M.H|&#ެQɥۼy@zkļpLbnUF)qcK#|f 5cZNY8?XDnQxYm+0z0m" ٺ0Ń7Rql#4(j~;8r!yWmzy+".Y"e{_s)Kti  L "HЖ0x_~\}$OJ*H"F wP3t*S<|h]Ďv)Q~Hl0~cEqsh> Lx Z^?Dy'^hj:4ٛ~m]F3){l҉މ3TVO6DN'ф*Rr c4ˎ? ;2_u!^?_c '^MBfa [-w7Q'Ÿ"ՊWxv"ಓydȗWUTe Sl=V .QTgI>bB8@^ >F%s/ _cgaVG+STM"3v Uܠj5m71ǚ) ^eMv靼^e`&NubdVЉ}OUL=H$׋5NH_^a%JY;3QUp`JU+pHN,jlςI J,rm,;)vC7S:iBVh!9ip{'jEPkVR4*$X!,gQ(M1$*<"`f7TwkTjd5lg wQ;6jI [^} ¨#1c̀:5qH௢1^(xElImq C[~jm a K=Ll1Ң1؞{`rM-! M2ss } E6F౐j)*:KY8܈>@)T`dO.Ҩ}^,4!L]B"(lFBW$b}IF9$'y^fhbb5&K%] +iHWԇ#[@6vˎtYq݀0otvfzY:JYYLgM0q)g7eJZcegJ< 2nVNZM|u2(8(d\]GaHݬ/Ț˾<:ETӀQ\#&\{e}efۺ1uYwc`JbG^vg%i9iAfͳ VZMBG][ĬɆlUSKZmJ͖ZTĠ9cF@1Dh%t$p=#*G[[o};K/h`ה r 10/б?P~Gt-bմ_a6D,{ɘ# jwP1Vn5Ԇb:o Kq0Jab/E.1묷> *A&ySRJܿ}0lY|č@mSW)fe$戣꽵bxDzl+CKޫ-v7aeAŎA9BE_&ePCP"&; uaC]Rh[c $W`rUM$ )>V\\jh;NB3ſaډN^^1R܍J-:Ɯdf5OT!ͼ[@u' 9;%õȵQ9<8wb;^k[l: ,䲞( ^[ΒjgyofؒoTg;`LFnNe*xVrq~_E]>' W '+dZ]P\+APWE9i_ƝK.xoe6;] U(ق}:%XIq`nU\  \&^bO>Y5)W'22kŘGM?:~^}fbXSN/B#PR}|@|>@zHFWW @?wJ Ţ|j?/J{$>=xY^RD f:zcjnSǠ k LNA}XTC~B Z?i3NwǙ_O:5|tD|w4Q.|_m5>-3v,'yCt{^߈z c1eHI.>uáᙴoţdVd SYai\x!'zF+F3ۮr⧆9euДA6VD1R)1pjR:S*GozA͕:F]0cYɭs0BtٕhH% m9>sL95<W ~y4!2qKT!FWvR4MzgxiOV\VHNCwMs>l20b>(NJ4O_a{9]VPq]i6eyR3{8y46c2QLjՀ>?oKz-ZI=y'&9sQsݷlvmgO#ve<cbFGS2p!u5@d΢%a$ʁkJz=D!}}Rq8ٛ> fc3n+{P-I}NNptq)*z!ybR==_7pι\#^h"K~VE /2j"eWyTM?)q˥eYζaz!A%Z7fyǭg/$go'mZzƞ_0[ 2tQDtx^^tdZoѓe: җVNPT5ctaanJ"ό'v=5-=h_$pjDu ^]) $yPG8c`R#yU?V>k_ w&9GU[]Kgbyat]R0iӶdJ,^a|E= u􇭺Dc&?'(jED>cy2gҡ?8!HoZ{"')E"%xؒHϔebFsAn&3km[-.tMS>TN<"5m͑\**`W" dy}ZiC ?%)Pq*4yUl+ʽQG)_Iv2d8ɷ[@XfQfx]L2 hI'g I!jFx\~m`2nT_!hx:\ !G$a/p-G9])/hDҍt8O L+.Ȋ2/zI#jM`]}q[09:?2FkmUkJxF?SY0kϙ\Yƌg$G_/ۺ-7g2"&2X CFEx|y:75D+)l;`ɸ?$Œ ^[Z2@*2hu#=T@w¦M jcYMtja{ܯɭ˦&_do5ֆobб Jw. (+lHiIˆ@i$94UMHUIOBqx2LZ-@ c!8Er`FkAT#@ڹqcdf#r7'\fF&5IT7BŢv\'{5@b1w#w=C*B3ae:ńn*9xegf'AqZ#gתO jѝƕ1 AvZ/ݲ&?Ea סt1U#؝mQu0vwe6C3}-%|%xi 4 Lz.e,xY^wdN騮{LzAwJ,;=3J2 a9R-fmf0+ VH/ { .,뜜HmNGfr2PmZ/Q3睚pwcdS <ԏR(B߹ŅÇ`9֐Fgfqa7YC8ˑ.3?B)w({H(aYBF·CL0CGCg8^wIZ?&溣)o(ܡ=0Un"{#yGAcBx.m-Eޤg Bt=/Wib_"kg.p2k'@*mo9vbyM^a$%٨e+8hqlnMeW+n/0!64eC~h'bNߢLkm[94n0v24/>-&%IyJq5_C2z4I18_/7TKܿ`N5~ֈQG@hW2IP=L(ɶ-UPrG%QN2'J KHY87Xڪ0aO:ڄ%] s9EqN(/.dxgorAcIEYrSj2?/(T\KJhC4Kzj? -?RS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP J`ڟ:,DÀ"Zp oQ?ߞv:>@ w^o_ݣ?K|mtq Jw:,Ri"+ToKg0!'f/:QhWxGp|> ]. v.3].8 txfeډ5i$B=[W<,ƌwnRG BQ6\|X"; x:^k 7 8`yizGNYRPҺ6zܔ]%͉ͷTWeqA#_jٓRAֹ8W0g GmҪD< EH8ʋ֜r2lQ>z#ѡ.(ɅH{n0"ShνW,^@69`%gq]j+6N4v_| Pvr©C*]ï'$oI@wuąGy#u@UyDM=%,;yr~/KǜqZr s|F\ zgsJ)cKE֣]zRR~uyS4@һP`/1Z)^:ɤ/r4 QW@[IWqpVuQVrN;#t- M12X7 9iUZ$$Wi'ks[WpgX;7n.7*S|j;cY:+K,I%m$681˰6 zYVoFt˲FUֽo$Z7Ȋ*&1⏴'PνJcP6}$4ʫF2b0󎜣)|ƹ܆wUk|CB[A~>%"oP h+,-JSj=j/dAmWulX\u\#=WUX4."Nkpbj_x~EM U|[s(Ѩed=<<_"4ᢸ.]5Y㽼Gj[?jJTd"6&)o ?j<̑@, I4?D7µOY?'N?# \$UVio2&5i#eV <֚|qpt0w^Ƕ44foZ[)n6C40%橅"do}&˅v,nGA&]62 C"0-0޲9,C|9 Duک0(: q>mJJԌa̬Mq#7Bxp"+VC&?{q|p jC̶M}E0<p&=L&)#'Q.`1@pkd;\ދNLpsz[/ 0;ߥѾֽ6hwoh(9H? Џ!j4*^tL)>c)@.K5WK :XKdY gcqdNG}c}l*t/10ý Ӂmw#T~> LG$d(fcqϚ3.%jіWM.:VvINyGpK!u]U"լ*/G G)?lkʁ>/$a^#gϓ2ncТE.bV-9IŲ|a\NTVz@(f;"ZiQNarLC$e8&OMI h=*;1@z!zn3tylNṆFr +RrPNޞ4b4eL[]\޶Ki%BիnFDfF~3:)V ]wL"#E+2cQG=KHGX_J,05ҜHUyNh"U/%b8@D Bܙͅ&֥QĤlUnv8uQL8*Fe*U'i 3;.7ͮ0UE1BG!TW=2t2o3rδ%x ] |έ lefCeޝ|TTmMvZĞ^!=&d?)4t.]xM1mMJ 7ӗ"[+́(şnE60&/ca\.j*0Xݥɻ"lj",+VMjnJOy+̓4HӖk \;6Sv"Ghҍ*xfRc" QpbjWon YxnF,(k:חm .w[!-hȺ/O=y!vL^ YGȋ"'mm]@]V?Kt6M?.3#.:Ll\?(re.K#Lܤ<)Hˁ?|px%܈ fXP$Kaԋ@l_x57%z$57-6 ᓾc}9fV0Vu9IX/#6Ȟu؁M?uyI+6&?^su7*B=7Y8pgsEKT Zf 7x*QRӯ%mƒuJ'D7i) 1Sm0 fσḱ^'4U3*Z[B@:LSLL@%mL kєnDgP^ET/`jHo"CijQom\c [ZDnǒ&i *c&tgk7wQ1<%{Z~t@m2Hj&-: 8)UJ,p[ۛ"\6g~@>Yț? nzۂTMHnV)O_ɗuv.MMM 5KqxP g/w8V"T+0 @z@U<(ur֖zN:pO^ y䦴 o3W_u(luj)܉//d:~pZ/Grcm*oplt :!h6Wֱ~II;N#D^j!>R bývԞه;ݱ~S Kږlxbt7”w<} [DS$Y7#jMI&M4`u!aS^hx _'|̹iC*~ \mK݂|=Nu/J@ҷ{ 5Pgd΀8Rzw{'0s}qTх08b\Zgޫl쯲D9w[N6kޒr.H/O9 ]$oR#-s&£w 52$>[:Dm#DVy ydbpsc$`Q:1DnYOxCX5貒5;H(w#\BPelK]\+ݮ U Lm<,Jn,W=UA|@|@>!߸Eg;`$i I@@@|j`Qx]n) 8r#5,y((.P Uܕyc%+Q{AgiZנ9& kۉJ,{4|υjKe^?|LF|wFJsٖ=}ѤWs K&Qq9탎54]$|j3b$NC䖰/ M`0bl(фc(<*V33<̓1*υDt֜pu2*Vs(^}OP=.T(IgxR`[Mt͗b!^ޑtn:!+QM{ylraNg1 Qf ;- ϖ:C2!A}E1sZYnȀ/GRЁ&kC.Zm/Ks^$=}H!B=r:*OͤmqCs-!,;/|>_xGu}@a˕h1*‘gz2 }p}Ѩ9 B{i֞fքi}Cy7OEJU@i&M"n$!5gxOM@+23)Px[_X=2U[]yHKL1v@ȔK'*vk*eyz2êoDLt 2!ƒ8H|qGz\+- QE %L*<ʞ +vCGbڍa%76(x5gg?M3 9_$͜[_sɃ[!zۖ{(kf~ųIű?ۊ|١*< DwY'AQo# E-j!3 k!tJ"O9z沴[bPk-}ZA'`!y.@n46ߕxn<(UDr>C8Y8j[q'bVP0qcP;G@U jn4i?`Mo՜qRJ֣?G4Q.*fCK"Uj1"F#sTQy-iԢ18ZY՛-FƚXx$Z&bg#+ G?iͻP] M.%lE H% E)⹉yIT Y׋tDifS #/c[dOJl,_,N4liFF=6-+-.Nv8$%mOXFBLOnb&OEP2V5UG}t" 휉;j*W0Iiq=Ձdl]ouC-Wy:{D1};[G qGK^ϝvafcsA=~EWedJcom˥wS!@Y؂00&~ͣgQG5X[N25JV5SOm3Buy oM%MdWT—);`\C}7q-v9VuRhF;1 IkIwV}Df̱YnDtiPz.O{4aXzJh+ltխhcY?$He)EB֟QRT-IإTxn&yOD xP u)M+^%ؠ7;$7*21 B#䉲ME5§2So_q}ҿ jCo/7cuviqK$c%t Zt醙ëjf:IW_BXWf(NnX&4~[EIMi^giSI_yx[ $Ih6$zo 2!L? *Sbr#|fUuk8ym (؀>uKPQQS,(l&6[?V8{R|J@ޚ.gKz^,b[\Ҟa]⮃T#fGuդG‰__bG{Q,KP d Ew;F`ܧ t}d 4PJ,"Ӥ>'"!X*2AXznkHZ0+. ;3A }@tayM;Z PXwW`Оu[7;,#'ac=&fVIK/'0* "']4&d,_K ;L\sC]IX'IiYsOqyGpAHKt/! yHn:-^PCzeWY1o\*4 '^"rb F{CVpO0c3֭G[Cf$ 꺊Ӭ1h2\h.WK"8%+!v\mؑ-o+0-J\q` &EV5iFK $)a }]4=aw$b3L¤{0ے*As wp("z;td,[n6ὰw_L?}-Ye{RhRXGFq:g_!~ƾ S@E0D\Rō]D'O)*Yh-S$iκ{pDƠC D Z]!AĕS %}~F1y&HUO{x%Oͥcݑ3&d]z?SS-ȿXM'D=G=r a5ڏ@J .\^sH/C-:H(ʳrs—^B3šdG"JA'qi5gޛ.G{b?7'oY=qIf`A Ա6ę6;.|Å6Gԓ2FXkȸ+|m$T= /N-:8+U3=KrIlRTm2F'xC-B2nB.Wb@1m**] k崙{$c_X((*Hٵ+-06BsgMN IϒךBžnc NO+$#xOCl{FflfsG CϮi.n J Ȝ|-='nr:2f,% ^]dLcJŪCi 8ې8b:^mπKA6XflмO1huY9EnZgd0.6XBY$vf1'#ͦu 6S)0!%Ŵ1k <*3UeQs\g-T? +:g1R!5p<|f% M娦4&9 υ+Q3G6b2řK+*f'3r _N%e~Ļ[~c|Y1#q^#*sYS|E\}ɫ cԙ1z(=4V ?.]墖Y؂MB~'R1< zlynB(Sit2$Df9E>jzNd`G)KNB+Y9 UV :)e}vlRd}6ڪdc.Ϧi뗕NG]ՖfaZd6>Po@ P_|,F|wOOdLP LҎLW%3"׫hL ?d֚h~|=X^ژhO Zo%?*rXHKu6oB8r8hm@kSɁ0 ;uk1ZI5$rҵ*B z}:pCRYL *zǤ,3{9UxQSl9-eDLKȈYb#@Lõz`tMgS.׊_Cs|MSt;Cn|uL"3LV }x`__x ;u|:22'|6STV3u[wK-p929{ 8׺(0Gk|ET^.8"+Zi]G˻?Cq+\=e 2+{UmH Ko'B"є(ͩ#Vyi\cn`R/ 軝_q?I ]>҃9vI=DV82&Ge"-v}s{@Ejҫ`w{I;1Җ󮸺xb'0Tj|0@SPV_T3iM? 02t ca %T:_ '솁1\E)J׏w~ ?;DH>8n7rP=;u.@egƐI()'LH_R?^k`K#>$.8GC/⡢:}b:&5yD 3bǮC9BkŅ,,X ˜S[| Bd[D;9NTx8+k#Dg4+ͳH$^#0|=&}2' FFi6X -g_yܜCjr0Y!>sGR\v`4H<پ}(|=krkTSEi23De,VB:SJ2cB^0+&JeOJn1ob=q,ELw, ] :A$ r8$.q*fmm^QzPQ,!یpҽ1(Vh^{mʬ)G(ZOYIHL6v!ʖ@@dd8^{ Be-[ `A]QqNwVAk_l.ͭK.VyjZ Oo{[č+r+W3VI{B'/rk:)WZ)PW,SW$aVR aj~${B&'zMZome"zvK> `.V?p7T5߇G%<&eep1i:Oi9e̛Wb<' 1ӚLCU1ٱ?ܫ^]3cəQM-3] &y~f>򇁦qsCN/8w)|MS}Jdyyc{jY^mzҢ;) DC"Ys+o"EŦw>v МY*lԩ4IJ++3܅Hf2.5n/:F/YT45ѲG͉wI$M?,>Jҵ,-XoiIS K:̆uhNxV0*,L[{6b/~+ ߀T6V3rl9+wgs$mP8 PZa_OJVRPf71L'5讠2(ֵ Ɉz)wLTBgq3vlȶo_x@ml@; nL\+t]eJ߻)^`#^$If ûzܺfن<"I^ 6˸FxlQ=< OĆ,\ԠMƇv8cN#Y곤kh7|GY0XB ;5HcqUkNT?ibH{4g>a3HH n3iHD6l3@1$_Wun|cc@ZyCcTT"SkLkhvUy~ʇf]xhkeחaZĺޞ=uT6#EI=dӛ ,'#nn^G h憠nCҭH% W|f xeQ Ab~J p]~ndE3`c?ǁM+'Ə7Qij){mIa~I7W={`@z>tPuG4K pQ@QQ +`Z D#ʖY"M+8!(8jBYN!„ӄwM= 6`un2F^ @V+,BBs_Jt|qz׎@W>^Cj"DC" ;yN֜^c!H} l@+(w3絫@F^2`K)1Z6ٚr˟ԧc78Ͷ6473*q |woo\{,f$ufQO@N9na:-g[\ќ9? q!|:c<َu4Zvt8.e\#8„pE+uqժe(/dC uSwVvc8x seh+~ 5p\a|7Z<+ #Ju`nNkl1B*n# M0ELռd!R̬H%d F"?\'BП|swE潼tQBJ`\ |[`<9?hn0܄(o/K_p MY;,w'BN#dB49+*Ͷf 뿯3+=P&#zPN5觿p$:` ی+C3=!0|cd!m4ġ'>.ɻ@/j/p5:lמ)4"6ݎ^gJDNb4,duY&2\XaR8{|[\g(bxW7&rI򾳟p㔪ӓM7>WcI*JJzaz[ M!ڸ^ADﰠ>- 7f7mYa*g {e &lesJDzy`!H 52e1[3*'!4ϟQ1hEc%Xdn~kP)aZ1C[ó22ac"R&,!>ӻSӄ@aɮ$B[Os,5S@[gu=1|Wdj+hv8ƽ-/@FU >Q݊u/-23ȞS `*BHТzn-KAsvW~mp$ι=mA!Ҝ%\ߗ }l iFÐOcpWdÉ[^_glA>=6`~]QXY\Y7yqÅ}+-c2I5hઋ(BeCʇ[13ƾ7:M=Xz{3DNMX bD.x'#N S\Gx.Y&Ah ZjԦɃn8d3X\UW׹ 6ҨhgU1D~{w&$m`)Zwn2r>@:?b]¤9Ƨ=(xLHa+ `͈_n ӏ<*ؾ%wp֠H%\Mb`X0܇O7͸ȧk<E`ď .@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPb0? I@:4€xƩЋs,}@| @9^_R *wN0KSCA[ˤUBp B+?0 !j+QՁ{ݱHOql):?? Tu`-e[T$BmvBa4 :ʘ5X@3#iŖ~p'myAoiؚLØ3v СjtMuoEg|t{o7=r?ùBA2_L81Ѵh/`'XN gpR30w?qVh?o][R|o@S8+B h7㬡ɧd#i2bExv%A׵F_$3Д!|ТFrTK1buC]*Q~!~B7Ndd@GBh~Psk J-ȭ~3ؔAuEPxGOT%L1\D}5^{q >X:]Еia2-R mH5 <./y8 6~vҦ=jg+n1]9ln:_V=Yh:>+Us7Գ2cnAMzMBv:M=3dB];;t1t fIa}ϧ;?]Fw/~_ YCH[yR 땰!O 18j"nC0k|bpt+.R>}=U:uQl4Y7H܉4&B$6˸4e3 =@v)HL)cGjib<?jy`Dct2Wr9셿" $͹5j|> 2Mkʮ;Kay9>2x(>!cW7v9-F趋ʔ8/L{-b/rVr)F-`K\RKX{r'03AQxwFέ8W?bF$`>ݣ""zݤ 2]=3dxeY m;{&4}}{Y4c8\e8*[Z,tUcX߶v8J!MWu !5VaO:bT ^xbe8k?L =KUQXNX|?q EKknMf 1JE^i3">ĞҖù!xOvؒ]~k1c#!}GICg=g䨮C>aO {Yo ]2B|՗l=dTڵОeWc=$+z򗝐g 2(lWpj4Q~c~m͔i:FK XcE vnJjOw#7-ݓ*F٢vP. öʈ4^QԄKin8oQbp> |tnF(%Q}Ba W^d:\g"fg_0P,4)4#O7E:*^,cn*7l/{16bO1Lz Q%nXKL$_lUj)ެ«^+Mܧ,D%̪.r0&yx$f%Ϊwi%+rta(rBcV MC!S(h;ϟr|kb^m>ϷkB:qm~i01MNwލG DžDҜusm[VUlO)rPx&v߳e- O5,"EL< D~IN=f%;+/O`OMVŘ= $.'Oj}IVy[eD&K}#Du8S5".Ԋ0 Р=Pe|xu|^>4x2OPq K 4LAWJC%\,L&riVsqՔ_dCnϟ'C*'q'=|2b/"Ā=$977o>Y?ْ vIb6ߔ/^Cpo㈸FS1G 6.[ؐ~@ Jo=~g^͍|LU|^b-)f++J#Us O`=hG̥Ds{L5ȗrZ;Hle| -nvVi@SB/E / xn{zwb2PۭM]ES},gL'|WV]098-3MMwƅh<%G_ ӈc\?>namz 7~Fl`!_{*y X! FM O&!%vxiQ w ¢kՇ&p;PXKs}曌g;p| KLfe -F(y@fX̏v'uPc6WX]YU XHdx<j&OLB2(mXUjEֶI(SFIO7vC#@"yjƈ]Y5Sߨ߻'udn᥹x6:%䄫F{C|\i0IÁy; MUE7FK3/#wՍk[kn߽08'mtj "WlyU:2S)BiO١r&W'A§{Z8tsFp&SoE(3PUڻ+Vw.y-]ґyB0 oMy4bC(I2u$j\j~е?s&*I~ qi8:7p!}neZi&Ô~Lm-e.LvsILux' q b,lp+A '܍Xk[k|tWuVѵz¶>r{ӉCɗDC炲)L:YɞncIS7B$WWy60! ՚Zoͬ(۲5TcꢉrT]c kyS*ԺO2'&Z:T,|Sۅ?T,dȀydΈh.mD~?,wQSX6{=Yz ozL27Ȍ#X8폗 {GPB0||>tI C&\Oy ''GDzxf #_O݉X]|L9;2̴g*X݇%RgpCINctc9[sMӿvXSmRG&UQ@|l$bb UM O[;pz*B߮DiPV&brWً>Q&!Ô黜;F el$=╎7'/2)fu^;Elf`_9l,aqAorR|HeuL8.fA=| kuב0DQ.uζ}aT& &.y7\"4j%X5>:?T+00n1X݁ B;IT,^@aƌ8 ;"XĿ%'q. lᑝmԞ$Cd~& BR,L8 e:(:B BvE:s>N%_M_niDfVy>kn"AQF,ŝ_lzVcPO7(-r(0/#ټ a^/+QSHKJZb=)¿ڻ8AC=Q w+x}ħ #㇫nΦ&C`@fj7{(4&@@VZCy%@6rU_GO7 0>n{PLLBe];?OuzQD܌'+,=n&dM_T1S8⹏S FWdڦՓ8CB}#xjKCoJ@$uj $xQ*J!VӋT y.98<%yEWHcovTBwL$kM{yueλ.&U"H YSglid\TAymOuOq+(Qlm3! _ aCdI{[mh4ۯG#-DOfmQ=d47cY/ιsZfz9POij I"N)2W0U:X(8xPݠDu(QOcB?@(pG|hY!F˝ILVH85M_BM?ǾUZbS:p  #DEgV W~N:#pҳTVG:?!__83o}YX5V)( gJçEf'0]Ԇp)JLV#MœuhD(=(/7ݘ+ k{14\k;K%9}\2 69#s  ,FJsϴ.AEU#gWZ6F3eKSGL4nA(qRtŗ]]/Nml$N 1ISn$.QXj/*~qw@sy -.~Q.DBdGı +a҆7 #짆IjeX 8hZp{,nmoVV+L*;9F݀GR@dP:!&/0?? C CFSN>y\ P5gf=,fkRKR =rxlXkwz+@ ]Ǻm.ri0 D)̋ːf2qf8iUN2/.R暍ҩy(bo:LbD籢a{ʸx qM3~lBngcƈjPHUdkY[>kE *9qľ>@ :v]| SpVcv.Q?|IspƢ&o=TR=taWD}hü G!zyind.C [V/ZD5C@VoH8u Q >cqN d eS90mk$$hQ/rɏSh;ӇǴsw-y.(mGj vy*$¤w Ƨz ӧI!;}E#PrVnHZ<4 +h%cG65jҞT]kce%0855Web6i}p 6q'>󡗱jOo$we)#Z-(uJf2J*8%[b*,qc4gm}A1$ЋXa17,vIp!<*oO򦊱gW4s7+  B y!KG0䑎Cf K P 57~8-XDZ 8+pF"=-\>)%fⅪ/O_ݶ;͒;OgC,eqBԏ^A> } VG!"+mZ0324SȌ+ރ U@h 7$U%#hL4ͤ(k_,WJvw9=&JxPLJ* )0KPu PR_ݼ0? }xðN+9D>F1\އ+L.3zgL:N]ţ_ESIҴҺ:ڜ2jGJ.j?;?10 ? I;tt`CF^T߄ŷOdxjHP NV$W9Z֊?iRsb^$aĤ٬Y']>9&Hk2V6\xUP$I#ØA{#>=~혲k<54!6]?R~0{kj`q;Cv7}ύJ??<0h6ʹDRȒQD{?Huu3^cЄ iwtA)oG Vj7 Eʃ@iu _|u%- 6MJ*Ph- ^iZ>mOſ.IeX9h Ȇ-5c U@Z,(^h\=8~.j=vRN8ښ35Z5(͹i[9C&tT0aH:*B˿BE7Q+w"s/[.!9I. c6IIN"yTk3R̢ 7v Bfտ( zs#@mq)O\ԇUU7RTw:C5$dҶdeJ IҨ.τ!I.+ nOˉv3NYdaf}8FmӼWE0)Wp6f+ L6`0BoyyHnhz: K򨿹GÙ9J؉U9,Vnܬ,aр zt)} 8{{ЗZ vg{dP^Dڙܼ@goxMF>0e^0K6N "Gh=J 29 $S7/{JH'dcLKmGzm6&.>֮iwqP0Gl|mjCqK :Di0+ 5Z*+wG:o8\+ρ֖۠؂0G'oNNsq7X\Y5i~'VPpgOPh( G!>;8Vre< sp%B^^HBOgLK)w9pi74sI-SX')%]n ;zjt4SB6ٍ4T*SFcH ,T\I*\7B(Q }:YS{P3F(|r|Miy l)UlU1a2c}|sbrnPqh 9(+H⧦hizbso*&'p@2,P7xoޜ/k$;s)_Fڢ2cXTrFd_,pnx;њ66: 8 p: "y b(ՎZf'8MxJ $Lע:;բ" TSvV(Yz|'Z;9#WAy&™k,=",yl*sW,{$R!MF'YSv@8H벎>=v~! ؕ.d_TG.)I]{1Ҭ(;_p+qɝ/ԗ}| ]UL)x@>|3ͥL-$NNJ5MC/$Awe8:p4PTi !67BǴѠ( ܗ ?^@q|4|_:<OV^BIN;zb?&>=LrR* Uw ηCꄔв8Tذj3 oT9W-ᦒVy^A @|#Hj8o;ISӣʧ%Fm1e_bS؅&f8[5p)эG;:Jo- e+2K>^~oGCMFJjhC#IRpӳc%FIgPKu2^8x@O\6".ǚo|0>DppBDP*vJ~z68PqI?6Sb-gEsDfvO"M}{ duiv\6.C£4C_ Ѹ/ )a}'-|dXbQ(4$lSkt0_S%>]KDKe0KT[XOjDNu|c :} #M5w@ bY MS\OƥSXgR/As:_@*N$Ѡ H_rqknq Ӣnv)!sJ_yмU4-acȀS# wbMX :ǃ cE@ZT.hUPPꝣu^M AM .OycKʕ\<3!%BywhTkHƴ(n8m%p֦cj'Dv:jE? CQ߀aT6Ns 0yf4_} 2;,ds$.D}KkA|xv>fn&}^xhoCXg0,Ѵ[W:٪f$ y%hj]gpo3 J$6ĉAmۘfE>eeeA{U!g&c%:Ilap6,y^E(% 3@1 V4{\t5|g6Y䄦^WdT檥x{YXEKiMXϵ0Dï[2Oœ 2k\đ EHA:JڀfXË?0gЩ,RF -n~-hrX]Jn;yi%["H*i^_?_? hg^Y\B!.S 9^ ,(&k9w'Q~,:%mpY)񀻔74?iCx̼ekz/ E\|66O ;.a`wW9 N$x!fp0Ii)`K_4O{W#B>Q99_-CG`Vz)YNxI2+9[i,ʖ?^ObInRL=exFH‘-JRB1Ch"qՎս.[箑$ֿyT-ݵ}ΈoޒS%xĹkO2O\k_/wJ D 1/Ӱ"D$`Ukw 3.[]ٚq_Յ{Mټ)͛@Ǜ&EPfZn/=tp m06#89>?$??O~x -~Xݣ?w@IF915iI˽Kȱ0~;J'Fy4vj6ru.nԦӝӫUk m*Ug@}17Lo5?sqdəP)lv9ruuDGF6?=Ɋf KR'N{#0)(6贔5Lc|`K4GZgԭ#4kz/Z,pqp$~ x^*j s,:/ (+tFko*[c. v PSM԰Ɏ^~N\{U_gywOm0ke.jQBQb6&| "x OqPk Fk"bѻf,5=UB)tWzV&ԉ(ybk^k$&m;XȣזxIc*{hR2-5|ojGsajAǸΚp+x֊gydM Keh6PʐOaylzus8N綁_mxQ#}q8}㣸sEhb@Ԑ,T V|DiCܵҚO~T8 ,/m .nVeXPtZe?~|*3@2ܗ^$$/6GV!MCUy% SCHA)7˩h(Ž(FR],DMAmY`zfzw%J3q4߸r wXUD4^ /6\R``ЕAN>M14xh::;eҪnyI~ž jWyaX*Yl2/S6ąLl,\)T&Ɲ(j]ꀯ#>cLR (<|<݅sTLꍽTipFzF;qb9|5X:-2*#COֱu{8 :,mW襓bF% +'>W44lv9(/exps!5wNPRQpkk&up×x#:8~ႜB}Mj7*4ZԿݾV>%^P}+{ٹ}qT4/QT &0n\i8-_{Jl?Iw葉#/ ok50baa9]Ͷl*p5FL?_އG n֓?{!oA E QG(b ;r7q[-[9tI7588WM#iK |] fpS*͈p jzFqr.9&9k RW.>5f#}']}?Xjq`o荻|,ֵ1Taȏٮ 1&Ӽ>idcy#t>遼 p}\)]V،Zl26Qǟn[^e\=nA0JCtw?>:٧V16a H)e&gYQPerbT6ąעqh aT+vV vnsr\EN` 7(RTr= n E A{_gV=7*?uмђ~B&&)Q{NA!@%&MÜ8{Lw8$ Ȫ5Qn# h,$% #"zVP.}ѓ~ѷ! GYNF ~3IG)mw)34cϚUйՇFmAfd\Xh|P[1y?;6RZk?FDnKVf[1hYQskKkMt9M(i=gf1IҤBjKNd;8p.)s 5KOE_JՊx5Ab"?.Œx{s$vVAxTar:Q~rXJ}gz- UIEp]IYDFP p13/m0?}MkzgT<.B|(3$z7%U2;pN}@ZYtژ?̙TPYbKXxRR};FMfZz!,:4w7?(R?}5Fg,AYan &jnEN3#yIBRjqDkxj2Ŷ>@йd΍K^Y%&DxŚ*Zc/=+nVU4;jVWmbQ:,fr:͉FBAeEJx6Ռw9r_ Haۛ JӍ/UEQ*㒎0~(ְQoP^MߑD}#mQrf 9A4k Yo:9D܈|I7_iGڎ)aqc>WdT~r>0ucѠAa5 reE(G(`N&tHs$1%F;C6L| *,:S R}\ P0g+YbT}?֬ѩ$l(Ej6SG,,QjpEIna}ŽAfW+<h0N|qHޣM ңys:\J,ܚEì pY0]dhCFVq iZئXbc {pW 'f*Mȋ(ů6rseX'(I\/R։Ŏ-r.9Q4Ry}˓1 3)s 1}nes)Z+?^uwK?-SFګi- `si"l*¤"8k㙫lX`^agc+V{2lOa7C\є /@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPԳ$EW:44$Iu ۭآ|,:le;FDz9k0tw!/]VS+ʇgyN;FF=qG,+H{5V.\bZwcOU_썭ZN" j xfI1N:GSKo&Bq} cƂIp8fڪ?;kF[Sa^9A3!(~cῄpUrC$P ԫ P> 2,H*IL=f(Q>Vpi/_VOwU5V*+D􆖃DdXN߆SI ~eA#t͓C j\=Y3^b*fNt,9n2rEa;_$g qVUqۓR鍂sb2CUӱ{ev]OyO_36QYJdjo?Âpe oᆊ>sYFuʫªp zv.M\ϡyKP8 Ź*B ܂wmT{/UTC.Rj4 2$q@ TœQ+O 0;_N>ыjAN1 S nٱiODFbԴc\K?Lf$гxɐpqC-inE)ch]ꡬonɱa6!XCC̍8dʖWg3!O#1NE*}fyΧ}[Ӑ$@L[ ZIԍbb><`b+ ~P FLB™^Q"њ.cvdraP3; X)@΅>SI!Lӊ׈ 9J6+Q sXjO &I^]aG+HͶ=q$w+s0$r  ռ/SWJp'[%5 QQF b9s GC$roDVDBda(W?:7gk@ǀvf͟=JK;MӍPR1ֻsx XDIʒG܎MUy_4W4c{צFD/q'"o[?U-ݑ? =t07{#[B-*'{*`K )=O%5ar(_Wµ[8+fkꅀHIf?KnZ)Yh'h:xlW0`OC8$MҟX7dBHOIj3ӷϊ ㇊ g3g.\:n_МuTHCS1_m]g ҹl*}0hJ+dT 4l<3Rս(+a䱻ln̽`>M6Md^BL. D#fusJtHJ⊇IO0hI\@۩ ӈ UXC7r3"rbRΗ JE2e*yK=[ $Zd<1/ÉN9q>#C$;2px@hM֘ߊ,|aGdxKĮ6:c6? dg$5?2jF ~" [ \ݾ I$$ӣm-nݱػl].fR!J"QGw4˴3*;;JouPa.GBGglU3h3L-+on]dOFeJ'sނr_Su"\z,kI:+6śS~M(_`˚KBZ!\@kq^vq/16 RPtm:A %ѭն}=E a;1y:i ^2u׭z9GŃQw$^{ٿdŤuomZL*R4 E0q炿:T!X8?̆;mqe`6fإ@75A3Y(d*3tєx34(~%ժ+yd<SIcgoI,; x+)5yfֺy~lGwG1*>åƱEؠ! aX^C$GyC_TdnsJK/"mX2=j54fV:'Gd說akQ'f1}oryCxg~;/YfNOv\&Miׂ7;|"l]?GV[V&_4/ҍ}Qc;m{6ECJ}c ~ܜ"fS='):=nhTLiNh=m@>ZأcHp"ܕDfo{(mq ߒBnܩA/T <\k;w!WmaM 3mϸ6>Mfz8,[F?b-KpW6qܰkvmHB_(x1Dna7Tu9_8_? $0`4Gg|El)%_bEՌ7;4+YجF" ޮDZn?67_4܆Z&ZH9d+Ͳ箟SzQ"k02Q/e=Sv2PF:>|jxpٚ%DĒ;y 6*c%,3O?ۄre v3SGW˪n5#+)YᬋTרme|Gxp< cě/u, ěWl2ڡYPHOLNR>YbVm*6z)T&•f '#j6NUƲ4K:6㎦*s#g&4k/xU_Qa7)苗nN7-؊3%}MA$t$R)Q-J Qڃ/݈r&^٣::^ޛ&s#JYD[KfS醘ȽZ*yxst7Uݶd.ɔgޕ0١H#[ۇOP9p5?*dn̵jPenAPc-˲nYwХ(2Ai PorpG5hqIUd俨B)40;Y]ϩ֮}'WBS($;77:0P%3}j]O"F)Tqu]{L}#BR\ז͙S )T8#RI@׫\m3i' ZMչi:}I6ulibQ6GT,/Q]L8=e_Ɯ :"Rqbp@>/N}z@Aώ׍M&cePx|!,kS6@\- DDŽ-lBc'V)VX|J.4sBsߵWsnKlSb fWٻڪ"PSpcl6+XjY<Ϸl׭DƆb/ !;,`-_yY|uUʤ̄ 6MPШx8\악;{\ Ƨ^-#m,EfڶάJ(ْ1! 5F[!XICg˘*KƼ%wpwS?N꛼H[?P\_ @Mq7\Z\r(S5.#Uúa %X_<tb<$B V!ʪ$Mu-}L``Orhzlŏ\{5F\ϣ݋H=`nLcW,@Iel͒b<7iê4$:>~g?|0sN򜍓K6h]x#\KfvRBP^ZIpWf.'gW6Bz`lӮݮ R,>~ _0f`?M9%1ҟWs'(#_S{~-_hA G^*‡cR+bgڰ/#{See,m  ^sܨȪ´K hhIZ'd)PbפǠX{݂Ip)f+;'qѩK,e,߅2}$3PY1.w ylxIE_і-7jS{NguіXJlxdȖ],|q_xLrrEDhGZw4xO5?[r&%PD]`,V l\8BϗC_,1hg2wkzǠJϹNGvb0ʻIE7e賵;,bɾ,h|)-'O ;sP 5"߳ X6EٴDYZ! oKorhQڧ)a[Z|M؎%Kre_*Բ:hGt!j0ygOm>z wP^)7~vՒ"iw :A窍PcMy8juV~O'glo8fK+sC*KOxG9Lh vB,{дywHie‹턠g&#zӭ&I^(,F+P/Py 2W^r@#VH0pC}|@|@>@!=7rNEd|4>4P~'%YX¸u}RPr̿(FqȜ>+҆$mFy?^]Z"7)~?_' /Z>ĘPLy^ yIѭ>|F|z ,!UK6\z+)Ёu6J}mF?85S:ŦLj==R;YZcʚd1m/[u]b(bx ύi*"X^ǩZ*^1, ]dJB(p@+Gi`.= I-lq_Ln` eXd-#JqK(=X%a6MSPg$bÆ(SJ/)cA2iS9:Y_sX1DcE;-[5 TCMCg"|>~B_8?z'/vhmsQ.N(gk-|#{4TDD"ugSF"flq>]^Pֆs;.׉rkfǤ4ubHmXrGIɹحBK+pc^0ZwSmwa&8z *18#!vL,d)""Tp9[ը 3琠|#G f{q)k{'inF˺Sw=Œj2Mq vu{ P!@⿽]ӵ; Uq Fr^zLS\.I%m|R w2\I2f:KnR GM|bOj E*?Zj8l^T.mtx$%'85~])R@ މ\v/AB]y jHRI>S[sMMkDGzE)U%L!R&ފ#[/M6eZu<-BՈ S89t'5 D!ÚE9.sN9geph]J8ym)`y6- ]D7B|a뽁\*ỏGI&pN.Wֈ#b8W61[$;pU/g e`N_,%uYۨ,:Q=XƂ>d,Nrw?ܳ6gXF!IwѮٙA{X+^t+^>$b*a(X4Sb#0 (Z tӹ059 tɌ$Ǒ{ ~,pJ^+5 U W\A-~:ZLC2T6pպ1?XEV }L7S?Jz|AFHeTqnC`ў#R&琨Rj^~9H'0t<(;^6Iגep@xN6zXMJvѴsmT^ԋ I"8/Š^W. I?nZ. 꿇@?}@[3 @zs{QASv³D cBZ,Nk^ Y%6$׺| eM-1FROq"iQK"ct2̼yf,&QX]jUy4U~ale$hDV*8icW.""fUI%t~)oX+zk[lqs G4 Re뿧maM&Q'rM̅5V[8iǏnZ@}[aܠu.;9))rnGڍ\gy܏Y0JXu71B/%R3uV~`c|P;?D” Vfg0B<pڷ:0,f V\1}M7ۺd]cd#i_4W?.n?-)ccj!]=4% xQ+Ad@5yTWL79}έꙭeygOK:7(Q4Դ6.lpm7(x #|0=Y;~McM]MweK ;@iV']YNo`&d];Xw(Ne;NRsĭ1k;&EGA̲qdL$0 [N o=!ăEfH30@܋9xu r8ü{_›%9,g.ӡs/ڮ۪_~4͚o/K? ԧכ E[y{PiHMpnE9l>azq7D-'"sB|A}5kRp#H~ m[T:W݌G͌ *hy.a' m/:z?܁Ħ% HSoH+䧾Xwv4dY3:W#jEӀNvlʳ~v$N8D'AoAQ[V~.$#tn8߄Zq;+nK?9n ԳGKͪ~E&7+p=Z~Xn%/ij]t *'s/7GF'zDclWb't Zź:=X2Rm4P|f.%_;Oʃˤ !`~{_IKMd鱇)źq1lԱ^硐AӉ0kՕZNQҌ71 i // u˙iEճ؍jtSeS d\jT؆s=Zt/jb 4Rnߦ'(M 5sFI\Zm +e8ZdP[>e!.AP29Hޞ?q/iOr { 9E2$fHqM48 O]l]Acъ[UZVc?%{pCMj{>w/"`e}0~:{|sjBuЛ`]V ת_6O'TdnuZ:z %Cdt_*;B'RO&oZ '{gsS G}+vofc(f,ʶzL i|XU Ȯp 475ֶ1dE=} 0<'#">C' m)?K _)º>]]n9?6t5 0saɉҬI"%LolO6 8N>N.<ŀ2aMEbvUC^.";n; nb{ jq\#<#S n Ŵ.;Yx^^zsMr9qw:LazX6Lž)HُMSXOdyNeuԣ'%TD@;!h;<G97V>2>M~p VUt;ե>e^h@R&ChD~ϬՏx |Fi';惆[ HoPuםϻ?Sy53|򓃜0|]a&Մ؀3%ruu])䯙@([I|Zr(* ܾ)(iP[^:ë!x}"f5quR#7<#]*F;x>xt 0P!؉xCgίiM [VBsf ~7kzh?Q(OC8--- B ]RN[F^[%BSTN*z>XgTb:}y񸃃̴=즞ⵁH1^Hmߦæ@[cb-7{c?6볞JQǼuz.ZɾдMss`esИc8o.aJh8=(bFUfK߃ԶYXχ5 iwn}ê k"W8&})?%(/10 2lj o dlRs.&տ8K?B<'̈́f6BQE [R  U<gҍ-Y3;پa)o}:r ɜ4Z 2Cj"0]/e< mx^+31\VY3G- D/8 Qn 1òu&W$!F(NPȪij͊ALb,Sbtumm׺2% ɥ{k-#>!,J2O{KUU7]dcƣiUmV)9SpdMuUsz3v͑ R~>s)^%xBTpSF~CTzU2g*=ջ7F{6n!a]+# 4E-14f4O ǫ/d@NLĂUphME~ {Q|2v'?)e &vJŴN8F%^\rxV^$}0"zZN JGA!<&הV e <'c&':#%\if/= x1dd١,2gniS/PO@V^ƕ`3y@,27o~q440-j@N: UxuO˃)0Lܟ@Š)'S Մ{Vљv!9h BIyN=8(x:sQki[ꩳyJ8C4}(EZc@+@rW`oS;4? `"ILJjE>VgDL6#Q)S&'djSxP &,1O xo|@||bda-4"$ks{?3*l,˴G@|Pp!VN%#+#lZ+(2/斪Yg իKgtvFf`X~D %7[yLvEjN6 .G|F@|z, D{8ʉ=f'PӀ0>Ѐo)a+bY 6@L5M2_ث(2NqsRӟq:^%(E{G E~9+)& C^b9S?{8{!kr)`b" B d6.di{*rzp#I!+ڍA%(#_@} C&A {DD-0TF({^-F/`Ca?=;G"wYk5zNjs)qiQug Jޅm0o\Aryͪ> Fv+3ovǺW7NԊHBdњeV"^eb5o|>`__?b^);qɞ?oS~t * ơlaxyVyD`0$M6/XzW`('רyJ5]Jft˝%iX pF[9YN*Ts眖uW[-mIY+˒<-W)9~\ɇnx6"&-sB\܌ν㤡 ׏\g"[AO4oէ<Ɗږg(2:@?^IFUYFrg'+Y,#˰I[$n{g 8N̅7tbi5 ffQ>ޑ*L&r'UZ0۝ԫFЃ`ΩEX\ #ɐ0&X+}5 p$:cGPGgсn"C`Bqnփ~nCY^x!+tnilg{'k^tRv;'oD]Ӯ.0T;h1(0DE:ԛM/ߣp٤BA!)7ΰDZoD:x ]AN(9#n`:IN# [\u6"`x1NODw3,=(HJ{]Okў20;'(.2+{JCj˕;h͉R%; x޵hQ,6$m08mHN:\=mDCEPojs ia0rWeVJgc߱GQ;&FST4+ѾUp~&:*ND~=isWpL֜?* 525$?oâ?,ZBп8d΃ 5†1j}"Lt nERQa֞H/XÚ}fQ`#»cžAMӸwhT_HRt#EPtHN06c/^tedMdC( ԖrZX0xs.Vyf r r͈w1h.,~K1pV$Qː<;S~oZb `E\q(t;d7@s٪S HYͤו0ɼAu<rlLOGzm<%eqL 8mzN-=^:;} j1;.G4" fY2S xEGU0HNPF2\MC;nqr搞X>ʻX¼AqЊT74^i `lxAe3f1{gM? ⮀)dIpZJ=nXCO+K#0a!|݆_gə+ Mntbl062g$uoR.@Rt~ ba7Ud꾕pQȈ }yY ݓR?76r,ZdoS l.z$>a&s<X '&ӰY-,-yPDU%{9&rϛ.7=;lx5+_s{5| IЫ2/Q^ :B`k'r{uABFXXPq+GmT4ӷae;}}idHvDȘg/]- oJ jjh @U[͚XȖ=Hڥ,5#]'wmiB]Ns;<㋍3W2i%AE=%ڭkaG2w-G贇Չ\`lfL|zJ⟢yP yܗ)\:B.iv< ?"iV`T.q:k_w6KUeJ.骍EB:VqZUUZ[D[ aOpzhcΦ:>QaMܭY{>^ݵa.Pk d./3|eZ%zu W? $pWujR 8 )D8q29V6w>zV0oR{{腂ױ~Fd[;Pk@7Ppsas| ݂[ݫyk.krUŶѿ9EY"td׆o.m1 >iq7oں.O<2ixmj@`RPP&FT|$(l,ɒv^o‰fsC.,;3d8 ?=TMC(;tΈ6yx*da_&1[m2:NZcIU"G?kQ!4mr.[,'rгe uRu`ưx$(4R bUgVG:Qy8c娩OB1ݛ7ޣq,>"|W4wl̓CsZo\I_kuL[2jbT dc]9y&Y0?58A:qX[kĊgRq1&.HE{,BKE+ Y)%mWQ;~.06w Ӊ\FVy|cro/!H*Q4 s#@"qf9!Erm\O!N |<% T9@3U^y׊FLϓv183. ՛FDBx T$:p U| vcMRqcv j= BFth!apd3*#{aMS}V*61޹u q]'r ] 0@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPer2y:,>Nb]G/C=d9Rf: 6U jP;nrɍޑ3' %;;ς|°c\|;$ñ|w6Ã|XQ(}UK?~Ct)I]d!~˛#U S?@x(&:UT;}\oUT4Ƹ>g%ْwO?l n?O`ve_zd*"i]5l eKX|6P=wy)]m`3O^"uD²Z%vxտ*B%jHAƶ|źu3"|亃SׂL@ QE(cP|_o#Ȓݓ`674Y?[@ %Opڙ146䄎% oK_ŶFe&lE돱-65}0$ ǜ2f{#@8{5it6%0&CSvO}jx]-7jE pTe{kr'@!knwX`D\Ժ W.gf C Gg2*mDfŁHpRg{T^`T;(|~O1msSбAO"䐠!l+QƇ>7\GN[{ .h$(s`E[*´/w~ywl^͈tV6;\{jQ y¨1_\s%Q~, cVht4Od\SYzݖX1Wi e;1 enǁٜocdM$C9o rl)E`x0rz5v#F6yJ>VdUĴnI+E:'áz/ hX(+"&dLA+@lύX@EGnh 5bΚ X;oawKs˓QP'Q ƒksn˱xx|0f;FI "  +AD;(/ETqY!4@x'~ƭZbͿĨfh[~*8 qDDIC2 țUqGOUt|4EB1Jy C7Q G51EYENP0lT5NڧM\|gN~T;[BI #u =p}DVo./ˑUz m[yo ltH'B!2&ܢ GBí񵝱[2Hf0ȍU==N2>9۶9wBj =.i<|o:}YuwkJ3/q|2 [Eu8IOTLEW:@?\h7gUj8А2++b]h) STSW |P$tӁ N%t%'G"_ܹMkTЕrOZ:#QS S9}ކlK;fmlcM#u>Q +&ׂfd 0CPqU%{q H ~!geZ}O&m<&bf55Z~WH`5!Xԗn͑)M BZx Br9wOR(=x MXgi9NǨ3 lsZ֋{qQ%E8jKo_N&cU)y0cP;<[9Zo svf+5s1{EЫ-|P] xW3~(>eD(g&DUaEfmL:)Pp |y OOƲ )9jSV`{N*r#O]օ@7m(fz( y]y˜ig!uL>p>~$|+u3 5;*'*'OettVfzm'd|7+`ť pg0թ0*VFtA[ug68_|)ܤ?|nmERn6g$SèkoZ/X !*_5rR P<)8/. -"l*;ƟíWVB(0ř%Cs<|}Ž\ǯe5zZ/st8 5JP;::Nq"G=<4 O` nY񣽆ʠc.9V%ygY@u$CG7.b1TB=գT3ܘph ՞:<\B| N^uWv"Q?m. MtMFt I~Gxt@G7Q(Ԍ ЇACVS( L˳DyuEFT7za /n{-bGۓw Z4ʯ+:Zλ`{SLV`i=Zu:Kk) @~&J {WSvYi9m \4,5 #YB80Ojb/[s;*UQlptW%qʾ(RNHHq bkSZR :Kg.b/J Y3A":{o$hG@2:-Fb3]tj] jI?}n*Qny6߰#d>uk0E FaYE ( HYmȎ)c "DY"!QJ{x&H&#dn+hhUX;5S-e͝R{O 8q~`x6ʟ"_R|E_)Y t+ (NMZ\';hkf':;ĀE)&r͘8p~ӳHt׺ |yi -V򷽜ȖmvNq $ThvC˰:(M?^SXl,:790i ]?+)9^K/&۝ {8L7B0z K̤TYg$a.r*ߨsٜ۸=hiJyFKpC$ L.0@a~Me0|8B+Rdv!;}+ׄ>\\NzAVAgZ Ho ?1}ߦP`̎ZX*과EcѾ*UyU ?f/FA ƱQ;4t}3Rg8\ʪ)ZCy$ +wba 3 zʣ oAMaȸW7춃@/7v}4\}J{'H#?*% Z2EM%"%^|\6KVU fwe;{uķy}Wpk2O",cSq]UFa8FI0DMhlGOcV-jf"#KٮënoQb`> ,uwq2 ,@~|פdۙV:F`hCrg}b$8j| j+۾ps]4Bm#xN8P3EbMpGܛ<)BsShZ?FB $oު;!m^)kWZ@gh >Wn8gvYWL+Q^G qCByݱ.P=OoL$:͛| La6YSk/0fH |6WvfSw4&Lf(}>R58mQ~ݤn e0fb ?JVMs~f+&NX߂y/\:ʊu0S+fnI|f 5*bט* >y&#Y)ꬋrrdsώҽ3LZi |nAP;O,b ;ShK 1-]Єt.\+ǑPVAV $ԏ:3YFOs2p8΋wTUD/(vGs'?q![˲ ZkOJЌ!.<'J?i^6:tսWD\jTAH0TP(.gH֔"SC-P5LoYzA'd19K>ώ3"Lߙ*%|j#idgd}ci@ #g:G>geAOA >a-(c*y@?]s Pi"7@ L3n[-7$`7('Nth wJ`k'9æQ{%1"g}abC5b۵]Q-7V-K.V@Qh`CVxnѪ}ϑ?#r*;+aGCPLJk4].c"nJGDZOiZ<"MmwEYd^4Ώx[@gl,6a jU nvʈ!} r66j!H,ɂoz-@u輭4nsSZ,R Mu%jN. Ϣd`Np)kx_2}RTdķy vyH.u%-@ޥbx;zwXœ觩eg(}3hq0o% Ro}m&ϔ->$։KlʶIh.WD冠%Aw} L?y \ʏ;9>V>OKNY' NjGό,}T5Wi)4Y9+Fat$SݞW~v6BSu]uNGzB<{A7n9rt’Q5[JNlPBCbDX|;d {[cU ]kҖߜ?g|F#rJCeܦe*+6'ٹ}j`ݬG/7S1ٍ w"R| g8X?ӕK13. 5׊0*<~@|8`L=~|")7S,E||i/sYWa^#t֏=:$w#oY~7`;_gEkJ_;uiYhh@"3af?G+QZd|G@|z ڝ6拯[íuڷpk?on#WkR0_i2gڼRkK˖Ya$ ާ?-Oo@%)EܕO8w1"֟ē1`cC+8:rM<+Nab7|.UkoqHW5&vi EgWg>" T9m3f67j[E%/rpgȗe*q`L'Ba!v'@hrUMiԾ6aΗpl+(-?a&tbEh {% \R)Wɧ mhI6ssZPY$eAP`agMvYܱZD&.?߇Ӝ #|~NO ~R@ \UAi=P<+ԉˡN4w3pÿM&I<8":,}g-ÜBEx0j{PGp2(hὕj)OޓeR+ً7O=~SǴH][e'fS#7^Úmk#cuE0q6L[87GjZ=Z'DО};ٷ8]SezЬphzCۂ,kOt!C `)ZO-^3HlTKK<,㊦?/,FE25A:t~ޑqm\PQ߲C, 'PD)~pWPGŝ$`p>;K52Sw~e+c'ݚz>3 MΏx{Y*w56։2(XhFw%7U_*YGPg>MtQYۉ{&8DmJ)Le (x,.$lnf]B!jSF{-e+&E$vxJ J9&mrZЭ䩩SY䬐&/`'ˮ{3 wy*L4`N}tÒt~w vTJWc?aE?OױdLPu&+nAŌR.?X|9~V>@8Lɽi>L xd "|oIV_B5?bxwDs$@*/dN?j-"fM"+Z>6}%[ϝP69Wxe:F O;VոXBUjhueF#ΌDBQ'`67V %q6C)opx8׭H۳HpgbWXO%t~M^x]@'y *98:wi?d* TYdW!*MtI9o Ow(.812"rG;g0mwI]Hzs^y9$7` *!8iPۯ }47=uOnm'GWɶj|K;. o௅?'ҧԿ rCAׂS.ՄCU;=:TP)N-D;T²aT5<xĨ_X@pOKx3:Ggd6SaȦP~/ۯoO[1xZ&N8ʧ"X~m(WQ)ko'WWIu RN'L<$1V<>z'yy15b+_,doGUk%Fa1'-cck#T)/$d.UKUh*VpaDFWN0:Ѽ}]![4/7I2 &7 d"}&'iV@~Srd27ߡDK5E}'moqL#vOܝ +~E&մ+x4-u@37%ڸw~5 94S7/,[Y}5F\opw<.cq.ǩ)9>T},⵮s (XHwHlQf#]Ay1^"H1Y2@펺/ q@wVߌsǹ0b,N;y >QhLvC2!m,^ɉ Ǎ;:0ܻ`^dݬsځ0wO^1ɢ""KKyghF*B%R*]~Zc 8'bb:P ֮.B%4@a5R40@I*FO~^/ii`zf׿T2T2p0"92ILafeu&|H(]Q WwYju肮ENH<\ roI[tV}|`P XӲ HVJˢd^hZR/9IQ]?XJc[ͦAʛz p]؁f>3N6*ˬ>]mw$ypϔ s7DPsth]ѯG< )+l ׳OCF5m`Iryߎ; ^rg5G윞wewf{%M[޷7v?'būkNT+S*V/d<;pf m8tx(&0&N*g5 `|Ar&u`|'G?0N5 +CI*`Vvִ |D#+u5{\N q^95# ~nĐr(bNDv,tsav4[:#_tQ6@干p#W Nк_ԬX6mogPTH/gB!O9"kZxi2z)}ӽ0R1Ӎo5ag\B=|Ktj'ocە5ҩ_ŽhqLWxBD]^гOqyɊ*-Z-Z-vMUt`e_a1us)".ӂZI!"|JC{ѣR޻3#PoRxGxaM&e`k[vr!3ΛݔbZ/FGHfaE@-NO! IJR(mnTyvR&ن rǟNCԙb=q0qD,"ڶ5z͌*p49w 69TG|办G m-O$fᄆ5 $YĔeIvJ">j(CoQ" a⍅IY;~*9UD-1gX 6Y3TjF!w&?İjP 쒝k385јB ݣH;-U3ڝ!^SKO%e}jӂ@mEBNT$H@'lSƥZnLtIF͈d6.EKa\9kZ1N 4u$8~ B" :d2< RM"xw Xn]"s @a,WFTMѴ'J/3Uv ]jS5 fv// q:\ j< _QmO{CAUd>&O@Khw, Bͪ&@P\SemٳCǩejwk?.2-Kr})cB$ hֲC1Y*%l젉d>@F=) ^~zPfO9%,_v t\YYIḰIoOF E65`2Xr &<08/ٚ֝ 8E)?L>qw:tC^'BwXlkO3DB=,&<9s Q7g@۱P/s⃱k)9e]*I*WC_&ʊLz~n޹QRJ3Lb (c"5(B;UCw*"/&2q/n !-м{20GwǮ\x*AsN%Q\Rʓf(o5~6;rzc~T jcbTn!hr^(.bbJw 'RE!CR mg1vv;Rc:K(omzQ S6Qrpptx'pb2pR~|8łv-<;Eg1lEmZ~;HoSq-Z#&Kvx`ϼT_vQuEͭE_\&} 4 Knr/ h}Q>%2a OO]:yOϜwso5:M,AVmljaR"J`heZW']:"X&~D\ cD\f COefkiHMN4k2e6 )x &H6R} uwYMO3ty߽]I"|{X 7 }O\ꪘZG@iGgoloy<6*9^˵ ZPB])|@8xXyȒ :jJEH|>4S$h( 2KcbSiU>~ "JPvpg&Qcnp:p]jD$~kP>| lv=k2Ahا|H@SFrt3LFq۳'ܝ7PNd9,RGwJ&4tĺ(:𕊈yjQ4v m"׷?}a&*9|Pr|{SGYI##5,xRŬXY}>q#8':ϫ6h6tvW%YUt"4'ءE̵'U)O%Q(Ɂ`i1A ( H[u"X6RFs{ ([Qo n J0N5$~N̠ltEɅе[@aЋ1Jō瀫8 ZRЈcboWj67U􈩫D e3a1"Vm5 ^c nٲr.?Ӽ N?n0 w 9d|-" B5hR_U۳n}(VyQN] ${Bwf;B9L +5;c5ˠ^$j*)x гP?; R^k72;uXF ?BBe?{#H5gr' 4ت'xQϓ,2Vi|C 4n#浉i,DzI2b I\p h,Dg%ctm|mC1ERo<ru1s^`=F4Kemb,G\}cf |~ne}W}.chlEO`ǡq^.[Et Ų&B-s4922qFMhD*-sEp/F/؈_)ip },-lsF$m^"yDs/;\H<; vI=>t=R A;?YjCA9@|}Ί P^0&=eݑʥ2|HѶtE{^pqٖ(Мئpo7 u8' /ܩ?UT6zixg^= BВR9E7(N^ k2IJ߹s^=ñq9'$ׅ#ҚE3!fM-O3(ڧ=qSRaWB>qtDj+r6vz~MDG}وAQIzE&jw]zߧ a9:Fwh/|!b7wgsrᰒ5iЂXX0n?"hվӢ̶= Kug疪16U%5NGRmht%IJo;-I0ai1gPyzj3f]zh Smnxc+ ޕV[WjE5שV[ v3JrbYkuc]c8LSQR=&qG6LĖWW~ nyҞg,ZR?=w] n^@K3jׇz1mF?2ֿ9hFXH >Ap,pfX5c5&=,|p?q?$WQ7a~K,஡oް  )l Dl{n?ZY԰)T)j@,Nz$g#⧾zi2trO ʭi/OL0ӊ\9)$z<ڟP##F< y5~D2y̥2W}+T[=KfƵ~\$FP]\7s  ?- A,dU"֑ؒ: X[b wSlHgz]3ҬU&%EI:=T19ARlMEHE.'zvU.):C; aoN2 )/€Bv(F=OJK k CGz_AmژV]7F\𕴲T$nc'u}'0o-ahޕ#XgaK+p0 [%K0WΖwoVbK~N$1؛wr\<tѱ5vwWBSL&TRY)#:\#7-vOԹ|IeLErD C!rk1udܠhǁr6$f (=Wb՛z=OA+&DFYOs0imkRxz>HRK/k|F[R'g ;a8\Z~s/J6EkDvY7t:nƈgTTn;#јgrέXІ-&i״y_stv^z,;}fZ16\6۔>`'cMN-t=qOpf ~mFGC&WEʩ|3cVfa+n)J12md7UZ$CB"~9ʗn >=G6PV ܜ&.͕gHX!˯rwbpΣiGGppd2yS Y]ݿ:iE:h&n,d0shT <J0LSL{)r,+0!fZ;5/L2d7Qԧw4hD˘ňnuz%嚵6i!NYlapdY0~.fK5c\ӑ4?O[YBj$)בMz.ha pQ4*r]Y?\OO3 B͋E}3."A>بѦ9&jb<6PC$a# A"u9-&]C:avz(q=T(2_qk?;փ[pHqUTg =M?pP[CLk]Mӭ&;Z!wr Vn'SL:Z绌Q`H̢9e|<(,I<]4o0Al ڎdl4N-WS.\gRrsZS JKqcO|@]mv{y~EX(~ҍ0ᎂ4{7e<Nd5te,ދJ_i zHWl#[S ,4sp̿#(Rl9+1pOg[HO0 Gp.zށM55q~+Ы53 ̨ M5m)sl0Z}M\9_wkS2% Bo_yX2Jb$? uƜu&ݍƌ?/AXOjb14K\?tD_395V@mur |'O$>Z2zɥ3jAZ(X.*E53i#\mΒ) Uqht6n$ Qi2 0uWWT,$D $U ?ΞäӐrlQlz`U+P6^"\mGЁԦ =x GNf <0Gl} .#{Cv'?xP8Z)1kJweHQb ]osv*/$}B?|+@|,>@ rv"\*B7F1aK]qg,2! 0v>fE/١|4|wԑ}`\&K2͕(c'P ֬iu )bw阊g'E`Y̦' @Y]o/rUUBM]/ 5jP˓A>`.- P܎˵V{j! 3gT@<܃<'ǰmWF!kP[4$>MD EӁB'Hç`5_>RjƛrR]j\Ov?Nj|0 y:x ,!+`Ha%oZ"RΩKif|`? CF}됏Z Uo-c%i jF2p{ uFh;^p8 ID a"u4.{^Ye|o:ei_[(2 40Rg> @G >W_D:d@͹c]]/aV'1f-C4BCTªH4xXv_ylэq ާEVxű12!m뷟ʪ?R\0M*`j$&/ I q.5}AވfhCuQQMx+H%< XKH<λǓCmlΩ$CȮ6i7fހIWmV+JAџ"l7 6֤T dץyԗ55Ib똄lW5;FǀωĿj/_LQg( s"ϾL&H36bVJXfk NhŪ%pIDΑg􀁓^AO ]/ ߋ>g` вk~/Ǎ)G'mǟ_lO0#1c*?ٍca6?p}T}VQ:Q}7R96-ljg1"!IF&gfExFAXJ:JLR+8 ?\j00wN8J.:QH^V#\5.׳TW]QI8$9AJep}0L *ígj |&kdw "`NgD,0lSL26T\BZ/E `,v{9Y;wێG|~gi^tc] KZ꺽Ԙ]cPgHEk!Aq4u'ȻXGN|&z gO u1=Jo##- ڇH7MsD˶tAcP(\3mT_/_I)MH W?4B~Aw>N^v9+zIՃ9' zv|Tbƒ,.l_qkmvZ4ຊ[ܓ]` /OTk+}<#I_x'b=~^3? y T&]]y]a,]Jl +YLRN#ፈH4Vd2z*ZcȜv zjЪ  'rL+.؄;(Ɨ|!L+7@DXH:m ڀ^FBYU+xwx18뢷N'V6JERF*VI|V̢yi>e@j($D $6=DGIl|@* e%F:iNz0ǸnޠZLR8_?q^+l]W(sy^ynyӏ'0Q {9`:W`?C&[08:Gl 'JbK)- 4tX+JiSiX 5p>\~ǥy"HFeEIy\ SոHVJL #r"n]Tߗ˘E5 zYs0H{VVFU]U+ b{pNiLA8IER 6žP)sNj#n>-lKCa[vߛ7KP/ B`v.Kc buH3%E ^]S>,@`@O_F m׫z)."{#gKm >'/rF?`TS G)̉{pJ?:^ĕˎ tpڬ;wY$ϖ~hD"r̩TqSN ]N[Ef}CŁٛ!J ~mhrٲKKDw'quZb5/ puY1aHAd]ŁW}iDH! <'7VÐqxŞ+"6npvE+k$@QBF~^QgÉ\z%%[ ŶN|nPdG% o'|I}r.Sk-]%+mv=.7+bbBp42FRcy!A_j?*˜+FzϲMv06 7lJJD_I.^'t#a& EZ1= 8BoFB |gcȩ85]I9*# .r6d,Z/r gVuKD_ bQf&HսU Klx:y8p|ܲ;d4WVE"Xi@czq m0`и_Wl6`aT"*A-Cl!Ywg-29nN>Z`ؽ'?W/[)ebźk,Z7kݎВY@It o5RY A+>WhԶ-{k u+i&W ŏ2sgyzx ,k&QQdYP.+ze jAQC|4Z,_q"(x]Kצ?Ķ5"=_JΝ})>6ɮ2UIu/FfN}ݑ?JuG9ҕ G)$HR4sPjJx]3Bn璄6@ p[-Z!d 3XYS/ZN=ⰌYhsB0SJ-#xxD옉Ц :5 )T2Т]ߗf{KNs}ğ(Tn870k`N:Ԝ+)Hw6Z 9~ut[_ (v[2[~1ۥQ9ARl_4$w990qzR \!J!i&35?LNf|[\@5Eu3sWv0o]< ͋a<,$ccV,Z#Y+RN>*=ԅd˃Ծ"/jAѧ)rGJ^'eoj nMxy~y CZj%xLw[<]2 5fm5:'o|HVO>&;cGo;UC3=wOꕫyծ `&x@}}fӕ0Iڰ By~ToBKhGL5Mgi\=:I7|_%>lr8XbjVr B{+Q8"YM"s)(Aȵ*YS]p{0UXY,)c90Jgv;l^xs^Jw3e=<8ZٳI׾ā1 ݤDN] 5>0G؃=w2dI+ZklSM ,CuN!󎻛ڧ"7W K)J\ʄ5VLljO>˧I 7ʕ&r5t}0"8U?'VXK.e࣎\AAU\~M/D+uk0I>k1*kSx^zC&^Н1wE &W ͈RcOvPɁ:(Vz=07ǖCBET.8l$g&keC?;fӶmSi{*SY=詆9CH˂N\_MzȒn).%l 8>B6h @3@Z@啌%ccZ"29 `Ox!\8f21q+,jqr8!I"g\Cj!n aJVe~G)GIqSrep衵^̵A[TF8xrP dϏ}W^bf^8Ie݈(W5 ܭw)H߰oFè۩]hG?0@%,bW_e]v7rKs']zcƎ2M BW}| %DH7ܣG*F/OuHߗEj/ &C=ꖠziQa$Z 2\N)R5`F_!H#?%iaϘ \aiPd@7¾vk4a1 Ddfu8hb`E"|@|@>@MǾ bG4L^TQ,pS| |@P ~^$ aL\϶!o'\)zPʍ[ӟ4A/5I4R q.إYw̢t +>=萫eߺ#D&\HZx`nV jQ1*ǑT[d|b -i>Q}RYbkl*0A[[8xQtWt폷;+ W%Xx0x%޲8 zF4[3pIQ/T ֽKtMe\g?FxE-ÍĀ9܈3"Tx/r\a`>AKM)_/6 u/e+Pnaze[R96%ˏs2=uשw+}=8?GQXBS~!'YѯY~8W~orB@`oP9.+ol_ zTɁE ו1)sʠ SV%]36={||>`_ ?;֋ ڻi*UT;K똗LFMĤ/PDIj}+x4-9T]W"jX|`=iF`33lm3M,JHhVL>[S.I4 u_[VU:ߒǔ: FSFطTΛ*V])(ӶTg\*23 ֆ3ڜe iQ/ n w6lKb"u$֤4: 0Hn~ a^xыf_xqiM$w5[J7HRc]LKjt Mƿ\X)u!2Y;A{$j7 ,F'Wd{3=(%S6 |W0ѸfI'LA#ͧ"!+:P >[2K,Oˎ -VgJ8d7̅Y J MelOlJ4C>Fw xNͤiH-w3&n] \ØH+?R Aoޜz|$c,mkZ=doQ&Bh=yDᾇ ^>í;)T]U'/w"ˉ:ny@.KtX%1;G\i~aLP6:TbpI@SAbNV,P֨oGi\VHN,Y7&r@? Kb:{y^Bv-uT6x4aB,|FR>=GƧBYHQ qx!'XQ@߆ټz*PɅ( FV9F}إ5 B]{e~h /zɂ7 Ve9޴`{DIi%*"G P!Tr9v;B3+-jq{ؠziPĸ 2i(lėHRxZ E)"6;BϻWD]b%k_ouJr_-Bir bH[ߨ3ċ QLGro^$*e!tcqis|BT$4 9TT[Z`T# 4e>mHMGfhG.u?é~?"*8ta`bSW?EWu"l{y2p(?aoJ tΫ !uuRPlv8 S.f>y-!ԕ!vjJ uWě9K?jʹ0a$܋ߣC~l7iDwO*s$!흯d4܏'F3K ֆW\u8T=s;T5bg? o1٭qcj;8QCzte/P5y*s $d;{4c9`GnyVE7 mt$7B.(5D2 Ճz ڸ)Gn-Ol'B} TTƈi^w)] ;<o٣(+wQ"Rv?0 6"GE̓,%!@A Y^n ȋ :ݰ,ɴ/1TX$~zHa_'pZHɺ^пbr|WI*g2nhOC| ,`zf}-FΕG&BAl/\9ᓕ>}lY׈P63ֱ(k12]nQoKUe2PLdyDqp3G#U붘23&[j/-udW?ؑP3=W7)Ӱ w0t[3wWlW7:48qf÷iJH~]f8E!H/q:P)CշLu~Vgwjxt_@:TSB p,&K7fp}BS|yARX,]񕋯J }YBi:qyADZp8V;bT&)"z,XDO =4z 50:kq/&{9Ufw9a Gww(sk?`F nٕLy=ϤAGbӬW?`r8µ N]8V[OHBkOŽn\nwR3"]RA]*CS\P{,Y/|͹Pӧڎ}J0{NZi֗2"|*33fBC.Ȱaio>^O"?G↜pC E%KEb؛0;`tV*Mu$[3/QB:~VLY*Xe- ^ޏx5{ʒ+#FBtB.|1Td.cw E8 cNiBsިλ,EMop K}_ %4qT|,UYS+a5R8%v8&MK'Ԋrͱ]W*nm9ujN:i' t$`~;>=LT@$tj>m 4JivJxq+Q$I̍pBF3eKcd=]FkHY-rà) SS@Y#,u=$ΣÔ m{i/J%@M/6t(h=UOӁd0--Ad+#HҎW+Ub;[05ފcmhO 6ux͡|+Y`n 0H0 O$lwG-͢AsbQIޣ'FP .YQ@\`}p_kz6Ut{ AQƪ]zHĮS@Sb2 rO`ԏF^]X~A⤥E i >8=H%7gk<[QUXs*ld0j *h|peKHZz\%PTGehzp%H@o7mFW6c5 4V-3ζ0`2)͢걂8Z6_UVF-B8Y.{d]#>ng .4)Q! KCl1CÞVu&Z8JZ2fNWZ SLoA75>VuYѮƮ~5jFvT9oē`B +ݏ}Lkm*#gn'{.~vH^B!;BfxIZ2.xg72N[)ć /<84e~GCz )q'N4D^f* mrH9ZC7_e:T?~J yة h?K ox+^DH_(D8z$9{B6ivi )[a(z0"!8_4~2~> =kY(+#Fyiz!zaWQT>`$3Z&5Ġ=@ZN 8Zpk"<`2l7(0|[\R6Y`\yMR쮌@5d8tiCNb265lZ>!NT:H?6me(pt BhK'x8He1*> *p s.3/ptZ;,j:9<B097 Xnt`|^s?ȸzmō{cL|N6CPyF^reâyӲ%J^IԜAg3`p0볓~g^(B05]&+bi8l{hV6Z&+HG[C &+,6+͹$g7#*jL/)vɡ?PI~?|@||b@u 73p[u3e||iWqDHF!si̔[?<@->s`0kUƺ {Ӑqn-UKnjըfaB4c/ M4a|=|B|zɄ8g o]ֈcWi|u}t݃Q)MvMI)ARS`gMZ;)>! f[|+B:]WiejaH$H3fg_crR9&#)SZ042g3-+8e:Gt!ߠ VLiV~ot mtp?[Y}!ο h"b<X& $Vdon?[Iuo~AGڜ}mUe{S:scO6u ΁> ^G)_6ֽVC;dLxT8=8ڨuw-St4RO!/<҂b3w#-0:b'M=k쀭K)(`eF rHo$v *WقXS_9V" +$ґגZ I1~ ,f&ۦ] b]<|{cqe:* XsF#λSY#M0Lړ 'ag\R!)kXrB=T-eBNb}mgz*NA8b9|cBf@6 -'on6(&L1]0 4>.>FKԤ=>Lk3I aJ6N2={HnF7n܎+~-YT)tݶΒrP.6( 5[ON/ܶ}{2wd10? Zfc2sFԆ:`#;Ky/7=UN&}韓`zlO 4jIpC3FZOQj[O++md<ȴӃ_ˇeO<-gv|Duתrt׃W['oIu ;6/VG< 5ӄxkayȜq6C$T(~pzNБ^x0WlezQ4^ zX.)_%܀bnEO<Iڇ^ bkpQGae8M.~1vMA[$_Oê~?H<Gu;Gۺ$1藄"0eC6G"sZZ ~`jA؊l F~ihfiDUbM^ȱ{>fPg?VcEwZų5+C*\E,2ǜ:a<w]kx-$hυ %A24[ oo%t=zVY(bIk5= X;(d]mFAוe VoN7$υVb J=+rzɾD]otk MnpL]z9jujN`xc7Ec{2AѦxzr\S!qgOLqbcIqlzϿ eۓf|_eUDiyz߶.=jtO$GOe~{n1~1+ 2+@~{@I f &1ZφqE]wwg!2b oaڥ&S{6sM r8&ߋ!]ʩg]ͼZKk_\~O`BEH Xd9|AD5gRIs*j=G3WAAx 4)ж7>:}v XQ 70ROj`ґϯ Zsvty1uq&IOCuG[씑KC ==X$3;kt+g҂ VS]jXmrSML!<׍sC 7jwz YAaꩪL7yX ^ysD3b$/ʰ#t]V[GF"2< DO_ũ41P6byt0:UOX2`[U$92\͈L w'6Zm̸Dp9l7%Cy2O^ W a# Ө`uC ]ҙP@>M@.C+ Y֚6q^&ނhpt3u׸C4[KgtH|ӑuwe9eO9Yml}W Bَ/ hdP"? 3MF?m=H(}_%4.Uf:/~w ސ{3z~TJe4sC`onf:#VŻ'J2'5C'?P !-oJx{+ s69|pF@*\ӆ 8'aqn&l`?V+&1a,L G?ɠuʁdFtWR#="hv2b,gpWAdۄ93mhKJ_-WT& t?a:Q4B?U>p B>mdX '[s6& 7x \?(n?ŭLa4=_\]g O )V2.C)},nLEs\ ƣ#bF'jEMGK}:@ȸuN:x }*@>/p'>s3q#Pmw718;K#H}rZ4&)7#t hǭooYB%ɩdl1D`0 uSԉ\*uvQt1H6,sF;ӑ= g*ϧ,(ťUiRK*KWB;՗Vأl4ϊfD8{a1ҎD=lhL{Fǯt3mZ )a=Kb՛yo3S~7#y=b^g^X{L7'*SFGp~ %KY+53:bZ+ BE&\:B5< hhGs}KIVZyAZӼGFGDZnDlZ޼D%(x/BA%`Ҥ3L nrƩ<# )p*f!;ϩMwA-x6A.13ߍC rzJRʫ൏] G9=-t&ᙅ'~Kp0w,Og˿&GпI?LrV FAkݮHMa.J_X:HJ xC#D|X֒gb#LګvBo ʰFM ]uTZ=]ZH}/;\PgJQ9' 슷A :E:95D  誰e m BTؚiv-z>6"C )~[9>z׷=&̃qD]rlvX*QtG Ϡ.~mlۛ޵d(fg#&s5t62?BN Ri[5ggZp ~5"',!Fƛuŗ]YC|k6{+iQk@09=τW0gXagZҠ^WsF).S6# iۿrd R4@o=}>HTq `1w͝D|yE0"w3 3qzhc j]g0"iW ;b[YB>'ÔDE֓[kb3Ň2Ƙ0`}?ls84Gֱ/F2z /5eM?W7o~sS avMq>rJc ܩ$2pzD3JDBH@bĊUb՝oumA8[Z7b[1 z#b ˆw0'mGJ%{q$i)ҠG/hV#^݀^5"?Ha 2?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP{%>Бw:,< )@X:dUw 2g?,ji2< wH@`obNt(Io (5nq,ҊkKۡ5H;? [~ÀԆ"D&E5i'f|oK&.)"vCP# 'Q@;W&ϨVr-H=3?żF9_Iea·7I+T _|jiVXu+/̋]#LWt!HfmosTQi~*#KN!k̨7_M YPHoIݥ9sWq Y}H_+8;#Wy'H–]?l_ W[+N7~ɛ#"yɪm`4C쎒($v aHk دt T́T)XwQ F41'g9pSR_kq;'>"q\N5Q)_[یL9:-ua>t7:{ =Nc'{em KqE?gX I`O\?vނNb;/B~|Ai.k_ P ~_=bm fokKr6Yhc 'SG :ڈ8XYU6JUU!bvN(#tv1;hf wm YMr,S3:-u2oefAИ‰idɓ"q_ʳ# mYgR5>Y4(W*ۂ{(>6)erU T-Df9 `!ex[:[ ɮzjm9/4φL}٩WDDnL\ jH%lYK$v'{_)2 VT6 /qXQȋo5Dž&eD$m Dҁat[/OҪ#<3oIah@Cӥ!St%ݳ!NwLxz~==X<1d h;l.Hph݅V-+P%ޡ"Zxyr'BYQ3 ȞOKt踥bF.N/ιoczE[ ̉ &YP\)dK.PJaJ3q|a~UIMqt`[adu2.h]l|6w>M}ܳmo'$^םRx6ـ['{CU i tO3ͯjmCe%JY.mCжX?L6G,P/5X7梨|@= .Ĩs9nLSDPKa*j.׆ fV"m5v_wµߓ鳁| ñ~Opê~ 4=9K>Ľ&ْ%baOkKVLUb]L&V#']a>erzTpY G Cy|dLu]^]5ѳ ]t uǜvbpFz3YN?0l&ٛ &.(Nux9GsiBhՃ-yt!ڠ܂vX~8S! ؛QT 59OtQi5 (t>;l:O*G}]mNWښkWDy-~wCC)@;\l,5X!<CGOxPNcJ1:kϫa$.7elMB`%L-?ߒ+%z83 GYIovuq楋h"@yA?;Nj?Z_w!MYeGOAф^?&(H-DXNdI Ba?@(E2r+2fnRb1Qk:jàl?RE*p3i cXSNߚ.e빮:BlDMQ, Or)m8vmPHҞȍkhtPC<m=2N65cwcbt(.[Oݨp_>'RXwV+Dj6+1M 4gG8] MJ// QzyE?d<"K;YPh0 -t>w@ldT]:q&El!iB RkaS_sBQ}!XHCI/ M,y&r,cPRN6jz;p?'K@36~dYØOc),n*lBBV>};I2yY++3lmxęUa} &p{q,Lɺr3r"V74{dnc#-ܔ֐6zmB hmxI]򃿭z6r5#?}舶GJO 8<Zi,yV0b_Np'3Ak U>h]MwT:rGj ;Zz(,=ýg̃HwY3~Nk>kL6,oKHN .%S55m6iy `ZhG7mQ6qf s  \'Ykd4Fբqw{e ~ 9W!4ڕW{>r8b,Xd"H0j+CmÙ}tӜ{_XYĎτmkL#>zίPsijO oaq7{R:4LܠڭtiT]EcV K!j)5W0}*x?ѾwВ–C@tBϺL"_wK@"QE\1E;0obsXE[;͸,ȶT=S,j>X' IX Fѣ|0:Lw.|S-n5 @.j!ށ*`D`Y{ b@wt>rC҄d5Z_qV*r]B]S,>|oHH j d{RBpBA rjOS.VUsh< k/?]Q\:蝡/z wY+ǎWei9~X{ҊnG.)si'0@9>%&2:#*/qVs}?jfi?Ln4J'ڼtYq[=2l?+ [l36S/#d ,3QƠp1 >{{CP]LC Pq0UN=|t:K9S84a1H7PqHEWXx2%QX*CP&r,|%EfGfW@GSD6SwNym׀,˵"ˆjDߚ\ŢEY!mV)L1ZwϔZ:Gث'Ťŀm0`'78ŅxRqA` 7]Ss|[LYAdg=e+08f}@ W& w,Mxn 3qKR\aFxETf&r+b]fE aJ Kp%ҷ`/XZ9GAs;&\RaJ$ [VsL :Vw7'c@v`N*7|> Sܨ1`җjXYKqDVy1di;u`@!Ÿ;"cVo[)o+~ǡjM,>(]y{=RnLv`ްY gc<#$ VNF#e4 2#LWDo{TӞ_o.8[R"lvu༷n7ؔi!=*L&_==<,jxF7@bAԉ** *-+ ̃zu_:}Sꛭ73- إb)'=T X><4\dΩ@4`8!V0'3||>@ :z 4 Hto~0FvƋ~d@&Tʡ?+ޝF!C9ߔ7ܽ|K\u,赆guA#g}19b}Yu) ;P@RTSA~wl Ph.#m?036JxYfuD(1FMg&&4%rj:ECp2#zB75 ;٠; cB01b\ J90 uj@j؞mDjNEpzB)$?F_2VQN/!"0:fc}0$ ٩]qæzؖu=VMK[u`ѹg'8Lza;C |@?,g0 C}Jxz` h.\ƹ8!Ct?F}NB]Zpﰂtkڄ [nI&ť|⏚sz^ D># 9ɹlՠnzi[XȀR5w(1ٳsF׮CY.~X#^"|/Sn?ʾWyV2x؋s VJ ,l=Cm/(ZʶV #}+K+\6FZqCbD.s6 }0rjt%Pn<6/ذ F@@/C Fg9!L[)9 K$7S:_\gzT:w(|jŕp$;$7}֐Q_ 0'ËJbt8oNJk@#haI(o .\ pnFg۪7[E.6hDzm7f !M:AJBKvT h*c @aDZ\ЛBb]? 9r-MR="2 46[y^S(0ymnXU&+KRxAv%T>j]jYk@M}IGfpʼpd]\FS xjQVB6 ?m3=/&>|wI >{{ >0/LvKsZpKL4Q#DK)kF|V7n+}GХ+ WN[ܣ{-s4K1/.,a] =de9o;QOV |dp\vM JuF40,w 3P]2hqM+CwJc\J &vz%? @D=J Ԟ }7#핆K[uG,ʻnJ%$!?xdcb9_{Nm*81,(4?(l=S+&!Cu|ȯyb坓|^#86^4 Uu9X:_<‰JD2zF7 iH391$Dً9ps֝z& Hx2ufI>ټLDÞ"ȶԉV~_ABv۪BHUՃd?rk7NPfT Ŭ 8jE$ v!QPWg#j)~IF Ք 4U 3)?-{50{n-(F¸.'8c=EXC݋ ´#pUaW'8'ݳ>͈',nwt((쀘9B}ţۜdFЭ41?ϳ| uQ1ubx Xq;ՇMPi(|*~jANJ GQ%8"|qJ|HwIPPVs+bEDZFE~Ƹ8?Pȷ:WQsWq>Z">]q/^بUq/'V}f҃:*V` E dKQmex]]O\,>V=P%2Yp;DH>f0uu$禩KQ)rʑZ LsB@ D'yl6\l2 ۠ʗ#3yڴ30xfoګZÄ7`鐾cE{m&`g#zE0ʙ\ot"6c$1&,ܖ!̀02ۧjp˛QlbpwLa|?lL $ ֊ީ!_-$m/a?UL6ev] y;6:7/lid%ga<-Mڴ֦fZ%^nLhUUybR|.}k:]CUAu?C;›sO|YҭȖoIwNG̷ ajx%wDS?g΁ZjXU:ҙO?Qw œAS2~0E0[EOk W\@t>:fGx>I0Gp%!  5(0o?ў-r r]'#͠hܳ3l5x+rd=9jAŒ%u 9X2ۚ!3b12v0~K1*2Mh.[̈́"dKd yɏ+](rg؉ Jj7aVMAp^ˎZÛz!(5X=j3FBlP?՘=;^8Ɍr&yfC8,‹BK$k0II9bS1#Q#c}S=#hAdNW_4MKVWfIiJUXXZ.f]8g^._f#bsd=sRc:NœyI4%q ?p_7э)!o8. p?^tRb0Hz>, u}q7^NE$FϐY@5 |Jo뎜aو-Y]PBRھ8hH S<LˋJwD u? р81o>!8/Z0(1Ee+9/ T.?"%m'JԂ`jrg?[?6%Ş]ͦͺV9[ Mvn>*_?݁|~=?J9fd;*( 'ʞbn(mcv̰ة:(fFfG XI W fC,b:1Jyovn86+'^H)L$ !^dW>D'{Ley0ڙazk\s%S]8 GwR† Q˫e .cM :Ík2ro"s4n g2JOFP8c3 <7IVQ-&E?V/((c&o*h@PT(zN 28NI~/]$$\&Q)쓖)Cr3hlۣQ)N*o3a1|>=g>U" X[7nѽc*o$aF\n@ӡTN6^PBCpY9iVU&E{GxP?vTQ% /|4z,[/C)Xw-+:)!xJ n om5?P d5M==\!}Zx.TQc$^,0]L32Wj9-ZM_ {mIvGXKH[x%[߶.si,6sagf ]; 0\Ywip ,bO$Cq*J%wAj!KxYCJh/y\(Sr.R~zBji-,?56#yPNuPhX"ܣ-BGwH ЇWs=)LuLZdwQ1GpLaYcϷAW *}!-vؒ9P2tE cs5[C 0wuɺÎڛN pR|aNM%D/EȑxigЌ8S%!<# )!lĵ "z䌘apE=+;2b}T~}J\ys֭̀W*".CŒumdIZv]3|Ģ|ۦ1ܩ[uïR;C4€[ Hӯ$7S:WHê]N~ ]_D#C?hZm{ڃ% ^"_&iT)bQ5bR| rZ`|qno]p.J<:]֣G4<`v< ;!vn@f-_EvQ^錞an\lD!@4\lyg>8|=/ThH>(IZyx}Fw}D'j6߹-=MȪ/Fyvn32 9rLcЃOFg!.pL"p8o3Y6u&!+=7Ŋu69yow}Ϧ t^#?A\0~*İ0'yۉp4h8s4%k0ho SwX5_}x96٭9j,ej_]/g5c8o=)KHE6)&|K9W\=$S}Krw'Ɖ5$Ϭ`h:g!YT-ӿdxZVg|.`ͨ @Nkd(gY%^ XEUt[Ly-0VCKMPEVהSJ 4 gЁqvT;e*7u|E)v$<|u8]a,z&5 v)%Y@>0E KIw℀ J bwbjƆ'^ܝDcۢET]*z{eW;[2r(f b痶*8",|5_.q$wC gfl2h _oJ86b~O ~&ݿjLz,BQPu|OGO:= 8jbXS4=Әmt'&olDG1ĝH{D;I8MZ7-E ;[o`&5_;E>#@[J7ϴԤHnM'2U,u.|Ijiա&ƤEc;_C9$G <9$F#h )-vE٣߫v,oc_4Z_5i5&_dOCI쯸ad0.T (ӢG8B  p$}M[oaZ]cha>Imj{TZ,ƺ]ǚK> 7%H6l` iqu/*[o&~?/Ws ! ~"g%x 1@N nbdw`=Z*6]!lqM~V[GIK&՝030'̈́=DTNV>y4(gIy=)5njV n\#şBv.pqUo7&Q<B:*>f("  ))\21yVTm7P%Am ur8_߯|{ؑhiˤwE8!RC:=[(kr8P3‘&au ˡfͫtߟ41ף"~tR13D$O]~`O|ߥ.yR)s6"Y# ɢ-\X7ic 5'pa[[?KA*~}]h5l~@q,Ӷ4XlrVfɪ-GܒC N.E3_zyJ9#p29"=Ҝ JqRqdUP>#;QΤ^U %F?rg)0b~u e+J[W:qy97bJ +b!@){Kn J$yd˅&= &M%~`Gۗ\O30Z7\ʢ疾>$"LiLvȿԀ=<9+uj3'u <jFJ6ՓPd>:]SM8 8ӆ X)L6ZaAK̈~^s9|ҵ27ƹY'H 8pQ]7'WٲQ58f l'jH&xm7Hj cXa3lϱChLˁ w=L`ZT6aPLk+"}\^0O=jWt B%q{00%ؼBzKUѕCȴsm˨&Q8.{%Jeϟvɫȴȯ"vRۼ_l3Ψ Mbv;vãV K CqiU|Z{˨ H~ñ$b Iɼs'ڨ)ToVQ{DaDvl:=kw&ꄞZwW6 w>?0"ss[ӿAl&:Rvk;-.# NF-l;Rܜgov#E+(/V,S;K=Մ~upx9R 3? S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP{+[i(@|#@8 q|+:2*t:> af('@5,!*H9⾓nΙ$%}ҐW&ǠZW]}o|;> ;俜cDl%`rb$@+͇gT~oΨVލ-O;\`k_|1+6`/}~lAʵ*fk H?[vve|{)FS.ʲ{>tGíMwd큉!֦rx |a8UF%4 l%_#rT9ڮؙ&Rե.P?!]+J살5"C9\ ` .rK# ;B~CS^7yT^ }?a|!6Ǹ~;|(~>`/P_"Ģko8Ҙ~nR4m/)x/vxoh.ݲB3OnLcj+TjBCپ"'tJnxЂcH4a.NqM;.yZ':T8`|ArJ~Y ^dxj~Z0%b*خJH z]3ƛwD#u_O~/RP!&Oa\IeP?⊎ʞy|þ_fK1?+UҝjeQQM"Fi/5sboĿ~› 2a#(_gc{;]K}v" S#Ud`>I CO (h<%l9 ugU\#Wה=va%*!7?ń;a'1;\M^Jt%XS[L<3HK!g8gѤoGLl8M6 1@/o; .Aa ﷳ"ayIj!. Xr/|?4cTMEF4G5W3klIW+Cw,QN7npH"oUBh)d*,F 07]y%j9ՕYHO`&L WF Wt 2HH1:W(A1P m`DsQ"\S`o@*&%ه]NyK nzUbC>YJ]kWz1 l`ݢ> ԑglCtLfyϩ98$17#qm-B2-j|8:ixҴ,ClU%O8h^S F4f+h'"Z~CbF|#à{3NV}70'|+_>x꿇d? HK ewvb5 &)̲df7qQasa3xw=ro 3.8L=N%TZ$X .LƹVJ5ØF yS0n@)Bt4œfa-EiG7 ckj}~jb"HsR/~ᑒZb72$;(ҳe[D$aw@rD(o]|VL =*y\*%Yg+hȿyuF4#g;t?%ZbivcҶ֠si3ڏA M r#j7J(:~y*oHw$Nrӌ  WD SrN[LؠMkLw\M#gr" WBdZ`p2y#?)47d=690=8 b8X I$+0Ct=vӬa I"lQP*L dk$ER}6ԣmWTM.qEܵx&c_VS^iˎ<8(|:*^Z<;* (PTWhmJIwG D=R4c#~ ഥ:՟>u}h]4F LTĉhK, CQ4Qu qeW/y^ci`1+$|Sd!E"e (h0 \5ai!єb YlOu͹,oG /ڼD1$}jAGX$P2@vݹjC`\|$Zwqnh" C+\W6~cv9Ԑǟځ+FbU|4xH6Ue_90ʨ&%0Xa#Lr<8+/4o[FZc}W_dLqF,l CgRfEH|ΫyWu/Jco9t$=UcӦ $Eb=_r|/w-ˤ/] x .H8y>3O .ΛjM 8L)jpϮB?K'nOD>HG K.,D`riӎ~/aь0&TqXG{nډ}Iڽ.EltPb^ș^ 7볼`2.SZ-11ٙ^p܋Xjֺ5zSB> q̬!WB8OP fWDm$<9\#_@8$ǣzAin:|32oY2B`a Jb泗j( lW)* 8dyM3<9*5`lJX0]5ŭ0m8'1{ঙgʮ΋НmWb#Г)C^ >*9)2- "K.O5S-M/='f"ݻ5 \{~¦l \N#}&se]Zِ!o%6 r2Q/o?rX3k>x6& KUTО8r:= bfJQ26=i% YӰ2*0pÊAh/Ň7]XV.Gfmj ave1#HÉ7 `qvlKԩBEªۇ M DZ' lfn keNTdž=ƜA ̔ !e"4E%;y-5su` vC~I?Im)!m=>@{#t+JqXub)'_%"g/C[> lܭz{ȿ&Ci#e /_&y}ܓASO{'ڙb[ JeOi ?Qȋ^l6*A32f;K 铆/0"tA`~7Gb=XUt=NG%ZOR=>cCآQwQB KqJ 2PպVR>?엛kr[8unȽy+{p Ǵ5HjͿG yrװ-b6fR$WQMd|w|)'3Qksoa[:ۛTm*,=^~8YO Psu:yA+臭5֔]GQGΡэ/,#a?wT:eK)-򠇭ݵmJRcS[Ƌ;: έ`XP]l\cHK*`dǐNԌom2>j5W,ڙ`EB\u,yIx#@zis@b$+-G ((f}B zDP/KӞQK)/-Pq@dh \oɁ7_l sLR=^f>IV*yp[{Ň6UI|9NUgt'/ʃDŽ9Uh`rґ_EMX+b8soT؄ P|kȤtk=$5iqN),L ߺebTKC\7̂)qZAW Js3 %c Ȇ9=5'3OjVkJ*J b&?ÏFЌ#+ O'lUgQ5l|[B͌b" 1f<$j5vQ /X, o$es@ȯc'N’:%ZhBDne6̯bjJ пR mL$ '^{U\hiP|̿5 "ioOV<߅o٘jbt{Ya'PIU$3Yly|[~,ɞ٨cbJw.cm#7xxa鬞O'&~ (J  'aQ28,h/\+4[FES@z#O9SNJ9:{-%OUl5qK B}WCLv!zltodpt O@L)n#!Q_|8xP#$gl2 WJ0!Y|0>4p>e \4A[UphLR/7[L%bެ e[_q=`p.|s \?m&5Cf2`ǴLc3M<,0h>=! 6|8Gg\KqWTN?S~ZV1ȫ 09I "2}V+b ayęP/WNG(j5koZuL]kdޔp0ȷXnٵY*H^Y>ҩoURZ"nK#vG@.`@C;5/ڳq2-SCtP:TZjPH _jYο>ORQBd7c; !ջi¯9tP$Sj5ȥZ$˴<TB~9qbL)34SXXֲǢ XeHE{c'A&V+-$|>`~2;)H94X^cLg8VB89jtۡ'.< ٮLuXxDjˆ[vjB"60Z!Mo5SGy]ACŀ 1Ѣd*K?^qL{ It Uׅ#o=/:ktm-R϶ ԊaөBQHVyGM˾ %!Q?(Xl/fX9)SmxjxY F^G<}^7}_l.7 ǃ?|zp8}>Gܖqg㬗#L-'GT@ =˭s@q55I1j:67n!CAA+쓤KOT۵&BF.'P>T19q$zS.裸P1Q`:&&b2.:*(r ᣆs `&=Ln\{,EYdbWܩK~R7/?xx<2 }|ҾC*kaL{ѤFI$vZne'gsk]#<.͵8 p ۇsZ ?%~?tޥVi@3aXgĘQtYφQmypD'kBa2 -_Cm %mE]Edn.JROH녧bE!Dv`E?<m~)2xg_Bw!0t+:$sk+fZ6b,E O*"Dr;`1/#x5m\ 䢦^O&4~Vy9CU% X\FG0te{3ёy4Zqo yj>Λ#,dzc D.mb^H_ ܤ.UzڍxXb;c)8S~ƭ]ĝrڄR+Tk{7{0##>y^굉cO DF5zmSڱgE5V8"Vj1; L0?7ׯTKMsIvSK ֑9Y^vREXl>~ N5Q?wS;G~ç;O aX@fc(#Eǁ[Q#%OŸr\78aW3:)mǶ,iH!nĄK 7;8m`Lar¬ ~ LCFNY9?=`:}Nj'E{uϖŹGW[ ԓ(5XSk|B#1_j$9%]%7:QўTA@N8Éø`B0V qhfeF[z+\.v*tۮw+> -r`m^ m>ֱd)\݇Q=!P 8tkd$O>n|y=8O\$ADVan b Un7Rp7 D7+Fd.؆xNdxY;i|9זS=a<}oyf(~FMBt.r5#6jSHĕ:ioCȌ"lZ=dYm`hi.- Qf+۸ .@8IfASuϒkXgյ>M ^Jx$ֺ yJD_"Ο&wC%@LHHWZy {+X|%!TW?on'X b<=~GA?(>է87p%q ^CyRls$e! 3[)boCMφ: Ï oܺVdp6evWF;:98Z&`>s8WρUM=tۮ!p~3c 0`6<\nIT&--IU u)Ov awst0*,-Jq!^_LǼ&Q/ѢFʛ"ɟ, FLYb,oѷmC*(ua^̿bžt8"Kz֧'nj95_KD 5,+8FDӖP}1<JW$W֡f*-8TX޷hNcZ*Hs0TұF(=7]_C8"\\ʑ>1iaz (0;@o".o R|QgVp7{(}R{K\|KU#C>M?¨FY'R1cSI,>U nSg$+1MZXSXGC)fn8LmERI̱ w&^ގO?r*Se+v*CI}['ҚxАE|jVdǝ +Ǥ(zevkmAs{EcY/qe'Kp9axEK{sBi$|1>].|`+vR-78.a x'˦]܃]ZGb>R󥦄 bи}Y18OP)̡̹< =#to) < Nń)5e'_=Sw2#2cX91~B2;.Vv *#Y\`A)Ɓ}Y|b`~?=eboz&\9aQ[PF.-4|@|@|b$nL=M B/1-cE!@|i@^qD.ʤöW KE0=P@fn(') =\ͅ!Ƕt[iߌӽ)lwzYe  YV96Yk5R_?8?kuZc% {JCa"#~iP&hkFFr Ų<|B; Z 8YmIz|1\IU~XYLM;dFXR9x&k5$Q87Ӧ.@X3jDEF߼AHqSItu? m3BW5N᰺`A6ú\[ej &f?bX]\y>_x$Ր 7 V&az9a[S #N &Je{$ˍۖb OFBV\6p1Lh|.)GoZ,qH?oDK.7AoSr͕-3\ 5ML~_hBbbV_94P"KvxRk)Q'B}/tw0]@)]҄ʳ 8iK[+ԝܝ+kaNCr?72Ux|z0G|=Q08IQͅ-@E nK ܲ0vsp I>-⯍Dyg}{Fu &%/gcB!1JVjs Bv.&1eQ9QS@$s!9Q'].B::(1HyUE{jL{PW 3[ kSF}߹AcM[ws0b*,bA$ :)čت ((_elgYRIH˕g\1jO@RoX UM~I|O&U8 ec0rm-v0nX9:Y9ln;u敫"I,w">'2GUO2f(.aj@iۉ:;Ï8%{K?͈ soy 4<[5BbE~ݩ_-m⋍L-.m">9߱.&x˷@ӆr) +1L >5d%Tz"U]-=$}b;Pjc@@ >`'?$WP:] ta0 ~[$r6I`b[(&?ÑrN%j͂iOŘ #t )l UIE844$r1KhXK8s ݧeзimt>9ŖX=UQ8Nup!}磥eуchjN|[8ǏΩ(\VZՐ8O!˵[Qޑ!+yj'm|& tSRYL:F&&,kd ,]LrW{/L؇IݡrkEU?b\貑ӕ6Xl =YSwx,VkGQoSdwHW7)ޕ6B埾YU.9|6VyG?e~=u19Z矄-2Ԫ,XM~[#*%eg !&p>-s5t|5<77_<F |a^'W0sT7HHqhZ0GqY;A 39c;b| 4SX́r6lH0?JSA>=2NMd;K&QQs2RfMCpU] q  D#[˟LXѷqT>쀎6Zt4a kܢG0!An LLk =o-vU@zB>:c%CkZ"<"F^!%j&ލnEl}5%;3PIqYa@H}:l/{IrM_9RH EX^+̈́Ma=5_'KģE)j*BI%@frO. 9ɬ,|j8qѕ|qP1Szu`,whB Wtl^`2X:]B#V%%>N_h NyQE fqǧҐ*ujF`ΩG}rL\B6VR",o'3 ɤ=L{s=gx:Xyd7}aVϋD`c8#(4XI@@aJVKLK WȥA)u%!~Pd zakF<2TdDR43e&'t8 ш͏>Gf5+BY]f$6(!G6k;i0UD\H:bS,Fm=6Q֝У$Ƽvl-P!Vǟx|rd)A~(iŀ;wyfu"iPնQEq?%BG6^) (hIJ-o ASN7JE" @U&vTlJ(ǾwڪVNt͏.7^leOWp…2'Z\.X!L@vL2? HgE?~@̕k!jd%peyPJѿV4Îs* ;:4_P= &pj F|5 3- ̘SR7f3C#6nR2*唻A.[p-8b`$]U{KC5S[xq]MT^Mºh')(V \Pog7ɵs 󏷻cy@@Te:=d:Mi>KxTVѿ')ѕ.#J0za{ןN4%R R:')v #h,4tX^n.$6 5ŦE\gS1&Rri]|邌]vS ʓE76x.Qr~pl;~@k'uXvD 0=Qa_O0B+$Zhb}B_^'Rgm,uGXqBvǬ9#wh"a0Wks$#*\;X+|obi;7NM ? }LF*JGVm/yϑd/$ t:"BNڮF& +~PЃӭ9ooirӹ<zCN!&i=WVǡ?ePQ8P3. mgXϫO)Dix0PnFf[ެ+=Co=iY-JP ]u" `ĕ5XVC^'CnEli6B|DE: !]|͞ݟ\b֤P`WJ%񿱫Đ VU NG]dF9RY{CACRy;VxZ}B÷١} cT y~O!Fr&aEuoF<,_6M,h+MS~yhiM -̞ gM0""$򚷽5]; *u&ݪAJ bR(3Rmuaj-1C&پUsu٫Τs!m")2s  :يU ()NC[/;XoFpf'(#4ԃ }9E2PYW'먜EdɥI,F"|ÙW<\;_쇻/ 4>zS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP{=Պr8h5E;  QW9bs] #mFZ\DⷿgCTY1Ɔ'2;EVs9Y?,B^Djnk!Wͭolb⟟| ñ@|wPb-7% pR28i2igi-+s< %nzf[^ռ͕ئf{ˣ@qRiMNUDj{ʷF0@iBc]hڙ໊º$;Ɲ9hQ:L/@4ܫoelCU g0,iWXYr, q_H!mHolw# Q+ GoҲu2&{W[gW}2tc.baA[hUM@i(<.r ePUS_o& @8+B+c]1,Yk*`U"SNaBC~xr5q=V ҄DY%"0לD> Ji_&3C(g0?'lpI O> /}%rN]ޙjr ?S"Ec@c(?$J:Td]%V Nyh\Y[6I&f;k#BDfjo܊0»Uy(Gѻg2y-gc_iǮKpKClD+B( 4.mGPCW9&*wʴh0׼]T?r`Z>d\̊tAwDLSjiOl.njp)"T&v "Ϭa3(xv2"!*k{͝asuARB =@?+fZ5ȕAC"#1#m.P;\'xPf*Pa6&; * -z֩wNA5)9SLg.,67sսƇ_'UK[!ڨ 8"3 nRkCAPX>* ō*ЍA޴4%(ǼV@/h]MJ3!fY`nCԶw].芿1;g^fe8s漽3.d_dm*O kpI\z3ڰ*G)̑/錏 -F!9ǩy?2tsYE]b h }ryOK:IFEx_r,~Z]- '*7Kg7*;(7պa\|%f辶gVJ6Xcb]2Ht:ܠk,n"$S潲|4\^蓓ց姭ݨҺ)__#V+ĵ ?JOδ @Cҫ12LE D__Rz 4=YgaG7Џ"Zy_;Nt<)JB'˜?o~2?D:(>]wǤcrwVF.,^>6SUqhL@~-%lYV8pJhoPMM> ƇN|)KW__~òЀxQ4h6U*ApA淙WdRcfu|I*vu#˅6=~M.΄2k?f-f%&F{8S'%,CMUqL$[ 5 G Ͼ>it^Jde(bp5W{]PDyO}bUB ӝG&$#γ-,lj='&Ml"*^Z:鑷qD'z?XW5ڝpSꖶ |&h&1pQ&,4 7E&]}񊵋 e(iNt;j%x={rW)o̣k%45öԦhn|YE̕y{M#Ԫ˰k{Aq"=rxuJ3< oW\!CշtkuHy_ju7u"؜mi0bY,+wY{-Ne|顎fqS<:w6$ީB#9zL[L~qo(OD/ferak2`QgTa7RX6=Nl *!(\jW:9ÓKO!6aSdߧ",Shq+yd2w!ՔP=r_[| ӊqDrSALfD+0Ǖ*R$ES2md tX¢\];k#2Je]LgI8=.'I@iVyD7@ 郅W{UԪ]触`f !X&iC8? k+g.d=I̯X)]ApTnC;/48ɞ/N`j_ vWw5dUbm*%0O+ntG+쑈v_ޜmO0W#?=)/22hS"YRg2yFGjH P9c;2풚c:7p.nK=H50QE19maVl{R'o$N+G#'1QW*R"/}!!ORW({AWs1׫x%+ ]|%.j\a_Mϼc;$\ȡyeN9J_];xcQH΢Z:͇.z}NFYt|Ȯ+???3sZ:({" Y4#4H?! p,ܩK~K0F.b'^v\՘+m /t~MpLy$sX@Nߡ&@D>eh7YW]/&̝^~K*tkTnʩƓYRbV?N)N{@_j5Zdž,I(cnZ}):Lk rZ\RvPr bA5\bI?]B5Q:MM{v "߂>4!Kz>ב;A*҃Jj8lŜlX98"ܻOB +Ѽ~0H8W~ooQgK* 1f` n!=ܽނ=—5_~wg@ĉ9]Ӌ3vt]5 Ϝ+G'?Rho=fF҈P]N$Bq+~X֭ǧbt1U@ Ȥ`U yN@WJU%pUNi3y>-(W4횠WLyUpLM53vNjW1G6Va*+7 "yc O櫰]: a9͞>,el534d9%\G0pį2eZWXY7Mp|Gm>ȹ$"ԵI_Lb j 0Y&%۔Catiج@V{OL$+=|\oY3 ?]⃲4A&gV !"9ʶL}@ѱEvkU+|| כUyw /qOa}SgWeyȪ3 [OYjq;tX9p.5L@iNO )7ƣF%ղk]RJ|8R^Ƞy$=[Ɏմn&eT۷ Xʬ_ۊ~NQJEÔ]:F#  >篿-ζPWA8Un2FN|48@EKY"71+*LBĀYeny͸8\LJGwAęeWˋETFZ LSK_(dTERG](pL_Sg㒰OiE"Su|z*myїJp+oaW6*iGm}v/%RCGT`:ncWB,Bn/߯=s/6#%<"yAHۤdCTY*f+KG55*[j_`RYpFTo@/|`VV)/[rmEyfQD]D:t-˕ GW|0\.̿3-Bn[bF0kVǷYI ]ZUUB2fWv6nHJ M@2/sZ'ܚ8Npd Io[3@7#4u|ǸFUz꩕Exinwx B4/EY-բ&XAY]=!0#(I(rmǾu m$G!XS*@2G<~D}Si7ԢGn)YtnL]NT&<3wF)z-fŰ ~w"5l;}B *hJ - x^8mcetgIY *oP36smsvoZ-%A3s*EUq~Hy됢hZؘfs2_-y{ Wo`D;Ib`/f} &0q5 D!s̕&=(V37(=EP梱饄:1DjSy{Ro&Q Z%1S?W!e/ټ ߂/y~:^L2}b=AdnM/c*BDWw]qeB摫Y9R.~HrJFQI/aDMGU$+#I?CüL6b I94~͇oIR궆nDf{ʐ%Yn ġCܤMЙ38¤P- < +γJэTy80-;f!rozXAc4$ 1޽k`fvK쌪E"#|VK?fі>;HKWhv ԏ!Pa<| Bf&$d:PvY f[׽ s2~v67'."ϠkpO*TiΤ_&&O8|ВYUs5Cm: }fyhRlo`.77w߱۩"[KU yFaU _>5ѐBM,~awsV&֮PPS/Bmn>EWX"R\/Ysp! }_>tJs꒺='c_ܓ7HKn”(1ōx.]z:6(.Ac/*T3d-ԡt4 fV{ܥߘg.gc.=FҸZSoAZ1!b{;/-ϪK,zNy0;撝@( ٍ[o0M&Mb!)?55g=-U=oi6Ѳ#8oh ԌC Q}+ AU1V-WM:ks ɰ;LT㢆OKhm!`#(m?#4LF0pd`zP0겷ҍ€Ȭ+}C1;KQE:I-E3Lz[z@P\Q(B5K&@QBz#^P"dweE ~bCB3&4*,2LûZa0;ST" ݹL^o$p YַoՄB$d)L0f8j>E00c6) #;"Xճz ͖gcy^4Af(&z~·kt54$_{Z}!0 R~@JVϱxuZhǁS ̿#|=a r |rȁ S;@C1fNVtCvYT}ϺhĜVO}? dpuFZfc#TF˂R$s[) | 'Ћttr9ZT4XXe]ܜk:Hi1ƭz „:q%W 4yE)'@'L J|Tn j:/|׿OJ8+"qUg*=(I]e/ubqhgOM'~..2$V\ S T\=UgLPB̏Oj5"WO52ksC'oA hZP2¯Nil1%$`e`l}u^k;"GfE8R>;ՠ~9 N{lzNwѐYs %9%:4vO Byy2c)4Yk_6iˉJ}@rmSAx0AL{2{~H%}d#N)=j"h5G4H74Yҹ;|DZ_,<7BSF%Q?-PhpH+<\x\C-y_,RV:IqլP i\ڛLo@v52Hta2QiL 9\zUzl&"߫2w!Df tyǹ>eQ>vI*29rZ5l% O[iKcDQJސCRSLx,ě =o_˨3 ?YsoJSz l ;_AT?x8Si b}.xPs Պ{`^k ~mv~+ Y u G!3)Y|g@ܯ{(5s:2sÕuՖAn4)y3QKpBŸ"Hf CaV^kݿT~ɯtnZN9f(TOA55OB)Xr9Nx@`1UPyAj|˙oC6.–#G ) kAy X %֯gq{yw; xuKdѓny2K^j'Sȋ{"RIV{_*ph%1. _hY3lr?t؜ \fvJ,.oښnQ:ow# @5͇O'6DEՃ_3HChD(U3lXQd$yṗ ۏKt[а?_#[ӿ"Lr]L:B33AXB% dKMep̘[Yik*ꀉ]p?w٭ͫ'ezJy@#[sPyYV לG_ [@ƐJeb"I꿍feE<^ؑ=Mwb%Qri lBG7mp}7 MR@f?p=Tyy_(6=,ϼrJI(YHbPN>(z)Ʋ#k;)]K:2j*Gt,h2 ?(:Vq`}ۙS/˵K!\ڎɅԼA!UtWJ$;eys,ӵzTޣðGÑHXoVb=4\|m ghcn9+Н ؚ9^A7 Ä{ٵݥ½PcDn3{c5逓 pzIRFPd~.?=ܪelu3 IMFbLW|㛼 gMĝP$,(Ɠn671ιgRwMpʚzk[2ޫL|dt́725b&B ^;, 4J^󹙤TܐbD "R B a/^bP$.u`kQP8Lq'ᖷns56Q筮$Yg| 6{;?z! B#29/S媞~.?;cBns?On>WbnX o8O^HpjOUpfwRځNy2J Nvڬ}RG{m$\>0Ừ?#\=_$C^~A}4픫OPWR{{e G7:p [ɏTwPP#+|I:<D( β5ՕI}ʯD7-*e|ƐE(~cی ś xғ^!A݀B+8<8[>=XOODfT5Jb{ƱӢ~ ȼٴ|4B@|zSR} Q > sZZ&SƒH'F 2y};,`')T*upcY;M*X ,0Rq 9F(M1f$ '/8(M0B1~ t@jhNn, V":T\gyD5Wl8*Z/{AEq>>J6HE~LxՇ+]enEaKA-+PQc|~V]bd@+~,tpc̪:L4/%ň{U}1֯ݖ[\N'LG? O!?!\' :D_-p\ n-&VHk;k״}Z-_+J{B4a?3K]BϏԋJNmUxP`>$@.`]nH6qwT0KrzkjLX A.đ}wc e7%57#Cz,U(('I0o%Z1X\e)ÏFm$^L IE1xͶA@lUVPIݜրAĺe4| `Ϟ]1<@;U Gh`+يcf;b10L: V?;DY^M(øZg6 ~tv&Dz3qWR@-oY0hY5dfHOUNKڭpCWvΥED0;A`eP\_'gԯ|eB Q ("T[<̻wA/$d=?ly/9AŹٔq}?jcϠ$Lc0uuLk]nϖ-c bkԪ> ?ub\>( (H~3e5 Ey5%!i#>v x-/{!-6iog9<z[Z'D3DSmXuksGPd ekrj!O5c| G DU:j BUy<)oﵑqU! b U?ɤG/o W!Wh鎘ƾ\F,ʓ Ckz$!C!{1=N  StտBeQL:T59/tՔnzFz[*Wo"^#ɋkXHb4lc}k׼Co*SA- #tHrBuޮ:;CҪizьCPw6f;+cyK1G^B KX 2<;4Q<[ ^%11@ w`~ܭV.<]>}t|6XY O@^s謎l~04q˞Jʵ\|˛r Es}9jOm|ء$wP:~? a?t+]ceۮ!γ79eEw/N>zɆZ,c0N [zR\yKϯ(,)@kEKḎU: c#JreɀZvJJy*RB̘zFX-\Y^T0>^Cٸ C7Jf5@NUF[ŒV;tLW^iCaъDqbʑl#%:%jB8>_j3_5z+{UmSaѲSp#4~.Ozj_řBΥYJcqm-0O:_g go2.Pɐ[g"f=ͲX9⦊y'75\URaōڴ ?a? dvZΈ{>WՌ2$axo\r' LF4MԶ gWH iŇS(bn%0aϋV",[E—ezC~,7C=q6LgIQgF|-!h~gx&7\ZK0/Djxn}Fp|U{7WV%#xnׅ?~#(5ȂA#qm_σ)wayZt /U@.3"`' xγl׬fe$zxϴnjH7 1[E"8Eq[U2}= 2JeG\˚OD 7^gT)cɁ^wu3\sS59o-Lβb9/@T8r*ǵέiQ BVNgm\fzMtܐ s[ab)R=r ŸJg^}&;Ut]8d@t{[? ?gKgL)?llWMR6{* ;W_+:x+A>&vRk'V>j!HS3j5 "_ot,kzn]Y$wI]>GU9'sCC5Y_[UtmL^tXS6 H7s7lN ֋SJLg+.\J RI/u<O`!fL9ŽH\tq|lMjKLby(yN–[?<'"w #k=>*/XmXf,Vc/0Rҹ8 \&}%y8--wo  J>cT ੗Y 4˯ e=ۍ cSrf&ө&: ;ySBn;iķC`p VA`[Fh &=$54rN:vvZ=2Q2@&\#Q7k%eFHDK]%' ;&* W`IN<&TLRWM#M1: 8hihy@JF*xWrKqK'*0w7T]c[33_#$Ḍ!;)=EóCA?6[i{W7*&D"1An}uF_~\d>Bh7UCi#lO$|OZ{o=m#}s PW'ZwNb\$y/W+]pArTV au` p˺?RO׶\{abOgм:Ћ}H,u+w[N4M؆s]w(=OV02Q~l>#J6c)Y_[ʡg^]S0WU8,@¶nTi|#,Ȩ.K+ěăVEp^ +PgeU͋9UR"%/\ɘ#b\.DB@_N~/HòbӾe#w"L?:V"r-Id4@)1W`I1l#!.ap|t~:$MDz TՆfxs*6$[,,fJP<c4HtNVᒂ g\D^&~"ˆB"Th cM/o1FùQl2XMYB|<@tE'Ip2QCXOXL^TjM~+[J`BXD\|NT,Q _ӑm3֌2\lc}TQlF0V:5eã_~cTZmMآ"p FN7VBzWL\ӄcPr4/uT**,#:) j FN1l8%HRLl~\I1o$ǃ;t)=K&NcQ NRYlX.f5 V%ڵ5^xq\.d2_HY=u Df2R57&4IBSe8ґ.3LiBuF,[A5ii=AS 7:J;qՐ(J^r> p37_ygU{2f 3˽i+O}Q7,%H?^HY;"z\Ȗc,  5>>S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPZ"zQdg:,@h6i% |+@:t6#EҎ64TU ]<u)c>啴ݘ`oRڇ1%ӡϲi< o4|:|vbS0S}zC\R`%ܥh3/`e`,/Tyf44/=%+-k'Y vpPݩ%-sM 8n`[B e -U  ωa D&65w#0b+Ŗ6vm u*Yk174k02luyJv|+C|.U7H5zŶ@54%Hԗ*3%q*MUDE1_ MFpD.M\ګ>dD8j4s blQUlG/}eb4/ S9SJr7.`[Is ; w%]nrYn]Z:^g@&Y3kʠŘY!ZZ蒹шzdg)N#BI21v&aLzH6Ax_H~/b޽`PK|q'j[fS:~8yE7k9PUtH^TlEQRQ 2`\nSכ蒳ېx.`4j% WȐ,]N k(U:,NF^9br& I>1,JGd/fˋ ރũZLiH r% g~iQCX 3ៜ\ϐݖ1ZhJS4J"i$~2`L'R P E +*x s#)|qДiQ*cf:E4:-%m(`2~{&$6?6_B? )dV)hrYD'3.dyNЌSE//^qخX^.=̶mabQ~Be4rb]u7h\}s`!/Ǣ]\5S |'V_@OaCrKh.wP{q\1<C޻Of(ثƣ($TsBZN0tmQTKTyĂƢQͮE E:fZ ak k,a&=HnQ!7E JVqLX c."&)E<3SPd=Dy ~z'3fé>O=fS`yl;[KAu$[Lcg$ ɿ ~BGy!ձ zZWnA/Y m6 E󑴧` 87{UYRVc(.uN^6qM ؅HaNMG>L Ԥ;&0o 7S"&%e)E 5v%Y~ǣA S5>򮝉P 2keUFWrvk hZr7Ow2złmL&N擰ɵNF;7"㳸X!1wSMG=Ղ*,vz#fĎZQ [V2' tO{\ikĆ`if'.]`]j%0ư$cj;NT-ǭ1(HٻgQt&`ݣ0njMڢ|4ˌˬ)KuFJHE4jAI#̟yr  \GӚtZmH3.vuV}yD CN's~ NM+TJ|EƐ}NeXEuMY 4"(vb&ttsj> ލx^llP 'M%rű%c4õy&ήW;bx-%3zãyI&t^9;+75Ɉ$x'Sn  :.l9ˮ|p3H+[CCb2J+DSQUՒOl@GzU\UB~<3P+Yڵ daSDb;\)~Q.GZktunOc]a5̩ :2ւ i"AqH^JŵXĂ%flӞLg  lHyo_ )?{ qvBJĬl#Er+2 I;qDr&Nc Zn)"HO Mڡ)Jt`BmdnF1A5jɴ}xO{VtM Fn♟YsK.7bYaLUnX57u̅e6Ǻ E'LՁs~T 'XRbbǼBkwfC[IRo0#Bu[9o9]!FHB Nw x2*VԀJAbMhC$י49%dsU->w7RIϔl 3>ef|ޮV8&?Ce{y6W&ؖOj h9MԔZ2t j6@5x$l97/eJ{(L#jyy*v&C-|̲AvXR!5 Q)577D0/{])Z",oh &`6/%G7#!?)xu- qL Y/&&<a:—ͳR WrnjΙeWiK jRCgPd_QJ$Mлk/֛IK .jP.(('/{y=\rn:j+:?]grF$T)ݏZɯ3ml]^;\]˛`YM^e- 4Ni!C3paN_qmF޶Y$Yjx.K1jqLp5p$Dnꭓ0;4Z!M=Zm-ö^%ַRs)B~~TRsMJbNX;G}GX׏]d2expPW뙲wHéT*Rh&B2)#8uh+t*>ƖTV B*K\N3w͡MKp,!^rΠ_B&˝zbΛçs(9(U/Ģm\+ɜ#O1ؓQ6B- [Mudr–p7z^.d&:mu{J ~ǒlccnQ i*Qy `mR]ޥm~XɚDRrq1uM4|ƅG!~qK3R=)2 m$zQ-NKc@AUzXEڦ|}E[֎j5y(ź.ITMb<_PABY1p`R?6fghdj׭foeij<$Ij?l+oj wSz2̆G`U2tnV{[ Lùc#`''Hx@|iMlH/` 0;1|7lN j ?|~덨&,„1Qn\'({!Bd歗!10;%>s瑆nȋN-p>= j n   'pnt֊DŽZmcf xIKY!#a,fcڣAÑ?Jl~tCNNTM!l6Ei5` ?(u.a?ՌsjgdO+'yǫq݉q/]}O:LSRhyOiV@1%m{p`CJONDFF=HR$IR *@E x'H(9`_J[7-']Q\Ai#No|,Wcz$F M|G@sL+ q${?QI5p)2'h&ʸk"!%"qꃧb|~B?zΨQ@~۫W0 1@@@&M"Q $ ; c)Vt~KGa"I. Cf]jԸ?5 o '{xv]6Zm"kIŝaGvsxT )6e06a@ S,0?#8^mK˛bbEcJVk\sGne"zӻLD8YuHF ɠc Qⷹ;sm(~lG W BD'A6RĭqowEw22u%{`)>(Faln2.#=)xz7C4i5T~~ci12|/ܶO`}S4ؙA65ug:^5*N轖0)|MD?Mܷ.p27g#DU$Cqgw.!0l<ȧY bvBB".5x~ ɖO+`fS5$l뱧Z0PNUСӊ]^&%p-  o?1 3%}Ee# ?1Ӄ.Z9ߥ֛-R;Rbu}&crT{=Q>ʭB81bb%-kj!}0ԋTd+\~SSd+V-oSXq-uVrXpb`v/Qvkgy}䊞[=0=Fk"Iy]|a ;8};7u)Cv'MD!d⅐l9لg]Z+eh$7:a9%I@>oHO<0'qRrr "dhQvCWY<[zS JS=yZ()|̏y׾m x:myBcϞq{ ;։ f63Fˆ{o%*LyP mBdvml{^;qUxՃ7&MpqgVSA=$:ujW?5WR:{Rc!T•ŋL|d(p1iqr+ެ),RaawхȴmȔ &/#{QXpV"vζ5 y>,Xb]visȻU>k۵X I߇챞3/X tp|6Ht*I&$.9"iWw]?? &)^+(MzfE:*RT+$WٰqfBi26'ȽM;xxzwAV`TƁ@C4,Cpo ~e%BVFgzY8#( Ś G۶;uywG!7dŽFsfE%|p}`gXPg(uxDM责yGτGuA"3Vh*[^ݽ7j-*MZ:D[$US?W CTWɥ旑c)pҾdx.eq= ޼x5m)*LZ̨+ @W}^A~z_X{:pW^&pE<!>>JHӖo]'^n LxQ93 j0>b2hn ܥdm z dYaQuxD~qT=%%EMG&-9ۿb[V>ϟ6T/c]^jpt,WQ}u_)R\0QmTyLEYYʶ7Eԙ1&># N_QٕͮꊒkcydYy,cpCL XB<5lc.Ӵ?Qd+GFD^=S9KTg ;[..OcDaUJ&eJV%U OeZC"+G`2m.)GFv!b+#c,tD`[ay}π$agzl0{\@>4~̤]gh0]s !QgLj-e cQ%yfuxnlS8œn=kATBth1ʖxoۉ_lB2R.~WQXn˝•7zF|hH9G_فc[pʆpcF N1IJ@0Awg2;8΍PH\Sp6g>igw.a1tJ_uS yt@iƤfT8K]M5F pyT7'x`TFwk CJT s-FZ>:.%ӉXšBxx;aD ;z=S|l0 q"RWk%l r:#zeO]qI r`-:5P4n-&e Ae q~Š!(bhv)@tصyEźjBN݂eFX:  'q㡣\/ kT+CҗnGed*ʊqAtM'-[KE-?$!49fʗߵ|g 3 '<-^7XABFpL@KeKRv߼Ѣb|ÖB)q9x,.7WZ  I67kO%ss.`%4G 5盹#[`7'5B?pƂa5YۋPf dg:=|d`+s9L_ncXHkrp70N0?7M%2ւi+AUTz;0f^|2plpzj&&l/e Ha8ŞTUеSY&EdF `lʴQyycT>ް8+.{1鴞 /)=)dN^Sܨ?_*WھMffY_+^!`MM)=3ܣ83c0;DΏ-JƸhwu}Ȅ6^aZ]SJ$5p"30wL OB&oĐ\!N-e܆O=\Qj Ps{8$ߠNR2@bX[r2A G1k;Bg~eͯs?LԵ1IG1Fv?g_mĦ'PA|@|#|b{{. 7Q`#D||i^ȹ;SD>&XUc_l"qH$ٓXu^% >7<' rbޣ.8nvj՞'b`|;C|wUH4 mbՒʤhMv#WW5-C \ZJED%S#;6rKCݭ?E 0]DЈ6wpX\GMPS9[3rX)7-wi]Y^][k/㱜u7O_VtXb}klIs54OQWڅ;֯xʴn@BϖJ64P9^9mi-~K]es DZ Wak1ȥ)q.ߣ)xikEioV 9ls!OqyRa$og]<*Vz䃸}ҿ/:Ȭc|>_ 7\ھh`*;9t7>rU .I 5,JCm%[gpxƞҘLws93YZB8-\>z>+jFv'/6DBKv[0*PB%,~$;=LITƊ–.u hO7\9jk߈qx'GrCW#C(;uEo":߁7꓀T;KU&slVc>w_k/ VPoxM %r5`-=LA]YtkhO!3Uq*ox*3% G0P$pj"2&g2֓E˄3;?8Ke|z0&F c7%K@!)9vRKBۤރ]k-ةW9pXSU\6v5r.?Q~ ӏ)&M2zH d7yЕs&[G<^7 v;=꫍S Ce$uXѭƊY+B/&4A ;CETL" فyL+VU'v$Ae.PH7Wi5Ưs%-5;/w '%(l, mOkt*B',:gs!*oRԥrDRTzcW JZ܀PR1I+d A)K1Qp2a|T$LN يE3']:xP! "mJ(b 6[7w]+Ș{BvliYuNμ(]ރԔ67BAglbUpgI.@&񐭃\K׼G}zՏx+xayl;Sl1]$Gkk(q0hh턜) H<ЉLCI 龓hot3ZrIeb?#0[9{ 6 m?@ʊhk#rOy_q;$t"d5PFxJ8C+b6}NA+7w.SɼzG߂n.$B߀HU5=\]GJg9, tG% Dy8dM]>|qlHx`UKٺhJ2a$ہgM+\w ~d6+3&;f5ix |I0J57 aVjZg`nX~G ,P9T^8lo Nk~59R O#p`NF=N&yY"k~̾,5a瀎.Eј BBvkȹ+ޑBe370b-"P. mZt<׬1d )֑6-2^dJ'Z(!23,7X D*UQaI8,K;2ߨiNE S2^IH86gXH SeED$-ͯlFed,KthP&{>0.Vb6*iBֳ }\]<8*uA_Peoϋ=HMC80S5 kP׋;imMR+\͓4-2Gr- s\jաTZ:Ձ 2 aQf72d=J'-!<Ϳ?IB$uW%9'z 7t8aѢPf.!ae[g+0|󿠕wVZV1jPf!ni# OA# Ӗk-?b4CMm@@f#rs[z2:Ewe:gl5t>d%5Qv}+ #1PMGcmF70wrN9:wdh8mGU^ӨMM"& 6'Z 9C2Q7Gb15pqh`P'U)" J "sݼsVشTt&=5N6M/L+/0Rk]%;q!d߃ DB:)M>+mu-~*ec?T8ǦYB50-VQmĵu=jA%D,Ժ)>{E*8̋Npey)pU)m]o{v;vDAŽ?:l M@JI*,U`!|)~jcӣl-soKB`5}]eC㊥x?.u\]_Gi=~y! \~ܰ {_!zU_*%s%14kn8n@ 0~?bgq) AP8I uK `A O)jhF4X@%X*-Tx $Kޝn$jѲkۺ֙Dt#X$ߌ: M>4j:!fR ʺ=c)k-LOi"X7ЄJ c<||>Ibhs\o/5G[OfTgG8]q\< .6q/}֏U)TO-!L dfWۼ,?S4@ӨdSa94{  HfN uI1H7\I ]նJsi"\l߹qQwGgP=p.9zC FBvIK }X֕E0Ɲ|WsaZtI\Q?MɗT39".hfrBy7S?N|+M>CFOt?? >K%ik^Sff\zT~4j!hѧAq$f'kjĺneWHVS¸i-pyZuN88$F4Cܺ W守 좀+)K68[ 1U; +_Èu?# ʤR]9A h C3/_pQ~ [Gq8ѭQrKsLLIAAM=?2KQfTb03-(gx{B@VӢm *MSȝBؖr'^E6K.שiF̐GRn{tu׋$> w]1ۦ!^j=+VWF mzsO.itw;"#"oN;Քn~_FoꟌ0( GK8^nQG^BvO'+`0x;B2mR;X?S,Sі;oqȨДU˴p+ T*'Y$CăìLw'2CNhʧAfGYFR)UނXzCB|2 !^p3*V.=Xz[OIJZ@Dz~Pd<ϰTaՂ }o@n(+Y`z`qڅ~k[VNE#!#dCnt֢U7;jKu3쪙ψfZPq8%k+є#,wrjpq?S ?"+z-)\35`1c1{\;-}Jն;G|h#,+M9ڤdoXT&ku; D6V\8mCo1(tBN]i QyDa'OH6e@_ghBqE\S_dY޹Rks[|ǡH^=@A9>QZ'uIZ7s+.qt2Pq2"v6Cx3ht flfIl^-ݾ|\7Z9- flaE_*ꗎD %[{[Zv2 gCfOZyc=4TŘv0;g?ا~5]nǨ]ㇵHX}82Jv䷓bnlW$tҚ '(l 1dB識+IŚPX+m4}y8H{Pܷ ]r:Zٛcm\35Si=f+@ל=ǾZ _h4I|%<"btLIK$`5x\""%^`:m\|'gJUXpC&#܄“tLW N\MLAΩ/vPnMI~/3LAyJ`u=±a k͏]O?@6#8ET][2i8[|c)J76Fh lw`gE GWaH뉵Z,&vh~S 'ؤAm9ֿH %b*~Vy;8v٥{1pHn9 {(=Y ~NB`y6zj;yS ƓtcN}W(ogME@0|**J+d8kw!"2'Uc=u2f7o-^sdŞgxsWn=}'7hCMyn }U41]-۴es=Xה1&}do(NQbz=א#3 6a(Vlk\Q-ܳ67V/{vz"p n1cP_a |?Teeja8KYf=Ux<5#nVJ/%[G!X3OFd$ q $ kq>Zz5Dwf*lƲ @pUQ_?lfwhdr@~A4<̥\1p]NG: \t8*F;-'bP m#_rat }ꇳx BI&'ר4ڡ-2 (O"!T}m@w<`G_8xxHnp4kO 8oSlİ D@|j@F)W$n.KOT1JBXeˬ_a/g]Ɯ5MHè$&ʈb\Bpz[-KP+41۟Lc$v7V~2W`?E?_shn?][I& )7DZM<'=ޑǶcHAL%f䭼IEZze-0؃n`et!* &+=[;6 wiGk `" S˥wf!μ&f@G(16e#q,^SLceKOuv+v>ٴUTlr@E9_d񟲖i= a,ξh{q3fR=~z^1kxahܠǠrV?Э| U@J=Ts/%esҊ2t,="^O!8%V\`VKW3mos{QGLu8`fouN<#o)? ?d؜_O=D&0e{^Kyr |*: :'\1%K,1j2!Qg5lF Y]˴Ҷps{t*cI|KFPE`| ŬXhRW  TͮDEg4w:dcCO EbE4xӪ@FRцt.cc :kLͷ/^bePayE[ &`Lȶr1 :%11ePѼůC6d[ZZNd‚AY]".vL;Z;U64 8% [ ՝w$BQsrEnYJS?YkeJXN|*<7Y7%`BOuʤ;pr{&D@i'ʼʹ 2;*LO#Y=}|,]ƧZ{BWC˫ɥ(4؃ZWx pxM'D<eOv릧 ZK])Uf T1ZGlPU'&FFW()>R Z,Lzsq<|#d*SW*6ZeJmX2QdOBJ~l2eM14g 3'a&1/c3xMϨ̄gtvT!l{ځ ړ+Yt0EY=SDZf. -MJi]X գ>T3졥FOÙ Җ :q^0w r8nLc* )\J˃kDKT|x3P{FAIa::"W"'M#'Qhшjc۱0 ;]D3.\ yڣe ] a98DxOHe8a=Ŗ[aQRL }%ȴCYCx}6w;h2$ MmziLq>o,4TV FvjU幧ݾ4K>YsHn82^ٕHo k$wQ;_Xoýѳn \%bDع I1 afPt{?DġK&aV_u%B['FE~]N@~Fhfgn-qZ=Rlt\{t,)&h6B=+A^՟mlMr}%m(oGEai8k6]/a*umݑY+ D7KDp}8ݥ!'x!9C `QW רe[q)+\m_R:It9^xV̓2|3tQe Hm6}6ķ8Z`ɟO^Vߊ]q.fYVvAZֺx >ȧp\ F⽨mi; 39"QulsV^ /L@zfp'J6̱P;neRn~ٯW@}@ASζ\  :/V]uKsRqH&//S7!pMZ.#}iUmD2nmW@FK2k^Ab,@@{cb"+MsFl<^w:3@!hE<)L "cvcs@ưRYk$52^Ko;~K}3!6j3bĝ Npb' z&3zn_!mGO??&സ +5)GF e5@C/@yʯ,(t?PY4B~~Z άpH1Rw þ5fċwE 6sJQ6Iz"mS dvM:i|n]Ő5_FR@N8spOnx%2wJ8v;932>Jr tǐͽ'F:BK~Eܮ(YY2jFD&6n$ĊBpΐ5ϱcr:{V3 !=\8τDQmEB Mmh'winԭmk.28?!!R{ g1zrT&u>r%'GuWqlY ^ |2K5z2@"Ucz&л^# G+FY|_βQH,a_!U4qk0,AB*sE 1<sֽ(4uYT $Cz9.I,TvpX E/)}fwfQC R|L&o1D"4_4Y~cAR9SbWOuxcE>11݆a:\( z,7@y;E*SyI̺EMa!WF)a@KUCxbw47߹@2AʲeR>U?/ ,^&@SV-RElMǾ;%2|E-U!^8@ص?H+ ~!N19; cXOP6w["{#q39ꪣ< KOiZ+ 9`Me5S{6R2|ɣ+H?2z*k_ۮl5ώIC8F-s|AC[B#9@S7˼ډlhujM~vhnȤ],CE-S~l8}/F\/$#oXbpCm\՛aAjZ] 7b2,-k{5UKYDBn8+O &'9IшKh Bs '^e<BF0Ζۅ~U-| LS'HGdL Rco8 :m,z,` 90n+2:L5?zW1iHsiz? F|,Ѭ,}Bb~ .H(x ]heA' R8βxڻP9#Lq!YkҿKgnyv;KO:Cd @a33y e4X~*TfcvG~G'nvic3dcسڡy%לC("F^]̿"1FCFZ!_ե_]s+7 v_/K9_Ui8-6ZT,sO䴛P=鼬:qrC*$gŊM Cf2?.ήr2[QNrp]\Sws\r0co٪FGu.+?.D+jU[ՇEM\l -zm˜ B0>t3~]̜%:BB&a>o"i s >k/^ߴ=z"w*M|JO=#hjΓ92HBt= \?RejMdS[ o%^' kAr2n!y"2OJ`2_^~cXmA~'y"`֖88yG T$^'Yq9QsSNbRR ^~s2B^y^=V&~A??Y.&*'ۥ"M:"( x7 YIw{~6`#VQA:0( yd#)f$ Ry@\xPvn?۷03IiƔz~6x> O&I,|LPdN.$ ă4g}2 f?>Ew &{vg &ge p%Ⱥ>dM`?`SXOQgrer8+oTw ƭHd5,f'_ -)D &7l4?n: Ӥ3J7qk3i4۷+B25e}.-#`;k%V{ x;5rAm2"'/6#/PP׳_:4<$2@scCb.޳&Ъ$@|i( L(4l^G-A1\(7QS(-^Q6$2rR%D\7&Xf#;d֎dT-<B ^3w6pZx?C`~1@??r.};?ԽZθGC91 [iZ~ZJx Qq18 UNxUgpf,T e9xay@+ xwh $I =F4]B՟㝪)n{/k1Qyw`gZJ}FX~YbWXxiQQGx%kx_VZC #CNR~@b8ef.ù*~Gr:G3{E;;2_HSE{a wD4120CiG;NnJ)>q0kw$$^gX=x59c?!؉MO?K-H/[)u[SBڨO.K//Fj^0 '~ O'0N6gO/܎i-뻿 x<L R$?F_? ^E ج5zvp0SܭbYˎ`̗wGE6獘bU3-K/Y "ٓ#ZOh-@n.P)]Zݠ*!״vjgH]#VO}wiJS|tT*{ViI,,)=^EgE5y'#0u|/,cN97Of^O) ҪAYCK9M L+njj¦]ZtȜujtau$Fm8u&{Z|k慮?a^6 SY};D|qӝ՟ h"m)?6&mc9{ ;wSDY2a;uJs157I^ȋae3xrvJ+C^W?kؑˤCIfrgEby_KbY({~7] c9xI铱yFzD(huhGJw^ $mf peF6QhpV`/J?ˎEHC@@?/w*qȍӄ])EC&Hz ▣ Qۯ; oL:$6el捸8,$ Fƒ?Z.U!~IB?6UH1s#-=QhЖG!L#:wOHrSC|%7 !2S4*us6ΙoKU.P* MV6UoHfP\^gh+!g&l2PɼGZ;\Wi2ޫ ndQ$Ls'\7q 0³ L *G B9H4a2?kv &h^2m;-W2cV(m 9ӟM׊K6C+9n(T['OulbX^㲮<8}gnF?ZKʇJ] yh$#U,|N8dIѮ8Zge#d)1ZP]ӄ"[yM'` ԾVsJ=k^Afր{nTYhMPI| ] GAV8" Rn'PVin V rcsY}Ό32,ՓL/Zn3F(iD]օg[Q%u1"9[\#3ӀE[bXg<1/+9m ̑4pPphqBhkSZCSΖB+h/OV^ .ͥ,Y'KnEFsi%[r~ ~97"qW\(lfZ&4t*^Ro0o!<9S}}qxlK!K"pVMz._hv ytQM H{>^5dZe?QxNe5zG]&qc;@y:c-Bzp|&O;Hyix~`Hc/gE,&OhGф:; q}p"}-, |:Ӵ?s?'_+{)D_I!ǡcJt ޷mvc7Gjp>uVcIR-%]X٪RfL\ %EƢ-3n<&+QpxC %ZW '*: *@jgٳJO k弧*9 fA*E 0&e+W7D@~mL? (fi+mpwPmPr+4aluKWqL;m,ɰ-p3(PqH淠ac!#E(1kSց!r ur-!/p{(d~Q P {f1˟ մgf}Y*J25^ZV3:x.3겠P=ih+NٝP).U+Wh'&L<&B-I70I dSy#g6 ({|f(ǻm& 9ҶD̘Q?cw/}G \USlRgSg9zGq5ˈ=} (;nR7;]| :s#'ʋjNG. OnljDv"\M΢/&3EQÊ~D s:BV(@,`P:gJFlR=zC1bq?mkI vLE \|% 0QxeDd - Y,Oni~yaY)ƭz۲+7W7` onIׯU %AG+=.k0Hފv482nqyIcH\9{ް-ڎD{!@G;ug6)3*wyP}v{}I1Y<+F8O=kn'JG@0[`\ ?LU]+W.cHzο%4SpVH#,Z t/O妱S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP@ɘ_:,8p# ?5> ma5:pZEQbX58M5r$5F]zB S'T="]Z%e>jZLL<|:ð@> "L%lAb87InΆeh@ cC.tCr-B$;$ݰeY8v8gcacoS+N]_`PΫ'?%dYY#V<ЖUD:Eݵ!K-F3 fFV'Ɏ@d:)%Ofj>t`eKkBu!fKk&IYuC7 _e~ǭmf>BiF3&Nѣaѯ*/ KQ}#{M.mOzcT >AM{0KM0@|_ߓx CvBt^lŸgnS `sU8 qIMM;6ں} (Ac3!ZulAč=.`Y<)m)pvUq0wV3{%qU6t*L̀(Jb*Һ&&3ϑa ckԢK@j{TZw,J6*:k|&b'T!.K!sS΁rÙ\{i$!S$iHlJJ40%Vm886=b_w8qhCձUe5npy`pVL<~ڬJrl#Q.Qgf&Dtfn>-X~i4ݪYc XjO&;|F"^ ;|xͶF]6AesH+Ne'Nj38|"X,?(< yw, ":@Y'ˮ@W/c:VmHճ?;z[<tM l-ՠ3VSCˬlgaN4<ˆGUFgd$2,XcK;'K1LRXj G VOغ%fq01ĵ+DqR@W|g8`O倦}"@ǒ<3S1ܩTO"h\Y`"oaRg4@Isfov*VN_{_pT^v8_9' K9cC! MD?|ke{!.^WwdEyAHWxTqǶ5`" AaM#ԗloR~KRAD+8(5 X)G#?' N v,'4ocreHG{ @2T(w"m CGL^􏖑ŢB13S͎etB<ҿK_xBċ\cwXR7y2rZ|Fؠ%G9. C )PpSu|~Ō"OǬ*܂G#~qѾG>FZAn bY} E> {2la_^/ߔD$Ÿ}+KOw>^F-Дktb?ecbו F&;ߎ dNqM>Ab>P#')BhOv!eQqNb7^A}x'3#x>!ͫ˄ .MOS]zČl2s)pp0:wz!kBE] Ex9#ީS$eNGF LfNLL}=z.MuWWei}φ`\Gwskc:D6% qW< 4T+Z<՞po.9}{m+&5Γ3},yq'Vm=!9=v-Y`ʣB\njbaW׏6ZR7-_!t3h%RӍDWH`Wݑ cQ:wI gAQ #iO *S`(%Nzcj"+ig?%nT;[2R )ʢSK\uv-C0^^GoxdIj^U RvQD3z«s9VLшe O_,fvEUi)ʇ${ѹgarqLs_,s*+WWu?ĪE|̸B0#w*_%#E .>Cz&!hES=m2ux_QHHd+&L!խ +sLjHbxqi冞 DD"yS1]v9D30œ!pwMbqKh]tL&w9 9SzBSTP;ߓ;2 gpMp*Ys=+@o͇~BăDWr&CS*Y^gJd=Nxk'1I*؛>˹|< ]9b̻k[yQ^R59$ȫ2t{bTaϛ~R@Α}CmPV.$3RHpejxCq 2JcCeJyrV:9<7~6SwiIb3? F8FE1)2#399fez\.y.}"mv}lf6RϱS>t۱.+uL]=A\~[(wx6p2.qߋT펳4wXuq7gDm ⵾8)zZCՇ'T7PI)'nk| ^#K>D WEXT+=Np0a$O2Lpadz (uFm>?~_: {wYPFɅ!Bc ªpHof%:@ӡ+jZjX}Z=HuB8o[rםEYbF C>"lPxWñrٲH -^)IV¦ĵcݗ<.VSILK(>C&pc)C,ǟzo\,r(BImyןfHRT>ď8&]&9Z\Mx+.LkbdghGE2 ۋIm榓%S̒]ڧ$0H ='2hlQR!@1}18mpJj]].'Jg$W:)H8bN|#*yXM]b=f!}؝)̬lwLyJ*gŚqN!$ 2תKMf~5uhm8#)/,@T? )#D N8'o "lgb>B#<]N+ЅsNWLYz#!$G2 !Brڣ/Y]4pK ʒ_3vQ $s1;lƮ \UyS}Na"CtlVZ {;͜1qDpQJ\Xݘd1Z=*?ب޽g's8{U SG?/~[ bHyOcE>4>e;㸮 (`~V !2g^qi)LzPAT>yVm fx? IIYf ;c1!6t9fpIUT 7H)*c8Ͳ_8f|$@|>@#2'|0>4p {}zX.b5eld5C݂.Ae 쾔pM P;lN$7g9ZzӊaWz]?4A1`|F@|z)4ZlC3̎I2t+8;uݟT Rb>I,ʕ7 Y(-ܦ Vy)E E߸SF;3?(Vr团4Z^BhXTy522gۣ9XM\/ gӴliݼ|r w_QcbnUB2>eZ1[ebqPۣCMbGG')fVT0GqM@kIw;QFriƒ~^kcsԱ~mbe <=l!~ֈcr&dø:1@f=LN%DIĜY]@\pCLMgWUq|>`_?/[T6X'T<IC?KWӺ7ʰZI@FSVz6|xg3ץνlĢA7&LNz NkG.aR|n$W+m7g 8p)I7FaM:䏃F^ٛFT٬6iChVY/LY'[׎w'QkYugE5Q0YSX ՜]>E}/N׋W*UYg 9^2~uD7^ƛÒ0t}=^}V0i8& ì,?]":.@ƈ:'8MM#Vg_h41,@>j缙a(+%so?vf'7X%\dwkibq310@Lm2"oVxA6)AMੜRbhWbK5NYU}mD8OHD_{HdV¢2tU1+ F4D_ϊ)GRjS֣reLhݕ08IObxʖӤ폕C-g$us\X]h%. 17)]D@^S%PA)CfL'[[k}JaSṮ=Cӑb<<iydPWCXnͨqK댫XM?,;~?||;/;~?tZRefXi_uAK-j)!4O3$( s |irR2Q;N~n 3t^$י8#g~.Tay(SK^q>Dz*d+whT@5[-`> aa7STw@nN-=x&JGfVIsU& ̡TSy}%*aDTo//_RtitZE_Oc#PT'SHZ!; 8L KIg[ 0}+ :8BakXkL˙Z#-q,e&bS:ٸĝ$Ie~nD$¦;E^~r%R 5jy耜~?]"'[@Qe<5HQG%.q9EȆJeMČ{zFB@ SrVtU_(YR@1*A:w㑂5mCIbOojNZ!'1I,|RmCPfpO>fYlsAX1,Eۋ;O#]a*'S*W~)Ъ/⍎l`j[ d!B4 K6#)MbSYD^ lc倐qܩ~B uN{_gۻOf_+XCp1P>={zWOt~UEmG6' MLp/%̣@~kO AR,R8rfcRC [e.҉brruW/S'7aʍۑ#aa"H(bgcך Q@M*"{8hL\>}ɋe/\>~BIk焉w$q/>\c/[8x=eFA* 6j{O.^ԩkOp^׮:W8^AЇ|cH fN̷dHY)mrm5|`HQOom>Wx^OGN}_rQ7tev!6EFq ZתÓFJ9GyDWO.iʒ(c"X9+_gl9d ~BLߜFmL#$Pᗒ$I\L . j䵚r`i#B;ɗK5`3E O(z_bc]hD7">sWJmqV4E 74eւJ&]Q2to wiٕ-ljV/x\"T~; (ƮI5HԱxjPJV/%Z(A) LVB#?(tՒ}a)tMs bĠi9! 'o2mwR& Hb|Wn` NL>ƼEߢ+{J,0VgSv@* `D2 zE 4j3:m;h*2NX5ê.X>M}j_z;J;B}(ېb~i:[ؒJ+)eޑt)~. Ԅ?hH=O^V meZBRuDnyO8zbRN9]ĿVѝ%$LoG~gdC[ IŹ4hr砈};x^3mZ" O 3өO6AvvIp>zA^@ؗZ!4R}|:*44p=r|lrݓЯ'>Dh9*RMWC_PLK6ǖS1*٫UF x?>DA9 byY 7U?M&!912]{gvsɞ{EUXI𶩂OH .{=K.{Ng@c8OGe+w4k)AZnΗkӌD|ӣϺ/-Dq`8o *nJަJ4 ZDCGbr <9ID}k:i/nsXFn2r]01cW!/HǗfݲdmt+FםFӞ(䯃7-M[9`@ Měgܶf9#OqĞ*onB.0:݄9?<5M lMvU:B\'5iD[ҨF5xƴd` ,ßg1&^Z*eAH:'+H i/2tz7|x}'{jf4B|lra\] djDg1íhsef7ip~q:T+a4:mwE FDZhCE _MQLMXqIk]ƼP:L{Q_UokG=ۧT'c ʙBLpqfv4$;twn+3G&WD{R㤤35 aJQef8C_7%")i Ŕp'OajgT~}KN򷜪S$:V">m;%#KE 8J{zoXEc*& lXkk(;c)B6۾zi#U{Ďq&4_ض7ua2 >Ը> JO ƴ"qNy+>>{J(U=?ntPAsxKBGQؙa\S!:JPk*y&rܟ; j/liD41]PQ**ƉX}c۷AܥqZI:WrTz?n8 c$T؎(V <O8Yմ31(Ҫ;yAvfNws+ LfvQzPOZĔt\.[.w+CWb)澪eT5}^T9s !|&nHTWFGgBt58h pяyDCChXZ;_|i'f/yYwOrխԐ5?t$WyJUC dR@ģ35}>#Nkqun/V@Q90M{--zz|DB@|w ݸSe1Y@3G-8Vҷ`Jm XiV-xmb-X"BګBHDΞ^{ Jp8a 毽0!8[i̻$wboQzxUnn ?lȌ٦f xgelOY,wrd-atirhKH&vC,Jث2 d: _G}[ɰAzW oEw[Z>WSStu2u "`(J^`q@04&lkQ/uћݭݨJJ$caL:o|>`~2;~d L/UI5PU@qA+C'VqXٹы-0)V"2zWUCɣ+V]8yi"lǢˌNZUD?069c4K%e1`L"k{CfF@)Kd7 ;gI_#jhry~F~gtzBE-OQ “ίY6}&:8 NORL7Xlnr\6f삧7K(:~ՐA`Qg!z{Y-'־n"'Y':i@ձ97_`$Dn%vQxTv"sH(;ӍT: mDq:Q_s*?Z* eބ,Õ'i $Q;RJm$rNjuÏ&gӋ>8Z$E-nX@ 0u[Z )r>eL`@(xCc}ycpxZttҡDNQ[S= x0aNCPWmFI>Ol!l`Ai[Pa:[B;:pa7,F5ʄVB6k(Iz +oe,gC 5ȷH'ރ МWJsJY;< 1HsqХ]eb=!39->G8g \"H cAe?kA|܂p[}9)j> =P:b"cHLcMJ`p?T;_V|=tyǼ6&(ANp u*mt A9O*mM!*:O4z ]SgdTt.&N+ֳi$]2`5_BQWX8km T?vAJ2Q.)jm!.@TF #38=>Zdxgz_.?w?t ~A,O`2/V >,r,=pͯI>㸖H-l. V`)_X{##Oz Kl+]#dts !l<:cFbO *9ѩ{IGql !՞A0C+uGh}BJʹuK^?._{i$4w(Ibs7g&[p5s:gx(X\954;FUZS_mMXȚSK"EOhIP[QGEq^$9MB_CM=.`f&.^^Ղ je[X}۩H|{k;;N~Uر) _Gnˡ@)gUp56ks2ŁsPӑϴ"rvgEtj<NQژCmNiN2S*9/$WL ŅˮwjDø;saai<9;fU* ༆5@FɫEnz$0H?OEG uVAġg">q[ `^ R ׍e47\{8!: \ :&`7&gS|TO,&A7>vZiZj!%CahlքNR)=!m@ORt:2##NC'$j/ufXi뚎^>T@Z;MC" M&Y ^]Ձǁ#~[Y ʴ"DH/_v;*n%lyGl5Vd~EƔ,ʙG_QqՖU,cR$o-wcb91(ѪGVL45lDM]za5hshF+>p[mqKi)qi!EML>VX+~iIq*kmaJ J+!E3?>qCMcOY.x1AIT%vWרmܾ_A}Ūϒd,@ۢ3o|̸ARu"P P,#u/̎rc*&pS'РHވ#QBAf?kTf(kF.(X N|q3 %."_\>^~m6O_y |_Z[3lh3# C߈=0xU`;xz4;;*TթdID_<ΎYp+pg7P޷&Eܒt%zK {@P7ʹlODM!,GEp9aZ zm]['jL䛛@ۚWH+^_"sj)ۍ /wч^CHh8x_/{? ?Nۭ-1r h5&63_SiCJǃ*j"|GN 1fȏo-gAOJfǁq 7y>aF́\(6C~V \aV.[`5dGZ(4;%m0 g\Aij8,15;hG1}:7^8Q|bֶ鶓Y0?W}y:avx´p8=g߉ڕn$`(JӢrZ;u~Tw Jk۲˝2h.t/!-lGgT d^A7S~?Mȵ^%^Z0gocPA:{yBrP} cS[1gTvWk$XK@m5;dO҉ݦ+Jܬ=Pe;sPPL| aK&|=ghihaB?(K3җCI GO"㋶$ 1tPs+:0$V(sgv6:6i^lg 7{R5t[4EصdżMqQfpŲ~kR} Oh`;D Ū-jI*qZ(iU*%-1yo5J~LjH8p~~ܼe?4fm`]3DR#Χ^~" )T_Lw=j"0yZ:b1pܲ;:L0<41 MH~.Y~7-X♪i#-OLexS=<^*0,7Rh F21Nh͢e}N/4Bpqh1įE7I@xި"U39:[5D QDPrI?J0O/Y(D&pi6e= јS5zZ㖛C,}s):S_9X}"@8:sad$;0)a5)bq]gJmEwZ2h==9PLF[]A$-Sɯ`SpW` EF4l8kѱanC:7u64J& \nx lgOs JyϚ~5x0E1 &vF>6H9ʲE"̝]DP"-!TDA]uЛK!^~= [icIXkHQH7M:I/V۰m\Ne{N(rt]`iK;= |KZЀUj=IRf GO7|9SQ8E>Du70[ ߳Di&V.oT_f|'5w q8Jk.))x_^)0F_/+v/ݱ;۟:w9YPK8"4;΍ΞXf+;M&V*wPl Eipֽ@$WE};Usg2,M?O#um DS o)f{M[sңs܍*T ؞˅걄l7)pGg!||L7c@!Nྜ`"qPw/ej;b 6P툵p#oQo$M"\d(jkl0l~jsX&MOBdMٓV3<xN Q#rICP^{ҟ-mpw=^LSm0PkBf?,5C;n(Cs65{vg7?|*r2rr`N|+M9>_ ?R~Ot?/VD 6۳Cb0o'EQJ׾_Fƒ7 g'H`4z`2nw!񃨃AȽ?C '~o q9aP;r#\VУ,$؝\*'~ySvzJE/&1[,zC?NkvexoRriS:x}fCn L=,UQx c}RxV'xsX:KQvŏ`Br m$$01,GiQǘJ쇋͇WFi?hٚ Th猧X|v uܸHQчz7XM1ntu!#%ϲ4N!,<c?nV̑ڲ.EC}|k8˒m 7s|wrCӌ[vYӧWphr4)Net3w yAf$)H쫙4\#(,kbB\|NSĴQ 8M)G_UMɎ(hY.*S~bXe߻&瀺3cUF ?Zwbz 7bxn{7\ySys&L2- !.vPj,~\6]d}#3/U2!/Eo6!0HЖQ cϯKPBp@I/Dq`Y-oJLʩs(w8Vy} `B?8JhI{YSdWGSQŽۏWa],97F,#,'m~Oϋ#q*BH!7?'pH&?K{ھ "gT؀#C ~a-ݔ]@ C6Y=w݇ 3Đ}_QAP= ==%V: )7$M H>Tw=H}!r"7V7z9tXz6Z~d_Bb`|@:4s 0Vy#yHedsx2+O@qF!ƒe&6 <^3+}tjTڇ7Ϊs2hyQI}A.32E"qE)Be'kMlDsW/!e|$g.WO4dūqlD Z:lUFhQdUR,SIH]@hbz }x[L1 ud& X*Krވ fZ{~- mGE$j*$(7KAk邭*kq0Q= E܃ϻwpw%nȹf ݃0} /GPY˂Q/9e%jdYh@3P]m'O0h)fD+[x+/"46iDb^C)[a]kVkB^ŧќIA>N36k FFVVUO2+dv!<5CIoF0ehD.; /׌G+MY?~ > Jz%wwԀhG'oלJq ~8"Meڦ@~.Fct:.70_fu8%D YZ#HD}͘$BŮS)3pE 6ȭh&"@~I<^o"e9)QŁ[ u^9۽h W!—nV'S?$t'?xA+#?\Q@kw $%W#/M} _+WG!!hg^ֈ!.!޿G`'[&E1Ryx7[ 1YnLA8e];~@3̮"& ABJ`/%BA%uJ9:t%cez^)'<:D?4ewu脧F?4Ƴ!e Z; cٗ|yoQӇONlܣi H%yd'VYea6cU.CGj% )V4kev/g<mxBx&͠f uu|Cˡx)>zY]=B?e(վo^Gk*ԭU?Z@H W.%_GAaDj[3gm&jdHZj:C/V sDg(LC.=!M |y*?=ZfvQ=C+E*u}ֻ&^W N `pƘ% O:,D㳼w~:Du}߮mőR8= 9zEy'^7g {k,hz F@IhǏY >v~'-ȴar21 e^qk>vҸ44_eS>Sk^N P_AMwfYv%Viņ\6\_!@ _Ο8Ϩ!{\ԣO?aOv|.i^9UhȒXZ+x$sFصkL}(^aF}- Tx oQ1g1޽NHg@vbZˋ*2?H^~Ct ԳQlRz }EJ%߬,W*Kȸ1 11vcTpB z`Cx6kSY(f~JZ3.َ- 1<|#eԨՑJ8PD+!5 b.-bT Te46w@|j+1Q*V3} |S`hs҉0| hE-![\˛~yHLyz v^*u :4-A %@T6k^3>=T:u0gX o 'zCpER]2>_pXR; ,Œ22#p_lZӀ+y5 38Պ!PDmS2b7ڣu D.YBaNF#r _*?!iC%WJ"1^ Ye<>FgpLP\Z֤4'#'0/r>OIЋ{DZԷjiQ&tj; o >ݡ1NOW_xWXUyNmV؉[r'lWR(DmX,d˽YQ&O[Ei  lsWi[W!?L}ñm5+0݊WUCzj!f3Om6h(Q~vϋ)9 g1cs(݉oH0sDwp)1zAL"xMpaܖ_ZWoBPϐoM"02$G˰5. =TcΓ'j3mh\^ZKEasKu]$L enT sɔЩ7z wm6y3sV뷾[`iPer&~=6ORr ȸ c1`p{wɳI{=@%kF^@"H,+!Q$Z<lHW@DBƤ`|+ 4N5$`޳7괐r#2> 螴ǣdܥ k jW'|Cox؍&TB)z1OnU5S`7(*ZPtjfov)x\u%x0HfBΦztDɹa!wTze *nڝ/$&md;ۋX&je\;!q/J(,0|xJt"[)0bY8 IEe6X]"WKozvw;T "XA9$΀X ;via8¹%_\G'g&]ub fp')ap,b!3sj*c! ytluK!L{JԺ3,mEZI$w2z XWHt0 p -[Ejy-yr+\ڛM!́zv0gQi}T.wc R~@>mH沶0K9_bJKz! $Yhf;IaTzEAF5l鲃%73 TD0ﬗG >#l_PG?Lvj&t`+Yi"G;9e.{аj>6OYxZ?U)D_%p;fϧYqdգ-ZƻI,Btfv^dn?>+иeDy7$:|WE$D/s9*.="T}`͚Uۄҩ^Uc4rJ̳ E*n[et\򍇇 @qC#GW7r#2BI`"2ͪ_?4sd^2<¢*;/d]I>;4țĒbaץ 7iN5>9ms#{$힑"YЂ!~u{;'z0 LI%s`k5͘Ə(7I@,wAkMٟpȫ~T,5/Jf1j_V@]ficqtϦPv&xp9 pƱCŏ.լ7oƂ=HUY$NB&KռYeL&+p,U?ey/,1y~3"@sqܼp3]3Pk#(]F2 ՗O^BAn6rjah!PlLz u3E;ǁQ> &ua_3,~$;}Xjyy `[$85gsp qVO]#"6852 |@,(|Ͽ4?A/FWAAqVCk@ )@:7^pW2z7*CQMoU:\IlBijJްY;:\ې&|Q]2>9De(&Pe`Cw|f3wX~àt+zcg@j:^<\ɬ@=?R봈QOjSdy|ups<)K,87"f*4AyC|TFb*ƅ9#UuT +(.dʔ+aC ЙXIA.4<iK.pS:&Owk2; Qؗkb=JF;e:x5M>g($cfOFxcW͈:*oϪԄHưrRƀeha%xh@$}yOpg!!eF 1|@,n-s\X-A| "ICn¨mM]fTE[TrgթCٙQq ԍ LJ݆ē% և[ҔRtT+qVNN>z rZllc<@BK(BHsKoKB:mQ4vp(i\rˎaYuWvE̙@4\G4"shۈ-A=dq20%oV8Vϲk Ԃ @-Q5ys{C v|9yЏw5cQfdw#-@h%nJz LJ ; NtoNDfwuAN VY[aNE`C+Q{wSS؍pǒ&#>&c[>{\|8]䥍IȮ<jgr:l9 */17 =Ch|#~/R)U Eo]'aeF&e|'3:6DǪ{nJ<~zJ! +͌L4k4lF}JIZ<;6 eoʲKjKCPP ݼI@Τ N.靆Je3mw0yh}PB 4%Ij>|@|#>@!ʮp9"ReuR4>@|i9Rod;@\k3}Y\DNoh}{q?o}2A~K kk[&rͅwQ|G|z(4*]Ȿ0Bl"d+n&%= +!3gZ<{Rjp9*RRSS$v 0!tZvG(IoUޡ/*>'s_1KIh"%C\j$ 5PV >$Be096]:Ƿt P*.AO\@qP!+T炤2K{M"=oMDwxј&>'r5F5b+}.%Rn:K7q s'Y^1(jaxCGcڑ#q,V,\p=jl0e|PCrB3:5Kn1j{%c_]MB>? pW_H ߆'_g9D-B>󸸯{?ID";$;2֡_i0,!;.P)°QJGwd6P&C;vOH4)Tz~D7L$,k4 `ۇ>Or~7(IIj\W~d^7;ptr$&}QL:,v:ih?JMhwʥv|XQ?fqD>'cɎj8._ۨD x3kiJ>4zIb/T!DwM__"&RkXJ19 =T\@  fLmJCiiorUK_1Y喂Z=1}arL亂|8̂lYE##mXX O·o'gԮKv=Ѝפ̾JfR"_XlƲPOd*(=EnM7gI%!f\p45󀤾UxG Г}>6[%h˰7#n&Ԫ2G\R$iq bU L#53ºS*K` ( 1Aj\U⩡<&Ȫ1)-e+&;Gsaڎ(!+ 6 ΰ /<ii CRFvi̐fbrhuꜳWH)ptiFo +:c`|xm*<]ù@(z.-y ,7HN0*.?$wSV=E<OûZu<0+Fh T)&QB}mfpxgq󜀫f zA QgRw1"y ^n59\*ڌ-U}|oD\䳑^pR\R]yUD_wΖ[ Tu-^z;9]Udb٪YrE$m R8۩dɈɉ󭭨4\]6>O{)m꿿9dt2:^+po\#+ o-9dl-.}2y;5/yavgYCJQVU+3<2 4C.q=J^=Zo[aK.YA% 6* )U4Z0`;)]N`}SƓ)ଟDQ"r~\ԏJL4i>kr-; C,㣥 u Gaz* 5.\^k[,z?ba\pd` n`ޟ9 YK†U GmwNd }| ՀJ`["%4ղH^T浰V">P@gWQH=#*![^:([/L^0{駪l@r_?$?}hVR|ӹCbʠQsӓ52lF#d&{F!rn%,l ɺsad.gC| MrD]] [a?ԫDm+lgoiFQP9@a=&ڄAT @WodrtJ8 K4F#4'mcJ̕ ]8u{(͋KE a^Gj՛ l [csL\O)\7uueK_ܫz:/4|]tS\Z  vuD | @|YIr~rlĴaV" b:PGStq2A|ygO= 7s.d t>\- IʢԬahZ HAָƳuZ@TU}zؔ%o}5UZn˩w*hc1{&vR'$BTxc]sp[[4]v jd[.n|1G ǥiTA*;{m)oeiCuVA$<G$Xk?V6>DK+bx5-=e ? v'I&\pcUBn;Ѭj7PE!QU-^㼍/Nʲ[9imԊlL<G g6 _`ޗNU3&/7 P:yjJwgpqF([ 4䤷H40{DvhF%NZNLK-e\t{V1_"F*=~á7Ay~W U4m  ^隵H9L(k6sB?b};nx48E?HfuOaV7)Z=o:QBH#=LLђمO"-d%@fŋٛħ.JS!%5૨;બ 5UY?@_uB!(kgyꏮۆR Bw[3Km{'`8aN_X>`v']r#I }UU {&-Ċ"6G/v$ky͆y(eP/$֙#2!' 1PZ@T@gub~q L.dQT/4F IhEWӷ³A$]aG%DeU/iwNcO^ U`E*A36I 8 Mf`ͼ%ό0` Z| M5HvSg*o =#R3aOdJ&v$v~oŧַȫmH| q{TcpNZDZP'rۭ63#-*]Ks6d~36szGhG椕.52?0y mArQr"0$9HR9hՑH%<ˣ䇅m[ޕM)hy܄fJ猈ӎ s |eKZb8}VQIvUH"V}f4zǕIG-9ŬtlHa} Ll9&23y5X+kF>E=o W}TzƔ-G6DWkmRd-mD=\zgedpK.96c›"Z苙A,Z'%m\J\EKK3)9+ Wqdq"\0vBp)N'=F[}8TL٫tK(_CC=+- -"mUSs'#`)[H<Ұo-jv=K[Y"t2'8<Jh Bjc|gXh0ZI%"5!-WuHpY( G21pL`BjkF_=wmj hh[}G X"?./e2Yy&v"@W\(͜IeJپaSƒգ>oiR;)=W-nV?5CYtFOevT) ܆joXcGq9Z+.h|hkn(*9k2k\B0O9ZH Z̴'C}իF=E1a7g 8FXtD>A[hETSBtʱ)IKҍg#1jB{mBT- 5LZ'xpHRd}9%oyvc`@3izV<;2)x 4j]R6SvXs޸Bk "S>//kz)msNnǦ t4'8 I>0ǀ'e@PmlAP׾x?]@mժUBe`Q"\~Aq`V/q~wHө7+׬j+ݙ* w]R\uwg`~ckdQgn56Ɩ\#+ǎEDpF!w r|רꃤE*6BV|,1yow;pI$ ,5_@ '¼hYK=;@;ۣ*/Gn0HeGe5!RIZzd'%Va2[:S)/^1*^PT_Z٧W `~J)=“TJ>=8Qj\{1?SHкkg5H!v/MwXFΦ%'0܁N#a $ 7AQxe٠FeRKk|< eAwg7*|?nV+)tJF6t/+d/n1NC K%7Pi}zTF3zq“b@lT90|- 1OEH eQ2s6'g%JJFIojV:Gݍ=5Lڌv~u&GbΜb\x_hYBs߶:>@{W(eMBR F_4)c3+K[e1( #fFk&E4b2l!S؍x%Kq^;z_6&Zazkvz6t9sx_UI0:GK?Z>rz׋@Z7|o{>Br<2:l)\]RYkЫŋjțnЏ"j*'D+a &ʶ=y(?%N|,__Oԟـ\'[W@f?0y g`\: $]JlUcHIձ\ğ1͗JH@K7ד\u?=JuPLnz4 ܢmS-_7Q$t})8Y3s=W"wJw [Ar>px4c(Nِ\r rn,ydGh(;6kL?cga Pfw* 'a*To?{촰}ڥXP.FL:Kj~Y#Z K"6D5lN1lg%8PKg IR܀9-&[xX>d';ϫLm2ظ]9πP0*v<<^MMoB*RP.~!s[uU!;Z<uWT۳hpMeVj9\H\42:>{TpGBOʢ/bx04HQUxԿUcU1Z WɁmqsmU+- [#fKϓ׉jkÂ'D?u:}j@0HcM!BGrfu#쓫^O$Jf2O*~e?23ޢh&p(>MnW5,k7x068H 3n % <+2K&ƏrB2 m<=وC AP\eJc`ؐm9%Z~/ɹ25;fh'l>q7d-/3 _I1hPĶ曤u1KN2mPҐI9Z O^ Λ.DtV1Ϩ?xɇ%󻅘U\{Æv]-moOɔF.{q2≛e%NnEu./ ߺ4{`]_Cf_k>Z'H)  '2j2ęzj~: 1D"H7Ȳ~\)/B,Fw}Y v2Y$V6?@a"(I @#IU^!ܻؒbF6>N]f BhfN>&zd 7΋Q$GCJ:xC[ *K紜骙08h±ϚYut  Cj ̤Oo%-l$A*co@0կOcxju/(n,D+G 5A78MjrW!d%pEQؔ%s/WvE>w{1fYMF|WO*Gm~$p>qut1!0Ҁ딍؆|JnePyL}#!|̹Q^C\ɭ^' FG*4`Lb"0~_o6**6["3uL`s \Xbw* oŕfkY;V\Ege357&[9_fjT}uPQّz&v& MC NfYZb ?h`F iƣ#gtrYS`Xs{'2@K %pdoS 8Í\6 .ԉ#y8 DLf٢UFnEد!leB|6r2̃yMQ%/ݲxr;"fuAlZO[fxEWѧ(1Q=,oF71 kqB)kg5aYss1VrPV~kZ9$+ˣZ:fuIup2&Uzg zO=.NŽjZI}i RP;0hyY|d @?3nP~|y3si8Z) &?t~ [/Q_-=;$/*6\1*к=b3~7ZReTrAT'aT9oxD`Iȝňwnn3^eD=..83KMooIEEfӬ#3=~~6p!?.83]h@UC? yF4Kekaa?XN!O2QaH[:wWq8׽+[p8rlq v~ k`PW::yө(Pu~V>cp0@\ͫ\*ObFXPG] 2UB'p_շ٩".g9Zc˯XYڑ?9R0bXڮl`h6~Ive6a{>.Spe,I[?_uj&Y/mA-|{|k%I6FLmYa,Kefau1| M(sl!)A_wxϊT| Y+uFc}w|wD-wrQ}\&V1?ԆyytλPO3s"򗊛vȚq PJek`bx5a6 Ex?D\]c  + o-gm ]Z8‹q/U:A{<ޚ݅JP3`hQMs0Qo$Dкˢ!56'{4+R9!/E끽,VyqEʎ!\!GU7k'Tf6%h|FC- Z&3@k _aO+50p%Za\ت94'N s(ʒ:gH_T'0CpuB)^\Ze ~.YWm~WLEZ(Ew|d,%'4tt$LZ3+W0UYk bg}8ZEs-5buɳEd,5H7&C`?iZ(<[&ef']qPЉ夅ڋUT"29GXnI} Y# ?ߛǬ #!I5GZH8p{Ur@Fed0%<ϖV)f3pe1m&]3rGAK#:/ nK! ߜhs*k?v: TX,rh PJC!G֑~ϤשJn.7A˳NIl!?ҢFt{HX-R-M#4}Tb"a|EnPrD\v]`߯kS"9m Ve\d@gxN<Qv Vy*>3|d&pjR/V@`5~whP_%Q4V^WmFo#>NKcuWLkrY_p83 "~߾=`㱿 h< @f$}2G.l-e<ͻlnm ?W{|~Ĵm?3}wX.UN(A*Q'! 4YCp~ r7;!hԳ0sTC׌Z&wUGm Ho赹2Z A{<6&Y#2HƦems_3G5Y*aO`Tpsp`d=7ܨ34xa"x@|@|@> @: H3>e 4y? ƥWXΣ#8jCyK.thˑ㰤bh" 7kF.57@YlW|U1eBXG|C@|z`=$BB>_t(0+ vEǡI|uAZvZ|r ƕEIB~_H, 3K [ BF 4/aGP3Ϛ;Q]Hk?'e29)XyU\G8O-Z:BSWCJSgmzJ$;He(eC:wCPx K?;q֠Ӡۼ}0RAUڏOd)?s1q K@1%s_N*=0<~ߢ4{Ri / Ie+B̠`ä@i7f]NXXn13*rr-an(2Z5WyzEFQW:с~>`/ʟ$4~Ń:z=/*"U$VN7A8:~"EN/W:L)y\RTޫ lKmY4`YRt߼ fYwO"j%{aMt날8|`KlDtJwَAq@cPp[8uylE(xA 𖓶AelnMfF#a&=#.O}eL+y>ZGf)¯g*s}wvZGz?"=ξ//^(G̽ZFrd4XstvJY{?{x]Sl6'% @Z5_3 ,F WSƪ.`CZ182~(1>C .-`C0A^LYfTXtn-m hqj*j_a<8h.73,vZD6p /xU+zl-q[()f|;@g/f5]*o EdAU+FrEh(.@x2p)eq_5p?ꈵqHLaҬvUgӘmbd%q ƺ|_*l {C#Fsg $PoV!#|ajg^~›N 0 >5tEW!{oC) NQ #x-z)tu̽CΚ<~_jl(luhEa]:lӒ0#ɵ@ QyQЅ dd|^c0$0mMhpRV:6'KT$21C/U fH1Lz+q(6!H?,P|grlAC3Ř>VadzQ$&jVK5b-s#7w6%^M7yQg;V Q6Va/Z^ d(($jo IiahnI^Q .yJ<) g(sg^),x1*WwULƓn:M)&J6g-G:c|n+Ύhsi&NB)ǒS&o`?ep8B[gN2讍p/9{")>utNvѣ6V7# Dnf(|! :O|bvkF},~1S@+顾/l{ %Y^SJ;ŏ8V 65vr#]}uyC[ȨYҨb̹cIY_,zT|R7JJ2WD}J*vY p8`9\[9_Cv ұ*6D|{~^-c"/: vd=qCXXrQ^;B3Ҽ?mW/&^ ʟĵ`D]D辖"hu_ְfJdb0C9E9 :4`]vؘ_q@G5n ($9(X>. :E[mE,!SQ`OUP2빅Vշɑȥk"s ~dr!)ӷ93g?Cukzכ7=əS7/1{M:8nEZ2P6lT^*\pO>Lc ~m| qW=dkpwqOO*cuP-Ȏ}Ho0p,=c 9P~nf~aĶA%d|[p}fZծ~9Lfo<_K4l$W U BP/]HE0y$ymv5pĒ6xQ㕟E+}U*s#s)fIOo"r=K<?175`)hK!e2~spe;,H-~Lafg(xY?hIah.`\[8 >0~N bCх\^tƛzD;߃?ЯPӷ!0x@`zU!^>Dxw{@FS6pov~ l9@^̩-D kV@׸ himഇau4hև,*)׮0tڵsf*pFd ļ|nJEW Ƽ ƗdS(І'+m) N *Yi/ZbMyޛx sLQKa<>N{=I097\j LP;$HfOOU<`@N1hCDN~ (踞V̲~}nV% _N#%Xig9P]th[j5iwˉ8x8s\gX4-ucI28Mg7U,ydM-uR׶e 07%U0y4Ԑ#fz ϫ`MFkf3ڮ=ZBJO;{ h2Q"\(2-b— ח [|NaeRrp0by'^uuv2R0K" wSw/25a\.aM=Lwf?8ϱBzZSI|b֞9];Krʰ)wg5%a~n*έzHů9yLN G)E\߯TwN+Nn f5},8dKfNaEj>FWõפC9aN}EY,bB4ͫatPXf|w؉ŃDdu u|qowi{1I8~(:$"Z9;O*헰GT1 tF`j mqU/V2ڣ0 oM<Ӛboh.;dwD2iԙSfDwIgm^ȑ=$)S D"Cʽm]&89YW'xqH[T=^Y7%8gXF':\iYn|}bT:!GHL3cA#.FXBez5jy6zO.1xLlbcnPS К?[V%LllW=*Ԭf-R%/KJ0H@*V^1 9׽ cl; @\.Cr\„I3'(hnL?$zw/: AVe8X@ ~? iFus wOx@|k#x*pCFxcͬi`w@{<57IAKV+\ܤi)Ly8DPE|Uq'D|aQu 7`YMϭM>= Xj R[}^>K4$ϯз IiSԟ]JȻ/-BXH Ɇ( PHC;C ăgr25_k 0ֿW#J -э nE_ Rۭ9 ]A%@Qzȡa;{{6ؔ{]tA+5q`KZeE$ ֳFd-oBS?O|ɤiBem(1GQ0#%dsp6l `ge!-t|J0ȋ$r ׾Yb=ۺb+%AVuYh%ޜ *V?( c섷&ɠ::G\_A:ԪL Z`|`~B_XGJqVN3;R*ku1y0z9 ^q,h?P|bҪ +Zq#M1AojFm(Y`Kﵸ9T0?wB·U*{S$TnD<&ʖ^a99._B9Z F.`ZˋT_F<&&" vHvd"E~AE Ya ZQƬx#?PE<;nxv|Lt'&c9DݤzYї sݴK7 E#AG*LXFE Zs?ILpho:cΡ o ]';/̐MG?F.Br\_]ԾVdNZDCi ًyzTX|_yA .61;'ÞE-oS,$°7HYFB [^L=K(:TyЃdru8@7{=ܷ'mqP/OVmaJ"Mزj0h| Ay;rA/9E00'8ꤾ\w'E( Jz":&ABfHkץx>a XXI)FjR(" Aqoud I"Z$ՐDuӹ:!@zYBÔ6 !Pk)=1BbtӃNK; 5ĄodJScpf xpv^"$.u?CI~ѧ-i DP2(Մ#fz3IQ=fi %Pۿ`+eg?GizJGόuԪM " XDX U=hޛ`=K`--8L+$o϶*[ÁyI▷Xvߪ-zNuBng$;wV($pGg~N:Xj& 3dӜ?"WqtIux4Wi.-NIc>Rqa{k1z烊*,*7*q;e;4AeKXk?Q˙Mo)K5IR]CRd55LK:`uۥo7Cb02R.]On#\wT{X12 -3u`d%IMPN:jyDYB QI+QwcO^ ';Дx:7nqbJi3@MJkXۊeWzO o=w\/ns{f{Jjh\xK{-df۳k%}ڿuQ뮙omXAmKt~>Hy`uOG= glxcg^-kQW~ rS+rݏeH[XeKX$sB-!lk@Ec%-@MU%/ ΡɽÝ5d1$*Ǫ/m23sD-ZGrIONq$ -`T˻1V wj+OGqͲJk MhG{`$Ju GqVH+_1"Ԅck(&a"_ڑ )z<.ȒPb1o[5:=ٍ l/de\+h oLw*RcgW9`B-N~#Ngl;yI [);ZLԑKO"֭&J5_c`Q; ;R\,@MGFD<*_ߢ|O˹0K\Ho^'#v]J/@ϰXzl6vm^Mޫi]zbgue]R&Kq56fj@UOBĔ_dtGX%ďʞkZeй>E׿dK଄ h^1d j(8}LtQ圂{-mhlDUaT5g7LlW^C.ke4+qMSH1@wHَJ ?F^mFW` M)-OijM bcwh )p TPĊįpiڢі6 +lxYPZk%9s[:FR0(rZeC+ɝAtR);h Id<ɶ9גf2<R[Nsik (\e#}A]& >!g0SG .+Įl&iP\)A#^̴KDTa!l@Iכu+O@1y[$_ 6Cockr>JK=dq6R S]~'V$FC)U"#X<[TI [} FǷ꺋1@DS&F7lƊ>!} 8;.XLu 53a#1!a&/*2=\4'i:m:p(w\c[:%L9m?S2]'[̀XcWǻ!xq|Ds@hg3YBf.]o 9X$PKK N]%YeĔK+"k1;P:} D7v7U>th+]#_ 'T!L&Ygܛ/uO,i ʑI2B a 4P& ʘgxY;3> [(4_VtR;BNsl[P @]S3&!" {pB,/Η :BS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP:W8_q?wDtl<3(W/U x% W"SʵBxUm]R6Q`F(ɝԶʭVt}Cݧ.7jxp㶀7|A&t0FDY(~ "Z::pNJo$'9sMYl6v!1l7WTc`?tZh60W` hdr lI82[|A-Ll?X}'%¼Ձ ubBhYyNE): | 2 d@N_"AicQ1kܾOxnA;fqZQ2Zm>,H[O7^4SVōFPΦ6cCr <֕. 8q%Nc.pAm_~ cTmh{X-T0 *?^@韼.R@+x˕ 4/ދ{E.!lO&桐YtRHV8D@?M*k=!m z4xP_:IQ: Y9ѷ1D*?Zj2m5טMdfEq1uE sZfA6 }M3oG*xvw'j**dX?yNP[PTŗ 6Nl0G LuϪPXTPQ6H4Ը_QR*ꉻB?\ }D\S{ z h0a]jXMzLJsNfC6btmg3ށpN~N?ד:?!G4P n/`m?xzebQArD˚H{.89ȿ=!կׂJPSY"`^V mڄ2 EBi vr95/>*sK jhxJ9C-[^Aޚ_>T1Mq<$CڂYy/BWo cANJҙJ1onaǦΣy_eW!iO}T`Bj@]3{Nc+Q1h^% p H+|a= bZ5BkZLcUޓ9yG-5x'B$l1̖:rXbX-ofc0BH X޷C4 =`0>90l 3?$"Mv}f{hM~rE*^2㝵Ǡ\>4Z+=Qs]d5 @x%f*PcX-PgB>EXG5n&9>nU06*sؿtPUwsJ11FB3o%ğsY% sLۉ;8:%o+G$d 8qݳt4 ĘwiVn+Ǎn@l?! T$! x#_m!eEz7c.W_^ʵ h5ΜПHn{}⭑c%/>P8xrPiVjn==SFX̟ZɥV<ƿ5C?@B]XzWOW-~[un5jqSA.Lmpi$۬ŧ}k$|&S x k '50̹޵ EsXWtDmhcF%xu7.8:*8yw-5e 4 nԍuǛQ^@爰?KǦBd"4%SnkAK$C p91wmے y:&+^6~DZ]+8rY ٗk cq(&q^sr͗^u`gsvgSV,? KGqYݘ¿u7%W 6jS{$Hz!]h5@J)g$ܸ Ր8[>J?HVKNiQU?sUsȈ`k61'> }Zz=D%4H#ʋF?_5?zh!Dz8Wgl0f7ڔ%T^Ut`Uv=_ň&\zY!IǼm<,cfG6NqX2]Az[wYr 6f+(0 # '&a}h4'n{}^5U'legIp ؘUn[\\*^GO5kڢ2fSv6 TYGq57˵I\rLbB+{ rԳK~`pQ̨mga:)Oy2`gNW)_G*74Oquhxr`` r>KIcίIÔ %FxARuzqz|3chN9r'^?p] 6 :` :裔J\#oo ?0Ts J3tn5HVR##E^uڔp(>a7 !hXhdrhY1w ?ߜ4OOoZd)Wա H:i ֙X۬Ĥp )<ֹ4j]O#z9fYT?]D[К8j <5gmttjEY!ҁLOx󡑤~5} =Q: NS;"#c=n^^@M WGeظue"ѠSSCOQckFtRIǙ*X䫎^a-GYitI,r 6Ӊh1:@2z\.kƿbrRDpmOZiI#U \[̷f%Y>U%]ŶM͘|[֏įݾ6ەt˲)9>z.Wi!链@;ZXɂ"ueBJ:>f*+;)tyi97g$ Wʼ6A=DIGWUnnC_"fm52b8:;ie\E\N Kq^]ߺ0]q*~rSF Ĉ?Ko+xfI83-p+1!׀=VQFÓiXjZkޒ*1Rj(r}O,턞5!s*jRQ6\S6EYGKdU WL|t2@Ls=q8<>rjg'r\^i2S}CQm(igOgjX:S #$)eoq)āg L*wNӘĊEWN."k7IT75?F=@HSo!Kw. J%M8ߝ}`'e.ñlJ6ʛ^llh[WվһMJ3uE@$}"V{l*jôxK3L_$տpe#j 1#[:*u4 ?Ԍ:)aXŞi:)\bC%7 N7i=5 H^+M0d^`o84BXa2N)OfGcGs/8BQ]LRAa dB{묺SRNKb (B$0I()w,7mY'fFz%tz2b\'Cgv>'Zv*'cGYbݝXqwlVswk= z#-1! b}ʘOql<\n.kmC1@xIXŕRLz\嬽&3eCz"{_z>˕~۹ĖVybݷȁ:D47_ Hhm7fXEGTpk9 rM &OGP]?绋৘Ck ?_?ρ;w ٞ2F"?8\)ElunSd ŋø+lkL5!36ٻ{)"Rh*h*ϫBin}GUisr7۩~dkPmkBa@WpFW Hm9Ǘ{si ]MYE# D#3YhoFQ,"7=JkoF;2)M^`-&DU2G51X>ź (ʢ)mt]}J;Xp0T8`,3VOw0s ,hRTtI]]r 0$ <#x\R60Q##? p_~>`C&~r@Fi2 VIeSx͝fX8 :'#uv$ {L*RvxU9 lAcTU^GAh&1|7\iF86~yp ;^nϒ̛aUvaV#Vq^7 w$!`~} -ן6-mֈ;IvŨy;TL~ @adb{Vdu9B t T{&]ݰ_W2s:g3[ f˚L%. gbҖk@?1CWKWb<@3т\ x I@?D' rܘ?_?" dqi_R8bM<7?]6X}l5 3%uJb<>yjϭYTFFiH/ w7;QϺ >W:s3zd)(Z0"B'tMvWB&{ɜ X]$WˆY1"A -!g(ܾgVТcQeUΫT d;ߔf,YbgY7W iwjp&H2&X%pnD~FqsXY{-EYjI#E9fIl]uahm _&lfoJ#S z?u~ Q9P u1o:\ca=b!K[t촂)@!k+dJq_H;5WZP)c˶`$Ґ4_5+D CUuu2㷭xi {ǃ%Z)S0uor}>3L^MtD^Ɩ*a V8f D ssW=c\iIauhw#ˬ/<ZI-_vR" ,b3X(ba,P`/7HMRfU{XSa:Oa9)>2H~ JT&Tw݆x(t3d˒ҡL\wE11LI8PN_<鶍ȑ fNОXD_:YRFܰg6IXrB.G}xs29r[0\S^͟·Eսnck.u?߇kt;^z}p ~GfEE~2kD]G%tG,G璢rg;I>UJ( sc,l7(r 'I[,6p)/"#'ҭĸ{Y3q?.R>}ʉ~%kg fOf^=yF3[\Csc!CpgD G S,=BST=I(4O2&t:T! Jޜ\3陵.[6MuZPe( {-@)Y#x=7=:сQ3_6YrGJdv"Pi&IO+>I(:2 +& G)wxS)M_j$Kmثms g|(LvJVPm-]M7'V`KsS66mYN1&I6ۘ!7<&z擹U} :aU?KTpTd֍_n9BHqvHЂDIdD7`jb>D'>7UoAq=ղO%;πuG=nL,%VڼpiڠqV>'Mf I49p=#~|RYS73z킼2>]4&SWm6~+ 6f*<=1>ކ-DёZs(^LoY"ƺGBAt"Ѧ3 M "/$]>iMᢻIב r"{f r];k4ۤچ;UQOjb CS2 k@= FJx &eWԃ9gr RpS&0 jAaC~}O^2z  ZNڱI@%jg_"y-檏d/Y/W683zLMMy`ѤwigÛ]#kO1O_,N歨av9#4q}BvìKI'غ1{sZ(l+p쒂<:Qf|+x3ILKW1[3X "O{",V$O2wIoq) p4=P5wge0ߙe7= M$0FYϪ7ĮEkA"gٻ#1i2*"4L#I7%'Jƙ=dw6pp|]wũ+Ht=V@iG~zӰY{'dCPOYd\4v)֧7 =֬xj||!j OQuMiN|//|1%Wqc1zMؓ_Q(Q% n jDJCv@^OwTIP15?@Ц60AةҪV$zG>gK-2F>hGv"8:d%,Y5ɀ((mOM)J`- #IsnvfٓZ4X3QIOv-ij;/NDڋJu% -ĉNOi7P2[<5ZF,>nP:͌2V1dRql\Mx{`6Ρ I͐>'fd]YbNoK|5b^-+ "*wG*MzD)'7s6㯐V^}7aYf 3i2:<,"Zm0^}MƪBב؂Wɾ,)e6\0ӔPs3 lF߽XAd)_(j7p̷});Z/BRK}UgXӶ-T\]oq>#qڹ?PH6[. _@ ks{yӪ]u9 dT)A~0 ?oƌA_{] E߅JZd)k)>ʵr +0P򕲷;uUz, \7 b "_P= c7/z(v6t{udQ^___ہ=d!>=M5yC}ηQ|\a)u#9<֟7fQԬ’؏795X )nh=Ÿ-n xAt8 4Tv7dBhGS] ZA&I5oVBZ?Fug(Em 2[UY!2XEW,3̿V&c93WX9#hr|bix#icNGuˑ#}S7q9+KibL˹1к%)="Ԝ^.)D~`V}ǀA;:4Z(w;#m8"YE<\6R&3Qe xnOqAf 76sIGIbD[c !QaLneͭɸya\-˳? |' I.hғ>FaOd0TmjZ(k4edG-<Wkyà BYD}3K3u^83/I:'dYcz$(ɉ=-״FqƇiC)M8ԡ2}QzYf9UJv*٢rYy^$ZO;[)leKkl&.cgԜz swM t$ى>}lQFME`9֏ g6I$}TZ|NLO!^<|TXE)KaI ئLwjv?^mz\-9@vsaUAL\xjx_K԰5h27؍\+Дq}Px̏Pwx,\$s7*7^rWdBlJF1# $_T}y5'g`Ѓ加n  jU ikևD0Ԁ ѵY MyKXЯ;H7{@sR1by =4"8Ȋ'`2Y](Ys ,dP[g&bUz d7Y.}JY67+庠;_|u tt>,8՛[N| Cl./"O}^qPnG9B/"p:Y;5* S|V}bM K:v)\0VI8^Qܿ=IH E&M5 mfeOvlW!V܌lx{k{&-B%)b"o9`4"a9Ѷ*jATB̯m,')٥+oQ&"L{% .?ӟ'p?x.u;~b#eÔFJM? hȨ-qC)$gˁ$gMQ7f<6(;rTd|{5TÀ1{̼}Q6~,7"y`!`Ϳ%ZSڝ1蜦 j7;J۪\hK"{,*ZH· !;b5orhcG6Z{%(P)=r+ylAYJA 3cҹ390':"lD})Cr,I5GZrz; o\W6IJMh|1ͥↃi S"ep iNM==eYBRԈwT//;jK#ڄet;.Lo%ST) WpUwﺻTGjñ*,cgfibҽ4V;,kp sF:/Wl7Q/%#+Y  C== _'nub%bst|rla-%)zGG➣QZ| ;UzV7Oi@-V3ђ(zJ7ΕᬁȓP۽aQ &k~ډ5o5T̿< teh&S&wonؐ$[~|׏ L$6JX z#Uz$=) wA b{cHEdWCp=8?( b2:Df.*MXudA$rY}IpEBk< nYPna~TھSJPnЫMKM2bIZ{IN8VIYs!w:(TLӏ:3 4R1 #q B}m-8aopcvQ❫ =Ӓ͕ڥ箁D2l5l5!Ś@DMĮ]*n+ԀOzj} 0>ytjh@rrx1PԧF3܆h {b9NbiovlsDK/wS%`l]J 5tF.,N~ʽ)2QGsW<- ݗ4a9X8ݛvTwԴ_ijW^  {kH2.g`h¢ˀ߁%Uv{4$4phh9 #'3>ԹfB>gƣҔkp``aVzB6Po_y1d45S/o`GUx I-gC}p暺K`ҀKrE{w;1C5zŃ^i2}`iw:*tLц8ɖ] .+v>lf~> `(̯7!q Wh^h7a#SG%,;HJt3h=Bh BHePQg i.q*zx`K/+j@8 Mk5~z̡hi-KWv)?;u6 lTt8d7 j}0s=M@p͸P☞pC6ڙuZ# e ]<ä:aEg #PYK}l{T)]5B6&buu`ӝߵN+H~r&bÞܒ^[YվAJ5Sj=p)6T V|@DHXF%n,|vmvCVkir^qQ-G 祻Ғ1BLn5ΒRыT/ &=}=*qD*Z<m#_W[gaW.д"CHLWD9ZPyEMG̑Y<e3Y#-N4|Y iy-RĦ\n~rĮh(3f`h*n4B =SNUvsb,i)0P;zSjIYO昴O'58fOsL&Q9 ͫ6OU~UaX砝rCVr5~&ЛAv1 ráoxWJ4Z^oCGD=|5OȹI(D Gg]kb[o oPšaTOډˤY G\j@U߲̩N=p5sQWW4e,@`t#H;bW3I8?zM1ɢvDZƋ* ~R;,`%AtV2m@JBgPe3齩? }35#c'8ht*^7ߔ+'7nlzOZe#IHdLM]5\h&_#q2tӆ͒4HEaiyH3]^ĕzV,|@f*eN>(!"*j;T x/JNDBg8(hI igW1?헸8ڛY`˗x:Qz˭[WZOr 8 zIT^|]~WL>dXf#5j_{9q}]X ,(AJ5'^ vJatnP(%vfxLQVh!y7dzEv{PDQ\H>8YiؔuFН7*hqD(iW0*|Myzz;Nh+;zY9łF'^bE@14y'aVWuH;srZI>CMWw|ϚegkGi}7ʒͲ-צūhZog._)?,$BwlOXzN50K~]wȲʄÉZN C6B*GpqKG󷈟S#)Y3yl>"HPA҉x;I;] 1=}?z9Jorj$x3i̭9v΄ Xc1$gl 8%3HET~o`W vyjX: ;BS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4fyIhv ?|8x8 !Zԉ`| :t,a-e/pl(aC{ 1W9{&hSbZK~N.p6U4:@80݉'w0Np0DIĻQ(s* }xv79ϗL(}v]/d)|)Dl"ө{W2LܣW^,]* :h3>*!TU> c+21 6`۪05I[ߤF" ?wcKj#ahz+a #9fi6T}LO/_o֮_W$@ܙ8\՝NO%Vܤ\K vi/-J6a~Yhb4r#\R~ڕvmU:5|'>/Q}e.f_(VϾIYTGa-_ioQ,+: PKuHQRԃaP'f\K'~X+2, ?Nŀ\yI$ۏںy#y^=Ry>ѡrIeUnD6C^7, -jܷF7 CfyNL d+J,2'` 5\"5D/6  ch.~kWTrį+B?PݸCٽƂM77dՒw͚@o[lïi܄mӚqM:bƻ?-Ry%I i2=RNv*ILf1J agO>Fm>'rAI='WF D'2s[}W'&Mw[ hԼȠ`V*}b~g~a,$ٙ4ܭ+g*_4m1vye}>\qC@'x+~X$BδZ#Zdmc1:~2'*YS[}~tZ6~ u+C.r!D6M4S#/X&j~x|fcl&%ZS]0M01"pD^tx,f#`~K 6mwφZgyUP,=q{5%+W>4륟2^2"_9^g eY"2%@\bN|+dON·ߓ\'c GyR0s*?P39Ǽh'Pҍ[C8K~VI=Y}t&i󻹉f$]9XDLio&p8ǻ~8հ ;J׫h\!cP|=LY :TaBcv,?ͿoqhD8sOT1:NY;kj~o8Vk,Tp{żȍ3kנ2.t 9K{:&q]H9"xjȽtHW!7fߎQO(>{qţ^0/┆H=$P2r}jvԫOӛ+5u ߨ(K eK~(Ip%J%Hh13o`jy?%~ 3eþs@G҂Y౤25nvU*%U!m1V#[VzNޙƍm#)yYN 0PM&>~2twGTHv.VdAc3Z06cbEkn]c*Jntߘ|f) %^U.Җ5_7 _ {4}q](шdͦYB@$+ŝX[dڂS׎ꑑ'0!>ǻxd$s=/b818Әc;;ܩF cW4'Dݰ 8=ݑ#_ŎyL J9\/0✩зoj!g,zY6"rZv2PgQ+7R\; > JsEl"}"rf7KsD_i}F&ni[чkjDހ?h2AC@?AŝܘLN$nyF-`Y *R+&nŅ%|vK3h:7eوYn¡fI7]‰)262jZ&BbҾ1}zK  J/N_}g.Gb<@=R9$Besk=;|g) Z×Rj]ЫP*K3}~j; PӯԎpXE\`*YMa-J]e{5cM(= ve]F:Bs7mF]k%"{nӓJlI1Ӏ iq3ROstKdp"mY|h0'x(L6CMm6362 3dMN"XT'LFĉow,3Dywҩbt#~#?{p6MODUt5Sq+z hr Xf ekA9V wJݺD .sm$yg'!/I/8kl&iRsW0Fo 契Z$}>l"I4fx&L&435P#Va-<ν5{HMKה Z~#f@>Zso[L( dW#>.X"5\eԐ#džшW9;lh=ڒWxzk!|)(rc&d>ܒȭ#+2xWqny FrR!z|)f:mvf7 PNBaMQ,̡Y~iwJO]+Ky+9>rZy {5W*fBJ%9nt3M2@L(Y;-j!9ĭx4W!}9ŎiVOgg5[vr^ax~CbGcMTI̢,ש rXV14𿶃wXE4Tk OKy8u0xN@6'_u?- HQon{6HSL:6 hƞlO$8ϳ݅)9R"|y{ +:LG-pn8 9wȠCna8oL`3:خ߾ d. 苮ޘ@?Jv*|@ LWVarYub4 T,4i ΋e0a.㲱:7<0+)P1^gnL5H/.z[2~]=bQͤW Ň>lA 6'A>ioC})uӔ_s-y7*k;0;&YJg&6۟z z}V(`1[zhu];}ece+YٝuRD0dOb3@r !JI*ζQ|LJo]%MD$nMF3)XdVSQF OMOJAr@ t$mS>?iP~s& Ϳs< f\)-. 'MdS1D7O{$+݈BL;/tɭ1)7HiB~`[2-gd)4VЁf\BbTB(Rt_ s?[!Kf&L! zlz &YXEW(sjU=#;#9u?砍M{ِc=k|H^i_{*͇fNE2]f ~c"EWk>(hBz{IdYɡI?/QOP,Zwo>%V5dS. kE@i`%" C%;I|Us󷆳! ⿈3' 4#B8#C"\pEX@C5ۙ1~;b7-%9ud\!PNow k [-r(>z y K! !cH=psBߢBua؇``_XQhq"+!EuBKIƸ :CuuSXQBVm *ALJC>Jn jSuS9oW(_]{1z)źhЪH2I.67`w6R6韾w2=,7<44e rϐ#Vjމ^Tu7K57(f1rCfGUySI$Õ $q6>k͜m]M%$r i!O3fq֓-G8$5+ PRbS5=o$!qm}PZzGIō<0 Đʾ]D gʝ;nF,+r@ .a_t=Am'>Bi1;P elҭKhDlJ{o >HOY4!ዪ@u׀f>N \W,'2 ږ `)?||i-+Uug∝ ܘoc#[_ijخ.|s|ݱy9e%nQUx]6`wSTލ`kT>tT>='F"H,ߘAs, bz{SG&ISCH ů$xRsȕiqR$UT|)݃i~nD B'aۛOw# yna>X_ÔWc? i*7*Kt+=j~$oRj N$%KN7hn="g*þBv (5G hB,}ۇve$u>\#Gw,@BY$VK9B.k{ tٟ=Bbƥ1bҢj3+tOGbLGPL z "3sown@m qci p \52\+jL:IC:)|>`~2?zytY\URcIm.c;(v}8sS%5A>$Ģoso}qזXaɋ";EgHX݂%(wgc 2GŬ4iVd*S4Fh Y -*x~5 ]3y!FFGH_W,wQOIJM\mn`'r1.ˉŹ^a!5n랐-TQBgǞWԝ{WK8~|zwGOX8p g=|ܯ ᛟCkMjN;+dDErACͣ>8KObڤ+< y$ϭ;P#Y9]GpZ4nah~)bCWvRǣMp[D+q*4uhwG^TBp~X{z6w3szq?9Hz:A.j!GIr_esx} >*QK%TPZ: 7@}a brH^`Ĵn˛~ixM=4Ofa`'voc@T_<*-+\×÷bg?E9p?_q$50y:J\E3u,["FHཇ@HcN p%"LrP<-ltl4W+m:ol#fIIX}\^_WB1lmOt a0f ]Tv4Nɭ)PN~Z eQ—F@A:MHaVc,65Rce%ԃx{8ט5S"T,9U 2VwuȄ_ĒBWif@qa}GI -m?u& S?TP+%,ی(|#(3 f#.T=_~pO¿_*K~?vg;RZ0aofB CyB8z~o[#O39G' UH`0\21l;H0-*[(wK\K6c?Ƈ4H1<*$hscdZx`$2 =A'"Q%fu8ڔ<'7-/Ъf4j;zsղ3ؿ}aa˽&" lAaqpeodeŇ@Y&N |u;]X0lgvȝ2Xl9'ekn DXe7pkZ5|YGo)շYW}fv~ 71IlP-69TaP~DUrRl,L̔;*,5=:SmQYv+*=IH w/EX|cLMXMʤ=\,WCCCJf|Ĵ`}wMulJYAy GGavAy`R})i]0J[7;I?.D@7X\ /?}}OUe>`3~+/} {D2q]xK9)A?5SXPkz,O`.r ֹXKPK0@'Ph*8'級eٌ3CZT+,0$fO_)"E|"TT.cۘq`3N9Z75Ywh.Nݑ&D(yhCrkũg\otVl,e U΁uYӨAV$w5u.K)S^pޯAWsCu2Աti4ĜPYNs$ի> vsP:=Nr:̩L%Y.vvM;qYdkwn1z(BDlYE=QOgF"=}?p%Lsv0 {Ƴ lqأe)lfE&vw#$hW2RIBl*z̒n"N1]qKæy B *ީkaƻ9KOX1Ob}Ttf.iǮOlSTSCW T$ϸ #Z:k𦟹XUvR& 69:,=9^X4gG<  !u)|Zivxh6q @:we0lB"BoM9T%ۓ\nbs}w=)]D6ݹef3q~^-!r) 4:]~rAxf馊'@{3)Bm %!dSkQһiǁn/"E!$̮/Sa|dN~&s>bOvr^c 2(Jwe݇fy8w  p9n9SEm}fr+^ڔȂ)DIC'RP4X%E,AEI3[gԪ-w=xA,|$*5QW늞 P3\9N@ B k H(2հxwL}avWߘI=m$L^xE)ٶ Poюj}:[ьG3wchw+Ԯx8'眞E@6QA:^D U#6q"T L (+jOk̘ԇ(TBZډ+.p,ƕ|w6lQ>HpLow ojD}V.>'6tUVOFF+ ]bmTeEu&(mޝ$Yj;cB&`0Zt7ذ2r?Qid D.)ѨKGyf~sxZX4lv Mj=TW  sNHldF=PвJ6Ă֩,q--TMNVi.iBy޴L^[ gt-鈘q+NG-N=&A7J(b'ʄ럿CQkĻ<(@byc^mgm:>qj#jc"Sok w!H{WOQ?.nlJ.Gnt-OJyJ:LE_ZMrH ;/WˡB`~XH5[42mk>shRv:0@`F6(Ll^.(0z-q5̓\E*09 Z.]톛xvRqD$K!u39Zjz(F?PH.i<5wK|9ĄgY)rDWLiI ! ^&z]d@eƎ#S(֊1*7&wۤ"ЀR)YPHK,?8x`' I/jÛ |P>4>e@ W~ƔD7уVkӖkM}κ*ull;d_$-b F̜u 1.֭<wru$nCC\3iΑ " iуAJ73pnoSeQzp>=1G.q)uԶEe[l,N}jy|I͸L;j&n5@AEGY?Kz{A- )/z]f _ qBW!Ƞ2(d(|qzYh^_!Q!E45>ǯoݑkvӭO}.nbX”\D;VXj.320굩~ZY>m}żga /m>P<&VQ`~y$DEVPf w`ܭ ?'CC%g9uaihphH-=w/h}ʣO8TDp~2?z$8F{&p8 O <8\w48a;P0ɲ,\FHAnˇӥJ{}ka~|jW~48Ԃ$}U Ifk}:ҾP{R GUn83sq+ذxZM;+.P/㔽U&UgZU:'G ׭ lϤM4k/HaY y2Z6wK^+1 t!en73&ƊALVMLBIt_s]!&u|G0 Bx8Ĥ I]+ٻRXZ¸ˣX8LB+rJX&xǮo/#6*H!=E}y3)`o= MY!O)|<][E4@xVЂQ^Ur%f w|VQDdLm9mAJ_=Ro8qXUR2_GٞS [)h4VDa|ְ%3 uXi觶K:- |.4 7hH.Ҧ^yv$)xH*?DFXrb}磕P"U?0N/5&i0Qh$Y$6HdE6]CySV.VSݜ0R(Wh>։L(gkDrFɘY;˖ſA]׸zX<2,(Եk9h4 {-mrlaTwtf])ژ_Vf:Wqb=@4ҧj +}i~)sO b.T=g~' |+XOD\U_;_c}}3y- '> ֦Drsd-m2,ƥn,.}!vd|V_P2aVjepUjdОZqP3-/ . S:nFCrJ8d9كS%|Bi2Ue5A~[3JjLfzgkZ:4`Ls١j'-G^ax셢smb%ELo TcDVrnA}mvJ}'ʹCOU5^^UJn1zJbG6 cESl3ƳBH4g 4oegGq  Kެ| k9w?#m5 Y@E V.pl%k⎊؛!4\9h6wvG auW}F&'m/EgV[ g{Vpѻ'܎]dKUp8P.cok8ZaiD[:H'8xb KksD1.'.:PZ{?4Mem00fxNq0L/HEgVA ?fVo+">س huh\=w !`ψ-mW|jf2gܞT o&s@} u?_?!s.g򤁪D ;&טNP|t>z@m5LUY\D_c޽~7rޤNܥd xz_=f ol{z.XCgdӵnMYGI %?KL6wy L􋒶 NXc r$"T—hWoo-g)$k,iIA-kdt8#.KZ j*a2I; & JmFrpng:9ZW\C@mdVb{w GB&0sl$\VrNQ݌ $ǤODsĎ,KŋlvˠR9?'ȹ1ev!C*͎%|q0ز<\v8e~Ћȷ,@i_2:9/PDN0gׇsK*8l4M"puBJ*m7?`slO쨐x>@>)OkGQ(×eE-a\n3S@yEM7+'6IE* P1^NxeSr3/@6q>6eѝj|Þ{s -vmx^Ǵ;NzBB߁s-6dl.6̺#paMƩYaN<( {Ϲt *+q@;81Oâ`_Pl$TZ$5d]oI1YtXX5 Y,ܖ'A-Jx=ɘN +VøjO`Y6Y`ĉF]#R8,)XR b !&--s6H%=d_\u8;V5oFzHlT5W]"2uOGR]k -~#%\!`/ԁ^JZj5?q{Py_ 0xq' e/p xި76d\5kӄi6=c'ϵ2uG G;;Wkwؾ*$ {r;׎B( E4ϩѬub3X=NYIlh)2T')QBP26C$?(pX.aB%ȫIF?Ycn)&6㐖ji]j.@]v<4־WK8q h U;O-~mG0Bn:5+[jA{ߥFha[%Vĩҹ*mO./.SB%yވprk.|QH F » %Cحw¹m/ucRwp"t@{Î&v~xw²%7k_]%>\LDWF@I(e1"ϝkxm~n;VV_ ,r'լ6C{Yy)O^8iadMWܜl[[)8?ZGDeN5z1,M+)ԝZZGxր5[{jbSH$B7[~^A))؂vw.(8 fJ;KnT' y'Yci ?" \̭nl/XZרO`-a֎'M 5Yn(t5?(dwв?D" NVT@rq&.fzOaꮺE狪:ECL@b|poQ~]߇n[WL hpvFc7n"! }8_ C8܉hwuqP@+1ƴ?UI),qcP/F{HK7s7iX(4SE}<'  ^լx_:~7YVxw޸'"R$'l,+k출`vq*&bA&ӱ?6sHza d2q#\2?cI}8nGF%M;c'j=Ag|~tUgDykXO']Th5!A6~I{ɞaZg': awxD@KG y:4`!H<<%-;~&En7^,s(te]x^Q?^0MuTiJfF*Ƚm!W) `&Pp$H%Űր =c,K쑪5ӧYIl$;k:PGٙ$&yiQ|e}u 9$"YEl.8.T\0\м~&"\4p K`!s wt P>9eu7zo|;,@|wFծNi3xܣ]&Qqm(b}sE+: \2ŋ u[YwCu]mbk"PUdgi-oL0PN#@h";/m愾Sc,0NeJ{&wMc'ƔhYU#}ӹ"s`4\3oGf@(q8t<نԁJ!0tbF叄%Mݽ%n 0KTŗ!k#I5a7HhenO~[ #Q;=tN+jB*#EG/qٲ8l`Cbnyخͧ0'].Q:J bY$ȯq1PɑOOrz gdS5oð c!~j\iNփesZ1״^v"k_=_Qxrϳi0W*Y;VP'P`ǚ)%#6&$*ŶcD)M.ilґى%Pw@<7F~oZևeN_KVXө6\S~~Az{/vP}mf2[y7Bѧ=1䀍}){anGv~"A侓^Ϟi KF0P7I{A #ˈ!3HĪw@Qƻ&^ټ΁ @yuXl"mn;TljzUydgj9)jm#*?˷27 b AEYۯH9/:,㝦Pj'ѓ=Iy~DzEU7 HwvwHMG{? q5T%Ǣ:*2fܣkyHSc:oRw2Gն6c^ly\ 'W]=fy4N _ڍ7^ˌ 0TUF{-a!(M(З&޸oB.!ZS6kLY^ݍ".HVRRQݟtu aע7OlMŜӕd$5 f2ifYz;wup<r.+OI/ݔc\Yc݃5'& ts,et{j=W,u>,XJqŠ,ZW,Ş wޓSKFoVx#k埆!,b큣-屢 \;PzHNVw};&%|`' |+bOwq# F@a\Mj `Jv e6vݜMh qW=tJ|>3!K`9 J<>\8Bx+Of-,$m5-B4,7JudlRp 54/ִr‘`GDjdy\hwlMjcۃ&- x(SqX4QʦI cw$anޯB!}!\>_(uXA]n qKҟuX/ (ٮ.ʶsui_,SJIXss2_$x!yJ֩{q} OÙ$ϗ/( ŎxV3]*YQ|cy@:ZҪLU_V!n*s{د`txsDgr_=r=^>CN^gC4YyYD9meձy SӪ#C0Amn#7 (x  a?s@\p;n-BPaSځKmJmLFPx4-[ZmG6 q(Zn[R*+rP⁅QR3Q_GwkTzz;84g3'u PzDF9sZCaK* Ѿ; xG()$z?"4[Md3, c)֤:hWWΈ нз٢IT I¬YzT\s=x: 7@hn5tql"2`h3m*Oy5G\N0xK~M_)* |@󚒒0X/,R"߰ Í8|*Ʊ2YsZ||2ʫfg$hx6w4Nl?U)/v d9m޲MY[ 'k1djC @{U$SCTvt=/j٩2o,=l Lf==`N)u(YqBɃ5w: K.eJ0MBF9& P4?-<QU~ZftG'l>2&~|J(g:Bh;/GL]("1^(dcu@wBO:U|W/(a{C?|A9nO4}C92I\pscԙH"9:L*b!w5of%^н_;Hq悢Z UBV?3[ -sU#`7tkMX-P<6=?|4Βgmh@#ԅ9Sj亀1xHv5b묩5e`P㶌6曙@0}E2w6jpf3[_wV/=t~!J&V}uzuHHD,u集NZKC&1?VcD7SEf̓>hVUuFUWv+k,gXW74:E!eVK'o-)L6F|Keb[ nXX\ 04+ި!M@J3Z&;a[Z+-ٓfnj$:>I_61*V*?IjR?>ڠv,иs?I&jmu6XNo]TΡL}5Ad-y\%@18cZucq&WCdDT!v[,ʼ5Y G'vQQQIJ(W($E3G_{%85`,7μxfjepV9]dDiߢh19 F׸i&b[CuN }Nvt~=+K-8Ȕfr ~&ݮ.<55]tU yB|(kTL ;qF9C%XGw(XEŵl 6M#ߑ? RVaj"q0rKf组 ?,%9,}=@_OS :=MvXwJy؏'z>'>rNvF>zDKZ+*}\ fd9_(@/0xE)ȼO`p7_7  #ḴHH Jb/Y6o1>3}\!"_ӜN%8/8/-TD ,4զF=fq {Qrޡsdi_ƚCH?|0ojU)m`_yXsLm@eAj{C1ŷV]~_;Rj*$/ += |ҏ۞oalMA:8א~Qyy7K\l²~NjVf'sBkkLJdQb129lAL ҄x?-Dm腨Z|wNS>z֤<)4&bn+~"O _<ڴ싅_׉C0nn:4{žDt.)&q뾸ig~o bGh LvűqТ 9?ibHvLɣK>3E:T#bI,U{Ɍ操=c[:x+\0!, z/t: q8.ßiVŜ\DQu "U?(Q\0ܩh|@|@|bլр7R$HO۷?tª8_@|j@*/Z_(Cp'x9pq`JJmC۸3iK@@9`\+>OQ:'sx0$^iogG[Y!3i|F|zFxyumvLQ.Du7D&f7vzN~._2(1iLn#ϴ.pZa iЙ ,/xz}3߿"J47jkŠVBuG s YwruC2׏a)|$6c?jw*{B Npb|=^s0zt.~½X8~p͢ bp5i:`7I[՜쎒 A ey=r~  ; @c~0]z-^j'F!Q@sN@1#?_m6(rW$̎v}z •m4>1^'UILQ?pG8/F.4$/\>G.g9)eNAAv׫+>EZ|uYF4[ZQj"?h?rv46ܲ۩h+Kk5FX{EA E5H#t#8 {NcwA:n>*\rm=lN ԔHzJ=aQ TKH1%;D"$]Jxe)l1Vbp6a5ٔ |'SؚaіudP כƽ9~^J=&Av?1}Dg>04{[vV@: ]4Hg(@BbGFI6+5YYaPQ謱l՜]9~Eףrowо%#Y |5ѮAѨ0**k_RhFW)ɿf!dMGa`Ba"g2q*{ HD<2.O qV²c-ġU֤)f3d}?"+rv;E<^bݛn[v]c)Iˠ߭g3u^wZ_9B\F;r_ Q[9op.uOt_"`[~?q@Cԏ[$FpݗAM@}YE+#³2ޡAaev9`SQaLbe&-:+lIΑcEl&|H*T0UhVٝ׋ /h ;ul~C3D}$83H?+\^7wI#SA[̉:Y;LIJ\؍*֔^&AZ]?mBۋ'9ΉQzhrڲ0:`,1q"8Ɗ\I4z@bkx+E =`FK-3V ~FN]J~"C\mx.RKƍ5(N\[`®m ʆ-2Z˥e@h&>Ru׷jIwhIM\„/dHu!Zں!, ZLحW=J­!`E3rD`}QvwЈDoF[,5h]7 'T33ZZapb+b>h<Xb @$pz{]^?tJ}ZW.v{_H)"&QTla_?,[\ס)ɾȿ&OfFf14AXMY ШeKdb5.mH逯,qKrm9+X^iqIAi5DZ :SNM]%ΛߗkwC%UuΩ|3j73o?`~Hn2OyӚsabto‡>moP(I-U¸zr<.bʭ Φ]._(];&ʐ׏;⟎l Ύ:?/+Kz烡Z cTR,֒F>]~/G8Dӄ+3ǦVw)3fK`:rBk<}WYu /*߈@zZxg92 ~5}#]gtB}? K'3plbWkjŀ0e{N5403 !lz2;Ae֜7G@PN 64LO%8,u1C66r,ܐw46bKyJk9ĤB*Yz) $HUo EbVE,s AO"[8BW6el=֞$mPxM( Lv)"HȐYq>(!ȅ^ur 8EG !M5SS@cb߿Ugw2§SD 08I#A(UsrMm؟BFiu:} WrAw.AgVg0334w|&:fa2\1fiäfq(P~`6㝳P2@kLڃ̸'I-~)$]E 5`ml Ԍ\`ʳT =&w kyy GܚAdCf\h-J"jA T:PbgI)!IZ$ d^d|hy?LRAPO6]6t NJ7fƤV'nKhC/:j,.A_؃`mxp禰fy5\~(AY19ڽ53'7[z?V%Vob"f?8[RGwV.<"ETϧ/32o6'g;چ QLTNbH Ɣ;w U<G/!)9agvkx اW*S}[%b{E.k_!4KkB7.J6e͊X6I:kwC絹c*f9+ԚMK=Co1-f?}cO2 d\3Hðq==.˸Y <2?m&B CIU@i͌Ky{@!tMs7 K)ΰqM @z1!(|@jCI BP\^便*2"i~|ʹB{Y Mõx%J `V0p[iQv]W1drnl4yKX"M\ʛ2t3x%wH'ͥa=ޅu5tOGߴr3 !N>1U÷'6OHe5weY ),Oo%3uaSh@t0}C7/WJ:.4}3YjBz+}bKmHrvEHaw r57ԒM(R7\?z|J O7Wl8A/?$]HϽ[|N=z3轐c=c9ᚮ :5xu*mpzArg؉z:|GC5й'ktgvi51I LRA\$(P@|,yΐ$+ mINc%JM_!A{2m>_֠w&z#ۧy^6 %.×LX{P]΁!k]ㅕ̣ ό}ͽt^kL98j/F\3*Q1z BJ0ʚ3r^ 5\= *HH3&X7dY X׭RaF,/:UoAVe/gCg&0?G_k<ȒnQ>]Ol?$!b㠜$h# ';וZk΁Մq/ld-4x$):xP3:llXnlG1XZå!3}$P8o/+ Q(ZYy9:g)>MN9nSy,}HG7SH_s^=ܢ\Է&*i+̇xg]'Q3f;9v+B%'^IR9,[giyPHs+_s7|@|$@|b C?7}מ@@$ LowJpqyuTȯboVїZ(mP^#q0~ҬU}|f`fؖtNlĄ_S!E]BVfLAߋ-`:˲ $9Cv͘fBR$89M~;V&(>7E14aacYb(-c8 [8-9TM;)CɕMIZnnfg:"yҁJjyD(p`&n+S2ŧYr=->iVQP ,ZF5F7ׂ-z +tA-^$ۥƽ"7MgG`2: < iʅϗ"*cpugݜWv%X=7ġor8$ɹgOpPC/MR.e ),%6')B35~J~ 7 DN^<.t=vL'`nVTr"K,W+ɧBE?:hOgK{0Xl n$Ìb^E03!T\ڭ(4w]x3@ґYDN:ܤCQ®5ҟ.B:5I`0 a'\xP@@C44a3mSz(Gb7TV:~QXo=P`+ͣ1瑚 nLmw%ۻs.BrۗlL4:`n =MfR~]Uy:l).Lp;jg4 %zm8hl}Fg&p-wibT_R¶[7IJd#i=͊2ot@ :X8?~nP~;C('7<%`,>!8uLut^,6gWjtQ U>bZQdKtP}jrqx5ܢs<"#ii^ !w{B7y19s ᒴІc}S5́b\*<#x妌ВqXV 4E*}d(33_-Έsv)%ku`қϪam?mK}l v߻mwXAn8=(”@&b Nw)dg[,<8}.|5rT<%Y%ţ`s*/gn[F  Rz4\&i81-pA(p$0 vgtI1(vআq *rI~B=GY݌N-ddjWl,B$M|%kǎwkN{U3nc4@o jj1 F%yzj*[Z]-N ԑa4vTi4w 2P>^pe|T=OI D?GNmII,!Ҫ#r>܂f&UtJ`Xvw/[xg*(/CīLDMݿt*܀7osx؃#jGb RٮKL pE_S6%┗7]6AWN_[+NĶ<'+YOApQ&J-4Mnz{AmiW_Qpk48&d䰆D˖ <9c<{mb>UF:-w=kT^L-MTQŇح7J3pMRkkЗ%mfRV?_Ү Ų,0N}h !]$6sXlC *l*ӱkv>6 [""`>/z5NX Ǘ?}:(|[u]j ;A,P̹]b؋链s^yy_8ӳ zEk%_d[8CȦBīΤh.e<<ӇۘS}Pɯt2KTu1SfZC|{7c& _1 ۔&V2 >ɚg#_wfF!a=bJ : 5 y=v% GH-S,13GPAQR4J.JH'zJNmJ.X|w(=6[ulVv7끅]\B5m ]?;_6th1FC`N{3!N:1AM. h/و|遊!=9\Z.LgV=YITsʔ +:n.;d9$W!iLd9$+E㪇cCX@hu\!TNWUNA I!~N2 HJUO#vυ8p!ʳ=vb+F<ޟodI̪Fam Ȼo(R=5BxWу|K/X NI6w%N8+mޮƈb&VIFsa ThJ5/T6pHH[Ɯ<8:tl bG]B Df#bΣλiAcAPw3QTk:%zH?ԓN'RyZ5,d:;qNs̤XB@¯IR)!kZW4 &õJuXN?$^>t@0`褨;cEBJ& K8' rf*^ +k%sȊK518eNآIgITs:AZe^dlm[xAODNa5 \/?Qv)1 8c;Ԫ;bZuy|-kFV~K v hHF-_AAӧgdpXdk):&:TqrFo!dU+Oߺ8YQ9#NP+IBf%NRQxjÙy ({Zq3&2wơ@ Z?8e!8vu"]2ҿd7B\^tAn#!bw &4ęͫ:/d _PxUD7nXxeHguUap3Ȯ-SNFKy9U~%Eɛr 8_ٗtnjSݻ4D><B>7Xx Cegb[Y E!*O 8cYTӥ^O:`ɼG܁?Md8F=<6Ӽ HџE&[=7M{dbKeiӻ1_1Ȇ@g2%#$.){LA z-{pOZSV~o8ڗS(kv .e,lDlTsIP_MxT # lse =DS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4PG-?Ï8hF:8Hs mf 0uU':p"<,RT5]Lzs/08`+S=A#؃ ]g~cMn  t[?\IBm|$ó|w XE޸͈NQlFg?A"iznYOsts1Wh9Z,͸C| ĺǪ3&a-5׬V8 "OrB56W3ݑ,}@rS^]v(TF0׿b}mztdb~9d-9…]YޜXPZI^(*5(I 6bni<\CEpU.`N yĘU*ΝjR,x}};5SjA^UD5$ xA *c :wA%.{qH!7.0e%w~>`/ݠ"Gψ-yH&n헏|"٨$~V:'SG7D}\@Bs)́M^ie%& JaT_ȚǢᰪӷ:GSWD21Q=Qɻ9Y@)./ѱ3&oh\w@Lr+֤=#j-7#c)ufL ^SUOp>*uu8C 9Z_I..o vv&g|c7bF[%ޝ"=bx'@Sb9OTk?da'uhl}R} ^h2"K\`>JPg\Ntjrˢj?d呻Y ?IJN%#=`,I<`vIN#1F:ZX!<& Z<0<)E"F_uԼ*~*Μ^ 2;֘ b[ ;:g!TEb)<֢a~;-z 1'cW z00OBj95A2—=Gȃƒ?{@.Ag{E{ j!%U}ܡtQXQPEf\J?Z>iBe_y!Љ#ܶdeشϟ_. ` }&C/^C))]$`)H5_k VH(%_2 X hncO)iY4 mO4a=hH"jIPr4/じ#X +aRPf xn]F!/,یLw%s(moeOB%SBZ}\cNK2 Z͔aCpZI 6Cj^Ki9PFQvfرE⌸n=E Z@L%~}<_U֗ZޭՕ\eajp8(#jt"g4p eu#.[35=\^ZU0JY'/a{(/Mp0/6W>Փޟ1=0^\]70 5$B^w.REc 0te e&VlO^kwU$"^k®\O]Hi_K]$,5=j~:xn[7=Aņ+&!&+Cö}4h o2C.DV&sy"8P)q7/ X6U [ +W/"CLSr[ 0j#}n Q6?ICiTNڰQRquwI~}5*Mh._k%'hvGǯRoF0Dm- "E_8]G`t~ftwO?Mü^I D.!d>`U7gpIX+3օ8ikQ/Oڴ< |P5} Sr,~)jf(X1sහAS0Г@q{f~hWmcuw*LKu{0e_Y(`ŏ(Ks G Tx7#~]NrpȅZp#|>ew^b~@E|.f~Y+ώ){/|ZE}42F9B;XXrW8ئԥF+\W"Q47"r^̶ajvV=ܣx+ȹqMoXoJkmӫevHN!ٖBcz_~]vҟk&W:BDr?7-!0;mlj/va.;}I@zZjbp K3)Y c9e݂療* ew}'vZ>.Xƫׂ'ə˷RL9)~~r%B24\P%Sz\MteEἕ(X6pޫ<פFS=3^zš-c=di8<{6탾^tF};X>+3CAoCv*OM\AY=6'v6(T{cc:9AV dj3svbd]H]0}]?'GTQE }szE+ =busK=3䈷MkΥ-z);_X)JDXO޲̸FvfTtC؏8m7ɾ.VH]/zjdO Za8̨XL]aN=KF}qLCe.XZ@lBMc8:<1qr>ˌ 蘩[&ROkB5 8%9qa|/y˱Cۏn<3B7Y4%dA%wVhJ*K~LzdM],:"7=[w0*Y^5Tg!>XETkAkř2C}'&D:hܨ`{!*,Yl=úCZ2؅XI_̱J4qZNnS^x >=JjT_A% hk2{;8V.-a^K|K?./ ĭջ-kRիU` %hbFjs[;:~ƂfE n t.:Gܼa|20j}uM.SI2։$ۛ.c,0RoaJNoP]CH{?A0TLDmH_xb }W(Ȏyڈ>1jȦ  (*] RSPRVP]BRBB^`J*;m[n>VD7ўf(ap6Zq'w*>%\!3S_z}aQt+">XLA{zt. ) K[C˜c'.Cn'"' %̘Tb(l|x޸ۦD :AJh'm(N)JShEKg1Y E=]IgګM$h1:T粻\}Pѳ=ͷ{4 1,y!3Wt˥ge01@h[qzC{r"t24+Smy״y/% U^cj4qP;WBBp2n`/d{u5,*#?&hsIl'pV}x^+Nw;PJ҄F z1!8*}h*>!%-y0y)]e ݼWģO.sqSsɗc6B3?`>o\.xk ?'Ww]8L=^W{Ei3L hRɜ`č1P]<QN}8]:u+P6O2+"UVgt5;7<*|?J2plICW.m1%o.hI+!{Bq}n_5 DBSDӦ b "Y(WMW|5cqrУ4#}rLYp$s[;5X0xKL7bA٭zP TJg#`io/hռ=xvJo1},|GcLF5?VOPN-?98O){bc̓HIGN[1񏕋BqB?[ר<86 %j8C@tʅ)KTd?Փ1PTJJ=pc'Tdphe|^pV7Ŀ,RSzf_TߞA((; JN3US->3&Zݔnpjt3.=(=es;/f#eUm}xXvHu uj V SQ%ٮqB" 'Xhtg\! FN5 B+U͝mF50=BFy<.7MAqzN2+x=kT-pYHXX|-wV`*Ṡ QF0^\W^ݳZqfT`;H>=GHZ'lbb:6BEDJ~T%R,HtNJ=A{`fp.1gˏ6`hs D 7Ui"9'Um-UY='u^FakҐꈏ?[Euk09Z~ 1o"G ]. oϦu0CA$#?GIy-LMcXK|##^n8 d!p@w|ih7 JFAp!+#U)*>gͰg'H'&n_eI1ttT* ]5q's8{{_S36T}\5eQ;4uEkm!ͱd|>~2X G2\ć S~0c52AS} k%q[%zUqաח?lF-;(2.H0A/yt]W:ږYL+@,;M !zQ5}(-fSNG=PWPeUm:;5yt>O=ZD/U#&l*0=׀XRb|賯bJ+)R>ޘ41@ 2E'Ig#6CrK-T œ&>H2%[ B-v7s`wθ O,B=ET+Oݐ-Ÿ$HeU\{8m ]-'A)-aخ+k"8Ƃ܋BxCED0yrv:@%2K,FĮ(`slW*aex.k9IQb#g1?H+?|gϔw+q)3pL,Q淎JVjfQOZ@"=,ݾ0&z~K=GP*/>A{R/z_Axs; F<?hdW"vw~FHeFG,\ֆ=@q;KP5p,%RN7^m!%I$8ʹv:/ޣ@xq帑$rj<]WIu0rWLjYZ[!%NcҟH[NBZAZ_uc ;J]Xv_.4 .mddߪ*]w7Xs@ӈK%ݯvv6On A$q$w)30EYDhyT hAZ^ϨA`W&1,nW[Rv3n*:Xsi0OBi!Ev[}lVpTe2 P}?T>'Db;ij*!EN\`]ٵMOSX%Dt[?8_COS9g5b "$y2PQ7ާ6t0F˃YeyZ 7\&ഡ=v=:LJg_йEN-ozqg-!Mה6{,M8tIaƬ0j|%#kO3J\V+ '*.ƪ2bj<;5>t]jS@ŸfXv]~U=iMKtK.#o11h.bBzɔE;g']KkfEVb^&r\}YL@la[GFV&67r]؞VhX.h#*:56LJ-S4Mfo>^͘`^8s߱zP#Wm ; O:VEhnː4t߮tj=⟇#V,)TΔ^SWP+e/?_Yw/6n7`]sk2%PV7r #CWH#.[MbD%A Ws+=?}۪qvN 쵿zmS`K=G1TIޅԥ8#&՚ n_ċ">P,E>عPN+!I)ծV% :(2&pwZQ4<"o[;Gh4K/%]I[vrRLuSFP#e_AMm̳RCR2ٓ\DF#|7ElL8+)ڤ߷e+)#T7a,Kl} Y+yfEllࡲR>s\:"88o3w%J+1g)Z'߬g8Zn3Oi* # W$GdHR#3 -LBF~)tS;DD=`9^hrh[+K6j;Ѷ{k+Nbgƨ.O>89y:oRR`gb Q-8ARb<0%nVk=N .rJQw/\zSs ˸_e.HK_hwc-tUt^OΠ?뛈7Ֆv6'ӽ>O89w淣vv q,M32 yb 8~ǿܬ)61 ɢ/~lҺXvXuKZҒ'x!XM%ڜPګSfx=Ɵ짰O ox|9%PwsQ6~b# w*a(]³Go\zCwfn 6?wOJYڷ,۫k`|+LtCCP [Z׹-gP6貳'Uxwf"WJ>8 'jXgGL؄#N%{Mf^/JclO^dhf~p+'jq> F ږ]6t]u7igeuS9X4wK[l!Z=d %$y\ Z<<6Agl/~yP"H Pk3AWܿk=YQ[kVhgpV6g%&lk\E_%&\ZCVNZff1kdR6^|G2.3J]"#0yq9Ny##&:8%m ;!m9_kU?t_ӑHs(cl劍@tiֳ'JqÖP3~ &k;jm*LH@Wt֝5fFٳo<8yJo)Qvβ9wp}@O2h(;6^='FϿ,/6SE5 4A|R*G$hK*..{3;rg'0qTNNvm=W)c>(]W &2Qk(_km&ھ}V͔_l節GVԚԁ[sQm2Aj({ ʺm.Bϒ#r M U+~/{X$A5XWQ3h^?s؆P $qv,L( VIsfI5-gcNb )k=蜭YkOmQhH)Kk5ڕwwy'6urt-Ɖx;P6nWVa]T0:XFD 3Uyݨ' ~^*ѐkC$t?v(B\:K dVBÄQ[q>efKӞմi W}bVƴKGo8jsfS+U|pgn]`$iiz)q}y;GIuM&&DK'k[.."Q(>?{T,x5F+TTXS.oPCqdyS_VuгP!+,5bvwH-. Me_5!\8zlU^h}*ã}1#fp8ľǘO)8jWN]7$Okv ZbFCďԘ^6L8K0Zngw P:9^o BF^4]proqf)pNi!WBRёˁHnAIUes{eK,Mҿhbσ|^,;IӬNC&+~_g1꽘bټʹyw l>uXϺYI5F2ٙhH~:4 GFjmkXZ /Y7xpx!oPp6#.Rf_^q < [-.7zPk"_叙|BLΩ~M4R}b/:_AFf\sr܈W*r}.j{h9bTF{gV@$@;<\8L.QSTXk3ye#$LFk!T\S<&Gx%0bհ J "WuN$9}mMvSm#lIA͕ >20 7PJRH?|||b11+v>hS@"D9eSA6LhϢE @K'jPZ IPR7koxs[=C`TY,#yk7eR"?E>qPQ^SSB;8AoBKDTԷ $=ҙa~`Y!FE"Ѣv@2,EY3ՍpDe+Im jiE5U^DzYyḿN:mCߡ*m//2'Ki4BCc id̾Y*_?J,+%C`Hܞa^?D1\?KFUNSTt^d~V(BQa6wϳ{8~l(?k5&YpӠvx47bΡH9>ܚ|g3kF`stnCdOĤvRg lH5傹zAR%7v` NWhw Zfh2oS~[e[ZيTTpƆ{5m,Qx$!EAH 0m(3*BXq#˽& 1< Z!4"p8r~2'2Dy@dP&71r+#^LXv@&lpJQǼ aK{6VNQo^ 9E?ň?ʈp,fhDCF_ ܦޚe0e26+?-o:uohSĀ_JtNV>]a0~SBbu;ƞoc3\(P8\7ewM99`73ߏį̃QVZTW;1o3^oUrQQg寂Yst!z16*3o9Eȯ08Ǯn-.XqRT3u&aN:ΜoZqVyebQNnSE͎0l>lӀb/:\i \`]a[h]ܬPuu+vEܭxjXZiO?m !EsXc~[HDJL@gL}g[X D^E1/tAUvHJq<dOSEO_g [M@%B%†)s]ީêޡdX(D Tz9 MqOPH>8h6r6l%TuR9y4fD* ͪZ#^&shĶ`iYLMY  S8Fg? 2~S[Cqfǽ4jb=J=D#J>^ȬsoeGa)ZxG}.B'}wY|)`f:..T 3#>:>Z<[?,T~ec:YJ>P(P*hMAZ:ӊbGg /5[kCƜa/T[D4ou#hlWי!|VI56BPfu+G4 Jr ciN7fAo]7Hh|=%nRG~\n(Ɨx{ᦘ[(VlGHX,ܮ˿F;ʨv.Sb1 R |rXiuOGz^׆S;tȊzgϩ9 \L!5 3_?c\cpp}uVݲ՗+09ې2;l>1^b+Ď^Y?<7P8pwxʭygdRMJ_J\+N>nkOO@wsIJ8ԁ /BQ.mk}mQU:F~h:psbuJBǞ7I 3 -CNUeȯ.7sRbqq|?mal35mt:-8퇜"^,LWU2`\k|[" 4bԆdwUD240 ÒI[_R|0Vip#4k>J**#V*u |-Y)*(PG\%YִpX`C\ҮĢ_Zsm]U@z^[s!ᢤVDG[Ygb~ Sj,6rKsL(T.5IUcّ g^K%%JpT_NfkȖ-E@_LDQ3"4/!I-׍p‰c iB.+.(řXKZPjjz>բvsUF {fbUo/CضZ9Ar^Q׎rqR$UQWQtĕWRiu>uVF?0k. 㻴2)=K̽RX$8,cpS?]5vnC߆_B+lVGQyi+0{vo,YfKX ־ 70$mc zp^<&6;WZPMځGD(}+fjV ޘ:07ݗ$tgk8b7!c~7zݡ^ʢ;+ FSCMq"WflܥA3,wETֺ^m0/6:q:)xLg&ڳ: U(wrϺU"5y۝G"V9W7jŠOMr[XX1]=U_XqgD$(U(~&4&q%? 1 SL˿1L'xqi]跟p$lSOl\hBٰKI9/GЙj]}n4hͬ/5҈O$W4Ts3;njC{Qf-/YO:={z>~Bs)~'4ģOAo`Cک)! xzg^(ozG7qM{L}9ıbJ} N0ߛカ2u"E'PNq>(#SDJI[)>lDD F+h˭c!$!Ի{]ix< opID Y2:X)mxCgMPS \2޵Ur0lgdM9 "L(aw L2 n~_(pk{5bu1Sg[I 1G&%)5p<*ݮ`$=J@dB4rjv!IM@> %oDUKx$EV]脕V4rc<u>e[dA< !zA+ Jo!@׈pke(ڒ/,ith,*`Vņ'Bm2 8ѳp8`Z:!Wk aGy)~L ̀8 ,ѭoA/Ϙe@&C_YoU\e=6jm8 E HHkl^\D{$; 7ӭ'**55b?ՓJMXԖ:NErTf;dp+.˔aG%Cf`)"wΠdI~=Rn+`s.pD[ 9|'a{[p[[YlmgWe 1OT" ? YP/."%G:*7믿y6{/B}śOخsy"~h#J?M.7fIRo驍UxOe3BSTR. o.@e/y b/ZRΒbyEl$XD)tQ7p*5y,s UuF?V=Bg+I?S "O`,oǂ M.,Ѕ?O`Y/ >9S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPF88J| }*|@:D,| %.?s`#?߁C7g?@KW;[ml</qeG"׈fb~׬>/#y+@ֺq#}9`bY"R[sR&!qK&{A2U BwKeP-&'Z^;-A4{\~:W`?_ p/~;V[9JLF5[`zs ou:]ۤ2nk/\Hּs:>H&p%3 dUimoiQ9ȁ*}93HdYisRv0{QMk`mKւ,-p9KYtBwT&w5<8Q?ZؔX{ cg'cÊ|/eE\/?{^tlXIYQrlqͩ) }!U>eja.2 "( O[7R_(8r˝~c7þT v i Y[c5&C?7"Mof W?\+{ (Y8\n0,]68A<ދ= W  %F+*1eJwO@ {+H/cV?DM:TE@w>NWۂ}r3o4aޏ tf*->XW;zdu̺q ykGƉv6qXYq2`e1iN ;ڪ qzg)h;;:?*?UM56_7t {pZ(2F U$r:??q2abm]Nc <&3 hA˗kXmhCGs6 (hyx^/ "!7ro?-V}C6sRuNFNPcxgHPGۜZ[8S_,&~n!xD=$sѷ gN^v[ 7BZ>3υՂ^ \]ѹ)$ΛpԝJ ZS!Ĺ!cޓ;F؇|m+LbH[>{I̓kP$n$⼃qћ }K`+o./} >"B`/oQUm.JʔRyZM @57f%\V[Qr ;DAHoAl'I{I i{Q@[j3=FOR=s4-~0xѹVǽئHP1WaL|?`գ]X&܏z0]nWMmgܢbЇ)݌/S םkqm/)p#$-F&2Sy܅P>/z~km`^ 'XkvAs(m nT9F8'z?w8_b%9=FR? |TShr.71LJfR}BN2z@7WWͨ%ger9iG9Š?ۜcùu}  K9Ba`Bzx)<5z4C3CAar"mI/ yK#4ᲅD^c£ΏJ;l|0>0_8Ҁ@|d;2(ڢ-K@rJc<[iB=?AE5w0s FWuoIy5 a¥@BvYyJԂ`r*tpg5UJ0/l&U%r,2dPp?츉$8+'??(Y-W-kiNC,MrboG+T7 __/; ïRmS3{~If2U׺m)9)8`Ƹg8I[z|jNlL62o FP>lrfe9 ~GTn4QZqS ]Ġ7V,{JlWI!M~:=9?Nbw p)"2׼l( -!?BA%Ĩ3 /b7>ϸ5V-S=6N7 iVԘpcfõ u @ B{ZKR.V)|^VRQBS*$-柖E#9^Lx$В; l~Gƛw Efz71wd[k'ΐa{O "<]@tS/řU:I/^K9)wDF?$Q m43AMfUv<~]iR+:^ثeF e1z E!yMH.p>t^kk3ܷgs=IA$#/emհ{9 .&8Ŋ+.F*螎 ;Q;$8U'>{2MqHS1&^W5re";bQ@玈#w36k4T7tt6 P%D^" HdhL@R/fMm[a1817knb1!ڐ훩f9%=pͫ$ydz ۬'3 w~JZw௮)X#T̗K7e0BF@A:5…-ϙ0OLkz:SK4KG4Hʤda2 YN+.qԬnZ0 -̯BLn9W 1&ڨ*aVJfc*bѕ@>Ѿ&y&\eC;cl2meN;[ySЮx #+{I, uBG9HWa٩PV^Ijro*txFm2 ] ῠ`\ZFJ{H8 οOi,O8~E(OY΄%g]CQ0xB.\T0WYA"@cG-|koaHui^G'c%op>*}t IE̔XPx N;5ǡ6Ky*}]dXsBT3/ vi7͊V#|Lew`; C <̓VGuAΫ9SN/d*L8"0;jo9*d묵"\(ʤw#ߨ{7i&)N{=VKVXBkv-JRJt}QNWAo]Wb*RpuuR#%m0/Ap?P2~5X]f NQ Vl;rLt DwVwzjxa㝕NzђHV <&vR  s<<+-a@d2yT#H)r:RnRӥD@N% R5Dbh%@ q1,c<$v M*N}uv ahve_^|!/ Pv>-0]2U9%Y@8į#r,:8Q р m2l3h=5t$p ߸37S υ/:ת[Cbqʴli^u_9H(䲁PD? '8Dxi{x0>YAtE-A k-DwzTY5;ofZ\q%2ЫQLH"֐_@XC{^HL)nHE6,RXi0;hS2Uu뢄bn壻ךS o<eAo2=טnת±i||@|a@_*6@@|d@3g(esjO&p 1Mb.M; Mt:_~3+?Ƙ%;HIq:}ЏZ;?ilZ//YvV%H` Hx`.}7#7ۭ&r˛ӔMf8lm ,MO9C_[Rf-vo(iΧ?{i!d1ǸGސ=t_.JY3iB9y $k=K!Zw5_% )]t'e/]zk Frh֛`N*DOIF"MS *౐H׸?cV+beeMy8Yҗ|V"$#e״bEf#S5,q0<_BS\>5#ƀJ" 5<ؼXì3PG w/,m+qjUQu|iJ%"W2Fj=%w&XU@ 2-D?}*Q=nIZ `cmTDySHLn+֦O?`-\Kp_d CDu奼pڟ^+R`~V?WݚVlLJ 5Z `>UDkMCS! X,<H EZ&1P/EpSXUJD/]Z_rtO"]9d[EQ6u %9jf!t=H=x [*jZ%0Ƿɚ?!YkS s{4",ƒբq"(^rF-.pC߇l HU.to}CCn#p]2cb7?0@Qݩ($EU.bH?'H', _RMWA/npC7FQkJ3=-o'ҦP8q7|pq_+00NW&c'Q -yA7xjarMBjO:.DP .҇9# Gt.%# 6wpmSq&3vWêu%'{Fn3J; P&,tV]C}=t=.T0nzQIN# `p& ".9_#;ZyW AV+mlr=GX& ?3#8pQ@Ԙ@"wQ9E -%[s/FTP\5ˆl}&"VMYg+;zyZ!} rK4\RwP{3<h 0:)/?ShSPy;U61ta`8e6嗍]'卋2;"ፈt mfQoԆ]q\D8AahK69p[Kkpڱae\:G]1s q2$Va)5ᾫ]-_9/._npU%N{A$i@"9$cRV7mYn_'ː"m,v)H{tp#:!YB!ys_AtX"\I9As@c&SN2c=br2E׳ `7e=2YSH>pXR-&q=naq?6L$ f$O_O"뮘,OVsC[D]2"[>&IGBQ͌63Mx%NYDnUಕXW1sq;k/?$~Cl:Kv!X0bsyya5͛l^ϲXЬA4}bt {TbJYB]/`3GT.h溜,;G ~-4e &; Yp"0&?-ã@x}߄S$\Ywn=Y m(G5 M>gv@`־"+CmUo~VxG=eOpߑ3d~E{ݐ5Cjyx8*פi>ɢ0C$|1ل\;9q64].@ `Gd߅ !^)?UΌ@t B܉|W,dJ) k(3Amdqs62"] MQ(i,X`PG,Jk|˽Rhf)lOEvr)`↛rPn)Y$b28Մ_~f=b'CO[]OT_,n8?rhHj.'- zw!j@[:$\N.ӥ?Y+Lq"|! lB "i u9«~N;^~ 5նs-3Tӵah:bjL"̧1Quuľ̔@By{ Wt\GrGtI:XK->/i>4bf&`o簽CFm%x%+}gxCl3o?g-]f#* eP(_0qҲԩ40ң,:&}ђteUt @УX12O(3Dw LNouq j]Y(6}SbF8?-, 95zvsjpZ3յkh05K&־-`:h[Xi9?e>rͣ ptǩ5>v r1n'݂ϔPHS``~Ǻȃ84i 74l_l[EhT<̀0m :~_ ߓρ|_w~a9>v(䈉؋MZ=f 0 "gW!5,-^̣BI,(xvH7q?dUIF|ED=$KxtJpKN< O_S<[0:r?YǫךB,sy0!.ip8-Z[U<)av"x~JIKnMyzavpAY'W* Za V9`!PIg̹]B9MMj͝aQ::kıӈ+/fD2MV". }Sv+W'dP @IPXݗlƸ!@`# DB27L@"Uk'uJ;'%5tn Nbs ]bŋ#u-٥hC 6VQDw7&kiZFe!m`k9(s(k!Ո*ƭhGW rvr1&s*6p/&l:zjnoJnPp 9u3] RrΜalMM~wq$EfMyYw_f\$;~瘥V>|\FpYWڬaRȒe1iR#-DQ`0Y/[nH 7ԟF@̪o T(3Ԧo-Ռ~D`B~RЖLP3fnVe;Zhtd(8 ƛtzjB:nHT 7Tdρ1\@e[d ˁS щ[0Fr^i90'"iq$+ n|u4eU+s]ZCBsv~f\RMSb+ ЧY*;T+Zҫҙ{ &6`GƆl~˞Y#Ӎy:cZg A{kI挐?l/h4%DhЯѠ-_qY>h0\Pa__y," BgxD9)l ^I+xkPP  m Aʉ*T;3oe(Be^}h88fһOφ*Z!9nŸC60[Pj<("_nY&2$D~ u)֕ooTtGFi9kbYvp=V?k Q?UGMٽ"GrN.MMsc(*3P 8@$Կ>CP^ړL SǨFg[6RDK!u. ?=;ӏ7@Mwh aG:3T]D Ziec:?jh!0Gm2(ȴHkTWKbj;b~/l-4nk~S//_U NoA7 OJKho1M((AEq3EiYSJj/Ȩx0(6/&~1'#Κ7#:c[M/ujC0h]j&+xd̃OFz U(d&AJv#Qڵ: ،{j;pt[|c3ys*Ri[?~ɚ$4%l5txkRRjڎ^v 1bM˗MGL(FB;1=Il>ۋE59$M~4.5{M?+詔( 1fN/eT}_zo{>Ep;ȭup.%գ^AuM𬛶L̾J"[Ǧ*P̬ IҎ?g`4fe 2Y=lm ur~,Ꜹ_D R#61AQ4^Nnx Pb"$5﷊cVYO#{c.v˲NġHt5Q rzY)F{Ij)u2u)~ݢ=JhT]0@fq{a͟,n#Z,O%&{9cձFdw*/V=qS}42S(QmT%˔rn44 x@aAU*!("y[Ozݦx#@MD*!zVr"HP"c8(a+z2,ܧxצa$pW[Jě΍@mXcp2 | b=Ɩ]G6ji"1g@OoQ'3ɥI4V%sCcUR8(r[vbZM|S(;.FO}2J Y~.iGI+/LY [6 1Lܧ pe;fpX}]Y?VcbR4 xpkWFT4׿0*n$ԥ-?#xp55ӋRvgXZ'j3Vމxs165QgD ҇BcFz-1hƦs+ج,;4! - PX8N;k`=Rn5 xxHa ''!i4 <:JЃv8 FCEзV!94:?8oaIiğ|@||b Ci{#H6ɦ xr.xC|j@AZw\a}Wj0ɘ݃# !#%8Ǝc8E1TUzo0_ 4T$[b<łMgTfZYQL'>=@A-qXb.6m)\C$Twqg1.繞Bd1Yព,VN034Q䯨S=' T8jeBĀdٌ? 2;)*]js5`)sCghB%@W} _u2QNd'J'N ^~G;McYΓETcv w>ZGYr%y4[zZ-I[ $8{L3>9AV+}6qe[CU<C{Zڙ[ d<,@ڳ]o SsB6mo `[4@vCn!>e$ #gG[)?|>}y6v,TBN.ٺ=c0\7JHa{K~#[s՘J8R6.}O4/`}=7~SJ^h~֯[i:S")ɛ!r$ vfÕܻh] C ڈ-Dধ|hiac /WTK#%iU%PPAg EJ$ 0!A F_խ5V(htbzN].46h'āY޽ DNaߤ mZbqlkӉG@y;L qہNM\~:;M'UtQ7ݧqĠOi\`KULki q_8jR튭r[Od_V,'<^0ϯýGy$=(!KpM&c+Ŀ:ffynl97EJ߬5`Þ& z("屷TM5 <#^^:f]ݦ54/َ aO3 /mH (*nQ2; \W9Qұ?ʵsi55ҥHK6*N)C,z.C,?+?pAQ|$5goB;` D Rӑqwweȫ/ؼ'͉~tִݹUgjm~ϋ}6"~׃aVW=zQ&b E[DIɪUL8tq?I6x _W߂Vf0uAVY*_秒W5!?/~]Ɯ¡Pqy;[foa/p;_h)W7 B =$," 0g= $ L.yHwg-1*6X=/ZNeQLVY&ΏC$ve D4/Nls*lςD/n `}F aP5P"ΐXFSu7rU{P3$qk16´1tHH ;3;KUxizclWܾ]"}LS Ή!p5c}(uX7?Գ4ק wba>9U^y6ruBLtaj=pz%pq={wmI{*H1A* N۟!'섇d{ !`$@s1֑|q>(=mD Sn=:%&Z(D<+Y:HnAB':g )@֮hMZXn ӶJ?!Qe8-}R2;''QYv#OӈM6pȵ߰#i~:Þ6Вt SЌFj -XvWBX*ޢ/k.!5,niϲP1)%P ;ϥFx9ba-RDODQBf  *#a?޾"@t$)b U 8(6{!ɒw.!4 @ڽ!2^+pg_S_yʛR+صAxjAӑjS6Ѐm  Y},O I'jy@uˇll[I@jL*|aZ2-YX{MqJHy̐|'r_=.K}\xDg윖!]6Jx 5ރgҡd/A0'2{#Il.\Y0{u)bjj{2"1esKzŵh08W u6m|[4. :v ׮ʳP7jiHF>R>X_LfɛT;wYzvSc0< ͈@p1W̒9 [4%.U %huWXT@Z|Y:j@yZY,ӫQ߱ю%Ekyqc?%7Rcۓ7tKz]U!9_7' vee(\́~Hx;ٽ F:" }<,VBhL,k d!?}R'"Іk0a߳7xO54_JI-I?ODo|Xc%/=|3:5L Mj;S՚G UzDYP/ﷵf*il@ʐ2)9@LI]I0v$SȪYwa'$Q1 }HdbԢ* eEZ;f𵞤Evv?˓+,C2@aC{gIPKԭ"^ *,y$I8x8hޣ"I"5jڌֶ"X#CJh8v8*fZ$,CI7|J~Ale][ҾΜ-_VK!ioPiÃR,5˷5d̼: /hR /A ρ <:ӘLN ,3nsQ@Ufo83e.ANaNE? _nR>m$BSdUolXAj "u rH>&MwPSVU,9x(:VXY@f<3{~\KDSҿUSQs7@Jo3!/B6IEg jÚIUsⲓ O}U.*W-p̖"&_ Ktb14_ É9=!"?;K$K!#W[ɳL Gx5H<_]ȣEg?Z*@)bZb#˨"H To+xJ8 u :%>.>xS`͔y + !I=NSE,\r3݀psE()Z*~e.VO|.,'N0/n(idf, $Pio0}O?׏ݽi^!wd6dQE@qxٓЙϸ=pHS)#ʕ ѪbTVU"sRT3›kZ/Z}Pb)Um Bժv"Fꯠ*"&>u_| @I^^ڃ2bχkOrgƴ;8 ('sM lTMf+lWГ17ű1$d&u/\ jyTzbxؗ/s-R#meDa$7,-N%c&y/4,[lΈ 3Pg^"B~ꃰ1M, ]#(/OU/xr:OyVf꬈#& `5%Qz[b֭RgtN+ Hs[/DiB5J)KMѵ?^l=2M Vv b4w|>}oV3pE>ݕTCIN>0|l;PJ/ZȪJ+HnbcGP60!nr6<ӎ''Wcp1#b\[PnCSMx^îZBQ8+|.ի ŏ.{6u-`>/d3{wڔ8ڊ``:"68k؉qT}]EmKMY,Fx1ћB%3" \9Sކ$BD .{龂B[uU٩oea36]~L'PFKhQ$H).-i%y=:yH$%IdR"x:QaڹnK.QOp>|xҖxd0l2I^u.04n˶+D;t!ak?#-FpDͶ\.6 1nc+amN}7$5 #3jBRSǨ['D901$]0Eع Ɗ4|`bZב)O#%.#)p&GLDʇ+1My+Z6Nlmg~0v#FK@Sq\S >7qtZ.7|9A9ٷEԳn-l{XrvB.z 4 hBlmSWѶkyk7Âe }eB0mihZ{[( G\g x!8CʒMYXq|m2[p\n5mwHDB;VށQ“sEIÃbYxݷT ֒kN*L!kڬLr4;3vnb#ҖaSg(?!&wS{6@-\@jzHhf@OA 7#=b8J[ry%H^Qa(H:y 5~\(vHZ%U"(lTP[]|}Eϸ,JiMvz:q3ύ~jfb>|Ѡ,u#h`צO:֙?no 8_*'Q=mwbLqH%兹Ƞ#tp;6s, HƓ.Ü16V;Wѽc"v!K0^w\JlۄO*EN{ >D\ -jᚎ6FVB׬(07lu1m;C#RUkV6=5XpT;;6]n lTH<'[ L/2tyXIc?00!Boj;lQ AeE8n.1ߌeQJG2NsӆEnۿÝ6~ w5 LLKq%=dr1%U{Evʉ//c_Jlbܷlp,)cRLQ"^aS]HNs.cvÉi.cx?QNw7NCwZ dJBk‚^I2ǂr%o`o꩷G=R)Bq[F}| k}͢#e(ixv5 thuqC>hm!+YK dvtEk~\0tf+g&'qRS +Fd@WTG,%.эy!ldJ Q$Lds <=d8y/oRk׶㮝2* taELFT9hUȵz.: |_x{vCחBP/'CpCb?*`YdsX߾gh*G-}ۂżʕ`GCK~|Ĥ_S3:sGsAߝZGCF>t snSu'P-\e`U=KLW5WW7tpZڱD.<~ z%pK.1f*LAK-$t*c7K*iW>(qZp_Da\Zcj]$>PTߔ5GjUd[g/?X?sʭs]->ǜ}!鬊 .KrtzAHO6:jY-.v 6(xGfyJNj@"@{c<-}A̖O Hg1+(9:L$ &h5z4,N>&/uCǡl|$dugt=)DzxX1B *==t_Lw~ 0.&H PN7-7'l `,|HohLBJ9Frȟ(]' R 7tR3ݬ;ߚ!`}:s#ڐifrfM&{4Dpf[st1jLG ^ ([:,94+ͺUE! V0"­G.ğq24~5:Wvi-O7b˲kh?Wceǐ̈́օ|n bwJv9 /KSg;@\oCIxsk+SZny$yFQK]7)9p_QKg%ԨE`"4v<DžEWekONOQ(>xö[j!IV $jՓA.+V;  9VބA c[ݤ/<p8@U>\ۓ4Q^)L p/-7eQb ͩm&Ý`VwO .CwKvoE|ږy!.@h_*!n8+2 6?iSuף6]5pq94S9c}8b(m[YaK1_k7PTtzևa~ʸDZ.Σ!L XAkd#aowx'GHIȽ$[|' @?8S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP!]:,Dv iOIC:A|+| @>@"KX"Z6sT^lx=. ܦƒvFXBYv[NBdcƴW|@|w 4qp ,yPs;ASʂńfIZ<8$Q!aykewH!E7UN}! l:!}F h PL_yK©0*^N MUFr3~bSHӠȚuh?PMJ?A0%R;4'06fƙ[kt&#)~ 2;}+!8W\rX/)Q!1]7Ry 0^bEla0; 2 \rvX%D'yY:0̿ J'ɢȚ֕`gۚGm_64ұ C6)-DEDq(~9:;1r$ѠY' t| ~QR҇~WG 6&B{+MFM@ʈͮRn#4Ѽ1>| 5M14#࣫*<w+mo}3UVU^ͣh7*K%wu\Jt(?,.v?pHECZ҄e+o tBwF”Fbܤ #`?F20mhR{J>#]/ko}U/}]0 -(.Q*:Mț(Y7A/X2Lc)&qſ.y?'R'I((\xW'V?`N7s_&1B/xqn^- 3O|&׉Y ԱdkDN98~=]3:$xP "FyBh9Dik6(uvߣ}` Eh}[7KQ;ZWNS62*N=E΢H1luֽ*.&My%`1!D(XNJ&iV %Y<0(f/*wOH?RU®~[^:7H:㖏3d}ܧXoFsp#Ik$eJg+KU۟/i&lj֓gA9h>h ȁTdau|8)hO)y:%@bnVU ԖÌ4]@.rlCoOBqײ [KB VT/\Qʠ4uUzk,,O8A<VT yP^DPX*PϢ> @/`zT<5Ib=0Hpdn@R`#}34 tve)p M?Ͻ5JMp&y2"=E<ÓϜ~Y4\ЁJFf2I3&A,>9tʠ\WU$,`OĶ<4h;*xaTrPj+2v$tb DubH9 5x_:Eoo[%%gv|#r:GQ*ڭjV>voumG$GPfYqw$q;|+*~?&mdG@q[حKJx1 x/ ǣwU%DWz!xږ@3w yOЙBc388ƌdZBo$diG"t̚{4n@)E6_r'8y[nƢ6բ!o l|y l(0>$2kTg}siߙ}/i6ܷ2UA9hjsw\C#:@ 0w1Z5b*©^L…5s\٘ԡiu}j(_sQY QE1 W\}r*yk7JK]L&B5.9eVeei`#'g f?(@$#A""I!i5\4{"C.]?ރ[ ޙ_ t3˕'JRHHdМuOzz8 _Lkov#}d i1ޏ,a:KQ=4|MS >+;z6z/Qm[hsmNz&b%o@X=4pabG-GL vb: 9R:[/1Wg8ޅUY}3-ͅYd]]Sw'<M T8Ka0hiIwU6G$KbZ}d6쳧ioȐ Yn`TD~'vA^gsV7gZӲe*V2X띳”ߤ "\+/b^-{>e'?&_̻TeZdU<(ʏCI'eTRF>C̃֐|!~v~OJpO_gbe-gP.fCU(0υȾgXHLA{n[Ejz2J s~TI6uxgOUe6ƍW4Y ͂F{B5loKn*;6`Lf~W }'!UZ&j P5Yox~e^}\E i䫷;@_$so=84[$E7GL:5f't*yb2:D_咤_6'['VӈN9fC͐TM.%PgxI(IȹϺ(y2 {wU)v[A vGjKg=0*UI𒗞gK^a &@,ݵQC|nutj5D?lc=9 ]P ``@U݅G2YsްJ\Qs .:w;Em]QҬF:pvKa] ;O+k܊hBlFlF|9 GA t{tTvA]%Q_|RY c]^p PM30 mҸ\$h !8݃*>*|DpmPui՛fND3c#Cuz:6m n[# #]Q/6&Ե=17}F`€4ռaKIXv g;r_N9F`{j`\OSVqL1FbT} xQhn9D懝\KNB^^D1e-x7_Ddm<7bh_?3:3TF.Y H~+3w, O9;$LXC2Ci,X}c *z83kI}lb]>Eрu)q&bAV( 8Y@uu.t V S>,@ ?GGZvT 1@iuX]'jjޕ־77 #{`?9 v1 13A\yѸD izJY W`́02KXBe|Tk!9Qs# )ЀFT> ]d/tSQޜߥ7v3};Fq1h.ZCZP6˜ѻ (pz{~3m4h;:{n)\RAzpHX'.x|L-ӁqmMZi}OLloV.HFe7I 0퍣.ٔ_(B+/$8u$*PeQgH5ZTVL!ĺWw-PpeFkٹ;=TKda7bM_y28Um鉮*` TJ‹O?2rgzkZlJ'Owm OCހel6 V`/q[N8/dϰ y1|.X]9T(x?} NlCb/1U%% j4c5d%nBDMp[_ ꣢au>e;+rt{KvƉP;dAI}sKiNJIZr/jao~,XZAJj伫g), f t tZ!7wZIK >5X2%TA9=cW{@jZڍG7>RIcKj4<'F%>g|@||bf;iQ6Q@|j@[~*=_RQ"{QR| \U?~knƣf8p%ݢa˸Op&$e^lD 6ik'aC LE)i?UK%~`+MF]"]_G&4<7 144:^D8.,V9Cd2\ ju<}Pu40jߨ:E"oqXх$&{YͮbPgWK# "Tc`I:fAO1Bץ1!}haR6ˣg QuIl'DaSȳtg7rHK[݇0[ʗ~ zt^Diݾ0d7$k?{wA"w҂8;X>[ Sr?VW֎ D 0BZ#>Аm5wd J(=~;Knӄ:Jn'R$,D 㩛=0ՖƮڢ6gUO:ATEA$0{FRv(Z2#_A 8l#] mUjq b(Im.6>W,vicw$ @T DF{HD#q7V%r"4/`e6+nb BnT7Z3\;ԬM }&H1^Rӝhǥ}WQ[jԪ6wb\ -ƚ6)(dw9g'086!xlE$l9 㙱]>Pq/(,inc-`RL`l}S9k>Ϟb[^L*HB pIy?._`_p`j @ ~G~GKswPCP UUH…, εO$B^@|CwK;"2MKp%7EG`3p5Tڂ"=n1i5!KZ!#X"M0+nL{bf8ib׎N)>pJrY Eɠ1LO_0t~>b(@'~Jj֙3{OIзAN=j"OX"DC1-GfNUxREYQ&lh'#B7Kxm1fƋb; ~ v3d߀.3>Aϑ>\KZ,27uն[Ҳ jЗ;v1"&rIDqFnZHpc?ߒ2m+#|vJ^kڅ2`8[u(]]C 8E2lizM8|Aт&r"iá{֑ǷS`dh; (߿TR8BBsd3u͢؝*tZ/!`~Lo7d]\3hת82%apJ=u&Rlc꘰EQ^c %xn@,ǒE ~.Kf*#1Sλ壑4%IPs5/ s4eZBU7ҨLo܍9B"7!! NڲHaB7m( 'K ^嫲oByzWP y휬M Y`"7s'$~+IEU$jbjNwuvsjH]pd;Cl6re#M75ԴmeF"y9ezbrg $ 8+wDXr~+'1X4~שB>aK|H-qihl]G W@7[AɾgS˘(d=;qqjhsD zGQbQL,tg{?.k@MJ 4p:&(ZU?Y`|\k`cn`)}9yҗLM!f:9*q5ؾjo&͍jB'N2+uA?t_Cï(o ^ɁxJȒ&Q,zm{oEx4ЖfI:Q.˰ Sq =7*ޖ. Fǯys+JĭQ9~~$^J8׭y׬Vr!xb#}C>%ZЄ9 y _O*$yL*1׭$8u? ;#􀆷iR[稌o4_$^zL7h1Kc6aF4`E(7υcc8OxȦd}XցݞsB -m/I wU `]6"uL(4`y_@''I|FNLQ,8$6BM# /ƪlqEfڙ9p}ۅ[aC,ō) ҿ|3| \.]wHARrXp?p׺ )uܨ.aŠ$$-Bi+Gn1 Fnfik->[5 ` 2fԕvL*9 +bX>Qd[}<뫅b'f0wnR4Zx:vD;2B0hMX=[1ϣ{F 65^ KjIQ.fuXno*s^tڲf+H6k>OhDǕ|gL4qʵD؀h 6E;[5Gl n\ە("MuᮇŞv:ݠ3UI'^ ve IX܃hEBP>SWM۷ĢTI4FMl@WdXuL+ǘg7ߟ0q9 -_©"Ta؎*!~9M AJe %]\6>';YXON>mJ~;6CO(TgTﱴ+7# D*/bpڠHPAn,@GwehZ^3 ܑQ%3+^uM9ye>dT;R6."{&G6%H&8^"mmΝqu'0c3&0wB^uZeYNy_LvN:tnią 'b(45Y piQd2)5sMհPϡ8 )4xB;=mSt]tTrrM _9ਵ%L PsANB)QT;ǵOo:t$fӽ6$@1fYYi0^!-[H2l~HLnp3`xWsR&0(s-)!:z~S6&~@J-M2 n Hñ*l[T[ȧs4KX#`L[9:Cx s\JR>՝({!>Foև% Icڛ^1tB6ipö[MvÿЮ]"'ԍ`IbwxǚKPnɀCѶoy2ꌬs@Yб?Komz1W:ȈW"Hqu3+g'u cpu!S'ZaɐH(k02W؝KQV񒺌B<(i茦6CX@'NL`.:b$¶>Rי2B;@#d}Mg.T8J9D-A4W{A_ 6wl0x ;JG.G9d~v[C`I-1^}? \u1d_ŭjy],yf:t|ț = fHB/WS@25mWD5=1<.\$Sk;T*BrePFNiL?{ӵF4\PNHe|@8h@0 |V pzG|0`"G z7fYƴ?RCIS/[  {_b2B:!咾sJo-eRX[8qCw8a_LR!I8Yfg-__|lA@|w`v&&;D0n z Rk(H꥝v]=QkL *yi rdR)#cI W^\.in)Ff4ax'` } = 3,i<>OZPe[$>f(w{-@;s}Ts'~Y.]w:Ve~6DYUALwߥQغNcƉ_SM35{_9X"| Ye]TP18  y](3?s6g_.2a|YU(›ț$o2Rl&[t7ɭw!zF k׋׵ Yovbh4KI]sdί>WtjLVy ͬA~9Ð_&Jj誾[oK0L8tcPkBK=|m_W.w)"SƱ~PlAt݌;Z06MV' ֵ6(CnXÒklK?ֺ2jVLd,efBZ[\ 藢zr?* 8fE25kSV`L~w31y>jQ@ eY5Eº&Yś]=d ygV %n_ky [j}b[* <" o K8lMjZYAީs/-sXh]|@t,I->..Tnz̯A5)çg0)ePZJ˚?oZ^k=BY u / v7݈BIUT⃘Wh Jm REe{%bUeQsO&jnsQeb.6Wތ\NZ}k "]:#}AC-.A"|":udXI\מ^JCp.&rH$T=BKgp`L<_JcV\Z%<`0ڭXlb.^I=%XǬRh?UQ#%^lˠ؎|yĈ Mx+ 1i ykYbkQ)Nt*rс 7ݵkʬh !B,FL3yǒl"ce [_`) ^8I(n]?{xeJlk؀)6!soIbQ__L+Bb%p!9BmDDH7<9/3xiu9D=,xeS r=(g驐-lbQwG$Wԍ{RQap{Uކ,( "6ܭlVITsD$wq(hnZhQP_P iM3NRn"#488?uS[^/%UڥUYHjbak.&'ߤi `8RKu ;A,o~ʆ7 玿Gjw:le c9Lnv"HMf a i# KBMzG~.tyX&CqC*<5@7]zOn 0eU䙭Nݚ-b}=2hI仈~\2:YDT)}5i~*/fu Hz/zǬEQd }-lF4Ɯ7 @8ha4`6Mp2"Exv9FP( ^Xӧ&{rэM">!Q~5!˽8Tػ/Fq}$:tJß=0BzOLR 㫪A˪i~#%8XJlW>zx!Evq (%ӡ<7_{nxO΅{>WGx!⌷b>B [3v^Gu:XۤY<ɤ7x9>ҝ`9p"-<w,~qT:Eﵚ/j5Rxba92xOBbk5 Šo,4D)rvP=|ǰHkI1]ҟ5sz2kEH5OrN*[ -H0_m=1 T"%6V> b<Ϯ)'G|/5܀$yZ9B9 Z* 㵪%?AN2LؒO"N؍n>iM !^J8;(8@MR_=sgO,kOΐ^xHF3=zo4/'YtM ljgM$U'}ȿNğ]zc  iˉe˰8ult_q"rBrA4kmp_FT˹0W/,O/V*H+ڬ[rv-Lq ZmRUo''Mqs^1̻?Map/4Co ԑד.焖V6vfcҍt ]S MM/4Zju%mx[ctVR[TyKbwhRQaLX鹢WLmO,[L2@dTMOx_|nO'‘L&cWA D8@7SpsKåcc mkWMmt%cI3MEtuŗAh9 : h4 22X&_)L[e,8qqײ\ej(tTA͈PQ1E*z+ 9% ,Zy 4"(UJk.(c8WvԀhrVb !шcfSSO%6GtӬ3L[le*6Yc"˩D"|i RIx8 _'O TsK`K;ꐎ(L1M!T2}J [< x?xDYO( m/At\דN#f0@ʬrwy=XP?ܠm#ݳI"MFg5OX5i6=oiq,:YPڹEC#:[+F=Ǡ6n#j.wEjJ:8r~x8+V/sل 9{&T?;7;$+xO[UR Kqc.(cGCY*Dj ^f˱0BK MpAK䀱M.S$IWR&.+. ?C#CSSώ)=#07CTO n5R}% ז)%FHB$D9 Mv(uNgOkPU8?vv~ .>aW0CHzy!d?H%}&[WjXV06°\a! \eZBR.LO|߿lsTP!BA_m"gM}Z$oKY7@ @GGhO1MZk SvR ̧XP"jdk8t]TtM&E؞fTg[؜;ps F{IRѢ%;Gϫ5؀SR')åb擄p@R Ī A>S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP$Gv/q@8xlGw33g:>@DONe,l8(Hd[RK ,ғ2u}o/2fd$a0u:Wc]|,î@|w0MǦ"0-\J):~~5rhMIz4KGIA#d &}翰 Iznh)q᠀ު%; N)~ OLnCK RMD&$R+/iT۫ )Gz\ H 'MƑ^ ι6%"[)զ(%#u28PPYUӆ]r=5o^6֪TǔMN9T2#i'rsUH50n` G>XsOKѽ P? hh0fD"WK z&qAjz 9fPr;hV_T]A47`WTo5 DBSGEٗz bۗgRfj4w&;u n30Aͮm{ܠZh^y@NfxaECK Tsܢ\@5Hk摙L&'7by+]j'=2ˈwMo_ˆb] h߬{f$JI;A,Ӻ}fsz3wЫ;hEK\cs^esV`e(1 -U!\cqv6#J&DV>m,=P;I.| L%)(btˆo$Fĵ1- /{`9*œ[9uONBrE.EpM${\$h_ %QѺ2[{L W7X}[<5/=.1'},378^ T}.z<9Ggmzj˔qLc~.GɈۡX QQ</b!훢^P'̑)*TNV%lx\ZifQO+ ÖO9\t=h;$/gXu8K݁|Npkm;*I1MZp0Ķ1ofN?7hZG-,B,4N+8:tqMD*Ń-vؑ3t: ]pw 'L/$9da?5tJBOAsW<|v@>OY8k2 Gt7ASAma[*lUڏ^cU /E A7`"5{C]:o˩av-ma 5W/t -S)NC-HNd{ {0z^Hs Օ}%GD>;ܢ~v0$0muvxiJbMH.[y{لM"OGe1\IS[$8ڎU5 TEPYyadW'zjИ`Tl*+èx~:26XGj_oF/{5E![ V UN*S~Dh<26} ŲD눏oS¦MN ~Pi廊QT {㽋NX_}Bp"ഝ_}Wp 7W?2cի _;Ӧk1@e-<Or/#vCg`G bH*HK㸏@.j3ZKw ; S;^caGSѲE?7&Vs DplΔ=g.WPcr埪Wd OkB9p:_y"_$cEDGJt#)>\jh11oI7V"V|Fh.JsJ;SX"yYF5q䯸`PM.kVvۢFV C)縹?)& [nT뒹?GD?TY7[` 1JV_^qpU_^S}XZ6<9Vexd7"X `{p #$9K6Л^:Ie+\t.ygYVdb`\ICh&|}۳4evYao߉)\c)o P^\qhnQ/4B| 8rX3`L5u> ':?4Y޷[GsId[YVV6 5|^C>Ԓl@TpkR h*p>J]P;l-՛$SX+jޮtVh5h?lRtXMV :}|}c`;NR;f"%Ŕ ͸i*=*ofaRϽkJ2,oB/tpw#/['26\wEF:/0A7p%|Z>D^Hc¤=f6rF8$G*e.wu[KCrdsJ}㐅-JM#v{>?yGvtGSzmݪ*oM*_&QȧX^ꯕ99O;-ፈQ yWK-d?ex/Y;d4|ёu,UIJ}a %U-8 8`g{N\m  SvH%h.x.$4 ӣᣅ7z<^sGZ_9S@rT ~Dj,cOR39:hV_J|`pDKAWa4;Ti'!8Vh֩Hٴ.L*]-jxӾV< g3f'5MAƷ{PML/Np:j /Y|mC`-U%'b hX&W6W3Df )=bn-]:{])cx+G8PyuPD.4_Qaq Q[L.1Z2//펈Z %x 4<7U~@4gvsgdaVOTpt=;u~8AO;X)^Yźi{-Rt6po9-曂p(\Z䟨V{8 Jȹoާ3K^9JTDs'We#8B'WހdQls|pe?EPğDhY'IT8wǾRQac nQ ׿ϛʼnEŚU*!F1N0mJ ǍT ,R<_ZcOfAA 辕3OT\bxI[Ɋ. O糾ȺZsҪ8L t> tL! cF,O1{CF5 ܟ4 >JoTlu*+=ˡA>Oh&?^bm7%wF9ʇ!p D{? jxl'  QطoFOflS27Yj^$*y R*t#r2Nܬͫ!413:c_ ^7\ajK۷՘ 4gx)ۿiU5yX?4oUK* Dl`eԀ{rQj H="]?Nn/~:˖Skc h/ qGjcF^ۈ|2D+!%0y0-xnKN=!G[u+-w+l3@Q#⠵Il5'g_2i/`L{ 6ŇvȺ%>f3ߛ ;2J5IH:9=wzh@8,2rY؋ػіC&Y&O PV{sB  Z\& */<`XtūV=>Ɯkwhjq`Se`Qɵp.½8ju>ޭ)9(?K"<$`5}7.[LCv(f{<8rC۽N`ب @ \';vTmR3bIΑzRM|ujWmr_ơYF몱!3*wR4k.yW;ֲ6'65Y FI7YCwc܊RӰgej :`ktq$@>Hp'?],[-?7Gѥ՝i|Lw>ڷԭEx S/:o-tj跹@u{ Q,YPϵx D8O ch!$[1: A*Eݪ^(|00c_yfDH S.CAFãʡjbIt@R6 tw>y\@Иf<GQ 9L(Eqzf]c.µVh6ѠQ_*ЈSzYbNƨśD ѧ["!`t3<lu(U:뀖C2N0gb3gfKA]M,9Ƿ_m)e tGu&ͽ %[' רgt&UkZKz3QsąP uKa2(ЭА+uTdRWmgaC# HpT$7ZrAvVu8X;{z:6ZiX l(ʀ=clC p5r{9l-o]}.s0vh= Yc$ p³dQ, ;}qJJFd}/ A?dtU4<>OOQR17RE.\S7ۇ">Mp:C~Zp5+˻i@]4tOo6ȳa<|n!F%'(ȼA;7#)_s,r#I蜴]LsMrn)ͲiyB!Q7}oAjao{vδ_fU)@+ܡp)*n fd[FPD]`HpLO$FH?< OU,hsZOfz@g\^KqX?-de~z>0͕>ssՆMNҚ$|`]ԦLf[2%%`Q6L.pS-clmOme;_:@%bJW(ɯ_ [*!T[nT[=Nwn3qU)L&'4ݖpsyhJ4/̞2;yWA(;v'4!+n9i'}` |8xPz#t\`dDuԓ^eb@|jD) j8~G2<8I i8%/xgdTLES\GU)dU!Y/J+~+A+ZzGFZNz1p'|B|wp7 ݪ24'O50Hm%f/N YbCX | 2cCYgRKCF 'ܥe$ʧ|4>v/1eR|]#gl[PvU|mh9lK'wIc@ZVh]6sYKn(HBNV*FLO_{~Dԕ4i'LFYoZx̝ #,/[qޔ(%O N Z|]Ҙ{Ֆq .#>ˍ‘x+: ar{I6~ߘj"]N F3V:`QTbiH"QH(k G0nŗr{xtσ0E]?_Xu0YaDY9o-qy~tvl͕tⅲZJ% "Cs{%K(Fqn^!O;3mӹD25Y' T.ꋯ5H59=RW8g][M2M.>CQ"U{D>3+Ffv?m( :gUUt ýby^/H?_EMxOm_?O^dID!mj7?; q+56G"ź圬=ùefF_Mompbnq& F2s^8MgrOג^Ð.1UϿxظG>²Mev6@K'5V6^9v\nx\x\~){" S6)_CDD./ln܄ C*,!#f2AD&?=>!hʕ!l.֗T޴<>\Akuj?:{~#ejTeYPحouT~KUw*GcY7A@fg9s9ձ?t"9MG *{*AcK8Cm* 0۷݌:ss9),IT=uh|]i4€7h]+)!ZsHǸAӿH*qMtWFO]ݓ0 `xޚֿHfYLu2ƛYno@g Ex8Eh_ 2G@w])!gyY3jD=r}c-WFΔ8~zw;TGb$?T-x)u0ْSm \A5tzD)N3,tlk$t鼆tT&%HcS+绽Sbb4'ݧ?Qj)'~ZfC](c x*IK 6,G&SXqQP] UN^Т#U/&ڈ"vaW]Ho&O- -{.OsV4ѸzK|^oT= WIy6po mrpn/M;XԋHOM¦+nf?6r \P=Q+wp_MCj.~@;ZT<55-Uyuc^ 4k|6ƯZeDNؘಱ/h\/9^BΟêimߠLĞ ?% (hwݗHkNoQ,TfU38hD_i8 vG>4V&Mv*|,D8fw(h<03T?bx*G<ň8?EQs[&y:!4%%BS|k4떞p8뗭q(h&vS<(D1q Z(7~,3t)\˫/>#g ޔJk>$%cv.aOKu4fims#ȱPv/C7(tP0`>sT @dC?0pXŝf/[ԠӢgHP†U +*S(P&]6a'pht7krlXplē([e@N zP#^Bh3C,4%<+Ջ`V&>R$d*ir1a1YrɄCQ6.a-_|쥿%:wvj3 (xDW^%w("2Oٺ bd@֐?ȫOd͋,W>r)T?AP2Gpa3Jn1Uy!OwF(xVHB;rmn (e~4.5g\Y/_@EB4zBq@*X>_VX"91mWt"~c Ыh'ׄxR`5RJ”rH?dLA4PEoѷsYC6;u>Gm ](0'X/`eZ. 0a%Jkma\D@K7[M(*Q=z0t+RTPO~L9vD\gN6*Yڌ@a(h:H0GDCSskv?D\%joJTB[g~NjmﱹE4'*n<}&ֶj;}X;9j+z=xu>R#]"Lv&M5 <3V׾h*h$Z"_8:ʟ{oؔm};oz,k􌏇q(67I5NdI1yv?d[ ۏ yRqhճTe>;u-iEp^Yc1:o|z/ #8v0)º8.`}_j뫉zT=w2Y;kq"r7\q,3\I5!.ɽG*ȊKqE V"NN67 tgY;V' vs(y Qjt>R ٣|EJtcR1aٕPg(5sBQ^>k V_qq)[QYb5V5^LV.gH6$ R-Duwr̀_f*_]2QmtTk cRnea 1x$ldѽyoЦ$Ozj ?5v]պg݃o>;w&֨Mbh}j83q07Ѝ]_Y.RYjQSߎX+)6%v`b&m#LQmؗ$g`L+@\n&eoh LpvKrY`'.9? CKU9ZR\O/3ZNh϶>qo&g)x2Rڮ:"Ϻ&BDg^ɋ ccE42 $[[hxF \T.G~fW ,K%neEVoXF"Q'qbwg##lxF;RkOx:Ac.Zp,H{o"Z旄׳0`3)WwL:øHZ;Xn8ZRTK25W(!o^Qi?w/v.rfg9׼ [7Ty:Qy&Gqͩ}pkǭB. lb{N:(èbwbWTct{}+1`_>C7Vį:}q8T!v[}6@T#dƥI*0ov7i!.\d/W7 ϫ$=P$gbGn"ucDGrN!|՚i$^.\WAFMd?fpR0IbT!9o )HjB}vC6z~ͪ2 vOU(h:EIEffVZT9oޕ[k5<, ̊Pc;j]@QM dPT{oRP؛Y~ʏvzeqpf͒R:GEB<%B!?yjpc3[f/{ͣRww%י&v:,o<BR28.޲H ߆:0 Д]r*c:b,ʪ1z׆)Y(2˫yO!&% %C)&x1*kX%%x9gVߢuskm IͰgv]PBCޝ;ゾB8fq#07t=% Vqۡ ,@\:_ݻ`y2%giT,~T8~\DjNĥo2-DJvqDzGs55b=n_V8$7Q\,ݣt+㴇]"wrtM LkZhU5KQ^e٣wtVjo׸c0S|x3*]Rq]<Uo/m؈0LlDSy1oStA[.8)>¢0'?|]?pTș`—YeA+ጘ嬇<B*Cx&oq ^!jR7W_jyj{MCغ+*>~/YJwj=W 5unu|#W<@\dݖL}Ic:]0r3^穎U&,`S-z "]|uĖBPpzѮqwj z;2C5g?Whm$%w[h U[O_M ^iCb-z`q%6Vm3֥(OqKrފ;H>mHO"7n yѣr1 Xno)1 d\g 0LH.wFB3lE &TAi\w/epFBGze|i[V`7y\UDukPN*[ QT\-$F5zM)LYen g{7@B1Rfߣ""w;SS~mEHR:CeX:~-~y h2,+J{.X|wRwq1o*d m )N4]8:',;. y=r"w^[=Hn7%`!H̼A&dݿHB -L3ܺ 'j!F7R-"mXx\%J/ ~?$)bRD)BtcmW&B53 G=SmKCFj|u@xi:7aVt3l=^K~CzmwrTL'.-_i"IBjݱõ_BF;SCBN-J3Q[zZg\sfj!ʭOeї30qs7+ ?e(19*}5}%96b<(ŶJR/>&eK5Mëj@P@'e0#tj(Њ'Tcn.*qϾD݅ U6y}Jˋ0H6" w?7#2[MŠ Z&{; $leO9)M&pdȚÊug$ndg MZ.bW8%L_Id8}K<ԁ`ш]K쓮x/ 7Z~YOkt$7zTTqm硪;ӎ _S>u6PY2NZ=FFJݚ"Tj4.]XlA*XjHʘ&~">`,;EH69;6 gXBMJ@z]q-G%HEHG+oO+԰<.4;3hzԂ=;S|qe;:\ f.G) k-:ITĩn3n:ToI."bcui:u=oz#6IvNUE@WxcoJv̤҃ q6{>nr~]4䖎 h&xcs>*~Mr9;%-AՠZP5dnJI2OzcZ:8B2 8 ̝,5S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPlzx&:4À+l`W  =_:a^Ӹ.OVŌjls͔uc!д|d{2=a`H_Mzћc/B۞o||vR߃h!Gwx I ;y"Zg o0n5MV_hakFѥÃ}N02(t|Ѳ}&;*ԇ~Rh1mϞņz4{̧h=- ݍT7lپrs' ?>ɎIMծHM 5A^cYfl]8|7ؐhQMF%6uof{Z#Z&\зXO\vmb @7W95DS}IN/o|>%PU06̅w *? ccj[&eT~fګCK"80W`($"[D H_>U'c^i+}XI ,a4:&7_0'` 49d8VbTdKVcc[gY;RqV5H܎*n!S,X:;/oAAW $%Cqʅ"`V*ekYH Θ *E84Vz]%(?[CdW̉Q>%)C04Ab.^IT%b@kx^fj=_ڵy@0F!ѕA{glvKuWނSN"DGi֧m b!p4yF)O/#KԖ-9"k#a"h"|{v1Ib- @5D=63RqDB 9N ޝt >LWG7/6v[ H8#0]9Na-Xmؙz=b,[DgѨW_ {уjژ<3wD[ &/NOEh"gر8ɧ.A2I:'>ؐ _X>At]# R9}8rx3N #;|?z(7q3-B?O_:Σxt)O%ߤFfw$h-Ok?՚y,_ ׹\]ܠZpS$D3_ ^ m/X?.ُ0$\↭;TTzB)+v! z=0X=Is;)%WY]UnD+;v,'Yd+jf!^V6&- 09AG>pIn׼DiĂ@4=ըF< cnk/> b/ǽ9۪Ba6 ILj+ʲlZ1r$t=Ǣ;B~`^ $0oFU:&꼙y%xm~SxbJRoh01S90b.Z{?(1JٔFQ"zj1kX2N+"lSWKf/#!-ǟMv6]-K[U~u}2iX5"ׁHo-N0Furqy(&ێL7!QN@ea@5=LUer{iqeg`~yf6ဏ=@$HZcero(?:^2 t-Ĉ%)rJy}ނq?;7 `Ŷ@ &`?G|j^k3cd]hԵ.E${⡞3IGoKoK !V/EၹcYVք){-C%ٴe9~ 4yZ2sF.U^EPI(DO`fS]1#?.pZZR 00jPhl"wj2{oG[5K~/%Ǚxg*7y+TOZRvA_*9JEv-.{.R,+Ц+k^ a!Ы-fPbQSZ`4.|h'j%B><Wo0_'!5T=57}#0χL5a1b*gk#AxiL-A3Kyt)Y=B=5axT\L(LrF`1zx %jqVhflrL']_8sqYD4Ns0lf)!|/i\LX tH;0rԎ3cDDo(SxD6 : "swfRS A*ܒ~K$b`Yb45n=V*vaQZz ?R񌋺?nQêV0[0^? 1?ϸ3MKm1ەACԀ*vf4$Pbw諪q4ظhHYA/^&g,dºA61!hq3RtҰ U]"̭S0a=՚UIͤs.œϭ?WBٷYr`c%N5B{ЁA8%Ya %`X%Zx=zHsbJ4J[ txrH#`kԔW<ҪZB/!ۙ5 nj#{ó1'?vԄ.[%9[1h%F P_^0e ;dHč8vU"\ԍxI[x.R$-`Cqmd!X^>`S#`(uò-J8ӄMH㌑_ž^4[JPfqMDfV̀ghcIܴ0˙[6j{m>gxd5QREXa)!]q8#ַD 쇍TkQl)Pq1?y~-b .Mʠb|ڂLx-Ԑ eZt.RZciaIdDM FH9P[8GRP20is?%z g"BLk^VYvoYr//%k< xtTJ4^NB[fzQ&L[zI߇5 ~^=(3$?6dLKT('dKas0WJWky-}lb |@e<TWL<9Utv-̛(`H.'=p!ʅ&1 l-_6Y!%oWDV_8T wsՒ3I8-\T|$~:Xk*ޙvMbBwZePB5\q O"x !$O +l  '0U+? EiaKP=?THg=: j\1Ud 6`8Ae;{-7j -DKMj .~'6P z#67 .eU?](Vi)Gdq)uIR{么 !]-[_yN by՝K/7/|n׵ /:d8Gxq^:T]NcAzb[0$.(699UpM}AUQ1ЂC/a @T>m8 -zje0aܘwDZTeaBF!f ז nXVF8{q>u00GQQaǂ;xqpR#Rn{VVQ@nT4nb}?>?˩@ BkB f-uؘwP\.@*[5OtUM x!NQTC.]ˆQKcB [DM'7)cjH~zdD;| z9 ɭfCƉb)Rp:8Rֹ})ךsR)MvNb3 }IF@bэLJ~ƞݼa0}O3+Ȃ26Bt51ڗ:[ 4"^WsJz3QV(}a~\ߛF$ RzE[m8p;E!u)7HRWz;p5A[| OuMsL7U`e#ף%4~wF@-z1\t v±Ț5Ǣ_ONg2<-R-/s `;Úa;sF8ie⸵HJH&9_VVLE|=jŕ4Ds&~IM2V, ]@TX锕 /ܢ[sspZ6$w@|j}X`duyn5Ux,O1„Ww."3%~ː ,OO1KHo2.5YO{N PKdDhds>='n!V `$A,KԠ6|:\7m˗cҷ~ c(tP?X2)3$ctD-l*JVt"x'N kXa|>@}}|=镭Ԡ]G0&)70 w&h 9FH7UIt&&t˽3.*%%WE3dFudmk/Q0Μ:Gm\i¸ ->4`dX1a氊H !y:1j!V4΢֮[<%K7HhzLZSK8̣e7 峠j0%i~zʓW}TgAtxiphY*mG%*[Q_0{`^ SID_ &h^mPЙt$ )^H-Nt rU,&JũiގǝԏJ֡LО_O[Pe VcslRQ(+6+TpLHhK`d3 Q!Z^٬lpWp!Ȝ^8?>-[}@^U엳 e_Ъ󃼠qm<^ABvR*do T13bW\ *;Ʃ* >En(B<0M+_ŝ€nCR?lC-|~Q+A Ͱq*SsTNX}"ٴob`璮3 ^9|=wA,2fLQYfYQt$A\F`7)pE@YDPAY}Xa &kp l"K25CutUq;Ky 22~Wރ^\}av6'x&",2Iz'Toî&Y s(,hKYwp=Q^-XV)F9"F2 9&(yPpr|XUx:&wc @Mƴ^ROJʰIP^ϟ"a[A{nX:QHJQso=RF,@Q꣦-1pU}MXVxx,+~ap_JGj? oYB2Y2Tp GL/#bPN 1y)FYiq^uOH>%:3RC_M\t, l "d Ư'O;ZM}4 Eͨוw0kebD 1 u`ͳ;5RYe*p.4t#:֩K6 ⎺.o\+Us.Ƈ~#1Ӭmׇ6J[ 4 &5R' 4zz1p?]~wɀ+8JأoiF>M}Ioe(׮אָ~rjY-7Iƛ"C K65m#QJ:7,e߽!;²_AR-q< 6n3D7Vލ):^}kF;;!AF׭Fxd뜪ܬС3ki/E;9ػHy94 e{ϮZT̐ hH2*ѪXa\kVV lZl5sYM_Ѕ!!hmɜ>Dx\I-%Q/b&A^ Js_p-W(k_Qi69"WJ^d+'ts0ԂȰ\f4-VN',,ZZ䈽O]ߞ~,s%RU3 |f=mqaϡɠ>RMF_v g yJFo>.{dfu@' mlsJ!ԷA^v8QcYzf #jDjпkFVr! K(=4ROyqʔ|^Ooyy(M@: [^w8Uzh#NO^z/%i潇AD}ZuPk[iOy' /\ڊX D9bg}6D3y9]2^%AYwspH"o-zX:#c= xXѝQq?-~Y7)ԞL(7S6}Rk1yBm;O/,k$;_9#=8iI[V;/z)+O@ҫ4K]"ֲhfJK$5@Em#`*8ʒkxA#'nHIhQZEvD~E,yĜkܲUCI}Q;]>FenkUFQ㑓tK- l}>0XL/iq=H-D:I ` T3 ""Q53[:Eis)b1ij 0 NsŪ.PQy_$wB$z%S$r "E@[4S* [@e{F~ Z+d(]׶l7f3u{$L>y,h~ʛX2- <5H,.7{_(wSN w(ԏ! ]߸z^YeBow! jZ-ѷC8s/TZFvaP~C/W)K;%rK$B%=\t1 oǚ'k]?, =vEDZb\wriWr"ȧ=nuEcxE=c^yRN0WkHP L0!X"؃v_YwmC3DMi$5*=ya|hg7DYo1Mg7 OG/cЀF Ew7R? $ Qu8 G+>ϲ95dPv@mYr߷}5m!"X"'{^p0eQ=bQ7j -~^NlcP 9?p͉ܭBdrWevȻW~ ( JNϒ'~dlL>T>^A 3')WQ-=¯qcﶥ|O]SWk.@ؽFCdXTLhϯ]X6ەEln |+_'J@E}~^H`ce^vZ@Ƿ"Uch7r/],jUA7&+*㴐tDj{+aQ87 6˗n*{4jѧx98b~ky5&iv .4) bY^dA1{-gL*oWZky_I"OIbBZݳQ.zf_ sz#e< K`hF~p1XƨmNzLrRC5V֥H#BhQ6a>tfI?%С㋻\`<$4G脃ke+<[Syx'ݓ¾VͣN  $Duϱcx R߿jW_ecc5cj_0KWȽ ~w(@( ,$ }f֝Q$IdРïCYq><`3ٵ<'`Tww#k_RFĈ6RN[e2u(`-"`.y.?Bo* S) e0/ msLG2i{)E,SيwQtْ<;4{pPz!yU<<hAHW.gɎ~+qQ}#V~fTylyFE-;R_`bɢ|>@C}iVmJWxԟMyޟ.c%Y\U*ZgU[Zހ-K&KH&~gvXR6o9nlYw'/fx,wv5DZ10T1לGhzX6]`#ݼaa [t',l骱o) ͔YLI.JU=rZr,Y˷'#T-#| uoPXwFX껿t0E=M8 +3ݨȟnC΃a0# T/{h=P%p=l $o& >.6.w։Bz t6烣|Bdȥg."9PW&SmN$b2Z&[k[ J@e޵ahYC(S:hD/_2?4 HD@C t3EۨW*+r? @hIʓq T2,ML@Z;M}ښ,b_->vƗXVXnUH0I4k͋=-}Dࢡݛ<2nX  5tYHg.@GM٩`W}4#-Q;EC3/Xvl^wN ,ֺ_ZSxIwE*ÛQ(BUz a8V-7Q#WO +fFwMNɜGP'H}pIӯO.t[תȆ!hNA^d77E6!sR k5|"-mi?3jbhl`"M1?@9u{2vX+RDHaiSDѨ 1 :~rvbt5+_d0頏{hXM#%52{K@I H_?{36!u{yERKjNLK'g_gZ*,;)h~u h\BM)FM*BT9G)e}bȮ? <G#f?LWv^(G iExKq5m[;9y I~uԺ0~Xj͒}ׂZ_qh2:p(vYS76JxYc/6b1xRS8ׁ7]C'AIgp޾}UBr%>Gɳ396 4 ` a1lPGMhiLoGa߆8V:qܐR/mfbt5hmZsg+k$c{cθ%"[)9՟ik$e֟ɘm8xCрbn T}q$Iq C?y[\%ZV;&lXiv (w͝Z%2>DnfrR!_iyeDR韁`X ӋVWkL c8`wtWmynj*bؑS@A[QuU6Թ8ö2dJE/mAZP"|~XrKx 7>,i>m*c?Kn349 pk&5|[>c<|}tTT} m YkZ@;GXBNR6aFOknU8Wv.Us[P}71`8Y5o8&W`3RXCS>F' Fp'1Q(8˜&?%aA%8IfYZLCжHB޽o[F|{ *cЫJ1L'mRހЪ MĨ3Ɛ .127Ѱ9X -& ! ~PlI ^ ܹŜ ÁCϸʨ4pk=Y紤~4tw+3^c N."XrH{:xe)]k,_Enxя}]tL?\jBhd25VP '?5ʐc JZ XNTA}gTQ7#Hp,yK6=FhHpM8`HZ1? f{n:u\sKG!_O Ka=B9F!Na҇Ž>QB 1~?uvQd4o> hCއSoq᧻7bXg|= R~,po_OǁQw/y=RGLt};dEu  .tA݇$0@%j-K9Pƞ=giTKԜbx|O\G=I$4\EJv:Lˆ$fUtg,X~ŰċYm.kSCP8m`˓pG;kZA;n#8̄|ddVikd+8S6u1DU,E[zfs>f䪸&cX/T*=K$?sfEM@-ၶrΊ;>6s_%ɝ o^ K~қ3jW aCJHn4I7̙gN@,FBtneqW8AOzoE0 ߨ9.16‘ mjM5T>^R8 B&&B-3]-$Mr~K tvkXOt]ㅖ5^ֆ ՟aZwx;Z far px k0Ui!$`Fޅ*KC!pT6GsO4kt,4 쭬L6r+ý`]h}U5./YM1A,oR9%UF9a| TwM%}.vcɳ|Fe 3-Ż C@ S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPϺU>4h/8Xh2 i0LLn:>@ 6,,.ED}'R \?,|.S yU0ymD4~vY? \u@@o?23]eD|x_GB yDQīpץ16jM~*͊ @tM$[Qǝ54idNuM*Dm": 3 kڼ7Z!4ZnX{xHPu<_=LY(NIWtT 14*E93kBKʛKp~Rp~M qz61Զٝv\g~\u[=(2WafFnN%d-gSÌ2/Abs q_{ Ω* 3h vYXHDgx$QSm=yz"a,vs*ONSA?-C?>*wfAvOĢwHFxbywi3ւ#DioV~>UN)p)ƪ:i|\2'SB0jhʸϤt+Cwh 3>HX,F=]#q)`y" 3F"n B^6KU~EE\Q *x~v^;lW<0/Dɡg{ǂ?$Uf;bǩ] _I7]6ۋS=C]Fr=zʱvpUچQ#)ۿ㸰RջGHXRևYT4G$+y-#|.B,PvT=xX=rƈڮz8AO4%)ݠe:6UU Pm2 Ř܋hUw+N5pwLFm^1ҵ2EbYI6$,eJoTeDwbg nýxhM]T{ZgId?صYkF9WZHFч*=/);ƋMo ,Mj5nSXw6wS*nZ< |w2+ގҽv+U6R|q46? zC6yM!'c$@BRjvlmBף!}S .AMj<(i#FW?n WW[ ._(f$gfD`>|Srt4ѺJkLJ &1qs$/ˡSM6R}s9 9V,5fPn~J sA|7|G"גfApW Rv'<*#%}-goj&X1`͓[XzR>HmJ^04Fwxؗ(R VGG%vE *YUR"8@VJ}$E* 3(7z А}Rc22ǰ*9X>9Y8=xgbPxnqޢY&:N!TbV"GB׍n )g&`5:A ==T!Y}PGƐ8zJW8A!W>+F+kgwCPqYė5ML]{~9,$-̫ kqDDRz+QEָn| 3ڄˌb&T n(b9քnC5s*yv}Fk2*w"ճ!:o)장DQU(O[B |d'D}/G[젼Že2+EI/45}0%} Gןu5foO3 _?^+S>< )P nDF0C>3)=*]~9֫e :mN>X21":FT3Ԁe 6q6\f! (%##LL(eoMv k-.U¤(?T|F!la__43Ѳ}:hA2ccRB~4" WEuT \;ܢ!D5_qVՄi7~Ya$ߠÞojU|(`^3HULkׄb:m젚E6iԠ,6O=:!/[V x`8ǭŃ\ս9kMO5b0q֬54਺=Иwn6]̼Q<*(I\H\>麵{Qc6"pFr)&9ɂ^-6t.fl:Fӏr/\%_ssEPO\/]pMD1\C]e+7B!QbyXimZ`;u𒭭 ֘!hT'9cxꁖ-*l +U|e+ uGtVM{H@q0j Ȱe#sX#MY!I.0Ok0B8**.RЦmVxm>:K̂Pe8 3IB+k15h9Sld؁>W]x+eq`6"*"P$B9gupE52ACOO9ctZ6X;SwFhjh{+SWL,&}1vi0kpde,gOn"7Ef+0,'}fv]xP\6$4}f1w{)WBw`i nAf8nu 3{~ # -<KyK.X"(n,@由!e|@|>@؊$) oP?C@|jQ355s4]erS!~qOF0o,һkɎL@WI~FGG'QCmGTb{Gl-+լ7!u?_ml@h^#'_&-ot**Uʏy|$=+uw/蠾%l}05wǡĞDg7:0LUEhtxpCVuu$hvw)!1;D hQ_ (B-$Zurl.2_2Ԥ s`.Fܵt7΁6&q+ݟFJPiN%pJI] ,ҙo(}ˌ1K&Cf0h ̘rXHaq_U鎃tkbbѲG;4Vy#7Z Fu2bÿo @Lz-[ TV fD~Z.}?dn0uڅA?-u.V@G ;5όШXSiKsJJ#KL##1>}Vv(D>ӔD R94+蔼[h~Npߛ0vD ~s'z<;a9Heb8{1ș[SH'33$ф UYs-y\'P8*V{59ݪGsH\u{0ˁYK=-!y ԍ/e=-}>\gtdǢMIU'  m"8 g3fw&ON@Mis}NM$[Z|Sx2gEyOMئp o 1yC`"p{ ˣ 㕥eRʤX6&%%tgY1s:#!W x@,a*:g8|( 9O "2tJI>C/>V'Pz~vht sGכ6'ibc !i%<83S.WaJ-_IѴP@{n+PM"|Q֊1635m%&ǡuoEn8q}ßa={:ECva.X*݆9ެlJ3[ty؏\s$*I Bs$sDeՙIy4wz ^ғьF^@41EŚ:6|>*&A]BGXz@v\}3؋qu(.5 D]0ދL3 M@e+G4qh^^?IyPAdNMQ4NpF<\peґڿxP0c Յp~:}/hL 5GAޛ2?^d:l ?,9,~9FuXo*>_ug"$LFU jb1jEk $0b/ NpȧbP8Fqdq~hWrBKzЏ8\Q&f ޹z*24Rnw0Ӎaam[*4?'`(Ce!;ۆ0` QKZ*tΧ`Կ?Iyíah. Wj?/gk{\ڋ&KEw}+n|÷++.j߂4fb+=R҉)s- nw+n^BCBD[SpTh؁gd+ 0]:d9SՇovF&+g`vf}rv4&!0p478&'OM/,1q)EB]+'KW/6ru z =!`GUdZ/ ]ɻbV^MABi%}=.%;3Jl% ft&뺦p;2*_iK+vO}4;wd'ՑK`7Wn_a4frpH i`ECd.Vѹo3mQka3Sˡf5%'T=>Y^<NLWF[-i_v-7}Ĺ7IKd<9)d$wOgCby<PK6=ʪs.\ `FV0޸4 /Jy,685B&p49Vf|re4% qL,t\r],-Mm9`0B0 P?5r6? Zw*[$ܫ~$Rפy6>~20ۈL#ݚ;iԵ?R1)#alțhNYY6f;ѲK9fIh#<\.B㐡},%:/"oaǭ}~9̻jqRm( E"v8fRDyv 3~¼OhAp*wISvGK$rE/S'FNAY3\6s7fEv3y>o= VP M? uCP4#W2)sJQJ&}+΋Va)'4;EjM2RS6H` "s&Q+ɷ\#!al=Khv>6zȡo$ YG !Kjز\yf|T)'~s)Yّyn08ee#4FbGPTp#rZ13p %E1xX)we2tDЍ(](;T=]tm'inxOՓ _ kn3J,ݾt_,(l>_j083jrdKIImuڙxL|)k }EgW>VW3zTބE~F3Owe_/@<# #NmjܬN<{ 9~b&)`E=TppרG][c>d,8ѫ wVͱCjMm̾c:~_l,knnqX^ ٓVdˣjȰ*YѤ_ֽ 'IUv!AY/O45ͺrBP: qҧ|$x 9i߹W4ߧ9w게TZO[F!qB:i3H^ʪDfڃ{[1=>B`ʧTJ9ؤ-'lmTW Ӯ[3،`<1]ႌN9>E7ղEN bP|\gƤRO؂Z"*nX{}ElLQj5})ns:-m˙`7< iVV[)R\x28PAbkNSz^ug+ *x+-vtƥƒ@u85h-EuԀޫ# cH8һTL9'Ȳ%ߗRN+;͇$Z@AZpM8dAq]ZE( Rl)э8`ܯc 7kuZL̏I<"NܸC* 2g4< _QagVu7#}1WCnd-/x P@^kdhZ\̗j› >|(۫@E_sN[;M6n=#sY{s | ̮?7OY+%wȞ`%cVcbG/q?UkWݵ=isM%Dع\uRxFj +`\,`n(|2klze֩ٱF-dX ?)SB;R6X0v5,Op?( Wmy"Pfaٰa" Rτ%u@HT]%Yy$YPrd~|UljkTF)vzd"E0 Gf?$ΩpjA*coZ~{du}qz ac?5k҈Ɯ3m7aכ?TxNKID-4,= p%+;ewmQ/X¬d ~f8V{\Vy $] ƧލO<ٳ8J@Qbѷ{|z1]H'f/} CW\7ՙ:]B:leM42.iPG\<$~D%1'M.]OdyVY߶jkXa 9kȉ#UV狿`8=PgA fXo^z`bwH?[*W [>kC+! DB}Pp\VYO ɉ^ ~ yfsX]&&&jsy6~^9Jg}gӃ]Q47U6C m4ɮ! ~q ְx%6Zj⋮r{ZSEHKt>إcq.=_W]䛃ka5@vՕXļF ٧櫽D^ݾ{`(qUx͔,zkLJ.օ_AR ol=%3V Q2* :vߜ-VT .9k ;)U>ACFҽ\pKDLhԦZ$֠|UW_#fhʻ+kY{<4K+-DP7?yF\}ƯȒIP,!<"tݔ /b>:0>&&68 4 Ǿ Γq2 946 2!ۆYMm̔$DvO\L6X~YZrCy:*L̮PN u|$@|@>@!_#>J<i#|>4>e@-fZ=&;Sr͊HYܚ'lu$" 4g\ER5RSUĥB:MSKPUځ>t=~\ט|=.b]V! _K?_m< @W_ dݱ+]ŸaQءꆬnXܫ7%*s +Q@xRS]'XHxrFs(?rI=8n,*Ah߬Lk$BӼNZ0udBIY +zxY}uS+5K^ AhB4SIk`nj[M5ZOnqf) FlIJ)Q@ 33xʦ xOk|t2c- i^zQ#ZaE@c0uWVBW*as@1BP0b=r /Z۱@՗%Fr#b Wt? CZ0pTkEUX׎ MR#F@E\Obrv!'oʴ`l0K<0<\Bg(-ݩ+L_VmALA38TjhW|s*u<97gxAv_fn{6$C`d=\58Za|-n$Ξ9ivC ESGydS3K`R([3_ʞe.w*Ve˾^ ڏa|ej9YD#)v&atJtb_o~i߾ \e?&<,̄V6kй?4ĀGq o3Vs6o~oD3g:{^aune*;Ep>4%5/\Ƕ1'LSڀN5>yfAΨIfu ߸U:ZDHKb`%N1!%1t8I<+-bDP)Հ//nc1QY ڦhQ8; dRBfo95 [^C3֞z4R ^LP[ӸW8} ՝L@>cCEhn]Sfɡ,kϥaqEر&`멗.diE;^|I0) $7TG~X5. E? ;œ%inϧſ@3u}4VQCȗ$`rȫ}%A۶F"[^i6nyl 6k}/긪ܼ Y^0yۀ3{Lq9mS1 rSW1K<I#4@t~̤aOȹ |tYY8@xͪb 4͝Z8c¢-ꛘHE&D΁ bkc98 !j6]>4QS C-}m苐bWϠ 6XdUuGQ % ~7d 4޸/K~t {KІZ`N;T5C%;WzvBi&X`"/B<|Y{ }mⷩcsDR1f-T\TgZS?qYR2a6bޚzcȊeU\8;}g㉑^oT+<Ɓ,cXډ,} uzF%vN lzΡbCh.I#b`b0N4oe4M/͛@8x3 X@WeE8/g?wyurW̡ߙ-C[#Ƨ[\ ^4n#pt,}&bNy' XR.KSDj^sO,%$F,McVT*?:IeeY+04% PhQ08TZi,k6HN 6I?TpgɰR>9E'gZfr;h6j c/@6xYs@J6Nyش) #H<6RV1'/fp$L w<}hqovrGsIN༁P\fBiuw9,vWu E.zm=؂` `VY!:u.G-p^"]sil8eXh+L3x0̣a YjHaG?zB9l[ȶ,_Hu 7#w #HӛÖVb@ czܤy '4ν5Oy֙VVrX%qabƤR07tAp=lմxPiBߖiD9یd&??Vi:LZ24R7Vn?DZcXk-d|\OLPD5dk&Zo)^csb? /%+6)nʹ [ȅ|c L\O'>td9KZK`DxނaQBGӮ8h,4U5\/H^Crj.lpCʼn8)|mND~nf/M|Ǧ|RӶcSާWgX{[iO_ &^[d-!%<_O;􌙢<ҳɨ!6Q.nTװkB3q'6N<[";}q5#7|T:Wu3%\#x ̧ {$/KD.귊 R}hmkWpBVtǛ2IIa4?ekύxdkmEÕ 20"Vp$]uaio D?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPFC:4:8#Hc C|*| @>,~y΃/"s_fhkI[NυS!k,s'y U NL¡?.fo|:@> 8wqW6킓-e7^> wj/*%=@]svr< bTҍReq,,04Dy[8!8H.٩n\= 9<"5a38MjJ?s.^Y.Y$ah{1y8AjJnANψ@|mseFF nZۦj #.йf,mIn}pe.mHݥ@|C,"쎚)DNvCI0?|@;1˯"$y/͕eT L&PG,[z.c![k^v5*a VJ/;l*Yƈ;agWfN@XHzb3>Jz|j {KC7GaXhr,mS|Eúwa} :=l3,]fmS@ v7q;&C#]%L'$Ndqi~h`$y۹B.0kI,vC @~l6x;p hQP]uvPR0,pN땦C2[ ]~j=vv8_s204,bvR>'o[ҷuv,CzqKgMAV+IY](v 0gyfyHϓ#>@Aɲ\Y^d7cI@dûk5ϝ|8ݡN  \u.<5zQ͂ E`' Go K}7*lϮ}K!U)Ջ4Vr[=gh@DQ@̙;^.Ic`kg;sp&Ŀ+}sCvpeXZ0z^$Y{D42ѳO6gB+;ب Cȶeb Ñڥ<Յ9E<i[}}(M n)¾}ة~K@dWqhw)=- 3Wv[>gg7jw+cLXd?ܴ_}RW.\ԃl$-yWu$xKvnFR΄'"N3݉$^)8,NDҦ?Z07Z?NʼneM8rJz?q*53=:#Z0'j>F琉b} ON|+> Y o`+H0#M\)zM)DF6:#^=.*^1ߖ{QCŴP$@8,k"-Чed@p(J̀UW s~c9_ߒ3OrpuY}E1_ =!5'cAw9 h<)ڣM"6uDmP,RNYy$2,WU3ТCo`IsRX9fuj~%77HV@IjRztKc#ZYR7LK"܀%6 \#8?qrp/D%c6 >g.8 \1OHK" ATΔ0Q 6 u9(!Uevަߒˊ'Xť_ ƶz|u#y̨[4Qc@0DퟟR */{753gvM xFL 6k иsWM'oV;M'Éwr'7!J9ޑ zI@Go3_1uk:z<.4U3k5Ye*/j*Dz <Hg-J,DMǖxґ]T&AlYA)G7 )>Jб9S3 D5XLҍdepP5SLmQg(C 4=rAsʫVy aU˄{|CHq.;+ ll9$,?ܽrpЍ 诎C(ӭx7a H\rj]-ɭp0v!ڄΰI.`T6YCB2a"%Һ[clT<uc3N r߄< 󏨀4@Br9lmw/8LmthF/-$_jBxPtq}Z" [C.RxZ>lܑ!9Ր#ʂ`@]p0 ƻ7zJ6Ȫ 7bj('!a+gِ[}}4bMrpE";d=9ړR}.`'nFt8sO kUvU?h dqW$o`x6L+m mJ2>5Ri%PoVI:h ( **'VΓV-puھ=t`F\ 4j+|oN> ß0ltSB *4;'媯'̼ \vо=5 "+MF%^4yHşXLP P]— F^V玓8_;Mu-Mq:"1u_ת4,M\F_/lLK"*mHLXvM? j=oGy-W$EB!t-t}_9iذrYe>BLKG}%\@7ǒB4 ٢T`ڠ^hϻ_+'c_ 7& f[@v\*'7l%8swf_HcԢK]%͖$&J}:~ΘzlIӃ8\Hz9>yJWI* FL0I*8O^P3ޤm,L_3!%eNk Pc̞._($*I|UV+q,"X)FiݠP'ԓ2 an(thwTsJ շd95KE;ƇY:ghvPv A"U'Y}Q4؂qK$@ 9~G)u{-\@` Px@Z׷QdIpY~6]O$_Lnj׋265wxKDa`?@=7{$(=~M0Ci"y=lЁGsm Ƀb@;~ jHxIu^<YZKsgA 䝥 o O~ lp3C$GRd6vy[b(NUnI})+%?@g36Y@j/RMoz*3p^6͗;HĶt<t\uWŌCRեy4N/uW k/XFA38nf8aXI"}AdH Sߑs&Kt=>~#v 0w~Z :I2)5%cs4GOw/8ǰ}+W؅:KS>M7BΛ|7e_!+ 1Tn c5^=.bQD75qmrL]tfڿO>לe.n@( igR$˙ŘX`'XSmhEEvQ0Ȉˮ.ఘfş.aZ8T޻ SrwKrEDw3|Sxm VK_[ 3.Tg%AZ6dJ +V,oiEr*!ڏKmL< gu߷YZ9<E~ ٦-%I]M[kC=@gê6Lq=(і\3eM$>o1L>U˨DX&*1P/rs/źvGC%p `,ݤP)P! :v@$[x|*z; +N66)9y;cx Iß?t:ੑOYd<:E'^++D&fj>J{72u]hlH@G?VzwǶ2K_<+⨑eRskJnĨ946ډR"L ;G|&eIbs_8& ./Y[ r_pH&40sFVk]%l~$xD*<|4=Y>\Do<۞}E=L cƪL~giZ)&ѠP;n ]ZbJʐHZB*!+Y|"cAh"+ =o~ !fw+?So36%Lt܇֢Qc2nK7*˽Mh+J eRo{4Qjj_ߡ TKAE,|?Z3zah L&XN|nܻ`l^;]~œR;"LOsg,uy F 7ROK=Xr:xKڣ1dڣsũc:ͳFݶaP?LI޳gW-^쿘CNyyB|GOZTR|@|@|bRv%2G## !u۷_|@|@|jjB;* 2ʅUaJ,bd.Hfgݟ,bsڊLU_f 0T8PJ`TdǗY7eɄ֤+Rs~"W}>= G)χd^=R^YBlُ@RwjUl`t$Sv[3Iv/UrVx6 yapN澡UF/%\ä@>׿CzĭOP{P'AɡJkZ0%@La#M0 ɼiFt {-cPrWgE$5`8_+ۇމ0҉nZ сi)0GvhjaBe6^x[P% ^l4|Kxպ4 PJ5Uڰލ{wCJ%Pc9dXYƉ"e=z $w|>}`a&(UI&jw"bORN7a~Nh?l=&%SڟPU+LNv=RILdIUg3wсrT*-ClKV NWNd\)<V7 `gzu":\@iV5 K +(%Q;q?&1+5~KQ~4x $ƮqO7 MU_ˊ«m%.ϹCIxiz2iF,O7#e "b inI~2!@B \i#'9g0ѥ/ ߸ٱT;ZD*up=_`/Su 3afBD pZ"ߜ%х̈YPvDq/`c $ ݘWoX>6ſȍ-Kh 1%v#7w}7#\4T>a$&+ XC8$HuյQlQRptO8IAD U:ejp?-l bܬ|o"ӥ . ?@?~ vsA 9OuE,cgn폕:3ld7sBGCFU/Bi~?n&EC4m A;S;CP8mu :<~~~ߗ0>&zwQơ~2)`k0Lwn-Kt9@tF?` _,N{5f >L~V_aCzIOЅ׮Gn<蚳}g 1 ]]vID=_Xf9M ^L6dF45<ҲkN]s5q>5e}7=e(הN̡5CewqS` >0Zv٦A^~Ywe#HbE?]gzG/B;BЭ %~aK{lNIy[w}w/bP½Z#[hы,̍rCFPvP{c\)-s =icN-[=(غ-&V|#ɑ1KjӶMP e`U/Wu@J|at4px n1fs&دbui,s_ngT2҃/hoI]:uas9F\uhsk:kf;3yl)`D9KSpZX}읗|s )t6y@E-UFc| ꐘΧ_yG9VlM#gCJn "ŠZf2'Ǐ,?*EKG={>|rbs"78Jo& =擀ALj˔G2DnkjZer}u͔=^K (zP 02R#'ge(o> ެv'RcSa/{?,=x =E vؗ(s3)o?  UOT"#cV-go8C]p VF!WZI{2r\T isͱ%[F nhbPgޚ1Y3U3g E2"SrTVۊZ]|vCG+ ڵ$O`a\d4(*)?5b&y`^/nբ>:+r (p>7|Kk?nX=o.Ht1U{ꎯo,츄2e"'T8mkє%96fщ~XfYXg516h%q<#)whcu @ &w6n/U=;WܦP0"m;puގ:V3*jZꉋl"TfOv,wzRs 2ԓf{A | u)F=Ar%`x8gE|)Ǻ'17k'Q \1@?D&x`:0XҠ)C03_UuŪdOӹӺ~[D,$NLI%_X#Z`Ćq:M%܌p3WRؔ=&l羭;{9-垙F ޶Y%B.fg!P]D2:)uj2¿bQUe/t 1Dy'R>'ۦqWXReRhՋ~~'ϣ5 uӤy蹯[NCZMܣWo}hԇ5e7Ӓ72Gx|49uVt#ʸYR wD[Wρrھ6AEy/ ]hN],|ΧOVǖV8Zncc͒Z2)|?Kh?%k@x.<>DŽ5gBOrE4w\oVf={Re ;Άq>K;R͈Jn` ?-$lhS4w`*8Lڬ䝻i *ݭs"}Քec+rh=ϗs!/rӬ_J 9IOgL;mp%Pyl' Dl+68n#$l xLVWԻkrʈ;}uIrUn0'g 7Ptr `LwLr%!kԌEsq 6%/pN=>,z&FRUP.Eϊs'M1T#=+Esjr8S%"eUa 8B.g^ :w_^\ptv'(9$W,rOp Z'\bh7=!:O*,C%s*g,L21S4|Ml%Bsʫ)ܲ_`*8v?yDó1TS#8|0Ƥ %1|өŋmU-\0T62fSV7=i8"20遹֠1fΊI q%fL2+PU<0ERat2u|E@JNA83VH5h<GEva ;$twiAw'QEACucʃ; Ìs3?@}l8bvRy^2de[Z %JC.snŹ]3`T?W42b=UHSӯ7֗7[ycx&6apάVqŝA`*!ZJ@y,fw?f2kҵPtܑTOEl3FoG3Һt؃rV,h+'{wr%<=U`ܯ)1hR)셶H0)nh)o}WW.b+e|L0KU EuBY[|t?>2*9Z$J~\]e SfYy2TH pm/^w^v_~2 (0M 7](9he@*33UuL U=p+pEN)Q&>k!:ޜ1ڑ O1)<F1bY"ԭC *kT4uCC~.c^Rf|& &/_1T29X@S[|6~EVL CkF<-<~M,:Bʜs5 <֯9Ij=¼ǧ}WVb6Ǵs]] DWOgoQ.SB K` nC<9֓7`0[3> vORaVɠ-[4>f]˗X{MtX٧sfJ4˶M5Tl@v;qţֺ9ɝ"Z ܋ܚ: b.Ƞbi}#E0CZ,9 }дshb"It|$WS:0, _+p 5_x~@MQ@D0R==9]wNsIL3xIKH=XX@C H1m gsb^+i%OJ-e sʻo䯮ꣂe?mk]7laP~18nz6"zƺ"J Ff/h^2b`DE+:cY.s(&zrG-ޥtM(D(TēgzpIb^xNe= @ ŠCZʤ*ָ }(J"Pg\<;w+_+e8R P *Fl.wPETgB|TSKC2\La<*Y<ږ<?d @& ǩqnâ Θ&Ġ??M>mcJ#mzm{;rMp˫~=צ9?v 0+5WI~;tU  ?T3w0vS|pvaenvgbwq]xl:;[beMJ[0; ylP~]jS@2FȒ!YvWc1,'-&nVvcU1T4M-7< 0vڳ|7WJ53YIXwLˣa8`WCT˛]wt%rI3ן\epwk{}> ȏ r aYVyp)'zgI;<؁ SخxYELFjo0ܐ o GJO96MG,CKV=gmXA%1Rti[7}U}'t/kG\ Yfj8%۪ fI-,!pSBiޘ|(]V {mI]xUMQo X73R690DݧsYs5 wyispR_+X3w1m̜`[Zg;SNybpzۄo 2? NY;H(޵~I"D ag_-`tiJTTnٰkH]CClw-A 넠JLm#586O'LزZ:J 2 <ݢ#iȷSm 30~DJ4{R~{|UO#pzpaW ]{R7p \Sn!%]ӨyN|s!j>D\ux;_NE.ж=U.(<.?k["d?,=V2cOVl)2U.}2A_ͳ~{cvڛ͉ks&A$c)]h}I >$" 91^JG0kL^c6 ,۾P%;" 6gsމ{ w37;߯Jվ-?FG!x+E bKVa pj-T/=T 1F3AÛ&/pO};~(ieIڻL}v~j {3_$$Q*0m"V(UD<ޭ*\Nmzi=~Έ0yacO80;]@{ qԌBAR5HS >b4E୒Q;KJG@P~}>_?=Jt!: !i-a &!}Սf#2_ЭsA=͛K  ͍"t2);ZYC,3E.`2 {(؍BiOْP w)-C#Nr˳@2o>!v<v"Tfk+p}w&RtCa],ͅAlMLݑh}Hgb浘mGCXxo>_xXk >!;\xPtTB+(L p%k7BVkw9O:ehu D*O貏םᰶc%1?@j}` 48; +|k bBsKe j՟ n=PDǟbLV@sLΠDʗ(`>Ƞ} i~T K( I_6ō+mAM4QN mӡ˪O j|A.h.ŗ>,~;Aly_J ƁX?JJ zD \tVs5[c=Љf'3xdb R$ _qgڟÉÛemܷ0ņu5O~ӎMΧvp5IpqSBMT5 94¶`48ohT>l= re< Pu2۔5ř59` :OTB3H&0d>jTT/Okޜ7Bz)lUL9Mф(J=bPx5[Q<_C  A23h$F’UE;z];΅pKp+ԟh1 t5`9߹zb3/ᆳJ2"dxijhf !A6SMk:?(7E>{EDzX=_V'zCҀѨ5ֺ)ڧ[!Cʄ}R Q$LJH;Np&32g! 7-\zwJ_V#.VP&k5J徎9hGkҲ|j]$WbQι{ @VFB-k0(5rd )fa@(CJ?^:)#>QlϪcQ&O.]L,SX{ HoE4s6ț( 5{(J\&aޕ <&MUt={ں nd͋R-95Ftq'P^NM*dl-"hWtKs;8hEH,֎7R: >~ԪCi<2o:爼 Ө`YrZ,=>jmk(c_y\ႎNe-~ߴʬ 8Jghw;a! E@^S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPIV<:,4рl2FWA(R|-@:l8*/gJTk?u"40hRC[2ԴXO{sTdwBbȠG2I?|:> G9eHGs ]:TwK| )I&<$8Wv0T_J!RRQI^[Bgm/0瓠'?jZ. W@w̬6fCR]Áao֙4DtoeYzl%{j5.Nh(RcKȄerƂsA畦.KE_M/C=&'w MӺPڽ).]bP|%Hxۣ\%,1 ŕ)M+wϭT܅֕_>/$&x$@BK$W*j+'⃷}iPtLDg˭ @-I^J.&F=o),R$ #2y$J$:o{xpͨ詤<4ٰr0yŲ17:q_lYzl;1_JD7f&(6&iʄ!. H>|*̏ 5ݳn6QHb'bk/Q\d`,Iƒ/gJ9]Wg5tf:]Xl7 FIHyLd nk$yxz8ӂW,migye*x tZ,>QHFDkęrn3(CMIUxFCS7 UQ[;K98,ǭSIΧ?Y->`{z .ǘz-* ]Qv.HBr.fī"US_}Ljtb}f]y7}"}kd,n ة?&~iNdӀk<\p؈ Uc ǩ9<'і9r˛R!l.;|d(R#j…ˢV[ x`^I ގG9EԘjDօry[[:3@iO73_?E>Lg\zuJO{3)C⤽iTV EB5*5nL+@ _:bsF` y'`C(ԏ߇PrlǰϷRL 2GX[TtAQ#52uh#$GZEVW uߟKkN!'ޛ '̚Ρ&=ךּ(wz%C/ƾ|LSfы{dW͗(>”r1sz/|E VACAKvU$F2Js2dfeP"P.NLSr|qI^^b;EPiZ#3FZRKx%L%t3=͠B#j.#f%_IyDa^uE:lLjT;'olO_\Y+C}KrpulV߾x5 j5["4ZVw~cBUE<gGc 97o&kɪYqb"j{Re0646/{҇KIi:6N[bA#O5 ?Gƫ͛_Ro[$c࣌G kJ ^sJ)}9OmdB"mtd2z8Ko6"6'JE}|p?p(O!-Oǽx1Zu1C-Ed%A52;,z/IBGe'8WlX"=;kaۚWVpG-!}FkfQ\nb$w 73FWv(!Uwl Q"sv Ђe d]?fok!ySJ ml^%w݋UɅApB1hÅ%Js_3L),fK=o@mb?tOasUG(̺h[8R:ܾ?Dލ`Ӻi7Kef+G6ݝZ{txDF,a&lv\tKMbEIz(&'r;;i%;ĎIY9EQ8ı UA1SZ[}Fg&yqOQrO*rz@pC1+L CIݱ/XX$C{Kՠ31[wKaw?ya֮͘2ev}Jme+hk(b c}@#1.Qt@]jI~/n"|T%-/=moWA[t ?Mu&lZ{KHWt<jݪ*7sz4 x3Xaz˞' 5-Ժf$ΡtmB7`}D ?V1#/^Y)NtԬzRח܊[5M_ !nާ[뻎B 2e0 9r6KHv5C>k9VK)X25 NGԒ~ݚgI[L45 lpǵs4nʑk(zݳ*5}%YfHBZ?W3?5d!Eu G$g2%]q4w+g'~f:ca݂==O b77>;7cbWn8y&ql3Б| rgаV$_ h* ~\pi9F1ZSRxi,H=wsj2Ϡ+*7@Gi ؔYmd5UbV )l;{ȏg#,b'÷יoU6OSw&u[vS ;Tb8c迣C(۱qCUB\ (+h-6D%|O=f樒[8z4V7*MiQ++.xRob RG zX33{dG?K^ c2 q4Fۓ559$Y)qhڦ~>_3 k{>AUg1*!yW k^@icvZiQ-W74ШgMZ;i`|Ӌ}C+%I4tԳd:uI cv_1CCn*7j8S9r?\@nU >pe¯<PZ2pi|HpBWTqX&Qp[ j s.\0_%rYoDc(=8Qa72uQ73?+L(oQ/ `.-`kQ {r}7pٱ^⇩l|^^CAMHLFj{v`XkT~jr~"/3Q =顂v S4; ,\SXUcF,r/ԙ E@5yӰ(XΪ~>pcQa|`U]S>Gڡ. 6, e K?'f-kTr pf)kdvi&Gul h>2x~FU䬛<Mwh'Bq.qp(S{0PiT6k+sk{fx<-93 rE 2{ QE~O@3Ej-@ESrZ9*O{JՌg\qtE*g+||M!!BS0$(`q[4/+ '+AjhdP)w|CO5/8zguzgK-?3qglK{'˺FHUp˸8D)KM@(H6t,8[vH(,Ʀqa%'x`KzBZ8vGn: P]Mwh̥Ӑ %%QSxbw֕M! @S*m+fMyB3,BppyOVxwjx6ͭ6=BL5^+bcj&D/8A|x"n" kA^f8oM)x2NZNL4ѓi5-K rPx('D* \re;?0sy6 `&Zf̑9Aq &hc<)kZչ07&BM/ ޔH{`^i{Xgql;÷&$飾M Ct {4BQno"Bc0դvw߫:eai]U>Gb/nzДJt#n~q27e{wQ=[\Sqߍ\@$xV=L?Uc"mBCҋ l<*% s#kDoK㴋exc) pUrc k1! ;-؁("ߑeJV7Pγ$h ocہdzzR<܃}IF9kGH)3)$IƁ<8ۦAH[$ruL>< lNLTXadrvV7 |Yi^(̂ B`p@'ĒǓ܀t6'E>"#QP }58>%{5d|LK_i ۦ7T~ח967C0]Fvq*'xǺVrӞG̓x8VwS@T695K&R,OQbz[Fϓw8xxP퓏? F|/#z.|0>4pk_u㰬 FvY8F9N$*sTbG(_DfDzNBf(!urnu(| {;2g|dB@|wQ`}IJ{Sf)M$0O L樏ҕ-I(,5[<>lȸmb_}x]h&I1jqb9YlÆ,3܇#6˖!{CJvcfrr@]xR@so\U]rt;B"y-9L"T-s}gdC\K߆}_bVCNpCܟgPe 9uȨ&YAw1a%{ XlVY*+^>S]>IK-8VPz)Ykt.Ajݫ_uweҞţ[[Jn'@{4{E^1P!N8Սq{Qc2Q#j({T]Ϻ ྺKlKɸ*,w0$w/- q3đö9+kG00g kWTۚdN@R f/Q$X?O?Vo[|{:jX},jR+amLuC¦*e ^Å\5!XIU9SF-V|clp jQ eb9m5A9/SֳLGV^ei1M;ICQ蝃KtAb,3Sj<kֻ@Ny#E "y NFhpH=:*~U!ek S6=P|#QS̅H|B-~sgƭĘQĺ kqRRXݩQVArH! :F!ų0W)[ӧ"m`ϟS=-(HzQK8trf\?n浕|<%B"03\;L'㕟hOm".u;t?ctUi e 3o6A}mvell_oIQYB~X=ԇIu=l_\p&,D]MQ0# Zpݲ0k6璤bJ9='9  Ep'f{4V5zRDI6/e.qZbXZn4=/e\3r *[BLJOo]tB;`8e"ɖxt{9.ͫZz+Q'4){tbt7L@0GsB]`@ nCz?/OLk0FGmTxuIpA.l/9Zu>z `#x h1amTN8 zeVnnRm(49[YjD|WaLTWbE HZvŬHDS4+aϦa IgJ<汖\rXPBJԕ -D0 > zh>K[0oWyHUʺtC^qlaYt;D?V^CԇK?q:Vm(/E g Ͷ,sLt)usOa3j5M,Y[Iuݰ)a|ʩAd[j<@oҚu>cIkb!9K/0̿^7nZhY풄$》\L'2_dZ-R Kyٰ'Cⓩy&?!1?CƄa j \wUDo0^? w QdOMpR{O4stIWz_;=\g%咐?U"\ آ,& ࢾTͺ/ :]OCEUpn N!fgnGYft٢I ϵwf7a|цr^Em38 닏\pHTfx X:݃¬Ƶ_0ʮٖ:`W5..0#%Wf_cdGuyww.~j0T5B@Kմ iHr84^M3>)}ra9䱗*j K= 8]M8}\hQXS/+.ٜ :\U)Fh$ʩERy@z˟#:L-9a 5J4k/%ul$,fhK\^ [(OD jdBu9+B%]"K@iA1`<<Ԩ)a۽D7r΀paĠ7})LFtq^uxo,9h~K%ǀAZKh!8p &ىtI+J[x+-MZVK'#:#0` VIp%6v6#Ng7 ?j7Æ=䐐cQ( puЦ6˧zQoLn#-Q% >qo gkbIdLWlna^ w F˙.F]h 2WI-${t]"O!>ͷ^×fl ͡(|5TMaN^yqfd"_($`aѵn]!m5Ǻ-&[Ki+֛ܧP\ץٙ=ql*J{ZykU_㲹E}?0;÷}iK"vU "6OhEwXܝSv;G>Jf0%*PۼD[iŇT!6mD F!IU$WnZ(Wƨg.(TmLYq!+Vnvn +G5B 0wLs!{i{{qϑxMWa q6S+D)3mRu3{3@/8fJuexߔfHIB4 LEfz$U@.=-z4O P@[й<`63'2Z'QuxO0 q1H(vܮ,$9 ơaQ$p-IM z-=cf u}SRZyҺg$bmIBKN1hg;4v77ܨvkl&%uܐ`[fI"wȒ])Kcx9flMxw d߯jx+WzY07{؀9fm 22S#yѦ9kaH⛷ɮjXjf]_vxQsĞb<<<rǍh`'"̙UH*[;=-cr()X/+OS3];M?y}rw& Wv΄Oy$(LO#C ~?]s @5ܻiZ *AwFb+~l]} |Uz29 ?||@|b@pMgpW8P^o@|iUkVTEŬݯSm ha1/] M=1݅! ! v5pUgr ~3& y 3֞ L*D˜h#e8uCA0$u). j3%Cafe +޺_^]ѓ#Ynl-#ρ"V#t̻]//}~J+D~!b&B+>Ѭ '5;1A7pAr=j1gNly4~c L[}b_#Cx?==0N0iCePv%y_}bbI-b],au*. g=ƴKb`}4-\fwLX̭sS5 ͡|kx)?_Kw;/Z"3ŃLilmy!+n>p+Q9#l-GƁ xa$5>&* )HDB9ڞp}XKd߅XznKwۋ>V|m/0dq&͟Jً0՗Cs=D®y)>1I 0oCf:^+v=~[ܻ5irvW0(<,gyp/: @?\K'.xL9JW~V;`q~"R: [M5]))77R-4>Xj |Yaof#6Vx<Ͱ+' Ll(T2zPvpZ][ql{EhWS A.XmqJu%hܚ7klVk"~ `DE1R uEʽ}UFBR6݊H21pP@T8Ĭ?Wl׌p tK$#:.@s:n zy J~NNoT^&ϵ4BZ؈UUu }EZGLz%g-R|\&kѠ S4A<)Pbuc*dڽGxϝN 5CFM@v).._[>t4PV鱨>Lz.̹ʕncHu& Gm 4&*Œ *WVLS4EX[JScqJHZ}4Yx&}Uz8׉vU E"X'#qUP">O:IDD- x6-)Ö e2 egce$ZA/'.ݐrr<9j\A˚YpӲ@*8ڤl{@6W%5OÃ>FjE}_-mT:-rUP iu(*ER[[$ř3֚Q2G:Z94iMH'm>&WM&<;\9gpffKXV)ΰtt܋#<4oݡ?Q ٵ5UVj=ʃ<@b%%_2^(W`o :H$Dtg\߄c{+jfkb+w)1teWGu8Pv9r> `·4A{ְfat}"(,!$}j+/O?P[arن@WW#]L(GBlXޝaj‹@ÏrA|4%oa&21I #qnEə?N\1U"3)xs;{\OG(ǕT$t 3l.ԣ춺azS:[[msV6eJ2Y P m R~ H8K""UQH JHAprvoqj,zOql̶ 1k.뽅օ$RSE fs09o=]s[4gj:.QLAdKHf_MV7'3#R3)E9z3z݂݇d^хU_*E W87h3<*m/OL̄YNy,oʘ(˼x9F3#ƒQBN$'t7F=9AWb 4TWf|(A;B'* Agj"rԁ9GyBV_Qp{WD֍_6uȍ_#16ϝIT"wӏ#&VdKd,`A=T20{Л:-KCQ!buX3rs>[϶}SoKcɻ |=8Vm ':zQ6d8#*ԿbuEj!k4 K՘7jzE4'ܛvLSRuPuVo)@Inj4Y.w3Y)ֹ٦ 9<ŷe>@תkx3j&8$!ϢSE|P ?ٺafs+W뱐܍ꊸj]]MË|{㙔* (5bͲg}Xƫ&Yg&(e׸y>*F +& *Xe@CP\+E)/+&Ȃ0,++ATnzOd89Re4,Z'ײL^7NcH]9,?g @O5`Ɗ)tZXQ_A uN?  &|eZ˰ЈJx]i`>Fjp ~㷰Yxsj?,~0¯~挳ìF;b,[ʖ;. ׆~1LV  kON5kV܂L͐oTQ*CNAvN<~ s0Kg,T\@a<> R^,=91d"MyHЯ' 4|5s)*d׉Tt@T8;?oRjDbmܒC=I};|n,s'/RFDȜrԠ]0Bf Snk~5d7}Zic~,yomk tU4a5k HHDcBSƄ-vjaCTT V_yH[[~DNJ g6cx:']#5z+Loj8oRת*ە\iނ(n̾L Mke o^%[@,\/B 3t.]ne{j!ݑRRwphU WWDZ᪃&W ]1l8 .KZ.nZɚSNBk3Yr F$Vݰd=,{<(ϫ5 *^g{;HXG ox1c6\ֈ;LhER@7DZEʇ<,?=`ڈh~1o| hՀOnݻ+_"ug']k椐Z!qhIRW^dnP.5vdi-g}H.ʠ ϩ3s_p~*[ϵG _"6Vi9׋(ߐq/:|3}uR}+ScG"b1r$|:Ʌggg(Dd 5 7a[}S <ԭ?%,,Pmj.6N-f6 .fMX$fV^[Jxh(fFU`>߬SYPŬj IJ2&xW"?%d>յPev.ʠ\r knQI,YL _YSEOE4 !uѬnxec|:`;<7ȐfdB(G=%Y2UC'tEb.g0 bxh{Txs+6@^ao"qk 7/[H'ZL72 4ҭe]*ҸA]>9k!@1 qsHQ jgXu2:3># (l5Fv`upeMi(gZ`ɖPړ"GK,, MS䇬\1XM^Q"C!lZs҈y#)!09V m yUt#>vT5nҦM~N` ۛK]fr_ )*pͷ, P0hgy. ^)"yшA@l('6O5>А!uS^Ԉ]Ie7ߠݿ #Ly fʎ'%j߀:ںaGsa_V5fy.f/I6_TTj(=)fەh\je5|>Hi9{r\LC8hF8pU(˿i?W,v)=9VZ`s9Re2shs?sIC$ENyϤ`WuS!@WQ[Q̉t{|; ç|w_d\+_&~Z1>Igٔ_~1ֹuzC8e9~`zbe{DBxF7^X#0PMkgE7e]i3#СqS_*ʨʕz W$DwȟuّGL6)xr;K?ZYofJ 2kˍ[ Z5AtBcC@Ϛo*y\r_|L.Iw K|j<4/uZ֢C@[v~{w4_S_R&)l+WI0C%^?zN0PD6<r_,ftL+)2E:<7q>-F jm3?T萹%X$*}Q1a>o]l@ݤ{e%_> k?%nF@ 1[%J AJHE% :(bImu ,#d-doЪfMq|L oi1##vsh=^gU/3dplfcI[AsuUE2X(pUW`fH 3hIO&Oe(ݯ_ߠzBÙ<)poHd'PӱNP*e⼂q|vC(@b!qT?ԈyѪzڝ1.CɃoQy#E D4<}%=_!7oiT K3 x&&l!FM8:åʆ1Iڠv`[1Բ۵IJ[^0/Ҁ0hyR ug lǷWU7˜A; q7̑G7Z[u 7㛴^ҶZJP:|}Y1Eŵ0z :?(e !Q9!znw}qcy4QrbK6![X]ޭHKItӃÚ-xFg [d#j榋Y ߚESN?pe/j87ñh17"tںV(.3uSzNH࿬(חhUʶi az`1OP;D-Ʉvˆ~̧3 $u:~e yI!-&DA5Kզ оPΆf']+.75Nf)+#[}3c|^DR##._HaOOU%7 b#gzI3urEҧ^=Ȑ("&bWX-+OlYQ, 7&ɴ1=ԙLAYVHcJ\yNLK+ !blF]x'k❇Ff wސ{g, K=̿)֧gp1C(y؅)^f,\|C=3iCȊI-0\ߝf>CiŠV?1]\ɕau1GmhU}g=gyTLGps*z^okyDRC@#<B{6#ѬNOW;|BUnkUx$ZLOd9̩vȃ&W{(pK_KAi-ѝ#[~\%Zbm\]H}AK1=㮄ěUP2 F61btLzqa1$:4RyezLs`S7_:ai ̹H}zL$b%ƲauY~uw_'eK0}09;g W.:^q#=6x2Y4ڴhqL֩< "?#,qxk!ⅱBKLW"/,Vzj >t*mXjTj׏}hAQQfhJjH(qA٣0׾ =#R5]»Ƽlsh=b4,J#Z-o'5 Q2>> $ (Ԓ."ѿceoKD)^<,-Êל!}67Mw>HFTRA`}(0f>CQm"D!^%U;M͆GQ dr;.pZluKYxT00#[{yBB*'.iGw?y; z -FIV@1C6$FMh),9HrF @"'a{88fݷISƑ@z ȦUzn d88c[FSzgA%Vr΢ ^YjLq?LQ>B:J6(W tTDˈxXOD(bI ]U6*kKA~"SUrVҒDkF7ٔSc 'AӇN .uTq=a '# K*h.%b BeL_?,@&qP ]:Q(>z8gʐGbUZ qpQu&"j셢Q(tydF ޿GĄUwD i掅H %w%/]@5C ky]0' :g=#"#qPt"lyfm,h24g~nô ]5-V= 3-f 0L2  y .b!rpŝ u-^${&?F\.y;r=0dVM!, .7Kw_>.9x\~:9r>_.V MJL3"k` HHh ` dB+GƤ~cI%+pֶ PsS N4"yQn[s) IecQ HT<<9GluhF)VZ ]m"fxap]rMkNpZ'ڰ.p3\إzn6qC1Y'RH카_NR`nDz֦@y.}lO$@^1]fw+ؓw M@&e+E܀8vyH !x#.J}|Acp笻"[R! S0_BtaxOG`05cSg<a L4Nc/gwM_ P#?W))Oa1MCxujdXC u(I1+2xwEn*KMV6ΦDK!и} 9$Q%"c'W9JvtŸUks#Y ]@znLfUZ^Np+YykQpਓ:K' 1\{szkގYc{Nd?Ze=I͛cL83ЈhR{\fm->f WVjc#V9ɀ[T<"ƚ/7۝}ǜAtQZ\p0^m25+:I {+# ~Bc:pQWM\NLdihT;j#U|"`m-ZZ-4 TT;Lp^S瓤sXloG64WO(Ş_{ .0LЦpj+=iXwNTv(k%ӆOie3F!&aiģ ܭ=w֚MHN20J.eġ hi4n%΀$j) v[ I3@B ]≠?W1mkn#?PD)HSK<@ ΌFr Sy; 8LC~^#aubslbF.=}ꢄʆFMswנKc(e弱`'&+cKENT/t_3S2Obl+fC~ DlGM=,dQʓ~SLt~24;dE]^\% *nPtaObvKjl~3"iX$Z">-sW"} ,R8BpĶS9[# 'n`ִ&1ij%h!Zl u[ީ Vl\ٝ lqaNMMD**Ј5X]7?@\l4qm 6CZ 땺Q7-Z= 7ǜ_3QAQg?w7}B1w u0ػ |Nvo Dxn!!7!,~@ Q)ynxP6$H ,Su Tj\mA9Rt4tkW:~|@|@> *ZM'߼c.z@|00,])j]*/Sg/5ryQp傥Dﰅ GH}+W}?X 7MB4K%ݕk}P;Ѥ)3EP>;Ǡ fJzw&F;7KbQ@s=aAHy%]#JgӴ7[zEiء珛YJF-HY[ytioɀTZ:z`gV\r3cc=k?zqt}oEDP)vը.ϕa{dV@|Y/ȩ3(dQ[#&,VݿM?T嵜xL6M2_:A!% %1o<5g-K|}UQso~h?n%N'ti^XLZ<]]٭ߑU N9+}8uJ]hv|>}~sf/Wy^>.4Km G什gdHN|4 ɥق%Z(GPOpVx(5:3ilM8cӒyZˏ|) @/!w  )»J? #>2 +Td_*$Bʏk-PĕVI{3/>{cvFݠyQ6_1=K\ٲ#?IAA1y/'>e!=5ɑ+8n]XM:1GYQ D'Wew lxS,q=^ ΓYc4iTObZCԎ :6h "E7SBXmwA [%ݻZRqqЯzi2X49<4z?PF7@aX**ǯ?.u/ê~p?.v~༎4YFŁ1W.e@f@~H*sꂫ!d۶f=^d 3ԵSej`֍SKeR 3nO+ꔸļ 2֫-L\bցV=&+ ߳iƭ4]kϨ왣l!w@w&"0a1]&i޹$Ӡw(,y7жj%-d@$ Ib[jXq=LK1ҒJh"fM3PM cgN`O@%OQJnXݽv\}7@}o%\ -D2NEd&@% WNKf>/]ص+ť5OeBR}!"`)ZAnvb i- Q";u fٛ?0onAnd}]au5 ws1, 3?BGwD]ɤ&/rŽ7&ouΪEwJ{~.cRW/sژYBV3 ۔Ţ+K"~:@px|i''BIk+$uZSb*OL™B3/s( /{G䁒Q[-q/@\kUHИr/%gx$ F #f ԕwI_m\Al#o{{G_u""wzy+%rgbO~N:N0-MF?EhWPY6qu6&tCxlKm[9%fZ$|֓/'<e({N} G?6KD<+^ ԏg%bvȱP^ZB}+68RZ[~SX2P ,AtÜ5(f#M+w,/u.J0ƛ|֌*K.f(?jmJn- 6=zwJ" VXAƲy4FB߉*Lk7d1yW1YD k')^`Öm9 գd? ag%DMCD]Jg iY[\h_7㠎?gzy K3}CF([Al, |ԖLk-n9~@ʵGťbPFܷNwRv͍z@% jC:eW]bMBZ|TiZB\s<+& ҵiJ"juο *xq,"'3u?'/;yb榙b #W- +uQ; I|JpVBD:TT0vR='wBta;R> (푖᠝v.vw`;$fNAsnV$3xcxzzK [`T1vd2l??vE|9Wɛnon_kޔCA".޾x p;PV*6 ZG:"@2 4}Q@tϮo@!e rT^}rm|_"4X̤. R$ >/rrjD .|9ZGtqRTS'{_`Ob%5G =7{1= KIKFn's0R9K&pl2vpW7&,+x,]iM_9*s2"U_N>2>'5rd9D01<5:Ҍ1~'0BT'!ERhqeSGf0n%^dh|oCi|@|@|b"W7fǫ`Oj!! r>`?@6b]M=DoA! %XY\8z.ٝdbV%"6վ Lw[/BOJvnrjh0L `a!mMt_|ͣ)z_Dhln#>|He&1e3M`t65KǃM,i*9JO>n *1Ȫ>Gh[@-vEIgM`JC$X{<͋P`44 &^Yb;(X rHcԝƸYݫ%KdBjp6SgM)ϣ)4Z5]_lܝ>Sלk<yWT'~ ?$Col`4}c|y_9$qa1,;1EZrw/؄ƍ!)_h`\ l%|lT:FY9wtnʹjyzI |>@=zR=n Ҫp=K Z"Aa*ZwHYI]thn':CUI_I:=r v9]UXQn|2` B@NxFytp9)@*9?@PEx.ƁۅwikCK¾=[+d}Js wUO;VP+ȁkhhRF" Ѭhϙςg.gfOZ 3Q@*Vblf% \Yh)@̙H9~W&BaT] Moi >7³Tf9ׁ>Or&8+{ϰLH'oMQ#S!0r ޕFw9~wJ\ BmXg <5Xѷ3K ƦqHooya%կ8DTZ_Ǥc⎡3Ќuf."z_[ȼȯDҰNSzMYδPgQŤIK!֙EoLV; .F 3q~vE/9#Vc d*~JUÅ{aC~FS equ<ՔROǂ{AA4ʢ$͟X½L+\RU)E*O8LL-y"Xd*o] JaP>!uKnr%Q*b sLp%v0yKi亿hXL+Ԋ'`1F(f1dDۻ,1(A 0tA4VA3;Qm4z}n{m +Yq:*OU'j*&jR&bQV4%ȊoI_;&樅)7显e x=P4FaE!xv+&ȻdM~U9,dF(D WiPQqG=}VZ*Fg-?1ehY+F;k{=c"ɑe[VwXהTR~ӕGԸiݥWZsуX`ª UIˢs5فz ;">Uw@B' kJ+*N}3vam_70WWP ~,s%) *AMgƏ:uy- #cQ~ lyݔˉRf|P@ucXˈݗI֊r|o+ę2TKt!8h53Y"T(ilϒ/y,O'|u ! &$C~YpIFH*-0B|C!W"75/C'ψCu#ɺ@.Ǵɺ6w%5 NWĬ)01U,j;d jb^DHS-f4.]ZO! <DgR(\JВ Z%X)17t=o!1%0HŘl]s?Ksű3(2pGz^7nE%:^Bj$R47`E$"&x xԮ6yu@ExsG310uhZA[B1LAPw&ھc?un` ne: TK ;|spOi@>0OۡB{~_ŢiJ 1tBv!VI~Kb$בo5ۿj6hA)y1k$Is]*^ TTLAɄdj2J9Cۢl)gid.j2G!dV beV+\gE,$v"KkGU(1jWA$3fߍ@>=iΏpfC& CoekQ`/]h{L?'; Ț.bbؙl$喑}5qDy?׹ wV3 !L} RYy]+ZE6'^ˤThYDr8Ҝe\gG_9RAL&V|oud7[iu|SuT-RȠWjCiiO V|8 4!,&>#3>{bw^sH ;ݯ[aBN_@ID?@M}m`YLxc"@W7iHe ;o"vX@5=ЬJn$ӕxcCoE_Dɇ2Owo{IT*؊Mj^@ s.~ܯ ?&x:Q=>#*֎Ŗ L-a=?orПHVˑԢ=/I8> o ԛ!bGX RHJ&r0`98{6}Qё8F( hd;@ByيoLo@ Oku 8BqH@ǣ>1>UiTLss?H=D%5:$#L(hlj$C&=? Y&d9hz-;˶\X!3Cd5U(ĦDcJm?űL;;oO`XfN.1nIOA=qevN,R@XHiLC9O7͙#eGs\gϕQedM',RGv.Uy 20i`Ne 8rzV5Ưd { ~FW?_֬ {|ηJR{7^X`8gOgo>"%vhY0>0q=\q>dP]2&}ter_ed.[*o̴$=2y:4䯰ˉ0| >ːY 242tԷM gAX6N " [Rٖ[e1B?P o,k5}2 s'[T@=lq+U1.pn*]!F[{Op稂{Pvы=kz7xvz>Q L/l H ;t9zBQj*_p@y{j}klG7߻~m~ ~*'A貳֍sBvnTRbOP:?Q rF쀫gZ:q]-IC=H6%]JFk^a뒇WIY?m-W:V}1 Jw:NCȥ&:笕x+L})(Xe˅=\_uuW4|roOd#**:`'GgH?R]ubސ;ajdl1; z0]'p~Ӧ\Pcfݚ+M REyc/v. ڂbQLf3d` e~%} VԑkM5LFHdѳ93- Le—,DC$ĶpE7cC].tu{)Xp61ewv/X@Uef2uD4+v@yǛߟHj5Ts-_> _ }_ &V?1̤JζB$@]`!Zi[.'{ʝ?\8"bz c,q<Ǎ.jC~ LXE@88){d8{Jl|>:$kap.`8z8%8džx8:8w3}#4QXᕗg!@ ;neB TJ,`C9x f%H)o&P9Y(1&@J5GHzn"dsq)88t"y@l<Ѕ`9kغ1oӓ5r3cʍ!!J?ª"mG/m1ʧtjVHցأ^4Z4%>[To8JN\U%^%Zau}.)LIMNo ܌oG[(Ÿ5N_ E<0,[KPD /cc^0[NDrÞ,<lL6k5b^OM^ڻAIn"v9Uq T:"B:rf//'K0rJЕ ^ HHO=Oe0@Aa NQB@"evr-jc1.{t<Zqȅ\@2fah8 pC$+{wAaeC,_ Q{D-^mEiA!0#x g~k]iX8u=$3&0j9q2`0I/HvA4^̳Rsc12UB6 w},)8cyH*.$ISR5bPsOHXB<q4n|&|w}zwdI;St5dE3h3{xhӄ1\D薲7UbWE:!77T• ux@2);g<.rp@1BA|\k<՘dc/4m_3g!Uiju0O%% YVKq]3[xA% z/Y8;؍R'+9 6ZrgrshR'w-16ic )l+`oavCeT:}dH+[/Y9[]VHᶗ =1x- c!X~r˟4s};sZpBh!Zg^_yMnd7 TXO4, w3+ڨHd lwI6)F <_`v?Cg_u֮GEJ %>?ޱ%j}4eE^5Z6QQ{!3tD r*ofݽa2+# 8﷣2tۖnK'et`2f? [*ZbmѺ pQ>IՓkvKӡ~hjͪ v >[>TJ('t~*_7q܏Y5VK [znOAZ杁5!lZuhrHP27(zHxMyx5Oy A `^F(.|)9L-%)qZhUu;SIN{lnd,=)B)ܿGvdˋX/*N:'٪ 56(|8'hܡV@[.pf w˭/B0꯾c؍8:_Gf$KC|  ]0HW=6jR]=Ɵ0Xs>i(SԐ9ŧQhzRǺ4!g vg`1ʍX#P}b[b@Pڇ )SB |Bhc̺SH{ i2@P  xԈYTZK3=>sY_J$Y 6`^.s5KBu(MJݥ{@A"| ῿ց/72b ~ 2h\F}c I. AMס,@Y~Kx&\&)Rɡ[=K)Iy]$ 83 ̋f8Նbuʝ qhg."ǪTSNc2Y}֢|,c^5j3=|p\NN1FJSkeA1hW*%Xu<$plu%ZQrtjyA{SN2\} >EQS^~{"ړ 0 ( &L/: Յ Zgf[8كN`ŗwwI3'Oi7dOlXBtO (s]<auB( {)NZ؃Idm]NE4<;fqI#fӫ|"7F99x:oWUwAR>Mq୑c% ^I; bW߉f%s^VJ[mȥ7%uX1*z29:>,,9R=@q1W_HtT>᷆Հ^7R,Ezm}]: _zN_1Q1M]OGYb{0@Ɨu1hucvIik1j`UߤE9wꎚ U8iq[a'UnF4?"A3tyL}͐: |]ľ1j(uYߋ5V!Pa9LT 鐘 $䉥'~-٘6Bs|>,,GaN i,yUhgx=ϫ}%"k|̈/;KE3dV3Uȴ| mK: UN p;Wm,ȳKW/ mChPLH9{2 Әsj}B$ÀWgm&EA37ZW7UH`aܥ{e\/u >lRI RiȰJdP܍ɮm*|YNI}k8xx@2&+g28%dµ.7P`?oƔ%8+$7Y8˨FMM;p'i(`5[NŅ {+2q\O\{P~)O%_Ӂ|; wp,`3C{ꇇNE 9wۨZ.38ӻp!n?`dS0XѿܒT,.u:NF{{'q ',i1FҊ?яmb Yt\n ٮAhC,"[)!;xģFOCwxI>V);1ILUnJ*pEMpފSHi?ۢ4կr#́]$ U38\U<{TM LVբ"zq@jҝ ?sb ƚ}BL)3iE 2KO zM'??C?OWr5 B`7bvc (; yG5WrZ,m[qHG il+dCe+F;\"TCh8l!.8k76 f`iOih}Lg61YS-zsG?Hsfr. 弪>+W?#Tn){:~n`ǤpNv%%=wfSg/Wymk\2~7߷7Fwskƒ.qгF,HA蝽M&dSLhCXv.0y}Cg^Úx?gQjc[d(xUb9AųF^c4&COo8r5wykhkLe9IU:gsIDϩBjGcCXtȏde3ɻdDrp}'/!$k=1Ѯ_Bl E=Rʨe)j"]dt=1ցQ$1SR6<B X.[$0(~B<²SY~AGRPhBiL֑#fnc:oNH2N*3ye.w-ܠU\ҎW}^Ydx_U8XR ֕gߛ5˗Pb*"?ǏL a}c43j tL垥ăۿ][$ܓc?qذLIuAw֏ .02Ego9.=yeMOl;t "v>ZV bPbŔaq[)VD^h ƴsY0pi0Y%IjS>wʱ1#ڿȫl=fX@ 'Zr-]ltR_ψ@凳։ M;ZCJ` 2<*#Q:wou.'8(IP|&TH*6pQ l\c|9|J6  2#I,١8v͡نhF]5(_>_oG#vbVB Mu/wyDͽrnYW/}䧢{r ÚB|Ƴ]$TFEb" (K @ŗ9Mf~=QwzZ*h$vhe)dtKEkqQXf<ׁ#u|wn7<ދ)=vGMIM2(N^m s\޵aε|VGYp:I+8 5'L+>FEI&7hma5G7,(iv:Gx}ULg]HVOﳾE] h#~;A6F-(oîD12js{י#m+.;Mj;W$kFEC9$hzzPժQLT+hӹæ#wDDs8erc^S<|X$ !P&ZXntƸ y~F$# +S/nkY~|a !?w P_m}8̙~xDB;9k0?zw,3d.n4=Enu] Ҥm~wAW 95#/٦nZU(bGrՋkHf5*xW|ũ[8ŘYėX4rkPK =ɺW{,<,KcBӓ\ORi*8a3e'cIؠ`31 :8vK|nTާxl_#&j%^Q:NB$Nv2 1kN:dxBQq<CDصvMSݝ%MèQy 2< <_h%y_kj H'<;=>+On" ZzMbz|J j9XP\\iY5/{10?N劣 -5 d ޱwp_K7{))N"[G`߿=(egLq+w['[gQY>Q-P$⡖T':9ŞmGQ}lT*V&}>5؀>؜rnkNISs0,-}g2ゐ:6Ièu#䷨]uR95UYo/ǧ~ jc'@@1+ '%z4?z1l!AEDR.yvn9.JЬzQGHmɿ|9Jn( g ,fb+ơv,$>^i(~XE'&B}Ir'0,͘^\S'8+\ }DX:-XaI/}P}:!B fƵ-yי#olp)E&NGnY҆;Bt@khù$$:K)C{9&{mX eX/HF&Y)/׌<#ϗFwΈiEbw5F]h}~GL`qXbdۆ|P mfyFi߸:HA {|I )j2_TŵHP&h&Q9d6Quy4m(]>BSR*h뾙zQ$j'ONL kw:y V $hQ ./zE|QcS7Ӗ{Y'XJ ㆬ>O^_8_|QTH1U,X>A2Ǔ-хV}_;EǭFT㌽1q,pfCZ&7STnYX S%[x3< \(YBQ&l~+Tlf(P43)iE74Ե-d77N A2Dإy$YUZ=$\Mӥ%X+b׳ԄAͼ;4 y![00$($yknZFpAekV'6X_'%DH y*s+ Tj(鸙,8o+뒀>zP$ vA+wp'<25bB'SWL*?SLi2& &L#y9 %rcp=)0H!VC'RyGo-:Ţ_cNS? ? Ƌ~X!w1~oŎ^zTݸf1zrho [T|9ǟj\#gXFh$ qE&@i cV6+l̻~K,Ř18™ZiF\_ $\?d'UT90A\G`ie0CGL28&+P#qc* Jt>xD|jXy  }겹 @J6;'+1T˛:ʓ=|Ft1]p8RHG.w(,fsA  ;WEA7bC!-LHX@<3*,Nؐ!z˾z?Cɀ__ Oʂ *΁O ࡰ lIL>Ka{0ݱ9 z=,8+aw !n]uLE'H҄Vg vo F / zGOvBw )%՝>\1 ˪M-N,$pBiTה^Bnb>R&zKE7_[\US/"2ٓ{M$q,~-WTT̮"n6t|oBF#Q ["Kv(5yPqe &IG*E-iǍO\+xo@(r%p}?@%K$WR~ î{K_K?z _ I*w8)} Z% ^)#,A[8}@I> 3lcd1\ ^Ugz<9'ӵb < Qe> F'Ƿ~DN)F>9_ul 1(T J8Rݖ? jR ) ) t9eʍd 93. Uޟ:nqcnMIE+xM[62Fxt%u͛K0–g>2SX?UT\+uIZww8LnW,qVvߕW}YjX&Ae#F4-JwPp)R|V[{G߱ݮRC! އ8\5&|q\Qܦq0 l]h`bFJ؛qjP,S˄FDllPXt:ߖtyӕlҁ{c.S ۀ8!$=<R sV>] Rz =@#Y6h5lVC-:"/#n4UT zx^}?]*Y/̍{OXLt58O_-JS:=|, ,myl{={ ƍkԘDhIc}{ZhsFp0N&IJAg{NHz!fn̈nl~~Dz煔6KU#bwUhe{2e9CB5x{9BkLYpBpPbD0A"p /)T1pE3Yxa{"kK\۷C Ϗ1+8hJ{VJXsR[4gr݅5Sjm =7` b:afغw Ʃ@xLPsAD?vnۺM=f7t{e.E (ֳƌ +_!i^'2-zՌvWV2>#zzݤ _}HsmH[s ^Y"[< :_:^'ڤ8Zœ+rtOhGlE[~M^_YQL<\+Gaʀ j}#< 3g_ݑ M)7_ nE+j(=x9yȈ1 w$DrԆ MɪflnjoKe!}OG+L?V~ԥHTК 5<&ǧ^E@z!/,]j1Ei1M*!gI("9iG"#Uv)]HLg7H6fbHc`nMX7k]S1Po]<;IqX.[\ד6^?5%S}~۳'ԈIh4rR76`E~wJ;;`3OR]gj4߇,r~Ϸ)-8F 6`voE5,h8nWxr|eokb`ZPͫ(] Ykeee/&^j/шRZ0c~)6o,1*jPY]VDpFn-qњ{Sy>+hU\(ʽ[d()kgiԳK8!)U im$L˜oSyaM do _zTjMgIy@G uһR [XNxA Ur!SS5G3rA5V8~iūe+ةa yS^1EM2$Ty%KTq[8V1|FF]%<Q~:Q=e&.,|vJ,1P+ɽ Z[j@a2\/? H@WS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPGhrp;Q:4@>$}sKo2 #SYo9Vf:rů@d]ȟՂ=Wlݶ$3U7տ4PGóD4WP(ջu|î|wppyn9*4hhuiFGS{M((^+$ӻ iYv&lXz0?<+ՂP0iߣQFgU?"oW_ABNr9A$e?͘GmLڒ R/lk[.VNMjV%ã֕`O@3<d\o=~<[b'-{U~̻lDd Z%v Ps*2 U}Q{{4Y62&]=b>-XC;[jɌ.=݅o9y0M|PCpW}"~fPs/cq:Kٮl*բ;=#2iu͇J? V";Ii*6g35,K[:"rUai{GϏT#ӻCھ(h/(<@LʞQ=Rq iDB־Nv%G[)[J6qmM EJ'U2{&%F%&p-Ks=8gm#ȯ~D d_e `.Up3%p2<{ɨ8YPA9=,_Xt~ 7\R/ i@cd!D>PռdqUM T)h_2+?-PI3|@s6Ai%x-:ѢC_ o(ܢk5 ~)E zz׽ )d*ˌQ=uފ[!00W9PR=;P NM!y3wxW C2 . \˾ .]ʍORsyqEx"W^y|=XULnB$XJU(LM!fS@D$wb :.xZG:tqh/[3WL>n߫?g'ܱ6 I= vOgS.%nW*NWju:}6߹}L v oH'-nd!!.M_!A ~Q'wMuuMWyH}}"]|R3$FSj(iҡM`^P{ lK}^h0x [F!11+ٻ }nd2.+&S046abuwԼAR..^qm\cbsd2:bOdcXRmʈ릢?!C$W?5P tz R#1@)]Иih u5?`x!:fUz|$#YxN(qk?fzhOnL)dwA6UkTO,jea`plc$,` ^ 6`~Ҥi+sL+H )4@xvR$0wΎ}p\7nV?E? {PH_&@WtBd*|Z!d#ұ8 *Ey7rfVX17ÆGg˟4UCi(,oktxnK!jbC 9P3¾:giY[aM]sIrMMq"|LTLh$43¦ЀLO2tNnao\2'd)mYf#'S2= ۘ_!Ntf*]y^@Dˊ8aLw}pObii[7D2KwVvBA=FtZ|2b:sϧW G5ziQbw"ij݊`sqycN HkZ{p)j?ݨ-+;,sz%Dx .tZ閄!5lU4Ǔ֯Tl#h&H0@Ew[)@B*ƵvrʑUH;FM+,ZW-bvry67LE'/0'sp6xSюڀ肘 piZ'%z(=75v9'ܝ&SgꈮBG9mr,micu CRvg) yVXZ]+hNubV#_"$x%{ϫRhJ,m X N51BFܨ5_S_݁)UiF~ s7UGw*-04Py Wul# R\k* }r"u :- u)K]|Ib uB3H۷:zvnwCVyA~)vPsuZydIWcgKGoבQćp:NrMZͤ`QOy0\%\(5O̘UUM2G"8bDx܌Nؘ){nqˋI!loY<F97vO۵[V),Q}FO룪,@yr Ņ=DO$7s- 3d3'nBDU/iV7yifn. 2^_/-My*^)ܤ\u*oV<$yяq "M&qǸDkU3817Nz,;& ۛz4N{BZSiBoX/Jg\ {ApW#DT4B]QǪ0FWx6JImEHɌ`FT)X؛lsXsRF5i2d(P튙!"߄- ,%m3wuTaB)bmXZtdհo{[D3.Ybn:HWnz T܊# [G?\ ZM,;! #0U=2F/76$| 9/cK4\noGRbG {< /Z@F|bV87R:A!Zpɺ1Lf(/Rx@W{n?O@̃iwȑwbgZE4S&4CDS*E 7 s&0g;]!Ajca~2l46dӄ3p:@GGWbsMoiS7 P_w_.1r95|c8?wŗ鞚1yipfZ(IO} 8k~ݫț˜> Vk%!ffPſVD=}mؔ_3w5 g²^[oNIu)'@¾햩7n6[>35vR\+W^1ag|&AIffǾ\$Zٽ)r%ʹF@j:B$@mW]؉u#a3jn@tpVb-4'i"WؘUk6OnxHk%h/#ڛh+MuZ8YʶA&CCJN9j"$>6 !-Etro5ko N&)$F5fѡPvŗ,/ x=κ43C"hXZ!HW@&xj. W:Jjb"I~(З0mFm k@=H$5\g-M|(%GwSDW qL4S+|lEYҞU;0<볂jW)A}k(uMNA<([%mދ$nCJ8ܡO6#[1̄d{/j2c(v,[Ly*>ELMZ5FQ'-tسȿQ"ʛ/!TzY "Wp DSg;.(,&Aa63b#%H<g -@{NWÌC-'n vD4_3n)F4G2>żn 9#6oa3a]!fN 4~<5g^imQࡄj׋/U6~5arũ43%)ح+! {OE_vJ`]>I;.m:bg^ c|@|@>W&`cD\ dP5@||j@6db(i Lnr n?6xZmhĀ/08rй d#ȸ^ߍ(Ǥ s\s/ښkrJMhP-ח|;dB|w ~ߡ'\)_O8ͿfHxnNm~GKe}s6g.G!27iP12h!F`8>av@qμ5WmPI !6JD7ZELB heT#/I zz x)և%nz8DM 1NN1i ydҢv3 l.+==9*eѫRZڂ:( :% scxeQE]KP-u UK ox:Ckfjz~Ts#*5Zi`hB2'Xc#W$׭ I5TMV|>}hVY8 ٓ>sݮ䐀Ie?@_ԧUĹ.)"U 4v@&@I]Ex('(%:P27GYgl]79HֹLw aI`K~c/9YFY\Tx6 ž h$BLBQl ry3UG{0-kߢ9{KD՝{+ _آXez]]o!Nx|+5-YT4`~55%R<)1EF_Jq e $5IMXg|h+F*-y q83y*3ڢKՒ\l,qɁjf_eMq+qTsJ~&<BY`X.[`Q {& ]gˀ޶oùSq 6s)(~@|=)ߪN.+8'|%u`p,8륉hÐӛ[ޡD׆Oga2!1]٭)'S/)sD,Z2dZV4b{xUݔXar^ g>sDWEϏܩ"%]fqم {( eH Ҵk`+۳B"E[nۣj`GrjQ}{vs'܎b]pCoW\YR <,h}itGHo!MzU:Ղgy65,l0/nBP/=Un\d BϪeo۶P(5..'z^ea#HQy Ol6_i){&ħX(6Gۺ?Zy3t/~`ShI+֓&5{{9WZW2"stBʈ\{l. '?Zą ?c"WDVς-Mh.МP~֟.@1>sO9h? {'q<.?a?{loSH n~{f7vL 7"ї3X9[R}1pswZ'eMb(yvYHɹJעB!^NԔ;gQmWJ/HD l87@z.GO!25.U͸>`b8Rb9lyZ|$Lt`gC'!}0Wkց[\M~d -)*,fo6ų# }KR_v%1}y6S;(DaCFe+yR)p"h=I6y|VRc{ ͷ9oj"<\bi0sz& y9n 11Exfn߀6tnHD=wEFz^íua;i{WtKX,}{S(&2j:[LY<ళ-/饵ұdnH'^d? g=TFz5tU`OMl or?M7֯x9$t@.Xg[c/HUķj &ZqKP+1h)`\n uܣp]81o+&Vb_FLP8$p4p!2B^xcۊRF?dCx^?P@_Fm ( y- r#"p7r?ڳD԰Lkk 7dUrpjtrc3 ԺL@b7(^r |UbѲtZ{ڹ6TN9IUكbk۸TE$dvȈw`+1Y^ie}rZ%Fx?\-稴@[CqՆI4w]租T6qSQpgߎ nĘlmLL/G3 +Q;V&:@k{k!&֠pM(&ڣ &ϯi'sVƤXzە1Ny]ho[H< ~q~;9ĵ\"0hZJǞqxF܅q:98"M2vj.lWW-qq~=ghQE)yv3gL^Ou(~m=2yI'NFoJAC-6þAUR'ymA=4bTQNPu ½ ;2;1h[JmVVD*Dt6 R5Ϯ!O7].yg+U'l]y͵d[)@ɯcUG_P1}79u%m^ =qC1p҅eTT6x AoNU0:TЗbV0Bl❣=Af)sEnd և?HnVXֳKJQcڑcOL8b:3וfè<*~.P+*Eѣ'KRh`ƣMWYkC}Dxlwe`x3c&J7r9 Wp"y6/qKd,}:J x*SV"keD1[8BNrQGGɯ| `SuV^$Ifx]M YG2Cz՟ SÝ`:1tX>J{$ut9_Uק8Ъdչ  h8Ol}Ns=>D) nR/V@ju[gV%Ynje,2đ~;9Zķ 6fܔ!\ ϸN?IRyozf̱ܮ`YD9p9d%en{+b]uV/ 9Dh#4ㄇ3.%JkPg AZ> \f Heؓ_V.!WhR.X=Zόތy\J-O:ס{%+09|z"] .Ld{c/}q?,H@Ŧ"K>F\XX,z<>@0(4O#\h3U˞t /T%ui'o0߷V׭N?Kj7 gޭCIKQ&Y\y^4R"򿊝2] JB' \m :TO?K_:ʯ3Q4QV6|$@|> z5Ϩb77w[n@|j@3R'MecׅDSi7;߫Qd25FuzфHì#f@ΨBs"?ZoyS" sY8d cElǤYO>B;9 TG|tE@|z#},(eNgo-`uZt0LjK>?eFr{.0wH@^m:5;TI EZiN+hnLKSY[N+i-K8곋%>8P Fk G J*ng_ 2YJ?YIބ-b&ռyBI$BaUR0|hxŸ́ 5a2:&-\|d ,Rқ}qps{__XU9Wy%7`mL*0YPrȅW7W 7jA;)2$X':v 2,eljs;Tp$J ^>DlݏYꆼ2%Vp/J5~|>@=o'_ 7ٳji'@ݪ0GRϛ)(UpL3xEu:3B"x!DWXms Op@/xS! fnwJ&̪m?jپ IpNӬLGDswP?ݯt[!+(ds'n1r5Jb(PNJƂE=+w\yWI* 8d }ξRo#( gtby ncD0B# xhdzGOuYr|vi47_2 c-ܹY{M`#}!ц@9/rdU/}uP=g~ttA%8Yǂ, K+ī/uh{} =I7H_' jI -kP/4RUac1L^*\+mV% m- &B 4Bd6[h,f0`Fk?|\0{@^#H\ITLb[͐-2C)xo M]pvc /9P2D}d2 qŵn.fX#Ţf,TK|'eJXݹnU|ށ#xhfxLޘWW & n2<6 O)o ?(4,,_uNkiQZm\5!' ,[ %0:OiR)0ؽc:շ>z:[roJ:1٥vAȭ]<]LelȟJL`SwSX}@9D\F럲kA.'^ vg;$zZNi#A/co2 +ڏ?Zn'rִ=5F&ӗz&_ '\6:Fw)`i{,C՞GiQ4ncN*U^m49Csbf%[gUګЩ=HB2JKA)*ۯX30FoacAsZ0b:N:8#;"GҩGzPJPT$*?Tߥ7wNf|yw. C~, _ꟓXin߇/" ;#B 75<+-5, MΙ15[=HreTL&n7\b)cq6=b:>y/+ŧvE7U9 ԛq0u0,'q,唟tzXDOH6@ b)¶w.0ӼQTf>to梻r=yDFC ? R^㋵sBttl2-R5ZG v#_U3ل C/D}J-yu=90,^e6oWHcKd*n'/5J@ns ^[R6\z7|sOkz__obcSvц: OA9?E2/U@M&lxe13!IP`b~DZ@UQ>E@/([#h2~Fں %=M*6c{=Qfv>dH_|!b* =5pa5hOr4\yd7(wm_,q%@}ܞn(ǟrתg}*o3{ Gҳ7XEnhXlX,& F`+jxQ;@cɏWdxb/a_V^7Hva%hLf2쥤]CO!N?$@!Uv!_T|E>fVv {2NLGvF GUw<30~HBq]aR XxчR0rI } oJN`ԂFP,{1]}7wsH% kS:_nk0nN5D80GR@܄V<8!WHxΣ%=إZk俜$ϯ2ff4PޗBdɛ;` K.{"qV^@5]ZYW!X**A(֫@ |M!һ0cQ(<'Ƹs5dM0[^m&!AcAMqy^rmO)<:A_e^:\dP6^wka_kaYѺdWn~Dr"Zy [`}U4RW^nX3s@s0/DA!YLuj SK^rq<}Smti3dF1p]zQR F7 h;/.7aATp|!JWMՋꚻQ<-%Vp(Q7sטs28Y DcdfȻs޴S Z鐮 6S!OȝXƚGsxok=-U.VS7ƷjGlI۠'lwμݦqR8f[F *0j&f Z,p 8<nc;12䴢.9QvU]; Xʆ!LЉP"Vz肓Wdrޏ.?M jҟFO54JZ㢌C \=sAU(dZ Ss6sT}oQ Ơ7$n:}Zp$K8Vf]0ϺD[3\ŀ+LNmR YFߩl)?@/@='$7sOGcp^s/b;W2 [A]Tf6蛌[Fus.2\/敧iDE#>;#K[e屒x͵OQ`#MEe<_x n{rjD0gG΅l Eei^m-WZ^+{UT=yťGoT\u+k) nV1qS##ñKPG] '?>长f:[mW/L8UDS0YsUTB;le56>U^82q*Z{rmq_ux"6Z3P1>Ec?wDlS@RjPvk+vc+e!5LIT^/h)&X,zȂo/FJ,*.]:#/D[Ca87Гyt;JU_0Z@ bL!1* CcԆ*8y  `#qD YOɥVt2׬z4[) F"O^jCgSk Xq3mI0|f&;)(WT^LԒuZ-1`= Շ+STٴ*qju# RvߺboڔDVQ@/U|b]xϭDgztc+JKO m q5̇A =8PoZ^H 'PJ)I$o0άAS8hJzhF`V(6o$A8mH֌Zk`E'&ky\\?UwX-OΪ>pm\7da1KZ[Is/ɲ#Vf:&PT*%nnS#A~;{M GE\qߵ~ph*jWLWEyT7J+d'{f ||6%wnfXEm[n$(@p]Ε^ 5ANrF?"PXbTX 3"d萧_w ׁThMWqx3=B!G(,&*ٜ{qN{8fc3 ^Qwx4:v4y,}2DSJYlWz=nEFCJ?? I@S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPH?=%r7:,|! Ds*? ;hT89^^8K;6VbyMc]I.TqLođ )g^Kj?L]xh7;|> ::qM˒.Nq㬃zɃ+-i 5BD0,IvHE*[&m63$?o4NOy0Un{Rb Ui0,OlSQ7tV`) آJ9xk-GL5I-U2[[s.5clALV!EvWցMw;Ј eYP[^ /?j/:?: -5 hByV+Ċu6+D. 3__;l.ij,9uEHso:O/~BGr.Dv:OT _֨V?pd%LxЃ0k-{CLɺouSׇS_>J4ST} S"dYƆ6\:+榢C:xH7'(g_u4E/QџV0?BkOw?,<:$P] VN%h赘I-2VG.#OnԞm( ƒ[8^Foxcٜ? Yf n(.>E(>b3"=h<4c.aj,Wzu=:EV*%,99SGD&H#old̘ ?{r\\5<.a*=t(e4Oھ`J^7<6j^gP 0S'p8[WMn| %Va߮+wQkhv.KE|Pd6MAmΕSfn$ԏUVW7gn'Ə)X<3T`wmlq<5>9vQ-Ťh ?|pyh⨟s[ SG=t7IT)],rItD =v+}Ջ1>zг3jo5 7:(D=e[RDK谢0Uԟ䐯K׃ȴHF) X9ΤۚwQsךu uFj'A V[09t]FNHp~6 h{P_.Z1ﶳR0tWQL[w\wbz'L%yd)VDw|FwûOpih\\["9_'uTG{thtuHCGJ jW,NBoeъ 4~Tx:V|1 L-J`~/Zbx?Ǣ]]ϴ7C寃A"3D_ tǜS7E{HI8R-f"d I6 ="ID@$ٱ+>m}o>1<-=ktz# DmW|˶%ZDWY/:yjQj%^-5;FljTjOTakNc夜BJzm4K _^K|;QVz8Vϭ#`WANMh(ۿtPt@ b)NEoų3RT͇<[uʼˑヵQ9;sr xlʪɠܔS9 '4MNz`!R,z?֎ γo?Ixw4E.R~#E2V!b2^Q;y36S&7DR R"a*(iU)YjR*Hd@vLƵ!=R&C]ȑ4_|50ȓ# PhU|rѾ;؊OF(3-9iM 58ԲkSxjn'8T _a2_-NNo9⚸[VH>To_nI d\o@X̓4hhŮ<=7n "pPQ'}hOD48WGDqV]Ev50 ƨT 8Bǧ{Zf@!Ii})Υ3<&ztNDӊJ; f_ Դ"SR\3}00z-2$mR٥ GN~3<2,7 EՌ O*pJ'[n3Hv"C ojS(dKcII8jzČ Bfte{lU5eTKj[p:4>U \gTf7qeǡ o#ڂw< _E'U #SwD~:̬$ /{#Y\H9k<..~(تF0₿փ&PtfGZPZ4 UY. H6*oH :J dQi IYJgfEK<>.&3T^f3?SpLm*"Bgv["9V`R]EZ e,[8OC`s`P}c׽ԄqG毗<9뙯l 9I1mb`Po̖Z8_cnTڭY$-ߥ^bɹY6"x=>K /"MHouh!\%Dk: P1@Q=$/~'!D%|;(/eJiUUzlvQOveE~,#[Ofbf{k5\i7+FIbZ yrd>us͛`1`8e:-ˉ3]/WZKJi7,?#5;~%YqQGqd@׏^l,b!;ՖwH {{sϬQ0 aMrS5YU£Y&S+}i [|H75ˮ9Wii(LxV,P וt%Jfm0JL4̿Q=qt?[g"BY%`k*nGmBmT9tRʷ񄞄lJ"UlnL>5*ҏY F=q'ӓ'z5@[7h9Ԭ'(m>+k馾n<ºbq^yfZG[]l7nX3CcʒPI|g5 Uk>qW 6ς ؈Q3,fJzkyY!+o-hiIl\hV<2(7o2lE=ѨYV3ʊv#˓~c.%y ]Ұ08x%sXW(un ůw9B);B-bҩ lpHAK>AiI0Bb5Ut<ԣR !%>Ez6A  +s:^v&h.nnߩ_ zaax\t$`jI6GiƑ;}Cy Ea˖QU}a&F-Yﯧ ~]KwDQ ѪLø>>VoR9ST7jK"*VOW~H5?W8`l_d֔R_ui{SNDZ! 3rk)VI:NcG';G(9զcᔧ_\g-4Hئfsq۾'&F/;DҴc߲+<$Fߴ$wZ=Cz !E;Oܱ(k`B5k=}rh E!W:/utD cÏRu*a,  vcG[AaĻ~DN[F[bzR) lpWɌ56%y [O??x ܵtyd /;:vDFPӆدzzg{aufvˍznbḯw3zi/Ld#8}v*#㌞/BMOmwa$H`s>o8QS0Ck0GqeCCOԍydW> r6y7NՃ4ӫXlVarlfe#1sLBXYB0yw㑨HrEl^4eGs8Mu.h-'*EFd~WDJB.3!%AxO~=^J9^V3R#l3%!3g$n7.GQGI8ڠ[k$|(u"(W*xhk!s}D&-뢞ƍ (J@QbtP‡Q &LMoFp4nQk 8ML鍳!k/,3|b|'P>0NXvH[Zm#>ďj GɟBTBJS9WQT[Mq˺V BޜEUR(Sdxiz<*'4$Z{K<jBoG\wY 2w8x k`V5xg!,^M<||` ^;&C}OZ/ E˩fo6$p!ɐ 9AnK-~&.y/eH5~1bձ %j۸Hs mC䍗V|B|w" gjj&3'lge14X멟i>o¢Bjt?ma9ՇvBӰ"}>C}e@e ܗݵhM^}];]6#'S?:":ZjeV>^C^xaLpJC0O:a#Kw<5O콦yvz;{+.ѽYgb8l@7؂y@\ ʁf̏5q[M~%+5s ,ԅe?,QjvI]%BHsoMDHֿ 0b 1սE\p;T{PD 0R\Q3K#-'-н#kM? ?}?OLL''S}a-. | s 埂>+2f_$m-s JTjA^#> +N×To2 ^+UOףJ7lZt Zߚ%arm+ÅԪ@u+㑟@U zu"5cžtf#@,kCZx?;Dxzr6,+Kl-y]4Sq04Pm#r!MOB8nJy~*+f7&H|ЩHkBpZex?Bol $Sw\npH `;2yX])fUCppӠЂV@cTaƀ0&@3aS;VT-= [wB]E7k~=piiyeDG?PUiZ(mq͆i7*&(%t;rvd){t6`b?v,5.~%$[~ !ͧy"gVOxM~.<6ثȺ;7S^]>,qLIK7N9@1@ӞMcέ ^!>yӷPjxSp:YV~lgB\(lhďx[-kF .b^d+$p6k rx4?R~ _]-OԀ^MitKR(.g6KGa(9U #DU~_e"%*G[h u^mo}{[ V~42q瀞•Xe 蹚&cU-dC;$Po4]e }7f. u(_QP57}NkFP%]М {Df0s)Z.c7hMtN{L#'8囓M,lFfpefA35Hu}oԠ"VX-p*ZƂiJ_BHF(ivZV8ōzpVQxSߵsgL:2 Kfk_x }U?beUPklyսxB$dV );D ^'NK2R);6qqFPOdn}C>vxiKlRᛯY<ΊܜY}E"&[wR0ړt߇̀H<Yr,8hc$Es0AK/kǐp6P}Ku\,/#'rڸdP#ʚ$k>#g)X.gr,y3ed @o$긣=}zfb}O̎4 ؁MDlh5fZȧZ\\҈vB;e78vi"|cA[JNdਂh9۴嫂w4!W (kq[x¹M ]S S2!yMJ7K&u$9|JdL3o.aaRCc+KI ܴdWd:cq%t Y 6t/ Y}vVGH#^+(%+>BUٳA)9rCuOf!Go8IͅXIΦ'V*'@ *{0:!%&w }ՠsSdAkTqY(8*ϭ)?X4tvK[!j i4@+bRxt&nM;y]8-ɗjzwӹq&(!n?ZoB@f> wVZ|ζo*7vN?4DVl-Q8Zge27G8gGt5A1Y&56];O4]ijշ񖗹Xy/DةN E=[I[q{ڦ!qEY+p ~:<=kxeX-wc-]T+߁V̛zlZ<,ڇaFTjGx,{u'F崊Mi.geHZ*XIkNo/26A>}^aSv+.6Ū85{._;D߄.ipl acd5|KQ9S64E4 RtX<5i\ $dIJ+"XG$Fxeo\I5,> $e 0@&n|1Pv@9۪&Ǥ2 fkaBgV=)^sAˎJg1IF4Oj˜U(f0HpSY@gRQ|.{oڄ`t)ItA屦j5Ÿ~}r?5.d6,\b>[+_z3b/ [ wϨ =ƳLJH.:mDH)ډ6ȦVI4I7Vr9;JEV SYN/M;/";kpA`חbs>ArZ٬uQ6 ލUjns|簪 dHδЃ*?|ۜ88M`|ַٴ*l'HTGH!~G.֋>mq9G `=tSm\M"i?X[j}ֽۢ];'d<@ą;.B zq⼤퉘Q\gT|dBIo,WKnLR!Z !ceO,M`HC³e2 ?N(_x^*v# H;NMqS,Rf %W1e%6z:눓IGQk=4@EaZܺQ{ö- >$ ˈt0|FWؿce}} ~(Oz|U?T2ݥ .x!dp>uVQa9RTɐ{q+NP|Z QKEӘHZK{9FTөˉNߍVEc% & x02KLB'p`P;ulהmP'scV{mX?;0u'Mk;3~_Dh.hM a!J$Λ|)5PؚH?l9_[$\Uо.JN ٤>lH;+p>=߀`q} XLpYR)rq\ xP[N쌅2o6 o@uB7<:D)&ET!)kVdA8>^tyԀZȔ o x9TB<lbvv۲WjZ!K6P윌]\83vQ+Rmt3vIHF2DK|I;: >ˢ fD+/8Ki/F ֩dvfvXv4IO?6wŹ~7E9l)8tQNBp@uőluјiϬ| ;ebZ)'*Lڅj% %d;Փ:J84^X12⧚EVCd 9? O}?OT  W|JJ&6Z勬j" *b dA7}6HAS=joX/nA!i~~=Eq0JP3FoM*دB?Ok ̭G4? FKm bm&xx;Mw7BcX\pSPǺx5[ګt=x n e3śS GFR|e*}FyM)ۉ>DM͑#@~X Sܦ]`M%o@\L?Ӄ_ 3mlqt!3eIz3Ͷ)~ZKˤ<[M'9Y`dոyR`XJP 9B6zȦʖ%6A]ذ jT&+خ x/{ɷ:*km;tbB.5(= Ψː Z@[]B2LPCx4[T+Ev19M`=1pXn[uumViޤ/GqEUءM6p)ۛ{ vza(wbn'!7 $O1 fm=9Mcbz@ʹElA̦˵d;$v )9He`V1# b50YE:u8K*j+/,Qa_L*5vq$X`ԫ@q/_QJ>P;u|k*s~5o_ީY.+EF+- kE>"5u%GِF Du!`uq0)ÐѡJoy̕`jHwO*݂EQs<-l&]JqT֝F5xo# ˛NĻr㥐Wl^|.v-=o}2Ӌ9ΗxJt7Ng3J$7P:]x_ '"& R]\52y8L$ ;N%?h($AWoZ avntXsU pL;VAd}:@ "2%Ć+RaLSo h ^{QYA{iƈQRIJfp|hD= Hڂ򻒌6I ܩ\~YV= _:\4ߜV* ZQRvB *!4p4^Nfntq.r=(pФf kЍNd< KV#ZUrD<'>r}Ƅ{vcܻR &:ק讕a nwיP24uCq&'؆1{bF|Dml$'P"QLL2wY`,[cjq"I+ݻ\?3 uZ$ s(e-cKngU4ώvh^|+i )m 5WކF8lԜ =Z`́QѾ~T~-9Z"_דS:1|6a vS?0R6TХ(<+Q(wT9lȗu07Ц!*.h48e\ҬhԸMIX>vW6YFE~,|7oQCt( ek"ŗNy/lYSWލ|פc9Ĩzd'p6=^Ӟte j e ߣ$w+5Jq*ac]~+$<Hy$ط;C:^3C~bR" z ('y곓ɬxmu-85\B1rx-s8tTZgbn80NAvHsVtj{aQ**].@UA~ӈ]:V"rt{ʡu9GI fPclx`q~*T)0V'l_n? U.!>hn;܂ѨwFG5Q0.x>ļ?_."VeId.Y=jBmfx 4*DRIXr``tG} :Jg<4*}9(/|y Tި5_=dIK3tDVn* 6F|<]O y\Esi(FjԐi'7"Q]WOmmfEZڈ :37=я X -OSZ."ɳhIo7fn.@8UȴYh ŕGN00$PXpRN $4|0@҃- %.G dnD&g˗ 9 WAg7jy$5н{󧗱=^\M_hm0U Oaѥ4-:i`xJvxYݙ-{H\D k!FWu^f\I+ᜲ/7gg n*N'c1Uw!Buj_BϠ2fw-z@{ؓO=vKBmN܇])KӢ9_pw3=!;Q{!N~.EK/לh =lo65z)KVNfgumVEeH.?AMŋ=E'oO bS(v/1K!bGilG1uѦSpк!u1r^uYsiݵZ3mʿDHJnğ,gܟ%3.͎2TIx`ƺ6c 86/3o7(@ո4*|3FjS.t52HuM '8g-ry+yI5`'p@Ƚ$:^=56s /zь`;R h`ACx>O\OI$أ0Ir(G_=L&+ )$8KL3$D`Zk7\vVt(RohMj0y `عUdō;<篇iu$~VFaQ[g0<&`j cY:#p,yV<Ǭ;EoSlX Fi*. } "sXώnPWL*1:vpiŬgz!ꭞ%[OBι,;,\)T [_Tjo/k_Zٕ3B8o"? RR"0Izp!o+Ae\mvߙ17?9iC.2+-(:`fNH8e;_C ܃o]sM\jWoHrf8zT$P]/M|K$6F/.yQC~$x<5!{+gxW^ Mõs(&t؎KKD^Uji_n`uA}T܀]#x#jn3\[2N.QeZ 8i50{b:rzFo9U|!+Gx['u+c]|gO^H;'^^qՇ;G[.dE6J /[KBc=X4Aݸf.c0uY1n{\!Lk/9y=@[uWg}Hh W \Lh0+2T،踀]*CF Wr½M΍?WnΣNM̴|E]!5dߴ–4nFic; tTe ;U6 ^paPwMSorUB0/kCTHY q{e!_&6Їx6\@#qހ(^ܡpƤoV\6-r̯8疜'E]S˱IAKQ'} _59%9@ {J ycUZJh0l@3>7_?Kl~+q{Ǿ{)UPe0/>$(yqϢ˓+ ݓ[-Uh#ʌb>j@8s҂6ސ(1RgTvLO:V81>n+9.Lͪ LIZ|1íkUXb}}8>!$uOcK^؟ytfvה%8L8aoct5z:cF鋪I _kם6@bm 4Ogd|:ï@> & * VT6iyF:Ad+N(rwwA2Y Kt6QF^ށ:0b 1{q',WpY}ly\!{ojk|Hvan)ԚIW}32%r`ޙDFժKZa&Sveo Op};~}P/ R89MdY؁ڟlxO_5R)tamp7Kz\>aLΡ[|I%Y>RMc|@w$oZ]6<|]<4SA-r}.p Lƙ!^ȕb0ʈe2 P,ZRqFs6 lZ]s~^LI1D=~- eu z^j!4sj-TXIlbzߏU;q@.>OUrB̄q<)8Z@qM_ ):ˋ~ƥ<WYnj'i[gLMI`GG\It8>uC&x \nh۱v)%*hu$- َJp̀|za.&2f̓Lv#'Z}&ʷt7NlRި&M[Ӌi{#Dsk7f"m.QY,H&~in58eQsSjnYcܾҘ\'//0㇋x|9}6gtvw纻h8o>T互xNSĎ'G6yb $jIRIKKu";q=+@a29gS={`ˀ2H z4O>/xkqN g K!9a4CCEI9wQ1 ,n~aASFЪvûP4*|lve~N'0Nmʧ 'NSr$Ԑr/-JP8G!TʡfJUԾ u8/dr>C; Ǚ$1-AF=@efgP"pwtЅeDrer(vCa7M]D#9ot8[V5<,>a=pCфIsioↈ#:e4&C}: .jA E\{"gpq!ipj nVIsEcQ#1m Lyu'*d 8* Q-ۄ B~:tѫ3vma"!x5IQ(&=h%H>,&lesmgUUw1a[kmkw ,;KL5nA"ncשvM0 v/^`)惝$_/MoQwxXwnUe˹ xE^9tv$G}J}K㪼yl[Ty)24򢙞K3T,SkP?ٲ(;0>mQ9jLSg,M;BTX"Z8!ӝKr>c,Lh0L[{&nJjEN;TlW١Ĺ.B@67MKv{8r  8KTyW=NH+.&S)b[7`{7tX2Yd,;}FJA`:P{UaH!zvc#x `ׄi(wNZU-C)Qz׵%jc$ 6,+4ᜩqyCg&nl1Gwn"PU޽˅8GwVm):,u!F($q<;5]0TA=ݞu9h_* a쁺s>spTiV;L'zAa3̌ W4 BLИbʟm >fyA J-*O}H$1m "Bb ~'!7):ű'ݴf*< 9*րhM-_D~牭Iq X+ҏ?ڣ \u^lJ4>5C `bGC@޼z)ShF{ߡ}O+%T+Hՙހ@xfh|Y),r:Xuegz1Aʏ:WuC҇FuҤ~/LX~ =|Qr]zZe`,u/ 9)1|\Kekd gw!*)>`X#U]&}[8 *o.4ڡ 2 T $Qnغbr%x~xO-Xn)ڑ Z A(–Hp3%I]q3<̿8] bHI aufqy!1@.ćέh"m{_q!Hy777/рB)V]D+$47|8ȵVMjg9lڡpk(<Ucˈ5q<>)njKrtN)p?EBaFPKm&6-l4Ը@gYn\//7z0El7[稡"}:EvaOPf ,.ApcǨМ乑~&h*&Φ6V[~V gJS *[zDuc}.P/bYqb!.SPՓS mw`v]֮#$I*{P.Zu+wtB }9`Tl*orˈ L"2%JTf2JtF?rR20Qٲ cґ3Ms.z"y΀Aͱyqb6c:]YaGFgF/},tk]9eQ\wy.sz E+1nv~謧I-=59Y Mj5I[NZeF_ҭDv+EE:D ,$:N%LRhykafhS]"lE5-:fkS{[A!L2kYh\.R8T`Wd"iëB SH%/|ǺIG+չHD6Ct pŮP #&|K_Tô/]5 B9.(a*h%$9å*zۣ$Fq)=R&Txe3M_8d]g]Q-< uj&|ZUo 40`&Gl[uƻD);HJBq1H"0 ƺZE2%`BMKeG7:q.(bvoQp]]s^Z] j88 Qꘉ|TB@|w@ ej΅]&:ݬ=7"R_riմ0&%zNArׁLOS`UQ_,eRf-+2rL-6 2GAK^a8DE0<4׃"(' TXSt͘),J{,FrtCSF4^f*:.䩿yE: 5@vZ4 igo֞\M}#6c"qYW|\6Ref Q,e߲9eF@vTڮ7iO |/4P[FtXA8)++ }E|>q b_\#E+u"j|1`n@[f fсz`AX_}=L0sf$ 3[bI;|p Tң@˻m 1Zbmuљjn~^MPpeQ7z 3 &#(,bLmߟ42zTѮoUO.!jO }CC `k"ȇ(Vzv{-CʨJCufSps:iYX5-)gh?3zouN]cJגxziՀȏto aɠm8-" J;wP'/hv|.UH F{ żIS/Rvx5^*Wj|F) D yK `'!CU4" oQ] z)*~SH^*}cfR=(, f" #4ᒦh'[P1P6NoCtnY%zrqM6/cM%QZ^5L(G\h&9[5aeD{ݥu>q7q֎"rq̵% q]ziߌw _Bނc}zȝZf>Ʃju:]ܔxeAȟB;-Nb]0,O.VB ӽTY$Ob,A'w܆RÐ JJ*Ay90v-A=. .q!FQ]t,ֳD7juCΨ99 ~91boKmnO S.v[ &T/=:tMgo*ҕOHCg.uK\/;gp ];QS5CҭlI]T2/mJ6ʀ أۥ1ۅ@wv_H²t^4.g"E+B =FxN)ߚl>s P,d!?5] *@S ~M}O9a2⢋<| |Y>8[NF ?Vx/-#9~|Y0C^H jqr ZcP/l7O#`rՎeM悱?FH13T P!<t[;!li׬N"F` ?e.2|02aQ`N┬8c2!Xsu$YFP'qXS&[a`I1q6­eǏ[bB5553.jqOA 3(wDt!-Q#%-?QW>t ڔ[|Q_#W4xDl2r:f>fC*>AGјWLDCq-uL%Qnx68r E L G:Vu. Do+dˊ1J0}-87 ;9֧ e>&{Ǣ$5qy :FN:oJu[JeLfB&VZ&(2S!-?e*rVNpj)͋dDG)81 dfS*VJf JFB؊$G&.jp]6lwqF0`-1}Gps?54tLC1ng1こa%E&Jl!x@ZoF׆Ŧa6DzJ$K@Z.:_wF[B9עqqen6-gϺ78F,GNc?|RT?+׈Iݻ`YFz,oM1?(pZ&\I9HodjaXRXQc xa=h,RW'f/ 0Q{u{,)8:nYV J* - &bH If^Ru]ن_DC 'veFcX56EB?)#RK~-Dw!/"#AM?t @Oih(,&IuYHĽ2/gF_g?|BW)Tjמ:?6]<蝬61^.b6}BN^ $sX Tɇ,3>! %#VYF9)n_q 1=77^-{V;_V:EB&rm,۬zeMm$;3;*=`3E%u_sZ)/Mc_a[]d7&vdd;SsD\u4hn̙j_4Rj~0I^ P|kćIUlš+ftT8az+.z$oXaq?+\]D2_5 =:CY7*p%R[8lb0i򭇫޵*SiPNtj,e LXFF1[2|3F7#FfI 1N@-6xB*Ҳ d9Jnʳ6F9y~ K{.,|'ABEH3ᵎ /j_SMϕ\&˚]비Gx^`YRjݐw8Ne2%)LPpV=nq?lgDE"Rc:\,ka dR;k5HAqNк!IZ e>Ή* ;'- X*xdi".1~Vtz8a0|&zHAg^=`LV2nLC UG4AztyE2\ <<ڻ @4H#:p6uh6fʴ#f\8zUD>i: +r<^ IC#Ӏ#7-wzLqfbv\idgn1>LR떪9kŨtb%O!| (䖊MVð.Ghك8ҖZ )/ԟxXK,) '>P3-JM\_''C[GnPYrWw/­]g S~4soG 4?_F' AdSg!)ߞVNf-& Kl:?Ǡ294j$6.%5E.y7EP_5jn Hm_(gDl~}졺 ݋S W)Pw GLx1@&ݵxS8lg N-C1xYF?%rbD٧}C`Dj~a&Y; R߻e&LOi99QexaI6:s-)_ }8qgad8[҈6FQQ!jNO>Zݯ I [l( [ 2͢t^Nm">}{NʻFy` A&Gyd+N]m.p;4xooAl*6ڕJ_ ԭpd)Tnj(#sǜ;1_w {T@ Z7$Mmk*6\d@:!F\fȂOf Z /)Pf!&&6%a,^Hsy` 5'LFeNxu%*\|kMuv57VAΕR WeAI3tqP:0=NC}.zdX`bp[n˘hHK"/'Kxb9Vm<1O{֒VC& gەH0*gMB7fWd#q^Cs!CiKp L;)SfFVj~W.ɩTXqyGXȩpT飾uoD=4뤶T!$X`ӵǚ,qCSz ^3szNVkq,XۥYLvl"<:fT+mbTf\E˞`b,KdJ7e0->e/!i]0ASιDMCj3KwHm?g:rn|#||b"NC[B1 g%||i۹Գɤ6FmF3/>gNn!=6YwC=F-Q+C Aa?%]QŞOl Wu+cȴ"=hAFN9x;#FӜ2,Ů yZYWXbd"ݶ(Szb?e@~N' ?bbՑꨨ*^3*J QI12:X;02rjW цLKm)Pkdeešq#R[/y"K*rR@;}z-](kŔLX5NWuQ~r((4ZuQ̓B yf9@/d8kY?~ZϯD{H 9ˎL I7wɰPڰ ]-,{IDt8=TTp/SɒbuJfDo[J\"}7ZV&dl*%oK垚q]lcO7ո3zmMxFZ`o5PU<&X8X-ܝt zD~iwFoWϩz˳AF6}z-jHc0[?C婙$nwj.V|[%B@*4EMV4o+Hj՝)}ޅ1>#Rq*f+yq9Vvs ج%t ,?+zy4U4(ss-|8>&ະ&= "/dчWNށ^0s"\ .v;`l, `2WEno> 'a'?V]ӗ;_Satso\1CLMIaY|Ja~/ &wR09Kُnj "ר!@!kgSTXaSxl;xi-G aPvd'>dT=Q^׍A4VzHlbP>ະRF_xB'?M[YTuRGSB@!!ixjW};m3iג٢75`o x&$l]`xT4qi3R̓rn]z N)h;T W(~K|1$xO]׵=s.(y0qBÕ^k}c,kltMͶ̺wj5ɒe(׆F$WR;ihFIuü3NN>G/yZ}ĵg.ŋR d5C #Gu%/ JREz^5LDWqM֮v- 3'^ yw,,E`%" K%:OD F}LL&O% Mڧ ) =\ '^'_Nٕ%^[ݻm:?,U+t&d7`yk$ew*uDZ.ǘ\yPRr֮WuՄ-BTK.Ud& Rn$kl{UḚX3|xa36ɛCB'_i{OtX*JJ0>c#0&n87:Z}}|TzWA*7$*t:M8Iȥp}gccKۿuDh 'kZ)Bcˏ;{O#6y9ɮR$`ǢVؙ^{gx9R3rү'ǻorCy.L3|}ѧqZۗ:& ŏ/>n&+ESoǖ-wX{z C6JhmyNk! z՟ mn ~ Ч+ Xjf:c.ސ|H9j>J2h4xǻiO 1D>`'e1{UT]ŀS۴.{"n)MBl,Lܽs&ʓ!g7 YYgX40#۰),A)Owsx%B7s ,Me\޹4 q_96÷ -~K˿rB<u5A7}A DQUp&e)K0T#LY3Y4u[ڷW9>_CEkg3I-˜Y9(yE+50nj+B ofB[p_흗B =ֱyE/P:W0F|\{/zՊG\ƃ2k&m[,+yU5:AX8'JV^@s 5]bZV.9C|HH+ @D){/"fK#3r"iDS1H'x%0:瓰6&S&@Qk7P<9r9/'WզIv :+V>y%כl,QrA(n;/~ݎxC,v-7 x[_/$H,:;ֳ)hЄs9#! %!V !h]3n<߅FR5lNg˹EO-ob'0FFҲ[5]DFDZƏgbYJ%Gu),mRi 8#bl ÇMصͩc)&`YX2mW;g %&#T7˧M2o~0%bQNr&aF]kڗWkRrQ%-k(d߰46a۸܏R$ "Zvx!oPQt.6V>BP= ?΢4/>{^ZsְLLUilRf%v ў"!R 09ڥW1ya947U% :a$H6g>%B.GAQsc]^ Oko 1\fI01Lg. !bw+ B^u5s] ,rN<<ψ|JNS[H)`u0hxvC>1F@ZCFęA,PЎm7HH NG/%㠮Ul71{.{Q񶔤uspE3'}j?\l΀Nh#  ߤw *9f KsZ[oʆ`ַ'WE/нƗ)hǪH@@?8? z ݑ&kEVF!ݣd0%*7x%H4+>a$wpM׋9 o%| /h3XLkKh',!nF Nf=héqMczв ܛ,=ZaWvW6ܓ!Xo7}!ܹ,sjs0^UTfJY5GBJ"cOIOþXz\3 =QۊipAcs{f.)G^a;eD.6Ng|@J+x,NlKv׈b%roqy02 1W&bEp[xiAEWlYץC#O=J5ۣg4\f~ƻ7%FW^>)|.l9&2LEtyM˓^i.Kou.]!?pXZ:\&./$B5w?O b$_wAKUZ4@DyՂs nfͪО=HU[^0G'ϱ!|¨0@Cp\m)^`jLUgX_3ԡJZvcOY"_E,p|TBK?ymm) |n0ĵF3k+vVռl jm-[ysAwmse1Saҙ7=btgY;UgMo&%օqgk¥Oa6{sKەtVǺwv'O.\wԞ8+\S1AT<[%)z*8`8* U%F'A3 bY[ocr!,ev͍Z]dZ¤;7(tJÚq]B;h t-.in`5cMjIcmO)^w^;UOS)<Ӡ L&,.z[[#p8h^Hǃr)C/4eէj!-d.^Θ.uL(g2 D˹URh<ʗ8r\OT ^&T_'7vWZƖŒ*d}R) GcXz u_1=QqRF̤лw\›0 =5[H׳?__>[ pҼϞIyvi4'} m V[4˵:h Mb_I'æe+Q޸RHn2G;V)ك0YBvYzȫQՑL_̐¸95tc#Gja̤Q$UB-s؆IJ$ˁʟ廷#?FD a_Jf4fƚu`5Dܣr 9$JjW˲v}+&x]* Wn࿘?p7s7_`оYeb#lw9 p4ބS! W22-:2 )JĻ襏 {KGC:$)kb3&Շ7X*voXi7M)J۳ !|eǍ¨{~3B!Je{r~^\0,ZElk%FHC[Mx)'Tkj@?yP[:y%_oHҀI؁N2u_s=fQg?{$s14 /】-R |9` 7 zoʼz[q1X-;}? =?dM #BAΚgzY0t&cm P^r{(^wEnEƱ9nZqdMY > nKsK);ӳAeBqmΰ1"y}s>)xqM]*ܺCO6()/o532?`G"Rv>_LFmp'!q=1A+E?N|*G~Ovoz?}@p7;d q.*$r90! >5.0O]7Z.Ig)eȪʏ2t%(a#NlXl3;eI:9t+`U'BΙ=8x?v6?d p{?8ǑCu k-R [ڬs-Z))չrKO TA퐧"O3X+Y*]Z1j1T `$ăF.2?mz)<%GӜ/'q]iW[LQ`ww(«ggd”Qi:*ua9osvLQY]u:1*zLzߐ REn,u< ABtgXM}uXc8[\5fgu$]fL#ФPd꫄$#CD@Gu 䚟 ސ W5@a+?`MS,\s8^*|_ ᜻) ]:SDdJOfƶȍ[6mA ΠXN 4}ܳ2}("B N/6$ʂ]fW%pa<߄Ç}xp@? `hvBt-/ϽwknI2ڑ 6@چ瓙dsN=y?N*p,k e..u@qɗ˿VX!ilcٙ\T: ĩ#}-)uJXK+a  im#!]tmTElf c.4mmi^x^?h*CIt$"1Ŵrۆb_\ (,\ I;Y¾+1|keis2O i\4Ls-$C/}Wy>YFU$}~/V1.G1/x?ѯ礻Hp|tmx+ܗ~[lb(I ȫ?H G^˽~Dy:L *76z|4?l>=C(g qtYW@[Sa>}CL(Ť[C!,[e?3m`p0,_Z#4x:QStJ|ϽSe~k2UPy[gr`$XmBd<@Nj̬%qkm+C?>?x™i3svnrȓg x & jY dLRtUpmh ,C0i>LL%_D31g?i= ΗzKOK[ϤkLb 5 ՝8-2}B|gB{caQW{B!wҀA By\>XYthhaF'k<88TpG.kp g69)9uL)x{PØk̹SPvPVUpoeU9.=YH;- ^hENYTkb>tj^r|QZK] ȩM>ж/hgT\x<ҐmLdy@O!H?߾Vuۨ/%)\W@\%[>@u^|܆9'J5gR9@@_Z^^mo[R% qW50FU4U Sf[WǠ;?g7ΪF-d2*)WC O,$<i<l2*Ml_qIN0HtFN^}]0"iq (>5A?t(Je7&y4;C[N`#U5~}"!Ƴ֧VZy.qhZ)d]U+o-b@⛪",3 [B6CJnR4oJvTE#a}CP8fJ#SѨ ms='I\zAmg*f7AV#.<ϯJL܃ofP7=uqf| Հe;ڈBf-:zz:y=$AsSòcW` ]m^Li_yW}/x_<e*) U(82a,hCqD`t'MM鯯})~S\LII/G?pq}U-ӼJ+tbH.{3ڍ ?HiMvR Z:Gɩ0~gOmÅo 䋒SyEVQmE6+U~{գˢ4Q S؆]#8D}B?G}zZ=O{N^8Pq2:` 4L]!eئ~>?}^0gr4LS^ZAiFv&&g.!h1eIEɇ0)i!2#<|GiLYY)d~j_X3 ;gּ;n LBMpp^$ ԑku*V[y 4SfjwjE)uȼY}#PuSt> ^X&LUn!.lqf:cp_`Pʠ`%%/Pgv3k "LbJQ^"yޱTv-raf r6ReVr" wf2!jRpk|>,_<ĵ} ^Z̓(A<V<}_a14rG֌R#ꐐWxu/p ֓tLIȱKYfx<|[Z~qP$C⫆5'$3γ~1c\ k:$mqi;9Q%g01 rnA(f^;Pmw;a{l@~EXgQɩ7L\Ob Ap4ٷ}{@,ߌ<.ǝݹWo'iU`Y `]9kZ:.Uw@ω_&p揊0ʺ}WGƯ@dy?\I~' jvIHH.?5Tb[-,7No[%t>g HaEM\ch4O|@|@|b0{ǑR[hTP/$2kٷ|@|j@=t5*fLaB ,}4#Cیe=j5hD[!&NG6']!#{JH{B\e$X=|[~2W`_ _d(Š G [&?7_M>B(c$LҴ A8kJf,)e.X5Ԭu)1cr>e1Q'+ /x6ȋ0,d6ӗWz~>"X<{}٥t{&FL9~\>62L3RDt?5beJӷf"4ܯcA ွruˌUNaLH8m"Qf+_eDuBm>g]G8+)g߳A9SG^dֻ;ڎ/*g $XNFe\53%q{e4m(2iYq$ߟ_? /,?gK}V+̯J.)͡4|@$ Y2l3g}+$n>M勼drfm}\0U#sՀ)CVy5=Q}jqO *%IrcVYWД񂦭UPUYݬj ?kj =O1/ov#Gm\z3xW0.o/mlN2 >ko_뗁zȂdV10 eO1};c &蹈wp%i4R'@8k_Fc_l-UFM '~':'XlJO74s@hl`.mqp!\N޷-B@W4 uJtm*D1Idh2&Gؾn)Mq7v'B0YTP,g< ЫI#K[t[ Є3G:c=Ns[`Yן vU@N %'{"Y:Fcf a5׾PZ3 7ɹz;T-ƭհFs IQN H)! \ î5Yo'k,BP[^n(>W R`;5^=MT㣁!zA>,6Cߔ3wGjylQ6UV?ҼJ2=uA$'p,SU> p)}1H#QW,ΙXwQ]yhX1 @O!~зn̉U0QfSJ!Z:vi ȁ>'o6SˣsD<NDIG=Ir%whJK7E'1JxY%fIPdɀO0S4L|Ga<]ԓ; /8eGՔBg/LFXO=/h5GhK2>g$h.|0la%vx]-f\_ S(U.v~ þѣOEwa?v_"(-k+PYj1qkA)ר'kq".zxGyAg# G<(]^,"A9nmVG %ŽAmsy5ͩg.zCƭ%12>]8H2/;K7 Vmib&Aab/=i +|H:F`R`P*k|kb AMZ j.T_N(J(iiy+^֒wDV0UC<͓\~:LN )g-~Ze7v"zaB٭0try:OTCj-Y$QCڮzTṪ Uڹ9[{Qe7}4,_(οu5E,V{ U XS.i*}3ց!lm@N%T/Y@{oޖ']&e0] 'IlOAaYl;4lo"x_c*Ks9Ȗcɸ̚ T.eP"4`s)Ğ}[;J&!Z}(axH>̭GE|9(0.,S;3^ $0gŦAՙyԫg.Y.s@Kz)0֋ 8c,6n. <~`1b~*L,o]jIFёwxڱ4Ei󌨆Bu{Y]?ؐe>]HE oGt20#ט\> %.: M4 {~ЃTI%Kzp\j%DCj1ںL6ys M]@Ύh  ALm9uJ‰/yӉ/Jg=x!&{E;w.YSbOK32v(=]!Mkhg8#})05\$41qCI 8\#g %FjT1aH*ބtm "99YMu_5\J7865!׵MݑHc Qj&&cşqiV2,sB𘋀.UҪóhRYS QT1t ZmOIiܽ`оú^nuviT¥W $[ޖz.K9 yϵ>.: R{E{_IFj51C8^[OGxٝf] 8о}w=ڋS^cVL sZ| ?o/c=ͣ獷!BCfn)w8Wc.&¢ffE'ޕ|piV;*0X׶ U0'L{IPX'-ՄImcqEp9oax6J~Dn'{}>AeD1&TJ.+O T`7;Q98Ѓ&Vv19g曜z0)7DTslciܒ?JI+b[3@DbItF==P=r14Z AA"87hGCZtNF5`(l/lەkJy dx6@!* Ptк$Tޟx,3Π\ثܭeoa@; H[fݺ *=qa6ο3%10.;Jzj'@9xc9tOH<2(Lmz_9K6XN6߭rJܗqtM_fa%rqٛTŞ;OTҧy:;Φ A%_NPKu6O|@:4$a|*H$j7|@@|jK 2NX!o;QH'b "=^MdwpG>=}'J@K$jc/(: )03ZV撿\vkfR:uO?`dWaofL@C Q !d!{X؞|Mu CQs*{wmnʲlMBORYqJQv7:AzAaj -}ӳ o{'"#b֢18}e}$P)(OsHζiƻ >1J-/CS8~('իEںU<}Jgr-k'g73VWt޿9Ѯ|eaR?:@[g LHfRQE 8-D6VM1XB.U˹I=^*PTF˭dOIGj(E|)%E&р$VK[xo.~J/vs4Ԡ*9we럊8IW~@,3uD:ϰ $JA*N"0|8ݴJyh hݣyN9$/]BpI Wd&"OnqS8~l5,#jĖ]FƬU<* a Oڹ 9kjt59'OtIUYFxc}]4J ]aon{c ڢ )Li@&I@ldlƒ^NQ쳩fg?Tq;xs.e)#g]'Zƻ|-YØ #]ya:Kn'N`"G¨fad*N5 >SX.y"Ck^];aI!v9)$*aumr /9$,,/9k_ "9agZ&2=HbBv;!%Bi6a@"^;@P yFbV^FG7?R CR}ф)KJ@CjPW>:ԕai%]֮-77y Uen\~O*!o2~sy튦ҊD6`).O"}Wurͩ:%aH6vFp>xGl߬a TVF`:nb >SlbL`RsS NP5c4ϯЛb,XnG?Z;S;x5UJy8ZyT *`hŤ)U?YSX?r~)k^eدZ, ҰlH(z2k]9.taۿk?E|xgؑm=⢇_{\<ݮgu}M!\/fh7rza hWR+1\mژEE^I/}$r `rCT,G5cd5zk8( KV.V'ѹ {Xj/%\Z 7\ eAi _ D:3'b̽8q)+)O88,6g@qYZGp[?…ǩ&nfAS]d k͢S_ "fqC2ז*GHFX %8M*TxsP95YJ#wrU}-B5QX-pl|1@|ULr﨣z:;U] unP>, lc}@֎)clG n1znPjX~Wdb8Chݕc݀i qɌIp4\6vq H,}[}EPUN bPڒViVMfB!ٝy_B NQ;ԐPi"ͨ}qUQf}QA\|uյ;Tqv=DV8Ǟi  p}lt?8u`KʔB3+(X-#|Oͱ36Cvj+9T:ȕ.hǤ:~СmDK᧌lR9Cz5TWUh z+K`vIwnϧߍ85y2@z5g yj-m4Z r&ċm`.b5~MaɇpMI &;,1a[HAԅ_<%znw!761z`T,^_%<.kyJ?lW`Ӡrp![ʞX:NvzN׭]ڲi)}]&.21˶ϋzd2(ZiĬOt]׵XD|!3ܠ6Zt2j fy+]Ё 4FG*? 7`{*vitHV/N}J-r&?oXl.Q@0m|^P"~.~d{ j cbeoDZ&-7l(R9d'LKͧфw}z2Kne^TSs}dva#qI{ú IN)#Y)Hfi& U [OZO+T@^z5)UB[Y+S@H0Q; YG4ut h2ڔl@ b{f3&Znr_h""5 G#zJS deh |JpK=_OZ97vyA,| (l{db>~uT< ]᝕;PD6£Z=#t8=KPʹ4JId|oIihi"^M/,t;?Ch2)ydy̰Ej{!/[WA#4$oy@ n > nW / oc5p .rՊ3҂_`'c&&ȆDAC c~(#Ve1'\v\D; $L'JR,6'ؑGv^3j/Ғ Fl:@.4mhF@fw];X񓲦[EbIf^KmyrZ ,һ>(1K1XΠ|)EhqZg?oNW\66fKV+"8Ֆ%>`\әk&Zϲ1G[="JKIȬpKOim(`nJ:E_^~OR79ܗ3ʘI&g[BΑR_)/AK]o 󥶌@uf[eU.Ȝ晽M-ِQ|藳EԍBݓDD_\+.զ(y=_Q0ipⲨN-bq.ա4vxmBFo*A{!fC_0J#"HAY<,dvHt+ $.u\>A=cT}Yy@$. v֖Q5p;\0cꎗ0C珉>,Zv$0Au~&v Y"1f*WiAzqYKRZ 1x%wVIf|S)rSGn@mu _Ql@V1l^ȓzc͈e yC2`,EShYd,׌OMcvI,D9"f T}K?{&G8#>Uoq>"j_KTvgE=x}!r ZzWB'Ahp D#b ooA5"6k&*gkqkύn!u/k\#,NOi śB NfI3؏hNdf t/:8r[Z"de3O) L?S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP΁s@8x =W~9c:>$L!qͶ{R?@/wsj9&\35/ R0-ǝbJ[2i{(vw<˿|> \_ bODol <&F_ڞ1nw ^=}R-f]]+]|#Zn xx@p7AtO. $@}gqv<.wlgKJͮ#l̶EW3~炼b1\Ī,W *lsNV||}j Z®y&>=H ֭A)"&8L/(J<*۝J ƻ&QTd].RUE q%jr#>po1\{&3 4N}I˪N̰DC%G@v0מQ?˵yox>]*$mGIz. a>!ƣQԟÇ%v !:ax<"(.t8ַy\n'l@O7vV?GL5'3m\Dpͤx}y@q~j/ '4+?h@ng(EWWXc5 $Ȟ!z| wtwyRdV 5xJ{}. #Guzs4h#Zkfm'klkʀ nyL/$WgH&}S"%-/|m׉yHlȒ;_ 5<Աc?P$ӓy)͖=myzb$*0tsl~[e"*Mo@َYJ.+vqS卽WKCA60#ЈO&͊^ub@Ib `u;h5 >~*qΎ L2ӗ`"b i d'XA uycL=p 7P[\gnh_xҶxoXmvFDZ˕͢ '*^X_J' i;Q4m\,4T{Zj8>PV8koA@s4ՆLrE]ʖ!$N?=Ebbn|+,PMN'OI?=+$%o=Ѭ){[Q;Og#B;㳊R5{v,Yd&` g7x*!;wX=׭"8(^KZv~u4)Ȝ2. 0n)R)ĞT7l#mkęcl@LhF?x/ەi|wG8^rߛ?;[8ʉ4j;|+}L;λer-vHiu90]IlWhb`vܹYÃ+edS CbdP݅[;oJM 9UPUktQ460篼VՀ&}h%/ @(ڱZ1le Uq GX{s—g6K3FI'p42:Cw S+t3)8co`Y(֠9=#)ke{z>qD'=pVX3a zNٛ<'xd}mߚ',Gee~*,1C& ,ʼnXL Aĥڇ %G^TnK9 @je㯁#a)ڶ=QVEW΢5>@\1=r-f:q,7,B9 >E@՛XI0?iT7[T2j m3Dcˉie8 7-?QYPu c9E\-D]qr/H RJz*6l7Ы/hUMck;VuȦEM|`+:k5ĞvƊp.+OPкqQ1rLq ZjjOc9-_O"u qB+iMcCIO8Y.C=>pҮ#|e#Ǯ/odt IB` >ک9~,J7c/>u`TѬhUoyWegĬQVɪH"PԧRezķ&y~]iۘP> y,Dklg؉@9v_UR%wCl+{b8IԣX0.!JF8~ζR5$AN QN3~isjM 2&X?~Qe"',{@ԓU[nmEؑYC F[8LX;^-`T9~z:mhB#ゞTvW7kG$[s4/3!˭\'NƩT/k P͈-zmg^#FKՊW,./^5'RǘDXKck8wkҘ+S 03g[<%m (y5>Kh9+@)ybC{;kQڈ?Ji yz8A-LAq3}ފw 9SV!oE,d 蹓]nQ^RmU^Tr 9$hUuKԦ幋Ur$v !3Z[΄*30&~8k:P!z؎1UrІ2%/x~`Fʽ!qF6,h眻b ׆mNjĬi|Z~tG]^.@ %vӦ6>>dodž] !_l׈:4 yN/'||>`a@ﱱgq|p>D0Pkв.[mVփ}z5ݳ}#W˘w9RŸIdno8鲍oz[!k%W&6̔O(!E_>ؗ_|B|wCt&."?SVCo߄6,A.FDgNJq2ڠuArG P`=@=c`)߷#d6s^mu^ădeT'(2e2 E9`m] 暖myo7eh o{Aɐb`:(3=]sf#]$7ph[ol-WWl$Ub? F)QjB%GO7PWHưR<.Ӓg_ُ nȁii<:*{N7]UN%xv~W$iͽDMTԀ8||>@}b.S)ۻ7rRVF{xw7 nwl,~ᔽ7hjٴv$&7b82e,R&JL?|TuKz-*ez45C/#[2!F6Ii5 Z : {n;  :OtOQPy9<Ѥ27\ZLe*S֟%/Q8S.b8mL8$4%zѿM`ǁUfX| rZ .wrmz)SPxN@jҹMCS^`-g$疸e^!MPMB| g>:%a[g^T4)xq*҇jsJd,׸b~N֛roij1X@5ch~#vaM@PHUg+9Z <yftx4#GV.wf9o;xx]d-Ctѐ;ZT> &8ѸlKQs=S4E_K.xQj%rG @ˢѹ#¨.]SD0-`Y'aG(S>i>f#1/'W}>ؿQ֋~ 4h$ iUϲ%?>)jwR>2`?Tm fTeyGւ 3z|b3n1ӤAqC;`c=Cبʒڰ\_!EE 0KY -5[ZTm :62^<[OU6߰AQ>D~Q@(i9ڱ}tpA,VhDx)BKSzi cuvzlx\ kcFA~ݼ.T/Q gGCH.Z.lylk Ji.=^=f`ZIJ_𞍳IVnު#dMh K;qZUD ^jvp,t3ҧ1 EI11p3G xL+\T8XٝH Tjɀ y'Eh #0~$y`r@IeHﰊ{ 'DhZ3Lc䞼bNOC^]!KB@b00o4OP{_!<E&/g#"baW"BCUPlR\[{Û#:Z1cMx/ZQr ZH@_*ݥ =΋zʬ@`%Y`@*Ű|Cdh SLEz[J. J79ȽwAS΂s̿^YCDSGܥCTuP:zɬ XƠ}+Qu@Y6~n~pU04!}йz7GRsMۜ.)QT|ཥR=0*'Ajҷ-?z|6sFϼ#;`HFOI MqU>\P7^LdD\濸t@>0UŨTs!tulS7#VR4x[Ƣ˲JMfu xd! =Q }øPtʀ#5 efd8m|,;,;o%X7ʎRO9_;>(nBqؐk;N[ ` T_BL$g p/ӚGw]Osl-Ph.llb^SxcŜxoN1B&4ЪLa N"m:ct J8 ^[Mw^u[ ]ĩj&vRmJ.F=d ;X3|5coB>BtR?h\ lr^:k:X%`-P%)q) c:37=> 䤬{JaJ>6zjyhXQ6AUx4uӛRN.g5NXF.9v) G࢕r8F–6)L+#=~-tBHIl'DKbnE7d O"MG/!n5:xg{{+. n> wB1ئ3At8UZ1`U=dM*=oq뺂zZ$Odl &Ox@xB@(EޅjhBLnlѥ"xzKN֢B/2`H|V -'FV| SwdEZtZ~*H}Бc4ˁ I⪜E'nxNfJ;c@?$vApACȼʻgqڶGr4EpƞP宷MLJŽUByM4` n,r?W羢I LՖR:>ZJcWGEbv}<̀F :;ϸO \s=y)a<*gv4suX| 6Hڼxe6ڠ1!DMa_:ZM']WDlw:p)=3^;0/ :v)Ӆh!< _t8>3H"$/7pϨ,!6&AQLpsD&^Pӷc]\*%$PƲQ*%Z6޷-?w\{+Ġ(u⎝֒>uC?i8#!)/s&嫿п1-gqVtixSh,:;;5ū۱.FP qNj_"$dD I:%:ؾ ěhEg])FI@|iS +u:  %OPi_nRQkeHqsAz ç JìuP `o L7IIr1'"=2e @8ȐI3Um\Ws ,mOgJc}Jzռ`v< h}F̣7iH\|LY1'6ڗ.ہxLF: = : x/kbۼHȋ)O̰ 9ǚƥ9vӂOS2i,Eռu(4tI;zڧE eMq1"^St)wwr|jcIYK7i s!Ȣ϶Vpw(Vh-Ϭνf9$v|15 [MB1M00PZNtW#lJYp|>@_}\{zQGr̭=0|\pҐ5)5U}&qoҦf0@Y)Z`r3omXРRzΝ3)BFTl}HZqJ\0ĨO'_oPP,2X8!+ |1g*=IE)P]n$6uXX1s8VR UY6sª"]6!QrTmKLc/f\'^Rwӑj@|8c^+P^Pl+1xfo X[)^QmRkNs;=ڲlDhɰIK3/,-Zq0Bm b"`ZLJ֊ #٤Lov9= xYo_Kz뚍ƙ.}翡i;zθHM|=F35)Od&}-SK̃+:Gy)۫^eǷd7-`p^{863P~owBf1j~5atG£Ipf/GQ{/|PO%({a'']kf'K [%ܒ{ϝr6ONי7Cn$$yiݛWmԙ3R&,dX16Yy?YSë%/p,!|Mr CAgV[g/niRW@J^IԢɀdY5`//FySӾM$wY]O_? g*=Κf<4PL܃k[w9:ϟsiXMGq$Fk?wJֆA_qanm { Xlfѷ!/?Ԫ?~S5ojylHB[`g9SOlJ: uhtFr )u/!00cMI7;Z(Y%tҹ`ĪZ:=C? 6L jkv Pg*pKr.XAjq/Im=I"~d8:*U~-.QR1zA.-$ijXwq)h" ;q``1ܶl0Ԯɗyg'P+|\v e:|VfN>ɁN'i#RsڪΊz_葱}Y_uCwZ,:Z%v}4ļj]zsp|:)|^B3. fbOmlHwkȤ1j^GӖ݌~.$}9@&Wi\iMzm`!%&s'*D-$8U3 dBt{?eZĨzq *I\[RE!#'4~̚B:Pn .-o:P1WiQ O܉e3J 8E]JYȂ@ɊfYX˿ 81 f~(UD<0+mDs ~Rp~\o[FbYBkƊa;gz {/?Vj{bH4Tќd޷%iwB|r5D(_CߗfG+fG;8zkL밇p*\BpBDXԆo04&H~|Q"$F.hEG}zMK3mrT*"Yn V Jyz'#sC GOFR@(QRºFhQƲ`# 0ߡv_e `Nfܭ§,&yBLjdY"(k}Mtm <{>IW~0*a?Ӓ3>Њ 81dGG@^<=} 6OIK"l @ 4/8ػ{CHCkBE)5@/X,kZE vc'"Ȩ;=N(%oɴ"?Jp/KJ:j^׌fiibn{6KUgᩪ(X}ݔ(I p iaPjMf2!ϸJׄpX'.UC%09}~ṞJN\E:;3""H;J)Tb[ˈ%N)DnIfs@$\tGA%_jϥjZs ~q+-.тϋޞAFFJHO3h44Im?-yg-4 y֎|1}W)L+ͅ:s+=vs3XU`xh-N5g|SwAjڲ-jC{t)h _mRob|blĊ;]c ($lEHVbP.>qzxX*+hۂ} lpsc ɯ K)Oi+)?j0HR',ʡRH&,!ZMM,8+$$?=!U*+4˜r1F(-XmPRtXo*B컭ehPӸr>킛 n/c?jɣBP茧V`MLZC nM3A8ov;,@^㋸5[ Q8lݼ/&+z']zOw]7W-rcBE3Cr!5T; ѿSퟄtxL){O\Q?o](1eZdk w)(: +M?A\[2 7lT?YbQŦs}%̍vBSYճtA&_e{:D99@ ~ltQXTI1ԯQ޵\QS" ۫e(]%Ւvv_ ueDBT3m&;DKpWUk:;eG $ (ǪXMM*]E[yB# B[ֹk,BZ? _'hnc{8&QOxqnI-ð57]=I1 Ŧ"B"k7G4,VMuyU^m9L@ތHPU=oF(> K4R!MHۙio;7 {wvLwjsg!mhhҀ`*))`/.4XSr+=ta[G .tLb&yj28ZNk_U~>?HX$'USb3?<CYU,YrEqbͻ7`"q#ԥm0uPfا"[F+gCj'cL%4{ިoPZ^.ĥk-z=3ҽdhq.k1@Ey "fZS(;5 ;q^ & MB)\18tҭۼ FfvM̼?6"SQ!%R7gpY(3IHIL%'gŷT#S0+[ .dX{``khvΨS =a8wo5~ t]DgZmWLϗٽ@_F7LK fcRõ>4NKev?$:6FJ*#)- em2p.цL= )QP7*r?1nwGUyFoEg,!`W3L&4:!,ѓ1<_ ,D׷/A8#rAsVQ8twVPIe$ L:v-Qh1| 4SFʋwh[sň1} "PJ[ء 5e PC%<(=w/n3ƌs&8pa>xxB0nv8`ZV U8c!*ȳq_2 A<r}?Sr[ &̾Wx ј8 =Y%џR!w{(}dFz/~G0qaM.M Ze+֫{iv?fO!*s.2ZT.9kp4b$7C7@, UuIO[:|} t1x (NU UlFSŴC`p̈́haOH 0b>S2.%_c ?)rTSWu*Wr`#h]2i3t 8NPXOƦQr -Dgvm=樱᷁8l hlF R^̷) C1,2 ?!gcjTkqhaȫøQ g!Θ`]w~CFէڋ{B%N|)M?>=M;>x FѷO1goN H{2C3Ah핊v=o}5'F^8aˮvP1aD碼dWy]w*sr|l^B~#sI|8TEȹ)D2ӼG?9 ˘ګMu YDY]|!]z$D#ŭHis0 r3𡄅8?"-dܩaO|jnAİV}!5e]_\tz#s=buĵ?@¨B`Gf=M<>jY]D)A&nMEzU v8UZx [أ; uŌ8"4? O W𢂘e&Pl-ֵQSK\fXZN@!EՏѬ w (!qTl=^HmI" 5C$:vag"B(`s*ua :3M'fArݧEwoa 3 yfO~Qv>J;[@nkHFtbdzI^oJ0%JD  ֱV|";XZfsݮ|)NpBh.HQ yE݌`j /̛?vv_ZO^{ KH5z%?}8B?NF?Z]t4 |O(2(FxQiIn6oA5DRQTX p:\<|$UYגßz*;'ZKS2W#Faa=WHJQ0&Zj<lEOClʳU&"̍ \sMq|hmzaoN4-fMm8ºo:TRP4f!rƵ^+I8LͮQn`hʈ+<؆"BVxɰ~@ h~er)U IъRt A)6a~$6.M4]d˯DDcv,>k5h{Ti$uV") e##o1TM?Di~w@Z:EֽS;w#2U =A)"2IL`jxl!l_">L]!JrKu2E ž(qa~&e*xܻ@[ r .NPt[O/{J SOͥQxn nj'b24c'D-'="Mh߯w˸YAʓ#˳T}Vץo o+%?qMoaq$c3gR<\5pp!IQ "PEmxhkD-mt*2[AI '6EJ#.gXɐh)(58)ps ~oSxv{MBwQͦ9H]Ѐ ̀(H}g7˨f'. ڙ95 fM?QƖ$h@S?Zy'r@lLuu<,R醾i4>cuFV&:H9Z7;ioP'`'G3X;Nh0[\8U:B/QBV_A{j+ w]tqź0UJ!+_N &+yOFyTr~|( F[:̧Y"S" [?h; \| q?\PYNi|׻W=b]\l3g KȺ*Cd[]EWݻS[~F7ua4ItbX:fA3G2@xw!{k5۲Lvi P8oYOG5,A];ևd:j`ʄ96x"nuO@W&6zL;$sFe=((XƍW(]@MnOcb=utH(5m `VcY1:=wDڶn6XL5QoUv{S[)8J,>\kI` 8b$;793xӠR>RY#ϓQi?A$u7mf'1d`߂%_ # IG+~gfV):pYXu 1˖c]<ܖg-0Fs9Og`YYbK*3"LZ deZ O ^ @0V`&݊2|PkmZF<>P~XO/ 6nNϘoeW]%}Y߲ʊtG/D9ϊ)^Ի7ee;o*zTyypVp[DP%hZPAiL=Ojd&ߑ6ȴpX'N#E+H_icG;}9ehbM'tWdߥVdJs/6Сܒ!({@x3ũ&Ѓ5aܨW1n9:nUά,{oRe#㔢 rx^?RoxL[&Ϟ˭OG'|;fʝ7ԗ1B W ul xHqAnz3;0݄3G v&ۍܶNymH 7-_ܑZ{ӹq::4m™`b-'y gno1.3I6~Qv.;0KRu/%7yPRCLeHw9r 3 W2RUʗzZ:>zRJ 8/ťs-i~}h'ӛܤbFe H$,in!ۣ$ Y -][<=Pk֩=Q~H8|RU(% ?!L2U=^H W7E{*w!ʬa &,% OryG`97b5.dmoG *߈X́N%(c")RM4 GP?!/["||@|b1B*{S!^k-@|iYHGa3cp~,r>L(G,P6PwQM⍣ 2T 8ߌ%đ4BF}QȢ̞@i5A;2hp>= y}`Pg=YX7H "LD" nk?*|%՞|zŵԦќwS.lȾԯ1)f:hI!UbkwDxdzo!!ى]?+gi}NQ8{-!phebsl)6 ʷw̬|7"M(2~䁳47"H?L.LFޗ`K)pR1Bz?$ .$Y0u}֗^pD.sv'察ǗP!IѶYw~ L|qw1j  n%RPQV= )[RVsbw5t1#d.=lw&U5](W;FG|$L@V%`O\:xyZqu|.snk_: }k0@XF\!:ЮX/T}$|zmZapU_ۆ!hhW@Ȧ`tu^ `,8oL9`9yc͜U>S0c@w|gꕔ]B7 d$L`*T& oɰB(lx[Ⱦ:{֖war*lL'0)WfP! QNPt uE kan+CSuMά*߉,$pGs拉Ff ލ嚠!}/yuGlBOvC<:}O,/rةݧxb]ՄASi%qDZw6̬LV݉ 8_>=ьk_KHs#l84i{}<|]DsS]eUC?) ~p&oW<\i=WDuu*Hӹ|xȂzs"!GE,E:\. ƍe9 '<Ln}AVMlr6$_;\7=!E|]?ܠ/3eㇺ0п eb *BjIKP܉|X_$a2+l:l`u ~N`hx存33/ɮN399+ҠvsZhRBlqwA'>zwCo;|zMuo)ds{vzc-ir$8r西XUoz jwm ,ڼq !V#𦵳bO)Pٯ姏>̽"Çh32q 7 hy#bdP,}J ,kus\`-F|׮]\0/IIԝn]jM1LJӉ3k,n՜] 5&bi\q;kQ~;տԦRQn/EԎBI 5xCk@$(==i0_S5^q?ar (ܡ_T[< Ċ$O| &)Uﰿe .΋uۉK]*.s˚T5׳±';ma2uTω#S! cM Uا3m}Kӽ Ā8Jnjz);'"3|k[-!K 7?9"Rt T>&]aM=dDCP3 y:juB*2+?8VyVڻkBUػX=9ו~`YԌqcU&S-DF~}$2ш:>-\:H_2vn) @ :V։M޵1,2.VԷW:\}f6gx"d4 <–bt*~ |wsΙc)BeŞ%RZW"bK.m<=[Ü7& h3IlZhQkhr[_L !Q9`296<P}${;VzgЪ~ByL/4@*{7H /7WK; VZtIaz ŵ,ٜL][[Ys1NC`K9cjpPs7՞wShOj |UNHLsoHu0Bc.57.DJc}tB՝k驷A3a& ϲ=Rdҽۡ/L(;8 Af5 vT2튩'Q(M]!Ƨ^ǚq [5_vt9N֑#UFw2~5*r&dUHO "񹧤W[yΚi&ƣœ+er&D} N_/zJc?h1 oUq_ᵦktU6|~K<=ȏ@c{͟lq0FȟG !-T\h DVw+].4onDňNO0 rJaprqE8;l3#dHvVH9G:lN90~~`P w|;a͞)P^oFw qHhyG `/ B"fjD1) UgӬu ՜\KL'W,aR¸ lqcVuvF͹Z+Y7k$J~{3h(@:v%éh9pH(nc IY,x:N%Ð_4 As{p.=}8I㧿dms#.(9*Nԛ=21yAb=i,n)__̷ T29"$`rZPĞ#CI|^Z1usPDbn=%%BYgkAs;0ӝVEVh2+ `qL2otL5qb^&(m*nG {}!ci:%/'m|aw+6)N6~ϓC_;:V٥_pF lWcGU^=&Kêw(w Oo ?=|LCI]0֜n6iFv 5@g#FߠVLNOa8?ΣyT4ɶi պ{@.B~.|K?["Kww#xed @N-čOYOʮQOٵ&9}ډSdZH1F~@pG"@zI֘'ܪEUL~x3avE`M0]Kvyv&fjt1-u@#mX x3,?d q|@|@|i #{* $9'/1+WdәCE٩\ciNtJl n*M=l9Č"uٱp>;wqkEW~d 4ޘڣ1_D(-p WYWp=`!9s>$5ݭLAO+A)fѷaX"0BIfjY#06#s[?fKLQ/Hs ۩\+"y9zÌx_hҥ,TyL.2 w5W\勢>{,Ԅ]le;] ܰ=GxT͛`d%'98avr}gl?Whș|R:d|&zvG;.Sh*#Bt֢O<+B.\ sHm_:Ss`"+<(_J]Vr-1\:!%^JpC}x_C%3KE{|jx8h ʒMb\sւ|:!SxO;nV +'={_54?ETQ!tY%a|݇i"fRTϞ-0p:a]e5n6T3zJx$ )5}{7d*BY`\VGWFcTݡG/Jl8Vf/t8,]F"2=K1no^Յԁ)?c B_!C-+lgmX ct_W .. ҿ/J$wK;i\-o߇.u'A (F Wʱ%ÕO1љ689m`ҹg+v?UpG$̌,qY[˧/5֙/4dVUJW`=vQYgpWi"XN 'SxrL0ÄI,n 'P,vs_wMI1ÂD֛mmکmD^ ez}JTzF{ jPbF+vMqz٨vڜ}kXпԶK%50|TI-tTAO0$Qv#Ol%nmT-VmsV0M|!ʙ*[E=1&F3gA=E@QL;ܣӏ_rX~d[!ՀX]`' =J"2KKЯhu(1>-[d2["C[\/u3]fm7(B46ίTp7w J{Sw|M3UCZ+‰BJ`L2Ks.< HXPGAG29n, 8:!41񬠢d~̔Sw욜p A&[~ދmyYw=bh;CDV$M5|1S&>5_ y`^oseƁy[w/&Ċs5չP Qt9^ &/Kzr8;.>!iTyRJ9V8['a&^ܐg3y-JfJ\g 8g,ŋ'<(~oe-6_h5i>FKqw?xeŮYfӀˑ$!Yx"\]8Giz*3܂YW*g]:BxyݞK/O/7y@*#s␏f2EwHݲIf➮**@/ȭB'BNyϿO? Ug+<']̇IFӈhy4̟g:Ra܄@,ؙԳ~ -ִc&6658 FδVw+tm גq:c8;$Tċ#Ԕ{Vs|&uY(X;VsfJ?_(ylc|-җ G$k'aE(3fe5Fuϗnef{qdrjs-5ġCgn7G!GiGzޝmԤw7JBRPas>Yehlݍգ㼉M40d1ϧl+~Ŗ KC#IsVRSg6WU+9D1y Wa`;OfOY : S18`7'V?hf7y]v i;6|-ƒ@a@,.{dޚ%s]z\KƃO>h:H>!6iH9VpU#'9%j8U8*FPH0d\m%"!<ӀG9l7}A#:p8_CXn16KҼX6Ǖ LdHqƪ#ֵ w_?:٠`eSqCvh '=} ht]X -ö|9L U 'صYӌl~ڼlqvaHR|Բʙ-]#K9p|1/2FKL[K.sƷaǭug ZqֹYv=+`hߔCFLM"P~ȼ[L+{nF>bo 9=tg MaӺJ6)֖ItN0Ɇ'z}tF{(2ָnJS!N;zK ЬƮ7չxʲCH*wygénȴS GBcc x2hgZ^ q,AB*J!nWֻ`2skfB7N9<1u"56^烫vɥdH ]A>8H(Duͯ4xTBxΕZ"ɗB[_ |Calq+ w'Z- (u:-{2, 5 Eg,!,[)gqJ\FyUyTNr>،o/Ԡvd4Fx $ fF3/{թ̹TDaVIrY[O_ MC.Wz=j6K`2沆Tӱz7>xwC&Oh qAWC̳YUNCy"ןU!FKw ڸ`k ܝb>"f_Jȩo&@kۨYdpNẙ؏`ΔOx/|0c؆ڿa1 U6\Im5s` f}73;ڕ8 Tom΄1mc,BT4EcyH./R~[ hA =O;.4}m:4XI `IXSHԯ9g#G^h3 N@eS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPnpe8h$N~~צ6:>@!&– ѶŪj"o6v~ (3Eb{f9"n~p60/+g|4|w,w;'Pa5}r֨{H-LN&nMi%x {G|ecdlO5VC»5,?ڈR`2E?6X*u1SDjkt}U 1ÿRz NPlsTj1WXC*P0hЌKM"۶HEWY؁^z~+@ʟn :Jƻ]D[q Noo¹v00aa+0;ӛ(x( $LdK |>/wPtLSKmmWmxff6>p;p FҒgdJ|xӿfY}}𰱻7Tz=OBXVUjsR=CH7i'/ 6Ѱ_dop|[E݇XlB;f:D 1ïM:|Z/QLeN" SFeԢWq5Hr RX Bwh:l{Y>=W]vҜo!Eh΃"y[U#[S1=LPAZD"]ncPk4' PPuϠi,[1ppI:z6;OՓ$>@h3xݎYGRrr翡]YXMvd"!e͆U, ճA $ٚM-G<Nkh\r n/XN kTxHI0(W(#,hCXAe S.'}|0e ==BC^$?]JR%%#QzL*( _]b#8I Կ{Mۼ8.@- -ҙaЭz( qGMЇ: *.B&us%?&SPjBݮIɅ*p`?^$ yoOUMFfawrN ] )eZ._  ̱ +-AWNn]W-r )!Yp˔TSdl G>n[+yT5ڎ1;Z)FQouĵ'b9zfۡn!9PInT|O`̬ Ib41c[FjTu=_RKcm@!%biTʀJH<VSf&nct.z'ǔ;}%QE( ~2shFd<\_)J {W^<íBVtyXĶX mE0HJO $GNV}2/z}@p 5_? 496xw"u4ݐ=ّ``)Ua }*mK)«)_0DmnET>`E |WRϼ>ᷲ@ )s Qt &q덄n﬏=˂]I -Po]#$iQDxW/* LP^StV)k.qJe]ˆS$ xqptTfzN{_$U"Yl\ jrtAA?O:RwøH=M?0C@ب33 A@7DBdqe Z%'H[ęKSއa3X[%U/l|V1c)sQLc#7 i:+Py&ܯZx>.QUrhӊz8X"8ޝp@39X֠)v}[{(w7v*b\+@Z=ڍ}^ok8/@7Aսʳ^+=;VͥJl` G Lۛ5Q [Pg+Q24ٳV;Qء'93xdJDrݍaf $Y}3\D!Wl_]NQ 5R%۳Sځi{xgxNg=k> mb*+CO+V6?87%)zNe/8KWcnA=+V7âɈdߴ@HpbK|e;*3m !*,EM(%p|a3%;~ քYK+zŸ/ppUb$jQxE⹗tJB(Z5;E$GuaDε 3ڤo3_UjԅT0W'n|6R"KG1vN ^ C?$eҞ)֓f4qa/)[u.\ q|>a—ؼ $YTRz #RfiG!G'Xjp MuI:1]ĎTGF@tWÀ1cD5Z4 4|h<' owKIiRc'ztl̝4Kai Ֆݨ eFzYiSNʉlU,C4Fv$*N,1eM5J+WD. »:@!cB04K Ԏm(@&`)ț1"-rq9\c=z;ޭ ,Hg{f*4:NhIr?lT:Sj[ݳz@hqTM\NnuC[Wա;s$a3L9!;{C@9~% _z<_lu+TCEș筻,olxŅam%wZ66U4~3naN| y:fȧ%> S䭞‡(guoFILq+k3:wb-)tNZk _X#toh{,tbvFwbI]0ܯHmT41+pV)%AdYTxJyHl}:ivVplw}uCpurRnp +9c@rHE9ͧkxp G;&wDV>, kPg^ K ՜\(a= Յ|!%O ޸{C޴Q7{;Bd7_z¾V @Lǜxc+dSdE)A>ǼuyhݾgLN6[ %ȱc/iR:-y7<)VE@Vo%PnpT$S DG{IB+&L$'X-G 1kYX" 4݇_AhoΙ[C]0l-_yug8ZM9ʡӌ+5Ē  ?<b⇸N @ ە jX"a Ǡk'īE5J{2EB3T[1@G! ?_YB V6U&y{[0rU[}}@v&O=dN^@CP w@..C.ad : ( }nP&yx`:,9^DW4yX_i<8jA Ѓ,C5 W3c\gFT(ϟ/IzP֬s:$#%@TFM"q-m21F}Q:Y``HuCC< %, ,>_ xyEz]mIߠkO=(R%[ŧIsbF۽'k+m zX?xln@|7i NiN ԐAPYU0=3UT!5SN B`Bl$KN| M6"#3Z.? jr,TIʬped| + գs <8P}JC :'޶юRZ<`k tGnY2nr[!#1ٶ7W +q~`c#CnQR=ry7rq1W|[]-~g0C둮Dk/d(&Ff< z4Ѳϼgs$ T ag٥]ŤZ>"Xpt7Nto_bBa,LN{%4dl}kow#;W0 ;{-ᣪ#A5^Fa |GA/?QAy+ WϏt amXNd4PX9ipl.'Ry% *eEi$s!"G[7u[Nc1duc`\Y!.4g> E%"m8m'juUs,㲅-AܒǫXk - u6833C?_>L*[Z0!jU,>8h._~:svxj|P>e`; 2q']Ft|]dVb DžiFgȉ > $; Sʲ}=?x 9hϻ@ldM\S/zo0' .>;~kr(k6dj]= ??'lF>RN rMk&KNX qT( yvT,@g,wb!iR;-ҎIC9s3݄dw3yv dA[/8H <2ΟrE\fX\x(KfMTGZUx -b(2X6Y6oV,&ɷ.ސȤJ|! u$jg*Qڙ7IP\壝V+Nl&ݕ%]i`G.dJ-P&8^ r@?&b]Ja]Cf@gs eA |>))h̓p;:Cʅw֓@6]*u".s{w3r5VUZxfg.׽yo"ѯג2Vy;},4,V@êLsKJsw)NOGNQo h%a?{sTlT@)x89fUݹYlsoai `c|< sB)WF9 w(I+,~ +y"qSr[=qPMXaeLg!f0zEV"ge>/BCu:^$t8Yt7X:?,navA=[̽y4cW9 9+ڍ%b(WEZ%kil_07fNQ1);hUϣ 4׽MX{9nNTB7s:vݛ?@,qenRX08Nlޅ3~DA=+r\]?B)Rs&TjÈ]뎖(i@(e-ܬۣAIS1) i ,߄ߵgҟ~%(ZŸ 9_"2ᴂ#rr FlEuN;JE V2$ H@4Pҕ|&JkxP"![1-G  DŽībӢ2Aլ)lDDqѴnMl Һt>CDr?̿h7mR8F>'jLg0+w7F*=AIЂ\ ,'9Æƀ}Lpw˗0(,OѺI/Sl}?џL#8+u/#|cGPtHEVAc5dN+ϯ& rf\f@Ҥ LRh└,A" {V<t]Ijߏ ,Vb GOqlZGxA`φUO98p* `1r=UnYBpWzwuδMA(7zd4ď6)^Jb jϥxa$wQ=/~/z2D~?s , HmSԻ=cs>=jlmFfi2l xUDMV_GsvT}2$xAӋLߺ*ٍؙՉkqG`02_2:6\5`7Gyrrޣ>`~@66beJpv^ܫ?K7NH>WVA}1Әӽ{4dGʠqӕ Cӆ>>.?I lu)!w(؈fjIa0"FA7-cz!OB, zXDzx_7a_RLAQD)Y`·a>K]̢ΊɛUH(,^+fޙCh g.6]Y?JآuL6cW#;93p7 kh["vh6x3W>wȒO(G^A&IOY| %?yB}pQJbD/OQ,#CI4/2G\spE]KN24^Zd fńtko݈vam%2aJQH($IiNQ^?{.M_'Bm5!iNUr:C^!2lo ~:yHG0T&cfaxfY*&ֈxBbYr&-1AbqTc2BwHRۧUa< VCj &{"4 ]VQΗx iAY(uA6D)3,Wcq;OB 9B/cݔ̢b/ėG:'H3qD=UnEزsT̮DZ~[U&*.t*lu`kF kBPg<{S@~۸?_7Pb&U ^1V̾qqp#Kys8E"o[ܢǀዟހ;yJ9FU'Ggzf [m_}e~Q!q~%5Ir(a6G/NjHVڈ} `a7|D1c{Pc6?@X&x~-GBԏhr!g( 7v1(֏5F乹~yDcC!;@*wi&(]D![eB_ف_oR;˺e} 4 .I@w?Ilm|1s>%Xj00Q K:L90}qatMeӃ@ {|hhܟs >8>G*@U5'X@3 -ؤ-3AQP Rk+#vgZt&zx|jB(_j?O6y~5/m"flZquvء҂U g ߸gYEzlo x0a Jp?:KbW7UI:?OݐaBJ}1OQ8u#jqF,`8zZf73IeݺTj( <#&64,>Z&H>ӈ4u2>ҁj\$Y!"npYCeu"7%7"yZQ^ƽ? *y!;(ZLH= Mj8oKԶٌit@_i>p9EL?}}ֵ{7ssh!M-Ј4EԐ#r@~ntx^9f <>p~$[&,)"}Zƾ5ry݊2īLޠn0*c*)(Elڙ-VN$k~WFS=PhA UTR5Q| ُ܈ɟ>}'fYb#H osmTI[b ]\Ue{-+UݑL0'ߊE,j!L fP-kihtAKu]9IVT%_P3|R`*S1k[2IyеCl1ZItooƘB[AU;fƤD83EolPq(Qz(M1ջ<>c"N$%q9bKp݌tAJ-2eGw*x*UUx^О !2Y eq;|rc dTGfi}T<@/2Z1H*O^6L*)!z)®=QhbBײ|,Obu1':V IXs @,`́Fvbx Ljt!x}Z$sFmf2gֻ;h|6="Lt,g'>VK.FUqs$I'%>-^< *F5S4xHV(b&"a :{I!9Vɝװh#%]6Yo#lN˾߉y #BQa"kj~(c33~ Z=g3io@g@%n$7}f>!^BR阗*]E̯-vhy= h q2f3"fr_? ^;ұޘ}I1feH|@:<Fg3Z#5"|>3m8RՒPkCd@CAM8Wk(>*)CO iqLߘ,ߚ~ HFe;/7VzmbÎ_k0>;y]xbՉm Vyds^`E+K="Rdf9-]lޖ )KH![`dLiXufu@s\[^kĥ/%BξJJFf +6JVGIJvb! 2CWL p~f jZCVgM 1D\ܵk=w$~ &PE7LsF7hN7К#9z)J5A(aਃI+N%5#`VvV cKŕa3{W+|X}N}@ QNË, Rq{T_햤k[&q9AR´q)v*SSE8ە6APYk@,p&+!3uz ~k۾E}7U79.Y\+jB$^H\r\sќJo# lOv ]8 t헒3vjF9}cD1]k*U(`#]SkMxg`D}­J}0+$WO=~p'E &.vCcFopr'0iֈmr#7XӺu+紳9TFwy4Hww V SKh8`MjN-m58 MЗj{l<1}2L2RfVK$M.3{ Y!G_g3;Hpcn(v;`GW޿tGجH_ʝD|m*{Sإ e I0 0VtJ>Umzd q U^ZV!bR]V:^rOC}37{ٟ!F ;E9A?64Z:2d'IiJ !0IM: VE8%G hБbN P\:|)-ڕ QLb eQ/ID4Aw0 [㠿!վ37ioH5F!0ċ4x7RLv+#/)mȗ3<;4#ɋzzz. 0/3Um?2HL%q/}AA몦'"5g#J$f(rk vP2K2g<4h*Al)\ě"@ceW}5{tݞ+O_vG#zxKϘ#?t+7^" EGGtCQ;r% nme4- EG# 2?,L1ѩLf$6ykS;ش k8~DE"hk uW3#|94khs%d!{ƒyQȆCTC"WQ4CV߉֘b(* ,. 깦%Tܟ{0~=s?㊶` ~`H߾tt&Bp˝Y%^vҽ%mfzCuB᯵r1-S ]gdmIAgH@O+D ONHJSwy 9 --L U#:Pj v|-]ʶV`)&&i:F^@RS/l Y f.|ybYlJ W{ qĩ.돿1O\~nG#fsF#; ֣E4+ح.eWД_$>e7yd3>V6yhc~[L=1  $s4$*up*?q ݀pF؝ "(*9㏦LLl$ Hޫ΂0Yl*ɦ/W0V$8tV4!m_[ ;95te 9CeRWۓ5,D«]8G Ӕ{;iUp`ޢEeN"\Y MBu`BwVÐl 9;ix=Yb\ydL|#, /8]%]8<4X9xSwӟ eoc^Gq;%hL.w͘lCoN<^26E2%;. X^n an"j<=гsSj|8: mE>N/ YiSxX%,W]o(IM) G#QtNu\#,W[-:p)juCo?sU$m}_]7^{5Y‹`J:Eb%^ gLBb-"ڵ)0q_,Ph?cWQy>A:vW̘G Cnqg:3MӹZx+p"r[Phk~L&AQrPO up"arbbd?OeȪ҅}x;l=Ap$m6u%~Жp?tx)"cpي! !flǿ_6QB d! =; OApS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP!etqW/F `@0?@qK lS \ q]1U4S|-v9[QgdiNZHB&)^D_yG r97aSƀg~Jv? R~P_ GaϨH'o RLJN7+^},*zOzx!6 <79XػƼ6^d5,ʗ&k7ZݽDi=Q*"R#d^fe>(kCJE'W$?n$ ]H';= D}6db062X.CE 6-0ܑ"]AI5Yc>t#^CT|dHpDSEt6p[ub,91r=0sR<>UȊ3?.]y:-/jqj9M> qULqv߀=0&̅Z+];lfr0 jnT8ɲ-C=b7+'oC3vW+S' l98JR=%i 6`361GgN7ϚQp`Mmij4_:=XIYM҉f͌uhW^89w6ΦS1^kh'aYk. m\vTǙfHxܷDAcX;h >)AG-p.(VV;Sk~éSi4'9ayn8ysiY1u_DsX~O o֟瀝i?''EBcԱ @]e]e(wøWV1+UHp3NET}}w]$D_8po7: ];L db 7^(8l;ug0!J@m$:pv;r)Td (|7:hoʔ=$YFG֊?œq&# 䱶yWŋ:@p|y۲u\{k˔+ 3nDfej" N\ڔ&(P5d'*Gnl\qHxHDnBɱx^0yX/Y2Gcݣ3 3>׺($B_E:?Q_"8j̉uL4PhaʚJ*9ĉ@b }(cZpO**Z XG }n2СF;0TNTMGp}u>?f# we^"+%`XE]| :L{Sx.gr4sGHg&NwZ_e 5oKihșF~RUa$\!?.HzeabL>QėPwt7\TT5_YLխTijߍ</?j<7K|Asl}"Œ?-G(&~JDbfU?ϙ@ ꁗ<*k-pOD0L-V'H߀oUx =IWGR%<XmpDcqSj#j]HsxDїŹ,޲jNY$"p3Qi4W]iAvmfS ablMGnzӼx1Gqbh hkqF@QTAa7Yꦪ?fv .Ju}40@{)2]>jN;!5!2*´6l|\۰Ja>@֖:e ҋ}.jJ7=+ԂS}S"IB l :^u(Pk69, g DwTnv;w!&0ߖ~^cea.Bd&dy0v/`%W?v_K{uGL :EG|,}Qt$;= )Brl\f%Z3|eC<6'1H `0]{Ǻ.b)!1u 4oD.Y"VK㎒oʤoZXxc U  f?R ,ts] JaF6)(/D怨v͕W]m Jz{v-#@.?v%Ǖ/nYȥ$O dlu6mq(6MjWٔmPX-44pW(\Ot`7ZcnTjx^u=!SiZ?;$TFYs3&=NGrTt.\%E2E8ǜuGicтU*V!TXrGG.vUh_kMLs}2 _NqUViQYMVWТpb9+l &botKgMUo>P$Uc?^͹2ET5wu|5iAZ?\]vzč}fK;5XycZf\/?Ymln ( Qga:l$Xby793Q"423 ?Fb]T% R\aaGT]{(:Udxʠ>#ؓT-T1n9gHߚ4ߴnZ.dt'>/D#Cv.\uS5Z+A`ɩ*>]-gĠDĈR6dz"x[KV:#? 50Zc` JhPW$@w,y@Rz i[ڸu)R.^rKi{{ӄκ0I2wdd WH`y7$$ς7c7pc -R,ST1n Mzbjzg0^cq1u N2ֱ2pU6|CF@Ru 3F(Rjt 8'XW2dOQ ,ѐR]Jq AY@HZ)jN>udPX]vWaccxP/.Ioy=ͳ>3q~]{(ѺsG+ PW_3UwEe11a09݈j<(3^KRO 9LqLX7(ɍ.x}즌4Y: EOB2\?2+1p-Ro>d[tW|=mY%1x{.2ySHWe`xMjWMHM%q4hљ&5֗]K$ wŚWے1&CH4'6M=|uc?H)j2C_)!lk {谽(h!QD]kT Qxi1?׿1 ,A /{Z88]S+*+ SN# *Zw\n޴n?1e]욦k-mE؆ۏ7u~1^(4"l?s&-,Q:Jxļr (pD^| 36bǿasQkÆd vdELҳQfB\SVE{57!ƿ_y E*] 9|BT` W^WNaùʆ^IoR#R"C} `O!0GL 9rU\nMQ)gu_D)?v dNЅv"U):!m Ev!" `XERv@ [ʃ|罹7PG7{haе5 j!>-}^)҂ͭΤ&>Q8;Cp`cae{D}81]MB:EUtMX; AuG-$W%4|[`o>Jdzԩj?%B e?$ރp%|+I`r3'(Mg,zx]exgi$ ,pc!urɖY)DJ5w *-3̟1WX#Bhjmv%ݗvw3AFcf\|PPytcjƧ*%c'T.% w!j}Ȉv[h~|V٘:K+Lii6oF _"m!> >ѝc(>#y 僻8jz] Ǜh/-&5u?#/Z=XTSJEuh:Eh8_"hnT|懑Aӫ8/V!k]g-fsW6HUny-;kփ Hl/-0ԥ9XAz=C '@ 7CMǃ+1*Ǝ aS$`tjY1K@J?ȏxu**UfMɲؒ(tibCQ\J 0xB_pH+|r.NhkBVC=fP ";|JA;}ܪlIQfя.hk,s+6_9~NjM E+>gL(qԸt@Fϝ3YzvaRr7QP7b>۫<}lVo0*2WƵ5$q14u mPJ1E4?EFӦz!Jo)މTV󇓲0wvvCnY0n7%At{LOU `괸w ur+mİa0;/4S߶ M_>~KyIR@/\ ^`ĭ_ߌ _o̘!/&r7>֪˗X4qJB#tA*K s0s̓.gNvA)]Uϱf9/bڦO\]CQ@?2YѮp1A3Kr+uG˗à1m-!ѻ|T8൶vU7@ Sߩ)A6Y"){y ;$YA<տ4m)dJ@ǻ}FE#>)P9HQGuv (}v_U|ـ5b()z0f{(f-!!pw[5hD뤑=%X&:'IRFt#hEzѲ}W1.3&IG (x KgۜE[z&"xVb|<ݪD]O+xlE"ʏ3#r.,bgăi}~HaB<8b([UjYs ɬᚤP%*d3uXK]X˴8Jz௑\PBǾ$%oP>0aCZ'p"#2y>}?=Z8oDW˙]ka{%s2h3ޘ#W84fXuWx.kR6Z#Kj9.7sX֎7ysP6Á"]Ef+F3S?~zQ=1l|73mITx%-FHMȴpbK mF.d7FEOL,g©ma8;ψhW#N;4PAqzȳ1\wwͰXxg#2-#.g3sX aڦ:/Lx Ȑ $9甈(CX.f}uҧicF XBξ w_.T=-~pazk~\7&#H+'؊٪J<Vluԅ^q1R3SXy+[#_o)0t m uWp3>e&W)",eڼxr QbƵyZZ&{Oe<0DC_Cd;Ц0XsknU*R`sÎ U-PeF'8< ]]l֜3^JA4vˎ@RntAF>#|o,un0DAocΩ9k-9?>Y "d&i|v%3Lc{kx?7{OԽ|-֊\v`23JTKPlJ:ꍖoH4\tz 1~fhHeywEe,֎7 Ofd2\F".Ud=Ã?[h8zt3v@-CpBo#O S-( sqO].xlEvZ[b-r3>R^ol4 EFJfK9 GRGhSd'd?.QQ";/,VWf(, A> y]ี%0W#>ֳ8 ~Ь2xPDx!7 rPn6 FtvAOĶ6IjDRU)VOEL- U l5:x TⓟӘĢ" 5X**U>y OrKJlGbQu"jZ_gJgy{]>Ng"5ZL.\5[-[F?)_@8[mBDL.Չhs~:cKj|Bd֗B$Ǝ*;,A.21sx]FH1ȵŸ$n2KqK0_vo  $,H4=IXsٛ3C͞"2>' /MkR mdw]T٭@VøVexݘE0>g6=>, wy8@$y럍n;[exixyT/7,❯lA/ɫww Ŀ0Wl< K[QaLS;*V 'PJ#c=Q_;qzd9e?0m.!;fty  dO-O>CcmQ ԁߜ‡7)>2pC-W҃^x H]iPOjVCCL.'Zn"z`H3OyHnA[#! #af*U{#&]{Pan)4NCMrL*^LGL# M4¨ \~F:zGXc:G_IK͝ DFn@rNd%emEG1rϲR/I/fqAdܵ\2ٿ![yKL`ހ`d+7J>'6N}( #9ph7րH6{fݫ lt1mJ&nⅺv=ג]Z V6!+MxϑY[ܲGz͡$_;_mFI 1z7bv' ɺ[/wP*~#V~*5ݱ 2tY򽂠zK(!B/r,Jr<ڪGO Jۇζ!]% CޜSFdYz(˳\ j[ T`LN8zpY f{#b1yIw)Ás EPn]j1NY1+2b_~K+R݊6SeEI4 Ϊl4Z7Ot>JFx yw6+bPR0dU!P7~dq7K֣AjSy"S1~c&ȏ@Kotd?xF~0w@ D_Y6 W Oǯ_ `? oƌH(gouAk _  M(2M7'9:g"V&_u2&b.[g< 'g./y16+?A~2_d#b~sW~V?Fd*3iBMCvhm`-WoK#ʱL{ *Hmpx6:D*<1y[uiyq{K=s8!)ֱRLPeQt׌0<筌8`:^81J] #畟q0ôYFbX&A Hut4蔣zJ)`cTu%JL%B k/ָ[9Ӆ<` LvY:aP]Ld' 2y&t$\bVa; d 5pKE1u)_āzge, 0=wlE1TC>!Dλ.Jw]x"QEAX'tzھ.y鿈5dBǹ> }(;> }u5EeVРOCI{^i~cݕ. Gbm8|)G0o!'kSWbC'*W4EK/8DZPL+R"| )`R^!ſؓ>^/]3DUc|>BClΈƆo2~ E,[rԨnՐ=^hp i-݊yzYki䷸6"HUˮ=t 1;]C򐧤U) B@(BM_DLw1`JRtqEXs-Mud2_7f9†!Ȕ|.2AU>)ʇמjg9 vG k24 [J5pABi>6-[1G4#bsdLgR_fV2r]\wnZL v,ey4Ĩذ|Tҟ [-n*E|U]x^gPwwjb"*ua:to|ɺZpdz4;Io2iR~$25(FlvN|f*/5!oYX{tNB5 %]Uc5k=@qF3 qk!HA6-kv*[;Ob#C8A{jŮO>Xaj^(1Begd5f:Ҽ-N0a@^?acA @U.(0xqR'T_VAh+rʣOۊyJ"v]7WdT2y ёOM 2,Q= #7ՖSyW! g5kҦ(Y9j|ˡPK5}U8P]8!-{> ?S=~'|5?e]-x~ t1[vv/DG^o:ѠSd5bah!+JbaG@$),(T3ސXty!NF/|Fȯ}/TkX25fn3 qu+G^T|0`s\{jHӲ 8'wݔ|Hp+GUc@\h7Kѝ|ȲE8]U vZwYaQ* h4=B/~ul(g(6iM)@r/4,Oq $p4Rqv^gXM!0BxJj:TJIΑYd( Ng3eE8( ZyCU˸$uqzR?/4p*aJ R7Mȱ2F©-+a 1ߨqջqefY+鵸bCBД0j9d<sz-~k֝h1VPEݺf iiTx' 4ҍNY/(6)xw6xA4I'= 䧲2-&߈rO fRݔ +wxn04\)Wa .g 3cЁ(OY"EۡrUF@x$k+r7uȯ`Wq{{IK>pLg.h#w{mDtj9JxyE,gaa^q{Tbl5#Kr߇uM&Xֹ*#l xqZ\wCK-kS Sp:ǭ[W7&tZݑ9~pE{y0%%"fӈPHGYV!rMWylUsFK&=O/J#+zS\ixӥ`![E]4Mu4 Ema/Ҁ u;׼f},\_DlfO.4 +#{⇄<-i SE֒Ꙙvo\ʿޔ~ qN\N䃢 Kj7@A ,fE^^-7T G7ԛJ6!S{ ߸C~JBxʝI<8 ;qҠڀpzS$\LCa({ol-^ΜcdV JioL[ q z_ťr鳟\à7\ v`G)\l8ϧY :8o3y@A_'ԣu!ٳVGoh[=}3^8m\L٢|Uv 'GȻJwwwȑUZZwC|ϝC.X<({܅0tXMT2gѕc0bo df [L~KV%9TBDFMǝǾ͗?<=f!VAkoiZ7e`Q0= SͪO2-.PU`AWP}b+ԇYu]H͘[XM¡)7E{rE L%Jr gQy%5.ppaICx=Zep=jq"BQc42Yav=nYv$={t &r?w@uwzԛ܃"foz2[d_# O͇U:{k[6=9'ٌu:QsQS{"i<-*[b/papnU&nH}y~= ˒1K^#w/IMMUVx%#jvG/j^.;ήud9ؼٜa%c>!&0N>5&CҢgXl G"%@Y&R sZc(Gf5ju PA;S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHPkz 8hp?oww uc|*9Z<6/WhgqJkc-;c P" !Wd<'4$vR&3@$pr6|; @|wX%IYrI;?=ᏊR=9# `rӄC^^9Zo]3tsJL)/)^.Qu \NŘ&絠A~s#:tƎH$jdZᶁQb$XM*6'gRˆ3i n(yXl4b-򤡧+4lb3- qadY+wޓ`xD~>M)?__yD`!c$q6v6|>@S00H:2?)ÍG7KY.EHP:[[p{Zi3~cDqY ךA+P _'uh 12Sj]yMqn3iqj,9<37j)VKľ";6DJ.+ ;LDp]LC|TSve!:SIU?h7DB<gKm8`49ь?I+'g]b')IUs K(/W >ٕQ=K]Xs T@ 0F\;;ϲ.0^UXb4 ; cZ!!/y<jXspL٣ak*)hT>6qu @#9 }Ml݃2ty=zRaVG@bGҾNqZrzf"}ATuOO#֛RN ԵѲvXDϜ$2t1f\xwѮ|~zW9m{aK+f3M afS03ѼJ$ q4BT#i[r"ڠ|1nwRfS7KпA *%, +/isJfĚ^BSpaѠ|#'۝=yi6jMAT XA%aGGcϜ5Rh ruQy8{sI(amr}nZ B/)4¢ GsL8ʂ̮?J(R1c2;u,qs9ei"?;jh+u}:2886 * +5 ]LKkK׫˗K} Sύ2(3E.W_waNN\VH; tV5*#dU*:NgĽ"}+K*L9; |L^-WX6 l(X[`\+09{w4k!v)0hk_\PV(&>.([m9 -@v.*Ȟ*`bua*M#)1Th26z ȞY&xp ڥ]@ Xrw9ypnѝr(qc=@~y1Ci3ΑMˎtmr c*)uߒN"iE:C}j3H_OK H}T oYg4+ȳ035 37Kj3pq?'wsI_`A_їR˄p̶STOg^lu1{ z)Fх5CDLZs[tpĂ_+,Gc^–`@iĈ3a)T׽!Uy$ [*ݖ2;w{2ANFT;=1FD*k .2nd~WWB ܆ ~~`ű-Q}u֮~>%YQ#y_&gQ~S`Bf k?';19ܓ-&o3`1ͤ#N+eގ0vr RtlD){L ӝ5 Xg ai},; 5ziQ%QY!DrȾ7>/Ul2ׇu7lg ƞGK-3qe 偆|[ox:\8:>VwAn,8'JN\<4:8I~`;A>˶ݿ?Mv}G& V€#Rӣl_S+' xȀK$%^윩r@yjկqc7~Hy+k2ܭ!Pe.+0MK*ټ#6m`WAWMq$ i7D&gv^#fg9,]\~MhYR:UI-HU{6`tI"I/Lk#% 9c># NёjC|Ew:bіd+a\D*AFWK>:Y5hj rd OȬ4ًua|CVP< \a6Rύ=1wD.fl`СJʜ֪bEH MeOPXr14Xū_O-XR UC6vgkË0=2ō<*K*NrVª2(~mB@)tv}}a-1q A u "a/QKG[Kpb]X[wQX L阁}Fb\43^ݨrZꍕӅ8ϊ{B378 iW_+X?{4,gdz¿8#HL+]c9M@6'Z!2Z,yJ"Ej_""#C)*aK*G.<1{!,'$'rdgN4*+W* 3{ok&p_3qj輔jno]=3ʱix(xJSNqs_l2h1]C s.g!kD I,su6 S"2Bzn$:qګkM.KBX(P'FY fpBG$v~  ?g( F,c从]#ƭݦ<q4<^MS*;IzRk|DF̜ w8gdZ1,qoqA!:i<Ď0<'*`3x:\0Hw@n(+Ky\HCگs᫠9™I9QK3l|3aףWND_7m2 zQi $K,l"& o01r[L a= ;5kdgՎe;gP}NX/*%aǣJSv-AZNZ:ї%::cJ Sc,$H0*C7JxZB$l ; HoHUFAV|/Cwbg^㋻8DtaVIQ ֣I}K0#nrYC񧌭*fE.r|kHd~WHeNCKJ{/;lFwԆ˯?!'aK2iVq2gX_p_Piq j iΒ7/j!HMUQT]8ºp3U}IY:װ)= #ZV!mI$흹m9[Mez!DYGW񈇶Ȍpt?~Uc5 eCjcgɳ}Ƣ^օ8; taSH90=FƓVw>pqX%bۑ$|:)3)@Ǭ>}?EQ[(΃*I1rDwЖ@|Oγ Z;'\lտ*h- k'ZQ n5PTBUt*R -(@W棲XDM !,C-kbO3z/l7UKMIe> 6g]J [UAt#@ 11!;koJt9fo;unvru?Uɔ2_@;GE8 2CTtcZbC` Kn5|R= ˋz3v5GW|C|w6p% n;pŒooAZ؂=,c5JYw8lMJ݄{gSvH!Y}&DY1FDT AOUҥHS2BqC>iXgȷfe)WVgn:uגXn)*obY6 q yq f5:YSCHU`Ϙ _8ճ]|QXX "ntPyͻ/Һ6BgNa00nO&m{yk &|f9Exo&HW! Շj v֜3`=MJ#`SJ)ɀItEQ}M@dv j5'W'uŬ=f$To|>;=ih\M561Eodggޥh}?Uf?:iL/@)H!2<+=N-79⻅1g^w-k@IيHmJ9s5hz5khf*4hOVP4`e!UbZFWBn*#ydOg׶ |/*zH`:FŴ3.uPQUzqh'S['ґt2`Q,`qWw^4tt[LR ozqs's^g:qvOvSyoKWQó̰F-жFy3Tnx(ڂ!Ye䨐4"f/xD3/R'%$hW=^8/MZ:Z(ӘN'ibTQ-fNYTEc6-o| C:-G ,,BƓ>b~m5߻d'boFH<̊۔ K[G]oMgm|187>T/d# OF tUaE߆$bnc17$x.pأ;m)-.}i٣3 k%r;*L=UOQU}fPaB7+֖A^/4<dG)m /43O, v~/HW"ב_eкՉl]=]>s~1@^Dq2! .!(,51sŢ>F!˞cZgX`% Z_D`EF$)Յ+۾7V311x3i #e K`P@2:Qcx|>G.LuTkL\7<;-&pG SlPgv %iuЃHi-*s%M^ݤ@h ! Ha%%ʐ'9ccR}[OBhUJy?.zu5+QldɡGYRW5 o1}2`^}jX\UIN~ꔰe['2{ѐsƇaVy}XO& E6]V>z a2a\#etw$aS t3TA|~UӬGb,v~98YE-8yjv8'WEbyZ{0 .@Bf!ې;Y 06~oSzkԉҸjأUx u|ۦ uߑ.C@VY̚piM!S~p]UbF}m)#}\s| rjrIA0qһRޕ?„P-1 v:-(b[,p-K ~)Bt)AVK*R |{5}V1N4%+G'eKTDb➼?O 'G|~ l}#M k#guWԅnfu4`{RK#m:_{v"K|嬳8uf2~6:G&lR!%u$wb9qh;JX?+T HٟFRƖ($ux^[UNpνU[?#5~73V  [`G2z̽8L\8@tRYȷK[Oá^Ossun 84jgJFHS;ĥF Z_T(l4:mG϶3 +..%= _Sc ssۼg5dqRIݙu'\,t݆nkb5j f-]6^܇3U]5f_eI+i|mzXocߣq|5sxCbA@bXmH,j{{=8Gyucqq{s^QjQ@ j== U5;pvJx YӦMӔ5*Dꟷ3m g(ם.9(뿶:Nui=Yer)ˏAʃeo1-c6ע`he'yxVDa3J_Q}1Q#FaƚvgWW7Fq:Zz=ީ?OF?Uj/|&Kv rl| {Oa?0qP$5Κtw+ĕUoW {M%ZIJftqS[xl`o# I` WJq{`%m==UF2{HWjR pc-l6 yG+¶©K=dzwӠ֚y"vztpTƎ5ʲIrr"freZw"HO]|n@U$\cyop8DסV5G, 3s ;ؾO( DǍqܮ#IZr3)wF#%:.4``TF$˕N&]*o^N%ͨ>5nVr[؈`7C# {B1.k0{%{+Ywb=u  lhrMʷXT$m {k$h f6DHKJ$f$Y:cSwe0>"X"ꍖ/ O *P>264'" tqwUޅwsk1aF%Rky{&q,9JsBIDoݹ!0}h[ӟk̋)_aM;NE,pKCqTP?YC%+C= <;XǬ0EWQY\P#p U\M!m0[Fa8I#UF6/lZw!H%kpjؚkD_E`vj&I}%ryPaý PdFFQ'*tH bw;M)E5e#.nRpԻ C[" [Q_IDO}hHqGѶ.DQ&&ETR٤?n֣+,I `h}| FAcގCf噂@@2œ1hK.ßy2~,l Lum1w\-dXZ.K69v8,sL6MB6B/XAO5 2_O y %0|9lY3j󥭸P~œHFL=U)/&:f@Sǒ*6AVƽ O}ZէJ<@`3 5!f)i,)e' N+e.P^ŹAc'Ҩ4Fɼ˯J|\ֹ|џ0LK> *(dH"s) 9cSų{V>Uu\\49bRL^<~ ʍ8q8>elVD]>nX<*m c<;23 ~Vӑ٘FG]=wnMPpSֿ|Q3<(tjyIY_wv 4#=&ۀ/ 4B#0"LxFei#.z( ҄n)Ire IY ;N6kAeƷA⨴ _ўlX =,UtNQ c2-dK7jp z>·PH'̼VYUUBS{hʤg J͖B |Ƨc =/6p)@yΤyD\ʧ#&M'Ö.g.u?՟ ?.,{*0YUǛZNI/m۬..dM"w|zNbEM Qhm5X"B} U)"a v8Y|,jјCn( ko䄷 2t]@EH{;E8cŝm14}k)NcwZsuWX}Ǐ&ix)FQ* j^Wx$&( wðGs3"n<ɲAh0r0F~Guu[KJ` ~.U!=M<qB:{7̪3ja+{7k$@ hiN3~{Ij3L߾JQw0 ]sEg?Xn4rķԏnjASksUP:!AʗgW,^Mݕxqϲ#vmO1G|MJ]`8/j)u)>H0s݆ cF BMst' \&nkp.}k[n5茱$ߝ/<*B; 8)N"zf2镣~?mͥUZaO`!Lcu<'#zU烡x>|cG0Ɏn}3q.{=Q1qHP:74N:a*Z +\uvආf+¸1[#ѻ{.t!q_ګ Q._|Pteӯ>"\ni?eDwA9_DuJW(? ?I3rqj@Y(Ns5’*8Qy 4: 1TJ_v`o95O;Q%Xڄ llEu֠3tBh4)SSs,ZieLs|ѭwۇYf{,JQ:ÎįmymԭGLWGt%0znT9cL%fMAS#a+'%o8ncs  !?&zU,k"4o!tR$ɏĖ&Tz#fMn歍k8*Po<8[wetNmY*c@s`@zX/G!.ٮk-).tt)Zy6mQ&u0{f(?%DM2(L}Yc'ſP}6Ya&%B/n,Rsdfj9/V% 7(i2g>R8k;_TZ|WUP(t`,K 23${Jj[O 8 $[s6r@@j7w-"gŹ< ٱ]HRcZYvN7{wW5 sw@=h5)jٽpE>`SRQPV[4˾LuL9?Oc hx%j 0 V -A!1* cgˉQnv A-L\_t=GG *(Knq#qÑTL!yzi$qژ+Ed u;%)uѤWC=EX)@m 6T v7o&uTQ7{ݺby~A / MRUM0Ɠpu<$y)01/qjOBP#5<#l },eLؼb洳+T~=\={U;ⶂkZ[8"v-^ e4[)z0r :A0˃Qg:f7WDȟYa wy-ɦ qXkN5q i(DrpL@[ĠgE؀#Qr.#&Rv$W!Vd Ȭ%&L"X+ "e+Oֵ=!MRz\yGOkf=E!I"&5 SO_$ ,CN$b+%RPNX+qsrBakAԐ D" 5gHn@I+k쀨r&V1d+ohB'h u1JENT@4LG8L|N,Y=$FE=/-ũ~}~ F񇩰STH3PËf 9彅N>I<\yFF.S}jim98iY36"JR4hib $XܙTxB;ؠ GZDRpخ"uԝJ4qnh$n&O2VdBTÿi±T/+ V~s^Ζ-- ΢Y"¦ܫ% U%.I;R+$pDKVñtڲFBQ3[?DŽ%Iu ␂Tg>EB.5 *٫CNn;A DJ82F!|ՔLd,# /Q8g#jeԃ Mn_[k?ҰP&aorz~ep-X;VZ&;6<ɸ%7[NVw_$qfn3Pù. 86QVCןgث kIG\9bG ˍ/ [>K(bMnkX9(Y*J#Ψpm,ܼ0D\?pdf=™ZvpP گ)7,LWwl\ZaLl~h]G_bܞ t}iL`w@?!pح'-twsAgcChCkߠL['_vdLjH>=&Ny 5if}6ARrK?QZ(OɞO˰2͂E6%-2.ل_ QBS ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP:W8$C8h q^@տdisr;| 9^8T4 Q@z,5Ÿ"L\b2d?Fi $1"m1O% S|;$|w"=%3us цM+؆ `(K9}WN!{:>h fs-PlV{a O!n#-[Ĉq#15 x|58zP_3#5ů:`0fR{r,TํZ{ Wg^欄RS:- #$>5dO_T/r}zvJdqw7h^j<.MԏѝИg yC};#`w#n~[yCCpEPbo ɞ03?{7I6p鬮Wn5ѿ_|x ?d: V.}Eی{Xz}Hװ̝i?ȵ˔vuz4FiUVϾYinȦ$}Y񌰒E#יHladizR0~v*4@*0;T!rF@ }nCN vuDgþl@Xܐ qxתJ7ނFU\5bq)"%I- GќHߒV/mRM-> cAbꍜ/HXRæ8ݽ=O-=yؙVQ=%^~IECi㳹REI(ok`m’6Ig+^HKM|R62L< ,ZE&N(A1ACU?o9} W |*(p8uH{[/&-M>L X,>_?:{4peJ{QҾ}%$]=;C\z~P,|*,Dd\;D`,Ei2XթNdJcr2J,Ҥ+]`|Q*XQ;baſQwcηi wS ]v g2o#Aձ/J+cw 5d>#2n"'%oP3{ b$he9k@^BfFg#2qޮFj0MD$g`=r.a̓[4gsۇ%l[ ;H`/b  ۡ 7[|:/H!۟I@TREv*=ä N|*_dO|hO G?OpL$:pګFArxA%vrnzY[bAR5` \ycVPI%䕊L> KX-k@G/Dg?|ΆgI8m^"^htxQjEspiP?sMlL#ͭ':lHc[y~ьHP}hH ]6I`O i2%u=nay;\tT,XdQ2~:np]?q"?%U BN(V`Tva)j4C|ӓzY$ZFq{ԫlҢ*CȾN9+CA8E`֥&;qy Z\VH}6#D"&FS5#^[m~7=C9!k@4r-q^o&˨$JR%:cL| }D+&ݫ~3WUU%w!۷>ur/wөMI2FH'wgRTV) 7#yj).5C|\ m'O>vGY-iD#;_JYfKf_: E݄\96ߴE;"YR5"A5p쥋-燂MxT͆"-.*IYZ+ Z rۮ Lܖa-ezu0D0|L>k=tLi“ôS⽖\-T 鲨Kks0ubn >{M+*lp@\j<$K(mTП`wq60J鯪Lƥ*K[ϵISDw,káE,q@|Vø<CBgw#vg)S!iu5TZxNhƞ+Woudf2DZ=v)UTuB8Ug@VB۔+ݝEs=bZښagQ`i5|gV}x$0z*,~s!}03 uK8A; t^FJx[[ #ln ḣlM%R>&91ݟ[脹C3/e%fvIY"Ŝ X`m\^ !ȁ"PwJ_EnO ݂mXuNQR`'+q^eqexovM|+\q{R>=)vJA*@szrF׫ꛢJxg+Pa=跎N#\l-_ݤsi;RT _?r,n۶Z`/ t^{ޢ.gYN嚪 ~tJ<uutfKKIǒo.O~?]H!vYB {J}ѧK$U9ā,tcEG% TXhfHj:>XL9U2Cn*!W7d՝rX$بMxzpoúH&bdM_ú&&':FYMC_7]1ԑ n%芲9lG%nٗA5˝j Ami6̐< jYm/AzŻ\\0j :«Ŵ)oǜ3/mj[]2DpX doS^ +_F<){3!nւ~|"cN0;naRЬQ[{eO:4kxY3+ʮ &)"w/4 K 8PI$ Nrjb HTŲqCDpHq$HL}*jpZU ]\'E]!@ɿ(Qqhf&=^1߇&][zP_AE4[&L¡f@ ^qO24*ԍD/?I0Yq܊;IM$QaZ: |()]* ԜL[_V ]ΜE&:h0̸* ^(ORH'ja2PC!}٧J}~9q҆4{XbGLM\tZ@wzbw!tzmcD%Hg37HjHjSM`[lnZ-8]WJhI,,'rͿ/71;߯Q9?ӕx@ȌQ{`qd 9 nJ*Ь+tij y L^W+Hth}NnYw]ĢK9U8sdGoo77Aij8!5.r(l||@|b!H$"=E)WxLB/{![4gDt~$K]I~68ZG. 3F+?CDw\(1t-S(h3TIAQ~HO ,zkR\NtL)#'Uj9c}RFy'.T7{ZH *;mq\eM2l&d3<ǝ|L9Wy9uFl'Rֆ`P#)&0}aʄqj>F\6]Ȗ=@*"ZGER vQ0"7-.)ʪdb`F ֻhB&z1lW},eq $:V6&zg8ALz"ljh:OqG/ RS;:GRIo$iӲ {(䲈ѵmؖR2p盺 H9L׿=|@s"BxouY{qf ʧFchv'/UŴ/.00[cȷd=I>Z=8ENdd\ &8_ ;yLA~D\)ԣ,ֻ:]2kވ ֡ *O7)Jj^Od 7vdl̋UXHӧo-#{EX3da\b} z-Ogr`8o Y.KH,+}^ pU:V,w V3 tuY]gDe")0%%A*I# G4NDхUUAs!/MIcX ]{Bȳ'2^-fSJGb87 5ϗ/{!S$i$%>a; 6Щ<NSFX9ꥁ>;פF7K'53ui>UoOIB)f!Y|ջZ# >j6 pr'XG,Yb/(y6Q3˅̔uD+iMyX1/:_ڗւA5zJ3nd] ^Ɇ` 5 bedjưS8iQZ/bwԁ!oA~~hMr^f)sP9(>,fCEr4`;(1qh-Fe@BV7i`y($.+a;pǫ98t̴{ϏMJ)4ju!)-p|ã☃ SQgpJYI$EH#ܤMлh;GL[@ B&'وEd^eo-Кt&9ʠK7D=IETB1i<8~l7 ;E!H.uCO[z~?q & *dT"J;|*VZ?(a,kd7ceO%#Jsn=C#s4NjZ8ix4IM9Ѵ(GLվa`4H82@(ڿlІO|1.L@o0-gXHЅdsTgc`Ns;HЩM(6JA[6AOߛt{·8IB$2Yf?)dơwrG&ISFTuVi:]҈$|MCq քb;+dzꁇ"0Jk^^"'݀ǍP'#] Mҡ20 FxTd /IIh/`e@DVn|Gُ$V%o;1lmge:rɅխz5WE[ll0m(?Ϗ#4J[>Km4}=*!)Unbb?9(/rc1֮9Z=hm | u 7y̞tLVWe;#R;JDqOBi;% ƨ3 ~#D˸SLP-EE|^ʆop?WK%ФOJbZzXc>Vwس~k‰dWT:&&P)J" Zz4A\iZꊬ _I3lC&m ZEcWrP={u+*6 QaߪS<6*|dp'&BtR` E@zSPZAte'rޮtӱ)g~1߼E#HrZ`_Q|SHB "/@t8Ų[<}?呏uHo8&`*} asX@хKi3*< Wă , ^i]9 ncՓIUT:Vu@S(~vRDP ePh5 ވkMCQR)"4 T2:L~}X)ܜqulvؓ")*ܙr L[l֮;`.e=m5Og-(cz_3w}=vp_0=zSh(ݸ" dKƞd#WlvQ61y\4[9OmEd6nr^ֈj]I=^eXoKދV2ϭ>ڃ1BRJ xMϼn=h Q #7}]׏z4\dQQ74OQaj9jWeybw5>C%ߛeh'mn e/׾uu|C\200\2TC]͊<8f'8{ao~v#ye<@ uMjRG16m|2܅U]6 4OBe{=bMix`j5k/{  ]Ű7cFp{,#jc|wm<:9 {lc:*7",=(sxTm;>\7 ËvdVǿ\tdSZU1ۏA&sǦf4m29-GEohfP7?bFrr渵H׹ܒ?0fCTOho6 xɽT TZNA1O GC|@|@>@ fc7{zzi5$|j@#+4cDć=d5%Y -Z i %_"3{0AGX/ )+ӎJ|d;hgL5҂&_RQdKɑUyA I0ƍW)+x6xۢCR[QIX,/WD~R\Yj#IBdg(wA,;v -NS} eQ#_`\|zʶdi4#r/mo"χ[e+yv_|=jM/v;0֎`HRSX*8iQ=VZkݥ tlF"Ƭ׏%:<e10?L>Kk' WK@ᢃƨ1KD;|_?p=迏HO*{N8$(Ҳ(9"< t(܏(_`uO S; Ƹ3/  #zCig~; CVJ02Ah/:x.1דND`yXs߸bQέS Z`RG-yy<Bk -&qxXn mZNYwe8][%Z:L*lv*AwF~or\rb{b@ys'z/Hн_"N_FBA<~ooY߭Hߟkk֊g( PrtԉU5pzK> 80mF=H~6Bqd)$=q.Q"<= ,>SKwO;VܨG{"VR:ԍDդpJrjsp-Q|a@MDl\#C9e1*m`Ƭs##>2y6$¬OoY ?!J9ܠHۮ1\ eh$C6FoY 8o߈9.Ɛ5'^o ipMyu1m/DJ F7΅z^}(~fІXQV! aY Q_=1^X~8(Jj$S{+ # l&p*-#CGмapPy88K蘢fk`7UTԙWX:vgrםw#$ӝ]BېEH8DdVn($eXaD)"3tYQ ӌiS 0BWo)a 2УRTQ񙱔nB FcAr%p.Nm$ey{փ , Ӗu`<V z> U#%i}5o3G`lj1+;9aeO?,ID˛ &Fh֒A 25 K̾ .LC59;x7*ЭU1@OKU<210Qaq zn[ g F%حWFWI..j?u\=?0 D OWbY {qXn_@qj~>Fdj õ ,M?7Ԅ:Rb [%Tk" L¬p:9M P|1~ޗ7e`eZ4 Vm+`?s??F[_A2ZLDO."S %fϔdo|e0wvd8*JAm@g=FCr~j{bueD>gGn8߷kR7=I @a挫q- SRkYhYȍ \Ȓ>s* 6:M3YfEu"Tmh,>״fgja Г/ܳ+9y\P hDmح~ViO{Tyś'|;ϸy^ZjJNS?Ql569TϹDng#+!u6 T-l#W4D>\bp"lE^<ۥk)ΓGnz?p"p^rugUwn?^'M8:)04PW:8xN s"yV+hW_v>fC,5JbHK <;S > ѽsfsA ɹ~ݠ{iGL*3 n|vh'AWo`R7"wWDqu8l+sjԲu$h Y>/w iS:?iHQlrm=.ëjY 3X&3f (ްO/Ǘy #8&]4wad } .L3`bTD O+pҥzJx M7Q N.4X\6'֖JǞܸ5U2 3xI;I>K*q7DyIDzV =mjJeÙK@bjTԛ_/ˆeA8E:ψg S_a bnɟR~qZM.55gtjM'C-fM/RLOy;7"s[Iz! G@8PVpF-*#b"i o#ZWM_ &I:-ky;Ee(K; u<.MV.w!Y!DT/]1?ѝ\_9b~Ṯŵ$ K3#Z~":;'XRl~}[^a ˓Qo|䅊 >$prərS*|]%_,Sl[FIiÚc!*l ]Y1yL}A\M{m~CC#t#)ư96^?(X!~|n=׿ 8@)zh)9Tp9à 24Ie>bF)pC':hѓl ~l"u&/K Z&uI Zhh@ 5+E է+JEՋiJhߘ\|JDC} $@K K]^唰qu8?^ۘ ^`1|U4ǺO{YE@N &l⩭wn*<'%ʭJE(cl~ْ3F#/YxftBA^5ʰF +OqU!1wZs"BUKL9cK;,%=j39Xm@"1zZ^YB(gh`I@e-,٥; ꐖ&Cς!։=Ix5|]w OѼ ﯖ_D[lAyd:L-_'U%F?ICC!nRtFf_UQRhz~S<* 6~;ik~=DTƓc()_eLVVoN&ɫkb!2rb2,=n^Z4ǰx0\ھG:eewXT{Χ ōowz oI|~dPԄd̃LWgHGb:^ 7sҚH=n 48#t$4FP.2,+R@_^{8[O웳~ ^ :O6O+J&-k"K$TS:Uv*8+s/42S'V2+)' 99U9n:q2}:s`: Y>eQ=Vf܌eTaex(B54dB"P▚ifɍ{w= vbu߄W5 )X8(/s':C+'u`]<^;(:pfoC9 IG(mAe豻~sYjÁ eƪ皗UOږ^$O -_,‘lxJ9T-@ _`,wծgM}=t@!D&0q/ o !oqf`'tYb~ ),ta1grP_lڔE ^* 5_ք|сDzr|y(N(N,8 .ap ]-FH/Fͺ Ԛ,'r_ndMrl]!``M՞3Z],X .Zׂn۟2,0^vp_M}m½*G۔Fs#󯸞f [HYmqݼ!}=xL2b4VYtS)7v8 !qBX5^m PLٸ N$m]?vԼv͂TAj@r.6׮ꘚo(eQ?n,i ̞[蜇:g7`[B!rr ny^BCU-xIvLmG XJw%"3:ɸGWq]* œcNe?́˖R=ͅM{mѶDx5TwB'? Csi@JQf fiW"uC'9cYSrZ5Y*d/d昃[({` %R0qm+ ?:f[M%Xh D1<~odlBWKf`>2PܰZr5xa$ RC>S ]@@HHPHHPHHPHHPHHPS ]@@HHPHHPHHPHHPHHP4R ^G:,À(5@T09Z0 bI7rVLDI76::{2!|A;R$?wѾŕ,Mw,nPei|ð@|wO붬xr|G _#ƍ, z yi8F&58t28 nQqlΗ-VBrMb_R`NPq|~AR :Hoh])zVK7zyϺgY!s_|ԋHH'(aW0Z[`6V<<:6SѻAhSی-,Yc48紓ʥ[@񾁷~n#(DuDr۶ @'E'98|aI_ָQ(S̑1|Y~V^O6U0.yG>($0Uջ7VOܯլB+>@~b.CZZ0(FOfJ K-s|+V?]fC&-4CYgd3(kgtidEiPv(:#p^xw+[m/[EvWqznrX֌*%ٞ!2Dͦo#읨N76<tٜ)BAVq &797g![O}j)!.'h 邱_>Z>_o(z#:z\HP:7E.x"G~Zn `qW &鷀[cu#(YىxnwYt6q|0\/w}@Tq!:ȓ66mе yNNt\Őgs)QvHg64׵{,BXvhv8S a4DcA$MtcCE%lZ_N|*M>Mi~OIɳ'`1yH-FOsB}pDaHaėP|ݮ!`J᱀}$~3!| >:xH(uJo{Evfz 60ySScΩ} "^MPϹc폼F4S_X$Ж)aՑ6N&}⃚b׆sS>sRj#4H3 vӭzULWл N ݙEyc# VVݴV< L}IS]eu0FF6sU!z GSp.4xձRd .J]%1<4lԶw1ʚsʖN`QT ]Mb@Ɣ] ib'`c{Odz'V˓&"LZ]~GKDQ0NtcT6 GvPy4l8`aer;Z9brPVZ݊z̓W{$XmWݦ=/wJRПLǎfg7=p}/L%[C\fJ[z\AӿvBܡL.#mDC N6+ҀZJ&C1 97qp .e8Wae2|]Y[I'{YF7IIx3 Y(C4Hdcpݏ#Ͽ(ߜIe;{įJ ik hQtW{9[@Զ_pȍGdR<{ѨP !O{+RRj:[Y'lKg;QҪ9[5 UH߾LWؼnخNCUbr H :H#T~- ]VG?e)zbi&:;Rz*9KrvXKh}Yg18Dž]q2u}mYP4@f]lvOXQrHᬔצrxp!2Ո^a _3z>lMsAɜߛ= 嬹J2 &pJ>Y]!N/ kϴ @1ťYg?-ۚsVE*QG~9>(~r^\R7ڕC5^4"\dT4@(q/M/dŇg [kYe LBq^?&U _)B҃~,xt!ʓDM/YKp/j58CbUqF; 4?k! iӔxuEG$#F䕘__2Jvi_zA<}Pmgoa|FHY,r˓ƍ^@-,7ʆ.g_-)F$y/ck[mb\$TsDU(wŏ #F&#VM;tCS?Fդ7R/瞊j:й$+K\4,ɃՆw ߢqxƘ/ Wٍ!m6H*ŃpLjStV\%--~_B~|6yQ, j*͂牣@S4[8j`%}.W-O&iZ#W[&2ưXn.{S&V\![q+i-RSBF/Vs皓 Ot[#7%2q#֏д&>|Xd0jBycK!~, / '͸$ &x.s̎tZiyxaؐqej?h8\ @p"A>s}@;z h"uvJ0L3>ks `IBdά2 x&? ooW^uhȳ(FMsԳ%E -]MwV@mΉpep^MfL0zlS͇v]ÿ~5链R4Dx[\ӏx{h35}[;i1zo0#05s`,ͩ&UԾńO%|1X_!ѻ!N蒺.>twDB6JƣAƎpK\s-PeB VT[u|;Y=rƏa^ +|au2 iBh#AŠf-VD9bKjH( Q(|D#U@b41?3 U MΥ)֥~42@^pJ|z $p!n1TlJIsoҹ',ho/ޣ{w<94~#p9cSh9yf:"oq7GBt'8O?[|f-_ڴ8|tdFqh "(vBAh Msîӽޗym:ll hr(չ45['jr'x#?vf=JjOL;:@bRFU{mOEιR&S>)V(`8Q"%C|~M`ps==/'a!h2Z܋anAꁇϥ0z'y ]yj5RXM bHA6LPҥY?7JϽ~$_R஌[`հ?uv %ހ83;9P o -*Yy @=jʂ_1"`\X`K;~q0(?gw%}Ğˁױ@'C (3˳luoI|#bN"nhR gB9:9!]¹TP;Jh^5<\ulQg ?z-^90;On3r'F[)):hZ8 .T(/tպ"r1U\8 i5dDZT1/g)]aْ_K]6;}>ԡz~j~xte Cx^ާ~ 01Ȫ`맲QHotͥA?[-2'wà6+8 Lg*@ᗨW_yRl۹WjX=Rz ,;gkC)p"n#ѳ 7!?{Muv(N)]"O;iLGWIdB"6ey,ĦWqo`3fߒl6-9?u2L' |uk!A7cfr({(.hP~V^Y?w #qd S*ſMж폰 {$ȦE,ZAp]9Oշb#`6=v/BZڤ;^1ɓ#x V4&@1 wu,ӯ)am&VTA?2 Kd嫝Ll#B|GIlHWK żoYUDx׈ zaP*#K|~H$~mf=PR}J9;:;uBx!ҥ,rZG;\# n\%- "LvIz>u )9,kkLuV_L@إЩ<##×7 */a԰F[|Ф ;guuC3CdHh-~Ēw}&BHI: (1Q06,qZ)svVٸ rڰGJjufsELsfj D4ޛApl3exfRtrw" G[*N GT]T^`XBW;ЪY[ f6Ơ}(Զ v U?1@[9{h(_!M; 7pt &sKd I#قsq>)쪻;Ͻς5_4@(z٦`|@|$>@|y-ɰI"+_VoX@|j@ _^|[`Z؁=\qZKڳOxkL&D:b {6DeA՝(jRG>= ݀;3_l #R 8<6ؓd҃bJUanm(lUv&%r = {I*Nw'?wMqI:ϭfGb /3|",n":w CshEKqyR,C31l@;=x˂k[Yo6Dg#BNrxޚ2X!-#`i=BZd"IMqzpWbЏ4R̕Uоك<-*Kxi*㷹rA.6R09k۵%DSS%HH:!nYׅ}5pM+mhy*?,&O-N?Έ͚b3Vllvki4?wS=~p[ztѐ,D;}`qtǦGudRcMﶧ 9S 3E"a*L>Hk^{BMbW?GsG[9iC25'CSkƊ*R[(0#X alNa5[ɾ$qvΦtɔ;5Qu *XCAٴCSLże YWN3r2>^bSgKH* 9 gw\ W(%Um\/f?GZ{DxWA_0GN_KZ$ ?U[a.e;GʩCB;2<2aJt:8AҟR ^赱Ÿ+L7M${m.4t\qnSmm?J;C =~l_ )G PkD)f1.>[J`oDԬdl/gM; }X4>{F3bU @Ҍf:NJQ͐͝>MҔ5dD(6 ZS c=FDN' (%d.F6vQay&ʋшudH>+mipfI',鍻! ]8C%,c>\NbonE5:aȡ|JpU@*:&߷yaDjץ#M' /qYGΧH 7ٻL=6 <T(0ab1@l~@RHƝ{'hg U?*Ztl7)thoWM.&M̪o[,b$[aAQӜN 8fxi`M7Avn:D? P_+mU</ag?ێ $8O 2!W |loNv:x+XC:Zܠs,8Wʄ XA ):*C QQazh~) JF_@:o O! 4*cx/޻ӳwMؙX+_( |TPuZ^L~BPO2.?םcB$ ɜ_*0ƵɁ[L,JLA" .uX#k7!w3L;-j]w1m/\&[[#D+팁ۄ :̼ 9ac>J2`7$O?.S~ ?u OR-ǻG\8. SؘsG)e ^8YdP$3JԠ®@<^eM33| 9rIkV'+;%%dCO2:`r|3}¤'1"+,!ur1&³uo'[ ~Uˉ؞םbU]Y&!^w+!M4Qi C 1)vJ~$`G0∣"B*%DgP`ǭDe" t-kNU#?OTiϜi5իDK]wD-ѢkbνS岖 !icT&chkfww?)JSM$ѿ,Xu`@%5B+`עeXtGXTtŚKGWR} 0?|Qk.ܦ6@HݙXn d ^;CxHrdWmYγ~YDƺT9:tD=9b$]OwA'-=3DJbAI_ Q7"XU۴(4v GI76?:j f '=ɧ̙v!-èȆQT.CB 7*>udBW{d한ITOό@YZ{&_}yV#Uc2%D}Z%CuKE";f4d&w#GO)bvrFnw4]`;YӥŮJܐqyeG*Q{1$)k BRJjag9"l8¡s ;i "'<e] A%St9:{"jʟ W7IsՇE lBosKv-7o4LCE@B:s+|; k &a1gcTx&ObP行,x2ߓm_[ZT1?}.*҄wّ*e3&!ĩU4ezI.&GdUݠ}+4h{^>Ora^aeo%bKLPfQ䴓fsKh`EUs ,jZl`{?P? "ZdL V q  Z'nr~{U2)"*$-V2&]eD9[=LыDU\Vʠfizu'w@n+87>PJ 8R|@||b!hMX/u!ri̻K ƣ@FJF?n5NW4(ߢF8I[sd2?|x.Z| g*`TWV<]ajhs/$D h/!b=|6fT|ڡ?Tmv>ΡLh< H8jX4L8UI*0 <(r_o͙Fp✉΀V*`%nlXiNſДpx1I@)9Q u)GwH3χFq*܄iNة鍽@;Bb};7-B}:v_gҔ'Ԁ}՗YEvMtebFW /6p-p2訒5bll^_U?U/uډm